UNPKG

@stanfordspezi/spezi-web-design-system

Version:

Stanford Biodesign Digital Health Spezi Web Design System

366 lines (365 loc) 11.1 kB
import { ReactNode, ComponentProps } from 'react'; import { Button } from '../Button'; import { Command, CommandGroup, CommandItem, CommandSeparator } from '../Command'; /** * Hook to access the Select context. Must be used within a Select component. * @throws {Error} If used outside a Select component. */ export declare const useSelectContext: () => { open: boolean; setOpen: import('react').Dispatch<import('react').SetStateAction<boolean>>; selectedValue: string | undefined; selectValue: (newValue: string) => void; items: Map<string, ItemsMapValue>; onItemAdded: (itemValue: string, value: ItemsMapValue) => void; create: CreateProp | null; search: { placeholder: string; emptyMessage: string; } | null; disabled: boolean | undefined; formatValue: ((value: string) => ReactNode) | undefined; id: string | undefined; }; interface SelectContextProps { /** * Controlled selected value. If provided, the component acts in a controlled manner. */ value?: string; /** * Default selected value for uncontrolled usage. */ defaultValue?: string; /** * Callback fired when the selected value changes. * @param value - The newly selected value */ onValueChange?: (value: string) => void; /** * Enable or disable the search input. Accepts three possible values: * - `true`: shows a search input with default placeholder and empty message. * - `false`: disables the search input. * - `object`: allows customizing the `placeholder` and `emptyMessage`. * * @default false */ search?: boolean | { placeholder?: string; emptyMessage?: string; }; /** * Enable creation of new options. Accepts three possible values: * - `true`: enables the create option with default behavior. * - `false`: disables the create option. * - `object`: allows customizing via `onCreateOption` callback and `render` function. * * @default false */ create?: boolean | CreateProp; /** * Function to format how value without a label appears when selected in the trigger and select options. * Usually, it's useful when value is created or option no longer exists in the list. * * @param value - The value of the created option * @returns ReactNode to display */ formatValue?: (value: string) => ReactNode; disabled?: boolean; /** * HTML id attribute forwarded to SelectTrigger. * Useful for associating a label with the select trigger via `htmlFor`. */ id?: string; } interface SelectProps extends SelectContextProps { /** * Child components that compose the Select (SelectTrigger, SelectContent, etc.) */ children: ReactNode; } interface ItemsMapValue { label: ReactNode; itemText?: string; } /** * Hook that manages Select component state and behavior. */ export declare const useSelectProvider: ({ value, defaultValue, onValueChange, create, search, disabled, formatValue, id, }: SelectContextProps) => { open: boolean; setOpen: import('react').Dispatch<import('react').SetStateAction<boolean>>; selectedValue: string | undefined; selectValue: (newValue: string) => void; items: Map<string, ItemsMapValue>; onItemAdded: (itemValue: string, value: ItemsMapValue) => void; create: CreateProp | null; search: { placeholder: string; emptyMessage: string; } | null; disabled: boolean | undefined; formatValue: ((value: string) => ReactNode) | undefined; id: string | undefined; }; /** * Root component that provides context for building a single-select input with search and create capabilities. * * Compose with {@link SelectTrigger}, {@link SelectValue}, and {@link SelectContent}. * * @example * ```tsx * // Basic usage * <Select> * <SelectTrigger className="w-full max-w-[400px]"> * <SelectValue placeholder="Select fruit..." /> * </SelectTrigger> * <SelectContent> * <SelectGroup> * <SelectItem value="apple">Apple</SelectItem> * <SelectItem value="banana">Banana</SelectItem> * </SelectGroup> * </SelectContent> * </Select> * ``` * * @example * ```tsx * // With search enabled * <Select search> * <SelectTrigger> * <SelectValue placeholder="Search fruits..." /> * </SelectTrigger> * <SelectContent> * <SelectGroup> * <SelectItem value="apple">Apple</SelectItem> * <SelectItem value="banana">Banana</SelectItem> * <SelectItem value="orange">Orange</SelectItem> * </SelectGroup> * </SelectContent> * </Select> * ``` * * @example * ```tsx * // With custom search configuration * <Select * search={{ * placeholder: "Type to search...", * emptyMessage: "No fruits found." * }} * > * <SelectTrigger> * <SelectValue placeholder="Select fruit..." /> * </SelectTrigger> * <SelectContent> * <SelectItem value="apple">Apple</SelectItem> * </SelectContent> * </Select> * ``` * * @example * ```tsx * // With create option enabled * <Select * search * create * > * <SelectTrigger> * <SelectValue placeholder="Select or create..." /> * </SelectTrigger> * <SelectContent> * <SelectItem value="apple">Apple</SelectItem> * </SelectContent> * </Select> * ``` * * @example * ```tsx * // With custom create option and formatValue * <Select * search * create={{ * onCreateOption: (value) => console.log("Created:", value), * render: (search) => `Add "${search}" as new option` * }} * formatValue={(value) => `Custom: ${value}`} * > * <SelectTrigger> * <SelectValue placeholder="Select or create..." /> * </SelectTrigger> * <SelectContent> * <SelectItem value="existing">Existing Option</SelectItem> * </SelectContent> * </Select> * ``` * * @example * ```tsx * // Controlled usage * const [value, setValue] = useState("apple"); * * <Select value={value} onValueChange={setValue}> * <SelectTrigger> * <SelectValue placeholder="Select fruit..." /> * </SelectTrigger> * <SelectContent> * <SelectItem value="apple">Apple</SelectItem> * <SelectItem value="banana">Banana</SelectItem> * </SelectContent> * </Select> * ``` */ export declare const Select: ({ children, ...props }: SelectProps) => import("react").JSX.Element; interface SelectTriggerProps extends Omit<ComponentProps<typeof Button>, "size" | "variant"> { } /** * Clickable trigger element that opens the selection popover. * * Renders like an input using the Button component. Place `SelectValue` inside to show selected item. * * @example * ```tsx * <SelectTrigger> * <SelectValue placeholder="Choose an option..." /> * </SelectTrigger> * ``` */ export declare const SelectTrigger: ({ role, "aria-expanded": propsAriaExpanded, className, children, id: propsId, ...props }: SelectTriggerProps) => import("react").JSX.Element; interface SelectValueProps extends Omit<ComponentProps<"span">, "children"> { /** * Placeholder text to show when no item is selected. */ placeholder?: string; } /** * Displays the current selection inside the trigger. * * @example * ```tsx * <SelectTrigger> * <SelectValue placeholder="Select a tag..." /> * </SelectTrigger> * ``` */ export declare const SelectValue: ({ placeholder, className, ...props }: SelectValueProps) => import("react").JSX.Element; interface CreateProp { /** * Callback fired when a new option is created. * @param value - The value of the newly created option */ onCreateOption?: (value: string) => void; /** * Function to customize how the "create" option appears in the list. * @param search - The current search term * @returns ReactNode to display */ render?: (search: string) => ReactNode; } interface SelectContentProps extends Omit<ComponentProps<typeof Command>, "children"> { /** * Child components, typically SelectGroup, SelectItem, and SelectSeparator */ children: ReactNode; } /** * Popover content that renders the `Command`-based searchable list of items. * * Automatically includes search input and create option if enabled via the parent Select component. * * @example * ```tsx * <SelectContent> * <SelectGroup> * <SelectItem value="apple">Apple</SelectItem> * <SelectItem value="banana">Banana</SelectItem> * </SelectGroup> * </SelectContent> * ``` * * @example * ```tsx * // With groups and separator * <SelectContent> * <SelectGroup heading="Fruits"> * <SelectItem value="apple">Apple</SelectItem> * </SelectGroup> * <SelectSeparator /> * <SelectGroup heading="Vegetables"> * <SelectItem value="carrot">Carrot</SelectItem> * </SelectGroup> * </SelectContent> * ``` */ export declare const SelectContent: ({ children, ...props }: SelectContentProps) => import("react").JSX.Element; interface SelectItemProps extends Omit<ComponentProps<typeof CommandItem>, "value" | "onSelect"> { /** * Provide itemText only if `children` is a complex ReactNode element. */ itemText?: string; /** * The unique value for this item within the selection. */ value: string; /** * Optional callback fired when this item is selected. * @param value - The value of the selected item */ onSelect?: (value: string) => void; /** * Whether to register this item in the Select's internal items map. * Set to false for internal items like the create option. * @default true */ addToItems?: boolean; } /** * Selectable item within the list. * * Displays a checkmark when selected and handles selection state automatically. * * @example * ```tsx * <SelectItem value="apple">Apple</SelectItem> * ``` * * @example * ```tsx * <SelectItem * value="banana" * onSelect={(value) => console.log("Selected:", value)} * > * Banana * </SelectItem> * ``` */ export declare const SelectItem: ({ value, children, onSelect, addToItems, itemText, ...props }: SelectItemProps) => import("react").JSX.Element; /** * Group wrapper for grouping related `SelectItem`s under a heading. * * @example * ```tsx * <SelectGroup heading="Fruits"> * <SelectItem value="apple">Apple</SelectItem> * </SelectGroup> * ``` */ export declare const SelectGroup: (props: ComponentProps<typeof CommandGroup>) => import("react").JSX.Element; /** * Visual separator between groups or sections in the list. * * @example * ```tsx * <> * <SelectGroup heading="A" /> * <SelectSeparator /> * <SelectGroup heading="B" /> * </> * ``` */ export declare const SelectSeparator: (props: ComponentProps<typeof CommandSeparator>) => import("react").JSX.Element; interface SelectCreateItemProps extends CreateProp { } /** * Component that renders the "create new option" item when the create feature is enabled. */ export declare const SelectCreateItem: ({ onCreateOption, render, }: SelectCreateItemProps) => import("react").JSX.Element; export {};