UNPKG

@itwin/itwinui-react

Version:

A react component library for iTwinUI

281 lines (280 loc) 8.43 kB
import * as React from 'react'; import type { CommonProps, PortalProps } from '../../utils/index.js'; import { usePopover } from '../Popover/Popover.js'; /** * Select component to select value from options. * Generic type is used for value. It prevents you from mistakenly using other types in `options`, `value` and `onChange`. * @example * <caption>Basic select.</caption> * <Select * options={[ * { value: '1', label: 'Option 1' }, * { value: '2', label: 'Option 2' }, * { value: '3', label: 'Option 3' }, * ]} * /> * @example * <caption>Native select.</caption> * <Select * native * options={[ * { value: '1', label: 'Option 1' }, * { value: '2', label: 'Option 2' }, * { value: '3', label: 'Option 3' }, * ]} * /> * @example * <caption>Disabled select with placeholder.</caption> * <Select * disabled={true} * placeholder='Placeholder text' * options={[{ value: 1, label: 'Option 1' }, { value: 2, label: 'Option 2' }, { value: 3, label: 'Option 3' }]} * /> * @example * <caption>Select with selected value and change handler.</caption> * <Select * value={selectedValue} * onChange={(value) => setSelectedValue(value)} * options={[{ value: 1, label: 'Option 1' }, { value: 2, label: 'Option 2' }, { value: 3, label: 'Option 3' }]} * /> * @example * <caption>Select using custom renderers for menu items and selected value.</caption> * <Select * options={[ * { value: 'yellow', label: 'Yellow' }, * { value: 'green', label: 'Green' }, * { value: 'red', label: 'Red' }, * ]} * value={selectedValue} * placeholder='Placeholder text' * itemRenderer={(option, itemProps) => ( * <MenuItem * style={{ color: option.value }} * isSelected={itemProps.isSelected} * onClick={() => { * setSelectedValue(option.value); * itemProps.close(); * }} * role='option' * ref={(el) => itemProps.isSelected && el?.scrollIntoView()} * > * {option.label} * </MenuItem> * )} * selectedItemRenderer={(option) => ( * <span style={{ backgroundColor: option.value }}>{option.label}</span> * )} * /> */ export declare const Select: <T>(props: SelectProps<T> & { ref?: React.ForwardedRef<HTMLElement>; }) => React.JSX.Element; export type SelectProps<T> = Omit<React.ComponentPropsWithoutRef<'div'>, 'onChange' | 'placeholder' | 'value' | 'defaultValue'> & (({ /** * If true, the native `<select>` element will be rendered. * * Extra props, such as `name` can be passed to the `<select>` using `triggerProps`. * * @default false */ native: true; } & NativeSelectProps) | ({ native?: false; } & CustomSelectProps<T> & { /** * styleType is only supported for `<Select native>`. */ styleType?: never; })); type NativeSelectProps = SelectCommonProps & { /** * Selected option value. * * Must be a string, because it is passed as an attribute to the native <select>. * * Alternatively, pass `null` to reset the value. */ value?: string | null; /** * Callback invoked when the selected value changes. */ onChange?: (value: string, event: React.ChangeEvent<HTMLSelectElement>) => void; /** * Array of options that populates the select menu. * * The `value` property of each option must be a string. */ options: Array<{ label: string; value: string; disabled?: boolean; }>; /** * Default value that is selected on initial render. This is useful when you don't want to * maintain your own state but still want to control the initial value. * * If not passed, the first option (or placeholder) will be automatically selected. */ defaultValue?: string; /** * Props to pass to the select element. */ triggerProps?: Omit<React.ComponentPropsWithRef<'select'>, 'size'>; required?: boolean; multiple?: never; } & NativeSelectStyleTypeProps; type NativeSelectStyleTypeProps = { /** * Style of the select. * Use 'borderless' to hide outline. * @default 'default' */ styleType?: 'default'; /** * Placeholder for when no item is selected. * * Will be rendered as a disabled option at the top of the list, and automatically * selected when no `value` or `defaultValue` is provided. * * Not allowed when `styleType` is `borderless`. */ placeholder?: string; } | { styleType: 'borderless'; placeholder?: never; }; type SelectCommonProps = { /** * Disables select. * @default false */ disabled?: boolean; /** * Modify size of select. */ size?: 'small' | 'large'; /** * Status of select. */ status?: 'positive' | 'warning' | 'negative'; }; export type CustomSelectProps<T> = SelectCommonProps & { /** * Placeholder when no item is selected. */ placeholder?: React.ReactNode; /** * Array of options that populates the select menu. */ options: SelectOption<T>[]; /** * Custom renderer for an item in the dropdown list. `MenuItem` item props are going to be populated if not provided. */ itemRenderer?: (option: SelectOption<T>, itemProps: ItemRendererProps) => React.JSX.Element; /** * Custom class for menu. */ menuClassName?: string; /** * Custom style for menu. */ menuStyle?: React.CSSProperties; /** * Props to customize Popover behavior. */ popoverProps?: Pick<Parameters<typeof usePopover>[0], 'visible' | 'onVisibleChange' | 'placement' | 'matchWidth' | 'closeOnOutsideClick'> & { /** * Middleware options. * * By default, `hide` is enabled. If the floating options get hidden even when they shouldn't (e.g. some custom * styles interfering with the trigger's hide detection) consider disabling the `hide` middleware. * * @see https://floating-ui.com/docs/middleware */ middleware?: { hide?: boolean; }; } & Pick<PortalProps, 'portal'>; /** * Props to pass to the select button (trigger) element. */ triggerProps?: React.ComponentPropsWithRef<'div'>; } & SelectMultipleTypeProps<T> & Omit<React.ComponentPropsWithoutRef<'div'>, 'size' | 'disabled' | 'placeholder' | 'onChange'>; export type SelectValueChangeEvent = 'added' | 'removed'; export type SelectMultipleTypeProps<T> = { /** * Enable multiple selection. * @default false */ multiple?: false; /** * Custom renderer for the selected item in select. * If `multiple` is enabled, it will give array of options to render. */ selectedItemRenderer?: (option: SelectOption<T>) => React.JSX.Element; /** * Selected option value. * If `multiple` is enabled, it is an array of values. * * Pass `null` to reset the value. */ value?: T | null; /** * Callback function handling change event on select. */ onChange?: (value: T) => void; } | { multiple: true; selectedItemRenderer?: (options: SelectOption<T>[]) => React.JSX.Element; value?: T[]; onChange?: (value: T, event: SelectValueChangeEvent) => void; }; export type ItemRendererProps = { /** * Close handler that closes the dropdown. */ close: () => void; /** * Indicates whether an item is selected. */ isSelected: boolean; }; export type SelectOption<T> = { /** * Label of the item used in dropdown list and when selected. */ label: string; /** * Sublabel of the item shown below the label. */ sublabel?: React.ReactNode; /** * Modify height of the item. * Use 'large' when any of the select options have `sublabel`. * * Defaults to 'large' if `sublabel` provided, otherwise 'default'. */ size?: 'default' | 'large'; /** * Value of the item. */ value: T; /** * @deprecated Use startIcon * SVG icon component shown on the left. */ icon?: React.JSX.Element; /** * SVG icon component shown on the left. */ startIcon?: React.JSX.Element; /** * Item is disabled. */ disabled?: boolean; /** * Any other props. */ [key: string]: unknown; } & CommonProps; export {};