@helixui/library 3.3.1 → 3.4.0

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 (321) hide show
  1. package/custom-elements.json +340 -71
  2. package/dist/components/hx-accordion/hx-accordion-item.d.ts +35 -0
  3. package/dist/components/hx-accordion/hx-accordion-item.d.ts.map +1 -1
  4. package/dist/components/hx-alert/hx-alert.d.ts +11 -0
  5. package/dist/components/hx-alert/hx-alert.d.ts.map +1 -1
  6. package/dist/components/hx-alert/hx-alert.styles.d.ts.map +1 -1
  7. package/dist/components/hx-alert/index.js +1 -1
  8. package/dist/components/hx-badge/hx-badge.styles.d.ts.map +1 -1
  9. package/dist/components/hx-badge/index.js +1 -1
  10. package/dist/components/hx-banner/hx-banner.d.ts +9 -1
  11. package/dist/components/hx-banner/hx-banner.d.ts.map +1 -1
  12. package/dist/components/hx-banner/index.js +1 -1
  13. package/dist/components/hx-button/hx-button.d.ts +11 -1
  14. package/dist/components/hx-button/hx-button.d.ts.map +1 -1
  15. package/dist/components/hx-button/index.js +1 -1
  16. package/dist/components/hx-button-group/hx-button-group.d.ts +13 -0
  17. package/dist/components/hx-button-group/hx-button-group.d.ts.map +1 -1
  18. package/dist/components/hx-button-group/index.js +1 -1
  19. package/dist/components/hx-checkbox/hx-checkbox.d.ts +153 -1
  20. package/dist/components/hx-checkbox/hx-checkbox.d.ts.map +1 -1
  21. package/dist/components/hx-checkbox/hx-checkbox.styles.d.ts.map +1 -1
  22. package/dist/components/hx-checkbox/index.js +1 -1
  23. package/dist/components/hx-checkbox-group/hx-checkbox-group.d.ts +151 -2
  24. package/dist/components/hx-checkbox-group/hx-checkbox-group.d.ts.map +1 -1
  25. package/dist/components/hx-checkbox-group/index.js +1 -1
  26. package/dist/components/hx-color-picker/hx-color-picker.d.ts +163 -1
  27. package/dist/components/hx-color-picker/hx-color-picker.d.ts.map +1 -1
  28. package/dist/components/hx-color-picker/hx-color-picker.styles.d.ts.map +1 -1
  29. package/dist/components/hx-color-picker/index.js +1 -1
  30. package/dist/components/hx-combobox/hx-combobox.d.ts +311 -2
  31. package/dist/components/hx-combobox/hx-combobox.d.ts.map +1 -1
  32. package/dist/components/hx-combobox/index.js +1 -1
  33. package/dist/components/hx-data-table/hx-data-table.d.ts.map +1 -1
  34. package/dist/components/hx-data-table/index.js +1 -1
  35. package/dist/components/hx-date-picker/hx-date-picker.d.ts +182 -56
  36. package/dist/components/hx-date-picker/hx-date-picker.d.ts.map +1 -1
  37. package/dist/components/hx-date-picker/hx-date-picker.styles.d.ts.map +1 -1
  38. package/dist/components/hx-date-picker/index.js +1 -1
  39. package/dist/components/hx-dialog/hx-dialog.d.ts +240 -0
  40. package/dist/components/hx-dialog/hx-dialog.d.ts.map +1 -1
  41. package/dist/components/hx-dialog/index.js +1 -1
  42. package/dist/components/hx-drawer/hx-drawer.d.ts +201 -0
  43. package/dist/components/hx-drawer/hx-drawer.d.ts.map +1 -1
  44. package/dist/components/hx-drawer/hx-drawer.styles.d.ts.map +1 -1
  45. package/dist/components/hx-drawer/index.js +1 -1
  46. package/dist/components/hx-dropdown/hx-dropdown.d.ts +168 -0
  47. package/dist/components/hx-dropdown/hx-dropdown.d.ts.map +1 -1
  48. package/dist/components/hx-dropdown/index.js +1 -1
  49. package/dist/components/hx-field/hx-field.d.ts +109 -0
  50. package/dist/components/hx-field/hx-field.d.ts.map +1 -1
  51. package/dist/components/hx-field/index.js +1 -1
  52. package/dist/components/hx-icon-button/hx-icon-button.d.ts +16 -3
  53. package/dist/components/hx-icon-button/hx-icon-button.d.ts.map +1 -1
  54. package/dist/components/hx-icon-button/hx-icon-button.styles.d.ts.map +1 -1
  55. package/dist/components/hx-icon-button/index.js +1 -1
  56. package/dist/components/hx-link/hx-link.d.ts +10 -1
  57. package/dist/components/hx-link/hx-link.d.ts.map +1 -1
  58. package/dist/components/hx-link/index.js +1 -1
  59. package/dist/components/hx-list/hx-list-item.d.ts +27 -1
  60. package/dist/components/hx-list/hx-list-item.d.ts.map +1 -1
  61. package/dist/components/hx-list/hx-list.d.ts +28 -0
  62. package/dist/components/hx-list/hx-list.d.ts.map +1 -1
  63. package/dist/components/hx-list/index.js +1 -1
  64. package/dist/components/hx-menu/hx-menu-divider.d.ts +10 -0
  65. package/dist/components/hx-menu/hx-menu-divider.d.ts.map +1 -1
  66. package/dist/components/hx-menu/hx-menu-item.d.ts +99 -2
  67. package/dist/components/hx-menu/hx-menu-item.d.ts.map +1 -1
  68. package/dist/components/hx-menu/hx-menu-item.styles.d.ts.map +1 -1
  69. package/dist/components/hx-menu/hx-menu.d.ts +117 -2
  70. package/dist/components/hx-menu/hx-menu.d.ts.map +1 -1
  71. package/dist/components/hx-menu/index.js +1 -1
  72. package/dist/components/hx-meter/hx-meter.d.ts +39 -0
  73. package/dist/components/hx-meter/hx-meter.d.ts.map +1 -1
  74. package/dist/components/hx-meter/hx-meter.styles.d.ts.map +1 -1
  75. package/dist/components/hx-meter/index.js +1 -1
  76. package/dist/components/hx-overflow-menu/hx-overflow-menu.d.ts +132 -1
  77. package/dist/components/hx-overflow-menu/hx-overflow-menu.d.ts.map +1 -1
  78. package/dist/components/hx-overflow-menu/index.js +1 -1
  79. package/dist/components/hx-phi-field/hx-phi-field.d.ts +0 -1
  80. package/dist/components/hx-phi-field/hx-phi-field.d.ts.map +1 -1
  81. package/dist/components/hx-popover/hx-popover.d.ts +91 -0
  82. package/dist/components/hx-popover/hx-popover.d.ts.map +1 -1
  83. package/dist/components/hx-popover/index.js +1 -1
  84. package/dist/components/hx-progress-bar/hx-progress-bar.d.ts +33 -0
  85. package/dist/components/hx-progress-bar/hx-progress-bar.d.ts.map +1 -1
  86. package/dist/components/hx-progress-bar/index.js +1 -1
  87. package/dist/components/hx-radio-group/hx-radio-group.d.ts +152 -1
  88. package/dist/components/hx-radio-group/hx-radio-group.d.ts.map +1 -1
  89. package/dist/components/hx-radio-group/hx-radio.d.ts +14 -0
  90. package/dist/components/hx-radio-group/hx-radio.d.ts.map +1 -1
  91. package/dist/components/hx-radio-group/index.js +1 -1
  92. package/dist/components/hx-select/hx-select.d.ts +304 -2
  93. package/dist/components/hx-select/hx-select.d.ts.map +1 -1
  94. package/dist/components/hx-select/hx-select.styles.d.ts.map +1 -1
  95. package/dist/components/hx-select/index.js +1 -1
  96. package/dist/components/hx-side-nav/hx-nav-item.styles.d.ts.map +1 -1
  97. package/dist/components/hx-side-nav/index.js +1 -1
  98. package/dist/components/hx-spinner/hx-spinner.d.ts +14 -0
  99. package/dist/components/hx-spinner/hx-spinner.d.ts.map +1 -1
  100. package/dist/components/hx-spinner/index.js +1 -1
  101. package/dist/components/hx-split-button/hx-split-button.d.ts +94 -7
  102. package/dist/components/hx-split-button/hx-split-button.d.ts.map +1 -1
  103. package/dist/components/hx-split-button/index.js +1 -1
  104. package/dist/components/hx-stat/hx-stat.d.ts +28 -0
  105. package/dist/components/hx-stat/hx-stat.d.ts.map +1 -1
  106. package/dist/components/hx-stat/index.js +1 -1
  107. package/dist/components/hx-switch/hx-switch.d.ts +78 -1
  108. package/dist/components/hx-switch/hx-switch.d.ts.map +1 -1
  109. package/dist/components/hx-switch/hx-switch.styles.d.ts.map +1 -1
  110. package/dist/components/hx-switch/index.js +1 -1
  111. package/dist/components/hx-table/hx-td.d.ts +30 -3
  112. package/dist/components/hx-table/hx-td.d.ts.map +1 -1
  113. package/dist/components/hx-table/hx-th.d.ts +39 -3
  114. package/dist/components/hx-table/hx-th.d.ts.map +1 -1
  115. package/dist/components/hx-table/hx-tr.d.ts +26 -0
  116. package/dist/components/hx-table/hx-tr.d.ts.map +1 -1
  117. package/dist/components/hx-table/index.js +1 -1
  118. package/dist/components/hx-tabs/hx-tab-panel.d.ts +34 -0
  119. package/dist/components/hx-tabs/hx-tab-panel.d.ts.map +1 -1
  120. package/dist/components/hx-tabs/hx-tab.d.ts +45 -2
  121. package/dist/components/hx-tabs/hx-tab.d.ts.map +1 -1
  122. package/dist/components/hx-tabs/hx-tab.styles.d.ts.map +1 -1
  123. package/dist/components/hx-tabs/hx-tabs.d.ts +32 -2
  124. package/dist/components/hx-tabs/hx-tabs.d.ts.map +1 -1
  125. package/dist/components/hx-tabs/index.js +1 -1
  126. package/dist/components/hx-tag/hx-tag.styles.d.ts.map +1 -1
  127. package/dist/components/hx-tag/index.js +1 -1
  128. package/dist/components/hx-theme/hx-theme.d.ts +10 -5
  129. package/dist/components/hx-theme/hx-theme.d.ts.map +1 -1
  130. package/dist/components/hx-time-picker/hx-time-picker.d.ts +210 -2
  131. package/dist/components/hx-time-picker/hx-time-picker.d.ts.map +1 -1
  132. package/dist/components/hx-time-picker/hx-time-picker.styles.d.ts.map +1 -1
  133. package/dist/components/hx-time-picker/index.js +1 -1
  134. package/dist/components/hx-toast/hx-toast-stack.d.ts +14 -0
  135. package/dist/components/hx-toast/hx-toast-stack.d.ts.map +1 -1
  136. package/dist/components/hx-toast/hx-toast.d.ts +22 -3
  137. package/dist/components/hx-toast/hx-toast.d.ts.map +1 -1
  138. package/dist/components/hx-toast/index.js +1 -1
  139. package/dist/components/hx-toast/toast-factory.d.ts.map +1 -1
  140. package/dist/components/hx-toggle-button/hx-toggle-button.d.ts +110 -0
  141. package/dist/components/hx-toggle-button/hx-toggle-button.d.ts.map +1 -1
  142. package/dist/components/hx-toggle-button/hx-toggle-button.styles.d.ts.map +1 -1
  143. package/dist/components/hx-toggle-button/index.js +1 -1
  144. package/dist/components/hx-tooltip/hx-tooltip.d.ts +52 -0
  145. package/dist/components/hx-tooltip/hx-tooltip.d.ts.map +1 -1
  146. package/dist/components/hx-tooltip/index.js +1 -1
  147. package/dist/components/hx-tree-view/hx-tree-item.d.ts +117 -12
  148. package/dist/components/hx-tree-view/hx-tree-item.d.ts.map +1 -1
  149. package/dist/components/hx-tree-view/hx-tree-view.d.ts +87 -7
  150. package/dist/components/hx-tree-view/hx-tree-view.d.ts.map +1 -1
  151. package/dist/components/hx-tree-view/index.js +1 -1
  152. package/dist/css/helix-all.css +221 -1
  153. package/dist/css/helix-core.css +81 -0
  154. package/dist/css/helix-feedback.css +14 -0
  155. package/dist/css/helix-forms.css +109 -1
  156. package/dist/css/helix-overlay.css +17 -0
  157. package/dist/css/hx-alert.css +9 -0
  158. package/dist/css/hx-badge.css +28 -0
  159. package/dist/css/hx-checkbox.css +18 -0
  160. package/dist/css/hx-color-picker.css +25 -0
  161. package/dist/css/hx-date-picker.css +2 -1
  162. package/dist/css/hx-drawer.css +17 -0
  163. package/dist/css/hx-icon-button.css +30 -0
  164. package/dist/css/hx-meter.css +5 -0
  165. package/dist/css/hx-select.css +19 -0
  166. package/dist/css/hx-switch.css +17 -0
  167. package/dist/css/hx-tag.css +23 -0
  168. package/dist/css/hx-time-picker.css +11 -0
  169. package/dist/css/hx-toggle-button.css +17 -0
  170. package/dist/css/index.css +1 -1
  171. package/dist/css/manifest.json +4 -1
  172. package/dist/index.js +38 -38
  173. package/dist/shared/aria-flatten-DY6v2vah.js +22 -0
  174. package/dist/shared/aria-flatten-DY6v2vah.js.map +1 -0
  175. package/dist/shared/aria-idref-CxvyzfQS.js +126 -0
  176. package/dist/shared/aria-idref-CxvyzfQS.js.map +1 -0
  177. package/dist/shared/hx-accordion-ZVzgDzTG.js.map +1 -1
  178. package/dist/shared/{hx-alert-CLn7CstP.js → hx-alert-Bto8-TIi.js} +55 -37
  179. package/dist/shared/hx-alert-Bto8-TIi.js.map +1 -0
  180. package/dist/shared/{hx-badge-CQXgOXJM.js → hx-badge-JlFtAdxS.js} +37 -9
  181. package/dist/shared/hx-badge-JlFtAdxS.js.map +1 -0
  182. package/dist/shared/{hx-banner-D3DzpfcP.js → hx-banner-fpRnciIO.js} +13 -5
  183. package/dist/shared/hx-banner-fpRnciIO.js.map +1 -0
  184. package/dist/shared/{hx-button-DPY6SPVT.js → hx-button-BOwAEcF1.js} +108 -85
  185. package/dist/shared/{hx-button-DPY6SPVT.js.map → hx-button-BOwAEcF1.js.map} +1 -1
  186. package/dist/shared/{hx-button-group-BI-QBqmO.js → hx-button-group-DcHP5MBv.js} +15 -16
  187. package/dist/shared/{hx-button-group-BI-QBqmO.js.map → hx-button-group-DcHP5MBv.js.map} +1 -1
  188. package/dist/shared/hx-checkbox-C48KYKFq.js +696 -0
  189. package/dist/shared/hx-checkbox-C48KYKFq.js.map +1 -0
  190. package/dist/shared/hx-checkbox-group-BJIAX3zU.js +496 -0
  191. package/dist/shared/hx-checkbox-group-BJIAX3zU.js.map +1 -0
  192. package/dist/shared/hx-color-picker-Dk4cBwYQ.js +1221 -0
  193. package/dist/shared/hx-color-picker-Dk4cBwYQ.js.map +1 -0
  194. package/dist/shared/hx-combobox-BTLO9qiK.js +1359 -0
  195. package/dist/shared/hx-combobox-BTLO9qiK.js.map +1 -0
  196. package/dist/shared/{hx-data-table-CLqVqdxr.js → hx-data-table-Ct3gQ6ya.js} +3 -2
  197. package/dist/shared/{hx-data-table-CLqVqdxr.js.map → hx-data-table-Ct3gQ6ya.js.map} +1 -1
  198. package/dist/shared/{hx-date-picker-2iRG1p74.js → hx-date-picker-CiR7FVnR.js} +542 -206
  199. package/dist/shared/hx-date-picker-CiR7FVnR.js.map +1 -0
  200. package/dist/shared/hx-dialog-AOZpHSuF.js +717 -0
  201. package/dist/shared/hx-dialog-AOZpHSuF.js.map +1 -0
  202. package/dist/shared/{hx-drawer-Y1Ui2IWJ.js → hx-drawer-DH6CdAN1.js} +300 -98
  203. package/dist/shared/hx-drawer-DH6CdAN1.js.map +1 -0
  204. package/dist/shared/hx-dropdown-DiLd40Lm.js +401 -0
  205. package/dist/shared/hx-dropdown-DiLd40Lm.js.map +1 -0
  206. package/dist/shared/{hx-field-B3Qo8OLS.js → hx-field-zw0U1KVi.js} +99 -38
  207. package/dist/shared/hx-field-zw0U1KVi.js.map +1 -0
  208. package/dist/shared/{hx-icon-button-CGNdQSFM.js → hx-icon-button-a6OpeQz5.js} +149 -68
  209. package/dist/shared/hx-icon-button-a6OpeQz5.js.map +1 -0
  210. package/dist/shared/{hx-link-C-O6vq0Q.js → hx-link-CMnZRUtQ.js} +55 -43
  211. package/dist/shared/hx-link-CMnZRUtQ.js.map +1 -0
  212. package/dist/shared/{hx-list-MyEhh8c7.js → hx-list-De66EtAP.js} +163 -107
  213. package/dist/shared/hx-list-De66EtAP.js.map +1 -0
  214. package/dist/shared/hx-menu-divider-BjiRIWKq.js +797 -0
  215. package/dist/shared/hx-menu-divider-BjiRIWKq.js.map +1 -0
  216. package/dist/shared/{hx-meter-BPscsw5t.js → hx-meter-BJdh6nrF.js} +105 -64
  217. package/dist/shared/hx-meter-BJdh6nrF.js.map +1 -0
  218. package/dist/shared/{hx-nav-item-xqRPOCWX.js → hx-nav-item-CODtUlew.js} +13 -9
  219. package/dist/shared/{hx-nav-item-xqRPOCWX.js.map → hx-nav-item-CODtUlew.js.map} +1 -1
  220. package/dist/shared/hx-overflow-menu-BQ4fiMYu.js +492 -0
  221. package/dist/shared/hx-overflow-menu-BQ4fiMYu.js.map +1 -0
  222. package/dist/shared/hx-phi-field-C19oxlrr.js.map +1 -1
  223. package/dist/shared/{hx-popover-B-FP3-wW.js → hx-popover-B9W8-tC0.js} +123 -66
  224. package/dist/shared/hx-popover-B9W8-tC0.js.map +1 -0
  225. package/dist/shared/hx-progress-bar-C8nDMdYa.js +290 -0
  226. package/dist/shared/hx-progress-bar-C8nDMdYa.js.map +1 -0
  227. package/dist/shared/hx-radio-Z1lV1zTO.js +822 -0
  228. package/dist/shared/hx-radio-Z1lV1zTO.js.map +1 -0
  229. package/dist/shared/hx-select-D18CnJ0e.js +1089 -0
  230. package/dist/shared/hx-select-D18CnJ0e.js.map +1 -0
  231. package/dist/shared/{hx-spinner-DL5AYr16.js → hx-spinner-BB0h2hKZ.js} +62 -34
  232. package/dist/shared/hx-spinner-BB0h2hKZ.js.map +1 -0
  233. package/dist/shared/{hx-split-button-Djnc5Aeg.js → hx-split-button-BoABoEm5.js} +153 -82
  234. package/dist/shared/hx-split-button-BoABoEm5.js.map +1 -0
  235. package/dist/shared/{hx-stat-WOcNV1Ry.js → hx-stat-Dtf9lz-O.js} +77 -47
  236. package/dist/shared/hx-stat-Dtf9lz-O.js.map +1 -0
  237. package/dist/shared/hx-switch-B6kr-EwE.js +540 -0
  238. package/dist/shared/hx-switch-B6kr-EwE.js.map +1 -0
  239. package/dist/shared/{hx-tab-panel-DspCrKqo.js → hx-tab-panel-BQtBXKLD.js} +255 -131
  240. package/dist/shared/hx-tab-panel-BQtBXKLD.js.map +1 -0
  241. package/dist/shared/{hx-tag-CNSmdyaK.js → hx-tag-C5aCUpVi.js} +63 -40
  242. package/dist/shared/hx-tag-C5aCUpVi.js.map +1 -0
  243. package/dist/shared/{hx-td-DnnEMIuA.js → hx-td-BGkFOJEK.js} +267 -123
  244. package/dist/shared/hx-td-BGkFOJEK.js.map +1 -0
  245. package/dist/shared/hx-theme-BsefFWTO.js.map +1 -1
  246. package/dist/shared/hx-time-picker-iwCD7rzW.js +1038 -0
  247. package/dist/shared/hx-time-picker-iwCD7rzW.js.map +1 -0
  248. package/dist/shared/{hx-toggle-button-iLiYrMbD.js → hx-toggle-button-BQ81EDkl.js} +226 -65
  249. package/dist/shared/hx-toggle-button-BQ81EDkl.js.map +1 -0
  250. package/dist/shared/{hx-tooltip-nYOv9OLu.js → hx-tooltip-DVqtKPCD.js} +68 -46
  251. package/dist/shared/hx-tooltip-DVqtKPCD.js.map +1 -0
  252. package/dist/shared/hx-tree-item-CHrUhuZL.js +925 -0
  253. package/dist/shared/hx-tree-item-CHrUhuZL.js.map +1 -0
  254. package/dist/shared/menu-roving-DmMnzJhn.js +14 -0
  255. package/dist/shared/menu-roving-DmMnzJhn.js.map +1 -0
  256. package/dist/shared/menu-tree-BNM0SYYq.js +42 -0
  257. package/dist/shared/menu-tree-BNM0SYYq.js.map +1 -0
  258. package/dist/shared/{toast-factory-YSznocIV.js → toast-factory-CL2BzdSB.js} +128 -77
  259. package/dist/shared/toast-factory-CL2BzdSB.js.map +1 -0
  260. package/dist/utils/aria-flatten.d.ts +56 -0
  261. package/dist/utils/aria-flatten.d.ts.map +1 -0
  262. package/dist/utils/aria-idref.d.ts +127 -0
  263. package/dist/utils/aria-idref.d.ts.map +1 -0
  264. package/dist/utils/menu-label.d.ts +18 -0
  265. package/dist/utils/menu-label.d.ts.map +1 -0
  266. package/dist/utils/menu-roving.d.ts +28 -0
  267. package/dist/utils/menu-roving.d.ts.map +1 -0
  268. package/dist/utils/menu-tree.d.ts +41 -0
  269. package/dist/utils/menu-tree.d.ts.map +1 -0
  270. package/dist/utils/tree-walk.d.ts +53 -0
  271. package/dist/utils/tree-walk.d.ts.map +1 -0
  272. package/figma-inventory.json +132 -20
  273. package/package.json +1 -1
  274. package/dist/shared/hx-alert-CLn7CstP.js.map +0 -1
  275. package/dist/shared/hx-badge-CQXgOXJM.js.map +0 -1
  276. package/dist/shared/hx-banner-D3DzpfcP.js.map +0 -1
  277. package/dist/shared/hx-checkbox-D7xma9YH.js +0 -524
  278. package/dist/shared/hx-checkbox-D7xma9YH.js.map +0 -1
  279. package/dist/shared/hx-checkbox-group-C9n315Ju.js +0 -323
  280. package/dist/shared/hx-checkbox-group-C9n315Ju.js.map +0 -1
  281. package/dist/shared/hx-color-picker-uRc865FJ.js +0 -882
  282. package/dist/shared/hx-color-picker-uRc865FJ.js.map +0 -1
  283. package/dist/shared/hx-combobox-DDzqNKEW.js +0 -924
  284. package/dist/shared/hx-combobox-DDzqNKEW.js.map +0 -1
  285. package/dist/shared/hx-date-picker-2iRG1p74.js.map +0 -1
  286. package/dist/shared/hx-dialog-DRN_1-Y-.js +0 -514
  287. package/dist/shared/hx-dialog-DRN_1-Y-.js.map +0 -1
  288. package/dist/shared/hx-drawer-Y1Ui2IWJ.js.map +0 -1
  289. package/dist/shared/hx-dropdown-LyaRc8Rf.js +0 -263
  290. package/dist/shared/hx-dropdown-LyaRc8Rf.js.map +0 -1
  291. package/dist/shared/hx-field-B3Qo8OLS.js.map +0 -1
  292. package/dist/shared/hx-icon-button-CGNdQSFM.js.map +0 -1
  293. package/dist/shared/hx-link-C-O6vq0Q.js.map +0 -1
  294. package/dist/shared/hx-list-MyEhh8c7.js.map +0 -1
  295. package/dist/shared/hx-menu-divider-C2omnPtj.js +0 -558
  296. package/dist/shared/hx-menu-divider-C2omnPtj.js.map +0 -1
  297. package/dist/shared/hx-meter-BPscsw5t.js.map +0 -1
  298. package/dist/shared/hx-overflow-menu-DCLsdIBy.js +0 -374
  299. package/dist/shared/hx-overflow-menu-DCLsdIBy.js.map +0 -1
  300. package/dist/shared/hx-popover-B-FP3-wW.js.map +0 -1
  301. package/dist/shared/hx-progress-bar-Bn3JEPUf.js +0 -258
  302. package/dist/shared/hx-progress-bar-Bn3JEPUf.js.map +0 -1
  303. package/dist/shared/hx-radio-CJvNU2yP.js +0 -621
  304. package/dist/shared/hx-radio-CJvNU2yP.js.map +0 -1
  305. package/dist/shared/hx-select-C8fEHQhC.js +0 -807
  306. package/dist/shared/hx-select-C8fEHQhC.js.map +0 -1
  307. package/dist/shared/hx-spinner-DL5AYr16.js.map +0 -1
  308. package/dist/shared/hx-split-button-Djnc5Aeg.js.map +0 -1
  309. package/dist/shared/hx-stat-WOcNV1Ry.js.map +0 -1
  310. package/dist/shared/hx-switch-BrZFaRue.js +0 -420
  311. package/dist/shared/hx-switch-BrZFaRue.js.map +0 -1
  312. package/dist/shared/hx-tab-panel-DspCrKqo.js.map +0 -1
  313. package/dist/shared/hx-tag-CNSmdyaK.js.map +0 -1
  314. package/dist/shared/hx-td-DnnEMIuA.js.map +0 -1
  315. package/dist/shared/hx-time-picker-BoEIZwzv.js +0 -688
  316. package/dist/shared/hx-time-picker-BoEIZwzv.js.map +0 -1
  317. package/dist/shared/hx-toggle-button-iLiYrMbD.js.map +0 -1
  318. package/dist/shared/hx-tooltip-nYOv9OLu.js.map +0 -1
  319. package/dist/shared/hx-tree-item-C2CiWuDE.js +0 -703
  320. package/dist/shared/hx-tree-item-C2CiWuDE.js.map +0 -1
  321. package/dist/shared/toast-factory-YSznocIV.js.map +0 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hx-dropdown-DiLd40Lm.js","sources":["../../src/components/hx-dropdown/hx-dropdown.styles.ts","../../src/components/hx-dropdown/hx-dropdown.ts"],"sourcesContent":["import { css } from 'lit';\n\nexport const helixDropdownStyles = css`\n :host {\n display: inline-block;\n position: relative;\n }\n\n :host([disabled]) {\n pointer-events: none;\n opacity: var(--hx-opacity-disabled, 0.5);\n }\n\n .trigger-wrapper {\n display: inline-block;\n }\n\n [part='panel'] {\n position: fixed;\n z-index: var(--hx-dropdown-panel-z-index, 1000);\n min-width: var(--hx-dropdown-panel-min-width, 160px);\n background: var(--hx-dropdown-panel-bg, var(--hx-color-surface-default, #ffffff));\n border: 1px solid var(--hx-dropdown-panel-border-color, var(--hx-color-border-default, #d6dbd5));\n border-radius: var(--hx-dropdown-panel-border-radius, var(--hx-border-radius-md, 0.375rem));\n box-shadow: var(\n --hx-dropdown-panel-shadow,\n 0 4px 16px var(--hx-overlay-black-12, rgba(0, 0, 0, 0.12))\n );\n visibility: hidden;\n opacity: 0;\n pointer-events: none;\n transition:\n opacity var(--hx-transition-fast, 150ms ease),\n visibility var(--hx-transition-fast, 150ms ease);\n outline: none;\n }\n\n [part='panel'].panel--visible {\n visibility: visible;\n opacity: 1;\n pointer-events: auto;\n }\n\n @media (prefers-reduced-motion: reduce) {\n [part='panel'] {\n transition: none;\n }\n }\n\n /* ─── High Contrast Mode (forced-colors) ─── */\n\n @media (forced-colors: active) {\n [part='panel'] {\n background-color: Canvas;\n border: 2px solid CanvasText;\n }\n }\n`;\n","import { html, nothing, type PropertyValues } from 'lit';\nimport '../../utilities/document-token-adoption.js';\nimport { customElement, property, state, query } from 'lit/decorators.js';\nimport { devWarn } from '../../utils/dev-warn.js';\nimport { HelixElement } from '../../base/index.js';\nimport type { Placement as FloatingPlacement } from '@floating-ui/dom';\nimport { createIdCounter } from '../../base/index.js';\nimport { forcedColorsInteractive } from '../../styles/forced-colors.js';\nimport { helixDropdownStyles } from './hx-dropdown.styles.js';\nimport { flattenAccName } from '../../utils/aria-flatten.js';\nimport { getMenuItemTypeaheadLabel } from '../../utils/menu-label.js';\nimport { writeMenuItemRovingTabIndex } from '../../utils/menu-roving.js';\nimport { findClosestMenuAncestor } from '../../utils/menu-tree.js';\nimport {\n installAriaIdrefMirror,\n resolveIdrefTokens,\n type AriaIdrefMirrorHandle,\n} from '../../utils/aria-idref.js';\n\n// P2-03: Export so TypeScript consumers can import this type for prop typing.\nexport type DropdownPlacement =\n | 'top'\n | 'top-start'\n | 'top-end'\n | 'bottom'\n | 'bottom-start'\n | 'bottom-end'\n | 'start'\n | 'end';\n\nconst _nextDropdownId = createIdCounter('hx-dropdown');\n\n/**\n * A dropdown component — a button that opens a floating panel on click.\n *\n * ## Architecture Note: Host-Attribute Label Mirror (group-4 round-1)\n *\n * The announced surface is the inner `[part=\"panel\"]` element, which carries\n * `role=\"menu\"`. The host wraps a slotted trigger and the floating panel and\n * does NOT claim a role itself (apart from the round-35-style host\n * `aria-expanded` fallback used only when the trigger slot is empty).\n *\n * Because the panel lives in shadow DOM and `ElementInternals` IDL refs on\n * the host project semantics OUTWARD (host → AT) rather than INWARD\n * (host → shadow descendant), we use the **host-attribute mirror** pattern:\n * resolve consumer `aria-labelledby` IDREFs against the host's composed-tree\n * roots, text-flatten via `flattenAccName`, and write the result to the\n * panel's `aria-label`. Host `aria-label` outranks the `label` property in\n * the same precedence used by every host-canonical hx-* control.\n *\n * Naming precedence (W3C AccName 1.2 §4.3.1):\n * 1. Host `aria-labelledby` (resolved IDREFs, text-flattened)\n * 2. Host `aria-label`\n * 3. `label` property\n * 4. Hard-coded literal `\"Menu\"` (last-resort accessible name)\n *\n * **Group 4b → Group 5b boundary:** Group 4b added the host-attribute\n * label mirror **only** — additive on top of the existing dropdown\n * behaviour. Group 5b (this commit) adds the composite-navigation\n * portion that 4b explicitly deferred:\n * - **Roving tabindex** inside the panel (`_applyRovingTabIndex` +\n * `_rovingIndex`). Only the focused item carries `tabindex=0`.\n * - **First-character typeahead** with 500ms timeout (`_handleTypeahead`)\n * matching `hx-menu`, `hx-overflow-menu`, `hx-split-button`.\n * - Submenu auto-handling is delegated to slotted `hx-menu` /\n * `hx-menu-item` (whose `hx-item-submenu-open` / `hx-item-submenu-close`\n * events are auto-handled by the parent `hx-menu` after Group 5b).\n *\n * The panel's inner-div `role=\"menu\"` is intentionally NOT migrated to\n * the host: the host wraps a slotted consumer trigger AND the panel,\n * so it cannot canonically carry the menu role. Slotted `hx-menu-item`\n * children carry `role=\"menuitem\"` on their HOST after Group 5b's menu\n * migration, which fixes the cross-shadow walk concern from the\n * consumer's perspective.\n *\n * `aria-controls` is intentionally omitted on the trigger: the panel lives\n * in shadow DOM and IDREF values cannot be resolved across shadow\n * boundaries by assistive technology (axe-core flags this as a critical\n * violation if attempted). See `_setupTriggerAria` for the inline note.\n *\n * @summary Button that opens a floating menu panel on click.\n *\n * @tag hx-dropdown\n *\n * @slot trigger - The element that opens the dropdown (e.g. hx-button).\n * @slot - Default slot for dropdown panel content (e.g. menu items).\n *\n * @fires {CustomEvent<void>} hx-show - Dispatched when the dropdown is opened.\n * @fires {CustomEvent<void>} hx-hide - Dispatched when the dropdown is closed.\n * @fires {CustomEvent<{value: string | null; label: string}>} hx-select - Dispatched when a menu item is selected.\n *\n * @csspart trigger - The trigger wrapper element.\n * @csspart panel - The floating panel element.\n *\n * @cssprop [--hx-dropdown-panel-bg=var(--hx-color-neutral-0)] - Panel background color.\n * @cssprop [--hx-dropdown-panel-border-color=var(--hx-color-neutral-200)] - Panel border color.\n * @cssprop [--hx-dropdown-panel-border-radius=var(--hx-border-radius-md)] - Panel border radius.\n * @cssprop [--hx-dropdown-panel-shadow=0 4px 16px rgba(0,0,0,0.12)] - Panel box shadow.\n * @cssprop [--hx-dropdown-panel-z-index=1000] - Panel z-index.\n * @cssprop [--hx-dropdown-panel-min-width=160px] - Panel minimum width.\n *\n * @example\n * ```html\n * <hx-dropdown>\n * <button slot=\"trigger\">Open Menu</button>\n * <ul>\n * <li data-value=\"edit\">Edit</li>\n * <li data-value=\"delete\">Delete</li>\n * </ul>\n * </hx-dropdown>\n * ```\n * @cssprop [--hx-opacity-disabled] - Opacity.\n * @cssprop [--hx-color-neutral-0] - Color.\n * @cssprop [--hx-color-neutral-200] - Color.\n * @cssprop [--hx-border-radius-md] - CSS custom property.\n * @cssprop [--hx-overlay-black-12] - Overlay color.\n * @cssprop [--hx-transition-fast] - Transition timing.\n */\n@customElement('hx-dropdown')\nexport class HelixDropdown extends HelixElement {\n static override styles = [helixDropdownStyles, forcedColorsInteractive];\n\n // ─── Public Properties ───\n\n /**\n * Whether the dropdown panel is open.\n * @attr open\n */\n @property({ type: Boolean, reflect: true })\n open = false;\n\n /**\n * Preferred placement of the panel relative to the trigger.\n * @attr placement\n */\n @property({ type: String, reflect: true })\n placement:\n | 'top'\n | 'top-start'\n | 'top-end'\n | 'bottom'\n | 'bottom-start'\n | 'bottom-end'\n | 'start'\n | 'end' = 'bottom-start';\n\n /**\n * Accessible label for the dropdown menu panel. Override for i18n.\n * @attr label\n */\n @property() label = 'Menu';\n\n /**\n * Whether the dropdown is disabled. Prevents opening.\n * @attr disabled\n */\n @property({ type: Boolean, reflect: true })\n disabled = false;\n\n /**\n * Gap in pixels between the trigger and the panel.\n * @attr distance\n */\n @property({ type: Number })\n distance = 4;\n\n // ─── Internal State ───\n\n /**\n * Whether the dropdown panel is currently visible.\n * @internal\n */\n @state() private _panelVisible = false;\n\n /**\n * Index within the panel's focusable menu items of the item currently\n * holding the roving tabindex (and thus visual focus). −1 means the\n * panel has not been keyboard-focused yet.\n * @internal\n */\n private _rovingIndex = -1;\n\n /**\n * Accumulated character buffer for typeahead search within the panel's\n * menu items. Cleared after 500ms of inactivity.\n * @internal\n */\n private _typeaheadBuffer = '';\n\n /**\n * Timer handle that clears the typeahead buffer after a period of inactivity.\n * @internal\n */\n private _typeaheadTimer: ReturnType<typeof setTimeout> | null = null;\n\n /**\n * Resolved accessible name for the menu panel — the value written to the\n * inner `[part=\"panel\"]` `aria-label`. Recomputed on every sync per\n * AccName 1.2 §4.3.1 precedence: host `aria-labelledby` (flattened) >\n * host `aria-label` > `label` property > literal `\"Menu\"`.\n * @internal\n */\n @state() private _resolvedLabel = '';\n\n /**\n * Most recently observed consumer-supplied `aria-labelledby` token list on\n * the host. Refreshed every sync via `getAttribute()`.\n * @internal\n */\n private _consumerLabelledBy: string | null = null;\n\n /**\n * Handle for the shared host attribute / root id observer.\n * @internal\n */\n private _ariaMirror: AriaIdrefMirrorHandle | null = null;\n\n /**\n * Watches in-place text / visibility mutations on consumer light-DOM\n * elements resolved from the host's `aria-labelledby`.\n * @internal\n */\n private _externalRefsObserver: MutationObserver | null = null;\n\n /**\n * Guards against accumulating multiple document click listeners when open state\n * changes faster than the microtask queue can process removeEventListener calls.\n * @internal\n */\n private _documentListenerAttached = false;\n\n // P1-02: Unique panel ID for aria-controls.\n /**\n * Unique ID assigned to the floating panel element, referenced by `aria-controls` on the trigger.\n * @internal\n */\n private _panelId = `${_nextDropdownId()}-panel`;\n\n /**\n * Reference to the floating panel element inside the shadow DOM.\n * @internal\n */\n @query('[part=\"panel\"]') private _panel: HTMLElement | undefined;\n /**\n * Reference to the trigger wrapper element inside the shadow DOM.\n * @internal\n */\n @query('[part=\"trigger\"]') private _triggerWrapper: HTMLElement | undefined;\n\n // ─── Lifecycle ───\n\n override connectedCallback(): void {\n super.connectedCallback();\n this.addEventListener('keydown', this._handleKeydown);\n // Seed the host-attribute label mirror BEFORE first paint so the panel's\n // `aria-label` carries the resolved name on its very first render.\n this._syncResolvedLabel();\n this._ariaMirror = installAriaIdrefMirror(this, () => {\n this._syncResolvedLabel();\n });\n }\n\n override disconnectedCallback(): void {\n super.disconnectedCallback();\n this.removeEventListener('keydown', this._handleKeydown);\n if (this._documentListenerAttached) {\n document.removeEventListener('click', this._handleOutsideClick, { capture: true });\n this._documentListenerAttached = false;\n }\n if (this._typeaheadTimer !== null) {\n clearTimeout(this._typeaheadTimer);\n this._typeaheadTimer = null;\n }\n this._ariaMirror?.disconnect();\n this._ariaMirror = null;\n this._externalRefsObserver?.disconnect();\n this._externalRefsObserver = null;\n }\n\n // ─── Open/Close ───\n\n /** @internal */\n private async _show(): Promise<void> {\n if (this.open || this.disabled) return;\n this.open = true;\n this._panelVisible = true;\n // Add outside-click listener synchronously before any await so it is registered\n // by the time the test fires an outside click after a single await el.updateComplete.\n if (!this._documentListenerAttached) {\n document.addEventListener('click', this._handleOutsideClick, { capture: true });\n this._documentListenerAttached = true;\n }\n await this.updateComplete;\n // P0-01: Fix focus management — use slot.assignedElements() to traverse slotted (light DOM) content.\n // Focus is set after updateComplete (panel is rendered) but before _updatePosition so\n // it executes in the same microtask as the test's await-continuation.\n const panel = this._panel;\n if (panel) {\n // Group 5b: initialize roving tabindex on slotted menu items\n // before focusing the first one. Tab from outside lands on the\n // same item that has visual focus.\n const items = this._getFocusableMenuItems();\n if (items.length > 0) {\n this._rovingIndex = 0;\n this._applyRovingTabIndex(items);\n }\n const firstFocusable = this._getFirstFocusableItem();\n firstFocusable?.focus();\n }\n await this._updatePosition();\n this.dispatchEvent(new CustomEvent<void>('hx-show', { bubbles: true, composed: true }));\n }\n\n // P2-02: returnFocus=true only on Escape; Tab should let focus advance naturally.\n /** @internal */\n private _hide(returnFocus = true): void {\n if (!this.open) return;\n this.open = false;\n this._panelVisible = false;\n this._rovingIndex = -1;\n if (this._typeaheadTimer !== null) {\n clearTimeout(this._typeaheadTimer);\n this._typeaheadTimer = null;\n }\n this._typeaheadBuffer = '';\n if (this._documentListenerAttached) {\n document.removeEventListener('click', this._handleOutsideClick, { capture: true });\n this._documentListenerAttached = false;\n }\n this.dispatchEvent(new CustomEvent<void>('hx-hide', { bubbles: true, composed: true }));\n if (returnFocus) {\n const slot = this.shadowRoot?.querySelector<HTMLSlotElement>('slot[name=\"trigger\"]');\n const trigger = slot?.assignedElements()[0] as HTMLElement | undefined;\n trigger?.focus();\n }\n }\n\n // ─── Positioning ───\n\n /** @internal */\n private async _updatePosition(): Promise<void> {\n const reference = this._triggerWrapper;\n const panel = this._panel;\n if (!reference || !panel) return;\n\n // Map 'start' and 'end' to floating-ui's 'left'/'right'\n const floatingPlacement = this.placement\n .replace(/^start$/, 'left')\n .replace(/^end$/, 'right') as FloatingPlacement;\n\n const { computePosition, flip, shift, offset } = await import('@floating-ui/dom');\n const { x, y } = await computePosition(reference, panel, {\n placement: floatingPlacement,\n strategy: 'fixed',\n middleware: [offset(this.distance), flip(), shift({ padding: 8 })],\n });\n\n Object.assign(panel.style, {\n left: `${x}px`,\n top: `${y}px`,\n });\n }\n\n // ─── Event Handlers ───\n\n /** @internal */\n private _handleTriggerClick(e: MouseEvent): void {\n e.stopPropagation();\n if (this.open) {\n this._hide();\n } else {\n void this._show();\n }\n }\n\n /** @internal */\n private _handleTriggerKeydown(e: KeyboardEvent): void {\n if (e.key === 'Enter' || e.key === ' ' || e.key === 'ArrowDown') {\n e.preventDefault();\n void this._show();\n }\n }\n\n /** @internal */\n private _handleKeydown = (e: KeyboardEvent): void => {\n if (e.key === 'Escape' && this.open) {\n e.stopPropagation();\n this._hide(true); // return focus to trigger on Escape\n } else if (e.key === 'Tab' && this.open) {\n // P2-02: Do not return focus to trigger on Tab — let focus advance naturally to next page element.\n this._hide(false);\n } else if (\n this.open &&\n (e.key === 'ArrowDown' || e.key === 'ArrowUp' || e.key === 'Home' || e.key === 'End')\n ) {\n // P2-01: Arrow key roving within panel per APG Menu Button pattern.\n e.preventDefault();\n this._handleMenuNavigation(e.key);\n } else if (\n this.open &&\n e.key.length === 1 &&\n e.key !== ' ' &&\n !e.ctrlKey &&\n !e.metaKey &&\n !e.altKey\n ) {\n // Group 5b: first-character typeahead within the panel's menu\n // items. 500ms timeout matching hx-menu / hx-overflow-menu.\n this._handleTypeahead(e.key);\n }\n };\n\n // P2-01: Move focus among menuitem elements using arrow keys.\n /** @internal */\n private _handleMenuNavigation(key: string): void {\n const items = this._getFocusableMenuItems();\n if (items.length === 0) return;\n const currentIndex = items.indexOf(document.activeElement as HTMLElement);\n let nextIndex: number;\n if (key === 'ArrowDown') {\n nextIndex = currentIndex < items.length - 1 ? currentIndex + 1 : 0;\n } else if (key === 'ArrowUp') {\n nextIndex = currentIndex > 0 ? currentIndex - 1 : items.length - 1;\n } else if (key === 'Home') {\n nextIndex = 0;\n } else {\n nextIndex = items.length - 1;\n }\n this._rovingIndex = nextIndex;\n this._applyRovingTabIndex(items);\n items[nextIndex]?.focus();\n }\n\n /**\n * Roving tabindex inside the panel: only the focused item carries\n * tabindex=0; the rest are tabindex=-1. APG-compliant for the menu\n * button pattern. Closing-Tab semantics are preserved by the\n * `_handleKeydown` Tab branch above (which lets focus advance\n * naturally and closes the panel).\n *\n * Group 5b: introduced to align hx-dropdown's panel keyboard contract\n * with hx-menu / hx-overflow-menu / hx-split-button. Group 4b only\n * added the host-attribute label mirror (additive); this is the\n * keyboard portion deferred until Group 5.\n *\n * Codex push-gate round-8 finding 2: route through\n * `writeMenuItemRovingTabIndex` so host-canonical `hx-menu-item` items\n * land their roving tabindex on the correct surface (host on the\n * modern path, inner `.menu-item` on the fallback path). A direct\n * `item.tabIndex = value` write on the host fails on the fallback\n * path because the host is forced to `tabindex=-1` to keep exactly\n * one focusable surface per item.\n * @internal\n */\n private _applyRovingTabIndex(items: HTMLElement[]): void {\n items.forEach((item, i) => {\n writeMenuItemRovingTabIndex(item, i === this._rovingIndex ? 0 : -1);\n });\n }\n\n /** @internal */\n private _handleTypeahead(char: string): void {\n if (this._typeaheadTimer !== null) {\n clearTimeout(this._typeaheadTimer);\n }\n this._typeaheadBuffer += char.toLowerCase();\n this._typeaheadTimer = setTimeout(() => {\n this._typeaheadBuffer = '';\n this._typeaheadTimer = null;\n }, 500);\n\n const items = this._getFocusableMenuItems();\n // Codex push-gate round-7 finding 3: read item label via the shared\n // submenu-aware extractor so a parent menuitem with a nested\n // `<hx-menu slot=\"submenu\">` does not match grandchild text and steal\n // focus from a sibling. Single source of truth across hx-menu /\n // hx-dropdown / hx-overflow-menu / hx-split-button.\n const match = items.findIndex((item) => {\n const text = getMenuItemTypeaheadLabel(item).toLowerCase();\n return text.startsWith(this._typeaheadBuffer);\n });\n\n if (match !== -1) {\n this._rovingIndex = match;\n this._applyRovingTabIndex(items);\n items[match]?.focus();\n }\n }\n\n // P0-01 / P2-01: Get focusable menu items from slotted content.\n /** @internal */\n private _getFocusableMenuItems(): HTMLElement[] {\n const panel = this._panel;\n if (!panel) return [];\n const slot = panel.querySelector<HTMLSlotElement>('slot');\n const assignedNodes = slot?.assignedElements({ flatten: true }) ?? [];\n const items: HTMLElement[] = [];\n // `hx-menu-item` carries `role=\"menuitem\"` (or menuitemcheckbox /\n // menuitemradio) via `_internals.role` — AT-only, not a DOM attribute —\n // so `[role=\"menuitem\"]` selectors miss the host. Match the tag name in\n // tandem with the legacy attribute selector so both shapes traverse.\n const isHostCanonicalMenuItem = (el: Element): boolean => el.localName === 'hx-menu-item';\n const collectFrom = (root: ParentNode): HTMLElement[] => {\n const found: HTMLElement[] = [];\n root.querySelectorAll<HTMLElement>('[role=\"menuitem\"]').forEach((item) => found.push(item));\n root.querySelectorAll<HTMLElement>('hx-menu-item').forEach((item) => found.push(item));\n return found;\n };\n for (const node of assignedNodes) {\n if (!(node instanceof HTMLElement)) continue;\n if (node.matches('[role=\"menuitem\"]') || isHostCanonicalMenuItem(node)) {\n items.push(node);\n } else {\n collectFrom(node).forEach((item) => items.push(item));\n }\n }\n return items;\n }\n\n // P0-01: Find the first focusable element in slotted panel content.\n /** @internal */\n private _getFirstFocusableItem(): HTMLElement | null {\n const panel = this._panel;\n if (!panel) return null;\n const slot = panel.querySelector<HTMLSlotElement>('slot');\n const assignedNodes = slot?.assignedElements({ flatten: true }) ?? [];\n // `hx-menu-item` host carries `role=\"menuitem\"` via `_internals.role`\n // (invisible to attribute selectors). Add the literal tag name to the\n // focusable selector so the host-canonical menu-item is found.\n const focusableSelector =\n 'hx-menu-item, [role=\"menuitem\"], button, [tabindex]:not([tabindex=\"-1\"]), a[href], input, select, textarea';\n for (const node of assignedNodes) {\n if (!(node instanceof HTMLElement)) continue;\n if (node.matches(focusableSelector)) return node;\n const found = node.querySelector<HTMLElement>(focusableSelector);\n if (found) return found;\n }\n return null;\n }\n\n /** @internal */\n private _handleOutsideClick = (e: MouseEvent): void => {\n const path = e.composedPath();\n if (!path.includes(this)) {\n this._hide();\n }\n };\n\n /** @internal */\n private _handlePanelClick(e: MouseEvent): void {\n const target = e.target as HTMLElement;\n // P2-06: Narrow selector — bare 'li' and 'button' cause spurious hx-select events.\n // Group 5b round-3 (codex): bail FIRST on host-canonical `hx-menu-item`,\n // independently of what `closest()` resolves with the legacy selectors.\n // If a consumer slots `<hx-menu-item><span data-value=\"…\">…</span></hx-menu-item>`\n // and the click lands on the inner span, `closest('hx-menu-item, …, [data-value]')`\n // resolves to the inner span (nearest match) — the legacy localName guard\n // misses, and we'd dispatch `hx-select` here AND again from\n // `_handlePanelItemSelect` when the host's bubbled `hx-item-select` arrives.\n // The host owns its own dispatch path; descendants of the host must defer.\n if (target.closest('hx-menu-item')) return;\n const item = target.closest<HTMLElement>('[role=\"menuitem\"], [data-value]');\n if (!item) return;\n\n const value = item.dataset['value'] ?? item.getAttribute('value') ?? null;\n const label = item.textContent?.trim() ?? '';\n\n this.dispatchEvent(\n new CustomEvent<{ value: string | null; label: string }>('hx-select', {\n bubbles: true,\n composed: true,\n detail: { value, label },\n }),\n );\n\n this._hide();\n }\n\n /**\n * Bubbled `hx-item-select` from a slotted `hx-menu-item` host. Forwards\n * the activation through the composite's `hx-select` contract using the\n * item's `value` property and label text. Disabled items never emit\n * `hx-item-select`, so no disabled-guard is needed here.\n * @internal\n */\n private _handlePanelItemSelect(e: Event): void {\n const detail = (e as CustomEvent<{ item: HTMLElement; value: string }>).detail;\n const item = detail?.item;\n const value = detail?.value ?? null;\n const label = item?.textContent?.trim() ?? '';\n this.dispatchEvent(\n new CustomEvent<{ value: string | null; label: string }>('hx-select', {\n bubbles: true,\n composed: true,\n detail: { value, label },\n }),\n );\n this._hide();\n }\n\n /**\n * Bubbled `hx-item-submenu-open` from a slotted `hx-menu-item` host.\n * Codex push-gate round-9 P1: when slotted `hx-menu-item`s open / close\n * a nested submenu inside this composite's panel (no enclosing\n * `hx-menu`), the events fly past with no handler. Match the round-4\n * `hx-menu._handleSubmenuOpen` shape so APG behaviour holds.\n *\n * If the dispatching item is enclosed by an inner `hx-menu` (a true\n * nested submenu inside the panel), that menu owns the toggle — defer.\n * Otherwise this composite's panel is the enclosing menu surface, so\n * call `setSubmenuOpen(true)` on the item and focus the first child.\n * @internal\n */\n private _handlePanelSubmenuOpen = (e: Event): void => {\n if (!(e instanceof CustomEvent)) return;\n const detail = (e as CustomEvent<{ item: HTMLElement }>).detail;\n const item = detail?.item;\n if (!item) return;\n // Defer to a closer enclosing `hx-menu` (a nested submenu) when one\n // exists — that menu's own handler will own the toggle.\n if (findClosestMenuAncestor(item) !== null) return;\n queueMicrotask(() => {\n if (e.defaultPrevented) return;\n const setter = (item as HTMLElement & { setSubmenuOpen?: (v: boolean) => void })\n .setSubmenuOpen;\n if (typeof setter !== 'function') return;\n setter.call(item, true);\n const updateComplete = (item as HTMLElement & { updateComplete?: Promise<unknown> })\n .updateComplete;\n if (updateComplete) {\n void updateComplete\n .then(() => {\n const submenuSlot = (\n item as HTMLElement & { shadowRoot?: ShadowRoot | null }\n ).shadowRoot?.querySelector<HTMLSlotElement>('slot[name=\"submenu\"]');\n const nested = submenuSlot\n ?.assignedElements({ flatten: true })\n .find((el) => el.tagName.toLowerCase() === 'hx-menu') as\n | (HTMLElement & { focusFirst?: () => void })\n | undefined;\n nested?.focusFirst?.();\n })\n .catch(() => undefined);\n }\n });\n };\n\n /**\n * Bubbled `hx-item-submenu-close` from a slotted `hx-menu-item` host.\n * Codex push-gate round-9 P1: routes the close to the right surface.\n *\n * - Nested submenu close (the dispatching item lives inside an inner\n * `hx-menu` slotted into a parent's `slot=\"submenu\"`): defer to that\n * inner menu's own handler. The composite's panel must NOT close.\n * - Top-level item ArrowLeft (no enclosing `hx-menu` between the item\n * and this composite): there is no parent submenu to close, so\n * collapse the composite's panel and return focus to the trigger,\n * matching APG menu-button behaviour.\n * @internal\n */\n private _handlePanelSubmenuClose = (e: Event): void => {\n if (!(e instanceof CustomEvent)) return;\n const detail = (e as CustomEvent<{ item: HTMLElement }>).detail;\n const item = detail?.item;\n if (!item) return;\n // A closer enclosing `hx-menu` owns the close — defer.\n if (findClosestMenuAncestor(item) !== null) return;\n if (e.defaultPrevented) return;\n this._hide(true);\n };\n\n // ─── Render ───\n\n override render() {\n return html`\n <div\n part=\"trigger\"\n class=\"trigger-wrapper\"\n @click=${this._handleTriggerClick}\n @keydown=${this._handleTriggerKeydown}\n >\n <slot name=\"trigger\" @slotchange=${this._onTriggerSlotChange}></slot>\n </div>\n <div\n part=\"panel\"\n id=${this._panelId}\n role=\"menu\"\n aria-hidden=${this._panelVisible ? nothing : 'true'}\n aria-label=${this._resolvedLabel}\n class=${this._panelVisible ? 'panel panel--visible' : 'panel'}\n @click=${this._handlePanelClick}\n @hx-item-select=${this._handlePanelItemSelect}\n @hx-item-submenu-open=${this._handlePanelSubmenuOpen}\n @hx-item-submenu-close=${this._handlePanelSubmenuClose}\n >\n <slot @slotchange=${this._onPanelSlotChange}></slot>\n </div>\n `;\n }\n\n // ─── Panel slot validation ───\n\n /** @internal */\n private _onPanelSlotChange(e: Event): void {\n const slot = e.target as HTMLSlotElement;\n const assigned = slot.assignedElements({ flatten: true });\n const nonItems = assigned.filter((el) => el.tagName.toLowerCase() !== 'hx-dropdown-item');\n if (nonItems.length > 0) {\n devWarn(\n 'hx-dropdown',\n `Default slot should contain only hx-dropdown-item elements. Found unexpected: ${nonItems.map((el) => `<${el.tagName.toLowerCase()}>`).join(', ')}. Non-hx-dropdown-item children will be included in keyboard navigation incorrectly.`,\n );\n }\n }\n\n // ─── ARIA setup for trigger slot ───\n\n /** @internal */\n private _onTriggerSlotChange(): void {\n this._setupTriggerAria();\n }\n\n override firstUpdated(): void {\n this._setupTriggerAria();\n }\n\n /** @internal */\n private _setupTriggerAria(): void {\n const slot = this.shadowRoot?.querySelector<HTMLSlotElement>('slot[name=\"trigger\"]');\n if (!slot) return;\n const trigger = slot.assignedElements()[0] as HTMLElement | undefined;\n if (trigger) {\n // P1-01: Use aria-haspopup=\"menu\" per ARIA 1.1+ / APG Menu Button pattern.\n trigger.setAttribute('aria-haspopup', 'menu');\n trigger.setAttribute('aria-expanded', String(this.open));\n // aria-controls is intentionally omitted: the panel lives in Shadow DOM and\n // IDREF values cannot be resolved across shadow boundaries by assistive technology.\n // P2-06: Remove host fallback when a trigger element is present.\n this.removeAttribute('aria-expanded');\n } else {\n // P2-06: Fallback — set aria-expanded on host when trigger slot is empty or unassigned.\n this.setAttribute('aria-expanded', String(this.open));\n }\n }\n\n override willUpdate(changedProperties: PropertyValues<this>): void {\n super.willUpdate(changedProperties);\n // `label` property changes must flow into the resolved name BEFORE\n // render so the new fallback is in place on the same paint. See\n // `hx-popover.willUpdate()` for the same rationale.\n if (changedProperties.has('label')) {\n this._syncResolvedLabel();\n }\n }\n\n override updated(changedProperties: PropertyValues<this>): void {\n super.updated(changedProperties);\n if (changedProperties.has('open')) {\n // Keep aria-expanded in sync\n const slot = this.shadowRoot?.querySelector<HTMLSlotElement>('slot[name=\"trigger\"]');\n const trigger = slot?.assignedElements()[0] as HTMLElement | undefined;\n if (trigger) {\n trigger.setAttribute('aria-expanded', String(this.open));\n } else {\n // P2-06: Fallback — keep host aria-expanded in sync when trigger slot is empty.\n this.setAttribute('aria-expanded', String(this.open));\n }\n }\n }\n\n // ─── Host-attribute label mirror ───\n\n /**\n * (Re-)installs a `MutationObserver` over the deduped union of\n * consumer-resolved label elements, watching for in-place text /\n * visibility mutations so the panel's `aria-label` tracks live consumer\n * text. See `hx-popover._installExternalRefsObserver` for the matching\n * shape used across the host-attribute-mirror family.\n * @internal\n */\n private _installExternalRefsObserver(elements: Element[]): void {\n if (this._externalRefsObserver) {\n this._externalRefsObserver.disconnect();\n this._externalRefsObserver = null;\n }\n if (elements.length === 0) return;\n const unique = new Set<Element>(elements);\n const observer = new MutationObserver(() => {\n this._syncResolvedLabel();\n });\n for (const el of unique) {\n observer.observe(el, {\n characterData: true,\n subtree: true,\n childList: true,\n attributes: true,\n attributeFilter: ['aria-hidden', 'hidden'],\n });\n }\n this._externalRefsObserver = observer;\n }\n\n /**\n * Resolves the menu panel's accessible name from host attributes and the\n * `label` property. AccName 1.2 §4.3.1 precedence:\n * 1. Host `aria-labelledby` (resolved IDREFs, flattened)\n * 2. Host `aria-label`\n * 3. `label` property\n * 4. Literal `\"Menu\"` (last-resort)\n * @internal\n */\n private _syncResolvedLabel(): void {\n const liveLabelledBy = this.getAttribute('aria-labelledby');\n this._consumerLabelledBy = liveLabelledBy;\n const consumerLabelEls = resolveIdrefTokens(this, liveLabelledBy);\n\n this._installExternalRefsObserver(consumerLabelEls);\n\n const isVisibleForAccName = (el: Element): boolean =>\n el.getAttribute('aria-hidden') !== 'true' && !el.hasAttribute('hidden');\n\n const flattenedFromIdrefs = consumerLabelEls\n .filter(isVisibleForAccName)\n .map((el) => flattenAccName(el))\n .filter((t) => t.length > 0)\n .join(' ')\n .replace(/\\s+/g, ' ')\n .trim();\n\n const liveAriaLabel = this.getAttribute('aria-label');\n const hostAriaLabel = liveAriaLabel !== null ? liveAriaLabel.trim() : '';\n\n let resolved = '';\n if (flattenedFromIdrefs) {\n resolved = flattenedFromIdrefs;\n } else if (hostAriaLabel) {\n resolved = hostAriaLabel;\n } else if (this.label) {\n resolved = this.label;\n } else {\n resolved = 'Menu';\n }\n\n this._resolvedLabel = resolved;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'hx-dropdown': HelixDropdown;\n }\n interface HTMLElementEventMap {\n 'hx-show': CustomEvent<void>;\n 'hx-hide': CustomEvent<void>;\n 'hx-select': CustomEvent<{ value: string | null; label: string }>;\n }\n}\n"],"names":["helixDropdownStyles","css","_nextDropdownId","createIdCounter","HelixDropdown","HelixElement","detail","item","findClosestMenuAncestor","setter","updateComplete","submenuSlot","_a","nested","el","_b","installAriaIdrefMirror","items","firstFocusable","returnFocus","slot","trigger","reference","panel","floatingPlacement","computePosition","flip","shift","offset","x","y","key","currentIndex","nextIndex","writeMenuItemRovingTabIndex","char","match","getMenuItemTypeaheadLabel","assignedNodes","isHostCanonicalMenuItem","collectFrom","root","found","node","focusableSelector","target","value","label","html","nothing","nonItems","devWarn","changedProperties","elements","unique","observer","liveLabelledBy","consumerLabelEls","resolveIdrefTokens","isVisibleForAccName","flattenedFromIdrefs","flattenAccName","t","liveAriaLabel","hostAriaLabel","resolved","forcedColorsInteractive","__decorateClass","property","state","query","customElement"],"mappings":"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"}
