@helixui/library 3.3.1-next.118 → 3.4.0-next.121
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.
- package/custom-elements.json +422 -322
- package/dist/components/hx-alert/hx-alert.d.ts +11 -0
- package/dist/components/hx-alert/hx-alert.d.ts.map +1 -1
- package/dist/components/hx-alert/hx-alert.styles.d.ts.map +1 -1
- package/dist/components/hx-alert/index.js +1 -1
- package/dist/components/hx-badge/hx-badge.styles.d.ts.map +1 -1
- package/dist/components/hx-badge/index.js +1 -1
- package/dist/components/hx-banner/hx-banner.d.ts +9 -1
- package/dist/components/hx-banner/hx-banner.d.ts.map +1 -1
- package/dist/components/hx-banner/index.js +1 -1
- package/dist/components/hx-button/hx-button.d.ts +11 -1
- package/dist/components/hx-button/hx-button.d.ts.map +1 -1
- package/dist/components/hx-button/index.js +1 -1
- package/dist/components/hx-button-group/hx-button-group.d.ts +13 -0
- package/dist/components/hx-button-group/hx-button-group.d.ts.map +1 -1
- package/dist/components/hx-button-group/index.js +1 -1
- package/dist/components/hx-checkbox/hx-checkbox.d.ts.map +1 -1
- package/dist/components/hx-checkbox/index.js +1 -1
- package/dist/components/hx-checkbox-group/index.js +1 -1
- package/dist/components/hx-color-picker/index.js +1 -1
- package/dist/components/hx-combobox/index.js +1 -1
- package/dist/components/hx-data-table/hx-data-table.d.ts.map +1 -1
- package/dist/components/hx-data-table/index.js +1 -1
- package/dist/components/hx-date-picker/index.js +1 -1
- package/dist/components/hx-dialog/index.js +1 -1
- package/dist/components/hx-drawer/hx-drawer.d.ts +201 -0
- package/dist/components/hx-drawer/hx-drawer.d.ts.map +1 -1
- package/dist/components/hx-drawer/hx-drawer.styles.d.ts.map +1 -1
- package/dist/components/hx-drawer/index.js +1 -1
- package/dist/components/hx-dropdown/hx-dropdown.d.ts +96 -8
- package/dist/components/hx-dropdown/hx-dropdown.d.ts.map +1 -1
- package/dist/components/hx-dropdown/index.js +1 -1
- package/dist/components/hx-icon-button/hx-icon-button.d.ts +16 -3
- package/dist/components/hx-icon-button/hx-icon-button.d.ts.map +1 -1
- package/dist/components/hx-icon-button/hx-icon-button.styles.d.ts.map +1 -1
- package/dist/components/hx-icon-button/index.js +1 -1
- package/dist/components/hx-link/hx-link.d.ts +10 -1
- package/dist/components/hx-link/hx-link.d.ts.map +1 -1
- package/dist/components/hx-link/index.js +1 -1
- package/dist/components/hx-list/hx-list-item.d.ts +27 -1
- package/dist/components/hx-list/hx-list-item.d.ts.map +1 -1
- package/dist/components/hx-list/hx-list.d.ts +28 -0
- package/dist/components/hx-list/hx-list.d.ts.map +1 -1
- package/dist/components/hx-list/index.js +1 -1
- package/dist/components/hx-menu/hx-menu-divider.d.ts +10 -0
- package/dist/components/hx-menu/hx-menu-divider.d.ts.map +1 -1
- package/dist/components/hx-menu/hx-menu-item.d.ts +99 -2
- package/dist/components/hx-menu/hx-menu-item.d.ts.map +1 -1
- package/dist/components/hx-menu/hx-menu-item.styles.d.ts.map +1 -1
- package/dist/components/hx-menu/hx-menu.d.ts +117 -2
- package/dist/components/hx-menu/hx-menu.d.ts.map +1 -1
- package/dist/components/hx-menu/index.js +1 -1
- package/dist/components/hx-meter/hx-meter.d.ts +39 -0
- package/dist/components/hx-meter/hx-meter.d.ts.map +1 -1
- package/dist/components/hx-meter/hx-meter.styles.d.ts.map +1 -1
- package/dist/components/hx-meter/index.js +1 -1
- package/dist/components/hx-overflow-menu/hx-overflow-menu.d.ts +132 -1
- package/dist/components/hx-overflow-menu/hx-overflow-menu.d.ts.map +1 -1
- package/dist/components/hx-overflow-menu/index.js +1 -1
- package/dist/components/hx-phi-field/hx-phi-field.d.ts +0 -1
- package/dist/components/hx-phi-field/hx-phi-field.d.ts.map +1 -1
- package/dist/components/hx-popover/index.js +1 -1
- package/dist/components/hx-progress-bar/hx-progress-bar.d.ts +33 -0
- package/dist/components/hx-progress-bar/hx-progress-bar.d.ts.map +1 -1
- package/dist/components/hx-progress-bar/index.js +1 -1
- package/dist/components/hx-radio-group/index.js +1 -1
- package/dist/components/hx-select/hx-select.d.ts +1 -0
- package/dist/components/hx-select/hx-select.d.ts.map +1 -1
- package/dist/components/hx-select/index.js +1 -1
- package/dist/components/hx-spinner/hx-spinner.d.ts +14 -0
- package/dist/components/hx-spinner/hx-spinner.d.ts.map +1 -1
- package/dist/components/hx-spinner/index.js +1 -1
- package/dist/components/hx-split-button/hx-split-button.d.ts +94 -7
- package/dist/components/hx-split-button/hx-split-button.d.ts.map +1 -1
- package/dist/components/hx-split-button/index.js +1 -1
- package/dist/components/hx-stat/hx-stat.d.ts +28 -0
- package/dist/components/hx-stat/hx-stat.d.ts.map +1 -1
- package/dist/components/hx-stat/index.js +1 -1
- package/dist/components/hx-switch/index.js +1 -1
- package/dist/components/hx-table/hx-td.d.ts +30 -3
- package/dist/components/hx-table/hx-td.d.ts.map +1 -1
- package/dist/components/hx-table/hx-th.d.ts +39 -3
- package/dist/components/hx-table/hx-th.d.ts.map +1 -1
- package/dist/components/hx-table/hx-tr.d.ts +26 -0
- package/dist/components/hx-table/hx-tr.d.ts.map +1 -1
- package/dist/components/hx-table/index.js +1 -1
- package/dist/components/hx-tabs/hx-tab-panel.d.ts +34 -0
- package/dist/components/hx-tabs/hx-tab-panel.d.ts.map +1 -1
- package/dist/components/hx-tabs/hx-tab.d.ts +45 -2
- package/dist/components/hx-tabs/hx-tab.d.ts.map +1 -1
- package/dist/components/hx-tabs/hx-tab.styles.d.ts.map +1 -1
- package/dist/components/hx-tabs/hx-tabs.d.ts +32 -2
- package/dist/components/hx-tabs/hx-tabs.d.ts.map +1 -1
- package/dist/components/hx-tabs/index.js +1 -1
- package/dist/components/hx-tag/hx-tag.styles.d.ts.map +1 -1
- package/dist/components/hx-tag/index.js +1 -1
- package/dist/components/hx-theme/hx-theme.d.ts +10 -5
- package/dist/components/hx-theme/hx-theme.d.ts.map +1 -1
- package/dist/components/hx-time-picker/hx-time-picker.d.ts +210 -2
- package/dist/components/hx-time-picker/hx-time-picker.d.ts.map +1 -1
- package/dist/components/hx-time-picker/hx-time-picker.styles.d.ts.map +1 -1
- package/dist/components/hx-time-picker/index.js +1 -1
- package/dist/components/hx-toast/hx-toast-stack.d.ts +14 -0
- package/dist/components/hx-toast/hx-toast-stack.d.ts.map +1 -1
- package/dist/components/hx-toast/hx-toast.d.ts +22 -3
- package/dist/components/hx-toast/hx-toast.d.ts.map +1 -1
- package/dist/components/hx-toast/index.js +1 -1
- package/dist/components/hx-toast/toast-factory.d.ts.map +1 -1
- package/dist/components/hx-toggle-button/index.js +1 -1
- package/dist/components/hx-tree-view/hx-tree-item.d.ts +117 -12
- package/dist/components/hx-tree-view/hx-tree-item.d.ts.map +1 -1
- package/dist/components/hx-tree-view/hx-tree-view.d.ts +87 -7
- package/dist/components/hx-tree-view/hx-tree-view.d.ts.map +1 -1
- package/dist/components/hx-tree-view/index.js +1 -1
- package/dist/css/helix-all.css +123 -0
- package/dist/css/helix-core.css +81 -0
- package/dist/css/helix-feedback.css +14 -0
- package/dist/css/helix-forms.css +11 -0
- package/dist/css/helix-overlay.css +17 -0
- package/dist/css/hx-alert.css +9 -0
- package/dist/css/hx-badge.css +28 -0
- package/dist/css/hx-drawer.css +17 -0
- package/dist/css/hx-icon-button.css +30 -0
- package/dist/css/hx-meter.css +5 -0
- package/dist/css/hx-tag.css +23 -0
- package/dist/css/hx-time-picker.css +11 -0
- package/dist/css/index.css +1 -1
- package/dist/css/manifest.json +3 -1
- package/dist/index.js +35 -35
- package/dist/shared/aria-idref-CxvyzfQS.js +126 -0
- package/dist/shared/aria-idref-CxvyzfQS.js.map +1 -0
- package/dist/shared/{hx-alert-CLn7CstP.js → hx-alert-Bto8-TIi.js} +55 -37
- package/dist/shared/hx-alert-Bto8-TIi.js.map +1 -0
- package/dist/shared/{hx-badge-CQXgOXJM.js → hx-badge-JlFtAdxS.js} +37 -9
- package/dist/shared/hx-badge-JlFtAdxS.js.map +1 -0
- package/dist/shared/{hx-banner-D3DzpfcP.js → hx-banner-fpRnciIO.js} +13 -5
- package/dist/shared/hx-banner-fpRnciIO.js.map +1 -0
- package/dist/shared/{hx-button-DPY6SPVT.js → hx-button-BOwAEcF1.js} +108 -85
- package/dist/shared/{hx-button-DPY6SPVT.js.map → hx-button-BOwAEcF1.js.map} +1 -1
- package/dist/shared/{hx-button-group-BI-QBqmO.js → hx-button-group-DcHP5MBv.js} +15 -16
- package/dist/shared/{hx-button-group-BI-QBqmO.js.map → hx-button-group-DcHP5MBv.js.map} +1 -1
- package/dist/shared/{hx-checkbox-BdgoUeWi.js → hx-checkbox-C48KYKFq.js} +87 -87
- package/dist/shared/hx-checkbox-C48KYKFq.js.map +1 -0
- package/dist/shared/{hx-checkbox-group-LWezHrvS.js → hx-checkbox-group-BJIAX3zU.js} +2 -2
- package/dist/shared/{hx-checkbox-group-LWezHrvS.js.map → hx-checkbox-group-BJIAX3zU.js.map} +1 -1
- package/dist/shared/{hx-color-picker-DVhZl88b.js → hx-color-picker-Dk4cBwYQ.js} +2 -2
- package/dist/shared/{hx-color-picker-DVhZl88b.js.map → hx-color-picker-Dk4cBwYQ.js.map} +1 -1
- package/dist/shared/{hx-combobox-DvlezcDV.js → hx-combobox-BTLO9qiK.js} +2 -2
- package/dist/shared/{hx-combobox-DvlezcDV.js.map → hx-combobox-BTLO9qiK.js.map} +1 -1
- package/dist/shared/{hx-data-table-CLqVqdxr.js → hx-data-table-Ct3gQ6ya.js} +3 -2
- package/dist/shared/{hx-data-table-CLqVqdxr.js.map → hx-data-table-Ct3gQ6ya.js.map} +1 -1
- package/dist/shared/{hx-date-picker-N-0aG5XL.js → hx-date-picker-CiR7FVnR.js} +2 -2
- package/dist/shared/{hx-date-picker-N-0aG5XL.js.map → hx-date-picker-CiR7FVnR.js.map} +1 -1
- package/dist/shared/{hx-dialog-DzB7VytW.js → hx-dialog-AOZpHSuF.js} +2 -2
- package/dist/shared/{hx-dialog-DzB7VytW.js.map → hx-dialog-AOZpHSuF.js.map} +1 -1
- package/dist/shared/{hx-drawer-Y1Ui2IWJ.js → hx-drawer-DH6CdAN1.js} +300 -98
- package/dist/shared/hx-drawer-DH6CdAN1.js.map +1 -0
- package/dist/shared/hx-dropdown-DiLd40Lm.js +401 -0
- package/dist/shared/hx-dropdown-DiLd40Lm.js.map +1 -0
- package/dist/shared/{hx-icon-button-CGNdQSFM.js → hx-icon-button-a6OpeQz5.js} +149 -68
- package/dist/shared/hx-icon-button-a6OpeQz5.js.map +1 -0
- package/dist/shared/{hx-link-C-O6vq0Q.js → hx-link-CMnZRUtQ.js} +55 -43
- package/dist/shared/hx-link-CMnZRUtQ.js.map +1 -0
- package/dist/shared/{hx-list-MyEhh8c7.js → hx-list-De66EtAP.js} +163 -107
- package/dist/shared/hx-list-De66EtAP.js.map +1 -0
- package/dist/shared/hx-menu-divider-BjiRIWKq.js +797 -0
- package/dist/shared/hx-menu-divider-BjiRIWKq.js.map +1 -0
- package/dist/shared/{hx-meter-BPscsw5t.js → hx-meter-BJdh6nrF.js} +105 -64
- package/dist/shared/hx-meter-BJdh6nrF.js.map +1 -0
- package/dist/shared/hx-overflow-menu-BQ4fiMYu.js +492 -0
- package/dist/shared/hx-overflow-menu-BQ4fiMYu.js.map +1 -0
- package/dist/shared/hx-phi-field-C19oxlrr.js.map +1 -1
- package/dist/shared/{hx-popover-CHxWY_cd.js → hx-popover-B9W8-tC0.js} +2 -2
- package/dist/shared/{hx-popover-CHxWY_cd.js.map → hx-popover-B9W8-tC0.js.map} +1 -1
- package/dist/shared/hx-progress-bar-C8nDMdYa.js +290 -0
- package/dist/shared/hx-progress-bar-C8nDMdYa.js.map +1 -0
- package/dist/shared/{hx-radio-CeGzARNk.js → hx-radio-Z1lV1zTO.js} +2 -2
- package/dist/shared/{hx-radio-CeGzARNk.js.map → hx-radio-Z1lV1zTO.js.map} +1 -1
- package/dist/shared/{hx-select-DrcS-YRJ.js → hx-select-D18CnJ0e.js} +2 -2
- package/dist/shared/hx-select-D18CnJ0e.js.map +1 -0
- package/dist/shared/{hx-spinner-DL5AYr16.js → hx-spinner-BB0h2hKZ.js} +62 -34
- package/dist/shared/hx-spinner-BB0h2hKZ.js.map +1 -0
- package/dist/shared/{hx-split-button-Djnc5Aeg.js → hx-split-button-BoABoEm5.js} +153 -82
- package/dist/shared/hx-split-button-BoABoEm5.js.map +1 -0
- package/dist/shared/{hx-stat-WOcNV1Ry.js → hx-stat-Dtf9lz-O.js} +77 -47
- package/dist/shared/hx-stat-Dtf9lz-O.js.map +1 -0
- package/dist/shared/{hx-switch-BX_8uNUs.js → hx-switch-B6kr-EwE.js} +2 -2
- package/dist/shared/{hx-switch-BX_8uNUs.js.map → hx-switch-B6kr-EwE.js.map} +1 -1
- package/dist/shared/{hx-tab-panel-DspCrKqo.js → hx-tab-panel-BQtBXKLD.js} +255 -131
- package/dist/shared/hx-tab-panel-BQtBXKLD.js.map +1 -0
- package/dist/shared/{hx-tag-CNSmdyaK.js → hx-tag-C5aCUpVi.js} +63 -40
- package/dist/shared/hx-tag-C5aCUpVi.js.map +1 -0
- package/dist/shared/{hx-td-DnnEMIuA.js → hx-td-BGkFOJEK.js} +267 -123
- package/dist/shared/hx-td-BGkFOJEK.js.map +1 -0
- package/dist/shared/hx-theme-BsefFWTO.js.map +1 -1
- package/dist/shared/hx-time-picker-iwCD7rzW.js +1038 -0
- package/dist/shared/hx-time-picker-iwCD7rzW.js.map +1 -0
- package/dist/shared/{hx-toggle-button-Dcz9IlUm.js → hx-toggle-button-BQ81EDkl.js} +2 -2
- package/dist/shared/{hx-toggle-button-Dcz9IlUm.js.map → hx-toggle-button-BQ81EDkl.js.map} +1 -1
- package/dist/shared/hx-tree-item-CHrUhuZL.js +925 -0
- package/dist/shared/hx-tree-item-CHrUhuZL.js.map +1 -0
- package/dist/shared/menu-roving-DmMnzJhn.js +14 -0
- package/dist/shared/menu-roving-DmMnzJhn.js.map +1 -0
- package/dist/shared/menu-tree-BNM0SYYq.js +42 -0
- package/dist/shared/menu-tree-BNM0SYYq.js.map +1 -0
- package/dist/shared/{toast-factory-YSznocIV.js → toast-factory-CL2BzdSB.js} +128 -77
- package/dist/shared/toast-factory-CL2BzdSB.js.map +1 -0
- package/dist/utils/aria-idref.d.ts.map +1 -1
- package/dist/utils/menu-label.d.ts +18 -0
- package/dist/utils/menu-label.d.ts.map +1 -0
- package/dist/utils/menu-roving.d.ts +28 -0
- package/dist/utils/menu-roving.d.ts.map +1 -0
- package/dist/utils/menu-tree.d.ts +41 -0
- package/dist/utils/menu-tree.d.ts.map +1 -0
- package/dist/utils/tree-walk.d.ts +53 -0
- package/dist/utils/tree-walk.d.ts.map +1 -0
- package/figma-inventory.json +69 -20
- package/package.json +2 -2
- package/dist/shared/aria-idref-Q0yiSR3p.js +0 -104
- package/dist/shared/aria-idref-Q0yiSR3p.js.map +0 -1
- package/dist/shared/hx-alert-CLn7CstP.js.map +0 -1
- package/dist/shared/hx-badge-CQXgOXJM.js.map +0 -1
- package/dist/shared/hx-banner-D3DzpfcP.js.map +0 -1
- package/dist/shared/hx-checkbox-BdgoUeWi.js.map +0 -1
- package/dist/shared/hx-drawer-Y1Ui2IWJ.js.map +0 -1
- package/dist/shared/hx-dropdown-DJWlF94E.js +0 -316
- package/dist/shared/hx-dropdown-DJWlF94E.js.map +0 -1
- package/dist/shared/hx-icon-button-CGNdQSFM.js.map +0 -1
- package/dist/shared/hx-link-C-O6vq0Q.js.map +0 -1
- package/dist/shared/hx-list-MyEhh8c7.js.map +0 -1
- package/dist/shared/hx-menu-divider-C2omnPtj.js +0 -558
- package/dist/shared/hx-menu-divider-C2omnPtj.js.map +0 -1
- package/dist/shared/hx-meter-BPscsw5t.js.map +0 -1
- package/dist/shared/hx-overflow-menu-DCLsdIBy.js +0 -374
- package/dist/shared/hx-overflow-menu-DCLsdIBy.js.map +0 -1
- package/dist/shared/hx-progress-bar-Bn3JEPUf.js +0 -258
- package/dist/shared/hx-progress-bar-Bn3JEPUf.js.map +0 -1
- package/dist/shared/hx-select-DrcS-YRJ.js.map +0 -1
- package/dist/shared/hx-spinner-DL5AYr16.js.map +0 -1
- package/dist/shared/hx-split-button-Djnc5Aeg.js.map +0 -1
- package/dist/shared/hx-stat-WOcNV1Ry.js.map +0 -1
- package/dist/shared/hx-tab-panel-DspCrKqo.js.map +0 -1
- package/dist/shared/hx-tag-CNSmdyaK.js.map +0 -1
- package/dist/shared/hx-td-DnnEMIuA.js.map +0 -1
- package/dist/shared/hx-time-picker-BoEIZwzv.js +0 -688
- package/dist/shared/hx-time-picker-BoEIZwzv.js.map +0 -1
- package/dist/shared/hx-tree-item-C2CiWuDE.js +0 -703
- package/dist/shared/hx-tree-item-C2CiWuDE.js.map +0 -1
- package/dist/shared/toast-factory-YSznocIV.js.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hx-time-picker-iwCD7rzW.js","sources":["../../src/components/hx-time-picker/hx-time-picker.styles.ts","../../src/components/hx-time-picker/hx-time-picker.ts"],"sourcesContent":["import { css } from 'lit';\n\nexport const helixTimePickerStyles = css`\n :host {\n display: block;\n position: relative;\n }\n :host([disabled]) {\n opacity: var(--hx-opacity-disabled, 0.5);\n pointer-events: none;\n }\n * {\n box-sizing: border-box;\n }\n .field {\n display: flex;\n flex-direction: column;\n gap: var(--hx-space-1, 0.25rem);\n font-family: var(--hx-time-picker-font-family, var(--hx-font-family-sans, sans-serif));\n }\n .field__label {\n display: flex;\n align-items: baseline;\n gap: var(--hx-space-1, 0.25rem);\n font-size: var(--hx-font-size-sm, 0.875rem);\n font-weight: var(--hx-font-weight-medium, 500);\n color: var(--hx-time-picker-label-color, var(--hx-color-text-strong, #202b39));\n line-height: var(--hx-line-height-normal, 1.5);\n }\n .field__required-marker {\n color: var(--hx-time-picker-error-color, var(--hx-color-error-text, #c92a2a));\n font-weight: var(--hx-font-weight-bold, 700);\n }\n .field__combobox {\n position: relative;\n display: flex;\n align-items: center;\n border: var(--hx-border-width-thin, 1px) solid\n var(--hx-time-picker-border-color, var(--hx-color-border-strong, #66787b));\n border-radius: var(--hx-time-picker-border-radius, var(--hx-border-radius-md, 0.375rem));\n background-color: var(--hx-time-picker-bg, var(--hx-color-surface-default, #ffffff));\n transition:\n border-color var(--hx-transition-fast, 150ms ease),\n box-shadow var(--hx-transition-fast, 150ms ease);\n overflow: visible;\n }\n .field__combobox:focus-within {\n border-color: var(--hx-time-picker-focus-ring-color, var(--hx-focus-ring-color));\n box-shadow: 0 0 0 var(--hx-focus-ring-width, 2px)\n color-mix(\n in srgb,\n var(--hx-time-picker-focus-ring-color, var(--hx-focus-ring-color))\n calc(var(--hx-focus-ring-opacity, 0.25) * 100%),\n transparent\n );\n }\n .field--error .field__combobox {\n border-color: var(--hx-time-picker-error-color, var(--hx-color-error-500, #e5493e));\n }\n .field--error .field__combobox:focus-within {\n border-color: var(--hx-time-picker-error-color, var(--hx-color-error-500, #e5493e));\n box-shadow: 0 0 0 var(--hx-focus-ring-width, 2px)\n color-mix(\n in srgb,\n var(--hx-time-picker-error-color, var(--hx-color-error-500, #e5493e))\n calc(var(--hx-focus-ring-opacity, 0.25) * 100%),\n transparent\n );\n }\n .field__input {\n flex: 1;\n border: none;\n outline: none;\n background: transparent;\n padding: var(--hx-space-2, 0.5rem) var(--hx-space-3, 0.75rem);\n font-family: inherit;\n font-size: var(--hx-font-size-md, 1rem);\n color: var(--hx-time-picker-color, var(--hx-color-text-strong, #202b39));\n line-height: var(--hx-line-height-normal, 1.5);\n min-height: var(--hx-size-10, 2.5rem);\n width: 100%;\n cursor: text;\n }\n .field__input::placeholder {\n color: var(--hx-color-text-placeholder, #66787b);\n }\n .field__input:disabled {\n cursor: not-allowed;\n }\n .field__toggle {\n display: flex;\n align-items: center;\n justify-content: center;\n border: none;\n background: transparent;\n padding: 0 var(--hx-space-3, 0.75rem);\n color: var(--hx-time-picker-chevron-color, var(--hx-color-text-muted, #4a5362));\n cursor: pointer;\n height: 100%;\n min-height: var(--hx-size-10, 2.5rem);\n flex-shrink: 0;\n border-inline-start: var(--hx-border-width-thin, 1px) solid\n var(--hx-time-picker-border-color, var(--hx-color-border-strong, #66787b));\n }\n .field__toggle:focus-visible {\n outline: var(--hx-focus-ring-width, 2px) solid\n var(--hx-time-picker-focus-ring-color, var(--hx-focus-ring-color));\n outline-offset: -2px;\n border-radius: 0 var(--hx-time-picker-border-radius, var(--hx-border-radius-md, 0.375rem));\n }\n .field__listbox {\n position: absolute;\n top: calc(100% + var(--hx-space-1, 0.25rem));\n inset-inline-start: 0;\n inset-inline-end: 0;\n z-index: var(--hx-z-index-dropdown, 1000);\n background-color: var(--hx-time-picker-listbox-bg, var(--hx-color-surface-default, #ffffff));\n border: var(--hx-border-width-thin, 1px) solid\n var(--hx-time-picker-border-color, var(--hx-color-border-strong, #66787b));\n border-radius: var(--hx-time-picker-border-radius, var(--hx-border-radius-md, 0.375rem));\n box-shadow: var(\n --hx-time-picker-listbox-shadow,\n 0 4px 16px color-mix(in srgb, var(--hx-color-neutral-900) 12%, transparent)\n );\n max-height: var(--hx-time-picker-listbox-max-height, 16rem);\n overflow-y: auto;\n padding: var(--hx-space-1, 0.25rem) 0;\n list-style: none;\n margin: 0;\n }\n @media (prefers-reduced-motion: no-preference) {\n .field__listbox {\n animation: hx-listbox-enter var(--hx-transition-fast, 150ms ease) forwards;\n }\n }\n @keyframes hx-listbox-enter {\n 0% {\n opacity: 0;\n transform: translateY(-0.25rem);\n }\n to {\n opacity: 1;\n transform: translateY(0);\n }\n }\n .field__option {\n display: flex;\n align-items: center;\n padding: var(--hx-space-2, 0.5rem) var(--hx-space-3, 0.75rem);\n font-size: var(--hx-font-size-md, 1rem);\n font-family: inherit;\n color: var(--hx-time-picker-option-color, var(--hx-color-text-strong, #202b39));\n cursor: pointer;\n transition: background-color var(--hx-transition-fast, 150ms ease);\n line-height: var(--hx-line-height-normal, 1.5);\n }\n .field__option:hover,\n .field__option--active {\n background-color: var(--hx-time-picker-option-hover-bg, var(--hx-color-primary-50, #ebf8f8));\n color: var(--hx-time-picker-option-hover-color, var(--hx-color-primary-700, #0f6363));\n }\n .field__option--selected {\n background-color: var(\n --hx-time-picker-option-selected-bg,\n var(--hx-color-primary-100, #dbf0f0)\n );\n color: var(--hx-time-picker-option-selected-color, var(--hx-color-primary-800, #07494a));\n font-weight: var(--hx-font-weight-medium, 500);\n }\n .field__option--selected.field__option--active {\n background-color: var(\n --hx-time-picker-option-selected-bg,\n var(--hx-color-primary-100, #dbf0f0)\n );\n }\n @media (prefers-reduced-motion: reduce) {\n .field__combobox,\n .field__option {\n transition: none;\n }\n }\n .field__help-text,\n .field__error {\n font-size: var(--hx-font-size-xs, 0.75rem);\n line-height: var(--hx-line-height-normal, 1.5);\n }\n .field__help-text {\n color: var(--hx-color-text-muted, #4a5362);\n }\n .field__error {\n color: var(--hx-time-picker-error-color, var(--hx-color-error-text, #c92a2a));\n }\n .field__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 @media (forced-colors: active) {\n .field__combobox {\n border-color: ButtonText;\n background-color: Canvas;\n }\n .field__combobox:focus-within {\n outline: 3px solid Highlight;\n outline-offset: 0;\n box-shadow: none;\n }\n .field--error .field__combobox {\n border-color: LinkText;\n }\n .field--error .field__combobox:focus-within {\n outline-color: Highlight;\n box-shadow: none;\n }\n .field__toggle:focus-visible {\n outline: 3px solid Highlight;\n outline-offset: 0;\n }\n .field__listbox {\n border-color: ButtonText;\n background-color: Canvas;\n box-shadow: none;\n }\n .field__option:hover,\n .field__option--active {\n background-color: Highlight;\n color: HighlightText;\n forced-color-adjust: none;\n }\n .field__option--selected {\n background-color: Highlight;\n color: HighlightText;\n forced-color-adjust: none;\n }\n .field__error {\n color: LinkText;\n }\n }\n`;\n","import { html, nothing, type PropertyValues } from 'lit';\nimport '../../utilities/document-token-adoption.js';\nimport { customElement, property, query, state } from 'lit/decorators.js';\nimport { HelixElement, createIdCounter } from '../../base/index.js';\nimport { FormMixin } from '../../mixins/FormMixin.js';\nimport { classMap } from 'lit/directives/class-map.js';\nimport { ifDefined } from 'lit/directives/if-defined.js';\nimport { live } from 'lit/directives/live.js';\nimport { repeat } from 'lit/directives/repeat.js';\nimport { helixTimePickerStyles } from './hx-time-picker.styles.js';\nimport { forcedColorsField } from '../../styles/forced-colors.js';\nimport { devWarn } from '../../utils/dev-warn.js';\nimport {\n installAriaIdrefMirror,\n resolveIdrefTokens,\n supportsIdrefElementReferences,\n type AriaIdrefMirrorHandle,\n} from '../../utils/aria-idref.js';\n\n// ─── Time Slot ───────────────────────────────────────────────────────────────\n\ninterface TimeSlot {\n /** HH:MM in 24-hour format — canonical internal value. */\n value: string;\n /** Display label respecting the component's `format` property. */\n label: string;\n}\n\n// ─── Helpers ─────────────────────────────────────────────────────────────────\n\n/** Parse \"HH:MM\" into { hours, minutes }. Returns null when the string is not valid. */\nfunction parseHHMM(raw: string): { hours: number; minutes: number } | null {\n const match = /^(\\d{1,2}):(\\d{2})$/.exec(raw.trim());\n if (!match) return null;\n const hours = parseInt(match[1] ?? '0', 10);\n const minutes = parseInt(match[2] ?? '0', 10);\n if (hours < 0 || hours > 23 || minutes < 0 || minutes > 59) return null;\n return { hours, minutes };\n}\n\n/** Format { hours, minutes } as zero-padded \"HH:MM\". */\nfunction toHHMM(hours: number, minutes: number): string {\n return `${String(hours).padStart(2, '0')}:${String(minutes).padStart(2, '0')}`;\n}\n\n/** Convert a 24-hour HH:MM value to a 12-hour display string (e.g. \"02:30 PM\"). */\nfunction to12h(value: string): string {\n const parsed = parseHHMM(value);\n if (!parsed) return value;\n const { hours, minutes } = parsed;\n const period = hours < 12 ? 'AM' : 'PM';\n const h = hours % 12 === 0 ? 12 : hours % 12;\n return `${String(h).padStart(2, '0')}:${String(minutes).padStart(2, '0')} ${period}`;\n}\n\n/**\n * Generate ordered time slots between `minTime` and `maxTime` (inclusive) at\n * `stepMinutes` intervals. Both bounds are HH:MM strings; defaults fall back\n * to \"00:00\" / \"23:59\".\n */\nfunction generateSlots(\n minTime: string,\n maxTime: string,\n stepMinutes: number,\n format: '12h' | '24h',\n): TimeSlot[] {\n const minParsed = parseHHMM(minTime) ?? { hours: 0, minutes: 0 };\n const maxParsed = parseHHMM(maxTime) ?? { hours: 23, minutes: 59 };\n\n const minTotal = minParsed.hours * 60 + minParsed.minutes;\n const maxTotal = maxParsed.hours * 60 + maxParsed.minutes;\n\n // Guard against degenerate step values\n const step = Math.max(1, Math.round(stepMinutes));\n\n const slots: TimeSlot[] = [];\n for (let t = minTotal; t <= maxTotal; t += step) {\n const h = Math.floor(t / 60) % 24;\n const m = t % 60;\n const value = toHHMM(h, m);\n slots.push({\n value,\n label: format === '12h' ? to12h(value) : value,\n });\n }\n return slots;\n}\n\n/** Clamp a raw HH:MM value to the [min, max] range; return '' when value is empty. */\nfunction clampValue(value: string, minTime: string, maxTime: string): string {\n if (!value) return '';\n const parsed = parseHHMM(value);\n if (!parsed) return '';\n\n const total = parsed.hours * 60 + parsed.minutes;\n const minParsed = parseHHMM(minTime) ?? { hours: 0, minutes: 0 };\n const maxParsed = parseHHMM(maxTime) ?? { hours: 23, minutes: 59 };\n const minTotal = minParsed.hours * 60 + minParsed.minutes;\n const maxTotal = maxParsed.hours * 60 + maxParsed.minutes;\n\n if (total < minTotal) return toHHMM(minParsed.hours, minParsed.minutes);\n if (total > maxTotal) return toHHMM(maxParsed.hours, maxParsed.minutes);\n return toHHMM(parsed.hours, parsed.minutes);\n}\n\n/**\n * Attempt to parse a user-typed string (12 h or 24 h) into an HH:MM value.\n * Returns null when the string cannot be resolved.\n */\nfunction parseUserInput(raw: string): string | null {\n const trimmed = raw.trim().toUpperCase();\n\n // 24-hour \"HH:MM\" or \"H:MM\"\n const hhmm = parseHHMM(trimmed);\n if (hhmm) return toHHMM(hhmm.hours, hhmm.minutes);\n\n // 12-hour patterns: \"2:30 PM\", \"2:30PM\", \"02:30 AM\", \"230 pm\", \"2 PM\"\n const twelve =\n /^(\\d{1,2})(?::(\\d{2}))?\\s*(AM|PM)$/.exec(trimmed) ??\n /^(\\d{1,2})(\\d{2})\\s*(AM|PM)$/.exec(trimmed);\n\n if (twelve) {\n let hours = parseInt(twelve[1] ?? '0', 10);\n const minutes = twelve[2] !== undefined ? parseInt(twelve[2], 10) : 0;\n const period = twelve[3] ?? '';\n if (hours < 1 || hours > 12 || minutes < 0 || minutes > 59) return null;\n if (period === 'AM') {\n hours = hours === 12 ? 0 : hours;\n } else {\n hours = hours === 12 ? 12 : hours + 12;\n }\n return toHHMM(hours, minutes);\n }\n\n return null;\n}\n\n/**\n * AccName-aware text flattener. Walks the subtree of `root` and concatenates\n * text-node content, REJECTING any element subtree carrying `aria-hidden=\"true\"`\n * or the `hidden` attribute per W3C AccName 1.2 §4.3.10. Used by hx-time-picker\n * for both external IDREF flatten (host aria-labelledby/aria-describedby\n * targets) and slotted-label aggregation, so nested decorative content like\n * `<svg aria-hidden=\"true\"><title>icon</title></svg>` does not leak into the\n * inner input's announced name/description.\n *\n * The TreeWalker filter only inspects elements VISITED during the walk — it\n * never tests the root itself, so a hidden ROOT (e.g. `<span slot=\"label\" hidden>`)\n * would still contribute its descendants' text. Per AccName 1.2 §4.3.10, a\n * hidden root contributes the empty string. Gate the walk here so every caller\n * (slotted label/help/error and external IDREF flatten) honors the rule\n * symmetrically.\n */\nfunction flattenAccName(root: Element): string {\n if (root.getAttribute('aria-hidden') === 'true' || root.hasAttribute('hidden')) {\n return '';\n }\n let result = '';\n const walker = document.createTreeWalker(root, NodeFilter.SHOW_ELEMENT | NodeFilter.SHOW_TEXT, {\n acceptNode(node) {\n if (node.nodeType === Node.ELEMENT_NODE) {\n const el = node as Element;\n if (el.getAttribute('aria-hidden') === 'true') {\n return NodeFilter.FILTER_REJECT;\n }\n if (el.hasAttribute('hidden')) {\n return NodeFilter.FILTER_REJECT;\n }\n return NodeFilter.FILTER_SKIP;\n }\n return NodeFilter.FILTER_ACCEPT;\n },\n });\n let textNode: Node | null = walker.nextNode();\n while (textNode) {\n result += textNode.textContent ?? '';\n textNode = walker.nextNode();\n }\n return result.replace(/\\s+/g, ' ').trim();\n}\n\nconst _nextTimePickerId = createIdCounter('hx-time-picker');\n\n// ─── Component ───────────────────────────────────────────────────────────────\n\n/** Detail for the hx-change event dispatched by hx-time-picker. */\nexport interface HxTimePickerChangeDetail {\n value: string;\n}\n\n/**\n * A time-picker component with a combobox pattern: a text input with format\n * masking and a dropdown listbox of pre-generated time slots.\n *\n * @summary Form-associated time picker with 12h/24h format support and dropdown listbox.\n *\n * @tag hx-time-picker\n *\n * @slot label - Custom label content; overrides the rendered label element when used.\n * @slot help-text - Help text displayed below the field.\n * @slot error - Custom error content; overrides the `error` property.\n *\n * @fires {CustomEvent<{value: string}>} hx-change - Dispatched when the selected time changes. Detail value is HH:MM (24h).\n *\n * @csspart label - The label element.\n * @csspart input - The text input element.\n * @csspart toggle - The clock icon toggle button.\n * @csspart listbox - The dropdown `<ul>` element.\n * @csspart option - Each `<li>` option in the listbox.\n * @csspart field - The outer field wrapper element.\n * @csspart error - The error message element.\n * @csspart help-text - The help text element.\n *\n * @cssprop [--hx-time-picker-bg=var(--hx-color-neutral-0)] - Input background color.\n * @cssprop [--hx-time-picker-color=var(--hx-color-neutral-800)] - Input text color.\n * @cssprop [--hx-time-picker-border-color=var(--hx-color-neutral-300)] - Border color.\n * @cssprop [--hx-time-picker-border-radius=var(--hx-border-radius-md)] - Border radius.\n * @cssprop [--hx-time-picker-font-family=var(--hx-font-family-sans)] - Font family.\n * @cssprop [--hx-time-picker-focus-ring-color=var(--hx-focus-ring-color)] - Focus ring color.\n * @cssprop [--hx-time-picker-error-color=var(--hx-color-error-500)] - Error state color.\n * @cssprop [--hx-time-picker-label-color=var(--hx-color-neutral-700)] - Label text color.\n * @cssprop [--hx-time-picker-chevron-color=var(--hx-color-neutral-500)] - Toggle chevron color.\n * @cssprop [--hx-time-picker-listbox-bg=var(--hx-color-neutral-0)] - Listbox background.\n * @cssprop [--hx-time-picker-listbox-max-height=16rem] - Maximum height of the dropdown.\n * @cssprop [--hx-time-picker-listbox-shadow=0 4px 16px color-mix(in srgb, var(--hx-color-neutral-900) 12%, transparent)] - Box shadow for the dropdown listbox.\n * @cssprop [--hx-time-picker-option-color=var(--hx-color-neutral-800)] - Option text color.\n * @cssprop [--hx-time-picker-option-hover-bg=var(--hx-color-primary-50)] - Option hover background.\n * @cssprop [--hx-time-picker-option-hover-color=var(--hx-color-primary-700)] - Option hover text color.\n * @cssprop [--hx-time-picker-option-selected-bg=var(--hx-color-primary-100)] - Selected option background.\n * @cssprop [--hx-time-picker-option-selected-color=var(--hx-color-primary-800)] - Selected option text color.\n * @cssprop [--hx-opacity-disabled] - Opacity.\n * @cssprop [--hx-space-1] - Spacing token.\n * @cssprop [--hx-font-family-sans] - Font family.\n * @cssprop [--hx-font-size-sm] - Font size.\n * @cssprop [--hx-font-weight-medium] - Font weight.\n * @cssprop [--hx-color-neutral-700] - Color.\n * @cssprop [--hx-line-height-normal] - Line height.\n * @cssprop [--hx-color-error-text] - Color.\n * @cssprop [--hx-font-weight-bold] - Font weight.\n * @cssprop [--hx-border-width-thin] - Width.\n * @cssprop [--hx-color-neutral-300] - Color.\n * @cssprop [--hx-border-radius-md] - CSS custom property.\n * @cssprop [--hx-color-neutral-0] - Color.\n * @cssprop [--hx-transition-fast] - Transition timing.\n * @cssprop [--hx-focus-ring-color] - Color.\n * @cssprop [--hx-focus-ring-width] - Width.\n * @cssprop [--hx-focus-ring-opacity] - CSS custom property.\n * @cssprop [--hx-color-error-500] - Color.\n * @cssprop [--hx-space-2] - Spacing token.\n * @cssprop [--hx-space-3] - Spacing token.\n * @cssprop [--hx-font-size-md] - Font size.\n * @cssprop [--hx-color-neutral-800] - Color.\n * @cssprop [--hx-size-10] - Size token.\n * @cssprop [--hx-color-neutral-400] - Color.\n * @cssprop [--hx-color-neutral-500] - Color.\n * @cssprop [--hx-z-index-dropdown] - Z-index layer.\n * @cssprop [--hx-color-neutral-900] - Color.\n * @cssprop [--hx-color-primary-50] - Color.\n * @cssprop [--hx-color-primary-700] - Color.\n * @cssprop [--hx-color-primary-100] - Color.\n * @cssprop [--hx-color-primary-800] - Color.\n * @cssprop [--hx-font-size-xs] - Font size.\n */\n@customElement('hx-time-picker')\nexport class HelixTimePicker extends FormMixin(HelixElement) {\n static override styles = [helixTimePickerStyles, forcedColorsField];\n\n // ─── Form Association ───\n\n /**\n * Declares this element as form-associated so it participates in native form submission.\n * @internal\n */\n static override formAssociated = true;\n\n /**\n * Test seam: when set to `true` or `false`, overrides the platform\n * `supportsIdrefElementReferences` probe before `connectedCallback` seeds\n * `_supportsIdrefRefs`. Production code MUST NOT touch this field. It is a\n * `static` so the test stub cleanup is global and obvious.\n * @internal\n */\n static __testSupportsIdrefRefsOverride: boolean | null = null;\n\n // ─── Properties ───\n\n /**\n * The name submitted with the form. Value is always HH:MM (24-hour).\n * @attr name\n */\n @property({ type: String, reflect: true })\n name = '';\n\n /**\n * The current value in HH:MM (24-hour) format.\n * @attr value\n */\n @property({ type: String, reflect: true })\n value = '';\n\n /**\n * The earliest selectable time in HH:MM format.\n * @attr min\n */\n @property({ type: String })\n min = '00:00';\n\n /**\n * The latest selectable time in HH:MM format.\n * @attr max\n */\n @property({ type: String })\n max = '23:59';\n\n /**\n * Step interval between dropdown options, in minutes. Defaults to 30.\n * @attr step\n */\n @property({ type: Number })\n step = 30;\n\n /**\n * The visible label text for the field.\n * @attr label\n */\n @property({ type: String })\n label = '';\n\n /**\n * Whether the field is required for form submission.\n * @attr required\n */\n @property({ type: Boolean, reflect: true })\n required = false;\n\n /**\n * Whether the field is disabled.\n * @attr disabled\n */\n @property({ type: Boolean, reflect: true })\n disabled = false;\n\n /**\n * Error message to display. When set, the field enters an error state.\n * @attr error\n */\n @property({ type: String })\n error = '';\n\n /**\n * Display format for the time input. '12h' shows AM/PM; '24h' is bare HH:MM.\n * @attr format\n */\n @property({ type: String, reflect: true })\n format: '12h' | '24h' = '12h';\n\n /**\n * Accessible name for screen readers, if different from the visible label.\n * Uses `accessible-label` attribute instead of `aria-label` to avoid\n * ARIAMixin shadowing on the host element. Highest-precedence naming source.\n * @attr accessible-label\n */\n @property({ type: String, attribute: 'accessible-label' })\n accessibleLabel: string | null = null;\n\n // ─── Internal State ───\n\n /**\n * Whether the dropdown listbox is currently open.\n * @internal\n */\n @state() private _open = false;\n /**\n * Index of the currently keyboard-active option in the listbox; -1 when none is active.\n * @internal\n */\n @state() private _activeIndex = -1;\n /**\n * The display string shown in the text input, formatted according to the current `format` property.\n * @internal\n */\n @state() private _inputDisplayValue = '';\n /**\n * Whether the label slot has slotted content assigned to it.\n * @internal\n */\n @state() private _hasLabelSlot = false;\n /**\n * Whether the error slot has slotted content assigned to it.\n * @internal\n */\n @state() private _hasErrorSlot = false;\n /**\n * Whether the help-text slot has slotted content assigned to it.\n * @internal\n */\n @state() private _hasHelpSlot = false;\n /**\n * Source of the accessible name. Discriminated union avoids string sentinels.\n * @internal\n */\n @state() private _labelSource: 'string' | 'slot' | 'none' = 'none';\n /**\n * Flattened, trimmed text content from all label-slot nodes — used to drive\n * the inner input's `aria-label` on the no-IDL-ref fallback path and to\n * gate `_hasLabelSlot` per AccName 1.2.\n * @internal\n */\n @state() private _labelSlotText = '';\n /**\n * Whether the platform supports IDL element references on `ElementInternals`.\n * Drives the cross-shadow naming strategy for the inner `<input>`.\n * @internal\n */\n @state() private _supportsIdrefRefs = true;\n /**\n * Cached invalidity flag derived from `internals.validity.valid`, the\n * `error` property, and the slotted error content. Drives `aria-invalid`\n * on the inner input.\n * @internal\n */\n @state() private _invalid = false;\n /**\n * Deferred copy of `error` driven through reactive state so the persistent\n * live region can re-announce on transitions without direct DOM mutation.\n * @internal\n */\n @state() private _announcedError = '';\n\n // ─── Stable IDs (monotonically incrementing counter for SSR safety) ───\n\n private readonly _id = _nextTimePickerId();\n /**\n * Unique ID for the listbox element, referenced by `aria-controls` on the combobox input.\n * @internal\n */\n private readonly _listboxId = `${this._id}-listbox`;\n /**\n * Unique ID for the error message element, referenced by `aria-describedby` on the input.\n * @internal\n */\n private readonly _errorId = `${this._id}-error`;\n /**\n * Unique ID for the help text element, referenced by `aria-describedby` on the input.\n * @internal\n */\n private readonly _helpId = `${this._id}-help`;\n /**\n * Unique ID for the internal `<label>` element, referenced by inner input\n * `aria-labelledby` when the `label` property names the field.\n * @internal\n */\n private readonly _labelId = `${this._id}-label`;\n /**\n * Id of the synthesized in-shadow span that mirrors the consumer-resolved\n * description text. Appended to the inner input's `aria-describedby` so AT\n * picks the consumer description up through the standard described-by\n * channel — `aria-description` is intentionally NOT written, because the\n * W3C AccName algorithm ignores `aria-description` whenever\n * `aria-describedby` is also present.\n * @internal\n */\n private readonly _consumerDescId = `${this._id}-consumer-desc`;\n\n // ─── Query References ───\n\n /**\n * Reference to the text input element inside the shadow DOM.\n * @internal\n */\n @query('.field__input')\n private _inputEl: HTMLInputElement | undefined;\n\n /**\n * Reference to the listbox `<ul>` element inside the shadow DOM.\n * @internal\n */\n @query('.field__listbox')\n private _listboxEl: HTMLUListElement | undefined;\n\n // ─── Memoized slot generation (avoids regenerating on every render call) ───\n\n /**\n * Memoized array of generated time slots; null until first access.\n * @internal\n */\n private _cachedSlots: TimeSlot[] | null = null;\n /**\n * Cache key composed of min, max, step, and format; used to detect when slots must be regenerated.\n * @internal\n */\n private _slotsKey = '';\n\n /**\n * Lazily generates and caches the list of time slots based on current min, max, step, and format.\n * @internal\n */\n private get _slots(): TimeSlot[] {\n const key = `${this.min}|${this.max}|${this.step}|${this.format}`;\n if (this._cachedSlots === null || key !== this._slotsKey) {\n this._slotsKey = key;\n this._cachedSlots = generateSlots(this.min, this.max, this.step, this.format);\n }\n return this._cachedSlots;\n }\n\n // ─── Host-canonical ARIA bookkeeping ───\n\n /** Handle for the shared IDREF observer. @internal */\n private _ariaMirror: AriaIdrefMirrorHandle | null = null;\n /**\n * Watches assigned `<slot name=\"help-text\">` nodes for in-place text\n * mutations so help-text effective state stays in sync with consumer\n * `textContent` writes that don't trigger a `slotchange` event.\n * @internal\n */\n private _helpSlotTextObserver: MutationObserver | null = null;\n /**\n * Watches assigned `<slot name=\"error\">` nodes for in-place text mutations.\n * @internal\n */\n private _errorSlotTextObserver: MutationObserver | null = null;\n /**\n * Dedicated host observer scoped to `aria-describedby` with\n * `attributeOldValue: true`. Governed by the disconnect-during-strip\n * discipline.\n * @internal\n */\n private _hostDescribedByObserver: MutationObserver | null = null;\n /**\n * Most recently observed *consumer-supplied* `aria-labelledby` baseline.\n * Refreshed on every sync. Modern + legacy paths leave the host attribute\n * in place, so the live attribute IS the cache.\n * @internal\n */\n private _consumerLabelledBy: string | null = null;\n /** @internal — see `_consumerLabelledBy`. */\n private _consumerDescribedBy: string | null = null;\n /**\n * Direct references to ALL labellable elements projected into\n * `<slot name=\"label\">`. Aggregating every assigned element preserves\n * composed labels such as\n * `<svg slot=\"label\" aria-hidden=\"true\">…</svg><span slot=\"label\">Time</span>`.\n * The modern path passes the visible subset to\n * `internals.ariaLabelledByElements`; the fallback path text-flattens every\n * non-hidden node into `_labelSlotText` per AccName 1.2.\n * @internal\n */\n private _slottedLabelEls: Element[] = [];\n /**\n * Watches in-place text mutations on the assigned slotted label nodes. The\n * `slotchange` event covers add/remove/replace; this MO covers\n * `node.textContent = '…'` updates on an unchanged node (consumer i18n\n * re-renders) and `aria-hidden` / `hidden` toggles per AccName 1.2 §4.3.10.\n * @internal\n */\n private _labelSlotTextObserver: MutationObserver | null = null;\n /**\n * Watches in-place text mutations on consumer light-DOM elements resolved\n * from host `aria-labelledby` / `aria-describedby`. Without this, a consumer\n * keeping the same `<label id=\"…\">` but mutating its `textContent` (e.g.\n * i18n re-render) would leave the inner input's `aria-label` and\n * synthesized description span stale indefinitely.\n * @internal\n */\n private _externalRefsObserver: MutationObserver | null = null;\n\n // ─── Outside-click handler (bound reference for add/removeEventListener) ───\n\n /**\n * Closes the listbox when a click is detected outside the component; bound for stable add/removeEventListener calls.\n * @internal\n */\n private readonly _handleOutsideClick = (e: MouseEvent): void => {\n if (!this.isConnected) return;\n if (!this.contains(e.target as Node) && !this.shadowRoot?.contains(e.target as Node)) {\n this._closeListbox();\n }\n };\n\n // ─── Lifecycle ───\n\n override connectedCallback(): void {\n super.connectedCallback();\n document.addEventListener('click', this._handleOutsideClick);\n\n // Honour the static test override so synthetic environments choose the\n // path BEFORE connect runs.\n const ctor = this.constructor as typeof HelixTimePicker;\n this._supportsIdrefRefs =\n ctor.__testSupportsIdrefRefsOverride !== null\n ? ctor.__testSupportsIdrefRefsOverride\n : supportsIdrefElementReferences(this._internals);\n\n // Install the dedicated `aria-describedby` retraction observer BEFORE\n // the seeded `_syncHostAriaSemantics()` call below, then govern its\n // lifetime with the disconnect-during-strip discipline.\n this._hostDescribedByObserver = new MutationObserver((records) => {\n let consumerCleared = false;\n for (const record of records) {\n if (record.attributeName !== 'aria-describedby') continue;\n const oldValue = record.oldValue;\n const newValue = this.getAttribute('aria-describedby');\n if (oldValue !== null && newValue === null) {\n this._consumerDescribedBy = null;\n consumerCleared = true;\n }\n }\n if (consumerCleared) {\n this._syncHostAriaSemantics();\n }\n });\n this._hostDescribedByObserver.observe(this, {\n attributes: true,\n attributeFilter: ['aria-describedby'],\n attributeOldValue: true,\n });\n\n // Seed root-independent semantics from connect so the inner input\n // resolves naming before first paint.\n this._syncHostAriaSemantics();\n this._ariaMirror = installAriaIdrefMirror(this, () => {\n this._syncHostAriaSemantics();\n });\n }\n\n override disconnectedCallback(): void {\n super.disconnectedCallback();\n document.removeEventListener('click', this._handleOutsideClick);\n this._ariaMirror?.disconnect();\n this._ariaMirror = null;\n this._helpSlotTextObserver?.disconnect();\n this._helpSlotTextObserver = null;\n this._errorSlotTextObserver?.disconnect();\n this._errorSlotTextObserver = null;\n this._labelSlotTextObserver?.disconnect();\n this._labelSlotTextObserver = null;\n this._hostDescribedByObserver?.disconnect();\n this._hostDescribedByObserver = null;\n this._externalRefsObserver?.disconnect();\n this._externalRefsObserver = null;\n }\n\n override willUpdate(changed: PropertyValues<this>): void {\n super.willUpdate(changed);\n // Keep display value in sync whenever the canonical value or format changes\n if (changed.has('value') || changed.has('format')) {\n this._inputDisplayValue = this.value\n ? this.format === '12h'\n ? to12h(this.value)\n : this.value\n : '';\n }\n // Seed `_announcedError` BEFORE render so the persistent live region\n // renders with the error text in the SAME frame that removes `hidden`\n // from the alert container. Covers first paint AND runtime transitions\n // from \"\" to \"Server rejected\" via async/server-side validation.\n if (changed.has('error') || !this.hasUpdated) {\n this._announcedError = this.error ?? '';\n }\n if (changed.has('label')) {\n this._refreshLabelSource();\n }\n }\n\n override updated(changed: PropertyValues<this>): void {\n super.updated(changed);\n if (changed.has('value')) {\n this._internals.setFormValue(this.value || null);\n }\n // When the listbox opens, scroll the selected (or active) option into view\n if ((changed as Map<PropertyKey, unknown>).has('_open') && this._open) {\n this._scrollActiveOptionIntoView();\n }\n // Host-elevated ARIA semantics — see _syncHostAriaSemantics.\n this._syncHostAriaSemantics();\n // Drive re-announcement from reactive state on error→error transitions\n // (rAF clear-and-re-set forces AT to re-read role=\"alert\" content).\n if (changed.has('error')) {\n const previousError = changed.get('error') as string | undefined;\n if (previousError && this.error) {\n this._announcedError = '';\n requestAnimationFrame(() => {\n this._announcedError = this.error;\n });\n } else {\n this._announcedError = this.error;\n }\n }\n }\n\n override firstUpdated(changed: PropertyValues<this>): void {\n super.firstUpdated(changed);\n // `slotchange` fires as a microtask after the initial synchronous render.\n // Without proactive seeding, the first `_syncHostAriaSemantics()` call\n // (driven from `updated()` in this same cycle, AFTER firstUpdated returns)\n // would observe stale `false` / empty state for `_hasLabelSlot`,\n // `_slottedLabelEls`, `_labelSlotText`, `_hasHelpSlot`, and\n // `_hasErrorSlot`. Seed synchronously here.\n this._seedSlotStateSync();\n // Re-sync now that the slot state is populated so AT sees the right\n // accessible name on first paint.\n this._syncHostAriaSemantics();\n // WCAG 4.1.2: warn when no accessible name is available.\n if (\n !this.label &&\n !this.accessibleLabel &&\n !this._hasLabelSlot &&\n !this.getAttribute('aria-label') &&\n !this.getAttribute('aria-labelledby')\n ) {\n devWarn(\n 'hx-time-picker',\n 'No accessible label provided. Set the `label` attribute, `accessible-label`, `aria-label`, `aria-labelledby`, or project a `<slot name=\"label\">` child. An unlabeled time picker violates WCAG 2.1 AA (4.1.2 Name, Role, Value).',\n );\n }\n }\n\n /**\n * Synchronous slot-state seed. Mirrors the side effects of the three\n * `_handle*SlotChange` handlers (label / help-text / error) but is driven by\n * direct `slot.assignedNodes()` reads so we can populate state BEFORE the\n * microtask `slotchange` events fire after the first render.\n * @internal\n */\n private _seedSlotStateSync(): void {\n const root = this.shadowRoot;\n if (!root) return;\n const labelSlot = root.querySelector<HTMLSlotElement>('slot[name=\"label\"]');\n if (labelSlot) {\n const state = this._readLabelSlotState(labelSlot);\n this._hasLabelSlot = state.hasUsefulName;\n this._slottedLabelEls = state.elements;\n this._labelSlotText = state.text;\n this._installLabelSlotTextObserver(state.elements);\n this._refreshLabelSource();\n }\n const helpSlot = root.querySelector<HTMLSlotElement>('slot[name=\"help-text\"]');\n if (helpSlot) {\n this._hasHelpSlot = this._readHelpSlotStateSync(helpSlot);\n this._installHelpSlotTextObserver(helpSlot);\n }\n const errorSlot = root.querySelector<HTMLSlotElement>('slot[name=\"error\"]');\n if (errorSlot) {\n this._hasErrorSlot = this._readErrorSlotStateSync(errorSlot);\n this._installErrorSlotTextObserver(errorSlot);\n }\n }\n\n /**\n * Reads the label slot's assigned nodes and computes the discriminated\n * naming state. An empty whitespace-only slot does NOT count as a useful\n * name. Aggregates ALL assigned elements (not just the first); per AccName\n * 1.2 §4.3.10, `aria-hidden=\"true\"` and `[hidden]` elements contribute zero\n * to the accessible name (their text is skipped during flattening).\n * @internal\n */\n private _readLabelSlotState(slot: HTMLSlotElement): {\n hasUsefulName: boolean;\n elements: Element[];\n text: string;\n } {\n const nodes = slot.assignedNodes({ flatten: true });\n const elements: Element[] = [];\n const fragments: string[] = [];\n for (const node of nodes) {\n if (node.nodeType === Node.ELEMENT_NODE) {\n const el = node as Element;\n elements.push(el);\n if (el.getAttribute('aria-hidden') === 'true') continue;\n const elText = flattenAccName(el);\n if (elText) fragments.push(elText);\n } else if (node.nodeType === Node.TEXT_NODE) {\n const txt = (node.textContent ?? '').trim();\n if (txt) fragments.push(txt);\n }\n }\n const trimmedText = fragments.join(' ').replace(/\\s+/g, ' ').trim();\n return {\n hasUsefulName: trimmedText.length > 0,\n elements,\n text: trimmedText,\n };\n }\n\n /**\n * Re-evaluate the help-text slot's \"has meaningful content\" state from its\n * current effective text. Mirrors the slotchange-handler logic but is\n * invocable from the in-place mutation observer so that clearing\n * `textContent` on the same slotted node flips `_hasHelpSlot` back to\n * `false`. Uses AccName-aware flatten so descendants carrying\n * `aria-hidden=\"true\"` or `hidden` do NOT count toward \"has meaningful\n * content\".\n * @internal\n */\n private _readHelpSlotStateSync(slot: HTMLSlotElement): boolean {\n const nodes = slot.assignedNodes({ flatten: true });\n for (const node of nodes) {\n if (node.nodeType === Node.TEXT_NODE) {\n if ((node.textContent ?? '').trim().length > 0) return true;\n } else if (node.nodeType === Node.ELEMENT_NODE) {\n if (flattenAccName(node as Element).length > 0) return true;\n }\n }\n return false;\n }\n\n /**\n * Re-evaluate the error slot's \"has meaningful content\" state from its\n * current effective text. AccName-aware so visibility-suppressed roots /\n * descendants don't keep the field stuck in error state.\n * @internal\n */\n private _readErrorSlotStateSync(slot: HTMLSlotElement): boolean {\n const nodes = slot.assignedNodes({ flatten: true });\n for (const node of nodes) {\n if (node.nodeType === Node.TEXT_NODE) {\n if ((node.textContent ?? '').trim().length > 0) return true;\n } else if (node.nodeType === Node.ELEMENT_NODE) {\n if (flattenAccName(node as Element).length > 0) return true;\n }\n }\n return false;\n }\n\n // ─── Inner-input ARIA sync (W3C APG editable combobox) ───\n\n /**\n * (Re-)installs a `MutationObserver` against the deduped union of\n * consumer-resolved label/description elements. Watches `characterData`,\n * `childList`, `subtree`, and aria-hidden/hidden attribute toggles so any\n * in-place text or visibility mutation triggers a fresh sync.\n * @internal\n */\n private _installExternalRefsObserver(elements: Element[]): void {\n if (this._externalRefsObserver) {\n this._externalRefsObserver.disconnect();\n this._externalRefsObserver = null;\n }\n if (elements.length === 0) return;\n const unique = new Set<Element>(elements);\n const observer = new MutationObserver(() => {\n this._syncHostAriaSemantics();\n });\n for (const el of unique) {\n observer.observe(el, {\n characterData: true,\n subtree: true,\n childList: true,\n attributes: true,\n attributeFilter: ['aria-hidden', 'hidden'],\n });\n }\n this._externalRefsObserver = observer;\n }\n\n /**\n * Resolves consumer-supplied label/description IDREFs on the host and writes\n * the canonical combobox ARIA onto the **inner `<input>`** per W3C APG\n * editable combobox pattern. The inner input owns `role=\"combobox\"`\n * (replacing its implicit textbox role) and all combobox state ARIA so AT\n * sees a single announced + focused surface.\n *\n * Cross-shadow naming uses a belt-and-suspenders strategy:\n *\n * 1. **Modern path** (`_supportsIdrefRefs === true`): consumer-resolved\n * label/description elements are written onto\n * `internals.ariaLabelledByElements` / `internals.ariaDescribedByElements`\n * on the host. Host-level `aria-labelledby` / `aria-describedby`\n * attributes are LEFT IN PLACE so AT walking up the DOM also sees them.\n * The text content of the resolved elements is also flattened onto the\n * inner input as `aria-label` so AT that does not walk up still\n * announces the right name.\n *\n * 2. **Legacy fallback** (`_supportsIdrefRefs === false`): the resolved-\n * element text is flattened onto the inner input as `aria-label` and\n * mirrored into a synthesized in-shadow span pointed at by the inner\n * input's `aria-describedby`.\n *\n * Writing `aria-labelledby=\"<light-DOM id>\"` directly on the shadow-DOM\n * inner input is INTENTIONALLY avoided: light-DOM ids do not resolve from\n * inside a shadow root.\n * @internal\n */\n private _syncHostAriaSemantics(): void {\n const internals = this._internals;\n\n const input = this._inputEl;\n if (!input) {\n // Inner input not yet rendered; defer. Still derive `_invalid` so\n // `aria-invalid` first-paint is correct once the input renders.\n const isInvalidEarly = !internals.validity.valid || !!(this.error || this._hasErrorSlot);\n if (this._invalid !== isInvalidEarly) this._invalid = isInvalidEarly;\n return;\n }\n\n const liveAriaLabel = this.getAttribute('aria-label');\n const hostAriaLabel = liveAriaLabel !== null ? liveAriaLabel.trim() || '' : '';\n\n const internalLabel = this.shadowRoot?.getElementById(this._labelId) ?? null;\n const slottedLabelEls = this._slottedLabelEls;\n const helpEl = this.shadowRoot?.getElementById(this._helpId) ?? null;\n const errorEl = this.shadowRoot?.getElementById(this._errorId) ?? null;\n\n const liveLabelledBy = this.getAttribute('aria-labelledby');\n this._consumerLabelledBy = liveLabelledBy;\n const liveDescribedBy = this.getAttribute('aria-describedby');\n this._consumerDescribedBy = liveDescribedBy;\n\n const consumerLabelEls = resolveIdrefTokens(this, this._consumerLabelledBy);\n const hasEffectiveLabelledBy = consumerLabelEls.length > 0;\n\n const consumerDescEls = resolveIdrefTokens(this, this._consumerDescribedBy);\n\n // Observe in-place text mutations on the resolved external IDREF targets.\n this._installExternalRefsObserver([...consumerLabelEls, ...consumerDescEls]);\n\n const hasError = !!(this.error || this._hasErrorSlot);\n\n // `aria-invalid` reflects EVERY signal the consumer can use to express\n // invalidity: `setValidity()` (required-empty), explicit `error` property,\n // and slotted error content.\n const isInvalid = !internals.validity.valid || hasError;\n if (this._invalid !== isInvalid) this._invalid = isInvalid;\n\n // `accessibleLabel` is the canonical AT name when explicitly set; it\n // outranks visible label / aria-labelledby per the helix override.\n const explicitAccessibleLabel =\n typeof this.accessibleLabel === 'string' && this.accessibleLabel.trim().length > 0\n ? this.accessibleLabel\n : null;\n\n // Top-level `aria-hidden=\"true\"` / `hidden` elements MUST NOT be forwarded\n // to `internals.ariaLabelledByElements` / `ariaDescribedByElements`.\n const isVisibleForAccName = (el: Element): boolean =>\n el.getAttribute('aria-hidden') !== 'true' && !el.hasAttribute('hidden');\n\n // Build the augmented element lists used by the modern (IDL-refs) path.\n const labelElsForInternals: Element[] = [];\n if (!explicitAccessibleLabel) {\n labelElsForInternals.push(...consumerLabelEls.filter(isVisibleForAccName));\n if (!hasEffectiveLabelledBy && !hostAriaLabel) {\n if (this._labelSource === 'slot' && slottedLabelEls.length > 0) {\n labelElsForInternals.push(...slottedLabelEls.filter(isVisibleForAccName));\n } else if (this._labelSource === 'string' && internalLabel) {\n labelElsForInternals.push(internalLabel);\n }\n }\n }\n\n const descElsForInternals: Element[] = [...consumerDescEls.filter(isVisibleForAccName)];\n if (helpEl && !hasError && this._hasHelpSlot) {\n descElsForInternals.push(helpEl);\n }\n if (errorEl && hasError) {\n descElsForInternals.push(errorEl);\n }\n\n // ─── Modern-path: ElementInternals IDL element references ───\n type InternalsWithIdrefRefs = ElementInternals & {\n ariaLabelledByElements: Element[] | null;\n ariaDescribedByElements: Element[] | null;\n };\n if (this._supportsIdrefRefs) {\n const refsInternals = internals as InternalsWithIdrefRefs;\n refsInternals.ariaLabelledByElements =\n labelElsForInternals.length > 0 ? labelElsForInternals : null;\n refsInternals.ariaDescribedByElements =\n descElsForInternals.length > 0 ? descElsForInternals : null;\n // Forward `accessibleLabel` to `internals.ariaLabel` when set; CLEAR\n // with `null` (NOT `''`) when absent, because per W3C AccName an empty\n // `aria-label` STILL outranks `aria-labelledby` and would erase the\n // name resolved from element references / fallbacks.\n if (explicitAccessibleLabel) {\n internals.ariaLabel = explicitAccessibleLabel;\n } else {\n internals.ariaLabel = null;\n }\n }\n\n // ─── Compute the inner input's accessible name (text-flatten path) ───\n const flattenText = (els: Element[]): string =>\n els\n .filter(isVisibleForAccName)\n .map((el) => flattenAccName(el))\n .filter((t) => t.length > 0)\n .join(' ');\n\n let inputAriaLabel: string | null = null;\n let inputAriaLabelledBy: string | null = null;\n\n // Precedence (per AccName 1.2 §4.3.1 with helix override):\n // 1. accessibleLabel (helix-specific override)\n // 2. consumer aria-labelledby resolves → text-flatten\n // 3. consumer aria-label on the host\n // 4. slotted label → text content (NEVER cross-shadow id reference)\n // 5. label property → internal `<label>` id (same shadow root)\n // 6. else: unnamed\n let labelledByFlat = '';\n if (!explicitAccessibleLabel && hasEffectiveLabelledBy) {\n labelledByFlat = flattenText(consumerLabelEls);\n }\n if (explicitAccessibleLabel) {\n inputAriaLabel = explicitAccessibleLabel;\n } else if (labelledByFlat) {\n inputAriaLabel = labelledByFlat;\n } else if (hostAriaLabel) {\n inputAriaLabel = hostAriaLabel;\n } else if (this._labelSource === 'slot') {\n // Light-DOM ids do not resolve from inside a shadow root, so we MUST\n // text-flatten on the legacy/fallback path.\n if (this._labelSlotText) {\n inputAriaLabel = this._labelSlotText;\n } else if (slottedLabelEls.length > 0) {\n const flat = flattenText(slottedLabelEls);\n if (flat) inputAriaLabel = flat;\n }\n } else if (this._labelSource === 'string') {\n if (internalLabel?.id) {\n inputAriaLabelledBy = internalLabel.id;\n } else if (this.label) {\n inputAriaLabel = this.label;\n }\n }\n\n if (inputAriaLabelledBy) {\n if (input.getAttribute('aria-labelledby') !== inputAriaLabelledBy) {\n input.setAttribute('aria-labelledby', inputAriaLabelledBy);\n }\n if (input.hasAttribute('aria-label')) input.removeAttribute('aria-label');\n } else if (inputAriaLabel) {\n if (input.getAttribute('aria-label') !== inputAriaLabel) {\n input.setAttribute('aria-label', inputAriaLabel);\n }\n if (input.hasAttribute('aria-labelledby')) input.removeAttribute('aria-labelledby');\n } else {\n if (input.hasAttribute('aria-label')) input.removeAttribute('aria-label');\n if (input.hasAttribute('aria-labelledby')) input.removeAttribute('aria-labelledby');\n }\n\n // ─── Write the inner input's aria-describedby chain ───\n // Unify ALL descriptions through a single `aria-describedby` channel.\n // The W3C AccName algorithm ignores `aria-description` whenever\n // `aria-describedby` is also present, so consumer descriptions are\n // mirrored into a synthesized in-shadow span and that same-root id is\n // added to the chain.\n const consumerDescSpan = this.shadowRoot?.getElementById(this._consumerDescId) ?? null;\n const consumerDescText = flattenText(consumerDescEls);\n if (consumerDescSpan && consumerDescSpan.textContent !== consumerDescText) {\n consumerDescSpan.textContent = consumerDescText;\n }\n\n const describedByIds: string[] = [];\n if (consumerDescText && consumerDescSpan) {\n describedByIds.push(this._consumerDescId);\n }\n if (helpEl && !hasError && this._hasHelpSlot) {\n describedByIds.push(this._helpId);\n }\n if (errorEl && hasError) {\n describedByIds.push(this._errorId);\n }\n if (describedByIds.length > 0) {\n const value = describedByIds.join(' ');\n if (input.getAttribute('aria-describedby') !== value) {\n input.setAttribute('aria-describedby', value);\n }\n } else if (input.hasAttribute('aria-describedby')) {\n input.removeAttribute('aria-describedby');\n }\n\n // Never write `aria-description` on the inner input — silently dropped by\n // AccName whenever `aria-describedby` is also present. Strip defensively.\n if (input.hasAttribute('aria-description')) {\n input.removeAttribute('aria-description');\n }\n }\n\n /**\n * (Re-)installs the help-text slot text/visibility observer.\n * @internal\n */\n private _installHelpSlotTextObserver(slot: HTMLSlotElement | null): void {\n this._helpSlotTextObserver?.disconnect();\n if (!slot) {\n this._helpSlotTextObserver = null;\n return;\n }\n const observer = new MutationObserver(() => {\n this._hasHelpSlot = this._readHelpSlotStateSync(slot);\n this._syncHostAriaSemantics();\n });\n slot.assignedNodes().forEach((node) => {\n if (node.nodeType !== Node.ELEMENT_NODE) {\n observer.observe(node, {\n characterData: true,\n childList: true,\n subtree: true,\n });\n return;\n }\n observer.observe(node, {\n characterData: true,\n childList: true,\n subtree: true,\n attributes: true,\n attributeFilter: ['aria-hidden', 'hidden'],\n });\n });\n this._helpSlotTextObserver = observer;\n }\n\n /**\n * (Re-)installs the error slot text/visibility observer.\n * @internal\n */\n private _installErrorSlotTextObserver(slot: HTMLSlotElement | null): void {\n this._errorSlotTextObserver?.disconnect();\n if (!slot) {\n this._errorSlotTextObserver = null;\n return;\n }\n const observer = new MutationObserver(() => {\n this._hasErrorSlot = this._readErrorSlotStateSync(slot);\n this._syncHostAriaSemantics();\n });\n slot.assignedNodes().forEach((node) => {\n if (node.nodeType !== Node.ELEMENT_NODE) {\n observer.observe(node, {\n characterData: true,\n childList: true,\n subtree: true,\n });\n return;\n }\n observer.observe(node, {\n characterData: true,\n childList: true,\n subtree: true,\n attributes: true,\n attributeFilter: ['aria-hidden', 'hidden'],\n });\n });\n this._errorSlotTextObserver = observer;\n }\n\n /**\n * (Re-)installs the label slot text/visibility observer over the current\n * set of slotted label elements.\n * @internal\n */\n private _installLabelSlotTextObserver(elements: Element[]): void {\n this._labelSlotTextObserver?.disconnect();\n if (elements.length === 0) {\n this._labelSlotTextObserver = null;\n return;\n }\n const observer = new MutationObserver(() => {\n const fragments: string[] = [];\n for (const el of elements) {\n if (el.getAttribute('aria-hidden') === 'true') continue;\n const t = flattenAccName(el);\n if (t) fragments.push(t);\n }\n const trimmed = fragments.join(' ').replace(/\\s+/g, ' ').trim();\n this._labelSlotText = trimmed;\n this._hasLabelSlot = trimmed.length > 0;\n this._refreshLabelSource();\n this._syncHostAriaSemantics();\n });\n for (const el of elements) {\n observer.observe(el, {\n characterData: true,\n childList: true,\n subtree: true,\n attributes: true,\n attributeFilter: ['aria-hidden', 'hidden'],\n });\n }\n this._labelSlotTextObserver = observer;\n }\n\n /**\n * Recomputes the discriminated label source. @internal\n */\n private _refreshLabelSource(): void {\n if (this.label) {\n this._labelSource = 'string';\n } else if (this._hasLabelSlot) {\n this._labelSource = 'slot';\n } else {\n this._labelSource = 'none';\n }\n }\n\n // ─── Form Integration ───\n\n /** @internal */\n override _updateValidity(): void {\n if (this.required && !this.value) {\n this._internals.setValidity(\n { valueMissing: true },\n this.error || 'Please select a time.',\n this._inputEl ?? undefined,\n );\n } else {\n this._internals.setValidity({});\n }\n // Re-sync ARIA after every setValidity() so `aria-invalid` reflects\n // freshly computed validity.\n this._syncHostAriaSemantics();\n }\n\n /** @internal */\n protected override _onFormReset(): void {\n this.value = '';\n this._inputDisplayValue = '';\n this._internals.setFormValue(null);\n this._closeListbox();\n this._resetInteractionState();\n }\n\n /** @internal */\n protected override _onFormStateRestore(\n state: File | string | FormData | null,\n _mode: 'restore' | 'autocomplete',\n ): void {\n if (typeof state !== 'string') return;\n const clamped = clampValue(state, this.min, this.max);\n this.value = clamped;\n }\n\n /** @internal */\n protected override _onFormDisabled(disabled: boolean): void {\n this.disabled = disabled;\n }\n\n // ─── Listbox helpers ───\n\n /** @internal */\n private _openListbox(): void {\n if (this._open) return;\n const selectedIndex = this._slots.findIndex((s) => s.value === this.value);\n this._activeIndex = selectedIndex >= 0 ? selectedIndex : 0;\n this._open = true;\n }\n\n /** @internal */\n private _closeListbox(): void {\n if (!this._open) return;\n this._open = false;\n this._activeIndex = -1;\n this._handleInteractionBlur();\n }\n\n /** @internal */\n private _scrollActiveOptionIntoView(): void {\n if (!this._listboxEl) return;\n const active = this._listboxEl.querySelector<HTMLElement>('.field__option--active');\n active?.scrollIntoView({ block: 'nearest' });\n }\n\n /** @internal */\n private _selectSlot(slot: TimeSlot): void {\n const clamped = clampValue(slot.value, this.min, this.max);\n this.value = clamped;\n this._handleInteractionInput();\n this._closeListbox();\n this._dispatchChange(clamped);\n }\n\n // ─── Slot tracking ───\n\n /** @internal */\n private _handleLabelSlotChange(e: Event): void {\n if (!(e.target instanceof HTMLSlotElement)) return;\n const state = this._readLabelSlotState(e.target);\n this._hasLabelSlot = state.hasUsefulName;\n this._slottedLabelEls = state.elements;\n this._labelSlotText = state.text;\n this._installLabelSlotTextObserver(state.elements);\n this._refreshLabelSource();\n this._syncHostAriaSemantics();\n }\n\n /** @internal */\n private _handleErrorSlotChange(e: Event): void {\n if (!(e.target instanceof HTMLSlotElement)) return;\n this._hasErrorSlot = this._readErrorSlotStateSync(e.target);\n this._installErrorSlotTextObserver(e.target);\n this._syncHostAriaSemantics();\n }\n\n /** @internal */\n private _handleHelpSlotChange(e: Event): void {\n if (!(e.target instanceof HTMLSlotElement)) return;\n this._hasHelpSlot = this._readHelpSlotStateSync(e.target);\n this._installHelpSlotTextObserver(e.target);\n this._syncHostAriaSemantics();\n }\n\n // ─── Event Dispatch ───\n\n /** @internal */\n private _dispatchChange(value: string): void {\n this.dispatchEvent(\n new CustomEvent<{ value: string }>('hx-change', {\n bubbles: true,\n composed: true,\n detail: { value },\n }),\n );\n }\n\n // ─── Input Handlers ───\n\n /** @internal */\n private _handleInputClick(): void {\n if (!this.disabled) this._openListbox();\n }\n\n /** @internal */\n private _handleToggleClick(e: MouseEvent): void {\n e.stopPropagation();\n if (this.disabled) return;\n if (this._open) {\n this._closeListbox();\n } else {\n this._openListbox();\n this._inputEl?.focus();\n }\n }\n\n /** @internal */\n private _handleInputInput(e: Event): void {\n const target = e.target as HTMLInputElement;\n this._inputDisplayValue = target.value;\n if (!this._open) this._openListbox();\n }\n\n /** @internal */\n private _handleInputChange(e: Event): void {\n const target = e.target as HTMLInputElement;\n const raw = target.value.trim();\n\n if (!raw) {\n this.value = '';\n this._handleInteractionInput();\n this._handleInteractionBlur();\n this._internals.setFormValue(null);\n this._dispatchChange('');\n return;\n }\n\n const parsed = parseUserInput(raw);\n if (parsed) {\n const clamped = clampValue(parsed, this.min, this.max);\n this.value = clamped;\n this._handleInteractionInput();\n this._handleInteractionBlur();\n this._dispatchChange(clamped);\n } else {\n this._inputDisplayValue = this.value\n ? this.format === '12h'\n ? to12h(this.value)\n : this.value\n : '';\n }\n }\n\n /** @internal */\n private _handleInputKeyDown(e: KeyboardEvent): void {\n switch (e.key) {\n case 'ArrowDown':\n e.preventDefault();\n if (!this._open) {\n this._openListbox();\n } else {\n this._activeIndex = Math.min(this._activeIndex + 1, this._slots.length - 1);\n this._scrollActiveOptionIntoView();\n }\n break;\n\n case 'ArrowUp':\n e.preventDefault();\n if (this._open) {\n this._activeIndex = Math.max(this._activeIndex - 1, 0);\n this._scrollActiveOptionIntoView();\n }\n break;\n\n case 'Enter':\n if (this._open && this._activeIndex >= 0) {\n e.preventDefault();\n const slot = this._slots[this._activeIndex];\n if (slot) this._selectSlot(slot);\n }\n break;\n\n case 'Escape':\n e.preventDefault();\n this._closeListbox();\n break;\n\n case 'Home':\n if (this._open) {\n e.preventDefault();\n this._activeIndex = 0;\n this._scrollActiveOptionIntoView();\n }\n break;\n\n case 'End':\n if (this._open) {\n e.preventDefault();\n this._activeIndex = this._slots.length - 1;\n this._scrollActiveOptionIntoView();\n }\n break;\n\n case 'Tab':\n this._closeListbox();\n break;\n }\n }\n\n /** @internal */\n private _handleOptionPointerDown(e: MouseEvent): void {\n e.preventDefault();\n }\n\n /** @internal */\n private _handleOptionClick(slot: TimeSlot): void {\n this._selectSlot(slot);\n this._inputEl?.focus();\n }\n\n /** @internal */\n private _handleOptionMouseEnter(index: number): void {\n this._activeIndex = index;\n }\n\n // ─── Public API ───\n\n /** Moves focus to the time input element. */\n override focus(options?: FocusOptions): void {\n this._inputEl?.focus(options);\n }\n\n // ─── Render ───\n\n override render() {\n const hasError = !!this.error || this._hasErrorSlot;\n const slots = this._slots;\n\n const fieldClasses = {\n field: true,\n 'field--error': hasError,\n 'field--disabled': this.disabled,\n 'field--required': this.required,\n };\n\n const activeDescendant =\n this._open && this._activeIndex >= 0\n ? `${this._listboxId}-option-${this._activeIndex}`\n : undefined;\n\n const placeholder = this.format === '12h' ? 'hh:mm AM' : 'hh:mm';\n\n // W3C APG editable combobox (option I): role=\"combobox\" lives on the\n // inner <input>, replacing the implicit textbox role. All combobox state\n // ARIA — aria-expanded, aria-controls, aria-activedescendant,\n // aria-autocomplete, aria-haspopup, aria-required, aria-invalid,\n // aria-disabled — is bound on the input via Lit. aria-label /\n // aria-labelledby / aria-describedby are written imperatively by\n // _syncHostAriaSemantics after consumer-IDREF resolution.\n return html`\n <div part=\"field\" class=${classMap(fieldClasses)}>\n <!-- Label -->\n <slot name=\"label\" @slotchange=${this._handleLabelSlotChange}>\n ${this.label\n ? html`\n <label part=\"label\" id=${this._labelId} class=\"field__label\" for=${this._id}>\n ${this.label}\n ${this.required\n ? html`<span class=\"field__required-marker\" aria-hidden=\"true\">*</span>`\n : nothing}\n </label>\n `\n : nothing}\n </slot>\n\n <!-- Combobox wrapper; role=\"combobox\" lives on the input per ARIA 1.2 -->\n <div class=\"field__combobox\">\n <input\n part=\"input\"\n class=\"field__input\"\n id=${this._id}\n type=\"text\"\n inputmode=\"text\"\n autocomplete=\"off\"\n spellcheck=\"false\"\n role=\"combobox\"\n aria-expanded=${this._open ? 'true' : 'false'}\n aria-haspopup=\"listbox\"\n .value=${live(this._inputDisplayValue)}\n placeholder=${placeholder}\n ?required=${this.required}\n ?disabled=${this.disabled}\n name=${ifDefined(this.name || undefined)}\n aria-autocomplete=\"list\"\n aria-controls=${this._listboxId}\n aria-activedescendant=${ifDefined(activeDescendant)}\n aria-invalid=${this._invalid ? 'true' : 'false'}\n aria-required=${this.required ? 'true' : 'false'}\n aria-disabled=${this.disabled ? 'true' : nothing}\n @click=${this._handleInputClick}\n @input=${this._handleInputInput}\n @change=${this._handleInputChange}\n @keydown=${this._handleInputKeyDown}\n />\n\n <!-- Toggle button -->\n <button\n part=\"toggle\"\n type=\"button\"\n class=\"field__toggle\"\n tabindex=\"-1\"\n aria-label=${this._open ? 'Close time picker' : 'Open time picker'}\n ?disabled=${this.disabled}\n @click=${this._handleToggleClick}\n >\n <!-- Clock icon -->\n <svg\n width=\"16\"\n height=\"16\"\n viewBox=\"0 0 16 16\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n aria-hidden=\"true\"\n >\n <circle cx=\"8\" cy=\"8\" r=\"6.5\" stroke=\"currentColor\" stroke-width=\"1.25\" />\n <path\n d=\"M8 4.5V8L10.5 10\"\n stroke=\"currentColor\"\n stroke-width=\"1.25\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n />\n </svg>\n </button>\n\n <!-- Dropdown listbox: always in DOM so aria-controls is never a dangling reference (WCAG 4.1.2). Hidden via the boolean hidden attribute when closed. -->\n <ul\n part=\"listbox\"\n class=\"field__listbox\"\n id=${this._listboxId}\n role=\"listbox\"\n aria-label=${this.label || this.accessibleLabel || 'Time options'}\n ?hidden=${!this._open}\n >\n ${this._open\n ? repeat(\n slots,\n (slot) => slot.value,\n (slot, index) => {\n const isSelected = slot.value === this.value;\n const isActive = index === this._activeIndex;\n return html`\n <li\n part=\"option\"\n class=${classMap({\n field__option: true,\n 'field__option--selected': isSelected,\n 'field__option--active': isActive,\n })}\n id=\"${this._listboxId}-option-${index}\"\n role=\"option\"\n aria-selected=${isSelected ? 'true' : 'false'}\n @pointerdown=${this._handleOptionPointerDown}\n @click=${() => this._handleOptionClick(slot)}\n @mouseenter=${() => this._handleOptionMouseEnter(index)}\n >\n ${slot.label}\n </li>\n `;\n },\n )\n : nothing}\n </ul>\n </div>\n\n <!--\n Persistent error live region. role=\"alert\" is set from first paint\n so the WAI-ARIA contract for live updates is honoured.\n -->\n <div\n part=\"error\"\n class=\"field__error\"\n id=${this._errorId}\n role=\"alert\"\n ?hidden=${!hasError}\n >\n <slot name=\"error\" @slotchange=${this._handleErrorSlotChange}\n >${this._announcedError}</slot\n >\n </div>\n\n <!-- Help slot -->\n <div\n part=\"help-text\"\n class=\"field__help-text\"\n id=${this._helpId}\n ?hidden=${!this._hasHelpSlot || hasError}\n >\n <slot name=\"help-text\" @slotchange=${this._handleHelpSlotChange}></slot>\n </div>\n\n <!--\n Synthesized in-shadow mirror of the consumer-resolved description\n text. Its id is appended to the inner input's aria-describedby chain\n so AT picks the consumer description up through the standard\n described-by channel without needing aria-description (which W3C\n AccName drops whenever aria-describedby is also present).\n -->\n <span id=${this._consumerDescId} class=\"field__sr-only\" aria-hidden=\"false\"></span>\n </div>\n `;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'hx-time-picker': HelixTimePicker;\n }\n}\n"],"names":["helixTimePickerStyles","css","parseHHMM","raw","match","hours","minutes","toHHMM","to12h","value","parsed","period","h","generateSlots","minTime","maxTime","stepMinutes","format","minParsed","maxParsed","minTotal","maxTotal","step","slots","t","m","clampValue","total","parseUserInput","trimmed","hhmm","twelve","flattenAccName","root","result","walker","node","el","textNode","_nextTimePickerId","createIdCounter","HelixTimePicker","FormMixin","HelixElement","_a","key","ctor","supportsIdrefElementReferences","records","consumerCleared","record","oldValue","newValue","installAriaIdrefMirror","_b","_c","_d","_e","_f","changed","labelSlot","state","helpSlot","errorSlot","slot","nodes","elements","fragments","elText","txt","trimmedText","unique","observer","internals","input","isInvalidEarly","liveAriaLabel","hostAriaLabel","internalLabel","slottedLabelEls","helpEl","errorEl","liveLabelledBy","liveDescribedBy","consumerLabelEls","resolveIdrefTokens","hasEffectiveLabelledBy","consumerDescEls","hasError","isInvalid","explicitAccessibleLabel","isVisibleForAccName","labelElsForInternals","descElsForInternals","refsInternals","flattenText","els","inputAriaLabel","inputAriaLabelledBy","labelledByFlat","flat","consumerDescSpan","consumerDescText","describedByIds","_mode","clamped","disabled","selectedIndex","s","active","target","index","options","fieldClasses","activeDescendant","placeholder","html","classMap","nothing","live","ifDefined","repeat","isSelected","isActive","forcedColorsField","__decorateClass","property","query","customElement"],"mappings":";;;;;;;;;;;AAEO,MAAMA,KAAwBC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;A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"}
|
|
@@ -3,7 +3,7 @@ import { query as m, property as n, state as u, customElement as y } from "lit/d
|
|
|
3
3
|
import { classMap as _ } from "lit/directives/class-map.js";
|
|
4
4
|
import { ifDefined as b } from "lit/directives/if-defined.js";
|
|
5
5
|
import { f as k } from "./forced-colors-CTEDFRGa.js";
|
|
6
|
-
import { s as A, i as T, r as g } from "./aria-idref-
|
|
6
|
+
import { s as A, i as T, r as g } from "./aria-idref-CxvyzfQS.js";
|
|
7
7
|
import { H as S } from "./helix-element-BNEYeiys.js";
|
|
8
8
|
const L = x`
|
|
9
9
|
:host {
|
|
@@ -574,4 +574,4 @@ r = a([
|
|
|
574
574
|
export {
|
|
575
575
|
r as H
|
|
576
576
|
};
|
|
577
|
-
//# sourceMappingURL=hx-toggle-button-
|
|
577
|
+
//# sourceMappingURL=hx-toggle-button-BQ81EDkl.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hx-toggle-button-Dcz9IlUm.js","sources":["../../src/components/hx-toggle-button/hx-toggle-button.styles.ts","../../src/components/hx-toggle-button/hx-toggle-button.ts"],"sourcesContent":["import { css } from 'lit';\n\nexport const helixToggleButtonStyles = css`\n :host {\n display: inline-block;\n }\n\n :host([disabled]) {\n pointer-events: none;\n opacity: var(--hx-opacity-disabled, 0.5);\n }\n\n /* ─── Base Button ─── */\n\n .button {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n gap: var(--hx-space-2, 0.5rem);\n border: var(--hx-border-width-thin, 1px) solid var(--hx-toggle-button-border-color, transparent);\n border-radius: var(--hx-toggle-button-border-radius, var(--hx-border-radius-md, 0.375rem));\n background-color: var(--hx-toggle-button-bg, var(--hx-color-primary-500, #429797));\n color: var(--hx-toggle-button-color, var(--hx-color-text-on-primary, #ffffff));\n font-family: var(--hx-toggle-button-font-family, var(--hx-font-family-sans, sans-serif));\n font-weight: var(--hx-toggle-button-font-weight, var(--hx-font-weight-semibold, 600));\n line-height: var(--hx-line-height-tight, 1.25);\n cursor: pointer;\n transition:\n background-color var(--hx-transition-fast, 150ms ease),\n color var(--hx-transition-fast, 150ms ease),\n border-color var(--hx-transition-fast, 150ms ease),\n box-shadow var(--hx-transition-fast, 150ms ease);\n text-decoration: none;\n white-space: nowrap;\n user-select: none;\n -webkit-user-select: none;\n }\n\n /*\n * Host-focus path: on the modern (IDL element-references) render branch the\n * host is the tabbable surface (tabindex=0) and the inner <button> is\n * demoted to tabindex=-1. Drive the focus ring from ':host(:focus-visible)'\n * so keyboard users still see a visible affordance. Codex round-11 P1.\n */\n :host(:focus-visible) .button {\n outline: var(--hx-focus-ring-width, 2px) solid\n var(--hx-toggle-button-focus-ring-color, var(--hx-focus-ring-color, #0f7078));\n outline-offset: var(--hx-focus-ring-offset, 2px);\n }\n\n /*\n * Fallback (no-IDL-ref) path: the host carries tabindex=-1 and the inner\n * <button> is the tab target. Native :focus-visible drives the ring.\n */\n .button:focus-visible {\n outline: var(--hx-focus-ring-width, 2px) solid\n var(--hx-toggle-button-focus-ring-color, var(--hx-focus-ring-color, #0f7078));\n outline-offset: var(--hx-focus-ring-offset, 2px);\n }\n\n .button:hover {\n filter: brightness(var(--hx-filter-brightness-hover, 0.9));\n }\n\n .button:active {\n filter: brightness(var(--hx-filter-brightness-active, 0.8));\n }\n\n /* ─── Size Variants ─── */\n\n /* WCAG 2.5.5 (healthcare mandate): minimum 44px touch target for sm variant.\n min-height uses --hx-touch-target-min to guarantee the interactive area\n meets the threshold even though the visual size token is smaller. */\n .button--sm {\n padding: var(--hx-space-1, 0.25rem) var(--hx-space-3, 0.75rem);\n font-size: var(--hx-font-size-sm, 0.875rem);\n min-height: var(--hx-touch-target-min, 2.75rem);\n }\n\n .button--md {\n padding: var(--hx-space-2, 0.5rem) var(--hx-space-4, 1rem);\n font-size: var(--hx-font-size-md, 1rem);\n min-height: var(--hx-size-10, 2.5rem);\n }\n\n .button--lg {\n padding: var(--hx-space-3, 0.75rem) var(--hx-space-6, 1.5rem);\n font-size: var(--hx-font-size-lg, 1.125rem);\n min-height: var(--hx-size-12, 3rem);\n }\n\n /* ─── Style Variants ─── */\n\n .button--primary {\n --hx-toggle-button-bg: var(--hx-color-primary-500, #429797);\n --hx-toggle-button-color: var(--hx-color-text-on-primary, #ffffff);\n --hx-toggle-button-border-color: transparent;\n }\n\n /*\n * secondary/ghost paint primary text on the surface (white). primary-500\n * (#429797) on white = 3.43:1 — fails AA at body sizes. shift to\n * primary-600 (#0F7078) = 6.06:1 — AA pass. border keeps primary-500\n * for the brand affordance (3:1 non-text contrast still met).\n */\n .button--secondary {\n --hx-toggle-button-bg: transparent;\n --hx-toggle-button-color: var(--hx-color-primary-600, #0f7078);\n --hx-toggle-button-border-color: var(--hx-color-primary-600, #0f7078);\n }\n\n .button--secondary:hover {\n --hx-toggle-button-bg: var(--hx-color-primary-50, #ebf8f8);\n }\n\n .button--tertiary {\n --hx-toggle-button-bg: var(--hx-color-surface-sunken, #ebeee9);\n --hx-toggle-button-color: var(--hx-color-text-primary, #0d1825);\n --hx-toggle-button-border-color: transparent;\n }\n\n .button--tertiary:hover {\n --hx-toggle-button-bg: var(--hx-color-surface-raised, #f5f8f3);\n }\n\n .button--ghost {\n --hx-toggle-button-bg: transparent;\n --hx-toggle-button-color: var(--hx-color-primary-600, #0f7078);\n --hx-toggle-button-border-color: transparent;\n }\n\n .button--ghost:hover {\n --hx-toggle-button-bg: var(--hx-color-surface-raised, #f5f8f3);\n }\n\n .button--outline {\n --hx-toggle-button-bg: transparent;\n --hx-toggle-button-color: var(--hx-color-text-primary, #0d1825);\n --hx-toggle-button-border-color: var(--hx-color-border-strong, #66787b);\n }\n\n .button--outline:hover {\n --hx-toggle-button-bg: var(--hx-color-surface-raised, #f5f8f3);\n }\n\n /* ─── Pressed State ─── */\n\n /*\n * Primary: already uses solid primary bg; pressed deepens to primary-700\n * to give clear visual feedback without introducing a new color.\n *\n * AA fix: text.on-primary (= neutral-900 #0D1825) on primary-700 (#0F6363)\n * = 2.54:1 — fails AA. Pin fg at neutral-0 for the darker pressed fill\n * (neutral-0 on primary-700 = 7.03:1, AAA pass). Mirrors hx-toast\n * precedent (commit 300e21ab0) and hx-button hover treatment.\n * Note: secondary.pressed below uses primary-500 and stays at 5.20:1 —\n * leave it alone.\n */\n .button--primary.button--pressed {\n --hx-toggle-button-bg: var(--hx-toggle-button-pressed-bg, var(--hx-color-primary-700, #0f6363));\n --hx-toggle-button-color: var(\n --hx-toggle-button-pressed-color,\n var(--hx-color-neutral-0, #ffffff)\n );\n --hx-toggle-button-border-color: transparent;\n }\n\n /*\n * Secondary: unpressed is outlined/transparent; pressed fills with primary bg\n * so the state change is immediately legible.\n */\n .button--secondary.button--pressed {\n --hx-toggle-button-bg: var(--hx-toggle-button-pressed-bg, var(--hx-color-primary-500, #429797));\n --hx-toggle-button-color: var(\n --hx-toggle-button-pressed-color,\n var(--hx-color-text-on-primary, #ffffff)\n );\n --hx-toggle-button-border-color: var(--hx-color-primary-500, #429797);\n }\n\n /* Tertiary pressed: use primary-100 bg + primary-700 text + border for WCAG 3:1 non-text contrast. */\n .button--tertiary.button--pressed {\n --hx-toggle-button-bg: var(--hx-toggle-button-pressed-bg, var(--hx-color-primary-100, #dbf0f0));\n --hx-toggle-button-color: var(\n --hx-toggle-button-pressed-color,\n var(--hx-color-primary-700, #0f6363)\n );\n --hx-toggle-button-border-color: var(--hx-color-primary-600, #0f7078);\n box-shadow: inset 0 0 0 1px var(--hx-color-primary-600, #0f7078);\n }\n\n /* Ghost pressed: subtle neutral fill, matching hover behavior as a baseline. */\n .button--ghost.button--pressed {\n --hx-toggle-button-bg: var(--hx-toggle-button-pressed-bg, var(--hx-color-primary-100, #dbf0f0));\n --hx-toggle-button-color: var(\n --hx-toggle-button-pressed-color,\n var(--hx-color-primary-700, #0f6363)\n );\n --hx-toggle-button-border-color: transparent;\n }\n\n /* Outline pressed: fills with a neutral tint, darkens the border, and adds an inset shadow for WCAG 3:1 non-text contrast. */\n .button--outline.button--pressed {\n --hx-toggle-button-bg: var(\n --hx-toggle-button-pressed-bg,\n var(--hx-color-surface-sunken, #ebeee9)\n );\n --hx-toggle-button-color: var(\n --hx-toggle-button-pressed-color,\n var(--hx-color-text-primary, #0d1825)\n );\n --hx-toggle-button-border-color: var(--hx-color-text-muted, #4a5362);\n box-shadow: inset 0 0 0 1px var(--hx-color-neutral-500, #66787b);\n }\n\n /* ─── Disabled ─── */\n\n .button[disabled] {\n cursor: not-allowed;\n }\n\n /* ─── Prefix / Suffix / Label ─── */\n\n .button__prefix,\n .button__suffix {\n display: inline-flex;\n align-items: center;\n flex-shrink: 0;\n }\n\n .button__label {\n flex: 1 1 auto;\n }\n\n /* ─── Reduced Motion ─── */\n\n @media (prefers-reduced-motion: reduce) {\n .button {\n transition: none;\n }\n }\n\n /* ─── High Contrast Mode (forced-colors) ─── */\n\n @media (forced-colors: active) {\n .button {\n forced-color-adjust: none;\n background-color: ButtonFace;\n color: ButtonText;\n border: 2px solid ButtonText;\n }\n\n :host(:focus-visible) .button,\n .button:focus-visible {\n outline: 3px solid Highlight;\n outline-offset: 2px;\n }\n\n .button--pressed {\n background-color: Highlight;\n color: HighlightText;\n border-color: Highlight;\n box-shadow: none;\n }\n\n .button[disabled] {\n background-color: ButtonFace;\n color: GrayText;\n border-color: GrayText;\n opacity: 1;\n }\n\n :host([disabled]) {\n opacity: 1;\n }\n }\n`;\n","import { html, nothing, type PropertyValues } from 'lit';\nimport '../../utilities/document-token-adoption.js';\nimport { customElement, property, query, state } from 'lit/decorators.js';\nimport { classMap } from 'lit/directives/class-map.js';\nimport { ifDefined } from 'lit/directives/if-defined.js';\nimport { HelixElement } from '../../base/index.js';\nimport { helixToggleButtonStyles } from './hx-toggle-button.styles.js';\nimport { forcedColorsInteractive } from '../../styles/forced-colors.js';\nimport {\n installAriaIdrefMirror,\n resolveIdrefTokens,\n supportsIdrefElementReferences,\n type AriaIdrefMirrorHandle,\n} from '../../utils/aria-idref.js';\n\n/** Detail for the hx-toggle event dispatched by hx-toggle-button. */\nexport interface HxToggleDetail {\n pressed: boolean;\n}\n\n/**\n * A two-state toggle button that communicates a pressed/unpressed status to\n * assistive technology via `aria-pressed`. Supports multiple visual variants\n * and sizes, prefix/suffix slots, full ElementInternals form association, and\n * a distinct pressed visual state for every variant.\n *\n * @summary Two-state toggle button with pressed/unpressed ARIA semantics.\n *\n * @tag hx-toggle-button\n *\n * @slot - Default slot for the button label text or content.\n * @slot prefix - Icon or content rendered before the label.\n * @slot suffix - Icon or content rendered after the label.\n *\n * @fires {CustomEvent<{pressed: boolean}>} hx-toggle - Dispatched when the\n * toggle state changes. Not dispatched when the button is disabled.\n *\n * @csspart button - The native `<button>` element.\n * @csspart label - The label text wrapper span.\n * @csspart prefix - The prefix slot container span.\n * @csspart suffix - The suffix slot container span.\n *\n * @cssprop [--hx-toggle-button-bg=var(--hx-color-primary-500)] - Button background color.\n * @cssprop [--hx-toggle-button-color=var(--hx-color-neutral-0)] - Button text color.\n * @cssprop [--hx-toggle-button-border-color=transparent] - Button border color.\n * @cssprop [--hx-toggle-button-border-radius=var(--hx-border-radius-md)] - Button border radius.\n * @cssprop [--hx-toggle-button-font-family=var(--hx-font-family-sans)] - Button font family.\n * @cssprop [--hx-toggle-button-font-weight=var(--hx-font-weight-semibold)] - Button font weight.\n * @cssprop [--hx-toggle-button-focus-ring-color=var(--hx-focus-ring-color)] - Focus ring color.\n * @cssprop [--hx-toggle-button-pressed-bg=var(--hx-color-primary-500)] - Background when pressed (variant-specific fallback applies).\n * @cssprop [--hx-toggle-button-pressed-color=var(--hx-color-neutral-0)] - Text color when pressed (variant-specific fallback applies).\n * @cssprop [--hx-opacity-disabled] - Opacity.\n * @cssprop [--hx-space-2] - Spacing token.\n * @cssprop [--hx-border-width-thin] - Width.\n * @cssprop [--hx-border-radius-md] - CSS custom property.\n * @cssprop [--hx-color-primary-500] - Color.\n * @cssprop [--hx-color-neutral-0] - Color.\n * @cssprop [--hx-font-family-sans] - Font family.\n * @cssprop [--hx-font-weight-semibold] - Font weight.\n * @cssprop [--hx-line-height-tight] - Line height.\n * @cssprop [--hx-transition-fast] - Transition timing.\n * @cssprop [--hx-focus-ring-width] - Width.\n * @cssprop [--hx-focus-ring-color] - Color.\n * @cssprop [--hx-color-primary-400] - Color.\n * @cssprop [--hx-focus-ring-offset] - CSS custom property.\n * @cssprop [--hx-filter-brightness-hover] - CSS filter.\n * @cssprop [--hx-filter-brightness-active] - CSS filter.\n * @cssprop [--hx-touch-target-min] - Minimum touch target size.\n * @cssprop [--hx-space-1] - Spacing token.\n * @cssprop [--hx-space-3] - Spacing token.\n * @cssprop [--hx-font-size-sm] - Font size.\n * @cssprop [--hx-space-4] - Spacing token.\n * @cssprop [--hx-font-size-md] - Font size.\n * @cssprop [--hx-size-10] - Size token.\n * @cssprop [--hx-space-6] - Spacing token.\n * @cssprop [--hx-font-size-lg] - Font size.\n * @cssprop [--hx-size-12] - Size token.\n * @cssprop [--hx-color-primary-50] - Color.\n * @cssprop [--hx-color-neutral-100] - Color.\n * @cssprop [--hx-color-neutral-900] - Color.\n * @cssprop [--hx-color-neutral-200] - Color.\n * @cssprop [--hx-color-neutral-300] - Color.\n * @cssprop [--hx-color-primary-700] - Color.\n * @cssprop [--hx-color-primary-100] - Color.\n * @cssprop [--hx-color-neutral-50] - Color.\n * @cssprop [--hx-color-neutral-500] - Color.\n */\n@customElement('hx-toggle-button')\nexport class HelixToggleButton extends HelixElement {\n static override styles = [helixToggleButtonStyles, forcedColorsInteractive];\n\n // ─── Form Association ───\n\n /** @internal */\n static override formAssociated = true;\n\n /** @internal */\n @query('slot:not([name])') private _defaultSlot!: HTMLSlotElement | null;\n\n // ─── Public Properties ───\n\n /**\n * Whether the toggle button is in the pressed state.\n * Reflected as an attribute so CSS selectors like `:host([pressed])` work.\n * @attr pressed\n */\n @property({ type: Boolean, reflect: true })\n pressed = false;\n\n /**\n * Visual style variant of the button.\n * @attr variant\n */\n @property({ type: String, reflect: true })\n variant: 'primary' | 'secondary' | 'tertiary' | 'ghost' | 'outline' = 'secondary';\n\n /**\n * Size of the button.\n * @attr hx-size\n */\n @property({ type: String, reflect: true, attribute: 'hx-size' })\n size: 'sm' | 'md' | 'lg' = 'md';\n\n /**\n * Whether the button is disabled. Prevents all interaction and form actions.\n * @attr disabled\n */\n @property({ type: Boolean, reflect: true })\n disabled = false;\n\n /**\n * Form field name submitted via ElementInternals when the button is pressed.\n * @attr name\n */\n @property({ type: String })\n name: string | undefined = undefined;\n\n /**\n * Form field value submitted via ElementInternals when the button is pressed.\n * @attr value\n */\n @property({ type: String })\n value: string | undefined = undefined;\n\n /**\n * Accessible label forwarded to the inner `<button>` as `aria-label`.\n * Required for icon-only toggle buttons where no visible text is present.\n * @attr label\n */\n @property({ type: String })\n label: string | undefined = undefined;\n\n /**\n * When true, the button must be in the pressed state for the form to be submitted.\n * @attr required\n */\n @property({ type: Boolean, reflect: true })\n required = false;\n\n // ─── Form API ───\n\n /** Returns the ValidityState object. */\n override get validity(): ValidityState {\n return this._internals.validity;\n }\n\n /** Returns the current validation message. */\n override get validationMessage(): string {\n return this._internals.validationMessage;\n }\n\n /** Checks whether the button satisfies its constraints. */\n checkValidity(): boolean {\n return this._internals.checkValidity();\n }\n\n /** Reports validity and shows the browser's constraint validation UI. */\n reportValidity(): boolean {\n return this._internals.reportValidity();\n }\n\n /**\n * Handle for the shared IDREF observer. See `installAriaIdrefMirror()`.\n * @internal\n */\n private _ariaMirror: AriaIdrefMirrorHandle | null = null;\n\n /**\n * Default-slot text content captured for use as the host's accessible name\n * when no explicit `label`/`aria-label`/`aria-labelledby` is supplied.\n * Codex round-1 finding #9.\n * @internal\n */\n @state() private _slotLabelText: string = '';\n\n /** No-IDL-ref fallback tokens applied to the inner button. @internal */\n @state() private _fallbackAriaLabelledBy: string | null = null;\n /** @internal */\n @state() private _fallbackAriaDescribedBy: string | null = null;\n /** @internal */\n @state() private _fallbackAriaLabel: string | null = null;\n\n /**\n * Whether the platform supports IDL element references on `ElementInternals`.\n * Drives the render-time branch between the modern path (host is the\n * announced surface, inner button is `aria-hidden + tabindex=-1`) and the\n * fallback path (inner button is the announced surface, host is demoted).\n * Codex round-2 finding #2.\n * @internal\n */\n @state() private _supportsIdrefRefs = true;\n\n /**\n * Tracks whether the host's `tabindex` is managed by the component itself\n * (vs. set explicitly by a consumer). Codex round-14 P2: a consumer-supplied\n * `tabindex` (e.g. roving-tabindex toolbar pattern with `tabindex=\"-1\"`)\n * must survive disabled flips and re-renders. Only re-assert tabindex in\n * `updated()` when the component originally claimed it.\n * @internal\n */\n private _internalTabindexManaged = false;\n\n // ─── Lifecycle ───\n\n override connectedCallback(): void {\n super.connectedCallback();\n // Detect platform support for IDL element references. Codex round-2\n // finding #2: drives the render-time branch between modern (host\n // announced) and fallback (inner button announced) paths.\n this._supportsIdrefRefs = supportsIdrefElementReferences(this._internals);\n // Seed root-independent semantics from the moment of connection so AT\n // sees the toggle role + pressed state before the first paint.\n this._syncHostAriaSemantics();\n // Codex round-1 finding #1: host is the canonical announced surface on\n // modern browsers, so the inner `<button>` is demoted via\n // `aria-hidden + tabindex=-1`.\n // Codex round-2 finding #2: on no-IDL-ref browsers the inner button is\n // the announced surface (it carries native button + aria-pressed), so\n // the host is demoted to `tabindex=-1` and lets the inner button own\n // tab order + activation.\n // Codex round-14 P2: only claim ownership of `tabindex` when no consumer\n // value is present. Consumers using roving-tabindex toolbar patterns\n // must be able to set `tabindex=\"-1\"` on the host without it being\n // clobbered on every disabled flip. Note we still claim ownership when\n // disabled — the initial value is `-1` to keep the host out of tab order\n // and `updated()` re-asserts the appropriate value when disabled flips.\n if (!this.hasAttribute('tabindex')) {\n this._internalTabindexManaged = true;\n const enabledTabIndex = this._supportsIdrefRefs ? '0' : '-1';\n this.setAttribute('tabindex', this.disabled ? '-1' : enabledTabIndex);\n }\n this.addEventListener('keydown', this._handleHostKeyDown);\n this.addEventListener('click', this._handleHostClickRouted);\n this._ariaMirror = installAriaIdrefMirror(this, () => {\n this._syncHostAriaSemantics();\n });\n }\n\n override disconnectedCallback(): void {\n super.disconnectedCallback();\n this.removeEventListener('keydown', this._handleHostKeyDown);\n this.removeEventListener('click', this._handleHostClickRouted);\n // Codex round-13 P2: tear down the assigned-node text observer so a\n // detached host does not receive mutation callbacks from nodes that may\n // outlive it (e.g. lifted out of the slot but kept in the document).\n this._slotTextObserver?.disconnect();\n this._slotTextObserver = null;\n this._ariaMirror?.disconnect();\n this._ariaMirror = null;\n }\n\n /**\n * Host-level keydown handler. Active only on the modern path; on the\n * no-IDL-ref fallback the inner `<button>` owns native Space/Enter\n * activation. Codex round-2 finding #2.\n * @internal\n */\n private _handleHostKeyDown = (e: KeyboardEvent): void => {\n if (this.disabled) return;\n if (!this._supportsIdrefRefs) return;\n if (e.target !== this) return;\n if (e.key === ' ' || e.key === 'Enter') {\n e.preventDefault();\n this._invokeToggle();\n }\n };\n\n /**\n * Host-level click router. The inner `<button>` is `aria-hidden + tabindex=-1`\n * on modern browsers but still receives clicks via mouse activation; toggling\n * is handled by the inner `_handleClick`. Host-level clicks (composed path\n * origin === host) only come from AT activation or programmatic triggers,\n * so we route those to the toggle pipeline.\n *\n * Codex round-2 finding #2: on no-IDL-ref browsers the inner button is the\n * announced surface so this host-level routing is a no-op — AT activation\n * lands on the inner button directly.\n * @internal\n */\n private _handleHostClickRouted = (e: MouseEvent): void => {\n if (this.disabled) return;\n if (!this._supportsIdrefRefs) return;\n // Only fire when the host itself originated the click — inner-button\n // clicks bubble through here too but are handled by `_handleClick`.\n const path = e.composedPath();\n if (path[0] !== this) return;\n this._invokeToggle();\n };\n\n /** @internal */\n private _invokeToggle(): void {\n this.pressed = !this.pressed;\n this._syncFormValue();\n this.dispatchEvent(\n new CustomEvent<{ pressed: boolean }>('hx-toggle', {\n bubbles: true,\n composed: true,\n detail: { pressed: this.pressed },\n }),\n );\n }\n\n /**\n * Moves focus to the announced toggle-button surface. Codex round-1 finding\n * `#1` made the host the canonical focus target on modern engines so AT\n * announces a single widget. Round-7 finding `#9` extends that contract to\n * the no-IDL-ref fallback: when the host is demoted (`tabindex=-1`,\n * role/state cleared on `internals`) the inner `<button>` owns the announced\n * semantics and tab order, so programmatic `focus()` must redirect there —\n * otherwise scripted focus and error recovery land on the demoted host on\n * unsupported engines.\n */\n override focus(options?: FocusOptions): void {\n if (this._supportsIdrefRefs) {\n super.focus(options);\n return;\n }\n this.shadowRoot?.querySelector<HTMLButtonElement>('[part=\"button\"]')?.focus(options);\n }\n\n override firstUpdated(changedProperties: PropertyValues<this>): void {\n super.firstUpdated(changedProperties);\n\n // Track default-slot text content so it can serve as the accessible\n // name when no explicit label is set. Codex round-1 finding #9.\n this._captureSlotLabelText();\n // Codex round-13 P2: also observe in-place text mutations on assigned\n // nodes so framework-driven `Mute` → `Unmute` rewrites refresh the\n // cached label without requiring the consumer to swap the node.\n this._installSlotTextObserver();\n\n if (!this.label) {\n const slot = this._defaultSlot;\n const hasSlotText = slot\n ? slot.assignedNodes({ flatten: true }).some((n) => n.textContent?.trim())\n : false;\n if (!hasSlotText) {\n console.warn(\n '[hx-toggle-button] No accessible label found. Set the `label` attribute or provide slot text content for WCAG 4.1.2 compliance.',\n );\n }\n }\n }\n\n override updated(changedProperties: PropertyValues<this>): void {\n super.updated(changedProperties);\n\n if (\n changedProperties.has('pressed') ||\n changedProperties.has('value') ||\n changedProperties.has('required')\n ) {\n this._syncFormValue();\n }\n\n if (\n changedProperties.has('disabled') ||\n (changedProperties as Map<PropertyKey, unknown>).has('_supportsIdrefRefs')\n ) {\n // Codex round-2 finding #2: align host tabindex with the chosen\n // announced surface. On no-IDL-ref browsers the inner button owns\n // tab order, so re-enabling the host should leave it `tabindex=-1`.\n // Codex round-14 P2: only re-assert when the component owns tabindex.\n // Consumer-managed values (e.g. roving-tabindex toolbar with `-1`) must\n // not be overwritten on disabled flips or supports-flag transitions.\n if (this._internalTabindexManaged) {\n const enabledTabIndex = this._supportsIdrefRefs ? '0' : '-1';\n this.setAttribute('tabindex', this.disabled ? '-1' : enabledTabIndex);\n }\n }\n\n // Host-elevated ARIA semantics — see _syncHostAriaSemantics.\n this._syncHostAriaSemantics();\n }\n\n /**\n * Reads the default slot's flattened text content into `_slotLabelText`.\n * Called from `firstUpdated()` and `slotchange` so host-canonical semantics\n * pick up slotted label text. Codex round-1 finding #9.\n * @internal\n */\n private _captureSlotLabelText(): void {\n const slot = this._defaultSlot;\n if (!slot) {\n this._slotLabelText = '';\n return;\n }\n const text = slot\n .assignedNodes({ flatten: true })\n .map((n) => n.textContent ?? '')\n .join(' ')\n .trim();\n this._slotLabelText = text;\n }\n\n /**\n * Watches assigned default-slot nodes for in-place text mutations so the\n * cached `_slotLabelText` (and thus `internals.ariaLabel`) stays in sync\n * when a framework rewrites textContent of an already-assigned node without\n * replacing it. `slotchange` does NOT fire for those mutations, so a\n * separate observer is required. Codex round-13 P2.\n * @internal\n */\n private _slotTextObserver: MutationObserver | null = null;\n\n /**\n * (Re-)installs the mutation observer over the current set of assigned\n * default-slot nodes. Disconnects any prior observer first so detached\n * nodes stop firing into a torn-down host.\n * @internal\n */\n private _installSlotTextObserver(): void {\n this._slotTextObserver?.disconnect();\n const slot = this._defaultSlot;\n if (!slot) {\n this._slotTextObserver = null;\n return;\n }\n const observer = new MutationObserver(() => {\n this._captureSlotLabelText();\n this._syncHostAriaSemantics();\n });\n slot.assignedNodes({ flatten: true }).forEach((node) => {\n observer.observe(node, {\n characterData: true,\n childList: true,\n subtree: true,\n });\n });\n this._slotTextObserver = observer;\n }\n\n /** @internal */\n private _handleDefaultSlotChange(): void {\n this._captureSlotLabelText();\n this._syncHostAriaSemantics();\n // Re-tune the in-place text observer over the new assigned-node set\n // (codex round-13 P2).\n this._installSlotTextObserver();\n }\n\n /**\n * Mirrors toggle-button semantics onto the host via ElementInternals so that\n * consumer-supplied `aria-label`, `aria-labelledby`, and `aria-describedby`\n * on `<hx-toggle-button>` reach the announced control. The codex aria-group-2\n * finding identified that the inner shadow `<button>` was the only carrier of\n * the toggle role + pressed state, leaving host-level IDREF tokens stranded\n * across the shadow boundary.\n *\n * The shadow `<button>` keeps `aria-pressed`/`aria-label` mirrored for\n * backwards-compat with existing tests and for browsers without IDL element\n * references; the host is the canonical announced surface.\n * @internal\n */\n private _syncHostAriaSemantics(): void {\n const internals = this._internals;\n\n const hostAriaLabel = this.getAttribute('aria-label')?.trim() || '';\n const externalLabelTokens = this.getAttribute('aria-labelledby');\n const externalDescTokens = this.getAttribute('aria-describedby');\n const labelEls = resolveIdrefTokens(this, externalLabelTokens);\n const descEls = resolveIdrefTokens(this, externalDescTokens);\n // Codex round-35 finding (CR major): `aria-labelledby` is only \"effective\"\n // when at least one IDREF resolves. A typo or transiently-missing target\n // must NOT erase the visible label — fall back to label/slot text so a\n // visibly-labeled toggle never becomes unnamed.\n const hasEffectiveLabelledBy = labelEls.length > 0;\n let resolvedLabel: string | null;\n if (hostAriaLabel) {\n resolvedLabel = hostAriaLabel;\n } else if (hasEffectiveLabelledBy) {\n resolvedLabel = null;\n } else if (this.label) {\n resolvedLabel = this.label;\n } else {\n // Codex round-1 finding #9: default-slot text becomes the accessible\n // name when no explicit label is provided. Without this, slotted text\n // never reaches the host's announced surface.\n resolvedLabel = this._slotLabelText || null;\n }\n\n // Codex round-2 finding #2: branch on platform support. Modern path —\n // host carries `role=button` + aria-pressed via ElementInternals.\n // Fallback path — inner native `<button>` is the announced surface; clear\n // host role/state on internals so AT does not double-announce.\n if (this._supportsIdrefRefs) {\n // ─── Modern path ───\n internals.role = 'button';\n internals.ariaPressed = this.pressed ? 'true' : 'false';\n internals.ariaDisabled = this.disabled ? 'true' : 'false';\n // Codex round-1 finding #6: drive aria-invalid from the live ValidityState\n // so a required-but-unpressed toggle is announced as invalid even before\n // any visible affordance renders. `_updateValidity()` calls this method\n // synchronously after every `setValidity()`.\n internals.ariaInvalid = !internals.validity.valid ? 'true' : 'false';\n internals.ariaLabel = resolvedLabel;\n\n type InternalsWithRefs = ElementInternals & {\n ariaLabelledByElements: Element[] | null;\n ariaDescribedByElements: Element[] | null;\n };\n const refsInternals = internals as InternalsWithRefs;\n\n refsInternals.ariaLabelledByElements = hasEffectiveLabelledBy ? labelEls : null;\n refsInternals.ariaDescribedByElements = descEls.length > 0 ? descEls : null;\n // Clear fallbacks when IDL refs are available.\n this._fallbackAriaLabelledBy = null;\n this._fallbackAriaDescribedBy = null;\n this._fallbackAriaLabel = null;\n } else {\n // ─── Fallback path: inner button is the announced surface ───\n // Round-2 finding #2: round-1 set host role/state via internals AND\n // mirrored aria-* onto the `aria-hidden` inner button — making the\n // mirrored attributes inert. The fix is to clear host role/state and\n // let the inner native `<button>` (rendered without aria-hidden, with\n // `tabindex=0`, with aria-pressed) carry semantics natively.\n internals.role = null;\n internals.ariaPressed = null;\n internals.ariaDisabled = null;\n internals.ariaInvalid = null;\n internals.ariaLabel = null;\n\n // Codex round-36 (medium): gate the fallback label tokens on the\n // *effective* labelledby contract. Mirroring broken consumer tokens to\n // the inner button on legacy engines erases the accessible name —\n // exactly the bug the modern path now defends against. When tokens\n // don't resolve, fall through to `_fallbackAriaLabel` (resolvedLabel)\n // so the slot/property still names the announced surface.\n this._fallbackAriaLabelledBy = hasEffectiveLabelledBy ? externalLabelTokens : null;\n this._fallbackAriaDescribedBy = externalDescTokens || null;\n this._fallbackAriaLabel = resolvedLabel;\n }\n }\n\n protected override _onFormReset(): void {\n this.pressed = false;\n }\n\n protected override _onFormStateRestore(\n state: string | File | FormData | null,\n _mode: 'restore' | 'autocomplete',\n ): void {\n this.pressed = typeof state === 'string' && state === 'pressed';\n }\n\n protected override _onFormDisabled(disabled: boolean): void {\n this.disabled = disabled;\n }\n\n // ─── Private Helpers ───\n\n /** @internal */\n private _syncFormValue(): void {\n if (this.pressed && this.value !== undefined) {\n // Pass explicit state 'pressed' so formStateRestoreCallback can reliably detect it.\n this._internals.setFormValue(this.value, 'pressed');\n } else {\n this._internals.setFormValue(null);\n }\n this._updateValidity();\n }\n\n /** @internal */\n private _updateValidity(): void {\n if (this.required && !this.pressed) {\n // Codex round-17 P2: anchor validity UI to the announced surface. On\n // the modern path the host is the canonical announced/focus surface\n // (the inner button is `aria-hidden + tabindex=-1`), so passing the\n // host avoids `reportValidity()` landing focus on a hidden node. On\n // the fallback path the inner button is the announced surface.\n const anchor: HTMLElement | undefined = this._supportsIdrefRefs\n ? this\n : (this.shadowRoot?.querySelector<HTMLElement>('[part=\"button\"]') ?? undefined);\n this._internals.setValidity(\n { valueMissing: true },\n 'Please activate this toggle button.',\n anchor,\n );\n } else {\n this._internals.setValidity({});\n }\n // Codex round-1 finding #6: keep `internals.ariaInvalid` aligned with the\n // current `ValidityState`.\n this._syncHostAriaSemantics();\n }\n\n // ─── Event Handling ───\n\n /** @internal */\n private _handleClick(e: MouseEvent): void {\n if (this.disabled) {\n e.preventDefault();\n e.stopPropagation();\n return;\n }\n\n this.pressed = !this.pressed;\n this._syncFormValue();\n\n /**\n * Dispatched when the toggle state changes.\n * @event hx-toggle\n */\n this.dispatchEvent(\n new CustomEvent<{ pressed: boolean }>('hx-toggle', {\n bubbles: true,\n composed: true,\n detail: { pressed: this.pressed },\n }),\n );\n\n // Codex round-12 P2: on the modern path the host owns role=\"button\" and\n // tabindex=0; the inner <button tabindex=\"-1\"> is aria-hidden. Native\n // click activation on a `<button>` still focuses it, which would leave\n // `document.activeElement` and AT focus on a hidden node. Move focus to\n // the host so the announced surface is also the focus target.\n if (this._supportsIdrefRefs) {\n this.focus();\n }\n }\n\n // ─── Render Helpers ───\n\n /** @internal */\n private _renderInner() {\n return html`\n <span part=\"prefix\" class=\"button__prefix\">\n <slot name=\"prefix\"></slot>\n </span>\n <span part=\"label\" class=\"button__label\">\n <slot @slotchange=${this._handleDefaultSlotChange}></slot>\n </span>\n <span part=\"suffix\" class=\"button__suffix\">\n <slot name=\"suffix\"></slot>\n </span>\n `;\n }\n\n // ─── Render ───\n\n override render() {\n const classes = {\n button: true,\n [`button--${this.variant}`]: true,\n [`button--${this.size}`]: true,\n 'button--pressed': this.pressed,\n };\n\n // Codex round-2 finding #2: branch the inner button on platform support.\n // Modern path — host announced, inner button is `aria-hidden + tabindex=-1`.\n // Fallback path — inner native `<button>` is announced (NO aria-hidden,\n // tabindex=0) so consumer-mirrored aria-* attributes resolve through a\n // visible accessibility-tree node and AT can name + activate it natively.\n const innerIsAnnounced = !this._supportsIdrefRefs;\n const innerTabIndex = innerIsAnnounced && !this.disabled ? '0' : '-1';\n // Round-1 finding #8: on no-IDL-ref browsers mirror host aria tokens onto\n // the inner button so it carries an accessible name. On modern browsers\n // we still mirror `label` onto the inner button for non-AT consumers\n // (testing, devtools) — does not affect announced semantics.\n const innerAriaLabel = this._fallbackAriaLabel ?? this.label ?? undefined;\n const innerAriaLabelledBy = this._fallbackAriaLabelledBy ?? undefined;\n const innerAriaDescribedBy = this._fallbackAriaDescribedBy ?? undefined;\n\n return html`\n <button\n part=\"button\"\n class=${classMap(classes)}\n ?disabled=${this.disabled}\n type=\"button\"\n tabindex=${innerTabIndex}\n aria-pressed=${this.pressed ? 'true' : 'false'}\n aria-label=${ifDefined(innerAriaLabel)}\n aria-labelledby=${ifDefined(innerAriaLabelledBy)}\n aria-describedby=${ifDefined(innerAriaDescribedBy)}\n aria-hidden=${innerIsAnnounced ? nothing : 'true'}\n @click=${this._handleClick}\n >\n ${this._renderInner()}\n </button>\n `;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'hx-toggle-button': HelixToggleButton;\n }\n}\n"],"names":["helixToggleButtonStyles","css","HelixToggleButton","HelixElement","e","supportsIdrefElementReferences","enabledTabIndex","installAriaIdrefMirror","_a","_b","options","changedProperties","slot","n","text","observer","node","internals","hostAriaLabel","externalLabelTokens","externalDescTokens","labelEls","resolveIdrefTokens","descEls","hasEffectiveLabelledBy","resolvedLabel","refsInternals","state","_mode","disabled","anchor","html","classes","innerIsAnnounced","innerTabIndex","innerAriaLabel","innerAriaLabelledBy","innerAriaDescribedBy","classMap","ifDefined","nothing","forcedColorsInteractive","__decorateClass","query","property","customElement"],"mappings":";;;;;;;AAEO,MAAMA,IAA0BC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;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"}
|
|
1
|
+
{"version":3,"file":"hx-toggle-button-BQ81EDkl.js","sources":["../../src/components/hx-toggle-button/hx-toggle-button.styles.ts","../../src/components/hx-toggle-button/hx-toggle-button.ts"],"sourcesContent":["import { css } from 'lit';\n\nexport const helixToggleButtonStyles = css`\n :host {\n display: inline-block;\n }\n\n :host([disabled]) {\n pointer-events: none;\n opacity: var(--hx-opacity-disabled, 0.5);\n }\n\n /* ─── Base Button ─── */\n\n .button {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n gap: var(--hx-space-2, 0.5rem);\n border: var(--hx-border-width-thin, 1px) solid var(--hx-toggle-button-border-color, transparent);\n border-radius: var(--hx-toggle-button-border-radius, var(--hx-border-radius-md, 0.375rem));\n background-color: var(--hx-toggle-button-bg, var(--hx-color-primary-500, #429797));\n color: var(--hx-toggle-button-color, var(--hx-color-text-on-primary, #ffffff));\n font-family: var(--hx-toggle-button-font-family, var(--hx-font-family-sans, sans-serif));\n font-weight: var(--hx-toggle-button-font-weight, var(--hx-font-weight-semibold, 600));\n line-height: var(--hx-line-height-tight, 1.25);\n cursor: pointer;\n transition:\n background-color var(--hx-transition-fast, 150ms ease),\n color var(--hx-transition-fast, 150ms ease),\n border-color var(--hx-transition-fast, 150ms ease),\n box-shadow var(--hx-transition-fast, 150ms ease);\n text-decoration: none;\n white-space: nowrap;\n user-select: none;\n -webkit-user-select: none;\n }\n\n /*\n * Host-focus path: on the modern (IDL element-references) render branch the\n * host is the tabbable surface (tabindex=0) and the inner <button> is\n * demoted to tabindex=-1. Drive the focus ring from ':host(:focus-visible)'\n * so keyboard users still see a visible affordance. Codex round-11 P1.\n */\n :host(:focus-visible) .button {\n outline: var(--hx-focus-ring-width, 2px) solid\n var(--hx-toggle-button-focus-ring-color, var(--hx-focus-ring-color, #0f7078));\n outline-offset: var(--hx-focus-ring-offset, 2px);\n }\n\n /*\n * Fallback (no-IDL-ref) path: the host carries tabindex=-1 and the inner\n * <button> is the tab target. Native :focus-visible drives the ring.\n */\n .button:focus-visible {\n outline: var(--hx-focus-ring-width, 2px) solid\n var(--hx-toggle-button-focus-ring-color, var(--hx-focus-ring-color, #0f7078));\n outline-offset: var(--hx-focus-ring-offset, 2px);\n }\n\n .button:hover {\n filter: brightness(var(--hx-filter-brightness-hover, 0.9));\n }\n\n .button:active {\n filter: brightness(var(--hx-filter-brightness-active, 0.8));\n }\n\n /* ─── Size Variants ─── */\n\n /* WCAG 2.5.5 (healthcare mandate): minimum 44px touch target for sm variant.\n min-height uses --hx-touch-target-min to guarantee the interactive area\n meets the threshold even though the visual size token is smaller. */\n .button--sm {\n padding: var(--hx-space-1, 0.25rem) var(--hx-space-3, 0.75rem);\n font-size: var(--hx-font-size-sm, 0.875rem);\n min-height: var(--hx-touch-target-min, 2.75rem);\n }\n\n .button--md {\n padding: var(--hx-space-2, 0.5rem) var(--hx-space-4, 1rem);\n font-size: var(--hx-font-size-md, 1rem);\n min-height: var(--hx-size-10, 2.5rem);\n }\n\n .button--lg {\n padding: var(--hx-space-3, 0.75rem) var(--hx-space-6, 1.5rem);\n font-size: var(--hx-font-size-lg, 1.125rem);\n min-height: var(--hx-size-12, 3rem);\n }\n\n /* ─── Style Variants ─── */\n\n .button--primary {\n --hx-toggle-button-bg: var(--hx-color-primary-500, #429797);\n --hx-toggle-button-color: var(--hx-color-text-on-primary, #ffffff);\n --hx-toggle-button-border-color: transparent;\n }\n\n /*\n * secondary/ghost paint primary text on the surface (white). primary-500\n * (#429797) on white = 3.43:1 — fails AA at body sizes. shift to\n * primary-600 (#0F7078) = 6.06:1 — AA pass. border keeps primary-500\n * for the brand affordance (3:1 non-text contrast still met).\n */\n .button--secondary {\n --hx-toggle-button-bg: transparent;\n --hx-toggle-button-color: var(--hx-color-primary-600, #0f7078);\n --hx-toggle-button-border-color: var(--hx-color-primary-600, #0f7078);\n }\n\n .button--secondary:hover {\n --hx-toggle-button-bg: var(--hx-color-primary-50, #ebf8f8);\n }\n\n .button--tertiary {\n --hx-toggle-button-bg: var(--hx-color-surface-sunken, #ebeee9);\n --hx-toggle-button-color: var(--hx-color-text-primary, #0d1825);\n --hx-toggle-button-border-color: transparent;\n }\n\n .button--tertiary:hover {\n --hx-toggle-button-bg: var(--hx-color-surface-raised, #f5f8f3);\n }\n\n .button--ghost {\n --hx-toggle-button-bg: transparent;\n --hx-toggle-button-color: var(--hx-color-primary-600, #0f7078);\n --hx-toggle-button-border-color: transparent;\n }\n\n .button--ghost:hover {\n --hx-toggle-button-bg: var(--hx-color-surface-raised, #f5f8f3);\n }\n\n .button--outline {\n --hx-toggle-button-bg: transparent;\n --hx-toggle-button-color: var(--hx-color-text-primary, #0d1825);\n --hx-toggle-button-border-color: var(--hx-color-border-strong, #66787b);\n }\n\n .button--outline:hover {\n --hx-toggle-button-bg: var(--hx-color-surface-raised, #f5f8f3);\n }\n\n /* ─── Pressed State ─── */\n\n /*\n * Primary: already uses solid primary bg; pressed deepens to primary-700\n * to give clear visual feedback without introducing a new color.\n *\n * AA fix: text.on-primary (= neutral-900 #0D1825) on primary-700 (#0F6363)\n * = 2.54:1 — fails AA. Pin fg at neutral-0 for the darker pressed fill\n * (neutral-0 on primary-700 = 7.03:1, AAA pass). Mirrors hx-toast\n * precedent (commit 300e21ab0) and hx-button hover treatment.\n * Note: secondary.pressed below uses primary-500 and stays at 5.20:1 —\n * leave it alone.\n */\n .button--primary.button--pressed {\n --hx-toggle-button-bg: var(--hx-toggle-button-pressed-bg, var(--hx-color-primary-700, #0f6363));\n --hx-toggle-button-color: var(\n --hx-toggle-button-pressed-color,\n var(--hx-color-neutral-0, #ffffff)\n );\n --hx-toggle-button-border-color: transparent;\n }\n\n /*\n * Secondary: unpressed is outlined/transparent; pressed fills with primary bg\n * so the state change is immediately legible.\n */\n .button--secondary.button--pressed {\n --hx-toggle-button-bg: var(--hx-toggle-button-pressed-bg, var(--hx-color-primary-500, #429797));\n --hx-toggle-button-color: var(\n --hx-toggle-button-pressed-color,\n var(--hx-color-text-on-primary, #ffffff)\n );\n --hx-toggle-button-border-color: var(--hx-color-primary-500, #429797);\n }\n\n /* Tertiary pressed: use primary-100 bg + primary-700 text + border for WCAG 3:1 non-text contrast. */\n .button--tertiary.button--pressed {\n --hx-toggle-button-bg: var(--hx-toggle-button-pressed-bg, var(--hx-color-primary-100, #dbf0f0));\n --hx-toggle-button-color: var(\n --hx-toggle-button-pressed-color,\n var(--hx-color-primary-700, #0f6363)\n );\n --hx-toggle-button-border-color: var(--hx-color-primary-600, #0f7078);\n box-shadow: inset 0 0 0 1px var(--hx-color-primary-600, #0f7078);\n }\n\n /* Ghost pressed: subtle neutral fill, matching hover behavior as a baseline. */\n .button--ghost.button--pressed {\n --hx-toggle-button-bg: var(--hx-toggle-button-pressed-bg, var(--hx-color-primary-100, #dbf0f0));\n --hx-toggle-button-color: var(\n --hx-toggle-button-pressed-color,\n var(--hx-color-primary-700, #0f6363)\n );\n --hx-toggle-button-border-color: transparent;\n }\n\n /* Outline pressed: fills with a neutral tint, darkens the border, and adds an inset shadow for WCAG 3:1 non-text contrast. */\n .button--outline.button--pressed {\n --hx-toggle-button-bg: var(\n --hx-toggle-button-pressed-bg,\n var(--hx-color-surface-sunken, #ebeee9)\n );\n --hx-toggle-button-color: var(\n --hx-toggle-button-pressed-color,\n var(--hx-color-text-primary, #0d1825)\n );\n --hx-toggle-button-border-color: var(--hx-color-text-muted, #4a5362);\n box-shadow: inset 0 0 0 1px var(--hx-color-neutral-500, #66787b);\n }\n\n /* ─── Disabled ─── */\n\n .button[disabled] {\n cursor: not-allowed;\n }\n\n /* ─── Prefix / Suffix / Label ─── */\n\n .button__prefix,\n .button__suffix {\n display: inline-flex;\n align-items: center;\n flex-shrink: 0;\n }\n\n .button__label {\n flex: 1 1 auto;\n }\n\n /* ─── Reduced Motion ─── */\n\n @media (prefers-reduced-motion: reduce) {\n .button {\n transition: none;\n }\n }\n\n /* ─── High Contrast Mode (forced-colors) ─── */\n\n @media (forced-colors: active) {\n .button {\n forced-color-adjust: none;\n background-color: ButtonFace;\n color: ButtonText;\n border: 2px solid ButtonText;\n }\n\n :host(:focus-visible) .button,\n .button:focus-visible {\n outline: 3px solid Highlight;\n outline-offset: 2px;\n }\n\n .button--pressed {\n background-color: Highlight;\n color: HighlightText;\n border-color: Highlight;\n box-shadow: none;\n }\n\n .button[disabled] {\n background-color: ButtonFace;\n color: GrayText;\n border-color: GrayText;\n opacity: 1;\n }\n\n :host([disabled]) {\n opacity: 1;\n }\n }\n`;\n","import { html, nothing, type PropertyValues } from 'lit';\nimport '../../utilities/document-token-adoption.js';\nimport { customElement, property, query, state } from 'lit/decorators.js';\nimport { classMap } from 'lit/directives/class-map.js';\nimport { ifDefined } from 'lit/directives/if-defined.js';\nimport { HelixElement } from '../../base/index.js';\nimport { helixToggleButtonStyles } from './hx-toggle-button.styles.js';\nimport { forcedColorsInteractive } from '../../styles/forced-colors.js';\nimport {\n installAriaIdrefMirror,\n resolveIdrefTokens,\n supportsIdrefElementReferences,\n type AriaIdrefMirrorHandle,\n} from '../../utils/aria-idref.js';\n\n/** Detail for the hx-toggle event dispatched by hx-toggle-button. */\nexport interface HxToggleDetail {\n pressed: boolean;\n}\n\n/**\n * A two-state toggle button that communicates a pressed/unpressed status to\n * assistive technology via `aria-pressed`. Supports multiple visual variants\n * and sizes, prefix/suffix slots, full ElementInternals form association, and\n * a distinct pressed visual state for every variant.\n *\n * @summary Two-state toggle button with pressed/unpressed ARIA semantics.\n *\n * @tag hx-toggle-button\n *\n * @slot - Default slot for the button label text or content.\n * @slot prefix - Icon or content rendered before the label.\n * @slot suffix - Icon or content rendered after the label.\n *\n * @fires {CustomEvent<{pressed: boolean}>} hx-toggle - Dispatched when the\n * toggle state changes. Not dispatched when the button is disabled.\n *\n * @csspart button - The native `<button>` element.\n * @csspart label - The label text wrapper span.\n * @csspart prefix - The prefix slot container span.\n * @csspart suffix - The suffix slot container span.\n *\n * @cssprop [--hx-toggle-button-bg=var(--hx-color-primary-500)] - Button background color.\n * @cssprop [--hx-toggle-button-color=var(--hx-color-neutral-0)] - Button text color.\n * @cssprop [--hx-toggle-button-border-color=transparent] - Button border color.\n * @cssprop [--hx-toggle-button-border-radius=var(--hx-border-radius-md)] - Button border radius.\n * @cssprop [--hx-toggle-button-font-family=var(--hx-font-family-sans)] - Button font family.\n * @cssprop [--hx-toggle-button-font-weight=var(--hx-font-weight-semibold)] - Button font weight.\n * @cssprop [--hx-toggle-button-focus-ring-color=var(--hx-focus-ring-color)] - Focus ring color.\n * @cssprop [--hx-toggle-button-pressed-bg=var(--hx-color-primary-500)] - Background when pressed (variant-specific fallback applies).\n * @cssprop [--hx-toggle-button-pressed-color=var(--hx-color-neutral-0)] - Text color when pressed (variant-specific fallback applies).\n * @cssprop [--hx-opacity-disabled] - Opacity.\n * @cssprop [--hx-space-2] - Spacing token.\n * @cssprop [--hx-border-width-thin] - Width.\n * @cssprop [--hx-border-radius-md] - CSS custom property.\n * @cssprop [--hx-color-primary-500] - Color.\n * @cssprop [--hx-color-neutral-0] - Color.\n * @cssprop [--hx-font-family-sans] - Font family.\n * @cssprop [--hx-font-weight-semibold] - Font weight.\n * @cssprop [--hx-line-height-tight] - Line height.\n * @cssprop [--hx-transition-fast] - Transition timing.\n * @cssprop [--hx-focus-ring-width] - Width.\n * @cssprop [--hx-focus-ring-color] - Color.\n * @cssprop [--hx-color-primary-400] - Color.\n * @cssprop [--hx-focus-ring-offset] - CSS custom property.\n * @cssprop [--hx-filter-brightness-hover] - CSS filter.\n * @cssprop [--hx-filter-brightness-active] - CSS filter.\n * @cssprop [--hx-touch-target-min] - Minimum touch target size.\n * @cssprop [--hx-space-1] - Spacing token.\n * @cssprop [--hx-space-3] - Spacing token.\n * @cssprop [--hx-font-size-sm] - Font size.\n * @cssprop [--hx-space-4] - Spacing token.\n * @cssprop [--hx-font-size-md] - Font size.\n * @cssprop [--hx-size-10] - Size token.\n * @cssprop [--hx-space-6] - Spacing token.\n * @cssprop [--hx-font-size-lg] - Font size.\n * @cssprop [--hx-size-12] - Size token.\n * @cssprop [--hx-color-primary-50] - Color.\n * @cssprop [--hx-color-neutral-100] - Color.\n * @cssprop [--hx-color-neutral-900] - Color.\n * @cssprop [--hx-color-neutral-200] - Color.\n * @cssprop [--hx-color-neutral-300] - Color.\n * @cssprop [--hx-color-primary-700] - Color.\n * @cssprop [--hx-color-primary-100] - Color.\n * @cssprop [--hx-color-neutral-50] - Color.\n * @cssprop [--hx-color-neutral-500] - Color.\n */\n@customElement('hx-toggle-button')\nexport class HelixToggleButton extends HelixElement {\n static override styles = [helixToggleButtonStyles, forcedColorsInteractive];\n\n // ─── Form Association ───\n\n /** @internal */\n static override formAssociated = true;\n\n /** @internal */\n @query('slot:not([name])') private _defaultSlot!: HTMLSlotElement | null;\n\n // ─── Public Properties ───\n\n /**\n * Whether the toggle button is in the pressed state.\n * Reflected as an attribute so CSS selectors like `:host([pressed])` work.\n * @attr pressed\n */\n @property({ type: Boolean, reflect: true })\n pressed = false;\n\n /**\n * Visual style variant of the button.\n * @attr variant\n */\n @property({ type: String, reflect: true })\n variant: 'primary' | 'secondary' | 'tertiary' | 'ghost' | 'outline' = 'secondary';\n\n /**\n * Size of the button.\n * @attr hx-size\n */\n @property({ type: String, reflect: true, attribute: 'hx-size' })\n size: 'sm' | 'md' | 'lg' = 'md';\n\n /**\n * Whether the button is disabled. Prevents all interaction and form actions.\n * @attr disabled\n */\n @property({ type: Boolean, reflect: true })\n disabled = false;\n\n /**\n * Form field name submitted via ElementInternals when the button is pressed.\n * @attr name\n */\n @property({ type: String })\n name: string | undefined = undefined;\n\n /**\n * Form field value submitted via ElementInternals when the button is pressed.\n * @attr value\n */\n @property({ type: String })\n value: string | undefined = undefined;\n\n /**\n * Accessible label forwarded to the inner `<button>` as `aria-label`.\n * Required for icon-only toggle buttons where no visible text is present.\n * @attr label\n */\n @property({ type: String })\n label: string | undefined = undefined;\n\n /**\n * When true, the button must be in the pressed state for the form to be submitted.\n * @attr required\n */\n @property({ type: Boolean, reflect: true })\n required = false;\n\n // ─── Form API ───\n\n /** Returns the ValidityState object. */\n override get validity(): ValidityState {\n return this._internals.validity;\n }\n\n /** Returns the current validation message. */\n override get validationMessage(): string {\n return this._internals.validationMessage;\n }\n\n /** Checks whether the button satisfies its constraints. */\n checkValidity(): boolean {\n return this._internals.checkValidity();\n }\n\n /** Reports validity and shows the browser's constraint validation UI. */\n reportValidity(): boolean {\n return this._internals.reportValidity();\n }\n\n /**\n * Handle for the shared IDREF observer. See `installAriaIdrefMirror()`.\n * @internal\n */\n private _ariaMirror: AriaIdrefMirrorHandle | null = null;\n\n /**\n * Default-slot text content captured for use as the host's accessible name\n * when no explicit `label`/`aria-label`/`aria-labelledby` is supplied.\n * Codex round-1 finding #9.\n * @internal\n */\n @state() private _slotLabelText: string = '';\n\n /** No-IDL-ref fallback tokens applied to the inner button. @internal */\n @state() private _fallbackAriaLabelledBy: string | null = null;\n /** @internal */\n @state() private _fallbackAriaDescribedBy: string | null = null;\n /** @internal */\n @state() private _fallbackAriaLabel: string | null = null;\n\n /**\n * Whether the platform supports IDL element references on `ElementInternals`.\n * Drives the render-time branch between the modern path (host is the\n * announced surface, inner button is `aria-hidden + tabindex=-1`) and the\n * fallback path (inner button is the announced surface, host is demoted).\n * Codex round-2 finding #2.\n * @internal\n */\n @state() private _supportsIdrefRefs = true;\n\n /**\n * Tracks whether the host's `tabindex` is managed by the component itself\n * (vs. set explicitly by a consumer). Codex round-14 P2: a consumer-supplied\n * `tabindex` (e.g. roving-tabindex toolbar pattern with `tabindex=\"-1\"`)\n * must survive disabled flips and re-renders. Only re-assert tabindex in\n * `updated()` when the component originally claimed it.\n * @internal\n */\n private _internalTabindexManaged = false;\n\n // ─── Lifecycle ───\n\n override connectedCallback(): void {\n super.connectedCallback();\n // Detect platform support for IDL element references. Codex round-2\n // finding #2: drives the render-time branch between modern (host\n // announced) and fallback (inner button announced) paths.\n this._supportsIdrefRefs = supportsIdrefElementReferences(this._internals);\n // Seed root-independent semantics from the moment of connection so AT\n // sees the toggle role + pressed state before the first paint.\n this._syncHostAriaSemantics();\n // Codex round-1 finding #1: host is the canonical announced surface on\n // modern browsers, so the inner `<button>` is demoted via\n // `aria-hidden + tabindex=-1`.\n // Codex round-2 finding #2: on no-IDL-ref browsers the inner button is\n // the announced surface (it carries native button + aria-pressed), so\n // the host is demoted to `tabindex=-1` and lets the inner button own\n // tab order + activation.\n // Codex round-14 P2: only claim ownership of `tabindex` when no consumer\n // value is present. Consumers using roving-tabindex toolbar patterns\n // must be able to set `tabindex=\"-1\"` on the host without it being\n // clobbered on every disabled flip. Note we still claim ownership when\n // disabled — the initial value is `-1` to keep the host out of tab order\n // and `updated()` re-asserts the appropriate value when disabled flips.\n if (!this.hasAttribute('tabindex')) {\n this._internalTabindexManaged = true;\n const enabledTabIndex = this._supportsIdrefRefs ? '0' : '-1';\n this.setAttribute('tabindex', this.disabled ? '-1' : enabledTabIndex);\n }\n this.addEventListener('keydown', this._handleHostKeyDown);\n this.addEventListener('click', this._handleHostClickRouted);\n this._ariaMirror = installAriaIdrefMirror(this, () => {\n this._syncHostAriaSemantics();\n });\n }\n\n override disconnectedCallback(): void {\n super.disconnectedCallback();\n this.removeEventListener('keydown', this._handleHostKeyDown);\n this.removeEventListener('click', this._handleHostClickRouted);\n // Codex round-13 P2: tear down the assigned-node text observer so a\n // detached host does not receive mutation callbacks from nodes that may\n // outlive it (e.g. lifted out of the slot but kept in the document).\n this._slotTextObserver?.disconnect();\n this._slotTextObserver = null;\n this._ariaMirror?.disconnect();\n this._ariaMirror = null;\n }\n\n /**\n * Host-level keydown handler. Active only on the modern path; on the\n * no-IDL-ref fallback the inner `<button>` owns native Space/Enter\n * activation. Codex round-2 finding #2.\n * @internal\n */\n private _handleHostKeyDown = (e: KeyboardEvent): void => {\n if (this.disabled) return;\n if (!this._supportsIdrefRefs) return;\n if (e.target !== this) return;\n if (e.key === ' ' || e.key === 'Enter') {\n e.preventDefault();\n this._invokeToggle();\n }\n };\n\n /**\n * Host-level click router. The inner `<button>` is `aria-hidden + tabindex=-1`\n * on modern browsers but still receives clicks via mouse activation; toggling\n * is handled by the inner `_handleClick`. Host-level clicks (composed path\n * origin === host) only come from AT activation or programmatic triggers,\n * so we route those to the toggle pipeline.\n *\n * Codex round-2 finding #2: on no-IDL-ref browsers the inner button is the\n * announced surface so this host-level routing is a no-op — AT activation\n * lands on the inner button directly.\n * @internal\n */\n private _handleHostClickRouted = (e: MouseEvent): void => {\n if (this.disabled) return;\n if (!this._supportsIdrefRefs) return;\n // Only fire when the host itself originated the click — inner-button\n // clicks bubble through here too but are handled by `_handleClick`.\n const path = e.composedPath();\n if (path[0] !== this) return;\n this._invokeToggle();\n };\n\n /** @internal */\n private _invokeToggle(): void {\n this.pressed = !this.pressed;\n this._syncFormValue();\n this.dispatchEvent(\n new CustomEvent<{ pressed: boolean }>('hx-toggle', {\n bubbles: true,\n composed: true,\n detail: { pressed: this.pressed },\n }),\n );\n }\n\n /**\n * Moves focus to the announced toggle-button surface. Codex round-1 finding\n * `#1` made the host the canonical focus target on modern engines so AT\n * announces a single widget. Round-7 finding `#9` extends that contract to\n * the no-IDL-ref fallback: when the host is demoted (`tabindex=-1`,\n * role/state cleared on `internals`) the inner `<button>` owns the announced\n * semantics and tab order, so programmatic `focus()` must redirect there —\n * otherwise scripted focus and error recovery land on the demoted host on\n * unsupported engines.\n */\n override focus(options?: FocusOptions): void {\n if (this._supportsIdrefRefs) {\n super.focus(options);\n return;\n }\n this.shadowRoot?.querySelector<HTMLButtonElement>('[part=\"button\"]')?.focus(options);\n }\n\n override firstUpdated(changedProperties: PropertyValues<this>): void {\n super.firstUpdated(changedProperties);\n\n // Track default-slot text content so it can serve as the accessible\n // name when no explicit label is set. Codex round-1 finding #9.\n this._captureSlotLabelText();\n // Codex round-13 P2: also observe in-place text mutations on assigned\n // nodes so framework-driven `Mute` → `Unmute` rewrites refresh the\n // cached label without requiring the consumer to swap the node.\n this._installSlotTextObserver();\n\n if (!this.label) {\n const slot = this._defaultSlot;\n const hasSlotText = slot\n ? slot.assignedNodes({ flatten: true }).some((n) => n.textContent?.trim())\n : false;\n if (!hasSlotText) {\n console.warn(\n '[hx-toggle-button] No accessible label found. Set the `label` attribute or provide slot text content for WCAG 4.1.2 compliance.',\n );\n }\n }\n }\n\n override updated(changedProperties: PropertyValues<this>): void {\n super.updated(changedProperties);\n\n if (\n changedProperties.has('pressed') ||\n changedProperties.has('value') ||\n changedProperties.has('required')\n ) {\n this._syncFormValue();\n }\n\n if (\n changedProperties.has('disabled') ||\n (changedProperties as Map<PropertyKey, unknown>).has('_supportsIdrefRefs')\n ) {\n // Codex round-2 finding #2: align host tabindex with the chosen\n // announced surface. On no-IDL-ref browsers the inner button owns\n // tab order, so re-enabling the host should leave it `tabindex=-1`.\n // Codex round-14 P2: only re-assert when the component owns tabindex.\n // Consumer-managed values (e.g. roving-tabindex toolbar with `-1`) must\n // not be overwritten on disabled flips or supports-flag transitions.\n if (this._internalTabindexManaged) {\n const enabledTabIndex = this._supportsIdrefRefs ? '0' : '-1';\n this.setAttribute('tabindex', this.disabled ? '-1' : enabledTabIndex);\n }\n }\n\n // Host-elevated ARIA semantics — see _syncHostAriaSemantics.\n this._syncHostAriaSemantics();\n }\n\n /**\n * Reads the default slot's flattened text content into `_slotLabelText`.\n * Called from `firstUpdated()` and `slotchange` so host-canonical semantics\n * pick up slotted label text. Codex round-1 finding #9.\n * @internal\n */\n private _captureSlotLabelText(): void {\n const slot = this._defaultSlot;\n if (!slot) {\n this._slotLabelText = '';\n return;\n }\n const text = slot\n .assignedNodes({ flatten: true })\n .map((n) => n.textContent ?? '')\n .join(' ')\n .trim();\n this._slotLabelText = text;\n }\n\n /**\n * Watches assigned default-slot nodes for in-place text mutations so the\n * cached `_slotLabelText` (and thus `internals.ariaLabel`) stays in sync\n * when a framework rewrites textContent of an already-assigned node without\n * replacing it. `slotchange` does NOT fire for those mutations, so a\n * separate observer is required. Codex round-13 P2.\n * @internal\n */\n private _slotTextObserver: MutationObserver | null = null;\n\n /**\n * (Re-)installs the mutation observer over the current set of assigned\n * default-slot nodes. Disconnects any prior observer first so detached\n * nodes stop firing into a torn-down host.\n * @internal\n */\n private _installSlotTextObserver(): void {\n this._slotTextObserver?.disconnect();\n const slot = this._defaultSlot;\n if (!slot) {\n this._slotTextObserver = null;\n return;\n }\n const observer = new MutationObserver(() => {\n this._captureSlotLabelText();\n this._syncHostAriaSemantics();\n });\n slot.assignedNodes({ flatten: true }).forEach((node) => {\n observer.observe(node, {\n characterData: true,\n childList: true,\n subtree: true,\n });\n });\n this._slotTextObserver = observer;\n }\n\n /** @internal */\n private _handleDefaultSlotChange(): void {\n this._captureSlotLabelText();\n this._syncHostAriaSemantics();\n // Re-tune the in-place text observer over the new assigned-node set\n // (codex round-13 P2).\n this._installSlotTextObserver();\n }\n\n /**\n * Mirrors toggle-button semantics onto the host via ElementInternals so that\n * consumer-supplied `aria-label`, `aria-labelledby`, and `aria-describedby`\n * on `<hx-toggle-button>` reach the announced control. The codex aria-group-2\n * finding identified that the inner shadow `<button>` was the only carrier of\n * the toggle role + pressed state, leaving host-level IDREF tokens stranded\n * across the shadow boundary.\n *\n * The shadow `<button>` keeps `aria-pressed`/`aria-label` mirrored for\n * backwards-compat with existing tests and for browsers without IDL element\n * references; the host is the canonical announced surface.\n * @internal\n */\n private _syncHostAriaSemantics(): void {\n const internals = this._internals;\n\n const hostAriaLabel = this.getAttribute('aria-label')?.trim() || '';\n const externalLabelTokens = this.getAttribute('aria-labelledby');\n const externalDescTokens = this.getAttribute('aria-describedby');\n const labelEls = resolveIdrefTokens(this, externalLabelTokens);\n const descEls = resolveIdrefTokens(this, externalDescTokens);\n // Codex round-35 finding (CR major): `aria-labelledby` is only \"effective\"\n // when at least one IDREF resolves. A typo or transiently-missing target\n // must NOT erase the visible label — fall back to label/slot text so a\n // visibly-labeled toggle never becomes unnamed.\n const hasEffectiveLabelledBy = labelEls.length > 0;\n let resolvedLabel: string | null;\n if (hostAriaLabel) {\n resolvedLabel = hostAriaLabel;\n } else if (hasEffectiveLabelledBy) {\n resolvedLabel = null;\n } else if (this.label) {\n resolvedLabel = this.label;\n } else {\n // Codex round-1 finding #9: default-slot text becomes the accessible\n // name when no explicit label is provided. Without this, slotted text\n // never reaches the host's announced surface.\n resolvedLabel = this._slotLabelText || null;\n }\n\n // Codex round-2 finding #2: branch on platform support. Modern path —\n // host carries `role=button` + aria-pressed via ElementInternals.\n // Fallback path — inner native `<button>` is the announced surface; clear\n // host role/state on internals so AT does not double-announce.\n if (this._supportsIdrefRefs) {\n // ─── Modern path ───\n internals.role = 'button';\n internals.ariaPressed = this.pressed ? 'true' : 'false';\n internals.ariaDisabled = this.disabled ? 'true' : 'false';\n // Codex round-1 finding #6: drive aria-invalid from the live ValidityState\n // so a required-but-unpressed toggle is announced as invalid even before\n // any visible affordance renders. `_updateValidity()` calls this method\n // synchronously after every `setValidity()`.\n internals.ariaInvalid = !internals.validity.valid ? 'true' : 'false';\n internals.ariaLabel = resolvedLabel;\n\n type InternalsWithRefs = ElementInternals & {\n ariaLabelledByElements: Element[] | null;\n ariaDescribedByElements: Element[] | null;\n };\n const refsInternals = internals as InternalsWithRefs;\n\n refsInternals.ariaLabelledByElements = hasEffectiveLabelledBy ? labelEls : null;\n refsInternals.ariaDescribedByElements = descEls.length > 0 ? descEls : null;\n // Clear fallbacks when IDL refs are available.\n this._fallbackAriaLabelledBy = null;\n this._fallbackAriaDescribedBy = null;\n this._fallbackAriaLabel = null;\n } else {\n // ─── Fallback path: inner button is the announced surface ───\n // Round-2 finding #2: round-1 set host role/state via internals AND\n // mirrored aria-* onto the `aria-hidden` inner button — making the\n // mirrored attributes inert. The fix is to clear host role/state and\n // let the inner native `<button>` (rendered without aria-hidden, with\n // `tabindex=0`, with aria-pressed) carry semantics natively.\n internals.role = null;\n internals.ariaPressed = null;\n internals.ariaDisabled = null;\n internals.ariaInvalid = null;\n internals.ariaLabel = null;\n\n // Codex round-36 (medium): gate the fallback label tokens on the\n // *effective* labelledby contract. Mirroring broken consumer tokens to\n // the inner button on legacy engines erases the accessible name —\n // exactly the bug the modern path now defends against. When tokens\n // don't resolve, fall through to `_fallbackAriaLabel` (resolvedLabel)\n // so the slot/property still names the announced surface.\n this._fallbackAriaLabelledBy = hasEffectiveLabelledBy ? externalLabelTokens : null;\n this._fallbackAriaDescribedBy = externalDescTokens || null;\n this._fallbackAriaLabel = resolvedLabel;\n }\n }\n\n protected override _onFormReset(): void {\n this.pressed = false;\n }\n\n protected override _onFormStateRestore(\n state: string | File | FormData | null,\n _mode: 'restore' | 'autocomplete',\n ): void {\n this.pressed = typeof state === 'string' && state === 'pressed';\n }\n\n protected override _onFormDisabled(disabled: boolean): void {\n this.disabled = disabled;\n }\n\n // ─── Private Helpers ───\n\n /** @internal */\n private _syncFormValue(): void {\n if (this.pressed && this.value !== undefined) {\n // Pass explicit state 'pressed' so formStateRestoreCallback can reliably detect it.\n this._internals.setFormValue(this.value, 'pressed');\n } else {\n this._internals.setFormValue(null);\n }\n this._updateValidity();\n }\n\n /** @internal */\n private _updateValidity(): void {\n if (this.required && !this.pressed) {\n // Codex round-17 P2: anchor validity UI to the announced surface. On\n // the modern path the host is the canonical announced/focus surface\n // (the inner button is `aria-hidden + tabindex=-1`), so passing the\n // host avoids `reportValidity()` landing focus on a hidden node. On\n // the fallback path the inner button is the announced surface.\n const anchor: HTMLElement | undefined = this._supportsIdrefRefs\n ? this\n : (this.shadowRoot?.querySelector<HTMLElement>('[part=\"button\"]') ?? undefined);\n this._internals.setValidity(\n { valueMissing: true },\n 'Please activate this toggle button.',\n anchor,\n );\n } else {\n this._internals.setValidity({});\n }\n // Codex round-1 finding #6: keep `internals.ariaInvalid` aligned with the\n // current `ValidityState`.\n this._syncHostAriaSemantics();\n }\n\n // ─── Event Handling ───\n\n /** @internal */\n private _handleClick(e: MouseEvent): void {\n if (this.disabled) {\n e.preventDefault();\n e.stopPropagation();\n return;\n }\n\n this.pressed = !this.pressed;\n this._syncFormValue();\n\n /**\n * Dispatched when the toggle state changes.\n * @event hx-toggle\n */\n this.dispatchEvent(\n new CustomEvent<{ pressed: boolean }>('hx-toggle', {\n bubbles: true,\n composed: true,\n detail: { pressed: this.pressed },\n }),\n );\n\n // Codex round-12 P2: on the modern path the host owns role=\"button\" and\n // tabindex=0; the inner <button tabindex=\"-1\"> is aria-hidden. Native\n // click activation on a `<button>` still focuses it, which would leave\n // `document.activeElement` and AT focus on a hidden node. Move focus to\n // the host so the announced surface is also the focus target.\n if (this._supportsIdrefRefs) {\n this.focus();\n }\n }\n\n // ─── Render Helpers ───\n\n /** @internal */\n private _renderInner() {\n return html`\n <span part=\"prefix\" class=\"button__prefix\">\n <slot name=\"prefix\"></slot>\n </span>\n <span part=\"label\" class=\"button__label\">\n <slot @slotchange=${this._handleDefaultSlotChange}></slot>\n </span>\n <span part=\"suffix\" class=\"button__suffix\">\n <slot name=\"suffix\"></slot>\n </span>\n `;\n }\n\n // ─── Render ───\n\n override render() {\n const classes = {\n button: true,\n [`button--${this.variant}`]: true,\n [`button--${this.size}`]: true,\n 'button--pressed': this.pressed,\n };\n\n // Codex round-2 finding #2: branch the inner button on platform support.\n // Modern path — host announced, inner button is `aria-hidden + tabindex=-1`.\n // Fallback path — inner native `<button>` is announced (NO aria-hidden,\n // tabindex=0) so consumer-mirrored aria-* attributes resolve through a\n // visible accessibility-tree node and AT can name + activate it natively.\n const innerIsAnnounced = !this._supportsIdrefRefs;\n const innerTabIndex = innerIsAnnounced && !this.disabled ? '0' : '-1';\n // Round-1 finding #8: on no-IDL-ref browsers mirror host aria tokens onto\n // the inner button so it carries an accessible name. On modern browsers\n // we still mirror `label` onto the inner button for non-AT consumers\n // (testing, devtools) — does not affect announced semantics.\n const innerAriaLabel = this._fallbackAriaLabel ?? this.label ?? undefined;\n const innerAriaLabelledBy = this._fallbackAriaLabelledBy ?? undefined;\n const innerAriaDescribedBy = this._fallbackAriaDescribedBy ?? undefined;\n\n return html`\n <button\n part=\"button\"\n class=${classMap(classes)}\n ?disabled=${this.disabled}\n type=\"button\"\n tabindex=${innerTabIndex}\n aria-pressed=${this.pressed ? 'true' : 'false'}\n aria-label=${ifDefined(innerAriaLabel)}\n aria-labelledby=${ifDefined(innerAriaLabelledBy)}\n aria-describedby=${ifDefined(innerAriaDescribedBy)}\n aria-hidden=${innerIsAnnounced ? nothing : 'true'}\n @click=${this._handleClick}\n >\n ${this._renderInner()}\n </button>\n `;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'hx-toggle-button': HelixToggleButton;\n }\n}\n"],"names":["helixToggleButtonStyles","css","HelixToggleButton","HelixElement","e","supportsIdrefElementReferences","enabledTabIndex","installAriaIdrefMirror","_a","_b","options","changedProperties","slot","n","text","observer","node","internals","hostAriaLabel","externalLabelTokens","externalDescTokens","labelEls","resolveIdrefTokens","descEls","hasEffectiveLabelledBy","resolvedLabel","refsInternals","state","_mode","disabled","anchor","html","classes","innerIsAnnounced","innerTabIndex","innerAriaLabel","innerAriaLabelledBy","innerAriaDescribedBy","classMap","ifDefined","nothing","forcedColorsInteractive","__decorateClass","query","property","customElement"],"mappings":";;;;;;;AAEO,MAAMA,IAA0BC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;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"}
|