@helixui/library 2.0.0-next.30 → 2.0.0-next.32

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 (250) hide show
  1. package/dist/base/styles.d.ts +12 -2
  2. package/dist/base/styles.d.ts.map +1 -1
  3. package/dist/components/hx-accordion/index.js +1 -1
  4. package/dist/components/hx-action-bar/index.js +1 -1
  5. package/dist/components/hx-alert/index.js +1 -1
  6. package/dist/components/hx-avatar/index.js +1 -1
  7. package/dist/components/hx-badge/index.js +1 -1
  8. package/dist/components/hx-banner/index.js +1 -1
  9. package/dist/components/hx-breadcrumb/index.js +1 -1
  10. package/dist/components/hx-button/index.js +1 -1
  11. package/dist/components/hx-button-group/index.js +1 -1
  12. package/dist/components/hx-card/index.js +1 -1
  13. package/dist/components/hx-carousel/index.js +1 -1
  14. package/dist/components/hx-checkbox/index.js +1 -1
  15. package/dist/components/hx-checkbox-group/index.js +1 -1
  16. package/dist/components/hx-clinical-status/index.js +1 -1
  17. package/dist/components/hx-code-snippet/index.js +1 -1
  18. package/dist/components/hx-color-picker/index.js +1 -1
  19. package/dist/components/hx-combobox/index.js +1 -1
  20. package/dist/components/hx-container/index.js +1 -1
  21. package/dist/components/hx-copy-button/index.js +1 -1
  22. package/dist/components/hx-counter/index.js +1 -1
  23. package/dist/components/hx-data-table/index.js +1 -1
  24. package/dist/components/hx-date-picker/index.js +1 -1
  25. package/dist/components/hx-dialog/index.js +1 -1
  26. package/dist/components/hx-divider/index.js +1 -1
  27. package/dist/components/hx-drawer/index.js +1 -1
  28. package/dist/components/hx-dropdown/index.js +1 -1
  29. package/dist/components/hx-field/index.js +1 -1
  30. package/dist/components/hx-field-label/index.js +1 -1
  31. package/dist/components/hx-file-upload/index.js +1 -1
  32. package/dist/components/hx-format-date/index.js +1 -1
  33. package/dist/components/hx-grid/index.js +1 -1
  34. package/dist/components/hx-help-text/index.js +1 -1
  35. package/dist/components/hx-icon/index.js +1 -1
  36. package/dist/components/hx-icon-button/index.js +1 -1
  37. package/dist/components/hx-image/index.js +1 -1
  38. package/dist/components/hx-link/index.js +1 -1
  39. package/dist/components/hx-list/index.js +1 -1
  40. package/dist/components/hx-menu/index.js +1 -1
  41. package/dist/components/hx-meter/index.js +1 -1
  42. package/dist/components/hx-nav/index.js +1 -1
  43. package/dist/components/hx-number-input/index.js +1 -1
  44. package/dist/components/hx-overflow-menu/index.js +1 -1
  45. package/dist/components/hx-pagination/index.js +1 -1
  46. package/dist/components/hx-patient-banner/index.js +1 -1
  47. package/dist/components/hx-phi-field/index.js +1 -1
  48. package/dist/components/hx-popover/index.js +1 -1
  49. package/dist/components/hx-popup/index.js +1 -1
  50. package/dist/components/hx-progress-bar/index.js +1 -1
  51. package/dist/components/hx-progress-ring/index.js +1 -1
  52. package/dist/components/hx-radio-group/index.js +1 -1
  53. package/dist/components/hx-rating/index.js +1 -1
  54. package/dist/components/hx-select/index.js +1 -1
  55. package/dist/components/hx-side-nav/index.js +1 -1
  56. package/dist/components/hx-skeleton/index.js +1 -1
  57. package/dist/components/hx-slider/index.js +1 -1
  58. package/dist/components/hx-spinner/index.js +1 -1
  59. package/dist/components/hx-split-button/index.js +1 -1
  60. package/dist/components/hx-split-panel/index.js +1 -1
  61. package/dist/components/hx-stack/index.js +1 -1
  62. package/dist/components/hx-stat/index.js +1 -1
  63. package/dist/components/hx-status-indicator/index.js +1 -1
  64. package/dist/components/hx-steps/index.js +1 -1
  65. package/dist/components/hx-structured-list/index.js +1 -1
  66. package/dist/components/hx-style-scope/index.js +1 -1
  67. package/dist/components/hx-switch/index.js +1 -1
  68. package/dist/components/hx-table/index.js +1 -1
  69. package/dist/components/hx-tabs/index.js +1 -1
  70. package/dist/components/hx-tag/index.js +1 -1
  71. package/dist/components/hx-text/index.js +1 -1
  72. package/dist/components/hx-text-input/index.js +1 -1
  73. package/dist/components/hx-textarea/index.js +1 -1
  74. package/dist/components/hx-theme/index.js +1 -1
  75. package/dist/components/hx-time-picker/index.js +1 -1
  76. package/dist/components/hx-toast/index.js +1 -1
  77. package/dist/components/hx-toggle-button/index.js +1 -1
  78. package/dist/components/hx-tooltip/index.js +1 -1
  79. package/dist/components/hx-top-nav/index.js +1 -1
  80. package/dist/components/hx-tree-view/index.js +1 -1
  81. package/dist/components/hx-visually-hidden/index.js +1 -1
  82. package/dist/css/index.css +1 -1
  83. package/dist/css/manifest.json +1 -1
  84. package/dist/index.js +80 -80
  85. package/dist/index.js.map +1 -1
  86. package/dist/shared/document-token-adoption-DuYNKd4k.js +21 -0
  87. package/dist/shared/document-token-adoption-DuYNKd4k.js.map +1 -0
  88. package/dist/shared/{hx-accordion-Cvs-uzZq.js → hx-accordion-CpfO0YQo.js} +2 -2
  89. package/dist/shared/{hx-accordion-Cvs-uzZq.js.map → hx-accordion-CpfO0YQo.js.map} +1 -1
  90. package/dist/shared/{hx-action-bar-B2BNlKQv.js → hx-action-bar-BpY1Z1UV.js} +2 -2
  91. package/dist/shared/{hx-action-bar-B2BNlKQv.js.map → hx-action-bar-BpY1Z1UV.js.map} +1 -1
  92. package/dist/shared/{hx-alert-CnDlZO6m.js → hx-alert-CHOjTBds.js} +2 -2
  93. package/dist/shared/{hx-alert-CnDlZO6m.js.map → hx-alert-CHOjTBds.js.map} +1 -1
  94. package/dist/shared/{hx-avatar-C68g1G2e.js → hx-avatar-an-WsuLl.js} +2 -2
  95. package/dist/shared/{hx-avatar-C68g1G2e.js.map → hx-avatar-an-WsuLl.js.map} +1 -1
  96. package/dist/shared/{hx-badge-D5vy_5BO.js → hx-badge-DDXTLoWi.js} +2 -2
  97. package/dist/shared/{hx-badge-D5vy_5BO.js.map → hx-badge-DDXTLoWi.js.map} +1 -1
  98. package/dist/shared/{hx-banner-Ccif-GaB.js → hx-banner-B-WEDiq7.js} +2 -2
  99. package/dist/shared/{hx-banner-Ccif-GaB.js.map → hx-banner-B-WEDiq7.js.map} +1 -1
  100. package/dist/shared/{hx-breadcrumb-item-DhxDZI3r.js → hx-breadcrumb-item-DzLyeL5Z.js} +2 -2
  101. package/dist/shared/{hx-breadcrumb-item-DhxDZI3r.js.map → hx-breadcrumb-item-DzLyeL5Z.js.map} +1 -1
  102. package/dist/shared/{hx-button-BF3VwcOJ.js → hx-button-DoN8jjQT.js} +2 -2
  103. package/dist/shared/{hx-button-BF3VwcOJ.js.map → hx-button-DoN8jjQT.js.map} +1 -1
  104. package/dist/shared/{hx-button-group-B8u25JjV.js → hx-button-group-BXlMQTt_.js} +2 -2
  105. package/dist/shared/{hx-button-group-B8u25JjV.js.map → hx-button-group-BXlMQTt_.js.map} +1 -1
  106. package/dist/shared/{hx-card-Dps4jvG9.js → hx-card-BgXZXDuc.js} +2 -2
  107. package/dist/shared/{hx-card-Dps4jvG9.js.map → hx-card-BgXZXDuc.js.map} +1 -1
  108. package/dist/shared/{hx-carousel-item-Dmo9pGFm.js → hx-carousel-item-Dwt9Pphz.js} +2 -2
  109. package/dist/shared/{hx-carousel-item-Dmo9pGFm.js.map → hx-carousel-item-Dwt9Pphz.js.map} +1 -1
  110. package/dist/shared/{hx-checkbox-99zyEKj7.js → hx-checkbox-CTEZ9IFq.js} +2 -2
  111. package/dist/shared/{hx-checkbox-99zyEKj7.js.map → hx-checkbox-CTEZ9IFq.js.map} +1 -1
  112. package/dist/shared/{hx-checkbox-group-J2CGHDwY.js → hx-checkbox-group-DThZeN5d.js} +2 -2
  113. package/dist/shared/{hx-checkbox-group-J2CGHDwY.js.map → hx-checkbox-group-DThZeN5d.js.map} +1 -1
  114. package/dist/shared/{hx-clinical-status-CGx5q5PL.js → hx-clinical-status-m4soOOwg.js} +2 -2
  115. package/dist/shared/{hx-clinical-status-CGx5q5PL.js.map → hx-clinical-status-m4soOOwg.js.map} +1 -1
  116. package/dist/shared/{hx-code-snippet-vAzJjm2O.js → hx-code-snippet-CoLYvX1Z.js} +2 -2
  117. package/dist/shared/{hx-code-snippet-vAzJjm2O.js.map → hx-code-snippet-CoLYvX1Z.js.map} +1 -1
  118. package/dist/shared/{hx-color-picker-CzMu9Fzw.js → hx-color-picker-DhOaNe6-.js} +2 -2
  119. package/dist/shared/{hx-color-picker-CzMu9Fzw.js.map → hx-color-picker-DhOaNe6-.js.map} +1 -1
  120. package/dist/shared/{hx-combobox-Dhw33U40.js → hx-combobox-BJ4lQocO.js} +2 -2
  121. package/dist/shared/{hx-combobox-Dhw33U40.js.map → hx-combobox-BJ4lQocO.js.map} +1 -1
  122. package/dist/shared/{hx-container-Dz4v6FSd.js → hx-container-31QT9KV_.js} +2 -2
  123. package/dist/shared/{hx-container-Dz4v6FSd.js.map → hx-container-31QT9KV_.js.map} +1 -1
  124. package/dist/shared/{hx-copy-button-Dcul7VwZ.js → hx-copy-button-BoM0WsMd.js} +2 -2
  125. package/dist/shared/{hx-copy-button-Dcul7VwZ.js.map → hx-copy-button-BoM0WsMd.js.map} +1 -1
  126. package/dist/shared/{hx-counter-czWWvciz.js → hx-counter-CP42cSVK.js} +2 -2
  127. package/dist/shared/{hx-counter-czWWvciz.js.map → hx-counter-CP42cSVK.js.map} +1 -1
  128. package/dist/shared/{hx-data-table-CAVgT4JG.js → hx-data-table-D5Ne-goy.js} +2 -2
  129. package/dist/shared/{hx-data-table-CAVgT4JG.js.map → hx-data-table-D5Ne-goy.js.map} +1 -1
  130. package/dist/shared/{hx-date-picker-Be8lTTO7.js → hx-date-picker-Cd3I3WkX.js} +2 -2
  131. package/dist/shared/{hx-date-picker-Be8lTTO7.js.map → hx-date-picker-Cd3I3WkX.js.map} +1 -1
  132. package/dist/shared/{hx-dialog-DTGX2FbP.js → hx-dialog-D4ubstxx.js} +2 -2
  133. package/dist/shared/{hx-dialog-DTGX2FbP.js.map → hx-dialog-D4ubstxx.js.map} +1 -1
  134. package/dist/shared/{hx-divider-BJjarZ9z.js → hx-divider-BBtOLHRP.js} +2 -2
  135. package/dist/shared/{hx-divider-BJjarZ9z.js.map → hx-divider-BBtOLHRP.js.map} +1 -1
  136. package/dist/shared/{hx-drawer-C5qI7jf1.js → hx-drawer--WDLuWtS.js} +2 -2
  137. package/dist/shared/{hx-drawer-C5qI7jf1.js.map → hx-drawer--WDLuWtS.js.map} +1 -1
  138. package/dist/shared/{hx-dropdown-BxNnUDyD.js → hx-dropdown-n5-XSmiV.js} +2 -2
  139. package/dist/shared/{hx-dropdown-BxNnUDyD.js.map → hx-dropdown-n5-XSmiV.js.map} +1 -1
  140. package/dist/shared/{hx-field-J1IUbQ8n.js → hx-field-CwT9tki1.js} +2 -2
  141. package/dist/shared/{hx-field-J1IUbQ8n.js.map → hx-field-CwT9tki1.js.map} +1 -1
  142. package/dist/shared/{hx-field-label-DhVdkhCN.js → hx-field-label-CcOK9VU3.js} +2 -2
  143. package/dist/shared/{hx-field-label-DhVdkhCN.js.map → hx-field-label-CcOK9VU3.js.map} +1 -1
  144. package/dist/shared/{hx-file-upload-79nMhnM_.js → hx-file-upload-Dwtu3WcB.js} +2 -2
  145. package/dist/shared/{hx-file-upload-79nMhnM_.js.map → hx-file-upload-Dwtu3WcB.js.map} +1 -1
  146. package/dist/shared/{hx-format-date-BMukpO2t.js → hx-format-date-B7L9odbA.js} +2 -2
  147. package/dist/shared/{hx-format-date-BMukpO2t.js.map → hx-format-date-B7L9odbA.js.map} +1 -1
  148. package/dist/shared/{hx-grid-CO6JZ6Kn.js → hx-grid-BIAR5h9m.js} +2 -2
  149. package/dist/shared/{hx-grid-CO6JZ6Kn.js.map → hx-grid-BIAR5h9m.js.map} +1 -1
  150. package/dist/shared/{hx-help-text-CYGvBLET.js → hx-help-text-Bmb80bP4.js} +2 -2
  151. package/dist/shared/{hx-help-text-CYGvBLET.js.map → hx-help-text-Bmb80bP4.js.map} +1 -1
  152. package/dist/shared/{hx-icon-C1hDsw-b.js → hx-icon-BKHs3OLu.js} +2 -2
  153. package/dist/shared/{hx-icon-C1hDsw-b.js.map → hx-icon-BKHs3OLu.js.map} +1 -1
  154. package/dist/shared/{hx-icon-button-DOWKUs0-.js → hx-icon-button-CJuy9xbw.js} +2 -2
  155. package/dist/shared/{hx-icon-button-DOWKUs0-.js.map → hx-icon-button-CJuy9xbw.js.map} +1 -1
  156. package/dist/shared/{hx-image-BqABFHGZ.js → hx-image-ztiXumZB.js} +2 -2
  157. package/dist/shared/{hx-image-BqABFHGZ.js.map → hx-image-ztiXumZB.js.map} +1 -1
  158. package/dist/shared/{hx-link-CAFRuAKJ.js → hx-link-IVsXmsKx.js} +2 -2
  159. package/dist/shared/{hx-link-CAFRuAKJ.js.map → hx-link-IVsXmsKx.js.map} +1 -1
  160. package/dist/shared/{hx-list-zbgO-9Xe.js → hx-list-CoTDMp19.js} +2 -2
  161. package/dist/shared/{hx-list-zbgO-9Xe.js.map → hx-list-CoTDMp19.js.map} +1 -1
  162. package/dist/shared/{hx-menu-divider-B1TIKAaq.js → hx-menu-divider-DRT8yHRZ.js} +2 -2
  163. package/dist/shared/{hx-menu-divider-B1TIKAaq.js.map → hx-menu-divider-DRT8yHRZ.js.map} +1 -1
  164. package/dist/shared/{hx-meter-BWNeWrg2.js → hx-meter-BvSJoqDp.js} +2 -2
  165. package/dist/shared/{hx-meter-BWNeWrg2.js.map → hx-meter-BvSJoqDp.js.map} +1 -1
  166. package/dist/shared/{hx-nav-item-D-9uG-Tt.js → hx-nav-item-CJN4VDrf.js} +2 -2
  167. package/dist/shared/{hx-nav-item-D-9uG-Tt.js.map → hx-nav-item-CJN4VDrf.js.map} +1 -1
  168. package/dist/shared/{hx-nav-DqNzqH2s.js → hx-nav-l0Rp7WPW.js} +2 -2
  169. package/dist/shared/{hx-nav-DqNzqH2s.js.map → hx-nav-l0Rp7WPW.js.map} +1 -1
  170. package/dist/shared/{hx-number-input-D7Jczm0J.js → hx-number-input-0Waw7Z7u.js} +2 -2
  171. package/dist/shared/{hx-number-input-D7Jczm0J.js.map → hx-number-input-0Waw7Z7u.js.map} +1 -1
  172. package/dist/shared/{hx-overflow-menu-UvSgk7yV.js → hx-overflow-menu-DElwFSCd.js} +2 -2
  173. package/dist/shared/{hx-overflow-menu-UvSgk7yV.js.map → hx-overflow-menu-DElwFSCd.js.map} +1 -1
  174. package/dist/shared/{hx-pagination-DBovb97q.js → hx-pagination-BNtx-LG6.js} +2 -2
  175. package/dist/shared/{hx-pagination-DBovb97q.js.map → hx-pagination-BNtx-LG6.js.map} +1 -1
  176. package/dist/shared/{hx-patient-banner-DLeU2pC2.js → hx-patient-banner-BKiN7nIE.js} +2 -2
  177. package/dist/shared/{hx-patient-banner-DLeU2pC2.js.map → hx-patient-banner-BKiN7nIE.js.map} +1 -1
  178. package/dist/shared/{hx-phi-field-BwlVKfHI.js → hx-phi-field-BiJH3V-k.js} +2 -2
  179. package/dist/shared/{hx-phi-field-BwlVKfHI.js.map → hx-phi-field-BiJH3V-k.js.map} +1 -1
  180. package/dist/shared/{hx-popover-DdjLdSr8.js → hx-popover-D63RXn5H.js} +2 -2
  181. package/dist/shared/{hx-popover-DdjLdSr8.js.map → hx-popover-D63RXn5H.js.map} +1 -1
  182. package/dist/shared/{hx-popup-DEYZKeH1.js → hx-popup-BQWMhvMO.js} +2 -2
  183. package/dist/shared/{hx-popup-DEYZKeH1.js.map → hx-popup-BQWMhvMO.js.map} +1 -1
  184. package/dist/shared/{hx-progress-bar-CdbFsimb.js → hx-progress-bar-Cm0VihTN.js} +2 -2
  185. package/dist/shared/{hx-progress-bar-CdbFsimb.js.map → hx-progress-bar-Cm0VihTN.js.map} +1 -1
  186. package/dist/shared/{hx-progress-ring-3YcGRxes.js → hx-progress-ring-BJeiDr3q.js} +2 -2
  187. package/dist/shared/{hx-progress-ring-3YcGRxes.js.map → hx-progress-ring-BJeiDr3q.js.map} +1 -1
  188. package/dist/shared/{hx-radio-BCEpX1tj.js → hx-radio-f8c5ggHG.js} +2 -2
  189. package/dist/shared/{hx-radio-BCEpX1tj.js.map → hx-radio-f8c5ggHG.js.map} +1 -1
  190. package/dist/shared/{hx-rating-BXnSN-Ln.js → hx-rating-qRJZXskm.js} +2 -2
  191. package/dist/shared/{hx-rating-BXnSN-Ln.js.map → hx-rating-qRJZXskm.js.map} +1 -1
  192. package/dist/shared/{hx-select-vzsOOYNx.js → hx-select-B5wq9Swh.js} +2 -2
  193. package/dist/shared/{hx-select-vzsOOYNx.js.map → hx-select-B5wq9Swh.js.map} +1 -1
  194. package/dist/shared/{hx-skeleton-Dikv9b7p.js → hx-skeleton-e5K9Qaxq.js} +2 -2
  195. package/dist/shared/{hx-skeleton-Dikv9b7p.js.map → hx-skeleton-e5K9Qaxq.js.map} +1 -1
  196. package/dist/shared/{hx-slider-DnncjdOT.js → hx-slider-BvXtvxmN.js} +2 -2
  197. package/dist/shared/{hx-slider-DnncjdOT.js.map → hx-slider-BvXtvxmN.js.map} +1 -1
  198. package/dist/shared/{hx-spinner-B52nJ4Vt.js → hx-spinner-Dyese1Tb.js} +2 -2
  199. package/dist/shared/{hx-spinner-B52nJ4Vt.js.map → hx-spinner-Dyese1Tb.js.map} +1 -1
  200. package/dist/shared/{hx-split-button-BJHIszDb.js → hx-split-button-CPndTJlC.js} +2 -2
  201. package/dist/shared/{hx-split-button-BJHIszDb.js.map → hx-split-button-CPndTJlC.js.map} +1 -1
  202. package/dist/shared/{hx-split-panel-uNW9xrA3.js → hx-split-panel-Dx72NaET.js} +2 -2
  203. package/dist/shared/{hx-split-panel-uNW9xrA3.js.map → hx-split-panel-Dx72NaET.js.map} +1 -1
  204. package/dist/shared/{hx-stack-BHc4gVv_.js → hx-stack-B76_1O6g.js} +2 -2
  205. package/dist/shared/{hx-stack-BHc4gVv_.js.map → hx-stack-B76_1O6g.js.map} +1 -1
  206. package/dist/shared/{hx-stat-BfgKgBeq.js → hx-stat-DKD2E7An.js} +2 -2
  207. package/dist/shared/{hx-stat-BfgKgBeq.js.map → hx-stat-DKD2E7An.js.map} +1 -1
  208. package/dist/shared/{hx-status-indicator-C146uMF0.js → hx-status-indicator-ClWpK6zz.js} +2 -2
  209. package/dist/shared/{hx-status-indicator-C146uMF0.js.map → hx-status-indicator-ClWpK6zz.js.map} +1 -1
  210. package/dist/shared/{hx-step-C0Unvyen.js → hx-step-C2Jk4mHa.js} +2 -2
  211. package/dist/shared/{hx-step-C0Unvyen.js.map → hx-step-C2Jk4mHa.js.map} +1 -1
  212. package/dist/shared/{hx-structured-list-3R69RETR.js → hx-structured-list-DKlrv7kS.js} +2 -2
  213. package/dist/shared/{hx-structured-list-3R69RETR.js.map → hx-structured-list-DKlrv7kS.js.map} +1 -1
  214. package/dist/shared/{hx-style-scope-D3dsKS58.js → hx-style-scope-CsQ2Phf_.js} +2 -2
  215. package/dist/shared/{hx-style-scope-D3dsKS58.js.map → hx-style-scope-CsQ2Phf_.js.map} +1 -1
  216. package/dist/shared/{hx-switch-BCNpbuk-.js → hx-switch-BzMN37PV.js} +2 -2
  217. package/dist/shared/{hx-switch-BCNpbuk-.js.map → hx-switch-BzMN37PV.js.map} +1 -1
  218. package/dist/shared/{hx-tab-panel-D7BTBgDQ.js → hx-tab-panel-J58zOSjq.js} +2 -2
  219. package/dist/shared/{hx-tab-panel-D7BTBgDQ.js.map → hx-tab-panel-J58zOSjq.js.map} +1 -1
  220. package/dist/shared/{hx-tag-C2E-6fJ3.js → hx-tag-F0ZcYj9b.js} +2 -2
  221. package/dist/shared/{hx-tag-C2E-6fJ3.js.map → hx-tag-F0ZcYj9b.js.map} +1 -1
  222. package/dist/shared/{hx-td-DWcp2XDO.js → hx-td-CNCvzBwY.js} +2 -2
  223. package/dist/shared/{hx-td-DWcp2XDO.js.map → hx-td-CNCvzBwY.js.map} +1 -1
  224. package/dist/shared/{hx-text-DxyBxz25.js → hx-text-DcWBqZwx.js} +2 -2
  225. package/dist/shared/{hx-text-DxyBxz25.js.map → hx-text-DcWBqZwx.js.map} +1 -1
  226. package/dist/shared/{hx-text-input-2LTGt0vQ.js → hx-text-input-Scyeefec.js} +2 -2
  227. package/dist/shared/{hx-text-input-2LTGt0vQ.js.map → hx-text-input-Scyeefec.js.map} +1 -1
  228. package/dist/shared/{hx-textarea-BZspivFK.js → hx-textarea-BfSJJtA1.js} +2 -2
  229. package/dist/shared/{hx-textarea-BZspivFK.js.map → hx-textarea-BfSJJtA1.js.map} +1 -1
  230. package/dist/shared/{hx-theme-J2YEpSIL.js → hx-theme-pc1V7dyL.js} +2 -2
  231. package/dist/shared/{hx-theme-J2YEpSIL.js.map → hx-theme-pc1V7dyL.js.map} +1 -1
  232. package/dist/shared/{hx-time-picker-CVrw4tju.js → hx-time-picker-CZvmihHD.js} +2 -2
  233. package/dist/shared/{hx-time-picker-CVrw4tju.js.map → hx-time-picker-CZvmihHD.js.map} +1 -1
  234. package/dist/shared/{hx-toggle-button-Ss7Gppx3.js → hx-toggle-button-BZUQUULm.js} +2 -2
  235. package/dist/shared/{hx-toggle-button-Ss7Gppx3.js.map → hx-toggle-button-BZUQUULm.js.map} +1 -1
  236. package/dist/shared/{hx-tooltip-xRNjEX7_.js → hx-tooltip-Ny4i1Idj.js} +2 -2
  237. package/dist/shared/{hx-tooltip-xRNjEX7_.js.map → hx-tooltip-Ny4i1Idj.js.map} +1 -1
  238. package/dist/shared/{hx-top-nav-28mxYGuj.js → hx-top-nav-CC4FW2Hp.js} +2 -2
  239. package/dist/shared/{hx-top-nav-28mxYGuj.js.map → hx-top-nav-CC4FW2Hp.js.map} +1 -1
  240. package/dist/shared/{hx-tree-item-C-cRw_ZA.js → hx-tree-item-CPQ9dJiK.js} +2 -2
  241. package/dist/shared/{hx-tree-item-C-cRw_ZA.js.map → hx-tree-item-CPQ9dJiK.js.map} +1 -1
  242. package/dist/shared/{hx-visually-hidden-D6Dv2l8l.js → hx-visually-hidden-vKX8QjeX.js} +2 -2
  243. package/dist/shared/{hx-visually-hidden-D6Dv2l8l.js.map → hx-visually-hidden-vKX8QjeX.js.map} +1 -1
  244. package/dist/shared/{toast-factory-oPHbhMZI.js → toast-factory-CEMNOt1T.js} +2 -2
  245. package/dist/shared/{toast-factory-oPHbhMZI.js.map → toast-factory-CEMNOt1T.js.map} +1 -1
  246. package/dist/utilities/document-token-adoption.d.ts +1 -1
  247. package/dist/utilities/document-token-adoption.d.ts.map +1 -1
  248. package/package.json +2 -2
  249. package/dist/shared/document-token-adoption-Dym9ALA4.js +0 -15
  250. package/dist/shared/document-token-adoption-Dym9ALA4.js.map +0 -1
