All Downloads are FREE. Search and download functionalities are using the official Maven repository.

package.dist.index.js Maven / Gradle / Ivy

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