Bluesky app fork with some witchin' additions 馃挮
at 35fa3d8fdbcad84d6f810abb2d0cb65e6549a9fe 117 lines 3.3 kB view raw
1import {Fragment, useMemo} from 'react' 2import {Image} from 'expo-image' 3import {msg} from '@lingui/macro' 4import {useLingui} from '@lingui/react' 5 6import { 7 type CountryCode, 8 getDefaultCountry, 9 INTERNATIONAL_TELEPHONE_CODES, 10} from '#/lib/international-telephone-codes' 11import {regionName} from '#/locale/helpers' 12import {isWeb} from '#/platform/detection' 13import {atoms as a, web} from '#/alf' 14import * as Select from '#/components/Select' 15import {useGeolocation} from '#/geolocation' 16 17/** 18 * Country picker for a phone number input 19 * 20 * Pro tip: you can use `location?.countryCode` from `useGeolocationStatus()` 21 * to set a default value. 22 */ 23export function InternationalPhoneCodeSelect({ 24 value, 25 onChange, 26}: { 27 value?: CountryCode 28 onChange: (value: CountryCode) => void 29}) { 30 const {_, i18n} = useLingui() 31 const location = useGeolocation() 32 33 const defaultCountry = useMemo(() => { 34 return getDefaultCountry(location) 35 }, [location]) 36 37 const items = useMemo(() => { 38 return ( 39 Object.entries(INTERNATIONAL_TELEPHONE_CODES) 40 .map(([value, {code, unicodeFlag, svgFlag}]) => { 41 const name = regionName(value, i18n.locale) 42 43 return { 44 value, 45 name, 46 code, 47 label: `${name} ${code}`, 48 unicodeFlag, 49 svgFlag, 50 } 51 }) 52 // boost the default value to the top, then sort by name 53 .sort((a, b) => { 54 if (a.value === defaultCountry) return -1 55 if (b.value === defaultCountry) return 1 56 return a.name.localeCompare(b.name) 57 }) 58 ) 59 }, [i18n.locale, defaultCountry]) 60 61 const selected = useMemo(() => { 62 return items.find(item => item.value === value) 63 }, [value, items]) 64 65 return ( 66 <Select.Root value={value} onValueChange={onChange as (v: string) => void}> 67 <Select.Trigger label={_(msg`Select telephone code`)}> 68 <Select.ValueText placeholder="+..." webOverrideValue={selected}> 69 {selected => ( 70 <> 71 <Flag {...selected} /> 72 {selected.code} 73 </> 74 )} 75 </Select.ValueText> 76 <Select.Icon /> 77 </Select.Trigger> 78 <Select.Content 79 label={_(msg`Country code`)} 80 items={items} 81 renderItem={item => ( 82 <Fragment key={item.value}> 83 <Select.Item value={item.value} label={item.label}> 84 <Select.ItemIndicator /> 85 <Select.ItemText style={[a.flex_1]} emoji> 86 {isWeb ? <Flag {...item} /> : item.unicodeFlag + ' '} 87 {item.name} 88 </Select.ItemText> 89 <Select.ItemText style={[a.text_right]}> 90 {' '} 91 {item.code} 92 </Select.ItemText> 93 </Select.Item> 94 {item.value === defaultCountry && <Select.Separator />} 95 </Fragment> 96 )} 97 /> 98 </Select.Root> 99 ) 100} 101 102function Flag({unicodeFlag, svgFlag}: {unicodeFlag: string; svgFlag: any}) { 103 if (isWeb) { 104 return ( 105 <Image 106 source={svgFlag} 107 style={[ 108 a.rounded_2xs, 109 {height: 13, aspectRatio: 4 / 3, marginRight: 6}, 110 web({verticalAlign: 'bottom'}), 111 ]} 112 accessibilityIgnoresInvertColors 113 /> 114 ) 115 } 116 return unicodeFlag + ' ' 117}