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:
@@ -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>
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user