import { c as create_ssr_component, v as validate_component, e as escape, a as each, b as add_attribute, s as spread, d as escape_attribute_value, f as escape_object, g as add_styles, h as merge_ssr_styles, m as missing_component } from './ssr-DX6yy04n.js'; import { I as Icon$1 } from './Icon-DFquJFK5.js'; import { c as compute_rest_props, b as getContext, a as subscribe, o as onDestroy, s as setContext, n as noop } from './lifecycle-CPZ0ouVO.js'; import { i as is_void, o as omit, w as withGet, c as createElHelpers, m as makeElement, s as styleToString, p as portalAttr, e as effect, a as isHTMLElement, b as executeCallbacks, d as addMeltEventListener, F as FIRST_LAST_KEYS, k as kbd, S as SELECTION_KEYS, u as useEscapeKeydown, n as noop$1, f as isElementDisabled, g as safeOnMount, h as isBrowser, j as addEventListener, l as disabledAttr } from './index3-TIAgGdNz.js'; import { d as derived, w as writable } from './index2-CkEewRlU.js'; import { c as createDispatcher, d as disabledAttrs, a as createBitAttrs, r as removeUndefined, g as getOptionUpdater, b as cn$1, t as toastState, e as toWritableStores, o as overridable, u as useEffect } from './index-EscoC7AS.js'; import { D as Dialog_content, a as Dialog_close, X as X$1, b as Dialog, c as Dialog_trigger, d as Dialog_portal, e as Dialog_overlay, f as fly, g as generateId, h as fade, i as getPositioningUpdater, j as createTypeaheadSearch, k as generateIds, l as derivedVisible, u as usePopper, m as getPortalDestination, n as handleRovingFocus, o as usePortal, s as sleep, r as removeHighlight, p as handleFocus, q as removeScroll, t as getNextFocusable, v as getPreviousFocusable, w as addHighlight } from './x-B9UrKsW1.js'; import { t as tick } from './scheduler-DW9WkiYZ.js'; import 'clsx'; import { tv } from 'tailwind-variants'; import { M as Mode_watcher, d as derivedMode } from './mode-watcher-BgZlA57W.js'; import './config-BHx687w1.js'; import { B as Button, c as cn, f as flyAndScale } from './button-DV8DKkH_.js'; import './ssr2-BVSPLo1E.js'; import './shared-server-i79vVjEm.js'; import 'tailwind-merge'; const Menu$1 = create_ssr_component(($$result, $$props, $$bindings, slots) => { const iconNode = [ [ "line", { "x1": "4", "x2": "20", "y1": "12", "y2": "12" } ], [ "line", { "x1": "4", "x2": "20", "y1": "6", "y2": "6" } ], [ "line", { "x1": "4", "x2": "20", "y1": "18", "y2": "18" } ] ]; return `${validate_component(Icon$1, "Icon").$$render($$result, Object.assign({}, { name: "menu" }, $$props, { iconNode }), {}, { default: () => { return `${slots.default ? slots.default({}) : ``}`; } })}`; }); const Menu$2 = Menu$1; const Package_2 = create_ssr_component(($$result, $$props, $$bindings, slots) => { const iconNode = [ [ "path", { "d": "M3 9h18v10a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V9Z" } ], [ "path", { "d": "m3 9 2.45-4.9A2 2 0 0 1 7.24 3h9.52a2 2 0 0 1 1.8 1.1L21 9" } ], ["path", { "d": "M12 3v6" }] ]; return `${validate_component(Icon$1, "Icon").$$render($$result, Object.assign({}, { name: "package-2" }, $$props, { iconNode }), {}, { default: () => { return `${slots.default ? slots.default({}) : ``}`; } })}`; }); const Package2 = Package_2; const Circle_user = create_ssr_component(($$result, $$props, $$bindings, slots) => { const iconNode = [ ["circle", { "cx": "12", "cy": "12", "r": "10" }], ["circle", { "cx": "12", "cy": "10", "r": "3" }], [ "path", { "d": "M7 20.662V19a2 2 0 0 1 2-2h6a2 2 0 0 1 2 2v1.662" } ] ]; return `${validate_component(Icon$1, "Icon").$$render($$result, Object.assign({}, { name: "circle-user" }, $$props, { iconNode }), {}, { default: () => { return `${slots.default ? slots.default({}) : ``}`; } })}`; }); const CircleUser = Circle_user; const Sun = create_ssr_component(($$result, $$props, $$bindings, slots) => { let $$restProps = compute_rest_props($$props, ["size", "role", "color", "ariaLabel", "withEvents"]); const ctx = getContext("iconCtx") ?? {}; let { size = ctx.size || "24" } = $$props; let { role = ctx.role || "img" } = $$props; let { color = ctx.color || "currentColor" } = $$props; let { ariaLabel = "sun," } = $$props; let { withEvents = false } = $$props; if ($$props.size === void 0 && $$bindings.size && size !== void 0) $$bindings.size(size); if ($$props.role === void 0 && $$bindings.role && role !== void 0) $$bindings.role(role); if ($$props.color === void 0 && $$bindings.color && color !== void 0) $$bindings.color(color); if ($$props.ariaLabel === void 0 && $$bindings.ariaLabel && ariaLabel !== void 0) $$bindings.ariaLabel(ariaLabel); if ($$props.withEvents === void 0 && $$bindings.withEvents && withEvents !== void 0) $$bindings.withEvents(withEvents); return `${withEvents ? `` : ``} `; }); const Moon = create_ssr_component(($$result, $$props, $$bindings, slots) => { let $$restProps = compute_rest_props($$props, ["size", "role", "color", "ariaLabel", "withEvents"]); const ctx = getContext("iconCtx") ?? {}; let { size = ctx.size || "24" } = $$props; let { role = ctx.role || "img" } = $$props; let { color = ctx.color || "currentColor" } = $$props; let { ariaLabel = "moon," } = $$props; let { withEvents = false } = $$props; if ($$props.size === void 0 && $$bindings.size && size !== void 0) $$bindings.size(size); if ($$props.role === void 0 && $$bindings.role && role !== void 0) $$bindings.role(role); if ($$props.color === void 0 && $$bindings.color && color !== void 0) $$bindings.color(color); if ($$props.ariaLabel === void 0 && $$bindings.ariaLabel && ariaLabel !== void 0) $$bindings.ariaLabel(ariaLabel); if ($$props.withEvents === void 0 && $$bindings.withEvents && withEvents !== void 0) $$bindings.withEvents(withEvents); return `${withEvents ? `` : ``} `; }); const SUB_OPEN_KEYS = { ltr: [...SELECTION_KEYS, kbd.ARROW_RIGHT], rtl: [...SELECTION_KEYS, kbd.ARROW_LEFT] }; const SUB_CLOSE_KEYS = { ltr: [kbd.ARROW_LEFT], rtl: [kbd.ARROW_RIGHT] }; const menuIdParts = ["menu", "trigger"]; const defaults$2 = { arrowSize: 8, positioning: { placement: "bottom" }, preventScroll: true, closeOnEscape: true, closeOnOutsideClick: true, portal: void 0, loop: false, dir: "ltr", defaultOpen: false, typeahead: true, closeOnItemClick: true, onOutsideClick: void 0 }; function createMenuBuilder(opts) { const { name, selector } = createElHelpers(opts.selector); const { preventScroll, arrowSize, positioning, closeOnEscape, closeOnOutsideClick, portal, forceVisible, typeahead, loop, closeFocus, disableFocusFirstItem, closeOnItemClick, onOutsideClick } = opts.rootOptions; const rootOpen = opts.rootOpen; const rootActiveTrigger = opts.rootActiveTrigger; const nextFocusable = opts.nextFocusable; const prevFocusable = opts.prevFocusable; const isUsingKeyboard = withGet.writable(false); const lastPointerX = withGet(writable(0)); const pointerGraceIntent = withGet(writable(null)); const pointerDir = withGet(writable("right")); const currentFocusedItem = withGet(writable(null)); const pointerMovingToSubmenu = withGet(derived([pointerDir, pointerGraceIntent], ([$pointerDir, $pointerGraceIntent]) => { return (e) => { const isMovingTowards = $pointerDir === $pointerGraceIntent?.side; return isMovingTowards && isPointerInGraceArea(e, $pointerGraceIntent?.area); }; })); const { typed, handleTypeaheadSearch } = createTypeaheadSearch(); const rootIds = toWritableStores({ ...generateIds(menuIdParts), ...opts.ids }); const isVisible = derivedVisible({ open: rootOpen, forceVisible, activeTrigger: rootActiveTrigger }); const rootMenu = makeElement(name(), { stores: [isVisible, portal, rootIds.menu, rootIds.trigger], returned: ([$isVisible, $portal, $rootMenuId, $rootTriggerId]) => { return { role: "menu", hidden: $isVisible ? void 0 : true, style: styleToString({ display: $isVisible ? void 0 : "none" }), id: $rootMenuId, "aria-labelledby": $rootTriggerId, "data-state": $isVisible ? "open" : "closed", "data-portal": portalAttr($portal), tabindex: -1 }; }, action: (node) => { let unsubPopper = noop$1; const unsubDerived = effect([isVisible, rootActiveTrigger, positioning, closeOnOutsideClick, portal, closeOnEscape], ([$isVisible, $rootActiveTrigger, $positioning, $closeOnOutsideClick, $portal, $closeOnEscape]) => { unsubPopper(); if (!$isVisible || !$rootActiveTrigger) return; tick().then(() => { unsubPopper(); setMeltMenuAttribute(node, selector); unsubPopper = usePopper(node, { anchorElement: $rootActiveTrigger, open: rootOpen, options: { floating: $positioning, modal: { closeOnInteractOutside: $closeOnOutsideClick, shouldCloseOnInteractOutside: (e) => { onOutsideClick.get()?.(e); if (e.defaultPrevented) return false; if (isHTMLElement($rootActiveTrigger) && $rootActiveTrigger.contains(e.target)) { return false; } return true; }, onClose: () => { rootOpen.set(false); $rootActiveTrigger.focus(); }, open: $isVisible }, portal: getPortalDestination(node, $portal), escapeKeydown: $closeOnEscape ? void 0 : null } }).destroy; }); }); const unsubEvents = executeCallbacks(addMeltEventListener(node, "keydown", (e) => { const target = e.target; const menuEl = e.currentTarget; if (!isHTMLElement(target) || !isHTMLElement(menuEl)) return; const isKeyDownInside = target.closest('[role="menu"]') === menuEl; if (!isKeyDownInside) return; if (FIRST_LAST_KEYS.includes(e.key)) { handleMenuNavigation(e, loop.get() ?? false); } if (e.key === kbd.TAB) { e.preventDefault(); rootOpen.set(false); handleTabNavigation(e, nextFocusable, prevFocusable); return; } const isCharacterKey = e.key.length === 1; const isModifierKey = e.ctrlKey || e.altKey || e.metaKey; if (!isModifierKey && isCharacterKey && typeahead.get() === true) { handleTypeaheadSearch(e.key, getMenuItems(menuEl)); } })); return { destroy() { unsubDerived(); unsubEvents(); unsubPopper(); } }; } }); const rootTrigger = makeElement(name("trigger"), { stores: [rootOpen, rootIds.menu, rootIds.trigger], returned: ([$rootOpen, $rootMenuId, $rootTriggerId]) => { return { "aria-controls": $rootMenuId, "aria-expanded": $rootOpen, "data-state": $rootOpen ? "open" : "closed", id: $rootTriggerId, tabindex: 0 }; }, action: (node) => { applyAttrsIfDisabled(node); rootActiveTrigger.update((p) => { if (p) return p; return node; }); const unsub = executeCallbacks(addMeltEventListener(node, "click", (e) => { const $rootOpen = rootOpen.get(); const triggerEl = e.currentTarget; if (!isHTMLElement(triggerEl)) return; handleOpen(triggerEl); if (!$rootOpen) e.preventDefault(); }), addMeltEventListener(node, "keydown", (e) => { const triggerEl = e.currentTarget; if (!isHTMLElement(triggerEl)) return; if (!(SELECTION_KEYS.includes(e.key) || e.key === kbd.ARROW_DOWN)) return; e.preventDefault(); handleOpen(triggerEl); const menuId = triggerEl.getAttribute("aria-controls"); if (!menuId) return; const menu = document.getElementById(menuId); if (!menu) return; const menuItems = getMenuItems(menu); if (!menuItems.length) return; handleRovingFocus(menuItems[0]); })); return { destroy: unsub }; } }); const rootArrow = makeElement(name("arrow"), { stores: arrowSize, returned: ($arrowSize) => ({ "data-arrow": true, style: styleToString({ position: "absolute", width: `var(--arrow-size, ${$arrowSize}px)`, height: `var(--arrow-size, ${$arrowSize}px)` }) }) }); const overlay = makeElement(name("overlay"), { stores: [isVisible], returned: ([$isVisible]) => { return { hidden: $isVisible ? void 0 : true, tabindex: -1, style: styleToString({ display: $isVisible ? void 0 : "none" }), "aria-hidden": "true", "data-state": stateAttr($isVisible) }; }, action: (node) => { let unsubEscapeKeydown = noop$1; if (closeOnEscape.get()) { const escapeKeydown = useEscapeKeydown(node, { handler: () => { rootOpen.set(false); const $rootActiveTrigger = rootActiveTrigger.get(); if ($rootActiveTrigger) $rootActiveTrigger.focus(); } }); if (escapeKeydown && escapeKeydown.destroy) { unsubEscapeKeydown = escapeKeydown.destroy; } } const unsubPortal = effect([portal], ([$portal]) => { if ($portal === null) return noop$1; const portalDestination = getPortalDestination(node, $portal); if (portalDestination === null) return noop$1; return usePortal(node, portalDestination).destroy; }); return { destroy() { unsubEscapeKeydown(); unsubPortal(); } }; } }); const item = makeElement(name("item"), { returned: () => { return { role: "menuitem", tabindex: -1, "data-orientation": "vertical" }; }, action: (node) => { setMeltMenuAttribute(node, selector); applyAttrsIfDisabled(node); const unsub = executeCallbacks(addMeltEventListener(node, "pointerdown", (e) => { const itemEl = e.currentTarget; if (!isHTMLElement(itemEl)) return; if (isElementDisabled(itemEl)) { e.preventDefault(); return; } }), addMeltEventListener(node, "click", (e) => { const itemEl = e.currentTarget; if (!isHTMLElement(itemEl)) return; if (isElementDisabled(itemEl)) { e.preventDefault(); return; } if (e.defaultPrevented) { handleRovingFocus(itemEl); return; } if (closeOnItemClick.get()) { sleep(1).then(() => { rootOpen.set(false); }); } }), addMeltEventListener(node, "keydown", (e) => { onItemKeyDown(e); }), addMeltEventListener(node, "pointermove", (e) => { onMenuItemPointerMove(e); }), addMeltEventListener(node, "pointerleave", (e) => { onMenuItemPointerLeave(e); }), addMeltEventListener(node, "focusin", (e) => { onItemFocusIn(e); }), addMeltEventListener(node, "focusout", (e) => { onItemFocusOut(e); })); return { destroy: unsub }; } }); const group = makeElement(name("group"), { returned: () => { return (groupId) => ({ role: "group", "aria-labelledby": groupId }); } }); const groupLabel = makeElement(name("group-label"), { returned: () => { return (groupId) => ({ id: groupId }); } }); const checkboxItemDefaults = { defaultChecked: false, disabled: false }; const createCheckboxItem = (props) => { const withDefaults = { ...checkboxItemDefaults, ...props }; const checkedWritable = withDefaults.checked ?? writable(withDefaults.defaultChecked ?? null); const checked = overridable(checkedWritable, withDefaults.onCheckedChange); const disabled = writable(withDefaults.disabled); const checkboxItem = makeElement(name("checkbox-item"), { stores: [checked, disabled], returned: ([$checked, $disabled]) => { return { role: "menuitemcheckbox", tabindex: -1, "data-orientation": "vertical", "aria-checked": isIndeterminate($checked) ? "mixed" : $checked ? "true" : "false", "data-disabled": disabledAttr($disabled), "data-state": getCheckedState($checked) }; }, action: (node) => { setMeltMenuAttribute(node, selector); applyAttrsIfDisabled(node); const unsub = executeCallbacks(addMeltEventListener(node, "pointerdown", (e) => { const itemEl = e.currentTarget; if (!isHTMLElement(itemEl)) return; if (isElementDisabled(itemEl)) { e.preventDefault(); return; } }), addMeltEventListener(node, "click", (e) => { const itemEl = e.currentTarget; if (!isHTMLElement(itemEl)) return; if (isElementDisabled(itemEl)) { e.preventDefault(); return; } if (e.defaultPrevented) { handleRovingFocus(itemEl); return; } checked.update((prev) => { if (isIndeterminate(prev)) return true; return !prev; }); if (closeOnItemClick.get()) { tick().then(() => { rootOpen.set(false); }); } }), addMeltEventListener(node, "keydown", (e) => { onItemKeyDown(e); }), addMeltEventListener(node, "pointermove", (e) => { const itemEl = e.currentTarget; if (!isHTMLElement(itemEl)) return; if (isElementDisabled(itemEl)) { onItemLeave(e); return; } onMenuItemPointerMove(e, itemEl); }), addMeltEventListener(node, "pointerleave", (e) => { onMenuItemPointerLeave(e); }), addMeltEventListener(node, "focusin", (e) => { onItemFocusIn(e); }), addMeltEventListener(node, "focusout", (e) => { onItemFocusOut(e); })); return { destroy: unsub }; } }); const isChecked = derived(checked, ($checked) => $checked === true); const _isIndeterminate = derived(checked, ($checked) => $checked === "indeterminate"); return { elements: { checkboxItem }, states: { checked }, helpers: { isChecked, isIndeterminate: _isIndeterminate }, options: { disabled } }; }; const createMenuRadioGroup = (args = {}) => { const valueWritable = args.value ?? writable(args.defaultValue ?? null); const value = overridable(valueWritable, args.onValueChange); const radioGroup = makeElement(name("radio-group"), { returned: () => ({ role: "group" }) }); const radioItemDefaults = { disabled: false }; const radioItem = makeElement(name("radio-item"), { stores: [value], returned: ([$value]) => { return (itemProps) => { const { value: itemValue, disabled } = { ...radioItemDefaults, ...itemProps }; const checked = $value === itemValue; return { disabled, role: "menuitemradio", "data-state": checked ? "checked" : "unchecked", "aria-checked": checked, "data-disabled": disabledAttr(disabled), "data-value": itemValue, "data-orientation": "vertical", tabindex: -1 }; }; }, action: (node) => { setMeltMenuAttribute(node, selector); const unsub = executeCallbacks(addMeltEventListener(node, "pointerdown", (e) => { const itemEl = e.currentTarget; if (!isHTMLElement(itemEl)) return; const itemValue = node.dataset.value; const disabled = node.dataset.disabled; if (disabled || itemValue === void 0) { e.preventDefault(); return; } }), addMeltEventListener(node, "click", (e) => { const itemEl = e.currentTarget; if (!isHTMLElement(itemEl)) return; const itemValue = node.dataset.value; const disabled = node.dataset.disabled; if (disabled || itemValue === void 0) { e.preventDefault(); return; } if (e.defaultPrevented) { if (!isHTMLElement(itemEl)) return; handleRovingFocus(itemEl); return; } value.set(itemValue); if (closeOnItemClick.get()) { tick().then(() => { rootOpen.set(false); }); } }), addMeltEventListener(node, "keydown", (e) => { onItemKeyDown(e); }), addMeltEventListener(node, "pointermove", (e) => { const itemEl = e.currentTarget; if (!isHTMLElement(itemEl)) return; const itemValue = node.dataset.value; const disabled = node.dataset.disabled; if (disabled || itemValue === void 0) { onItemLeave(e); return; } onMenuItemPointerMove(e, itemEl); }), addMeltEventListener(node, "pointerleave", (e) => { onMenuItemPointerLeave(e); }), addMeltEventListener(node, "focusin", (e) => { onItemFocusIn(e); }), addMeltEventListener(node, "focusout", (e) => { onItemFocusOut(e); })); return { destroy: unsub }; } }); const isChecked = derived(value, ($value) => { return (itemValue) => { return $value === itemValue; }; }); return { elements: { radioGroup, radioItem }, states: { value }, helpers: { isChecked } }; }; const { elements: { root: separator } } = createSeparator({ orientation: "horizontal" }); const subMenuDefaults = { ...defaults$2, disabled: false, positioning: { placement: "right-start", gutter: 8 } }; const createSubmenu = (args) => { const withDefaults = { ...subMenuDefaults, ...args }; const subOpenWritable = withDefaults.open ?? writable(false); const subOpen = overridable(subOpenWritable, withDefaults?.onOpenChange); const options = toWritableStores(omit(withDefaults, "ids")); const { positioning: positioning2, arrowSize: arrowSize2, disabled } = options; const subActiveTrigger = withGet(writable(null)); const subOpenTimer = withGet(writable(null)); const pointerGraceTimer = withGet(writable(0)); const subIds = toWritableStores({ ...generateIds(menuIdParts), ...withDefaults.ids }); safeOnMount(() => { const subTrigger2 = document.getElementById(subIds.trigger.get()); if (subTrigger2) { subActiveTrigger.set(subTrigger2); } }); const subIsVisible = derivedVisible({ open: subOpen, forceVisible, activeTrigger: subActiveTrigger }); const subMenu = makeElement(name("submenu"), { stores: [subIsVisible, subIds.menu, subIds.trigger], returned: ([$subIsVisible, $subMenuId, $subTriggerId]) => { return { role: "menu", hidden: $subIsVisible ? void 0 : true, style: styleToString({ display: $subIsVisible ? void 0 : "none" }), id: $subMenuId, "aria-labelledby": $subTriggerId, "data-state": $subIsVisible ? "open" : "closed", // unit tests fail on `.closest` if the id starts with a number // so using a data attribute "data-id": $subMenuId, tabindex: -1 }; }, action: (node) => { let unsubPopper = noop$1; const unsubDerived = effect([subIsVisible, positioning2], ([$subIsVisible, $positioning]) => { unsubPopper(); if (!$subIsVisible) return; const activeTrigger = subActiveTrigger.get(); if (!activeTrigger) return; tick().then(() => { unsubPopper(); const parentMenuEl = getParentMenu(activeTrigger); unsubPopper = usePopper(node, { anchorElement: activeTrigger, open: subOpen, options: { floating: $positioning, portal: isHTMLElement(parentMenuEl) ? parentMenuEl : void 0, modal: null, focusTrap: null, escapeKeydown: null } }).destroy; }); }); const unsubEvents = executeCallbacks(addMeltEventListener(node, "keydown", (e) => { if (e.key === kbd.ESCAPE) { return; } const target = e.target; const menuEl = e.currentTarget; if (!isHTMLElement(target) || !isHTMLElement(menuEl)) return; const isKeyDownInside = target.closest('[role="menu"]') === menuEl; if (!isKeyDownInside) return; if (FIRST_LAST_KEYS.includes(e.key)) { e.stopImmediatePropagation(); handleMenuNavigation(e, loop.get() ?? false); return; } const isCloseKey = SUB_CLOSE_KEYS["ltr"].includes(e.key); const isModifierKey = e.ctrlKey || e.altKey || e.metaKey; const isCharacterKey = e.key.length === 1; if (isCloseKey) { const $subActiveTrigger = subActiveTrigger.get(); e.preventDefault(); subOpen.update(() => { if ($subActiveTrigger) { handleRovingFocus($subActiveTrigger); } return false; }); return; } if (e.key === kbd.TAB) { e.preventDefault(); rootOpen.set(false); handleTabNavigation(e, nextFocusable, prevFocusable); return; } if (!isModifierKey && isCharacterKey && typeahead.get() === true) { handleTypeaheadSearch(e.key, getMenuItems(menuEl)); } }), addMeltEventListener(node, "pointermove", (e) => { onMenuPointerMove(e); }), addMeltEventListener(node, "focusout", (e) => { const $subActiveTrigger = subActiveTrigger.get(); if (isUsingKeyboard.get()) { const target = e.target; const submenuEl = document.getElementById(subIds.menu.get()); if (!isHTMLElement(submenuEl) || !isHTMLElement(target)) return; if (!submenuEl.contains(target) && target !== $subActiveTrigger) { subOpen.set(false); } } else { const menuEl = e.currentTarget; const relatedTarget = e.relatedTarget; if (!isHTMLElement(relatedTarget) || !isHTMLElement(menuEl)) return; if (!menuEl.contains(relatedTarget) && relatedTarget !== $subActiveTrigger) { subOpen.set(false); } } })); return { destroy() { unsubDerived(); unsubPopper(); unsubEvents(); } }; } }); const subTrigger = makeElement(name("subtrigger"), { stores: [subOpen, disabled, subIds.menu, subIds.trigger], returned: ([$subOpen, $disabled, $subMenuId, $subTriggerId]) => { return { role: "menuitem", id: $subTriggerId, tabindex: -1, "aria-controls": $subMenuId, "aria-expanded": $subOpen, "data-state": $subOpen ? "open" : "closed", "data-disabled": disabledAttr($disabled), "aria-haspopop": "menu" }; }, action: (node) => { setMeltMenuAttribute(node, selector); applyAttrsIfDisabled(node); subActiveTrigger.update((p) => { if (p) return p; return node; }); const unsubTimer = () => { clearTimerStore(subOpenTimer); window.clearTimeout(pointerGraceTimer.get()); pointerGraceIntent.set(null); }; const unsubEvents = executeCallbacks(addMeltEventListener(node, "click", (e) => { if (e.defaultPrevented) return; const triggerEl = e.currentTarget; if (!isHTMLElement(triggerEl) || isElementDisabled(triggerEl)) return; handleRovingFocus(triggerEl); if (!subOpen.get()) { subOpen.update((prev) => { const isAlreadyOpen = prev; if (!isAlreadyOpen) { subActiveTrigger.set(triggerEl); return !prev; } return prev; }); } }), addMeltEventListener(node, "keydown", (e) => { const $typed = typed.get(); const triggerEl = e.currentTarget; if (!isHTMLElement(triggerEl) || isElementDisabled(triggerEl)) return; const isTypingAhead = $typed.length > 0; if (isTypingAhead && e.key === kbd.SPACE) return; if (SUB_OPEN_KEYS["ltr"].includes(e.key)) { if (!subOpen.get()) { triggerEl.click(); e.preventDefault(); return; } const menuId = triggerEl.getAttribute("aria-controls"); if (!menuId) return; const menuEl = document.getElementById(menuId); if (!isHTMLElement(menuEl)) return; const firstItem = getMenuItems(menuEl)[0]; handleRovingFocus(firstItem); } }), addMeltEventListener(node, "pointermove", (e) => { if (!isMouse(e)) return; onItemEnter(e); if (e.defaultPrevented) return; const triggerEl = e.currentTarget; if (!isHTMLElement(triggerEl)) return; if (!isFocusWithinSubmenu(subIds.menu.get())) { handleRovingFocus(triggerEl); } const openTimer = subOpenTimer.get(); if (!subOpen.get() && !openTimer && !isElementDisabled(triggerEl)) { subOpenTimer.set(window.setTimeout(() => { subOpen.update(() => { subActiveTrigger.set(triggerEl); return true; }); clearTimerStore(subOpenTimer); }, 100)); } }), addMeltEventListener(node, "pointerleave", (e) => { if (!isMouse(e)) return; clearTimerStore(subOpenTimer); const submenuEl = document.getElementById(subIds.menu.get()); const contentRect = submenuEl?.getBoundingClientRect(); if (contentRect) { const side = submenuEl?.dataset.side; const rightSide = side === "right"; const bleed = rightSide ? -5 : 5; const contentNearEdge = contentRect[rightSide ? "left" : "right"]; const contentFarEdge = contentRect[rightSide ? "right" : "left"]; pointerGraceIntent.set({ area: [ // Apply a bleed on clientX to ensure that our exit point is // consistently within polygon bounds { x: e.clientX + bleed, y: e.clientY }, { x: contentNearEdge, y: contentRect.top }, { x: contentFarEdge, y: contentRect.top }, { x: contentFarEdge, y: contentRect.bottom }, { x: contentNearEdge, y: contentRect.bottom } ], side }); window.clearTimeout(pointerGraceTimer.get()); pointerGraceTimer.set(window.setTimeout(() => { pointerGraceIntent.set(null); }, 300)); } else { onTriggerLeave(e); if (e.defaultPrevented) return; pointerGraceIntent.set(null); } }), addMeltEventListener(node, "focusout", (e) => { const triggerEl = e.currentTarget; if (!isHTMLElement(triggerEl)) return; removeHighlight(triggerEl); const relatedTarget = e.relatedTarget; if (!isHTMLElement(relatedTarget)) return; const menuId = triggerEl.getAttribute("aria-controls"); if (!menuId) return; const menu = document.getElementById(menuId); if (menu && !menu.contains(relatedTarget)) { subOpen.set(false); } }), addMeltEventListener(node, "focusin", (e) => { onItemFocusIn(e); })); return { destroy() { unsubTimer(); unsubEvents(); } }; } }); const subArrow = makeElement(name("subarrow"), { stores: arrowSize2, returned: ($arrowSize) => ({ "data-arrow": true, style: styleToString({ position: "absolute", width: `var(--arrow-size, ${$arrowSize}px)`, height: `var(--arrow-size, ${$arrowSize}px)` }) }) }); effect([rootOpen], ([$rootOpen]) => { if (!$rootOpen) { subActiveTrigger.set(null); subOpen.set(false); } }); effect([pointerGraceIntent], ([$pointerGraceIntent]) => { if (!isBrowser || $pointerGraceIntent) return; window.clearTimeout(pointerGraceTimer.get()); }); effect([subOpen], ([$subOpen]) => { if (!isBrowser) return; if ($subOpen && isUsingKeyboard.get()) { sleep(1).then(() => { const menuEl = document.getElementById(subIds.menu.get()); if (!menuEl) return; const menuItems = getMenuItems(menuEl); if (!menuItems.length) return; handleRovingFocus(menuItems[0]); }); } if (!$subOpen) { const focusedItem = currentFocusedItem.get(); const subTriggerEl = document.getElementById(subIds.trigger.get()); if (focusedItem) { sleep(1).then(() => { const menuEl = document.getElementById(subIds.menu.get()); if (!menuEl) return; if (menuEl.contains(focusedItem)) { removeHighlight(focusedItem); } }); } if (!subTriggerEl || document.activeElement === subTriggerEl) return; removeHighlight(subTriggerEl); } }); return { ids: subIds, elements: { subTrigger, subMenu, subArrow }, states: { subOpen }, options }; }; safeOnMount(() => { const triggerEl = document.getElementById(rootIds.trigger.get()); if (isHTMLElement(triggerEl) && rootOpen.get()) { rootActiveTrigger.set(triggerEl); } const unsubs = []; const handlePointer = () => isUsingKeyboard.set(false); const handleKeyDown = () => { isUsingKeyboard.set(true); unsubs.push(executeCallbacks(addEventListener(document, "pointerdown", handlePointer, { capture: true, once: true }), addEventListener(document, "pointermove", handlePointer, { capture: true, once: true }))); }; const keydownListener = (e) => { if (e.key === kbd.ESCAPE && closeOnEscape.get()) { rootOpen.set(false); return; } }; unsubs.push(addEventListener(document, "keydown", handleKeyDown, { capture: true })); unsubs.push(addEventListener(document, "keydown", keydownListener)); return () => { unsubs.forEach((unsub) => unsub()); }; }); effect([rootOpen, currentFocusedItem], ([$rootOpen, $currentFocusedItem]) => { if (!$rootOpen && $currentFocusedItem) { removeHighlight($currentFocusedItem); } }); effect([rootOpen], ([$rootOpen]) => { if (!isBrowser) return; if (!$rootOpen) { const $rootActiveTrigger = rootActiveTrigger.get(); if (!$rootActiveTrigger) return; const $closeFocus = closeFocus.get(); if (!$rootOpen && $rootActiveTrigger) { handleFocus({ prop: $closeFocus, defaultEl: $rootActiveTrigger }); } } }); effect([rootOpen, preventScroll], ([$rootOpen, $preventScroll]) => { if (!isBrowser) return; const unsubs = []; if (opts.removeScroll && $rootOpen && $preventScroll) { unsubs.push(removeScroll()); } sleep(1).then(() => { const menuEl = document.getElementById(rootIds.menu.get()); if (menuEl && $rootOpen && isUsingKeyboard.get()) { if (disableFocusFirstItem.get()) { handleRovingFocus(menuEl); return; } const menuItems = getMenuItems(menuEl); if (!menuItems.length) return; handleRovingFocus(menuItems[0]); } }); return () => { unsubs.forEach((unsub) => unsub()); }; }); effect(rootOpen, ($rootOpen) => { if (!isBrowser) return; const handlePointer = () => isUsingKeyboard.set(false); const handleKeyDown = (e) => { isUsingKeyboard.set(true); if (e.key === kbd.ESCAPE && $rootOpen && closeOnEscape.get()) { rootOpen.set(false); return; } }; return executeCallbacks(addEventListener(document, "pointerdown", handlePointer, { capture: true, once: true }), addEventListener(document, "pointermove", handlePointer, { capture: true, once: true }), addEventListener(document, "keydown", handleKeyDown, { capture: true })); }); function handleOpen(triggerEl) { rootOpen.update((prev) => { const isOpen = !prev; if (isOpen) { nextFocusable.set(getNextFocusable(triggerEl)); prevFocusable.set(getPreviousFocusable(triggerEl)); rootActiveTrigger.set(triggerEl); } return isOpen; }); } function onItemFocusIn(e) { const itemEl = e.currentTarget; if (!isHTMLElement(itemEl)) return; const $currentFocusedItem = currentFocusedItem.get(); if ($currentFocusedItem) { removeHighlight($currentFocusedItem); } addHighlight(itemEl); currentFocusedItem.set(itemEl); } function onItemFocusOut(e) { const itemEl = e.currentTarget; if (!isHTMLElement(itemEl)) return; removeHighlight(itemEl); } function onItemEnter(e) { if (isPointerMovingToSubmenu(e)) { e.preventDefault(); } } function onItemLeave(e) { if (isPointerMovingToSubmenu(e)) { return; } const target = e.target; if (!isHTMLElement(target)) return; const parentMenuEl = getParentMenu(target); if (!parentMenuEl) return; handleRovingFocus(parentMenuEl); } function onTriggerLeave(e) { if (isPointerMovingToSubmenu(e)) { e.preventDefault(); } } function onMenuPointerMove(e) { if (!isMouse(e)) return; const target = e.target; const currentTarget = e.currentTarget; if (!isHTMLElement(currentTarget) || !isHTMLElement(target)) return; const $lastPointerX = lastPointerX.get(); const pointerXHasChanged = $lastPointerX !== e.clientX; if (currentTarget.contains(target) && pointerXHasChanged) { const newDir = e.clientX > $lastPointerX ? "right" : "left"; pointerDir.set(newDir); lastPointerX.set(e.clientX); } } function onMenuItemPointerMove(e, currTarget = null) { if (!isMouse(e)) return; onItemEnter(e); if (e.defaultPrevented) return; if (currTarget) { handleRovingFocus(currTarget); return; } const currentTarget = e.currentTarget; if (!isHTMLElement(currentTarget)) return; handleRovingFocus(currentTarget); } function onMenuItemPointerLeave(e) { if (!isMouse(e)) return; onItemLeave(e); } function onItemKeyDown(e) { const $typed = typed.get(); const isTypingAhead = $typed.length > 0; if (isTypingAhead && e.key === kbd.SPACE) { e.preventDefault(); return; } if (SELECTION_KEYS.includes(e.key)) { e.preventDefault(); const itemEl = e.currentTarget; if (!isHTMLElement(itemEl)) return; itemEl.click(); } } function isIndeterminate(checked) { return checked === "indeterminate"; } function getCheckedState(checked) { return isIndeterminate(checked) ? "indeterminate" : checked ? "checked" : "unchecked"; } function isPointerMovingToSubmenu(e) { return pointerMovingToSubmenu.get()(e); } function getParentMenu(element) { const parentMenuEl = element.closest('[role="menu"]'); if (!isHTMLElement(parentMenuEl)) return null; return parentMenuEl; } return { elements: { trigger: rootTrigger, menu: rootMenu, overlay, item, group, groupLabel, arrow: rootArrow, separator }, builders: { createCheckboxItem, createSubmenu, createMenuRadioGroup }, states: { open: rootOpen }, helpers: { handleTypeaheadSearch }, ids: rootIds, options: opts.rootOptions }; } function handleTabNavigation(e, nextFocusable, prevFocusable) { if (e.shiftKey) { const $prevFocusable = prevFocusable.get(); if ($prevFocusable) { e.preventDefault(); sleep(1).then(() => $prevFocusable.focus()); prevFocusable.set(null); } } else { const $nextFocusable = nextFocusable.get(); if ($nextFocusable) { e.preventDefault(); sleep(1).then(() => $nextFocusable.focus()); nextFocusable.set(null); } } } function getMenuItems(menuElement) { return Array.from(menuElement.querySelectorAll(`[data-melt-menu-id="${menuElement.id}"]`)).filter((item) => isHTMLElement(item)); } function applyAttrsIfDisabled(element) { if (!element || !isElementDisabled(element)) return; element.setAttribute("data-disabled", ""); element.setAttribute("aria-disabled", "true"); } function clearTimerStore(timerStore) { if (!isBrowser) return; const timer = timerStore.get(); if (timer) { window.clearTimeout(timer); timerStore.set(null); } } function isMouse(e) { return e.pointerType === "mouse"; } function setMeltMenuAttribute(element, selector) { if (!element) return; const menuEl = element.closest(`${selector()}, ${selector("submenu")}`); if (!isHTMLElement(menuEl)) return; element.setAttribute("data-melt-menu-id", menuEl.id); } function handleMenuNavigation(e, loop) { e.preventDefault(); const currentFocusedItem = document.activeElement; const currentTarget = e.currentTarget; if (!isHTMLElement(currentFocusedItem) || !isHTMLElement(currentTarget)) return; const menuItems = getMenuItems(currentTarget); if (!menuItems.length) return; const candidateNodes = menuItems.filter((item) => { if (item.hasAttribute("data-disabled") || item.getAttribute("disabled") === "true") { return false; } return true; }); const currentIndex = candidateNodes.indexOf(currentFocusedItem); let nextIndex; switch (e.key) { case kbd.ARROW_DOWN: if (loop) { nextIndex = currentIndex < candidateNodes.length - 1 ? currentIndex + 1 : 0; } else { nextIndex = currentIndex < candidateNodes.length - 1 ? currentIndex + 1 : currentIndex; } break; case kbd.ARROW_UP: if (loop) { nextIndex = currentIndex > 0 ? currentIndex - 1 : candidateNodes.length - 1; } else { nextIndex = currentIndex < 0 ? candidateNodes.length - 1 : currentIndex > 0 ? currentIndex - 1 : 0; } break; case kbd.HOME: nextIndex = 0; break; case kbd.END: nextIndex = candidateNodes.length - 1; break; default: return; } handleRovingFocus(candidateNodes[nextIndex]); } function isPointerInGraceArea(e, area) { if (!area) return false; const cursorPos = { x: e.clientX, y: e.clientY }; return isPointInPolygon(cursorPos, area); } function isPointInPolygon(point, polygon) { const { x, y } = point; let inside = false; for (let i = 0, j = polygon.length - 1; i < polygon.length; j = i++) { const xi = polygon[i].x; const yi = polygon[i].y; const xj = polygon[j].x; const yj = polygon[j].y; const intersect = yi > y !== yj > y && x < (xj - xi) * (y - yi) / (yj - yi) + xi; if (intersect) inside = !inside; } return inside; } function isFocusWithinSubmenu(submenuId) { const activeEl = document.activeElement; if (!isHTMLElement(activeEl)) return false; const submenuEl = activeEl.closest(`[data-id="${submenuId}"]`); return isHTMLElement(submenuEl); } function stateAttr(open) { return open ? "open" : "closed"; } const defaults$1 = { arrowSize: 8, positioning: { placement: "bottom" }, preventScroll: true, closeOnEscape: true, closeOnOutsideClick: true, portal: void 0, loop: false, dir: "ltr", defaultOpen: false, forceVisible: false, typeahead: true, closeFocus: void 0, disableFocusFirstItem: false, closeOnItemClick: true, onOutsideClick: void 0 }; function createDropdownMenu(props) { const withDefaults = { ...defaults$1, ...props }; const rootOptions = toWritableStores(omit(withDefaults, "ids")); const openWritable = withDefaults.open ?? writable(withDefaults.defaultOpen); const rootOpen = overridable(openWritable, withDefaults?.onOpenChange); const rootActiveTrigger = withGet(writable(null)); const nextFocusable = withGet(writable(null)); const prevFocusable = withGet(writable(null)); const { elements, builders, ids, states, options } = createMenuBuilder({ rootOptions, rootOpen, rootActiveTrigger: withGet(rootActiveTrigger), nextFocusable: withGet(nextFocusable), prevFocusable: withGet(prevFocusable), selector: "dropdown-menu", removeScroll: true, ids: withDefaults.ids }); return { ids, elements, states, builders, options }; } const defaults = { orientation: "horizontal", decorative: false }; const createSeparator = (props) => { const withDefaults = { ...defaults, ...props }; const options = toWritableStores(withDefaults); const { orientation, decorative } = options; const root = makeElement("separator", { stores: [orientation, decorative], returned: ([$orientation, $decorative]) => { const ariaOrientation = $orientation === "vertical" ? $orientation : void 0; return { role: $decorative ? "none" : "separator", "aria-orientation": ariaOrientation, "aria-hidden": $decorative, "data-orientation": $orientation }; } }); return { elements: { root }, options }; }; function getMenuData() { const NAME = "menu"; const SUB_NAME = "menu-submenu"; const RADIO_GROUP_NAME = "menu-radiogroup"; const CHECKBOX_ITEM_NAME = "menu-checkboxitem"; const RADIO_ITEM_NAME = "menu-radioitem"; const GROUP_NAME = "menu-group"; const PARTS = [ "arrow", "checkbox-indicator", "checkbox-item", "content", "group", "item", "label", "radio-group", "radio-item", "radio-indicator", "separator", "sub-content", "sub-trigger", "trigger" ]; return { NAME, SUB_NAME, RADIO_GROUP_NAME, CHECKBOX_ITEM_NAME, RADIO_ITEM_NAME, GROUP_NAME, PARTS }; } function getCtx() { const { NAME } = getMenuData(); return getContext(NAME); } function setCtx(props) { const { NAME, PARTS } = getMenuData(); const getAttrs = createBitAttrs("menu", PARTS); const dropdownMenu = { ...createDropdownMenu({ ...removeUndefined(props), forceVisible: true }), getAttrs }; setContext(NAME, dropdownMenu); return { ...dropdownMenu, updateOption: getOptionUpdater(dropdownMenu.options) }; } function getGroupLabel() { const { GROUP_NAME } = getMenuData(); const id = getContext(GROUP_NAME) ?? generateId(); const { elements: { groupLabel }, getAttrs } = getCtx(); return { groupLabel, id, getAttrs }; } function updatePositioning(props) { const defaultPlacement = { side: "bottom", align: "center" }; const withDefaults = { ...defaultPlacement, ...props }; const { options: { positioning } } = getCtx(); const updater = getPositioningUpdater(positioning); updater(withDefaults); } const Menu_item = create_ssr_component(($$result, $$props, $$bindings, slots) => { let builder; let attrs; let $$restProps = compute_rest_props($$props, ["href", "asChild", "disabled", "el"]); let $item, $$unsubscribe_item; let { href = void 0 } = $$props; let { asChild = false } = $$props; let { disabled = false } = $$props; let { el = void 0 } = $$props; const { elements: { item }, getAttrs } = getCtx(); $$unsubscribe_item = subscribe(item, (value) => $item = value); createDispatcher(); if ($$props.href === void 0 && $$bindings.href && href !== void 0) $$bindings.href(href); if ($$props.asChild === void 0 && $$bindings.asChild && asChild !== void 0) $$bindings.asChild(asChild); if ($$props.disabled === void 0 && $$bindings.disabled && disabled !== void 0) $$bindings.disabled(disabled); if ($$props.el === void 0 && $$bindings.el && el !== void 0) $$bindings.el(el); builder = $item; attrs = { ...getAttrs("item"), ...disabledAttrs(disabled) }; { Object.assign(builder, attrs); } $$unsubscribe_item(); return `${asChild ? `${slots.default ? slots.default({ builder }) : ``}` : `${((tag) => { return tag ? `<${href ? "a" : "div"}${spread( [ { href: escape_attribute_value(href) }, escape_object(builder), escape_object($$restProps) ], {} )}${add_attribute("this", el, 0)}>${is_void(tag) ? "" : `${slots.default ? slots.default({ builder }) : ``}`}${is_void(tag) ? "" : `${tag}>`}` : ""; })(href ? "a" : "div")}`}`; }); const Menu_label = create_ssr_component(($$result, $$props, $$bindings, slots) => { let builder; let $$restProps = compute_rest_props($$props, ["asChild", "el"]); let $groupLabel, $$unsubscribe_groupLabel; let { asChild = false } = $$props; let { el = void 0 } = $$props; const { groupLabel, id, getAttrs } = getGroupLabel(); $$unsubscribe_groupLabel = subscribe(groupLabel, (value) => $groupLabel = value); const attrs = getAttrs("label"); if ($$props.asChild === void 0 && $$bindings.asChild && asChild !== void 0) $$bindings.asChild(asChild); if ($$props.el === void 0 && $$bindings.el && el !== void 0) $$bindings.el(el); builder = $groupLabel(id); { Object.assign(builder, attrs); } $$unsubscribe_groupLabel(); return `${asChild ? `${slots.default ? slots.default({ builder }) : ``}` : `