@helixui/library 3.0.0-next.65 → 3.1.0-next.66

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 (408) hide show
  1. package/custom-elements.json +6549 -318
  2. package/dist/components/hx-accordion/hx-accordion.d.ts +3 -0
  3. package/dist/components/hx-accordion/hx-accordion.d.ts.map +1 -1
  4. package/dist/components/hx-action-bar/hx-action-bar.d.ts +14 -0
  5. package/dist/components/hx-action-bar/hx-action-bar.d.ts.map +1 -1
  6. package/dist/components/hx-action-bar/index.js +1 -1
  7. package/dist/components/hx-alert/hx-alert.d.ts +36 -0
  8. package/dist/components/hx-alert/hx-alert.d.ts.map +1 -1
  9. package/dist/components/hx-avatar/hx-avatar.d.ts +17 -0
  10. package/dist/components/hx-avatar/hx-avatar.d.ts.map +1 -1
  11. package/dist/components/hx-badge/hx-badge.d.ts +35 -0
  12. package/dist/components/hx-badge/hx-badge.d.ts.map +1 -1
  13. package/dist/components/hx-banner/hx-banner.d.ts +34 -0
  14. package/dist/components/hx-banner/hx-banner.d.ts.map +1 -1
  15. package/dist/components/hx-breadcrumb/hx-breadcrumb.d.ts +3 -0
  16. package/dist/components/hx-breadcrumb/hx-breadcrumb.d.ts.map +1 -1
  17. package/dist/components/hx-breadcrumb/index.js +1 -1
  18. package/dist/components/hx-button/hx-button.d.ts +42 -0
  19. package/dist/components/hx-button/hx-button.d.ts.map +1 -1
  20. package/dist/components/hx-button/index.js +1 -1
  21. package/dist/components/hx-button-group/hx-button-group.d.ts +2 -0
  22. package/dist/components/hx-button-group/hx-button-group.d.ts.map +1 -1
  23. package/dist/components/hx-card/hx-card.d.ts +28 -0
  24. package/dist/components/hx-card/hx-card.d.ts.map +1 -1
  25. package/dist/components/hx-card/index.js +1 -1
  26. package/dist/components/hx-carousel/hx-carousel.d.ts +25 -0
  27. package/dist/components/hx-carousel/hx-carousel.d.ts.map +1 -1
  28. package/dist/components/hx-checkbox/hx-checkbox.d.ts +31 -0
  29. package/dist/components/hx-checkbox/hx-checkbox.d.ts.map +1 -1
  30. package/dist/components/hx-checkbox/index.js +1 -1
  31. package/dist/components/hx-checkbox-group/hx-checkbox-group.d.ts +14 -0
  32. package/dist/components/hx-checkbox-group/hx-checkbox-group.d.ts.map +1 -1
  33. package/dist/components/hx-checkbox-group/index.js +1 -1
  34. package/dist/components/hx-clinical-status/hx-clinical-status.d.ts +37 -0
  35. package/dist/components/hx-clinical-status/hx-clinical-status.d.ts.map +1 -1
  36. package/dist/components/hx-code-snippet/hx-code-snippet.d.ts +35 -0
  37. package/dist/components/hx-code-snippet/hx-code-snippet.d.ts.map +1 -1
  38. package/dist/components/hx-color-picker/hx-color-picker.d.ts +29 -0
  39. package/dist/components/hx-color-picker/hx-color-picker.d.ts.map +1 -1
  40. package/dist/components/hx-combobox/hx-combobox.d.ts +49 -0
  41. package/dist/components/hx-combobox/hx-combobox.d.ts.map +1 -1
  42. package/dist/components/hx-combobox/index.js +1 -1
  43. package/dist/components/hx-container/hx-container.d.ts +5 -0
  44. package/dist/components/hx-container/hx-container.d.ts.map +1 -1
  45. package/dist/components/hx-copy-button/hx-copy-button.d.ts +24 -0
  46. package/dist/components/hx-copy-button/hx-copy-button.d.ts.map +1 -1
  47. package/dist/components/hx-counter/hx-counter.d.ts +7 -0
  48. package/dist/components/hx-counter/hx-counter.d.ts.map +1 -1
  49. package/dist/components/hx-data-table/hx-data-table.d.ts +29 -0
  50. package/dist/components/hx-data-table/hx-data-table.d.ts.map +1 -1
  51. package/dist/components/hx-data-table/hx-data-table.styles.d.ts.map +1 -1
  52. package/dist/components/hx-data-table/index.js +1 -1
  53. package/dist/components/hx-date-picker/hx-date-picker.d.ts +44 -0
  54. package/dist/components/hx-date-picker/hx-date-picker.d.ts.map +1 -1
  55. package/dist/components/hx-date-picker/index.js +1 -1
  56. package/dist/components/hx-dialog/hx-dialog.d.ts +31 -0
  57. package/dist/components/hx-dialog/hx-dialog.d.ts.map +1 -1
  58. package/dist/components/hx-dialog/index.js +1 -1
  59. package/dist/components/hx-divider/hx-divider.d.ts +9 -0
  60. package/dist/components/hx-divider/hx-divider.d.ts.map +1 -1
  61. package/dist/components/hx-divider/index.js +1 -1
  62. package/dist/components/hx-drawer/hx-drawer.d.ts +30 -0
  63. package/dist/components/hx-drawer/hx-drawer.d.ts.map +1 -1
  64. package/dist/components/hx-drawer/hx-drawer.styles.d.ts.map +1 -1
  65. package/dist/components/hx-drawer/index.js +1 -1
  66. package/dist/components/hx-dropdown/hx-dropdown.d.ts +6 -0
  67. package/dist/components/hx-dropdown/hx-dropdown.d.ts.map +1 -1
  68. package/dist/components/hx-dropdown/index.js +1 -1
  69. package/dist/components/hx-field/hx-field.d.ts +15 -0
  70. package/dist/components/hx-field/hx-field.d.ts.map +1 -1
  71. package/dist/components/hx-field/index.js +1 -1
  72. package/dist/components/hx-field-label/hx-field-label.d.ts +11 -0
  73. package/dist/components/hx-field-label/hx-field-label.d.ts.map +1 -1
  74. package/dist/components/hx-field-label/index.js +1 -1
  75. package/dist/components/hx-file-upload/hx-file-upload.d.ts +35 -0
  76. package/dist/components/hx-file-upload/hx-file-upload.d.ts.map +1 -1
  77. package/dist/components/hx-file-upload/index.js +1 -1
  78. package/dist/components/hx-grid/hx-grid.d.ts +5 -0
  79. package/dist/components/hx-grid/hx-grid.d.ts.map +1 -1
  80. package/dist/components/hx-help-text/hx-help-text.d.ts +8 -0
  81. package/dist/components/hx-help-text/hx-help-text.d.ts.map +1 -1
  82. package/dist/components/hx-help-text/index.js +1 -1
  83. package/dist/components/hx-icon/hx-icon.d.ts +5 -0
  84. package/dist/components/hx-icon/hx-icon.d.ts.map +1 -1
  85. package/dist/components/hx-icon-button/hx-icon-button.d.ts +27 -0
  86. package/dist/components/hx-icon-button/hx-icon-button.d.ts.map +1 -1
  87. package/dist/components/hx-icon-button/index.js +1 -1
  88. package/dist/components/hx-image/hx-image.d.ts +4 -0
  89. package/dist/components/hx-image/hx-image.d.ts.map +1 -1
  90. package/dist/components/hx-link/hx-link.d.ts +15 -0
  91. package/dist/components/hx-link/hx-link.d.ts.map +1 -1
  92. package/dist/components/hx-link/index.js +1 -1
  93. package/dist/components/hx-list/hx-list.d.ts +3 -0
  94. package/dist/components/hx-list/hx-list.d.ts.map +1 -1
  95. package/dist/components/hx-menu/hx-menu.d.ts +6 -0
  96. package/dist/components/hx-menu/hx-menu.d.ts.map +1 -1
  97. package/dist/components/hx-menu/index.js +1 -1
  98. package/dist/components/hx-meter/hx-meter.d.ts +23 -0
  99. package/dist/components/hx-meter/hx-meter.d.ts.map +1 -1
  100. package/dist/components/hx-nav/hx-nav.d.ts +29 -0
  101. package/dist/components/hx-nav/hx-nav.d.ts.map +1 -1
  102. package/dist/components/hx-number-input/hx-number-input.d.ts +34 -0
  103. package/dist/components/hx-number-input/hx-number-input.d.ts.map +1 -1
  104. package/dist/components/hx-number-input/index.js +1 -1
  105. package/dist/components/hx-overflow-menu/hx-overflow-menu.d.ts +26 -0
  106. package/dist/components/hx-overflow-menu/hx-overflow-menu.d.ts.map +1 -1
  107. package/dist/components/hx-overflow-menu/index.js +1 -1
  108. package/dist/components/hx-pagination/hx-pagination.d.ts +21 -0
  109. package/dist/components/hx-pagination/hx-pagination.d.ts.map +1 -1
  110. package/dist/components/hx-pagination/index.js +1 -1
  111. package/dist/components/hx-patient-banner/hx-patient-banner.d.ts +23 -0
  112. package/dist/components/hx-patient-banner/hx-patient-banner.d.ts.map +1 -1
  113. package/dist/components/hx-phi-field/hx-phi-field.d.ts +14 -0
  114. package/dist/components/hx-phi-field/hx-phi-field.d.ts.map +1 -1
  115. package/dist/components/hx-phi-field/index.js +1 -1
  116. package/dist/components/hx-popover/hx-popover.d.ts +15 -0
  117. package/dist/components/hx-popover/hx-popover.d.ts.map +1 -1
  118. package/dist/components/hx-popover/index.js +1 -1
  119. package/dist/components/hx-popup/hx-popup.d.ts +1 -0
  120. package/dist/components/hx-popup/hx-popup.d.ts.map +1 -1
  121. package/dist/components/hx-progress-bar/hx-progress-bar.d.ts +17 -0
  122. package/dist/components/hx-progress-bar/hx-progress-bar.d.ts.map +1 -1
  123. package/dist/components/hx-progress-bar/index.js +1 -1
  124. package/dist/components/hx-progress-ring/hx-progress-ring.d.ts +15 -0
  125. package/dist/components/hx-progress-ring/hx-progress-ring.d.ts.map +1 -1
  126. package/dist/components/hx-prose/hx-prose.d.ts +2 -0
  127. package/dist/components/hx-prose/hx-prose.d.ts.map +1 -1
  128. package/dist/components/hx-radio-group/hx-radio-group.d.ts +14 -0
  129. package/dist/components/hx-radio-group/hx-radio-group.d.ts.map +1 -1
  130. package/dist/components/hx-radio-group/index.js +1 -1
  131. package/dist/components/hx-rating/hx-rating.d.ts +13 -0
  132. package/dist/components/hx-rating/hx-rating.d.ts.map +1 -1
  133. package/dist/components/hx-select/hx-select.d.ts +43 -0
  134. package/dist/components/hx-select/hx-select.d.ts.map +1 -1
  135. package/dist/components/hx-select/hx-select.styles.d.ts.map +1 -1
  136. package/dist/components/hx-select/index.js +1 -1
  137. package/dist/components/hx-side-nav/hx-nav-item.styles.d.ts.map +1 -1
  138. package/dist/components/hx-side-nav/hx-side-nav.d.ts +19 -0
  139. package/dist/components/hx-side-nav/hx-side-nav.d.ts.map +1 -1
  140. package/dist/components/hx-side-nav/index.js +1 -1
  141. package/dist/components/hx-skeleton/hx-skeleton.d.ts +5 -0
  142. package/dist/components/hx-skeleton/hx-skeleton.d.ts.map +1 -1
  143. package/dist/components/hx-slider/hx-slider.d.ts +38 -0
  144. package/dist/components/hx-slider/hx-slider.d.ts.map +1 -1
  145. package/dist/components/hx-slider/index.js +1 -1
  146. package/dist/components/hx-spinner/hx-spinner.d.ts +10 -0
  147. package/dist/components/hx-spinner/hx-spinner.d.ts.map +1 -1
  148. package/dist/components/hx-split-button/hx-split-button.d.ts +39 -0
  149. package/dist/components/hx-split-button/hx-split-button.d.ts.map +1 -1
  150. package/dist/components/hx-split-button/index.js +1 -1
  151. package/dist/components/hx-split-panel/hx-split-panel.d.ts +12 -0
  152. package/dist/components/hx-split-panel/hx-split-panel.d.ts.map +1 -1
  153. package/dist/components/hx-split-panel/index.js +1 -1
  154. package/dist/components/hx-stack/hx-stack.d.ts +5 -0
  155. package/dist/components/hx-stack/hx-stack.d.ts.map +1 -1
  156. package/dist/components/hx-stat/hx-stat.d.ts +24 -0
  157. package/dist/components/hx-stat/hx-stat.d.ts.map +1 -1
  158. package/dist/components/hx-status-indicator/hx-status-indicator.d.ts +13 -0
  159. package/dist/components/hx-status-indicator/hx-status-indicator.d.ts.map +1 -1
  160. package/dist/components/hx-steps/hx-steps.d.ts +15 -0
  161. package/dist/components/hx-steps/hx-steps.d.ts.map +1 -1
  162. package/dist/components/hx-structured-list/hx-structured-list.d.ts +7 -0
  163. package/dist/components/hx-structured-list/hx-structured-list.d.ts.map +1 -1
  164. package/dist/components/hx-switch/hx-switch.d.ts +42 -0
  165. package/dist/components/hx-switch/hx-switch.d.ts.map +1 -1
  166. package/dist/components/hx-switch/index.js +1 -1
  167. package/dist/components/hx-table/hx-table.d.ts +14 -0
  168. package/dist/components/hx-table/hx-table.d.ts.map +1 -1
  169. package/dist/components/hx-tabs/hx-tabs.d.ts +4 -0
  170. package/dist/components/hx-tabs/hx-tabs.d.ts.map +1 -1
  171. package/dist/components/hx-tag/hx-tag.d.ts +36 -0
  172. package/dist/components/hx-tag/hx-tag.d.ts.map +1 -1
  173. package/dist/components/hx-text/hx-text.d.ts +22 -0
  174. package/dist/components/hx-text/hx-text.d.ts.map +1 -1
  175. package/dist/components/hx-text-input/hx-text-input.d.ts +30 -0
  176. package/dist/components/hx-text-input/hx-text-input.d.ts.map +1 -1
  177. package/dist/components/hx-text-input/index.js +1 -1
  178. package/dist/components/hx-textarea/hx-textarea.d.ts +27 -0
  179. package/dist/components/hx-textarea/hx-textarea.d.ts.map +1 -1
  180. package/dist/components/hx-textarea/index.js +1 -1
  181. package/dist/components/hx-theme/hx-theme.d.ts +3 -0
  182. package/dist/components/hx-theme/hx-theme.d.ts.map +1 -1
  183. package/dist/components/hx-theme/index.js +1 -1
  184. package/dist/components/hx-time-picker/hx-time-picker.d.ts +32 -0
  185. package/dist/components/hx-time-picker/hx-time-picker.d.ts.map +1 -1
  186. package/dist/components/hx-time-picker/index.js +1 -1
  187. package/dist/components/hx-toast/hx-toast.d.ts +24 -0
  188. package/dist/components/hx-toast/hx-toast.d.ts.map +1 -1
  189. package/dist/components/hx-toggle-button/hx-toggle-button.d.ts +35 -0
  190. package/dist/components/hx-toggle-button/hx-toggle-button.d.ts.map +1 -1
  191. package/dist/components/hx-toggle-button/hx-toggle-button.styles.d.ts.map +1 -1
  192. package/dist/components/hx-toggle-button/index.js +1 -1
  193. package/dist/components/hx-tooltip/hx-tooltip.d.ts +13 -0
  194. package/dist/components/hx-tooltip/hx-tooltip.d.ts.map +1 -1
  195. package/dist/components/hx-tooltip/index.js +1 -1
  196. package/dist/components/hx-top-nav/hx-top-nav.d.ts +21 -0
  197. package/dist/components/hx-top-nav/hx-top-nav.d.ts.map +1 -1
  198. package/dist/components/hx-top-nav/index.js +1 -1
  199. package/dist/components/hx-tree-view/hx-tree-view.d.ts +6 -0
  200. package/dist/components/hx-tree-view/hx-tree-view.d.ts.map +1 -1
  201. package/dist/css/helix-all.css +263 -253
  202. package/dist/css/helix-core.css +26 -26
  203. package/dist/css/helix-data.css +8 -7
  204. package/dist/css/helix-feedback.css +2 -2
  205. package/dist/css/helix-forms.css +137 -131
  206. package/dist/css/helix-layout.css +3 -3
  207. package/dist/css/helix-navigation.css +35 -35
  208. package/dist/css/helix-overlay.css +32 -29
  209. package/dist/css/helix-tokens.css +12 -0
  210. package/dist/css/helix-utility.css +18 -18
  211. package/dist/css/hx-action-bar.css +3 -3
  212. package/dist/css/hx-button.css +10 -10
  213. package/dist/css/hx-card.css +6 -6
  214. package/dist/css/hx-checkbox-group.css +2 -2
  215. package/dist/css/hx-checkbox.css +5 -5
  216. package/dist/css/hx-combobox.css +13 -13
  217. package/dist/css/hx-data-table.css +8 -7
  218. package/dist/css/hx-date-picker.css +20 -20
  219. package/dist/css/hx-dialog.css +10 -10
  220. package/dist/css/hx-divider.css +2 -2
  221. package/dist/css/hx-drawer.css +12 -9
  222. package/dist/css/hx-dropdown.css +2 -2
  223. package/dist/css/hx-field-label.css +2 -2
  224. package/dist/css/hx-field.css +2 -2
  225. package/dist/css/hx-file-upload.css +11 -11
  226. package/dist/css/hx-help-text.css +2 -2
  227. package/dist/css/hx-icon-button.css +6 -6
  228. package/dist/css/hx-link.css +2 -2
  229. package/dist/css/hx-menu.css +2 -2
  230. package/dist/css/hx-number-input.css +12 -12
  231. package/dist/css/hx-overflow-menu.css +7 -7
  232. package/dist/css/hx-pagination.css +10 -10
  233. package/dist/css/hx-phi-field.css +2 -2
  234. package/dist/css/hx-popover.css +5 -5
  235. package/dist/css/hx-progress-bar.css +2 -2
  236. package/dist/css/hx-radio-group.css +2 -2
  237. package/dist/css/hx-select.css +11 -8
  238. package/dist/css/hx-side-nav.css +9 -9
  239. package/dist/css/hx-slider.css +9 -9
  240. package/dist/css/hx-split-button.css +15 -15
  241. package/dist/css/hx-split-panel.css +3 -3
  242. package/dist/css/hx-switch.css +4 -4
  243. package/dist/css/hx-text-input.css +7 -7
  244. package/dist/css/hx-textarea.css +7 -7
  245. package/dist/css/hx-time-picker.css +11 -11
  246. package/dist/css/hx-toggle-button.css +17 -14
  247. package/dist/css/hx-tooltip.css +3 -3
  248. package/dist/css/hx-top-nav.css +7 -7
  249. package/dist/css/index.css +1 -1
  250. package/dist/css/manifest.json +162 -163
  251. package/dist/index.js +40 -40
  252. package/dist/shared/hx-accordion-Wt52OOZD.js.map +1 -1
  253. package/dist/shared/{hx-action-bar-BKMADbHj.js → hx-action-bar-6UzmViHI.js} +4 -4
  254. package/dist/shared/hx-action-bar-6UzmViHI.js.map +1 -0
  255. package/dist/shared/hx-alert-D7n94HwI.js.map +1 -1
  256. package/dist/shared/hx-avatar-iLYzu8MJ.js.map +1 -1
  257. package/dist/shared/hx-badge-CVCmMPyW.js.map +1 -1
  258. package/dist/shared/hx-banner-C_He7Tr4.js.map +1 -1
  259. package/dist/shared/{hx-breadcrumb-item-CldCwD1d.js → hx-breadcrumb-item-BgG5RcmA.js} +3 -3
  260. package/dist/shared/hx-breadcrumb-item-BgG5RcmA.js.map +1 -0
  261. package/dist/shared/{hx-button-Ddl-T6T-.js → hx-button-CQZswjtQ.js} +15 -15
  262. package/dist/shared/hx-button-CQZswjtQ.js.map +1 -0
  263. package/dist/shared/hx-button-group-BJOGWoMa.js.map +1 -1
  264. package/dist/shared/{hx-card-ycveujjL.js → hx-card-Dy_FuLfS.js} +23 -23
  265. package/dist/shared/hx-card-Dy_FuLfS.js.map +1 -0
  266. package/dist/shared/hx-carousel-item-D_dCv61-.js.map +1 -1
  267. package/dist/shared/{hx-checkbox-DkkoWoye.js → hx-checkbox-ZKjOF7_3.js} +17 -17
  268. package/dist/shared/{hx-checkbox-DkkoWoye.js.map → hx-checkbox-ZKjOF7_3.js.map} +1 -1
  269. package/dist/shared/{hx-checkbox-group-C3poJ-Zw.js → hx-checkbox-group-XjOBHLiP.js} +3 -3
  270. package/dist/shared/hx-checkbox-group-XjOBHLiP.js.map +1 -0
  271. package/dist/shared/hx-clinical-status-BS5lcddT.js.map +1 -1
  272. package/dist/shared/hx-code-snippet-B7wUKzyb.js.map +1 -1
  273. package/dist/shared/hx-color-picker-DBaKTVLr.js.map +1 -1
  274. package/dist/shared/{hx-combobox-BmgYT7Ar.js → hx-combobox-DLwnvHVd.js} +17 -17
  275. package/dist/shared/hx-combobox-DLwnvHVd.js.map +1 -0
  276. package/dist/shared/hx-container-DVI7sxfX.js.map +1 -1
  277. package/dist/shared/hx-copy-button-8deNUdwP.js.map +1 -1
  278. package/dist/shared/hx-counter-CKfl_g8K.js.map +1 -1
  279. package/dist/shared/{hx-data-table-B6h0RPn0.js → hx-data-table-CnLxo9PH.js} +77 -76
  280. package/dist/shared/hx-data-table-CnLxo9PH.js.map +1 -0
  281. package/dist/shared/{hx-date-picker-Dq2Nb68_.js → hx-date-picker-D7H7CsVH.js} +21 -21
  282. package/dist/shared/hx-date-picker-D7H7CsVH.js.map +1 -0
  283. package/dist/shared/{hx-dialog-CvIlY0Tc.js → hx-dialog-BW-jetzN.js} +33 -33
  284. package/dist/shared/hx-dialog-BW-jetzN.js.map +1 -0
  285. package/dist/shared/{hx-divider-DwpOrzMW.js → hx-divider-CvyUVcp-.js} +13 -13
  286. package/dist/shared/hx-divider-CvyUVcp-.js.map +1 -0
  287. package/dist/shared/{hx-drawer-Cx2ZJhBe.js → hx-drawer-BT52I4tk.js} +13 -10
  288. package/dist/shared/hx-drawer-BT52I4tk.js.map +1 -0
  289. package/dist/shared/{hx-dropdown-BjDrPUq5.js → hx-dropdown-BpVpL6Dz.js} +3 -3
  290. package/dist/shared/{hx-dropdown-BjDrPUq5.js.map → hx-dropdown-BpVpL6Dz.js.map} +1 -1
  291. package/dist/shared/{hx-field-Dp3qQMut.js → hx-field-BX4zE3z5.js} +7 -7
  292. package/dist/shared/hx-field-BX4zE3z5.js.map +1 -0
  293. package/dist/shared/{hx-field-label-BC8QViXv.js → hx-field-label-DtJzb1r3.js} +8 -8
  294. package/dist/shared/hx-field-label-DtJzb1r3.js.map +1 -0
  295. package/dist/shared/{hx-file-upload-B6Yl1u0i.js → hx-file-upload-BNuepoGn.js} +34 -34
  296. package/dist/shared/hx-file-upload-BNuepoGn.js.map +1 -0
  297. package/dist/shared/hx-grid-CXZf3jeK.js.map +1 -1
  298. package/dist/shared/{hx-help-text-D7eytSim.js → hx-help-text-Br3igJv5.js} +7 -7
  299. package/dist/shared/hx-help-text-Br3igJv5.js.map +1 -0
  300. package/dist/shared/hx-icon-CcyDPDYY.js.map +1 -1
  301. package/dist/shared/{hx-icon-button-BHneqPCU.js → hx-icon-button-CqXH5Wwb.js} +7 -7
  302. package/dist/shared/hx-icon-button-CqXH5Wwb.js.map +1 -0
  303. package/dist/shared/hx-image-2gt14zZd.js.map +1 -1
  304. package/dist/shared/{hx-link-BESrWK8M.js → hx-link-Bem4Gn68.js} +8 -8
  305. package/dist/shared/hx-link-Bem4Gn68.js.map +1 -0
  306. package/dist/shared/hx-list-_9qVv02L.js.map +1 -1
  307. package/dist/shared/{hx-menu-divider-Ck-9Os1t.js → hx-menu-divider-DsHWyPHy.js} +37 -37
  308. package/dist/shared/hx-menu-divider-DsHWyPHy.js.map +1 -0
  309. package/dist/shared/hx-meter-TbROk-dw.js.map +1 -1
  310. package/dist/shared/hx-nav-BcYDmjf7.js.map +1 -1
  311. package/dist/shared/{hx-nav-item-pqPasRUm.js → hx-nav-item-BTMMQv6c.js} +34 -30
  312. package/dist/shared/hx-nav-item-BTMMQv6c.js.map +1 -0
  313. package/dist/shared/{hx-number-input-mOIZ3-46.js → hx-number-input-l6jeaGWW.js} +71 -71
  314. package/dist/shared/hx-number-input-l6jeaGWW.js.map +1 -0
  315. package/dist/shared/{hx-overflow-menu-Dprb9lnT.js → hx-overflow-menu-DJ4qpgmi.js} +12 -12
  316. package/dist/shared/hx-overflow-menu-DJ4qpgmi.js.map +1 -0
  317. package/dist/shared/{hx-pagination-AguTQjYC.js → hx-pagination-5FeVFIve.js} +64 -64
  318. package/dist/shared/hx-pagination-5FeVFIve.js.map +1 -0
  319. package/dist/shared/hx-patient-banner-uE6gqLpT.js.map +1 -1
  320. package/dist/shared/{hx-phi-field-BC_XowhC.js → hx-phi-field-DxeWcRm9.js} +3 -3
  321. package/dist/shared/hx-phi-field-DxeWcRm9.js.map +1 -0
  322. package/dist/shared/{hx-popover-B2_203ct.js → hx-popover-C05QcD9m.js} +6 -6
  323. package/dist/shared/hx-popover-C05QcD9m.js.map +1 -0
  324. package/dist/shared/hx-popup-DZXpsJ1R.js.map +1 -1
  325. package/dist/shared/{hx-progress-bar-KjEkEJLy.js → hx-progress-bar-CJdwAeDg.js} +11 -11
  326. package/dist/shared/hx-progress-bar-CJdwAeDg.js.map +1 -0
  327. package/dist/shared/hx-progress-ring-3zMwvrwD.js.map +1 -1
  328. package/dist/shared/hx-prose-BCtK7YL6.js.map +1 -1
  329. package/dist/shared/{hx-radio-BBC5qZgE.js → hx-radio-QHrhL908.js} +11 -11
  330. package/dist/shared/hx-radio-QHrhL908.js.map +1 -0
  331. package/dist/shared/hx-rating-C3E3ENJb.js.map +1 -1
  332. package/dist/shared/{hx-select-CixTo7jp.js → hx-select-BuMvRDkY.js} +47 -44
  333. package/dist/shared/hx-select-BuMvRDkY.js.map +1 -0
  334. package/dist/shared/hx-skeleton-LxkI0pxr.js.map +1 -1
  335. package/dist/shared/{hx-slider-DFHuzF3N.js → hx-slider-wcF_oyNJ.js} +41 -41
  336. package/dist/shared/hx-slider-wcF_oyNJ.js.map +1 -0
  337. package/dist/shared/hx-spinner-BKjuCdZB.js.map +1 -1
  338. package/dist/shared/{hx-split-button-CGcJMmCG.js → hx-split-button-CEkQqbF9.js} +32 -32
  339. package/dist/shared/hx-split-button-CEkQqbF9.js.map +1 -0
  340. package/dist/shared/{hx-split-panel-C-1R10Mc.js → hx-split-panel-BymHlV5e.js} +4 -4
  341. package/dist/shared/hx-split-panel-BymHlV5e.js.map +1 -0
  342. package/dist/shared/hx-stack-DGfcOfWJ.js.map +1 -1
  343. package/dist/shared/hx-stat-BTpykQAt.js.map +1 -1
  344. package/dist/shared/hx-status-indicator-X2QEWNFt.js.map +1 -1
  345. package/dist/shared/hx-step-CRNQlmSo.js.map +1 -1
  346. package/dist/shared/hx-structured-list-CqNbaEXg.js.map +1 -1
  347. package/dist/shared/{hx-switch-DqOD9JR7.js → hx-switch-CbunfMHW.js} +5 -5
  348. package/dist/shared/hx-switch-CbunfMHW.js.map +1 -0
  349. package/dist/shared/hx-tab-panel-BIzKfW5i.js.map +1 -1
  350. package/dist/shared/hx-tag-CgnrNnte.js.map +1 -1
  351. package/dist/shared/hx-td-Bra35cH4.js.map +1 -1
  352. package/dist/shared/hx-text-DMC2CPlL.js.map +1 -1
  353. package/dist/shared/{hx-text-input--q0GH78x.js → hx-text-input-eSPVURd5.js} +8 -8
  354. package/dist/shared/hx-text-input-eSPVURd5.js.map +1 -0
  355. package/dist/shared/{hx-textarea-CK621vSL.js → hx-textarea-C4DjRmo4.js} +12 -12
  356. package/dist/shared/hx-textarea-C4DjRmo4.js.map +1 -0
  357. package/dist/shared/{hx-theme-DfEy-SJA.js → hx-theme-DP4oPU1i.js} +44 -35
  358. package/dist/shared/hx-theme-DP4oPU1i.js.map +1 -0
  359. package/dist/shared/{hx-time-picker-tPUfgElQ.js → hx-time-picker-BtbHX7A4.js} +28 -28
  360. package/dist/shared/hx-time-picker-BtbHX7A4.js.map +1 -0
  361. package/dist/shared/{hx-toggle-button-L-uBJr-a.js → hx-toggle-button-FOvw-ebx.js} +26 -23
  362. package/dist/shared/hx-toggle-button-FOvw-ebx.js.map +1 -0
  363. package/dist/shared/{hx-tooltip-B_zfKvwc.js → hx-tooltip-BoZi2crX.js} +4 -4
  364. package/dist/shared/hx-tooltip-BoZi2crX.js.map +1 -0
  365. package/dist/shared/{hx-top-nav-CATbRvIv.js → hx-top-nav-Cd9zvv1B.js} +20 -20
  366. package/dist/shared/hx-top-nav-Cd9zvv1B.js.map +1 -0
  367. package/dist/shared/hx-tree-item-A45WCiBu.js.map +1 -1
  368. package/dist/shared/toast-factory-BPPnG3mM.js.map +1 -1
  369. package/figma-inventory.json +8526 -511
  370. package/package.json +2 -2
  371. package/dist/shared/hx-action-bar-BKMADbHj.js.map +0 -1
  372. package/dist/shared/hx-breadcrumb-item-CldCwD1d.js.map +0 -1
  373. package/dist/shared/hx-button-Ddl-T6T-.js.map +0 -1
  374. package/dist/shared/hx-card-ycveujjL.js.map +0 -1
  375. package/dist/shared/hx-checkbox-group-C3poJ-Zw.js.map +0 -1
  376. package/dist/shared/hx-combobox-BmgYT7Ar.js.map +0 -1
  377. package/dist/shared/hx-data-table-B6h0RPn0.js.map +0 -1
  378. package/dist/shared/hx-date-picker-Dq2Nb68_.js.map +0 -1
  379. package/dist/shared/hx-dialog-CvIlY0Tc.js.map +0 -1
  380. package/dist/shared/hx-divider-DwpOrzMW.js.map +0 -1
  381. package/dist/shared/hx-drawer-Cx2ZJhBe.js.map +0 -1
  382. package/dist/shared/hx-field-Dp3qQMut.js.map +0 -1
  383. package/dist/shared/hx-field-label-BC8QViXv.js.map +0 -1
  384. package/dist/shared/hx-file-upload-B6Yl1u0i.js.map +0 -1
  385. package/dist/shared/hx-help-text-D7eytSim.js.map +0 -1
  386. package/dist/shared/hx-icon-button-BHneqPCU.js.map +0 -1
  387. package/dist/shared/hx-link-BESrWK8M.js.map +0 -1
  388. package/dist/shared/hx-menu-divider-Ck-9Os1t.js.map +0 -1
  389. package/dist/shared/hx-nav-item-pqPasRUm.js.map +0 -1
  390. package/dist/shared/hx-number-input-mOIZ3-46.js.map +0 -1
  391. package/dist/shared/hx-overflow-menu-Dprb9lnT.js.map +0 -1
  392. package/dist/shared/hx-pagination-AguTQjYC.js.map +0 -1
  393. package/dist/shared/hx-phi-field-BC_XowhC.js.map +0 -1
  394. package/dist/shared/hx-popover-B2_203ct.js.map +0 -1
  395. package/dist/shared/hx-progress-bar-KjEkEJLy.js.map +0 -1
  396. package/dist/shared/hx-radio-BBC5qZgE.js.map +0 -1
  397. package/dist/shared/hx-select-CixTo7jp.js.map +0 -1
  398. package/dist/shared/hx-slider-DFHuzF3N.js.map +0 -1
  399. package/dist/shared/hx-split-button-CGcJMmCG.js.map +0 -1
  400. package/dist/shared/hx-split-panel-C-1R10Mc.js.map +0 -1
  401. package/dist/shared/hx-switch-DqOD9JR7.js.map +0 -1
  402. package/dist/shared/hx-text-input--q0GH78x.js.map +0 -1
  403. package/dist/shared/hx-textarea-CK621vSL.js.map +0 -1
  404. package/dist/shared/hx-theme-DfEy-SJA.js.map +0 -1
  405. package/dist/shared/hx-time-picker-tPUfgElQ.js.map +0 -1
  406. package/dist/shared/hx-toggle-button-L-uBJr-a.js.map +0 -1
  407. package/dist/shared/hx-tooltip-B_zfKvwc.js.map +0 -1
  408. package/dist/shared/hx-top-nav-CATbRvIv.js.map +0 -1
