Fix overflow issue on iOS autocomplete, among other things (#6611)

* stop using ref in render

* fix display name fallback on web

* use unicode ellipsis for useGrapheme

* fix overflow issue

* sanitize handle/displayname on web
This commit is contained in:
Samuel Newman
2024-11-21 22:32:32 +00:00
committed by GitHub
parent f67e00a85c
commit 9f1e648686
3 changed files with 27 additions and 40 deletions
@@ -13,7 +13,7 @@ export const useGrapheme = () => {
if (graphemes.length > length) {
remainingCharacters = 0
name = `${graphemes.slice(0, length).join('')}...`
name = `${graphemes.slice(0, length).join('')}`
} else {
remainingCharacters = length - graphemes.length
name = graphemes.join('')
@@ -1,7 +1,5 @@
import {useRef} from 'react'
import {View} from 'react-native'
import Animated, {FadeInDown, FadeOut} from 'react-native-reanimated'
import {AppBskyActorDefs} from '@atproto/api'
import {Trans} from '@lingui/macro'
import {PressableScale} from '#/lib/custom-animations/PressableScale'
@@ -11,7 +9,6 @@ import {useActorAutocompleteQuery} from '#/state/queries/actor-autocomplete'
import {UserAvatar} from '#/view/com/util/UserAvatar'
import {atoms as a, useTheme} from '#/alf'
import {Text} from '#/components/Typography'
import {useGrapheme} from '../hooks/useGrapheme'
export function Autocomplete({
prefix,
@@ -22,15 +19,11 @@ export function Autocomplete({
}) {
const t = useTheme()
const {getGraphemeString} = useGrapheme()
const isActive = !!prefix
const {data: suggestions, isFetching} = useActorAutocompleteQuery(prefix)
const suggestionsRef = useRef<
AppBskyActorDefs.ProfileViewBasic[] | undefined
>(undefined)
if (suggestions) {
suggestionsRef.current = suggestions
}
const {data: suggestions, isFetching} = useActorAutocompleteQuery(
prefix,
true,
)
if (!isActive) return null
@@ -46,26 +39,8 @@ export function Autocomplete({
t.atoms.border_contrast_high,
{marginLeft: -62},
]}>
{suggestionsRef.current?.length ? (
suggestionsRef.current.slice(0, 5).map((item, index, arr) => {
// Eventually use an average length
const MAX_CHARS = 40
const MAX_HANDLE_CHARS = 20
// Using this approach because styling is not respecting
// bounding box wrapping (before converting to ellipsis)
const {name: displayHandle, remainingCharacters} = getGraphemeString(
item.handle,
MAX_HANDLE_CHARS,
)
const {name: displayName} = getGraphemeString(
item.displayName || item.handle,
MAX_CHARS -
MAX_HANDLE_CHARS +
(remainingCharacters > 0 ? remainingCharacters : 0),
)
{suggestions?.length ? (
suggestions.slice(0, 5).map((item, index, arr) => {
return (
<View
style={[
@@ -93,15 +68,23 @@ export function Autocomplete({
type={item.associated?.labeler ? 'labeler' : 'user'}
/>
<Text
style={[a.text_md, a.font_bold]}
emoji={true}
style={[a.flex_1, a.text_md, a.font_bold]}
emoji
numberOfLines={1}>
{sanitizeDisplayName(displayName)}
{sanitizeDisplayName(
item.displayName || sanitizeHandle(item.handle),
)}
</Text>
<Text
style={[
t.atoms.text_contrast_medium,
a.text_right,
{maxWidth: '50%'},
]}
numberOfLines={1}>
{sanitizeHandle(item.handle, '@')}
</Text>
</View>
<Text style={[t.atoms.text_contrast_medium]} numberOfLines={1}>
{sanitizeHandle(displayHandle, '@')}
</Text>
</PressableScale>
</View>
)
@@ -10,6 +10,8 @@ import {
import tippy, {Instance as TippyInstance} from 'tippy.js'
import {usePalette} from '#/lib/hooks/usePalette'
import {sanitizeDisplayName} from '#/lib/strings/display-names'
import {sanitizeHandle} from '#/lib/strings/handles'
import {ActorAutocompleteFn} from '#/state/queries/actor-autocomplete'
import {Text} from '#/view/com/util/text/Text'
import {UserAvatar} from '#/view/com/util/UserAvatar'
@@ -148,7 +150,9 @@ const MentionList = forwardRef<MentionListRef, SuggestionProps>(
{items.length > 0 ? (
items.map((item, index) => {
const {name: displayName} = getGraphemeString(
item.displayName ?? item.handle,
sanitizeDisplayName(
item.displayName || sanitizeHandle(item.handle),
),
30, // Heuristic value; can be modified
)
const isSelected = selectedIndex === index
@@ -181,7 +185,7 @@ const MentionList = forwardRef<MentionListRef, SuggestionProps>(
</Text>
</View>
<Text type="xs" style={pal.textLight} numberOfLines={1}>
@{item.handle}
{sanitizeHandle(item.handle, '@')}
</Text>
</Pressable>
)