@helixui/library 3.2.0-next.91 → 3.2.0-next.96

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 (225) hide show
  1. package/custom-elements.json +358 -358
  2. package/dist/components/hx-accordion/hx-accordion-item.styles.d.ts.map +1 -1
  3. package/dist/components/hx-accordion/index.js +1 -1
  4. package/dist/components/hx-alert/index.js +1 -1
  5. package/dist/components/hx-banner/index.js +1 -1
  6. package/dist/components/hx-breadcrumb/hx-breadcrumb-item.styles.d.ts.map +1 -1
  7. package/dist/components/hx-breadcrumb/index.js +1 -1
  8. package/dist/components/hx-button/hx-button.styles.d.ts.map +1 -1
  9. package/dist/components/hx-button/index.js +1 -1
  10. package/dist/components/hx-card/hx-card.styles.d.ts.map +1 -1
  11. package/dist/components/hx-card/index.js +1 -1
  12. package/dist/components/hx-checkbox/index.js +1 -1
  13. package/dist/components/hx-clinical-status/hx-clinical-status.styles.d.ts.map +1 -1
  14. package/dist/components/hx-clinical-status/index.js +1 -1
  15. package/dist/components/hx-code-snippet/index.js +1 -1
  16. package/dist/components/hx-color-picker/hx-color-picker.styles.d.ts.map +1 -1
  17. package/dist/components/hx-color-picker/index.js +1 -1
  18. package/dist/components/hx-combobox/index.js +1 -1
  19. package/dist/components/hx-data-table/hx-data-table.styles.d.ts.map +1 -1
  20. package/dist/components/hx-data-table/index.js +1 -1
  21. package/dist/components/hx-date-picker/index.js +1 -1
  22. package/dist/components/hx-dialog/hx-dialog.styles.d.ts.map +1 -1
  23. package/dist/components/hx-dialog/index.js +1 -1
  24. package/dist/components/hx-drawer/hx-drawer.styles.d.ts.map +1 -1
  25. package/dist/components/hx-drawer/index.js +1 -1
  26. package/dist/components/hx-file-upload/hx-file-upload.styles.d.ts.map +1 -1
  27. package/dist/components/hx-file-upload/index.js +1 -1
  28. package/dist/components/hx-icon-button/hx-icon-button.styles.d.ts.map +1 -1
  29. package/dist/components/hx-icon-button/index.js +1 -1
  30. package/dist/components/hx-link/index.js +1 -1
  31. package/dist/components/hx-menu/hx-menu-item.styles.d.ts.map +1 -1
  32. package/dist/components/hx-menu/index.js +1 -1
  33. package/dist/components/hx-meter/hx-meter.styles.d.ts.map +1 -1
  34. package/dist/components/hx-meter/index.js +1 -1
  35. package/dist/components/hx-nav/hx-nav.styles.d.ts.map +1 -1
  36. package/dist/components/hx-nav/index.js +1 -1
  37. package/dist/components/hx-overflow-menu/hx-overflow-menu.styles.d.ts.map +1 -1
  38. package/dist/components/hx-overflow-menu/index.js +1 -1
  39. package/dist/components/hx-pagination/hx-pagination.styles.d.ts.map +1 -1
  40. package/dist/components/hx-pagination/index.js +1 -1
  41. package/dist/components/hx-phi-field/hx-phi-field.styles.d.ts.map +1 -1
  42. package/dist/components/hx-phi-field/index.js +1 -1
  43. package/dist/components/hx-popover/hx-popover.styles.d.ts.map +1 -1
  44. package/dist/components/hx-popover/index.js +1 -1
  45. package/dist/components/hx-radio-group/index.js +1 -1
  46. package/dist/components/hx-rating/index.js +1 -1
  47. package/dist/components/hx-select/index.js +1 -1
  48. package/dist/components/hx-side-nav/index.js +1 -1
  49. package/dist/components/hx-slider/index.js +1 -1
  50. package/dist/components/hx-split-button/hx-split-button.d.ts +1 -1
  51. package/dist/components/hx-split-button/index.js +1 -1
  52. package/dist/components/hx-split-panel/hx-split-panel.styles.d.ts.map +1 -1
  53. package/dist/components/hx-split-panel/index.js +1 -1
  54. package/dist/components/hx-steps/hx-step.styles.d.ts.map +1 -1
  55. package/dist/components/hx-steps/index.js +1 -1
  56. package/dist/components/hx-switch/index.js +1 -1
  57. package/dist/components/hx-table/hx-table.styles.d.ts.map +1 -1
  58. package/dist/components/hx-table/index.js +1 -1
  59. package/dist/components/hx-tabs/index.js +1 -1
  60. package/dist/components/hx-text-input/index.js +1 -1
  61. package/dist/components/hx-textarea/index.js +1 -1
  62. package/dist/components/hx-time-picker/index.js +1 -1
  63. package/dist/components/hx-toggle-button/index.js +1 -1
  64. package/dist/components/hx-top-nav/hx-top-nav.styles.d.ts.map +1 -1
  65. package/dist/components/hx-top-nav/index.js +1 -1
  66. package/dist/components/hx-tree-view/hx-tree-item.styles.d.ts.map +1 -1
  67. package/dist/components/hx-tree-view/index.js +1 -1
  68. package/dist/css/helix-all.css +100 -164
  69. package/dist/css/helix-core.css +16 -12
  70. package/dist/css/helix-data.css +7 -14
  71. package/dist/css/helix-feedback.css +4 -5
  72. package/dist/css/helix-forms.css +48 -67
  73. package/dist/css/helix-layout.css +2 -8
  74. package/dist/css/helix-navigation.css +12 -33
  75. package/dist/css/helix-overlay.css +3 -12
  76. package/dist/css/helix-tokens.css +16 -5
  77. package/dist/css/helix-utility.css +5 -5
  78. package/dist/css/hx-alert.css +1 -1
  79. package/dist/css/hx-banner.css +2 -2
  80. package/dist/css/hx-button.css +12 -2
  81. package/dist/css/hx-card.css +1 -4
  82. package/dist/css/hx-checkbox.css +2 -2
  83. package/dist/css/hx-clinical-status.css +2 -4
  84. package/dist/css/hx-code-snippet.css +4 -4
  85. package/dist/css/hx-color-picker.css +3 -13
  86. package/dist/css/hx-combobox.css +7 -7
  87. package/dist/css/hx-data-table.css +2 -8
  88. package/dist/css/hx-date-picker.css +7 -7
  89. package/dist/css/hx-dialog.css +1 -4
  90. package/dist/css/hx-drawer.css +1 -4
  91. package/dist/css/hx-file-upload.css +4 -13
  92. package/dist/css/hx-icon-button.css +2 -5
  93. package/dist/css/hx-link.css +1 -1
  94. package/dist/css/hx-meter.css +1 -2
  95. package/dist/css/hx-nav.css +2 -8
  96. package/dist/css/hx-overflow-menu.css +2 -8
  97. package/dist/css/hx-pagination.css +2 -8
  98. package/dist/css/hx-phi-field.css +1 -4
  99. package/dist/css/hx-popover.css +1 -4
  100. package/dist/css/hx-rating.css +3 -3
  101. package/dist/css/hx-select.css +2 -2
  102. package/dist/css/hx-side-nav.css +4 -4
  103. package/dist/css/hx-slider.css +4 -4
  104. package/dist/css/hx-split-button.css +5 -5
  105. package/dist/css/hx-split-panel.css +2 -8
  106. package/dist/css/hx-switch.css +3 -3
  107. package/dist/css/hx-table.css +1 -2
  108. package/dist/css/hx-text-input.css +4 -4
  109. package/dist/css/hx-textarea.css +2 -2
  110. package/dist/css/hx-time-picker.css +3 -3
  111. package/dist/css/hx-toggle-button.css +4 -4
  112. package/dist/css/hx-top-nav.css +1 -4
  113. package/dist/css/hx-tree-view.css +1 -1
  114. package/dist/css/index.css +1 -1
  115. package/dist/css/manifest.json +28 -26
  116. package/dist/index.js +42 -42
  117. package/dist/shared/{hx-accordion-cnKg4_la.js → hx-accordion-ZVzgDzTG.js} +4 -5
  118. package/dist/shared/hx-accordion-ZVzgDzTG.js.map +1 -0
  119. package/dist/shared/{hx-alert-BZH8iHQf.js → hx-alert-C597yHpD.js} +2 -2
  120. package/dist/shared/{hx-alert-BZH8iHQf.js.map → hx-alert-C597yHpD.js.map} +1 -1
  121. package/dist/shared/{hx-banner-DT7Zn9Bo.js → hx-banner-Cxd7eFUP.js} +3 -3
  122. package/dist/shared/{hx-banner-DT7Zn9Bo.js.map → hx-banner-Cxd7eFUP.js.map} +1 -1
  123. package/dist/shared/{hx-breadcrumb-item-COeYcB2x.js → hx-breadcrumb-item-3tKppF9h.js} +2 -5
  124. package/dist/shared/{hx-breadcrumb-item-COeYcB2x.js.map → hx-breadcrumb-item-3tKppF9h.js.map} +1 -1
  125. package/dist/shared/{hx-button-ebUV8KhT.js → hx-button-D3gC-OJb.js} +13 -3
  126. package/dist/shared/hx-button-D3gC-OJb.js.map +1 -0
  127. package/dist/shared/{hx-card-CU1QnjNb.js → hx-card-qNAM2QNV.js} +6 -9
  128. package/dist/shared/hx-card-qNAM2QNV.js.map +1 -0
  129. package/dist/shared/{hx-checkbox-C46TyXhM.js → hx-checkbox-DBD-gMoz.js} +3 -3
  130. package/dist/shared/{hx-checkbox-C46TyXhM.js.map → hx-checkbox-DBD-gMoz.js.map} +1 -1
  131. package/dist/shared/{hx-clinical-status-BmSjfSEN.js → hx-clinical-status-D3XQIOqX.js} +3 -5
  132. package/dist/shared/hx-clinical-status-D3XQIOqX.js.map +1 -0
  133. package/dist/shared/{hx-code-snippet-CJ0FbQYG.js → hx-code-snippet-CJrFeyz0.js} +5 -5
  134. package/dist/shared/{hx-code-snippet-CJ0FbQYG.js.map → hx-code-snippet-CJrFeyz0.js.map} +1 -1
  135. package/dist/shared/{hx-color-picker-DiDLZyvK.js → hx-color-picker-uRc865FJ.js} +23 -33
  136. package/dist/shared/hx-color-picker-uRc865FJ.js.map +1 -0
  137. package/dist/shared/{hx-combobox-DaA5dBC4.js → hx-combobox-ClhNRAS5.js} +8 -8
  138. package/dist/shared/hx-combobox-ClhNRAS5.js.map +1 -0
  139. package/dist/shared/{hx-data-table-Cq3t86Ic.js → hx-data-table-CLqVqdxr.js} +3 -9
  140. package/dist/shared/hx-data-table-CLqVqdxr.js.map +1 -0
  141. package/dist/shared/{hx-date-picker-DMqRQNSB.js → hx-date-picker-BJm7Yrda.js} +8 -8
  142. package/dist/shared/{hx-date-picker-DMqRQNSB.js.map → hx-date-picker-BJm7Yrda.js.map} +1 -1
  143. package/dist/shared/{hx-dialog-eIS8tcDm.js → hx-dialog-DRN_1-Y-.js} +2 -5
  144. package/dist/shared/hx-dialog-DRN_1-Y-.js.map +1 -0
  145. package/dist/shared/{hx-drawer-DDhDz7RI.js → hx-drawer-Y1Ui2IWJ.js} +2 -5
  146. package/dist/shared/hx-drawer-Y1Ui2IWJ.js.map +1 -0
  147. package/dist/shared/{hx-file-upload-zTDbjsRw.js → hx-file-upload-D3rKROK5.js} +17 -26
  148. package/dist/shared/hx-file-upload-D3rKROK5.js.map +1 -0
  149. package/dist/shared/{hx-icon-button-BmV97nqz.js → hx-icon-button-CGNdQSFM.js} +3 -6
  150. package/dist/shared/hx-icon-button-CGNdQSFM.js.map +1 -0
  151. package/dist/shared/{hx-link-DmiV-mPw.js → hx-link-9Ig2DW6L.js} +5 -5
  152. package/dist/shared/{hx-link-DmiV-mPw.js.map → hx-link-9Ig2DW6L.js.map} +1 -1
  153. package/dist/shared/{hx-menu-divider-j__TZjH2.js → hx-menu-divider-C2omnPtj.js} +2 -5
  154. package/dist/shared/hx-menu-divider-C2omnPtj.js.map +1 -0
  155. package/dist/shared/{hx-meter-Cm7k_Ro8.js → hx-meter-BPscsw5t.js} +2 -3
  156. package/dist/shared/hx-meter-BPscsw5t.js.map +1 -0
  157. package/dist/shared/{hx-nav-item-CvTxO3Sa.js → hx-nav-item-DH2tXcj1.js} +6 -6
  158. package/dist/shared/{hx-nav-item-CvTxO3Sa.js.map → hx-nav-item-DH2tXcj1.js.map} +1 -1
  159. package/dist/shared/{hx-nav-LoyEKZQC.js → hx-nav-ldFM3Fle.js} +37 -43
  160. package/dist/shared/hx-nav-ldFM3Fle.js.map +1 -0
  161. package/dist/shared/{hx-overflow-menu-BmKyAp5D.js → hx-overflow-menu-DCLsdIBy.js} +3 -9
  162. package/dist/shared/hx-overflow-menu-DCLsdIBy.js.map +1 -0
  163. package/dist/shared/{hx-pagination-Dqw5dorC.js → hx-pagination-C7y8GVyU.js} +54 -60
  164. package/dist/shared/hx-pagination-C7y8GVyU.js.map +1 -0
  165. package/dist/shared/{hx-phi-field-Bf9TdtC1.js → hx-phi-field-C19oxlrr.js} +2 -5
  166. package/dist/shared/hx-phi-field-C19oxlrr.js.map +1 -0
  167. package/dist/shared/{hx-popover-B93rTAfr.js → hx-popover-B-FP3-wW.js} +8 -11
  168. package/dist/shared/hx-popover-B-FP3-wW.js.map +1 -0
  169. package/dist/shared/{hx-radio-N8xgDd_5.js → hx-radio-dFjUAost.js} +4 -4
  170. package/dist/shared/{hx-radio-N8xgDd_5.js.map → hx-radio-dFjUAost.js.map} +1 -1
  171. package/dist/shared/{hx-rating-i2FL1WUN.js → hx-rating-CGtsejNf.js} +4 -4
  172. package/dist/shared/{hx-rating-i2FL1WUN.js.map → hx-rating-CGtsejNf.js.map} +1 -1
  173. package/dist/shared/{hx-select-vgaBo1Ai.js → hx-select-zfIRr9qM.js} +3 -3
  174. package/dist/shared/{hx-select-vgaBo1Ai.js.map → hx-select-zfIRr9qM.js.map} +1 -1
  175. package/dist/shared/{hx-slider-ydBamYhd.js → hx-slider-m0aEClH1.js} +5 -5
  176. package/dist/shared/{hx-slider-ydBamYhd.js.map → hx-slider-m0aEClH1.js.map} +1 -1
  177. package/dist/shared/{hx-split-button-BeMsmS6N.js → hx-split-button-BxDFfx4D.js} +6 -6
  178. package/dist/shared/{hx-split-button-BeMsmS6N.js.map → hx-split-button-BxDFfx4D.js.map} +1 -1
  179. package/dist/shared/{hx-split-panel-BVG1VWNT.js → hx-split-panel-B-u0Z3mm.js} +3 -9
  180. package/dist/shared/hx-split-panel-B-u0Z3mm.js.map +1 -0
  181. package/dist/shared/{hx-step-DL3PbOzm.js → hx-step-R2rjp1fT.js} +2 -5
  182. package/dist/shared/hx-step-R2rjp1fT.js.map +1 -0
  183. package/dist/shared/{hx-switch-Dougzsgp.js → hx-switch-DvAW4YY-.js} +4 -4
  184. package/dist/shared/{hx-switch-Dougzsgp.js.map → hx-switch-DvAW4YY-.js.map} +1 -1
  185. package/dist/shared/{hx-tab-panel-CbkO9VKu.js → hx-tab-panel-SWOEHuJc.js} +3 -3
  186. package/dist/shared/{hx-tab-panel-CbkO9VKu.js.map → hx-tab-panel-SWOEHuJc.js.map} +1 -1
  187. package/dist/shared/{hx-td-1zwTFLRw.js → hx-td-DnnEMIuA.js} +2 -3
  188. package/dist/shared/hx-td-DnnEMIuA.js.map +1 -0
  189. package/dist/shared/{hx-text-input-ClrrmoE1.js → hx-text-input-Bn7Gn8CI.js} +5 -5
  190. package/dist/shared/{hx-text-input-ClrrmoE1.js.map → hx-text-input-Bn7Gn8CI.js.map} +1 -1
  191. package/dist/shared/{hx-textarea-D9O4U8cb.js → hx-textarea-Jx1xnhgv.js} +7 -7
  192. package/dist/shared/{hx-textarea-D9O4U8cb.js.map → hx-textarea-Jx1xnhgv.js.map} +1 -1
  193. package/dist/shared/{hx-time-picker-m0z4nFB-.js → hx-time-picker-BoEIZwzv.js} +4 -4
  194. package/dist/shared/{hx-time-picker-m0z4nFB-.js.map → hx-time-picker-BoEIZwzv.js.map} +1 -1
  195. package/dist/shared/{hx-toggle-button-Dd8clXB4.js → hx-toggle-button-DPAIh_Xo.js} +24 -24
  196. package/dist/shared/{hx-toggle-button-Dd8clXB4.js.map → hx-toggle-button-DPAIh_Xo.js.map} +1 -1
  197. package/dist/shared/{hx-top-nav-CchPYaiV.js → hx-top-nav-DP6OFS8C.js} +11 -14
  198. package/dist/shared/hx-top-nav-DP6OFS8C.js.map +1 -0
  199. package/dist/shared/{hx-tree-item-DtMC3DTa.js → hx-tree-item-Dt0Ozqyr.js} +4 -10
  200. package/dist/shared/hx-tree-item-Dt0Ozqyr.js.map +1 -0
  201. package/figma-inventory.json +3 -3
  202. package/package.json +2 -2
  203. package/dist/shared/hx-accordion-cnKg4_la.js.map +0 -1
  204. package/dist/shared/hx-button-ebUV8KhT.js.map +0 -1
  205. package/dist/shared/hx-card-CU1QnjNb.js.map +0 -1
  206. package/dist/shared/hx-clinical-status-BmSjfSEN.js.map +0 -1
  207. package/dist/shared/hx-color-picker-DiDLZyvK.js.map +0 -1
  208. package/dist/shared/hx-combobox-DaA5dBC4.js.map +0 -1
  209. package/dist/shared/hx-data-table-Cq3t86Ic.js.map +0 -1
  210. package/dist/shared/hx-dialog-eIS8tcDm.js.map +0 -1
  211. package/dist/shared/hx-drawer-DDhDz7RI.js.map +0 -1
  212. package/dist/shared/hx-file-upload-zTDbjsRw.js.map +0 -1
  213. package/dist/shared/hx-icon-button-BmV97nqz.js.map +0 -1
  214. package/dist/shared/hx-menu-divider-j__TZjH2.js.map +0 -1
  215. package/dist/shared/hx-meter-Cm7k_Ro8.js.map +0 -1
  216. package/dist/shared/hx-nav-LoyEKZQC.js.map +0 -1
  217. package/dist/shared/hx-overflow-menu-BmKyAp5D.js.map +0 -1
  218. package/dist/shared/hx-pagination-Dqw5dorC.js.map +0 -1
  219. package/dist/shared/hx-phi-field-Bf9TdtC1.js.map +0 -1
  220. package/dist/shared/hx-popover-B93rTAfr.js.map +0 -1
  221. package/dist/shared/hx-split-panel-BVG1VWNT.js.map +0 -1
  222. package/dist/shared/hx-step-DL3PbOzm.js.map +0 -1
  223. package/dist/shared/hx-td-1zwTFLRw.js.map +0 -1
  224. package/dist/shared/hx-top-nav-CchPYaiV.js.map +0 -1
  225. package/dist/shared/hx-tree-item-DtMC3DTa.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"hx-alert-BZH8iHQf.js","sources":["../../src/components/hx-alert/hx-alert.styles.ts","../../src/components/hx-alert/hx-alert.ts"],"sourcesContent":["import { css } from 'lit';\n\n/**\n * hx-alert styles.\n *\n * Component-tier tokens with two-level var() fallback:\n * var(--hx-alert-{prop}, var(--hx-color-{semantic}, #hex))\n * Inner hex fallbacks track the \"precision cool\" palette (3.2.0):\n * info-50 = #EFF6FE, info-200 = #BEDCFC, info-500 = #0C8BEB, info-800 = #064172,\n * success-50 = #EAFAEC, success-200 = #BAE6C2, success-500 = #3B9E58, success-800 = #0B4D23,\n * warning-50 = #FFF3EA, warning-200 = #FACFAE, warning-500 = #C2711C, warning-800 = #603301,\n * error-50 = #FFF2F0, error-200 = #FCCBC4, error-500 = #E5493E, error-800 = #7A090A,\n * primary-400 = #6AB1B1.\n */\nexport const helixAlertStyles = css`\n :host {\n display: block;\n }\n\n :host(:not([open])) {\n display: none;\n }\n\n /* ─── Screen-reader-only announcement region ─── */\n /* Always present in DOM so AT registers it before content is injected. */\n /* Visually hidden via clip-path technique (superior to display:none which */\n /* removes the element from the AT tree entirely). */\n\n .sr-only {\n position: absolute;\n width: 1px;\n height: 1px;\n padding: 0;\n margin: -1px;\n overflow: hidden;\n clip: rect(0, 0, 0, 0);\n white-space: nowrap;\n border: 0;\n }\n\n * {\n box-sizing: border-box;\n }\n\n /* ─── Alert Container ─── */\n\n .alert {\n display: flex;\n align-items: flex-start;\n gap: var(--hx-alert-gap, var(--hx-space-3, 0.75rem));\n padding: var(--hx-alert-padding, var(--hx-space-4, 1rem));\n border: var(--hx-alert-border-width, var(--hx-border-width-thin, 1px)) solid\n var(--hx-alert-border-color, var(--hx-color-info-200, #bedcfc));\n border-radius: var(--hx-alert-border-radius, var(--hx-border-radius-md, 0.375rem));\n background-color: var(--hx-alert-bg, var(--hx-color-info-50, #eff6fe));\n color: var(--hx-alert-color, var(--hx-color-info-800, #064172));\n font-family: var(--hx-alert-font-family, var(--hx-font-family-sans, sans-serif));\n font-size: var(--hx-font-size-sm, 0.875rem);\n line-height: var(--hx-line-height-normal, 1.5);\n }\n\n /* ─── Accent Variant (left border stripe) ─── */\n /* Removes full border and replaces with a left-side accent stripe. */\n /* Common healthcare/enterprise dashboard pattern for dense information UIs. */\n\n .alert--accent {\n border-width: 0;\n border-inline-start: var(--hx-alert-accent-width, 4px) solid\n var(--hx-alert-border-color, var(--hx-color-info-200, #bedcfc));\n border-radius: 0;\n }\n\n /* ─── Severity Label (WCAG 1.4.1) ─── */\n /* Visually hidden — provides a non-color cue for screen readers and users */\n /* who cannot distinguish variants by color alone (e.g. color-blind users). */\n /* Always present regardless of showIcon so severity is never color-only. */\n\n .alert__severity-label {\n position: absolute;\n width: 1px;\n height: 1px;\n padding: 0;\n margin: -1px;\n overflow: hidden;\n clip: rect(0, 0, 0, 0);\n white-space: nowrap;\n border: 0;\n }\n\n /* ─── Icon ─── */\n\n .alert__icon {\n display: flex;\n align-items: center;\n flex-shrink: 0;\n color: var(--hx-alert-icon-color, var(--hx-color-info-500, #0c8beb));\n }\n\n .alert__icon svg {\n width: var(--hx-space-5, 1.25rem);\n height: var(--hx-space-5, 1.25rem);\n fill: currentColor;\n }\n\n /* ─── Title ─── */\n\n .alert__title {\n display: none;\n font-weight: var(--hx-font-weight-semibold, 600);\n margin-bottom: var(--hx-space-1, 0.25rem);\n }\n\n .alert__title--visible {\n display: block;\n }\n\n /* ─── Message ─── */\n\n .alert__message {\n flex: 1;\n min-width: 0;\n }\n\n /* ─── Actions ─── */\n /* Hidden by default; shown via JS slotchange detection to avoid invisible */\n /* margin-top spacing when no actions are slotted. */\n\n .alert__actions {\n display: none;\n align-items: center;\n gap: var(--hx-space-2, 0.5rem);\n margin-top: var(--hx-space-2, 0.5rem);\n }\n\n .alert__actions--visible {\n display: flex;\n }\n\n /* ─── Close Button ─── */\n /* Minimum 44px touch target per WCAG 2.5.8 (Target Size Minimum, AA) and */\n /* Apple HIG / Google Material guidelines. Uses absolute px units to ensure */\n /* the target size is independent of the consumer's base font size. */\n\n .alert__close-button {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n min-width: var(--hx-touch-target-size, 44px);\n min-height: var(--hx-touch-target-size, 44px);\n margin-inline-start: auto;\n padding: 0;\n border: none;\n border-radius: var(--hx-border-radius-sm, 0.25rem);\n background: transparent;\n color: var(--hx-alert-color, var(--hx-color-info-800, #064172));\n cursor: pointer;\n font-size: var(--hx-font-size-md, 1rem);\n line-height: 1;\n transition:\n background-color var(--hx-transition-fast, 150ms ease),\n opacity var(--hx-transition-fast, 150ms ease);\n opacity: var(--hx-opacity-75, 0.75);\n }\n\n .alert__close-button:hover {\n opacity: var(--hx-opacity-100, 1);\n /* color-mix() is supported in Chrome 111+, Firefox 113+, Safari 16.2+. */\n /* Falls back to transparent (no hover background) in older environments. */\n background-color: color-mix(in srgb, currentColor 10%, transparent);\n }\n\n .alert__close-button:focus-visible {\n outline: var(--hx-focus-ring-width, 2px) solid\n var(\n --hx-alert-close-btn-focus-ring-color,\n var(--hx-focus-ring-color, var(--hx-color-primary-400, #6ab1b1))\n );\n outline-offset: var(--hx-focus-ring-offset, 2px);\n opacity: 1;\n }\n\n .alert__close-button svg {\n width: var(--hx-space-4, 1rem);\n height: var(--hx-space-4, 1rem);\n fill: currentColor;\n }\n\n @media (prefers-reduced-motion: reduce) {\n .alert__close-button {\n transition: none;\n }\n }\n\n /* ─── Variant: info ─── */\n\n :host([variant='info']) .alert,\n :host(:not([variant])) .alert {\n --hx-alert-bg: var(--hx-color-info-50, #eff6fe);\n --hx-alert-border-color: var(--hx-color-info-200, #bedcfc);\n --hx-alert-color: var(--hx-color-info-800, #064172);\n --hx-alert-icon-color: var(--hx-color-info-500, #0c8beb);\n }\n\n /* ─── Variant: success ─── */\n\n :host([variant='success']) .alert {\n --hx-alert-bg: var(--hx-color-success-50, #eafaec);\n --hx-alert-border-color: var(--hx-color-success-200, #bae6c2);\n --hx-alert-color: var(--hx-color-success-800, #0b4d23);\n --hx-alert-icon-color: var(--hx-color-success-500, #3b9e58);\n }\n\n /* ─── Variant: warning ─── */\n\n :host([variant='warning']) .alert {\n --hx-alert-bg: var(--hx-color-warning-50, #fff3ea);\n --hx-alert-border-color: var(--hx-color-warning-200, #facfae);\n --hx-alert-color: var(--hx-color-warning-800, #603301);\n --hx-alert-icon-color: var(--hx-color-warning-500, #c2711c);\n }\n\n /* ─── Variant: error ─── */\n\n :host([variant='error']) .alert {\n --hx-alert-bg: var(--hx-color-error-50, #fff2f0);\n --hx-alert-border-color: var(--hx-color-error-200, #fccbc4);\n --hx-alert-color: var(--hx-color-error-800, #7a090a);\n --hx-alert-icon-color: var(--hx-color-error-500, #e5493e);\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 .alert {\n border-color: CanvasText;\n }\n\n .alert--accent {\n border-inline-start-color: CanvasText;\n }\n\n .alert__icon svg {\n fill: CanvasText;\n }\n\n .alert__close-button {\n color: ButtonText;\n border: 1px solid ButtonText;\n }\n }\n`;\n","import { html, nothing, type PropertyValues } from 'lit';\nimport '../../utilities/document-token-adoption.js';\nimport { customElement, property, state } from 'lit/decorators.js';\nimport { classMap } from 'lit/directives/class-map.js';\nimport { HelixElement } from '../../base/index.js';\nimport { helixAlertStyles } from './hx-alert.styles.js';\nimport { forcedColorsSurface } from '../../styles/forced-colors.js';\n\n/** Alert variant determines visual styling and ARIA semantics. */\nexport type AlertVariant = 'info' | 'success' | 'warning' | 'error';\n\n/** Detail for the hx-close event dispatched by hx-alert. */\nexport interface HxAlertCloseDetail {\n reason: string;\n}\n\n/**\n * A feedback component for communicating status messages, warnings, and errors.\n * Critical for healthcare patient safety alerts.\n *\n * @summary Feedback alert for status messages with variant-based styling and ARIA live regions.\n *\n * @tag hx-alert\n *\n * @slot - Default slot for alert message content.\n * @slot title - Optional title/headline for the alert.\n * @slot icon - Custom icon to override the default variant icon.\n * @slot actions - Action buttons rendered within the alert.\n *\n * @attr {string} heading - Text used to build the close button's contextual aria-label\n * (e.g., \"Close Low blood pressure alert\"). When absent the label falls back to \"Close alert\".\n *\n * @fires {CustomEvent<{reason: string}>} hx-close - Dispatched when the user dismisses the alert.\n * @fires {CustomEvent} hx-after-close - Dispatched after the alert is dismissed.\n *\n * @csspart alert - The outer alert container.\n * @csspart title - The title/headline container.\n * @csspart icon - The icon container.\n * @csspart message - The message content area.\n * @csspart close-button - The dismiss button (only rendered when dismissible).\n * @csspart actions - The actions container.\n *\n * @cssprop [--hx-alert-bg=var(--hx-color-info-50)] - Alert background color.\n * @cssprop [--hx-alert-color=var(--hx-color-info-800)] - Alert text color.\n * @cssprop [--hx-alert-border-color=var(--hx-color-info-200)] - Alert border color.\n * @cssprop [--hx-alert-border-radius=var(--hx-border-radius-md)] - Alert border radius.\n * @cssprop [--hx-alert-border-width=var(--hx-border-width-thin)] - Alert border width.\n * @cssprop [--hx-alert-padding=var(--hx-space-4)] - Alert padding.\n * @cssprop [--hx-alert-gap=var(--hx-space-3)] - Gap between alert elements.\n * @cssprop [--hx-alert-icon-color=var(--hx-color-info-500)] - Alert icon color.\n * @cssprop [--hx-alert-font-family=var(--hx-font-family-sans)] - Alert font family.\n * @cssprop [--hx-touch-target-size=44px] - Minimum touch target size for the close button.\n * @cssprop [--hx-alert-accent-width=4px] - Width of the left border accent stripe.\n * @cssprop [--hx-border-radius-md] - CSS custom property.\n * @cssprop [--hx-border-radius-sm] - CSS custom property.\n * @cssprop [--hx-border-width-thin] - Width.\n * @cssprop [--hx-color-error-200] - Color.\n * @cssprop [--hx-color-error-50] - Color.\n * @cssprop [--hx-color-error-500] - Color.\n * @cssprop [--hx-color-error-800] - Color.\n * @cssprop [--hx-color-info-200] - Color.\n * @cssprop [--hx-color-info-50] - Color.\n * @cssprop [--hx-color-info-500] - Color.\n * @cssprop [--hx-color-info-800] - Color.\n * @cssprop [--hx-color-primary-400] - Color.\n * @cssprop [--hx-color-success-200] - Color.\n * @cssprop [--hx-color-success-50] - Color.\n * @cssprop [--hx-color-success-500] - Color.\n * @cssprop [--hx-color-success-800] - Color.\n * @cssprop [--hx-color-warning-200] - Color.\n * @cssprop [--hx-color-warning-50] - Color.\n * @cssprop [--hx-color-warning-500] - Color.\n * @cssprop [--hx-color-warning-800] - Color.\n * @cssprop [--hx-focus-ring-color] - Color.\n * @cssprop [--hx-focus-ring-offset] - CSS custom property.\n * @cssprop [--hx-focus-ring-width] - Width.\n * @cssprop [--hx-font-family-sans] - Font family.\n * @cssprop [--hx-font-size-md] - Font size.\n * @cssprop [--hx-font-size-sm] - Font size.\n * @cssprop [--hx-font-weight-semibold] - Font weight.\n * @cssprop [--hx-line-height-normal] - Line height.\n * @cssprop [--hx-opacity-100] - Opacity.\n * @cssprop [--hx-opacity-75] - Opacity.\n * @cssprop [--hx-space-1] - Spacing token.\n * @cssprop [--hx-space-2] - Spacing token.\n * @cssprop [--hx-space-3] - Spacing token.\n * @cssprop [--hx-space-4] - Spacing token.\n * @cssprop [--hx-space-5] - Spacing token.\n * @cssprop [--hx-transition-fast] - Transition timing.\n */\n@customElement('hx-alert')\nexport class HelixAlert extends HelixElement {\n static override styles = [helixAlertStyles, forcedColorsSurface];\n\n // ─── Properties ───\n\n /**\n * Visual variant of the alert that determines colors and ARIA semantics.\n * @attr variant\n */\n @property({ type: String, reflect: true })\n variant: 'info' | 'success' | 'warning' | 'error' = 'info';\n\n /**\n * Whether the alert can be dismissed by the user.\n * @attr dismissible\n */\n @property({ type: Boolean, reflect: true })\n dismissible = false;\n\n /**\n * Optional heading text that provides context for the close button's accessible label.\n * When provided, the close button is announced as \"Close [heading] alert\".\n * When absent, the close button falls back to \"Close alert\".\n * @attr heading\n */\n @property({ type: String })\n heading = '';\n\n /**\n * Accessible label for the close button. Override for i18n.\n * @attr label-close\n */\n @property({ attribute: 'label-close' }) labelClose = 'Close alert';\n\n /**\n * Whether the alert is visible. Add the `open` attribute to show the alert.\n * @attr open\n */\n @property({ type: Boolean, reflect: true })\n open = false;\n\n /**\n * Whether to show the default variant icon. Add `show-icon` attribute to display the icon.\n * @attr show-icon\n */\n @property({ type: Boolean, reflect: true, attribute: 'show-icon' })\n showIcon = false;\n\n /**\n * When true, applies a left border accent stripe instead of a full border.\n * Common healthcare/enterprise dashboard pattern for visual distinction of alert types.\n * @attr accent\n */\n @property({ type: Boolean, reflect: true })\n accent = false;\n\n /**\n * Override for the severity prefix announced to screen readers (e.g., \"Info:\", \"Error:\").\n * When not set, defaults to the English label matching the current variant.\n * @attr severity-label\n */\n @property({ attribute: 'severity-label' })\n severityLabel: string | undefined;\n\n /**\n * CSS selector for the element to return focus to after the alert is dismissed.\n * When set, the component will find and focus the matching element after dismissal.\n * If not set, focus management is the caller's responsibility via the hx-after-close event.\n * @attr return-focus-to\n */\n @property({ type: String, attribute: 'return-focus-to' })\n returnFocusTo: string | null = null;\n\n // ─── State ───\n\n /** @internal */\n @state()\n private _hasActions = false;\n\n /** @internal */\n @state()\n private _hasTitle = false;\n\n // ─── Private Handler References ───\n\n /** @internal */\n private _actionsSlotChangeHandler: (() => void) | null = null;\n /** @internal */\n private _titleSlotChangeHandler: (() => void) | null = null;\n\n // ─── Private Helpers ───\n\n /** @internal */\n private _defaultSeverityLabel(): string {\n const labels: Record<string, string> = {\n info: 'Info:',\n success: 'Success:',\n warning: 'Warning:',\n error: 'Error:',\n };\n return labels[this.variant] ?? '';\n }\n\n /** @internal */\n private get _effectiveSeverityLabel(): string {\n return this.severityLabel ?? this._defaultSeverityLabel();\n }\n\n /** Returns true when the variant requires assertive announcement. */\n /** @internal */\n private get _isAssertive(): boolean {\n return this.variant === 'error';\n }\n\n /**\n * Returns the appropriate ARIA role based on variant.\n * role=\"alert\" implies aria-live=\"assertive\"; role=\"status\" implies aria-live=\"polite\".\n * We do NOT set aria-live explicitly to avoid double-announcements in JAWS.\n */\n /** @internal */\n private get _role(): string {\n return this._isAssertive ? 'alert' : 'status';\n }\n\n // ─── Lifecycle ───\n\n override connectedCallback(): void {\n super.connectedCallback();\n // Apply ARIA role to the host element for reliable screen reader support across\n // Shadow DOM boundaries. Placing role on a shadow-internal element has inconsistent\n // AT support in JAWS+Chrome and VoiceOver+Safari combinations (particularly pre-2024).\n this.setAttribute('role', this._role);\n if (!this.open) {\n this.setAttribute('aria-hidden', 'true');\n }\n }\n\n override disconnectedCallback(): void {\n super.disconnectedCallback();\n const actionsSlot = this.renderRoot.querySelector<HTMLSlotElement>('slot[name=\"actions\"]');\n if (actionsSlot && this._actionsSlotChangeHandler) {\n actionsSlot.removeEventListener('slotchange', this._actionsSlotChangeHandler);\n }\n const titleSlot = this.renderRoot.querySelector<HTMLSlotElement>('slot[name=\"title\"]');\n if (titleSlot && this._titleSlotChangeHandler) {\n titleSlot.removeEventListener('slotchange', this._titleSlotChangeHandler);\n }\n }\n\n override firstUpdated(): void {\n // Track actions slot content to avoid invisible spacing when no actions are slotted.\n const actionsSlot = this.renderRoot.querySelector<HTMLSlotElement>('slot[name=\"actions\"]');\n if (actionsSlot) {\n this._actionsSlotChangeHandler = () => {\n this._hasActions = actionsSlot.assignedNodes({ flatten: true }).length > 0;\n };\n actionsSlot.addEventListener('slotchange', this._actionsSlotChangeHandler);\n }\n\n // Track title slot content so the title container doesn't create dead space when empty.\n const titleSlot = this.renderRoot.querySelector<HTMLSlotElement>('slot[name=\"title\"]');\n if (titleSlot) {\n this._titleSlotChangeHandler = () => {\n this._hasTitle = titleSlot.assignedNodes({ flatten: true }).length > 0;\n };\n titleSlot.addEventListener('slotchange', this._titleSlotChangeHandler);\n }\n }\n\n protected override updated(changedProperties: PropertyValues<this>): void {\n super.updated(changedProperties);\n if (changedProperties.has('variant')) {\n // Keep host ARIA role in sync with variant (assertive vs. polite).\n this.setAttribute('role', this._role);\n }\n if (changedProperties.has('open')) {\n // Manage aria-hidden in addition to display:none for reliable AT exclusion.\n // When open transitions from false→true, removing aria-hidden signals to AT\n // that the live region content should be announced.\n if (this.open) {\n this.removeAttribute('aria-hidden');\n // Trigger announcement via the sr-only polite live region for ATs (JAWS+Chrome,\n // NVDA) that do not re-announce existing content when aria-hidden is merely removed.\n // We inject text after a microtask so the DOM has settled and the live region\n // is registered by the AT before content arrives.\n const previousOpen = changedProperties.get('open');\n if (previousOpen === false) {\n Promise.resolve().then(() => {\n const announcer = this.renderRoot.querySelector<HTMLElement>('.sr-only');\n if (announcer) {\n announcer.textContent = '';\n // Second microtask ensures the clear is processed before re-injection,\n // guaranteeing the AT sees a content change rather than no-op.\n Promise.resolve().then(() => {\n const prefix = this._effectiveSeverityLabel;\n const message = this.textContent?.trim() ?? '';\n announcer.textContent = prefix ? `${prefix} ${message}` : message;\n });\n }\n });\n }\n } else {\n this.setAttribute('aria-hidden', 'true');\n // Clear the announcer when hidden so stale text is not re-read on next open.\n const announcer = this.renderRoot.querySelector<HTMLElement>('.sr-only');\n if (announcer) {\n announcer.textContent = '';\n }\n }\n }\n }\n\n // ─── Default Icons ───\n\n /** @internal */\n private _renderInfoIcon() {\n return html`<svg viewBox=\"0 0 20 20\" aria-hidden=\"true\">\n <path\n d=\"M10 2a8 8 0 100 16 8 8 0 000-16zm.75 4.75a.75.75 0 11-1.5 0 .75.75 0 011.5 0zM9.25 9a.75.75 0 011.5 0v4a.75.75 0 01-1.5 0V9z\"\n />\n </svg>`;\n }\n\n /** @internal */\n private _renderSuccessIcon() {\n return html`<svg viewBox=\"0 0 20 20\" aria-hidden=\"true\">\n <path\n d=\"M10 2a8 8 0 100 16 8 8 0 000-16zm3.03 6.28a.75.75 0 00-1.06-1.06L9 10.19 7.78 8.97a.75.75 0 00-1.06 1.06l1.75 1.75a.75.75 0 001.06 0l3.5-3.5z\"\n />\n </svg>`;\n }\n\n /** @internal */\n private _renderWarningIcon() {\n return html`<svg viewBox=\"0 0 20 20\" aria-hidden=\"true\">\n <path\n d=\"M8.49 2.92a1.75 1.75 0 013.02 0l6.25 10.83A1.75 1.75 0 0116.25 16H3.75a1.75 1.75 0 01-1.51-2.25L8.49 2.92zM10 7a.75.75 0 01.75.75v3a.75.75 0 01-1.5 0v-3A.75.75 0 0110 7zm0 7.5a.75.75 0 100-1.5.75.75 0 000 1.5z\"\n />\n </svg>`;\n }\n\n /** @internal */\n private _renderErrorIcon() {\n return html`<svg viewBox=\"0 0 20 20\" aria-hidden=\"true\">\n <path\n d=\"M10 2a8 8 0 100 16 8 8 0 000-16zm-1.72 5.22a.75.75 0 011.06 0L10 7.94l.66-.72a.75.75 0 111.06 1.06L11.06 9l.66.72a.75.75 0 11-1.06 1.06L10 10.06l-.66.72a.75.75 0 01-1.06-1.06L8.94 9l-.66-.72a.75.75 0 010-1.06z\"\n />\n </svg>`;\n }\n\n /** @internal */\n private _renderDefaultIcon() {\n switch (this.variant) {\n case 'success':\n return this._renderSuccessIcon();\n case 'warning':\n return this._renderWarningIcon();\n case 'error':\n return this._renderErrorIcon();\n case 'info':\n default:\n return this._renderInfoIcon();\n }\n }\n\n /** @internal */\n private _renderCloseIcon() {\n return html`<svg viewBox=\"0 0 20 20\" aria-hidden=\"true\">\n <path\n d=\"M6.28 5.22a.75.75 0 00-1.06 1.06L8.94 10l-3.72 3.72a.75.75 0 101.06 1.06L10 11.06l3.72 3.72a.75.75 0 101.06-1.06L11.06 10l3.72-3.72a.75.75 0 00-1.06-1.06L10 8.94 6.28 5.22z\"\n />\n </svg>`;\n }\n\n // ─── Event Handling ───\n\n /** @internal */\n private _handleDismiss(): void {\n this.open = false;\n\n /**\n * Dispatched when the user dismisses the alert.\n * @event hx-close\n */\n this.dispatchEvent(\n new CustomEvent<{ reason: string }>('hx-close', {\n bubbles: true,\n composed: true,\n detail: { reason: 'user' },\n }),\n );\n\n /**\n * Dispatched after the alert is dismissed.\n * @event hx-after-close\n */\n this.dispatchEvent(\n new CustomEvent<void>('hx-after-close', {\n bubbles: true,\n composed: true,\n }),\n );\n\n // Return focus to a designated element if specified via returnFocusTo.\n if (this.returnFocusTo) {\n const target = document.querySelector(this.returnFocusTo);\n if (target instanceof HTMLElement) {\n target.focus();\n }\n }\n }\n\n // ─── Render ───\n\n override render() {\n const classes = {\n alert: true,\n [`alert--${this.variant}`]: true,\n 'alert--accent': this.accent,\n };\n\n // WCAG 1.4.1: Always render a visually-hidden severity label so the variant\n // is never conveyed by color alone, regardless of whether showIcon is set.\n const severityLabel = this._effectiveSeverityLabel;\n\n return html`\n <div\n class=\"sr-only\"\n aria-live=${this._isAssertive ? 'assertive' : 'polite'}\n aria-atomic=\"true\"\n ></div>\n <div part=\"alert\" class=${classMap(classes)}>\n <span class=\"alert__severity-label\">${severityLabel}</span>\n ${this.showIcon\n ? html`\n <div part=\"icon\" class=\"alert__icon\">\n <slot name=\"icon\">${this._renderDefaultIcon()}</slot>\n </div>\n `\n : nothing}\n\n <div part=\"message\" class=\"alert__message\">\n <div part=\"title\" class=\"alert__title ${this._hasTitle ? 'alert__title--visible' : ''}\">\n <slot name=\"title\"></slot>\n </div>\n <slot></slot>\n <div\n part=\"actions\"\n class=\"alert__actions ${this._hasActions ? 'alert__actions--visible' : ''}\"\n >\n <slot name=\"actions\"></slot>\n </div>\n </div>\n\n ${this.dismissible\n ? html`\n <button\n part=\"close-button\"\n class=\"alert__close-button\"\n aria-label=${this.labelClose}\n @click=${this._handleDismiss}\n >\n ${this._renderCloseIcon()}\n </button>\n `\n : nothing}\n </div>\n `;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'hx-alert': HelixAlert;\n }\n}\n\nexport type { HelixAlert as HxAlert };\n"],"names":["helixAlertStyles","css","HelixAlert","HelixElement","actionsSlot","titleSlot","changedProperties","announcer","prefix","message","_a","html","target","classes","severityLabel","classMap","nothing","forcedColorsSurface","__decorateClass","property","state","customElement"],"mappings":";;;;;AAcO,MAAMA,IAAmBC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA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"}