@@ -1,13 +1,13 @@
1
- import { css as g, nothing as p, html as f } from "lit";
2
- import { property as n, state as b, query as x, customElement as _ } from "lit/decorators.js";
1
+ import { css as x, nothing as p, html as f } from "lit";
2
+ import { property as n, state as v, query as g, customElement as _ } from "lit/decorators.js";
3
3
  import { classMap as y } from "lit/directives/class-map.js";
4
- import { ifDefined as v } from "lit/directives/if-defined.js";
4
+ import { ifDefined as b } from "lit/directives/if-defined.js";
5
5
  import { repeat as w } from "lit/directives/repeat.js";
6
6
  import { F as z } from "./FormMixin-B8PXk5RQ.js";
7
7
  import { m as $ } from "./aria-delegation-Doq6RRUy.js";
8
8
  import { c as F } from "./id-counter-DuX8vsui.js";
9
9
  import { H as D } from "./helix-element-BNEYeiys.js";
10
- const S = g`
10
+ const S = x`
11
11
  :host {
12
12
  display: block;
13
13
  }
@@ -36,7 +36,7 @@ const S = g`
36
36
  gap: var(--hx-space-1, 0.25rem);
37
37
  font-size: var(--hx-font-size-sm, 0.875rem);
38
38
  font-weight: var(--hx-font-weight-medium, 500);
39
- color: var(--hx-color-neutral-700, #334155);
39
+ color: var(--hx-color-text-strong, #334155);
40
40
  line-height: var(--hx-line-height-normal, 1.5);
41
41
  }
42
42
 
@@ -51,9 +51,9 @@ const S = g`
51
51
  min-height: var(--hx-space-32, 8rem);
