@vielzeug/refine 2.0.1 → 2.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (74) hide show
  1. package/dist/calendar.cjs +1 -1
  2. package/dist/calendar.cjs.map +1 -1
  3. package/dist/calendar.js +1 -1
  4. package/dist/calendar.js.map +1 -1
  5. package/dist/combobox.cjs +1 -1
  6. package/dist/combobox.cjs.map +1 -1
  7. package/dist/combobox.js +1 -1
  8. package/dist/combobox.js.map +1 -1
  9. package/dist/core/choice-field.cjs +1 -1
  10. package/dist/core/choice-field.cjs.map +1 -1
  11. package/dist/core/choice-field.d.ts.map +1 -1
  12. package/dist/core/choice-field.js +18 -17
  13. package/dist/core/choice-field.js.map +1 -1
  14. package/dist/core/date-picker.cjs +1 -1
  15. package/dist/core/date-picker.cjs.map +1 -1
  16. package/dist/core/date-picker.d.ts.map +1 -1
  17. package/dist/core/date-picker.js +7 -7
  18. package/dist/core/date-picker.js.map +1 -1
  19. package/dist/core/focus.cjs +1 -1
  20. package/dist/core/focus.cjs.map +1 -1
  21. package/dist/core/focus.d.ts +5 -0
  22. package/dist/core/focus.d.ts.map +1 -1
  23. package/dist/core/focus.js +12 -5
  24. package/dist/core/focus.js.map +1 -1
  25. package/dist/core/index.d.ts +3 -3
  26. package/dist/core/index.d.ts.map +1 -1
  27. package/dist/core/option-list.cjs +1 -1
  28. package/dist/core/option-list.cjs.map +1 -1
  29. package/dist/core/option-list.d.ts +5 -0
  30. package/dist/core/option-list.d.ts.map +1 -1
  31. package/dist/core/option-list.js +20 -13
  32. package/dist/core/option-list.js.map +1 -1
  33. package/dist/core/overlay.cjs +1 -1
  34. package/dist/core/overlay.cjs.map +1 -1
  35. package/dist/core/overlay.d.ts +8 -2
  36. package/dist/core/overlay.d.ts.map +1 -1
  37. package/dist/core/overlay.js +1 -1
  38. package/dist/core/overlay.js.map +1 -1
  39. package/dist/custom-elements.json +6857 -7074
  40. package/dist/date-picker.cjs +1 -1
  41. package/dist/date-picker.cjs.map +1 -1
  42. package/dist/date-picker.js +1 -1
  43. package/dist/date-picker.js.map +1 -1
  44. package/dist/inputs/select/select.d.ts.map +1 -1
  45. package/dist/menu.cjs +3 -3
  46. package/dist/menu.cjs.map +1 -1
  47. package/dist/menu.js +34 -34
  48. package/dist/menu.js.map +1 -1
  49. package/dist/overlay/menu/menu.d.ts.map +1 -1
  50. package/dist/overlay/shared/use-dialog.cjs +1 -1
  51. package/dist/overlay/shared/use-dialog.cjs.map +1 -1
  52. package/dist/overlay/shared/use-dialog.d.ts.map +1 -1
  53. package/dist/overlay/shared/use-dialog.js +5 -5
  54. package/dist/overlay/shared/use-dialog.js.map +1 -1
  55. package/dist/overlay/shared/use-floating-trigger.cjs +1 -1
  56. package/dist/overlay/shared/use-floating-trigger.cjs.map +1 -1
  57. package/dist/overlay/shared/use-floating-trigger.d.ts.map +1 -1
  58. package/dist/overlay/shared/use-floating-trigger.js +13 -7
  59. package/dist/overlay/shared/use-floating-trigger.js.map +1 -1
  60. package/dist/refine.cjs +111 -111
  61. package/dist/refine.cjs.map +1 -1
  62. package/dist/refine.iife.js +111 -111
  63. package/dist/refine.iife.js.map +1 -1
  64. package/dist/refine.js +91 -91
  65. package/dist/refine.js.map +1 -1
  66. package/dist/select.cjs +1 -1
  67. package/dist/select.cjs.map +1 -1
  68. package/dist/select.js +17 -17
  69. package/dist/select.js.map +1 -1
  70. package/package.json +41 -40
  71. package/dist/core/_internal.d.ts +0 -15
  72. package/dist/core/_internal.d.ts.map +0 -1
  73. package/dist/core/paginated-list.d.ts +0 -42
  74. package/dist/core/paginated-list.d.ts.map +0 -1
