@vielzeug/refine 2.4.0 → 3.0.0

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 (206) hide show
  1. package/README.md +5 -18
  2. package/dist/accordion-item.cjs.map +1 -1
  3. package/dist/accordion-item.js.map +1 -1
  4. package/dist/accordion.cjs.map +1 -1
  5. package/dist/accordion.js.map +1 -1
  6. package/dist/async.cjs +1 -1
  7. package/dist/async.cjs.map +1 -1
  8. package/dist/async.js +3 -3
  9. package/dist/async.js.map +1 -1
  10. package/dist/box.cjs.map +1 -1
  11. package/dist/box.js.map +1 -1
  12. package/dist/card.cjs +1 -1
  13. package/dist/card.cjs.map +1 -1
  14. package/dist/card.js +2 -2
  15. package/dist/card.js.map +1 -1
  16. package/dist/checkbox-group.cjs +1 -1
  17. package/dist/checkbox-group.cjs.map +1 -1
  18. package/dist/checkbox-group.js +1 -1
  19. package/dist/checkbox-group.js.map +1 -1
  20. package/dist/combobox.cjs +2 -2
  21. package/dist/combobox.cjs.map +1 -1
  22. package/dist/combobox.js +7 -3
  23. package/dist/combobox.js.map +1 -1
  24. package/dist/command-palette.cjs +1 -1
  25. package/dist/command-palette.cjs.map +1 -1
  26. package/dist/command-palette.js +6 -2
  27. package/dist/command-palette.js.map +1 -1
  28. package/dist/content/card/card.css.cjs +1 -1
  29. package/dist/content/card/card.css.cjs.map +1 -1
  30. package/dist/content/card/card.css.js +1 -1
  31. package/dist/content/card/card.css.js.map +1 -1
  32. package/dist/content/card/card.d.ts +2 -2
  33. package/dist/content/card/card.d.ts.map +1 -1
  34. package/dist/content/pagination/pagination.css.cjs +1 -1
  35. package/dist/content/pagination/pagination.css.cjs.map +1 -1
  36. package/dist/content/pagination/pagination.css.js +1 -1
  37. package/dist/content/pagination/pagination.css.js.map +1 -1
  38. package/dist/core/field-base.cjs +1 -1
  39. package/dist/core/field-base.cjs.map +1 -1
  40. package/dist/core/field-base.d.ts +1 -1
  41. package/dist/core/field-base.js +1 -1
  42. package/dist/core/field-base.js.map +1 -1
  43. package/dist/core/nav.cjs +1 -1
  44. package/dist/core/nav.cjs.map +1 -1
  45. package/dist/core/nav.d.ts +4 -1
  46. package/dist/core/nav.d.ts.map +1 -1
  47. package/dist/core/nav.js +41 -28
  48. package/dist/core/nav.js.map +1 -1
  49. package/dist/core/option-list.cjs +1 -1
  50. package/dist/core/option-list.cjs.map +1 -1
  51. package/dist/core/option-list.d.ts.map +1 -1
  52. package/dist/core/option-list.js +30 -28
  53. package/dist/core/option-list.js.map +1 -1
  54. package/dist/core/slider.cjs +1 -1
  55. package/dist/core/slider.cjs.map +1 -1
  56. package/dist/core/slider.js +1 -1
  57. package/dist/core/slider.js.map +1 -1
  58. package/dist/core/spinner.cjs +1 -1
  59. package/dist/core/spinner.cjs.map +1 -1
  60. package/dist/core/spinner.js +1 -1
  61. package/dist/core/spinner.js.map +1 -1
  62. package/dist/custom-elements.json +215 -17
  63. package/dist/datagrid.cjs +73 -73
  64. package/dist/datagrid.cjs.map +1 -1
  65. package/dist/datagrid.js +331 -332
  66. package/dist/datagrid.js.map +1 -1
  67. package/dist/disclosure/accordion/accordion.css.cjs +1 -1
  68. package/dist/disclosure/accordion/accordion.css.cjs.map +1 -1
  69. package/dist/disclosure/accordion/accordion.css.js +1 -1
  70. package/dist/disclosure/accordion/accordion.css.js.map +1 -1
  71. package/dist/disclosure/accordion/accordion.d.ts +5 -5
  72. package/dist/disclosure/accordion/accordion.d.ts.map +1 -1
  73. package/dist/disclosure/accordion-item/accordion-item.css.cjs +1 -1
  74. package/dist/disclosure/accordion-item/accordion-item.css.cjs.map +1 -1
  75. package/dist/disclosure/accordion-item/accordion-item.css.js +1 -1
  76. package/dist/disclosure/accordion-item/accordion-item.css.js.map +1 -1
  77. package/dist/disclosure/accordion-item/accordion-item.d.ts +3 -3
  78. package/dist/disclosure/accordion-item/accordion-item.d.ts.map +1 -1
  79. package/dist/disclosure/tab-item/tab-item.css.cjs +1 -1
  80. package/dist/disclosure/tab-item/tab-item.css.cjs.map +1 -1
  81. package/dist/disclosure/tab-item/tab-item.css.js +1 -1
  82. package/dist/disclosure/tab-item/tab-item.css.js.map +1 -1
  83. package/dist/disclosure/tab-item/tab-item.d.ts +3 -3
  84. package/dist/disclosure/tab-item/tab-item.d.ts.map +1 -1
  85. package/dist/disclosure/tabs/tabs.css.cjs +1 -1
  86. package/dist/disclosure/tabs/tabs.css.cjs.map +1 -1
  87. package/dist/disclosure/tabs/tabs.css.js +1 -1
  88. package/dist/disclosure/tabs/tabs.css.js.map +1 -1
  89. package/dist/disclosure/tabs/tabs.d.ts +5 -5
  90. package/dist/disclosure/tabs/tabs.d.ts.map +1 -1
  91. package/dist/drawer.cjs +1 -1
  92. package/dist/drawer.cjs.map +1 -1
  93. package/dist/drawer.js +1 -1
  94. package/dist/drawer.js.map +1 -1
  95. package/dist/feedback/toast/toast.d.ts.map +1 -1
  96. package/dist/file-input.cjs +1 -1
  97. package/dist/file-input.cjs.map +1 -1
  98. package/dist/file-input.js +2 -2
  99. package/dist/file-input.js.map +1 -1
  100. package/dist/frameworks/elements.d.ts +4 -86
  101. package/dist/frameworks/react.d.ts +5 -4
  102. package/dist/frameworks/vue.d.ts +4 -4
  103. package/dist/grid.cjs +2 -2
  104. package/dist/grid.cjs.map +1 -1
  105. package/dist/grid.js +21 -18
  106. package/dist/grid.js.map +1 -1
  107. package/dist/inputs/combobox/combobox.d.ts +12 -1
  108. package/dist/inputs/combobox/combobox.d.ts.map +1 -1
  109. package/dist/inputs/datagrid/datagrid.d.ts +24 -32
  110. package/dist/inputs/datagrid/datagrid.d.ts.map +1 -1
  111. package/dist/inputs/file-input/file-input-upload.cjs +1 -1
  112. package/dist/inputs/file-input/file-input-upload.cjs.map +1 -1
  113. package/dist/inputs/file-input/file-input-upload.js +1 -1
  114. package/dist/inputs/file-input/file-input-upload.js.map +1 -1
  115. package/dist/inputs/index.d.ts +2 -3
  116. package/dist/inputs/index.d.ts.map +1 -1
  117. package/dist/inputs/shared/field-binding.cjs +1 -1
  118. package/dist/inputs/shared/field-binding.cjs.map +1 -1
  119. package/dist/inputs/shared/field-binding.js +6 -6
  120. package/dist/inputs/shared/field-binding.js.map +1 -1
  121. package/dist/layout/box/box.css.cjs +1 -1
  122. package/dist/layout/box/box.css.cjs.map +1 -1
  123. package/dist/layout/box/box.css.js +1 -1
  124. package/dist/layout/box/box.css.js.map +1 -1
  125. package/dist/layout/box/box.d.ts +3 -3
  126. package/dist/layout/box/box.d.ts.map +1 -1
  127. package/dist/layout/grid/grid.d.ts.map +1 -1
  128. package/dist/layout/navbar/navbar.css.cjs +1 -1
  129. package/dist/layout/navbar/navbar.css.cjs.map +1 -1
  130. package/dist/layout/navbar/navbar.css.js +1 -1
  131. package/dist/layout/navbar/navbar.css.js.map +1 -1
  132. package/dist/layout/navbar/navbar.d.ts +1 -1
  133. package/dist/layout/navbar/navbar.d.ts.map +1 -1
  134. package/dist/layout/sidebar/sidebar.d.ts.map +1 -1
  135. package/dist/menu.cjs +1 -1
  136. package/dist/menu.cjs.map +1 -1
  137. package/dist/menu.js +6 -6
  138. package/dist/menu.js.map +1 -1
  139. package/dist/navbar.cjs +1 -1
  140. package/dist/navbar.cjs.map +1 -1
  141. package/dist/navbar.js +87 -85
  142. package/dist/navbar.js.map +1 -1
  143. package/dist/navigation-menu.cjs +1 -1
  144. package/dist/navigation-menu.cjs.map +1 -1
  145. package/dist/navigation-menu.js +1 -1
  146. package/dist/navigation-menu.js.map +1 -1
  147. package/dist/number-input.cjs +1 -1
  148. package/dist/number-input.cjs.map +1 -1
  149. package/dist/number-input.js +1 -1
  150. package/dist/number-input.js.map +1 -1
  151. package/dist/overlay/popover/popover.d.ts.map +1 -1
  152. package/dist/overlay/tooltip/tooltip.d.ts.map +1 -1
  153. package/dist/popover.cjs +1 -1
  154. package/dist/popover.cjs.map +1 -1
  155. package/dist/popover.js +6 -6
  156. package/dist/popover.js.map +1 -1
  157. package/dist/radio-group.cjs +1 -1
  158. package/dist/radio-group.cjs.map +1 -1
  159. package/dist/radio-group.js +1 -1
  160. package/dist/radio-group.js.map +1 -1
  161. package/dist/radio.cjs +1 -1
  162. package/dist/radio.cjs.map +1 -1
  163. package/dist/radio.js +5 -5
  164. package/dist/radio.js.map +1 -1
  165. package/dist/rating.cjs +1 -1
  166. package/dist/rating.cjs.map +1 -1
  167. package/dist/rating.js +1 -1
  168. package/dist/rating.js.map +1 -1
  169. package/dist/refine.cjs +207 -207
  170. package/dist/refine.cjs.map +1 -1
  171. package/dist/refine.iife.js +268 -268
  172. package/dist/refine.iife.js.map +1 -1
  173. package/dist/refine.js +222 -222
  174. package/dist/refine.js.map +1 -1
  175. package/dist/shared/types.d.ts +0 -2
  176. package/dist/shared/types.d.ts.map +1 -1
  177. package/dist/sidebar.cjs +1 -1
  178. package/dist/sidebar.cjs.map +1 -1
  179. package/dist/sidebar.js +83 -83
  180. package/dist/sidebar.js.map +1 -1
  181. package/dist/skeleton.cjs +1 -1
  182. package/dist/skeleton.cjs.map +1 -1
  183. package/dist/skeleton.js +11 -9
  184. package/dist/skeleton.js.map +1 -1
  185. package/dist/slider.cjs +1 -1
  186. package/dist/slider.cjs.map +1 -1
  187. package/dist/slider.js +20 -20
  188. package/dist/slider.js.map +1 -1
  189. package/dist/stats.cjs +1 -1
  190. package/dist/stats.cjs.map +1 -1
  191. package/dist/stats.js +2 -2
  192. package/dist/stats.js.map +1 -1
  193. package/dist/tab-item.cjs.map +1 -1
  194. package/dist/tab-item.js.map +1 -1
  195. package/dist/tabs.cjs.map +1 -1
  196. package/dist/tabs.js.map +1 -1
  197. package/dist/toast.cjs +8 -8
  198. package/dist/toast.cjs.map +1 -1
  199. package/dist/toast.js +32 -33
  200. package/dist/toast.js.map +1 -1
  201. package/dist/tooltip.cjs +1 -1
  202. package/dist/tooltip.cjs.map +1 -1
  203. package/dist/tooltip.js +2 -2
  204. package/dist/tooltip.js.map +1 -1
  205. package/dist/types/elements.d.ts +207 -0
  206. package/package.json +12 -12
