about summary refs log tree commit diff
path: root/src/components/Select/types.ts
diff options
context:
space:
mode:
authorSamuel Newman <mozzius@protonmail.com>2025-05-06 20:27:05 +0300
committerGitHub <noreply@github.com>2025-05-06 10:27:05 -0700
commit973538d246a3f76550611e438152f1a6cad75f49 (patch)
tree83c7547eb9ba1123bac8ab8ef30f37d5164b3ce2 /src/components/Select/types.ts
parent25f8506c4152840e83ba9210452b60ea5cc0987f (diff)
downloadvoidsky-973538d246a3f76550611e438152f1a6cad75f49.tar.zst
New `Select` component (#8323)
* radix select component on web

* native implementation (wip)

* fix sheet height/padding

* tone down web styles

* react 19 cleanup

* replace primary language select

* change style on native

* get auto placeholder working

* more style tweaks

* replace app language dropdown

* replace rnpickerselect with native select

* rm react-native-picker-select dependency

* rm placeholder, since a value is always selected

* docblock for renderItem

* add more docblocks

* add style prop to item

* pass selectedValue through renderItem

* fix context

* Style overflow buttons

---------

Co-authored-by: Eric Bailey <git@esb.lol>
Diffstat (limited to 'src/components/Select/types.ts')
-rw-r--r--src/components/Select/types.ts185
1 files changed, 185 insertions, 0 deletions
diff --git a/src/components/Select/types.ts b/src/components/Select/types.ts
new file mode 100644
index 000000000..5c1b80a3b
--- /dev/null
+++ b/src/components/Select/types.ts
@@ -0,0 +1,185 @@
+import {
+  type AccessibilityProps,
+  type StyleProp,
+  type TextStyle,
+  type ViewStyle,
+} from 'react-native'
+
+import {type TextStyleProp} from '#/alf'
+import {type DialogControlProps} from '#/components/Dialog'
+import {type Props as SVGIconProps} from '#/components/icons/common'
+
+export type RootProps = {
+  children?: React.ReactNode
+  value?: string
+  onValueChange?: (value: string) => void
+  disabled?: boolean
+  /**
+   * @platform web
+   */
+  defaultValue?: string
+  /**
+   * @platform web
+   */
+  open?: boolean
+  /**
+   * @platform web
+   */
+  defaultOpen?: boolean
+  /**
+   * @platform web
+   */
+  onOpenChange?(open: boolean): void
+  /**
+   * @platform web
+   */
+  name?: string
+  /**
+   * @platform web
+   */
+  autoComplete?: string
+  /**
+   * @platform web
+   */
+  required?: boolean
+}
+
+export type RadixPassThroughTriggerProps = {
+  id: string
+  type: 'button'
+  disabled: boolean
+  ['data-disabled']: boolean
+  ['data-state']: string
+  ['aria-controls']?: string
+  ['aria-haspopup']?: boolean
+  ['aria-expanded']?: AccessibilityProps['aria-expanded']
+  onPress: () => void
+}
+
+export type TriggerProps = {
+  children: React.ReactNode | ((props: TriggerChildProps) => React.ReactNode)
+  label: string
+}
+
+export type TriggerChildProps =
+  | {
+      isNative: true
+      control: DialogControlProps
+      state: {
+        /**
+         * Web only, `false` on native
+         */
+        hovered: false
+        focused: boolean
+        pressed: boolean
+      }
+      /**
+       * We don't necessarily know what these will be spread on to, so we
+       * should add props one-by-one.
+       *
+       * On web, these properties are applied to a parent `Pressable`, so this
+       * object is empty.
+       */
+      props: {
+        onPress: () => void
+        onFocus: () => void
+        onBlur: () => void
+        onPressIn: () => void
+        onPressOut: () => void
+        accessibilityLabel: string
+      }
+    }
+  | {
+      isNative: false
+      state: {
+        hovered: boolean
+        focused: boolean
+        /**
+         * Native only, `false` on web
+         */
+        pressed: false
+      }
+      props: RadixPassThroughTriggerProps & {
+        onPress: () => void
+        onFocus: () => void
+        onBlur: () => void
+        onMouseEnter: () => void
+        onMouseLeave: () => void
+        accessibilityLabel: string
+      }
+    }
+
+/*
+ * For use within the `Select.Trigger` component.
+ * Shows the currently selected value. You can also
+ * provide a placeholder to show when no value is selected.
+ *
+ * If you're passing items of a different shape than {value: string, label: string},
+ * you'll need to pass a function to `children` that extracts the label from an item.
+ */
+export type ValueProps = {
+  /**
+   * Only needed for native. Extracts the label from an item. Defaults to `item => item.label`
+   */
+  children?: (value: any) => string
+  placeholder?: string
+  style?: StyleProp<TextStyle>
+}
+
+/*
+ * Icon for use within the `Select.Trigger` component.
+ * Changes based on platform - chevron down on web, up/down chevrons on native
+ *
+ * `style` prop is web only
+ */
+export type IconProps = TextStyleProp
+
+export type ContentProps<T> = {
+  /**
+   * Items to render. Recommended to be in the form {value: string, label: string} - if not,
+   * you need to provide a `valueExtractor` function to extract the value from an item and
+   * customise the `Select.ValueText` component.
+   */
+  items: T[]
+  /**
+   * Renders an item. You should probably use the `Select.Item` component.
+   *
+   * @example
+   * ```tsx
+   * renderItem={({label, value}) => (
+   *   <Select.Item value={value} label={label}>
+   *     <Select.ItemIndicator />
+   *     <Select.ItemText>{label}</Select.ItemText>
+   *   </Select.Item>
+   * )}
+   * ```
+   */
+  renderItem: (
+    item: T,
+    index: number,
+    selectedValue?: string | null,
+  ) => React.ReactElement
+  /*
+   * Extracts the value from an item. Defaults to `item => item.value`
+   */
+  valueExtractor?: (item: T) => string
+}
+
+/*
+ * An item within the select dropdown
+ */
+export type ItemProps = {
+  ref?: React.Ref<HTMLDivElement>
+  value: string
+  label: string
+  children: React.ReactNode
+  style?: StyleProp<ViewStyle>
+}
+
+export type ItemTextProps = {
+  children: React.ReactNode
+}
+
+export type ItemIndicatorProps = {
+  icon?: React.ComponentType<SVGIconProps>
+}