@vielzeug/refine 26.10.0 → 26.10.5

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 (468) hide show
  1. package/README.md +1 -1
  2. package/dist/accordion-item.cjs.map +1 -1
  3. package/dist/accordion-item.js.map +1 -1
  4. package/dist/accordion.cjs.map +1 -1
  5. package/dist/accordion.js.map +1 -1
  6. package/dist/async.cjs.map +1 -1
  7. package/dist/async.js.map +1 -1
  8. package/dist/badge.cjs.map +1 -1
  9. package/dist/badge.js.map +1 -1
  10. package/dist/box.cjs.map +1 -1
  11. package/dist/box.js.map +1 -1
  12. package/dist/button.cjs +3 -3
  13. package/dist/button.cjs.map +1 -1
  14. package/dist/button.js +3 -3
  15. package/dist/button.js.map +1 -1
  16. package/dist/calendar.cjs.map +1 -1
  17. package/dist/calendar.js.map +1 -1
  18. package/dist/carousel.cjs.map +1 -1
  19. package/dist/carousel.js.map +1 -1
  20. package/dist/chat-message.cjs.map +1 -1
  21. package/dist/chat-message.js.map +1 -1
  22. package/dist/chat-panel.cjs.map +1 -1
  23. package/dist/chat-panel.js.map +1 -1
  24. package/dist/checkbox-group.cjs.map +1 -1
  25. package/dist/checkbox-group.js.map +1 -1
  26. package/dist/chip.cjs.map +1 -1
  27. package/dist/chip.js.map +1 -1
  28. package/dist/code-window.cjs.map +1 -1
  29. package/dist/code-window.js.map +1 -1
  30. package/dist/combobox.cjs.map +1 -1
  31. package/dist/combobox.js.map +1 -1
  32. package/dist/command-palette.cjs +9 -1
  33. package/dist/command-palette.cjs.map +1 -1
  34. package/dist/command-palette.js +9 -1
  35. package/dist/command-palette.js.map +1 -1
  36. package/dist/content/card/card.css.cjs.map +1 -1
  37. package/dist/content/card/card.css.js.map +1 -1
  38. package/dist/content/carousel/carousel-slide.css.cjs.map +1 -1
  39. package/dist/content/carousel/carousel-slide.css.js.map +1 -1
  40. package/dist/content/carousel/carousel.css.cjs.map +1 -1
  41. package/dist/content/carousel/carousel.css.js.map +1 -1
  42. package/dist/content/carousel/carousel.d.ts +5 -5
  43. package/dist/content/chat-message/chat-message.css.cjs +1 -1
  44. package/dist/content/chat-message/chat-message.css.cjs.map +1 -1
  45. package/dist/content/chat-message/chat-message.css.js +1 -1
  46. package/dist/content/chat-message/chat-message.css.js.map +1 -1
  47. package/dist/content/chat-message/chat-message.d.ts +4 -4
  48. package/dist/content/chat-message/chat-message.d.ts.map +1 -1
  49. package/dist/content/chat-panel/chat-panel.d.ts +1 -1
  50. package/dist/content/code-window/code-window.css.cjs.map +1 -1
  51. package/dist/content/code-window/code-window.css.js.map +1 -1
  52. package/dist/content/code-window/code-window.d.ts +4 -4
  53. package/dist/content/index.d.ts +4 -0
  54. package/dist/content/index.d.ts.map +1 -1
  55. package/dist/content/list/_list-item-reveal.cjs.map +1 -1
  56. package/dist/content/list/_list-item-reveal.d.ts +4 -4
  57. package/dist/content/list/_list-item-reveal.d.ts.map +1 -1
  58. package/dist/content/list/_list-item-reveal.js.map +1 -1
  59. package/dist/content/list/list-item.css.cjs.map +1 -1
  60. package/dist/content/list/list-item.css.js.map +1 -1
  61. package/dist/content/list/list-item.d.ts +8 -8
  62. package/dist/content/list/list-item.d.ts.map +1 -1
  63. package/dist/content/list/list.d.ts +8 -8
  64. package/dist/content/list/list.d.ts.map +1 -1
  65. package/dist/content/qr-code/qr-code.d.ts +1 -1
  66. package/dist/content/rank-list/rank-item.css.cjs +2 -0
  67. package/dist/content/rank-list/rank-item.css.cjs.map +1 -0
  68. package/dist/content/rank-list/rank-item.css.js +2 -0
  69. package/dist/content/rank-list/rank-item.css.js.map +1 -0
  70. package/dist/content/rank-list/rank-item.d.ts +68 -0
  71. package/dist/content/rank-list/rank-item.d.ts.map +1 -0
  72. package/dist/content/rank-list/rank-list.css.cjs +2 -0
  73. package/dist/content/rank-list/rank-list.css.cjs.map +1 -0
  74. package/dist/content/rank-list/rank-list.css.js +2 -0
  75. package/dist/content/rank-list/rank-list.css.js.map +1 -0
  76. package/dist/content/rank-list/rank-list.d.ts +44 -0
  77. package/dist/content/rank-list/rank-list.d.ts.map +1 -0
  78. package/dist/content/separator/separator.d.ts +1 -1
  79. package/dist/content/separator/separator.d.ts.map +1 -1
  80. package/dist/content/speech-player/speech-player.css.cjs.map +1 -1
  81. package/dist/content/speech-player/speech-player.css.js.map +1 -1
  82. package/dist/content/speech-player/speech-player.d.ts +12 -12
  83. package/dist/content/speech-player/speech-player.d.ts.map +1 -1
  84. package/dist/content/stepper/step.css.cjs.map +1 -1
  85. package/dist/content/stepper/step.css.js.map +1 -1
  86. package/dist/content/stepper/step.d.ts +3 -3
  87. package/dist/content/stepper/step.d.ts.map +1 -1
  88. package/dist/content/stepper/stepper.css.cjs.map +1 -1
  89. package/dist/content/stepper/stepper.css.js.map +1 -1
  90. package/dist/content/stepper/stepper.d.ts +3 -3
  91. package/dist/content/stepper/stepper.d.ts.map +1 -1
  92. package/dist/content/table/table.css.cjs.map +1 -1
  93. package/dist/content/table/table.css.js.map +1 -1
  94. package/dist/content/table/table.d.ts +3 -3
  95. package/dist/content/table/table.d.ts.map +1 -1
  96. package/dist/content/text/text.css.cjs.map +1 -1
  97. package/dist/content/text/text.css.js.map +1 -1
  98. package/dist/content/text/text.d.ts +2 -2
  99. package/dist/content/text/text.d.ts.map +1 -1
  100. package/dist/cookie-banner.cjs.map +1 -1
  101. package/dist/cookie-banner.js.map +1 -1
  102. package/dist/copy-command.cjs +1 -1
  103. package/dist/copy-command.cjs.map +1 -1
  104. package/dist/copy-command.js +1 -1
  105. package/dist/copy-command.js.map +1 -1
  106. package/dist/core/announcer.cjs.map +1 -1
  107. package/dist/core/announcer.d.ts +2 -2
  108. package/dist/core/announcer.js.map +1 -1
  109. package/dist/core/aria-reflection.cjs.map +1 -1
  110. package/dist/core/aria-reflection.d.ts +3 -3
  111. package/dist/core/aria-reflection.js.map +1 -1
  112. package/dist/core/auto-resize.cjs.map +1 -1
  113. package/dist/core/auto-resize.d.ts +1 -1
  114. package/dist/core/auto-resize.js.map +1 -1
  115. package/dist/core/checkable.cjs.map +1 -1
  116. package/dist/core/checkable.d.ts +2 -2
  117. package/dist/core/checkable.d.ts.map +1 -1
  118. package/dist/core/checkable.js.map +1 -1
  119. package/dist/core/choice-field.cjs.map +1 -1
  120. package/dist/core/choice-field.d.ts +3 -3
  121. package/dist/core/choice-field.d.ts.map +1 -1
  122. package/dist/core/choice-field.js.map +1 -1
  123. package/dist/core/composer.cjs.map +1 -1
  124. package/dist/core/composer.d.ts +4 -4
  125. package/dist/core/composer.d.ts.map +1 -1
  126. package/dist/core/composer.js.map +1 -1
  127. package/dist/core/date-picker.cjs.map +1 -1
  128. package/dist/core/date-picker.d.ts +5 -5
  129. package/dist/core/date-picker.d.ts.map +1 -1
  130. package/dist/core/date-picker.js.map +1 -1
  131. package/dist/core/direction.cjs.map +1 -1
  132. package/dist/core/direction.d.ts +1 -1
  133. package/dist/core/direction.js.map +1 -1
  134. package/dist/core/field-base.cjs.map +1 -1
  135. package/dist/core/field-base.d.ts +9 -9
  136. package/dist/core/field-base.d.ts.map +1 -1
  137. package/dist/core/field-base.js.map +1 -1
  138. package/dist/core/focus.cjs.map +1 -1
  139. package/dist/core/focus.d.ts +1 -1
  140. package/dist/core/focus.js.map +1 -1
  141. package/dist/core/icon-registry.cjs.map +1 -1
  142. package/dist/core/icon-registry.d.ts +1 -1
  143. package/dist/core/icon-registry.js.map +1 -1
  144. package/dist/core/icons.cjs.map +1 -1
  145. package/dist/core/icons.js.map +1 -1
  146. package/dist/core/keyboard.cjs.map +1 -1
  147. package/dist/core/keyboard.d.ts +1 -1
  148. package/dist/core/keyboard.js.map +1 -1
  149. package/dist/core/numbers.cjs.map +1 -1
  150. package/dist/core/numbers.d.ts +1 -1
  151. package/dist/core/numbers.js.map +1 -1
  152. package/dist/core/overlay.cjs.map +1 -1
  153. package/dist/core/overlay.d.ts +6 -6
  154. package/dist/core/overlay.js.map +1 -1
  155. package/dist/core/parse.cjs.map +1 -1
  156. package/dist/core/parse.d.ts +1 -1
  157. package/dist/core/parse.js.map +1 -1
  158. package/dist/core/positioner.cjs.map +1 -1
  159. package/dist/core/positioner.d.ts +3 -3
  160. package/dist/core/positioner.js.map +1 -1
  161. package/dist/core/ref-callback.cjs.map +1 -1
  162. package/dist/core/ref-callback.d.ts +2 -2
  163. package/dist/core/ref-callback.d.ts.map +1 -1
  164. package/dist/core/ref-callback.js.map +1 -1
  165. package/dist/core/text-field.cjs.map +1 -1
  166. package/dist/core/text-field.d.ts +6 -6
  167. package/dist/core/text-field.d.ts.map +1 -1
  168. package/dist/core/text-field.js.map +1 -1
  169. package/dist/counter.cjs +1 -0
  170. package/dist/counter.cjs.map +1 -1
  171. package/dist/counter.js +1 -0
  172. package/dist/counter.js.map +1 -1
  173. package/dist/custom-elements.json +334 -87
  174. package/dist/datagrid.cjs.map +1 -1
  175. package/dist/datagrid.js.map +1 -1
  176. package/dist/date-picker.cjs +1 -1
  177. package/dist/date-picker.cjs.map +1 -1
  178. package/dist/date-picker.js +1 -1
  179. package/dist/date-picker.js.map +1 -1
  180. package/dist/dialog.cjs.map +1 -1
  181. package/dist/dialog.js.map +1 -1
  182. package/dist/disclosure/accordion-item/accordion-item.css.cjs +1 -1
  183. package/dist/disclosure/accordion-item/accordion-item.css.cjs.map +1 -1
  184. package/dist/disclosure/accordion-item/accordion-item.css.js +1 -1
  185. package/dist/disclosure/accordion-item/accordion-item.css.js.map +1 -1
  186. package/dist/disclosure/tab-item/tab-item.d.ts +1 -1
  187. package/dist/disclosure/tab-item/tab-item.d.ts.map +1 -1
  188. package/dist/drawer.cjs.map +1 -1
  189. package/dist/drawer.js.map +1 -1
  190. package/dist/feedback/alert/alert.css.cjs.map +1 -1
  191. package/dist/feedback/alert/alert.css.js.map +1 -1
  192. package/dist/feedback/badge/badge.css.cjs.map +1 -1
  193. package/dist/feedback/badge/badge.css.js.map +1 -1
  194. package/dist/feedback/badge/badge.d.ts +1 -1
  195. package/dist/feedback/badge/badge.d.ts.map +1 -1
  196. package/dist/feedback/chip/chip.css.cjs.map +1 -1
  197. package/dist/feedback/chip/chip.css.js.map +1 -1
  198. package/dist/feedback/chip/chip.d.ts +3 -3
  199. package/dist/feedback/chip/chip.d.ts.map +1 -1
  200. package/dist/feedback/cookie-banner/cookie-banner.css.cjs.map +1 -1
  201. package/dist/feedback/cookie-banner/cookie-banner.css.js.map +1 -1
  202. package/dist/feedback/cookie-banner/cookie-banner.d.ts +8 -8
  203. package/dist/feedback/cookie-banner/cookie-banner.d.ts.map +1 -1
  204. package/dist/feedback/progress/progress.css.cjs.map +1 -1
  205. package/dist/feedback/progress/progress.css.js.map +1 -1
  206. package/dist/feedback/progress/progress.d.ts +1 -1
  207. package/dist/feedback/progress/progress.d.ts.map +1 -1
  208. package/dist/feedback/skeleton/skeleton.css.cjs.map +1 -1
  209. package/dist/feedback/skeleton/skeleton.css.js.map +1 -1
  210. package/dist/feedback/skeleton/skeleton.d.ts +1 -1
  211. package/dist/feedback/skeleton/skeleton.d.ts.map +1 -1
  212. package/dist/feedback/toast/toast.css.cjs +1 -1
  213. package/dist/feedback/toast/toast.css.cjs.map +1 -1
  214. package/dist/feedback/toast/toast.css.js +1 -1
  215. package/dist/feedback/toast/toast.css.js.map +1 -1
  216. package/dist/feedback/toast/toast.d.ts +1 -1
  217. package/dist/feedback/toast/toast.d.ts.map +1 -1
  218. package/dist/feedback/typing-indicator/typing-indicator.d.ts +2 -2
  219. package/dist/file-input.cjs +1 -1
  220. package/dist/file-input.cjs.map +1 -1
  221. package/dist/file-input.js +1 -1
  222. package/dist/file-input.js.map +1 -1
  223. package/dist/frameworks/elements.d.ts +1 -1
  224. package/dist/grid-item.cjs.map +1 -1
  225. package/dist/grid-item.js.map +1 -1
  226. package/dist/grid.cjs.map +1 -1
  227. package/dist/grid.js.map +1 -1
  228. package/dist/icon.cjs.map +1 -1
  229. package/dist/icon.js.map +1 -1
  230. package/dist/input.cjs.map +1 -1
  231. package/dist/input.js.map +1 -1
  232. package/dist/inputs/button/button.css.cjs.map +1 -1
  233. package/dist/inputs/button/button.css.js.map +1 -1
  234. package/dist/inputs/button/button.d.ts +3 -3
  235. package/dist/inputs/button/button.d.ts.map +1 -1
  236. package/dist/inputs/calendar/calendar.css.cjs.map +1 -1
  237. package/dist/inputs/calendar/calendar.css.js.map +1 -1
  238. package/dist/inputs/calendar/calendar.d.ts +2 -2
  239. package/dist/inputs/checkbox-group/checkbox-group.d.ts +2 -2
  240. package/dist/inputs/checkbox-group/checkbox-group.d.ts.map +1 -1
  241. package/dist/inputs/combobox/combobox.css.cjs.map +1 -1
  242. package/dist/inputs/combobox/combobox.css.js.map +1 -1
  243. package/dist/inputs/counter/counter.css.cjs +1 -1
  244. package/dist/inputs/counter/counter.css.cjs.map +1 -1
  245. package/dist/inputs/counter/counter.css.js +1 -1
  246. package/dist/inputs/counter/counter.css.js.map +1 -1
  247. package/dist/inputs/counter/counter.d.ts +2 -1
  248. package/dist/inputs/counter/counter.d.ts.map +1 -1
  249. package/dist/inputs/datagrid/datagrid.css.cjs.map +1 -1
  250. package/dist/inputs/datagrid/datagrid.css.js.map +1 -1
  251. package/dist/inputs/datagrid/datagrid.d.ts +5 -5
  252. package/dist/inputs/date-picker/date-picker.css.cjs.map +1 -1
  253. package/dist/inputs/date-picker/date-picker.css.js.map +1 -1
  254. package/dist/inputs/date-picker/date-picker.d.ts +1 -1
  255. package/dist/inputs/file-input/file-input-upload.cjs.map +1 -1
  256. package/dist/inputs/file-input/file-input-upload.d.ts +6 -6
  257. package/dist/inputs/file-input/file-input-upload.js.map +1 -1
  258. package/dist/inputs/file-input/file-input.css.cjs.map +1 -1
  259. package/dist/inputs/file-input/file-input.css.js.map +1 -1
  260. package/dist/inputs/file-input/file-input.d.ts +6 -6
  261. package/dist/inputs/input/input.css.cjs +1 -1
  262. package/dist/inputs/input/input.css.cjs.map +1 -1
  263. package/dist/inputs/input/input.css.js +1 -1
  264. package/dist/inputs/input/input.css.js.map +1 -1
  265. package/dist/inputs/input/input.d.ts +6 -6
  266. package/dist/inputs/input/input.d.ts.map +1 -1
  267. package/dist/inputs/message-composer/message-composer.css.cjs.map +1 -1
  268. package/dist/inputs/message-composer/message-composer.css.js.map +1 -1
  269. package/dist/inputs/message-composer/message-composer.d.ts +7 -7
  270. package/dist/inputs/message-composer/message-composer.d.ts.map +1 -1
  271. package/dist/inputs/number-input/number-input.css.cjs.map +1 -1
  272. package/dist/inputs/number-input/number-input.css.js.map +1 -1
  273. package/dist/inputs/number-input/number-input.d.ts +2 -2
  274. package/dist/inputs/otp-input/otp-input.css.cjs.map +1 -1
  275. package/dist/inputs/otp-input/otp-input.css.js.map +1 -1
  276. package/dist/inputs/qr-scanner/qr-scanner.d.ts +1 -1
  277. package/dist/inputs/qr-scanner/qr-scanner.d.ts.map +1 -1
  278. package/dist/inputs/rating/rating.d.ts +1 -1
  279. package/dist/inputs/rating/rating.d.ts.map +1 -1
  280. package/dist/inputs/select/select.css.cjs +1 -1
  281. package/dist/inputs/select/select.css.cjs.map +1 -1
  282. package/dist/inputs/select/select.css.js +1 -1
  283. package/dist/inputs/select/select.css.js.map +1 -1
  284. package/dist/inputs/select/select.d.ts +1 -1
  285. package/dist/inputs/select/select.d.ts.map +1 -1
  286. package/dist/inputs/shared/field-binding.cjs.map +1 -1
  287. package/dist/inputs/shared/field-binding.d.ts +2 -2
  288. package/dist/inputs/shared/field-binding.d.ts.map +1 -1
  289. package/dist/inputs/shared/field-binding.js.map +1 -1
  290. package/dist/inputs/shared/native-field-event.cjs.map +1 -1
  291. package/dist/inputs/shared/native-field-event.d.ts +1 -1
  292. package/dist/inputs/shared/native-field-event.js.map +1 -1
  293. package/dist/inputs/shared/templates.cjs.map +1 -1
  294. package/dist/inputs/shared/templates.d.ts +3 -3
  295. package/dist/inputs/shared/templates.js.map +1 -1
  296. package/dist/inputs/slider/slider.css.cjs.map +1 -1
  297. package/dist/inputs/slider/slider.css.js.map +1 -1
  298. package/dist/inputs/slider/slider.d.ts +1 -1
  299. package/dist/inputs/slider/slider.d.ts.map +1 -1
  300. package/dist/inputs/textarea/textarea.css.cjs.map +1 -1
  301. package/dist/inputs/textarea/textarea.css.js.map +1 -1
  302. package/dist/inputs/textarea/textarea.d.ts +1 -1
  303. package/dist/inputs/time-picker/time-picker.css.cjs.map +1 -1
  304. package/dist/inputs/time-picker/time-picker.css.js.map +1 -1
  305. package/dist/inputs/time-picker/time-picker.d.ts +1 -1
  306. package/dist/layout/box/box.css.cjs.map +1 -1
  307. package/dist/layout/box/box.css.js.map +1 -1
  308. package/dist/layout/box/box.d.ts +1 -1
  309. package/dist/layout/grid/grid.d.ts +1 -1
  310. package/dist/layout/grid-item/grid-item.d.ts +3 -3
  311. package/dist/layout/grid-item/grid-item.d.ts.map +1 -1
  312. package/dist/layout/navbar/navbar.css.cjs +1 -1
  313. package/dist/layout/navbar/navbar.css.cjs.map +1 -1
  314. package/dist/layout/navbar/navbar.css.js +1 -1
  315. package/dist/layout/navbar/navbar.css.js.map +1 -1
  316. package/dist/layout/navbar/navbar.d.ts +3 -3
  317. package/dist/layout/sidebar/sidebar-item.css.cjs.map +1 -1
  318. package/dist/layout/sidebar/sidebar-item.css.js.map +1 -1
  319. package/dist/layout/sidebar/sidebar.d.ts +5 -5
  320. package/dist/layout/sidebar/sidebar.d.ts.map +1 -1
  321. package/dist/list-item.cjs.map +1 -1
  322. package/dist/list-item.js.map +1 -1
  323. package/dist/list.cjs.map +1 -1
  324. package/dist/list.js.map +1 -1
  325. package/dist/menu.cjs +6 -5
  326. package/dist/menu.cjs.map +1 -1
  327. package/dist/menu.js +6 -5
  328. package/dist/menu.js.map +1 -1
  329. package/dist/message-composer.cjs.map +1 -1
  330. package/dist/message-composer.js.map +1 -1
  331. package/dist/navbar.cjs.map +1 -1
  332. package/dist/navbar.js.map +1 -1
  333. package/dist/number-input.cjs.map +1 -1
  334. package/dist/number-input.js.map +1 -1
  335. package/dist/otp-input.cjs.map +1 -1
  336. package/dist/otp-input.js.map +1 -1
  337. package/dist/overlay/command-palette/command-palette-items.cjs.map +1 -1
  338. package/dist/overlay/command-palette/command-palette-items.d.ts +1 -1
  339. package/dist/overlay/command-palette/command-palette-items.js.map +1 -1
  340. package/dist/overlay/command-palette/command-palette.css.cjs +1 -1
  341. package/dist/overlay/command-palette/command-palette.css.cjs.map +1 -1
  342. package/dist/overlay/command-palette/command-palette.css.js +1 -1
  343. package/dist/overlay/command-palette/command-palette.css.js.map +1 -1
  344. package/dist/overlay/command-palette/command-palette.d.ts +7 -3
  345. package/dist/overlay/command-palette/command-palette.d.ts.map +1 -1
  346. package/dist/overlay/command-palette/command-palette.types.d.ts +16 -6
  347. package/dist/overlay/command-palette/command-palette.types.d.ts.map +1 -1
  348. package/dist/overlay/dialog/dialog.css.cjs +1 -1
  349. package/dist/overlay/dialog/dialog.css.cjs.map +1 -1
  350. package/dist/overlay/dialog/dialog.css.js +1 -1
  351. package/dist/overlay/dialog/dialog.css.js.map +1 -1
  352. package/dist/overlay/dialog/dialog.d.ts +2 -2
  353. package/dist/overlay/dialog/dialog.d.ts.map +1 -1
  354. package/dist/overlay/drawer/drawer.css.cjs.map +1 -1
  355. package/dist/overlay/drawer/drawer.css.js.map +1 -1
  356. package/dist/overlay/drawer/drawer.d.ts +1 -1
  357. package/dist/overlay/drawer/drawer.d.ts.map +1 -1
  358. package/dist/overlay/menu/menu-item.css.cjs.map +1 -1
  359. package/dist/overlay/menu/menu-item.css.js.map +1 -1
  360. package/dist/overlay/menu/menu.d.ts.map +1 -1
  361. package/dist/overlay/shared/use-dialog.cjs.map +1 -1
  362. package/dist/overlay/shared/use-dialog.d.ts +6 -6
  363. package/dist/overlay/shared/use-dialog.d.ts.map +1 -1
  364. package/dist/overlay/shared/use-dialog.js.map +1 -1
  365. package/dist/overlay/shared/use-floating-trigger.cjs.map +1 -1
  366. package/dist/overlay/shared/use-floating-trigger.d.ts +1 -1
  367. package/dist/overlay/shared/use-floating-trigger.d.ts.map +1 -1
  368. package/dist/overlay/shared/use-floating-trigger.js.map +1 -1
  369. package/dist/overlay/tooltip/tooltip.css.cjs.map +1 -1
  370. package/dist/overlay/tooltip/tooltip.css.js.map +1 -1
  371. package/dist/progress.cjs.map +1 -1
  372. package/dist/progress.js.map +1 -1
  373. package/dist/qr-code.cjs.map +1 -1
  374. package/dist/qr-code.js.map +1 -1
  375. package/dist/qr-scanner.cjs.map +1 -1
  376. package/dist/qr-scanner.js.map +1 -1
  377. package/dist/radio-group.cjs.map +1 -1
  378. package/dist/radio-group.js.map +1 -1
  379. package/dist/radio.cjs.map +1 -1
  380. package/dist/radio.js.map +1 -1
  381. package/dist/rank-item.cjs +21 -0
  382. package/dist/rank-item.cjs.map +1 -0
  383. package/dist/rank-item.js +21 -0
  384. package/dist/rank-item.js.map +1 -0
  385. package/dist/rank-list.cjs +4 -0
  386. package/dist/rank-list.cjs.map +1 -0
  387. package/dist/rank-list.js +4 -0
  388. package/dist/rank-list.js.map +1 -0
  389. package/dist/rating.cjs.map +1 -1
  390. package/dist/rating.js.map +1 -1
  391. package/dist/refine.cjs +111 -80
  392. package/dist/refine.cjs.map +1 -1
  393. package/dist/refine.iife.js +111 -80
  394. package/dist/refine.iife.js.map +1 -1
  395. package/dist/refine.js +112 -81
  396. package/dist/refine.js.map +1 -1
  397. package/dist/select.cjs.map +1 -1
  398. package/dist/select.js.map +1 -1
  399. package/dist/separator.cjs.map +1 -1
  400. package/dist/separator.js.map +1 -1
  401. package/dist/shared/index.d.ts +3 -3
  402. package/dist/shared/size-presets.cjs.map +1 -1
  403. package/dist/shared/size-presets.d.ts +4 -4
  404. package/dist/shared/size-presets.js.map +1 -1
  405. package/dist/shared/types.d.ts +1 -1
  406. package/dist/sidebar.cjs.map +1 -1
  407. package/dist/sidebar.js.map +1 -1
  408. package/dist/skeleton.cjs.map +1 -1
  409. package/dist/skeleton.js.map +1 -1
  410. package/dist/slider.cjs.map +1 -1
  411. package/dist/slider.js.map +1 -1
  412. package/dist/speech-player.cjs.map +1 -1
  413. package/dist/speech-player.js.map +1 -1
  414. package/dist/step.cjs.map +1 -1
  415. package/dist/step.js.map +1 -1
  416. package/dist/stepper.cjs.map +1 -1
  417. package/dist/stepper.js.map +1 -1
  418. package/dist/styles/fouc.css +2 -2
  419. package/dist/styles/mixins/accessibility.css.cjs.map +1 -1
  420. package/dist/styles/mixins/accessibility.css.d.ts +4 -4
  421. package/dist/styles/mixins/accessibility.css.js.map +1 -1
  422. package/dist/styles/mixins/animation.css.cjs +2 -2
  423. package/dist/styles/mixins/animation.css.cjs.map +1 -1
  424. package/dist/styles/mixins/animation.css.d.ts +4 -4
  425. package/dist/styles/mixins/animation.css.js +2 -2
  426. package/dist/styles/mixins/animation.css.js.map +1 -1
  427. package/dist/styles/mixins/field-variants.css.cjs +2 -2
  428. package/dist/styles/mixins/field-variants.css.cjs.map +1 -1
  429. package/dist/styles/mixins/field-variants.css.d.ts +6 -6
  430. package/dist/styles/mixins/field-variants.css.d.ts.map +1 -1
  431. package/dist/styles/mixins/field-variants.css.js +2 -2
  432. package/dist/styles/mixins/field-variants.css.js.map +1 -1
  433. package/dist/styles/mixins/shape.css.cjs.map +1 -1
  434. package/dist/styles/mixins/shape.css.d.ts +9 -9
  435. package/dist/styles/mixins/shape.css.d.ts.map +1 -1
  436. package/dist/styles/mixins/shape.css.js.map +1 -1
  437. package/dist/styles/mixins/variants.css.cjs.map +1 -1
  438. package/dist/styles/mixins/variants.css.d.ts +1 -1
  439. package/dist/styles/mixins/variants.css.js.map +1 -1
  440. package/dist/styles/theme.css +36 -28
  441. package/dist/tab-item.cjs.map +1 -1
  442. package/dist/tab-item.js.map +1 -1
  443. package/dist/tab-panel.cjs.map +1 -1
  444. package/dist/tab-panel.js.map +1 -1
  445. package/dist/table.cjs.map +1 -1
  446. package/dist/table.js.map +1 -1
  447. package/dist/text.cjs.map +1 -1
  448. package/dist/text.js.map +1 -1
  449. package/dist/textarea.cjs.map +1 -1
  450. package/dist/textarea.js.map +1 -1
  451. package/dist/theme.cjs.map +1 -1
  452. package/dist/theme.d.ts +2 -2
  453. package/dist/theme.js.map +1 -1
  454. package/dist/time-picker.cjs +1 -1
  455. package/dist/time-picker.cjs.map +1 -1
  456. package/dist/time-picker.js +1 -1
  457. package/dist/time-picker.js.map +1 -1
  458. package/dist/toast.cjs.map +1 -1
  459. package/dist/toast.js.map +1 -1
  460. package/dist/types/elements.d.ts +6 -2
  461. package/dist/typing-indicator.cjs.map +1 -1
  462. package/dist/typing-indicator.js.map +1 -1
  463. package/dist/utils/css.cjs.map +1 -1
  464. package/dist/utils/css.js.map +1 -1
  465. package/dist/utils/link.cjs.map +1 -1
  466. package/dist/utils/link.d.ts +2 -2
  467. package/dist/utils/link.js.map +1 -1
  468. package/package.json +31 -14