@@ -1 +1 @@
1
- {"version":3,"file":"navbar.css.cjs","names":[],"sources":["../../../src/layout/navbar/navbar.css?inline"],"sourcesContent":["@layer refine.base {\n :host {\n --_navbar-height: var(--navbar-height, var(--size-14));\n --_navbar-width: var(--navbar-width, min(100%, 80rem));\n --_navbar-offset: var(--navbar-offset, var(--size-3));\n --_navbar-bg: var(--navbar-bg, var(--color-canvas));\n --_navbar-color: var(--navbar-color, var(--color-contrast-900));\n --_navbar-border-color: var(--navbar-border-color, var(--color-divider));\n --_navbar-shadow: var(--navbar-shadow, var(--shadow-md));\n --_navbar-radius: var(--navbar-radius, var(--rounded-lg));\n\n box-sizing: border-box;\n display: block;\n width: 100%;\n color: var(--_navbar-color);\n }\n\n :host([data-mode='sticky']) {\n position: sticky;\n top: 0;\n z-index: var(--z-sticky);\n }\n\n :host([data-mode='floating']) {\n position: fixed;\n inset-inline: var(--_navbar-offset);\n top: var(--_navbar-offset);\n z-index: var(--z-sticky);\n }\n\n /* Preview mode: use absolute positioning so component stays within container bounds */\n :host([data-preview-mode][data-mode='floating']) {\n position: absolute;\n inset-inline: var(--_navbar-offset);\n top: auto;\n }\n\n :host([floating][sticky][data-scrolled]) {\n inset-inline: 0;\n top: 0;\n width: 100%;\n }\n\n :host([data-preview-mode][floating][sticky][data-scrolled]) {\n position: absolute;\n inset-inline: 0;\n top: auto;\n width: auto;\n }\n\n :host > nav {\n position: relative;\n display: flex;\n flex-direction: column;\n width: 100%;\n }\n\n .navbar {\n box-sizing: border-box;\n display: flex;\n flex-wrap: nowrap;\n gap: var(--size-2);\n align-items: center;\n width: 100%;\n max-width: var(--_navbar-width);\n min-height: var(--_navbar-height);\n padding: var(--size-2) var(--size-4);\n margin-inline: auto;\n overflow: auto hidden;\n color: inherit;\n white-space: nowrap;\n background: var(--_navbar-bg);\n border-top: none;\n border-right: none;\n border-bottom: var(--border) solid var(--_navbar-border-color);\n border-left: none;\n border-radius: 0;\n backdrop-filter: var(--navbar-backdrop-filter, blur(var(--blur-md)));\n transition: var(\n --_motion-transition,\n background var(--transition-normal),\n border-color var(--transition-normal),\n box-shadow var(--transition-normal),\n transform var(--transition-normal)\n );\n }\n\n :host([data-mode='floating']) .navbar {\n border-top: var(--border) solid var(--_navbar-border-color);\n border-right: var(--border) solid var(--_navbar-border-color);\n border-bottom: var(--border) solid var(--_navbar-border-color);\n border-left: var(--border) solid var(--_navbar-border-color);\n border-radius: var(--_navbar-radius);\n }\n\n :host([data-mode='sticky']) .navbar,\n :host([floating][sticky][data-scrolled]) .navbar {\n max-width: 100%;\n border-inline: none;\n border-radius: 0;\n }\n\n :host([data-mode-transitioning][data-mode='sticky']) .navbar {\n animation: navbar-floating-to-sticky var(--transition-normal) var(--ease-in-out);\n }\n\n :host([data-mode-transitioning][data-mode='floating']) .navbar {\n animation: navbar-sticky-to-floating var(--transition-normal) var(--ease-in-out);\n }\n\n .navbar-logo,\n .navbar-start,\n .navbar-center,\n .navbar-end {\n display: flex;\n align-items: center;\n min-width: 0;\n white-space: nowrap;\n }\n\n .navbar-logo {\n flex: 0 0 auto;\n }\n\n .navbar-start {\n flex: 0 0 auto;\n gap: var(--size-1);\n }\n\n .navbar-center {\n display: flex;\n flex: 0 1 auto;\n gap: var(--size-1);\n justify-content: flex-start;\n min-width: 0;\n }\n\n .navbar-end {\n flex: 0 0 auto;\n gap: var(--size-1);\n margin-inline-start: auto;\n }\n\n .mobile-toggle {\n display: none;\n flex-shrink: 0;\n align-items: center;\n justify-content: center;\n width: var(--size-9);\n height: var(--size-9);\n padding: 0;\n color: var(--color-contrast-700);\n cursor: pointer;\n background: transparent;\n border: var(--border) solid transparent;\n border-radius: var(--rounded-md);\n transition:\n background var(--transition-fast),\n border-color var(--transition-fast),\n color var(--transition-fast);\n }\n\n .mobile-toggle:hover {\n color: var(--color-contrast-900);\n background: var(--color-contrast-100);\n border-color: var(--color-contrast-200);\n }\n\n .mobile-toggle:focus-visible {\n outline: var(--focus-ring);\n }\n\n .mobile-menu-panel {\n position: relative;\n z-index: 1;\n box-sizing: border-box;\n display: none;\n width: 100%;\n max-width: var(--_navbar-width);\n padding: var(--size-2);\n margin-block-start: var(--size-2);\n margin-inline: auto;\n background: var(--_navbar-bg);\n border: var(--border) solid var(--_navbar-border-color);\n border-radius: var(--rounded-lg);\n box-shadow: var(--_shadow, var(--_navbar-shadow));\n backdrop-filter: var(--navbar-backdrop-filter, blur(var(--blur-md)));\n transform-origin: top;\n animation: navbar-mobile-in var(--transition-fast) var(--ease-out);\n }\n\n /* `:not([hidden])` — same reasoning as `.mobile-toggle` above: this panel's own `?hidden=`\n binding (navbar.ts) already covers \"not mobile\" / \"menu closed\" / \"no mobile-menu content\",\n but an unconditional `display: grid` here would still override that `[hidden]` for the \"no\n content\" case specifically, since author styles always win over the UA stylesheet. */\n :host([data-mobile][data-mobile-open]) .mobile-menu-panel:not([hidden]) {\n display: grid;\n gap: var(--size-1);\n }\n\n :host([data-mobile][data-mobile-open][data-mode='floating']) .mobile-menu-panel {\n margin-block-start: var(--size-1-5);\n }\n\n :host([data-mobile][data-mobile-open][data-mode='sticky']) .mobile-menu-panel,\n :host([data-mobile][data-mobile-open][floating][sticky][data-scrolled]) .mobile-menu-panel {\n position: absolute;\n inset-inline: 0;\n top: 100%;\n z-index: 2;\n max-width: 100%;\n margin: 0;\n border-inline: none;\n border-top: none;\n border-radius: 0 0 var(--rounded-md) var(--rounded-md);\n }\n\n /* `:not([hidden])` matters — the component's own `?hidden=` binding (navbar.ts) hides this\n button when there's neither `mobile-menu` slot content nor a `mobile-sidebar` target to\n toggle. Without it, this rule's `display: inline-flex` — an author-stylesheet declaration —\n unconditionally overrides the UA stylesheet's `[hidden] { display: none }`, since author\n styles always win over UA styles regardless of selector specificity. That left the button\n visibly clickable while toggling a `mobile-menu-panel` that stays hidden too (its own\n `?hidden=` binding includes the same \"nothing to show\" check) — clicking did nothing\n visible at all. */\n :host([data-mobile]) .mobile-toggle:not([hidden]) {\n display: inline-flex;\n order: -1;\n }\n\n :host([data-mobile]) .navbar-start,\n :host([data-mobile]) .navbar-center,\n :host([data-mobile]) .navbar-end {\n display: none;\n }\n\n :host([data-mobile][data-mobile-open]) .navbar {\n border-bottom-right-radius: var(--rounded-md);\n border-bottom-left-radius: var(--rounded-md);\n }\n\n @starting-style {\n .mobile-menu-panel {\n opacity: 0;\n transform: translateY(var(--overlay-enter-translate-y));\n }\n }\n\n @keyframes navbar-mobile-in {\n from {\n opacity: 0;\n transform: translateY(var(--overlay-enter-translate-y));\n }\n\n to {\n opacity: 1;\n transform: translateY(0);\n }\n }\n\n @keyframes navbar-floating-to-sticky {\n from {\n opacity: 0.92;\n transform: translateY(6px) scale(0.985);\n }\n\n to {\n opacity: 1;\n transform: translateY(0) scale(1);\n }\n }\n\n @keyframes navbar-sticky-to-floating {\n from {\n opacity: 0.95;\n transform: translateY(-2px) scale(1);\n }\n\n to {\n opacity: 1;\n transform: translateY(0) scale(0.99);\n }\n }\n\n .item {\n box-sizing: border-box;\n display: inline-flex;\n flex-shrink: 0;\n gap: var(--size-1);\n align-items: center;\n min-height: var(--_touch-target);\n padding: var(--size-1-5) var(--size-2-5);\n font-size: var(--text-sm);\n font-weight: var(--font-medium);\n color: var(--navbar-item-color, var(--color-contrast-700));\n white-space: nowrap;\n text-decoration: none;\n appearance: none;\n cursor: pointer;\n background: transparent;\n border: none;\n border-radius: var(--rounded-md);\n transition:\n background var(--transition-fast),\n color var(--transition-fast);\n }\n\n .item:hover,\n .item:focus-visible {\n color: var(--navbar-item-hover-color, var(--color-contrast-900));\n outline: var(--focus-ring);\n outline-offset: 1px;\n background: var(--navbar-item-hover-bg, var(--color-contrast-100));\n }\n\n :host([active]) .item {\n color: var(--navbar-item-active-color, var(--color-primary));\n background: var(--navbar-item-active-bg, color-mix(in oklch, var(--color-primary) 12%, transparent));\n }\n\n :host([disabled]) .item,\n :host([disabled]) .item:hover,\n :host([disabled]) .item:focus-visible {\n color: var(--color-contrast-400);\n pointer-events: none;\n cursor: not-allowed;\n outline: none;\n background: transparent;\n }\n\n .item-icon,\n .item-end {\n display: inline-flex;\n align-items: center;\n }\n\n .item-label {\n min-width: 0;\n white-space: nowrap;\n }\n\n /* Icon-only items (no visible label — name conveyed via aria-label) hide the empty label\n region so it stops reserving a `gap` slot next to the icon, and switch to compact,\n symmetric padding instead of the icon+label layout's wider horizontal padding. Without\n this, an icon-only item ends up lopsided: too much horizontal space around the icon plus\n a phantom gap left over for a label that never renders. */\n :host([icon-only]) .item-label {\n display: none;\n }\n\n :host([icon-only]) .item {\n padding: var(--size-1-5);\n }\n\n :host([navbar-mobile]) {\n display: block;\n width: 100%;\n }\n\n :host([navbar-mobile]) .item {\n display: flex;\n justify-content: flex-start;\n width: 100%;\n }\n}\n\n@layer refine.variants {\n :host([variant='flat']) {\n --_navbar-bg: color-mix(in oklch, var(--color-canvas) 88%, transparent);\n --_navbar-shadow: none;\n }\n\n :host([variant='bordered']) {\n --_navbar-bg: var(--color-canvas);\n --_navbar-border-color: color-mix(in oklch, var(--color-contrast-500) 32%, transparent);\n }\n\n :host([variant='outline']) {\n --_navbar-bg: transparent;\n --_navbar-shadow: none;\n --_navbar-border-color: color-mix(in oklch, var(--color-contrast-500) 40%, transparent);\n }\n\n :host([variant='glass']) {\n --_navbar-bg: color-mix(in oklch, var(--color-canvas) 70%, transparent);\n --navbar-backdrop-filter: blur(var(--blur-lg)) saturate(180%);\n }\n\n :host([color]) {\n --_navbar-border-color: color-mix(in oklch, var(--_theme-border) 30%, transparent);\n }\n}\n\n@media (width <= 768px) {\n @layer refine.base {\n :host([data-mode='floating']) {\n inset-inline: var(--size-2);\n top: var(--size-2);\n }\n\n :host([floating][sticky][data-scrolled]) {\n inset-inline: 0;\n top: 0;\n }\n }\n}\n"],"mappings":""}
1
+ {"version":3,"file":"navbar.css.cjs","names":[],"sources":["../../../src/layout/navbar/navbar.css?inline"],"sourcesContent":["@layer refine.base {\n :host {\n --_navbar-height: var(--navbar-height, var(--size-14));\n --_navbar-width: var(--navbar-width, min(100%, 80rem));\n --_navbar-offset: var(--navbar-offset, var(--size-3));\n --_navbar-bg: var(--navbar-bg, var(--color-canvas));\n --_navbar-color: var(--navbar-color, var(--color-contrast-900));\n --_navbar-border-color: var(--navbar-border-color, var(--color-divider));\n --_navbar-shadow: var(--navbar-shadow, var(--shadow-md));\n --_navbar-radius: var(--navbar-radius, var(--rounded-lg));\n\n box-sizing: border-box;\n display: block;\n width: 100%;\n color: var(--_navbar-color);\n }\n\n :host([data-mode='sticky']) {\n position: sticky;\n top: 0;\n z-index: var(--z-sticky);\n }\n\n :host([data-mode='floating']) {\n position: fixed;\n inset-inline: var(--_navbar-offset);\n top: var(--_navbar-offset);\n z-index: var(--z-sticky);\n }\n\n /* Preview mode: use absolute positioning so component stays within container bounds */\n :host([data-preview-mode][data-mode='floating']) {\n position: absolute;\n inset-inline: var(--_navbar-offset);\n top: auto;\n }\n\n :host([floating][sticky][data-scrolled]) {\n inset-inline: 0;\n top: 0;\n width: 100%;\n }\n\n :host([data-preview-mode][floating][sticky][data-scrolled]) {\n position: absolute;\n inset-inline: 0;\n top: auto;\n width: auto;\n }\n\n :host > nav {\n position: relative;\n display: flex;\n flex-direction: column;\n width: 100%;\n }\n\n .navbar {\n box-sizing: border-box;\n display: flex;\n flex-wrap: nowrap;\n gap: var(--size-2);\n align-items: center;\n width: 100%;\n max-width: var(--_navbar-width);\n min-height: var(--_navbar-height);\n padding: var(--size-2) var(--size-4);\n margin-inline: auto;\n overflow: auto hidden;\n color: inherit;\n white-space: nowrap;\n background: var(--_navbar-bg);\n border-top: none;\n border-right: none;\n border-bottom: var(--border) solid var(--_navbar-border-color);\n border-left: none;\n border-radius: 0;\n backdrop-filter: var(--navbar-backdrop-filter, blur(var(--blur-md)));\n transition: var(\n --_motion-transition,\n background var(--transition-normal),\n border-color var(--transition-normal),\n box-shadow var(--transition-normal),\n transform var(--transition-normal)\n );\n }\n\n :host([data-mode='floating']) .navbar {\n border-top: var(--border) solid var(--_navbar-border-color);\n border-right: var(--border) solid var(--_navbar-border-color);\n border-bottom: var(--border) solid var(--_navbar-border-color);\n border-left: var(--border) solid var(--_navbar-border-color);\n border-radius: var(--_navbar-radius);\n }\n\n :host([data-mode='sticky']) .navbar,\n :host([floating][sticky][data-scrolled]) .navbar {\n max-width: 100%;\n border-inline: none;\n border-radius: 0;\n }\n\n :host([data-mode-transitioning][data-mode='sticky']) .navbar {\n animation: navbar-floating-to-sticky var(--transition-normal) var(--ease-in-out);\n }\n\n :host([data-mode-transitioning][data-mode='floating']) .navbar {\n animation: navbar-sticky-to-floating var(--transition-normal) var(--ease-in-out);\n }\n\n .navbar-logo,\n .navbar-start,\n .navbar-center,\n .navbar-end {\n display: flex;\n align-items: center;\n min-width: 0;\n white-space: nowrap;\n }\n\n .navbar-logo {\n flex: 0 0 auto;\n }\n\n .navbar-start {\n flex: 0 0 auto;\n gap: var(--size-1);\n }\n\n .navbar-center {\n display: flex;\n flex: 0 1 auto;\n gap: var(--size-1);\n justify-content: flex-start;\n min-width: 0;\n }\n\n .navbar-end {\n flex: 0 0 auto;\n gap: var(--size-1);\n margin-inline-start: auto;\n }\n\n .mobile-toggle {\n display: none;\n flex-shrink: 0;\n align-items: center;\n justify-content: center;\n width: var(--size-9);\n height: var(--size-9);\n padding: 0;\n color: var(--color-contrast-700);\n cursor: pointer;\n background: transparent;\n border: var(--border) solid transparent;\n border-radius: var(--rounded-md);\n transition:\n background var(--transition-fast),\n border-color var(--transition-fast),\n color var(--transition-fast);\n }\n\n .mobile-toggle:hover {\n color: var(--color-contrast-900);\n background: var(--color-contrast-100);\n border-color: var(--color-contrast-200);\n }\n\n .mobile-toggle:focus-visible {\n outline: var(--focus-ring);\n }\n\n .mobile-menu-panel {\n position: relative;\n z-index: 1;\n box-sizing: border-box;\n display: none;\n width: 100%;\n max-width: var(--_navbar-width);\n padding: var(--size-2);\n margin-block-start: var(--size-2);\n margin-inline: auto;\n background: var(--_navbar-bg);\n border: var(--border) solid var(--_navbar-border-color);\n border-radius: var(--rounded-lg);\n box-shadow: var(--_shadow, var(--_navbar-shadow));\n backdrop-filter: var(--navbar-backdrop-filter, blur(var(--blur-md)));\n transform-origin: top;\n animation: navbar-mobile-in var(--transition-fast) var(--ease-out);\n }\n\n /* `:not([hidden])` — same reasoning as `.mobile-toggle` above: this panel's own `?hidden=`\n binding (navbar.ts) already covers \"not mobile\" / \"menu closed\" / \"no mobile-menu content\",\n but an unconditional `display: grid` here would still override that `[hidden]` for the \"no\n content\" case specifically, since author styles always win over the UA stylesheet. */\n :host([data-mobile][data-mobile-open]) .mobile-menu-panel:not([hidden]) {\n display: grid;\n gap: var(--size-1);\n }\n\n :host([data-mobile][data-mobile-open][data-mode='floating']) .mobile-menu-panel {\n margin-block-start: var(--size-1-5);\n }\n\n :host([data-mobile][data-mobile-open][data-mode='sticky']) .mobile-menu-panel,\n :host([data-mobile][data-mobile-open][floating][sticky][data-scrolled]) .mobile-menu-panel {\n position: absolute;\n inset-inline: 0;\n top: 100%;\n z-index: 2;\n max-width: 100%;\n margin: 0;\n border-inline: none;\n border-top: none;\n border-radius: 0 0 var(--rounded-md) var(--rounded-md);\n }\n\n /* `:not([hidden])` matters — the component's own `?hidden=` binding (navbar.ts) hides this\n button when there's neither `mobile-menu` slot content nor a `mobile-sidebar` target to\n toggle. Without it, this rule's `display: inline-flex` — an author-stylesheet declaration —\n unconditionally overrides the UA stylesheet's `[hidden] { display: none }`, since author\n styles always win over UA styles regardless of selector specificity. That left the button\n visibly clickable while toggling a `mobile-menu-panel` that stays hidden too (its own\n `?hidden=` binding includes the same \"nothing to show\" check) — clicking did nothing\n visible at all. */\n :host([data-mobile]) .mobile-toggle:not([hidden]) {\n display: inline-flex;\n order: -1;\n }\n\n :host([data-mobile]) .navbar-start,\n :host([data-mobile]) .navbar-center,\n :host([data-mobile]) .navbar-end {\n display: none;\n }\n\n :host([data-mobile][data-mobile-open]) .navbar {\n border-bottom-right-radius: var(--rounded-md);\n border-bottom-left-radius: var(--rounded-md);\n }\n\n @starting-style {\n .mobile-menu-panel {\n opacity: 0;\n transform: translateY(var(--overlay-enter-translate-y));\n }\n }\n\n @keyframes navbar-mobile-in {\n from {\n opacity: 0;\n transform: translateY(var(--overlay-enter-translate-y));\n }\n\n to {\n opacity: 1;\n transform: translateY(0);\n }\n }\n\n @keyframes navbar-floating-to-sticky {\n from {\n opacity: 0.92;\n transform: translateY(6px) scale(0.985);\n }\n\n to {\n opacity: 1;\n transform: translateY(0) scale(1);\n }\n }\n\n @keyframes navbar-sticky-to-floating {\n from {\n opacity: 0.95;\n transform: translateY(-2px) scale(1);\n }\n\n to {\n opacity: 1;\n transform: translateY(0) scale(0.99);\n }\n }\n\n .item {\n box-sizing: border-box;\n display: inline-flex;\n flex-shrink: 0;\n gap: var(--size-1);\n align-items: center;\n min-height: var(--_touch-target);\n padding: var(--size-1-5) var(--size-2-5);\n font-size: var(--text-sm);\n font-weight: var(--font-medium);\n color: var(--navbar-item-color, var(--color-contrast-700));\n white-space: nowrap;\n text-decoration: none;\n appearance: none;\n cursor: pointer;\n background: transparent;\n border: none;\n border-radius: var(--rounded-md);\n transition:\n background var(--transition-fast),\n color var(--transition-fast);\n }\n\n .item:hover,\n .item:focus-visible {\n color: var(--navbar-item-hover-color, var(--color-contrast-900));\n outline: var(--focus-ring);\n outline-offset: 1px;\n background: var(--navbar-item-hover-bg, var(--color-contrast-100));\n }\n\n :host([active]) .item {\n color: var(--navbar-item-active-color, var(--color-primary));\n background: var(--navbar-item-active-bg, color-mix(in oklch, var(--color-primary) 12%, transparent));\n }\n\n :host([disabled]) .item,\n :host([disabled]) .item:hover,\n :host([disabled]) .item:focus-visible {\n color: var(--color-contrast-400);\n pointer-events: none;\n cursor: not-allowed;\n outline: none;\n background: transparent;\n }\n\n .item-icon,\n .item-end {\n display: inline-flex;\n align-items: center;\n }\n\n .item-label {\n min-width: 0;\n white-space: nowrap;\n }\n\n /* Icon-only items (no visible label — name conveyed via aria-label) hide the empty label\n region so it stops reserving a `gap` slot next to the icon, and switch to compact,\n symmetric padding instead of the icon+label layout's wider horizontal padding. Without\n this, an icon-only item ends up lopsided: too much horizontal space around the icon plus\n a phantom gap left over for a label that never renders. */\n :host([icon-only]) .item-label {\n display: none;\n }\n\n :host([icon-only]) .item {\n padding: var(--size-1-5);\n }\n\n :host([navbar-mobile]) {\n display: block;\n width: 100%;\n }\n\n :host([navbar-mobile]) .item {\n display: flex;\n justify-content: flex-start;\n width: 100%;\n }\n}\n\n@layer refine.variants {\n :host([variant='flat']) {\n --_navbar-bg: color-mix(in oklch, var(--color-canvas) 88%, transparent);\n --_navbar-shadow: none;\n }\n\n :host([variant='bordered']) {\n --_navbar-bg: var(--color-canvas);\n --_navbar-border-color: color-mix(in oklch, var(--color-contrast-500) 32%, transparent);\n }\n\n :host([variant='outline']) {\n --_navbar-bg: transparent;\n --_navbar-shadow: none;\n --_navbar-border-color: color-mix(in oklch, var(--color-contrast-500) 40%, transparent);\n }\n\n :host([color]) {\n --_navbar-border-color: color-mix(in oklch, var(--_theme-border) 30%, transparent);\n }\n}\n\n@media (width <= 768px) {\n @layer refine.base {\n :host([data-mode='floating']) {\n inset-inline: var(--size-2);\n top: var(--size-2);\n }\n\n :host([floating][sticky][data-scrolled]) {\n inset-inline: 0;\n top: 0;\n }\n }\n}\n"],"mappings":""}
@@ -1,5 +1,5 @@
1
1
  //#region src/layout/navbar/navbar.css?inline
