/** * createDropdownList - the HEADLESS core behind : a single-select * dropdown state machine (trigger open/close, roving active index over enabled * options, full keyboard) exposed as **prop-getters** you spread onto YOUR OWN * markup. No styles, no DOM, no portal/measurement - those stay in the styled * component. * * ```svelte * * * {#if dd.open} * * {/if} * ``` */ import { type ListOption } from './list-option'; export type DropdownValue = string | number | null; /** Reactive inputs are passed as getters so the core tracks live prop changes. */ export type DropdownListConfig = { options: () => ReadonlyArray; value: () => DropdownValue; onChange?: (value: string | number) => void; disabled?: () => boolean; /** Read-only: value shown, trigger focusable, but the panel will not open. */ readonly?: () => boolean; ariaLabel?: () => string | undefined; /** DOM focus hook provided by the renderer; the core never touches the DOM. */ focusTrigger?: () => void; id?: () => string | undefined; invalid?: () => boolean; required?: () => boolean; error?: () => string | undefined; hint?: () => string | undefined; }; export declare function createDropdownList(config: DropdownListConfig): { /** Panel open state. */ readonly open: boolean; /** Highlighted option index into `options`. */ readonly activeIndex: number; /** The option matching the controlled value, if any. */ readonly selected: ListOption | null; /** Controlled value. */ readonly value: DropdownValue; isActive: (i: number) => boolean; isSelected: (o: ListOption) => boolean; setActive: (i: number) => void; openPanel: () => void; close: () => void; toggle: () => void; pick: (i: number) => void; move: (d: number) => void; onKeydown: (e: KeyboardEvent) => void; /** Spread onto the trigger