package/dist/menu.cjs.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"menu.cjs","names":[],"sources":["../src/overlay/menu/menu.ts"],"sourcesContent":["import type { Placement } from '@vielzeug/orbit';\n\nimport {\n createStableId,\n define,\n html,\n prop,\n bind,\n getHost,\n onCleanup,\n onMounted,\n useEmit,\n useSlots,\n watchEffect,\n} from '@vielzeug/ore';\nimport { computed, signal } from '@vielzeug/ripple';\nimport { watch as rippleWatch } from '@vielzeug/ripple/watch';\n\nimport type { ComponentSize } from '../../types';\n\nimport {\n lifecycleSignal,\n createInteraction,\n type DropdownCloseReason,\n type OverlayOpenChangeDetail,\n type OverlayOpenReason,\n} from '../../core';\nimport { createListControl, createDropdownPositioner } from '../../core/_internal';\nimport { createOutsidePointerDismissal, restoreFocus } from '../../core/overlay';\nimport { disablableBundle, MENU_SIZE_PRESET, sizableBundle } from '../../shared';\nimport { colorThemeMixin, forcedColorsMixin, sizeVariantMixin } from '../../styles';\nimport menuItemStyles from './menu-item.css?inline';\nimport menuSeparatorStyles from './menu-separator.css?inline';\nimport componentStyles from './menu.css?inline';\n\n// ── Types ─────────────────────────────────────────────────────────────\n\nexport interface MenuSelectDetail {\n value: string;\n checked?: boolean;\n}\n\nexport type OreMenuItemType = 'checkbox' | 'radio';\n\nexport type OreMenuEvents = {\n 'open-change': OverlayOpenChangeDetail;\n select: MenuSelectDetail;\n};\n\nexport type OreMenuItemProps = {\n checked?: boolean;\n disabled?: boolean;\n type?: OreMenuItemType;\n value?: string;\n};\n\nexport type OreMenuProps = {\n /** Initial uncontrolled open state. Ignored when `open` is set. */\n 'default-open'?: boolean;\n disabled?: boolean;\n /** Controlled open state. */\n open?: boolean;\n placement?: 'bottom' | 'bottom-start' | 'bottom-end' | 'top' | 'top-start' | 'top-end';\n size?: ComponentSize;\n};\n\n// ── Styles ─────────────────────────────────────────────────────────────\n\n// ── Menu Item Component ─────────────────────────────────────────────────────────────\n\n/**\n * A selectable action item used inside `<ore-menu>`.\n *\n * @element ore-menu-item\n *\n * @attr {boolean} checked - Checked state for `checkbox` and `radio` item types\n * @attr {boolean} disabled - Disables selection and pointer interaction\n * @attr {'checkbox'|'radio'} type - Optional checkable menu item mode\n * @attr {string} value - Value emitted by parent menu on selection\n *\n * @slot - Item label/content\n * @slot icon - Optional leading icon content\n *\n * @cssprop --menu-item-hover-bg - Background on hover\n * @cssprop --menu-item-focus-color - Text color when keyboard-focused\n * @cssprop --menu-item-focus-bg - Background when keyboard-focused\n * @cssprop --menu-item-selection-bg - Background for checkbox/radio items (unselected)\n * @cssprop --menu-item-checked-color - Text color when checked\n * @cssprop --menu-item-checked-bg - Background when checked\n *\n * @part item - Root item container element.\n * @part item-label - Label text container.\n * @part icon-slot - Leading icon slot container.\n *\n * @example\n * ```html\n * <ore-menu-item value=\"edit\">Edit</ore-menu-item>\n * <ore-menu-item value=\"delete\" disabled>Delete</ore-menu-item>\n * <ore-menu-item type=\"checkbox\" value=\"wrap\" checked>Word wrap</ore-menu-item>\n * <ore-menu-item type=\"radio\" value=\"left\">Align left</ore-menu-item>\n * ```\n */\nexport const MENU_ITEM_TAG = 'ore-menu-item' as const;\ndefine<OreMenuItemProps>(MENU_ITEM_TAG, {\n props: {\n checked: prop.bool(false),\n disabled: prop.bool(false),\n type: prop.string<OreMenuItemType>(),\n value: prop.string(),\n },\n setup(props) {\n const isCheckable = () => props.type.value === 'checkbox' || props.type.value === 'radio';\n const isChecked = () => isCheckable() && props.checked.value;\n const itemRole = () => {\n if (props.type.value === 'checkbox') return 'menuitemcheckbox';\n\n if (props.type.value === 'radio') return 'menuitemradio';\n\n return 'menuitem';\n };\n const itemClass = () => {\n const type = props.type.value;\n\n return [\n 'item',\n type === 'checkbox' ? 'is-checkbox' : '',\n type === 'radio' ? 'is-radio' : '',\n isChecked() ? 'is-checked' : '',\n ]\n .filter(Boolean)\n .join(' ');\n };\n\n return isCheckable()\n ? html`\n <div\n class=\"${itemClass}\"\n tabindex=\"-1\"\n role=\"${itemRole}\"\n aria-checked=\"${() => String(isChecked())}\"\n aria-disabled=\"${props.disabled}\">\n <span class=\"item-check\" aria-hidden=\"true\"></span>\n <span class=\"icon-slot\"><slot name=\"icon\"></slot></span>\n <span class=\"item-label\"><slot></slot></span>\n </div>\n `\n : html`\n <div class=\"item\" tabindex=\"-1\" role=\"menuitem\" aria-disabled=\"${props.disabled}\">\n <span class=\"icon-slot\"><slot name=\"icon\"></slot></span>\n <span class=\"item-label\"><slot></slot></span>\n </div>\n `;\n },\n styles: [colorThemeMixin, menuItemStyles],\n});\n\n// ── Menu Separator ─────────────────────────────────────────────────────────────\n\n/**\n * Visual separator used to group menu items inside `<ore-menu>`.\n *\n * @element ore-menu-separator\n *\n * @example\n * ```html\n * <ore-menu-item value=\"cut\">Cut</ore-menu-item>\n * <ore-menu-separator></ore-menu-separator>\n * <ore-menu-item value=\"paste\">Paste</ore-menu-item>\n * ```\n */\nexport const SEPARATOR_TAG = 'ore-menu-separator' as const;\ndefine(SEPARATOR_TAG, {\n setup() {\n return html``;\n },\n styles: [menuSeparatorStyles],\n});\n\n// ── Menu Component ─────────────────────────────────────────────────────────────\n\nconst isCheckableItemType = (value: string | null): value is OreMenuItemType =>\n value === 'checkbox' || value === 'radio';\n\nconst parseOptionalBool = (value: string | null): boolean | undefined =>\n value == null ? undefined : value === '' || value === 'true';\n\n/**\n * Action dropdown menu triggered by a slotted trigger element.\n *\n * @element ore-menu\n * @element ore-menu-item - Clickable menu option (place in default slot)\n * @element ore-menu-separator - Visual divider between menu groups\n *\n * @attr {boolean} disabled - Disables opening and keyboard interaction\n * @attr {boolean} open - Controlled open state\n * @attr {boolean} default-open - Initial uncontrolled open state\n * @attr {string} placement - Panel placement: 'bottom' | 'bottom-start' | 'bottom-end' | 'top' | 'top-start' | 'top-end' (default: 'bottom-start')\n * @attr {string} size - Size: 'sm' | 'md' | 'lg'\n *\n * @fires open-change - Fired when the menu state changes. detail: { open, reason }\n * @fires select - Fired when an item is selected. detail: { value: string, checked?: boolean }\n *\n * @slot trigger - Trigger element that toggles menu visibility\n * @slot - Menu content (`<ore-menu-item>` and `<ore-menu-separator>`)\n *\n * @part panel - Floating menu panel container\n *\n * @cssprop --menu-panel-bg - Background of the floating panel\n * @cssprop --menu-panel-border-color - Border color of the floating panel\n * @cssprop --menu-panel-shadow - Box shadow of the floating panel\n * @cssprop --menu-panel-blur - Backdrop blur amount for the floating panel\n * @cssprop --menu-panel-min-width - Minimum width of the floating panel\n * @cssprop --menu-panel-max-height - Maximum height of the floating panel before it scrolls\n * @cssprop --menu-panel-radius - Border radius of the floating panel\n *\n * @example\n * ```html\n * <ore-menu>\n * <button slot=\"trigger\">Actions</button>\n * <ore-menu-item value=\"edit\">Edit</ore-menu-item>\n * <ore-menu-item value=\"delete\">Delete</ore-menu-item>\n * </ore-menu>\n * ```\n */\nexport const MENU_TAG = 'ore-menu' as const;\ndefine<OreMenuProps>(MENU_TAG, {\n props: {\n ...sizableBundle,\n ...disablableBundle,\n 'default-open': prop.bool(false),\n open: { default: undefined as boolean | undefined, parse: parseOptionalBool },\n placement: prop.oneOf(\n ['bottom', 'bottom-start', 'bottom-end', 'top', 'top-start', 'top-end'] as const,\n 'bottom-start',\n ),\n },\n setup(props) {\n const el = getHost();\n const emit = useEmit<OreMenuEvents>();\n const slots = useSlots();\n const watch = watchEffect;\n\n const menuId = createStableId('menu');\n const isDisabled = computed(() => Boolean(props.disabled.value));\n const abortSignal = lifecycleSignal(onCleanup);\n let triggerEl: HTMLElement | null = null;\n let panelEl: HTMLElement | null = null;\n let cleanupTrigger: (() => void) | null = null;\n\n // ── Helpers ───────────────────────────────────────────────────────────────\n function getItems(): HTMLElement[] {\n return Array.from(el.querySelectorAll<HTMLElement>('ore-menu-item:not([disabled])'));\n }\n\n function getItemFocusable(item: HTMLElement | null | undefined): HTMLElement | null {\n if (!item) return null;\n\n return item.shadowRoot?.querySelector<HTMLElement>('[role^=\"menuitem\"]') ?? item;\n }\n\n function getFocusedItemIndex(): number {\n const items = getItems();\n\n return items.findIndex((item) => {\n const focusable = getItemFocusable(item);\n\n return item === document.activeElement || focusable === document.activeElement;\n });\n }\n\n const isOpenSignal = signal(false);\n let stopPositioning: (() => void) | null = null;\n const positioner = createDropdownPositioner({\n getFloating: () => panelEl,\n getPlacement: () => (props.placement.value ?? 'bottom-start') as Placement,\n getReference: () => triggerEl,\n matchWidth: false,\n offsetPx: 4,\n padding: 6,\n });\n const list = createListControl<HTMLElement>({\n disabled: computed(() => !isOpenSignal.value),\n getItems: getItems,\n isItemDisabled: (item) => item.hasAttribute('disabled'),\n onNavigate: (_action, index) => {\n const nextItem = getItems()[index];\n\n getItemFocusable(nextItem)?.focus();\n },\n signal: abortSignal,\n });\n\n const close = (reason: DropdownCloseReason = 'programmatic', shouldRestoreFocus = true): void => {\n if (!isOpenSignal.value) return;\n\n isOpenSignal.value = false;\n list.reset();\n stopPositioning?.();\n stopPositioning = null;\n\n if (shouldRestoreFocus) restoreFocus(() => triggerEl);\n\n emit('open-change', { open: false, reason });\n };\n\n const open = (reason: OverlayOpenReason = 'programmatic'): void => {\n if (isDisabled.value || isOpenSignal.value) return;\n\n isOpenSignal.value = true;\n positioner.update();\n stopPositioning = positioner.startAutoUpdate?.() ?? null;\n emit('open-change', { open: true, reason });\n };\n\n const toggle = (): void => {\n if (isOpenSignal.value) close('trigger');\n else open('click');\n };\n\n createOutsidePointerDismissal({\n getTargets: () => [el, panelEl],\n isActive: () => isOpenSignal.value,\n onDismiss: () => close('outsideClick'),\n signal: abortSignal,\n });\n\n let initialized = false;\n\n rippleWatch(\n props.open,\n (value) => {\n if (value === undefined) {\n if (!initialized) {\n if (props['default-open'].value) open('programmatic');\n } else {\n close('programmatic');\n }\n } else if (value) {\n open('programmatic');\n } else {\n close('programmatic');\n }\n\n initialized = true;\n },\n { immediate: true },\n );\n abortSignal.addEventListener(\n 'abort',\n () => {\n if (!isOpenSignal.value) return;\n\n isOpenSignal.value = false;\n list.reset();\n stopPositioning?.();\n stopPositioning = null;\n },\n { once: true },\n );\n\n const activateItem = (item: HTMLElement): void => {\n const type = item.getAttribute('type');\n const isCheckable = isCheckableItemType(type);\n\n if (type === 'checkbox') {\n item.toggleAttribute('checked', !item.hasAttribute('checked'));\n } else if (type === 'radio') {\n for (const radio of el.querySelectorAll<HTMLElement>('ore-menu-item[type=\"radio\"]')) {\n radio.toggleAttribute('checked', radio === item);\n }\n }\n\n const value = item.getAttribute('value') ?? '';\n const checked = isCheckable ? item.hasAttribute('checked') : undefined;\n\n emit('select', { checked, value });\n\n if (!isCheckable) {\n close('programmatic');\n }\n };\n\n const openFromKeyboardPress = createInteraction({\n keys: ['Enter', ' ', 'ArrowDown'],\n onPress: () => {\n open('keyboard');\n requestAnimationFrame(() => list.set(0));\n },\n });\n\n const activateFocusedFromKeyboardPress = createInteraction({\n onPress: () => {\n const focused = list.getActiveItem();\n\n if (focused) activateItem(focused);\n },\n });\n\n // ── Keyboard Navigation ───────────────────────────────────────────────────\n function handleMenuKeydown(e: KeyboardEvent) {\n if (isDisabled.value) return;\n\n const open = isOpenSignal.value;\n\n // When closed: open on Enter / Space / ArrowDown\n if (!open) {\n openFromKeyboardPress.handleKeydown(e);\n\n return;\n }\n\n const currentFocusedIndex = getFocusedItemIndex();\n\n if (currentFocusedIndex >= 0) list.set(currentFocusedIndex);\n\n if (e.key === 'Escape') {\n e.preventDefault();\n close('escape');\n\n return;\n }\n\n if (list.handleKeydown(e)) return;\n\n // When open: navigate and activate\n if (e.key === ' ' || e.key === 'Enter') {\n activateFocusedFromKeyboardPress.handleKeydown(e);\n\n return;\n }\n\n if (e.key === 'Tab') {\n close('programmatic');\n }\n }\n\n // ── Lifecycle ─────────────────────────────────────────────────────────────\n bind({\n on: {\n click: (e: MouseEvent) => {\n const path = e.composedPath();\n\n if (!isOpenSignal.value) return;\n\n const itemFromPath = path.find(\n (node): node is HTMLElement => node instanceof HTMLElement && node.tagName === 'ORE-MENU-ITEM',\n );\n const item = itemFromPath ?? (e.target as HTMLElement | null)?.closest<HTMLElement>('ore-menu-item') ?? null;\n\n if (!item || item.hasAttribute('disabled')) return;\n\n activateItem(item);\n },\n },\n });\n\n watch(() => {\n const open = isOpenSignal.value;\n\n if (!panelEl) return;\n\n panelEl.toggleAttribute('data-open', open);\n });\n\n function resolveTrigger() {\n cleanupTrigger?.();\n cleanupTrigger = null;\n\n const assigned = slots.elements('trigger').value;\n\n triggerEl = (assigned?.[0] as HTMLElement | undefined) ?? null;\n\n if (!triggerEl) return;\n\n const cleanups: Array<() => void> = [];\n const removeAria = bind(\n {\n aria: {\n controls: () => menuId,\n disabled: () => isDisabled.value,\n expanded: () => String(isOpenSignal.value),\n haspopup: 'menu',\n },\n },\n { target: triggerEl },\n );\n\n const onTriggerClick = (event: MouseEvent) => {\n event.stopPropagation();\n\n if (isDisabled.value) return;\n\n toggle();\n };\n const onTriggerKeydown = (event: KeyboardEvent) => {\n handleMenuKeydown(event);\n };\n\n triggerEl.addEventListener('click', onTriggerClick);\n triggerEl.addEventListener('keydown', onTriggerKeydown);\n cleanups.push(() => triggerEl?.removeEventListener('click', onTriggerClick));\n cleanups.push(() => triggerEl?.removeEventListener('keydown', onTriggerKeydown));\n\n cleanupTrigger = () => {\n removeAria();\n\n for (const cleanup of cleanups) cleanup();\n };\n }\n\n rippleWatch(slots.elements('trigger'), resolveTrigger, { immediate: true });\n\n onMounted(() => {\n return () => {\n cleanupTrigger?.();\n cleanupTrigger = null;\n };\n });\n\n return html`\n <slot name=\"trigger\"></slot>\n <div\n class=\"menu-panel\"\n part=\"panel\"\n id=\"${menuId}\"\n role=\"menu\"\n aria-orientation=\"vertical\"\n @keydown=\"${handleMenuKeydown}\"\n ref=\"${(el: HTMLElement | null) => {\n panelEl = el;\n panelEl?.toggleAttribute('data-open', isOpenSignal.value);\n }}\">\n <slot></slot>\n </div>\n `;\n },\n styles: [componentStyles, sizeVariantMixin(MENU_SIZE_PRESET), forcedColorsMixin],\n});\n"],"mappings":"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"}
1
+ {"version":3,"file":"menu.cjs","names":[],"sources":["../src/overlay/menu/menu.ts"],"sourcesContent":["import type { Placement } from '@vielzeug/orbit';\n\nimport {\n createStableId,\n define,\n html,\n prop,\n bind,\n getHost,\n onCleanup,\n onMounted,\n useEmit,\n useSlots,\n watchEffect,\n} from '@vielzeug/ore';\nimport { computed, signal } from '@vielzeug/ripple';\nimport { watch as rippleWatch } from '@vielzeug/ripple/watch';\n\nimport type { ComponentSize } from '../../types';\n\nimport {\n lifecycleSignal,\n createDropdownPositioner,\n createInteraction,\n createListControl,\n createOutsidePointerDismissal,\n restoreTriggerFocus,\n type DropdownCloseReason,\n type OverlayOpenChangeDetail,\n type OverlayOpenReason,\n} from '../../core';\nimport { disablableBundle, MENU_SIZE_PRESET, sizableBundle } from '../../shared';\nimport { colorThemeMixin, forcedColorsMixin, sizeVariantMixin } from '../../styles';\nimport menuItemStyles from './menu-item.css?inline';\nimport menuSeparatorStyles from './menu-separator.css?inline';\nimport componentStyles from './menu.css?inline';\n\n// ── Types ─────────────────────────────────────────────────────────────\n\nexport interface MenuSelectDetail {\n value: string;\n checked?: boolean;\n}\n\nexport type OreMenuItemType = 'checkbox' | 'radio';\n\nexport type OreMenuEvents = {\n 'open-change': OverlayOpenChangeDetail;\n select: MenuSelectDetail;\n};\n\nexport type OreMenuItemProps = {\n checked?: boolean;\n disabled?: boolean;\n type?: OreMenuItemType;\n value?: string;\n};\n\nexport type OreMenuProps = {\n /** Initial uncontrolled open state. Ignored when `open` is set. */\n 'default-open'?: boolean;\n disabled?: boolean;\n /** Controlled open state. */\n open?: boolean;\n placement?: 'bottom' | 'bottom-start' | 'bottom-end' | 'top' | 'top-start' | 'top-end';\n size?: ComponentSize;\n};\n\n// ── Styles ─────────────────────────────────────────────────────────────\n\n// ── Menu Item Component ─────────────────────────────────────────────────────────────\n\n/**\n * A selectable action item used inside `<ore-menu>`.\n *\n * @element ore-menu-item\n *\n * @attr {boolean} checked - Checked state for `checkbox` and `radio` item types\n * @attr {boolean} disabled - Disables selection and pointer interaction\n * @attr {'checkbox'|'radio'} type - Optional checkable menu item mode\n * @attr {string} value - Value emitted by parent menu on selection\n *\n * @slot - Item label/content\n * @slot icon - Optional leading icon content\n *\n * @cssprop --menu-item-hover-bg - Background on hover\n * @cssprop --menu-item-focus-color - Text color when keyboard-focused\n * @cssprop --menu-item-focus-bg - Background when keyboard-focused\n * @cssprop --menu-item-selection-bg - Background for checkbox/radio items (unselected)\n * @cssprop --menu-item-checked-color - Text color when checked\n * @cssprop --menu-item-checked-bg - Background when checked\n *\n * @part item - Root item container element.\n * @part item-label - Label text container.\n * @part icon-slot - Leading icon slot container.\n *\n * @example\n * ```html\n * <ore-menu-item value=\"edit\">Edit</ore-menu-item>\n * <ore-menu-item value=\"delete\" disabled>Delete</ore-menu-item>\n * <ore-menu-item type=\"checkbox\" value=\"wrap\" checked>Word wrap</ore-menu-item>\n * <ore-menu-item type=\"radio\" value=\"left\">Align left</ore-menu-item>\n * ```\n */\nexport const MENU_ITEM_TAG = 'ore-menu-item' as const;\ndefine<OreMenuItemProps>(MENU_ITEM_TAG, {\n props: {\n checked: prop.bool(false),\n disabled: prop.bool(false),\n type: prop.string<OreMenuItemType>(),\n value: prop.string(),\n },\n setup(props) {\n const isCheckable = () => props.type.value === 'checkbox' || props.type.value === 'radio';\n const isChecked = () => isCheckable() && props.checked.value;\n const itemRole = () => {\n if (props.type.value === 'checkbox') return 'menuitemcheckbox';\n\n if (props.type.value === 'radio') return 'menuitemradio';\n\n return 'menuitem';\n };\n const itemClass = () => {\n const type = props.type.value;\n\n return [\n 'item',\n type === 'checkbox' ? 'is-checkbox' : '',\n type === 'radio' ? 'is-radio' : '',\n isChecked() ? 'is-checked' : '',\n ]\n .filter(Boolean)\n .join(' ');\n };\n\n return isCheckable()\n ? html`\n <div\n class=\"${itemClass}\"\n tabindex=\"-1\"\n role=\"${itemRole}\"\n aria-checked=\"${() => String(isChecked())}\"\n aria-disabled=\"${props.disabled}\">\n <span class=\"item-check\" aria-hidden=\"true\"></span>\n <span class=\"icon-slot\"><slot name=\"icon\"></slot></span>\n <span class=\"item-label\"><slot></slot></span>\n </div>\n `\n : html`\n <div class=\"item\" tabindex=\"-1\" role=\"menuitem\" aria-disabled=\"${props.disabled}\">\n <span class=\"icon-slot\"><slot name=\"icon\"></slot></span>\n <span class=\"item-label\"><slot></slot></span>\n </div>\n `;\n },\n styles: [colorThemeMixin, menuItemStyles],\n});\n\n// ── Menu Separator ─────────────────────────────────────────────────────────────\n\n/**\n * Visual separator used to group menu items inside `<ore-menu>`.\n *\n * @element ore-menu-separator\n *\n * @example\n * ```html\n * <ore-menu-item value=\"cut\">Cut</ore-menu-item>\n * <ore-menu-separator></ore-menu-separator>\n * <ore-menu-item value=\"paste\">Paste</ore-menu-item>\n * ```\n */\nexport const SEPARATOR_TAG = 'ore-menu-separator' as const;\ndefine(SEPARATOR_TAG, {\n setup() {\n return html``;\n },\n styles: [menuSeparatorStyles],\n});\n\n// ── Menu Component ─────────────────────────────────────────────────────────────\n\nconst isCheckableItemType = (value: string | null): value is OreMenuItemType =>\n value === 'checkbox' || value === 'radio';\n\nconst parseOptionalBool = (value: string | null): boolean | undefined =>\n value == null ? undefined : value === '' || value === 'true';\n\n/**\n * Action dropdown menu triggered by a slotted trigger element.\n *\n * @element ore-menu\n * @element ore-menu-item - Clickable menu option (place in default slot)\n * @element ore-menu-separator - Visual divider between menu groups\n *\n * @attr {boolean} disabled - Disables opening and keyboard interaction\n * @attr {boolean} open - Controlled open state\n * @attr {boolean} default-open - Initial uncontrolled open state\n * @attr {string} placement - Panel placement: 'bottom' | 'bottom-start' | 'bottom-end' | 'top' | 'top-start' | 'top-end' (default: 'bottom-start')\n * @attr {string} size - Size: 'sm' | 'md' | 'lg'\n *\n * @fires open-change - Fired when the menu state changes. detail: { open, reason }\n * @fires select - Fired when an item is selected. detail: { value: string, checked?: boolean }\n *\n * @slot trigger - Trigger element that toggles menu visibility\n * @slot - Menu content (`<ore-menu-item>` and `<ore-menu-separator>`)\n *\n * @part panel - Floating menu panel container\n *\n * @cssprop --menu-panel-bg - Background of the floating panel\n * @cssprop --menu-panel-border-color - Border color of the floating panel\n * @cssprop --menu-panel-shadow - Box shadow of the floating panel\n * @cssprop --menu-panel-blur - Backdrop blur amount for the floating panel\n * @cssprop --menu-panel-min-width - Minimum width of the floating panel\n * @cssprop --menu-panel-max-height - Maximum height of the floating panel before it scrolls\n * @cssprop --menu-panel-radius - Border radius of the floating panel\n *\n * @example\n * ```html\n * <ore-menu>\n * <button slot=\"trigger\">Actions</button>\n * <ore-menu-item value=\"edit\">Edit</ore-menu-item>\n * <ore-menu-item value=\"delete\">Delete</ore-menu-item>\n * </ore-menu>\n * ```\n */\nexport const MENU_TAG = 'ore-menu' as const;\ndefine<OreMenuProps>(MENU_TAG, {\n props: {\n ...sizableBundle,\n ...disablableBundle,\n 'default-open': prop.bool(false),\n open: { default: undefined as boolean | undefined, parse: parseOptionalBool },\n placement: prop.oneOf(\n ['bottom', 'bottom-start', 'bottom-end', 'top', 'top-start', 'top-end'] as const,\n 'bottom-start',\n ),\n },\n setup(props) {\n const el = getHost();\n const emit = useEmit<OreMenuEvents>();\n const slots = useSlots();\n const watch = watchEffect;\n\n const menuId = createStableId('menu');\n const isDisabled = computed(() => Boolean(props.disabled.value));\n const abortSignal = lifecycleSignal(onCleanup);\n let triggerEl: HTMLElement | null = null;\n let panelEl: HTMLElement | null = null;\n let cleanupTrigger: (() => void) | null = null;\n\n // ── Helpers ───────────────────────────────────────────────────────────────\n function getItems(): HTMLElement[] {\n return Array.from(el.querySelectorAll<HTMLElement>('ore-menu-item:not([disabled])'));\n }\n\n function getItemFocusable(item: HTMLElement | null | undefined): HTMLElement | null {\n if (!item) return null;\n\n return item.shadowRoot?.querySelector<HTMLElement>('[role^=\"menuitem\"]') ?? item;\n }\n\n function getFocusedItemIndex(): number {\n const items = getItems();\n\n return items.findIndex((item) => {\n const focusable = getItemFocusable(item);\n\n return item === document.activeElement || focusable === document.activeElement;\n });\n }\n\n const isOpenSignal = signal(false);\n let stopPositioning: (() => void) | null = null;\n const positioner = createDropdownPositioner({\n getFloating: () => panelEl,\n getPlacement: () => (props.placement.value ?? 'bottom-start') as Placement,\n getReference: () => triggerEl,\n matchWidth: false,\n offsetPx: 4,\n padding: 6,\n });\n const list = createListControl<HTMLElement>({\n disabled: computed(() => !isOpenSignal.value),\n getItems: getItems,\n isItemDisabled: (item) => item.hasAttribute('disabled'),\n onNavigate: (_action, index) => {\n const nextItem = getItems()[index];\n\n getItemFocusable(nextItem)?.focus();\n },\n signal: abortSignal,\n });\n\n const close = (reason: DropdownCloseReason = 'programmatic', shouldRestoreFocus = true): void => {\n if (!isOpenSignal.value) return;\n\n isOpenSignal.value = false;\n list.reset();\n stopPositioning?.();\n stopPositioning = null;\n\n if (shouldRestoreFocus) restoreTriggerFocus(() => triggerEl);\n\n emit('open-change', { open: false, reason });\n };\n\n const open = (reason: OverlayOpenReason = 'programmatic'): void => {\n if (isDisabled.value || isOpenSignal.value) return;\n\n isOpenSignal.value = true;\n positioner.update();\n stopPositioning = positioner.startAutoUpdate?.() ?? null;\n emit('open-change', { open: true, reason });\n };\n\n const toggle = (): void => {\n if (isOpenSignal.value) close('trigger');\n else open('click');\n };\n\n createOutsidePointerDismissal({\n getTargets: () => [el, panelEl],\n isActive: () => isOpenSignal.value,\n onDismiss: () => close('outsideClick'),\n signal: abortSignal,\n });\n\n let initialized = false;\n\n rippleWatch(\n props.open,\n (value) => {\n if (value === undefined) {\n if (!initialized) {\n if (props['default-open'].value) open('programmatic');\n } else {\n close('programmatic');\n }\n } else if (value) {\n open('programmatic');\n } else {\n close('programmatic');\n }\n\n initialized = true;\n },\n { immediate: true },\n );\n abortSignal.addEventListener(\n 'abort',\n () => {\n if (!isOpenSignal.value) return;\n\n isOpenSignal.value = false;\n list.reset();\n stopPositioning?.();\n stopPositioning = null;\n },\n { once: true },\n );\n\n const activateItem = (item: HTMLElement): void => {\n const type = item.getAttribute('type');\n const isCheckable = isCheckableItemType(type);\n\n if (type === 'checkbox') {\n item.toggleAttribute('checked', !item.hasAttribute('checked'));\n } else if (type === 'radio') {\n for (const radio of el.querySelectorAll<HTMLElement>('ore-menu-item[type=\"radio\"]')) {\n radio.toggleAttribute('checked', radio === item);\n }\n }\n\n const value = item.getAttribute('value') ?? '';\n const checked = isCheckable ? item.hasAttribute('checked') : undefined;\n\n emit('select', { checked, value });\n\n if (!isCheckable) {\n close('programmatic');\n }\n };\n\n const openFromKeyboardPress = createInteraction({\n keys: ['Enter', ' ', 'ArrowDown'],\n onPress: () => {\n open('keyboard');\n requestAnimationFrame(() => list.set(0));\n },\n });\n\n const activateFocusedFromKeyboardPress = createInteraction({\n onPress: () => {\n const focused = list.getActiveItem();\n\n if (focused) activateItem(focused);\n },\n });\n\n // ── Keyboard Navigation ───────────────────────────────────────────────────\n function handleMenuKeydown(e: KeyboardEvent) {\n if (isDisabled.value) return;\n\n const open = isOpenSignal.value;\n\n // When closed: open on Enter / Space / ArrowDown\n if (!open) {\n openFromKeyboardPress.handleKeydown(e);\n\n return;\n }\n\n const currentFocusedIndex = getFocusedItemIndex();\n\n if (currentFocusedIndex >= 0) list.set(currentFocusedIndex);\n\n if (e.key === 'Escape') {\n e.preventDefault();\n close('escape');\n\n return;\n }\n\n if (list.handleKeydown(e)) return;\n\n // When open: navigate and activate\n if (e.key === ' ' || e.key === 'Enter') {\n activateFocusedFromKeyboardPress.handleKeydown(e);\n\n return;\n }\n\n if (e.key === 'Tab') {\n close('programmatic');\n }\n }\n\n // ── Lifecycle ─────────────────────────────────────────────────────────────\n bind({\n on: {\n click: (e: MouseEvent) => {\n const path = e.composedPath();\n\n if (!isOpenSignal.value) return;\n\n const itemFromPath = path.find(\n (node): node is HTMLElement => node instanceof HTMLElement && node.tagName === 'ORE-MENU-ITEM',\n );\n const item = itemFromPath ?? (e.target as HTMLElement | null)?.closest<HTMLElement>('ore-menu-item') ?? null;\n\n if (!item || item.hasAttribute('disabled')) return;\n\n activateItem(item);\n },\n },\n });\n\n watch(() => {\n const open = isOpenSignal.value;\n\n if (!panelEl) return;\n\n panelEl.toggleAttribute('data-open', open);\n });\n\n function resolveTrigger() {\n cleanupTrigger?.();\n cleanupTrigger = null;\n\n const assigned = slots.elements('trigger').value;\n\n triggerEl = (assigned?.[0] as HTMLElement | undefined) ?? null;\n\n if (!triggerEl) return;\n\n const cleanups: Array<() => void> = [];\n const removeAria = bind(\n {\n aria: {\n controls: () => menuId,\n disabled: () => isDisabled.value,\n expanded: () => String(isOpenSignal.value),\n haspopup: 'menu',\n },\n },\n { target: triggerEl },\n );\n\n const onTriggerClick = (event: MouseEvent) => {\n event.stopPropagation();\n\n if (isDisabled.value) return;\n\n toggle();\n };\n const onTriggerKeydown = (event: KeyboardEvent) => {\n handleMenuKeydown(event);\n };\n\n triggerEl.addEventListener('click', onTriggerClick);\n triggerEl.addEventListener('keydown', onTriggerKeydown);\n cleanups.push(() => triggerEl?.removeEventListener('click', onTriggerClick));\n cleanups.push(() => triggerEl?.removeEventListener('keydown', onTriggerKeydown));\n\n cleanupTrigger = () => {\n removeAria();\n\n for (const cleanup of cleanups) cleanup();\n };\n }\n\n rippleWatch(slots.elements('trigger'), resolveTrigger, { immediate: true });\n\n onMounted(() => {\n return () => {\n cleanupTrigger?.();\n cleanupTrigger = null;\n };\n });\n\n return html`\n <slot name=\"trigger\"></slot>\n <div\n class=\"menu-panel\"\n part=\"panel\"\n id=\"${menuId}\"\n role=\"menu\"\n aria-orientation=\"vertical\"\n @keydown=\"${handleMenuKeydown}\"\n ref=\"${(el: HTMLElement | null) => {\n panelEl = el;\n panelEl?.toggleAttribute('data-open', isOpenSignal.value);\n }}\">\n <slot></slot>\n </div>\n `;\n },\n styles: [componentStyles, sizeVariantMixin(MENU_SIZE_PRESET), forcedColorsMixin],\n});\n"],"mappings":"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"}
package/dist/menu.js CHANGED
@@ -1,12 +1,12 @@
1
1
  import { lifecycleSignal as e } from "./core/ore.js";
