@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
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"hx-toggle-button-DSJeFlb0.js","sources":["../../src/components/hx-toggle-button/hx-toggle-button.styles.ts","../../src/components/hx-toggle-button/hx-toggle-button.ts"],"sourcesContent":["import { css } from 'lit';\n\nexport const helixToggleButtonStyles = css`\n :host {\n display: inline-block;\n }\n\n :host([disabled]) {\n pointer-events: none;\n opacity: var(--hx-opacity-disabled, 0.5);\n }\n\n /* ─── Base Button ─── */\n\n .button {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n gap: var(--hx-space-2, 0.5rem);\n border: var(--hx-border-width-thin, 1px) solid var(--hx-toggle-button-border-color, transparent);\n border-radius: var(--hx-toggle-button-border-radius, var(--hx-border-radius-md, 0.375rem));\n background-color: var(--hx-toggle-button-bg, var(--hx-color-action-primary-bg, #0f7078));\n color: var(--hx-toggle-button-color, var(--hx-color-text-on-primary, #ffffff));\n font-family: var(--hx-toggle-button-font-family, var(--hx-font-family-sans, sans-serif));\n font-weight: var(--hx-toggle-button-font-weight, var(--hx-font-weight-semibold, 600));\n line-height: var(--hx-line-height-tight, 1.25);\n cursor: pointer;\n transition:\n background-color var(--hx-transition-fast, 150ms ease),\n color var(--hx-transition-fast, 150ms ease),\n border-color var(--hx-transition-fast, 150ms ease),\n box-shadow var(--hx-transition-fast, 150ms ease);\n text-decoration: none;\n white-space: nowrap;\n user-select: none;\n -webkit-user-select: none;\n }\n\n /*\n * Host-focus path: on the modern (IDL element-references) render branch the\n * host is the tabbable surface (tabindex=0) and the inner <button> is\n * demoted to tabindex=-1. Drive the focus ring from ':host(:focus-visible)'\n * so keyboard users still see a visible affordance. Codex round-11 P1.\n */\n :host(:focus-visible) .button {\n outline: var(--hx-focus-ring-width, 2px) solid\n var(--hx-toggle-button-focus-ring-color, var(--hx-focus-ring-color, #0f7078));\n outline-offset: var(--hx-focus-ring-offset, 2px);\n }\n\n /*\n * Fallback (no-IDL-ref) path: the host carries tabindex=-1 and the inner\n * <button> is the tab target. Native :focus-visible drives the ring.\n */\n .button:focus-visible {\n outline: var(--hx-focus-ring-width, 2px) solid\n var(--hx-toggle-button-focus-ring-color, var(--hx-focus-ring-color, #0f7078));\n outline-offset: var(--hx-focus-ring-offset, 2px);\n }\n\n .button:hover {\n filter: brightness(var(--hx-filter-brightness-hover, 0.9));\n }\n\n .button:active {\n filter: brightness(var(--hx-filter-brightness-active, 0.8));\n }\n\n /* ─── Size Variants ─── */\n\n /* WCAG 2.5.5 (healthcare mandate): minimum 44px touch target for sm variant.\n min-height uses --hx-touch-target-min to guarantee the interactive area\n meets the threshold even though the visual size token is smaller. */\n .button--sm {\n padding: var(--hx-space-1, 0.25rem) var(--hx-space-3, 0.75rem);\n font-size: var(--hx-font-size-sm, 0.875rem);\n min-height: var(--hx-touch-target-min, 2.75rem);\n }\n\n .button--md {\n padding: var(--hx-space-2, 0.5rem) var(--hx-space-4, 1rem);\n font-size: var(--hx-font-size-md, 1rem);\n min-height: var(--hx-size-10, 2.5rem);\n }\n\n .button--lg {\n padding: var(--hx-space-3, 0.75rem) var(--hx-space-6, 1.5rem);\n font-size: var(--hx-font-size-lg, 1.125rem);\n min-height: var(--hx-size-12, 3rem);\n }\n\n /* ─── Style Variants ─── */\n\n .button--primary {\n --hx-toggle-button-bg: var(--hx-color-action-primary-bg, #0f7078);\n --hx-toggle-button-color: var(--hx-color-text-on-primary, #ffffff);\n --hx-toggle-button-border-color: transparent;\n }\n\n /*\n * secondary/ghost paint primary text on the surface (white). primary-500\n * (#429797) on white = 3.43:1 — fails AA at body sizes. shift to\n * primary-600 (#0F7078) = 6.06:1 — AA pass. border keeps primary-500\n * for the brand affordance (3:1 non-text contrast still met).\n */\n .button--secondary {\n --hx-toggle-button-bg: transparent;\n --hx-toggle-button-color: var(--hx-color-primary-600, #0f7078);\n --hx-toggle-button-border-color: var(--hx-color-primary-600, #0f7078);\n }\n\n .button--secondary:hover {\n --hx-toggle-button-bg: var(--hx-color-primary-50, #ebf8f8);\n }\n\n .button--tertiary {\n --hx-toggle-button-bg: var(--hx-color-surface-sunken, #ebeee9);\n --hx-toggle-button-color: var(--hx-color-text-primary, #0d1825);\n --hx-toggle-button-border-color: transparent;\n }\n\n .button--tertiary:hover {\n --hx-toggle-button-bg: var(--hx-color-surface-raised, #f5f8f3);\n }\n\n .button--ghost {\n --hx-toggle-button-bg: transparent;\n --hx-toggle-button-color: var(--hx-color-primary-600, #0f7078);\n --hx-toggle-button-border-color: transparent;\n }\n\n .button--ghost:hover {\n --hx-toggle-button-bg: var(--hx-color-surface-raised, #f5f8f3);\n }\n\n .button--outline {\n --hx-toggle-button-bg: transparent;\n --hx-toggle-button-color: var(--hx-color-text-primary, #0d1825);\n --hx-toggle-button-border-color: var(--hx-color-border-strong, #66787b);\n }\n\n .button--outline:hover {\n --hx-toggle-button-bg: var(--hx-color-surface-raised, #f5f8f3);\n }\n\n /* ─── Pressed State ─── */\n\n /*\n * Primary: already uses solid primary bg; pressed deepens to primary-700\n * to give clear visual feedback without introducing a new color.\n *\n * AA fix: text.on-primary (= neutral-900 #0D1825) on primary-700 (#0F6363)\n * = 2.54:1 — fails AA. Pin fg at neutral-0 for the darker pressed fill\n * (neutral-0 on primary-700 = 7.03:1, AAA pass). Mirrors hx-toast\n * precedent (commit 300e21ab0) and hx-button hover treatment.\n * Note: secondary.pressed below uses primary-500 and stays at 5.20:1 —\n * leave it alone.\n */\n .button--primary.button--pressed {\n --hx-toggle-button-bg: var(--hx-toggle-button-pressed-bg, var(--hx-color-primary-700, #0f6363));\n --hx-toggle-button-color: var(\n --hx-toggle-button-pressed-color,\n var(--hx-color-neutral-0, #ffffff)\n );\n --hx-toggle-button-border-color: transparent;\n }\n\n /*\n * Secondary: unpressed is outlined/transparent; pressed fills with primary bg\n * so the state change is immediately legible.\n */\n .button--secondary.button--pressed {\n --hx-toggle-button-bg: var(\n --hx-toggle-button-pressed-bg,\n var(--hx-color-action-primary-bg, #0f7078)\n );\n --hx-toggle-button-color: var(\n --hx-toggle-button-pressed-color,\n var(--hx-color-text-on-primary, #ffffff)\n );\n --hx-toggle-button-border-color: var(--hx-color-action-primary-bg, #0f7078);\n }\n\n /* Tertiary pressed: use primary-100 bg + primary-700 text + border for WCAG 3:1 non-text contrast. */\n .button--tertiary.button--pressed {\n --hx-toggle-button-bg: var(--hx-toggle-button-pressed-bg, var(--hx-color-primary-100, #dbf0f0));\n --hx-toggle-button-color: var(\n --hx-toggle-button-pressed-color,\n var(--hx-color-primary-700, #0f6363)\n );\n --hx-toggle-button-border-color: var(--hx-color-primary-600, #0f7078);\n box-shadow: inset 0 0 0 var(--hx-toggle-button-pressed-ring-width, 1px)\n var(--hx-color-primary-600, #0f7078);\n }\n\n /* Ghost pressed: subtle neutral fill, matching hover behavior as a baseline. */\n .button--ghost.button--pressed {\n --hx-toggle-button-bg: var(--hx-toggle-button-pressed-bg, var(--hx-color-primary-100, #dbf0f0));\n --hx-toggle-button-color: var(\n --hx-toggle-button-pressed-color,\n var(--hx-color-primary-700, #0f6363)\n );\n --hx-toggle-button-border-color: transparent;\n }\n\n /* Outline pressed: fills with a neutral tint, darkens the border, and adds an inset shadow for WCAG 3:1 non-text contrast. */\n .button--outline.button--pressed {\n --hx-toggle-button-bg: var(\n --hx-toggle-button-pressed-bg,\n var(--hx-color-surface-sunken, #ebeee9)\n );\n --hx-toggle-button-color: var(\n --hx-toggle-button-pressed-color,\n var(--hx-color-text-primary, #0d1825)\n );\n --hx-toggle-button-border-color: var(--hx-color-text-muted, #4a5362);\n box-shadow: inset 0 0 0 var(--hx-toggle-button-pressed-ring-width, 1px)\n var(--hx-color-neutral-500, #66787b);\n }\n\n /* ─── Disabled ─── */\n\n .button[disabled] {\n cursor: not-allowed;\n }\n\n /* ─── Prefix / Suffix / Label ─── */\n\n .button__prefix,\n .button__suffix {\n display: inline-flex;\n align-items: center;\n flex-shrink: 0;\n }\n\n .button__label {\n flex: 1 1 auto;\n }\n\n /* ─── Reduced Motion ─── */\n\n @media (prefers-reduced-motion: reduce) {\n .button {\n transition: none;\n }\n }\n\n /* ─── High Contrast Mode (forced-colors) ─── */\n\n @media (forced-colors: active) {\n .button {\n forced-color-adjust: none;\n background-color: var(--hx-toggle-button-fc-bg, ButtonFace);\n color: var(--hx-toggle-button-fc-color, ButtonText);\n border: var(--hx-toggle-button-fc-border-width, 2px) solid\n var(--hx-toggle-button-fc-border-color, ButtonText);\n }\n\n :host(:focus-visible) .button,\n .button:focus-visible {\n outline: var(--hx-toggle-button-fc-focus-ring-width, 3px) solid\n var(--hx-toggle-button-fc-focus-ring-color, Highlight);\n outline-offset: var(--hx-toggle-button-fc-focus-ring-offset, 2px);\n }\n\n .button--pressed {\n background-color: Highlight;\n color: HighlightText;\n border-color: Highlight;\n box-shadow: none;\n }\n\n .button[disabled] {\n background-color: ButtonFace;\n color: GrayText;\n border-color: GrayText;\n opacity: 1;\n }\n\n :host([disabled]) {\n opacity: 1;\n }\n }\n`;\n","import { html, nothing, type PropertyValues } from 'lit';\nimport '../../utilities/document-token-adoption.js';\nimport { customElement, property, query, state } from 'lit/decorators.js';\nimport { classMap } from 'lit/directives/class-map.js';\nimport { ifDefined } from 'lit/directives/if-defined.js';\nimport { HelixElement } from '../../base/index.js';\nimport { helixToggleButtonStyles } from './hx-toggle-button.styles.js';\nimport { forcedColorsInteractive } from '../../styles/forced-colors.js';\nimport {\n installAriaIdrefMirror,\n resolveIdrefTokens,\n supportsIdrefElementReferences,\n type AriaIdrefMirrorHandle,\n} from '../../utils/aria-idref.js';\n\n/** Detail for the hx-toggle event dispatched by hx-toggle-button. */\nexport interface HxToggleDetail {\n pressed: boolean;\n}\n\n/**\n * A two-state toggle button that communicates a pressed/unpressed status to\n * assistive technology via `aria-pressed`. Supports multiple visual variants\n * and sizes, prefix/suffix slots, full ElementInternals form association, and\n * a distinct pressed visual state for every variant.\n *\n * @summary Two-state toggle button with pressed/unpressed ARIA semantics.\n *\n * @tag hx-toggle-button\n *\n * @slot - Default slot for the button label text or content.\n * @slot prefix - Icon or content rendered before the label.\n * @slot suffix - Icon or content rendered after the label.\n *\n * @fires {CustomEvent<{pressed: boolean}>} hx-toggle - Dispatched when the\n * toggle state changes. Not dispatched when the button is disabled.\n *\n * @csspart button - The native `<button>` element.\n * @csspart label - The label text wrapper span.\n * @csspart prefix - The prefix slot container span.\n * @csspart suffix - The suffix slot container span.\n *\n * @cssprop [--hx-toggle-button-bg=var(--hx-color-primary-500)] - Button background color.\n * @cssprop [--hx-toggle-button-color=var(--hx-color-neutral-0)] - Button text color.\n * @cssprop [--hx-toggle-button-border-color=transparent] - Button border color.\n * @cssprop [--hx-toggle-button-border-radius=var(--hx-border-radius-md)] - Button border radius.\n * @cssprop [--hx-toggle-button-font-family=var(--hx-font-family-sans)] - Button font family.\n * @cssprop [--hx-toggle-button-font-weight=var(--hx-font-weight-semibold)] - Button font weight.\n * @cssprop [--hx-toggle-button-focus-ring-color=var(--hx-focus-ring-color)] - Focus ring color.\n * @cssprop [--hx-toggle-button-pressed-bg=var(--hx-color-primary-500)] - Background when pressed (variant-specific fallback applies).\n * @cssprop [--hx-toggle-button-pressed-color=var(--hx-color-neutral-0)] - Text color when pressed (variant-specific fallback applies).\n * @cssprop [--hx-opacity-disabled] - Opacity.\n * @cssprop [--hx-space-2] - Spacing token.\n * @cssprop [--hx-border-width-thin] - Width.\n * @cssprop [--hx-border-radius-md] - CSS custom property.\n * @cssprop [--hx-color-primary-500] - Color.\n * @cssprop [--hx-color-neutral-0] - Color.\n * @cssprop [--hx-font-family-sans] - Font family.\n * @cssprop [--hx-font-weight-semibold] - Font weight.\n * @cssprop [--hx-line-height-tight] - Line height.\n * @cssprop [--hx-transition-fast] - Transition timing.\n * @cssprop [--hx-focus-ring-width] - Width.\n * @cssprop [--hx-focus-ring-color] - Color.\n * @cssprop [--hx-color-primary-400] - Color.\n * @cssprop [--hx-focus-ring-offset] - CSS custom property.\n * @cssprop [--hx-filter-brightness-hover] - CSS filter.\n * @cssprop [--hx-filter-brightness-active] - CSS filter.\n * @cssprop [--hx-touch-target-min] - Minimum touch target size.\n * @cssprop [--hx-space-1] - Spacing token.\n * @cssprop [--hx-space-3] - Spacing token.\n * @cssprop [--hx-font-size-sm] - Font size.\n * @cssprop [--hx-space-4] - Spacing token.\n * @cssprop [--hx-font-size-md] - Font size.\n * @cssprop [--hx-size-10] - Size token.\n * @cssprop [--hx-space-6] - Spacing token.\n * @cssprop [--hx-font-size-lg] - Font size.\n * @cssprop [--hx-size-12] - Size token.\n * @cssprop [--hx-color-primary-50] - Color.\n * @cssprop [--hx-color-neutral-100] - Color.\n * @cssprop [--hx-color-neutral-900] - Color.\n * @cssprop [--hx-color-neutral-200] - Color.\n * @cssprop [--hx-color-neutral-300] - Color.\n * @cssprop [--hx-color-primary-700] - Color.\n * @cssprop [--hx-color-primary-100] - Color.\n * @cssprop [--hx-color-neutral-50] - Color.\n * @cssprop [--hx-color-neutral-500] - Color.\n */\n@customElement('hx-toggle-button')\nexport class HelixToggleButton extends HelixElement {\n static override styles = [helixToggleButtonStyles, forcedColorsInteractive];\n\n // ─── Form Association ───\n\n /** @internal */\n static override formAssociated = true;\n\n /** @internal */\n @query('slot:not([name])') private _defaultSlot!: HTMLSlotElement | null;\n\n // ─── Public Properties ───\n\n /**\n * Whether the toggle button is in the pressed state.\n * Reflected as an attribute so CSS selectors like `:host([pressed])` work.\n * @attr pressed\n */\n @property({ type: Boolean, reflect: true })\n pressed = false;\n\n /**\n * Visual style variant of the button.\n * @attr variant\n */\n @property({ type: String, reflect: true })\n variant: 'primary' | 'secondary' | 'tertiary' | 'ghost' | 'outline' = 'secondary';\n\n /**\n * Size of the button.\n * @attr hx-size\n */\n @property({ type: String, reflect: true, attribute: 'hx-size' })\n size: 'sm' | 'md' | 'lg' = 'md';\n\n /**\n * Whether the button is disabled. Prevents all interaction and form actions.\n * @attr disabled\n */\n @property({ type: Boolean, reflect: true })\n disabled = false;\n\n /**\n * Form field name submitted via ElementInternals when the button is pressed.\n * @attr name\n */\n @property({ type: String })\n name: string | undefined = undefined;\n\n /**\n * Form field value submitted via ElementInternals when the button is pressed.\n * @attr value\n */\n @property({ type: String })\n value: string | undefined = undefined;\n\n /**\n * Accessible label forwarded to the inner `<button>` as `aria-label`.\n * Required for icon-only toggle buttons where no visible text is present.\n * @attr label\n */\n @property({ type: String })\n label: string | undefined = undefined;\n\n /**\n * When true, the button must be in the pressed state for the form to be submitted.\n * @attr required\n */\n @property({ type: Boolean, reflect: true })\n required = false;\n\n // ─── Form API ───\n\n /** Returns the ValidityState object. */\n override get validity(): ValidityState {\n return this._internals.validity;\n }\n\n /** Returns the current validation message. */\n override get validationMessage(): string {\n return this._internals.validationMessage;\n }\n\n /** Checks whether the button satisfies its constraints. */\n checkValidity(): boolean {\n return this._internals.checkValidity();\n }\n\n /** Reports validity and shows the browser's constraint validation UI. */\n reportValidity(): boolean {\n return this._internals.reportValidity();\n }\n\n /**\n * Handle for the shared IDREF observer. See `installAriaIdrefMirror()`.\n * @internal\n */\n private _ariaMirror: AriaIdrefMirrorHandle | null = null;\n\n /**\n * Default-slot text content captured for use as the host's accessible name\n * when no explicit `label`/`aria-label`/`aria-labelledby` is supplied.\n * Codex round-1 finding #9.\n * @internal\n */\n @state() private _slotLabelText: string = '';\n\n /** No-IDL-ref fallback tokens applied to the inner button. @internal */\n @state() private _fallbackAriaLabelledBy: string | null = null;\n /** @internal */\n @state() private _fallbackAriaDescribedBy: string | null = null;\n /** @internal */\n @state() private _fallbackAriaLabel: string | null = null;\n\n /**\n * Whether the platform supports IDL element references on `ElementInternals`.\n * Drives the render-time branch between the modern path (host is the\n * announced surface, inner button is `aria-hidden + tabindex=-1`) and the\n * fallback path (inner button is the announced surface, host is demoted).\n * Codex round-2 finding #2.\n * @internal\n */\n @state() private _supportsIdrefRefs = true;\n\n /**\n * Tracks whether the host's `tabindex` is managed by the component itself\n * (vs. set explicitly by a consumer). Codex round-14 P2: a consumer-supplied\n * `tabindex` (e.g. roving-tabindex toolbar pattern with `tabindex=\"-1\"`)\n * must survive disabled flips and re-renders. Only re-assert tabindex in\n * `updated()` when the component originally claimed it.\n * @internal\n */\n private _internalTabindexManaged = false;\n\n // ─── Lifecycle ───\n\n override connectedCallback(): void {\n super.connectedCallback();\n // Detect platform support for IDL element references. Codex round-2\n // finding #2: drives the render-time branch between modern (host\n // announced) and fallback (inner button announced) paths.\n this._supportsIdrefRefs = supportsIdrefElementReferences(this._internals);\n // Seed root-independent semantics from the moment of connection so AT\n // sees the toggle role + pressed state before the first paint.\n this._syncHostAriaSemantics();\n // Codex round-1 finding #1: host is the canonical announced surface on\n // modern browsers, so the inner `<button>` is demoted via\n // `aria-hidden + tabindex=-1`.\n // Codex round-2 finding #2: on no-IDL-ref browsers the inner button is\n // the announced surface (it carries native button + aria-pressed), so\n // the host is demoted to `tabindex=-1` and lets the inner button own\n // tab order + activation.\n // Codex round-14 P2: only claim ownership of `tabindex` when no consumer\n // value is present. Consumers using roving-tabindex toolbar patterns\n // must be able to set `tabindex=\"-1\"` on the host without it being\n // clobbered on every disabled flip. Note we still claim ownership when\n // disabled — the initial value is `-1` to keep the host out of tab order\n // and `updated()` re-asserts the appropriate value when disabled flips.\n if (!this.hasAttribute('tabindex')) {\n this._internalTabindexManaged = true;\n const enabledTabIndex = this._supportsIdrefRefs ? '0' : '-1';\n this.setAttribute('tabindex', this.disabled ? '-1' : enabledTabIndex);\n }\n this.addEventListener('keydown', this._handleHostKeyDown);\n this.addEventListener('click', this._handleHostClickRouted);\n this._ariaMirror = installAriaIdrefMirror(this, () => {\n this._syncHostAriaSemantics();\n });\n }\n\n override disconnectedCallback(): void {\n super.disconnectedCallback();\n this.removeEventListener('keydown', this._handleHostKeyDown);\n this.removeEventListener('click', this._handleHostClickRouted);\n // Codex round-13 P2: tear down the assigned-node text observer so a\n // detached host does not receive mutation callbacks from nodes that may\n // outlive it (e.g. lifted out of the slot but kept in the document).\n this._slotTextObserver?.disconnect();\n this._slotTextObserver = null;\n this._ariaMirror?.disconnect();\n this._ariaMirror = null;\n }\n\n /**\n * Host-level keydown handler. Active only on the modern path; on the\n * no-IDL-ref fallback the inner `<button>` owns native Space/Enter\n * activation. Codex round-2 finding #2.\n * @internal\n */\n private _handleHostKeyDown = (e: KeyboardEvent): void => {\n if (this.disabled) return;\n if (!this._supportsIdrefRefs) return;\n if (e.target !== this) return;\n if (e.key === ' ' || e.key === 'Enter') {\n e.preventDefault();\n this._invokeToggle();\n }\n };\n\n /**\n * Host-level click router. The inner `<button>` is `aria-hidden + tabindex=-1`\n * on modern browsers but still receives clicks via mouse activation; toggling\n * is handled by the inner `_handleClick`. Host-level clicks (composed path\n * origin === host) only come from AT activation or programmatic triggers,\n * so we route those to the toggle pipeline.\n *\n * Codex round-2 finding #2: on no-IDL-ref browsers the inner button is the\n * announced surface so this host-level routing is a no-op — AT activation\n * lands on the inner button directly.\n * @internal\n */\n private _handleHostClickRouted = (e: MouseEvent): void => {\n if (this.disabled) return;\n if (!this._supportsIdrefRefs) return;\n // Only fire when the host itself originated the click — inner-button\n // clicks bubble through here too but are handled by `_handleClick`.\n const path = e.composedPath();\n if (path[0] !== this) return;\n this._invokeToggle();\n };\n\n /** @internal */\n private _invokeToggle(): void {\n this.pressed = !this.pressed;\n this._syncFormValue();\n this.dispatchEvent(\n new CustomEvent<{ pressed: boolean }>('hx-toggle', {\n bubbles: true,\n composed: true,\n detail: { pressed: this.pressed },\n }),\n );\n }\n\n /**\n * Moves focus to the announced toggle-button surface. Codex round-1 finding\n * `#1` made the host the canonical focus target on modern engines so AT\n * announces a single widget. Round-7 finding `#9` extends that contract to\n * the no-IDL-ref fallback: when the host is demoted (`tabindex=-1`,\n * role/state cleared on `internals`) the inner `<button>` owns the announced\n * semantics and tab order, so programmatic `focus()` must redirect there —\n * otherwise scripted focus and error recovery land on the demoted host on\n * unsupported engines.\n */\n override focus(options?: FocusOptions): void {\n if (this._supportsIdrefRefs) {\n super.focus(options);\n return;\n }\n this.shadowRoot?.querySelector<HTMLButtonElement>('[part=\"button\"]')?.focus(options);\n }\n\n override firstUpdated(changedProperties: PropertyValues<this>): void {\n super.firstUpdated(changedProperties);\n\n // Track default-slot text content so it can serve as the accessible\n // name when no explicit label is set. Codex round-1 finding #9.\n this._captureSlotLabelText();\n // Codex round-13 P2: also observe in-place text mutations on assigned\n // nodes so framework-driven `Mute` → `Unmute` rewrites refresh the\n // cached label without requiring the consumer to swap the node.\n this._installSlotTextObserver();\n\n if (!this.label) {\n const slot = this._defaultSlot;\n const hasSlotText = slot\n ? slot.assignedNodes({ flatten: true }).some((n) => n.textContent?.trim())\n : false;\n if (!hasSlotText) {\n console.warn(\n '[hx-toggle-button] No accessible label found. Set the `label` attribute or provide slot text content for WCAG 4.1.2 compliance.',\n );\n }\n }\n }\n\n override updated(changedProperties: PropertyValues<this>): void {\n super.updated(changedProperties);\n\n if (\n changedProperties.has('pressed') ||\n changedProperties.has('value') ||\n changedProperties.has('required')\n ) {\n this._syncFormValue();\n }\n\n if (\n changedProperties.has('disabled') ||\n (changedProperties as Map<PropertyKey, unknown>).has('_supportsIdrefRefs')\n ) {\n // Codex round-2 finding #2: align host tabindex with the chosen\n // announced surface. On no-IDL-ref browsers the inner button owns\n // tab order, so re-enabling the host should leave it `tabindex=-1`.\n // Codex round-14 P2: only re-assert when the component owns tabindex.\n // Consumer-managed values (e.g. roving-tabindex toolbar with `-1`) must\n // not be overwritten on disabled flips or supports-flag transitions.\n if (this._internalTabindexManaged) {\n const enabledTabIndex = this._supportsIdrefRefs ? '0' : '-1';\n this.setAttribute('tabindex', this.disabled ? '-1' : enabledTabIndex);\n }\n }\n\n // Host-elevated ARIA semantics — see _syncHostAriaSemantics.\n this._syncHostAriaSemantics();\n }\n\n /**\n * Reads the default slot's flattened text content into `_slotLabelText`.\n * Called from `firstUpdated()` and `slotchange` so host-canonical semantics\n * pick up slotted label text. Codex round-1 finding #9.\n * @internal\n */\n private _captureSlotLabelText(): void {\n const slot = this._defaultSlot;\n if (!slot) {\n this._slotLabelText = '';\n return;\n }\n const text = slot\n .assignedNodes({ flatten: true })\n .map((n) => n.textContent ?? '')\n .join(' ')\n .trim();\n this._slotLabelText = text;\n }\n\n /**\n * Watches assigned default-slot nodes for in-place text mutations so the\n * cached `_slotLabelText` (and thus `internals.ariaLabel`) stays in sync\n * when a framework rewrites textContent of an already-assigned node without\n * replacing it. `slotchange` does NOT fire for those mutations, so a\n * separate observer is required. Codex round-13 P2.\n * @internal\n */\n private _slotTextObserver: MutationObserver | null = null;\n\n /**\n * (Re-)installs the mutation observer over the current set of assigned\n * default-slot nodes. Disconnects any prior observer first so detached\n * nodes stop firing into a torn-down host.\n * @internal\n */\n private _installSlotTextObserver(): void {\n this._slotTextObserver?.disconnect();\n const slot = this._defaultSlot;\n if (!slot) {\n this._slotTextObserver = null;\n return;\n }\n const observer = new MutationObserver(() => {\n this._captureSlotLabelText();\n this._syncHostAriaSemantics();\n });\n slot.assignedNodes({ flatten: true }).forEach((node) => {\n observer.observe(node, {\n characterData: true,\n childList: true,\n subtree: true,\n });\n });\n this._slotTextObserver = observer;\n }\n\n /** @internal */\n private _handleDefaultSlotChange(): void {\n this._captureSlotLabelText();\n this._syncHostAriaSemantics();\n // Re-tune the in-place text observer over the new assigned-node set\n // (codex round-13 P2).\n this._installSlotTextObserver();\n }\n\n /**\n * Mirrors toggle-button semantics onto the host via ElementInternals so that\n * consumer-supplied `aria-label`, `aria-labelledby`, and `aria-describedby`\n * on `<hx-toggle-button>` reach the announced control. The codex aria-group-2\n * finding identified that the inner shadow `<button>` was the only carrier of\n * the toggle role + pressed state, leaving host-level IDREF tokens stranded\n * across the shadow boundary.\n *\n * The shadow `<button>` keeps `aria-pressed`/`aria-label` mirrored for\n * backwards-compat with existing tests and for browsers without IDL element\n * references; the host is the canonical announced surface.\n * @internal\n */\n private _syncHostAriaSemantics(): void {\n const internals = this._internals;\n\n const hostAriaLabel = this.getAttribute('aria-label')?.trim() || '';\n const externalLabelTokens = this.getAttribute('aria-labelledby');\n const externalDescTokens = this.getAttribute('aria-describedby');\n const labelEls = resolveIdrefTokens(this, externalLabelTokens);\n const descEls = resolveIdrefTokens(this, externalDescTokens);\n // Codex round-35 finding (CR major): `aria-labelledby` is only \"effective\"\n // when at least one IDREF resolves. A typo or transiently-missing target\n // must NOT erase the visible label — fall back to label/slot text so a\n // visibly-labeled toggle never becomes unnamed.\n const hasEffectiveLabelledBy = labelEls.length > 0;\n let resolvedLabel: string | null;\n if (hostAriaLabel) {\n resolvedLabel = hostAriaLabel;\n } else if (hasEffectiveLabelledBy) {\n resolvedLabel = null;\n } else if (this.label) {\n resolvedLabel = this.label;\n } else {\n // Codex round-1 finding #9: default-slot text becomes the accessible\n // name when no explicit label is provided. Without this, slotted text\n // never reaches the host's announced surface.\n resolvedLabel = this._slotLabelText || null;\n }\n\n // Codex round-2 finding #2: branch on platform support. Modern path —\n // host carries `role=button` + aria-pressed via ElementInternals.\n // Fallback path — inner native `<button>` is the announced surface; clear\n // host role/state on internals so AT does not double-announce.\n if (this._supportsIdrefRefs) {\n // ─── Modern path ───\n internals.role = 'button';\n internals.ariaPressed = this.pressed ? 'true' : 'false';\n internals.ariaDisabled = this.disabled ? 'true' : 'false';\n // Codex round-1 finding #6: drive aria-invalid from the live ValidityState\n // so a required-but-unpressed toggle is announced as invalid even before\n // any visible affordance renders. `_updateValidity()` calls this method\n // synchronously after every `setValidity()`.\n internals.ariaInvalid = !internals.validity.valid ? 'true' : 'false';\n internals.ariaLabel = resolvedLabel;\n\n type InternalsWithRefs = ElementInternals & {\n ariaLabelledByElements: Element[] | null;\n ariaDescribedByElements: Element[] | null;\n };\n const refsInternals = internals as InternalsWithRefs;\n\n refsInternals.ariaLabelledByElements = hasEffectiveLabelledBy ? labelEls : null;\n refsInternals.ariaDescribedByElements = descEls.length > 0 ? descEls : null;\n // Clear fallbacks when IDL refs are available.\n this._fallbackAriaLabelledBy = null;\n this._fallbackAriaDescribedBy = null;\n this._fallbackAriaLabel = null;\n } else {\n // ─── Fallback path: inner button is the announced surface ───\n // Round-2 finding #2: round-1 set host role/state via internals AND\n // mirrored aria-* onto the `aria-hidden` inner button — making the\n // mirrored attributes inert. The fix is to clear host role/state and\n // let the inner native `<button>` (rendered without aria-hidden, with\n // `tabindex=0`, with aria-pressed) carry semantics natively.\n internals.role = null;\n internals.ariaPressed = null;\n internals.ariaDisabled = null;\n internals.ariaInvalid = null;\n internals.ariaLabel = null;\n\n // Codex round-36 (medium): gate the fallback label tokens on the\n // *effective* labelledby contract. Mirroring broken consumer tokens to\n // the inner button on legacy engines erases the accessible name —\n // exactly the bug the modern path now defends against. When tokens\n // don't resolve, fall through to `_fallbackAriaLabel` (resolvedLabel)\n // so the slot/property still names the announced surface.\n this._fallbackAriaLabelledBy = hasEffectiveLabelledBy ? externalLabelTokens : null;\n this._fallbackAriaDescribedBy = externalDescTokens || null;\n this._fallbackAriaLabel = resolvedLabel;\n }\n }\n\n protected override _onFormReset(): void {\n this.pressed = false;\n }\n\n protected override _onFormStateRestore(\n state: string | File | FormData | null,\n _mode: 'restore' | 'autocomplete',\n ): void {\n this.pressed = typeof state === 'string' && state === 'pressed';\n }\n\n protected override _onFormDisabled(disabled: boolean): void {\n this.disabled = disabled;\n }\n\n // ─── Private Helpers ───\n\n /** @internal */\n private _syncFormValue(): void {\n if (this.pressed && this.value !== undefined) {\n // Pass explicit state 'pressed' so formStateRestoreCallback can reliably detect it.\n this._internals.setFormValue(this.value, 'pressed');\n } else {\n this._internals.setFormValue(null);\n }\n this._updateValidity();\n }\n\n /** @internal */\n private _updateValidity(): void {\n if (this.required && !this.pressed) {\n // Codex round-17 P2: anchor validity UI to the announced surface. On\n // the modern path the host is the canonical announced/focus surface\n // (the inner button is `aria-hidden + tabindex=-1`), so passing the\n // host avoids `reportValidity()` landing focus on a hidden node. On\n // the fallback path the inner button is the announced surface.\n const anchor: HTMLElement | undefined = this._supportsIdrefRefs\n ? this\n : (this.shadowRoot?.querySelector<HTMLElement>('[part=\"button\"]') ?? undefined);\n this._internals.setValidity(\n { valueMissing: true },\n 'Please activate this toggle button.',\n anchor,\n );\n } else {\n this._internals.setValidity({});\n }\n // Codex round-1 finding #6: keep `internals.ariaInvalid` aligned with the\n // current `ValidityState`.\n this._syncHostAriaSemantics();\n }\n\n // ─── Event Handling ───\n\n /** @internal */\n private _handleClick(e: MouseEvent): void {\n if (this.disabled) {\n e.preventDefault();\n e.stopPropagation();\n return;\n }\n\n this.pressed = !this.pressed;\n this._syncFormValue();\n\n /**\n * Dispatched when the toggle state changes.\n * @event hx-toggle\n */\n this.dispatchEvent(\n new CustomEvent<{ pressed: boolean }>('hx-toggle', {\n bubbles: true,\n composed: true,\n detail: { pressed: this.pressed },\n }),\n );\n\n // Codex round-12 P2: on the modern path the host owns role=\"button\" and\n // tabindex=0; the inner <button tabindex=\"-1\"> is aria-hidden. Native\n // click activation on a `<button>` still focuses it, which would leave\n // `document.activeElement` and AT focus on a hidden node. Move focus to\n // the host so the announced surface is also the focus target.\n if (this._supportsIdrefRefs) {\n this.focus();\n }\n }\n\n // ─── Render Helpers ───\n\n /** @internal */\n private _renderInner() {\n return html`\n <span part=\"prefix\" class=\"button__prefix\">\n <slot name=\"prefix\"></slot>\n </span>\n <span part=\"label\" class=\"button__label\">\n <slot @slotchange=${this._handleDefaultSlotChange}></slot>\n </span>\n <span part=\"suffix\" class=\"button__suffix\">\n <slot name=\"suffix\"></slot>\n </span>\n `;\n }\n\n // ─── Render ───\n\n override render() {\n const classes = {\n button: true,\n [`button--${this.variant}`]: true,\n [`button--${this.size}`]: true,\n 'button--pressed': this.pressed,\n };\n\n // Codex round-2 finding #2: branch the inner button on platform support.\n // Modern path — host announced, inner button is `aria-hidden + tabindex=-1`.\n // Fallback path — inner native `<button>` is announced (NO aria-hidden,\n // tabindex=0) so consumer-mirrored aria-* attributes resolve through a\n // visible accessibility-tree node and AT can name + activate it natively.\n const innerIsAnnounced = !this._supportsIdrefRefs;\n const innerTabIndex = innerIsAnnounced && !this.disabled ? '0' : '-1';\n // Round-1 finding #8: on no-IDL-ref browsers mirror host aria tokens onto\n // the inner button so it carries an accessible name. On modern browsers\n // we still mirror `label` onto the inner button for non-AT consumers\n // (testing, devtools) — does not affect announced semantics.\n const innerAriaLabel = this._fallbackAriaLabel ?? this.label ?? undefined;\n const innerAriaLabelledBy = this._fallbackAriaLabelledBy ?? undefined;\n const innerAriaDescribedBy = this._fallbackAriaDescribedBy ?? undefined;\n\n return html`\n <button\n part=\"button\"\n class=${classMap(classes)}\n ?disabled=${this.disabled}\n type=\"button\"\n tabindex=${innerTabIndex}\n aria-pressed=${this.pressed ? 'true' : 'false'}\n aria-label=${ifDefined(innerAriaLabel)}\n aria-labelledby=${ifDefined(innerAriaLabelledBy)}\n aria-describedby=${ifDefined(innerAriaDescribedBy)}\n aria-hidden=${innerIsAnnounced ? nothing : 'true'}\n @click=${this._handleClick}\n >\n ${this._renderInner()}\n </button>\n `;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'hx-toggle-button': HelixToggleButton;\n }\n}\n"],"names":["helixToggleButtonStyles","css","HelixToggleButton","HelixElement","e","supportsIdrefElementReferences","enabledTabIndex","installAriaIdrefMirror","_a","_b","options","changedProperties","slot","n","text","observer","node","internals","hostAriaLabel","externalLabelTokens","externalDescTokens","labelEls","resolveIdrefTokens","descEls","hasEffectiveLabelledBy","resolvedLabel","refsInternals","state","_mode","disabled","anchor","html","classes","innerIsAnnounced","innerTabIndex","innerAriaLabel","innerAriaLabelledBy","innerAriaDescribedBy","classMap","ifDefined","nothing","forcedColorsInteractive","__decorateClass","query","property","customElement"],"mappings":";;;;;;;AAEO,MAAMA,IAA0BC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;;;;ACsFhC,IAAMC,IAAN,cAAgCC,EAAa;AAAA,EAA7C,cAAA;AAAA,UAAA,GAAA,SAAA,GAmBL,KAAA,UAAU,IAOV,KAAA,UAAsE,aAOtE,KAAA,OAA2B,MAO3B,KAAA,WAAW,IAOX,KAAA,OAA2B,QAO3B,KAAA,QAA4B,QAQ5B,KAAA,QAA4B,QAO5B,KAAA,WAAW,IA4BX,KAAQ,cAA4C,MAQ3C,KAAQ,iBAAyB,IAGjC,KAAQ,0BAAyC,MAEjD,KAAQ,2BAA0C,MAElD,KAAQ,qBAAoC,MAU5C,KAAQ,qBAAqB,IAUtC,KAAQ,2BAA2B,IAyDnC,KAAQ,qBAAqB,CAACC,MAA2B;AACvD,MAAI,KAAK,YACJ,KAAK,sBACNA,EAAE,WAAW,SACbA,EAAE,QAAQ,OAAOA,EAAE,QAAQ,aAC7BA,EAAE,eAAA,GACF,KAAK,cAAA;AAAA,IAET,GAcA,KAAQ,yBAAyB,CAACA,MAAwB;AAMxD,MALI,KAAK,YACL,CAAC,KAAK,sBAGGA,EAAE,aAAA,EACN,CAAC,MAAM,QAChB,KAAK,cAAA;AAAA,IACP,GAoHA,KAAQ,oBAA6C;AAAA,EAAA;AAAA;AAAA;AAAA,EArQrD,IAAa,WAA0B;AACrC,WAAO,KAAK,WAAW;AAAA,EACzB;AAAA;AAAA,EAGA,IAAa,oBAA4B;AACvC,WAAO,KAAK,WAAW;AAAA,EACzB;AAAA;AAAA,EAGA,gBAAyB;AACvB,WAAO,KAAK,WAAW,cAAA;AAAA,EACzB;AAAA;AAAA,EAGA,iBAA0B;AACxB,WAAO,KAAK,WAAW,eAAA;AAAA,EACzB;AAAA;AAAA,EA6CS,oBAA0B;AAsBjC,QArBA,MAAM,kBAAA,GAIN,KAAK,qBAAqBC,EAA+B,KAAK,UAAU,GAGxE,KAAK,uBAAA,GAcD,CAAC,KAAK,aAAa,UAAU,GAAG;AAClC,WAAK,2BAA2B;AAChC,YAAMC,IAAkB,KAAK,qBAAqB,MAAM;AACxD,WAAK,aAAa,YAAY,KAAK,WAAW,OAAOA,CAAe;AAAA,IACtE;AACA,SAAK,iBAAiB,WAAW,KAAK,kBAAkB,GACxD,KAAK,iBAAiB,SAAS,KAAK,sBAAsB,GAC1D,KAAK,cAAcC,EAAuB,MAAM,MAAM;AACpD,WAAK,uBAAA;AAAA,IACP,CAAC;AAAA,EACH;AAAA,EAES,uBAA6B;;AACpC,UAAM,qBAAA,GACN,KAAK,oBAAoB,WAAW,KAAK,kBAAkB,GAC3D,KAAK,oBAAoB,SAAS,KAAK,sBAAsB,IAI7DC,IAAA,KAAK,sBAAL,QAAAA,EAAwB,cACxB,KAAK,oBAAoB,OACzBC,IAAA,KAAK,gBAAL,QAAAA,EAAkB,cAClB,KAAK,cAAc;AAAA,EACrB;AAAA;AAAA,EAyCQ,gBAAsB;AAC5B,SAAK,UAAU,CAAC,KAAK,SACrB,KAAK,eAAA,GACL,KAAK;AAAA,MACH,IAAI,YAAkC,aAAa;AAAA,QACjD,SAAS;AAAA,QACT,UAAU;AAAA,QACV,QAAQ,EAAE,SAAS,KAAK,QAAA;AAAA,MAAQ,CACjC;AAAA,IAAA;AAAA,EAEL;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYS,MAAMC,GAA8B;;AAC3C,QAAI,KAAK,oBAAoB;AAC3B,YAAM,MAAMA,CAAO;AACnB;AAAA,IACF;AACA,KAAAD,KAAAD,IAAA,KAAK,eAAL,gBAAAA,EAAiB,cAAiC,uBAAlD,QAAAC,EAAsE,MAAMC;AAAA,EAC9E;AAAA,EAES,aAAaC,GAA+C;AAWnE,QAVA,MAAM,aAAaA,CAAiB,GAIpC,KAAK,sBAAA,GAIL,KAAK,yBAAA,GAED,CAAC,KAAK,OAAO;AACf,YAAMC,IAAO,KAAK;AAIlB,OAHoBA,IAChBA,EAAK,cAAc,EAAE,SAAS,GAAA,CAAM,EAAE,KAAK,CAACC,MAAA;;AAAM,gBAAAL,IAAAK,EAAE,gBAAF,gBAAAL,EAAe;AAAA,OAAM,IACvE,OAEF,QAAQ;AAAA,QACN;AAAA,MAAA;AAAA,IAGN;AAAA,EACF;AAAA,EAES,QAAQG,GAA+C;AAW9D,QAVA,MAAM,QAAQA,CAAiB,IAG7BA,EAAkB,IAAI,SAAS,KAC/BA,EAAkB,IAAI,OAAO,KAC7BA,EAAkB,IAAI,UAAU,MAEhC,KAAK,eAAA,IAILA,EAAkB,IAAI,UAAU,KAC/BA,EAAgD,IAAI,oBAAoB,MAQrE,KAAK,0BAA0B;AACjC,YAAML,IAAkB,KAAK,qBAAqB,MAAM;AACxD,WAAK,aAAa,YAAY,KAAK,WAAW,OAAOA,CAAe;AAAA,IACtE;AAIF,SAAK,uBAAA;AAAA,EACP;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQQ,wBAA8B;AACpC,UAAMM,IAAO,KAAK;AAClB,QAAI,CAACA,GAAM;AACT,WAAK,iBAAiB;AACtB;AAAA,IACF;AACA,UAAME,IAAOF,EACV,cAAc,EAAE,SAAS,GAAA,CAAM,EAC/B,IAAI,CAACC,MAAMA,EAAE,eAAe,EAAE,EAC9B,KAAK,GAAG,EACR,KAAA;AACH,SAAK,iBAAiBC;AAAA,EACxB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAkBQ,2BAAiC;;AACvC,KAAAN,IAAA,KAAK,sBAAL,QAAAA,EAAwB;AACxB,UAAMI,IAAO,KAAK;AAClB,QAAI,CAACA,GAAM;AACT,WAAK,oBAAoB;AACzB;AAAA,IACF;AACA,UAAMG,IAAW,IAAI,iBAAiB,MAAM;AAC1C,WAAK,sBAAA,GACL,KAAK,uBAAA;AAAA,IACP,CAAC;AACD,IAAAH,EAAK,cAAc,EAAE,SAAS,GAAA,CAAM,EAAE,QAAQ,CAACI,MAAS;AACtD,MAAAD,EAAS,QAAQC,GAAM;AAAA,QACrB,eAAe;AAAA,QACf,WAAW;AAAA,QACX,SAAS;AAAA,MAAA,CACV;AAAA,IACH,CAAC,GACD,KAAK,oBAAoBD;AAAA,EAC3B;AAAA;AAAA,EAGQ,2BAAiC;AACvC,SAAK,sBAAA,GACL,KAAK,uBAAA,GAGL,KAAK,yBAAA;AAAA,EACP;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAeQ,yBAA+B;;AACrC,UAAME,IAAY,KAAK,YAEjBC,MAAgBV,IAAA,KAAK,aAAa,YAAY,MAA9B,gBAAAA,EAAiC,WAAU,IAC3DW,IAAsB,KAAK,aAAa,iBAAiB,GACzDC,IAAqB,KAAK,aAAa,kBAAkB,GACzDC,IAAWC,EAAmB,MAAMH,CAAmB,GACvDI,IAAUD,EAAmB,MAAMF,CAAkB,GAKrDI,IAAyBH,EAAS,SAAS;AACjD,QAAII;AAkBJ,QAjBIP,IACFO,IAAgBP,IACPM,IACTC,IAAgB,OACP,KAAK,QACdA,IAAgB,KAAK,QAKrBA,IAAgB,KAAK,kBAAkB,MAOrC,KAAK,oBAAoB;AAE3B,MAAAR,EAAU,OAAO,UACjBA,EAAU,cAAc,KAAK,UAAU,SAAS,SAChDA,EAAU,eAAe,KAAK,WAAW,SAAS,SAKlDA,EAAU,cAAeA,EAAU,SAAS,QAAiB,UAAT,QACpDA,EAAU,YAAYQ;AAMtB,YAAMC,IAAgBT;AAEtB,MAAAS,EAAc,yBAAyBF,IAAyBH,IAAW,MAC3EK,EAAc,0BAA0BH,EAAQ,SAAS,IAAIA,IAAU,MAEvE,KAAK,0BAA0B,MAC/B,KAAK,2BAA2B,MAChC,KAAK,qBAAqB;AAAA,IAC5B;AAOE,MAAAN,EAAU,OAAO,MACjBA,EAAU,cAAc,MACxBA,EAAU,eAAe,MACzBA,EAAU,cAAc,MACxBA,EAAU,YAAY,MAQtB,KAAK,0BAA0BO,IAAyBL,IAAsB,MAC9E,KAAK,2BAA2BC,KAAsB,MACtD,KAAK,qBAAqBK;AAAA,EAE9B;AAAA,EAEmB,eAAqB;AACtC,SAAK,UAAU;AAAA,EACjB;AAAA,EAEmB,oBACjBE,GACAC,GACM;AACN,SAAK,UAAU,OAAOD,KAAU,YAAYA,MAAU;AAAA,EACxD;AAAA,EAEmB,gBAAgBE,GAAyB;AAC1D,SAAK,WAAWA;AAAA,EAClB;AAAA;AAAA;AAAA,EAKQ,iBAAuB;AAC7B,IAAI,KAAK,WAAW,KAAK,UAAU,SAEjC,KAAK,WAAW,aAAa,KAAK,OAAO,SAAS,IAElD,KAAK,WAAW,aAAa,IAAI,GAEnC,KAAK,gBAAA;AAAA,EACP;AAAA;AAAA,EAGQ,kBAAwB;;AAC9B,QAAI,KAAK,YAAY,CAAC,KAAK,SAAS;AAMlC,YAAMC,IAAkC,KAAK,qBACzC,SACCtB,IAAA,KAAK,eAAL,gBAAAA,EAAiB,cAA2B,uBAAsB;AACvE,WAAK,WAAW;AAAA,QACd,EAAE,cAAc,GAAA;AAAA,QAChB;AAAA,QACAsB;AAAA,MAAA;AAAA,IAEJ;AACE,WAAK,WAAW,YAAY,EAAE;AAIhC,SAAK,uBAAA;AAAA,EACP;AAAA;AAAA;AAAA,EAKQ,aAAa1B,GAAqB;AACxC,QAAI,KAAK,UAAU;AACjB,MAAAA,EAAE,eAAA,GACFA,EAAE,gBAAA;AACF;AAAA,IACF;AAEA,SAAK,UAAU,CAAC,KAAK,SACrB,KAAK,eAAA,GAML,KAAK;AAAA,MACH,IAAI,YAAkC,aAAa;AAAA,QACjD,SAAS;AAAA,QACT,UAAU;AAAA,QACV,QAAQ,EAAE,SAAS,KAAK,QAAA;AAAA,MAAQ,CACjC;AAAA,IAAA,GAQC,KAAK,sBACP,KAAK,MAAA;AAAA,EAET;AAAA;AAAA;AAAA,EAKQ,eAAe;AACrB,WAAO2B;AAAA;AAAA;AAAA;AAAA;AAAA,4BAKiB,KAAK,wBAAwB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAMvD;AAAA;AAAA,EAIS,SAAS;AAChB,UAAMC,IAAU;AAAA,MACd,QAAQ;AAAA,MACR,CAAC,WAAW,KAAK,OAAO,EAAE,GAAG;AAAA,MAC7B,CAAC,WAAW,KAAK,IAAI,EAAE,GAAG;AAAA,MAC1B,mBAAmB,KAAK;AAAA,IAAA,GAQpBC,IAAmB,CAAC,KAAK,oBACzBC,IAAgBD,KAAoB,CAAC,KAAK,WAAW,MAAM,MAK3DE,IAAiB,KAAK,sBAAsB,KAAK,SAAS,QAC1DC,IAAsB,KAAK,2BAA2B,QACtDC,IAAuB,KAAK,4BAA4B;AAE9D,WAAON;AAAA;AAAA;AAAA,gBAGKO,EAASN,CAAO,CAAC;AAAA,oBACb,KAAK,QAAQ;AAAA;AAAA,mBAEdE,CAAa;AAAA,uBACT,KAAK,UAAU,SAAS,OAAO;AAAA,qBACjCK,EAAUJ,CAAc,CAAC;AAAA,0BACpBI,EAAUH,CAAmB,CAAC;AAAA,2BAC7BG,EAAUF,CAAoB,CAAC;AAAA,sBACpCJ,IAAmBO,IAAU,MAAM;AAAA,iBACxC,KAAK,YAAY;AAAA;AAAA,UAExB,KAAK,cAAc;AAAA;AAAA;AAAA,EAG3B;AACF;AArmBatC,EACK,SAAS,CAACF,GAAyByC,CAAuB;AAD/DvC,EAMK,iBAAiB;AAGEwC,EAAA;AAAA,EAAlCC,EAAM,kBAAkB;AAAA,GATdzC,EASwB,WAAA,gBAAA,CAAA;AAUnCwC,EAAA;AAAA,EADCE,EAAS,EAAE,MAAM,SAAS,SAAS,IAAM;AAAA,GAlB/B1C,EAmBX,WAAA,WAAA,CAAA;AAOAwC,EAAA;AAAA,EADCE,EAAS,EAAE,MAAM,QAAQ,SAAS,IAAM;AAAA,GAzB9B1C,EA0BX,WAAA,WAAA,CAAA;AAOAwC,EAAA;AAAA,EADCE,EAAS,EAAE,MAAM,QAAQ,SAAS,IAAM,WAAW,WAAW;AAAA,GAhCpD1C,EAiCX,WAAA,QAAA,CAAA;AAOAwC,EAAA;AAAA,EADCE,EAAS,EAAE,MAAM,SAAS,SAAS,IAAM;AAAA,GAvC/B1C,EAwCX,WAAA,YAAA,CAAA;AAOAwC,EAAA;AAAA,EADCE,EAAS,EAAE,MAAM,OAAA,CAAQ;AAAA,GA9Cf1C,EA+CX,WAAA,QAAA,CAAA;AAOAwC,EAAA;AAAA,EADCE,EAAS,EAAE,MAAM,OAAA,CAAQ;AAAA,GArDf1C,EAsDX,WAAA,SAAA,CAAA;AAQAwC,EAAA;AAAA,EADCE,EAAS,EAAE,MAAM,OAAA,CAAQ;AAAA,GA7Df1C,EA8DX,WAAA,SAAA,CAAA;AAOAwC,EAAA;AAAA,EADCE,EAAS,EAAE,MAAM,SAAS,SAAS,IAAM;AAAA,GApE/B1C,EAqEX,WAAA,YAAA,CAAA;AAoCiBwC,EAAA;AAAA,EAAhBf,EAAA;AAAM,GAzGIzB,EAyGM,WAAA,kBAAA,CAAA;AAGAwC,EAAA;AAAA,EAAhBf,EAAA;AAAM,GA5GIzB,EA4GM,WAAA,2BAAA,CAAA;AAEAwC,EAAA;AAAA,EAAhBf,EAAA;AAAM,GA9GIzB,EA8GM,WAAA,4BAAA,CAAA;AAEAwC,EAAA;AAAA,EAAhBf,EAAA;AAAM,GAhHIzB,EAgHM,WAAA,sBAAA,CAAA;AAUAwC,EAAA;AAAA,EAAhBf,EAAA;AAAM,GA1HIzB,EA0HM,WAAA,sBAAA,CAAA;AA1HNA,IAANwC,EAAA;AAAA,EADNG,EAAc,kBAAkB;AAAA,GACpB3C,CAAA;"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"hx-tooltip-DVqtKPCD.js","sources":["../../src/components/hx-tooltip/hx-tooltip.styles.ts","../../src/components/hx-tooltip/hx-tooltip.ts"],"sourcesContent":["import { css } from 'lit';\n\n/**\n * hx-tooltip styles.\n *\n * Component-tier tokens with two-level var() fallback:\n * var(--hx-tooltip-{prop}, var(--hx-color-{semantic}, #hex))\n * Inner hex fallbacks track the \"precision cool\" palette (3.2.0):\n * neutral-0 = #FFFFFF, neutral-900 = #0D1825 (surface-inverse anchor).\n */\nexport const helixTooltipStyles = css`\n :host {\n display: inline-block;\n }\n\n .trigger-wrapper {\n display: inline-block;\n }\n\n [part='tooltip'] {\n position: fixed;\n z-index: var(--hx-tooltip-z-index, var(--hx-z-index-tooltip, 1600));\n max-width: var(--hx-tooltip-max-width, 280px);\n padding: var(--hx-tooltip-padding, var(--hx-space-1, 0.25rem) var(--hx-space-2, 0.5rem));\n background: var(--hx-tooltip-bg, var(--hx-color-surface-inverse, #0d1825));\n color: var(--hx-tooltip-color, var(--hx-color-text-inverse, #ffffff));\n font-family: var(--hx-tooltip-font-family, var(--hx-font-family-sans, sans-serif));\n font-size: var(--hx-tooltip-font-size, var(--hx-font-size-xs, 0.75rem));\n line-height: var(--hx-line-height-normal, 1.5);\n border-radius: var(--hx-tooltip-border-radius, var(--hx-border-radius-sm, 0.25rem));\n box-shadow: var(\n --hx-tooltip-shadow,\n var(--hx-shadow-sm, 0 2px 8px var(--hx-overlay-black-20, rgba(0, 0, 0, 0.2)))\n );\n visibility: hidden;\n opacity: 0;\n transition:\n opacity var(--hx-tooltip-transition-duration, var(--hx-transition-fast, 150ms ease)),\n visibility var(--hx-tooltip-transition-duration, var(--hx-transition-fast, 150ms ease));\n overflow-wrap: break-word;\n }\n\n [part='tooltip'].visible {\n visibility: visible;\n opacity: 1;\n }\n\n [part='arrow'] {\n position: absolute;\n width: var(--hx-tooltip-arrow-size, 8px);\n height: var(--hx-tooltip-arrow-size, 8px);\n background: var(--hx-tooltip-bg, var(--hx-color-surface-inverse, #0d1825));\n transform: rotate(45deg);\n pointer-events: none;\n }\n\n @media (prefers-reduced-motion: reduce) {\n [part='tooltip'] {\n transition: none;\n }\n }\n\n /* ─── Forced Colors (Windows High Contrast) ─── */\n /* Belt-and-suspenders: rich per-class HC overrides PLUS the forcedColorsSurface mixin. */\n\n @media (forced-colors: active) {\n [part='tooltip'] {\n border: 1px solid CanvasText;\n }\n\n [part='arrow'] {\n border: 1px solid CanvasText;\n }\n }\n`;\n","import { html } from 'lit';\nimport '../../utilities/document-token-adoption.js';\nimport { customElement, property, query, state } from 'lit/decorators.js';\n\nimport { HelixElement, createIdCounter } from '../../base/index.js';\nimport { helixTooltipStyles } from './hx-tooltip.styles.js';\nimport { forcedColorsSurface } from '../../styles/forced-colors.js';\n\nconst _nextTooltipId = createIdCounter('hx-tooltip');\n\n/**\n * A tooltip that displays contextual help text on hover or focus.\n *\n * ## Architecture Note: Light-DOM Description Shim (group-4 round-1)\n *\n * `aria-describedby` IDREFs cannot resolve across the Shadow DOM boundary —\n * the trigger lives in the consumer's light DOM and references a tooltip\n * whose body is in this component's shadow root. The tooltip text must\n * therefore be exposed in DOCUMENT scope.\n *\n * The shim is a single visually-hidden `<span>` appended to `document.body`\n * with the `_tooltipId` as its `id`. The trigger's `aria-describedby` points\n * at this span. The text content is mirrored from the slotted `content`\n * slot on every relevant signal:\n *\n * 1. `firstUpdated` (initial wiring)\n * 2. `slotchange` on the default slot AND the `content` slot (the slotted\n * element list changes)\n * 3. **Text-content mutations on the assigned `content` slot elements**\n * (round-23 P2 pattern). Without this observer a framework that\n * rewrites the slotted `<span slot=\"content\">` `textContent` IN PLACE\n * (Vue / React keyed text rerender) would leave the shim stale.\n *\n * Cleanup: `disconnectedCallback` removes the shim from `document.body`,\n * disconnects the slot-text observer, and clears the timers. SSR is\n * sidestepped by guarding `document` access — the shim is created lazily\n * the first time `_setupTriggerAria()` runs in a browser environment.\n *\n * `role=\"tooltip\"` is the correct APG role and is NEVER promoted to\n * `role=\"dialog\"` — APG explicitly forbids tooltips from holding focus and\n * the tooltip body is not a focus target. No host-canonical `_internals`\n * work is owed: the trigger is the announced surface, and it correctly\n * references the tooltip via `aria-describedby`.\n *\n * @summary Contextual help text and abbreviations with smart positioning.\n *\n * @tag hx-tooltip\n *\n * @slot - Default slot for the trigger element.\n * @slot content - Tooltip content to display.\n *\n * @csspart tooltip - The tooltip container element.\n * @csspart arrow - The arrow indicator element.\n *\n * @cssprop [--hx-tooltip-bg=var(--hx-color-neutral-900)] - Tooltip background color.\n * @cssprop [--hx-tooltip-color=var(--hx-color-neutral-50)] - Tooltip text color.\n * @cssprop [--hx-tooltip-font-size=var(--hx-font-size-xs)] - Tooltip font size.\n * @cssprop [--hx-tooltip-max-width=280px] - Maximum tooltip width.\n * @cssprop [--hx-tooltip-padding] - Tooltip padding.\n * @cssprop [--hx-tooltip-border-radius=var(--hx-border-radius-sm)] - Tooltip border radius.\n * @cssprop [--hx-tooltip-shadow] - Tooltip box shadow.\n * @cssprop [--hx-tooltip-z-index=9999] - Tooltip z-index.\n * @cssprop [--hx-tooltip-transition-duration=0.15s] - Show/hide transition duration.\n * @cssprop [--hx-tooltip-arrow-size=8px] - Size of the arrow indicator.\n *\n * @example\n * ```html\n * <hx-tooltip>\n * <button>Hover me</button>\n * <span slot=\"content\">Helpful context here</span>\n * </hx-tooltip>\n * ```\n *\n * @example Drupal/Twig usage\n * ```twig\n * <hx-tooltip>\n * <button type=\"button\">{{ trigger_label }}</button>\n * <span slot=\"content\">{{ tooltip_text }}</span>\n * </hx-tooltip>\n * ```\n * @cssprop [--hx-tooltip-font-family=var(--hx-font-family-sans)] - CSS custom property.\n * @cssprop [--hx-z-index-tooltip] - Z-index layer.\n * @cssprop [--hx-space-1] - Spacing token.\n * @cssprop [--hx-space-2] - Spacing token.\n * @cssprop [--hx-color-neutral-900] - Color.\n * @cssprop [--hx-color-neutral-50] - Color.\n * @cssprop [--hx-font-family-sans] - Font family.\n * @cssprop [--hx-font-size-xs] - Font size.\n * @cssprop [--hx-line-height-normal] - Line height.\n * @cssprop [--hx-border-radius-sm] - CSS custom property.\n * @cssprop [--hx-shadow-sm] - Box shadow.\n * @cssprop [--hx-overlay-black-20] - Overlay color.\n * @cssprop [--hx-transition-fast] - Transition timing.\n */\n\n@customElement('hx-tooltip')\nexport class HelixTooltip extends HelixElement {\n static override styles = [helixTooltipStyles, forcedColorsSurface];\n\n /**\n * Preferred placement of the tooltip relative to the trigger.\n * Supports all Floating UI placement values including alignment variants\n * (e.g. 'top-start', 'bottom-end') and 'auto'.\n * @attr placement\n */\n @property({ type: String, reflect: true })\n placement:\n | 'top'\n | 'top-start'\n | 'top-end'\n | 'right'\n | 'right-start'\n | 'right-end'\n | 'bottom'\n | 'bottom-start'\n | 'bottom-end'\n | 'left'\n | 'left-start'\n | 'left-end' = 'top';\n\n /**\n * Delay in milliseconds before the tooltip is shown.\n * @attr show-delay\n */\n @property({ type: Number, attribute: 'show-delay' })\n showDelay = 300;\n\n /**\n * Delay in milliseconds before the tooltip is hidden.\n * @attr hide-delay\n */\n @property({ type: Number, attribute: 'hide-delay' })\n hideDelay = 100;\n\n /** @internal */\n @state() private _visible = false;\n\n /** @internal */\n private _showTimer: ReturnType<typeof setTimeout> | null = null;\n /** @internal */\n private _hideTimer: ReturnType<typeof setTimeout> | null = null;\n\n /** @internal */\n private readonly _tooltipId = _nextTooltipId();\n\n /** @internal */\n @query('slot:not([name])') private _defaultSlot!: HTMLSlotElement | null;\n /** @internal */\n @query('slot[name=\"content\"]') private _contentSlot!: HTMLSlotElement | null;\n /** @internal */\n @query('.trigger-wrapper') private _triggerWrapper!: HTMLElement | null;\n /** @internal */\n @query('[part=\"tooltip\"]') private _tooltipEl!: HTMLElement | null;\n /** @internal */\n @query('[part=\"arrow\"]') private _arrowEl!: HTMLElement | null;\n\n /**\n * Visually-hidden description element in light DOM.\n * Necessary because aria-describedby cannot cross Shadow DOM boundaries —\n * ARIA ID references are scoped to the element's root node. This element\n * lives in the document scope so the trigger's aria-describedby resolves correctly.\n * @internal\n */\n private _lightDomDescription: HTMLSpanElement | null = null;\n\n /**\n * Watches in-place text mutations on the elements assigned to the\n * `<slot name=\"content\">`. Without this observer, a framework that\n * rewrites the slotted `<span slot=\"content\">` `textContent` in place\n * would leave the document-scope shim stale — the `slotchange` event\n * does NOT fire on descendant text mutations.\n *\n * The observer is reinstalled on every `_setupTriggerAria()` call against\n * the deduped current set of assigned elements; it is fully torn down in\n * `disconnectedCallback` to prevent leaks on SSR teardown.\n * @internal\n */\n private _contentSlotTextObserver: MutationObserver | null = null;\n\n // ─── Lifecycle ───\n\n override connectedCallback(): void {\n super.connectedCallback();\n this.addEventListener('keydown', this._handleKeydown);\n // Re-run ARIA setup on reconnection (firstUpdated does not re-run).\n // hasUpdated is true after the first update cycle completes.\n if (this.hasUpdated) {\n this._setupTriggerAria();\n }\n }\n\n override disconnectedCallback(): void {\n super.disconnectedCallback();\n this.removeEventListener('keydown', this._handleKeydown);\n this._clearTimers();\n this._lightDomDescription?.remove();\n this._lightDomDescription = null;\n // Round-23 P2: tear down the slotted-content text observer so a\n // disconnect-then-reconnect cycle never leaks observers and the\n // observed light-DOM nodes do not retain a reference to this host.\n this._contentSlotTextObserver?.disconnect();\n this._contentSlotTextObserver = null;\n }\n\n override firstUpdated(): void {\n this._setupTriggerAria();\n }\n\n // ─── ARIA setup ───\n\n /** @internal */\n private _setupTriggerAria(): void {\n const slot = this._defaultSlot;\n if (!slot) return;\n const trigger = slot.assignedElements()[0] as HTMLElement | undefined;\n\n // Sync content from the content slot into a visually-hidden light DOM element.\n // aria-describedby cannot cross Shadow DOM boundaries, so the referenced element\n // must live in the document scope (light DOM), not inside the shadow root.\n const contentSlot = this._contentSlot;\n const contentEls = contentSlot?.assignedElements() ?? [];\n const contentText = contentEls\n .map((el) => el.textContent)\n .join(' ')\n .trim();\n\n // Guard for SSR — document is unavailable server-side\n if (!this._lightDomDescription && typeof document !== 'undefined') {\n this._lightDomDescription = document.createElement('span');\n this._lightDomDescription.id = this._tooltipId;\n // Visually hidden but accessible to screen readers via aria-describedby.\n // Appended to document.body (not this element) so that the ID is in the\n // document scope and resolves correctly across shadow DOM boundaries.\n // Web components must not mutate their own light DOM children.\n this._lightDomDescription.style.cssText =\n 'position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0';\n document.body.appendChild(this._lightDomDescription);\n }\n if (this._lightDomDescription) {\n this._lightDomDescription.textContent = contentText;\n }\n\n if (trigger) {\n trigger.setAttribute('aria-describedby', this._tooltipId);\n }\n\n // Round-23 P2 pattern: observe in-place text mutations on the assigned\n // content elements so a framework-driven `textContent` rewrite re-syncs\n // the document-scope shim. `slotchange` fires only on the assignment\n // list itself, never on descendant text/attribute mutations.\n this._installContentSlotTextObserver(contentEls);\n }\n\n /**\n * (Re-)installs the slotted-content text observer over the deduped union\n * of assigned `content` slot elements. Disconnects any previous observer\n * before re-attaching so observer count is bounded by component lifetime,\n * not by `slotchange` event count.\n * @internal\n */\n private _installContentSlotTextObserver(elements: Element[]): void {\n if (this._contentSlotTextObserver) {\n this._contentSlotTextObserver.disconnect();\n this._contentSlotTextObserver = null;\n }\n if (elements.length === 0) return;\n if (typeof MutationObserver === 'undefined') return;\n const unique = new Set<Element>(elements);\n const observer = new MutationObserver(() => {\n // Re-flatten the current assignment and write the fresh text into the\n // shim. We deliberately do NOT call `_setupTriggerAria()` here — that\n // would reinstall this very observer in a tight loop. The trigger's\n // `aria-describedby` and the shim element are already wired; only the\n // text mirror needs to be refreshed.\n if (!this._lightDomDescription) return;\n const contentSlot = this._contentSlot;\n const fresh =\n contentSlot\n ?.assignedElements()\n .map((el) => el.textContent)\n .join(' ')\n .trim() ?? '';\n if (this._lightDomDescription.textContent !== fresh) {\n this._lightDomDescription.textContent = fresh;\n }\n });\n for (const el of unique) {\n observer.observe(el, {\n characterData: true,\n subtree: true,\n childList: true,\n });\n }\n this._contentSlotTextObserver = observer;\n }\n\n // ─── Show/Hide ───\n\n /** @internal */\n private _scheduleShow(): void {\n this._clearTimers();\n this._showTimer = setTimeout(() => {\n void this._show();\n }, this.showDelay);\n }\n\n /** @internal */\n private _scheduleHide(): void {\n this._clearTimers();\n this._hideTimer = setTimeout(() => {\n this._hide();\n }, this.hideDelay);\n }\n\n /** @internal */\n private async _show(): Promise<void> {\n this._visible = true;\n await this.updateComplete;\n await this._updatePosition();\n }\n\n /** @internal */\n private _hide(): void {\n this._visible = false;\n }\n\n /** @internal */\n private _clearTimers(): void {\n if (this._showTimer !== null) {\n clearTimeout(this._showTimer);\n this._showTimer = null;\n }\n if (this._hideTimer !== null) {\n clearTimeout(this._hideTimer);\n this._hideTimer = null;\n }\n }\n\n // ─── Positioning ───\n\n /** @internal */\n private async _updatePosition(): Promise<void> {\n const reference = this._triggerWrapper;\n const tooltipEl = this._tooltipEl;\n const arrowEl = this._arrowEl;\n\n if (!reference || !tooltipEl || !arrowEl) return;\n\n const { computePosition, flip, shift, offset, arrow } = await import('@floating-ui/dom');\n const { x, y, placement, middlewareData } = await computePosition(reference, tooltipEl, {\n placement: this.placement,\n strategy: 'fixed',\n middleware: [offset(8), flip(), shift({ padding: 8 }), arrow({ element: arrowEl })],\n });\n\n Object.assign(tooltipEl.style, {\n left: `${x}px`,\n top: `${y}px`,\n });\n\n const arrowData = middlewareData.arrow;\n const basePlacement = placement.split('-')[0] ?? 'top';\n const oppositeSide: Record<string, string> = {\n top: 'bottom',\n right: 'left',\n bottom: 'top',\n left: 'right',\n };\n const staticSide = oppositeSide[basePlacement] ?? 'bottom';\n\n // Offset is derived from the arrow element's actual size so that custom\n // --hx-tooltip-arrow-size values position the arrow correctly.\n Object.assign(arrowEl.style, {\n left: arrowData?.x != null ? `${arrowData.x}px` : '',\n top: arrowData?.y != null ? `${arrowData.y}px` : '',\n right: '',\n bottom: '',\n [staticSide]: `${-(arrowEl.offsetWidth / 2)}px`,\n });\n }\n\n // ─── Events ───\n\n /** @internal */\n private _handleKeydown = (e: Event): void => {\n if (!(e instanceof KeyboardEvent)) return;\n if (e.key === 'Escape' && this._visible) {\n this._clearTimers();\n this._hide();\n }\n };\n\n /**\n * Handle mouseleave on the trigger wrapper.\n * Does not schedule hide if keyboard focus is still on the trigger element,\n * preventing mixed keyboard+mouse interactions from dismissing the tooltip\n * while the user is still navigating by keyboard.\n * @internal\n */\n private _handleTriggerMouseleave(): void {\n const slot = this._defaultSlot;\n const trigger = slot?.assignedElements()[0] as HTMLElement | undefined;\n // Guard for SSR — document is unavailable server-side\n const active = typeof document !== 'undefined' ? document.activeElement : null;\n if (trigger && (trigger === active || trigger.contains(active))) {\n return;\n }\n this._scheduleHide();\n }\n\n // ─── Render ───\n\n override render() {\n return html`\n <div\n class=\"trigger-wrapper\"\n @mouseenter=${this._scheduleShow}\n @mouseleave=${this._handleTriggerMouseleave}\n @focusin=${this._scheduleShow}\n @focusout=${this._scheduleHide}\n >\n <slot @slotchange=${this._setupTriggerAria}></slot>\n </div>\n <div\n part=\"tooltip\"\n id=${this._tooltipId}\n role=\"tooltip\"\n aria-hidden=${String(!this._visible)}\n class=${this._visible ? 'visible' : ''}\n @mouseenter=${this._clearTimers}\n @mouseleave=${this._scheduleHide}\n >\n <slot name=\"content\" @slotchange=${this._setupTriggerAria}></slot>\n <div part=\"arrow\"></div>\n </div>\n `;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'hx-tooltip': HelixTooltip;\n }\n}\n"],"names":["helixTooltipStyles","css","_nextTooltipId","createIdCounter","HelixTooltip","HelixElement","e","_a","_b","slot","trigger","contentSlot","contentEls","contentText","el","elements","unique","observer","fresh","reference","tooltipEl","arrowEl","computePosition","flip","shift","offset","arrow","x","y","placement","middlewareData","arrowData","basePlacement","staticSide","active","html","forcedColorsSurface","__decorateClass","property","state","query","customElement"],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"hx-top-nav-DP6OFS8C.js","sources":["../../src/components/hx-top-nav/hx-top-nav.styles.ts","../../src/components/hx-top-nav/hx-top-nav.ts"],"sourcesContent":["import { css } from 'lit';\n\nexport const helixTopNavStyles = css`\n /* ─── Host ─── */\n\n :host {\n display: block;\n }\n\n /* ─── Header wrapper (landmark) ─── */\n\n header {\n display: block;\n margin: 0;\n padding: 0;\n }\n\n /* ─── Sticky mode ─── */\n\n :host([sticky]) .nav {\n position: sticky;\n top: 0;\n /* Fallback 1000 is appropriate for sticky navbars (below modals ~1300, above content) */\n z-index: var(--hx-top-nav-z-index, var(--hx-z-index-sticky, 1000));\n }\n\n /* ─── Nav container ─── */\n\n .nav {\n background-color: var(--hx-top-nav-bg, var(--hx-color-surface-default, #ffffff));\n color: var(--hx-top-nav-color, var(--hx-color-text-strong, #202b39));\n border-bottom: var(--hx-border-width-thin, 1px) solid\n var(--hx-top-nav-border-color, var(--hx-color-border-default, #d6dbd5));\n font-family: var(--hx-top-nav-font-family, var(--hx-font-family-sans, sans-serif));\n }\n\n /* ─── Bar row (always visible) ─── */\n\n .nav__bar {\n display: flex;\n align-items: center;\n min-height: var(--hx-top-nav-height, var(--hx-space-16, 4rem));\n padding-inline: var(--hx-top-nav-padding-x, var(--hx-space-6, 1.5rem));\n gap: var(--hx-space-4, 1rem);\n }\n\n /* ─── Logo ─── */\n\n .nav__logo {\n display: flex;\n align-items: center;\n flex-shrink: 0;\n }\n\n /* ─── Mobile toggle (hamburger) ─── */\n\n .mobile-toggle {\n display: flex;\n align-items: center;\n justify-content: center;\n margin-inline-start: auto;\n /* var(--hx-space-3, 0.75rem) padding + 24px icon = 48×48px touch target (exceeds WCAG 2.5.5 44×44px) */\n padding: var(--hx-space-3, 0.75rem);\n background: transparent;\n border: none;\n border-radius: var(--hx-border-radius-sm, 0.25rem);\n color: var(--hx-top-nav-toggle-color, var(--hx-color-text-strong, #202b39));\n cursor: pointer;\n line-height: 0;\n }\n\n .mobile-toggle:hover {\n background: var(--hx-top-nav-toggle-hover-bg, var(--hx-color-surface-sunken, #ebeee9));\n }\n\n .mobile-toggle:focus-visible {\n outline: var(--hx-focus-ring-width, 2px) solid\n var(--hx-top-nav-focus-ring-color, var(--hx-focus-ring-color, #0f7078));\n outline-offset: var(--hx-focus-ring-offset, 2px);\n }\n\n .mobile-toggle__icon {\n width: var(--hx-space-6, 1.5rem);\n height: var(--hx-space-6, 1.5rem);\n }\n\n /* ─── Collapsible panel (mobile) ─── */\n\n .nav__collapsible {\n display: none;\n flex-direction: column;\n width: 100%;\n padding-block: var(--hx-space-3, 0.75rem);\n border-top: var(--hx-border-width-thin, 1px) solid\n var(--hx-top-nav-border-color, var(--hx-color-border-default, #d6dbd5));\n }\n\n .nav__collapsible--open {\n display: flex;\n animation: hx-mobile-nav-open var(--hx-duration-fast, 100ms) ease-out;\n }\n\n /* ─── Menu and actions in collapsible (mobile) ─── */\n\n .nav__menu,\n .nav__actions {\n display: flex;\n flex-direction: column;\n gap: var(--hx-space-1, 0.25rem);\n padding-inline: var(--hx-top-nav-padding-x, var(--hx-space-6, 1.5rem));\n }\n\n .nav__actions {\n margin-top: var(--hx-space-3, 0.75rem);\n padding-top: var(--hx-space-3, 0.75rem);\n border-top: var(--hx-border-width-thin, 1px) solid\n var(--hx-top-nav-border-color, var(--hx-color-border-default, #d6dbd5));\n }\n\n /* ─── Desktop breakpoint ─── */\n\n /* NOTE: CSS @media queries do not support custom properties.\n This value corresponds to --hx-breakpoint-md (768px). */\n @media (min-width: 768px) {\n /* Make nav a flex row so bar and collapsible sit side-by-side */\n .nav {\n display: flex;\n align-items: center;\n padding-inline: var(--hx-top-nav-padding-x, var(--hx-space-6, 1.5rem));\n }\n\n .nav__bar {\n flex-shrink: 0;\n padding-inline: 0;\n min-height: var(--hx-top-nav-height, var(--hx-space-16, 4rem));\n }\n\n /* Hide hamburger on desktop */\n .mobile-toggle {\n display: none;\n }\n\n /* Collapsible becomes a standard inline flex row */\n .nav__collapsible {\n display: flex;\n flex-direction: row;\n align-items: center;\n flex: 1;\n padding-block: 0;\n border-top: none;\n margin-inline-start: auto;\n gap: var(--hx-space-4, 1rem);\n animation: none;\n }\n\n /* Override open modifier — always visible on desktop regardless of state */\n .nav__collapsible--open {\n display: flex;\n animation: none;\n }\n\n /* Menu grows to fill available space */\n .nav__menu {\n display: flex;\n flex-direction: row;\n align-items: center;\n gap: var(--hx-space-1, 0.25rem);\n flex: 1;\n padding-inline: 0;\n }\n\n /* Actions sit at the far right */\n .nav__actions {\n display: flex;\n flex-direction: row;\n align-items: center;\n gap: var(--hx-space-2, 0.5rem);\n margin-top: 0;\n padding-top: 0;\n padding-inline: 0;\n border-top: none;\n flex-shrink: 0;\n }\n }\n\n /* ─── Mobile menu open animation ─── */\n\n @keyframes hx-mobile-nav-open {\n from {\n opacity: 0;\n transform: translateY(-0.25rem);\n }\n to {\n opacity: 1;\n transform: translateY(0);\n }\n }\n\n /* ─── Reduced motion ─── */\n\n @media (prefers-reduced-motion: reduce) {\n .nav__collapsible--open {\n animation: none;\n }\n }\n\n /* ─── Forced Colors (Windows High Contrast) ─── */\n\n @media (forced-colors: active) {\n .nav {\n border-bottom-color: CanvasText;\n }\n\n .mobile-toggle {\n color: ButtonText;\n border: 1px solid ButtonText;\n }\n\n .nav__collapsible {\n border-top-color: CanvasText;\n }\n\n .nav__actions {\n border-top-color: CanvasText;\n }\n }\n`;\n","import { html, svg } from 'lit';\nimport '../../utilities/document-token-adoption.js';\nimport { customElement, property, state } from 'lit/decorators.js';\nimport { classMap } from 'lit/directives/class-map.js';\nimport { HelixElement } from '../../base/index.js';\nimport { forcedColorsInteractive } from '../../styles/forced-colors.js';\nimport { helixTopNavStyles } from './hx-top-nav.styles.js';\n\n/**\n * Top-of-page site navigation bar with logo, menu items, and utility area.\n * Supports sticky positioning, responsive hamburger menu, and full slot-driven\n * content composition for Drupal and other CMS consumers.\n *\n * @summary Site-level navigation bar with logo, nav items, and action slots.\n *\n * @tag hx-top-nav\n *\n * @slot logo - Brand area rendered on the left side.\n * @slot - Default slot for primary navigation items rendered in the center.\n * IMPORTANT: Do NOT place a `<nav>` element in this slot — the component\n * already renders a `<nav>` landmark internally. Use a `<div>` or bare links.\n * @slot actions - Utility area rendered on the right side (search, user menu, etc.).\n *\n * @fires {CustomEvent<{open: boolean}>} hx-mobile-toggle - Dispatched when the\n * hamburger button is toggled. Detail contains the new open state.\n *\n * @csspart header - The outer `<header>` landmark element.\n * @csspart nav - The `<nav>` element inside the header.\n * @csspart logo - The logo slot container.\n * @csspart menu - The primary navigation slot container.\n * @csspart actions - The actions slot container.\n * @csspart mobile-toggle - The hamburger toggle button.\n *\n * @cssprop [--hx-top-nav-bg=var(--hx-color-neutral-0)] - Navigation bar background color.\n * @cssprop [--hx-top-nav-color=var(--hx-color-neutral-800)] - Navigation bar text color.\n * @cssprop [--hx-top-nav-border-color=var(--hx-color-neutral-200)] - Bottom border color.\n * @cssprop [--hx-top-nav-height=var(--hx-space-16)] - Navigation bar height.\n * @cssprop [--hx-top-nav-padding-x=var(--hx-space-6)] - Horizontal padding.\n * @cssprop [--hx-top-nav-z-index=var(--hx-z-index-sticky)] - Z-index for sticky mode.\n * @cssprop [--hx-top-nav-toggle-color=var(--hx-color-neutral-700)] - Hamburger icon color.\n * @cssprop [--hx-top-nav-font-family=var(--hx-font-family-sans)] - CSS custom property.\n * @cssprop [--hx-z-index-sticky] - Z-index layer.\n * @cssprop [--hx-color-neutral-0] - Color.\n * @cssprop [--hx-color-neutral-800] - Color.\n * @cssprop [--hx-color-neutral-200] - Color.\n * @cssprop [--hx-font-family-sans] - Font family.\n * @cssprop [--hx-space-16] - Spacing token.\n * @cssprop [--hx-space-6] - Spacing token.\n * @cssprop [--hx-space-4] - Spacing token.\n * @cssprop [--hx-space-3] - Spacing token.\n * @cssprop [--hx-border-radius-sm] - CSS custom property.\n * @cssprop [--hx-color-neutral-700] - Color.\n * @cssprop [--hx-color-neutral-100] - Color.\n * @cssprop [--hx-focus-ring-width] - Width.\n * @cssprop [--hx-focus-ring-color] - Color.\n * @cssprop [--hx-color-primary-500] - Color.\n * @cssprop [--hx-focus-ring-offset] - CSS custom property.\n * @cssprop [--hx-duration-fast] - Animation duration.\n * @cssprop [--hx-space-1] - Spacing token.\n * @cssprop [--hx-space-2] - Spacing token.\n * @cssprop [--hx-border-width-thin] - Width.\n */\n@customElement('hx-top-nav')\nexport class HelixTopNav extends HelixElement {\n static override styles = [helixTopNavStyles, forcedColorsInteractive];\n\n // ─── Public Properties ───\n\n /**\n * When true, the navigation bar sticks to the top of the viewport during scroll.\n * @attr sticky\n */\n @property({ type: Boolean, reflect: true })\n sticky = false;\n\n /**\n * Accessible label applied to the `<nav>` element via `aria-label`.\n * @attr label\n */\n @property({ type: String })\n label = 'Site Navigation';\n\n // ─── Private State ───\n\n /** Whether the mobile collapsible menu is currently open. */\n /** @internal */\n @state() private _mobileOpen = false;\n\n // ─── Lifecycle ───\n\n override connectedCallback(): void {\n super.connectedCallback();\n this.addEventListener('keydown', this._handleKeydown);\n }\n\n override disconnectedCallback(): void {\n super.disconnectedCallback();\n this.removeEventListener('keydown', this._handleKeydown);\n }\n\n // ─── Event Handling ───\n\n /** @internal */\n private _handleMobileToggle(): void {\n this._mobileOpen = !this._mobileOpen;\n\n /**\n * Dispatched when the hamburger button is toggled.\n * @event hx-mobile-toggle\n */\n this.dispatchEvent(\n new CustomEvent<{ open: boolean }>('hx-mobile-toggle', {\n bubbles: true,\n composed: true,\n detail: { open: this._mobileOpen },\n }),\n );\n\n if (this._mobileOpen) {\n // Move focus to first truly interactive element in the default slot (WCAG 2.4.3).\n // A plain HTMLElement (e.g. <div>) is not keyboard-reachable; we must find a\n // focusable descendant to avoid trapping focus on a non-interactive node.\n void this.updateComplete.then(() => {\n const FOCUSABLE_SELECTOR = 'a[href], button:not([disabled]), [tabindex=\"0\"]';\n const slot = this.shadowRoot?.querySelector<HTMLSlotElement>('slot:not([name])');\n const assigned = slot?.assignedElements({ flatten: true }) ?? [];\n let firstFocusable: HTMLElement | null = null;\n for (const el of assigned) {\n if (!(el instanceof HTMLElement)) continue;\n if (el.matches(FOCUSABLE_SELECTOR)) {\n firstFocusable = el;\n break;\n }\n const found = el.querySelector<HTMLElement>(FOCUSABLE_SELECTOR);\n if (found) {\n firstFocusable = found;\n break;\n }\n }\n firstFocusable?.focus();\n });\n }\n }\n\n /** @internal */\n private _handleKeydown = (e: KeyboardEvent): void => {\n if (e.key === 'Escape' && this._mobileOpen) {\n this._mobileOpen = false;\n this.dispatchEvent(\n new CustomEvent<{ open: boolean }>('hx-mobile-toggle', {\n bubbles: true,\n composed: true,\n detail: { open: false },\n }),\n );\n // Return focus to the toggle button after Lit re-render completes\n void this.updateComplete.then(() => {\n this.shadowRoot?.querySelector<HTMLButtonElement>('[part=\"mobile-toggle\"]')?.focus();\n });\n }\n };\n\n // ─── Render Helpers ───\n\n /** @internal */\n private _renderHamburgerIcon() {\n return html`\n <svg\n class=\"mobile-toggle__icon\"\n aria-hidden=\"true\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n >\n ${this._mobileOpen\n ? svg`\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\"></line>\n <line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\"></line>\n `\n : svg`\n <line x1=\"3\" y1=\"6\" x2=\"21\" y2=\"6\"></line>\n <line x1=\"3\" y1=\"12\" x2=\"21\" y2=\"12\"></line>\n <line x1=\"3\" y1=\"18\" x2=\"21\" y2=\"18\"></line>\n `}\n </svg>\n `;\n }\n\n // ─── Render ───\n\n override render() {\n const menuClasses = {\n nav__collapsible: true,\n 'nav__collapsible--open': this._mobileOpen,\n };\n\n return html`\n <header part=\"header\">\n <nav part=\"nav\" class=\"nav\" aria-label=${this.label}>\n <div class=\"nav__bar\">\n <div part=\"logo\" class=\"nav__logo\">\n <slot name=\"logo\"></slot>\n </div>\n\n <button\n part=\"mobile-toggle\"\n class=\"mobile-toggle\"\n type=\"button\"\n aria-expanded=${String(this._mobileOpen)}\n aria-controls=\"nav-menu\"\n aria-label=${this._mobileOpen ? 'Close navigation' : 'Open navigation'}\n @click=${this._handleMobileToggle}\n >\n ${this._renderHamburgerIcon()}\n </button>\n </div>\n\n <div id=\"nav-menu\" class=${classMap(menuClasses)}>\n <div part=\"menu\" class=\"nav__menu\">\n <slot></slot>\n </div>\n\n <div part=\"actions\" class=\"nav__actions\">\n <slot name=\"actions\"></slot>\n </div>\n </div>\n </nav>\n </header>\n `;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'hx-top-nav': HelixTopNav;\n }\n}\n"],"names":["helixTopNavStyles","css","HelixTopNav","HelixElement","e","_b","_a","FOCUSABLE_SELECTOR","slot","assigned","firstFocusable","el","found","html","svg","menuClasses","classMap","forcedColorsInteractive","__decorateClass","property","state","customElement"],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"hx-tree-item-CXyspGxI.js","sources":["../../src/components/hx-tree-view/hx-tree-view.styles.ts","../../src/utils/tree-walk.ts","../../src/components/hx-tree-view/hx-tree-view.ts","../../src/components/hx-tree-view/hx-tree-item.styles.ts","../../src/components/hx-tree-view/hx-tree-item.ts"],"sourcesContent":["import { css } from 'lit';\n\nexport const helixTreeViewStyles = css`\n :host {\n display: block;\n contain: layout style;\n font-family: var(--hx-tree-font-family, var(--hx-font-family-sans, sans-serif));\n }\n\n * {\n box-sizing: border-box;\n }\n\n .tree {\n display: block;\n outline: none;\n }\n\n .tree:focus-visible {\n outline: var(--hx-focus-ring-width, 2px) solid var(--hx-focus-ring-color, #0f7078);\n outline-offset: var(--hx-focus-ring-offset, 2px);\n border-radius: var(--hx-border-radius-sm, 0.25rem);\n }\n\n /* ─── High Contrast Mode (forced-colors) ─── */\n\n @media (forced-colors: active) {\n .tree:focus-visible {\n outline: 3px solid Highlight;\n outline-offset: 2px;\n }\n }\n`;\n","/**\n * Composed-tree walkers for the `hx-tree-view` family.\n *\n * Mirrors the `menu-tree.ts` utilities (codex push-gate round-9 extraction\n * for the menu family), but specialized for `hx-tree-view` / `hx-tree-item`\n * where nesting is structural rather than slot-based — child items live in a\n * named `slot=\"children\"` projected into the parent item's shadow root,\n * and any number of nesting levels are legal.\n *\n * Group 5c (codex push-gate round-1 lift): `hx-tree-view`'s host-bound\n * keydown / select handlers receive bubbled events from EVERY descendant\n * tree-item, including ones that legitimately belong to an inner\n * `hx-tree-view`. The same guard pattern that `hx-menu` uses (act only when\n * THIS host is the closest enclosing surface of the dispatching item) is\n * required for trees too. `hx-tree-item._handleClick` /\n * `_handleKeyDown` need to ignore bubbled events from a CHILD `hx-tree-item`\n * — otherwise selecting Child also activates Parent and Enter on Child\n * re-fires Parent's handler.\n *\n * @module\n */\n\n/**\n * Walks the composed tree from `start` outward and returns the closest\n * enclosing `<hx-tree-view>` element, or `null` if none exists. Crosses\n * shadow boundaries (`getRootNode().host`) and slot boundaries\n * (`assignedSlot`) so that an item nested inside a child tree-item — which\n * lives in the parent item's `slot=\"children\"`, projected into the parent's\n * shadow root — resolves to the correct enclosing tree.\n *\n * Returned as `Element` to avoid a circular import between `hx-tree-view`\n * and this util; callers narrow with `instanceof HelixTreeView` if needed.\n *\n * @internal\n */\nexport function findClosestTreeView(start: Element): Element | null {\n let node: Node | null = start;\n while (node) {\n if (node instanceof Element && node.tagName.toLowerCase() === 'hx-tree-view') {\n return node;\n }\n if (node instanceof Element && node.assignedSlot) {\n node = node.assignedSlot;\n continue;\n }\n const parentNode: Node | null = node.parentNode;\n if (parentNode) {\n node = parentNode;\n continue;\n }\n if (node instanceof ShadowRoot) {\n node = node.host;\n continue;\n }\n break;\n }\n return null;\n}\n\n/**\n * Walks the composed tree from `start` outward and returns the closest\n * enclosing `<hx-tree-item>` element, or `null` if none exists. Includes\n * `start` itself when it is an `hx-tree-item`.\n *\n * Used by `hx-tree-item`'s `_isOwnEvent` origin guard: a click or keydown\n * is \"ours\" iff the closest `hx-tree-item` ancestor of the original event\n * target is THIS item (not a child item slotted into our `children` slot).\n * The walk crosses shadow + slot boundaries so a deeply nested child item\n * resolves correctly.\n *\n * Returned as `Element` to avoid a circular import; callers narrow with\n * `instanceof HelixTreeItem` if needed.\n *\n * @internal\n */\nexport function findClosestTreeItem(start: Element): Element | null {\n let node: Node | null = start;\n while (node) {\n if (node instanceof Element && node.tagName.toLowerCase() === 'hx-tree-item') {\n return node;\n }\n if (node instanceof Element && node.assignedSlot) {\n node = node.assignedSlot;\n continue;\n }\n const parentNode: Node | null = node.parentNode;\n if (parentNode) {\n node = parentNode;\n continue;\n }\n if (node instanceof ShadowRoot) {\n node = node.host;\n continue;\n }\n break;\n }\n return null;\n}\n","import { html, nothing, type PropertyValues } from 'lit';\nimport '../../utilities/document-token-adoption.js';\nimport { customElement, property, state } from 'lit/decorators.js';\nimport { HelixElement } from '../../base/index.js';\nimport { helixTreeViewStyles } from './hx-tree-view.styles.js';\nimport { forcedColorsSurface } from '../../styles/forced-colors.js';\nimport type { HelixTreeItem, HxTreeItemSelectDetail } from './hx-tree-item.js';\nimport { devWarn } from '../../utils/dev-warn.js';\nimport {\n installAriaIdrefMirror,\n resolveIdrefTokens,\n supportsIdrefElementReferences,\n type AriaIdrefMirrorHandle,\n} from '../../utils/aria-idref.js';\nimport { flattenAccName } from '../../utils/aria-flatten.js';\nimport { findClosestTreeView } from '../../utils/tree-walk.js';\n\n/** Selection mode for the tree. */\nexport type TreeSelection = 'none' | 'single' | 'multiple';\n\n/** Detail type for the `hx-select` event. */\nexport interface HxSelectDetail {\n /** The tree item that was selected or deselected. */\n item: HelixTreeItem;\n /** Whether the item is now selected. */\n selected: boolean;\n}\n\n/**\n * A hierarchical tree component for navigating nested data structures.\n * Used in healthcare applications for org charts, ICD-10 code hierarchies, and department navigation.\n *\n * Group 5c host-canonical: `role=\"tree\"` lives on the **host** via\n * `_internals.role` on the modern path. The host carries the announced\n * surface so AT walks `<hx-tree-view>` (role=tree) → slotted\n * `<hx-tree-item>` (role=treeitem on host) directly without two layers of\n * indirection. Consumer-supplied `aria-label` / `aria-labelledby` on the\n * host are resolved via the shared IDREF mirror; cross-shadow naming uses\n * `ariaLabelledByElements` (modern) with a flattened-string fallback\n * (legacy). On the legacy fallback path the inner `[role=\"tree\"]` carries\n * the role + accessible name and the host role is suppressed so AT only\n * sees one tree per logical surface (mirrors `hx-menu` round-8).\n *\n * Full keyboard navigation: Arrow keys for movement, Enter/Space for\n * selection, Home/End for first/last item, ArrowRight/Left for\n * expand/collapse + parent/child traversal, typeahead.\n *\n * ## Scale Limits\n *\n * This component renders all tree items simultaneously in the DOM. It is suitable for\n * trees with up to ~500 visible items. For large taxonomies (e.g., ICD-10 with 70,000+\n * codes), use async/lazy loading: only render top-level nodes initially and populate\n * child nodes on `hx-select` or expand events. The component exposes the `expanded`\n * property on `hx-tree-item` for programmatic control of subtrees, enabling consumer-level\n * virtualization strategies without requiring changes to this component.\n *\n * @summary Hierarchical tree view with expand/collapse and keyboard navigation.\n *\n * @tag hx-tree-view\n *\n * @slot - Default slot for hx-tree-item elements.\n *\n * @fires {CustomEvent<HxSelectDetail>} hx-select - Dispatched when a tree item is selected or deselected.\n *\n * @csspart tree - The tree container element with role=\"tree\" (legacy fallback path) or the inner shadow surface (modern path; role lives on the host).\n *\n * @cssprop [--hx-tree-font-family=var(--hx-font-family-sans)] - Tree font family.\n * @cssprop [--hx-font-family-sans] - Font family.\n * @cssprop [--hx-focus-ring-width] - Width.\n * @cssprop [--hx-focus-ring-color] - Color.\n * @cssprop [--hx-color-primary-400] - Color.\n * @cssprop [--hx-focus-ring-offset] - CSS custom property.\n * @cssprop [--hx-border-radius-sm] - CSS custom property.\n */\n@customElement('hx-tree-view')\nexport class HelixTreeView extends HelixElement {\n static override styles = [helixTreeViewStyles, forcedColorsSurface];\n\n // ─── Properties ───\n\n /**\n * Accessible label for the tree. Used as a fallback when no\n * consumer-supplied `aria-label` / `aria-labelledby` is present on the\n * host. On the modern host-canonical path this projects onto\n * `internals.ariaLabel`; on the legacy fallback path it appears as\n * `aria-label` on the inner `[role=\"tree\"]` element.\n * @attr label\n */\n @property({ type: String, reflect: true })\n label = '';\n\n /**\n * Selection mode for the tree.\n * - `none` — items cannot be selected\n * - `single` — only one item can be selected at a time\n * - `multiple` — multiple items can be selected\n * @attr selection\n */\n @property({ type: String, reflect: true })\n selection: 'none' | 'single' | 'multiple' = 'none';\n\n // ─── Internal State ───\n\n /** @internal */\n @state() private _currentIndex = 0;\n\n /** Tracks whether the tree has any visible items, to decide the container tabindex. */\n /** @internal */\n @state() private _hasVisibleItems = false;\n\n // ─── Host-canonical ARIA bookkeeping ───\n\n /**\n * Test seam (codex push-gate round-1 lift from group 5b): when set to\n * `true` or `false`, overrides the platform `supportsIdrefElementReferences`\n * probe before `connectedCallback` seeds `_supportsIdrefRefs`. Mirrors the\n * hx-menu / hx-menu-item / hx-select seam — required so tests can\n * deterministically exercise the legacy fallback render branch.\n *\n * Production code MUST NOT touch this field. It is `static` so the test\n * stub cleanup is global and obvious.\n * @internal\n */\n static __testSupportsIdrefRefsOverride: boolean | null = null;\n\n /** @internal */\n private _supportsIdrefRefs = true;\n\n /** @internal */\n private _ariaMirror: AriaIdrefMirrorHandle | null = null;\n\n /**\n * Resolved accessible name for the tree — the single source of truth read\n * by `_syncHostAriaSemantics()` (modern path: writes to\n * `internals.ariaLabel`) and the fallback `render()` branch (legacy path:\n * writes to inner `div[role=\"tree\"]` `aria-label`). AccName 1.2 §4.3.1\n * precedence: consumer host `aria-labelledby` (resolved + flattened) >\n * consumer host `aria-label` > `label` property > literal \"Tree\".\n * @internal\n */\n private _resolvedAccessibleName = '';\n\n // ─── Visible items cache ───\n\n /**\n * Cached flat list of visible items (depth-first, respects collapsed nodes).\n * Set to null to invalidate; rebuilt on next access.\n * @internal\n */\n private _cachedVisibleItems: HelixTreeItem[] | null = null;\n\n /**\n * Invalidate the visible-items cache. Call after any expand/collapse or structural change.\n * @internal\n */\n private _invalidateVisibleItemsCache(): void {\n this._cachedVisibleItems = null;\n }\n\n // ─── Internal Helpers ───\n\n /**\n * Returns a flat ordered list of all visible (not inside a collapsed item) hx-tree-items\n * in depth-first order. Result is cached; invalidated on expand/collapse/slotchange.\n */\n /** @internal */\n private _getVisibleItems(): HelixTreeItem[] {\n if (!this._cachedVisibleItems) {\n this._cachedVisibleItems = this._collectVisibleItems(this);\n }\n return this._cachedVisibleItems;\n }\n\n /** @internal */\n private _collectVisibleItems(container: Element): HelixTreeItem[] {\n const items: HelixTreeItem[] = [];\n for (const child of Array.from(container.children)) {\n if (child.tagName.toLowerCase() === 'hx-tree-item') {\n const item = child as HelixTreeItem;\n items.push(item);\n if (item.expanded) {\n items.push(...this._collectVisibleItems(item));\n }\n } else {\n items.push(...this._collectVisibleItems(child));\n }\n }\n return items;\n }\n\n /** @internal */\n private _getSelectedItems(): HelixTreeItem[] {\n return Array.from(this.querySelectorAll<HelixTreeItem>('hx-tree-item[selected]'));\n }\n\n /**\n * Updates the roving tabindex across all visible items so that only the\n * item at `activeIndex` has `tabindex=\"0\"`. All others receive `tabindex=\"-1\"`.\n * This is called whenever the active item changes (navigation, initial render).\n */\n /** @internal */\n private _updateRovingTabindex(items: HelixTreeItem[], activeIndex: number): void {\n items.forEach((item, i) => {\n item.setRovingActive(i === activeIndex);\n });\n }\n\n /** @internal */\n private _focusItem(index: number): void {\n const items = this._getVisibleItems();\n if (items.length === 0) return;\n const clamped = Math.max(0, Math.min(index, items.length - 1));\n this._currentIndex = clamped;\n this._updateRovingTabindex(items, clamped);\n items[clamped]?.focus();\n }\n\n // ─── Event Handling ───\n\n /** @internal */\n private _handleTreeItemSelect(e: Event): void {\n if (!(e instanceof CustomEvent)) return;\n const event = e as CustomEvent<HxTreeItemSelectDetail>;\n const item = event.detail.item;\n\n if (this.selection === 'none') return;\n\n if (this.selection === 'single') {\n const wasSelected = item.selected;\n this._getSelectedItems().forEach((i) => {\n i.selected = false;\n });\n item.selected = !wasSelected;\n } else if (this.selection === 'multiple') {\n item.selected = !item.selected;\n }\n\n this.dispatchEvent(\n new CustomEvent<HxSelectDetail>('hx-select', {\n bubbles: true,\n composed: true,\n detail: { item, selected: item.selected },\n }),\n );\n }\n\n /**\n * Codex push-gate round-1 lift (mirrors hx-menu round-7 finding 2):\n * `hx-tree-item-select` bubbles composed through every enclosing\n * `hx-tree-view`. The outer tree would otherwise corrupt `_currentIndex`\n * to `-1` (the bubbled item is not in its top-level list) and re-emit a\n * duplicate `hx-select`. Only act when THIS tree is the closest\n * enclosing tree of the dispatching item.\n * @internal\n */\n private _handleItemSelectHost = (e: Event): void => {\n if (!(e instanceof CustomEvent)) return;\n const detail = (e as CustomEvent<HxTreeItemSelectDetail>).detail;\n const item = detail?.item;\n if (item && findClosestTreeView(item) !== this) {\n return;\n }\n this._handleTreeItemSelect(e);\n };\n\n /** @internal */\n private _handleKeyDown(e: KeyboardEvent): void {\n const items = this._getVisibleItems();\n if (items.length === 0) return;\n\n let currentIndex = this._currentIndex;\n const focused = document.activeElement;\n\n for (let i = 0; i < items.length; i++) {\n if (items[i] === focused || items[i]?.shadowRoot?.activeElement) {\n currentIndex = i;\n break;\n }\n }\n\n switch (e.key) {\n case 'ArrowDown': {\n e.preventDefault();\n // Intentional design: wrap-around from last to first item provides\n // a continuous navigation loop, consistent with the component's\n // circular keyboard navigation model.\n const next = currentIndex < items.length - 1 ? currentIndex + 1 : 0;\n this._focusItem(next);\n break;\n }\n case 'ArrowUp': {\n e.preventDefault();\n // Intentional design: wrap-around from first to last item (see ArrowDown note).\n const prev = currentIndex > 0 ? currentIndex - 1 : items.length - 1;\n this._focusItem(prev);\n break;\n }\n case 'ArrowLeft': {\n e.preventDefault();\n const currentItem = items[currentIndex];\n if (!currentItem) break;\n if (currentItem.disabled) break;\n if (currentItem.expanded && currentItem.hasChildItems) {\n currentItem.expanded = false;\n this._invalidateVisibleItemsCache();\n } else {\n const parentItem = currentItem.parentElement?.closest('hx-tree-item') as\n | HelixTreeItem\n | undefined;\n if (parentItem) {\n const parentIndex = items.indexOf(parentItem);\n if (parentIndex >= 0) {\n this._focusItem(parentIndex);\n }\n }\n }\n break;\n }\n case 'ArrowRight': {\n e.preventDefault();\n const currentItem = items[currentIndex];\n if (!currentItem) break;\n if (currentItem.disabled) break;\n if (currentItem.hasChildItems) {\n if (!currentItem.expanded) {\n currentItem.expanded = true;\n this._invalidateVisibleItemsCache();\n } else {\n this._focusItem(currentIndex + 1);\n }\n }\n break;\n }\n case 'Home': {\n e.preventDefault();\n this._focusItem(0);\n break;\n }\n case 'End': {\n e.preventDefault();\n this._focusItem(items.length - 1);\n break;\n }\n default: {\n // WAI-ARIA APG typeahead: a printable character moves focus to the next visible\n // item whose label starts with that character (case-insensitive).\n if (e.key.length === 1) {\n e.preventDefault();\n const matchIndex = this._findTypeaheadMatch(e.key.toLowerCase(), currentIndex);\n if (matchIndex !== -1) {\n this._focusItem(matchIndex);\n }\n }\n break;\n }\n }\n }\n\n /**\n * Codex push-gate round-1 lift (mirrors hx-menu round-7 finding 1):\n * keydown bound on the host receives events bubbled out of nested\n * tree-views. Without this guard the outer tree would run `_focusItem`\n * over its own top-level items and steal focus back out of the inner\n * tree. Only act when THIS tree is the closest enclosing tree of the\n * keydown target.\n * @internal\n */\n private _handleHostKeyDown = (e: KeyboardEvent): void => {\n const target = e.target;\n if (target instanceof Element && findClosestTreeView(target) !== this) {\n return;\n }\n this._handleKeyDown(e);\n };\n\n /**\n * Finds the next visible item (starting after `currentIndex`, wrapping around) whose\n * label text begins with the given lowercase character. Returns -1 if no match.\n * @internal\n */\n private _findTypeaheadMatch(char: string, currentIndex: number): number {\n const items = this._getVisibleItems();\n if (items.length === 0) return -1;\n for (let i = 1; i <= items.length; i++) {\n const index = (currentIndex + i) % items.length;\n const item = items[index];\n if (item && item.labelText.toLowerCase().startsWith(char)) {\n return index;\n }\n }\n return -1;\n }\n\n /** @internal */\n private _handleFocusIn(e: FocusEvent): void {\n // With roving tabindex, the tree container (tabindex=\"-1\") should only receive\n // focus when the tree is empty. If focus does land on the container (e.g. the\n // tree is empty or programmatic focus), redirect to the active item if present.\n if (e.target === e.currentTarget) {\n const items = this._getVisibleItems();\n if (items.length > 0) {\n this._focusItem(this._currentIndex);\n }\n }\n }\n\n /**\n * Compute and push ARIA position metadata (level, posInSet, setSize, selectable) to all\n * direct hx-tree-item children of a container in a single O(n) pass.\n * Each item also recurses for its own children, building the full tree in O(total-items) total.\n * @internal\n */\n private _updateAriaMetadataForContainer(container: Element, level: number): void {\n const selectable = this.selection === 'single' || this.selection === 'multiple';\n const children = Array.from(container.children).filter(\n (c) => c.tagName.toLowerCase() === 'hx-tree-item',\n ) as HelixTreeItem[];\n const setSize = children.length;\n children.forEach((item, index) => {\n item.setAriaMetadata(level, index + 1, setSize, selectable);\n // Recurse into child items so the full tree is updated in one traversal\n this._updateAriaMetadataForContainer(item, level + 1);\n });\n }\n\n /**\n * Initializes the roving tabindex after items are first slotted in.\n * Ensures the active item (index 0 by default) has tabindex=\"0\" from the start,\n * so a Tab into the tree lands directly on the first item without a redirect.\n * Also updates `_hasVisibleItems` so the container tabindex re-renders correctly.\n * Pushes O(n) ARIA metadata to all items to replace the O(n^2) per-item ancestor walk.\n */\n /** @internal */\n private _handleSlotChange(): void {\n this._invalidateVisibleItemsCache();\n // Push ARIA metadata from parent in a single O(n) traversal\n this._updateAriaMetadataForContainer(this, 1);\n const items = this._getVisibleItems();\n this._hasVisibleItems = items.length > 0;\n if (items.length === 0) return;\n // Clamp _currentIndex in case items were removed.\n const clamped = Math.min(this._currentIndex, items.length - 1);\n this._currentIndex = clamped;\n this._updateRovingTabindex(items, clamped);\n }\n\n // ─── Lifecycle ───\n\n override connectedCallback(): void {\n super.connectedCallback();\n // Honour the static test override so synthetic environments choose the\n // path BEFORE connect runs — the fallback render branch needs to be\n // selected at first paint so the inner `[role=\"tree\"]` carries the\n // resolved accessible name without a mid-life flag flip.\n const ctor = this.constructor as typeof HelixTreeView;\n this._supportsIdrefRefs =\n ctor.__testSupportsIdrefRefsOverride !== null\n ? ctor.__testSupportsIdrefRefsOverride\n : supportsIdrefElementReferences(this._internals);\n // Keydown + select are bound on the HOST so events from focused\n // host-canonical tree-items (which keep keydown out of this tree's\n // shadow DOM on the modern path) still reach the navigation handler.\n // Both handlers carry composed-tree origin guards that ignore events\n // bubbled out of a NESTED `<hx-tree-view>`.\n this.addEventListener('keydown', this._handleHostKeyDown);\n this.addEventListener('hx-tree-item-select', this._handleItemSelectHost);\n // Seed host-canonical semantics so role/label appear before first paint.\n this._syncHostAriaSemantics();\n this._ariaMirror = installAriaIdrefMirror(this, () => {\n this._syncHostAriaSemantics();\n });\n }\n\n override disconnectedCallback(): void {\n super.disconnectedCallback();\n this.removeEventListener('keydown', this._handleHostKeyDown);\n this.removeEventListener('hx-tree-item-select', this._handleItemSelectHost);\n this._ariaMirror?.disconnect();\n this._ariaMirror = null;\n }\n\n override updated(changedProperties: PropertyValues<this>): void {\n super.updated(changedProperties);\n // CodeRabbit MUST-FIX: `selection` change must re-sync host\n // semantics so `aria-multiselectable` reflects the new mode\n // (single → false, multiple → true, none → unset). Previously only\n // `label` triggered the resync, leaving stale aria-multiselectable.\n if (changedProperties.has('label') || changedProperties.has('selection')) {\n this._syncHostAriaSemantics();\n }\n if (changedProperties.has('selection')) {\n // Per-item _selectable flag also depends on the parent's selection\n // mode — recompute the descendants so each hx-tree-item host's\n // `aria-selected` matches the new container contract.\n this._updateAriaMetadataForContainer(this, 1);\n }\n }\n\n override firstUpdated(): void {\n const hasEffectiveLabel =\n this.hasAttribute('aria-label') ||\n this.hasAttribute('aria-labelledby') ||\n Boolean(this.label);\n if (!hasEffectiveLabel) {\n devWarn(\n 'hx-tree-view',\n 'No accessible label provided. Set the `label` attribute, or supply `aria-label` / `aria-labelledby` on hx-tree-view so screen readers can identify this tree (WCAG 4.1.2).',\n );\n }\n }\n\n /**\n * Mirror tree semantics onto the host via ElementInternals so consumer-\n * supplied `aria-label`, `aria-labelledby`, and the `label` property all\n * reach the announced control. Falls back to a flattened-string label on\n * engines that do not implement `ariaLabelledByElements`.\n *\n * Codex push-gate round-1 lift (mirrors hx-menu round-8 finding 1): on\n * the legacy fallback path the inner `<div role=\"tree\" aria-label=\"…\">`\n * is the announced surface. If we ALSO write `internals.role = 'tree'`\n * onto the host, AT sees TWO trees for one logical surface — the\n * duplicate-surface problem host-canonical migration is meant to\n * eliminate. Suppress host role + label writes on the fallback path; the\n * inner element is the canonical announced surface there. Modern path\n * keeps the host as the canonical surface and clears the inner role.\n * @internal\n */\n private _syncHostAriaSemantics(): void {\n const internals = this._internals;\n\n if (!this._supportsIdrefRefs) {\n internals.role = null;\n internals.ariaLabel = null;\n internals.ariaMultiSelectable = null;\n } else {\n internals.role = 'tree';\n internals.ariaMultiSelectable =\n this.selection === 'none' ? null : this.selection === 'multiple' ? 'true' : 'false';\n }\n\n const hostAriaLabel = this.getAttribute('aria-label')?.trim() || '';\n const consumerLabelledBy = this.getAttribute('aria-labelledby');\n const labelEls = resolveIdrefTokens(this, consumerLabelledBy);\n const hasEffectiveLabelledBy = labelEls.length > 0;\n\n type InternalsWithRefs = ElementInternals & {\n ariaLabelledByElements: Element[] | null;\n };\n\n if (this._supportsIdrefRefs) {\n const refsInternals = internals as InternalsWithRefs;\n refsInternals.ariaLabelledByElements = hasEffectiveLabelledBy ? labelEls : null;\n }\n\n // AccName 1.2 §4.3.1 precedence: consumer aria-labelledby (resolved) >\n // consumer aria-label > `label` property > literal \"Tree\" (last-resort).\n let resolved = '';\n if (hasEffectiveLabelledBy) {\n const flattened =\n labelEls\n .map((el) => flattenAccName(el))\n .filter(Boolean)\n .join(' ') ||\n hostAriaLabel ||\n this.label ||\n 'Tree';\n resolved = flattened;\n if (this._supportsIdrefRefs) {\n // Modern path: element refs win; clear ariaLabel so they aren't\n // shadowed by a stale string. Fallback branch reads\n // `_resolvedAccessibleName` for its inner-div mirror — host\n // ariaLabel is already cleared above on the fallback path.\n internals.ariaLabel = null;\n }\n } else if (hostAriaLabel) {\n resolved = hostAriaLabel;\n if (this._supportsIdrefRefs) {\n internals.ariaLabel = hostAriaLabel;\n }\n } else {\n resolved = this.label || 'Tree';\n if (this._supportsIdrefRefs) {\n internals.ariaLabel = resolved;\n }\n }\n\n if (this._resolvedAccessibleName !== resolved) {\n this._resolvedAccessibleName = resolved;\n if (!this._supportsIdrefRefs) {\n this.requestUpdate();\n }\n }\n }\n\n // ─── Render ───\n\n override render() {\n // Roving tabindex pattern (WCAG 2.4.3 Fix):\n // The tree container is NOT a Tab stop (tabindex=\"-1\"). Tab focus goes\n // directly to the active item, which carries tabindex=\"0\". The container\n // is only a landing target (tabindex=\"0\") when the tree is empty.\n const containerTabindex = this._hasVisibleItems ? '-1' : '0';\n\n // Modern host-canonical path: role + aria-label live on the host via\n // `_internals`. The inner div is roleless on the modern path so AT\n // does not see a duplicated container role nested inside the host.\n if (this._supportsIdrefRefs) {\n return html`\n <div part=\"tree\" class=\"tree\" tabindex=${containerTabindex} @focusin=${this._handleFocusIn}>\n <slot @slotchange=${this._handleSlotChange}></slot>\n </div>\n `;\n }\n\n // Legacy fallback: keep role + aria-label on inner div for AT without\n // IDL element-references on ElementInternals. Mirror the resolved\n // accessible name (consumer aria-label / aria-labelledby flatten /\n // `label` property cascade) so menus named via the new host API still\n // announce on legacy engines.\n const fallbackLabel = this._resolvedAccessibleName || this.label || 'Tree';\n return html`\n <div\n part=\"tree\"\n class=\"tree\"\n role=\"tree\"\n tabindex=${containerTabindex}\n aria-label=${fallbackLabel}\n aria-multiselectable=${this.selection === 'none'\n ? nothing\n : this.selection === 'multiple'\n ? 'true'\n : 'false'}\n @focusin=${this._handleFocusIn}\n >\n <slot @slotchange=${this._handleSlotChange}></slot>\n </div>\n `;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'hx-tree-view': HelixTreeView;\n }\n}\n\n/** Canonical type alias for HelixTreeView. Use this when typing hx-tree-view element references. */\nexport type HxTreeView = HelixTreeView;\n","import { css } from 'lit';\n\nexport const helixTreeItemStyles = css`\n :host {\n display: block;\n contain: layout style;\n }\n\n * {\n box-sizing: border-box;\n }\n\n /* ─── Item Container ─── */\n\n .item {\n display: block;\n }\n\n /* ─── Item Row ─── */\n\n .item-row {\n display: flex;\n align-items: center;\n min-height: var(--hx-touch-target-min, 44px);\n gap: var(--hx-tree-item-gap, var(--hx-space-2, 0.5rem));\n padding: var(--hx-tree-item-padding-y, var(--hx-space-2, 0.5rem))\n var(--hx-tree-item-padding-x, var(--hx-space-2, 0.5rem));\n padding-inline-start: calc(\n var(--hx-tree-item-padding-x, var(--hx-space-2, 0.5rem)) + var(--_indent-level, 0) *\n var(--hx-tree-indent-size, 1.5rem)\n );\n border-radius: var(--hx-tree-item-border-radius, var(--hx-border-radius-sm, 0.25rem));\n cursor: pointer;\n outline: none;\n color: var(--hx-tree-item-color, var(--hx-color-neutral-900, #0d1825));\n font-family: var(--hx-tree-item-font-family, var(--hx-font-family-sans, sans-serif));\n font-size: var(--hx-tree-item-font-size, var(--hx-font-size-sm, 0.875rem));\n line-height: var(--hx-line-height-normal, 1.5);\n transition: background-color var(--hx-transition-fast, 150ms ease);\n user-select: none;\n }\n\n .item-row:hover {\n background-color: var(--hx-tree-item-hover-bg, var(--hx-color-neutral-100, #ebeee9));\n }\n\n .item-row:focus-visible {\n outline: var(--hx-focus-ring-width, 2px) solid\n var(--hx-tree-item-focus-ring-color, var(--hx-focus-ring-color, #0f7078));\n outline-offset: var(--hx-focus-ring-offset, -2px);\n }\n\n /* ─── Selected State ─── */\n\n :host([selected]) .item-row {\n background-color: var(--hx-tree-item-selected-bg, var(--hx-color-primary-100, #dbf0f0));\n color: var(--hx-tree-item-selected-color, var(--hx-color-primary-800, #07494a));\n }\n\n :host([selected]) .item-row:hover {\n background-color: var(--hx-tree-item-selected-hover-bg, var(--hx-color-primary-200, #bce1e1));\n }\n\n /* ─── Disabled State ─── */\n\n :host([disabled]) .item-row {\n opacity: var(--hx-opacity-disabled, 0.5);\n cursor: not-allowed;\n pointer-events: none;\n }\n\n /* ─── Expand Icon ─── */\n\n .expand-icon {\n display: flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n width: var(--hx-space-4, 1rem);\n height: var(--hx-space-4, 1rem);\n }\n\n .expand-btn {\n display: flex;\n align-items: center;\n justify-content: center;\n width: var(--hx-space-4, 1rem);\n height: var(--hx-space-4, 1rem);\n padding: 0;\n border: none;\n background: transparent;\n color: var(--hx-tree-item-expand-icon-color, var(--hx-color-neutral-500, #66787b));\n cursor: pointer;\n border-radius: var(--hx-border-radius-sm, 0.25rem);\n transition: transform var(--hx-transition-fast, 150ms ease);\n pointer-events: auto;\n }\n\n .expand-btn:hover {\n background-color: var(\n --hx-tree-item-expand-hover-bg,\n var(--hx-overlay-black-6, rgba(0, 0, 0, 0.06))\n );\n }\n\n .expand-btn:focus-visible {\n outline: var(--hx-focus-ring-width, 2px) solid\n var(--hx-tree-item-focus-ring-color, var(--hx-focus-ring-color, #0f7078));\n outline-offset: var(--hx-focus-ring-offset, 2px);\n }\n\n .expand-btn svg {\n width: var(--hx-space-3, 0.75rem);\n height: var(--hx-space-3, 0.75rem);\n stroke: currentColor;\n fill: none;\n stroke-width: 2;\n stroke-linecap: round;\n stroke-linejoin: round;\n transition: transform var(--hx-transition-fast, 150ms ease);\n }\n\n :host([expanded]) .expand-btn svg {\n transform: rotate(90deg);\n }\n\n .expand-placeholder {\n display: block;\n width: var(--hx-space-4, 1rem);\n flex-shrink: 0;\n }\n\n /* ─── Icon Slot ─── */\n\n .item-icon {\n display: flex;\n align-items: center;\n flex-shrink: 0;\n color: var(--hx-tree-item-icon-color, var(--hx-color-neutral-500, #66787b));\n }\n\n .item-icon:empty {\n display: none;\n }\n\n /* ─── Label ─── */\n\n .item-label {\n flex: 1;\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n }\n\n /* ─── Children (animated) ─── */\n\n .children {\n display: grid;\n grid-template-rows: 0fr;\n transition: grid-template-rows var(--hx-transition-base, 200ms ease);\n --_indent-level: calc(var(--_indent-level, 0) + 1);\n }\n\n .children--expanded {\n grid-template-rows: 1fr;\n }\n\n @media (prefers-reduced-motion: reduce) {\n .item-row,\n .expand-btn,\n .expand-btn svg,\n .children {\n transition: none;\n }\n }\n\n /* ─── Forced Colors (Windows High Contrast) ─── */\n\n @media (forced-colors: active) {\n .item-row:focus-visible {\n outline: 3px solid Highlight;\n outline-offset: -2px;\n }\n\n .expand-btn:focus-visible {\n outline: 3px solid Highlight;\n outline-offset: 2px;\n }\n\n :host([selected]) .item-row {\n outline: 2px solid Highlight;\n }\n }\n\n .children-inner {\n overflow: hidden;\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 { HelixElement } from '../../base/index.js';\nimport { helixTreeItemStyles } from './hx-tree-item.styles.js';\nimport { forcedColorsSurface } from '../../styles/forced-colors.js';\nimport {\n installAriaIdrefMirror,\n resolveIdrefTokens,\n supportsIdrefElementReferences,\n type AriaIdrefMirrorHandle,\n} from '../../utils/aria-idref.js';\nimport { flattenAccName } from '../../utils/aria-flatten.js';\nimport { findClosestTreeItem } from '../../utils/tree-walk.js';\n\n/** Detail type for the `hx-tree-item-select` event. */\nexport interface HxTreeItemSelectDetail {\n /** The tree item that was selected or activated. */\n item: HelixTreeItem;\n}\n\n/**\n * A tree item used within an hx-tree-view component.\n * Supports expand/collapse, selection, keyboard navigation, and icon/children slots.\n *\n * Group 5c host-canonical: `role=\"treeitem\"` lives on the **host** via\n * `_internals.role`. The roving tabindex is written to the host on the\n * modern path so the host is the focusable surface and lands directly\n * under the parent `<hx-tree-view>` (which carries `role=\"tree\"`) in the\n * AT-walked tree. The inner `.item-row` is presentational on the modern\n * path — no role, no aria-* attributes — and carries only click/keyboard\n * event handlers. Keyboard activation (Enter/Space) and expand/collapse\n * (ArrowLeft/Right at the leaf level) are owned by the host's `keydown`\n * handler; ArrowUp/Down/Home/End and typeahead bubble to the parent\n * `<hx-tree-view>` for navigation.\n *\n * The nested `[role=\"group\"]` element that wraps the `slot=\"children\"`\n * stays in the inner shadow DOM regardless of path — that group is a\n * separate sub-surface for the children, not a duplicate of the\n * treeitem role.\n *\n * On the legacy fallback path the inner `.item-row` carries\n * `role=\"treeitem\"` + aria-* state, the host role is suppressed, and the\n * roving tabindex is written to the inner element so there is only ONE\n * focusable surface per item (mirrors hx-menu-item round-8).\n *\n * @summary Individual item within an hx-tree-view hierarchical tree.\n *\n * @tag hx-tree-item\n *\n * @slot - Default slot for the item label content. This text is also used to label the children group.\n * @slot icon - Custom icon shown before the label.\n * @slot children - Nested hx-tree-item elements for sub-tree.\n *\n * @csspart item - The outer item container.\n * @csspart row - The interactive item row (presentational on the modern path; carries role=\"treeitem\" + aria-* on the legacy fallback).\n * @csspart expand-icon - The expand/collapse toggle button.\n * @csspart label - The label text content area.\n * @csspart children - The children container (always carries role=\"group\").\n *\n * @cssprop [--hx-tree-item-color=var(--hx-color-neutral-900)] - Item text color.\n * @cssprop [--hx-tree-item-hover-bg=var(--hx-color-neutral-100)] - Hover background color.\n * @cssprop [--hx-tree-item-selected-bg=var(--hx-color-primary-100)] - Selected background color.\n * @cssprop [--hx-tree-item-selected-color=var(--hx-color-primary-800)] - Selected text color.\n * @cssprop [--hx-tree-item-padding-x=var(--hx-space-2)] - Horizontal padding.\n * @cssprop [--hx-tree-item-padding-y=var(--hx-space-1)] - Vertical padding.\n * @cssprop [--hx-tree-indent-size=1.5rem] - Indentation size per level.\n *\n * @fires {CustomEvent<HxTreeItemSelectDetail>} hx-tree-item-select - Dispatched when this item is clicked or activated via keyboard.\n */\n@customElement('hx-tree-item')\nexport class HelixTreeItem extends HelixElement {\n static override styles = [helixTreeItemStyles, forcedColorsSurface];\n\n /**\n * Test seam (codex push-gate round-1 lift from group 5b): when set to\n * `true` or `false`, overrides the platform `supportsIdrefElementReferences`\n * probe before `connectedCallback` seeds `_supportsIdrefRefs`. Mirrors the\n * hx-menu-item / hx-select seam — required so tests can deterministically\n * exercise the legacy fallback render branch.\n *\n * Production code MUST NOT touch this field. It is `static` so the test\n * stub cleanup is global and obvious.\n * @internal\n */\n static __testSupportsIdrefRefsOverride: boolean | null = null;\n\n // ─── Properties ───\n\n /**\n * Whether the item is expanded (showing children).\n * @attr expanded\n */\n @property({ type: Boolean, reflect: true })\n expanded = false;\n\n /**\n * Whether the item is selected.\n * @attr selected\n */\n @property({ type: Boolean, reflect: true })\n selected = false;\n\n /**\n * Whether the item is disabled (non-interactive).\n * @attr disabled\n */\n @property({ type: Boolean, reflect: true })\n disabled = false;\n\n // ─── Internal State ───\n\n /**\n * Tracks whether any elements are assigned to the children slot, controlling expand icon visibility.\n * @internal\n */\n @state() private _hasChildren = false;\n\n /**\n * Whether this item is the roving-tabindex active item in the tree.\n * @internal\n */\n @state() private _rovingActive = false;\n\n /**\n * Text content from the default slot, used to label the children group for screen readers.\n * @internal\n */\n @state() private _labelText = '';\n\n /**\n * Cached ARIA position metadata. Computed once on connect and on slotchange\n * of the parent container, avoiding repeated DOM traversal on every render.\n * @internal\n */\n @state() private _level = 1;\n /**\n * One-based position of this item within its sibling set, set as aria-posinset.\n * @internal\n */\n @state() private _posInSet = 1;\n /**\n * Total count of sibling hx-tree-item elements at the same level, set as aria-setsize.\n * @internal\n */\n @state() private _setSize = 1;\n /**\n * Whether the owning hx-tree-view supports item selection (single or multiple mode).\n * @internal\n */\n @state() private _selectable = false;\n\n /** @internal */\n @query('.item-row') private _itemRowEl!: HTMLElement | null;\n\n // ─── Host-canonical ARIA bookkeeping ───\n\n /** @internal */\n private _supportsIdrefRefs = true;\n\n /** @internal */\n private _ariaMirror: AriaIdrefMirrorHandle | null = null;\n\n /**\n * Resolved accessible name override for the tree item — read by both\n * `_syncHostAriaSemantics()` (modern path: host `internals.ariaLabel`)\n * and the fallback `render()` branch (legacy path: inner\n * `div[role=\"treeitem\"]` `aria-label`). Empty string means \"no override\"\n * — slotted text content provides the implicit name through the\n * announced surface (host on modern; inner row on fallback). AccName 1.2\n * §4.3.1 precedence: consumer host `aria-labelledby` (flattened) >\n * consumer host `aria-label` > implicit slotted text.\n * @internal\n */\n private _resolvedAccessibleName = '';\n\n // ─── Computed ARIA ───\n\n /**\n * Whether this item has slotted children.\n * @returns True if one or more elements are assigned to the children slot.\n */\n get hasChildItems(): boolean {\n return this._hasChildren;\n }\n\n /**\n * The text content of the item's label slot, used for typeahead keyboard navigation.\n * Returns an empty string until the label slot has been assigned.\n */\n get labelText(): string {\n return this._labelText;\n }\n\n /**\n * Recompute all cached ARIA metadata in a single DOM pass.\n * Called on connect, slotchange, and whenever structural context may change.\n * @internal\n */\n private _updateAriaMetadata(): void {\n // Compute nesting level by counting ancestor hx-tree-item elements.\n let level = 1;\n let el: Element | null = this.parentElement;\n while (el) {\n if (el.tagName.toLowerCase() === 'hx-tree-item') level++;\n el = el.parentElement;\n }\n this._level = level;\n\n // Compute position-in-set and set-size from sibling hx-tree-item elements.\n const parent = this.parentElement;\n if (parent) {\n const siblings = Array.from(parent.children).filter(\n (c) => c.tagName.toLowerCase() === 'hx-tree-item',\n );\n this._posInSet = siblings.indexOf(this) + 1;\n this._setSize = siblings.length;\n } else {\n this._posInSet = 1;\n this._setSize = 1;\n }\n\n // Determine if the owning tree supports selection.\n const tree = this.closest('hx-tree-view');\n if (tree) {\n const selection = tree.getAttribute('selection');\n this._selectable = selection === 'single' || selection === 'multiple';\n } else {\n this._selectable = false;\n }\n }\n\n /**\n * Set ARIA position metadata from the parent hx-tree-view in a single O(n) pass.\n * Calling this avoids the O(n^2) ancestor-walk + sibling-iteration in _updateAriaMetadata\n * when the parent already knows the layout.\n * @internal\n */\n setAriaMetadata(level: number, posInSet: number, setSize: number, selectable: boolean): void {\n this._level = level;\n this._posInSet = posInSet;\n this._setSize = setSize;\n this._selectable = selectable;\n }\n\n // ─── Lifecycle ───\n\n override connectedCallback(): void {\n super.connectedCallback();\n // Honour the static test override so synthetic environments choose the\n // path BEFORE connect runs — the fallback render branch needs to be\n // selected at first paint so role + roving tabindex placement matches a\n // legacy engine for the entire lifecycle.\n const ctor = this.constructor as typeof HelixTreeItem;\n this._supportsIdrefRefs =\n ctor.__testSupportsIdrefRefsOverride !== null\n ? ctor.__testSupportsIdrefRefsOverride\n : supportsIdrefElementReferences(this._internals);\n this._updateAriaMetadata();\n // Click + keydown live on the HOST so the active surface (the host on\n // the modern path; either the host or the inner div in delegating\n // engines) receives events. Origin guards (`_isOwnEvent`) reject events\n // bubbled from a CHILD `hx-tree-item` slotted into our `children`\n // slot — without that, selecting Child also activates Parent.\n this.addEventListener('click', this._handleClick);\n this.addEventListener('keydown', this._handleKeyDown);\n this._syncHostAriaSemantics();\n this._applyHostTabIndex();\n this._ariaMirror = installAriaIdrefMirror(this, () => {\n this._syncHostAriaSemantics();\n });\n }\n\n override disconnectedCallback(): void {\n super.disconnectedCallback();\n this.removeEventListener('click', this._handleClick);\n this.removeEventListener('keydown', this._handleKeyDown);\n this._ariaMirror?.disconnect();\n this._ariaMirror = null;\n }\n\n override updated(changedProperties: PropertyValues<this>): void {\n super.updated(changedProperties);\n if (\n changedProperties.has('disabled') ||\n changedProperties.has('selected') ||\n changedProperties.has('expanded') ||\n (changedProperties as Map<PropertyKey, unknown>).has('_hasChildren') ||\n (changedProperties as Map<PropertyKey, unknown>).has('_selectable') ||\n (changedProperties as Map<PropertyKey, unknown>).has('_level') ||\n (changedProperties as Map<PropertyKey, unknown>).has('_posInSet') ||\n (changedProperties as Map<PropertyKey, unknown>).has('_setSize')\n ) {\n this._syncHostAriaSemantics();\n }\n if (\n (changedProperties as Map<PropertyKey, unknown>).has('_rovingActive') ||\n changedProperties.has('disabled')\n ) {\n this._applyHostTabIndex();\n }\n }\n\n /**\n * Apply the roving tabindex through the right surface for the active\n * path. On the modern host-canonical path the host carries the role +\n * tabindex; on the legacy fallback path the inner `.item-row` carries\n * both via the template, so the host MUST stay out of the tab order to\n * avoid a double-focusable per item (mirrors hx-menu-item round-1\n * finding 3).\n * @internal\n */\n private _applyHostTabIndex(): void {\n if (!this._supportsIdrefRefs) {\n // Fallback path: inner `.item-row` is the focusable surface. Keep\n // the host out of the sequential focus order entirely.\n this.tabIndex = -1;\n return;\n }\n if (this.disabled) {\n this.tabIndex = -1;\n } else {\n this.tabIndex = this._rovingActive ? 0 : -1;\n }\n }\n\n /**\n * Mirror treeitem semantics onto the host via ElementInternals so\n * consumer-supplied `aria-label`, `aria-labelledby`, expand/select state,\n * and tree position all reach the announced control.\n *\n * Codex push-gate round-1 lift (mirrors hx-menu-item round-6 finding 2):\n * on the legacy fallback path the inner `.item-row` already exposes\n * role=\"treeitem\" + aria-* via the template. If we ALSO write those onto\n * the host's ElementInternals, AT sees TWO treeitems for one logical\n * option — the duplicate-surface problem host-canonical migration is\n * meant to eliminate. Suppress all of these state writes on the host\n * when the fallback path is in effect; the inner element is the\n * canonical announced surface.\n * @internal\n */\n private _syncHostAriaSemantics(): void {\n const internals = this._internals;\n\n if (!this._supportsIdrefRefs) {\n internals.role = null;\n internals.ariaLabel = null;\n internals.ariaDisabled = null;\n internals.ariaSelected = null;\n internals.ariaExpanded = null;\n internals.ariaLevel = null;\n internals.ariaPosInSet = null;\n internals.ariaSetSize = null;\n } else {\n internals.role = 'treeitem';\n internals.ariaDisabled = this.disabled ? 'true' : null;\n internals.ariaSelected = this._selectable ? (this.selected ? 'true' : 'false') : null;\n internals.ariaExpanded = this._hasChildren ? (this.expanded ? 'true' : 'false') : null;\n internals.ariaLevel = String(this._level);\n internals.ariaPosInSet = String(this._posInSet);\n internals.ariaSetSize = String(this._setSize);\n }\n\n const hostAriaLabel = this.getAttribute('aria-label')?.trim() || '';\n const consumerLabelledBy = this.getAttribute('aria-labelledby');\n const labelEls = resolveIdrefTokens(this, consumerLabelledBy);\n const hasEffectiveLabelledBy = labelEls.length > 0;\n\n type InternalsWithRefs = ElementInternals & {\n ariaLabelledByElements: Element[] | null;\n };\n\n if (this._supportsIdrefRefs) {\n const refsInternals = internals as InternalsWithRefs;\n refsInternals.ariaLabelledByElements = hasEffectiveLabelledBy ? labelEls : null;\n }\n\n // AccName 1.2 §4.3.1 precedence: consumer aria-labelledby (resolved) >\n // consumer aria-label > implicit slotted text (left to AccName\n // computation through the host's role). When neither override is\n // supplied, ariaLabel is cleared so AT walks slotted children for the\n // accessible name.\n let resolved = '';\n if (hasEffectiveLabelledBy) {\n const flattened =\n labelEls\n .map((el) => flattenAccName(el))\n .filter(Boolean)\n .join(' ') ||\n hostAriaLabel ||\n '';\n resolved = flattened;\n if (this._supportsIdrefRefs) {\n // Modern path: element refs win; clear ariaLabel so they aren't\n // shadowed by a stale string.\n internals.ariaLabel = null;\n } else {\n internals.ariaLabel = flattened || null;\n }\n } else if (hostAriaLabel) {\n resolved = hostAriaLabel;\n internals.ariaLabel = hostAriaLabel;\n } else {\n internals.ariaLabel = null;\n }\n\n if (this._resolvedAccessibleName !== resolved) {\n this._resolvedAccessibleName = resolved;\n if (!this._supportsIdrefRefs) {\n this.requestUpdate();\n }\n }\n }\n\n // ─── Children Detection ───\n\n /**\n * Updates _hasChildren and recomputes ARIA metadata when the children slot assignment changes.\n * @internal\n */\n private _handleChildrenSlotChange(e: Event): void {\n const slot = e.target as HTMLSlotElement;\n this._hasChildren = slot.assignedElements().length > 0;\n this._updateAriaMetadata();\n this._syncHostAriaSemantics();\n }\n\n /**\n * Captures the text content from the default (label) slot for use on the children group label.\n * @internal\n */\n private _handleLabelSlotChange(e: Event): void {\n const slot = e.target as HTMLSlotElement;\n const nodes = slot.assignedNodes({ flatten: true });\n this._labelText = nodes\n .map((n) => n.textContent ?? '')\n .join('')\n .trim();\n }\n\n // ─── Event Handlers ───\n\n /**\n * Origin guard for host-bound click/keydown handlers. Returns `true` only\n * when the event originated on THIS host's surface (its shadow tree or\n * itself) and not on a nested `hx-tree-item` projected into the\n * `children` slot.\n *\n * Codex push-gate round-1 lift (mirrors hx-menu-item round-5 P1):\n * children are slotted descendants in the parent's light DOM. Click/\n * keydown events from a Child item bubble through the parent host's\n * listeners — without this guard, selecting Child also activates\n * Parent (double `hx-tree-item-select`) and Enter/Space on Child\n * re-trigger Parent's handlers.\n *\n * Uses the shared `findClosestTreeItem` walker (composed-tree, crosses\n * shadow + slot boundaries) so the test bed is reused across the\n * tree family. The event is \"ours\" iff the closest `hx-tree-item`\n * ancestor of the original target is `this`.\n * @internal\n */\n private _isOwnEvent(e: Event): boolean {\n const path = e.composedPath();\n for (const node of path) {\n if (!(node instanceof Element)) continue;\n const closest = findClosestTreeItem(node);\n if (closest) {\n return closest === this;\n }\n }\n return false;\n }\n\n /**\n * Toggles the expanded state when the expand/collapse button is clicked, stopping event propagation.\n * @internal\n */\n private _handleExpandClick(e: Event): void {\n e.stopPropagation();\n if (this.disabled) return;\n this.expanded = !this.expanded;\n }\n\n /**\n * Dispatches the hx-tree-item-select event when the item is activated via\n * click or keyboard. The host listens for click; this method is also\n * invoked from the Enter/Space keydown branch.\n * @internal\n */\n private _activate(): void {\n if (this.disabled) return;\n this.dispatchEvent(\n new CustomEvent<HxTreeItemSelectDetail>('hx-tree-item-select', {\n bubbles: true,\n composed: true,\n detail: { item: this },\n }),\n );\n }\n\n /** @internal */\n private _handleClick = (e: MouseEvent): void => {\n // Codex push-gate round-1 lift (mirrors hx-menu-item round-5 P1):\n // clicks on a nested CHILD tree-item bubble through this host. Without\n // an origin guard, both Child and Parent activate.\n if (!this._isOwnEvent(e)) return;\n // CodeRabbit MUST-FIX: a click landing inside our own children\n // container (the `[role=\"group\"]` wrapper around `<slot name=\"children\">`)\n // — i.e. on padding, between child items, on the group itself — also\n // walks back up to THIS host through `_isOwnEvent`. Treat any click\n // sourced from the children group as NOT a row activation.\n const path = e.composedPath();\n for (const node of path) {\n if (!(node instanceof Element)) continue;\n if (node === this) break;\n if (node.getAttribute && node.getAttribute('part') === 'children') return;\n }\n if (this.disabled) {\n e.preventDefault();\n e.stopPropagation();\n return;\n }\n this._activate();\n };\n\n /** @internal */\n private _handleKeyDown = (e: KeyboardEvent): void => {\n // Codex push-gate round-1 lift (mirrors hx-menu-item round-5 P1):\n // Enter / Space / ArrowLeft / ArrowRight at a focused CHILD bubble\n // through this host. Without an origin guard, Parent treats them as\n // its own — double activation, wrong-level expand/collapse.\n if (!this._isOwnEvent(e)) return;\n if (this.disabled) return;\n\n switch (e.key) {\n case 'ArrowRight':\n e.preventDefault();\n if (this._hasChildren && !this.expanded) {\n this.expanded = true;\n }\n break;\n case 'ArrowLeft':\n e.preventDefault();\n if (this._hasChildren && this.expanded) {\n this.expanded = false;\n }\n break;\n case 'Enter':\n case ' ':\n e.preventDefault();\n this._activate();\n break;\n case 'ArrowDown':\n case 'ArrowUp':\n case 'Home':\n case 'End':\n // Bubble up to hx-tree-view for navigation\n break;\n }\n };\n\n // ─── Public API ───\n\n /**\n * Sets the roving tabindex state for this item.\n * When `active` is true, the host (modern) or inner row (fallback) gets\n * `tabindex=\"0\"` making it the Tab-reachable surface in the tree. All\n * other items should be set to false. Called by the parent hx-tree-view\n * to manage the roving tabindex pattern.\n */\n setRovingActive(active: boolean): void {\n this._rovingActive = active;\n this._applyHostTabIndex();\n }\n\n /**\n * Focus this item. On the modern host-canonical path, focus lands on the\n * host (which carries the roving tabindex and announced role). On the\n * legacy fallback path, focus delegates to the inner `.item-row` which\n * still carries the role.\n */\n override focus(options?: FocusOptions): void {\n if (this._supportsIdrefRefs) {\n HTMLElement.prototype.focus.call(this, options);\n } else {\n this._itemRowEl?.focus(options);\n }\n }\n\n // ─── Render ───\n\n /**\n * Renders the expand/collapse chevron button, or a placeholder span when the item has no children.\n * @internal\n */\n private _renderExpandIcon() {\n if (!this._hasChildren) {\n return html`<span class=\"expand-placeholder\" aria-hidden=\"true\"></span>`;\n }\n return html`\n <button\n part=\"expand-icon\"\n class=\"expand-btn\"\n tabindex=\"-1\"\n aria-label=\"${this.expanded ? 'Collapse' : 'Expand'}\"\n @click=${this._handleExpandClick}\n >\n <svg viewBox=\"0 0 16 16\" aria-hidden=\"true\">\n <polyline points=\"6 4 10 8 6 12\" />\n </svg>\n </button>\n `;\n }\n\n override render() {\n // The nested children container always carries role=\"group\" — that is\n // a separate sub-surface for the children, not a duplicate of the\n // treeitem role, and is correct on both the modern and fallback paths.\n const childrenGroup = html`\n <div\n part=\"children\"\n class=${classMap({ children: true, 'children--expanded': this.expanded })}\n role=\"group\"\n aria-label=${this._labelText ? `${this._labelText} children` : 'children'}\n aria-hidden=${!this.expanded || nothing}\n >\n <div class=\"children-inner\">\n <slot name=\"children\" @slotchange=${this._handleChildrenSlotChange}></slot>\n </div>\n </div>\n `;\n\n // Modern host-canonical path: role/aria-* and tabindex live on the\n // host via `_internals` and the `_applyHostTabIndex()` helper. The\n // inner `.item-row` is presentational (no role, no aria-*) and carries\n // only the visual treatment + slot composition. Click + keydown\n // handlers stay on the host (see connectedCallback) so keyboard\n // activation works regardless of which surface is focused.\n if (this._supportsIdrefRefs) {\n return html`\n <div part=\"item\" class=\"item\">\n <div part=\"row\" class=\"item-row\">\n ${this._renderExpandIcon()}\n <span class=\"item-icon\">\n <slot name=\"icon\"></slot>\n </span>\n <span part=\"label\" class=\"item-label\">\n <slot @slotchange=${this._handleLabelSlotChange}></slot>\n </span>\n </div>\n ${childrenGroup}\n </div>\n `;\n }\n\n // Legacy fallback: keep role/aria-* on the inner `.item-row` for AT\n // without IDL element-references on ElementInternals. Click + keydown\n // still listen on the host (see connectedCallback) so behaviour is\n // uniform across paths. The inner element MUST mirror the same\n // accessible name resolved by `_syncHostAriaSemantics()`.\n const fallbackAriaLabel = this._resolvedAccessibleName || nothing;\n const ariaExpanded = this._hasChildren ? String(this.expanded) : nothing;\n const ariaSelected = this._selectable ? String(this.selected) : nothing;\n\n return html`\n <div part=\"item\" class=\"item\">\n <div\n part=\"row\"\n class=\"item-row\"\n role=\"treeitem\"\n tabindex=${this._rovingActive ? '0' : '-1'}\n aria-label=${fallbackAriaLabel}\n aria-expanded=${ariaExpanded}\n aria-selected=${ariaSelected}\n aria-disabled=${this.disabled ? 'true' : nothing}\n aria-level=${this._level}\n aria-posinset=${this._posInSet}\n aria-setsize=${this._setSize}\n >\n ${this._renderExpandIcon()}\n <span class=\"item-icon\">\n <slot name=\"icon\"></slot>\n </span>\n <span part=\"label\" class=\"item-label\">\n <slot @slotchange=${this._handleLabelSlotChange}></slot>\n </span>\n </div>\n ${childrenGroup}\n </div>\n `;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'hx-tree-item': HelixTreeItem;\n }\n}\n\n/** Canonical type alias for HelixTreeItem. Use this when typing hx-tree-item element references. */\nexport type HxTreeItem = HelixTreeItem;\n"],"names":["helixTreeViewStyles","css","findClosestTreeView","start","node","parentNode","findClosestTreeItem","HelixTreeView","HelixElement","detail","item","target","container","items","child","activeIndex","index","clamped","_a","wasSelected","i","currentIndex","focused","_b","next","prev","currentItem","parentItem","_c","parentIndex","matchIndex","char","level","selectable","children","c","setSize","ctor","supportsIdrefElementReferences","installAriaIdrefMirror","changedProperties","internals","hostAriaLabel","consumerLabelledBy","labelEls","resolveIdrefTokens","hasEffectiveLabelledBy","refsInternals","resolved","el","flattenAccName","containerTabindex","html","fallbackLabel","nothing","forcedColorsSurface","__decorateClass","property","state","customElement","helixTreeItemStyles","HelixTreeItem","path","parent","siblings","tree","selection","posInSet","flattened","slot","nodes","n","closest","active","options","childrenGroup","classMap","fallbackAriaLabel","ariaExpanded","ariaSelected","query"],"mappings":"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"}
|