1
+ {"version":3,"file":"hx-alert-C597yHpD.js","sources":["../../src/components/hx-alert/hx-alert.styles.ts","../../src/components/hx-alert/hx-alert.ts"],"sourcesContent":["import { css } from 'lit';\n\n/**\n * hx-alert styles.\n *\n * Component-tier tokens with two-level var() fallback:\n * var(--hx-alert-{prop}, var(--hx-color-{semantic}, #hex))\n * Inner hex fallbacks track the \"precision cool\" palette (3.2.0):\n * info-50 = #EFF6FE, info-200 = #BEDCFC, info-500 = #0C8BEB, info-800 = #064172,\n * success-50 = #EAFAEC, success-200 = #BAE6C2, success-500 = #3B9E58, success-800 = #0B4D23,\n * warning-50 = #FFF3EA, warning-200 = #FACFAE, warning-500 = #C2711C, warning-800 = #603301,\n * error-50 = #FFF2F0, error-200 = #FCCBC4, error-500 = #E5493E, error-800 = #7A090A,\n * primary-400 = #6AB1B1.\n */\nexport const helixAlertStyles = css`\n :host {\n display: block;\n }\n\n :host(:not([open])) {\n display: none;\n }\n\n /* ─── Screen-reader-only announcement region ─── */\n /* Always present in DOM so AT registers it before content is injected. */\n /* Visually hidden via clip-path technique (superior to display:none which */\n /* removes the element from the AT tree entirely). */\n\n .sr-only {\n position: absolute;\n width: 1px;\n height: 1px;\n padding: 0;\n margin: -1px;\n overflow: hidden;\n clip: rect(0, 0, 0, 0);\n white-space: nowrap;\n border: 0;\n }\n\n * {\n box-sizing: border-box;\n }\n\n /* ─── Alert Container ─── */\n\n .alert {\n display: flex;\n align-items: flex-start;\n gap: var(--hx-alert-gap, var(--hx-space-3, 0.75rem));\n padding: var(--hx-alert-padding, var(--hx-space-4, 1rem));\n border: var(--hx-alert-border-width, var(--hx-border-width-thin, 1px)) solid\n var(--hx-alert-border-color, var(--hx-color-info-200, #bedcfc));\n border-radius: var(--hx-alert-border-radius, var(--hx-border-radius-md, 0.375rem));\n background-color: var(--hx-alert-bg, var(--hx-color-info-50, #eff6fe));\n color: var(--hx-alert-color, var(--hx-color-info-800, #064172));\n font-family: var(--hx-alert-font-family, var(--hx-font-family-sans, sans-serif));\n font-size: var(--hx-font-size-sm, 0.875rem);\n line-height: var(--hx-line-height-normal, 1.5);\n }\n\n /* ─── Accent Variant (left border stripe) ─── */\n /* Removes full border and replaces with a left-side accent stripe. */\n /* Common healthcare/enterprise dashboard pattern for dense information UIs. */\n\n .alert--accent {\n border-width: 0;\n border-inline-start: var(--hx-alert-accent-width, 4px) solid\n var(--hx-alert-border-color, var(--hx-color-info-200, #bedcfc));\n border-radius: 0;\n }\n\n /* ─── Severity Label (WCAG 1.4.1) ─── */\n /* Visually hidden — provides a non-color cue for screen readers and users */\n /* who cannot distinguish variants by color alone (e.g. color-blind users). */\n /* Always present regardless of showIcon so severity is never color-only. */\n\n .alert__severity-label {\n position: absolute;\n width: 1px;\n height: 1px;\n padding: 0;\n margin: -1px;\n overflow: hidden;\n clip: rect(0, 0, 0, 0);\n white-space: nowrap;\n border: 0;\n }\n\n /* ─── Icon ─── */\n\n .alert__icon {\n display: flex;\n align-items: center;\n flex-shrink: 0;\n color: var(--hx-alert-icon-color, var(--hx-color-info-500, #0c8beb));\n }\n\n .alert__icon svg {\n width: var(--hx-space-5, 1.25rem);\n height: var(--hx-space-5, 1.25rem);\n fill: currentColor;\n }\n\n /* ─── Title ─── */\n\n .alert__title {\n display: none;\n font-weight: var(--hx-font-weight-semibold, 600);\n margin-bottom: var(--hx-space-1, 0.25rem);\n }\n\n .alert__title--visible {\n display: block;\n }\n\n /* ─── Message ─── */\n\n .alert__message {\n flex: 1;\n min-width: 0;\n }\n\n /* ─── Actions ─── */\n /* Hidden by default; shown via JS slotchange detection to avoid invisible */\n /* margin-top spacing when no actions are slotted. */\n\n .alert__actions {\n display: none;\n align-items: center;\n gap: var(--hx-space-2, 0.5rem);\n margin-top: var(--hx-space-2, 0.5rem);\n }\n\n .alert__actions--visible {\n display: flex;\n }\n\n /* ─── Close Button ─── */\n /* Minimum 44px touch target per WCAG 2.5.8 (Target Size Minimum, AA) and */\n /* Apple HIG / Google Material guidelines. Uses absolute px units to ensure */\n /* the target size is independent of the consumer's base font size. */\n\n .alert__close-button {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n min-width: var(--hx-touch-target-size, 44px);\n min-height: var(--hx-touch-target-size, 44px);\n margin-inline-start: auto;\n padding: 0;\n border: none;\n border-radius: var(--hx-border-radius-sm, 0.25rem);\n background: transparent;\n color: var(--hx-alert-color, var(--hx-color-info-800, #064172));\n cursor: pointer;\n font-size: var(--hx-font-size-md, 1rem);\n line-height: 1;\n transition:\n background-color var(--hx-transition-fast, 150ms ease),\n opacity var(--hx-transition-fast, 150ms ease);\n opacity: var(--hx-opacity-75, 0.75);\n }\n\n .alert__close-button:hover {\n opacity: var(--hx-opacity-100, 1);\n /* color-mix() is supported in Chrome 111+, Firefox 113+, Safari 16.2+. */\n /* Falls back to transparent (no hover background) in older environments. */\n background-color: color-mix(in srgb, currentColor 10%, transparent);\n }\n\n .alert__close-button:focus-visible {\n outline: var(--hx-focus-ring-width, 2px) solid\n var(\n --hx-alert-close-btn-focus-ring-color,\n var(--hx-focus-ring-color, var(--hx-color-primary-600, #0f7078))\n );\n outline-offset: var(--hx-focus-ring-offset, 2px);\n opacity: 1;\n }\n\n .alert__close-button svg {\n width: var(--hx-space-4, 1rem);\n height: var(--hx-space-4, 1rem);\n fill: currentColor;\n }\n\n @media (prefers-reduced-motion: reduce) {\n .alert__close-button {\n transition: none;\n }\n }\n\n /* ─── Variant: info ─── */\n\n :host([variant='info']) .alert,\n :host(:not([variant])) .alert {\n --hx-alert-bg: var(--hx-color-info-50, #eff6fe);\n --hx-alert-border-color: var(--hx-color-info-200, #bedcfc);\n --hx-alert-color: var(--hx-color-info-800, #064172);\n --hx-alert-icon-color: var(--hx-color-info-500, #0c8beb);\n }\n\n /* ─── Variant: success ─── */\n\n :host([variant='success']) .alert {\n --hx-alert-bg: var(--hx-color-success-50, #eafaec);\n --hx-alert-border-color: var(--hx-color-success-200, #bae6c2);\n --hx-alert-color: var(--hx-color-success-800, #0b4d23);\n --hx-alert-icon-color: var(--hx-color-success-500, #3b9e58);\n }\n\n /* ─── Variant: warning ─── */\n\n :host([variant='warning']) .alert {\n --hx-alert-bg: var(--hx-color-warning-50, #fff3ea);\n --hx-alert-border-color: var(--hx-color-warning-200, #facfae);\n --hx-alert-color: var(--hx-color-warning-800, #603301);\n --hx-alert-icon-color: var(--hx-color-warning-500, #c2711c);\n }\n\n /* ─── Variant: error ─── */\n\n :host([variant='error']) .alert {\n --hx-alert-bg: var(--hx-color-error-50, #fff2f0);\n --hx-alert-border-color: var(--hx-color-error-200, #fccbc4);\n --hx-alert-color: var(--hx-color-error-800, #7a090a);\n --hx-alert-icon-color: var(--hx-color-error-500, #e5493e);\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 .alert {\n border-color: CanvasText;\n }\n\n .alert--accent {\n border-inline-start-color: CanvasText;\n }\n\n .alert__icon svg {\n fill: CanvasText;\n }\n\n .alert__close-button {\n color: ButtonText;\n border: 1px solid ButtonText;\n }\n }\n`;\n","import { html, nothing, type PropertyValues } from 'lit';\nimport '../../utilities/document-token-adoption.js';\nimport { customElement, property, state } from 'lit/decorators.js';\nimport { classMap } from 'lit/directives/class-map.js';\nimport { HelixElement } from '../../base/index.js';\nimport { helixAlertStyles } from './hx-alert.styles.js';\nimport { forcedColorsSurface } from '../../styles/forced-colors.js';\n\n/** Alert variant determines visual styling and ARIA semantics. */\nexport type AlertVariant = 'info' | 'success' | 'warning' | 'error';\n\n/** Detail for the hx-close event dispatched by hx-alert. */\nexport interface HxAlertCloseDetail {\n reason: string;\n}\n\n/**\n * A feedback component for communicating status messages, warnings, and errors.\n * Critical for healthcare patient safety alerts.\n *\n * @summary Feedback alert for status messages with variant-based styling and ARIA live regions.\n *\n * @tag hx-alert\n *\n * @slot - Default slot for alert message content.\n * @slot title - Optional title/headline for the alert.\n * @slot icon - Custom icon to override the default variant icon.\n * @slot actions - Action buttons rendered within the alert.\n *\n * @attr {string} heading - Text used to build the close button's contextual aria-label\n * (e.g., \"Close Low blood pressure alert\"). When absent the label falls back to \"Close alert\".\n *\n * @fires {CustomEvent<{reason: string}>} hx-close - Dispatched when the user dismisses the alert.\n * @fires {CustomEvent} hx-after-close - Dispatched after the alert is dismissed.\n *\n * @csspart alert - The outer alert container.\n * @csspart title - The title/headline container.\n * @csspart icon - The icon container.\n * @csspart message - The message content area.\n * @csspart close-button - The dismiss button (only rendered when dismissible).\n * @csspart actions - The actions container.\n *\n * @cssprop [--hx-alert-bg=var(--hx-color-info-50)] - Alert background color.\n * @cssprop [--hx-alert-color=var(--hx-color-info-800)] - Alert text color.\n * @cssprop [--hx-alert-border-color=var(--hx-color-info-200)] - Alert border color.\n * @cssprop [--hx-alert-border-radius=var(--hx-border-radius-md)] - Alert border radius.\n * @cssprop [--hx-alert-border-width=var(--hx-border-width-thin)] - Alert border width.\n * @cssprop [--hx-alert-padding=var(--hx-space-4)] - Alert padding.\n * @cssprop [--hx-alert-gap=var(--hx-space-3)] - Gap between alert elements.\n * @cssprop [--hx-alert-icon-color=var(--hx-color-info-500)] - Alert icon color.\n * @cssprop [--hx-alert-font-family=var(--hx-font-family-sans)] - Alert font family.\n * @cssprop [--hx-touch-target-size=44px] - Minimum touch target size for the close button.\n * @cssprop [--hx-alert-accent-width=4px] - Width of the left border accent stripe.\n * @cssprop [--hx-border-radius-md] - CSS custom property.\n * @cssprop [--hx-border-radius-sm] - CSS custom property.\n * @cssprop [--hx-border-width-thin] - Width.\n * @cssprop [--hx-color-error-200] - Color.\n * @cssprop [--hx-color-error-50] - Color.\n * @cssprop [--hx-color-error-500] - Color.\n * @cssprop [--hx-color-error-800] - Color.\n * @cssprop [--hx-color-info-200] - Color.\n * @cssprop [--hx-color-info-50] - Color.\n * @cssprop [--hx-color-info-500] - Color.\n * @cssprop [--hx-color-info-800] - Color.\n * @cssprop [--hx-color-primary-400] - Color.\n * @cssprop [--hx-color-success-200] - Color.\n * @cssprop [--hx-color-success-50] - Color.\n * @cssprop [--hx-color-success-500] - Color.\n * @cssprop [--hx-color-success-800] - Color.\n * @cssprop [--hx-color-warning-200] - Color.\n * @cssprop [--hx-color-warning-50] - Color.\n * @cssprop [--hx-color-warning-500] - Color.\n * @cssprop [--hx-color-warning-800] - Color.\n * @cssprop [--hx-focus-ring-color] - Color.\n * @cssprop [--hx-focus-ring-offset] - CSS custom property.\n * @cssprop [--hx-focus-ring-width] - Width.\n * @cssprop [--hx-font-family-sans] - Font family.\n * @cssprop [--hx-font-size-md] - Font size.\n * @cssprop [--hx-font-size-sm] - Font size.\n * @cssprop [--hx-font-weight-semibold] - Font weight.\n * @cssprop [--hx-line-height-normal] - Line height.\n * @cssprop [--hx-opacity-100] - Opacity.\n * @cssprop [--hx-opacity-75] - Opacity.\n * @cssprop [--hx-space-1] - Spacing token.\n * @cssprop [--hx-space-2] - Spacing token.\n * @cssprop [--hx-space-3] - Spacing token.\n * @cssprop [--hx-space-4] - Spacing token.\n * @cssprop [--hx-space-5] - Spacing token.\n * @cssprop [--hx-transition-fast] - Transition timing.\n */\n@customElement('hx-alert')\nexport class HelixAlert extends HelixElement {\n static override styles = [helixAlertStyles, forcedColorsSurface];\n\n // ─── Properties ───\n\n /**\n * Visual variant of the alert that determines colors and ARIA semantics.\n * @attr variant\n */\n @property({ type: String, reflect: true })\n variant: 'info' | 'success' | 'warning' | 'error' = 'info';\n\n /**\n * Whether the alert can be dismissed by the user.\n * @attr dismissible\n */\n @property({ type: Boolean, reflect: true })\n dismissible = false;\n\n /**\n * Optional heading text that provides context for the close button's accessible label.\n * When provided, the close button is announced as \"Close [heading] alert\".\n * When absent, the close button falls back to \"Close alert\".\n * @attr heading\n */\n @property({ type: String })\n heading = '';\n\n /**\n * Accessible label for the close button. Override for i18n.\n * @attr label-close\n */\n @property({ attribute: 'label-close' }) labelClose = 'Close alert';\n\n /**\n * Whether the alert is visible. Add the `open` attribute to show the alert.\n * @attr open\n */\n @property({ type: Boolean, reflect: true })\n open = false;\n\n /**\n * Whether to show the default variant icon. Add `show-icon` attribute to display the icon.\n * @attr show-icon\n */\n @property({ type: Boolean, reflect: true, attribute: 'show-icon' })\n showIcon = false;\n\n /**\n * When true, applies a left border accent stripe instead of a full border.\n * Common healthcare/enterprise dashboard pattern for visual distinction of alert types.\n * @attr accent\n */\n @property({ type: Boolean, reflect: true })\n accent = false;\n\n /**\n * Override for the severity prefix announced to screen readers (e.g., \"Info:\", \"Error:\").\n * When not set, defaults to the English label matching the current variant.\n * @attr severity-label\n */\n @property({ attribute: 'severity-label' })\n severityLabel: string | undefined;\n\n /**\n * CSS selector for the element to return focus to after the alert is dismissed.\n * When set, the component will find and focus the matching element after dismissal.\n * If not set, focus management is the caller's responsibility via the hx-after-close event.\n * @attr return-focus-to\n */\n @property({ type: String, attribute: 'return-focus-to' })\n returnFocusTo: string | null = null;\n\n // ─── State ───\n\n /** @internal */\n @state()\n private _hasActions = false;\n\n /** @internal */\n @state()\n private _hasTitle = false;\n\n // ─── Private Handler References ───\n\n /** @internal */\n private _actionsSlotChangeHandler: (() => void) | null = null;\n /** @internal */\n private _titleSlotChangeHandler: (() => void) | null = null;\n\n // ─── Private Helpers ───\n\n /** @internal */\n private _defaultSeverityLabel(): string {\n const labels: Record<string, string> = {\n info: 'Info:',\n success: 'Success:',\n warning: 'Warning:',\n error: 'Error:',\n };\n return labels[this.variant] ?? '';\n }\n\n /** @internal */\n private get _effectiveSeverityLabel(): string {\n return this.severityLabel ?? this._defaultSeverityLabel();\n }\n\n /** Returns true when the variant requires assertive announcement. */\n /** @internal */\n private get _isAssertive(): boolean {\n return this.variant === 'error';\n }\n\n /**\n * Returns the appropriate ARIA role based on variant.\n * role=\"alert\" implies aria-live=\"assertive\"; role=\"status\" implies aria-live=\"polite\".\n * We do NOT set aria-live explicitly to avoid double-announcements in JAWS.\n */\n /** @internal */\n private get _role(): string {\n return this._isAssertive ? 'alert' : 'status';\n }\n\n // ─── Lifecycle ───\n\n override connectedCallback(): void {\n super.connectedCallback();\n // Apply ARIA role to the host element for reliable screen reader support across\n // Shadow DOM boundaries. Placing role on a shadow-internal element has inconsistent\n // AT support in JAWS+Chrome and VoiceOver+Safari combinations (particularly pre-2024).\n this.setAttribute('role', this._role);\n if (!this.open) {\n this.setAttribute('aria-hidden', 'true');\n }\n }\n\n override disconnectedCallback(): void {\n super.disconnectedCallback();\n const actionsSlot = this.renderRoot.querySelector<HTMLSlotElement>('slot[name=\"actions\"]');\n if (actionsSlot && this._actionsSlotChangeHandler) {\n actionsSlot.removeEventListener('slotchange', this._actionsSlotChangeHandler);\n }\n const titleSlot = this.renderRoot.querySelector<HTMLSlotElement>('slot[name=\"title\"]');\n if (titleSlot && this._titleSlotChangeHandler) {\n titleSlot.removeEventListener('slotchange', this._titleSlotChangeHandler);\n }\n }\n\n override firstUpdated(): void {\n // Track actions slot content to avoid invisible spacing when no actions are slotted.\n const actionsSlot = this.renderRoot.querySelector<HTMLSlotElement>('slot[name=\"actions\"]');\n if (actionsSlot) {\n this._actionsSlotChangeHandler = () => {\n this._hasActions = actionsSlot.assignedNodes({ flatten: true }).length > 0;\n };\n actionsSlot.addEventListener('slotchange', this._actionsSlotChangeHandler);\n }\n\n // Track title slot content so the title container doesn't create dead space when empty.\n const titleSlot = this.renderRoot.querySelector<HTMLSlotElement>('slot[name=\"title\"]');\n if (titleSlot) {\n this._titleSlotChangeHandler = () => {\n this._hasTitle = titleSlot.assignedNodes({ flatten: true }).length > 0;\n };\n titleSlot.addEventListener('slotchange', this._titleSlotChangeHandler);\n }\n }\n\n protected override updated(changedProperties: PropertyValues<this>): void {\n super.updated(changedProperties);\n if (changedProperties.has('variant')) {\n // Keep host ARIA role in sync with variant (assertive vs. polite).\n this.setAttribute('role', this._role);\n }\n if (changedProperties.has('open')) {\n // Manage aria-hidden in addition to display:none for reliable AT exclusion.\n // When open transitions from false→true, removing aria-hidden signals to AT\n // that the live region content should be announced.\n if (this.open) {\n this.removeAttribute('aria-hidden');\n // Trigger announcement via the sr-only polite live region for ATs (JAWS+Chrome,\n // NVDA) that do not re-announce existing content when aria-hidden is merely removed.\n // We inject text after a microtask so the DOM has settled and the live region\n // is registered by the AT before content arrives.\n const previousOpen = changedProperties.get('open');\n if (previousOpen === false) {\n Promise.resolve().then(() => {\n const announcer = this.renderRoot.querySelector<HTMLElement>('.sr-only');\n if (announcer) {\n announcer.textContent = '';\n // Second microtask ensures the clear is processed before re-injection,\n // guaranteeing the AT sees a content change rather than no-op.\n Promise.resolve().then(() => {\n const prefix = this._effectiveSeverityLabel;\n const message = this.textContent?.trim() ?? '';\n announcer.textContent = prefix ? `${prefix} ${message}` : message;\n });\n }\n });\n }\n } else {\n this.setAttribute('aria-hidden', 'true');\n // Clear the announcer when hidden so stale text is not re-read on next open.\n const announcer = this.renderRoot.querySelector<HTMLElement>('.sr-only');\n if (announcer) {\n announcer.textContent = '';\n }\n }\n }\n }\n\n // ─── Default Icons ───\n\n /** @internal */\n private _renderInfoIcon() {\n return html`<svg viewBox=\"0 0 20 20\" aria-hidden=\"true\">\n <path\n d=\"M10 2a8 8 0 100 16 8 8 0 000-16zm.75 4.75a.75.75 0 11-1.5 0 .75.75 0 011.5 0zM9.25 9a.75.75 0 011.5 0v4a.75.75 0 01-1.5 0V9z\"\n />\n </svg>`;\n }\n\n /** @internal */\n private _renderSuccessIcon() {\n return html`<svg viewBox=\"0 0 20 20\" aria-hidden=\"true\">\n <path\n d=\"M10 2a8 8 0 100 16 8 8 0 000-16zm3.03 6.28a.75.75 0 00-1.06-1.06L9 10.19 7.78 8.97a.75.75 0 00-1.06 1.06l1.75 1.75a.75.75 0 001.06 0l3.5-3.5z\"\n />\n </svg>`;\n }\n\n /** @internal */\n private _renderWarningIcon() {\n return html`<svg viewBox=\"0 0 20 20\" aria-hidden=\"true\">\n <path\n d=\"M8.49 2.92a1.75 1.75 0 013.02 0l6.25 10.83A1.75 1.75 0 0116.25 16H3.75a1.75 1.75 0 01-1.51-2.25L8.49 2.92zM10 7a.75.75 0 01.75.75v3a.75.75 0 01-1.5 0v-3A.75.75 0 0110 7zm0 7.5a.75.75 0 100-1.5.75.75 0 000 1.5z\"\n />\n </svg>`;\n }\n\n /** @internal */\n private _renderErrorIcon() {\n return html`<svg viewBox=\"0 0 20 20\" aria-hidden=\"true\">\n <path\n d=\"M10 2a8 8 0 100 16 8 8 0 000-16zm-1.72 5.22a.75.75 0 011.06 0L10 7.94l.66-.72a.75.75 0 111.06 1.06L11.06 9l.66.72a.75.75 0 11-1.06 1.06L10 10.06l-.66.72a.75.75 0 01-1.06-1.06L8.94 9l-.66-.72a.75.75 0 010-1.06z\"\n />\n </svg>`;\n }\n\n /** @internal */\n private _renderDefaultIcon() {\n switch (this.variant) {\n case 'success':\n return this._renderSuccessIcon();\n case 'warning':\n return this._renderWarningIcon();\n case 'error':\n return this._renderErrorIcon();\n case 'info':\n default:\n return this._renderInfoIcon();\n }\n }\n\n /** @internal */\n private _renderCloseIcon() {\n return html`<svg viewBox=\"0 0 20 20\" aria-hidden=\"true\">\n <path\n d=\"M6.28 5.22a.75.75 0 00-1.06 1.06L8.94 10l-3.72 3.72a.75.75 0 101.06 1.06L10 11.06l3.72 3.72a.75.75 0 101.06-1.06L11.06 10l3.72-3.72a.75.75 0 00-1.06-1.06L10 8.94 6.28 5.22z\"\n />\n </svg>`;\n }\n\n // ─── Event Handling ───\n\n /** @internal */\n private _handleDismiss(): void {\n this.open = false;\n\n /**\n * Dispatched when the user dismisses the alert.\n * @event hx-close\n */\n this.dispatchEvent(\n new CustomEvent<{ reason: string }>('hx-close', {\n bubbles: true,\n composed: true,\n detail: { reason: 'user' },\n }),\n );\n\n /**\n * Dispatched after the alert is dismissed.\n * @event hx-after-close\n */\n this.dispatchEvent(\n new CustomEvent<void>('hx-after-close', {\n bubbles: true,\n composed: true,\n }),\n );\n\n // Return focus to a designated element if specified via returnFocusTo.\n if (this.returnFocusTo) {\n const target = document.querySelector(this.returnFocusTo);\n if (target instanceof HTMLElement) {\n target.focus();\n }\n }\n }\n\n // ─── Render ───\n\n override render() {\n const classes = {\n alert: true,\n [`alert--${this.variant}`]: true,\n 'alert--accent': this.accent,\n };\n\n // WCAG 1.4.1: Always render a visually-hidden severity label so the variant\n // is never conveyed by color alone, regardless of whether showIcon is set.\n const severityLabel = this._effectiveSeverityLabel;\n\n return html`\n <div\n class=\"sr-only\"\n aria-live=${this._isAssertive ? 'assertive' : 'polite'}\n aria-atomic=\"true\"\n ></div>\n <div part=\"alert\" class=${classMap(classes)}>\n <span class=\"alert__severity-label\">${severityLabel}</span>\n ${this.showIcon\n ? html`\n <div part=\"icon\" class=\"alert__icon\">\n <slot name=\"icon\">${this._renderDefaultIcon()}</slot>\n </div>\n `\n : nothing}\n\n <div part=\"message\" class=\"alert__message\">\n <div part=\"title\" class=\"alert__title ${this._hasTitle ? 'alert__title--visible' : ''}\">\n <slot name=\"title\"></slot>\n </div>\n <slot></slot>\n <div\n part=\"actions\"\n class=\"alert__actions ${this._hasActions ? 'alert__actions--visible' : ''}\"\n >\n <slot name=\"actions\"></slot>\n </div>\n </div>\n\n ${this.dismissible\n ? html`\n <button\n part=\"close-button\"\n class=\"alert__close-button\"\n aria-label=${this.labelClose}\n @click=${this._handleDismiss}\n >\n ${this._renderCloseIcon()}\n </button>\n `\n : nothing}\n </div>\n `;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'hx-alert': HelixAlert;\n }\n}\n\nexport type { HelixAlert as HxAlert };\n"],"names":["helixAlertStyles","css","HelixAlert","HelixElement","actionsSlot","titleSlot","changedProperties","announcer","prefix","message","_a","html","target","classes","severityLabel","classMap","nothing","forcedColorsSurface","__decorateClass","property","state","customElement"],"mappings":";;;;;AAcO,MAAMA,IAAmBC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA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"}
@@ -104,7 +104,7 @@ const g = d`
104
104
  outline: var(--hx-focus-ring-width, 2px) solid
105
105
  var(
106
106
  --hx-banner-action-focus-ring-color,
107
- var(--hx-focus-ring-color, var(--hx-color-primary-400, #6ab1b1))
107
+ var(--hx-focus-ring-color, var(--hx-color-primary-600, #0f7078))
108
108
  );
109
109
  outline-offset: var(--hx-focus-ring-offset, 2px);
110
110
  border-radius: var(--hx-border-radius-sm, 0.25rem);
@@ -148,7 +148,7 @@ const g = d`
148
148
  outline: var(--hx-focus-ring-width, 2px) solid