2
- var e = "@layer refine.base{:host{--_navbar-height:var(--navbar-height,var(--size-14));--_navbar-width:var(--navbar-width,min(100%, 80rem));--_navbar-offset:var(--navbar-offset,var(--size-3));--_navbar-bg:var(--navbar-bg,var(--color-canvas));--_navbar-color:var(--navbar-color,var(--color-contrast-900));--_navbar-border-color:var(--navbar-border-color,var(--color-divider));--_navbar-shadow:var(--navbar-shadow,var(--shadow-md));--_navbar-radius:var(--navbar-radius,var(--rounded-lg));box-sizing:border-box;width:100%;color:var(--_navbar-color);display:block}:host([data-mode=sticky]){z-index:var(--z-sticky);position:sticky;top:0}:host([data-mode=floating]){inset-inline:var(--_navbar-offset);top:var(--_navbar-offset);z-index:var(--z-sticky);position:fixed}:host([data-preview-mode][data-mode=floating]){inset-inline:var(--_navbar-offset);position:absolute;top:auto}:host([floating][sticky][data-scrolled]){width:100%;top:0;left:0;right:0}:host([data-preview-mode][floating][sticky][data-scrolled]){width:auto;position:absolute;top:auto;left:0;right:0}:host>nav{flex-direction:column;width:100%;display:flex;position:relative}.navbar{box-sizing:border-box;gap:var(--size-2);width:100%;max-width:var(--_navbar-width);min-height:var(--_navbar-height);padding:var(--size-2) var(--size-4);color:inherit;white-space:nowrap;background:var(--_navbar-bg);border-top:none;border-right:none;border-bottom:var(--border) solid var(--_navbar-border-color);-webkit-backdrop-filter:var(--navbar-backdrop-filter,blur(var(--blur-md)));backdrop-filter:var(--navbar-backdrop-filter,blur(var(--blur-md)));transition:var(--_motion-transition,background var(--transition-normal), border-color var(--transition-normal), box-shadow var(--transition-normal), transform var(--transition-normal));border-left:none;border-radius:0;flex-wrap:nowrap;align-items:center;margin-left:auto;margin-right:auto;display:flex;overflow:auto hidden}:host([data-mode=floating]) .navbar{border-top:var(--border) solid var(--_navbar-border-color);border-right:var(--border) solid var(--_navbar-border-color);border-bottom:var(--border) solid var(--_navbar-border-color);border-left:var(--border) solid var(--_navbar-border-color);border-radius:var(--_navbar-radius)}:host([data-mode=sticky]) .navbar,:host([floating][sticky][data-scrolled]) .navbar{border-left:none;border-right:none;border-radius:0;max-width:100%}:host([data-mode-transitioning][data-mode=sticky]) .navbar{animation:navbar-floating-to-sticky var(--transition-normal) var(--ease-in-out)}:host([data-mode-transitioning][data-mode=floating]) .navbar{animation:navbar-sticky-to-floating var(--transition-normal) var(--ease-in-out)}.navbar-logo,.navbar-start,.navbar-center,.navbar-end{white-space:nowrap;align-items:center;min-width:0;display:flex}.navbar-logo{flex:none}.navbar-start{gap:var(--size-1);flex:none}.navbar-center{gap:var(--size-1);flex:0 auto;justify-content:flex-start;min-width:0;display:flex}.navbar-end{gap:var(--size-1);flex:none}.navbar-end:not(:is(:lang(ae),:lang(ar),:lang(arc),:lang(bcc),:lang(bqi),:lang(ckb),:lang(dv),:lang(fa),:lang(glk),:lang(he),:lang(ku),:lang(mzn),:lang(nqo),:lang(pnb),:lang(ps),:lang(sd),:lang(ug),:lang(ur),:lang(yi))){margin-left:auto}.navbar-end:is(:lang(ae),:lang(ar),:lang(arc),:lang(bcc),:lang(bqi),:lang(ckb),:lang(dv),:lang(fa),:lang(glk),:lang(he),:lang(ku),:lang(mzn),:lang(nqo),:lang(pnb),:lang(ps),:lang(sd),:lang(ug),:lang(ur),:lang(yi)){margin-right:auto}.mobile-toggle{width:var(--size-9);height:var(--size-9);color:var(--color-contrast-700);cursor:pointer;border:var(--border) solid transparent;border-radius:var(--rounded-md);transition:background var(--transition-fast), border-color var(--transition-fast), color var(--transition-fast);background:0 0;flex-shrink:0;justify-content:center;align-items:center;padding:0;display:none}.mobile-toggle:hover{color:var(--color-contrast-900);background:var(--color-contrast-100);border-color:var(--color-contrast-200)}.mobile-toggle:focus-visible{outline:var(--focus-ring)}.mobile-menu-panel{z-index:1;box-sizing:border-box;width:100%;max-width:var(--_navbar-width);padding:var(--size-2);background:var(--_navbar-bg);border:var(--border) solid var(--_navbar-border-color);border-radius:var(--rounded-lg);box-shadow:var(--_shadow,var(--_navbar-shadow));-webkit-backdrop-filter:var(--navbar-backdrop-filter,blur(var(--blur-md)));backdrop-filter:var(--navbar-backdrop-filter,blur(var(--blur-md)));transform-origin:top;animation:navbar-mobile-in var(--transition-fast) var(--ease-out);margin-top:var(--size-2);margin-left:auto;margin-right:auto;display:none;position:relative}:host([data-mobile][data-mobile-open]) .mobile-menu-panel:not([hidden]){gap:var(--size-1);display:grid}:host([data-mobile][data-mobile-open][data-mode=floating]) .mobile-menu-panel{margin-top:var(--size-1-5)}:host([data-mobile][data-mobile-open][data-mode=sticky]) .mobile-menu-panel,:host([data-mobile][data-mobile-open][floating][sticky][data-scrolled]) .mobile-menu-panel{z-index:2;border-radius:0 0 var(--rounded-md) var(--rounded-md);border-top:none;border-left:none;border-right:none;max-width:100%;margin:0;position:absolute;top:100%;left:0;right:0}:host([data-mobile]) .mobile-toggle:not([hidden]){order:-1;display:inline-flex}:host([data-mobile]) .navbar-start,:host([data-mobile]) .navbar-center,:host([data-mobile]) .navbar-end{display:none}:host([data-mobile][data-mobile-open]) .navbar{border-bottom-right-radius:var(--rounded-md);border-bottom-left-radius:var(--rounded-md)}@starting-style{.mobile-menu-panel{opacity:0;transform:translateY(var(--overlay-enter-translate-y))}}@keyframes navbar-mobile-in{0%{opacity:0;transform:translateY(var(--overlay-enter-translate-y))}to{opacity:1;transform:translateY(0)}}@keyframes navbar-floating-to-sticky{0%{opacity:.92;transform:translateY(6px)scale(.985)}to{opacity:1;transform:translateY(0)scale(1)}}@keyframes navbar-sticky-to-floating{0%{opacity:.95;transform:translateY(-2px)scale(1)}to{opacity:1;transform:translateY(0)scale(.99)}}.item{box-sizing:border-box;gap:var(--size-1);min-height:var(--_touch-target);padding:var(--size-1-5) var(--size-2-5);font-size:var(--text-sm);font-weight:var(--font-medium);color:var(--navbar-item-color,var(--color-contrast-700));white-space:nowrap;appearance:none;cursor:pointer;border-radius:var(--rounded-md);transition:background var(--transition-fast), color var(--transition-fast);background:0 0;border:none;flex-shrink:0;align-items:center;text-decoration:none;display:inline-flex}.item:hover,.item:focus-visible{color:var(--navbar-item-hover-color,var(--color-contrast-900));outline:var(--focus-ring);outline-offset:1px;background:var(--navbar-item-hover-bg,var(--color-contrast-100))}:host([active]) .item{color:var(--navbar-item-active-color,var(--color-primary));background:var(--navbar-item-active-bg,color-mix(in oklch, var(--color-primary) 12%, transparent))}:host([disabled]) .item,:host([disabled]) .item:hover,:host([disabled]) .item:focus-visible{color:var(--color-contrast-400);pointer-events:none;cursor:not-allowed;background:0 0;outline:none}.item-icon,.item-end{align-items:center;display:inline-flex}.item-label{white-space:nowrap;min-width:0}:host([icon-only]) .item-label{display:none}:host([icon-only]) .item{padding:var(--size-1-5)}:host([navbar-mobile]){width:100%;display:block}:host([navbar-mobile]) .item{justify-content:flex-start;width:100%;display:flex}}@layer refine.variants{:host([variant=flat]){--_navbar-bg:color-mix(in oklch, var(--color-canvas) 88%, transparent);--_navbar-shadow:none}:host([variant=bordered]){--_navbar-bg:var(--color-canvas);--_navbar-border-color:color-mix(in oklch, var(--color-contrast-500) 32%, transparent)}:host([variant=outline]){--_navbar-bg:transparent;--_navbar-shadow:none;--_navbar-border-color:color-mix(in oklch, var(--color-contrast-500) 40%, transparent)}:host([variant=glass]){--_navbar-bg:color-mix(in oklch, var(--color-canvas) 70%, transparent);--navbar-backdrop-filter:blur(var(--blur-lg)) saturate(180%)}:host([color]){--_navbar-border-color:color-mix(in oklch, var(--_theme-border) 30%, transparent)}}@media (width<=768px){@layer refine.base{:host([data-mode=floating]){inset-inline:var(--size-2);top:var(--size-2)}:host([floating][sticky][data-scrolled]){top:0;left:0;right:0}}}";
2
+ var e = "@layer refine.base{:host{--_navbar-height:var(--navbar-height,var(--size-14));--_navbar-width:var(--navbar-width,min(100%, 80rem));--_navbar-offset:var(--navbar-offset,var(--size-3));--_navbar-bg:var(--navbar-bg,var(--color-canvas));--_navbar-color:var(--navbar-color,var(--color-contrast-900));--_navbar-border-color:var(--navbar-border-color,var(--color-divider));--_navbar-shadow:var(--navbar-shadow,var(--shadow-md));--_navbar-radius:var(--navbar-radius,var(--rounded-lg));box-sizing:border-box;width:100%;color:var(--_navbar-color);display:block}:host([data-mode=sticky]){z-index:var(--z-sticky);position:sticky;top:0}:host([data-mode=floating]){inset-inline:var(--_navbar-offset);top:var(--_navbar-offset);z-index:var(--z-sticky);position:fixed}:host([data-preview-mode][data-mode=floating]){inset-inline:var(--_navbar-offset);position:absolute;top:auto}:host([floating][sticky][data-scrolled]){width:100%;top:0;left:0;right:0}:host([data-preview-mode][floating][sticky][data-scrolled]){width:auto;position:absolute;top:auto;left:0;right:0}:host>nav{flex-direction:column;width:100%;display:flex;position:relative}.navbar{box-sizing:border-box;gap:var(--size-2);width:100%;max-width:var(--_navbar-width);min-height:var(--_navbar-height);padding:var(--size-2) var(--size-4);color:inherit;white-space:nowrap;background:var(--_navbar-bg);border-top:none;border-right:none;border-bottom:var(--border) solid var(--_navbar-border-color);-webkit-backdrop-filter:var(--navbar-backdrop-filter,blur(var(--blur-md)));backdrop-filter:var(--navbar-backdrop-filter,blur(var(--blur-md)));transition:var(--_motion-transition,background var(--transition-normal), border-color var(--transition-normal), box-shadow var(--transition-normal), transform var(--transition-normal));border-left:none;border-radius:0;flex-wrap:nowrap;align-items:center;margin-left:auto;margin-right:auto;display:flex;overflow:auto hidden}:host([data-mode=floating]) .navbar{border-top:var(--border) solid var(--_navbar-border-color);border-right:var(--border) solid var(--_navbar-border-color);border-bottom:var(--border) solid var(--_navbar-border-color);border-left:var(--border) solid var(--_navbar-border-color);border-radius:var(--_navbar-radius)}:host([data-mode=sticky]) .navbar,:host([floating][sticky][data-scrolled]) .navbar{border-left:none;border-right:none;border-radius:0;max-width:100%}:host([data-mode-transitioning][data-mode=sticky]) .navbar{animation:navbar-floating-to-sticky var(--transition-normal) var(--ease-in-out)}:host([data-mode-transitioning][data-mode=floating]) .navbar{animation:navbar-sticky-to-floating var(--transition-normal) var(--ease-in-out)}.navbar-logo,.navbar-start,.navbar-center,.navbar-end{white-space:nowrap;align-items:center;min-width:0;display:flex}.navbar-logo{flex:none}.navbar-start{gap:var(--size-1);flex:none}.navbar-center{gap:var(--size-1);flex:0 auto;justify-content:flex-start;min-width:0;display:flex}.navbar-end{gap:var(--size-1);flex:none}.navbar-end:not(:is(:lang(ae),:lang(ar),:lang(arc),:lang(bcc),:lang(bqi),:lang(ckb),:lang(dv),:lang(fa),:lang(glk),:lang(he),:lang(ku),:lang(mzn),:lang(nqo),:lang(pnb),:lang(ps),:lang(sd),:lang(ug),:lang(ur),:lang(yi))){margin-left:auto}.navbar-end:is(:lang(ae),:lang(ar),:lang(arc),:lang(bcc),:lang(bqi),:lang(ckb),:lang(dv),:lang(fa),:lang(glk),:lang(he),:lang(ku),:lang(mzn),:lang(nqo),:lang(pnb),:lang(ps),:lang(sd),:lang(ug),:lang(ur),:lang(yi)){margin-right:auto}.mobile-toggle{width:var(--size-9);height:var(--size-9);color:var(--color-contrast-700);cursor:pointer;border:var(--border) solid transparent;border-radius:var(--rounded-md);transition:background var(--transition-fast), border-color var(--transition-fast), color var(--transition-fast);background:0 0;flex-shrink:0;justify-content:center;align-items:center;padding:0;display:none}.mobile-toggle:hover{color:var(--color-contrast-900);background:var(--color-contrast-100);border-color:var(--color-contrast-200)}.mobile-toggle:focus-visible{outline:var(--focus-ring)}.mobile-menu-panel{z-index:1;box-sizing:border-box;width:100%;max-width:var(--_navbar-width);padding:var(--size-2);background:var(--_navbar-bg);border:var(--border) solid var(--_navbar-border-color);border-radius:var(--rounded-lg);box-shadow:var(--_shadow,var(--_navbar-shadow));-webkit-backdrop-filter:var(--navbar-backdrop-filter,blur(var(--blur-md)));backdrop-filter:var(--navbar-backdrop-filter,blur(var(--blur-md)));transform-origin:top;animation:navbar-mobile-in var(--transition-fast) var(--ease-out);margin-top:var(--size-2);margin-left:auto;margin-right:auto;display:none;position:relative}:host([data-mobile][data-mobile-open]) .mobile-menu-panel:not([hidden]){gap:var(--size-1);display:grid}:host([data-mobile][data-mobile-open][data-mode=floating]) .mobile-menu-panel{margin-top:var(--size-1-5)}:host([data-mobile][data-mobile-open][data-mode=sticky]) .mobile-menu-panel,:host([data-mobile][data-mobile-open][floating][sticky][data-scrolled]) .mobile-menu-panel{z-index:2;border-radius:0 0 var(--rounded-md) var(--rounded-md);border-top:none;border-left:none;border-right:none;max-width:100%;margin:0;position:absolute;top:100%;left:0;right:0}:host([data-mobile]) .mobile-toggle:not([hidden]){order:-1;display:inline-flex}:host([data-mobile]) .navbar-start,:host([data-mobile]) .navbar-center,:host([data-mobile]) .navbar-end{display:none}:host([data-mobile][data-mobile-open]) .navbar{border-bottom-right-radius:var(--rounded-md);border-bottom-left-radius:var(--rounded-md)}@starting-style{.mobile-menu-panel{opacity:0;transform:translateY(var(--overlay-enter-translate-y))}}@keyframes navbar-mobile-in{0%{opacity:0;transform:translateY(var(--overlay-enter-translate-y))}to{opacity:1;transform:translateY(0)}}@keyframes navbar-floating-to-sticky{0%{opacity:.92;transform:translateY(6px)scale(.985)}to{opacity:1;transform:translateY(0)scale(1)}}@keyframes navbar-sticky-to-floating{0%{opacity:.95;transform:translateY(-2px)scale(1)}to{opacity:1;transform:translateY(0)scale(.99)}}.item{box-sizing:border-box;gap:var(--size-1);min-height:var(--_touch-target);padding:var(--size-1-5) var(--size-2-5);font-size:var(--text-sm);font-weight:var(--font-medium);color:var(--navbar-item-color,var(--color-contrast-700));white-space:nowrap;appearance:none;cursor:pointer;border-radius:var(--rounded-md);transition:background var(--transition-fast), color var(--transition-fast);background:0 0;border:none;flex-shrink:0;align-items:center;text-decoration:none;display:inline-flex}.item:hover,.item:focus-visible{color:var(--navbar-item-hover-color,var(--color-contrast-900));outline:var(--focus-ring);outline-offset:1px;background:var(--navbar-item-hover-bg,var(--color-contrast-100))}:host([active]) .item{color:var(--navbar-item-active-color,var(--color-primary));background:var(--navbar-item-active-bg,color-mix(in oklch, var(--color-primary) 12%, transparent))}:host([disabled]) .item,:host([disabled]) .item:hover,:host([disabled]) .item:focus-visible{color:var(--color-contrast-400);pointer-events:none;cursor:not-allowed;background:0 0;outline:none}.item-icon,.item-end{align-items:center;display:inline-flex}.item-label{white-space:nowrap;min-width:0}:host([icon-only]) .item-label{display:none}:host([icon-only]) .item{padding:var(--size-1-5)}:host([navbar-mobile]){width:100%;display:block}:host([navbar-mobile]) .item{justify-content:flex-start;width:100%;display:flex}}@layer refine.variants{:host([variant=flat]){--_navbar-bg:color-mix(in oklch, var(--color-canvas) 88%, transparent);--_navbar-shadow:none}:host([variant=bordered]){--_navbar-bg:var(--color-canvas);--_navbar-border-color:color-mix(in oklch, var(--color-contrast-500) 32%, transparent)}:host([variant=outline]){--_navbar-bg:transparent;--_navbar-shadow:none;--_navbar-border-color:color-mix(in oklch, var(--color-contrast-500) 40%, transparent)}:host([color]){--_navbar-border-color:color-mix(in oklch, var(--_theme-border) 30%, transparent)}}@media (width<=768px){@layer refine.base{:host([data-mode=floating]){inset-inline:var(--size-2);top:var(--size-2)}:host([floating][sticky][data-scrolled]){top:0;left:0;right:0}}}";
3
3
  //#endregion
