@stanfordspezi/spezi-web-design-system
Version:
Stanford Biodesign Digital Health Spezi Web Design System
366 lines (365 loc) • 11.1 kB
TypeScript
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 {};