package.dist.index.js Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of select Show documentation
Show all versions of select Show documentation
Core logic for the select widget implemented as a state machine
The newest version!
'use strict';
var anatomy$1 = require('@zag-js/anatomy');
var collection$1 = require('@zag-js/collection');
var core = require('@zag-js/core');
var domEvent = require('@zag-js/dom-event');
var domQuery = require('@zag-js/dom-query');
var popper = require('@zag-js/popper');
var dismissable = require('@zag-js/dismissable');
var formUtils = require('@zag-js/form-utils');
var utils = require('@zag-js/utils');
var types = require('@zag-js/types');
// src/select.anatomy.ts
var anatomy = anatomy$1.createAnatomy("select").parts(
"label",
"positioner",
"trigger",
"indicator",
"clearTrigger",
"item",
"itemText",
"itemIndicator",
"itemGroup",
"itemGroupLabel",
"list",
"content",
"root",
"control",
"valueText"
);
var parts = anatomy.build();
var collection = (options) => {
return core.ref(new collection$1.ListCollection(options));
};
collection.empty = () => {
return core.ref(new collection$1.ListCollection({ items: [] }));
};
var dom = domQuery.createScope({
getRootId: (ctx) => ctx.ids?.root ?? `select:${ctx.id}`,
getContentId: (ctx) => ctx.ids?.content ?? `select:${ctx.id}:content`,
getTriggerId: (ctx) => ctx.ids?.trigger ?? `select:${ctx.id}:trigger`,
getClearTriggerId: (ctx) => ctx.ids?.clearTrigger ?? `select:${ctx.id}:clear-trigger`,
getLabelId: (ctx) => ctx.ids?.label ?? `select:${ctx.id}:label`,
getControlId: (ctx) => ctx.ids?.control ?? `select:${ctx.id}:control`,
getItemId: (ctx, id) => ctx.ids?.item?.(id) ?? `select:${ctx.id}:option:${id}`,
getHiddenSelectId: (ctx) => ctx.ids?.hiddenSelect ?? `select:${ctx.id}:select`,
getPositionerId: (ctx) => ctx.ids?.positioner ?? `select:${ctx.id}:positioner`,
getItemGroupId: (ctx, id) => ctx.ids?.itemGroup?.(id) ?? `select:${ctx.id}:optgroup:${id}`,
getItemGroupLabelId: (ctx, id) => ctx.ids?.itemGroupLabel?.(id) ?? `select:${ctx.id}:optgroup-label:${id}`,
getHiddenSelectEl: (ctx) => dom.getById(ctx, dom.getHiddenSelectId(ctx)),
getContentEl: (ctx) => dom.getById(ctx, dom.getContentId(ctx)),
getControlEl: (ctx) => dom.getById(ctx, dom.getControlId(ctx)),
getTriggerEl: (ctx) => dom.getById(ctx, dom.getTriggerId(ctx)),
getClearTriggerEl: (ctx) => dom.getById(ctx, dom.getClearTriggerId(ctx)),
getPositionerEl: (ctx) => dom.getById(ctx, dom.getPositionerId(ctx)),
getHighlightedOptionEl(ctx) {
if (!ctx.highlightedValue) return null;
return dom.getById(ctx, dom.getItemId(ctx, ctx.highlightedValue));
}
});
// src/select.connect.ts
function connect(state, send, normalize) {
const disabled = state.context.isDisabled;
const invalid = state.context.invalid;
const readOnly = state.context.readOnly;
const interactive = state.context.isInteractive;
const composite = state.context.composite;
const open = state.hasTag("open");
const focused = state.matches("focused");
const highlightedValue = state.context.highlightedValue;
const highlightedItem = state.context.highlightedItem;
const selectedItems = state.context.selectedItems;
const isTypingAhead = state.context.isTypingAhead;
const collection2 = state.context.collection;
const ariaActiveDescendant = highlightedValue ? dom.getItemId(state.context, highlightedValue) : void 0;
function getItemState(props2) {
const _disabled = collection2.getItemDisabled(props2.item);
const value = collection2.getItemValue(props2.item);
return {
value,
disabled: Boolean(disabled || _disabled),
highlighted: highlightedValue === value,
selected: state.context.value.includes(value)
};
}
const popperStyles = popper.getPlacementStyles({
...state.context.positioning,
placement: state.context.currentPlacement
});
return {
open,
focused,
empty: state.context.value.length === 0,
highlightedItem,
highlightedValue,
selectedItems,
hasSelectedItems: state.context.hasSelectedItems,
value: state.context.value,
valueAsString: state.context.valueAsString,
collection: collection2,
multiple: !!state.context.multiple,
disabled: !!disabled,
setCollection(collection3) {
send({ type: "COLLECTION.SET", value: collection3 });
},
reposition(options = {}) {
send({ type: "POSITIONING.SET", options });
},
focus() {
dom.getTriggerEl(state.context)?.focus({ preventScroll: true });
},
setOpen(nextOpen) {
if (nextOpen === open) return;
send(nextOpen ? "OPEN" : "CLOSE");
},
selectValue(value) {
send({ type: "ITEM.SELECT", value });
},
setValue(value) {
send({ type: "VALUE.SET", value });
},
selectAll() {
send({ type: "VALUE.SET", value: collection2.getValues() });
},
highlightValue(value) {
send({ type: "HIGHLIGHTED_VALUE.SET", value });
},
clearValue(value) {
if (value) {
send({ type: "ITEM.CLEAR", value });
} else {
send({ type: "VALUE.CLEAR" });
}
},
getItemState,
getRootProps() {
return normalize.element({
...parts.root.attrs,
dir: state.context.dir,
id: dom.getRootId(state.context),
"data-invalid": domQuery.dataAttr(invalid),
"data-readonly": domQuery.dataAttr(readOnly)
});
},
getLabelProps() {
return normalize.label({
dir: state.context.dir,
id: dom.getLabelId(state.context),
...parts.label.attrs,
"data-disabled": domQuery.dataAttr(disabled),
"data-invalid": domQuery.dataAttr(invalid),
"data-readonly": domQuery.dataAttr(readOnly),
htmlFor: dom.getHiddenSelectId(state.context),
onClick(event) {
if (event.defaultPrevented) return;
if (disabled) return;
dom.getTriggerEl(state.context)?.focus({ preventScroll: true });
}
});
},
getControlProps() {
return normalize.element({
...parts.control.attrs,
dir: state.context.dir,
id: dom.getControlId(state.context),
"data-state": open ? "open" : "closed",
"data-focus": domQuery.dataAttr(focused),
"data-disabled": domQuery.dataAttr(disabled),
"data-invalid": domQuery.dataAttr(invalid)
});
},
getValueTextProps() {
return normalize.element({
...parts.valueText.attrs,
dir: state.context.dir,
"data-disabled": domQuery.dataAttr(disabled),
"data-invalid": domQuery.dataAttr(invalid),
"data-focus": domQuery.dataAttr(focused)
});
},
getTriggerProps() {
return normalize.button({
id: dom.getTriggerId(state.context),
disabled,
dir: state.context.dir,
type: "button",
role: "combobox",
"aria-controls": dom.getContentId(state.context),
"aria-expanded": open,
"aria-haspopup": "listbox",
"data-state": open ? "open" : "closed",
"aria-invalid": invalid,
"aria-labelledby": dom.getLabelId(state.context),
...parts.trigger.attrs,
"data-disabled": domQuery.dataAttr(disabled),
"data-invalid": domQuery.dataAttr(invalid),
"data-readonly": domQuery.dataAttr(readOnly),
"data-placement": state.context.currentPlacement,
"data-placeholder-shown": domQuery.dataAttr(!state.context.hasSelectedItems),
onClick(event) {
if (!interactive) return;
if (event.defaultPrevented) return;
send({ type: "TRIGGER.CLICK" });
},
onFocus() {
send("TRIGGER.FOCUS");
},
onBlur() {
send("TRIGGER.BLUR");
},
onKeyDown(event) {
if (event.defaultPrevented) return;
if (!interactive) return;
const keyMap = {
ArrowUp() {
send({ type: "TRIGGER.ARROW_UP" });
},
ArrowDown(event2) {
send({ type: event2.altKey ? "OPEN" : "TRIGGER.ARROW_DOWN" });
},
ArrowLeft() {
send({ type: "TRIGGER.ARROW_LEFT" });
},
ArrowRight() {
send({ type: "TRIGGER.ARROW_RIGHT" });
},
Home() {
send({ type: "TRIGGER.HOME" });
},
End() {
send({ type: "TRIGGER.END" });
},
Enter() {
send({ type: "TRIGGER.ENTER" });
},
Space(event2) {
if (isTypingAhead) {
send({ type: "TRIGGER.TYPEAHEAD", key: event2.key });
} else {
send({ type: "TRIGGER.ENTER" });
}
}
};
const exec = keyMap[domEvent.getEventKey(event, state.context)];
if (exec) {
exec(event);
event.preventDefault();
return;
}
if (domQuery.getByTypeahead.isValidEvent(event)) {
send({ type: "TRIGGER.TYPEAHEAD", key: event.key });
event.preventDefault();
}
}
});
},
getIndicatorProps() {
return normalize.element({
...parts.indicator.attrs,
dir: state.context.dir,
"aria-hidden": true,
"data-state": open ? "open" : "closed",
"data-disabled": domQuery.dataAttr(disabled),
"data-invalid": domQuery.dataAttr(invalid),
"data-readonly": domQuery.dataAttr(readOnly)
});
},
getItemProps(props2) {
const itemState = getItemState(props2);
return normalize.element({
id: dom.getItemId(state.context, itemState.value),
role: "option",
...parts.item.attrs,
dir: state.context.dir,
"data-value": itemState.value,
"aria-selected": itemState.selected,
"data-state": itemState.selected ? "checked" : "unchecked",
"data-highlighted": domQuery.dataAttr(itemState.highlighted),
"data-disabled": domQuery.dataAttr(itemState.disabled),
"aria-disabled": domQuery.ariaAttr(itemState.disabled),
onPointerMove(event) {
if (itemState.disabled || event.pointerType !== "mouse") return;
if (itemState.value === state.context.highlightedValue) return;
send({ type: "ITEM.POINTER_MOVE", value: itemState.value });
},
onClick(event) {
if (event.defaultPrevented) return;
if (itemState.disabled) return;
send({ type: "ITEM.CLICK", src: "pointerup", value: itemState.value });
},
onPointerLeave(event) {
if (itemState.disabled) return;
if (props2.persistFocus) return;
if (event.pointerType !== "mouse") return;
const pointerMoved = state.previousEvent.type.includes("POINTER");
if (!pointerMoved) return;
send({ type: "ITEM.POINTER_LEAVE" });
}
});
},
getItemTextProps(props2) {
const itemState = getItemState(props2);
return normalize.element({
...parts.itemText.attrs,
"data-state": itemState.selected ? "checked" : "unchecked",
"data-disabled": domQuery.dataAttr(itemState.disabled),
"data-highlighted": domQuery.dataAttr(itemState.highlighted)
});
},
getItemIndicatorProps(props2) {
const itemState = getItemState(props2);
return normalize.element({
"aria-hidden": true,
...parts.itemIndicator.attrs,
"data-state": itemState.selected ? "checked" : "unchecked",
hidden: !itemState.selected
});
},
getItemGroupLabelProps(props2) {
const { htmlFor } = props2;
return normalize.element({
...parts.itemGroupLabel.attrs,
id: dom.getItemGroupLabelId(state.context, htmlFor),
role: "group",
dir: state.context.dir
});
},
getItemGroupProps(props2) {
const { id } = props2;
return normalize.element({
...parts.itemGroup.attrs,
"data-disabled": domQuery.dataAttr(disabled),
id: dom.getItemGroupId(state.context, id),
"aria-labelledby": dom.getItemGroupLabelId(state.context, id),
dir: state.context.dir
});
},
getClearTriggerProps() {
return normalize.button({
...parts.clearTrigger.attrs,
id: dom.getClearTriggerId(state.context),
type: "button",
"aria-label": "Clear value",
"data-invalid": domQuery.dataAttr(invalid),
disabled,
hidden: !state.context.hasSelectedItems,
dir: state.context.dir,
onClick(event) {
if (event.defaultPrevented) return;
send("CLEAR.CLICK");
}
});
},
getHiddenSelectProps() {
return normalize.select({
name: state.context.name,
form: state.context.form,
disabled,
multiple: state.context.multiple,
required: state.context.required,
"aria-hidden": true,
id: dom.getHiddenSelectId(state.context),
defaultValue: state.context.multiple ? state.context.value : state.context.value[0],
style: domQuery.visuallyHiddenStyle,
tabIndex: -1,
// Some browser extensions will focus the hidden select.
// Let's forward the focus to the trigger.
onFocus() {
dom.getTriggerEl(state.context)?.focus({ preventScroll: true });
},
"aria-labelledby": dom.getLabelId(state.context)
});
},
getPositionerProps() {
return normalize.element({
...parts.positioner.attrs,
dir: state.context.dir,
id: dom.getPositionerId(state.context),
style: popperStyles.floating
});
},
getContentProps() {
return normalize.element({
hidden: !open,
dir: state.context.dir,
id: dom.getContentId(state.context),
role: composite ? "listbox" : "dialog",
...parts.content.attrs,
"data-state": open ? "open" : "closed",
"data-placement": state.context.currentPlacement,
"data-activedescendant": ariaActiveDescendant,
"aria-activedescendant": composite ? ariaActiveDescendant : void 0,
"aria-multiselectable": state.context.multiple && composite ? true : void 0,
"aria-labelledby": dom.getLabelId(state.context),
tabIndex: 0,
onKeyDown(event) {
if (!interactive) return;
if (!domQuery.isSelfTarget(event)) return;
if (event.key === "Tab") {
const valid = domQuery.isValidTabEvent(event);
if (!valid) {
event.preventDefault();
return;
}
}
const keyMap = {
ArrowUp() {
send({ type: "CONTENT.ARROW_UP" });
},
ArrowDown() {
send({ type: "CONTENT.ARROW_DOWN" });
},
Home() {
send({ type: "CONTENT.HOME" });
},
End() {
send({ type: "CONTENT.END" });
},
Enter() {
send({ type: "ITEM.CLICK", src: "keydown.enter" });
},
Space(event2) {
if (isTypingAhead) {
send({ type: "CONTENT.TYPEAHEAD", key: event2.key });
} else {
keyMap.Enter?.(event2);
}
}
};
const exec = keyMap[domEvent.getEventKey(event)];
if (exec) {
exec(event);
event.preventDefault();
return;
}
const target = domQuery.getEventTarget(event);
if (domQuery.isEditableElement(target)) {
return;
}
if (domQuery.getByTypeahead.isValidEvent(event)) {
send({ type: "CONTENT.TYPEAHEAD", key: event.key });
event.preventDefault();
}
}
});
},
getListProps() {
return normalize.element({
...parts.list.attrs,
tabIndex: 0,
role: !composite ? "listbox" : void 0,
"aria-labelledby": dom.getTriggerId(state.context),
"aria-activedescendant": !composite ? ariaActiveDescendant : void 0,
"aria-multiselectable": !composite && state.context.multiple ? true : void 0
});
}
};
}
var { and, not, or } = core.guards;
function machine(userContext) {
const ctx = utils.compact(userContext);
return core.createMachine(
{
id: "select",
context: {
value: [],
highlightedValue: null,
loopFocus: false,
closeOnSelect: !ctx.multiple,
disabled: false,
readOnly: false,
composite: true,
...ctx,
highlightedItem: null,
selectedItems: [],
valueAsString: "",
collection: ctx.collection ?? collection.empty(),
typeahead: domQuery.getByTypeahead.defaultOptions,
fieldsetDisabled: false,
positioning: {
placement: "bottom-start",
gutter: 8,
...ctx.positioning
}
},
computed: {
hasSelectedItems: (ctx2) => ctx2.value.length > 0,
isTypingAhead: (ctx2) => ctx2.typeahead.keysSoFar !== "",
isDisabled: (ctx2) => !!ctx2.disabled || ctx2.fieldsetDisabled,
isInteractive: (ctx2) => !(ctx2.isDisabled || ctx2.readOnly)
},
initial: ctx.open ? "open" : "idle",
created: ["syncCollection"],
entry: ["syncSelectElement"],
watch: {
open: ["toggleVisibility"],
value: ["syncSelectedItems", "syncSelectElement"],
highlightedValue: ["syncHighlightedItem"],
collection: ["syncCollection"]
},
on: {
"HIGHLIGHTED_VALUE.SET": {
actions: ["setHighlightedItem"]
},
"ITEM.SELECT": {
actions: ["selectItem"]
},
"ITEM.CLEAR": {
actions: ["clearItem"]
},
"VALUE.SET": {
actions: ["setSelectedItems"]
},
"VALUE.CLEAR": {
actions: ["clearSelectedItems"]
},
"CLEAR.CLICK": {
actions: ["clearSelectedItems", "focusTriggerEl"]
},
"COLLECTION.SET": {
actions: ["setCollection"]
}
},
activities: ["trackFormControlState"],
states: {
idle: {
tags: ["closed"],
on: {
"CONTROLLED.OPEN": [
{
guard: "isTriggerClickEvent",
target: "open",
actions: ["setInitialFocus", "highlightFirstSelectedItem"]
},
{
target: "open",
actions: ["setInitialFocus"]
}
],
"TRIGGER.CLICK": [
{
guard: "isOpenControlled",
actions: ["invokeOnOpen"]
},
{
target: "open",
actions: ["invokeOnOpen", "setInitialFocus", "highlightFirstSelectedItem"]
}
],
"TRIGGER.FOCUS": {
target: "focused"
},
OPEN: [
{
guard: "isOpenControlled",
actions: ["invokeOnOpen"]
},
{
target: "open",
actions: ["setInitialFocus", "invokeOnOpen"]
}
]
}
},
focused: {
tags: ["closed"],
on: {
"CONTROLLED.OPEN": [
{
guard: "isTriggerClickEvent",
target: "open",
actions: ["setInitialFocus", "highlightFirstSelectedItem"]
},
{
guard: "isTriggerArrowUpEvent",
target: "open",
actions: ["setInitialFocus", "highlightComputedLastItem"]
},
{
guard: or("isTriggerArrowDownEvent", "isTriggerEnterEvent"),
target: "open",
actions: ["setInitialFocus", "highlightComputedFirstItem"]
},
{
target: "open",
actions: ["setInitialFocus"]
}
],
OPEN: [
{
guard: "isOpenControlled",
actions: ["invokeOnOpen"]
},
{
target: "open",
actions: ["setInitialFocus", "invokeOnOpen"]
}
],
"TRIGGER.BLUR": {
target: "idle"
},
"TRIGGER.CLICK": [
{
guard: "isOpenControlled",
actions: ["invokeOnOpen"]
},
{
target: "open",
actions: ["setInitialFocus", "invokeOnOpen", "highlightFirstSelectedItem"]
}
],
"TRIGGER.ENTER": [
{
guard: "isOpenControlled",
actions: ["invokeOnOpen"]
},
{
target: "open",
actions: ["setInitialFocus", "invokeOnOpen", "highlightComputedFirstItem"]
}
],
"TRIGGER.ARROW_UP": [
{
guard: "isOpenControlled",
actions: ["invokeOnOpen"]
},
{
target: "open",
actions: ["setInitialFocus", "invokeOnOpen", "highlightComputedLastItem"]
}
],
"TRIGGER.ARROW_DOWN": [
{
guard: "isOpenControlled",
actions: ["invokeOnOpen"]
},
{
target: "open",
actions: ["setInitialFocus", "invokeOnOpen", "highlightComputedFirstItem"]
}
],
"TRIGGER.ARROW_LEFT": [
{
guard: and(not("multiple"), "hasSelectedItems"),
actions: ["selectPreviousItem"]
},
{
guard: not("multiple"),
actions: ["selectLastItem"]
}
],
"TRIGGER.ARROW_RIGHT": [
{
guard: and(not("multiple"), "hasSelectedItems"),
actions: ["selectNextItem"]
},
{
guard: not("multiple"),
actions: ["selectFirstItem"]
}
],
"TRIGGER.HOME": {
guard: not("multiple"),
actions: ["selectFirstItem"]
},
"TRIGGER.END": {
guard: not("multiple"),
actions: ["selectLastItem"]
},
"TRIGGER.TYPEAHEAD": {
guard: not("multiple"),
actions: ["selectMatchingItem"]
}
}
},
open: {
tags: ["open"],
exit: ["scrollContentToTop"],
activities: ["trackDismissableElement", "computePlacement", "scrollToHighlightedItem"],
on: {
"CONTROLLED.CLOSE": {
target: "focused",
actions: ["focusTriggerEl", "clearHighlightedItem"]
},
CLOSE: [
{
guard: "isOpenControlled",
actions: ["invokeOnClose"]
},
{
target: "focused",
actions: ["invokeOnClose", "focusTriggerEl", "clearHighlightedItem"]
}
],
"TRIGGER.CLICK": [
{
guard: "isOpenControlled",
actions: ["invokeOnClose"]
},
{
target: "focused",
actions: ["invokeOnClose", "clearHighlightedItem"]
}
],
"ITEM.CLICK": [
{
guard: and("closeOnSelect", "isOpenControlled"),
actions: ["selectHighlightedItem", "invokeOnClose"]
},
{
guard: "closeOnSelect",
target: "focused",
actions: ["selectHighlightedItem", "invokeOnClose", "focusTriggerEl", "clearHighlightedItem"]
},
{
actions: ["selectHighlightedItem"]
}
],
"CONTENT.HOME": {
actions: ["highlightFirstItem"]
},
"CONTENT.END": {
actions: ["highlightLastItem"]
},
"CONTENT.ARROW_DOWN": [
{
guard: and("hasHighlightedItem", "loop", "isLastItemHighlighted"),
actions: ["highlightFirstItem"]
},
{
guard: "hasHighlightedItem",
actions: ["highlightNextItem"]
},
{
actions: ["highlightFirstItem"]
}
],
"CONTENT.ARROW_UP": [
{
guard: and("hasHighlightedItem", "loop", "isFirstItemHighlighted"),
actions: ["highlightLastItem"]
},
{
guard: "hasHighlightedItem",
actions: ["highlightPreviousItem"]
},
{
actions: ["highlightLastItem"]
}
],
"CONTENT.TYPEAHEAD": {
actions: ["highlightMatchingItem"]
},
"ITEM.POINTER_MOVE": {
actions: ["highlightItem"]
},
"ITEM.POINTER_LEAVE": {
actions: ["clearHighlightedItem"]
},
"POSITIONING.SET": {
actions: ["reposition"]
}
}
}
}
},
{
guards: {
loop: (ctx2) => !!ctx2.loopFocus,
multiple: (ctx2) => !!ctx2.multiple,
hasSelectedItems: (ctx2) => !!ctx2.hasSelectedItems,
hasHighlightedItem: (ctx2) => ctx2.highlightedValue != null,
isFirstItemHighlighted: (ctx2) => ctx2.highlightedValue === ctx2.collection.firstValue,
isLastItemHighlighted: (ctx2) => ctx2.highlightedValue === ctx2.collection.lastValue,
closeOnSelect: (ctx2, evt) => !!(evt.closeOnSelect ?? ctx2.closeOnSelect),
// guard assertions (for controlled mode)
isOpenControlled: (ctx2) => !!ctx2["open.controlled"],
isTriggerClickEvent: (_ctx, evt) => evt.previousEvent?.type === "TRIGGER.CLICK",
isTriggerEnterEvent: (_ctx, evt) => evt.previousEvent?.type === "TRIGGER.ENTER",
isTriggerArrowUpEvent: (_ctx, evt) => evt.previousEvent?.type === "TRIGGER.ARROW_UP",
isTriggerArrowDownEvent: (_ctx, evt) => evt.previousEvent?.type === "TRIGGER.ARROW_DOWN"
},
activities: {
trackFormControlState(ctx2, _evt, { initialContext }) {
return formUtils.trackFormControl(dom.getHiddenSelectEl(ctx2), {
onFieldsetDisabledChange(disabled) {
ctx2.fieldsetDisabled = disabled;
},
onFormReset() {
set.selectedItems(ctx2, initialContext.value);
}
});
},
trackDismissableElement(ctx2, _evt, { send }) {
const contentEl = () => dom.getContentEl(ctx2);
let restoreFocus = true;
return dismissable.trackDismissableElement(contentEl, {
defer: true,
exclude: [dom.getTriggerEl(ctx2), dom.getClearTriggerEl(ctx2)],
onFocusOutside: ctx2.onFocusOutside,
onPointerDownOutside: ctx2.onPointerDownOutside,
onInteractOutside(event) {
ctx2.onInteractOutside?.(event);
restoreFocus = !(event.detail.focusable || event.detail.contextmenu);
},
onDismiss() {
send({ type: "CLOSE", src: "interact-outside", restoreFocus });
}
});
},
computePlacement(ctx2) {
ctx2.currentPlacement = ctx2.positioning.placement;
const triggerEl = () => dom.getTriggerEl(ctx2);
const positionerEl = () => dom.getPositionerEl(ctx2);
return popper.getPlacement(triggerEl, positionerEl, {
defer: true,
...ctx2.positioning,
onComplete(data) {
ctx2.currentPlacement = data.placement;
}
});
},
scrollToHighlightedItem(ctx2, _evt, { getState }) {
const exec = (immediate) => {
if (ctx2.highlightedValue == null) return;
const state = getState();
if (state.event.type.includes("POINTER")) return;
const optionEl = dom.getHighlightedOptionEl(ctx2);
const contentEl2 = dom.getContentEl(ctx2);
if (ctx2.scrollToIndexFn) {
const highlightedIndex = ctx2.collection.indexOf(ctx2.highlightedValue);
ctx2.scrollToIndexFn({ index: highlightedIndex, immediate });
return;
}
domQuery.scrollIntoView(optionEl, { rootEl: contentEl2, block: "nearest" });
};
domQuery.raf(() => exec(true));
const contentEl = () => dom.getContentEl(ctx2);
return domQuery.observeAttributes(contentEl, {
defer: true,
attributes: ["data-activedescendant"],
callback() {
exec(false);
}
});
}
},
actions: {
reposition(ctx2, evt) {
const positionerEl = () => dom.getPositionerEl(ctx2);
popper.getPlacement(dom.getTriggerEl(ctx2), positionerEl, {
...ctx2.positioning,
...evt.options,
defer: true,
listeners: false,
onComplete(data) {
ctx2.currentPlacement = data.placement;
}
});
},
toggleVisibility(ctx2, evt, { send }) {
send({ type: ctx2.open ? "CONTROLLED.OPEN" : "CONTROLLED.CLOSE", previousEvent: evt });
},
highlightPreviousItem(ctx2) {
if (ctx2.highlightedValue == null) return;
const value = ctx2.collection.getPreviousValue(ctx2.highlightedValue);
set.highlightedItem(ctx2, value);
},
highlightNextItem(ctx2) {
if (ctx2.highlightedValue == null) return;
const value = ctx2.collection.getNextValue(ctx2.highlightedValue);
set.highlightedItem(ctx2, value);
},
highlightFirstItem(ctx2) {
const value = ctx2.collection.firstValue;
set.highlightedItem(ctx2, value);
},
highlightLastItem(ctx2) {
const value = ctx2.collection.lastValue;
set.highlightedItem(ctx2, value);
},
setInitialFocus(ctx2) {
domQuery.raf(() => {
const element = domQuery.getInitialFocus({
root: dom.getContentEl(ctx2)
});
element?.focus({ preventScroll: true });
});
},
focusTriggerEl(ctx2, evt) {
const restoreFocus = evt.restoreFocus ?? evt.previousEvent?.restoreFocus;
if (restoreFocus != null && !restoreFocus) return;
domQuery.raf(() => {
const element = dom.getTriggerEl(ctx2);
element?.focus({ preventScroll: true });
});
},
selectHighlightedItem(ctx2, evt) {
let value = evt.value ?? ctx2.highlightedValue;
if (value == null) return;
const nullable = ctx2.deselectable && !ctx2.multiple && ctx2.value.includes(value);
value = nullable ? null : value;
set.selectedItem(ctx2, value, nullable);
},
highlightComputedFirstItem(ctx2) {
const value = ctx2.hasSelectedItems ? ctx2.collection.sort(ctx2.value)[0] : ctx2.collection.firstValue;
set.highlightedItem(ctx2, value);
},
highlightComputedLastItem(ctx2) {
const value = ctx2.hasSelectedItems ? ctx2.collection.sort(ctx2.value)[0] : ctx2.collection.lastValue;
set.highlightedItem(ctx2, value);
},
highlightFirstSelectedItem(ctx2) {
if (!ctx2.hasSelectedItems) return;
const [value] = ctx2.collection.sort(ctx2.value);
set.highlightedItem(ctx2, value);
},
highlightItem(ctx2, evt) {
set.highlightedItem(ctx2, evt.value);
},
highlightMatchingItem(ctx2, evt) {
const value = ctx2.collection.search(evt.key, {
state: ctx2.typeahead,
currentValue: ctx2.highlightedValue
});
if (value == null) return;
set.highlightedItem(ctx2, value);
},
setHighlightedItem(ctx2, evt) {
set.highlightedItem(ctx2, evt.value);
},
clearHighlightedItem(ctx2) {
set.highlightedItem(ctx2, null, true);
},
selectItem(ctx2, evt) {
const nullable = ctx2.deselectable && !ctx2.multiple && ctx2.value.includes(evt.value);
const value = nullable ? null : evt.value;
set.selectedItem(ctx2, value, nullable);
},
clearItem(ctx2, evt) {
const value = ctx2.value.filter((v) => v !== evt.value);
set.selectedItems(ctx2, value);
},
setSelectedItems(ctx2, evt) {
set.selectedItems(ctx2, evt.value);
},
clearSelectedItems(ctx2) {
set.selectedItems(ctx2, []);
},
selectPreviousItem(ctx2) {
const value = ctx2.collection.getPreviousValue(ctx2.value[0]);
set.selectedItem(ctx2, value);
},
selectNextItem(ctx2) {
const value = ctx2.collection.getNextValue(ctx2.value[0]);
set.selectedItem(ctx2, value);
},
selectFirstItem(ctx2) {
const value = ctx2.collection.firstValue;
set.selectedItem(ctx2, value);
},
selectLastItem(ctx2) {
const value = ctx2.collection.lastValue;
set.selectedItem(ctx2, value);
},
selectMatchingItem(ctx2, evt) {
const value = ctx2.collection.search(evt.key, {
state: ctx2.typeahead,
currentValue: ctx2.value[0]
});
if (value == null) return;
set.selectedItem(ctx2, value);
},
scrollContentToTop(ctx2) {
if (ctx2.scrollToIndexFn) {
ctx2.scrollToIndexFn({ index: 0, immediate: true });
} else {
dom.getContentEl(ctx2)?.scrollTo(0, 0);
}
},
invokeOnOpen(ctx2) {
ctx2.onOpenChange?.({ open: true });
},
invokeOnClose(ctx2) {
ctx2.onOpenChange?.({ open: false });
},
syncSelectElement(ctx2) {
const selectEl = dom.getHiddenSelectEl(ctx2);
if (!selectEl) return;
if (ctx2.value.length === 0 && !ctx2.multiple) {
selectEl.selectedIndex = -1;
return;
}
for (const option of selectEl.options) {
option.selected = ctx2.value.includes(option.value);
}
},
setCollection(ctx2, evt) {
ctx2.collection = evt.value;
},
syncCollection(ctx2) {
const selectedItems = ctx2.collection.findMany(ctx2.value);
const valueAsString = ctx2.collection.stringifyItems(selectedItems);
ctx2.highlightedItem = ctx2.collection.find(ctx2.highlightedValue);
ctx2.selectedItems = selectedItems;
ctx2.valueAsString = valueAsString;
},
syncSelectedItems(ctx2) {
sync.valueChange(ctx2);
},
syncHighlightedItem(ctx2) {
sync.highlightChange(ctx2);
}
}
}
);
}
function dispatchChangeEvent(ctx) {
domQuery.raf(() => {
const node = dom.getHiddenSelectEl(ctx);
if (!node) return;
const win = dom.getWin(ctx);
const changeEvent = new win.Event("change", { bubbles: true, composed: true });
node.dispatchEvent(changeEvent);
});
}
var sync = {
valueChange: (ctx) => {
const prevSelectedItems = ctx.selectedItems;
ctx.selectedItems = ctx.value.map((value) => {
const foundItem = prevSelectedItems.find((item) => ctx.collection.getItemValue(item) === value);
if (foundItem) return foundItem;
return ctx.collection.find(value);
});
ctx.valueAsString = ctx.collection.stringifyItems(ctx.selectedItems);
},
highlightChange: (ctx) => {
ctx.highlightedItem = ctx.collection.find(ctx.highlightedValue);
}
};
var invoke = {
valueChange: (ctx) => {
sync.valueChange(ctx);
ctx.onValueChange?.({
value: Array.from(ctx.value),
items: Array.from(ctx.selectedItems)
});
dispatchChangeEvent(ctx);
},
highlightChange: (ctx) => {
sync.highlightChange(ctx);
ctx.onHighlightChange?.({
highlightedValue: ctx.highlightedValue,
highlightedItem: ctx.highlightedItem,
highlightedIndex: ctx.collection.indexOf(ctx.highlightedValue)
});
}
};
var set = {
selectedItem: (ctx, value, force = false) => {
if (utils.isEqual(ctx.value, value)) return;
if (value == null && !force) return;
if (value == null && force) {
ctx.value = [];
invoke.valueChange(ctx);
return;
}
ctx.value = ctx.multiple ? utils.addOrRemove(ctx.value, value) : [value];
invoke.valueChange(ctx);
},
selectedItems: (ctx, value) => {
if (utils.isEqual(ctx.value, value)) return;
ctx.value = value;
invoke.valueChange(ctx);
},
highlightedItem: (ctx, value, force = false) => {
if (utils.isEqual(ctx.highlightedValue, value)) return;
if (value == null && !force) return;
ctx.highlightedValue = value ?? null;
invoke.highlightChange(ctx);
}
};
var props = types.createProps()([
"closeOnSelect",
"collection",
"dir",
"disabled",
"deselectable",
"form",
"getRootNode",
"highlightedValue",
"id",
"ids",
"invalid",
"loopFocus",
"multiple",
"name",
"onFocusOutside",
"onHighlightChange",
"onInteractOutside",
"onOpenChange",
"onPointerDownOutside",
"onValueChange",
"open.controlled",
"open",
"composite",
"positioning",
"required",
"readOnly",
"scrollToIndexFn",
"value"
]);
var splitProps = utils.createSplitProps(props);
var itemProps = types.createProps()(["item", "persistFocus"]);
var splitItemProps = utils.createSplitProps(itemProps);
var itemGroupProps = types.createProps()(["id"]);
var splitItemGroupProps = utils.createSplitProps(itemGroupProps);
var itemGroupLabelProps = types.createProps()(["htmlFor"]);
var splitItemGroupLabelProps = utils.createSplitProps(itemGroupLabelProps);
exports.anatomy = anatomy;
exports.collection = collection;
exports.connect = connect;
exports.itemGroupLabelProps = itemGroupLabelProps;
exports.itemGroupProps = itemGroupProps;
exports.itemProps = itemProps;
exports.machine = machine;
exports.props = props;
exports.splitItemGroupLabelProps = splitItemGroupLabelProps;
exports.splitItemGroupProps = splitItemGroupProps;
exports.splitItemProps = splitItemProps;
exports.splitProps = splitProps;
© 2015 - 2025 Weber Informatics LLC | Privacy Policy