149
149
  var(
150
150
  --hx-banner-close-btn-focus-ring-color,
151
- var(--hx-focus-ring-color, var(--hx-color-primary-400, #6ab1b1))
151
+ var(--hx-focus-ring-color, var(--hx-color-primary-600, #0f7078))
152
152
  );
153
153
  outline-offset: var(--hx-focus-ring-offset, 2px);
154
154
  opacity: 1;
@@ -422,4 +422,4 @@ e = r([
422
422
  export {
423
423
  e as H
424
424
  };
425
- //# sourceMappingURL=hx-banner-DT7Zn9Bo.js.map
425
+ //# sourceMappingURL=hx-banner-Cxd7eFUP.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"hx-banner-DT7Zn9Bo.js","sources":["../../src/components/hx-banner/hx-banner.styles.ts","../../src/components/hx-banner/hx-banner.ts"],"sourcesContent":["import { css } from 'lit';\n\n/**\n * hx-banner styles.\n *\n * Component-tier tokens with two-level var() fallback:\n * var(--hx-banner-{prop}, var(--hx-color-{semantic}, #hex))\n * Inner hex fallbacks track the \"precision cool\" palette (3.2.0):\n * info-50 = #EFF6FE, info-200 = #BEDCFC, info-500 = #0C8BEB, info-800 = #064172,\n * success-50 = #EAFAEC, success-200 = #BAE6C2, success-500 = #3B9E58, success-800 = #0B4D23,\n * warning-50 = #FFF3EA, warning-200 = #FACFAE, warning-500 = #C2711C, warning-800 = #603301,\n * error-50 = #FFF2F0, error-200 = #FCCBC4, error-500 = #E5493E, error-800 = #7A090A,\n * primary-400 = #6AB1B1.\n */\nexport const helixBannerStyles = css`\n :host {\n display: block;\n width: 100%;\n position: var(--hx-banner-position, sticky);\n top: 0;\n left: 0;\n right: 0;\n z-index: var(--hx-banner-z-index, 100);\n }\n\n :host(:not([open])) {\n display: none;\n }\n\n * {\n box-sizing: border-box;\n }\n\n /* ─── Severity Label (WCAG 1.4.1) ─── */\n /* Visually hidden — ensures variant is never conveyed by color alone. */\n /* Always rendered so screen readers can identify the banner severity. */\n\n .banner__severity-label {\n position: absolute;\n width: 1px;\n height: 1px;\n padding: 0;\n margin: -1px;\n overflow: hidden;\n clip: rect(0, 0, 0, 0);\n white-space: nowrap;\n border: 0;\n }\n\n /* ─── Banner Container ─── */\n\n .banner {\n display: flex;\n align-items: center;\n gap: var(--hx-banner-gap, var(--hx-space-3, 0.75rem));\n padding: var(--hx-banner-padding, var(--hx-space-3, 0.75rem) var(--hx-space-4, 1rem));\n background-color: var(--hx-banner-bg, var(--hx-color-info-50, #eff6fe));\n color: var(--hx-banner-color, var(--hx-color-info-800, #064172));\n border-bottom: var(--hx-banner-border-width, var(--hx-border-width-thin, 1px)) solid\n var(--hx-banner-border-color, var(--hx-color-info-200, #bedcfc));\n font-family: var(--hx-banner-font-family, var(--hx-font-family-sans, sans-serif));\n font-size: var(--hx-font-size-sm, 0.875rem);\n line-height: var(--hx-line-height-normal, 1.5);\n width: 100%;\n }\n\n /* ─── Icon ─── */\n\n .banner__icon {\n display: flex;\n align-items: center;\n flex-shrink: 0;\n color: var(--hx-banner-icon-color, var(--hx-color-info-500, #0c8beb));\n }\n\n .banner__icon svg {\n width: var(--hx-space-5, 1.25rem);\n height: var(--hx-space-5, 1.25rem);\n fill: currentColor;\n }\n\n /* ─── Message ─── */\n\n .banner__message {\n flex: 1;\n min-width: 0;\n }\n\n /* ─── Action Link ─── */\n\n .banner__action {\n display: inline-flex;\n align-items: center;\n flex-shrink: 0;\n color: var(--hx-banner-action-color, var(--hx-banner-color, var(--hx-color-info-800, #064172)));\n font-weight: var(--hx-font-weight-semibold, 600);\n text-decoration: underline;\n text-underline-offset: 2px;\n cursor: pointer;\n background: transparent;\n border: none;\n padding: 0;\n font-size: inherit;\n font-family: inherit;\n }\n\n .banner__action:hover {\n opacity: var(--hx-opacity-90, 0.9);\n }\n\n .banner__action:focus-visible {\n outline: var(--hx-focus-ring-width, 2px) solid\n var(\n --hx-banner-action-focus-ring-color,\n var(--hx-focus-ring-color, var(--hx-color-primary-400, #6ab1b1))\n );\n outline-offset: var(--hx-focus-ring-offset, 2px);\n border-radius: var(--hx-border-radius-sm, 0.25rem);\n }\n\n /* ─── Close Button ─── */\n /* Minimum 44px touch target per WCAG 2.5.8 (Target Size Minimum, AA) and */\n /* Apple HIG / Google Material guidelines. Uses absolute px units to ensure */\n /* the target size is independent of the consumer's base font size. */\n\n .banner__close-button {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n min-width: var(--hx-touch-target-size, 44px);\n min-height: var(--hx-touch-target-size, 44px);\n margin-inline-start: auto;\n padding: 0;\n border: none;\n border-radius: var(--hx-border-radius-sm, 0.25rem);\n background: transparent;\n color: var(--hx-banner-color, var(--hx-color-info-800, #064172));\n cursor: pointer;\n font-size: var(--hx-font-size-md, 1rem);\n line-height: 1;\n transition:\n background-color var(--hx-transition-fast, 150ms ease),\n opacity var(--hx-transition-fast, 150ms ease);\n opacity: var(--hx-opacity-75, 0.75);\n }\n\n .banner__close-button:hover {\n opacity: var(--hx-opacity-100, 1);\n /* color-mix() is supported in Chrome 111+, Firefox 113+, Safari 16.2+. */\n /* Falls back to transparent (no hover background) in older environments. */\n background-color: color-mix(in srgb, currentColor 10%, transparent);\n }\n\n .banner__close-button:focus-visible {\n outline: var(--hx-focus-ring-width, 2px) solid\n var(\n --hx-banner-close-btn-focus-ring-color,\n var(--hx-focus-ring-color, var(--hx-color-primary-400, #6ab1b1))\n );\n outline-offset: var(--hx-focus-ring-offset, 2px);\n opacity: 1;\n }\n\n .banner__close-button svg {\n width: var(--hx-space-4, 1rem);\n height: var(--hx-space-4, 1rem);\n fill: currentColor;\n }\n\n /* ─── Variant: info ─── */\n\n :host([variant='info']) .banner,\n :host(:not([variant])) .banner {\n --hx-banner-bg: var(--hx-color-info-50, #eff6fe);\n --hx-banner-border-color: var(--hx-color-info-200, #bedcfc);\n --hx-banner-color: var(--hx-color-info-800, #064172);\n --hx-banner-icon-color: var(--hx-color-info-500, #0c8beb);\n }\n\n /* ─── Variant: success ─── */\n\n :host([variant='success']) .banner {\n --hx-banner-bg: var(--hx-color-success-50, #eafaec);\n --hx-banner-border-color: var(--hx-color-success-200, #bae6c2);\n --hx-banner-color: var(--hx-color-success-800, #0b4d23);\n --hx-banner-icon-color: var(--hx-color-success-500, #3b9e58);\n }\n\n /* ─── Variant: warning ─── */\n\n :host([variant='warning']) .banner {\n --hx-banner-bg: var(--hx-color-warning-50, #fff3ea);\n --hx-banner-border-color: var(--hx-color-warning-200, #facfae);\n --hx-banner-color: var(--hx-color-warning-800, #603301);\n --hx-banner-icon-color: var(--hx-color-warning-500, #c2711c);\n }\n\n /* ─── Variant: error ─── */\n\n :host([variant='error']) .banner {\n --hx-banner-bg: var(--hx-color-error-50, #fff2f0);\n --hx-banner-border-color: var(--hx-color-error-200, #fccbc4);\n --hx-banner-color: var(--hx-color-error-800, #7a090a);\n --hx-banner-icon-color: var(--hx-color-error-500, #e5493e);\n }\n\n /* ─── Position: fixed ─── */\n /* When position=\"fixed\", override the host-level CSS custom property. */\n /* The :host rule above sets position via var(--hx-banner-position). */\n /* We use an attribute selector to override it cleanly without duplication. */\n\n :host([position='fixed']) {\n position: fixed;\n }\n\n /* ─── Reduced Motion ─── */\n\n @media (prefers-reduced-motion: reduce) {\n .banner__close-button {\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 .banner {\n border-bottom-color: CanvasText;\n }\n\n .banner__icon svg {\n fill: CanvasText;\n }\n\n .banner__close-button {\n color: ButtonText;\n border: 1px solid ButtonText;\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 { classMap } from 'lit/directives/class-map.js';\nimport { ifDefined } from 'lit/directives/if-defined.js';\nimport { HelixElement } from '../../base/index.js';\nimport { helixBannerStyles } from './hx-banner.styles.js';\nimport { forcedColorsSurface } from '../../styles/forced-colors.js';\n\n/** Banner variant determines visual styling and ARIA semantics. */\nexport type BannerVariant = 'info' | 'success' | 'warning' | 'error';\n\n/** Banner position determines CSS positioning behavior. */\nexport type BannerPosition = 'sticky' | 'fixed';\n\n/**\n * A full-width page-level banner for persistent notifications and announcements.\n * Designed for healthcare applications requiring prominent system-level messaging.\n *\n * @summary Full-width page-level banner for persistent notifications with variant-based styling and ARIA live regions.\n *\n * @tag hx-banner\n *\n * @slot - Default slot for banner message content.\n * @slot action - Optional slot to override the built-in action link with custom content.\n *\n * @fires {CustomEvent<{reason: string}>} hx-dismiss - Dispatched when the user dismisses the banner.\n *\n * @csspart banner - The outer banner container.\n * @csspart icon - The icon container.\n * @csspart message - The message content area.\n * @csspart action - The action link element (only rendered when action-label and action-href are set).\n * @csspart close-button - The dismiss button (only rendered when dismissible).\n *\n * @cssprop [--hx-banner-bg=var(--hx-color-info-50)] - Banner background color.\n * @cssprop [--hx-banner-color=var(--hx-color-info-800)] - Banner text color.\n * @cssprop [--hx-banner-border-color=var(--hx-color-info-200)] - Banner bottom border color.\n * @cssprop [--hx-banner-border-width=var(--hx-border-width-thin)] - Banner bottom border width.\n * @cssprop [--hx-banner-padding=var(--hx-space-3) var(--hx-space-4)] - Banner padding.\n * @cssprop [--hx-banner-gap=var(--hx-space-3)] - Gap between banner elements.\n * @cssprop [--hx-banner-icon-color=var(--hx-color-info-500)] - Banner icon color.\n * @cssprop [--hx-banner-font-family=var(--hx-font-family-sans)] - Banner font family.\n * @cssprop [--hx-banner-action-color=var(--hx-banner-color)] - Action link color.\n * @cssprop [--hx-banner-position=sticky] - CSS position value (sticky or fixed).\n * @cssprop [--hx-banner-z-index=100] - Banner z-index for stacking context.\n * @cssprop [--hx-touch-target-size=44px] - Minimum touch target size for the close button.\n * @cssprop [--hx-space-3] - Spacing token.\n * @cssprop [--hx-space-4] - Spacing token.\n * @cssprop [--hx-color-info-50] - Color.\n * @cssprop [--hx-color-info-800] - Color.\n * @cssprop [--hx-border-width-thin] - Width.\n * @cssprop [--hx-color-info-200] - 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-info-500] - Color.\n * @cssprop [--hx-space-5] - Spacing token.\n * @cssprop [--hx-font-weight-semibold] - Font weight.\n * @cssprop [--hx-opacity-90] - Opacity.\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-font-size-md] - Font size.\n * @cssprop [--hx-transition-fast] - Transition timing.\n * @cssprop [--hx-opacity-75] - Opacity.\n * @cssprop [--hx-opacity-100] - Opacity.\n * @cssprop [--hx-color-success-50] - Color.\n * @cssprop [--hx-color-success-200] - Color.\n * @cssprop [--hx-color-success-800] - Color.\n * @cssprop [--hx-color-success-500] - Color.\n * @cssprop [--hx-color-warning-50] - Color.\n * @cssprop [--hx-color-warning-200] - Color.\n * @cssprop [--hx-color-warning-800] - Color.\n * @cssprop [--hx-color-warning-500] - Color.\n * @cssprop [--hx-color-error-50] - Color.\n * @cssprop [--hx-color-error-200] - Color.\n * @cssprop [--hx-color-error-800] - Color.\n * @cssprop [--hx-color-error-500] - Color.\n */\n@customElement('hx-banner')\nexport class HelixBanner extends HelixElement {\n static override styles = [helixBannerStyles, forcedColorsSurface];\n\n // ─── Properties ───\n\n /**\n * Visual variant of the banner that determines colors and ARIA semantics.\n * @attr variant\n */\n @property({ type: String, reflect: true })\n variant: 'info' | 'success' | 'warning' | 'error' = 'info';\n\n /**\n * CSS positioning behavior. \"sticky\" keeps the banner in flow; \"fixed\" pins it to the viewport.\n * @attr position\n */\n @property({ type: String, reflect: true })\n position: 'sticky' | 'fixed' = 'sticky';\n\n /**\n * Whether the banner can be dismissed by the user.\n * @attr dismissible\n */\n @property({ type: Boolean, reflect: true })\n dismissible = false;\n\n /**\n * Heading text for the banner, used to provide context in the action link's and\n * close button's accessible labels.\n * @attr heading\n */\n @property({ type: String })\n heading = '';\n\n /**\n * Label text for the optional action link. Requires action-href to render.\n * @attr action-label\n */\n @property({ type: String, attribute: 'action-label' })\n actionLabel = '';\n\n /**\n * URL for the optional action link. Requires action-label to render.\n * @attr action-href\n */\n @property({ type: String, attribute: 'action-href' })\n actionHref = '';\n\n /**\n * Whether the banner is visible. Defaults to true — banners are shown by default.\n * @attr open\n */\n @property({ type: Boolean, reflect: true })\n open = true;\n\n /** Accessible label for the dismiss button. Override for localized text. */\n @property({ type: String, attribute: 'label-close' })\n labelClose = 'Dismiss banner';\n\n /**\n * Override for the severity prefix announced to screen readers (e.g., \"Info:\", \"Error:\").\n * When not set, defaults to the English label matching the current variant.\n * @attr severity-label\n */\n @property({ attribute: 'severity-label' })\n severityLabel: string | undefined;\n\n // ─── Private Helpers ───\n\n /** Returns the default English severity label for the current variant. */\n private _defaultSeverityLabel(): string {\n const labels: Record<string, string> = {\n info: 'Info:',\n success: 'Success:',\n warning: 'Warning:',\n error: 'Error:',\n };\n return labels[this.variant] ?? '';\n }\n\n /** Returns the effective severity label, using the override if provided. */\n private get _effectiveSeverityLabel(): string {\n return this.severityLabel ?? this._defaultSeverityLabel();\n }\n\n /** Returns true when the variant requires assertive announcement. */\n /** @internal */\n private get _isAssertive(): boolean {\n return this.variant === 'error' || this.variant === 'warning';\n }\n\n /**\n * Returns the appropriate ARIA role based on variant.\n * role=\"alert\" implies aria-live=\"assertive\"; role=\"status\" implies aria-live=\"polite\".\n * We do NOT set aria-live explicitly to avoid double-announcements in JAWS.\n */\n /** @internal */\n private get _role(): string {\n return this._isAssertive ? 'alert' : 'status';\n }\n\n // ─── Lifecycle ───\n\n override connectedCallback(): void {\n super.connectedCallback();\n // Apply ARIA role to the host element for reliable screen reader support across\n // Shadow DOM boundaries. Placing role on a shadow-internal element has inconsistent\n // AT support in JAWS+Chrome and VoiceOver+Safari combinations (particularly pre-2024).\n this.setAttribute('role', this._role);\n if (!this.open) {\n this.setAttribute('aria-hidden', 'true');\n }\n }\n\n protected override updated(changedProperties: PropertyValues<this>): void {\n super.updated(changedProperties);\n if (changedProperties.has('variant')) {\n // Keep host ARIA role in sync with variant (assertive vs. polite).\n this.setAttribute('role', this._role);\n }\n if (changedProperties.has('open')) {\n // Manage aria-hidden in addition to display:none for reliable AT exclusion.\n // When open transitions from false→true, removing aria-hidden signals to AT\n // that the live region content should be announced.\n if (this.open) {\n this.removeAttribute('aria-hidden');\n } else {\n this.setAttribute('aria-hidden', 'true');\n }\n }\n }\n\n // ─── Default Icons ───\n\n /** @internal */\n private _renderInfoIcon() {\n return html`<svg viewBox=\"0 0 20 20\" aria-hidden=\"true\">\n <path\n d=\"M10 2a8 8 0 100 16 8 8 0 000-16zm.75 4.75a.75.75 0 11-1.5 0 .75.75 0 011.5 0zM9.25 9a.75.75 0 011.5 0v4a.75.75 0 01-1.5 0V9z\"\n />\n </svg>`;\n }\n\n /** @internal */\n private _renderSuccessIcon() {\n return html`<svg viewBox=\"0 0 20 20\" aria-hidden=\"true\">\n <path\n d=\"M10 2a8 8 0 100 16 8 8 0 000-16zm3.03 6.28a.75.75 0 00-1.06-1.06L9 10.19 7.78 8.97a.75.75 0 00-1.06 1.06l1.75 1.75a.75.75 0 001.06 0l3.5-3.5z\"\n />\n </svg>`;\n }\n\n /** @internal */\n private _renderWarningIcon() {\n return html`<svg viewBox=\"0 0 20 20\" aria-hidden=\"true\">\n <path\n d=\"M8.49 2.92a1.75 1.75 0 013.02 0l6.25 10.83A1.75 1.75 0 0116.25 16H3.75a1.75 1.75 0 01-1.51-2.25L8.49 2.92zM10 7a.75.75 0 01.75.75v3a.75.75 0 01-1.5 0v-3A.75.75 0 0110 7zm0 7.5a.75.75 0 100-1.5.75.75 0 000 1.5z\"\n />\n </svg>`;\n }\n\n /** @internal */\n private _renderErrorIcon() {\n return html`<svg viewBox=\"0 0 20 20\" aria-hidden=\"true\">\n <path\n d=\"M10 2a8 8 0 100 16 8 8 0 000-16zm-1.72 5.22a.75.75 0 011.06 0L10 7.94l.66-.72a.75.75 0 111.06 1.06L11.06 9l.66.72a.75.75 0 11-1.06 1.06L10 10.06l-.66.72a.75.75 0 01-1.06-1.06L8.94 9l-.66-.72a.75.75 0 010-1.06z\"\n />\n </svg>`;\n }\n\n /** @internal */\n private _renderDefaultIcon() {\n switch (this.variant) {\n case 'success':\n return this._renderSuccessIcon();\n case 'warning':\n return this._renderWarningIcon();\n case 'error':\n return this._renderErrorIcon();\n case 'info':\n default:\n return this._renderInfoIcon();\n }\n }\n\n /** @internal */\n private _renderCloseIcon() {\n return html`<svg viewBox=\"0 0 20 20\" aria-hidden=\"true\">\n <path\n d=\"M6.28 5.22a.75.75 0 00-1.06 1.06L8.94 10l-3.72 3.72a.75.75 0 101.06 1.06L10 11.06l3.72 3.72a.75.75 0 101.06-1.06L11.06 10l3.72-3.72a.75.75 0 00-1.06-1.06L10 8.94 6.28 5.22z\"\n />\n </svg>`;\n }\n\n // ─── Public Methods ───\n\n /**\n * Programmatically dismisses the banner. Sets open=false and dispatches hx-dismiss.\n */\n dismiss(): void {\n this._handleDismiss();\n }\n\n // ─── Event Handling ───\n\n /** @internal */\n private _handleDismiss(): void {\n this.open = false;\n\n /**\n * Dispatched when the user (or caller) dismisses the banner.\n * @event hx-dismiss\n */\n this.dispatchEvent(\n new CustomEvent<{ reason: string }>('hx-dismiss', {\n bubbles: true,\n composed: true,\n detail: { reason: 'user' },\n }),\n );\n }\n\n // ─── Render ───\n\n override render() {\n const classes = {\n banner: true,\n [`banner--${this.variant}`]: true,\n };\n\n const hasAction = this.actionLabel.length > 0 && this.actionHref.length > 0;\n\n // WCAG 1.4.1: Always render a visually-hidden severity label so the variant\n // is never conveyed by color alone.\n const severityLabel = this._effectiveSeverityLabel;\n\n return html`\n <div part=\"banner\" class=${classMap(classes)}>\n <span class=\"banner__severity-label\">${severityLabel}</span>\n <div part=\"icon\" class=\"banner__icon\">${this._renderDefaultIcon()}</div>\n\n <div part=\"message\" class=\"banner__message\">\n <slot></slot>\n </div>\n\n ${hasAction\n ? html`\n <a\n part=\"action\"\n class=\"banner__action\"\n href=${ifDefined(this.actionHref || undefined)}\n aria-label=${this.heading\n ? `${this.actionLabel}: ${this.heading}`\n : this.actionLabel}\n >\n <slot name=\"action\">${this.actionLabel}</slot>\n </a>\n `\n : nothing}\n ${this.dismissible\n ? html`\n <button\n part=\"close-button\"\n class=\"banner__close-button\"\n aria-label=${this.labelClose}\n @click=${this._handleDismiss}\n >\n ${this._renderCloseIcon()}\n </button>\n `\n : nothing}\n </div>\n `;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'hx-banner': HelixBanner;\n }\n}\n\nexport type { HelixBanner as HxBanner };\n"],"names":["helixBannerStyles","css","HelixBanner","HelixElement","changedProperties","html","classes","hasAction","severityLabel","classMap","ifDefined","nothing","forcedColorsSurface","__decorateClass","property","customElement"],"mappings":";;;;;;AAcO,MAAMA,IAAoBC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;;;;ACoE1B,IAAMC,IAAN,cAA0BC,EAAa;AAAA,E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"}
1
+ {"version":3,"file":"hx-banner-Cxd7eFUP.js","sources":["../../src/components/hx-banner/hx-banner.styles.ts","../../src/components/hx-banner/hx-banner.ts"],"sourcesContent":["import { css } from 'lit';\n\n/**\n * hx-banner styles.\n *\n * Component-tier tokens with two-level var() fallback:\n * var(--hx-banner-{prop}, var(--hx-color-{semantic}, #hex))\n * Inner hex fallbacks track the \"precision cool\" palette (3.2.0):\n * info-50 = #EFF6FE, info-200 = #BEDCFC, info-500 = #0C8BEB, info-800 = #064172,\n * success-50 = #EAFAEC, success-200 = #BAE6C2, success-500 = #3B9E58, success-800 = #0B4D23,\n * warning-50 = #FFF3EA, warning-200 = #FACFAE, warning-500 = #C2711C, warning-800 = #603301,\n * error-50 = #FFF2F0, error-200 = #FCCBC4, error-500 = #E5493E, error-800 = #7A090A,\n * primary-400 = #6AB1B1.\n */\nexport const helixBannerStyles = css`\n :host {\n display: block;\n width: 100%;\n position: var(--hx-banner-position, sticky);\n top: 0;\n left: 0;\n right: 0;\n z-index: var(--hx-banner-z-index, 100);\n }\n\n :host(:not([open])) {\n display: none;\n }\n\n * {\n box-sizing: border-box;\n }\n\n /* ─── Severity Label (WCAG 1.4.1) ─── */\n /* Visually hidden — ensures variant is never conveyed by color alone. */\n /* Always rendered so screen readers can identify the banner severity. */\n\n .banner__severity-label {\n position: absolute;\n width: 1px;\n height: 1px;\n padding: 0;\n margin: -1px;\n overflow: hidden;\n clip: rect(0, 0, 0, 0);\n white-space: nowrap;\n border: 0;\n }\n\n /* ─── Banner Container ─── */\n\n .banner {\n display: flex;\n align-items: center;\n gap: var(--hx-banner-gap, var(--hx-space-3, 0.75rem));\n padding: var(--hx-banner-padding, var(--hx-space-3, 0.75rem) var(--hx-space-4, 1rem));\n background-color: var(--hx-banner-bg, var(--hx-color-info-50, #eff6fe));\n color: var(--hx-banner-color, var(--hx-color-info-800, #064172));\n border-bottom: var(--hx-banner-border-width, var(--hx-border-width-thin, 1px)) solid\n var(--hx-banner-border-color, var(--hx-color-info-200, #bedcfc));\n font-family: var(--hx-banner-font-family, var(--hx-font-family-sans, sans-serif));\n font-size: var(--hx-font-size-sm, 0.875rem);\n line-height: var(--hx-line-height-normal, 1.5);\n width: 100%;\n }\n\n /* ─── Icon ─── */\n\n .banner__icon {\n display: flex;\n align-items: center;\n flex-shrink: 0;\n color: var(--hx-banner-icon-color, var(--hx-color-info-500, #0c8beb));\n }\n\n .banner__icon svg {\n width: var(--hx-space-5, 1.25rem);\n height: var(--hx-space-5, 1.25rem);\n fill: currentColor;\n }\n\n /* ─── Message ─── */\n\n .banner__message {\n flex: 1;\n min-width: 0;\n }\n\n /* ─── Action Link ─── */\n\n .banner__action {\n display: inline-flex;\n align-items: center;\n flex-shrink: 0;\n color: var(--hx-banner-action-color, var(--hx-banner-color, var(--hx-color-info-800, #064172)));\n font-weight: var(--hx-font-weight-semibold, 600);\n text-decoration: underline;\n text-underline-offset: 2px;\n cursor: pointer;\n background: transparent;\n border: none;\n padding: 0;\n font-size: inherit;\n font-family: inherit;\n }\n\n .banner__action:hover {\n opacity: var(--hx-opacity-90, 0.9);\n }\n\n .banner__action:focus-visible {\n outline: var(--hx-focus-ring-width, 2px) solid\n var(\n --hx-banner-action-focus-ring-color,\n var(--hx-focus-ring-color, var(--hx-color-primary-600, #0f7078))\n );\n outline-offset: var(--hx-focus-ring-offset, 2px);\n border-radius: var(--hx-border-radius-sm, 0.25rem);\n }\n\n /* ─── Close Button ─── */\n /* Minimum 44px touch target per WCAG 2.5.8 (Target Size Minimum, AA) and */\n /* Apple HIG / Google Material guidelines. Uses absolute px units to ensure */\n /* the target size is independent of the consumer's base font size. */\n\n .banner__close-button {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n min-width: var(--hx-touch-target-size, 44px);\n min-height: var(--hx-touch-target-size, 44px);\n margin-inline-start: auto;\n padding: 0;\n border: none;\n border-radius: var(--hx-border-radius-sm, 0.25rem);\n background: transparent;\n color: var(--hx-banner-color, var(--hx-color-info-800, #064172));\n cursor: pointer;\n font-size: var(--hx-font-size-md, 1rem);\n line-height: 1;\n transition:\n background-color var(--hx-transition-fast, 150ms ease),\n opacity var(--hx-transition-fast, 150ms ease);\n opacity: var(--hx-opacity-75, 0.75);\n }\n\n .banner__close-button:hover {\n opacity: var(--hx-opacity-100, 1);\n /* color-mix() is supported in Chrome 111+, Firefox 113+, Safari 16.2+. */\n /* Falls back to transparent (no hover background) in older environments. */\n background-color: color-mix(in srgb, currentColor 10%, transparent);\n }\n\n .banner__close-button:focus-visible {\n outline: var(--hx-focus-ring-width, 2px) solid\n var(\n --hx-banner-close-btn-focus-ring-color,\n var(--hx-focus-ring-color, var(--hx-color-primary-600, #0f7078))\n );\n outline-offset: var(--hx-focus-ring-offset, 2px);\n opacity: 1;\n }\n\n .banner__close-button svg {\n width: var(--hx-space-4, 1rem);\n height: var(--hx-space-4, 1rem);\n fill: currentColor;\n }\n\n /* ─── Variant: info ─── */\n\n :host([variant='info']) .banner,\n :host(:not([variant])) .banner {\n --hx-banner-bg: var(--hx-color-info-50, #eff6fe);\n --hx-banner-border-color: var(--hx-color-info-200, #bedcfc);\n --hx-banner-color: var(--hx-color-info-800, #064172);\n --hx-banner-icon-color: var(--hx-color-info-500, #0c8beb);\n }\n\n /* ─── Variant: success ─── */\n\n :host([variant='success']) .banner {\n --hx-banner-bg: var(--hx-color-success-50, #eafaec);\n --hx-banner-border-color: var(--hx-color-success-200, #bae6c2);\n --hx-banner-color: var(--hx-color-success-800, #0b4d23);\n --hx-banner-icon-color: var(--hx-color-success-500, #3b9e58);\n }\n\n /* ─── Variant: warning ─── */\n\n :host([variant='warning']) .banner {\n --hx-banner-bg: var(--hx-color-warning-50, #fff3ea);\n --hx-banner-border-color: var(--hx-color-warning-200, #facfae);\n --hx-banner-color: var(--hx-color-warning-800, #603301);\n --hx-banner-icon-color: var(--hx-color-warning-500, #c2711c);\n }\n\n /* ─── Variant: error ─── */\n\n :host([variant='error']) .banner {\n --hx-banner-bg: var(--hx-color-error-50, #fff2f0);\n --hx-banner-border-color: var(--hx-color-error-200, #fccbc4);\n --hx-banner-color: var(--hx-color-error-800, #7a090a);\n --hx-banner-icon-color: var(--hx-color-error-500, #e5493e);\n }\n\n /* ─── Position: fixed ─── */\n /* When position=\"fixed\", override the host-level CSS custom property. */\n /* The :host rule above sets position via var(--hx-banner-position). */\n /* We use an attribute selector to override it cleanly without duplication. */\n\n :host([position='fixed']) {\n position: fixed;\n }\n\n /* ─── Reduced Motion ─── */\n\n @media (prefers-reduced-motion: reduce) {\n .banner__close-button {\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 .banner {\n border-bottom-color: CanvasText;\n }\n\n .banner__icon svg {\n fill: CanvasText;\n }\n\n .banner__close-button {\n color: ButtonText;\n border: 1px solid ButtonText;\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 { classMap } from 'lit/directives/class-map.js';\nimport { ifDefined } from 'lit/directives/if-defined.js';\nimport { HelixElement } from '../../base/index.js';\nimport { helixBannerStyles } from './hx-banner.styles.js';\nimport { forcedColorsSurface } from '../../styles/forced-colors.js';\n\n/** Banner variant determines visual styling and ARIA semantics. */\nexport type BannerVariant = 'info' | 'success' | 'warning' | 'error';\n\n/** Banner position determines CSS positioning behavior. */\nexport type BannerPosition = 'sticky' | 'fixed';\n\n/**\n * A full-width page-level banner for persistent notifications and announcements.\n * Designed for healthcare applications requiring prominent system-level messaging.\n *\n * @summary Full-width page-level banner for persistent notifications with variant-based styling and ARIA live regions.\n *\n * @tag hx-banner\n *\n * @slot - Default slot for banner message content.\n * @slot action - Optional slot to override the built-in action link with custom content.\n *\n * @fires {CustomEvent<{reason: string}>} hx-dismiss - Dispatched when the user dismisses the banner.\n *\n * @csspart banner - The outer banner container.\n * @csspart icon - The icon container.\n * @csspart message - The message content area.\n * @csspart action - The action link element (only rendered when action-label and action-href are set).\n * @csspart close-button - The dismiss button (only rendered when dismissible).\n *\n * @cssprop [--hx-banner-bg=var(--hx-color-info-50)] - Banner background color.\n * @cssprop [--hx-banner-color=var(--hx-color-info-800)] - Banner text color.\n * @cssprop [--hx-banner-border-color=var(--hx-color-info-200)] - Banner bottom border color.\n * @cssprop [--hx-banner-border-width=var(--hx-border-width-thin)] - Banner bottom border width.\n * @cssprop [--hx-banner-padding=var(--hx-space-3) var(--hx-space-4)] - Banner padding.\n * @cssprop [--hx-banner-gap=var(--hx-space-3)] - Gap between banner elements.\n * @cssprop [--hx-banner-icon-color=var(--hx-color-info-500)] - Banner icon color.\n * @cssprop [--hx-banner-font-family=var(--hx-font-family-sans)] - Banner font family.\n * @cssprop [--hx-banner-action-color=var(--hx-banner-color)] - Action link color.\n * @cssprop [--hx-banner-position=sticky] - CSS position value (sticky or fixed).\n * @cssprop [--hx-banner-z-index=100] - Banner z-index for stacking context.\n * @cssprop [--hx-touch-target-size=44px] - Minimum touch target size for the close button.\n * @cssprop [--hx-space-3] - Spacing token.\n * @cssprop [--hx-space-4] - Spacing token.\n * @cssprop [--hx-color-info-50] - Color.\n * @cssprop [--hx-color-info-800] - Color.\n * @cssprop [--hx-border-width-thin] - Width.\n * @cssprop [--hx-color-info-200] - 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-info-500] - Color.\n * @cssprop [--hx-space-5] - Spacing token.\n * @cssprop [--hx-font-weight-semibold] - Font weight.\n * @cssprop [--hx-opacity-90] - Opacity.\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-font-size-md] - Font size.\n * @cssprop [--hx-transition-fast] - Transition timing.\n * @cssprop [--hx-opacity-75] - Opacity.\n * @cssprop [--hx-opacity-100] - Opacity.\n * @cssprop [--hx-color-success-50] - Color.\n * @cssprop [--hx-color-success-200] - Color.\n * @cssprop [--hx-color-success-800] - Color.\n * @cssprop [--hx-color-success-500] - Color.\n * @cssprop [--hx-color-warning-50] - Color.\n * @cssprop [--hx-color-warning-200] - Color.\n * @cssprop [--hx-color-warning-800] - Color.\n * @cssprop [--hx-color-warning-500] - Color.\n * @cssprop [--hx-color-error-50] - Color.\n * @cssprop [--hx-color-error-200] - Color.\n * @cssprop [--hx-color-error-800] - Color.\n * @cssprop [--hx-color-error-500] - Color.\n */\n@customElement('hx-banner')\nexport class HelixBanner extends HelixElement {\n static override styles = [helixBannerStyles, forcedColorsSurface];\n\n // ─── Properties ───\n\n /**\n * Visual variant of the banner that determines colors and ARIA semantics.\n * @attr variant\n */\n @property({ type: String, reflect: true })\n variant: 'info' | 'success' | 'warning' | 'error' = 'info';\n\n /**\n * CSS positioning behavior. \"sticky\" keeps the banner in flow; \"fixed\" pins it to the viewport.\n * @attr position\n */\n @property({ type: String, reflect: true })\n position: 'sticky' | 'fixed' = 'sticky';\n\n /**\n * Whether the banner can be dismissed by the user.\n * @attr dismissible\n */\n @property({ type: Boolean, reflect: true })\n dismissible = false;\n\n /**\n * Heading text for the banner, used to provide context in the action link's and\n * close button's accessible labels.\n * @attr heading\n */\n @property({ type: String })\n heading = '';\n\n /**\n * Label text for the optional action link. Requires action-href to render.\n * @attr action-label\n */\n @property({ type: String, attribute: 'action-label' })\n actionLabel = '';\n\n /**\n * URL for the optional action link. Requires action-label to render.\n * @attr action-href\n */\n @property({ type: String, attribute: 'action-href' })\n actionHref = '';\n\n /**\n * Whether the banner is visible. Defaults to true — banners are shown by default.\n * @attr open\n */\n @property({ type: Boolean, reflect: true })\n open = true;\n\n /** Accessible label for the dismiss button. Override for localized text. */\n @property({ type: String, attribute: 'label-close' })\n labelClose = 'Dismiss banner';\n\n /**\n * Override for the severity prefix announced to screen readers (e.g., \"Info:\", \"Error:\").\n * When not set, defaults to the English label matching the current variant.\n * @attr severity-label\n */\n @property({ attribute: 'severity-label' })\n severityLabel: string | undefined;\n\n // ─── Private Helpers ───\n\n /** Returns the default English severity label for the current variant. */\n private _defaultSeverityLabel(): string {\n const labels: Record<string, string> = {\n info: 'Info:',\n success: 'Success:',\n warning: 'Warning:',\n error: 'Error:',\n };\n return labels[this.variant] ?? '';\n }\n\n /** Returns the effective severity label, using the override if provided. */\n private get _effectiveSeverityLabel(): string {\n return this.severityLabel ?? this._defaultSeverityLabel();\n }\n\n /** Returns true when the variant requires assertive announcement. */\n /** @internal */\n private get _isAssertive(): boolean {\n return this.variant === 'error' || this.variant === 'warning';\n }\n\n /**\n * Returns the appropriate ARIA role based on variant.\n * role=\"alert\" implies aria-live=\"assertive\"; role=\"status\" implies aria-live=\"polite\".\n * We do NOT set aria-live explicitly to avoid double-announcements in JAWS.\n */\n /** @internal */\n private get _role(): string {\n return this._isAssertive ? 'alert' : 'status';\n }\n\n // ─── Lifecycle ───\n\n override connectedCallback(): void {\n super.connectedCallback();\n // Apply ARIA role to the host element for reliable screen reader support across\n // Shadow DOM boundaries. Placing role on a shadow-internal element has inconsistent\n // AT support in JAWS+Chrome and VoiceOver+Safari combinations (particularly pre-2024).\n this.setAttribute('role', this._role);\n if (!this.open) {\n this.setAttribute('aria-hidden', 'true');\n }\n }\n\n protected override updated(changedProperties: PropertyValues<this>): void {\n super.updated(changedProperties);\n if (changedProperties.has('variant')) {\n // Keep host ARIA role in sync with variant (assertive vs. polite).\n this.setAttribute('role', this._role);\n }\n if (changedProperties.has('open')) {\n // Manage aria-hidden in addition to display:none for reliable AT exclusion.\n // When open transitions from false→true, removing aria-hidden signals to AT\n // that the live region content should be announced.\n if (this.open) {\n this.removeAttribute('aria-hidden');\n } else {\n this.setAttribute('aria-hidden', 'true');\n }\n }\n }\n\n // ─── Default Icons ───\n\n /** @internal */\n private _renderInfoIcon() {\n return html`<svg viewBox=\"0 0 20 20\" aria-hidden=\"true\">\n <path\n d=\"M10 2a8 8 0 100 16 8 8 0 000-16zm.75 4.75a.75.75 0 11-1.5 0 .75.75 0 011.5 0zM9.25 9a.75.75 0 011.5 0v4a.75.75 0 01-1.5 0V9z\"\n />\n </svg>`;\n }\n\n /** @internal */\n private _renderSuccessIcon() {\n return html`<svg viewBox=\"0 0 20 20\" aria-hidden=\"true\">\n <path\n d=\"M10 2a8 8 0 100 16 8 8 0 000-16zm3.03 6.28a.75.75 0 00-1.06-1.06L9 10.19 7.78 8.97a.75.75 0 00-1.06 1.06l1.75 1.75a.75.75 0 001.06 0l3.5-3.5z\"\n />\n </svg>`;\n }\n\n /** @internal */\n private _renderWarningIcon() {\n return html`<svg viewBox=\"0 0 20 20\" aria-hidden=\"true\">\n <path\n d=\"M8.49 2.92a1.75 1.75 0 013.02 0l6.25 10.83A1.75 1.75 0 0116.25 16H3.75a1.75 1.75 0 01-1.51-2.25L8.49 2.92zM10 7a.75.75 0 01.75.75v3a.75.75 0 01-1.5 0v-3A.75.75 0 0110 7zm0 7.5a.75.75 0 100-1.5.75.75 0 000 1.5z\"\n />\n </svg>`;\n }\n\n /** @internal */\n private _renderErrorIcon() {\n return html`<svg viewBox=\"0 0 20 20\" aria-hidden=\"true\">\n <path\n d=\"M10 2a8 8 0 100 16 8 8 0 000-16zm-1.72 5.22a.75.75 0 011.06 0L10 7.94l.66-.72a.75.75 0 111.06 1.06L11.06 9l.66.72a.75.75 0 11-1.06 1.06L10 10.06l-.66.72a.75.75 0 01-1.06-1.06L8.94 9l-.66-.72a.75.75 0 010-1.06z\"\n />\n </svg>`;\n }\n\n /** @internal */\n private _renderDefaultIcon() {\n switch (this.variant) {\n case 'success':\n return this._renderSuccessIcon();\n case 'warning':\n return this._renderWarningIcon();\n case 'error':\n return this._renderErrorIcon();\n case 'info':\n default:\n return this._renderInfoIcon();\n }\n }\n\n /** @internal */\n private _renderCloseIcon() {\n return html`<svg viewBox=\"0 0 20 20\" aria-hidden=\"true\">\n <path\n d=\"M6.28 5.22a.75.75 0 00-1.06 1.06L8.94 10l-3.72 3.72a.75.75 0 101.06 1.06L10 11.06l3.72 3.72a.75.75 0 101.06-1.06L11.06 10l3.72-3.72a.75.75 0 00-1.06-1.06L10 8.94 6.28 5.22z\"\n />\n </svg>`;\n }\n\n // ─── Public Methods ───\n\n /**\n * Programmatically dismisses the banner. Sets open=false and dispatches hx-dismiss.\n */\n dismiss(): void {\n this._handleDismiss();\n }\n\n // ─── Event Handling ───\n\n /** @internal */\n private _handleDismiss(): void {\n this.open = false;\n\n /**\n * Dispatched when the user (or caller) dismisses the banner.\n * @event hx-dismiss\n */\n this.dispatchEvent(\n new CustomEvent<{ reason: string }>('hx-dismiss', {\n bubbles: true,\n composed: true,\n detail: { reason: 'user' },\n }),\n );\n }\n\n // ─── Render ───\n\n override render() {\n const classes = {\n banner: true,\n [`banner--${this.variant}`]: true,\n };\n\n const hasAction = this.actionLabel.length > 0 && this.actionHref.length > 0;\n\n // WCAG 1.4.1: Always render a visually-hidden severity label so the variant\n // is never conveyed by color alone.\n const severityLabel = this._effectiveSeverityLabel;\n\n return html`\n <div part=\"banner\" class=${classMap(classes)}>\n <span class=\"banner__severity-label\">${severityLabel}</span>\n <div part=\"icon\" class=\"banner__icon\">${this._renderDefaultIcon()}</div>\n\n <div part=\"message\" class=\"banner__message\">\n <slot></slot>\n </div>\n\n ${hasAction\n ? html`\n <a\n part=\"action\"\n class=\"banner__action\"\n href=${ifDefined(this.actionHref || undefined)}\n aria-label=${this.heading\n ? `${this.actionLabel}: ${this.heading}`\n : this.actionLabel}\n >\n <slot name=\"action\">${this.actionLabel}</slot>\n </a>\n `\n : nothing}\n ${this.dismissible\n ? html`\n <button\n part=\"close-button\"\n class=\"banner__close-button\"\n aria-label=${this.labelClose}\n @click=${this._handleDismiss}\n >\n ${this._renderCloseIcon()}\n </button>\n `\n : nothing}\n </div>\n `;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'hx-banner': HelixBanner;\n }\n}\n\nexport type { HelixBanner as HxBanner };\n"],"names":["helixBannerStyles","css","HelixBanner","HelixElement","changedProperties","html","classes","hasAction","severityLabel","classMap","ifDefined","nothing","forcedColorsSurface","__decorateClass","property","customElement"],"mappings":";;;;;;AAcO,MAAMA,IAAoBC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;;;;ACoE1B,IAAMC,IAAN,cAA0BC,EAAa;AAAA,E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"}
@@ -283,10 +283,7 @@ const C = m`
283
283
 
284
284
  [part='link']:focus-visible {
285
285
  outline: var(--hx-focus-ring-width, 2px) solid
286
- var(
287
- --hx-breadcrumb-link-focus-ring-color,
288
- var(--hx-focus-ring-color, var(--hx-color-primary-500, #429797))
289
- );
286
+ var(--hx-breadcrumb-link-focus-ring-color, var(--hx-focus-ring-color, #0f7078));
290
287
  outline-offset: var(--hx-focus-ring-offset, 2px);
291
288
  border-radius: var(--hx-border-radius-sm, 0.25rem);
292
289
  }
@@ -375,4 +372,4 @@ export {
375
372
  i as H,
376
373
  p as a
377
374
  };
378
- //# sourceMappingURL=hx-breadcrumb-item-COeYcB2x.js.map
375
+ //# sourceMappingURL=hx-breadcrumb-item-3tKppF9h.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"hx-breadcrumb-item-COeYcB2x.js","sources":["../../src/components/hx-breadcrumb/hx-breadcrumb.styles.ts","../../src/components/hx-breadcrumb/hx-breadcrumb.ts","../../src/components/hx-breadcrumb/hx-breadcrumb-item.styles.ts","../../src/components/hx-breadcrumb/hx-breadcrumb-item.ts"],"sourcesContent":["import { css } from 'lit';\n\nexport const helixBreadcrumbStyles = css`\n :host {\n display: block;\n font-family: var(\n --hx-breadcrumb-font-family,\n var(--hx-font-family-sans, system-ui, sans-serif)\n );\n font-size: var(--hx-breadcrumb-font-size, var(--hx-font-size-sm, 0.875rem));\n }\n\n [part='nav'] {\n /* nav landmark — no additional styling needed */\n }\n\n [part='list'] {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n list-style: none;\n margin: 0;\n padding: 0;\n gap: 0;\n }\n\n /* Hide middle items when collapsed via maxItems */\n ::slotted([data-bc-hidden]) {\n display: none;\n }\n\n /*\n * Ellipsis ordering when collapsed (FS-014 fix):\n * The ellipsis <hx-breadcrumb-item> lives in shadow DOM to avoid mutating\n * the consumer's light DOM. CSS order places it between the first item\n * (order: 0, default) and the last item (order: 2) in the flex <ol>.\n */\n .hx-bc-ellipsis {\n order: 1;\n }\n\n ::slotted([data-bc-last]) {\n order: 2;\n }\n\n /* Visually hide the separator slot — used only to read text content.\n * display:none is intentional: the slot contains no interactive or focusable\n * content. If a future change adds focusable elements to this slot, switch to\n * visibility:hidden + position:absolute to preserve focus reachability. */\n .separator-slot {\n display: none;\n }\n\n /* ─── High Contrast Mode (forced-colors) ─── */\n\n /*\n * hx-breadcrumb is a nav container. Link colors and separators are handled\n * by hx-breadcrumb-item's own forced-colors block. No additional overrides needed\n * at the container level.\n */\n @media (forced-colors: active) {\n :host {\n forced-color-adjust: auto;\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 { forcedColorsInteractive } from '../../styles/forced-colors.js';\nimport { helixBreadcrumbStyles } from './hx-breadcrumb.styles.js';\n\n/** Typed schema.org ListItem entry for JSON-LD BreadcrumbList structured data. */\ninterface JsonLdListItem {\n '@type': string;\n position: number;\n name: string;\n item?: string;\n}\n\nconst _nextBreadcrumbId = createIdCounter('hx-breadcrumb');\n\n/**\n * Hierarchical page path navigation showing current location in site structure.\n *\n * @summary Navigation breadcrumb showing the page hierarchy. Works with Drupal's breadcrumb system.\n *\n * @tag hx-breadcrumb\n *\n * @slot - Default slot for hx-breadcrumb-item children.\n * @slot separator - Optional separator element. Its text content overrides the `separator` property.\n *\n * @csspart nav - The nav landmark element.\n * @csspart list - The ordered list containing items.\n *\n * @cssprop [--hx-breadcrumb-separator-content='/'] - Separator character between items.\n * NOTE: If overriding this custom property directly in CSS (rather than via the `separator`\n * attribute), the value MUST be quoted: `--hx-breadcrumb-separator-content: \">\"`. An unquoted\n * value is invalid for the CSS `content` property and will silently render nothing.\n * @cssprop [--hx-breadcrumb-separator-color=var(--hx-color-neutral-400)] - Separator color.\n * @cssprop [--hx-breadcrumb-separator-gap=var(--hx-space-1)] - Horizontal gap around separators.\n * @cssprop [--hx-breadcrumb-font-size=var(--hx-font-size-sm)] - Font size.\n * @cssprop [--hx-breadcrumb-link-color=var(--hx-color-primary-600)] - Link color.\n * @cssprop [--hx-breadcrumb-link-hover-color=var(--hx-color-primary-700)] - Link hover color.\n * @cssprop [--hx-breadcrumb-text-color=var(--hx-color-neutral-700)] - Current page text color.\n * @cssprop [--hx-breadcrumb-item-max-width] - Max-width for item text truncation (e.g. `12rem`).\n * @cssprop [--hx-breadcrumb-font-family] - CSS custom property.\n * @cssprop [--hx-font-family-sans] - Font family.\n * @cssprop [--hx-font-size-sm] - Font size.\n */\n@customElement('hx-breadcrumb')\nexport class HelixBreadcrumb extends HelixElement {\n static override styles = [helixBreadcrumbStyles, forcedColorsInteractive];\n\n /**\n * The separator character displayed between breadcrumb items.\n * @attr separator\n */\n @property({ type: String })\n separator = '/';\n\n /**\n * The accessible label for the nav landmark.\n * @attr label\n */\n @property({ type: String })\n label = 'Breadcrumb';\n\n /**\n * Maximum number of items to show before collapsing middle items with an ellipsis.\n * Set to 0 (default) to show all items. The ellipsis is a keyboard-accessible\n * button; activating it expands the full breadcrumb by setting maxItems to 0.\n * @attr max-items\n */\n @property({ type: Number, attribute: 'max-items' })\n maxItems = 0;\n\n /**\n * Accessible label for the expand ellipsis button. Override for i18n.\n * @attr label-ellipsis\n */\n @property({ attribute: 'label-ellipsis' }) labelEllipsis = 'Show all breadcrumb items';\n\n /**\n * When true, injects a JSON-LD BreadcrumbList structured data script into the document head.\n *\n * NOTE: Drupal manages `<head>` content via its own render pipeline. Injecting a\n * `<script>` directly via `document.head.appendChild()` in a Drupal context:\n * 1. Bypasses Drupal's deduplication and `hook_html_head_alter()` hook.\n * 2. Is not cacheable by Drupal's page cache.\n * 3. Will be wiped on BigPipe partial page replacements.\n *\n * For Drupal integrations, leave `json-ld` false and use the structured data\n * Twig template instead (see `hx-breadcrumb.twig` in the component directory).\n *\n * @attr json-ld\n */\n @property({ type: Boolean, attribute: 'json-ld' })\n jsonLd = false;\n\n /**\n * Whether the ellipsis expand button is currently shown (shadow DOM rendered).\n * Driven by maxItems collapse logic; replaces the old light-DOM ellipsis injection.\n * @internal\n */\n @state() private _showEllipsis = false;\n /** @internal */\n private _jsonLdScript: HTMLScriptElement | null = null;\n\n /**\n * Tracks which items had their `current` attribute set by this component\n * (as opposed to set by a consumer/Drupal template). This lets us re-evaluate\n * positional current-page detection on each slotchange without incorrectly\n * treating a previously component-set `current` attribute as a consumer-set\n * explicit override.\n * @internal\n */\n private readonly _managedCurrentItems = new WeakSet<Element>();\n\n /**\n * Stable per-instance ID used to tag the injected script element so that\n * multiple hx-breadcrumb instances on the same page don't produce conflicting\n * or duplicate structured-data blocks. Each instance owns exactly one script\n * tag identified by this ID; any stale tag from a previous render cycle is\n * removed before a new one is inserted.\n *\n * Uses a static counter (not Math.random()) so IDs are deterministic across\n * server and client renders, enabling SSR hydration matching.\n * @internal\n */\n private readonly _jsonLdId = `${_nextBreadcrumbId()}-ld`;\n\n // ─── Item Helpers ───\n\n /**\n * Returns only real breadcrumb items, excluding the managed ellipsis element.\n * @internal\n */\n private _getBreadcrumbItems(slot: HTMLSlotElement): Element[] {\n return slot\n .assignedElements({ flatten: true })\n .filter(\n (el) =>\n el.tagName.toLowerCase() === 'hx-breadcrumb-item' &&\n !el.classList.contains('hx-bc-ellipsis'),\n );\n }\n\n /**\n * Applies aria/state attributes to the item list.\n *\n * Current-page detection: if any item has an explicit `current` attribute\n * (e.g. set by a Drupal Twig template), that item is treated as the current\n * page. Otherwise the last item is the current page (default behaviour).\n *\n * This separation allows Drupal to control current-page marking without\n * relying on item order.\n * @internal\n */\n private _applyItemAttributes(items: Element[]): void {\n // Detect consumer-set 'current' attributes. An item has an explicit consumer\n // current if it has the 'current' attribute AND the component did not set it\n // (tracked via _managedCurrentItems). This prevents component-managed state\n // from being misread as a consumer override on subsequent slotchange events.\n const hasExplicitCurrent = items.some(\n (el) => el.hasAttribute('current') && !this._managedCurrentItems.has(el),\n );\n\n items.forEach((item, i) => {\n const el = item as HTMLElement;\n const isLast = i === items.length - 1;\n\n // Separator hiding: always positional — last item has no trailing separator.\n if (isLast) {\n el.setAttribute('data-bc-last', '');\n } else {\n el.removeAttribute('data-bc-last');\n }\n\n // Current-page marker: explicit consumer attribute wins over positional last.\n // The item component renders aria-current=\"page\" on its inner element\n // based on this attribute (see hx-breadcrumb-item.ts).\n if (!hasExplicitCurrent) {\n if (isLast) {\n el.setAttribute('current', '');\n this._managedCurrentItems.add(el);\n } else {\n el.removeAttribute('current');\n this._managedCurrentItems.delete(el);\n }\n }\n // When hasExplicitCurrent is true, leave 'current' attributes as-is so\n // consumer or Drupal template markup is not overridden.\n });\n }\n\n // ─── Slot Handling ───\n\n /** @internal */\n private _handleSlotChange(e: Event): void {\n if (!(e.target instanceof HTMLSlotElement)) return;\n const items = this._getBreadcrumbItems(e.target);\n\n // Handle collapse behaviour\n if (this.maxItems > 0 && items.length > this.maxItems) {\n this._applyCollapse(items);\n } else {\n this._removeCollapse(items);\n }\n\n this._applyItemAttributes(items);\n\n if (this.jsonLd) {\n this._updateJsonLd(items);\n }\n }\n\n /** @internal */\n private _handleSeparatorSlotChange(e: Event): void {\n if (!(e.target instanceof HTMLSlotElement)) return;\n const assigned = e.target.assignedElements({ flatten: true });\n if (assigned.length > 0) {\n const text = (assigned[0] as HTMLElement).textContent?.trim() ?? '';\n this.style.setProperty('--hx-breadcrumb-separator-content', JSON.stringify(text));\n }\n }\n\n // ─── Collapse ───\n\n /** @internal */\n private _applyCollapse(items: Element[]): void {\n // Show only first and last; hide all middle items via data attribute.\n // The ellipsis is rendered in shadow DOM (see render()) to avoid mutating\n // the consumer's light DOM structure (FS-014).\n items.forEach((item, i) => {\n const el = item as HTMLElement;\n if (i === 0 || i === items.length - 1) {\n el.removeAttribute('data-bc-hidden');\n } else {\n el.setAttribute('data-bc-hidden', '');\n }\n });\n\n this._showEllipsis = true;\n }\n\n /** @internal */\n private _removeCollapse(items: Element[]): void {\n items.forEach((item) => {\n (item as HTMLElement).removeAttribute('data-bc-hidden');\n });\n\n this._showEllipsis = false;\n }\n\n /**\n * Expands a collapsed breadcrumb by resetting maxItems to 0.\n * Called by the ellipsis expand button (click or Enter/Space).\n * @internal\n */\n private _expandBreadcrumb(): void {\n this.maxItems = 0;\n // updated() will detect the maxItems change and call _removeCollapse.\n }\n\n // ─── JSON-LD ───\n\n /**\n * JSON-LD ListItem entry with typed fields to avoid Record<string, unknown>.\n * @internal\n */\n private _buildListItem(item: Element, position: number): JsonLdListItem {\n const href = (item as HTMLElement).getAttribute('href');\n const name = (item as HTMLElement).textContent?.trim() ?? '';\n const entry: JsonLdListItem = {\n '@type': 'ListItem',\n position,\n name,\n };\n if (href) entry.item = href;\n return entry;\n }\n\n /** @internal */\n private _updateJsonLd(items: Element[]): void {\n const schema = {\n '@context': 'https://schema.org',\n '@type': 'BreadcrumbList',\n itemListElement: items.map((item, i) => this._buildListItem(item, i + 1)),\n };\n\n // Guard for SSR — document is unavailable server-side\n if (typeof document === 'undefined') return;\n\n if (!this._jsonLdScript) {\n // Dedup guard: remove any stale script with this instance's ID before\n // creating a fresh one. This handles the edge case where the element was\n // reconnected to the DOM after being disconnected without the script\n // reference being re-established.\n document.getElementById(this._jsonLdId)?.remove();\n\n this._jsonLdScript = document.createElement('script');\n this._jsonLdScript.type = 'application/ld+json';\n this._jsonLdScript.id = this._jsonLdId;\n this._jsonLdScript.setAttribute('data-hx-breadcrumb', '');\n document.head.appendChild(this._jsonLdScript);\n }\n\n this._jsonLdScript.textContent = JSON.stringify(schema);\n }\n\n /** @internal */\n private _removeJsonLd(): void {\n this._jsonLdScript?.remove();\n this._jsonLdScript = null;\n }\n\n // ─── Lifecycle ───\n\n override connectedCallback(): void {\n super.connectedCallback();\n // Do NOT set role=\"list\" on the host. The shadow-DOM <nav><ol> provides\n // both navigation landmark and list semantics. Setting role=\"list\" on\n // the host conflicts with the <nav> child — axe-core flags\n // aria-required-children because a list cannot own a navigation landmark.\n // Slotted items no longer need role=\"listitem\" either; the native <ol>\n // handles list semantics in the composed accessibility tree.\n }\n\n override disconnectedCallback(): void {\n super.disconnectedCallback();\n this._removeJsonLd();\n }\n\n override updated(changedProperties: PropertyValues<this>): void {\n super.updated(changedProperties);\n\n if (changedProperties.has('separator')) {\n // JSON.stringify wraps the string in quotes so the value is valid\n // for use in the CSS `content` property (e.g. '/' becomes '\"/\"').\n this.style.setProperty('--hx-breadcrumb-separator-content', JSON.stringify(this.separator));\n }\n\n if (changedProperties.has('maxItems')) {\n // Re-evaluate collapse state when maxItems changes programmatically\n // (e.g. when the expand button resets maxItems to 0).\n const slot = this.shadowRoot?.querySelector<HTMLSlotElement>('slot:not([name])');\n if (slot) {\n const items = this._getBreadcrumbItems(slot);\n if (this.maxItems > 0 && items.length > this.maxItems) {\n this._applyCollapse(items);\n } else {\n this._removeCollapse(items);\n }\n this._applyItemAttributes(items);\n }\n }\n\n if (changedProperties.has('jsonLd')) {\n if (this.jsonLd) {\n // json-ld toggled on after initial render — inject script immediately.\n const slot = this.shadowRoot?.querySelector<HTMLSlotElement>('slot:not([name])');\n if (slot) {\n this._updateJsonLd(this._getBreadcrumbItems(slot));\n }\n } else {\n // json-ld toggled off — remove existing script.\n this._removeJsonLd();\n }\n }\n }\n\n // ─── Render ───\n\n override render() {\n return html`\n <nav part=\"nav\" aria-label=${this.label}>\n <ol part=\"list\">\n <slot @slotchange=${this._handleSlotChange}></slot>\n ${this._showEllipsis\n ? html`\n <hx-breadcrumb-item class=\"hx-bc-ellipsis\">\n <button\n type=\"button\"\n aria-label=${this.labelEllipsis}\n @click=${this._expandBreadcrumb}\n >\n …\n </button>\n </hx-breadcrumb-item>\n `\n : nothing}\n </ol>\n </nav>\n <slot\n name=\"separator\"\n class=\"separator-slot\"\n @slotchange=${this._handleSeparatorSlotChange}\n ></slot>\n `;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'hx-breadcrumb': HelixBreadcrumb;\n }\n}\n","import { css } from 'lit';\n\nexport const helixBreadcrumbItemStyles = css`\n :host {\n display: inline-flex;\n align-items: center;\n }\n\n /*\n * display: contents removes [part='item'] from the box model entirely.\n * This is intentional — the wrapper exists only for slot selection purposes.\n * Consumers using ::part(item) CANNOT apply box-model properties (padding,\n * margin, background, border) to this part. Use ::part(link) or ::part(text)\n * for visual styling of breadcrumb item content.\n */\n [part='item'] {\n display: contents;\n }\n\n [part='link'] {\n color: var(--hx-breadcrumb-link-color, var(--hx-color-primary-600, #0f7078));\n text-decoration: none;\n cursor: pointer;\n font-family: inherit;\n font-size: inherit;\n max-width: var(--hx-breadcrumb-item-max-width);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n }\n\n [part='link']:hover {\n color: var(--hx-breadcrumb-link-hover-color, var(--hx-color-primary-700, #0f6363));\n text-decoration: underline;\n }\n\n [part='link']:focus-visible {\n outline: var(--hx-focus-ring-width, 2px) solid\n var(\n --hx-breadcrumb-link-focus-ring-color,\n var(--hx-focus-ring-color, var(--hx-color-primary-500, #429797))\n );\n outline-offset: var(--hx-focus-ring-offset, 2px);\n border-radius: var(--hx-border-radius-sm, 0.25rem);\n }\n\n [part='text'] {\n color: var(--hx-breadcrumb-text-color, var(--hx-color-text-strong, #202b39));\n font-family: inherit;\n font-size: inherit;\n max-width: var(--hx-breadcrumb-item-max-width);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n }\n\n .separator {\n margin-inline: var(--hx-breadcrumb-separator-gap, var(--hx-space-1, 0.25rem));\n color: var(--hx-breadcrumb-separator-color, var(--hx-color-text-muted, #4a5362));\n user-select: none;\n }\n\n .separator::before {\n content: var(--hx-breadcrumb-separator-content, '/');\n }\n\n /* Normalize buttons slotted into breadcrumb items (e.g. the expand-ellipsis button). */\n ::slotted(button) {\n background: none;\n border: none;\n cursor: pointer;\n font: inherit;\n color: inherit;\n padding: 0;\n }\n\n /* ─── Forced Colors (Windows High Contrast) ─── */\n\n @media (forced-colors: active) {\n [part='link'] {\n color: LinkText;\n }\n\n [part='link']:hover {\n color: LinkText;\n }\n\n .separator {\n color: CanvasText;\n }\n }\n`;\n","import { html, nothing } from 'lit';\nimport '../../utilities/document-token-adoption.js';\nimport { customElement, property } from 'lit/decorators.js';\nimport { HelixElement } from '../../base/index.js';\nimport { forcedColorsInteractive } from '../../styles/forced-colors.js';\nimport { helixBreadcrumbItemStyles } from './hx-breadcrumb-item.styles.js';\n\n/**\n * A single breadcrumb navigation item.\n *\n * @summary A navigation item within an hx-breadcrumb component. Renders as a link when `href` is\n * provided, or as static text for the current page item. The current page item is determined by\n * the `current` attribute (set explicitly or automatically by the parent `hx-breadcrumb`).\n *\n * @tag hx-breadcrumb-item\n *\n * @slot - The link or page text content. Accepts text, HTML, or icon elements.\n *\n * @csspart item - Wrapper around the link or text content.\n * @csspart link - The anchor element when href is provided (non-current items only).\n * @csspart text - The span element for the current page or items without href.\n * @csspart separator - The separator element rendered after non-last items.\n *\n * @cssprop [--hx-breadcrumb-link-color=var(--hx-color-primary-600)] - Link text color.\n * @cssprop [--hx-breadcrumb-link-hover-color=var(--hx-color-primary-700)] - Link hover text color.\n * @cssprop [--hx-breadcrumb-text-color=var(--hx-color-neutral-700)] - Current page text color.\n * @cssprop [--hx-breadcrumb-separator-content='/'] - Separator character displayed after non-last items.\n * @cssprop [--hx-breadcrumb-separator-color=var(--hx-color-neutral-400)] - Separator color.\n * @cssprop [--hx-breadcrumb-separator-gap=var(--hx-space-1)] - Horizontal margin around separator.\n * @cssprop [--hx-breadcrumb-item-max-width] - Optional max-width for text truncation.\n * @cssprop [--hx-breadcrumb-link-focus-ring-color=var(--hx-focus-ring-color, var(--hx-color-primary-500))] - Focus ring color for breadcrumb links.\n */\n@customElement('hx-breadcrumb-item')\nexport class HelixBreadcrumbItem extends HelixElement {\n static override styles = [helixBreadcrumbItemStyles, forcedColorsInteractive];\n\n override connectedCallback(): void {\n super.connectedCallback();\n // No explicit role needed. The shadow-DOM <ol> inside hx-breadcrumb\n // provides native list semantics; slotted items are projected into it.\n // Previously role=\"listitem\" was set here, but it conflicted with the\n // host's role=\"list\" + shadow-DOM <nav> structure (aria-required-children).\n // The native <ol> handles the accessibility tree correctly without\n // explicit ARIA roles on host or items.\n }\n\n /**\n * The URL for this breadcrumb link. Omit for the current page item.\n * When `current` is true, this attribute is ignored and the item always\n * renders as static text per WAI-ARIA APG breadcrumb guidance.\n * @attr href\n */\n @property({ type: String, reflect: true })\n href: string | undefined = undefined;\n\n /**\n * Whether this is the last item in the breadcrumb trail. Set by the parent\n * hx-breadcrumb component via the `data-bc-last` boolean attribute. When\n * present the trailing separator is hidden.\n *\n * @attr data-bc-last\n * @internal\n */\n @property({ type: Boolean, attribute: 'data-bc-last', reflect: true })\n dataBcLast = false;\n\n /**\n * Marks this item as the current page. When set, the item always renders as\n * static text (never a navigable link) and `aria-current=\"page\"` is placed on\n * the inner text element per WAI-ARIA APG breadcrumb guidance, yielding the\n * canonical AT announcement (\"current page, Patient Records\").\n *\n * Can be set explicitly by consumers (e.g. Drupal Twig templates) to override\n * the default positional last-item detection in `hx-breadcrumb`. When any item\n * in the breadcrumb has an explicit `current` attribute, the parent will not\n * override it.\n *\n * @attr current\n */\n @property({ type: Boolean, reflect: true })\n current = false;\n\n override render() {\n // Per WAI-ARIA APG, the current page item MUST NOT be a navigable link.\n // aria-current=\"page\" is placed on the inner element (not the listitem host)\n // for canonical AT announcement (\"current page, Patient Records\" vs\n // \"current page, list item\").\n return html`\n <span part=\"item\">\n ${this.current\n ? html`<span part=\"text\" aria-current=\"page\"><slot></slot></span>`\n : this.href\n ? html`<a part=\"link\" href=${this.href}><slot></slot></a>`\n : html`<span part=\"text\"><slot></slot></span>`}\n </span>\n ${!this.dataBcLast\n ? html`<span class=\"separator\" part=\"separator\" aria-hidden=\"true\"></span>`\n : nothing}\n `;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'hx-breadcrumb-item': HelixBreadcrumbItem;\n }\n}\n"],"names":["helixBreadcrumbStyles","css","_nextBreadcrumbId","createIdCounter","HelixBreadcrumb","HelixElement","slot","el","items","hasExplicitCurrent","item","i","isLast","e","assigned","text","_a","position","href","name","entry","schema","changedProperties","_b","html","nothing","forcedColorsInteractive","__decorateClass","property","state","customElement","helixBreadcrumbItemStyles","HelixBreadcrumbItem"],"mappings":"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"}
1
+ {"version":3,"file":"hx-breadcrumb-item-3tKppF9h.js","sources":["../../src/components/hx-breadcrumb/hx-breadcrumb.styles.ts","../../src/components/hx-breadcrumb/hx-breadcrumb.ts","../../src/components/hx-breadcrumb/hx-breadcrumb-item.styles.ts","../../src/components/hx-breadcrumb/hx-breadcrumb-item.ts"],"sourcesContent":["import { css } from 'lit';\n\nexport const helixBreadcrumbStyles = css`\n :host {\n display: block;\n font-family: var(\n --hx-breadcrumb-font-family,\n var(--hx-font-family-sans, system-ui, sans-serif)\n );\n font-size: var(--hx-breadcrumb-font-size, var(--hx-font-size-sm, 0.875rem));\n }\n\n [part='nav'] {\n /* nav landmark — no additional styling needed */\n }\n\n [part='list'] {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n list-style: none;\n margin: 0;\n padding: 0;\n gap: 0;\n }\n\n /* Hide middle items when collapsed via maxItems */\n ::slotted([data-bc-hidden]) {\n display: none;\n }\n\n /*\n * Ellipsis ordering when collapsed (FS-014 fix):\n * The ellipsis <hx-breadcrumb-item> lives in shadow DOM to avoid mutating\n * the consumer's light DOM. CSS order places it between the first item\n * (order: 0, default) and the last item (order: 2) in the flex <ol>.\n */\n .hx-bc-ellipsis {\n order: 1;\n }\n\n ::slotted([data-bc-last]) {\n order: 2;\n }\n\n /* Visually hide the separator slot — used only to read text content.\n * display:none is intentional: the slot contains no interactive or focusable\n * content. If a future change adds focusable elements to this slot, switch to\n * visibility:hidden + position:absolute to preserve focus reachability. */\n .separator-slot {\n display: none;\n }\n\n /* ─── High Contrast Mode (forced-colors) ─── */\n\n /*\n * hx-breadcrumb is a nav container. Link colors and separators are handled\n * by hx-breadcrumb-item's own forced-colors block. No additional overrides needed\n * at the container level.\n */\n @media (forced-colors: active) {\n :host {\n forced-color-adjust: auto;\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 { forcedColorsInteractive } from '../../styles/forced-colors.js';\nimport { helixBreadcrumbStyles } from './hx-breadcrumb.styles.js';\n\n/** Typed schema.org ListItem entry for JSON-LD BreadcrumbList structured data. */\ninterface JsonLdListItem {\n '@type': string;\n position: number;\n name: string;\n item?: string;\n}\n\nconst _nextBreadcrumbId = createIdCounter('hx-breadcrumb');\n\n/**\n * Hierarchical page path navigation showing current location in site structure.\n *\n * @summary Navigation breadcrumb showing the page hierarchy. Works with Drupal's breadcrumb system.\n *\n * @tag hx-breadcrumb\n *\n * @slot - Default slot for hx-breadcrumb-item children.\n * @slot separator - Optional separator element. Its text content overrides the `separator` property.\n *\n * @csspart nav - The nav landmark element.\n * @csspart list - The ordered list containing items.\n *\n * @cssprop [--hx-breadcrumb-separator-content='/'] - Separator character between items.\n * NOTE: If overriding this custom property directly in CSS (rather than via the `separator`\n * attribute), the value MUST be quoted: `--hx-breadcrumb-separator-content: \">\"`. An unquoted\n * value is invalid for the CSS `content` property and will silently render nothing.\n * @cssprop [--hx-breadcrumb-separator-color=var(--hx-color-neutral-400)] - Separator color.\n * @cssprop [--hx-breadcrumb-separator-gap=var(--hx-space-1)] - Horizontal gap around separators.\n * @cssprop [--hx-breadcrumb-font-size=var(--hx-font-size-sm)] - Font size.\n * @cssprop [--hx-breadcrumb-link-color=var(--hx-color-primary-600)] - Link color.\n * @cssprop [--hx-breadcrumb-link-hover-color=var(--hx-color-primary-700)] - Link hover color.\n * @cssprop [--hx-breadcrumb-text-color=var(--hx-color-neutral-700)] - Current page text color.\n * @cssprop [--hx-breadcrumb-item-max-width] - Max-width for item text truncation (e.g. `12rem`).\n * @cssprop [--hx-breadcrumb-font-family] - CSS custom property.\n * @cssprop [--hx-font-family-sans] - Font family.\n * @cssprop [--hx-font-size-sm] - Font size.\n */\n@customElement('hx-breadcrumb')\nexport class HelixBreadcrumb extends HelixElement {\n static override styles = [helixBreadcrumbStyles, forcedColorsInteractive];\n\n /**\n * The separator character displayed between breadcrumb items.\n * @attr separator\n */\n @property({ type: String })\n separator = '/';\n\n /**\n * The accessible label for the nav landmark.\n * @attr label\n */\n @property({ type: String })\n label = 'Breadcrumb';\n\n /**\n * Maximum number of items to show before collapsing middle items with an ellipsis.\n * Set to 0 (default) to show all items. The ellipsis is a keyboard-accessible\n * button; activating it expands the full breadcrumb by setting maxItems to 0.\n * @attr max-items\n */\n @property({ type: Number, attribute: 'max-items' })\n maxItems = 0;\n\n /**\n * Accessible label for the expand ellipsis button. Override for i18n.\n * @attr label-ellipsis\n */\n @property({ attribute: 'label-ellipsis' }) labelEllipsis = 'Show all breadcrumb items';\n\n /**\n * When true, injects a JSON-LD BreadcrumbList structured data script into the document head.\n *\n * NOTE: Drupal manages `<head>` content via its own render pipeline. Injecting a\n * `<script>` directly via `document.head.appendChild()` in a Drupal context:\n * 1. Bypasses Drupal's deduplication and `hook_html_head_alter()` hook.\n * 2. Is not cacheable by Drupal's page cache.\n * 3. Will be wiped on BigPipe partial page replacements.\n *\n * For Drupal integrations, leave `json-ld` false and use the structured data\n * Twig template instead (see `hx-breadcrumb.twig` in the component directory).\n *\n * @attr json-ld\n */\n @property({ type: Boolean, attribute: 'json-ld' })\n jsonLd = false;\n\n /**\n * Whether the ellipsis expand button is currently shown (shadow DOM rendered).\n * Driven by maxItems collapse logic; replaces the old light-DOM ellipsis injection.\n * @internal\n */\n @state() private _showEllipsis = false;\n /** @internal */\n private _jsonLdScript: HTMLScriptElement | null = null;\n\n /**\n * Tracks which items had their `current` attribute set by this component\n * (as opposed to set by a consumer/Drupal template). This lets us re-evaluate\n * positional current-page detection on each slotchange without incorrectly\n * treating a previously component-set `current` attribute as a consumer-set\n * explicit override.\n * @internal\n */\n private readonly _managedCurrentItems = new WeakSet<Element>();\n\n /**\n * Stable per-instance ID used to tag the injected script element so that\n * multiple hx-breadcrumb instances on the same page don't produce conflicting\n * or duplicate structured-data blocks. Each instance owns exactly one script\n * tag identified by this ID; any stale tag from a previous render cycle is\n * removed before a new one is inserted.\n *\n * Uses a static counter (not Math.random()) so IDs are deterministic across\n * server and client renders, enabling SSR hydration matching.\n * @internal\n */\n private readonly _jsonLdId = `${_nextBreadcrumbId()}-ld`;\n\n // ─── Item Helpers ───\n\n /**\n * Returns only real breadcrumb items, excluding the managed ellipsis element.\n * @internal\n */\n private _getBreadcrumbItems(slot: HTMLSlotElement): Element[] {\n return slot\n .assignedElements({ flatten: true })\n .filter(\n (el) =>\n el.tagName.toLowerCase() === 'hx-breadcrumb-item' &&\n !el.classList.contains('hx-bc-ellipsis'),\n );\n }\n\n /**\n * Applies aria/state attributes to the item list.\n *\n * Current-page detection: if any item has an explicit `current` attribute\n * (e.g. set by a Drupal Twig template), that item is treated as the current\n * page. Otherwise the last item is the current page (default behaviour).\n *\n * This separation allows Drupal to control current-page marking without\n * relying on item order.\n * @internal\n */\n private _applyItemAttributes(items: Element[]): void {\n // Detect consumer-set 'current' attributes. An item has an explicit consumer\n // current if it has the 'current' attribute AND the component did not set it\n // (tracked via _managedCurrentItems). This prevents component-managed state\n // from being misread as a consumer override on subsequent slotchange events.\n const hasExplicitCurrent = items.some(\n (el) => el.hasAttribute('current') && !this._managedCurrentItems.has(el),\n );\n\n items.forEach((item, i) => {\n const el = item as HTMLElement;\n const isLast = i === items.length - 1;\n\n // Separator hiding: always positional — last item has no trailing separator.\n if (isLast) {\n el.setAttribute('data-bc-last', '');\n } else {\n el.removeAttribute('data-bc-last');\n }\n\n // Current-page marker: explicit consumer attribute wins over positional last.\n // The item component renders aria-current=\"page\" on its inner element\n // based on this attribute (see hx-breadcrumb-item.ts).\n if (!hasExplicitCurrent) {\n if (isLast) {\n el.setAttribute('current', '');\n this._managedCurrentItems.add(el);\n } else {\n el.removeAttribute('current');\n this._managedCurrentItems.delete(el);\n }\n }\n // When hasExplicitCurrent is true, leave 'current' attributes as-is so\n // consumer or Drupal template markup is not overridden.\n });\n }\n\n // ─── Slot Handling ───\n\n /** @internal */\n private _handleSlotChange(e: Event): void {\n if (!(e.target instanceof HTMLSlotElement)) return;\n const items = this._getBreadcrumbItems(e.target);\n\n // Handle collapse behaviour\n if (this.maxItems > 0 && items.length > this.maxItems) {\n this._applyCollapse(items);\n } else {\n this._removeCollapse(items);\n }\n\n this._applyItemAttributes(items);\n\n if (this.jsonLd) {\n this._updateJsonLd(items);\n }\n }\n\n /** @internal */\n private _handleSeparatorSlotChange(e: Event): void {\n if (!(e.target instanceof HTMLSlotElement)) return;\n const assigned = e.target.assignedElements({ flatten: true });\n if (assigned.length > 0) {\n const text = (assigned[0] as HTMLElement).textContent?.trim() ?? '';\n this.style.setProperty('--hx-breadcrumb-separator-content', JSON.stringify(text));\n }\n }\n\n // ─── Collapse ───\n\n /** @internal */\n private _applyCollapse(items: Element[]): void {\n // Show only first and last; hide all middle items via data attribute.\n // The ellipsis is rendered in shadow DOM (see render()) to avoid mutating\n // the consumer's light DOM structure (FS-014).\n items.forEach((item, i) => {\n const el = item as HTMLElement;\n if (i === 0 || i === items.length - 1) {\n el.removeAttribute('data-bc-hidden');\n } else {\n el.setAttribute('data-bc-hidden', '');\n }\n });\n\n this._showEllipsis = true;\n }\n\n /** @internal */\n private _removeCollapse(items: Element[]): void {\n items.forEach((item) => {\n (item as HTMLElement).removeAttribute('data-bc-hidden');\n });\n\n this._showEllipsis = false;\n }\n\n /**\n * Expands a collapsed breadcrumb by resetting maxItems to 0.\n * Called by the ellipsis expand button (click or Enter/Space).\n * @internal\n */\n private _expandBreadcrumb(): void {\n this.maxItems = 0;\n // updated() will detect the maxItems change and call _removeCollapse.\n }\n\n // ─── JSON-LD ───\n\n /**\n * JSON-LD ListItem entry with typed fields to avoid Record<string, unknown>.\n * @internal\n */\n private _buildListItem(item: Element, position: number): JsonLdListItem {\n const href = (item as HTMLElement).getAttribute('href');\n const name = (item as HTMLElement).textContent?.trim() ?? '';\n const entry: JsonLdListItem = {\n '@type': 'ListItem',\n position,\n name,\n };\n if (href) entry.item = href;\n return entry;\n }\n\n /** @internal */\n private _updateJsonLd(items: Element[]): void {\n const schema = {\n '@context': 'https://schema.org',\n '@type': 'BreadcrumbList',\n itemListElement: items.map((item, i) => this._buildListItem(item, i + 1)),\n };\n\n // Guard for SSR — document is unavailable server-side\n if (typeof document === 'undefined') return;\n\n if (!this._jsonLdScript) {\n // Dedup guard: remove any stale script with this instance's ID before\n // creating a fresh one. This handles the edge case where the element was\n // reconnected to the DOM after being disconnected without the script\n // reference being re-established.\n document.getElementById(this._jsonLdId)?.remove();\n\n this._jsonLdScript = document.createElement('script');\n this._jsonLdScript.type = 'application/ld+json';\n this._jsonLdScript.id = this._jsonLdId;\n this._jsonLdScript.setAttribute('data-hx-breadcrumb', '');\n document.head.appendChild(this._jsonLdScript);\n }\n\n this._jsonLdScript.textContent = JSON.stringify(schema);\n }\n\n /** @internal */\n private _removeJsonLd(): void {\n this._jsonLdScript?.remove();\n this._jsonLdScript = null;\n }\n\n // ─── Lifecycle ───\n\n override connectedCallback(): void {\n super.connectedCallback();\n // Do NOT set role=\"list\" on the host. The shadow-DOM <nav><ol> provides\n // both navigation landmark and list semantics. Setting role=\"list\" on\n // the host conflicts with the <nav> child — axe-core flags\n // aria-required-children because a list cannot own a navigation landmark.\n // Slotted items no longer need role=\"listitem\" either; the native <ol>\n // handles list semantics in the composed accessibility tree.\n }\n\n override disconnectedCallback(): void {\n super.disconnectedCallback();\n this._removeJsonLd();\n }\n\n override updated(changedProperties: PropertyValues<this>): void {\n super.updated(changedProperties);\n\n if (changedProperties.has('separator')) {\n // JSON.stringify wraps the string in quotes so the value is valid\n // for use in the CSS `content` property (e.g. '/' becomes '\"/\"').\n this.style.setProperty('--hx-breadcrumb-separator-content', JSON.stringify(this.separator));\n }\n\n if (changedProperties.has('maxItems')) {\n // Re-evaluate collapse state when maxItems changes programmatically\n // (e.g. when the expand button resets maxItems to 0).\n const slot = this.shadowRoot?.querySelector<HTMLSlotElement>('slot:not([name])');\n if (slot) {\n const items = this._getBreadcrumbItems(slot);\n if (this.maxItems > 0 && items.length > this.maxItems) {\n this._applyCollapse(items);\n } else {\n this._removeCollapse(items);\n }\n this._applyItemAttributes(items);\n }\n }\n\n if (changedProperties.has('jsonLd')) {\n if (this.jsonLd) {\n // json-ld toggled on after initial render — inject script immediately.\n const slot = this.shadowRoot?.querySelector<HTMLSlotElement>('slot:not([name])');\n if (slot) {\n this._updateJsonLd(this._getBreadcrumbItems(slot));\n }\n } else {\n // json-ld toggled off — remove existing script.\n this._removeJsonLd();\n }\n }\n }\n\n // ─── Render ───\n\n override render() {\n return html`\n <nav part=\"nav\" aria-label=${this.label}>\n <ol part=\"list\">\n <slot @slotchange=${this._handleSlotChange}></slot>\n ${this._showEllipsis\n ? html`\n <hx-breadcrumb-item class=\"hx-bc-ellipsis\">\n <button\n type=\"button\"\n aria-label=${this.labelEllipsis}\n @click=${this._expandBreadcrumb}\n >\n …\n </button>\n </hx-breadcrumb-item>\n `\n : nothing}\n </ol>\n </nav>\n <slot\n name=\"separator\"\n class=\"separator-slot\"\n @slotchange=${this._handleSeparatorSlotChange}\n ></slot>\n `;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'hx-breadcrumb': HelixBreadcrumb;\n }\n}\n","import { css } from 'lit';\n\nexport const helixBreadcrumbItemStyles = css`\n :host {\n display: inline-flex;\n align-items: center;\n }\n\n /*\n * display: contents removes [part='item'] from the box model entirely.\n * This is intentional — the wrapper exists only for slot selection purposes.\n * Consumers using ::part(item) CANNOT apply box-model properties (padding,\n * margin, background, border) to this part. Use ::part(link) or ::part(text)\n * for visual styling of breadcrumb item content.\n */\n [part='item'] {\n display: contents;\n }\n\n [part='link'] {\n color: var(--hx-breadcrumb-link-color, var(--hx-color-primary-600, #0f7078));\n text-decoration: none;\n cursor: pointer;\n font-family: inherit;\n font-size: inherit;\n max-width: var(--hx-breadcrumb-item-max-width);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n }\n\n [part='link']:hover {\n color: var(--hx-breadcrumb-link-hover-color, var(--hx-color-primary-700, #0f6363));\n text-decoration: underline;\n }\n\n [part='link']:focus-visible {\n outline: var(--hx-focus-ring-width, 2px) solid\n var(--hx-breadcrumb-link-focus-ring-color, 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 [part='text'] {\n color: var(--hx-breadcrumb-text-color, var(--hx-color-text-strong, #202b39));\n font-family: inherit;\n font-size: inherit;\n max-width: var(--hx-breadcrumb-item-max-width);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n }\n\n .separator {\n margin-inline: var(--hx-breadcrumb-separator-gap, var(--hx-space-1, 0.25rem));\n color: var(--hx-breadcrumb-separator-color, var(--hx-color-text-muted, #4a5362));\n user-select: none;\n }\n\n .separator::before {\n content: var(--hx-breadcrumb-separator-content, '/');\n }\n\n /* Normalize buttons slotted into breadcrumb items (e.g. the expand-ellipsis button). */\n ::slotted(button) {\n background: none;\n border: none;\n cursor: pointer;\n font: inherit;\n color: inherit;\n padding: 0;\n }\n\n /* ─── Forced Colors (Windows High Contrast) ─── */\n\n @media (forced-colors: active) {\n [part='link'] {\n color: LinkText;\n }\n\n [part='link']:hover {\n color: LinkText;\n }\n\n .separator {\n color: CanvasText;\n }\n }\n`;\n","import { html, nothing } from 'lit';\nimport '../../utilities/document-token-adoption.js';\nimport { customElement, property } from 'lit/decorators.js';\nimport { HelixElement } from '../../base/index.js';\nimport { forcedColorsInteractive } from '../../styles/forced-colors.js';\nimport { helixBreadcrumbItemStyles } from './hx-breadcrumb-item.styles.js';\n\n/**\n * A single breadcrumb navigation item.\n *\n * @summary A navigation item within an hx-breadcrumb component. Renders as a link when `href` is\n * provided, or as static text for the current page item. The current page item is determined by\n * the `current` attribute (set explicitly or automatically by the parent `hx-breadcrumb`).\n *\n * @tag hx-breadcrumb-item\n *\n * @slot - The link or page text content. Accepts text, HTML, or icon elements.\n *\n * @csspart item - Wrapper around the link or text content.\n * @csspart link - The anchor element when href is provided (non-current items only).\n * @csspart text - The span element for the current page or items without href.\n * @csspart separator - The separator element rendered after non-last items.\n *\n * @cssprop [--hx-breadcrumb-link-color=var(--hx-color-primary-600)] - Link text color.\n * @cssprop [--hx-breadcrumb-link-hover-color=var(--hx-color-primary-700)] - Link hover text color.\n * @cssprop [--hx-breadcrumb-text-color=var(--hx-color-neutral-700)] - Current page text color.\n * @cssprop [--hx-breadcrumb-separator-content='/'] - Separator character displayed after non-last items.\n * @cssprop [--hx-breadcrumb-separator-color=var(--hx-color-neutral-400)] - Separator color.\n * @cssprop [--hx-breadcrumb-separator-gap=var(--hx-space-1)] - Horizontal margin around separator.\n * @cssprop [--hx-breadcrumb-item-max-width] - Optional max-width for text truncation.\n * @cssprop [--hx-breadcrumb-link-focus-ring-color=var(--hx-focus-ring-color, var(--hx-color-primary-500))] - Focus ring color for breadcrumb links.\n */\n@customElement('hx-breadcrumb-item')\nexport class HelixBreadcrumbItem extends HelixElement {\n static override styles = [helixBreadcrumbItemStyles, forcedColorsInteractive];\n\n override connectedCallback(): void {\n super.connectedCallback();\n // No explicit role needed. The shadow-DOM <ol> inside hx-breadcrumb\n // provides native list semantics; slotted items are projected into it.\n // Previously role=\"listitem\" was set here, but it conflicted with the\n // host's role=\"list\" + shadow-DOM <nav> structure (aria-required-children).\n // The native <ol> handles the accessibility tree correctly without\n // explicit ARIA roles on host or items.\n }\n\n /**\n * The URL for this breadcrumb link. Omit for the current page item.\n * When `current` is true, this attribute is ignored and the item always\n * renders as static text per WAI-ARIA APG breadcrumb guidance.\n * @attr href\n */\n @property({ type: String, reflect: true })\n href: string | undefined = undefined;\n\n /**\n * Whether this is the last item in the breadcrumb trail. Set by the parent\n * hx-breadcrumb component via the `data-bc-last` boolean attribute. When\n * present the trailing separator is hidden.\n *\n * @attr data-bc-last\n * @internal\n */\n @property({ type: Boolean, attribute: 'data-bc-last', reflect: true })\n dataBcLast = false;\n\n /**\n * Marks this item as the current page. When set, the item always renders as\n * static text (never a navigable link) and `aria-current=\"page\"` is placed on\n * the inner text element per WAI-ARIA APG breadcrumb guidance, yielding the\n * canonical AT announcement (\"current page, Patient Records\").\n *\n * Can be set explicitly by consumers (e.g. Drupal Twig templates) to override\n * the default positional last-item detection in `hx-breadcrumb`. When any item\n * in the breadcrumb has an explicit `current` attribute, the parent will not\n * override it.\n *\n * @attr current\n */\n @property({ type: Boolean, reflect: true })\n current = false;\n\n override render() {\n // Per WAI-ARIA APG, the current page item MUST NOT be a navigable link.\n // aria-current=\"page\" is placed on the inner element (not the listitem host)\n // for canonical AT announcement (\"current page, Patient Records\" vs\n // \"current page, list item\").\n return html`\n <span part=\"item\">\n ${this.current\n ? html`<span part=\"text\" aria-current=\"page\"><slot></slot></span>`\n : this.href\n ? html`<a part=\"link\" href=${this.href}><slot></slot></a>`\n : html`<span part=\"text\"><slot></slot></span>`}\n </span>\n ${!this.dataBcLast\n ? html`<span class=\"separator\" part=\"separator\" aria-hidden=\"true\"></span>`\n : nothing}\n `;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'hx-breadcrumb-item': HelixBreadcrumbItem;\n }\n}\n"],"names":["helixBreadcrumbStyles","css","_nextBreadcrumbId","createIdCounter","HelixBreadcrumb","HelixElement","slot","el","items","hasExplicitCurrent","item","i","isLast","e","assigned","text","_a","position","href","name","entry","schema","changedProperties","_b","html","nothing","forcedColorsInteractive","__decorateClass","property","state","customElement","helixBreadcrumbItemStyles","HelixBreadcrumbItem"],"mappings":"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"}
@@ -53,7 +53,7 @@ const m = v`
53
53
 
54
54
  .button:focus-visible {
55
55
  outline: var(--hx-focus-ring-width, 2px) solid
56
- var(--hx-button-focus-ring-color, var(--hx-focus-ring-color, #6ab1b1));
56
+ var(--hx-button-focus-ring-color, var(--hx-focus-ring-color, #0f7078));
57
57
  outline-offset: var(--hx-focus-ring-offset, 2px);
58
58
  }
59
59
 
@@ -167,7 +167,7 @@ const m = v`
167
167
  .button--outline {
168
168
  --hx-button-bg: transparent;
169
169
  --hx-button-color: var(--hx-color-text-primary, #0d1825);
170
- --hx-button-border-color: var(--hx-color-border-strong, #8e9c98);
170
+ --hx-button-border-color: var(--hx-color-border-strong, #66787b);
171
171
  }
172
172
 
173
173
  .button--outline:hover {
@@ -260,6 +260,16 @@ const m = v`
260
260
  );
261
261
  }
262
262
 
263
+ /* Primary inverted — resting bg routes through action.primary.bg-inverted-rest
264
+ so dark mode can flip the fill to primary-600. surface.inverse becomes light
265
+ (#EBEEE9) in dark mode; primary-500 on #EBEEE9 = 2.94:1 (sub-3:1 UI floor
266
+ fail for the inverted-button boundary). primary-600 on #EBEEE9 = 4.97:1
267
+ (AA pass). Light mode tracks action.primary.bg (primary-500, 5.20:1 on
268
+ dark surface.inverse). */
269
+ :host([inverted]) .button--primary {
270
+ --hx-button-bg: var(--hx-color-action-primary-bg-inverted-rest, #429797);
271
+ }
272
+
263
273
  /* Primary inverted — hover/pressed lift to action.primary.bg-inverted-hover
264
274
  (primary-400, light teal). The base :host([inverted]) .button rule binds
265
275
  color to text.inverse, which flips by mode (neutral-0 in light, neutral-900
@@ -612,4 +622,4 @@ e = n([
612
622
  export {
613
623
  e as H
614
624
  };
615
- //# sourceMappingURL=hx-button-ebUV8KhT.js.map
625
+ //# sourceMappingURL=hx-button-D3gC-OJb.js.map