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