@@ -1,5 +1,5 @@
1
1
  import { css as p, LitElement as _, nothing as c, html as n } from "lit";
2
- import "./document-token-adoption-Dym9ALA4.js";
2
+ import "./document-token-adoption-DuYNKd4k.js";
3
3
  import { property as o, state as f, customElement as u } from "lit/decorators.js";
4
4
  import { classMap as x } from "lit/directives/class-map.js";
5
5
  import { d as b } from "./dev-warn-YlwPHjtX.js";
@@ -316,4 +316,4 @@ r = l([
316
316
  export {
317
317
  r as H
318
318
  };
319
- //# sourceMappingURL=hx-field-J1IUbQ8n.js.map
319
+ //# sourceMappingURL=hx-field-CwT9tki1.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"hx-field-J1IUbQ8n.js","sources":["../../src/components/hx-field/hx-field.styles.ts","../../src/components/hx-field/hx-field.ts"],"sourcesContent":["import { css } from 'lit';\n\nexport const helixFieldStyles = 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-field-gap, var(--hx-space-1, 0.25rem));\n font-family: var(--hx-field-font-family, var(--hx-font-family-sans, sans-serif));\n }\n\n /* ─── Inline Layout ─── */\n\n .field--layout-inline {\n flex-direction: row;\n align-items: baseline;\n flex-wrap: wrap;\n }\n\n .field--layout-inline .field__label-wrapper {\n display: flex;\n align-items: baseline;\n flex-shrink: 0;\n min-width: 8rem;\n }\n\n /* ─── Label ─── */\n\n .field__label-wrapper {\n display: contents;\n }\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-field-label-color, var(--hx-color-neutral-700, #374151));\n line-height: var(--hx-line-height-normal, 1.5);\n cursor: pointer;\n }\n\n .field__required-marker {\n color: var(--hx-field-error-color, var(--hx-color-error-text, #b91c1c));\n font-weight: var(--hx-font-weight-bold, 700);\n }\n\n /* ─── Control Wrapper ─── */\n\n .field__control {\n display: block;\n }\n\n /* ─── Error Slot Announcer (visually hidden live region) ─── */\n\n .field__error-slot-announcer {\n position: absolute;\n width: 1px;\n height: 1px;\n overflow: hidden;\n clip: rect(0, 0, 0, 0);\n white-space: nowrap;\n border: 0;\n }\n\n /* ─── Size Variants ─── */\n\n :host([hx-size='sm']) .field__label {\n font-size: var(--hx-font-size-xs, 0.75rem);\n }\n\n :host([hx-size='lg']) .field__label {\n font-size: var(--hx-font-size-md, 1rem);\n }\n\n :host([hx-size='sm']) .field__help-text {\n font-size: var(--hx-font-size-xs, 0.75rem);\n }\n\n :host([hx-size='lg']) .field__help-text {\n font-size: var(--hx-font-size-sm, 0.875rem);\n }\n\n /* ─── Help Text & Error Messages ─── */\n\n .field__help-text {\n font-size: var(--hx-font-size-xs, 0.75rem);\n color: var(--hx-field-help-text-color, var(--hx-color-neutral-500, #6b7280));\n line-height: var(--hx-line-height-normal, 1.5);\n }\n\n .field__error {\n font-size: var(--hx-font-size-xs, 0.75rem);\n color: var(--hx-field-error-color, var(--hx-color-error-text, #b91c1c));\n line-height: var(--hx-line-height-normal, 1.5);\n }\n\n /* ─── Error State ─── */\n\n .field--error .field__label {\n color: var(--hx-field-error-color, var(--hx-color-error-text, #b91c1c));\n }\n\n .field--error .field__control {\n outline: 2px solid var(--hx-field-error-color, var(--hx-color-error-500, #ef4444));\n outline-offset: var(--hx-focus-ring-offset, 2px);\n border-radius: var(--hx-border-radius-sm, 0.25rem);\n }\n`;\n","import { LitElement, html, nothing, type PropertyValues } from 'lit';\nimport '../../utilities/document-token-adoption.js';\nimport { customElement, property, state } from 'lit/decorators.js';\nimport { classMap } from 'lit/directives/class-map.js';\nimport { helixFieldStyles } from './hx-field.styles.js';\nimport { devWarn } from '../../utils/dev-warn.js';\n\n/** Native form control tag names that can receive ARIA attributes. */\nconst FORM_CONTROL_TAGS = new Set(['INPUT', 'SELECT', 'TEXTAREA', 'BUTTON']);\n\nlet _fieldCounter = 0;\n\n/** Returns true if the element is a native form control or a custom element. */\nfunction isFormControl(el: Element): el is HTMLElement {\n return FORM_CONTROL_TAGS.has(el.tagName) || el.tagName.includes('-');\n}\n\n/**\n * Layout wrapper providing consistent label + input + help text + validation\n * message structure for any form control. Use this when wrapping non-HELiX\n * form controls or native HTML elements in the HELiX form field pattern.\n *\n * This component is NOT form-associated — it is a pure visual layout wrapper.\n *\n * **Light DOM side effect:** This component injects a visually-hidden `<span>`\n * into its light DOM children for ARIA describedby linkage across the shadow\n * DOM boundary. This span has `id=\"${fieldId}-desc\"` and is removed on\n * `disconnectedCallback`. This is an intentional, documented accessibility\n * mechanism.\n *\n * @summary Layout wrapper for label, control, help text, and error message.\n *\n * @tag hx-field\n *\n * @slot - The form control element (native or custom).\n * @slot label - Custom label content (overrides the label property).\n * @slot help-text - Custom help text content (overrides the helpText property).\n * @slot error - Custom error content (overrides the error property).\n * @slot description - Additional descriptive content above the control.\n *\n * @csspart field - The outer field container.\n * @csspart label - The label element.\n * @csspart control - The wrapper around slotted content.\n * @csspart help-text - The help text container.\n * @csspart error-message - The error message container.\n * @csspart required-indicator - The required asterisk span.\n *\n * @cssprop [--hx-field-label-color=var(--hx-color-neutral-700)] - Label color.\n * @cssprop [--hx-field-error-color=var(--hx-color-error-500)] - Error color.\n * @cssprop [--hx-field-font-family=var(--hx-font-family-sans)] - Font family.\n * @cssprop [--hx-field-gap=var(--hx-space-1, 0.25rem)] - Gap between field segments.\n * @cssprop [--hx-field-help-text-color=var(--hx-color-neutral-500)] - Help text color.\n */\n@customElement('hx-field')\nexport class HelixField extends LitElement {\n static override styles = [helixFieldStyles];\n\n // ─── Properties ───\n\n /**\n * The visible label text for the field.\n * @attr label\n */\n @property({ type: String })\n label = '';\n\n /**\n * Whether the field is required. Shows a required indicator on the label.\n * @attr required\n */\n @property({ type: Boolean, reflect: true })\n required = false;\n\n /**\n * Error message to display. When set, the field enters an error state.\n * @attr error\n */\n @property({ type: String })\n error = '';\n\n /**\n * Help text displayed below the control for guidance.\n * @attr help-text\n */\n @property({ type: String, attribute: 'help-text' })\n helpText = '';\n\n /**\n * Visual disabled state applied via opacity. Does not affect slotted control\n * interactivity — set disabled on the slotted control directly.\n * @attr disabled\n */\n @property({ type: Boolean, reflect: true })\n disabled = false;\n\n /**\n * Size variant controlling label and help text font sizes.\n * @attr hx-size\n */\n @property({ type: String, attribute: 'hx-size', reflect: true })\n size: 'sm' | 'md' | 'lg' = 'md';\n\n /**\n * Layout variant. 'column' stacks label above control; 'inline' places them side-by-side.\n * @attr layout\n */\n @property({ type: String, reflect: true })\n layout: 'column' | 'inline' = 'column';\n\n // ─── Slot Tracking ───\n\n /**\n * Tracks whether any content is assigned to the label slot, used to conditionally render the label property.\n * @internal\n */\n @state() private _hasLabelSlot = false;\n\n /**\n * Tracks whether any content is assigned to the error slot, used to toggle error state rendering.\n * @internal\n */\n @state() private _hasErrorSlot = false;\n\n /**\n * Tracks whether any content is assigned to the help-text slot, used to toggle help text rendering.\n * @internal\n */\n @state() private _hasHelpSlot = false;\n\n /** @internal */\n private _handleLabelSlotChange(e: Event): void {\n const slot = e.target as HTMLSlotElement;\n this._hasLabelSlot = slot.assignedElements().length > 0;\n }\n\n /** @internal */\n private _handleErrorSlotChange(e: Event): void {\n const slot = e.target as HTMLSlotElement;\n this._hasErrorSlot = slot.assignedElements().length > 0;\n }\n\n /** @internal */\n private _handleHelpSlotChange(e: Event): void {\n const slot = e.target as HTMLSlotElement;\n this._hasHelpSlot = slot.assignedElements().length > 0;\n }\n\n // ─── Unique IDs for Accessibility ───\n\n /**\n * Unique ID for this field instance, used as a base for all derived accessibility IDs.\n * @internal\n */\n private _fieldId = `hx-field-${++_fieldCounter}`;\n\n /**\n * ID for the help text element, allowing aria-describedby to reference it.\n * @internal\n */\n private _helpTextId = `${this._fieldId}-help`;\n\n /**\n * ID for the error message element, allowing aria-describedby to reference it.\n * @internal\n */\n private _errorId = `${this._fieldId}-error`;\n\n /**\n * ID for the light-DOM description span injected for cross-shadow-root aria-describedby linkage.\n * @internal\n */\n private _a11yDescId = `${this._fieldId}-desc`;\n\n // ─── A11y: Slotted control tracking + light-DOM description element ───\n\n /**\n * The first form control in the default slot. We set aria attributes on this\n * element to bridge the shadow DOM accessibility boundary.\n * @internal\n */\n private _slottedControl: HTMLElement | null = null;\n\n /**\n * A visually-hidden span injected into the host's light DOM (assigned to the\n * default slot). Because it lives in the same document as the slotted input,\n * `aria-describedby` can reference its ID without cross-shadow-root IDREF\n * limitations.\n *\n * **Documented side effect:** This element is intentionally injected into the\n * component's light DOM children. It is invisible to users but present in the\n * accessibility tree. It is removed in `disconnectedCallback`. Consumers\n * should not remove or modify this span (identifiable by its `id` ending in\n * `-desc`).\n * @internal\n */\n private _a11yDescEl: HTMLElement | null = null;\n\n override connectedCallback(): void {\n super.connectedCallback();\n this._ensureA11yDescEl();\n }\n\n override disconnectedCallback(): void {\n super.disconnectedCallback();\n this._a11yDescEl?.remove();\n this._a11yDescEl = null;\n // Remove aria attributes we set on the slotted control\n if (this._slottedControl) {\n this._slottedControl.removeAttribute('aria-label');\n this._slottedControl.removeAttribute('aria-required');\n this._slottedControl.removeAttribute('aria-invalid');\n this._slottedControl.removeAttribute('aria-describedby');\n this._slottedControl = null;\n }\n }\n\n override updated(changedProps: PropertyValues<this>): void {\n super.updated(changedProps);\n\n // P2-01: Warn on invalid size values\n if (changedProps.has('size')) {\n const validSizes = ['sm', 'md', 'lg'];\n if (!validSizes.includes(this.size)) {\n devWarn(\n 'hx-field',\n `Invalid hx-size value: \"${this.size}\". Expected \"sm\" | \"md\" | \"lg\". Defaulting to \"md\".`,\n );\n }\n }\n\n this._syncA11yDescEl();\n this._syncSlottedControl();\n }\n\n /** Creates a visually-hidden span in light DOM used as the ARIA description anchor. */\n /** @internal */\n private _ensureA11yDescEl(): void {\n if (this._a11yDescEl) return;\n // Guard for SSR — document is unavailable server-side\n if (typeof document === 'undefined') return;\n const span = document.createElement('span');\n span.id = this._a11yDescId;\n // Visually hidden but present in the accessibility tree\n span.style.cssText =\n 'position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0';\n this.appendChild(span);\n this._a11yDescEl = span;\n }\n\n /** Keeps the light-DOM description span in sync with the current error/help text. */\n /** @internal */\n private _syncA11yDescEl(): void {\n if (!this._a11yDescEl) return;\n const hasError = !!this.error || this._hasErrorSlot;\n if (hasError && this.error) {\n this._a11yDescEl.textContent = this.error;\n } else if (this.helpText) {\n this._a11yDescEl.textContent = this.helpText;\n } else {\n this._a11yDescEl.textContent = '';\n }\n }\n\n /** Tracks the first form control assigned to the default slot. */\n /** @internal */\n private _handleDefaultSlotChange(e: Event): void {\n const slot = e.target as HTMLSlotElement;\n const assigned = slot.assignedElements();\n this._slottedControl = assigned.find(isFormControl) ?? null;\n this._syncSlottedControl();\n }\n\n /**\n * Focuses the slotted form control when the shadow DOM label is clicked.\n * The shadow `<label>` cannot use `for`/`id` to link to a slotted input\n * across the shadow boundary, so we handle focus programmatically.\n */\n /** @internal */\n private _handleLabelClick(_e: Event): void {\n this._slottedControl?.focus();\n }\n\n /**\n * Applies ARIA attributes to the slotted form control, bridging the\n * shadow DOM accessibility boundary.\n *\n * - aria-label: associates the field label with the control\n * - aria-required: communicates required state to AT\n * - aria-invalid: communicates error state to AT\n * - aria-describedby: points to the light-DOM description span\n *\n * **Skip conditions:**\n * - `HX-*` elements manage their own ARIA attributes; bridging is skipped.\n * - Elements with `data-aria-managed` attribute opt out of ARIA mutation;\n * bridging is skipped entirely for those elements.\n */\n /** @internal */\n private _syncSlottedControl(): void {\n const control = this._slottedControl;\n if (!control) return;\n\n // hx-* elements manage their own ARIA attributes; skip bridging for them\n if (control.tagName.startsWith('HX-')) return;\n\n // Elements that declare data-aria-managed opt out of ARIA mutation\n if (control.hasAttribute('data-aria-managed')) return;\n\n const hasError = !!this.error || this._hasErrorSlot;\n const hasDesc = !!(this.error || this.helpText || this._hasErrorSlot || this._hasHelpSlot);\n\n // Label association: aria-label bridges the shadow DOM boundary\n if (this.label && !this._hasLabelSlot) {\n control.setAttribute('aria-label', this.label);\n } else {\n control.removeAttribute('aria-label');\n }\n\n // Required state\n if (this.required) {\n control.setAttribute('aria-required', 'true');\n } else {\n control.removeAttribute('aria-required');\n }\n\n // Invalid state\n if (hasError) {\n control.setAttribute('aria-invalid', 'true');\n } else {\n control.removeAttribute('aria-invalid');\n }\n\n // Description (error or help text) via light-DOM span\n if (hasDesc) {\n control.setAttribute('aria-describedby', this._a11yDescId);\n } else {\n control.removeAttribute('aria-describedby');\n }\n }\n\n // ─── Render ───\n\n override render() {\n const hasError = !!this.error || this._hasErrorSlot;\n const hasHelp = !!this.helpText || this._hasHelpSlot;\n\n const fieldClasses = {\n field: true,\n 'field--error': hasError,\n 'field--disabled': this.disabled,\n 'field--required': this.required,\n 'field--size-sm': this.size === 'sm',\n 'field--size-md': this.size === 'md',\n 'field--size-lg': this.size === 'lg',\n 'field--layout-inline': this.layout === 'inline',\n };\n\n return html`\n <div part=\"field\" class=${classMap(fieldClasses)}>\n <!-- Label -->\n <div class=\"field__label-wrapper\">\n <slot name=\"label\" @slotchange=${this._handleLabelSlotChange}>\n ${this.label && !this._hasLabelSlot\n ? html`\n <label part=\"label\" class=\"field__label\" @click=${this._handleLabelClick}>\n ${this.label}\n ${this.required\n ? html`<span\n part=\"required-indicator\"\n class=\"field__required-marker\"\n aria-hidden=\"true\"\n >*</span\n >`\n : nothing}\n </label>\n `\n : nothing}\n </slot>\n </div>\n\n <!-- Description -->\n <slot name=\"description\"></slot>\n\n <!-- Control (default slot) -->\n <div part=\"control\" class=\"field__control\">\n <slot @slotchange=${this._handleDefaultSlotChange}></slot>\n </div>\n\n <!-- Error -->\n <slot name=\"error\" @slotchange=${this._handleErrorSlotChange}>\n ${this.error\n ? html`\n <div part=\"error-message\" class=\"field__error\" id=${this._errorId} role=\"alert\">\n ${this.error}\n </div>\n `\n : nothing}\n </slot>\n\n <!-- Slotted error live region — ensures slotted error content is announced -->\n <div aria-live=\"assertive\" class=\"field__error-slot-announcer\"></div>\n\n <!-- Help text (always in DOM so slot detection works; hidden when no help or error is shown) -->\n <div\n part=\"help-text\"\n class=\"field__help-text\"\n id=${this._helpTextId}\n ?hidden=${!hasHelp || hasError}\n >\n <slot name=\"help-text\" @slotchange=${this._handleHelpSlotChange}>${this.helpText}</slot>\n </div>\n </div>\n `;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'hx-field': HelixField;\n }\n}\n"],"names":["helixFieldStyles","css","FORM_CONTROL_TAGS","_fieldCounter","isFormControl","el","HelixField","LitElement","slot","_a","changedProps","devWarn","span","assigned","_e","control","hasError","hasDesc","hasHelp","fieldClasses","html","classMap","nothing","__decorateClass","property","state","customElement"],"mappings":"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"}
1
+ {"version":3,"file":"hx-field-CwT9tki1.js","sources":["../../src/components/hx-field/hx-field.styles.ts","../../src/components/hx-field/hx-field.ts"],"sourcesContent":["import { css } from 'lit';\n\nexport const helixFieldStyles = 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-field-gap, var(--hx-space-1, 0.25rem));\n font-family: var(--hx-field-font-family, var(--hx-font-family-sans, sans-serif));\n }\n\n /* ─── Inline Layout ─── */\n\n .field--layout-inline {\n flex-direction: row;\n align-items: baseline;\n flex-wrap: wrap;\n }\n\n .field--layout-inline .field__label-wrapper {\n display: flex;\n align-items: baseline;\n flex-shrink: 0;\n min-width: 8rem;\n }\n\n /* ─── Label ─── */\n\n .field__label-wrapper {\n display: contents;\n }\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-field-label-color, var(--hx-color-neutral-700, #374151));\n line-height: var(--hx-line-height-normal, 1.5);\n cursor: pointer;\n }\n\n .field__required-marker {\n color: var(--hx-field-error-color, var(--hx-color-error-text, #b91c1c));\n font-weight: var(--hx-font-weight-bold, 700);\n }\n\n /* ─── Control Wrapper ─── */\n\n .field__control {\n display: block;\n }\n\n /* ─── Error Slot Announcer (visually hidden live region) ─── */\n\n .field__error-slot-announcer {\n position: absolute;\n width: 1px;\n height: 1px;\n overflow: hidden;\n clip: rect(0, 0, 0, 0);\n white-space: nowrap;\n border: 0;\n }\n\n /* ─── Size Variants ─── */\n\n :host([hx-size='sm']) .field__label {\n font-size: var(--hx-font-size-xs, 0.75rem);\n }\n\n :host([hx-size='lg']) .field__label {\n font-size: var(--hx-font-size-md, 1rem);\n }\n\n :host([hx-size='sm']) .field__help-text {\n font-size: var(--hx-font-size-xs, 0.75rem);\n }\n\n :host([hx-size='lg']) .field__help-text {\n font-size: var(--hx-font-size-sm, 0.875rem);\n }\n\n /* ─── Help Text & Error Messages ─── */\n\n .field__help-text {\n font-size: var(--hx-font-size-xs, 0.75rem);\n color: var(--hx-field-help-text-color, var(--hx-color-neutral-500, #6b7280));\n line-height: var(--hx-line-height-normal, 1.5);\n }\n\n .field__error {\n font-size: var(--hx-font-size-xs, 0.75rem);\n color: var(--hx-field-error-color, var(--hx-color-error-text, #b91c1c));\n line-height: var(--hx-line-height-normal, 1.5);\n }\n\n /* ─── Error State ─── */\n\n .field--error .field__label {\n color: var(--hx-field-error-color, var(--hx-color-error-text, #b91c1c));\n }\n\n .field--error .field__control {\n outline: 2px solid var(--hx-field-error-color, var(--hx-color-error-500, #ef4444));\n outline-offset: var(--hx-focus-ring-offset, 2px);\n border-radius: var(--hx-border-radius-sm, 0.25rem);\n }\n`;\n","import { LitElement, html, nothing, type PropertyValues } from 'lit';\nimport '../../utilities/document-token-adoption.js';\nimport { customElement, property, state } from 'lit/decorators.js';\nimport { classMap } from 'lit/directives/class-map.js';\nimport { helixFieldStyles } from './hx-field.styles.js';\nimport { devWarn } from '../../utils/dev-warn.js';\n\n/** Native form control tag names that can receive ARIA attributes. */\nconst FORM_CONTROL_TAGS = new Set(['INPUT', 'SELECT', 'TEXTAREA', 'BUTTON']);\n\nlet _fieldCounter = 0;\n\n/** Returns true if the element is a native form control or a custom element. */\nfunction isFormControl(el: Element): el is HTMLElement {\n return FORM_CONTROL_TAGS.has(el.tagName) || el.tagName.includes('-');\n}\n\n/**\n * Layout wrapper providing consistent label + input + help text + validation\n * message structure for any form control. Use this when wrapping non-HELiX\n * form controls or native HTML elements in the HELiX form field pattern.\n *\n * This component is NOT form-associated — it is a pure visual layout wrapper.\n *\n * **Light DOM side effect:** This component injects a visually-hidden `<span>`\n * into its light DOM children for ARIA describedby linkage across the shadow\n * DOM boundary. This span has `id=\"${fieldId}-desc\"` and is removed on\n * `disconnectedCallback`. This is an intentional, documented accessibility\n * mechanism.\n *\n * @summary Layout wrapper for label, control, help text, and error message.\n *\n * @tag hx-field\n *\n * @slot - The form control element (native or custom).\n * @slot label - Custom label content (overrides the label property).\n * @slot help-text - Custom help text content (overrides the helpText property).\n * @slot error - Custom error content (overrides the error property).\n * @slot description - Additional descriptive content above the control.\n *\n * @csspart field - The outer field container.\n * @csspart label - The label element.\n * @csspart control - The wrapper around slotted content.\n * @csspart help-text - The help text container.\n * @csspart error-message - The error message container.\n * @csspart required-indicator - The required asterisk span.\n *\n * @cssprop [--hx-field-label-color=var(--hx-color-neutral-700)] - Label color.\n * @cssprop [--hx-field-error-color=var(--hx-color-error-500)] - Error color.\n * @cssprop [--hx-field-font-family=var(--hx-font-family-sans)] - Font family.\n * @cssprop [--hx-field-gap=var(--hx-space-1, 0.25rem)] - Gap between field segments.\n * @cssprop [--hx-field-help-text-color=var(--hx-color-neutral-500)] - Help text color.\n */\n@customElement('hx-field')\nexport class HelixField extends LitElement {\n static override styles = [helixFieldStyles];\n\n // ─── Properties ───\n\n /**\n * The visible label text for the field.\n * @attr label\n */\n @property({ type: String })\n label = '';\n\n /**\n * Whether the field is required. Shows a required indicator on the label.\n * @attr required\n */\n @property({ type: Boolean, reflect: true })\n required = false;\n\n /**\n * Error message to display. When set, the field enters an error state.\n * @attr error\n */\n @property({ type: String })\n error = '';\n\n /**\n * Help text displayed below the control for guidance.\n * @attr help-text\n */\n @property({ type: String, attribute: 'help-text' })\n helpText = '';\n\n /**\n * Visual disabled state applied via opacity. Does not affect slotted control\n * interactivity — set disabled on the slotted control directly.\n * @attr disabled\n */\n @property({ type: Boolean, reflect: true })\n disabled = false;\n\n /**\n * Size variant controlling label and help text font sizes.\n * @attr hx-size\n */\n @property({ type: String, attribute: 'hx-size', reflect: true })\n size: 'sm' | 'md' | 'lg' = 'md';\n\n /**\n * Layout variant. 'column' stacks label above control; 'inline' places them side-by-side.\n * @attr layout\n */\n @property({ type: String, reflect: true })\n layout: 'column' | 'inline' = 'column';\n\n // ─── Slot Tracking ───\n\n /**\n * Tracks whether any content is assigned to the label slot, used to conditionally render the label property.\n * @internal\n */\n @state() private _hasLabelSlot = false;\n\n /**\n * Tracks whether any content is assigned to the error slot, used to toggle error state rendering.\n * @internal\n */\n @state() private _hasErrorSlot = false;\n\n /**\n * Tracks whether any content is assigned to the help-text slot, used to toggle help text rendering.\n * @internal\n */\n @state() private _hasHelpSlot = false;\n\n /** @internal */\n private _handleLabelSlotChange(e: Event): void {\n const slot = e.target as HTMLSlotElement;\n this._hasLabelSlot = slot.assignedElements().length > 0;\n }\n\n /** @internal */\n private _handleErrorSlotChange(e: Event): void {\n const slot = e.target as HTMLSlotElement;\n this._hasErrorSlot = slot.assignedElements().length > 0;\n }\n\n /** @internal */\n private _handleHelpSlotChange(e: Event): void {\n const slot = e.target as HTMLSlotElement;\n this._hasHelpSlot = slot.assignedElements().length > 0;\n }\n\n // ─── Unique IDs for Accessibility ───\n\n /**\n * Unique ID for this field instance, used as a base for all derived accessibility IDs.\n * @internal\n */\n private _fieldId = `hx-field-${++_fieldCounter}`;\n\n /**\n * ID for the help text element, allowing aria-describedby to reference it.\n * @internal\n */\n private _helpTextId = `${this._fieldId}-help`;\n\n /**\n * ID for the error message element, allowing aria-describedby to reference it.\n * @internal\n */\n private _errorId = `${this._fieldId}-error`;\n\n /**\n * ID for the light-DOM description span injected for cross-shadow-root aria-describedby linkage.\n * @internal\n */\n private _a11yDescId = `${this._fieldId}-desc`;\n\n // ─── A11y: Slotted control tracking + light-DOM description element ───\n\n /**\n * The first form control in the default slot. We set aria attributes on this\n * element to bridge the shadow DOM accessibility boundary.\n * @internal\n */\n private _slottedControl: HTMLElement | null = null;\n\n /**\n * A visually-hidden span injected into the host's light DOM (assigned to the\n * default slot). Because it lives in the same document as the slotted input,\n * `aria-describedby` can reference its ID without cross-shadow-root IDREF\n * limitations.\n *\n * **Documented side effect:** This element is intentionally injected into the\n * component's light DOM children. It is invisible to users but present in the\n * accessibility tree. It is removed in `disconnectedCallback`. Consumers\n * should not remove or modify this span (identifiable by its `id` ending in\n * `-desc`).\n * @internal\n */\n private _a11yDescEl: HTMLElement | null = null;\n\n override connectedCallback(): void {\n super.connectedCallback();\n this._ensureA11yDescEl();\n }\n\n override disconnectedCallback(): void {\n super.disconnectedCallback();\n this._a11yDescEl?.remove();\n this._a11yDescEl = null;\n // Remove aria attributes we set on the slotted control\n if (this._slottedControl) {\n this._slottedControl.removeAttribute('aria-label');\n this._slottedControl.removeAttribute('aria-required');\n this._slottedControl.removeAttribute('aria-invalid');\n this._slottedControl.removeAttribute('aria-describedby');\n this._slottedControl = null;\n }\n }\n\n override updated(changedProps: PropertyValues<this>): void {\n super.updated(changedProps);\n\n // P2-01: Warn on invalid size values\n if (changedProps.has('size')) {\n const validSizes = ['sm', 'md', 'lg'];\n if (!validSizes.includes(this.size)) {\n devWarn(\n 'hx-field',\n `Invalid hx-size value: \"${this.size}\". Expected \"sm\" | \"md\" | \"lg\". Defaulting to \"md\".`,\n );\n }\n }\n\n this._syncA11yDescEl();\n this._syncSlottedControl();\n }\n\n /** Creates a visually-hidden span in light DOM used as the ARIA description anchor. */\n /** @internal */\n private _ensureA11yDescEl(): void {\n if (this._a11yDescEl) return;\n // Guard for SSR — document is unavailable server-side\n if (typeof document === 'undefined') return;\n const span = document.createElement('span');\n span.id = this._a11yDescId;\n // Visually hidden but present in the accessibility tree\n span.style.cssText =\n 'position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0';\n this.appendChild(span);\n this._a11yDescEl = span;\n }\n\n /** Keeps the light-DOM description span in sync with the current error/help text. */\n /** @internal */\n private _syncA11yDescEl(): void {\n if (!this._a11yDescEl) return;\n const hasError = !!this.error || this._hasErrorSlot;\n if (hasError && this.error) {\n this._a11yDescEl.textContent = this.error;\n } else if (this.helpText) {\n this._a11yDescEl.textContent = this.helpText;\n } else {\n this._a11yDescEl.textContent = '';\n }\n }\n\n /** Tracks the first form control assigned to the default slot. */\n /** @internal */\n private _handleDefaultSlotChange(e: Event): void {\n const slot = e.target as HTMLSlotElement;\n const assigned = slot.assignedElements();\n this._slottedControl = assigned.find(isFormControl) ?? null;\n this._syncSlottedControl();\n }\n\n /**\n * Focuses the slotted form control when the shadow DOM label is clicked.\n * The shadow `<label>` cannot use `for`/`id` to link to a slotted input\n * across the shadow boundary, so we handle focus programmatically.\n */\n /** @internal */\n private _handleLabelClick(_e: Event): void {\n this._slottedControl?.focus();\n }\n\n /**\n * Applies ARIA attributes to the slotted form control, bridging the\n * shadow DOM accessibility boundary.\n *\n * - aria-label: associates the field label with the control\n * - aria-required: communicates required state to AT\n * - aria-invalid: communicates error state to AT\n * - aria-describedby: points to the light-DOM description span\n *\n * **Skip conditions:**\n * - `HX-*` elements manage their own ARIA attributes; bridging is skipped.\n * - Elements with `data-aria-managed` attribute opt out of ARIA mutation;\n * bridging is skipped entirely for those elements.\n */\n /** @internal */\n private _syncSlottedControl(): void {\n const control = this._slottedControl;\n if (!control) return;\n\n // hx-* elements manage their own ARIA attributes; skip bridging for them\n if (control.tagName.startsWith('HX-')) return;\n\n // Elements that declare data-aria-managed opt out of ARIA mutation\n if (control.hasAttribute('data-aria-managed')) return;\n\n const hasError = !!this.error || this._hasErrorSlot;\n const hasDesc = !!(this.error || this.helpText || this._hasErrorSlot || this._hasHelpSlot);\n\n // Label association: aria-label bridges the shadow DOM boundary\n if (this.label && !this._hasLabelSlot) {\n control.setAttribute('aria-label', this.label);\n } else {\n control.removeAttribute('aria-label');\n }\n\n // Required state\n if (this.required) {\n control.setAttribute('aria-required', 'true');\n } else {\n control.removeAttribute('aria-required');\n }\n\n // Invalid state\n if (hasError) {\n control.setAttribute('aria-invalid', 'true');\n } else {\n control.removeAttribute('aria-invalid');\n }\n\n // Description (error or help text) via light-DOM span\n if (hasDesc) {\n control.setAttribute('aria-describedby', this._a11yDescId);\n } else {\n control.removeAttribute('aria-describedby');\n }\n }\n\n // ─── Render ───\n\n override render() {\n const hasError = !!this.error || this._hasErrorSlot;\n const hasHelp = !!this.helpText || this._hasHelpSlot;\n\n const fieldClasses = {\n field: true,\n 'field--error': hasError,\n 'field--disabled': this.disabled,\n 'field--required': this.required,\n 'field--size-sm': this.size === 'sm',\n 'field--size-md': this.size === 'md',\n 'field--size-lg': this.size === 'lg',\n 'field--layout-inline': this.layout === 'inline',\n };\n\n return html`\n <div part=\"field\" class=${classMap(fieldClasses)}>\n <!-- Label -->\n <div class=\"field__label-wrapper\">\n <slot name=\"label\" @slotchange=${this._handleLabelSlotChange}>\n ${this.label && !this._hasLabelSlot\n ? html`\n <label part=\"label\" class=\"field__label\" @click=${this._handleLabelClick}>\n ${this.label}\n ${this.required\n ? html`<span\n part=\"required-indicator\"\n class=\"field__required-marker\"\n aria-hidden=\"true\"\n >*</span\n >`\n : nothing}\n </label>\n `\n : nothing}\n </slot>\n </div>\n\n <!-- Description -->\n <slot name=\"description\"></slot>\n\n <!-- Control (default slot) -->\n <div part=\"control\" class=\"field__control\">\n <slot @slotchange=${this._handleDefaultSlotChange}></slot>\n </div>\n\n <!-- Error -->\n <slot name=\"error\" @slotchange=${this._handleErrorSlotChange}>\n ${this.error\n ? html`\n <div part=\"error-message\" class=\"field__error\" id=${this._errorId} role=\"alert\">\n ${this.error}\n </div>\n `\n : nothing}\n </slot>\n\n <!-- Slotted error live region — ensures slotted error content is announced -->\n <div aria-live=\"assertive\" class=\"field__error-slot-announcer\"></div>\n\n <!-- Help text (always in DOM so slot detection works; hidden when no help or error is shown) -->\n <div\n part=\"help-text\"\n class=\"field__help-text\"\n id=${this._helpTextId}\n ?hidden=${!hasHelp || hasError}\n >\n <slot name=\"help-text\" @slotchange=${this._handleHelpSlotChange}>${this.helpText}</slot>\n </div>\n </div>\n `;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'hx-field': HelixField;\n }\n}\n"],"names":["helixFieldStyles","css","FORM_CONTROL_TAGS","_fieldCounter","isFormControl","el","HelixField","LitElement","slot","_a","changedProps","devWarn","span","assigned","_e","control","hasError","hasDesc","hasHelp","fieldClasses","html","classMap","nothing","__decorateClass","property","state","customElement"],"mappings":"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"}
@@ -1,5 +1,5 @@
1
1
  import { css as f, LitElement as d, html as a, nothing as c } from "lit";
2
- import "./document-token-adoption-Dym9ALA4.js";
2
+ import "./document-token-adoption-DuYNKd4k.js";
3
3
  import { property as h, customElement as x } from "lit/decorators.js";
4
4
  const u = f`
5
5
  :host {
@@ -73,4 +73,4 @@ o = n([
73
73
  export {
74
74
  o as H
75
75
  };
76
- //# sourceMappingURL=hx-field-label-DhVdkhCN.js.map
76
+ //# sourceMappingURL=hx-field-label-CcOK9VU3.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"hx-field-label-DhVdkhCN.js","sources":["../../src/components/hx-field-label/hx-field-label.styles.ts","../../src/components/hx-field-label/hx-field-label.ts"],"sourcesContent":["import { css } from 'lit';\n\nexport const helixFieldLabelStyles = css`\n :host {\n display: block;\n }\n\n .label {\n display: inline-flex;\n align-items: baseline;\n gap: var(--hx-space-1, 0.25rem);\n font-size: var(--hx-font-label-size, var(--hx-font-size-sm, 0.875rem));\n font-weight: var(--hx-font-label-weight, var(--hx-font-weight-medium, 500));\n color: var(--hx-field-label-color, var(--hx-color-neutral-700, #374151));\n line-height: var(--hx-font-label-line-height, var(--hx-line-height-normal, 1.5));\n font-family: var(--hx-font-label-family, var(--hx-font-family-sans, sans-serif));\n }\n\n .required-indicator {\n color: var(--hx-field-label-required-color, var(--hx-color-error-text, #b91c1c));\n font-weight: var(--hx-font-weight-bold, 700);\n }\n\n .optional-indicator {\n font-size: var(--hx-font-size-xs, 0.75rem);\n font-weight: var(--hx-font-weight-normal, 400);\n color: var(--hx-color-neutral-500, #6b7280);\n }\n\n .visually-hidden {\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: 0;\n }\n`;\n","import { LitElement, html, nothing } from 'lit';\nimport '../../utilities/document-token-adoption.js';\nimport { customElement, property } from 'lit/decorators.js';\nimport { helixFieldLabelStyles } from './hx-field-label.styles.js';\n\n/**\n * Standardized label for form fields. Used as a consistent sub-component\n * for hx-field and other form field components.\n *\n * ## Label Association\n *\n * **For inputs in light DOM (the typical consumer deployment):** Use\n * `aria-labelledby` pointing to the host element's `id`. The `for` attribute\n * renders a native `<label for=\"...\">` inside shadow DOM, but the HTML spec\n * scopes `for`/`id` lookup to the same tree — a shadow-DOM label cannot\n * associate with a light-DOM input. Example:\n *\n * ```html\n * <hx-field-label id=\"label-email\">Email</hx-field-label>\n * <input id=\"email\" aria-labelledby=\"label-email\" />\n * ```\n *\n * **For inputs in the same shadow root:** The `for` attribute works as\n * expected for direct label association.\n *\n * When `for` is unset, renders a `<span>` that can be referenced via\n * `aria-labelledby` for labeling controls across the shadow DOM boundary.\n *\n * @summary Standardized label for form fields.\n *\n * @tag hx-field-label\n *\n * @slot - Label text content.\n * @slot required-indicator - Custom required marker (defaults to \"*\").\n *\n * @csspart base - The label or span element.\n * @csspart required-indicator - The required indicator wrapper.\n * @csspart optional-indicator - The optional text indicator.\n *\n * @cssprop [--hx-field-label-color=var(--hx-color-neutral-700)] - Label text color.\n * @cssprop [--hx-field-label-required-color=var(--hx-color-danger, var(--hx-color-error-text, #b91c1c))] - Required indicator color.\n * @cssprop [--hx-font-label-size=var(--hx-font-size-sm)] - Label font size.\n * @cssprop [--hx-font-label-weight=var(--hx-font-weight-medium)] - Label font weight.\n * @cssprop [--hx-font-label-line-height=var(--hx-line-height-normal)] - Label line height.\n * @cssprop [--hx-font-label-family=var(--hx-font-family-sans)] - Label font family.\n */\n@customElement('hx-field-label')\nexport class HelixFieldLabel extends LitElement {\n static override styles = [helixFieldLabelStyles];\n\n /**\n * The ID of the associated form control. When set, renders a native\n * `<label for=\"...\">` element for direct label association.\n * @attr for\n */\n @property({ type: String })\n for = '';\n\n /**\n * Whether the associated field is required. Shows a required indicator (*).\n * @attr required\n */\n @property({ type: Boolean, reflect: true })\n required = false;\n\n /**\n * Whether the associated field is optional. Shows \"(optional)\" text.\n * @attr optional\n */\n @property({ type: Boolean, reflect: true })\n optional = false;\n\n override render() {\n const requiredIndicator = this.required\n ? html`<span part=\"required-indicator\" class=\"required-indicator\"\n ><span aria-hidden=\"true\"><slot name=\"required-indicator\">*</slot></span\n ><span class=\"visually-hidden\">required</span></span\n >`\n : nothing;\n\n const optionalIndicator = this.optional\n ? html`<span part=\"optional-indicator\" class=\"optional-indicator\">(optional)</span>`\n : nothing;\n\n const content = html`<slot></slot>${requiredIndicator}${optionalIndicator}`;\n\n if (this.for) {\n return html`<label part=\"base\" class=\"label\" for=${this.for}>${content}</label>`;\n }\n\n return html`<span part=\"base\" class=\"label\">${content}</span>`;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'hx-field-label': HelixFieldLabel;\n }\n}\n"],"names":["helixFieldLabelStyles","css","HelixFieldLabel","LitElement","requiredIndicator","html","nothing","optionalIndicator","content","__decorateClass","property","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;;;;;;AC6C9B,IAAMC,IAAN,cAA8BC,EAAW;AAAA,EAAzC,cAAA;AAAA,UAAA,GAAA,SAAA,GASL,KAAA,MAAM,IAON,KAAA,WAAW,IAOX,KAAA,WAAW;AAAA,EAAA;AAAA,EAEF,SAAS;AAChB,UAAMC,IAAoB,KAAK,WAC3BC;AAAA;AAAA;AAAA,aAIAC,GAEEC,IAAoB,KAAK,WAC3BF,kFACAC,GAEEE,IAAUH,iBAAoBD,CAAiB,GAAGG,CAAiB;AAEzE,WAAI,KAAK,MACAF,yCAA4C,KAAK,GAAG,IAAIG,CAAO,aAGjEH,oCAAuCG,CAAO;AAAA,EACvD;AACF;AA7CaN,EACK,SAAS,CAACF,CAAqB;AAQ/CS,EAAA;AAAA,EADCC,EAAS,EAAE,MAAM,OAAA,CAAQ;AAAA,GARfR,EASX,WAAA,OAAA,CAAA;AAOAO,EAAA;AAAA,EADCC,EAAS,EAAE,MAAM,SAAS,SAAS,IAAM;AAAA,GAf/BR,EAgBX,WAAA,YAAA,CAAA;AAOAO,EAAA;AAAA,EADCC,EAAS,EAAE,MAAM,SAAS,SAAS,IAAM;AAAA,GAtB/BR,EAuBX,WAAA,YAAA,CAAA;AAvBWA,IAANO,EAAA;AAAA,EADNE,EAAc,gBAAgB;AAAA,GAClBT,CAAA;"}
1
+ {"version":3,"file":"hx-field-label-CcOK9VU3.js","sources":["../../src/components/hx-field-label/hx-field-label.styles.ts","../../src/components/hx-field-label/hx-field-label.ts"],"sourcesContent":["import { css } from 'lit';\n\nexport const helixFieldLabelStyles = css`\n :host {\n display: block;\n }\n\n .label {\n display: inline-flex;\n align-items: baseline;\n gap: var(--hx-space-1, 0.25rem);\n font-size: var(--hx-font-label-size, var(--hx-font-size-sm, 0.875rem));\n font-weight: var(--hx-font-label-weight, var(--hx-font-weight-medium, 500));\n color: var(--hx-field-label-color, var(--hx-color-neutral-700, #374151));\n line-height: var(--hx-font-label-line-height, var(--hx-line-height-normal, 1.5));\n font-family: var(--hx-font-label-family, var(--hx-font-family-sans, sans-serif));\n }\n\n .required-indicator {\n color: var(--hx-field-label-required-color, var(--hx-color-error-text, #b91c1c));\n font-weight: var(--hx-font-weight-bold, 700);\n }\n\n .optional-indicator {\n font-size: var(--hx-font-size-xs, 0.75rem);\n font-weight: var(--hx-font-weight-normal, 400);\n color: var(--hx-color-neutral-500, #6b7280);\n }\n\n .visually-hidden {\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: 0;\n }\n`;\n","import { LitElement, html, nothing } from 'lit';\nimport '../../utilities/document-token-adoption.js';\nimport { customElement, property } from 'lit/decorators.js';\nimport { helixFieldLabelStyles } from './hx-field-label.styles.js';\n\n/**\n * Standardized label for form fields. Used as a consistent sub-component\n * for hx-field and other form field components.\n *\n * ## Label Association\n *\n * **For inputs in light DOM (the typical consumer deployment):** Use\n * `aria-labelledby` pointing to the host element's `id`. The `for` attribute\n * renders a native `<label for=\"...\">` inside shadow DOM, but the HTML spec\n * scopes `for`/`id` lookup to the same tree — a shadow-DOM label cannot\n * associate with a light-DOM input. Example:\n *\n * ```html\n * <hx-field-label id=\"label-email\">Email</hx-field-label>\n * <input id=\"email\" aria-labelledby=\"label-email\" />\n * ```\n *\n * **For inputs in the same shadow root:** The `for` attribute works as\n * expected for direct label association.\n *\n * When `for` is unset, renders a `<span>` that can be referenced via\n * `aria-labelledby` for labeling controls across the shadow DOM boundary.\n *\n * @summary Standardized label for form fields.\n *\n * @tag hx-field-label\n *\n * @slot - Label text content.\n * @slot required-indicator - Custom required marker (defaults to \"*\").\n *\n * @csspart base - The label or span element.\n * @csspart required-indicator - The required indicator wrapper.\n * @csspart optional-indicator - The optional text indicator.\n *\n * @cssprop [--hx-field-label-color=var(--hx-color-neutral-700)] - Label text color.\n * @cssprop [--hx-field-label-required-color=var(--hx-color-danger, var(--hx-color-error-text, #b91c1c))] - Required indicator color.\n * @cssprop [--hx-font-label-size=var(--hx-font-size-sm)] - Label font size.\n * @cssprop [--hx-font-label-weight=var(--hx-font-weight-medium)] - Label font weight.\n * @cssprop [--hx-font-label-line-height=var(--hx-line-height-normal)] - Label line height.\n * @cssprop [--hx-font-label-family=var(--hx-font-family-sans)] - Label font family.\n */\n@customElement('hx-field-label')\nexport class HelixFieldLabel extends LitElement {\n static override styles = [helixFieldLabelStyles];\n\n /**\n * The ID of the associated form control. When set, renders a native\n * `<label for=\"...\">` element for direct label association.\n * @attr for\n */\n @property({ type: String })\n for = '';\n\n /**\n * Whether the associated field is required. Shows a required indicator (*).\n * @attr required\n */\n @property({ type: Boolean, reflect: true })\n required = false;\n\n /**\n * Whether the associated field is optional. Shows \"(optional)\" text.\n * @attr optional\n */\n @property({ type: Boolean, reflect: true })\n optional = false;\n\n override render() {\n const requiredIndicator = this.required\n ? html`<span part=\"required-indicator\" class=\"required-indicator\"\n ><span aria-hidden=\"true\"><slot name=\"required-indicator\">*</slot></span\n ><span class=\"visually-hidden\">required</span></span\n >`\n : nothing;\n\n const optionalIndicator = this.optional\n ? html`<span part=\"optional-indicator\" class=\"optional-indicator\">(optional)</span>`\n : nothing;\n\n const content = html`<slot></slot>${requiredIndicator}${optionalIndicator}`;\n\n if (this.for) {\n return html`<label part=\"base\" class=\"label\" for=${this.for}>${content}</label>`;\n }\n\n return html`<span part=\"base\" class=\"label\">${content}</span>`;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'hx-field-label': HelixFieldLabel;\n }\n}\n"],"names":["helixFieldLabelStyles","css","HelixFieldLabel","LitElement","requiredIndicator","html","nothing","optionalIndicator","content","__decorateClass","property","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;;;;;;AC6C9B,IAAMC,IAAN,cAA8BC,EAAW;AAAA,EAAzC,cAAA;AAAA,UAAA,GAAA,SAAA,GASL,KAAA,MAAM,IAON,KAAA,WAAW,IAOX,KAAA,WAAW;AAAA,EAAA;AAAA,EAEF,SAAS;AAChB,UAAMC,IAAoB,KAAK,WAC3BC;AAAA;AAAA;AAAA,aAIAC,GAEEC,IAAoB,KAAK,WAC3BF,kFACAC,GAEEE,IAAUH,iBAAoBD,CAAiB,GAAGG,CAAiB;AAEzE,WAAI,KAAK,MACAF,yCAA4C,KAAK,GAAG,IAAIG,CAAO,aAGjEH,oCAAuCG,CAAO;AAAA,EACvD;AACF;AA7CaN,EACK,SAAS,CAACF,CAAqB;AAQ/CS,EAAA;AAAA,EADCC,EAAS,EAAE,MAAM,OAAA,CAAQ;AAAA,GARfR,EASX,WAAA,OAAA,CAAA;AAOAO,EAAA;AAAA,EADCC,EAAS,EAAE,MAAM,SAAS,SAAS,IAAM;AAAA,GAf/BR,EAgBX,WAAA,YAAA,CAAA;AAOAO,EAAA;AAAA,EADCC,EAAS,EAAE,MAAM,SAAS,SAAS,IAAM;AAAA,GAtB/BR,EAuBX,WAAA,YAAA,CAAA;AAvBWA,IAANO,EAAA;AAAA,EADNE,EAAc,gBAAgB;AAAA,GAClBT,CAAA;"}
@@ -1,5 +1,5 @@
1
1
  import { css as x, LitElement as g, nothing as p, html as c } from "lit";
2
- import "./document-token-adoption-Dym9ALA4.js";
2
+ import "./document-token-adoption-DuYNKd4k.js";
3
3
  import { property as a, state as b, query as _, customElement as y } from "lit/decorators.js";
4
4
  import { classMap as w } from "lit/directives/class-map.js";
5
5
  import { ifDefined as v } from "lit/directives/if-defined.js";
@@ -650,4 +650,4 @@ i = o([
650
650
  export {
651
651
  i as H
652
652
  };
653
- //# sourceMappingURL=hx-file-upload-79nMhnM_.js.map
653
+ //# sourceMappingURL=hx-file-upload-Dwtu3WcB.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"hx-file-upload-79nMhnM_.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-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-neutral-700, #343a40);\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-neutral-300, #ced4da));\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-neutral-50, #f8f9fa));\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-neutral-600, #495057);\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-neutral-0, #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, #dc3545));\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-neutral-200, #e9ecef);\n border-radius: var(--hx-border-radius-md, 0.375rem);\n background-color: var(--hx-color-neutral-0, #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-neutral-800, #212529);\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-neutral-500, #6c757d);\n }\n\n .file-item__remove {\n flex-shrink: 0;\n display: inline-flex;\n align-items: center;\n justify-content: center;\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-neutral-500, #6c757d);\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, #dc3545) 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-neutral-200, #e9ecef);\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","import { LitElement, html, nothing, type PropertyValues } from 'lit';\nimport '../../utilities/document-token-adoption.js';\nimport { customElement, property, query, state } from 'lit/decorators.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 { helixFileUploadStyles } from './hx-file-upload.styles.js';\n\n// Module-level counter for stable, SSR-safe IDs (avoids Math.random() hydration mismatch)\nlet _hxFileUploadIdCounter = 0;\n\ninterface FileEntry {\n file: File;\n progress: number;\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 */\n@customElement('hx-file-upload')\nexport class HelixFileUpload extends LitElement {\n static override styles = [helixFileUploadStyles];\n\n // ─── Form Association ───\n\n /** Marks this element as form-associated for ElementInternals support. @internal */\n static formAssociated = true;\n\n /** Holds the ElementInternals instance used for form value and validity management. @internal */\n private _internals: ElementInternals;\n\n constructor() {\n super();\n /** @internal */\n this._internals = this.attachInternals();\n }\n\n // ─── Properties ───\n\n /**\n * The form field name used during form submission.\n * @attr name\n */\n @property({ type: String })\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 * 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 = `hx-file-upload-${++_hxFileUploadIdCounter}`;\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 }\n\n // ─── Form Integration ───\n\n /** Returns the associated form element, if any. */\n get form(): HTMLFormElement | null {\n return this._internals.form;\n }\n\n /** Returns the validation message. */\n get validationMessage(): string {\n return this._internals.validationMessage;\n }\n\n /** Returns the ValidityState object. */\n get validity(): ValidityState {\n return this._internals.validity;\n }\n\n /** Checks whether the component satisfies its constraints. */\n checkValidity(): boolean {\n return this._internals.checkValidity();\n }\n\n /** Reports validity and shows the browser's constraint validation UI. */\n reportValidity(): boolean {\n return this._internals.reportValidity();\n }\n\n /** @internal */\n formResetCallback(): void {\n this._files = [];\n this._internals.setFormValue(null);\n }\n\n /** @internal */\n formDisabledCallback(disabled: boolean): void {\n this.disabled = disabled;\n }\n\n /** @internal */\n formStateRestoreCallback(_state: string | File | FormData, mode: string): 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.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\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.label ? dropzoneLabel : undefined)}\n aria-labelledby=${ifDefined(this.label ? this._labelId : undefined)}\n aria-disabled=${this.disabled ? '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","_hxFileUploadIdCounter","HelixFileUpload","LitElement","name","progress","slot","changedProperties","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","_a","dt","input","removedFile","_","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;AAAA;A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"}
1
+ {"version":3,"file":"hx-file-upload-Dwtu3WcB.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-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-neutral-700, #343a40);\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-neutral-300, #ced4da));\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-neutral-50, #f8f9fa));\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-neutral-600, #495057);\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-neutral-0, #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, #dc3545));\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-neutral-200, #e9ecef);\n border-radius: var(--hx-border-radius-md, 0.375rem);\n background-color: var(--hx-color-neutral-0, #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-neutral-800, #212529);\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-neutral-500, #6c757d);\n }\n\n .file-item__remove {\n flex-shrink: 0;\n display: inline-flex;\n align-items: center;\n justify-content: center;\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-neutral-500, #6c757d);\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, #dc3545) 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-neutral-200, #e9ecef);\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","import { LitElement, html, nothing, type PropertyValues } from 'lit';\nimport '../../utilities/document-token-adoption.js';\nimport { customElement, property, query, state } from 'lit/decorators.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 { helixFileUploadStyles } from './hx-file-upload.styles.js';\n\n// Module-level counter for stable, SSR-safe IDs (avoids Math.random() hydration mismatch)\nlet _hxFileUploadIdCounter = 0;\n\ninterface FileEntry {\n file: File;\n progress: number;\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 */\n@customElement('hx-file-upload')\nexport class HelixFileUpload extends LitElement {\n static override styles = [helixFileUploadStyles];\n\n // ─── Form Association ───\n\n /** Marks this element as form-associated for ElementInternals support. @internal */\n static formAssociated = true;\n\n /** Holds the ElementInternals instance used for form value and validity management. @internal */\n private _internals: ElementInternals;\n\n constructor() {\n super();\n /** @internal */\n this._internals = this.attachInternals();\n }\n\n // ─── Properties ───\n\n /**\n * The form field name used during form submission.\n * @attr name\n */\n @property({ type: String })\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 * 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 = `hx-file-upload-${++_hxFileUploadIdCounter}`;\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 }\n\n // ─── Form Integration ───\n\n /** Returns the associated form element, if any. */\n get form(): HTMLFormElement | null {\n return this._internals.form;\n }\n\n /** Returns the validation message. */\n get validationMessage(): string {\n return this._internals.validationMessage;\n }\n\n /** Returns the ValidityState object. */\n get validity(): ValidityState {\n return this._internals.validity;\n }\n\n /** Checks whether the component satisfies its constraints. */\n checkValidity(): boolean {\n return this._internals.checkValidity();\n }\n\n /** Reports validity and shows the browser's constraint validation UI. */\n reportValidity(): boolean {\n return this._internals.reportValidity();\n }\n\n /** @internal */\n formResetCallback(): void {\n this._files = [];\n this._internals.setFormValue(null);\n }\n\n /** @internal */\n formDisabledCallback(disabled: boolean): void {\n this.disabled = disabled;\n }\n\n /** @internal */\n formStateRestoreCallback(_state: string | File | FormData, mode: string): 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.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\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.label ? dropzoneLabel : undefined)}\n aria-labelledby=${ifDefined(this.label ? this._labelId : undefined)}\n aria-disabled=${this.disabled ? '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","_hxFileUploadIdCounter","HelixFileUpload","LitElement","name","progress","slot","changedProperties","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","_a","dt","input","removedFile","_","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;AAAA;A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"}
@@ -1,5 +1,5 @@
1
1
  import { css as _, LitElement as D, html as M } from "lit";
2
- import "./document-token-adoption-Dym9ALA4.js";
2
+ import "./document-token-adoption-DuYNKd4k.js";
3
3
  import { property as h, customElement as w } from "lit/decorators.js";
4
4
  const N = _`
5
5
  :host {
@@ -177,4 +177,4 @@ r = n([
177
177
  export {
178
178
  r as H
179
179
  };
180
- //# sourceMappingURL=hx-format-date-BMukpO2t.js.map
180
+ //# sourceMappingURL=hx-format-date-B7L9odbA.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"hx-format-date-BMukpO2t.js","sources":["../../src/components/hx-format-date/hx-format-date.styles.ts","../../src/components/hx-format-date/hx-format-date.ts"],"sourcesContent":["import { css } from 'lit';\n\nexport const helixFormatDateStyles = css`\n :host {\n display: inline;\n }\n\n [part='base'] {\n display: inline;\n font: inherit;\n color: inherit;\n }\n`;\n","import { LitElement, html } from 'lit';\nimport '../../utilities/document-token-adoption.js';\nimport { customElement, property } from 'lit/decorators.js';\nimport { helixFormatDateStyles } from './hx-format-date.styles.js';\n\n/**\n * Formats and displays a date/time value using the browser's `Intl.DateTimeFormat`\n * (or `Intl.RelativeTimeFormat` when `relative` is set). Renders as an inline\n * `<time>` element — machine-readable via `datetime`, human-readable via formatted text.\n *\n * No external dependencies. Uses native Intl APIs only.\n *\n * @summary Inline date/time formatter using Intl APIs with semantic `<time>` output.\n *\n * @tag hx-format-date\n *\n * @csspart base - The inner `<time>` element.\n */\n@customElement('hx-format-date')\nexport class HelixFormatDate extends LitElement {\n static override styles = [helixFormatDateStyles];\n\n // ─── Intl formatter caches (keyed by locale+options fingerprint) ───\n /** @internal */\n private static _dtfCache = new Map<string, Intl.DateTimeFormat>();\n /** @internal */\n private static _rtfCache = new Map<string, Intl.RelativeTimeFormat>();\n\n /**\n * The date/time value to format. Accepts an ISO string, a Unix timestamp (ms), or\n * a `Date` object. Defaults to the current date/time when empty.\n * @attr date\n */\n @property()\n date: string | number | Date = '';\n\n /**\n * BCP 47 locale tag used for formatting (e.g. `\"en-US\"`, `\"de\"`, `\"ja\"`).\n * Defaults to `document.documentElement.lang`, then `navigator.language`.\n * @attr lang\n */\n @property()\n override lang = '';\n\n /**\n * Month display format.\n * @attr month\n */\n @property()\n month: 'narrow' | 'short' | 'long' | 'numeric' | '2-digit' | undefined = undefined;\n\n /**\n * Year display format.\n * @attr year\n */\n @property()\n year: 'numeric' | '2-digit' | undefined = undefined;\n\n /**\n * Day display format.\n * @attr day\n */\n @property()\n day: 'numeric' | '2-digit' | undefined = undefined;\n\n /**\n * Weekday display format.\n * @attr weekday\n */\n @property()\n weekday: 'narrow' | 'short' | 'long' | undefined = undefined;\n\n /**\n * Hour display format.\n * @attr hour\n */\n @property()\n hour: 'numeric' | '2-digit' | undefined = undefined;\n\n /**\n * Minute display format.\n * @attr minute\n */\n @property()\n minute: 'numeric' | '2-digit' | undefined = undefined;\n\n /**\n * Second display format.\n * @attr second\n */\n @property()\n second: 'numeric' | '2-digit' | undefined = undefined;\n\n /**\n * Time zone name display format. Accepts all values supported by\n * `Intl.DateTimeFormatOptions.timeZoneName` including `'short'`, `'long'`,\n * `'shortOffset'`, `'longOffset'`, `'shortGeneric'`, and `'longGeneric'`.\n * @attr time-zone-name\n */\n @property({ attribute: 'time-zone-name' })\n timeZoneName: Intl.DateTimeFormatOptions['timeZoneName'] = undefined;\n\n /**\n * IANA time zone identifier (e.g. `\"America/New_York\"`, `\"UTC\"`).\n * @attr time-zone\n */\n @property({ attribute: 'time-zone' })\n timeZone: string | undefined = undefined;\n\n /**\n * Whether to use 12-hour or 24-hour clock. `\"auto\"` defers to locale default.\n * @attr hour-format\n */\n @property({ attribute: 'hour-format' })\n hourFormat: 'auto' | '12' | '24' = 'auto';\n\n /**\n * Controls whether `Intl.RelativeTimeFormat` always shows numeric output\n * (`\"always\"`) or uses natural language when possible (`\"auto\"`, e.g. \"yesterday\").\n * Only used when `relative` is true.\n * @attr numeric\n */\n @property()\n numeric: 'always' | 'auto' = 'auto';\n\n /**\n * When true, displays a relative time string such as \"2 hours ago\" or \"in 3 days\"\n * using `Intl.RelativeTimeFormat`.\n *\n * **Important:** The relative time string is computed once at render time and does\n * not auto-update. If the displayed text must stay current (e.g. a live \"X minutes\n * ago\" counter), the consuming component must re-set the `date` property on its own\n * interval to trigger a re-render.\n * @attr relative\n */\n @property({ type: Boolean })\n relative = false;\n\n // ─── Private helpers ───\n\n /** @internal */\n private _getDate(): Date {\n const val = this.date;\n if (val === '') return new Date();\n if (val instanceof Date) {\n return isNaN(val.getTime()) ? new Date() : val;\n }\n if (typeof val === 'number') {\n const d = new Date(val);\n return isNaN(d.getTime()) ? new Date() : d;\n }\n // Numeric strings (e.g. Unix timestamps set via HTML attribute) must be\n // converted to a number before passing to Date — new Date(\"1718462400000\")\n // returns Invalid Date in most JS engines.\n const asNumber = Number(val);\n if (!isNaN(asNumber)) {\n const d = new Date(asNumber);\n return isNaN(d.getTime()) ? new Date() : d;\n }\n const parsed = new Date(val);\n return isNaN(parsed.getTime()) ? new Date() : parsed;\n }\n\n /** @internal */\n private _getLocale(): string {\n if (this.lang) return this.lang;\n const docLang = typeof document !== 'undefined' ? document.documentElement.lang : '';\n const navLang = typeof navigator !== 'undefined' ? navigator.language : '';\n return docLang || navLang || 'en';\n }\n\n /** @internal */\n private _getHour12(): boolean | undefined {\n if (this.hourFormat === '12') return true;\n if (this.hourFormat === '24') return false;\n return undefined;\n }\n\n /**\n * Returns the `datetime` attribute value. When `timeZone` is set, returns a\n * timezone-offset ISO string (e.g. `2024-09-20T05:00:00-04:00`) so that\n * assistive technology reads the same local time as the visual display.\n */\n /** @internal */\n private _getDatetimeAttr(date: Date): string {\n if (!this.timeZone) return date.toISOString();\n try {\n const fmtOpts: Intl.DateTimeFormatOptions = {\n timeZone: this.timeZone,\n year: 'numeric',\n month: '2-digit',\n day: '2-digit',\n hour: '2-digit',\n minute: '2-digit',\n second: '2-digit',\n hour12: false,\n };\n const reduceParts = (parts: Intl.DateTimeFormatPart[]) =>\n parts.reduce<Record<string, string>>((acc, p) => {\n if (p.type !== 'literal') acc[p.type] = p.value;\n return acc;\n }, {});\n\n const tzParts = reduceParts(new Intl.DateTimeFormat('en-CA', fmtOpts).formatToParts(date));\n const utcParts = reduceParts(\n new Intl.DateTimeFormat('en-CA', { ...fmtOpts, timeZone: 'UTC' }).formatToParts(date),\n );\n\n const toMs = (p: Record<string, string>) =>\n Date.UTC(\n parseInt(p['year'] ?? '0'),\n parseInt(p['month'] ?? '1') - 1,\n parseInt(p['day'] ?? '1'),\n parseInt(p['hour'] === '24' ? '0' : (p['hour'] ?? '0')),\n parseInt(p['minute'] ?? '0'),\n parseInt(p['second'] ?? '0'),\n );\n\n const offsetMin = Math.round((toMs(tzParts) - toMs(utcParts)) / 60000);\n const sign = offsetMin >= 0 ? '+' : '-';\n const absMin = Math.abs(offsetMin);\n const hh = String(Math.floor(absMin / 60)).padStart(2, '0');\n const mm = String(absMin % 60).padStart(2, '0');\n const h = tzParts['hour'] === '24' ? '00' : (tzParts['hour'] ?? '00');\n return `${tzParts['year']}-${tzParts['month']}-${tzParts['day']}T${h}:${tzParts['minute']}:${tzParts['second']}${sign}${hh}:${mm}`;\n } catch {\n return date.toISOString();\n }\n }\n\n /** @internal */\n private _formatRelative(date: Date): string {\n const now = new Date();\n const diffMs = date.getTime() - now.getTime();\n const diffSec = Math.round(diffMs / 1000);\n const absSec = Math.abs(diffSec);\n const diffMin = Math.round(diffSec / 60);\n const absMin = Math.abs(diffMin);\n const diffHour = Math.round(diffSec / 3600);\n const absHour = Math.abs(diffHour);\n const diffDay = Math.round(diffSec / 86400);\n const absDay = Math.abs(diffDay);\n const diffMonth = Math.round(diffDay / 30);\n const absMonth = Math.abs(diffMonth);\n const diffYear = Math.round(diffDay / 365);\n\n const locale = this._getLocale();\n const cacheKey = `${locale}|${this.numeric}`;\n let rtf = HelixFormatDate._rtfCache.get(cacheKey);\n if (!rtf) {\n try {\n rtf = new Intl.RelativeTimeFormat(locale, { numeric: this.numeric });\n HelixFormatDate._rtfCache.set(cacheKey, rtf);\n } catch {\n return '';\n }\n }\n\n try {\n if (absSec < 60) return rtf.format(diffSec, 'second');\n if (absMin < 60) return rtf.format(diffMin, 'minute');\n if (absHour < 24) return rtf.format(diffHour, 'hour');\n if (absDay < 30) return rtf.format(diffDay, 'day');\n if (absMonth < 12) return rtf.format(diffMonth, 'month');\n return rtf.format(diffYear, 'year');\n } catch {\n return '';\n }\n }\n\n /** @internal */\n private _formatAbsolute(date: Date): string {\n const options: Intl.DateTimeFormatOptions = {};\n\n if (this.month !== undefined) options.month = this.month;\n if (this.year !== undefined) options.year = this.year;\n if (this.day !== undefined) options.day = this.day;\n if (this.weekday !== undefined) options.weekday = this.weekday;\n if (this.hour !== undefined) options.hour = this.hour;\n if (this.minute !== undefined) options.minute = this.minute;\n if (this.second !== undefined) options.second = this.second;\n if (this.timeZoneName !== undefined) options.timeZoneName = this.timeZoneName;\n if (this.timeZone !== undefined) options.timeZone = this.timeZone;\n\n const hour12 = this._getHour12();\n if (hour12 !== undefined) options.hour12 = hour12;\n\n // Fall back to a sensible default when no format options are specified\n if (Object.keys(options).length === 0) {\n options.year = 'numeric';\n options.month = 'long';\n options.day = 'numeric';\n }\n\n const locale = this._getLocale();\n const cacheKey = `${locale}|${JSON.stringify(options)}`;\n let dtf = HelixFormatDate._dtfCache.get(cacheKey);\n if (!dtf) {\n try {\n dtf = new Intl.DateTimeFormat(locale, options);\n HelixFormatDate._dtfCache.set(cacheKey, dtf);\n } catch {\n // Invalid options (e.g. unknown timeZone) — return empty string\n return '';\n }\n }\n\n try {\n return dtf.format(date);\n } catch {\n return '';\n }\n }\n\n // ─── Render ───\n\n override render() {\n const date = this._getDate();\n const datetimeAttr = this._getDatetimeAttr(date);\n const formattedText = this.relative ? this._formatRelative(date) : this._formatAbsolute(date);\n\n return html`<time part=\"base\" datetime=${datetimeAttr}>${formattedText}</time>`;\n }\n}\n\nexport type HxFormatDate = HelixFormatDate;\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'hx-format-date': HelixFormatDate;\n }\n}\n"],"names":["helixFormatDateStyles","css","HelixFormatDate","LitElement","val","d","asNumber","parsed","docLang","navLang","date","fmtOpts","reduceParts","parts","acc","p","tzParts","utcParts","toMs","offsetMin","sign","absMin","hh","mm","h","now","diffMs","diffSec","absSec","diffMin","diffHour","absHour","diffDay","absDay","diffMonth","absMonth","diffYear","locale","cacheKey","rtf","options","hour12","dtf","datetimeAttr","formattedText","html","__decorateClass","property","customElement"],"mappings":"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"}
1
+ {"version":3,"file":"hx-format-date-B7L9odbA.js","sources":["../../src/components/hx-format-date/hx-format-date.styles.ts","../../src/components/hx-format-date/hx-format-date.ts"],"sourcesContent":["import { css } from 'lit';\n\nexport const helixFormatDateStyles = css`\n :host {\n display: inline;\n }\n\n [part='base'] {\n display: inline;\n font: inherit;\n color: inherit;\n }\n`;\n","import { LitElement, html } from 'lit';\nimport '../../utilities/document-token-adoption.js';\nimport { customElement, property } from 'lit/decorators.js';\nimport { helixFormatDateStyles } from './hx-format-date.styles.js';\n\n/**\n * Formats and displays a date/time value using the browser's `Intl.DateTimeFormat`\n * (or `Intl.RelativeTimeFormat` when `relative` is set). Renders as an inline\n * `<time>` element — machine-readable via `datetime`, human-readable via formatted text.\n *\n * No external dependencies. Uses native Intl APIs only.\n *\n * @summary Inline date/time formatter using Intl APIs with semantic `<time>` output.\n *\n * @tag hx-format-date\n *\n * @csspart base - The inner `<time>` element.\n */\n@customElement('hx-format-date')\nexport class HelixFormatDate extends LitElement {\n static override styles = [helixFormatDateStyles];\n\n // ─── Intl formatter caches (keyed by locale+options fingerprint) ───\n /** @internal */\n private static _dtfCache = new Map<string, Intl.DateTimeFormat>();\n /** @internal */\n private static _rtfCache = new Map<string, Intl.RelativeTimeFormat>();\n\n /**\n * The date/time value to format. Accepts an ISO string, a Unix timestamp (ms), or\n * a `Date` object. Defaults to the current date/time when empty.\n * @attr date\n */\n @property()\n date: string | number | Date = '';\n\n /**\n * BCP 47 locale tag used for formatting (e.g. `\"en-US\"`, `\"de\"`, `\"ja\"`).\n * Defaults to `document.documentElement.lang`, then `navigator.language`.\n * @attr lang\n */\n @property()\n override lang = '';\n\n /**\n * Month display format.\n * @attr month\n */\n @property()\n month: 'narrow' | 'short' | 'long' | 'numeric' | '2-digit' | undefined = undefined;\n\n /**\n * Year display format.\n * @attr year\n */\n @property()\n year: 'numeric' | '2-digit' | undefined = undefined;\n\n /**\n * Day display format.\n * @attr day\n */\n @property()\n day: 'numeric' | '2-digit' | undefined = undefined;\n\n /**\n * Weekday display format.\n * @attr weekday\n */\n @property()\n weekday: 'narrow' | 'short' | 'long' | undefined = undefined;\n\n /**\n * Hour display format.\n * @attr hour\n */\n @property()\n hour: 'numeric' | '2-digit' | undefined = undefined;\n\n /**\n * Minute display format.\n * @attr minute\n */\n @property()\n minute: 'numeric' | '2-digit' | undefined = undefined;\n\n /**\n * Second display format.\n * @attr second\n */\n @property()\n second: 'numeric' | '2-digit' | undefined = undefined;\n\n /**\n * Time zone name display format. Accepts all values supported by\n * `Intl.DateTimeFormatOptions.timeZoneName` including `'short'`, `'long'`,\n * `'shortOffset'`, `'longOffset'`, `'shortGeneric'`, and `'longGeneric'`.\n * @attr time-zone-name\n */\n @property({ attribute: 'time-zone-name' })\n timeZoneName: Intl.DateTimeFormatOptions['timeZoneName'] = undefined;\n\n /**\n * IANA time zone identifier (e.g. `\"America/New_York\"`, `\"UTC\"`).\n * @attr time-zone\n */\n @property({ attribute: 'time-zone' })\n timeZone: string | undefined = undefined;\n\n /**\n * Whether to use 12-hour or 24-hour clock. `\"auto\"` defers to locale default.\n * @attr hour-format\n */\n @property({ attribute: 'hour-format' })\n hourFormat: 'auto' | '12' | '24' = 'auto';\n\n /**\n * Controls whether `Intl.RelativeTimeFormat` always shows numeric output\n * (`\"always\"`) or uses natural language when possible (`\"auto\"`, e.g. \"yesterday\").\n * Only used when `relative` is true.\n * @attr numeric\n */\n @property()\n numeric: 'always' | 'auto' = 'auto';\n\n /**\n * When true, displays a relative time string such as \"2 hours ago\" or \"in 3 days\"\n * using `Intl.RelativeTimeFormat`.\n *\n * **Important:** The relative time string is computed once at render time and does\n * not auto-update. If the displayed text must stay current (e.g. a live \"X minutes\n * ago\" counter), the consuming component must re-set the `date` property on its own\n * interval to trigger a re-render.\n * @attr relative\n */\n @property({ type: Boolean })\n relative = false;\n\n // ─── Private helpers ───\n\n /** @internal */\n private _getDate(): Date {\n const val = this.date;\n if (val === '') return new Date();\n if (val instanceof Date) {\n return isNaN(val.getTime()) ? new Date() : val;\n }\n if (typeof val === 'number') {\n const d = new Date(val);\n return isNaN(d.getTime()) ? new Date() : d;\n }\n // Numeric strings (e.g. Unix timestamps set via HTML attribute) must be\n // converted to a number before passing to Date — new Date(\"1718462400000\")\n // returns Invalid Date in most JS engines.\n const asNumber = Number(val);\n if (!isNaN(asNumber)) {\n const d = new Date(asNumber);\n return isNaN(d.getTime()) ? new Date() : d;\n }\n const parsed = new Date(val);\n return isNaN(parsed.getTime()) ? new Date() : parsed;\n }\n\n /** @internal */\n private _getLocale(): string {\n if (this.lang) return this.lang;\n const docLang = typeof document !== 'undefined' ? document.documentElement.lang : '';\n const navLang = typeof navigator !== 'undefined' ? navigator.language : '';\n return docLang || navLang || 'en';\n }\n\n /** @internal */\n private _getHour12(): boolean | undefined {\n if (this.hourFormat === '12') return true;\n if (this.hourFormat === '24') return false;\n return undefined;\n }\n\n /**\n * Returns the `datetime` attribute value. When `timeZone` is set, returns a\n * timezone-offset ISO string (e.g. `2024-09-20T05:00:00-04:00`) so that\n * assistive technology reads the same local time as the visual display.\n */\n /** @internal */\n private _getDatetimeAttr(date: Date): string {\n if (!this.timeZone) return date.toISOString();\n try {\n const fmtOpts: Intl.DateTimeFormatOptions = {\n timeZone: this.timeZone,\n year: 'numeric',\n month: '2-digit',\n day: '2-digit',\n hour: '2-digit',\n minute: '2-digit',\n second: '2-digit',\n hour12: false,\n };\n const reduceParts = (parts: Intl.DateTimeFormatPart[]) =>\n parts.reduce<Record<string, string>>((acc, p) => {\n if (p.type !== 'literal') acc[p.type] = p.value;\n return acc;\n }, {});\n\n const tzParts = reduceParts(new Intl.DateTimeFormat('en-CA', fmtOpts).formatToParts(date));\n const utcParts = reduceParts(\n new Intl.DateTimeFormat('en-CA', { ...fmtOpts, timeZone: 'UTC' }).formatToParts(date),\n );\n\n const toMs = (p: Record<string, string>) =>\n Date.UTC(\n parseInt(p['year'] ?? '0'),\n parseInt(p['month'] ?? '1') - 1,\n parseInt(p['day'] ?? '1'),\n parseInt(p['hour'] === '24' ? '0' : (p['hour'] ?? '0')),\n parseInt(p['minute'] ?? '0'),\n parseInt(p['second'] ?? '0'),\n );\n\n const offsetMin = Math.round((toMs(tzParts) - toMs(utcParts)) / 60000);\n const sign = offsetMin >= 0 ? '+' : '-';\n const absMin = Math.abs(offsetMin);\n const hh = String(Math.floor(absMin / 60)).padStart(2, '0');\n const mm = String(absMin % 60).padStart(2, '0');\n const h = tzParts['hour'] === '24' ? '00' : (tzParts['hour'] ?? '00');\n return `${tzParts['year']}-${tzParts['month']}-${tzParts['day']}T${h}:${tzParts['minute']}:${tzParts['second']}${sign}${hh}:${mm}`;\n } catch {\n return date.toISOString();\n }\n }\n\n /** @internal */\n private _formatRelative(date: Date): string {\n const now = new Date();\n const diffMs = date.getTime() - now.getTime();\n const diffSec = Math.round(diffMs / 1000);\n const absSec = Math.abs(diffSec);\n const diffMin = Math.round(diffSec / 60);\n const absMin = Math.abs(diffMin);\n const diffHour = Math.round(diffSec / 3600);\n const absHour = Math.abs(diffHour);\n const diffDay = Math.round(diffSec / 86400);\n const absDay = Math.abs(diffDay);\n const diffMonth = Math.round(diffDay / 30);\n const absMonth = Math.abs(diffMonth);\n const diffYear = Math.round(diffDay / 365);\n\n const locale = this._getLocale();\n const cacheKey = `${locale}|${this.numeric}`;\n let rtf = HelixFormatDate._rtfCache.get(cacheKey);\n if (!rtf) {\n try {\n rtf = new Intl.RelativeTimeFormat(locale, { numeric: this.numeric });\n HelixFormatDate._rtfCache.set(cacheKey, rtf);\n } catch {\n return '';\n }\n }\n\n try {\n if (absSec < 60) return rtf.format(diffSec, 'second');\n if (absMin < 60) return rtf.format(diffMin, 'minute');\n if (absHour < 24) return rtf.format(diffHour, 'hour');\n if (absDay < 30) return rtf.format(diffDay, 'day');\n if (absMonth < 12) return rtf.format(diffMonth, 'month');\n return rtf.format(diffYear, 'year');\n } catch {\n return '';\n }\n }\n\n /** @internal */\n private _formatAbsolute(date: Date): string {\n const options: Intl.DateTimeFormatOptions = {};\n\n if (this.month !== undefined) options.month = this.month;\n if (this.year !== undefined) options.year = this.year;\n if (this.day !== undefined) options.day = this.day;\n if (this.weekday !== undefined) options.weekday = this.weekday;\n if (this.hour !== undefined) options.hour = this.hour;\n if (this.minute !== undefined) options.minute = this.minute;\n if (this.second !== undefined) options.second = this.second;\n if (this.timeZoneName !== undefined) options.timeZoneName = this.timeZoneName;\n if (this.timeZone !== undefined) options.timeZone = this.timeZone;\n\n const hour12 = this._getHour12();\n if (hour12 !== undefined) options.hour12 = hour12;\n\n // Fall back to a sensible default when no format options are specified\n if (Object.keys(options).length === 0) {\n options.year = 'numeric';\n options.month = 'long';\n options.day = 'numeric';\n }\n\n const locale = this._getLocale();\n const cacheKey = `${locale}|${JSON.stringify(options)}`;\n let dtf = HelixFormatDate._dtfCache.get(cacheKey);\n if (!dtf) {\n try {\n dtf = new Intl.DateTimeFormat(locale, options);\n HelixFormatDate._dtfCache.set(cacheKey, dtf);\n } catch {\n // Invalid options (e.g. unknown timeZone) — return empty string\n return '';\n }\n }\n\n try {\n return dtf.format(date);\n } catch {\n return '';\n }\n }\n\n // ─── Render ───\n\n override render() {\n const date = this._getDate();\n const datetimeAttr = this._getDatetimeAttr(date);\n const formattedText = this.relative ? this._formatRelative(date) : this._formatAbsolute(date);\n\n return html`<time part=\"base\" datetime=${datetimeAttr}>${formattedText}</time>`;\n }\n}\n\nexport type HxFormatDate = HelixFormatDate;\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'hx-format-date': HelixFormatDate;\n }\n}\n"],"names":["helixFormatDateStyles","css","HelixFormatDate","LitElement","val","d","asNumber","parsed","docLang","navLang","date","fmtOpts","reduceParts","parts","acc","p","tzParts","utcParts","toMs","offsetMin","sign","absMin","hh","mm","h","now","diffMs","diffSec","absSec","diffMin","diffHour","absHour","diffDay","absDay","diffMonth","absMonth","diffYear","locale","cacheKey","rtf","options","hour12","dtf","datetimeAttr","formattedText","html","__decorateClass","property","customElement"],"mappings":"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"}
@@ -1,5 +1,5 @@
1
1
  import { css as m, LitElement as c, html as d } from "lit";
2
- import "./document-token-adoption-Dym9ALA4.js";
2
+ import "./document-token-adoption-DuYNKd4k.js";
3
3
  import { property as s, customElement as g } from "lit/decorators.js";
4
4
  import { styleMap as y } from "lit/directives/style-map.js";
5
5
  const f = m`
@@ -122,4 +122,4 @@ export {
122
122
  r as H,
123
123
  i as a
124
124
  };
125
- //# sourceMappingURL=hx-grid-CO6JZ6Kn.js.map
125
+ //# sourceMappingURL=hx-grid-BIAR5h9m.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"hx-grid-CO6JZ6Kn.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","import { LitElement, 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 { 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 LitElement {\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 LitElement {\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","LitElement","cols","size","html","styleMap","__decorateClass","property","customElement","HelixGridItem","changed"],"mappings":"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"}
1
+ {"version":3,"file":"hx-grid-BIAR5h9m.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","import { LitElement, 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 { 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 LitElement {\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 LitElement {\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","LitElement","cols","size","html","styleMap","__decorateClass","property","customElement","HelixGridItem","changed"],"mappings":"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"}
@@ -1,5 +1,5 @@
1
1
  import { css as p, LitElement as v, nothing as c, html as n } from "lit";
2
- import "./document-token-adoption-Dym9ALA4.js";
2
+ import "./document-token-adoption-DuYNKd4k.js";
3
3
  import { property as f, customElement as u } from "lit/decorators.js";
4
4
  import { classMap as d } from "lit/directives/class-map.js";
5
5
  import { ifDefined as h } from "lit/directives/if-defined.js";
@@ -132,4 +132,4 @@ i = x([
132
132
  export {
133
133
  i as H
134
134
  };
135
- //# sourceMappingURL=hx-help-text-CYGvBLET.js.map
135
+ //# sourceMappingURL=hx-help-text-Bmb80bP4.js.map