@vielzeug/refine 2.0.3 → 2.1.2

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 (521) hide show
  1. package/dist/accordion-item.cjs +1 -1
  2. package/dist/accordion-item.cjs.map +1 -1
  3. package/dist/accordion-item.js +1 -1
  4. package/dist/accordion-item.js.map +1 -1
  5. package/dist/accordion.cjs +1 -1
  6. package/dist/accordion.cjs.map +1 -1
  7. package/dist/accordion.js +1 -1
  8. package/dist/accordion.js.map +1 -1
  9. package/dist/alert.cjs.map +1 -1
  10. package/dist/alert.js.map +1 -1
  11. package/dist/async.cjs.map +1 -1
  12. package/dist/async.js.map +1 -1
  13. package/dist/avatar-group.cjs.map +1 -1
  14. package/dist/avatar-group.js.map +1 -1
  15. package/dist/avatar.cjs +6 -6
  16. package/dist/avatar.cjs.map +1 -1
  17. package/dist/avatar.js +1 -2
  18. package/dist/avatar.js.map +1 -1
  19. package/dist/badge.cjs.map +1 -1
  20. package/dist/badge.js.map +1 -1
  21. package/dist/box.cjs.map +1 -1
  22. package/dist/box.js.map +1 -1
  23. package/dist/breadcrumb.cjs +3 -3
  24. package/dist/breadcrumb.cjs.map +1 -1
  25. package/dist/breadcrumb.js +4 -4
  26. package/dist/breadcrumb.js.map +1 -1
  27. package/dist/button-group.cjs +1 -1
  28. package/dist/button-group.cjs.map +1 -1
  29. package/dist/button-group.js +0 -1
  30. package/dist/button-group.js.map +1 -1
  31. package/dist/button.cjs.map +1 -1
  32. package/dist/button.js.map +1 -1
  33. package/dist/calendar.cjs.map +1 -1
  34. package/dist/calendar.js.map +1 -1
  35. package/dist/card.cjs +7 -7
  36. package/dist/card.cjs.map +1 -1
  37. package/dist/card.js +27 -27
  38. package/dist/card.js.map +1 -1
  39. package/dist/carousel.cjs +20 -20
  40. package/dist/carousel.cjs.map +1 -1
  41. package/dist/carousel.js +7 -8
  42. package/dist/carousel.js.map +1 -1
  43. package/dist/chat-message.cjs +10 -10
  44. package/dist/chat-message.cjs.map +1 -1
  45. package/dist/chat-message.js +1 -2
  46. package/dist/chat-message.js.map +1 -1
  47. package/dist/checkbox-group.cjs +7 -7
  48. package/dist/checkbox-group.cjs.map +1 -1
  49. package/dist/checkbox-group.js +26 -26
  50. package/dist/checkbox-group.js.map +1 -1
  51. package/dist/checkbox.cjs +2 -2
  52. package/dist/checkbox.cjs.map +1 -1
  53. package/dist/checkbox.js +33 -33
  54. package/dist/checkbox.js.map +1 -1
  55. package/dist/chip.cjs +16 -16
  56. package/dist/chip.cjs.map +1 -1
  57. package/dist/chip.js +1 -2
  58. package/dist/chip.js.map +1 -1
  59. package/dist/combobox.cjs +28 -28
  60. package/dist/combobox.cjs.map +1 -1
  61. package/dist/combobox.js +211 -211
  62. package/dist/combobox.js.map +1 -1
  63. package/dist/command-palette.cjs +21 -21
  64. package/dist/command-palette.cjs.map +1 -1
  65. package/dist/command-palette.js +27 -28
  66. package/dist/command-palette.js.map +1 -1
  67. package/dist/content/avatar/avatar.css.cjs +1 -1
  68. package/dist/content/avatar/avatar.css.js +1 -1
  69. package/dist/content/avatar/avatar.d.ts.map +1 -1
  70. package/dist/content/breadcrumb/breadcrumb.d.ts.map +1 -1
  71. package/dist/content/card/card.css.cjs +1 -1
  72. package/dist/content/card/card.css.cjs.map +1 -1
  73. package/dist/content/card/card.css.js +1 -1
  74. package/dist/content/card/card.css.js.map +1 -1
  75. package/dist/content/card/card.d.ts.map +1 -1
  76. package/dist/content/carousel/carousel-slide.cjs.map +1 -1
  77. package/dist/content/carousel/carousel-slide.js.map +1 -1
  78. package/dist/content/carousel/carousel.css.cjs +1 -1
  79. package/dist/content/carousel/carousel.css.cjs.map +1 -1
  80. package/dist/content/carousel/carousel.css.js +1 -1
  81. package/dist/content/carousel/carousel.css.js.map +1 -1
  82. package/dist/content/carousel/carousel.d.ts.map +1 -1
  83. package/dist/content/carousel/index.d.ts +1 -1
  84. package/dist/content/carousel/index.d.ts.map +1 -1
  85. package/dist/content/chat-message/chat-message.css.cjs +1 -1
  86. package/dist/content/chat-message/chat-message.css.js +1 -1
  87. package/dist/content/chat-message/chat-message.d.ts.map +1 -1
  88. package/dist/content/code-window/code-window.css.cjs +1 -1
  89. package/dist/content/code-window/code-window.css.js +1 -1
  90. package/dist/content/copy-command/copy-command.css.cjs +1 -1
  91. package/dist/content/copy-command/copy-command.css.js +1 -1
  92. package/dist/content/copy-command/copy-command.d.ts.map +1 -1
  93. package/dist/content/index.d.ts +22 -22
  94. package/dist/content/index.d.ts.map +1 -1
  95. package/dist/content/list/_list-item-reveal.cjs.map +1 -1
  96. package/dist/content/list/_list-item-reveal.d.ts +1 -1
  97. package/dist/content/list/_list-item-reveal.d.ts.map +1 -1
  98. package/dist/content/list/_list-item-reveal.js.map +1 -1
  99. package/dist/content/list/list-item.css.cjs +1 -1
  100. package/dist/content/list/list-item.css.cjs.map +1 -1
  101. package/dist/content/list/list-item.css.js +1 -1
  102. package/dist/content/list/list-item.css.js.map +1 -1
  103. package/dist/content/list/list.d.ts.map +1 -1
  104. package/dist/content/marquee/marquee.css.cjs +1 -1
  105. package/dist/content/marquee/marquee.css.js +1 -1
  106. package/dist/content/pagination/pagination.css.cjs +1 -1
  107. package/dist/content/pagination/pagination.css.js +1 -1
  108. package/dist/content/pagination/pagination.d.ts.map +1 -1
  109. package/dist/content/separator/separator.css.cjs +1 -1
  110. package/dist/content/separator/separator.css.js +1 -1
  111. package/dist/content/separator/separator.d.ts.map +1 -1
  112. package/dist/content/stepper/step.css.cjs.map +1 -1
  113. package/dist/content/stepper/step.css.js.map +1 -1
  114. package/dist/content/stepper/stepper.d.ts.map +1 -1
  115. package/dist/content/table/table.css.cjs +1 -1
  116. package/dist/content/table/table.css.js +1 -1
  117. package/dist/content/text/text.css.cjs +1 -1
  118. package/dist/content/text/text.css.cjs.map +1 -1
  119. package/dist/content/text/text.css.js +1 -1
  120. package/dist/content/text/text.css.js.map +1 -1
  121. package/dist/content/text/text.d.ts +1 -1
  122. package/dist/content/text/text.d.ts.map +1 -1
  123. package/dist/copy-command.cjs.map +1 -1
  124. package/dist/copy-command.js.map +1 -1
  125. package/dist/core/checkable.cjs +1 -1
  126. package/dist/core/checkable.cjs.map +1 -1
  127. package/dist/core/checkable.d.ts.map +1 -1
  128. package/dist/core/checkable.js +4 -4
  129. package/dist/core/checkable.js.map +1 -1
  130. package/dist/core/choice-field.cjs +1 -1
  131. package/dist/core/choice-field.cjs.map +1 -1
  132. package/dist/core/choice-field.d.ts.map +1 -1
  133. package/dist/core/choice-field.js +1 -2
  134. package/dist/core/choice-field.js.map +1 -1
  135. package/dist/core/date-picker.cjs +1 -1
  136. package/dist/core/date-picker.cjs.map +1 -1
  137. package/dist/core/date-picker.d.ts.map +1 -1
  138. package/dist/core/date-picker.js +3 -3
  139. package/dist/core/date-picker.js.map +1 -1
  140. package/dist/core/index.d.ts +17 -17
  141. package/dist/core/index.d.ts.map +1 -1
  142. package/dist/core/option-list.cjs +1 -1
  143. package/dist/core/option-list.cjs.map +1 -1
  144. package/dist/core/option-list.d.ts.map +1 -1
  145. package/dist/core/option-list.js +4 -4
  146. package/dist/core/option-list.js.map +1 -1
  147. package/dist/core/overlay.cjs.map +1 -1
  148. package/dist/core/overlay.d.ts +2 -2
  149. package/dist/core/overlay.d.ts.map +1 -1
  150. package/dist/core/overlay.js.map +1 -1
  151. package/dist/core/positioner.cjs +1 -1
  152. package/dist/core/positioner.cjs.map +1 -1
  153. package/dist/core/positioner.d.ts +6 -1
  154. package/dist/core/positioner.d.ts.map +1 -1
  155. package/dist/core/positioner.js +11 -11
  156. package/dist/core/positioner.js.map +1 -1
  157. package/dist/core/ref-callback.cjs +1 -1
  158. package/dist/core/ref-callback.cjs.map +1 -1
  159. package/dist/core/ref-callback.d.ts.map +1 -1
  160. package/dist/core/ref-callback.js +1 -1
  161. package/dist/core/ref-callback.js.map +1 -1
  162. package/dist/core/signals.cjs +1 -1
  163. package/dist/core/signals.cjs.map +1 -1
  164. package/dist/core/signals.d.ts.map +1 -1
  165. package/dist/core/signals.js +1 -2
  166. package/dist/core/signals.js.map +1 -1
  167. package/dist/core/slider.cjs.map +1 -1
  168. package/dist/core/slider.d.ts.map +1 -1
  169. package/dist/core/slider.js.map +1 -1
  170. package/dist/core/spinner.cjs.map +1 -1
  171. package/dist/core/spinner.d.ts.map +1 -1
  172. package/dist/core/spinner.js.map +1 -1
  173. package/dist/core/text-field.cjs +1 -1
  174. package/dist/core/text-field.cjs.map +1 -1
  175. package/dist/core/text-field.js +1 -1
  176. package/dist/core/text-field.js.map +1 -1
  177. package/dist/custom-elements.json +4926 -4678
  178. package/dist/datagrid.cjs +114 -114
  179. package/dist/datagrid.cjs.map +1 -1
  180. package/dist/datagrid.js +42 -43
  181. package/dist/datagrid.js.map +1 -1
  182. package/dist/date-picker.cjs.map +1 -1
  183. package/dist/date-picker.js.map +1 -1
  184. package/dist/dialog.cjs.map +1 -1
  185. package/dist/dialog.js.map +1 -1
  186. package/dist/disclosure/accordion/accordion.d.ts.map +1 -1
  187. package/dist/disclosure/accordion-item/accordion-item.css.cjs +1 -1
  188. package/dist/disclosure/accordion-item/accordion-item.css.cjs.map +1 -1
  189. package/dist/disclosure/accordion-item/accordion-item.css.js +1 -1
  190. package/dist/disclosure/accordion-item/accordion-item.css.js.map +1 -1
  191. package/dist/disclosure/index.d.ts +6 -6
  192. package/dist/disclosure/index.d.ts.map +1 -1
  193. package/dist/disclosure/tab-item/tab-item.css.cjs.map +1 -1
  194. package/dist/disclosure/tab-item/tab-item.css.js.map +1 -1
  195. package/dist/disclosure/tab-item/tab-item.d.ts.map +1 -1
  196. package/dist/disclosure/tabs/tabs.css.cjs +1 -1
  197. package/dist/disclosure/tabs/tabs.css.cjs.map +1 -1
  198. package/dist/disclosure/tabs/tabs.css.js +1 -1
  199. package/dist/disclosure/tabs/tabs.css.js.map +1 -1
  200. package/dist/disclosure/tabs/tabs.d.ts.map +1 -1
  201. package/dist/drawer.cjs +5 -5
  202. package/dist/drawer.cjs.map +1 -1
  203. package/dist/drawer.js +26 -26
  204. package/dist/drawer.js.map +1 -1
  205. package/dist/feedback/alert/alert.css.cjs +1 -1
  206. package/dist/feedback/alert/alert.css.js +1 -1
  207. package/dist/feedback/async/async.d.ts +1 -1
  208. package/dist/feedback/async/async.d.ts.map +1 -1
  209. package/dist/feedback/badge/badge.css.cjs +1 -1
  210. package/dist/feedback/badge/badge.css.js +1 -1
  211. package/dist/feedback/badge/badge.d.ts.map +1 -1
  212. package/dist/feedback/chip/chip.css.cjs.map +1 -1
  213. package/dist/feedback/chip/chip.css.js.map +1 -1
  214. package/dist/feedback/chip/chip.d.ts.map +1 -1
  215. package/dist/feedback/index.d.ts +12 -12
  216. package/dist/feedback/index.d.ts.map +1 -1
  217. package/dist/feedback/progress/progress.d.ts.map +1 -1
  218. package/dist/feedback/skeleton/skeleton.d.ts.map +1 -1
  219. package/dist/feedback/toast/index.d.ts +1 -1
  220. package/dist/feedback/toast/index.d.ts.map +1 -1
  221. package/dist/feedback/toast/toast.css.cjs +1 -1
  222. package/dist/feedback/toast/toast.css.cjs.map +1 -1
  223. package/dist/feedback/toast/toast.css.js +1 -1
  224. package/dist/feedback/toast/toast.css.js.map +1 -1
  225. package/dist/feedback/toast/toast.d.ts +1 -1
  226. package/dist/feedback/toast/toast.d.ts.map +1 -1
  227. package/dist/feedback/typing-indicator/typing-indicator.d.ts.map +1 -1
  228. package/dist/file-input.cjs +67 -67
  229. package/dist/file-input.cjs.map +1 -1
  230. package/dist/file-input.js +129 -130
  231. package/dist/file-input.js.map +1 -1
  232. package/dist/frameworks/elements.d.ts +86 -0
  233. package/dist/frameworks/react.d.ts +18 -0
  234. package/dist/frameworks/vue.d.ts +16 -0
  235. package/dist/grid.cjs.map +1 -1
  236. package/dist/grid.js.map +1 -1
  237. package/dist/icon.cjs.map +1 -1
  238. package/dist/icon.js.map +1 -1
  239. package/dist/input.cjs +21 -21
  240. package/dist/input.cjs.map +1 -1
  241. package/dist/input.js +58 -58
  242. package/dist/input.js.map +1 -1
  243. package/dist/inputs/button/button.css.cjs +1 -1
  244. package/dist/inputs/button/button.css.cjs.map +1 -1
  245. package/dist/inputs/button/button.css.js +1 -1
  246. package/dist/inputs/button/button.css.js.map +1 -1
  247. package/dist/inputs/button/button.d.ts.map +1 -1
  248. package/dist/inputs/button-group/button-group.css.cjs.map +1 -1
  249. package/dist/inputs/button-group/button-group.css.js.map +1 -1
  250. package/dist/inputs/button-group/button-group.d.ts +1 -1
  251. package/dist/inputs/button-group/button-group.d.ts.map +1 -1
  252. package/dist/inputs/calendar/calendar.css.cjs +1 -1
  253. package/dist/inputs/calendar/calendar.css.cjs.map +1 -1
  254. package/dist/inputs/calendar/calendar.css.js +1 -1
  255. package/dist/inputs/calendar/calendar.css.js.map +1 -1
  256. package/dist/inputs/calendar/calendar.d.ts.map +1 -1
  257. package/dist/inputs/checkbox/checkbox.css.cjs +1 -1
  258. package/dist/inputs/checkbox/checkbox.css.js +1 -1
  259. package/dist/inputs/checkbox/checkbox.d.ts.map +1 -1
  260. package/dist/inputs/checkbox-group/checkbox-group.d.ts +1 -1
  261. package/dist/inputs/checkbox-group/checkbox-group.d.ts.map +1 -1
  262. package/dist/inputs/combobox/combobox.css.cjs +1 -1
  263. package/dist/inputs/combobox/combobox.css.js +1 -1
  264. package/dist/inputs/combobox/combobox.d.ts.map +1 -1
  265. package/dist/inputs/datagrid/datagrid-column.cjs.map +1 -1
  266. package/dist/inputs/datagrid/datagrid-column.d.ts.map +1 -1
  267. package/dist/inputs/datagrid/datagrid-column.js.map +1 -1
  268. package/dist/inputs/datagrid/datagrid-model.cjs +1 -1
  269. package/dist/inputs/datagrid/datagrid-model.cjs.map +1 -1
  270. package/dist/inputs/datagrid/datagrid-model.d.ts.map +1 -1
  271. package/dist/inputs/datagrid/datagrid-model.js +1 -2
  272. package/dist/inputs/datagrid/datagrid-model.js.map +1 -1
  273. package/dist/inputs/datagrid/datagrid.css.cjs +1 -1
  274. package/dist/inputs/datagrid/datagrid.css.cjs.map +1 -1
  275. package/dist/inputs/datagrid/datagrid.css.js +1 -1
  276. package/dist/inputs/datagrid/datagrid.css.js.map +1 -1
  277. package/dist/inputs/datagrid/datagrid.d.ts +1 -1
  278. package/dist/inputs/datagrid/datagrid.d.ts.map +1 -1
  279. package/dist/inputs/date-picker/date-picker.css.cjs +1 -1
  280. package/dist/inputs/date-picker/date-picker.css.cjs.map +1 -1
  281. package/dist/inputs/date-picker/date-picker.css.js +1 -1
  282. package/dist/inputs/date-picker/date-picker.css.js.map +1 -1
  283. package/dist/inputs/date-picker/date-picker.d.ts.map +1 -1
  284. package/dist/inputs/file-input/file-input-upload.cjs +1 -1
  285. package/dist/inputs/file-input/file-input-upload.cjs.map +1 -1
  286. package/dist/inputs/file-input/file-input-upload.d.ts.map +1 -1
  287. package/dist/inputs/file-input/file-input-upload.js +2 -3
  288. package/dist/inputs/file-input/file-input-upload.js.map +1 -1
  289. package/dist/inputs/file-input/file-input.css.cjs +1 -1
  290. package/dist/inputs/file-input/file-input.css.js +1 -1
  291. package/dist/inputs/file-input/file-input.d.ts.map +1 -1
  292. package/dist/inputs/index.d.ts +28 -28
  293. package/dist/inputs/index.d.ts.map +1 -1
  294. package/dist/inputs/input/input.css.cjs +1 -1
  295. package/dist/inputs/input/input.css.js +1 -1
  296. package/dist/inputs/input/input.d.ts.map +1 -1
  297. package/dist/inputs/message-composer/message-composer.css.cjs +1 -1
  298. package/dist/inputs/message-composer/message-composer.css.js +1 -1
  299. package/dist/inputs/message-composer/message-composer.d.ts +1 -1
  300. package/dist/inputs/message-composer/message-composer.d.ts.map +1 -1
  301. package/dist/inputs/number-input/number-input.d.ts.map +1 -1
  302. package/dist/inputs/otp-input/otp-input.d.ts.map +1 -1
  303. package/dist/inputs/radio/radio.css.cjs +1 -1
  304. package/dist/inputs/radio/radio.css.js +1 -1
  305. package/dist/inputs/radio/radio.d.ts.map +1 -1
  306. package/dist/inputs/radio-group/radio-group.d.ts +2 -2
  307. package/dist/inputs/radio-group/radio-group.d.ts.map +1 -1
  308. package/dist/inputs/rating/rating.d.ts.map +1 -1
  309. package/dist/inputs/select/select.css.cjs +1 -1
  310. package/dist/inputs/select/select.css.js +1 -1
  311. package/dist/inputs/select/select.d.ts.map +1 -1
  312. package/dist/inputs/shared/field-binding.cjs.map +1 -1
  313. package/dist/inputs/shared/field-binding.d.ts.map +1 -1
  314. package/dist/inputs/shared/field-binding.js.map +1 -1
  315. package/dist/inputs/shared/templates.cjs.map +1 -1
  316. package/dist/inputs/shared/templates.d.ts.map +1 -1
  317. package/dist/inputs/shared/templates.js.map +1 -1
  318. package/dist/inputs/slider/slider.d.ts.map +1 -1
  319. package/dist/inputs/switch/switch.css.cjs +1 -1
  320. package/dist/inputs/switch/switch.css.js +1 -1
  321. package/dist/inputs/switch/switch.d.ts.map +1 -1
  322. package/dist/inputs/textarea/textarea.css.cjs +1 -1
  323. package/dist/inputs/textarea/textarea.css.js +1 -1
  324. package/dist/inputs/textarea/textarea.d.ts.map +1 -1
  325. package/dist/inputs/time-picker/time-picker.css.cjs +1 -1
  326. package/dist/inputs/time-picker/time-picker.css.cjs.map +1 -1
  327. package/dist/inputs/time-picker/time-picker.css.js +1 -1
  328. package/dist/inputs/time-picker/time-picker.css.js.map +1 -1
  329. package/dist/inputs/time-picker/time-picker.d.ts.map +1 -1
  330. package/dist/layout/box/box.d.ts.map +1 -1
  331. package/dist/layout/grid/grid.d.ts.map +1 -1
  332. package/dist/layout/index.d.ts +6 -6
  333. package/dist/layout/index.d.ts.map +1 -1
  334. package/dist/layout/navbar/navbar.css.cjs +1 -1
  335. package/dist/layout/navbar/navbar.css.js +1 -1
  336. package/dist/layout/navbar/navbar.d.ts.map +1 -1
  337. package/dist/layout/sidebar/sidebar-group.css.cjs +1 -1
  338. package/dist/layout/sidebar/sidebar-group.css.cjs.map +1 -1
  339. package/dist/layout/sidebar/sidebar-group.css.js +1 -1
  340. package/dist/layout/sidebar/sidebar-group.css.js.map +1 -1
  341. package/dist/layout/sidebar/sidebar.css.cjs +1 -1
  342. package/dist/layout/sidebar/sidebar.css.cjs.map +1 -1
  343. package/dist/layout/sidebar/sidebar.css.js +1 -1
  344. package/dist/layout/sidebar/sidebar.css.js.map +1 -1
  345. package/dist/layout/sidebar/sidebar.d.ts.map +1 -1
  346. package/dist/list-item.cjs.map +1 -1
  347. package/dist/list-item.js.map +1 -1
  348. package/dist/list.cjs +2 -2
  349. package/dist/list.cjs.map +1 -1
  350. package/dist/list.js +15 -16
  351. package/dist/list.js.map +1 -1
  352. package/dist/marquee.cjs +1 -1
  353. package/dist/marquee.cjs.map +1 -1
  354. package/dist/marquee.js +1 -1
  355. package/dist/marquee.js.map +1 -1
  356. package/dist/menu.cjs +5 -5
  357. package/dist/menu.cjs.map +1 -1
  358. package/dist/menu.js +40 -41
  359. package/dist/menu.js.map +1 -1
  360. package/dist/message-composer.cjs +16 -16
  361. package/dist/message-composer.cjs.map +1 -1
  362. package/dist/message-composer.js +61 -61
  363. package/dist/message-composer.js.map +1 -1
  364. package/dist/navbar.cjs +9 -9
  365. package/dist/navbar.cjs.map +1 -1
  366. package/dist/navbar.js +1 -2
  367. package/dist/navbar.js.map +1 -1
  368. package/dist/navigation-menu.cjs +11 -0
  369. package/dist/navigation-menu.cjs.map +1 -0
  370. package/dist/navigation-menu.js +138 -0
  371. package/dist/navigation-menu.js.map +1 -0
  372. package/dist/number-input.cjs +24 -24
  373. package/dist/number-input.cjs.map +1 -1
  374. package/dist/number-input.js +41 -42
  375. package/dist/number-input.js.map +1 -1
  376. package/dist/otp-input.cjs +13 -13
  377. package/dist/otp-input.cjs.map +1 -1
  378. package/dist/otp-input.js +32 -33
  379. package/dist/otp-input.js.map +1 -1
  380. package/dist/overlay/command-palette/command-palette-items.cjs.map +1 -1
  381. package/dist/overlay/command-palette/command-palette-items.d.ts.map +1 -1
  382. package/dist/overlay/command-palette/command-palette-items.js.map +1 -1
  383. package/dist/overlay/command-palette/command-palette.css.cjs +1 -1
  384. package/dist/overlay/command-palette/command-palette.css.cjs.map +1 -1
  385. package/dist/overlay/command-palette/command-palette.css.js +1 -1
  386. package/dist/overlay/command-palette/command-palette.css.js.map +1 -1
  387. package/dist/overlay/command-palette/command-palette.d.ts.map +1 -1
  388. package/dist/overlay/dialog/dialog.css.cjs +1 -1
  389. package/dist/overlay/dialog/dialog.css.js +1 -1
  390. package/dist/overlay/dialog/dialog.d.ts.map +1 -1
  391. package/dist/overlay/drawer/drawer.css.cjs +1 -1
  392. package/dist/overlay/drawer/drawer.css.js +1 -1
  393. package/dist/overlay/drawer/drawer.d.ts +2 -2
  394. package/dist/overlay/drawer/drawer.d.ts.map +1 -1
  395. package/dist/overlay/index.d.ts +7 -5
  396. package/dist/overlay/index.d.ts.map +1 -1
  397. package/dist/overlay/menu/menu.css.cjs +1 -1
  398. package/dist/overlay/menu/menu.css.js +1 -1
  399. package/dist/overlay/menu/menu.d.ts +2 -2
  400. package/dist/overlay/menu/menu.d.ts.map +1 -1
  401. package/dist/overlay/navigation-menu/navigation-menu-item.css.cjs +2 -0
  402. package/dist/overlay/navigation-menu/navigation-menu-item.css.cjs.map +1 -0
  403. package/dist/overlay/navigation-menu/navigation-menu-item.css.js +6 -0
  404. package/dist/overlay/navigation-menu/navigation-menu-item.css.js.map +1 -0
  405. package/dist/overlay/navigation-menu/navigation-menu-panel.css.cjs +2 -0
  406. package/dist/overlay/navigation-menu/navigation-menu-panel.css.cjs.map +1 -0
  407. package/dist/overlay/navigation-menu/navigation-menu-panel.css.js +6 -0
  408. package/dist/overlay/navigation-menu/navigation-menu-panel.css.js.map +1 -0
  409. package/dist/overlay/navigation-menu/navigation-menu.css.cjs +2 -0
  410. package/dist/overlay/navigation-menu/navigation-menu.css.cjs.map +1 -0
  411. package/dist/overlay/navigation-menu/navigation-menu.css.js +6 -0
  412. package/dist/overlay/navigation-menu/navigation-menu.css.js.map +1 -0
  413. package/dist/overlay/navigation-menu/navigation-menu.d.ts +75 -0
  414. package/dist/overlay/navigation-menu/navigation-menu.d.ts.map +1 -0
  415. package/dist/overlay/popover/popover.d.ts +1 -1
  416. package/dist/overlay/popover/popover.d.ts.map +1 -1
  417. package/dist/overlay/shared/use-dialog.cjs +1 -1
  418. package/dist/overlay/shared/use-dialog.cjs.map +1 -1
  419. package/dist/overlay/shared/use-dialog.d.ts.map +1 -1
  420. package/dist/overlay/shared/use-dialog.js +4 -5
  421. package/dist/overlay/shared/use-dialog.js.map +1 -1
  422. package/dist/overlay/shared/use-floating-trigger.cjs +1 -1
  423. package/dist/overlay/shared/use-floating-trigger.cjs.map +1 -1
  424. package/dist/overlay/shared/use-floating-trigger.d.ts.map +1 -1
  425. package/dist/overlay/shared/use-floating-trigger.js +1 -2
  426. package/dist/overlay/shared/use-floating-trigger.js.map +1 -1
  427. package/dist/overlay/tooltip/tooltip.d.ts +1 -1
  428. package/dist/overlay/tooltip/tooltip.d.ts.map +1 -1
  429. package/dist/pagination.cjs.map +1 -1
  430. package/dist/pagination.js.map +1 -1
  431. package/dist/popover.cjs +1 -1
  432. package/dist/popover.cjs.map +1 -1
  433. package/dist/popover.js +0 -1
  434. package/dist/popover.js.map +1 -1
  435. package/dist/progress.cjs.map +1 -1
  436. package/dist/progress.js.map +1 -1
  437. package/dist/radio-group.cjs +5 -5
  438. package/dist/radio-group.cjs.map +1 -1
  439. package/dist/radio-group.js +26 -27
  440. package/dist/radio-group.js.map +1 -1
  441. package/dist/radio.cjs +2 -2
  442. package/dist/radio.cjs.map +1 -1
  443. package/dist/radio.js +41 -41
  444. package/dist/radio.js.map +1 -1
  445. package/dist/rating.cjs +4 -4
  446. package/dist/rating.cjs.map +1 -1
  447. package/dist/rating.js +36 -36
  448. package/dist/rating.js.map +1 -1
  449. package/dist/refine.cjs +692 -683
  450. package/dist/refine.cjs.map +1 -1
  451. package/dist/refine.iife.js +692 -683
  452. package/dist/refine.iife.js.map +1 -1
  453. package/dist/refine.js +743 -734
  454. package/dist/refine.js.map +1 -1
  455. package/dist/select.cjs +42 -42
  456. package/dist/select.cjs.map +1 -1
  457. package/dist/select.js +146 -147
  458. package/dist/select.js.map +1 -1
  459. package/dist/separator.cjs.map +1 -1
  460. package/dist/separator.js.map +1 -1
  461. package/dist/sidebar.cjs +17 -17
  462. package/dist/sidebar.cjs.map +1 -1
  463. package/dist/sidebar.js +7 -8
  464. package/dist/sidebar.js.map +1 -1
  465. package/dist/skeleton.cjs +3 -3
  466. package/dist/skeleton.cjs.map +1 -1
  467. package/dist/skeleton.js +1 -2
  468. package/dist/skeleton.js.map +1 -1
  469. package/dist/slider.cjs +12 -12
  470. package/dist/slider.cjs.map +1 -1
  471. package/dist/slider.js +54 -55
  472. package/dist/slider.js.map +1 -1
  473. package/dist/step.cjs.map +1 -1
  474. package/dist/step.js.map +1 -1
  475. package/dist/stepper.cjs +2 -2
  476. package/dist/stepper.cjs.map +1 -1
  477. package/dist/stepper.js +8 -7
  478. package/dist/stepper.js.map +1 -1
  479. package/dist/styles/index.d.ts +2 -2
  480. package/dist/styles/index.d.ts.map +1 -1
  481. package/dist/styles/preflight.css +1 -1
  482. package/dist/styles/theme.css +15 -30
  483. package/dist/switch.cjs +3 -3
  484. package/dist/switch.cjs.map +1 -1
  485. package/dist/switch.js +28 -28
  486. package/dist/switch.js.map +1 -1
  487. package/dist/tab-item.cjs +2 -2
  488. package/dist/tab-item.cjs.map +1 -1
  489. package/dist/tab-item.js +21 -21
  490. package/dist/tab-item.js.map +1 -1
  491. package/dist/tab-panel.cjs +2 -2
  492. package/dist/tab-panel.cjs.map +1 -1
  493. package/dist/tab-panel.js +9 -9
  494. package/dist/tab-panel.js.map +1 -1
  495. package/dist/table.cjs +1 -1
  496. package/dist/table.cjs.map +1 -1
  497. package/dist/table.js +1 -1
  498. package/dist/table.js.map +1 -1
  499. package/dist/tabs.cjs +6 -6
  500. package/dist/tabs.cjs.map +1 -1
  501. package/dist/tabs.js +14 -15
  502. package/dist/tabs.js.map +1 -1
  503. package/dist/text.cjs.map +1 -1
  504. package/dist/text.js.map +1 -1
  505. package/dist/textarea.cjs +11 -11
  506. package/dist/textarea.cjs.map +1 -1
  507. package/dist/textarea.js +59 -59
  508. package/dist/textarea.js.map +1 -1
  509. package/dist/time-picker.cjs.map +1 -1
  510. package/dist/time-picker.js.map +1 -1
  511. package/dist/toast.cjs +16 -16
  512. package/dist/toast.cjs.map +1 -1
  513. package/dist/toast.js +20 -21
  514. package/dist/toast.js.map +1 -1
  515. package/dist/tooltip.cjs.map +1 -1
  516. package/dist/tooltip.js.map +1 -1
  517. package/dist/typing-indicator.cjs +1 -1
  518. package/dist/typing-indicator.cjs.map +1 -1
  519. package/dist/typing-indicator.js +1 -1
  520. package/dist/typing-indicator.js.map +1 -1
  521. package/package.json +104 -78
