Bluesky app fork with some witchin' additions 💫
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

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

authored by

Samuel Newman and committed by
GitHub
9f1e6486 f67e00a8

+27 -40
+1 -1
src/view/com/composer/text-input/hooks/useGrapheme.tsx
··· 13 13 14 14 if (graphemes.length > length) { 15 15 remainingCharacters = 0 16 - name = `${graphemes.slice(0, length).join('')}...` 16 + name = `${graphemes.slice(0, length).join('')}…` 17 17 } else { 18 18 remainingCharacters = length - graphemes.length 19 19 name = graphemes.join('')
+20 -37
src/view/com/composer/text-input/mobile/Autocomplete.tsx
··· 1 - import {useRef} from 'react' 2 1 import {View} from 'react-native' 3 2 import Animated, {FadeInDown, FadeOut} from 'react-native-reanimated' 4 - import {AppBskyActorDefs} from '@atproto/api' 5 3 import {Trans} from '@lingui/macro' 6 4 7 5 import {PressableScale} from '#/lib/custom-animations/PressableScale' ··· 11 9 import {UserAvatar} from '#/view/com/util/UserAvatar' 12 10 import {atoms as a, useTheme} from '#/alf' 13 11 import {Text} from '#/components/Typography' 14 - import {useGrapheme} from '../hooks/useGrapheme' 15 12 16 13 export function Autocomplete({ 17 14 prefix, ··· 22 19 }) { 23 20 const t = useTheme() 24 21 25 - const {getGraphemeString} = useGrapheme() 26 22 const isActive = !!prefix 27 - const {data: suggestions, isFetching} = useActorAutocompleteQuery(prefix) 28 - const suggestionsRef = useRef< 29 - AppBskyActorDefs.ProfileViewBasic[] | undefined 30 - >(undefined) 31 - if (suggestions) { 32 - suggestionsRef.current = suggestions 33 - } 23 + const {data: suggestions, isFetching} = useActorAutocompleteQuery( 24 + prefix, 25 + true, 26 + ) 34 27 35 28 if (!isActive) return null 36 29 ··· 46 39 t.atoms.border_contrast_high, 47 40 {marginLeft: -62}, 48 41 ]}> 49 - {suggestionsRef.current?.length ? ( 50 - suggestionsRef.current.slice(0, 5).map((item, index, arr) => { 51 - // Eventually use an average length 52 - const MAX_CHARS = 40 53 - const MAX_HANDLE_CHARS = 20 54 - 55 - // Using this approach because styling is not respecting 56 - // bounding box wrapping (before converting to ellipsis) 57 - const {name: displayHandle, remainingCharacters} = getGraphemeString( 58 - item.handle, 59 - MAX_HANDLE_CHARS, 60 - ) 61 - 62 - const {name: displayName} = getGraphemeString( 63 - item.displayName || item.handle, 64 - MAX_CHARS - 65 - MAX_HANDLE_CHARS + 66 - (remainingCharacters > 0 ? remainingCharacters : 0), 67 - ) 68 - 42 + {suggestions?.length ? ( 43 + suggestions.slice(0, 5).map((item, index, arr) => { 69 44 return ( 70 45 <View 71 46 style={[ ··· 93 68 type={item.associated?.labeler ? 'labeler' : 'user'} 94 69 /> 95 70 <Text 96 - style={[a.text_md, a.font_bold]} 97 - emoji={true} 71 + style={[a.flex_1, a.text_md, a.font_bold]} 72 + emoji 98 73 numberOfLines={1}> 99 - {sanitizeDisplayName(displayName)} 74 + {sanitizeDisplayName( 75 + item.displayName || sanitizeHandle(item.handle), 76 + )} 77 + </Text> 78 + <Text 79 + style={[ 80 + t.atoms.text_contrast_medium, 81 + a.text_right, 82 + {maxWidth: '50%'}, 83 + ]} 84 + numberOfLines={1}> 85 + {sanitizeHandle(item.handle, '@')} 100 86 </Text> 101 87 </View> 102 - <Text style={[t.atoms.text_contrast_medium]} numberOfLines={1}> 103 - {sanitizeHandle(displayHandle, '@')} 104 - </Text> 105 88 </PressableScale> 106 89 </View> 107 90 )
+6 -2
src/view/com/composer/text-input/web/Autocomplete.tsx
··· 10 10 import tippy, {Instance as TippyInstance} from 'tippy.js' 11 11 12 12 import {usePalette} from '#/lib/hooks/usePalette' 13 + import {sanitizeDisplayName} from '#/lib/strings/display-names' 14 + import {sanitizeHandle} from '#/lib/strings/handles' 13 15 import {ActorAutocompleteFn} from '#/state/queries/actor-autocomplete' 14 16 import {Text} from '#/view/com/util/text/Text' 15 17 import {UserAvatar} from '#/view/com/util/UserAvatar' ··· 148 150 {items.length > 0 ? ( 149 151 items.map((item, index) => { 150 152 const {name: displayName} = getGraphemeString( 151 - item.displayName ?? item.handle, 153 + sanitizeDisplayName( 154 + item.displayName || sanitizeHandle(item.handle), 155 + ), 152 156 30, // Heuristic value; can be modified 153 157 ) 154 158 const isSelected = selectedIndex === index ··· 181 185 </Text> 182 186 </View> 183 187 <Text type="xs" style={pal.textLight} numberOfLines={1}> 184 - @{item.handle} 188 + {sanitizeHandle(item.handle, '@')} 185 189 </Text> 186 190 </Pressable> 187 191 )