2
2
  import { createInteraction as t } from "./core/keyboard.js";
3
- import { sizeVariantMixin as n } from "./styles/mixins/shape.css.js";
4
- import { colorThemeMixin as r, forcedColorsMixin as i } from "./styles/mixins/theme.css.js";
5
- import { createDropdownPositioner as a } from "./core/positioner.js";
6
- import { createListControl as o } from "./core/nav.js";
7
- import { disablableBundle as s, sizableBundle as c } from "./shared/prop-bundles.js";
8
- import { MENU_SIZE_PRESET as l } from "./shared/size-presets.js";
9
- import { createOutsidePointerDismissal as u, restoreFocus as d } from "./core/overlay.js";
3
+ import { createOutsidePointerDismissal as n, restoreTriggerFocus as r } from "./core/overlay.js";
4
+ import { sizeVariantMixin as i } from "./styles/mixins/shape.css.js";
5
+ import { colorThemeMixin as a, forcedColorsMixin as o } from "./styles/mixins/theme.css.js";
6
+ import { createDropdownPositioner as s } from "./core/positioner.js";
7
+ import { createListControl as c } from "./core/nav.js";
8
+ import { disablableBundle as l, sizableBundle as u } from "./shared/prop-bundles.js";
9
+ import { MENU_SIZE_PRESET as d } from "./shared/size-presets.js";
10
10
  import f from "./overlay/menu/menu-item.css.js";
11
11
  import p from "./overlay/menu/menu-separator.css.js";
12
12
  import m from "./overlay/menu/menu.css.js";
