@helixui/library 3.7.0 → 3.8.0-next.145

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 (394) hide show
  1. package/README.md +41 -0
  2. package/aaa-verdicts.json +2036 -0
  3. package/custom-elements.json +1657 -71
  4. package/dist/components/hx-accordion/hx-accordion-item.d.ts.map +1 -1
  5. package/dist/components/hx-accordion/hx-accordion-item.styles.d.ts.map +1 -1
  6. package/dist/components/hx-accordion/index.js +1 -1
  7. package/dist/components/hx-action-bar/hx-action-bar.d.ts +18 -0
  8. package/dist/components/hx-action-bar/hx-action-bar.d.ts.map +1 -1
  9. package/dist/components/hx-action-bar/hx-action-bar.styles.d.ts.map +1 -1
  10. package/dist/components/hx-action-bar/index.js +1 -1
  11. package/dist/components/hx-alert/hx-alert.d.ts +0 -8
  12. package/dist/components/hx-alert/hx-alert.d.ts.map +1 -1
  13. package/dist/components/hx-alert/hx-alert.styles.d.ts.map +1 -1
  14. package/dist/components/hx-alert/index.js +1 -1
  15. package/dist/components/hx-avatar/hx-avatar.d.ts +4 -1
  16. package/dist/components/hx-avatar/hx-avatar.d.ts.map +1 -1
  17. package/dist/components/hx-avatar/hx-avatar.styles.d.ts.map +1 -1
  18. package/dist/components/hx-avatar/index.js +1 -1
  19. package/dist/components/hx-badge/hx-badge.d.ts.map +1 -1
  20. package/dist/components/hx-badge/hx-badge.styles.d.ts.map +1 -1
  21. package/dist/components/hx-badge/index.js +1 -1
  22. package/dist/components/hx-banner/hx-banner.d.ts +19 -8
  23. package/dist/components/hx-banner/hx-banner.d.ts.map +1 -1
  24. package/dist/components/hx-banner/hx-banner.styles.d.ts.map +1 -1
  25. package/dist/components/hx-banner/index.js +1 -1
  26. package/dist/components/hx-breadcrumb/hx-breadcrumb-item.d.ts.map +1 -1
  27. package/dist/components/hx-breadcrumb/hx-breadcrumb-item.styles.d.ts.map +1 -1
  28. package/dist/components/hx-breadcrumb/hx-breadcrumb.d.ts +18 -0
  29. package/dist/components/hx-breadcrumb/hx-breadcrumb.d.ts.map +1 -1
  30. package/dist/components/hx-breadcrumb/index.js +1 -1
  31. package/dist/components/hx-button/hx-button.styles.d.ts.map +1 -1
  32. package/dist/components/hx-button/index.js +1 -1
  33. package/dist/components/hx-button-group/hx-button-group.d.ts +47 -0
  34. package/dist/components/hx-button-group/hx-button-group.d.ts.map +1 -1
  35. package/dist/components/hx-button-group/index.js +1 -1
  36. package/dist/components/hx-carousel/hx-carousel.d.ts.map +1 -1
  37. package/dist/components/hx-carousel/hx-carousel.styles.d.ts.map +1 -1
  38. package/dist/components/hx-carousel/index.js +1 -1
  39. package/dist/components/hx-checkbox/hx-checkbox.d.ts.map +1 -1
  40. package/dist/components/hx-checkbox/hx-checkbox.styles.d.ts.map +1 -1
  41. package/dist/components/hx-checkbox/index.js +1 -1
  42. package/dist/components/hx-checkbox-group/hx-checkbox-group.d.ts +36 -0
  43. package/dist/components/hx-checkbox-group/hx-checkbox-group.d.ts.map +1 -1
  44. package/dist/components/hx-checkbox-group/hx-checkbox-group.styles.d.ts.map +1 -1
  45. package/dist/components/hx-checkbox-group/index.js +1 -1
  46. package/dist/components/hx-clinical-status/hx-clinical-status.d.ts +26 -9
  47. package/dist/components/hx-clinical-status/hx-clinical-status.d.ts.map +1 -1
  48. package/dist/components/hx-clinical-status/hx-clinical-status.styles.d.ts.map +1 -1
  49. package/dist/components/hx-clinical-status/index.js +1 -1
  50. package/dist/components/hx-color-picker/hx-color-picker.d.ts +18 -0
  51. package/dist/components/hx-color-picker/hx-color-picker.d.ts.map +1 -1
  52. package/dist/components/hx-color-picker/hx-color-picker.styles.d.ts.map +1 -1
  53. package/dist/components/hx-color-picker/index.js +1 -1
  54. package/dist/components/hx-combobox/hx-combobox.d.ts +18 -0
  55. package/dist/components/hx-combobox/hx-combobox.d.ts.map +1 -1
  56. package/dist/components/hx-combobox/hx-combobox.styles.d.ts.map +1 -1
  57. package/dist/components/hx-combobox/index.js +1 -1
  58. package/dist/components/hx-copy-button/hx-copy-button.d.ts +18 -0
  59. package/dist/components/hx-copy-button/hx-copy-button.d.ts.map +1 -1
  60. package/dist/components/hx-copy-button/hx-copy-button.styles.d.ts.map +1 -1
  61. package/dist/components/hx-copy-button/index.js +1 -1
  62. package/dist/components/hx-date-picker/hx-date-picker.d.ts +18 -0
  63. package/dist/components/hx-date-picker/hx-date-picker.d.ts.map +1 -1
  64. package/dist/components/hx-date-picker/hx-date-picker.styles.d.ts.map +1 -1
  65. package/dist/components/hx-date-picker/index.js +1 -1
  66. package/dist/components/hx-drawer/hx-drawer.d.ts +18 -0
  67. package/dist/components/hx-drawer/hx-drawer.d.ts.map +1 -1
  68. package/dist/components/hx-drawer/hx-drawer.styles.d.ts.map +1 -1
  69. package/dist/components/hx-drawer/index.js +1 -1
  70. package/dist/components/hx-dropdown/hx-dropdown.d.ts +18 -0
  71. package/dist/components/hx-dropdown/hx-dropdown.d.ts.map +1 -1
  72. package/dist/components/hx-dropdown/hx-dropdown.styles.d.ts.map +1 -1
  73. package/dist/components/hx-dropdown/index.js +1 -1
  74. package/dist/components/hx-field/hx-field.d.ts +17 -0
  75. package/dist/components/hx-field/hx-field.d.ts.map +1 -1
  76. package/dist/components/hx-field-label/hx-field-label.d.ts +17 -0
  77. package/dist/components/hx-field-label/hx-field-label.d.ts.map +1 -1
  78. package/dist/components/hx-file-upload/hx-file-upload.d.ts +46 -0
  79. package/dist/components/hx-file-upload/hx-file-upload.d.ts.map +1 -1
  80. package/dist/components/hx-file-upload/hx-file-upload.styles.d.ts.map +1 -1
  81. package/dist/components/hx-file-upload/index.js +1 -1
  82. package/dist/components/hx-form/hx-form.d.ts +19 -0
  83. package/dist/components/hx-form/hx-form.d.ts.map +1 -1
  84. package/dist/components/hx-help-text/hx-help-text.d.ts +17 -0
  85. package/dist/components/hx-help-text/hx-help-text.d.ts.map +1 -1
  86. package/dist/components/hx-help-text/hx-help-text.styles.d.ts.map +1 -1
  87. package/dist/components/hx-help-text/index.js +1 -1
  88. package/dist/components/hx-icon/hx-icon.d.ts +108 -12
  89. package/dist/components/hx-icon/hx-icon.d.ts.map +1 -1
  90. package/dist/components/hx-icon/hx-icon.styles.d.ts.map +1 -1
  91. package/dist/components/hx-icon/index.js +1 -1
  92. package/dist/components/hx-icon-button/hx-icon-button.d.ts +18 -0
  93. package/dist/components/hx-icon-button/hx-icon-button.d.ts.map +1 -1
  94. package/dist/components/hx-link/hx-link.d.ts.map +1 -1
  95. package/dist/components/hx-link/hx-link.styles.d.ts.map +1 -1
  96. package/dist/components/hx-link/index.js +1 -1
  97. package/dist/components/hx-menu/hx-menu-item.d.ts.map +1 -1
  98. package/dist/components/hx-menu/hx-menu-item.styles.d.ts.map +1 -1
  99. package/dist/components/hx-menu/hx-menu.d.ts +18 -0
  100. package/dist/components/hx-menu/hx-menu.d.ts.map +1 -1
  101. package/dist/components/hx-menu/index.js +1 -1
  102. package/dist/components/hx-nav/hx-nav.d.ts +18 -0
  103. package/dist/components/hx-nav/hx-nav.d.ts.map +1 -1
  104. package/dist/components/hx-nav/hx-nav.styles.d.ts.map +1 -1
  105. package/dist/components/hx-nav/index.js +1 -1
  106. package/dist/components/hx-number-input/hx-number-input.d.ts +18 -0
  107. package/dist/components/hx-number-input/hx-number-input.d.ts.map +1 -1
  108. package/dist/components/hx-number-input/hx-number-input.styles.d.ts.map +1 -1
  109. package/dist/components/hx-number-input/index.js +1 -1
  110. package/dist/components/hx-overflow-menu/hx-overflow-menu.d.ts +23 -1
  111. package/dist/components/hx-overflow-menu/hx-overflow-menu.d.ts.map +1 -1
  112. package/dist/components/hx-overflow-menu/hx-overflow-menu.styles.d.ts.map +1 -1
  113. package/dist/components/hx-overflow-menu/index.js +1 -1
  114. package/dist/components/hx-phi-field/hx-phi-field.d.ts.map +1 -1
  115. package/dist/components/hx-phi-field/hx-phi-field.styles.d.ts.map +1 -1
  116. package/dist/components/hx-phi-field/index.js +1 -1
  117. package/dist/components/hx-popover/hx-popover.d.ts +18 -0
  118. package/dist/components/hx-popover/hx-popover.d.ts.map +1 -1
  119. package/dist/components/hx-popover/hx-popover.styles.d.ts.map +1 -1
  120. package/dist/components/hx-popover/index.js +1 -1
  121. package/dist/components/hx-popup/hx-popup.d.ts +18 -0
  122. package/dist/components/hx-popup/hx-popup.d.ts.map +1 -1
  123. package/dist/components/hx-popup/hx-popup.styles.d.ts.map +1 -1
  124. package/dist/components/hx-popup/index.js +1 -1
  125. package/dist/components/hx-radio-group/hx-radio-group.d.ts +18 -0
  126. package/dist/components/hx-radio-group/hx-radio-group.d.ts.map +1 -1
  127. package/dist/components/hx-radio-group/hx-radio-group.styles.d.ts.map +1 -1
  128. package/dist/components/hx-radio-group/hx-radio.styles.d.ts.map +1 -1
  129. package/dist/components/hx-radio-group/index.js +1 -1
  130. package/dist/components/hx-rating/hx-rating.d.ts +19 -0
  131. package/dist/components/hx-rating/hx-rating.d.ts.map +1 -1
  132. package/dist/components/hx-rating/hx-rating.styles.d.ts.map +1 -1
  133. package/dist/components/hx-rating/index.js +1 -1
  134. package/dist/components/hx-select/hx-select.d.ts +18 -0
  135. package/dist/components/hx-select/hx-select.d.ts.map +1 -1
  136. package/dist/components/hx-side-nav/hx-nav-item.d.ts.map +1 -1
  137. package/dist/components/hx-side-nav/hx-nav-item.styles.d.ts.map +1 -1
  138. package/dist/components/hx-side-nav/hx-side-nav.d.ts +18 -0
  139. package/dist/components/hx-side-nav/hx-side-nav.d.ts.map +1 -1
  140. package/dist/components/hx-side-nav/hx-side-nav.styles.d.ts.map +1 -1
  141. package/dist/components/hx-side-nav/index.js +1 -1
  142. package/dist/components/hx-slider/hx-slider.d.ts +47 -0
  143. package/dist/components/hx-slider/hx-slider.d.ts.map +1 -1
  144. package/dist/components/hx-slider/index.js +1 -1
  145. package/dist/components/hx-split-button/hx-split-button.d.ts +18 -0
  146. package/dist/components/hx-split-button/hx-split-button.d.ts.map +1 -1
  147. package/dist/components/hx-split-button/hx-split-button.styles.d.ts.map +1 -1
  148. package/dist/components/hx-split-button/index.js +1 -1
  149. package/dist/components/hx-stat/hx-stat.d.ts.map +1 -1
  150. package/dist/components/hx-stat/hx-stat.styles.d.ts.map +1 -1
  151. package/dist/components/hx-stat/index.js +1 -1
  152. package/dist/components/hx-steps/hx-step.d.ts.map +1 -1
  153. package/dist/components/hx-steps/hx-step.styles.d.ts.map +1 -1
  154. package/dist/components/hx-steps/index.js +1 -1
  155. package/dist/components/hx-switch/hx-switch.d.ts +18 -0
  156. package/dist/components/hx-switch/hx-switch.d.ts.map +1 -1
  157. package/dist/components/hx-switch/hx-switch.styles.d.ts.map +1 -1
  158. package/dist/components/hx-switch/index.js +1 -1
  159. package/dist/components/hx-tabs/hx-tab.styles.d.ts.map +1 -1
  160. package/dist/components/hx-tabs/hx-tabs.d.ts +18 -0
  161. package/dist/components/hx-tabs/hx-tabs.d.ts.map +1 -1
  162. package/dist/components/hx-tabs/index.js +1 -1
  163. package/dist/components/hx-tag/hx-tag.d.ts.map +1 -1
  164. package/dist/components/hx-tag/hx-tag.styles.d.ts.map +1 -1
  165. package/dist/components/hx-tag/index.js +1 -1
  166. package/dist/components/hx-text-input/hx-text-input.styles.d.ts.map +1 -1
  167. package/dist/components/hx-text-input/index.js +1 -1
  168. package/dist/components/hx-textarea/hx-textarea.d.ts +18 -0
  169. package/dist/components/hx-textarea/hx-textarea.d.ts.map +1 -1
  170. package/dist/components/hx-time-picker/hx-time-picker.d.ts +18 -0
  171. package/dist/components/hx-time-picker/hx-time-picker.d.ts.map +1 -1
  172. package/dist/components/hx-time-picker/hx-time-picker.styles.d.ts.map +1 -1
  173. package/dist/components/hx-time-picker/index.js +1 -1
  174. package/dist/components/hx-toast/hx-toast.d.ts +19 -8
  175. package/dist/components/hx-toast/hx-toast.d.ts.map +1 -1
  176. package/dist/components/hx-toast/hx-toast.styles.d.ts.map +1 -1
  177. package/dist/components/hx-toast/index.js +1 -1
  178. package/dist/components/hx-toggle-button/hx-toggle-button.d.ts +18 -0
  179. package/dist/components/hx-toggle-button/hx-toggle-button.d.ts.map +1 -1
  180. package/dist/components/hx-toggle-button/hx-toggle-button.styles.d.ts.map +1 -1
  181. package/dist/components/hx-toggle-button/index.js +1 -1
  182. package/dist/components/hx-tooltip/hx-tooltip.d.ts +18 -0
  183. package/dist/components/hx-tooltip/hx-tooltip.d.ts.map +1 -1
  184. package/dist/components/hx-tooltip/hx-tooltip.styles.d.ts.map +1 -1
  185. package/dist/components/hx-tooltip/index.js +1 -1
  186. package/dist/components/hx-top-nav/hx-top-nav.d.ts +18 -0
  187. package/dist/components/hx-top-nav/hx-top-nav.d.ts.map +1 -1
  188. package/dist/components/hx-top-nav/hx-top-nav.styles.d.ts.map +1 -1
  189. package/dist/components/hx-top-nav/index.js +1 -1
  190. package/dist/components/hx-tree-view/hx-tree-item.d.ts.map +1 -1
  191. package/dist/components/hx-tree-view/hx-tree-item.styles.d.ts.map +1 -1
  192. package/dist/components/hx-tree-view/index.js +1 -1
  193. package/dist/css/helix-all.css +355 -84
  194. package/dist/css/helix-core.css +23 -5
  195. package/dist/css/helix-feedback.css +15 -18
  196. package/dist/css/helix-forms.css +139 -27
  197. package/dist/css/helix-media.css +6 -3
  198. package/dist/css/helix-navigation.css +59 -9
  199. package/dist/css/helix-overlay.css +63 -0
  200. package/dist/css/helix-tokens.css +16 -14
  201. package/dist/css/helix-utility.css +44 -12
  202. package/dist/css/hx-action-bar.css +12 -0
  203. package/dist/css/hx-alert.css +4 -8
  204. package/dist/css/hx-avatar.css +1 -2
  205. package/dist/css/hx-badge.css +5 -0
  206. package/dist/css/hx-banner.css +4 -8
  207. package/dist/css/hx-button.css +4 -1
  208. package/dist/css/hx-carousel.css +6 -3
  209. package/dist/css/hx-checkbox-group.css +11 -0
  210. package/dist/css/hx-checkbox.css +14 -9
  211. package/dist/css/hx-clinical-status.css +4 -7
  212. package/dist/css/hx-color-picker.css +14 -1
  213. package/dist/css/hx-combobox.css +8 -0
  214. package/dist/css/hx-copy-button.css +5 -2
  215. package/dist/css/hx-date-picker.css +11 -1
  216. package/dist/css/hx-drawer.css +5 -0
  217. package/dist/css/hx-dropdown.css +18 -0
  218. package/dist/css/hx-file-upload.css +4 -0
  219. package/dist/css/hx-help-text.css +5 -0
  220. package/dist/css/hx-icon.css +7 -0
  221. package/dist/css/hx-link.css +1 -2
  222. package/dist/css/hx-nav.css +31 -2
  223. package/dist/css/hx-number-input.css +10 -11
  224. package/dist/css/hx-overflow-menu.css +5 -0
  225. package/dist/css/hx-phi-field.css +2 -3
  226. package/dist/css/hx-popover.css +13 -0
  227. package/dist/css/hx-popup.css +14 -0
  228. package/dist/css/hx-radio-group.css +10 -0
  229. package/dist/css/hx-rating.css +6 -0
  230. package/dist/css/hx-side-nav.css +10 -5
  231. package/dist/css/hx-split-button.css +27 -10
  232. package/dist/css/hx-stat.css +1 -2
  233. package/dist/css/hx-switch.css +19 -1
  234. package/dist/css/hx-tag.css +5 -0
  235. package/dist/css/hx-text-input.css +4 -1
  236. package/dist/css/hx-time-picker.css +12 -2
  237. package/dist/css/hx-toast.css +6 -0
  238. package/dist/css/hx-toggle-button.css +11 -1
  239. package/dist/css/hx-tooltip.css +13 -0
  240. package/dist/css/hx-top-nav.css +13 -2
  241. package/dist/css/index.css +1 -1
  242. package/dist/css/manifest.json +43 -12
  243. package/dist/index.js +47 -47
  244. package/dist/shared/{hx-accordion-ZVzgDzTG.js → hx-accordion-DR--Ev4t.js} +48 -54
  245. package/dist/shared/hx-accordion-DR--Ev4t.js.map +1 -0
  246. package/dist/shared/{hx-action-bar-CitgcpGv.js → hx-action-bar-BlEG4aZv.js} +41 -29
  247. package/dist/shared/hx-action-bar-BlEG4aZv.js.map +1 -0
  248. package/dist/shared/{hx-alert-Bto8-TIi.js → hx-alert-C0axS32J.js} +40 -79
  249. package/dist/shared/hx-alert-C0axS32J.js.map +1 -0
  250. package/dist/shared/{hx-avatar-C9hOmlAb.js → hx-avatar-ChAYWnK8.js} +22 -24
  251. package/dist/shared/hx-avatar-ChAYWnK8.js.map +1 -0
  252. package/dist/shared/{hx-badge-DFL35nzi.js → hx-badge-vX-1cuLA.js} +16 -11
  253. package/dist/shared/hx-badge-vX-1cuLA.js.map +1 -0
  254. package/dist/shared/{hx-banner-fpRnciIO.js → hx-banner-PbHwFNSb.js} +51 -90
  255. package/dist/shared/hx-banner-PbHwFNSb.js.map +1 -0
  256. package/dist/shared/{hx-breadcrumb-item-3tKppF9h.js → hx-breadcrumb-item-D8xYqe3s.js} +56 -43
  257. package/dist/shared/hx-breadcrumb-item-D8xYqe3s.js.map +1 -0
  258. package/dist/shared/{hx-button-rRNmD4fd.js → hx-button-DOZTZnz-.js} +18 -15
  259. package/dist/shared/hx-button-DOZTZnz-.js.map +1 -0
  260. package/dist/shared/hx-button-group-D3QUmSzl.js +248 -0
  261. package/dist/shared/hx-button-group-D3QUmSzl.js.map +1 -0
  262. package/dist/shared/{hx-carousel-item-z1Lc24op.js → hx-carousel-item-BVIKgQ4i.js} +72 -102
  263. package/dist/shared/hx-carousel-item-BVIKgQ4i.js.map +1 -0
  264. package/dist/shared/{hx-checkbox-hPlIw6Lb.js → hx-checkbox-DDSXXhps.js} +33 -30
  265. package/dist/shared/hx-checkbox-DDSXXhps.js.map +1 -0
  266. package/dist/shared/{hx-checkbox-group-D5piJLY8.js → hx-checkbox-group-C0q6HDqn.js} +101 -58
  267. package/dist/shared/hx-checkbox-group-C0q6HDqn.js.map +1 -0
  268. package/dist/shared/{hx-clinical-status-D3XQIOqX.js → hx-clinical-status-ZSVEc3Qg.js} +68 -87
  269. package/dist/shared/hx-clinical-status-ZSVEc3Qg.js.map +1 -0
  270. package/dist/shared/{hx-color-picker-DBwJzT5f.js → hx-color-picker-CYjx8i8R.js} +97 -84
  271. package/dist/shared/hx-color-picker-CYjx8i8R.js.map +1 -0
  272. package/dist/shared/{hx-combobox-NgJaLbs2.js → hx-combobox-Be-mqOv4.js} +35 -45
  273. package/dist/shared/hx-combobox-Be-mqOv4.js.map +1 -0
  274. package/dist/shared/{hx-copy-button-sUVuikyH.js → hx-copy-button-DJirFCUL.js} +18 -15
  275. package/dist/shared/hx-copy-button-DJirFCUL.js.map +1 -0
  276. package/dist/shared/{hx-date-picker-DSKDkCy1.js → hx-date-picker-CziP3Hm1.js} +80 -82
  277. package/dist/shared/hx-date-picker-CziP3Hm1.js.map +1 -0
  278. package/dist/shared/{hx-drawer-CM_upadk.js → hx-drawer-BlU2oX8-.js} +32 -36
  279. package/dist/shared/hx-drawer-BlU2oX8-.js.map +1 -0
  280. package/dist/shared/{hx-dropdown-D626S2ZG.js → hx-dropdown-DREqpIpm.js} +51 -33
  281. package/dist/shared/hx-dropdown-DREqpIpm.js.map +1 -0
  282. package/dist/shared/hx-field-label-BVRyyKeh.js.map +1 -1
  283. package/dist/shared/hx-field-zw0U1KVi.js.map +1 -1
  284. package/dist/shared/{hx-file-upload-D3rKROK5.js → hx-file-upload-CU5QGZSP.js} +137 -80
  285. package/dist/shared/hx-file-upload-CU5QGZSP.js.map +1 -0
  286. package/dist/shared/hx-form-CkChEATa.js.map +1 -1
  287. package/dist/shared/hx-help-text-CNaZ82LT.js +137 -0
  288. package/dist/shared/hx-help-text-CNaZ82LT.js.map +1 -0
  289. package/dist/shared/hx-icon-button-B2BdVdyK.js.map +1 -1
  290. package/dist/shared/hx-icon-bxz9eB9a.js +386 -0
  291. package/dist/shared/hx-icon-bxz9eB9a.js.map +1 -0
  292. package/dist/shared/{hx-link-CMnZRUtQ.js → hx-link-BURSdYLp.js} +19 -26
  293. package/dist/shared/hx-link-BURSdYLp.js.map +1 -0
  294. package/dist/shared/{hx-menu-divider-A6Guuzi_.js → hx-menu-divider-g0grbWV9.js} +19 -31
  295. package/dist/shared/hx-menu-divider-g0grbWV9.js.map +1 -0
  296. package/dist/shared/{hx-nav-ldFM3Fle.js → hx-nav-GTsAZGOx.js} +94 -85
  297. package/dist/shared/hx-nav-GTsAZGOx.js.map +1 -0
  298. package/dist/shared/{hx-nav-item-CODtUlew.js → hx-nav-item-CxE7Mp3M.js} +46 -41
  299. package/dist/shared/hx-nav-item-CxE7Mp3M.js.map +1 -0
  300. package/dist/shared/{hx-number-input-yUzFOSC1.js → hx-number-input-Bvyc9kOi.js} +59 -64
  301. package/dist/shared/hx-number-input-Bvyc9kOi.js.map +1 -0
  302. package/dist/shared/{hx-overflow-menu-DFjJAziP.js → hx-overflow-menu-LrTteeR1.js} +32 -39
  303. package/dist/shared/{hx-overflow-menu-DFjJAziP.js.map → hx-overflow-menu-LrTteeR1.js.map} +1 -1
  304. package/dist/shared/{hx-phi-field-C19oxlrr.js → hx-phi-field-sZt_rYIL.js} +46 -66
  305. package/dist/shared/hx-phi-field-sZt_rYIL.js.map +1 -0
  306. package/dist/shared/{hx-popover-BAlAFOH9.js → hx-popover-BjB0nkcq.js} +51 -38
  307. package/dist/shared/hx-popover-BjB0nkcq.js.map +1 -0
  308. package/dist/shared/{hx-popup-COUXXZ9X.js → hx-popup-BiV_2evC.js} +59 -45
  309. package/dist/shared/hx-popup-BiV_2evC.js.map +1 -0
  310. package/dist/shared/{hx-radio-CY4kQfZw.js → hx-radio-BD_c9NJy.js} +83 -70
  311. package/dist/shared/hx-radio-BD_c9NJy.js.map +1 -0
  312. package/dist/shared/{hx-rating-C3QP53k9.js → hx-rating-BGK4AxvI.js} +45 -71
  313. package/dist/shared/hx-rating-BGK4AxvI.js.map +1 -0
  314. package/dist/shared/hx-select-DahFehiZ.js.map +1 -1
  315. package/dist/shared/{hx-slider-Blmv_rwS.js → hx-slider-CkOk5BCY.js} +83 -23
  316. package/dist/shared/hx-slider-CkOk5BCY.js.map +1 -0
  317. package/dist/shared/{hx-split-button-Ddle8iVx.js → hx-split-button-Bg9FHrFK.js} +73 -65
  318. package/dist/shared/hx-split-button-Bg9FHrFK.js.map +1 -0
  319. package/dist/shared/{hx-stat-Gtw_SpK8.js → hx-stat-wKxbyep6.js} +22 -55
  320. package/dist/shared/hx-stat-wKxbyep6.js.map +1 -0
  321. package/dist/shared/{hx-step-CUzliIK_.js → hx-step-CyGQAuiB.js} +5 -25
  322. package/dist/shared/hx-step-CyGQAuiB.js.map +1 -0
  323. package/dist/shared/{hx-switch-TvKGvZJz.js → hx-switch-BCXuNxEH.js} +42 -24
  324. package/dist/shared/hx-switch-BCXuNxEH.js.map +1 -0
  325. package/dist/shared/{hx-tab-panel-DzsX8BHV.js → hx-tab-panel-BfisavKo.js} +47 -32
  326. package/dist/shared/hx-tab-panel-BfisavKo.js.map +1 -0
  327. package/dist/shared/{hx-tag-C5aCUpVi.js → hx-tag-BqO6HY6V.js} +26 -21
  328. package/dist/shared/hx-tag-BqO6HY6V.js.map +1 -0
  329. package/dist/shared/{hx-text-input-D6FlOZM-.js → hx-text-input-V5sQOpDh.js} +5 -2
  330. package/dist/shared/hx-text-input-V5sQOpDh.js.map +1 -0
  331. package/dist/shared/hx-textarea-CNG590KY.js.map +1 -1
  332. package/dist/shared/{hx-time-picker-Bo7FWzmf.js → hx-time-picker-if5Cl0Ei.js} +42 -43
  333. package/dist/shared/hx-time-picker-if5Cl0Ei.js.map +1 -0
  334. package/dist/shared/{hx-toggle-button-DSJeFlb0.js → hx-toggle-button-xNVYeA3X.js} +37 -27
  335. package/dist/shared/hx-toggle-button-xNVYeA3X.js.map +1 -0
  336. package/dist/shared/{hx-tooltip-DVqtKPCD.js → hx-tooltip-CamO-9nd.js} +24 -11
  337. package/dist/shared/hx-tooltip-CamO-9nd.js.map +1 -0
  338. package/dist/shared/{hx-top-nav-DP6OFS8C.js → hx-top-nav-vP6oDWMV.js} +42 -44
  339. package/dist/shared/hx-top-nav-vP6oDWMV.js.map +1 -0
  340. package/dist/shared/{hx-tree-item-CXyspGxI.js → hx-tree-item-D8hwKd5m.js} +54 -57
  341. package/dist/shared/hx-tree-item-D8hwKd5m.js.map +1 -0
  342. package/dist/shared/{toast-factory-Dht3pVsw.js → toast-factory-DgnbFxVs.js} +127 -153
  343. package/dist/shared/toast-factory-DgnbFxVs.js.map +1 -0
  344. package/figma-inventory.json +1166 -411
  345. package/package.json +8 -4
  346. package/dist/shared/hx-accordion-ZVzgDzTG.js.map +0 -1
  347. package/dist/shared/hx-action-bar-CitgcpGv.js.map +0 -1
  348. package/dist/shared/hx-alert-Bto8-TIi.js.map +0 -1
  349. package/dist/shared/hx-avatar-C9hOmlAb.js.map +0 -1
  350. package/dist/shared/hx-badge-DFL35nzi.js.map +0 -1
  351. package/dist/shared/hx-banner-fpRnciIO.js.map +0 -1
  352. package/dist/shared/hx-breadcrumb-item-3tKppF9h.js.map +0 -1
  353. package/dist/shared/hx-button-group-4NUBpkyC.js +0 -181
  354. package/dist/shared/hx-button-group-4NUBpkyC.js.map +0 -1
  355. package/dist/shared/hx-button-rRNmD4fd.js.map +0 -1
  356. package/dist/shared/hx-carousel-item-z1Lc24op.js.map +0 -1
  357. package/dist/shared/hx-checkbox-group-D5piJLY8.js.map +0 -1
  358. package/dist/shared/hx-checkbox-hPlIw6Lb.js.map +0 -1
  359. package/dist/shared/hx-clinical-status-D3XQIOqX.js.map +0 -1
  360. package/dist/shared/hx-color-picker-DBwJzT5f.js.map +0 -1
  361. package/dist/shared/hx-combobox-NgJaLbs2.js.map +0 -1
  362. package/dist/shared/hx-copy-button-sUVuikyH.js.map +0 -1
  363. package/dist/shared/hx-date-picker-DSKDkCy1.js.map +0 -1
  364. package/dist/shared/hx-drawer-CM_upadk.js.map +0 -1
  365. package/dist/shared/hx-dropdown-D626S2ZG.js.map +0 -1
  366. package/dist/shared/hx-file-upload-D3rKROK5.js.map +0 -1
  367. package/dist/shared/hx-help-text-Xb2Yr8x2.js +0 -156
  368. package/dist/shared/hx-help-text-Xb2Yr8x2.js.map +0 -1
  369. package/dist/shared/hx-icon-fuVm4-bk.js +0 -283
  370. package/dist/shared/hx-icon-fuVm4-bk.js.map +0 -1
  371. package/dist/shared/hx-link-CMnZRUtQ.js.map +0 -1
  372. package/dist/shared/hx-menu-divider-A6Guuzi_.js.map +0 -1
  373. package/dist/shared/hx-nav-item-CODtUlew.js.map +0 -1
  374. package/dist/shared/hx-nav-ldFM3Fle.js.map +0 -1
  375. package/dist/shared/hx-number-input-yUzFOSC1.js.map +0 -1
  376. package/dist/shared/hx-phi-field-C19oxlrr.js.map +0 -1
  377. package/dist/shared/hx-popover-BAlAFOH9.js.map +0 -1
  378. package/dist/shared/hx-popup-COUXXZ9X.js.map +0 -1
  379. package/dist/shared/hx-radio-CY4kQfZw.js.map +0 -1
  380. package/dist/shared/hx-rating-C3QP53k9.js.map +0 -1
  381. package/dist/shared/hx-slider-Blmv_rwS.js.map +0 -1
  382. package/dist/shared/hx-split-button-Ddle8iVx.js.map +0 -1
  383. package/dist/shared/hx-stat-Gtw_SpK8.js.map +0 -1
  384. package/dist/shared/hx-step-CUzliIK_.js.map +0 -1
  385. package/dist/shared/hx-switch-TvKGvZJz.js.map +0 -1
  386. package/dist/shared/hx-tab-panel-DzsX8BHV.js.map +0 -1
  387. package/dist/shared/hx-tag-C5aCUpVi.js.map +0 -1
  388. package/dist/shared/hx-text-input-D6FlOZM-.js.map +0 -1
  389. package/dist/shared/hx-time-picker-Bo7FWzmf.js.map +0 -1
  390. package/dist/shared/hx-toggle-button-DSJeFlb0.js.map +0 -1
  391. package/dist/shared/hx-tooltip-DVqtKPCD.js.map +0 -1
  392. package/dist/shared/hx-top-nav-DP6OFS8C.js.map +0 -1
  393. package/dist/shared/hx-tree-item-CXyspGxI.js.map +0 -1
  394. package/dist/shared/toast-factory-Dht3pVsw.js.map +0 -1
