Bluesky app fork with some witchin' additions 馃挮
witchsky.app
bluesky
fork
client
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}