52
52
  padding: var(--hx-space-6, 1.5rem) var(--hx-space-4, 1rem);
53
53
  border: var(--hx-border-width-thin, 1px) dashed
54
- var(--hx-file-upload-dropzone-border-color, var(--hx-color-neutral-300, #cbd5e1));
54
+ var(--hx-file-upload-dropzone-border-color, var(--hx-color-border-strong, #cbd5e1));
55
55
  border-radius: var(--hx-file-upload-dropzone-border-radius, var(--hx-border-radius-lg, 0.5rem));
56
- background-color: var(--hx-file-upload-dropzone-bg, var(--hx-color-neutral-50, #f8fafc));
56
+ background-color: var(--hx-file-upload-dropzone-bg, var(--hx-color-surface-raised, #f8fafc));
57
57
  cursor: pointer;
58
58
  text-align: center;
59
59
  transition:
@@ -61,7 +61,7 @@ const S = g`
61
61
  background-color var(--hx-transition-fast, 150ms ease),
62
62
  box-shadow var(--hx-transition-fast, 150ms ease);
63
63
  user-select: none;
64
- color: var(--hx-color-neutral-600, #475569);
64
+ color: var(--hx-color-text-secondary, #475569);
65
65
  font-size: var(--hx-font-size-sm, 0.875rem);
66
66
  }
67
67
 
@@ -85,7 +85,7 @@ const S = g`
85
85
  color-mix(
86
86
  in srgb,
87
87
  var(--hx-color-primary-500, #2563eb) 8%,
88
- var(--hx-color-neutral-0, #ffffff)
88
+ var(--hx-color-surface-default, #ffffff)
89
89
  )
90
90
  );
91
91
  border-style: solid;
@@ -137,9 +137,9 @@ const S = g`
137
137
  flex-direction: column;
138
138
  gap: var(--hx-space-1, 0.25rem);
139
139
  padding: var(--hx-space-2, 0.5rem) var(--hx-space-3, 0.75rem);
140
- border: var(--hx-border-width-thin, 1px) solid var(--hx-color-neutral-200, #e2e8f0);
140
+ border: var(--hx-border-width-thin, 1px) solid var(--hx-color-border-default, #e2e8f0);
141
141
  border-radius: var(--hx-border-radius-md, 0.375rem);
142
- background-color: var(--hx-color-neutral-0, #ffffff);
142
+ background-color: var(--hx-color-surface-default, #ffffff);
143
143
  }
144
144
 
145
145
  .file-item__row {
@@ -152,7 +152,7 @@ const S = g`
152
152
  flex: 1;
153
153
  font-size: var(--hx-font-size-sm, 0.875rem);
154
154
  font-weight: var(--hx-font-weight-medium, 500);
155
- color: var(--hx-color-neutral-800, #1e293b);
155
+ color: var(--hx-color-text-strong, #1e293b);
156
156
  overflow: hidden;
157
157
  text-overflow: ellipsis;
158
158
  white-space: nowrap;
@@ -161,7 +161,7 @@ const S = g`
161
161
  .file-item__size {
162
162
  flex-shrink: 0;
163
163
  font-size: var(--hx-font-size-xs, 0.75rem);
164
- color: var(--hx-color-neutral-500, #64748b);
164
+ color: var(--hx-color-text-muted, #64748b);
165
165
  }
166
166
 
167
167
  .file-item__remove {
@@ -175,7 +175,7 @@ const S = g`
175
175
  border: none;
176
176
  border-radius: var(--hx-border-radius-sm, 0.25rem);
177
177
  background: transparent;
178
- color: var(--hx-color-neutral-500, #64748b);
178
+ color: var(--hx-color-text-muted, #64748b);
179
179
  cursor: pointer;
180
180
  line-height: 1;
181
181
  transition:
@@ -208,7 +208,7 @@ const S = g`
208
208
  .progress-track {
209
209
  width: 100%;
210
210
  height: var(--hx-file-upload-progress-height, var(--hx-space-1, 0.25rem));
211
- background-color: var(--hx-color-neutral-200, #e2e8f0);
211
+ background-color: var(--hx-color-border-default, #e2e8f0);
212
212
  border-radius: var(--hx-border-radius-full, 9999px);
213
213
  overflow: hidden;
214
214
  }
@@ -298,8 +298,8 @@ const S = g`
298
298
  }
299
299
  `;
300
300
  var k = Object.defineProperty, L = Object.getOwnPropertyDescriptor, s = (e, r, t, i) => {
301
- for (var l = i > 1 ? void 0 : i ? L(r, t) : r, a = e.length - 1, h; a >= 0; a--)
302
- (h = e[a]) && (l = (i ? h(r, t, l) : h(l)) || l);
301
+ for (var l = i > 1 ? void 0 : i ? L(r, t) : r, a = e.length - 1, d; a >= 0; a--)
302
+ (d = e[a]) && (l = (i ? d(r, t, l) : d(l)) || l);
303
303
  return i && l && k(r, t, l), l;
304
304
  };
305
305
  const C = F("hx-file-upload");
@@ -414,8 +414,8 @@ let o = class extends z($(D)) {
414
414
  detail: { message: l.join(" "), files: i }
415
415
  })
416
416
  ), t.length === 0) return;
417
- const a = this.multiple ? this._files.length : 0, h = this.maxFiles > 0 ? Math.max(0, this.maxFiles - a) : t.length, d = t.slice(0, h);
418
- if (d.length === 0 && this.maxFiles > 0) {
417
+ const a = this.multiple ? this._files.length : 0, d = this.maxFiles > 0 ? Math.max(0, this.maxFiles - a) : t.length, h = t.slice(0, d);
418
+ if (h.length === 0 && this.maxFiles > 0) {
419
419
  this.dispatchEvent(
420
420
  new CustomEvent("hx-error", {
421
421
  bubbles: !0,
@@ -428,17 +428,17 @@ let o = class extends z($(D)) {
428
428
  );
429
429
  return;
430
430
  }
431
- if (d.length > 0) {
432
- const c = d.map((m) => ({ file: m, progress: 0 }));
431
+ if (h.length > 0) {
432
+ const c = h.map((m) => ({ file: m, progress: 0 }));
433
433
  this.multiple ? this._files = [...this._files, ...c] : this._files = c, this._handleInteractionInput(), this.dispatchEvent(
434
434
  new CustomEvent("hx-upload", {
435
435
  bubbles: !0,
436
436
  composed: !0,
437
- detail: { files: d }
437
+ detail: { files: h }
438
438
  })
439
439
  );
440
440
  }
441
- const u = t.slice(h);
441
+ const u = t.slice(d);
442
442
  u.length > 0 && this.maxFiles > 0 && this.dispatchEvent(
443
443
  new CustomEvent("hx-error", {
444
444
  bubbles: !0,
@@ -529,8 +529,8 @@ let o = class extends z($(D)) {
529
529
  } else {
530
530
  const a = (l = this.shadowRoot) == null ? void 0 : l.querySelectorAll(".file-item__remove");
531
531
  if (a && a.length > 0) {
532
- const h = e < this._files.length ? e : this._files.length - 1, d = a[h];
533
- d && d.focus();
532
+ const d = e < this._files.length ? e : this._files.length - 1, h = a[d];
533
+ h && h.focus();
534
534
  }
535
535
  }
536
536
  }).catch(() => {
@@ -619,13 +619,13 @@ let o = class extends z($(D)) {
619
619
  id=${this._dropzoneId}
620
620
  role="button"
621
621
  tabindex=${this.disabled ? "-1" : "0"}
622
- aria-label=${v(this._effectiveLabel || (this.label ? void 0 : t))}
623
- aria-labelledby=${v(
622
+ aria-label=${b(this._effectiveLabel || (this.label ? void 0 : t))}
623
+ aria-labelledby=${b(
624
624
  !this._effectiveLabel && this.label ? this._labelId : void 0
625
625
  )}
626
626
  aria-disabled=${this.disabled ? "true" : p}
627
627
  aria-invalid=${e ? "true" : p}
628
- aria-describedby=${v(e ? this._errorId : void 0)}
628
+ aria-describedby=${b(e ? this._errorId : void 0)}
629
629
  @click=${this._handleDropzoneClick}
630
630
  @keydown=${this._handleDropzoneKeyDown}
631
631
  @dragover=${this._handleDragOver}
@@ -640,7 +640,7 @@ let o = class extends z($(D)) {
640
640
  type="file"
641
641
  tabindex="-1"
642
642
  aria-hidden="true"
643
- accept=${v(this.accept || void 0)}
643
+ accept=${b(this.accept || void 0)}
644
644
  ?multiple=${this.multiple}
645
645
  ?disabled=${this.disabled}
646
646
  @change=${this._handleFileInputChange}
@@ -704,16 +704,16 @@ s([
704
704
  n({ attribute: "label-drag-detected" })
705
705
  ], o.prototype, "labelDragDetected", 2);
706
706
  s([
707
- b()
707
+ v()
708
708
  ], o.prototype, "_files", 2);
709
709
  s([
710
- b()
710
+ v()
711
711
  ], o.prototype, "_dragOver", 2);
712
712
  s([
713
- b()
713
+ v()
714
714
  ], o.prototype, "_hasFileListSlot", 2);
715
715
  s([
716
- x(".file-input")
716
+ g(".file-input")
717
717
  ], o.prototype, "_fileInput", 2);
718
718
  o = s([
719
719
  _("hx-file-upload")
@@ -721,4 +721,4 @@ o = s([
721
721
  export {
722
722
  o as H
723
723
  };
724
- //# sourceMappingURL=hx-file-upload-B6Yl1u0i.js.map
724
+ //# sourceMappingURL=hx-file-upload-BNuepoGn.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hx-file-upload-BNuepoGn.js","sources":["../../src/components/hx-file-upload/hx-file-upload.styles.ts","../../src/components/hx-file-upload/hx-file-upload.ts"],"sourcesContent":["import { css } from 'lit';\n\nexport const helixFileUploadStyles = css`\n :host {\n display: block;\n }\n\n :host([disabled]) {\n opacity: var(--hx-opacity-disabled, 0.5);\n pointer-events: none;\n }\n\n * {\n box-sizing: border-box;\n }\n\n .field {\n display: flex;\n flex-direction: column;\n gap: var(--hx-space-2, 0.5rem);\n font-family: var(--hx-file-upload-font-family, var(--hx-font-family-sans, sans-serif));\n }\n\n /* ─── Label ─── */\n\n .field__label {\n display: flex;\n align-items: baseline;\n gap: var(--hx-space-1, 0.25rem);\n font-size: var(--hx-font-size-sm, 0.875rem);\n font-weight: var(--hx-font-weight-medium, 500);\n color: var(--hx-color-text-strong, #334155);\n line-height: var(--hx-line-height-normal, 1.5);\n }\n\n /* ─── Dropzone ─── */\n\n .dropzone {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n gap: var(--hx-space-2, 0.5rem);\n min-height: var(--hx-space-32, 8rem);\n padding: var(--hx-space-6, 1.5rem) var(--hx-space-4, 1rem);\n border: var(--hx-border-width-thin, 1px) dashed\n var(--hx-file-upload-dropzone-border-color, var(--hx-color-border-strong, #cbd5e1));\n border-radius: var(--hx-file-upload-dropzone-border-radius, var(--hx-border-radius-lg, 0.5rem));\n background-color: var(--hx-file-upload-dropzone-bg, var(--hx-color-surface-raised, #f8fafc));\n cursor: pointer;\n text-align: center;\n transition:\n border-color var(--hx-transition-fast, 150ms ease),\n background-color var(--hx-transition-fast, 150ms ease),\n box-shadow var(--hx-transition-fast, 150ms ease);\n user-select: none;\n color: var(--hx-color-text-secondary, #475569);\n font-size: var(--hx-font-size-sm, 0.875rem);\n }\n\n .dropzone:focus-visible {\n outline: var(--hx-focus-ring-width, 2px) solid\n var(\n --hx-file-upload-focus-ring-color,\n var(--hx-focus-ring-color, var(--hx-color-primary-500))\n );\n outline-offset: var(--hx-focus-ring-offset, 2px);\n border-color: var(\n --hx-file-upload-focus-ring-color,\n var(--hx-focus-ring-color, var(--hx-color-primary-500))\n );\n }\n\n .dropzone--drag-over {\n border-color: var(--hx-color-primary-500, #2563eb);\n background-color: var(\n --hx-file-upload-dropzone-active-bg,\n color-mix(\n in srgb,\n var(--hx-color-primary-500, #2563eb) 8%,\n var(--hx-color-surface-default, #ffffff)\n )\n );\n border-style: solid;\n }\n\n .dropzone--error {\n border-color: var(--hx-file-upload-error-color, var(--hx-color-error-500, #dc2626));\n }\n\n @media (prefers-reduced-motion: reduce) {\n .dropzone {\n transition: none;\n }\n }\n\n /* ─── Hidden file input ─── */\n\n .file-input {\n position: absolute;\n width: 1px;\n height: 1px;\n padding: 0;\n margin: -1px;\n overflow: hidden;\n clip: rect(0, 0, 0, 0);\n white-space: nowrap;\n border-width: 0;\n }\n\n /* ─── File list ─── */\n\n .file-list {\n display: flex;\n flex-direction: column;\n gap: var(--hx-space-2, 0.5rem);\n list-style: none;\n margin: 0;\n padding: 0;\n }\n\n .file-list:empty {\n display: none;\n }\n\n /* ─── File item ─── */\n\n .file-item {\n display: flex;\n flex-direction: column;\n gap: var(--hx-space-1, 0.25rem);\n padding: var(--hx-space-2, 0.5rem) var(--hx-space-3, 0.75rem);\n border: var(--hx-border-width-thin, 1px) solid var(--hx-color-border-default, #e2e8f0);\n border-radius: var(--hx-border-radius-md, 0.375rem);\n background-color: var(--hx-color-surface-default, #ffffff);\n }\n\n .file-item__row {\n display: flex;\n align-items: center;\n gap: var(--hx-space-2, 0.5rem);\n }\n\n .file-item__name {\n flex: 1;\n font-size: var(--hx-font-size-sm, 0.875rem);\n font-weight: var(--hx-font-weight-medium, 500);\n color: var(--hx-color-text-strong, #1e293b);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n }\n\n .file-item__size {\n flex-shrink: 0;\n font-size: var(--hx-font-size-xs, 0.75rem);\n color: var(--hx-color-text-muted, #64748b);\n }\n\n .file-item__remove {\n flex-shrink: 0;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n min-width: 44px;\n min-height: 44px;\n padding: var(--hx-space-1, 0.25rem);\n border: none;\n border-radius: var(--hx-border-radius-sm, 0.25rem);\n background: transparent;\n color: var(--hx-color-text-muted, #64748b);\n cursor: pointer;\n line-height: 1;\n transition:\n color var(--hx-transition-fast, 150ms ease),\n background-color var(--hx-transition-fast, 150ms ease);\n }\n\n .file-item__remove:hover {\n color: var(--hx-file-upload-error-color, var(--hx-color-error-text, #b91c1c));\n background-color: color-mix(in srgb, var(--hx-color-error-500, #dc2626) 8%, transparent);\n }\n\n .file-item__remove:focus-visible {\n outline: var(--hx-focus-ring-width, 2px) solid\n var(\n --hx-file-upload-focus-ring-color,\n var(--hx-focus-ring-color, var(--hx-color-primary-500))\n );\n outline-offset: var(--hx-focus-ring-offset, 2px);\n }\n\n @media (prefers-reduced-motion: reduce) {\n .file-item__remove {\n transition: none;\n }\n }\n\n /* ─── Progress bar ─── */\n\n .progress-track {\n width: 100%;\n height: var(--hx-file-upload-progress-height, var(--hx-space-1, 0.25rem));\n background-color: var(--hx-color-border-default, #e2e8f0);\n border-radius: var(--hx-border-radius-full, 9999px);\n overflow: hidden;\n }\n\n .progress-bar {\n height: 100%;\n width: 100%;\n background-color: var(--hx-file-upload-progress-color, var(--hx-color-primary-500, #2563eb));\n border-radius: inherit;\n transform-origin: left center;\n transform: scaleX(var(--_progress-ratio, 0));\n transition: transform var(--hx-transition-fast, 150ms ease);\n }\n\n @media (prefers-reduced-motion: reduce) {\n .progress-bar {\n transition: none;\n }\n }\n\n /* ─── Screen-reader only utility ─── */\n\n .sr-only {\n position: absolute;\n width: 1px;\n height: 1px;\n padding: 0;\n margin: -1px;\n overflow: hidden;\n clip: rect(0, 0, 0, 0);\n white-space: nowrap;\n border-width: 0;\n }\n\n /* ─── Error message ─── */\n\n .field__error {\n font-size: var(--hx-font-size-xs, 0.75rem);\n color: var(--hx-file-upload-error-color, var(--hx-color-error-text, #b91c1c));\n line-height: var(--hx-line-height-normal, 1.5);\n }\n\n /* ─── Forced colors (Windows High Contrast / Forced Colors Mode) ─── */\n\n @media (forced-colors: active) {\n .dropzone {\n border: 2px dashed ButtonText;\n background-color: Canvas;\n color: ButtonText;\n }\n\n .dropzone--drag-over {\n border: 2px solid Highlight;\n outline: none;\n background-color: Canvas;\n }\n\n .dropzone--error {\n border: 2px solid LinkText;\n }\n\n .dropzone:focus-visible {\n outline: 2px solid Highlight;\n outline-offset: 2px;\n }\n\n .progress-bar {\n background: Highlight;\n forced-color-adjust: none;\n }\n\n .file-item__remove:hover {\n outline: 2px solid Highlight;\n background-color: transparent;\n color: ButtonText;\n }\n\n .file-item__remove:focus-visible {\n outline: 2px solid Highlight;\n }\n\n :host([disabled]) .dropzone {\n border-color: GrayText;\n color: GrayText;\n opacity: 1;\n }\n }\n`;\n","import { html, nothing, type PropertyValues } from 'lit';\nimport '../../utilities/document-token-adoption.js';\nimport { customElement, property, query, state } from 'lit/decorators.js';\nimport { HelixElement, createIdCounter } from '../../base/index.js';\nimport { classMap } from 'lit/directives/class-map.js';\nimport { ifDefined } from 'lit/directives/if-defined.js';\nimport { repeat } from 'lit/directives/repeat.js';\nimport { mixinDelegatesAria } from '../../mixins/index.js';\nimport { FormMixin } from '../../mixins/FormMixin.js';\nimport { helixFileUploadStyles } from './hx-file-upload.styles.js';\n\nconst _nextFileUploadId = createIdCounter('hx-file-upload');\n\ninterface FileEntry {\n file: File;\n progress: number;\n}\n\n/** Detail for the hx-upload event dispatched by hx-file-upload. */\nexport interface HxFileUploadDetail {\n files: File[];\n}\n\n/** Detail for the hx-remove event dispatched by hx-file-upload. */\nexport interface HxFileRemoveDetail {\n file: File;\n index: number;\n}\n\n/** Detail for the hx-error event dispatched by hx-file-upload. */\nexport interface HxFileErrorDetail {\n message: string;\n files: File[];\n}\n\n/**\n * A drag-and-drop file upload component with client-side validation,\n * file list management, per-file progress, and native form association.\n *\n * @summary Form-associated file upload dropzone with drag-and-drop, validation, and progress tracking.\n *\n * @tag hx-file-upload\n *\n * @slot - Default dropzone content. Replaces the built-in \"Drag files here or click to browse\" prompt.\n * @slot file-list - Custom file list display. When provided, the built-in file list is hidden.\n *\n * @fires {CustomEvent<{files: File[]}>} hx-upload - Dispatched when valid files are selected via drag-and-drop or the file picker.\n * @fires {CustomEvent<{file: File, index: number}>} hx-remove - Dispatched when a file is removed from the list.\n * @fires {CustomEvent<{message: string, files: File[]}>} hx-error - Dispatched when file validation fails (type or size constraint).\n *\n * @csspart dropzone - The drag-and-drop target area.\n * @csspart file-list - The container wrapping the list of selected files.\n * @csspart file-item - An individual file entry in the list.\n * @csspart progress - The progress bar track for a file item.\n * @csspart label - The visible label element.\n * @csspart error - The error message container below the dropzone.\n *\n * @cssprop [--hx-file-upload-dropzone-bg=var(--hx-color-neutral-50)] - Dropzone background color.\n * @cssprop [--hx-file-upload-dropzone-border-color=var(--hx-color-neutral-300)] - Dropzone border color.\n * @cssprop [--hx-file-upload-dropzone-border-radius=var(--hx-border-radius-lg)] - Dropzone border radius.\n * @cssprop [--hx-file-upload-dropzone-active-bg] - Dropzone background when a file is dragged over.\n * @cssprop [--hx-file-upload-progress-color=var(--hx-color-primary-500)] - Progress bar fill color.\n * @cssprop [--hx-file-upload-error-color=var(--hx-color-error-500)] - Error state and remove-button hover color.\n * @cssprop [--hx-opacity-disabled] - Opacity.\n * @cssprop [--hx-space-2] - Spacing token.\n * @cssprop [--hx-file-upload-font-family=var(--hx-font-family-sans)] - CSS custom property.\n * @cssprop [--hx-font-family-sans] - Font family.\n * @cssprop [--hx-space-1] - Spacing token.\n * @cssprop [--hx-font-size-sm] - Font size.\n * @cssprop [--hx-font-weight-medium] - Font weight.\n * @cssprop [--hx-color-neutral-700] - Color.\n * @cssprop [--hx-line-height-normal] - Line height.\n * @cssprop [--hx-space-32] - Spacing token.\n * @cssprop [--hx-space-6] - Spacing token.\n * @cssprop [--hx-space-4] - Spacing token.\n * @cssprop [--hx-border-width-thin] - Width.\n * @cssprop [--hx-color-neutral-300] - Color.\n * @cssprop [--hx-border-radius-lg] - CSS custom property.\n * @cssprop [--hx-color-neutral-50] - Color.\n * @cssprop [--hx-transition-fast] - Transition timing.\n * @cssprop [--hx-color-neutral-600] - Color.\n * @cssprop [--hx-focus-ring-width] - Width.\n * @cssprop [--hx-file-upload-focus-ring-color] - Color.\n * @cssprop [--hx-focus-ring-color] - Color.\n * @cssprop [--hx-color-primary-500] - Color.\n * @cssprop [--hx-focus-ring-offset] - CSS custom property.\n * @cssprop [--hx-color-neutral-0] - Color.\n * @cssprop [--hx-color-error-500] - Color.\n * @cssprop [--hx-space-3] - Spacing token.\n * @cssprop [--hx-color-neutral-200] - Color.\n * @cssprop [--hx-border-radius-md] - CSS custom property.\n * @cssprop [--hx-color-neutral-800] - Color.\n * @cssprop [--hx-font-size-xs] - Font size.\n * @cssprop [--hx-color-neutral-500] - Color.\n * @cssprop [--hx-border-radius-sm] - CSS custom property.\n * @cssprop [--hx-color-error-text] - Color.\n * @cssprop [--hx-file-upload-progress-height=var(--hx-space-1)] - Height.\n * @cssprop [--hx-border-radius-full] - CSS custom property.\n */\n@customElement('hx-file-upload')\nexport class HelixFileUpload extends FormMixin(mixinDelegatesAria(HelixElement)) {\n static override styles = [helixFileUploadStyles];\n\n // ─── Form Association ───\n\n /** Marks this element as form-associated for ElementInternals support. @internal */\n static override formAssociated = true;\n\n // ─── Properties ───\n\n /**\n * The form field name used during form submission.\n * @attr name\n */\n @property({ type: String, reflect: true })\n name = '';\n\n /**\n * Accepted file types as a comma-separated list of MIME types or extensions.\n * Mirrors the native `<input type=\"file\" accept>` attribute.\n * @attr accept\n */\n @property({ type: String })\n accept = '';\n\n /**\n * Maximum allowed file size in bytes. 0 means unlimited.\n * @attr max-size\n */\n @property({ type: Number, attribute: 'max-size' })\n maxSize = 0;\n\n /**\n * Maximum number of files that can be selected. 0 means unlimited.\n * @attr max-files\n */\n @property({ type: Number, attribute: 'max-files' })\n maxFiles = 0;\n\n /**\n * Whether multiple files may be selected at once.\n * @attr multiple\n */\n @property({ type: Boolean })\n multiple = false;\n\n /**\n * Visible label text for the dropzone.\n * @attr label\n */\n @property({ type: String })\n label = '';\n\n /**\n * Whether the component is disabled.\n * @attr disabled\n */\n @property({ type: Boolean, reflect: true })\n disabled = false;\n\n /**\n * Error message displayed below the dropzone. Also puts the dropzone in an error visual state.\n * @attr error\n */\n @property({ type: String })\n error = '';\n\n /**\n * Instructional text shown in the dropzone when no custom slot content is provided.\n * Also used as the accessible label for the dropzone.\n * @attr label-dropzone\n */\n @property({ type: String, attribute: 'label-dropzone' })\n labelDropzone = 'Drag files here or click to browse';\n\n /** Accessible label for the selected files list. */\n @property({ type: String, attribute: 'label-file-list' })\n labelFileList = 'Selected files';\n\n /**\n * Accessible label for the dropzone when no visible label text is provided.\n * Falls back to `label-dropzone` prop value, then a default string.\n *\n * Accepts both `accessible-label` and the standard `aria-label` HTML attribute.\n * `accessible-label` takes precedence when both are set.\n *\n * @attr accessible-label\n */\n @property({ type: String, attribute: 'accessible-label' })\n accessibleLabel: string = '';\n\n /**\n * Returns the effective label for the dropzone, checking accessible-label first,\n * then the aria-label attribute, falling back to empty string.\n * @internal\n */\n private get _effectiveLabel(): string {\n return this.accessibleLabel?.trim() || this.ariaLabel?.trim() || '';\n }\n\n /**\n * Generates upload progress description for screen readers.\n * @param name - file name\n * @param progress - progress percentage 0-100\n */\n @property({ attribute: false })\n labelUploadProgress: (name: string, progress: number) => string = (name, progress) =>\n `Upload progress for ${name}: ${progress}%`;\n\n /**\n * Screen reader announcement when file drag detected. Override for i18n.\n * @attr label-drag-detected\n */\n @property({ attribute: 'label-drag-detected' })\n labelDragDetected = 'File detected. Release to upload.';\n\n // ─── Internal State ───\n\n /** The list of currently selected file entries, each with a file reference and upload progress. @internal */\n @state() private _files: FileEntry[] = [];\n /** Whether a file is currently being dragged over the dropzone. @internal */\n @state() private _dragOver = false;\n /** Whether the named file-list slot contains projected content. @internal */\n @state() private _hasFileListSlot = false;\n\n // ─── Internal References ───\n\n /** Reference to the hidden native file input element used to open the OS file picker. @internal */\n @query('.file-input')\n private _fileInput: HTMLInputElement | null | undefined;\n\n // ─── Stable IDs ───\n\n /** @internal */\n private readonly _baseId = _nextFileUploadId();\n /** @internal */\n private readonly _labelId = `${this._baseId}-label`;\n /** @internal */\n private readonly _errorId = `${this._baseId}-error`;\n /** @internal */\n private readonly _dropzoneId = `${this._baseId}-dropzone`;\n /** @internal */\n private readonly _liveId = `${this._baseId}-live`;\n\n // ─── Slot Handling ───\n\n /** @internal */\n private _handleFileListSlotChange(e: Event): void {\n const slot = e.target as HTMLSlotElement;\n this._hasFileListSlot = slot.assignedElements({ flatten: true }).length > 0;\n }\n\n // ─── Lifecycle ───\n\n override updated(changedProperties: PropertyValues<this>): void {\n super.updated(changedProperties);\n if (changedProperties.has('_files' as keyof HelixFileUpload) || changedProperties.has('name')) {\n this._syncFormValue();\n }\n // Force screen reader re-announcement when error text changes (a11y-v3-005)\n if (changedProperties.has('error') && this.error) {\n const errorEl = this.shadowRoot?.querySelector('[role=\"alert\"]');\n if (errorEl) {\n const msg = this.error;\n requestAnimationFrame(() => {\n errorEl.textContent = '';\n requestAnimationFrame(() => {\n errorEl.textContent = msg;\n });\n });\n }\n }\n }\n\n // ─── Form Integration ───\n\n /** @internal */\n protected override _onFormReset(): void {\n this._files = [];\n this._internals.setFormValue(null);\n this._resetInteractionState();\n }\n\n /** @internal */\n protected override _onFormDisabled(disabled: boolean): void {\n this.disabled = disabled;\n }\n\n /** @internal */\n protected override _onFormStateRestore(\n _state: File | string | FormData | null,\n _mode: 'restore' | 'autocomplete',\n ): void {\n if (_mode === 'restore' || _mode === 'autocomplete') {\n this._files = [];\n this._internals.setFormValue(null);\n }\n }\n\n /** @internal */\n private _syncFormValue(): void {\n if (this._files.length === 0) {\n this._internals.setFormValue(null);\n return;\n }\n\n if (this._files.length === 1) {\n // Single file — pass directly as File (accepted by setFormValue)\n const firstEntry = this._files[0];\n if (firstEntry) {\n this._internals.setFormValue(firstEntry.file);\n }\n return;\n }\n\n // Multiple files — use FormData so all files are submitted under the same name\n const formData = new FormData();\n for (const entry of this._files) {\n formData.append(this.name, entry.file, entry.file.name);\n }\n this._internals.setFormValue(formData);\n }\n\n // ─── Validation ───\n\n /**\n * Validates a file against `accept` and `maxSize` constraints.\n * Returns null on success, or an error message string on failure.\n */\n /** @internal */\n private _validateFile(file: File): string | null {\n if (this.accept) {\n const accepted = this._isAccepted(file);\n if (!accepted) {\n return `\"${file.name}\" has an unsupported file type. Accepted types: ${this.accept}`;\n }\n }\n\n if (this.maxSize > 0 && file.size > this.maxSize) {\n const maxMb = (this.maxSize / (1024 * 1024)).toFixed(1);\n return `\"${file.name}\" exceeds the maximum size of ${maxMb} MB.`;\n }\n\n return null;\n }\n\n /**\n * Checks whether a file is accepted given the `accept` attribute value.\n * Handles MIME types (e.g. \"image/png\"), wildcard MIME types (e.g. \"image/*\"),\n * and extensions (e.g. \".pdf\").\n */\n /** @internal */\n private _isAccepted(file: File): boolean {\n const tokens = this.accept.split(',').map((t) => t.trim().toLowerCase());\n\n for (const token of tokens) {\n if (token.startsWith('.')) {\n // Extension match\n if (file.name.toLowerCase().endsWith(token)) return true;\n } else if (token.endsWith('/*')) {\n // Wildcard MIME type e.g. \"image/*\"\n const baseType = token.slice(0, -2);\n if (file.type.toLowerCase().startsWith(baseType)) return true;\n } else {\n // Exact MIME type\n if (file.type.toLowerCase() === token) return true;\n }\n }\n\n return false;\n }\n\n // ─── File Processing ───\n\n /** @internal */\n private _processFiles(rawFiles: File[]): void {\n if (this.disabled) return;\n\n const candidateFiles = this.multiple ? rawFiles : rawFiles.slice(0, 1);\n const validFiles: File[] = [];\n const invalidFiles: File[] = [];\n const errorMessages: string[] = [];\n\n for (const file of candidateFiles) {\n const validationError = this._validateFile(file);\n if (validationError) {\n invalidFiles.push(file);\n errorMessages.push(validationError);\n } else {\n validFiles.push(file);\n }\n }\n\n if (invalidFiles.length > 0) {\n this.dispatchEvent(\n new CustomEvent<{ message: string; files: File[] }>('hx-error', {\n bubbles: true,\n composed: true,\n detail: { message: errorMessages.join(' '), files: invalidFiles },\n }),\n );\n }\n\n if (validFiles.length === 0) return;\n\n // Enforce maxFiles limit (only in multiple mode — single-file mode always replaces)\n const currentCount = this.multiple ? this._files.length : 0;\n const capacity =\n this.maxFiles > 0 ? Math.max(0, this.maxFiles - currentCount) : validFiles.length;\n const allowedFiles = validFiles.slice(0, capacity);\n\n if (allowedFiles.length === 0 && this.maxFiles > 0) {\n this.dispatchEvent(\n new CustomEvent<{ message: string; files: File[] }>('hx-error', {\n bubbles: true,\n composed: true,\n detail: {\n message: `Maximum of ${this.maxFiles} file${this.maxFiles === 1 ? '' : 's'} allowed.`,\n files: validFiles,\n },\n }),\n );\n return;\n }\n\n if (allowedFiles.length > 0) {\n const newEntries: FileEntry[] = allowedFiles.map((file) => ({ file, progress: 0 }));\n\n if (this.multiple) {\n this._files = [...this._files, ...newEntries];\n } else {\n this._files = newEntries;\n }\n\n this._handleInteractionInput();\n\n this.dispatchEvent(\n new CustomEvent<{ files: File[] }>('hx-upload', {\n bubbles: true,\n composed: true,\n detail: { files: allowedFiles },\n }),\n );\n }\n\n // If remaining valid files were cut by maxFiles, report that too\n const overflow = validFiles.slice(capacity);\n if (overflow.length > 0 && this.maxFiles > 0) {\n this.dispatchEvent(\n new CustomEvent<{ message: string; files: File[] }>('hx-error', {\n bubbles: true,\n composed: true,\n detail: {\n message: `Maximum of ${this.maxFiles} file${this.maxFiles === 1 ? '' : 's'} allowed. ${overflow.length} file${overflow.length === 1 ? ' was' : 's were'} not added.`,\n files: overflow,\n },\n }),\n );\n }\n }\n\n // ─── Public Methods ───\n\n /**\n * Sets the upload progress for a file at the given index.\n * @param index - Zero-based index into the current file list.\n * @param percent - Progress percentage from 0 to 100.\n */\n setProgress(index: number, percent: number): void {\n if (index < 0 || index >= this._files.length) return;\n const clamped = Math.max(0, Math.min(100, percent));\n this._files = this._files.map((entry, i) =>\n i === index ? { ...entry, progress: clamped } : entry,\n );\n }\n\n /**\n * Returns a read-only copy of the currently selected files.\n */\n get files(): File[] {\n return this._files.map((e) => e.file);\n }\n\n // ─── Drag and Drop Handlers ───\n\n /** @internal */\n private _handleDragOver(e: DragEvent): void {\n e.preventDefault();\n if (this.disabled) return;\n this._dragOver = true;\n }\n\n /** @internal */\n private _handleDragLeave(e: DragEvent): void {\n // Only clear drag state when leaving the dropzone entirely\n const target = e.relatedTarget as Node | null;\n if (target && this.contains(target)) return;\n const dropzone = this.shadowRoot?.querySelector('.dropzone');\n if (dropzone && dropzone.contains(target)) return;\n this._dragOver = false;\n }\n\n /** @internal */\n private _handleDrop(e: DragEvent): void {\n e.preventDefault();\n this._dragOver = false;\n if (this.disabled) return;\n\n const dt = e.dataTransfer;\n if (!dt) return;\n\n const rawFiles = Array.from(dt.files);\n if (rawFiles.length === 0) return;\n\n this._processFiles(rawFiles);\n }\n\n // ─── Click / Keyboard Handlers ───\n\n /** @internal */\n private _handleDropzoneClick(): void {\n if (this.disabled) return;\n this._fileInput?.click();\n }\n\n /** @internal */\n private _handleDropzoneKeyDown(e: KeyboardEvent): void {\n if (this.disabled) return;\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault();\n this._fileInput?.click();\n }\n }\n\n /** @internal */\n private _handleFileInputChange(e: Event): void {\n const input = e.target as HTMLInputElement;\n if (!input.files || input.files.length === 0) return;\n\n const rawFiles = Array.from(input.files);\n // Reset the input so the same file can be re-selected after removal\n input.value = '';\n this._processFiles(rawFiles);\n }\n\n // ─── Remove Handler ───\n\n /** @internal */\n private _handleRemove(index: number): void {\n if (this.disabled) return;\n const entry = this._files[index];\n if (!entry) return;\n\n const removedFile = entry.file;\n this._files = this._files.filter((_, i) => i !== index);\n\n this.dispatchEvent(\n new CustomEvent<{ file: File; index: number }>('hx-remove', {\n bubbles: true,\n composed: true,\n detail: { file: removedFile, index },\n }),\n );\n\n // Restore focus after removal so keyboard users are not stranded.\n this.updateComplete\n .then(() => {\n if (this._files.length === 0) {\n // List is now empty — return focus to the dropzone.\n const dropzone = this.shadowRoot?.querySelector<HTMLElement>('[part=\"dropzone\"]');\n dropzone?.focus();\n } else {\n // Focus the remove button at the same position, or the previous one if\n // the removed item was the last in the list.\n const removeButtons =\n this.shadowRoot?.querySelectorAll<HTMLButtonElement>('.file-item__remove');\n if (removeButtons && removeButtons.length > 0) {\n const targetIndex = index < this._files.length ? index : this._files.length - 1;\n const targetButton = removeButtons[targetIndex];\n if (targetButton) {\n targetButton.focus();\n }\n }\n }\n })\n .catch(() => {\n // Focus restoration is best-effort; ignore errors.\n });\n }\n\n // ─── Formatters ───\n\n /** @internal */\n private _formatSize(bytes: number): string {\n if (bytes < 1024) return `${bytes} B`;\n if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;\n return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;\n }\n\n // ─── Render Helpers ───\n\n /** @internal */\n private _renderFileList() {\n if (this._hasFileListSlot) return nothing;\n if (this._files.length === 0) return nothing;\n\n return html`\n <ul part=\"file-list\" class=\"file-list\" aria-label=${this.labelFileList}>\n ${repeat(\n this._files,\n (entry) => entry.file.name + entry.file.size,\n (entry, index) => html`\n <li part=\"file-item\" class=\"file-item\">\n <div class=\"file-item__row\">\n <span class=\"file-item__name\" title=${entry.file.name}> ${entry.file.name} </span>\n <span class=\"file-item__size\">${this._formatSize(entry.file.size)}</span>\n <button\n type=\"button\"\n class=\"file-item__remove\"\n aria-label=${`Remove ${entry.file.name}`}\n @click=${() => this._handleRemove(index)}\n >\n <svg\n width=\"14\"\n height=\"14\"\n viewBox=\"0 0 14 14\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n aria-hidden=\"true\"\n focusable=\"false\"\n >\n <path\n d=\"M1 1L13 13M13 1L1 13\"\n stroke=\"currentColor\"\n stroke-width=\"1.75\"\n stroke-linecap=\"round\"\n />\n </svg>\n </button>\n </div>\n <div\n part=\"progress\"\n class=\"progress-track\"\n role=\"progressbar\"\n aria-valuenow=${entry.progress}\n aria-valuemin=\"0\"\n aria-valuemax=\"100\"\n aria-label=${this.labelUploadProgress(entry.file.name, entry.progress)}\n >\n <div\n class=\"progress-bar\"\n style=\"--_progress-ratio: ${String(entry.progress / 100)}\"\n ></div>\n </div>\n </li>\n `,\n )}\n </ul>\n `;\n }\n\n // ─── Render ───\n\n override render() {\n const hasError = !!this.error;\n\n const dropzoneClasses = {\n dropzone: true,\n 'dropzone--drag-over': this._dragOver,\n 'dropzone--error': hasError,\n };\n\n const dropzoneLabel = this.label ? `${this.label} — ${this.labelDropzone}` : this.labelDropzone;\n\n return html`\n <div class=\"field\">\n ${this.label\n ? html`\n <label part=\"label\" class=\"field__label\" id=${this._labelId} for=${this._dropzoneId}>\n ${this.label}\n </label>\n `\n : nothing}\n\n <div\n part=\"dropzone\"\n class=${classMap(dropzoneClasses)}\n id=${this._dropzoneId}\n role=\"button\"\n tabindex=${this.disabled ? '-1' : '0'}\n aria-label=${ifDefined(this._effectiveLabel || (!this.label ? dropzoneLabel : undefined))}\n aria-labelledby=${ifDefined(\n !this._effectiveLabel && this.label ? this._labelId : undefined,\n )}\n aria-disabled=${this.disabled ? 'true' : nothing}\n aria-invalid=${hasError ? 'true' : nothing}\n aria-describedby=${ifDefined(hasError ? this._errorId : undefined)}\n @click=${this._handleDropzoneClick}\n @keydown=${this._handleDropzoneKeyDown}\n @dragover=${this._handleDragOver}\n @dragleave=${this._handleDragLeave}\n @drop=${this._handleDrop}\n >\n <slot>${this.labelDropzone}</slot>\n </div>\n\n <input\n class=\"file-input\"\n type=\"file\"\n tabindex=\"-1\"\n aria-hidden=\"true\"\n accept=${ifDefined(this.accept || undefined)}\n ?multiple=${this.multiple}\n ?disabled=${this.disabled}\n @change=${this._handleFileInputChange}\n />\n\n <slot name=\"file-list\" @slotchange=${this._handleFileListSlotChange}></slot>\n\n ${this._renderFileList()}\n ${hasError\n ? html`\n <div part=\"error\" class=\"field__error\" id=${this._errorId} role=\"alert\">\n ${this.error}\n </div>\n `\n : nothing}\n\n <div id=${this._liveId} class=\"sr-only\" aria-live=\"polite\" aria-atomic=\"true\">\n ${this._dragOver ? this.labelDragDetected : ''}\n </div>\n </div>\n `;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'hx-file-upload': HelixFileUpload;\n }\n}\n"],"names":["helixFileUploadStyles","css","_nextFileUploadId","createIdCounter","HelixFileUpload","FormMixin","mixinDelegatesAria","HelixElement","name","progress","_a","_b","slot","changedProperties","errorEl","msg","disabled","_state","_mode","firstEntry","formData","entry","file","maxMb","tokens","token","baseType","rawFiles","candidateFiles","validFiles","invalidFiles","errorMessages","validationError","currentCount","capacity","allowedFiles","newEntries","overflow","index","percent","clamped","i","target","dropzone","dt","input","removedFile","_","removeButtons","targetIndex","targetButton","bytes","nothing","html","repeat","hasError","dropzoneClasses","dropzoneLabel","classMap","ifDefined","__decorateClass","property","state","query","customElement"],"mappings":";;;;;;;;;AAEO,MAAMA,IAAwBC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAA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"}
@@ -1 +1 @@
1
- {"version":3,"file":"hx-grid-CXZf3jeK.js","sources":["../../src/components/hx-grid/hx-grid.styles.ts","../../src/components/hx-grid/hx-grid.ts"],"sourcesContent":["import { css } from 'lit';\n\nexport const helixGridStyles = css`\n :host {\n display: block;\n box-sizing: border-box;\n width: 100%;\n }\n`;\n\nexport const helixGridItemStyles = css`\n :host {\n display: block;\n min-width: 0;\n min-height: 0;\n }\n\n /* ─── High Contrast Mode (forced-colors) ─── */\n\n /* hx-grid and hx-grid-item are layout wrappers with no state communicated\n via color. forced-color-adjust: auto (default) is sufficient. */\n @media (forced-colors: active) {\n :host {\n forced-color-adjust: auto;\n }\n }\n`;\n","import { html, type PropertyValues } from 'lit';\nimport '../../utilities/document-token-adoption.js';\nimport { customElement, property } from 'lit/decorators.js';\nimport { styleMap } from 'lit/directives/style-map.js';\nimport { HelixElement } from '../../base/index.js';\nimport { helixGridStyles, helixGridItemStyles } from './hx-grid.styles.js';\n\ntype GapSize = 'none' | 'xs' | 'sm' | 'md' | 'lg' | 'xl';\n\nconst GAP_TOKENS: Record<GapSize, string> = {\n none: '0',\n xs: 'var(--hx-space-1, 0.25rem)',\n sm: 'var(--hx-space-2, 0.5rem)',\n md: 'var(--hx-space-4, 1rem)',\n lg: 'var(--hx-space-6, 1.5rem)',\n xl: 'var(--hx-space-8, 2rem)',\n};\n\n/**\n * A CSS Grid layout wrapper with design-token-based column and gap system.\n *\n * @summary CSS Grid layout primitive for building responsive grid layouts.\n *\n * @tag hx-grid\n *\n * @slot - Default slot for grid content (use `hx-grid-item` for precise placement).\n *\n * @csspart base - The grid container element.\n *\n * @cssprop [--hx-grid-columns] - Override the computed grid-template-columns.\n * @cssprop [--hx-grid-gap] - Override the computed gap.\n * @cssprop [--hx-grid-row-gap] - Override the computed row-gap.\n * @cssprop [--hx-grid-column-gap] - Override the computed column-gap.\n */\n@customElement('hx-grid')\nexport class HelixGrid extends HelixElement {\n static override styles = [helixGridStyles];\n\n /**\n * Number of equal columns (`repeat(N, 1fr)`) or a CSS grid-template-columns string.\n * @attr columns\n */\n @property({ reflect: true })\n columns: number | string = 1;\n\n /**\n * Gap size applied to both row and column gaps.\n * @attr gap\n */\n @property({ reflect: true })\n gap: 'none' | 'xs' | 'sm' | 'md' | 'lg' | 'xl' = 'md';\n\n /**\n * Row gap override. When set, takes precedence over `gap` for row spacing.\n * @attr row-gap\n */\n @property({ attribute: 'row-gap', reflect: true })\n rowGap: 'none' | 'xs' | 'sm' | 'md' | 'lg' | 'xl' | undefined;\n\n /**\n * Column gap override. When set, takes precedence over `gap` for column spacing.\n * @attr column-gap\n */\n @property({ attribute: 'column-gap', reflect: true })\n columnGap: 'none' | 'xs' | 'sm' | 'md' | 'lg' | 'xl' | undefined;\n\n /**\n * Aligns grid items along the block axis (align-items).\n * @attr align\n */\n @property({ reflect: true })\n align: 'start' | 'center' | 'end' | 'stretch' = 'stretch';\n\n /**\n * Justifies grid items along the inline axis (justify-items).\n * @attr justify\n */\n @property({ reflect: true })\n justify: 'start' | 'center' | 'end' | 'stretch' = 'stretch';\n\n /** @internal */\n private _gridTemplateColumns(): string {\n const cols = this.columns;\n if (typeof cols === 'number' || /^\\d+$/.test(String(cols))) {\n return `var(--hx-grid-columns, repeat(${cols}, 1fr))`;\n }\n return `var(--hx-grid-columns, ${cols})`;\n }\n\n /** @internal */\n private _resolveGap(size: GapSize): string {\n return GAP_TOKENS[size] ?? GAP_TOKENS.md;\n }\n\n /** @internal */\n private _computedRowGap(): string {\n if (this.rowGap) {\n return `var(--hx-grid-row-gap, ${this._resolveGap(this.rowGap)})`;\n }\n return `var(--hx-grid-row-gap, var(--hx-grid-gap, ${this._resolveGap(this.gap)}))`;\n }\n\n /** @internal */\n private _computedColumnGap(): string {\n if (this.columnGap) {\n return `var(--hx-grid-column-gap, ${this._resolveGap(this.columnGap)})`;\n }\n return `var(--hx-grid-column-gap, var(--hx-grid-gap, ${this._resolveGap(this.gap)}))`;\n }\n\n /** @internal */\n private _baseStyleMap(): Record<string, string> {\n return {\n display: 'grid',\n 'grid-template-columns': this._gridTemplateColumns(),\n 'row-gap': this._computedRowGap(),\n 'column-gap': this._computedColumnGap(),\n 'align-items': this.align,\n 'justify-items': this.justify,\n };\n }\n\n override render() {\n return html`\n <div part=\"base\" role=\"presentation\" style=${styleMap(this._baseStyleMap())}>\n <slot></slot>\n </div>\n `;\n }\n}\n\n/**\n * Optional companion element for precise grid item placement.\n * Applies grid-column and grid-row directly to the host element\n * so it participates correctly in the parent CSS grid layout.\n *\n * @summary Grid item with explicit column/row placement.\n *\n * @tag hx-grid-item\n *\n * @slot - Default slot for item content.\n */\n@customElement('hx-grid-item')\nexport class HelixGridItem extends HelixElement {\n static override styles = [helixGridItemStyles];\n\n /**\n * CSS grid-column value (e.g., \"1 / 3\", \"span 2\").\n * @attr column\n */\n @property({ reflect: true })\n column: string | undefined;\n\n /**\n * CSS grid-row value (e.g., \"1 / 2\").\n * @attr row\n */\n @property({ reflect: true })\n row: string | undefined;\n\n /**\n * Column span shorthand — equivalent to setting `column: \"span N\"`.\n * @attr span\n */\n @property({ type: Number, reflect: true })\n span: number | undefined;\n\n override updated(changed: PropertyValues<this>): void {\n super.updated(changed);\n if (changed.has('column') || changed.has('row') || changed.has('span')) {\n this._applyHostGridStyles();\n }\n }\n\n override connectedCallback(): void {\n super.connectedCallback();\n this._applyHostGridStyles();\n }\n\n /** @internal */\n private _applyHostGridStyles(): void {\n if (this.column) {\n this.style.gridColumn = this.column;\n } else if (this.span !== undefined) {\n this.style.gridColumn = `span ${this.span}`;\n } else {\n this.style.gridColumn = '';\n }\n if (this.row) {\n this.style.gridRow = this.row;\n } else {\n this.style.gridRow = '';\n }\n }\n\n override render() {\n return html`<slot></slot>`;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'hx-grid': HelixGrid;\n 'hx-grid-item': HelixGridItem;\n }\n}\n"],"names":["helixGridStyles","css","helixGridItemStyles","GAP_TOKENS","HelixGrid","HelixElement","cols","size","html","styleMap","__decorateClass","property","customElement","HelixGridItem","changed"],"mappings":"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"}
1
+ {"version":3,"file":"hx-grid-CXZf3jeK.js","sources":["../../src/components/hx-grid/hx-grid.styles.ts","../../src/components/hx-grid/hx-grid.ts"],"sourcesContent":["import { css } from 'lit';\n\nexport const helixGridStyles = css`\n :host {\n display: block;\n box-sizing: border-box;\n width: 100%;\n }\n`;\n\nexport const helixGridItemStyles = css`\n :host {\n display: block;\n min-width: 0;\n min-height: 0;\n }\n\n /* ─── High Contrast Mode (forced-colors) ─── */\n\n /* hx-grid and hx-grid-item are layout wrappers with no state communicated\n via color. forced-color-adjust: auto (default) is sufficient. */\n @media (forced-colors: active) {\n :host {\n forced-color-adjust: auto;\n }\n }\n`;\n","import { html, type PropertyValues } from 'lit';\nimport '../../utilities/document-token-adoption.js';\nimport { customElement, property } from 'lit/decorators.js';\nimport { styleMap } from 'lit/directives/style-map.js';\nimport { HelixElement } from '../../base/index.js';\nimport { helixGridStyles, helixGridItemStyles } from './hx-grid.styles.js';\n\ntype GapSize = 'none' | 'xs' | 'sm' | 'md' | 'lg' | 'xl';\n\nconst GAP_TOKENS: Record<GapSize, string> = {\n none: '0',\n xs: 'var(--hx-space-1, 0.25rem)',\n sm: 'var(--hx-space-2, 0.5rem)',\n md: 'var(--hx-space-4, 1rem)',\n lg: 'var(--hx-space-6, 1.5rem)',\n xl: 'var(--hx-space-8, 2rem)',\n};\n\n/**\n * A CSS Grid layout wrapper with design-token-based column and gap system.\n *\n * @summary CSS Grid layout primitive for building responsive grid layouts.\n *\n * @tag hx-grid\n *\n * @slot - Default slot for grid content (use `hx-grid-item` for precise placement).\n *\n * @csspart base - The grid container element.\n *\n * @cssprop [--hx-grid-columns] - Override the computed grid-template-columns.\n * @cssprop [--hx-grid-gap] - Override the computed gap.\n * @cssprop [--hx-grid-row-gap] - Override the computed row-gap.\n * @cssprop [--hx-grid-column-gap] - Override the computed column-gap.\n * @cssprop [--hx-space-1] - Spacing token.\n * @cssprop [--hx-space-2] - Spacing token.\n * @cssprop [--hx-space-4] - Spacing token.\n * @cssprop [--hx-space-6] - Spacing token.\n * @cssprop [--hx-space-8] - Spacing token.\n */\n@customElement('hx-grid')\nexport class HelixGrid extends HelixElement {\n static override styles = [helixGridStyles];\n\n /**\n * Number of equal columns (`repeat(N, 1fr)`) or a CSS grid-template-columns string.\n * @attr columns\n */\n @property({ reflect: true })\n columns: number | string = 1;\n\n /**\n * Gap size applied to both row and column gaps.\n * @attr gap\n */\n @property({ reflect: true })\n gap: 'none' | 'xs' | 'sm' | 'md' | 'lg' | 'xl' = 'md';\n\n /**\n * Row gap override. When set, takes precedence over `gap` for row spacing.\n * @attr row-gap\n */\n @property({ attribute: 'row-gap', reflect: true })\n rowGap: 'none' | 'xs' | 'sm' | 'md' | 'lg' | 'xl' | undefined;\n\n /**\n * Column gap override. When set, takes precedence over `gap` for column spacing.\n * @attr column-gap\n */\n @property({ attribute: 'column-gap', reflect: true })\n columnGap: 'none' | 'xs' | 'sm' | 'md' | 'lg' | 'xl' | undefined;\n\n /**\n * Aligns grid items along the block axis (align-items).\n * @attr align\n */\n @property({ reflect: true })\n align: 'start' | 'center' | 'end' | 'stretch' = 'stretch';\n\n /**\n * Justifies grid items along the inline axis (justify-items).\n * @attr justify\n */\n @property({ reflect: true })\n justify: 'start' | 'center' | 'end' | 'stretch' = 'stretch';\n\n /** @internal */\n private _gridTemplateColumns(): string {\n const cols = this.columns;\n if (typeof cols === 'number' || /^\\d+$/.test(String(cols))) {\n return `var(--hx-grid-columns, repeat(${cols}, 1fr))`;\n }\n return `var(--hx-grid-columns, ${cols})`;\n }\n\n /** @internal */\n private _resolveGap(size: GapSize): string {\n return GAP_TOKENS[size] ?? GAP_TOKENS.md;\n }\n\n /** @internal */\n private _computedRowGap(): string {\n if (this.rowGap) {\n return `var(--hx-grid-row-gap, ${this._resolveGap(this.rowGap)})`;\n }\n return `var(--hx-grid-row-gap, var(--hx-grid-gap, ${this._resolveGap(this.gap)}))`;\n }\n\n /** @internal */\n private _computedColumnGap(): string {\n if (this.columnGap) {\n return `var(--hx-grid-column-gap, ${this._resolveGap(this.columnGap)})`;\n }\n return `var(--hx-grid-column-gap, var(--hx-grid-gap, ${this._resolveGap(this.gap)}))`;\n }\n\n /** @internal */\n private _baseStyleMap(): Record<string, string> {\n return {\n display: 'grid',\n 'grid-template-columns': this._gridTemplateColumns(),\n 'row-gap': this._computedRowGap(),\n 'column-gap': this._computedColumnGap(),\n 'align-items': this.align,\n 'justify-items': this.justify,\n };\n }\n\n override render() {\n return html`\n <div part=\"base\" role=\"presentation\" style=${styleMap(this._baseStyleMap())}>\n <slot></slot>\n </div>\n `;\n }\n}\n\n/**\n * Optional companion element for precise grid item placement.\n * Applies grid-column and grid-row directly to the host element\n * so it participates correctly in the parent CSS grid layout.\n *\n * @summary Grid item with explicit column/row placement.\n *\n * @tag hx-grid-item\n *\n * @slot - Default slot for item content.\n */\n@customElement('hx-grid-item')\nexport class HelixGridItem extends HelixElement {\n static override styles = [helixGridItemStyles];\n\n /**\n * CSS grid-column value (e.g., \"1 / 3\", \"span 2\").\n * @attr column\n */\n @property({ reflect: true })\n column: string | undefined;\n\n /**\n * CSS grid-row value (e.g., \"1 / 2\").\n * @attr row\n */\n @property({ reflect: true })\n row: string | undefined;\n\n /**\n * Column span shorthand — equivalent to setting `column: \"span N\"`.\n * @attr span\n */\n @property({ type: Number, reflect: true })\n span: number | undefined;\n\n override updated(changed: PropertyValues<this>): void {\n super.updated(changed);\n if (changed.has('column') || changed.has('row') || changed.has('span')) {\n this._applyHostGridStyles();\n }\n }\n\n override connectedCallback(): void {\n super.connectedCallback();\n this._applyHostGridStyles();\n }\n\n /** @internal */\n private _applyHostGridStyles(): void {\n if (this.column) {\n this.style.gridColumn = this.column;\n } else if (this.span !== undefined) {\n this.style.gridColumn = `span ${this.span}`;\n } else {\n this.style.gridColumn = '';\n }\n if (this.row) {\n this.style.gridRow = this.row;\n } else {\n this.style.gridRow = '';\n }\n }\n\n override render() {\n return html`<slot></slot>`;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'hx-grid': HelixGrid;\n 'hx-grid-item': HelixGridItem;\n }\n}\n"],"names":["helixGridStyles","css","helixGridItemStyles","GAP_TOKENS","HelixGrid","HelixElement","cols","size","html","styleMap","__decorateClass","property","customElement","HelixGridItem","changed"],"mappings":"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"}
@@ -1,8 +1,8 @@
1
1
  import { css as p, nothing as c, html as l } from "lit";
2
2
  import { property as v, customElement as f } from "lit/decorators.js";
3
- import { classMap as u } from "lit/directives/class-map.js";
3
+ import { classMap as d } from "lit/directives/class-map.js";
4
4
  import { ifDefined as h } from "lit/directives/if-defined.js";
5
- import { H as d } from "./helix-element-BNEYeiys.js";
5
+ import { H as u } from "./helix-element-BNEYeiys.js";
6
6
  const m = p`
7
7
  :host {
8
8
  display: block;
@@ -16,7 +16,7 @@ const m = p`
16
16
  font-size: var(--hx-help-text-font-size, var(--hx-font-size-sm, 0.875rem));
17
17
  font-weight: var(--hx-help-text-font-weight, var(--hx-font-weight-normal, 400));
18
18
  line-height: var(--hx-help-text-line-height, var(--hx-line-height-normal, 1.5));
19
- color: var(--hx-help-text-color, var(--hx-color-neutral-500, #64748b));
19
+ color: var(--hx-help-text-color, var(--hx-color-text-muted, #64748b));
20
20
  margin: 0;
21
21
  }
22
22
 
@@ -33,7 +33,7 @@ const m = p`
33
33
  /* ─── Variant: default ─── */
34
34
 
35
35
  .help-text--default {
36
- --hx-help-text-color: var(--hx-color-neutral-500, #64748b);
36
+ --hx-help-text-color: var(--hx-color-text-muted, #64748b);
37
37
  }
38
38
 
39
39
  /* ─── Variant: error ─── */
@@ -124,7 +124,7 @@ const y = l`<svg viewBox="0 0 16 16" aria-hidden="true" width="1em" height="1em"
124
124
  warning: k,
125
125
  success: _
126
126
  };
127
- let i = class extends d {
127
+ let i = class extends u {
128
128
  constructor() {
129
129
  super(...arguments), this.variant = "default";
130
130
  }
@@ -135,7 +135,7 @@ let i = class extends d {
135
135
  }, e = C[this.variant], o = this.variant === "error" ? "alert" : void 0, r = this.variant === "warning" || this.variant === "success" ? "polite" : void 0;
136
136
  return l`<span
137
137
  part="base"
138
- class=${u(n)}
138
+ class=${d(n)}
139
139
  role=${h(o)}
140
140
  aria-live=${h(r)}
141
141
  >${e !== c ? l`<span part="icon" class="help-text__icon">${e}</span>` : c}<span part="text" class="help-text__text"><slot></slot></span>
@@ -152,4 +152,4 @@ i = x([
152
152
  export {
153
153
  i as H
154
154
  };
155
- //# sourceMappingURL=hx-help-text-D7eytSim.js.map
155
+ //# sourceMappingURL=hx-help-text-Br3igJv5.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hx-help-text-Br3igJv5.js","sources":["../../src/components/hx-help-text/hx-help-text.styles.ts","../../src/components/hx-help-text/hx-help-text.ts"],"sourcesContent":["import { css } from 'lit';\n\nexport const helixHelpTextStyles = css`\n :host {\n display: block;\n }\n\n .help-text {\n display: inline-flex;\n align-items: baseline;\n gap: var(--hx-help-text-icon-gap, 0.375rem);\n font-family: var(--hx-help-text-font-family, var(--hx-font-family-sans, sans-serif));\n font-size: var(--hx-help-text-font-size, var(--hx-font-size-sm, 0.875rem));\n font-weight: var(--hx-help-text-font-weight, var(--hx-font-weight-normal, 400));\n line-height: var(--hx-help-text-line-height, var(--hx-line-height-normal, 1.5));\n color: var(--hx-help-text-color, var(--hx-color-text-muted, #64748b));\n margin: 0;\n }\n\n .help-text__icon {\n flex-shrink: 0;\n display: inline-flex;\n align-items: center;\n }\n\n .help-text__text {\n min-width: 0;\n }\n\n /* ─── Variant: default ─── */\n\n .help-text--default {\n --hx-help-text-color: var(--hx-color-text-muted, #64748b);\n }\n\n /* ─── Variant: error ─── */\n\n .help-text--error {\n --hx-help-text-color: var(--hx-color-error-600, #b91c1c);\n }\n\n /* ─── Variant: warning ─── */\n\n .help-text--warning {\n --hx-help-text-color: var(--hx-color-warning-700, #92400e);\n }\n\n /* ─── Variant: success ─── */\n\n .help-text--success {\n --hx-help-text-color: var(--hx-color-success-700, #166534);\n }\n\n /* ─── High Contrast Mode (forced-colors) ─── */\n\n @media (forced-colors: active) {\n .help-text {\n color: GrayText;\n }\n\n .help-text--error {\n color: LinkText;\n }\n\n .help-text--warning {\n color: CanvasText;\n }\n\n .help-text--success {\n color: CanvasText;\n }\n }\n`;\n","import { html, nothing } from 'lit';\nimport '../../utilities/document-token-adoption.js';\nimport { customElement, property } from 'lit/decorators.js';\nimport { classMap } from 'lit/directives/class-map.js';\nimport { ifDefined } from 'lit/directives/if-defined.js';\nimport { HelixElement } from '../../base/index.js';\nimport { helixHelpTextStyles } from './hx-help-text.styles.js';\n\n/** Icon SVG for error variant (circle with exclamation mark). */\nconst errorIcon = html`<svg viewBox=\"0 0 16 16\" aria-hidden=\"true\" width=\"1em\" height=\"1em\">\n <circle cx=\"8\" cy=\"8\" r=\"7\" stroke=\"currentColor\" stroke-width=\"1.5\" fill=\"none\" />\n <line\n x1=\"8\"\n y1=\"4.5\"\n x2=\"8\"\n y2=\"8.5\"\n stroke=\"currentColor\"\n stroke-width=\"1.5\"\n stroke-linecap=\"round\"\n />\n <circle cx=\"8\" cy=\"11\" r=\"0.75\" fill=\"currentColor\" />\n</svg>`;\n\n/** Icon SVG for warning variant (triangle with exclamation mark). */\nconst warningIcon = html`<svg viewBox=\"0 0 16 16\" aria-hidden=\"true\" width=\"1em\" height=\"1em\">\n <path\n d=\"M7.134 2.5a1 1 0 011.732 0l5.196 9a1 1 0 01-.866 1.5H2.804a1 1 0 01-.866-1.5l5.196-9z\"\n stroke=\"currentColor\"\n stroke-width=\"1.25\"\n fill=\"none\"\n />\n <line\n x1=\"8\"\n y1=\"6\"\n x2=\"8\"\n y2=\"9\"\n stroke=\"currentColor\"\n stroke-width=\"1.25\"\n stroke-linecap=\"round\"\n />\n <circle cx=\"8\" cy=\"11\" r=\"0.625\" fill=\"currentColor\" />\n</svg>`;\n\n/** Icon SVG for success variant (circle with checkmark). */\nconst successIcon = html`<svg viewBox=\"0 0 16 16\" aria-hidden=\"true\" width=\"1em\" height=\"1em\">\n <circle cx=\"8\" cy=\"8\" r=\"7\" stroke=\"currentColor\" stroke-width=\"1.5\" fill=\"none\" />\n <path\n d=\"M5.25 8.25l1.75 1.75 3.75-3.75\"\n stroke=\"currentColor\"\n stroke-width=\"1.5\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n fill=\"none\"\n />\n</svg>`;\n\n/** Map of variant to icon template. Default has no icon. */\nconst variantIcons = {\n default: nothing,\n error: errorIcon,\n warning: warningIcon,\n success: successIcon,\n} as const;\n\n/**\n * Standardized help/hint text displayed below form fields.\n * Used by hx-field as a consistent sub-component for guidance and validation messages.\n *\n * Non-default variants render an inline icon alongside the text to satisfy\n * WCAG 1.4.1 (color is not the sole visual indicator). The `error` variant\n * uses `role=\"alert\"` for immediate screen-reader announcement; `warning`\n * and `success` use `aria-live=\"polite\"` for non-intrusive announcements.\n *\n * @summary Help text displayed below form controls for guidance or validation feedback.\n *\n * @tag hx-help-text\n *\n * @slot - The help text content.\n *\n * @csspart base - The root element of the help text.\n * @csspart icon - The icon wrapper (only rendered for non-default variants).\n * @csspart text - The text wrapper around the default slot.\n *\n * @cssprop [--hx-help-text-color=var(--hx-color-neutral-500)] - Text color.\n * @cssprop [--hx-help-text-font-family=var(--hx-font-family-sans)] - Font family.\n * @cssprop [--hx-help-text-font-size=var(--hx-font-size-sm)] - Font size.\n * @cssprop [--hx-help-text-font-weight=var(--hx-font-weight-normal)] - Font weight.\n * @cssprop [--hx-help-text-line-height=var(--hx-line-height-normal)] - Line height.\n * @cssprop [--hx-help-text-icon-gap=0.375rem] - Gap between icon and text.\n * @cssprop [--hx-font-family-sans] - Font family.\n * @cssprop [--hx-font-size-sm] - Font size.\n * @cssprop [--hx-font-weight-normal] - Font weight.\n * @cssprop [--hx-line-height-normal] - Line height.\n * @cssprop [--hx-color-neutral-500] - Color.\n * @cssprop [--hx-color-error-600] - Color.\n * @cssprop [--hx-color-warning-700] - Color.\n * @cssprop [--hx-color-success-700] - Color.\n */\n@customElement('hx-help-text')\nexport class HelixHelpText extends HelixElement {\n static override styles = [helixHelpTextStyles];\n\n /**\n * Visual variant that determines the text color and icon.\n * Use `error` for validation errors, `warning` for cautions, `success` for confirmation.\n * @attr variant\n */\n @property({ type: String, reflect: true })\n variant: 'default' | 'error' | 'warning' | 'success' = 'default';\n\n override render() {\n const classes = {\n 'help-text': true,\n [`help-text--${this.variant}`]: true,\n };\n\n const icon = variantIcons[this.variant];\n const role = this.variant === 'error' ? 'alert' : undefined;\n const ariaLive =\n this.variant === 'warning' || this.variant === 'success' ? 'polite' : undefined;\n\n return html`<span\n part=\"base\"\n class=${classMap(classes)}\n role=${ifDefined(role)}\n aria-live=${ifDefined(ariaLive)}\n >${icon !== nothing\n ? html`<span part=\"icon\" class=\"help-text__icon\">${icon}</span>`\n : nothing}<span part=\"text\" class=\"help-text__text\"><slot></slot></span>\n </span>`;\n }\n}\n\n/** Canonical type alias for the hx-help-text component. */\nexport type HxHelpText = HelixHelpText;\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'hx-help-text': HelixHelpText;\n }\n}\n"],"names":["helixHelpTextStyles","css","errorIcon","html","warningIcon","successIcon","variantIcons","nothing","HelixHelpText","HelixElement","classes","icon","role","ariaLive","classMap","ifDefined","__decorateClass","property","customElement"],"mappings":";;;;;AAEO,MAAMA,IAAsBC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;;;;ACOnC,MAAMC,IAAYC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,SAeZC,IAAcD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,SAoBdE,IAAcF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,SAadG,IAAe;AAAA,EACnB,SAASC;AAAA,EACT,OAAOL;AAAA,EACP,SAASE;AAAA,EACT,SAASC;AACX;AAqCO,IAAMG,IAAN,cAA4BC,EAAa;AAAA,EAAzC,cAAA;AAAA,UAAA,GAAA,SAAA,GASL,KAAA,UAAuD;AAAA,EAAA;AAAA,EAE9C,SAAS;AAChB,UAAMC,IAAU;AAAA,MACd,aAAa;AAAA,MACb,CAAC,cAAc,KAAK,OAAO,EAAE,GAAG;AAAA,IAAA,GAG5BC,IAAOL,EAAa,KAAK,OAAO,GAChCM,IAAO,KAAK,YAAY,UAAU,UAAU,QAC5CC,IACJ,KAAK,YAAY,aAAa,KAAK,YAAY,YAAY,WAAW;AAExE,WAAOV;AAAA;AAAA,cAEGW,EAASJ,CAAO,CAAC;AAAA,aAClBK,EAAUH,CAAI,CAAC;AAAA,kBACVG,EAAUF,CAAQ,CAAC;AAAA,SAC5BF,MAASJ,IACRJ,8CAAiDQ,CAAI,YACrDJ,CAAO;AAAA;AAAA,EAEf;AACF;AAhCaC,EACK,SAAS,CAACR,CAAmB;AAQ7CgB,EAAA;AAAA,EADCC,EAAS,EAAE,MAAM,QAAQ,SAAS,IAAM;AAAA,GAR9BT,EASX,WAAA,WAAA,CAAA;AATWA,IAANQ,EAAA;AAAA,EADNE,EAAc,cAAc;AAAA,GAChBV,CAAA;"}
@@ -1 +1 @@
1
- {"version":3,"file":"hx-icon-CcyDPDYY.js","sources":["../../src/components/hx-icon/hx-icon.styles.ts","../../src/components/hx-icon/hx-icon.ts"],"sourcesContent":["import { css } from 'lit';\n\nexport const helixIconStyles = css`\n :host {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n /* vertical-align: middle ensures the icon aligns to the visual centre of\n adjacent inline text rather than the text baseline. */\n vertical-align: middle;\n /* overflow: hidden prevents malformed or oversized icons from painting\n outside the component boundary. The inner SVG may still set\n overflow: visible for its own viewBox content. */\n overflow: hidden;\n width: var(--hx-icon-size, var(--hx-size-6, 1.5rem));\n height: var(--hx-icon-size, var(--hx-size-6, 1.5rem));\n color: var(--hx-icon-color, currentColor);\n flex-shrink: 0;\n }\n\n /* ─── Size Variants ───\n Fallback pixel values mirror the design token values at time of writing.\n If token values are updated the fallbacks should be updated to match. */\n\n :host([hx-size='xs']) {\n --hx-icon-size: var(--hx-size-4, 1rem);\n }\n\n :host([hx-size='sm']) {\n --hx-icon-size: var(--hx-size-5, 1.25rem);\n }\n\n :host([hx-size='md']) {\n --hx-icon-size: var(--hx-size-6, 1.5rem);\n }\n\n :host([hx-size='lg']) {\n --hx-icon-size: var(--hx-size-8, 2rem);\n }\n\n :host([hx-size='xl']) {\n --hx-icon-size: var(--hx-size-10, 2.5rem);\n }\n\n /* ─── SVG (sprite mode) ───\n In sprite mode [part=\"svg\"] is an actual <svg> element. The selector\n targets it specifically. In inline mode the part is applied to a <span>\n wrapper — see .icon__inline below. */\n\n svg[part='svg'] {\n width: 100%;\n height: 100%;\n fill: currentColor;\n display: block;\n overflow: visible;\n }\n\n /* ─── Inline SVG wrapper ───\n In inline mode [part=\"svg\"] is a <span> that wraps the fetched SVG.\n The inner <svg> is sized to fill the wrapper. */\n\n .icon__inline {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 100%;\n height: 100%;\n }\n\n .icon__inline svg {\n width: 100%;\n height: 100%;\n fill: currentColor;\n display: block;\n }\n\n /* ─── Forced Colors (Windows High Contrast) ─── */\n\n @media (forced-colors: active) {\n :host {\n color: CanvasText;\n }\n }\n`;\n","import { html, nothing, type PropertyValues } from 'lit';\nimport '../../utilities/document-token-adoption.js';\nimport { customElement, property, state } from 'lit/decorators.js';\nimport { unsafeHTML } from 'lit/directives/unsafe-html.js';\nimport { HelixElement } from '../../base/index.js';\nimport { helixIconStyles } from './hx-icon.styles.js';\n\n/**\n * An icon component that supports inline SVG fetching and SVG sprite sheet references.\n * Decorative icons are automatically hidden from assistive technology.\n * When a label is provided the icon is announced as an image with that label.\n *\n * **Render modes:**\n * - **Sprite mode** (recommended for Drupal/SSR): Set `name` and optionally `sprite-url`.\n * Renders an `<svg><use href=\"...#name\">` — works server-side without JavaScript.\n * - **Inline mode**: Set `src` to a URL of a standalone SVG file. The component fetches,\n * sanitizes, and embeds the SVG markup. Requires JavaScript; not server-side renderable.\n * For Drupal/Twig templates use sprite mode to avoid content shift before hydration.\n *\n * @summary SVG icon with sprite and inline fetch modes for healthcare applications.\n *\n * @tag hx-icon\n *\n * @csspart svg - The SVG element rendered in sprite mode, or the inline SVG container\n * in inline mode. In sprite mode this is an `<svg>` element; in inline mode it is a\n * `<span>` element wrapping the fetched SVG. Both expose the same `part` name for\n * consistent external styling via `::part(svg)`.\n *\n * @cssprop [--hx-icon-size=var(--hx-size-6,1.5rem)] - Width and height of the icon.\n * @cssprop [--hx-icon-color=currentColor] - Icon color.\n */\n@customElement('hx-icon')\nexport class HelixIcon extends HelixElement {\n static override styles = [helixIconStyles];\n\n /**\n * Icon name used as the fragment identifier when referencing a sprite sheet.\n * For sprite mode provide the bare symbol id (e.g. `check`). The component\n * will build the full href as `${spriteUrl}#${name}`. If `name` already\n * starts with `#` it is used as-is (inline sprite reference without a base\n * URL).\n * @attr name\n */\n @property({ type: String })\n name = '';\n\n /**\n * URL of a standalone SVG file to fetch and render inline. Takes precedence\n * over sprite mode when both `src` and `spriteUrl`/`name` are set.\n *\n * **Note:** Inline mode requires browser JavaScript (`fetch` + `DOMParser`).\n * It is not server-side renderable. For Drupal/Twig use sprite mode instead.\n * @attr src\n */\n @property({ type: String })\n src: string | undefined = undefined;\n\n /**\n * Base URL of the SVG sprite sheet. Used together with `name` to construct\n * the `<use>` href: `${spriteUrl}#${name}`.\n * @attr sprite-url\n */\n @property({ type: String, attribute: 'sprite-url' })\n spriteUrl: string | undefined = undefined;\n\n /**\n * Size variant of the icon.\n *\n * Set via the `hx-size` HTML attribute (e.g. `hx-size=\"lg\"`) or via the\n * `size` JavaScript property (e.g. `el.size = 'lg'`). Both are equivalent —\n * the `attribute: 'hx-size'` mapping is used to avoid colliding with the\n * native `<input>` `size` attribute in Drupal attribute-passthrough scenarios.\n * The CEM exposes both the JS property name (`size`) and the HTML attribute\n * name (`hx-size`).\n *\n * @attr hx-size\n */\n @property({ type: String, reflect: true, attribute: 'hx-size' })\n size: 'xs' | 'sm' | 'md' | 'lg' | 'xl' = 'md';\n\n /**\n * Accessible label for the icon. When non-empty, `role=\"img\"` and\n * `aria-label` are applied so assistive technology announces the icon.\n * When empty the icon is treated as decorative and `aria-hidden=\"true\"` is\n * applied.\n * @attr label\n */\n @property({ type: String })\n label = '';\n\n /**\n * Comma-separated list of allowed origins for cross-origin SVG fetches.\n * By default, only same-origin URLs are permitted. Set this to allow\n * specific CDN or asset server origins (e.g., \"https://cdn.example.com,https://assets.example.com\").\n * @attr allowed-origins\n */\n @property({ type: String, attribute: 'allowed-origins' })\n allowedOrigins = '';\n\n /**\n * Stores the sanitized inner markup of an externally fetched SVG.\n * @internal\n */\n @state()\n private _inlineSvg = '';\n\n /**\n * Tracks the `src` URL that was last successfully fetched so that we only\n * refetch when it genuinely changes.\n * @internal\n */\n @state()\n private _fetchedSrc: string | undefined = undefined;\n\n /**\n * Monotonically-increasing sequence number. Incremented before each fetch so\n * that stale out-of-order responses can be discarded.\n */\n /** @internal */\n private _fetchSeq = 0;\n\n // ─── Lifecycle ───\n\n override updated(changed: PropertyValues<this>): void {\n super.updated(changed);\n if (changed.has('src') && this.src !== this._fetchedSrc) {\n void this._fetchInlineSvg(this.src);\n }\n }\n\n // ─── Inline SVG Fetch ───\n\n /** @internal */\n private async _fetchInlineSvg(url: string | undefined): Promise<void> {\n const seq = ++this._fetchSeq;\n\n if (!url) {\n this._inlineSvg = '';\n this._fetchedSrc = undefined;\n return;\n }\n\n // Validate URL origin — only allow same-origin or data: URIs by default.\n // Cross-origin SVGs are blocked unless explicitly allowed via allowedOrigins.\n if (!this._isAllowedOrigin(url)) {\n console.warn(\n `[hx-icon] Blocked cross-origin SVG fetch: \"${url}\". ` +\n 'Only same-origin URLs are allowed by default. ' +\n 'Set the allowed-origins attribute to permit specific external origins.',\n );\n this._inlineSvg = '';\n this._fetchedSrc = undefined;\n return;\n }\n\n // Use module-level cache to avoid duplicate network requests for the same URL.\n // Multiple hx-icon instances sharing the same src will share one in-flight fetch.\n try {\n let pending = _svgCache.get(url);\n if (!pending) {\n pending = fetch(url).then(async (response) => {\n if (!response.ok) {\n _svgCache.delete(url);\n return '';\n }\n return response.text();\n });\n _svgCache.set(url, pending);\n }\n\n const text = await pending;\n if (seq !== this._fetchSeq) return;\n\n if (!text) {\n this._inlineSvg = '';\n this._fetchedSrc = undefined;\n return;\n }\n\n const sanitized = this._sanitizeSvg(text);\n this._inlineSvg = sanitized;\n this._fetchedSrc = url;\n } catch {\n if (seq !== this._fetchSeq) return;\n _svgCache.delete(url);\n this._inlineSvg = '';\n this._fetchedSrc = undefined;\n }\n }\n\n /**\n * Checks whether a URL is same-origin or matches the configured allowedOrigins.\n * Relative URLs and data: URIs are always allowed. Cross-origin URLs are blocked\n * unless their origin appears in the allowedOrigins list.\n * @internal\n */\n private _isAllowedOrigin(url: string): boolean {\n // Relative URLs are always same-origin\n if (url.startsWith('/') || url.startsWith('./') || url.startsWith('../')) {\n return true;\n }\n\n try {\n const parsed = new URL(url, window.location.href);\n\n // Same-origin is always allowed\n if (parsed.origin === window.location.origin) {\n return true;\n }\n\n // Check configured allowlist\n if (this.allowedOrigins) {\n const allowed = this.allowedOrigins\n .split(',')\n .map((o) => o.trim().toLowerCase())\n .filter(Boolean);\n return allowed.includes(parsed.origin.toLowerCase());\n }\n\n return false;\n } catch {\n // Unparseable URL — block it\n return false;\n }\n }\n\n /**\n * Parses the raw SVG text, strips dangerous content (script elements,\n * foreignObject, on* event-handler attributes, javascript:/data: URIs,\n * and style attributes that could carry CSS injection payloads), and\n * returns the outer SVG markup safe for rendering via `unsafeHTML`.\n *\n * Additionally injects `focusable=\"false\"` on the root SVG element to\n * prevent IE11/old-Edge from making the SVG keyboard-focusable, and strips\n * any ARIA attributes from the inner SVG to prevent conflicts with the\n * wrapper's own ARIA semantics.\n */\n /** @internal */\n private _sanitizeSvg(raw: string): string {\n const parser = new DOMParser();\n const doc = parser.parseFromString(raw, 'image/svg+xml');\n\n const parseError = doc.querySelector('parsererror');\n if (parseError) {\n return '';\n }\n\n const svgEl = doc.querySelector('svg');\n if (!svgEl) {\n return '';\n }\n\n // Remove dangerous embedded elements:\n // - script: arbitrary code execution\n // - foreignObject: can embed arbitrary HTML including scripts\n // - style: CSS injection (url() payloads, expression(), external references)\n // - animate, animateTransform, animateMotion, set: SMIL animation elements\n // can trigger event handlers and modify attributes to bypass sanitization\n const dangerousElements = [\n 'script',\n 'foreignObject',\n 'style',\n 'animate',\n 'animateTransform',\n 'animateMotion',\n 'set',\n ];\n svgEl.querySelectorAll(dangerousElements.join(', ')).forEach((s) => {\n s.remove();\n });\n\n // URL-bearing attributes that can carry javascript:/data: payloads.\n const urlAttrs = new Set(['href', 'xlink:href', 'src', 'action', 'formaction']);\n\n // ARIA attributes that may conflict with the wrapper element's own semantics.\n // The wrapper <span part=\"svg\"> owns role/aria-label/aria-hidden — the inner\n // SVG must not duplicate or contradict these.\n const ariaAttrs = new Set(['role', 'aria-label', 'aria-labelledby', 'aria-hidden']);\n\n // Sanitize every element including the root svg.\n const allElements: Element[] = [svgEl, ...Array.from(svgEl.querySelectorAll('*'))];\n allElements.forEach((el) => {\n const attrs = Array.from(el.attributes);\n attrs.forEach((attr) => {\n const attrName = attr.name.toLowerCase();\n // Strip event-handler attributes.\n if (attrName.startsWith('on')) {\n el.removeAttribute(attr.name);\n return;\n }\n // Strip style attributes — CSS can carry injection payloads via\n // url(javascript:...), expression(), or external filter/clip-path references.\n if (attrName === 'style') {\n el.removeAttribute(attr.name);\n return;\n }\n // Strip javascript: and data: URIs from URL-bearing attributes.\n if (urlAttrs.has(attrName)) {\n const val = attr.value.replace(/\\s/g, '').toLowerCase();\n if (val.startsWith('javascript:') || val.startsWith('data:')) {\n el.removeAttribute(attr.name);\n }\n }\n });\n });\n\n // Strip ARIA attributes from the root SVG only — they conflict with the\n // wrapper element's ARIA. Child elements' ARIA is left intact.\n ariaAttrs.forEach((a) => svgEl.removeAttribute(a));\n\n // Inject focusable=\"false\" so IE11/old-Edge do not tab into the SVG.\n svgEl.setAttribute('focusable', 'false');\n\n return svgEl.outerHTML;\n }\n\n // ─── Render Helpers ───\n\n /**\n * Returns the href used in the `<use>` element for sprite mode.\n * If `name` already begins with `#` it is treated as an inline reference.\n */\n /** @internal */\n private _spriteHref(): string {\n const n = this.name;\n if (n.startsWith('#')) {\n return n;\n }\n const base = this.spriteUrl ?? '';\n return base ? `${base}#${n}` : `#${n}`;\n }\n\n /** @internal */\n private _renderSprite() {\n const isDecorative = !this.label.trim();\n\n return html`\n <svg\n part=\"svg\"\n class=\"icon__svg\"\n viewBox=\"0 0 24 24\"\n xmlns=\"http://www.w3.org/2000/svg\"\n role=${isDecorative ? nothing : 'img'}\n aria-label=${isDecorative ? nothing : this.label}\n aria-hidden=${isDecorative ? 'true' : nothing}\n focusable=\"false\"\n >\n ${isDecorative ? nothing : html`<title>${this.label}</title>`}\n <use href=${this._spriteHref()}></use>\n </svg>\n `;\n }\n\n /** @internal */\n private _renderInline() {\n if (!this._inlineSvg) {\n return nothing;\n }\n\n const isDecorative = !this.label.trim();\n\n // The fetched SVG is rendered inside a wrapper span that carries the\n // csspart and ARIA semantics. The inner SVG from unsafeHTML fills the\n // container via the `.icon__inline svg` CSS rule. ARIA attributes and\n // focusable=\"false\" are injected into the inner SVG by _sanitizeSvg.\n return html`\n <span\n part=\"svg\"\n class=\"icon__inline\"\n role=${isDecorative ? nothing : 'img'}\n aria-label=${isDecorative ? nothing : this.label}\n aria-hidden=${isDecorative ? 'true' : nothing}\n >\n ${unsafeHTML(this._inlineSvg)}\n </span>\n `;\n }\n\n // ─── Render ───\n\n override render() {\n // Inline fetch mode takes precedence when src is a non-empty string.\n if (typeof this.src === 'string' && this.src.trim().length > 0) {\n return this._renderInline();\n }\n\n // Sprite mode: requires at least a name.\n if (this.name) {\n return this._renderSprite();\n }\n\n return nothing;\n }\n}\n\n/**\n * Module-level SVG fetch cache. Shared across all `hx-icon` instances so that\n * multiple icons sharing the same `src` URL issue only one network request.\n * The cache stores in-flight `Promise<string>` values — resolved entries remain\n * cached for the lifetime of the page to prevent redundant re-fetches.\n */\nconst _svgCache = new Map<string, Promise<string>>();\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'hx-icon': HelixIcon;\n }\n}\n"],"names":["helixIconStyles","css","HelixIcon","HelixElement","changed","url","seq","pending","_svgCache","response","text","sanitized","parsed","o","raw","doc","svgEl","dangerousElements","s","urlAttrs","ariaAttrs","el","attr","attrName","val","a","n","base","isDecorative","html","nothing","unsafeHTML","__decorateClass","property","state","customElement"],"mappings":"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"}
1
+ {"version":3,"file":"hx-icon-CcyDPDYY.js","sources":["../../src/components/hx-icon/hx-icon.styles.ts","../../src/components/hx-icon/hx-icon.ts"],"sourcesContent":["import { css } from 'lit';\n\nexport const helixIconStyles = css`\n :host {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n /* vertical-align: middle ensures the icon aligns to the visual centre of\n adjacent inline text rather than the text baseline. */\n vertical-align: middle;\n /* overflow: hidden prevents malformed or oversized icons from painting\n outside the component boundary. The inner SVG may still set\n overflow: visible for its own viewBox content. */\n overflow: hidden;\n width: var(--hx-icon-size, var(--hx-size-6, 1.5rem));\n height: var(--hx-icon-size, var(--hx-size-6, 1.5rem));\n color: var(--hx-icon-color, currentColor);\n flex-shrink: 0;\n }\n\n /* ─── Size Variants ───\n Fallback pixel values mirror the design token values at time of writing.\n If token values are updated the fallbacks should be updated to match. */\n\n :host([hx-size='xs']) {\n --hx-icon-size: var(--hx-size-4, 1rem);\n }\n\n :host([hx-size='sm']) {\n --hx-icon-size: var(--hx-size-5, 1.25rem);\n }\n\n :host([hx-size='md']) {\n --hx-icon-size: var(--hx-size-6, 1.5rem);\n }\n\n :host([hx-size='lg']) {\n --hx-icon-size: var(--hx-size-8, 2rem);\n }\n\n :host([hx-size='xl']) {\n --hx-icon-size: var(--hx-size-10, 2.5rem);\n }\n\n /* ─── SVG (sprite mode) ───\n In sprite mode [part=\"svg\"] is an actual <svg> element. The selector\n targets it specifically. In inline mode the part is applied to a <span>\n wrapper — see .icon__inline below. */\n\n svg[part='svg'] {\n width: 100%;\n height: 100%;\n fill: currentColor;\n display: block;\n overflow: visible;\n }\n\n /* ─── Inline SVG wrapper ───\n In inline mode [part=\"svg\"] is a <span> that wraps the fetched SVG.\n The inner <svg> is sized to fill the wrapper. */\n\n .icon__inline {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 100%;\n height: 100%;\n }\n\n .icon__inline svg {\n width: 100%;\n height: 100%;\n fill: currentColor;\n display: block;\n }\n\n /* ─── Forced Colors (Windows High Contrast) ─── */\n\n @media (forced-colors: active) {\n :host {\n color: CanvasText;\n }\n }\n`;\n","import { html, nothing, type PropertyValues } from 'lit';\nimport '../../utilities/document-token-adoption.js';\nimport { customElement, property, state } from 'lit/decorators.js';\nimport { unsafeHTML } from 'lit/directives/unsafe-html.js';\nimport { HelixElement } from '../../base/index.js';\nimport { helixIconStyles } from './hx-icon.styles.js';\n\n/**\n * An icon component that supports inline SVG fetching and SVG sprite sheet references.\n * Decorative icons are automatically hidden from assistive technology.\n * When a label is provided the icon is announced as an image with that label.\n *\n * **Render modes:**\n * - **Sprite mode** (recommended for Drupal/SSR): Set `name` and optionally `sprite-url`.\n * Renders an `<svg><use href=\"...#name\">` — works server-side without JavaScript.\n * - **Inline mode**: Set `src` to a URL of a standalone SVG file. The component fetches,\n * sanitizes, and embeds the SVG markup. Requires JavaScript; not server-side renderable.\n * For Drupal/Twig templates use sprite mode to avoid content shift before hydration.\n *\n * @summary SVG icon with sprite and inline fetch modes for healthcare applications.\n *\n * @tag hx-icon\n *\n * @csspart svg - The SVG element rendered in sprite mode, or the inline SVG container\n * in inline mode. In sprite mode this is an `<svg>` element; in inline mode it is a\n * `<span>` element wrapping the fetched SVG. Both expose the same `part` name for\n * consistent external styling via `::part(svg)`.\n *\n * @cssprop [--hx-icon-size=var(--hx-size-6,1.5rem)] - Width and height of the icon.\n * @cssprop [--hx-icon-color=currentColor] - Icon color.\n * @cssprop [--hx-size-4] - Size token.\n * @cssprop [--hx-size-5] - Size token.\n * @cssprop [--hx-size-6] - Size token.\n * @cssprop [--hx-size-8] - Size token.\n * @cssprop [--hx-size-10] - Size token.\n */\n@customElement('hx-icon')\nexport class HelixIcon extends HelixElement {\n static override styles = [helixIconStyles];\n\n /**\n * Icon name used as the fragment identifier when referencing a sprite sheet.\n * For sprite mode provide the bare symbol id (e.g. `check`). The component\n * will build the full href as `${spriteUrl}#${name}`. If `name` already\n * starts with `#` it is used as-is (inline sprite reference without a base\n * URL).\n * @attr name\n */\n @property({ type: String })\n name = '';\n\n /**\n * URL of a standalone SVG file to fetch and render inline. Takes precedence\n * over sprite mode when both `src` and `spriteUrl`/`name` are set.\n *\n * **Note:** Inline mode requires browser JavaScript (`fetch` + `DOMParser`).\n * It is not server-side renderable. For Drupal/Twig use sprite mode instead.\n * @attr src\n */\n @property({ type: String })\n src: string | undefined = undefined;\n\n /**\n * Base URL of the SVG sprite sheet. Used together with `name` to construct\n * the `<use>` href: `${spriteUrl}#${name}`.\n * @attr sprite-url\n */\n @property({ type: String, attribute: 'sprite-url' })\n spriteUrl: string | undefined = undefined;\n\n /**\n * Size variant of the icon.\n *\n * Set via the `hx-size` HTML attribute (e.g. `hx-size=\"lg\"`) or via the\n * `size` JavaScript property (e.g. `el.size = 'lg'`). Both are equivalent —\n * the `attribute: 'hx-size'` mapping is used to avoid colliding with the\n * native `<input>` `size` attribute in Drupal attribute-passthrough scenarios.\n * The CEM exposes both the JS property name (`size`) and the HTML attribute\n * name (`hx-size`).\n *\n * @attr hx-size\n */\n @property({ type: String, reflect: true, attribute: 'hx-size' })\n size: 'xs' | 'sm' | 'md' | 'lg' | 'xl' = 'md';\n\n /**\n * Accessible label for the icon. When non-empty, `role=\"img\"` and\n * `aria-label` are applied so assistive technology announces the icon.\n * When empty the icon is treated as decorative and `aria-hidden=\"true\"` is\n * applied.\n * @attr label\n */\n @property({ type: String })\n label = '';\n\n /**\n * Comma-separated list of allowed origins for cross-origin SVG fetches.\n * By default, only same-origin URLs are permitted. Set this to allow\n * specific CDN or asset server origins (e.g., \"https://cdn.example.com,https://assets.example.com\").\n * @attr allowed-origins\n */\n @property({ type: String, attribute: 'allowed-origins' })\n allowedOrigins = '';\n\n /**\n * Stores the sanitized inner markup of an externally fetched SVG.\n * @internal\n */\n @state()\n private _inlineSvg = '';\n\n /**\n * Tracks the `src` URL that was last successfully fetched so that we only\n * refetch when it genuinely changes.\n * @internal\n */\n @state()\n private _fetchedSrc: string | undefined = undefined;\n\n /**\n * Monotonically-increasing sequence number. Incremented before each fetch so\n * that stale out-of-order responses can be discarded.\n */\n /** @internal */\n private _fetchSeq = 0;\n\n // ─── Lifecycle ───\n\n override updated(changed: PropertyValues<this>): void {\n super.updated(changed);\n if (changed.has('src') && this.src !== this._fetchedSrc) {\n void this._fetchInlineSvg(this.src);\n }\n }\n\n // ─── Inline SVG Fetch ───\n\n /** @internal */\n private async _fetchInlineSvg(url: string | undefined): Promise<void> {\n const seq = ++this._fetchSeq;\n\n if (!url) {\n this._inlineSvg = '';\n this._fetchedSrc = undefined;\n return;\n }\n\n // Validate URL origin — only allow same-origin or data: URIs by default.\n // Cross-origin SVGs are blocked unless explicitly allowed via allowedOrigins.\n if (!this._isAllowedOrigin(url)) {\n console.warn(\n `[hx-icon] Blocked cross-origin SVG fetch: \"${url}\". ` +\n 'Only same-origin URLs are allowed by default. ' +\n 'Set the allowed-origins attribute to permit specific external origins.',\n );\n this._inlineSvg = '';\n this._fetchedSrc = undefined;\n return;\n }\n\n // Use module-level cache to avoid duplicate network requests for the same URL.\n // Multiple hx-icon instances sharing the same src will share one in-flight fetch.\n try {\n let pending = _svgCache.get(url);\n if (!pending) {\n pending = fetch(url).then(async (response) => {\n if (!response.ok) {\n _svgCache.delete(url);\n return '';\n }\n return response.text();\n });\n _svgCache.set(url, pending);\n }\n\n const text = await pending;\n if (seq !== this._fetchSeq) return;\n\n if (!text) {\n this._inlineSvg = '';\n this._fetchedSrc = undefined;\n return;\n }\n\n const sanitized = this._sanitizeSvg(text);\n this._inlineSvg = sanitized;\n this._fetchedSrc = url;\n } catch {\n if (seq !== this._fetchSeq) return;\n _svgCache.delete(url);\n this._inlineSvg = '';\n this._fetchedSrc = undefined;\n }\n }\n\n /**\n * Checks whether a URL is same-origin or matches the configured allowedOrigins.\n * Relative URLs and data: URIs are always allowed. Cross-origin URLs are blocked\n * unless their origin appears in the allowedOrigins list.\n * @internal\n */\n private _isAllowedOrigin(url: string): boolean {\n // Relative URLs are always same-origin\n if (url.startsWith('/') || url.startsWith('./') || url.startsWith('../')) {\n return true;\n }\n\n try {\n const parsed = new URL(url, window.location.href);\n\n // Same-origin is always allowed\n if (parsed.origin === window.location.origin) {\n return true;\n }\n\n // Check configured allowlist\n if (this.allowedOrigins) {\n const allowed = this.allowedOrigins\n .split(',')\n .map((o) => o.trim().toLowerCase())\n .filter(Boolean);\n return allowed.includes(parsed.origin.toLowerCase());\n }\n\n return false;\n } catch {\n // Unparseable URL — block it\n return false;\n }\n }\n\n /**\n * Parses the raw SVG text, strips dangerous content (script elements,\n * foreignObject, on* event-handler attributes, javascript:/data: URIs,\n * and style attributes that could carry CSS injection payloads), and\n * returns the outer SVG markup safe for rendering via `unsafeHTML`.\n *\n * Additionally injects `focusable=\"false\"` on the root SVG element to\n * prevent IE11/old-Edge from making the SVG keyboard-focusable, and strips\n * any ARIA attributes from the inner SVG to prevent conflicts with the\n * wrapper's own ARIA semantics.\n */\n /** @internal */\n private _sanitizeSvg(raw: string): string {\n const parser = new DOMParser();\n const doc = parser.parseFromString(raw, 'image/svg+xml');\n\n const parseError = doc.querySelector('parsererror');\n if (parseError) {\n return '';\n }\n\n const svgEl = doc.querySelector('svg');\n if (!svgEl) {\n return '';\n }\n\n // Remove dangerous embedded elements:\n // - script: arbitrary code execution\n // - foreignObject: can embed arbitrary HTML including scripts\n // - style: CSS injection (url() payloads, expression(), external references)\n // - animate, animateTransform, animateMotion, set: SMIL animation elements\n // can trigger event handlers and modify attributes to bypass sanitization\n const dangerousElements = [\n 'script',\n 'foreignObject',\n 'style',\n 'animate',\n 'animateTransform',\n 'animateMotion',\n 'set',\n ];\n svgEl.querySelectorAll(dangerousElements.join(', ')).forEach((s) => {\n s.remove();\n });\n\n // URL-bearing attributes that can carry javascript:/data: payloads.\n const urlAttrs = new Set(['href', 'xlink:href', 'src', 'action', 'formaction']);\n\n // ARIA attributes that may conflict with the wrapper element's own semantics.\n // The wrapper <span part=\"svg\"> owns role/aria-label/aria-hidden — the inner\n // SVG must not duplicate or contradict these.\n const ariaAttrs = new Set(['role', 'aria-label', 'aria-labelledby', 'aria-hidden']);\n\n // Sanitize every element including the root svg.\n const allElements: Element[] = [svgEl, ...Array.from(svgEl.querySelectorAll('*'))];\n allElements.forEach((el) => {\n const attrs = Array.from(el.attributes);\n attrs.forEach((attr) => {\n const attrName = attr.name.toLowerCase();\n // Strip event-handler attributes.\n if (attrName.startsWith('on')) {\n el.removeAttribute(attr.name);\n return;\n }\n // Strip style attributes — CSS can carry injection payloads via\n // url(javascript:...), expression(), or external filter/clip-path references.\n if (attrName === 'style') {\n el.removeAttribute(attr.name);\n return;\n }\n // Strip javascript: and data: URIs from URL-bearing attributes.\n if (urlAttrs.has(attrName)) {\n const val = attr.value.replace(/\\s/g, '').toLowerCase();\n if (val.startsWith('javascript:') || val.startsWith('data:')) {\n el.removeAttribute(attr.name);\n }\n }\n });\n });\n\n // Strip ARIA attributes from the root SVG only — they conflict with the\n // wrapper element's ARIA. Child elements' ARIA is left intact.\n ariaAttrs.forEach((a) => svgEl.removeAttribute(a));\n\n // Inject focusable=\"false\" so IE11/old-Edge do not tab into the SVG.\n svgEl.setAttribute('focusable', 'false');\n\n return svgEl.outerHTML;\n }\n\n // ─── Render Helpers ───\n\n /**\n * Returns the href used in the `<use>` element for sprite mode.\n * If `name` already begins with `#` it is treated as an inline reference.\n */\n /** @internal */\n private _spriteHref(): string {\n const n = this.name;\n if (n.startsWith('#')) {\n return n;\n }\n const base = this.spriteUrl ?? '';\n return base ? `${base}#${n}` : `#${n}`;\n }\n\n /** @internal */\n private _renderSprite() {\n const isDecorative = !this.label.trim();\n\n return html`\n <svg\n part=\"svg\"\n class=\"icon__svg\"\n viewBox=\"0 0 24 24\"\n xmlns=\"http://www.w3.org/2000/svg\"\n role=${isDecorative ? nothing : 'img'}\n aria-label=${isDecorative ? nothing : this.label}\n aria-hidden=${isDecorative ? 'true' : nothing}\n focusable=\"false\"\n >\n ${isDecorative ? nothing : html`<title>${this.label}</title>`}\n <use href=${this._spriteHref()}></use>\n </svg>\n `;\n }\n\n /** @internal */\n private _renderInline() {\n if (!this._inlineSvg) {\n return nothing;\n }\n\n const isDecorative = !this.label.trim();\n\n // The fetched SVG is rendered inside a wrapper span that carries the\n // csspart and ARIA semantics. The inner SVG from unsafeHTML fills the\n // container via the `.icon__inline svg` CSS rule. ARIA attributes and\n // focusable=\"false\" are injected into the inner SVG by _sanitizeSvg.\n return html`\n <span\n part=\"svg\"\n class=\"icon__inline\"\n role=${isDecorative ? nothing : 'img'}\n aria-label=${isDecorative ? nothing : this.label}\n aria-hidden=${isDecorative ? 'true' : nothing}\n >\n ${unsafeHTML(this._inlineSvg)}\n </span>\n `;\n }\n\n // ─── Render ───\n\n override render() {\n // Inline fetch mode takes precedence when src is a non-empty string.\n if (typeof this.src === 'string' && this.src.trim().length > 0) {\n return this._renderInline();\n }\n\n // Sprite mode: requires at least a name.\n if (this.name) {\n return this._renderSprite();\n }\n\n return nothing;\n }\n}\n\n/**\n * Module-level SVG fetch cache. Shared across all `hx-icon` instances so that\n * multiple icons sharing the same `src` URL issue only one network request.\n * The cache stores in-flight `Promise<string>` values — resolved entries remain\n * cached for the lifetime of the page to prevent redundant re-fetches.\n */\nconst _svgCache = new Map<string, Promise<string>>();\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'hx-icon': HelixIcon;\n }\n}\n"],"names":["helixIconStyles","css","HelixIcon","HelixElement","changed","url","seq","pending","_svgCache","response","text","sanitized","parsed","o","raw","doc","svgEl","dangerousElements","s","urlAttrs","ariaAttrs","el","attr","attrName","val","a","n","base","isDecorative","html","nothing","unsafeHTML","__decorateClass","property","state","customElement"],"mappings":"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"}
@@ -80,7 +80,7 @@ const m = x`
80
80
 
81
81
  .button--primary {
82
82
  --hx-icon-button-bg: var(--hx-color-primary-500);
83
- --hx-icon-button-color: var(--hx-color-neutral-0);
83
+ --hx-icon-button-color: var(--hx-color-text-on-primary);
84
84
  --hx-icon-button-border-color: transparent;
85
85
  }
86
86
 
@@ -100,17 +100,17 @@ const m = x`
100
100
 
101
101
  .button--tertiary {
102
102
  --hx-icon-button-bg: transparent;
103
- --hx-icon-button-color: var(--hx-color-neutral-700);
104
- --hx-icon-button-border-color: var(--hx-color-neutral-300);
103
+ --hx-icon-button-color: var(--hx-color-text-strong);
104
+ --hx-icon-button-border-color: var(--hx-color-border-strong);
105
105
  }
106
106
 
107
107
  .button--tertiary:hover {
108
- --hx-icon-button-bg: var(--hx-color-neutral-100);
108
+ --hx-icon-button-bg: var(--hx-color-surface-sunken);
109
109
  }
110
110
 
111
111
  .button--danger {
112
112
  --hx-icon-button-bg: var(--hx-color-error-500);
113
- --hx-icon-button-color: var(--hx-color-neutral-0);
113
+ --hx-icon-button-color: var(--hx-color-text-on-error);
114
114
  --hx-icon-button-border-color: transparent;
115
115
  }
116
116
 
@@ -125,7 +125,7 @@ const m = x`
125
125
  }
126
126
 
127
127
  .button--ghost:hover {
128
- --hx-icon-button-bg: var(--hx-color-neutral-100);
128
+ --hx-icon-button-bg: var(--hx-color-surface-raised);
129
129
  }
130
130
 
131
131
  /* ─── Icon Container ─── */
@@ -292,4 +292,4 @@ o = r([
292
292
  export {
293
293
  o as H
294
294
  };
295
- //# sourceMappingURL=hx-icon-button-BHneqPCU.js.map
295
+ //# sourceMappingURL=hx-icon-button-CqXH5Wwb.js.map