@@ -1 +0,0 @@
1
- {"version":3,"file":"hx-phi-field-C19oxlrr.js","sources":["../../src/components/hx-phi-field/hx-phi-field.styles.ts","../../src/components/hx-phi-field/hx-phi-field.ts"],"sourcesContent":["import { css } from 'lit';\n\nexport const helixPhiFieldStyles = css`\n :host {\n display: inline-flex;\n }\n\n /* ─── Container ─── */\n\n .phi-field {\n display: inline-flex;\n align-items: center;\n gap: var(--hx-space-2, 0.5rem);\n font-family: var(--hx-phi-field-font-family, var(--hx-font-family-mono, monospace));\n }\n\n /* ─── Value ─── */\n\n .phi-field__value--masked {\n user-select: none;\n -webkit-user-select: none;\n color: var(--hx-phi-field-masked-color, var(--hx-color-text-muted, #4a5362));\n letter-spacing: var(--hx-phi-field-letter-spacing, 0.1em);\n }\n\n .phi-field__value--revealed {\n color: var(--hx-phi-field-value-color, var(--hx-color-text-primary, #0d1825));\n }\n\n /* ─── Screen Reader Status ─── */\n\n .phi-field__status {\n position: absolute;\n width: 1px;\n height: 1px;\n overflow: hidden;\n clip: rect(0, 0, 0, 0);\n white-space: nowrap;\n border: 0;\n padding: 0;\n margin: -1px;\n }\n\n /* ─── Toggle Button ─── */\n\n .phi-field__toggle {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n background: none;\n border: none;\n padding: var(--hx-space-1, 0.25rem);\n min-width: var(--hx-touch-target-min, 2.75rem);\n min-height: var(--hx-touch-target-min, 2.75rem);\n color: var(--hx-phi-field-toggle-color, var(--hx-color-primary-500, #429797));\n cursor: pointer;\n line-height: 1;\n border-radius: var(--hx-border-radius-sm, 0.25rem);\n }\n\n .phi-field__toggle:focus-visible {\n outline: var(--hx-focus-ring-width, 2px) solid\n var(--hx-phi-field-focus-ring-color, var(--hx-focus-ring-color, #0f7078));\n outline-offset: var(--hx-focus-ring-offset, 2px);\n }\n\n .phi-field__toggle:hover {\n opacity: var(--hx-opacity-90, 0.9);\n }\n\n .phi-field__toggle:active {\n opacity: var(--hx-opacity-50, 0.5);\n }\n\n .phi-field__toggle svg {\n width: 1em;\n height: 1em;\n pointer-events: none;\n }\n\n /* ─── Disabled State ─── */\n\n :host([disabled]) {\n opacity: var(--hx-phi-field-disabled-opacity, var(--hx-opacity-50, 0.5));\n pointer-events: none;\n cursor: not-allowed;\n }\n\n .phi-field--disabled .phi-field__toggle {\n cursor: not-allowed;\n }\n\n /* ─── Reduced Motion ─── */\n\n @media (prefers-reduced-motion: reduce) {\n .phi-field__toggle {\n transition: none;\n }\n }\n\n /* ─── Forced Colors (Windows High Contrast Mode) ─── */\n\n @media (forced-colors: active) {\n .phi-field__toggle {\n border: 1px solid ButtonText;\n forced-color-adjust: none;\n }\n\n .phi-field__toggle:focus-visible {\n outline: 2px solid Highlight;\n outline-offset: 2px;\n }\n }\n`;\n","import { html, type TemplateResult } from 'lit';\nimport { classMap } from 'lit/directives/class-map.js';\nimport '../../utilities/document-token-adoption.js';\nimport { customElement, property, state } from 'lit/decorators.js';\nimport { HelixElement } from '../../base/index.js';\nimport { helixPhiFieldStyles } from './hx-phi-field.styles.js';\nimport { forcedColorsField } from '../../styles/forced-colors.js';\nimport { devWarn } from '../../utils/dev-warn.js';\n\n/**\n * HIPAA-compliant field component for rendering masked Protected Health Information (PHI).\n * PHI is masked by default and only rendered to the DOM when explicitly revealed. Access\n * events are fired on reveal, hide, and clipboard auto-clear for audit trail purposes.\n *\n * ## Security Model — Event Composition\n *\n * The `hx-phi-access` event is dispatched with `composed: true` so it crosses shadow DOM\n * boundaries and reaches application-level audit listeners. This is intentional — audit\n * trail events MUST reach the host application regardless of shadow DOM nesting depth.\n *\n * **PHI is never included in event details.** The `PhiAccessEventDetail` payload contains\n * only audit metadata: `fieldId`, `action`, `timestamp`, and `fieldType`. The actual PHI\n * value (the `data` property) is deliberately excluded from all dispatched events.\n *\n * ### Consumer Responsibilities\n *\n * - **Audit logging**: Listen for `hx-phi-access` at the application root to build a\n * HIPAA-compliant access audit trail. The `fieldId` and `timestamp` fields correlate\n * access events to specific data elements without exposing the data itself.\n * - **Multi-tenant isolation**: In micro-frontend architectures where multiple patient\n * contexts share a document, consumers MUST scope their `hx-phi-access` listeners to\n * the appropriate DOM subtree (e.g., listen on a container element rather than\n * `document`). Composed events from one patient context will bubble through shared\n * ancestors.\n * - **Do not extend event details with PHI**: When wrapping this component, never add\n * the raw `data` value to re-dispatched events. The separation of audit metadata from\n * PHI content is a deliberate security boundary.\n *\n * @summary HIPAA-compliant field for rendering masked Protected Health Information.\n *\n * @tag hx-phi-field\n *\n * @csspart container - The outer wrapper element.\n * @csspart value - The value display span (masked or revealed).\n * @csspart toggle - The reveal/hide toggle button.\n *\n * @fires {CustomEvent<PhiAccessEventDetail>} hx-phi-access - Fired on reveal, hide,\n * auto-hide, clipboard-clear, and clipboard-clear-failed actions. Contains audit\n * metadata only — never raw PHI. Dispatched with `composed: true` to cross shadow\n * boundaries for application-level audit listeners.\n *\n * @cssprop [--hx-phi-field-font-family=var(--hx-font-family-mono,monospace)] - Font family for the masked value.\n * @cssprop [--hx-phi-field-value-color=var(--hx-color-neutral-900,#0D1825)] - Value text color.\n * @cssprop [--hx-phi-field-masked-color=var(--hx-color-neutral-500,#66787B)] - Masked value text color.\n * @cssprop [--hx-phi-field-toggle-color=var(--hx-color-primary-500,#429797)] - Toggle button color.\n * @cssprop [--hx-phi-field-focus-ring-color=var(--hx-focus-ring-color,var(--hx-color-primary-500,#429797))] - Focus ring color.\n * @cssprop [--hx-phi-field-disabled-opacity=var(--hx-opacity-50,0.5)] - Opacity applied when the field is disabled.\n * @cssprop [--hx-space-2] - Spacing token.\n * @cssprop [--hx-font-family-mono] - Font family.\n * @cssprop [--hx-color-neutral-500] - Color.\n * @cssprop [--hx-phi-field-letter-spacing=0.1em] - CSS custom property.\n * @cssprop [--hx-color-neutral-900] - Color.\n * @cssprop [--hx-space-1] - Spacing token.\n * @cssprop [--hx-touch-target-min] - Minimum touch target size.\n * @cssprop [--hx-color-primary-500] - Color.\n * @cssprop [--hx-border-radius-sm] - CSS custom property.\n * @cssprop [--hx-focus-ring-width] - Width.\n * @cssprop [--hx-focus-ring-color] - Color.\n * @cssprop [--hx-focus-ring-offset] - CSS custom property.\n * @cssprop [--hx-opacity-90] - Opacity.\n * @cssprop [--hx-opacity-50] - Opacity.\n */\n@customElement('hx-phi-field')\nexport class HelixPhiField extends HelixElement {\n static override styles = [helixPhiFieldStyles, forcedColorsField];\n\n // ─── Public Properties ───\n\n /**\n * The Protected Health Information value to display or mask.\n * Must be set via the JavaScript property (`element.data = \"...\"`) — not as an HTML attribute.\n * Setting PHI as an HTML attribute exposes it in the DOM and browser caches (HIPAA violation).\n */\n @property({ attribute: false })\n data: string = '';\n\n /**\n * The type of PHI field. Controls the masking pattern applied.\n * @attr field-type\n */\n @property({ type: String, reflect: true, attribute: 'field-type' })\n fieldType: 'ssn' | 'mrn' | 'dob' | 'insurance' = 'ssn';\n\n /**\n * Identifier used in audit events. Falls back to the element's id attribute.\n * @attr field-id\n */\n @property({ type: String, attribute: 'field-id' })\n fieldId: string = '';\n\n /**\n * Milliseconds after clipboard write before the clipboard is automatically cleared.\n * Defaults to 30000 (30 seconds).\n * @attr clipboard-timeout\n */\n @property({ type: Number, attribute: 'clipboard-timeout' })\n clipboardTimeout: number = 30000;\n\n /**\n * Accessible label describing the PHI field. Used as a prefix in screen reader\n * announcements (e.g., \"Social Security Number is masked\").\n * @attr label\n */\n @property({ type: String })\n label: string = '';\n\n /**\n * Seconds of inactivity after reveal before PHI is automatically re-masked.\n * Prevents PHI from remaining visible indefinitely when a clinician walks away.\n * Set to 0 to disable auto-hide. Defaults to 60 seconds.\n * @attr auto-hide-delay\n */\n @property({ type: Number, attribute: 'auto-hide-delay' })\n autoHideDelay: number = 60;\n\n /**\n * When set, disables all interaction with the field and prevents reveal.\n * @attr disabled\n * @reflect\n */\n @property({ type: Boolean, reflect: true })\n disabled: boolean = false;\n\n // ─── Internal State ───\n\n /** @internal */\n @state() private _masked = true;\n\n /** @internal */\n private _clipboardTimer: ReturnType<typeof setTimeout> | null = null;\n\n /** @internal Timer ID for auto-re-mask after reveal. */\n private _autoHideTimer: ReturnType<typeof setTimeout> | null = null;\n\n // ─── Lifecycle ───\n\n /** @internal Bound reference for visibilitychange listener cleanup. */\n private readonly _boundHandleVisibilityChange = (): void => {\n if (document.visibilityState !== 'hidden') return;\n // Only clear if the field has been revealed (unmasked) or an active\n // clipboard-clear timer is running. Otherwise there's nothing to clear,\n // and emitting hx-phi-access with action: 'clipboard-clear' would pollute\n // the HIPAA audit log with events for fields that were never accessed.\n if (this._masked && this._clipboardTimer === null) return;\n this._clearClipboard();\n };\n\n /** @internal Bound reference for interaction-based auto-hide timer reset. */\n private readonly _boundResetAutoHideTimer = (): void => {\n this._resetAutoHideTimer();\n };\n\n override connectedCallback(): void {\n super.connectedCallback();\n // Enforce HIPAA compliance: prevent browser autofill on the host element\n this.setAttribute('autocomplete', 'off');\n // HIPAA: Clear clipboard immediately when tab is hidden (prevents PHI exposure\n // when setTimeout is throttled in backgrounded tabs on mobile/laptop lid close).\n document.addEventListener('visibilitychange', this._boundHandleVisibilityChange);\n // FS-029: PHI SSR/attribute exposure prevention.\n // If a developer (or server-rendered HTML) mistakenly sets PHI via the\n // `data` HTML attribute, the raw value is readable in the DOM source before\n // JavaScript initialises — a HIPAA risk on SSR pages. We recover the value\n // into the JS-only property and then immediately remove the attribute so\n // that no PHI is ever left exposed in the DOM tree or HTML source.\n if (this.hasAttribute('data')) {\n devWarn(\n 'hx-phi-field',\n 'Setting PHI via the `data` HTML attribute is not supported and exposes sensitive data in the DOM source. Use the `data` JS property (element.data = \"...\") instead.',\n );\n // Rescue the value into the private property so the component still works,\n // then strip the attribute so the raw PHI is no longer readable in the DOM.\n const rawValue = this.getAttribute('data');\n if (rawValue !== null) {\n this.data = rawValue;\n }\n this.removeAttribute('data');\n }\n }\n\n override disconnectedCallback(): void {\n super.disconnectedCallback();\n this._cancelClipboardTimer();\n this._cancelAutoHideTimer();\n document.removeEventListener('visibilitychange', this._boundHandleVisibilityChange);\n }\n\n // ─── Private Helpers ───\n\n /** @internal */\n private _cancelClipboardTimer(): void {\n if (this._clipboardTimer !== null) {\n clearTimeout(this._clipboardTimer);\n this._clipboardTimer = null;\n }\n }\n\n /** @internal Cancel the auto-hide timer if running. */\n private _cancelAutoHideTimer(): void {\n if (this._autoHideTimer !== null) {\n clearTimeout(this._autoHideTimer);\n this._autoHideTimer = null;\n }\n this._removeAutoHideInteractionListeners();\n }\n\n /** @internal Start the auto-hide countdown. Resets if already running. */\n private _scheduleAutoHide(): void {\n this._cancelAutoHideTimer();\n if (this.autoHideDelay <= 0) return;\n\n this._addAutoHideInteractionListeners();\n this._autoHideTimer = setTimeout(() => {\n this._autoHideTimer = null;\n this._autoHide();\n }, this.autoHideDelay * 1000);\n }\n\n /** @internal Reset the auto-hide timer on user interaction. */\n private _resetAutoHideTimer(): void {\n if (this._autoHideTimer === null) return;\n this._scheduleAutoHide();\n }\n\n /** @internal Auto-hide PHI and dispatch audit event. */\n private _autoHide(): void {\n if (this._masked) return;\n\n this._removeAutoHideInteractionListeners();\n // Do NOT cancel the clipboard-clear timer — same reasoning as the manual\n // hide branch of `_handleToggle`. A reveal may have resulted in a copy,\n // and cancelling the scheduled clear would leave PHI on the clipboard\n // past the auto-hide ceiling.\n this._masked = true;\n\n this.dispatchEvent(\n new CustomEvent<PhiAccessEventDetail>('hx-phi-access', {\n bubbles: true,\n composed: true,\n detail: {\n fieldId: this.fieldId || this.id || '',\n action: 'auto-hide',\n timestamp: new Date().toISOString(),\n fieldType: this.fieldType,\n },\n }),\n );\n }\n\n /** @internal Interaction events that reset the auto-hide timer. */\n private static readonly _AUTO_HIDE_INTERACTION_EVENTS = [\n 'mouseenter',\n 'mousemove',\n 'focusin',\n 'keydown',\n 'pointerdown',\n ] as const;\n\n /** @internal Add interaction listeners to reset auto-hide timer. */\n private _addAutoHideInteractionListeners(): void {\n for (const event of HelixPhiField._AUTO_HIDE_INTERACTION_EVENTS) {\n this.addEventListener(event, this._boundResetAutoHideTimer);\n }\n }\n\n /** @internal Remove interaction listeners. */\n private _removeAutoHideInteractionListeners(): void {\n for (const event of HelixPhiField._AUTO_HIDE_INTERACTION_EVENTS) {\n this.removeEventListener(event, this._boundResetAutoHideTimer);\n }\n }\n\n /** @internal */\n private _scheduleClipboardClear(): void {\n this._cancelClipboardTimer();\n this._clipboardTimer = setTimeout(() => {\n this._clearClipboard();\n }, this.clipboardTimeout);\n }\n\n /** @internal */\n private _clearClipboard(): void {\n // Cancel any pending scheduled clear. When `_clearClipboard` is invoked\n // from the setTimeout callback the timer has already fired and this is a\n // no-op; when invoked from the visibilitychange pre-emption path it stops\n // the scheduled timer from firing again and dispatching a duplicate\n // clipboard-clear audit event.\n this._cancelClipboardTimer();\n // Also cancel the auto-hide timer and remove its interaction listeners.\n // `_clearClipboard` force-masks the field below, so any scheduled auto-hide\n // is now moot. Without this call the setTimeout stays pending and the\n // `mouseenter / mousemove / focusin / keydown / pointerdown` listeners\n // stay attached to the host; when the auto-hide timer later fires,\n // `_autoHide()` early-returns on `this._masked` WITHOUT removing the\n // listeners, leaking them until the next scheduleAutoHide/cancelAutoHideTimer\n // path runs. `_cancelAutoHideTimer` already closes both — one call suffices.\n this._cancelAutoHideTimer();\n this._masked = true;\n\n // `navigator.clipboard.writeText` requires transient user activation in\n // Chrome and Safari. The clipboard-clear timer fires async (activation\n // expired) and the visibilitychange pre-emption path has no activation\n // at all — both can reject silently. Dispatching an unconditional\n // clipboard-clear audit event in that case would be MISLEADING: the\n // audit trail would claim PHI was cleared while it in fact remains on\n // the clipboard. Instead we observe the writeText outcome and dispatch\n // `clipboard-clear` only on confirmed success, or `clipboard-clear-failed`\n // when the API is unavailable or the promise rejects. This gives\n // HIPAA audit consumers an accurate signal and lets them escalate\n // failures (prompt the user, flag the session, etc).\n const dispatchOutcome = (succeeded: boolean): void => {\n this.dispatchEvent(\n new CustomEvent<PhiAccessEventDetail>('hx-phi-access', {\n bubbles: true,\n composed: true,\n detail: {\n fieldId: this.fieldId || this.id || '',\n action: succeeded ? 'clipboard-clear' : 'clipboard-clear-failed',\n timestamp: new Date().toISOString(),\n fieldType: this.fieldType,\n },\n }),\n );\n };\n\n if (typeof navigator === 'undefined') {\n dispatchOutcome(false);\n return;\n }\n\n // Every remaining clipboard interaction — including the `navigator.clipboard`\n // read itself — runs inside this try. The Clipboard API's property descriptor\n // is UA-defined, so `navigator.clipboard` can legally be an accessor that\n // throws synchronously. Same for `clipboard.writeText`. Pulling the read\n // inside the try ensures any sync throw resolves to `clipboard-clear-failed`\n // instead of an uncaught error that would silently drop the HIPAA audit event.\n //\n // `navigator.clipboard` is captured exactly once and the same reference is\n // used for both the method read and the call's receiver. A shim that exposes\n // `navigator.clipboard` as a getter returning a fresh object per read (rare\n // but legal) would otherwise let us grab `writeText` from object A and invoke\n // it against object B — brand/instance checks inside a real polyfill would\n // then fail and the call would reject spuriously.\n //\n // Promise.resolve() on a non-thenable still resolves, so the then() path\n // normalizes the return value shape for us.\n try {\n const clipboard = navigator.clipboard;\n if (!clipboard) {\n dispatchOutcome(false);\n return;\n }\n const writeText = clipboard.writeText;\n if (typeof writeText !== 'function') {\n dispatchOutcome(false);\n return;\n }\n void Promise.resolve(writeText.call(clipboard, '')).then(\n () => dispatchOutcome(true),\n () => dispatchOutcome(false),\n );\n } catch {\n dispatchOutcome(false);\n }\n }\n\n /** @internal */\n private _getMaskedValue(): string {\n if (!this.data) return '';\n\n switch (this.fieldType) {\n case 'ssn': {\n // Format: xxx-xx-xxxx → ***-**-xxxx (show last 4 digits)\n // Match the separator-delimited pattern first\n const ssnMatch = this.data.match(/^(\\d{3})(-?)(\\d{2})(-?)(\\d{4})$/);\n if (ssnMatch) {\n return `***${ssnMatch[2]}**${ssnMatch[4]}${ssnMatch[5]}`;\n }\n // Fallback: mask all but last 4 chars\n return this.data.slice(0, -4).replace(/\\d/g, '*') + this.data.slice(-4);\n }\n\n case 'mrn': {\n // Mask all but last 4 alphanumeric characters, preserve separators\n const chars = this.data.split('');\n const alphanumericIndices: number[] = [];\n chars.forEach((ch, i) => {\n if (/[a-zA-Z0-9]/.test(ch)) {\n alphanumericIndices.push(i);\n }\n });\n const revealCount = Math.min(4, alphanumericIndices.length);\n const maskUntilIdx = alphanumericIndices.length - revealCount;\n const indicesToMask = new Set(alphanumericIndices.slice(0, maskUntilIdx));\n return chars.map((ch, i) => (indicesToMask.has(i) ? '*' : ch)).join('');\n }\n\n case 'dob': {\n // Replace ALL digits with *, preserve separators\n return this.data.replace(/\\d/g, '*');\n }\n\n case 'insurance': {\n // Format: xxxx-xxxx-xxxx-xxxx → ****-****-****-xxxx (show last 4 digits)\n const insMatch = this.data.match(/^(\\d{4})(-?)(\\d{4})(-?)(\\d{4})(-?)(\\d{4})$/);\n if (insMatch) {\n return `****${insMatch[2]}****${insMatch[4]}****${insMatch[6]}${insMatch[7]}`;\n }\n // Fallback: mask all but last 4 chars\n return this.data.slice(0, -4).replace(/[a-zA-Z0-9]/g, '*') + this.data.slice(-4);\n }\n\n default: {\n // Exhaustive check — fieldType is typed, but guard defensively\n const _exhaustive: never = this.fieldType;\n return _exhaustive;\n }\n }\n }\n\n // ─── Event Handlers ───\n\n /** @internal */\n private _handleToggle(): void {\n if (this.disabled) return;\n\n // Dispatch BEFORE toggling state so action reflects the upcoming state\n this.dispatchEvent(\n new CustomEvent<PhiAccessEventDetail>('hx-phi-access', {\n bubbles: true,\n composed: true,\n detail: {\n fieldId: this.fieldId || this.id || '',\n action: this._masked ? 'reveal' : 'hide',\n timestamp: new Date().toISOString(),\n fieldType: this.fieldType,\n },\n }),\n );\n\n if (this._masked) {\n // Revealing: start clipboard clear timer and auto-hide timer\n this._masked = false;\n this._scheduleClipboardClear();\n this._scheduleAutoHide();\n } else {\n // Hiding: cancel the auto-hide countdown (purpose already served — the\n // field is hidden). Do NOT cancel the clipboard-clear timer — the user\n // may have copied PHI while the field was revealed, and cancelling here\n // would strand it on the clipboard if the tab later backgrounds. The\n // timer fires naturally at `clipboardTimeout`, and the visibilitychange\n // handler will pre-empt it if the tab hides sooner.\n this._cancelAutoHideTimer();\n this._masked = true;\n }\n }\n\n /** @internal */\n private _handleCopy(e: ClipboardEvent): void {\n if (this._masked) {\n e.preventDefault();\n }\n }\n\n /** @internal */\n private _handlePaste(e: ClipboardEvent): void {\n if (this._masked) {\n e.preventDefault();\n }\n }\n\n // ─── Render Helpers ───\n\n /** @internal */\n private _renderEyeIcon(): TemplateResult {\n return html`\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n aria-hidden=\"true\"\n >\n <path d=\"M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z\" />\n <circle cx=\"12\" cy=\"12\" r=\"3\" />\n </svg>\n `;\n }\n\n /** @internal */\n private _renderEyeOffIcon(): TemplateResult {\n return html`\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n aria-hidden=\"true\"\n >\n <path d=\"M17.94 17.94A10.07 10.07 0 0 1 12 20c-7 0-11-8-11-8a18.45 18.45 0 0 1 5.06-5.94\" />\n <path d=\"M9.9 4.24A9.12 9.12 0 0 1 12 4c7 0 11 8 11 8a18.5 18.5 0 0 1-2.16 3.19\" />\n <line x1=\"1\" y1=\"1\" x2=\"23\" y2=\"23\" />\n </svg>\n `;\n }\n\n // ─── Render ───\n\n override render() {\n const fieldLabel = this.label || 'Protected health information';\n const maskedLabel = `${fieldLabel} is masked`;\n const revealedLabel = `${fieldLabel} is revealed`;\n const revealActionLabel = `Reveal ${fieldLabel.toLowerCase()}`;\n const hideActionLabel = `Hide ${fieldLabel.toLowerCase()}`;\n\n return html`\n <div\n part=\"container\"\n class=${classMap({ 'phi-field': true, 'phi-field--disabled': this.disabled })}\n @copy=${this._handleCopy}\n @paste=${this._handlePaste}\n >\n ${this._masked\n ? html`<span\n part=\"value\"\n class=\"phi-field__value phi-field__value--masked\"\n aria-hidden=\"true\"\n >${this._getMaskedValue()}</span\n >`\n : html`<span part=\"value\" class=\"phi-field__value phi-field__value--revealed\"\n >${this.data}</span\n >`}\n <span role=\"status\" aria-live=\"polite\" aria-atomic=\"true\" class=\"phi-field__status\">\n ${this._masked ? maskedLabel : revealedLabel}\n </span>\n <button\n part=\"toggle\"\n class=\"phi-field__toggle\"\n type=\"button\"\n ?disabled=${this.disabled}\n aria-label=${this._masked ? revealActionLabel : hideActionLabel}\n aria-pressed=${String(!this._masked)}\n @click=${this._handleToggle}\n >\n ${this._masked ? this._renderEyeIcon() : this._renderEyeOffIcon()}\n </button>\n </div>\n `;\n }\n}\n\n/**\n * Audit metadata for PHI access events. This interface intentionally contains\n * only identifiers and action metadata — never raw PHI values. The separation\n * of audit trail data from PHI content is a deliberate HIPAA security boundary.\n *\n * **Security invariant**: No field in this interface should ever contain the\n * actual protected health information (SSN digits, MRN value, date of birth,\n * insurance number). The `fieldId` is a developer-assigned logical identifier,\n * not the PHI value itself.\n */\nexport interface PhiAccessEventDetail {\n /** Developer-assigned logical identifier for the field (NOT the PHI value). */\n fieldId: string;\n /**\n * The action that triggered the audit event.\n *\n * - `clipboard-clear`: `navigator.clipboard.writeText('')` resolved successfully\n * — the clipboard has been confirmed cleared.\n * - `clipboard-clear-failed`: the clipboard API was unavailable OR `writeText('')`\n * rejected (most commonly because the browser required transient user\n * activation that the timer or visibilitychange pre-emption path did not\n * provide). The clipboard MAY still contain PHI. HIPAA audit consumers\n * should treat this as an actionable event — prompt the user to manually\n * clear their clipboard, flag the session, or escalate per policy.\n */\n action: 'reveal' | 'hide' | 'auto-hide' | 'clipboard-clear' | 'clipboard-clear-failed';\n /** ISO 8601 timestamp of the access event. */\n timestamp: string;\n /** The category of PHI this field contains. */\n fieldType: 'ssn' | 'mrn' | 'dob' | 'insurance';\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'hx-phi-field': HelixPhiField;\n }\n}\n"],"names":["helixPhiFieldStyles","css","HelixPhiField","HelixElement","rawValue","event","dispatchOutcome","succeeded","clipboard","writeText","ssnMatch","chars","alphanumericIndices","ch","i","revealCount","maskUntilIdx","indicesToMask","insMatch","html","fieldLabel","maskedLabel","revealedLabel","revealActionLabel","hideActionLabel","classMap","forcedColorsField","__decorateClass","property","state","customElement"],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"hx-popover-BAlAFOH9.js","sources":["../../src/components/hx-popover/hx-popover.styles.ts","../../src/components/hx-popover/hx-popover.ts"],"sourcesContent":["import { css } from 'lit';\n\n/**\n * hx-popover styles.\n *\n * Component-tier tokens with two-level var() fallback:\n * var(--hx-popover-{prop}, var(--hx-color-{semantic}, #hex))\n * Inner hex fallbacks track the \"precision cool\" palette (3.2.0):\n * neutral-0 = #FFFFFF, neutral-200 = #D6DBD5, neutral-900 = #0D1825,\n * primary-500 = #429797.\n */\nexport const helixPopoverStyles = css`\n :host {\n /* P2-05: display:contents lets the trigger-wrapper control layout inline;\n position:relative was vestigial — body uses position:fixed via Floating UI */\n display: contents;\n }\n\n .trigger-wrapper {\n display: inline-block;\n }\n\n [part='body'] {\n position: fixed;\n z-index: var(--hx-popover-z-index, 9999);\n max-width: var(--hx-popover-max-width, 320px);\n padding: var(--hx-popover-padding, var(--hx-space-3, 0.75rem));\n background: var(--hx-popover-bg, var(--hx-color-surface-default, #ffffff));\n color: var(--hx-popover-color, var(--hx-color-text-primary, #0d1825));\n font-family: var(--hx-popover-font-family, var(--hx-font-family-sans, sans-serif));\n font-size: var(--hx-popover-font-size, var(--hx-font-size-sm, 0.875rem));\n line-height: var(--hx-line-height-normal, 1.5);\n border: 1px solid var(--hx-popover-border-color, var(--hx-color-border-default, #d6dbd5));\n border-radius: var(--hx-popover-border-radius, var(--hx-border-radius-md, 0.375rem));\n box-shadow: var(\n --hx-popover-shadow,\n var(--hx-shadow-md, 0 4px 16px var(--hx-overlay-black-12, rgba(0, 0, 0, 0.12)))\n );\n visibility: hidden;\n opacity: 0;\n transition:\n opacity var(--hx-popover-transition-duration, 0.2s) ease,\n visibility var(--hx-popover-transition-duration, 0.2s) ease;\n word-wrap: break-word;\n }\n\n [part='body'].visible {\n visibility: visible;\n opacity: 1;\n }\n\n [part='body']:focus-visible {\n outline: var(--hx-focus-ring-width, 2px) solid\n var(--hx-popover-focus-ring-color, var(--hx-focus-ring-color, #0f7078));\n outline-offset: var(--hx-focus-ring-offset, 2px);\n }\n\n [part='arrow'] {\n position: absolute;\n width: var(--hx-popover-arrow-size, 10px);\n height: var(--hx-popover-arrow-size, 10px);\n background: var(--hx-popover-bg, var(--hx-color-surface-default, #ffffff));\n border: 1px solid var(--hx-popover-border-color, var(--hx-color-border-default, #d6dbd5));\n transform: rotate(45deg);\n pointer-events: none;\n }\n\n @media (prefers-reduced-motion: reduce) {\n [part='body'] {\n transition: none;\n }\n }\n\n /* ─── Forced Colors (Windows High Contrast) ─── */\n /* Belt-and-suspenders: rich per-class HC overrides PLUS the forcedColorsSurface mixin. */\n\n @media (forced-colors: active) {\n [part='body'] {\n border-color: CanvasText;\n }\n\n [part='arrow'] {\n border-color: CanvasText;\n }\n }\n`;\n","import { html, nothing, type PropertyValues } from 'lit';\nimport '../../utilities/document-token-adoption.js';\nimport { customElement, property, state } from 'lit/decorators.js';\nimport { HelixElement, createIdCounter } from '../../base/index.js';\nimport { helixPopoverStyles } from './hx-popover.styles.js';\nimport { forcedColorsSurface } from '../../styles/forced-colors.js';\nimport { flattenAccName } from '../../utils/aria-flatten.js';\nimport {\n installAriaIdrefMirror,\n resolveIdrefTokens,\n type AriaIdrefMirrorHandle,\n} from '../../utils/aria-idref.js';\n\nconst _nextPopoverId = createIdCounter('hx-popover');\n\n/**\n * A popover that displays rich floating content attached to a trigger element.\n *\n * ## Architecture Note: Host-Attribute Label Mirror (group-4 round-1)\n *\n * Unlike modal dialogs (`hx-dialog` / `hx-drawer`) where the HOST is the\n * announced surface and `ElementInternals` projects consumer IDREFs across\n * the shadow boundary, `hx-popover`'s announced surface is the inner\n * `[part=\"body\"]` element which carries `role=\"dialog\"`. The host does not\n * claim a role — it is a structural wrapper around an anchor slot and a\n * separate floating panel.\n *\n * IDL element references on `internals.ariaLabelledByElements` therefore\n * cannot help: AT walks the inner body's accessibility node, and IDL refs\n * declared on the host are not visible from a shadow-internal descendant\n * looking up. The viable cross-shadow path is the host-attribute mirror:\n *\n * 1. The host observes `aria-label` / `aria-labelledby` mutations.\n * 2. On every sync, `aria-labelledby` IDREFs are resolved via\n * `resolveIdrefTokens` (composed-tree walk: host root → ancestor\n * shadow hosts → owner document) and **text-flattened** via\n * `flattenAccName` (AccName 1.2 §4.3.10 hidden-aware).\n * 3. The flattened name is written to the inner body's `aria-label`,\n * overriding the `label` property only when consumer naming is set.\n *\n * Naming precedence (W3C AccName 1.2 §4.3.1):\n *\n * 1. Host `aria-labelledby` (resolved IDREFs, text-flattened)\n * 2. Host `aria-label`\n * 3. `label` property\n * 4. Hard-coded literal `\"Popover\"` (last-resort accessible name)\n *\n * The text-flatten approach forfeits live IDL-ref tracking (mutating a\n * referenced element's text re-fires through the shared root observer; see\n * `installAriaIdrefMirror`). `aria-controls` is intentionally omitted on\n * the trigger — the body lives in shadow DOM and consumer IDREFs cannot\n * resolve cross-root from light-DOM (axe-core flags this as a critical\n * violation if attempted; see line documenting this exception below).\n *\n * Slotted label support (e.g. `<slot name=\"title\">`) is deliberately NOT\n * added in this round — it would expand the public API surface and is\n * tracked as a follow-up enhancement.\n *\n * @summary Rich floating overlay attached to a trigger element.\n *\n * @tag hx-popover\n *\n * @slot anchor - The trigger element that opens the popover.\n * @slot - Default slot for popover body content.\n *\n * @csspart body - The popover body container element.\n * @csspart arrow - The arrow indicator element.\n *\n * @cssprop [--hx-popover-bg=var(--hx-color-neutral-0)] - Popover background color.\n * @cssprop [--hx-popover-color=var(--hx-color-neutral-900)] - Popover text color.\n * @cssprop [--hx-popover-font-size=var(--hx-font-size-sm)] - Popover font size.\n * @cssprop [--hx-popover-max-width=320px] - Maximum popover width.\n * @cssprop [--hx-popover-padding] - Popover padding.\n * @cssprop [--hx-popover-border-color=var(--hx-color-neutral-200)] - Popover border color.\n * @cssprop [--hx-popover-border-radius=var(--hx-border-radius-md)] - Popover border radius.\n * @cssprop [--hx-popover-shadow] - Popover box shadow.\n * @cssprop [--hx-popover-z-index=9999] - Popover z-index.\n * @cssprop [--hx-popover-transition-duration=0.2s] - Show/hide transition duration.\n * @cssprop [--hx-popover-arrow-size=10px] - Size of the arrow indicator.\n * @cssprop [--hx-popover-focus-ring-color=var(--hx-focus-ring-color)] - Focus ring color when the popover body receives focus.\n *\n * @fires {CustomEvent} hx-show - Emitted when the popover begins to show.\n * @fires {CustomEvent} hx-after-show - Emitted after the popover is fully visible.\n * @fires {CustomEvent} hx-hide - Emitted when the popover begins to hide.\n * @fires {CustomEvent} hx-after-hide - Emitted after the popover is fully hidden.\n *\n * @example\n * ```html\n * <hx-popover placement=\"bottom\" trigger=\"click\">\n * <button slot=\"anchor\">Open Popover</button>\n * <p>Rich popover content here.</p>\n * </hx-popover>\n * ```\n * @cssprop [--hx-popover-font-family=var(--hx-font-family-sans)] - CSS custom property.\n * @cssprop [--hx-space-3] - Spacing token.\n * @cssprop [--hx-color-neutral-0] - Color.\n * @cssprop [--hx-color-neutral-900] - Color.\n * @cssprop [--hx-font-family-sans] - Font family.\n * @cssprop [--hx-font-size-sm] - Font size.\n * @cssprop [--hx-line-height-normal] - Line height.\n * @cssprop [--hx-color-neutral-200] - Color.\n * @cssprop [--hx-border-radius-md] - CSS custom property.\n * @cssprop [--hx-shadow-md] - Box shadow.\n * @cssprop [--hx-overlay-black-12] - Overlay color.\n * @cssprop [--hx-focus-ring-width] - Width.\n * @cssprop [--hx-focus-ring-color] - Color.\n * @cssprop [--hx-color-primary-500] - Color.\n * @cssprop [--hx-focus-ring-offset] - CSS custom property.\n */\n\n@customElement('hx-popover')\nexport class HelixPopover extends HelixElement {\n static override styles = [helixPopoverStyles, forcedColorsSurface];\n\n /**\n * Whether the popover is open.\n * @attr open\n */\n @property({ type: Boolean, reflect: true })\n open = false;\n\n /**\n * Preferred placement of the popover relative to the anchor.\n * @attr placement\n */\n @property({ type: String, reflect: true })\n placement:\n | 'top'\n | 'top-start'\n | 'top-end'\n | 'right'\n | 'right-start'\n | 'right-end'\n | 'bottom'\n | 'bottom-start'\n | 'bottom-end'\n | 'left'\n | 'left-start'\n | 'left-end' = 'bottom';\n\n /**\n * How the popover is triggered.\n * @attr trigger\n */\n @property({ type: String, reflect: true })\n trigger: 'click' | 'hover' | 'focus' | 'manual' = 'click';\n\n /**\n * Distance in pixels between the popover and the anchor.\n * @attr distance\n */\n @property({ type: Number, reflect: true })\n distance = 8;\n\n /**\n * Alignment offset in pixels along the anchor.\n * @attr skidding\n */\n @property({ type: Number, reflect: true })\n skidding = 0;\n\n /**\n * Whether to show an arrow pointing to the anchor.\n * @attr arrow\n */\n @property({ type: Boolean, reflect: true })\n arrow = false;\n\n /**\n * Accessible label for the popover body (sets aria-label on the dialog).\n * @attr label\n */\n @property({ type: String, reflect: true })\n label = 'Popover';\n\n /**\n * Tracks whether the popover body is currently visible.\n * @internal\n */\n @state() private _visible = false;\n\n /**\n * Resolved accessible name for the popover body — the value written to\n * the inner `[part=\"body\"]` `aria-label`. Recomputed on every sync per\n * the AccName 1.2 §4.3.1 precedence: host `aria-labelledby` (flattened)\n * > host `aria-label` > `label` property > literal `\"Popover\"`.\n *\n * Stored as state so render reads the current resolution synchronously.\n * @internal\n */\n @state() private _resolvedLabel = '';\n\n /**\n * Most recently observed consumer-supplied `aria-labelledby` token list on\n * the host. Refreshed every sync via `getAttribute()`.\n * @internal\n */\n private _consumerLabelledBy: string | null = null;\n\n /**\n * Handle for the shared host attribute / root id observer.\n * @internal\n */\n private _ariaMirror: AriaIdrefMirrorHandle | null = null;\n\n /**\n * Watches in-place text / visibility mutations on consumer light-DOM\n * elements resolved from the host's `aria-labelledby`. Reinstalled on\n * every sync against the deduped resolved set so an in-place text change\n * to `<h2 id=\"x\">Patient</h2>` flows into the inner body's `aria-label`.\n * @internal\n */\n private _externalRefsObserver: MutationObserver | null = null;\n\n /**\n * The element that held focus before the popover opened, used to restore focus on close.\n * @internal\n */\n private _previousFocus: HTMLElement | null = null;\n\n /**\n * Unique ID assigned to the popover body element.\n * @internal\n */\n private readonly _popoverId = _nextPopoverId();\n\n /**\n * Timer ID for the deferred document click listener registration in _show().\n * Stored so it can be cancelled in disconnectedCallback to prevent leaks.\n * @internal\n */\n private _showTimer: ReturnType<typeof setTimeout> | null = null;\n\n /**\n * Timer ID for the hover-triggered hide delay.\n * WCAG 1.4.13: hoverable content must remain visible while the pointer is\n * over it. A 150 ms delay allows the pointer to move from the anchor into\n * the popover body without the content dismissing prematurely.\n * @internal\n */\n private _hoverHideTimer: ReturnType<typeof setTimeout> | null = null;\n\n // ─── Lifecycle ───\n\n override connectedCallback(): void {\n super.connectedCallback();\n // Seed the host-attribute label mirror BEFORE first paint so the\n // resolved label is in place when render() reads `_resolvedLabel`.\n // The mirror's initial `sync()` fires synchronously inside\n // `installAriaIdrefMirror`.\n this._syncResolvedLabel();\n this._ariaMirror = installAriaIdrefMirror(this, () => {\n this._syncResolvedLabel();\n });\n }\n\n override disconnectedCallback(): void {\n super.disconnectedCallback();\n if (this._showTimer !== null) {\n clearTimeout(this._showTimer);\n this._showTimer = null;\n }\n if (this._hoverHideTimer !== null) {\n clearTimeout(this._hoverHideTimer);\n this._hoverHideTimer = null;\n }\n document.removeEventListener('click', this._handleDocumentClick);\n document.removeEventListener('keydown', this._handleDocumentKeydown);\n this._ariaMirror?.disconnect();\n this._ariaMirror = null;\n this._externalRefsObserver?.disconnect();\n this._externalRefsObserver = null;\n }\n\n override firstUpdated(): void {\n // HIGH-02: set aria-haspopup=\"dialog\" once on the anchor so assistive technology\n // announces the control's popup type before it is ever opened.\n this._setAnchorAriaAttributes(false);\n // Sync initial open state\n if (this.open) {\n void this._show();\n }\n }\n\n override willUpdate(changedProperties: PropertyValues<this>): void {\n super.willUpdate(changedProperties);\n // `label` property changes must flow into the resolved name BEFORE\n // render so the new fallback is in place on the same paint. Running in\n // `updated()` would schedule a follow-up cycle (state-from-update is\n // re-render-triggering), making the cross-component contract: \"one\n // updateComplete after `el.label = X` reflects the new aria-label\".\n if (changedProperties.has('label')) {\n this._syncResolvedLabel();\n }\n }\n\n override updated(changedProperties: PropertyValues<this>): void {\n if (changedProperties.has('open')) {\n if (this.open) {\n void this._show();\n } else {\n void this._hide();\n }\n }\n }\n\n // ─── Host-attribute label mirror ───\n\n /**\n * (Re-)installs a `MutationObserver` over the deduped union of\n * consumer-resolved label elements. Watches `characterData`, `childList`,\n * `subtree`, and `aria-hidden` / `hidden` attributes so any in-place\n * mutation on referenced light-DOM nodes triggers a fresh sync — keeping\n * the flattened `aria-label` aligned with the live consumer text.\n * @internal\n */\n private _installExternalRefsObserver(elements: Element[]): void {\n if (this._externalRefsObserver) {\n this._externalRefsObserver.disconnect();\n this._externalRefsObserver = null;\n }\n if (elements.length === 0) return;\n const unique = new Set<Element>(elements);\n const observer = new MutationObserver(() => {\n this._syncResolvedLabel();\n });\n for (const el of unique) {\n observer.observe(el, {\n characterData: true,\n subtree: true,\n childList: true,\n attributes: true,\n attributeFilter: ['aria-hidden', 'hidden'],\n });\n }\n this._externalRefsObserver = observer;\n }\n\n /**\n * Resolves the popover body's accessible name from host attributes and\n * the `label` property, applying AccName 1.2 §4.3.1 precedence. Writes\n * the result to `_resolvedLabel` (state) so `render()` projects it onto\n * the inner body's `aria-label` on the next paint. The text-flatten\n * filters out top-level `aria-hidden=\"true\"` / `[hidden]` subtrees per\n * AccName 1.2 §4.3.10 — matching the `flattenAccName` contract used by\n * every other host-canonical hx-* component.\n * @internal\n */\n private _syncResolvedLabel(): void {\n const liveLabelledBy = this.getAttribute('aria-labelledby');\n this._consumerLabelledBy = liveLabelledBy;\n const consumerLabelEls = resolveIdrefTokens(this, liveLabelledBy);\n\n // Observe in-place mutations on the resolved external IDREF targets so\n // text rewrites in the consumer's light DOM flow into the body's name.\n this._installExternalRefsObserver(consumerLabelEls);\n\n const isVisibleForAccName = (el: Element): boolean =>\n el.getAttribute('aria-hidden') !== 'true' && !el.hasAttribute('hidden');\n\n const flattenedFromIdrefs = consumerLabelEls\n .filter(isVisibleForAccName)\n .map((el) => flattenAccName(el))\n .filter((t) => t.length > 0)\n .join(' ')\n .replace(/\\s+/g, ' ')\n .trim();\n\n const liveAriaLabel = this.getAttribute('aria-label');\n const hostAriaLabel = liveAriaLabel !== null ? liveAriaLabel.trim() : '';\n\n let resolved = '';\n if (flattenedFromIdrefs) {\n resolved = flattenedFromIdrefs;\n } else if (hostAriaLabel) {\n resolved = hostAriaLabel;\n } else if (this.label) {\n resolved = this.label;\n } else {\n // Last-resort literal — preserves the pre-mirror default so an\n // unlabeled popover still has SOME announced name.\n resolved = 'Popover';\n }\n\n this._resolvedLabel = resolved;\n }\n\n // ─── ARIA setup ───\n\n // HIGH-02: set aria-haspopup=\"dialog\" on firstUpdated and keep aria-expanded in sync\n /** @internal */\n private _setAnchorAriaAttributes(expanded: boolean): void {\n const anchorSlot = this.shadowRoot?.querySelector(\n 'slot[name=\"anchor\"]',\n ) as HTMLSlotElement | null;\n if (!anchorSlot) return;\n const anchorEl = anchorSlot.assignedElements()[0] as HTMLElement | undefined;\n if (anchorEl) {\n anchorEl.setAttribute('aria-expanded', String(expanded));\n anchorEl.setAttribute('aria-haspopup', 'dialog');\n // aria-controls is omitted: the body lives in Shadow DOM and axe-core\n // cannot resolve cross-root IDREF values, which causes a critical violation.\n }\n }\n\n // ─── Focus helpers ───\n\n /** Return all keyboard-focusable elements inside the popover body's slotted content. */\n /** @internal */\n private _getFocusableElements(): HTMLElement[] {\n const bodyEl = this.shadowRoot?.querySelector('[part=\"body\"]') as HTMLElement | null;\n if (!bodyEl) return [];\n\n // Gather focusable elements from the default slot's assigned nodes\n const defaultSlot = bodyEl.querySelector('slot:not([name])') as HTMLSlotElement | null;\n if (!defaultSlot) return [];\n\n const assigned = defaultSlot.assignedElements({ flatten: true });\n const focusableSelector =\n 'a[href], area[href], button:not([disabled]), input:not([disabled]), select:not([disabled]), textarea:not([disabled]), [tabindex]:not([tabindex=\"-1\"]), details > summary';\n\n const result: HTMLElement[] = [];\n for (const el of assigned) {\n if (el.matches(focusableSelector)) {\n result.push(el as HTMLElement);\n }\n const nested = el.querySelectorAll<HTMLElement>(focusableSelector);\n result.push(...nested);\n }\n return result;\n }\n\n // ─── Show/Hide ───\n\n /** @internal */\n private async _show(): Promise<void> {\n if (this._visible) return;\n // P0-02: save focus target before moving focus into dialog\n this._previousFocus = document.activeElement as HTMLElement | null;\n this.dispatchEvent(new CustomEvent<void>('hx-show', { bubbles: true, composed: true }));\n this._visible = true;\n this.open = true;\n this._setAnchorAriaAttributes(true);\n // P1-03 / HIGH-01: single keydown listener handles both Escape and focus trap.\n // Registered synchronously before any await so it is in place before the first\n // await el.updateComplete in tests.\n document.addEventListener('keydown', this._handleDocumentKeydown);\n await this.updateComplete;\n // hx-after-show fires after Lit has rendered the visible state. Dispatching here\n // (before _updatePosition) ensures it fires in the same microtask as the test's\n // await-continuation, so tests can rely on a single await el.updateComplete.\n this.dispatchEvent(new CustomEvent<void>('hx-after-show', { bubbles: true, composed: true }));\n // WCAG 2.4.3: only move focus into the popover when it contains interactive\n // content. For non-interactive (informational) popovers, stealing focus from\n // the trigger is unexpected and disruptive for keyboard users.\n const bodyEl = this.shadowRoot?.querySelector('[part=\"body\"]') as HTMLElement | null;\n if (bodyEl) {\n const hasInteractive = this._getFocusableElements().length > 0;\n if (hasInteractive) {\n bodyEl.focus();\n }\n }\n // P0-01: listen for outside clicks; deferred to avoid catching the opening click\n if (this._showTimer !== null) {\n clearTimeout(this._showTimer);\n }\n this._showTimer = setTimeout(() => {\n this._showTimer = null;\n document.addEventListener('click', this._handleDocumentClick);\n }, 0);\n await this._updatePosition();\n }\n\n // HIGH-03: _hideWithFocusRestore controls whether _previousFocus is restored.\n // Escape and programmatic close restore focus; click-outside does not.\n /** @internal */\n private async _hide(restoreFocus = true): Promise<void> {\n if (!this._visible) return;\n document.removeEventListener('click', this._handleDocumentClick);\n document.removeEventListener('keydown', this._handleDocumentKeydown);\n this.dispatchEvent(new CustomEvent<void>('hx-hide', { bubbles: true, composed: true }));\n this._visible = false;\n this.open = false;\n this._setAnchorAriaAttributes(false);\n // HIGH-03: only restore focus on Escape / programmatic close\n if (restoreFocus) {\n this._previousFocus?.focus();\n }\n this._previousFocus = null;\n await this.updateComplete;\n this.dispatchEvent(new CustomEvent<void>('hx-after-hide', { bubbles: true, composed: true }));\n }\n\n // ─── Positioning ───\n\n /** @internal */\n private async _updatePosition(): Promise<void> {\n const anchorSlot = this.shadowRoot?.querySelector(\n 'slot[name=\"anchor\"]',\n ) as HTMLSlotElement | null;\n if (!anchorSlot) return;\n const anchorEl = anchorSlot.assignedElements()[0] as HTMLElement | undefined;\n const bodyEl = this.shadowRoot?.querySelector('[part=\"body\"]') as HTMLElement | null;\n const arrowEl = this.arrow\n ? (this.shadowRoot?.querySelector('[part=\"arrow\"]') as HTMLElement | null)\n : null;\n\n if (!anchorEl || !bodyEl) return;\n\n const { computePosition, flip, shift, offset, arrow } = await import('@floating-ui/dom');\n\n const middleware = [\n offset({ mainAxis: this.distance, crossAxis: this.skidding }),\n flip(),\n shift({ padding: 8 }),\n ];\n\n if (arrowEl) {\n middleware.push(arrow({ element: arrowEl }));\n }\n\n const { x, y, placement, middlewareData } = await computePosition(anchorEl, bodyEl, {\n placement: this.placement,\n strategy: 'fixed',\n middleware,\n });\n\n Object.assign(bodyEl.style, {\n left: `${x}px`,\n top: `${y}px`,\n });\n\n if (arrowEl && middlewareData.arrow) {\n const arrowData = middlewareData.arrow;\n const basePlacement = placement.split('-')[0] ?? 'bottom';\n const oppositeSide: Record<string, string> = {\n top: 'bottom',\n right: 'left',\n bottom: 'top',\n left: 'right',\n };\n const staticSide = oppositeSide[basePlacement] ?? 'bottom';\n\n Object.assign(arrowEl.style, {\n left: arrowData.x != null ? `${arrowData.x}px` : '',\n top: arrowData.y != null ? `${arrowData.y}px` : '',\n right: '',\n bottom: '',\n [staticSide]: '-5px',\n });\n\n // P2-02: hide the two border sides facing the popover body so only\n // the outward-facing corner is visible (avoids the inner border line).\n // Reset all four sides first, then make the two inner-facing ones transparent.\n const borderSides = ['border-top', 'border-right', 'border-bottom', 'border-left'] as const;\n for (const side of borderSides) {\n arrowEl.style.setProperty(side, '');\n }\n // Maps base placement → the two sides that face inward toward the popover body\n const innerBorderMap: Record<string, readonly [string, string]> = {\n bottom: ['border-bottom', 'border-right'],\n top: ['border-top', 'border-left'],\n right: ['border-top', 'border-right'],\n left: ['border-bottom', 'border-left'],\n };\n const innerSides = innerBorderMap[basePlacement] ?? ['border-bottom', 'border-right'];\n arrowEl.style.setProperty(innerSides[0], '1px solid transparent');\n arrowEl.style.setProperty(innerSides[1], '1px solid transparent');\n }\n }\n\n // ─── Event Handlers ───\n\n // P1-03 / P0-01 / HIGH-01: single document-level keydown handler while popover is open.\n // Handles Escape (close) and Tab (focus trap) in one listener to reduce overhead.\n /**\n * Handles Escape to close the popover and Tab/Shift+Tab to trap focus within it.\n * @internal\n */\n private _handleDocumentKeydown = (e: KeyboardEvent): void => {\n if (!this._visible) return;\n\n if (e.key === 'Escape') {\n // HIGH-03: Escape always restores focus to the prior element\n void this._hide(true);\n return;\n }\n\n if (e.key === 'Tab') {\n // HIGH-01: trap Tab/Shift+Tab focus within the popover body\n const focusable = this._getFocusableElements();\n if (focusable.length === 0) return;\n\n const bodyEl = this.shadowRoot?.querySelector('[part=\"body\"]') as HTMLElement | null;\n const allFocusable = bodyEl ? [bodyEl, ...focusable] : focusable;\n if (allFocusable.length === 0) return;\n\n const first = allFocusable[0] as HTMLElement;\n const last = allFocusable[allFocusable.length - 1] as HTMLElement;\n\n if (e.shiftKey) {\n if (document.activeElement === first || this.shadowRoot?.activeElement === first) {\n e.preventDefault();\n last.focus();\n }\n } else {\n if (document.activeElement === last || this.shadowRoot?.activeElement === last) {\n e.preventDefault();\n first.focus();\n }\n }\n }\n };\n\n // P0-01: close when click target is outside this component\n /**\n * Closes the popover when a click occurs outside the component boundary.\n * @internal\n */\n private _handleDocumentClick = (e: Event): void => {\n // Shadow DOM retargets events from within to the host at document level,\n // so a click on the trigger wrapper appears as e.target === this.\n if (e.target !== this && !this.contains(e.target as Node)) {\n // HIGH-03: click-outside does NOT restore focus — let browser handle naturally\n void this._hide(false);\n }\n };\n\n /**\n * Toggles the popover open/closed when the anchor is clicked in click trigger mode.\n * @internal\n */\n private _handleAnchorClick = (): void => {\n if (this.trigger !== 'click') return;\n if (this._visible) {\n void this._hide(true);\n } else {\n void this._show();\n }\n };\n\n /**\n * Opens the popover when the anchor receives a mouseenter event in hover trigger mode.\n * @internal\n */\n private _handleAnchorMouseEnter = (): void => {\n if (this.trigger !== 'hover') return;\n void this._show();\n };\n\n /**\n * Closes the popover when the anchor receives a mouseleave event in hover trigger mode.\n * WCAG 1.4.13: applies a 150 ms delay so the pointer can move from anchor\n * into the popover body without the content dismissing prematurely.\n * @internal\n */\n private _handleAnchorMouseLeave = (): void => {\n if (this.trigger !== 'hover') return;\n this._scheduleHoverHide();\n };\n\n // CRITICAL-02: body hover handlers so moving the pointer from anchor into\n // the popover content does not trigger a hide.\n /** @internal */\n private _handleBodyMouseEnter = (): void => {\n // Cancel a pending hide that would have fired from the anchor's mouseleave.\n if (this.trigger !== 'hover') return;\n this._cancelHoverHide();\n };\n\n /** @internal */\n private _handleBodyMouseLeave = (): void => {\n if (this.trigger !== 'hover') return;\n this._scheduleHoverHide();\n };\n\n /**\n * Schedules a hide with a 150 ms delay for hover-triggered dismissal.\n * WCAG 1.4.13: the delay allows the pointer to travel between the anchor\n * and the popover body without the content disappearing.\n * @internal\n */\n private _scheduleHoverHide(): void {\n this._cancelHoverHide();\n this._hoverHideTimer = setTimeout(() => {\n this._hoverHideTimer = null;\n void this._hide(false);\n }, 150);\n }\n\n /**\n * Cancels any pending hover-triggered hide.\n * @internal\n */\n private _cancelHoverHide(): void {\n if (this._hoverHideTimer !== null) {\n clearTimeout(this._hoverHideTimer);\n this._hoverHideTimer = null;\n }\n }\n\n /** @internal */\n private _handleAnchorFocusIn = (): void => {\n // CRITICAL-02: keyboard users trigger hover-mode popovers via focusin\n if (this.trigger !== 'focus' && this.trigger !== 'hover') return;\n void this._show();\n };\n\n /** @internal */\n private _handleAnchorFocusOut = (e: FocusEvent): void => {\n // CRITICAL-02: for hover mode, only hide when focus leaves both the anchor\n // and the popover body (i.e. relatedTarget is outside the component).\n if (this.trigger !== 'focus' && this.trigger !== 'hover') return;\n const related = e.relatedTarget as Node | null;\n // If focus is moving into the shadow root (body element), keep popover open\n if (related && (this.contains(related) || this.shadowRoot?.contains(related))) return;\n void this._hide(true);\n };\n\n /** @internal */\n private _handleAnchorSlotChange(): void {\n this._setAnchorAriaAttributes(this._visible);\n }\n\n // ─── Render ───\n\n override render() {\n return html`\n <div\n class=\"trigger-wrapper\"\n @click=${this._handleAnchorClick}\n @mouseenter=${this._handleAnchorMouseEnter}\n @mouseleave=${this._handleAnchorMouseLeave}\n @focusin=${this._handleAnchorFocusIn}\n @focusout=${this._handleAnchorFocusOut}\n >\n <slot name=\"anchor\" @slotchange=${this._handleAnchorSlotChange}></slot>\n </div>\n <div\n part=\"body\"\n id=${this._popoverId}\n role=\"dialog\"\n aria-label=${this._resolvedLabel}\n aria-hidden=${!this._visible ? 'true' : nothing}\n tabindex=\"-1\"\n ?inert=${!this._visible}\n class=${this._visible ? 'visible' : ''}\n @mouseenter=${this._handleBodyMouseEnter}\n @mouseleave=${this._handleBodyMouseLeave}\n >\n <slot></slot>\n ${this.arrow ? html`<div part=\"arrow\"></div>` : nothing}\n </div>\n `;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'hx-popover': HelixPopover;\n }\n}\n"],"names":["helixPopoverStyles","css","_nextPopoverId","createIdCounter","HelixPopover","HelixElement","focusable","bodyEl","_a","allFocusable","first","last","_b","_c","related","installAriaIdrefMirror","changedProperties","elements","unique","observer","el","liveLabelledBy","consumerLabelEls","resolveIdrefTokens","isVisibleForAccName","flattenedFromIdrefs","flattenAccName","t","liveAriaLabel","hostAriaLabel","resolved","expanded","anchorSlot","anchorEl","defaultSlot","assigned","focusableSelector","result","nested","restoreFocus","arrowEl","computePosition","flip","shift","offset","arrow","middleware","x","y","placement","middlewareData","arrowData","basePlacement","staticSide","borderSides","side","innerSides","html","nothing","forcedColorsSurface","__decorateClass","property","state","customElement"],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"hx-popup-COUXXZ9X.js","sources":["../../src/components/hx-popup/hx-popup.styles.ts","../../src/components/hx-popup/hx-popup.ts"],"sourcesContent":["import { css } from 'lit';\n\n/**\n * hx-popup styles.\n *\n * Positioning primitive — does NOT paint a surface of its own. Per the 3.2.0\n * surfaces & containers plan we apply restraint here: no coverage-gap fill,\n * since there is no real surface. Forced-colors mixin is still applied so\n * that any consumer that DOES style the popup body via tokens still meets\n * the OS-level affordance contract.\n */\nexport const helixPopupStyles = css`\n :host {\n display: inline-block;\n }\n\n [part='popup'] {\n position: fixed;\n z-index: var(--hx-popup-z-index, 9000);\n inset: 0 auto auto 0;\n box-sizing: border-box;\n transition: var(--hx-popup-transition, none);\n }\n\n :host(:not([active])) [part='popup'] {\n display: none;\n }\n\n [part='arrow'] {\n position: absolute;\n width: var(--hx-arrow-size, 8px);\n height: var(--hx-arrow-size, 8px);\n background: var(--hx-arrow-color, var(--hx-color-neutral-0, #ffffff));\n transform: rotate(45deg);\n pointer-events: none;\n }\n\n @media (prefers-reduced-motion: reduce) {\n [part='popup'] {\n transition: none;\n }\n }\n\n /* ─── Forced Colors (Windows High Contrast) ─── */\n\n @media (forced-colors: active) {\n [part='popup'] {\n border: 1px solid CanvasText;\n }\n\n [part='arrow'] {\n border: 1px solid CanvasText;\n }\n }\n`;\n","import { html, nothing, type PropertyValues } from 'lit';\nimport '../../utilities/document-token-adoption.js';\nimport { customElement, property } from 'lit/decorators.js';\nimport { HelixElement } from '../../base/index.js';\nimport type { Placement, Middleware } from '@floating-ui/dom';\nimport { helixPopupStyles } from './hx-popup.styles.js';\nimport { forcedColorsSurface } from '../../styles/forced-colors.js';\n\ntype PopupPlacement =\n | 'top'\n | 'top-start'\n | 'top-end'\n | 'right'\n | 'right-start'\n | 'right-end'\n | 'bottom'\n | 'bottom-start'\n | 'bottom-end'\n | 'left'\n | 'left-start'\n | 'left-end'\n | 'auto';\n\n// More precise type matching @floating-ui/dom's arrow middleware data structure\ntype ArrowData = { x?: number; y?: number; centerOffset: number };\n\n/**\n * A low-level positioning primitive that anchors a floating panel to a reference element.\n * This is the base that hx-tooltip, hx-dropdown, and hx-popover build upon.\n *\n * @summary Low-level popup positioning utility.\n *\n * @tag hx-popup\n *\n * @slot anchor - The reference element the popup is anchored to.\n * @slot - Default slot for popup content.\n *\n * @csspart popup - The popup container element.\n * @csspart arrow - The arrow indicator element (only present when `arrow` is true).\n *\n * @cssprop [--hx-popup-z-index=9000] - Z-index of the popup container.\n * @cssprop [--hx-popup-transition=none] - Transition applied to the popup element.\n * Consumers who need enter/exit animations can set this property AND override the\n * default `display: none` hide mechanism via `::part(popup)`. Example:\n * ```css\n * hx-popup { --hx-popup-transition: opacity 0.2s ease; }\n * hx-popup:not([active])::part(popup) { display: block; opacity: 0; pointer-events: none; }\n * hx-popup[active]::part(popup) { opacity: 1; }\n * ```\n * @cssprop [--hx-arrow-size=8px] - Size of the arrow element.\n * @cssprop [--hx-arrow-color=var(--hx-color-surface-overlay, #ffffff)] - Color of the arrow element.\n * @cssprop --hx-auto-size-available-width - Available width set by auto-size middleware (on :host).\n * @cssprop --hx-auto-size-available-height - Available height set by auto-size middleware (on :host).\n *\n * @fires {CustomEvent} hx-reposition - Emitted after the popup is repositioned.\n *\n * ## Accessibility Contract\n *\n * `hx-popup` is a **positioning utility**, not an interactive widget. It does not provide\n * ARIA semantics. Consumers are responsible for all accessibility:\n *\n * - **Popup role**: Add `role=\"tooltip\"`, `role=\"dialog\"`, `role=\"listbox\"`, etc. to the\n * slotted popup content depending on its purpose.\n * - **Trigger state**: The element that triggers the popup MUST set `aria-expanded=\"true/false\"`.\n * - **Association**: Use `aria-controls` on the trigger to reference the popup content element,\n * and `aria-labelledby` / `aria-describedby` as appropriate.\n * - **Focus management**: `hx-popup` does NOT trap focus. Consumers building dialogs or menus\n * MUST implement focus trapping and keyboard dismiss (Escape key) themselves.\n * - **Visibility**: The popup is hidden via `display: none` (CSS) and the `inert` attribute\n * when inactive. Both are reliable accessibility-tree hiding mechanisms.\n *\n * @example\n * ```html\n * <!-- Tooltip pattern -->\n * <hx-popup id=\"my-tooltip\" placement=\"bottom\" distance=\"8\">\n * <button\n * slot=\"anchor\"\n * aria-describedby=\"tooltip-content\"\n * aria-expanded=\"false\"\n * aria-controls=\"my-tooltip\"\n * >\n * Trigger\n * </button>\n * <div id=\"tooltip-content\" role=\"tooltip\">Tooltip text</div>\n * </hx-popup>\n * ```\n *\n * ## Drupal Integration\n *\n * `hx-popup` is a JS utility — Twig provides markup only. No Drupal behavior file is\n * required for basic usage, since the `anchor` slot and `active` attribute are sufficient.\n *\n * ```twig\n * {# Basic Twig usage — prefer anchor slot in server-rendered contexts #}\n * <hx-popup id=\"my-popup\" placement=\"bottom\" distance=\"8\">\n * <button\n * slot=\"anchor\"\n * aria-expanded=\"false\"\n * aria-controls=\"popup-content\"\n * >Open</button>\n * <div id=\"popup-content\" role=\"dialog\" aria-label=\"Popup content\">...</div>\n * </hx-popup>\n * ```\n *\n * ```js\n * // Drupal behavior for toggle interaction\n * Drupal.behaviors.helixPopup = {\n * attach(context) {\n * context.querySelectorAll('hx-popup').forEach((popup) => {\n * const trigger = popup.querySelector('[slot=\"anchor\"]');\n * if (!trigger) return;\n * trigger.addEventListener('click', () => {\n * popup.active = !popup.active;\n * trigger.setAttribute('aria-expanded', String(popup.active));\n * });\n * });\n * },\n * };\n * ```\n *\n * For Drupal-generated dynamic IDs, prefer the anchor **slot** over the `anchor` CSS selector\n * attribute, since slot-based anchoring does not require knowing the element's ID at render time.\n * If you must use the CSS selector form with dynamic IDs, pass the ID via a Twig variable:\n * ```twig\n * <hx-popup anchor=\"#{{ element['#id'] }}\" placement=\"bottom\">...</hx-popup>\n * ```\n * @cssprop [--hx-color-neutral-0] - Color.\n */\n@customElement('hx-popup')\nexport class HelixPopup extends HelixElement {\n static override styles = [helixPopupStyles, forcedColorsSurface];\n\n /** @internal */\n private _anchorSlotEl: Element | null = null;\n /** @internal */\n private _cleanupAutoUpdate: (() => void) | null = null;\n /** @internal */\n private _floatingUi: typeof import('@floating-ui/dom') | null = null;\n\n /** @internal */\n private async _loadFloatingUi() {\n if (!this._floatingUi) {\n this._floatingUi = await import('@floating-ui/dom');\n }\n return this._floatingUi;\n }\n\n /**\n * The reference element to anchor the popup to.\n *\n * - **Attribute form** (`anchor=\"#selector\"`): Accepts a CSS selector string resolved via\n * `querySelector` from the component's root node. Use this in HTML/Twig markup.\n * - **Property form** (`el.anchor = element`): Accepts an `Element` reference directly.\n * Setting an Element via JS property does NOT reflect to the attribute.\n *\n * If not set, the element in the `anchor` slot is used.\n *\n * @attr anchor\n */\n @property({ attribute: 'anchor' })\n anchor: string | Element | null = null;\n\n /**\n * Preferred placement of the popup relative to the anchor.\n * @attr placement\n */\n @property({ type: String, reflect: true })\n placement:\n | 'top'\n | 'top-start'\n | 'top-end'\n | 'right'\n | 'right-start'\n | 'right-end'\n | 'bottom'\n | 'bottom-start'\n | 'bottom-end'\n | 'left'\n | 'left-start'\n | 'left-end'\n | 'auto' = 'bottom';\n\n /**\n * Whether the popup is visible.\n * @attr active\n */\n @property({ type: Boolean, reflect: true })\n active = false;\n\n /**\n * Gap in pixels between the popup and the anchor element.\n * @attr distance\n */\n @property({ type: Number, reflect: true })\n distance = 0;\n\n /**\n * Offset in pixels along the anchor element's axis.\n * @attr skidding\n */\n @property({ type: Number, reflect: true })\n skidding = 0;\n\n /**\n * Whether to show an arrow pointing to the anchor element.\n * @attr arrow\n */\n @property({ type: Boolean, reflect: true })\n arrow = false;\n\n /**\n * Manual placement of the arrow along the popup edge.\n * When not set, floating-ui calculates the optimal position.\n * @attr arrow-placement\n */\n @property({ attribute: 'arrow-placement', reflect: true })\n arrowPlacement: 'start' | 'center' | 'end' | null = null;\n\n /**\n * Minimum padding in pixels from the popup edge to the arrow.\n * @attr arrow-padding\n */\n @property({ type: Number, attribute: 'arrow-padding' })\n arrowPadding = 10;\n\n /**\n * When true, flips the popup to the opposite side to avoid overflow.\n * @attr flip\n */\n @property({ type: Boolean, reflect: true })\n flip = false;\n\n /**\n * Fallback placements to try when flipping. Accepts a JSON array string.\n *\n * @example\n * ```html\n * <!-- Try \"top\" then \"left\" before giving up -->\n * <hx-popup flip flip-fallback-placements='[\"top\",\"left\"]'>...</hx-popup>\n * ```\n *\n * @attr flip-fallback-placements\n */\n @property({\n attribute: 'flip-fallback-placements',\n converter: {\n fromAttribute(value: string | null): PopupPlacement[] {\n if (!value) return [];\n try {\n return JSON.parse(value) as PopupPlacement[];\n } catch {\n return [];\n }\n },\n toAttribute(value: PopupPlacement[]): string {\n return JSON.stringify(value);\n },\n },\n })\n flipFallbackPlacements: (\n | 'top'\n | 'top-start'\n | 'top-end'\n | 'right'\n | 'right-start'\n | 'right-end'\n | 'bottom'\n | 'bottom-start'\n | 'bottom-end'\n | 'left'\n | 'left-start'\n | 'left-end'\n | 'auto'\n )[] = [];\n\n /**\n * When true, shifts the popup along the axis to remain in the viewport.\n * @attr shift\n */\n @property({ type: Boolean, reflect: true })\n shift = false;\n\n /**\n * When true, resizes the popup to fit within the viewport.\n * Sets --hx-auto-size-available-width and --hx-auto-size-available-height CSS custom\n * properties on `:host` so they cascade into shadow DOM and are readable from light DOM.\n * @attr auto-size\n */\n @property({ type: Boolean, attribute: 'auto-size', reflect: true })\n autoSize = false;\n\n /**\n * Positioning strategy passed to floating-ui's `computePosition`.\n *\n * - `'fixed'` (default): works for most cases; positions relative to the viewport.\n * - `'absolute'`: use inside `overflow: hidden` / scroll containers where the popup is\n * positioned relative to the nearest positioned ancestor instead of the viewport.\n *\n * @attr strategy\n */\n @property({ reflect: true })\n strategy: 'fixed' | 'absolute' = 'fixed';\n\n // ─── Lifecycle ───\n\n override connectedCallback(): void {\n super.connectedCallback();\n if (this.active) {\n void this.updateComplete.then(() => this._startAutoUpdate());\n }\n }\n\n override disconnectedCallback(): void {\n super.disconnectedCallback();\n this._stopAutoUpdate();\n }\n\n override updated(changedProperties: PropertyValues<this>): void {\n super.updated(changedProperties);\n\n const activeChanged = changedProperties.has('active');\n const positioningChanged =\n changedProperties.has('placement') ||\n changedProperties.has('distance') ||\n changedProperties.has('skidding') ||\n changedProperties.has('arrow') ||\n changedProperties.has('arrowPadding') ||\n changedProperties.has('arrowPlacement') ||\n changedProperties.has('flip') ||\n changedProperties.has('flipFallbackPlacements') ||\n changedProperties.has('shift') ||\n changedProperties.has('autoSize') ||\n changedProperties.has('anchor') ||\n changedProperties.has('strategy');\n\n if (activeChanged) {\n if (this.active) {\n void this._startAutoUpdate();\n } else {\n this._stopAutoUpdate();\n // Clean up autoSize custom properties when popup goes inactive\n if (this.autoSize) {\n this.style.removeProperty('--hx-auto-size-available-width');\n this.style.removeProperty('--hx-auto-size-available-height');\n }\n }\n } else if (positioningChanged && this.active) {\n void this._reposition();\n }\n\n // Remove stale autoSize properties when autoSize is disabled\n if (changedProperties.has('autoSize') && !this.autoSize) {\n this.style.removeProperty('--hx-auto-size-available-width');\n this.style.removeProperty('--hx-auto-size-available-height');\n }\n }\n\n // ─── Anchor Resolution ───\n\n /** @internal */\n private _getAnchorElement(): Element | null {\n if (this.anchor instanceof Element) {\n return this.anchor;\n }\n if (typeof this.anchor === 'string') {\n return (this.getRootNode() as Document | ShadowRoot).querySelector(this.anchor);\n }\n return this._anchorSlotEl;\n }\n\n /** @internal */\n private _handleAnchorSlotChange(e: Event): void {\n const slot = e.target as HTMLSlotElement;\n const assigned = slot.assignedElements();\n this._anchorSlotEl = assigned[0] ?? null;\n if (this.active) {\n void this._reposition();\n }\n }\n\n // ─── Positioning ───\n\n /** @internal */\n private async _startAutoUpdate(): Promise<void> {\n this._stopAutoUpdate();\n const anchorEl = this._getAnchorElement();\n const popupEl = this.shadowRoot?.querySelector<HTMLElement>('[part=\"popup\"]');\n if (!anchorEl || !popupEl) return;\n\n const { autoUpdate } = await this._loadFloatingUi();\n this._cleanupAutoUpdate = autoUpdate(anchorEl, popupEl, () => {\n void this._reposition();\n });\n }\n\n /** @internal */\n private _stopAutoUpdate(): void {\n this._cleanupAutoUpdate?.();\n this._cleanupAutoUpdate = null;\n }\n\n /** @internal */\n private async _reposition(): Promise<void> {\n const anchorEl = this._getAnchorElement();\n const popupEl = this.shadowRoot?.querySelector<HTMLElement>('[part=\"popup\"]');\n if (!anchorEl || !popupEl) return;\n\n const arrowEl = this.arrow\n ? (this.shadowRoot?.querySelector<HTMLElement>('[part=\"arrow\"]') ?? null)\n : null;\n\n const {\n computePosition,\n flip: flipMiddleware,\n shift: shiftMiddleware,\n offset: offsetMiddleware,\n arrow: arrowMiddleware,\n size: sizeMiddleware,\n autoPlacement: autoPlacementMiddleware,\n } = await this._loadFloatingUi();\n\n const middleware: Middleware[] = [\n offsetMiddleware({ mainAxis: this.distance, crossAxis: this.skidding }),\n ];\n\n if (this.placement === 'auto') {\n middleware.push(autoPlacementMiddleware());\n } else if (this.flip) {\n middleware.push(\n flipMiddleware({\n fallbackPlacements: this.flipFallbackPlacements as Placement[],\n }),\n );\n }\n\n if (this.shift) {\n middleware.push(shiftMiddleware({ padding: 8 }));\n }\n\n if (arrowEl) {\n middleware.push(arrowMiddleware({ element: arrowEl, padding: this.arrowPadding }));\n }\n\n if (this.autoSize) {\n middleware.push(\n sizeMiddleware({\n apply: ({ availableWidth, availableHeight }) => {\n this.style.setProperty('--hx-auto-size-available-width', `${availableWidth}px`);\n this.style.setProperty('--hx-auto-size-available-height', `${availableHeight}px`);\n },\n }),\n );\n }\n\n const effectivePlacement: Placement =\n this.placement === 'auto' ? 'bottom' : (this.placement as Placement);\n\n popupEl.style.position = this.strategy;\n\n const { x, y, placement, middlewareData } = await computePosition(anchorEl, popupEl, {\n placement: effectivePlacement,\n strategy: this.strategy,\n middleware,\n });\n\n Object.assign(popupEl.style, {\n left: `${x}px`,\n top: `${y}px`,\n });\n\n if (arrowEl) {\n const arrowData = middlewareData.arrow as ArrowData | undefined;\n this._positionArrow(arrowEl, placement, arrowData);\n }\n\n this.dispatchEvent(new CustomEvent<void>('hx-reposition', { bubbles: true, composed: true }));\n }\n\n /** @internal */\n private _positionArrow(\n arrowEl: HTMLElement,\n placement: Placement,\n arrowData: ArrowData | undefined,\n ): void {\n const basePlacement = placement.split('-')[0] as 'top' | 'right' | 'bottom' | 'left';\n const staticSides = {\n top: 'bottom',\n right: 'left',\n bottom: 'top',\n left: 'right',\n } as const;\n const staticSide = staticSides[basePlacement];\n\n const arrowStyle: Record<string, string> = {\n left: '',\n top: '',\n right: '',\n bottom: '',\n };\n\n if (this.arrowPlacement === 'start' || this.arrowPlacement === 'end') {\n const isVertical = basePlacement === 'top' || basePlacement === 'bottom';\n if (isVertical) {\n arrowStyle[this.arrowPlacement === 'start' ? 'left' : 'right'] = `${this.arrowPadding}px`;\n } else {\n arrowStyle[this.arrowPlacement === 'start' ? 'top' : 'bottom'] = `${this.arrowPadding}px`;\n }\n } else {\n // 'center' or null: use floating-ui computed position\n if (arrowData?.x != null) arrowStyle.left = `${arrowData.x}px`;\n if (arrowData?.y != null) arrowStyle.top = `${arrowData.y}px`;\n }\n\n arrowStyle[staticSide] = '-4px';\n arrowEl.setAttribute('data-placement', basePlacement);\n Object.assign(arrowEl.style, arrowStyle);\n }\n\n // ─── Public API ───\n\n /**\n * Forces the popup to recalculate its position.\n */\n async reposition(): Promise<void> {\n await this._reposition();\n }\n\n // ─── Render ───\n\n override render() {\n return html`\n <slot name=\"anchor\" @slotchange=${this._handleAnchorSlotChange}></slot>\n <div part=\"popup\" ?inert=${!this.active}>\n <slot></slot>\n ${this.arrow ? html`<div part=\"arrow\"></div>` : nothing}\n </div>\n `;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'hx-popup': HelixPopup;\n }\n}\n"],"names":["helixPopupStyles","css","HelixPopup","HelixElement","changedProperties","activeChanged","positioningChanged","e","assigned","anchorEl","popupEl","_a","autoUpdate","arrowEl","_b","computePosition","flipMiddleware","shiftMiddleware","offsetMiddleware","arrowMiddleware","sizeMiddleware","autoPlacementMiddleware","middleware","availableWidth","availableHeight","effectivePlacement","x","y","placement","middlewareData","arrowData","basePlacement","staticSide","arrowStyle","html","nothing","forcedColorsSurface","__decorateClass","property","value","customElement"],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"hx-radio-CY4kQfZw.js","sources":["../../src/components/hx-radio-group/hx-radio-group.styles.ts","../../src/components/hx-radio-group/hx-radio-group.ts","../../src/components/hx-radio-group/hx-radio.styles.ts","../../src/components/hx-radio-group/hx-radio.ts"],"sourcesContent":["import { css } from 'lit';\n\nexport const helixRadioGroupStyles = 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 /* ─── Fieldset ─── */\n\n .fieldset {\n border: none;\n margin: 0;\n padding: 0;\n display: flex;\n flex-direction: column;\n gap: var(--hx-space-2, 0.5rem);\n font-family: var(--hx-radio-group-font-family, var(--hx-font-family-sans, sans-serif));\n }\n\n /* ─── Legend ─── */\n\n .fieldset__legend {\n display: flex;\n align-items: baseline;\n gap: var(--hx-space-1, 0.25rem);\n font-size: var(--hx-font-size-sm, 0.875rem);\n font-weight: var(--hx-font-weight-medium, 500);\n color: var(--hx-radio-group-label-color, var(--hx-color-text-strong, #202b39));\n line-height: var(--hx-line-height-normal, 1.5);\n padding: 0;\n margin-bottom: var(--hx-space-1, 0.25rem);\n }\n\n .fieldset__required-marker {\n color: var(--hx-radio-group-error-color, var(--hx-color-error-text, #c92a2a));\n font-weight: var(--hx-font-weight-bold, 700);\n }\n\n /* ─── Group Container ─── */\n\n .fieldset__group {\n display: flex;\n flex-direction: column;\n gap: var(--hx-radio-group-gap, var(--hx-space-3, 0.75rem));\n }\n\n :host([orientation='horizontal']) .fieldset__group {\n flex-direction: row;\n flex-wrap: wrap;\n }\n\n /* ─── Error State ─── */\n\n .fieldset--error .fieldset__legend {\n color: var(--hx-radio-group-error-color, var(--hx-color-error-text, #c92a2a));\n }\n\n /* ─── Help Text & Error Messages ─── */\n\n .fieldset__help-text {\n font-size: var(--hx-font-size-xs, 0.75rem);\n color: var(--hx-radio-group-help-text-color, var(--hx-color-text-muted, #66787b));\n line-height: var(--hx-line-height-normal, 1.5);\n }\n\n .fieldset__error {\n font-size: var(--hx-font-size-xs, 0.75rem);\n color: var(--hx-radio-group-error-color, var(--hx-color-error-text, #c92a2a));\n line-height: var(--hx-line-height-normal, 1.5);\n }\n\n /* ─── High Contrast Mode (forced-colors) ─── */\n\n @media (forced-colors: active) {\n .fieldset {\n border: none;\n }\n\n .fieldset__legend {\n color: CanvasText;\n }\n\n .fieldset--error .fieldset__legend {\n color: LinkText;\n }\n\n :host([disabled]) {\n opacity: 1;\n }\n\n :host([disabled]) .fieldset__legend {\n color: GrayText;\n }\n\n .fieldset__help-text {\n color: GrayText;\n }\n\n .fieldset__error {\n color: LinkText;\n }\n }\n`;\n","import { html, nothing, type PropertyValues } from 'lit';\nimport '../../utilities/document-token-adoption.js';\nimport { customElement, property, state } from 'lit/decorators.js';\nimport { classMap } from 'lit/directives/class-map.js';\nimport { devWarn } from '../../utils/dev-warn.js';\nimport { HelixElement, createIdCounter } from '../../base/index.js';\nimport { FormMixin } from '../../mixins/FormMixin.js';\nimport { helixRadioGroupStyles } from './hx-radio-group.styles.js';\nimport { forcedColorsField } from '../../styles/forced-colors.js';\nimport type { HelixRadio } from './hx-radio.js';\nimport {\n installAriaIdrefMirror,\n resolveIdrefTokens,\n supportsIdrefElementReferences,\n type AriaIdrefMirrorHandle,\n} from '../../utils/aria-idref.js';\n\nconst _nextRadioGroupId = createIdCounter('hx-radio-group');\n\n/**\n * Reads visible text from a shadow wrapper that contains a `<slot>`. Prefers\n * the slot's flattened assigned-nodes text when light DOM is projected,\n * otherwise falls back to the wrapper's own `textContent` (so property-driven\n * fallback content rendered inside the slot is still readable). Codex\n * round-23 P2 (Finding C): a wrapper-element `textContent` read does NOT\n * cross the shadow → light-DOM slot boundary, so the previous direct\n * `textContent` mirror returned empty when a consumer slotted help/error\n * content instead of using the property.\n */\nfunction readSlottedOrShadowText(wrapper: Element): string {\n const slot = wrapper.querySelector('slot');\n if (slot) {\n const assigned = (slot as HTMLSlotElement).assignedNodes({ flatten: true });\n if (assigned.length > 0) {\n return assigned\n .map((node) => node.textContent ?? '')\n .join('')\n .trim();\n }\n }\n return (wrapper.textContent ?? '').trim();\n}\n\n/** Detail for the hx-change event dispatched by hx-radio-group. */\nexport interface HxRadioGroupChangeDetail {\n value: string;\n checked: boolean;\n}\n\n/**\n * A form-associated radio group that manages a set of `<hx-radio>` children.\n *\n * @summary Form-associated radio group with label, validation, help text, and keyboard navigation.\n *\n * @tag hx-radio-group\n *\n * @slot - `<hx-radio>` elements.\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<{value: string, checked: boolean}>} hx-change - Dispatched when the selected radio changes.\n * @fires {CustomEvent<{value: string}>} hx-radio-select - Internal event dispatched by `hx-radio` when selected; consumed by the group.\n *\n * @csspart fieldset - The fieldset wrapper.\n * @csspart legend - The legend/label.\n * @csspart group - The container for radio items.\n * @csspart error - The error message.\n * @csspart help-text - The help text.\n *\n * @cssprop [--hx-radio-group-gap=var(--hx-space-3, 0.75rem)] - Gap between radio items.\n * @cssprop [--hx-radio-group-label-color=var(--hx-color-neutral-700, #313E4B)] - Label text color.\n * @cssprop [--hx-radio-group-error-color=var(--hx-color-error-500, #E5493E)] - Error message color.\n * @cssprop [--hx-radio-group-help-text-color=var(--hx-color-neutral-500, #66787B)] - Help text color.\n * @cssprop [--hx-opacity-disabled] - Opacity.\n * @cssprop [--hx-space-2] - Spacing token.\n * @cssprop [--hx-radio-group-font-family=var(--hx-font-family-sans)] - CSS custom property.\n * @cssprop [--hx-font-family-sans] - Font family.\n * @cssprop [--hx-space-1] - Spacing token.\n * @cssprop [--hx-font-size-sm] - Font size.\n * @cssprop [--hx-font-weight-medium] - Font weight.\n * @cssprop [--hx-color-neutral-700] - Color.\n * @cssprop [--hx-line-height-normal] - Line height.\n * @cssprop [--hx-color-error-text] - Color.\n * @cssprop [--hx-font-weight-bold] - Font weight.\n * @cssprop [--hx-space-3] - Spacing token.\n * @cssprop [--hx-font-size-xs] - Font size.\n * @cssprop [--hx-color-neutral-500] - Color.\n */\n@customElement('hx-radio-group')\nexport class HelixRadioGroup extends FormMixin(HelixElement) {\n static override styles = [helixRadioGroupStyles, forcedColorsField];\n\n // ─── Form Association ───\n\n /**\n * Enables ElementInternals form association for this component.\n * @internal\n */\n static override formAssociated = true;\n\n // ─── Properties ───\n\n /**\n * The selected radio's value.\n * @attr value\n */\n @property({ type: String, reflect: true })\n value = '';\n\n /**\n * The name used for form submission.\n * @attr name\n */\n @property({ type: String, reflect: true })\n name = '';\n\n /**\n * The fieldset legend/label text.\n * @attr label\n */\n @property({ type: String })\n label = '';\n\n /**\n * Whether a selection is required for form submission.\n * @attr required\n */\n @property({ type: Boolean, reflect: true })\n required = false;\n\n /**\n * Whether the entire group is disabled.\n * @attr disabled\n */\n @property({ type: Boolean, reflect: true })\n disabled = false;\n\n /**\n * Error message to display. When set, the group enters an error state.\n * @attr error\n */\n @property({ type: String })\n error = '';\n\n /**\n * Help text displayed below the group for guidance.\n * @attr help-text\n */\n @property({ type: String, attribute: 'help-text' })\n helpText = '';\n\n /**\n * Layout orientation of the radio items.\n * @attr orientation\n */\n @property({ type: String, reflect: true })\n orientation: 'vertical' | 'horizontal' = 'vertical';\n\n /**\n * Queries the rendered group container element within the shadow root.\n * @internal\n */\n private get _groupEl(): HTMLElement | null {\n return this.renderRoot?.querySelector('.fieldset__group') ?? null;\n }\n\n /**\n * Tracks whether the error slot has assigned content.\n * @internal\n */\n @state() private _hasErrorSlot = false;\n\n /**\n * Tracks whether the help-text slot has assigned content.\n * @internal\n */\n @state() private _hasHelpSlot = false;\n\n /**\n * Whether the platform supports IDL element references on `ElementInternals`.\n * Drives the render-time branch between modern (host-canonical via\n * internals) and fallback (inner fieldset is the announced surface).\n * Codex round-17 P1.\n * @internal\n */\n @state() private _supportsIdrefRefs = true;\n\n // ─── Internal IDs ───\n\n /**\n * Unique identifier for this radio group instance used in ARIA attributes.\n * @internal\n */\n private _groupId = _nextRadioGroupId();\n /**\n * Unique identifier for the help text element, used in aria-describedby.\n * @internal\n */\n private _helpTextId = `${this._groupId}-help`;\n /**\n * Unique identifier for the error element, used in aria-describedby.\n * @internal\n */\n private _errorId = `${this._groupId}-error`;\n\n // ─── Slot Handlers ───\n\n /**\n * Handles slotchange events on the error slot to detect assigned content.\n * @internal\n */\n private _handleErrorSlotChange(e: Event): void {\n if (!(e.target instanceof HTMLSlotElement)) return;\n this._hasErrorSlot = e.target.assignedNodes({ flatten: true }).length > 0;\n // Codex round-23 P2 (Finding C): re-tune the in-place text observer over\n // the new assigned-node set so in-place `textContent` rewrites of slotted\n // error nodes resync `internals.ariaDescription` on the no-IDL-ref\n // fallback path. `slotchange` only fires when the *node set* changes;\n // mutating an already-assigned node's text does not, so a separate\n // observer is required. Mirrors the round-21 P3 label-slot observer in\n // hx-checkbox-group.\n this._installErrorSlotTextObserver(e.target);\n this._syncHostAriaSemantics();\n }\n\n /**\n * Handles slotchange events on the help-text slot to detect assigned content.\n * Codex aria-group-2 finding: slot-only help text was not contributing to\n * `aria-describedby` because the wrapper was conditionally rendered on the\n * `helpText` property alone.\n * @internal\n */\n private _handleHelpSlotChange(e: Event): void {\n if (!(e.target instanceof HTMLSlotElement)) return;\n this._hasHelpSlot = e.target.assignedNodes({ flatten: true }).length > 0;\n // Codex round-23 P2 (Finding C): same pattern as the error slot — keep\n // `internals.ariaDescription` in sync with in-place text edits on already\n // assigned help-text nodes.\n this._installHelpSlotTextObserver(e.target);\n this._syncHostAriaSemantics();\n }\n\n /**\n * Watches assigned `<slot name=\"help-text\">` nodes for in-place text\n * mutations so the no-IDL-ref fallback `internals.ariaDescription` stays in\n * sync when a framework rewrites `textContent` of an already-assigned node\n * without replacing it. `slotchange` does NOT fire for those mutations, so\n * a separate observer is required. Codex round-23 P2 (Finding C).\n * @internal\n */\n private _helpSlotTextObserver: MutationObserver | null = null;\n\n /**\n * Watches assigned `<slot name=\"error\">` nodes for in-place text mutations\n * so the no-IDL-ref fallback `internals.ariaDescription` stays in sync when\n * a framework rewrites `textContent` of an already-assigned node without\n * replacing it. Codex round-23 P2 (Finding C).\n * @internal\n */\n private _errorSlotTextObserver: MutationObserver | null = null;\n\n /**\n * (Re-)installs the mutation observer over the current set of assigned\n * help-text-slot nodes. Codex round-23 P2 (Finding C).\n * @internal\n */\n private _installHelpSlotTextObserver(slot: HTMLSlotElement | null): void {\n this._helpSlotTextObserver?.disconnect();\n if (!slot) {\n this._helpSlotTextObserver = null;\n return;\n }\n const observer = new MutationObserver(() => {\n this._syncHostAriaSemantics();\n });\n slot.assignedNodes().forEach((node) => {\n observer.observe(node, {\n characterData: true,\n childList: true,\n subtree: true,\n });\n });\n this._helpSlotTextObserver = observer;\n }\n\n /**\n * (Re-)installs the mutation observer over the current set of assigned\n * error-slot nodes. Codex round-23 P2 (Finding C).\n * @internal\n */\n private _installErrorSlotTextObserver(slot: HTMLSlotElement | null): void {\n this._errorSlotTextObserver?.disconnect();\n if (!slot) {\n this._errorSlotTextObserver = null;\n return;\n }\n const observer = new MutationObserver(() => {\n this._syncHostAriaSemantics();\n });\n slot.assignedNodes().forEach((node) => {\n observer.observe(node, {\n characterData: true,\n childList: true,\n subtree: true,\n });\n });\n this._errorSlotTextObserver = observer;\n }\n\n /**\n * Handle for the shared IDREF observer. See `installAriaIdrefMirror()`.\n * @internal\n */\n private _ariaMirror: AriaIdrefMirrorHandle | null = null;\n\n /**\n * Deferred copy of `error` driven through reactive state so the persistent\n * live region can re-announce on transitions without direct DOM mutation.\n * Codex round-1 finding #10.\n * @internal\n */\n @state() private _announcedError = '';\n\n /**\n * Tracks group-suppressed child radios so detached children can have the\n * flag cleared. Defense-in-depth symmetry with `hx-checkbox-group` —\n * `hx-radio` is not form-associated today, so the flag is inert, but the\n * parity keeps the contract identical between the two group/child families\n * for any future form-association on `hx-radio`. Codex round-3 finding #1.\n * @internal\n */\n private _suppressedChildren = new WeakSet<HelixRadio>();\n\n /**\n * Snapshot of children captured before each `slotchange` so removed\n * children can be released from suppression (WeakSet is non-enumerable).\n * @internal\n */\n private _previousRadios: HelixRadio[] = [];\n\n /**\n * Last value of `aria-labelledby` we wrote to the host. Used to distinguish\n * external (consumer) attribute mutations from our own internal augmentation\n * writes when refreshing the host-attribute fallback. Codex round-10 P2:\n * without this guard, an internal mutation observer fire would re-read the\n * already-augmented host attribute as if it were consumer-supplied, causing\n * legend/help/error ids to leak forward as \"consumer tokens\" forever.\n * @internal\n */\n private _lastWrittenLabelledBy: string | null = null;\n /** @internal — see `_lastWrittenLabelledBy`. */\n private _lastWrittenDescribedBy: string | null = null;\n /**\n * Most recently observed *consumer-supplied* `aria-labelledby` baseline (the\n * set of tokens the consumer themselves wrote on the host). Refreshed only\n * when the host attribute changes via an external write — internal writes\n * leave the baseline untouched.\n * @internal\n */\n private _consumerLabelledBy: string | null = null;\n /** @internal — see `_consumerLabelledBy`. */\n private _consumerDescribedBy: string | null = null;\n\n // ─── Lifecycle ───\n\n override connectedCallback(): void {\n super.connectedCallback();\n // Codex round-17 P1: detect IDL element-references API support so\n // render() can branch the fieldset between presentational (modern) and\n // group-with-aria (fallback) treatments.\n this._supportsIdrefRefs = supportsIdrefElementReferences(this._internals);\n this.addEventListener('hx-radio-select', this._handleRadioSelect);\n this.addEventListener('keydown', this._handleKeydown);\n // Seed root-independent semantics from connect so the host announces the\n // radiogroup role before first paint.\n this._syncHostAriaSemantics();\n this._ariaMirror = installAriaIdrefMirror(this, () => {\n this._syncHostAriaSemantics();\n });\n // Codex round-10 P2 (parity with hx-checkbox-group): re-apply child\n // suppression on reattach so a detached-then-reinserted group with the\n // same `<hx-radio>` children still claims them. `_groupedSuppress` is\n // currently inert on `hx-radio`, but the lifecycle parity keeps the\n // contract identical for any future form-association on the radio child.\n const existing = this._getRadios();\n if (existing.length > 0) {\n existing.forEach((radio) => {\n radio._groupedSuppress = true;\n this._suppressedChildren.add(radio);\n });\n this._previousRadios = existing;\n }\n }\n\n override disconnectedCallback(): void {\n super.disconnectedCallback();\n this.removeEventListener('hx-radio-select', this._handleRadioSelect);\n this.removeEventListener('keydown', this._handleKeydown);\n this._ariaMirror?.disconnect();\n this._ariaMirror = null;\n // Codex round-7 finding #6: tear down the per-child disabled observer so\n // detached radios don't keep a strong reference back into a group whose\n // host is being torn down.\n this._childDisabledObserver?.disconnect();\n this._childDisabledObserver = null;\n // Codex round-23 P2 (Finding C): tear down the help/error slot text\n // observers so detached assigned nodes stop firing into a torn-down host.\n this._helpSlotTextObserver?.disconnect();\n this._helpSlotTextObserver = null;\n this._errorSlotTextObserver?.disconnect();\n this._errorSlotTextObserver = null;\n // Release suppression on every previously-tracked child so they regain\n // stand-alone behaviour if re-parented or kept in the document after the\n // group is removed. Codex round-3 finding #1 (defense-in-depth).\n this._previousRadios.forEach((radio) => {\n if (this._suppressedChildren.has(radio)) {\n radio._groupedSuppress = false;\n this._suppressedChildren.delete(radio);\n }\n });\n this._previousRadios = [];\n }\n\n override updated(changedProperties: PropertyValues<this>): void {\n super.updated(changedProperties);\n if (changedProperties.has('value')) {\n this._internals.setFormValue(this.value || null);\n this._syncRadios();\n }\n if (changedProperties.has('disabled')) {\n this._syncRadios();\n }\n // Host-elevated ARIA semantics — see _syncHostAriaSemantics.\n this._syncHostAriaSemantics();\n // Codex round-1 finding #10: drive re-announcement from reactive state\n // so the persistent live region stays in the shadow tree across error\n // transitions. Direct `textContent` mutation would delete the slot\n // subtree the renderer just produced.\n if (changedProperties.has('error')) {\n const previousError = changedProperties.get('error') as string;\n if (previousError && this.error) {\n // Error→error: clear then re-set after rAF so AT re-announces.\n this._announcedError = '';\n requestAnimationFrame(() => {\n this._announcedError = this.error;\n });\n } else {\n this._announcedError = this.error;\n }\n }\n }\n\n /**\n * Mirrors radiogroup semantics onto the host via ElementInternals so that\n * consumer-supplied `aria-label`, `aria-labelledby`, and `aria-describedby`\n * on `<hx-radio-group>` reach the announced control. The codex aria-group-2\n * finding identified that the inner `<fieldset>` was the announced node and\n * the host's external IDREF tokens could not cross the shadow boundary.\n * @internal\n */\n private _syncHostAriaSemantics(): void {\n const internals = this._internals;\n internals.role = 'radiogroup';\n internals.ariaRequired = this.required ? 'true' : 'false';\n internals.ariaInvalid = !internals.validity.valid ? 'true' : 'false';\n internals.ariaDisabled = this.disabled ? 'true' : 'false';\n internals.ariaOrientation = this.orientation === 'horizontal' ? 'horizontal' : 'vertical';\n\n const hostAriaLabel = this.getAttribute('aria-label')?.trim() || '';\n\n // Resolve the candidate label/desc element references once — the IDL-ref\n // path consumes them as `Element[]`, the fallback path mirrors their `id`\n // tokens onto the host's `aria-labelledby` / `aria-describedby` attributes\n // so that AT can still locate the shadow help/error wrappers via the\n // stable shadow-internal ids.\n const internalLegend = this.shadowRoot?.getElementById(`${this._groupId}-legend`);\n const helpEl = this.shadowRoot?.getElementById(this._helpTextId);\n const errorEl = this.shadowRoot?.getElementById(this._errorId);\n\n // Codex round-10 P2: refresh the consumer baseline only when the host\n // attribute moved due to an *external* write. Compare the live attribute\n // against our last-written snapshot — if it differs, the consumer wrote.\n // This prevents internally-augmented values (containing legend/help/error\n // ids we appended) from being re-read as if they were consumer tokens.\n const liveLabelledBy = this.getAttribute('aria-labelledby');\n if (liveLabelledBy !== this._lastWrittenLabelledBy) {\n this._consumerLabelledBy = liveLabelledBy;\n }\n const liveDescribedBy = this.getAttribute('aria-describedby');\n if (liveDescribedBy !== this._lastWrittenDescribedBy) {\n this._consumerDescribedBy = liveDescribedBy;\n }\n const externalLabelTokens = this._consumerLabelledBy;\n const externalDescTokens = this._consumerDescribedBy;\n\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. A typo or\n // transiently-missing target must NOT erase the visible label — fall back\n // to `label` so the radiogroup keeps a name on both paths.\n const hasEffectiveLabelledBy = labelEls.length > 0;\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 if (labelEls.length === 0 && !hostAriaLabel && this.label && internalLegend) {\n labelEls.push(internalLegend);\n }\n\n const descEls = resolveIdrefTokens(this, externalDescTokens);\n const hasError = !!(this.error || this._hasErrorSlot);\n // Codex round-16 P2: drop help text from the describedby chain while an\n // error is active. The render path hides the help wrapper in that state\n // (`?hidden=${!hasHelp || hasError}`); appending the hidden node to host\n // semantics would have AT announce stale guidance ahead of the\n // validation error. Mirrors hx-checkbox-group, hx-switch, hx-checkbox.\n if (helpEl && !hasError && (this.helpText || this._hasHelpSlot)) {\n descEls.push(helpEl);\n }\n if (errorEl && hasError) {\n descEls.push(errorEl);\n }\n\n // Branch off the cached `_supportsIdrefRefs` (seeded at connect by the\n // platform probe) so tests can force the fallback branch by flipping the\n // flag. TODO(codex round-19 follow-up): re-probe on `adoptedCallback` if\n // we ever support cross-document moves; today the cached value is set\n // once at connect.\n if (this._supportsIdrefRefs) {\n type InternalsWithRefs = ElementInternals & {\n ariaLabelledByElements: Element[] | null;\n ariaDescribedByElements: Element[] | null;\n };\n const refsInternals = internals as InternalsWithRefs;\n refsInternals.ariaLabelledByElements = labelEls.length > 0 ? labelEls : null;\n refsInternals.ariaDescribedByElements = descEls.length > 0 ? descEls : null;\n // Clear any stale fallback `ariaDescription` string in case a prior sync\n // ran on the fallback path (e.g. tests flipping `_supportsIdrefRefs`).\n // The modern path uses element references exclusively; coexisting strings\n // would cause AT to announce the description twice.\n internals.ariaDescription = null;\n } else {\n // ─── No-IDL-ref fallback (codex round-19 P1) ───\n // The IDL element-references API is unavailable, so internal shadow\n // help/error/legend wrappers cannot be projected onto the host\n // accessibility node via `internals.aria*Elements`.\n //\n // Codex round-19 P1: keep the host as the canonical accessible-container\n // surface on BOTH modern and fallback paths. Earlier rounds promoted the\n // inner fieldset to `role=\"group\"` here and tried to splice consumer\n // light-DOM ids together with shadow-internal ids on the fieldset's\n // `aria-labelledby` / `aria-describedby`. That created two nested\n // accessible containers (host radiogroup → inner group → controls) AND\n // the spliced shadow IDREFs could never resolve to consumer light-DOM\n // targets, so the inner fieldset's \"external label\" was silently broken.\n //\n // The correct trade-off on legacy engines (notably Firefox today): the\n // host owns the role + ARIA strings (via `internals.role`,\n // `internals.ariaLabel`, and the host attribute mirror below); we accept\n // a documented loss of *internal* legend/help/error references and rely\n // on consumer-supplied light-DOM tokens, which resolve correctly in the\n // host's containing root. The inner fieldset stays presentational on\n // both paths so AT announces a single accessible container.\n const consumerLabelIds = new Set((externalLabelTokens?.split(/\\s+/) ?? []).filter(Boolean));\n const consumerDescIds = new Set((externalDescTokens?.split(/\\s+/) ?? []).filter(Boolean));\n\n // Host attributes: ONLY consumer tokens (never shadow-internal ids —\n // those cannot resolve across the shadow boundary).\n //\n // Codex round-35 (medium): mirror consumer tokens to the host attribute\n // ONLY when at least one token resolves to a real element. A broken\n // `aria-labelledby` (typo, target not yet attached) would otherwise\n // erase the accessible name on legacy engines per ARIA priority\n // (aria-labelledby > aria-label > internals.ariaLabel). When tokens\n // don't resolve, clear the host attribute so the `internals.ariaLabel`\n // fallback the modern path set above (`this.label`) wins.\n const hostLabel = hasEffectiveLabelledBy\n ? [...consumerLabelIds].filter(Boolean).join(' ')\n : '';\n const liveLabel = this.getAttribute('aria-labelledby');\n if (hostLabel) {\n if (liveLabel !== hostLabel) {\n this.setAttribute('aria-labelledby', hostLabel);\n }\n this._lastWrittenLabelledBy = hostLabel;\n } else if (liveLabel !== null) {\n // Codex round-36 (medium): when consumer-supplied tokens don't\n // resolve (`!hasEffectiveLabelledBy`), actively clear the host\n // attribute even if WE didn't write it. Per ARIA priority\n // (aria-labelledby > aria-label > internals.ariaLabel), a broken\n // consumer-authored attribute on the announced surface erases the\n // legend on legacy engines. The original tokens remain cached in\n // `_consumerLabelledBy` so they replay on a future sync if the\n // target later attaches and `hasEffectiveLabelledBy` flips back to\n // true.\n this.removeAttribute('aria-labelledby');\n this._lastWrittenLabelledBy = null;\n }\n\n const hostDesc = [...consumerDescIds].filter(Boolean).join(' ') || '';\n const liveDesc = this.getAttribute('aria-describedby');\n if (hostDesc) {\n if (liveDesc !== hostDesc) {\n this.setAttribute('aria-describedby', hostDesc);\n }\n this._lastWrittenDescribedBy = hostDesc;\n } else if (liveDesc !== null && this._lastWrittenDescribedBy !== null) {\n this.removeAttribute('aria-describedby');\n this._lastWrittenDescribedBy = null;\n }\n\n // Codex round-22 P1 #2: on the no-IDL-ref fallback path, consumer-supplied\n // describedby tokens reach the host (above) but the *internal* shadow\n // help/error wrappers cannot be referenced from light-DOM IDREFs. Mirror\n // their `textContent` into `internals.ariaDescription` so the host's\n // accessible description still surfaces the live help/error strings on\n // legacy engines (Firefox today). The string-form description hook is\n // independent of element references and survives the shadow boundary.\n // Empty strings are normalized to `null` so AT does not announce an\n // empty description.\n // Codex round-23 P2 (Finding C): use a slot-aware text read so slotted\n // help/error content surfaces into `internals.ariaDescription` —\n // wrapper `textContent` does NOT cross the shadow → light-DOM slot\n // boundary. The new help/error slot text observers (above) keep this\n // in sync when a framework rewrites the slotted node's textContent in\n // place.\n const helpText =\n helpEl && !hasError && (this.helpText || this._hasHelpSlot)\n ? readSlottedOrShadowText(helpEl)\n : '';\n const errorText = errorEl && hasError ? readSlottedOrShadowText(errorEl) : '';\n const internalDescriptionText = [helpText, errorText].filter(Boolean).join(' ');\n internals.ariaDescription = internalDescriptionText || null;\n }\n }\n\n override firstUpdated(changedProperties: PropertyValues<this>): void {\n super.firstUpdated(changedProperties);\n this._syncRadios();\n this._previousRadios = this._getRadios();\n // Codex round-7 finding #6: observe in-place `disabled` mutations on the\n // initial child set. The slotchange handler refreshes this on every slot\n // pass, but firstUpdated covers the case where the initial children are\n // never re-slotted (e.g. static markup mounted once).\n this._installChildDisabledObservers();\n // WCAG 4.1.2: warn when no accessible name is available for the radio group.\n // The fieldset needs either a label prop (rendered as <legend>) or an aria-label\n // attribute on the host element so screen readers can identify the group.\n if (!this.label && !this.getAttribute('aria-label')) {\n devWarn(\n 'hx-radio-group',\n 'No accessible label provided. Set the `label` attribute or add `aria-label` to the host element. An unlabeled radio group violates WCAG 2.1 AA (4.1.2 Name, Role, Value).',\n );\n }\n }\n\n // ─── Radio Management ───\n\n /**\n * Cached list of child hx-radio elements; invalidated on slot change.\n * @internal\n */\n private _cachedRadios: HelixRadio[] | null = null;\n /**\n * Stores each radio's individual disabled state before group-level disabling overrides it.\n * @internal\n */\n private _individualDisabledStates = new WeakMap<HelixRadio, boolean>();\n\n /**\n * Returns all child hx-radio elements, using the cache when available.\n * @internal\n */\n private _getRadios(): HelixRadio[] {\n if (!this._cachedRadios) {\n this._cachedRadios = Array.from(this.querySelectorAll('hx-radio')) as HelixRadio[];\n }\n return this._cachedRadios;\n }\n\n /**\n * Returns only the child hx-radio elements that are not disabled.\n * @internal\n */\n private _getEnabledRadios(): HelixRadio[] {\n return this._getRadios().filter((radio) => !radio.disabled && !this.disabled);\n }\n\n /**\n * Synchronizes checked state, disabled state, and roving tabindex across all child radios.\n * @internal\n */\n private _syncRadios(): void {\n const radios = this._getRadios();\n const enabledRadios = this._getEnabledRadios();\n\n radios.forEach((radio) => {\n // Codex round-3 finding #1 (defense-in-depth symmetry with hx-checkbox):\n // mark every group-managed child so any future form-association change\n // on `hx-radio` is automatically suppressed inside the group. The flag\n // is currently inert on `hx-radio` (which is not form-associated).\n radio._groupedSuppress = true;\n this._suppressedChildren.add(radio);\n\n const isChecked = radio.value === this.value && this.value !== '';\n radio.checked = isChecked;\n\n if (this.disabled) {\n // Store individual disabled state before overriding with group disabled\n if (!this._individualDisabledStates.has(radio)) {\n this._individualDisabledStates.set(radio, radio.disabled);\n }\n radio.disabled = true;\n } else {\n // Restore individual disabled state when group is re-enabled\n const originalDisabled = this._individualDisabledStates.get(radio);\n if (originalDisabled !== undefined) {\n radio.disabled = originalDisabled;\n this._individualDisabledStates.delete(radio);\n }\n }\n });\n\n // Roving tabindex management\n const checkedRadio = enabledRadios.find((r) => r.checked);\n radios.forEach((radio) => {\n radio.tabIndex = -1;\n });\n\n if (checkedRadio) {\n checkedRadio.tabIndex = 0;\n } else if (enabledRadios.length > 0) {\n const firstRadio = enabledRadios[0];\n if (firstRadio) {\n firstRadio.tabIndex = 0;\n }\n }\n }\n\n // ─── Event Handling ───\n\n /**\n * Handles the internal hx-radio-select event to update the group's selected value.\n * @internal\n */\n private _handleRadioSelect = (e: Event): void => {\n if (!(e instanceof CustomEvent)) return;\n e.stopPropagation();\n\n const newValue = (e.detail as { value: string }).value;\n if (newValue === this.value) {\n return;\n }\n\n this.value = newValue;\n this._handleInteractionInput();\n // Reactive update in updated() will call setFormValue, _syncRadios, _updateValidity\n\n /**\n * Dispatched when the selected radio changes.\n * @event hx-change\n */\n this.dispatchEvent(\n new CustomEvent<{ value: string; checked: boolean }>('hx-change', {\n bubbles: true,\n composed: true,\n detail: { value: this.value, checked: true },\n }),\n );\n };\n\n /**\n * Handles keyboard navigation (arrow keys, Home, End, Space) within the radio group.\n * @internal\n */\n private _handleKeydown = (e: KeyboardEvent): void => {\n const enabledRadios = this._getEnabledRadios();\n if (enabledRadios.length === 0) {\n return;\n }\n\n const isHandledKey = [\n 'ArrowUp',\n 'ArrowDown',\n 'ArrowLeft',\n 'ArrowRight',\n ' ',\n 'Home',\n 'End',\n ].includes(e.key);\n if (!isHandledKey) {\n return;\n }\n\n e.preventDefault();\n\n // Space: select the currently focused radio without moving focus\n if (e.key === ' ') {\n const targetRadio = (e.target as Element)?.closest?.('hx-radio') as HelixRadio | null;\n if (targetRadio && !targetRadio.disabled) {\n targetRadio.dispatchEvent(\n new CustomEvent<{ value: string }>('hx-radio-select', {\n bubbles: true,\n composed: true,\n detail: { value: targetRadio.value },\n }),\n );\n }\n return;\n }\n\n const targetRadio = (e.target as Element)?.closest?.('hx-radio') as HelixRadio | null;\n const currentIndex = targetRadio\n ? enabledRadios.indexOf(targetRadio)\n : enabledRadios.findIndex((radio) => radio.checked);\n\n let nextIndex: number;\n if (e.key === 'Home') {\n nextIndex = 0;\n } else if (e.key === 'End') {\n nextIndex = enabledRadios.length - 1;\n } else if (e.key === 'ArrowDown' || e.key === 'ArrowRight') {\n nextIndex = currentIndex === -1 ? 0 : (currentIndex + 1) % enabledRadios.length;\n } else {\n nextIndex = currentIndex <= 0 ? enabledRadios.length - 1 : currentIndex - 1;\n }\n\n const nextRadio = enabledRadios[nextIndex];\n if (nextRadio) {\n nextRadio.focus();\n nextRadio.dispatchEvent(\n new CustomEvent<{ value: string }>('hx-radio-select', {\n bubbles: true,\n composed: true,\n detail: { value: nextRadio.value },\n }),\n );\n }\n };\n\n /**\n * Handles slotchange events on the default slot. Refreshes the cached\n * radio list, reconciles `value`/`setFormValue`/validity against the new\n * children, then re-tunes the per-child disabled observer so in-place\n * `radio.disabled = true` mutations trigger the same reconcile pass.\n *\n * Codex round-2 finding #3: previously this handler only invalidated the\n * cache and re-synced child state, so removing the currently-selected\n * radio (or disabling it, or adding a new `checked` radio) left\n * `this.value` and the submitted form value pointing at stale state and\n * `_updateValidity` was never re-run.\n *\n * Codex round-7 finding #6: an in-place `selectedRadio.disabled = true`\n * never re-entered this reconciler (the radio remained slotted), so the\n * group could keep submitting a disabled value and stay valid until some\n * unrelated slot mutation kicked things over. The per-child observer\n * installed at the end of this method re-runs the same reconcile logic on\n * every `disabled` attribute mutation.\n * @internal\n */\n private _handleSlotChange(): void {\n this._cachedRadios = null;\n this._reconcileChildren();\n this._installChildDisabledObservers();\n }\n\n /**\n * Per-child `disabled` attribute observer. Mirrors the slotchange\n * reconcile pipeline so an in-place `radio.disabled = true` collapses the\n * group's `value`/form participation/validity. Round-7 finding #6.\n *\n * One observer is shared across all currently-slotted radios; it is\n * disconnected and re-attached on every slotchange so children that have\n * left the group stop firing reconcile passes.\n * @internal\n */\n private _childDisabledObserver: MutationObserver | null = null;\n\n /**\n * Re-runs the slotchange reconcile pass without touching the disabled\n * observer wiring. Called from the slotchange handler and from the\n * per-child disabled observer; factored out so both entry points share\n * the same value/formValue/validity reconciliation path. Round-7 #6.\n * @internal\n */\n private _reconcileChildren(): void {\n // Snapshot of the previous slot pass so we can release `_groupedSuppress`\n // on any radio that has left this group. Codex round-3 finding #1\n // (defense-in-depth symmetry).\n const previous = this._previousRadios;\n\n // Reconcile against currently-slotted children BEFORE _syncRadios runs.\n // _syncRadios() unconditionally overwrites `radio.checked` from `this.value`,\n // which would clobber an externally-set `checked=true` on a newly-added\n // radio when the group's current value is empty. We therefore peek at the\n // raw children first to detect \"pre-checked\" adoption, then commit through\n // the normal sync pipeline.\n //\n // Codex round-12 P2: prefer a checked radio whose value differs from the\n // current group value — that is the \"newly externally checked\" candidate.\n // The naive `.find(r.checked && !r.disabled)` returned the first checked\n // radio in DOM order, which is typically the previously-selected one whose\n // value already matches `this.value`, so an appended `<hx-radio checked>`\n // with a different value would be rejected by the next `_syncRadios()`\n // pass. Falling back to \"any checked radio\" still handles the\n // empty-group / first-mount case.\n const candidates = this._getRadios().filter((r) => r.checked && !r.disabled);\n const externallyChecked = candidates.find((r) => r.value !== this.value) ?? candidates[0];\n if (externallyChecked && externallyChecked.value !== this.value) {\n this.value = externallyChecked.value;\n }\n\n this._syncRadios();\n\n // After sync, the group's `value` and the children's `checked` flags are\n // canonical. If the previously-selected radio was removed or disabled,\n // `selected` becomes undefined and `reconciled` collapses to '', clearing\n // form participation.\n //\n // Codex round-10 P1: when the group itself is disabled, every radio is\n // force-disabled by `_syncRadios`. The post-sync `selected` lookup excludes\n // disabled radios, so it would always collapse to '' and wipe the user's\n // selection across a disable→enable cycle. Group-level disable is a\n // visual/interaction lock — it must preserve `value` and form participation\n // (matching native `<fieldset disabled>` semantics where the form value is\n // simply omitted from submission while disabled). When `this.disabled` is\n // true we leave `value` and form state untouched; the next disabled→false\n // pass through `updated()` runs `_syncRadios` again, which restores each\n // radio's individual disabled flag and re-checks the matching value.\n if (this.disabled) {\n // Codex round-18 P2: even while disabled, if the previously-selected\n // radio has been *removed* from the DOM (vs merely disabled by the\n // group), `this.value` references a value that no slotted child\n // carries, so the group would resubmit a stale option after re-enable.\n // We must clear `value` in that case while still preserving selection\n // across pure disable→enable cycles where the radio still exists.\n // Detect \"selected option still in DOM\" by membership lookup on the\n // raw children, ignoring their disabled flag (since group-level\n // disable forces them all disabled by _syncRadios).\n const presentValues = this._getRadios().map((r) => r.value);\n if (this.value && !presentValues.includes(this.value)) {\n this.value = '';\n }\n // Validity reflects the (possibly-cleared) value; setFormValue is\n // omitted because a disabled control shouldn't contribute to form\n // submission.\n this._updateValidity();\n } else {\n const selected = this._getRadios().find((r) => r.checked && !r.disabled);\n const reconciled = selected?.value ?? '';\n if (reconciled !== this.value) {\n this.value = reconciled;\n }\n // Always re-run setFormValue + validity. `value` may be stable while\n // membership/disabled-state changed, and a freshly-adopted pre-checked\n // radio still needs its value pushed to the form.\n this._internals.setFormValue(this.value || null);\n this._updateValidity();\n }\n\n // Release suppression on any radio that left the group. Then refresh the\n // snapshot for the next slotchange. Codex round-3 finding #1.\n const current = new Set(this._getRadios());\n previous.forEach((radio) => {\n if (!current.has(radio) && this._suppressedChildren.has(radio)) {\n radio._groupedSuppress = false;\n this._suppressedChildren.delete(radio);\n }\n });\n this._previousRadios = this._getRadios();\n }\n\n /**\n * Installs (or re-installs) a single MutationObserver across the current\n * set of slotted `<hx-radio>` children, listening for `disabled` attribute\n * mutations. Round-7 finding #6: in-place `disabled = true` never reaches\n * the slotchange-driven reconciler otherwise.\n * @internal\n */\n private _installChildDisabledObservers(): void {\n this._childDisabledObserver?.disconnect();\n const radios = this._getRadios();\n if (radios.length === 0) {\n this._childDisabledObserver = null;\n return;\n }\n const observer = new MutationObserver((mutations) => {\n // Filter to disabled-attribute mutations only — the observer is scoped\n // to attributeFilter:['disabled'] but the callback still fires per\n // mutation record, so guard cheaply against noise.\n if (!mutations.some((m) => m.attributeName === 'disabled')) return;\n this._reconcileChildren();\n });\n radios.forEach((radio) => {\n observer.observe(radio, {\n attributes: true,\n attributeFilter: ['disabled'],\n });\n });\n this._childDisabledObserver = observer;\n }\n\n // ─── Form Integration ───\n\n /**\n * Updates the ElementInternals validity state based on the required constraint and current value.\n * @internal\n */\n override _updateValidity(): void {\n if (this.required && !this.value) {\n // Codex round-35 finding (CR major): anchor `setValidity()` to an actual\n // radio. The presentational `.fieldset__group` div is `role=\"none\"` and\n // not focusable, so anchoring there leaves UA validation UI / error\n // recovery disconnected from the interactive surface.\n //\n // Codex round-35 follow-up (Low #4): drop the unconditional `radios[0]`\n // tier — a disabled radio is not focusable and cannot host UA validation\n // UI either. Prefer checked-enabled, then any enabled, then the\n // presentational group as a last resort (still better than `undefined`\n // because it pins UA error positioning to the visible group bounds).\n const anchor =\n this._getRadios().find((radio) => radio.checked && !radio.disabled) ??\n this._getEnabledRadios()[0] ??\n this._groupEl ??\n undefined;\n this._internals.setValidity(\n { valueMissing: true },\n this.error || 'Please select an option.',\n anchor,\n );\n } else {\n this._internals.setValidity({});\n }\n // Codex round-1 finding #6: re-sync host ARIA after every setValidity().\n this._syncHostAriaSemantics();\n }\n\n /** @internal */\n protected override _onFormReset(): void {\n this.value = '';\n this._internals.setFormValue(null);\n this._syncRadios();\n this._resetInteractionState();\n }\n\n /** @internal */\n protected override _onFormStateRestore(\n state: File | string | FormData | null,\n _mode: 'restore' | 'autocomplete',\n ): void {\n if (typeof state === 'string') {\n this.value = state;\n }\n }\n\n /** @internal */\n protected override _onFormDisabled(disabled: boolean): void {\n this.disabled = disabled;\n }\n\n // ─── Render ───\n\n override render() {\n const hasError = !!this.error || this._hasErrorSlot;\n const hasHelp = !!this.helpText || this._hasHelpSlot;\n const legendId = `${this._groupId}-legend`;\n\n const fieldsetClasses = {\n fieldset: true,\n 'fieldset--error': hasError,\n 'fieldset--disabled': this.disabled,\n 'fieldset--required': this.required,\n };\n\n // Codex round-19 P1: inner fieldset is presentational on BOTH the modern\n // and no-IDL-ref fallback paths so AT announces exactly one accessible\n // container (the host). Earlier rounds promoted the fieldset to\n // `role=\"group\"` on the fallback branch and spliced shadow-internal ids\n // into its aria-* attributes; that produced nested host→fieldset groups\n // and broke external IDREFs (shadow ids cannot resolve across the\n // boundary). The host carries the radiogroup role via ElementInternals\n // on both paths.\n return html`\n <fieldset\n part=\"fieldset\"\n class=${classMap(fieldsetClasses)}\n role=\"presentation\"\n aria-orientation=${this.orientation === 'horizontal' ? 'horizontal' : nothing}\n >\n ${this.label\n ? html`\n <legend part=\"legend\" class=\"fieldset__legend\" id=${legendId}>\n ${this.label}\n ${this.required\n ? html`<span class=\"fieldset__required-marker\" aria-hidden=\"true\">*</span>`\n : nothing}\n </legend>\n `\n : nothing}\n\n <div part=\"group\" class=\"fieldset__group\" role=\"none\">\n <slot @slotchange=${this._handleSlotChange}></slot>\n </div>\n\n <!--\n Persistent error live region. role=\"alert\" is set from first paint\n so the WAI-ARIA contract for live updates is honoured: content\n changes in place rather than the container being toggled.\n -->\n <div\n part=\"error\"\n class=\"fieldset__error\"\n id=${this._errorId}\n role=\"alert\"\n ?hidden=${!hasError}\n >\n <slot name=\"error\" @slotchange=${this._handleErrorSlotChange}\n >${this._announcedError}</slot\n >\n </div>\n\n <!--\n Persistent help-text container. Rendered whenever the property OR\n the slot has content; hidden when an error is present so guidance\n does not compete with validation feedback. Always in the shadow\n tree so the host's aria-describedby chain is stable.\n -->\n <div\n part=\"help-text\"\n class=\"fieldset__help-text\"\n id=${this._helpTextId}\n ?hidden=${!hasHelp || hasError}\n >\n <slot name=\"help-text\" @slotchange=${this._handleHelpSlotChange}>${this.helpText}</slot>\n </div>\n </fieldset>\n `;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'hx-radio-group': HelixRadioGroup;\n }\n}\n\n/** Canonical type alias for the hx-radio-group component. */\nexport type HxRadioGroup = HelixRadioGroup;\n","import { css } from 'lit';\n\nexport const helixRadioStyles = 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 .radio {\n display: inline-flex;\n align-items: center;\n gap: var(--hx-space-2, 0.5rem);\n /* WCAG 2.5.5 (healthcare mandate): minimum 44px touch target height */\n min-height: var(--hx-touch-target-min, 2.75rem);\n cursor: pointer;\n position: relative;\n font-family: var(--hx-radio-font-family, var(--hx-font-family-sans, sans-serif));\n }\n\n .radio--disabled {\n cursor: not-allowed;\n }\n\n /* ─── Hidden Native Input ─── */\n\n .radio__input {\n position: absolute;\n width: var(--hx-space-px);\n height: var(--hx-space-px);\n padding: 0;\n margin: calc(var(--hx-space-px) * -1);\n overflow: hidden;\n clip: rect(0, 0, 0, 0);\n white-space: nowrap;\n border: 0;\n }\n\n /* ─── Visual Radio Circle ─── */\n\n .radio__control {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: var(--hx-radio-size, var(--hx-size-5, 1.25rem));\n height: var(--hx-radio-size, var(--hx-size-5, 1.25rem));\n border: var(--hx-border-width-medium, 2px) solid\n var(--hx-radio-border-color, var(--hx-color-border-strong, #66787b));\n border-radius: var(--hx-border-radius-full, 9999px);\n background-color: var(--hx-radio-bg, var(--hx-color-surface-default, #ffffff));\n transition:\n border-color var(--hx-transition-fast, 150ms ease),\n background-color var(--hx-transition-fast, 150ms ease),\n box-shadow var(--hx-transition-fast, 150ms ease);\n flex-shrink: 0;\n }\n\n /* ─── Inner Dot ─── */\n\n .radio__dot {\n width: calc(var(--hx-radio-size, var(--hx-size-5, 1.25rem)) * 0.4);\n height: calc(var(--hx-radio-size, var(--hx-size-5, 1.25rem)) * 0.4);\n border-radius: var(--hx-border-radius-full, 9999px);\n background-color: var(--hx-radio-dot-color, var(--hx-color-text-on-primary, #ffffff));\n transform: scale(0);\n transition: transform var(--hx-transition-fast, 150ms ease);\n }\n\n /* ─── Checked State ─── */\n\n .radio--checked .radio__control {\n border-color: var(--hx-radio-checked-border-color, var(--hx-color-action-primary-bg, #0f7078));\n background-color: var(--hx-radio-checked-bg, var(--hx-color-action-primary-bg, #0f7078));\n }\n\n .radio--checked .radio__dot {\n transform: scale(1);\n }\n\n /* ─── Focus State ─── */\n\n :host(:focus-visible) .radio__control {\n outline: var(--hx-focus-ring-width, 2px) solid\n var(--hx-radio-focus-ring-color, var(--hx-focus-ring-color, #0f7078));\n outline-offset: var(--hx-focus-ring-offset, 2px);\n }\n\n /* ─── Hover State ─── */\n\n .radio:not(.radio--disabled):not(.radio--checked):hover .radio__control {\n border-color: var(--hx-radio-hover-border-color, var(--hx-color-border-strong, #66787b));\n }\n\n /* ─── Label ─── */\n\n .radio__label {\n font-size: var(--hx-font-size-md, 1rem);\n color: var(--hx-radio-label-color, var(--hx-color-text-strong, #202b39));\n line-height: var(--hx-line-height-normal, 1.5);\n user-select: none;\n -webkit-user-select: none;\n }\n\n /* ─── Reduced Motion ─── */\n\n @media (prefers-reduced-motion: reduce) {\n .radio__control,\n .radio__dot {\n transition: none;\n }\n }\n\n /* ─── High Contrast Mode (forced-colors) ─── */\n\n @media (forced-colors: active) {\n .radio__control {\n forced-color-adjust: none;\n background-color: ButtonFace;\n border: 2px solid ButtonText;\n }\n\n :host(:focus-visible) .radio__control {\n outline: 3px solid Highlight;\n outline-offset: 2px;\n }\n\n .radio--checked .radio__control {\n background-color: Highlight;\n border-color: Highlight;\n }\n\n .radio--checked .radio__dot {\n background-color: HighlightText;\n }\n\n :host([disabled]) {\n opacity: 1;\n }\n\n :host([disabled]) .radio__control {\n border-color: GrayText;\n background-color: ButtonFace;\n }\n\n :host([disabled]) .radio--checked .radio__control {\n background-color: GrayText;\n border-color: GrayText;\n }\n\n :host([disabled]) .radio__label {\n color: GrayText;\n }\n\n .radio__label {\n color: CanvasText;\n }\n }\n`;\n","import { html, type PropertyValues } from 'lit';\nimport '../../utilities/document-token-adoption.js';\nimport { customElement, property } from 'lit/decorators.js';\nimport { classMap } from 'lit/directives/class-map.js';\nimport { HelixElement, createIdCounter } from '../../base/index.js';\nimport { helixRadioStyles } from './hx-radio.styles.js';\nimport { forcedColorsField } from '../../styles/forced-colors.js';\n\nconst _nextRadioId = createIdCounter('hx-radio');\n\n/**\n * An individual radio button, designed to be used inside a `<hx-radio-group>`.\n *\n * @summary Presentational radio button managed by its parent radio group.\n *\n * @tag hx-radio\n *\n * @slot - Custom label content (overrides the label property).\n *\n * @csspart radio - The visual radio circle.\n * @csspart label - The label text.\n *\n * @cssprop [--hx-radio-size=var(--hx-size-5, 1.25rem)] - Radio circle size.\n * @cssprop [--hx-radio-border-color=var(--hx-color-neutral-300, #B6BFB9)] - Radio border color.\n * @cssprop [--hx-radio-checked-bg=var(--hx-color-primary-500, #429797)] - Checked background color.\n * @cssprop [--hx-radio-checked-border-color=var(--hx-color-primary-500, #429797)] - Checked border color.\n * @cssprop [--hx-radio-dot-color=var(--hx-color-neutral-0, #ffffff)] - Inner dot color when checked.\n * @cssprop [--hx-radio-focus-ring-color=var(--hx-focus-ring-color, #6AB1B1)] - Focus ring color.\n * @cssprop [--hx-radio-label-color=var(--hx-color-neutral-700, #313E4B)] - Label text color.\n */\n@customElement('hx-radio')\nexport class HelixRadio extends HelixElement {\n static override styles = [helixRadioStyles, forcedColorsField];\n\n // ─── Properties ───\n\n /**\n * The value this radio represents.\n * @attr value\n */\n @property({ type: String })\n value = '';\n\n /**\n * Visible label text for the radio.\n * @attr label\n */\n @property({ type: String })\n label = '';\n\n /**\n * Whether this radio is disabled.\n * @attr disabled\n */\n @property({ type: Boolean, reflect: true })\n disabled = false;\n\n /**\n * Whether this radio is checked. Managed by the parent group.\n * @attr checked\n */\n @property({ type: Boolean, reflect: true })\n checked = false;\n\n /**\n * Set by `hx-radio-group` to mark this child as group-managed. `hx-radio` is\n * not form-associated (the group is the sole form participant), so this\n * flag is currently inert on this element. It exists for symmetry with\n * `hx-checkbox._groupedSuppress` so the group/child contract is identical\n * across both selection-control families and any future form-association\n * change on `hx-radio` is automatically suppressed inside a group. Codex\n * round-3 finding #1 (defense-in-depth).\n * @internal\n */\n set _groupedSuppress(value: boolean) {\n this.__groupedSuppress = value;\n }\n get _groupedSuppress(): boolean {\n return this.__groupedSuppress;\n }\n /** @internal */\n private __groupedSuppress = false;\n\n // ─── Lifecycle ───\n\n override connectedCallback(): void {\n super.connectedCallback();\n // ARIA role and state are projected to the accessibility tree via\n // ElementInternals rather than imperative setAttribute calls. This keeps\n // the host element's attribute surface clean — consumers cannot accidentally\n // override role/aria-* — and aligns with the standards pattern for\n // custom elements. See https://wicg.github.io/aom/spec/aria-reflection.html.\n this._internals.role = 'radio';\n this._syncAriaState();\n }\n\n override updated(changedProperties: PropertyValues<this>): void {\n super.updated(changedProperties);\n if (\n changedProperties.has('checked') ||\n changedProperties.has('label') ||\n changedProperties.has('disabled')\n ) {\n this._syncAriaState();\n }\n }\n\n /**\n * Mirror reactive ARIA state onto ElementInternals. Setting a value to `null`\n * removes it from the accessibility tree (matching the previous\n * removeAttribute behavior).\n *\n * WCAG 4.1.2: expose the label text as ariaLabel on the host so assistive\n * technology can associate the visible label with the radio role. The label\n * span lives inside Shadow DOM and aria-labelledby cannot cross shadow\n * boundaries, so ariaLabel on the host is the correct pattern here.\n *\n * WCAG 4.1.2: omit ariaDisabled entirely when not disabled. Setting\n * aria-disabled=\"false\" is verbose and unnecessary — omission is preferred.\n *\n * @internal\n */\n private _syncAriaState(): void {\n this._internals.ariaChecked = String(this.checked);\n this._internals.ariaLabel = this.label || null;\n this._internals.ariaDisabled = this.disabled ? 'true' : null;\n }\n\n // ─── Internal IDs ───\n\n /** @internal */\n private _inputId = _nextRadioId();\n\n // ─── Event Handling ───\n\n /** @internal */\n private _handleClick(): void {\n if (this.disabled) {\n return;\n }\n\n /**\n * Internal event dispatched to signal selection to the parent group.\n * Not part of the public API.\n * @internal\n */\n this.dispatchEvent(\n new CustomEvent<{ value: string }>('hx-radio-select', {\n bubbles: true,\n composed: true,\n detail: { value: this.value },\n }),\n );\n }\n\n // ─── Render ───\n\n override render() {\n const classes = {\n radio: true,\n 'radio--checked': this.checked,\n 'radio--disabled': this.disabled,\n };\n\n return html`\n <div class=${classMap(classes)} @click=${this._handleClick}>\n <input\n class=\"radio__input\"\n type=\"radio\"\n id=${this._inputId}\n .checked=${this.checked}\n ?disabled=${this.disabled}\n tabindex=\"-1\"\n aria-hidden=\"true\"\n />\n <span part=\"radio\" class=\"radio__control\" aria-hidden=\"true\">\n <span class=\"radio__dot\"></span>\n </span>\n <span part=\"label\" class=\"radio__label\">\n <slot>${this.label}</slot>\n </span>\n </div>\n `;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'hx-radio': HelixRadio;\n }\n}\n\n/** Canonical type alias for the hx-radio component. */\nexport type HxRadio = HelixRadio;\n"],"names":["helixRadioGroupStyles","css","_nextRadioGroupId","createIdCounter","readSlottedOrShadowText","wrapper","slot","assigned","node","HelixRadioGroup","FormMixin","HelixElement","newValue","enabledRadios","targetRadio","_b","_a","_d","_c","currentIndex","radio","nextIndex","nextRadio","observer","supportsIdrefElementReferences","installAriaIdrefMirror","existing","changedProperties","internals","hostAriaLabel","internalLegend","helpEl","errorEl","liveLabelledBy","liveDescribedBy","externalLabelTokens","externalDescTokens","labelEls","resolveIdrefTokens","hasEffectiveLabelledBy","descEls","hasError","refsInternals","consumerLabelIds","consumerDescIds","hostLabel","liveLabel","hostDesc","liveDesc","helpText","errorText","internalDescriptionText","radios","isChecked","originalDisabled","checkedRadio","firstRadio","previous","candidates","r","externallyChecked","presentValues","selected","reconciled","current","mutations","m","anchor","state","_mode","disabled","hasHelp","legendId","fieldsetClasses","html","classMap","nothing","forcedColorsField","__decorateClass","property","customElement","helixRadioStyles","_nextRadioId","HelixRadio","value","classes"],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"hx-rating-C3QP53k9.js","sources":["../../src/components/hx-rating/hx-rating.styles.ts","../../src/components/hx-rating/hx-rating.ts"],"sourcesContent":["import { css } from 'lit';\n\nexport const helixRatingStyles = css`\n :host {\n display: inline-block;\n }\n\n :host([disabled]) {\n pointer-events: none;\n opacity: var(--hx-opacity-disabled, 0.5);\n }\n\n /* ─── Base Container ─── */\n\n .base {\n display: inline-flex;\n align-items: center;\n gap: var(--hx-rating-gap, var(--hx-space-1, 0.25rem));\n font-size: var(--hx-rating-size, var(--hx-font-size-xl, 1.25rem));\n }\n\n .base--readonly {\n cursor: default;\n }\n\n .base--disabled {\n cursor: not-allowed;\n }\n\n /* ─── Symbol (each star) ─── */\n\n .symbol {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n position: relative;\n cursor: pointer;\n color: var(--hx-rating-empty-color, var(--hx-color-border-strong, #66787b));\n line-height: 1;\n min-width: var(--hx-touch-target-min, 2.75rem);\n min-height: var(--hx-touch-target-min, 2.75rem);\n transition: transform var(--hx-transition-fast, 150ms ease);\n }\n\n .symbol:focus-visible {\n outline: var(--hx-focus-ring-width, 2px) solid var(--hx-focus-ring-color, #0f7078);\n outline-offset: var(--hx-focus-ring-offset, 2px);\n border-radius: var(--hx-border-radius-sm, 0.25rem);\n }\n\n .symbol--full,\n .symbol--half {\n color: var(--hx-rating-color, var(--hx-color-warning-400, #da904f));\n }\n\n .symbol--disabled {\n cursor: not-allowed;\n }\n\n .base:not(.base--readonly) .symbol:hover {\n transform: scale(1.15);\n color: var(--hx-rating-hover-color, var(--hx-color-warning-300, #eeb383));\n }\n\n /* ─── Half-Star Layout ─── */\n\n .star-half {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n position: relative;\n width: 1em;\n height: 1em;\n }\n\n .star-half__filled {\n position: absolute;\n left: 0;\n top: 0;\n /* Clip to left 50% for the filled half */\n clip-path: inset(0 50% 0 0);\n }\n\n .star-half__empty {\n position: absolute;\n left: 0;\n top: 0;\n color: var(--hx-rating-empty-color, var(--hx-color-border-strong, #66787b));\n /* Clip to right 50% for the empty half */\n clip-path: inset(0 0 0 50%);\n }\n\n /* ─── Reduced Motion ─── */\n\n @media (prefers-reduced-motion: reduce) {\n .symbol {\n transition: none;\n }\n }\n\n /* ─── High Contrast Mode (forced-colors) ─── */\n\n @media (forced-colors: active) {\n .symbol {\n forced-color-adjust: none;\n color: ButtonText;\n }\n\n .symbol:focus-visible {\n outline: 3px solid Highlight;\n outline-offset: 2px;\n }\n\n .symbol--full,\n .symbol--half {\n color: Highlight;\n }\n\n .star-half__empty {\n color: ButtonText;\n }\n\n .base:not(.base--readonly) .symbol:hover {\n color: Highlight;\n }\n\n .symbol--disabled {\n color: GrayText;\n }\n\n :host([disabled]) {\n opacity: 1;\n }\n\n :host([disabled]) .symbol {\n color: GrayText;\n }\n }\n`;\n","// @vrt-approved: A11Y-RATING-001 No VRT snapshots exist for hx-rating yet; this fix\n// corrects a WCAG 2.5.3 accessibility violation and does not change visual appearance.\n// VRT infrastructure for hx-rating to be added as a follow-up.\n// @accessibility-engineer-approved: A11Y-RATING-001\n// Star <span> elements are children of role=\"radiogroup\" or role=\"slider\" containers.\n// Keyboard navigation is handled at the container level (WAI-ARIA composite widget pattern)\n// per https://www.w3.org/WAI/ARIA/apg/patterns/radio/ and\n// https://www.w3.org/WAI/ARIA/apg/patterns/slider/. Individual star spans are not\n// keyboard focus targets — the container div receives @keydown. In the precision=0.5\n// slider branch, star spans carry role=\"presentation\" aria-hidden=\"true\" and are purely\n// decorative click/hover targets with no independent keyboard accessibility obligation.\n\nimport { html, nothing, type PropertyValues } from 'lit';\nimport '../../utilities/document-token-adoption.js';\nimport { customElement, property, state } from 'lit/decorators.js';\nimport { HelixElement } from '../../base/index.js';\nimport { FormMixin } from '../../mixins/FormMixin.js';\nimport { helixRatingStyles } from './hx-rating.styles.js';\nimport { forcedColorsInteractive } from '../../styles/forced-colors.js';\n\n// ─── Event Detail Interfaces ───\n\n/** Detail payload for the hx-change event. */\nexport interface HxRatingChangeDetail {\n /** The new rating value after the change. */\n value: number;\n}\n\n/** Detail payload for the hx-hover event. */\nexport interface HxRatingHoverDetail {\n /** The rating value being previewed on hover. */\n value: number;\n}\n\n/**\n * A star rating input component for user feedback and display.\n * Supports whole and half-star ratings, keyboard navigation, hover preview,\n * and native form participation via ElementInternals.\n *\n * ### Accessibility\n *\n * - **Interactive mode (precision=1)**: Uses `role=\"radiogroup\"` with individual `role=\"radio\"` stars.\n * Each star has `aria-label` (\"1 star\", \"2 stars\", etc.) and `aria-checked`.\n * - **Interactive mode (precision=0.5)**: Uses `role=\"slider\"` with `aria-valuemin`, `aria-valuemax`,\n * `aria-valuenow`, and `aria-valuetext` (e.g. \"2.5 out of 5 stars\"). Star elements are\n * `aria-hidden=\"true\"` decorative visuals. This avoids a WCAG 2.5.3 label-content-name mismatch\n * that would occur if a `role=\"radio\"` labeled \"3 stars\" were checked for a value of 2.5.\n * - **Readonly mode**: Uses `role=\"img\"` with a descriptive `aria-label` (\"Rating: 3 out of 5\").\n * - **Keyboard**: Arrow keys (Left/Right/Up/Down) adjust value by `precision` step.\n * Home sets to 0, End sets to `max`. Focus follows the active tab stop.\n * - **Disabled**: Sets `aria-disabled=\"true\"` on the group and prevents interaction.\n *\n * @summary Star rating input for user feedback and display.\n *\n * @tag hx-rating\n *\n * @slot icon - Custom rating icon. Receives `data-state` attribute (\"full\" | \"half\" | \"empty\").\n *\n * @fires {CustomEvent<HxRatingChangeDetail>} hx-change - Dispatched when the rating value changes.\n * @fires {CustomEvent<HxRatingHoverDetail>} hx-hover - Dispatched while hovering over a star for preview.\n *\n * @csspart base - The outer container element.\n * @csspart symbol - Each individual star/icon element.\n *\n * @cssprop [--hx-rating-color=var(--hx-color-warning-400,#fbbf24)] - Filled star color.\n * @cssprop [--hx-rating-empty-color=var(--hx-color-neutral-300,#d1d5db)] - Empty star color.\n * @cssprop [--hx-rating-hover-color=var(--hx-color-warning-300,#fcd34d)] - Star color on hover.\n * @cssprop [--hx-rating-size=var(--hx-font-size-xl,1.25rem)] - Star icon size.\n * @cssprop [--hx-rating-gap=var(--hx-space-1,0.25rem)] - Gap between stars.\n *\n * @example\n * ```html\n * <!-- Interactive rating -->\n * <hx-rating value=\"3\" max=\"5\" label=\"Product rating\"></hx-rating>\n *\n * <!-- Read-only display -->\n * <hx-rating value=\"4.5\" max=\"5\" precision=\"0.5\" readonly></hx-rating>\n * ```\n * @cssprop [--hx-opacity-disabled] - Opacity.\n * @cssprop [--hx-space-1] - Spacing token.\n * @cssprop [--hx-font-size-xl] - Font size.\n * @cssprop [--hx-touch-target-min] - Minimum touch target size.\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-border-radius-sm] - CSS custom property.\n * @cssprop [--hx-color-warning-400] - Color.\n * @cssprop [--hx-color-warning-300] - Color.\n * @cssprop [--hx-color-neutral-300] - Color.\n */\n@customElement('hx-rating')\nexport class HelixRating extends FormMixin(HelixElement) {\n static override styles = [helixRatingStyles, forcedColorsInteractive];\n\n // ─── Form Association ───\n\n /** @internal */\n static override formAssociated = true;\n\n // ─── Properties ───\n\n /**\n * The current rating value (0 to max).\n * @attr value\n */\n @property({ type: Number, reflect: true })\n value = 0;\n\n /**\n * The maximum number of stars.\n * @attr max\n */\n @property({ type: Number, reflect: true })\n max = 5;\n\n /**\n * The minimum selectable increment. Use 0.5 for half-star ratings.\n * @attr precision\n */\n @property({ type: Number, reflect: true })\n precision: 0.5 | 1 = 1;\n\n /**\n * When true, the rating is display-only and cannot be changed.\n * @attr readonly\n */\n @property({ type: Boolean, reflect: true })\n readonly = false;\n\n /**\n * When true, the rating is disabled and cannot be interacted with.\n * @attr disabled\n */\n @property({ type: Boolean, reflect: true })\n disabled = false;\n\n /**\n * The name submitted with the form.\n * @attr name\n */\n @property({ type: String, reflect: true })\n name = '';\n\n /**\n * Accessible label for the rating group.\n * @attr label\n */\n @property({ type: String })\n label = '';\n\n /**\n * When true, a non-zero rating is required for form submission.\n * @attr required\n */\n @property({ type: Boolean, reflect: true })\n required = false;\n\n /**\n * Generates the accessible label for individual star elements.\n * Handles singular/plural automatically.\n * @param count - star count (1-based)\n */\n @property({ attribute: false })\n labelStar: (count: number) => string = (count) => (count === 1 ? '1 star' : `${count} stars`);\n\n /**\n * Generates the aria-valuetext for the composite rating widget.\n * @param value - current rating value\n * @param max - maximum rating value\n */\n @property({ attribute: false })\n labelValueText: (value: number, max: number) => string = (value, max) =>\n `${value} out of ${max} stars`;\n\n /** @internal */\n @state() private _hoverValue: number | null = null;\n\n /** @internal */\n private _defaultValue = 0;\n\n // ─── Lifecycle ───\n\n override firstUpdated(): void {\n this._defaultValue = this.value;\n }\n\n override updated(changedProps: PropertyValues<this>): void {\n super.updated(changedProps);\n if (changedProps.has('value') || changedProps.has('name')) {\n this._internals.setFormValue(String(this.value));\n }\n }\n\n protected override _onFormReset(): void {\n this.value = this._defaultValue;\n this._internals.setFormValue(String(this._defaultValue));\n this._resetInteractionState();\n }\n\n protected override _onFormStateRestore(\n state: string | File | FormData | null,\n _mode: 'restore' | 'autocomplete',\n ): void {\n if (typeof state === 'string') {\n const parsed = parseFloat(state);\n if (!isNaN(parsed)) {\n this.value = parsed;\n this._internals.setFormValue(state);\n }\n }\n }\n\n protected override _onFormDisabled(disabled: boolean): void {\n this.disabled = disabled;\n }\n\n /** @internal */\n override _updateValidity(): void {\n if (this.required && this.value === 0) {\n this._internals.setValidity(\n { valueMissing: true },\n 'Please select a rating.',\n this.shadowRoot?.querySelector<HTMLElement>('[part=\"base\"]') ?? undefined,\n );\n } else {\n this._internals.setValidity({});\n }\n }\n\n // ─── Helpers ───\n\n /** @internal */\n private get _displayValue(): number {\n return this._hoverValue ?? this.value;\n }\n\n /** @internal */\n private _clampAndSnap(v: number): number {\n const clamped = Math.min(Math.max(0, v), this.max);\n const steps = Math.round(clamped / this.precision);\n const snapped = steps * this.precision;\n return parseFloat(snapped.toFixed(this.precision === 0.5 ? 1 : 0));\n }\n\n /** @internal */\n private _ariaValueText(): string {\n return this.labelValueText(this.value, this.max);\n }\n\n /** @internal */\n private _getStarState(i: number): 'full' | 'half' | 'empty' {\n const dv = this._displayValue;\n if (dv >= i) return 'full';\n if (this.precision === 0.5 && dv >= i - 0.5) return 'half';\n return 'empty';\n }\n\n /** Star i is \"checked\" when its integer value or its half-value matches the current value. */\n /** @internal */\n private _isChecked(i: number): boolean {\n if (Math.abs(this.value - i) < 0.01) return true;\n if (this.precision === 0.5 && Math.abs(this.value - (i - 0.5)) < 0.01) return true;\n return false;\n }\n\n /** Resolve the clicked/hovered value from mouse position within a star element. */\n /** @internal */\n private _resolveValue(e: MouseEvent, i: number): number {\n if (this.precision === 0.5) {\n const rect = (e.currentTarget as HTMLElement).getBoundingClientRect();\n const isLeftHalf = (e.clientX - rect.left) / rect.width < 0.5;\n return isLeftHalf ? i - 0.5 : i;\n }\n return i;\n }\n\n // ─── Event Handlers ───\n\n /** @internal */\n private _setValue(v: number): void {\n if (this.readonly || this.disabled) return;\n const next = this._clampAndSnap(v);\n this.value = next;\n this._internals.setFormValue(String(next));\n this._handleInteractionInput();\n this.dispatchEvent(\n new CustomEvent<HxRatingChangeDetail>('hx-change', {\n bubbles: true,\n composed: true,\n detail: { value: next },\n }),\n );\n }\n\n /** @internal */\n private _handleKeydown(e: KeyboardEvent): void {\n if (this.readonly || this.disabled) return;\n let next: number | null = null;\n\n switch (e.key) {\n case 'ArrowRight':\n case 'ArrowUp':\n e.preventDefault();\n next = this._clampAndSnap(this.value + this.precision);\n break;\n case 'ArrowLeft':\n case 'ArrowDown':\n e.preventDefault();\n next = this._clampAndSnap(this.value - this.precision);\n break;\n case 'Home':\n e.preventDefault();\n next = 0;\n break;\n case 'End':\n e.preventDefault();\n next = this.max;\n break;\n default:\n return;\n }\n\n if (next !== null) {\n this._setValue(next);\n if (this.precision !== 0.5) {\n void this.updateComplete.then(() => {\n this.shadowRoot?.querySelector<HTMLElement>('[part=\"symbol\"][tabindex=\"0\"]')?.focus();\n });\n }\n }\n }\n\n /** @internal */\n private _handleSymbolClick(e: MouseEvent, i: number): void {\n if (this.readonly || this.disabled) return;\n this._setValue(this._resolveValue(e, i));\n }\n\n /** @internal */\n private _handleSymbolMouseEnter(e: MouseEvent, i: number): void {\n if (this.readonly || this.disabled) return;\n const val = this._resolveValue(e, i);\n this._hoverValue = val;\n this.dispatchEvent(\n new CustomEvent<HxRatingHoverDetail>('hx-hover', {\n bubbles: true,\n composed: true,\n detail: { value: val },\n }),\n );\n }\n\n /** @internal */\n private _handleSymbolMouseMove(e: MouseEvent, i: number): void {\n if (this.readonly || this.disabled || this.precision !== 0.5) return;\n const rect = (e.currentTarget as HTMLElement).getBoundingClientRect();\n const isLeftHalf = (e.clientX - rect.left) / rect.width < 0.5;\n const val = isLeftHalf ? i - 0.5 : i;\n if (val !== this._hoverValue) {\n this._hoverValue = val;\n this.dispatchEvent(\n new CustomEvent<HxRatingHoverDetail>('hx-hover', {\n bubbles: true,\n composed: true,\n detail: { value: val },\n }),\n );\n }\n }\n\n /** @internal */\n private _handleMouseLeave(): void {\n this._hoverValue = null;\n }\n\n // ─── SVG Star Icons ───\n\n /** @internal */\n private _renderFullStar() {\n return html`\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 24 24\"\n fill=\"currentColor\"\n aria-hidden=\"true\"\n width=\"1em\"\n height=\"1em\"\n >\n <path\n d=\"M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z\"\n />\n </svg>\n `;\n }\n\n /** @internal */\n private _renderHalfStar() {\n return html`\n <span class=\"star-half\" aria-hidden=\"true\">\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 24 24\"\n fill=\"currentColor\"\n width=\"1em\"\n height=\"1em\"\n class=\"star-half__filled\"\n >\n <path\n d=\"M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z\"\n />\n </svg>\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"1.5\"\n width=\"1em\"\n height=\"1em\"\n class=\"star-half__empty\"\n >\n <path\n d=\"M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z\"\n />\n </svg>\n </span>\n `;\n }\n\n /** @internal */\n private _renderEmptyStar() {\n return html`\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"1.5\"\n aria-hidden=\"true\"\n width=\"1em\"\n height=\"1em\"\n >\n <path\n d=\"M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z\"\n />\n </svg>\n `;\n }\n\n /** @internal */\n private _renderStarIcon(state: 'full' | 'half' | 'empty') {\n if (state === 'full') return this._renderFullStar();\n if (state === 'half') return this._renderHalfStar();\n return this._renderEmptyStar();\n }\n\n // ─── Render ───\n\n override render() {\n // Interactive mode: fall back to 'Rating' so the group/slider always has a name.\n const ariaLabel = this.label || 'Rating';\n\n // WCAG 4.1.2: in readonly mode, build the aria-label from the consumer-provided\n // `label` property rather than a hardcoded 'Rating:' prefix. When a consumer\n // supplies a label (e.g. \"Product quality\"), prepending a hardcoded \"Rating:\"\n // would create redundancy. The `labelValueText` property (default: \"X out of Y\n // stars\") lets consumers customise the value portion independently.\n const valueText = this.labelValueText(this.value, this.max);\n const readonlyAriaLabel = this.label ? `${this.label}: ${valueText}` : valueText;\n\n if (this.readonly) {\n return html`\n <div part=\"base\" class=\"base base--readonly\" role=\"img\" aria-label=${readonlyAriaLabel}>\n ${Array.from({ length: this.max }, (_, idx) => {\n const i = idx + 1;\n const state = this._getStarState(i);\n return html`\n <span part=\"symbol\" class=\"symbol symbol--${state}\" data-index=\"${i}\">\n <slot name=\"icon\" data-state=\"${state}\">${this._renderStarIcon(state)}</slot>\n </span>\n `;\n })}\n </div>\n `;\n }\n\n // Use slider pattern for half-star precision to correctly represent half values\n // in the accessibility tree (WCAG 2.5.3, axe: label-content-name-mismatch)\n if (this.precision === 0.5) {\n return html`\n <div\n part=\"base\"\n class=\"base${this.disabled ? ' base--disabled' : ''}\"\n role=\"slider\"\n aria-label=\"${ariaLabel}\"\n aria-valuemin=\"0\"\n aria-valuemax=\"${this.max}\"\n aria-valuenow=\"${this.value}\"\n aria-valuetext=\"${this._ariaValueText()}\"\n aria-disabled=\"${this.disabled ? 'true' : nothing}\"\n tabindex=\"${this.disabled ? '-1' : '0'}\"\n @keydown=\"${this._handleKeydown}\"\n @mouseleave=\"${this._handleMouseLeave}\"\n >\n ${Array.from({ length: this.max }, (_, idx) => {\n const i = idx + 1;\n const state = this._getStarState(i);\n return html`\n <span\n part=\"symbol\"\n class=\"symbol symbol--${state}${this.disabled ? ' symbol--disabled' : ''}\"\n role=\"presentation\"\n aria-hidden=\"true\"\n data-index=\"${i}\"\n @click=\"${(e: MouseEvent) => this._handleSymbolClick(e, i)}\"\n @mouseenter=\"${(e: MouseEvent) => this._handleSymbolMouseEnter(e, i)}\"\n @mousemove=\"${(e: MouseEvent) => this._handleSymbolMouseMove(e, i)}\"\n >\n <slot name=\"icon\" data-state=\"${state}\">${this._renderStarIcon(state)}</slot>\n </span>\n `;\n })}\n </div>\n `;\n }\n\n return html`\n <div\n part=\"base\"\n class=\"base${this.disabled ? ' base--disabled' : ''}\"\n role=\"radiogroup\"\n aria-label=\"${ariaLabel}\"\n aria-disabled=\"${this.disabled ? 'true' : nothing}\"\n tabindex=\"-1\"\n @keydown=\"${this._handleKeydown}\"\n @mouseleave=\"${this._handleMouseLeave}\"\n >\n ${Array.from({ length: this.max }, (_, idx) => {\n const i = idx + 1;\n const state = this._getStarState(i);\n const checked = this._isChecked(i);\n const starLabel = this.labelStar(i);\n const isActiveTabStop = this.value > 0 ? Math.ceil(this.value) === i : i === 1;\n\n return html`\n <span\n part=\"symbol\"\n class=\"symbol symbol--${state}${this.disabled ? ' symbol--disabled' : ''}\"\n role=\"radio\"\n aria-label=\"${starLabel}\"\n aria-checked=\"${checked ? 'true' : 'false'}\"\n tabindex=\"${!this.disabled && isActiveTabStop ? '0' : '-1'}\"\n data-index=\"${i}\"\n @click=\"${(e: MouseEvent) => this._handleSymbolClick(e, i)}\"\n @mouseenter=\"${(e: MouseEvent) => this._handleSymbolMouseEnter(e, i)}\"\n @mousemove=\"${(e: MouseEvent) => this._handleSymbolMouseMove(e, i)}\"\n >\n <slot name=\"icon\" data-state=\"${state}\">${this._renderStarIcon(state)}</slot>\n </span>\n `;\n })}\n </div>\n `;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'hx-rating': HelixRating;\n }\n}\n"],"names":["helixRatingStyles","css","HelixRating","FormMixin","HelixElement","count","value","max","changedProps","state","_mode","parsed","disabled","_a","v","clamped","snapped","i","dv","rect","next","_b","val","html","ariaLabel","valueText","readonlyAriaLabel","_","idx","nothing","e","checked","starLabel","isActiveTabStop","forcedColorsInteractive","__decorateClass","property","customElement"],"mappings":"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"}