@helixui/library 3.3.1-next.118 → 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 (249) hide show
  1. package/custom-elements.json +422 -322
  2. package/dist/components/hx-alert/hx-alert.d.ts +11 -0
  3. package/dist/components/hx-alert/hx-alert.d.ts.map +1 -1
  4. package/dist/components/hx-alert/hx-alert.styles.d.ts.map +1 -1
  5. package/dist/components/hx-alert/index.js +1 -1
  6. package/dist/components/hx-badge/hx-badge.styles.d.ts.map +1 -1
  7. package/dist/components/hx-badge/index.js +1 -1
  8. package/dist/components/hx-banner/hx-banner.d.ts +9 -1
  9. package/dist/components/hx-banner/hx-banner.d.ts.map +1 -1
  10. package/dist/components/hx-banner/index.js +1 -1
  11. package/dist/components/hx-button/hx-button.d.ts +11 -1
  12. package/dist/components/hx-button/hx-button.d.ts.map +1 -1
  13. package/dist/components/hx-button/index.js +1 -1
  14. package/dist/components/hx-button-group/hx-button-group.d.ts +13 -0
  15. package/dist/components/hx-button-group/hx-button-group.d.ts.map +1 -1
  16. package/dist/components/hx-button-group/index.js +1 -1
  17. package/dist/components/hx-checkbox/hx-checkbox.d.ts.map +1 -1
  18. package/dist/components/hx-checkbox/index.js +1 -1
  19. package/dist/components/hx-checkbox-group/index.js +1 -1
  20. package/dist/components/hx-color-picker/index.js +1 -1
  21. package/dist/components/hx-combobox/index.js +1 -1
  22. package/dist/components/hx-data-table/hx-data-table.d.ts.map +1 -1
  23. package/dist/components/hx-data-table/index.js +1 -1
  24. package/dist/components/hx-date-picker/index.js +1 -1
  25. package/dist/components/hx-dialog/index.js +1 -1
  26. package/dist/components/hx-drawer/hx-drawer.d.ts +201 -0
  27. package/dist/components/hx-drawer/hx-drawer.d.ts.map +1 -1
  28. package/dist/components/hx-drawer/hx-drawer.styles.d.ts.map +1 -1
  29. package/dist/components/hx-drawer/index.js +1 -1
  30. package/dist/components/hx-dropdown/hx-dropdown.d.ts +96 -8
  31. package/dist/components/hx-dropdown/hx-dropdown.d.ts.map +1 -1
  32. package/dist/components/hx-dropdown/index.js +1 -1
  33. package/dist/components/hx-icon-button/hx-icon-button.d.ts +16 -3
  34. package/dist/components/hx-icon-button/hx-icon-button.d.ts.map +1 -1
  35. package/dist/components/hx-icon-button/hx-icon-button.styles.d.ts.map +1 -1
  36. package/dist/components/hx-icon-button/index.js +1 -1
  37. package/dist/components/hx-link/hx-link.d.ts +10 -1
  38. package/dist/components/hx-link/hx-link.d.ts.map +1 -1
  39. package/dist/components/hx-link/index.js +1 -1
  40. package/dist/components/hx-list/hx-list-item.d.ts +27 -1
  41. package/dist/components/hx-list/hx-list-item.d.ts.map +1 -1
  42. package/dist/components/hx-list/hx-list.d.ts +28 -0
  43. package/dist/components/hx-list/hx-list.d.ts.map +1 -1
  44. package/dist/components/hx-list/index.js +1 -1
  45. package/dist/components/hx-menu/hx-menu-divider.d.ts +10 -0
  46. package/dist/components/hx-menu/hx-menu-divider.d.ts.map +1 -1
  47. package/dist/components/hx-menu/hx-menu-item.d.ts +99 -2
  48. package/dist/components/hx-menu/hx-menu-item.d.ts.map +1 -1
  49. package/dist/components/hx-menu/hx-menu-item.styles.d.ts.map +1 -1
  50. package/dist/components/hx-menu/hx-menu.d.ts +117 -2
  51. package/dist/components/hx-menu/hx-menu.d.ts.map +1 -1
  52. package/dist/components/hx-menu/index.js +1 -1
  53. package/dist/components/hx-meter/hx-meter.d.ts +39 -0
  54. package/dist/components/hx-meter/hx-meter.d.ts.map +1 -1
  55. package/dist/components/hx-meter/hx-meter.styles.d.ts.map +1 -1
  56. package/dist/components/hx-meter/index.js +1 -1
  57. package/dist/components/hx-overflow-menu/hx-overflow-menu.d.ts +132 -1
  58. package/dist/components/hx-overflow-menu/hx-overflow-menu.d.ts.map +1 -1
  59. package/dist/components/hx-overflow-menu/index.js +1 -1
  60. package/dist/components/hx-phi-field/hx-phi-field.d.ts +0 -1
  61. package/dist/components/hx-phi-field/hx-phi-field.d.ts.map +1 -1
  62. package/dist/components/hx-popover/index.js +1 -1
  63. package/dist/components/hx-progress-bar/hx-progress-bar.d.ts +33 -0
  64. package/dist/components/hx-progress-bar/hx-progress-bar.d.ts.map +1 -1
  65. package/dist/components/hx-progress-bar/index.js +1 -1
  66. package/dist/components/hx-radio-group/index.js +1 -1
  67. package/dist/components/hx-select/hx-select.d.ts +1 -0
  68. package/dist/components/hx-select/hx-select.d.ts.map +1 -1
  69. package/dist/components/hx-select/index.js +1 -1
  70. package/dist/components/hx-spinner/hx-spinner.d.ts +14 -0
  71. package/dist/components/hx-spinner/hx-spinner.d.ts.map +1 -1
  72. package/dist/components/hx-spinner/index.js +1 -1
  73. package/dist/components/hx-split-button/hx-split-button.d.ts +94 -7
  74. package/dist/components/hx-split-button/hx-split-button.d.ts.map +1 -1
  75. package/dist/components/hx-split-button/index.js +1 -1
  76. package/dist/components/hx-stat/hx-stat.d.ts +28 -0
  77. package/dist/components/hx-stat/hx-stat.d.ts.map +1 -1
  78. package/dist/components/hx-stat/index.js +1 -1
  79. package/dist/components/hx-switch/index.js +1 -1
  80. package/dist/components/hx-table/hx-td.d.ts +30 -3
  81. package/dist/components/hx-table/hx-td.d.ts.map +1 -1
  82. package/dist/components/hx-table/hx-th.d.ts +39 -3
  83. package/dist/components/hx-table/hx-th.d.ts.map +1 -1
  84. package/dist/components/hx-table/hx-tr.d.ts +26 -0
  85. package/dist/components/hx-table/hx-tr.d.ts.map +1 -1
  86. package/dist/components/hx-table/index.js +1 -1
  87. package/dist/components/hx-tabs/hx-tab-panel.d.ts +34 -0
  88. package/dist/components/hx-tabs/hx-tab-panel.d.ts.map +1 -1
  89. package/dist/components/hx-tabs/hx-tab.d.ts +45 -2
  90. package/dist/components/hx-tabs/hx-tab.d.ts.map +1 -1
  91. package/dist/components/hx-tabs/hx-tab.styles.d.ts.map +1 -1
  92. package/dist/components/hx-tabs/hx-tabs.d.ts +32 -2
  93. package/dist/components/hx-tabs/hx-tabs.d.ts.map +1 -1
  94. package/dist/components/hx-tabs/index.js +1 -1
  95. package/dist/components/hx-tag/hx-tag.styles.d.ts.map +1 -1
  96. package/dist/components/hx-tag/index.js +1 -1
  97. package/dist/components/hx-theme/hx-theme.d.ts +10 -5
  98. package/dist/components/hx-theme/hx-theme.d.ts.map +1 -1
  99. package/dist/components/hx-time-picker/hx-time-picker.d.ts +210 -2
  100. package/dist/components/hx-time-picker/hx-time-picker.d.ts.map +1 -1
  101. package/dist/components/hx-time-picker/hx-time-picker.styles.d.ts.map +1 -1
  102. package/dist/components/hx-time-picker/index.js +1 -1
  103. package/dist/components/hx-toast/hx-toast-stack.d.ts +14 -0
  104. package/dist/components/hx-toast/hx-toast-stack.d.ts.map +1 -1
  105. package/dist/components/hx-toast/hx-toast.d.ts +22 -3
  106. package/dist/components/hx-toast/hx-toast.d.ts.map +1 -1
  107. package/dist/components/hx-toast/index.js +1 -1
  108. package/dist/components/hx-toast/toast-factory.d.ts.map +1 -1
  109. package/dist/components/hx-toggle-button/index.js +1 -1
  110. package/dist/components/hx-tree-view/hx-tree-item.d.ts +117 -12
  111. package/dist/components/hx-tree-view/hx-tree-item.d.ts.map +1 -1
  112. package/dist/components/hx-tree-view/hx-tree-view.d.ts +87 -7
  113. package/dist/components/hx-tree-view/hx-tree-view.d.ts.map +1 -1
  114. package/dist/components/hx-tree-view/index.js +1 -1
  115. package/dist/css/helix-all.css +123 -0
  116. package/dist/css/helix-core.css +81 -0
  117. package/dist/css/helix-feedback.css +14 -0
  118. package/dist/css/helix-forms.css +11 -0
  119. package/dist/css/helix-overlay.css +17 -0
  120. package/dist/css/hx-alert.css +9 -0
  121. package/dist/css/hx-badge.css +28 -0
  122. package/dist/css/hx-drawer.css +17 -0
  123. package/dist/css/hx-icon-button.css +30 -0
  124. package/dist/css/hx-meter.css +5 -0
  125. package/dist/css/hx-tag.css +23 -0
  126. package/dist/css/hx-time-picker.css +11 -0
  127. package/dist/css/index.css +1 -1
  128. package/dist/css/manifest.json +3 -1
  129. package/dist/index.js +35 -35
  130. package/dist/shared/aria-idref-CxvyzfQS.js +126 -0
  131. package/dist/shared/aria-idref-CxvyzfQS.js.map +1 -0
  132. package/dist/shared/{hx-alert-CLn7CstP.js → hx-alert-Bto8-TIi.js} +55 -37
  133. package/dist/shared/hx-alert-Bto8-TIi.js.map +1 -0
  134. package/dist/shared/{hx-badge-CQXgOXJM.js → hx-badge-JlFtAdxS.js} +37 -9
  135. package/dist/shared/hx-badge-JlFtAdxS.js.map +1 -0
  136. package/dist/shared/{hx-banner-D3DzpfcP.js → hx-banner-fpRnciIO.js} +13 -5
  137. package/dist/shared/hx-banner-fpRnciIO.js.map +1 -0
  138. package/dist/shared/{hx-button-DPY6SPVT.js → hx-button-BOwAEcF1.js} +108 -85
  139. package/dist/shared/{hx-button-DPY6SPVT.js.map → hx-button-BOwAEcF1.js.map} +1 -1
  140. package/dist/shared/{hx-button-group-BI-QBqmO.js → hx-button-group-DcHP5MBv.js} +15 -16
  141. package/dist/shared/{hx-button-group-BI-QBqmO.js.map → hx-button-group-DcHP5MBv.js.map} +1 -1
  142. package/dist/shared/{hx-checkbox-BdgoUeWi.js → hx-checkbox-C48KYKFq.js} +87 -87
  143. package/dist/shared/hx-checkbox-C48KYKFq.js.map +1 -0
  144. package/dist/shared/{hx-checkbox-group-LWezHrvS.js → hx-checkbox-group-BJIAX3zU.js} +2 -2
  145. package/dist/shared/{hx-checkbox-group-LWezHrvS.js.map → hx-checkbox-group-BJIAX3zU.js.map} +1 -1
  146. package/dist/shared/{hx-color-picker-DVhZl88b.js → hx-color-picker-Dk4cBwYQ.js} +2 -2
  147. package/dist/shared/{hx-color-picker-DVhZl88b.js.map → hx-color-picker-Dk4cBwYQ.js.map} +1 -1
  148. package/dist/shared/{hx-combobox-DvlezcDV.js → hx-combobox-BTLO9qiK.js} +2 -2
  149. package/dist/shared/{hx-combobox-DvlezcDV.js.map → hx-combobox-BTLO9qiK.js.map} +1 -1
  150. package/dist/shared/{hx-data-table-CLqVqdxr.js → hx-data-table-Ct3gQ6ya.js} +3 -2
  151. package/dist/shared/{hx-data-table-CLqVqdxr.js.map → hx-data-table-Ct3gQ6ya.js.map} +1 -1
  152. package/dist/shared/{hx-date-picker-N-0aG5XL.js → hx-date-picker-CiR7FVnR.js} +2 -2
  153. package/dist/shared/{hx-date-picker-N-0aG5XL.js.map → hx-date-picker-CiR7FVnR.js.map} +1 -1
  154. package/dist/shared/{hx-dialog-DzB7VytW.js → hx-dialog-AOZpHSuF.js} +2 -2
  155. package/dist/shared/{hx-dialog-DzB7VytW.js.map → hx-dialog-AOZpHSuF.js.map} +1 -1
  156. package/dist/shared/{hx-drawer-Y1Ui2IWJ.js → hx-drawer-DH6CdAN1.js} +300 -98
  157. package/dist/shared/hx-drawer-DH6CdAN1.js.map +1 -0
  158. package/dist/shared/hx-dropdown-DiLd40Lm.js +401 -0
  159. package/dist/shared/hx-dropdown-DiLd40Lm.js.map +1 -0
  160. package/dist/shared/{hx-icon-button-CGNdQSFM.js → hx-icon-button-a6OpeQz5.js} +149 -68
  161. package/dist/shared/hx-icon-button-a6OpeQz5.js.map +1 -0
  162. package/dist/shared/{hx-link-C-O6vq0Q.js → hx-link-CMnZRUtQ.js} +55 -43
  163. package/dist/shared/hx-link-CMnZRUtQ.js.map +1 -0
  164. package/dist/shared/{hx-list-MyEhh8c7.js → hx-list-De66EtAP.js} +163 -107
  165. package/dist/shared/hx-list-De66EtAP.js.map +1 -0
  166. package/dist/shared/hx-menu-divider-BjiRIWKq.js +797 -0
  167. package/dist/shared/hx-menu-divider-BjiRIWKq.js.map +1 -0
  168. package/dist/shared/{hx-meter-BPscsw5t.js → hx-meter-BJdh6nrF.js} +105 -64
  169. package/dist/shared/hx-meter-BJdh6nrF.js.map +1 -0
  170. package/dist/shared/hx-overflow-menu-BQ4fiMYu.js +492 -0
  171. package/dist/shared/hx-overflow-menu-BQ4fiMYu.js.map +1 -0
  172. package/dist/shared/hx-phi-field-C19oxlrr.js.map +1 -1
  173. package/dist/shared/{hx-popover-CHxWY_cd.js → hx-popover-B9W8-tC0.js} +2 -2
  174. package/dist/shared/{hx-popover-CHxWY_cd.js.map → hx-popover-B9W8-tC0.js.map} +1 -1
  175. package/dist/shared/hx-progress-bar-C8nDMdYa.js +290 -0
  176. package/dist/shared/hx-progress-bar-C8nDMdYa.js.map +1 -0
  177. package/dist/shared/{hx-radio-CeGzARNk.js → hx-radio-Z1lV1zTO.js} +2 -2
  178. package/dist/shared/{hx-radio-CeGzARNk.js.map → hx-radio-Z1lV1zTO.js.map} +1 -1
  179. package/dist/shared/{hx-select-DrcS-YRJ.js → hx-select-D18CnJ0e.js} +2 -2
  180. package/dist/shared/hx-select-D18CnJ0e.js.map +1 -0
  181. package/dist/shared/{hx-spinner-DL5AYr16.js → hx-spinner-BB0h2hKZ.js} +62 -34
  182. package/dist/shared/hx-spinner-BB0h2hKZ.js.map +1 -0
  183. package/dist/shared/{hx-split-button-Djnc5Aeg.js → hx-split-button-BoABoEm5.js} +153 -82
  184. package/dist/shared/hx-split-button-BoABoEm5.js.map +1 -0
  185. package/dist/shared/{hx-stat-WOcNV1Ry.js → hx-stat-Dtf9lz-O.js} +77 -47
  186. package/dist/shared/hx-stat-Dtf9lz-O.js.map +1 -0
  187. package/dist/shared/{hx-switch-BX_8uNUs.js → hx-switch-B6kr-EwE.js} +2 -2
  188. package/dist/shared/{hx-switch-BX_8uNUs.js.map → hx-switch-B6kr-EwE.js.map} +1 -1
  189. package/dist/shared/{hx-tab-panel-DspCrKqo.js → hx-tab-panel-BQtBXKLD.js} +255 -131
  190. package/dist/shared/hx-tab-panel-BQtBXKLD.js.map +1 -0
  191. package/dist/shared/{hx-tag-CNSmdyaK.js → hx-tag-C5aCUpVi.js} +63 -40
  192. package/dist/shared/hx-tag-C5aCUpVi.js.map +1 -0
  193. package/dist/shared/{hx-td-DnnEMIuA.js → hx-td-BGkFOJEK.js} +267 -123
  194. package/dist/shared/hx-td-BGkFOJEK.js.map +1 -0
  195. package/dist/shared/hx-theme-BsefFWTO.js.map +1 -1
  196. package/dist/shared/hx-time-picker-iwCD7rzW.js +1038 -0
  197. package/dist/shared/hx-time-picker-iwCD7rzW.js.map +1 -0
  198. package/dist/shared/{hx-toggle-button-Dcz9IlUm.js → hx-toggle-button-BQ81EDkl.js} +2 -2
  199. package/dist/shared/{hx-toggle-button-Dcz9IlUm.js.map → hx-toggle-button-BQ81EDkl.js.map} +1 -1
  200. package/dist/shared/hx-tree-item-CHrUhuZL.js +925 -0
  201. package/dist/shared/hx-tree-item-CHrUhuZL.js.map +1 -0
  202. package/dist/shared/menu-roving-DmMnzJhn.js +14 -0
  203. package/dist/shared/menu-roving-DmMnzJhn.js.map +1 -0
  204. package/dist/shared/menu-tree-BNM0SYYq.js +42 -0
  205. package/dist/shared/menu-tree-BNM0SYYq.js.map +1 -0
  206. package/dist/shared/{toast-factory-YSznocIV.js → toast-factory-CL2BzdSB.js} +128 -77
  207. package/dist/shared/toast-factory-CL2BzdSB.js.map +1 -0
  208. package/dist/utils/aria-idref.d.ts.map +1 -1
  209. package/dist/utils/menu-label.d.ts +18 -0
  210. package/dist/utils/menu-label.d.ts.map +1 -0
  211. package/dist/utils/menu-roving.d.ts +28 -0
  212. package/dist/utils/menu-roving.d.ts.map +1 -0
  213. package/dist/utils/menu-tree.d.ts +41 -0
  214. package/dist/utils/menu-tree.d.ts.map +1 -0
  215. package/dist/utils/tree-walk.d.ts +53 -0
  216. package/dist/utils/tree-walk.d.ts.map +1 -0
  217. package/figma-inventory.json +69 -20
  218. package/package.json +2 -2
  219. package/dist/shared/aria-idref-Q0yiSR3p.js +0 -104
  220. package/dist/shared/aria-idref-Q0yiSR3p.js.map +0 -1
  221. package/dist/shared/hx-alert-CLn7CstP.js.map +0 -1
  222. package/dist/shared/hx-badge-CQXgOXJM.js.map +0 -1
  223. package/dist/shared/hx-banner-D3DzpfcP.js.map +0 -1
  224. package/dist/shared/hx-checkbox-BdgoUeWi.js.map +0 -1
  225. package/dist/shared/hx-drawer-Y1Ui2IWJ.js.map +0 -1
  226. package/dist/shared/hx-dropdown-DJWlF94E.js +0 -316
  227. package/dist/shared/hx-dropdown-DJWlF94E.js.map +0 -1
  228. package/dist/shared/hx-icon-button-CGNdQSFM.js.map +0 -1
  229. package/dist/shared/hx-link-C-O6vq0Q.js.map +0 -1
  230. package/dist/shared/hx-list-MyEhh8c7.js.map +0 -1
  231. package/dist/shared/hx-menu-divider-C2omnPtj.js +0 -558
  232. package/dist/shared/hx-menu-divider-C2omnPtj.js.map +0 -1
  233. package/dist/shared/hx-meter-BPscsw5t.js.map +0 -1
  234. package/dist/shared/hx-overflow-menu-DCLsdIBy.js +0 -374
  235. package/dist/shared/hx-overflow-menu-DCLsdIBy.js.map +0 -1
  236. package/dist/shared/hx-progress-bar-Bn3JEPUf.js +0 -258
  237. package/dist/shared/hx-progress-bar-Bn3JEPUf.js.map +0 -1
  238. package/dist/shared/hx-select-DrcS-YRJ.js.map +0 -1
  239. package/dist/shared/hx-spinner-DL5AYr16.js.map +0 -1
  240. package/dist/shared/hx-split-button-Djnc5Aeg.js.map +0 -1
  241. package/dist/shared/hx-stat-WOcNV1Ry.js.map +0 -1
  242. package/dist/shared/hx-tab-panel-DspCrKqo.js.map +0 -1
  243. package/dist/shared/hx-tag-CNSmdyaK.js.map +0 -1
  244. package/dist/shared/hx-td-DnnEMIuA.js.map +0 -1
  245. package/dist/shared/hx-time-picker-BoEIZwzv.js +0 -688
  246. package/dist/shared/hx-time-picker-BoEIZwzv.js.map +0 -1
  247. package/dist/shared/hx-tree-item-C2CiWuDE.js +0 -703
  248. package/dist/shared/hx-tree-item-C2CiWuDE.js.map +0 -1
  249. package/dist/shared/toast-factory-YSznocIV.js.map +0 -1
