@helixui/library 3.7.0 → 3.8.0-next.145
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +41 -0
- package/aaa-verdicts.json +2036 -0
- package/custom-elements.json +1657 -71
- package/dist/components/hx-accordion/hx-accordion-item.d.ts.map +1 -1
- package/dist/components/hx-accordion/hx-accordion-item.styles.d.ts.map +1 -1
- package/dist/components/hx-accordion/index.js +1 -1
- package/dist/components/hx-action-bar/hx-action-bar.d.ts +18 -0
- package/dist/components/hx-action-bar/hx-action-bar.d.ts.map +1 -1
- package/dist/components/hx-action-bar/hx-action-bar.styles.d.ts.map +1 -1
- package/dist/components/hx-action-bar/index.js +1 -1
- package/dist/components/hx-alert/hx-alert.d.ts +0 -8
- 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-avatar/hx-avatar.d.ts +4 -1
- package/dist/components/hx-avatar/hx-avatar.d.ts.map +1 -1
- package/dist/components/hx-avatar/hx-avatar.styles.d.ts.map +1 -1
- package/dist/components/hx-avatar/index.js +1 -1
- package/dist/components/hx-badge/hx-badge.d.ts.map +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 +19 -8
- package/dist/components/hx-banner/hx-banner.d.ts.map +1 -1
- package/dist/components/hx-banner/hx-banner.styles.d.ts.map +1 -1
- package/dist/components/hx-banner/index.js +1 -1
- package/dist/components/hx-breadcrumb/hx-breadcrumb-item.d.ts.map +1 -1
- package/dist/components/hx-breadcrumb/hx-breadcrumb-item.styles.d.ts.map +1 -1
- package/dist/components/hx-breadcrumb/hx-breadcrumb.d.ts +18 -0
- package/dist/components/hx-breadcrumb/hx-breadcrumb.d.ts.map +1 -1
- package/dist/components/hx-breadcrumb/index.js +1 -1
- package/dist/components/hx-button/hx-button.styles.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 +47 -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-carousel/hx-carousel.d.ts.map +1 -1
- package/dist/components/hx-carousel/hx-carousel.styles.d.ts.map +1 -1
- package/dist/components/hx-carousel/index.js +1 -1
- package/dist/components/hx-checkbox/hx-checkbox.d.ts.map +1 -1
- package/dist/components/hx-checkbox/hx-checkbox.styles.d.ts.map +1 -1
- package/dist/components/hx-checkbox/index.js +1 -1
- package/dist/components/hx-checkbox-group/hx-checkbox-group.d.ts +36 -0
- package/dist/components/hx-checkbox-group/hx-checkbox-group.d.ts.map +1 -1
- package/dist/components/hx-checkbox-group/hx-checkbox-group.styles.d.ts.map +1 -1
- package/dist/components/hx-checkbox-group/index.js +1 -1
- package/dist/components/hx-clinical-status/hx-clinical-status.d.ts +26 -9
- package/dist/components/hx-clinical-status/hx-clinical-status.d.ts.map +1 -1
- package/dist/components/hx-clinical-status/hx-clinical-status.styles.d.ts.map +1 -1
- package/dist/components/hx-clinical-status/index.js +1 -1
- package/dist/components/hx-color-picker/hx-color-picker.d.ts +18 -0
- package/dist/components/hx-color-picker/hx-color-picker.d.ts.map +1 -1
- package/dist/components/hx-color-picker/hx-color-picker.styles.d.ts.map +1 -1
- package/dist/components/hx-color-picker/index.js +1 -1
- package/dist/components/hx-combobox/hx-combobox.d.ts +18 -0
- package/dist/components/hx-combobox/hx-combobox.d.ts.map +1 -1
- package/dist/components/hx-combobox/hx-combobox.styles.d.ts.map +1 -1
- package/dist/components/hx-combobox/index.js +1 -1
- package/dist/components/hx-copy-button/hx-copy-button.d.ts +18 -0
- package/dist/components/hx-copy-button/hx-copy-button.d.ts.map +1 -1
- package/dist/components/hx-copy-button/hx-copy-button.styles.d.ts.map +1 -1
- package/dist/components/hx-copy-button/index.js +1 -1
- package/dist/components/hx-date-picker/hx-date-picker.d.ts +18 -0
- package/dist/components/hx-date-picker/hx-date-picker.d.ts.map +1 -1
- package/dist/components/hx-date-picker/hx-date-picker.styles.d.ts.map +1 -1
- package/dist/components/hx-date-picker/index.js +1 -1
- package/dist/components/hx-drawer/hx-drawer.d.ts +18 -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 +18 -0
- package/dist/components/hx-dropdown/hx-dropdown.d.ts.map +1 -1
- package/dist/components/hx-dropdown/hx-dropdown.styles.d.ts.map +1 -1
- package/dist/components/hx-dropdown/index.js +1 -1
- package/dist/components/hx-field/hx-field.d.ts +17 -0
- package/dist/components/hx-field/hx-field.d.ts.map +1 -1
- package/dist/components/hx-field-label/hx-field-label.d.ts +17 -0
- package/dist/components/hx-field-label/hx-field-label.d.ts.map +1 -1
- package/dist/components/hx-file-upload/hx-file-upload.d.ts +46 -0
- package/dist/components/hx-file-upload/hx-file-upload.d.ts.map +1 -1
- package/dist/components/hx-file-upload/hx-file-upload.styles.d.ts.map +1 -1
- package/dist/components/hx-file-upload/index.js +1 -1
- package/dist/components/hx-form/hx-form.d.ts +19 -0
- package/dist/components/hx-form/hx-form.d.ts.map +1 -1
- package/dist/components/hx-help-text/hx-help-text.d.ts +17 -0
- package/dist/components/hx-help-text/hx-help-text.d.ts.map +1 -1
- package/dist/components/hx-help-text/hx-help-text.styles.d.ts.map +1 -1
- package/dist/components/hx-help-text/index.js +1 -1
- package/dist/components/hx-icon/hx-icon.d.ts +108 -12
- package/dist/components/hx-icon/hx-icon.d.ts.map +1 -1
- package/dist/components/hx-icon/hx-icon.styles.d.ts.map +1 -1
- package/dist/components/hx-icon/index.js +1 -1
- package/dist/components/hx-icon-button/hx-icon-button.d.ts +18 -0
- package/dist/components/hx-icon-button/hx-icon-button.d.ts.map +1 -1
- package/dist/components/hx-link/hx-link.d.ts.map +1 -1
- package/dist/components/hx-link/hx-link.styles.d.ts.map +1 -1
- package/dist/components/hx-link/index.js +1 -1
- 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 +18 -0
- 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-nav/hx-nav.d.ts +18 -0
- package/dist/components/hx-nav/hx-nav.d.ts.map +1 -1
- package/dist/components/hx-nav/hx-nav.styles.d.ts.map +1 -1
- package/dist/components/hx-nav/index.js +1 -1
- package/dist/components/hx-number-input/hx-number-input.d.ts +18 -0
- package/dist/components/hx-number-input/hx-number-input.d.ts.map +1 -1
- package/dist/components/hx-number-input/hx-number-input.styles.d.ts.map +1 -1
- package/dist/components/hx-number-input/index.js +1 -1
- package/dist/components/hx-overflow-menu/hx-overflow-menu.d.ts +23 -1
- package/dist/components/hx-overflow-menu/hx-overflow-menu.d.ts.map +1 -1
- package/dist/components/hx-overflow-menu/hx-overflow-menu.styles.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.map +1 -1
- package/dist/components/hx-phi-field/hx-phi-field.styles.d.ts.map +1 -1
- package/dist/components/hx-phi-field/index.js +1 -1
- package/dist/components/hx-popover/hx-popover.d.ts +18 -0
- package/dist/components/hx-popover/hx-popover.d.ts.map +1 -1
- package/dist/components/hx-popover/hx-popover.styles.d.ts.map +1 -1
- package/dist/components/hx-popover/index.js +1 -1
- package/dist/components/hx-popup/hx-popup.d.ts +18 -0
- package/dist/components/hx-popup/hx-popup.d.ts.map +1 -1
- package/dist/components/hx-popup/hx-popup.styles.d.ts.map +1 -1
- package/dist/components/hx-popup/index.js +1 -1
- package/dist/components/hx-radio-group/hx-radio-group.d.ts +18 -0
- package/dist/components/hx-radio-group/hx-radio-group.d.ts.map +1 -1
- package/dist/components/hx-radio-group/hx-radio-group.styles.d.ts.map +1 -1
- package/dist/components/hx-radio-group/hx-radio.styles.d.ts.map +1 -1
- package/dist/components/hx-radio-group/index.js +1 -1
- package/dist/components/hx-rating/hx-rating.d.ts +19 -0
- package/dist/components/hx-rating/hx-rating.d.ts.map +1 -1
- package/dist/components/hx-rating/hx-rating.styles.d.ts.map +1 -1
- package/dist/components/hx-rating/index.js +1 -1
- package/dist/components/hx-select/hx-select.d.ts +18 -0
- package/dist/components/hx-select/hx-select.d.ts.map +1 -1
- package/dist/components/hx-side-nav/hx-nav-item.d.ts.map +1 -1
- package/dist/components/hx-side-nav/hx-nav-item.styles.d.ts.map +1 -1
- package/dist/components/hx-side-nav/hx-side-nav.d.ts +18 -0
- package/dist/components/hx-side-nav/hx-side-nav.d.ts.map +1 -1
- package/dist/components/hx-side-nav/hx-side-nav.styles.d.ts.map +1 -1
- package/dist/components/hx-side-nav/index.js +1 -1
- package/dist/components/hx-slider/hx-slider.d.ts +47 -0
- package/dist/components/hx-slider/hx-slider.d.ts.map +1 -1
- package/dist/components/hx-slider/index.js +1 -1
- package/dist/components/hx-split-button/hx-split-button.d.ts +18 -0
- package/dist/components/hx-split-button/hx-split-button.d.ts.map +1 -1
- package/dist/components/hx-split-button/hx-split-button.styles.d.ts.map +1 -1
- package/dist/components/hx-split-button/index.js +1 -1
- package/dist/components/hx-stat/hx-stat.d.ts.map +1 -1
- package/dist/components/hx-stat/hx-stat.styles.d.ts.map +1 -1
- package/dist/components/hx-stat/index.js +1 -1
- package/dist/components/hx-steps/hx-step.d.ts.map +1 -1
- package/dist/components/hx-steps/hx-step.styles.d.ts.map +1 -1
- package/dist/components/hx-steps/index.js +1 -1
- package/dist/components/hx-switch/hx-switch.d.ts +18 -0
- package/dist/components/hx-switch/hx-switch.d.ts.map +1 -1
- package/dist/components/hx-switch/hx-switch.styles.d.ts.map +1 -1
- package/dist/components/hx-switch/index.js +1 -1
- package/dist/components/hx-tabs/hx-tab.styles.d.ts.map +1 -1
- package/dist/components/hx-tabs/hx-tabs.d.ts +18 -0
- 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.d.ts.map +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-text-input/hx-text-input.styles.d.ts.map +1 -1
- package/dist/components/hx-text-input/index.js +1 -1
- package/dist/components/hx-textarea/hx-textarea.d.ts +18 -0
- package/dist/components/hx-textarea/hx-textarea.d.ts.map +1 -1
- package/dist/components/hx-time-picker/hx-time-picker.d.ts +18 -0
- 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.d.ts +19 -8
- package/dist/components/hx-toast/hx-toast.d.ts.map +1 -1
- package/dist/components/hx-toast/hx-toast.styles.d.ts.map +1 -1
- package/dist/components/hx-toast/index.js +1 -1
- package/dist/components/hx-toggle-button/hx-toggle-button.d.ts +18 -0
- package/dist/components/hx-toggle-button/hx-toggle-button.d.ts.map +1 -1
- package/dist/components/hx-toggle-button/hx-toggle-button.styles.d.ts.map +1 -1
- package/dist/components/hx-toggle-button/index.js +1 -1
- package/dist/components/hx-tooltip/hx-tooltip.d.ts +18 -0
- package/dist/components/hx-tooltip/hx-tooltip.d.ts.map +1 -1
- package/dist/components/hx-tooltip/hx-tooltip.styles.d.ts.map +1 -1
- package/dist/components/hx-tooltip/index.js +1 -1
- package/dist/components/hx-top-nav/hx-top-nav.d.ts +18 -0
- package/dist/components/hx-top-nav/hx-top-nav.d.ts.map +1 -1
- package/dist/components/hx-top-nav/hx-top-nav.styles.d.ts.map +1 -1
- package/dist/components/hx-top-nav/index.js +1 -1
- package/dist/components/hx-tree-view/hx-tree-item.d.ts.map +1 -1
- package/dist/components/hx-tree-view/hx-tree-item.styles.d.ts.map +1 -1
- package/dist/components/hx-tree-view/index.js +1 -1
- package/dist/css/helix-all.css +355 -84
- package/dist/css/helix-core.css +23 -5
- package/dist/css/helix-feedback.css +15 -18
- package/dist/css/helix-forms.css +139 -27
- package/dist/css/helix-media.css +6 -3
- package/dist/css/helix-navigation.css +59 -9
- package/dist/css/helix-overlay.css +63 -0
- package/dist/css/helix-tokens.css +16 -14
- package/dist/css/helix-utility.css +44 -12
- package/dist/css/hx-action-bar.css +12 -0
- package/dist/css/hx-alert.css +4 -8
- package/dist/css/hx-avatar.css +1 -2
- package/dist/css/hx-badge.css +5 -0
- package/dist/css/hx-banner.css +4 -8
- package/dist/css/hx-button.css +4 -1
- package/dist/css/hx-carousel.css +6 -3
- package/dist/css/hx-checkbox-group.css +11 -0
- package/dist/css/hx-checkbox.css +14 -9
- package/dist/css/hx-clinical-status.css +4 -7
- package/dist/css/hx-color-picker.css +14 -1
- package/dist/css/hx-combobox.css +8 -0
- package/dist/css/hx-copy-button.css +5 -2
- package/dist/css/hx-date-picker.css +11 -1
- package/dist/css/hx-drawer.css +5 -0
- package/dist/css/hx-dropdown.css +18 -0
- package/dist/css/hx-file-upload.css +4 -0
- package/dist/css/hx-help-text.css +5 -0
- package/dist/css/hx-icon.css +7 -0
- package/dist/css/hx-link.css +1 -2
- package/dist/css/hx-nav.css +31 -2
- package/dist/css/hx-number-input.css +10 -11
- package/dist/css/hx-overflow-menu.css +5 -0
- package/dist/css/hx-phi-field.css +2 -3
- package/dist/css/hx-popover.css +13 -0
- package/dist/css/hx-popup.css +14 -0
- package/dist/css/hx-radio-group.css +10 -0
- package/dist/css/hx-rating.css +6 -0
- package/dist/css/hx-side-nav.css +10 -5
- package/dist/css/hx-split-button.css +27 -10
- package/dist/css/hx-stat.css +1 -2
- package/dist/css/hx-switch.css +19 -1
- package/dist/css/hx-tag.css +5 -0
- package/dist/css/hx-text-input.css +4 -1
- package/dist/css/hx-time-picker.css +12 -2
- package/dist/css/hx-toast.css +6 -0
- package/dist/css/hx-toggle-button.css +11 -1
- package/dist/css/hx-tooltip.css +13 -0
- package/dist/css/hx-top-nav.css +13 -2
- package/dist/css/index.css +1 -1
- package/dist/css/manifest.json +43 -12
- package/dist/index.js +47 -47
- package/dist/shared/{hx-accordion-ZVzgDzTG.js → hx-accordion-DR--Ev4t.js} +48 -54
- package/dist/shared/hx-accordion-DR--Ev4t.js.map +1 -0
- package/dist/shared/{hx-action-bar-CitgcpGv.js → hx-action-bar-BlEG4aZv.js} +41 -29
- package/dist/shared/hx-action-bar-BlEG4aZv.js.map +1 -0
- package/dist/shared/{hx-alert-Bto8-TIi.js → hx-alert-C0axS32J.js} +40 -79
- package/dist/shared/hx-alert-C0axS32J.js.map +1 -0
- package/dist/shared/{hx-avatar-C9hOmlAb.js → hx-avatar-ChAYWnK8.js} +22 -24
- package/dist/shared/hx-avatar-ChAYWnK8.js.map +1 -0
- package/dist/shared/{hx-badge-DFL35nzi.js → hx-badge-vX-1cuLA.js} +16 -11
- package/dist/shared/hx-badge-vX-1cuLA.js.map +1 -0
- package/dist/shared/{hx-banner-fpRnciIO.js → hx-banner-PbHwFNSb.js} +51 -90
- package/dist/shared/hx-banner-PbHwFNSb.js.map +1 -0
- package/dist/shared/{hx-breadcrumb-item-3tKppF9h.js → hx-breadcrumb-item-D8xYqe3s.js} +56 -43
- package/dist/shared/hx-breadcrumb-item-D8xYqe3s.js.map +1 -0
- package/dist/shared/{hx-button-rRNmD4fd.js → hx-button-DOZTZnz-.js} +18 -15
- package/dist/shared/hx-button-DOZTZnz-.js.map +1 -0
- package/dist/shared/hx-button-group-D3QUmSzl.js +248 -0
- package/dist/shared/hx-button-group-D3QUmSzl.js.map +1 -0
- package/dist/shared/{hx-carousel-item-z1Lc24op.js → hx-carousel-item-BVIKgQ4i.js} +72 -102
- package/dist/shared/hx-carousel-item-BVIKgQ4i.js.map +1 -0
- package/dist/shared/{hx-checkbox-hPlIw6Lb.js → hx-checkbox-DDSXXhps.js} +33 -30
- package/dist/shared/hx-checkbox-DDSXXhps.js.map +1 -0
- package/dist/shared/{hx-checkbox-group-D5piJLY8.js → hx-checkbox-group-C0q6HDqn.js} +101 -58
- package/dist/shared/hx-checkbox-group-C0q6HDqn.js.map +1 -0
- package/dist/shared/{hx-clinical-status-D3XQIOqX.js → hx-clinical-status-ZSVEc3Qg.js} +68 -87
- package/dist/shared/hx-clinical-status-ZSVEc3Qg.js.map +1 -0
- package/dist/shared/{hx-color-picker-DBwJzT5f.js → hx-color-picker-CYjx8i8R.js} +97 -84
- package/dist/shared/hx-color-picker-CYjx8i8R.js.map +1 -0
- package/dist/shared/{hx-combobox-NgJaLbs2.js → hx-combobox-Be-mqOv4.js} +35 -45
- package/dist/shared/hx-combobox-Be-mqOv4.js.map +1 -0
- package/dist/shared/{hx-copy-button-sUVuikyH.js → hx-copy-button-DJirFCUL.js} +18 -15
- package/dist/shared/hx-copy-button-DJirFCUL.js.map +1 -0
- package/dist/shared/{hx-date-picker-DSKDkCy1.js → hx-date-picker-CziP3Hm1.js} +80 -82
- package/dist/shared/hx-date-picker-CziP3Hm1.js.map +1 -0
- package/dist/shared/{hx-drawer-CM_upadk.js → hx-drawer-BlU2oX8-.js} +32 -36
- package/dist/shared/hx-drawer-BlU2oX8-.js.map +1 -0
- package/dist/shared/{hx-dropdown-D626S2ZG.js → hx-dropdown-DREqpIpm.js} +51 -33
- package/dist/shared/hx-dropdown-DREqpIpm.js.map +1 -0
- package/dist/shared/hx-field-label-BVRyyKeh.js.map +1 -1
- package/dist/shared/hx-field-zw0U1KVi.js.map +1 -1
- package/dist/shared/{hx-file-upload-D3rKROK5.js → hx-file-upload-CU5QGZSP.js} +137 -80
- package/dist/shared/hx-file-upload-CU5QGZSP.js.map +1 -0
- package/dist/shared/hx-form-CkChEATa.js.map +1 -1
- package/dist/shared/hx-help-text-CNaZ82LT.js +137 -0
- package/dist/shared/hx-help-text-CNaZ82LT.js.map +1 -0
- package/dist/shared/hx-icon-button-B2BdVdyK.js.map +1 -1
- package/dist/shared/hx-icon-bxz9eB9a.js +386 -0
- package/dist/shared/hx-icon-bxz9eB9a.js.map +1 -0
- package/dist/shared/{hx-link-CMnZRUtQ.js → hx-link-BURSdYLp.js} +19 -26
- package/dist/shared/hx-link-BURSdYLp.js.map +1 -0
- package/dist/shared/{hx-menu-divider-A6Guuzi_.js → hx-menu-divider-g0grbWV9.js} +19 -31
- package/dist/shared/hx-menu-divider-g0grbWV9.js.map +1 -0
- package/dist/shared/{hx-nav-ldFM3Fle.js → hx-nav-GTsAZGOx.js} +94 -85
- package/dist/shared/hx-nav-GTsAZGOx.js.map +1 -0
- package/dist/shared/{hx-nav-item-CODtUlew.js → hx-nav-item-CxE7Mp3M.js} +46 -41
- package/dist/shared/hx-nav-item-CxE7Mp3M.js.map +1 -0
- package/dist/shared/{hx-number-input-yUzFOSC1.js → hx-number-input-Bvyc9kOi.js} +59 -64
- package/dist/shared/hx-number-input-Bvyc9kOi.js.map +1 -0
- package/dist/shared/{hx-overflow-menu-DFjJAziP.js → hx-overflow-menu-LrTteeR1.js} +32 -39
- package/dist/shared/{hx-overflow-menu-DFjJAziP.js.map → hx-overflow-menu-LrTteeR1.js.map} +1 -1
- package/dist/shared/{hx-phi-field-C19oxlrr.js → hx-phi-field-sZt_rYIL.js} +46 -66
- package/dist/shared/hx-phi-field-sZt_rYIL.js.map +1 -0
- package/dist/shared/{hx-popover-BAlAFOH9.js → hx-popover-BjB0nkcq.js} +51 -38
- package/dist/shared/hx-popover-BjB0nkcq.js.map +1 -0
- package/dist/shared/{hx-popup-COUXXZ9X.js → hx-popup-BiV_2evC.js} +59 -45
- package/dist/shared/hx-popup-BiV_2evC.js.map +1 -0
- package/dist/shared/{hx-radio-CY4kQfZw.js → hx-radio-BD_c9NJy.js} +83 -70
- package/dist/shared/hx-radio-BD_c9NJy.js.map +1 -0
- package/dist/shared/{hx-rating-C3QP53k9.js → hx-rating-BGK4AxvI.js} +45 -71
- package/dist/shared/hx-rating-BGK4AxvI.js.map +1 -0
- package/dist/shared/hx-select-DahFehiZ.js.map +1 -1
- package/dist/shared/{hx-slider-Blmv_rwS.js → hx-slider-CkOk5BCY.js} +83 -23
- package/dist/shared/hx-slider-CkOk5BCY.js.map +1 -0
- package/dist/shared/{hx-split-button-Ddle8iVx.js → hx-split-button-Bg9FHrFK.js} +73 -65
- package/dist/shared/hx-split-button-Bg9FHrFK.js.map +1 -0
- package/dist/shared/{hx-stat-Gtw_SpK8.js → hx-stat-wKxbyep6.js} +22 -55
- package/dist/shared/hx-stat-wKxbyep6.js.map +1 -0
- package/dist/shared/{hx-step-CUzliIK_.js → hx-step-CyGQAuiB.js} +5 -25
- package/dist/shared/hx-step-CyGQAuiB.js.map +1 -0
- package/dist/shared/{hx-switch-TvKGvZJz.js → hx-switch-BCXuNxEH.js} +42 -24
- package/dist/shared/hx-switch-BCXuNxEH.js.map +1 -0
- package/dist/shared/{hx-tab-panel-DzsX8BHV.js → hx-tab-panel-BfisavKo.js} +47 -32
- package/dist/shared/hx-tab-panel-BfisavKo.js.map +1 -0
- package/dist/shared/{hx-tag-C5aCUpVi.js → hx-tag-BqO6HY6V.js} +26 -21
- package/dist/shared/hx-tag-BqO6HY6V.js.map +1 -0
- package/dist/shared/{hx-text-input-D6FlOZM-.js → hx-text-input-V5sQOpDh.js} +5 -2
- package/dist/shared/hx-text-input-V5sQOpDh.js.map +1 -0
- package/dist/shared/hx-textarea-CNG590KY.js.map +1 -1
- package/dist/shared/{hx-time-picker-Bo7FWzmf.js → hx-time-picker-if5Cl0Ei.js} +42 -43
- package/dist/shared/hx-time-picker-if5Cl0Ei.js.map +1 -0
- package/dist/shared/{hx-toggle-button-DSJeFlb0.js → hx-toggle-button-xNVYeA3X.js} +37 -27
- package/dist/shared/hx-toggle-button-xNVYeA3X.js.map +1 -0
- package/dist/shared/{hx-tooltip-DVqtKPCD.js → hx-tooltip-CamO-9nd.js} +24 -11
- package/dist/shared/hx-tooltip-CamO-9nd.js.map +1 -0
- package/dist/shared/{hx-top-nav-DP6OFS8C.js → hx-top-nav-vP6oDWMV.js} +42 -44
- package/dist/shared/hx-top-nav-vP6oDWMV.js.map +1 -0
- package/dist/shared/{hx-tree-item-CXyspGxI.js → hx-tree-item-D8hwKd5m.js} +54 -57
- package/dist/shared/hx-tree-item-D8hwKd5m.js.map +1 -0
- package/dist/shared/{toast-factory-Dht3pVsw.js → toast-factory-DgnbFxVs.js} +127 -153
- package/dist/shared/toast-factory-DgnbFxVs.js.map +1 -0
- package/figma-inventory.json +1166 -411
- package/package.json +8 -4
- package/dist/shared/hx-accordion-ZVzgDzTG.js.map +0 -1
- package/dist/shared/hx-action-bar-CitgcpGv.js.map +0 -1
- package/dist/shared/hx-alert-Bto8-TIi.js.map +0 -1
- package/dist/shared/hx-avatar-C9hOmlAb.js.map +0 -1
- package/dist/shared/hx-badge-DFL35nzi.js.map +0 -1
- package/dist/shared/hx-banner-fpRnciIO.js.map +0 -1
- package/dist/shared/hx-breadcrumb-item-3tKppF9h.js.map +0 -1
- package/dist/shared/hx-button-group-4NUBpkyC.js +0 -181
- package/dist/shared/hx-button-group-4NUBpkyC.js.map +0 -1
- package/dist/shared/hx-button-rRNmD4fd.js.map +0 -1
- package/dist/shared/hx-carousel-item-z1Lc24op.js.map +0 -1
- package/dist/shared/hx-checkbox-group-D5piJLY8.js.map +0 -1
- package/dist/shared/hx-checkbox-hPlIw6Lb.js.map +0 -1
- package/dist/shared/hx-clinical-status-D3XQIOqX.js.map +0 -1
- package/dist/shared/hx-color-picker-DBwJzT5f.js.map +0 -1
- package/dist/shared/hx-combobox-NgJaLbs2.js.map +0 -1
- package/dist/shared/hx-copy-button-sUVuikyH.js.map +0 -1
- package/dist/shared/hx-date-picker-DSKDkCy1.js.map +0 -1
- package/dist/shared/hx-drawer-CM_upadk.js.map +0 -1
- package/dist/shared/hx-dropdown-D626S2ZG.js.map +0 -1
- package/dist/shared/hx-file-upload-D3rKROK5.js.map +0 -1
- package/dist/shared/hx-help-text-Xb2Yr8x2.js +0 -156
- package/dist/shared/hx-help-text-Xb2Yr8x2.js.map +0 -1
- package/dist/shared/hx-icon-fuVm4-bk.js +0 -283
- package/dist/shared/hx-icon-fuVm4-bk.js.map +0 -1
- package/dist/shared/hx-link-CMnZRUtQ.js.map +0 -1
- package/dist/shared/hx-menu-divider-A6Guuzi_.js.map +0 -1
- package/dist/shared/hx-nav-item-CODtUlew.js.map +0 -1
- package/dist/shared/hx-nav-ldFM3Fle.js.map +0 -1
- package/dist/shared/hx-number-input-yUzFOSC1.js.map +0 -1
- package/dist/shared/hx-phi-field-C19oxlrr.js.map +0 -1
- package/dist/shared/hx-popover-BAlAFOH9.js.map +0 -1
- package/dist/shared/hx-popup-COUXXZ9X.js.map +0 -1
- package/dist/shared/hx-radio-CY4kQfZw.js.map +0 -1
- package/dist/shared/hx-rating-C3QP53k9.js.map +0 -1
- package/dist/shared/hx-slider-Blmv_rwS.js.map +0 -1
- package/dist/shared/hx-split-button-Ddle8iVx.js.map +0 -1
- package/dist/shared/hx-stat-Gtw_SpK8.js.map +0 -1
- package/dist/shared/hx-step-CUzliIK_.js.map +0 -1
- package/dist/shared/hx-switch-TvKGvZJz.js.map +0 -1
- package/dist/shared/hx-tab-panel-DzsX8BHV.js.map +0 -1
- package/dist/shared/hx-tag-C5aCUpVi.js.map +0 -1
- package/dist/shared/hx-text-input-D6FlOZM-.js.map +0 -1
- package/dist/shared/hx-time-picker-Bo7FWzmf.js.map +0 -1
- package/dist/shared/hx-toggle-button-DSJeFlb0.js.map +0 -1
- package/dist/shared/hx-tooltip-DVqtKPCD.js.map +0 -1
- package/dist/shared/hx-top-nav-DP6OFS8C.js.map +0 -1
- package/dist/shared/hx-tree-item-CXyspGxI.js.map +0 -1
- package/dist/shared/toast-factory-Dht3pVsw.js.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hx-drawer-BlU2oX8-.js","sources":["../../src/components/hx-drawer/hx-drawer.styles.ts","../../src/components/hx-drawer/hx-drawer.ts"],"sourcesContent":["import { css } from 'lit';\n\n/**\n * hx-drawer styles.\n *\n * Component-tier tokens with two-level var() fallback:\n * var(--hx-drawer-{prop}, var(--hx-color-{semantic}, #hex))\n * Inner hex fallbacks track the \"precision cool\" palette (3.2.0):\n * neutral-0 = #FFFFFF, neutral-100 = #EBEEE9, neutral-200 = #D6DBD5,\n * neutral-500 = #66787B, neutral-800 = #202B39, neutral-900 = #0D1825,\n * primary-500 = #429797.\n */\nexport const helixDrawerStyles = css`\n /* P2-03: Explicit [hidden] rule to survive CSS resets that may override the UA stylesheet. */\n [hidden] {\n display: none !important;\n }\n\n :host {\n display: contents;\n }\n\n :host([contained]) {\n display: block;\n position: relative;\n overflow: hidden;\n }\n\n /* ─── Overlay ─── */\n\n .drawer-overlay {\n position: fixed;\n inset: 0;\n z-index: var(--hx-z-index-modal, 1400);\n display: flex;\n pointer-events: none;\n visibility: hidden;\n }\n\n :host([contained]) .drawer-overlay {\n position: absolute;\n }\n\n .drawer-overlay.is-open {\n pointer-events: auto;\n visibility: visible;\n }\n\n /* ─── Backdrop ─── */\n\n .drawer-backdrop {\n position: absolute;\n inset: 0;\n background-color: var(\n --hx-drawer-backdrop-color,\n var(--hx-color-surface-overlay, rgba(0, 0, 0, 0.75))\n );\n opacity: 0;\n transition: opacity var(--hx-duration-slow, 300ms) var(--hx-easing-out, ease-out);\n }\n\n .drawer-overlay.is-open .drawer-backdrop {\n opacity: var(--hx-drawer-backdrop-opacity, 0.5);\n }\n\n @media (prefers-reduced-motion: reduce) {\n .drawer-backdrop {\n transition: none;\n }\n }\n\n /* ─── Panel ─── */\n\n .drawer-panel {\n position: absolute;\n display: flex;\n flex-direction: column;\n background-color: var(--hx-drawer-bg, var(--hx-color-surface-default, #ffffff));\n color: var(--hx-drawer-color, var(--hx-color-text-primary, #0d1825));\n box-shadow: var(--hx-drawer-shadow, var(--hx-shadow-xl, 0 20px 25px -5px rgb(0 0 0 / 0.1)));\n overflow: hidden;\n outline: none;\n z-index: 1; /* local stacking context: panel above backdrop within overlay container */\n transition:\n transform var(--hx-duration-slow, 300ms) var(--hx-easing-out, ease-out),\n opacity var(--hx-duration-slow, 300ms) var(--hx-easing-out, ease-out);\n opacity: 0;\n }\n\n @media (prefers-reduced-motion: reduce) {\n .drawer-panel {\n transition: none;\n }\n\n .drawer-close-button {\n transition: none;\n }\n }\n\n /* ─── Placement: end (default — right) ─── */\n\n :host([placement='end']) .drawer-panel,\n :host(:not([placement])) .drawer-panel {\n top: 0;\n inset-inline-end: 0;\n bottom: 0;\n width: var(--_drawer-size, var(--hx-drawer-size-md, 30rem));\n max-width: 100%;\n transform: translateX(100%);\n }\n\n :host([placement='end']) .drawer-overlay.is-open .drawer-panel,\n :host(:not([placement])) .drawer-overlay.is-open .drawer-panel {\n transform: translateX(0);\n opacity: 1;\n }\n\n /* ─── Placement: start (left) ─── */\n\n :host([placement='start']) .drawer-panel {\n top: 0;\n inset-inline-start: 0;\n bottom: 0;\n width: var(--_drawer-size, var(--hx-drawer-size-md, 30rem));\n max-width: 100%;\n transform: translateX(-100%);\n }\n\n :host([placement='start']) .drawer-overlay.is-open .drawer-panel {\n transform: translateX(0);\n opacity: 1;\n }\n\n /* ─── Placement: top ─── */\n\n :host([placement='top']) .drawer-panel {\n top: 0;\n inset-inline-start: 0;\n inset-inline-end: 0;\n height: var(--_drawer-size, var(--hx-drawer-size-md, 30rem));\n max-height: 100%;\n width: 100%;\n transform: translateY(-100%);\n }\n\n :host([placement='top']) .drawer-overlay.is-open .drawer-panel {\n transform: translateY(0);\n opacity: 1;\n }\n\n /* ─── Placement: bottom ─── */\n\n :host([placement='bottom']) .drawer-panel {\n bottom: 0;\n inset-inline-start: 0;\n inset-inline-end: 0;\n height: var(--_drawer-size, var(--hx-drawer-size-md, 30rem));\n max-height: 100%;\n width: 100%;\n transform: translateY(100%);\n }\n\n :host([placement='bottom']) .drawer-overlay.is-open .drawer-panel {\n transform: translateY(0);\n opacity: 1;\n }\n\n /* ─── Header ─── */\n\n .drawer-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: var(--hx-space-4, 1rem);\n padding: var(--hx-drawer-header-padding, var(--hx-space-5, 1.25rem) var(--hx-space-6, 1.5rem));\n border-bottom: var(--hx-border-width-thin, 1px) solid\n var(--hx-drawer-header-border-color, var(--hx-color-border-default, #d6dbd5));\n flex-shrink: 0;\n }\n\n .drawer-title {\n margin: 0;\n flex: 1 1 auto;\n font-family: var(--hx-drawer-font-family, var(--hx-font-family-sans, sans-serif));\n font-size: var(--hx-font-size-lg, 1.125rem);\n font-weight: var(--hx-font-weight-semibold, 600);\n line-height: var(--hx-line-height-tight, 1.25);\n color: var(--hx-drawer-title-color, var(--hx-color-text-primary, #0d1825));\n }\n\n .drawer-header-actions {\n display: flex;\n align-items: center;\n gap: var(--hx-space-2, 0.5rem);\n flex-shrink: 0;\n }\n\n .drawer-close-button {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n /* WCAG 2.5.5 (healthcare mandate): minimum 44x44px touch target */\n min-width: var(--hx-touch-target-min, 2.75rem);\n min-height: var(--hx-touch-target-min, 2.75rem);\n width: var(--hx-touch-target-min, 2.75rem);\n height: var(--hx-touch-target-min, 2.75rem);\n padding: 0;\n border: none;\n border-radius: var(--hx-border-radius-md, 0.375rem);\n background: transparent;\n color: var(--hx-drawer-close-btn-color, var(--hx-color-text-muted, #4a5362));\n cursor: pointer;\n flex-shrink: 0;\n transition: background-color var(--hx-duration-fast, 100ms) var(--hx-easing-default, ease);\n }\n\n .drawer-close-button:hover {\n background-color: var(--hx-drawer-close-btn-hover-bg, var(--hx-color-surface-sunken, #ebeee9));\n color: var(--hx-drawer-close-btn-hover-color, var(--hx-color-text-primary, #0d1825));\n }\n\n .drawer-close-button:focus-visible {\n outline: var(--hx-focus-ring-width, 2px) solid\n var(--hx-drawer-close-btn-focus-ring-color, var(--hx-focus-ring-color, #0f7078));\n outline-offset: var(--hx-focus-ring-offset, 2px);\n }\n\n /* ─── Visually-hidden close button (no-header mode, WCAG 4.1.2) ─── */\n /* Keeps the button reachable by keyboard/AT but invisible to sighted users. */\n\n .drawer-close-button--sr-only {\n position: absolute;\n width: 1px;\n height: 1px;\n padding: 0;\n margin: -1px;\n overflow: hidden;\n clip: rect(0, 0, 0, 0);\n white-space: nowrap;\n border: 0;\n }\n\n /* When focused via keyboard, restore visibility so users know where focus is. */\n .drawer-close-button--sr-only:focus-visible {\n position: static;\n width: auto;\n height: auto;\n clip: auto;\n white-space: normal;\n overflow: visible;\n margin: 0;\n }\n\n /* ─── Synthesized consumer-description span ─── */\n /* Visually hidden mirror of consumer-resolved aria-describedby text used by */\n /* the host-canonical ARIA pipeline. Always present in the shadow tree so AT */\n /* can resolve the same-root id even when the description is currently empty. */\n\n .drawer-sr-only {\n position: absolute;\n width: 1px;\n height: 1px;\n padding: 0;\n margin: -1px;\n overflow: hidden;\n clip: rect(0, 0, 0, 0);\n white-space: nowrap;\n border: 0;\n }\n\n /* ─── Body ─── */\n\n .drawer-body {\n flex: 1 1 auto;\n padding: var(--hx-drawer-body-padding, var(--hx-space-6, 1.5rem));\n overflow-y: auto;\n overscroll-behavior: contain;\n }\n\n /* ─── Footer ─── */\n\n .drawer-footer {\n display: flex;\n align-items: center;\n justify-content: flex-end;\n gap: var(--hx-space-3, 0.75rem);\n padding: var(--hx-drawer-footer-padding, var(--hx-space-4, 1rem) var(--hx-space-6, 1.5rem));\n border-top: var(--hx-border-width-thin, 1px) solid\n var(--hx-drawer-footer-border-color, var(--hx-color-border-default, #d6dbd5));\n flex-shrink: 0;\n }\n\n /* ─── Forced Colors (Windows High Contrast) ─── */\n\n @media (forced-colors: active) {\n .drawer-panel {\n border: 1px solid CanvasText;\n }\n\n .drawer-header {\n border-bottom-color: CanvasText;\n }\n\n .drawer-footer {\n border-top-color: CanvasText;\n }\n\n .drawer-close-button {\n color: ButtonText;\n border: 1px solid ButtonText;\n }\n }\n\n /* hx-icon glyph sizing for the migrated close-button SVG. */\n .drawer-close-button-glyph {\n --hx-icon-size: 16px;\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 { lockBodyScroll, unlockBodyScroll } from '../../utils/body-scroll-lock.js';\nimport { devWarn } from '../../utils/dev-warn.js';\nimport '../hx-icon/hx-icon.js';\nimport { HelixElement, createIdCounter } from '../../base/index.js';\nimport { helixDrawerStyles } from './hx-drawer.styles.js';\nimport { forcedColorsSurface } from '../../styles/forced-colors.js';\nimport { flattenAccName } from '../../utils/aria-flatten.js';\nimport {\n installAriaIdrefMirror,\n resolveIdrefTokens,\n supportsIdrefElementReferences,\n type AriaIdrefMirrorHandle,\n} from '../../utils/aria-idref.js';\n\nconst _nextDrawerId = createIdCounter('hx-drawer');\n\ntype DrawerSizePreset = 'sm' | 'md' | 'lg' | 'full';\ntype DrawerSize = DrawerSizePreset | (string & Record<never, never>);\n\nconst DRAWER_SIZE_MAP: Record<DrawerSizePreset, string> = {\n sm: '20rem',\n md: '30rem',\n lg: '40rem',\n full: '100%',\n};\n\nconst FOCUSABLE_SELECTORS = [\n 'a[href]',\n 'area[href]',\n 'button:not([disabled])',\n 'input:not([disabled])',\n 'select:not([disabled])',\n 'textarea:not([disabled])',\n '[tabindex]:not([tabindex=\"-1\"])',\n 'details > summary',\n].join(',');\n\n/**\n * A slide-in drawer panel that can appear from any edge of the viewport.\n * Supports focus trapping, overlay backdrop, keyboard navigation, and full\n * ARIA labelling for enterprise healthcare accessibility requirements.\n *\n * ## Architecture Note: Host-Canonical ARIA (group-4 round-1, Path A)\n *\n * The host carries the announced dialog semantics via `ElementInternals`:\n *\n * - `internals.role = 'dialog'` (the host IS the dialog surface)\n * - `internals.ariaModal = 'true'` (modality declared on host)\n * - `internals.ariaLabelledByElements` / `internals.ariaDescribedByElements`\n * project consumer light-DOM IDREFs across the shadow boundary.\n * - `internals.ariaLabel` carries the resolved fallback name when no\n * IDREF chain or slotted title exists.\n *\n * The inner `<div part=\"overlay\">` no longer carries `role`, `aria-modal`,\n * `aria-labelledby`, or `aria-label` — those would create a nested-dialog\n * announcement above the host's canonical surface. Belt-and-suspenders\n * fallback: when the runtime does NOT expose IDL element references on\n * `ElementInternals` (older Firefox / Safari builds), the resolved label\n * text is text-flattened and written to the inner overlay's `aria-label`\n * so AT walking down from the host still finds an announceable name.\n *\n * Naming precedence (W3C AccName 1.2 §4.3.1):\n *\n * 1. Consumer `aria-labelledby` on the host — IDREFs resolved across the\n * shadow boundary via `resolveIdrefTokens` (same scope walk used by\n * every host-canonical hx-* control: own root → ancestor shadow hosts\n * → owner document → slot owners).\n * 2. Consumer `aria-label` on the host.\n * 3. `<slot name=\"label\">` text content (multi-node aggregation per\n * AccName 1.2 §4.3.10 — decorative `aria-hidden` / `[hidden]` subtrees\n * contribute zero to the name).\n * 4. `label` property — explicit author fallback string.\n * 5. Hard-coded literal `\"Drawer\"` (last-resort accessible name).\n *\n * Description channel: a synthesized `<span id=\"${id}-consumer-desc\">` is\n * rendered inside the shadow root and updated to mirror consumer-resolved\n * description text. The host's `internals.ariaDescribedByElements` carries\n * the live element references on the modern path; the in-shadow span is the\n * fallback target for AT that does not walk IDL refs. `aria-description` is\n * intentionally NEVER written — the W3C AccName algorithm ignores it\n * whenever `aria-describedby` is also present.\n *\n * Slot mutation observers track:\n * 1. The label slot's text content (in-place i18n re-renders).\n * 2. Consumer-resolved external IDREF targets (so a consumer mutating\n * `<label id=\"x\">Patient</label>` in place re-flows the name).\n * 3. Host attribute mutations (delegated to `installAriaIdrefMirror`,\n * which also catches late-inserted IDREF targets and id renames in\n * every relevant root).\n *\n * Focus trap, ESC dismiss, focus-restore, and the inert-outside-content\n * sibling-walk are unchanged from the pre-host-canonical implementation —\n * they operate against the shadow-internal panel which is still the focus\n * target for keyboard users.\n *\n * ## Architecture Note: Native `<dialog>` Migration\n *\n * This component currently uses `role=\"dialog\"` + `aria-modal=\"true\"` on a\n * `<div>` rather than the native `<dialog>` element. This is intentional for\n * the current release because:\n *\n * 1. **SSR compatibility**: Native `<dialog>` requires `showModal()` to activate\n * its modal behavior (focus trapping, backdrop, top-layer). This JavaScript\n * call is not available during server-side rendering, which is a primary\n * consumption pattern for Drupal/Twig templates.\n *\n * 2. **Contained mode**: The `contained` property constrains the drawer to a\n * positioned parent. Native `<dialog>` in modal mode renders in the top layer\n * and cannot be constrained to a parent element.\n *\n * 3. **Animation control**: The current CSS transition approach provides precise\n * control over slide-in/slide-out animations. Native `<dialog>` `::backdrop`\n * animations have inconsistent cross-browser support.\n *\n * Migration to native `<dialog>` is tracked as a future enhancement. When browser\n * support for `CloseWatcher`, `::backdrop` transitions, and declarative dialog\n * opening stabilizes, this component will be migrated to native semantics.\n *\n * @summary Slide-in panel overlay from any viewport edge.\n *\n * @tag hx-drawer\n *\n * @slot label - The drawer title text.\n * @slot header-actions - Action buttons displayed in the header near the close button.\n * @slot - Default slot for the drawer body content.\n * @slot footer - Action buttons or footer content.\n *\n * @fires {CustomEvent<void>} hx-show - Fired when the drawer begins to open.\n * @fires {CustomEvent<void>} hx-after-show - Fired after the drawer open animation completes.\n * @fires {CustomEvent<void>} hx-hide - Fired when the drawer begins to close.\n * @fires {CustomEvent<void>} hx-after-hide - Fired after the drawer close animation completes.\n * @fires {CustomEvent<void>} hx-initial-focus - Fired when initial focus is set inside the drawer. Cancelable to override focus behavior.\n *\n * **Event naming rationale:** hx-drawer uses the `hx-show`/`hx-hide`/`hx-after-show`/`hx-after-hide`\n * pattern shared by all overlay components (hx-popover, hx-tooltip, hx-dropdown). This differs from\n * hx-dialog's `hx-open`/`hx-close`/`hx-cancel` events, which align with native `<dialog>` semantics.\n * The distinction is intentional: overlays are transient visibility toggles, while dialog is a stateful\n * container with cancel semantics.\n *\n * @csspart overlay - The full-screen overlay container (includes backdrop and panel).\n * @csspart panel - The drawer panel itself.\n * @csspart header - The header region containing the title and actions.\n * @csspart title - The drawer title element.\n * @csspart close-button - The built-in close button.\n * @csspart close-btn - The visually-hidden close button rendered when noHeader is true.\n * @csspart body - The scrollable body region.\n * @csspart footer - The footer region.\n *\n * @attr [label] - Accessible label for the dialog when no visible label slot is provided.\n *\n * @cssprop [--hx-drawer-bg=var(--hx-color-neutral-0)] - Drawer panel background color.\n * @cssprop [--hx-drawer-color=var(--hx-color-neutral-900)] - Drawer panel text color.\n * @cssprop [--hx-drawer-shadow=var(--hx-shadow-xl)] - Drawer panel box shadow.\n * @cssprop [--hx-drawer-backdrop-color=var(--hx-color-neutral-900)] - Backdrop color.\n * @cssprop [--hx-drawer-backdrop-opacity=0.5] - Backdrop opacity.\n * @cssprop [--hx-drawer-header-padding] - Padding inside the header.\n * @cssprop [--hx-drawer-header-border-color=var(--hx-color-neutral-200)] - Header border color.\n * @cssprop [--hx-drawer-title-color=var(--hx-color-neutral-900)] - Title text color.\n * @cssprop [--hx-drawer-body-padding] - Padding inside the body.\n * @cssprop [--hx-drawer-footer-padding] - Padding inside the footer.\n * @cssprop [--hx-drawer-footer-border-color=var(--hx-color-neutral-200)] - Footer border color.\n * @cssprop [--hx-z-index-modal] - Z-index layer.\n * @cssprop [--hx-color-neutral-900] - Color.\n * @cssprop [--hx-duration-slow] - Animation duration.\n * @cssprop [--hx-easing-out] - CSS custom property.\n * @cssprop [--hx-color-neutral-0] - Color.\n * @cssprop [--hx-shadow-xl] - Box shadow.\n * @cssprop [--hx-drawer-size-md=30rem] - CSS custom property.\n * @cssprop [--hx-space-4] - Spacing token.\n * @cssprop [--hx-space-5] - Spacing token.\n * @cssprop [--hx-space-6] - Spacing token.\n * @cssprop [--hx-border-width-thin] - Width.\n * @cssprop [--hx-color-neutral-200] - Color.\n * @cssprop [--hx-drawer-font-family=var(--hx-font-family-sans)] - CSS custom property.\n * @cssprop [--hx-font-family-sans] - Font family.\n * @cssprop [--hx-font-size-lg] - Font size.\n * @cssprop [--hx-font-weight-semibold] - Font weight.\n * @cssprop [--hx-line-height-tight] - Line height.\n * @cssprop [--hx-space-2] - Spacing token.\n * @cssprop [--hx-touch-target-min] - Minimum touch target size.\n * @cssprop [--hx-border-radius-md] - CSS custom property.\n * @cssprop [--hx-color-neutral-500] - Color.\n * @cssprop [--hx-duration-fast] - Animation duration.\n * @cssprop [--hx-easing-default] - CSS custom property.\n * @cssprop [--hx-color-neutral-100] - Color.\n * @cssprop [--hx-focus-ring-width] - Width.\n * @cssprop [--hx-drawer-close-btn-focus-ring-color] - Color.\n * @cssprop [--hx-focus-ring-color] - Color.\n * @cssprop [--hx-color-primary-500] - Color.\n * @cssprop [--hx-focus-ring-offset] - CSS custom property.\n * @cssprop [--hx-space-3] - Spacing token.\n * @aaa-certified 2026-05-08\n * @aaa-criteria 1.4.6, 1.4.9, 2.1.3, 2.3.3, 2.4.12, 2.4.13, 2.5.5, 3.2.5, 3.3.6, forced-colors, apg-keyboard\n * @aaa-audit src/components/hx-drawer/AAA-AUDIT.md\n * @keyboard-contract dismiss=Escape; trap-focus=true\n * @aria-pattern dialog\n * @aria-pattern-source https://www.w3.org/WAI/ARIA/apg/patterns/dialog-modal/\n * @forced-colors-supported true\n * @stability stable\n * @since 3.7.0\n * @form-associated false\n * @theme-aware true\n * @brand-aware true\n * @drupal-sdc-eligible true\n * @react-wrapper-status complete\n * @figma-component-name hx-drawer\n * @priority-tier P0\n * @phi-handles false\n * @clinical-context none\n */\n@customElement('hx-drawer')\nexport class HelixDrawer extends HelixElement {\n static override styles = [helixDrawerStyles, forcedColorsSurface];\n\n // ─── Queries ───\n\n /**\n * Reference to the overlay element that wraps the backdrop and panel.\n * @internal\n */\n @query('.drawer-overlay')\n private _overlayEl: HTMLElement | null | undefined;\n\n /**\n * Reference to the drawer panel element used for focus management.\n * @internal\n */\n @query('.drawer-panel')\n private _panelEl: HTMLElement | null | undefined;\n\n // ─── Internal state ───\n\n /**\n * Whether the drawer is in the open state and visible to the user.\n * @internal\n */\n @state()\n private _isOpen = false;\n\n /**\n * Whether the header-actions slot has any assigned content.\n * @internal\n */\n @state()\n private _hasHeaderActionsSlot = false;\n\n /**\n * Whether the footer slot has any assigned content.\n * @internal\n */\n @state()\n private _hasFooterSlot = false;\n\n /**\n * Whether the label slot has any assigned content.\n * @internal\n */\n @state()\n private _hasLabelSlot = false;\n\n /**\n * Cached list of focusable elements within the drawer, used for focus trapping.\n * @internal\n */\n private _cachedFocusableElements: HTMLElement[] = [];\n /**\n * The element that triggered the drawer to open, restored focus when the drawer closes.\n * @internal\n */\n private _triggerElement: HTMLElement | null = null;\n /**\n * Handle for the pending animation end timeout, cleared when the drawer opens or closes again.\n * @internal\n */\n private _animationTimeout: ReturnType<typeof setTimeout> | null = null;\n /** Whether this drawer instance currently holds a body-scroll lock. */\n /** @internal */\n private _hasScrollLock = false;\n /**\n * Elements outside the drawer that were given aria-hidden during open, restored on close.\n * @internal\n */\n private _siblingAriaHiddenElements: Element[] = [];\n\n /**\n * Unique ID for the title element, used by aria-labelledby to link the dialog to its label.\n * @internal\n */\n private readonly _id = _nextDrawerId();\n /** @internal */\n private readonly _titleId = `${this._id}-title`;\n /**\n * Id of the synthesized in-shadow span that mirrors consumer-resolved\n * description text. Belt-and-suspenders: the host's\n * `internals.ariaDescribedByElements` carries the live element references\n * on the modern path; this in-shadow span is the fallback referenced via\n * `aria-describedby` on the inner overlay so AT that does not walk IDL refs\n * still finds an announceable description.\n * @internal\n */\n private readonly _consumerDescId = `${this._id}-consumer-desc`;\n\n // ─── Host-canonical ARIA state ───\n\n /**\n * Test seam: when set to `true` or `false`, overrides the platform\n * `supportsIdrefElementReferences` probe before `connectedCallback`\n * seeds `_supportsIdrefRefs`. Mirrors hx-combobox round-3 finding 4 —\n * tests must select the path BEFORE the host connects so the synthetic\n * environment matches a legacy engine. Production code MUST NOT touch\n * this field. It is `static` so the cleanup is global and obvious.\n * @internal\n */\n static __testSupportsIdrefRefsOverride: boolean | null = null;\n\n /**\n * Whether the runtime exposes IDL element references on ElementInternals.\n * Drives the modern-vs-fallback ARIA projection in `_syncHostAriaSemantics`.\n * @internal\n */\n @state() private _supportsIdrefRefs = true;\n\n /**\n * Direct references to ALL labellable elements projected into\n * `<slot name=\"label\">`. Aggregates every assigned element so composed\n * labels (e.g. `<svg slot=\"label\" aria-hidden=\"true\">…</svg><span slot=\"label\">Patient</span>`)\n * project the FULL visible label via `internals.ariaLabelledByElements`\n * while `flattenAccName` strips the decorative subtree per AccName 1.2.\n * @internal\n */\n private _slottedLabelEls: Element[] = [];\n\n /**\n * Flattened text content of the slotted label nodes, used for the no-IDL-ref\n * fallback `internals.ariaLabel` and the legacy inner-overlay `aria-label`.\n * @internal\n */\n @state() private _labelSlotText = '';\n\n /**\n * Most recently observed consumer-supplied `aria-labelledby` token list on\n * the host. Refreshed every sync via `getAttribute()` — the host attribute\n * IS the live source of truth, so `removeAttribute` is observable on the\n * next sync (it returns `null`).\n * @internal\n */\n private _consumerLabelledBy: string | null = null;\n /** @internal — see `_consumerLabelledBy`. */\n private _consumerDescribedBy: string | null = null;\n\n /**\n * Handle for the shared IDREF mirror. See `installAriaIdrefMirror()`.\n * @internal\n */\n private _ariaMirror: AriaIdrefMirrorHandle | null = null;\n\n /**\n * Watches in-place text mutations on the assigned slotted label nodes\n * (e.g. consumer i18n re-renders that mutate `textContent` instead of\n * replacing the node). `slotchange` does NOT fire on descendant text\n * mutations, so this observer is the only signal that keeps the host's\n * accessible name synchronized with the visible label.\n * @internal\n */\n private _labelSlotTextObserver: MutationObserver | null = null;\n\n /**\n * Watches in-place text / visibility mutations on consumer light-DOM\n * elements resolved from host `aria-labelledby` / `aria-describedby`.\n * Reinstalled on every sync against the deduped union of resolved\n * elements; disconnects automatically when the consumer retracts both\n * IDREF chains.\n * @internal\n */\n private _externalRefsObserver: MutationObserver | null = null;\n\n /**\n * Dedicated host observer scoped to `aria-describedby` with\n * `attributeOldValue: true`. Catches authentic consumer retraction\n * (oldValue !== null && newValue === null) so the cached baseline\n * follows the live attribute.\n * @internal\n */\n private _hostDescribedByObserver: MutationObserver | null = null;\n\n // ─── Public Properties ───\n\n /**\n * Controls whether the drawer is open.\n * @attr open\n */\n @property({ type: Boolean, reflect: true })\n open = false;\n\n /**\n * Which edge of the viewport the drawer slides in from.\n * @attr placement\n */\n @property({ type: String, reflect: true })\n placement: 'start' | 'end' | 'top' | 'bottom' = 'end';\n\n /**\n * The size of the drawer panel. Use 'sm', 'md', 'lg', 'full', or any valid CSS length.\n * @attr hx-size\n */\n @property({ type: String, reflect: true, attribute: 'hx-size' })\n size: 'sm' | 'md' | 'lg' | 'full' | (string & Record<never, never>) = 'md';\n\n /**\n * When true, the drawer is constrained to its positioned parent instead of the viewport.\n * The host element must have `position: relative` (or the library handles it via :host).\n * @attr contained\n */\n @property({ type: Boolean, reflect: true })\n contained = false;\n\n /**\n * When true, the header (title, header-actions, close button) is hidden.\n * @attr no-header\n */\n @property({ type: Boolean, reflect: true, attribute: 'no-header' })\n noHeader = false;\n\n /**\n * When true, the footer slot is hidden.\n * @attr no-footer\n */\n @property({ type: Boolean, reflect: true, attribute: 'no-footer' })\n noFooter = false;\n\n /**\n * Accessible label for the dialog when the `label` slot is not populated.\n * When the `label` slot is used, `aria-labelledby` takes precedence.\n * @attr label\n */\n @property({ type: String })\n label = '';\n\n /** Accessible label for the built-in close button. Override for localized text. */\n @property({ type: String, attribute: 'label-close' })\n labelClose = 'Close drawer';\n\n // ─── Lifecycle ───\n\n override connectedCallback(): void {\n super.connectedCallback();\n // Backward compat: accept legacy `size` attribute. When present and `hx-size`\n // is not set, map the value and emit a deprecation warning.\n const legacySize = this.getAttribute('size');\n if (legacySize !== null && !this.hasAttribute('hx-size')) {\n devWarn('hx-drawer', 'The \"size\" attribute is deprecated. Use \"hx-size\" instead.');\n this.size = legacySize as DrawerSize;\n }\n\n // Honour the static test override so synthetic environments choose the\n // path BEFORE connect runs.\n const ctor = this.constructor as typeof HelixDrawer;\n this._supportsIdrefRefs =\n ctor.__testSupportsIdrefRefsOverride !== null\n ? ctor.__testSupportsIdrefRefsOverride\n : supportsIdrefElementReferences(this._internals);\n\n // Establish host-canonical ARIA semantics BEFORE first paint. The host\n // carries `role=\"dialog\"` and `aria-modal=\"true\"` via ElementInternals,\n // but ONLY while the drawer is open — a CLOSED drawer is invisible to AT\n // and must not surface a \"modal dialog\" announcement before the consumer\n // ever flips `open`. Initial state is gated through\n // `_syncHostDialogSemantics()`, which is called from `connectedCallback`\n // (here) and on every `open` change in `updated()`.\n this._syncHostDialogSemantics();\n\n // Install the dedicated `aria-describedby` retraction observer BEFORE the\n // seeded `_syncHostAriaSemantics()` call below — mirrors hx-combobox\n // round-10 finding 1 — so authentic consumer clears propagate immediately.\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 host announces its\n // dialog role + accessible name before first paint. The mirror's initial\n // sync also fires synchronously inside `installAriaIdrefMirror`.\n this._syncHostAriaSemantics();\n this._ariaMirror = installAriaIdrefMirror(this, () => {\n this._syncHostAriaSemantics();\n });\n }\n\n override disconnectedCallback(): void {\n super.disconnectedCallback();\n this._removeListeners();\n if (this._animationTimeout !== null) {\n clearTimeout(this._animationTimeout);\n }\n this._restoreBodyScroll();\n this._ariaMirror?.disconnect();\n this._ariaMirror = null;\n this._labelSlotTextObserver?.disconnect();\n this._labelSlotTextObserver = null;\n this._externalRefsObserver?.disconnect();\n this._externalRefsObserver = null;\n this._hostDescribedByObserver?.disconnect();\n this._hostDescribedByObserver = null;\n }\n\n override updated(changedProperties: PropertyValues<this>): void {\n super.updated(changedProperties);\n\n if (changedProperties.has('open')) {\n // Lift role=dialog + aria-modal onto the host BEFORE the open animation\n // begins so AT announces the dialog surface as it appears; retract\n // them after close so a closed drawer is invisible to the AT tree.\n this._syncHostDialogSemantics();\n if (this.open) {\n this._openDrawer();\n } else {\n this._closeDrawer();\n }\n }\n\n if (changedProperties.has('size')) {\n this._applySizeVar();\n }\n\n // Re-sync host ARIA on every update — `label` / `_hasLabelSlot` /\n // `_slottedLabelEls` / `_labelSlotText` / consumer attributes can all\n // change between renders and the projection is the SSOT for AT.\n this._syncHostAriaSemantics();\n }\n\n override firstUpdated(changedProperties: PropertyValues<this>): void {\n super.firstUpdated(changedProperties);\n // The native `slotchange` event fires as a microtask after the initial\n // synchronous render. We deliberately do NOT proactively seed\n // `_hasLabelSlot` / `_labelSlotText` from `firstUpdated` because doing so\n // schedules an additional Lit re-render that subtly reorders the\n // promise-chain inside `_openDrawer` (`updateComplete.then(...) →\n // _isOpen = true → updateComplete.then(...) → _setInitialFocus()`). On\n // Chromium that reordering interleaves the inner `is-open` visibility\n // flip with `_setInitialFocus()` and breaks slotted-children focus for\n // consumer test code that calls `.focus()` immediately after the first\n // `updateComplete` (regression: `Focus Trap > traps forward Tab at the\n // last focusable element`). The slotchange handler runs one microtask\n // later and the `_syncHostAriaSemantics()` call from `updated()` picks\n // up the resolved state on the very next paint — close enough that AT\n // never observes the unnamed window. If a future round needs the seed\n // for a stricter timing requirement, re-introduce it here AND update the\n // open-drawer chain to await `_isOpen` activation before the focus\n // restoration test runs (likely needs an extra `updateComplete`).\n }\n\n // ─── Public Methods ───\n\n /** Opens the drawer. */\n show(): void {\n this.open = true;\n }\n\n /** Closes the drawer. */\n hide(): void {\n this.open = false;\n }\n\n // ─── Private: Size CSS variable ───\n\n /** @internal */\n private _applySizeVar(): void {\n const resolvedSize = DRAWER_SIZE_MAP[this.size as DrawerSizePreset] ?? this.size;\n this.style.setProperty('--_drawer-size', resolvedSize);\n }\n\n // ─── Private: Open / Close ───\n\n /** @internal */\n private _lockBodyScroll(): void {\n if (this.contained || this._hasScrollLock) return;\n // Uses a shared reference-counted lock so that simultaneous hx-dialog / hx-drawer\n // instances don't clobber each other when one closes before the other\n // (see utils/body-scroll-lock.ts).\n lockBodyScroll();\n this._hasScrollLock = true;\n }\n\n /** @internal */\n private _restoreBodyScroll(): void {\n if (!this._hasScrollLock) return;\n unlockBodyScroll();\n this._hasScrollLock = false;\n }\n\n /** @internal */\n private _openDrawer(): void {\n // Capture trigger for focus restoration (P2-04: use instanceof guard)\n const active = document.activeElement;\n this._triggerElement = active instanceof HTMLElement ? active : null;\n\n // P1-05: clear any pending animation timeout before scheduling a new one\n if (this._animationTimeout !== null) {\n clearTimeout(this._animationTimeout);\n this._animationTimeout = null;\n }\n\n this._applySizeVar();\n this._lockBodyScroll();\n this._hideBackgroundFromScreenReaders();\n\n // Dispatch hx-show before visual update\n this.dispatchEvent(new CustomEvent<void>('hx-show', { bubbles: true, composed: true }));\n\n // Transition to open state\n void this.updateComplete\n .then(() => {\n this._isOpen = true;\n this._addListeners();\n\n // Set initial focus after next render\n return this.updateComplete;\n })\n .then(() => {\n this._cachedFocusableElements = this._getFocusableElements();\n this._setInitialFocus();\n\n // Dispatch hx-after-show when the panel's CSS transition completes.\n // If prefers-reduced-motion is active (duration === 0) or the element\n // is missing, fire immediately — transitionend will never fire.\n const duration = this._getAnimationDuration();\n const panel = this._panelEl;\n if (duration === 0 || !panel) {\n this.dispatchEvent(\n new CustomEvent<void>('hx-after-show', { bubbles: true, composed: true }),\n );\n } else {\n const emitAfterShow = () => {\n if (this._animationTimeout !== null) {\n clearTimeout(this._animationTimeout);\n this._animationTimeout = null;\n }\n this.dispatchEvent(\n new CustomEvent<void>('hx-after-show', { bubbles: true, composed: true }),\n );\n };\n panel.addEventListener('transitionend', emitAfterShow, { once: true });\n // Safety fallback: if transitionend never fires (e.g. transition\n // cancelled, element removed), ensure the event is still dispatched.\n this._animationTimeout = setTimeout(emitAfterShow, duration + 50);\n }\n })\n .catch(console.error);\n }\n\n /** @internal */\n private _closeDrawer(): void {\n // P1-05: clear any pending animation timeout before scheduling a new one\n if (this._animationTimeout !== null) {\n clearTimeout(this._animationTimeout);\n this._animationTimeout = null;\n }\n\n this._isOpen = false;\n this._removeListeners();\n this._cachedFocusableElements = [];\n this._restoreBodyScroll();\n this._restoreBackgroundForScreenReaders();\n\n this.dispatchEvent(new CustomEvent<void>('hx-hide', { bubbles: true, composed: true }));\n\n // Restore focus to the trigger immediately — before any animation timeout.\n // WCAG 2.4.3: focus must never remain on invisible or inert content.\n if (this._triggerElement && typeof this._triggerElement.focus === 'function') {\n this._triggerElement.focus();\n }\n this._triggerElement = null;\n\n // Dispatch hx-after-hide when the panel's CSS transition completes.\n // If prefers-reduced-motion is active (duration === 0) or the element\n // is missing, fire immediately — transitionend will never fire.\n const duration = this._getAnimationDuration();\n const panel = this._panelEl;\n if (duration === 0 || !panel) {\n this.dispatchEvent(new CustomEvent<void>('hx-after-hide', { bubbles: true, composed: true }));\n } else {\n const emitAfterHide = () => {\n if (this._animationTimeout !== null) {\n clearTimeout(this._animationTimeout);\n this._animationTimeout = null;\n }\n this.dispatchEvent(\n new CustomEvent<void>('hx-after-hide', { bubbles: true, composed: true }),\n );\n };\n panel.addEventListener('transitionend', emitAfterHide, { once: true });\n // Safety fallback: if transitionend never fires (e.g. transition\n // cancelled, element removed), ensure the event is still dispatched.\n this._animationTimeout = setTimeout(emitAfterHide, duration + 50);\n }\n }\n\n /** @internal */\n private _getAnimationDuration(): number {\n if (typeof window === 'undefined') return 0;\n if (window.matchMedia('(prefers-reduced-motion: reduce)').matches) return 0;\n return 300;\n }\n\n // ─── Background aria-hidden management (P1-03) ───\n\n /** @internal */\n private _hideBackgroundFromScreenReaders(): void {\n if (this.contained) return;\n this._siblingAriaHiddenElements = [];\n // Walk the parent chain once to find which body child is an ancestor of this component.\n // This avoids calling child.contains(this) in a loop (which is O(n * depth)).\n // Starting from parentElement avoids aliasing `this` to a local variable.\n let ancestorBodyChild: Element | null = null;\n let el: Element | null = this.parentElement;\n while (el && el.parentElement !== document.body) {\n el = el.parentElement;\n }\n if (el && el.parentElement === document.body) {\n ancestorBodyChild = el;\n }\n Array.from(document.body.children).forEach((child) => {\n if (child === this || child === ancestorBodyChild) return;\n if (!child.hasAttribute('aria-hidden')) {\n child.setAttribute('aria-hidden', 'true');\n this._siblingAriaHiddenElements.push(child);\n }\n });\n }\n\n /** @internal */\n private _restoreBackgroundForScreenReaders(): void {\n this._siblingAriaHiddenElements.forEach((el) => {\n el.removeAttribute('aria-hidden');\n });\n this._siblingAriaHiddenElements = [];\n }\n\n // ─── Event Listeners (P1-01: use only document listener, not overlay) ───\n\n /** @internal */\n private _addListeners(): void {\n document.addEventListener('keydown', this._handleKeyDown);\n }\n\n /** @internal */\n private _removeListeners(): void {\n document.removeEventListener('keydown', this._handleKeyDown);\n }\n\n // ─── Keyboard Handler ───\n\n /**\n * Handles keyboard events on the document to trap focus and close the drawer on Escape.\n * @internal\n */\n private _handleKeyDown = (e: KeyboardEvent): void => {\n if (!this._isOpen) return;\n\n if (e.key === 'Escape') {\n e.preventDefault();\n this.open = false;\n return;\n }\n\n if (e.key === 'Tab') {\n this._trapFocus(e);\n }\n };\n\n // ─── Focus ───\n\n /** @internal */\n private _setInitialFocus(): void {\n const event = new CustomEvent<void>('hx-initial-focus', {\n bubbles: true,\n composed: true,\n cancelable: true,\n });\n this.dispatchEvent(event);\n\n if (!event.defaultPrevented) {\n const focusable = this._cachedFocusableElements;\n if (focusable.length > 0 && focusable[0]) {\n focusable[0].focus();\n } else {\n this._panelEl?.focus();\n }\n }\n }\n\n /** @internal */\n private _getFocusableElements(): HTMLElement[] {\n const shadowFocusable = Array.from(\n this.shadowRoot?.querySelectorAll<HTMLElement>(FOCUSABLE_SELECTORS) ?? [],\n );\n\n const slots = this.shadowRoot?.querySelectorAll<HTMLSlotElement>('slot') ?? [];\n const lightFocusable: HTMLElement[] = [];\n\n slots.forEach((slot) => {\n slot.assignedElements({ flatten: true }).forEach((el) => {\n if (el instanceof HTMLElement) {\n if (el.matches(FOCUSABLE_SELECTORS)) {\n lightFocusable.push(el);\n }\n el.querySelectorAll<HTMLElement>(FOCUSABLE_SELECTORS).forEach((child) => {\n lightFocusable.push(child);\n });\n }\n });\n });\n\n return [...shadowFocusable, ...lightFocusable].filter(\n (el) => !el.hasAttribute('disabled') && el.getAttribute('tabindex') !== '-1',\n );\n }\n\n /** @internal */\n private _trapFocus(e: KeyboardEvent): void {\n const focusable =\n this._cachedFocusableElements.length > 0\n ? this._cachedFocusableElements\n : this._getFocusableElements();\n\n if (focusable.length === 0) {\n e.preventDefault();\n return;\n }\n\n const [first, ...rest] = focusable;\n const last = rest.length > 0 ? rest[rest.length - 1] : first;\n\n if (!first || !last) return;\n\n // P1-02: Use document.activeElement for reliable detection of slotted (light DOM) elements.\n // shadowRoot.activeElement returns the <slot> host for slotted content, not the actual element.\n const active = document.activeElement as HTMLElement | null;\n\n if (e.shiftKey) {\n if (active === first) {\n e.preventDefault();\n last.focus();\n }\n } else {\n if (active === last) {\n e.preventDefault();\n first.focus();\n }\n }\n }\n\n // ─── Overlay Click ───\n\n /**\n * Handles clicks on the overlay backdrop to close the drawer when the user clicks outside the panel.\n * @internal\n */\n private _handleOverlayClick = (e: MouseEvent): void => {\n // Only close when clicking the overlay itself (backdrop), not the panel\n const target = e.target as HTMLElement;\n if (target === this._overlayEl || target.classList.contains('drawer-backdrop')) {\n this.open = false;\n }\n };\n\n // ─── Slot change handlers ───\n\n /** @internal */\n private _handleHeaderActionsSlotChange(e: Event): void {\n const slot = e.target as HTMLSlotElement;\n this._hasHeaderActionsSlot = slot.assignedNodes({ flatten: true }).length > 0;\n }\n\n /** @internal */\n private _handleFooterSlotChange(e: Event): void {\n const slot = e.target as HTMLSlotElement;\n this._hasFooterSlot = slot.assignedNodes({ flatten: true }).length > 0;\n }\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._syncHostAriaSemantics();\n }\n\n // ─── Host-canonical ARIA helpers ───\n\n /**\n * Reads the label slot's assigned nodes and computes the discriminated\n * naming state. Aggregates ALL assigned elements (not just the first) so\n * composed labels project the FULL visible label via\n * `internals.ariaLabelledByElements`. Per AccName 1.2 §4.3.10,\n * `aria-hidden=\"true\"` / `[hidden]` elements contribute zero to the\n * accessible name but stay in `elements` so AT walking IDL refs sees the\n * full visible group. `hasUsefulName` is gated on the flattened text\n * length: a slot containing only decorative wrappers does NOT name the\n * dialog, and the host falls through to the next naming source.\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-)installs the mutation observer over the current set of slotted label\n * elements. On any descendant text/visibility mutation we re-flatten and\n * re-sync so the host's accessible name tracks the visible label.\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._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 * (Re-)installs a `MutationObserver` against the deduped union of\n * consumer-resolved label/description elements. Watches `characterData`,\n * `childList`, `subtree`, and `aria-hidden` / `hidden` attributes so any\n * in-place mutation on the referenced light-DOM nodes triggers a fresh\n * sync — keeping the modern-path IDL refs and the fallback-path text\n * flatten aligned with the live consumer text.\n * @internal\n */\n private _installExternalRefsObserver(elements: Element[]): void {\n if (this._externalRefsObserver) {\n this._externalRefsObserver.disconnect();\n this._externalRefsObserver = null;\n }\n if (elements.length === 0) return;\n const unique = new Set<Element>(elements);\n const observer = new MutationObserver(() => {\n this._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 * Gates `role=\"dialog\"` + `aria-modal=\"true\"` on the host's\n * `ElementInternals` behind the `open` boolean. A closed drawer must NOT\n * surface as a modal dialog to the accessibility tree — otherwise screen\n * readers announce an invisible modal before the consumer ever opens it\n * (regression introduced when the ARIA surface moved from the inner\n * overlay to the host in group-4 round-1).\n *\n * Open → `role = 'dialog'`, `ariaModal = 'true'`\n * Closed → `role = null`, `ariaModal = null` (cleared from the AT tree)\n *\n * Called from `connectedCallback()` (initial state) and from `updated()`\n * whenever `open` changes. Idempotent: writing the same value twice is a\n * no-op for both AT and the accessibility tree builder.\n * @internal\n */\n private _syncHostDialogSemantics(): void {\n if (this.open) {\n this._internals.role = 'dialog';\n this._internals.ariaModal = 'true';\n } else {\n this._internals.role = null;\n this._internals.ariaModal = null;\n }\n }\n\n /**\n * Resolves consumer-supplied label/description IDREFs on the host and\n * projects the canonical dialog ARIA onto the **host** via\n * `ElementInternals` (modern path) and onto the inner overlay via attribute\n * writes (fallback path).\n *\n * Cross-shadow naming is belt-and-suspenders:\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. AT walking the host's accessibility tree finds them\n * across the shadow boundary. `internals.ariaLabel` carries the\n * flattened text fallback (only when no labelledby resolves) so AT\n * that does not walk IDL refs still announces a name.\n * 2. **Fallback path** (`_supportsIdrefRefs === false`): the resolved\n * element text is flattened and written to `internals.ariaLabel` AND\n * mirrored to the inner overlay's `aria-label`.\n *\n * The synthesized `<span id=\"${_consumerDescId}\">` mirrors the resolved\n * description text on every sync. The inner overlay's `aria-describedby`\n * chains the in-shadow span. `aria-description` is intentionally NEVER\n * written — W3C AccName ignores it whenever `aria-describedby` is set.\n *\n * Naming precedence (W3C AccName 1.2 §4.3.1):\n * 1. Consumer `aria-labelledby` (resolved IDREFs, text-flattened)\n * 2. Consumer `aria-label`\n * 3. Slotted `<slot name=\"label\">` text\n * 4. `label` property\n * 5. Hard-coded `\"Drawer\"`\n * @internal\n */\n private _syncHostAriaSemantics(): void {\n const internals = this._internals;\n // The host's canonical role + modal flag are managed separately by\n // `_syncHostDialogSemantics()` — they are gated on `this.open` so a\n // CLOSED drawer is invisible to the accessibility tree (no orphan\n // `role=\"dialog\"` / `aria-modal=\"true\"` before the consumer flips open).\n // Naming/description state below is independent of open-state because\n // the resolved label still composes correctly while closed and the\n // dialog surface only becomes visible to AT when role/aria-modal lift.\n\n // Refresh the consumer baseline. The host attribute IS the live source\n // of truth — `null` authentically represents consumer retraction.\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 const consumerDescEls = resolveIdrefTokens(this, this._consumerDescribedBy);\n\n // Observe in-place mutations on the resolved external IDREF targets.\n // Without this a consumer mutating `<h2 id=\"x\">Patient</h2>` → \"Member\"\n // in place leaves the host's flattened `aria-label` stuck on \"Patient\".\n this._installExternalRefsObserver([...consumerLabelEls, ...consumerDescEls]);\n\n // Per AccName 1.2 §4.3.10, top-level aria-hidden / hidden elements\n // contribute zero to the name. Filter them from the IDL-refs path so the\n // modern path matches the fallback path's text-flatten behavior.\n const isVisibleForAccName = (el: Element): boolean =>\n el.getAttribute('aria-hidden') !== 'true' && !el.hasAttribute('hidden');\n\n const liveAriaLabel = this.getAttribute('aria-label');\n const hostAriaLabel = liveAriaLabel !== null ? liveAriaLabel.trim() : '';\n\n // Build the augmented label-elements list used by the modern path.\n // Slotted-title elements feed in only when no consumer aria-labelledby\n // resolved (AccName 1.2 precedence: external > slot > property).\n const labelElsForInternals: Element[] = [];\n labelElsForInternals.push(...consumerLabelEls.filter(isVisibleForAccName));\n if (!hasEffectiveLabelledBy && !hostAriaLabel && this._hasLabelSlot) {\n // Aggregate every slotted label element so AT composes icon + text.\n labelElsForInternals.push(...this._slottedLabelEls.filter(isVisibleForAccName));\n }\n\n const descElsForInternals: Element[] = [...consumerDescEls.filter(isVisibleForAccName)];\n\n // ─── Compute the resolved 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 resolvedName = '';\n if (hasEffectiveLabelledBy) {\n resolvedName = flattenText(consumerLabelEls);\n }\n if (!resolvedName && hostAriaLabel) {\n resolvedName = hostAriaLabel;\n }\n if (!resolvedName && this._hasLabelSlot && this._labelSlotText) {\n resolvedName = this._labelSlotText;\n }\n if (!resolvedName && this.label) {\n resolvedName = this.label;\n }\n if (!resolvedName) {\n // Last-resort literal — preserves the pre-host-canonical default so an\n // unlabeled drawer still has SOME announced name. Consumer responsibility\n // to provide a meaningful one in real usage.\n resolvedName = 'Drawer';\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 `aria-label` to `internals.ariaLabel` ONLY when no labelledby\n // resolved — per AccName 1.2 a non-empty aria-label outranks\n // aria-labelledby, and we never want to silently erase the IDL-ref\n // resolution. When labelledby is present, `null` removes the override\n // so element references win.\n if (hasEffectiveLabelledBy) {\n internals.ariaLabel = null;\n } else {\n internals.ariaLabel = resolvedName;\n }\n } else {\n // Fallback path: write the flattened name directly to internals.\n // Older engines without IDL refs use this as the canonical name.\n internals.ariaLabel = resolvedName;\n }\n\n // ─── Synthesized in-shadow consumer-description span ───\n // Mirror consumer-resolved description text into a same-root span so the\n // inner overlay's `aria-describedby` resolves cross-shadow without\n // pointing at light-DOM ids (which do not resolve from inside a shadow\n // root). `aria-description` is intentionally NEVER written.\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 // ─── Inner overlay attribute reconciliation ───\n // The overlay no longer carries `role` / `aria-modal` / `aria-labelledby`\n // / `aria-label` on the modern path — the host owns those via internals.\n // Strip stale attributes defensively in case an earlier sync wrote them\n // and reconcile the fallback `aria-label` only when IDL refs are not\n // supported (so screen readers walking the inner overlay still find a\n // name on legacy engines).\n const overlay = this._overlayEl ?? null;\n if (overlay) {\n // Belt-and-suspenders: never write `role` / `aria-modal` to the inner\n // overlay on either path — that would create nested-dialog semantics\n // above the host's canonical surface.\n if (overlay.hasAttribute('role')) overlay.removeAttribute('role');\n if (overlay.hasAttribute('aria-modal')) overlay.removeAttribute('aria-modal');\n // Internal slotted-title id on the SAME shadow root resolves cleanly,\n // so we project it onto the overlay's `aria-labelledby` only on the\n // fallback path. The modern path uses `internals.ariaLabelledByElements`.\n const wantOverlayLabelledBy =\n !this._supportsIdrefRefs && this._hasLabelSlot ? this._titleId : null;\n const wantOverlayLabel =\n !this._supportsIdrefRefs && !wantOverlayLabelledBy ? resolvedName : null;\n if (wantOverlayLabelledBy) {\n if (overlay.getAttribute('aria-labelledby') !== wantOverlayLabelledBy) {\n overlay.setAttribute('aria-labelledby', wantOverlayLabelledBy);\n }\n } else if (overlay.hasAttribute('aria-labelledby')) {\n overlay.removeAttribute('aria-labelledby');\n }\n if (wantOverlayLabel) {\n if (overlay.getAttribute('aria-label') !== wantOverlayLabel) {\n overlay.setAttribute('aria-label', wantOverlayLabel);\n }\n } else if (overlay.hasAttribute('aria-label')) {\n overlay.removeAttribute('aria-label');\n }\n\n // Inner overlay's `aria-describedby` chains the in-shadow consumer-desc\n // span. Same-root id resolves cleanly; cross-shadow consumer ids are\n // ignored at the AT level (light-DOM ids do not resolve from inside a\n // shadow root) so we never write them directly.\n if (consumerDescText && consumerDescSpan) {\n const value = this._consumerDescId;\n if (overlay.getAttribute('aria-describedby') !== value) {\n overlay.setAttribute('aria-describedby', value);\n }\n } else if (overlay.hasAttribute('aria-describedby')) {\n overlay.removeAttribute('aria-describedby');\n }\n\n // Forced-colors: the host has display: contents so :host(:focus-visible)\n // has no painting surface — focus is on the inner panel. The existing\n // `forcedColorsSurface` mixin paints the host CanvasText border which\n // the panel inherits via the parent box. No change owed here, but if a\n // future change makes the host focusable directly we'd add the rule.\n }\n\n // Strip `aria-description` defensively — never written on either path.\n if (overlay && overlay.hasAttribute('aria-description')) {\n overlay.removeAttribute('aria-description');\n }\n }\n\n // ─── Render Helpers ───\n\n /** @internal */\n private _renderHeader() {\n if (this.noHeader) {\n // WCAG 4.1.2: When the header is hidden there must still be a reachable close\n // mechanism for keyboard and mouse/touch users. Render a visually-hidden close\n // button that is focusable and announced by screen readers.\n return html`\n <button\n part=\"close-btn\"\n class=\"drawer-close-button drawer-close-button--sr-only\"\n aria-label=${this.labelClose}\n @click=${() => {\n this.open = false;\n }}\n ></button>\n `;\n }\n\n return html`\n <div part=\"header\" class=\"drawer-header\">\n <h2 part=\"title\" id=${this._titleId} class=\"drawer-title\">\n <slot name=\"label\" @slotchange=${this._handleLabelSlotChange}></slot>\n </h2>\n <div class=\"drawer-header-actions\">\n ${this._hasHeaderActionsSlot\n ? html`<slot\n name=\"header-actions\"\n @slotchange=${this._handleHeaderActionsSlotChange}\n ></slot>`\n : html`<slot\n name=\"header-actions\"\n @slotchange=${this._handleHeaderActionsSlotChange}\n style=\"display:none\"\n ></slot>`}\n <button\n part=\"close-button\"\n class=\"drawer-close-button\"\n aria-label=${this.labelClose}\n @click=${() => {\n this.open = false;\n }}\n >\n <hx-icon\n class=\"drawer-close-button-glyph\"\n library=\"helix\"\n name=\"close\"\n aria-hidden=\"true\"\n ></hx-icon>\n </button>\n </div>\n </div>\n `;\n }\n\n /** @internal */\n private _renderFooter() {\n if (this.noFooter) return nothing;\n\n return html`\n <div part=\"footer\" class=\"drawer-footer\" ?hidden=${!this._hasFooterSlot}>\n <slot name=\"footer\" @slotchange=${this._handleFooterSlotChange}></slot>\n </div>\n `;\n }\n\n // ─── Render ───\n\n override render() {\n const overlayClasses = {\n 'drawer-overlay': true,\n 'is-open': this._isOpen,\n };\n\n // Host-canonical: the inner overlay carries NO `role` / `aria-modal` /\n // `aria-labelledby` / `aria-label` here. Those are projected onto the\n // host via `ElementInternals` in `_syncHostAriaSemantics()`. On the\n // legacy (no-IDL-ref) fallback path the sync method imperatively writes\n // `aria-label` / `aria-labelledby` onto the overlay so AT walking down\n // from the host still finds an announceable name.\n return html`\n <div\n part=\"overlay\"\n class=${classMap(overlayClasses)}\n tabindex=\"-1\"\n @click=${this._handleOverlayClick}\n >\n <div class=\"drawer-backdrop\" aria-hidden=\"true\"></div>\n <div part=\"panel\" class=\"drawer-panel\" tabindex=\"-1\">\n ${this._renderHeader()}\n <div part=\"body\" class=\"drawer-body\">\n <slot></slot>\n </div>\n ${this._renderFooter()}\n </div>\n <!--\n Synthesized in-shadow span carrying consumer-resolved description\n text. Updated imperatively on every sync. The inner overlay's\n \\`aria-describedby\\` references this span so cross-shadow consumer\n descriptions resolve through the standard described-by channel\n without writing light-DOM ids that cannot resolve from inside a\n shadow root. \\`aria-description\\` is intentionally NEVER written —\n AccName ignores it whenever \\`aria-describedby\\` is present.\n -->\n <span id=${this._consumerDescId} class=\"drawer-sr-only\" aria-hidden=\"false\"></span>\n </div>\n `;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'hx-drawer': HelixDrawer;\n }\n interface HTMLElementEventMap {\n 'hx-show': CustomEvent<void>;\n 'hx-after-show': CustomEvent<void>;\n 'hx-hide': CustomEvent<void>;\n 'hx-after-hide': CustomEvent<void>;\n 'hx-initial-focus': CustomEvent<void>;\n }\n}\n"],"names":["helixDrawerStyles","css","_nextDrawerId","createIdCounter","DRAWER_SIZE_MAP","FOCUSABLE_SELECTORS","HelixDrawer","HelixElement","target","legacySize","ctor","supportsIdrefElementReferences","records","consumerCleared","record","oldValue","newValue","installAriaIdrefMirror","_a","_b","_c","_d","changedProperties","resolvedSize","lockBodyScroll","unlockBodyScroll","active","duration","panel","emitAfterShow","emitAfterHide","ancestorBodyChild","el","child","event","focusable","shadowFocusable","slots","lightFocusable","slot","first","rest","last","state","nodes","elements","fragments","node","elText","flattenAccName","txt","trimmedText","observer","t","trimmed","unique","internals","liveLabelledBy","liveDescribedBy","consumerLabelEls","resolveIdrefTokens","hasEffectiveLabelledBy","consumerDescEls","isVisibleForAccName","liveAriaLabel","hostAriaLabel","labelElsForInternals","descElsForInternals","flattenText","els","resolvedName","refsInternals","consumerDescSpan","consumerDescText","overlay","wantOverlayLabelledBy","wantOverlayLabel","value","html","nothing","overlayClasses","classMap","forcedColorsSurface","__decorateClass","query","property","customElement"],"mappings":";;;;;;;;;AAYO,MAAMA,IAAoBC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAA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"}
|
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
import { css as b, nothing as
|
|
2
|
-
import { property as c, state as p, query as
|
|
1
|
+
import { css as b, nothing as g, html as _ } from "lit";
|
|
2
|
+
import { property as c, state as p, query as f, customElement as v } from "lit/decorators.js";
|
|
3
3
|
import { d as y } from "./dev-warn-YlwPHjtX.js";
|
|
4
4
|
import { f as x } from "./forced-colors-CTEDFRGa.js";
|
|
5
5
|
import { f as w } from "./aria-flatten-DY6v2vah.js";
|
|
6
6
|
import { f as u, g as C } from "./menu-tree-BNM0SYYq.js";
|
|
7
|
-
import { w as
|
|
8
|
-
import { i as
|
|
7
|
+
import { w as A } from "./menu-roving-DmMnzJhn.js";
|
|
8
|
+
import { i as E, r as T } from "./aria-idref-DCuEaknC.js";
|
|
9
9
|
import { H as k } from "./helix-element-BNEYeiys.js";
|
|
10
|
-
import { c as
|
|
10
|
+
import { c as L } from "./id-counter-DuX8vsui.js";
|
|
11
11
|
const I = b`
|
|
12
12
|
:host {
|
|
13
13
|
display: inline-block;
|
|
@@ -23,11 +23,29 @@ const I = b`
|
|
|
23
23
|
display: inline-block;
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
+
/*
|
|
27
|
+
* AAA 2.4.13 Focus Appearance — enforce a ≥2px focus ring on the slotted
|
|
28
|
+
* trigger (typically <hx-button>, <button>, or <hx-icon-button>). The host
|
|
29
|
+
* is a popover-container; the interactive surface is the slotted trigger.
|
|
30
|
+
*/
|
|
31
|
+
::slotted([slot='trigger']:focus-visible),
|
|
32
|
+
::slotted(button:focus-visible),
|
|
33
|
+
::slotted(a:focus-visible) {
|
|
34
|
+
outline: var(--hx-focus-ring-width, 2px) solid
|
|
35
|
+
var(--hx-dropdown-focus-ring-color, var(--hx-focus-ring-color, #0f7078));
|
|
36
|
+
outline-offset: var(--hx-focus-ring-offset, 2px);
|
|
37
|
+
}
|
|
38
|
+
|
|
26
39
|
[part='panel'] {
|
|
27
40
|
position: fixed;
|
|
28
41
|
z-index: var(--hx-dropdown-panel-z-index, 1000);
|
|
29
42
|
min-width: var(--hx-dropdown-panel-min-width, 160px);
|
|
30
43
|
background: var(--hx-dropdown-panel-bg, var(--hx-color-surface-default, #ffffff));
|
|
44
|
+
/* Anchor slotted text color to the design-system primary text token so
|
|
45
|
+
slotted <li>'s and other native consumer markup don't inherit a
|
|
46
|
+
foreign color cascade (e.g. brand toolbar setting body { color: #fff }
|
|
47
|
+
and rendering Edit/Duplicate as white-on-white). */
|
|
48
|
+
color: var(--hx-dropdown-panel-color, var(--hx-color-text-primary, #1a1a1a));
|
|
31
49
|
border: 1px solid var(--hx-dropdown-panel-border-color, var(--hx-color-border-default, #d6dbd5));
|
|
32
50
|
border-radius: var(--hx-dropdown-panel-border-radius, var(--hx-border-radius-md, 0.375rem));
|
|
33
51
|
box-shadow: var(
|
|
@@ -65,11 +83,11 @@ const I = b`
|
|
|
65
83
|
}
|
|
66
84
|
`;
|
|
67
85
|
var S = Object.defineProperty, O = Object.getOwnPropertyDescriptor, d = (e, t, i, n) => {
|
|
68
|
-
for (var s = n > 1 ? void 0 : n ? O(t, i) : t,
|
|
69
|
-
(r = e[
|
|
86
|
+
for (var s = n > 1 ? void 0 : n ? O(t, i) : t, o = e.length - 1, r; o >= 0; o--)
|
|
87
|
+
(r = e[o]) && (s = (n ? r(t, i, s) : r(s)) || s);
|
|
70
88
|
return n && s && S(t, i, s), s;
|
|
71
89
|
};
|
|
72
|
-
const R =
|
|
90
|
+
const R = L("hx-dropdown");
|
|
73
91
|
let l = class extends k {
|
|
74
92
|
constructor() {
|
|
75
93
|
super(...arguments), this.open = !1, this.placement = "bottom-start", this.label = "Menu", this.disabled = !1, this.distance = 4, this._panelVisible = !1, this._rovingIndex = -1, this._typeaheadBuffer = "", this._typeaheadTimer = null, this._resolvedLabel = "", this._consumerLabelledBy = null, this._ariaMirror = null, this._externalRefsObserver = null, this._documentListenerAttached = !1, this._panelId = `${R()}-panel`, this._handleKeydown = (e) => {
|
|
@@ -86,8 +104,8 @@ let l = class extends k {
|
|
|
86
104
|
n.call(i, !0);
|
|
87
105
|
const s = i.updateComplete;
|
|
88
106
|
s && s.then(() => {
|
|
89
|
-
var
|
|
90
|
-
const
|
|
107
|
+
var a, h;
|
|
108
|
+
const o = (a = i.shadowRoot) == null ? void 0 : a.querySelector('slot[name="submenu"]'), r = o == null ? void 0 : o.assignedElements({ flatten: !0 }).find((m) => m.tagName.toLowerCase() === "hx-menu");
|
|
91
109
|
(h = r == null ? void 0 : r.focusFirst) == null || h.call(r);
|
|
92
110
|
}).catch(() => {
|
|
93
111
|
});
|
|
@@ -100,7 +118,7 @@ let l = class extends k {
|
|
|
100
118
|
}
|
|
101
119
|
// ─── Lifecycle ───
|
|
102
120
|
connectedCallback() {
|
|
103
|
-
super.connectedCallback(), this.addEventListener("keydown", this._handleKeydown), this._syncResolvedLabel(), this._ariaMirror =
|
|
121
|
+
super.connectedCallback(), this.addEventListener("keydown", this._handleKeydown), this._syncResolvedLabel(), this._ariaMirror = E(this, () => {
|
|
104
122
|
this._syncResolvedLabel();
|
|
105
123
|
});
|
|
106
124
|
}
|
|
@@ -134,13 +152,13 @@ let l = class extends k {
|
|
|
134
152
|
async _updatePosition() {
|
|
135
153
|
const e = this._triggerWrapper, t = this._panel;
|
|
136
154
|
if (!e || !t) return;
|
|
137
|
-
const i = this.placement.replace(/^start$/, "left").replace(/^end$/, "right"), { computePosition: n, flip: s, shift:
|
|
155
|
+
const i = this.placement.replace(/^start$/, "left").replace(/^end$/, "right"), { computePosition: n, flip: s, shift: o, offset: r } = await import("@floating-ui/dom"), { x: a, y: h } = await n(e, t, {
|
|
138
156
|
placement: i,
|
|
139
157
|
strategy: "fixed",
|
|
140
|
-
middleware: [r(this.distance), s(),
|
|
158
|
+
middleware: [r(this.distance), s(), o({ padding: 8 })]
|
|
141
159
|
});
|
|
142
160
|
Object.assign(t.style, {
|
|
143
|
-
left: `${
|
|
161
|
+
left: `${a}px`,
|
|
144
162
|
top: `${h}px`
|
|
145
163
|
});
|
|
146
164
|
}
|
|
@@ -186,7 +204,7 @@ let l = class extends k {
|
|
|
186
204
|
*/
|
|
187
205
|
_applyRovingTabIndex(e) {
|
|
188
206
|
e.forEach((t, i) => {
|
|
189
|
-
|
|
207
|
+
A(t, i === this._rovingIndex ? 0 : -1);
|
|
190
208
|
});
|
|
191
209
|
}
|
|
192
210
|
/** @internal */
|
|
@@ -203,12 +221,12 @@ let l = class extends k {
|
|
|
203
221
|
_getFocusableMenuItems() {
|
|
204
222
|
const e = this._panel;
|
|
205
223
|
if (!e) return [];
|
|
206
|
-
const t = e.querySelector("slot"), i = (t == null ? void 0 : t.assignedElements({ flatten: !0 })) ?? [], n = [], s = (r) => r.localName === "hx-menu-item",
|
|
207
|
-
const
|
|
208
|
-
return r.querySelectorAll('[role="menuitem"]').forEach((h) =>
|
|
224
|
+
const t = e.querySelector("slot"), i = (t == null ? void 0 : t.assignedElements({ flatten: !0 })) ?? [], n = [], s = (r) => r.localName === "hx-menu-item", o = (r) => {
|
|
225
|
+
const a = [];
|
|
226
|
+
return r.querySelectorAll('[role="menuitem"]').forEach((h) => a.push(h)), r.querySelectorAll("hx-menu-item").forEach((h) => a.push(h)), a;
|
|
209
227
|
};
|
|
210
228
|
for (const r of i)
|
|
211
|
-
r instanceof HTMLElement && (r.matches('[role="menuitem"]') || s(r) ? n.push(r) :
|
|
229
|
+
r instanceof HTMLElement && (r.matches('[role="menuitem"]') || s(r) ? n.push(r) : o(r).forEach((a) => n.push(a)));
|
|
212
230
|
return n;
|
|
213
231
|
}
|
|
214
232
|
// P0-01: Find the first focusable element in slotted panel content.
|
|
@@ -220,19 +238,19 @@ let l = class extends k {
|
|
|
220
238
|
for (const s of i) {
|
|
221
239
|
if (!(s instanceof HTMLElement)) continue;
|
|
222
240
|
if (s.matches(n)) return s;
|
|
223
|
-
const
|
|
224
|
-
if (
|
|
241
|
+
const o = s.querySelector(n);
|
|
242
|
+
if (o) return o;
|
|
225
243
|
}
|
|
226
244
|
return null;
|
|
227
245
|
}
|
|
228
246
|
/** @internal */
|
|
229
247
|
_handlePanelClick(e) {
|
|
230
|
-
var
|
|
248
|
+
var o;
|
|
231
249
|
const t = e.target;
|
|
232
250
|
if (t.closest("hx-menu-item")) return;
|
|
233
251
|
const i = t.closest('[role="menuitem"], [data-value]');
|
|
234
252
|
if (!i) return;
|
|
235
|
-
const n = i.dataset.value ?? i.getAttribute("value") ?? null, s = ((
|
|
253
|
+
const n = i.dataset.value ?? i.getAttribute("value") ?? null, s = ((o = i.textContent) == null ? void 0 : o.trim()) ?? "";
|
|
236
254
|
this.dispatchEvent(
|
|
237
255
|
new CustomEvent("hx-select", {
|
|
238
256
|
bubbles: !0,
|
|
@@ -249,8 +267,8 @@ let l = class extends k {
|
|
|
249
267
|
* @internal
|
|
250
268
|
*/
|
|
251
269
|
_handlePanelItemSelect(e) {
|
|
252
|
-
var
|
|
253
|
-
const t = e.detail, i = t == null ? void 0 : t.item, n = (t == null ? void 0 : t.value) ?? null, s = ((
|
|
270
|
+
var o;
|
|
271
|
+
const t = e.detail, i = t == null ? void 0 : t.item, n = (t == null ? void 0 : t.value) ?? null, s = ((o = i == null ? void 0 : i.textContent) == null ? void 0 : o.trim()) ?? "";
|
|
254
272
|
this.dispatchEvent(
|
|
255
273
|
new CustomEvent("hx-select", {
|
|
256
274
|
bubbles: !0,
|
|
@@ -261,7 +279,7 @@ let l = class extends k {
|
|
|
261
279
|
}
|
|
262
280
|
// ─── Render ───
|
|
263
281
|
render() {
|
|
264
|
-
return
|
|
282
|
+
return _`
|
|
265
283
|
<div
|
|
266
284
|
part="trigger"
|
|
267
285
|
class="trigger-wrapper"
|
|
@@ -274,7 +292,7 @@ let l = class extends k {
|
|
|
274
292
|
part="panel"
|
|
275
293
|
id=${this._panelId}
|
|
276
294
|
role="menu"
|
|
277
|
-
aria-hidden=${this._panelVisible ?
|
|
295
|
+
aria-hidden=${this._panelVisible ? g : "true"}
|
|
278
296
|
aria-label=${this._resolvedLabel}
|
|
279
297
|
class=${this._panelVisible ? "panel panel--visible" : "panel"}
|
|
280
298
|
@click=${this._handlePanelClick}
|
|
@@ -357,11 +375,11 @@ let l = class extends k {
|
|
|
357
375
|
_syncResolvedLabel() {
|
|
358
376
|
const e = this.getAttribute("aria-labelledby");
|
|
359
377
|
this._consumerLabelledBy = e;
|
|
360
|
-
const t =
|
|
378
|
+
const t = T(this, e);
|
|
361
379
|
this._installExternalRefsObserver(t);
|
|
362
|
-
const i = (
|
|
380
|
+
const i = (a) => a.getAttribute("aria-hidden") !== "true" && !a.hasAttribute("hidden"), n = t.filter(i).map((a) => w(a)).filter((a) => a.length > 0).join(" ").replace(/\s+/g, " ").trim(), s = this.getAttribute("aria-label"), o = s !== null ? s.trim() : "";
|
|
363
381
|
let r = "";
|
|
364
|
-
n ? r = n :
|
|
382
|
+
n ? r = n : o ? r = o : this.label ? r = this.label : r = "Menu", this._resolvedLabel = r;
|
|
365
383
|
}
|
|
366
384
|
};
|
|
367
385
|
l.styles = [I, x];
|
|
@@ -387,10 +405,10 @@ d([
|
|
|
387
405
|
p()
|
|
388
406
|
], l.prototype, "_resolvedLabel", 2);
|
|
389
407
|
d([
|
|
390
|
-
|
|
408
|
+
f('[part="panel"]')
|
|
391
409
|
], l.prototype, "_panel", 2);
|
|
392
410
|
d([
|
|
393
|
-
|
|
411
|
+
f('[part="trigger"]')
|
|
394
412
|
], l.prototype, "_triggerWrapper", 2);
|
|
395
413
|
l = d([
|
|
396
414
|
v("hx-dropdown")
|
|
@@ -398,4 +416,4 @@ l = d([
|
|
|
398
416
|
export {
|
|
399
417
|
l as H
|
|
400
418
|
};
|
|
401
|
-
//# sourceMappingURL=hx-dropdown-
|
|
419
|
+
//# sourceMappingURL=hx-dropdown-DREqpIpm.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hx-dropdown-DREqpIpm.js","sources":["../../src/components/hx-dropdown/hx-dropdown.styles.ts","../../src/components/hx-dropdown/hx-dropdown.ts"],"sourcesContent":["import { css } from 'lit';\n\nexport const helixDropdownStyles = css`\n :host {\n display: inline-block;\n position: relative;\n }\n\n :host([disabled]) {\n pointer-events: none;\n opacity: var(--hx-opacity-disabled, 0.5);\n }\n\n .trigger-wrapper {\n display: inline-block;\n }\n\n /*\n * AAA 2.4.13 Focus Appearance — enforce a ≥2px focus ring on the slotted\n * trigger (typically <hx-button>, <button>, or <hx-icon-button>). The host\n * is a popover-container; the interactive surface is the slotted trigger.\n */\n ::slotted([slot='trigger']:focus-visible),\n ::slotted(button:focus-visible),\n ::slotted(a:focus-visible) {\n outline: var(--hx-focus-ring-width, 2px) solid\n var(--hx-dropdown-focus-ring-color, var(--hx-focus-ring-color, #0f7078));\n outline-offset: var(--hx-focus-ring-offset, 2px);\n }\n\n [part='panel'] {\n position: fixed;\n z-index: var(--hx-dropdown-panel-z-index, 1000);\n min-width: var(--hx-dropdown-panel-min-width, 160px);\n background: var(--hx-dropdown-panel-bg, var(--hx-color-surface-default, #ffffff));\n /* Anchor slotted text color to the design-system primary text token so\n slotted <li>'s and other native consumer markup don't inherit a\n foreign color cascade (e.g. brand toolbar setting body { color: #fff }\n and rendering Edit/Duplicate as white-on-white). */\n color: var(--hx-dropdown-panel-color, var(--hx-color-text-primary, #1a1a1a));\n border: 1px solid var(--hx-dropdown-panel-border-color, var(--hx-color-border-default, #d6dbd5));\n border-radius: var(--hx-dropdown-panel-border-radius, var(--hx-border-radius-md, 0.375rem));\n box-shadow: var(\n --hx-dropdown-panel-shadow,\n 0 4px 16px var(--hx-overlay-black-12, rgba(0, 0, 0, 0.12))\n );\n visibility: hidden;\n opacity: 0;\n pointer-events: none;\n transition:\n opacity var(--hx-transition-fast, 150ms ease),\n visibility var(--hx-transition-fast, 150ms ease);\n outline: none;\n }\n\n [part='panel'].panel--visible {\n visibility: visible;\n opacity: 1;\n pointer-events: auto;\n }\n\n @media (prefers-reduced-motion: reduce) {\n [part='panel'] {\n transition: none;\n }\n }\n\n /* ─── High Contrast Mode (forced-colors) ─── */\n\n @media (forced-colors: active) {\n [part='panel'] {\n background-color: Canvas;\n border: 2px solid CanvasText;\n }\n }\n`;\n","import { html, nothing, type PropertyValues } from 'lit';\nimport '../../utilities/document-token-adoption.js';\nimport { customElement, property, state, query } from 'lit/decorators.js';\nimport { devWarn } from '../../utils/dev-warn.js';\nimport { HelixElement } from '../../base/index.js';\nimport type { Placement as FloatingPlacement } from '@floating-ui/dom';\nimport { createIdCounter } from '../../base/index.js';\nimport { forcedColorsInteractive } from '../../styles/forced-colors.js';\nimport { helixDropdownStyles } from './hx-dropdown.styles.js';\nimport { flattenAccName } from '../../utils/aria-flatten.js';\nimport { getMenuItemTypeaheadLabel } from '../../utils/menu-label.js';\nimport { writeMenuItemRovingTabIndex } from '../../utils/menu-roving.js';\nimport { findClosestMenuAncestor } from '../../utils/menu-tree.js';\nimport {\n installAriaIdrefMirror,\n resolveIdrefTokens,\n type AriaIdrefMirrorHandle,\n} from '../../utils/aria-idref.js';\n\n// P2-03: Export so TypeScript consumers can import this type for prop typing.\nexport type DropdownPlacement =\n | 'top'\n | 'top-start'\n | 'top-end'\n | 'bottom'\n | 'bottom-start'\n | 'bottom-end'\n | 'start'\n | 'end';\n\nconst _nextDropdownId = createIdCounter('hx-dropdown');\n\n/**\n * A dropdown component — a button that opens a floating panel on click.\n *\n * ## Architecture Note: Host-Attribute Label Mirror (group-4 round-1)\n *\n * The announced surface is the inner `[part=\"panel\"]` element, which carries\n * `role=\"menu\"`. The host wraps a slotted trigger and the floating panel and\n * does NOT claim a role itself (apart from the round-35-style host\n * `aria-expanded` fallback used only when the trigger slot is empty).\n *\n * Because the panel lives in shadow DOM and `ElementInternals` IDL refs on\n * the host project semantics OUTWARD (host → AT) rather than INWARD\n * (host → shadow descendant), we use the **host-attribute mirror** pattern:\n * resolve consumer `aria-labelledby` IDREFs against the host's composed-tree\n * roots, text-flatten via `flattenAccName`, and write the result to the\n * panel's `aria-label`. Host `aria-label` outranks the `label` property in\n * the same precedence used by every host-canonical hx-* control.\n *\n * Naming precedence (W3C AccName 1.2 §4.3.1):\n * 1. Host `aria-labelledby` (resolved IDREFs, text-flattened)\n * 2. Host `aria-label`\n * 3. `label` property\n * 4. Hard-coded literal `\"Menu\"` (last-resort accessible name)\n *\n * **Group 4b → Group 5b boundary:** Group 4b added the host-attribute\n * label mirror **only** — additive on top of the existing dropdown\n * behaviour. Group 5b (this commit) adds the composite-navigation\n * portion that 4b explicitly deferred:\n * - **Roving tabindex** inside the panel (`_applyRovingTabIndex` +\n * `_rovingIndex`). Only the focused item carries `tabindex=0`.\n * - **First-character typeahead** with 500ms timeout (`_handleTypeahead`)\n * matching `hx-menu`, `hx-overflow-menu`, `hx-split-button`.\n * - Submenu auto-handling is delegated to slotted `hx-menu` /\n * `hx-menu-item` (whose `hx-item-submenu-open` / `hx-item-submenu-close`\n * events are auto-handled by the parent `hx-menu` after Group 5b).\n *\n * The panel's inner-div `role=\"menu\"` is intentionally NOT migrated to\n * the host: the host wraps a slotted consumer trigger AND the panel,\n * so it cannot canonically carry the menu role. Slotted `hx-menu-item`\n * children carry `role=\"menuitem\"` on their HOST after Group 5b's menu\n * migration, which fixes the cross-shadow walk concern from the\n * consumer's perspective.\n *\n * `aria-controls` is intentionally omitted on the trigger: the panel lives\n * in shadow DOM and IDREF values cannot be resolved across shadow\n * boundaries by assistive technology (axe-core flags this as a critical\n * violation if attempted). See `_setupTriggerAria` for the inline note.\n *\n * @summary Button that opens a floating menu panel on click.\n *\n * @tag hx-dropdown\n *\n * @slot trigger - The element that opens the dropdown (e.g. hx-button).\n * @slot - Default slot for dropdown panel content (e.g. menu items).\n *\n * @fires {CustomEvent<void>} hx-show - Dispatched when the dropdown is opened.\n * @fires {CustomEvent<void>} hx-hide - Dispatched when the dropdown is closed.\n * @fires {CustomEvent<{value: string | null; label: string}>} hx-select - Dispatched when a menu item is selected.\n *\n * @csspart trigger - The trigger wrapper element.\n * @csspart panel - The floating panel element.\n *\n * @cssprop [--hx-dropdown-panel-bg=var(--hx-color-neutral-0)] - Panel background color.\n * @cssprop [--hx-dropdown-panel-border-color=var(--hx-color-neutral-200)] - Panel border color.\n * @cssprop [--hx-dropdown-panel-border-radius=var(--hx-border-radius-md)] - Panel border radius.\n * @cssprop [--hx-dropdown-panel-shadow=0 4px 16px rgba(0,0,0,0.12)] - Panel box shadow.\n * @cssprop [--hx-dropdown-panel-z-index=1000] - Panel z-index.\n * @cssprop [--hx-dropdown-panel-min-width=160px] - Panel minimum width.\n *\n * @example\n * ```html\n * <hx-dropdown>\n * <button slot=\"trigger\">Open Menu</button>\n * <ul>\n * <li data-value=\"edit\">Edit</li>\n * <li data-value=\"delete\">Delete</li>\n * </ul>\n * </hx-dropdown>\n * ```\n * @cssprop [--hx-opacity-disabled] - Opacity.\n * @cssprop [--hx-color-neutral-0] - Color.\n * @cssprop [--hx-color-neutral-200] - Color.\n * @cssprop [--hx-border-radius-md] - CSS custom property.\n * @cssprop [--hx-overlay-black-12] - Overlay color.\n * @cssprop [--hx-transition-fast] - Transition timing.\n * @aaa-certified 2026-05-08\n * @aaa-criteria 1.4.6, 1.4.9, 2.1.3, 2.3.3, 2.4.12, 2.4.13, 2.5.5, 3.2.5, 3.3.6, forced-colors, apg-keyboard\n * @aaa-audit src/components/hx-dropdown/AAA-AUDIT.md\n * @keyboard-contract navigate=Arrow,Home,End; activate=Enter,Space; dismiss=Escape; disabled-suppresses=true\n * @aria-pattern menu\n * @aria-pattern-source https://www.w3.org/WAI/ARIA/apg/patterns/menubar/\n * @forced-colors-supported true\n * @stability stable\n * @since 3.7.0\n * @form-associated false\n * @theme-aware true\n * @brand-aware true\n * @drupal-sdc-eligible true\n * @react-wrapper-status complete\n * @figma-component-name hx-dropdown\n * @priority-tier P0\n * @phi-handles false\n * @clinical-context none\n */\n@customElement('hx-dropdown')\nexport class HelixDropdown extends HelixElement {\n static override styles = [helixDropdownStyles, forcedColorsInteractive];\n\n // ─── Public Properties ───\n\n /**\n * Whether the dropdown panel is open.\n * @attr open\n */\n @property({ type: Boolean, reflect: true })\n open = false;\n\n /**\n * Preferred placement of the panel relative to the trigger.\n * @attr placement\n */\n @property({ type: String, reflect: true })\n placement:\n | 'top'\n | 'top-start'\n | 'top-end'\n | 'bottom'\n | 'bottom-start'\n | 'bottom-end'\n | 'start'\n | 'end' = 'bottom-start';\n\n /**\n * Accessible label for the dropdown menu panel. Override for i18n.\n * @attr label\n */\n @property() label = 'Menu';\n\n /**\n * Whether the dropdown is disabled. Prevents opening.\n * @attr disabled\n */\n @property({ type: Boolean, reflect: true })\n disabled = false;\n\n /**\n * Gap in pixels between the trigger and the panel.\n * @attr distance\n */\n @property({ type: Number })\n distance = 4;\n\n // ─── Internal State ───\n\n /**\n * Whether the dropdown panel is currently visible.\n * @internal\n */\n @state() private _panelVisible = false;\n\n /**\n * Index within the panel's focusable menu items of the item currently\n * holding the roving tabindex (and thus visual focus). −1 means the\n * panel has not been keyboard-focused yet.\n * @internal\n */\n private _rovingIndex = -1;\n\n /**\n * Accumulated character buffer for typeahead search within the panel's\n * menu items. Cleared after 500ms of inactivity.\n * @internal\n */\n private _typeaheadBuffer = '';\n\n /**\n * Timer handle that clears the typeahead buffer after a period of inactivity.\n * @internal\n */\n private _typeaheadTimer: ReturnType<typeof setTimeout> | null = null;\n\n /**\n * Resolved accessible name for the menu panel — the value written to the\n * inner `[part=\"panel\"]` `aria-label`. Recomputed on every sync per\n * AccName 1.2 §4.3.1 precedence: host `aria-labelledby` (flattened) >\n * host `aria-label` > `label` property > literal `\"Menu\"`.\n * @internal\n */\n @state() private _resolvedLabel = '';\n\n /**\n * Most recently observed consumer-supplied `aria-labelledby` token list on\n * the host. Refreshed every sync via `getAttribute()`.\n * @internal\n */\n private _consumerLabelledBy: string | null = null;\n\n /**\n * Handle for the shared host attribute / root id observer.\n * @internal\n */\n private _ariaMirror: AriaIdrefMirrorHandle | null = null;\n\n /**\n * Watches in-place text / visibility mutations on consumer light-DOM\n * elements resolved from the host's `aria-labelledby`.\n * @internal\n */\n private _externalRefsObserver: MutationObserver | null = null;\n\n /**\n * Guards against accumulating multiple document click listeners when open state\n * changes faster than the microtask queue can process removeEventListener calls.\n * @internal\n */\n private _documentListenerAttached = false;\n\n // P1-02: Unique panel ID for aria-controls.\n /**\n * Unique ID assigned to the floating panel element, referenced by `aria-controls` on the trigger.\n * @internal\n */\n private _panelId = `${_nextDropdownId()}-panel`;\n\n /**\n * Reference to the floating panel element inside the shadow DOM.\n * @internal\n */\n @query('[part=\"panel\"]') private _panel: HTMLElement | undefined;\n /**\n * Reference to the trigger wrapper element inside the shadow DOM.\n * @internal\n */\n @query('[part=\"trigger\"]') private _triggerWrapper: HTMLElement | undefined;\n\n // ─── Lifecycle ───\n\n override connectedCallback(): void {\n super.connectedCallback();\n this.addEventListener('keydown', this._handleKeydown);\n // Seed the host-attribute label mirror BEFORE first paint so the panel's\n // `aria-label` carries the resolved name on its very first render.\n this._syncResolvedLabel();\n this._ariaMirror = installAriaIdrefMirror(this, () => {\n this._syncResolvedLabel();\n });\n }\n\n override disconnectedCallback(): void {\n super.disconnectedCallback();\n this.removeEventListener('keydown', this._handleKeydown);\n if (this._documentListenerAttached) {\n document.removeEventListener('click', this._handleOutsideClick, { capture: true });\n this._documentListenerAttached = false;\n }\n if (this._typeaheadTimer !== null) {\n clearTimeout(this._typeaheadTimer);\n this._typeaheadTimer = null;\n }\n this._ariaMirror?.disconnect();\n this._ariaMirror = null;\n this._externalRefsObserver?.disconnect();\n this._externalRefsObserver = null;\n }\n\n // ─── Open/Close ───\n\n /** @internal */\n private async _show(): Promise<void> {\n if (this.open || this.disabled) return;\n this.open = true;\n this._panelVisible = true;\n // Add outside-click listener synchronously before any await so it is registered\n // by the time the test fires an outside click after a single await el.updateComplete.\n if (!this._documentListenerAttached) {\n document.addEventListener('click', this._handleOutsideClick, { capture: true });\n this._documentListenerAttached = true;\n }\n await this.updateComplete;\n // P0-01: Fix focus management — use slot.assignedElements() to traverse slotted (light DOM) content.\n // Focus is set after updateComplete (panel is rendered) but before _updatePosition so\n // it executes in the same microtask as the test's await-continuation.\n const panel = this._panel;\n if (panel) {\n // Group 5b: initialize roving tabindex on slotted menu items\n // before focusing the first one. Tab from outside lands on the\n // same item that has visual focus.\n const items = this._getFocusableMenuItems();\n if (items.length > 0) {\n this._rovingIndex = 0;\n this._applyRovingTabIndex(items);\n }\n const firstFocusable = this._getFirstFocusableItem();\n firstFocusable?.focus();\n }\n await this._updatePosition();\n this.dispatchEvent(new CustomEvent<void>('hx-show', { bubbles: true, composed: true }));\n }\n\n // P2-02: returnFocus=true only on Escape; Tab should let focus advance naturally.\n /** @internal */\n private _hide(returnFocus = true): void {\n if (!this.open) return;\n this.open = false;\n this._panelVisible = false;\n this._rovingIndex = -1;\n if (this._typeaheadTimer !== null) {\n clearTimeout(this._typeaheadTimer);\n this._typeaheadTimer = null;\n }\n this._typeaheadBuffer = '';\n if (this._documentListenerAttached) {\n document.removeEventListener('click', this._handleOutsideClick, { capture: true });\n this._documentListenerAttached = false;\n }\n this.dispatchEvent(new CustomEvent<void>('hx-hide', { bubbles: true, composed: true }));\n if (returnFocus) {\n const slot = this.shadowRoot?.querySelector<HTMLSlotElement>('slot[name=\"trigger\"]');\n const trigger = slot?.assignedElements()[0] as HTMLElement | undefined;\n trigger?.focus();\n }\n }\n\n // ─── Positioning ───\n\n /** @internal */\n private async _updatePosition(): Promise<void> {\n const reference = this._triggerWrapper;\n const panel = this._panel;\n if (!reference || !panel) return;\n\n // Map 'start' and 'end' to floating-ui's 'left'/'right'\n const floatingPlacement = this.placement\n .replace(/^start$/, 'left')\n .replace(/^end$/, 'right') as FloatingPlacement;\n\n const { computePosition, flip, shift, offset } = await import('@floating-ui/dom');\n const { x, y } = await computePosition(reference, panel, {\n placement: floatingPlacement,\n strategy: 'fixed',\n middleware: [offset(this.distance), flip(), shift({ padding: 8 })],\n });\n\n Object.assign(panel.style, {\n left: `${x}px`,\n top: `${y}px`,\n });\n }\n\n // ─── Event Handlers ───\n\n /** @internal */\n private _handleTriggerClick(e: MouseEvent): void {\n e.stopPropagation();\n if (this.open) {\n this._hide();\n } else {\n void this._show();\n }\n }\n\n /** @internal */\n private _handleTriggerKeydown(e: KeyboardEvent): void {\n if (e.key === 'Enter' || e.key === ' ' || e.key === 'ArrowDown') {\n e.preventDefault();\n void this._show();\n }\n }\n\n /** @internal */\n private _handleKeydown = (e: KeyboardEvent): void => {\n if (e.key === 'Escape' && this.open) {\n e.stopPropagation();\n this._hide(true); // return focus to trigger on Escape\n } else if (e.key === 'Tab' && this.open) {\n // P2-02: Do not return focus to trigger on Tab — let focus advance naturally to next page element.\n this._hide(false);\n } else if (\n this.open &&\n (e.key === 'ArrowDown' || e.key === 'ArrowUp' || e.key === 'Home' || e.key === 'End')\n ) {\n // P2-01: Arrow key roving within panel per APG Menu Button pattern.\n e.preventDefault();\n this._handleMenuNavigation(e.key);\n } else if (\n this.open &&\n e.key.length === 1 &&\n e.key !== ' ' &&\n !e.ctrlKey &&\n !e.metaKey &&\n !e.altKey\n ) {\n // Group 5b: first-character typeahead within the panel's menu\n // items. 500ms timeout matching hx-menu / hx-overflow-menu.\n this._handleTypeahead(e.key);\n }\n };\n\n // P2-01: Move focus among menuitem elements using arrow keys.\n /** @internal */\n private _handleMenuNavigation(key: string): void {\n const items = this._getFocusableMenuItems();\n if (items.length === 0) return;\n const currentIndex = items.indexOf(document.activeElement as HTMLElement);\n let nextIndex: number;\n if (key === 'ArrowDown') {\n nextIndex = currentIndex < items.length - 1 ? currentIndex + 1 : 0;\n } else if (key === 'ArrowUp') {\n nextIndex = currentIndex > 0 ? currentIndex - 1 : items.length - 1;\n } else if (key === 'Home') {\n nextIndex = 0;\n } else {\n nextIndex = items.length - 1;\n }\n this._rovingIndex = nextIndex;\n this._applyRovingTabIndex(items);\n items[nextIndex]?.focus();\n }\n\n /**\n * Roving tabindex inside the panel: only the focused item carries\n * tabindex=0; the rest are tabindex=-1. APG-compliant for the menu\n * button pattern. Closing-Tab semantics are preserved by the\n * `_handleKeydown` Tab branch above (which lets focus advance\n * naturally and closes the panel).\n *\n * Group 5b: introduced to align hx-dropdown's panel keyboard contract\n * with hx-menu / hx-overflow-menu / hx-split-button. Group 4b only\n * added the host-attribute label mirror (additive); this is the\n * keyboard portion deferred until Group 5.\n *\n * Codex push-gate round-8 finding 2: route through\n * `writeMenuItemRovingTabIndex` so host-canonical `hx-menu-item` items\n * land their roving tabindex on the correct surface (host on the\n * modern path, inner `.menu-item` on the fallback path). A direct\n * `item.tabIndex = value` write on the host fails on the fallback\n * path because the host is forced to `tabindex=-1` to keep exactly\n * one focusable surface per item.\n * @internal\n */\n private _applyRovingTabIndex(items: HTMLElement[]): void {\n items.forEach((item, i) => {\n writeMenuItemRovingTabIndex(item, i === this._rovingIndex ? 0 : -1);\n });\n }\n\n /** @internal */\n private _handleTypeahead(char: string): void {\n if (this._typeaheadTimer !== null) {\n clearTimeout(this._typeaheadTimer);\n }\n this._typeaheadBuffer += char.toLowerCase();\n this._typeaheadTimer = setTimeout(() => {\n this._typeaheadBuffer = '';\n this._typeaheadTimer = null;\n }, 500);\n\n const items = this._getFocusableMenuItems();\n // Codex push-gate round-7 finding 3: read item label via the shared\n // submenu-aware extractor so a parent menuitem with a nested\n // `<hx-menu slot=\"submenu\">` does not match grandchild text and steal\n // focus from a sibling. Single source of truth across hx-menu /\n // hx-dropdown / hx-overflow-menu / hx-split-button.\n const match = items.findIndex((item) => {\n const text = getMenuItemTypeaheadLabel(item).toLowerCase();\n return text.startsWith(this._typeaheadBuffer);\n });\n\n if (match !== -1) {\n this._rovingIndex = match;\n this._applyRovingTabIndex(items);\n items[match]?.focus();\n }\n }\n\n // P0-01 / P2-01: Get focusable menu items from slotted content.\n /** @internal */\n private _getFocusableMenuItems(): HTMLElement[] {\n const panel = this._panel;\n if (!panel) return [];\n const slot = panel.querySelector<HTMLSlotElement>('slot');\n const assignedNodes = slot?.assignedElements({ flatten: true }) ?? [];\n const items: HTMLElement[] = [];\n // `hx-menu-item` carries `role=\"menuitem\"` (or menuitemcheckbox /\n // menuitemradio) via `_internals.role` — AT-only, not a DOM attribute —\n // so `[role=\"menuitem\"]` selectors miss the host. Match the tag name in\n // tandem with the legacy attribute selector so both shapes traverse.\n const isHostCanonicalMenuItem = (el: Element): boolean => el.localName === 'hx-menu-item';\n const collectFrom = (root: ParentNode): HTMLElement[] => {\n const found: HTMLElement[] = [];\n root.querySelectorAll<HTMLElement>('[role=\"menuitem\"]').forEach((item) => found.push(item));\n root.querySelectorAll<HTMLElement>('hx-menu-item').forEach((item) => found.push(item));\n return found;\n };\n for (const node of assignedNodes) {\n if (!(node instanceof HTMLElement)) continue;\n if (node.matches('[role=\"menuitem\"]') || isHostCanonicalMenuItem(node)) {\n items.push(node);\n } else {\n collectFrom(node).forEach((item) => items.push(item));\n }\n }\n return items;\n }\n\n // P0-01: Find the first focusable element in slotted panel content.\n /** @internal */\n private _getFirstFocusableItem(): HTMLElement | null {\n const panel = this._panel;\n if (!panel) return null;\n const slot = panel.querySelector<HTMLSlotElement>('slot');\n const assignedNodes = slot?.assignedElements({ flatten: true }) ?? [];\n // `hx-menu-item` host carries `role=\"menuitem\"` via `_internals.role`\n // (invisible to attribute selectors). Add the literal tag name to the\n // focusable selector so the host-canonical menu-item is found.\n const focusableSelector =\n 'hx-menu-item, [role=\"menuitem\"], button, [tabindex]:not([tabindex=\"-1\"]), a[href], input, select, textarea';\n for (const node of assignedNodes) {\n if (!(node instanceof HTMLElement)) continue;\n if (node.matches(focusableSelector)) return node;\n const found = node.querySelector<HTMLElement>(focusableSelector);\n if (found) return found;\n }\n return null;\n }\n\n /** @internal */\n private _handleOutsideClick = (e: MouseEvent): void => {\n const path = e.composedPath();\n if (!path.includes(this)) {\n this._hide();\n }\n };\n\n /** @internal */\n private _handlePanelClick(e: MouseEvent): void {\n const target = e.target as HTMLElement;\n // P2-06: Narrow selector — bare 'li' and 'button' cause spurious hx-select events.\n // Group 5b round-3 (codex): bail FIRST on host-canonical `hx-menu-item`,\n // independently of what `closest()` resolves with the legacy selectors.\n // If a consumer slots `<hx-menu-item><span data-value=\"…\">…</span></hx-menu-item>`\n // and the click lands on the inner span, `closest('hx-menu-item, …, [data-value]')`\n // resolves to the inner span (nearest match) — the legacy localName guard\n // misses, and we'd dispatch `hx-select` here AND again from\n // `_handlePanelItemSelect` when the host's bubbled `hx-item-select` arrives.\n // The host owns its own dispatch path; descendants of the host must defer.\n if (target.closest('hx-menu-item')) return;\n const item = target.closest<HTMLElement>('[role=\"menuitem\"], [data-value]');\n if (!item) return;\n\n const value = item.dataset['value'] ?? item.getAttribute('value') ?? null;\n const label = item.textContent?.trim() ?? '';\n\n this.dispatchEvent(\n new CustomEvent<{ value: string | null; label: string }>('hx-select', {\n bubbles: true,\n composed: true,\n detail: { value, label },\n }),\n );\n\n this._hide();\n }\n\n /**\n * Bubbled `hx-item-select` from a slotted `hx-menu-item` host. Forwards\n * the activation through the composite's `hx-select` contract using the\n * item's `value` property and label text. Disabled items never emit\n * `hx-item-select`, so no disabled-guard is needed here.\n * @internal\n */\n private _handlePanelItemSelect(e: Event): void {\n const detail = (e as CustomEvent<{ item: HTMLElement; value: string }>).detail;\n const item = detail?.item;\n const value = detail?.value ?? null;\n const label = item?.textContent?.trim() ?? '';\n this.dispatchEvent(\n new CustomEvent<{ value: string | null; label: string }>('hx-select', {\n bubbles: true,\n composed: true,\n detail: { value, label },\n }),\n );\n this._hide();\n }\n\n /**\n * Bubbled `hx-item-submenu-open` from a slotted `hx-menu-item` host.\n * Codex push-gate round-9 P1: when slotted `hx-menu-item`s open / close\n * a nested submenu inside this composite's panel (no enclosing\n * `hx-menu`), the events fly past with no handler. Match the round-4\n * `hx-menu._handleSubmenuOpen` shape so APG behaviour holds.\n *\n * If the dispatching item is enclosed by an inner `hx-menu` (a true\n * nested submenu inside the panel), that menu owns the toggle — defer.\n * Otherwise this composite's panel is the enclosing menu surface, so\n * call `setSubmenuOpen(true)` on the item and focus the first child.\n * @internal\n */\n private _handlePanelSubmenuOpen = (e: Event): void => {\n if (!(e instanceof CustomEvent)) return;\n const detail = (e as CustomEvent<{ item: HTMLElement }>).detail;\n const item = detail?.item;\n if (!item) return;\n // Defer to a closer enclosing `hx-menu` (a nested submenu) when one\n // exists — that menu's own handler will own the toggle.\n if (findClosestMenuAncestor(item) !== null) return;\n queueMicrotask(() => {\n if (e.defaultPrevented) return;\n const setter = (item as HTMLElement & { setSubmenuOpen?: (v: boolean) => void })\n .setSubmenuOpen;\n if (typeof setter !== 'function') return;\n setter.call(item, true);\n const updateComplete = (item as HTMLElement & { updateComplete?: Promise<unknown> })\n .updateComplete;\n if (updateComplete) {\n void updateComplete\n .then(() => {\n const submenuSlot = (\n item as HTMLElement & { shadowRoot?: ShadowRoot | null }\n ).shadowRoot?.querySelector<HTMLSlotElement>('slot[name=\"submenu\"]');\n const nested = submenuSlot\n ?.assignedElements({ flatten: true })\n .find((el) => el.tagName.toLowerCase() === 'hx-menu') as\n | (HTMLElement & { focusFirst?: () => void })\n | undefined;\n nested?.focusFirst?.();\n })\n .catch(() => undefined);\n }\n });\n };\n\n /**\n * Bubbled `hx-item-submenu-close` from a slotted `hx-menu-item` host.\n * Codex push-gate round-9 P1: routes the close to the right surface.\n *\n * - Nested submenu close (the dispatching item lives inside an inner\n * `hx-menu` slotted into a parent's `slot=\"submenu\"`): defer to that\n * inner menu's own handler. The composite's panel must NOT close.\n * - Top-level item ArrowLeft (no enclosing `hx-menu` between the item\n * and this composite): there is no parent submenu to close, so\n * collapse the composite's panel and return focus to the trigger,\n * matching APG menu-button behaviour.\n * @internal\n */\n private _handlePanelSubmenuClose = (e: Event): void => {\n if (!(e instanceof CustomEvent)) return;\n const detail = (e as CustomEvent<{ item: HTMLElement }>).detail;\n const item = detail?.item;\n if (!item) return;\n // A closer enclosing `hx-menu` owns the close — defer.\n if (findClosestMenuAncestor(item) !== null) return;\n if (e.defaultPrevented) return;\n this._hide(true);\n };\n\n // ─── Render ───\n\n override render() {\n return html`\n <div\n part=\"trigger\"\n class=\"trigger-wrapper\"\n @click=${this._handleTriggerClick}\n @keydown=${this._handleTriggerKeydown}\n >\n <slot name=\"trigger\" @slotchange=${this._onTriggerSlotChange}></slot>\n </div>\n <div\n part=\"panel\"\n id=${this._panelId}\n role=\"menu\"\n aria-hidden=${this._panelVisible ? nothing : 'true'}\n aria-label=${this._resolvedLabel}\n class=${this._panelVisible ? 'panel panel--visible' : 'panel'}\n @click=${this._handlePanelClick}\n @hx-item-select=${this._handlePanelItemSelect}\n @hx-item-submenu-open=${this._handlePanelSubmenuOpen}\n @hx-item-submenu-close=${this._handlePanelSubmenuClose}\n >\n <slot @slotchange=${this._onPanelSlotChange}></slot>\n </div>\n `;\n }\n\n // ─── Panel slot validation ───\n\n /** @internal */\n private _onPanelSlotChange(e: Event): void {\n const slot = e.target as HTMLSlotElement;\n const assigned = slot.assignedElements({ flatten: true });\n const nonItems = assigned.filter((el) => el.tagName.toLowerCase() !== 'hx-dropdown-item');\n if (nonItems.length > 0) {\n devWarn(\n 'hx-dropdown',\n `Default slot should contain only hx-dropdown-item elements. Found unexpected: ${nonItems.map((el) => `<${el.tagName.toLowerCase()}>`).join(', ')}. Non-hx-dropdown-item children will be included in keyboard navigation incorrectly.`,\n );\n }\n }\n\n // ─── ARIA setup for trigger slot ───\n\n /** @internal */\n private _onTriggerSlotChange(): void {\n this._setupTriggerAria();\n }\n\n override firstUpdated(): void {\n this._setupTriggerAria();\n }\n\n /** @internal */\n private _setupTriggerAria(): void {\n const slot = this.shadowRoot?.querySelector<HTMLSlotElement>('slot[name=\"trigger\"]');\n if (!slot) return;\n const trigger = slot.assignedElements()[0] as HTMLElement | undefined;\n if (trigger) {\n // P1-01: Use aria-haspopup=\"menu\" per ARIA 1.1+ / APG Menu Button pattern.\n trigger.setAttribute('aria-haspopup', 'menu');\n trigger.setAttribute('aria-expanded', String(this.open));\n // aria-controls is intentionally omitted: the panel lives in Shadow DOM and\n // IDREF values cannot be resolved across shadow boundaries by assistive technology.\n // P2-06: Remove host fallback when a trigger element is present.\n this.removeAttribute('aria-expanded');\n } else {\n // P2-06: Fallback — set aria-expanded on host when trigger slot is empty or unassigned.\n this.setAttribute('aria-expanded', String(this.open));\n }\n }\n\n override willUpdate(changedProperties: PropertyValues<this>): void {\n super.willUpdate(changedProperties);\n // `label` property changes must flow into the resolved name BEFORE\n // render so the new fallback is in place on the same paint. See\n // `hx-popover.willUpdate()` for the same rationale.\n if (changedProperties.has('label')) {\n this._syncResolvedLabel();\n }\n }\n\n override updated(changedProperties: PropertyValues<this>): void {\n super.updated(changedProperties);\n if (changedProperties.has('open')) {\n // Keep aria-expanded in sync\n const slot = this.shadowRoot?.querySelector<HTMLSlotElement>('slot[name=\"trigger\"]');\n const trigger = slot?.assignedElements()[0] as HTMLElement | undefined;\n if (trigger) {\n trigger.setAttribute('aria-expanded', String(this.open));\n } else {\n // P2-06: Fallback — keep host aria-expanded in sync when trigger slot is empty.\n this.setAttribute('aria-expanded', String(this.open));\n }\n }\n }\n\n // ─── Host-attribute label mirror ───\n\n /**\n * (Re-)installs a `MutationObserver` over the deduped union of\n * consumer-resolved label elements, watching for in-place text /\n * visibility mutations so the panel's `aria-label` tracks live consumer\n * text. See `hx-popover._installExternalRefsObserver` for the matching\n * shape used across the host-attribute-mirror family.\n * @internal\n */\n private _installExternalRefsObserver(elements: Element[]): void {\n if (this._externalRefsObserver) {\n this._externalRefsObserver.disconnect();\n this._externalRefsObserver = null;\n }\n if (elements.length === 0) return;\n const unique = new Set<Element>(elements);\n const observer = new MutationObserver(() => {\n this._syncResolvedLabel();\n });\n for (const el of unique) {\n observer.observe(el, {\n characterData: true,\n subtree: true,\n childList: true,\n attributes: true,\n attributeFilter: ['aria-hidden', 'hidden'],\n });\n }\n this._externalRefsObserver = observer;\n }\n\n /**\n * Resolves the menu panel's accessible name from host attributes and the\n * `label` property. AccName 1.2 §4.3.1 precedence:\n * 1. Host `aria-labelledby` (resolved IDREFs, flattened)\n * 2. Host `aria-label`\n * 3. `label` property\n * 4. Literal `\"Menu\"` (last-resort)\n * @internal\n */\n private _syncResolvedLabel(): void {\n const liveLabelledBy = this.getAttribute('aria-labelledby');\n this._consumerLabelledBy = liveLabelledBy;\n const consumerLabelEls = resolveIdrefTokens(this, liveLabelledBy);\n\n this._installExternalRefsObserver(consumerLabelEls);\n\n const isVisibleForAccName = (el: Element): boolean =>\n el.getAttribute('aria-hidden') !== 'true' && !el.hasAttribute('hidden');\n\n const flattenedFromIdrefs = consumerLabelEls\n .filter(isVisibleForAccName)\n .map((el) => flattenAccName(el))\n .filter((t) => t.length > 0)\n .join(' ')\n .replace(/\\s+/g, ' ')\n .trim();\n\n const liveAriaLabel = this.getAttribute('aria-label');\n const hostAriaLabel = liveAriaLabel !== null ? liveAriaLabel.trim() : '';\n\n let resolved = '';\n if (flattenedFromIdrefs) {\n resolved = flattenedFromIdrefs;\n } else if (hostAriaLabel) {\n resolved = hostAriaLabel;\n } else if (this.label) {\n resolved = this.label;\n } else {\n resolved = 'Menu';\n }\n\n this._resolvedLabel = resolved;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'hx-dropdown': HelixDropdown;\n }\n interface HTMLElementEventMap {\n 'hx-show': CustomEvent<void>;\n 'hx-hide': CustomEvent<void>;\n 'hx-select': CustomEvent<{ value: string | null; label: string }>;\n }\n}\n"],"names":["helixDropdownStyles","css","_nextDropdownId","createIdCounter","HelixDropdown","HelixElement","detail","item","findClosestMenuAncestor","setter","updateComplete","submenuSlot","_a","nested","el","_b","installAriaIdrefMirror","items","firstFocusable","returnFocus","slot","trigger","reference","panel","floatingPlacement","computePosition","flip","shift","offset","x","y","key","currentIndex","nextIndex","writeMenuItemRovingTabIndex","char","match","getMenuItemTypeaheadLabel","assignedNodes","isHostCanonicalMenuItem","collectFrom","root","found","node","focusableSelector","target","value","label","html","nothing","nonItems","devWarn","changedProperties","elements","unique","observer","liveLabelledBy","consumerLabelEls","resolveIdrefTokens","isVisibleForAccName","flattenedFromIdrefs","flattenAccName","t","liveAriaLabel","hostAriaLabel","resolved","forcedColorsInteractive","__decorateClass","property","state","query","customElement"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hx-field-label-BVRyyKeh.js","sources":["../../src/components/hx-field-label/hx-field-label.styles.ts","../../src/components/hx-field-label/hx-field-label.ts"],"sourcesContent":["import { css } from 'lit';\n\nexport const helixFieldLabelStyles = css`\n :host {\n display: block;\n }\n\n .label {\n display: inline-flex;\n align-items: baseline;\n gap: var(--hx-space-1, 0.25rem);\n font-size: var(--hx-font-label-size, var(--hx-font-size-sm, 0.875rem));\n font-weight: var(--hx-font-label-weight, var(--hx-font-weight-medium, 500));\n color: var(--hx-field-label-color, var(--hx-color-text-strong, #313e4b));\n line-height: var(--hx-font-label-line-height, var(--hx-line-height-normal, 1.5));\n font-family: var(--hx-font-label-family, var(--hx-font-family-sans, sans-serif));\n }\n\n .required-indicator {\n color: var(--hx-field-label-required-color, var(--hx-color-error-text, #c92a2a));\n font-weight: var(--hx-font-weight-bold, 700);\n }\n\n .optional-indicator {\n font-size: var(--hx-font-size-xs, 0.75rem);\n font-weight: var(--hx-font-weight-normal, 400);\n color: var(--hx-color-text-muted, #66787b);\n }\n\n /* ─── High Contrast Mode (forced-colors) ─── */\n\n @media (forced-colors: active) {\n .label {\n color: CanvasText;\n }\n\n .required-indicator {\n color: LinkText;\n }\n\n .optional-indicator {\n color: GrayText;\n }\n }\n\n .visually-hidden {\n position: absolute;\n width: 1px;\n height: 1px;\n padding: 0;\n margin: -1px;\n overflow: hidden;\n clip: rect(0, 0, 0, 0);\n white-space: nowrap;\n border: 0;\n }\n`;\n","import { html, nothing } from 'lit';\nimport '../../utilities/document-token-adoption.js';\nimport { customElement, property } from 'lit/decorators.js';\nimport { HelixElement } from '../../base/index.js';\nimport { helixFieldLabelStyles } from './hx-field-label.styles.js';\nimport { forcedColorsSurface } from '../../styles/forced-colors.js';\n\n/**\n * Standardized label for form fields. Used as a consistent sub-component\n * for hx-field and other form field components.\n *\n * ## Label Association\n *\n * **For inputs in light DOM (the typical consumer deployment):** Use\n * `aria-labelledby` pointing to the host element's `id`. The `for` attribute\n * renders a native `<label for=\"...\">` inside shadow DOM, but the HTML spec\n * scopes `for`/`id` lookup to the same tree — a shadow-DOM label cannot\n * associate with a light-DOM input. Example:\n *\n * ```html\n * <hx-field-label id=\"label-email\">Email</hx-field-label>\n * <input id=\"email\" aria-labelledby=\"label-email\" />\n * ```\n *\n * **For inputs in the same shadow root:** The `for` attribute works as\n * expected for direct label association.\n *\n * When `for` is unset, renders a `<span>` that can be referenced via\n * `aria-labelledby` for labeling controls across the shadow DOM boundary.\n *\n * @summary Standardized label for form fields.\n *\n * @tag hx-field-label\n *\n * @slot - Label text content.\n * @slot required-indicator - Custom required marker (defaults to \"*\").\n *\n * @csspart base - The label or span element.\n * @csspart required-indicator - The required indicator wrapper.\n * @csspart optional-indicator - The optional text indicator.\n *\n * @cssprop [--hx-field-label-color=var(--hx-color-neutral-700)] - Label text color.\n * @cssprop [--hx-field-label-required-color=var(--hx-color-danger, var(--hx-color-error-text, #b91c1c))] - Required indicator color.\n * @cssprop [--hx-font-label-size=var(--hx-font-size-sm)] - Label font size.\n * @cssprop [--hx-font-label-weight=var(--hx-font-weight-medium)] - Label font weight.\n * @cssprop [--hx-font-label-line-height=var(--hx-line-height-normal)] - Label line height.\n * @cssprop [--hx-font-label-family=var(--hx-font-family-sans)] - Label font family.\n * @cssprop [--hx-space-1] - Spacing token.\n * @cssprop [--hx-font-size-sm] - Font size.\n * @cssprop [--hx-font-weight-medium] - Font weight.\n * @cssprop [--hx-color-neutral-700] - Color.\n * @cssprop [--hx-line-height-normal] - Line height.\n * @cssprop [--hx-font-family-sans] - Font family.\n * @cssprop [--hx-color-error-text] - Color.\n * @cssprop [--hx-font-weight-bold] - Font weight.\n * @cssprop [--hx-font-size-xs] - Font size.\n * @cssprop [--hx-font-weight-normal] - Font weight.\n * @cssprop [--hx-color-neutral-500] - Color.\n */\n@customElement('hx-field-label')\nexport class HelixFieldLabel extends HelixElement {\n static override styles = [helixFieldLabelStyles, forcedColorsSurface];\n\n /**\n * The ID of the associated form control. When set, renders a native\n * `<label for=\"...\">` element for direct label association.\n * @attr for\n */\n @property({ type: String })\n for = '';\n\n /**\n * Whether the associated field is required. Shows a required indicator (*).\n * @attr required\n */\n @property({ type: Boolean, reflect: true })\n required = false;\n\n /**\n * Whether the associated field is optional. Shows \"(optional)\" text.\n * @attr optional\n */\n @property({ type: Boolean, reflect: true })\n optional = false;\n\n override render() {\n const requiredIndicator = this.required\n ? html`<span part=\"required-indicator\" class=\"required-indicator\"\n ><span aria-hidden=\"true\"><slot name=\"required-indicator\">*</slot></span\n ><span class=\"visually-hidden\">required</span></span\n >`\n : nothing;\n\n const optionalIndicator = this.optional\n ? html`<span part=\"optional-indicator\" class=\"optional-indicator\">(optional)</span>`\n : nothing;\n\n const content = html`<slot></slot>${requiredIndicator}${optionalIndicator}`;\n\n if (this.for) {\n return html`<label part=\"base\" class=\"label\" for=${this.for}>${content}</label>`;\n }\n\n return html`<span part=\"base\" class=\"label\">${content}</span>`;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'hx-field-label': HelixFieldLabel;\n }\n}\n"],"names":["helixFieldLabelStyles","css","HelixFieldLabel","HelixElement","requiredIndicator","html","nothing","optionalIndicator","content","forcedColorsSurface","__decorateClass","property","customElement"],"mappings":";;;;AAEO,MAAMA,IAAwBC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;;;;
|
|
1
|
+
{"version":3,"file":"hx-field-label-BVRyyKeh.js","sources":["../../src/components/hx-field-label/hx-field-label.styles.ts","../../src/components/hx-field-label/hx-field-label.ts"],"sourcesContent":["import { css } from 'lit';\n\nexport const helixFieldLabelStyles = css`\n :host {\n display: block;\n }\n\n .label {\n display: inline-flex;\n align-items: baseline;\n gap: var(--hx-space-1, 0.25rem);\n font-size: var(--hx-font-label-size, var(--hx-font-size-sm, 0.875rem));\n font-weight: var(--hx-font-label-weight, var(--hx-font-weight-medium, 500));\n color: var(--hx-field-label-color, var(--hx-color-text-strong, #313e4b));\n line-height: var(--hx-font-label-line-height, var(--hx-line-height-normal, 1.5));\n font-family: var(--hx-font-label-family, var(--hx-font-family-sans, sans-serif));\n }\n\n .required-indicator {\n color: var(--hx-field-label-required-color, var(--hx-color-error-text, #c92a2a));\n font-weight: var(--hx-font-weight-bold, 700);\n }\n\n .optional-indicator {\n font-size: var(--hx-font-size-xs, 0.75rem);\n font-weight: var(--hx-font-weight-normal, 400);\n color: var(--hx-color-text-muted, #66787b);\n }\n\n /* ─── High Contrast Mode (forced-colors) ─── */\n\n @media (forced-colors: active) {\n .label {\n color: CanvasText;\n }\n\n .required-indicator {\n color: LinkText;\n }\n\n .optional-indicator {\n color: GrayText;\n }\n }\n\n .visually-hidden {\n position: absolute;\n width: 1px;\n height: 1px;\n padding: 0;\n margin: -1px;\n overflow: hidden;\n clip: rect(0, 0, 0, 0);\n white-space: nowrap;\n border: 0;\n }\n`;\n","import { html, nothing } from 'lit';\nimport '../../utilities/document-token-adoption.js';\nimport { customElement, property } from 'lit/decorators.js';\nimport { HelixElement } from '../../base/index.js';\nimport { helixFieldLabelStyles } from './hx-field-label.styles.js';\nimport { forcedColorsSurface } from '../../styles/forced-colors.js';\n\n/**\n * Standardized label for form fields. Used as a consistent sub-component\n * for hx-field and other form field components.\n *\n * ## Label Association\n *\n * **For inputs in light DOM (the typical consumer deployment):** Use\n * `aria-labelledby` pointing to the host element's `id`. The `for` attribute\n * renders a native `<label for=\"...\">` inside shadow DOM, but the HTML spec\n * scopes `for`/`id` lookup to the same tree — a shadow-DOM label cannot\n * associate with a light-DOM input. Example:\n *\n * ```html\n * <hx-field-label id=\"label-email\">Email</hx-field-label>\n * <input id=\"email\" aria-labelledby=\"label-email\" />\n * ```\n *\n * **For inputs in the same shadow root:** The `for` attribute works as\n * expected for direct label association.\n *\n * When `for` is unset, renders a `<span>` that can be referenced via\n * `aria-labelledby` for labeling controls across the shadow DOM boundary.\n *\n * @summary Standardized label for form fields.\n *\n * @tag hx-field-label\n *\n * @slot - Label text content.\n * @slot required-indicator - Custom required marker (defaults to \"*\").\n *\n * @csspart base - The label or span element.\n * @csspart required-indicator - The required indicator wrapper.\n * @csspart optional-indicator - The optional text indicator.\n *\n * @cssprop [--hx-field-label-color=var(--hx-color-neutral-700)] - Label text color.\n * @cssprop [--hx-field-label-required-color=var(--hx-color-danger, var(--hx-color-error-text, #b91c1c))] - Required indicator color.\n * @cssprop [--hx-font-label-size=var(--hx-font-size-sm)] - Label font size.\n * @cssprop [--hx-font-label-weight=var(--hx-font-weight-medium)] - Label font weight.\n * @cssprop [--hx-font-label-line-height=var(--hx-line-height-normal)] - Label line height.\n * @cssprop [--hx-font-label-family=var(--hx-font-family-sans)] - Label font family.\n * @cssprop [--hx-space-1] - Spacing token.\n * @cssprop [--hx-font-size-sm] - Font size.\n * @cssprop [--hx-font-weight-medium] - Font weight.\n * @cssprop [--hx-color-neutral-700] - Color.\n * @cssprop [--hx-line-height-normal] - Line height.\n * @cssprop [--hx-font-family-sans] - Font family.\n * @cssprop [--hx-color-error-text] - Color.\n * @cssprop [--hx-font-weight-bold] - Font weight.\n * @cssprop [--hx-font-size-xs] - Font size.\n * @cssprop [--hx-font-weight-normal] - Font weight.\n * @cssprop [--hx-color-neutral-500] - Color.\n *\n * @aaa-certified 2026-05-09\n * @aaa-criteria 1.4.6, 1.4.9, 2.1.3, 2.3.3, 2.4.12, 2.4.13, 2.5.5, 3.2.5, 3.3.6, forced-colors, apg-keyboard\n * @aaa-audit src/components/hx-field-label/AAA-AUDIT.md\n * @aria-pattern label\n * @forced-colors-supported true\n * @stability stable\n * @since 3.7.0\n * @form-associated false\n * @theme-aware true\n * @brand-aware true\n * @drupal-sdc-eligible true\n * @react-wrapper-status complete\n * @figma-component-name hx-field-label\n * @priority-tier P0\n * @phi-handles false\n * @clinical-context none\n */\n@customElement('hx-field-label')\nexport class HelixFieldLabel extends HelixElement {\n static override styles = [helixFieldLabelStyles, forcedColorsSurface];\n\n /**\n * The ID of the associated form control. When set, renders a native\n * `<label for=\"...\">` element for direct label association.\n * @attr for\n */\n @property({ type: String })\n for = '';\n\n /**\n * Whether the associated field is required. Shows a required indicator (*).\n * @attr required\n */\n @property({ type: Boolean, reflect: true })\n required = false;\n\n /**\n * Whether the associated field is optional. Shows \"(optional)\" text.\n * @attr optional\n */\n @property({ type: Boolean, reflect: true })\n optional = false;\n\n override render() {\n const requiredIndicator = this.required\n ? html`<span part=\"required-indicator\" class=\"required-indicator\"\n ><span aria-hidden=\"true\"><slot name=\"required-indicator\">*</slot></span\n ><span class=\"visually-hidden\">required</span></span\n >`\n : nothing;\n\n const optionalIndicator = this.optional\n ? html`<span part=\"optional-indicator\" class=\"optional-indicator\">(optional)</span>`\n : nothing;\n\n const content = html`<slot></slot>${requiredIndicator}${optionalIndicator}`;\n\n if (this.for) {\n return html`<label part=\"base\" class=\"label\" for=${this.for}>${content}</label>`;\n }\n\n return html`<span part=\"base\" class=\"label\">${content}</span>`;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'hx-field-label': HelixFieldLabel;\n }\n}\n"],"names":["helixFieldLabelStyles","css","HelixFieldLabel","HelixElement","requiredIndicator","html","nothing","optionalIndicator","content","forcedColorsSurface","__decorateClass","property","customElement"],"mappings":";;;;AAEO,MAAMA,IAAwBC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;;;;AC2E9B,IAAMC,IAAN,cAA8BC,EAAa;AAAA,EAA3C,cAAA;AAAA,UAAA,GAAA,SAAA,GASL,KAAA,MAAM,IAON,KAAA,WAAW,IAOX,KAAA,WAAW;AAAA,EAAA;AAAA,EAEF,SAAS;AAChB,UAAMC,IAAoB,KAAK,WAC3BC;AAAA;AAAA;AAAA,aAIAC,GAEEC,IAAoB,KAAK,WAC3BF,kFACAC,GAEEE,IAAUH,iBAAoBD,CAAiB,GAAGG,CAAiB;AAEzE,WAAI,KAAK,MACAF,yCAA4C,KAAK,GAAG,IAAIG,CAAO,aAGjEH,oCAAuCG,CAAO;AAAA,EACvD;AACF;AA7CaN,EACK,SAAS,CAACF,GAAuBS,CAAmB;AAQpEC,EAAA;AAAA,EADCC,EAAS,EAAE,MAAM,OAAA,CAAQ;AAAA,GARfT,EASX,WAAA,OAAA,CAAA;AAOAQ,EAAA;AAAA,EADCC,EAAS,EAAE,MAAM,SAAS,SAAS,IAAM;AAAA,GAf/BT,EAgBX,WAAA,YAAA,CAAA;AAOAQ,EAAA;AAAA,EADCC,EAAS,EAAE,MAAM,SAAS,SAAS,IAAM;AAAA,GAtB/BT,EAuBX,WAAA,YAAA,CAAA;AAvBWA,IAANQ,EAAA;AAAA,EADNE,EAAc,gBAAgB;AAAA,GAClBV,CAAA;"}
|