@@ -1 +1 @@
1
- {"version":3,"file":"marquee.cjs","names":[],"sources":["../src/content/marquee/marquee.ts"],"sourcesContent":["import { define, getHost, html, onMounted, prop } from '@vielzeug/ore';\nimport { watch } from '@vielzeug/ripple/watch';\n\nimport type { ThemeColor } from '../../types';\n\nimport '../icon/icon';\nimport '../../inputs/button/button';\nimport componentStyles from './marquee.css?inline';\n\nexport type MarqueeDirection = 'left' | 'right';\n\nexport type OreMarqueeProps = {\n /** Theme color for the navigation controls. */\n color?: ThemeColor;\n /** Scroll direction. Defaults to `'left'`. */\n direction?: MarqueeDirection;\n /** Duration in seconds for one complete ticker cycle. Defaults to `20`. */\n duration?: number;\n /** Pause the ticker while it is hovered. Defaults to `false`. */\n 'pause-on-hover'?: boolean;\n /** Show previous/next navigation controls. Defaults to `true`. */\n 'show-controls'?: boolean;\n};\n\n/**\n * A CSS-driven, continuously scrolling ticker.\n *\n * Direct child elements are duplicated internally for a seamless loop. Cloned\n * content is inert and hidden from assistive technology, so author interactive\n * content only in the original children.\n *\n * @element ore-marquee\n *\n * @attr {string} color - Theme color for the navigation controls.\n * @attr {number} duration - Duration in seconds for one ticker cycle (default: 20)\n * @attr {string} direction - 'left' (default) | 'right'\n * @attr {boolean} pause-on-hover - Pause while hovered (default: false)\n * @attr {boolean} show-controls - Show previous/next controls (default: true)\n *\n * @cssprop --marquee-gap - Gap between ticker items (default: var(--size-4))\n *\n * @part track - The animated ticker track.\n * @example\n * ```html\n * <ore-marquee duration=\"24\" pause-on-hover>\n * <span>Free shipping</span>\n * <span>New arrivals</span>\n * </ore-marquee>\n * ```\n */\nexport const MARQUEE_TAG = 'ore-marquee' as const;\n\ndefine<OreMarqueeProps>(MARQUEE_TAG, {\n props: {\n color: prop.string<ThemeColor>(),\n direction: prop.string<MarqueeDirection>('left'),\n duration: prop.number(20),\n 'pause-on-hover': prop.bool(false),\n 'show-controls': prop.bool(true),\n },\n setup(props) {\n const el = getHost();\n let activeIndex = 0;\n let clones: HTMLElement[] = [];\n let items: HTMLElement[] = [];\n let layoutFrame: number | null = null;\n let loopWidth = 0;\n let resizeObserver: ResizeObserver | null = null;\n let track: HTMLElement | null = null;\n\n const seekTo = (index: number): void => {\n if (!track || items.length === 0) return;\n\n activeIndex = (index + items.length) % items.length;\n\n const item = items[activeIndex];\n\n if (!item || loopWidth === 0) return;\n\n const duration = props.duration.value ?? 20;\n const delay = -((item.offsetLeft / loopWidth) * duration);\n\n track.style.setProperty('animation-delay', `${delay}s`);\n };\n\n watch(\n props.duration,\n (duration) => {\n el.style.setProperty('--_marquee-duration', `${duration ?? 20}s`);\n },\n { immediate: true },\n );\n\n onMounted(() => {\n track = el.shadowRoot?.querySelector<HTMLElement>('.track') ?? null;\n\n const slot = el.shadowRoot?.querySelector<HTMLSlotElement>('slot') ?? null;\n\n const removeClones = (): void => {\n clones.forEach((clone) => clone.remove());\n clones = [];\n };\n\n const appendCloneSet = (): void => {\n clones.push(\n ...items.map((item) => {\n const clone = item.cloneNode(true) as HTMLElement;\n\n clone.setAttribute('aria-hidden', 'true');\n clone.setAttribute('data-marquee-clone', '');\n clone.setAttribute('inert', '');\n el.appendChild(clone);\n\n return clone;\n }),\n );\n };\n\n const syncLoop = (): void => {\n if (!track || items.length === 0) return;\n\n const marqueeTrack = track;\n\n if (layoutFrame !== null) cancelAnimationFrame(layoutFrame);\n\n removeClones();\n loopWidth = 0;\n marqueeTrack.style.removeProperty('--_marquee-translate');\n appendCloneSet();\n\n layoutFrame = requestAnimationFrame(() => {\n layoutFrame = null;\n\n const firstClone = clones[0];\n const firstItem = items[0];\n\n if (!firstClone || !firstItem) return;\n\n loopWidth = firstClone.offsetLeft - firstItem.offsetLeft;\n\n if (loopWidth <= 0) return;\n\n const requiredSets = Math.max(2, Math.ceil((el.clientWidth + loopWidth) / loopWidth));\n\n for (let set = 2; set < requiredSets; set += 1) appendCloneSet();\n\n marqueeTrack.style.setProperty('--_marquee-translate', `-${loopWidth}px`);\n });\n };\n\n const refreshItems = (): void => {\n const nextItems = (slot?.assignedElements() ?? []).filter(\n (child): child is HTMLElement => child instanceof HTMLElement && !child.hasAttribute('data-marquee-clone'),\n );\n const itemsChanged =\n nextItems.length !== items.length || nextItems.some((item, index) => item !== items[index]);\n\n if (!itemsChanged) return;\n\n items = nextItems;\n activeIndex = Math.min(activeIndex, Math.max(items.length - 1, 0));\n syncLoop();\n };\n\n resizeObserver = typeof ResizeObserver === 'undefined' ? null : new ResizeObserver(syncLoop);\n resizeObserver?.observe(el);\n slot?.addEventListener('slotchange', refreshItems);\n refreshItems();\n\n return () => {\n if (layoutFrame !== null) cancelAnimationFrame(layoutFrame);\n\n resizeObserver?.disconnect();\n slot?.removeEventListener('slotchange', refreshItems);\n removeClones();\n track = null;\n items = [];\n loopWidth = 0;\n };\n });\n\n return html`\n <div class=\"track\" part=\"track\" aria-live=\"off\">\n <slot></slot>\n </div>\n ${() =>\n props['show-controls'].value !== false\n ? html`\n <div class=\"controls\" part=\"controls\">\n <ore-button\n class=\"nav-btn prev-btn\"\n part=\"prev-btn\"\n variant=\"ghost\"\n color=${() => props.color.value}\n rounded\n icon-only\n label=\"Previous item\"\n @click=${(event: Event) => {\n event.stopPropagation();\n seekTo(activeIndex - 1);\n }}>\n <ore-icon name=\"chevron-left\" size=\"16\" stroke-width=\"2\" aria-hidden=\"true\"></ore-icon>\n </ore-button>\n <ore-button\n class=\"nav-btn next-btn\"\n part=\"next-btn\"\n variant=\"ghost\"\n color=${() => props.color.value}\n rounded\n icon-only\n label=\"Next item\"\n @click=${(event: Event) => {\n event.stopPropagation();\n seekTo(activeIndex + 1);\n }}>\n <ore-icon name=\"chevron-right\" size=\"16\" stroke-width=\"2\" aria-hidden=\"true\"></ore-icon>\n </ore-button>\n </div>\n `\n : null}\n `;\n },\n styles: [componentStyles],\n});\n"],"mappings":"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"}
1
+ {"version":3,"file":"marquee.cjs","names":[],"sources":["../src/content/marquee/marquee.ts"],"sourcesContent":["import { define, getHost, html, onMounted, prop } from '@vielzeug/ore';\nimport { watch } from '@vielzeug/ripple';\n\nimport type { ThemeColor } from '../../types';\n\nimport '../icon/icon';\nimport '../../inputs/button/button';\nimport componentStyles from './marquee.css?inline';\n\nexport type MarqueeDirection = 'left' | 'right';\n\nexport type OreMarqueeProps = {\n /** Theme color for the navigation controls. */\n color?: ThemeColor;\n /** Scroll direction. Defaults to `'left'`. */\n direction?: MarqueeDirection;\n /** Duration in seconds for one complete ticker cycle. Defaults to `20`. */\n duration?: number;\n /** Pause the ticker while it is hovered. Defaults to `false`. */\n 'pause-on-hover'?: boolean;\n /** Show previous/next navigation controls. Defaults to `true`. */\n 'show-controls'?: boolean;\n};\n\n/**\n * A CSS-driven, continuously scrolling ticker.\n *\n * Direct child elements are duplicated internally for a seamless loop. Cloned\n * content is inert and hidden from assistive technology, so author interactive\n * content only in the original children.\n *\n * @element ore-marquee\n *\n * @attr {string} color - Theme color for the navigation controls.\n * @attr {number} duration - Duration in seconds for one ticker cycle (default: 20)\n * @attr {string} direction - 'left' (default) | 'right'\n * @attr {boolean} pause-on-hover - Pause while hovered (default: false)\n * @attr {boolean} show-controls - Show previous/next controls (default: true)\n *\n * @cssprop --marquee-gap - Gap between ticker items (default: var(--size-4))\n *\n * @part track - The animated ticker track.\n * @example\n * ```html\n * <ore-marquee duration=\"24\" pause-on-hover>\n * <span>Free shipping</span>\n * <span>New arrivals</span>\n * </ore-marquee>\n * ```\n */\nexport const MARQUEE_TAG = 'ore-marquee' as const;\n\ndefine<OreMarqueeProps>(MARQUEE_TAG, {\n props: {\n color: prop.string<ThemeColor>(),\n direction: prop.string<MarqueeDirection>('left'),\n duration: prop.number(20),\n 'pause-on-hover': prop.bool(false),\n 'show-controls': prop.bool(true),\n },\n setup(props) {\n const el = getHost();\n let activeIndex = 0;\n let clones: HTMLElement[] = [];\n let items: HTMLElement[] = [];\n let layoutFrame: number | null = null;\n let loopWidth = 0;\n let resizeObserver: ResizeObserver | null = null;\n let track: HTMLElement | null = null;\n\n const seekTo = (index: number): void => {\n if (!track || items.length === 0) return;\n\n activeIndex = (index + items.length) % items.length;\n\n const item = items[activeIndex];\n\n if (!item || loopWidth === 0) return;\n\n const duration = props.duration.value ?? 20;\n const delay = -((item.offsetLeft / loopWidth) * duration);\n\n track.style.setProperty('animation-delay', `${delay}s`);\n };\n\n watch(\n props.duration,\n (duration) => {\n el.style.setProperty('--_marquee-duration', `${duration ?? 20}s`);\n },\n { immediate: true },\n );\n\n onMounted(() => {\n track = el.shadowRoot?.querySelector<HTMLElement>('.track') ?? null;\n\n const slot = el.shadowRoot?.querySelector<HTMLSlotElement>('slot') ?? null;\n\n const removeClones = (): void => {\n clones.forEach((clone) => clone.remove());\n clones = [];\n };\n\n const appendCloneSet = (): void => {\n clones.push(\n ...items.map((item) => {\n const clone = item.cloneNode(true) as HTMLElement;\n\n clone.setAttribute('aria-hidden', 'true');\n clone.setAttribute('data-marquee-clone', '');\n clone.setAttribute('inert', '');\n el.appendChild(clone);\n\n return clone;\n }),\n );\n };\n\n const syncLoop = (): void => {\n if (!track || items.length === 0) return;\n\n const marqueeTrack = track;\n\n if (layoutFrame !== null) cancelAnimationFrame(layoutFrame);\n\n removeClones();\n loopWidth = 0;\n marqueeTrack.style.removeProperty('--_marquee-translate');\n appendCloneSet();\n\n layoutFrame = requestAnimationFrame(() => {\n layoutFrame = null;\n\n const firstClone = clones[0];\n const firstItem = items[0];\n\n if (!firstClone || !firstItem) return;\n\n loopWidth = firstClone.offsetLeft - firstItem.offsetLeft;\n\n if (loopWidth <= 0) return;\n\n const requiredSets = Math.max(2, Math.ceil((el.clientWidth + loopWidth) / loopWidth));\n\n for (let set = 2; set < requiredSets; set += 1) appendCloneSet();\n\n marqueeTrack.style.setProperty('--_marquee-translate', `-${loopWidth}px`);\n });\n };\n\n const refreshItems = (): void => {\n const nextItems = (slot?.assignedElements() ?? []).filter(\n (child): child is HTMLElement => child instanceof HTMLElement && !child.hasAttribute('data-marquee-clone'),\n );\n const itemsChanged =\n nextItems.length !== items.length || nextItems.some((item, index) => item !== items[index]);\n\n if (!itemsChanged) return;\n\n items = nextItems;\n activeIndex = Math.min(activeIndex, Math.max(items.length - 1, 0));\n syncLoop();\n };\n\n resizeObserver = typeof ResizeObserver === 'undefined' ? null : new ResizeObserver(syncLoop);\n resizeObserver?.observe(el);\n slot?.addEventListener('slotchange', refreshItems);\n refreshItems();\n\n return () => {\n if (layoutFrame !== null) cancelAnimationFrame(layoutFrame);\n\n resizeObserver?.disconnect();\n slot?.removeEventListener('slotchange', refreshItems);\n removeClones();\n track = null;\n items = [];\n loopWidth = 0;\n };\n });\n\n return html`\n <div class=\"track\" part=\"track\" aria-live=\"off\">\n <slot></slot>\n </div>\n ${() =>\n props['show-controls'].value !== false\n ? html`\n <div class=\"controls\" part=\"controls\">\n <ore-button\n class=\"nav-btn prev-btn\"\n part=\"prev-btn\"\n variant=\"ghost\"\n color=${() => props.color.value}\n rounded\n icon-only\n label=\"Previous item\"\n @click=${(event: Event) => {\n event.stopPropagation();\n seekTo(activeIndex - 1);\n }}>\n <ore-icon name=\"chevron-left\" size=\"16\" stroke-width=\"2\" aria-hidden=\"true\"></ore-icon>\n </ore-button>\n <ore-button\n class=\"nav-btn next-btn\"\n part=\"next-btn\"\n variant=\"ghost\"\n color=${() => props.color.value}\n rounded\n icon-only\n label=\"Next item\"\n @click=${(event: Event) => {\n event.stopPropagation();\n seekTo(activeIndex + 1);\n }}>\n <ore-icon name=\"chevron-right\" size=\"16\" stroke-width=\"2\" aria-hidden=\"true\"></ore-icon>\n </ore-button>\n </div>\n `\n : null}\n `;\n },\n styles: [componentStyles],\n});\n"],"mappings":"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"}
package/dist/marquee.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import e from "./content/marquee/marquee.css.js";
2
2
  import { define as t, getHost as n, html as r, onMounted as i, prop as a } from "@vielzeug/ore";
