import type { JSX } from 'solid-js'; import { createComponent, createEffect, createMemo, createSignal, createUniqueId, mergeProps, } from 'solid-js'; import { omitProps } from 'solid-use/props'; import type { AutocompleteStateRenderProps, MultipleAutocompleteStateControlledOptions, MultipleAutocompleteStateUncontrolledOptions, SingleAutocompleteStateControlledOptions, SingleAutocompleteStateUncontrolledOptions, } from '../../states/create-autocomplete-state'; import { AutocompleteStateProvider, createMultipleAutocompleteState, createSingleAutocompleteState, } from '../../states/create-autocomplete-state'; import createDynamic from '../../utils/create-dynamic'; import type { DynamicProps, HeadlessProps, ValidConstructor, } from '../../utils/dynamic-prop'; import { createARIADisabledState, createDisabledState, createHasActiveState, createHasQueryState, createHasSelectedState, } from '../../utils/state-props'; import type { Prettify } from '../../utils/types'; import { CommandContext, createCommandOptionFocusNavigator, } from './CommandContext'; import { COMMAND_TAG } from './tags'; export interface CommandBaseProps { horizontal?: boolean; } export type SingleCommandControlledBaseProps = Prettify< CommandBaseProps & SingleAutocompleteStateControlledOptions & AutocompleteStateRenderProps >; export type SingleCommandControlledProps< V, T extends ValidConstructor = 'div', > = HeadlessProps>; export type SingleCommandUncontrolledBaseProps = Prettify< CommandBaseProps & SingleAutocompleteStateUncontrolledOptions & AutocompleteStateRenderProps >; export type SingleCommandUncontrolledProps< V, T extends ValidConstructor = 'div', > = HeadlessProps>; export type SingleCommandProps = | SingleCommandControlledProps | SingleCommandUncontrolledProps; export type MultipleCommandControlledBaseProps = Prettify< CommandBaseProps & MultipleAutocompleteStateControlledOptions & AutocompleteStateRenderProps >; export type MultipleCommandControlledProps< V, T extends ValidConstructor = 'div', > = HeadlessProps>; export type MultipleCommandUncontrolledBaseProps = Prettify< CommandBaseProps & MultipleAutocompleteStateUncontrolledOptions & AutocompleteStateRenderProps >; export type MultipleCommandUncontrolledProps< V, T extends ValidConstructor = 'div', > = HeadlessProps>; export type MultipleCommandProps = | MultipleCommandControlledProps | MultipleCommandUncontrolledProps; export type CommandProps = | SingleCommandProps | MultipleCommandProps; function isCommandMultiple( props: CommandProps, ): props is MultipleCommandProps { return !!props.multiple; } function isCommandUncontrolled( props: CommandProps, ): props is | SingleCommandUncontrolledProps | MultipleCommandUncontrolledProps { return 'defaultValue' in props; } export function Command( props: CommandProps, ): JSX.Element { return createMemo(() => { const controller = createCommandOptionFocusNavigator(); const state = isCommandMultiple(props) ? createMultipleAutocompleteState(props) : createSingleAutocompleteState(props); const [activeDescendant, setActiveDescendant] = createSignal(); const [selectedDescendant, setSelectedDescendant] = createSignal< string | undefined >(undefined, { equals: false, }); const inputID = createUniqueId(); const optionsID = createUniqueId(); const labelID = createUniqueId(); createEffect(() => { if (!state.hasActive()) { setActiveDescendant(undefined); } }); return createComponent(CommandContext.Provider, { value: { multiple: !!props.multiple, controller, get activeDescendant() { return activeDescendant(); }, set activeDescendant(value: string | undefined) { setActiveDescendant(value); }, get selectedDescendant() { return selectedDescendant(); }, set selectedDescendant(value: string | undefined) { setSelectedDescendant(value); }, inputID, optionsID, labelID, optionsHovering: false, }, get children() { return createDynamic( () => props.as || 'div', mergeProps( COMMAND_TAG, { id: controller.getId(), 'aria-labelledby': labelID, }, createDisabledState(() => state.disabled()), createARIADisabledState(() => state.disabled()), createHasSelectedState(() => state.hasSelected()), createHasActiveState(() => state.hasActive()), createHasQueryState(() => state.hasQuery()), isCommandUncontrolled(props) ? omitProps(props, [ 'as', 'by', 'children', 'defaultValue', 'disabled', 'horizontal', 'multiple', 'onChange', 'toggleable', ]) : omitProps(props, [ 'as', 'by', 'children', 'value', 'disabled', 'horizontal', 'multiple', 'onChange', 'toggleable', ]), { get children() { return createComponent(AutocompleteStateProvider, { state, get children() { return props.children; }, }); }, }, ) as DynamicProps, ); }, }); }) as unknown as JSX.Element; }