Combobox组件构建于Popover组件之上. Combobox组件被设计用于构建具有下拉选项列表的复合输入组件的低级组件.
@rtdui/core中的Select,AutoComplete,MultiSelect组件都基于Combobox组件实现.
Combobox组件预定义一组独立的子组件, 可以自由的控制渲染和逻辑:
Combobox.Target - 用于包裹触发下拉的组件, 如Input组件. 注意: 并不是必须为input元素.
Combobox.Dropdown - 用于包裹下拉框的组件.
Combobox.Options - 用于包裹Option的组件
Combobox.Option - 用于包括自定义选项的组件
Combobox.Search - 用于在下拉框中提供额外的过滤组件
Combobox.Empty - 用于未匹配过滤条件时下拉框内容
Combobox.Chevron - 用于Target右侧的下拉指示图表
Combobox.Header - 用于为下拉提供固定的头部组件
Combobox.Footer - 用于为下拉提供固定的底部组件
Combobox.EventsTarget - 当下拉定位目标和事件目标不同时, 用于包括事件目标, 作为下拉框的事件目标, 同一Combobox下可以有多个.
Combobox.DropdownTarget - 当下拉定位目标和事件目标不同时, 用于包裹下拉目标, 作为下拉框的定位目标, 同一Combobox下最多只能有一个.
Combobox.Group - 用于选项组的组件
Combobox.ClearButton - 用于清除选择的按钮组件
Combobox.HiddenInput - 隐藏的表单域, 用于存储选择的实际值用于表单提交.
你完全可以使用Combobox及其子组件自定义实现你自己的Select,AutoComplete,MultiSelect组件
useCombobox 钩子用于创建 combobox 的存储对象. 该存储对象包含了组件的当前状态和更新处理函数. 创建的存储必须传递给Combobox的store属性:
import { Combobox, useCombobox } from "@rtdui/core";
function Demo() {
const combobox = useCombobox();
return <Combobox store={combobox}>{/* Your implementation */}</Combobox>;
}
interface UseComboboxOptions {
/** Default value for `dropdownOpened`, `false` by default */
defaultOpened?: boolean;
/** Controlled `dropdownOpened` state */
opened?: boolean;
/** Called when `dropdownOpened` state changes */
onOpenedChange?(opened: boolean): void;
/** Called when dropdown closes with event source: keyboard, mouse or unknown */
onDropdownClose?(eventSource: ComboboxDropdownEventSource): void;
/** Called when dropdown opens with event source: keyboard, mouse or unknown */
onDropdownOpen?(eventSource: ComboboxDropdownEventSource): void;
/** Determines whether arrow key presses should loop though items (first to last and last to first), `true` by default */
loop?: boolean;
/** `behavior` passed down to `element.scrollIntoView`, `'instant'` by default */
scrollBehavior?: ScrollBehavior;
}
你可以从@rtdui/core导入UseComboboxOptions类型:
import type { UseComboboxOptions } from "@rtdui/core";
interface ComboboxStore {
/** Current dropdown opened state */
dropdownOpened: boolean;
/** Opens dropdown */
openDropdown(eventSource?: "keyboard" | "mouse" | "unknown"): void;
/** Closes dropdown */
closeDropdown(eventSource?: "keyboard" | "mouse" | "unknown"): void;
/** Toggles dropdown opened state */
toggleDropdown(eventSource?: "keyboard" | "mouse" | "unknown"): void;
/** Selected option index */
selectedOptionIndex: number;
/** Selects `Combobox.Option` by index */
selectOption(index: number): void;
/** Selects first `Combobox.Option` with `active` prop.
* If there are no such options, the function does nothing.
*/
selectActiveOption(): string | null;
/** Selects first `Combobox.Option` that is not disabled.
* If there are no such options, the function does nothing.
* */
selectFirstOption(): string | null;
/** Selects next `Combobox.Option` that is not disabled.
* If the current option is the last one, the function selects first option, if `loop` is true.
*/
selectNextOption(): string | null;
/** Selects previous `Combobox.Option` that is not disabled.
* If the current option is the first one, the function selects last option, if `loop` is true.
* */
selectPreviousOption(): string | null;
/** Resets selected option index to -1, removes `data-combobox-selected` from selected option */
resetSelectedOption(): void;
/** Triggers `onClick` event of selected option.
* If there is no selected option, the function does nothing.
*/
clickSelectedOption(): void;
/** Updates selected option index to currently selected or active option.
* The function is required to be used with searchable components to update selected option index
* when options list changes based on search query.
*/
updateSelectedOptionIndex(target?: "active" | "selected"): void;
/** List id, used for `aria-*` attributes */
listId: string | null;
/** Sets list id */
setListId(id: string): void;
/** Ref of `Combobox.Search` input */
searchRef: React.MutableRefObject<HTMLInputElement | null>;
/** Moves focus to `Combobox.Search` input */
focusSearchInput(): void;
/** Ref of the target element */
targetRef: React.MutableRefObject<HTMLElement | null>;
/** Moves focus to the target element */
focusTarget(): void;
}
可以从 @rtdui/core导入ComboboxStore类型 :
import type { ComboboxStore } from "@rtdui/core";
可以在useCombobox的选项参数中使用存储中的处理函数, 如:
import { Combobox, useCombobox } from "@rtdui/core";
function Demo() {
const combobox = useCombobox({
onDropdownOpen: () => combobox.selectFirstOption(),
onDropdownClose: () => combobox.resetSelectedOption(),
});
return <Combobox store={combobox}>{/* Your implementation */}</Combobox>;
}
| 属性名 | 类型 | 是否必须 | 默认值 | 说明 |
|---|---|---|---|---|
| arrowOffset | number | undefined | no | 10 | Arrow offset in px |
| arrowPosition | ArrowPosition | undefined | no | "side" | Arrow position |
| arrowRadius | number | undefined | no | 0 | Arrow <code>border-radius</code> in px |
| arrowSize | number | undefined | no | 7 | Arrow size in px |
| children | React.ReactNode | no | Combobox content | |
| clickOutsideEvents | string[] | undefined | no | ["mousedown", "touchstart"] | Events that trigger outside clicks |
| closeOnClickOutside | boolean | undefined | no | true | Determines whether dropdown should be closed on outside clicks |
| closeOnEscape | boolean | undefined | no | true | Determines whether dropdown should be closed when <code>Escape</code> key is pressed |
| defaultOpened | boolean | undefined | no | Initial opened state for uncontrolled component | |
| disabled | boolean | undefined | no | If set, popover dropdown will not be rendered | |
| dropdownColor | string | undefined | no | background color of dropdown and arrow, default 'bg-base-100' | |
| dropdownPadding | Padding<string | number> | undefined | no | 4 | Controls <code>padding</code> of the dropdown |
| floatingStrategy | FloatingStrategy | undefined | no | "absolute" | Changes floating ui [position strategy](https://floating-ui.com/docs/usefloating#strategy) |
| id | string | undefined | no | id base to create accessibility connections | |
| keepMounted | boolean | undefined | no | If set dropdown will not be unmounted from the DOM when it is hidden, <code>display: none</code> styles will be added instead | |
| middlewares | PopoverMiddlewares | undefined | no | { flip: true, shift: true, inline: false } | Floating ui middlewares to configure position handling |
| offset | number | FloatingAxesOffsets | undefined | no | 8 | Offset of the dropdown element |
| onChange | ((opened: boolean) => void) | undefined | no | Called with current state when dropdown opens or closes | |
| onClose | (() => void) | undefined | no | Called when dropdown closes | |
| onOpen | (() => void) | undefined | no | Called when dropdown opens | |
| onOptionSubmit | ((value: string, optionProps: ComboboxOptionProps) => void) | undefined | no | Called when item is selected with <code>Enter</code> key or by clicking it | |
| onPositionChange | ((position: FloatingPosition) => void) | undefined | no | Called when dropdown position changes | |
| opened | boolean | undefined | no | Controlled dropdown opened state | |
| optionPadding | ThemeBaseSize | undefined | no | sm | Controls <code>padding</code> of the Option |
| portalProps | Omit<PortalProps, "children"> | undefined | no | Props to pass down to the <code>Portal</code> when <code>withinPortal</code> is true | |
| position | FloatingPosition | undefined | no | "bottom" | Dropdown position relative to the target element |
| positionDependencies | any[] | undefined | no | [] | <code>useEffect</code> dependencies to force update dropdown position |
| radius | string | undefined | no | "md" | Key of <code>theme.radius</code> or any valid CSS value to set border-radius |
| readOnly | boolean | undefined | no | Determines whether Combobox value can be changed | |
| resetSelectionOnOptionHover | boolean | undefined | no | false | Determines whether selection should be reset when option is hovered |
| returnFocus | boolean | undefined | no | false | Determines whether focus should be automatically returned to control when dropdown closes |
| shadow | ThemeShadow | undefined | no | "md" | Key of <code>theme.shadows</code> or any other valid CSS <code>box-shadow</code> value |
| size | string | undefined | no | "sm" | Controls items <code>font-size</code> and <code>padding</code> |
| store | ComboboxStore | undefined | no | Combobox store, can be used to control combobox state | |
| transitionProps | Omit<TransitionProps, "children"> | undefined | no | {duration: 150, transition: 'fade'} | Props passed down to the <code>Transition</code> component that used to animate dropdown presence, use to configure duration and animation type |
| trapFocus | boolean | undefined | no | false | Determines whether focus should be trapped within dropdown |
| width | PopoverWidth | no | "max-content" | Dropdown width, or <code>'target'</code> to make dropdown width the same as target element |
| withArrow | boolean | undefined | no | false | Determines whether component should have an arrow |
| withRoles | boolean | undefined | no | true | Determines whether dropdown and target elements should have accessible roles |
| withinPortal | boolean | undefined | no | true | Determines whether dropdown should be rendered within the <code>Portal</code> |
| zIndex | string | number | undefined | no | 50 | Dropdown <code>z-index</code> |