3
- import { watch as o } from "@vielzeug/ripple/watch";
3
+ import { watch as o } from "@vielzeug/ripple";
4
4
  //#region src/content/marquee/marquee.ts
5
5
  var s = "ore-marquee";
6
6
  t(s, {
@@ -1 +1 @@
1
- {"version":3,"file":"marquee.js","names":[],"sources":["../src/content/marquee/marquee.ts"],"sourcesContent":["import { define, getHost, html, onMounted, prop } from '@vielzeug/ore';\nimport { watch } from '@vielzeug/ripple/watch';\n\nimport type { ThemeColor } from '../../types';\n\nimport '../icon/icon';\nimport '../../inputs/button/button';\nimport componentStyles from './marquee.css?inline';\n\nexport type MarqueeDirection = 'left' | 'right';\n\nexport type OreMarqueeProps = {\n /** Theme color for the navigation controls. */\n color?: ThemeColor;\n /** Scroll direction. Defaults to `'left'`. */\n direction?: MarqueeDirection;\n /** Duration in seconds for one complete ticker cycle. Defaults to `20`. */\n duration?: number;\n /** Pause the ticker while it is hovered. Defaults to `false`. */\n 'pause-on-hover'?: boolean;\n /** Show previous/next navigation controls. Defaults to `true`. */\n 'show-controls'?: boolean;\n};\n\n/**\n * A CSS-driven, continuously scrolling ticker.\n *\n * Direct child elements are duplicated internally for a seamless loop. Cloned\n * content is inert and hidden from assistive technology, so author interactive\n * content only in the original children.\n *\n * @element ore-marquee\n *\n * @attr {string} color - Theme color for the navigation controls.\n * @attr {number} duration - Duration in seconds for one ticker cycle (default: 20)\n * @attr {string} direction - 'left' (default) | 'right'\n * @attr {boolean} pause-on-hover - Pause while hovered (default: false)\n * @attr {boolean} show-controls - Show previous/next controls (default: true)\n *\n * @cssprop --marquee-gap - Gap between ticker items (default: var(--size-4))\n *\n * @part track - The animated ticker track.\n * @example\n * ```html\n * <ore-marquee duration=\"24\" pause-on-hover>\n * <span>Free shipping</span>\n * <span>New arrivals</span>\n * </ore-marquee>\n * ```\n */\nexport const MARQUEE_TAG = 'ore-marquee' as const;\n\ndefine<OreMarqueeProps>(MARQUEE_TAG, {\n props: {\n color: prop.string<ThemeColor>(),\n direction: prop.string<MarqueeDirection>('left'),\n duration: prop.number(20),\n 'pause-on-hover': prop.bool(false),\n 'show-controls': prop.bool(true),\n },\n setup(props) {\n const el = getHost();\n let activeIndex = 0;\n let clones: HTMLElement[] = [];\n let items: HTMLElement[] = [];\n let layoutFrame: number | null = null;\n let loopWidth = 0;\n let resizeObserver: ResizeObserver | null = null;\n let track: HTMLElement | null = null;\n\n const seekTo = (index: number): void => {\n if (!track || items.length === 0) return;\n\n activeIndex = (index + items.length) % items.length;\n\n const item = items[activeIndex];\n\n if (!item || loopWidth === 0) return;\n\n const duration = props.duration.value ?? 20;\n const delay = -((item.offsetLeft / loopWidth) * duration);\n\n track.style.setProperty('animation-delay', `${delay}s`);\n };\n\n watch(\n props.duration,\n (duration) => {\n el.style.setProperty('--_marquee-duration', `${duration ?? 20}s`);\n },\n { immediate: true },\n );\n\n onMounted(() => {\n track = el.shadowRoot?.querySelector<HTMLElement>('.track') ?? null;\n\n const slot = el.shadowRoot?.querySelector<HTMLSlotElement>('slot') ?? null;\n\n const removeClones = (): void => {\n clones.forEach((clone) => clone.remove());\n clones = [];\n };\n\n const appendCloneSet = (): void => {\n clones.push(\n ...items.map((item) => {\n const clone = item.cloneNode(true) as HTMLElement;\n\n clone.setAttribute('aria-hidden', 'true');\n clone.setAttribute('data-marquee-clone', '');\n clone.setAttribute('inert', '');\n el.appendChild(clone);\n\n return clone;\n }),\n );\n };\n\n const syncLoop = (): void => {\n if (!track || items.length === 0) return;\n\n const marqueeTrack = track;\n\n if (layoutFrame !== null) cancelAnimationFrame(layoutFrame);\n\n removeClones();\n loopWidth = 0;\n marqueeTrack.style.removeProperty('--_marquee-translate');\n appendCloneSet();\n\n layoutFrame = requestAnimationFrame(() => {\n layoutFrame = null;\n\n const firstClone = clones[0];\n const firstItem = items[0];\n\n if (!firstClone || !firstItem) return;\n\n loopWidth = firstClone.offsetLeft - firstItem.offsetLeft;\n\n if (loopWidth <= 0) return;\n\n const requiredSets = Math.max(2, Math.ceil((el.clientWidth + loopWidth) / loopWidth));\n\n for (let set = 2; set < requiredSets; set += 1) appendCloneSet();\n\n marqueeTrack.style.setProperty('--_marquee-translate', `-${loopWidth}px`);\n });\n };\n\n const refreshItems = (): void => {\n const nextItems = (slot?.assignedElements() ?? []).filter(\n (child): child is HTMLElement => child instanceof HTMLElement && !child.hasAttribute('data-marquee-clone'),\n );\n const itemsChanged =\n nextItems.length !== items.length || nextItems.some((item, index) => item !== items[index]);\n\n if (!itemsChanged) return;\n\n items = nextItems;\n activeIndex = Math.min(activeIndex, Math.max(items.length - 1, 0));\n syncLoop();\n };\n\n resizeObserver = typeof ResizeObserver === 'undefined' ? null : new ResizeObserver(syncLoop);\n resizeObserver?.observe(el);\n slot?.addEventListener('slotchange', refreshItems);\n refreshItems();\n\n return () => {\n if (layoutFrame !== null) cancelAnimationFrame(layoutFrame);\n\n resizeObserver?.disconnect();\n slot?.removeEventListener('slotchange', refreshItems);\n removeClones();\n track = null;\n items = [];\n loopWidth = 0;\n };\n });\n\n return html`\n <div class=\"track\" part=\"track\" aria-live=\"off\">\n <slot></slot>\n </div>\n ${() =>\n props['show-controls'].value !== false\n ? html`\n <div class=\"controls\" part=\"controls\">\n <ore-button\n class=\"nav-btn prev-btn\"\n part=\"prev-btn\"\n variant=\"ghost\"\n color=${() => props.color.value}\n rounded\n icon-only\n label=\"Previous item\"\n @click=${(event: Event) => {\n event.stopPropagation();\n seekTo(activeIndex - 1);\n }}>\n <ore-icon name=\"chevron-left\" size=\"16\" stroke-width=\"2\" aria-hidden=\"true\"></ore-icon>\n </ore-button>\n <ore-button\n class=\"nav-btn next-btn\"\n part=\"next-btn\"\n variant=\"ghost\"\n color=${() => props.color.value}\n rounded\n icon-only\n label=\"Next item\"\n @click=${(event: Event) => {\n event.stopPropagation();\n seekTo(activeIndex + 1);\n }}>\n <ore-icon name=\"chevron-right\" size=\"16\" stroke-width=\"2\" aria-hidden=\"true\"></ore-icon>\n </ore-button>\n </div>\n `\n : null}\n `;\n },\n styles: [componentStyles],\n});\n"],"mappings":"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"}
1
+ {"version":3,"file":"marquee.js","names":[],"sources":["../src/content/marquee/marquee.ts"],"sourcesContent":["import { define, getHost, html, onMounted, prop } from '@vielzeug/ore';\nimport { watch } from '@vielzeug/ripple';\n\nimport type { ThemeColor } from '../../types';\n\nimport '../icon/icon';\nimport '../../inputs/button/button';\nimport componentStyles from './marquee.css?inline';\n\nexport type MarqueeDirection = 'left' | 'right';\n\nexport type OreMarqueeProps = {\n /** Theme color for the navigation controls. */\n color?: ThemeColor;\n /** Scroll direction. Defaults to `'left'`. */\n direction?: MarqueeDirection;\n /** Duration in seconds for one complete ticker cycle. Defaults to `20`. */\n duration?: number;\n /** Pause the ticker while it is hovered. Defaults to `false`. */\n 'pause-on-hover'?: boolean;\n /** Show previous/next navigation controls. Defaults to `true`. */\n 'show-controls'?: boolean;\n};\n\n/**\n * A CSS-driven, continuously scrolling ticker.\n *\n * Direct child elements are duplicated internally for a seamless loop. Cloned\n * content is inert and hidden from assistive technology, so author interactive\n * content only in the original children.\n *\n * @element ore-marquee\n *\n * @attr {string} color - Theme color for the navigation controls.\n * @attr {number} duration - Duration in seconds for one ticker cycle (default: 20)\n * @attr {string} direction - 'left' (default) | 'right'\n * @attr {boolean} pause-on-hover - Pause while hovered (default: false)\n * @attr {boolean} show-controls - Show previous/next controls (default: true)\n *\n * @cssprop --marquee-gap - Gap between ticker items (default: var(--size-4))\n *\n * @part track - The animated ticker track.\n * @example\n * ```html\n * <ore-marquee duration=\"24\" pause-on-hover>\n * <span>Free shipping</span>\n * <span>New arrivals</span>\n * </ore-marquee>\n * ```\n */\nexport const MARQUEE_TAG = 'ore-marquee' as const;\n\ndefine<OreMarqueeProps>(MARQUEE_TAG, {\n props: {\n color: prop.string<ThemeColor>(),\n direction: prop.string<MarqueeDirection>('left'),\n duration: prop.number(20),\n 'pause-on-hover': prop.bool(false),\n 'show-controls': prop.bool(true),\n },\n setup(props) {\n const el = getHost();\n let activeIndex = 0;\n let clones: HTMLElement[] = [];\n let items: HTMLElement[] = [];\n let layoutFrame: number | null = null;\n let loopWidth = 0;\n let resizeObserver: ResizeObserver | null = null;\n let track: HTMLElement | null = null;\n\n const seekTo = (index: number): void => {\n if (!track || items.length === 0) return;\n\n activeIndex = (index + items.length) % items.length;\n\n const item = items[activeIndex];\n\n if (!item || loopWidth === 0) return;\n\n const duration = props.duration.value ?? 20;\n const delay = -((item.offsetLeft / loopWidth) * duration);\n\n track.style.setProperty('animation-delay', `${delay}s`);\n };\n\n watch(\n props.duration,\n (duration) => {\n el.style.setProperty('--_marquee-duration', `${duration ?? 20}s`);\n },\n { immediate: true },\n );\n\n onMounted(() => {\n track = el.shadowRoot?.querySelector<HTMLElement>('.track') ?? null;\n\n const slot = el.shadowRoot?.querySelector<HTMLSlotElement>('slot') ?? null;\n\n const removeClones = (): void => {\n clones.forEach((clone) => clone.remove());\n clones = [];\n };\n\n const appendCloneSet = (): void => {\n clones.push(\n ...items.map((item) => {\n const clone = item.cloneNode(true) as HTMLElement;\n\n clone.setAttribute('aria-hidden', 'true');\n clone.setAttribute('data-marquee-clone', '');\n clone.setAttribute('inert', '');\n el.appendChild(clone);\n\n return clone;\n }),\n );\n };\n\n const syncLoop = (): void => {\n if (!track || items.length === 0) return;\n\n const marqueeTrack = track;\n\n if (layoutFrame !== null) cancelAnimationFrame(layoutFrame);\n\n removeClones();\n loopWidth = 0;\n marqueeTrack.style.removeProperty('--_marquee-translate');\n appendCloneSet();\n\n layoutFrame = requestAnimationFrame(() => {\n layoutFrame = null;\n\n const firstClone = clones[0];\n const firstItem = items[0];\n\n if (!firstClone || !firstItem) return;\n\n loopWidth = firstClone.offsetLeft - firstItem.offsetLeft;\n\n if (loopWidth <= 0) return;\n\n const requiredSets = Math.max(2, Math.ceil((el.clientWidth + loopWidth) / loopWidth));\n\n for (let set = 2; set < requiredSets; set += 1) appendCloneSet();\n\n marqueeTrack.style.setProperty('--_marquee-translate', `-${loopWidth}px`);\n });\n };\n\n const refreshItems = (): void => {\n const nextItems = (slot?.assignedElements() ?? []).filter(\n (child): child is HTMLElement => child instanceof HTMLElement && !child.hasAttribute('data-marquee-clone'),\n );\n const itemsChanged =\n nextItems.length !== items.length || nextItems.some((item, index) => item !== items[index]);\n\n if (!itemsChanged) return;\n\n items = nextItems;\n activeIndex = Math.min(activeIndex, Math.max(items.length - 1, 0));\n syncLoop();\n };\n\n resizeObserver = typeof ResizeObserver === 'undefined' ? null : new ResizeObserver(syncLoop);\n resizeObserver?.observe(el);\n slot?.addEventListener('slotchange', refreshItems);\n refreshItems();\n\n return () => {\n if (layoutFrame !== null) cancelAnimationFrame(layoutFrame);\n\n resizeObserver?.disconnect();\n slot?.removeEventListener('slotchange', refreshItems);\n removeClones();\n track = null;\n items = [];\n loopWidth = 0;\n };\n });\n\n return html`\n <div class=\"track\" part=\"track\" aria-live=\"off\">\n <slot></slot>\n </div>\n ${() =>\n props['show-controls'].value !== false\n ? html`\n <div class=\"controls\" part=\"controls\">\n <ore-button\n class=\"nav-btn prev-btn\"\n part=\"prev-btn\"\n variant=\"ghost\"\n color=${() => props.color.value}\n rounded\n icon-only\n label=\"Previous item\"\n @click=${(event: Event) => {\n event.stopPropagation();\n seekTo(activeIndex - 1);\n }}>\n <ore-icon name=\"chevron-left\" size=\"16\" stroke-width=\"2\" aria-hidden=\"true\"></ore-icon>\n </ore-button>\n <ore-button\n class=\"nav-btn next-btn\"\n part=\"next-btn\"\n variant=\"ghost\"\n color=${() => props.color.value}\n rounded\n icon-only\n label=\"Next item\"\n @click=${(event: Event) => {\n event.stopPropagation();\n seekTo(activeIndex + 1);\n }}>\n <ore-icon name=\"chevron-right\" size=\"16\" stroke-width=\"2\" aria-hidden=\"true\"></ore-icon>\n </ore-button>\n </div>\n `\n : null}\n `;\n },\n styles: [componentStyles],\n});\n"],"mappings":"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"}
package/dist/menu.cjs CHANGED
@@ -1,4 +1,4 @@
1
- Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("./core/ore.cjs"),t=require("./core/keyboard.cjs"),n=require("./core/overlay.cjs"),r=require("./styles/mixins/shape.css.cjs"),i=require("./styles/mixins/theme.css.cjs"),a=require("./core/positioner.cjs"),o=require("./core/nav.cjs"),s=require("./shared/prop-bundles.cjs"),c=require("./shared/size-presets.cjs"),l=require("./overlay/menu/menu-item.css.cjs"),u=require("./overlay/menu/menu-separator.css.cjs"),d=require("./overlay/menu/menu.css.cjs");let f=require("@vielzeug/ore"),p=require("@vielzeug/ripple"),m=require("@vielzeug/ripple/watch");var h=`ore-menu-item`;(0,f.define)(h,{props:{checked:f.prop.bool(!1),disabled:f.prop.bool(!1),type:f.prop.string(),value:f.prop.string()},setup(e){let t=()=>e.type.value===`checkbox`||e.type.value===`radio`,n=()=>t()&&e.checked.value;return t()?f.html`
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("./styles/mixins/shape.css.cjs"),t=require("./styles/mixins/theme.css.cjs"),n=require("./core/keyboard.cjs"),r=require("./core/ore.cjs"),i=require("./core/overlay.cjs"),a=require("./core/nav.cjs"),o=require("./core/positioner.cjs"),s=require("./shared/prop-bundles.cjs"),c=require("./shared/size-presets.cjs"),l=require("./overlay/menu/menu.css.cjs"),u=require("./overlay/menu/menu-item.css.cjs"),d=require("./overlay/menu/menu-separator.css.cjs");let f=require("@vielzeug/ore"),p=require("@vielzeug/ripple");var m=`ore-menu-item`;(0,f.define)(m,{props:{checked:f.prop.bool(!1),disabled:f.prop.bool(!1),type:f.prop.string(),value:f.prop.string()},setup(e){let t=()=>e.type.value===`checkbox`||e.type.value===`radio`,n=()=>t()&&e.checked.value;return t()?f.html`
2
2
  <div
3
3
  class="${()=>{let t=e.type.value;return[`item`,t===`checkbox`?`is-checkbox`:``,t===`radio`?`is-radio`:``,n()?`is-checked`:``].filter(Boolean).join(` `)}}"
4
4
  tabindex="-1"
@@ -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:[i.colorThemeMixin,l.default]});var g=`ore-menu-separator`;(0,f.define)(g,{setup(){return f.html``},styles:[u.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(r){let i=(0,f.getHost)(),s=(0,f.useEmit)(),c=(0,f.useSlots)(),l=f.watchEffect,u=(0,f.createStableId)(`menu`),d=(0,p.computed)(()=>!!r.disabled.value),h=e.lifecycleSignal(f.onCleanup),g=null,v=null,y=null;function b(){return Array.from(i.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=a.createDropdownPositioner({getFloating:()=>v,getPlacement:()=>r.placement.value??`bottom-start`,getReference:()=>g,matchWidth:!1,offsetPx:4,padding:6}),E=o.createListControl({disabled:(0,p.computed)(()=>!C.value),getItems:b,isItemDisabled:e=>e.hasAttribute(`disabled`),onNavigate:(e,t)=>{let n=b()[t];x(n)?.focus()},signal:h}),D=(e=`programmatic`,t=!0)=>{C.value&&(C.value=!1,E.reset(),w?.(),w=null,t&&n.restoreTriggerFocus(()=>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`)};n.createOutsidePointerDismissal({getTargets:()=>[i,v],isActive:()=>C.value,onDismiss:()=>D(`outsideClick`),signal:h});let A=!1;(0,m.watch)(r.open,e=>{e===void 0?A?D(`programmatic`):r[`default-open`].value&&O(`programmatic`):e?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 t=e.getAttribute(`type`),n=_(t);if(t===`checkbox`)e.toggleAttribute(`checked`,!e.hasAttribute(`checked`));else if(t===`radio`)for(let t of i.querySelectorAll(`ore-menu-item[type="radio"]`))t.toggleAttribute(`checked`,t===e);let r=e.getAttribute(`value`)??``,a=n?e.hasAttribute(`checked`):void 0;s(`select`,{checked:a,value:r}),n||D(`programmatic`)},M=t.createInteraction({keys:[`Enter`,` `,`ArrowDown`],onPress:()=>{O(`keyboard`),requestAnimationFrame(()=>E.set(0))}}),N=t.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,m.watch)(c.elements(`trigger`),F,{immediate:!0}),(0,f.onMounted)(()=>()=>{y?.(),y=null}),f.html`
17
+ `},styles:[t.colorThemeMixin,u.default]});var h=`ore-menu-separator`;(0,f.define)(h,{setup(){return f.html``},styles:[d.default]});var g=e=>e===`checkbox`||e===`radio`,_=e=>e==null?void 0:e===``||e===`true`,v=`ore-menu`;(0,f.define)(v,{props:{...s.sizableBundle,...s.disablableBundle,"default-open":f.prop.bool(!1),open:{default:void 0,parse:_},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),m=r.lifecycleSignal(f.onCleanup),h=null,_=null,v=null;function y(){return Array.from(t.querySelectorAll(`ore-menu-item:not([disabled])`))}function b(e){return e?e.shadowRoot?.querySelector(`[role^="menuitem"]`)??e:null}function x(){return y().findIndex(e=>{let t=b(e);return e===document.activeElement||t===document.activeElement})}let S=(0,p.signal)(!1),C=null,w=o.createDropdownPositioner({getFloating:()=>_,getPlacement:()=>e.placement.value??`bottom-start`,getReference:()=>h,matchWidth:!1,offsetPx:4,padding:6}),T=a.createListControl({disabled:(0,p.computed)(()=>!S.value),getItems:y,isItemDisabled:e=>e.hasAttribute(`disabled`),onNavigate:(e,t)=>{let n=y()[t];b(n)?.focus()},signal:m}),E=(e=`programmatic`,t=!0)=>{S.value&&(S.value=!1,T.reset(),C?.(),C=null,t&&i.restoreTriggerFocus(()=>h),s(`open-change`,{open:!1,reason:e}))},D=(e=`programmatic`)=>{d.value||S.value||(S.value=!0,w.update(),C=w.startAutoUpdate?.()??null,s(`open-change`,{open:!0,reason:e}))},O=()=>{S.value?E(`trigger`):D(`click`)};i.createOutsidePointerDismissal({getTargets:()=>[t,_],isActive:()=>S.value,onDismiss:()=>E(`outsideClick`),signal:m});let k=!1;(0,p.watch)(e.open,t=>{t===void 0?k?E(`programmatic`):e[`default-open`].value&&D(`programmatic`):t?D(`programmatic`):E(`programmatic`),k=!0},{immediate:!0}),m.addEventListener(`abort`,()=>{S.value&&(S.value=!1,T.reset(),C?.(),C=null)},{once:!0});let A=e=>{let n=e.getAttribute(`type`),r=g(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||E(`programmatic`)},j=n.createInteraction({keys:[`Enter`,` `,`ArrowDown`],onPress:()=>{D(`keyboard`),requestAnimationFrame(()=>T.set(0))}}),M=n.createInteraction({onPress:()=>{let e=T.getActiveItem();e&&A(e)}});function N(e){if(d.value)return;if(!S.value){j.handleKeydown(e);return}let t=x();if(t>=0&&T.set(t),e.key===`Escape`){e.preventDefault(),E(`escape`);return}if(!T.handleKeydown(e)){if(e.key===` `||e.key===`Enter`){M.handleKeydown(e);return}e.key===`Tab`&&E(`programmatic`)}}(0,f.bind)({on:{click:e=>{let t=e.composedPath();if(!S.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`)||A(n)}}}),l(()=>{let e=S.value;_&&_.toggleAttribute(`data-open`,e)});function P(){if(v?.(),v=null,h=c.elements(`trigger`).value?.[0]??null,!h)return;let e=[],t=(0,f.bind)({aria:{controls:()=>u,disabled:()=>d.value,expanded:()=>String(S.value),haspopup:`menu`}},{target:h}),n=e=>{e.stopPropagation(),!d.value&&O()},r=e=>{N(e)};h.addEventListener(`click`,n),h.addEventListener(`keydown`,r),e.push(()=>h?.removeEventListener(`click`,n)),e.push(()=>h?.removeEventListener(`keydown`,r)),v=()=>{t();for(let t of e)t()}}return(0,p.watch)(c.elements(`trigger`),P,{immediate:!0}),(0,f.onMounted)(()=>(P(),()=>{v?.(),v=null})),f.html`
18
18
  <slot name="trigger"></slot>
19
19
  <div
20
20
  class="menu-panel"
@@ -22,9 +22,9 @@ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=requi
22
22
  id="${u}"
23
23
  role="menu"
24
24
  aria-orientation="vertical"
25
- @keydown="${P}"
26
- ref="${e=>{v=e,v?.toggleAttribute(`data-open`,C.value)}}">
25
+ @keydown="${N}"
26
+ ref="${e=>{_=e,_?.toggleAttribute(`data-open`,S.value)}}">
27
27
  <slot></slot>
28
28
  </div>
29
- `},styles:[d.default,r.sizeVariantMixin(c.MENU_SIZE_PRESET),i.forcedColorsMixin]}),exports.MENU_ITEM_TAG=h,exports.MENU_TAG=y,exports.SEPARATOR_TAG=g;
29
+ `},styles:[l.default,e.sizeVariantMixin(c.MENU_SIZE_PRESET),t.forcedColorsMixin]}),exports.MENU_ITEM_TAG=m,exports.MENU_TAG=v,exports.SEPARATOR_TAG=h;
30
30
  //# sourceMappingURL=menu.cjs.map
package/dist/menu.cjs.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"menu.cjs","names":[],"sources":["../src/overlay/menu/menu.ts"],"sourcesContent":["import type { Placement } from '@vielzeug/orbit';\n\nimport {\n createStableId,\n define,\n html,\n prop,\n bind,\n getHost,\n onCleanup,\n onMounted,\n useEmit,\n useSlots,\n watchEffect,\n} from '@vielzeug/ore';\nimport { computed, signal } from '@vielzeug/ripple';\nimport { watch as rippleWatch } from '@vielzeug/ripple/watch';\n\nimport type { ComponentSize } from '../../types';\n\nimport {\n lifecycleSignal,\n createDropdownPositioner,\n createInteraction,\n createListControl,\n createOutsidePointerDismissal,\n restoreTriggerFocus,\n type DropdownCloseReason,\n type OverlayOpenChangeDetail,\n type OverlayOpenReason,\n} from '../../core';\nimport { disablableBundle, MENU_SIZE_PRESET, sizableBundle } from '../../shared';\nimport { colorThemeMixin, forcedColorsMixin, sizeVariantMixin } from '../../styles';\nimport menuItemStyles from './menu-item.css?inline';\nimport menuSeparatorStyles from './menu-separator.css?inline';\nimport componentStyles from './menu.css?inline';\n\n// ── Types ─────────────────────────────────────────────────────────────\n\nexport interface MenuSelectDetail {\n value: string;\n checked?: boolean;\n}\n\nexport type OreMenuItemType = 'checkbox' | 'radio';\n\nexport type OreMenuEvents = {\n 'open-change': OverlayOpenChangeDetail;\n select: MenuSelectDetail;\n};\n\nexport type OreMenuItemProps = {\n checked?: boolean;\n disabled?: boolean;\n type?: OreMenuItemType;\n value?: string;\n};\n\nexport type OreMenuProps = {\n /** Initial uncontrolled open state. Ignored when `open` is set. */\n 'default-open'?: boolean;\n disabled?: boolean;\n /** Controlled open state. */\n open?: boolean;\n placement?: 'bottom' | 'bottom-start' | 'bottom-end' | 'top' | 'top-start' | 'top-end';\n size?: ComponentSize;\n};\n\n// ── Styles ─────────────────────────────────────────────────────────────\n\n// ── Menu Item Component ─────────────────────────────────────────────────────────────\n\n/**\n * A selectable action item used inside `<ore-menu>`.\n *\n * @element ore-menu-item\n *\n * @attr {boolean} checked - Checked state for `checkbox` and `radio` item types\n * @attr {boolean} disabled - Disables selection and pointer interaction\n * @attr {'checkbox'|'radio'} type - Optional checkable menu item mode\n * @attr {string} value - Value emitted by parent menu on selection\n *\n * @slot - Item label/content\n * @slot icon - Optional leading icon content\n *\n * @cssprop --menu-item-hover-bg - Background on hover\n * @cssprop --menu-item-focus-color - Text color when keyboard-focused\n * @cssprop --menu-item-focus-bg - Background when keyboard-focused\n * @cssprop --menu-item-selection-bg - Background for checkbox/radio items (unselected)\n * @cssprop --menu-item-checked-color - Text color when checked\n * @cssprop --menu-item-checked-bg - Background when checked\n *\n * @part item - Root item container element.\n * @part item-label - Label text container.\n * @part icon-slot - Leading icon slot container.\n *\n * @example\n * ```html\n * <ore-menu-item value=\"edit\">Edit</ore-menu-item>\n * <ore-menu-item value=\"delete\" disabled>Delete</ore-menu-item>\n * <ore-menu-item type=\"checkbox\" value=\"wrap\" checked>Word wrap</ore-menu-item>\n * <ore-menu-item type=\"radio\" value=\"left\">Align left</ore-menu-item>\n * ```\n */\nexport const MENU_ITEM_TAG = 'ore-menu-item' as const;\ndefine<OreMenuItemProps>(MENU_ITEM_TAG, {\n props: {\n checked: prop.bool(false),\n disabled: prop.bool(false),\n type: prop.string<OreMenuItemType>(),\n value: prop.string(),\n },\n setup(props) {\n const isCheckable = () => props.type.value === 'checkbox' || props.type.value === 'radio';\n const isChecked = () => isCheckable() && props.checked.value;\n const itemRole = () => {\n if (props.type.value === 'checkbox') return 'menuitemcheckbox';\n\n if (props.type.value === 'radio') return 'menuitemradio';\n\n return 'menuitem';\n };\n const itemClass = () => {\n const type = props.type.value;\n\n return [\n 'item',\n type === 'checkbox' ? 'is-checkbox' : '',\n type === 'radio' ? 'is-radio' : '',\n isChecked() ? 'is-checked' : '',\n ]\n .filter(Boolean)\n .join(' ');\n };\n\n return isCheckable()\n ? html`\n <div\n class=\"${itemClass}\"\n tabindex=\"-1\"\n role=\"${itemRole}\"\n aria-checked=\"${() => String(isChecked())}\"\n aria-disabled=\"${props.disabled}\">\n <span class=\"item-check\" aria-hidden=\"true\"></span>\n <span class=\"icon-slot\"><slot name=\"icon\"></slot></span>\n <span class=\"item-label\"><slot></slot></span>\n </div>\n `\n : html`\n <div class=\"item\" tabindex=\"-1\" role=\"menuitem\" aria-disabled=\"${props.disabled}\">\n <span class=\"icon-slot\"><slot name=\"icon\"></slot></span>\n <span class=\"item-label\"><slot></slot></span>\n </div>\n `;\n },\n styles: [colorThemeMixin, menuItemStyles],\n});\n\n// ── Menu Separator ─────────────────────────────────────────────────────────────\n\n/**\n * Visual separator used to group menu items inside `<ore-menu>`.\n *\n * @element ore-menu-separator\n *\n * @example\n * ```html\n * <ore-menu-item value=\"cut\">Cut</ore-menu-item>\n * <ore-menu-separator></ore-menu-separator>\n * <ore-menu-item value=\"paste\">Paste</ore-menu-item>\n * ```\n */\nexport const SEPARATOR_TAG = 'ore-menu-separator' as const;\ndefine(SEPARATOR_TAG, {\n setup() {\n return html``;\n },\n styles: [menuSeparatorStyles],\n});\n\n// ── Menu Component ─────────────────────────────────────────────────────────────\n\nconst isCheckableItemType = (value: string | null): value is OreMenuItemType =>\n value === 'checkbox' || value === 'radio';\n\nconst parseOptionalBool = (value: string | null): boolean | undefined =>\n value == null ? undefined : value === '' || value === 'true';\n\n/**\n * Action dropdown menu triggered by a slotted trigger element.\n *\n * @element ore-menu\n * @element ore-menu-item - Clickable menu option (place in default slot)\n * @element ore-menu-separator - Visual divider between menu groups\n *\n * @attr {boolean} disabled - Disables opening and keyboard interaction\n * @attr {boolean} open - Controlled open state\n * @attr {boolean} default-open - Initial uncontrolled open state\n * @attr {string} placement - Panel placement: 'bottom' | 'bottom-start' | 'bottom-end' | 'top' | 'top-start' | 'top-end' (default: 'bottom-start')\n * @attr {string} size - Size: 'sm' | 'md' | 'lg'\n *\n * @fires open-change - Fired when the menu state changes. detail: { open, reason }\n * @fires select - Fired when an item is selected. detail: { value: string, checked?: boolean }\n *\n * @slot trigger - Trigger element that toggles menu visibility\n * @slot - Menu content (`<ore-menu-item>` and `<ore-menu-separator>`)\n *\n * @part panel - Floating menu panel container\n *\n * @cssprop --menu-panel-bg - Background of the floating panel\n * @cssprop --menu-panel-border-color - Border color of the floating panel\n * @cssprop --menu-panel-shadow - Box shadow of the floating panel\n * @cssprop --menu-panel-blur - Backdrop blur amount for the floating panel\n * @cssprop --menu-panel-min-width - Minimum width of the floating panel\n * @cssprop --menu-panel-max-height - Maximum height of the floating panel before it scrolls\n * @cssprop --menu-panel-radius - Border radius of the floating panel\n *\n * @example\n * ```html\n * <ore-menu>\n * <button slot=\"trigger\">Actions</button>\n * <ore-menu-item value=\"edit\">Edit</ore-menu-item>\n * <ore-menu-item value=\"delete\">Delete</ore-menu-item>\n * </ore-menu>\n * ```\n */\nexport const MENU_TAG = 'ore-menu' as const;\ndefine<OreMenuProps>(MENU_TAG, {\n props: {\n ...sizableBundle,\n ...disablableBundle,\n 'default-open': prop.bool(false),\n open: { default: undefined as boolean | undefined, parse: parseOptionalBool },\n placement: prop.oneOf(\n ['bottom', 'bottom-start', 'bottom-end', 'top', 'top-start', 'top-end'] as const,\n 'bottom-start',\n ),\n },\n setup(props) {\n const el = getHost();\n const emit = useEmit<OreMenuEvents>();\n const slots = useSlots();\n const watch = watchEffect;\n\n const menuId = createStableId('menu');\n const isDisabled = computed(() => Boolean(props.disabled.value));\n const abortSignal = lifecycleSignal(onCleanup);\n let triggerEl: HTMLElement | null = null;\n let panelEl: HTMLElement | null = null;\n let cleanupTrigger: (() => void) | null = null;\n\n // ── Helpers ───────────────────────────────────────────────────────────────\n function getItems(): HTMLElement[] {\n return Array.from(el.querySelectorAll<HTMLElement>('ore-menu-item:not([disabled])'));\n }\n\n function getItemFocusable(item: HTMLElement | null | undefined): HTMLElement | null {\n if (!item) return null;\n\n return item.shadowRoot?.querySelector<HTMLElement>('[role^=\"menuitem\"]') ?? item;\n }\n\n function getFocusedItemIndex(): number {\n const items = getItems();\n\n return items.findIndex((item) => {\n const focusable = getItemFocusable(item);\n\n return item === document.activeElement || focusable === document.activeElement;\n });\n }\n\n const isOpenSignal = signal(false);\n let stopPositioning: (() => void) | null = null;\n const positioner = createDropdownPositioner({\n getFloating: () => panelEl,\n getPlacement: () => (props.placement.value ?? 'bottom-start') as Placement,\n getReference: () => triggerEl,\n matchWidth: false,\n offsetPx: 4,\n padding: 6,\n });\n const list = createListControl<HTMLElement>({\n disabled: computed(() => !isOpenSignal.value),\n getItems: getItems,\n isItemDisabled: (item) => item.hasAttribute('disabled'),\n onNavigate: (_action, index) => {\n const nextItem = getItems()[index];\n\n getItemFocusable(nextItem)?.focus();\n },\n signal: abortSignal,\n });\n\n const close = (reason: DropdownCloseReason = 'programmatic', shouldRestoreFocus = true): void => {\n if (!isOpenSignal.value) return;\n\n isOpenSignal.value = false;\n list.reset();\n stopPositioning?.();\n stopPositioning = null;\n\n if (shouldRestoreFocus) restoreTriggerFocus(() => triggerEl);\n\n emit('open-change', { open: false, reason });\n };\n\n const open = (reason: OverlayOpenReason = 'programmatic'): void => {\n if (isDisabled.value || isOpenSignal.value) return;\n\n isOpenSignal.value = true;\n positioner.update();\n stopPositioning = positioner.startAutoUpdate?.() ?? null;\n emit('open-change', { open: true, reason });\n };\n\n const toggle = (): void => {\n if (isOpenSignal.value) close('trigger');\n else open('click');\n };\n\n createOutsidePointerDismissal({\n getTargets: () => [el, panelEl],\n isActive: () => isOpenSignal.value,\n onDismiss: () => close('outsideClick'),\n signal: abortSignal,\n });\n\n let initialized = false;\n\n rippleWatch(\n props.open,\n (value) => {\n if (value === undefined) {\n if (!initialized) {\n if (props['default-open'].value) open('programmatic');\n } else {\n close('programmatic');\n }\n } else if (value) {\n open('programmatic');\n } else {\n close('programmatic');\n }\n\n initialized = true;\n },\n { immediate: true },\n );\n abortSignal.addEventListener(\n 'abort',\n () => {\n if (!isOpenSignal.value) return;\n\n isOpenSignal.value = false;\n list.reset();\n stopPositioning?.();\n stopPositioning = null;\n },\n { once: true },\n );\n\n const activateItem = (item: HTMLElement): void => {\n const type = item.getAttribute('type');\n const isCheckable = isCheckableItemType(type);\n\n if (type === 'checkbox') {\n item.toggleAttribute('checked', !item.hasAttribute('checked'));\n } else if (type === 'radio') {\n for (const radio of el.querySelectorAll<HTMLElement>('ore-menu-item[type=\"radio\"]')) {\n radio.toggleAttribute('checked', radio === item);\n }\n }\n\n const value = item.getAttribute('value') ?? '';\n const checked = isCheckable ? item.hasAttribute('checked') : undefined;\n\n emit('select', { checked, value });\n\n if (!isCheckable) {\n close('programmatic');\n }\n };\n\n const openFromKeyboardPress = createInteraction({\n keys: ['Enter', ' ', 'ArrowDown'],\n onPress: () => {\n open('keyboard');\n requestAnimationFrame(() => list.set(0));\n },\n });\n\n const activateFocusedFromKeyboardPress = createInteraction({\n onPress: () => {\n const focused = list.getActiveItem();\n\n if (focused) activateItem(focused);\n },\n });\n\n // ── Keyboard Navigation ───────────────────────────────────────────────────\n function handleMenuKeydown(e: KeyboardEvent) {\n if (isDisabled.value) return;\n\n const open = isOpenSignal.value;\n\n // When closed: open on Enter / Space / ArrowDown\n if (!open) {\n openFromKeyboardPress.handleKeydown(e);\n\n return;\n }\n\n const currentFocusedIndex = getFocusedItemIndex();\n\n if (currentFocusedIndex >= 0) list.set(currentFocusedIndex);\n\n if (e.key === 'Escape') {\n e.preventDefault();\n close('escape');\n\n return;\n }\n\n if (list.handleKeydown(e)) return;\n\n // When open: navigate and activate\n if (e.key === ' ' || e.key === 'Enter') {\n activateFocusedFromKeyboardPress.handleKeydown(e);\n\n return;\n }\n\n if (e.key === 'Tab') {\n close('programmatic');\n }\n }\n\n // ── Lifecycle ─────────────────────────────────────────────────────────────\n bind({\n on: {\n click: (e: MouseEvent) => {\n const path = e.composedPath();\n\n if (!isOpenSignal.value) return;\n\n const itemFromPath = path.find(\n (node): node is HTMLElement => node instanceof HTMLElement && node.tagName === 'ORE-MENU-ITEM',\n );\n const item = itemFromPath ?? (e.target as HTMLElement | null)?.closest<HTMLElement>('ore-menu-item') ?? null;\n\n if (!item || item.hasAttribute('disabled')) return;\n\n activateItem(item);\n },\n },\n });\n\n watch(() => {\n const open = isOpenSignal.value;\n\n if (!panelEl) return;\n\n panelEl.toggleAttribute('data-open', open);\n });\n\n function resolveTrigger() {\n cleanupTrigger?.();\n cleanupTrigger = null;\n\n const assigned = slots.elements('trigger').value;\n\n triggerEl = (assigned?.[0] as HTMLElement | undefined) ?? null;\n\n if (!triggerEl) return;\n\n const cleanups: Array<() => void> = [];\n const removeAria = bind(\n {\n aria: {\n controls: () => menuId,\n disabled: () => isDisabled.value,\n expanded: () => String(isOpenSignal.value),\n haspopup: 'menu',\n },\n },\n { target: triggerEl },\n );\n\n const onTriggerClick = (event: MouseEvent) => {\n event.stopPropagation();\n\n if (isDisabled.value) return;\n\n toggle();\n };\n const onTriggerKeydown = (event: KeyboardEvent) => {\n handleMenuKeydown(event);\n };\n\n triggerEl.addEventListener('click', onTriggerClick);\n triggerEl.addEventListener('keydown', onTriggerKeydown);\n cleanups.push(() => triggerEl?.removeEventListener('click', onTriggerClick));\n cleanups.push(() => triggerEl?.removeEventListener('keydown', onTriggerKeydown));\n\n cleanupTrigger = () => {\n removeAria();\n\n for (const cleanup of cleanups) cleanup();\n };\n }\n\n rippleWatch(slots.elements('trigger'), resolveTrigger, { immediate: true });\n\n onMounted(() => {\n return () => {\n cleanupTrigger?.();\n cleanupTrigger = null;\n };\n });\n\n return html`\n <slot name=\"trigger\"></slot>\n <div\n class=\"menu-panel\"\n part=\"panel\"\n id=\"${menuId}\"\n role=\"menu\"\n aria-orientation=\"vertical\"\n @keydown=\"${handleMenuKeydown}\"\n ref=\"${(el: HTMLElement | null) => {\n panelEl = el;\n panelEl?.toggleAttribute('data-open', isOpenSignal.value);\n }}\">\n <slot></slot>\n </div>\n `;\n },\n styles: [componentStyles, sizeVariantMixin(MENU_SIZE_PRESET), forcedColorsMixin],\n});\n"],"mappings":"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"}
1
+ {"version":3,"file":"menu.cjs","names":[],"sources":["../src/overlay/menu/menu.ts"],"sourcesContent":["import type { Placement } from '@vielzeug/orbit';\n\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 restoreTriggerFocus,\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: (_action, index) => {\n const nextItem = getItems()[index];\n\n getItemFocusable(nextItem)?.focus();\n },\n signal: abortSignal,\n });\n\n const close = (reason: DropdownCloseReason = 'programmatic', shouldRestoreFocus = true): void => {\n if (!isOpenSignal.value) return;\n\n isOpenSignal.value = false;\n list.reset();\n stopPositioning?.();\n stopPositioning = null;\n\n if (shouldRestoreFocus) restoreTriggerFocus(() => triggerEl);\n\n emit('open-change', { open: false, reason });\n };\n\n const open = (reason: OverlayOpenReason = 'programmatic'): void => {\n if (isDisabled.value || isOpenSignal.value) return;\n\n isOpenSignal.value = true;\n positioner.update();\n stopPositioning = positioner.startAutoUpdate?.() ?? null;\n emit('open-change', { open: true, reason });\n };\n\n const toggle = (): void => {\n if (isOpenSignal.value) close('trigger');\n else open('click');\n };\n\n createOutsidePointerDismissal({\n getTargets: () => [el, panelEl],\n isActive: () => isOpenSignal.value,\n onDismiss: () => close('outsideClick'),\n signal: abortSignal,\n });\n\n let initialized = false;\n\n rippleWatch(\n props.open,\n (value) => {\n if (value === undefined) {\n if (!initialized) {\n if (props['default-open'].value) open('programmatic');\n } else {\n close('programmatic');\n }\n } else if (value) {\n open('programmatic');\n } else {\n close('programmatic');\n }\n\n initialized = true;\n },\n { immediate: true },\n );\n abortSignal.addEventListener(\n 'abort',\n () => {\n if (!isOpenSignal.value) return;\n\n isOpenSignal.value = false;\n list.reset();\n stopPositioning?.();\n stopPositioning = null;\n },\n { once: true },\n );\n\n const activateItem = (item: HTMLElement): void => {\n const type = item.getAttribute('type');\n const isCheckable = isCheckableItemType(type);\n\n if (type === 'checkbox') {\n item.toggleAttribute('checked', !item.hasAttribute('checked'));\n } else if (type === 'radio') {\n for (const radio of el.querySelectorAll<HTMLElement>('ore-menu-item[type=\"radio\"]')) {\n radio.toggleAttribute('checked', radio === item);\n }\n }\n\n const value = item.getAttribute('value') ?? '';\n const checked = isCheckable ? item.hasAttribute('checked') : undefined;\n\n emit('select', { checked, value });\n\n if (!isCheckable) {\n close('programmatic');\n }\n };\n\n const openFromKeyboardPress = createInteraction({\n keys: ['Enter', ' ', 'ArrowDown'],\n onPress: () => {\n open('keyboard');\n requestAnimationFrame(() => list.set(0));\n },\n });\n\n const activateFocusedFromKeyboardPress = createInteraction({\n onPress: () => {\n const focused = list.getActiveItem();\n\n if (focused) activateItem(focused);\n },\n });\n\n // ── Keyboard Navigation ───────────────────────────────────────────────────\n function handleMenuKeydown(e: KeyboardEvent) {\n if (isDisabled.value) return;\n\n const open = isOpenSignal.value;\n\n // When closed: open on Enter / Space / ArrowDown\n if (!open) {\n openFromKeyboardPress.handleKeydown(e);\n\n return;\n }\n\n const currentFocusedIndex = getFocusedItemIndex();\n\n if (currentFocusedIndex >= 0) list.set(currentFocusedIndex);\n\n if (e.key === 'Escape') {\n e.preventDefault();\n close('escape');\n\n return;\n }\n\n if (list.handleKeydown(e)) return;\n\n // When open: navigate and activate\n if (e.key === ' ' || e.key === 'Enter') {\n activateFocusedFromKeyboardPress.handleKeydown(e);\n\n return;\n }\n\n if (e.key === 'Tab') {\n close('programmatic');\n }\n }\n\n // ── Lifecycle ─────────────────────────────────────────────────────────────\n bind({\n on: {\n click: (e: MouseEvent) => {\n const path = e.composedPath();\n\n if (!isOpenSignal.value) return;\n\n const itemFromPath = path.find(\n (node): node is HTMLElement => node instanceof HTMLElement && node.tagName === 'ORE-MENU-ITEM',\n );\n const item = itemFromPath ?? (e.target as HTMLElement | null)?.closest<HTMLElement>('ore-menu-item') ?? null;\n\n if (!item || item.hasAttribute('disabled')) return;\n\n activateItem(item);\n },\n },\n });\n\n watch(() => {\n const open = isOpenSignal.value;\n\n if (!panelEl) return;\n\n panelEl.toggleAttribute('data-open', open);\n });\n\n function resolveTrigger() {\n cleanupTrigger?.();\n cleanupTrigger = null;\n\n const assigned = slots.elements('trigger').value;\n\n triggerEl = (assigned?.[0] as HTMLElement | undefined) ?? null;\n\n if (!triggerEl) return;\n\n const cleanups: Array<() => void> = [];\n const removeAria = bind(\n {\n aria: {\n controls: () => menuId,\n disabled: () => isDisabled.value,\n expanded: () => String(isOpenSignal.value),\n haspopup: 'menu',\n },\n },\n { target: triggerEl },\n );\n\n const onTriggerClick = (event: MouseEvent) => {\n event.stopPropagation();\n\n if (isDisabled.value) return;\n\n toggle();\n };\n const onTriggerKeydown = (event: KeyboardEvent) => {\n handleMenuKeydown(event);\n };\n\n triggerEl.addEventListener('click', onTriggerClick);\n triggerEl.addEventListener('keydown', onTriggerKeydown);\n cleanups.push(() => triggerEl?.removeEventListener('click', onTriggerClick));\n cleanups.push(() => triggerEl?.removeEventListener('keydown', onTriggerKeydown));\n\n cleanupTrigger = () => {\n removeAria();\n\n for (const cleanup of cleanups) cleanup();\n };\n }\n\n rippleWatch(slots.elements('trigger'), resolveTrigger, { immediate: true });\n\n onMounted(() => {\n 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":"glBAqGA,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,eAAA,CAAe,MAAM,EAC9B,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,EAAS,IAAU,CAC9B,IAAM,EAAW,EAAS,CAAC,CAAC,GAE5B,EAAiB,CAAQ,CAAC,EAAE,MAAM,CACpC,EACA,OAAQ,CACV,CAAC,EAEK,GAAS,EAA8B,eAAgB,EAAqB,KAAe,CAC1F,EAAa,QAElB,EAAa,MAAQ,GACrB,EAAK,MAAM,EACX,IAAkB,EAClB,EAAkB,KAEd,GAAoB,EAAA,wBAA0B,CAAS,EAE3D,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,KAEpG,CAAC,GAAQ,EAAK,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,aAAgB,EAChB,aAAgB,EAAW,MAC3B,aAAgB,OAAO,EAAa,KAAK,EACzC,SAAU,MACZ,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
@@ -1,18 +1,17 @@
1
- import { lifecycleSignal as e } from "./core/ore.js";
2
- import { createInteraction as t } from "./core/keyboard.js";
3
- import { createOutsidePointerDismissal as n, restoreTriggerFocus as r } from "./core/overlay.js";
4
- import { sizeVariantMixin as i } from "./styles/mixins/shape.css.js";
5
- import { colorThemeMixin as a, forcedColorsMixin as o } from "./styles/mixins/theme.css.js";
6
- import { createDropdownPositioner as s } from "./core/positioner.js";
7
- import { createListControl as c } from "./core/nav.js";
1
+ import { sizeVariantMixin as e } from "./styles/mixins/shape.css.js";
2
+ import { colorThemeMixin as t, forcedColorsMixin as n } from "./styles/mixins/theme.css.js";
3
+ import { createInteraction as r } from "./core/keyboard.js";
4
+ import { lifecycleSignal as i } from "./core/ore.js";
5
+ import { createOutsidePointerDismissal as a, restoreTriggerFocus as o } from "./core/overlay.js";
6
+ import { createListControl as s } from "./core/nav.js";
7
+ import { createDropdownPositioner as c } from "./core/positioner.js";
8
8
  import { disablableBundle as l, sizableBundle as u } from "./shared/prop-bundles.js";
9
9
  import { MENU_SIZE_PRESET as d } from "./shared/size-presets.js";
10
- import f from "./overlay/menu/menu-item.css.js";
11
- import p from "./overlay/menu/menu-separator.css.js";
12
- import m from "./overlay/menu/menu.css.js";
10
+ import f from "./overlay/menu/menu.css.js";
11
+ import p from "./overlay/menu/menu-item.css.js";
12
+ import m from "./overlay/menu/menu-separator.css.js";
13
13
  import { bind as h, createStableId as g, define as _, getHost as v, html as y, onCleanup as b, onMounted as x, prop as S, useEmit as C, useSlots as w, watchEffect as T } from "@vielzeug/ore";
14
- import { computed as E, signal as D } from "@vielzeug/ripple";
15
- import { watch as O } from "@vielzeug/ripple/watch";
14
+ import { computed as E, signal as D, watch as O } from "@vielzeug/ripple";
16
15
  //#region src/overlay/menu/menu.ts
17
16
  var k = "ore-menu-item";
18
17
  _(k, {
@@ -50,14 +49,14 @@ _(k, {
50
49
  </div>
51
50
  `;
52
51
  },
53
- styles: [a, f]
52
+ styles: [t, p]
54
53
  });
55
54
  var A = "ore-menu-separator";
56
55
  _(A, {
57
56
  setup() {
58
57
  return y``;
59
58
  },
60
- styles: [p]
59
+ styles: [m]
61
60
  });
62
61
  var j = (e) => e === "checkbox" || e === "radio", M = (e) => e == null ? void 0 : e === "" || e === "true", N = "ore-menu";
63
62
  _(N, {
@@ -78,10 +77,10 @@ _(N, {
78
77
  "top-end"
79
78
  ], "bottom-start")
80
79
  },
81
- setup(i) {
82
- let a = v(), o = C(), l = w(), u = T, d = g("menu"), f = E(() => !!i.disabled.value), p = e(b), m = null, _ = null, S = null;
80
+ setup(e) {
81
+ let t = v(), n = C(), l = w(), u = T, d = g("menu"), f = E(() => !!e.disabled.value), p = i(b), m = null, _ = null, S = null;
83
82
  function k() {
84
- return Array.from(a.querySelectorAll("ore-menu-item:not([disabled])"));
83
+ return Array.from(t.querySelectorAll("ore-menu-item:not([disabled])"));
85
84
  }
86
85
  function A(e) {
87
86
  return e ? e.shadowRoot?.querySelector("[role^=\"menuitem\"]") ?? e : null;
@@ -92,14 +91,14 @@ _(N, {
92
91
  return e === document.activeElement || t === document.activeElement;
93
92
  });
94
93
  }
95
- let N = D(!1), P = null, F = s({
94
+ let N = D(!1), P = null, F = c({
96
95
  getFloating: () => _,
97
- getPlacement: () => i.placement.value ?? "bottom-start",
96
+ getPlacement: () => e.placement.value ?? "bottom-start",
98
97
  getReference: () => m,
99
98
  matchWidth: !1,
100
99
  offsetPx: 4,
101
100
  padding: 6
102
- }), I = c({
101
+ }), I = s({
103
102
  disabled: E(() => !N.value),
104
103
  getItems: k,
105
104
  isItemDisabled: (e) => e.hasAttribute("disabled"),
@@ -109,40 +108,40 @@ _(N, {
109
108
  },
110
109
  signal: p
111
110
  }), L = (e = "programmatic", t = !0) => {
112
- N.value && (N.value = !1, I.reset(), P?.(), P = null, t && r(() => m), o("open-change", {
111
+ N.value && (N.value = !1, I.reset(), P?.(), P = null, t && o(() => m), n("open-change", {
113
112
  open: !1,
114
113
  reason: e
115
114
  }));
116
115
  }, R = (e = "programmatic") => {
117
- f.value || N.value || (N.value = !0, F.update(), P = F.startAutoUpdate?.() ?? null, o("open-change", {
116
+ f.value || N.value || (N.value = !0, F.update(), P = F.startAutoUpdate?.() ?? null, n("open-change", {
118
117
  open: !0,
119
118
  reason: e
120
119
  }));
121
120
  }, z = () => {
122
121
  N.value ? L("trigger") : R("click");
123
122
  };
124
- n({
125
- getTargets: () => [a, _],
123
+ a({
124
+ getTargets: () => [t, _],
126
125
  isActive: () => N.value,
127
126
  onDismiss: () => L("outsideClick"),
128
127
  signal: p
129
128
  });
130
129
  let B = !1;
131
- O(i.open, (e) => {
132
- e === void 0 ? B ? L("programmatic") : i["default-open"].value && R("programmatic") : e ? R("programmatic") : L("programmatic"), B = !0;
130
+ O(e.open, (t) => {
131
+ t === void 0 ? B ? L("programmatic") : e["default-open"].value && R("programmatic") : t ? R("programmatic") : L("programmatic"), B = !0;
133
132
  }, { immediate: !0 }), p.addEventListener("abort", () => {
134
133
  N.value && (N.value = !1, I.reset(), P?.(), P = null);
135
134
  }, { once: !0 });
136
135
  let V = (e) => {
137
- let t = e.getAttribute("type"), n = j(t);
138
- if (t === "checkbox") e.toggleAttribute("checked", !e.hasAttribute("checked"));
139
- else if (t === "radio") for (let t of a.querySelectorAll("ore-menu-item[type=\"radio\"]")) t.toggleAttribute("checked", t === e);
140
- let r = e.getAttribute("value") ?? "", i = n ? e.hasAttribute("checked") : void 0;
141
- o("select", {
142
- checked: i,
143
- value: r
144
- }), n || L("programmatic");
145
- }, H = t({
136
+ let r = e.getAttribute("type"), i = j(r);
137
+ if (r === "checkbox") e.toggleAttribute("checked", !e.hasAttribute("checked"));
138
+ else if (r === "radio") for (let n of t.querySelectorAll("ore-menu-item[type=\"radio\"]")) n.toggleAttribute("checked", n === e);
139
+ let a = e.getAttribute("value") ?? "", o = i ? e.hasAttribute("checked") : void 0;
140
+ n("select", {
141
+ checked: o,
142
+ value: a
143
+ }), i || L("programmatic");
144
+ }, H = r({
146
145
  keys: [
147
146
  "Enter",
148
147
  " ",
@@ -151,7 +150,7 @@ _(N, {
151
150
  onPress: () => {
152
151
  R("keyboard"), requestAnimationFrame(() => I.set(0));
153
152
  }
154
- }), U = t({ onPress: () => {
153
+ }), U = r({ onPress: () => {
155
154
  let e = I.getActiveItem();
156
155
  e && V(e);
157
156
  } });
@@ -200,9 +199,9 @@ _(N, {
200
199
  for (let t of e) t();
201
200
  };
202
201
  }
203
- return O(l.elements("trigger"), G, { immediate: !0 }), x(() => () => {
202
+ return O(l.elements("trigger"), G, { immediate: !0 }), x(() => (G(), () => {
204
203
  S?.(), S = null;
205
- }), y`
204
+ })), y`
206
205
  <slot name="trigger"></slot>
207
206
  <div
208
207
  class="menu-panel"
@@ -219,9 +218,9 @@ _(N, {
219
218
  `;
220
219
  },
221
220
  styles: [
222
- m,
223
- i(d),
224
- o
221
+ f,
222
+ e(d),
223
+ n
225
224
  ]
226
225
  });
227
226
  //#endregion
package/dist/menu.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"menu.js","names":[],"sources":["../src/overlay/menu/menu.ts"],"sourcesContent":["import type { Placement } from '@vielzeug/orbit';\n\nimport {\n createStableId,\n define,\n html,\n prop,\n bind,\n getHost,\n onCleanup,\n onMounted,\n useEmit,\n useSlots,\n watchEffect,\n} from '@vielzeug/ore';\nimport { computed, signal } from '@vielzeug/ripple';\nimport { watch as rippleWatch } from '@vielzeug/ripple/watch';\n\nimport type { ComponentSize } from '../../types';\n\nimport {\n lifecycleSignal,\n createDropdownPositioner,\n createInteraction,\n createListControl,\n createOutsidePointerDismissal,\n restoreTriggerFocus,\n type DropdownCloseReason,\n type OverlayOpenChangeDetail,\n type OverlayOpenReason,\n} from '../../core';\nimport { disablableBundle, MENU_SIZE_PRESET, sizableBundle } from '../../shared';\nimport { colorThemeMixin, forcedColorsMixin, sizeVariantMixin } from '../../styles';\nimport menuItemStyles from './menu-item.css?inline';\nimport menuSeparatorStyles from './menu-separator.css?inline';\nimport componentStyles from './menu.css?inline';\n\n// ── Types ─────────────────────────────────────────────────────────────\n\nexport interface MenuSelectDetail {\n value: string;\n checked?: boolean;\n}\n\nexport type OreMenuItemType = 'checkbox' | 'radio';\n\nexport type OreMenuEvents = {\n 'open-change': OverlayOpenChangeDetail;\n select: MenuSelectDetail;\n};\n\nexport type OreMenuItemProps = {\n checked?: boolean;\n disabled?: boolean;\n type?: OreMenuItemType;\n value?: string;\n};\n\nexport type OreMenuProps = {\n /** Initial uncontrolled open state. Ignored when `open` is set. */\n 'default-open'?: boolean;\n disabled?: boolean;\n /** Controlled open state. */\n open?: boolean;\n placement?: 'bottom' | 'bottom-start' | 'bottom-end' | 'top' | 'top-start' | 'top-end';\n size?: ComponentSize;\n};\n\n// ── Styles ─────────────────────────────────────────────────────────────\n\n// ── Menu Item Component ─────────────────────────────────────────────────────────────\n\n/**\n * A selectable action item used inside `<ore-menu>`.\n *\n * @element ore-menu-item\n *\n * @attr {boolean} checked - Checked state for `checkbox` and `radio` item types\n * @attr {boolean} disabled - Disables selection and pointer interaction\n * @attr {'checkbox'|'radio'} type - Optional checkable menu item mode\n * @attr {string} value - Value emitted by parent menu on selection\n *\n * @slot - Item label/content\n * @slot icon - Optional leading icon content\n *\n * @cssprop --menu-item-hover-bg - Background on hover\n * @cssprop --menu-item-focus-color - Text color when keyboard-focused\n * @cssprop --menu-item-focus-bg - Background when keyboard-focused\n * @cssprop --menu-item-selection-bg - Background for checkbox/radio items (unselected)\n * @cssprop --menu-item-checked-color - Text color when checked\n * @cssprop --menu-item-checked-bg - Background when checked\n *\n * @part item - Root item container element.\n * @part item-label - Label text container.\n * @part icon-slot - Leading icon slot container.\n *\n * @example\n * ```html\n * <ore-menu-item value=\"edit\">Edit</ore-menu-item>\n * <ore-menu-item value=\"delete\" disabled>Delete</ore-menu-item>\n * <ore-menu-item type=\"checkbox\" value=\"wrap\" checked>Word wrap</ore-menu-item>\n * <ore-menu-item type=\"radio\" value=\"left\">Align left</ore-menu-item>\n * ```\n */\nexport const MENU_ITEM_TAG = 'ore-menu-item' as const;\ndefine<OreMenuItemProps>(MENU_ITEM_TAG, {\n props: {\n checked: prop.bool(false),\n disabled: prop.bool(false),\n type: prop.string<OreMenuItemType>(),\n value: prop.string(),\n },\n setup(props) {\n const isCheckable = () => props.type.value === 'checkbox' || props.type.value === 'radio';\n const isChecked = () => isCheckable() && props.checked.value;\n const itemRole = () => {\n if (props.type.value === 'checkbox') return 'menuitemcheckbox';\n\n if (props.type.value === 'radio') return 'menuitemradio';\n\n return 'menuitem';\n };\n const itemClass = () => {\n const type = props.type.value;\n\n return [\n 'item',\n type === 'checkbox' ? 'is-checkbox' : '',\n type === 'radio' ? 'is-radio' : '',\n isChecked() ? 'is-checked' : '',\n ]\n .filter(Boolean)\n .join(' ');\n };\n\n return isCheckable()\n ? html`\n <div\n class=\"${itemClass}\"\n tabindex=\"-1\"\n role=\"${itemRole}\"\n aria-checked=\"${() => String(isChecked())}\"\n aria-disabled=\"${props.disabled}\">\n <span class=\"item-check\" aria-hidden=\"true\"></span>\n <span class=\"icon-slot\"><slot name=\"icon\"></slot></span>\n <span class=\"item-label\"><slot></slot></span>\n </div>\n `\n : html`\n <div class=\"item\" tabindex=\"-1\" role=\"menuitem\" aria-disabled=\"${props.disabled}\">\n <span class=\"icon-slot\"><slot name=\"icon\"></slot></span>\n <span class=\"item-label\"><slot></slot></span>\n </div>\n `;\n },\n styles: [colorThemeMixin, menuItemStyles],\n});\n\n// ── Menu Separator ─────────────────────────────────────────────────────────────\n\n/**\n * Visual separator used to group menu items inside `<ore-menu>`.\n *\n * @element ore-menu-separator\n *\n * @example\n * ```html\n * <ore-menu-item value=\"cut\">Cut</ore-menu-item>\n * <ore-menu-separator></ore-menu-separator>\n * <ore-menu-item value=\"paste\">Paste</ore-menu-item>\n * ```\n */\nexport const SEPARATOR_TAG = 'ore-menu-separator' as const;\ndefine(SEPARATOR_TAG, {\n setup() {\n return html``;\n },\n styles: [menuSeparatorStyles],\n});\n\n// ── Menu Component ─────────────────────────────────────────────────────────────\n\nconst isCheckableItemType = (value: string | null): value is OreMenuItemType =>\n value === 'checkbox' || value === 'radio';\n\nconst parseOptionalBool = (value: string | null): boolean | undefined =>\n value == null ? undefined : value === '' || value === 'true';\n\n/**\n * Action dropdown menu triggered by a slotted trigger element.\n *\n * @element ore-menu\n * @element ore-menu-item - Clickable menu option (place in default slot)\n * @element ore-menu-separator - Visual divider between menu groups\n *\n * @attr {boolean} disabled - Disables opening and keyboard interaction\n * @attr {boolean} open - Controlled open state\n * @attr {boolean} default-open - Initial uncontrolled open state\n * @attr {string} placement - Panel placement: 'bottom' | 'bottom-start' | 'bottom-end' | 'top' | 'top-start' | 'top-end' (default: 'bottom-start')\n * @attr {string} size - Size: 'sm' | 'md' | 'lg'\n *\n * @fires open-change - Fired when the menu state changes. detail: { open, reason }\n * @fires select - Fired when an item is selected. detail: { value: string, checked?: boolean }\n *\n * @slot trigger - Trigger element that toggles menu visibility\n * @slot - Menu content (`<ore-menu-item>` and `<ore-menu-separator>`)\n *\n * @part panel - Floating menu panel container\n *\n * @cssprop --menu-panel-bg - Background of the floating panel\n * @cssprop --menu-panel-border-color - Border color of the floating panel\n * @cssprop --menu-panel-shadow - Box shadow of the floating panel\n * @cssprop --menu-panel-blur - Backdrop blur amount for the floating panel\n * @cssprop --menu-panel-min-width - Minimum width of the floating panel\n * @cssprop --menu-panel-max-height - Maximum height of the floating panel before it scrolls\n * @cssprop --menu-panel-radius - Border radius of the floating panel\n *\n * @example\n * ```html\n * <ore-menu>\n * <button slot=\"trigger\">Actions</button>\n * <ore-menu-item value=\"edit\">Edit</ore-menu-item>\n * <ore-menu-item value=\"delete\">Delete</ore-menu-item>\n * </ore-menu>\n * ```\n */\nexport const MENU_TAG = 'ore-menu' as const;\ndefine<OreMenuProps>(MENU_TAG, {\n props: {\n ...sizableBundle,\n ...disablableBundle,\n 'default-open': prop.bool(false),\n open: { default: undefined as boolean | undefined, parse: parseOptionalBool },\n placement: prop.oneOf(\n ['bottom', 'bottom-start', 'bottom-end', 'top', 'top-start', 'top-end'] as const,\n 'bottom-start',\n ),\n },\n setup(props) {\n const el = getHost();\n const emit = useEmit<OreMenuEvents>();\n const slots = useSlots();\n const watch = watchEffect;\n\n const menuId = createStableId('menu');\n const isDisabled = computed(() => Boolean(props.disabled.value));\n const abortSignal = lifecycleSignal(onCleanup);\n let triggerEl: HTMLElement | null = null;\n let panelEl: HTMLElement | null = null;\n let cleanupTrigger: (() => void) | null = null;\n\n // ── Helpers ───────────────────────────────────────────────────────────────\n function getItems(): HTMLElement[] {\n return Array.from(el.querySelectorAll<HTMLElement>('ore-menu-item:not([disabled])'));\n }\n\n function getItemFocusable(item: HTMLElement | null | undefined): HTMLElement | null {\n if (!item) return null;\n\n return item.shadowRoot?.querySelector<HTMLElement>('[role^=\"menuitem\"]') ?? item;\n }\n\n function getFocusedItemIndex(): number {\n const items = getItems();\n\n return items.findIndex((item) => {\n const focusable = getItemFocusable(item);\n\n return item === document.activeElement || focusable === document.activeElement;\n });\n }\n\n const isOpenSignal = signal(false);\n let stopPositioning: (() => void) | null = null;\n const positioner = createDropdownPositioner({\n getFloating: () => panelEl,\n getPlacement: () => (props.placement.value ?? 'bottom-start') as Placement,\n getReference: () => triggerEl,\n matchWidth: false,\n offsetPx: 4,\n padding: 6,\n });\n const list = createListControl<HTMLElement>({\n disabled: computed(() => !isOpenSignal.value),\n getItems: getItems,\n isItemDisabled: (item) => item.hasAttribute('disabled'),\n onNavigate: (_action, index) => {\n const nextItem = getItems()[index];\n\n getItemFocusable(nextItem)?.focus();\n },\n signal: abortSignal,\n });\n\n const close = (reason: DropdownCloseReason = 'programmatic', shouldRestoreFocus = true): void => {\n if (!isOpenSignal.value) return;\n\n isOpenSignal.value = false;\n list.reset();\n stopPositioning?.();\n stopPositioning = null;\n\n if (shouldRestoreFocus) restoreTriggerFocus(() => triggerEl);\n\n emit('open-change', { open: false, reason });\n };\n\n const open = (reason: OverlayOpenReason = 'programmatic'): void => {\n if (isDisabled.value || isOpenSignal.value) return;\n\n isOpenSignal.value = true;\n positioner.update();\n stopPositioning = positioner.startAutoUpdate?.() ?? null;\n emit('open-change', { open: true, reason });\n };\n\n const toggle = (): void => {\n if (isOpenSignal.value) close('trigger');\n else open('click');\n };\n\n createOutsidePointerDismissal({\n getTargets: () => [el, panelEl],\n isActive: () => isOpenSignal.value,\n onDismiss: () => close('outsideClick'),\n signal: abortSignal,\n });\n\n let initialized = false;\n\n rippleWatch(\n props.open,\n (value) => {\n if (value === undefined) {\n if (!initialized) {\n if (props['default-open'].value) open('programmatic');\n } else {\n close('programmatic');\n }\n } else if (value) {\n open('programmatic');\n } else {\n close('programmatic');\n }\n\n initialized = true;\n },\n { immediate: true },\n );\n abortSignal.addEventListener(\n 'abort',\n () => {\n if (!isOpenSignal.value) return;\n\n isOpenSignal.value = false;\n list.reset();\n stopPositioning?.();\n stopPositioning = null;\n },\n { once: true },\n );\n\n const activateItem = (item: HTMLElement): void => {\n const type = item.getAttribute('type');\n const isCheckable = isCheckableItemType(type);\n\n if (type === 'checkbox') {\n item.toggleAttribute('checked', !item.hasAttribute('checked'));\n } else if (type === 'radio') {\n for (const radio of el.querySelectorAll<HTMLElement>('ore-menu-item[type=\"radio\"]')) {\n radio.toggleAttribute('checked', radio === item);\n }\n }\n\n const value = item.getAttribute('value') ?? '';\n const checked = isCheckable ? item.hasAttribute('checked') : undefined;\n\n emit('select', { checked, value });\n\n if (!isCheckable) {\n close('programmatic');\n }\n };\n\n const openFromKeyboardPress = createInteraction({\n keys: ['Enter', ' ', 'ArrowDown'],\n onPress: () => {\n open('keyboard');\n requestAnimationFrame(() => list.set(0));\n },\n });\n\n const activateFocusedFromKeyboardPress = createInteraction({\n onPress: () => {\n const focused = list.getActiveItem();\n\n if (focused) activateItem(focused);\n },\n });\n\n // ── Keyboard Navigation ───────────────────────────────────────────────────\n function handleMenuKeydown(e: KeyboardEvent) {\n if (isDisabled.value) return;\n\n const open = isOpenSignal.value;\n\n // When closed: open on Enter / Space / ArrowDown\n if (!open) {\n openFromKeyboardPress.handleKeydown(e);\n\n return;\n }\n\n const currentFocusedIndex = getFocusedItemIndex();\n\n if (currentFocusedIndex >= 0) list.set(currentFocusedIndex);\n\n if (e.key === 'Escape') {\n e.preventDefault();\n close('escape');\n\n return;\n }\n\n if (list.handleKeydown(e)) return;\n\n // When open: navigate and activate\n if (e.key === ' ' || e.key === 'Enter') {\n activateFocusedFromKeyboardPress.handleKeydown(e);\n\n return;\n }\n\n if (e.key === 'Tab') {\n close('programmatic');\n }\n }\n\n // ── Lifecycle ─────────────────────────────────────────────────────────────\n bind({\n on: {\n click: (e: MouseEvent) => {\n const path = e.composedPath();\n\n if (!isOpenSignal.value) return;\n\n const itemFromPath = path.find(\n (node): node is HTMLElement => node instanceof HTMLElement && node.tagName === 'ORE-MENU-ITEM',\n );\n const item = itemFromPath ?? (e.target as HTMLElement | null)?.closest<HTMLElement>('ore-menu-item') ?? null;\n\n if (!item || item.hasAttribute('disabled')) return;\n\n activateItem(item);\n },\n },\n });\n\n watch(() => {\n const open = isOpenSignal.value;\n\n if (!panelEl) return;\n\n panelEl.toggleAttribute('data-open', open);\n });\n\n function resolveTrigger() {\n cleanupTrigger?.();\n cleanupTrigger = null;\n\n const assigned = slots.elements('trigger').value;\n\n triggerEl = (assigned?.[0] as HTMLElement | undefined) ?? null;\n\n if (!triggerEl) return;\n\n const cleanups: Array<() => void> = [];\n const removeAria = bind(\n {\n aria: {\n controls: () => menuId,\n disabled: () => isDisabled.value,\n expanded: () => String(isOpenSignal.value),\n haspopup: 'menu',\n },\n },\n { target: triggerEl },\n );\n\n const onTriggerClick = (event: MouseEvent) => {\n event.stopPropagation();\n\n if (isDisabled.value) return;\n\n toggle();\n };\n const onTriggerKeydown = (event: KeyboardEvent) => {\n handleMenuKeydown(event);\n };\n\n triggerEl.addEventListener('click', onTriggerClick);\n triggerEl.addEventListener('keydown', onTriggerKeydown);\n cleanups.push(() => triggerEl?.removeEventListener('click', onTriggerClick));\n cleanups.push(() => triggerEl?.removeEventListener('keydown', onTriggerKeydown));\n\n cleanupTrigger = () => {\n removeAria();\n\n for (const cleanup of cleanups) cleanup();\n };\n }\n\n rippleWatch(slots.elements('trigger'), resolveTrigger, { immediate: true });\n\n onMounted(() => {\n return () => {\n cleanupTrigger?.();\n cleanupTrigger = null;\n };\n });\n\n return html`\n <slot name=\"trigger\"></slot>\n <div\n class=\"menu-panel\"\n part=\"panel\"\n id=\"${menuId}\"\n role=\"menu\"\n aria-orientation=\"vertical\"\n @keydown=\"${handleMenuKeydown}\"\n ref=\"${(el: HTMLElement | null) => {\n panelEl = el;\n panelEl?.toggleAttribute('data-open', isOpenSignal.value);\n }}\">\n <slot></slot>\n </div>\n `;\n },\n styles: [componentStyles, sizeVariantMixin(MENU_SIZE_PRESET), forcedColorsMixin],\n});\n"],"mappings":";;;;;;;;;;;;;;;;AAwGA,IAAa,IAAgB;AAC7B,EAAyB,GAAe;CACtC,OAAO;EACL,SAAS,EAAK,KAAK,EAAK;EACxB,UAAU,EAAK,KAAK,EAAK;EACzB,MAAM,EAAK,OAAwB;EACnC,OAAO,EAAK,OAAO;CACrB;CACA,MAAM,GAAO;EACX,IAAM,UAAoB,EAAM,KAAK,UAAU,cAAc,EAAM,KAAK,UAAU,SAC5E,UAAkB,EAAY,KAAK,EAAM,QAAQ;EAqBvD,OAAO,EAAY,IACf,CAAI;;2BAdgB;GACtB,IAAM,IAAO,EAAM,KAAK;GAExB,OAAO;IACL;IACA,MAAS,aAAa,gBAAgB;IACtC,MAAS,UAAU,aAAa;IAChC,EAAU,IAAI,eAAe;GAC/B,CAAC,CACE,OAAO,OAAO,CAAC,CACf,KAAK,GAAG;EACb,EAK2B;;0BAtBrB,EAAM,KAAK,UAAU,aAAmB,qBAExC,EAAM,KAAK,UAAU,UAAgB,kBAElC,WAoBgB;kCACK,OAAO,EAAU,CAAC,EAAE;6BACzB,EAAM,SAAS;;;;;YAMpC,CAAI;2EAC+D,EAAM,SAAS;;;;;CAKxF;CACA,QAAQ,CAAC,GAAiB,CAAc;AAC1C,CAAC;AAgBD,IAAa,IAAgB;AAC7B,EAAO,GAAe;CACpB,QAAQ;EACN,OAAO,CAAI;CACb;CACA,QAAQ,CAAC,CAAmB;AAC9B,CAAC;AAID,IAAM,KAAuB,MAC3B,MAAU,cAAc,MAAU,SAE9B,KAAqB,MACzB,KAAS,OAAO,KAAA,IAAY,MAAU,MAAM,MAAU,QAwC3C,IAAW;AACxB,EAAqB,GAAU;CAC7B,OAAO;EACL,GAAG;EACH,GAAG;EACH,gBAAgB,EAAK,KAAK,EAAK;EAC/B,MAAM;GAAE,SAAS,KAAA;GAAkC,OAAO;EAAkB;EAC5E,WAAW,EAAK,MACd;GAAC;GAAU;GAAgB;GAAc;GAAO;GAAa;EAAS,GACtE,cACF;CACF;CACA,MAAM,GAAO;EACX,IAAM,IAAK,EAAQ,GACb,IAAO,EAAuB,GAC9B,IAAQ,EAAS,GACjB,IAAQ,GAER,IAAS,EAAe,MAAM,GAC9B,IAAa,QAAe,EAAQ,EAAM,SAAS,KAAM,GACzD,IAAc,EAAgB,CAAS,GACzC,IAAgC,MAChC,IAA8B,MAC9B,IAAsC;EAG1C,SAAS,IAA0B;GACjC,OAAO,MAAM,KAAK,EAAG,iBAA8B,+BAA+B,CAAC;EACrF;EAEA,SAAS,EAAiB,GAA0D;GAGlF,OAFK,IAEE,EAAK,YAAY,cAA2B,sBAAoB,KAAK,IAF1D;EAGpB;EAEA,SAAS,IAA8B;GAGrC,OAFc,EAEP,CAAA,CAAM,WAAW,MAAS;IAC/B,IAAM,IAAY,EAAiB,CAAI;IAEvC,OAAO,MAAS,SAAS,iBAAiB,MAAc,SAAS;GACnE,CAAC;EACH;EAEA,IAAM,IAAe,EAAO,EAAK,GAC7B,IAAuC,MACrC,IAAa,EAAyB;GAC1C,mBAAmB;GACnB,oBAAqB,EAAM,UAAU,SAAS;GAC9C,oBAAoB;GACpB,YAAY;GACZ,UAAU;GACV,SAAS;EACX,CAAC,GACK,IAAO,EAA+B;GAC1C,UAAU,QAAe,CAAC,EAAa,KAAK;GAClC;GACV,iBAAiB,MAAS,EAAK,aAAa,UAAU;GACtD,aAAa,GAAS,MAAU;IAC9B,IAAM,IAAW,EAAS,CAAC,CAAC;IAE5B,EAAiB,CAAQ,CAAC,EAAE,MAAM;GACpC;GACA,QAAQ;EACV,CAAC,GAEK,KAAS,IAA8B,gBAAgB,IAAqB,OAAe;GAC1F,EAAa,UAElB,EAAa,QAAQ,IACrB,EAAK,MAAM,GACX,IAAkB,GAClB,IAAkB,MAEd,KAAoB,QAA0B,CAAS,GAE3D,EAAK,eAAe;IAAE,MAAM;IAAO;GAAO,CAAC;EAC7C,GAEM,KAAQ,IAA4B,mBAAyB;GAC7D,EAAW,SAAS,EAAa,UAErC,EAAa,QAAQ,IACrB,EAAW,OAAO,GAClB,IAAkB,EAAW,kBAAkB,KAAK,MACpD,EAAK,eAAe;IAAE,MAAM;IAAM;GAAO,CAAC;EAC5C,GAEM,UAAqB;GACzB,AAAI,EAAa,QAAO,EAAM,SAAS,IAClC,EAAK,OAAO;EACnB;EAEA,EAA8B;GAC5B,kBAAkB,CAAC,GAAI,CAAO;GAC9B,gBAAgB,EAAa;GAC7B,iBAAiB,EAAM,cAAc;GACrC,QAAQ;EACV,CAAC;EAED,IAAI,IAAc;EAqBlB,AAnBA,EACE,EAAM,OACL,MAAU;GAaT,AAZI,MAAU,KAAA,IACP,IAGH,EAAM,cAAc,IAFhB,EAAM,eAAe,CAAC,SAAO,EAAK,cAAc,IAI7C,IACT,EAAK,cAAc,IAEnB,EAAM,cAAc,GAGtB,IAAc;EAChB,GACA,EAAE,WAAW,GAAK,CACpB,GACA,EAAY,iBACV,eACM;GACC,EAAa,UAElB,EAAa,QAAQ,IACrB,EAAK,MAAM,GACX,IAAkB,GAClB,IAAkB;EACpB,GACA,EAAE,MAAM,GAAK,CACf;EAEA,IAAM,KAAgB,MAA4B;GAChD,IAAM,IAAO,EAAK,aAAa,MAAM,GAC/B,IAAc,EAAoB,CAAI;GAE5C,IAAI,MAAS,YACX,EAAK,gBAAgB,WAAW,CAAC,EAAK,aAAa,SAAS,CAAC;QACxD,IAAI,MAAS,SAClB,KAAK,IAAM,KAAS,EAAG,iBAA8B,+BAA6B,GAChF,EAAM,gBAAgB,WAAW,MAAU,CAAI;GAInD,IAAM,IAAQ,EAAK,aAAa,OAAO,KAAK,IACtC,IAAU,IAAc,EAAK,aAAa,SAAS,IAAI,KAAA;GAI7D,AAFA,EAAK,UAAU;IAAE;IAAS;GAAM,CAAC,GAE5B,KACH,EAAM,cAAc;EAExB,GAEM,IAAwB,EAAkB;GAC9C,MAAM;IAAC;IAAS;IAAK;GAAW;GAChC,eAAe;IAEb,AADA,EAAK,UAAU,GACf,4BAA4B,EAAK,IAAI,CAAC,CAAC;GACzC;EACF,CAAC,GAEK,IAAmC,EAAkB,EACzD,eAAe;GACb,IAAM,IAAU,EAAK,cAAc;GAEnC,AAAI,KAAS,EAAa,CAAO;EACnC,EACF,CAAC;EAGD,SAAS,EAAkB,GAAkB;GAC3C,IAAI,EAAW,OAAO;GAKtB,IAAI,CAHS,EAAa,OAGf;IACT,EAAsB,cAAc,CAAC;IAErC;GACF;GAEA,IAAM,IAAsB,EAAoB;GAIhD,IAFI,KAAuB,KAAG,EAAK,IAAI,CAAmB,GAEtD,EAAE,QAAQ,UAAU;IAEtB,AADA,EAAE,eAAe,GACjB,EAAM,QAAQ;IAEd;GACF;GAEI,OAAK,cAAc,CAAC,GAGxB;QAAI,EAAE,QAAQ,OAAO,EAAE,QAAQ,SAAS;KACtC,EAAiC,cAAc,CAAC;KAEhD;IACF;IAEA,AAAI,EAAE,QAAQ,SACZ,EAAM,cAAc;GAHtB;EAKF;EAsBA,AAnBA,EAAK,EACH,IAAI,EACF,QAAQ,MAAkB;GACxB,IAAM,IAAO,EAAE,aAAa;GAE5B,IAAI,CAAC,EAAa,OAAO;GAKzB,IAAM,IAHe,EAAK,MACvB,MAA8B,aAAgB,eAAe,EAAK,YAAY,eAEpE,KAAiB,EAAE,QAA+B,QAAqB,eAAe,KAAK;GAEpG,CAAC,KAAQ,EAAK,aAAa,UAAU,KAEzC,EAAa,CAAI;EACnB,EACF,EACF,CAAC,GAED,QAAY;GACV,IAAM,IAAO,EAAa;GAErB,KAEL,EAAQ,gBAAgB,aAAa,CAAI;EAC3C,CAAC;EAED,SAAS,IAAiB;GAQxB,IAPA,IAAiB,GACjB,IAAiB,MAIjB,IAFiB,EAAM,SAAS,SAAS,CAAC,CAAC,QAEnB,MAAkC,MAEtD,CAAC,GAAW;GAEhB,IAAM,IAA8B,CAAC,GAC/B,IAAa,EACjB,EACE,MAAM;IACJ,gBAAgB;IAChB,gBAAgB,EAAW;IAC3B,gBAAgB,OAAO,EAAa,KAAK;IACzC,UAAU;GACZ,EACF,GACA,EAAE,QAAQ,EAAU,CACtB,GAEM,KAAkB,MAAsB;IAC5C,EAAM,gBAAgB,GAElB,GAAW,SAEf,EAAO;GACT,GACM,KAAoB,MAAyB;IACjD,EAAkB,CAAK;GACzB;GAOA,AALA,EAAU,iBAAiB,SAAS,CAAc,GAClD,EAAU,iBAAiB,WAAW,CAAgB,GACtD,EAAS,WAAW,GAAW,oBAAoB,SAAS,CAAc,CAAC,GAC3E,EAAS,WAAW,GAAW,oBAAoB,WAAW,CAAgB,CAAC,GAE/E,UAAuB;IACrB,EAAW;IAEX,KAAK,IAAM,KAAW,GAAU,EAAQ;GAC1C;EACF;EAWA,OATA,EAAY,EAAM,SAAS,SAAS,GAAG,GAAgB,EAAE,WAAW,GAAK,CAAC,GAE1E,cACe;GAEX,AADA,IAAiB,GACjB,IAAiB;EACnB,CACD,GAEM,CAAI;;;;;cAKD,EAAO;;;oBAGD,EAAkB;gBACtB,MAA2B;GAEjC,AADA,IAAU,GACV,GAAS,gBAAgB,aAAa,EAAa,KAAK;EAC1D,EAAE;;;;CAIR;CACA,QAAQ;EAAC;EAAiB,EAAiB,CAAgB;EAAG;CAAiB;AACjF,CAAC"}
1
+ {"version":3,"file":"menu.js","names":[],"sources":["../src/overlay/menu/menu.ts"],"sourcesContent":["import type { Placement } from '@vielzeug/orbit';\n\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 restoreTriggerFocus,\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: (_action, index) => {\n const nextItem = getItems()[index];\n\n getItemFocusable(nextItem)?.focus();\n },\n signal: abortSignal,\n });\n\n const close = (reason: DropdownCloseReason = 'programmatic', shouldRestoreFocus = true): void => {\n if (!isOpenSignal.value) return;\n\n isOpenSignal.value = false;\n list.reset();\n stopPositioning?.();\n stopPositioning = null;\n\n if (shouldRestoreFocus) restoreTriggerFocus(() => triggerEl);\n\n emit('open-change', { open: false, reason });\n };\n\n const open = (reason: OverlayOpenReason = 'programmatic'): void => {\n if (isDisabled.value || isOpenSignal.value) return;\n\n isOpenSignal.value = true;\n positioner.update();\n stopPositioning = positioner.startAutoUpdate?.() ?? null;\n emit('open-change', { open: true, reason });\n };\n\n const toggle = (): void => {\n if (isOpenSignal.value) close('trigger');\n else open('click');\n };\n\n createOutsidePointerDismissal({\n getTargets: () => [el, panelEl],\n isActive: () => isOpenSignal.value,\n onDismiss: () => close('outsideClick'),\n signal: abortSignal,\n });\n\n let initialized = false;\n\n rippleWatch(\n props.open,\n (value) => {\n if (value === undefined) {\n if (!initialized) {\n if (props['default-open'].value) open('programmatic');\n } else {\n close('programmatic');\n }\n } else if (value) {\n open('programmatic');\n } else {\n close('programmatic');\n }\n\n initialized = true;\n },\n { immediate: true },\n );\n abortSignal.addEventListener(\n 'abort',\n () => {\n if (!isOpenSignal.value) return;\n\n isOpenSignal.value = false;\n list.reset();\n stopPositioning?.();\n stopPositioning = null;\n },\n { once: true },\n );\n\n const activateItem = (item: HTMLElement): void => {\n const type = item.getAttribute('type');\n const isCheckable = isCheckableItemType(type);\n\n if (type === 'checkbox') {\n item.toggleAttribute('checked', !item.hasAttribute('checked'));\n } else if (type === 'radio') {\n for (const radio of el.querySelectorAll<HTMLElement>('ore-menu-item[type=\"radio\"]')) {\n radio.toggleAttribute('checked', radio === item);\n }\n }\n\n const value = item.getAttribute('value') ?? '';\n const checked = isCheckable ? item.hasAttribute('checked') : undefined;\n\n emit('select', { checked, value });\n\n if (!isCheckable) {\n close('programmatic');\n }\n };\n\n const openFromKeyboardPress = createInteraction({\n keys: ['Enter', ' ', 'ArrowDown'],\n onPress: () => {\n open('keyboard');\n requestAnimationFrame(() => list.set(0));\n },\n });\n\n const activateFocusedFromKeyboardPress = createInteraction({\n onPress: () => {\n const focused = list.getActiveItem();\n\n if (focused) activateItem(focused);\n },\n });\n\n // ── Keyboard Navigation ───────────────────────────────────────────────────\n function handleMenuKeydown(e: KeyboardEvent) {\n if (isDisabled.value) return;\n\n const open = isOpenSignal.value;\n\n // When closed: open on Enter / Space / ArrowDown\n if (!open) {\n openFromKeyboardPress.handleKeydown(e);\n\n return;\n }\n\n const currentFocusedIndex = getFocusedItemIndex();\n\n if (currentFocusedIndex >= 0) list.set(currentFocusedIndex);\n\n if (e.key === 'Escape') {\n e.preventDefault();\n close('escape');\n\n return;\n }\n\n if (list.handleKeydown(e)) return;\n\n // When open: navigate and activate\n if (e.key === ' ' || e.key === 'Enter') {\n activateFocusedFromKeyboardPress.handleKeydown(e);\n\n return;\n }\n\n if (e.key === 'Tab') {\n close('programmatic');\n }\n }\n\n // ── Lifecycle ─────────────────────────────────────────────────────────────\n bind({\n on: {\n click: (e: MouseEvent) => {\n const path = e.composedPath();\n\n if (!isOpenSignal.value) return;\n\n const itemFromPath = path.find(\n (node): node is HTMLElement => node instanceof HTMLElement && node.tagName === 'ORE-MENU-ITEM',\n );\n const item = itemFromPath ?? (e.target as HTMLElement | null)?.closest<HTMLElement>('ore-menu-item') ?? null;\n\n if (!item || item.hasAttribute('disabled')) return;\n\n activateItem(item);\n },\n },\n });\n\n watch(() => {\n const open = isOpenSignal.value;\n\n if (!panelEl) return;\n\n panelEl.toggleAttribute('data-open', open);\n });\n\n function resolveTrigger() {\n cleanupTrigger?.();\n cleanupTrigger = null;\n\n const assigned = slots.elements('trigger').value;\n\n triggerEl = (assigned?.[0] as HTMLElement | undefined) ?? null;\n\n if (!triggerEl) return;\n\n const cleanups: Array<() => void> = [];\n const removeAria = bind(\n {\n aria: {\n controls: () => menuId,\n disabled: () => isDisabled.value,\n expanded: () => String(isOpenSignal.value),\n haspopup: 'menu',\n },\n },\n { target: triggerEl },\n );\n\n const onTriggerClick = (event: MouseEvent) => {\n event.stopPropagation();\n\n if (isDisabled.value) return;\n\n toggle();\n };\n const onTriggerKeydown = (event: KeyboardEvent) => {\n handleMenuKeydown(event);\n };\n\n triggerEl.addEventListener('click', onTriggerClick);\n triggerEl.addEventListener('keydown', onTriggerKeydown);\n cleanups.push(() => triggerEl?.removeEventListener('click', onTriggerClick));\n cleanups.push(() => triggerEl?.removeEventListener('keydown', onTriggerKeydown));\n\n cleanupTrigger = () => {\n removeAria();\n\n for (const cleanup of cleanups) cleanup();\n };\n }\n\n rippleWatch(slots.elements('trigger'), resolveTrigger, { immediate: true });\n\n onMounted(() => {\n 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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"}