import type { JSX, ValidComponent } from "@solidjs/web"; import { dynamic } from "@solidjs/web"; import { createEffect, createSignal, omit } from "solid-js"; import { composeRefs, userRef } from "../../internals/compose-refs"; import { CompositeList } from "../../internals/composite/composite-list"; import type { MutableRef } from "../../internals/floating-ui/types"; import { mergeRootProps } from "../../internals/merge-root-props"; import { resolveClassStyle } from "../../internals/resolve-class-style"; import type { BaseUIComponentProps } from "../../internals/types"; import { useComboboxRootContext } from "../root/combobox-root-context"; import { ComboboxChipsContext, type ComboboxChipsContextValue, } from "./chips-context"; export type ComboboxChipsState = Record; export interface ComboboxChipsProps extends BaseUIComponentProps<"div", ComboboxChipsState> { as?: ValidComponent; } const EMPTY_STATE: ComboboxChipsState = {}; /** * A container for chips that represent values in a multiselectable input. * Renders a `
` — gets `role="toolbar"` once at least one chip is * rendered so NVDA stays in focus mode during arrow-key traversal. */ export function ComboboxChips(props: ComboboxChipsProps): JSX.Element { const root = useComboboxRootContext(); const [highlightedChipIndex, setHighlightedChipIndex] = createSignal< number | undefined >(undefined, { ownedWrite: true }); createEffect( () => root.open(), (openVal) => { if (openVal && highlightedChipIndex() !== undefined) { setHighlightedChipIndex(undefined); } }, ); const chipsRef: MutableRef> = { current: [] }; const hasChips = (): boolean => { const sv = root.selectedValue() as unknown; return Array.isArray(sv) && sv.length > 0; }; const contextValue: ComboboxChipsContextValue = { highlightedChipIndex, setHighlightedChipIndex, chipsRef, }; function onMouseDown(): void { if (root.readOnly() || root.disabled()) return; root.inputRef.current?.focus(); } const setContainerRef = (el: HTMLElement | null): void => { root.chipsContainerRef.current = el as HTMLDivElement | null; }; const internal = { get role() { return hasChips() ? ("toolbar" as const) : undefined; }, onMouseDown, }; const userClassStyle = resolveClassStyle(props, () => EMPTY_STATE); const userProps = omit(props, "as", "class", "style", "attrs"); let merged: Record = mergeRootProps( internal, userClassStyle, ); merged = mergeRootProps(merged, userProps); const Tag = dynamic(() => props.as ?? "div"); return ( ); }