@@ -1,9 +1,11 @@
1
- import { css as v, html as h, nothing as c } from "lit";
2
- import { property as i, state as p, customElement as u } from "lit/decorators.js";
1
+ import { css as v, html as d, nothing as u } from "lit";
2
+ import { property as h, state as _, customElement as m } from "lit/decorators.js";
3
3
  import { classMap as x } from "lit/directives/class-map.js";
4
- import { a as f } from "./forced-colors-CTEDFRGa.js";
5
- import { H as g } from "./helix-element-BNEYeiys.js";
6
- const _ = v`
4
+ import { a as b } from "./forced-colors-CTEDFRGa.js";
5
+ import { s as g, i as w, r as y } from "./aria-idref-CxvyzfQS.js";
6
+ import { f as z } from "./aria-flatten-DY6v2vah.js";
7
+ import { H as I } from "./helix-element-BNEYeiys.js";
8
+ const $ = v`
7
9
  :host {
8
10
  display: block;
9
11
  }
@@ -157,25 +159,52 @@ const _ = v`
157
159
  }
158
160
  }
159
161
  `;
160
- var m = Object.defineProperty, b = Object.getOwnPropertyDescriptor, l = (t, e, o, a) => {
161
- for (var r = a > 1 ? void 0 : a ? b(e, o) : e, n = t.length - 1, d; n >= 0; n--)
162
- (d = t[n]) && (r = (a ? d(e, o, r) : d(r)) || r);
163
- return a && r && m(e, o, r), r;
162
+ var S = Object.defineProperty, C = Object.getOwnPropertyDescriptor, n = (t, e, a, r) => {
163
+ for (var s = r > 1 ? void 0 : r ? C(e, a) : e, o = t.length - 1, l; o >= 0; o--)
164
+ (l = t[o]) && (s = (r ? l(e, a, s) : l(s)) || s);
165
+ return r && s && S(e, a, s), s;
164
166
  };
165
- let s = class extends g {
167
+ let i = class extends I {
166
168
  constructor() {
167
- super(...arguments), this.label = "", this.value = "", this.trend = "neutral", this.size = "md", this.labelTrend = "Trend", this._hasWarnedUnnamed = !1, this._hasIcon = !1;
169
+ super(...arguments), this.label = "", this.value = "", this.trend = "neutral", this.size = "md", this.labelTrend = "Trend", this._hasWarnedUnnamed = !1, this._supportsIdrefRefs = !0, this._ariaMirror = null, this._resolvedAccessibleName = "", this._hasIcon = !1;
168
170
  }
169
171
  // ─── Lifecycle ───
170
172
  connectedCallback() {
171
173
  super.connectedCallback();
172
174
  const t = this.getAttribute("size");
173
175
  t !== null && !this.hasAttribute("hx-size") && (this.size = t);
176
+ const e = this.constructor;
177
+ this._supportsIdrefRefs = e.__testSupportsIdrefRefsOverride !== null ? e.__testSupportsIdrefRefsOverride : g(this._internals), this._syncHostAriaSemantics(), this._ariaMirror = w(this, () => {
178
+ this._syncHostAriaSemantics();
179
+ });
180
+ }
181
+ disconnectedCallback() {
182
+ var t;
183
+ super.disconnectedCallback(), (t = this._ariaMirror) == null || t.disconnect(), this._ariaMirror = null;
174
184
  }
175
185
  updated(t) {
176
186
  super.updated(t);
177
- const e = t.has("value") || t.has("label"), o = this.value.trim().length > 0, a = this.label.trim().length > 0;
178
- e && !o && !a && !this._hasWarnedUnnamed && (this._hasWarnedUnnamed = !0), (o || a) && (this._hasWarnedUnnamed = !1);
187
+ const e = t.has("value") || t.has("label"), a = this.value.trim().length > 0, r = this.label.trim().length > 0;
188
+ e && !a && !r && !this._hasWarnedUnnamed && (this._hasWarnedUnnamed = !0), (a || r) && (this._hasWarnedUnnamed = !1), (t.has("value") || t.has("label") || t.has("trend") || t.has("labelTrend")) && this._syncHostAriaSemantics();
189
+ }
190
+ /**
191
+ * Mirror group semantics onto the host. The default group label is
192
+ * `${value}: ${label}` (matching the prior inner-div behaviour). Consumer
193
+ * `aria-label` / `aria-labelledby` on the host take precedence per AccName
194
+ * 1.2 §4.3.1.
195
+ * @internal
196
+ */
197
+ _syncHostAriaSemantics() {
198
+ var c;
199
+ const t = this._internals, e = this.value && this.label ? `${this.value}: ${this.label}` : this.value || this.label || "";
200
+ this._supportsIdrefRefs ? t.role = "group" : (t.role = null, t.ariaLabel = null);
201
+ const a = ((c = this.getAttribute("aria-label")) == null ? void 0 : c.trim()) || "", r = this.getAttribute("aria-labelledby"), s = y(this, r), o = s.length > 0;
202
+ if (this._supportsIdrefRefs) {
203
+ const f = t;
204
+ f.ariaLabelledByElements = o ? s : null;
205
+ }
206
+ let l = "";
207
+ o ? (l = s.map((p) => z(p)).filter(Boolean).join(" ") || a || e, this._supportsIdrefRefs && (t.ariaLabel = null)) : a ? (l = a, this._supportsIdrefRefs && (t.ariaLabel = a)) : e ? (l = e, this._supportsIdrefRefs && (t.ariaLabel = e)) : (l = "", this._supportsIdrefRefs && (t.ariaLabel = null)), this._resolvedAccessibleName !== l && (this._resolvedAccessibleName = l, this._supportsIdrefRefs || this.requestUpdate());
179
208
  }
180
209
  /** @internal */
181
210
  _onIconSlotChange(t) {
@@ -185,7 +214,7 @@ let s = class extends g {
185
214
  // ─── Render Helpers ───
186
215
  /** @internal */
187
216
  _renderTrendArrow(t) {
188
- return t === "up" ? h`
217
+ return t === "up" ? d`
189
218
  <svg
190
219
  class="stat__trend-arrow"
191
220
  aria-hidden="true"
@@ -201,7 +230,7 @@ let s = class extends g {
201
230
  stroke-linejoin="round"
202
231
  />
203
232
  </svg>
204
- ` : h`
233
+ ` : d`
205
234
  <svg
206
235
  class="stat__trend-arrow"
207
236
  aria-hidden="true"
@@ -224,23 +253,23 @@ let s = class extends g {
224
253
  const t = {
225
254
  stat: !0,
226
255
  [`stat--${this.size}`]: !0
227
- }, e = this.trend !== "neutral", o = this.value && this.label ? `${this.value}: ${this.label}` : this.value || this.label || c, a = [], r = this.label && this.value ? `${this.label}: ${this.value}` : this.value || this.label || "";
228
- r && a.push(r), e && a.push(`${this.labelTrend}: ${this.trend}`);
229
- const n = a.join(", ");
230
- return h`
256
+ }, e = this.trend !== "neutral", a = this.value && this.label ? `${this.value}: ${this.label}` : this.value || this.label || u, r = [], s = this.label && this.value ? `${this.label}: ${this.value}` : this.value || this.label || "";
257
+ s && r.push(s), e && r.push(`${this.labelTrend}: ${this.trend}`);
258
+ const o = r.join(", ");
259
+ return d`
231
260
  <div
232
261
  part="container"
233
262
  class=${x(t)}
234
263
  role="group"
235
- aria-label=${o}
264
+ aria-label=${a}
236
265
  >
237
- <span class="stat__live-region" aria-live="polite" aria-atomic="true">${n}</span>
266
+ <span class="stat__live-region" aria-live="polite" aria-atomic="true">${o}</span>
238
267
  <div part="header" class="stat__header">
239
268
  <span part="icon" class="stat__icon" ?hidden=${!this._hasIcon}>
240
269
  <slot name="icon" @slotchange=${this._onIconSlotChange}></slot>
241
270
  </span>
242
271
  <span part="value" class="stat__value" aria-hidden="true">${this.value}</span>
243
- ${e ? h`
272
+ ${e ? d`
244
273
  <span
245
274
  part="trend"
246
275
  class="stat__trend stat__trend--${this.trend}"
@@ -249,36 +278,37 @@ let s = class extends g {
249
278
  >
250
279
  ${this._renderTrendArrow(this.trend)}
251
280
  </span>
252
- ` : c}
281
+ ` : u}
253
282
  </div>
254
283
  <span part="label" class="stat__label" aria-hidden="true">${this.label}</span>
255
284
  </div>
256
285
  `;
257
286
  }
258
287
  };
259
- s.styles = [_, f];
260
- l([
261
- i({ type: String, reflect: !0 })
262
- ], s.prototype, "label", 2);
263
- l([
264
- i({ type: String, reflect: !0 })
265
- ], s.prototype, "value", 2);
266
- l([
267
- i({ type: String, reflect: !0 })
268
- ], s.prototype, "trend", 2);
269
- l([
270
- i({ type: String, reflect: !0, attribute: "hx-size" })
271
- ], s.prototype, "size", 2);
272
- l([
273
- i({ attribute: "label-trend" })
274
- ], s.prototype, "labelTrend", 2);
275
- l([
276
- p()
277
- ], s.prototype, "_hasIcon", 2);
278
- s = l([
279
- u("hx-stat")
280
- ], s);
288
+ i.styles = [$, b];
289
+ i.__testSupportsIdrefRefsOverride = null;
290
+ n([
291
+ h({ type: String, reflect: !0 })
292
+ ], i.prototype, "label", 2);
293
+ n([
294
+ h({ type: String, reflect: !0 })
295
+ ], i.prototype, "value", 2);
296
+ n([
297
+ h({ type: String, reflect: !0 })
298
+ ], i.prototype, "trend", 2);
299
+ n([
300
+ h({ type: String, reflect: !0, attribute: "hx-size" })
301
+ ], i.prototype, "size", 2);
302
+ n([
303
+ h({ attribute: "label-trend" })
304
+ ], i.prototype, "labelTrend", 2);
305
+ n([
306
+ _()
307
+ ], i.prototype, "_hasIcon", 2);
308
+ i = n([
309
+ m("hx-stat")
310
+ ], i);
281
311
  export {
282
- s as H
312
+ i as H
283
313
  };
284
- //# sourceMappingURL=hx-stat-WOcNV1Ry.js.map
314
+ //# sourceMappingURL=hx-stat-Dtf9lz-O.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hx-stat-Dtf9lz-O.js","sources":["../../src/components/hx-stat/hx-stat.styles.ts","../../src/components/hx-stat/hx-stat.ts"],"sourcesContent":["import { css } from 'lit';\n\nexport const helixStatStyles = css`\n :host {\n display: block;\n }\n\n .stat {\n display: flex;\n flex-direction: column;\n gap: var(--hx-stat-gap, var(--hx-space-1, 0.25rem));\n font-family: var(--hx-stat-font-family, var(--hx-font-family-sans, sans-serif));\n color: var(--hx-stat-color, var(--hx-color-text-strong, #202b39));\n }\n\n /* ─── Size Variants ─── */\n\n .stat--sm .stat__value {\n font-size: var(--hx-stat-value-font-size-sm, var(--hx-font-size-xl, 1.25rem));\n line-height: var(--hx-line-height-tight, 1.25);\n font-weight: var(--hx-stat-value-font-weight, var(--hx-font-weight-bold, 700));\n }\n\n .stat--sm .stat__label {\n font-size: var(--hx-stat-label-font-size-sm, var(--hx-font-size-xs, 0.75rem));\n }\n\n .stat--md .stat__value {\n font-size: var(--hx-stat-value-font-size-md, var(--hx-font-size-3xl, 1.875rem));\n line-height: var(--hx-line-height-tight, 1.25);\n font-weight: var(--hx-stat-value-font-weight, var(--hx-font-weight-bold, 700));\n }\n\n .stat--md .stat__label {\n font-size: var(--hx-stat-label-font-size-md, var(--hx-font-size-sm, 0.875rem));\n }\n\n .stat--lg .stat__value {\n font-size: var(--hx-stat-value-font-size-lg, var(--hx-font-size-5xl, 3rem));\n line-height: var(--hx-line-height-tight, 1.25);\n font-weight: var(--hx-stat-value-font-weight, var(--hx-font-weight-bold, 700));\n }\n\n .stat--lg .stat__label {\n font-size: var(--hx-stat-label-font-size-lg, var(--hx-font-size-md, 1rem));\n }\n\n /* ─── Value ─── */\n\n .stat__header {\n display: flex;\n align-items: center;\n gap: var(--hx-stat-header-gap, var(--hx-space-2, 0.5rem));\n }\n\n .stat__value {\n color: var(--hx-stat-value-color, var(--hx-color-text-primary, #0d1825));\n }\n\n /* ─── Label ─── */\n\n .stat__label {\n color: var(--hx-stat-label-color, var(--hx-color-text-muted, #4a5362));\n font-weight: var(--hx-font-weight-normal, 400);\n }\n\n /* ─── Icon Slot ─── */\n\n .stat__icon {\n display: flex;\n align-items: center;\n color: var(--hx-stat-icon-color, var(--hx-color-primary-500, #429797));\n flex-shrink: 0;\n }\n\n /* ─── Trend Indicator ─── */\n\n .stat__trend {\n display: inline-flex;\n align-items: center;\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-semibold, 600);\n border-radius: var(--hx-border-radius-sm, 0.25rem);\n padding: var(--hx-space-0-5, 0.125rem) var(--hx-space-1-5, 0.375rem);\n }\n\n .stat__trend--up {\n color: var(--hx-stat-trend-up-color, var(--hx-color-success-700, #146831));\n background-color: var(--hx-stat-trend-up-bg, var(--hx-color-success-50, #eafaec));\n }\n\n .stat__trend--down {\n color: var(--hx-stat-trend-down-color, var(--hx-color-error-700, #a21312));\n background-color: var(--hx-stat-trend-down-bg, var(--hx-color-error-50, #fff2f0));\n }\n\n .stat__trend-arrow {\n width: 0.75em;\n height: 0.75em;\n flex-shrink: 0;\n }\n\n /* ─── Hidden empty slot wrappers ─── */\n\n [hidden] {\n display: none !important;\n }\n\n /* ─── Visually-hidden live region ─── */\n\n .stat__live-region {\n position: absolute;\n width: 1px;\n height: 1px;\n overflow: hidden;\n clip: rect(0, 0, 0, 0);\n white-space: nowrap;\n }\n\n /* ─── Forced Colors (Windows High Contrast Mode) ─── */\n\n @media (forced-colors: active) {\n .stat__trend {\n forced-color-adjust: none;\n }\n\n .stat__value {\n color: CanvasText;\n }\n\n .stat__label {\n color: CanvasText;\n }\n\n .stat__icon {\n color: CanvasText;\n }\n\n .stat__trend--up {\n background: Highlight;\n color: HighlightText;\n border: 1px solid Highlight;\n }\n\n .stat__trend--down {\n background: ButtonText;\n color: ButtonFace;\n border: 1px solid ButtonText;\n }\n\n .stat__trend-arrow {\n color: currentColor;\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 { devWarn } from '../../utils/dev-warn.js';\nimport { HelixElement } from '../../base/index.js';\nimport { helixStatStyles } from './hx-stat.styles.js';\nimport { forcedColorsSurface } from '../../styles/forced-colors.js';\nimport {\n installAriaIdrefMirror,\n resolveIdrefTokens,\n supportsIdrefElementReferences,\n type AriaIdrefMirrorHandle,\n} from '../../utils/aria-idref.js';\nimport { flattenAccName } from '../../utils/aria-flatten.js';\n\nexport type StatSize = 'sm' | 'md' | 'lg';\nexport type StatTrend = 'up' | 'down' | 'neutral';\n\n/**\n * A static stat display component for presenting key metrics in a healthcare dashboard.\n *\n * Group 7 host-canonical: `role=\"group\"` lives on the **host** via\n * `_internals.role`. The host carries the resolved accessible name so AT\n * walks `<hx-stat>` (role=group, label=\"value: label\") directly. The\n * internal `aria-live=\"polite\"` announcer remains in the shadow tree —\n * `role=\"group\"` does NOT imply a live region, so the announcer is required\n * for value/label/trend update announcements.\n *\n * @summary Displays a labeled metric value with optional trend indicator and icon slot.\n *\n * @tag hx-stat\n *\n * @slot icon - Optional icon displayed alongside the stat value.\n *\n * @csspart container - The outer stat container element.\n * @csspart header - The row containing the value and optional icon.\n * @csspart value - The stat value element.\n * @csspart label - The stat label element.\n * @csspart trend - The trend indicator element (only rendered when trend is not 'neutral').\n * @csspart icon - The icon slot container.\n *\n * @cssprop [--hx-stat-gap=var(--hx-space-1)] - Gap between value and label.\n * @cssprop [--hx-stat-header-gap=var(--hx-space-2)] - Gap between icon and value in the header row.\n * @cssprop [--hx-stat-color=var(--hx-color-neutral-800)] - Default text color.\n * @cssprop [--hx-stat-value-color=var(--hx-color-neutral-900)] - Value text color.\n * @cssprop [--hx-stat-label-color=var(--hx-color-neutral-500)] - Label text color.\n * @cssprop [--hx-stat-icon-color=var(--hx-color-primary-500)] - Icon color.\n * @cssprop [--hx-stat-value-font-weight=var(--hx-font-weight-bold)] - Value font weight.\n * @cssprop [--hx-stat-font-family=var(--hx-font-family-sans)] - Font family.\n * @cssprop [--hx-stat-value-font-size-sm=var(--hx-font-size-xl)] - Value font size at sm.\n * @cssprop [--hx-stat-value-font-size-md=var(--hx-font-size-3xl)] - Value font size at md.\n * @cssprop [--hx-stat-value-font-size-lg=var(--hx-font-size-5xl)] - Value font size at lg.\n * @cssprop [--hx-stat-label-font-size-sm=var(--hx-font-size-xs)] - Label font size at sm.\n * @cssprop [--hx-stat-label-font-size-md=var(--hx-font-size-sm)] - Label font size at md.\n * @cssprop [--hx-stat-label-font-size-lg=var(--hx-font-size-md)] - Label font size at lg.\n * @cssprop [--hx-stat-trend-up-color=var(--hx-color-success-700)] - Trend up text color.\n * @cssprop [--hx-stat-trend-up-bg=var(--hx-color-success-50)] - Trend up background color.\n * @cssprop [--hx-stat-trend-down-color=var(--hx-color-error-700)] - Trend down text color.\n * @cssprop [--hx-stat-trend-down-bg=var(--hx-color-error-50)] - Trend down background color.\n * @cssprop [--hx-space-1] - Spacing token.\n * @cssprop [--hx-font-family-sans] - Font family.\n * @cssprop [--hx-color-neutral-800] - Color.\n * @cssprop [--hx-font-size-xl] - Font size.\n * @cssprop [--hx-line-height-tight] - Line height.\n * @cssprop [--hx-font-weight-bold] - Font weight.\n * @cssprop [--hx-font-size-xs] - Font size.\n * @cssprop [--hx-font-size-3xl] - Font size.\n * @cssprop [--hx-font-size-sm] - Font size.\n * @cssprop [--hx-font-size-5xl] - Font size.\n * @cssprop [--hx-font-size-md] - Font size.\n * @cssprop [--hx-space-2] - Spacing token.\n * @cssprop [--hx-color-neutral-900] - Color.\n * @cssprop [--hx-color-neutral-500] - Color.\n * @cssprop [--hx-font-weight-normal] - Font weight.\n * @cssprop [--hx-color-primary-500] - Color.\n * @cssprop [--hx-font-weight-semibold] - Font weight.\n * @cssprop [--hx-border-radius-sm] - CSS custom property.\n * @cssprop [--hx-space-0-5] - Spacing token.\n * @cssprop [--hx-space-1-5] - Spacing token.\n * @cssprop [--hx-color-success-700] - Color.\n * @cssprop [--hx-color-success-50] - Color.\n * @cssprop [--hx-color-error-700] - Color.\n * @cssprop [--hx-color-error-50] - Color.\n */\n@customElement('hx-stat')\nexport class HelixStat extends HelixElement {\n static override styles = [helixStatStyles, forcedColorsSurface];\n\n /**\n * Test seam (Group 7 host-canonical migration): see other Group 7 components.\n * Production code MUST NOT touch this field.\n * @internal\n */\n static __testSupportsIdrefRefsOverride: boolean | null = null;\n\n /**\n * The metric label displayed below the value.\n * @attr label\n */\n @property({ type: String, reflect: true })\n label = '';\n\n /**\n * The metric value displayed prominently.\n * @attr value\n */\n @property({ type: String, reflect: true })\n value = '';\n\n /**\n * Trend direction indicator. 'neutral' hides the indicator.\n * @attr trend\n */\n @property({ type: String, reflect: true })\n trend: 'up' | 'down' | 'neutral' = 'neutral';\n\n /**\n * Size variant controlling font size.\n * @attr hx-size\n */\n @property({ type: String, reflect: true, attribute: 'hx-size' })\n size: 'sm' | 'md' | 'lg' = 'md';\n\n /**\n * Prefix label for trend indicator. Override for i18n.\n * @attr label-trend\n */\n @property({ attribute: 'label-trend' }) labelTrend = 'Trend';\n\n /** @internal tracks whether the \"unnamed\" devWarn has already fired this lifecycle */\n private _hasWarnedUnnamed = false;\n\n // ─── Host-canonical ARIA bookkeeping ───\n\n /** @internal */\n private _supportsIdrefRefs = true;\n\n /** @internal */\n private _ariaMirror: AriaIdrefMirrorHandle | null = null;\n\n /** @internal */\n private _resolvedAccessibleName = '';\n\n // ─── Lifecycle ───\n\n override connectedCallback(): void {\n super.connectedCallback();\n // Backward compat: accept legacy `size` attribute. When present and `hx-size`\n // is not set, map the value and emit a deprecation warning.\n const legacySize = this.getAttribute('size');\n if (legacySize !== null && !this.hasAttribute('hx-size')) {\n devWarn('hx-stat', 'The \"size\" attribute is deprecated. Use \"hx-size\" instead.');\n this.size = legacySize as StatSize;\n }\n\n const ctor = this.constructor as typeof HelixStat;\n this._supportsIdrefRefs =\n ctor.__testSupportsIdrefRefsOverride !== null\n ? ctor.__testSupportsIdrefRefsOverride\n : supportsIdrefElementReferences(this._internals);\n this._syncHostAriaSemantics();\n this._ariaMirror = installAriaIdrefMirror(this, () => {\n this._syncHostAriaSemantics();\n });\n }\n\n override disconnectedCallback(): void {\n super.disconnectedCallback();\n this._ariaMirror?.disconnect();\n this._ariaMirror = null;\n }\n\n override updated(changedProperties: PropertyValues<this>): void {\n super.updated(changedProperties);\n const identityChanged = changedProperties.has('value') || changedProperties.has('label');\n const hasValue = this.value.trim().length > 0;\n const hasLabel = this.label.trim().length > 0;\n if (identityChanged && !hasValue && !hasLabel && !this._hasWarnedUnnamed) {\n this._hasWarnedUnnamed = true;\n devWarn(\n 'hx-stat',\n 'Rendering an unnamed hx-stat; provide at least value or label for screen reader accessibility.',\n );\n }\n if (hasValue || hasLabel) {\n this._hasWarnedUnnamed = false;\n }\n\n if (\n changedProperties.has('value') ||\n changedProperties.has('label') ||\n changedProperties.has('trend') ||\n changedProperties.has('labelTrend')\n ) {\n this._syncHostAriaSemantics();\n }\n }\n\n /**\n * Mirror group semantics onto the host. The default group label is\n * `${value}: ${label}` (matching the prior inner-div behaviour). Consumer\n * `aria-label` / `aria-labelledby` on the host take precedence per AccName\n * 1.2 §4.3.1.\n * @internal\n */\n private _syncHostAriaSemantics(): void {\n const internals = this._internals;\n const groupLabel =\n this.value && this.label ? `${this.value}: ${this.label}` : this.value || this.label || '';\n\n if (!this._supportsIdrefRefs) {\n internals.role = null;\n internals.ariaLabel = null;\n } else {\n internals.role = 'group';\n }\n\n const hostAriaLabel = this.getAttribute('aria-label')?.trim() || '';\n const consumerLabelledBy = this.getAttribute('aria-labelledby');\n const labelEls = resolveIdrefTokens(this, consumerLabelledBy);\n const hasEffectiveLabelledBy = labelEls.length > 0;\n\n type InternalsWithRefs = ElementInternals & {\n ariaLabelledByElements: Element[] | null;\n };\n\n if (this._supportsIdrefRefs) {\n const refsInternals = internals as InternalsWithRefs;\n refsInternals.ariaLabelledByElements = hasEffectiveLabelledBy ? labelEls : null;\n }\n\n let resolved = '';\n if (hasEffectiveLabelledBy) {\n const flattened =\n labelEls\n .map((el) => flattenAccName(el))\n .filter(Boolean)\n .join(' ') ||\n hostAriaLabel ||\n groupLabel;\n resolved = flattened;\n if (this._supportsIdrefRefs) {\n internals.ariaLabel = null;\n }\n } else if (hostAriaLabel) {\n resolved = hostAriaLabel;\n if (this._supportsIdrefRefs) {\n internals.ariaLabel = hostAriaLabel;\n }\n } else if (groupLabel) {\n resolved = groupLabel;\n if (this._supportsIdrefRefs) {\n internals.ariaLabel = groupLabel;\n }\n } else {\n resolved = '';\n if (this._supportsIdrefRefs) {\n internals.ariaLabel = null;\n }\n }\n\n if (this._resolvedAccessibleName !== resolved) {\n this._resolvedAccessibleName = resolved;\n if (!this._supportsIdrefRefs) {\n this.requestUpdate();\n }\n }\n }\n\n // ─── Slot Detection ───\n\n /** @internal */\n @state() private _hasIcon = false;\n\n /** @internal */\n private _onIconSlotChange(e: Event): void {\n const slot = e.target as HTMLSlotElement;\n this._hasIcon = slot.assignedNodes({ flatten: true }).length > 0;\n }\n\n // ─── Render Helpers ───\n\n /** @internal */\n private _renderTrendArrow(trend: 'up' | 'down'): ReturnType<typeof html> {\n if (trend === 'up') {\n return html`\n <svg\n class=\"stat__trend-arrow\"\n aria-hidden=\"true\"\n viewBox=\"0 0 12 12\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path\n d=\"M6 10V2M6 2L2 6M6 2L10 6\"\n stroke=\"currentColor\"\n stroke-width=\"1.5\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n />\n </svg>\n `;\n }\n return html`\n <svg\n class=\"stat__trend-arrow\"\n aria-hidden=\"true\"\n viewBox=\"0 0 12 12\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path\n d=\"M6 2V10M6 10L2 6M6 10L10 6\"\n stroke=\"currentColor\"\n stroke-width=\"1.5\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n />\n </svg>\n `;\n }\n\n // ─── Render ───\n\n override render() {\n const containerClasses = {\n stat: true,\n [`stat--${this.size}`]: true,\n };\n\n const hasTrend = this.trend !== 'neutral';\n\n // WCAG 1.3.1: wrap value and label in a group so screen readers announce them\n // together with a combined accessible name instead of as disconnected text runs.\n const groupLabel =\n this.value && this.label\n ? `${this.value}: ${this.label}`\n : this.value || this.label || nothing;\n\n // Live region text: announces value, label, and trend direction to screen\n // readers when any of those properties change programmatically.\n const liveParts: string[] = [];\n const primary =\n this.label && this.value ? `${this.label}: ${this.value}` : this.value || this.label || '';\n if (primary) liveParts.push(primary);\n if (hasTrend) liveParts.push(`${this.labelTrend}: ${this.trend}`);\n const liveText = liveParts.join(', ');\n\n // Dual-surface (Group 7 hx-progress-ring exemplar): inner div keeps\n // role=\"group\" + aria-label for legacy AT and consumer queries; host\n // adds the cross-shadow IDREF wiring via internals.* in\n // _syncHostAriaSemantics().\n return html`\n <div\n part=\"container\"\n class=${classMap(containerClasses)}\n role=\"group\"\n aria-label=${groupLabel}\n >\n <span class=\"stat__live-region\" aria-live=\"polite\" aria-atomic=\"true\">${liveText}</span>\n <div part=\"header\" class=\"stat__header\">\n <span part=\"icon\" class=\"stat__icon\" ?hidden=${!this._hasIcon}>\n <slot name=\"icon\" @slotchange=${this._onIconSlotChange}></slot>\n </span>\n <span part=\"value\" class=\"stat__value\" aria-hidden=\"true\">${this.value}</span>\n ${hasTrend\n ? html`\n <span\n part=\"trend\"\n class=\"stat__trend stat__trend--${this.trend}\"\n role=\"img\"\n aria-label=\"${this.labelTrend}: ${this.trend}\"\n >\n ${this._renderTrendArrow(this.trend as 'up' | 'down')}\n </span>\n `\n : nothing}\n </div>\n <span part=\"label\" class=\"stat__label\" aria-hidden=\"true\">${this.label}</span>\n </div>\n `;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'hx-stat': HelixStat;\n }\n}\n"],"names":["helixStatStyles","css","HelixStat","HelixElement","legacySize","ctor","supportsIdrefElementReferences","installAriaIdrefMirror","_a","changedProperties","identityChanged","hasValue","hasLabel","internals","groupLabel","hostAriaLabel","consumerLabelledBy","labelEls","resolveIdrefTokens","hasEffectiveLabelledBy","refsInternals","resolved","el","flattenAccName","e","slot","trend","html","containerClasses","hasTrend","nothing","liveParts","primary","liveText","classMap","forcedColorsSurface","__decorateClass","property","state","customElement"],"mappings":"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"}
@@ -4,7 +4,7 @@ import { classMap as A } from "lit/directives/class-map.js";
4
4
  import { ifDefined as m } from "lit/directives/if-defined.js";
5
5
  import { F as E } from "./FormMixin-B8PXk5RQ.js";
6
6
  import { b as L } from "./forced-colors-CTEDFRGa.js";
7
- import { s as D, i as $, r as y } from "./aria-idref-Q0yiSR3p.js";
7
+ import { s as D, i as $, r as y } from "./aria-idref-CxvyzfQS.js";
8
8
  import { H as B } from "./helix-element-BNEYeiys.js";
9
9
  import { c as H } from "./id-counter-DuX8vsui.js";
10
10
  const C = S`
@@ -537,4 +537,4 @@ r = s([
537
537
  export {
538
538
  r as H
539
539
  };
540
- //# sourceMappingURL=hx-switch-BX_8uNUs.js.map
540
+ //# sourceMappingURL=hx-switch-B6kr-EwE.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"hx-switch-BX_8uNUs.js","sources":["../../src/components/hx-switch/hx-switch.styles.ts","../../src/components/hx-switch/hx-switch.ts"],"sourcesContent":["import { css } from 'lit';\n\nexport const helixSwitchStyles = 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 /* --- Layout --- */\n\n .switch {\n display: flex;\n flex-direction: column;\n gap: var(--hx-space-1, 0.25rem);\n font-family: var(--hx-switch-font-family, var(--hx-font-family-sans, sans-serif));\n }\n\n /* WCAG 2.5.5 (healthcare mandate): minimum 44px touch target height.\n The track itself is smaller visually, but the row must meet the\n interactive touch target threshold for all size variants. */\n .switch__control-row {\n display: flex;\n align-items: center;\n gap: var(--hx-space-2, 0.5rem);\n min-height: var(--hx-touch-target-min, 2.75rem);\n }\n\n /* --- Track --- */\n\n .switch__track {\n position: relative;\n display: inline-flex;\n align-items: center;\n flex-shrink: 0;\n border: none;\n padding: 0;\n border-radius: var(--hx-border-radius-full, 9999px);\n background-color: var(--hx-switch-track-bg, var(--hx-color-border-strong, #66787b));\n cursor: pointer;\n transition: background-color var(--hx-transition-fast, 150ms ease);\n outline: none;\n -webkit-appearance: none;\n appearance: none;\n }\n\n /*\n * Host-focus path: on the modern (IDL element-references) render branch the\n * host is the tabbable surface (tabindex=0) and the inner track button is\n * demoted to tabindex=-1. Drive the focus ring from ':host(:focus-visible)'\n * so keyboard users still see a visible affordance. Codex round-11 P1.\n */\n :host(:focus-visible) .switch__track {\n outline: var(--hx-focus-ring-width, 2px) solid\n var(--hx-switch-focus-ring-color, var(--hx-focus-ring-color, #0f7078));\n outline-offset: var(--hx-focus-ring-offset, 2px);\n }\n\n /*\n * Fallback (no-IDL-ref) path: the host carries tabindex=-1 and the inner\n * track button is the tab target. Native :focus-visible drives the ring.\n */\n .switch__track:focus-visible {\n outline: var(--hx-focus-ring-width, 2px) solid\n var(--hx-switch-focus-ring-color, var(--hx-focus-ring-color, #0f7078));\n outline-offset: var(--hx-focus-ring-offset, 2px);\n }\n\n .switch--checked .switch__track {\n background-color: var(--hx-switch-track-checked-bg, var(--hx-color-primary-500, #429797));\n }\n\n .switch:not(.switch--checked) .switch__track:hover {\n background-color: var(--hx-switch-track-hover-bg, var(--hx-color-border-strong, #66787b));\n }\n\n .switch--checked .switch__track:hover {\n background-color: var(--hx-switch-track-checked-hover-bg, var(--hx-color-primary-600, #0f7078));\n }\n\n /* --- Thumb --- */\n\n .switch__thumb {\n position: absolute;\n border-radius: var(--hx-border-radius-full, 9999px);\n background-color: var(--hx-switch-thumb-bg, var(--hx-color-surface-default, #ffffff));\n box-shadow: var(--hx-switch-thumb-shadow, var(--hx-shadow-sm, 0 1px 2px 0 rgb(0 0 0 / 0.05)));\n transition: transform var(--hx-transition-fast, 150ms ease);\n }\n\n /* --- Size: sm (track 32x18, thumb 14px) --- */\n\n .switch--sm .switch__track {\n width: var(--hx-switch-track-width-sm, var(--hx-size-8, 2rem));\n height: var(--hx-switch-track-height-sm, var(--hx-size-4-5, 1.125rem));\n }\n\n .switch--sm .switch__thumb {\n width: var(--hx-switch-thumb-size-sm, var(--hx-size-3-5, 0.875rem));\n height: var(--hx-switch-thumb-size-sm, var(--hx-size-3-5, 0.875rem));\n top: 50%;\n left: var(--hx-switch-thumb-offset, var(--hx-space-0-5, 0.125rem));\n transform: translateY(-50%);\n }\n\n .switch--sm.switch--checked .switch__thumb {\n transform: translateY(-50%)\n translateX(var(--hx-switch-thumb-size-sm, var(--hx-size-3-5, 0.875rem)));\n }\n\n /* --- Size: md (track 40x22, thumb 18px) --- */\n\n .switch--md .switch__track {\n width: var(--hx-switch-track-width-md, var(--hx-size-10, 2.5rem));\n height: var(--hx-switch-track-height-md, var(--hx-size-5-5, 1.375rem));\n }\n\n .switch--md .switch__thumb {\n width: var(--hx-switch-thumb-size-md, var(--hx-size-4-5, 1.125rem));\n height: var(--hx-switch-thumb-size-md, var(--hx-size-4-5, 1.125rem));\n top: 50%;\n left: var(--hx-switch-thumb-offset, var(--hx-space-0-5, 0.125rem));\n transform: translateY(-50%);\n }\n\n .switch--md.switch--checked .switch__thumb {\n transform: translateY(-50%)\n translateX(var(--hx-switch-thumb-size-md, var(--hx-size-4-5, 1.125rem)));\n }\n\n /* --- Size: lg (track 48x26, thumb 22px) --- */\n\n .switch--lg .switch__track {\n width: var(--hx-switch-track-width-lg, var(--hx-size-12, 3rem));\n height: var(--hx-switch-track-height-lg, var(--hx-size-6-5, 1.625rem));\n }\n\n .switch--lg .switch__thumb {\n width: var(--hx-switch-thumb-size-lg, var(--hx-size-5-5, 1.375rem));\n height: var(--hx-switch-thumb-size-lg, var(--hx-size-5-5, 1.375rem));\n top: 50%;\n left: var(--hx-switch-thumb-offset, var(--hx-space-0-5, 0.125rem));\n transform: translateY(-50%);\n }\n\n .switch--lg.switch--checked .switch__thumb {\n transform: translateY(-50%)\n translateX(var(--hx-switch-thumb-size-lg, var(--hx-size-5-5, 1.375rem)));\n }\n\n /* --- Label --- */\n\n .switch__label {\n font-size: var(--hx-font-size-sm, 0.875rem);\n font-weight: var(--hx-font-weight-medium, 500);\n color: var(--hx-switch-label-color, var(--hx-color-text-strong, #202b39));\n line-height: var(--hx-line-height-normal, 1.5);\n cursor: pointer;\n user-select: none;\n -webkit-user-select: none;\n }\n\n .switch__required-marker {\n color: var(--hx-switch-error-color, var(--hx-color-error-text, #c92a2a));\n font-weight: var(--hx-font-weight-bold, 700);\n }\n\n /* --- Help Text & Error --- */\n\n .switch__help-text {\n font-size: var(--hx-font-size-xs, 0.75rem);\n color: var(--hx-switch-help-text-color, var(--hx-color-text-muted, #4a5362));\n line-height: var(--hx-line-height-normal, 1.5);\n }\n\n .switch__error {\n font-size: var(--hx-font-size-xs, 0.75rem);\n color: var(--hx-switch-error-color, var(--hx-color-error-text, #c92a2a));\n line-height: var(--hx-line-height-normal, 1.5);\n }\n\n /* --- Reduced Motion --- */\n\n @media (prefers-reduced-motion: reduce) {\n .switch__track,\n .switch__thumb {\n transition: none;\n }\n }\n\n /* ─── High Contrast Mode (forced-colors) ─── */\n\n @media (forced-colors: active) {\n .switch__track {\n forced-color-adjust: none;\n background-color: ButtonFace;\n border: 2px solid ButtonText;\n }\n\n :host(:focus-visible) .switch__track,\n .switch__track:focus-visible {\n outline: 3px solid Highlight;\n outline-offset: 2px;\n }\n\n .switch__thumb {\n background-color: ButtonText;\n box-shadow: none;\n }\n\n .switch--checked .switch__track {\n background-color: Highlight;\n border-color: Highlight;\n }\n\n .switch--checked .switch__thumb {\n background-color: HighlightText;\n }\n\n :host([disabled]) {\n opacity: 1;\n }\n\n :host([disabled]) .switch__track {\n border-color: GrayText;\n background-color: ButtonFace;\n }\n\n :host([disabled]) .switch__thumb {\n background-color: GrayText;\n }\n\n :host([disabled]) .switch__label {\n color: GrayText;\n }\n\n .switch__label {\n color: CanvasText;\n }\n\n .switch__help-text {\n color: GrayText;\n }\n\n .switch__error {\n color: LinkText;\n }\n }\n`;\n","import { html, nothing, type PropertyValues } from 'lit';\nimport '../../utilities/document-token-adoption.js';\nimport { customElement, property, query, state } from 'lit/decorators.js';\nimport { classMap } from 'lit/directives/class-map.js';\nimport { ifDefined } from 'lit/directives/if-defined.js';\nimport { HelixElement, createIdCounter } from '../../base/index.js';\nimport { FormMixin } from '../../mixins/FormMixin.js';\nimport { helixSwitchStyles } from './hx-switch.styles.js';\nimport { forcedColorsField } from '../../styles/forced-colors.js';\nimport {\n installAriaIdrefMirror,\n resolveIdrefTokens,\n supportsIdrefElementReferences,\n type AriaIdrefMirrorHandle,\n} from '../../utils/aria-idref.js';\n\nconst _nextSwitchId = createIdCounter('hx-switch');\n\n/** Detail for the hx-change event dispatched by hx-switch. */\nexport interface HxSwitchChangeDetail {\n checked: boolean;\n value: string;\n}\n\n/**\n * A toggle switch component for on/off states.\n *\n * Uses `role=\"switch\"` with `aria-checked` to convey toggle state.\n * Supports keyboard activation via Space key (per ARIA APG switch pattern).\n * Label association is handled through `aria-labelledby`, and\n * error/help text are linked via `aria-describedby`.\n *\n * @summary Form-associated toggle switch with label, error, and help text.\n *\n * @tag hx-switch\n *\n * @slot - Custom label content (overrides the label property).\n * @slot error - Custom error content (overrides the error property).\n * @slot help-text - Custom help text content (overrides the helpText property).\n *\n * @fires {CustomEvent<{checked: boolean, value: string}>} hx-change - Dispatched when the switch is toggled. Boolean-selection controls (`hx-switch`, `hx-checkbox`) include both `checked` (boolean state) and `value` (form value) in the detail; text-value controls (`hx-text-input`, `hx-combobox`, `hx-select`) emit only `{value}`.\n *\n * @csspart switch - The switch container (track + thumb wrapper).\n * @csspart track - The track background element.\n * @csspart thumb - The sliding thumb element.\n * @csspart label - The label text element.\n * @csspart help-text - The help text container.\n * @csspart error - The error message container.\n *\n * @cssprop [--hx-switch-track-bg=var(--hx-color-neutral-300)] - Track background color.\n * @cssprop [--hx-switch-track-checked-bg=var(--hx-color-primary-500)] - Track background when checked.\n * @cssprop [--hx-switch-thumb-bg=var(--hx-color-neutral-0)] - Thumb background color.\n * @cssprop [--hx-switch-thumb-shadow=var(--hx-shadow-sm)] - Thumb box shadow.\n * @cssprop [--hx-switch-focus-ring-color=var(--hx-focus-ring-color)] - Focus ring color.\n * @cssprop [--hx-switch-label-color=var(--hx-color-neutral-700)] - Label text color.\n * @cssprop [--hx-switch-error-color=var(--hx-color-error-500)] - Error message color.\n * @cssprop [--hx-switch-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-switch-font-family=var(--hx-font-family-sans)] - CSS custom property.\n * @cssprop [--hx-font-family-sans] - Font family.\n * @cssprop [--hx-space-2] - Spacing token.\n * @cssprop [--hx-touch-target-min] - Minimum touch target size.\n * @cssprop [--hx-border-radius-full] - CSS custom property.\n * @cssprop [--hx-color-neutral-300] - Color.\n * @cssprop [--hx-transition-fast] - Transition timing.\n * @cssprop [--hx-focus-ring-width] - Width.\n * @cssprop [--hx-focus-ring-color] - Color.\n * @cssprop [--hx-color-primary-400] - Color.\n * @cssprop [--hx-focus-ring-offset] - CSS custom property.\n * @cssprop [--hx-color-primary-500] - Color.\n * @cssprop [--hx-color-neutral-0] - Color.\n * @cssprop [--hx-shadow-sm] - Box shadow.\n * @cssprop [--hx-switch-track-width-sm=var(--hx-size-8)] - Width.\n * @cssprop [--hx-size-8] - Size token.\n * @cssprop [--hx-switch-track-height-sm=var(--hx-size-4-5)] - Height.\n * @cssprop [--hx-size-4-5] - Size token.\n * @cssprop [--hx-switch-thumb-size-sm=var(--hx-size-3-5)] - CSS custom property.\n * @cssprop [--hx-size-3-5] - Size token.\n * @cssprop [--hx-switch-thumb-offset=var(--hx-space-0-5)] - CSS custom property.\n * @cssprop [--hx-space-0-5] - Spacing token.\n * @cssprop [--hx-switch-track-width-md=var(--hx-size-10)] - Width.\n * @cssprop [--hx-size-10] - Size token.\n * @cssprop [--hx-switch-track-height-md=var(--hx-size-5-5)] - Height.\n * @cssprop [--hx-size-5-5] - Size token.\n * @cssprop [--hx-switch-thumb-size-md=var(--hx-size-4-5)] - CSS custom property.\n * @cssprop [--hx-switch-track-width-lg=var(--hx-size-12)] - Width.\n * @cssprop [--hx-size-12] - Size token.\n * @cssprop [--hx-switch-track-height-lg=var(--hx-size-6-5)] - Height.\n * @cssprop [--hx-size-6-5] - Size token.\n * @cssprop [--hx-switch-thumb-size-lg=var(--hx-size-5-5)] - CSS custom property.\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-color-neutral-500] - Color.\n */\n@customElement('hx-switch')\nexport class HelixSwitch extends FormMixin(HelixElement) {\n static override styles = [helixSwitchStyles, forcedColorsField];\n\n // ─── Form Association ───\n\n /** @internal */\n static override formAssociated = true;\n\n // ─── Properties ───\n\n /**\n * Whether the switch is toggled on.\n * @attr checked\n */\n @property({ type: Boolean, reflect: true })\n checked = false;\n\n /**\n * Whether the switch is disabled.\n * @attr disabled\n */\n @property({ type: Boolean, reflect: true })\n disabled = false;\n\n /**\n * Whether the switch is required for form submission.\n * @attr required\n */\n @property({ type: Boolean, reflect: true })\n required = false;\n\n /**\n * The name of the switch, used for form submission.\n * @attr name\n */\n @property({ type: String, reflect: true })\n name = '';\n\n /**\n * The value submitted when the switch is checked.\n * @attr value\n */\n @property({ type: String, reflect: true })\n value = 'on';\n\n /**\n * The visible label text for the switch.\n * @attr label\n */\n @property({ type: String })\n label = '';\n\n /**\n * Size variant of the switch.\n * @attr hx-size\n */\n @property({ type: String, reflect: true, attribute: 'hx-size' })\n size: 'sm' | 'md' | 'lg' = 'md';\n\n /**\n * Error message to display. When set, the switch enters an error state.\n * @attr error\n */\n @property({ type: String })\n error = '';\n\n /**\n * Help text displayed below the switch for guidance.\n * @attr help-text\n */\n @property({ type: String, attribute: 'help-text' })\n helpText = '';\n\n /**\n * Validation message shown when the field is required but empty.\n * @attr required-message\n */\n @property({ attribute: 'required-message' })\n requiredMessage = 'This field is required.';\n\n /**\n * Handle for the shared IDREF observer. Installed in `connectedCallback()`\n * so late-mutated `aria-labelledby`/`aria-describedby` and late-inserted\n * IDREF targets are picked up. See `installAriaIdrefMirror()`.\n * @internal\n */\n private _ariaMirror: AriaIdrefMirrorHandle | null = null;\n\n /**\n * No-IDL-ref fallback tokens applied to the inner button so consumer\n * labelling resolves through the shadow root. Tracked as reactive state\n * so values flow through the next `render()`.\n * @internal\n */\n @state() private _fallbackAriaLabelledBy: string | null = null;\n /** @internal */\n @state() private _fallbackAriaDescribedBy: string | null = null;\n /** @internal */\n @state() private _fallbackAriaLabel: string | null = null;\n\n /**\n * Whether the platform supports IDL element references on `ElementInternals`.\n * Drives the render-time branch between the modern path (host is the\n * announced surface, inner button is `aria-hidden + tabindex=-1`) and the\n * fallback path (inner button is the announced surface, host is demoted).\n * Codex round-2 finding #2.\n * @internal\n */\n @state() private _supportsIdrefRefs = true;\n\n /**\n * Tracks whether the host's `tabindex` is managed by the component itself\n * (vs. set explicitly by a consumer). Codex round-14 P2: a consumer-supplied\n * `tabindex` (e.g. roving-tabindex toolbar pattern with `tabindex=\"-1\"`)\n * must survive disabled flips and re-renders. Only re-assert tabindex in\n * `updated()` when the component originally claimed it.\n * @internal\n */\n private _internalTabindexManaged = false;\n\n // ─── Lifecycle ───\n\n override connectedCallback(): void {\n super.connectedCallback();\n // Detect platform support for IDL element references. Codex round-2\n // finding #2: drives the render-time branch.\n this._supportsIdrefRefs = supportsIdrefElementReferences(this._internals);\n // Seed root-independent semantics so the host announces the switch role\n // immediately on connect — before the first paint.\n this._syncHostAriaSemantics();\n // Codex round-1 finding #1: host is the canonical announced surface on\n // modern browsers, so the inner `<button role=switch>` is demoted via\n // `aria-hidden + tabindex=-1`.\n // Codex round-2 finding #2: on no-IDL-ref browsers the inner button is\n // the announced surface (it carries native button semantics + ARIA\n // role/state), so the host is demoted to `tabindex=-1`.\n // Codex round-14 P2: only claim ownership of `tabindex` when no consumer\n // value is present. Consumers using roving-tabindex toolbar patterns\n // must be able to set `tabindex=\"-1\"` on the host without it being\n // clobbered on every disabled flip. Note we still claim ownership when\n // disabled — the initial value is `-1` to keep the host out of tab order\n // and `updated()` re-asserts the appropriate value when disabled flips.\n if (!this.hasAttribute('tabindex')) {\n this._internalTabindexManaged = true;\n const enabledTabIndex = this._supportsIdrefRefs ? '0' : '-1';\n this.setAttribute('tabindex', this.disabled ? '-1' : enabledTabIndex);\n }\n this.addEventListener('keydown', this._handleHostKeyDown);\n this.addEventListener('click', this._handleHostClick);\n this._ariaMirror = installAriaIdrefMirror(this, () => {\n this._syncHostAriaSemantics();\n });\n }\n\n override disconnectedCallback(): void {\n super.disconnectedCallback();\n this.removeEventListener('keydown', this._handleHostKeyDown);\n this.removeEventListener('click', this._handleHostClick);\n this._ariaMirror?.disconnect();\n this._ariaMirror = null;\n }\n\n /**\n * Host-level keydown handler. Active only on the modern path; on the\n * no-IDL-ref fallback the inner `<button>` owns native activation.\n * Codex round-2 finding #2.\n * @internal\n */\n private _handleHostKeyDown = (e: KeyboardEvent): void => {\n if (this.disabled) return;\n if (!this._supportsIdrefRefs) return;\n if (e.target !== this) return;\n if (e.key === ' ' || e.key === 'Enter') {\n e.preventDefault();\n this._toggle();\n }\n };\n\n /**\n * Host-level click handler. Active only on the modern path; on the\n * fallback path AT activation flows directly to the inner button.\n * Codex round-2 finding #2.\n * @internal\n */\n private _handleHostClick = (e: MouseEvent): void => {\n if (this.disabled) return;\n if (!this._supportsIdrefRefs) return;\n const path = e.composedPath();\n if (path[0] !== this) return;\n this._toggle();\n };\n\n override updated(changedProperties: PropertyValues<this>): void {\n super.updated(changedProperties);\n if (changedProperties.has('checked') || changedProperties.has('value')) {\n this._internals.setFormValue(this.checked ? this.value : null);\n }\n if (\n changedProperties.has('disabled') ||\n (changedProperties as Map<PropertyKey, unknown>).has('_supportsIdrefRefs')\n ) {\n // Codex round-2 finding #2: keep host tabindex aligned with the chosen\n // announced surface. On no-IDL-ref browsers the inner button owns tab\n // order, so re-enabling the host should leave it `tabindex=-1`.\n // Codex round-14 P2: only re-assert when the component owns tabindex.\n // Consumer-managed values (e.g. roving-tabindex toolbar with `-1`) must\n // not be overwritten on disabled flips or supports-flag transitions.\n if (this._internalTabindexManaged) {\n const enabledTabIndex = this._supportsIdrefRefs ? '0' : '-1';\n this.setAttribute('tabindex', this.disabled ? '-1' : enabledTabIndex);\n }\n }\n // Re-resolve element references against the (possibly mutated) shadow\n // tree. `_syncHostAriaSemantics()` is also invoked from `_updateValidity()`\n // and by the IDREF mirror observer.\n this._syncHostAriaSemantics();\n }\n\n /**\n * Mirrors switch semantics onto the host via ElementInternals so that\n * consumer-supplied `aria-label`, `aria-labelledby`, and `aria-describedby`\n * on `<hx-switch>` reach the announced control. The codex aria-group-2\n * finding identified that the inner shadow `<button role=switch>` was the\n * only carrier of switch semantics, leaving host-level IDREF tokens stranded\n * on the wrong side of the shadow boundary.\n * @internal\n */\n private _syncHostAriaSemantics(): void {\n const internals = this._internals;\n const hostAriaLabel = this.getAttribute('aria-label')?.trim() || '';\n const externalLabelTokens = this.getAttribute('aria-labelledby');\n const externalDescTokens = this.getAttribute('aria-describedby');\n const labelEls = resolveIdrefTokens(this, externalLabelTokens);\n // Codex round-35 finding (CR major + codex follow-up): `aria-labelledby`\n // is only \"effective\" when at least one IDREF resolves to an element. A\n // typo or transiently-missing target must NOT erase the visible label —\n // fall back to `label` / slot so a labeled switch never becomes unnamed\n // on either render path.\n const hasEffectiveLabelledBy = labelEls.length > 0;\n\n // Codex round-2 finding #2: branch on platform support. Modern path —\n // host is the announced surface and carries `role=switch` + state via\n // ElementInternals. Fallback path — inner `<button role=switch>` is the\n // announced surface; clear host role/state so AT does not double-announce.\n if (this._supportsIdrefRefs) {\n // ─── Modern path ───\n internals.role = 'switch';\n internals.ariaChecked = this.checked ? 'true' : 'false';\n internals.ariaRequired = this.required ? 'true' : 'false';\n internals.ariaInvalid = !internals.validity.valid ? 'true' : 'false';\n internals.ariaDisabled = this.disabled ? 'true' : 'false';\n\n if (hostAriaLabel) {\n internals.ariaLabel = hostAriaLabel;\n } else if (!hasEffectiveLabelledBy) {\n internals.ariaLabel = this.label || null;\n } else {\n internals.ariaLabel = null;\n }\n\n type InternalsWithRefs = ElementInternals & {\n ariaLabelledByElements: Element[] | null;\n ariaDescribedByElements: Element[] | null;\n };\n const refsInternals = internals as InternalsWithRefs;\n\n const internalLabel = this.shadowRoot?.getElementById(this._labelId);\n const hasLabel = !!this.label || this._hasDefaultSlot;\n if (labelEls.length === 0 && !hostAriaLabel && hasLabel && internalLabel) {\n labelEls.push(internalLabel);\n }\n refsInternals.ariaLabelledByElements = labelEls.length > 0 ? labelEls : null;\n\n const descEls = resolveIdrefTokens(this, externalDescTokens);\n const helpEl = this.shadowRoot?.getElementById(this._helpTextId);\n const errorEl = this.shadowRoot?.getElementById(this._errorId);\n const hasError = !!(this.error || this._hasErrorSlot);\n // Codex round-15 P2: drop help text from the describedby chain while\n // an error is active. The render path hides the help wrapper in that\n // state (`?hidden=${... || hasError}`); appending the hidden node here\n // would have AT announce stale guidance ahead of the validation error.\n if (helpEl && !hasError && (this.helpText || this._hasHelpTextSlot)) {\n descEls.push(helpEl);\n }\n if (errorEl && hasError) {\n descEls.push(errorEl);\n }\n refsInternals.ariaDescribedByElements = descEls.length > 0 ? descEls : null;\n // Clear fallback state when IDL refs are available.\n this._fallbackAriaLabelledBy = null;\n this._fallbackAriaDescribedBy = null;\n this._fallbackAriaLabel = null;\n } else {\n // ─── Fallback path: inner button is the announced surface ───\n // Round-2 finding #2: round-1 set host role/state via internals AND\n // mirrored aria-* onto the `aria-hidden` inner button — making the\n // mirrored attributes inert. The fix is to clear host role/state on\n // internals so AT does not double-announce, and let the inner button\n // (rendered without aria-hidden, with `tabindex=0`, with role=switch\n // and aria-checked) be the announced surface.\n internals.role = null;\n internals.ariaChecked = null;\n internals.ariaRequired = null;\n internals.ariaInvalid = null;\n internals.ariaDisabled = null;\n internals.ariaLabel = null;\n\n // Round-35 codex follow-up: only mirror the consumer's labelledby tokens\n // when at least one resolves; otherwise the inner button must fall back\n // to `aria-label` (label property or slot) so the switch keeps a name\n // when an IDREF is a typo. Same contract as the modern path.\n this._fallbackAriaLabelledBy = hasEffectiveLabelledBy ? externalLabelTokens : null;\n this._fallbackAriaDescribedBy = externalDescTokens || null;\n this._fallbackAriaLabel = hasEffectiveLabelledBy ? null : hostAriaLabel || this.label || null;\n }\n }\n\n // ─── Form Integration ───\n\n /** Recalculates and sets the validity state based on required and checked. */\n /** @internal */\n override _updateValidity(): void {\n if (this.required && !this.checked) {\n // Codex round-17 P2: anchor validity UI to the announced surface. On\n // the modern path the host carries `role=switch` via internals and is\n // the canonical focus target (the inner track button is `aria-hidden +\n // tabindex=-1`), so reportValidity() would otherwise focus a hidden\n // node. On the fallback path the inner button is the announced\n // surface.\n const anchor: HTMLElement | undefined = this._supportsIdrefRefs\n ? this\n : (this._trackEl ?? undefined);\n this._internals.setValidity(\n { valueMissing: true },\n this.error || this.requiredMessage,\n anchor,\n );\n } else {\n this._internals.setValidity({});\n }\n // Codex round-1 finding #6: sync host ARIA semantics immediately after\n // every `setValidity()` call so `internals.ariaInvalid` reflects the\n // current `ValidityState` rather than the previous render snapshot.\n this._syncHostAriaSemantics();\n }\n\n protected override _onFormReset(): void {\n this.checked = false;\n this._internals.setFormValue(null);\n this._resetInteractionState();\n }\n\n protected override _onFormStateRestore(\n state: File | string | FormData | null,\n _mode: 'restore' | 'autocomplete',\n ): void {\n if (typeof state === 'string') {\n this.checked = state === this.value;\n }\n }\n\n protected override _onFormDisabled(disabled: boolean): void {\n this.disabled = disabled;\n }\n\n /** Reference to the native button element acting as the switch track. * @internal\n */\n @query('.switch__track')\n private _trackEl: HTMLButtonElement | null | undefined;\n\n /** Whether the error slot has assigned content. */\n /** @internal */\n @state() private _hasErrorSlot = false;\n\n /** Whether the default slot has assigned content (slotted label). */\n /** @internal */\n @state() private _hasDefaultSlot = false;\n\n /** Whether the help-text slot has assigned content. */\n /** @internal */\n @state() private _hasHelpTextSlot = false;\n\n // ─── Slot Handlers ───\n\n /** Updates _hasErrorSlot when error slot content changes. */\n /** @internal */\n private _handleErrorSlotChange(e: Event): void {\n const slot = e.target as HTMLSlotElement;\n this._hasErrorSlot = slot.assignedNodes({ flatten: true }).length > 0;\n }\n\n /** Updates _hasDefaultSlot when default slot content changes. */\n /** @internal */\n private _handleDefaultSlotChange(e: Event): void {\n const slot = e.target as HTMLSlotElement;\n this._hasDefaultSlot = slot.assignedNodes({ flatten: true }).length > 0;\n }\n\n /** Updates _hasHelpTextSlot when help-text slot content changes. */\n /** @internal */\n private _handleHelpTextSlotChange(e: Event): void {\n const slot = e.target as HTMLSlotElement;\n this._hasHelpTextSlot = slot.assignedNodes({ flatten: true }).length > 0;\n }\n\n // ─── Event Handling ───\n\n /** Toggles checked state and dispatches hx-change event. */\n /** @internal */\n private _toggle(): void {\n if (this.disabled) return;\n this.checked = !this.checked;\n this._handleInteractionInput();\n\n this.dispatchEvent(\n new CustomEvent<{ checked: boolean; value: string }>('hx-change', {\n bubbles: true,\n composed: true,\n detail: { checked: this.checked, value: this.value },\n }),\n );\n }\n\n /** Handles click events on the track. */\n /** @internal */\n private _handleClick(): void {\n this._toggle();\n // Codex round-12 P2: on the modern path the host owns role=\"switch\" and\n // tabindex=0; the inner <button tabindex=\"-1\"> is aria-hidden. Native\n // click activation on a `<button>` still focuses it, which would leave\n // `document.activeElement` and AT focus on a hidden node. Move focus back\n // to the host so the announced surface is also the focus target.\n if (this._supportsIdrefRefs) {\n this.focus();\n }\n }\n\n /** Handles keydown events — Space toggles the switch per ARIA APG. */\n /** @internal */\n private _handleKeyDown(e: KeyboardEvent): void {\n if (e.key === ' ') {\n e.preventDefault();\n this._toggle();\n }\n }\n\n // ─── Public Methods ───\n\n /**\n * Moves focus to the announced switch surface. Codex round-1 finding #1\n * relocated the focus target to the host so AT announces a single widget;\n * the host carries the canonical role/state on modern engines. Round-7\n * finding #7 extends that contract to the no-IDL-ref fallback: when the\n * host is demoted (`tabindex=-1`, role/state cleared on `internals`) the\n * inner `<button role=switch>` owns the announced semantics and tab order,\n * so programmatic `focus()` must redirect there — otherwise scripted focus\n * and error recovery land on the demoted host on unsupported engines.\n */\n override focus(options?: FocusOptions): void {\n if (this._supportsIdrefRefs) {\n super.focus(options);\n return;\n }\n this._trackEl?.focus(options);\n }\n\n // ─── Render ───\n\n /** Unique ID for this switch instance, used for ARIA associations. */\n /** @internal */\n private _switchId = _nextSwitchId();\n /** ID for the label element, referenced by aria-labelledby. */\n /** @internal */\n private _labelId = `${this._switchId}-label`;\n /** ID for the help text element, referenced by aria-describedby. */\n /** @internal */\n private _helpTextId = `${this._switchId}-help`;\n /** ID for the error element, referenced by aria-describedby. */\n /** @internal */\n private _errorId = `${this._switchId}-error`;\n\n override render() {\n const hasError = !!this.error || this._hasErrorSlot;\n const hasHelpText = !!this.helpText || this._hasHelpTextSlot;\n const hasLabel = !!this.label || this._hasDefaultSlot;\n // Validity-driven invalid state: a required-but-unchecked switch is\n // invalid via setValidity() even before any visible error renders.\n const isInvalid = hasError || (this.required && !this.checked);\n\n const containerClasses = {\n switch: true,\n 'switch--checked': this.checked,\n 'switch--disabled': this.disabled,\n 'switch--required': this.required,\n 'switch--error': hasError,\n [`switch--${this.size}`]: true,\n };\n\n // help-text first, error appended — assistive tech announces guidance\n // before validation feedback. Both ids are persistent in the shadow tree.\n // Codex round-15 P2: drop help text from the chain when an error is\n // active. The help wrapper renders hidden in that state, so referencing\n // it would have AT announce stale guidance ahead of the validation\n // error. Mirrors the modern-path host-internals chain.\n const describedBy =\n [!hasError && hasHelpText ? this._helpTextId : null, hasError ? this._errorId : null]\n .filter(Boolean)\n .join(' ') || undefined;\n\n // Codex round-1 finding #8: merge consumer fallback tokens with the\n // shadow-internal describedBy chain on browsers without IDL element\n // references. Internal `_labelId` is preferred when no consumer\n // labelledby tokens are supplied.\n const innerDescribedBy =\n [describedBy ?? null, this._fallbackAriaDescribedBy].filter(Boolean).join(' ') || undefined;\n // Codex round-14 P2: per ARIA spec, `aria-labelledby` overrides\n // `aria-label`. On the no-IDL-ref fallback path the consumer-set\n // `aria-label` was being shadowed because we always assigned the\n // internal `_labelId`. When the consumer supplied an `aria-label` (and\n // did NOT supply an `aria-labelledby`), omit the internal labelledby so\n // AT announces the consumer-supplied name — matching the modern path\n // and the spec. Consumer-supplied `aria-labelledby` (mirrored into\n // `_fallbackAriaLabelledBy`) still wins over the internal label.\n const innerAriaLabel = this._fallbackAriaLabel ?? undefined;\n const innerLabelledBy = this._fallbackAriaLabelledBy\n ? this._fallbackAriaLabelledBy\n : innerAriaLabel\n ? undefined\n : hasLabel\n ? this._labelId\n : undefined;\n\n // Codex round-2 finding #2: branch the inner button on platform support.\n // Modern path — host is announced, inner button is `aria-hidden + tabindex=-1`.\n // Fallback path — inner button is announced (NO aria-hidden, role=switch,\n // tabindex=0) so consumer-mirrored aria-* attributes resolve through a\n // visible accessibility-tree node and AT can name + activate it natively.\n const innerIsAnnounced = !this._supportsIdrefRefs;\n const innerTabIndex = innerIsAnnounced && !this.disabled ? '0' : '-1';\n // On the fallback path the inner button must carry role=switch so AT\n // announces \"switch\", aria-checked for state, and aria-required when set.\n const innerRole = innerIsAnnounced ? 'switch' : nothing;\n\n return html`\n <div part=\"switch\" class=${classMap(containerClasses)}>\n <div class=\"switch__control-row\">\n <button\n part=\"track\"\n class=\"switch__track\"\n id=${this._switchId}\n type=\"button\"\n role=${innerRole}\n tabindex=${innerTabIndex}\n aria-checked=${this.checked ? 'true' : 'false'}\n aria-labelledby=${ifDefined(innerLabelledBy)}\n aria-describedby=${ifDefined(innerDescribedBy)}\n aria-label=${ifDefined(innerAriaLabel)}\n aria-invalid=${isInvalid ? 'true' : nothing}\n aria-required=${this.required ? 'true' : nothing}\n aria-hidden=${innerIsAnnounced ? nothing : 'true'}\n ?disabled=${this.disabled}\n @click=${this._handleClick}\n @keydown=${this._handleKeyDown}\n >\n <span part=\"thumb\" class=\"switch__thumb\"></span>\n </button>\n\n <label part=\"label\" class=\"switch__label\" id=${this._labelId} for=${this._switchId}>\n <slot @slotchange=${this._handleDefaultSlotChange}>${this.label}</slot>${this.required\n ? html`<span class=\"switch__required-marker\" aria-hidden=\"true\">*</span>`\n : nothing}\n </label>\n </div>\n\n <!--\n Persistent error live region. Slot fallback content provides the\n property-driven message; consumers can replace it via slot=\"error\".\n The wrapper carries a stable id so aria-describedby remains valid\n across both code paths and across show/hide transitions.\n -->\n <div\n part=\"error\"\n class=\"switch__error\"\n id=${this._errorId}\n role=\"alert\"\n ?hidden=${!hasError}\n >\n <slot name=\"error\" @slotchange=${this._handleErrorSlotChange}>${this.error}</slot>\n </div>\n\n <!--\n Persistent help-text wrapper. Rendered whenever the property OR the\n slot has content; hidden when an error is present so guidance does\n not compete with validation feedback.\n -->\n <div\n part=\"help-text\"\n class=\"switch__help-text\"\n id=${this._helpTextId}\n ?hidden=${!hasHelpText || hasError}\n >\n <slot name=\"help-text\" @slotchange=${this._handleHelpTextSlotChange}\n >${this.helpText}</slot\n >\n </div>\n </div>\n `;\n }\n}\n\n/**\n * Per-component event map for type-safe addEventListener on hx-switch.\n * The `hx-change` detail always includes both `checked` and `value` for this component.\n */\nexport interface HxSwitchEventMap {\n 'hx-change': CustomEvent<{ checked: boolean; value: string }>;\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'hx-switch': HelixSwitch;\n }\n}\n\nexport type HxSwitch = HelixSwitch;\n"],"names":["helixSwitchStyles","css","_nextSwitchId","createIdCounter","HelixSwitch","FormMixin","HelixElement","supportsIdrefElementReferences","enabledTabIndex","installAriaIdrefMirror","_a","changedProperties","internals","hostAriaLabel","externalLabelTokens","externalDescTokens","labelEls","resolveIdrefTokens","hasEffectiveLabelledBy","refsInternals","internalLabel","_b","hasLabel","descEls","helpEl","_c","errorEl","_d","hasError","anchor","state","_mode","disabled","slot","options","hasHelpText","isInvalid","containerClasses","innerDescribedBy","innerAriaLabel","innerLabelledBy","innerIsAnnounced","innerTabIndex","innerRole","nothing","html","classMap","ifDefined","forcedColorsField","__decorateClass","property","query","customElement"],"mappings":";;;;;;;;;AAEO,MAAMA,IAAoBC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAA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"}
1
+ {"version":3,"file":"hx-switch-B6kr-EwE.js","sources":["../../src/components/hx-switch/hx-switch.styles.ts","../../src/components/hx-switch/hx-switch.ts"],"sourcesContent":["import { css } from 'lit';\n\nexport const helixSwitchStyles = 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 /* --- Layout --- */\n\n .switch {\n display: flex;\n flex-direction: column;\n gap: var(--hx-space-1, 0.25rem);\n font-family: var(--hx-switch-font-family, var(--hx-font-family-sans, sans-serif));\n }\n\n /* WCAG 2.5.5 (healthcare mandate): minimum 44px touch target height.\n The track itself is smaller visually, but the row must meet the\n interactive touch target threshold for all size variants. */\n .switch__control-row {\n display: flex;\n align-items: center;\n gap: var(--hx-space-2, 0.5rem);\n min-height: var(--hx-touch-target-min, 2.75rem);\n }\n\n /* --- Track --- */\n\n .switch__track {\n position: relative;\n display: inline-flex;\n align-items: center;\n flex-shrink: 0;\n border: none;\n padding: 0;\n border-radius: var(--hx-border-radius-full, 9999px);\n background-color: var(--hx-switch-track-bg, var(--hx-color-border-strong, #66787b));\n cursor: pointer;\n transition: background-color var(--hx-transition-fast, 150ms ease);\n outline: none;\n -webkit-appearance: none;\n appearance: none;\n }\n\n /*\n * Host-focus path: on the modern (IDL element-references) render branch the\n * host is the tabbable surface (tabindex=0) and the inner track button is\n * demoted to tabindex=-1. Drive the focus ring from ':host(:focus-visible)'\n * so keyboard users still see a visible affordance. Codex round-11 P1.\n */\n :host(:focus-visible) .switch__track {\n outline: var(--hx-focus-ring-width, 2px) solid\n var(--hx-switch-focus-ring-color, var(--hx-focus-ring-color, #0f7078));\n outline-offset: var(--hx-focus-ring-offset, 2px);\n }\n\n /*\n * Fallback (no-IDL-ref) path: the host carries tabindex=-1 and the inner\n * track button is the tab target. Native :focus-visible drives the ring.\n */\n .switch__track:focus-visible {\n outline: var(--hx-focus-ring-width, 2px) solid\n var(--hx-switch-focus-ring-color, var(--hx-focus-ring-color, #0f7078));\n outline-offset: var(--hx-focus-ring-offset, 2px);\n }\n\n .switch--checked .switch__track {\n background-color: var(--hx-switch-track-checked-bg, var(--hx-color-primary-500, #429797));\n }\n\n .switch:not(.switch--checked) .switch__track:hover {\n background-color: var(--hx-switch-track-hover-bg, var(--hx-color-border-strong, #66787b));\n }\n\n .switch--checked .switch__track:hover {\n background-color: var(--hx-switch-track-checked-hover-bg, var(--hx-color-primary-600, #0f7078));\n }\n\n /* --- Thumb --- */\n\n .switch__thumb {\n position: absolute;\n border-radius: var(--hx-border-radius-full, 9999px);\n background-color: var(--hx-switch-thumb-bg, var(--hx-color-surface-default, #ffffff));\n box-shadow: var(--hx-switch-thumb-shadow, var(--hx-shadow-sm, 0 1px 2px 0 rgb(0 0 0 / 0.05)));\n transition: transform var(--hx-transition-fast, 150ms ease);\n }\n\n /* --- Size: sm (track 32x18, thumb 14px) --- */\n\n .switch--sm .switch__track {\n width: var(--hx-switch-track-width-sm, var(--hx-size-8, 2rem));\n height: var(--hx-switch-track-height-sm, var(--hx-size-4-5, 1.125rem));\n }\n\n .switch--sm .switch__thumb {\n width: var(--hx-switch-thumb-size-sm, var(--hx-size-3-5, 0.875rem));\n height: var(--hx-switch-thumb-size-sm, var(--hx-size-3-5, 0.875rem));\n top: 50%;\n left: var(--hx-switch-thumb-offset, var(--hx-space-0-5, 0.125rem));\n transform: translateY(-50%);\n }\n\n .switch--sm.switch--checked .switch__thumb {\n transform: translateY(-50%)\n translateX(var(--hx-switch-thumb-size-sm, var(--hx-size-3-5, 0.875rem)));\n }\n\n /* --- Size: md (track 40x22, thumb 18px) --- */\n\n .switch--md .switch__track {\n width: var(--hx-switch-track-width-md, var(--hx-size-10, 2.5rem));\n height: var(--hx-switch-track-height-md, var(--hx-size-5-5, 1.375rem));\n }\n\n .switch--md .switch__thumb {\n width: var(--hx-switch-thumb-size-md, var(--hx-size-4-5, 1.125rem));\n height: var(--hx-switch-thumb-size-md, var(--hx-size-4-5, 1.125rem));\n top: 50%;\n left: var(--hx-switch-thumb-offset, var(--hx-space-0-5, 0.125rem));\n transform: translateY(-50%);\n }\n\n .switch--md.switch--checked .switch__thumb {\n transform: translateY(-50%)\n translateX(var(--hx-switch-thumb-size-md, var(--hx-size-4-5, 1.125rem)));\n }\n\n /* --- Size: lg (track 48x26, thumb 22px) --- */\n\n .switch--lg .switch__track {\n width: var(--hx-switch-track-width-lg, var(--hx-size-12, 3rem));\n height: var(--hx-switch-track-height-lg, var(--hx-size-6-5, 1.625rem));\n }\n\n .switch--lg .switch__thumb {\n width: var(--hx-switch-thumb-size-lg, var(--hx-size-5-5, 1.375rem));\n height: var(--hx-switch-thumb-size-lg, var(--hx-size-5-5, 1.375rem));\n top: 50%;\n left: var(--hx-switch-thumb-offset, var(--hx-space-0-5, 0.125rem));\n transform: translateY(-50%);\n }\n\n .switch--lg.switch--checked .switch__thumb {\n transform: translateY(-50%)\n translateX(var(--hx-switch-thumb-size-lg, var(--hx-size-5-5, 1.375rem)));\n }\n\n /* --- Label --- */\n\n .switch__label {\n font-size: var(--hx-font-size-sm, 0.875rem);\n font-weight: var(--hx-font-weight-medium, 500);\n color: var(--hx-switch-label-color, var(--hx-color-text-strong, #202b39));\n line-height: var(--hx-line-height-normal, 1.5);\n cursor: pointer;\n user-select: none;\n -webkit-user-select: none;\n }\n\n .switch__required-marker {\n color: var(--hx-switch-error-color, var(--hx-color-error-text, #c92a2a));\n font-weight: var(--hx-font-weight-bold, 700);\n }\n\n /* --- Help Text & Error --- */\n\n .switch__help-text {\n font-size: var(--hx-font-size-xs, 0.75rem);\n color: var(--hx-switch-help-text-color, var(--hx-color-text-muted, #4a5362));\n line-height: var(--hx-line-height-normal, 1.5);\n }\n\n .switch__error {\n font-size: var(--hx-font-size-xs, 0.75rem);\n color: var(--hx-switch-error-color, var(--hx-color-error-text, #c92a2a));\n line-height: var(--hx-line-height-normal, 1.5);\n }\n\n /* --- Reduced Motion --- */\n\n @media (prefers-reduced-motion: reduce) {\n .switch__track,\n .switch__thumb {\n transition: none;\n }\n }\n\n /* ─── High Contrast Mode (forced-colors) ─── */\n\n @media (forced-colors: active) {\n .switch__track {\n forced-color-adjust: none;\n background-color: ButtonFace;\n border: 2px solid ButtonText;\n }\n\n :host(:focus-visible) .switch__track,\n .switch__track:focus-visible {\n outline: 3px solid Highlight;\n outline-offset: 2px;\n }\n\n .switch__thumb {\n background-color: ButtonText;\n box-shadow: none;\n }\n\n .switch--checked .switch__track {\n background-color: Highlight;\n border-color: Highlight;\n }\n\n .switch--checked .switch__thumb {\n background-color: HighlightText;\n }\n\n :host([disabled]) {\n opacity: 1;\n }\n\n :host([disabled]) .switch__track {\n border-color: GrayText;\n background-color: ButtonFace;\n }\n\n :host([disabled]) .switch__thumb {\n background-color: GrayText;\n }\n\n :host([disabled]) .switch__label {\n color: GrayText;\n }\n\n .switch__label {\n color: CanvasText;\n }\n\n .switch__help-text {\n color: GrayText;\n }\n\n .switch__error {\n color: LinkText;\n }\n }\n`;\n","import { html, nothing, type PropertyValues } from 'lit';\nimport '../../utilities/document-token-adoption.js';\nimport { customElement, property, query, state } from 'lit/decorators.js';\nimport { classMap } from 'lit/directives/class-map.js';\nimport { ifDefined } from 'lit/directives/if-defined.js';\nimport { HelixElement, createIdCounter } from '../../base/index.js';\nimport { FormMixin } from '../../mixins/FormMixin.js';\nimport { helixSwitchStyles } from './hx-switch.styles.js';\nimport { forcedColorsField } from '../../styles/forced-colors.js';\nimport {\n installAriaIdrefMirror,\n resolveIdrefTokens,\n supportsIdrefElementReferences,\n type AriaIdrefMirrorHandle,\n} from '../../utils/aria-idref.js';\n\nconst _nextSwitchId = createIdCounter('hx-switch');\n\n/** Detail for the hx-change event dispatched by hx-switch. */\nexport interface HxSwitchChangeDetail {\n checked: boolean;\n value: string;\n}\n\n/**\n * A toggle switch component for on/off states.\n *\n * Uses `role=\"switch\"` with `aria-checked` to convey toggle state.\n * Supports keyboard activation via Space key (per ARIA APG switch pattern).\n * Label association is handled through `aria-labelledby`, and\n * error/help text are linked via `aria-describedby`.\n *\n * @summary Form-associated toggle switch with label, error, and help text.\n *\n * @tag hx-switch\n *\n * @slot - Custom label content (overrides the label property).\n * @slot error - Custom error content (overrides the error property).\n * @slot help-text - Custom help text content (overrides the helpText property).\n *\n * @fires {CustomEvent<{checked: boolean, value: string}>} hx-change - Dispatched when the switch is toggled. Boolean-selection controls (`hx-switch`, `hx-checkbox`) include both `checked` (boolean state) and `value` (form value) in the detail; text-value controls (`hx-text-input`, `hx-combobox`, `hx-select`) emit only `{value}`.\n *\n * @csspart switch - The switch container (track + thumb wrapper).\n * @csspart track - The track background element.\n * @csspart thumb - The sliding thumb element.\n * @csspart label - The label text element.\n * @csspart help-text - The help text container.\n * @csspart error - The error message container.\n *\n * @cssprop [--hx-switch-track-bg=var(--hx-color-neutral-300)] - Track background color.\n * @cssprop [--hx-switch-track-checked-bg=var(--hx-color-primary-500)] - Track background when checked.\n * @cssprop [--hx-switch-thumb-bg=var(--hx-color-neutral-0)] - Thumb background color.\n * @cssprop [--hx-switch-thumb-shadow=var(--hx-shadow-sm)] - Thumb box shadow.\n * @cssprop [--hx-switch-focus-ring-color=var(--hx-focus-ring-color)] - Focus ring color.\n * @cssprop [--hx-switch-label-color=var(--hx-color-neutral-700)] - Label text color.\n * @cssprop [--hx-switch-error-color=var(--hx-color-error-500)] - Error message color.\n * @cssprop [--hx-switch-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-switch-font-family=var(--hx-font-family-sans)] - CSS custom property.\n * @cssprop [--hx-font-family-sans] - Font family.\n * @cssprop [--hx-space-2] - Spacing token.\n * @cssprop [--hx-touch-target-min] - Minimum touch target size.\n * @cssprop [--hx-border-radius-full] - CSS custom property.\n * @cssprop [--hx-color-neutral-300] - Color.\n * @cssprop [--hx-transition-fast] - Transition timing.\n * @cssprop [--hx-focus-ring-width] - Width.\n * @cssprop [--hx-focus-ring-color] - Color.\n * @cssprop [--hx-color-primary-400] - Color.\n * @cssprop [--hx-focus-ring-offset] - CSS custom property.\n * @cssprop [--hx-color-primary-500] - Color.\n * @cssprop [--hx-color-neutral-0] - Color.\n * @cssprop [--hx-shadow-sm] - Box shadow.\n * @cssprop [--hx-switch-track-width-sm=var(--hx-size-8)] - Width.\n * @cssprop [--hx-size-8] - Size token.\n * @cssprop [--hx-switch-track-height-sm=var(--hx-size-4-5)] - Height.\n * @cssprop [--hx-size-4-5] - Size token.\n * @cssprop [--hx-switch-thumb-size-sm=var(--hx-size-3-5)] - CSS custom property.\n * @cssprop [--hx-size-3-5] - Size token.\n * @cssprop [--hx-switch-thumb-offset=var(--hx-space-0-5)] - CSS custom property.\n * @cssprop [--hx-space-0-5] - Spacing token.\n * @cssprop [--hx-switch-track-width-md=var(--hx-size-10)] - Width.\n * @cssprop [--hx-size-10] - Size token.\n * @cssprop [--hx-switch-track-height-md=var(--hx-size-5-5)] - Height.\n * @cssprop [--hx-size-5-5] - Size token.\n * @cssprop [--hx-switch-thumb-size-md=var(--hx-size-4-5)] - CSS custom property.\n * @cssprop [--hx-switch-track-width-lg=var(--hx-size-12)] - Width.\n * @cssprop [--hx-size-12] - Size token.\n * @cssprop [--hx-switch-track-height-lg=var(--hx-size-6-5)] - Height.\n * @cssprop [--hx-size-6-5] - Size token.\n * @cssprop [--hx-switch-thumb-size-lg=var(--hx-size-5-5)] - CSS custom property.\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-color-neutral-500] - Color.\n */\n@customElement('hx-switch')\nexport class HelixSwitch extends FormMixin(HelixElement) {\n static override styles = [helixSwitchStyles, forcedColorsField];\n\n // ─── Form Association ───\n\n /** @internal */\n static override formAssociated = true;\n\n // ─── Properties ───\n\n /**\n * Whether the switch is toggled on.\n * @attr checked\n */\n @property({ type: Boolean, reflect: true })\n checked = false;\n\n /**\n * Whether the switch is disabled.\n * @attr disabled\n */\n @property({ type: Boolean, reflect: true })\n disabled = false;\n\n /**\n * Whether the switch is required for form submission.\n * @attr required\n */\n @property({ type: Boolean, reflect: true })\n required = false;\n\n /**\n * The name of the switch, used for form submission.\n * @attr name\n */\n @property({ type: String, reflect: true })\n name = '';\n\n /**\n * The value submitted when the switch is checked.\n * @attr value\n */\n @property({ type: String, reflect: true })\n value = 'on';\n\n /**\n * The visible label text for the switch.\n * @attr label\n */\n @property({ type: String })\n label = '';\n\n /**\n * Size variant of the switch.\n * @attr hx-size\n */\n @property({ type: String, reflect: true, attribute: 'hx-size' })\n size: 'sm' | 'md' | 'lg' = 'md';\n\n /**\n * Error message to display. When set, the switch enters an error state.\n * @attr error\n */\n @property({ type: String })\n error = '';\n\n /**\n * Help text displayed below the switch for guidance.\n * @attr help-text\n */\n @property({ type: String, attribute: 'help-text' })\n helpText = '';\n\n /**\n * Validation message shown when the field is required but empty.\n * @attr required-message\n */\n @property({ attribute: 'required-message' })\n requiredMessage = 'This field is required.';\n\n /**\n * Handle for the shared IDREF observer. Installed in `connectedCallback()`\n * so late-mutated `aria-labelledby`/`aria-describedby` and late-inserted\n * IDREF targets are picked up. See `installAriaIdrefMirror()`.\n * @internal\n */\n private _ariaMirror: AriaIdrefMirrorHandle | null = null;\n\n /**\n * No-IDL-ref fallback tokens applied to the inner button so consumer\n * labelling resolves through the shadow root. Tracked as reactive state\n * so values flow through the next `render()`.\n * @internal\n */\n @state() private _fallbackAriaLabelledBy: string | null = null;\n /** @internal */\n @state() private _fallbackAriaDescribedBy: string | null = null;\n /** @internal */\n @state() private _fallbackAriaLabel: string | null = null;\n\n /**\n * Whether the platform supports IDL element references on `ElementInternals`.\n * Drives the render-time branch between the modern path (host is the\n * announced surface, inner button is `aria-hidden + tabindex=-1`) and the\n * fallback path (inner button is the announced surface, host is demoted).\n * Codex round-2 finding #2.\n * @internal\n */\n @state() private _supportsIdrefRefs = true;\n\n /**\n * Tracks whether the host's `tabindex` is managed by the component itself\n * (vs. set explicitly by a consumer). Codex round-14 P2: a consumer-supplied\n * `tabindex` (e.g. roving-tabindex toolbar pattern with `tabindex=\"-1\"`)\n * must survive disabled flips and re-renders. Only re-assert tabindex in\n * `updated()` when the component originally claimed it.\n * @internal\n */\n private _internalTabindexManaged = false;\n\n // ─── Lifecycle ───\n\n override connectedCallback(): void {\n super.connectedCallback();\n // Detect platform support for IDL element references. Codex round-2\n // finding #2: drives the render-time branch.\n this._supportsIdrefRefs = supportsIdrefElementReferences(this._internals);\n // Seed root-independent semantics so the host announces the switch role\n // immediately on connect — before the first paint.\n this._syncHostAriaSemantics();\n // Codex round-1 finding #1: host is the canonical announced surface on\n // modern browsers, so the inner `<button role=switch>` is demoted via\n // `aria-hidden + tabindex=-1`.\n // Codex round-2 finding #2: on no-IDL-ref browsers the inner button is\n // the announced surface (it carries native button semantics + ARIA\n // role/state), so the host is demoted to `tabindex=-1`.\n // Codex round-14 P2: only claim ownership of `tabindex` when no consumer\n // value is present. Consumers using roving-tabindex toolbar patterns\n // must be able to set `tabindex=\"-1\"` on the host without it being\n // clobbered on every disabled flip. Note we still claim ownership when\n // disabled — the initial value is `-1` to keep the host out of tab order\n // and `updated()` re-asserts the appropriate value when disabled flips.\n if (!this.hasAttribute('tabindex')) {\n this._internalTabindexManaged = true;\n const enabledTabIndex = this._supportsIdrefRefs ? '0' : '-1';\n this.setAttribute('tabindex', this.disabled ? '-1' : enabledTabIndex);\n }\n this.addEventListener('keydown', this._handleHostKeyDown);\n this.addEventListener('click', this._handleHostClick);\n this._ariaMirror = installAriaIdrefMirror(this, () => {\n this._syncHostAriaSemantics();\n });\n }\n\n override disconnectedCallback(): void {\n super.disconnectedCallback();\n this.removeEventListener('keydown', this._handleHostKeyDown);\n this.removeEventListener('click', this._handleHostClick);\n this._ariaMirror?.disconnect();\n this._ariaMirror = null;\n }\n\n /**\n * Host-level keydown handler. Active only on the modern path; on the\n * no-IDL-ref fallback the inner `<button>` owns native activation.\n * Codex round-2 finding #2.\n * @internal\n */\n private _handleHostKeyDown = (e: KeyboardEvent): void => {\n if (this.disabled) return;\n if (!this._supportsIdrefRefs) return;\n if (e.target !== this) return;\n if (e.key === ' ' || e.key === 'Enter') {\n e.preventDefault();\n this._toggle();\n }\n };\n\n /**\n * Host-level click handler. Active only on the modern path; on the\n * fallback path AT activation flows directly to the inner button.\n * Codex round-2 finding #2.\n * @internal\n */\n private _handleHostClick = (e: MouseEvent): void => {\n if (this.disabled) return;\n if (!this._supportsIdrefRefs) return;\n const path = e.composedPath();\n if (path[0] !== this) return;\n this._toggle();\n };\n\n override updated(changedProperties: PropertyValues<this>): void {\n super.updated(changedProperties);\n if (changedProperties.has('checked') || changedProperties.has('value')) {\n this._internals.setFormValue(this.checked ? this.value : null);\n }\n if (\n changedProperties.has('disabled') ||\n (changedProperties as Map<PropertyKey, unknown>).has('_supportsIdrefRefs')\n ) {\n // Codex round-2 finding #2: keep host tabindex aligned with the chosen\n // announced surface. On no-IDL-ref browsers the inner button owns tab\n // order, so re-enabling the host should leave it `tabindex=-1`.\n // Codex round-14 P2: only re-assert when the component owns tabindex.\n // Consumer-managed values (e.g. roving-tabindex toolbar with `-1`) must\n // not be overwritten on disabled flips or supports-flag transitions.\n if (this._internalTabindexManaged) {\n const enabledTabIndex = this._supportsIdrefRefs ? '0' : '-1';\n this.setAttribute('tabindex', this.disabled ? '-1' : enabledTabIndex);\n }\n }\n // Re-resolve element references against the (possibly mutated) shadow\n // tree. `_syncHostAriaSemantics()` is also invoked from `_updateValidity()`\n // and by the IDREF mirror observer.\n this._syncHostAriaSemantics();\n }\n\n /**\n * Mirrors switch semantics onto the host via ElementInternals so that\n * consumer-supplied `aria-label`, `aria-labelledby`, and `aria-describedby`\n * on `<hx-switch>` reach the announced control. The codex aria-group-2\n * finding identified that the inner shadow `<button role=switch>` was the\n * only carrier of switch semantics, leaving host-level IDREF tokens stranded\n * on the wrong side of the shadow boundary.\n * @internal\n */\n private _syncHostAriaSemantics(): void {\n const internals = this._internals;\n const hostAriaLabel = this.getAttribute('aria-label')?.trim() || '';\n const externalLabelTokens = this.getAttribute('aria-labelledby');\n const externalDescTokens = this.getAttribute('aria-describedby');\n const labelEls = resolveIdrefTokens(this, externalLabelTokens);\n // Codex round-35 finding (CR major + codex follow-up): `aria-labelledby`\n // is only \"effective\" when at least one IDREF resolves to an element. A\n // typo or transiently-missing target must NOT erase the visible label —\n // fall back to `label` / slot so a labeled switch never becomes unnamed\n // on either render path.\n const hasEffectiveLabelledBy = labelEls.length > 0;\n\n // Codex round-2 finding #2: branch on platform support. Modern path —\n // host is the announced surface and carries `role=switch` + state via\n // ElementInternals. Fallback path — inner `<button role=switch>` is the\n // announced surface; clear host role/state so AT does not double-announce.\n if (this._supportsIdrefRefs) {\n // ─── Modern path ───\n internals.role = 'switch';\n internals.ariaChecked = this.checked ? 'true' : 'false';\n internals.ariaRequired = this.required ? 'true' : 'false';\n internals.ariaInvalid = !internals.validity.valid ? 'true' : 'false';\n internals.ariaDisabled = this.disabled ? 'true' : 'false';\n\n if (hostAriaLabel) {\n internals.ariaLabel = hostAriaLabel;\n } else if (!hasEffectiveLabelledBy) {\n internals.ariaLabel = this.label || null;\n } else {\n internals.ariaLabel = null;\n }\n\n type InternalsWithRefs = ElementInternals & {\n ariaLabelledByElements: Element[] | null;\n ariaDescribedByElements: Element[] | null;\n };\n const refsInternals = internals as InternalsWithRefs;\n\n const internalLabel = this.shadowRoot?.getElementById(this._labelId);\n const hasLabel = !!this.label || this._hasDefaultSlot;\n if (labelEls.length === 0 && !hostAriaLabel && hasLabel && internalLabel) {\n labelEls.push(internalLabel);\n }\n refsInternals.ariaLabelledByElements = labelEls.length > 0 ? labelEls : null;\n\n const descEls = resolveIdrefTokens(this, externalDescTokens);\n const helpEl = this.shadowRoot?.getElementById(this._helpTextId);\n const errorEl = this.shadowRoot?.getElementById(this._errorId);\n const hasError = !!(this.error || this._hasErrorSlot);\n // Codex round-15 P2: drop help text from the describedby chain while\n // an error is active. The render path hides the help wrapper in that\n // state (`?hidden=${... || hasError}`); appending the hidden node here\n // would have AT announce stale guidance ahead of the validation error.\n if (helpEl && !hasError && (this.helpText || this._hasHelpTextSlot)) {\n descEls.push(helpEl);\n }\n if (errorEl && hasError) {\n descEls.push(errorEl);\n }\n refsInternals.ariaDescribedByElements = descEls.length > 0 ? descEls : null;\n // Clear fallback state when IDL refs are available.\n this._fallbackAriaLabelledBy = null;\n this._fallbackAriaDescribedBy = null;\n this._fallbackAriaLabel = null;\n } else {\n // ─── Fallback path: inner button is the announced surface ───\n // Round-2 finding #2: round-1 set host role/state via internals AND\n // mirrored aria-* onto the `aria-hidden` inner button — making the\n // mirrored attributes inert. The fix is to clear host role/state on\n // internals so AT does not double-announce, and let the inner button\n // (rendered without aria-hidden, with `tabindex=0`, with role=switch\n // and aria-checked) be the announced surface.\n internals.role = null;\n internals.ariaChecked = null;\n internals.ariaRequired = null;\n internals.ariaInvalid = null;\n internals.ariaDisabled = null;\n internals.ariaLabel = null;\n\n // Round-35 codex follow-up: only mirror the consumer's labelledby tokens\n // when at least one resolves; otherwise the inner button must fall back\n // to `aria-label` (label property or slot) so the switch keeps a name\n // when an IDREF is a typo. Same contract as the modern path.\n this._fallbackAriaLabelledBy = hasEffectiveLabelledBy ? externalLabelTokens : null;\n this._fallbackAriaDescribedBy = externalDescTokens || null;\n this._fallbackAriaLabel = hasEffectiveLabelledBy ? null : hostAriaLabel || this.label || null;\n }\n }\n\n // ─── Form Integration ───\n\n /** Recalculates and sets the validity state based on required and checked. */\n /** @internal */\n override _updateValidity(): void {\n if (this.required && !this.checked) {\n // Codex round-17 P2: anchor validity UI to the announced surface. On\n // the modern path the host carries `role=switch` via internals and is\n // the canonical focus target (the inner track button is `aria-hidden +\n // tabindex=-1`), so reportValidity() would otherwise focus a hidden\n // node. On the fallback path the inner button is the announced\n // surface.\n const anchor: HTMLElement | undefined = this._supportsIdrefRefs\n ? this\n : (this._trackEl ?? undefined);\n this._internals.setValidity(\n { valueMissing: true },\n this.error || this.requiredMessage,\n anchor,\n );\n } else {\n this._internals.setValidity({});\n }\n // Codex round-1 finding #6: sync host ARIA semantics immediately after\n // every `setValidity()` call so `internals.ariaInvalid` reflects the\n // current `ValidityState` rather than the previous render snapshot.\n this._syncHostAriaSemantics();\n }\n\n protected override _onFormReset(): void {\n this.checked = false;\n this._internals.setFormValue(null);\n this._resetInteractionState();\n }\n\n protected override _onFormStateRestore(\n state: File | string | FormData | null,\n _mode: 'restore' | 'autocomplete',\n ): void {\n if (typeof state === 'string') {\n this.checked = state === this.value;\n }\n }\n\n protected override _onFormDisabled(disabled: boolean): void {\n this.disabled = disabled;\n }\n\n /** Reference to the native button element acting as the switch track. * @internal\n */\n @query('.switch__track')\n private _trackEl: HTMLButtonElement | null | undefined;\n\n /** Whether the error slot has assigned content. */\n /** @internal */\n @state() private _hasErrorSlot = false;\n\n /** Whether the default slot has assigned content (slotted label). */\n /** @internal */\n @state() private _hasDefaultSlot = false;\n\n /** Whether the help-text slot has assigned content. */\n /** @internal */\n @state() private _hasHelpTextSlot = false;\n\n // ─── Slot Handlers ───\n\n /** Updates _hasErrorSlot when error slot content changes. */\n /** @internal */\n private _handleErrorSlotChange(e: Event): void {\n const slot = e.target as HTMLSlotElement;\n this._hasErrorSlot = slot.assignedNodes({ flatten: true }).length > 0;\n }\n\n /** Updates _hasDefaultSlot when default slot content changes. */\n /** @internal */\n private _handleDefaultSlotChange(e: Event): void {\n const slot = e.target as HTMLSlotElement;\n this._hasDefaultSlot = slot.assignedNodes({ flatten: true }).length > 0;\n }\n\n /** Updates _hasHelpTextSlot when help-text slot content changes. */\n /** @internal */\n private _handleHelpTextSlotChange(e: Event): void {\n const slot = e.target as HTMLSlotElement;\n this._hasHelpTextSlot = slot.assignedNodes({ flatten: true }).length > 0;\n }\n\n // ─── Event Handling ───\n\n /** Toggles checked state and dispatches hx-change event. */\n /** @internal */\n private _toggle(): void {\n if (this.disabled) return;\n this.checked = !this.checked;\n this._handleInteractionInput();\n\n this.dispatchEvent(\n new CustomEvent<{ checked: boolean; value: string }>('hx-change', {\n bubbles: true,\n composed: true,\n detail: { checked: this.checked, value: this.value },\n }),\n );\n }\n\n /** Handles click events on the track. */\n /** @internal */\n private _handleClick(): void {\n this._toggle();\n // Codex round-12 P2: on the modern path the host owns role=\"switch\" and\n // tabindex=0; the inner <button tabindex=\"-1\"> is aria-hidden. Native\n // click activation on a `<button>` still focuses it, which would leave\n // `document.activeElement` and AT focus on a hidden node. Move focus back\n // to the host so the announced surface is also the focus target.\n if (this._supportsIdrefRefs) {\n this.focus();\n }\n }\n\n /** Handles keydown events — Space toggles the switch per ARIA APG. */\n /** @internal */\n private _handleKeyDown(e: KeyboardEvent): void {\n if (e.key === ' ') {\n e.preventDefault();\n this._toggle();\n }\n }\n\n // ─── Public Methods ───\n\n /**\n * Moves focus to the announced switch surface. Codex round-1 finding #1\n * relocated the focus target to the host so AT announces a single widget;\n * the host carries the canonical role/state on modern engines. Round-7\n * finding #7 extends that contract to the no-IDL-ref fallback: when the\n * host is demoted (`tabindex=-1`, role/state cleared on `internals`) the\n * inner `<button role=switch>` owns the announced semantics and tab order,\n * so programmatic `focus()` must redirect there — otherwise scripted focus\n * and error recovery land on the demoted host on unsupported engines.\n */\n override focus(options?: FocusOptions): void {\n if (this._supportsIdrefRefs) {\n super.focus(options);\n return;\n }\n this._trackEl?.focus(options);\n }\n\n // ─── Render ───\n\n /** Unique ID for this switch instance, used for ARIA associations. */\n /** @internal */\n private _switchId = _nextSwitchId();\n /** ID for the label element, referenced by aria-labelledby. */\n /** @internal */\n private _labelId = `${this._switchId}-label`;\n /** ID for the help text element, referenced by aria-describedby. */\n /** @internal */\n private _helpTextId = `${this._switchId}-help`;\n /** ID for the error element, referenced by aria-describedby. */\n /** @internal */\n private _errorId = `${this._switchId}-error`;\n\n override render() {\n const hasError = !!this.error || this._hasErrorSlot;\n const hasHelpText = !!this.helpText || this._hasHelpTextSlot;\n const hasLabel = !!this.label || this._hasDefaultSlot;\n // Validity-driven invalid state: a required-but-unchecked switch is\n // invalid via setValidity() even before any visible error renders.\n const isInvalid = hasError || (this.required && !this.checked);\n\n const containerClasses = {\n switch: true,\n 'switch--checked': this.checked,\n 'switch--disabled': this.disabled,\n 'switch--required': this.required,\n 'switch--error': hasError,\n [`switch--${this.size}`]: true,\n };\n\n // help-text first, error appended — assistive tech announces guidance\n // before validation feedback. Both ids are persistent in the shadow tree.\n // Codex round-15 P2: drop help text from the chain when an error is\n // active. The help wrapper renders hidden in that state, so referencing\n // it would have AT announce stale guidance ahead of the validation\n // error. Mirrors the modern-path host-internals chain.\n const describedBy =\n [!hasError && hasHelpText ? this._helpTextId : null, hasError ? this._errorId : null]\n .filter(Boolean)\n .join(' ') || undefined;\n\n // Codex round-1 finding #8: merge consumer fallback tokens with the\n // shadow-internal describedBy chain on browsers without IDL element\n // references. Internal `_labelId` is preferred when no consumer\n // labelledby tokens are supplied.\n const innerDescribedBy =\n [describedBy ?? null, this._fallbackAriaDescribedBy].filter(Boolean).join(' ') || undefined;\n // Codex round-14 P2: per ARIA spec, `aria-labelledby` overrides\n // `aria-label`. On the no-IDL-ref fallback path the consumer-set\n // `aria-label` was being shadowed because we always assigned the\n // internal `_labelId`. When the consumer supplied an `aria-label` (and\n // did NOT supply an `aria-labelledby`), omit the internal labelledby so\n // AT announces the consumer-supplied name — matching the modern path\n // and the spec. Consumer-supplied `aria-labelledby` (mirrored into\n // `_fallbackAriaLabelledBy`) still wins over the internal label.\n const innerAriaLabel = this._fallbackAriaLabel ?? undefined;\n const innerLabelledBy = this._fallbackAriaLabelledBy\n ? this._fallbackAriaLabelledBy\n : innerAriaLabel\n ? undefined\n : hasLabel\n ? this._labelId\n : undefined;\n\n // Codex round-2 finding #2: branch the inner button on platform support.\n // Modern path — host is announced, inner button is `aria-hidden + tabindex=-1`.\n // Fallback path — inner button is announced (NO aria-hidden, role=switch,\n // tabindex=0) so consumer-mirrored aria-* attributes resolve through a\n // visible accessibility-tree node and AT can name + activate it natively.\n const innerIsAnnounced = !this._supportsIdrefRefs;\n const innerTabIndex = innerIsAnnounced && !this.disabled ? '0' : '-1';\n // On the fallback path the inner button must carry role=switch so AT\n // announces \"switch\", aria-checked for state, and aria-required when set.\n const innerRole = innerIsAnnounced ? 'switch' : nothing;\n\n return html`\n <div part=\"switch\" class=${classMap(containerClasses)}>\n <div class=\"switch__control-row\">\n <button\n part=\"track\"\n class=\"switch__track\"\n id=${this._switchId}\n type=\"button\"\n role=${innerRole}\n tabindex=${innerTabIndex}\n aria-checked=${this.checked ? 'true' : 'false'}\n aria-labelledby=${ifDefined(innerLabelledBy)}\n aria-describedby=${ifDefined(innerDescribedBy)}\n aria-label=${ifDefined(innerAriaLabel)}\n aria-invalid=${isInvalid ? 'true' : nothing}\n aria-required=${this.required ? 'true' : nothing}\n aria-hidden=${innerIsAnnounced ? nothing : 'true'}\n ?disabled=${this.disabled}\n @click=${this._handleClick}\n @keydown=${this._handleKeyDown}\n >\n <span part=\"thumb\" class=\"switch__thumb\"></span>\n </button>\n\n <label part=\"label\" class=\"switch__label\" id=${this._labelId} for=${this._switchId}>\n <slot @slotchange=${this._handleDefaultSlotChange}>${this.label}</slot>${this.required\n ? html`<span class=\"switch__required-marker\" aria-hidden=\"true\">*</span>`\n : nothing}\n </label>\n </div>\n\n <!--\n Persistent error live region. Slot fallback content provides the\n property-driven message; consumers can replace it via slot=\"error\".\n The wrapper carries a stable id so aria-describedby remains valid\n across both code paths and across show/hide transitions.\n -->\n <div\n part=\"error\"\n class=\"switch__error\"\n id=${this._errorId}\n role=\"alert\"\n ?hidden=${!hasError}\n >\n <slot name=\"error\" @slotchange=${this._handleErrorSlotChange}>${this.error}</slot>\n </div>\n\n <!--\n Persistent help-text wrapper. Rendered whenever the property OR the\n slot has content; hidden when an error is present so guidance does\n not compete with validation feedback.\n -->\n <div\n part=\"help-text\"\n class=\"switch__help-text\"\n id=${this._helpTextId}\n ?hidden=${!hasHelpText || hasError}\n >\n <slot name=\"help-text\" @slotchange=${this._handleHelpTextSlotChange}\n >${this.helpText}</slot\n >\n </div>\n </div>\n `;\n }\n}\n\n/**\n * Per-component event map for type-safe addEventListener on hx-switch.\n * The `hx-change` detail always includes both `checked` and `value` for this component.\n */\nexport interface HxSwitchEventMap {\n 'hx-change': CustomEvent<{ checked: boolean; value: string }>;\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'hx-switch': HelixSwitch;\n }\n}\n\nexport type HxSwitch = HelixSwitch;\n"],"names":["helixSwitchStyles","css","_nextSwitchId","createIdCounter","HelixSwitch","FormMixin","HelixElement","supportsIdrefElementReferences","enabledTabIndex","installAriaIdrefMirror","_a","changedProperties","internals","hostAriaLabel","externalLabelTokens","externalDescTokens","labelEls","resolveIdrefTokens","hasEffectiveLabelledBy","refsInternals","internalLabel","_b","hasLabel","descEls","helpEl","_c","errorEl","_d","hasError","anchor","state","_mode","disabled","slot","options","hasHelpText","isInvalid","containerClasses","innerDescribedBy","innerAriaLabel","innerLabelledBy","innerIsAnnounced","innerTabIndex","innerRole","nothing","html","classMap","ifDefined","forcedColorsField","__decorateClass","property","query","customElement"],"mappings":";;;;;;;;;AAEO,MAAMA,IAAoBC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAA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"}