@@ -1,10 +1,10 @@
1
- import { css as p, nothing as c, html as n } from "lit";
2
- import { property as o, state as f, customElement as _ } from "lit/decorators.js";
3
- import { classMap as x } from "lit/directives/class-map.js";
4
- import { d as u } from "./dev-warn-YlwPHjtX.js";
5
- import { H as m } from "./helix-element-BNEYeiys.js";
6
- import { c as b } from "./id-counter-DuX8vsui.js";
7
- const v = p`
1
+ import { css as f, nothing as _, html as n } from "lit";
2
+ import { property as a, state as c, customElement as p } from "lit/decorators.js";
3
+ import { classMap as u } from "lit/directives/class-map.js";
4
+ import { d as b } from "./dev-warn-YlwPHjtX.js";
5
+ import { H as x } from "./helix-element-BNEYeiys.js";
6
+ import { c as m } from "./id-counter-DuX8vsui.js";
7
+ const v = f`
8
8
  :host {
9
9
  display: block;
10
10
  }
@@ -160,18 +160,18 @@ const v = p`
160
160
  }
161
161
  }
162
162
  `;
163
- var y = Object.defineProperty, g = Object.getOwnPropertyDescriptor, l = (e, t, i, a) => {
164
- for (var s = a > 1 ? void 0 : a ? g(t, i) : t, h = e.length - 1, d; h >= 0; h--)
165
- (d = e[h]) && (s = (a ? d(t, i, s) : d(s)) || s);
166
- return a && s && y(t, i, s), s;
163
+ var g = Object.defineProperty, y = Object.getOwnPropertyDescriptor, l = (e, t, i, s) => {
164
+ for (var o = s > 1 ? void 0 : s ? y(t, i) : t, h = e.length - 1, d; h >= 0; h--)
165
+ (d = e[h]) && (o = (s ? d(t, i, o) : d(o)) || o);
166
+ return s && o && g(t, i, o), o;
167
167
  };
168
- const S = /* @__PURE__ */ new Set(["INPUT", "SELECT", "TEXTAREA", "BUTTON"]), E = b("hx-field");
169
- function C(e) {
170
- return S.has(e.tagName) || e.tagName.includes("-");
168
+ const A = /* @__PURE__ */ new Set(["INPUT", "SELECT", "TEXTAREA", "BUTTON"]), E = m("hx-field");
169
+ function L(e) {
170
+ return A.has(e.tagName) || e.tagName.includes("-");
171
171
  }
172
- let r = class extends m {
172
+ let r = class extends x {
173
173
  constructor() {
174
- super(...arguments), this.label = "", this.required = !1, this.error = "", this.helpText = "", this.disabled = !1, this.size = "md", this.layout = "column", this._hasLabelSlot = !1, this._hasErrorSlot = !1, this._hasHelpSlot = !1, this._fieldId = E(), this._helpTextId = `${this._fieldId}-help`, this._errorId = `${this._fieldId}-error`, this._a11yDescId = `${this._fieldId}-desc`, this._slottedControl = null, this._a11yDescEl = null;
174
+ super(...arguments), this.label = "", this.required = !1, this.error = "", this.helpText = "", this.disabled = !1, this.size = "md", this.layout = "column", this._hasLabelSlot = !1, this._hasErrorSlot = !1, this._hasHelpSlot = !1, this._fieldId = E(), this._helpTextId = `${this._fieldId}-help`, this._errorId = `${this._fieldId}-error`, this._a11yDescId = `${this._fieldId}-desc`, this._slottedControl = null, this._a11yDescEl = null, this._lastWrittenAriaLabel = null, this._competingLabelWarned = !1;
175
175
  }
176
176
  /** @internal */
177
177
  _handleLabelSlotChange(e) {
@@ -193,10 +193,10 @@ let r = class extends m {
193
193
  }
194
194
  disconnectedCallback() {
195
195
  var e;
196
- super.disconnectedCallback(), (e = this._a11yDescEl) == null || e.remove(), this._a11yDescEl = null, this._slottedControl && (this._slottedControl.removeAttribute("aria-label"), this._slottedControl.removeAttribute("aria-required"), this._slottedControl.removeAttribute("aria-invalid"), this._slottedControl.removeAttribute("aria-describedby"), this._slottedControl = null);
196
+ super.disconnectedCallback(), (e = this._a11yDescEl) == null || e.remove(), this._a11yDescEl = null, this._slottedControl && (this._releaseHostOwnedAriaLabel(this._slottedControl), this._slottedControl.removeAttribute("aria-required"), this._slottedControl.removeAttribute("aria-invalid"), this._slottedControl.removeAttribute("aria-describedby"), this._slottedControl = null), this._competingLabelWarned = !1;
197
197
  }
198
198
  updated(e) {
199
- super.updated(e), e.has("size") && (["sm", "md", "lg"].includes(this.size) || u(
199
+ super.updated(e), e.has("size") && (["sm", "md", "lg"].includes(this.size) || b(
200
200
  "hx-field",
201
201
  `Invalid hx-size value: "${this.size}". Expected "sm" | "md" | "lg". Defaulting to "md".`
202
202
  )), this._syncA11yDescEl(), this._syncSlottedControl();
@@ -217,8 +217,61 @@ let r = class extends m {
217
217
  /** Tracks the first form control assigned to the default slot. */
218
218
  /** @internal */
219
219
  _handleDefaultSlotChange(e) {
220
- const i = e.target.assignedElements();
221
- this._slottedControl = i.find(C) ?? null, this._syncSlottedControl();
220
+ const s = e.target.assignedElements().find(L) ?? null;
221
+ this._resolveSlottedControl(s);
222
+ }
223
+ /**
224
+ * Adopts a new slotted control and re-syncs ARIA wiring.
225
+ *
226
+ * Ownership of `aria-label` is tracked via the
227
+ * `data-hx-owns-label` marker attribute on the control itself, recomputed
228
+ * on every `_syncSlottedControl()` call — there is no cached ownership
229
+ * flag, so post-mount mutations of `aria-label` and `data-aria-managed`
230
+ * by the consumer are always honored.
231
+ * @internal
232
+ */
233
+ _resolveSlottedControl(e) {
234
+ const t = this._slottedControl;
235
+ t !== e && (t && (this._releaseHostOwnedAriaLabel(t), t.removeAttribute("aria-required"), t.removeAttribute("aria-invalid"), t.removeAttribute("aria-describedby")), this._slottedControl = e, this._competingLabelWarned = !1, this._lastWrittenAriaLabel = null, this._syncSlottedControl());
236
+ }
237
+ /**
238
+ * Returns true if hx-field owns the `aria-label` on the given control —
239
+ * i.e. the host wrote it, the marker attribute is still present, AND the
240
+ * live value still matches the value the host last wrote.
241
+ *
242
+ * Side effect: when the marker is present but the value no longer matches
243
+ * `_lastWrittenAriaLabel`, the consumer has overwritten the host value
244
+ * directly. We release the marker (and reset the snapshot) so subsequent
245
+ * syncs treat the value as consumer-owned. This keeps the marker honest
246
+ * without a MutationObserver.
247
+ *
248
+ * Cross-host migration / pre-mounted marker: if the marker is present but
249
+ * `_lastWrittenAriaLabel === null`, this host has never written to the
250
+ * control. Either (a) the control was migrated from a prior hx-field that
251
+ * stamped the marker, or (b) a consumer pre-mounted the marker themselves.
252
+ * In both cases this host has no ownership claim, so we strip the orphan
253
+ * marker and treat the value as consumer-owned. Without this, a fresh host
254
+ * with `label=""` would silently strip the inherited aria-label.
255
+ *
256
+ * Note (snapshot limitation): if the consumer rewrites `aria-label` to the
257
+ * exact same value we last wrote, we cannot detect the overwrite — to
258
+ * genuinely take ownership in that case the consumer must either write a
259
+ * different value or remove the `data-hx-owns-label` marker themselves.
260
+ *
261
+ * Absence of the marker (or presence of `data-aria-managed`) means the
262
+ * consumer owns the value and hx-field must not touch it.
263
+ * @internal
264
+ */
265
+ _hostOwnsAriaLabel(e) {
266
+ return e.hasAttribute("data-aria-managed") || !e.hasAttribute(r._ARIA_LABEL_OWNED_ATTR) ? !1 : this._lastWrittenAriaLabel === null ? (e.removeAttribute(r._ARIA_LABEL_OWNED_ATTR), !1) : e.getAttribute("aria-label") !== this._lastWrittenAriaLabel ? (e.removeAttribute(r._ARIA_LABEL_OWNED_ATTR), this._lastWrittenAriaLabel = null, !1) : !0;
267
+ }
268
+ /**
269
+ * Removes the host-owned `aria-label` and its ownership marker if (and only
270
+ * if) hx-field still owns them. Consumer-set values are left untouched.
271
+ * @internal
272
+ */
273
+ _releaseHostOwnedAriaLabel(e) {
274
+ this._hostOwnsAriaLabel(e) && (e.removeAttribute("aria-label"), e.removeAttribute(r._ARIA_LABEL_OWNED_ATTR), this._lastWrittenAriaLabel = null);
222
275
  }
223
276
  /**
224
277
  * Focuses the slotted form control when the shadow DOM label is clicked.
@@ -243,13 +296,20 @@ let r = class extends m {
243
296
  * - `HX-*` elements manage their own ARIA attributes; bridging is skipped.
244
297
  * - Elements with `data-aria-managed` attribute opt out of ARIA mutation;
245
298
  * bridging is skipped entirely for those elements.
299
+ *
300
+ * **Round-13 F2 ownership model:** `aria-label` ownership is recomputed
301
+ * from the live DOM on every call. If the marker attribute
302
+ * `data-hx-owns-label` is present, hx-field owns the value and may
303
+ * overwrite or remove it. Otherwise the consumer owns it, and hx-field
304
+ * leaves it alone. This makes post-mount consumer mutations
305
+ * (add/remove/replace) authoritative without relying on a stale flag.
246
306
  */
247
307
  /** @internal */
248
308
  _syncSlottedControl() {
249
309
  const e = this._slottedControl;
250
310
  if (!e || e.tagName.startsWith("HX-") || e.hasAttribute("data-aria-managed")) return;
251
- const t = !!this.error || this._hasErrorSlot, i = !!(this.error || this.helpText || this._hasErrorSlot || this._hasHelpSlot);
252
- this.label && !this._hasLabelSlot ? e.setAttribute("aria-label", this.label) : e.removeAttribute("aria-label"), this.required ? e.setAttribute("aria-required", "true") : e.removeAttribute("aria-required"), t ? e.setAttribute("aria-invalid", "true") : e.removeAttribute("aria-invalid"), i ? e.setAttribute("aria-describedby", this._a11yDescId) : e.removeAttribute("aria-describedby");
311
+ const t = !!this.error || this._hasErrorSlot, i = !!(this.error || this.helpText || this._hasErrorSlot || this._hasHelpSlot), s = this._hostOwnsAriaLabel(e);
312
+ e.hasAttribute("aria-label") && !s ? this.label && !this._hasLabelSlot && !this._competingLabelWarned && (this._competingLabelWarned = !0) : this.label && !this._hasLabelSlot ? (e.setAttribute("aria-label", this.label), e.setAttribute(r._ARIA_LABEL_OWNED_ATTR, "true"), this._lastWrittenAriaLabel = this.label) : this._releaseHostOwnedAriaLabel(e), this.required ? e.setAttribute("aria-required", "true") : e.removeAttribute("aria-required"), t ? e.setAttribute("aria-invalid", "true") : e.removeAttribute("aria-invalid"), i ? e.setAttribute("aria-describedby", this._a11yDescId) : e.removeAttribute("aria-describedby");
253
313
  }
254
314
  // ─── Render ───
255
315
  render() {
@@ -264,7 +324,7 @@ let r = class extends m {
264
324
  "field--layout-inline": this.layout === "inline"
265
325
  };
266
326
  return n`
267
- <div part="field" class=${x(i)}>
327
+ <div part="field" class=${u(i)}>
268
328
  <!-- Label -->
269
329
  <div class="field__label-wrapper">
270
330
  <slot name="label" @slotchange=${this._handleLabelSlotChange}>
@@ -276,9 +336,9 @@ let r = class extends m {
276
336
  class="field__required-marker"
277
337
  aria-hidden="true"
278
338
  >*</span
279
- >` : c}
339
+ >` : _}
280
340
  </label>
281
- ` : c}
341
+ ` : _}
282
342
  </slot>
283
343
  </div>
284
344
 
@@ -296,7 +356,7 @@ let r = class extends m {
296
356
  <div part="error" class="field__error" id=${this._errorId} role="alert">
297
357
  ${this.error}
298
358
  </div>
299
- ` : c}
359
+ ` : _}
300
360
  </slot>
301
361
 
302
362
  <!-- Slotted error live region — ensures slotted error content is announced -->
@@ -316,40 +376,41 @@ let r = class extends m {
316
376
  }
317
377
  };
318
378
  r.styles = [v];
379
+ r._ARIA_LABEL_OWNED_ATTR = "data-hx-owns-label";
319
380
  l([
320
- o({ type: String })
381
+ a({ type: String })
321
382
  ], r.prototype, "label", 2);
322
383
  l([
323
- o({ type: Boolean, reflect: !0 })
384
+ a({ type: Boolean, reflect: !0 })
324
385
  ], r.prototype, "required", 2);
325
386
  l([
326
- o({ type: String })
387
+ a({ type: String })
327
388
  ], r.prototype, "error", 2);
328
389
  l([
329
- o({ type: String, attribute: "help-text" })
390
+ a({ type: String, attribute: "help-text" })
330
391
  ], r.prototype, "helpText", 2);
331
392
  l([
332
- o({ type: Boolean, reflect: !0 })
393
+ a({ type: Boolean, reflect: !0 })
333
394
  ], r.prototype, "disabled", 2);
334
395
  l([
335
- o({ type: String, attribute: "hx-size", reflect: !0 })
396
+ a({ type: String, attribute: "hx-size", reflect: !0 })
336
397
  ], r.prototype, "size", 2);
337
398
  l([
338
- o({ type: String, reflect: !0 })
399
+ a({ type: String, reflect: !0 })
339
400
  ], r.prototype, "layout", 2);
340
401
  l([
341
- f()
402
+ c()
342
403
  ], r.prototype, "_hasLabelSlot", 2);
343
404
  l([
344
- f()
405
+ c()
345
406
  ], r.prototype, "_hasErrorSlot", 2);
346
407
  l([
347
- f()
408
+ c()
348
409
  ], r.prototype, "_hasHelpSlot", 2);
349
410
  r = l([
350
- _("hx-field")
411
+ p("hx-field")
351
412
  ], r);
352
413
  export {
353
414
  r as H
354
415
  };
355
- //# sourceMappingURL=hx-field-B3Qo8OLS.js.map
416
+ //# sourceMappingURL=hx-field-zw0U1KVi.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hx-field-zw0U1KVi.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-text-strong, #202b39));\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, #c92a2a));\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-text-muted, #4a5362));\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, #c92a2a));\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, #c92a2a));\n }\n\n .field--error .field__control {\n outline: 2px solid var(--hx-field-error-color, var(--hx-color-error-500, #e5493e));\n outline-offset: var(--hx-focus-ring-offset, 2px);\n border-radius: var(--hx-border-radius-sm, 0.25rem);\n }\n\n /* ─── High Contrast Mode (forced-colors) ─── */\n\n @media (forced-colors: active) {\n .field__label {\n color: CanvasText;\n }\n\n .field__required-marker {\n color: LinkText;\n }\n\n .field--error .field__label {\n color: LinkText;\n }\n\n .field--error .field__control {\n outline-color: LinkText;\n }\n\n :host([disabled]) {\n opacity: 1;\n }\n\n :host([disabled]) .field__label {\n color: GrayText;\n }\n\n .field__help-text {\n color: GrayText;\n }\n\n .field__error {\n color: LinkText;\n }\n }\n`;\n","import { html, nothing, type PropertyValues } from 'lit';\nimport '../../utilities/document-token-adoption.js';\nimport { customElement, property, state } from 'lit/decorators.js';\nimport { classMap } from 'lit/directives/class-map.js';\nimport { HelixElement, createIdCounter } from '../../base/index.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\nconst _nextFieldId = createIdCounter('hx-field');\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 * **`aria-label` ownership model:** When `label` is set and no shadow `<label>`\n * is rendered, hx-field writes `aria-label` to the slotted control and stamps\n * a `data-hx-owns-label=\"true\"` ownership marker.\n *\n * Consumers have two ways to keep their value safe from hx-field's writes:\n * (a) **Suspend** all ARIA bridging by setting `data-aria-managed` on the\n * control. While present, hx-field skips every aria-* mutation and\n * leaves any existing marker/snapshot in place — removing\n * `data-aria-managed` later may resume host ownership of an `aria-label`\n * value that still matches the snapshot.\n * (b) **Release** ownership permanently by overwriting `aria-label` to a\n * different value than the one hx-field last wrote. The mismatch\n * triggers `_releaseHostOwnedAriaLabel`, which strips the marker and\n * clears the snapshot, transferring ownership to the consumer.\n *\n * **Limitation:** because release detection is snapshot-based, a consumer\n * rewrite to the *exact same value* hx-field last wrote is invisible. To\n * genuinely take ownership in that case the consumer must write a different\n * value (even briefly), or remove the `data-hx-owns-label` marker themselves.\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 - 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 * @cssprop [--hx-opacity-disabled] - Opacity.\n * @cssprop [--hx-space-1] - Spacing token.\n * @cssprop [--hx-font-family-sans] - Font family.\n * @cssprop [--hx-font-size-sm] - Font size.\n * @cssprop [--hx-font-weight-medium] - Font weight.\n * @cssprop [--hx-color-neutral-700] - Color.\n * @cssprop [--hx-line-height-normal] - Line height.\n * @cssprop [--hx-color-error-text] - Color.\n * @cssprop [--hx-font-weight-bold] - Font weight.\n * @cssprop [--hx-font-size-xs] - Font size.\n * @cssprop [--hx-font-size-md] - Font size.\n * @cssprop [--hx-color-neutral-500] - Color.\n * @cssprop [--hx-color-error-500] - Color.\n * @cssprop [--hx-focus-ring-offset] - CSS custom property.\n * @cssprop [--hx-border-radius-sm] - CSS custom property.\n */\n@customElement('hx-field')\nexport class HelixField extends HelixElement {\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 = _nextFieldId();\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 /**\n * Marker attribute placed on the slotted control whenever hx-field writes\n * `aria-label` to it. Presence of this marker indicates host ownership of\n * the attribute; absence means the value belongs to the consumer.\n *\n * Ownership is recomputed from the live DOM on every `_syncSlottedControl()`\n * call rather than cached in a flag — this keeps post-mount mutations\n * (consumer adds/removes `aria-label`, toggles `data-aria-managed`)\n * authoritative instead of letting a stale snapshot win.\n *\n * See round-13 F2 for context on the precedence hazard.\n * @internal\n */\n private static readonly _ARIA_LABEL_OWNED_ATTR = 'data-hx-owns-label';\n\n /**\n * Last `aria-label` value written by hx-field to the currently adopted\n * control. Used in combination with the ownership marker to detect a\n * consumer overwrite: if the marker is present but the live value no\n * longer matches what we last wrote, the consumer has taken over and we\n * release the marker so subsequent syncs treat the value as consumer-\n * owned.\n * @internal\n */\n private _lastWrittenAriaLabel: string | null = null;\n\n /**\n * Tracks whether the dev-time competing-label warning has already been\n * emitted for the currently adopted slotted control.\n *\n * Latch semantics: this fires **once per adopted control**. The latch is\n * only reset on adoption (`_resolveSlottedControl()`) or disconnection.\n * Toggling `data-aria-managed` on/off on the same control after the\n * warning has fired does NOT re-arm the latch — by design, to avoid\n * console spam from consumers who toggle the attribute repeatedly.\n * @internal\n */\n private _competingLabelWarned = false;\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. We only remove\n // `aria-label` if hx-field owns it (marker present) — otherwise the\n // value belongs to the consumer and removing would clobber their input.\n if (this._slottedControl) {\n this._releaseHostOwnedAriaLabel(this._slottedControl);\n this._slottedControl.removeAttribute('aria-required');\n this._slottedControl.removeAttribute('aria-invalid');\n this._slottedControl.removeAttribute('aria-describedby');\n this._slottedControl = null;\n }\n this._competingLabelWarned = false;\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 const next = assigned.find(isFormControl) ?? null;\n this._resolveSlottedControl(next);\n }\n\n /**\n * Adopts a new slotted control and re-syncs ARIA wiring.\n *\n * Ownership of `aria-label` is tracked via the\n * `data-hx-owns-label` marker attribute on the control itself, recomputed\n * on every `_syncSlottedControl()` call — there is no cached ownership\n * flag, so post-mount mutations of `aria-label` and `data-aria-managed`\n * by the consumer are always honored.\n * @internal\n */\n private _resolveSlottedControl(next: HTMLElement | null): void {\n const prev = this._slottedControl;\n if (prev === next) return;\n\n // If we are leaving a previous control, strip the aria attributes we own\n // so the host doesn't leave stale wiring on a control that is no longer\n // associated. We only remove `aria-label` if hx-field owns it\n // (round-13 F2 — respect consumer overrides).\n if (prev) {\n this._releaseHostOwnedAriaLabel(prev);\n prev.removeAttribute('aria-required');\n prev.removeAttribute('aria-invalid');\n prev.removeAttribute('aria-describedby');\n }\n\n this._slottedControl = next;\n // Reset the once-per-adoption warning latch so the warning can fire\n // again for the freshly adopted control.\n this._competingLabelWarned = false;\n // Drop the value snapshot from any previous adoption.\n this._lastWrittenAriaLabel = null;\n\n this._syncSlottedControl();\n }\n\n /**\n * Returns true if hx-field owns the `aria-label` on the given control —\n * i.e. the host wrote it, the marker attribute is still present, AND the\n * live value still matches the value the host last wrote.\n *\n * Side effect: when the marker is present but the value no longer matches\n * `_lastWrittenAriaLabel`, the consumer has overwritten the host value\n * directly. We release the marker (and reset the snapshot) so subsequent\n * syncs treat the value as consumer-owned. This keeps the marker honest\n * without a MutationObserver.\n *\n * Cross-host migration / pre-mounted marker: if the marker is present but\n * `_lastWrittenAriaLabel === null`, this host has never written to the\n * control. Either (a) the control was migrated from a prior hx-field that\n * stamped the marker, or (b) a consumer pre-mounted the marker themselves.\n * In both cases this host has no ownership claim, so we strip the orphan\n * marker and treat the value as consumer-owned. Without this, a fresh host\n * with `label=\"\"` would silently strip the inherited aria-label.\n *\n * Note (snapshot limitation): if the consumer rewrites `aria-label` to the\n * exact same value we last wrote, we cannot detect the overwrite — to\n * genuinely take ownership in that case the consumer must either write a\n * different value or remove the `data-hx-owns-label` marker themselves.\n *\n * Absence of the marker (or presence of `data-aria-managed`) means the\n * consumer owns the value and hx-field must not touch it.\n * @internal\n */\n private _hostOwnsAriaLabel(control: HTMLElement): boolean {\n if (control.hasAttribute('data-aria-managed')) return false;\n if (!control.hasAttribute(HelixField._ARIA_LABEL_OWNED_ATTR)) return false;\n if (this._lastWrittenAriaLabel === null) {\n // Orphan marker — either migrated from a prior host or pre-mounted by\n // the consumer. This host has no claim; release and defer to consumer.\n control.removeAttribute(HelixField._ARIA_LABEL_OWNED_ATTR);\n return false;\n }\n const liveValue = control.getAttribute('aria-label');\n if (liveValue !== this._lastWrittenAriaLabel) {\n // Consumer rewrote the attribute under us — they are the owner now.\n control.removeAttribute(HelixField._ARIA_LABEL_OWNED_ATTR);\n this._lastWrittenAriaLabel = null;\n return false;\n }\n return true;\n }\n\n /**\n * Removes the host-owned `aria-label` and its ownership marker if (and only\n * if) hx-field still owns them. Consumer-set values are left untouched.\n * @internal\n */\n private _releaseHostOwnedAriaLabel(control: HTMLElement): void {\n if (this._hostOwnsAriaLabel(control)) {\n control.removeAttribute('aria-label');\n control.removeAttribute(HelixField._ARIA_LABEL_OWNED_ATTR);\n this._lastWrittenAriaLabel = null;\n }\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 * **Round-13 F2 ownership model:** `aria-label` ownership is recomputed\n * from the live DOM on every call. If the marker attribute\n * `data-hx-owns-label` is present, hx-field owns the value and may\n * overwrite or remove it. Otherwise the consumer owns it, and hx-field\n * leaves it alone. This makes post-mount consumer mutations\n * (add/remove/replace) authoritative without relying on a stale flag.\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 // entirely — including any host-owned aria-label we may have written\n // before the attribute was added. We do NOT remove a host-owned label\n // here because doing so would silently strip the visible label simply\n // because the consumer toggled the opt-out.\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 //\n // Round-13 F2: ownership is decided by the marker on the control, not a\n // cached flag. A consumer-owned value is always left intact.\n const hostOwnsLabel = this._hostOwnsAriaLabel(control);\n const consumerHasLabel = control.hasAttribute('aria-label') && !hostOwnsLabel;\n\n if (consumerHasLabel) {\n // Consumer owns the value — never touch it.\n if (this.label && !this._hasLabelSlot && !this._competingLabelWarned) {\n // Dev-only: warn once per adoption that the consumer's aria-label\n // takes precedence over the visible `label` prop. Production builds\n // drop this call entirely via the `import.meta.env.DEV` gate inside\n // `devWarn`. The latch (`_competingLabelWarned`) is reset on every\n // adoption in `_resolveSlottedControl()`.\n devWarn(\n 'hx-field',\n 'Slotted control already has `aria-label`. The consumer override is being respected; the visible `label` prop will not be mirrored to the control. Remove one of the two to silence this warning.',\n );\n this._competingLabelWarned = true;\n }\n } else if (this.label && !this._hasLabelSlot) {\n // Host writes the label and stamps the ownership marker so a future\n // sync can tell its own value apart from a consumer override.\n control.setAttribute('aria-label', this.label);\n control.setAttribute(HelixField._ARIA_LABEL_OWNED_ATTR, 'true');\n this._lastWrittenAriaLabel = this.label;\n } else {\n // No host-supplied label and no consumer label — clean up any prior\n // host-owned value. (If the consumer set one in the meantime, the\n // `consumerHasLabel` branch above handles it.)\n this._releaseHostOwnedAriaLabel(control);\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\" 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","_nextFieldId","createIdCounter","isFormControl","el","HelixField","HelixElement","slot","_a","changedProps","devWarn","span","next","prev","control","_e","hasError","hasDesc","hostOwnsLabel","hasHelp","fieldClasses","html","classMap","nothing","__decorateClass","property","state","customElement"],"mappings":";;;;;;AAEO,MAAMA,IAAmBC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;;;;ACOhC,MAAMC,wBAAwB,IAAI,CAAC,SAAS,UAAU,YAAY,QAAQ,CAAC,GAErEC,IAAeC,EAAgB,UAAU;AAG/C,SAASC,EAAcC,GAAgC;AACrD,SAAOJ,EAAkB,IAAII,EAAG,OAAO,KAAKA,EAAG,QAAQ,SAAS,GAAG;AACrE;AA0EO,IAAMC,IAAN,cAAyBC,EAAa;AAAA,EAAtC,cAAA;AAAA,UAAA,GAAA,SAAA,GAUL,KAAA,QAAQ,IAOR,KAAA,WAAW,IAOX,KAAA,QAAQ,IAOR,KAAA,WAAW,IAQX,KAAA,WAAW,IAOX,KAAA,OAA2B,MAO3B,KAAA,SAA8B,UAQrB,KAAQ,gBAAgB,IAMxB,KAAQ,gBAAgB,IAMxB,KAAQ,eAAe,IA0BhC,KAAQ,WAAWL,EAAA,GAMnB,KAAQ,cAAc,GAAG,KAAK,QAAQ,SAMtC,KAAQ,WAAW,GAAG,KAAK,QAAQ,UAMnC,KAAQ,cAAc,GAAG,KAAK,QAAQ,SAStC,KAAQ,kBAAsC,MAe9C,KAAQ,cAAkC,MA0B1C,KAAQ,wBAAuC,MAa/C,KAAQ,wBAAwB;AAAA,EAAA;AAAA;AAAA,EAxGxB,uBAAuB,GAAgB;AAC7C,UAAMM,IAAO,EAAE;AACf,SAAK,gBAAgBA,EAAK,iBAAA,EAAmB,SAAS;AAAA,EACxD;AAAA;AAAA,EAGQ,uBAAuB,GAAgB;AAC7C,UAAMA,IAAO,EAAE;AACf,SAAK,gBAAgBA,EAAK,iBAAA,EAAmB,SAAS;AAAA,EACxD;AAAA;AAAA,EAGQ,sBAAsB,GAAgB;AAC5C,UAAMA,IAAO,EAAE;AACf,SAAK,eAAeA,EAAK,iBAAA,EAAmB,SAAS;AAAA,EACvD;AAAA,EA2FS,oBAA0B;AACjC,UAAM,kBAAA,GACN,KAAK,kBAAA;AAAA,EACP;AAAA,EAES,uBAA6B;;AACpC,UAAM,qBAAA,IACNC,IAAA,KAAK,gBAAL,QAAAA,EAAkB,UAClB,KAAK,cAAc,MAIf,KAAK,oBACP,KAAK,2BAA2B,KAAK,eAAe,GACpD,KAAK,gBAAgB,gBAAgB,eAAe,GACpD,KAAK,gBAAgB,gBAAgB,cAAc,GACnD,KAAK,gBAAgB,gBAAgB,kBAAkB,GACvD,KAAK,kBAAkB,OAEzB,KAAK,wBAAwB;AAAA,EAC/B;AAAA,EAES,QAAQC,GAA0C;AACzD,UAAM,QAAQA,CAAY,GAGtBA,EAAa,IAAI,MAAM,MACN,CAAC,MAAM,MAAM,IAAI,EACpB,SAAS,KAAK,IAAI,KAChCC;AAAA,MACE;AAAA,MACA,2BAA2B,KAAK,IAAI;AAAA,IAAA,IAK1C,KAAK,gBAAA,GACL,KAAK,oBAAA;AAAA,EACP;AAAA;AAAA;AAAA,EAIQ,oBAA0B;AAGhC,QAFI,KAAK,eAEL,OAAO,WAAa,IAAa;AACrC,UAAMC,IAAO,SAAS,cAAc,MAAM;AAC1C,IAAAA,EAAK,KAAK,KAAK,aAEfA,EAAK,MAAM,UACT,yGACF,KAAK,YAAYA,CAAI,GACrB,KAAK,cAAcA;AAAA,EACrB;AAAA;AAAA;AAAA,EAIQ,kBAAwB;AAC9B,QAAI,CAAC,KAAK,YAAa;AAEvB,KADiB,CAAC,CAAC,KAAK,SAAS,KAAK,kBACtB,KAAK,QACnB,KAAK,YAAY,cAAc,KAAK,QAC3B,KAAK,WACd,KAAK,YAAY,cAAc,KAAK,WAEpC,KAAK,YAAY,cAAc;AAAA,EAEnC;AAAA;AAAA;AAAA,EAIQ,yBAAyB,GAAgB;AAG/C,UAAMC,IAFO,EAAE,OACO,iBAAA,EACA,KAAKT,CAAa,KAAK;AAC7C,SAAK,uBAAuBS,CAAI;AAAA,EAClC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYQ,uBAAuBA,GAAgC;AAC7D,UAAMC,IAAO,KAAK;AAClB,IAAIA,MAASD,MAMTC,MACF,KAAK,2BAA2BA,CAAI,GACpCA,EAAK,gBAAgB,eAAe,GACpCA,EAAK,gBAAgB,cAAc,GACnCA,EAAK,gBAAgB,kBAAkB,IAGzC,KAAK,kBAAkBD,GAGvB,KAAK,wBAAwB,IAE7B,KAAK,wBAAwB,MAE7B,KAAK,oBAAA;AAAA,EACP;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EA8BQ,mBAAmBE,GAA+B;AAExD,WADIA,EAAQ,aAAa,mBAAmB,KACxC,CAACA,EAAQ,aAAaT,EAAW,sBAAsB,IAAU,KACjE,KAAK,0BAA0B,QAGjCS,EAAQ,gBAAgBT,EAAW,sBAAsB,GAClD,MAESS,EAAQ,aAAa,YAAY,MACjC,KAAK,yBAErBA,EAAQ,gBAAgBT,EAAW,sBAAsB,GACzD,KAAK,wBAAwB,MACtB,MAEF;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOQ,2BAA2BS,GAA4B;AAC7D,IAAI,KAAK,mBAAmBA,CAAO,MACjCA,EAAQ,gBAAgB,YAAY,GACpCA,EAAQ,gBAAgBT,EAAW,sBAAsB,GACzD,KAAK,wBAAwB;AAAA,EAEjC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQQ,kBAAkBU,GAAiB;;AACzC,KAAAP,IAAA,KAAK,oBAAL,QAAAA,EAAsB;AAAA,EACxB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAwBQ,sBAA4B;AAClC,UAAMM,IAAU,KAAK;AAWrB,QAVI,CAACA,KAGDA,EAAQ,QAAQ,WAAW,KAAK,KAOhCA,EAAQ,aAAa,mBAAmB,EAAG;AAE/C,UAAME,IAAW,CAAC,CAAC,KAAK,SAAS,KAAK,eAChCC,IAAU,CAAC,EAAE,KAAK,SAAS,KAAK,YAAY,KAAK,iBAAiB,KAAK,eAMvEC,IAAgB,KAAK,mBAAmBJ,CAAO;AAGrD,IAFyBA,EAAQ,aAAa,YAAY,KAAK,CAACI,IAI1D,KAAK,SAAS,CAAC,KAAK,iBAAiB,CAAC,KAAK,0BAU7C,KAAK,wBAAwB,MAEtB,KAAK,SAAS,CAAC,KAAK,iBAG7BJ,EAAQ,aAAa,cAAc,KAAK,KAAK,GAC7CA,EAAQ,aAAaT,EAAW,wBAAwB,MAAM,GAC9D,KAAK,wBAAwB,KAAK,SAKlC,KAAK,2BAA2BS,CAAO,GAIrC,KAAK,WACPA,EAAQ,aAAa,iBAAiB,MAAM,IAE5CA,EAAQ,gBAAgB,eAAe,GAIrCE,IACFF,EAAQ,aAAa,gBAAgB,MAAM,IAE3CA,EAAQ,gBAAgB,cAAc,GAIpCG,IACFH,EAAQ,aAAa,oBAAoB,KAAK,WAAW,IAEzDA,EAAQ,gBAAgB,kBAAkB;AAAA,EAE9C;AAAA;AAAA,EAIS,SAAS;AAChB,UAAME,IAAW,CAAC,CAAC,KAAK,SAAS,KAAK,eAChCG,IAAU,CAAC,CAAC,KAAK,YAAY,KAAK,cAElCC,IAAe;AAAA,MACnB,OAAO;AAAA,MACP,gBAAgBJ;AAAA,MAChB,mBAAmB,KAAK;AAAA,MACxB,mBAAmB,KAAK;AAAA,MACxB,kBAAkB,KAAK,SAAS;AAAA,MAChC,kBAAkB,KAAK,SAAS;AAAA,MAChC,kBAAkB,KAAK,SAAS;AAAA,MAChC,wBAAwB,KAAK,WAAW;AAAA,IAAA;AAG1C,WAAOK;AAAA,gCACqBC,EAASF,CAAY,CAAC;AAAA;AAAA;AAAA,2CAGX,KAAK,sBAAsB;AAAA,cACxD,KAAK,SAAS,CAAC,KAAK,gBAClBC;AAAA,oEACoD,KAAK,iBAAiB;AAAA,sBACpE,KAAK,KAAK;AAAA,sBACV,KAAK,WACHA;AAAA;AAAA;AAAA;AAAA;AAAA,6BAMAE,CAAO;AAAA;AAAA,oBAGfA,CAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,8BASO,KAAK,wBAAwB;AAAA;AAAA;AAAA;AAAA,yCAIlB,KAAK,sBAAsB;AAAA,YACxD,KAAK,QACHF;AAAA,4DAC8C,KAAK,QAAQ;AAAA,oBACrD,KAAK,KAAK;AAAA;AAAA,kBAGhBE,CAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,eAUN,KAAK,WAAW;AAAA,oBACX,CAACJ,KAAWH,CAAQ;AAAA;AAAA,+CAEO,KAAK,qBAAqB,IAAI,KAAK,QAAQ;AAAA;AAAA;AAAA;AAAA,EAIxF;AACF;AAthBaX,EACK,SAAS,CAACP,CAAgB;AAD/BO,EA4Ja,yBAAyB;AAlJjDmB,EAAA;AAAA,EADCC,EAAS,EAAE,MAAM,OAAA,CAAQ;AAAA,GATfpB,EAUX,WAAA,SAAA,CAAA;AAOAmB,EAAA;AAAA,EADCC,EAAS,EAAE,MAAM,SAAS,SAAS,IAAM;AAAA,GAhB/BpB,EAiBX,WAAA,YAAA,CAAA;AAOAmB,EAAA;AAAA,EADCC,EAAS,EAAE,MAAM,OAAA,CAAQ;AAAA,GAvBfpB,EAwBX,WAAA,SAAA,CAAA;AAOAmB,EAAA;AAAA,EADCC,EAAS,EAAE,MAAM,QAAQ,WAAW,aAAa;AAAA,GA9BvCpB,EA+BX,WAAA,YAAA,CAAA;AAQAmB,EAAA;AAAA,EADCC,EAAS,EAAE,MAAM,SAAS,SAAS,IAAM;AAAA,GAtC/BpB,EAuCX,WAAA,YAAA,CAAA;AAOAmB,EAAA;AAAA,EADCC,EAAS,EAAE,MAAM,QAAQ,WAAW,WAAW,SAAS,IAAM;AAAA,GA7CpDpB,EA8CX,WAAA,QAAA,CAAA;AAOAmB,EAAA;AAAA,EADCC,EAAS,EAAE,MAAM,QAAQ,SAAS,IAAM;AAAA,GApD9BpB,EAqDX,WAAA,UAAA,CAAA;AAQiBmB,EAAA;AAAA,EAAhBE,EAAA;AAAM,GA7DIrB,EA6DM,WAAA,iBAAA,CAAA;AAMAmB,EAAA;AAAA,EAAhBE,EAAA;AAAM,GAnEIrB,EAmEM,WAAA,iBAAA,CAAA;AAMAmB,EAAA;AAAA,EAAhBE,EAAA;AAAM,GAzEIrB,EAyEM,WAAA,gBAAA,CAAA;AAzENA,IAANmB,EAAA;AAAA,EADNG,EAAc,UAAU;AAAA,GACZtB,CAAA;"}