UNPKG

@yamada-ui/react

Version:

React UI components of the Yamada, by the Yamada, for the Yamada built with React and Emotion

1 lines • 15.8 kB
{"version":3,"file":"use-select.cjs","names":["defaultRender: SelectItemRender","createContext","useI18n","useFieldProps","useControllableState","value","items","useCombobox","valueMap: { [key: string]: ComboboxItemWithValue }","item","valueMap","onClear","getRootProps: PropGetter","props","getFieldProps: PropGetter","mergeRefs","getInputProps: PropGetter<\"input\">","visuallyHiddenAttributes","getContentProps: PropGetter","getIconProps: PropGetter","runKeyAction","useComboboxItem"],"sources":["../../../../src/components/select/use-select.tsx"],"sourcesContent":["\"use client\"\n\nimport type { MouseEvent, ReactNode } from \"react\"\nimport type { HTMLProps, PropGetter } from \"../../core\"\nimport type {\n ComboboxItem,\n ComboboxItemWithValue,\n UseComboboxItemProps,\n UseComboboxProps,\n} from \"../../hooks/use-combobox\"\nimport type { Dict } from \"../../utils\"\nimport type { FieldProps } from \"../field\"\nimport {\n cloneElement,\n isValidElement,\n useCallback,\n useMemo,\n useRef,\n} from \"react\"\nimport { useCombobox, useComboboxItem } from \"../../hooks/use-combobox\"\nimport { useControllableState } from \"../../hooks/use-controllable-state\"\nimport { useI18n } from \"../../providers/i18n-provider\"\nimport {\n ariaAttr,\n createContext,\n cx,\n dataAttr,\n handlerAll,\n isArray,\n isNumber,\n isString,\n isUndefined,\n mergeRefs,\n runKeyAction,\n toArray,\n visuallyHiddenAttributes,\n} from \"../../utils\"\nimport { useFieldProps } from \"../field\"\n\ninterface SelectRenderProps extends ComboboxItemWithValue {\n count: number\n index: number\n separator: string\n onClear: () => void\n}\n\nexport interface SelectItemRender {\n (props: SelectRenderProps): ReactNode\n}\n\nconst defaultRender: SelectItemRender = ({\n count,\n index,\n label,\n separator,\n value,\n}) => {\n const last = count - 1 === index\n\n return (\n <span\n style={{ marginInlineEnd: \"var(--gap)\" }}\n data-placeholder={dataAttr(value === \"\")}\n >\n {label}\n {!last ? separator : null}\n </span>\n )\n}\n\ninterface SelectContext extends Pick<UseSelectReturn, \"max\" | \"value\"> {}\n\nconst [SelectContext, useSelectContext] = createContext<SelectContext>({\n name: \"SelectContext\",\n})\n\nexport { SelectContext, useSelectContext }\n\nexport interface UseSelectProps<Multiple extends boolean = false>\n extends Omit<HTMLProps, \"defaultValue\" | \"onChange\" | \"value\">,\n Omit<\n UseComboboxProps,\n \"defaultValue\" | \"initialFocusValue\" | \"onChange\" | \"value\"\n >,\n FieldProps {\n /**\n * The `id` attribute of the input element.\n */\n id?: string\n /**\n * The `name` attribute of the input element.\n */\n name?: string\n /**\n * The initial value of the select.\n */\n defaultValue?: Multiple extends true ? string[] : string\n /**\n * If `true`, the field will be focused when the clear icon is clicked.\n *\n * @default true\n */\n focusOnClear?: boolean\n /**\n * If `true`, include placeholder in options.\n *\n * @default true\n */\n includePlaceholder?: boolean\n /**\n * If provided, generate options based on items.\n *\n * @default []\n */\n items?: ComboboxItem[]\n /**\n * The maximum selectable value.\n */\n max?: number\n /**\n * If `true`, the select will be multiple.\n *\n * @default false\n */\n multiple?: Multiple\n /**\n * The placeholder for select.\n */\n placeholder?: string\n /**\n * The function to render the selected items.\n */\n render?: (props: SelectRenderProps) => ReactNode\n /**\n * The visual separator between each value.\n *\n * @default ','\n */\n separator?: string\n /**\n * The value of the select.\n */\n value?: Multiple extends true ? string[] : string\n /**\n * The callback invoked when value state changes.\n */\n onChange?: (value: Multiple extends true ? string[] : string) => void\n}\n\nexport const useSelect = <Multiple extends boolean = false>(\n props: UseSelectProps<Multiple> = {},\n) => {\n type MaybeValue = Multiple extends true ? string[] : string\n\n const { t } = useI18n(\"select\")\n const {\n context: { labelId } = {},\n props: {\n id,\n name,\n multiple = false,\n closeOnSelect = !multiple,\n defaultValue = (multiple ? [] : \"\") as MaybeValue,\n disabled,\n focusOnClear = true,\n includePlaceholder = !multiple,\n items: itemProp = [],\n max,\n placeholder,\n readOnly,\n render = defaultRender,\n required,\n separator = \",\",\n value: valueProp,\n onChange: onChangeProp,\n ...rest\n },\n ariaProps,\n dataProps,\n eventProps,\n } = useFieldProps(props)\n const fieldRef = useRef<HTMLDivElement>(null)\n const [value, setValue] = useControllableState({\n defaultValue,\n value: valueProp,\n onChange: onChangeProp,\n })\n const onChange = useCallback(\n (value: string) => {\n setValue((prev) => {\n if (isArray(prev)) {\n if (prev.includes(value)) {\n return prev.filter((prevValue) => prevValue !== value) as MaybeValue\n } else if (!isNumber(max) || prev.length < max) {\n return [...prev, value] as MaybeValue\n } else {\n return prev\n }\n } else {\n return value as MaybeValue\n }\n })\n },\n [max, setValue],\n )\n const items = useMemo<ComboboxItem[]>(() => {\n const items = [...itemProp]\n\n if (placeholder)\n items.unshift({\n hidden: !includePlaceholder,\n label: placeholder,\n value: \"\",\n })\n\n return items\n }, [itemProp, placeholder, includePlaceholder])\n const empty = useMemo(\n () => !items.filter(({ hidden }) => !hidden).length,\n [items],\n )\n const {\n descendants,\n interactive,\n open,\n getContentProps: getComboboxContentProps,\n getSeparatorProps,\n getTriggerProps,\n popoverProps,\n onActiveDescendant,\n onClose,\n onOpen,\n onSelect,\n } = useCombobox({\n closeOnSelect,\n disabled,\n initialFocusValue: isArray(value) ? value[0] : value,\n readOnly,\n onChange,\n ...ariaProps,\n ...dataProps,\n ...eventProps,\n ...rest,\n })\n const valueMap = useMemo<{ [key: string]: ComboboxItemWithValue }>(() => {\n const valueMap: { [key: string]: ComboboxItemWithValue } = {}\n\n items.forEach((item) => {\n if (\"items\" in item) {\n item.items.forEach((item) => {\n item.value ??= isString(item.label) ? item.label : undefined\n\n if (!isUndefined(item.value)) valueMap[item.value] = item\n })\n } else {\n item.value ??= isString(item.label) ? item.label : undefined\n\n if (!isUndefined(item.value)) valueMap[item.value] = item\n }\n })\n\n return valueMap\n }, [items])\n const selectedItems = useMemo<ComboboxItemWithValue[]>(() => {\n if (isArray(value)) {\n if (value.length) {\n return toArray(value.map((value) => valueMap[value]))\n } else {\n return placeholder ? [{ label: placeholder, value: \"\" }] : []\n }\n } else {\n return isString(value) ? toArray(valueMap[value]) : []\n }\n }, [placeholder, value, valueMap])\n const children = useMemo<ReactNode>(() => {\n const count = selectedItems.length\n\n return selectedItems.map((item, index) => {\n const onClear = (ev?: MouseEvent<HTMLElement>) => {\n ev?.preventDefault()\n ev?.stopPropagation()\n\n if (item.value) onChange(item.value)\n }\n\n const component = render({\n count,\n index,\n separator,\n onClear,\n ...item,\n })\n\n if (isValidElement<Dict>(component)) {\n return cloneElement(component, { ...component.props, key: index })\n } else {\n return component\n }\n })\n }, [onChange, render, selectedItems, separator])\n\n const onFocus = useCallback(() => {\n if (!interactive || !fieldRef.current) return\n\n fieldRef.current.focus()\n }, [interactive])\n\n const onClear = useCallback(() => {\n if (!interactive) return\n\n setValue((prev) => (isArray(prev) ? [] : \"\") as MaybeValue)\n\n if (!fieldRef.current) return\n\n if (focusOnClear) fieldRef.current.focus()\n }, [focusOnClear, interactive, setValue])\n\n const getRootProps: PropGetter = useCallback(\n (props) => ({ ...dataProps, ...props }),\n [dataProps],\n )\n\n const getFieldProps: PropGetter = useCallback(\n ({ ref, \"aria-labelledby\": ariaLabelledby, ...props } = {}) =>\n getTriggerProps({\n ref: mergeRefs(ref, fieldRef),\n \"aria-label\": placeholder,\n \"aria-labelledby\": cx(ariaLabelledby, labelId),\n ...props,\n children,\n }),\n [children, getTriggerProps, labelId, placeholder],\n )\n\n const getInputProps: PropGetter<\"input\"> = useCallback(\n (props = {}) => ({\n ...dataProps,\n ...visuallyHiddenAttributes,\n id,\n name,\n defaultValue: isString(value) ? value : value.join(\", \"),\n disabled,\n readOnly,\n required,\n ...props,\n onFocus: handlerAll(props.onFocus, onFocus),\n }),\n [dataProps, disabled, id, name, onFocus, readOnly, required, value],\n )\n\n const getContentProps: PropGetter = useCallback(\n (props) => getComboboxContentProps({ hidden: empty, ...props }),\n [empty, getComboboxContentProps],\n )\n\n const getIconProps: PropGetter = useCallback(\n (props) => ({ ...dataProps, ...props }),\n [dataProps],\n )\n\n const getClearIconProps: PropGetter = useCallback(\n (props = {}) =>\n getIconProps({\n \"aria-disabled\": ariaAttr(!interactive),\n \"aria-label\": t(\"Clear value\"),\n role: \"button\",\n tabIndex: interactive ? 0 : -1,\n ...props,\n onClick: handlerAll(props.onClick, onClear),\n onKeyDown: handlerAll(props.onKeyDown, (ev) =>\n runKeyAction(ev, { Enter: onClear, Space: onClear }),\n ),\n }),\n [getIconProps, interactive, onClear, t],\n )\n\n return {\n descendants,\n includePlaceholder,\n interactive,\n items,\n max,\n open,\n placeholder,\n setValue,\n value,\n valueMap,\n getClearIconProps,\n getContentProps,\n getFieldProps,\n getIconProps,\n getInputProps,\n getRootProps,\n getSeparatorProps,\n popoverProps,\n onActiveDescendant,\n onChange,\n onClose,\n onOpen,\n onSelect,\n }\n}\n\nexport type UseSelectReturn = ReturnType<typeof useSelect>\n\nexport interface UseSelectOptionProps extends UseComboboxItemProps {}\n\nexport const useSelectOption = ({\n children,\n closeOnSelect,\n disabled,\n hidden,\n value,\n ...rest\n}: UseSelectOptionProps = {}) => {\n const { max, value: selectedValue } = useSelectContext()\n\n value ??= isString(children) ? children : undefined\n\n const selected = isArray(selectedValue)\n ? !isUndefined(value) && selectedValue.includes(value)\n : selectedValue === value\n const completed =\n isNumber(max) && isArray(selectedValue) && selectedValue.length >= max\n const { getIndicatorProps, getItemProps } = useComboboxItem({\n children,\n closeOnSelect,\n disabled: disabled || hidden || (completed && !selected),\n hidden,\n selected,\n value,\n ...rest,\n })\n\n const getOptionProps: PropGetter = useCallback(\n (props = {}) => getItemProps(props),\n [getItemProps],\n )\n\n return { getIndicatorProps, getOptionProps }\n}\n\nexport type UseSelectOptionReturn = ReturnType<typeof useSelectOption>\n"],"mappings":"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"}