@@ -50,7 +50,7 @@ _(k, {
50
50
  </div>
51
51
  `;
52
52
  },
53
- styles: [r, f]
53
+ styles: [a, f]
54
54
  });
55
55
  var A = "ore-menu-separator";
56
56
  _(A, {
@@ -62,8 +62,8 @@ _(A, {
62
62
  var j = (e) => e === "checkbox" || e === "radio", M = (e) => e == null ? void 0 : e === "" || e === "true", N = "ore-menu";
63
63
  _(N, {
64
64
  props: {
65
- ...c,
66
- ...s,
65
+ ...u,
66
+ ...l,
67
67
  "default-open": S.bool(!1),
68
68
  open: {
69
69
  default: void 0,
@@ -78,10 +78,10 @@ _(N, {
78
78
  "top-end"
79
79
  ], "bottom-start")
80
80
  },
81
- setup(n) {
82
- let r = v(), i = C(), s = w(), c = T, l = g("menu"), f = E(() => !!n.disabled.value), p = e(b), m = null, _ = null, S = null;
81
+ setup(i) {
82
+ let a = v(), o = C(), l = w(), u = T, d = g("menu"), f = E(() => !!i.disabled.value), p = e(b), m = null, _ = null, S = null;
83
83
  function k() {
84
- return Array.from(r.querySelectorAll("ore-menu-item:not([disabled])"));
84
+ return Array.from(a.querySelectorAll("ore-menu-item:not([disabled])"));
85
85
  }
86
86
  function A(e) {
87
87
  return e ? e.shadowRoot?.querySelector("[role^=\"menuitem\"]") ?? e : null;
@@ -92,14 +92,14 @@ _(N, {
92
92
  return e === document.activeElement || t === document.activeElement;
93
93
  });
94
94
  }
95
- let N = D(!1), P = null, F = a({
95
+ let N = D(!1), P = null, F = s({
96
96
  getFloating: () => _,
97
- getPlacement: () => n.placement.value ?? "bottom-start",
97
+ getPlacement: () => i.placement.value ?? "bottom-start",
98
98
  getReference: () => m,
99
99
  matchWidth: !1,
100
100
  offsetPx: 4,
101
101
  padding: 6
102
- }), I = o({
102
+ }), I = c({
103
103
  disabled: E(() => !N.value),
104
104
  getItems: k,
105
105
  isItemDisabled: (e) => e.hasAttribute("disabled"),
@@ -109,38 +109,38 @@ _(N, {
109
109
  },
110
110
  signal: p
111
111
  }), L = (e = "programmatic", t = !0) => {
112
- N.value && (N.value = !1, I.reset(), P?.(), P = null, t && d(() => m), i("open-change", {
112
+ N.value && (N.value = !1, I.reset(), P?.(), P = null, t && r(() => m), o("open-change", {
113
113
  open: !1,
114
114
  reason: e
115
115
  }));
116
116
  }, R = (e = "programmatic") => {
117
- f.value || N.value || (N.value = !0, F.update(), P = F.startAutoUpdate?.() ?? null, i("open-change", {
117
+ f.value || N.value || (N.value = !0, F.update(), P = F.startAutoUpdate?.() ?? null, o("open-change", {
118
118
  open: !0,
119
119
  reason: e
120
120
  }));
121
121
  }, z = () => {
122
122
  N.value ? L("trigger") : R("click");
123
123
  };
124
- u({
125
- getTargets: () => [r, _],
124
+ n({
125
+ getTargets: () => [a, _],
126
126
  isActive: () => N.value,
127
127
  onDismiss: () => L("outsideClick"),
128
128
  signal: p
129
129
  });
130
130
  let B = !1;
131
- O(n.open, (e) => {
132
- e === void 0 ? B ? L("programmatic") : n["default-open"].value && R("programmatic") : e ? R("programmatic") : L("programmatic"), B = !0;
131
+ O(i.open, (e) => {
132
+ e === void 0 ? B ? L("programmatic") : i["default-open"].value && R("programmatic") : e ? R("programmatic") : L("programmatic"), B = !0;
133
133
  }, { immediate: !0 }), p.addEventListener("abort", () => {
134
134
  N.value && (N.value = !1, I.reset(), P?.(), P = null);
135
135
  }, { once: !0 });
136
136
  let V = (e) => {
137
137
  let t = e.getAttribute("type"), n = j(t);
138
138
  if (t === "checkbox") e.toggleAttribute("checked", !e.hasAttribute("checked"));
139
- else if (t === "radio") for (let t of r.querySelectorAll("ore-menu-item[type=\"radio\"]")) t.toggleAttribute("checked", t === e);
140
- let a = e.getAttribute("value") ?? "", o = n ? e.hasAttribute("checked") : void 0;
141
- i("select", {
142
- checked: o,
143
- value: a
139
+ else if (t === "radio") for (let t of a.querySelectorAll("ore-menu-item[type=\"radio\"]")) t.toggleAttribute("checked", t === e);
140
+ let r = e.getAttribute("value") ?? "", i = n ? e.hasAttribute("checked") : void 0;
141
+ o("select", {
142
+ checked: i,
143
+ value: r
144
144
  }), n || L("programmatic");
145
145
  }, H = t({
146
146
  keys: [
@@ -179,14 +179,14 @@ _(N, {
179
179
  if (!N.value) return;
180
180
  let n = t.find((e) => e instanceof HTMLElement && e.tagName === "ORE-MENU-ITEM") ?? e.target?.closest("ore-menu-item") ?? null;
181
181
  !n || n.hasAttribute("disabled") || V(n);
182
- } } }), c(() => {
182
+ } } }), u(() => {
183
183
  let e = N.value;
184
184
  _ && _.toggleAttribute("data-open", e);
185
185
  });
186
186
  function G() {
187
- if (S?.(), S = null, m = s.elements("trigger").value?.[0] ?? null, !m) return;
187
+ if (S?.(), S = null, m = l.elements("trigger").value?.[0] ?? null, !m) return;
188
188
  let e = [], t = h({ aria: {
189
- controls: () => l,
189
+ controls: () => d,
190
190
  disabled: () => f.value,
191
191
  expanded: () => String(N.value),
192
192
  haspopup: "menu"
@@ -200,14 +200,14 @@ _(N, {
200
200
  for (let t of e) t();
201
201
  };
202
202
  }
203
- return O(s.elements("trigger"), G, { immediate: !0 }), x(() => () => {
203
+ return O(l.elements("trigger"), G, { immediate: !0 }), x(() => () => {
204
204
  S?.(), S = null;
205
205
  }), y`
206
206
  <slot name="trigger"></slot>
207
207
  <div
208
208
  class="menu-panel"
209
209
  part="panel"
210
- id="${l}"
210
+ id="${d}"
211
211
  role="menu"
212
212
  aria-orientation="vertical"
213
213
  @keydown="${W}"
@@ -220,8 +220,8 @@ _(N, {
220
220
  },
221
221
  styles: [
222
222
  m,
223
- n(l),
224
- i
223
+ i(d),
224
+ o
225
225
  ]
226
226
  });
227
227
  //#endregion
package/dist/menu.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"menu.js","names":[],"sources":["../src/overlay/menu/menu.ts"],"sourcesContent":["import type { Placement } from '@vielzeug/orbit';\n\nimport {\n createStableId,\n define,\n html,\n prop,\n bind,\n getHost,\n onCleanup,\n onMounted,\n useEmit,\n useSlots,\n watchEffect,\n} from '@vielzeug/ore';\nimport { computed, signal } from '@vielzeug/ripple';\nimport { watch as rippleWatch } from '@vielzeug/ripple/watch';\n\nimport type { ComponentSize } from '../../types';\n\nimport {\n lifecycleSignal,\n createInteraction,\n type DropdownCloseReason,\n type OverlayOpenChangeDetail,\n type OverlayOpenReason,\n} from '../../core';\nimport { createListControl, createDropdownPositioner } from '../../core/_internal';\nimport { createOutsidePointerDismissal, restoreFocus } from '../../core/overlay';\nimport { disablableBundle, MENU_SIZE_PRESET, sizableBundle } from '../../shared';\nimport { colorThemeMixin, forcedColorsMixin, sizeVariantMixin } from '../../styles';\nimport menuItemStyles from './menu-item.css?inline';\nimport menuSeparatorStyles from './menu-separator.css?inline';\nimport componentStyles from './menu.css?inline';\n\n// ── Types ─────────────────────────────────────────────────────────────\n\nexport interface MenuSelectDetail {\n value: string;\n checked?: boolean;\n}\n\nexport type OreMenuItemType = 'checkbox' | 'radio';\n\nexport type OreMenuEvents = {\n 'open-change': OverlayOpenChangeDetail;\n select: MenuSelectDetail;\n};\n\nexport type OreMenuItemProps = {\n checked?: boolean;\n disabled?: boolean;\n type?: OreMenuItemType;\n value?: string;\n};\n\nexport type OreMenuProps = {\n /** Initial uncontrolled open state. Ignored when `open` is set. */\n 'default-open'?: boolean;\n disabled?: boolean;\n /** Controlled open state. */\n open?: boolean;\n placement?: 'bottom' | 'bottom-start' | 'bottom-end' | 'top' | 'top-start' | 'top-end';\n size?: ComponentSize;\n};\n\n// ── Styles ─────────────────────────────────────────────────────────────\n\n// ── Menu Item Component ─────────────────────────────────────────────────────────────\n\n/**\n * A selectable action item used inside `<ore-menu>`.\n *\n * @element ore-menu-item\n *\n * @attr {boolean} checked - Checked state for `checkbox` and `radio` item types\n * @attr {boolean} disabled - Disables selection and pointer interaction\n * @attr {'checkbox'|'radio'} type - Optional checkable menu item mode\n * @attr {string} value - Value emitted by parent menu on selection\n *\n * @slot - Item label/content\n * @slot icon - Optional leading icon content\n *\n * @cssprop --menu-item-hover-bg - Background on hover\n * @cssprop --menu-item-focus-color - Text color when keyboard-focused\n * @cssprop --menu-item-focus-bg - Background when keyboard-focused\n * @cssprop --menu-item-selection-bg - Background for checkbox/radio items (unselected)\n * @cssprop --menu-item-checked-color - Text color when checked\n * @cssprop --menu-item-checked-bg - Background when checked\n *\n * @part item - Root item container element.\n * @part item-label - Label text container.\n * @part icon-slot - Leading icon slot container.\n *\n * @example\n * ```html\n * <ore-menu-item value=\"edit\">Edit</ore-menu-item>\n * <ore-menu-item value=\"delete\" disabled>Delete</ore-menu-item>\n * <ore-menu-item type=\"checkbox\" value=\"wrap\" checked>Word wrap</ore-menu-item>\n * <ore-menu-item type=\"radio\" value=\"left\">Align left</ore-menu-item>\n * ```\n */\nexport const MENU_ITEM_TAG = 'ore-menu-item' as const;\ndefine<OreMenuItemProps>(MENU_ITEM_TAG, {\n props: {\n checked: prop.bool(false),\n disabled: prop.bool(false),\n type: prop.string<OreMenuItemType>(),\n value: prop.string(),\n },\n setup(props) {\n const isCheckable = () => props.type.value === 'checkbox' || props.type.value === 'radio';\n const isChecked = () => isCheckable() && props.checked.value;\n const itemRole = () => {\n if (props.type.value === 'checkbox') return 'menuitemcheckbox';\n\n if (props.type.value === 'radio') return 'menuitemradio';\n\n return 'menuitem';\n };\n const itemClass = () => {\n const type = props.type.value;\n\n return [\n 'item',\n type === 'checkbox' ? 'is-checkbox' : '',\n type === 'radio' ? 'is-radio' : '',\n isChecked() ? 'is-checked' : '',\n ]\n .filter(Boolean)\n .join(' ');\n };\n\n return isCheckable()\n ? html`\n <div\n class=\"${itemClass}\"\n tabindex=\"-1\"\n role=\"${itemRole}\"\n aria-checked=\"${() => String(isChecked())}\"\n aria-disabled=\"${props.disabled}\">\n <span class=\"item-check\" aria-hidden=\"true\"></span>\n <span class=\"icon-slot\"><slot name=\"icon\"></slot></span>\n <span class=\"item-label\"><slot></slot></span>\n </div>\n `\n : html`\n <div class=\"item\" tabindex=\"-1\" role=\"menuitem\" aria-disabled=\"${props.disabled}\">\n <span class=\"icon-slot\"><slot name=\"icon\"></slot></span>\n <span class=\"item-label\"><slot></slot></span>\n </div>\n `;\n },\n styles: [colorThemeMixin, menuItemStyles],\n});\n\n// ── Menu Separator ─────────────────────────────────────────────────────────────\n\n/**\n * Visual separator used to group menu items inside `<ore-menu>`.\n *\n * @element ore-menu-separator\n *\n * @example\n * ```html\n * <ore-menu-item value=\"cut\">Cut</ore-menu-item>\n * <ore-menu-separator></ore-menu-separator>\n * <ore-menu-item value=\"paste\">Paste</ore-menu-item>\n * ```\n */\nexport const SEPARATOR_TAG = 'ore-menu-separator' as const;\ndefine(SEPARATOR_TAG, {\n setup() {\n return html``;\n },\n styles: [menuSeparatorStyles],\n});\n\n// ── Menu Component ─────────────────────────────────────────────────────────────\n\nconst isCheckableItemType = (value: string | null): value is OreMenuItemType =>\n value === 'checkbox' || value === 'radio';\n\nconst parseOptionalBool = (value: string | null): boolean | undefined =>\n value == null ? undefined : value === '' || value === 'true';\n\n/**\n * Action dropdown menu triggered by a slotted trigger element.\n *\n * @element ore-menu\n * @element ore-menu-item - Clickable menu option (place in default slot)\n * @element ore-menu-separator - Visual divider between menu groups\n *\n * @attr {boolean} disabled - Disables opening and keyboard interaction\n * @attr {boolean} open - Controlled open state\n * @attr {boolean} default-open - Initial uncontrolled open state\n * @attr {string} placement - Panel placement: 'bottom' | 'bottom-start' | 'bottom-end' | 'top' | 'top-start' | 'top-end' (default: 'bottom-start')\n * @attr {string} size - Size: 'sm' | 'md' | 'lg'\n *\n * @fires open-change - Fired when the menu state changes. detail: { open, reason }\n * @fires select - Fired when an item is selected. detail: { value: string, checked?: boolean }\n *\n * @slot trigger - Trigger element that toggles menu visibility\n * @slot - Menu content (`<ore-menu-item>` and `<ore-menu-separator>`)\n *\n * @part panel - Floating menu panel container\n *\n * @cssprop --menu-panel-bg - Background of the floating panel\n * @cssprop --menu-panel-border-color - Border color of the floating panel\n * @cssprop --menu-panel-shadow - Box shadow of the floating panel\n * @cssprop --menu-panel-blur - Backdrop blur amount for the floating panel\n * @cssprop --menu-panel-min-width - Minimum width of the floating panel\n * @cssprop --menu-panel-max-height - Maximum height of the floating panel before it scrolls\n * @cssprop --menu-panel-radius - Border radius of the floating panel\n *\n * @example\n * ```html\n * <ore-menu>\n * <button slot=\"trigger\">Actions</button>\n * <ore-menu-item value=\"edit\">Edit</ore-menu-item>\n * <ore-menu-item value=\"delete\">Delete</ore-menu-item>\n * </ore-menu>\n * ```\n */\nexport const MENU_TAG = 'ore-menu' as const;\ndefine<OreMenuProps>(MENU_TAG, {\n props: {\n ...sizableBundle,\n ...disablableBundle,\n 'default-open': prop.bool(false),\n open: { default: undefined as boolean | undefined, parse: parseOptionalBool },\n placement: prop.oneOf(\n ['bottom', 'bottom-start', 'bottom-end', 'top', 'top-start', 'top-end'] as const,\n 'bottom-start',\n ),\n },\n setup(props) {\n const el = getHost();\n const emit = useEmit<OreMenuEvents>();\n const slots = useSlots();\n const watch = watchEffect;\n\n const menuId = createStableId('menu');\n const isDisabled = computed(() => Boolean(props.disabled.value));\n const abortSignal = lifecycleSignal(onCleanup);\n let triggerEl: HTMLElement | null = null;\n let panelEl: HTMLElement | null = null;\n let cleanupTrigger: (() => void) | null = null;\n\n // ── Helpers ───────────────────────────────────────────────────────────────\n function getItems(): HTMLElement[] {\n return Array.from(el.querySelectorAll<HTMLElement>('ore-menu-item:not([disabled])'));\n }\n\n function getItemFocusable(item: HTMLElement | null | undefined): HTMLElement | null {\n if (!item) return null;\n\n return item.shadowRoot?.querySelector<HTMLElement>('[role^=\"menuitem\"]') ?? item;\n }\n\n function getFocusedItemIndex(): number {\n const items = getItems();\n\n return items.findIndex((item) => {\n const focusable = getItemFocusable(item);\n\n return item === document.activeElement || focusable === document.activeElement;\n });\n }\n\n const isOpenSignal = signal(false);\n let stopPositioning: (() => void) | null = null;\n const positioner = createDropdownPositioner({\n getFloating: () => panelEl,\n getPlacement: () => (props.placement.value ?? 'bottom-start') as Placement,\n getReference: () => triggerEl,\n matchWidth: false,\n offsetPx: 4,\n padding: 6,\n });\n const list = createListControl<HTMLElement>({\n disabled: computed(() => !isOpenSignal.value),\n getItems: getItems,\n isItemDisabled: (item) => item.hasAttribute('disabled'),\n onNavigate: (_action, index) => {\n const nextItem = getItems()[index];\n\n getItemFocusable(nextItem)?.focus();\n },\n signal: abortSignal,\n });\n\n const close = (reason: DropdownCloseReason = 'programmatic', shouldRestoreFocus = true): void => {\n if (!isOpenSignal.value) return;\n\n isOpenSignal.value = false;\n list.reset();\n stopPositioning?.();\n stopPositioning = null;\n\n if (shouldRestoreFocus) restoreFocus(() => triggerEl);\n\n emit('open-change', { open: false, reason });\n };\n\n const open = (reason: OverlayOpenReason = 'programmatic'): void => {\n if (isDisabled.value || isOpenSignal.value) return;\n\n isOpenSignal.value = true;\n positioner.update();\n stopPositioning = positioner.startAutoUpdate?.() ?? null;\n emit('open-change', { open: true, reason });\n };\n\n const toggle = (): void => {\n if (isOpenSignal.value) close('trigger');\n else open('click');\n };\n\n createOutsidePointerDismissal({\n getTargets: () => [el, panelEl],\n isActive: () => isOpenSignal.value,\n onDismiss: () => close('outsideClick'),\n signal: abortSignal,\n });\n\n let initialized = false;\n\n rippleWatch(\n props.open,\n (value) => {\n if (value === undefined) {\n if (!initialized) {\n if (props['default-open'].value) open('programmatic');\n } else {\n close('programmatic');\n }\n } else if (value) {\n open('programmatic');\n } else {\n close('programmatic');\n }\n\n initialized = true;\n },\n { immediate: true },\n );\n abortSignal.addEventListener(\n 'abort',\n () => {\n if (!isOpenSignal.value) return;\n\n isOpenSignal.value = false;\n list.reset();\n stopPositioning?.();\n stopPositioning = null;\n },\n { once: true },\n );\n\n const activateItem = (item: HTMLElement): void => {\n const type = item.getAttribute('type');\n const isCheckable = isCheckableItemType(type);\n\n if (type === 'checkbox') {\n item.toggleAttribute('checked', !item.hasAttribute('checked'));\n } else if (type === 'radio') {\n for (const radio of el.querySelectorAll<HTMLElement>('ore-menu-item[type=\"radio\"]')) {\n radio.toggleAttribute('checked', radio === item);\n }\n }\n\n const value = item.getAttribute('value') ?? '';\n const checked = isCheckable ? item.hasAttribute('checked') : undefined;\n\n emit('select', { checked, value });\n\n if (!isCheckable) {\n close('programmatic');\n }\n };\n\n const openFromKeyboardPress = createInteraction({\n keys: ['Enter', ' ', 'ArrowDown'],\n onPress: () => {\n open('keyboard');\n requestAnimationFrame(() => list.set(0));\n },\n });\n\n const activateFocusedFromKeyboardPress = createInteraction({\n onPress: () => {\n const focused = list.getActiveItem();\n\n if (focused) activateItem(focused);\n },\n });\n\n // ── Keyboard Navigation ───────────────────────────────────────────────────\n function handleMenuKeydown(e: KeyboardEvent) {\n if (isDisabled.value) return;\n\n const open = isOpenSignal.value;\n\n // When closed: open on Enter / Space / ArrowDown\n if (!open) {\n openFromKeyboardPress.handleKeydown(e);\n\n return;\n }\n\n const currentFocusedIndex = getFocusedItemIndex();\n\n if (currentFocusedIndex >= 0) list.set(currentFocusedIndex);\n\n if (e.key === 'Escape') {\n e.preventDefault();\n close('escape');\n\n return;\n }\n\n if (list.handleKeydown(e)) return;\n\n // When open: navigate and activate\n if (e.key === ' ' || e.key === 'Enter') {\n activateFocusedFromKeyboardPress.handleKeydown(e);\n\n return;\n }\n\n if (e.key === 'Tab') {\n close('programmatic');\n }\n }\n\n // ── Lifecycle ─────────────────────────────────────────────────────────────\n bind({\n on: {\n click: (e: MouseEvent) => {\n const path = e.composedPath();\n\n if (!isOpenSignal.value) return;\n\n const itemFromPath = path.find(\n (node): node is HTMLElement => node instanceof HTMLElement && node.tagName === 'ORE-MENU-ITEM',\n );\n const item = itemFromPath ?? (e.target as HTMLElement | null)?.closest<HTMLElement>('ore-menu-item') ?? null;\n\n if (!item || item.hasAttribute('disabled')) return;\n\n activateItem(item);\n },\n },\n });\n\n watch(() => {\n const open = isOpenSignal.value;\n\n if (!panelEl) return;\n\n panelEl.toggleAttribute('data-open', open);\n });\n\n function resolveTrigger() {\n cleanupTrigger?.();\n cleanupTrigger = null;\n\n const assigned = slots.elements('trigger').value;\n\n triggerEl = (assigned?.[0] as HTMLElement | undefined) ?? null;\n\n if (!triggerEl) return;\n\n const cleanups: Array<() => void> = [];\n const removeAria = bind(\n {\n aria: {\n controls: () => menuId,\n disabled: () => isDisabled.value,\n expanded: () => String(isOpenSignal.value),\n haspopup: 'menu',\n },\n },\n { target: triggerEl },\n );\n\n const onTriggerClick = (event: MouseEvent) => {\n event.stopPropagation();\n\n if (isDisabled.value) return;\n\n toggle();\n };\n const onTriggerKeydown = (event: KeyboardEvent) => {\n handleMenuKeydown(event);\n };\n\n triggerEl.addEventListener('click', onTriggerClick);\n triggerEl.addEventListener('keydown', onTriggerKeydown);\n cleanups.push(() => triggerEl?.removeEventListener('click', onTriggerClick));\n cleanups.push(() => triggerEl?.removeEventListener('keydown', onTriggerKeydown));\n\n cleanupTrigger = () => {\n removeAria();\n\n for (const cleanup of cleanups) cleanup();\n };\n }\n\n rippleWatch(slots.elements('trigger'), resolveTrigger, { immediate: true });\n\n onMounted(() => {\n return () => {\n cleanupTrigger?.();\n cleanupTrigger = null;\n };\n });\n\n return html`\n <slot name=\"trigger\"></slot>\n <div\n class=\"menu-panel\"\n part=\"panel\"\n id=\"${menuId}\"\n role=\"menu\"\n aria-orientation=\"vertical\"\n @keydown=\"${handleMenuKeydown}\"\n ref=\"${(el: HTMLElement | null) => {\n panelEl = el;\n panelEl?.toggleAttribute('data-open', isOpenSignal.value);\n }}\">\n <slot></slot>\n </div>\n `;\n },\n styles: [componentStyles, sizeVariantMixin(MENU_SIZE_PRESET), forcedColorsMixin],\n});\n"],"mappings":"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"}
1
+ {"version":3,"file":"menu.js","names":[],"sources":["../src/overlay/menu/menu.ts"],"sourcesContent":["import type { Placement } from '@vielzeug/orbit';\n\nimport {\n createStableId,\n define,\n html,\n prop,\n bind,\n getHost,\n onCleanup,\n onMounted,\n useEmit,\n useSlots,\n watchEffect,\n} from '@vielzeug/ore';\nimport { computed, signal } from '@vielzeug/ripple';\nimport { watch as rippleWatch } from '@vielzeug/ripple/watch';\n\nimport type { ComponentSize } from '../../types';\n\nimport {\n lifecycleSignal,\n createDropdownPositioner,\n createInteraction,\n createListControl,\n createOutsidePointerDismissal,\n restoreTriggerFocus,\n type DropdownCloseReason,\n type OverlayOpenChangeDetail,\n type OverlayOpenReason,\n} from '../../core';\nimport { disablableBundle, MENU_SIZE_PRESET, sizableBundle } from '../../shared';\nimport { colorThemeMixin, forcedColorsMixin, sizeVariantMixin } from '../../styles';\nimport menuItemStyles from './menu-item.css?inline';\nimport menuSeparatorStyles from './menu-separator.css?inline';\nimport componentStyles from './menu.css?inline';\n\n// ── Types ─────────────────────────────────────────────────────────────\n\nexport interface MenuSelectDetail {\n value: string;\n checked?: boolean;\n}\n\nexport type OreMenuItemType = 'checkbox' | 'radio';\n\nexport type OreMenuEvents = {\n 'open-change': OverlayOpenChangeDetail;\n select: MenuSelectDetail;\n};\n\nexport type OreMenuItemProps = {\n checked?: boolean;\n disabled?: boolean;\n type?: OreMenuItemType;\n value?: string;\n};\n\nexport type OreMenuProps = {\n /** Initial uncontrolled open state. Ignored when `open` is set. */\n 'default-open'?: boolean;\n disabled?: boolean;\n /** Controlled open state. */\n open?: boolean;\n placement?: 'bottom' | 'bottom-start' | 'bottom-end' | 'top' | 'top-start' | 'top-end';\n size?: ComponentSize;\n};\n\n// ── Styles ─────────────────────────────────────────────────────────────\n\n// ── Menu Item Component ─────────────────────────────────────────────────────────────\n\n/**\n * A selectable action item used inside `<ore-menu>`.\n *\n * @element ore-menu-item\n *\n * @attr {boolean} checked - Checked state for `checkbox` and `radio` item types\n * @attr {boolean} disabled - Disables selection and pointer interaction\n * @attr {'checkbox'|'radio'} type - Optional checkable menu item mode\n * @attr {string} value - Value emitted by parent menu on selection\n *\n * @slot - Item label/content\n * @slot icon - Optional leading icon content\n *\n * @cssprop --menu-item-hover-bg - Background on hover\n * @cssprop --menu-item-focus-color - Text color when keyboard-focused\n * @cssprop --menu-item-focus-bg - Background when keyboard-focused\n * @cssprop --menu-item-selection-bg - Background for checkbox/radio items (unselected)\n * @cssprop --menu-item-checked-color - Text color when checked\n * @cssprop --menu-item-checked-bg - Background when checked\n *\n * @part item - Root item container element.\n * @part item-label - Label text container.\n * @part icon-slot - Leading icon slot container.\n *\n * @example\n * ```html\n * <ore-menu-item value=\"edit\">Edit</ore-menu-item>\n * <ore-menu-item value=\"delete\" disabled>Delete</ore-menu-item>\n * <ore-menu-item type=\"checkbox\" value=\"wrap\" checked>Word wrap</ore-menu-item>\n * <ore-menu-item type=\"radio\" value=\"left\">Align left</ore-menu-item>\n * ```\n */\nexport const MENU_ITEM_TAG = 'ore-menu-item' as const;\ndefine<OreMenuItemProps>(MENU_ITEM_TAG, {\n props: {\n checked: prop.bool(false),\n disabled: prop.bool(false),\n type: prop.string<OreMenuItemType>(),\n value: prop.string(),\n },\n setup(props) {\n const isCheckable = () => props.type.value === 'checkbox' || props.type.value === 'radio';\n const isChecked = () => isCheckable() && props.checked.value;\n const itemRole = () => {\n if (props.type.value === 'checkbox') return 'menuitemcheckbox';\n\n if (props.type.value === 'radio') return 'menuitemradio';\n\n return 'menuitem';\n };\n const itemClass = () => {\n const type = props.type.value;\n\n return [\n 'item',\n type === 'checkbox' ? 'is-checkbox' : '',\n type === 'radio' ? 'is-radio' : '',\n isChecked() ? 'is-checked' : '',\n ]\n .filter(Boolean)\n .join(' ');\n };\n\n return isCheckable()\n ? html`\n <div\n class=\"${itemClass}\"\n tabindex=\"-1\"\n role=\"${itemRole}\"\n aria-checked=\"${() => String(isChecked())}\"\n aria-disabled=\"${props.disabled}\">\n <span class=\"item-check\" aria-hidden=\"true\"></span>\n <span class=\"icon-slot\"><slot name=\"icon\"></slot></span>\n <span class=\"item-label\"><slot></slot></span>\n </div>\n `\n : html`\n <div class=\"item\" tabindex=\"-1\" role=\"menuitem\" aria-disabled=\"${props.disabled}\">\n <span class=\"icon-slot\"><slot name=\"icon\"></slot></span>\n <span class=\"item-label\"><slot></slot></span>\n </div>\n `;\n },\n styles: [colorThemeMixin, menuItemStyles],\n});\n\n// ── Menu Separator ─────────────────────────────────────────────────────────────\n\n/**\n * Visual separator used to group menu items inside `<ore-menu>`.\n *\n * @element ore-menu-separator\n *\n * @example\n * ```html\n * <ore-menu-item value=\"cut\">Cut</ore-menu-item>\n * <ore-menu-separator></ore-menu-separator>\n * <ore-menu-item value=\"paste\">Paste</ore-menu-item>\n * ```\n */\nexport const SEPARATOR_TAG = 'ore-menu-separator' as const;\ndefine(SEPARATOR_TAG, {\n setup() {\n return html``;\n },\n styles: [menuSeparatorStyles],\n});\n\n// ── Menu Component ─────────────────────────────────────────────────────────────\n\nconst isCheckableItemType = (value: string | null): value is OreMenuItemType =>\n value === 'checkbox' || value === 'radio';\n\nconst parseOptionalBool = (value: string | null): boolean | undefined =>\n value == null ? undefined : value === '' || value === 'true';\n\n/**\n * Action dropdown menu triggered by a slotted trigger element.\n *\n * @element ore-menu\n * @element ore-menu-item - Clickable menu option (place in default slot)\n * @element ore-menu-separator - Visual divider between menu groups\n *\n * @attr {boolean} disabled - Disables opening and keyboard interaction\n * @attr {boolean} open - Controlled open state\n * @attr {boolean} default-open - Initial uncontrolled open state\n * @attr {string} placement - Panel placement: 'bottom' | 'bottom-start' | 'bottom-end' | 'top' | 'top-start' | 'top-end' (default: 'bottom-start')\n * @attr {string} size - Size: 'sm' | 'md' | 'lg'\n *\n * @fires open-change - Fired when the menu state changes. detail: { open, reason }\n * @fires select - Fired when an item is selected. detail: { value: string, checked?: boolean }\n *\n * @slot trigger - Trigger element that toggles menu visibility\n * @slot - Menu content (`<ore-menu-item>` and `<ore-menu-separator>`)\n *\n * @part panel - Floating menu panel container\n *\n * @cssprop --menu-panel-bg - Background of the floating panel\n * @cssprop --menu-panel-border-color - Border color of the floating panel\n * @cssprop --menu-panel-shadow - Box shadow of the floating panel\n * @cssprop --menu-panel-blur - Backdrop blur amount for the floating panel\n * @cssprop --menu-panel-min-width - Minimum width of the floating panel\n * @cssprop --menu-panel-max-height - Maximum height of the floating panel before it scrolls\n * @cssprop --menu-panel-radius - Border radius of the floating panel\n *\n * @example\n * ```html\n * <ore-menu>\n * <button slot=\"trigger\">Actions</button>\n * <ore-menu-item value=\"edit\">Edit</ore-menu-item>\n * <ore-menu-item value=\"delete\">Delete</ore-menu-item>\n * </ore-menu>\n * ```\n */\nexport const MENU_TAG = 'ore-menu' as const;\ndefine<OreMenuProps>(MENU_TAG, {\n props: {\n ...sizableBundle,\n ...disablableBundle,\n 'default-open': prop.bool(false),\n open: { default: undefined as boolean | undefined, parse: parseOptionalBool },\n placement: prop.oneOf(\n ['bottom', 'bottom-start', 'bottom-end', 'top', 'top-start', 'top-end'] as const,\n 'bottom-start',\n ),\n },\n setup(props) {\n const el = getHost();\n const emit = useEmit<OreMenuEvents>();\n const slots = useSlots();\n const watch = watchEffect;\n\n const menuId = createStableId('menu');\n const isDisabled = computed(() => Boolean(props.disabled.value));\n const abortSignal = lifecycleSignal(onCleanup);\n let triggerEl: HTMLElement | null = null;\n let panelEl: HTMLElement | null = null;\n let cleanupTrigger: (() => void) | null = null;\n\n // ── Helpers ───────────────────────────────────────────────────────────────\n function getItems(): HTMLElement[] {\n return Array.from(el.querySelectorAll<HTMLElement>('ore-menu-item:not([disabled])'));\n }\n\n function getItemFocusable(item: HTMLElement | null | undefined): HTMLElement | null {\n if (!item) return null;\n\n return item.shadowRoot?.querySelector<HTMLElement>('[role^=\"menuitem\"]') ?? item;\n }\n\n function getFocusedItemIndex(): number {\n const items = getItems();\n\n return items.findIndex((item) => {\n const focusable = getItemFocusable(item);\n\n return item === document.activeElement || focusable === document.activeElement;\n });\n }\n\n const isOpenSignal = signal(false);\n let stopPositioning: (() => void) | null = null;\n const positioner = createDropdownPositioner({\n getFloating: () => panelEl,\n getPlacement: () => (props.placement.value ?? 'bottom-start') as Placement,\n getReference: () => triggerEl,\n matchWidth: false,\n offsetPx: 4,\n padding: 6,\n });\n const list = createListControl<HTMLElement>({\n disabled: computed(() => !isOpenSignal.value),\n getItems: getItems,\n isItemDisabled: (item) => item.hasAttribute('disabled'),\n onNavigate: (_action, index) => {\n const nextItem = getItems()[index];\n\n getItemFocusable(nextItem)?.focus();\n },\n signal: abortSignal,\n });\n\n const close = (reason: DropdownCloseReason = 'programmatic', shouldRestoreFocus = true): void => {\n if (!isOpenSignal.value) return;\n\n isOpenSignal.value = false;\n list.reset();\n stopPositioning?.();\n stopPositioning = null;\n\n if (shouldRestoreFocus) restoreTriggerFocus(() => triggerEl);\n\n emit('open-change', { open: false, reason });\n };\n\n const open = (reason: OverlayOpenReason = 'programmatic'): void => {\n if (isDisabled.value || isOpenSignal.value) return;\n\n isOpenSignal.value = true;\n positioner.update();\n stopPositioning = positioner.startAutoUpdate?.() ?? null;\n emit('open-change', { open: true, reason });\n };\n\n const toggle = (): void => {\n if (isOpenSignal.value) close('trigger');\n else open('click');\n };\n\n createOutsidePointerDismissal({\n getTargets: () => [el, panelEl],\n isActive: () => isOpenSignal.value,\n onDismiss: () => close('outsideClick'),\n signal: abortSignal,\n });\n\n let initialized = false;\n\n rippleWatch(\n props.open,\n (value) => {\n if (value === undefined) {\n if (!initialized) {\n if (props['default-open'].value) open('programmatic');\n } else {\n close('programmatic');\n }\n } else if (value) {\n open('programmatic');\n } else {\n close('programmatic');\n }\n\n initialized = true;\n },\n { immediate: true },\n );\n abortSignal.addEventListener(\n 'abort',\n () => {\n if (!isOpenSignal.value) return;\n\n isOpenSignal.value = false;\n list.reset();\n stopPositioning?.();\n stopPositioning = null;\n },\n { once: true },\n );\n\n const activateItem = (item: HTMLElement): void => {\n const type = item.getAttribute('type');\n const isCheckable = isCheckableItemType(type);\n\n if (type === 'checkbox') {\n item.toggleAttribute('checked', !item.hasAttribute('checked'));\n } else if (type === 'radio') {\n for (const radio of el.querySelectorAll<HTMLElement>('ore-menu-item[type=\"radio\"]')) {\n radio.toggleAttribute('checked', radio === item);\n }\n }\n\n const value = item.getAttribute('value') ?? '';\n const checked = isCheckable ? item.hasAttribute('checked') : undefined;\n\n emit('select', { checked, value });\n\n if (!isCheckable) {\n close('programmatic');\n }\n };\n\n const openFromKeyboardPress = createInteraction({\n keys: ['Enter', ' ', 'ArrowDown'],\n onPress: () => {\n open('keyboard');\n requestAnimationFrame(() => list.set(0));\n },\n });\n\n const activateFocusedFromKeyboardPress = createInteraction({\n onPress: () => {\n const focused = list.getActiveItem();\n\n if (focused) activateItem(focused);\n },\n });\n\n // ── Keyboard Navigation ───────────────────────────────────────────────────\n function handleMenuKeydown(e: KeyboardEvent) {\n if (isDisabled.value) return;\n\n const open = isOpenSignal.value;\n\n // When closed: open on Enter / Space / ArrowDown\n if (!open) {\n openFromKeyboardPress.handleKeydown(e);\n\n return;\n }\n\n const currentFocusedIndex = getFocusedItemIndex();\n\n if (currentFocusedIndex >= 0) list.set(currentFocusedIndex);\n\n if (e.key === 'Escape') {\n e.preventDefault();\n close('escape');\n\n return;\n }\n\n if (list.handleKeydown(e)) return;\n\n // When open: navigate and activate\n if (e.key === ' ' || e.key === 'Enter') {\n activateFocusedFromKeyboardPress.handleKeydown(e);\n\n return;\n }\n\n if (e.key === 'Tab') {\n close('programmatic');\n }\n }\n\n // ── Lifecycle ─────────────────────────────────────────────────────────────\n bind({\n on: {\n click: (e: MouseEvent) => {\n const path = e.composedPath();\n\n if (!isOpenSignal.value) return;\n\n const itemFromPath = path.find(\n (node): node is HTMLElement => node instanceof HTMLElement && node.tagName === 'ORE-MENU-ITEM',\n );\n const item = itemFromPath ?? (e.target as HTMLElement | null)?.closest<HTMLElement>('ore-menu-item') ?? null;\n\n if (!item || item.hasAttribute('disabled')) return;\n\n activateItem(item);\n },\n },\n });\n\n watch(() => {\n const open = isOpenSignal.value;\n\n if (!panelEl) return;\n\n panelEl.toggleAttribute('data-open', open);\n });\n\n function resolveTrigger() {\n cleanupTrigger?.();\n cleanupTrigger = null;\n\n const assigned = slots.elements('trigger').value;\n\n triggerEl = (assigned?.[0] as HTMLElement | undefined) ?? null;\n\n if (!triggerEl) return;\n\n const cleanups: Array<() => void> = [];\n const removeAria = bind(\n {\n aria: {\n controls: () => menuId,\n disabled: () => isDisabled.value,\n expanded: () => String(isOpenSignal.value),\n haspopup: 'menu',\n },\n },\n { target: triggerEl },\n );\n\n const onTriggerClick = (event: MouseEvent) => {\n event.stopPropagation();\n\n if (isDisabled.value) return;\n\n toggle();\n };\n const onTriggerKeydown = (event: KeyboardEvent) => {\n handleMenuKeydown(event);\n };\n\n triggerEl.addEventListener('click', onTriggerClick);\n triggerEl.addEventListener('keydown', onTriggerKeydown);\n cleanups.push(() => triggerEl?.removeEventListener('click', onTriggerClick));\n cleanups.push(() => triggerEl?.removeEventListener('keydown', onTriggerKeydown));\n\n cleanupTrigger = () => {\n removeAria();\n\n for (const cleanup of cleanups) cleanup();\n };\n }\n\n rippleWatch(slots.elements('trigger'), resolveTrigger, { immediate: true });\n\n onMounted(() => {\n return () => {\n cleanupTrigger?.();\n cleanupTrigger = null;\n };\n });\n\n return html`\n <slot name=\"trigger\"></slot>\n <div\n class=\"menu-panel\"\n part=\"panel\"\n id=\"${menuId}\"\n role=\"menu\"\n aria-orientation=\"vertical\"\n @keydown=\"${handleMenuKeydown}\"\n ref=\"${(el: HTMLElement | null) => {\n panelEl = el;\n panelEl?.toggleAttribute('data-open', isOpenSignal.value);\n }}\">\n <slot></slot>\n </div>\n `;\n },\n styles: [componentStyles, sizeVariantMixin(MENU_SIZE_PRESET), forcedColorsMixin],\n});\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"menu.d.ts","sourceRoot":"","sources":["../../../src/overlay/menu/menu.ts"],"names":[],"mappings":"AAkBA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAEjD,OAAO,EAIL,KAAK,uBAAuB,EAE7B,MAAM,YAAY,CAAC;AAWpB,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,MAAM,MAAM,eAAe,GAAG,UAAU,GAAG,OAAO,CAAC;AAEnD,MAAM,MAAM,aAAa,GAAG;IAC1B,aAAa,EAAE,uBAAuB,CAAC;IACvC,MAAM,EAAE,gBAAgB,CAAC;CAC1B,CAAC;AAEF,MAAM,MAAM,gBAAgB,GAAG;IAC7B,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,IAAI,CAAC,EAAE,eAAe,CAAC;IACvB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,MAAM,MAAM,YAAY,GAAG;IACzB,mEAAmE;IACnE,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,6BAA6B;IAC7B,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,SAAS,CAAC,EAAE,QAAQ,GAAG,cAAc,GAAG,YAAY,GAAG,KAAK,GAAG,WAAW,GAAG,SAAS,CAAC;IACvF,IAAI,CAAC,EAAE,aAAa,CAAC;CACtB,CAAC;AAMF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,eAAO,MAAM,aAAa,EAAG,eAAwB,CAAC;AAwDtD;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,aAAa,EAAG,oBAA6B,CAAC;AAgB3D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AACH,eAAO,MAAM,QAAQ,EAAG,UAAmB,CAAC"}
1
+ {"version":3,"file":"menu.d.ts","sourceRoot":"","sources":["../../../src/overlay/menu/menu.ts"],"names":[],"mappings":"AAkBA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAEjD,OAAO,EAQL,KAAK,uBAAuB,EAE7B,MAAM,YAAY,CAAC;AASpB,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,MAAM,MAAM,eAAe,GAAG,UAAU,GAAG,OAAO,CAAC;AAEnD,MAAM,MAAM,aAAa,GAAG;IAC1B,aAAa,EAAE,uBAAuB,CAAC;IACvC,MAAM,EAAE,gBAAgB,CAAC;CAC1B,CAAC;AAEF,MAAM,MAAM,gBAAgB,GAAG;IAC7B,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,IAAI,CAAC,EAAE,eAAe,CAAC;IACvB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,MAAM,MAAM,YAAY,GAAG;IACzB,mEAAmE;IACnE,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,6BAA6B;IAC7B,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,SAAS,CAAC,EAAE,QAAQ,GAAG,cAAc,GAAG,YAAY,GAAG,KAAK,GAAG,WAAW,GAAG,SAAS,CAAC;IACvF,IAAI,CAAC,EAAE,aAAa,CAAC;CACtB,CAAC;AAMF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,eAAO,MAAM,aAAa,EAAG,eAAwB,CAAC;AAwDtD;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,aAAa,EAAG,oBAA6B,CAAC;AAgB3D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AACH,eAAO,MAAM,QAAQ,EAAG,UAAmB,CAAC"}
@@ -1,2 +1,2 @@
1
- const e=require("../../core/ore.cjs"),t=require("./await-exit.cjs"),n=require("../../core/focus.cjs"),r=require("./background-lock.cjs");let i=require("@vielzeug/ripple"),a=require("@vielzeug/ripple/watch");function o(o){let s=e.lifecycleSignal(o.onCleanup),c=(0,i.signal)(!1),l=`programmatic`,u=r.createBackgroundLock(),d=!1,f=n.createFocusManager({getInitialFocusSelector:()=>o.initialFocus.value,getReturnFocus:()=>o.returnFocus.value,host:o.host,signal:s}),p=()=>{let e=o.dialogRef.value;if(!e?.open||d)return;d=!0,e.classList.add(`closing`);let n=()=>{e.close(),d=!1},r=o.getPanelEl();r?t.awaitExit(r,n,`transition`):n()},m=e=>o.host.dispatchEvent(new CustomEvent(`close-request`,{bubbles:!0,cancelable:!0,composed:!0,detail:{reason:e,...o.closeRequestDetail?.(e)}})),h={close(e=`programmatic`){if(!c.value)return;let t=o.dialogRef.value;t?.open?(l=e,(o.performClose??((e,t)=>e.close()))(t,e)):c.value=!1},dispose(){h.close(`programmatic`)},open(e=`programmatic`){if(c.value)return;let t=o.dialogRef.value;!t||t.open||(t.classList.remove(`closing`),f.captureReturnFocus(),o.beforeOpen?.(t),t.showModal(),u.lock(o.host),f.applyInitialFocus(),c.value=!0,o.onOpen?.(e))},[Symbol.dispose](){h.dispose()},toggle(e=`click`,t=`trigger`){c.value?h.close(t):h.open(e)}};s.addEventListener(`abort`,h.dispose,{once:!0});let g=e=>{m(e)&&h.close(e)};o.host.addEventListener(`command`,e=>{let t=e.command;t===`show-modal`?h.open(`trigger`):(t===`close`||t===`request-close`)&&g(`trigger`)},{signal:s});let _=e=>{e.target===o.dialogRef.value&&(e.preventDefault(),!o.isPersistent()&&g(`escape`))},v=e=>{o.isPersistent()||e.target===o.dialogRef.value&&g(`outsideClick`)},y=e=>{if(e&&e.target!==o.dialogRef.value)return;u.unlock(),o.host.removeAttribute(`open`),c.value=!1,f.restoreFocus();let t=l;l=`programmatic`,o.onNativeClose?.(t)},b=()=>{let e=o.dialogRef.value;e&&o.onEvent(e,`close`,y);let t=!1;(0,a.watch)(o.openProp,e=>{if(e===void 0){if(!t){o.defaultOpen.value&&h.open(`programmatic`),t=!0;return}h.close(`programmatic`);return}t=!0,e?h.open(`programmatic`):h.close(`programmatic`)},{immediate:!0})};return{closeWithAnimation:p,dispatchCloseRequest:m,handleBackdropClick:v,handleCancel:_,isOpen:c,overlay:h,requestClose:g,setupNativeListeners:()=>{let e=o.dialogRef.value;e&&(b(),o.onEvent(e,`click`,v),o.onEvent(e,`cancel`,_))},watchOpenProp:b}}exports.useDialogControl=o;
1
+ const e=require("../../core/ore.cjs"),t=require("../../core/focus.cjs"),n=require("./await-exit.cjs"),r=require("./background-lock.cjs");let i=require("@vielzeug/ripple"),a=require("@vielzeug/ripple/watch");function o(o){let s=e.lifecycleSignal(o.onCleanup),c=(0,i.signal)(!1),l=`programmatic`,u=r.createBackgroundLock(),d=!1,f=t.createFocusManager({getInitialFocusSelector:()=>o.initialFocus.value,getReturnFocus:()=>o.returnFocus.value,host:o.host,signal:s}),p=()=>{let e=o.dialogRef.value;if(!e?.open||d)return;d=!0,e.classList.add(`closing`);let t=()=>{e.close(),d=!1},r=o.getPanelEl();r?n.awaitExit(r,t,`transition`):t()},m=e=>o.host.dispatchEvent(new CustomEvent(`close-request`,{bubbles:!0,cancelable:!0,composed:!0,detail:{reason:e,...o.closeRequestDetail?.(e)}})),h={close(e=`programmatic`){if(!c.value)return;let t=o.dialogRef.value;t?.open?(l=e,(o.performClose??((e,t)=>e.close()))(t,e)):c.value=!1},dispose(){h.close(`programmatic`)},open(e=`programmatic`){if(c.value)return;let t=o.dialogRef.value;!t||t.open||(t.classList.remove(`closing`),f.captureReturnFocus(),o.beforeOpen?.(t),t.showModal(),u.lock(o.host),f.applyInitialFocus(),c.value=!0,o.onOpen?.(e))},[Symbol.dispose](){h.dispose()},toggle(e=`click`,t=`trigger`){c.value?h.close(t):h.open(e)}};s.addEventListener(`abort`,h.dispose,{once:!0});let g=e=>{m(e)&&h.close(e)};o.host.addEventListener(`command`,e=>{let t=e.command;t===`show-modal`?h.open(`trigger`):(t===`close`||t===`request-close`)&&g(`trigger`)},{signal:s});let _=e=>{e.target===o.dialogRef.value&&(e.preventDefault(),!o.isPersistent()&&g(`escape`))},v=e=>{o.isPersistent()||e.target===o.dialogRef.value&&g(`outsideClick`)},y=e=>{if(e&&e.target!==o.dialogRef.value)return;u.unlock(),o.host.removeAttribute(`open`),c.value=!1,f.restoreFocus();let t=l;l=`programmatic`,o.onNativeClose?.(t)},b=()=>{let e=o.dialogRef.value;e&&o.onEvent(e,`close`,y);let t=!1;(0,a.watch)(o.openProp,e=>{if(e===void 0){if(!t){o.defaultOpen.value&&h.open(`programmatic`),t=!0;return}h.close(`programmatic`);return}t=!0,e?h.open(`programmatic`):h.close(`programmatic`)},{immediate:!0})};return{closeWithAnimation:p,dispatchCloseRequest:m,handleBackdropClick:v,handleCancel:_,isOpen:c,overlay:h,requestClose:g,setupNativeListeners:()=>{let e=o.dialogRef.value;e&&(b(),o.onEvent(e,`click`,v),o.onEvent(e,`cancel`,_))},watchOpenProp:b}}exports.useDialogControl=o;
2
2
  //# sourceMappingURL=use-dialog.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"use-dialog.cjs","names":[],"sources":["../../../src/overlay/shared/use-dialog.ts"],"sourcesContent":["import { type Readable, type Signal, signal } from '@vielzeug/ripple';\nimport { watch } from '@vielzeug/ripple/watch';\n\nimport { lifecycleSignal, type DialogCloseReason, type OverlayOpenReason } from '../../core';\nimport { createFocusManager } from '../../core/focus';\nimport { awaitExit } from './await-exit';\nimport { createBackgroundLock } from './background-lock';\n\n// Invoker Commands API — not yet in lib.dom.d.ts\ninterface CommandEvent extends Event {\n command: string;\n}\n\n// ── Types ─────────────────────────────────────────────────────────────────────\n\nexport type UseDialogOptions = {\n /** Called after showModal() but before isOpen = true. Use to clear drag styles etc. */\n beforeOpen?: (dialog: HTMLDialogElement) => void;\n /** Extra properties merged into the `close-request` custom event detail. */\n closeRequestDetail?: (reason: Exclude<DialogCloseReason, 'programmatic'>) => Record<string, unknown>;\n /** Initial uncontrolled open state. Ignored when `openProp` is defined. */\n defaultOpen: Readable<boolean | undefined>;\n dialogRef: { value: HTMLDialogElement | null | undefined };\n getPanelEl: () => HTMLElement | null | undefined;\n host: HTMLElement;\n initialFocus: Readable<string | undefined>;\n isPersistent: () => boolean;\n /** Cleanup registrar from the component setup ctx. Automatically called on disconnect. */\n onCleanup: (fn: () => void) => void;\n /**\n * Scoped event listener registrar from the component setup ctx.\n * Automatically removed on component disconnect.\n */\n onEvent: <K extends keyof HTMLElementEventMap>(\n target: EventTarget | null | undefined,\n event: K,\n listener: (e: HTMLElementEventMap[K]) => void,\n options?: AddEventListenerOptions,\n ) => void;\n /**\n * Called after the native `close` event fires — after background unlock,\n * isOpen reset, and focus restore. Use to emit component events.\n */\n onNativeClose?: (reason: DialogCloseReason) => void;\n /** Called by the overlay on open. Use to emit events. */\n onOpen?: (reason: OverlayOpenReason) => void;\n /** Open prop from the component — drives programmatic open/close via watch. */\n openProp: Readable<boolean | undefined>;\n /**\n * Called by the overlay when closing. Orchestrates the close animation.\n * Default: `dialog.close()`. Override in dialog.ts to add the CSS exit animation.\n */\n performClose?: (dialog: HTMLDialogElement, reason: DialogCloseReason) => void;\n returnFocus: Readable<boolean | undefined>;\n};\n\nexport type UseDialogHandle = {\n closeWithAnimation: () => void;\n /**\n * Dispatch a cancelable `close-request` event on the host. Returns true when\n * the close is allowed (event not prevented), false when it was cancelled.\n */\n dispatchCloseRequest: (reason: Exclude<DialogCloseReason, 'programmatic'>) => boolean;\n handleBackdropClick: (e: MouseEvent) => void;\n handleCancel: (e: Event) => void;\n isOpen: Signal<boolean>;\n /** The modal dialog controller — open/close/toggle/dispose. */\n overlay: ModalDialogController;\n /**\n * Dispatch `close-request`; if allowed, call `overlay.close()`.\n */\n requestClose: (reason: Exclude<DialogCloseReason, 'programmatic'>) => void;\n /**\n * Registers the open-prop watcher AND standard click/cancel event listeners on\n * the dialog element (backdrop click-to-close, Escape via the native `cancel`\n * event). Use for components that need standard dialog behavior.\n * Call inside `onMounted()`.\n */\n setupNativeListeners: () => void;\n /**\n * Registers only the open-prop watcher (without adding click/cancel listeners).\n * Use for components like drawer that register their own event handlers.\n * Call inside `onMounted()`.\n */\n watchOpenProp: () => void;\n};\n\ntype ModalDialogController = {\n [Symbol.dispose](): void;\n close(reason?: DialogCloseReason): void;\n dispose(): void;\n open(reason?: OverlayOpenReason): void;\n toggle(openReason?: OverlayOpenReason, closeReason?: DialogCloseReason): void;\n};\n\n// ── Factory ───────────────────────────────────────────────────────────────────\n\n/**\n * Shared dialog-control composable for `ore-dialog` and `ore-drawer`.\n *\n * Owns: `isOpen`, close-reason tracking, focus management, `overlay`,\n * `requestClose`, background lock/unlock, and the `close` event handler.\n * Components supply only their unique behavior via callbacks and `onNativeClose`.\n */\nexport function useDialogControl(options: UseDialogOptions): UseDialogHandle {\n const abortSignal = lifecycleSignal(options.onCleanup);\n const isOpen = signal(false);\n // Internal close-reason: set atomically before dialog.close() fires.\n let pendingCloseReason: DialogCloseReason = 'programmatic';\n const bgLock = createBackgroundLock();\n let isClosing = false;\n\n // ── Focus management ──────────────────────────────────────────────────────\n const focus = createFocusManager({\n getInitialFocusSelector: () => options.initialFocus.value,\n getReturnFocus: () => options.returnFocus.value,\n host: options.host,\n signal: abortSignal,\n });\n // ─────────────────────────────────────────────────────────────────────────\n\n const closeWithAnimation = (): void => {\n const dialog = options.dialogRef.value;\n\n if (!dialog?.open || isClosing) return;\n\n isClosing = true;\n dialog.classList.add('closing');\n\n const finish = () => {\n dialog.close();\n // Do NOT remove 'closing' here — removing it while the native ::backdrop is\n // still held in the top layer by the 'overlay allow-discrete' transition\n // would revert its opacity to 1 and cause a visible flash. The class is\n // cleaned up at the start of the next open cycle (see setOpen below).\n isClosing = false;\n };\n\n const panel = options.getPanelEl();\n\n if (panel) {\n awaitExit(panel, finish, 'transition');\n } else {\n finish();\n }\n };\n\n const dispatchCloseRequest = (reason: Exclude<DialogCloseReason, 'programmatic'>): boolean => {\n return options.host.dispatchEvent(\n new CustomEvent('close-request', {\n bubbles: true,\n cancelable: true,\n composed: true,\n detail: { reason, ...options.closeRequestDetail?.(reason) },\n }),\n );\n };\n\n const overlay: ModalDialogController = {\n close(reason: DialogCloseReason = 'programmatic'): void {\n if (!isOpen.value) return;\n\n const dialog = options.dialogRef.value;\n\n if (dialog?.open) {\n pendingCloseReason = reason;\n (options.performClose ?? ((element, _reason) => element.close()))(dialog, reason);\n } else {\n isOpen.value = false;\n }\n },\n dispose(): void {\n overlay.close('programmatic');\n },\n open(reason: OverlayOpenReason = 'programmatic'): void {\n if (isOpen.value) return;\n\n const dialog = options.dialogRef.value;\n\n if (!dialog || dialog.open) return;\n\n // Clean up any leftover 'closing' class from the previous close animation\n // before opening so the entry @starting-style and transition work correctly.\n dialog.classList.remove('closing');\n focus.captureReturnFocus();\n options.beforeOpen?.(dialog);\n dialog.showModal();\n bgLock.lock(options.host);\n focus.applyInitialFocus();\n isOpen.value = true;\n options.onOpen?.(reason);\n },\n [Symbol.dispose](): void {\n overlay.dispose();\n },\n toggle(openReason: OverlayOpenReason = 'click', closeReason: DialogCloseReason = 'trigger'): void {\n if (isOpen.value) overlay.close(closeReason);\n else overlay.open(openReason);\n },\n };\n\n abortSignal.addEventListener('abort', overlay.dispose, { once: true });\n\n const requestClose = (reason: Exclude<DialogCloseReason, 'programmatic'>): void => {\n const allowed = dispatchCloseRequest(reason);\n\n if (!allowed) return;\n\n overlay.close(reason);\n };\n\n // Invoker Commands API — allows declarative open/close from outside the component:\n // <button commandfor=\"ore-dialog-id\" command=\"show-modal\">Open</button>\n // <button commandfor=\"ore-dialog-id\" command=\"close\">Close</button>\n options.host.addEventListener(\n 'command',\n (e: Event) => {\n const cmd = (e as CommandEvent).command;\n\n if (cmd === 'show-modal') overlay.open('trigger');\n else if (cmd === 'close' || cmd === 'request-close') requestClose('trigger');\n },\n { signal: abortSignal },\n );\n\n // The native `<dialog>` element auto-closes on Escape via its own close-watcher, which\n // dispatches a cancelable `cancel` event before `close`. Suppressing/redirecting that is the\n // spec-correct hook — relying on `keydown`'s `preventDefault()` to stop the close-watcher is\n // implementation-specific, not guaranteed across browsers.\n const handleCancel = (e: Event): void => {\n // See `handleNativeClose`'s comment: guard against a same-named bubbling event from a\n // descendant field being misread as this dialog's own native event.\n if (e.target !== options.dialogRef.value) return;\n\n e.preventDefault();\n\n if (options.isPersistent()) return;\n\n requestClose('escape');\n };\n\n const handleBackdropClick = (e: MouseEvent): void => {\n if (options.isPersistent()) return;\n\n if (e.target === options.dialogRef.value) requestClose('outsideClick');\n };\n\n // ── Internal native close handler ─────────────────────────────────────────\n // `e.target` must be checked against the native `<dialog>` itself, the same way\n // `handleBackdropClick` already does: a bubbling `close`-named event fired by *any* descendant\n // component reaches this listener too — regardless of that event's own `composed` flag, since\n // slot-assignment-based event-path computation (a slotted descendant's \"parent\" is the `<slot>`\n // projecting it) isn't gated by `composed` the way crossing back out of a shadow root is. Some\n // fields nested here (`ore-select`, `ore-combobox`, …) emit their own public `close` event when\n // *their* dropdown closes — without this check, selecting an option in one of those closes this\n // dialog too, misreading the field's own event as this dialog's native close.\n const handleNativeClose = (e?: Event): void => {\n if (e && e.target !== options.dialogRef.value) return;\n\n bgLock.unlock();\n options.host.removeAttribute('open');\n isOpen.value = false;\n focus.restoreFocus();\n\n const reason = pendingCloseReason;\n\n pendingCloseReason = 'programmatic';\n options.onNativeClose?.(reason);\n };\n\n const watchOpenProp = (): void => {\n const dialog = options.dialogRef.value;\n\n if (dialog) options.onEvent(dialog, 'close', handleNativeClose);\n\n let initialized = false;\n\n watch(\n options.openProp,\n (open) => {\n if (open === undefined) {\n if (!initialized) {\n if (options.defaultOpen.value) overlay.open('programmatic');\n\n initialized = true;\n\n return;\n }\n\n overlay.close('programmatic');\n\n return;\n }\n\n initialized = true;\n\n if (open) {\n overlay.open('programmatic');\n } else {\n overlay.close('programmatic');\n }\n },\n { immediate: true },\n );\n };\n\n const setupNativeListeners = (): void => {\n const dialog = options.dialogRef.value;\n\n if (!dialog) return;\n\n watchOpenProp();\n options.onEvent(dialog, 'click', handleBackdropClick);\n options.onEvent(dialog, 'cancel', handleCancel);\n };\n\n return {\n closeWithAnimation,\n dispatchCloseRequest,\n handleBackdropClick,\n handleCancel,\n isOpen,\n overlay,\n requestClose,\n setupNativeListeners,\n watchOpenProp,\n };\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"use-dialog.cjs","names":[],"sources":["../../../src/overlay/shared/use-dialog.ts"],"sourcesContent":["import { type Readable, type Signal, signal } from '@vielzeug/ripple';\nimport { watch } from '@vielzeug/ripple/watch';\n\nimport { createFocusManager, lifecycleSignal, type DialogCloseReason, type OverlayOpenReason } from '../../core';\nimport { awaitExit } from './await-exit';\nimport { createBackgroundLock } from './background-lock';\n\n// Invoker Commands API — not yet in lib.dom.d.ts\ninterface CommandEvent extends Event {\n command: string;\n}\n\n// ── Types ─────────────────────────────────────────────────────────────────────\n\nexport type UseDialogOptions = {\n /** Called after showModal() but before isOpen = true. Use to clear drag styles etc. */\n beforeOpen?: (dialog: HTMLDialogElement) => void;\n /** Extra properties merged into the `close-request` custom event detail. */\n closeRequestDetail?: (reason: Exclude<DialogCloseReason, 'programmatic'>) => Record<string, unknown>;\n /** Initial uncontrolled open state. Ignored when `openProp` is defined. */\n defaultOpen: Readable<boolean | undefined>;\n dialogRef: { value: HTMLDialogElement | null | undefined };\n getPanelEl: () => HTMLElement | null | undefined;\n host: HTMLElement;\n initialFocus: Readable<string | undefined>;\n isPersistent: () => boolean;\n /** Cleanup registrar from the component setup ctx. Automatically called on disconnect. */\n onCleanup: (fn: () => void) => void;\n /**\n * Scoped event listener registrar from the component setup ctx.\n * Automatically removed on component disconnect.\n */\n onEvent: <K extends keyof HTMLElementEventMap>(\n target: EventTarget | null | undefined,\n event: K,\n listener: (e: HTMLElementEventMap[K]) => void,\n options?: AddEventListenerOptions,\n ) => void;\n /**\n * Called after the native `close` event fires — after background unlock,\n * isOpen reset, and focus restore. Use to emit component events.\n */\n onNativeClose?: (reason: DialogCloseReason) => void;\n /** Called by the overlay on open. Use to emit events. */\n onOpen?: (reason: OverlayOpenReason) => void;\n /** Open prop from the component — drives programmatic open/close via watch. */\n openProp: Readable<boolean | undefined>;\n /**\n * Called by the overlay when closing. Orchestrates the close animation.\n * Default: `dialog.close()`. Override in dialog.ts to add the CSS exit animation.\n */\n performClose?: (dialog: HTMLDialogElement, reason: DialogCloseReason) => void;\n returnFocus: Readable<boolean | undefined>;\n};\n\nexport type UseDialogHandle = {\n closeWithAnimation: () => void;\n /**\n * Dispatch a cancelable `close-request` event on the host. Returns true when\n * the close is allowed (event not prevented), false when it was cancelled.\n */\n dispatchCloseRequest: (reason: Exclude<DialogCloseReason, 'programmatic'>) => boolean;\n handleBackdropClick: (e: MouseEvent) => void;\n handleCancel: (e: Event) => void;\n isOpen: Signal<boolean>;\n /** The modal dialog controller — open/close/toggle/dispose. */\n overlay: ModalDialogController;\n /**\n * Dispatch `close-request`; if allowed, call `overlay.close()`.\n */\n requestClose: (reason: Exclude<DialogCloseReason, 'programmatic'>) => void;\n /**\n * Registers the open-prop watcher AND standard click/cancel event listeners on\n * the dialog element (backdrop click-to-close, Escape via the native `cancel`\n * event). Use for components that need standard dialog behavior.\n * Call inside `onMounted()`.\n */\n setupNativeListeners: () => void;\n /**\n * Registers only the open-prop watcher (without adding click/cancel listeners).\n * Use for components like drawer that register their own event handlers.\n * Call inside `onMounted()`.\n */\n watchOpenProp: () => void;\n};\n\ntype ModalDialogController = {\n [Symbol.dispose](): void;\n close(reason?: DialogCloseReason): void;\n dispose(): void;\n open(reason?: OverlayOpenReason): void;\n toggle(openReason?: OverlayOpenReason, closeReason?: DialogCloseReason): void;\n};\n\n// ── Factory ───────────────────────────────────────────────────────────────────\n\n/**\n * Shared dialog-control composable for `ore-dialog` and `ore-drawer`.\n *\n * Owns: `isOpen`, close-reason tracking, focus management, `overlay`,\n * `requestClose`, background lock/unlock, and the `close` event handler.\n * Components supply only their unique behavior via callbacks and `onNativeClose`.\n */\nexport function useDialogControl(options: UseDialogOptions): UseDialogHandle {\n const abortSignal = lifecycleSignal(options.onCleanup);\n const isOpen = signal(false);\n // Internal close-reason: set atomically before dialog.close() fires.\n let pendingCloseReason: DialogCloseReason = 'programmatic';\n const bgLock = createBackgroundLock();\n let isClosing = false;\n\n // ── Focus management ──────────────────────────────────────────────────────\n const focus = createFocusManager({\n getInitialFocusSelector: () => options.initialFocus.value,\n getReturnFocus: () => options.returnFocus.value,\n host: options.host,\n signal: abortSignal,\n });\n // ─────────────────────────────────────────────────────────────────────────\n\n const closeWithAnimation = (): void => {\n const dialog = options.dialogRef.value;\n\n if (!dialog?.open || isClosing) return;\n\n isClosing = true;\n dialog.classList.add('closing');\n\n const finish = () => {\n dialog.close();\n // Do NOT remove 'closing' here — removing it while the native ::backdrop is\n // still held in the top layer by the 'overlay allow-discrete' transition\n // would revert its opacity to 1 and cause a visible flash. The class is\n // cleaned up at the start of the next open cycle (see setOpen below).\n isClosing = false;\n };\n\n const panel = options.getPanelEl();\n\n if (panel) {\n awaitExit(panel, finish, 'transition');\n } else {\n finish();\n }\n };\n\n const dispatchCloseRequest = (reason: Exclude<DialogCloseReason, 'programmatic'>): boolean => {\n return options.host.dispatchEvent(\n new CustomEvent('close-request', {\n bubbles: true,\n cancelable: true,\n composed: true,\n detail: { reason, ...options.closeRequestDetail?.(reason) },\n }),\n );\n };\n\n const overlay: ModalDialogController = {\n close(reason: DialogCloseReason = 'programmatic'): void {\n if (!isOpen.value) return;\n\n const dialog = options.dialogRef.value;\n\n if (dialog?.open) {\n pendingCloseReason = reason;\n (options.performClose ?? ((element, _reason) => element.close()))(dialog, reason);\n } else {\n isOpen.value = false;\n }\n },\n dispose(): void {\n overlay.close('programmatic');\n },\n open(reason: OverlayOpenReason = 'programmatic'): void {\n if (isOpen.value) return;\n\n const dialog = options.dialogRef.value;\n\n if (!dialog || dialog.open) return;\n\n // Clean up any leftover 'closing' class from the previous close animation\n // before opening so the entry @starting-style and transition work correctly.\n dialog.classList.remove('closing');\n focus.captureReturnFocus();\n options.beforeOpen?.(dialog);\n dialog.showModal();\n bgLock.lock(options.host);\n focus.applyInitialFocus();\n isOpen.value = true;\n options.onOpen?.(reason);\n },\n [Symbol.dispose](): void {\n overlay.dispose();\n },\n toggle(openReason: OverlayOpenReason = 'click', closeReason: DialogCloseReason = 'trigger'): void {\n if (isOpen.value) overlay.close(closeReason);\n else overlay.open(openReason);\n },\n };\n\n abortSignal.addEventListener('abort', overlay.dispose, { once: true });\n\n const requestClose = (reason: Exclude<DialogCloseReason, 'programmatic'>): void => {\n const allowed = dispatchCloseRequest(reason);\n\n if (!allowed) return;\n\n overlay.close(reason);\n };\n\n // Invoker Commands API — allows declarative open/close from outside the component:\n // <button commandfor=\"ore-dialog-id\" command=\"show-modal\">Open</button>\n // <button commandfor=\"ore-dialog-id\" command=\"close\">Close</button>\n options.host.addEventListener(\n 'command',\n (e: Event) => {\n const cmd = (e as CommandEvent).command;\n\n if (cmd === 'show-modal') overlay.open('trigger');\n else if (cmd === 'close' || cmd === 'request-close') requestClose('trigger');\n },\n { signal: abortSignal },\n );\n\n // The native `<dialog>` element auto-closes on Escape via its own close-watcher, which\n // dispatches a cancelable `cancel` event before `close`. Suppressing/redirecting that is the\n // spec-correct hook — relying on `keydown`'s `preventDefault()` to stop the close-watcher is\n // implementation-specific, not guaranteed across browsers.\n const handleCancel = (e: Event): void => {\n // See `handleNativeClose`'s comment: guard against a same-named bubbling event from a\n // descendant field being misread as this dialog's own native event.\n if (e.target !== options.dialogRef.value) return;\n\n e.preventDefault();\n\n if (options.isPersistent()) return;\n\n requestClose('escape');\n };\n\n const handleBackdropClick = (e: MouseEvent): void => {\n if (options.isPersistent()) return;\n\n if (e.target === options.dialogRef.value) requestClose('outsideClick');\n };\n\n // ── Internal native close handler ─────────────────────────────────────────\n // `e.target` must be checked against the native `<dialog>` itself, the same way\n // `handleBackdropClick` already does: a bubbling `close`-named event fired by *any* descendant\n // component reaches this listener too — regardless of that event's own `composed` flag, since\n // slot-assignment-based event-path computation (a slotted descendant's \"parent\" is the `<slot>`\n // projecting it) isn't gated by `composed` the way crossing back out of a shadow root is. Some\n // fields nested here (`ore-select`, `ore-combobox`, …) emit their own public `close` event when\n // *their* dropdown closes — without this check, selecting an option in one of those closes this\n // dialog too, misreading the field's own event as this dialog's native close.\n const handleNativeClose = (e?: Event): void => {\n if (e && e.target !== options.dialogRef.value) return;\n\n bgLock.unlock();\n options.host.removeAttribute('open');\n isOpen.value = false;\n focus.restoreFocus();\n\n const reason = pendingCloseReason;\n\n pendingCloseReason = 'programmatic';\n options.onNativeClose?.(reason);\n };\n\n const watchOpenProp = (): void => {\n const dialog = options.dialogRef.value;\n\n if (dialog) options.onEvent(dialog, 'close', handleNativeClose);\n\n let initialized = false;\n\n watch(\n options.openProp,\n (open) => {\n if (open === undefined) {\n if (!initialized) {\n if (options.defaultOpen.value) overlay.open('programmatic');\n\n initialized = true;\n\n return;\n }\n\n overlay.close('programmatic');\n\n return;\n }\n\n initialized = true;\n\n if (open) {\n overlay.open('programmatic');\n } else {\n overlay.close('programmatic');\n }\n },\n { immediate: true },\n );\n };\n\n const setupNativeListeners = (): void => {\n const dialog = options.dialogRef.value;\n\n if (!dialog) return;\n\n watchOpenProp();\n options.onEvent(dialog, 'click', handleBackdropClick);\n options.onEvent(dialog, 'cancel', handleCancel);\n };\n\n return {\n closeWithAnimation,\n dispatchCloseRequest,\n handleBackdropClick,\n handleCancel,\n isOpen,\n overlay,\n requestClose,\n setupNativeListeners,\n watchOpenProp,\n };\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"use-dialog.d.ts","sourceRoot":"","sources":["../../../src/overlay/shared/use-dialog.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"use-dialog.d.ts","sourceRoot":"","sources":["../../../src/overlay/shared/use-dialog.ts"],"names":[],"mappings":"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"}
@@ -1,12 +1,12 @@
1
1
  import { lifecycleSignal as e } from "../../core/ore.js";
2
- import { awaitExit as t } from "./await-exit.js";
3
- import { createFocusManager as n } from "../../core/focus.js";
2
+ import { createFocusManager as t } from "../../core/focus.js";
3
+ import { awaitExit as n } from "./await-exit.js";
4
4
  import { createBackgroundLock as r } from "./background-lock.js";
5
5
  import { signal as i } from "@vielzeug/ripple";
6
6
  import { watch as a } from "@vielzeug/ripple/watch";
7
7
  //#region src/overlay/shared/use-dialog.ts
8
8
  function o(o) {
9
- let s = e(o.onCleanup), c = i(!1), l = "programmatic", u = r(), d = !1, f = n({
9
+ let s = e(o.onCleanup), c = i(!1), l = "programmatic", u = r(), d = !1, f = t({
10
10
  getInitialFocusSelector: () => o.initialFocus.value,
11
11
  getReturnFocus: () => o.returnFocus.value,
12
12
  host: o.host,
@@ -15,10 +15,10 @@ function o(o) {
15
15
  let e = o.dialogRef.value;
16
16
  if (!e?.open || d) return;
17
17
  d = !0, e.classList.add("closing");
18
- let n = () => {
18
+ let t = () => {
19
19
  e.close(), d = !1;
20
20
  }, r = o.getPanelEl();
21
- r ? t(r, n, "transition") : n();
21
+ r ? n(r, t, "transition") : t();
22
22
  }, m = (e) => o.host.dispatchEvent(new CustomEvent("close-request", {
23
23
  bubbles: !0,
24
24
  cancelable: !0,