forked from
jollywhoppers.com/witchsky.app
Bluesky app fork with some witchin' additions 馃挮
1import {
2 type AccessibilityProps,
3 type StyleProp,
4 type TextStyle,
5 type ViewStyle,
6} from 'react-native'
7
8import {type TextStyleProp} from '#/alf'
9import {type DialogControlProps} from '#/components/Dialog'
10import {type Props as SVGIconProps} from '#/components/icons/common'
11
12export type RootProps = {
13 children?: React.ReactNode
14 value?: string
15 onValueChange?: (value: string) => void
16 disabled?: boolean
17 /**
18 * @platform web
19 */
20 defaultValue?: string
21 /**
22 * @platform web
23 */
24 open?: boolean
25 /**
26 * @platform web
27 */
28 defaultOpen?: boolean
29 /**
30 * @platform web
31 */
32 onOpenChange?(open: boolean): void
33 /**
34 * @platform web
35 */
36 name?: string
37 /**
38 * @platform web
39 */
40 autoComplete?: string
41 /**
42 * @platform web
43 */
44 required?: boolean
45}
46
47export type RadixPassThroughTriggerProps = {
48 id: string
49 type: 'button'
50 disabled: boolean
51 ['data-disabled']: boolean
52 ['data-state']: string
53 ['aria-controls']?: string
54 ['aria-haspopup']?: boolean
55 ['aria-expanded']?: AccessibilityProps['aria-expanded']
56 onClick: () => void
57 onPointerDown: () => void
58 onKeyDown: () => void
59}
60
61export type TriggerProps = {
62 children: React.ReactNode | ((props: TriggerChildProps) => React.ReactNode)
63 label: string
64}
65
66export type TriggerChildProps =
67 | {
68 IS_NATIVE: true
69 control: DialogControlProps
70 state: {
71 /**
72 * Web only, `false` on native
73 */
74 hovered: false
75 focused: boolean
76 pressed: boolean
77 }
78 /**
79 * We don't necessarily know what these will be spread on to, so we
80 * should add props one-by-one.
81 *
82 * On web, these properties are applied to a parent `Pressable`, so this
83 * object is empty.
84 */
85 props: {
86 onPress: () => void
87 onFocus: () => void
88 onBlur: () => void
89 onPressIn: () => void
90 onPressOut: () => void
91 accessibilityLabel: string
92 }
93 }
94 | {
95 IS_NATIVE: false
96 state: {
97 hovered: boolean
98 focused: boolean
99 /**
100 * Native only, `false` on web
101 */
102 pressed: false
103 }
104 props: RadixPassThroughTriggerProps & {
105 onPress: () => void
106 onFocus: () => void
107 onBlur: () => void
108 onMouseEnter: () => void
109 onMouseLeave: () => void
110 accessibilityLabel: string
111 }
112 }
113
114/*
115 * For use within the `Select.Trigger` component.
116 * Shows the currently selected value. You can also
117 * provide a placeholder to show when no value is selected.
118 *
119 * If you're passing items of a different shape than {value: string, label: string},
120 * you'll need to pass a function to `children` that extracts the label from an item.
121 */
122export type ValueProps = {
123 /**
124 * Only needed for native. Extracts the label from an item. Defaults to `item => item.label`
125 */
126 children?: (value: any) => React.ReactNode
127 placeholder?: string
128 style?: StyleProp<TextStyle>
129 /**
130 * By default, web just extracts the component from inside the dropdown and portals it in here.
131 * If you want to override this, pass a value that will then be rendered via `children(value)`
132 *
133 * @platform web
134 */
135 webOverrideValue?: any
136}
137
138/*
139 * Icon for use within the `Select.Trigger` component.
140 * Changes based on platform - chevron down on web, up/down chevrons on native
141 *
142 * `style` prop is web only
143 */
144export type IconProps = TextStyleProp
145
146export type ContentProps<T> = {
147 /**
148 * Label at the top of the sheet on native.
149 *
150 * @default "Select an option"
151 */
152 label?: string
153 /**
154 * Items to render. Recommended to be in the form {value: string, label: string} - if not,
155 * you need to provide a `valueExtractor` function to extract the value from an item and
156 * customise the `Select.ValueText` component.
157 */
158 items: T[]
159 /**
160 * Renders an item. You should probably use the `Select.Item` component.
161 *
162 * @example
163 * ```tsx
164 * renderItem={({label, value}) => (
165 * <Select.Item value={value} label={label}>
166 * <Select.ItemIndicator />
167 * <Select.ItemText>{label}</Select.ItemText>
168 * </Select.Item>
169 * )}
170 * ```
171 */
172 renderItem: (
173 item: T,
174 index: number,
175 selectedValue?: string | null,
176 ) => React.ReactElement<any>
177 /*
178 * Extracts the value from an item. Defaults to `item => item.value`
179 */
180 valueExtractor?: (item: T) => string
181}
182
183/*
184 * An item within the select dropdown
185 */
186export type ItemProps = {
187 ref?: React.Ref<HTMLDivElement>
188 value: string
189 label: string
190 children: React.ReactNode
191 style?: StyleProp<ViewStyle>
192}
193
194export type ItemTextProps = {
195 children: React.ReactNode
196 style?: StyleProp<TextStyle>
197 emoji?: boolean
198}
199
200export type ItemIndicatorProps = {
201 icon?: React.ComponentType<SVGIconProps>
202}