package/dist/button.js CHANGED
@@ -1,4 +1,4 @@
1
- import{coarsePointerMixin as e,reducedMotionMixin as t}from"./styles/mixins/accessibility.css.js";import{rainbowEffectMixin as n,shineEffectMixin as r}from"./styles/mixins/animation.css.js";import{roundedVariantMixin as i,sizeVariantMixin as a}from"./styles/mixins/shape.css.js";import{disabledLoadingMixin as o}from"./styles/mixins/states.css.js";import{colorThemeMixin as s,forcedColorsMixin as c}from"./styles/mixins/theme.css.js";import{frostVariantMixin as l}from"./styles/mixins/variants.css.js";import{commonProps as u}from"./shared/prop-bundles.js";import{useLinkProps as d}from"./utils/link.js";import{BUTTON_GROUP_CTX as f}from"./button-group.js";import{useFormAction as p}from"./inputs/shared/use-form-action.js";import m from"./inputs/button/button.css.js";import{computed as h}from"@vielzeug/ripple";import{bind as g,define as _,getHost as v,html as y,inject as b,prop as x,useField as S}from"@vielzeug/ore";var C=[`solid`,`flat`,`bordered`,`outline`,`ghost`,`text`,`frost`],w=`ore-button`;_(w,{formAssociated:!0,props:{...u,effect:x.string(),fullheight:x.bool(!1),fullwidth:x.bool(!1),href:x.string(),iconOnly:x.bool(!1),label:x.string(),rel:x.string(),target:x.string(),type:x.oneOf([`button`,`submit`,`reset`],`button`),variant:x.oneOf(C,`solid`)},setup(e){let t=v(),n=b(f),r=h(()=>n?.color.value??e.color.value),i=h(()=>n?.size.value??e.size.value),a=h(()=>n?.variant.value??e.variant.value),o=h(()=>!!(e.disabled.value||e.loading.value)),{effectiveRel:s,isLink:c}=d(e.href,e.rel,e.target),l=S({disabled:o,toFormValue:()=>null,value:h(()=>``)}),handleClick=n=>{if(o.value){n.preventDefault();return}p(()=>c.value?null:l.internals.form,e.type,o,t)(n)},handleKeydown=e=>{c.value||(e.key===`Enter`||e.key===` `)&&(e.preventDefault(),(t.shadowRoot?.querySelector(`[part="button"]`))?.click())};g({attr:{"aria-busy":h(()=>c.value?null:e.loading.value),"aria-disabled":h(()=>c.value?null:o.value),"aria-label":h(()=>c.value?null:e.label.value),color:r,effect:e.effect,role:h(()=>c.value?null:t.getAttribute(`role`)??`button`),size:i,tabindex:h(()=>c.value?null:o.value?`-1`:`0`),variant:a},on:{keydown:handleKeydown}});let u=y`
1
+ import{coarsePointerMixin as e,reducedMotionMixin as t}from"./styles/mixins/accessibility.css.js";import{rainbowEffectMixin as n,shineEffectMixin as r}from"./styles/mixins/animation.css.js";import{roundedVariantMixin as i,sizeVariantMixin as a}from"./styles/mixins/shape.css.js";import{disabledLoadingMixin as o}from"./styles/mixins/states.css.js";import{colorThemeMixin as s,forcedColorsMixin as c}from"./styles/mixins/theme.css.js";import{frostVariantMixin as l}from"./styles/mixins/variants.css.js";import{commonProps as u}from"./shared/prop-bundles.js";import{useLinkProps as d}from"./utils/link.js";import{BUTTON_GROUP_CTX as f}from"./button-group.js";import{useFormAction as p}from"./inputs/shared/use-form-action.js";import m from"./inputs/button/button.css.js";import{computed as h}from"@vielzeug/ripple";import{bind as g,define as _,getHost as v,html as y,inject as b,prop as x,useField as S}from"@vielzeug/ore";var C=[`solid`,`flat`,`bordered`,`outline`,`ghost`,`text`,`frost`],w=`ore-button`;_(w,{formAssociated:!0,props:{...u,effect:x.string(),fullheight:x.bool(!1),fullwidth:x.bool(!1),href:x.string(),iconOnly:x.bool(!1),label:x.string(),rel:x.string(),target:x.string(),type:x.oneOf([`button`,`submit`,`reset`],`button`),variant:x.oneOf(C,`solid`)},setup(e){let t=v(),n=b(f),r=h(()=>n?.color.value??e.color.value),i=h(()=>n?.size.value??e.size.value),a=h(()=>n?.variant.value??e.variant.value),o=h(()=>!!(e.disabled.value||e.loading.value)),{effectiveRel:s,isLink:c}=d(e.href,e.rel,e.target),l=S({disabled:o,toFormValue:()=>null,value:h(()=>``)}),handleClick=n=>{if(o.value){n.preventDefault();return}p(()=>c.value?null:l.internals.form,e.type,o,t)(n)},handleKeydown=e=>{c.value||(e.key===`Enter`||e.key===` `)&&(e.preventDefault(),(t.shadowRoot?.querySelector(`[part="button"]`))?.click())};g({attr:{"aria-busy":h(()=>c.value?null:e.loading.value),"aria-disabled":h(()=>c.value?null:o.value),"aria-label":h(()=>c.value?null:e.label.value),color:r,effect:e.effect,role:h(()=>c.value?null:t.getAttribute(`role`)??`button`),size:i,tabindex:h(()=>c.value?null:o.value?`-1`:`0`),variant:a},on:{keydown:handleKeydown}});let buttonContent=()=>y`
2
2
  <span class="loader" part="loader" aria-label="Loading" ?hidden=${()=>!e.loading.value}></span>
3
3
  <slot name="prefix"></slot>
4
4
  <span class="content" part="content"><slot></slot></span>
@@ -15,10 +15,10 @@ import{coarsePointerMixin as e,reducedMotionMixin as t}from"./styles/mixins/acce
15
15
  rel="${s}"
16
16
  target="${e.target}"
17
17
  @click="${handleClick}">
18
- ${u}
18
+ ${buttonContent()}
19
19
  </a>
20
20
  `:y`
21
- <span part="button" role="presentation" @click="${handleClick}">${u}</span>
21
+ <span part="button" role="presentation" @click="${handleClick}">${buttonContent()}</span>
22
22
  `}
23
23
  `},shadow:{delegatesFocus:!1},styles:[s,e,t,i,c,a({lg:{fontSize:`var(--text-base)`,gap:`var(--size-2-5)`,height:`var(--size-12)`,iconSize:`var(--size-6)`,lineHeight:`var(--leading-relaxed)`,padding:`var(--size-2-5) var(--size-5)`},sm:{fontSize:`var(--text-sm)`,gap:`var(--size-1-5)`,height:`var(--size-8)`,iconSize:`var(--size-4)`,lineHeight:`var(--leading-tight)`,padding:`var(--size-1-5) var(--size-3)`}}),l(`[part="button"]`),n(`[part="button"]`),r(`[part="button"]`),o,m]});export{w as BUTTON_TAG,C as BUTTON_VARIANTS};
24
24
  //# sourceMappingURL=button.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"button.js","names":[],"sources":["../src/inputs/button/button.ts"],"sourcesContent":["import { bind, define, getHost, html, inject, prop, useField } from '@vielzeug/ore';\nimport { computed } from '@vielzeug/ripple';\nimport { commonProps } from '../../shared';\nimport {\n coarsePointerMixin,\n colorThemeMixin,\n disabledLoadingMixin,\n forcedColorsMixin,\n frostVariantMixin,\n rainbowEffectMixin,\n reducedMotionMixin,\n roundedVariantMixin,\n shineEffectMixin,\n sizeVariantMixin,\n} from '../../styles';\nimport type { ButtonType, ComponentSize, LinkTarget, RoundedSize, ThemeColor } from '../../types';\nimport { useLinkProps } from '../../utils';\nimport { BUTTON_GROUP_CTX } from '../button-group/button-group';\nimport { useFormAction } from '../shared';\nimport componentStyles from './button.css?inline';\n\nexport const BUTTON_VARIANTS = ['solid', 'flat', 'bordered', 'outline', 'ghost', 'text', 'frost'] as const;\n\n/** Visual variant for ore-button — derived from BUTTON_VARIANTS for a single source of truth. */\nexport type ButtonVariant = (typeof BUTTON_VARIANTS)[number];\n\n/** Animated border effect for ore-button. */\nexport type ButtonEffect = 'shine' | 'rainbow';\n\n/** Button component properties */\nexport type OreButtonProps = {\n /** Theme color */\n color?: ThemeColor;\n /** Disable interaction */\n disabled?: boolean;\n /** Animated border effect: 'shine' (color-aware neon sweep) or 'rainbow' */\n effect?: ButtonEffect;\n /**\n * Full height button (100% of container) — the inner `[part=\"button\"]` fills its host's\n * height instead of the size preset's fixed height. Useful when the button itself is the\n * whole tappable surface of a container it doesn't otherwise control the size of (e.g. a\n * swipe-revealed row action in `ore-list-item`'s `actions-left`/`actions-right` slots).\n */\n fullheight?: boolean;\n /** Full width button (100% of container) */\n fullwidth?: boolean;\n /** When set, renders an `<a>` instead of `<button>` */\n href?: string;\n /** Icon-only mode (square aspect ratio, no padding) */\n iconOnly?: boolean;\n /** Accessible label for the inner button — required for icon-only buttons */\n label?: string;\n /** Show loading state with spinner */\n loading?: boolean;\n /** Link rel attribute (requires href) */\n rel?: string;\n /** Border radius size */\n rounded?: RoundedSize;\n /** Component size */\n size?: ComponentSize;\n /** Link target (requires href) */\n target?: LinkTarget;\n /** HTML button type attribute */\n type?: ButtonType;\n /** Visual style variant */\n variant?: ButtonVariant;\n};\n\n/**\n * A customizable button component with multiple variants, sizes, and states.\n * Supports icons, loading states, and animated border effects.\n *\n * @element ore-button\n *\n * @attr {string} type - HTML button type: 'button' | 'submit' | 'reset'\n * @attr {boolean} disabled - Disable button interaction\n * @attr {boolean} loading - Show loading state with spinner\n * @attr {string} color - Theme color: 'primary' | 'secondary' | 'info' | 'success' | 'warning' | 'error'\n * @attr {string} variant - Visual variant: 'solid' | 'flat' | 'bordered' | 'outline' | 'ghost' | 'text' | 'frost'\n * @attr {string} size - Button size: 'sm' | 'md' | 'lg'\n * @attr {string} rounded - Border radius: 'none' | 'sm' | 'md' | 'lg' | 'xl' | '2xl' | '3xl' | 'full'\n * @attr {string} effect - Animated border effect: 'shine' | 'rainbow'\n * @attr {boolean} icon-only - Icon-only mode (square aspect ratio, no padding)\n * @attr {boolean} fullwidth - Full width button (100% of container)\n * @attr {boolean} fullheight - Full height button (100% of container)\n *\n * @fires click - Emitted when button is clicked (unless disabled/loading)\n *\n * @slot - Button content (text, icons, etc.)\n * @slot prefix - Content before the button text (e.g., icons)\n * @slot suffix - Content after the button text (e.g., icons, badges)\n *\n * @part button - The inner button or anchor element\n * @part loader - The loading spinner element\n * @part content - The button content wrapper\n *\n * @cssprop --button-bg - Background color override\n * @cssprop --button-color - Text color override\n * @cssprop --button-border - Border width override\n * @cssprop --button-border-color - Border color override\n * @cssprop --button-radius - Border radius override\n * @cssprop --button-padding - Inner padding override\n * @cssprop --button-gap - Gap between icon and text override\n * @cssprop --button-font-size - Font size override\n * @cssprop --button-frost-active-bg - Background when pressed (frost variant)\n * @cssprop --button-frost-active-border-color - Border color when pressed (frost variant)\n *\n * @example\n * ```html\n * <ore-button variant=\"solid\" color=\"primary\">Click me</ore-button>\n * <ore-button loading color=\"success\">Processing...</ore-button>\n * <ore-button effect=\"shine\" color=\"primary\">Shine</ore-button>\n * <ore-button effect=\"rainbow\" variant=\"frost\">Rainbow</ore-button>\n * ```\n */\nexport const BUTTON_TAG = 'ore-button' as const;\ndefine<OreButtonProps>(BUTTON_TAG, {\n formAssociated: true,\n props: {\n ...commonProps,\n effect: prop.string<ButtonEffect>(),\n fullheight: prop.bool(false),\n fullwidth: prop.bool(false),\n href: prop.string(),\n iconOnly: prop.bool(false),\n label: prop.string(),\n rel: prop.string(),\n target: prop.string<LinkTarget>(),\n type: prop.oneOf(['button', 'submit', 'reset'] as const, 'button'),\n variant: prop.oneOf(BUTTON_VARIANTS, 'solid'),\n },\n setup(props) {\n const el = getHost();\n\n // Prefer group context over own props for color/size/variant.\n const groupCtx = inject(BUTTON_GROUP_CTX);\n const effectiveColor = computed(() => groupCtx?.color.value ?? props.color.value);\n const effectiveSize = computed(() => groupCtx?.size.value ?? props.size.value);\n const effectiveVariant = computed(() => groupCtx?.variant.value ?? props.variant.value);\n\n const isDisabled = computed(() => !!(props.disabled.value || props.loading.value));\n\n // isLink and effectiveRel are computed from signals — correct even if href changes at runtime.\n const { effectiveRel, isLink } = useLinkProps(props.href, props.rel, props.target);\n\n // Form association: relay submit/reset clicks to the associated form.\n // The inner <button> always has type=\"button\" so shadow DOM never drives native form actions.\n // getForm() returns null for link mode at runtime, so no form actions fire.\n const formField = useField({\n disabled: isDisabled,\n toFormValue: () => null,\n value: computed(() => ''),\n });\n\n const handleClick = (e: MouseEvent) => {\n if (isDisabled.value) {\n e.preventDefault();\n\n return;\n }\n\n // Link mode renders a real <a href> below — the browser handles left/middle/ctrl-click\n // navigation, target, and rel natively. No manual window.open/location.href needed.\n useFormAction(() => (isLink.value ? null : formField.internals.form), props.type, isDisabled, el)(e);\n };\n\n const handleKeydown = (e: KeyboardEvent) => {\n if (isLink.value) return;\n\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault();\n (el.shadowRoot?.querySelector('[part=\"button\"]') as HTMLElement)?.click();\n }\n };\n\n // ARIA attributes live on the host.\n bind({\n attr: {\n 'aria-busy': computed(() => (isLink.value ? null : props.loading.value)),\n 'aria-disabled': computed(() => (isLink.value ? null : isDisabled.value)),\n 'aria-label': computed(() => (isLink.value ? null : props.label.value)),\n color: effectiveColor,\n effect: props.effect,\n role: computed(() => (isLink.value ? null : (el.getAttribute('role') ?? 'button'))),\n size: effectiveSize,\n tabindex: computed(() => (isLink.value ? null : isDisabled.value ? '-1' : '0')),\n variant: effectiveVariant,\n },\n on: {\n keydown: handleKeydown,\n },\n });\n\n const buttonContent = html`\n <span class=\"loader\" part=\"loader\" aria-label=\"Loading\" ?hidden=${() => !props.loading.value}></span>\n <slot name=\"prefix\"></slot>\n <span class=\"content\" part=\"content\"><slot></slot></span>\n <slot name=\"suffix\"></slot>\n `;\n\n // Link mode delegates semantics and focus to the native anchor. Button mode keeps them on\n // the form-associated host because its visual part is intentionally a non-semantic span.\n return html`\n ${() =>\n isLink.value\n ? html`\n <a\n part=\"button\"\n aria-busy=\"${props.loading}\"\n aria-disabled=\"${isDisabled}\"\n aria-label=\"${computed(() => props.label.value || el.textContent?.trim() || null)}\"\n tabindex=\"${computed(() => (isDisabled.value ? '-1' : null))}\"\n href=\"${computed(() => (isDisabled.value ? null : props.href.value))}\"\n rel=\"${effectiveRel}\"\n target=\"${props.target}\"\n @click=\"${handleClick}\">\n ${buttonContent}\n </a>\n `\n : html`\n <span part=\"button\" role=\"presentation\" @click=\"${handleClick}\">${buttonContent}</span>\n `}\n `;\n },\n shadow: { delegatesFocus: false },\n styles: [\n colorThemeMixin,\n coarsePointerMixin,\n reducedMotionMixin,\n roundedVariantMixin,\n forcedColorsMixin,\n sizeVariantMixin({\n lg: {\n fontSize: 'var(--text-base)',\n gap: 'var(--size-2-5)',\n height: 'var(--size-12)',\n iconSize: 'var(--size-6)',\n lineHeight: 'var(--leading-relaxed)',\n padding: 'var(--size-2-5) var(--size-5)',\n },\n sm: {\n fontSize: 'var(--text-sm)',\n gap: 'var(--size-1-5)',\n height: 'var(--size-8)',\n iconSize: 'var(--size-4)',\n lineHeight: 'var(--leading-tight)',\n padding: 'var(--size-1-5) var(--size-3)',\n },\n }),\n frostVariantMixin('[part=\"button\"]'),\n rainbowEffectMixin('[part=\"button\"]'),\n shineEffectMixin('[part=\"button\"]'),\n disabledLoadingMixin,\n componentStyles,\n ],\n});\n"],"mappings":"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"}
