@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
@@ -1 +1 @@
1
- {"version":3,"file":"tab-item.cjs","names":[],"sources":["../src/disclosure/tab-item/tab-item.ts"],"sourcesContent":["import { bind, define, getHost, html, inject, onMounted, prop, ref, watchEffect } from '@vielzeug/ore';\nimport { computed } from '@vielzeug/ripple';\nimport { setAriaReflection } from '../../core';\nimport { disablableBundle } from '../../shared';\nimport { coarsePointerMixin, colorThemeMixin, forcedColorsFocusMixin } from '../../styles';\nimport type { ComponentSize, ThemeColor, VisualVariant } from '../../types';\nimport { TABS_CTX } from '../tabs/tabs';\nimport styles from './tab-item.css?inline';\n\nexport type OreTabItemProps = {\n /** Whether this tab is currently selected (set by ore-tabs) */\n active?: boolean;\n /** Theme color (inherited from ore-tabs) */\n color?: ThemeColor;\n /** Disable this tab */\n disabled?: boolean;\n /** Spatial density (inherited from ore-tabs) */\n density?: 'compact' | 'default';\n /** Size (inherited from ore-tabs) */\n size?: ComponentSize;\n /** Unique value identifier — must match a ore-tab-panel value */\n value: string;\n /** Visual variant (inherited from ore-tabs) */\n variant?: VisualVariant;\n};\n\n/**\n * Individual tab trigger. Must be placed in the `tabs` slot of `ore-tabs`.\n *\n * @element ore-tab-item\n *\n * @attr {string} value - Unique identifier, matches the corresponding ore-tab-panel value\n * @attr {boolean} active - Set by the parent ore-tabs when this tab is selected\n * @attr {boolean} disabled - Prevents selection\n * @attr {string} density - Inherited spatial density: 'default' | 'compact'\n * @attr {string} size - 'sm' | 'md' | 'lg'\n * @attr {string} variant - Inherited from ore-tabs: 'solid' | 'flat' | 'bordered' | 'ghost' | 'frost'\n * @attr {string} color - Inherited from ore-tabs: 'primary' | 'secondary' | 'info' | 'success' | 'warning' | 'error'\n *\n * @slot prefix - Icon or content before the label\n * @slot - Tab label\n * @slot suffix - Badge or count after the label\n *\n * @cssprop --tab-item-radius - Button border radius\n * @cssprop --tab-item-transition - Transition duration/easing\n * @cssprop --tab-item-padding - Button padding\n * @cssprop --tab-item-font-size - Button font size\n * @cssprop --tab-item-color - Default text color\n * @cssprop --tab-item-hover-bg - Background on hover\n * @cssprop --tab-item-active-bg - Background when active/selected\n * @cssprop --tab-item-active-color - Text color when active/selected\n * @cssprop --tab-item-active-shadow - Box shadow when active/selected\n * @part tab - Tab trigger element.\n * @example\n * ```html\n * <ore-tab-item slot=\"tabs\" value=\"overview\">Overview</ore-tab-item>\n * <ore-tab-item slot=\"tabs\" value=\"settings\" disabled>Settings</ore-tab-item>\n * ```\n */\nexport const TAB_ITEM_TAG = 'ore-tab-item' as const;\ndefine<OreTabItemProps>(TAB_ITEM_TAG, {\n props: {\n ...disablableBundle,\n active: prop.bool(false),\n color: prop.string<ThemeColor>(),\n density: prop.oneOf(['compact', 'default'] as const, 'default'),\n size: prop.string<ComponentSize>(),\n value: prop.string(''),\n variant: prop.string<VisualVariant>(),\n },\n setup(props) {\n const el = getHost();\n const watch = watchEffect;\n\n const tabsCtx = inject(TABS_CTX);\n\n if (tabsCtx) {\n watch(() => {\n const color = tabsCtx.color.value;\n const density = tabsCtx.density.value;\n const size = tabsCtx.size.value;\n const variant = tabsCtx.variant.value;\n\n if (color !== undefined) el.setAttribute('color', color);\n\n el.setAttribute('density', density);\n\n if (size !== undefined) el.setAttribute('size', size);\n\n if (variant !== undefined) el.setAttribute('variant', variant);\n });\n }\n\n const isActive = computed(() =>\n tabsCtx ? !!tabsCtx.value.value && tabsCtx.value.value === props.value.value : props.active.value,\n );\n const isDisabled = () => Boolean(props.disabled.value);\n\n bind({\n attr: {\n active: () => (isActive.value ? true : undefined),\n },\n });\n\n const handleClick = (event: MouseEvent) => {\n event.stopPropagation();\n\n if (isDisabled()) {\n event.preventDefault();\n\n return;\n }\n\n el.dispatchEvent(new CustomEvent('click', { bubbles: true, detail: { value: props.value.value } }));\n };\n\n const tabId = () => `tab-${props.value.value}`;\n const buttonRef = ref<HTMLButtonElement>();\n\n // `aria-controls` as a plain IDREF attribute cannot resolve across shadow-tree boundaries\n // (the matching `id` lives inside <ore-tab-panel>'s own shadow root) — see\n // `setAriaReflection()`'s doc comment. Deferred to `onMounted()`: sibling custom elements\n // (including the peer `<ore-tab-panel>`) connect in tree order within the same synchronous\n // insertion, so a sibling's shadow content may not exist yet during this element's own\n // `setup()` — `onMounted()`'s microtask runs after the whole subtree has connected.\n onMounted(() => {\n watchEffect(() => {\n const button = buttonRef.value;\n const value = props.value.value;\n\n if (!button) return;\n\n const tabsEl = value ? el.closest('ore-tabs') : null;\n const panelEl = tabsEl?.querySelector<HTMLElement>(`:scope > ore-tab-panel[value=\"${value}\"]`);\n const panel = panelEl?.shadowRoot?.querySelector<HTMLElement>('.panel') ?? null;\n\n setAriaReflection(button, 'ariaControlsElements', panel ? [panel] : []);\n });\n });\n\n return html`\n <button\n role=\"tab\"\n type=\"button\"\n part=\"tab\"\n ref=\"${buttonRef}\"\n id=\"${tabId}\"\n aria-selected=\"${isActive}\"\n tabindex=\"${() => (isActive.value ? '0' : '-1')}\"\n aria-disabled=\"${isDisabled}\"\n @click=\"${handleClick}\">\n <slot name=\"prefix\"></slot>\n <slot></slot>\n <slot name=\"suffix\"></slot>\n </button>\n `;\n },\n styles: [colorThemeMixin, forcedColorsFocusMixin('button'), coarsePointerMixin, styles],\n});\n"],"mappings":"+XA2DA,IAAa,EAAe,gBAC5B,EAAA,EAAA,OAAA,CAAwB,EAAc,CACpC,MAAO,CACL,GAAG,EAAA,iBACH,OAAQ,EAAA,KAAK,KAAK,EAAK,EACvB,MAAO,EAAA,KAAK,OAAmB,EAC/B,QAAS,EAAA,KAAK,MAAM,CAAC,UAAW,SAAS,EAAY,SAAS,EAC9D,KAAM,EAAA,KAAK,OAAsB,EACjC,MAAO,EAAA,KAAK,OAAO,EAAE,EACrB,QAAS,EAAA,KAAK,OAAsB,CACtC,EACA,MAAM,EAAO,CACX,IAAM,GAAA,EAAK,EAAA,QAAA,CAAQ,EACb,EAAQ,EAAA,YAER,GAAA,EAAU,EAAA,OAAA,CAAO,EAAA,QAAQ,EAE3B,GACF,MAAY,CACV,IAAM,EAAQ,EAAQ,MAAM,MACtB,EAAU,EAAQ,QAAQ,MAC1B,EAAO,EAAQ,KAAK,MACpB,EAAU,EAAQ,QAAQ,MAE5B,IAAU,IAAA,IAAW,EAAG,aAAa,QAAS,CAAK,EAEvD,EAAG,aAAa,UAAW,CAAO,EAE9B,IAAS,IAAA,IAAW,EAAG,aAAa,OAAQ,CAAI,EAEhD,IAAY,IAAA,IAAW,EAAG,aAAa,UAAW,CAAO,CAC/D,CAAC,EAGH,IAAM,GAAA,EAAW,EAAA,SAAA,KACf,EAAU,CAAC,CAAC,EAAQ,MAAM,OAAS,EAAQ,MAAM,QAAU,EAAM,MAAM,MAAQ,EAAM,OAAO,KAC9F,EACM,eAAmB,EAAQ,EAAM,SAAS,OAEhD,EAAA,EAAA,KAAA,CAAK,CACH,KAAM,CACJ,WAAe,EAAS,MAAQ,GAAO,IAAA,EACzC,CACF,CAAC,EAED,IAAM,YAAe,GAAsB,CAGzC,GAFA,EAAM,gBAAgB,EAElB,WAAW,EAAG,CAChB,EAAM,eAAe,EAErB,MACF,CAEA,EAAG,cAAc,IAAI,YAAY,QAAS,CAAE,QAAS,GAAM,OAAQ,CAAE,MAAO,EAAM,MAAM,KAAM,CAAE,CAAC,CAAC,CACpG,EAEM,UAAc,OAAO,EAAM,MAAM,QACjC,GAAA,EAAY,EAAA,IAAA,CAAuB,EAuBzC,OAfA,EAAA,EAAA,UAAA,KAAgB,EACd,EAAA,EAAA,YAAA,KAAkB,CAChB,IAAM,EAAS,EAAU,MACnB,EAAQ,EAAM,MAAM,MAE1B,GAAI,CAAC,EAAQ,OAIb,IAAM,IAFS,EAAQ,EAAG,QAAQ,UAAU,EAAI,KAAA,EACxB,cAA2B,iCAAiC,EAAM,GAAG,EAAA,EACtE,YAAY,cAA2B,QAAQ,GAAK,KAE3E,EAAA,kBAAkB,EAAQ,uBAAwB,EAAQ,CAAC,CAAK,EAAI,CAAC,CAAC,CACxE,CAAC,CACH,CAAC,EAEM,EAAA,IAAI;;;;;eAKA,EAAU;cACX,MAAM;yBACK,EAAS;wBACP,EAAS,MAAQ,IAAM,KAAM;yBAC/B,WAAW;kBAClB,YAAY;;;;;KAM5B,EACA,OAAQ,CAAC,EAAA,gBAAiB,EAAA,uBAAuB,QAAQ,EAAG,EAAA,mBAAoB,EAAA,OAAM,CACxF,CAAC"}
1
+ {"version":3,"file":"tab-item.cjs","names":[],"sources":["../src/disclosure/tab-item/tab-item.ts"],"sourcesContent":["import { bind, define, getHost, html, inject, onMounted, prop, ref, watchEffect } from '@vielzeug/ore';\nimport { computed } from '@vielzeug/ripple';\nimport { setAriaReflection } from '../../core';\nimport { disablableBundle } from '../../shared';\nimport { coarsePointerMixin, colorThemeMixin, forcedColorsFocusMixin } from '../../styles';\nimport type { ComponentSize, ThemeColor, VisualVariant } from '../../types';\nimport { TABS_CTX } from '../tabs/tabs';\nimport styles from './tab-item.css?inline';\n\nexport type OreTabItemProps = {\n /** Whether this tab is currently selected (set by ore-tabs) */\n active?: boolean;\n /** Theme color (inherited from ore-tabs) */\n color?: ThemeColor;\n /** Disable this tab */\n disabled?: boolean;\n /** Spatial density (inherited from ore-tabs) */\n density?: 'compact' | 'default';\n /** Size (inherited from ore-tabs) */\n size?: ComponentSize;\n /** Unique value identifier: must match a ore-tab-panel value */\n value: string;\n /** Visual variant (inherited from ore-tabs) */\n variant?: VisualVariant;\n};\n\n/**\n * Individual tab trigger. Must be placed in the `tabs` slot of `ore-tabs`.\n *\n * @element ore-tab-item\n *\n * @attr {string} value - Unique identifier, matches the corresponding ore-tab-panel value\n * @attr {boolean} active - Set by the parent ore-tabs when this tab is selected\n * @attr {boolean} disabled - Prevents selection\n * @attr {string} density - Inherited spatial density: 'default' | 'compact'\n * @attr {string} size - 'sm' | 'md' | 'lg'\n * @attr {string} variant - Inherited from ore-tabs: 'solid' | 'flat' | 'bordered' | 'ghost' | 'frost'\n * @attr {string} color - Inherited from ore-tabs: 'primary' | 'secondary' | 'info' | 'success' | 'warning' | 'error'\n *\n * @slot prefix - Icon or content before the label\n * @slot - Tab label\n * @slot suffix - Badge or count after the label\n *\n * @cssprop --tab-item-radius - Button border radius\n * @cssprop --tab-item-transition - Transition duration/easing\n * @cssprop --tab-item-padding - Button padding\n * @cssprop --tab-item-font-size - Button font size\n * @cssprop --tab-item-color - Default text color\n * @cssprop --tab-item-hover-bg - Background on hover\n * @cssprop --tab-item-active-bg - Background when active/selected\n * @cssprop --tab-item-active-color - Text color when active/selected\n * @cssprop --tab-item-active-shadow - Box shadow when active/selected\n * @part tab - Tab trigger element.\n * @example\n * ```html\n * <ore-tab-item slot=\"tabs\" value=\"overview\">Overview</ore-tab-item>\n * <ore-tab-item slot=\"tabs\" value=\"settings\" disabled>Settings</ore-tab-item>\n * ```\n */\nexport const TAB_ITEM_TAG = 'ore-tab-item' as const;\ndefine<OreTabItemProps>(TAB_ITEM_TAG, {\n props: {\n ...disablableBundle,\n active: prop.bool(false),\n color: prop.string<ThemeColor>(),\n density: prop.oneOf(['compact', 'default'] as const, 'default'),\n size: prop.string<ComponentSize>(),\n value: prop.string(''),\n variant: prop.string<VisualVariant>(),\n },\n setup(props) {\n const el = getHost();\n const watch = watchEffect;\n\n const tabsCtx = inject(TABS_CTX);\n\n if (tabsCtx) {\n watch(() => {\n const color = tabsCtx.color.value;\n const density = tabsCtx.density.value;\n const size = tabsCtx.size.value;\n const variant = tabsCtx.variant.value;\n\n if (color !== undefined) el.setAttribute('color', color);\n\n el.setAttribute('density', density);\n\n if (size !== undefined) el.setAttribute('size', size);\n\n if (variant !== undefined) el.setAttribute('variant', variant);\n });\n }\n\n const isActive = computed(() =>\n tabsCtx ? !!tabsCtx.value.value && tabsCtx.value.value === props.value.value : props.active.value,\n );\n const isDisabled = () => Boolean(props.disabled.value);\n\n bind({\n attr: {\n active: () => (isActive.value ? true : undefined),\n },\n });\n\n const handleClick = (event: MouseEvent) => {\n event.stopPropagation();\n\n if (isDisabled()) {\n event.preventDefault();\n\n return;\n }\n\n el.dispatchEvent(new CustomEvent('click', { bubbles: true, detail: { value: props.value.value } }));\n };\n\n const tabId = () => `tab-${props.value.value}`;\n const buttonRef = ref<HTMLButtonElement>();\n\n // `aria-controls` as a plain IDREF attribute cannot resolve across shadow-tree boundaries\n // (the matching `id` lives inside <ore-tab-panel>'s own shadow root): see\n // `setAriaReflection()`'s doc comment. Deferred to `onMounted()`: sibling custom elements\n // (including the peer `<ore-tab-panel>`) connect in tree order within the same synchronous\n // insertion, so a sibling's shadow content may not exist yet during this element's own\n // `setup()`: `onMounted()`'s microtask runs after the whole subtree has connected.\n onMounted(() => {\n watchEffect(() => {\n const button = buttonRef.value;\n const value = props.value.value;\n\n if (!button) return;\n\n const tabsEl = value ? el.closest('ore-tabs') : null;\n const panelEl = tabsEl?.querySelector<HTMLElement>(`:scope > ore-tab-panel[value=\"${value}\"]`);\n const panel = panelEl?.shadowRoot?.querySelector<HTMLElement>('.panel') ?? null;\n\n setAriaReflection(button, 'ariaControlsElements', panel ? [panel] : []);\n });\n });\n\n return html`\n <button\n role=\"tab\"\n type=\"button\"\n part=\"tab\"\n ref=\"${buttonRef}\"\n id=\"${tabId}\"\n aria-selected=\"${isActive}\"\n tabindex=\"${() => (isActive.value ? '0' : '-1')}\"\n aria-disabled=\"${isDisabled}\"\n @click=\"${handleClick}\">\n <slot name=\"prefix\"></slot>\n <slot></slot>\n <slot name=\"suffix\"></slot>\n </button>\n `;\n },\n styles: [colorThemeMixin, forcedColorsFocusMixin('button'), coarsePointerMixin, styles],\n});\n"],"mappings":"+XA2DA,IAAa,EAAe,gBAC5B,EAAA,EAAA,OAAA,CAAwB,EAAc,CACpC,MAAO,CACL,GAAG,EAAA,iBACH,OAAQ,EAAA,KAAK,KAAK,EAAK,EACvB,MAAO,EAAA,KAAK,OAAmB,EAC/B,QAAS,EAAA,KAAK,MAAM,CAAC,UAAW,SAAS,EAAY,SAAS,EAC9D,KAAM,EAAA,KAAK,OAAsB,EACjC,MAAO,EAAA,KAAK,OAAO,EAAE,EACrB,QAAS,EAAA,KAAK,OAAsB,CACtC,EACA,MAAM,EAAO,CACX,IAAM,GAAA,EAAK,EAAA,QAAA,CAAQ,EACb,EAAQ,EAAA,YAER,GAAA,EAAU,EAAA,OAAA,CAAO,EAAA,QAAQ,EAE3B,GACF,MAAY,CACV,IAAM,EAAQ,EAAQ,MAAM,MACtB,EAAU,EAAQ,QAAQ,MAC1B,EAAO,EAAQ,KAAK,MACpB,EAAU,EAAQ,QAAQ,MAE5B,IAAU,IAAA,IAAW,EAAG,aAAa,QAAS,CAAK,EAEvD,EAAG,aAAa,UAAW,CAAO,EAE9B,IAAS,IAAA,IAAW,EAAG,aAAa,OAAQ,CAAI,EAEhD,IAAY,IAAA,IAAW,EAAG,aAAa,UAAW,CAAO,CAC/D,CAAC,EAGH,IAAM,GAAA,EAAW,EAAA,SAAA,KACf,EAAU,CAAC,CAAC,EAAQ,MAAM,OAAS,EAAQ,MAAM,QAAU,EAAM,MAAM,MAAQ,EAAM,OAAO,KAC9F,EACM,eAAmB,EAAQ,EAAM,SAAS,OAEhD,EAAA,EAAA,KAAA,CAAK,CACH,KAAM,CACJ,WAAe,EAAS,MAAQ,GAAO,IAAA,EACzC,CACF,CAAC,EAED,IAAM,YAAe,GAAsB,CAGzC,GAFA,EAAM,gBAAgB,EAElB,WAAW,EAAG,CAChB,EAAM,eAAe,EAErB,MACF,CAEA,EAAG,cAAc,IAAI,YAAY,QAAS,CAAE,QAAS,GAAM,OAAQ,CAAE,MAAO,EAAM,MAAM,KAAM,CAAE,CAAC,CAAC,CACpG,EAEM,UAAc,OAAO,EAAM,MAAM,QACjC,GAAA,EAAY,EAAA,IAAA,CAAuB,EAuBzC,OAfA,EAAA,EAAA,UAAA,KAAgB,EACd,EAAA,EAAA,YAAA,KAAkB,CAChB,IAAM,EAAS,EAAU,MACnB,EAAQ,EAAM,MAAM,MAE1B,GAAI,CAAC,EAAQ,OAIb,IAAM,IAFS,EAAQ,EAAG,QAAQ,UAAU,EAAI,KAAA,EACxB,cAA2B,iCAAiC,EAAM,GAAG,EAAA,EACtE,YAAY,cAA2B,QAAQ,GAAK,KAE3E,EAAA,kBAAkB,EAAQ,uBAAwB,EAAQ,CAAC,CAAK,EAAI,CAAC,CAAC,CACxE,CAAC,CACH,CAAC,EAEM,EAAA,IAAI;;;;;eAKA,EAAU;cACX,MAAM;yBACK,EAAS;wBACP,EAAS,MAAQ,IAAM,KAAM;yBAC/B,WAAW;kBAClB,YAAY;;;;;KAM5B,EACA,OAAQ,CAAC,EAAA,gBAAiB,EAAA,uBAAuB,QAAQ,EAAG,EAAA,mBAAoB,EAAA,OAAM,CACxF,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"tab-item.js","names":[],"sources":["../src/disclosure/tab-item/tab-item.ts"],"sourcesContent":["import { bind, define, getHost, html, inject, onMounted, prop, ref, watchEffect } from '@vielzeug/ore';\nimport { computed } from '@vielzeug/ripple';\nimport { setAriaReflection } from '../../core';\nimport { disablableBundle } from '../../shared';\nimport { coarsePointerMixin, colorThemeMixin, forcedColorsFocusMixin } from '../../styles';\nimport type { ComponentSize, ThemeColor, VisualVariant } from '../../types';\nimport { TABS_CTX } from '../tabs/tabs';\nimport styles from './tab-item.css?inline';\n\nexport type OreTabItemProps = {\n /** Whether this tab is currently selected (set by ore-tabs) */\n active?: boolean;\n /** Theme color (inherited from ore-tabs) */\n color?: ThemeColor;\n /** Disable this tab */\n disabled?: boolean;\n /** Spatial density (inherited from ore-tabs) */\n density?: 'compact' | 'default';\n /** Size (inherited from ore-tabs) */\n size?: ComponentSize;\n /** Unique value identifier — must match a ore-tab-panel value */\n value: string;\n /** Visual variant (inherited from ore-tabs) */\n variant?: VisualVariant;\n};\n\n/**\n * Individual tab trigger. Must be placed in the `tabs` slot of `ore-tabs`.\n *\n * @element ore-tab-item\n *\n * @attr {string} value - Unique identifier, matches the corresponding ore-tab-panel value\n * @attr {boolean} active - Set by the parent ore-tabs when this tab is selected\n * @attr {boolean} disabled - Prevents selection\n * @attr {string} density - Inherited spatial density: 'default' | 'compact'\n * @attr {string} size - 'sm' | 'md' | 'lg'\n * @attr {string} variant - Inherited from ore-tabs: 'solid' | 'flat' | 'bordered' | 'ghost' | 'frost'\n * @attr {string} color - Inherited from ore-tabs: 'primary' | 'secondary' | 'info' | 'success' | 'warning' | 'error'\n *\n * @slot prefix - Icon or content before the label\n * @slot - Tab label\n * @slot suffix - Badge or count after the label\n *\n * @cssprop --tab-item-radius - Button border radius\n * @cssprop --tab-item-transition - Transition duration/easing\n * @cssprop --tab-item-padding - Button padding\n * @cssprop --tab-item-font-size - Button font size\n * @cssprop --tab-item-color - Default text color\n * @cssprop --tab-item-hover-bg - Background on hover\n * @cssprop --tab-item-active-bg - Background when active/selected\n * @cssprop --tab-item-active-color - Text color when active/selected\n * @cssprop --tab-item-active-shadow - Box shadow when active/selected\n * @part tab - Tab trigger element.\n * @example\n * ```html\n * <ore-tab-item slot=\"tabs\" value=\"overview\">Overview</ore-tab-item>\n * <ore-tab-item slot=\"tabs\" value=\"settings\" disabled>Settings</ore-tab-item>\n * ```\n */\nexport const TAB_ITEM_TAG = 'ore-tab-item' as const;\ndefine<OreTabItemProps>(TAB_ITEM_TAG, {\n props: {\n ...disablableBundle,\n active: prop.bool(false),\n color: prop.string<ThemeColor>(),\n density: prop.oneOf(['compact', 'default'] as const, 'default'),\n size: prop.string<ComponentSize>(),\n value: prop.string(''),\n variant: prop.string<VisualVariant>(),\n },\n setup(props) {\n const el = getHost();\n const watch = watchEffect;\n\n const tabsCtx = inject(TABS_CTX);\n\n if (tabsCtx) {\n watch(() => {\n const color = tabsCtx.color.value;\n const density = tabsCtx.density.value;\n const size = tabsCtx.size.value;\n const variant = tabsCtx.variant.value;\n\n if (color !== undefined) el.setAttribute('color', color);\n\n el.setAttribute('density', density);\n\n if (size !== undefined) el.setAttribute('size', size);\n\n if (variant !== undefined) el.setAttribute('variant', variant);\n });\n }\n\n const isActive = computed(() =>\n tabsCtx ? !!tabsCtx.value.value && tabsCtx.value.value === props.value.value : props.active.value,\n );\n const isDisabled = () => Boolean(props.disabled.value);\n\n bind({\n attr: {\n active: () => (isActive.value ? true : undefined),\n },\n });\n\n const handleClick = (event: MouseEvent) => {\n event.stopPropagation();\n\n if (isDisabled()) {\n event.preventDefault();\n\n return;\n }\n\n el.dispatchEvent(new CustomEvent('click', { bubbles: true, detail: { value: props.value.value } }));\n };\n\n const tabId = () => `tab-${props.value.value}`;\n const buttonRef = ref<HTMLButtonElement>();\n\n // `aria-controls` as a plain IDREF attribute cannot resolve across shadow-tree boundaries\n // (the matching `id` lives inside <ore-tab-panel>'s own shadow root) — see\n // `setAriaReflection()`'s doc comment. Deferred to `onMounted()`: sibling custom elements\n // (including the peer `<ore-tab-panel>`) connect in tree order within the same synchronous\n // insertion, so a sibling's shadow content may not exist yet during this element's own\n // `setup()` — `onMounted()`'s microtask runs after the whole subtree has connected.\n onMounted(() => {\n watchEffect(() => {\n const button = buttonRef.value;\n const value = props.value.value;\n\n if (!button) return;\n\n const tabsEl = value ? el.closest('ore-tabs') : null;\n const panelEl = tabsEl?.querySelector<HTMLElement>(`:scope > ore-tab-panel[value=\"${value}\"]`);\n const panel = panelEl?.shadowRoot?.querySelector<HTMLElement>('.panel') ?? null;\n\n setAriaReflection(button, 'ariaControlsElements', panel ? [panel] : []);\n });\n });\n\n return html`\n <button\n role=\"tab\"\n type=\"button\"\n part=\"tab\"\n ref=\"${buttonRef}\"\n id=\"${tabId}\"\n aria-selected=\"${isActive}\"\n tabindex=\"${() => (isActive.value ? '0' : '-1')}\"\n aria-disabled=\"${isDisabled}\"\n @click=\"${handleClick}\">\n <slot name=\"prefix\"></slot>\n <slot></slot>\n <slot name=\"suffix\"></slot>\n </button>\n `;\n },\n styles: [colorThemeMixin, forcedColorsFocusMixin('button'), coarsePointerMixin, styles],\n});\n"],"mappings":"4iBA2DA,IAAa,EAAe,eAC5B,EAAwB,EAAc,CACpC,MAAO,CACL,GAAG,EACH,OAAQ,EAAK,KAAK,EAAK,EACvB,MAAO,EAAK,OAAmB,EAC/B,QAAS,EAAK,MAAM,CAAC,UAAW,SAAS,EAAY,SAAS,EAC9D,KAAM,EAAK,OAAsB,EACjC,MAAO,EAAK,OAAO,EAAE,EACrB,QAAS,EAAK,OAAsB,CACtC,EACA,MAAM,EAAO,CACX,IAAM,EAAK,EAAQ,EACb,EAAQ,EAER,EAAU,EAAO,CAAQ,EAE3B,GACF,MAAY,CACV,IAAM,EAAQ,EAAQ,MAAM,MACtB,EAAU,EAAQ,QAAQ,MAC1B,EAAO,EAAQ,KAAK,MACpB,EAAU,EAAQ,QAAQ,MAE5B,IAAU,IAAA,IAAW,EAAG,aAAa,QAAS,CAAK,EAEvD,EAAG,aAAa,UAAW,CAAO,EAE9B,IAAS,IAAA,IAAW,EAAG,aAAa,OAAQ,CAAI,EAEhD,IAAY,IAAA,IAAW,EAAG,aAAa,UAAW,CAAO,CAC/D,CAAC,EAGH,IAAM,EAAW,MACf,EAAU,CAAC,CAAC,EAAQ,MAAM,OAAS,EAAQ,MAAM,QAAU,EAAM,MAAM,MAAQ,EAAM,OAAO,KAC9F,EACM,eAAmB,EAAQ,EAAM,SAAS,MAEhD,EAAK,CACH,KAAM,CACJ,WAAe,EAAS,MAAQ,GAAO,IAAA,EACzC,CACF,CAAC,EAED,IAAM,YAAe,GAAsB,CAGzC,GAFA,EAAM,gBAAgB,EAElB,WAAW,EAAG,CAChB,EAAM,eAAe,EAErB,MACF,CAEA,EAAG,cAAc,IAAI,YAAY,QAAS,CAAE,QAAS,GAAM,OAAQ,CAAE,MAAO,EAAM,MAAM,KAAM,CAAE,CAAC,CAAC,CACpG,EAEM,UAAc,OAAO,EAAM,MAAM,QACjC,EAAY,EAAuB,EAuBzC,OAfA,MAAgB,CACd,MAAkB,CAChB,IAAM,EAAS,EAAU,MACnB,EAAQ,EAAM,MAAM,MAE1B,GAAI,CAAC,EAAQ,OAIb,IAAM,IAFS,EAAQ,EAAG,QAAQ,UAAU,EAAI,KAAA,EACxB,cAA2B,iCAAiC,EAAM,GAAG,EAAA,EACtE,YAAY,cAA2B,QAAQ,GAAK,KAE3E,EAAkB,EAAQ,uBAAwB,EAAQ,CAAC,CAAK,EAAI,CAAC,CAAC,CACxE,CAAC,CACH,CAAC,EAEM,CAAI;;;;;eAKA,EAAU;cACX,MAAM;yBACK,EAAS;wBACP,EAAS,MAAQ,IAAM,KAAM;yBAC/B,WAAW;kBAClB,YAAY;;;;;KAM5B,EACA,OAAQ,CAAC,EAAiB,EAAuB,QAAQ,EAAG,EAAoB,CAAM,CACxF,CAAC"}
1
+ {"version":3,"file":"tab-item.js","names":[],"sources":["../src/disclosure/tab-item/tab-item.ts"],"sourcesContent":["import { bind, define, getHost, html, inject, onMounted, prop, ref, watchEffect } from '@vielzeug/ore';\nimport { computed } from '@vielzeug/ripple';\nimport { setAriaReflection } from '../../core';\nimport { disablableBundle } from '../../shared';\nimport { coarsePointerMixin, colorThemeMixin, forcedColorsFocusMixin } from '../../styles';\nimport type { ComponentSize, ThemeColor, VisualVariant } from '../../types';\nimport { TABS_CTX } from '../tabs/tabs';\nimport styles from './tab-item.css?inline';\n\nexport type OreTabItemProps = {\n /** Whether this tab is currently selected (set by ore-tabs) */\n active?: boolean;\n /** Theme color (inherited from ore-tabs) */\n color?: ThemeColor;\n /** Disable this tab */\n disabled?: boolean;\n /** Spatial density (inherited from ore-tabs) */\n density?: 'compact' | 'default';\n /** Size (inherited from ore-tabs) */\n size?: ComponentSize;\n /** Unique value identifier: must match a ore-tab-panel value */\n value: string;\n /** Visual variant (inherited from ore-tabs) */\n variant?: VisualVariant;\n};\n\n/**\n * Individual tab trigger. Must be placed in the `tabs` slot of `ore-tabs`.\n *\n * @element ore-tab-item\n *\n * @attr {string} value - Unique identifier, matches the corresponding ore-tab-panel value\n * @attr {boolean} active - Set by the parent ore-tabs when this tab is selected\n * @attr {boolean} disabled - Prevents selection\n * @attr {string} density - Inherited spatial density: 'default' | 'compact'\n * @attr {string} size - 'sm' | 'md' | 'lg'\n * @attr {string} variant - Inherited from ore-tabs: 'solid' | 'flat' | 'bordered' | 'ghost' | 'frost'\n * @attr {string} color - Inherited from ore-tabs: 'primary' | 'secondary' | 'info' | 'success' | 'warning' | 'error'\n *\n * @slot prefix - Icon or content before the label\n * @slot - Tab label\n * @slot suffix - Badge or count after the label\n *\n * @cssprop --tab-item-radius - Button border radius\n * @cssprop --tab-item-transition - Transition duration/easing\n * @cssprop --tab-item-padding - Button padding\n * @cssprop --tab-item-font-size - Button font size\n * @cssprop --tab-item-color - Default text color\n * @cssprop --tab-item-hover-bg - Background on hover\n * @cssprop --tab-item-active-bg - Background when active/selected\n * @cssprop --tab-item-active-color - Text color when active/selected\n * @cssprop --tab-item-active-shadow - Box shadow when active/selected\n * @part tab - Tab trigger element.\n * @example\n * ```html\n * <ore-tab-item slot=\"tabs\" value=\"overview\">Overview</ore-tab-item>\n * <ore-tab-item slot=\"tabs\" value=\"settings\" disabled>Settings</ore-tab-item>\n * ```\n */\nexport const TAB_ITEM_TAG = 'ore-tab-item' as const;\ndefine<OreTabItemProps>(TAB_ITEM_TAG, {\n props: {\n ...disablableBundle,\n active: prop.bool(false),\n color: prop.string<ThemeColor>(),\n density: prop.oneOf(['compact', 'default'] as const, 'default'),\n size: prop.string<ComponentSize>(),\n value: prop.string(''),\n variant: prop.string<VisualVariant>(),\n },\n setup(props) {\n const el = getHost();\n const watch = watchEffect;\n\n const tabsCtx = inject(TABS_CTX);\n\n if (tabsCtx) {\n watch(() => {\n const color = tabsCtx.color.value;\n const density = tabsCtx.density.value;\n const size = tabsCtx.size.value;\n const variant = tabsCtx.variant.value;\n\n if (color !== undefined) el.setAttribute('color', color);\n\n el.setAttribute('density', density);\n\n if (size !== undefined) el.setAttribute('size', size);\n\n if (variant !== undefined) el.setAttribute('variant', variant);\n });\n }\n\n const isActive = computed(() =>\n tabsCtx ? !!tabsCtx.value.value && tabsCtx.value.value === props.value.value : props.active.value,\n );\n const isDisabled = () => Boolean(props.disabled.value);\n\n bind({\n attr: {\n active: () => (isActive.value ? true : undefined),\n },\n });\n\n const handleClick = (event: MouseEvent) => {\n event.stopPropagation();\n\n if (isDisabled()) {\n event.preventDefault();\n\n return;\n }\n\n el.dispatchEvent(new CustomEvent('click', { bubbles: true, detail: { value: props.value.value } }));\n };\n\n const tabId = () => `tab-${props.value.value}`;\n const buttonRef = ref<HTMLButtonElement>();\n\n // `aria-controls` as a plain IDREF attribute cannot resolve across shadow-tree boundaries\n // (the matching `id` lives inside <ore-tab-panel>'s own shadow root): see\n // `setAriaReflection()`'s doc comment. Deferred to `onMounted()`: sibling custom elements\n // (including the peer `<ore-tab-panel>`) connect in tree order within the same synchronous\n // insertion, so a sibling's shadow content may not exist yet during this element's own\n // `setup()`: `onMounted()`'s microtask runs after the whole subtree has connected.\n onMounted(() => {\n watchEffect(() => {\n const button = buttonRef.value;\n const value = props.value.value;\n\n if (!button) return;\n\n const tabsEl = value ? el.closest('ore-tabs') : null;\n const panelEl = tabsEl?.querySelector<HTMLElement>(`:scope > ore-tab-panel[value=\"${value}\"]`);\n const panel = panelEl?.shadowRoot?.querySelector<HTMLElement>('.panel') ?? null;\n\n setAriaReflection(button, 'ariaControlsElements', panel ? [panel] : []);\n });\n });\n\n return html`\n <button\n role=\"tab\"\n type=\"button\"\n part=\"tab\"\n ref=\"${buttonRef}\"\n id=\"${tabId}\"\n aria-selected=\"${isActive}\"\n tabindex=\"${() => (isActive.value ? '0' : '-1')}\"\n aria-disabled=\"${isDisabled}\"\n @click=\"${handleClick}\">\n <slot name=\"prefix\"></slot>\n <slot></slot>\n <slot name=\"suffix\"></slot>\n </button>\n `;\n },\n styles: [colorThemeMixin, forcedColorsFocusMixin('button'), coarsePointerMixin, styles],\n});\n"],"mappings":"4iBA2DA,IAAa,EAAe,eAC5B,EAAwB,EAAc,CACpC,MAAO,CACL,GAAG,EACH,OAAQ,EAAK,KAAK,EAAK,EACvB,MAAO,EAAK,OAAmB,EAC/B,QAAS,EAAK,MAAM,CAAC,UAAW,SAAS,EAAY,SAAS,EAC9D,KAAM,EAAK,OAAsB,EACjC,MAAO,EAAK,OAAO,EAAE,EACrB,QAAS,EAAK,OAAsB,CACtC,EACA,MAAM,EAAO,CACX,IAAM,EAAK,EAAQ,EACb,EAAQ,EAER,EAAU,EAAO,CAAQ,EAE3B,GACF,MAAY,CACV,IAAM,EAAQ,EAAQ,MAAM,MACtB,EAAU,EAAQ,QAAQ,MAC1B,EAAO,EAAQ,KAAK,MACpB,EAAU,EAAQ,QAAQ,MAE5B,IAAU,IAAA,IAAW,EAAG,aAAa,QAAS,CAAK,EAEvD,EAAG,aAAa,UAAW,CAAO,EAE9B,IAAS,IAAA,IAAW,EAAG,aAAa,OAAQ,CAAI,EAEhD,IAAY,IAAA,IAAW,EAAG,aAAa,UAAW,CAAO,CAC/D,CAAC,EAGH,IAAM,EAAW,MACf,EAAU,CAAC,CAAC,EAAQ,MAAM,OAAS,EAAQ,MAAM,QAAU,EAAM,MAAM,MAAQ,EAAM,OAAO,KAC9F,EACM,eAAmB,EAAQ,EAAM,SAAS,MAEhD,EAAK,CACH,KAAM,CACJ,WAAe,EAAS,MAAQ,GAAO,IAAA,EACzC,CACF,CAAC,EAED,IAAM,YAAe,GAAsB,CAGzC,GAFA,EAAM,gBAAgB,EAElB,WAAW,EAAG,CAChB,EAAM,eAAe,EAErB,MACF,CAEA,EAAG,cAAc,IAAI,YAAY,QAAS,CAAE,QAAS,GAAM,OAAQ,CAAE,MAAO,EAAM,MAAM,KAAM,CAAE,CAAC,CAAC,CACpG,EAEM,UAAc,OAAO,EAAM,MAAM,QACjC,EAAY,EAAuB,EAuBzC,OAfA,MAAgB,CACd,MAAkB,CAChB,IAAM,EAAS,EAAU,MACnB,EAAQ,EAAM,MAAM,MAE1B,GAAI,CAAC,EAAQ,OAIb,IAAM,IAFS,EAAQ,EAAG,QAAQ,UAAU,EAAI,KAAA,EACxB,cAA2B,iCAAiC,EAAM,GAAG,EAAA,EACtE,YAAY,cAA2B,QAAQ,GAAK,KAE3E,EAAkB,EAAQ,uBAAwB,EAAQ,CAAC,CAAK,EAAI,CAAC,CAAC,CACxE,CAAC,CACH,CAAC,EAEM,CAAI;;;;;eAKA,EAAU;cACX,MAAM;yBACK,EAAS;wBACP,EAAS,MAAQ,IAAM,KAAM;yBAC/B,WAAW;kBAClB,YAAY;;;;;KAM5B,EACA,OAAQ,CAAC,EAAiB,EAAuB,QAAQ,EAAG,EAAoB,CAAM,CACxF,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"tab-panel.cjs","names":[],"sources":["../src/disclosure/tab-panel/tab-panel.ts"],"sourcesContent":["import { bind, define, getHost, html, inject, onMounted, prop, ref, styleMap, watchEffect, when } from '@vielzeug/ore';\nimport { computed, signal } from '@vielzeug/ripple';\n\nimport { setAriaReflection } from '../../core';\nimport { reducedMotionMixin } from '../../styles';\nimport { TABS_CTX } from '../tabs/tabs';\nimport styles from './tab-panel.css?inline';\n\nconst TAB_PANEL_PADDING_PRESET: Record<string, string> = {\n '2xl': 'var(--size-12)',\n lg: 'var(--size-6)',\n md: 'var(--size-4)',\n none: '0',\n sm: 'var(--size-2)',\n xl: 'var(--size-8)',\n xs: 'var(--size-1)',\n};\n\nexport type OreTabPanelProps = {\n /** Active state (managed by ore-tabs) */\n active?: boolean;\n /** When true, the panel content is not rendered until first activation (preserves resources) */\n lazy?: boolean;\n /** Panel padding size: 'none' | 'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl' (default: 'md' = var(--size-4)) */\n padding?: 'none' | 'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl';\n /** Must match the `value` of its corresponding ore-tab-item */\n value: string;\n};\n\n/**\n * Content panel for a tab. Shown when its `value` matches the selected tab.\n *\n * @element ore-tab-panel\n *\n * @attr {string} value - Must match the corresponding ore-tab-item value\n * @attr {boolean} active - Toggled by the parent ore-tabs\n * @attr {string} padding - Panel padding: 'none' | 'xs' | 'sm' | 'md' (default) | 'lg' | 'xl' | '2xl'\n *\n * @slot - Panel content\n *\n * @cssprop --tab-panel-padding - Inner padding of the panel content area\n * @cssprop --tab-panel-font-size - Font size of the panel content\n * @part panel - Panel container.\n * @example\n * ```html\n * <ore-tab-panel value=\"overview\"><p>Overview content here</p></ore-tab-panel>\n * <ore-tab-panel value=\"settings\" padding=\"lg\"><p>Large padding</p></ore-tab-panel>\n * <ore-tab-panel value=\"code\" padding=\"none\"><pre>No padding for code</pre></ore-tab-panel>\n * ```\n */\nexport const TAB_PANEL_TAG = 'ore-tab-panel' as const;\ndefine<OreTabPanelProps>(TAB_PANEL_TAG, {\n props: {\n active: prop.bool(false),\n lazy: prop.bool(false),\n padding: prop.oneOf(['none', 'xs', 'sm', 'md', 'lg', 'xl', '2xl'] as const, 'md'),\n value: prop.string(''),\n },\n setup(props) {\n const el = getHost();\n const watch = watchEffect;\n\n const tabsCtx = inject(TABS_CTX);\n const isActive = computed(() =>\n tabsCtx ? !!tabsCtx.value.value && tabsCtx.value.value === props.value.value : props.active.value,\n );\n\n bind({\n attr: {\n active: () => (isActive.value ? true : undefined),\n },\n });\n\n // Map padding prop to CSS variable\n const paddingValue = computed(() => {\n const key = props.padding.value ?? 'md';\n\n return TAB_PANEL_PADDING_PRESET[key] ?? TAB_PANEL_PADDING_PRESET.md;\n });\n // Track whether the panel has ever been active (for lazy rendering)\n const hasBeenActive = signal(false);\n\n watch(() => {\n if (isActive.value) hasBeenActive.value = true;\n });\n\n // shouldRender: true if not lazy OR has been active at least once\n const shouldRender = computed(() => !props.lazy.value || hasBeenActive.value);\n const panelStyle = styleMap({ '--tab-panel-padding': paddingValue });\n const panelId = () => `tabpanel-${props.value.value}`;\n const panelRef = ref<HTMLElement>();\n\n // `aria-labelledby` as a plain IDREF attribute cannot resolve across shadow-tree boundaries\n // (the matching `id` lives inside <ore-tab-item>'s own shadow root) — see\n // `setAriaReflection()`'s doc comment. Deferred to `onMounted()`: sibling custom elements\n // (including the peer `<ore-tab-item>`) connect in tree order within the same synchronous\n // insertion, so a sibling's shadow content may not exist yet during this element's own\n // `setup()` — `onMounted()`'s microtask runs after the whole subtree has connected.\n onMounted(() => {\n watch(() => {\n const panel = panelRef.value;\n const value = props.value.value;\n\n if (!panel) return;\n\n const tabsEl = value ? el.closest('ore-tabs') : null;\n const tabEl = tabsEl?.querySelector<HTMLElement>(`:scope > ore-tab-item[value=\"${value}\"]`);\n const button = tabEl?.shadowRoot?.querySelector<HTMLElement>('[role=\"tab\"]') ?? null;\n\n setAriaReflection(panel, 'ariaLabelledByElements', button ? [button] : []);\n });\n });\n\n return html`\n <div\n class=\"panel\"\n part=\"panel\"\n role=\"tabpanel\"\n ref=\"${panelRef}\"\n id=\"${panelId}\"\n aria-hidden=\"${() => String(!isActive.value)}\"\n style=\"${panelStyle}\"\n tabindex=\"0\">\n ${when(\n shouldRender,\n () => html`\n <slot></slot>\n `,\n )}\n </div>\n `;\n },\n styles: [reducedMotionMixin, styles],\n});\n"],"mappings":"+SAQA,IAAM,EAAmD,CACvD,MAAO,iBACP,GAAI,gBACJ,GAAI,gBACJ,KAAM,IACN,GAAI,gBACJ,GAAI,gBACJ,GAAI,eACN,EAkCa,EAAgB,iBAC7B,EAAA,EAAA,OAAA,CAAyB,EAAe,CACtC,MAAO,CACL,OAAQ,EAAA,KAAK,KAAK,EAAK,EACvB,KAAM,EAAA,KAAK,KAAK,EAAK,EACrB,QAAS,EAAA,KAAK,MAAM,CAAC,OAAQ,KAAM,KAAM,KAAM,KAAM,KAAM,KAAK,EAAY,IAAI,EAChF,MAAO,EAAA,KAAK,OAAO,EAAE,CACvB,EACA,MAAM,EAAO,CACX,IAAM,GAAA,EAAK,EAAA,QAAA,CAAQ,EACb,EAAQ,EAAA,YAER,GAAA,EAAU,EAAA,OAAA,CAAO,EAAA,QAAQ,EACzB,GAAA,EAAW,EAAA,SAAA,KACf,EAAU,CAAC,CAAC,EAAQ,MAAM,OAAS,EAAQ,MAAM,QAAU,EAAM,MAAM,MAAQ,EAAM,OAAO,KAC9F,GAEA,EAAA,EAAA,KAAA,CAAK,CACH,KAAM,CACJ,WAAe,EAAS,MAAQ,GAAO,IAAA,EACzC,CACF,CAAC,EAGD,IAAM,GAAA,EAAe,EAAA,SAAA,KAGZ,EAFK,EAAM,QAAQ,OAAS,OAEK,EAAyB,EAClE,EAEK,GAAA,EAAgB,EAAA,OAAA,CAAO,EAAK,EAElC,MAAY,CACN,EAAS,QAAO,EAAc,MAAQ,GAC5C,CAAC,EAGD,IAAM,GAAA,EAAe,EAAA,SAAA,KAAe,CAAC,EAAM,KAAK,OAAS,EAAc,KAAK,EACtE,GAAA,EAAa,EAAA,SAAA,CAAS,CAAE,sBAAuB,CAAa,CAAC,EAC7D,YAAgB,YAAY,EAAM,MAAM,QACxC,GAAA,EAAW,EAAA,IAAA,CAAiB,EAuBlC,OAfA,EAAA,EAAA,UAAA,KAAgB,CACd,MAAY,CACV,IAAM,EAAQ,EAAS,MACjB,EAAQ,EAAM,MAAM,MAE1B,GAAI,CAAC,EAAO,OAIZ,IAAM,IAFS,EAAQ,EAAG,QAAQ,UAAU,EAAI,KAAA,EAC1B,cAA2B,gCAAgC,EAAM,GAAG,EAAA,EACpE,YAAY,cAA2B,cAAc,GAAK,KAEhF,EAAA,kBAAkB,EAAO,yBAA0B,EAAS,CAAC,CAAM,EAAI,CAAC,CAAC,CAC3E,CAAC,CACH,CAAC,EAEM,EAAA,IAAI;;;;;eAKA,EAAS;cACV,QAAQ;2BACO,OAAO,CAAC,EAAS,KAAK,EAAE;iBACpC,EAAW;;WAElB,EAAA,EAAA,KAAA,CACA,MACM,EAAA,IAAI;;WAGZ,EAAE;;KAGR,EACA,OAAQ,CAAC,EAAA,mBAAoB,EAAA,OAAM,CACrC,CAAC"}
1
+ {"version":3,"file":"tab-panel.cjs","names":[],"sources":["../src/disclosure/tab-panel/tab-panel.ts"],"sourcesContent":["import { bind, define, getHost, html, inject, onMounted, prop, ref, styleMap, watchEffect, when } from '@vielzeug/ore';\nimport { computed, signal } from '@vielzeug/ripple';\n\nimport { setAriaReflection } from '../../core';\nimport { reducedMotionMixin } from '../../styles';\nimport { TABS_CTX } from '../tabs/tabs';\nimport styles from './tab-panel.css?inline';\n\nconst TAB_PANEL_PADDING_PRESET: Record<string, string> = {\n '2xl': 'var(--size-12)',\n lg: 'var(--size-6)',\n md: 'var(--size-4)',\n none: '0',\n sm: 'var(--size-2)',\n xl: 'var(--size-8)',\n xs: 'var(--size-1)',\n};\n\nexport type OreTabPanelProps = {\n /** Active state (managed by ore-tabs) */\n active?: boolean;\n /** When true, the panel content is not rendered until first activation (preserves resources) */\n lazy?: boolean;\n /** Panel padding size: 'none' | 'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl' (default: 'md' = var(--size-4)) */\n padding?: 'none' | 'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl';\n /** Must match the `value` of its corresponding ore-tab-item */\n value: string;\n};\n\n/**\n * Content panel for a tab. Shown when its `value` matches the selected tab.\n *\n * @element ore-tab-panel\n *\n * @attr {string} value - Must match the corresponding ore-tab-item value\n * @attr {boolean} active - Toggled by the parent ore-tabs\n * @attr {string} padding - Panel padding: 'none' | 'xs' | 'sm' | 'md' (default) | 'lg' | 'xl' | '2xl'\n *\n * @slot - Panel content\n *\n * @cssprop --tab-panel-padding - Inner padding of the panel content area\n * @cssprop --tab-panel-font-size - Font size of the panel content\n * @part panel - Panel container.\n * @example\n * ```html\n * <ore-tab-panel value=\"overview\"><p>Overview content here</p></ore-tab-panel>\n * <ore-tab-panel value=\"settings\" padding=\"lg\"><p>Large padding</p></ore-tab-panel>\n * <ore-tab-panel value=\"code\" padding=\"none\"><pre>No padding for code</pre></ore-tab-panel>\n * ```\n */\nexport const TAB_PANEL_TAG = 'ore-tab-panel' as const;\ndefine<OreTabPanelProps>(TAB_PANEL_TAG, {\n props: {\n active: prop.bool(false),\n lazy: prop.bool(false),\n padding: prop.oneOf(['none', 'xs', 'sm', 'md', 'lg', 'xl', '2xl'] as const, 'md'),\n value: prop.string(''),\n },\n setup(props) {\n const el = getHost();\n const watch = watchEffect;\n\n const tabsCtx = inject(TABS_CTX);\n const isActive = computed(() =>\n tabsCtx ? !!tabsCtx.value.value && tabsCtx.value.value === props.value.value : props.active.value,\n );\n\n bind({\n attr: {\n active: () => (isActive.value ? true : undefined),\n },\n });\n\n // Map padding prop to CSS variable\n const paddingValue = computed(() => {\n const key = props.padding.value ?? 'md';\n\n return TAB_PANEL_PADDING_PRESET[key] ?? TAB_PANEL_PADDING_PRESET.md;\n });\n // Track whether the panel has ever been active (for lazy rendering)\n const hasBeenActive = signal(false);\n\n watch(() => {\n if (isActive.value) hasBeenActive.value = true;\n });\n\n // shouldRender: true if not lazy OR has been active at least once\n const shouldRender = computed(() => !props.lazy.value || hasBeenActive.value);\n const panelStyle = styleMap({ '--tab-panel-padding': paddingValue });\n const panelId = () => `tabpanel-${props.value.value}`;\n const panelRef = ref<HTMLElement>();\n\n // `aria-labelledby` as a plain IDREF attribute cannot resolve across shadow-tree boundaries\n // (the matching `id` lives inside <ore-tab-item>'s own shadow root): see\n // `setAriaReflection()`'s doc comment. Deferred to `onMounted()`: sibling custom elements\n // (including the peer `<ore-tab-item>`) connect in tree order within the same synchronous\n // insertion, so a sibling's shadow content may not exist yet during this element's own\n // `setup()`: `onMounted()`'s microtask runs after the whole subtree has connected.\n onMounted(() => {\n watch(() => {\n const panel = panelRef.value;\n const value = props.value.value;\n\n if (!panel) return;\n\n const tabsEl = value ? el.closest('ore-tabs') : null;\n const tabEl = tabsEl?.querySelector<HTMLElement>(`:scope > ore-tab-item[value=\"${value}\"]`);\n const button = tabEl?.shadowRoot?.querySelector<HTMLElement>('[role=\"tab\"]') ?? null;\n\n setAriaReflection(panel, 'ariaLabelledByElements', button ? [button] : []);\n });\n });\n\n return html`\n <div\n class=\"panel\"\n part=\"panel\"\n role=\"tabpanel\"\n ref=\"${panelRef}\"\n id=\"${panelId}\"\n aria-hidden=\"${() => String(!isActive.value)}\"\n style=\"${panelStyle}\"\n tabindex=\"0\">\n ${when(\n shouldRender,\n () => html`\n <slot></slot>\n `,\n )}\n </div>\n `;\n },\n styles: [reducedMotionMixin, styles],\n});\n"],"mappings":"+SAQA,IAAM,EAAmD,CACvD,MAAO,iBACP,GAAI,gBACJ,GAAI,gBACJ,KAAM,IACN,GAAI,gBACJ,GAAI,gBACJ,GAAI,eACN,EAkCa,EAAgB,iBAC7B,EAAA,EAAA,OAAA,CAAyB,EAAe,CACtC,MAAO,CACL,OAAQ,EAAA,KAAK,KAAK,EAAK,EACvB,KAAM,EAAA,KAAK,KAAK,EAAK,EACrB,QAAS,EAAA,KAAK,MAAM,CAAC,OAAQ,KAAM,KAAM,KAAM,KAAM,KAAM,KAAK,EAAY,IAAI,EAChF,MAAO,EAAA,KAAK,OAAO,EAAE,CACvB,EACA,MAAM,EAAO,CACX,IAAM,GAAA,EAAK,EAAA,QAAA,CAAQ,EACb,EAAQ,EAAA,YAER,GAAA,EAAU,EAAA,OAAA,CAAO,EAAA,QAAQ,EACzB,GAAA,EAAW,EAAA,SAAA,KACf,EAAU,CAAC,CAAC,EAAQ,MAAM,OAAS,EAAQ,MAAM,QAAU,EAAM,MAAM,MAAQ,EAAM,OAAO,KAC9F,GAEA,EAAA,EAAA,KAAA,CAAK,CACH,KAAM,CACJ,WAAe,EAAS,MAAQ,GAAO,IAAA,EACzC,CACF,CAAC,EAGD,IAAM,GAAA,EAAe,EAAA,SAAA,KAGZ,EAFK,EAAM,QAAQ,OAAS,OAEK,EAAyB,EAClE,EAEK,GAAA,EAAgB,EAAA,OAAA,CAAO,EAAK,EAElC,MAAY,CACN,EAAS,QAAO,EAAc,MAAQ,GAC5C,CAAC,EAGD,IAAM,GAAA,EAAe,EAAA,SAAA,KAAe,CAAC,EAAM,KAAK,OAAS,EAAc,KAAK,EACtE,GAAA,EAAa,EAAA,SAAA,CAAS,CAAE,sBAAuB,CAAa,CAAC,EAC7D,YAAgB,YAAY,EAAM,MAAM,QACxC,GAAA,EAAW,EAAA,IAAA,CAAiB,EAuBlC,OAfA,EAAA,EAAA,UAAA,KAAgB,CACd,MAAY,CACV,IAAM,EAAQ,EAAS,MACjB,EAAQ,EAAM,MAAM,MAE1B,GAAI,CAAC,EAAO,OAIZ,IAAM,IAFS,EAAQ,EAAG,QAAQ,UAAU,EAAI,KAAA,EAC1B,cAA2B,gCAAgC,EAAM,GAAG,EAAA,EACpE,YAAY,cAA2B,cAAc,GAAK,KAEhF,EAAA,kBAAkB,EAAO,yBAA0B,EAAS,CAAC,CAAM,EAAI,CAAC,CAAC,CAC3E,CAAC,CACH,CAAC,EAEM,EAAA,IAAI;;;;;eAKA,EAAS;cACV,QAAQ;2BACO,OAAO,CAAC,EAAS,KAAK,EAAE;iBACpC,EAAW;;WAElB,EAAA,EAAA,KAAA,CACA,MACM,EAAA,IAAI;;WAGZ,EAAE;;KAGR,EACA,OAAQ,CAAC,EAAA,mBAAoB,EAAA,OAAM,CACrC,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"tab-panel.js","names":[],"sources":["../src/disclosure/tab-panel/tab-panel.ts"],"sourcesContent":["import { bind, define, getHost, html, inject, onMounted, prop, ref, styleMap, watchEffect, when } from '@vielzeug/ore';\nimport { computed, signal } from '@vielzeug/ripple';\n\nimport { setAriaReflection } from '../../core';\nimport { reducedMotionMixin } from '../../styles';\nimport { TABS_CTX } from '../tabs/tabs';\nimport styles from './tab-panel.css?inline';\n\nconst TAB_PANEL_PADDING_PRESET: Record<string, string> = {\n '2xl': 'var(--size-12)',\n lg: 'var(--size-6)',\n md: 'var(--size-4)',\n none: '0',\n sm: 'var(--size-2)',\n xl: 'var(--size-8)',\n xs: 'var(--size-1)',\n};\n\nexport type OreTabPanelProps = {\n /** Active state (managed by ore-tabs) */\n active?: boolean;\n /** When true, the panel content is not rendered until first activation (preserves resources) */\n lazy?: boolean;\n /** Panel padding size: 'none' | 'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl' (default: 'md' = var(--size-4)) */\n padding?: 'none' | 'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl';\n /** Must match the `value` of its corresponding ore-tab-item */\n value: string;\n};\n\n/**\n * Content panel for a tab. Shown when its `value` matches the selected tab.\n *\n * @element ore-tab-panel\n *\n * @attr {string} value - Must match the corresponding ore-tab-item value\n * @attr {boolean} active - Toggled by the parent ore-tabs\n * @attr {string} padding - Panel padding: 'none' | 'xs' | 'sm' | 'md' (default) | 'lg' | 'xl' | '2xl'\n *\n * @slot - Panel content\n *\n * @cssprop --tab-panel-padding - Inner padding of the panel content area\n * @cssprop --tab-panel-font-size - Font size of the panel content\n * @part panel - Panel container.\n * @example\n * ```html\n * <ore-tab-panel value=\"overview\"><p>Overview content here</p></ore-tab-panel>\n * <ore-tab-panel value=\"settings\" padding=\"lg\"><p>Large padding</p></ore-tab-panel>\n * <ore-tab-panel value=\"code\" padding=\"none\"><pre>No padding for code</pre></ore-tab-panel>\n * ```\n */\nexport const TAB_PANEL_TAG = 'ore-tab-panel' as const;\ndefine<OreTabPanelProps>(TAB_PANEL_TAG, {\n props: {\n active: prop.bool(false),\n lazy: prop.bool(false),\n padding: prop.oneOf(['none', 'xs', 'sm', 'md', 'lg', 'xl', '2xl'] as const, 'md'),\n value: prop.string(''),\n },\n setup(props) {\n const el = getHost();\n const watch = watchEffect;\n\n const tabsCtx = inject(TABS_CTX);\n const isActive = computed(() =>\n tabsCtx ? !!tabsCtx.value.value && tabsCtx.value.value === props.value.value : props.active.value,\n );\n\n bind({\n attr: {\n active: () => (isActive.value ? true : undefined),\n },\n });\n\n // Map padding prop to CSS variable\n const paddingValue = computed(() => {\n const key = props.padding.value ?? 'md';\n\n return TAB_PANEL_PADDING_PRESET[key] ?? TAB_PANEL_PADDING_PRESET.md;\n });\n // Track whether the panel has ever been active (for lazy rendering)\n const hasBeenActive = signal(false);\n\n watch(() => {\n if (isActive.value) hasBeenActive.value = true;\n });\n\n // shouldRender: true if not lazy OR has been active at least once\n const shouldRender = computed(() => !props.lazy.value || hasBeenActive.value);\n const panelStyle = styleMap({ '--tab-panel-padding': paddingValue });\n const panelId = () => `tabpanel-${props.value.value}`;\n const panelRef = ref<HTMLElement>();\n\n // `aria-labelledby` as a plain IDREF attribute cannot resolve across shadow-tree boundaries\n // (the matching `id` lives inside <ore-tab-item>'s own shadow root) — see\n // `setAriaReflection()`'s doc comment. Deferred to `onMounted()`: sibling custom elements\n // (including the peer `<ore-tab-item>`) connect in tree order within the same synchronous\n // insertion, so a sibling's shadow content may not exist yet during this element's own\n // `setup()` — `onMounted()`'s microtask runs after the whole subtree has connected.\n onMounted(() => {\n watch(() => {\n const panel = panelRef.value;\n const value = props.value.value;\n\n if (!panel) return;\n\n const tabsEl = value ? el.closest('ore-tabs') : null;\n const tabEl = tabsEl?.querySelector<HTMLElement>(`:scope > ore-tab-item[value=\"${value}\"]`);\n const button = tabEl?.shadowRoot?.querySelector<HTMLElement>('[role=\"tab\"]') ?? null;\n\n setAriaReflection(panel, 'ariaLabelledByElements', button ? [button] : []);\n });\n });\n\n return html`\n <div\n class=\"panel\"\n part=\"panel\"\n role=\"tabpanel\"\n ref=\"${panelRef}\"\n id=\"${panelId}\"\n aria-hidden=\"${() => String(!isActive.value)}\"\n style=\"${panelStyle}\"\n tabindex=\"0\">\n ${when(\n shouldRender,\n () => html`\n <slot></slot>\n `,\n )}\n </div>\n `;\n },\n styles: [reducedMotionMixin, styles],\n});\n"],"mappings":"2bAQA,IAAM,EAAmD,CACvD,MAAO,iBACP,GAAI,gBACJ,GAAI,gBACJ,KAAM,IACN,GAAI,gBACJ,GAAI,gBACJ,GAAI,eACN,EAkCa,EAAgB,gBAC7B,EAAyB,EAAe,CACtC,MAAO,CACL,OAAQ,EAAK,KAAK,EAAK,EACvB,KAAM,EAAK,KAAK,EAAK,EACrB,QAAS,EAAK,MAAM,CAAC,OAAQ,KAAM,KAAM,KAAM,KAAM,KAAM,KAAK,EAAY,IAAI,EAChF,MAAO,EAAK,OAAO,EAAE,CACvB,EACA,MAAM,EAAO,CACX,IAAM,EAAK,EAAQ,EACb,EAAQ,EAER,EAAU,EAAO,CAAQ,EACzB,EAAW,MACf,EAAU,CAAC,CAAC,EAAQ,MAAM,OAAS,EAAQ,MAAM,QAAU,EAAM,MAAM,MAAQ,EAAM,OAAO,KAC9F,EAEA,EAAK,CACH,KAAM,CACJ,WAAe,EAAS,MAAQ,GAAO,IAAA,EACzC,CACF,CAAC,EAGD,IAAM,EAAe,MAGZ,EAFK,EAAM,QAAQ,OAAS,OAEK,EAAyB,EAClE,EAEK,EAAgB,EAAO,EAAK,EAElC,MAAY,CACN,EAAS,QAAO,EAAc,MAAQ,GAC5C,CAAC,EAGD,IAAM,EAAe,MAAe,CAAC,EAAM,KAAK,OAAS,EAAc,KAAK,EACtE,EAAa,EAAS,CAAE,sBAAuB,CAAa,CAAC,EAC7D,YAAgB,YAAY,EAAM,MAAM,QACxC,EAAW,EAAiB,EAuBlC,OAfA,MAAgB,CACd,MAAY,CACV,IAAM,EAAQ,EAAS,MACjB,EAAQ,EAAM,MAAM,MAE1B,GAAI,CAAC,EAAO,OAIZ,IAAM,IAFS,EAAQ,EAAG,QAAQ,UAAU,EAAI,KAAA,EAC1B,cAA2B,gCAAgC,EAAM,GAAG,EAAA,EACpE,YAAY,cAA2B,cAAc,GAAK,KAEhF,EAAkB,EAAO,yBAA0B,EAAS,CAAC,CAAM,EAAI,CAAC,CAAC,CAC3E,CAAC,CACH,CAAC,EAEM,CAAI;;;;;eAKA,EAAS;cACV,QAAQ;2BACO,OAAO,CAAC,EAAS,KAAK,EAAE;iBACpC,EAAW;;UAElB,EACA,MACM,CAAI;;WAGZ,EAAE;;KAGR,EACA,OAAQ,CAAC,EAAoB,CAAM,CACrC,CAAC"}
1
+ {"version":3,"file":"tab-panel.js","names":[],"sources":["../src/disclosure/tab-panel/tab-panel.ts"],"sourcesContent":["import { bind, define, getHost, html, inject, onMounted, prop, ref, styleMap, watchEffect, when } from '@vielzeug/ore';\nimport { computed, signal } from '@vielzeug/ripple';\n\nimport { setAriaReflection } from '../../core';\nimport { reducedMotionMixin } from '../../styles';\nimport { TABS_CTX } from '../tabs/tabs';\nimport styles from './tab-panel.css?inline';\n\nconst TAB_PANEL_PADDING_PRESET: Record<string, string> = {\n '2xl': 'var(--size-12)',\n lg: 'var(--size-6)',\n md: 'var(--size-4)',\n none: '0',\n sm: 'var(--size-2)',\n xl: 'var(--size-8)',\n xs: 'var(--size-1)',\n};\n\nexport type OreTabPanelProps = {\n /** Active state (managed by ore-tabs) */\n active?: boolean;\n /** When true, the panel content is not rendered until first activation (preserves resources) */\n lazy?: boolean;\n /** Panel padding size: 'none' | 'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl' (default: 'md' = var(--size-4)) */\n padding?: 'none' | 'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl';\n /** Must match the `value` of its corresponding ore-tab-item */\n value: string;\n};\n\n/**\n * Content panel for a tab. Shown when its `value` matches the selected tab.\n *\n * @element ore-tab-panel\n *\n * @attr {string} value - Must match the corresponding ore-tab-item value\n * @attr {boolean} active - Toggled by the parent ore-tabs\n * @attr {string} padding - Panel padding: 'none' | 'xs' | 'sm' | 'md' (default) | 'lg' | 'xl' | '2xl'\n *\n * @slot - Panel content\n *\n * @cssprop --tab-panel-padding - Inner padding of the panel content area\n * @cssprop --tab-panel-font-size - Font size of the panel content\n * @part panel - Panel container.\n * @example\n * ```html\n * <ore-tab-panel value=\"overview\"><p>Overview content here</p></ore-tab-panel>\n * <ore-tab-panel value=\"settings\" padding=\"lg\"><p>Large padding</p></ore-tab-panel>\n * <ore-tab-panel value=\"code\" padding=\"none\"><pre>No padding for code</pre></ore-tab-panel>\n * ```\n */\nexport const TAB_PANEL_TAG = 'ore-tab-panel' as const;\ndefine<OreTabPanelProps>(TAB_PANEL_TAG, {\n props: {\n active: prop.bool(false),\n lazy: prop.bool(false),\n padding: prop.oneOf(['none', 'xs', 'sm', 'md', 'lg', 'xl', '2xl'] as const, 'md'),\n value: prop.string(''),\n },\n setup(props) {\n const el = getHost();\n const watch = watchEffect;\n\n const tabsCtx = inject(TABS_CTX);\n const isActive = computed(() =>\n tabsCtx ? !!tabsCtx.value.value && tabsCtx.value.value === props.value.value : props.active.value,\n );\n\n bind({\n attr: {\n active: () => (isActive.value ? true : undefined),\n },\n });\n\n // Map padding prop to CSS variable\n const paddingValue = computed(() => {\n const key = props.padding.value ?? 'md';\n\n return TAB_PANEL_PADDING_PRESET[key] ?? TAB_PANEL_PADDING_PRESET.md;\n });\n // Track whether the panel has ever been active (for lazy rendering)\n const hasBeenActive = signal(false);\n\n watch(() => {\n if (isActive.value) hasBeenActive.value = true;\n });\n\n // shouldRender: true if not lazy OR has been active at least once\n const shouldRender = computed(() => !props.lazy.value || hasBeenActive.value);\n const panelStyle = styleMap({ '--tab-panel-padding': paddingValue });\n const panelId = () => `tabpanel-${props.value.value}`;\n const panelRef = ref<HTMLElement>();\n\n // `aria-labelledby` as a plain IDREF attribute cannot resolve across shadow-tree boundaries\n // (the matching `id` lives inside <ore-tab-item>'s own shadow root): see\n // `setAriaReflection()`'s doc comment. Deferred to `onMounted()`: sibling custom elements\n // (including the peer `<ore-tab-item>`) connect in tree order within the same synchronous\n // insertion, so a sibling's shadow content may not exist yet during this element's own\n // `setup()`: `onMounted()`'s microtask runs after the whole subtree has connected.\n onMounted(() => {\n watch(() => {\n const panel = panelRef.value;\n const value = props.value.value;\n\n if (!panel) return;\n\n const tabsEl = value ? el.closest('ore-tabs') : null;\n const tabEl = tabsEl?.querySelector<HTMLElement>(`:scope > ore-tab-item[value=\"${value}\"]`);\n const button = tabEl?.shadowRoot?.querySelector<HTMLElement>('[role=\"tab\"]') ?? null;\n\n setAriaReflection(panel, 'ariaLabelledByElements', button ? [button] : []);\n });\n });\n\n return html`\n <div\n class=\"panel\"\n part=\"panel\"\n role=\"tabpanel\"\n ref=\"${panelRef}\"\n id=\"${panelId}\"\n aria-hidden=\"${() => String(!isActive.value)}\"\n style=\"${panelStyle}\"\n tabindex=\"0\">\n ${when(\n shouldRender,\n () => html`\n <slot></slot>\n `,\n )}\n </div>\n `;\n },\n styles: [reducedMotionMixin, styles],\n});\n"],"mappings":"2bAQA,IAAM,EAAmD,CACvD,MAAO,iBACP,GAAI,gBACJ,GAAI,gBACJ,KAAM,IACN,GAAI,gBACJ,GAAI,gBACJ,GAAI,eACN,EAkCa,EAAgB,gBAC7B,EAAyB,EAAe,CACtC,MAAO,CACL,OAAQ,EAAK,KAAK,EAAK,EACvB,KAAM,EAAK,KAAK,EAAK,EACrB,QAAS,EAAK,MAAM,CAAC,OAAQ,KAAM,KAAM,KAAM,KAAM,KAAM,KAAK,EAAY,IAAI,EAChF,MAAO,EAAK,OAAO,EAAE,CACvB,EACA,MAAM,EAAO,CACX,IAAM,EAAK,EAAQ,EACb,EAAQ,EAER,EAAU,EAAO,CAAQ,EACzB,EAAW,MACf,EAAU,CAAC,CAAC,EAAQ,MAAM,OAAS,EAAQ,MAAM,QAAU,EAAM,MAAM,MAAQ,EAAM,OAAO,KAC9F,EAEA,EAAK,CACH,KAAM,CACJ,WAAe,EAAS,MAAQ,GAAO,IAAA,EACzC,CACF,CAAC,EAGD,IAAM,EAAe,MAGZ,EAFK,EAAM,QAAQ,OAAS,OAEK,EAAyB,EAClE,EAEK,EAAgB,EAAO,EAAK,EAElC,MAAY,CACN,EAAS,QAAO,EAAc,MAAQ,GAC5C,CAAC,EAGD,IAAM,EAAe,MAAe,CAAC,EAAM,KAAK,OAAS,EAAc,KAAK,EACtE,EAAa,EAAS,CAAE,sBAAuB,CAAa,CAAC,EAC7D,YAAgB,YAAY,EAAM,MAAM,QACxC,EAAW,EAAiB,EAuBlC,OAfA,MAAgB,CACd,MAAY,CACV,IAAM,EAAQ,EAAS,MACjB,EAAQ,EAAM,MAAM,MAE1B,GAAI,CAAC,EAAO,OAIZ,IAAM,IAFS,EAAQ,EAAG,QAAQ,UAAU,EAAI,KAAA,EAC1B,cAA2B,gCAAgC,EAAM,GAAG,EAAA,EACpE,YAAY,cAA2B,cAAc,GAAK,KAEhF,EAAkB,EAAO,yBAA0B,EAAS,CAAC,CAAM,EAAI,CAAC,CAAC,CAC3E,CAAC,CACH,CAAC,EAEM,CAAI;;;;;eAKA,EAAS;cACV,QAAQ;2BACO,OAAO,CAAC,EAAS,KAAK,EAAE;iBACpC,EAAW;;UAElB,EACA,MACM,CAAI;;WAGZ,EAAE;;KAGR,EACA,OAAQ,CAAC,EAAoB,CAAM,CACrC,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"table.cjs","names":[],"sources":["../src/content/table/table.ts"],"sourcesContent":["import { bind, define, getHost, html, onMounted, prop, watchEffect } from '@vielzeug/ore';\n\nimport { reducedMotionMixin, tableBaseMixin } from '../../styles';\nimport componentStyles from './table.css?inline';\n\n/* ── Types ───────────────────────────────────────────────────────────────── */\n\n/** Table component properties */\nexport type OreTableProps = {\n /** Adds a thicker outer border */\n bordered?: boolean;\n /** Visible caption text — also used as the accessible table label via `aria-label` */\n caption?: string;\n /** Cell density: `'compact'` | `'cozy'` (default) | `'comfortable'` */\n density?: 'compact' | 'cozy' | 'comfortable';\n /** Expands the table to 100% of its container width */\n fullwidth?: boolean;\n /** Applies a busy/disabled state with reduced opacity */\n loading?: boolean;\n /** Enables sticky column headers with a vertical scroll container */\n sticky?: boolean;\n /** Alternating row stripe backgrounds */\n striped?: boolean;\n};\n\n/* ── Child element markers ───────────────────────────────────────────────── */\n// ore-tr, ore-th, ore-td are lightweight light-DOM markers.\n// ore-table reads them and constructs a fully-native shadow <table> so that\n// browser features that require real table elements (colspan/rowspan,\n// position:sticky on <thead>, table layout algorithm) all work correctly.\n// Attributes on ore-th/ore-td are mirrored to the generated native cells.\n\n/**\n * Light-DOM row marker consumed by `<ore-table>`.\n *\n * @element ore-tr\n * @attr {boolean} head - Places the row in the generated `<thead>` section\n * @attr {boolean} foot - Places the row in the generated `<tfoot>` section\n *\n * @example\n * ```html\n * <ore-table>\n * <ore-tr head><ore-th>Name</ore-th><ore-th>Role</ore-th></ore-tr>\n * <ore-tr><ore-td>Alice</ore-td><ore-td>Admin</ore-td></ore-tr>\n * </ore-table>\n * ```\n */\nif (!customElements.get('ore-tr')) customElements.define('ore-tr', class extends HTMLElement {});\n\n/**\n * Light-DOM header cell marker consumed by `<ore-table>`.\n *\n * @element ore-th\n * @attr {number} colspan - Mirrors to native `<th colspan>`\n * @attr {number} rowspan - Mirrors to native `<th rowspan>`\n * @attr {string} scope - Mirrors to native `<th scope>`: 'col' | 'row' | 'colgroup' | 'rowgroup'\n * @attr {string} headers - Mirrors to native `<th headers>`\n *\n * @example\n * ```html\n * <ore-tr head>\n * <ore-th scope=\"col\">Name</ore-th>\n * <ore-th scope=\"col\" colspan=\"2\">Address</ore-th>\n * </ore-tr>\n * ```\n */\nif (!customElements.get('ore-th')) customElements.define('ore-th', class extends HTMLElement {});\n\n/**\n * Light-DOM data cell marker consumed by `<ore-table>`.\n *\n * @element ore-td\n * @attr {number} colspan - Mirrors to native `<td colspan>`\n * @attr {number} rowspan - Mirrors to native `<td rowspan>`\n * @attr {string} headers - Mirrors to native `<td headers>`\n *\n * @example\n * ```html\n * <ore-tr>\n * <ore-td>Alice</ore-td>\n * <ore-td colspan=\"2\">123 Main St, Springfield</ore-td>\n * </ore-tr>\n * ```\n */\nif (!customElements.get('ore-td')) customElements.define('ore-td', class extends HTMLElement {});\n\n/* ── Proxy/mirror helpers ────────────────────────────────────────────────── */\n\n// Attributes forwarded from ore-th/ore-td to the generated native cell.\n// scope is intentionally excluded — it requires fallback logic and is handled separately.\nconst CELL_ATTRS = ['colspan', 'rowspan', 'headers', 'abbr'];\n\n/**\n * Sync text content and tracked attributes from a light-DOM marker to its\n * native mirror. `fallbackScope` is applied when the source element carries no\n * explicit `scope` attribute, ensuring the auto-inferred value is always\n * present and is restored if an explicit override is later removed.\n */\nfunction syncCell(source: Element, native: HTMLTableCellElement, fallbackScope?: string): void {\n if (source.childElementCount > 0) {\n // Source has element children — deep-clone them into the native cell so\n // components like ore-skeleton render correctly inside the shadow table.\n // Guard: skip re-clone if the serialised content is identical to avoid\n // redundant DOM work on every MutationObserver tick (e.g. 250+ cells\n // of skeleton loaders all cloning on each attribute change).\n const snapshot = source.innerHTML;\n\n if (native.getAttribute('data-src-html') === snapshot) return;\n\n native.setAttribute('data-src-html', snapshot);\n native.textContent = '';\n\n for (const child of source.childNodes) {\n native.appendChild(child.cloneNode(true));\n }\n } else {\n const text = source.textContent ?? '';\n\n if (native.textContent !== text) native.textContent = text;\n }\n\n for (const attr of CELL_ATTRS) {\n const val = source.getAttribute(attr);\n\n if (val !== null) native.setAttribute(attr, val);\n else native.removeAttribute(attr);\n }\n\n // scope: explicit attribute wins; otherwise restore the inferred fallback.\n const explicitScope = source.getAttribute('scope');\n\n if (explicitScope !== null) native.setAttribute('scope', explicitScope);\n else if (fallbackScope) native.scope = fallbackScope;\n else native.removeAttribute('scope');\n}\n\n/** Entry stored in the cell map: native mirror element + its inferred scope fallback. */\ntype CellEntry = { inferredScope: string | undefined; native: HTMLTableCellElement };\n\n/**\n * (Re)build the entire native shadow table from the current light-DOM markers.\n * Returns a WeakMap of source marker → CellEntry for targeted sync by the\n * content observer. Storing `inferredScope` per cell ensures that removing an\n * explicit `scope` attribute reverts to the auto-inferred value rather than\n * dropping it entirely.\n */\nfunction buildTable(\n host: HTMLElement,\n thead: HTMLTableSectionElement,\n tbody: HTMLTableSectionElement,\n tfoot: HTMLTableSectionElement,\n): WeakMap<Element, CellEntry> {\n const cellMap = new WeakMap<Element, CellEntry>();\n\n thead.textContent = '';\n tbody.textContent = '';\n tfoot.textContent = '';\n\n for (const child of host.children) {\n if (child.localName !== 'ore-tr') continue;\n\n const section = child.hasAttribute('head') ? thead : child.hasAttribute('foot') ? tfoot : tbody;\n const tr = document.createElement('tr');\n\n for (const cell of child.children) {\n if (cell.localName !== 'ore-th' && cell.localName !== 'ore-td') continue;\n\n const isHeader = cell.localName === 'ore-th';\n const native = document.createElement(isHeader ? 'th' : 'td');\n // Auto-infer scope for <th> elements; undefined for <td>.\n const inferredScope = isHeader ? (section === thead ? 'col' : 'row') : undefined;\n\n native.setAttribute('part', section === tbody ? 'cell' : 'header-cell');\n native.removeAttribute('data-src-html');\n syncCell(cell, native, inferredScope);\n cellMap.set(cell, { inferredScope, native });\n tr.appendChild(native);\n }\n\n section.appendChild(tr);\n }\n\n return cellMap;\n}\n\n/**\n * Data table component.\n *\n * Reads light-DOM `<ore-tr>`/`<ore-th>`/`<ore-td>` markers and projects them\n * into a fully-native shadow `<table>`. Cell attributes (`colspan`, `rowspan`,\n * `scope`, etc.) are mirrored. Changes are observed and synced incrementally.\n *\n * Native table features — sticky headers, colspan/rowspan, the table layout\n * algorithm — all work because the shadow tree contains real table elements.\n *\n * @element ore-table\n *\n * @attr {boolean} bordered - Thicker outer border\n * @attr {string} caption - Caption text shown above the table\n * @attr {boolean} fullwidth - Expands to 100% container width\n * @attr {boolean} loading - Busy state: reduced opacity, no pointer events\n * @attr {string} density - Cell density: 'compact' | 'cozy' | 'comfortable' (default: 'cozy')\n * @attr {boolean} sticky - Sticky `<thead>` with scroll container\n * @attr {boolean} striped - Alternating row backgrounds\n *\n * @part scroll - Scroll container that hosts the generated native table\n * @part table - Generated native `<table>` element\n * @part head - Generated native `<thead>` section\n * @part body - Generated native `<tbody>` section\n * @part foot - Generated native `<tfoot>` section\n * @part cell - Every native `<td>` in `<tbody>` rows\n * @part header-cell - Every native `<th>` / `<td>` in `<thead>` and `<tfoot>` rows\n *\n * @cssprop --table-bg - Table background color\n * @cssprop --table-border-color - Cell separator and outer border color\n * @cssprop --table-radius - Corner radius of the table container\n * @cssprop --table-shadow - Box shadow of the table container\n * @cssprop --table-header-bg - Background of header and footer rows\n * @cssprop --table-accent - Accent color for interactive states\n * @cssprop --table-row-hover-bg - Row hover background\n * @cssprop --table-stripe-bg - Even-row stripe background\n * @cssprop --table-cell-padding-x - Cell horizontal padding\n * @cssprop --table-cell-padding-y - Cell vertical padding\n * @cssprop --table-font-size - Base font size for cells\n * @cssprop --table-sticky-max-height - Max height of the sticky scroll container\n * @cssprop --table-sticky-header-bg - Background of sticky header cells\n * @cssprop --table-sticky-blur - Backdrop blur applied to sticky headers\n *\n * @example\n * ```html\n * <ore-table caption=\"Top repositories\" striped bordered sticky>\n * <ore-tr head>\n * <ore-th>Repository</ore-th>\n * <ore-th>Stars</ore-th>\n * </ore-tr>\n * <ore-tr>\n * <ore-td>vielzeug/refine</ore-td>\n * <ore-td>1 200</ore-td>\n * </ore-tr>\n * </ore-table>\n * ```\n */\nexport const TABLE_TAG = 'ore-table' as const;\ndefine<OreTableProps>(TABLE_TAG, {\n props: {\n bordered: prop.bool(false),\n caption: prop.string(),\n density: prop.string<'compact' | 'cozy' | 'comfortable'>(),\n fullwidth: prop.bool(false),\n loading: prop.bool(false),\n sticky: prop.bool(false),\n striped: prop.bool(false),\n },\n\n setup(props) {\n const el = getHost();\n const watch = watchEffect;\n\n bind({\n attr: {\n 'aria-busy': props.loading,\n 'aria-label': props.caption,\n },\n });\n\n // Build the native shadow table via DOM APIs (not innerHTML) to avoid\n // HTML-parser foster-parenting, which ejects table section elements from\n // their intended positions in the tree.\n onMounted(() => {\n const scrollContainer = el.shadowRoot?.querySelector('.scroll-container')!;\n\n const table = document.createElement('table');\n const captionEl = document.createElement('caption');\n const thead = document.createElement('thead');\n const tbody = document.createElement('tbody');\n const tfoot = document.createElement('tfoot');\n\n scrollContainer.setAttribute('part', 'scroll');\n table.setAttribute('part', 'table');\n thead.setAttribute('part', 'head');\n tbody.setAttribute('part', 'body');\n tfoot.setAttribute('part', 'foot');\n table.append(captionEl, thead, tbody, tfoot);\n scrollContainer.appendChild(table);\n\n // Reactively sync caption text and visibility from prop.\n watch(() => {\n const text = props.caption.value ?? '';\n\n captionEl.textContent = text;\n captionEl.hidden = text === '';\n });\n\n // Initial full build.\n let cellMap = buildTable(el, thead, tbody, tfoot);\n\n // Content observer: syncs text/attribute changes inside ore-th/ore-td.\n // Remains connected throughout the component lifetime — no\n // disconnect/reconnect during structural rebuilds. Records that arrive\n // for cells no longer in cellMap (after a rebuild) are silently ignored\n // by the `if (entry)` guard, so there is no correctness risk.\n const contentObserver = new MutationObserver((records) => {\n for (const rec of records) {\n const sourceCell = (rec.target instanceof Element ? rec.target : rec.target.parentElement)?.closest(\n 'ore-th, ore-td',\n );\n\n if (sourceCell) {\n const entry = cellMap.get(sourceCell);\n\n if (entry) syncCell(sourceCell, entry.native, entry.inferredScope);\n }\n }\n });\n\n contentObserver.observe(el, {\n // Include 'scope' in attributeFilter so explicit scope changes are picked\n // up and the fallback-restore logic in syncCell runs correctly.\n attributeFilter: [...CELL_ATTRS, 'scope'],\n attributes: true,\n characterData: true,\n childList: true,\n subtree: true,\n });\n\n // Structure observer: triggers a full rebuild when ore-tr elements are\n // added, removed, or reordered. Scoped to direct children only so it\n // never fires for cell-level mutations.\n const structureObserver = new MutationObserver(() => {\n cellMap = buildTable(el, thead, tbody, tfoot);\n });\n\n structureObserver.observe(el, { childList: true });\n\n return () => {\n structureObserver.disconnect();\n contentObserver.disconnect();\n };\n });\n\n return html`\n <div class=\"scroll-container\"></div>\n `;\n },\n\n styles: [reducedMotionMixin, tableBaseMixin('table'), componentStyles],\n});\n"],"mappings":"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"}
1
+ {"version":3,"file":"table.cjs","names":[],"sources":["../src/content/table/table.ts"],"sourcesContent":["import { bind, define, getHost, html, onMounted, prop, watchEffect } from '@vielzeug/ore';\n\nimport { reducedMotionMixin, tableBaseMixin } from '../../styles';\nimport componentStyles from './table.css?inline';\n\n/* ── Types ───────────────────────────────────────────────────────────────── */\n\n/** Table component properties */\nexport type OreTableProps = {\n /** Adds a thicker outer border */\n bordered?: boolean;\n /** Visible caption text: also used as the accessible table label via `aria-label` */\n caption?: string;\n /** Cell density: `'compact'` | `'cozy'` (default) | `'comfortable'` */\n density?: 'compact' | 'cozy' | 'comfortable';\n /** Expands the table to 100% of its container width */\n fullwidth?: boolean;\n /** Applies a busy/disabled state with reduced opacity */\n loading?: boolean;\n /** Enables sticky column headers with a vertical scroll container */\n sticky?: boolean;\n /** Alternating row stripe backgrounds */\n striped?: boolean;\n};\n\n/* ── Child element markers ───────────────────────────────────────────────── */\n// ore-tr, ore-th, ore-td are lightweight light-DOM markers.\n// ore-table reads them and constructs a fully-native shadow <table> so that\n// browser features that require real table elements (colspan/rowspan,\n// position:sticky on <thead>, table layout algorithm) all work correctly.\n// Attributes on ore-th/ore-td are mirrored to the generated native cells.\n\n/**\n * Light-DOM row marker consumed by `<ore-table>`.\n *\n * @element ore-tr\n * @attr {boolean} head - Places the row in the generated `<thead>` section\n * @attr {boolean} foot - Places the row in the generated `<tfoot>` section\n *\n * @example\n * ```html\n * <ore-table>\n * <ore-tr head><ore-th>Name</ore-th><ore-th>Role</ore-th></ore-tr>\n * <ore-tr><ore-td>Alice</ore-td><ore-td>Admin</ore-td></ore-tr>\n * </ore-table>\n * ```\n */\nif (!customElements.get('ore-tr')) customElements.define('ore-tr', class extends HTMLElement {});\n\n/**\n * Light-DOM header cell marker consumed by `<ore-table>`.\n *\n * @element ore-th\n * @attr {number} colspan - Mirrors to native `<th colspan>`\n * @attr {number} rowspan - Mirrors to native `<th rowspan>`\n * @attr {string} scope - Mirrors to native `<th scope>`: 'col' | 'row' | 'colgroup' | 'rowgroup'\n * @attr {string} headers - Mirrors to native `<th headers>`\n *\n * @example\n * ```html\n * <ore-tr head>\n * <ore-th scope=\"col\">Name</ore-th>\n * <ore-th scope=\"col\" colspan=\"2\">Address</ore-th>\n * </ore-tr>\n * ```\n */\nif (!customElements.get('ore-th')) customElements.define('ore-th', class extends HTMLElement {});\n\n/**\n * Light-DOM data cell marker consumed by `<ore-table>`.\n *\n * @element ore-td\n * @attr {number} colspan - Mirrors to native `<td colspan>`\n * @attr {number} rowspan - Mirrors to native `<td rowspan>`\n * @attr {string} headers - Mirrors to native `<td headers>`\n *\n * @example\n * ```html\n * <ore-tr>\n * <ore-td>Alice</ore-td>\n * <ore-td colspan=\"2\">123 Main St, Springfield</ore-td>\n * </ore-tr>\n * ```\n */\nif (!customElements.get('ore-td')) customElements.define('ore-td', class extends HTMLElement {});\n\n/* ── Proxy/mirror helpers ────────────────────────────────────────────────── */\n\n// Attributes forwarded from ore-th/ore-td to the generated native cell.\n// scope is intentionally excluded: it requires fallback logic and is handled separately.\nconst CELL_ATTRS = ['colspan', 'rowspan', 'headers', 'abbr'];\n\n/**\n * Sync text content and tracked attributes from a light-DOM marker to its\n * native mirror. `fallbackScope` is applied when the source element carries no\n * explicit `scope` attribute, ensuring the auto-inferred value is always\n * present and is restored if an explicit override is later removed.\n */\nfunction syncCell(source: Element, native: HTMLTableCellElement, fallbackScope?: string): void {\n if (source.childElementCount > 0) {\n // Source has element children: deep-clone them into the native cell so\n // components like ore-skeleton render correctly inside the shadow table.\n // Guard: skip re-clone if the serialised content is identical to avoid\n // redundant DOM work on every MutationObserver tick (e.g. 250+ cells\n // of skeleton loaders all cloning on each attribute change).\n const snapshot = source.innerHTML;\n\n if (native.getAttribute('data-src-html') === snapshot) return;\n\n native.setAttribute('data-src-html', snapshot);\n native.textContent = '';\n\n for (const child of source.childNodes) {\n native.appendChild(child.cloneNode(true));\n }\n } else {\n const text = source.textContent ?? '';\n\n if (native.textContent !== text) native.textContent = text;\n }\n\n for (const attr of CELL_ATTRS) {\n const val = source.getAttribute(attr);\n\n if (val !== null) native.setAttribute(attr, val);\n else native.removeAttribute(attr);\n }\n\n // scope: explicit attribute wins; otherwise restore the inferred fallback.\n const explicitScope = source.getAttribute('scope');\n\n if (explicitScope !== null) native.setAttribute('scope', explicitScope);\n else if (fallbackScope) native.scope = fallbackScope;\n else native.removeAttribute('scope');\n}\n\n/** Entry stored in the cell map: native mirror element + its inferred scope fallback. */\ntype CellEntry = { inferredScope: string | undefined; native: HTMLTableCellElement };\n\n/**\n * (Re)build the entire native shadow table from the current light-DOM markers.\n * Returns a WeakMap of source marker → CellEntry for targeted sync by the\n * content observer. Storing `inferredScope` per cell ensures that removing an\n * explicit `scope` attribute reverts to the auto-inferred value rather than\n * dropping it entirely.\n */\nfunction buildTable(\n host: HTMLElement,\n thead: HTMLTableSectionElement,\n tbody: HTMLTableSectionElement,\n tfoot: HTMLTableSectionElement,\n): WeakMap<Element, CellEntry> {\n const cellMap = new WeakMap<Element, CellEntry>();\n\n thead.textContent = '';\n tbody.textContent = '';\n tfoot.textContent = '';\n\n for (const child of host.children) {\n if (child.localName !== 'ore-tr') continue;\n\n const section = child.hasAttribute('head') ? thead : child.hasAttribute('foot') ? tfoot : tbody;\n const tr = document.createElement('tr');\n\n for (const cell of child.children) {\n if (cell.localName !== 'ore-th' && cell.localName !== 'ore-td') continue;\n\n const isHeader = cell.localName === 'ore-th';\n const native = document.createElement(isHeader ? 'th' : 'td');\n // Auto-infer scope for <th> elements; undefined for <td>.\n const inferredScope = isHeader ? (section === thead ? 'col' : 'row') : undefined;\n\n native.setAttribute('part', section === tbody ? 'cell' : 'header-cell');\n native.removeAttribute('data-src-html');\n syncCell(cell, native, inferredScope);\n cellMap.set(cell, { inferredScope, native });\n tr.appendChild(native);\n }\n\n section.appendChild(tr);\n }\n\n return cellMap;\n}\n\n/**\n * Data table component.\n *\n * Reads light-DOM `<ore-tr>`/`<ore-th>`/`<ore-td>` markers and projects them\n * into a fully-native shadow `<table>`. Cell attributes (`colspan`, `rowspan`,\n * `scope`, etc.) are mirrored. Changes are observed and synced incrementally.\n *\n * Native table features: sticky headers, colspan/rowspan, the table layout\n * algorithm: all work because the shadow tree contains real table elements.\n *\n * @element ore-table\n *\n * @attr {boolean} bordered - Thicker outer border\n * @attr {string} caption - Caption text shown above the table\n * @attr {boolean} fullwidth - Expands to 100% container width\n * @attr {boolean} loading - Busy state: reduced opacity, no pointer events\n * @attr {string} density - Cell density: 'compact' | 'cozy' | 'comfortable' (default: 'cozy')\n * @attr {boolean} sticky - Sticky `<thead>` with scroll container\n * @attr {boolean} striped - Alternating row backgrounds\n *\n * @part scroll - Scroll container that hosts the generated native table\n * @part table - Generated native `<table>` element\n * @part head - Generated native `<thead>` section\n * @part body - Generated native `<tbody>` section\n * @part foot - Generated native `<tfoot>` section\n * @part cell - Every native `<td>` in `<tbody>` rows\n * @part header-cell - Every native `<th>` / `<td>` in `<thead>` and `<tfoot>` rows\n *\n * @cssprop --table-bg - Table background color\n * @cssprop --table-border-color - Cell separator and outer border color\n * @cssprop --table-radius - Corner radius of the table container\n * @cssprop --table-shadow - Box shadow of the table container\n * @cssprop --table-header-bg - Background of header and footer rows\n * @cssprop --table-accent - Accent color for interactive states\n * @cssprop --table-row-hover-bg - Row hover background\n * @cssprop --table-stripe-bg - Even-row stripe background\n * @cssprop --table-cell-padding-x - Cell horizontal padding\n * @cssprop --table-cell-padding-y - Cell vertical padding\n * @cssprop --table-font-size - Base font size for cells\n * @cssprop --table-sticky-max-height - Max height of the sticky scroll container\n * @cssprop --table-sticky-header-bg - Background of sticky header cells\n * @cssprop --table-sticky-blur - Backdrop blur applied to sticky headers\n *\n * @example\n * ```html\n * <ore-table caption=\"Top repositories\" striped bordered sticky>\n * <ore-tr head>\n * <ore-th>Repository</ore-th>\n * <ore-th>Stars</ore-th>\n * </ore-tr>\n * <ore-tr>\n * <ore-td>vielzeug/refine</ore-td>\n * <ore-td>1 200</ore-td>\n * </ore-tr>\n * </ore-table>\n * ```\n */\nexport const TABLE_TAG = 'ore-table' as const;\ndefine<OreTableProps>(TABLE_TAG, {\n props: {\n bordered: prop.bool(false),\n caption: prop.string(),\n density: prop.string<'compact' | 'cozy' | 'comfortable'>(),\n fullwidth: prop.bool(false),\n loading: prop.bool(false),\n sticky: prop.bool(false),\n striped: prop.bool(false),\n },\n\n setup(props) {\n const el = getHost();\n const watch = watchEffect;\n\n bind({\n attr: {\n 'aria-busy': props.loading,\n 'aria-label': props.caption,\n },\n });\n\n // Build the native shadow table via DOM APIs (not innerHTML) to avoid\n // HTML-parser foster-parenting, which ejects table section elements from\n // their intended positions in the tree.\n onMounted(() => {\n const scrollContainer = el.shadowRoot?.querySelector('.scroll-container')!;\n\n const table = document.createElement('table');\n const captionEl = document.createElement('caption');\n const thead = document.createElement('thead');\n const tbody = document.createElement('tbody');\n const tfoot = document.createElement('tfoot');\n\n scrollContainer.setAttribute('part', 'scroll');\n table.setAttribute('part', 'table');\n thead.setAttribute('part', 'head');\n tbody.setAttribute('part', 'body');\n tfoot.setAttribute('part', 'foot');\n table.append(captionEl, thead, tbody, tfoot);\n scrollContainer.appendChild(table);\n\n // Reactively sync caption text and visibility from prop.\n watch(() => {\n const text = props.caption.value ?? '';\n\n captionEl.textContent = text;\n captionEl.hidden = text === '';\n });\n\n // Initial full build.\n let cellMap = buildTable(el, thead, tbody, tfoot);\n\n // Content observer: syncs text/attribute changes inside ore-th/ore-td.\n // Remains connected throughout the component lifetime: no\n // disconnect/reconnect during structural rebuilds. Records that arrive\n // for cells no longer in cellMap (after a rebuild) are silently ignored\n // by the `if (entry)` guard, so there is no correctness risk.\n const contentObserver = new MutationObserver((records) => {\n for (const rec of records) {\n const sourceCell = (rec.target instanceof Element ? rec.target : rec.target.parentElement)?.closest(\n 'ore-th, ore-td',\n );\n\n if (sourceCell) {\n const entry = cellMap.get(sourceCell);\n\n if (entry) syncCell(sourceCell, entry.native, entry.inferredScope);\n }\n }\n });\n\n contentObserver.observe(el, {\n // Include 'scope' in attributeFilter so explicit scope changes are picked\n // up and the fallback-restore logic in syncCell runs correctly.\n attributeFilter: [...CELL_ATTRS, 'scope'],\n attributes: true,\n characterData: true,\n childList: true,\n subtree: true,\n });\n\n // Structure observer: triggers a full rebuild when ore-tr elements are\n // added, removed, or reordered. Scoped to direct children only so it\n // never fires for cell-level mutations.\n const structureObserver = new MutationObserver(() => {\n cellMap = buildTable(el, thead, tbody, tfoot);\n });\n\n structureObserver.observe(el, { childList: true });\n\n return () => {\n structureObserver.disconnect();\n contentObserver.disconnect();\n };\n });\n\n return html`\n <div class=\"scroll-container\"></div>\n `;\n },\n\n styles: [reducedMotionMixin, tableBaseMixin('table'), componentStyles],\n});\n"],"mappings":"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"}
package/dist/table.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"table.js","names":[],"sources":["../src/content/table/table.ts"],"sourcesContent":["import { bind, define, getHost, html, onMounted, prop, watchEffect } from '@vielzeug/ore';\n\nimport { reducedMotionMixin, tableBaseMixin } from '../../styles';\nimport componentStyles from './table.css?inline';\n\n/* ── Types ───────────────────────────────────────────────────────────────── */\n\n/** Table component properties */\nexport type OreTableProps = {\n /** Adds a thicker outer border */\n bordered?: boolean;\n /** Visible caption text — also used as the accessible table label via `aria-label` */\n caption?: string;\n /** Cell density: `'compact'` | `'cozy'` (default) | `'comfortable'` */\n density?: 'compact' | 'cozy' | 'comfortable';\n /** Expands the table to 100% of its container width */\n fullwidth?: boolean;\n /** Applies a busy/disabled state with reduced opacity */\n loading?: boolean;\n /** Enables sticky column headers with a vertical scroll container */\n sticky?: boolean;\n /** Alternating row stripe backgrounds */\n striped?: boolean;\n};\n\n/* ── Child element markers ───────────────────────────────────────────────── */\n// ore-tr, ore-th, ore-td are lightweight light-DOM markers.\n// ore-table reads them and constructs a fully-native shadow <table> so that\n// browser features that require real table elements (colspan/rowspan,\n// position:sticky on <thead>, table layout algorithm) all work correctly.\n// Attributes on ore-th/ore-td are mirrored to the generated native cells.\n\n/**\n * Light-DOM row marker consumed by `<ore-table>`.\n *\n * @element ore-tr\n * @attr {boolean} head - Places the row in the generated `<thead>` section\n * @attr {boolean} foot - Places the row in the generated `<tfoot>` section\n *\n * @example\n * ```html\n * <ore-table>\n * <ore-tr head><ore-th>Name</ore-th><ore-th>Role</ore-th></ore-tr>\n * <ore-tr><ore-td>Alice</ore-td><ore-td>Admin</ore-td></ore-tr>\n * </ore-table>\n * ```\n */\nif (!customElements.get('ore-tr')) customElements.define('ore-tr', class extends HTMLElement {});\n\n/**\n * Light-DOM header cell marker consumed by `<ore-table>`.\n *\n * @element ore-th\n * @attr {number} colspan - Mirrors to native `<th colspan>`\n * @attr {number} rowspan - Mirrors to native `<th rowspan>`\n * @attr {string} scope - Mirrors to native `<th scope>`: 'col' | 'row' | 'colgroup' | 'rowgroup'\n * @attr {string} headers - Mirrors to native `<th headers>`\n *\n * @example\n * ```html\n * <ore-tr head>\n * <ore-th scope=\"col\">Name</ore-th>\n * <ore-th scope=\"col\" colspan=\"2\">Address</ore-th>\n * </ore-tr>\n * ```\n */\nif (!customElements.get('ore-th')) customElements.define('ore-th', class extends HTMLElement {});\n\n/**\n * Light-DOM data cell marker consumed by `<ore-table>`.\n *\n * @element ore-td\n * @attr {number} colspan - Mirrors to native `<td colspan>`\n * @attr {number} rowspan - Mirrors to native `<td rowspan>`\n * @attr {string} headers - Mirrors to native `<td headers>`\n *\n * @example\n * ```html\n * <ore-tr>\n * <ore-td>Alice</ore-td>\n * <ore-td colspan=\"2\">123 Main St, Springfield</ore-td>\n * </ore-tr>\n * ```\n */\nif (!customElements.get('ore-td')) customElements.define('ore-td', class extends HTMLElement {});\n\n/* ── Proxy/mirror helpers ────────────────────────────────────────────────── */\n\n// Attributes forwarded from ore-th/ore-td to the generated native cell.\n// scope is intentionally excluded — it requires fallback logic and is handled separately.\nconst CELL_ATTRS = ['colspan', 'rowspan', 'headers', 'abbr'];\n\n/**\n * Sync text content and tracked attributes from a light-DOM marker to its\n * native mirror. `fallbackScope` is applied when the source element carries no\n * explicit `scope` attribute, ensuring the auto-inferred value is always\n * present and is restored if an explicit override is later removed.\n */\nfunction syncCell(source: Element, native: HTMLTableCellElement, fallbackScope?: string): void {\n if (source.childElementCount > 0) {\n // Source has element children — deep-clone them into the native cell so\n // components like ore-skeleton render correctly inside the shadow table.\n // Guard: skip re-clone if the serialised content is identical to avoid\n // redundant DOM work on every MutationObserver tick (e.g. 250+ cells\n // of skeleton loaders all cloning on each attribute change).\n const snapshot = source.innerHTML;\n\n if (native.getAttribute('data-src-html') === snapshot) return;\n\n native.setAttribute('data-src-html', snapshot);\n native.textContent = '';\n\n for (const child of source.childNodes) {\n native.appendChild(child.cloneNode(true));\n }\n } else {\n const text = source.textContent ?? '';\n\n if (native.textContent !== text) native.textContent = text;\n }\n\n for (const attr of CELL_ATTRS) {\n const val = source.getAttribute(attr);\n\n if (val !== null) native.setAttribute(attr, val);\n else native.removeAttribute(attr);\n }\n\n // scope: explicit attribute wins; otherwise restore the inferred fallback.\n const explicitScope = source.getAttribute('scope');\n\n if (explicitScope !== null) native.setAttribute('scope', explicitScope);\n else if (fallbackScope) native.scope = fallbackScope;\n else native.removeAttribute('scope');\n}\n\n/** Entry stored in the cell map: native mirror element + its inferred scope fallback. */\ntype CellEntry = { inferredScope: string | undefined; native: HTMLTableCellElement };\n\n/**\n * (Re)build the entire native shadow table from the current light-DOM markers.\n * Returns a WeakMap of source marker → CellEntry for targeted sync by the\n * content observer. Storing `inferredScope` per cell ensures that removing an\n * explicit `scope` attribute reverts to the auto-inferred value rather than\n * dropping it entirely.\n */\nfunction buildTable(\n host: HTMLElement,\n thead: HTMLTableSectionElement,\n tbody: HTMLTableSectionElement,\n tfoot: HTMLTableSectionElement,\n): WeakMap<Element, CellEntry> {\n const cellMap = new WeakMap<Element, CellEntry>();\n\n thead.textContent = '';\n tbody.textContent = '';\n tfoot.textContent = '';\n\n for (const child of host.children) {\n if (child.localName !== 'ore-tr') continue;\n\n const section = child.hasAttribute('head') ? thead : child.hasAttribute('foot') ? tfoot : tbody;\n const tr = document.createElement('tr');\n\n for (const cell of child.children) {\n if (cell.localName !== 'ore-th' && cell.localName !== 'ore-td') continue;\n\n const isHeader = cell.localName === 'ore-th';\n const native = document.createElement(isHeader ? 'th' : 'td');\n // Auto-infer scope for <th> elements; undefined for <td>.\n const inferredScope = isHeader ? (section === thead ? 'col' : 'row') : undefined;\n\n native.setAttribute('part', section === tbody ? 'cell' : 'header-cell');\n native.removeAttribute('data-src-html');\n syncCell(cell, native, inferredScope);\n cellMap.set(cell, { inferredScope, native });\n tr.appendChild(native);\n }\n\n section.appendChild(tr);\n }\n\n return cellMap;\n}\n\n/**\n * Data table component.\n *\n * Reads light-DOM `<ore-tr>`/`<ore-th>`/`<ore-td>` markers and projects them\n * into a fully-native shadow `<table>`. Cell attributes (`colspan`, `rowspan`,\n * `scope`, etc.) are mirrored. Changes are observed and synced incrementally.\n *\n * Native table features — sticky headers, colspan/rowspan, the table layout\n * algorithm — all work because the shadow tree contains real table elements.\n *\n * @element ore-table\n *\n * @attr {boolean} bordered - Thicker outer border\n * @attr {string} caption - Caption text shown above the table\n * @attr {boolean} fullwidth - Expands to 100% container width\n * @attr {boolean} loading - Busy state: reduced opacity, no pointer events\n * @attr {string} density - Cell density: 'compact' | 'cozy' | 'comfortable' (default: 'cozy')\n * @attr {boolean} sticky - Sticky `<thead>` with scroll container\n * @attr {boolean} striped - Alternating row backgrounds\n *\n * @part scroll - Scroll container that hosts the generated native table\n * @part table - Generated native `<table>` element\n * @part head - Generated native `<thead>` section\n * @part body - Generated native `<tbody>` section\n * @part foot - Generated native `<tfoot>` section\n * @part cell - Every native `<td>` in `<tbody>` rows\n * @part header-cell - Every native `<th>` / `<td>` in `<thead>` and `<tfoot>` rows\n *\n * @cssprop --table-bg - Table background color\n * @cssprop --table-border-color - Cell separator and outer border color\n * @cssprop --table-radius - Corner radius of the table container\n * @cssprop --table-shadow - Box shadow of the table container\n * @cssprop --table-header-bg - Background of header and footer rows\n * @cssprop --table-accent - Accent color for interactive states\n * @cssprop --table-row-hover-bg - Row hover background\n * @cssprop --table-stripe-bg - Even-row stripe background\n * @cssprop --table-cell-padding-x - Cell horizontal padding\n * @cssprop --table-cell-padding-y - Cell vertical padding\n * @cssprop --table-font-size - Base font size for cells\n * @cssprop --table-sticky-max-height - Max height of the sticky scroll container\n * @cssprop --table-sticky-header-bg - Background of sticky header cells\n * @cssprop --table-sticky-blur - Backdrop blur applied to sticky headers\n *\n * @example\n * ```html\n * <ore-table caption=\"Top repositories\" striped bordered sticky>\n * <ore-tr head>\n * <ore-th>Repository</ore-th>\n * <ore-th>Stars</ore-th>\n * </ore-tr>\n * <ore-tr>\n * <ore-td>vielzeug/refine</ore-td>\n * <ore-td>1 200</ore-td>\n * </ore-tr>\n * </ore-table>\n * ```\n */\nexport const TABLE_TAG = 'ore-table' as const;\ndefine<OreTableProps>(TABLE_TAG, {\n props: {\n bordered: prop.bool(false),\n caption: prop.string(),\n density: prop.string<'compact' | 'cozy' | 'comfortable'>(),\n fullwidth: prop.bool(false),\n loading: prop.bool(false),\n sticky: prop.bool(false),\n striped: prop.bool(false),\n },\n\n setup(props) {\n const el = getHost();\n const watch = watchEffect;\n\n bind({\n attr: {\n 'aria-busy': props.loading,\n 'aria-label': props.caption,\n },\n });\n\n // Build the native shadow table via DOM APIs (not innerHTML) to avoid\n // HTML-parser foster-parenting, which ejects table section elements from\n // their intended positions in the tree.\n onMounted(() => {\n const scrollContainer = el.shadowRoot?.querySelector('.scroll-container')!;\n\n const table = document.createElement('table');\n const captionEl = document.createElement('caption');\n const thead = document.createElement('thead');\n const tbody = document.createElement('tbody');\n const tfoot = document.createElement('tfoot');\n\n scrollContainer.setAttribute('part', 'scroll');\n table.setAttribute('part', 'table');\n thead.setAttribute('part', 'head');\n tbody.setAttribute('part', 'body');\n tfoot.setAttribute('part', 'foot');\n table.append(captionEl, thead, tbody, tfoot);\n scrollContainer.appendChild(table);\n\n // Reactively sync caption text and visibility from prop.\n watch(() => {\n const text = props.caption.value ?? '';\n\n captionEl.textContent = text;\n captionEl.hidden = text === '';\n });\n\n // Initial full build.\n let cellMap = buildTable(el, thead, tbody, tfoot);\n\n // Content observer: syncs text/attribute changes inside ore-th/ore-td.\n // Remains connected throughout the component lifetime — no\n // disconnect/reconnect during structural rebuilds. Records that arrive\n // for cells no longer in cellMap (after a rebuild) are silently ignored\n // by the `if (entry)` guard, so there is no correctness risk.\n const contentObserver = new MutationObserver((records) => {\n for (const rec of records) {\n const sourceCell = (rec.target instanceof Element ? rec.target : rec.target.parentElement)?.closest(\n 'ore-th, ore-td',\n );\n\n if (sourceCell) {\n const entry = cellMap.get(sourceCell);\n\n if (entry) syncCell(sourceCell, entry.native, entry.inferredScope);\n }\n }\n });\n\n contentObserver.observe(el, {\n // Include 'scope' in attributeFilter so explicit scope changes are picked\n // up and the fallback-restore logic in syncCell runs correctly.\n attributeFilter: [...CELL_ATTRS, 'scope'],\n attributes: true,\n characterData: true,\n childList: true,\n subtree: true,\n });\n\n // Structure observer: triggers a full rebuild when ore-tr elements are\n // added, removed, or reordered. Scoped to direct children only so it\n // never fires for cell-level mutations.\n const structureObserver = new MutationObserver(() => {\n cellMap = buildTable(el, thead, tbody, tfoot);\n });\n\n structureObserver.observe(el, { childList: true });\n\n return () => {\n structureObserver.disconnect();\n contentObserver.disconnect();\n };\n });\n\n return html`\n <div class=\"scroll-container\"></div>\n `;\n },\n\n styles: [reducedMotionMixin, tableBaseMixin('table'), componentStyles],\n});\n"],"mappings":"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"}
1
+ {"version":3,"file":"table.js","names":[],"sources":["../src/content/table/table.ts"],"sourcesContent":["import { bind, define, getHost, html, onMounted, prop, watchEffect } from '@vielzeug/ore';\n\nimport { reducedMotionMixin, tableBaseMixin } from '../../styles';\nimport componentStyles from './table.css?inline';\n\n/* ── Types ───────────────────────────────────────────────────────────────── */\n\n/** Table component properties */\nexport type OreTableProps = {\n /** Adds a thicker outer border */\n bordered?: boolean;\n /** Visible caption text: also used as the accessible table label via `aria-label` */\n caption?: string;\n /** Cell density: `'compact'` | `'cozy'` (default) | `'comfortable'` */\n density?: 'compact' | 'cozy' | 'comfortable';\n /** Expands the table to 100% of its container width */\n fullwidth?: boolean;\n /** Applies a busy/disabled state with reduced opacity */\n loading?: boolean;\n /** Enables sticky column headers with a vertical scroll container */\n sticky?: boolean;\n /** Alternating row stripe backgrounds */\n striped?: boolean;\n};\n\n/* ── Child element markers ───────────────────────────────────────────────── */\n// ore-tr, ore-th, ore-td are lightweight light-DOM markers.\n// ore-table reads them and constructs a fully-native shadow <table> so that\n// browser features that require real table elements (colspan/rowspan,\n// position:sticky on <thead>, table layout algorithm) all work correctly.\n// Attributes on ore-th/ore-td are mirrored to the generated native cells.\n\n/**\n * Light-DOM row marker consumed by `<ore-table>`.\n *\n * @element ore-tr\n * @attr {boolean} head - Places the row in the generated `<thead>` section\n * @attr {boolean} foot - Places the row in the generated `<tfoot>` section\n *\n * @example\n * ```html\n * <ore-table>\n * <ore-tr head><ore-th>Name</ore-th><ore-th>Role</ore-th></ore-tr>\n * <ore-tr><ore-td>Alice</ore-td><ore-td>Admin</ore-td></ore-tr>\n * </ore-table>\n * ```\n */\nif (!customElements.get('ore-tr')) customElements.define('ore-tr', class extends HTMLElement {});\n\n/**\n * Light-DOM header cell marker consumed by `<ore-table>`.\n *\n * @element ore-th\n * @attr {number} colspan - Mirrors to native `<th colspan>`\n * @attr {number} rowspan - Mirrors to native `<th rowspan>`\n * @attr {string} scope - Mirrors to native `<th scope>`: 'col' | 'row' | 'colgroup' | 'rowgroup'\n * @attr {string} headers - Mirrors to native `<th headers>`\n *\n * @example\n * ```html\n * <ore-tr head>\n * <ore-th scope=\"col\">Name</ore-th>\n * <ore-th scope=\"col\" colspan=\"2\">Address</ore-th>\n * </ore-tr>\n * ```\n */\nif (!customElements.get('ore-th')) customElements.define('ore-th', class extends HTMLElement {});\n\n/**\n * Light-DOM data cell marker consumed by `<ore-table>`.\n *\n * @element ore-td\n * @attr {number} colspan - Mirrors to native `<td colspan>`\n * @attr {number} rowspan - Mirrors to native `<td rowspan>`\n * @attr {string} headers - Mirrors to native `<td headers>`\n *\n * @example\n * ```html\n * <ore-tr>\n * <ore-td>Alice</ore-td>\n * <ore-td colspan=\"2\">123 Main St, Springfield</ore-td>\n * </ore-tr>\n * ```\n */\nif (!customElements.get('ore-td')) customElements.define('ore-td', class extends HTMLElement {});\n\n/* ── Proxy/mirror helpers ────────────────────────────────────────────────── */\n\n// Attributes forwarded from ore-th/ore-td to the generated native cell.\n// scope is intentionally excluded: it requires fallback logic and is handled separately.\nconst CELL_ATTRS = ['colspan', 'rowspan', 'headers', 'abbr'];\n\n/**\n * Sync text content and tracked attributes from a light-DOM marker to its\n * native mirror. `fallbackScope` is applied when the source element carries no\n * explicit `scope` attribute, ensuring the auto-inferred value is always\n * present and is restored if an explicit override is later removed.\n */\nfunction syncCell(source: Element, native: HTMLTableCellElement, fallbackScope?: string): void {\n if (source.childElementCount > 0) {\n // Source has element children: deep-clone them into the native cell so\n // components like ore-skeleton render correctly inside the shadow table.\n // Guard: skip re-clone if the serialised content is identical to avoid\n // redundant DOM work on every MutationObserver tick (e.g. 250+ cells\n // of skeleton loaders all cloning on each attribute change).\n const snapshot = source.innerHTML;\n\n if (native.getAttribute('data-src-html') === snapshot) return;\n\n native.setAttribute('data-src-html', snapshot);\n native.textContent = '';\n\n for (const child of source.childNodes) {\n native.appendChild(child.cloneNode(true));\n }\n } else {\n const text = source.textContent ?? '';\n\n if (native.textContent !== text) native.textContent = text;\n }\n\n for (const attr of CELL_ATTRS) {\n const val = source.getAttribute(attr);\n\n if (val !== null) native.setAttribute(attr, val);\n else native.removeAttribute(attr);\n }\n\n // scope: explicit attribute wins; otherwise restore the inferred fallback.\n const explicitScope = source.getAttribute('scope');\n\n if (explicitScope !== null) native.setAttribute('scope', explicitScope);\n else if (fallbackScope) native.scope = fallbackScope;\n else native.removeAttribute('scope');\n}\n\n/** Entry stored in the cell map: native mirror element + its inferred scope fallback. */\ntype CellEntry = { inferredScope: string | undefined; native: HTMLTableCellElement };\n\n/**\n * (Re)build the entire native shadow table from the current light-DOM markers.\n * Returns a WeakMap of source marker → CellEntry for targeted sync by the\n * content observer. Storing `inferredScope` per cell ensures that removing an\n * explicit `scope` attribute reverts to the auto-inferred value rather than\n * dropping it entirely.\n */\nfunction buildTable(\n host: HTMLElement,\n thead: HTMLTableSectionElement,\n tbody: HTMLTableSectionElement,\n tfoot: HTMLTableSectionElement,\n): WeakMap<Element, CellEntry> {\n const cellMap = new WeakMap<Element, CellEntry>();\n\n thead.textContent = '';\n tbody.textContent = '';\n tfoot.textContent = '';\n\n for (const child of host.children) {\n if (child.localName !== 'ore-tr') continue;\n\n const section = child.hasAttribute('head') ? thead : child.hasAttribute('foot') ? tfoot : tbody;\n const tr = document.createElement('tr');\n\n for (const cell of child.children) {\n if (cell.localName !== 'ore-th' && cell.localName !== 'ore-td') continue;\n\n const isHeader = cell.localName === 'ore-th';\n const native = document.createElement(isHeader ? 'th' : 'td');\n // Auto-infer scope for <th> elements; undefined for <td>.\n const inferredScope = isHeader ? (section === thead ? 'col' : 'row') : undefined;\n\n native.setAttribute('part', section === tbody ? 'cell' : 'header-cell');\n native.removeAttribute('data-src-html');\n syncCell(cell, native, inferredScope);\n cellMap.set(cell, { inferredScope, native });\n tr.appendChild(native);\n }\n\n section.appendChild(tr);\n }\n\n return cellMap;\n}\n\n/**\n * Data table component.\n *\n * Reads light-DOM `<ore-tr>`/`<ore-th>`/`<ore-td>` markers and projects them\n * into a fully-native shadow `<table>`. Cell attributes (`colspan`, `rowspan`,\n * `scope`, etc.) are mirrored. Changes are observed and synced incrementally.\n *\n * Native table features: sticky headers, colspan/rowspan, the table layout\n * algorithm: all work because the shadow tree contains real table elements.\n *\n * @element ore-table\n *\n * @attr {boolean} bordered - Thicker outer border\n * @attr {string} caption - Caption text shown above the table\n * @attr {boolean} fullwidth - Expands to 100% container width\n * @attr {boolean} loading - Busy state: reduced opacity, no pointer events\n * @attr {string} density - Cell density: 'compact' | 'cozy' | 'comfortable' (default: 'cozy')\n * @attr {boolean} sticky - Sticky `<thead>` with scroll container\n * @attr {boolean} striped - Alternating row backgrounds\n *\n * @part scroll - Scroll container that hosts the generated native table\n * @part table - Generated native `<table>` element\n * @part head - Generated native `<thead>` section\n * @part body - Generated native `<tbody>` section\n * @part foot - Generated native `<tfoot>` section\n * @part cell - Every native `<td>` in `<tbody>` rows\n * @part header-cell - Every native `<th>` / `<td>` in `<thead>` and `<tfoot>` rows\n *\n * @cssprop --table-bg - Table background color\n * @cssprop --table-border-color - Cell separator and outer border color\n * @cssprop --table-radius - Corner radius of the table container\n * @cssprop --table-shadow - Box shadow of the table container\n * @cssprop --table-header-bg - Background of header and footer rows\n * @cssprop --table-accent - Accent color for interactive states\n * @cssprop --table-row-hover-bg - Row hover background\n * @cssprop --table-stripe-bg - Even-row stripe background\n * @cssprop --table-cell-padding-x - Cell horizontal padding\n * @cssprop --table-cell-padding-y - Cell vertical padding\n * @cssprop --table-font-size - Base font size for cells\n * @cssprop --table-sticky-max-height - Max height of the sticky scroll container\n * @cssprop --table-sticky-header-bg - Background of sticky header cells\n * @cssprop --table-sticky-blur - Backdrop blur applied to sticky headers\n *\n * @example\n * ```html\n * <ore-table caption=\"Top repositories\" striped bordered sticky>\n * <ore-tr head>\n * <ore-th>Repository</ore-th>\n * <ore-th>Stars</ore-th>\n * </ore-tr>\n * <ore-tr>\n * <ore-td>vielzeug/refine</ore-td>\n * <ore-td>1 200</ore-td>\n * </ore-tr>\n * </ore-table>\n * ```\n */\nexport const TABLE_TAG = 'ore-table' as const;\ndefine<OreTableProps>(TABLE_TAG, {\n props: {\n bordered: prop.bool(false),\n caption: prop.string(),\n density: prop.string<'compact' | 'cozy' | 'comfortable'>(),\n fullwidth: prop.bool(false),\n loading: prop.bool(false),\n sticky: prop.bool(false),\n striped: prop.bool(false),\n },\n\n setup(props) {\n const el = getHost();\n const watch = watchEffect;\n\n bind({\n attr: {\n 'aria-busy': props.loading,\n 'aria-label': props.caption,\n },\n });\n\n // Build the native shadow table via DOM APIs (not innerHTML) to avoid\n // HTML-parser foster-parenting, which ejects table section elements from\n // their intended positions in the tree.\n onMounted(() => {\n const scrollContainer = el.shadowRoot?.querySelector('.scroll-container')!;\n\n const table = document.createElement('table');\n const captionEl = document.createElement('caption');\n const thead = document.createElement('thead');\n const tbody = document.createElement('tbody');\n const tfoot = document.createElement('tfoot');\n\n scrollContainer.setAttribute('part', 'scroll');\n table.setAttribute('part', 'table');\n thead.setAttribute('part', 'head');\n tbody.setAttribute('part', 'body');\n tfoot.setAttribute('part', 'foot');\n table.append(captionEl, thead, tbody, tfoot);\n scrollContainer.appendChild(table);\n\n // Reactively sync caption text and visibility from prop.\n watch(() => {\n const text = props.caption.value ?? '';\n\n captionEl.textContent = text;\n captionEl.hidden = text === '';\n });\n\n // Initial full build.\n let cellMap = buildTable(el, thead, tbody, tfoot);\n\n // Content observer: syncs text/attribute changes inside ore-th/ore-td.\n // Remains connected throughout the component lifetime: no\n // disconnect/reconnect during structural rebuilds. Records that arrive\n // for cells no longer in cellMap (after a rebuild) are silently ignored\n // by the `if (entry)` guard, so there is no correctness risk.\n const contentObserver = new MutationObserver((records) => {\n for (const rec of records) {\n const sourceCell = (rec.target instanceof Element ? rec.target : rec.target.parentElement)?.closest(\n 'ore-th, ore-td',\n );\n\n if (sourceCell) {\n const entry = cellMap.get(sourceCell);\n\n if (entry) syncCell(sourceCell, entry.native, entry.inferredScope);\n }\n }\n });\n\n contentObserver.observe(el, {\n // Include 'scope' in attributeFilter so explicit scope changes are picked\n // up and the fallback-restore logic in syncCell runs correctly.\n attributeFilter: [...CELL_ATTRS, 'scope'],\n attributes: true,\n characterData: true,\n childList: true,\n subtree: true,\n });\n\n // Structure observer: triggers a full rebuild when ore-tr elements are\n // added, removed, or reordered. Scoped to direct children only so it\n // never fires for cell-level mutations.\n const structureObserver = new MutationObserver(() => {\n cellMap = buildTable(el, thead, tbody, tfoot);\n });\n\n structureObserver.observe(el, { childList: true });\n\n return () => {\n structureObserver.disconnect();\n contentObserver.disconnect();\n };\n });\n\n return html`\n <div class=\"scroll-container\"></div>\n `;\n },\n\n styles: [reducedMotionMixin, tableBaseMixin('table'), componentStyles],\n});\n"],"mappings":"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"}
package/dist/text.cjs.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"text.cjs","names":[],"sources":["../src/content/text/text.ts"],"sourcesContent":["import { bind, define, html, prop } from '@vielzeug/ore';\n\nimport styles from './text.css?inline';\n\n/** Text component properties */\nexport type OreTextProps = {\n /** Text alignment */\n align?: 'left' | 'center' | 'right' | 'justify';\n /** Semantic HTML element to render as — sets the correct ARIA role/level on the host */\n as?: 'span' | 'p' | 'div' | 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6' | 'label' | 'code';\n /** Text color (semantic + theme colors) */\n color?:\n | 'primary'\n | 'secondary'\n | 'info'\n | 'success'\n | 'warning'\n | 'error'\n | 'heading'\n | 'body'\n | 'muted'\n | 'tertiary'\n | 'disabled'\n | 'contrast';\n /** Italic text style */\n italic?: boolean;\n /** Clamp text to N lines with an ellipsis (multi-line truncation) */\n lines?: number;\n /** Text size — maps to --text-* tokens for body variants and --heading-* tokens for the heading variant */\n size?: '2xs' | 'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl';\n /** Enable single-line text truncation with ellipsis */\n truncate?: boolean;\n /** Text semantic variant */\n variant?: 'body' | 'heading' | 'label' | 'caption' | 'overline' | 'code';\n /** Font weight */\n weight?: 'normal' | 'medium' | 'semibold' | 'bold';\n};\n\n/**\n * A typography component with semantic variants and responsive sizing.\n *\n * @element ore-text\n *\n * @attr {string} variant - Text variant: 'body' | 'heading' | 'label' | 'caption' | 'overline' | 'code'\n * @attr {string} size - Font size: 'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl'. Maps to --text-* tokens for body variants and --heading-* tokens for the heading variant.\n * @attr {string} weight - Font weight: 'normal' | 'medium' | 'semibold' | 'bold'\n * @attr {string} color - Text color: 'primary' | 'secondary' | 'info' | 'success' | 'warning' | 'error' | 'heading' | 'body' | 'muted' | 'tertiary' | 'disabled' | 'contrast'\n * @attr {string} align - Text alignment: 'left' | 'center' | 'right' | 'justify'\n * @attr {boolean} truncate - Truncate text with ellipsis when it overflows (single-line)\n * @attr {number} lines - Clamp to N lines with ellipsis (multi-line truncation)\n * @attr {boolean} italic - Italic text style\n * @attr {string} as - Semantic HTML element: 'span' | 'p' | 'div' | 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6' | 'label' | 'code'\n *\n * @slot - Text content\n *\n * @cssprop --text-size - Font size\n * @cssprop --text-weight - Font weight\n * @cssprop --text-color - Text color\n * @cssprop --text-line-height - Line height\n * @cssprop --text-letter-spacing - Letter spacing\n *\n * @example\n * ```html\n * <ore-text variant=\"heading\" size=\"2xl\" weight=\"bold\">Welcome</ore-text>\n * <ore-text as=\"h2\" variant=\"heading\" size=\"xl\">Section title</ore-text>\n * <ore-text color=\"primary\" weight=\"semibold\">Important notice</ore-text>\n * <ore-text variant=\"code\">npm install</ore-text>\n * <ore-text lines=\"2\">Long paragraph that clamps at two lines…</ore-text>\n * ```\n */\n\nexport const TEXT_TAG = 'ore-text' as const;\ndefine<OreTextProps>(TEXT_TAG, {\n props: {\n align: prop.string<'left' | 'center' | 'right' | 'justify'>(),\n as: prop.string<'span' | 'p' | 'div' | 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6' | 'label' | 'code'>(),\n color: prop.string<\n | 'primary'\n | 'secondary'\n | 'info'\n | 'success'\n | 'warning'\n | 'error'\n | 'heading'\n | 'body'\n | 'muted'\n | 'tertiary'\n | 'disabled'\n | 'contrast'\n >(),\n italic: prop.bool(),\n lines: prop.number(),\n size: prop.string<'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl'>(),\n truncate: prop.bool(),\n variant: prop.string<'body' | 'heading' | 'label' | 'caption' | 'overline' | 'code'>(),\n weight: prop.string<'normal' | 'medium' | 'semibold' | 'bold'>(),\n },\n setup(props) {\n bind({\n attr: {\n 'aria-level': () => {\n const match = /^h([1-6])$/.exec((props.as.value as string) ?? '');\n\n return match ? match[1] : null;\n },\n role: () => (/^h([1-6])$/.test((props.as.value as string) ?? '') ? 'heading' : null),\n },\n style: {\n '--_lines': () => (props.lines.value != null ? String(props.lines.value) : null),\n },\n });\n\n return html`\n <slot></slot>\n `;\n },\n styles: [styles],\n});\n"],"mappings":"iJAuEA,IAAa,EAAW,YACxB,EAAA,EAAA,OAAA,CAAqB,EAAU,CAC7B,MAAO,CACL,MAAO,EAAA,KAAK,OAAgD,EAC5D,GAAI,EAAA,KAAK,OAA0F,EACnG,MAAO,EAAA,KAAK,OAaV,EACF,OAAQ,EAAA,KAAK,KAAK,EAClB,MAAO,EAAA,KAAK,OAAO,EACnB,KAAM,EAAA,KAAK,OAAiD,EAC5D,SAAU,EAAA,KAAK,KAAK,EACpB,QAAS,EAAA,KAAK,OAAuE,EACrF,OAAQ,EAAA,KAAK,OAAkD,CACjE,EACA,MAAM,EAAO,CAeX,OAdA,EAAA,EAAA,KAAA,CAAK,CACH,KAAM,CACJ,iBAAoB,CAClB,IAAM,EAAQ,aAAa,KAAM,EAAM,GAAG,OAAoB,EAAE,EAEhE,OAAO,EAAQ,EAAM,GAAK,IAC5B,EACA,SAAa,aAAa,KAAM,EAAM,GAAG,OAAoB,EAAE,EAAI,UAAY,IACjF,EACA,MAAO,CACL,eAAmB,EAAM,MAAM,OAAS,KAAmC,KAA5B,OAAO,EAAM,MAAM,KAAK,CACzE,CACF,CAAC,EAEM,EAAA,IAAI;;KAGb,EACA,OAAQ,CAAC,EAAA,OAAM,CACjB,CAAC"}
1
+ {"version":3,"file":"text.cjs","names":[],"sources":["../src/content/text/text.ts"],"sourcesContent":["import { bind, define, html, prop } from '@vielzeug/ore';\n\nimport styles from './text.css?inline';\n\n/** Text component properties */\nexport type OreTextProps = {\n /** Text alignment */\n align?: 'left' | 'center' | 'right' | 'justify';\n /** Semantic HTML element to render as: sets the correct ARIA role/level on the host */\n as?: 'span' | 'p' | 'div' | 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6' | 'label' | 'code';\n /** Text color (semantic + theme colors) */\n color?:\n | 'primary'\n | 'secondary'\n | 'info'\n | 'success'\n | 'warning'\n | 'error'\n | 'heading'\n | 'body'\n | 'muted'\n | 'tertiary'\n | 'disabled'\n | 'contrast';\n /** Italic text style */\n italic?: boolean;\n /** Clamp text to N lines with an ellipsis (multi-line truncation) */\n lines?: number;\n /** Text size: maps to --text-* tokens for body variants and --heading-* tokens for the heading variant */\n size?: '2xs' | 'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl';\n /** Enable single-line text truncation with ellipsis */\n truncate?: boolean;\n /** Text semantic variant */\n variant?: 'body' | 'heading' | 'label' | 'caption' | 'overline' | 'code';\n /** Font weight */\n weight?: 'normal' | 'medium' | 'semibold' | 'bold';\n};\n\n/**\n * A typography component with semantic variants and responsive sizing.\n *\n * @element ore-text\n *\n * @attr {string} variant - Text variant: 'body' | 'heading' | 'label' | 'caption' | 'overline' | 'code'\n * @attr {string} size - Font size: 'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl'. Maps to --text-* tokens for body variants and --heading-* tokens for the heading variant.\n * @attr {string} weight - Font weight: 'normal' | 'medium' | 'semibold' | 'bold'\n * @attr {string} color - Text color: 'primary' | 'secondary' | 'info' | 'success' | 'warning' | 'error' | 'heading' | 'body' | 'muted' | 'tertiary' | 'disabled' | 'contrast'\n * @attr {string} align - Text alignment: 'left' | 'center' | 'right' | 'justify'\n * @attr {boolean} truncate - Truncate text with ellipsis when it overflows (single-line)\n * @attr {number} lines - Clamp to N lines with ellipsis (multi-line truncation)\n * @attr {boolean} italic - Italic text style\n * @attr {string} as - Semantic HTML element: 'span' | 'p' | 'div' | 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6' | 'label' | 'code'\n *\n * @slot - Text content\n *\n * @cssprop --text-size - Font size\n * @cssprop --text-weight - Font weight\n * @cssprop --text-color - Text color\n * @cssprop --text-line-height - Line height\n * @cssprop --text-letter-spacing - Letter spacing\n *\n * @example\n * ```html\n * <ore-text variant=\"heading\" size=\"2xl\" weight=\"bold\">Welcome</ore-text>\n * <ore-text as=\"h2\" variant=\"heading\" size=\"xl\">Section title</ore-text>\n * <ore-text color=\"primary\" weight=\"semibold\">Important notice</ore-text>\n * <ore-text variant=\"code\">npm install</ore-text>\n * <ore-text lines=\"2\">Long paragraph that clamps at two lines…</ore-text>\n * ```\n */\n\nexport const TEXT_TAG = 'ore-text' as const;\ndefine<OreTextProps>(TEXT_TAG, {\n props: {\n align: prop.string<'left' | 'center' | 'right' | 'justify'>(),\n as: prop.string<'span' | 'p' | 'div' | 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6' | 'label' | 'code'>(),\n color: prop.string<\n | 'primary'\n | 'secondary'\n | 'info'\n | 'success'\n | 'warning'\n | 'error'\n | 'heading'\n | 'body'\n | 'muted'\n | 'tertiary'\n | 'disabled'\n | 'contrast'\n >(),\n italic: prop.bool(),\n lines: prop.number(),\n size: prop.string<'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl'>(),\n truncate: prop.bool(),\n variant: prop.string<'body' | 'heading' | 'label' | 'caption' | 'overline' | 'code'>(),\n weight: prop.string<'normal' | 'medium' | 'semibold' | 'bold'>(),\n },\n setup(props) {\n bind({\n attr: {\n 'aria-level': () => {\n const match = /^h([1-6])$/.exec((props.as.value as string) ?? '');\n\n return match ? match[1] : null;\n },\n role: () => (/^h([1-6])$/.test((props.as.value as string) ?? '') ? 'heading' : null),\n },\n style: {\n '--_lines': () => (props.lines.value != null ? String(props.lines.value) : null),\n },\n });\n\n return html`\n <slot></slot>\n `;\n },\n styles: [styles],\n});\n"],"mappings":"iJAuEA,IAAa,EAAW,YACxB,EAAA,EAAA,OAAA,CAAqB,EAAU,CAC7B,MAAO,CACL,MAAO,EAAA,KAAK,OAAgD,EAC5D,GAAI,EAAA,KAAK,OAA0F,EACnG,MAAO,EAAA,KAAK,OAaV,EACF,OAAQ,EAAA,KAAK,KAAK,EAClB,MAAO,EAAA,KAAK,OAAO,EACnB,KAAM,EAAA,KAAK,OAAiD,EAC5D,SAAU,EAAA,KAAK,KAAK,EACpB,QAAS,EAAA,KAAK,OAAuE,EACrF,OAAQ,EAAA,KAAK,OAAkD,CACjE,EACA,MAAM,EAAO,CAeX,OAdA,EAAA,EAAA,KAAA,CAAK,CACH,KAAM,CACJ,iBAAoB,CAClB,IAAM,EAAQ,aAAa,KAAM,EAAM,GAAG,OAAoB,EAAE,EAEhE,OAAO,EAAQ,EAAM,GAAK,IAC5B,EACA,SAAa,aAAa,KAAM,EAAM,GAAG,OAAoB,EAAE,EAAI,UAAY,IACjF,EACA,MAAO,CACL,eAAmB,EAAM,MAAM,OAAS,KAAmC,KAA5B,OAAO,EAAM,MAAM,KAAK,CACzE,CACF,CAAC,EAEM,EAAA,IAAI;;KAGb,EACA,OAAQ,CAAC,EAAA,OAAM,CACjB,CAAC"}
package/dist/text.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"text.js","names":[],"sources":["../src/content/text/text.ts"],"sourcesContent":["import { bind, define, html, prop } from '@vielzeug/ore';\n\nimport styles from './text.css?inline';\n\n/** Text component properties */\nexport type OreTextProps = {\n /** Text alignment */\n align?: 'left' | 'center' | 'right' | 'justify';\n /** Semantic HTML element to render as — sets the correct ARIA role/level on the host */\n as?: 'span' | 'p' | 'div' | 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6' | 'label' | 'code';\n /** Text color (semantic + theme colors) */\n color?:\n | 'primary'\n | 'secondary'\n | 'info'\n | 'success'\n | 'warning'\n | 'error'\n | 'heading'\n | 'body'\n | 'muted'\n | 'tertiary'\n | 'disabled'\n | 'contrast';\n /** Italic text style */\n italic?: boolean;\n /** Clamp text to N lines with an ellipsis (multi-line truncation) */\n lines?: number;\n /** Text size — maps to --text-* tokens for body variants and --heading-* tokens for the heading variant */\n size?: '2xs' | 'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl';\n /** Enable single-line text truncation with ellipsis */\n truncate?: boolean;\n /** Text semantic variant */\n variant?: 'body' | 'heading' | 'label' | 'caption' | 'overline' | 'code';\n /** Font weight */\n weight?: 'normal' | 'medium' | 'semibold' | 'bold';\n};\n\n/**\n * A typography component with semantic variants and responsive sizing.\n *\n * @element ore-text\n *\n * @attr {string} variant - Text variant: 'body' | 'heading' | 'label' | 'caption' | 'overline' | 'code'\n * @attr {string} size - Font size: 'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl'. Maps to --text-* tokens for body variants and --heading-* tokens for the heading variant.\n * @attr {string} weight - Font weight: 'normal' | 'medium' | 'semibold' | 'bold'\n * @attr {string} color - Text color: 'primary' | 'secondary' | 'info' | 'success' | 'warning' | 'error' | 'heading' | 'body' | 'muted' | 'tertiary' | 'disabled' | 'contrast'\n * @attr {string} align - Text alignment: 'left' | 'center' | 'right' | 'justify'\n * @attr {boolean} truncate - Truncate text with ellipsis when it overflows (single-line)\n * @attr {number} lines - Clamp to N lines with ellipsis (multi-line truncation)\n * @attr {boolean} italic - Italic text style\n * @attr {string} as - Semantic HTML element: 'span' | 'p' | 'div' | 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6' | 'label' | 'code'\n *\n * @slot - Text content\n *\n * @cssprop --text-size - Font size\n * @cssprop --text-weight - Font weight\n * @cssprop --text-color - Text color\n * @cssprop --text-line-height - Line height\n * @cssprop --text-letter-spacing - Letter spacing\n *\n * @example\n * ```html\n * <ore-text variant=\"heading\" size=\"2xl\" weight=\"bold\">Welcome</ore-text>\n * <ore-text as=\"h2\" variant=\"heading\" size=\"xl\">Section title</ore-text>\n * <ore-text color=\"primary\" weight=\"semibold\">Important notice</ore-text>\n * <ore-text variant=\"code\">npm install</ore-text>\n * <ore-text lines=\"2\">Long paragraph that clamps at two lines…</ore-text>\n * ```\n */\n\nexport const TEXT_TAG = 'ore-text' as const;\ndefine<OreTextProps>(TEXT_TAG, {\n props: {\n align: prop.string<'left' | 'center' | 'right' | 'justify'>(),\n as: prop.string<'span' | 'p' | 'div' | 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6' | 'label' | 'code'>(),\n color: prop.string<\n | 'primary'\n | 'secondary'\n | 'info'\n | 'success'\n | 'warning'\n | 'error'\n | 'heading'\n | 'body'\n | 'muted'\n | 'tertiary'\n | 'disabled'\n | 'contrast'\n >(),\n italic: prop.bool(),\n lines: prop.number(),\n size: prop.string<'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl'>(),\n truncate: prop.bool(),\n variant: prop.string<'body' | 'heading' | 'label' | 'caption' | 'overline' | 'code'>(),\n weight: prop.string<'normal' | 'medium' | 'semibold' | 'bold'>(),\n },\n setup(props) {\n bind({\n attr: {\n 'aria-level': () => {\n const match = /^h([1-6])$/.exec((props.as.value as string) ?? '');\n\n return match ? match[1] : null;\n },\n role: () => (/^h([1-6])$/.test((props.as.value as string) ?? '') ? 'heading' : null),\n },\n style: {\n '--_lines': () => (props.lines.value != null ? String(props.lines.value) : null),\n },\n });\n\n return html`\n <slot></slot>\n `;\n },\n styles: [styles],\n});\n"],"mappings":"+GAuEA,IAAa,EAAW,WACxB,EAAqB,EAAU,CAC7B,MAAO,CACL,MAAO,EAAK,OAAgD,EAC5D,GAAI,EAAK,OAA0F,EACnG,MAAO,EAAK,OAaV,EACF,OAAQ,EAAK,KAAK,EAClB,MAAO,EAAK,OAAO,EACnB,KAAM,EAAK,OAAiD,EAC5D,SAAU,EAAK,KAAK,EACpB,QAAS,EAAK,OAAuE,EACrF,OAAQ,EAAK,OAAkD,CACjE,EACA,MAAM,EAAO,CAeX,OAdA,EAAK,CACH,KAAM,CACJ,iBAAoB,CAClB,IAAM,EAAQ,aAAa,KAAM,EAAM,GAAG,OAAoB,EAAE,EAEhE,OAAO,EAAQ,EAAM,GAAK,IAC5B,EACA,SAAa,aAAa,KAAM,EAAM,GAAG,OAAoB,EAAE,EAAI,UAAY,IACjF,EACA,MAAO,CACL,eAAmB,EAAM,MAAM,OAAS,KAAmC,KAA5B,OAAO,EAAM,MAAM,KAAK,CACzE,CACF,CAAC,EAEM,CAAI;;KAGb,EACA,OAAQ,CAAC,CAAM,CACjB,CAAC"}
1
+ {"version":3,"file":"text.js","names":[],"sources":["../src/content/text/text.ts"],"sourcesContent":["import { bind, define, html, prop } from '@vielzeug/ore';\n\nimport styles from './text.css?inline';\n\n/** Text component properties */\nexport type OreTextProps = {\n /** Text alignment */\n align?: 'left' | 'center' | 'right' | 'justify';\n /** Semantic HTML element to render as: sets the correct ARIA role/level on the host */\n as?: 'span' | 'p' | 'div' | 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6' | 'label' | 'code';\n /** Text color (semantic + theme colors) */\n color?:\n | 'primary'\n | 'secondary'\n | 'info'\n | 'success'\n | 'warning'\n | 'error'\n | 'heading'\n | 'body'\n | 'muted'\n | 'tertiary'\n | 'disabled'\n | 'contrast';\n /** Italic text style */\n italic?: boolean;\n /** Clamp text to N lines with an ellipsis (multi-line truncation) */\n lines?: number;\n /** Text size: maps to --text-* tokens for body variants and --heading-* tokens for the heading variant */\n size?: '2xs' | 'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl';\n /** Enable single-line text truncation with ellipsis */\n truncate?: boolean;\n /** Text semantic variant */\n variant?: 'body' | 'heading' | 'label' | 'caption' | 'overline' | 'code';\n /** Font weight */\n weight?: 'normal' | 'medium' | 'semibold' | 'bold';\n};\n\n/**\n * A typography component with semantic variants and responsive sizing.\n *\n * @element ore-text\n *\n * @attr {string} variant - Text variant: 'body' | 'heading' | 'label' | 'caption' | 'overline' | 'code'\n * @attr {string} size - Font size: 'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl'. Maps to --text-* tokens for body variants and --heading-* tokens for the heading variant.\n * @attr {string} weight - Font weight: 'normal' | 'medium' | 'semibold' | 'bold'\n * @attr {string} color - Text color: 'primary' | 'secondary' | 'info' | 'success' | 'warning' | 'error' | 'heading' | 'body' | 'muted' | 'tertiary' | 'disabled' | 'contrast'\n * @attr {string} align - Text alignment: 'left' | 'center' | 'right' | 'justify'\n * @attr {boolean} truncate - Truncate text with ellipsis when it overflows (single-line)\n * @attr {number} lines - Clamp to N lines with ellipsis (multi-line truncation)\n * @attr {boolean} italic - Italic text style\n * @attr {string} as - Semantic HTML element: 'span' | 'p' | 'div' | 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6' | 'label' | 'code'\n *\n * @slot - Text content\n *\n * @cssprop --text-size - Font size\n * @cssprop --text-weight - Font weight\n * @cssprop --text-color - Text color\n * @cssprop --text-line-height - Line height\n * @cssprop --text-letter-spacing - Letter spacing\n *\n * @example\n * ```html\n * <ore-text variant=\"heading\" size=\"2xl\" weight=\"bold\">Welcome</ore-text>\n * <ore-text as=\"h2\" variant=\"heading\" size=\"xl\">Section title</ore-text>\n * <ore-text color=\"primary\" weight=\"semibold\">Important notice</ore-text>\n * <ore-text variant=\"code\">npm install</ore-text>\n * <ore-text lines=\"2\">Long paragraph that clamps at two lines…</ore-text>\n * ```\n */\n\nexport const TEXT_TAG = 'ore-text' as const;\ndefine<OreTextProps>(TEXT_TAG, {\n props: {\n align: prop.string<'left' | 'center' | 'right' | 'justify'>(),\n as: prop.string<'span' | 'p' | 'div' | 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6' | 'label' | 'code'>(),\n color: prop.string<\n | 'primary'\n | 'secondary'\n | 'info'\n | 'success'\n | 'warning'\n | 'error'\n | 'heading'\n | 'body'\n | 'muted'\n | 'tertiary'\n | 'disabled'\n | 'contrast'\n >(),\n italic: prop.bool(),\n lines: prop.number(),\n size: prop.string<'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl'>(),\n truncate: prop.bool(),\n variant: prop.string<'body' | 'heading' | 'label' | 'caption' | 'overline' | 'code'>(),\n weight: prop.string<'normal' | 'medium' | 'semibold' | 'bold'>(),\n },\n setup(props) {\n bind({\n attr: {\n 'aria-level': () => {\n const match = /^h([1-6])$/.exec((props.as.value as string) ?? '');\n\n return match ? match[1] : null;\n },\n role: () => (/^h([1-6])$/.test((props.as.value as string) ?? '') ? 'heading' : null),\n },\n style: {\n '--_lines': () => (props.lines.value != null ? String(props.lines.value) : null),\n },\n });\n\n return html`\n <slot></slot>\n `;\n },\n styles: [styles],\n});\n"],"mappings":"+GAuEA,IAAa,EAAW,WACxB,EAAqB,EAAU,CAC7B,MAAO,CACL,MAAO,EAAK,OAAgD,EAC5D,GAAI,EAAK,OAA0F,EACnG,MAAO,EAAK,OAaV,EACF,OAAQ,EAAK,KAAK,EAClB,MAAO,EAAK,OAAO,EACnB,KAAM,EAAK,OAAiD,EAC5D,SAAU,EAAK,KAAK,EACpB,QAAS,EAAK,OAAuE,EACrF,OAAQ,EAAK,OAAkD,CACjE,EACA,MAAM,EAAO,CAeX,OAdA,EAAK,CACH,KAAM,CACJ,iBAAoB,CAClB,IAAM,EAAQ,aAAa,KAAM,EAAM,GAAG,OAAoB,EAAE,EAEhE,OAAO,EAAQ,EAAM,GAAK,IAC5B,EACA,SAAa,aAAa,KAAM,EAAM,GAAG,OAAoB,EAAE,EAAI,UAAY,IACjF,EACA,MAAO,CACL,eAAmB,EAAM,MAAM,OAAS,KAAmC,KAA5B,OAAO,EAAM,MAAM,KAAK,CACzE,CACF,CAAC,EAEM,CAAI;;KAGb,EACA,OAAQ,CAAC,CAAM,CACjB,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"textarea.cjs","names":[],"sources":["../src/inputs/textarea/textarea.ts"],"sourcesContent":["import {\n bind,\n define,\n getHost,\n html,\n live,\n onCleanup,\n onElement,\n prop,\n ref,\n useField,\n watchEffect,\n} from '@vielzeug/ore';\nimport { computed } from '@vielzeug/ripple';\nimport { bindRefCallback, createAutoResize, createTextField, lifecycleSignal } from '../../core';\nimport type { TextFieldProps } from '../../shared';\nimport { disablableBundle, roundableBundle, sizableBundle, TEXTAREA_SIZE_PRESET, themableBundle } from '../../shared';\nimport {\n coarsePointerMixin,\n colorThemeMixin,\n disabledLoadingMixin,\n fieldVariantMixin,\n forcedColorsFocusMixin,\n reducedMotionMixin,\n roundedVariantMixin,\n sizeVariantMixin,\n} from '../../styles';\nimport type { VisualVariant } from '../../types';\nimport { errorAttr } from '../shared/field-binding';\nimport { defineFieldValue, dispatchNativeFieldEvent, setFieldValue } from '../shared/native-field-event';\nimport { renderFieldStatusRegion, renderStatusIcon } from '../shared/templates';\nimport componentStyles from './textarea.css?inline';\n\nexport { ICON_TAG } from '../../content/icon/icon';\n/** Textarea component properties */\n\nexport type OreTextareaEvents = {\n change: Event;\n input: InputEvent;\n};\n\nexport type OreTextareaProps = TextFieldProps<Exclude<VisualVariant, 'frost' | 'text'>> & {\n /** Allow auto-grow with content */\n 'auto-resize'?: boolean;\n /**\n * Shows an inline spinner inside the field and forces the inner `<textarea>` into\n * `disabled` for the duration — use while an async validation/submission request\n * is in flight to prevent double-submits.\n */\n loading?: boolean;\n /** Maximum character count; shows a counter when set */\n maxlength?: number;\n /** Disable a manual resize handle */\n 'no-resize'?: boolean;\n /**\n * JS-only callback fired with the inner `<textarea>` element when it mounts,\n * and with `null` when it unmounts. Intended for composed components that\n * need imperative access to the raw element.\n * Set as a JS property: `bitTextarea.ref = (el) => { ... }`.\n */\n ref?: ((el: HTMLTextAreaElement | null) => void) | null;\n /** Resize direction override */\n resize?: 'none' | 'horizontal' | 'both' | 'vertical';\n /** Number of visible text rows */\n rows?: number;\n};\n\n/**\n * A multi-line text input with label, helper text, character counter, and auto-resize.\n *\n * @element ore-textarea\n *\n * @attr {string} label - Label text\n * @attr {string} label-placement - 'inset' | 'outside'\n * @attr {string} value - Current value\n * @attr {string} placeholder - Placeholder text\n * @attr {string} name - Form field name\n * @attr {number} rows - Visible row count\n * @attr {number} maxlength - Max character count (shows counter)\n * @attr {string} helper - Helper text below the textarea\n * @attr {string} error - Error message\n * @attr {boolean} disabled - Disable interaction\n * @attr {boolean} readonly - Read-only mode\n * @attr {boolean} required - Required field\n * @attr {boolean} no-resize - Disable manual resize\n * @attr {boolean} auto-resize - Grow with content\n * @attr {boolean} loading - Show an inline spinner and force the field disabled\n * @attr {boolean} success - Show an inline success check icon (suppressed while `error` is set)\n * @attr {string} resize - Resize direction: 'none' | 'horizontal' | 'both' | 'vertical'\n * @attr {string} color - Theme color: 'primary' | 'secondary' | 'info' | 'success' | 'warning' | 'error'\n * @attr {string} variant - Visual variant: 'solid' | 'flat' | 'bordered' | 'outline' | 'ghost'\n * @attr {string} size - Component size: 'sm' | 'md' | 'lg'\n * @attr {string} rounded - Border radius: 'none' | 'sm' | 'md' | 'lg' | 'xl' | '2xl' | '3xl' | 'full'\n *\n * @fires input - Fired on every keystroke with current value.\n * @fires change - Fired on blur with changed value.\n *\n * @slot helper - Complex helper content\n *\n * @part status-icon - The inline error/success icon shown inside the field\n * @part spinner - The inline loading spinner shown inside the field while `loading`\n *\n * @cssprop --textarea-bg - Background color\n * @cssprop --textarea-border-color - Border color\n * @cssprop --textarea-placeholder-color - Placeholder text color\n * @cssprop --textarea-radius - Border radius\n * @cssprop --textarea-padding - Inner padding (block inline)\n * @cssprop --textarea-gap - Gap between label and field\n * @cssprop --textarea-font-size - Font size\n * @cssprop --textarea-min-height - Minimum field height\n * @cssprop --textarea-max-height - Maximum field height (none = unlimited)\n * @cssprop --textarea-resize - CSS resize direction ('vertical' | 'horizontal' | 'both' | 'none')\n * @cssprop --textarea-hover-bg - Field background on hover (flat/ghost variants)\n * @cssprop --textarea-hover-border-color - Field border on hover (flat/bordered variants)\n * @cssprop --textarea-focus-bg - Field background when focused (flat variant)\n * @cssprop --textarea-focus-border-color - Field border when focused (flat variant)\n *\n * @part wrapper - Outer wrapper element.\n * @part label - Label element.\n * @part field - Field container.\n * @part textarea - The native `<textarea>` element.\n * @part helper - The helper text element.\n * @part error - The error text element (`role=\"alert\"`).\n *\n * @example\n * ```html\n * <ore-textarea></ore-textarea>\n * <ore-textarea label=\"Bio\" success></ore-textarea>\n * <ore-textarea label=\"Bio\" loading></ore-textarea>\n * ```\n */\nexport const TEXTAREA_TAG = 'ore-textarea' as const;\ndefine<OreTextareaProps>(TEXTAREA_TAG, {\n formAssociated: true,\n props: {\n ...themableBundle,\n ...sizableBundle,\n ...disablableBundle,\n ...roundableBundle,\n 'auto-resize': prop.bool(false),\n error: prop.string(),\n fullwidth: prop.bool(false),\n helper: prop.string(),\n label: prop.string(),\n 'label-placement': prop.oneOf(['inset', 'outside'] as const, 'inset'),\n loading: prop.bool(false),\n maxlength: prop.json(undefined as number | undefined),\n name: prop.string(),\n 'no-resize': prop.bool(false),\n placeholder: prop.string(),\n readonly: prop.bool(false),\n ref: prop.data<((el: HTMLTextAreaElement | null) => void) | null>(),\n required: prop.bool(false),\n resize: prop.string<'none' | 'both' | 'horizontal' | 'vertical'>(),\n rows: prop.json(undefined as number | undefined),\n success: prop.bool(false),\n value: prop.string(),\n variant: prop.string<'flat' | 'solid' | 'bordered' | 'outline' | 'ghost'>(),\n },\n setup(props) {\n const el = getHost();\n const watch = watchEffect;\n\n const textareaRef = ref<HTMLTextAreaElement>();\n const autoResize = createAutoResize({ enabled: props['auto-resize'] });\n // `loading` behaves like a temporary `disabled` — see ore-input's identical computation.\n const isDisabled = computed(() => props.disabled.value || props.loading.value);\n\n const abortSignal = lifecycleSignal(onCleanup);\n const tf = createTextField({\n disabled: isDisabled,\n error: props.error,\n helper: props.helper,\n label: props.label,\n labelPlacement: props['label-placement'],\n maxLength: props.maxlength,\n onChange: (_event: Event, value: string) => {\n setFieldValue(el, value);\n dispatchNativeFieldEvent(el, 'change');\n },\n onInput: (_event: Event, value: string) => {\n setFieldValue(el, value);\n dispatchNativeFieldEvent(el, 'input');\n },\n prefix: 'textarea',\n readonly: props.readonly,\n required: props.required,\n signal: abortSignal,\n value: props.value,\n });\n\n defineFieldValue(\n el,\n () => tf.value.value,\n (value) => {\n tf.value.value = value;\n },\n );\n\n tf.attachFormField(\n useField<string>({\n disabled: tf.disabled,\n onReset: () => {\n tf.reset();\n requestAnimationFrame(() => autoResize.recompute());\n },\n toFormValue: (v) => v,\n validationMessage: tf.validationMessage,\n validity: tf.validity,\n value: tf.value,\n }),\n );\n\n const {\n ariaDescribedBy,\n ariaErrorMessage,\n ariaInvalid,\n ariaLabelledBy,\n assistiveId,\n counter,\n errorId,\n errorText,\n fieldId: textareaId,\n helperText,\n labelId,\n labelVisible,\n } = tf;\n\n onElement(textareaRef, (textareaEl) => {\n const unwireEl = tf.wire(textareaEl);\n const unwireAutoResize = autoResize.wire(textareaEl);\n const unwireRef = bindRefCallback(props.ref, textareaEl);\n\n const stopLayoutEffect = watch(() => {\n textareaEl.style.resize =\n props['auto-resize'].value || props['no-resize'].value ? 'none' : props.resize.value || 'vertical';\n\n // Deferred a frame: on mount (or right after `auto-resize` flips true) the browser\n // hasn't necessarily finished laying out the textarea yet, so `scrollHeight` read\n // synchronously here could be stale.\n requestAnimationFrame(() => autoResize.recompute());\n });\n\n return () => {\n unwireRef();\n unwireEl();\n unwireAutoResize();\n stopLayoutEffect();\n };\n });\n\n bind({\n attr: {\n error: errorAttr(errorText),\n size: props.size,\n // Reflects `success` only once `error` is confirmed empty — keeps the two host\n // attributes mutually exclusive even if a consumer sets both props at once.\n success: () => (props.success.value && !errorText.value ? true : undefined),\n variant: props.variant,\n },\n });\n\n return html`\n <div class=\"textarea-wrapper\" part=\"wrapper\">\n <label class=\"label\" part=\"label\" for=\"${textareaId}\" id=\"${labelId}\" ?hidden=\"${() => !labelVisible.value}\">\n ${props.label}\n </label>\n <div class=\"field\" part=\"field\">\n <textarea\n part=\"textarea\"\n ref=\"${textareaRef}\"\n id=\"${textareaId}\"\n name=\"${props.name}\"\n placeholder=\"${props.placeholder}\"\n rows=\"${props.rows}\"\n maxlength=\"${props.maxlength}\"\n ?disabled=\"${isDisabled}\"\n ?readonly=\"${props.readonly}\"\n ?required=\"${props.required}\"\n value=\"${live(tf.value)}\"\n aria-describedby=\"${ariaDescribedBy}\"\n aria-errormessage=\"${ariaErrorMessage}\"\n aria-invalid=\"${ariaInvalid}\"\n aria-labelledby=\"${ariaLabelledBy}\"\n aria-busy=\"${() => (props.loading.value ? 'true' : null)}\"></textarea>\n ${renderStatusIcon(errorText)}\n <span class=\"field-spinner\" part=\"spinner\" role=\"status\" aria-label=\"Loading\"></span>\n </div>\n ${renderFieldStatusRegion({ assistiveId, counter, errorId, errorText, helperText })}\n </div>\n `;\n },\n shadow: { delegatesFocus: true },\n styles: [\n colorThemeMixin,\n coarsePointerMixin,\n reducedMotionMixin,\n roundedVariantMixin,\n disabledLoadingMixin,\n sizeVariantMixin(TEXTAREA_SIZE_PRESET),\n forcedColorsFocusMixin('textarea'),\n componentStyles,\n // Must come after `componentStyles` — see `ore-input`'s identical ordering note for why\n // (`@layer` precedence is fixed by which layer name is *first* referenced across this whole\n // array; `componentStyles` establishes `refine.base`, which this mixin's `refine.variants`\n // rules need to win over).\n fieldVariantMixin({ container: '.field', text: 'textarea', tokenPrefix: 'textarea' }),\n ],\n});\n"],"mappings":"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"}
1
+ {"version":3,"file":"textarea.cjs","names":[],"sources":["../src/inputs/textarea/textarea.ts"],"sourcesContent":["import {\n bind,\n define,\n getHost,\n html,\n live,\n onCleanup,\n onElement,\n prop,\n ref,\n useField,\n watchEffect,\n} from '@vielzeug/ore';\nimport { computed } from '@vielzeug/ripple';\nimport { bindRefCallback, createAutoResize, createTextField, lifecycleSignal } from '../../core';\nimport type { TextFieldProps } from '../../shared';\nimport { disablableBundle, roundableBundle, sizableBundle, TEXTAREA_SIZE_PRESET, themableBundle } from '../../shared';\nimport {\n coarsePointerMixin,\n colorThemeMixin,\n disabledLoadingMixin,\n fieldVariantMixin,\n forcedColorsFocusMixin,\n reducedMotionMixin,\n roundedVariantMixin,\n sizeVariantMixin,\n} from '../../styles';\nimport type { VisualVariant } from '../../types';\nimport { errorAttr } from '../shared/field-binding';\nimport { defineFieldValue, dispatchNativeFieldEvent, setFieldValue } from '../shared/native-field-event';\nimport { renderFieldStatusRegion, renderStatusIcon } from '../shared/templates';\nimport componentStyles from './textarea.css?inline';\n\nexport { ICON_TAG } from '../../content/icon/icon';\n/** Textarea component properties */\n\nexport type OreTextareaEvents = {\n change: Event;\n input: InputEvent;\n};\n\nexport type OreTextareaProps = TextFieldProps<Exclude<VisualVariant, 'frost' | 'text'>> & {\n /** Allow auto-grow with content */\n 'auto-resize'?: boolean;\n /**\n * Shows an inline spinner inside the field and forces the inner `<textarea>` into\n * `disabled` for the duration: use while an async validation/submission request\n * is in flight to prevent double-submits.\n */\n loading?: boolean;\n /** Maximum character count; shows a counter when set */\n maxlength?: number;\n /** Disable a manual resize handle */\n 'no-resize'?: boolean;\n /**\n * JS-only callback fired with the inner `<textarea>` element when it mounts,\n * and with `null` when it unmounts. Intended for composed components that\n * need imperative access to the raw element.\n * Set as a JS property: `bitTextarea.ref = (el) => { ... }`.\n */\n ref?: ((el: HTMLTextAreaElement | null) => void) | null;\n /** Resize direction override */\n resize?: 'none' | 'horizontal' | 'both' | 'vertical';\n /** Number of visible text rows */\n rows?: number;\n};\n\n/**\n * A multi-line text input with label, helper text, character counter, and auto-resize.\n *\n * @element ore-textarea\n *\n * @attr {string} label - Label text\n * @attr {string} label-placement - 'inset' | 'outside'\n * @attr {string} value - Current value\n * @attr {string} placeholder - Placeholder text\n * @attr {string} name - Form field name\n * @attr {number} rows - Visible row count\n * @attr {number} maxlength - Max character count (shows counter)\n * @attr {string} helper - Helper text below the textarea\n * @attr {string} error - Error message\n * @attr {boolean} disabled - Disable interaction\n * @attr {boolean} readonly - Read-only mode\n * @attr {boolean} required - Required field\n * @attr {boolean} no-resize - Disable manual resize\n * @attr {boolean} auto-resize - Grow with content\n * @attr {boolean} loading - Show an inline spinner and force the field disabled\n * @attr {boolean} success - Show an inline success check icon (suppressed while `error` is set)\n * @attr {string} resize - Resize direction: 'none' | 'horizontal' | 'both' | 'vertical'\n * @attr {string} color - Theme color: 'primary' | 'secondary' | 'info' | 'success' | 'warning' | 'error'\n * @attr {string} variant - Visual variant: 'solid' | 'flat' | 'bordered' | 'outline' | 'ghost'\n * @attr {string} size - Component size: 'sm' | 'md' | 'lg'\n * @attr {string} rounded - Border radius: 'none' | 'sm' | 'md' | 'lg' | 'xl' | '2xl' | '3xl' | 'full'\n *\n * @fires input - Fired on every keystroke with current value.\n * @fires change - Fired on blur with changed value.\n *\n * @slot helper - Complex helper content\n *\n * @part status-icon - The inline error/success icon shown inside the field\n * @part spinner - The inline loading spinner shown inside the field while `loading`\n *\n * @cssprop --textarea-bg - Background color\n * @cssprop --textarea-border-color - Border color\n * @cssprop --textarea-placeholder-color - Placeholder text color\n * @cssprop --textarea-radius - Border radius\n * @cssprop --textarea-padding - Inner padding (block inline)\n * @cssprop --textarea-gap - Gap between label and field\n * @cssprop --textarea-font-size - Font size\n * @cssprop --textarea-min-height - Minimum field height\n * @cssprop --textarea-max-height - Maximum field height (none = unlimited)\n * @cssprop --textarea-resize - CSS resize direction ('vertical' | 'horizontal' | 'both' | 'none')\n * @cssprop --textarea-hover-bg - Field background on hover (flat/ghost variants)\n * @cssprop --textarea-hover-border-color - Field border on hover (flat/bordered variants)\n * @cssprop --textarea-focus-bg - Field background when focused (flat variant)\n * @cssprop --textarea-focus-border-color - Field border when focused (flat variant)\n *\n * @part wrapper - Outer wrapper element.\n * @part label - Label element.\n * @part field - Field container.\n * @part textarea - The native `<textarea>` element.\n * @part helper - The helper text element.\n * @part error - The error text element (`role=\"alert\"`).\n *\n * @example\n * ```html\n * <ore-textarea></ore-textarea>\n * <ore-textarea label=\"Bio\" success></ore-textarea>\n * <ore-textarea label=\"Bio\" loading></ore-textarea>\n * ```\n */\nexport const TEXTAREA_TAG = 'ore-textarea' as const;\ndefine<OreTextareaProps>(TEXTAREA_TAG, {\n formAssociated: true,\n props: {\n ...themableBundle,\n ...sizableBundle,\n ...disablableBundle,\n ...roundableBundle,\n 'auto-resize': prop.bool(false),\n error: prop.string(),\n fullwidth: prop.bool(false),\n helper: prop.string(),\n label: prop.string(),\n 'label-placement': prop.oneOf(['inset', 'outside'] as const, 'inset'),\n loading: prop.bool(false),\n maxlength: prop.json(undefined as number | undefined),\n name: prop.string(),\n 'no-resize': prop.bool(false),\n placeholder: prop.string(),\n readonly: prop.bool(false),\n ref: prop.data<((el: HTMLTextAreaElement | null) => void) | null>(),\n required: prop.bool(false),\n resize: prop.string<'none' | 'both' | 'horizontal' | 'vertical'>(),\n rows: prop.json(undefined as number | undefined),\n success: prop.bool(false),\n value: prop.string(),\n variant: prop.string<'flat' | 'solid' | 'bordered' | 'outline' | 'ghost'>(),\n },\n setup(props) {\n const el = getHost();\n const watch = watchEffect;\n\n const textareaRef = ref<HTMLTextAreaElement>();\n const autoResize = createAutoResize({ enabled: props['auto-resize'] });\n // `loading` behaves like a temporary `disabled`: see ore-input's identical computation.\n const isDisabled = computed(() => props.disabled.value || props.loading.value);\n\n const abortSignal = lifecycleSignal(onCleanup);\n const tf = createTextField({\n disabled: isDisabled,\n error: props.error,\n helper: props.helper,\n label: props.label,\n labelPlacement: props['label-placement'],\n maxLength: props.maxlength,\n onChange: (_event: Event, value: string) => {\n setFieldValue(el, value);\n dispatchNativeFieldEvent(el, 'change');\n },\n onInput: (_event: Event, value: string) => {\n setFieldValue(el, value);\n dispatchNativeFieldEvent(el, 'input');\n },\n prefix: 'textarea',\n readonly: props.readonly,\n required: props.required,\n signal: abortSignal,\n value: props.value,\n });\n\n defineFieldValue(\n el,\n () => tf.value.value,\n (value) => {\n tf.value.value = value;\n },\n );\n\n tf.attachFormField(\n useField<string>({\n disabled: tf.disabled,\n onReset: () => {\n tf.reset();\n requestAnimationFrame(() => autoResize.recompute());\n },\n toFormValue: (v) => v,\n validationMessage: tf.validationMessage,\n validity: tf.validity,\n value: tf.value,\n }),\n );\n\n const {\n ariaDescribedBy,\n ariaErrorMessage,\n ariaInvalid,\n ariaLabelledBy,\n assistiveId,\n counter,\n errorId,\n errorText,\n fieldId: textareaId,\n helperText,\n labelId,\n labelVisible,\n } = tf;\n\n onElement(textareaRef, (textareaEl) => {\n const unwireEl = tf.wire(textareaEl);\n const unwireAutoResize = autoResize.wire(textareaEl);\n const unwireRef = bindRefCallback(props.ref, textareaEl);\n\n const stopLayoutEffect = watch(() => {\n textareaEl.style.resize =\n props['auto-resize'].value || props['no-resize'].value ? 'none' : props.resize.value || 'vertical';\n\n // Deferred a frame: on mount (or right after `auto-resize` flips true) the browser\n // hasn't necessarily finished laying out the textarea yet, so `scrollHeight` read\n // synchronously here could be stale.\n requestAnimationFrame(() => autoResize.recompute());\n });\n\n return () => {\n unwireRef();\n unwireEl();\n unwireAutoResize();\n stopLayoutEffect();\n };\n });\n\n bind({\n attr: {\n error: errorAttr(errorText),\n size: props.size,\n // Reflects `success` only once `error` is confirmed empty: keeps the two host\n // attributes mutually exclusive even if a consumer sets both props at once.\n success: () => (props.success.value && !errorText.value ? true : undefined),\n variant: props.variant,\n },\n });\n\n return html`\n <div class=\"textarea-wrapper\" part=\"wrapper\">\n <label class=\"label\" part=\"label\" for=\"${textareaId}\" id=\"${labelId}\" ?hidden=\"${() => !labelVisible.value}\">\n ${props.label}\n </label>\n <div class=\"field\" part=\"field\">\n <textarea\n part=\"textarea\"\n ref=\"${textareaRef}\"\n id=\"${textareaId}\"\n name=\"${props.name}\"\n placeholder=\"${props.placeholder}\"\n rows=\"${props.rows}\"\n maxlength=\"${props.maxlength}\"\n ?disabled=\"${isDisabled}\"\n ?readonly=\"${props.readonly}\"\n ?required=\"${props.required}\"\n value=\"${live(tf.value)}\"\n aria-describedby=\"${ariaDescribedBy}\"\n aria-errormessage=\"${ariaErrorMessage}\"\n aria-invalid=\"${ariaInvalid}\"\n aria-labelledby=\"${ariaLabelledBy}\"\n aria-busy=\"${() => (props.loading.value ? 'true' : null)}\"></textarea>\n ${renderStatusIcon(errorText)}\n <span class=\"field-spinner\" part=\"spinner\" role=\"status\" aria-label=\"Loading\"></span>\n </div>\n ${renderFieldStatusRegion({ assistiveId, counter, errorId, errorText, helperText })}\n </div>\n `;\n },\n shadow: { delegatesFocus: true },\n styles: [\n colorThemeMixin,\n coarsePointerMixin,\n reducedMotionMixin,\n roundedVariantMixin,\n disabledLoadingMixin,\n sizeVariantMixin(TEXTAREA_SIZE_PRESET),\n forcedColorsFocusMixin('textarea'),\n componentStyles,\n // Must come after `componentStyles`: see `ore-input`'s identical ordering note for why\n // (`@layer` precedence is fixed by which layer name is *first* referenced across this whole\n // array; `componentStyles` establishes `refine.base`, which this mixin's `refine.variants`\n // rules need to win over).\n fieldVariantMixin({ container: '.field', text: 'textarea', tokenPrefix: 'textarea' }),\n ],\n});\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"textarea.js","names":[],"sources":["../src/inputs/textarea/textarea.ts"],"sourcesContent":["import {\n bind,\n define,\n getHost,\n html,\n live,\n onCleanup,\n onElement,\n prop,\n ref,\n useField,\n watchEffect,\n} from '@vielzeug/ore';\nimport { computed } from '@vielzeug/ripple';\nimport { bindRefCallback, createAutoResize, createTextField, lifecycleSignal } from '../../core';\nimport type { TextFieldProps } from '../../shared';\nimport { disablableBundle, roundableBundle, sizableBundle, TEXTAREA_SIZE_PRESET, themableBundle } from '../../shared';\nimport {\n coarsePointerMixin,\n colorThemeMixin,\n disabledLoadingMixin,\n fieldVariantMixin,\n forcedColorsFocusMixin,\n reducedMotionMixin,\n roundedVariantMixin,\n sizeVariantMixin,\n} from '../../styles';\nimport type { VisualVariant } from '../../types';\nimport { errorAttr } from '../shared/field-binding';\nimport { defineFieldValue, dispatchNativeFieldEvent, setFieldValue } from '../shared/native-field-event';\nimport { renderFieldStatusRegion, renderStatusIcon } from '../shared/templates';\nimport componentStyles from './textarea.css?inline';\n\nexport { ICON_TAG } from '../../content/icon/icon';\n/** Textarea component properties */\n\nexport type OreTextareaEvents = {\n change: Event;\n input: InputEvent;\n};\n\nexport type OreTextareaProps = TextFieldProps<Exclude<VisualVariant, 'frost' | 'text'>> & {\n /** Allow auto-grow with content */\n 'auto-resize'?: boolean;\n /**\n * Shows an inline spinner inside the field and forces the inner `<textarea>` into\n * `disabled` for the duration — use while an async validation/submission request\n * is in flight to prevent double-submits.\n */\n loading?: boolean;\n /** Maximum character count; shows a counter when set */\n maxlength?: number;\n /** Disable a manual resize handle */\n 'no-resize'?: boolean;\n /**\n * JS-only callback fired with the inner `<textarea>` element when it mounts,\n * and with `null` when it unmounts. Intended for composed components that\n * need imperative access to the raw element.\n * Set as a JS property: `bitTextarea.ref = (el) => { ... }`.\n */\n ref?: ((el: HTMLTextAreaElement | null) => void) | null;\n /** Resize direction override */\n resize?: 'none' | 'horizontal' | 'both' | 'vertical';\n /** Number of visible text rows */\n rows?: number;\n};\n\n/**\n * A multi-line text input with label, helper text, character counter, and auto-resize.\n *\n * @element ore-textarea\n *\n * @attr {string} label - Label text\n * @attr {string} label-placement - 'inset' | 'outside'\n * @attr {string} value - Current value\n * @attr {string} placeholder - Placeholder text\n * @attr {string} name - Form field name\n * @attr {number} rows - Visible row count\n * @attr {number} maxlength - Max character count (shows counter)\n * @attr {string} helper - Helper text below the textarea\n * @attr {string} error - Error message\n * @attr {boolean} disabled - Disable interaction\n * @attr {boolean} readonly - Read-only mode\n * @attr {boolean} required - Required field\n * @attr {boolean} no-resize - Disable manual resize\n * @attr {boolean} auto-resize - Grow with content\n * @attr {boolean} loading - Show an inline spinner and force the field disabled\n * @attr {boolean} success - Show an inline success check icon (suppressed while `error` is set)\n * @attr {string} resize - Resize direction: 'none' | 'horizontal' | 'both' | 'vertical'\n * @attr {string} color - Theme color: 'primary' | 'secondary' | 'info' | 'success' | 'warning' | 'error'\n * @attr {string} variant - Visual variant: 'solid' | 'flat' | 'bordered' | 'outline' | 'ghost'\n * @attr {string} size - Component size: 'sm' | 'md' | 'lg'\n * @attr {string} rounded - Border radius: 'none' | 'sm' | 'md' | 'lg' | 'xl' | '2xl' | '3xl' | 'full'\n *\n * @fires input - Fired on every keystroke with current value.\n * @fires change - Fired on blur with changed value.\n *\n * @slot helper - Complex helper content\n *\n * @part status-icon - The inline error/success icon shown inside the field\n * @part spinner - The inline loading spinner shown inside the field while `loading`\n *\n * @cssprop --textarea-bg - Background color\n * @cssprop --textarea-border-color - Border color\n * @cssprop --textarea-placeholder-color - Placeholder text color\n * @cssprop --textarea-radius - Border radius\n * @cssprop --textarea-padding - Inner padding (block inline)\n * @cssprop --textarea-gap - Gap between label and field\n * @cssprop --textarea-font-size - Font size\n * @cssprop --textarea-min-height - Minimum field height\n * @cssprop --textarea-max-height - Maximum field height (none = unlimited)\n * @cssprop --textarea-resize - CSS resize direction ('vertical' | 'horizontal' | 'both' | 'none')\n * @cssprop --textarea-hover-bg - Field background on hover (flat/ghost variants)\n * @cssprop --textarea-hover-border-color - Field border on hover (flat/bordered variants)\n * @cssprop --textarea-focus-bg - Field background when focused (flat variant)\n * @cssprop --textarea-focus-border-color - Field border when focused (flat variant)\n *\n * @part wrapper - Outer wrapper element.\n * @part label - Label element.\n * @part field - Field container.\n * @part textarea - The native `<textarea>` element.\n * @part helper - The helper text element.\n * @part error - The error text element (`role=\"alert\"`).\n *\n * @example\n * ```html\n * <ore-textarea></ore-textarea>\n * <ore-textarea label=\"Bio\" success></ore-textarea>\n * <ore-textarea label=\"Bio\" loading></ore-textarea>\n * ```\n */\nexport const TEXTAREA_TAG = 'ore-textarea' as const;\ndefine<OreTextareaProps>(TEXTAREA_TAG, {\n formAssociated: true,\n props: {\n ...themableBundle,\n ...sizableBundle,\n ...disablableBundle,\n ...roundableBundle,\n 'auto-resize': prop.bool(false),\n error: prop.string(),\n fullwidth: prop.bool(false),\n helper: prop.string(),\n label: prop.string(),\n 'label-placement': prop.oneOf(['inset', 'outside'] as const, 'inset'),\n loading: prop.bool(false),\n maxlength: prop.json(undefined as number | undefined),\n name: prop.string(),\n 'no-resize': prop.bool(false),\n placeholder: prop.string(),\n readonly: prop.bool(false),\n ref: prop.data<((el: HTMLTextAreaElement | null) => void) | null>(),\n required: prop.bool(false),\n resize: prop.string<'none' | 'both' | 'horizontal' | 'vertical'>(),\n rows: prop.json(undefined as number | undefined),\n success: prop.bool(false),\n value: prop.string(),\n variant: prop.string<'flat' | 'solid' | 'bordered' | 'outline' | 'ghost'>(),\n },\n setup(props) {\n const el = getHost();\n const watch = watchEffect;\n\n const textareaRef = ref<HTMLTextAreaElement>();\n const autoResize = createAutoResize({ enabled: props['auto-resize'] });\n // `loading` behaves like a temporary `disabled` — see ore-input's identical computation.\n const isDisabled = computed(() => props.disabled.value || props.loading.value);\n\n const abortSignal = lifecycleSignal(onCleanup);\n const tf = createTextField({\n disabled: isDisabled,\n error: props.error,\n helper: props.helper,\n label: props.label,\n labelPlacement: props['label-placement'],\n maxLength: props.maxlength,\n onChange: (_event: Event, value: string) => {\n setFieldValue(el, value);\n dispatchNativeFieldEvent(el, 'change');\n },\n onInput: (_event: Event, value: string) => {\n setFieldValue(el, value);\n dispatchNativeFieldEvent(el, 'input');\n },\n prefix: 'textarea',\n readonly: props.readonly,\n required: props.required,\n signal: abortSignal,\n value: props.value,\n });\n\n defineFieldValue(\n el,\n () => tf.value.value,\n (value) => {\n tf.value.value = value;\n },\n );\n\n tf.attachFormField(\n useField<string>({\n disabled: tf.disabled,\n onReset: () => {\n tf.reset();\n requestAnimationFrame(() => autoResize.recompute());\n },\n toFormValue: (v) => v,\n validationMessage: tf.validationMessage,\n validity: tf.validity,\n value: tf.value,\n }),\n );\n\n const {\n ariaDescribedBy,\n ariaErrorMessage,\n ariaInvalid,\n ariaLabelledBy,\n assistiveId,\n counter,\n errorId,\n errorText,\n fieldId: textareaId,\n helperText,\n labelId,\n labelVisible,\n } = tf;\n\n onElement(textareaRef, (textareaEl) => {\n const unwireEl = tf.wire(textareaEl);\n const unwireAutoResize = autoResize.wire(textareaEl);\n const unwireRef = bindRefCallback(props.ref, textareaEl);\n\n const stopLayoutEffect = watch(() => {\n textareaEl.style.resize =\n props['auto-resize'].value || props['no-resize'].value ? 'none' : props.resize.value || 'vertical';\n\n // Deferred a frame: on mount (or right after `auto-resize` flips true) the browser\n // hasn't necessarily finished laying out the textarea yet, so `scrollHeight` read\n // synchronously here could be stale.\n requestAnimationFrame(() => autoResize.recompute());\n });\n\n return () => {\n unwireRef();\n unwireEl();\n unwireAutoResize();\n stopLayoutEffect();\n };\n });\n\n bind({\n attr: {\n error: errorAttr(errorText),\n size: props.size,\n // Reflects `success` only once `error` is confirmed empty — keeps the two host\n // attributes mutually exclusive even if a consumer sets both props at once.\n success: () => (props.success.value && !errorText.value ? true : undefined),\n variant: props.variant,\n },\n });\n\n return html`\n <div class=\"textarea-wrapper\" part=\"wrapper\">\n <label class=\"label\" part=\"label\" for=\"${textareaId}\" id=\"${labelId}\" ?hidden=\"${() => !labelVisible.value}\">\n ${props.label}\n </label>\n <div class=\"field\" part=\"field\">\n <textarea\n part=\"textarea\"\n ref=\"${textareaRef}\"\n id=\"${textareaId}\"\n name=\"${props.name}\"\n placeholder=\"${props.placeholder}\"\n rows=\"${props.rows}\"\n maxlength=\"${props.maxlength}\"\n ?disabled=\"${isDisabled}\"\n ?readonly=\"${props.readonly}\"\n ?required=\"${props.required}\"\n value=\"${live(tf.value)}\"\n aria-describedby=\"${ariaDescribedBy}\"\n aria-errormessage=\"${ariaErrorMessage}\"\n aria-invalid=\"${ariaInvalid}\"\n aria-labelledby=\"${ariaLabelledBy}\"\n aria-busy=\"${() => (props.loading.value ? 'true' : null)}\"></textarea>\n ${renderStatusIcon(errorText)}\n <span class=\"field-spinner\" part=\"spinner\" role=\"status\" aria-label=\"Loading\"></span>\n </div>\n ${renderFieldStatusRegion({ assistiveId, counter, errorId, errorText, helperText })}\n </div>\n `;\n },\n shadow: { delegatesFocus: true },\n styles: [\n colorThemeMixin,\n coarsePointerMixin,\n reducedMotionMixin,\n roundedVariantMixin,\n disabledLoadingMixin,\n sizeVariantMixin(TEXTAREA_SIZE_PRESET),\n forcedColorsFocusMixin('textarea'),\n componentStyles,\n // Must come after `componentStyles` — see `ore-input`'s identical ordering note for why\n // (`@layer` precedence is fixed by which layer name is *first* referenced across this whole\n // array; `componentStyles` establishes `refine.base`, which this mixin's `refine.variants`\n // rules need to win over).\n fieldVariantMixin({ container: '.field', text: 'textarea', tokenPrefix: 'textarea' }),\n ],\n});\n"],"mappings":"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"}
1
+ {"version":3,"file":"textarea.js","names":[],"sources":["../src/inputs/textarea/textarea.ts"],"sourcesContent":["import {\n bind,\n define,\n getHost,\n html,\n live,\n onCleanup,\n onElement,\n prop,\n ref,\n useField,\n watchEffect,\n} from '@vielzeug/ore';\nimport { computed } from '@vielzeug/ripple';\nimport { bindRefCallback, createAutoResize, createTextField, lifecycleSignal } from '../../core';\nimport type { TextFieldProps } from '../../shared';\nimport { disablableBundle, roundableBundle, sizableBundle, TEXTAREA_SIZE_PRESET, themableBundle } from '../../shared';\nimport {\n coarsePointerMixin,\n colorThemeMixin,\n disabledLoadingMixin,\n fieldVariantMixin,\n forcedColorsFocusMixin,\n reducedMotionMixin,\n roundedVariantMixin,\n sizeVariantMixin,\n} from '../../styles';\nimport type { VisualVariant } from '../../types';\nimport { errorAttr } from '../shared/field-binding';\nimport { defineFieldValue, dispatchNativeFieldEvent, setFieldValue } from '../shared/native-field-event';\nimport { renderFieldStatusRegion, renderStatusIcon } from '../shared/templates';\nimport componentStyles from './textarea.css?inline';\n\nexport { ICON_TAG } from '../../content/icon/icon';\n/** Textarea component properties */\n\nexport type OreTextareaEvents = {\n change: Event;\n input: InputEvent;\n};\n\nexport type OreTextareaProps = TextFieldProps<Exclude<VisualVariant, 'frost' | 'text'>> & {\n /** Allow auto-grow with content */\n 'auto-resize'?: boolean;\n /**\n * Shows an inline spinner inside the field and forces the inner `<textarea>` into\n * `disabled` for the duration: use while an async validation/submission request\n * is in flight to prevent double-submits.\n */\n loading?: boolean;\n /** Maximum character count; shows a counter when set */\n maxlength?: number;\n /** Disable a manual resize handle */\n 'no-resize'?: boolean;\n /**\n * JS-only callback fired with the inner `<textarea>` element when it mounts,\n * and with `null` when it unmounts. Intended for composed components that\n * need imperative access to the raw element.\n * Set as a JS property: `bitTextarea.ref = (el) => { ... }`.\n */\n ref?: ((el: HTMLTextAreaElement | null) => void) | null;\n /** Resize direction override */\n resize?: 'none' | 'horizontal' | 'both' | 'vertical';\n /** Number of visible text rows */\n rows?: number;\n};\n\n/**\n * A multi-line text input with label, helper text, character counter, and auto-resize.\n *\n * @element ore-textarea\n *\n * @attr {string} label - Label text\n * @attr {string} label-placement - 'inset' | 'outside'\n * @attr {string} value - Current value\n * @attr {string} placeholder - Placeholder text\n * @attr {string} name - Form field name\n * @attr {number} rows - Visible row count\n * @attr {number} maxlength - Max character count (shows counter)\n * @attr {string} helper - Helper text below the textarea\n * @attr {string} error - Error message\n * @attr {boolean} disabled - Disable interaction\n * @attr {boolean} readonly - Read-only mode\n * @attr {boolean} required - Required field\n * @attr {boolean} no-resize - Disable manual resize\n * @attr {boolean} auto-resize - Grow with content\n * @attr {boolean} loading - Show an inline spinner and force the field disabled\n * @attr {boolean} success - Show an inline success check icon (suppressed while `error` is set)\n * @attr {string} resize - Resize direction: 'none' | 'horizontal' | 'both' | 'vertical'\n * @attr {string} color - Theme color: 'primary' | 'secondary' | 'info' | 'success' | 'warning' | 'error'\n * @attr {string} variant - Visual variant: 'solid' | 'flat' | 'bordered' | 'outline' | 'ghost'\n * @attr {string} size - Component size: 'sm' | 'md' | 'lg'\n * @attr {string} rounded - Border radius: 'none' | 'sm' | 'md' | 'lg' | 'xl' | '2xl' | '3xl' | 'full'\n *\n * @fires input - Fired on every keystroke with current value.\n * @fires change - Fired on blur with changed value.\n *\n * @slot helper - Complex helper content\n *\n * @part status-icon - The inline error/success icon shown inside the field\n * @part spinner - The inline loading spinner shown inside the field while `loading`\n *\n * @cssprop --textarea-bg - Background color\n * @cssprop --textarea-border-color - Border color\n * @cssprop --textarea-placeholder-color - Placeholder text color\n * @cssprop --textarea-radius - Border radius\n * @cssprop --textarea-padding - Inner padding (block inline)\n * @cssprop --textarea-gap - Gap between label and field\n * @cssprop --textarea-font-size - Font size\n * @cssprop --textarea-min-height - Minimum field height\n * @cssprop --textarea-max-height - Maximum field height (none = unlimited)\n * @cssprop --textarea-resize - CSS resize direction ('vertical' | 'horizontal' | 'both' | 'none')\n * @cssprop --textarea-hover-bg - Field background on hover (flat/ghost variants)\n * @cssprop --textarea-hover-border-color - Field border on hover (flat/bordered variants)\n * @cssprop --textarea-focus-bg - Field background when focused (flat variant)\n * @cssprop --textarea-focus-border-color - Field border when focused (flat variant)\n *\n * @part wrapper - Outer wrapper element.\n * @part label - Label element.\n * @part field - Field container.\n * @part textarea - The native `<textarea>` element.\n * @part helper - The helper text element.\n * @part error - The error text element (`role=\"alert\"`).\n *\n * @example\n * ```html\n * <ore-textarea></ore-textarea>\n * <ore-textarea label=\"Bio\" success></ore-textarea>\n * <ore-textarea label=\"Bio\" loading></ore-textarea>\n * ```\n */\nexport const TEXTAREA_TAG = 'ore-textarea' as const;\ndefine<OreTextareaProps>(TEXTAREA_TAG, {\n formAssociated: true,\n props: {\n ...themableBundle,\n ...sizableBundle,\n ...disablableBundle,\n ...roundableBundle,\n 'auto-resize': prop.bool(false),\n error: prop.string(),\n fullwidth: prop.bool(false),\n helper: prop.string(),\n label: prop.string(),\n 'label-placement': prop.oneOf(['inset', 'outside'] as const, 'inset'),\n loading: prop.bool(false),\n maxlength: prop.json(undefined as number | undefined),\n name: prop.string(),\n 'no-resize': prop.bool(false),\n placeholder: prop.string(),\n readonly: prop.bool(false),\n ref: prop.data<((el: HTMLTextAreaElement | null) => void) | null>(),\n required: prop.bool(false),\n resize: prop.string<'none' | 'both' | 'horizontal' | 'vertical'>(),\n rows: prop.json(undefined as number | undefined),\n success: prop.bool(false),\n value: prop.string(),\n variant: prop.string<'flat' | 'solid' | 'bordered' | 'outline' | 'ghost'>(),\n },\n setup(props) {\n const el = getHost();\n const watch = watchEffect;\n\n const textareaRef = ref<HTMLTextAreaElement>();\n const autoResize = createAutoResize({ enabled: props['auto-resize'] });\n // `loading` behaves like a temporary `disabled`: see ore-input's identical computation.\n const isDisabled = computed(() => props.disabled.value || props.loading.value);\n\n const abortSignal = lifecycleSignal(onCleanup);\n const tf = createTextField({\n disabled: isDisabled,\n error: props.error,\n helper: props.helper,\n label: props.label,\n labelPlacement: props['label-placement'],\n maxLength: props.maxlength,\n onChange: (_event: Event, value: string) => {\n setFieldValue(el, value);\n dispatchNativeFieldEvent(el, 'change');\n },\n onInput: (_event: Event, value: string) => {\n setFieldValue(el, value);\n dispatchNativeFieldEvent(el, 'input');\n },\n prefix: 'textarea',\n readonly: props.readonly,\n required: props.required,\n signal: abortSignal,\n value: props.value,\n });\n\n defineFieldValue(\n el,\n () => tf.value.value,\n (value) => {\n tf.value.value = value;\n },\n );\n\n tf.attachFormField(\n useField<string>({\n disabled: tf.disabled,\n onReset: () => {\n tf.reset();\n requestAnimationFrame(() => autoResize.recompute());\n },\n toFormValue: (v) => v,\n validationMessage: tf.validationMessage,\n validity: tf.validity,\n value: tf.value,\n }),\n );\n\n const {\n ariaDescribedBy,\n ariaErrorMessage,\n ariaInvalid,\n ariaLabelledBy,\n assistiveId,\n counter,\n errorId,\n errorText,\n fieldId: textareaId,\n helperText,\n labelId,\n labelVisible,\n } = tf;\n\n onElement(textareaRef, (textareaEl) => {\n const unwireEl = tf.wire(textareaEl);\n const unwireAutoResize = autoResize.wire(textareaEl);\n const unwireRef = bindRefCallback(props.ref, textareaEl);\n\n const stopLayoutEffect = watch(() => {\n textareaEl.style.resize =\n props['auto-resize'].value || props['no-resize'].value ? 'none' : props.resize.value || 'vertical';\n\n // Deferred a frame: on mount (or right after `auto-resize` flips true) the browser\n // hasn't necessarily finished laying out the textarea yet, so `scrollHeight` read\n // synchronously here could be stale.\n requestAnimationFrame(() => autoResize.recompute());\n });\n\n return () => {\n unwireRef();\n unwireEl();\n unwireAutoResize();\n stopLayoutEffect();\n };\n });\n\n bind({\n attr: {\n error: errorAttr(errorText),\n size: props.size,\n // Reflects `success` only once `error` is confirmed empty: keeps the two host\n // attributes mutually exclusive even if a consumer sets both props at once.\n success: () => (props.success.value && !errorText.value ? true : undefined),\n variant: props.variant,\n },\n });\n\n return html`\n <div class=\"textarea-wrapper\" part=\"wrapper\">\n <label class=\"label\" part=\"label\" for=\"${textareaId}\" id=\"${labelId}\" ?hidden=\"${() => !labelVisible.value}\">\n ${props.label}\n </label>\n <div class=\"field\" part=\"field\">\n <textarea\n part=\"textarea\"\n ref=\"${textareaRef}\"\n id=\"${textareaId}\"\n name=\"${props.name}\"\n placeholder=\"${props.placeholder}\"\n rows=\"${props.rows}\"\n maxlength=\"${props.maxlength}\"\n ?disabled=\"${isDisabled}\"\n ?readonly=\"${props.readonly}\"\n ?required=\"${props.required}\"\n value=\"${live(tf.value)}\"\n aria-describedby=\"${ariaDescribedBy}\"\n aria-errormessage=\"${ariaErrorMessage}\"\n aria-invalid=\"${ariaInvalid}\"\n aria-labelledby=\"${ariaLabelledBy}\"\n aria-busy=\"${() => (props.loading.value ? 'true' : null)}\"></textarea>\n ${renderStatusIcon(errorText)}\n <span class=\"field-spinner\" part=\"spinner\" role=\"status\" aria-label=\"Loading\"></span>\n </div>\n ${renderFieldStatusRegion({ assistiveId, counter, errorId, errorText, helperText })}\n </div>\n `;\n },\n shadow: { delegatesFocus: true },\n styles: [\n colorThemeMixin,\n coarsePointerMixin,\n reducedMotionMixin,\n roundedVariantMixin,\n disabledLoadingMixin,\n sizeVariantMixin(TEXTAREA_SIZE_PRESET),\n forcedColorsFocusMixin('textarea'),\n componentStyles,\n // Must come after `componentStyles`: see `ore-input`'s identical ordering note for why\n // (`@layer` precedence is fixed by which layer name is *first* referenced across this whole\n // array; `componentStyles` establishes `refine.base`, which this mixin's `refine.variants`\n // rules need to win over).\n fieldVariantMixin({ container: '.field', text: 'textarea', tokenPrefix: 'textarea' }),\n ],\n});\n"],"mappings":"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"}