4
4
  export { e as default };
5
5
 
@@ -1 +1 @@
1
- {"version":3,"file":"navbar.css.js","names":[],"sources":["../../../src/layout/navbar/navbar.css?inline"],"sourcesContent":["@layer refine.base {\n :host {\n --_navbar-height: var(--navbar-height, var(--size-14));\n --_navbar-width: var(--navbar-width, min(100%, 80rem));\n --_navbar-offset: var(--navbar-offset, var(--size-3));\n --_navbar-bg: var(--navbar-bg, var(--color-canvas));\n --_navbar-color: var(--navbar-color, var(--color-contrast-900));\n --_navbar-border-color: var(--navbar-border-color, var(--color-divider));\n --_navbar-shadow: var(--navbar-shadow, var(--shadow-md));\n --_navbar-radius: var(--navbar-radius, var(--rounded-lg));\n\n box-sizing: border-box;\n display: block;\n width: 100%;\n color: var(--_navbar-color);\n }\n\n :host([data-mode='sticky']) {\n position: sticky;\n top: 0;\n z-index: var(--z-sticky);\n }\n\n :host([data-mode='floating']) {\n position: fixed;\n inset-inline: var(--_navbar-offset);\n top: var(--_navbar-offset);\n z-index: var(--z-sticky);\n }\n\n /* Preview mode: use absolute positioning so component stays within container bounds */\n :host([data-preview-mode][data-mode='floating']) {\n position: absolute;\n inset-inline: var(--_navbar-offset);\n top: auto;\n }\n\n :host([floating][sticky][data-scrolled]) {\n inset-inline: 0;\n top: 0;\n width: 100%;\n }\n\n :host([data-preview-mode][floating][sticky][data-scrolled]) {\n position: absolute;\n inset-inline: 0;\n top: auto;\n width: auto;\n }\n\n :host > nav {\n position: relative;\n display: flex;\n flex-direction: column;\n width: 100%;\n }\n\n .navbar {\n box-sizing: border-box;\n display: flex;\n flex-wrap: nowrap;\n gap: var(--size-2);\n align-items: center;\n width: 100%;\n max-width: var(--_navbar-width);\n min-height: var(--_navbar-height);\n padding: var(--size-2) var(--size-4);\n margin-inline: auto;\n overflow: auto hidden;\n color: inherit;\n white-space: nowrap;\n background: var(--_navbar-bg);\n border-top: none;\n border-right: none;\n border-bottom: var(--border) solid var(--_navbar-border-color);\n border-left: none;\n border-radius: 0;\n backdrop-filter: var(--navbar-backdrop-filter, blur(var(--blur-md)));\n transition: var(\n --_motion-transition,\n background var(--transition-normal),\n border-color var(--transition-normal),\n box-shadow var(--transition-normal),\n transform var(--transition-normal)\n );\n }\n\n :host([data-mode='floating']) .navbar {\n border-top: var(--border) solid var(--_navbar-border-color);\n border-right: var(--border) solid var(--_navbar-border-color);\n border-bottom: var(--border) solid var(--_navbar-border-color);\n border-left: var(--border) solid var(--_navbar-border-color);\n border-radius: var(--_navbar-radius);\n }\n\n :host([data-mode='sticky']) .navbar,\n :host([floating][sticky][data-scrolled]) .navbar {\n max-width: 100%;\n border-inline: none;\n border-radius: 0;\n }\n\n :host([data-mode-transitioning][data-mode='sticky']) .navbar {\n animation: navbar-floating-to-sticky var(--transition-normal) var(--ease-in-out);\n }\n\n :host([data-mode-transitioning][data-mode='floating']) .navbar {\n animation: navbar-sticky-to-floating var(--transition-normal) var(--ease-in-out);\n }\n\n .navbar-logo,\n .navbar-start,\n .navbar-center,\n .navbar-end {\n display: flex;\n align-items: center;\n min-width: 0;\n white-space: nowrap;\n }\n\n .navbar-logo {\n flex: 0 0 auto;\n }\n\n .navbar-start {\n flex: 0 0 auto;\n gap: var(--size-1);\n }\n\n .navbar-center {\n display: flex;\n flex: 0 1 auto;\n gap: var(--size-1);\n justify-content: flex-start;\n min-width: 0;\n }\n\n .navbar-end {\n flex: 0 0 auto;\n gap: var(--size-1);\n margin-inline-start: auto;\n }\n\n .mobile-toggle {\n display: none;\n flex-shrink: 0;\n align-items: center;\n justify-content: center;\n width: var(--size-9);\n height: var(--size-9);\n padding: 0;\n color: var(--color-contrast-700);\n cursor: pointer;\n background: transparent;\n border: var(--border) solid transparent;\n border-radius: var(--rounded-md);\n transition:\n background var(--transition-fast),\n border-color var(--transition-fast),\n color var(--transition-fast);\n }\n\n .mobile-toggle:hover {\n color: var(--color-contrast-900);\n background: var(--color-contrast-100);\n border-color: var(--color-contrast-200);\n }\n\n .mobile-toggle:focus-visible {\n outline: var(--focus-ring);\n }\n\n .mobile-menu-panel {\n position: relative;\n z-index: 1;\n box-sizing: border-box;\n display: none;\n width: 100%;\n max-width: var(--_navbar-width);\n padding: var(--size-2);\n margin-block-start: var(--size-2);\n margin-inline: auto;\n background: var(--_navbar-bg);\n border: var(--border) solid var(--_navbar-border-color);\n border-radius: var(--rounded-lg);\n box-shadow: var(--_shadow, var(--_navbar-shadow));\n backdrop-filter: var(--navbar-backdrop-filter, blur(var(--blur-md)));\n transform-origin: top;\n animation: navbar-mobile-in var(--transition-fast) var(--ease-out);\n }\n\n /* `:not([hidden])` — same reasoning as `.mobile-toggle` above: this panel's own `?hidden=`\n binding (navbar.ts) already covers \"not mobile\" / \"menu closed\" / \"no mobile-menu content\",\n but an unconditional `display: grid` here would still override that `[hidden]` for the \"no\n content\" case specifically, since author styles always win over the UA stylesheet. */\n :host([data-mobile][data-mobile-open]) .mobile-menu-panel:not([hidden]) {\n display: grid;\n gap: var(--size-1);\n }\n\n :host([data-mobile][data-mobile-open][data-mode='floating']) .mobile-menu-panel {\n margin-block-start: var(--size-1-5);\n }\n\n :host([data-mobile][data-mobile-open][data-mode='sticky']) .mobile-menu-panel,\n :host([data-mobile][data-mobile-open][floating][sticky][data-scrolled]) .mobile-menu-panel {\n position: absolute;\n inset-inline: 0;\n top: 100%;\n z-index: 2;\n max-width: 100%;\n margin: 0;\n border-inline: none;\n border-top: none;\n border-radius: 0 0 var(--rounded-md) var(--rounded-md);\n }\n\n /* `:not([hidden])` matters — the component's own `?hidden=` binding (navbar.ts) hides this\n button when there's neither `mobile-menu` slot content nor a `mobile-sidebar` target to\n toggle. Without it, this rule's `display: inline-flex` — an author-stylesheet declaration —\n unconditionally overrides the UA stylesheet's `[hidden] { display: none }`, since author\n styles always win over UA styles regardless of selector specificity. That left the button\n visibly clickable while toggling a `mobile-menu-panel` that stays hidden too (its own\n `?hidden=` binding includes the same \"nothing to show\" check) — clicking did nothing\n visible at all. */\n :host([data-mobile]) .mobile-toggle:not([hidden]) {\n display: inline-flex;\n order: -1;\n }\n\n :host([data-mobile]) .navbar-start,\n :host([data-mobile]) .navbar-center,\n :host([data-mobile]) .navbar-end {\n display: none;\n }\n\n :host([data-mobile][data-mobile-open]) .navbar {\n border-bottom-right-radius: var(--rounded-md);\n border-bottom-left-radius: var(--rounded-md);\n }\n\n @starting-style {\n .mobile-menu-panel {\n opacity: 0;\n transform: translateY(var(--overlay-enter-translate-y));\n }\n }\n\n @keyframes navbar-mobile-in {\n from {\n opacity: 0;\n transform: translateY(var(--overlay-enter-translate-y));\n }\n\n to {\n opacity: 1;\n transform: translateY(0);\n }\n }\n\n @keyframes navbar-floating-to-sticky {\n from {\n opacity: 0.92;\n transform: translateY(6px) scale(0.985);\n }\n\n to {\n opacity: 1;\n transform: translateY(0) scale(1);\n }\n }\n\n @keyframes navbar-sticky-to-floating {\n from {\n opacity: 0.95;\n transform: translateY(-2px) scale(1);\n }\n\n to {\n opacity: 1;\n transform: translateY(0) scale(0.99);\n }\n }\n\n .item {\n box-sizing: border-box;\n display: inline-flex;\n flex-shrink: 0;\n gap: var(--size-1);\n align-items: center;\n min-height: var(--_touch-target);\n padding: var(--size-1-5) var(--size-2-5);\n font-size: var(--text-sm);\n font-weight: var(--font-medium);\n color: var(--navbar-item-color, var(--color-contrast-700));\n white-space: nowrap;\n text-decoration: none;\n appearance: none;\n cursor: pointer;\n background: transparent;\n border: none;\n border-radius: var(--rounded-md);\n transition:\n background var(--transition-fast),\n color var(--transition-fast);\n }\n\n .item:hover,\n .item:focus-visible {\n color: var(--navbar-item-hover-color, var(--color-contrast-900));\n outline: var(--focus-ring);\n outline-offset: 1px;\n background: var(--navbar-item-hover-bg, var(--color-contrast-100));\n }\n\n :host([active]) .item {\n color: var(--navbar-item-active-color, var(--color-primary));\n background: var(--navbar-item-active-bg, color-mix(in oklch, var(--color-primary) 12%, transparent));\n }\n\n :host([disabled]) .item,\n :host([disabled]) .item:hover,\n :host([disabled]) .item:focus-visible {\n color: var(--color-contrast-400);\n pointer-events: none;\n cursor: not-allowed;\n outline: none;\n background: transparent;\n }\n\n .item-icon,\n .item-end {\n display: inline-flex;\n align-items: center;\n }\n\n .item-label {\n min-width: 0;\n white-space: nowrap;\n }\n\n /* Icon-only items (no visible label — name conveyed via aria-label) hide the empty label\n region so it stops reserving a `gap` slot next to the icon, and switch to compact,\n symmetric padding instead of the icon+label layout's wider horizontal padding. Without\n this, an icon-only item ends up lopsided: too much horizontal space around the icon plus\n a phantom gap left over for a label that never renders. */\n :host([icon-only]) .item-label {\n display: none;\n }\n\n :host([icon-only]) .item {\n padding: var(--size-1-5);\n }\n\n :host([navbar-mobile]) {\n display: block;\n width: 100%;\n }\n\n :host([navbar-mobile]) .item {\n display: flex;\n justify-content: flex-start;\n width: 100%;\n }\n}\n\n@layer refine.variants {\n :host([variant='flat']) {\n --_navbar-bg: color-mix(in oklch, var(--color-canvas) 88%, transparent);\n --_navbar-shadow: none;\n }\n\n :host([variant='bordered']) {\n --_navbar-bg: var(--color-canvas);\n --_navbar-border-color: color-mix(in oklch, var(--color-contrast-500) 32%, transparent);\n }\n\n :host([variant='outline']) {\n --_navbar-bg: transparent;\n --_navbar-shadow: none;\n --_navbar-border-color: color-mix(in oklch, var(--color-contrast-500) 40%, transparent);\n }\n\n :host([variant='glass']) {\n --_navbar-bg: color-mix(in oklch, var(--color-canvas) 70%, transparent);\n --navbar-backdrop-filter: blur(var(--blur-lg)) saturate(180%);\n }\n\n :host([color]) {\n --_navbar-border-color: color-mix(in oklch, var(--_theme-border) 30%, transparent);\n }\n}\n\n@media (width <= 768px) {\n @layer refine.base {\n :host([data-mode='floating']) {\n inset-inline: var(--size-2);\n top: var(--size-2);\n }\n\n :host([floating][sticky][data-scrolled]) {\n inset-inline: 0;\n top: 0;\n }\n }\n}\n"],"mappings":""}
1
+ {"version":3,"file":"navbar.css.js","names":[],"sources":["../../../src/layout/navbar/navbar.css?inline"],"sourcesContent":["@layer refine.base {\n :host {\n --_navbar-height: var(--navbar-height, var(--size-14));\n --_navbar-width: var(--navbar-width, min(100%, 80rem));\n --_navbar-offset: var(--navbar-offset, var(--size-3));\n --_navbar-bg: var(--navbar-bg, var(--color-canvas));\n --_navbar-color: var(--navbar-color, var(--color-contrast-900));\n --_navbar-border-color: var(--navbar-border-color, var(--color-divider));\n --_navbar-shadow: var(--navbar-shadow, var(--shadow-md));\n --_navbar-radius: var(--navbar-radius, var(--rounded-lg));\n\n box-sizing: border-box;\n display: block;\n width: 100%;\n color: var(--_navbar-color);\n }\n\n :host([data-mode='sticky']) {\n position: sticky;\n top: 0;\n z-index: var(--z-sticky);\n }\n\n :host([data-mode='floating']) {\n position: fixed;\n inset-inline: var(--_navbar-offset);\n top: var(--_navbar-offset);\n z-index: var(--z-sticky);\n }\n\n /* Preview mode: use absolute positioning so component stays within container bounds */\n :host([data-preview-mode][data-mode='floating']) {\n position: absolute;\n inset-inline: var(--_navbar-offset);\n top: auto;\n }\n\n :host([floating][sticky][data-scrolled]) {\n inset-inline: 0;\n top: 0;\n width: 100%;\n }\n\n :host([data-preview-mode][floating][sticky][data-scrolled]) {\n position: absolute;\n inset-inline: 0;\n top: auto;\n width: auto;\n }\n\n :host > nav {\n position: relative;\n display: flex;\n flex-direction: column;\n width: 100%;\n }\n\n .navbar {\n box-sizing: border-box;\n display: flex;\n flex-wrap: nowrap;\n gap: var(--size-2);\n align-items: center;\n width: 100%;\n max-width: var(--_navbar-width);\n min-height: var(--_navbar-height);\n padding: var(--size-2) var(--size-4);\n margin-inline: auto;\n overflow: auto hidden;\n color: inherit;\n white-space: nowrap;\n background: var(--_navbar-bg);\n border-top: none;\n border-right: none;\n border-bottom: var(--border) solid var(--_navbar-border-color);\n border-left: none;\n border-radius: 0;\n backdrop-filter: var(--navbar-backdrop-filter, blur(var(--blur-md)));\n transition: var(\n --_motion-transition,\n background var(--transition-normal),\n border-color var(--transition-normal),\n box-shadow var(--transition-normal),\n transform var(--transition-normal)\n );\n }\n\n :host([data-mode='floating']) .navbar {\n border-top: var(--border) solid var(--_navbar-border-color);\n border-right: var(--border) solid var(--_navbar-border-color);\n border-bottom: var(--border) solid var(--_navbar-border-color);\n border-left: var(--border) solid var(--_navbar-border-color);\n border-radius: var(--_navbar-radius);\n }\n\n :host([data-mode='sticky']) .navbar,\n :host([floating][sticky][data-scrolled]) .navbar {\n max-width: 100%;\n border-inline: none;\n border-radius: 0;\n }\n\n :host([data-mode-transitioning][data-mode='sticky']) .navbar {\n animation: navbar-floating-to-sticky var(--transition-normal) var(--ease-in-out);\n }\n\n :host([data-mode-transitioning][data-mode='floating']) .navbar {\n animation: navbar-sticky-to-floating var(--transition-normal) var(--ease-in-out);\n }\n\n .navbar-logo,\n .navbar-start,\n .navbar-center,\n .navbar-end {\n display: flex;\n align-items: center;\n min-width: 0;\n white-space: nowrap;\n }\n\n .navbar-logo {\n flex: 0 0 auto;\n }\n\n .navbar-start {\n flex: 0 0 auto;\n gap: var(--size-1);\n }\n\n .navbar-center {\n display: flex;\n flex: 0 1 auto;\n gap: var(--size-1);\n justify-content: flex-start;\n min-width: 0;\n }\n\n .navbar-end {\n flex: 0 0 auto;\n gap: var(--size-1);\n margin-inline-start: auto;\n }\n\n .mobile-toggle {\n display: none;\n flex-shrink: 0;\n align-items: center;\n justify-content: center;\n width: var(--size-9);\n height: var(--size-9);\n padding: 0;\n color: var(--color-contrast-700);\n cursor: pointer;\n background: transparent;\n border: var(--border) solid transparent;\n border-radius: var(--rounded-md);\n transition:\n background var(--transition-fast),\n border-color var(--transition-fast),\n color var(--transition-fast);\n }\n\n .mobile-toggle:hover {\n color: var(--color-contrast-900);\n background: var(--color-contrast-100);\n border-color: var(--color-contrast-200);\n }\n\n .mobile-toggle:focus-visible {\n outline: var(--focus-ring);\n }\n\n .mobile-menu-panel {\n position: relative;\n z-index: 1;\n box-sizing: border-box;\n display: none;\n width: 100%;\n max-width: var(--_navbar-width);\n padding: var(--size-2);\n margin-block-start: var(--size-2);\n margin-inline: auto;\n background: var(--_navbar-bg);\n border: var(--border) solid var(--_navbar-border-color);\n border-radius: var(--rounded-lg);\n box-shadow: var(--_shadow, var(--_navbar-shadow));\n backdrop-filter: var(--navbar-backdrop-filter, blur(var(--blur-md)));\n transform-origin: top;\n animation: navbar-mobile-in var(--transition-fast) var(--ease-out);\n }\n\n /* `:not([hidden])` — same reasoning as `.mobile-toggle` above: this panel's own `?hidden=`\n binding (navbar.ts) already covers \"not mobile\" / \"menu closed\" / \"no mobile-menu content\",\n but an unconditional `display: grid` here would still override that `[hidden]` for the \"no\n content\" case specifically, since author styles always win over the UA stylesheet. */\n :host([data-mobile][data-mobile-open]) .mobile-menu-panel:not([hidden]) {\n display: grid;\n gap: var(--size-1);\n }\n\n :host([data-mobile][data-mobile-open][data-mode='floating']) .mobile-menu-panel {\n margin-block-start: var(--size-1-5);\n }\n\n :host([data-mobile][data-mobile-open][data-mode='sticky']) .mobile-menu-panel,\n :host([data-mobile][data-mobile-open][floating][sticky][data-scrolled]) .mobile-menu-panel {\n position: absolute;\n inset-inline: 0;\n top: 100%;\n z-index: 2;\n max-width: 100%;\n margin: 0;\n border-inline: none;\n border-top: none;\n border-radius: 0 0 var(--rounded-md) var(--rounded-md);\n }\n\n /* `:not([hidden])` matters — the component's own `?hidden=` binding (navbar.ts) hides this\n button when there's neither `mobile-menu` slot content nor a `mobile-sidebar` target to\n toggle. Without it, this rule's `display: inline-flex` — an author-stylesheet declaration —\n unconditionally overrides the UA stylesheet's `[hidden] { display: none }`, since author\n styles always win over UA styles regardless of selector specificity. That left the button\n visibly clickable while toggling a `mobile-menu-panel` that stays hidden too (its own\n `?hidden=` binding includes the same \"nothing to show\" check) — clicking did nothing\n visible at all. */\n :host([data-mobile]) .mobile-toggle:not([hidden]) {\n display: inline-flex;\n order: -1;\n }\n\n :host([data-mobile]) .navbar-start,\n :host([data-mobile]) .navbar-center,\n :host([data-mobile]) .navbar-end {\n display: none;\n }\n\n :host([data-mobile][data-mobile-open]) .navbar {\n border-bottom-right-radius: var(--rounded-md);\n border-bottom-left-radius: var(--rounded-md);\n }\n\n @starting-style {\n .mobile-menu-panel {\n opacity: 0;\n transform: translateY(var(--overlay-enter-translate-y));\n }\n }\n\n @keyframes navbar-mobile-in {\n from {\n opacity: 0;\n transform: translateY(var(--overlay-enter-translate-y));\n }\n\n to {\n opacity: 1;\n transform: translateY(0);\n }\n }\n\n @keyframes navbar-floating-to-sticky {\n from {\n opacity: 0.92;\n transform: translateY(6px) scale(0.985);\n }\n\n to {\n opacity: 1;\n transform: translateY(0) scale(1);\n }\n }\n\n @keyframes navbar-sticky-to-floating {\n from {\n opacity: 0.95;\n transform: translateY(-2px) scale(1);\n }\n\n to {\n opacity: 1;\n transform: translateY(0) scale(0.99);\n }\n }\n\n .item {\n box-sizing: border-box;\n display: inline-flex;\n flex-shrink: 0;\n gap: var(--size-1);\n align-items: center;\n min-height: var(--_touch-target);\n padding: var(--size-1-5) var(--size-2-5);\n font-size: var(--text-sm);\n font-weight: var(--font-medium);\n color: var(--navbar-item-color, var(--color-contrast-700));\n white-space: nowrap;\n text-decoration: none;\n appearance: none;\n cursor: pointer;\n background: transparent;\n border: none;\n border-radius: var(--rounded-md);\n transition:\n background var(--transition-fast),\n color var(--transition-fast);\n }\n\n .item:hover,\n .item:focus-visible {\n color: var(--navbar-item-hover-color, var(--color-contrast-900));\n outline: var(--focus-ring);\n outline-offset: 1px;\n background: var(--navbar-item-hover-bg, var(--color-contrast-100));\n }\n\n :host([active]) .item {\n color: var(--navbar-item-active-color, var(--color-primary));\n background: var(--navbar-item-active-bg, color-mix(in oklch, var(--color-primary) 12%, transparent));\n }\n\n :host([disabled]) .item,\n :host([disabled]) .item:hover,\n :host([disabled]) .item:focus-visible {\n color: var(--color-contrast-400);\n pointer-events: none;\n cursor: not-allowed;\n outline: none;\n background: transparent;\n }\n\n .item-icon,\n .item-end {\n display: inline-flex;\n align-items: center;\n }\n\n .item-label {\n min-width: 0;\n white-space: nowrap;\n }\n\n /* Icon-only items (no visible label — name conveyed via aria-label) hide the empty label\n region so it stops reserving a `gap` slot next to the icon, and switch to compact,\n symmetric padding instead of the icon+label layout's wider horizontal padding. Without\n this, an icon-only item ends up lopsided: too much horizontal space around the icon plus\n a phantom gap left over for a label that never renders. */\n :host([icon-only]) .item-label {\n display: none;\n }\n\n :host([icon-only]) .item {\n padding: var(--size-1-5);\n }\n\n :host([navbar-mobile]) {\n display: block;\n width: 100%;\n }\n\n :host([navbar-mobile]) .item {\n display: flex;\n justify-content: flex-start;\n width: 100%;\n }\n}\n\n@layer refine.variants {\n :host([variant='flat']) {\n --_navbar-bg: color-mix(in oklch, var(--color-canvas) 88%, transparent);\n --_navbar-shadow: none;\n }\n\n :host([variant='bordered']) {\n --_navbar-bg: var(--color-canvas);\n --_navbar-border-color: color-mix(in oklch, var(--color-contrast-500) 32%, transparent);\n }\n\n :host([variant='outline']) {\n --_navbar-bg: transparent;\n --_navbar-shadow: none;\n --_navbar-border-color: color-mix(in oklch, var(--color-contrast-500) 40%, transparent);\n }\n\n :host([color]) {\n --_navbar-border-color: color-mix(in oklch, var(--_theme-border) 30%, transparent);\n }\n}\n\n@media (width <= 768px) {\n @layer refine.base {\n :host([data-mode='floating']) {\n inset-inline: var(--size-2);\n top: var(--size-2);\n }\n\n :host([floating][sticky][data-scrolled]) {\n inset-inline: 0;\n top: 0;\n }\n }\n}\n"],"mappings":""}
@@ -81,7 +81,7 @@ export type OreNavbarItemProps = {
81
81
  * @attr {number} scroll-threshold - Scroll threshold for floating+sticky transition
82
82
  * @attr {string} breakpoint - CSS media query used for mobile mode
83
83
  * @attr {boolean} container-breakpoints - Evaluates parseable max-width breakpoints against container width
84
- * @attr {string} variant - Visual variant: 'flat' | 'solid' | 'bordered' | 'outline' | 'frost' | 'glass'
84
+ * @attr {string} variant - Visual variant: 'flat' | 'solid' | 'bordered' | 'outline' | 'frost'
85
85
  * @attr {string} color - Theme color: 'primary' | 'secondary' | 'info' | 'success' | 'warning' | 'error'
86
86
  * @attr {string} rounded - Border radius: 'none' | 'sm' | 'md' | 'lg' | 'xl' | '2xl' | '3xl' | 'full'
87
87
  * @attr {string} elevation - Shadow elevation: '0' | '1' | '2' | '3' | '4' | '5'
@@ -1 +1 @@
1
- {"version":3,"file":"navbar.d.ts","sourceRoot":"","sources":["../../../src/layout/navbar/navbar.ts"],"names":[],"mappings":"AAcA,OAAO,EAAY,KAAK,QAAQ,EAA0B,MAAM,kBAAkB,CAAC;AAGnF,OAAO,KAAK,EAAE,cAAc,EAAE,WAAW,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAE1F,OAAO,yBAAyB,CAAC;AAsFjC,sEAAsE;AACtE,MAAM,MAAM,aAAa,GAAG;IAC1B,eAAe,EAAE,MAAM,IAAI,CAAC;IAC5B,QAAQ,EAAE,QAAQ,CAAC,OAAO,CAAC,CAAC;IAC5B,cAAc,EAAE,QAAQ,CAAC,OAAO,CAAC,CAAC;CACnC,CAAC;AAEF,wCAAwC;AACxC,eAAO,MAAM,UAAU,qDAAgD,CAAC;AAExE,8BAA8B;AAC9B,MAAM,MAAM,eAAe,GAAG;IAC5B,oBAAoB,EAAE;QAAE,IAAI,EAAE,OAAO,CAAA;KAAE,CAAC;CACzC,CAAC;AAEF,yCAAyC;AACzC,MAAM,MAAM,aAAa,GAAG,WAAW,GACrC,cAAc,GAAG;IACf,eAAe,IAAI,IAAI,CAAC;IACxB,cAAc,IAAI,IAAI,CAAC;IACvB,gBAAgB,IAAI,IAAI,CAAC;CAC1B,CAAC;AAQJ,kCAAkC;AAClC,MAAM,MAAM,cAAc,GAAG;IAC3B,uDAAuD;IACvD,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,kBAAkB;IAClB,KAAK,CAAC,EAAE,UAAU,CAAC;IACnB,6EAA6E;IAC7E,uBAAuB,CAAC,EAAE,OAAO,CAAC;IAClC,mCAAmC;IACnC,SAAS,CAAC,EAAE,cAAc,CAAC;IAC3B,wCAAwC;IACxC,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,oCAAoC;IACpC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,wEAAwE;IACxE,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,yBAAyB;IACzB,OAAO,CAAC,EAAE,WAAW,CAAC;IACtB,gEAAgE;IAChE,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,+BAA+B;IAC/B,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,2BAA2B;IAC3B,OAAO,CAAC,EAAE,OAAO,CAAC,aAAa,EAAE,OAAO,GAAG,MAAM,CAAC,CAAC;CACpD,CAAC;AAEF,6BAA6B;AAC7B,MAAM,MAAM,kBAAkB,GAAG;IAC/B,oDAAoD;IACpD,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,oCAAoC;IACpC,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,wDAAwD;IACxD,IAAI,CAAC,EAAE,MAAM,CAAC;IACd;;;;;;OAMG;IACH,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,+CAA+C;IAC/C,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,8CAA8C;IAC9C,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4DG;AACH,eAAO,MAAM,UAAU,EAAG,YAAqB,CAAC;AAqhBhD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,eAAO,MAAM,eAAe,EAAG,iBAA0B,CAAC"}
1
+ {"version":3,"file":"navbar.d.ts","sourceRoot":"","sources":["../../../src/layout/navbar/navbar.ts"],"names":[],"mappings":"AAcA,OAAO,EAA8B,KAAK,QAAQ,EAA0B,MAAM,kBAAkB,CAAC;AAGrG,OAAO,KAAK,EAAE,cAAc,EAAE,WAAW,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAE1F,OAAO,yBAAyB,CAAC;AAsFjC,sEAAsE;AACtE,MAAM,MAAM,aAAa,GAAG;IAC1B,eAAe,EAAE,MAAM,IAAI,CAAC;IAC5B,QAAQ,EAAE,QAAQ,CAAC,OAAO,CAAC,CAAC;IAC5B,cAAc,EAAE,QAAQ,CAAC,OAAO,CAAC,CAAC;CACnC,CAAC;AAEF,wCAAwC;AACxC,eAAO,MAAM,UAAU,qDAAgD,CAAC;AAExE,8BAA8B;AAC9B,MAAM,MAAM,eAAe,GAAG;IAC5B,oBAAoB,EAAE;QAAE,IAAI,EAAE,OAAO,CAAA;KAAE,CAAC;CACzC,CAAC;AAEF,yCAAyC;AACzC,MAAM,MAAM,aAAa,GAAG,WAAW,GACrC,cAAc,GAAG;IACf,eAAe,IAAI,IAAI,CAAC;IACxB,cAAc,IAAI,IAAI,CAAC;IACvB,gBAAgB,IAAI,IAAI,CAAC;CAC1B,CAAC;AAQJ,kCAAkC;AAClC,MAAM,MAAM,cAAc,GAAG;IAC3B,uDAAuD;IACvD,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,kBAAkB;IAClB,KAAK,CAAC,EAAE,UAAU,CAAC;IACnB,6EAA6E;IAC7E,uBAAuB,CAAC,EAAE,OAAO,CAAC;IAClC,mCAAmC;IACnC,SAAS,CAAC,EAAE,cAAc,CAAC;IAC3B,wCAAwC;IACxC,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,oCAAoC;IACpC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,wEAAwE;IACxE,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,yBAAyB;IACzB,OAAO,CAAC,EAAE,WAAW,CAAC;IACtB,gEAAgE;IAChE,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,+BAA+B;IAC/B,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,2BAA2B;IAC3B,OAAO,CAAC,EAAE,OAAO,CAAC,aAAa,EAAE,OAAO,GAAG,MAAM,CAAC,CAAC;CACpD,CAAC;AAEF,6BAA6B;AAC7B,MAAM,MAAM,kBAAkB,GAAG;IAC/B,oDAAoD;IACpD,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,oCAAoC;IACpC,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,wDAAwD;IACxD,IAAI,CAAC,EAAE,MAAM,CAAC;IACd;;;;;;OAMG;IACH,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,+CAA+C;IAC/C,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,8CAA8C;IAC9C,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4DG;AACH,eAAO,MAAM,UAAU,EAAG,YAAqB,CAAC;AAgiBhD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,eAAO,MAAM,eAAe,EAAG,iBAA0B,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"sidebar.d.ts","sourceRoot":"","sources":["../../../src/layout/sidebar/sidebar.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"sidebar.d.ts","sourceRoot":"","sources":["../../../src/layout/sidebar/sidebar.ts"],"names":[],"mappings":"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"}
package/dist/menu.cjs CHANGED
@@ -14,7 +14,7 @@ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=requi
14
14
  <span class="icon-slot"><slot name="icon"></slot></span>
15
15
  <span class="item-label"><slot></slot></span>
16
16
  </div>
17
- `},styles:[t.colorThemeMixin,u.default]});var g=`ore-menu-separator`;(0,f.define)(g,{setup(){return f.html``},styles:[d.default]});var _=e=>e===`checkbox`||e===`radio`,v=e=>e==null?void 0:e===``||e===`true`,y=`ore-menu`;(0,f.define)(y,{props:{...s.sizableBundle,...s.disablableBundle,"default-open":f.prop.bool(!1),open:{default:void 0,parse:v},placement:f.prop.oneOf([`bottom`,`bottom-start`,`bottom-end`,`top`,`top-start`,`top-end`],`bottom-start`)},setup(e){let t=(0,f.getHost)(),s=(0,f.useEmit)(),c=(0,f.useSlots)(),l=f.watchEffect,u=(0,f.createStableId)(`menu`),d=(0,p.computed)(()=>!!e.disabled.value),h=r.lifecycleSignal(f.onCleanup),g=null,v=null,y=null;function b(){return Array.from(t.querySelectorAll(`ore-menu-item:not([disabled])`))}function x(e){return e?e.shadowRoot?.querySelector(`[role^="menuitem"]`)??e:null}function S(){return b().findIndex(e=>{let t=x(e);return e===document.activeElement||t===document.activeElement})}let C=(0,p.signal)(!1),w=null,T=o.createDropdownPositioner({getFloating:()=>v,getPlacement:()=>e.placement.value??`bottom-start`,getReference:()=>g,matchWidth:!1,offsetPx:4,padding:6}),E=a.createListControl({disabled:(0,p.computed)(()=>!C.value),getItems:b,isItemDisabled:e=>e.hasAttribute(`disabled`),onNavigate:({item:e})=>{x(e)?.focus()},signal:h}),D=(e=`programmatic`,t=!0)=>{C.value&&(C.value=!1,E.reset(),w?.(),w=null,t&&(0,m.restoreFocus)(()=>g),s(`open-change`,{open:!1,reason:e}))},O=(e=`programmatic`)=>{d.value||C.value||(C.value=!0,T.update(),w=T.startAutoUpdate?.()??null,s(`open-change`,{open:!0,reason:e}))},k=()=>{C.value?D(`trigger`):O(`click`)};i.createOutsidePointerDismissal({getTargets:()=>[t,v],isActive:()=>C.value,onDismiss:()=>D(`outsideClick`),signal:h});let A=!1;(0,p.watch)(e.open,t=>{t===void 0?A?D(`programmatic`):e[`default-open`].value&&O(`programmatic`):t?O(`programmatic`):D(`programmatic`),A=!0},{immediate:!0}),h.addEventListener(`abort`,()=>{C.value&&(C.value=!1,E.reset(),w?.(),w=null)},{once:!0});let j=e=>{let n=e.getAttribute(`type`),r=_(n);if(n===`checkbox`)e.toggleAttribute(`checked`,!e.hasAttribute(`checked`));else if(n===`radio`)for(let n of t.querySelectorAll(`ore-menu-item[type="radio"]`))n.toggleAttribute(`checked`,n===e);let i=e.getAttribute(`value`)??``,a=r?e.hasAttribute(`checked`):void 0;s(`select`,{checked:a,value:i}),r||D(`programmatic`)},M=n.createInteraction({keys:[`Enter`,` `,`ArrowDown`],onPress:()=>{O(`keyboard`),requestAnimationFrame(()=>E.set(0))}}),N=n.createInteraction({onPress:()=>{let e=E.getActiveItem();e&&j(e)}});function P(e){if(d.value)return;if(!C.value){M.handleKeydown(e);return}let t=S();if(t>=0&&E.set(t),e.key===`Escape`){e.preventDefault(),D(`escape`);return}if(!E.handleKeydown(e)){if(e.key===` `||e.key===`Enter`){N.handleKeydown(e);return}e.key===`Tab`&&D(`programmatic`)}}(0,f.bind)({on:{click:e=>{let t=e.composedPath();if(!C.value)return;let n=t.find(e=>e instanceof HTMLElement&&e.tagName===`ORE-MENU-ITEM`)??e.target?.closest(`ore-menu-item`)??null;n&&!n.hasAttribute(`disabled`)&&j(n)}}}),l(()=>{let e=C.value;v&&v.toggleAttribute(`data-open`,e)});function F(){if(y?.(),y=null,g=c.elements(`trigger`).value?.[0]??null,!g)return;let e=[],t=(0,f.bind)({aria:{controls:()=>u,disabled:()=>d.value,expanded:()=>String(C.value),haspopup:`menu`}},{target:g}),n=e=>{e.stopPropagation(),!d.value&&k()},r=e=>{P(e)};g.addEventListener(`click`,n),g.addEventListener(`keydown`,r),e.push(()=>g?.removeEventListener(`click`,n)),e.push(()=>g?.removeEventListener(`keydown`,r)),y=()=>{t();for(let t of e)t()}}return(0,p.watch)(c.elements(`trigger`),F,{immediate:!0}),(0,f.onMounted)(()=>(F(),()=>{y?.(),y=null})),f.html`
17
+ `},styles:[t.colorThemeMixin,u.default]});var g=`ore-menu-separator`;(0,f.define)(g,{setup(){return f.html``},styles:[d.default]});var _=e=>e===`checkbox`||e===`radio`,v=e=>e==null?void 0:e===``||e===`true`,y=`ore-menu`;(0,f.define)(y,{props:{...s.sizableBundle,...s.disablableBundle,"default-open":f.prop.bool(!1),open:{default:void 0,parse:v},placement:f.prop.oneOf([`bottom`,`bottom-start`,`bottom-end`,`top`,`top-start`,`top-end`],`bottom-start`)},setup(e){let t=(0,f.getHost)(),s=(0,f.useEmit)(),c=(0,f.useSlots)(),l=f.watchEffect,u=(0,f.createId)(`menu`),d=(0,p.computed)(()=>!!e.disabled.value),h=r.lifecycleSignal(f.onCleanup),g=null,v=null,y=null;function b(){return Array.from(t.querySelectorAll(`ore-menu-item:not([disabled])`))}function x(e){return e?e.shadowRoot?.querySelector(`[role^="menuitem"]`)??e:null}function S(){return b().findIndex(e=>{let t=x(e);return e===document.activeElement||t===document.activeElement})}let C=(0,p.signal)(!1),w=null,T=o.createDropdownPositioner({getFloating:()=>v,getPlacement:()=>e.placement.value??`bottom-start`,getReference:()=>g,matchWidth:!1,offsetPx:4,padding:6}),E=a.createListControl({disabled:(0,p.computed)(()=>!C.value),getItems:b,isItemDisabled:e=>e.hasAttribute(`disabled`),onNavigate:({item:e})=>{x(e)?.focus()},signal:h}),D=(e=`programmatic`,t=!0)=>{C.value&&(C.value=!1,E.reset(),w?.(),w=null,t&&(0,m.restoreFocus)(()=>g),s(`open-change`,{open:!1,reason:e}))},O=(e=`programmatic`)=>{d.value||C.value||(C.value=!0,T.update(),w=T.startAutoUpdate?.()??null,s(`open-change`,{open:!0,reason:e}))},k=()=>{C.value?D(`trigger`):O(`click`)};i.createOutsidePointerDismissal({getTargets:()=>[t,v],isActive:()=>C.value,onDismiss:()=>D(`outsideClick`),signal:h});let A=!1;(0,p.watch)(e.open,t=>{t===void 0?A?D(`programmatic`):e[`default-open`].value&&O(`programmatic`):t?O(`programmatic`):D(`programmatic`),A=!0},{immediate:!0}),h.addEventListener(`abort`,()=>{C.value&&(C.value=!1,E.reset(),w?.(),w=null)},{once:!0});let j=e=>{let n=e.getAttribute(`type`),r=_(n);if(n===`checkbox`)e.toggleAttribute(`checked`,!e.hasAttribute(`checked`));else if(n===`radio`)for(let n of t.querySelectorAll(`ore-menu-item[type="radio"]`))n.toggleAttribute(`checked`,n===e);let i=e.getAttribute(`value`)??``,a=r?e.hasAttribute(`checked`):void 0;s(`select`,{checked:a,value:i}),r||D(`programmatic`)},M=n.createInteraction({keys:[`Enter`,` `,`ArrowDown`],onPress:()=>{O(`keyboard`),requestAnimationFrame(()=>E.set(0))}}),N=n.createInteraction({onPress:()=>{let e=E.getActiveItem();e&&j(e)}});function P(e){if(d.value)return;if(!C.value){M.handleKeydown(e);return}let t=S();if(t>=0&&E.set(t),e.key===`Escape`){e.preventDefault(),D(`escape`);return}if(!E.handleKeydown(e)){if(e.key===` `||e.key===`Enter`){N.handleKeydown(e);return}e.key===`Tab`&&D(`programmatic`)}}(0,f.bind)({on:{click:e=>{let t=e.composedPath();if(!C.value)return;let n=t.find(e=>e instanceof HTMLElement&&e.tagName===`ORE-MENU-ITEM`)??e.target?.closest(`ore-menu-item`)??null;n&&!n.hasAttribute(`disabled`)&&j(n)}}}),l(()=>{let e=C.value;v&&v.toggleAttribute(`data-open`,e)});function F(){if(y?.(),y=null,g=c.elements(`trigger`).value?.[0]??null,!g)return;let e=[],t=(0,f.bind)({attr:{"aria-controls":()=>u,"aria-disabled":()=>d.value,"aria-expanded":()=>String(C.value),"aria-haspopup":`menu`}},{target:g}),n=e=>{e.stopPropagation(),!d.value&&k()},r=e=>{P(e)};g.addEventListener(`click`,n),g.addEventListener(`keydown`,r),e.push(()=>g?.removeEventListener(`click`,n)),e.push(()=>g?.removeEventListener(`keydown`,r)),y=()=>{t();for(let t of e)t()}}return(0,p.watch)(c.elements(`trigger`),F,{immediate:!0}),(0,f.onMounted)(()=>(F(),()=>{y?.(),y=null})),f.html`
18
18
  <slot name="trigger"></slot>
19
19
  <div
20
20
  class="menu-panel"
package/dist/menu.cjs.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"menu.cjs","names":[],"sources":["../src/overlay/menu/menu.ts"],"sourcesContent":["import { restoreFocus } from '@vielzeug/focus';\nimport type { Placement } from '@vielzeug/orbit';\nimport {\n bind,\n createStableId,\n define,\n getHost,\n html,\n onCleanup,\n onMounted,\n prop,\n useEmit,\n useSlots,\n watchEffect,\n} from '@vielzeug/ore';\nimport { computed, watch as rippleWatch, signal } from '@vielzeug/ripple';\nimport {\n createDropdownPositioner,\n createInteraction,\n createListControl,\n createOutsidePointerDismissal,\n type DropdownCloseReason,\n lifecycleSignal,\n type OverlayOpenChangeDetail,\n type OverlayOpenReason,\n} from '../../core';\nimport { disablableBundle, MENU_SIZE_PRESET, sizableBundle } from '../../shared';\nimport { colorThemeMixin, forcedColorsMixin, sizeVariantMixin } from '../../styles';\nimport type { ComponentSize } from '../../types';\nimport componentStyles from './menu.css?inline';\nimport menuItemStyles from './menu-item.css?inline';\nimport menuSeparatorStyles from './menu-separator.css?inline';\n\n// ── Types ─────────────────────────────────────────────────────────────\n\nexport interface MenuSelectDetail {\n checked?: boolean;\n value: string;\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: ({ item }) => {\n getItemFocusable(item)?.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 resolveTrigger();\n\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 { restoreFocus } from '@vielzeug/focus';\nimport type { Placement } from '@vielzeug/orbit';\nimport {\n bind,\n createId,\n define,\n getHost,\n html,\n onCleanup,\n onMounted,\n prop,\n useEmit,\n useSlots,\n watchEffect,\n} from '@vielzeug/ore';\nimport { computed, watch as rippleWatch, signal } from '@vielzeug/ripple';\nimport {\n createDropdownPositioner,\n createInteraction,\n createListControl,\n createOutsidePointerDismissal,\n type DropdownCloseReason,\n lifecycleSignal,\n type OverlayOpenChangeDetail,\n type OverlayOpenReason,\n} from '../../core';\nimport { disablableBundle, MENU_SIZE_PRESET, sizableBundle } from '../../shared';\nimport { colorThemeMixin, forcedColorsMixin, sizeVariantMixin } from '../../styles';\nimport type { ComponentSize } from '../../types';\nimport componentStyles from './menu.css?inline';\nimport menuItemStyles from './menu-item.css?inline';\nimport menuSeparatorStyles from './menu-separator.css?inline';\n\n// ── Types ─────────────────────────────────────────────────────────────\n\nexport interface MenuSelectDetail {\n checked?: boolean;\n value: string;\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 = createId('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: ({ item }) => {\n getItemFocusable(item)?.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 attr: {\n 'aria-controls': () => menuId,\n 'aria-disabled': () => isDisabled.value,\n 'aria-expanded': () => String(isOpenSignal.value),\n 'aria-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 resolveTrigger();\n\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":"6mBAoGA,IAAa,EAAgB,iBAC7B,EAAA,EAAA,OAAA,CAAyB,EAAe,CACtC,MAAO,CACL,QAAS,EAAA,KAAK,KAAK,EAAK,EACxB,SAAU,EAAA,KAAK,KAAK,EAAK,EACzB,KAAM,EAAA,KAAK,OAAwB,EACnC,MAAO,EAAA,KAAK,OAAO,CACrB,EACA,MAAM,EAAO,CACX,IAAM,MAAoB,EAAM,KAAK,QAAU,YAAc,EAAM,KAAK,QAAU,QAC5E,MAAkB,EAAY,GAAK,EAAM,QAAQ,MAqBvD,OAAO,EAAY,EACf,EAAA,IAAI;;yBAdgB,CACtB,IAAM,EAAO,EAAM,KAAK,MAExB,MAAO,CACL,OACA,IAAS,WAAa,cAAgB,GACtC,IAAS,QAAU,WAAa,GAChC,EAAU,EAAI,aAAe,EAC/B,CAAC,CACE,OAAO,OAAO,CAAC,CACf,KAAK,GAAG,CACb,EAK2B;;wBAtBrB,EAAM,KAAK,QAAU,WAAmB,mBAExC,EAAM,KAAK,QAAU,QAAgB,gBAElC,WAoBgB;gCACK,OAAO,EAAU,CAAC,EAAE;6BACzB,EAAM,SAAS;;;;;UAMpC,EAAA,IAAI;2EAC+D,EAAM,SAAS;;;;SAKxF,EACA,OAAQ,CAAC,EAAA,gBAAiB,EAAA,OAAc,CAC1C,CAAC,EAgBD,IAAa,EAAgB,sBAC7B,EAAA,EAAA,OAAA,CAAO,EAAe,CACpB,OAAQ,CACN,MAAO,GAAA,IAAI,EACb,EACA,OAAQ,CAAC,EAAA,OAAmB,CAC9B,CAAC,EAID,IAAM,EAAuB,GAC3B,IAAU,YAAc,IAAU,QAE9B,EAAqB,GACzB,GAAS,KAAO,IAAA,GAAY,IAAU,IAAM,IAAU,OAwC3C,EAAW,YACxB,EAAA,EAAA,OAAA,CAAqB,EAAU,CAC7B,MAAO,CACL,GAAG,EAAA,cACH,GAAG,EAAA,iBACH,eAAgB,EAAA,KAAK,KAAK,EAAK,EAC/B,KAAM,CAAE,QAAS,IAAA,GAAkC,MAAO,CAAkB,EAC5E,UAAW,EAAA,KAAK,MACd,CAAC,SAAU,eAAgB,aAAc,MAAO,YAAa,SAAS,EACtE,cACF,CACF,EACA,MAAM,EAAO,CACX,IAAM,GAAA,EAAK,EAAA,QAAA,CAAQ,EACb,GAAA,EAAO,EAAA,QAAA,CAAuB,EAC9B,GAAA,EAAQ,EAAA,SAAA,CAAS,EACjB,EAAQ,EAAA,YAER,GAAA,EAAS,EAAA,SAAA,CAAS,MAAM,EACxB,GAAA,EAAa,EAAA,SAAA,KAAe,EAAQ,EAAM,SAAS,KAAM,EACzD,EAAc,EAAA,gBAAgB,EAAA,SAAS,EACzC,EAAgC,KAChC,EAA8B,KAC9B,EAAsC,KAG1C,SAAS,GAA0B,CACjC,OAAO,MAAM,KAAK,EAAG,iBAA8B,+BAA+B,CAAC,CACrF,CAEA,SAAS,EAAiB,EAA0D,CAGlF,OAFK,EAEE,EAAK,YAAY,cAA2B,oBAAoB,GAAK,EAF1D,IAGpB,CAEA,SAAS,GAA8B,CAGrC,OAFc,EAEP,CAAA,CAAM,UAAW,GAAS,CAC/B,IAAM,EAAY,EAAiB,CAAI,EAEvC,OAAO,IAAS,SAAS,eAAiB,IAAc,SAAS,aACnE,CAAC,CACH,CAEA,IAAM,GAAA,EAAe,EAAA,OAAA,CAAO,EAAK,EAC7B,EAAuC,KACrC,EAAa,EAAA,yBAAyB,CAC1C,gBAAmB,EACnB,iBAAqB,EAAM,UAAU,OAAS,eAC9C,iBAAoB,EACpB,WAAY,GACZ,SAAU,EACV,QAAS,CACX,CAAC,EACK,EAAO,EAAA,kBAA+B,CAC1C,UAAA,EAAU,EAAA,SAAA,KAAe,CAAC,EAAa,KAAK,EAClC,WACV,eAAiB,GAAS,EAAK,aAAa,UAAU,EACtD,YAAa,CAAE,UAAW,CACxB,EAAiB,CAAI,CAAC,EAAE,MAAM,CAChC,EACA,OAAQ,CACV,CAAC,EAEK,GAAS,EAA8B,eAAgB,EAAqB,KAAe,CAC1F,EAAa,QAElB,EAAa,MAAQ,GACrB,EAAK,MAAM,EACX,IAAkB,EAClB,EAAkB,KAEd,IAAoB,EAAA,EAAA,aAAA,KAAmB,CAAS,EAEpD,EAAK,cAAe,CAAE,KAAM,GAAO,QAAO,CAAC,EAC7C,EAEM,GAAQ,EAA4B,iBAAyB,CAC7D,EAAW,OAAS,EAAa,QAErC,EAAa,MAAQ,GACrB,EAAW,OAAO,EAClB,EAAkB,EAAW,kBAAkB,GAAK,KACpD,EAAK,cAAe,CAAE,KAAM,GAAM,QAAO,CAAC,EAC5C,EAEM,MAAqB,CACrB,EAAa,MAAO,EAAM,SAAS,EAClC,EAAK,OAAO,CACnB,EAEA,EAAA,8BAA8B,CAC5B,eAAkB,CAAC,EAAI,CAAO,EAC9B,aAAgB,EAAa,MAC7B,cAAiB,EAAM,cAAc,EACrC,OAAQ,CACV,CAAC,EAED,IAAI,EAAc,IAElB,EAAA,EAAA,MAAA,CACE,EAAM,KACL,GAAU,CACL,IAAU,IAAA,GACP,EAGH,EAAM,cAAc,EAFhB,EAAM,eAAe,CAAC,OAAO,EAAK,cAAc,EAI7C,EACT,EAAK,cAAc,EAEnB,EAAM,cAAc,EAGtB,EAAc,EAChB,EACA,CAAE,UAAW,EAAK,CACpB,EACA,EAAY,iBACV,YACM,CACC,EAAa,QAElB,EAAa,MAAQ,GACrB,EAAK,MAAM,EACX,IAAkB,EAClB,EAAkB,KACpB,EACA,CAAE,KAAM,EAAK,CACf,EAEA,IAAM,EAAgB,GAA4B,CAChD,IAAM,EAAO,EAAK,aAAa,MAAM,EAC/B,EAAc,EAAoB,CAAI,EAE5C,GAAI,IAAS,WACX,EAAK,gBAAgB,UAAW,CAAC,EAAK,aAAa,SAAS,CAAC,OACxD,GAAI,IAAS,QAClB,IAAK,IAAM,KAAS,EAAG,iBAA8B,6BAA6B,EAChF,EAAM,gBAAgB,UAAW,IAAU,CAAI,EAInD,IAAM,EAAQ,EAAK,aAAa,OAAO,GAAK,GACtC,EAAU,EAAc,EAAK,aAAa,SAAS,EAAI,IAAA,GAE7D,EAAK,SAAU,CAAE,UAAS,OAAM,CAAC,EAE5B,GACH,EAAM,cAAc,CAExB,EAEM,EAAwB,EAAA,kBAAkB,CAC9C,KAAM,CAAC,QAAS,IAAK,WAAW,EAChC,YAAe,CACb,EAAK,UAAU,EACf,0BAA4B,EAAK,IAAI,CAAC,CAAC,CACzC,CACF,CAAC,EAEK,EAAmC,EAAA,kBAAkB,CACzD,YAAe,CACb,IAAM,EAAU,EAAK,cAAc,EAE/B,GAAS,EAAa,CAAO,CACnC,CACF,CAAC,EAGD,SAAS,EAAkB,EAAkB,CAC3C,GAAI,EAAW,MAAO,OAKtB,GAAI,CAHS,EAAa,MAGf,CACT,EAAsB,cAAc,CAAC,EAErC,MACF,CAEA,IAAM,EAAsB,EAAoB,EAIhD,GAFI,GAAuB,GAAG,EAAK,IAAI,CAAmB,EAEtD,EAAE,MAAQ,SAAU,CACtB,EAAE,eAAe,EACjB,EAAM,QAAQ,EAEd,MACF,CAEI,MAAK,cAAc,CAAC,EAGxB,IAAI,EAAE,MAAQ,KAAO,EAAE,MAAQ,QAAS,CACtC,EAAiC,cAAc,CAAC,EAEhD,MACF,CAEI,EAAE,MAAQ,OACZ,EAAM,cAAc,CAHtB,CAKF,EAGA,EAAA,EAAA,KAAA,CAAK,CACH,GAAI,CACF,MAAQ,GAAkB,CACxB,IAAM,EAAO,EAAE,aAAa,EAE5B,GAAI,CAAC,EAAa,MAAO,OAKzB,IAAM,EAHe,EAAK,KACvB,GAA8B,aAAgB,aAAe,EAAK,UAAY,eAEpE,GAAiB,EAAE,QAA+B,QAAqB,eAAe,GAAK,KAEnG,GAAQ,GAAK,aAAa,UAAU,GAEzC,EAAa,CAAI,CACnB,CACF,CACF,CAAC,EAED,MAAY,CACV,IAAM,EAAO,EAAa,MAErB,GAEL,EAAQ,gBAAgB,YAAa,CAAI,CAC3C,CAAC,EAED,SAAS,GAAiB,CAQxB,GAPA,IAAiB,EACjB,EAAiB,KAIjB,EAFiB,EAAM,SAAS,SAAS,CAAC,CAAC,QAEnB,IAAkC,KAEtD,CAAC,EAAW,OAEhB,IAAM,EAA8B,CAAC,EAC/B,GAAA,EAAa,EAAA,KAAA,CACjB,CACE,KAAM,CACJ,oBAAuB,EACvB,oBAAuB,EAAW,MAClC,oBAAuB,OAAO,EAAa,KAAK,EAChD,gBAAiB,MACnB,CACF,EACA,CAAE,OAAQ,CAAU,CACtB,EAEM,EAAkB,GAAsB,CAC5C,EAAM,gBAAgB,EAElB,GAAW,OAEf,EAAO,CACT,EACM,EAAoB,GAAyB,CACjD,EAAkB,CAAK,CACzB,EAEA,EAAU,iBAAiB,QAAS,CAAc,EAClD,EAAU,iBAAiB,UAAW,CAAgB,EACtD,EAAS,SAAW,GAAW,oBAAoB,QAAS,CAAc,CAAC,EAC3E,EAAS,SAAW,GAAW,oBAAoB,UAAW,CAAgB,CAAC,EAE/E,MAAuB,CACrB,EAAW,EAEX,IAAK,IAAM,KAAW,EAAU,EAAQ,CAC1C,CACF,CAaA,OAXA,EAAA,EAAA,MAAA,CAAY,EAAM,SAAS,SAAS,EAAG,EAAgB,CAAE,UAAW,EAAK,CAAC,GAE1E,EAAA,EAAA,UAAA,MACE,EAAe,MAEF,CACX,IAAiB,EACjB,EAAiB,IACnB,EACD,EAEM,EAAA,IAAI;;;;;cAKD,EAAO;;;oBAGD,EAAkB;eACtB,GAA2B,CACjC,EAAU,EACV,GAAS,gBAAgB,YAAa,EAAa,KAAK,CAC1D,EAAE;;;KAIR,EACA,OAAQ,CAAC,EAAA,QAAiB,EAAA,iBAAiB,EAAA,gBAAgB,EAAG,EAAA,iBAAiB,CACjF,CAAC"}
package/dist/menu.js CHANGED
@@ -10,7 +10,7 @@ import { MENU_SIZE_PRESET as u } from "./shared/size-presets.js";
10
10
  import d from "./overlay/menu/menu.css.js";
11
11
  import f from "./overlay/menu/menu-item.css.js";
12
12
  import p from "./overlay/menu/menu-separator.css.js";
13
- import { bind as m, createStableId as h, define as g, getHost as _, html as v, onCleanup as y, onMounted as b, prop as x, useEmit as S, useSlots as C, watchEffect as w } from "@vielzeug/ore";
13
+ import { bind as m, createId as h, define as g, getHost as _, html as v, onCleanup as y, onMounted as b, prop as x, useEmit as S, useSlots as C, watchEffect as w } from "@vielzeug/ore";
14
14
  import { computed as T, signal as E, watch as D } from "@vielzeug/ripple";
15
15
  import { restoreFocus as O } from "@vielzeug/focus";
16
16
  //#region src/overlay/menu/menu.ts
@@ -184,11 +184,11 @@ g(N, {
184
184
  });
185
185
  function G() {
186
186
  if (x?.(), x = null, p = c.elements("trigger").value?.[0] ?? null, !p) return;
187
- let e = [], t = m({ aria: {
188
- controls: () => u,
189
- disabled: () => d.value,
190
- expanded: () => String(N.value),
191
- haspopup: "menu"
187
+ let e = [], t = m({ attr: {
188
+ "aria-controls": () => u,
189
+ "aria-disabled": () => d.value,
190
+ "aria-expanded": () => String(N.value),
191
+ "aria-haspopup": "menu"
192
192
  } }, { target: p }), n = (e) => {
193
193
  e.stopPropagation(), !d.value && z();
194
194
  }, r = (e) => {
package/dist/menu.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"menu.js","names":[],"sources":["../src/overlay/menu/menu.ts"],"sourcesContent":["import { restoreFocus } from '@vielzeug/focus';\nimport type { Placement } from '@vielzeug/orbit';\nimport {\n bind,\n createStableId,\n define,\n getHost,\n html,\n onCleanup,\n onMounted,\n prop,\n useEmit,\n useSlots,\n watchEffect,\n} from '@vielzeug/ore';\nimport { computed, watch as rippleWatch, signal } from '@vielzeug/ripple';\nimport {\n createDropdownPositioner,\n createInteraction,\n createListControl,\n createOutsidePointerDismissal,\n type DropdownCloseReason,\n lifecycleSignal,\n type OverlayOpenChangeDetail,\n type OverlayOpenReason,\n} from '../../core';\nimport { disablableBundle, MENU_SIZE_PRESET, sizableBundle } from '../../shared';\nimport { colorThemeMixin, forcedColorsMixin, sizeVariantMixin } from '../../styles';\nimport type { ComponentSize } from '../../types';\nimport componentStyles from './menu.css?inline';\nimport menuItemStyles from './menu-item.css?inline';\nimport menuSeparatorStyles from './menu-separator.css?inline';\n\n// ── Types ─────────────────────────────────────────────────────────────\n\nexport interface MenuSelectDetail {\n checked?: boolean;\n value: string;\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: ({ item }) => {\n getItemFocusable(item)?.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 resolveTrigger();\n\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 { restoreFocus } from '@vielzeug/focus';\nimport type { Placement } from '@vielzeug/orbit';\nimport {\n bind,\n createId,\n define,\n getHost,\n html,\n onCleanup,\n onMounted,\n prop,\n useEmit,\n useSlots,\n watchEffect,\n} from '@vielzeug/ore';\nimport { computed, watch as rippleWatch, signal } from '@vielzeug/ripple';\nimport {\n createDropdownPositioner,\n createInteraction,\n createListControl,\n createOutsidePointerDismissal,\n type DropdownCloseReason,\n lifecycleSignal,\n type OverlayOpenChangeDetail,\n type OverlayOpenReason,\n} from '../../core';\nimport { disablableBundle, MENU_SIZE_PRESET, sizableBundle } from '../../shared';\nimport { colorThemeMixin, forcedColorsMixin, sizeVariantMixin } from '../../styles';\nimport type { ComponentSize } from '../../types';\nimport componentStyles from './menu.css?inline';\nimport menuItemStyles from './menu-item.css?inline';\nimport menuSeparatorStyles from './menu-separator.css?inline';\n\n// ── Types ─────────────────────────────────────────────────────────────\n\nexport interface MenuSelectDetail {\n checked?: boolean;\n value: string;\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 = createId('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: ({ item }) => {\n getItemFocusable(item)?.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 attr: {\n 'aria-controls': () => menuId,\n 'aria-disabled': () => isDisabled.value,\n 'aria-expanded': () => String(isOpenSignal.value),\n 'aria-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 resolveTrigger();\n\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/navbar.cjs CHANGED
@@ -1,4 +1,4 @@
1
- Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("./styles/mixins/accessibility.css.cjs"),t=require("./styles/mixins/shape.css.cjs"),n=require("./styles/mixins/theme.css.cjs"),r=require("./styles/mixins/variants.css.cjs"),i=require("./utils/link.cjs"),a=require("./layout/navbar/navbar.css.cjs");let o=require("@vielzeug/ore"),s=require("@vielzeug/ripple"),c=require("@vielzeug/sentinel");var l=(e,t,n,r)=>e?(e.addEventListener(t,n,r),()=>e.removeEventListener(t,n,r)):()=>{},u=e=>!(e instanceof HTMLElement)||e.tagName.includes(`-`)||e.childElementCount>0?!0:(e.textContent??``).trim().length>0,d=e=>{let t=String(e??``).trim();if(!t)return;let n=/max-width\s*:\s*([0-9]+(?:\.[0-9]+)?)px/i.exec(t);if(!n)return;let r=Number.parseFloat(n[1]);return Number.isFinite(r)?r:void 0},f=e=>{let t=e.parentElement;for(;t?.tagName.toLowerCase()===`ore-grid-item`;)t=t.parentElement;return t},p=e=>{let t=f(e)?.clientWidth??0;return t>0?t:e.offsetWidth},m=e=>{let t=e.parentElement;for(;t;){let e=window.getComputedStyle(t).overflowY;if(e===`auto`||e===`scroll`||e===`overlay`)return t;t=t.parentElement}return null},h=(0,o.createContext)(`NavbarContext`),g=`ore-navbar`;(0,o.define)(g,{props:{breakpoint:o.prop.string(`(max-width: 768px)`),color:o.prop.string(),"container-breakpoints":o.prop.bool(!1),elevation:o.prop.number(),floating:o.prop.bool(!1),label:o.prop.string(`Main navigation`),"menu-close-label":o.prop.string(`Close navigation menu`),"menu-open-label":o.prop.string(`Open navigation menu`),"mobile-sidebar":o.prop.string(),rounded:o.prop.string(),"scroll-threshold":o.prop.number(80),sticky:o.prop.bool(!1),variant:o.prop.string()},setup(e){let t=(0,o.getHost)(),n=(0,o.useEmit)(),r=(0,o.useSlots)(),i=r.has(`logo`),a=r.elements(`mobile-menu`),g=(0,s.signal)(!1),_=(0,s.signal)(null),v=(0,s.signal)(!1),y=(0,s.signal)(!1),b=(0,s.signal)(!1),x=(0,s.signal)(!1),S=(0,s.signal)(!1),C=(0,s.signal)(!1),w=(0,s.signal)(0),T=(0,s.signal)(!1),E=(0,s.signal)(!1),D=(0,s.signal)(d(e.breakpoint.value)),O=(0,s.signal)(!1),k=()=>{let n=String(e[`mobile-sidebar`].value??``).trim();if(!n)return null;let r=t.getRootNode();return(r instanceof ShadowRoot||r instanceof Document?r.querySelector(n):null)??document.querySelector(n)};(0,o.provide)(h,{closeMobileMenu:()=>M(),isMobile:(0,s.computed)(()=>b.value),mobileMenuOpen:(0,s.computed)(()=>x.value)});let A=()=>{if(e.floating.value&&e.sticky.value)return C.value?`sticky`:`floating`;if(e.floating.value)return`floating`;if(e.sticky.value)return`sticky`},j=e=>{let t=!!e;if(!g.value){let e=_.value??k();if(e){t?e.openMobile?.():e.closeMobile?.();return}}(!t||g.value)&&x.value!==t&&(x.value=t,n(`mobile-menu-change`,{open:t}))},M=()=>j(!1),N=()=>j(!0),P=()=>{if(!g.value){let e=_.value??k();if(e){typeof e.toggleMobile==`function`?e.toggleMobile():typeof e.openMobile==`function`&&typeof e.closeMobile==`function`&&(e.hasAttribute(`data-mobile-open`)?e.closeMobile():e.openMobile());return}}j(!x.value)},F=()=>{let t=(_.value&&!g.value?v.value:!1)||T.value||!!e[`container-breakpoints`].value&&E.value;b.value=t,t||M()},I=e=>e?e.scrollTop||0:window.scrollY||document.documentElement.scrollTop||0,L=e=>{w.value=I(e)},R=(t=null)=>{if(!(e.floating.value&&e.sticky.value)){C.value&&=!1;return}let n=Math.max(0,Number(e[`scroll-threshold`].value)||0),r=I(t)-w.value;C.value=r>n};return(0,o.bind)({attr:{"data-mobile":()=>b.value?!0:void 0,"data-mobile-open":()=>b.value&&x.value?!0:void 0,"data-mode":()=>A()??null,"data-mode-transitioning":()=>S.value?!0:void 0,"data-preview-mode":()=>O.value?!0:void 0,"data-scrolled":()=>e.floating.value&&e.sticky.value&&C.value?!0:void 0}}),(0,o.onMounted)(()=>{let n=t,r=m(t);n.closeMobileMenu=M,n.openMobileMenu=N,n.toggleMobileMenu=P;let i=l(window,`scroll`,()=>{R(r)},{passive:!0}),h=r?l(r,`scroll`,()=>{R(r)},{passive:!0}):void 0,b=l(t,`keydown`,e=>{e.key===`Escape`&&x.value&&M()}),w,j,I,z,B=()=>{if(j?.(),j=void 0,_.value=null,v.value=!1,y.value=!1,!String(e[`mobile-sidebar`].value??``).trim())return;let n=k();if(!n){let e=t.getRootNode(),n=e instanceof Document||e instanceof ShadowRoot?e:document,r=new MutationObserver(()=>{k()&&B()});r.observe(n,{childList:!0,subtree:!0}),j=()=>r.disconnect();return}let r=e=>{let t=n.hasAttribute(`data-bottom-nav`),r=n.hasAttribute(`data-mobile-open`);v.value=t,y.value=e?.detail?e.detail.open:r,y.value&&!v.value&&(v.value=!0),F()},i=new MutationObserver(()=>{r()});r(),i.observe(n,{attributeFilter:[`data-bottom-nav`,`data-mobile-open`],attributes:!0}),n.addEventListener(`mobile-open-change`,r),j=()=>{i.disconnect(),n.removeEventListener(`mobile-open-change`,r)},_.value=n},V=()=>{S.value=!0,I!=null&&clearTimeout(I),I=setTimeout(()=>{S.value=!1,I=void 0},220)},H=(0,s.watch)((0,s.computed)(()=>e.floating.value&&e.sticky.value),e=>{if(!e){C.value&&=!1,S.value&&=!1,z=void 0,I!=null&&(clearTimeout(I),I=void 0);return}L(r),R(r),z=A()},{immediate:!0}),U=(0,s.watch)(e[`mobile-sidebar`],()=>{B()},{immediate:!0}),W=(0,s.watch)((0,s.computed)(()=>A()),t=>{if(!(e.floating.value&&e.sticky.value)){z=t??void 0;return}let n=t??void 0;z&&n&&z!==n&&V(),z=n},{immediate:!0}),G=(0,s.watch)(g,e=>{!e&&x.value&&M()},{immediate:!0}),K=()=>{g.value=a.value.some(u)},q=(0,s.watch)(a,K,{immediate:!0}),J=new MutationObserver(()=>{K()});J.observe(t,{childList:!0,subtree:!0}),(0,s.watch)(e.breakpoint,n=>{(0,s.untrack)(()=>{w?.(),w=void 0;let r=String(n??``).trim();D.value=d(r),T.value=!1;let i=p(t);if(E.value=i>0&&D.value!=null&&i<=D.value,F(),!(e[`container-breakpoints`].value&&D.value!=null)&&r)try{let e=(0,c.createMediaQuery)(r),t=e=>{e&&(T.value=e.matches,F())};t(e.value);let n=(0,s.watch)(e,t);w=()=>{n.dispose(),e.dispose()}}catch(e){if(!(e instanceof c.SentinelUnavailableError))throw e}})},{immediate:!0});let Y=typeof ResizeObserver==`function`?(()=>{let e=(0,c.createElementSize)(t);(0,o.onCleanup)(()=>e.dispose());let n=t.parentElement,r=f(t),i=n?(0,c.createElementSize)(n):void 0,a=r&&r!==n?(0,c.createElementSize)(r):void 0;return i&&(0,o.onCleanup)(()=>i.dispose()),a&&(0,o.onCleanup)(()=>a.dispose()),(0,s.watch)((0,s.computed)(()=>[e.value?.width,e.value?.height,i?.value?.width,i?.value?.height,a?.value?.width,a?.value?.height]),()=>{let e=p(t),n=f(t)?.clientWidth??0;E.value=e>0&&D.value!=null&&e<=D.value,O.value=n>0&&n<window.innerWidth,F()})})():void 0;return()=>{b?.(),i?.(),h?.(),H?.dispose(),W?.dispose(),G?.dispose(),q?.dispose(),U?.dispose(),J.disconnect(),w?.(),j?.(),Y?.dispose(),I!=null&&(clearTimeout(I),I=void 0)}}),o.html`
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("./styles/mixins/accessibility.css.cjs"),t=require("./styles/mixins/shape.css.cjs"),n=require("./styles/mixins/theme.css.cjs"),r=require("./styles/mixins/variants.css.cjs"),i=require("./utils/link.cjs"),a=require("./layout/navbar/navbar.css.cjs");let o=require("@vielzeug/ore"),s=require("@vielzeug/ripple"),c=require("@vielzeug/sentinel");var l=(e,t,n,r)=>e?(e.addEventListener(t,n,r),()=>e.removeEventListener(t,n,r)):()=>{},u=e=>!(e instanceof HTMLElement)||e.tagName.includes(`-`)||e.childElementCount>0?!0:(e.textContent??``).trim().length>0,d=e=>{let t=String(e??``).trim();if(!t)return;let n=/max-width\s*:\s*([0-9]+(?:\.[0-9]+)?)px/i.exec(t);if(!n)return;let r=Number.parseFloat(n[1]);return Number.isFinite(r)?r:void 0},f=e=>{let t=e.parentElement;for(;t?.tagName.toLowerCase()===`ore-grid-item`;)t=t.parentElement;return t},p=e=>{let t=f(e)?.clientWidth??0;return t>0?t:e.offsetWidth},m=e=>{let t=e.parentElement;for(;t;){let e=window.getComputedStyle(t).overflowY;if(e===`auto`||e===`scroll`||e===`overlay`)return t;t=t.parentElement}return null},h=(0,o.createContext)(`NavbarContext`),g=`ore-navbar`;(0,o.define)(g,{props:{breakpoint:o.prop.string(`(max-width: 768px)`),color:o.prop.string(),"container-breakpoints":o.prop.bool(!1),elevation:o.prop.number(),floating:o.prop.bool(!1),label:o.prop.string(`Main navigation`),"menu-close-label":o.prop.string(`Close navigation menu`),"menu-open-label":o.prop.string(`Open navigation menu`),"mobile-sidebar":o.prop.string(),rounded:o.prop.string(),"scroll-threshold":o.prop.number(80),sticky:o.prop.bool(!1),variant:o.prop.string()},setup(e){let t=(0,o.getHost)(),n=(0,o.useEmit)(),r=(0,o.useSlots)(),i=r.has(`logo`),a=r.elements(`mobile-menu`),g=(0,s.signal)(!1),_=(0,s.signal)(null),v=(0,s.signal)(!1),y=(0,s.signal)(!1),b=(0,s.signal)(!1),x=(0,s.signal)(!1),S=(0,s.signal)(!1),C=(0,s.signal)(!1),w=(0,s.signal)(0),T=(0,s.signal)(!1),E=(0,s.signal)(!1),D=(0,s.signal)(d(e.breakpoint.value)),O=(0,s.signal)(!1),k=()=>{let n=String(e[`mobile-sidebar`].value??``).trim();if(!n)return null;let r=t.getRootNode();return(r instanceof ShadowRoot||r instanceof Document?r.querySelector(n):null)??document.querySelector(n)};(0,o.provide)(h,{closeMobileMenu:()=>M(),isMobile:(0,s.computed)(()=>b.value),mobileMenuOpen:(0,s.computed)(()=>x.value)});let A=()=>{if(e.floating.value&&e.sticky.value)return C.value?`sticky`:`floating`;if(e.floating.value)return`floating`;if(e.sticky.value)return`sticky`},j=e=>{let t=!!e;if(!g.value){let e=_.value??k();if(e){t?e.openMobile?.():e.closeMobile?.();return}}(!t||g.value)&&x.value!==t&&(x.value=t,n(`mobile-menu-change`,{open:t}))},M=()=>j(!1),N=()=>j(!0),P=()=>{if(!g.value){let e=_.value??k();if(e){typeof e.toggleMobile==`function`?e.toggleMobile():typeof e.openMobile==`function`&&typeof e.closeMobile==`function`&&(e.hasAttribute(`data-mobile-open`)?e.closeMobile():e.openMobile());return}}j(!x.value)},F=()=>{let t=(_.value&&!g.value?v.value:!1)||T.value||!!e[`container-breakpoints`].value&&E.value;b.value=t,t||M()},I=e=>e?e.scrollTop||0:window.scrollY||document.documentElement.scrollTop||0,L=e=>{w.value=I(e)},R=(t=null)=>{if(!(e.floating.value&&e.sticky.value)){C.value&&=!1;return}let n=Math.max(0,Number(e[`scroll-threshold`].value)||0),r=I(t)-w.value;C.value=r>n};return(0,o.bind)({attr:{"data-mobile":()=>b.value?!0:void 0,"data-mobile-open":()=>b.value&&x.value?!0:void 0,"data-mode":()=>A()??null,"data-mode-transitioning":()=>S.value?!0:void 0,"data-preview-mode":()=>O.value?!0:void 0,"data-scrolled":()=>e.floating.value&&e.sticky.value&&C.value?!0:void 0}}),(0,o.onMounted)(()=>{let n=t,r=m(t);n.closeMobileMenu=M,n.openMobileMenu=N,n.toggleMobileMenu=P;let i=l(window,`scroll`,()=>{R(r)},{passive:!0}),h=r?l(r,`scroll`,()=>{R(r)},{passive:!0}):void 0,b=l(t,`keydown`,e=>{e.key===`Escape`&&x.value&&M()}),w,j,I,z,B=()=>{if(j?.(),j=void 0,_.value=null,v.value=!1,y.value=!1,!String(e[`mobile-sidebar`].value??``).trim())return;let n=k();if(!n){let e=t.getRootNode(),n=e instanceof Document||e instanceof ShadowRoot?e:document,r=new MutationObserver(()=>{k()&&B()});r.observe(n,{childList:!0,subtree:!0}),j=()=>r.disconnect();return}let r=e=>{let t=n.hasAttribute(`data-bottom-nav`),r=n.hasAttribute(`data-mobile-open`);v.value=t,y.value=e?.detail?e.detail.open:r,y.value&&!v.value&&(v.value=!0),F()},i=new MutationObserver(()=>{r()});r(),i.observe(n,{attributeFilter:[`data-bottom-nav`,`data-mobile-open`],attributes:!0}),n.addEventListener(`mobile-open-change`,r),j=()=>{i.disconnect(),n.removeEventListener(`mobile-open-change`,r)},_.value=n},V=()=>{S.value=!0,I!=null&&clearTimeout(I),I=setTimeout(()=>{S.value=!1,I=void 0},220)},H=(0,s.watch)((0,s.computed)(()=>e.floating.value&&e.sticky.value),e=>{if(!e){C.value&&=!1,S.value&&=!1,z=void 0,I!=null&&(clearTimeout(I),I=void 0);return}L(r),R(r),z=A()},{immediate:!0}),U=(0,s.watch)(e[`mobile-sidebar`],()=>{B()},{immediate:!0}),W=(0,s.watch)((0,s.computed)(()=>A()),t=>{if(!(e.floating.value&&e.sticky.value)){z=t??void 0;return}let n=t??void 0;z&&n&&z!==n&&V(),z=n},{immediate:!0}),G=(0,s.watch)(g,e=>{!e&&x.value&&M()},{immediate:!0}),K=()=>{g.value=a.value.some(u)},q=(0,s.watch)(a,K,{immediate:!0}),J=new MutationObserver(()=>{K()});J.observe(t,{childList:!0,subtree:!0}),(0,s.watch)(e.breakpoint,n=>{(0,s.untrack)(()=>{w?.(),w=void 0;let r=String(n??``).trim();D.value=d(r),T.value=!1;let i=p(t);if(E.value=i>0&&D.value!=null&&i<=D.value,F(),!(e[`container-breakpoints`].value&&D.value!=null)&&r)try{let e=(0,c.createMediaQuery)(r),t=e=>{e&&(T.value=e.matches,F())};t(e.getSnapshot());let n=(0,s.watch)((0,s.fromSubscribable)(e,{signal:e.disposalSignal}),t);w=()=>{n.dispose(),e.dispose()}}catch(e){if(!(e instanceof c.SentinelUnavailableError))throw e}})},{immediate:!0});let Y=typeof ResizeObserver==`function`?(()=>{let e=(0,c.createElementSize)(t);(0,o.onCleanup)(()=>e.dispose());let n=(0,s.fromSubscribable)(e,{signal:e.disposalSignal}),r=t.parentElement,i=f(t),a=r?(0,c.createElementSize)(r):void 0,l=i&&i!==r?(0,c.createElementSize)(i):void 0;a&&(0,o.onCleanup)(()=>a.dispose()),l&&(0,o.onCleanup)(()=>l.dispose());let u=a?(0,s.fromSubscribable)(a,{signal:a.disposalSignal}):void 0,d=l?(0,s.fromSubscribable)(l,{signal:l.disposalSignal}):void 0;return(0,s.watch)((0,s.computed)(()=>[n.value?.width,n.value?.height,u?.value?.width,u?.value?.height,d?.value?.width,d?.value?.height]),()=>{let e=p(t),n=f(t)?.clientWidth??0;E.value=e>0&&D.value!=null&&e<=D.value,O.value=n>0&&n<window.innerWidth,F()})})():void 0;return()=>{b?.(),i?.(),h?.(),H?.dispose(),W?.dispose(),G?.dispose(),q?.dispose(),U?.dispose(),J.disconnect(),w?.(),j?.(),Y?.dispose(),I!=null&&(clearTimeout(I),I=void 0)}}),o.html`
2
2
  <nav part="nav" aria-label="${e.label}">
3
3
  <div class="navbar" part="bar">
4
4
  <div class="navbar-logo" part="logo" ?hidden=${()=>!i.value}>