1
+ {"version":3,"file":"button.js","names":[],"sources":["../src/inputs/button/button.ts"],"sourcesContent":["import { bind, define, getHost, html, inject, prop, useField } from '@vielzeug/ore';\nimport { computed } from '@vielzeug/ripple';\nimport { commonProps } from '../../shared';\nimport {\n coarsePointerMixin,\n colorThemeMixin,\n disabledLoadingMixin,\n forcedColorsMixin,\n frostVariantMixin,\n rainbowEffectMixin,\n reducedMotionMixin,\n roundedVariantMixin,\n shineEffectMixin,\n sizeVariantMixin,\n} from '../../styles';\nimport type { ButtonType, ComponentSize, LinkTarget, RoundedSize, ThemeColor } from '../../types';\nimport { useLinkProps } from '../../utils';\nimport { BUTTON_GROUP_CTX } from '../button-group/button-group';\nimport { useFormAction } from '../shared';\nimport componentStyles from './button.css?inline';\n\nexport const BUTTON_VARIANTS = ['solid', 'flat', 'bordered', 'outline', 'ghost', 'text', 'frost'] as const;\n\n/** Visual variant for ore-button: derived from BUTTON_VARIANTS for a single source of truth. */\nexport type ButtonVariant = (typeof BUTTON_VARIANTS)[number];\n\n/** Animated border effect for ore-button. */\nexport type ButtonEffect = 'shine' | 'rainbow';\n\n/** Button component properties */\nexport type OreButtonProps = {\n /** Theme color */\n color?: ThemeColor;\n /** Disable interaction */\n disabled?: boolean;\n /** Animated border effect: 'shine' (color-aware neon sweep) or 'rainbow' */\n effect?: ButtonEffect;\n /**\n * Full height button (100% of container): the inner `[part=\"button\"]` fills its host's\n * height instead of the size preset's fixed height. Useful when the button itself is the\n * whole tappable surface of a container it doesn't otherwise control the size of (e.g. a\n * swipe-revealed row action in `ore-list-item`'s `actions-left`/`actions-right` slots).\n */\n fullheight?: boolean;\n /** Full width button (100% of container) */\n fullwidth?: boolean;\n /** When set, renders an `<a>` instead of `<button>` */\n href?: string;\n /** Icon-only mode (square aspect ratio, no padding) */\n iconOnly?: boolean;\n /** Accessible label for the inner button: required for icon-only buttons */\n label?: string;\n /** Show loading state with spinner */\n loading?: boolean;\n /** Link rel attribute (requires href) */\n rel?: string;\n /** Border radius size */\n rounded?: RoundedSize;\n /** Component size */\n size?: ComponentSize;\n /** Link target (requires href) */\n target?: LinkTarget;\n /** HTML button type attribute */\n type?: ButtonType;\n /** Visual style variant */\n variant?: ButtonVariant;\n};\n\n/**\n * A customizable button component with multiple variants, sizes, and states.\n * Supports icons, loading states, and animated border effects.\n *\n * @element ore-button\n *\n * @attr {string} type - HTML button type: 'button' | 'submit' | 'reset'\n * @attr {boolean} disabled - Disable button interaction\n * @attr {boolean} loading - Show loading state with spinner\n * @attr {string} color - Theme color: 'primary' | 'secondary' | 'info' | 'success' | 'warning' | 'error'\n * @attr {string} variant - Visual variant: 'solid' | 'flat' | 'bordered' | 'outline' | 'ghost' | 'text' | 'frost'\n * @attr {string} size - Button size: 'sm' | 'md' | 'lg'\n * @attr {string} rounded - Border radius: 'none' | 'sm' | 'md' | 'lg' | 'xl' | '2xl' | '3xl' | 'full'\n * @attr {string} effect - Animated border effect: 'shine' | 'rainbow'\n * @attr {boolean} icon-only - Icon-only mode (square aspect ratio, no padding)\n * @attr {boolean} fullwidth - Full width button (100% of container)\n * @attr {boolean} fullheight - Full height button (100% of container)\n *\n * @fires click - Emitted when button is clicked (unless disabled/loading)\n *\n * @slot - Button content (text, icons, etc.)\n * @slot prefix - Content before the button text (e.g., icons)\n * @slot suffix - Content after the button text (e.g., icons, badges)\n *\n * @part button - The inner button or anchor element\n * @part loader - The loading spinner element\n * @part content - The button content wrapper\n *\n * @cssprop --button-bg - Background color override\n * @cssprop --button-color - Text color override\n * @cssprop --button-border - Border width override\n * @cssprop --button-border-color - Border color override\n * @cssprop --button-radius - Border radius override\n * @cssprop --button-padding - Inner padding override\n * @cssprop --button-gap - Gap between icon and text override\n * @cssprop --button-font-size - Font size override\n * @cssprop --button-frost-active-bg - Background when pressed (frost variant)\n * @cssprop --button-frost-active-border-color - Border color when pressed (frost variant)\n *\n * @example\n * ```html\n * <ore-button variant=\"solid\" color=\"primary\">Click me</ore-button>\n * <ore-button loading color=\"success\">Processing...</ore-button>\n * <ore-button effect=\"shine\" color=\"primary\">Shine</ore-button>\n * <ore-button effect=\"rainbow\" variant=\"frost\">Rainbow</ore-button>\n * ```\n */\nexport const BUTTON_TAG = 'ore-button' as const;\ndefine<OreButtonProps>(BUTTON_TAG, {\n formAssociated: true,\n props: {\n ...commonProps,\n effect: prop.string<ButtonEffect>(),\n fullheight: prop.bool(false),\n fullwidth: prop.bool(false),\n href: prop.string(),\n iconOnly: prop.bool(false),\n label: prop.string(),\n rel: prop.string(),\n target: prop.string<LinkTarget>(),\n type: prop.oneOf(['button', 'submit', 'reset'] as const, 'button'),\n variant: prop.oneOf(BUTTON_VARIANTS, 'solid'),\n },\n setup(props) {\n const el = getHost();\n\n // Prefer group context over own props for color/size/variant.\n const groupCtx = inject(BUTTON_GROUP_CTX);\n const effectiveColor = computed(() => groupCtx?.color.value ?? props.color.value);\n const effectiveSize = computed(() => groupCtx?.size.value ?? props.size.value);\n const effectiveVariant = computed(() => groupCtx?.variant.value ?? props.variant.value);\n\n const isDisabled = computed(() => !!(props.disabled.value || props.loading.value));\n\n // isLink and effectiveRel are computed from signals: correct even if href changes at runtime.\n const { effectiveRel, isLink } = useLinkProps(props.href, props.rel, props.target);\n\n // Form association: relay submit/reset clicks to the associated form.\n // The inner <button> always has type=\"button\" so shadow DOM never drives native form actions.\n // getForm() returns null for link mode at runtime, so no form actions fire.\n const formField = useField({\n disabled: isDisabled,\n toFormValue: () => null,\n value: computed(() => ''),\n });\n\n const handleClick = (e: MouseEvent) => {\n if (isDisabled.value) {\n e.preventDefault();\n\n return;\n }\n\n // Link mode renders a real <a href> below: the browser handles left/middle/ctrl-click\n // navigation, target, and rel natively. No manual window.open/location.href needed.\n useFormAction(() => (isLink.value ? null : formField.internals.form), props.type, isDisabled, el)(e);\n };\n\n const handleKeydown = (e: KeyboardEvent) => {\n if (isLink.value) return;\n\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault();\n (el.shadowRoot?.querySelector('[part=\"button\"]') as HTMLElement)?.click();\n }\n };\n\n // ARIA attributes live on the host.\n bind({\n attr: {\n 'aria-busy': computed(() => (isLink.value ? null : props.loading.value)),\n 'aria-disabled': computed(() => (isLink.value ? null : isDisabled.value)),\n 'aria-label': computed(() => (isLink.value ? null : props.label.value)),\n color: effectiveColor,\n effect: props.effect,\n role: computed(() => (isLink.value ? null : (el.getAttribute('role') ?? 'button'))),\n size: effectiveSize,\n tabindex: computed(() => (isLink.value ? null : isDisabled.value ? '-1' : '0')),\n variant: effectiveVariant,\n },\n on: {\n keydown: handleKeydown,\n },\n });\n\n // A factory, not a shared result: ore's static embed moves a result's\n // fragment children into place, consuming it. The link/button switch below\n // re-renders whenever `href` arrives or is removed at runtime (ore\n // templates set interpolated attributes after upgrade, so the first render\n // is usually the span branch), and a shared instance would render empty on\n // every switch after the first.\n const buttonContent = () => html`\n <span class=\"loader\" part=\"loader\" aria-label=\"Loading\" ?hidden=${() => !props.loading.value}></span>\n <slot name=\"prefix\"></slot>\n <span class=\"content\" part=\"content\"><slot></slot></span>\n <slot name=\"suffix\"></slot>\n `;\n\n // Link mode delegates semantics and focus to the native anchor. Button mode keeps them on\n // the form-associated host because its visual part is intentionally a non-semantic span.\n return html`\n ${() =>\n isLink.value\n ? html`\n <a\n part=\"button\"\n aria-busy=\"${props.loading}\"\n aria-disabled=\"${isDisabled}\"\n aria-label=\"${computed(() => props.label.value || el.textContent?.trim() || null)}\"\n tabindex=\"${computed(() => (isDisabled.value ? '-1' : null))}\"\n href=\"${computed(() => (isDisabled.value ? null : props.href.value))}\"\n rel=\"${effectiveRel}\"\n target=\"${props.target}\"\n @click=\"${handleClick}\">\n ${buttonContent()}\n </a>\n `\n : html`\n <span part=\"button\" role=\"presentation\" @click=\"${handleClick}\">${buttonContent()}</span>\n `}\n `;\n },\n shadow: { delegatesFocus: false },\n styles: [\n colorThemeMixin,\n coarsePointerMixin,\n reducedMotionMixin,\n roundedVariantMixin,\n forcedColorsMixin,\n sizeVariantMixin({\n lg: {\n fontSize: 'var(--text-base)',\n gap: 'var(--size-2-5)',\n height: 'var(--size-12)',\n iconSize: 'var(--size-6)',\n lineHeight: 'var(--leading-relaxed)',\n padding: 'var(--size-2-5) var(--size-5)',\n },\n sm: {\n fontSize: 'var(--text-sm)',\n gap: 'var(--size-1-5)',\n height: 'var(--size-8)',\n iconSize: 'var(--size-4)',\n lineHeight: 'var(--leading-tight)',\n padding: 'var(--size-1-5) var(--size-3)',\n },\n }),\n frostVariantMixin('[part=\"button\"]'),\n rainbowEffectMixin('[part=\"button\"]'),\n shineEffectMixin('[part=\"button\"]'),\n disabledLoadingMixin,\n componentStyles,\n ],\n});\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"calendar.cjs","names":[],"sources":["../src/inputs/calendar/calendar.ts"],"sourcesContent":["import { bind, define, html, prop, styleMap, useEmit, useField } from '@vielzeug/ore';\nimport { computed, signal } from '@vielzeug/ripple';\nimport { format, Temporal } from '@vielzeug/tempo';\nimport {\n createDatePickerControl,\n type DatePickerView,\n handleCalendarGridKeydown,\n parseIso,\n toIsoString,\n} from '../../core';\nimport type { ComponentSize, RoundedSize, ThemeColor } from '../../shared';\nimport { disablableBundle, roundableBundle, sizableBundle, themableBundle } from '../../shared';\nimport { colorThemeMixin, reducedMotionMixin } from '../../styles';\nimport componentStyles from './calendar.css?inline';\n\nexport { ICON_TAG } from '../../content/icon/icon';\nexport { BADGE_TAG } from '../../feedback/badge/badge';\n// ── Types ─────────────────────────────────────────────────────────────────────\n\nexport type OreCalendarEvents = {\n change: { isoValue: string | null };\n};\n\n/**\n * A calendar event entry.\n * Dates must be ISO 8601 strings (yyyy-MM-dd).\n *\n * The `color` field accepts any valid CSS color value (e.g. `'#e11d48'`,\n * `'var(--color-primary)'`). An invalid value silently falls back to the\n * component's theme color. Only pass values you control.\n */\nexport type CalendarEvent = {\n /**\n * Any CSS color value for the event dot / pill.\n * Defaults to the component's theme color when omitted.\n * Rendered via `styleMap()`, which strips `;`/`{`/`}` so the value can't break out of\n * its custom-property declaration — it is not a full CSS-color syntax validator, so an\n * invalid (but injection-safe) value may still render as no color.\n */\n color?: string;\n /** ISO date the event falls on (yyyy-MM-dd) */\n date: string;\n /** Unique identifier */\n id: string;\n /** Short label shown in the calendar cell */\n label: string;\n};\n\nexport type OreCalendarProps = {\n /** Theme color */\n color?: ThemeColor;\n /** Disable all date selection */\n disabled?: boolean;\n /**\n * Array of calendar events to display on day cells.\n * In normal mode each event renders as a small colored dot (max 3 dots, then \"+N\").\n * In expanded mode each event renders as a full-width colored pill with its label.\n * Pass as a JS property or as a JSON-encoded attribute.\n * @example\n * ```js\n * calendar.events = [\n * { id: '1', date: '2025-06-15', label: 'Team standup', color: 'var(--color-primary)' },\n * { id: '2', date: '2025-06-20', label: 'Release', color: '#e11d48' },\n * ];\n * ```\n */\n events?: CalendarEvent[];\n /**\n * Expanded layout — large cells with top-aligned day numbers suitable\n * for a full-page calendar app view.\n */\n expanded?: boolean;\n /** Expand to container width */\n fullwidth?: boolean;\n /** Locale for day/month names (default: browser locale) */\n locale?: string;\n /** Latest selectable date in ISO 8601 format (yyyy-MM-dd) */\n max?: string;\n /** Earliest selectable date in ISO 8601 format (yyyy-MM-dd) */\n min?: string;\n /** Form field name (when used inside a form) */\n name?: string;\n /** Mark field as required */\n required?: boolean;\n /** Border radius override */\n rounded?: RoundedSize;\n /** Component size */\n size?: ComponentSize;\n /**\n * Selected date in ISO 8601 format (yyyy-MM-dd).\n * @example '2025-06-15'\n */\n value?: string;\n /**\n * Day-of-week indices to disable (0 = Sunday … 6 = Saturday).\n * Pass as a JSON array attribute or a JS property.\n * @example\n * ```html\n * <ore-calendar weekend-days=\"[0,6]\"></ore-calendar>\n * ```\n */\n 'weekend-days'?: number[];\n};\n\n/**\n * An accessible, keyboard-navigable inline calendar component.\n * Supports day/month/year drill-down views, min/max bounds, disabled weekend\n * days, and optional form association.\n *\n * @element ore-calendar\n *\n * @attr {string} value - Selected date in ISO 8601 format (yyyy-MM-dd)\n * @attr {string} min - Minimum selectable date (yyyy-MM-dd)\n * @attr {string} max - Maximum selectable date (yyyy-MM-dd)\n * @attr {boolean} disabled - Disable all interaction\n * @attr {boolean} required - Required field (form association)\n * @attr {string} name - Form field name\n * @attr {string} color - Theme color: 'primary' | 'secondary' | 'info' | 'success' | 'warning' | 'error'\n * @attr {string} size - Component size: 'sm' | 'md' | 'lg'\n * @attr {string} rounded - Border radius: 'none' | 'sm' | 'md' | 'lg' | 'xl' | '2xl' | '3xl' | 'full'\n * @attr {string} locale - BCP 47 locale string\n * @attr {string} weekend-days - JSON array of day indices to disable (0=Sun…6=Sat)\n * @attr {boolean} fullwidth - Expand to full container width\n * @attr {boolean} expanded - Large-cell calendar-app layout with top-aligned day numbers\n *\n * @fires change - Fired when a date is selected. detail: { isoValue: string | null }\n *\n * @cssprop --calendar-bg - Calendar background\n * @cssprop --calendar-border-color - Calendar border color\n * @cssprop --calendar-radius - Calendar border radius\n * @cssprop --calendar-shadow - Calendar drop shadow\n * @cssprop --calendar-day-selected-bg - Background of selected day cell\n * @cssprop --calendar-day-today-color - Colour of today's date number\n * @cssprop --calendar-day-outside-opacity - Opacity of days outside visible month\n *\n * @part calendar - The root calendar panel\n * @part header - Calendar header (nav + label)\n * @part grid - Day grid\n * @part day - Individual day cell\n *\n * @example\n * ```html\n * <!-- Single date with bounds -->\n * <ore-calendar value=\"2025-06-15\" min=\"2025-01-01\" max=\"2025-12-31\" color=\"primary\"></ore-calendar>\n *\n * <!-- Expanded calendar-app layout -->\n * <ore-calendar expanded fullwidth color=\"primary\"></ore-calendar>\n * ```\n */\nexport const CALENDAR_TAG = 'ore-calendar' as const;\n\n/** Maximum event dots/pills shown per cell before \"+N\" overflow */\nconst MAX_EVENTS = 3;\n\n// ── Component ────────────────────────────────────────────────────────────────\n\ndefine<OreCalendarProps>(CALENDAR_TAG, {\n formAssociated: true,\n props: {\n ...themableBundle,\n ...sizableBundle,\n ...disablableBundle,\n ...roundableBundle,\n events: prop.json([] as CalendarEvent[]),\n expanded: prop.bool(false),\n fullwidth: prop.bool(false),\n locale: prop.string(),\n max: prop.string(),\n min: prop.string(),\n name: prop.string(),\n required: prop.bool(false),\n value: prop.string(),\n 'weekend-days': prop.json([] as number[]),\n },\n\n setup(props) {\n const emit = useEmit<OreCalendarEvents>();\n\n // ── Derived flags ────────────────────────────────────────────────────────\n\n const isDisabled = computed(() => props.disabled.value === true);\n const isExpanded = computed(() => props.expanded.value === true);\n\n // ── Selected date: local-override pattern ─────────────────────────────────\n // `localSelection` holds a user-initiated pick (or undefined = no override).\n // `selectedDate` derives from it, falling back to the value prop reactively.\n // This eliminates setInterval polling — external prop changes propagate\n // through the computed graph automatically.\n\n const localSelection = signal<Temporal.PlainDate | null | undefined>(undefined);\n\n const selectedDate = computed(() =>\n localSelection.value !== undefined ? localSelection.value : parseIso(props.value.value),\n );\n\n // ── Date-picker control ──────────────────────────────────────────────────\n\n const ctrl = createDatePickerControl({\n get locale() {\n return props.locale.value ?? (typeof navigator !== 'undefined' ? navigator.language : 'en');\n },\n get max() {\n return parseIso(props.max.value);\n },\n get min() {\n return parseIso(props.min.value);\n },\n onChange(date) {\n localSelection.value = date;\n currentView.value = 'day';\n displayYear.value = ctrl.displayYear();\n displayMonth.value = ctrl.displayMonth();\n emit('change', { isoValue: toIsoString(date) });\n },\n get value() {\n return selectedDate.value;\n },\n get weekendDays() {\n return props['weekend-days'].value ?? [];\n },\n });\n\n // ── Reactive display state ────────────────────────────────────────────────\n // Three separate primitive signals — the proven pattern. Mutating any one\n // of them invalidates only the computeds that read it.\n\n const currentView = signal<DatePickerView>('day');\n const displayYear = signal(ctrl.displayYear());\n const displayMonth = signal(ctrl.displayMonth()); // 1-indexed (Temporal)\n\n // ── Form value ───────────────────────────────────────────────────────────\n\n useField<string>({\n disabled: isDisabled,\n toFormValue: (v) => v || null,\n value: computed(() => toIsoString(selectedDate.value) ?? ''),\n });\n\n // ── Events lookup ─────────────────────────────────────────────────────────\n\n const eventsByDate = computed(() => {\n const map = new Map<string, CalendarEvent[]>();\n\n for (const evt of props.events.value ?? []) {\n const list = map.get(evt.date) ?? [];\n\n list.push(evt);\n map.set(evt.date, list);\n }\n\n return map;\n });\n\n // ── Derived cells ─────────────────────────────────────────────────────────\n // Each reads a display signal so they re-run when navigation changes.\n\n const dayCells = computed(() => {\n void displayYear.value;\n void displayMonth.value;\n void selectedDate.value; // re-run when selection changes to refresh isSelected flags\n\n return ctrl.dayCells();\n });\n const monthCells = computed(() => {\n void displayYear.value;\n\n return ctrl.monthCells();\n });\n const yearCells = computed(() => {\n void displayYear.value;\n\n return ctrl.yearCells();\n });\n const weekdayLabels = computed(() => ctrl.weekdayLabels());\n\n const displayMonth_ = computed(() => {\n const d = Temporal.PlainDate.from({ day: 1, month: displayMonth.value, year: displayYear.value });\n const loc = props.locale.value ?? (typeof navigator !== 'undefined' ? navigator.language : 'en');\n\n return format(d, { intl: { month: 'long' }, locale: loc, timeZone: 'UTC' });\n });\n\n const displayYear_ = computed(() => String(displayYear.value));\n const displayLabel = computed(() => `${displayMonth_.value} ${displayYear_.value}`);\n\n // ── Navigation ───────────────────────────────────────────────────────────\n\n function handlePrev(): void {\n if (currentView.value === 'day') ctrl.prevMonth();\n else ctrl.prevYear();\n\n displayYear.value = ctrl.displayYear();\n displayMonth.value = ctrl.displayMonth();\n }\n\n function handleNext(): void {\n if (currentView.value === 'day') ctrl.nextMonth();\n else ctrl.nextYear();\n\n displayYear.value = ctrl.displayYear();\n displayMonth.value = ctrl.displayMonth();\n }\n\n function handleHeaderClick(): void {\n const views: DatePickerView[] = ['day', 'month', 'year'];\n const next = views[(views.indexOf(currentView.value) + 1) % views.length];\n\n ctrl.setView(next);\n currentView.value = next;\n }\n\n // ── Selection handlers — all disabled guards live here ────────────────────\n\n function handleSelectMonth(month: number): void {\n if (isDisabled.value) return;\n\n ctrl.goTo(ctrl.displayYear(), month);\n ctrl.setView('day');\n displayYear.value = ctrl.displayYear();\n displayMonth.value = ctrl.displayMonth();\n currentView.value = 'day';\n }\n\n function handleSelectYear(year: number): void {\n if (isDisabled.value) return;\n\n ctrl.goTo(year, ctrl.displayMonth());\n ctrl.setView('month');\n displayYear.value = ctrl.displayYear();\n currentView.value = 'month';\n }\n\n function handleSelectDay(isoStr: string): void {\n if (isDisabled.value) return;\n\n const date = parseIso(isoStr);\n\n if (!date) return;\n\n ctrl.select(date); // ctrl.select() internally rejects disabled/out-of-range dates\n }\n\n // ── Cell keyboard navigation (shared ARIA grid pattern) ───────────────────\n // Day cells activate by their `data-iso`; month/year cells use their closure value.\n\n function handleDayKeydown(e: KeyboardEvent): void {\n handleCalendarGridKeydown(e, '.cal-cell-day', 7, (cell) => handleSelectDay(cell.dataset.iso ?? ''));\n }\n\n // ── Host bindings ────────────────────────────────────────────────────────\n\n bind({\n attr: {\n 'aria-disabled': () => (isDisabled.value ? 'true' : null),\n 'aria-label': () => displayLabel.value,\n role: 'group',\n },\n class: {\n 'is-disabled': isDisabled,\n },\n });\n\n // ── Template ─────────────────────────────────────────────────────────────\n\n return html`\n <div class=\"calendar\" part=\"calendar\" role=\"presentation\">\n <!-- Header -->\n <div class=\"cal-header\" part=\"header\">\n <button class=\"nav-btn\" type=\"button\" aria-label=\"Previous\" ?disabled=\"${isDisabled}\" @click=\"${handlePrev}\">\n <ore-icon name=\"chevron-left\" size=\"16\" stroke-width=\"2\" aria-hidden=\"true\"></ore-icon>\n </button>\n\n <button\n class=\"cal-label-btn\"\n type=\"button\"\n aria-label=\"${() =>\n `Switch to ${currentView.value === 'day' ? 'month' : currentView.value === 'month' ? 'year' : 'day'} view`}\"\n ?disabled=\"${isDisabled}\"\n @click=\"${handleHeaderClick}\">\n <span class=\"cal-label-month\">${displayMonth_}</span>\n <span class=\"cal-label-sep\" aria-hidden=\"true\">/</span>\n <span class=\"cal-label-year\">${displayYear_}</span>\n </button>\n\n <button class=\"nav-btn\" type=\"button\" aria-label=\"Next\" ?disabled=\"${isDisabled}\" @click=\"${handleNext}\">\n <ore-icon name=\"chevron-right\" size=\"16\" stroke-width=\"2\" aria-hidden=\"true\"></ore-icon>\n </button>\n </div>\n\n <!-- Day view -->\n <div\n class=\"cal-grid cal-grid-days\"\n role=\"grid\"\n part=\"grid\"\n aria-label=\"${() => displayLabel.value}\"\n ?hidden=\"${() => currentView.value !== 'day'}\">\n <div role=\"row\" class=\"cal-grid-row\">\n ${() =>\n weekdayLabels.value.map(\n (lbl) => html`\n <div class=\"cal-cell cal-cell-head\" role=\"columnheader\" aria-label=\"${lbl}\">${lbl}</div>\n `,\n )}\n </div>\n ${() => {\n const cells = dayCells.value;\n const rows: (typeof cells)[number][][] = [];\n\n for (let i = 0; i < cells.length; i += 7) rows.push(cells.slice(i, i + 7));\n\n return rows.map(\n (row) => html`\n <div role=\"row\" class=\"cal-grid-row\">\n ${row.map(\n (cell) => html`\n <div\n class=\"cal-cell cal-cell-day\"\n role=\"gridcell\"\n part=\"day\"\n aria-selected=\"${() => String(cell.isSelected)}\"\n aria-disabled=\"${() => String(cell.isDisabled || isDisabled.value)}\"\n aria-current=\"${() => (cell.isToday ? 'date' : null)}\"\n ?data-selected=\"${() => cell.isSelected}\"\n ?data-today=\"${() => cell.isToday}\"\n ?data-outside=\"${() => cell.isOutsideMonth}\"\n ?data-disabled=\"${() => cell.isDisabled || isDisabled.value}\"\n data-iso=\"${cell.iso}\"\n data-day=\"${String(cell.day)}\"\n tabindex=\"${() => (cell.isDisabled || isDisabled.value ? '-1' : '0')}\"\n @click=\"${() => handleSelectDay(cell.iso)}\"\n @keydown=\"${handleDayKeydown}\">\n ${String(cell.day)}\n ${() => {\n const evts = eventsByDate.value.get(cell.iso) ?? [];\n\n if (!evts.length) return html``;\n\n const shown = evts.slice(0, MAX_EVENTS);\n const overflow = evts.length - MAX_EVENTS;\n\n if (isExpanded.value) {\n // Text node is written tag-tight (no inner line breaks) — this custom\n // `html` tagged template does not collapse whitespace at runtime like a\n // browser parser would, so a pretty-printed multi-line `<span>...</span>`\n // here would render literal newlines/indentation into `textContent`.\n // biome-ignore format: Preserve text-node whitespace in the template.\n const overflowPill =\n overflow > 0\n ? html`<span class=\"cal-event-pill-overflow\" aria-hidden=\"true\"\n >+${overflow} more</span\n >`\n : html``;\n\n return html`\n <div\n class=\"cal-events\"\n aria-label=\"${() => `${evts.length} event${evts.length > 1 ? 's' : ''}`}\">\n ${shown.map(\n (evt) => html`\n <ore-badge\n class=\"cal-event-pill\"\n size=\"xs\"\n rounded=\"sm\"\n aria-label=\"${evt.label}\"\n style=\"${styleMap({\n '--badge-bg': evt.color,\n '--badge-border-color': evt.color,\n })}\">\n ${evt.label}\n </ore-badge>\n `,\n )}\n ${overflowPill}\n </div>\n `;\n }\n\n return html`\n <div\n class=\"cal-dots\"\n aria-label=\"${() => `${evts.length} event${evts.length > 1 ? 's' : ''}`}\">\n ${shown.map(\n (evt) => html`\n <ore-badge\n class=\"cal-dot\"\n dot\n size=\"xs\"\n aria-hidden=\"true\"\n style=\"${styleMap({\n '--badge-bg': evt.color,\n '--badge-border-color': evt.color,\n })}\"></ore-badge>\n `,\n )}\n ${\n overflow > 0\n ? html`\n <span class=\"cal-dot-overflow\" aria-hidden=\"true\">+${overflow}</span>\n `\n : html``\n }\n </div>\n `;\n }}\n </div>\n `,\n )}\n </div>\n `,\n );\n }}\n </div>\n\n <!-- Month view -->\n <div\n class=\"cal-grid cal-grid-months\"\n role=\"grid\"\n aria-label=\"${() => displayYear_.value}\"\n ?hidden=\"${() => currentView.value !== 'month'}\">\n ${() => {\n const cells = monthCells.value;\n const rows: (typeof cells)[number][][] = [];\n\n for (let i = 0; i < cells.length; i += 4) rows.push(cells.slice(i, i + 4));\n\n return rows.map(\n (row) => html`\n <div role=\"row\">\n ${row.map(\n (cell) => html`\n <div\n class=\"cal-cell cal-cell-month\"\n role=\"gridcell\"\n aria-selected=\"${() => String(cell.isSelected)}\"\n aria-disabled=\"${() => String(cell.isDisabled || isDisabled.value)}\"\n ?data-selected=\"${() => cell.isSelected}\"\n ?data-disabled=\"${() => cell.isDisabled || isDisabled.value}\"\n tabindex=\"${() => (cell.isDisabled || isDisabled.value ? '-1' : '0')}\"\n @click=\"${() => handleSelectMonth(cell.month)}\"\n @keydown=\"${(e: KeyboardEvent) =>\n handleCalendarGridKeydown(e, '.cal-cell-month', 4, () => handleSelectMonth(cell.month))}\">\n ${cell.shortLabel}\n </div>\n `,\n )}\n </div>\n `,\n );\n }}\n </div>\n\n <!-- Year view -->\n <div\n class=\"cal-grid cal-grid-years\"\n role=\"grid\"\n aria-label=\"Select year\"\n ?hidden=\"${() => currentView.value !== 'year'}\">\n ${() => {\n const cells = yearCells.value;\n const rows: (typeof cells)[number][][] = [];\n\n for (let i = 0; i < cells.length; i += 4) rows.push(cells.slice(i, i + 4));\n\n return rows.map(\n (row) => html`\n <div role=\"row\">\n ${row.map(\n (cell) => html`\n <div\n class=\"cal-cell cal-cell-year\"\n role=\"gridcell\"\n aria-selected=\"${() => String(cell.isSelected)}\"\n aria-disabled=\"${() => String(cell.isDisabled || isDisabled.value)}\"\n ?data-selected=\"${() => cell.isSelected}\"\n ?data-disabled=\"${() => cell.isDisabled || isDisabled.value}\"\n tabindex=\"${() => (cell.isDisabled || isDisabled.value ? '-1' : '0')}\"\n @click=\"${() => handleSelectYear(cell.year)}\"\n @keydown=\"${(e: KeyboardEvent) =>\n handleCalendarGridKeydown(e, '.cal-cell-year', 4, () => handleSelectYear(cell.year))}\">\n ${String(cell.year)}\n </div>\n `,\n )}\n </div>\n `,\n );\n }}\n </div>\n </div>\n `;\n },\n shadow: { delegatesFocus: true },\n styles: [colorThemeMixin, reducedMotionMixin, componentStyles],\n});\n"],"mappings":"6aAqJA,IAAa,EAAe,eAGtB,EAAa,GAInB,EAAA,EAAA,OAAA,CAAyB,EAAc,CACrC,eAAgB,GAChB,MAAO,CACL,GAAG,EAAA,eACH,GAAG,EAAA,cACH,GAAG,EAAA,iBACH,GAAG,EAAA,gBACH,OAAQ,EAAA,KAAK,KAAK,CAAC,CAAoB,EACvC,SAAU,EAAA,KAAK,KAAK,EAAK,EACzB,UAAW,EAAA,KAAK,KAAK,EAAK,EAC1B,OAAQ,EAAA,KAAK,OAAO,EACpB,IAAK,EAAA,KAAK,OAAO,EACjB,IAAK,EAAA,KAAK,OAAO,EACjB,KAAM,EAAA,KAAK,OAAO,EAClB,SAAU,EAAA,KAAK,KAAK,EAAK,EACzB,MAAO,EAAA,KAAK,OAAO,EACnB,eAAgB,EAAA,KAAK,KAAK,CAAC,CAAa,CAC1C,EAEA,MAAM,EAAO,CACX,IAAM,GAAA,EAAO,EAAA,QAAA,CAA2B,EAIlC,GAAA,EAAa,EAAA,SAAA,KAAe,EAAM,SAAS,QAAU,EAAI,EACzD,GAAA,EAAa,EAAA,SAAA,KAAe,EAAM,SAAS,QAAU,EAAI,EAQzD,GAAA,EAAiB,EAAA,OAAA,CAA8C,IAAA,EAAS,EAExE,GAAA,EAAe,EAAA,SAAA,KACnB,EAAe,QAAU,IAAA,GAAmC,EAAA,SAAS,EAAM,MAAM,KAAK,EAAjD,EAAe,KACtD,EAIM,EAAO,EAAA,wBAAwB,CACnC,IAAI,QAAS,CACX,OAAO,EAAM,OAAO,QAAU,OAAO,UAAc,IAAc,UAAU,SAAW,KACxF,EACA,IAAI,KAAM,CACR,OAAO,EAAA,SAAS,EAAM,IAAI,KAAK,CACjC,EACA,IAAI,KAAM,CACR,OAAO,EAAA,SAAS,EAAM,IAAI,KAAK,CACjC,EACA,SAAS,EAAM,CACb,EAAe,MAAQ,EACvB,EAAY,MAAQ,MACpB,EAAY,MAAQ,EAAK,YAAY,EACrC,EAAa,MAAQ,EAAK,aAAa,EACvC,EAAK,SAAU,CAAE,SAAU,EAAA,YAAY,CAAI,CAAE,CAAC,CAChD,EACA,IAAI,OAAQ,CACV,OAAO,EAAa,KACtB,EACA,IAAI,aAAc,CAChB,OAAO,EAAM,eAAe,CAAC,OAAS,CAAC,CACzC,CACF,CAAC,EAMK,GAAA,EAAc,EAAA,OAAA,CAAuB,KAAK,EAC1C,GAAA,EAAc,EAAA,OAAA,CAAO,EAAK,YAAY,CAAC,EACvC,GAAA,EAAe,EAAA,OAAA,CAAO,EAAK,aAAa,CAAC,GAI/C,EAAA,EAAA,SAAA,CAAiB,CACf,SAAU,EACV,YAAc,GAAM,GAAK,KACzB,OAAA,EAAO,EAAA,SAAA,KAAe,EAAA,YAAY,EAAa,KAAK,GAAK,EAAE,CAC7D,CAAC,EAID,IAAM,GAAA,EAAe,EAAA,SAAA,KAAe,CAClC,IAAM,EAAM,IAAI,IAEhB,IAAK,IAAM,KAAO,EAAM,OAAO,OAAS,CAAC,EAAG,CAC1C,IAAM,EAAO,EAAI,IAAI,EAAI,IAAI,GAAK,CAAC,EAEnC,EAAK,KAAK,CAAG,EACb,EAAI,IAAI,EAAI,KAAM,CAAI,CACxB,CAEA,OAAO,CACT,CAAC,EAKK,GAAA,EAAW,EAAA,SAAA,MACf,EAAiB,MACjB,EAAkB,MAClB,EAAkB,MAEX,EAAK,SAAS,EACtB,EACK,GAAA,EAAa,EAAA,SAAA,MACjB,EAAiB,MAEV,EAAK,WAAW,EACxB,EACK,GAAA,EAAY,EAAA,SAAA,MAChB,EAAiB,MAEV,EAAK,UAAU,EACvB,EACK,GAAA,EAAgB,EAAA,SAAA,KAAe,EAAK,cAAc,CAAC,EAEnD,GAAA,EAAgB,EAAA,SAAA,KAAe,CACnC,IAAM,EAAI,EAAA,SAAS,UAAU,KAAK,CAAE,IAAK,EAAG,MAAO,EAAa,MAAO,KAAM,EAAY,KAAM,CAAC,EAC1F,EAAM,EAAM,OAAO,QAAU,OAAO,UAAc,IAAc,UAAU,SAAW,MAE3F,OAAA,EAAO,EAAA,OAAA,CAAO,EAAG,CAAE,KAAM,CAAE,MAAO,MAAO,EAAG,OAAQ,EAAK,SAAU,KAAM,CAAC,CAC5E,CAAC,EAEK,GAAA,EAAe,EAAA,SAAA,KAAe,OAAO,EAAY,KAAK,CAAC,EACvD,GAAA,EAAe,EAAA,SAAA,KAAe,GAAG,EAAc,MAAM,GAAG,EAAa,OAAO,EAIlF,SAAS,YAAmB,CACtB,EAAY,QAAU,MAAO,EAAK,UAAU,EAC3C,EAAK,SAAS,EAEnB,EAAY,MAAQ,EAAK,YAAY,EACrC,EAAa,MAAQ,EAAK,aAAa,CACzC,CAEA,SAAS,YAAmB,CACtB,EAAY,QAAU,MAAO,EAAK,UAAU,EAC3C,EAAK,SAAS,EAEnB,EAAY,MAAQ,EAAK,YAAY,EACrC,EAAa,MAAQ,EAAK,aAAa,CACzC,CAEA,SAAS,mBAA0B,CACjC,IAAM,EAA0B,CAAC,MAAO,QAAS,MAAM,EACjD,EAAO,GAAO,EAAM,QAAQ,EAAY,KAAK,EAAI,GAAK,EAAM,QAElE,EAAK,QAAQ,CAAI,EACjB,EAAY,MAAQ,CACtB,CAIA,SAAS,kBAAkB,EAAqB,CAC1C,EAAW,QAEf,EAAK,KAAK,EAAK,YAAY,EAAG,CAAK,EACnC,EAAK,QAAQ,KAAK,EAClB,EAAY,MAAQ,EAAK,YAAY,EACrC,EAAa,MAAQ,EAAK,aAAa,EACvC,EAAY,MAAQ,MACtB,CAEA,SAAS,iBAAiB,EAAoB,CACxC,EAAW,QAEf,EAAK,KAAK,EAAM,EAAK,aAAa,CAAC,EACnC,EAAK,QAAQ,OAAO,EACpB,EAAY,MAAQ,EAAK,YAAY,EACrC,EAAY,MAAQ,QACtB,CAEA,SAAS,gBAAgB,EAAsB,CAC7C,GAAI,EAAW,MAAO,OAEtB,IAAM,EAAO,EAAA,SAAS,CAAM,EAEvB,GAEL,EAAK,OAAO,CAAI,CAClB,CAKA,SAAS,iBAAiB,EAAwB,CAChD,EAAA,0BAA0B,EAAG,gBAAiB,EAAI,GAAS,gBAAgB,EAAK,QAAQ,KAAO,EAAE,CAAC,CACpG,CAiBA,OAbA,EAAA,EAAA,KAAA,CAAK,CACH,KAAM,CACJ,oBAAwB,EAAW,MAAQ,OAAS,KACpD,iBAAoB,EAAa,MACjC,KAAM,OACR,EACA,MAAO,CACL,cAAe,CACjB,CACF,CAAC,EAIM,EAAA,IAAI;;;;mFAIoE,EAAW,YAAY,WAAW;;;;;;;8BAQvG,aAAa,EAAY,QAAU,MAAQ,QAAU,EAAY,QAAU,QAAU,OAAS,MAAM,OAAO;yBAChG,EAAW;sBACd,kBAAkB;4CACI,EAAc;;2CAEf,EAAa;;;+EAGuB,EAAW,YAAY,WAAW;;;;;;;;;;4BAUnF,EAAa,MAAM;yBACtB,EAAY,QAAU,MAAM;;kBAGzC,EAAc,MAAM,IACjB,GAAQ,EAAA,IAAI;wFAC2D,EAAI,IAAI,EAAI;iBAEtF,EAAE;;gBAEE,CACN,IAAM,EAAQ,EAAS,MACjB,EAAmC,CAAC,EAE1C,IAAK,IAAI,EAAI,EAAG,EAAI,EAAM,OAAQ,GAAK,EAAG,EAAK,KAAK,EAAM,MAAM,EAAG,EAAI,CAAC,CAAC,EAEzE,OAAO,EAAK,IACT,GAAQ,EAAA,IAAI;;oBAEP,EAAI,IACH,GAAS,EAAA,IAAI;;;;;6CAKa,OAAO,EAAK,UAAU,EAAE;6CACxB,OAAO,EAAK,YAAc,EAAW,KAAK,EAAE;4CAC5C,EAAK,QAAU,OAAS,KAAM;8CAC7B,EAAK,WAAW;2CACnB,EAAK,QAAQ;6CACX,EAAK,eAAe;8CACnB,EAAK,YAAc,EAAW,MAAM;oCAChD,EAAK,IAAI;oCACT,OAAO,EAAK,GAAG,EAAE;wCACV,EAAK,YAAc,EAAW,MAAQ,KAAO,IAAK;sCACrD,gBAAgB,EAAK,GAAG,EAAE;oCAC9B,iBAAiB;0BAC3B,OAAO,EAAK,GAAG,EAAE;8BACX,CACN,IAAM,EAAO,EAAa,MAAM,IAAI,EAAK,GAAG,GAAK,CAAC,EAElD,GAAI,CAAC,EAAK,OAAQ,MAAO,GAAA,IAAI,GAE7B,IAAM,EAAQ,EAAK,MAAM,EAAG,CAAU,EAChC,EAAW,EAAK,OAAS,EAE/B,GAAI,EAAW,MAAO,CAMpB,IAAM,EACJ,EAAW,EACP,EAAA,IAAI;sCACA,EAAS;mCAEb,EAAA,IAAI,GAEV,MAAO,GAAA,IAAI;;;kDAGa,GAAG,EAAK,OAAO,QAAQ,EAAK,OAAS,EAAI,IAAM,KAAK;kCACtE,EAAM,IACL,GAAQ,EAAA,IAAI;;;;;oDAKK,EAAI,MAAM;gDACf,EAAA,EAAA,SAAA,CAAS,CAChB,aAAc,EAAI,MAClB,uBAAwB,EAAI,KAC9B,CAAC,EAAE;wCACD,EAAI,MAAM;;mCAGlB,EAAE;kCACA,EAAa;;6BAGrB,CAEA,MAAO,GAAA,IAAI;;;gDAGa,GAAG,EAAK,OAAO,QAAQ,EAAK,OAAS,EAAI,IAAM,KAAK;gCACtE,EAAM,IACL,GAAQ,EAAA,IAAI;;;;;;8CAMA,EAAA,EAAA,SAAA,CAAS,CAChB,aAAc,EAAI,MAClB,uBAAwB,EAAI,KAC9B,CAAC,EAAE;iCAET,EAAE;gCAEA,EAAW,EACP,EAAA,IAAI;2FACmD,EAAS;sCAEhE,EAAA,IAAI,GACT;;2BAGP,EAAE;;qBAGR,EAAE;;eAGR,CACF,EAAE;;;;;;;4BAOkB,EAAa,MAAM;yBACtB,EAAY,QAAU,QAAQ;gBACvC,CACN,IAAM,EAAQ,EAAW,MACnB,EAAmC,CAAC,EAE1C,IAAK,IAAI,EAAI,EAAG,EAAI,EAAM,OAAQ,GAAK,EAAG,EAAK,KAAK,EAAM,MAAM,EAAG,EAAI,CAAC,CAAC,EAEzE,OAAO,EAAK,IACT,GAAQ,EAAA,IAAI;;oBAEP,EAAI,IACH,GAAS,EAAA,IAAI;;;;6CAIa,OAAO,EAAK,UAAU,EAAE;6CACxB,OAAO,EAAK,YAAc,EAAW,KAAK,EAAE;8CAC3C,EAAK,WAAW;8CAChB,EAAK,YAAc,EAAW,MAAM;wCACzC,EAAK,YAAc,EAAW,MAAQ,KAAO,IAAK;sCACrD,kBAAkB,EAAK,KAAK,EAAE;oCACjC,GACX,EAAA,0BAA0B,EAAG,kBAAmB,MAAS,kBAAkB,EAAK,KAAK,CAAC,EAAE;0BACxF,EAAK,WAAW;;qBAGxB,EAAE;;eAGR,CACF,EAAE;;;;;;;;yBAQe,EAAY,QAAU,OAAO;gBACtC,CACN,IAAM,EAAQ,EAAU,MAClB,EAAmC,CAAC,EAE1C,IAAK,IAAI,EAAI,EAAG,EAAI,EAAM,OAAQ,GAAK,EAAG,EAAK,KAAK,EAAM,MAAM,EAAG,EAAI,CAAC,CAAC,EAEzE,OAAO,EAAK,IACT,GAAQ,EAAA,IAAI;;oBAEP,EAAI,IACH,GAAS,EAAA,IAAI;;;;6CAIa,OAAO,EAAK,UAAU,EAAE;6CACxB,OAAO,EAAK,YAAc,EAAW,KAAK,EAAE;8CAC3C,EAAK,WAAW;8CAChB,EAAK,YAAc,EAAW,MAAM;wCACzC,EAAK,YAAc,EAAW,MAAQ,KAAO,IAAK;sCACrD,iBAAiB,EAAK,IAAI,EAAE;oCAC/B,GACX,EAAA,0BAA0B,EAAG,iBAAkB,MAAS,iBAAiB,EAAK,IAAI,CAAC,EAAE;0BACrF,OAAO,EAAK,IAAI,EAAE;;qBAG1B,EAAE;;eAGR,CACF,EAAE;;;KAIV,EACA,OAAQ,CAAE,eAAgB,EAAK,EAC/B,OAAQ,CAAC,EAAA,gBAAiB,EAAA,mBAAoB,EAAA,OAAe,CAC/D,CAAC"}
1
+ {"version":3,"file":"calendar.cjs","names":[],"sources":["../src/inputs/calendar/calendar.ts"],"sourcesContent":["import { bind, define, html, prop, styleMap, useEmit, useField } from '@vielzeug/ore';\nimport { computed, signal } from '@vielzeug/ripple';\nimport { format, Temporal } from '@vielzeug/tempo';\nimport {\n createDatePickerControl,\n type DatePickerView,\n handleCalendarGridKeydown,\n parseIso,\n toIsoString,\n} from '../../core';\nimport type { ComponentSize, RoundedSize, ThemeColor } from '../../shared';\nimport { disablableBundle, roundableBundle, sizableBundle, themableBundle } from '../../shared';\nimport { colorThemeMixin, reducedMotionMixin } from '../../styles';\nimport componentStyles from './calendar.css?inline';\n\nexport { ICON_TAG } from '../../content/icon/icon';\nexport { BADGE_TAG } from '../../feedback/badge/badge';\n// ── Types ─────────────────────────────────────────────────────────────────────\n\nexport type OreCalendarEvents = {\n change: { isoValue: string | null };\n};\n\n/**\n * A calendar event entry.\n * Dates must be ISO 8601 strings (yyyy-MM-dd).\n *\n * The `color` field accepts any valid CSS color value (e.g. `'#e11d48'`,\n * `'var(--color-primary)'`). An invalid value silently falls back to the\n * component's theme color. Only pass values you control.\n */\nexport type CalendarEvent = {\n /**\n * Any CSS color value for the event dot / pill.\n * Defaults to the component's theme color when omitted.\n * Rendered via `styleMap()`, which strips `;`/`{`/`}` so the value can't break out of\n * its custom-property declaration: it is not a full CSS-color syntax validator, so an\n * invalid (but injection-safe) value may still render as no color.\n */\n color?: string;\n /** ISO date the event falls on (yyyy-MM-dd) */\n date: string;\n /** Unique identifier */\n id: string;\n /** Short label shown in the calendar cell */\n label: string;\n};\n\nexport type OreCalendarProps = {\n /** Theme color */\n color?: ThemeColor;\n /** Disable all date selection */\n disabled?: boolean;\n /**\n * Array of calendar events to display on day cells.\n * In normal mode each event renders as a small colored dot (max 3 dots, then \"+N\").\n * In expanded mode each event renders as a full-width colored pill with its label.\n * Pass as a JS property or as a JSON-encoded attribute.\n * @example\n * ```js\n * calendar.events = [\n * { id: '1', date: '2025-06-15', label: 'Team standup', color: 'var(--color-primary)' },\n * { id: '2', date: '2025-06-20', label: 'Release', color: '#e11d48' },\n * ];\n * ```\n */\n events?: CalendarEvent[];\n /**\n * Expanded layout: large cells with top-aligned day numbers suitable\n * for a full-page calendar app view.\n */\n expanded?: boolean;\n /** Expand to container width */\n fullwidth?: boolean;\n /** Locale for day/month names (default: browser locale) */\n locale?: string;\n /** Latest selectable date in ISO 8601 format (yyyy-MM-dd) */\n max?: string;\n /** Earliest selectable date in ISO 8601 format (yyyy-MM-dd) */\n min?: string;\n /** Form field name (when used inside a form) */\n name?: string;\n /** Mark field as required */\n required?: boolean;\n /** Border radius override */\n rounded?: RoundedSize;\n /** Component size */\n size?: ComponentSize;\n /**\n * Selected date in ISO 8601 format (yyyy-MM-dd).\n * @example '2025-06-15'\n */\n value?: string;\n /**\n * Day-of-week indices to disable (0 = Sunday … 6 = Saturday).\n * Pass as a JSON array attribute or a JS property.\n * @example\n * ```html\n * <ore-calendar weekend-days=\"[0,6]\"></ore-calendar>\n * ```\n */\n 'weekend-days'?: number[];\n};\n\n/**\n * An accessible, keyboard-navigable inline calendar component.\n * Supports day/month/year drill-down views, min/max bounds, disabled weekend\n * days, and optional form association.\n *\n * @element ore-calendar\n *\n * @attr {string} value - Selected date in ISO 8601 format (yyyy-MM-dd)\n * @attr {string} min - Minimum selectable date (yyyy-MM-dd)\n * @attr {string} max - Maximum selectable date (yyyy-MM-dd)\n * @attr {boolean} disabled - Disable all interaction\n * @attr {boolean} required - Required field (form association)\n * @attr {string} name - Form field name\n * @attr {string} color - Theme color: 'primary' | 'secondary' | 'info' | 'success' | 'warning' | 'error'\n * @attr {string} size - Component size: 'sm' | 'md' | 'lg'\n * @attr {string} rounded - Border radius: 'none' | 'sm' | 'md' | 'lg' | 'xl' | '2xl' | '3xl' | 'full'\n * @attr {string} locale - BCP 47 locale string\n * @attr {string} weekend-days - JSON array of day indices to disable (0=Sun…6=Sat)\n * @attr {boolean} fullwidth - Expand to full container width\n * @attr {boolean} expanded - Large-cell calendar-app layout with top-aligned day numbers\n *\n * @fires change - Fired when a date is selected. detail: { isoValue: string | null }\n *\n * @cssprop --calendar-bg - Calendar background\n * @cssprop --calendar-border-color - Calendar border color\n * @cssprop --calendar-radius - Calendar border radius\n * @cssprop --calendar-shadow - Calendar drop shadow\n * @cssprop --calendar-day-selected-bg - Background of selected day cell\n * @cssprop --calendar-day-today-color - Colour of today's date number\n * @cssprop --calendar-day-outside-opacity - Opacity of days outside visible month\n *\n * @part calendar - The root calendar panel\n * @part header - Calendar header (nav + label)\n * @part grid - Day grid\n * @part day - Individual day cell\n *\n * @example\n * ```html\n * <!-- Single date with bounds -->\n * <ore-calendar value=\"2025-06-15\" min=\"2025-01-01\" max=\"2025-12-31\" color=\"primary\"></ore-calendar>\n *\n * <!-- Expanded calendar-app layout -->\n * <ore-calendar expanded fullwidth color=\"primary\"></ore-calendar>\n * ```\n */\nexport const CALENDAR_TAG = 'ore-calendar' as const;\n\n/** Maximum event dots/pills shown per cell before \"+N\" overflow */\nconst MAX_EVENTS = 3;\n\n// ── Component ────────────────────────────────────────────────────────────────\n\ndefine<OreCalendarProps>(CALENDAR_TAG, {\n formAssociated: true,\n props: {\n ...themableBundle,\n ...sizableBundle,\n ...disablableBundle,\n ...roundableBundle,\n events: prop.json([] as CalendarEvent[]),\n expanded: prop.bool(false),\n fullwidth: prop.bool(false),\n locale: prop.string(),\n max: prop.string(),\n min: prop.string(),\n name: prop.string(),\n required: prop.bool(false),\n value: prop.string(),\n 'weekend-days': prop.json([] as number[]),\n },\n\n setup(props) {\n const emit = useEmit<OreCalendarEvents>();\n\n // ── Derived flags ────────────────────────────────────────────────────────\n\n const isDisabled = computed(() => props.disabled.value === true);\n const isExpanded = computed(() => props.expanded.value === true);\n\n // ── Selected date: local-override pattern ─────────────────────────────────\n // `localSelection` holds a user-initiated pick (or undefined = no override).\n // `selectedDate` derives from it, falling back to the value prop reactively.\n // This eliminates setInterval polling: external prop changes propagate\n // through the computed graph automatically.\n\n const localSelection = signal<Temporal.PlainDate | null | undefined>(undefined);\n\n const selectedDate = computed(() =>\n localSelection.value !== undefined ? localSelection.value : parseIso(props.value.value),\n );\n\n // ── Date-picker control ──────────────────────────────────────────────────\n\n const ctrl = createDatePickerControl({\n get locale() {\n return props.locale.value ?? (typeof navigator !== 'undefined' ? navigator.language : 'en');\n },\n get max() {\n return parseIso(props.max.value);\n },\n get min() {\n return parseIso(props.min.value);\n },\n onChange(date) {\n localSelection.value = date;\n currentView.value = 'day';\n displayYear.value = ctrl.displayYear();\n displayMonth.value = ctrl.displayMonth();\n emit('change', { isoValue: toIsoString(date) });\n },\n get value() {\n return selectedDate.value;\n },\n get weekendDays() {\n return props['weekend-days'].value ?? [];\n },\n });\n\n // ── Reactive display state ────────────────────────────────────────────────\n // Three separate primitive signals: the proven pattern. Mutating any one\n // of them invalidates only the computeds that read it.\n\n const currentView = signal<DatePickerView>('day');\n const displayYear = signal(ctrl.displayYear());\n const displayMonth = signal(ctrl.displayMonth()); // 1-indexed (Temporal)\n\n // ── Form value ───────────────────────────────────────────────────────────\n\n useField<string>({\n disabled: isDisabled,\n toFormValue: (v) => v || null,\n value: computed(() => toIsoString(selectedDate.value) ?? ''),\n });\n\n // ── Events lookup ─────────────────────────────────────────────────────────\n\n const eventsByDate = computed(() => {\n const map = new Map<string, CalendarEvent[]>();\n\n for (const evt of props.events.value ?? []) {\n const list = map.get(evt.date) ?? [];\n\n list.push(evt);\n map.set(evt.date, list);\n }\n\n return map;\n });\n\n // ── Derived cells ─────────────────────────────────────────────────────────\n // Each reads a display signal so they re-run when navigation changes.\n\n const dayCells = computed(() => {\n void displayYear.value;\n void displayMonth.value;\n void selectedDate.value; // re-run when selection changes to refresh isSelected flags\n\n return ctrl.dayCells();\n });\n const monthCells = computed(() => {\n void displayYear.value;\n\n return ctrl.monthCells();\n });\n const yearCells = computed(() => {\n void displayYear.value;\n\n return ctrl.yearCells();\n });\n const weekdayLabels = computed(() => ctrl.weekdayLabels());\n\n const displayMonth_ = computed(() => {\n const d = Temporal.PlainDate.from({ day: 1, month: displayMonth.value, year: displayYear.value });\n const loc = props.locale.value ?? (typeof navigator !== 'undefined' ? navigator.language : 'en');\n\n return format(d, { intl: { month: 'long' }, locale: loc, timeZone: 'UTC' });\n });\n\n const displayYear_ = computed(() => String(displayYear.value));\n const displayLabel = computed(() => `${displayMonth_.value} ${displayYear_.value}`);\n\n // ── Navigation ───────────────────────────────────────────────────────────\n\n function handlePrev(): void {\n if (currentView.value === 'day') ctrl.prevMonth();\n else ctrl.prevYear();\n\n displayYear.value = ctrl.displayYear();\n displayMonth.value = ctrl.displayMonth();\n }\n\n function handleNext(): void {\n if (currentView.value === 'day') ctrl.nextMonth();\n else ctrl.nextYear();\n\n displayYear.value = ctrl.displayYear();\n displayMonth.value = ctrl.displayMonth();\n }\n\n function handleHeaderClick(): void {\n const views: DatePickerView[] = ['day', 'month', 'year'];\n const next = views[(views.indexOf(currentView.value) + 1) % views.length];\n\n ctrl.setView(next);\n currentView.value = next;\n }\n\n // ── Selection handlers: all disabled guards live here ────────────────────\n\n function handleSelectMonth(month: number): void {\n if (isDisabled.value) return;\n\n ctrl.goTo(ctrl.displayYear(), month);\n ctrl.setView('day');\n displayYear.value = ctrl.displayYear();\n displayMonth.value = ctrl.displayMonth();\n currentView.value = 'day';\n }\n\n function handleSelectYear(year: number): void {\n if (isDisabled.value) return;\n\n ctrl.goTo(year, ctrl.displayMonth());\n ctrl.setView('month');\n displayYear.value = ctrl.displayYear();\n currentView.value = 'month';\n }\n\n function handleSelectDay(isoStr: string): void {\n if (isDisabled.value) return;\n\n const date = parseIso(isoStr);\n\n if (!date) return;\n\n ctrl.select(date); // ctrl.select() internally rejects disabled/out-of-range dates\n }\n\n // ── Cell keyboard navigation (shared ARIA grid pattern) ───────────────────\n // Day cells activate by their `data-iso`; month/year cells use their closure value.\n\n function handleDayKeydown(e: KeyboardEvent): void {\n handleCalendarGridKeydown(e, '.cal-cell-day', 7, (cell) => handleSelectDay(cell.dataset.iso ?? ''));\n }\n\n // ── Host bindings ────────────────────────────────────────────────────────\n\n bind({\n attr: {\n 'aria-disabled': () => (isDisabled.value ? 'true' : null),\n 'aria-label': () => displayLabel.value,\n role: 'group',\n },\n class: {\n 'is-disabled': isDisabled,\n },\n });\n\n // ── Template ─────────────────────────────────────────────────────────────\n\n return html`\n <div class=\"calendar\" part=\"calendar\" role=\"presentation\">\n <!-- Header -->\n <div class=\"cal-header\" part=\"header\">\n <button class=\"nav-btn\" type=\"button\" aria-label=\"Previous\" ?disabled=\"${isDisabled}\" @click=\"${handlePrev}\">\n <ore-icon name=\"chevron-left\" size=\"16\" stroke-width=\"2\" aria-hidden=\"true\"></ore-icon>\n </button>\n\n <button\n class=\"cal-label-btn\"\n type=\"button\"\n aria-label=\"${() =>\n `Switch to ${currentView.value === 'day' ? 'month' : currentView.value === 'month' ? 'year' : 'day'} view`}\"\n ?disabled=\"${isDisabled}\"\n @click=\"${handleHeaderClick}\">\n <span class=\"cal-label-month\">${displayMonth_}</span>\n <span class=\"cal-label-sep\" aria-hidden=\"true\">/</span>\n <span class=\"cal-label-year\">${displayYear_}</span>\n </button>\n\n <button class=\"nav-btn\" type=\"button\" aria-label=\"Next\" ?disabled=\"${isDisabled}\" @click=\"${handleNext}\">\n <ore-icon name=\"chevron-right\" size=\"16\" stroke-width=\"2\" aria-hidden=\"true\"></ore-icon>\n </button>\n </div>\n\n <!-- Day view -->\n <div\n class=\"cal-grid cal-grid-days\"\n role=\"grid\"\n part=\"grid\"\n aria-label=\"${() => displayLabel.value}\"\n ?hidden=\"${() => currentView.value !== 'day'}\">\n <div role=\"row\" class=\"cal-grid-row\">\n ${() =>\n weekdayLabels.value.map(\n (lbl) => html`\n <div class=\"cal-cell cal-cell-head\" role=\"columnheader\" aria-label=\"${lbl}\">${lbl}</div>\n `,\n )}\n </div>\n ${() => {\n const cells = dayCells.value;\n const rows: (typeof cells)[number][][] = [];\n\n for (let i = 0; i < cells.length; i += 7) rows.push(cells.slice(i, i + 7));\n\n return rows.map(\n (row) => html`\n <div role=\"row\" class=\"cal-grid-row\">\n ${row.map(\n (cell) => html`\n <div\n class=\"cal-cell cal-cell-day\"\n role=\"gridcell\"\n part=\"day\"\n aria-selected=\"${() => String(cell.isSelected)}\"\n aria-disabled=\"${() => String(cell.isDisabled || isDisabled.value)}\"\n aria-current=\"${() => (cell.isToday ? 'date' : null)}\"\n ?data-selected=\"${() => cell.isSelected}\"\n ?data-today=\"${() => cell.isToday}\"\n ?data-outside=\"${() => cell.isOutsideMonth}\"\n ?data-disabled=\"${() => cell.isDisabled || isDisabled.value}\"\n data-iso=\"${cell.iso}\"\n data-day=\"${String(cell.day)}\"\n tabindex=\"${() => (cell.isDisabled || isDisabled.value ? '-1' : '0')}\"\n @click=\"${() => handleSelectDay(cell.iso)}\"\n @keydown=\"${handleDayKeydown}\">\n ${String(cell.day)}\n ${() => {\n const evts = eventsByDate.value.get(cell.iso) ?? [];\n\n if (!evts.length) return html``;\n\n const shown = evts.slice(0, MAX_EVENTS);\n const overflow = evts.length - MAX_EVENTS;\n\n if (isExpanded.value) {\n // Text node is written tag-tight (no inner line breaks): this custom\n // `html` tagged template does not collapse whitespace at runtime like a\n // browser parser would, so a pretty-printed multi-line `<span>...</span>`\n // here would render literal newlines/indentation into `textContent`.\n // biome-ignore format: Preserve text-node whitespace in the template.\n const overflowPill =\n overflow > 0\n ? html`<span class=\"cal-event-pill-overflow\" aria-hidden=\"true\"\n >+${overflow} more</span\n >`\n : html``;\n\n return html`\n <div\n class=\"cal-events\"\n aria-label=\"${() => `${evts.length} event${evts.length > 1 ? 's' : ''}`}\">\n ${shown.map(\n (evt) => html`\n <ore-badge\n class=\"cal-event-pill\"\n size=\"xs\"\n rounded=\"sm\"\n aria-label=\"${evt.label}\"\n style=\"${styleMap({\n '--badge-bg': evt.color,\n '--badge-border-color': evt.color,\n })}\">\n ${evt.label}\n </ore-badge>\n `,\n )}\n ${overflowPill}\n </div>\n `;\n }\n\n return html`\n <div\n class=\"cal-dots\"\n aria-label=\"${() => `${evts.length} event${evts.length > 1 ? 's' : ''}`}\">\n ${shown.map(\n (evt) => html`\n <ore-badge\n class=\"cal-dot\"\n dot\n size=\"xs\"\n aria-hidden=\"true\"\n style=\"${styleMap({\n '--badge-bg': evt.color,\n '--badge-border-color': evt.color,\n })}\"></ore-badge>\n `,\n )}\n ${\n overflow > 0\n ? html`\n <span class=\"cal-dot-overflow\" aria-hidden=\"true\">+${overflow}</span>\n `\n : html``\n }\n </div>\n `;\n }}\n </div>\n `,\n )}\n </div>\n `,\n );\n }}\n </div>\n\n <!-- Month view -->\n <div\n class=\"cal-grid cal-grid-months\"\n role=\"grid\"\n aria-label=\"${() => displayYear_.value}\"\n ?hidden=\"${() => currentView.value !== 'month'}\">\n ${() => {\n const cells = monthCells.value;\n const rows: (typeof cells)[number][][] = [];\n\n for (let i = 0; i < cells.length; i += 4) rows.push(cells.slice(i, i + 4));\n\n return rows.map(\n (row) => html`\n <div role=\"row\">\n ${row.map(\n (cell) => html`\n <div\n class=\"cal-cell cal-cell-month\"\n role=\"gridcell\"\n aria-selected=\"${() => String(cell.isSelected)}\"\n aria-disabled=\"${() => String(cell.isDisabled || isDisabled.value)}\"\n ?data-selected=\"${() => cell.isSelected}\"\n ?data-disabled=\"${() => cell.isDisabled || isDisabled.value}\"\n tabindex=\"${() => (cell.isDisabled || isDisabled.value ? '-1' : '0')}\"\n @click=\"${() => handleSelectMonth(cell.month)}\"\n @keydown=\"${(e: KeyboardEvent) =>\n handleCalendarGridKeydown(e, '.cal-cell-month', 4, () => handleSelectMonth(cell.month))}\">\n ${cell.shortLabel}\n </div>\n `,\n )}\n </div>\n `,\n );\n }}\n </div>\n\n <!-- Year view -->\n <div\n class=\"cal-grid cal-grid-years\"\n role=\"grid\"\n aria-label=\"Select year\"\n ?hidden=\"${() => currentView.value !== 'year'}\">\n ${() => {\n const cells = yearCells.value;\n const rows: (typeof cells)[number][][] = [];\n\n for (let i = 0; i < cells.length; i += 4) rows.push(cells.slice(i, i + 4));\n\n return rows.map(\n (row) => html`\n <div role=\"row\">\n ${row.map(\n (cell) => html`\n <div\n class=\"cal-cell cal-cell-year\"\n role=\"gridcell\"\n aria-selected=\"${() => String(cell.isSelected)}\"\n aria-disabled=\"${() => String(cell.isDisabled || isDisabled.value)}\"\n ?data-selected=\"${() => cell.isSelected}\"\n ?data-disabled=\"${() => cell.isDisabled || isDisabled.value}\"\n tabindex=\"${() => (cell.isDisabled || isDisabled.value ? '-1' : '0')}\"\n @click=\"${() => handleSelectYear(cell.year)}\"\n @keydown=\"${(e: KeyboardEvent) =>\n handleCalendarGridKeydown(e, '.cal-cell-year', 4, () => handleSelectYear(cell.year))}\">\n ${String(cell.year)}\n </div>\n `,\n )}\n </div>\n `,\n );\n }}\n </div>\n </div>\n `;\n },\n shadow: { delegatesFocus: true },\n styles: [colorThemeMixin, reducedMotionMixin, componentStyles],\n});\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"calendar.js","names":[],"sources":["../src/inputs/calendar/calendar.ts"],"sourcesContent":["import { bind, define, html, prop, styleMap, useEmit, useField } from '@vielzeug/ore';\nimport { computed, signal } from '@vielzeug/ripple';\nimport { format, Temporal } from '@vielzeug/tempo';\nimport {\n createDatePickerControl,\n type DatePickerView,\n handleCalendarGridKeydown,\n parseIso,\n toIsoString,\n} from '../../core';\nimport type { ComponentSize, RoundedSize, ThemeColor } from '../../shared';\nimport { disablableBundle, roundableBundle, sizableBundle, themableBundle } from '../../shared';\nimport { colorThemeMixin, reducedMotionMixin } from '../../styles';\nimport componentStyles from './calendar.css?inline';\n\nexport { ICON_TAG } from '../../content/icon/icon';\nexport { BADGE_TAG } from '../../feedback/badge/badge';\n// ── Types ─────────────────────────────────────────────────────────────────────\n\nexport type OreCalendarEvents = {\n change: { isoValue: string | null };\n};\n\n/**\n * A calendar event entry.\n * Dates must be ISO 8601 strings (yyyy-MM-dd).\n *\n * The `color` field accepts any valid CSS color value (e.g. `'#e11d48'`,\n * `'var(--color-primary)'`). An invalid value silently falls back to the\n * component's theme color. Only pass values you control.\n */\nexport type CalendarEvent = {\n /**\n * Any CSS color value for the event dot / pill.\n * Defaults to the component's theme color when omitted.\n * Rendered via `styleMap()`, which strips `;`/`{`/`}` so the value can't break out of\n * its custom-property declaration — it is not a full CSS-color syntax validator, so an\n * invalid (but injection-safe) value may still render as no color.\n */\n color?: string;\n /** ISO date the event falls on (yyyy-MM-dd) */\n date: string;\n /** Unique identifier */\n id: string;\n /** Short label shown in the calendar cell */\n label: string;\n};\n\nexport type OreCalendarProps = {\n /** Theme color */\n color?: ThemeColor;\n /** Disable all date selection */\n disabled?: boolean;\n /**\n * Array of calendar events to display on day cells.\n * In normal mode each event renders as a small colored dot (max 3 dots, then \"+N\").\n * In expanded mode each event renders as a full-width colored pill with its label.\n * Pass as a JS property or as a JSON-encoded attribute.\n * @example\n * ```js\n * calendar.events = [\n * { id: '1', date: '2025-06-15', label: 'Team standup', color: 'var(--color-primary)' },\n * { id: '2', date: '2025-06-20', label: 'Release', color: '#e11d48' },\n * ];\n * ```\n */\n events?: CalendarEvent[];\n /**\n * Expanded layout — large cells with top-aligned day numbers suitable\n * for a full-page calendar app view.\n */\n expanded?: boolean;\n /** Expand to container width */\n fullwidth?: boolean;\n /** Locale for day/month names (default: browser locale) */\n locale?: string;\n /** Latest selectable date in ISO 8601 format (yyyy-MM-dd) */\n max?: string;\n /** Earliest selectable date in ISO 8601 format (yyyy-MM-dd) */\n min?: string;\n /** Form field name (when used inside a form) */\n name?: string;\n /** Mark field as required */\n required?: boolean;\n /** Border radius override */\n rounded?: RoundedSize;\n /** Component size */\n size?: ComponentSize;\n /**\n * Selected date in ISO 8601 format (yyyy-MM-dd).\n * @example '2025-06-15'\n */\n value?: string;\n /**\n * Day-of-week indices to disable (0 = Sunday … 6 = Saturday).\n * Pass as a JSON array attribute or a JS property.\n * @example\n * ```html\n * <ore-calendar weekend-days=\"[0,6]\"></ore-calendar>\n * ```\n */\n 'weekend-days'?: number[];\n};\n\n/**\n * An accessible, keyboard-navigable inline calendar component.\n * Supports day/month/year drill-down views, min/max bounds, disabled weekend\n * days, and optional form association.\n *\n * @element ore-calendar\n *\n * @attr {string} value - Selected date in ISO 8601 format (yyyy-MM-dd)\n * @attr {string} min - Minimum selectable date (yyyy-MM-dd)\n * @attr {string} max - Maximum selectable date (yyyy-MM-dd)\n * @attr {boolean} disabled - Disable all interaction\n * @attr {boolean} required - Required field (form association)\n * @attr {string} name - Form field name\n * @attr {string} color - Theme color: 'primary' | 'secondary' | 'info' | 'success' | 'warning' | 'error'\n * @attr {string} size - Component size: 'sm' | 'md' | 'lg'\n * @attr {string} rounded - Border radius: 'none' | 'sm' | 'md' | 'lg' | 'xl' | '2xl' | '3xl' | 'full'\n * @attr {string} locale - BCP 47 locale string\n * @attr {string} weekend-days - JSON array of day indices to disable (0=Sun…6=Sat)\n * @attr {boolean} fullwidth - Expand to full container width\n * @attr {boolean} expanded - Large-cell calendar-app layout with top-aligned day numbers\n *\n * @fires change - Fired when a date is selected. detail: { isoValue: string | null }\n *\n * @cssprop --calendar-bg - Calendar background\n * @cssprop --calendar-border-color - Calendar border color\n * @cssprop --calendar-radius - Calendar border radius\n * @cssprop --calendar-shadow - Calendar drop shadow\n * @cssprop --calendar-day-selected-bg - Background of selected day cell\n * @cssprop --calendar-day-today-color - Colour of today's date number\n * @cssprop --calendar-day-outside-opacity - Opacity of days outside visible month\n *\n * @part calendar - The root calendar panel\n * @part header - Calendar header (nav + label)\n * @part grid - Day grid\n * @part day - Individual day cell\n *\n * @example\n * ```html\n * <!-- Single date with bounds -->\n * <ore-calendar value=\"2025-06-15\" min=\"2025-01-01\" max=\"2025-12-31\" color=\"primary\"></ore-calendar>\n *\n * <!-- Expanded calendar-app layout -->\n * <ore-calendar expanded fullwidth color=\"primary\"></ore-calendar>\n * ```\n */\nexport const CALENDAR_TAG = 'ore-calendar' as const;\n\n/** Maximum event dots/pills shown per cell before \"+N\" overflow */\nconst MAX_EVENTS = 3;\n\n// ── Component ────────────────────────────────────────────────────────────────\n\ndefine<OreCalendarProps>(CALENDAR_TAG, {\n formAssociated: true,\n props: {\n ...themableBundle,\n ...sizableBundle,\n ...disablableBundle,\n ...roundableBundle,\n events: prop.json([] as CalendarEvent[]),\n expanded: prop.bool(false),\n fullwidth: prop.bool(false),\n locale: prop.string(),\n max: prop.string(),\n min: prop.string(),\n name: prop.string(),\n required: prop.bool(false),\n value: prop.string(),\n 'weekend-days': prop.json([] as number[]),\n },\n\n setup(props) {\n const emit = useEmit<OreCalendarEvents>();\n\n // ── Derived flags ────────────────────────────────────────────────────────\n\n const isDisabled = computed(() => props.disabled.value === true);\n const isExpanded = computed(() => props.expanded.value === true);\n\n // ── Selected date: local-override pattern ─────────────────────────────────\n // `localSelection` holds a user-initiated pick (or undefined = no override).\n // `selectedDate` derives from it, falling back to the value prop reactively.\n // This eliminates setInterval polling — external prop changes propagate\n // through the computed graph automatically.\n\n const localSelection = signal<Temporal.PlainDate | null | undefined>(undefined);\n\n const selectedDate = computed(() =>\n localSelection.value !== undefined ? localSelection.value : parseIso(props.value.value),\n );\n\n // ── Date-picker control ──────────────────────────────────────────────────\n\n const ctrl = createDatePickerControl({\n get locale() {\n return props.locale.value ?? (typeof navigator !== 'undefined' ? navigator.language : 'en');\n },\n get max() {\n return parseIso(props.max.value);\n },\n get min() {\n return parseIso(props.min.value);\n },\n onChange(date) {\n localSelection.value = date;\n currentView.value = 'day';\n displayYear.value = ctrl.displayYear();\n displayMonth.value = ctrl.displayMonth();\n emit('change', { isoValue: toIsoString(date) });\n },\n get value() {\n return selectedDate.value;\n },\n get weekendDays() {\n return props['weekend-days'].value ?? [];\n },\n });\n\n // ── Reactive display state ────────────────────────────────────────────────\n // Three separate primitive signals — the proven pattern. Mutating any one\n // of them invalidates only the computeds that read it.\n\n const currentView = signal<DatePickerView>('day');\n const displayYear = signal(ctrl.displayYear());\n const displayMonth = signal(ctrl.displayMonth()); // 1-indexed (Temporal)\n\n // ── Form value ───────────────────────────────────────────────────────────\n\n useField<string>({\n disabled: isDisabled,\n toFormValue: (v) => v || null,\n value: computed(() => toIsoString(selectedDate.value) ?? ''),\n });\n\n // ── Events lookup ─────────────────────────────────────────────────────────\n\n const eventsByDate = computed(() => {\n const map = new Map<string, CalendarEvent[]>();\n\n for (const evt of props.events.value ?? []) {\n const list = map.get(evt.date) ?? [];\n\n list.push(evt);\n map.set(evt.date, list);\n }\n\n return map;\n });\n\n // ── Derived cells ─────────────────────────────────────────────────────────\n // Each reads a display signal so they re-run when navigation changes.\n\n const dayCells = computed(() => {\n void displayYear.value;\n void displayMonth.value;\n void selectedDate.value; // re-run when selection changes to refresh isSelected flags\n\n return ctrl.dayCells();\n });\n const monthCells = computed(() => {\n void displayYear.value;\n\n return ctrl.monthCells();\n });\n const yearCells = computed(() => {\n void displayYear.value;\n\n return ctrl.yearCells();\n });\n const weekdayLabels = computed(() => ctrl.weekdayLabels());\n\n const displayMonth_ = computed(() => {\n const d = Temporal.PlainDate.from({ day: 1, month: displayMonth.value, year: displayYear.value });\n const loc = props.locale.value ?? (typeof navigator !== 'undefined' ? navigator.language : 'en');\n\n return format(d, { intl: { month: 'long' }, locale: loc, timeZone: 'UTC' });\n });\n\n const displayYear_ = computed(() => String(displayYear.value));\n const displayLabel = computed(() => `${displayMonth_.value} ${displayYear_.value}`);\n\n // ── Navigation ───────────────────────────────────────────────────────────\n\n function handlePrev(): void {\n if (currentView.value === 'day') ctrl.prevMonth();\n else ctrl.prevYear();\n\n displayYear.value = ctrl.displayYear();\n displayMonth.value = ctrl.displayMonth();\n }\n\n function handleNext(): void {\n if (currentView.value === 'day') ctrl.nextMonth();\n else ctrl.nextYear();\n\n displayYear.value = ctrl.displayYear();\n displayMonth.value = ctrl.displayMonth();\n }\n\n function handleHeaderClick(): void {\n const views: DatePickerView[] = ['day', 'month', 'year'];\n const next = views[(views.indexOf(currentView.value) + 1) % views.length];\n\n ctrl.setView(next);\n currentView.value = next;\n }\n\n // ── Selection handlers — all disabled guards live here ────────────────────\n\n function handleSelectMonth(month: number): void {\n if (isDisabled.value) return;\n\n ctrl.goTo(ctrl.displayYear(), month);\n ctrl.setView('day');\n displayYear.value = ctrl.displayYear();\n displayMonth.value = ctrl.displayMonth();\n currentView.value = 'day';\n }\n\n function handleSelectYear(year: number): void {\n if (isDisabled.value) return;\n\n ctrl.goTo(year, ctrl.displayMonth());\n ctrl.setView('month');\n displayYear.value = ctrl.displayYear();\n currentView.value = 'month';\n }\n\n function handleSelectDay(isoStr: string): void {\n if (isDisabled.value) return;\n\n const date = parseIso(isoStr);\n\n if (!date) return;\n\n ctrl.select(date); // ctrl.select() internally rejects disabled/out-of-range dates\n }\n\n // ── Cell keyboard navigation (shared ARIA grid pattern) ───────────────────\n // Day cells activate by their `data-iso`; month/year cells use their closure value.\n\n function handleDayKeydown(e: KeyboardEvent): void {\n handleCalendarGridKeydown(e, '.cal-cell-day', 7, (cell) => handleSelectDay(cell.dataset.iso ?? ''));\n }\n\n // ── Host bindings ────────────────────────────────────────────────────────\n\n bind({\n attr: {\n 'aria-disabled': () => (isDisabled.value ? 'true' : null),\n 'aria-label': () => displayLabel.value,\n role: 'group',\n },\n class: {\n 'is-disabled': isDisabled,\n },\n });\n\n // ── Template ─────────────────────────────────────────────────────────────\n\n return html`\n <div class=\"calendar\" part=\"calendar\" role=\"presentation\">\n <!-- Header -->\n <div class=\"cal-header\" part=\"header\">\n <button class=\"nav-btn\" type=\"button\" aria-label=\"Previous\" ?disabled=\"${isDisabled}\" @click=\"${handlePrev}\">\n <ore-icon name=\"chevron-left\" size=\"16\" stroke-width=\"2\" aria-hidden=\"true\"></ore-icon>\n </button>\n\n <button\n class=\"cal-label-btn\"\n type=\"button\"\n aria-label=\"${() =>\n `Switch to ${currentView.value === 'day' ? 'month' : currentView.value === 'month' ? 'year' : 'day'} view`}\"\n ?disabled=\"${isDisabled}\"\n @click=\"${handleHeaderClick}\">\n <span class=\"cal-label-month\">${displayMonth_}</span>\n <span class=\"cal-label-sep\" aria-hidden=\"true\">/</span>\n <span class=\"cal-label-year\">${displayYear_}</span>\n </button>\n\n <button class=\"nav-btn\" type=\"button\" aria-label=\"Next\" ?disabled=\"${isDisabled}\" @click=\"${handleNext}\">\n <ore-icon name=\"chevron-right\" size=\"16\" stroke-width=\"2\" aria-hidden=\"true\"></ore-icon>\n </button>\n </div>\n\n <!-- Day view -->\n <div\n class=\"cal-grid cal-grid-days\"\n role=\"grid\"\n part=\"grid\"\n aria-label=\"${() => displayLabel.value}\"\n ?hidden=\"${() => currentView.value !== 'day'}\">\n <div role=\"row\" class=\"cal-grid-row\">\n ${() =>\n weekdayLabels.value.map(\n (lbl) => html`\n <div class=\"cal-cell cal-cell-head\" role=\"columnheader\" aria-label=\"${lbl}\">${lbl}</div>\n `,\n )}\n </div>\n ${() => {\n const cells = dayCells.value;\n const rows: (typeof cells)[number][][] = [];\n\n for (let i = 0; i < cells.length; i += 7) rows.push(cells.slice(i, i + 7));\n\n return rows.map(\n (row) => html`\n <div role=\"row\" class=\"cal-grid-row\">\n ${row.map(\n (cell) => html`\n <div\n class=\"cal-cell cal-cell-day\"\n role=\"gridcell\"\n part=\"day\"\n aria-selected=\"${() => String(cell.isSelected)}\"\n aria-disabled=\"${() => String(cell.isDisabled || isDisabled.value)}\"\n aria-current=\"${() => (cell.isToday ? 'date' : null)}\"\n ?data-selected=\"${() => cell.isSelected}\"\n ?data-today=\"${() => cell.isToday}\"\n ?data-outside=\"${() => cell.isOutsideMonth}\"\n ?data-disabled=\"${() => cell.isDisabled || isDisabled.value}\"\n data-iso=\"${cell.iso}\"\n data-day=\"${String(cell.day)}\"\n tabindex=\"${() => (cell.isDisabled || isDisabled.value ? '-1' : '0')}\"\n @click=\"${() => handleSelectDay(cell.iso)}\"\n @keydown=\"${handleDayKeydown}\">\n ${String(cell.day)}\n ${() => {\n const evts = eventsByDate.value.get(cell.iso) ?? [];\n\n if (!evts.length) return html``;\n\n const shown = evts.slice(0, MAX_EVENTS);\n const overflow = evts.length - MAX_EVENTS;\n\n if (isExpanded.value) {\n // Text node is written tag-tight (no inner line breaks) — this custom\n // `html` tagged template does not collapse whitespace at runtime like a\n // browser parser would, so a pretty-printed multi-line `<span>...</span>`\n // here would render literal newlines/indentation into `textContent`.\n // biome-ignore format: Preserve text-node whitespace in the template.\n const overflowPill =\n overflow > 0\n ? html`<span class=\"cal-event-pill-overflow\" aria-hidden=\"true\"\n >+${overflow} more</span\n >`\n : html``;\n\n return html`\n <div\n class=\"cal-events\"\n aria-label=\"${() => `${evts.length} event${evts.length > 1 ? 's' : ''}`}\">\n ${shown.map(\n (evt) => html`\n <ore-badge\n class=\"cal-event-pill\"\n size=\"xs\"\n rounded=\"sm\"\n aria-label=\"${evt.label}\"\n style=\"${styleMap({\n '--badge-bg': evt.color,\n '--badge-border-color': evt.color,\n })}\">\n ${evt.label}\n </ore-badge>\n `,\n )}\n ${overflowPill}\n </div>\n `;\n }\n\n return html`\n <div\n class=\"cal-dots\"\n aria-label=\"${() => `${evts.length} event${evts.length > 1 ? 's' : ''}`}\">\n ${shown.map(\n (evt) => html`\n <ore-badge\n class=\"cal-dot\"\n dot\n size=\"xs\"\n aria-hidden=\"true\"\n style=\"${styleMap({\n '--badge-bg': evt.color,\n '--badge-border-color': evt.color,\n })}\"></ore-badge>\n `,\n )}\n ${\n overflow > 0\n ? html`\n <span class=\"cal-dot-overflow\" aria-hidden=\"true\">+${overflow}</span>\n `\n : html``\n }\n </div>\n `;\n }}\n </div>\n `,\n )}\n </div>\n `,\n );\n }}\n </div>\n\n <!-- Month view -->\n <div\n class=\"cal-grid cal-grid-months\"\n role=\"grid\"\n aria-label=\"${() => displayYear_.value}\"\n ?hidden=\"${() => currentView.value !== 'month'}\">\n ${() => {\n const cells = monthCells.value;\n const rows: (typeof cells)[number][][] = [];\n\n for (let i = 0; i < cells.length; i += 4) rows.push(cells.slice(i, i + 4));\n\n return rows.map(\n (row) => html`\n <div role=\"row\">\n ${row.map(\n (cell) => html`\n <div\n class=\"cal-cell cal-cell-month\"\n role=\"gridcell\"\n aria-selected=\"${() => String(cell.isSelected)}\"\n aria-disabled=\"${() => String(cell.isDisabled || isDisabled.value)}\"\n ?data-selected=\"${() => cell.isSelected}\"\n ?data-disabled=\"${() => cell.isDisabled || isDisabled.value}\"\n tabindex=\"${() => (cell.isDisabled || isDisabled.value ? '-1' : '0')}\"\n @click=\"${() => handleSelectMonth(cell.month)}\"\n @keydown=\"${(e: KeyboardEvent) =>\n handleCalendarGridKeydown(e, '.cal-cell-month', 4, () => handleSelectMonth(cell.month))}\">\n ${cell.shortLabel}\n </div>\n `,\n )}\n </div>\n `,\n );\n }}\n </div>\n\n <!-- Year view -->\n <div\n class=\"cal-grid cal-grid-years\"\n role=\"grid\"\n aria-label=\"Select year\"\n ?hidden=\"${() => currentView.value !== 'year'}\">\n ${() => {\n const cells = yearCells.value;\n const rows: (typeof cells)[number][][] = [];\n\n for (let i = 0; i < cells.length; i += 4) rows.push(cells.slice(i, i + 4));\n\n return rows.map(\n (row) => html`\n <div role=\"row\">\n ${row.map(\n (cell) => html`\n <div\n class=\"cal-cell cal-cell-year\"\n role=\"gridcell\"\n aria-selected=\"${() => String(cell.isSelected)}\"\n aria-disabled=\"${() => String(cell.isDisabled || isDisabled.value)}\"\n ?data-selected=\"${() => cell.isSelected}\"\n ?data-disabled=\"${() => cell.isDisabled || isDisabled.value}\"\n tabindex=\"${() => (cell.isDisabled || isDisabled.value ? '-1' : '0')}\"\n @click=\"${() => handleSelectYear(cell.year)}\"\n @keydown=\"${(e: KeyboardEvent) =>\n handleCalendarGridKeydown(e, '.cal-cell-year', 4, () => handleSelectYear(cell.year))}\">\n ${String(cell.year)}\n </div>\n `,\n )}\n </div>\n `,\n );\n }}\n </div>\n </div>\n `;\n },\n shadow: { delegatesFocus: true },\n styles: [colorThemeMixin, reducedMotionMixin, componentStyles],\n});\n"],"mappings":"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"}
1
+ {"version":3,"file":"calendar.js","names":[],"sources":["../src/inputs/calendar/calendar.ts"],"sourcesContent":["import { bind, define, html, prop, styleMap, useEmit, useField } from '@vielzeug/ore';\nimport { computed, signal } from '@vielzeug/ripple';\nimport { format, Temporal } from '@vielzeug/tempo';\nimport {\n createDatePickerControl,\n type DatePickerView,\n handleCalendarGridKeydown,\n parseIso,\n toIsoString,\n} from '../../core';\nimport type { ComponentSize, RoundedSize, ThemeColor } from '../../shared';\nimport { disablableBundle, roundableBundle, sizableBundle, themableBundle } from '../../shared';\nimport { colorThemeMixin, reducedMotionMixin } from '../../styles';\nimport componentStyles from './calendar.css?inline';\n\nexport { ICON_TAG } from '../../content/icon/icon';\nexport { BADGE_TAG } from '../../feedback/badge/badge';\n// ── Types ─────────────────────────────────────────────────────────────────────\n\nexport type OreCalendarEvents = {\n change: { isoValue: string | null };\n};\n\n/**\n * A calendar event entry.\n * Dates must be ISO 8601 strings (yyyy-MM-dd).\n *\n * The `color` field accepts any valid CSS color value (e.g. `'#e11d48'`,\n * `'var(--color-primary)'`). An invalid value silently falls back to the\n * component's theme color. Only pass values you control.\n */\nexport type CalendarEvent = {\n /**\n * Any CSS color value for the event dot / pill.\n * Defaults to the component's theme color when omitted.\n * Rendered via `styleMap()`, which strips `;`/`{`/`}` so the value can't break out of\n * its custom-property declaration: it is not a full CSS-color syntax validator, so an\n * invalid (but injection-safe) value may still render as no color.\n */\n color?: string;\n /** ISO date the event falls on (yyyy-MM-dd) */\n date: string;\n /** Unique identifier */\n id: string;\n /** Short label shown in the calendar cell */\n label: string;\n};\n\nexport type OreCalendarProps = {\n /** Theme color */\n color?: ThemeColor;\n /** Disable all date selection */\n disabled?: boolean;\n /**\n * Array of calendar events to display on day cells.\n * In normal mode each event renders as a small colored dot (max 3 dots, then \"+N\").\n * In expanded mode each event renders as a full-width colored pill with its label.\n * Pass as a JS property or as a JSON-encoded attribute.\n * @example\n * ```js\n * calendar.events = [\n * { id: '1', date: '2025-06-15', label: 'Team standup', color: 'var(--color-primary)' },\n * { id: '2', date: '2025-06-20', label: 'Release', color: '#e11d48' },\n * ];\n * ```\n */\n events?: CalendarEvent[];\n /**\n * Expanded layout: large cells with top-aligned day numbers suitable\n * for a full-page calendar app view.\n */\n expanded?: boolean;\n /** Expand to container width */\n fullwidth?: boolean;\n /** Locale for day/month names (default: browser locale) */\n locale?: string;\n /** Latest selectable date in ISO 8601 format (yyyy-MM-dd) */\n max?: string;\n /** Earliest selectable date in ISO 8601 format (yyyy-MM-dd) */\n min?: string;\n /** Form field name (when used inside a form) */\n name?: string;\n /** Mark field as required */\n required?: boolean;\n /** Border radius override */\n rounded?: RoundedSize;\n /** Component size */\n size?: ComponentSize;\n /**\n * Selected date in ISO 8601 format (yyyy-MM-dd).\n * @example '2025-06-15'\n */\n value?: string;\n /**\n * Day-of-week indices to disable (0 = Sunday … 6 = Saturday).\n * Pass as a JSON array attribute or a JS property.\n * @example\n * ```html\n * <ore-calendar weekend-days=\"[0,6]\"></ore-calendar>\n * ```\n */\n 'weekend-days'?: number[];\n};\n\n/**\n * An accessible, keyboard-navigable inline calendar component.\n * Supports day/month/year drill-down views, min/max bounds, disabled weekend\n * days, and optional form association.\n *\n * @element ore-calendar\n *\n * @attr {string} value - Selected date in ISO 8601 format (yyyy-MM-dd)\n * @attr {string} min - Minimum selectable date (yyyy-MM-dd)\n * @attr {string} max - Maximum selectable date (yyyy-MM-dd)\n * @attr {boolean} disabled - Disable all interaction\n * @attr {boolean} required - Required field (form association)\n * @attr {string} name - Form field name\n * @attr {string} color - Theme color: 'primary' | 'secondary' | 'info' | 'success' | 'warning' | 'error'\n * @attr {string} size - Component size: 'sm' | 'md' | 'lg'\n * @attr {string} rounded - Border radius: 'none' | 'sm' | 'md' | 'lg' | 'xl' | '2xl' | '3xl' | 'full'\n * @attr {string} locale - BCP 47 locale string\n * @attr {string} weekend-days - JSON array of day indices to disable (0=Sun…6=Sat)\n * @attr {boolean} fullwidth - Expand to full container width\n * @attr {boolean} expanded - Large-cell calendar-app layout with top-aligned day numbers\n *\n * @fires change - Fired when a date is selected. detail: { isoValue: string | null }\n *\n * @cssprop --calendar-bg - Calendar background\n * @cssprop --calendar-border-color - Calendar border color\n * @cssprop --calendar-radius - Calendar border radius\n * @cssprop --calendar-shadow - Calendar drop shadow\n * @cssprop --calendar-day-selected-bg - Background of selected day cell\n * @cssprop --calendar-day-today-color - Colour of today's date number\n * @cssprop --calendar-day-outside-opacity - Opacity of days outside visible month\n *\n * @part calendar - The root calendar panel\n * @part header - Calendar header (nav + label)\n * @part grid - Day grid\n * @part day - Individual day cell\n *\n * @example\n * ```html\n * <!-- Single date with bounds -->\n * <ore-calendar value=\"2025-06-15\" min=\"2025-01-01\" max=\"2025-12-31\" color=\"primary\"></ore-calendar>\n *\n * <!-- Expanded calendar-app layout -->\n * <ore-calendar expanded fullwidth color=\"primary\"></ore-calendar>\n * ```\n */\nexport const CALENDAR_TAG = 'ore-calendar' as const;\n\n/** Maximum event dots/pills shown per cell before \"+N\" overflow */\nconst MAX_EVENTS = 3;\n\n// ── Component ────────────────────────────────────────────────────────────────\n\ndefine<OreCalendarProps>(CALENDAR_TAG, {\n formAssociated: true,\n props: {\n ...themableBundle,\n ...sizableBundle,\n ...disablableBundle,\n ...roundableBundle,\n events: prop.json([] as CalendarEvent[]),\n expanded: prop.bool(false),\n fullwidth: prop.bool(false),\n locale: prop.string(),\n max: prop.string(),\n min: prop.string(),\n name: prop.string(),\n required: prop.bool(false),\n value: prop.string(),\n 'weekend-days': prop.json([] as number[]),\n },\n\n setup(props) {\n const emit = useEmit<OreCalendarEvents>();\n\n // ── Derived flags ────────────────────────────────────────────────────────\n\n const isDisabled = computed(() => props.disabled.value === true);\n const isExpanded = computed(() => props.expanded.value === true);\n\n // ── Selected date: local-override pattern ─────────────────────────────────\n // `localSelection` holds a user-initiated pick (or undefined = no override).\n // `selectedDate` derives from it, falling back to the value prop reactively.\n // This eliminates setInterval polling: external prop changes propagate\n // through the computed graph automatically.\n\n const localSelection = signal<Temporal.PlainDate | null | undefined>(undefined);\n\n const selectedDate = computed(() =>\n localSelection.value !== undefined ? localSelection.value : parseIso(props.value.value),\n );\n\n // ── Date-picker control ──────────────────────────────────────────────────\n\n const ctrl = createDatePickerControl({\n get locale() {\n return props.locale.value ?? (typeof navigator !== 'undefined' ? navigator.language : 'en');\n },\n get max() {\n return parseIso(props.max.value);\n },\n get min() {\n return parseIso(props.min.value);\n },\n onChange(date) {\n localSelection.value = date;\n currentView.value = 'day';\n displayYear.value = ctrl.displayYear();\n displayMonth.value = ctrl.displayMonth();\n emit('change', { isoValue: toIsoString(date) });\n },\n get value() {\n return selectedDate.value;\n },\n get weekendDays() {\n return props['weekend-days'].value ?? [];\n },\n });\n\n // ── Reactive display state ────────────────────────────────────────────────\n // Three separate primitive signals: the proven pattern. Mutating any one\n // of them invalidates only the computeds that read it.\n\n const currentView = signal<DatePickerView>('day');\n const displayYear = signal(ctrl.displayYear());\n const displayMonth = signal(ctrl.displayMonth()); // 1-indexed (Temporal)\n\n // ── Form value ───────────────────────────────────────────────────────────\n\n useField<string>({\n disabled: isDisabled,\n toFormValue: (v) => v || null,\n value: computed(() => toIsoString(selectedDate.value) ?? ''),\n });\n\n // ── Events lookup ─────────────────────────────────────────────────────────\n\n const eventsByDate = computed(() => {\n const map = new Map<string, CalendarEvent[]>();\n\n for (const evt of props.events.value ?? []) {\n const list = map.get(evt.date) ?? [];\n\n list.push(evt);\n map.set(evt.date, list);\n }\n\n return map;\n });\n\n // ── Derived cells ─────────────────────────────────────────────────────────\n // Each reads a display signal so they re-run when navigation changes.\n\n const dayCells = computed(() => {\n void displayYear.value;\n void displayMonth.value;\n void selectedDate.value; // re-run when selection changes to refresh isSelected flags\n\n return ctrl.dayCells();\n });\n const monthCells = computed(() => {\n void displayYear.value;\n\n return ctrl.monthCells();\n });\n const yearCells = computed(() => {\n void displayYear.value;\n\n return ctrl.yearCells();\n });\n const weekdayLabels = computed(() => ctrl.weekdayLabels());\n\n const displayMonth_ = computed(() => {\n const d = Temporal.PlainDate.from({ day: 1, month: displayMonth.value, year: displayYear.value });\n const loc = props.locale.value ?? (typeof navigator !== 'undefined' ? navigator.language : 'en');\n\n return format(d, { intl: { month: 'long' }, locale: loc, timeZone: 'UTC' });\n });\n\n const displayYear_ = computed(() => String(displayYear.value));\n const displayLabel = computed(() => `${displayMonth_.value} ${displayYear_.value}`);\n\n // ── Navigation ───────────────────────────────────────────────────────────\n\n function handlePrev(): void {\n if (currentView.value === 'day') ctrl.prevMonth();\n else ctrl.prevYear();\n\n displayYear.value = ctrl.displayYear();\n displayMonth.value = ctrl.displayMonth();\n }\n\n function handleNext(): void {\n if (currentView.value === 'day') ctrl.nextMonth();\n else ctrl.nextYear();\n\n displayYear.value = ctrl.displayYear();\n displayMonth.value = ctrl.displayMonth();\n }\n\n function handleHeaderClick(): void {\n const views: DatePickerView[] = ['day', 'month', 'year'];\n const next = views[(views.indexOf(currentView.value) + 1) % views.length];\n\n ctrl.setView(next);\n currentView.value = next;\n }\n\n // ── Selection handlers: all disabled guards live here ────────────────────\n\n function handleSelectMonth(month: number): void {\n if (isDisabled.value) return;\n\n ctrl.goTo(ctrl.displayYear(), month);\n ctrl.setView('day');\n displayYear.value = ctrl.displayYear();\n displayMonth.value = ctrl.displayMonth();\n currentView.value = 'day';\n }\n\n function handleSelectYear(year: number): void {\n if (isDisabled.value) return;\n\n ctrl.goTo(year, ctrl.displayMonth());\n ctrl.setView('month');\n displayYear.value = ctrl.displayYear();\n currentView.value = 'month';\n }\n\n function handleSelectDay(isoStr: string): void {\n if (isDisabled.value) return;\n\n const date = parseIso(isoStr);\n\n if (!date) return;\n\n ctrl.select(date); // ctrl.select() internally rejects disabled/out-of-range dates\n }\n\n // ── Cell keyboard navigation (shared ARIA grid pattern) ───────────────────\n // Day cells activate by their `data-iso`; month/year cells use their closure value.\n\n function handleDayKeydown(e: KeyboardEvent): void {\n handleCalendarGridKeydown(e, '.cal-cell-day', 7, (cell) => handleSelectDay(cell.dataset.iso ?? ''));\n }\n\n // ── Host bindings ────────────────────────────────────────────────────────\n\n bind({\n attr: {\n 'aria-disabled': () => (isDisabled.value ? 'true' : null),\n 'aria-label': () => displayLabel.value,\n role: 'group',\n },\n class: {\n 'is-disabled': isDisabled,\n },\n });\n\n // ── Template ─────────────────────────────────────────────────────────────\n\n return html`\n <div class=\"calendar\" part=\"calendar\" role=\"presentation\">\n <!-- Header -->\n <div class=\"cal-header\" part=\"header\">\n <button class=\"nav-btn\" type=\"button\" aria-label=\"Previous\" ?disabled=\"${isDisabled}\" @click=\"${handlePrev}\">\n <ore-icon name=\"chevron-left\" size=\"16\" stroke-width=\"2\" aria-hidden=\"true\"></ore-icon>\n </button>\n\n <button\n class=\"cal-label-btn\"\n type=\"button\"\n aria-label=\"${() =>\n `Switch to ${currentView.value === 'day' ? 'month' : currentView.value === 'month' ? 'year' : 'day'} view`}\"\n ?disabled=\"${isDisabled}\"\n @click=\"${handleHeaderClick}\">\n <span class=\"cal-label-month\">${displayMonth_}</span>\n <span class=\"cal-label-sep\" aria-hidden=\"true\">/</span>\n <span class=\"cal-label-year\">${displayYear_}</span>\n </button>\n\n <button class=\"nav-btn\" type=\"button\" aria-label=\"Next\" ?disabled=\"${isDisabled}\" @click=\"${handleNext}\">\n <ore-icon name=\"chevron-right\" size=\"16\" stroke-width=\"2\" aria-hidden=\"true\"></ore-icon>\n </button>\n </div>\n\n <!-- Day view -->\n <div\n class=\"cal-grid cal-grid-days\"\n role=\"grid\"\n part=\"grid\"\n aria-label=\"${() => displayLabel.value}\"\n ?hidden=\"${() => currentView.value !== 'day'}\">\n <div role=\"row\" class=\"cal-grid-row\">\n ${() =>\n weekdayLabels.value.map(\n (lbl) => html`\n <div class=\"cal-cell cal-cell-head\" role=\"columnheader\" aria-label=\"${lbl}\">${lbl}</div>\n `,\n )}\n </div>\n ${() => {\n const cells = dayCells.value;\n const rows: (typeof cells)[number][][] = [];\n\n for (let i = 0; i < cells.length; i += 7) rows.push(cells.slice(i, i + 7));\n\n return rows.map(\n (row) => html`\n <div role=\"row\" class=\"cal-grid-row\">\n ${row.map(\n (cell) => html`\n <div\n class=\"cal-cell cal-cell-day\"\n role=\"gridcell\"\n part=\"day\"\n aria-selected=\"${() => String(cell.isSelected)}\"\n aria-disabled=\"${() => String(cell.isDisabled || isDisabled.value)}\"\n aria-current=\"${() => (cell.isToday ? 'date' : null)}\"\n ?data-selected=\"${() => cell.isSelected}\"\n ?data-today=\"${() => cell.isToday}\"\n ?data-outside=\"${() => cell.isOutsideMonth}\"\n ?data-disabled=\"${() => cell.isDisabled || isDisabled.value}\"\n data-iso=\"${cell.iso}\"\n data-day=\"${String(cell.day)}\"\n tabindex=\"${() => (cell.isDisabled || isDisabled.value ? '-1' : '0')}\"\n @click=\"${() => handleSelectDay(cell.iso)}\"\n @keydown=\"${handleDayKeydown}\">\n ${String(cell.day)}\n ${() => {\n const evts = eventsByDate.value.get(cell.iso) ?? [];\n\n if (!evts.length) return html``;\n\n const shown = evts.slice(0, MAX_EVENTS);\n const overflow = evts.length - MAX_EVENTS;\n\n if (isExpanded.value) {\n // Text node is written tag-tight (no inner line breaks): this custom\n // `html` tagged template does not collapse whitespace at runtime like a\n // browser parser would, so a pretty-printed multi-line `<span>...</span>`\n // here would render literal newlines/indentation into `textContent`.\n // biome-ignore format: Preserve text-node whitespace in the template.\n const overflowPill =\n overflow > 0\n ? html`<span class=\"cal-event-pill-overflow\" aria-hidden=\"true\"\n >+${overflow} more</span\n >`\n : html``;\n\n return html`\n <div\n class=\"cal-events\"\n aria-label=\"${() => `${evts.length} event${evts.length > 1 ? 's' : ''}`}\">\n ${shown.map(\n (evt) => html`\n <ore-badge\n class=\"cal-event-pill\"\n size=\"xs\"\n rounded=\"sm\"\n aria-label=\"${evt.label}\"\n style=\"${styleMap({\n '--badge-bg': evt.color,\n '--badge-border-color': evt.color,\n })}\">\n ${evt.label}\n </ore-badge>\n `,\n )}\n ${overflowPill}\n </div>\n `;\n }\n\n return html`\n <div\n class=\"cal-dots\"\n aria-label=\"${() => `${evts.length} event${evts.length > 1 ? 's' : ''}`}\">\n ${shown.map(\n (evt) => html`\n <ore-badge\n class=\"cal-dot\"\n dot\n size=\"xs\"\n aria-hidden=\"true\"\n style=\"${styleMap({\n '--badge-bg': evt.color,\n '--badge-border-color': evt.color,\n })}\"></ore-badge>\n `,\n )}\n ${\n overflow > 0\n ? html`\n <span class=\"cal-dot-overflow\" aria-hidden=\"true\">+${overflow}</span>\n `\n : html``\n }\n </div>\n `;\n }}\n </div>\n `,\n )}\n </div>\n `,\n );\n }}\n </div>\n\n <!-- Month view -->\n <div\n class=\"cal-grid cal-grid-months\"\n role=\"grid\"\n aria-label=\"${() => displayYear_.value}\"\n ?hidden=\"${() => currentView.value !== 'month'}\">\n ${() => {\n const cells = monthCells.value;\n const rows: (typeof cells)[number][][] = [];\n\n for (let i = 0; i < cells.length; i += 4) rows.push(cells.slice(i, i + 4));\n\n return rows.map(\n (row) => html`\n <div role=\"row\">\n ${row.map(\n (cell) => html`\n <div\n class=\"cal-cell cal-cell-month\"\n role=\"gridcell\"\n aria-selected=\"${() => String(cell.isSelected)}\"\n aria-disabled=\"${() => String(cell.isDisabled || isDisabled.value)}\"\n ?data-selected=\"${() => cell.isSelected}\"\n ?data-disabled=\"${() => cell.isDisabled || isDisabled.value}\"\n tabindex=\"${() => (cell.isDisabled || isDisabled.value ? '-1' : '0')}\"\n @click=\"${() => handleSelectMonth(cell.month)}\"\n @keydown=\"${(e: KeyboardEvent) =>\n handleCalendarGridKeydown(e, '.cal-cell-month', 4, () => handleSelectMonth(cell.month))}\">\n ${cell.shortLabel}\n </div>\n `,\n )}\n </div>\n `,\n );\n }}\n </div>\n\n <!-- Year view -->\n <div\n class=\"cal-grid cal-grid-years\"\n role=\"grid\"\n aria-label=\"Select year\"\n ?hidden=\"${() => currentView.value !== 'year'}\">\n ${() => {\n const cells = yearCells.value;\n const rows: (typeof cells)[number][][] = [];\n\n for (let i = 0; i < cells.length; i += 4) rows.push(cells.slice(i, i + 4));\n\n return rows.map(\n (row) => html`\n <div role=\"row\">\n ${row.map(\n (cell) => html`\n <div\n class=\"cal-cell cal-cell-year\"\n role=\"gridcell\"\n aria-selected=\"${() => String(cell.isSelected)}\"\n aria-disabled=\"${() => String(cell.isDisabled || isDisabled.value)}\"\n ?data-selected=\"${() => cell.isSelected}\"\n ?data-disabled=\"${() => cell.isDisabled || isDisabled.value}\"\n tabindex=\"${() => (cell.isDisabled || isDisabled.value ? '-1' : '0')}\"\n @click=\"${() => handleSelectYear(cell.year)}\"\n @keydown=\"${(e: KeyboardEvent) =>\n handleCalendarGridKeydown(e, '.cal-cell-year', 4, () => handleSelectYear(cell.year))}\">\n ${String(cell.year)}\n </div>\n `,\n )}\n </div>\n `,\n );\n }}\n </div>\n </div>\n `;\n },\n shadow: { delegatesFocus: true },\n styles: [colorThemeMixin, reducedMotionMixin, componentStyles],\n});\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"carousel.cjs","names":[],"sources":["../src/content/carousel/carousel.ts"],"sourcesContent":["import { createPanGesture } from '@vielzeug/gesture';\nimport { bind, define, getHost, html, onCleanup, onMounted, prop, useEmit } from '@vielzeug/ore';\nimport { computed, signal, watch } from '@vielzeug/ripple';\nimport { announce, createListControl, lifecycleSignal } from '../../core';\nimport type { ThemeColor } from '../../types';\nimport componentStyles from './carousel.css?inline';\nimport './carousel-slide';\n\nexport { ICON_TAG } from '../../content/icon/icon';\nexport { PROGRESS_TAG } from '../../feedback/progress/progress';\nexport { CAROUSEL_SLIDE_TAG } from './carousel-slide';\n// ── Types ──────────────────────────────────────────────────────────────────────\n\nexport type CarouselOrientation = 'horizontal' | 'vertical';\nexport type CarouselVariant = 'default' | 'fade' | 'filmstrip' | 'gallery';\n\nexport type OreCarouselEvents = {\n /** Fired when the active slide changes. */\n change: { index: number };\n};\n\nexport type OreCarouselProps = {\n /**\n * Whether to advance slides automatically. Defaults to `false`.\n * Opt in explicitly — autoplay on by default is a WCAG 2.1 SC 2.2.2 violation for many use cases.\n */\n autoplay?: boolean;\n /** Interval in milliseconds between automatic slide advances. Defaults to `5000`. */\n 'autoplay-interval'?: number;\n /** Theme color passed to the prev/next navigation buttons. */\n color?: ThemeColor;\n /** Accessible label for the carousel region. */\n label?: string;\n /** Whether the carousel loops from the last slide back to the first. Defaults to `true`. */\n loop?: boolean;\n /** Carousel orientation. Defaults to `'horizontal'`. */\n orientation?: CarouselOrientation;\n /** Show next/prev navigation buttons. Defaults to `true`. */\n 'show-controls'?: boolean;\n /** Show dot/indicator navigation. Defaults to `true`. */\n 'show-indicators'?: boolean;\n /** Index of the currently active slide (zero-based). Defaults to `0`. */\n 'slide-index'?: number;\n /**\n * Layout variant.\n * - `'default'` — slides translate in/out (default)\n * - `'fade'` — slides crossfade; no movement\n * - `'filmstrip'` — all slides visible side-by-side; active expands\n * - `'gallery'` — active slide fills the majority; adjacent slides show as thumbnails\n */\n variant?: CarouselVariant;\n};\n\n/**\n * An accessible, keyboard-navigable carousel / slideshow with optional\n * autoplay, swipe support, and indicator dots.\n *\n * Place `<ore-carousel-slide>` elements as direct children.\n *\n * @element ore-carousel\n * @element ore-carousel-slide - Child element for individual slides\n *\n * @attr {string} color - Theme color for navigation buttons: 'primary' | 'secondary' | 'info' | 'success' | 'warning' | 'error'\n * @attr {boolean} autoplay - Advance slides automatically (default false)\n * @attr {number} autoplay-interval - Milliseconds between automatic advances (default 5000)\n * @attr {string} label - Accessible label for the carousel region\n * @attr {boolean} loop - Loop from last slide to first (default true)\n * @attr {string} orientation - 'horizontal' (default) | 'vertical'\n * @attr {string} variant - 'default' | 'fade' | 'filmstrip' | 'gallery'\n * @attr {boolean} show-controls - Show prev/next buttons (default true)\n * @attr {boolean} show-indicators - Show indicator dots (default true)\n * @attr {number} slide-index - Active slide index (zero-based, default 0)\n *\n * @fires change - Fires when the active slide changes. detail: { index: number }\n *\n * @slot - Place `<ore-carousel-slide>` elements here\n *\n * @cssprop --carousel-bg - Slide area background\n * @cssprop --carousel-radius - Border radius of the carousel\n * @cssprop --carousel-dot-bg - Inactive indicator color (default: var(--color-contrast-300))\n * @cssprop --carousel-dot-active-bg - Active indicator / fill color (default: var(--color-contrast-700))\n * @cssprop --carousel-transition-duration - Slide transition duration (default 0.35s; 0s under prefers-reduced-motion).\n * @cssprop --carousel-min-height - Minimum height when no explicit height is set (default 240px)\n * @cssprop --carousel-filmstrip-inactive - Width (horizontal) or height (vertical) of inactive slides in filmstrip mode\n * @cssprop --carousel-filmstrip-gap - Gap between slides in filmstrip mode\n * @cssprop --carousel-gallery-thumbnail - Width (horizontal) or height (vertical) of thumbnail slides in gallery mode (default var(--size-24))\n * @cssprop --carousel-gallery-gap - Gap between slides in gallery mode (default var(--size-2))\n *\n * @part track - The scrolling slide track element\n * @part controls - The prev/next button container\n * @part indicators - The indicator dots container\n * @part prev-btn - The previous-slide button\n * @part next-btn - The next-slide button\n *\n * @example\n * ```html\n * <ore-carousel label=\"Product highlights\" loop>\n * <ore-carousel-slide>Slide 1</ore-carousel-slide>\n * <ore-carousel-slide>Slide 2</ore-carousel-slide>\n * <ore-carousel-slide>Slide 3</ore-carousel-slide>\n * </ore-carousel>\n * ```\n */\nexport const CAROUSEL_TAG = 'ore-carousel' as const;\n\n// ── Slide-state sync helpers ──────────────────────────────────────────────────\n// Each function handles exactly one variant's attribute bookkeeping.\n// Called from a dispatch table in syncActiveState.\n\nconst syncDefaultSlides = (slides: HTMLElement[], current: number): void => {\n const count = slides.length;\n\n slides.forEach((slide, i) => {\n const active = i === current;\n\n slide.toggleAttribute('data-active', active);\n slide.setAttribute('aria-hidden', String(!active));\n slide.setAttribute('aria-label', slide.getAttribute('aria-label') ?? `Slide ${i + 1} of ${count}`);\n slide.removeAttribute('data-gallery-visible');\n slide.toggleAttribute('data-before', i < current);\n slide.toggleAttribute('data-after', i > current);\n });\n};\n\nconst syncFilmstripSlides = (slides: HTMLElement[], current: number): void => {\n const count = slides.length;\n\n slides.forEach((slide, i) => {\n const active = i === current;\n\n slide.toggleAttribute('data-active', active);\n slide.setAttribute('aria-hidden', String(!active));\n slide.setAttribute('aria-label', slide.getAttribute('aria-label') ?? `Slide ${i + 1} of ${count}`);\n slide.removeAttribute('data-gallery-visible');\n slide.removeAttribute('data-before');\n slide.removeAttribute('data-after');\n });\n};\n\nconst syncGallerySlides = (slides: HTMLElement[], current: number): void => {\n const count = slides.length;\n\n slides.forEach((slide, i) => {\n const active = i === current;\n const isPrev = current > 0 && i === current - 1;\n const isNext = current < count - 1 && i === current + 1;\n\n slide.toggleAttribute('data-active', active);\n slide.setAttribute('aria-hidden', String(!active));\n slide.setAttribute('aria-label', slide.getAttribute('aria-label') ?? `Slide ${i + 1} of ${count}`);\n slide.removeAttribute('data-before');\n slide.removeAttribute('data-after');\n slide.toggleAttribute('data-gallery-visible', active || isPrev || isNext);\n });\n};\n\n// ── ore-carousel ──────────────────────────────────────────────────────────────\n\ndefine<OreCarouselProps>(CAROUSEL_TAG, {\n props: {\n autoplay: prop.bool(false),\n 'autoplay-interval': prop.number(5000),\n color: prop.string<ThemeColor>(),\n label: prop.string('Carousel'),\n loop: prop.bool(true),\n orientation: prop.string<CarouselOrientation>('horizontal'),\n 'show-controls': prop.bool(true),\n 'show-indicators': prop.bool(true),\n 'slide-index': prop.number(0),\n variant: prop.string<CarouselVariant>('default'),\n },\n\n setup(props) {\n const el = getHost();\n const emit = useEmit<OreCarouselEvents>();\n\n // ── State ────────────────────────────────────────────────────────────────\n\n const activeIndex = signal<number>(props['slide-index'].value ?? 0);\n let autoplayTimer: ReturnType<typeof setInterval> | null = null;\n\n // Slide cache — populated immediately, refreshed on slotchange.\n let slides: HTMLElement[] = Array.from(el.querySelectorAll<HTMLElement>(':scope > ore-carousel-slide'));\n const slideCount = signal(slides.length);\n\n const refreshSlides = (): void => {\n slides = Array.from(el.querySelectorAll<HTMLElement>(':scope > ore-carousel-slide'));\n slideCount.value = slides.length;\n };\n\n const isHorizontal = computed(() => props.orientation.value !== 'vertical');\n const looping = computed(() => props.loop.value !== false);\n const showControls = computed(() => props['show-controls'].value !== false);\n const showIndicators = computed(() => props['show-indicators'].value !== false);\n\n const canGoPrev = computed(() => looping.value || activeIndex.value > 0);\n const canGoNext = computed(() => looping.value || activeIndex.value < slideCount.value - 1);\n\n // ── Navigation ───────────────────────────────────────────────────────────\n\n const goTo = (index: number, announce_: boolean = true): void => {\n const count = slideCount.value;\n\n if (count === 0) return;\n\n const next = looping.value ? ((index % count) + count) % count : Math.max(0, Math.min(index, count - 1));\n\n if (next === activeIndex.value) return;\n\n activeIndex.value = next;\n el.setAttribute('slide-index', String(next));\n emit('change', { index: next });\n\n if (announce_) {\n announce(slides[next]?.getAttribute('aria-label') ?? `Slide ${next + 1} of ${count}`, {\n document: el.ownerDocument,\n });\n }\n };\n\n const prev = (): void => goTo(activeIndex.value - 1);\n const next = (): void => goTo(activeIndex.value + 1);\n\n // ── Sync prop → state ────────────────────────────────────────────────────\n\n watch(props['slide-index'], (v) => {\n if (typeof v === 'number' && v !== activeIndex.value) goTo(v, false);\n });\n\n // ── Sync variant + orientation → slides ──────────────────────────────────\n\n const syncSlideVariants = (): void => {\n const variant = props.variant.value ?? 'default';\n const orientation = props.orientation.value ?? 'horizontal';\n\n slides.forEach((slide) => {\n slide.setAttribute('data-variant', variant);\n slide.setAttribute('data-orientation', orientation);\n });\n };\n\n watch(\n computed(() => ({ orientation: props.orientation.value, variant: props.variant.value })),\n syncSlideVariants,\n { immediate: true },\n );\n\n // ── Sync active index → slides — dispatch table ───────────────────────────\n\n const syncTable: Record<CarouselVariant, (slides: HTMLElement[], current: number) => void> = {\n default: syncDefaultSlides,\n fade: syncDefaultSlides,\n filmstrip: syncFilmstripSlides,\n gallery: syncGallerySlides,\n };\n\n const syncActiveState = (): void => {\n const variant = (props.variant.value ?? 'default') as CarouselVariant;\n\n syncTable[variant](slides, activeIndex.value);\n };\n\n watch(activeIndex, syncActiveState, { immediate: true });\n\n // ── Autoplay ─────────────────────────────────────────────────────────────\n\n const startAutoplay = (): void => {\n if (autoplayTimer !== null) return;\n\n autoplayTimer = setInterval(next, props['autoplay-interval'].value ?? 5000);\n };\n\n const stopAutoplay = (): void => {\n if (autoplayTimer !== null) {\n clearInterval(autoplayTimer);\n autoplayTimer = null;\n }\n };\n\n watch(\n computed(() => ({ enabled: props.autoplay.value, interval: props['autoplay-interval'].value })),\n ({ enabled }) => {\n stopAutoplay();\n\n if (enabled) startAutoplay();\n },\n );\n\n // ── Keyboard navigation ──────────────────────────────────────────────────\n\n const handleKeydown = (e: KeyboardEvent): void => {\n const isH = isHorizontal.value;\n const prevKey = isH ? 'ArrowLeft' : 'ArrowUp';\n const nextKey = isH ? 'ArrowRight' : 'ArrowDown';\n\n if (e.key === prevKey) {\n e.preventDefault();\n prev();\n } else if (e.key === nextKey) {\n e.preventDefault();\n next();\n } else if (e.key === 'Home') {\n e.preventDefault();\n goTo(0);\n } else if (e.key === 'End') {\n e.preventDefault();\n goTo(slideCount.value - 1);\n }\n };\n\n const indicatorNav = createListControl<number>({\n getItems: () => Array.from({ length: slideCount.value }, (_, index) => index),\n loop: true,\n onNavigate: ({ index }) => {\n goTo(index);\n const dot = el.shadowRoot?.querySelector<HTMLElement>(`.indicator[data-index=\"${index}\"]`);\n\n dot?.focus();\n },\n orientation: () => (isHorizontal.value ? 'horizontal' : 'vertical'),\n signal: lifecycleSignal(onCleanup),\n });\n\n // ── Host bindings ────────────────────────────────────────────────────────\n\n bind({\n attr: {\n 'aria-label': () => props.label.value ?? 'Carousel',\n 'aria-roledescription': () => 'carousel',\n orientation: () => props.orientation.value ?? 'horizontal',\n role: () => 'region',\n style: () => `touch-action:${isHorizontal.value ? 'pan-y' : 'pan-x'}`,\n variant: () => props.variant.value ?? 'default',\n },\n on: {\n focusin: () => {\n stopAutoplay();\n },\n focusout: () => {\n if (props.autoplay.value) startAutoplay();\n },\n keydown: handleKeydown,\n pointerenter: () => {\n stopAutoplay();\n },\n pointerleave: () => {\n if (props.autoplay.value) startAutoplay();\n },\n },\n });\n\n // ── Lifecycle ────────────────────────────────────────────────────────────\n\n onMounted(() => {\n const pan = createPanGesture(el, {\n axis: () => (isHorizontal.value ? 'x' : 'y'),\n onEnd: ({ distance, reason }) => {\n if (reason !== 'release' || Math.abs(distance) < 48) return;\n\n if (distance < 0) next();\n else prev();\n },\n shouldStart: (event) => {\n const path = event.composedPath();\n\n return !path.some(\n (node) =>\n node instanceof HTMLElement &&\n (node.tagName === 'BUTTON' || node.tagName === 'ORE-BUTTON' || node.tagName === 'ORE-PROGRESS'),\n );\n },\n });\n const shadowRoot = el.shadowRoot!;\n const slot = shadowRoot.querySelector<HTMLSlotElement>('slot')!;\n\n // slotchange replaces MutationObserver — fires exactly when assigned\n // nodes change, scoped to this component's slot, no polling overhead.\n const onSlotChange = (): void => {\n refreshSlides();\n syncSlideVariants();\n syncActiveState();\n };\n\n slot.addEventListener('slotchange', onSlotChange);\n\n if (props.autoplay.value) {\n startAutoplay();\n }\n\n return () => {\n pan.dispose();\n stopAutoplay();\n slot.removeEventListener('slotchange', onSlotChange);\n };\n });\n\n // ── Template ─────────────────────────────────────────────────────────────\n\n const renderControls = () =>\n showControls.value\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 aria-label=\"Previous slide\"\n disabled=${() => (!canGoPrev.value ? true : undefined)}\n @click=${(e: Event) => {\n e.stopPropagation();\n prev();\n }}>\n <ore-icon\n name=${() => (isHorizontal.value ? 'chevron-left' : 'chevron-up')}\n size=\"16\"\n stroke-width=\"2\"\n 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 aria-label=\"Next slide\"\n disabled=${() => (!canGoNext.value ? true : undefined)}\n @click=${(e: Event) => {\n e.stopPropagation();\n next();\n }}>\n <ore-icon\n name=${() => (isHorizontal.value ? 'chevron-right' : 'chevron-down')}\n size=\"16\"\n stroke-width=\"2\"\n aria-hidden=\"true\"></ore-icon>\n </ore-button>\n </div>\n `\n : html``;\n\n return html`\n <div class=\"track\" part=\"track\" aria-live=${() => (props.autoplay.value ? 'off' : 'polite')}>\n <slot></slot>\n </div>\n\n ${() =>\n showIndicators.value && slideCount.value > 1\n ? html`\n <div class=\"indicators\" part=\"indicators\" role=\"tablist\" aria-label=\"Slide indicators\">\n ${() =>\n Array.from(\n { length: slideCount.value },\n (_, i) => html`\n <button\n type=\"button\"\n role=\"tab\"\n data-index=\"${i}\"\n class=${() => `indicator${i === activeIndex.value ? ' indicator-active' : ''}`}\n aria-selected=${() => String(i === activeIndex.value)}\n tabindex=${() => (i === activeIndex.value ? '0' : '-1')}\n aria-label=\"${`Go to slide ${i + 1}`}\"\n @focus=${() => indicatorNav.set(i)}\n @click=${() => goTo(i)}\n @keydown=${(e: KeyboardEvent) => {\n const target = e.currentTarget;\n\n if (target instanceof HTMLElement) {\n const index = Number(target.dataset.index);\n\n if (Number.isInteger(index)) indicatorNav.set(index);\n }\n\n indicatorNav.handleKeydown(e);\n }}>\n <ore-progress\n aria-hidden=\"true\"\n tabindex=\"-1\"\n color=${() => props.color.value}\n type=${() => (isHorizontal.value ? 'linear' : 'vertical')}\n value=${() => (i === activeIndex.value ? 100 : 0)}\n style=${() => {\n const fillAnim = isHorizontal.value ? 'carousel-fill' : 'carousel-fill-v';\n\n return `--carousel-timeout:${props['autoplay-interval'].value ?? 5000};--carousel-animation-name:${i === activeIndex.value && props.autoplay.value ? fillAnim : 'none'}`;\n }}></ore-progress>\n </button>\n `,\n )}\n ${renderControls}\n </div>\n `\n : html`\n ${renderControls}\n `}\n `;\n },\n styles: [componentStyles],\n});\n"],"mappings":"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"}
1
+ {"version":3,"file":"carousel.cjs","names":[],"sources":["../src/content/carousel/carousel.ts"],"sourcesContent":["import { createPanGesture } from '@vielzeug/gesture';\nimport { bind, define, getHost, html, onCleanup, onMounted, prop, useEmit } from '@vielzeug/ore';\nimport { computed, signal, watch } from '@vielzeug/ripple';\nimport { announce, createListControl, lifecycleSignal } from '../../core';\nimport type { ThemeColor } from '../../types';\nimport componentStyles from './carousel.css?inline';\nimport './carousel-slide';\n\nexport { ICON_TAG } from '../../content/icon/icon';\nexport { PROGRESS_TAG } from '../../feedback/progress/progress';\nexport { CAROUSEL_SLIDE_TAG } from './carousel-slide';\n// ── Types ──────────────────────────────────────────────────────────────────────\n\nexport type CarouselOrientation = 'horizontal' | 'vertical';\nexport type CarouselVariant = 'default' | 'fade' | 'filmstrip' | 'gallery';\n\nexport type OreCarouselEvents = {\n /** Fired when the active slide changes. */\n change: { index: number };\n};\n\nexport type OreCarouselProps = {\n /**\n * Whether to advance slides automatically. Defaults to `false`.\n * Opt in explicitly: autoplay on by default is a WCAG 2.1 SC 2.2.2 violation for many use cases.\n */\n autoplay?: boolean;\n /** Interval in milliseconds between automatic slide advances. Defaults to `5000`. */\n 'autoplay-interval'?: number;\n /** Theme color passed to the prev/next navigation buttons. */\n color?: ThemeColor;\n /** Accessible label for the carousel region. */\n label?: string;\n /** Whether the carousel loops from the last slide back to the first. Defaults to `true`. */\n loop?: boolean;\n /** Carousel orientation. Defaults to `'horizontal'`. */\n orientation?: CarouselOrientation;\n /** Show next/prev navigation buttons. Defaults to `true`. */\n 'show-controls'?: boolean;\n /** Show dot/indicator navigation. Defaults to `true`. */\n 'show-indicators'?: boolean;\n /** Index of the currently active slide (zero-based). Defaults to `0`. */\n 'slide-index'?: number;\n /**\n * Layout variant.\n * - `'default'`: slides translate in/out (default)\n * - `'fade'`: slides crossfade; no movement\n * - `'filmstrip'`: all slides visible side-by-side; active expands\n * - `'gallery'`: active slide fills the majority; adjacent slides show as thumbnails\n */\n variant?: CarouselVariant;\n};\n\n/**\n * An accessible, keyboard-navigable carousel / slideshow with optional\n * autoplay, swipe support, and indicator dots.\n *\n * Place `<ore-carousel-slide>` elements as direct children.\n *\n * @element ore-carousel\n * @element ore-carousel-slide - Child element for individual slides\n *\n * @attr {string} color - Theme color for navigation buttons: 'primary' | 'secondary' | 'info' | 'success' | 'warning' | 'error'\n * @attr {boolean} autoplay - Advance slides automatically (default false)\n * @attr {number} autoplay-interval - Milliseconds between automatic advances (default 5000)\n * @attr {string} label - Accessible label for the carousel region\n * @attr {boolean} loop - Loop from last slide to first (default true)\n * @attr {string} orientation - 'horizontal' (default) | 'vertical'\n * @attr {string} variant - 'default' | 'fade' | 'filmstrip' | 'gallery'\n * @attr {boolean} show-controls - Show prev/next buttons (default true)\n * @attr {boolean} show-indicators - Show indicator dots (default true)\n * @attr {number} slide-index - Active slide index (zero-based, default 0)\n *\n * @fires change - Fires when the active slide changes. detail: { index: number }\n *\n * @slot - Place `<ore-carousel-slide>` elements here\n *\n * @cssprop --carousel-bg - Slide area background\n * @cssprop --carousel-radius - Border radius of the carousel\n * @cssprop --carousel-dot-bg - Inactive indicator color (default: var(--color-contrast-300))\n * @cssprop --carousel-dot-active-bg - Active indicator / fill color (default: var(--color-contrast-700))\n * @cssprop --carousel-transition-duration - Slide transition duration (default 0.35s; 0s under prefers-reduced-motion).\n * @cssprop --carousel-min-height - Minimum height when no explicit height is set (default 240px)\n * @cssprop --carousel-filmstrip-inactive - Width (horizontal) or height (vertical) of inactive slides in filmstrip mode\n * @cssprop --carousel-filmstrip-gap - Gap between slides in filmstrip mode\n * @cssprop --carousel-gallery-thumbnail - Width (horizontal) or height (vertical) of thumbnail slides in gallery mode (default var(--size-24))\n * @cssprop --carousel-gallery-gap - Gap between slides in gallery mode (default var(--size-2))\n *\n * @part track - The scrolling slide track element\n * @part controls - The prev/next button container\n * @part indicators - The indicator dots container\n * @part prev-btn - The previous-slide button\n * @part next-btn - The next-slide button\n *\n * @example\n * ```html\n * <ore-carousel label=\"Product highlights\" loop>\n * <ore-carousel-slide>Slide 1</ore-carousel-slide>\n * <ore-carousel-slide>Slide 2</ore-carousel-slide>\n * <ore-carousel-slide>Slide 3</ore-carousel-slide>\n * </ore-carousel>\n * ```\n */\nexport const CAROUSEL_TAG = 'ore-carousel' as const;\n\n// ── Slide-state sync helpers ──────────────────────────────────────────────────\n// Each function handles exactly one variant's attribute bookkeeping.\n// Called from a dispatch table in syncActiveState.\n\nconst syncDefaultSlides = (slides: HTMLElement[], current: number): void => {\n const count = slides.length;\n\n slides.forEach((slide, i) => {\n const active = i === current;\n\n slide.toggleAttribute('data-active', active);\n slide.setAttribute('aria-hidden', String(!active));\n slide.setAttribute('aria-label', slide.getAttribute('aria-label') ?? `Slide ${i + 1} of ${count}`);\n slide.removeAttribute('data-gallery-visible');\n slide.toggleAttribute('data-before', i < current);\n slide.toggleAttribute('data-after', i > current);\n });\n};\n\nconst syncFilmstripSlides = (slides: HTMLElement[], current: number): void => {\n const count = slides.length;\n\n slides.forEach((slide, i) => {\n const active = i === current;\n\n slide.toggleAttribute('data-active', active);\n slide.setAttribute('aria-hidden', String(!active));\n slide.setAttribute('aria-label', slide.getAttribute('aria-label') ?? `Slide ${i + 1} of ${count}`);\n slide.removeAttribute('data-gallery-visible');\n slide.removeAttribute('data-before');\n slide.removeAttribute('data-after');\n });\n};\n\nconst syncGallerySlides = (slides: HTMLElement[], current: number): void => {\n const count = slides.length;\n\n slides.forEach((slide, i) => {\n const active = i === current;\n const isPrev = current > 0 && i === current - 1;\n const isNext = current < count - 1 && i === current + 1;\n\n slide.toggleAttribute('data-active', active);\n slide.setAttribute('aria-hidden', String(!active));\n slide.setAttribute('aria-label', slide.getAttribute('aria-label') ?? `Slide ${i + 1} of ${count}`);\n slide.removeAttribute('data-before');\n slide.removeAttribute('data-after');\n slide.toggleAttribute('data-gallery-visible', active || isPrev || isNext);\n });\n};\n\n// ── ore-carousel ──────────────────────────────────────────────────────────────\n\ndefine<OreCarouselProps>(CAROUSEL_TAG, {\n props: {\n autoplay: prop.bool(false),\n 'autoplay-interval': prop.number(5000),\n color: prop.string<ThemeColor>(),\n label: prop.string('Carousel'),\n loop: prop.bool(true),\n orientation: prop.string<CarouselOrientation>('horizontal'),\n 'show-controls': prop.bool(true),\n 'show-indicators': prop.bool(true),\n 'slide-index': prop.number(0),\n variant: prop.string<CarouselVariant>('default'),\n },\n\n setup(props) {\n const el = getHost();\n const emit = useEmit<OreCarouselEvents>();\n\n // ── State ────────────────────────────────────────────────────────────────\n\n const activeIndex = signal<number>(props['slide-index'].value ?? 0);\n let autoplayTimer: ReturnType<typeof setInterval> | null = null;\n\n // Slide cache: populated immediately, refreshed on slotchange.\n let slides: HTMLElement[] = Array.from(el.querySelectorAll<HTMLElement>(':scope > ore-carousel-slide'));\n const slideCount = signal(slides.length);\n\n const refreshSlides = (): void => {\n slides = Array.from(el.querySelectorAll<HTMLElement>(':scope > ore-carousel-slide'));\n slideCount.value = slides.length;\n };\n\n const isHorizontal = computed(() => props.orientation.value !== 'vertical');\n const looping = computed(() => props.loop.value !== false);\n const showControls = computed(() => props['show-controls'].value !== false);\n const showIndicators = computed(() => props['show-indicators'].value !== false);\n\n const canGoPrev = computed(() => looping.value || activeIndex.value > 0);\n const canGoNext = computed(() => looping.value || activeIndex.value < slideCount.value - 1);\n\n // ── Navigation ───────────────────────────────────────────────────────────\n\n const goTo = (index: number, announce_: boolean = true): void => {\n const count = slideCount.value;\n\n if (count === 0) return;\n\n const next = looping.value ? ((index % count) + count) % count : Math.max(0, Math.min(index, count - 1));\n\n if (next === activeIndex.value) return;\n\n activeIndex.value = next;\n el.setAttribute('slide-index', String(next));\n emit('change', { index: next });\n\n if (announce_) {\n announce(slides[next]?.getAttribute('aria-label') ?? `Slide ${next + 1} of ${count}`, {\n document: el.ownerDocument,\n });\n }\n };\n\n const prev = (): void => goTo(activeIndex.value - 1);\n const next = (): void => goTo(activeIndex.value + 1);\n\n // ── Sync prop → state ────────────────────────────────────────────────────\n\n watch(props['slide-index'], (v) => {\n if (typeof v === 'number' && v !== activeIndex.value) goTo(v, false);\n });\n\n // ── Sync variant + orientation → slides ──────────────────────────────────\n\n const syncSlideVariants = (): void => {\n const variant = props.variant.value ?? 'default';\n const orientation = props.orientation.value ?? 'horizontal';\n\n slides.forEach((slide) => {\n slide.setAttribute('data-variant', variant);\n slide.setAttribute('data-orientation', orientation);\n });\n };\n\n watch(\n computed(() => ({ orientation: props.orientation.value, variant: props.variant.value })),\n syncSlideVariants,\n { immediate: true },\n );\n\n // ── Sync active index → slides: dispatch table ───────────────────────────\n\n const syncTable: Record<CarouselVariant, (slides: HTMLElement[], current: number) => void> = {\n default: syncDefaultSlides,\n fade: syncDefaultSlides,\n filmstrip: syncFilmstripSlides,\n gallery: syncGallerySlides,\n };\n\n const syncActiveState = (): void => {\n const variant = (props.variant.value ?? 'default') as CarouselVariant;\n\n syncTable[variant](slides, activeIndex.value);\n };\n\n watch(activeIndex, syncActiveState, { immediate: true });\n\n // ── Autoplay ─────────────────────────────────────────────────────────────\n\n const startAutoplay = (): void => {\n if (autoplayTimer !== null) return;\n\n autoplayTimer = setInterval(next, props['autoplay-interval'].value ?? 5000);\n };\n\n const stopAutoplay = (): void => {\n if (autoplayTimer !== null) {\n clearInterval(autoplayTimer);\n autoplayTimer = null;\n }\n };\n\n watch(\n computed(() => ({ enabled: props.autoplay.value, interval: props['autoplay-interval'].value })),\n ({ enabled }) => {\n stopAutoplay();\n\n if (enabled) startAutoplay();\n },\n );\n\n // ── Keyboard navigation ──────────────────────────────────────────────────\n\n const handleKeydown = (e: KeyboardEvent): void => {\n const isH = isHorizontal.value;\n const prevKey = isH ? 'ArrowLeft' : 'ArrowUp';\n const nextKey = isH ? 'ArrowRight' : 'ArrowDown';\n\n if (e.key === prevKey) {\n e.preventDefault();\n prev();\n } else if (e.key === nextKey) {\n e.preventDefault();\n next();\n } else if (e.key === 'Home') {\n e.preventDefault();\n goTo(0);\n } else if (e.key === 'End') {\n e.preventDefault();\n goTo(slideCount.value - 1);\n }\n };\n\n const indicatorNav = createListControl<number>({\n getItems: () => Array.from({ length: slideCount.value }, (_, index) => index),\n loop: true,\n onNavigate: ({ index }) => {\n goTo(index);\n const dot = el.shadowRoot?.querySelector<HTMLElement>(`.indicator[data-index=\"${index}\"]`);\n\n dot?.focus();\n },\n orientation: () => (isHorizontal.value ? 'horizontal' : 'vertical'),\n signal: lifecycleSignal(onCleanup),\n });\n\n // ── Host bindings ────────────────────────────────────────────────────────\n\n bind({\n attr: {\n 'aria-label': () => props.label.value ?? 'Carousel',\n 'aria-roledescription': () => 'carousel',\n orientation: () => props.orientation.value ?? 'horizontal',\n role: () => 'region',\n style: () => `touch-action:${isHorizontal.value ? 'pan-y' : 'pan-x'}`,\n variant: () => props.variant.value ?? 'default',\n },\n on: {\n focusin: () => {\n stopAutoplay();\n },\n focusout: () => {\n if (props.autoplay.value) startAutoplay();\n },\n keydown: handleKeydown,\n pointerenter: () => {\n stopAutoplay();\n },\n pointerleave: () => {\n if (props.autoplay.value) startAutoplay();\n },\n },\n });\n\n // ── Lifecycle ────────────────────────────────────────────────────────────\n\n onMounted(() => {\n const pan = createPanGesture(el, {\n axis: () => (isHorizontal.value ? 'x' : 'y'),\n onEnd: ({ distance, reason }) => {\n if (reason !== 'release' || Math.abs(distance) < 48) return;\n\n if (distance < 0) next();\n else prev();\n },\n shouldStart: (event) => {\n const path = event.composedPath();\n\n return !path.some(\n (node) =>\n node instanceof HTMLElement &&\n (node.tagName === 'BUTTON' || node.tagName === 'ORE-BUTTON' || node.tagName === 'ORE-PROGRESS'),\n );\n },\n });\n const shadowRoot = el.shadowRoot!;\n const slot = shadowRoot.querySelector<HTMLSlotElement>('slot')!;\n\n // slotchange replaces MutationObserver: fires exactly when assigned\n // nodes change, scoped to this component's slot, no polling overhead.\n const onSlotChange = (): void => {\n refreshSlides();\n syncSlideVariants();\n syncActiveState();\n };\n\n slot.addEventListener('slotchange', onSlotChange);\n\n if (props.autoplay.value) {\n startAutoplay();\n }\n\n return () => {\n pan.dispose();\n stopAutoplay();\n slot.removeEventListener('slotchange', onSlotChange);\n };\n });\n\n // ── Template ─────────────────────────────────────────────────────────────\n\n const renderControls = () =>\n showControls.value\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 aria-label=\"Previous slide\"\n disabled=${() => (!canGoPrev.value ? true : undefined)}\n @click=${(e: Event) => {\n e.stopPropagation();\n prev();\n }}>\n <ore-icon\n name=${() => (isHorizontal.value ? 'chevron-left' : 'chevron-up')}\n size=\"16\"\n stroke-width=\"2\"\n 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 aria-label=\"Next slide\"\n disabled=${() => (!canGoNext.value ? true : undefined)}\n @click=${(e: Event) => {\n e.stopPropagation();\n next();\n }}>\n <ore-icon\n name=${() => (isHorizontal.value ? 'chevron-right' : 'chevron-down')}\n size=\"16\"\n stroke-width=\"2\"\n aria-hidden=\"true\"></ore-icon>\n </ore-button>\n </div>\n `\n : html``;\n\n return html`\n <div class=\"track\" part=\"track\" aria-live=${() => (props.autoplay.value ? 'off' : 'polite')}>\n <slot></slot>\n </div>\n\n ${() =>\n showIndicators.value && slideCount.value > 1\n ? html`\n <div class=\"indicators\" part=\"indicators\" role=\"tablist\" aria-label=\"Slide indicators\">\n ${() =>\n Array.from(\n { length: slideCount.value },\n (_, i) => html`\n <button\n type=\"button\"\n role=\"tab\"\n data-index=\"${i}\"\n class=${() => `indicator${i === activeIndex.value ? ' indicator-active' : ''}`}\n aria-selected=${() => String(i === activeIndex.value)}\n tabindex=${() => (i === activeIndex.value ? '0' : '-1')}\n aria-label=\"${`Go to slide ${i + 1}`}\"\n @focus=${() => indicatorNav.set(i)}\n @click=${() => goTo(i)}\n @keydown=${(e: KeyboardEvent) => {\n const target = e.currentTarget;\n\n if (target instanceof HTMLElement) {\n const index = Number(target.dataset.index);\n\n if (Number.isInteger(index)) indicatorNav.set(index);\n }\n\n indicatorNav.handleKeydown(e);\n }}>\n <ore-progress\n aria-hidden=\"true\"\n tabindex=\"-1\"\n color=${() => props.color.value}\n type=${() => (isHorizontal.value ? 'linear' : 'vertical')}\n value=${() => (i === activeIndex.value ? 100 : 0)}\n style=${() => {\n const fillAnim = isHorizontal.value ? 'carousel-fill' : 'carousel-fill-v';\n\n return `--carousel-timeout:${props['autoplay-interval'].value ?? 5000};--carousel-animation-name:${i === activeIndex.value && props.autoplay.value ? fillAnim : 'none'}`;\n }}></ore-progress>\n </button>\n `,\n )}\n ${renderControls}\n </div>\n `\n : html`\n ${renderControls}\n `}\n `;\n },\n styles: [componentStyles],\n});\n"],"mappings":"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"}