import { mergeDefaultProps, mergeRefs } from "@kobalte/utils";
import {
type Component,
type ValidComponent,
createEffect,
onCleanup,
splitProps,
} from "solid-js";
import { useFormControlContext } from "../form-control";
import * as Listbox from "../listbox";
import type { ElementOf, PolymorphicProps } from "../polymorphic";
import { useComboboxContext } from "./combobox-context";
export interface ComboboxListboxOptions
extends Pick<
Listbox.ListboxRootOptions ,
"scrollRef" | "scrollToItem" | "children"
> {}
export interface ComboboxListboxCommonProps<
T extends HTMLElement = HTMLElement,
> {
id: string;
ref: T | ((el: T) => void);
}
export interface ComboboxListboxRenderProps
extends ComboboxListboxCommonProps,
Listbox.ListboxRootRenderProps {
"aria-label": string | undefined;
"aria-labelledby": string | undefined;
}
export type ComboboxListboxProps<
Option,
OptGroup = never,
T extends ValidComponent | HTMLElement = HTMLElement,
> = ComboboxListboxOptions &
Partial>>;
/**
* Contains all the items of a `Combobox`.
*/
export function ComboboxListbox<
Option = any,
OptGroup = never,
T extends ValidComponent = "ul",
>(props: PolymorphicProps>) {
const formControlContext = useFormControlContext();
const context = useComboboxContext();
const mergedProps = mergeDefaultProps(
{
id: context.generateId("listbox"),
},
props as ComboboxListboxProps,
);
const [local, others] = splitProps(mergedProps, ["ref"]);
const ariaLabelledBy = () => {
return formControlContext.getAriaLabelledBy(
others.id,
context.listboxAriaLabel(),
undefined,
);
};
createEffect(() => onCleanup(context.registerListboxId(others.id!)));
return (
>
>
ref={mergeRefs(context.setListboxRef, local.ref)}
state={context.listState()}
autoFocus={context.autoFocus()}
shouldUseVirtualFocus
shouldSelectOnPressUp
shouldFocusOnHover
aria-label={context.listboxAriaLabel()}
aria-labelledby={ariaLabelledBy()}
renderItem={context.renderItem}
renderSection={context.renderSection}
virtualized={context.isVirtualized()}
{...others}
/>
);
}