@helixui/library 2.0.0-next.30 → 2.0.0-next.32
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/dist/base/styles.d.ts +12 -2
- package/dist/base/styles.d.ts.map +1 -1
- package/dist/components/hx-accordion/index.js +1 -1
- package/dist/components/hx-action-bar/index.js +1 -1
- package/dist/components/hx-alert/index.js +1 -1
- package/dist/components/hx-avatar/index.js +1 -1
- package/dist/components/hx-badge/index.js +1 -1
- package/dist/components/hx-banner/index.js +1 -1
- package/dist/components/hx-breadcrumb/index.js +1 -1
- package/dist/components/hx-button/index.js +1 -1
- package/dist/components/hx-button-group/index.js +1 -1
- package/dist/components/hx-card/index.js +1 -1
- package/dist/components/hx-carousel/index.js +1 -1
- package/dist/components/hx-checkbox/index.js +1 -1
- package/dist/components/hx-checkbox-group/index.js +1 -1
- package/dist/components/hx-clinical-status/index.js +1 -1
- package/dist/components/hx-code-snippet/index.js +1 -1
- package/dist/components/hx-color-picker/index.js +1 -1
- package/dist/components/hx-combobox/index.js +1 -1
- package/dist/components/hx-container/index.js +1 -1
- package/dist/components/hx-copy-button/index.js +1 -1
- package/dist/components/hx-counter/index.js +1 -1
- package/dist/components/hx-data-table/index.js +1 -1
- package/dist/components/hx-date-picker/index.js +1 -1
- package/dist/components/hx-dialog/index.js +1 -1
- package/dist/components/hx-divider/index.js +1 -1
- package/dist/components/hx-drawer/index.js +1 -1
- package/dist/components/hx-dropdown/index.js +1 -1
- package/dist/components/hx-field/index.js +1 -1
- package/dist/components/hx-field-label/index.js +1 -1
- package/dist/components/hx-file-upload/index.js +1 -1
- package/dist/components/hx-format-date/index.js +1 -1
- package/dist/components/hx-grid/index.js +1 -1
- package/dist/components/hx-help-text/index.js +1 -1
- package/dist/components/hx-icon/index.js +1 -1
- package/dist/components/hx-icon-button/index.js +1 -1
- package/dist/components/hx-image/index.js +1 -1
- package/dist/components/hx-link/index.js +1 -1
- package/dist/components/hx-list/index.js +1 -1
- package/dist/components/hx-menu/index.js +1 -1
- package/dist/components/hx-meter/index.js +1 -1
- package/dist/components/hx-nav/index.js +1 -1
- package/dist/components/hx-number-input/index.js +1 -1
- package/dist/components/hx-overflow-menu/index.js +1 -1
- package/dist/components/hx-pagination/index.js +1 -1
- package/dist/components/hx-patient-banner/index.js +1 -1
- package/dist/components/hx-phi-field/index.js +1 -1
- package/dist/components/hx-popover/index.js +1 -1
- package/dist/components/hx-popup/index.js +1 -1
- package/dist/components/hx-progress-bar/index.js +1 -1
- package/dist/components/hx-progress-ring/index.js +1 -1
- package/dist/components/hx-radio-group/index.js +1 -1
- package/dist/components/hx-rating/index.js +1 -1
- package/dist/components/hx-select/index.js +1 -1
- package/dist/components/hx-side-nav/index.js +1 -1
- package/dist/components/hx-skeleton/index.js +1 -1
- package/dist/components/hx-slider/index.js +1 -1
- package/dist/components/hx-spinner/index.js +1 -1
- package/dist/components/hx-split-button/index.js +1 -1
- package/dist/components/hx-split-panel/index.js +1 -1
- package/dist/components/hx-stack/index.js +1 -1
- package/dist/components/hx-stat/index.js +1 -1
- package/dist/components/hx-status-indicator/index.js +1 -1
- package/dist/components/hx-steps/index.js +1 -1
- package/dist/components/hx-structured-list/index.js +1 -1
- package/dist/components/hx-style-scope/index.js +1 -1
- package/dist/components/hx-switch/index.js +1 -1
- package/dist/components/hx-table/index.js +1 -1
- package/dist/components/hx-tabs/index.js +1 -1
- package/dist/components/hx-tag/index.js +1 -1
- package/dist/components/hx-text/index.js +1 -1
- package/dist/components/hx-text-input/index.js +1 -1
- package/dist/components/hx-textarea/index.js +1 -1
- package/dist/components/hx-theme/index.js +1 -1
- package/dist/components/hx-time-picker/index.js +1 -1
- package/dist/components/hx-toast/index.js +1 -1
- package/dist/components/hx-toggle-button/index.js +1 -1
- package/dist/components/hx-tooltip/index.js +1 -1
- package/dist/components/hx-top-nav/index.js +1 -1
- package/dist/components/hx-tree-view/index.js +1 -1
- package/dist/components/hx-visually-hidden/index.js +1 -1
- package/dist/css/index.css +1 -1
- package/dist/css/manifest.json +1 -1
- package/dist/index.js +80 -80
- package/dist/index.js.map +1 -1
- package/dist/shared/document-token-adoption-DuYNKd4k.js +21 -0
- package/dist/shared/document-token-adoption-DuYNKd4k.js.map +1 -0
- package/dist/shared/{hx-accordion-Cvs-uzZq.js → hx-accordion-CpfO0YQo.js} +2 -2
- package/dist/shared/{hx-accordion-Cvs-uzZq.js.map → hx-accordion-CpfO0YQo.js.map} +1 -1
- package/dist/shared/{hx-action-bar-B2BNlKQv.js → hx-action-bar-BpY1Z1UV.js} +2 -2
- package/dist/shared/{hx-action-bar-B2BNlKQv.js.map → hx-action-bar-BpY1Z1UV.js.map} +1 -1
- package/dist/shared/{hx-alert-CnDlZO6m.js → hx-alert-CHOjTBds.js} +2 -2
- package/dist/shared/{hx-alert-CnDlZO6m.js.map → hx-alert-CHOjTBds.js.map} +1 -1
- package/dist/shared/{hx-avatar-C68g1G2e.js → hx-avatar-an-WsuLl.js} +2 -2
- package/dist/shared/{hx-avatar-C68g1G2e.js.map → hx-avatar-an-WsuLl.js.map} +1 -1
- package/dist/shared/{hx-badge-D5vy_5BO.js → hx-badge-DDXTLoWi.js} +2 -2
- package/dist/shared/{hx-badge-D5vy_5BO.js.map → hx-badge-DDXTLoWi.js.map} +1 -1
- package/dist/shared/{hx-banner-Ccif-GaB.js → hx-banner-B-WEDiq7.js} +2 -2
- package/dist/shared/{hx-banner-Ccif-GaB.js.map → hx-banner-B-WEDiq7.js.map} +1 -1
- package/dist/shared/{hx-breadcrumb-item-DhxDZI3r.js → hx-breadcrumb-item-DzLyeL5Z.js} +2 -2
- package/dist/shared/{hx-breadcrumb-item-DhxDZI3r.js.map → hx-breadcrumb-item-DzLyeL5Z.js.map} +1 -1
- package/dist/shared/{hx-button-BF3VwcOJ.js → hx-button-DoN8jjQT.js} +2 -2
- package/dist/shared/{hx-button-BF3VwcOJ.js.map → hx-button-DoN8jjQT.js.map} +1 -1
- package/dist/shared/{hx-button-group-B8u25JjV.js → hx-button-group-BXlMQTt_.js} +2 -2
- package/dist/shared/{hx-button-group-B8u25JjV.js.map → hx-button-group-BXlMQTt_.js.map} +1 -1
- package/dist/shared/{hx-card-Dps4jvG9.js → hx-card-BgXZXDuc.js} +2 -2
- package/dist/shared/{hx-card-Dps4jvG9.js.map → hx-card-BgXZXDuc.js.map} +1 -1
- package/dist/shared/{hx-carousel-item-Dmo9pGFm.js → hx-carousel-item-Dwt9Pphz.js} +2 -2
- package/dist/shared/{hx-carousel-item-Dmo9pGFm.js.map → hx-carousel-item-Dwt9Pphz.js.map} +1 -1
- package/dist/shared/{hx-checkbox-99zyEKj7.js → hx-checkbox-CTEZ9IFq.js} +2 -2
- package/dist/shared/{hx-checkbox-99zyEKj7.js.map → hx-checkbox-CTEZ9IFq.js.map} +1 -1
- package/dist/shared/{hx-checkbox-group-J2CGHDwY.js → hx-checkbox-group-DThZeN5d.js} +2 -2
- package/dist/shared/{hx-checkbox-group-J2CGHDwY.js.map → hx-checkbox-group-DThZeN5d.js.map} +1 -1
- package/dist/shared/{hx-clinical-status-CGx5q5PL.js → hx-clinical-status-m4soOOwg.js} +2 -2
- package/dist/shared/{hx-clinical-status-CGx5q5PL.js.map → hx-clinical-status-m4soOOwg.js.map} +1 -1
- package/dist/shared/{hx-code-snippet-vAzJjm2O.js → hx-code-snippet-CoLYvX1Z.js} +2 -2
- package/dist/shared/{hx-code-snippet-vAzJjm2O.js.map → hx-code-snippet-CoLYvX1Z.js.map} +1 -1
- package/dist/shared/{hx-color-picker-CzMu9Fzw.js → hx-color-picker-DhOaNe6-.js} +2 -2
- package/dist/shared/{hx-color-picker-CzMu9Fzw.js.map → hx-color-picker-DhOaNe6-.js.map} +1 -1
- package/dist/shared/{hx-combobox-Dhw33U40.js → hx-combobox-BJ4lQocO.js} +2 -2
- package/dist/shared/{hx-combobox-Dhw33U40.js.map → hx-combobox-BJ4lQocO.js.map} +1 -1
- package/dist/shared/{hx-container-Dz4v6FSd.js → hx-container-31QT9KV_.js} +2 -2
- package/dist/shared/{hx-container-Dz4v6FSd.js.map → hx-container-31QT9KV_.js.map} +1 -1
- package/dist/shared/{hx-copy-button-Dcul7VwZ.js → hx-copy-button-BoM0WsMd.js} +2 -2
- package/dist/shared/{hx-copy-button-Dcul7VwZ.js.map → hx-copy-button-BoM0WsMd.js.map} +1 -1
- package/dist/shared/{hx-counter-czWWvciz.js → hx-counter-CP42cSVK.js} +2 -2
- package/dist/shared/{hx-counter-czWWvciz.js.map → hx-counter-CP42cSVK.js.map} +1 -1
- package/dist/shared/{hx-data-table-CAVgT4JG.js → hx-data-table-D5Ne-goy.js} +2 -2
- package/dist/shared/{hx-data-table-CAVgT4JG.js.map → hx-data-table-D5Ne-goy.js.map} +1 -1
- package/dist/shared/{hx-date-picker-Be8lTTO7.js → hx-date-picker-Cd3I3WkX.js} +2 -2
- package/dist/shared/{hx-date-picker-Be8lTTO7.js.map → hx-date-picker-Cd3I3WkX.js.map} +1 -1
- package/dist/shared/{hx-dialog-DTGX2FbP.js → hx-dialog-D4ubstxx.js} +2 -2
- package/dist/shared/{hx-dialog-DTGX2FbP.js.map → hx-dialog-D4ubstxx.js.map} +1 -1
- package/dist/shared/{hx-divider-BJjarZ9z.js → hx-divider-BBtOLHRP.js} +2 -2
- package/dist/shared/{hx-divider-BJjarZ9z.js.map → hx-divider-BBtOLHRP.js.map} +1 -1
- package/dist/shared/{hx-drawer-C5qI7jf1.js → hx-drawer--WDLuWtS.js} +2 -2
- package/dist/shared/{hx-drawer-C5qI7jf1.js.map → hx-drawer--WDLuWtS.js.map} +1 -1
- package/dist/shared/{hx-dropdown-BxNnUDyD.js → hx-dropdown-n5-XSmiV.js} +2 -2
- package/dist/shared/{hx-dropdown-BxNnUDyD.js.map → hx-dropdown-n5-XSmiV.js.map} +1 -1
- package/dist/shared/{hx-field-J1IUbQ8n.js → hx-field-CwT9tki1.js} +2 -2
- package/dist/shared/{hx-field-J1IUbQ8n.js.map → hx-field-CwT9tki1.js.map} +1 -1
- package/dist/shared/{hx-field-label-DhVdkhCN.js → hx-field-label-CcOK9VU3.js} +2 -2
- package/dist/shared/{hx-field-label-DhVdkhCN.js.map → hx-field-label-CcOK9VU3.js.map} +1 -1
- package/dist/shared/{hx-file-upload-79nMhnM_.js → hx-file-upload-Dwtu3WcB.js} +2 -2
- package/dist/shared/{hx-file-upload-79nMhnM_.js.map → hx-file-upload-Dwtu3WcB.js.map} +1 -1
- package/dist/shared/{hx-format-date-BMukpO2t.js → hx-format-date-B7L9odbA.js} +2 -2
- package/dist/shared/{hx-format-date-BMukpO2t.js.map → hx-format-date-B7L9odbA.js.map} +1 -1
- package/dist/shared/{hx-grid-CO6JZ6Kn.js → hx-grid-BIAR5h9m.js} +2 -2
- package/dist/shared/{hx-grid-CO6JZ6Kn.js.map → hx-grid-BIAR5h9m.js.map} +1 -1
- package/dist/shared/{hx-help-text-CYGvBLET.js → hx-help-text-Bmb80bP4.js} +2 -2
- package/dist/shared/{hx-help-text-CYGvBLET.js.map → hx-help-text-Bmb80bP4.js.map} +1 -1
- package/dist/shared/{hx-icon-C1hDsw-b.js → hx-icon-BKHs3OLu.js} +2 -2
- package/dist/shared/{hx-icon-C1hDsw-b.js.map → hx-icon-BKHs3OLu.js.map} +1 -1
- package/dist/shared/{hx-icon-button-DOWKUs0-.js → hx-icon-button-CJuy9xbw.js} +2 -2
- package/dist/shared/{hx-icon-button-DOWKUs0-.js.map → hx-icon-button-CJuy9xbw.js.map} +1 -1
- package/dist/shared/{hx-image-BqABFHGZ.js → hx-image-ztiXumZB.js} +2 -2
- package/dist/shared/{hx-image-BqABFHGZ.js.map → hx-image-ztiXumZB.js.map} +1 -1
- package/dist/shared/{hx-link-CAFRuAKJ.js → hx-link-IVsXmsKx.js} +2 -2
- package/dist/shared/{hx-link-CAFRuAKJ.js.map → hx-link-IVsXmsKx.js.map} +1 -1
- package/dist/shared/{hx-list-zbgO-9Xe.js → hx-list-CoTDMp19.js} +2 -2
- package/dist/shared/{hx-list-zbgO-9Xe.js.map → hx-list-CoTDMp19.js.map} +1 -1
- package/dist/shared/{hx-menu-divider-B1TIKAaq.js → hx-menu-divider-DRT8yHRZ.js} +2 -2
- package/dist/shared/{hx-menu-divider-B1TIKAaq.js.map → hx-menu-divider-DRT8yHRZ.js.map} +1 -1
- package/dist/shared/{hx-meter-BWNeWrg2.js → hx-meter-BvSJoqDp.js} +2 -2
- package/dist/shared/{hx-meter-BWNeWrg2.js.map → hx-meter-BvSJoqDp.js.map} +1 -1
- package/dist/shared/{hx-nav-item-D-9uG-Tt.js → hx-nav-item-CJN4VDrf.js} +2 -2
- package/dist/shared/{hx-nav-item-D-9uG-Tt.js.map → hx-nav-item-CJN4VDrf.js.map} +1 -1
- package/dist/shared/{hx-nav-DqNzqH2s.js → hx-nav-l0Rp7WPW.js} +2 -2
- package/dist/shared/{hx-nav-DqNzqH2s.js.map → hx-nav-l0Rp7WPW.js.map} +1 -1
- package/dist/shared/{hx-number-input-D7Jczm0J.js → hx-number-input-0Waw7Z7u.js} +2 -2
- package/dist/shared/{hx-number-input-D7Jczm0J.js.map → hx-number-input-0Waw7Z7u.js.map} +1 -1
- package/dist/shared/{hx-overflow-menu-UvSgk7yV.js → hx-overflow-menu-DElwFSCd.js} +2 -2
- package/dist/shared/{hx-overflow-menu-UvSgk7yV.js.map → hx-overflow-menu-DElwFSCd.js.map} +1 -1
- package/dist/shared/{hx-pagination-DBovb97q.js → hx-pagination-BNtx-LG6.js} +2 -2
- package/dist/shared/{hx-pagination-DBovb97q.js.map → hx-pagination-BNtx-LG6.js.map} +1 -1
- package/dist/shared/{hx-patient-banner-DLeU2pC2.js → hx-patient-banner-BKiN7nIE.js} +2 -2
- package/dist/shared/{hx-patient-banner-DLeU2pC2.js.map → hx-patient-banner-BKiN7nIE.js.map} +1 -1
- package/dist/shared/{hx-phi-field-BwlVKfHI.js → hx-phi-field-BiJH3V-k.js} +2 -2
- package/dist/shared/{hx-phi-field-BwlVKfHI.js.map → hx-phi-field-BiJH3V-k.js.map} +1 -1
- package/dist/shared/{hx-popover-DdjLdSr8.js → hx-popover-D63RXn5H.js} +2 -2
- package/dist/shared/{hx-popover-DdjLdSr8.js.map → hx-popover-D63RXn5H.js.map} +1 -1
- package/dist/shared/{hx-popup-DEYZKeH1.js → hx-popup-BQWMhvMO.js} +2 -2
- package/dist/shared/{hx-popup-DEYZKeH1.js.map → hx-popup-BQWMhvMO.js.map} +1 -1
- package/dist/shared/{hx-progress-bar-CdbFsimb.js → hx-progress-bar-Cm0VihTN.js} +2 -2
- package/dist/shared/{hx-progress-bar-CdbFsimb.js.map → hx-progress-bar-Cm0VihTN.js.map} +1 -1
- package/dist/shared/{hx-progress-ring-3YcGRxes.js → hx-progress-ring-BJeiDr3q.js} +2 -2
- package/dist/shared/{hx-progress-ring-3YcGRxes.js.map → hx-progress-ring-BJeiDr3q.js.map} +1 -1
- package/dist/shared/{hx-radio-BCEpX1tj.js → hx-radio-f8c5ggHG.js} +2 -2
- package/dist/shared/{hx-radio-BCEpX1tj.js.map → hx-radio-f8c5ggHG.js.map} +1 -1
- package/dist/shared/{hx-rating-BXnSN-Ln.js → hx-rating-qRJZXskm.js} +2 -2
- package/dist/shared/{hx-rating-BXnSN-Ln.js.map → hx-rating-qRJZXskm.js.map} +1 -1
- package/dist/shared/{hx-select-vzsOOYNx.js → hx-select-B5wq9Swh.js} +2 -2
- package/dist/shared/{hx-select-vzsOOYNx.js.map → hx-select-B5wq9Swh.js.map} +1 -1
- package/dist/shared/{hx-skeleton-Dikv9b7p.js → hx-skeleton-e5K9Qaxq.js} +2 -2
- package/dist/shared/{hx-skeleton-Dikv9b7p.js.map → hx-skeleton-e5K9Qaxq.js.map} +1 -1
- package/dist/shared/{hx-slider-DnncjdOT.js → hx-slider-BvXtvxmN.js} +2 -2
- package/dist/shared/{hx-slider-DnncjdOT.js.map → hx-slider-BvXtvxmN.js.map} +1 -1
- package/dist/shared/{hx-spinner-B52nJ4Vt.js → hx-spinner-Dyese1Tb.js} +2 -2
- package/dist/shared/{hx-spinner-B52nJ4Vt.js.map → hx-spinner-Dyese1Tb.js.map} +1 -1
- package/dist/shared/{hx-split-button-BJHIszDb.js → hx-split-button-CPndTJlC.js} +2 -2
- package/dist/shared/{hx-split-button-BJHIszDb.js.map → hx-split-button-CPndTJlC.js.map} +1 -1
- package/dist/shared/{hx-split-panel-uNW9xrA3.js → hx-split-panel-Dx72NaET.js} +2 -2
- package/dist/shared/{hx-split-panel-uNW9xrA3.js.map → hx-split-panel-Dx72NaET.js.map} +1 -1
- package/dist/shared/{hx-stack-BHc4gVv_.js → hx-stack-B76_1O6g.js} +2 -2
- package/dist/shared/{hx-stack-BHc4gVv_.js.map → hx-stack-B76_1O6g.js.map} +1 -1
- package/dist/shared/{hx-stat-BfgKgBeq.js → hx-stat-DKD2E7An.js} +2 -2
- package/dist/shared/{hx-stat-BfgKgBeq.js.map → hx-stat-DKD2E7An.js.map} +1 -1
- package/dist/shared/{hx-status-indicator-C146uMF0.js → hx-status-indicator-ClWpK6zz.js} +2 -2
- package/dist/shared/{hx-status-indicator-C146uMF0.js.map → hx-status-indicator-ClWpK6zz.js.map} +1 -1
- package/dist/shared/{hx-step-C0Unvyen.js → hx-step-C2Jk4mHa.js} +2 -2
- package/dist/shared/{hx-step-C0Unvyen.js.map → hx-step-C2Jk4mHa.js.map} +1 -1
- package/dist/shared/{hx-structured-list-3R69RETR.js → hx-structured-list-DKlrv7kS.js} +2 -2
- package/dist/shared/{hx-structured-list-3R69RETR.js.map → hx-structured-list-DKlrv7kS.js.map} +1 -1
- package/dist/shared/{hx-style-scope-D3dsKS58.js → hx-style-scope-CsQ2Phf_.js} +2 -2
- package/dist/shared/{hx-style-scope-D3dsKS58.js.map → hx-style-scope-CsQ2Phf_.js.map} +1 -1
- package/dist/shared/{hx-switch-BCNpbuk-.js → hx-switch-BzMN37PV.js} +2 -2
- package/dist/shared/{hx-switch-BCNpbuk-.js.map → hx-switch-BzMN37PV.js.map} +1 -1
- package/dist/shared/{hx-tab-panel-D7BTBgDQ.js → hx-tab-panel-J58zOSjq.js} +2 -2
- package/dist/shared/{hx-tab-panel-D7BTBgDQ.js.map → hx-tab-panel-J58zOSjq.js.map} +1 -1
- package/dist/shared/{hx-tag-C2E-6fJ3.js → hx-tag-F0ZcYj9b.js} +2 -2
- package/dist/shared/{hx-tag-C2E-6fJ3.js.map → hx-tag-F0ZcYj9b.js.map} +1 -1
- package/dist/shared/{hx-td-DWcp2XDO.js → hx-td-CNCvzBwY.js} +2 -2
- package/dist/shared/{hx-td-DWcp2XDO.js.map → hx-td-CNCvzBwY.js.map} +1 -1
- package/dist/shared/{hx-text-DxyBxz25.js → hx-text-DcWBqZwx.js} +2 -2
- package/dist/shared/{hx-text-DxyBxz25.js.map → hx-text-DcWBqZwx.js.map} +1 -1
- package/dist/shared/{hx-text-input-2LTGt0vQ.js → hx-text-input-Scyeefec.js} +2 -2
- package/dist/shared/{hx-text-input-2LTGt0vQ.js.map → hx-text-input-Scyeefec.js.map} +1 -1
- package/dist/shared/{hx-textarea-BZspivFK.js → hx-textarea-BfSJJtA1.js} +2 -2
- package/dist/shared/{hx-textarea-BZspivFK.js.map → hx-textarea-BfSJJtA1.js.map} +1 -1
- package/dist/shared/{hx-theme-J2YEpSIL.js → hx-theme-pc1V7dyL.js} +2 -2
- package/dist/shared/{hx-theme-J2YEpSIL.js.map → hx-theme-pc1V7dyL.js.map} +1 -1
- package/dist/shared/{hx-time-picker-CVrw4tju.js → hx-time-picker-CZvmihHD.js} +2 -2
- package/dist/shared/{hx-time-picker-CVrw4tju.js.map → hx-time-picker-CZvmihHD.js.map} +1 -1
- package/dist/shared/{hx-toggle-button-Ss7Gppx3.js → hx-toggle-button-BZUQUULm.js} +2 -2
- package/dist/shared/{hx-toggle-button-Ss7Gppx3.js.map → hx-toggle-button-BZUQUULm.js.map} +1 -1
- package/dist/shared/{hx-tooltip-xRNjEX7_.js → hx-tooltip-Ny4i1Idj.js} +2 -2
- package/dist/shared/{hx-tooltip-xRNjEX7_.js.map → hx-tooltip-Ny4i1Idj.js.map} +1 -1
- package/dist/shared/{hx-top-nav-28mxYGuj.js → hx-top-nav-CC4FW2Hp.js} +2 -2
- package/dist/shared/{hx-top-nav-28mxYGuj.js.map → hx-top-nav-CC4FW2Hp.js.map} +1 -1
- package/dist/shared/{hx-tree-item-C-cRw_ZA.js → hx-tree-item-CPQ9dJiK.js} +2 -2
- package/dist/shared/{hx-tree-item-C-cRw_ZA.js.map → hx-tree-item-CPQ9dJiK.js.map} +1 -1
- package/dist/shared/{hx-visually-hidden-D6Dv2l8l.js → hx-visually-hidden-vKX8QjeX.js} +2 -2
- package/dist/shared/{hx-visually-hidden-D6Dv2l8l.js.map → hx-visually-hidden-vKX8QjeX.js.map} +1 -1
- package/dist/shared/{toast-factory-oPHbhMZI.js → toast-factory-CEMNOt1T.js} +2 -2
- package/dist/shared/{toast-factory-oPHbhMZI.js.map → toast-factory-CEMNOt1T.js.map} +1 -1
- package/dist/utilities/document-token-adoption.d.ts +1 -1
- package/dist/utilities/document-token-adoption.d.ts.map +1 -1
- package/package.json +2 -2
- package/dist/shared/document-token-adoption-Dym9ALA4.js +0 -15
- package/dist/shared/document-token-adoption-Dym9ALA4.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hx-dialog-DTGX2FbP.js","sources":["../../src/components/hx-dialog/hx-dialog.styles.ts","../../src/components/hx-dialog/hx-dialog.ts"],"sourcesContent":["import { css } from 'lit';\n\nexport const helixDialogStyles = css`\n :host {\n display: contents;\n }\n\n /* ─── Native dialog reset ─── */\n\n dialog {\n padding: 0;\n border: none;\n background: transparent;\n color: inherit;\n max-width: 100%;\n max-height: 100%;\n overflow: visible;\n /* D5 — ensure native dialog element renders above the non-modal backdrop sibling */\n position: relative;\n z-index: calc(var(--hx-z-index-modal, 1400) + 1);\n }\n\n /* ─── Dialog container ─── */\n\n .dialog {\n display: flex;\n flex-direction: column;\n position: relative;\n background-color: var(--hx-dialog-bg, var(--hx-color-neutral-0));\n color: var(--hx-dialog-color, var(--hx-color-neutral-900));\n border-radius: var(--hx-dialog-border-radius, var(--hx-border-radius-lg));\n box-shadow: var(--hx-dialog-shadow, var(--hx-shadow-xl));\n width: var(--hx-dialog-width, var(--hx-container-narrow, 32rem));\n max-width: calc(100vw - var(--hx-space-8, 2rem));\n max-height: calc(100vh - var(--hx-space-8, 2rem));\n overflow: hidden;\n outline: none;\n\n /* Open/close animation */\n opacity: 0;\n transform: translateY(var(--hx-space-4, 1rem)) scale(0.97);\n transition:\n opacity var(--hx-duration-normal, 200ms) var(--hx-easing-out, ease-out),\n transform var(--hx-duration-normal, 200ms) var(--hx-easing-out, ease-out);\n }\n\n dialog[open] .dialog {\n opacity: 1;\n transform: translateY(0) scale(1);\n }\n\n @media (prefers-reduced-motion: reduce) {\n .dialog {\n transition: none;\n }\n\n .dialog__close-btn {\n transition: none;\n }\n }\n\n /* ─── Native backdrop (modal mode) ─── */\n\n dialog::backdrop {\n background-color: var(--hx-dialog-backdrop-color, var(--hx-color-neutral-900));\n opacity: 0;\n transition: opacity var(--hx-duration-normal, 200ms) var(--hx-easing-out, ease-out);\n }\n\n dialog[open]::backdrop {\n opacity: var(--hx-dialog-backdrop-opacity, 0.5);\n }\n\n @media (prefers-reduced-motion: reduce) {\n dialog::backdrop {\n transition: none;\n }\n }\n\n /* ─── Non-modal backdrop overlay ─── */\n\n .dialog-backdrop {\n position: fixed;\n inset: 0;\n background-color: var(--hx-dialog-backdrop-color, var(--hx-color-neutral-900));\n opacity: var(--hx-dialog-backdrop-opacity, 0.5);\n /* D5 — backdrop z-index must be lower than the dialog element's z-index */\n z-index: var(--hx-z-index-modal, 1400);\n }\n\n /* ─── Header ─── */\n\n .dialog__header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: var(--hx-dialog-header-padding, var(--hx-space-5) var(--hx-space-6));\n border-bottom: var(--hx-border-width-thin) solid\n var(--hx-dialog-header-border-color, var(--hx-color-neutral-200));\n gap: var(--hx-space-4);\n flex-shrink: 0;\n }\n\n .dialog__heading {\n margin: 0;\n font-family: var(--hx-font-family-sans);\n font-size: var(--hx-font-size-lg);\n font-weight: var(--hx-font-weight-semibold);\n line-height: var(--hx-line-height-tight);\n color: var(--hx-dialog-heading-color, var(--hx-color-neutral-900));\n flex: 1 1 auto;\n }\n\n /* ─── Built-in close button (D17) ─── */\n\n .dialog__close-btn {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n /* WCAG 2.5.5 (healthcare mandate): minimum 44x44px touch target */\n min-width: var(--hx-touch-target-min, 2.75rem);\n min-height: var(--hx-touch-target-min, 2.75rem);\n width: var(--hx-touch-target-min, 2.75rem);\n height: var(--hx-touch-target-min, 2.75rem);\n padding: 0;\n margin-inline-start: auto;\n background: transparent;\n border: none;\n border-radius: var(--hx-border-radius-sm, 0.25rem);\n cursor: pointer;\n color: var(--hx-color-neutral-500, #6b7280);\n font-size: var(--hx-font-size-xl, 1.25rem);\n line-height: 1; /* intentional literal: icon button needs line-height 1; no token maps to exactly 1 */\n transition:\n color var(--hx-duration-fast, 100ms) ease,\n background-color var(--hx-duration-fast, 100ms) ease;\n }\n\n .dialog__close-btn::before {\n content: '×';\n }\n\n .dialog__close-btn:hover {\n color: var(--hx-color-neutral-900);\n background-color: var(--hx-color-neutral-100);\n }\n\n .dialog__close-btn:focus-visible {\n outline: var(--hx-focus-ring-width, 2px) solid\n var(\n --hx-dialog-close-btn-focus-ring-color,\n var(--hx-focus-ring-color, var(--hx-color-primary-500))\n );\n outline-offset: var(--hx-focus-ring-offset, 2px);\n }\n\n /* ─── Body ─── */\n\n .dialog__body {\n flex: 1 1 auto;\n padding: var(--hx-dialog-body-padding, var(--hx-space-6));\n overflow-y: auto;\n overscroll-behavior: contain;\n }\n\n /* ─── Footer ─── */\n\n .dialog__footer {\n display: flex;\n align-items: center;\n justify-content: flex-end;\n gap: var(--hx-space-3);\n padding: var(--hx-dialog-footer-padding, var(--hx-space-4) var(--hx-space-6));\n border-top: var(--hx-border-width-thin) solid\n var(--hx-dialog-footer-border-color, var(--hx-color-neutral-200));\n flex-shrink: 0;\n }\n\n /* ─── Visually-hidden description (D8) ─── */\n\n .dialog__description {\n position: absolute;\n width: 1px;\n height: 1px;\n padding: 0;\n margin: -1px;\n overflow: hidden;\n clip: rect(0, 0, 0, 0);\n white-space: nowrap;\n border: 0;\n }\n`;\n","import { LitElement, html, nothing, type PropertyValues } from 'lit';\nimport '../../utilities/document-token-adoption.js';\nimport { customElement, property, query, state } from 'lit/decorators.js';\nimport { lockBodyScroll, unlockBodyScroll } from '../../utils/body-scroll-lock.js';\nimport { helixDialogStyles } from './hx-dialog.styles.js';\nimport { devWarn } from '../../utils/dev-warn.js';\n\n// D21 — deterministic monotonic counter instead of Math.random()\nlet _dialogCounter = 0;\n\n// Module-level constant avoids rebuilding the selector string on every _getFocusableElements call.\n// Pattern matches hx-drawer's FOCUSABLE_SELECTORS constant at module scope.\nconst FOCUSABLE_SELECTORS = [\n 'a[href]',\n 'area[href]',\n 'button:not([disabled])',\n 'input:not([disabled])',\n 'select:not([disabled])',\n 'textarea:not([disabled])',\n '[tabindex]:not([tabindex=\"-1\"])',\n 'details > summary',\n].join(',');\n\n/**\n * A modal and non-modal dialog component built on the native HTML `<dialog>` element.\n * Provides focus trapping, backdrop interaction, keyboard navigation, and full\n * ARIA labelling for enterprise healthcare accessibility requirements.\n *\n * @summary Accessible dialog overlay for confirmations, forms, and detailed content.\n *\n * @tag hx-dialog\n *\n * @slot - Default slot for the dialog body content.\n * @slot header - Slot for custom header content. When provided, replaces the built-in heading.\n * @slot footer - Slot for action buttons or footer content.\n *\n * @fires {CustomEvent<void>} hx-open - Fired when the dialog opens.\n * @fires {CustomEvent<void>} hx-close - Fired when the dialog closes for any reason.\n * @fires {CustomEvent<void>} hx-cancel - Fired when the dialog is dismissed via Escape key or cancel action.\n *\n * @csspart dialog - The inner container div that holds the dialog content.\n * @csspart backdrop - The non-modal backdrop overlay element.\n * @csspart header - The header region containing the heading and header slot.\n * @csspart close-button - The built-in close button in the dialog header.\n * @csspart body - The scrollable body region containing the default slot.\n * @csspart footer - The footer region containing the footer slot.\n *\n * @cssprop [--hx-dialog-bg=var(--hx-color-neutral-0)] - Dialog background color.\n * @cssprop [--hx-dialog-color=var(--hx-color-neutral-900)] - Dialog text color.\n * @cssprop [--hx-dialog-border-radius=var(--hx-border-radius-lg)] - Dialog corner radius.\n * @cssprop [--hx-dialog-shadow=var(--hx-shadow-xl)] - Dialog box shadow.\n * @cssprop [--hx-dialog-width=32rem] - Dialog width.\n * @cssprop [--hx-dialog-backdrop-color=var(--hx-color-neutral-900)] - Backdrop overlay color.\n * @cssprop [--hx-dialog-backdrop-opacity=0.5] - Backdrop overlay opacity (set to 0 to hide; note\n * that opacity:0 makes the backdrop invisible but still present in the layout — use pointer-events\n * carefully if you need a fully non-blocking backdrop).\n * @cssprop [--hx-dialog-header-padding] - Padding inside the dialog header.\n * @cssprop [--hx-dialog-header-border-color=var(--hx-color-neutral-200)] - Header bottom border color.\n * @cssprop [--hx-dialog-heading-color=var(--hx-color-neutral-900)] - Heading text color.\n * @cssprop [--hx-dialog-body-padding] - Padding inside the dialog body.\n * @cssprop [--hx-dialog-footer-padding] - Padding inside the dialog footer.\n * @cssprop [--hx-dialog-footer-border-color=var(--hx-color-neutral-200)] - Footer top border color.\n *\n * @remarks\n * **Browser support for `::backdrop`:** The `dialog::backdrop` pseudo-element inside Shadow DOM\n * is well-supported in Chrome/Chromium and Firefox 122+. For Firefox < 122, modal backdrop\n * animation will silently fall back to no animation. A non-modal backdrop fallback is rendered\n * for non-modal dialogs.\n *\n * **Drupal integration:** This component is Twig-renderable via attributes (`heading`, `open`,\n * `modal`, `close-on-backdrop`). For trigger-button wiring in Drupal behaviors:\n * ```js\n * Drupal.behaviors.hxDialog = {\n * attach(context) {\n * context.querySelectorAll('[data-hx-dialog-trigger]').forEach((btn) => {\n * btn.addEventListener('click', () => {\n * const id = btn.getAttribute('data-hx-dialog-trigger');\n * document.getElementById(id)?.showModal();\n * });\n * });\n * },\n * };\n * ```\n * Focus restoration to the trigger element is handled automatically by the component.\n */\n@customElement('hx-dialog')\nexport class HelixDialog extends LitElement {\n static override styles = [helixDialogStyles];\n\n // D10 — observe aria-label attribute without shadowing ARIAMixin.ariaLabel\n static override get observedAttributes(): string[] {\n return [...super.observedAttributes, 'aria-label'];\n }\n\n // ─── Queries ───\n\n /** @internal */\n @query('dialog')\n private _dialogEl: HTMLDialogElement | null | undefined;\n\n // ─── Internal state ───\n\n /** Tracks whether a header slot has been assigned content. * @internal\n */\n @state()\n private _hasHeaderSlot = false;\n\n /** Tracks whether a footer slot has been assigned content. * @internal\n */\n @state()\n private _hasFooterSlot = false;\n\n /** Cached focusable elements — populated on open, cleared on close. */\n /** @internal */\n private _cachedFocusableElements: HTMLElement[] = [];\n\n /** Guards against rapid open/close state changes causing asymmetric scroll lock. */\n /** @internal */\n private _isTransitioning = false;\n\n /** The element that had focus when the dialog opened — restored on close (D1). */\n /** @internal */\n private _triggerElement: HTMLElement | null = null;\n\n /** Pending returnValue to pass to native dialog.close() (D11). */\n /** @internal */\n private _pendingReturnValue: string | undefined = undefined;\n\n // ─── Unique IDs for aria-labelledby / aria-describedby ───\n\n /** @internal */\n private readonly _headingId = `hx-dialog-heading-${++_dialogCounter}`;\n /** @internal */\n private readonly _descriptionId = `hx-dialog-description-${_dialogCounter}`;\n\n // ─── Public Properties ───\n\n /**\n * Controls whether the dialog is open.\n * @attr open\n */\n @property({ type: Boolean, reflect: true })\n open = false;\n\n /**\n * When true, renders as a modal dialog with a backdrop and focus trap.\n * When false, renders as a non-modal dialog.\n * @attr modal\n */\n @property({ type: Boolean, reflect: true })\n modal = true;\n\n /**\n * When true, clicking the backdrop closes the dialog.\n * @attr close-on-backdrop\n */\n @property({\n attribute: 'close-on-backdrop',\n reflect: true,\n converter: {\n fromAttribute: (value: string | null) => value !== 'false',\n toAttribute: (value: boolean) => String(value),\n },\n })\n closeOnBackdrop = true;\n\n /**\n * Text content for the dialog heading. Used as the accessible label via aria-labelledby.\n * @attr heading\n */\n @property({ type: String })\n heading = '';\n\n /**\n * ARIA role variant. Use `'alertdialog'` for urgent dialogs requiring immediate attention\n * (e.g., drug interaction warnings, critical lab alerts). Defaults to `'dialog'`.\n * @attr variant\n */\n @property({ type: String, reflect: true })\n variant: 'dialog' | 'alertdialog' = 'dialog';\n\n /**\n * Optional description text linked to the dialog via `aria-describedby`.\n * When provided, screen readers will announce this text when the dialog receives focus.\n * Recommended for dialogs that surface critical clinical information.\n * @attr description\n */\n @property({ type: String })\n description = '';\n\n /** Accessible label for the close button. Override for localized text. */\n @property({ type: String, attribute: 'label-close' })\n labelClose = 'Close dialog';\n\n /**\n * Returns the dialog's return value — the string passed to `close(returnValue)`.\n * Mirrors `HTMLDialogElement.returnValue`.\n */\n get returnValue(): string {\n return this._dialogEl?.returnValue ?? '';\n }\n\n // ─── Lifecycle ───\n\n // D10 — re-render when aria-label attribute changes (without declaring a shadowing property)\n override attributeChangedCallback(\n name: string,\n oldVal: string | null,\n newVal: string | null,\n ): void {\n super.attributeChangedCallback(name, oldVal, newVal);\n if (name === 'aria-label' && oldVal !== newVal) {\n this.requestUpdate('aria-label', oldVal);\n }\n }\n\n override firstUpdated(): void {\n // Initialize header slot state without a querySelector in render()\n this._hasHeaderSlot = this.querySelector('[slot=\"header\"]') !== null;\n // Warn when no accessible heading is available\n if (!this.heading.trim() && !this._hasHeaderSlot) {\n devWarn(\n 'hx-dialog',\n 'No heading or header slot provided. Dialog will use a fallback aria-label. Provide a `heading` attribute or populate the `header` slot for a descriptive accessible name.',\n );\n }\n }\n\n override disconnectedCallback(): void {\n super.disconnectedCallback();\n this._removeGlobalListeners();\n // Restore body scroll if disconnected while open\n if (this.modal && this.open) {\n unlockBodyScroll();\n }\n }\n\n override updated(changedProperties: PropertyValues<this>): void {\n super.updated(changedProperties);\n\n if (changedProperties.has('open')) {\n if (this.open) {\n this._openDialog();\n } else {\n this._closeDialog();\n }\n }\n }\n\n // ─── Public Methods ───\n\n /** Opens the dialog in the mode determined by the `modal` property. */\n show(): void {\n this.open = true;\n }\n\n /** Opens the dialog as a modal regardless of the `modal` property setting. */\n showModal(): void {\n this.modal = true;\n this.open = true;\n }\n\n /**\n * Closes the dialog.\n * @param returnValue - Optional return value string stored as `dialog.returnValue`.\n */\n close(returnValue?: string): void {\n if (returnValue !== undefined) {\n this._pendingReturnValue = returnValue;\n }\n this.open = false;\n }\n\n // ─── Private: Open / Close ───\n\n /** @internal */\n private _openDialog(): void {\n const dialog = this._dialogEl;\n if (!dialog) return;\n if (this._isTransitioning) return;\n this._isTransitioning = true;\n\n // D1 — store the element that triggered the dialog open for focus restoration on close\n this._triggerElement = document.activeElement as HTMLElement | null;\n\n if (this.modal) {\n if (!dialog.open) {\n dialog.showModal();\n }\n // D4 — lock body scroll when modal dialog is open. Uses a shared reference-counted\n // lock so that simultaneous hx-dialog / hx-drawer instances don't clobber each other\n // when one closes before the other (see utils/body-scroll-lock.ts).\n lockBodyScroll();\n } else {\n if (!dialog.open) {\n dialog.show();\n }\n }\n\n this._addGlobalListeners();\n\n // Cache focusable elements after the dialog is open in the DOM\n void this.updateComplete.then(() => {\n this._cachedFocusableElements = this._getFocusableElements();\n // D3 — explicitly move initial focus to the first focusable element inside the dialog\n // (browser's built-in focus delegation cannot reach slotted light DOM through Shadow DOM)\n this._cachedFocusableElements[0]?.focus();\n this._isTransitioning = false;\n });\n\n this.dispatchEvent(\n new CustomEvent<void>('hx-open', {\n bubbles: true,\n composed: true,\n }),\n );\n }\n\n /** @internal */\n private _closeDialog(): void {\n const dialog = this._dialogEl;\n if (!dialog) return;\n if (this._isTransitioning) return;\n this._isTransitioning = true;\n\n const wasOpen = dialog.open;\n if (dialog.open) {\n // D11 — forward returnValue to native dialog.close() if provided\n if (this._pendingReturnValue !== undefined) {\n dialog.close(this._pendingReturnValue);\n this._pendingReturnValue = undefined;\n } else {\n dialog.close();\n }\n }\n\n // D4 — release body scroll lock. Uses shared counter so scroll is only restored\n // after every open overlay (hx-dialog + hx-drawer) has closed.\n unlockBodyScroll();\n\n this._removeGlobalListeners();\n this._cachedFocusableElements = [];\n\n // D1 — restore focus to the element that opened the dialog (WCAG 2.4.3)\n this._triggerElement?.focus();\n this._triggerElement = null;\n\n this._isTransitioning = false;\n\n if (wasOpen) {\n this.dispatchEvent(\n new CustomEvent<void>('hx-close', {\n bubbles: true,\n composed: true,\n }),\n );\n }\n }\n\n // ─── Event Listeners ───\n\n /** @internal */\n private _addGlobalListeners(): void {\n this._dialogEl?.addEventListener('keydown', this._handleKeyDown);\n this._dialogEl?.addEventListener('click', this._handleDialogClick);\n this._dialogEl?.addEventListener('cancel', this._handleNativeCancel);\n }\n\n /** @internal */\n private _removeGlobalListeners(): void {\n this._dialogEl?.removeEventListener('keydown', this._handleKeyDown);\n this._dialogEl?.removeEventListener('click', this._handleDialogClick);\n this._dialogEl?.removeEventListener('cancel', this._handleNativeCancel);\n }\n\n // ─── Keyboard Handler ───\n\n /** @internal */\n private _handleKeyDown = (e: KeyboardEvent): void => {\n if (e.key === 'Escape') {\n // Native dialog fires a 'cancel' event before close when Escape is pressed.\n // We prevent default here and handle it ourselves so we fire hx-cancel\n // before setting open = false (which triggers hx-close).\n e.preventDefault();\n this._cancel();\n return;\n }\n\n if (e.key === 'Tab' && this.modal) {\n this._trapFocus(e);\n }\n };\n\n // ─── Focus Trap ───\n\n /** @internal */\n private _getFocusableElements(): HTMLElement[] {\n // Collect focusable elements from slotted light DOM content only.\n // Shadow DOM elements (e.g., the built-in close button) remain accessible via\n // the native <dialog> tab order — including them here would cause focus to land\n // on shadow DOM elements whose document.activeElement resolves to the host,\n // breaking the test assertions and D7 initial focus behavior.\n const slots = this.shadowRoot?.querySelectorAll<HTMLSlotElement>('slot') ?? [];\n const lightFocusable: HTMLElement[] = [];\n\n slots.forEach((slot) => {\n slot.assignedElements({ flatten: true }).forEach((el) => {\n if (el instanceof HTMLElement) {\n if (el.matches(FOCUSABLE_SELECTORS)) {\n lightFocusable.push(el);\n }\n el.querySelectorAll<HTMLElement>(FOCUSABLE_SELECTORS).forEach((child) => {\n lightFocusable.push(child);\n });\n }\n });\n });\n\n const filtered = lightFocusable.filter(\n (el) => !el.hasAttribute('disabled') && el.getAttribute('tabindex') !== '-1',\n );\n\n // WCAG 2.4.3: if no light DOM focusable elements exist, fall back to the shadow\n // close button so the dialog always has at least one reachable focus target.\n if (filtered.length === 0) {\n const closeBtn = this.shadowRoot?.querySelector<HTMLElement>('.dialog__close-btn');\n if (closeBtn) filtered.push(closeBtn);\n }\n\n return filtered;\n }\n\n /** @internal */\n private _trapFocus(e: KeyboardEvent): void {\n const focusable =\n this._cachedFocusableElements.length > 0\n ? this._cachedFocusableElements\n : this._getFocusableElements();\n if (focusable.length === 0) {\n e.preventDefault();\n return;\n }\n\n const [first, ...rest] = focusable;\n const last = rest.length > 0 ? rest[rest.length - 1] : first;\n\n if (!first || !last) return;\n\n const active = document.activeElement;\n // Also check shadow root active element\n const shadowActive = this.shadowRoot?.activeElement;\n const currentActive = (shadowActive ?? active) as HTMLElement | null;\n\n // The shadow close button may be the first focusable element when no light DOM\n // content exists (WCAG 2.1.2). Check both the element reference and shadow root\n // active element so Shift+Tab wraps correctly across the shadow boundary.\n const closeBtn = this.shadowRoot?.querySelector<HTMLElement>('.dialog__close-btn');\n\n if (e.shiftKey) {\n // Shift+Tab: if focus is on first, wrap to last\n const isOnFirst =\n currentActive === first ||\n (closeBtn !== null && shadowActive === closeBtn && first === closeBtn);\n if (isOnFirst) {\n e.preventDefault();\n last.focus();\n }\n } else {\n // Tab: if focus is on last, wrap to first\n if (currentActive === last) {\n e.preventDefault();\n first.focus();\n }\n }\n }\n\n // ─── Backdrop Click ───\n\n /** @internal */\n private _handleDialogClick = (e: MouseEvent): void => {\n if (!this.closeOnBackdrop) return;\n\n // The native dialog element fills only the content area in showModal().\n // Clicks on the backdrop reach the <dialog> element itself.\n // We detect this by checking whether the click target is the dialog element.\n const target = e.target as HTMLElement;\n if (target === this._dialogEl) {\n this._cancel();\n }\n };\n\n // ─── Non-modal backdrop click ───\n\n /** @internal */\n private _handleBackdropClick = (): void => {\n if (!this.closeOnBackdrop) return;\n this._cancel();\n };\n\n // ─── Native cancel (Escape via browser, before our handler runs) ───\n\n /** @internal */\n private _handleNativeCancel = (e: Event): void => {\n // We always prevent the native cancel so we can manage close state ourselves.\n e.preventDefault();\n };\n\n // ─── Cancel logic ───\n\n /** @internal */\n private _cancel(): void {\n this.dispatchEvent(\n new CustomEvent<void>('hx-cancel', {\n bubbles: true,\n composed: true,\n }),\n );\n\n this.open = false;\n // hx-close is dispatched by _closeDialog() which is called via the open property setter\n }\n\n // ─── Slot change handlers ───\n\n /** @internal */\n private _handleHeaderSlotChange(e: Event): void {\n const slot = e.target as HTMLSlotElement;\n this._hasHeaderSlot = slot.assignedNodes({ flatten: true }).length > 0;\n }\n\n /** @internal */\n private _handleFooterSlotChange(e: Event): void {\n const slot = e.target as HTMLSlotElement;\n this._hasFooterSlot = slot.assignedNodes({ flatten: true }).length > 0;\n }\n\n // ─── Render Helpers ───\n\n /** @internal */\n private _renderHeader() {\n const hasHeading = this.heading.trim().length > 0;\n\n // Always render header to include the built-in close button (D17)\n return html`\n <div part=\"header\" class=\"dialog__header\">\n ${hasHeading\n ? html`<h2 id=${this._headingId} class=\"dialog__heading\">${this.heading}</h2>`\n : nothing}\n <slot name=\"header\" @slotchange=${this._handleHeaderSlotChange}></slot>\n <button\n part=\"close-button\"\n class=\"dialog__close-btn\"\n type=\"button\"\n aria-label=${this.labelClose}\n @click=${() => this.close()}\n ></button>\n </div>\n `;\n }\n\n /** @internal */\n private _renderFooter() {\n return html`\n <div part=\"footer\" class=\"dialog__footer\" ?hidden=${!this._hasFooterSlot}>\n <slot name=\"footer\" @slotchange=${this._handleFooterSlotChange}></slot>\n </div>\n `;\n }\n\n /** @internal */\n private _renderNonModalBackdrop() {\n if (this.modal || !this.open) return nothing;\n return html`\n <div\n part=\"backdrop\"\n class=\"dialog-backdrop\"\n @click=${this._handleBackdropClick}\n aria-hidden=\"true\"\n ></div>\n `;\n }\n\n // D8 — render visually-hidden description for aria-describedby\n /** @internal */\n private _renderDescription() {\n if (!this.description) return nothing;\n return html`<span id=${this._descriptionId} class=\"dialog__description\"\n >${this.description}</span\n >`;\n }\n\n // ─── Render ───\n\n override render() {\n const hasHeading = this.heading.trim().length > 0;\n // D10 — read aria-label via getAttribute to avoid shadowing ARIAMixin.ariaLabel\n const ariaLabel = this.getAttribute('aria-label');\n\n return html`\n ${this._renderNonModalBackdrop()}\n <dialog\n role=${this.variant !== 'dialog' ? this.variant : nothing}\n aria-labelledby=${hasHeading ? this._headingId : nothing}\n aria-label=${!hasHeading ? (ariaLabel ?? 'Dialog') : nothing}\n aria-describedby=${this.description ? this._descriptionId : nothing}\n aria-modal=${this.modal ? 'true' : nothing}\n >\n <div part=\"dialog\" class=\"dialog\">\n ${this._renderHeader()} ${this._renderDescription()}\n <div part=\"body\" class=\"dialog__body\">\n <slot></slot>\n </div>\n ${this._renderFooter()}\n </div>\n </dialog>\n `;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'hx-dialog': HelixDialog;\n }\n}\n"],"names":["helixDialogStyles","css","_dialogCounter","FOCUSABLE_SELECTORS","HelixDialog","LitElement","_a","name","oldVal","newVal","unlockBodyScroll","changedProperties","returnValue","dialog","lockBodyScroll","wasOpen","_b","_c","slots","lightFocusable","slot","el","child","filtered","closeBtn","focusable","first","rest","last","active","shadowActive","currentActive","hasHeading","html","nothing","ariaLabel","__decorateClass","query","state","property","value","customElement"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"hx-dialog-D4ubstxx.js","sources":["../../src/components/hx-dialog/hx-dialog.styles.ts","../../src/components/hx-dialog/hx-dialog.ts"],"sourcesContent":["import { css } from 'lit';\n\nexport const helixDialogStyles = css`\n :host {\n display: contents;\n }\n\n /* ─── Native dialog reset ─── */\n\n dialog {\n padding: 0;\n border: none;\n background: transparent;\n color: inherit;\n max-width: 100%;\n max-height: 100%;\n overflow: visible;\n /* D5 — ensure native dialog element renders above the non-modal backdrop sibling */\n position: relative;\n z-index: calc(var(--hx-z-index-modal, 1400) + 1);\n }\n\n /* ─── Dialog container ─── */\n\n .dialog {\n display: flex;\n flex-direction: column;\n position: relative;\n background-color: var(--hx-dialog-bg, var(--hx-color-neutral-0));\n color: var(--hx-dialog-color, var(--hx-color-neutral-900));\n border-radius: var(--hx-dialog-border-radius, var(--hx-border-radius-lg));\n box-shadow: var(--hx-dialog-shadow, var(--hx-shadow-xl));\n width: var(--hx-dialog-width, var(--hx-container-narrow, 32rem));\n max-width: calc(100vw - var(--hx-space-8, 2rem));\n max-height: calc(100vh - var(--hx-space-8, 2rem));\n overflow: hidden;\n outline: none;\n\n /* Open/close animation */\n opacity: 0;\n transform: translateY(var(--hx-space-4, 1rem)) scale(0.97);\n transition:\n opacity var(--hx-duration-normal, 200ms) var(--hx-easing-out, ease-out),\n transform var(--hx-duration-normal, 200ms) var(--hx-easing-out, ease-out);\n }\n\n dialog[open] .dialog {\n opacity: 1;\n transform: translateY(0) scale(1);\n }\n\n @media (prefers-reduced-motion: reduce) {\n .dialog {\n transition: none;\n }\n\n .dialog__close-btn {\n transition: none;\n }\n }\n\n /* ─── Native backdrop (modal mode) ─── */\n\n dialog::backdrop {\n background-color: var(--hx-dialog-backdrop-color, var(--hx-color-neutral-900));\n opacity: 0;\n transition: opacity var(--hx-duration-normal, 200ms) var(--hx-easing-out, ease-out);\n }\n\n dialog[open]::backdrop {\n opacity: var(--hx-dialog-backdrop-opacity, 0.5);\n }\n\n @media (prefers-reduced-motion: reduce) {\n dialog::backdrop {\n transition: none;\n }\n }\n\n /* ─── Non-modal backdrop overlay ─── */\n\n .dialog-backdrop {\n position: fixed;\n inset: 0;\n background-color: var(--hx-dialog-backdrop-color, var(--hx-color-neutral-900));\n opacity: var(--hx-dialog-backdrop-opacity, 0.5);\n /* D5 — backdrop z-index must be lower than the dialog element's z-index */\n z-index: var(--hx-z-index-modal, 1400);\n }\n\n /* ─── Header ─── */\n\n .dialog__header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: var(--hx-dialog-header-padding, var(--hx-space-5) var(--hx-space-6));\n border-bottom: var(--hx-border-width-thin) solid\n var(--hx-dialog-header-border-color, var(--hx-color-neutral-200));\n gap: var(--hx-space-4);\n flex-shrink: 0;\n }\n\n .dialog__heading {\n margin: 0;\n font-family: var(--hx-font-family-sans);\n font-size: var(--hx-font-size-lg);\n font-weight: var(--hx-font-weight-semibold);\n line-height: var(--hx-line-height-tight);\n color: var(--hx-dialog-heading-color, var(--hx-color-neutral-900));\n flex: 1 1 auto;\n }\n\n /* ─── Built-in close button (D17) ─── */\n\n .dialog__close-btn {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n /* WCAG 2.5.5 (healthcare mandate): minimum 44x44px touch target */\n min-width: var(--hx-touch-target-min, 2.75rem);\n min-height: var(--hx-touch-target-min, 2.75rem);\n width: var(--hx-touch-target-min, 2.75rem);\n height: var(--hx-touch-target-min, 2.75rem);\n padding: 0;\n margin-inline-start: auto;\n background: transparent;\n border: none;\n border-radius: var(--hx-border-radius-sm, 0.25rem);\n cursor: pointer;\n color: var(--hx-color-neutral-500, #6b7280);\n font-size: var(--hx-font-size-xl, 1.25rem);\n line-height: 1; /* intentional literal: icon button needs line-height 1; no token maps to exactly 1 */\n transition:\n color var(--hx-duration-fast, 100ms) ease,\n background-color var(--hx-duration-fast, 100ms) ease;\n }\n\n .dialog__close-btn::before {\n content: '×';\n }\n\n .dialog__close-btn:hover {\n color: var(--hx-color-neutral-900);\n background-color: var(--hx-color-neutral-100);\n }\n\n .dialog__close-btn:focus-visible {\n outline: var(--hx-focus-ring-width, 2px) solid\n var(\n --hx-dialog-close-btn-focus-ring-color,\n var(--hx-focus-ring-color, var(--hx-color-primary-500))\n );\n outline-offset: var(--hx-focus-ring-offset, 2px);\n }\n\n /* ─── Body ─── */\n\n .dialog__body {\n flex: 1 1 auto;\n padding: var(--hx-dialog-body-padding, var(--hx-space-6));\n overflow-y: auto;\n overscroll-behavior: contain;\n }\n\n /* ─── Footer ─── */\n\n .dialog__footer {\n display: flex;\n align-items: center;\n justify-content: flex-end;\n gap: var(--hx-space-3);\n padding: var(--hx-dialog-footer-padding, var(--hx-space-4) var(--hx-space-6));\n border-top: var(--hx-border-width-thin) solid\n var(--hx-dialog-footer-border-color, var(--hx-color-neutral-200));\n flex-shrink: 0;\n }\n\n /* ─── Visually-hidden description (D8) ─── */\n\n .dialog__description {\n position: absolute;\n width: 1px;\n height: 1px;\n padding: 0;\n margin: -1px;\n overflow: hidden;\n clip: rect(0, 0, 0, 0);\n white-space: nowrap;\n border: 0;\n }\n`;\n","import { LitElement, html, nothing, type PropertyValues } from 'lit';\nimport '../../utilities/document-token-adoption.js';\nimport { customElement, property, query, state } from 'lit/decorators.js';\nimport { lockBodyScroll, unlockBodyScroll } from '../../utils/body-scroll-lock.js';\nimport { helixDialogStyles } from './hx-dialog.styles.js';\nimport { devWarn } from '../../utils/dev-warn.js';\n\n// D21 — deterministic monotonic counter instead of Math.random()\nlet _dialogCounter = 0;\n\n// Module-level constant avoids rebuilding the selector string on every _getFocusableElements call.\n// Pattern matches hx-drawer's FOCUSABLE_SELECTORS constant at module scope.\nconst FOCUSABLE_SELECTORS = [\n 'a[href]',\n 'area[href]',\n 'button:not([disabled])',\n 'input:not([disabled])',\n 'select:not([disabled])',\n 'textarea:not([disabled])',\n '[tabindex]:not([tabindex=\"-1\"])',\n 'details > summary',\n].join(',');\n\n/**\n * A modal and non-modal dialog component built on the native HTML `<dialog>` element.\n * Provides focus trapping, backdrop interaction, keyboard navigation, and full\n * ARIA labelling for enterprise healthcare accessibility requirements.\n *\n * @summary Accessible dialog overlay for confirmations, forms, and detailed content.\n *\n * @tag hx-dialog\n *\n * @slot - Default slot for the dialog body content.\n * @slot header - Slot for custom header content. When provided, replaces the built-in heading.\n * @slot footer - Slot for action buttons or footer content.\n *\n * @fires {CustomEvent<void>} hx-open - Fired when the dialog opens.\n * @fires {CustomEvent<void>} hx-close - Fired when the dialog closes for any reason.\n * @fires {CustomEvent<void>} hx-cancel - Fired when the dialog is dismissed via Escape key or cancel action.\n *\n * @csspart dialog - The inner container div that holds the dialog content.\n * @csspart backdrop - The non-modal backdrop overlay element.\n * @csspart header - The header region containing the heading and header slot.\n * @csspart close-button - The built-in close button in the dialog header.\n * @csspart body - The scrollable body region containing the default slot.\n * @csspart footer - The footer region containing the footer slot.\n *\n * @cssprop [--hx-dialog-bg=var(--hx-color-neutral-0)] - Dialog background color.\n * @cssprop [--hx-dialog-color=var(--hx-color-neutral-900)] - Dialog text color.\n * @cssprop [--hx-dialog-border-radius=var(--hx-border-radius-lg)] - Dialog corner radius.\n * @cssprop [--hx-dialog-shadow=var(--hx-shadow-xl)] - Dialog box shadow.\n * @cssprop [--hx-dialog-width=32rem] - Dialog width.\n * @cssprop [--hx-dialog-backdrop-color=var(--hx-color-neutral-900)] - Backdrop overlay color.\n * @cssprop [--hx-dialog-backdrop-opacity=0.5] - Backdrop overlay opacity (set to 0 to hide; note\n * that opacity:0 makes the backdrop invisible but still present in the layout — use pointer-events\n * carefully if you need a fully non-blocking backdrop).\n * @cssprop [--hx-dialog-header-padding] - Padding inside the dialog header.\n * @cssprop [--hx-dialog-header-border-color=var(--hx-color-neutral-200)] - Header bottom border color.\n * @cssprop [--hx-dialog-heading-color=var(--hx-color-neutral-900)] - Heading text color.\n * @cssprop [--hx-dialog-body-padding] - Padding inside the dialog body.\n * @cssprop [--hx-dialog-footer-padding] - Padding inside the dialog footer.\n * @cssprop [--hx-dialog-footer-border-color=var(--hx-color-neutral-200)] - Footer top border color.\n *\n * @remarks\n * **Browser support for `::backdrop`:** The `dialog::backdrop` pseudo-element inside Shadow DOM\n * is well-supported in Chrome/Chromium and Firefox 122+. For Firefox < 122, modal backdrop\n * animation will silently fall back to no animation. A non-modal backdrop fallback is rendered\n * for non-modal dialogs.\n *\n * **Drupal integration:** This component is Twig-renderable via attributes (`heading`, `open`,\n * `modal`, `close-on-backdrop`). For trigger-button wiring in Drupal behaviors:\n * ```js\n * Drupal.behaviors.hxDialog = {\n * attach(context) {\n * context.querySelectorAll('[data-hx-dialog-trigger]').forEach((btn) => {\n * btn.addEventListener('click', () => {\n * const id = btn.getAttribute('data-hx-dialog-trigger');\n * document.getElementById(id)?.showModal();\n * });\n * });\n * },\n * };\n * ```\n * Focus restoration to the trigger element is handled automatically by the component.\n */\n@customElement('hx-dialog')\nexport class HelixDialog extends LitElement {\n static override styles = [helixDialogStyles];\n\n // D10 — observe aria-label attribute without shadowing ARIAMixin.ariaLabel\n static override get observedAttributes(): string[] {\n return [...super.observedAttributes, 'aria-label'];\n }\n\n // ─── Queries ───\n\n /** @internal */\n @query('dialog')\n private _dialogEl: HTMLDialogElement | null | undefined;\n\n // ─── Internal state ───\n\n /** Tracks whether a header slot has been assigned content. * @internal\n */\n @state()\n private _hasHeaderSlot = false;\n\n /** Tracks whether a footer slot has been assigned content. * @internal\n */\n @state()\n private _hasFooterSlot = false;\n\n /** Cached focusable elements — populated on open, cleared on close. */\n /** @internal */\n private _cachedFocusableElements: HTMLElement[] = [];\n\n /** Guards against rapid open/close state changes causing asymmetric scroll lock. */\n /** @internal */\n private _isTransitioning = false;\n\n /** The element that had focus when the dialog opened — restored on close (D1). */\n /** @internal */\n private _triggerElement: HTMLElement | null = null;\n\n /** Pending returnValue to pass to native dialog.close() (D11). */\n /** @internal */\n private _pendingReturnValue: string | undefined = undefined;\n\n // ─── Unique IDs for aria-labelledby / aria-describedby ───\n\n /** @internal */\n private readonly _headingId = `hx-dialog-heading-${++_dialogCounter}`;\n /** @internal */\n private readonly _descriptionId = `hx-dialog-description-${_dialogCounter}`;\n\n // ─── Public Properties ───\n\n /**\n * Controls whether the dialog is open.\n * @attr open\n */\n @property({ type: Boolean, reflect: true })\n open = false;\n\n /**\n * When true, renders as a modal dialog with a backdrop and focus trap.\n * When false, renders as a non-modal dialog.\n * @attr modal\n */\n @property({ type: Boolean, reflect: true })\n modal = true;\n\n /**\n * When true, clicking the backdrop closes the dialog.\n * @attr close-on-backdrop\n */\n @property({\n attribute: 'close-on-backdrop',\n reflect: true,\n converter: {\n fromAttribute: (value: string | null) => value !== 'false',\n toAttribute: (value: boolean) => String(value),\n },\n })\n closeOnBackdrop = true;\n\n /**\n * Text content for the dialog heading. Used as the accessible label via aria-labelledby.\n * @attr heading\n */\n @property({ type: String })\n heading = '';\n\n /**\n * ARIA role variant. Use `'alertdialog'` for urgent dialogs requiring immediate attention\n * (e.g., drug interaction warnings, critical lab alerts). Defaults to `'dialog'`.\n * @attr variant\n */\n @property({ type: String, reflect: true })\n variant: 'dialog' | 'alertdialog' = 'dialog';\n\n /**\n * Optional description text linked to the dialog via `aria-describedby`.\n * When provided, screen readers will announce this text when the dialog receives focus.\n * Recommended for dialogs that surface critical clinical information.\n * @attr description\n */\n @property({ type: String })\n description = '';\n\n /** Accessible label for the close button. Override for localized text. */\n @property({ type: String, attribute: 'label-close' })\n labelClose = 'Close dialog';\n\n /**\n * Returns the dialog's return value — the string passed to `close(returnValue)`.\n * Mirrors `HTMLDialogElement.returnValue`.\n */\n get returnValue(): string {\n return this._dialogEl?.returnValue ?? '';\n }\n\n // ─── Lifecycle ───\n\n // D10 — re-render when aria-label attribute changes (without declaring a shadowing property)\n override attributeChangedCallback(\n name: string,\n oldVal: string | null,\n newVal: string | null,\n ): void {\n super.attributeChangedCallback(name, oldVal, newVal);\n if (name === 'aria-label' && oldVal !== newVal) {\n this.requestUpdate('aria-label', oldVal);\n }\n }\n\n override firstUpdated(): void {\n // Initialize header slot state without a querySelector in render()\n this._hasHeaderSlot = this.querySelector('[slot=\"header\"]') !== null;\n // Warn when no accessible heading is available\n if (!this.heading.trim() && !this._hasHeaderSlot) {\n devWarn(\n 'hx-dialog',\n 'No heading or header slot provided. Dialog will use a fallback aria-label. Provide a `heading` attribute or populate the `header` slot for a descriptive accessible name.',\n );\n }\n }\n\n override disconnectedCallback(): void {\n super.disconnectedCallback();\n this._removeGlobalListeners();\n // Restore body scroll if disconnected while open\n if (this.modal && this.open) {\n unlockBodyScroll();\n }\n }\n\n override updated(changedProperties: PropertyValues<this>): void {\n super.updated(changedProperties);\n\n if (changedProperties.has('open')) {\n if (this.open) {\n this._openDialog();\n } else {\n this._closeDialog();\n }\n }\n }\n\n // ─── Public Methods ───\n\n /** Opens the dialog in the mode determined by the `modal` property. */\n show(): void {\n this.open = true;\n }\n\n /** Opens the dialog as a modal regardless of the `modal` property setting. */\n showModal(): void {\n this.modal = true;\n this.open = true;\n }\n\n /**\n * Closes the dialog.\n * @param returnValue - Optional return value string stored as `dialog.returnValue`.\n */\n close(returnValue?: string): void {\n if (returnValue !== undefined) {\n this._pendingReturnValue = returnValue;\n }\n this.open = false;\n }\n\n // ─── Private: Open / Close ───\n\n /** @internal */\n private _openDialog(): void {\n const dialog = this._dialogEl;\n if (!dialog) return;\n if (this._isTransitioning) return;\n this._isTransitioning = true;\n\n // D1 — store the element that triggered the dialog open for focus restoration on close\n this._triggerElement = document.activeElement as HTMLElement | null;\n\n if (this.modal) {\n if (!dialog.open) {\n dialog.showModal();\n }\n // D4 — lock body scroll when modal dialog is open. Uses a shared reference-counted\n // lock so that simultaneous hx-dialog / hx-drawer instances don't clobber each other\n // when one closes before the other (see utils/body-scroll-lock.ts).\n lockBodyScroll();\n } else {\n if (!dialog.open) {\n dialog.show();\n }\n }\n\n this._addGlobalListeners();\n\n // Cache focusable elements after the dialog is open in the DOM\n void this.updateComplete.then(() => {\n this._cachedFocusableElements = this._getFocusableElements();\n // D3 — explicitly move initial focus to the first focusable element inside the dialog\n // (browser's built-in focus delegation cannot reach slotted light DOM through Shadow DOM)\n this._cachedFocusableElements[0]?.focus();\n this._isTransitioning = false;\n });\n\n this.dispatchEvent(\n new CustomEvent<void>('hx-open', {\n bubbles: true,\n composed: true,\n }),\n );\n }\n\n /** @internal */\n private _closeDialog(): void {\n const dialog = this._dialogEl;\n if (!dialog) return;\n if (this._isTransitioning) return;\n this._isTransitioning = true;\n\n const wasOpen = dialog.open;\n if (dialog.open) {\n // D11 — forward returnValue to native dialog.close() if provided\n if (this._pendingReturnValue !== undefined) {\n dialog.close(this._pendingReturnValue);\n this._pendingReturnValue = undefined;\n } else {\n dialog.close();\n }\n }\n\n // D4 — release body scroll lock. Uses shared counter so scroll is only restored\n // after every open overlay (hx-dialog + hx-drawer) has closed.\n unlockBodyScroll();\n\n this._removeGlobalListeners();\n this._cachedFocusableElements = [];\n\n // D1 — restore focus to the element that opened the dialog (WCAG 2.4.3)\n this._triggerElement?.focus();\n this._triggerElement = null;\n\n this._isTransitioning = false;\n\n if (wasOpen) {\n this.dispatchEvent(\n new CustomEvent<void>('hx-close', {\n bubbles: true,\n composed: true,\n }),\n );\n }\n }\n\n // ─── Event Listeners ───\n\n /** @internal */\n private _addGlobalListeners(): void {\n this._dialogEl?.addEventListener('keydown', this._handleKeyDown);\n this._dialogEl?.addEventListener('click', this._handleDialogClick);\n this._dialogEl?.addEventListener('cancel', this._handleNativeCancel);\n }\n\n /** @internal */\n private _removeGlobalListeners(): void {\n this._dialogEl?.removeEventListener('keydown', this._handleKeyDown);\n this._dialogEl?.removeEventListener('click', this._handleDialogClick);\n this._dialogEl?.removeEventListener('cancel', this._handleNativeCancel);\n }\n\n // ─── Keyboard Handler ───\n\n /** @internal */\n private _handleKeyDown = (e: KeyboardEvent): void => {\n if (e.key === 'Escape') {\n // Native dialog fires a 'cancel' event before close when Escape is pressed.\n // We prevent default here and handle it ourselves so we fire hx-cancel\n // before setting open = false (which triggers hx-close).\n e.preventDefault();\n this._cancel();\n return;\n }\n\n if (e.key === 'Tab' && this.modal) {\n this._trapFocus(e);\n }\n };\n\n // ─── Focus Trap ───\n\n /** @internal */\n private _getFocusableElements(): HTMLElement[] {\n // Collect focusable elements from slotted light DOM content only.\n // Shadow DOM elements (e.g., the built-in close button) remain accessible via\n // the native <dialog> tab order — including them here would cause focus to land\n // on shadow DOM elements whose document.activeElement resolves to the host,\n // breaking the test assertions and D7 initial focus behavior.\n const slots = this.shadowRoot?.querySelectorAll<HTMLSlotElement>('slot') ?? [];\n const lightFocusable: HTMLElement[] = [];\n\n slots.forEach((slot) => {\n slot.assignedElements({ flatten: true }).forEach((el) => {\n if (el instanceof HTMLElement) {\n if (el.matches(FOCUSABLE_SELECTORS)) {\n lightFocusable.push(el);\n }\n el.querySelectorAll<HTMLElement>(FOCUSABLE_SELECTORS).forEach((child) => {\n lightFocusable.push(child);\n });\n }\n });\n });\n\n const filtered = lightFocusable.filter(\n (el) => !el.hasAttribute('disabled') && el.getAttribute('tabindex') !== '-1',\n );\n\n // WCAG 2.4.3: if no light DOM focusable elements exist, fall back to the shadow\n // close button so the dialog always has at least one reachable focus target.\n if (filtered.length === 0) {\n const closeBtn = this.shadowRoot?.querySelector<HTMLElement>('.dialog__close-btn');\n if (closeBtn) filtered.push(closeBtn);\n }\n\n return filtered;\n }\n\n /** @internal */\n private _trapFocus(e: KeyboardEvent): void {\n const focusable =\n this._cachedFocusableElements.length > 0\n ? this._cachedFocusableElements\n : this._getFocusableElements();\n if (focusable.length === 0) {\n e.preventDefault();\n return;\n }\n\n const [first, ...rest] = focusable;\n const last = rest.length > 0 ? rest[rest.length - 1] : first;\n\n if (!first || !last) return;\n\n const active = document.activeElement;\n // Also check shadow root active element\n const shadowActive = this.shadowRoot?.activeElement;\n const currentActive = (shadowActive ?? active) as HTMLElement | null;\n\n // The shadow close button may be the first focusable element when no light DOM\n // content exists (WCAG 2.1.2). Check both the element reference and shadow root\n // active element so Shift+Tab wraps correctly across the shadow boundary.\n const closeBtn = this.shadowRoot?.querySelector<HTMLElement>('.dialog__close-btn');\n\n if (e.shiftKey) {\n // Shift+Tab: if focus is on first, wrap to last\n const isOnFirst =\n currentActive === first ||\n (closeBtn !== null && shadowActive === closeBtn && first === closeBtn);\n if (isOnFirst) {\n e.preventDefault();\n last.focus();\n }\n } else {\n // Tab: if focus is on last, wrap to first\n if (currentActive === last) {\n e.preventDefault();\n first.focus();\n }\n }\n }\n\n // ─── Backdrop Click ───\n\n /** @internal */\n private _handleDialogClick = (e: MouseEvent): void => {\n if (!this.closeOnBackdrop) return;\n\n // The native dialog element fills only the content area in showModal().\n // Clicks on the backdrop reach the <dialog> element itself.\n // We detect this by checking whether the click target is the dialog element.\n const target = e.target as HTMLElement;\n if (target === this._dialogEl) {\n this._cancel();\n }\n };\n\n // ─── Non-modal backdrop click ───\n\n /** @internal */\n private _handleBackdropClick = (): void => {\n if (!this.closeOnBackdrop) return;\n this._cancel();\n };\n\n // ─── Native cancel (Escape via browser, before our handler runs) ───\n\n /** @internal */\n private _handleNativeCancel = (e: Event): void => {\n // We always prevent the native cancel so we can manage close state ourselves.\n e.preventDefault();\n };\n\n // ─── Cancel logic ───\n\n /** @internal */\n private _cancel(): void {\n this.dispatchEvent(\n new CustomEvent<void>('hx-cancel', {\n bubbles: true,\n composed: true,\n }),\n );\n\n this.open = false;\n // hx-close is dispatched by _closeDialog() which is called via the open property setter\n }\n\n // ─── Slot change handlers ───\n\n /** @internal */\n private _handleHeaderSlotChange(e: Event): void {\n const slot = e.target as HTMLSlotElement;\n this._hasHeaderSlot = slot.assignedNodes({ flatten: true }).length > 0;\n }\n\n /** @internal */\n private _handleFooterSlotChange(e: Event): void {\n const slot = e.target as HTMLSlotElement;\n this._hasFooterSlot = slot.assignedNodes({ flatten: true }).length > 0;\n }\n\n // ─── Render Helpers ───\n\n /** @internal */\n private _renderHeader() {\n const hasHeading = this.heading.trim().length > 0;\n\n // Always render header to include the built-in close button (D17)\n return html`\n <div part=\"header\" class=\"dialog__header\">\n ${hasHeading\n ? html`<h2 id=${this._headingId} class=\"dialog__heading\">${this.heading}</h2>`\n : nothing}\n <slot name=\"header\" @slotchange=${this._handleHeaderSlotChange}></slot>\n <button\n part=\"close-button\"\n class=\"dialog__close-btn\"\n type=\"button\"\n aria-label=${this.labelClose}\n @click=${() => this.close()}\n ></button>\n </div>\n `;\n }\n\n /** @internal */\n private _renderFooter() {\n return html`\n <div part=\"footer\" class=\"dialog__footer\" ?hidden=${!this._hasFooterSlot}>\n <slot name=\"footer\" @slotchange=${this._handleFooterSlotChange}></slot>\n </div>\n `;\n }\n\n /** @internal */\n private _renderNonModalBackdrop() {\n if (this.modal || !this.open) return nothing;\n return html`\n <div\n part=\"backdrop\"\n class=\"dialog-backdrop\"\n @click=${this._handleBackdropClick}\n aria-hidden=\"true\"\n ></div>\n `;\n }\n\n // D8 — render visually-hidden description for aria-describedby\n /** @internal */\n private _renderDescription() {\n if (!this.description) return nothing;\n return html`<span id=${this._descriptionId} class=\"dialog__description\"\n >${this.description}</span\n >`;\n }\n\n // ─── Render ───\n\n override render() {\n const hasHeading = this.heading.trim().length > 0;\n // D10 — read aria-label via getAttribute to avoid shadowing ARIAMixin.ariaLabel\n const ariaLabel = this.getAttribute('aria-label');\n\n return html`\n ${this._renderNonModalBackdrop()}\n <dialog\n role=${this.variant !== 'dialog' ? this.variant : nothing}\n aria-labelledby=${hasHeading ? this._headingId : nothing}\n aria-label=${!hasHeading ? (ariaLabel ?? 'Dialog') : nothing}\n aria-describedby=${this.description ? this._descriptionId : nothing}\n aria-modal=${this.modal ? 'true' : nothing}\n >\n <div part=\"dialog\" class=\"dialog\">\n ${this._renderHeader()} ${this._renderDescription()}\n <div part=\"body\" class=\"dialog__body\">\n <slot></slot>\n </div>\n ${this._renderFooter()}\n </div>\n </dialog>\n `;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'hx-dialog': HelixDialog;\n }\n}\n"],"names":["helixDialogStyles","css","_dialogCounter","FOCUSABLE_SELECTORS","HelixDialog","LitElement","_a","name","oldVal","newVal","unlockBodyScroll","changedProperties","returnValue","dialog","lockBodyScroll","wasOpen","_b","_c","slots","lightFocusable","slot","el","child","filtered","closeBtn","focusable","first","rest","last","active","shadowActive","currentActive","hasHeading","html","nothing","ariaLabel","__decorateClass","query","state","property","value","customElement"],"mappings":"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"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { css as v, LitElement as p, nothing as c, html as o } from "lit";
|
|
2
|
-
import "./document-token-adoption-
|
|
2
|
+
import "./document-token-adoption-DuYNKd4k.js";
|
|
3
3
|
import { property as n, state as _, customElement as g } from "lit/decorators.js";
|
|
4
4
|
const b = v`
|
|
5
5
|
:host {
|
|
@@ -155,4 +155,4 @@ r = l([
|
|
|
155
155
|
export {
|
|
156
156
|
r as H
|
|
157
157
|
};
|
|
158
|
-
//# sourceMappingURL=hx-divider-
|
|
158
|
+
//# sourceMappingURL=hx-divider-BBtOLHRP.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hx-divider-
|
|
1
|
+
{"version":3,"file":"hx-divider-BBtOLHRP.js","sources":["../../src/components/hx-divider/hx-divider.styles.ts","../../src/components/hx-divider/hx-divider.ts"],"sourcesContent":["import { css } from 'lit';\n\nexport const helixDividerStyles = css`\n :host {\n display: block;\n --_divider-color: var(--hx-divider-color, var(--hx-color-neutral-200, #e2e8f0));\n --_divider-width: var(--hx-divider-width, var(--hx-border-width-thin, 1px));\n --_divider-label-color: var(--hx-divider-label-color, var(--hx-color-neutral-500, #64748b));\n --_divider-label-size: var(--hx-divider-label-font-size, var(--hx-font-size-sm, 0.875rem));\n --_divider-label-gap: var(--hx-divider-label-gap, var(--hx-space-3, 0.75rem));\n }\n\n /* ─── Spacing Variants ─── */\n\n :host([spacing='none']) {\n --_spacing: 0;\n }\n\n :host([spacing='sm']) {\n --_spacing: var(--hx-space-2, 0.5rem);\n }\n\n :host,\n :host([spacing='md']) {\n --_spacing: var(--hx-space-4, 1rem);\n }\n\n :host([spacing='lg']) {\n --_spacing: var(--hx-space-6, 1.5rem);\n }\n\n /* ─── Horizontal (default) ─── */\n\n :host([orientation='horizontal']) {\n margin-block: var(--_spacing);\n }\n\n /* ─── Vertical ─── */\n\n :host([orientation='vertical']) {\n display: inline-flex;\n align-self: stretch;\n margin-inline: var(--_spacing);\n }\n\n /* ─── Base (hr) — horizontal ─── */\n\n .divider {\n display: flex;\n align-items: center;\n gap: var(--_divider-label-gap);\n border: none;\n margin: 0;\n padding: 0;\n }\n\n /* ─── Base — vertical ─── */\n\n :host([orientation='vertical']) .divider {\n flex-direction: column;\n height: 100%;\n }\n\n /* ─── Lines flanking label ─── */\n\n .divider__line {\n flex: 1;\n background-color: var(--_divider-color);\n }\n\n :host(:not([orientation='vertical'])) .divider__line {\n height: var(--_divider-width);\n }\n\n :host([orientation='vertical']) .divider__line {\n width: var(--_divider-width);\n height: auto;\n min-height: 0;\n }\n\n /* ─── Label ─── */\n\n .divider__label {\n flex-shrink: 0;\n color: var(--_divider-label-color);\n font-size: var(--_divider-label-size);\n line-height: var(--hx-line-height-tight, 1.25);\n white-space: nowrap;\n }\n`;\n","import { LitElement, html, nothing, type PropertyValues } from 'lit';\nimport '../../utilities/document-token-adoption.js';\nimport { devWarn } from '../../utils/dev-warn.js';\nimport { customElement, property, state } from 'lit/decorators.js';\nimport { helixDividerStyles } from './hx-divider.styles.js';\n\n/**\n * A visual separator element for dividing content sections. Supports\n * horizontal and vertical orientations, configurable spacing, and an optional\n * centered label rendered between two lines.\n *\n * @summary Horizontal or vertical separator line with optional label.\n *\n * @tag hx-divider\n *\n * @slot - Optional label text rendered centered between two lines.\n *\n * @csspart base - The root divider element.\n * @csspart label - The optional centered label wrapper.\n *\n * @cssprop [--hx-divider-color=var(--hx-color-neutral-200)] - Line color.\n * @cssprop [--hx-divider-width=var(--hx-border-width-thin)] - Line thickness.\n * @cssprop [--hx-divider-label-color=var(--hx-color-neutral-500)] - Label text color.\n * @cssprop [--hx-divider-label-font-size=var(--hx-font-size-sm)] - Label font size.\n * @cssprop [--hx-divider-label-gap=var(--hx-space-3)] - Gap between lines and label.\n */\n@customElement('hx-divider')\nexport class HelixDivider extends LitElement {\n static override styles = [helixDividerStyles];\n\n /**\n * Orientation of the divider.\n * @attr orientation\n */\n @property({ type: String, reflect: true })\n orientation: 'horizontal' | 'vertical' = 'horizontal';\n\n /**\n * Spacing applied to the block axis (horizontal) or inline axis (vertical).\n * @attr spacing\n */\n @property({ type: String, reflect: true })\n spacing: 'none' | 'sm' | 'md' | 'lg' = 'md';\n\n /**\n * When true, renders the divider as decorative only (role=\"presentation\").\n * Screen readers will not announce decorative dividers.\n * @attr decorative\n */\n @property({ type: Boolean, reflect: true })\n decorative = false;\n\n /**\n * Optional text label rendered centered between the divider lines.\n * Also sets aria-label on the separator for assistive technologies.\n * @attr label\n */\n @property({ type: String, reflect: true })\n label?: string;\n\n /** @internal */\n @state()\n private _hasLabel = false;\n\n /** @internal */\n private _checkSlot(slot: HTMLSlotElement): void {\n const nodes = slot.assignedNodes({ flatten: true });\n this._hasLabel = nodes.some((node) =>\n node.nodeType === Node.TEXT_NODE\n ? (node.textContent ?? '').trim().length > 0\n : node.nodeType === Node.ELEMENT_NODE,\n );\n }\n\n /** @internal */\n private _slotChangeHandler = (e: Event): void => {\n this._checkSlot(e.target as HTMLSlotElement);\n };\n\n override firstUpdated(_changedProperties: PropertyValues<this>): void {\n super.firstUpdated(_changedProperties);\n const slot = this.shadowRoot?.querySelector<HTMLSlotElement>('slot:not([name])');\n if (slot) this._checkSlot(slot);\n if (!this.decorative && !this.label && !this._hasLabel) {\n devWarn(\n 'hx-divider',\n 'Non-decorative separator has no accessible name. Provide a `label` attribute or slot content, or set `decorative` to suppress this warning (WCAG 4.1.2).',\n );\n }\n }\n\n override render() {\n const isDecorative = this.decorative;\n const showLabel = this._hasLabel || !!this.label;\n\n return html`\n <div\n part=\"base\"\n class=\"divider${showLabel ? ' divider--labeled' : ''}\"\n role=\"${isDecorative ? 'presentation' : 'separator'}\"\n aria-orientation=\"${isDecorative ? nothing : this.orientation}\"\n aria-label=\"${!isDecorative && this.label ? this.label : nothing}\"\n >\n <span class=\"divider__line\"></span>\n ${showLabel\n ? html`<span part=\"label\" class=\"divider__label\">\n ${this.label ? html`${this.label}` : nothing}\n <slot @slotchange=${this._slotChangeHandler}></slot>\n </span>`\n : html`<slot @slotchange=${this._slotChangeHandler}></slot>`}\n <span class=\"divider__line\"></span>\n </div>\n `;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'hx-divider': HelixDivider;\n }\n}\n\n/** Canonical type alias for the hx-divider component. */\nexport type HxDivider = HelixDivider;\n\n/** @deprecated Use {@link HxDivider} instead. The `Wc` prefix was a legacy naming convention. */\nexport type WcDivider = HelixDivider;\n"],"names":["helixDividerStyles","css","HelixDivider","LitElement","slot","nodes","node","_changedProperties","_a","isDecorative","showLabel","html","nothing","__decorateClass","property","state","customElement"],"mappings":";;;AAEO,MAAMA,IAAqBC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;;;;ACyB3B,IAAMC,IAAN,cAA2BC,EAAW;AAAA,EAAtC,cAAA;AAAA,UAAA,GAAA,SAAA,GAQL,KAAA,cAAyC,cAOzC,KAAA,UAAuC,MAQvC,KAAA,aAAa,IAYb,KAAQ,YAAY,IAapB,KAAQ,qBAAqB,CAAC,MAAmB;AAC/C,WAAK,WAAW,EAAE,MAAyB;AAAA,IAC7C;AAAA,EAAA;AAAA;AAAA,EAZQ,WAAWC,GAA6B;AAC9C,UAAMC,IAAQD,EAAK,cAAc,EAAE,SAAS,IAAM;AAClD,SAAK,YAAYC,EAAM;AAAA,MAAK,CAACC,MAC3BA,EAAK,aAAa,KAAK,aAClBA,EAAK,eAAe,IAAI,OAAO,SAAS,IACzCA,EAAK,aAAa,KAAK;AAAA,IAAA;AAAA,EAE/B;AAAA,EAOS,aAAaC,GAAgD;;AACpE,UAAM,aAAaA,CAAkB;AACrC,UAAMH,KAAOI,IAAA,KAAK,eAAL,gBAAAA,EAAiB,cAA+B;AAC7D,IAAIJ,KAAM,KAAK,WAAWA,CAAI,GAC1B,CAAC,KAAK,cAAc,CAAC,KAAK,SAAU,KAAK;AAAA,EAM/C;AAAA,EAES,SAAS;AAChB,UAAMK,IAAe,KAAK,YACpBC,IAAY,KAAK,aAAa,CAAC,CAAC,KAAK;AAE3C,WAAOC;AAAA;AAAA;AAAA,wBAGaD,IAAY,sBAAsB,EAAE;AAAA,gBAC5CD,IAAe,iBAAiB,WAAW;AAAA,4BAC/BA,IAAeG,IAAU,KAAK,WAAW;AAAA,sBAC/C,CAACH,KAAgB,KAAK,QAAQ,KAAK,QAAQG,CAAO;AAAA;AAAA;AAAA,UAG9DF,IACEC;AAAA,gBACI,KAAK,QAAQA,IAAO,KAAK,KAAK,KAAKC,CAAO;AAAA,kCACxB,KAAK,kBAAkB;AAAA,uBAE7CD,sBAAyB,KAAK,kBAAkB,UAAU;AAAA;AAAA;AAAA;AAAA,EAIpE;AACF;AAvFaT,EACK,SAAS,CAACF,CAAkB;AAO5Ca,EAAA;AAAA,EADCC,EAAS,EAAE,MAAM,QAAQ,SAAS,IAAM;AAAA,GAP9BZ,EAQX,WAAA,eAAA,CAAA;AAOAW,EAAA;AAAA,EADCC,EAAS,EAAE,MAAM,QAAQ,SAAS,IAAM;AAAA,GAd9BZ,EAeX,WAAA,WAAA,CAAA;AAQAW,EAAA;AAAA,EADCC,EAAS,EAAE,MAAM,SAAS,SAAS,IAAM;AAAA,GAtB/BZ,EAuBX,WAAA,cAAA,CAAA;AAQAW,EAAA;AAAA,EADCC,EAAS,EAAE,MAAM,QAAQ,SAAS,IAAM;AAAA,GA9B9BZ,EA+BX,WAAA,SAAA,CAAA;AAIQW,EAAA;AAAA,EADPE,EAAA;AAAM,GAlCIb,EAmCH,WAAA,aAAA,CAAA;AAnCGA,IAANW,EAAA;AAAA,EADNG,EAAc,YAAY;AAAA,GACdd,CAAA;"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { css as b, LitElement as v, html as h, nothing as w } from "lit";
|
|
2
|
-
import "./document-token-adoption-
|
|
2
|
+
import "./document-token-adoption-DuYNKd4k.js";
|
|
3
3
|
import { query as m, state as c, property as d, customElement as y } from "lit/decorators.js";
|
|
4
4
|
import { classMap as g } from "lit/directives/class-map.js";
|
|
5
5
|
import { ifDefined as p } from "lit/directives/if-defined.js";
|
|
@@ -589,4 +589,4 @@ a = o([
|
|
|
589
589
|
export {
|
|
590
590
|
a as H
|
|
591
591
|
};
|
|
592
|
-
//# sourceMappingURL=hx-drawer
|
|
592
|
+
//# sourceMappingURL=hx-drawer--WDLuWtS.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hx-drawer-C5qI7jf1.js","sources":["../../src/components/hx-drawer/hx-drawer.styles.ts","../../src/components/hx-drawer/hx-drawer.ts"],"sourcesContent":["import { css } from 'lit';\n\nexport const helixDrawerStyles = css`\n /* P2-03: Explicit [hidden] rule to survive CSS resets that may override the UA stylesheet. */\n [hidden] {\n display: none !important;\n }\n\n :host {\n display: contents;\n }\n\n :host([contained]) {\n display: block;\n position: relative;\n overflow: hidden;\n }\n\n /* ─── Overlay ─── */\n\n .drawer-overlay {\n position: fixed;\n inset: 0;\n z-index: var(--hx-z-index-modal, 1400);\n display: flex;\n pointer-events: none;\n visibility: hidden;\n }\n\n :host([contained]) .drawer-overlay {\n position: absolute;\n }\n\n .drawer-overlay.is-open {\n pointer-events: auto;\n visibility: visible;\n }\n\n /* ─── Backdrop ─── */\n\n .drawer-backdrop {\n position: absolute;\n inset: 0;\n background-color: var(--hx-drawer-backdrop-color, var(--hx-color-neutral-900));\n opacity: 0;\n transition: opacity var(--hx-duration-slow, 300ms) var(--hx-easing-out, ease-out);\n }\n\n .drawer-overlay.is-open .drawer-backdrop {\n opacity: var(--hx-drawer-backdrop-opacity, 0.5);\n }\n\n @media (prefers-reduced-motion: reduce) {\n .drawer-backdrop {\n transition: none;\n }\n }\n\n /* ─── Panel ─── */\n\n .drawer-panel {\n position: absolute;\n display: flex;\n flex-direction: column;\n background-color: var(--hx-drawer-bg, var(--hx-color-neutral-0));\n color: var(--hx-drawer-color, var(--hx-color-neutral-900));\n box-shadow: var(--hx-drawer-shadow, var(--hx-shadow-xl));\n overflow: hidden;\n outline: none;\n z-index: 1; /* local stacking context: panel above backdrop within overlay container */\n transition:\n transform var(--hx-duration-slow, 300ms) var(--hx-easing-out, ease-out),\n opacity var(--hx-duration-slow, 300ms) var(--hx-easing-out, ease-out);\n opacity: 0;\n }\n\n @media (prefers-reduced-motion: reduce) {\n .drawer-panel {\n transition: none;\n }\n\n .drawer-close-button {\n transition: none;\n }\n }\n\n /* ─── Placement: end (default — right) ─── */\n\n :host([placement='end']) .drawer-panel,\n :host(:not([placement])) .drawer-panel {\n top: 0;\n inset-inline-end: 0;\n bottom: 0;\n width: var(--_drawer-size, var(--hx-drawer-size-md, 30rem));\n max-width: 100%;\n transform: translateX(100%);\n }\n\n :host([placement='end']) .drawer-overlay.is-open .drawer-panel,\n :host(:not([placement])) .drawer-overlay.is-open .drawer-panel {\n transform: translateX(0);\n opacity: 1;\n }\n\n /* ─── Placement: start (left) ─── */\n\n :host([placement='start']) .drawer-panel {\n top: 0;\n inset-inline-start: 0;\n bottom: 0;\n width: var(--_drawer-size, var(--hx-drawer-size-md, 30rem));\n max-width: 100%;\n transform: translateX(-100%);\n }\n\n :host([placement='start']) .drawer-overlay.is-open .drawer-panel {\n transform: translateX(0);\n opacity: 1;\n }\n\n /* ─── Placement: top ─── */\n\n :host([placement='top']) .drawer-panel {\n top: 0;\n inset-inline-start: 0;\n inset-inline-end: 0;\n height: var(--_drawer-size, var(--hx-drawer-size-md, 30rem));\n max-height: 100%;\n width: 100%;\n transform: translateY(-100%);\n }\n\n :host([placement='top']) .drawer-overlay.is-open .drawer-panel {\n transform: translateY(0);\n opacity: 1;\n }\n\n /* ─── Placement: bottom ─── */\n\n :host([placement='bottom']) .drawer-panel {\n bottom: 0;\n inset-inline-start: 0;\n inset-inline-end: 0;\n height: var(--_drawer-size, var(--hx-drawer-size-md, 30rem));\n max-height: 100%;\n width: 100%;\n transform: translateY(100%);\n }\n\n :host([placement='bottom']) .drawer-overlay.is-open .drawer-panel {\n transform: translateY(0);\n opacity: 1;\n }\n\n /* ─── Header ─── */\n\n .drawer-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: var(--hx-space-4, 1rem);\n padding: var(--hx-drawer-header-padding, var(--hx-space-5, 1.25rem) var(--hx-space-6, 1.5rem));\n border-bottom: var(--hx-border-width-thin, 1px) solid\n var(--hx-drawer-header-border-color, var(--hx-color-neutral-200));\n flex-shrink: 0;\n }\n\n .drawer-title {\n margin: 0;\n flex: 1 1 auto;\n font-family: var(--hx-font-family-sans);\n font-size: var(--hx-font-size-lg);\n font-weight: var(--hx-font-weight-semibold);\n line-height: var(--hx-line-height-tight);\n color: var(--hx-drawer-title-color, var(--hx-color-neutral-900));\n }\n\n .drawer-header-actions {\n display: flex;\n align-items: center;\n gap: var(--hx-space-2, 0.5rem);\n flex-shrink: 0;\n }\n\n .drawer-close-button {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n /* WCAG 2.5.5 (healthcare mandate): minimum 44x44px touch target */\n min-width: var(--hx-touch-target-min, 2.75rem);\n min-height: var(--hx-touch-target-min, 2.75rem);\n width: var(--hx-touch-target-min, 2.75rem);\n height: var(--hx-touch-target-min, 2.75rem);\n padding: 0;\n border: none;\n border-radius: var(--hx-border-radius-md, 0.375rem);\n background: transparent;\n color: var(--hx-color-neutral-500);\n cursor: pointer;\n flex-shrink: 0;\n transition: background-color var(--hx-duration-fast, 100ms) var(--hx-easing-default, ease);\n }\n\n .drawer-close-button:hover {\n background-color: var(--hx-color-neutral-100);\n color: var(--hx-color-neutral-900);\n }\n\n .drawer-close-button:focus-visible {\n outline: var(--hx-focus-ring-width, 2px) solid\n var(\n --hx-drawer-close-btn-focus-ring-color,\n var(--hx-focus-ring-color, var(--hx-color-primary-500))\n );\n outline-offset: var(--hx-focus-ring-offset, 2px);\n }\n\n /* ─── Visually-hidden close button (no-header mode, WCAG 4.1.2) ─── */\n /* Keeps the button reachable by keyboard/AT but invisible to sighted users. */\n\n .drawer-close-button--sr-only {\n position: absolute;\n width: 1px;\n height: 1px;\n padding: 0;\n margin: -1px;\n overflow: hidden;\n clip: rect(0, 0, 0, 0);\n white-space: nowrap;\n border: 0;\n }\n\n /* When focused via keyboard, restore visibility so users know where focus is. */\n .drawer-close-button--sr-only:focus-visible {\n position: static;\n width: auto;\n height: auto;\n clip: auto;\n white-space: normal;\n overflow: visible;\n margin: 0;\n }\n\n /* ─── Body ─── */\n\n .drawer-body {\n flex: 1 1 auto;\n padding: var(--hx-drawer-body-padding, var(--hx-space-6, 1.5rem));\n overflow-y: auto;\n overscroll-behavior: contain;\n }\n\n /* ─── Footer ─── */\n\n .drawer-footer {\n display: flex;\n align-items: center;\n justify-content: flex-end;\n gap: var(--hx-space-3, 0.75rem);\n padding: var(--hx-drawer-footer-padding, var(--hx-space-4, 1rem) var(--hx-space-6, 1.5rem));\n border-top: var(--hx-border-width-thin, 1px) solid\n var(--hx-drawer-footer-border-color, var(--hx-color-neutral-200));\n flex-shrink: 0;\n }\n`;\n","import { LitElement, 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 { lockBodyScroll, unlockBodyScroll } from '../../utils/body-scroll-lock.js';\nimport { devWarn } from '../../utils/dev-warn.js';\nimport { helixDrawerStyles } from './hx-drawer.styles.js';\n\n// Module-level counter for stable, SSR-safe IDs (avoids Math.random() hydration mismatch)\nlet _hxDrawerIdCounter = 0;\n\ntype DrawerSizePreset = 'sm' | 'md' | 'lg' | 'full';\ntype DrawerSize = DrawerSizePreset | (string & Record<never, never>);\n\nconst DRAWER_SIZE_MAP: Record<DrawerSizePreset, string> = {\n sm: '20rem',\n md: '30rem',\n lg: '40rem',\n full: '100%',\n};\n\nconst FOCUSABLE_SELECTORS = [\n 'a[href]',\n 'area[href]',\n 'button:not([disabled])',\n 'input:not([disabled])',\n 'select:not([disabled])',\n 'textarea:not([disabled])',\n '[tabindex]:not([tabindex=\"-1\"])',\n 'details > summary',\n].join(',');\n\n/**\n * A slide-in drawer panel that can appear from any edge of the viewport.\n * Supports focus trapping, overlay backdrop, keyboard navigation, and full\n * ARIA labelling for enterprise healthcare accessibility requirements.\n *\n * @summary Slide-in panel overlay from any viewport edge.\n *\n * @tag hx-drawer\n *\n * @slot label - The drawer title text.\n * @slot header-actions - Action buttons displayed in the header near the close button.\n * @slot - Default slot for the drawer body content.\n * @slot footer - Action buttons or footer content.\n *\n * @fires {CustomEvent<void>} hx-show - Fired when the drawer begins to open.\n * @fires {CustomEvent<void>} hx-after-show - Fired after the drawer open animation completes.\n * @fires {CustomEvent<void>} hx-hide - Fired when the drawer begins to close.\n * @fires {CustomEvent<void>} hx-after-hide - Fired after the drawer close animation completes.\n * @fires {CustomEvent<void>} hx-initial-focus - Fired when initial focus is set inside the drawer. Cancelable to override focus behavior.\n *\n * @csspart overlay - The full-screen overlay container (includes backdrop and panel).\n * @csspart panel - The drawer panel itself.\n * @csspart header - The header region containing the title and actions.\n * @csspart title - The drawer title element.\n * @csspart close-button - The built-in close button.\n * @csspart close-btn - The visually-hidden close button rendered when noHeader is true.\n * @csspart body - The scrollable body region.\n * @csspart footer - The footer region.\n *\n * @attr [label] - Accessible label for the dialog when no visible label slot is provided.\n *\n * @cssprop [--hx-drawer-bg=var(--hx-color-neutral-0)] - Drawer panel background color.\n * @cssprop [--hx-drawer-color=var(--hx-color-neutral-900)] - Drawer panel text color.\n * @cssprop [--hx-drawer-shadow=var(--hx-shadow-xl)] - Drawer panel box shadow.\n * @cssprop [--hx-drawer-backdrop-color=var(--hx-color-neutral-900)] - Backdrop color.\n * @cssprop [--hx-drawer-backdrop-opacity=0.5] - Backdrop opacity.\n * @cssprop [--hx-drawer-header-padding] - Padding inside the header.\n * @cssprop [--hx-drawer-header-border-color=var(--hx-color-neutral-200)] - Header border color.\n * @cssprop [--hx-drawer-title-color=var(--hx-color-neutral-900)] - Title text color.\n * @cssprop [--hx-drawer-body-padding] - Padding inside the body.\n * @cssprop [--hx-drawer-footer-padding] - Padding inside the footer.\n * @cssprop [--hx-drawer-footer-border-color=var(--hx-color-neutral-200)] - Footer border color.\n */\n@customElement('hx-drawer')\nexport class HelixDrawer extends LitElement {\n static override styles = [helixDrawerStyles];\n\n // ─── Queries ───\n\n /**\n * Reference to the overlay element that wraps the backdrop and panel.\n * @internal\n */\n @query('.drawer-overlay')\n private _overlayEl: HTMLElement | null | undefined;\n\n /**\n * Reference to the drawer panel element used for focus management.\n * @internal\n */\n @query('.drawer-panel')\n private _panelEl: HTMLElement | null | undefined;\n\n // ─── Internal state ───\n\n /**\n * Whether the drawer is in the open state and visible to the user.\n * @internal\n */\n @state()\n private _isOpen = false;\n\n /**\n * Whether the header-actions slot has any assigned content.\n * @internal\n */\n @state()\n private _hasHeaderActionsSlot = false;\n\n /**\n * Whether the footer slot has any assigned content.\n * @internal\n */\n @state()\n private _hasFooterSlot = false;\n\n /**\n * Whether the label slot has any assigned content.\n * @internal\n */\n @state()\n private _hasLabelSlot = false;\n\n /**\n * Cached list of focusable elements within the drawer, used for focus trapping.\n * @internal\n */\n private _cachedFocusableElements: HTMLElement[] = [];\n /**\n * The element that triggered the drawer to open, restored focus when the drawer closes.\n * @internal\n */\n private _triggerElement: HTMLElement | null = null;\n /**\n * Handle for the pending animation end timeout, cleared when the drawer opens or closes again.\n * @internal\n */\n private _animationTimeout: ReturnType<typeof setTimeout> | null = null;\n /** Whether this drawer instance currently holds a body-scroll lock. */\n /** @internal */\n private _hasScrollLock = false;\n /**\n * Elements outside the drawer that were given aria-hidden during open, restored on close.\n * @internal\n */\n private _siblingAriaHiddenElements: Element[] = [];\n\n /**\n * Unique ID for the title element, used by aria-labelledby to link the dialog to its label.\n * @internal\n */\n private readonly _titleId = `hx-drawer-title-${++_hxDrawerIdCounter}`;\n\n // ─── Public Properties ───\n\n /**\n * Controls whether the drawer is open.\n * @attr open\n */\n @property({ type: Boolean, reflect: true })\n open = false;\n\n /**\n * Which edge of the viewport the drawer slides in from.\n * @attr placement\n */\n @property({ type: String, reflect: true })\n placement: 'start' | 'end' | 'top' | 'bottom' = 'end';\n\n /**\n * The size of the drawer panel. Use 'sm', 'md', 'lg', 'full', or any valid CSS length.\n * @attr hx-size\n */\n @property({ type: String, reflect: true, attribute: 'hx-size' })\n size: 'sm' | 'md' | 'lg' | 'full' | (string & Record<never, never>) = 'md';\n\n /**\n * When true, the drawer is constrained to its positioned parent instead of the viewport.\n * The host element must have `position: relative` (or the library handles it via :host).\n * @attr contained\n */\n @property({ type: Boolean, reflect: true })\n contained = false;\n\n /**\n * When true, the header (title, header-actions, close button) is hidden.\n * @attr no-header\n */\n @property({ type: Boolean, reflect: true, attribute: 'no-header' })\n noHeader = false;\n\n /**\n * When true, the footer slot is hidden.\n * @attr no-footer\n */\n @property({ type: Boolean, reflect: true, attribute: 'no-footer' })\n noFooter = false;\n\n /**\n * Accessible label for the dialog when the `label` slot is not populated.\n * When the `label` slot is used, `aria-labelledby` takes precedence.\n * @attr label\n */\n @property({ type: String })\n label = '';\n\n /** Accessible label for the built-in close button. Override for localized text. */\n @property({ type: String, attribute: 'label-close' })\n labelClose = 'Close drawer';\n\n // ─── Lifecycle ───\n\n override connectedCallback(): void {\n super.connectedCallback();\n // Backward compat: accept legacy `size` attribute. When present and `hx-size`\n // is not set, map the value and emit a deprecation warning.\n const legacySize = this.getAttribute('size');\n if (legacySize !== null && !this.hasAttribute('hx-size')) {\n devWarn('hx-drawer', 'The \"size\" attribute is deprecated. Use \"hx-size\" instead.');\n this.size = legacySize as DrawerSize;\n }\n }\n\n override disconnectedCallback(): void {\n super.disconnectedCallback();\n this._removeListeners();\n if (this._animationTimeout !== null) {\n clearTimeout(this._animationTimeout);\n }\n this._restoreBodyScroll();\n }\n\n override updated(changedProperties: PropertyValues<this>): void {\n super.updated(changedProperties);\n\n if (changedProperties.has('open')) {\n if (this.open) {\n this._openDrawer();\n } else {\n this._closeDrawer();\n }\n }\n\n if (changedProperties.has('size')) {\n this._applySizeVar();\n }\n }\n\n // ─── Public Methods ───\n\n /** Opens the drawer. */\n show(): void {\n this.open = true;\n }\n\n /** Closes the drawer. */\n hide(): void {\n this.open = false;\n }\n\n // ─── Private: Size CSS variable ───\n\n /** @internal */\n private _applySizeVar(): void {\n const resolvedSize = DRAWER_SIZE_MAP[this.size as DrawerSizePreset] ?? this.size;\n this.style.setProperty('--_drawer-size', resolvedSize);\n }\n\n // ─── Private: Open / Close ───\n\n /** @internal */\n private _lockBodyScroll(): void {\n if (this.contained || this._hasScrollLock) return;\n // Uses a shared reference-counted lock so that simultaneous hx-dialog / hx-drawer\n // instances don't clobber each other when one closes before the other\n // (see utils/body-scroll-lock.ts).\n lockBodyScroll();\n this._hasScrollLock = true;\n }\n\n /** @internal */\n private _restoreBodyScroll(): void {\n if (!this._hasScrollLock) return;\n unlockBodyScroll();\n this._hasScrollLock = false;\n }\n\n /** @internal */\n private _openDrawer(): void {\n // Capture trigger for focus restoration (P2-04: use instanceof guard)\n const active = document.activeElement;\n this._triggerElement = active instanceof HTMLElement ? active : null;\n\n // P1-05: clear any pending animation timeout before scheduling a new one\n if (this._animationTimeout !== null) {\n clearTimeout(this._animationTimeout);\n this._animationTimeout = null;\n }\n\n this._applySizeVar();\n this._lockBodyScroll();\n this._hideBackgroundFromScreenReaders();\n\n // Dispatch hx-show before visual update\n this.dispatchEvent(new CustomEvent<void>('hx-show', { bubbles: true, composed: true }));\n\n // Transition to open state\n void this.updateComplete\n .then(() => {\n this._isOpen = true;\n this._addListeners();\n\n // Set initial focus after next render\n return this.updateComplete;\n })\n .then(() => {\n this._cachedFocusableElements = this._getFocusableElements();\n this._setInitialFocus();\n\n // Dispatch hx-after-show after animation duration\n const duration = this._getAnimationDuration();\n this._animationTimeout = setTimeout(() => {\n this.dispatchEvent(\n new CustomEvent<void>('hx-after-show', { bubbles: true, composed: true }),\n );\n }, duration);\n })\n .catch(console.error);\n }\n\n /** @internal */\n private _closeDrawer(): void {\n // P1-05: clear any pending animation timeout before scheduling a new one\n if (this._animationTimeout !== null) {\n clearTimeout(this._animationTimeout);\n this._animationTimeout = null;\n }\n\n this._isOpen = false;\n this._removeListeners();\n this._cachedFocusableElements = [];\n this._restoreBodyScroll();\n this._restoreBackgroundForScreenReaders();\n\n this.dispatchEvent(new CustomEvent<void>('hx-hide', { bubbles: true, composed: true }));\n\n // Restore focus to the trigger immediately — before any animation timeout.\n // WCAG 2.4.3: focus must never remain on invisible or inert content.\n if (this._triggerElement && typeof this._triggerElement.focus === 'function') {\n this._triggerElement.focus();\n }\n this._triggerElement = null;\n\n // Animation cleanup only — no focus management inside this timeout.\n const duration = this._getAnimationDuration();\n this._animationTimeout = setTimeout(() => {\n this.dispatchEvent(new CustomEvent<void>('hx-after-hide', { bubbles: true, composed: true }));\n }, duration);\n }\n\n /** @internal */\n private _getAnimationDuration(): number {\n if (typeof window === 'undefined') return 0;\n if (window.matchMedia('(prefers-reduced-motion: reduce)').matches) return 0;\n return 300;\n }\n\n // ─── Background aria-hidden management (P1-03) ───\n\n /** @internal */\n private _hideBackgroundFromScreenReaders(): void {\n if (this.contained) return;\n this._siblingAriaHiddenElements = [];\n // Walk the parent chain once to find which body child is an ancestor of this component.\n // This avoids calling child.contains(this) in a loop (which is O(n * depth)).\n // Starting from parentElement avoids aliasing `this` to a local variable.\n let ancestorBodyChild: Element | null = null;\n let el: Element | null = this.parentElement;\n while (el && el.parentElement !== document.body) {\n el = el.parentElement;\n }\n if (el && el.parentElement === document.body) {\n ancestorBodyChild = el;\n }\n Array.from(document.body.children).forEach((child) => {\n if (child === this || child === ancestorBodyChild) return;\n if (!child.hasAttribute('aria-hidden')) {\n child.setAttribute('aria-hidden', 'true');\n this._siblingAriaHiddenElements.push(child);\n }\n });\n }\n\n /** @internal */\n private _restoreBackgroundForScreenReaders(): void {\n this._siblingAriaHiddenElements.forEach((el) => {\n el.removeAttribute('aria-hidden');\n });\n this._siblingAriaHiddenElements = [];\n }\n\n // ─── Event Listeners (P1-01: use only document listener, not overlay) ───\n\n /** @internal */\n private _addListeners(): void {\n document.addEventListener('keydown', this._handleKeyDown);\n }\n\n /** @internal */\n private _removeListeners(): void {\n document.removeEventListener('keydown', this._handleKeyDown);\n }\n\n // ─── Keyboard Handler ───\n\n /**\n * Handles keyboard events on the document to trap focus and close the drawer on Escape.\n * @internal\n */\n private _handleKeyDown = (e: KeyboardEvent): void => {\n if (!this._isOpen) return;\n\n if (e.key === 'Escape') {\n e.preventDefault();\n this.open = false;\n return;\n }\n\n if (e.key === 'Tab') {\n this._trapFocus(e);\n }\n };\n\n // ─── Focus ───\n\n /** @internal */\n private _setInitialFocus(): void {\n const event = new CustomEvent<void>('hx-initial-focus', {\n bubbles: true,\n composed: true,\n cancelable: true,\n });\n this.dispatchEvent(event);\n\n if (!event.defaultPrevented) {\n const focusable = this._cachedFocusableElements;\n if (focusable.length > 0 && focusable[0]) {\n focusable[0].focus();\n } else {\n this._panelEl?.focus();\n }\n }\n }\n\n /** @internal */\n private _getFocusableElements(): HTMLElement[] {\n const shadowFocusable = Array.from(\n this.shadowRoot?.querySelectorAll<HTMLElement>(FOCUSABLE_SELECTORS) ?? [],\n );\n\n const slots = this.shadowRoot?.querySelectorAll<HTMLSlotElement>('slot') ?? [];\n const lightFocusable: HTMLElement[] = [];\n\n slots.forEach((slot) => {\n slot.assignedElements({ flatten: true }).forEach((el) => {\n if (el instanceof HTMLElement) {\n if (el.matches(FOCUSABLE_SELECTORS)) {\n lightFocusable.push(el);\n }\n el.querySelectorAll<HTMLElement>(FOCUSABLE_SELECTORS).forEach((child) => {\n lightFocusable.push(child);\n });\n }\n });\n });\n\n return [...shadowFocusable, ...lightFocusable].filter(\n (el) => !el.hasAttribute('disabled') && el.getAttribute('tabindex') !== '-1',\n );\n }\n\n /** @internal */\n private _trapFocus(e: KeyboardEvent): void {\n const focusable =\n this._cachedFocusableElements.length > 0\n ? this._cachedFocusableElements\n : this._getFocusableElements();\n\n if (focusable.length === 0) {\n e.preventDefault();\n return;\n }\n\n const [first, ...rest] = focusable;\n const last = rest.length > 0 ? rest[rest.length - 1] : first;\n\n if (!first || !last) return;\n\n // P1-02: Use document.activeElement for reliable detection of slotted (light DOM) elements.\n // shadowRoot.activeElement returns the <slot> host for slotted content, not the actual element.\n const active = document.activeElement as HTMLElement | null;\n\n if (e.shiftKey) {\n if (active === first) {\n e.preventDefault();\n last.focus();\n }\n } else {\n if (active === last) {\n e.preventDefault();\n first.focus();\n }\n }\n }\n\n // ─── Overlay Click ───\n\n /**\n * Handles clicks on the overlay backdrop to close the drawer when the user clicks outside the panel.\n * @internal\n */\n private _handleOverlayClick = (e: MouseEvent): void => {\n // Only close when clicking the overlay itself (backdrop), not the panel\n const target = e.target as HTMLElement;\n if (target === this._overlayEl || target.classList.contains('drawer-backdrop')) {\n this.open = false;\n }\n };\n\n // ─── Slot change handlers ───\n\n /** @internal */\n private _handleHeaderActionsSlotChange(e: Event): void {\n const slot = e.target as HTMLSlotElement;\n this._hasHeaderActionsSlot = slot.assignedNodes({ flatten: true }).length > 0;\n }\n\n /** @internal */\n private _handleFooterSlotChange(e: Event): void {\n const slot = e.target as HTMLSlotElement;\n this._hasFooterSlot = slot.assignedNodes({ flatten: true }).length > 0;\n }\n\n /** @internal */\n private _handleLabelSlotChange(e: Event): void {\n const slot = e.target as HTMLSlotElement;\n this._hasLabelSlot = slot.assignedNodes({ flatten: true }).length > 0;\n }\n\n // ─── Render Helpers ───\n\n /** @internal */\n private _renderHeader() {\n if (this.noHeader) {\n // WCAG 4.1.2: When the header is hidden there must still be a reachable close\n // mechanism for keyboard and mouse/touch users. Render a visually-hidden close\n // button that is focusable and announced by screen readers.\n return html`\n <button\n part=\"close-btn\"\n class=\"drawer-close-button drawer-close-button--sr-only\"\n aria-label=${this.labelClose}\n @click=${() => {\n this.open = false;\n }}\n ></button>\n `;\n }\n\n return html`\n <div part=\"header\" class=\"drawer-header\">\n <h2 part=\"title\" id=${this._titleId} class=\"drawer-title\">\n <slot name=\"label\" @slotchange=${this._handleLabelSlotChange}></slot>\n </h2>\n <div class=\"drawer-header-actions\">\n ${this._hasHeaderActionsSlot\n ? html`<slot\n name=\"header-actions\"\n @slotchange=${this._handleHeaderActionsSlotChange}\n ></slot>`\n : html`<slot\n name=\"header-actions\"\n @slotchange=${this._handleHeaderActionsSlotChange}\n style=\"display:none\"\n ></slot>`}\n <button\n part=\"close-button\"\n class=\"drawer-close-button\"\n aria-label=${this.labelClose}\n @click=${() => {\n this.open = false;\n }}\n >\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"16\"\n height=\"16\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n aria-hidden=\"true\"\n >\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\"></line>\n <line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\"></line>\n </svg>\n </button>\n </div>\n </div>\n `;\n }\n\n /** @internal */\n private _renderFooter() {\n if (this.noFooter) return nothing;\n\n return html`\n <div part=\"footer\" class=\"drawer-footer\" ?hidden=${!this._hasFooterSlot}>\n <slot name=\"footer\" @slotchange=${this._handleFooterSlotChange}></slot>\n </div>\n `;\n }\n\n // ─── Render ───\n\n override render() {\n const overlayClasses = {\n 'drawer-overlay': true,\n 'is-open': this._isOpen,\n };\n\n // P1-06: ensure the dialog always has an accessible name.\n // Priority: aria-labelledby (slot) > aria-label (prop) > aria-label (fallback \"Drawer\")\n const ariaLabelledby = this._hasLabelSlot ? this._titleId : undefined;\n const ariaLabel = !this._hasLabelSlot ? this.label || 'Drawer' : undefined;\n\n return html`\n <div\n part=\"overlay\"\n class=${classMap(overlayClasses)}\n role=\"dialog\"\n aria-modal=\"true\"\n aria-labelledby=${ifDefined(ariaLabelledby)}\n aria-label=${ifDefined(ariaLabel)}\n tabindex=\"-1\"\n @click=${this._handleOverlayClick}\n >\n <div class=\"drawer-backdrop\" aria-hidden=\"true\"></div>\n <div part=\"panel\" class=\"drawer-panel\" tabindex=\"-1\">\n ${this._renderHeader()}\n <div part=\"body\" class=\"drawer-body\">\n <slot></slot>\n </div>\n ${this._renderFooter()}\n </div>\n </div>\n `;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'hx-drawer': HelixDrawer;\n }\n}\n"],"names":["helixDrawerStyles","css","_hxDrawerIdCounter","DRAWER_SIZE_MAP","FOCUSABLE_SELECTORS","HelixDrawer","LitElement","target","legacySize","changedProperties","resolvedSize","lockBodyScroll","unlockBodyScroll","active","duration","ancestorBodyChild","el","child","event","focusable","_a","shadowFocusable","slots","_b","lightFocusable","slot","first","rest","last","html","nothing","overlayClasses","ariaLabelledby","ariaLabel","classMap","ifDefined","__decorateClass","query","state","property","customElement"],"mappings":";;;;;;AAEO,MAAMA,IAAoBC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;A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"}
|
|
1
|
+
{"version":3,"file":"hx-drawer--WDLuWtS.js","sources":["../../src/components/hx-drawer/hx-drawer.styles.ts","../../src/components/hx-drawer/hx-drawer.ts"],"sourcesContent":["import { css } from 'lit';\n\nexport const helixDrawerStyles = css`\n /* P2-03: Explicit [hidden] rule to survive CSS resets that may override the UA stylesheet. */\n [hidden] {\n display: none !important;\n }\n\n :host {\n display: contents;\n }\n\n :host([contained]) {\n display: block;\n position: relative;\n overflow: hidden;\n }\n\n /* ─── Overlay ─── */\n\n .drawer-overlay {\n position: fixed;\n inset: 0;\n z-index: var(--hx-z-index-modal, 1400);\n display: flex;\n pointer-events: none;\n visibility: hidden;\n }\n\n :host([contained]) .drawer-overlay {\n position: absolute;\n }\n\n .drawer-overlay.is-open {\n pointer-events: auto;\n visibility: visible;\n }\n\n /* ─── Backdrop ─── */\n\n .drawer-backdrop {\n position: absolute;\n inset: 0;\n background-color: var(--hx-drawer-backdrop-color, var(--hx-color-neutral-900));\n opacity: 0;\n transition: opacity var(--hx-duration-slow, 300ms) var(--hx-easing-out, ease-out);\n }\n\n .drawer-overlay.is-open .drawer-backdrop {\n opacity: var(--hx-drawer-backdrop-opacity, 0.5);\n }\n\n @media (prefers-reduced-motion: reduce) {\n .drawer-backdrop {\n transition: none;\n }\n }\n\n /* ─── Panel ─── */\n\n .drawer-panel {\n position: absolute;\n display: flex;\n flex-direction: column;\n background-color: var(--hx-drawer-bg, var(--hx-color-neutral-0));\n color: var(--hx-drawer-color, var(--hx-color-neutral-900));\n box-shadow: var(--hx-drawer-shadow, var(--hx-shadow-xl));\n overflow: hidden;\n outline: none;\n z-index: 1; /* local stacking context: panel above backdrop within overlay container */\n transition:\n transform var(--hx-duration-slow, 300ms) var(--hx-easing-out, ease-out),\n opacity var(--hx-duration-slow, 300ms) var(--hx-easing-out, ease-out);\n opacity: 0;\n }\n\n @media (prefers-reduced-motion: reduce) {\n .drawer-panel {\n transition: none;\n }\n\n .drawer-close-button {\n transition: none;\n }\n }\n\n /* ─── Placement: end (default — right) ─── */\n\n :host([placement='end']) .drawer-panel,\n :host(:not([placement])) .drawer-panel {\n top: 0;\n inset-inline-end: 0;\n bottom: 0;\n width: var(--_drawer-size, var(--hx-drawer-size-md, 30rem));\n max-width: 100%;\n transform: translateX(100%);\n }\n\n :host([placement='end']) .drawer-overlay.is-open .drawer-panel,\n :host(:not([placement])) .drawer-overlay.is-open .drawer-panel {\n transform: translateX(0);\n opacity: 1;\n }\n\n /* ─── Placement: start (left) ─── */\n\n :host([placement='start']) .drawer-panel {\n top: 0;\n inset-inline-start: 0;\n bottom: 0;\n width: var(--_drawer-size, var(--hx-drawer-size-md, 30rem));\n max-width: 100%;\n transform: translateX(-100%);\n }\n\n :host([placement='start']) .drawer-overlay.is-open .drawer-panel {\n transform: translateX(0);\n opacity: 1;\n }\n\n /* ─── Placement: top ─── */\n\n :host([placement='top']) .drawer-panel {\n top: 0;\n inset-inline-start: 0;\n inset-inline-end: 0;\n height: var(--_drawer-size, var(--hx-drawer-size-md, 30rem));\n max-height: 100%;\n width: 100%;\n transform: translateY(-100%);\n }\n\n :host([placement='top']) .drawer-overlay.is-open .drawer-panel {\n transform: translateY(0);\n opacity: 1;\n }\n\n /* ─── Placement: bottom ─── */\n\n :host([placement='bottom']) .drawer-panel {\n bottom: 0;\n inset-inline-start: 0;\n inset-inline-end: 0;\n height: var(--_drawer-size, var(--hx-drawer-size-md, 30rem));\n max-height: 100%;\n width: 100%;\n transform: translateY(100%);\n }\n\n :host([placement='bottom']) .drawer-overlay.is-open .drawer-panel {\n transform: translateY(0);\n opacity: 1;\n }\n\n /* ─── Header ─── */\n\n .drawer-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: var(--hx-space-4, 1rem);\n padding: var(--hx-drawer-header-padding, var(--hx-space-5, 1.25rem) var(--hx-space-6, 1.5rem));\n border-bottom: var(--hx-border-width-thin, 1px) solid\n var(--hx-drawer-header-border-color, var(--hx-color-neutral-200));\n flex-shrink: 0;\n }\n\n .drawer-title {\n margin: 0;\n flex: 1 1 auto;\n font-family: var(--hx-font-family-sans);\n font-size: var(--hx-font-size-lg);\n font-weight: var(--hx-font-weight-semibold);\n line-height: var(--hx-line-height-tight);\n color: var(--hx-drawer-title-color, var(--hx-color-neutral-900));\n }\n\n .drawer-header-actions {\n display: flex;\n align-items: center;\n gap: var(--hx-space-2, 0.5rem);\n flex-shrink: 0;\n }\n\n .drawer-close-button {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n /* WCAG 2.5.5 (healthcare mandate): minimum 44x44px touch target */\n min-width: var(--hx-touch-target-min, 2.75rem);\n min-height: var(--hx-touch-target-min, 2.75rem);\n width: var(--hx-touch-target-min, 2.75rem);\n height: var(--hx-touch-target-min, 2.75rem);\n padding: 0;\n border: none;\n border-radius: var(--hx-border-radius-md, 0.375rem);\n background: transparent;\n color: var(--hx-color-neutral-500);\n cursor: pointer;\n flex-shrink: 0;\n transition: background-color var(--hx-duration-fast, 100ms) var(--hx-easing-default, ease);\n }\n\n .drawer-close-button:hover {\n background-color: var(--hx-color-neutral-100);\n color: var(--hx-color-neutral-900);\n }\n\n .drawer-close-button:focus-visible {\n outline: var(--hx-focus-ring-width, 2px) solid\n var(\n --hx-drawer-close-btn-focus-ring-color,\n var(--hx-focus-ring-color, var(--hx-color-primary-500))\n );\n outline-offset: var(--hx-focus-ring-offset, 2px);\n }\n\n /* ─── Visually-hidden close button (no-header mode, WCAG 4.1.2) ─── */\n /* Keeps the button reachable by keyboard/AT but invisible to sighted users. */\n\n .drawer-close-button--sr-only {\n position: absolute;\n width: 1px;\n height: 1px;\n padding: 0;\n margin: -1px;\n overflow: hidden;\n clip: rect(0, 0, 0, 0);\n white-space: nowrap;\n border: 0;\n }\n\n /* When focused via keyboard, restore visibility so users know where focus is. */\n .drawer-close-button--sr-only:focus-visible {\n position: static;\n width: auto;\n height: auto;\n clip: auto;\n white-space: normal;\n overflow: visible;\n margin: 0;\n }\n\n /* ─── Body ─── */\n\n .drawer-body {\n flex: 1 1 auto;\n padding: var(--hx-drawer-body-padding, var(--hx-space-6, 1.5rem));\n overflow-y: auto;\n overscroll-behavior: contain;\n }\n\n /* ─── Footer ─── */\n\n .drawer-footer {\n display: flex;\n align-items: center;\n justify-content: flex-end;\n gap: var(--hx-space-3, 0.75rem);\n padding: var(--hx-drawer-footer-padding, var(--hx-space-4, 1rem) var(--hx-space-6, 1.5rem));\n border-top: var(--hx-border-width-thin, 1px) solid\n var(--hx-drawer-footer-border-color, var(--hx-color-neutral-200));\n flex-shrink: 0;\n }\n`;\n","import { LitElement, 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 { lockBodyScroll, unlockBodyScroll } from '../../utils/body-scroll-lock.js';\nimport { devWarn } from '../../utils/dev-warn.js';\nimport { helixDrawerStyles } from './hx-drawer.styles.js';\n\n// Module-level counter for stable, SSR-safe IDs (avoids Math.random() hydration mismatch)\nlet _hxDrawerIdCounter = 0;\n\ntype DrawerSizePreset = 'sm' | 'md' | 'lg' | 'full';\ntype DrawerSize = DrawerSizePreset | (string & Record<never, never>);\n\nconst DRAWER_SIZE_MAP: Record<DrawerSizePreset, string> = {\n sm: '20rem',\n md: '30rem',\n lg: '40rem',\n full: '100%',\n};\n\nconst FOCUSABLE_SELECTORS = [\n 'a[href]',\n 'area[href]',\n 'button:not([disabled])',\n 'input:not([disabled])',\n 'select:not([disabled])',\n 'textarea:not([disabled])',\n '[tabindex]:not([tabindex=\"-1\"])',\n 'details > summary',\n].join(',');\n\n/**\n * A slide-in drawer panel that can appear from any edge of the viewport.\n * Supports focus trapping, overlay backdrop, keyboard navigation, and full\n * ARIA labelling for enterprise healthcare accessibility requirements.\n *\n * @summary Slide-in panel overlay from any viewport edge.\n *\n * @tag hx-drawer\n *\n * @slot label - The drawer title text.\n * @slot header-actions - Action buttons displayed in the header near the close button.\n * @slot - Default slot for the drawer body content.\n * @slot footer - Action buttons or footer content.\n *\n * @fires {CustomEvent<void>} hx-show - Fired when the drawer begins to open.\n * @fires {CustomEvent<void>} hx-after-show - Fired after the drawer open animation completes.\n * @fires {CustomEvent<void>} hx-hide - Fired when the drawer begins to close.\n * @fires {CustomEvent<void>} hx-after-hide - Fired after the drawer close animation completes.\n * @fires {CustomEvent<void>} hx-initial-focus - Fired when initial focus is set inside the drawer. Cancelable to override focus behavior.\n *\n * @csspart overlay - The full-screen overlay container (includes backdrop and panel).\n * @csspart panel - The drawer panel itself.\n * @csspart header - The header region containing the title and actions.\n * @csspart title - The drawer title element.\n * @csspart close-button - The built-in close button.\n * @csspart close-btn - The visually-hidden close button rendered when noHeader is true.\n * @csspart body - The scrollable body region.\n * @csspart footer - The footer region.\n *\n * @attr [label] - Accessible label for the dialog when no visible label slot is provided.\n *\n * @cssprop [--hx-drawer-bg=var(--hx-color-neutral-0)] - Drawer panel background color.\n * @cssprop [--hx-drawer-color=var(--hx-color-neutral-900)] - Drawer panel text color.\n * @cssprop [--hx-drawer-shadow=var(--hx-shadow-xl)] - Drawer panel box shadow.\n * @cssprop [--hx-drawer-backdrop-color=var(--hx-color-neutral-900)] - Backdrop color.\n * @cssprop [--hx-drawer-backdrop-opacity=0.5] - Backdrop opacity.\n * @cssprop [--hx-drawer-header-padding] - Padding inside the header.\n * @cssprop [--hx-drawer-header-border-color=var(--hx-color-neutral-200)] - Header border color.\n * @cssprop [--hx-drawer-title-color=var(--hx-color-neutral-900)] - Title text color.\n * @cssprop [--hx-drawer-body-padding] - Padding inside the body.\n * @cssprop [--hx-drawer-footer-padding] - Padding inside the footer.\n * @cssprop [--hx-drawer-footer-border-color=var(--hx-color-neutral-200)] - Footer border color.\n */\n@customElement('hx-drawer')\nexport class HelixDrawer extends LitElement {\n static override styles = [helixDrawerStyles];\n\n // ─── Queries ───\n\n /**\n * Reference to the overlay element that wraps the backdrop and panel.\n * @internal\n */\n @query('.drawer-overlay')\n private _overlayEl: HTMLElement | null | undefined;\n\n /**\n * Reference to the drawer panel element used for focus management.\n * @internal\n */\n @query('.drawer-panel')\n private _panelEl: HTMLElement | null | undefined;\n\n // ─── Internal state ───\n\n /**\n * Whether the drawer is in the open state and visible to the user.\n * @internal\n */\n @state()\n private _isOpen = false;\n\n /**\n * Whether the header-actions slot has any assigned content.\n * @internal\n */\n @state()\n private _hasHeaderActionsSlot = false;\n\n /**\n * Whether the footer slot has any assigned content.\n * @internal\n */\n @state()\n private _hasFooterSlot = false;\n\n /**\n * Whether the label slot has any assigned content.\n * @internal\n */\n @state()\n private _hasLabelSlot = false;\n\n /**\n * Cached list of focusable elements within the drawer, used for focus trapping.\n * @internal\n */\n private _cachedFocusableElements: HTMLElement[] = [];\n /**\n * The element that triggered the drawer to open, restored focus when the drawer closes.\n * @internal\n */\n private _triggerElement: HTMLElement | null = null;\n /**\n * Handle for the pending animation end timeout, cleared when the drawer opens or closes again.\n * @internal\n */\n private _animationTimeout: ReturnType<typeof setTimeout> | null = null;\n /** Whether this drawer instance currently holds a body-scroll lock. */\n /** @internal */\n private _hasScrollLock = false;\n /**\n * Elements outside the drawer that were given aria-hidden during open, restored on close.\n * @internal\n */\n private _siblingAriaHiddenElements: Element[] = [];\n\n /**\n * Unique ID for the title element, used by aria-labelledby to link the dialog to its label.\n * @internal\n */\n private readonly _titleId = `hx-drawer-title-${++_hxDrawerIdCounter}`;\n\n // ─── Public Properties ───\n\n /**\n * Controls whether the drawer is open.\n * @attr open\n */\n @property({ type: Boolean, reflect: true })\n open = false;\n\n /**\n * Which edge of the viewport the drawer slides in from.\n * @attr placement\n */\n @property({ type: String, reflect: true })\n placement: 'start' | 'end' | 'top' | 'bottom' = 'end';\n\n /**\n * The size of the drawer panel. Use 'sm', 'md', 'lg', 'full', or any valid CSS length.\n * @attr hx-size\n */\n @property({ type: String, reflect: true, attribute: 'hx-size' })\n size: 'sm' | 'md' | 'lg' | 'full' | (string & Record<never, never>) = 'md';\n\n /**\n * When true, the drawer is constrained to its positioned parent instead of the viewport.\n * The host element must have `position: relative` (or the library handles it via :host).\n * @attr contained\n */\n @property({ type: Boolean, reflect: true })\n contained = false;\n\n /**\n * When true, the header (title, header-actions, close button) is hidden.\n * @attr no-header\n */\n @property({ type: Boolean, reflect: true, attribute: 'no-header' })\n noHeader = false;\n\n /**\n * When true, the footer slot is hidden.\n * @attr no-footer\n */\n @property({ type: Boolean, reflect: true, attribute: 'no-footer' })\n noFooter = false;\n\n /**\n * Accessible label for the dialog when the `label` slot is not populated.\n * When the `label` slot is used, `aria-labelledby` takes precedence.\n * @attr label\n */\n @property({ type: String })\n label = '';\n\n /** Accessible label for the built-in close button. Override for localized text. */\n @property({ type: String, attribute: 'label-close' })\n labelClose = 'Close drawer';\n\n // ─── Lifecycle ───\n\n override connectedCallback(): void {\n super.connectedCallback();\n // Backward compat: accept legacy `size` attribute. When present and `hx-size`\n // is not set, map the value and emit a deprecation warning.\n const legacySize = this.getAttribute('size');\n if (legacySize !== null && !this.hasAttribute('hx-size')) {\n devWarn('hx-drawer', 'The \"size\" attribute is deprecated. Use \"hx-size\" instead.');\n this.size = legacySize as DrawerSize;\n }\n }\n\n override disconnectedCallback(): void {\n super.disconnectedCallback();\n this._removeListeners();\n if (this._animationTimeout !== null) {\n clearTimeout(this._animationTimeout);\n }\n this._restoreBodyScroll();\n }\n\n override updated(changedProperties: PropertyValues<this>): void {\n super.updated(changedProperties);\n\n if (changedProperties.has('open')) {\n if (this.open) {\n this._openDrawer();\n } else {\n this._closeDrawer();\n }\n }\n\n if (changedProperties.has('size')) {\n this._applySizeVar();\n }\n }\n\n // ─── Public Methods ───\n\n /** Opens the drawer. */\n show(): void {\n this.open = true;\n }\n\n /** Closes the drawer. */\n hide(): void {\n this.open = false;\n }\n\n // ─── Private: Size CSS variable ───\n\n /** @internal */\n private _applySizeVar(): void {\n const resolvedSize = DRAWER_SIZE_MAP[this.size as DrawerSizePreset] ?? this.size;\n this.style.setProperty('--_drawer-size', resolvedSize);\n }\n\n // ─── Private: Open / Close ───\n\n /** @internal */\n private _lockBodyScroll(): void {\n if (this.contained || this._hasScrollLock) return;\n // Uses a shared reference-counted lock so that simultaneous hx-dialog / hx-drawer\n // instances don't clobber each other when one closes before the other\n // (see utils/body-scroll-lock.ts).\n lockBodyScroll();\n this._hasScrollLock = true;\n }\n\n /** @internal */\n private _restoreBodyScroll(): void {\n if (!this._hasScrollLock) return;\n unlockBodyScroll();\n this._hasScrollLock = false;\n }\n\n /** @internal */\n private _openDrawer(): void {\n // Capture trigger for focus restoration (P2-04: use instanceof guard)\n const active = document.activeElement;\n this._triggerElement = active instanceof HTMLElement ? active : null;\n\n // P1-05: clear any pending animation timeout before scheduling a new one\n if (this._animationTimeout !== null) {\n clearTimeout(this._animationTimeout);\n this._animationTimeout = null;\n }\n\n this._applySizeVar();\n this._lockBodyScroll();\n this._hideBackgroundFromScreenReaders();\n\n // Dispatch hx-show before visual update\n this.dispatchEvent(new CustomEvent<void>('hx-show', { bubbles: true, composed: true }));\n\n // Transition to open state\n void this.updateComplete\n .then(() => {\n this._isOpen = true;\n this._addListeners();\n\n // Set initial focus after next render\n return this.updateComplete;\n })\n .then(() => {\n this._cachedFocusableElements = this._getFocusableElements();\n this._setInitialFocus();\n\n // Dispatch hx-after-show after animation duration\n const duration = this._getAnimationDuration();\n this._animationTimeout = setTimeout(() => {\n this.dispatchEvent(\n new CustomEvent<void>('hx-after-show', { bubbles: true, composed: true }),\n );\n }, duration);\n })\n .catch(console.error);\n }\n\n /** @internal */\n private _closeDrawer(): void {\n // P1-05: clear any pending animation timeout before scheduling a new one\n if (this._animationTimeout !== null) {\n clearTimeout(this._animationTimeout);\n this._animationTimeout = null;\n }\n\n this._isOpen = false;\n this._removeListeners();\n this._cachedFocusableElements = [];\n this._restoreBodyScroll();\n this._restoreBackgroundForScreenReaders();\n\n this.dispatchEvent(new CustomEvent<void>('hx-hide', { bubbles: true, composed: true }));\n\n // Restore focus to the trigger immediately — before any animation timeout.\n // WCAG 2.4.3: focus must never remain on invisible or inert content.\n if (this._triggerElement && typeof this._triggerElement.focus === 'function') {\n this._triggerElement.focus();\n }\n this._triggerElement = null;\n\n // Animation cleanup only — no focus management inside this timeout.\n const duration = this._getAnimationDuration();\n this._animationTimeout = setTimeout(() => {\n this.dispatchEvent(new CustomEvent<void>('hx-after-hide', { bubbles: true, composed: true }));\n }, duration);\n }\n\n /** @internal */\n private _getAnimationDuration(): number {\n if (typeof window === 'undefined') return 0;\n if (window.matchMedia('(prefers-reduced-motion: reduce)').matches) return 0;\n return 300;\n }\n\n // ─── Background aria-hidden management (P1-03) ───\n\n /** @internal */\n private _hideBackgroundFromScreenReaders(): void {\n if (this.contained) return;\n this._siblingAriaHiddenElements = [];\n // Walk the parent chain once to find which body child is an ancestor of this component.\n // This avoids calling child.contains(this) in a loop (which is O(n * depth)).\n // Starting from parentElement avoids aliasing `this` to a local variable.\n let ancestorBodyChild: Element | null = null;\n let el: Element | null = this.parentElement;\n while (el && el.parentElement !== document.body) {\n el = el.parentElement;\n }\n if (el && el.parentElement === document.body) {\n ancestorBodyChild = el;\n }\n Array.from(document.body.children).forEach((child) => {\n if (child === this || child === ancestorBodyChild) return;\n if (!child.hasAttribute('aria-hidden')) {\n child.setAttribute('aria-hidden', 'true');\n this._siblingAriaHiddenElements.push(child);\n }\n });\n }\n\n /** @internal */\n private _restoreBackgroundForScreenReaders(): void {\n this._siblingAriaHiddenElements.forEach((el) => {\n el.removeAttribute('aria-hidden');\n });\n this._siblingAriaHiddenElements = [];\n }\n\n // ─── Event Listeners (P1-01: use only document listener, not overlay) ───\n\n /** @internal */\n private _addListeners(): void {\n document.addEventListener('keydown', this._handleKeyDown);\n }\n\n /** @internal */\n private _removeListeners(): void {\n document.removeEventListener('keydown', this._handleKeyDown);\n }\n\n // ─── Keyboard Handler ───\n\n /**\n * Handles keyboard events on the document to trap focus and close the drawer on Escape.\n * @internal\n */\n private _handleKeyDown = (e: KeyboardEvent): void => {\n if (!this._isOpen) return;\n\n if (e.key === 'Escape') {\n e.preventDefault();\n this.open = false;\n return;\n }\n\n if (e.key === 'Tab') {\n this._trapFocus(e);\n }\n };\n\n // ─── Focus ───\n\n /** @internal */\n private _setInitialFocus(): void {\n const event = new CustomEvent<void>('hx-initial-focus', {\n bubbles: true,\n composed: true,\n cancelable: true,\n });\n this.dispatchEvent(event);\n\n if (!event.defaultPrevented) {\n const focusable = this._cachedFocusableElements;\n if (focusable.length > 0 && focusable[0]) {\n focusable[0].focus();\n } else {\n this._panelEl?.focus();\n }\n }\n }\n\n /** @internal */\n private _getFocusableElements(): HTMLElement[] {\n const shadowFocusable = Array.from(\n this.shadowRoot?.querySelectorAll<HTMLElement>(FOCUSABLE_SELECTORS) ?? [],\n );\n\n const slots = this.shadowRoot?.querySelectorAll<HTMLSlotElement>('slot') ?? [];\n const lightFocusable: HTMLElement[] = [];\n\n slots.forEach((slot) => {\n slot.assignedElements({ flatten: true }).forEach((el) => {\n if (el instanceof HTMLElement) {\n if (el.matches(FOCUSABLE_SELECTORS)) {\n lightFocusable.push(el);\n }\n el.querySelectorAll<HTMLElement>(FOCUSABLE_SELECTORS).forEach((child) => {\n lightFocusable.push(child);\n });\n }\n });\n });\n\n return [...shadowFocusable, ...lightFocusable].filter(\n (el) => !el.hasAttribute('disabled') && el.getAttribute('tabindex') !== '-1',\n );\n }\n\n /** @internal */\n private _trapFocus(e: KeyboardEvent): void {\n const focusable =\n this._cachedFocusableElements.length > 0\n ? this._cachedFocusableElements\n : this._getFocusableElements();\n\n if (focusable.length === 0) {\n e.preventDefault();\n return;\n }\n\n const [first, ...rest] = focusable;\n const last = rest.length > 0 ? rest[rest.length - 1] : first;\n\n if (!first || !last) return;\n\n // P1-02: Use document.activeElement for reliable detection of slotted (light DOM) elements.\n // shadowRoot.activeElement returns the <slot> host for slotted content, not the actual element.\n const active = document.activeElement as HTMLElement | null;\n\n if (e.shiftKey) {\n if (active === first) {\n e.preventDefault();\n last.focus();\n }\n } else {\n if (active === last) {\n e.preventDefault();\n first.focus();\n }\n }\n }\n\n // ─── Overlay Click ───\n\n /**\n * Handles clicks on the overlay backdrop to close the drawer when the user clicks outside the panel.\n * @internal\n */\n private _handleOverlayClick = (e: MouseEvent): void => {\n // Only close when clicking the overlay itself (backdrop), not the panel\n const target = e.target as HTMLElement;\n if (target === this._overlayEl || target.classList.contains('drawer-backdrop')) {\n this.open = false;\n }\n };\n\n // ─── Slot change handlers ───\n\n /** @internal */\n private _handleHeaderActionsSlotChange(e: Event): void {\n const slot = e.target as HTMLSlotElement;\n this._hasHeaderActionsSlot = slot.assignedNodes({ flatten: true }).length > 0;\n }\n\n /** @internal */\n private _handleFooterSlotChange(e: Event): void {\n const slot = e.target as HTMLSlotElement;\n this._hasFooterSlot = slot.assignedNodes({ flatten: true }).length > 0;\n }\n\n /** @internal */\n private _handleLabelSlotChange(e: Event): void {\n const slot = e.target as HTMLSlotElement;\n this._hasLabelSlot = slot.assignedNodes({ flatten: true }).length > 0;\n }\n\n // ─── Render Helpers ───\n\n /** @internal */\n private _renderHeader() {\n if (this.noHeader) {\n // WCAG 4.1.2: When the header is hidden there must still be a reachable close\n // mechanism for keyboard and mouse/touch users. Render a visually-hidden close\n // button that is focusable and announced by screen readers.\n return html`\n <button\n part=\"close-btn\"\n class=\"drawer-close-button drawer-close-button--sr-only\"\n aria-label=${this.labelClose}\n @click=${() => {\n this.open = false;\n }}\n ></button>\n `;\n }\n\n return html`\n <div part=\"header\" class=\"drawer-header\">\n <h2 part=\"title\" id=${this._titleId} class=\"drawer-title\">\n <slot name=\"label\" @slotchange=${this._handleLabelSlotChange}></slot>\n </h2>\n <div class=\"drawer-header-actions\">\n ${this._hasHeaderActionsSlot\n ? html`<slot\n name=\"header-actions\"\n @slotchange=${this._handleHeaderActionsSlotChange}\n ></slot>`\n : html`<slot\n name=\"header-actions\"\n @slotchange=${this._handleHeaderActionsSlotChange}\n style=\"display:none\"\n ></slot>`}\n <button\n part=\"close-button\"\n class=\"drawer-close-button\"\n aria-label=${this.labelClose}\n @click=${() => {\n this.open = false;\n }}\n >\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"16\"\n height=\"16\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n aria-hidden=\"true\"\n >\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\"></line>\n <line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\"></line>\n </svg>\n </button>\n </div>\n </div>\n `;\n }\n\n /** @internal */\n private _renderFooter() {\n if (this.noFooter) return nothing;\n\n return html`\n <div part=\"footer\" class=\"drawer-footer\" ?hidden=${!this._hasFooterSlot}>\n <slot name=\"footer\" @slotchange=${this._handleFooterSlotChange}></slot>\n </div>\n `;\n }\n\n // ─── Render ───\n\n override render() {\n const overlayClasses = {\n 'drawer-overlay': true,\n 'is-open': this._isOpen,\n };\n\n // P1-06: ensure the dialog always has an accessible name.\n // Priority: aria-labelledby (slot) > aria-label (prop) > aria-label (fallback \"Drawer\")\n const ariaLabelledby = this._hasLabelSlot ? this._titleId : undefined;\n const ariaLabel = !this._hasLabelSlot ? this.label || 'Drawer' : undefined;\n\n return html`\n <div\n part=\"overlay\"\n class=${classMap(overlayClasses)}\n role=\"dialog\"\n aria-modal=\"true\"\n aria-labelledby=${ifDefined(ariaLabelledby)}\n aria-label=${ifDefined(ariaLabel)}\n tabindex=\"-1\"\n @click=${this._handleOverlayClick}\n >\n <div class=\"drawer-backdrop\" aria-hidden=\"true\"></div>\n <div part=\"panel\" class=\"drawer-panel\" tabindex=\"-1\">\n ${this._renderHeader()}\n <div part=\"body\" class=\"drawer-body\">\n <slot></slot>\n </div>\n ${this._renderFooter()}\n </div>\n </div>\n `;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'hx-drawer': HelixDrawer;\n }\n}\n"],"names":["helixDrawerStyles","css","_hxDrawerIdCounter","DRAWER_SIZE_MAP","FOCUSABLE_SELECTORS","HelixDrawer","LitElement","target","legacySize","changedProperties","resolvedSize","lockBodyScroll","unlockBodyScroll","active","duration","ancestorBodyChild","el","child","event","focusable","_a","shadowFocusable","slots","_b","lightFocusable","slot","first","rest","last","html","nothing","overlayClasses","ariaLabelledby","ariaLabel","classMap","ifDefined","__decorateClass","query","state","property","customElement"],"mappings":";;;;;;AAEO,MAAMA,IAAoBC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;;;;ACQjC,IAAIC,IAAqB;AAKzB,MAAMC,IAAoD;AAAA,EACxD,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,MAAM;AACR,GAEMC,IAAsB;AAAA,EAC1B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,EAAE,KAAK,GAAG;AA8CH,IAAMC,IAAN,cAA0BC,EAAW;AAAA,EAArC,cAAA;AAAA,UAAA,GAAA,SAAA,GA0BL,KAAQ,UAAU,IAOlB,KAAQ,wBAAwB,IAOhC,KAAQ,iBAAiB,IAOzB,KAAQ,gBAAgB,IAMxB,KAAQ,2BAA0C,CAAA,GAKlD,KAAQ,kBAAsC,MAK9C,KAAQ,oBAA0D,MAGlE,KAAQ,iBAAiB,IAKzB,KAAQ,6BAAwC,CAAA,GAMhD,KAAiB,WAAW,mBAAmB,EAAEJ,CAAkB,IASnE,KAAA,OAAO,IAOP,KAAA,YAAgD,OAOhD,KAAA,OAAsE,MAQtE,KAAA,YAAY,IAOZ,KAAA,WAAW,IAOX,KAAA,WAAW,IAQX,KAAA,QAAQ,IAIR,KAAA,aAAa,gBAmNb,KAAQ,iBAAiB,CAAC,MAA2B;AACnD,UAAK,KAAK,SAEV;AAAA,YAAI,EAAE,QAAQ,UAAU;AACtB,YAAE,eAAA,GACF,KAAK,OAAO;AACZ;AAAA,QACF;AAEA,QAAI,EAAE,QAAQ,SACZ,KAAK,WAAW,CAAC;AAAA;AAAA,IAErB,GA0FA,KAAQ,sBAAsB,CAAC,MAAwB;AAErD,YAAMK,IAAS,EAAE;AACjB,OAAIA,MAAW,KAAK,cAAcA,EAAO,UAAU,SAAS,iBAAiB,OAC3E,KAAK,OAAO;AAAA,IAEhB;AAAA,EAAA;AAAA;AAAA,EA3TS,oBAA0B;AACjC,UAAM,kBAAA;AAGN,UAAMC,IAAa,KAAK,aAAa,MAAM;AAC3C,IAAIA,MAAe,QAAQ,CAAC,KAAK,aAAa,SAAS,MAErD,KAAK,OAAOA;AAAA,EAEhB;AAAA,EAES,uBAA6B;AACpC,UAAM,qBAAA,GACN,KAAK,iBAAA,GACD,KAAK,sBAAsB,QAC7B,aAAa,KAAK,iBAAiB,GAErC,KAAK,mBAAA;AAAA,EACP;AAAA,EAES,QAAQC,GAA+C;AAC9D,UAAM,QAAQA,CAAiB,GAE3BA,EAAkB,IAAI,MAAM,MAC1B,KAAK,OACP,KAAK,YAAA,IAEL,KAAK,aAAA,IAILA,EAAkB,IAAI,MAAM,KAC9B,KAAK,cAAA;AAAA,EAET;AAAA;AAAA;AAAA,EAKA,OAAa;AACX,SAAK,OAAO;AAAA,EACd;AAAA;AAAA,EAGA,OAAa;AACX,SAAK,OAAO;AAAA,EACd;AAAA;AAAA;AAAA,EAKQ,gBAAsB;AAC5B,UAAMC,IAAeP,EAAgB,KAAK,IAAwB,KAAK,KAAK;AAC5E,SAAK,MAAM,YAAY,kBAAkBO,CAAY;AAAA,EACvD;AAAA;AAAA;AAAA,EAKQ,kBAAwB;AAC9B,IAAI,KAAK,aAAa,KAAK,mBAI3BC,EAAA,GACA,KAAK,iBAAiB;AAAA,EACxB;AAAA;AAAA,EAGQ,qBAA2B;AACjC,IAAK,KAAK,mBACVC,EAAA,GACA,KAAK,iBAAiB;AAAA,EACxB;AAAA;AAAA,EAGQ,cAAoB;AAE1B,UAAMC,IAAS,SAAS;AACxB,SAAK,kBAAkBA,aAAkB,cAAcA,IAAS,MAG5D,KAAK,sBAAsB,SAC7B,aAAa,KAAK,iBAAiB,GACnC,KAAK,oBAAoB,OAG3B,KAAK,cAAA,GACL,KAAK,gBAAA,GACL,KAAK,iCAAA,GAGL,KAAK,cAAc,IAAI,YAAkB,WAAW,EAAE,SAAS,IAAM,UAAU,GAAA,CAAM,CAAC,GAGjF,KAAK,eACP,KAAK,OACJ,KAAK,UAAU,IACf,KAAK,cAAA,GAGE,KAAK,eACb,EACA,KAAK,MAAM;AACV,WAAK,2BAA2B,KAAK,sBAAA,GACrC,KAAK,iBAAA;AAGL,YAAMC,IAAW,KAAK,sBAAA;AACtB,WAAK,oBAAoB,WAAW,MAAM;AACxC,aAAK;AAAA,UACH,IAAI,YAAkB,iBAAiB,EAAE,SAAS,IAAM,UAAU,IAAM;AAAA,QAAA;AAAA,MAE5E,GAAGA,CAAQ;AAAA,IACb,CAAC,EACA,MAAM,QAAQ,KAAK;AAAA,EACxB;AAAA;AAAA,EAGQ,eAAqB;AAE3B,IAAI,KAAK,sBAAsB,SAC7B,aAAa,KAAK,iBAAiB,GACnC,KAAK,oBAAoB,OAG3B,KAAK,UAAU,IACf,KAAK,iBAAA,GACL,KAAK,2BAA2B,CAAA,GAChC,KAAK,mBAAA,GACL,KAAK,mCAAA,GAEL,KAAK,cAAc,IAAI,YAAkB,WAAW,EAAE,SAAS,IAAM,UAAU,GAAA,CAAM,CAAC,GAIlF,KAAK,mBAAmB,OAAO,KAAK,gBAAgB,SAAU,cAChE,KAAK,gBAAgB,MAAA,GAEvB,KAAK,kBAAkB;AAGvB,UAAMA,IAAW,KAAK,sBAAA;AACtB,SAAK,oBAAoB,WAAW,MAAM;AACxC,WAAK,cAAc,IAAI,YAAkB,iBAAiB,EAAE,SAAS,IAAM,UAAU,GAAA,CAAM,CAAC;AAAA,IAC9F,GAAGA,CAAQ;AAAA,EACb;AAAA;AAAA,EAGQ,wBAAgC;AAEtC,WADI,OAAO,SAAW,OAClB,OAAO,WAAW,kCAAkC,EAAE,UAAgB,IACnE;AAAA,EACT;AAAA;AAAA;AAAA,EAKQ,mCAAyC;AAC/C,QAAI,KAAK,UAAW;AACpB,SAAK,6BAA6B,CAAA;AAIlC,QAAIC,IAAoC,MACpCC,IAAqB,KAAK;AAC9B,WAAOA,KAAMA,EAAG,kBAAkB,SAAS;AACzC,MAAAA,IAAKA,EAAG;AAEV,IAAIA,KAAMA,EAAG,kBAAkB,SAAS,SACtCD,IAAoBC,IAEtB,MAAM,KAAK,SAAS,KAAK,QAAQ,EAAE,QAAQ,CAACC,MAAU;AACpD,MAAIA,MAAU,QAAQA,MAAUF,KAC3BE,EAAM,aAAa,aAAa,MACnCA,EAAM,aAAa,eAAe,MAAM,GACxC,KAAK,2BAA2B,KAAKA,CAAK;AAAA,IAE9C,CAAC;AAAA,EACH;AAAA;AAAA,EAGQ,qCAA2C;AACjD,SAAK,2BAA2B,QAAQ,CAACD,MAAO;AAC9C,MAAAA,EAAG,gBAAgB,aAAa;AAAA,IAClC,CAAC,GACD,KAAK,6BAA6B,CAAA;AAAA,EACpC;AAAA;AAAA;AAAA,EAKQ,gBAAsB;AAC5B,aAAS,iBAAiB,WAAW,KAAK,cAAc;AAAA,EAC1D;AAAA;AAAA,EAGQ,mBAAyB;AAC/B,aAAS,oBAAoB,WAAW,KAAK,cAAc;AAAA,EAC7D;AAAA;AAAA;AAAA,EAyBQ,mBAAyB;;AAC/B,UAAME,IAAQ,IAAI,YAAkB,oBAAoB;AAAA,MACtD,SAAS;AAAA,MACT,UAAU;AAAA,MACV,YAAY;AAAA,IAAA,CACb;AAGD,QAFA,KAAK,cAAcA,CAAK,GAEpB,CAACA,EAAM,kBAAkB;AAC3B,YAAMC,IAAY,KAAK;AACvB,MAAIA,EAAU,SAAS,KAAKA,EAAU,CAAC,IACrCA,EAAU,CAAC,EAAE,MAAA,KAEbC,IAAA,KAAK,aAAL,QAAAA,EAAe;AAAA,IAEnB;AAAA,EACF;AAAA;AAAA,EAGQ,wBAAuC;;AAC7C,UAAMC,IAAkB,MAAM;AAAA,QAC5BD,IAAA,KAAK,eAAL,gBAAAA,EAAiB,iBAA8BhB,OAAwB,CAAA;AAAA,IAAC,GAGpEkB,MAAQC,IAAA,KAAK,eAAL,gBAAAA,EAAiB,iBAAkC,YAAW,CAAA,GACtEC,IAAgC,CAAA;AAEtC,WAAAF,EAAM,QAAQ,CAACG,MAAS;AACtB,MAAAA,EAAK,iBAAiB,EAAE,SAAS,GAAA,CAAM,EAAE,QAAQ,CAACT,MAAO;AACvD,QAAIA,aAAc,gBACZA,EAAG,QAAQZ,CAAmB,KAChCoB,EAAe,KAAKR,CAAE,GAExBA,EAAG,iBAA8BZ,CAAmB,EAAE,QAAQ,CAACa,MAAU;AACvE,UAAAO,EAAe,KAAKP,CAAK;AAAA,QAC3B,CAAC;AAAA,MAEL,CAAC;AAAA,IACH,CAAC,GAEM,CAAC,GAAGI,GAAiB,GAAGG,CAAc,EAAE;AAAA,MAC7C,CAACR,MAAO,CAACA,EAAG,aAAa,UAAU,KAAKA,EAAG,aAAa,UAAU,MAAM;AAAA,IAAA;AAAA,EAE5E;AAAA;AAAA,EAGQ,WAAW,GAAwB;AACzC,UAAMG,IACJ,KAAK,yBAAyB,SAAS,IACnC,KAAK,2BACL,KAAK,sBAAA;AAEX,QAAIA,EAAU,WAAW,GAAG;AAC1B,QAAE,eAAA;AACF;AAAA,IACF;AAEA,UAAM,CAACO,GAAO,GAAGC,CAAI,IAAIR,GACnBS,IAAOD,EAAK,SAAS,IAAIA,EAAKA,EAAK,SAAS,CAAC,IAAID;AAEvD,QAAI,CAACA,KAAS,CAACE,EAAM;AAIrB,UAAMf,IAAS,SAAS;AAExB,IAAI,EAAE,WACAA,MAAWa,MACb,EAAE,eAAA,GACFE,EAAK,MAAA,KAGHf,MAAWe,MACb,EAAE,eAAA,GACFF,EAAM,MAAA;AAAA,EAGZ;AAAA;AAAA;AAAA,EAmBQ,+BAA+B,GAAgB;AACrD,UAAMD,IAAO,EAAE;AACf,SAAK,wBAAwBA,EAAK,cAAc,EAAE,SAAS,GAAA,CAAM,EAAE,SAAS;AAAA,EAC9E;AAAA;AAAA,EAGQ,wBAAwB,GAAgB;AAC9C,UAAMA,IAAO,EAAE;AACf,SAAK,iBAAiBA,EAAK,cAAc,EAAE,SAAS,GAAA,CAAM,EAAE,SAAS;AAAA,EACvE;AAAA;AAAA,EAGQ,uBAAuB,GAAgB;AAC7C,UAAMA,IAAO,EAAE;AACf,SAAK,gBAAgBA,EAAK,cAAc,EAAE,SAAS,GAAA,CAAM,EAAE,SAAS;AAAA,EACtE;AAAA;AAAA;AAAA,EAKQ,gBAAgB;AACtB,WAAI,KAAK,WAIAI;AAAA;AAAA;AAAA;AAAA,uBAIU,KAAK,UAAU;AAAA,mBACnB,MAAM;AACb,WAAK,OAAO;AAAA,IACd,CAAC;AAAA;AAAA,UAKAA;AAAA;AAAA,8BAEmB,KAAK,QAAQ;AAAA,2CACA,KAAK,sBAAsB;AAAA;AAAA;AAAA,YAG1D,KAAK,wBACHA;AAAA;AAAA,8BAEgB,KAAK,8BAA8B;AAAA,0BAEnDA;AAAA;AAAA,8BAEgB,KAAK,8BAA8B;AAAA;AAAA,uBAE1C;AAAA;AAAA;AAAA;AAAA,yBAIE,KAAK,UAAU;AAAA,qBACnB,MAAM;AACb,WAAK,OAAO;AAAA,IACd,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAqBX;AAAA;AAAA,EAGQ,gBAAgB;AACtB,WAAI,KAAK,WAAiBC,IAEnBD;AAAA,yDAC8C,CAAC,KAAK,cAAc;AAAA,0CACnC,KAAK,uBAAuB;AAAA;AAAA;AAAA,EAGpE;AAAA;AAAA,EAIS,SAAS;AAChB,UAAME,IAAiB;AAAA,MACrB,kBAAkB;AAAA,MAClB,WAAW,KAAK;AAAA,IAAA,GAKZC,IAAiB,KAAK,gBAAgB,KAAK,WAAW,QACtDC,IAAa,KAAK,gBAAyC,SAAzB,KAAK,SAAS;AAEtD,WAAOJ;AAAA;AAAA;AAAA,gBAGKK,EAASH,CAAc,CAAC;AAAA;AAAA;AAAA,0BAGdI,EAAUH,CAAc,CAAC;AAAA,qBAC9BG,EAAUF,CAAS,CAAC;AAAA;AAAA,iBAExB,KAAK,mBAAmB;AAAA;AAAA;AAAA;AAAA,YAI7B,KAAK,eAAe;AAAA;AAAA;AAAA;AAAA,YAIpB,KAAK,eAAe;AAAA;AAAA;AAAA;AAAA,EAI9B;AACF;AA1kBa5B,EACK,SAAS,CAACL,CAAiB;AASnCoC,EAAA;AAAA,EADPC,EAAM,iBAAiB;AAAA,GATbhC,EAUH,WAAA,cAAA,CAAA;AAOA+B,EAAA;AAAA,EADPC,EAAM,eAAe;AAAA,GAhBXhC,EAiBH,WAAA,YAAA,CAAA;AASA+B,EAAA;AAAA,EADPE,EAAA;AAAM,GAzBIjC,EA0BH,WAAA,WAAA,CAAA;AAOA+B,EAAA;AAAA,EADPE,EAAA;AAAM,GAhCIjC,EAiCH,WAAA,yBAAA,CAAA;AAOA+B,EAAA;AAAA,EADPE,EAAA;AAAM,GAvCIjC,EAwCH,WAAA,kBAAA,CAAA;AAOA+B,EAAA;AAAA,EADPE,EAAA;AAAM,GA9CIjC,EA+CH,WAAA,iBAAA,CAAA;AAuCR+B,EAAA;AAAA,EADCG,EAAS,EAAE,MAAM,SAAS,SAAS,IAAM;AAAA,GArF/BlC,EAsFX,WAAA,QAAA,CAAA;AAOA+B,EAAA;AAAA,EADCG,EAAS,EAAE,MAAM,QAAQ,SAAS,IAAM;AAAA,GA5F9BlC,EA6FX,WAAA,aAAA,CAAA;AAOA+B,EAAA;AAAA,EADCG,EAAS,EAAE,MAAM,QAAQ,SAAS,IAAM,WAAW,WAAW;AAAA,GAnGpDlC,EAoGX,WAAA,QAAA,CAAA;AAQA+B,EAAA;AAAA,EADCG,EAAS,EAAE,MAAM,SAAS,SAAS,IAAM;AAAA,GA3G/BlC,EA4GX,WAAA,aAAA,CAAA;AAOA+B,EAAA;AAAA,EADCG,EAAS,EAAE,MAAM,SAAS,SAAS,IAAM,WAAW,aAAa;AAAA,GAlHvDlC,EAmHX,WAAA,YAAA,CAAA;AAOA+B,EAAA;AAAA,EADCG,EAAS,EAAE,MAAM,SAAS,SAAS,IAAM,WAAW,aAAa;AAAA,GAzHvDlC,EA0HX,WAAA,YAAA,CAAA;AAQA+B,EAAA;AAAA,EADCG,EAAS,EAAE,MAAM,OAAA,CAAQ;AAAA,GAjIflC,EAkIX,WAAA,SAAA,CAAA;AAIA+B,EAAA;AAAA,EADCG,EAAS,EAAE,MAAM,QAAQ,WAAW,eAAe;AAAA,GArIzClC,EAsIX,WAAA,cAAA,CAAA;AAtIWA,IAAN+B,EAAA;AAAA,EADNI,EAAc,WAAW;AAAA,GACbnC,CAAA;"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { css as h, LitElement as c, nothing as u, html as m } from "lit";
|
|
2
|
-
import "./document-token-adoption-
|
|
2
|
+
import "./document-token-adoption-DuYNKd4k.js";
|
|
3
3
|
import { property as l, state as f, query as p, customElement as g } from "lit/decorators.js";
|
|
4
4
|
import { d as b } from "./dev-warn-YlwPHjtX.js";
|
|
5
5
|
import { computePosition as _, offset as v, flip as y, shift as w } from "@floating-ui/dom";
|
|
@@ -250,4 +250,4 @@ o = a([
|
|
|
250
250
|
export {
|
|
251
251
|
o as H
|
|
252
252
|
};
|
|
253
|
-
//# sourceMappingURL=hx-dropdown-
|
|
253
|
+
//# sourceMappingURL=hx-dropdown-n5-XSmiV.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hx-dropdown-BxNnUDyD.js","sources":["../../src/components/hx-dropdown/hx-dropdown.styles.ts","../../src/components/hx-dropdown/hx-dropdown.ts"],"sourcesContent":["import { css } from 'lit';\n\nexport const helixDropdownStyles = css`\n :host {\n display: inline-block;\n position: relative;\n }\n\n :host([disabled]) {\n pointer-events: none;\n opacity: var(--hx-opacity-disabled, 0.5);\n }\n\n .trigger-wrapper {\n display: inline-block;\n }\n\n [part='panel'] {\n position: fixed;\n z-index: var(--hx-dropdown-panel-z-index, 1000);\n min-width: var(--hx-dropdown-panel-min-width, 160px);\n background: var(--hx-dropdown-panel-bg, var(--hx-color-neutral-0, #ffffff));\n border: 1px solid var(--hx-dropdown-panel-border-color, var(--hx-color-neutral-200, #e5e7eb));\n border-radius: var(--hx-dropdown-panel-border-radius, var(--hx-border-radius-md, 0.375rem));\n box-shadow: var(\n --hx-dropdown-panel-shadow,\n 0 4px 16px var(--hx-overlay-black-12, rgba(0, 0, 0, 0.12))\n );\n visibility: hidden;\n opacity: 0;\n pointer-events: none;\n transition:\n opacity var(--hx-transition-fast, 150ms ease),\n visibility var(--hx-transition-fast, 150ms ease);\n outline: none;\n }\n\n [part='panel'].panel--visible {\n visibility: visible;\n opacity: 1;\n pointer-events: auto;\n }\n\n @media (prefers-reduced-motion: reduce) {\n [part='panel'] {\n transition: none;\n }\n }\n`;\n","import { LitElement, html, nothing, type PropertyValues } from 'lit';\nimport '../../utilities/document-token-adoption.js';\nimport { customElement, property, state, query } from 'lit/decorators.js';\nimport { devWarn } from '../../utils/dev-warn.js';\nimport {\n computePosition,\n flip,\n shift,\n offset,\n type Placement as FloatingPlacement,\n} from '@floating-ui/dom';\nimport { helixDropdownStyles } from './hx-dropdown.styles.js';\n\n// P2-03: Export so TypeScript consumers can import this type for prop typing.\nexport type DropdownPlacement =\n | 'top'\n | 'top-start'\n | 'top-end'\n | 'bottom'\n | 'bottom-start'\n | 'bottom-end'\n | 'start'\n | 'end';\n\n/**\n * A dropdown component — a button that opens a floating panel on click.\n *\n * @summary Button that opens a floating menu panel on click.\n *\n * @tag hx-dropdown\n *\n * @slot trigger - The element that opens the dropdown (e.g. hx-button).\n * @slot - Default slot for dropdown panel content (e.g. menu items).\n *\n * @fires {CustomEvent<void>} hx-show - Dispatched when the dropdown is opened.\n * @fires {CustomEvent<void>} hx-hide - Dispatched when the dropdown is closed.\n * @fires {CustomEvent<{value: string | null; label: string}>} hx-select - Dispatched when a menu item is selected.\n *\n * @csspart trigger - The trigger wrapper element.\n * @csspart panel - The floating panel element.\n *\n * @cssprop [--hx-dropdown-panel-bg=var(--hx-color-neutral-0)] - Panel background color.\n * @cssprop [--hx-dropdown-panel-border-color=var(--hx-color-neutral-200)] - Panel border color.\n * @cssprop [--hx-dropdown-panel-border-radius=var(--hx-border-radius-md)] - Panel border radius.\n * @cssprop [--hx-dropdown-panel-shadow=0 4px 16px rgba(0,0,0,0.12)] - Panel box shadow.\n * @cssprop [--hx-dropdown-panel-z-index=1000] - Panel z-index.\n * @cssprop [--hx-dropdown-panel-min-width=160px] - Panel minimum width.\n *\n * @example\n * ```html\n * <hx-dropdown>\n * <button slot=\"trigger\">Open Menu</button>\n * <ul>\n * <li data-value=\"edit\">Edit</li>\n * <li data-value=\"delete\">Delete</li>\n * </ul>\n * </hx-dropdown>\n * ```\n */\n@customElement('hx-dropdown')\nexport class HelixDropdown extends LitElement {\n static override styles = [helixDropdownStyles];\n\n // ─── Public Properties ───\n\n /**\n * Whether the dropdown panel is open.\n * @attr open\n */\n @property({ type: Boolean, reflect: true })\n open = false;\n\n /**\n * Preferred placement of the panel relative to the trigger.\n * @attr placement\n */\n @property({ type: String, reflect: true })\n placement:\n | 'top'\n | 'top-start'\n | 'top-end'\n | 'bottom'\n | 'bottom-start'\n | 'bottom-end'\n | 'start'\n | 'end' = 'bottom-start';\n\n /**\n * Accessible label for the dropdown menu panel. Override for i18n.\n * @attr label\n */\n @property() label = 'Menu';\n\n /**\n * Whether the dropdown is disabled. Prevents opening.\n * @attr disabled\n */\n @property({ type: Boolean, reflect: true })\n disabled = false;\n\n /**\n * Gap in pixels between the trigger and the panel.\n * @attr distance\n */\n @property({ type: Number })\n distance = 4;\n\n // ─── Internal State ───\n\n /**\n * Whether the dropdown panel is currently visible.\n * @internal\n */\n @state() private _panelVisible = false;\n\n /**\n * Guards against accumulating multiple document click listeners when open state\n * changes faster than the microtask queue can process removeEventListener calls.\n * @internal\n */\n private _documentListenerAttached = false;\n\n // P1-02: Unique panel ID for aria-controls.\n /**\n * Monotonically incrementing counter used to generate unique panel IDs across instances.\n * @internal\n */\n private static _instanceCounter = 0;\n /**\n * Unique ID assigned to the floating panel element, referenced by `aria-controls` on the trigger.\n * @internal\n */\n private _panelId = `hx-dropdown-panel-${++HelixDropdown._instanceCounter}`;\n\n /**\n * Reference to the floating panel element inside the shadow DOM.\n * @internal\n */\n @query('[part=\"panel\"]') private _panel: HTMLElement | undefined;\n /**\n * Reference to the trigger wrapper element inside the shadow DOM.\n * @internal\n */\n @query('[part=\"trigger\"]') private _triggerWrapper: HTMLElement | undefined;\n\n // ─── Lifecycle ───\n\n override connectedCallback(): void {\n super.connectedCallback();\n this.addEventListener('keydown', this._handleKeydown);\n }\n\n override disconnectedCallback(): void {\n super.disconnectedCallback();\n this.removeEventListener('keydown', this._handleKeydown);\n if (this._documentListenerAttached) {\n document.removeEventListener('click', this._handleOutsideClick, { capture: true });\n this._documentListenerAttached = false;\n }\n }\n\n // ─── Open/Close ───\n\n /** @internal */\n private async _show(): Promise<void> {\n if (this.open || this.disabled) return;\n this.open = true;\n this._panelVisible = true;\n // Add outside-click listener synchronously before any await so it is registered\n // by the time the test fires an outside click after a single await el.updateComplete.\n if (!this._documentListenerAttached) {\n document.addEventListener('click', this._handleOutsideClick, { capture: true });\n this._documentListenerAttached = true;\n }\n await this.updateComplete;\n // P0-01: Fix focus management — use slot.assignedElements() to traverse slotted (light DOM) content.\n // Focus is set after updateComplete (panel is rendered) but before _updatePosition so\n // it executes in the same microtask as the test's await-continuation.\n const panel = this._panel;\n if (panel) {\n const firstFocusable = this._getFirstFocusableItem();\n firstFocusable?.focus();\n }\n await this._updatePosition();\n this.dispatchEvent(new CustomEvent<void>('hx-show', { bubbles: true, composed: true }));\n }\n\n // P2-02: returnFocus=true only on Escape; Tab should let focus advance naturally.\n /** @internal */\n private _hide(returnFocus = true): void {\n if (!this.open) return;\n this.open = false;\n this._panelVisible = false;\n if (this._documentListenerAttached) {\n document.removeEventListener('click', this._handleOutsideClick, { capture: true });\n this._documentListenerAttached = false;\n }\n this.dispatchEvent(new CustomEvent<void>('hx-hide', { bubbles: true, composed: true }));\n if (returnFocus) {\n const slot = this.shadowRoot?.querySelector<HTMLSlotElement>('slot[name=\"trigger\"]');\n const trigger = slot?.assignedElements()[0] as HTMLElement | undefined;\n trigger?.focus();\n }\n }\n\n // ─── Positioning ───\n\n /** @internal */\n private async _updatePosition(): Promise<void> {\n const reference = this._triggerWrapper;\n const panel = this._panel;\n if (!reference || !panel) return;\n\n // Map 'start' and 'end' to floating-ui's 'left'/'right'\n const floatingPlacement = this.placement\n .replace(/^start$/, 'left')\n .replace(/^end$/, 'right') as FloatingPlacement;\n\n const { x, y } = await computePosition(reference, panel, {\n placement: floatingPlacement,\n strategy: 'fixed',\n middleware: [offset(this.distance), flip(), shift({ padding: 8 })],\n });\n\n Object.assign(panel.style, {\n left: `${x}px`,\n top: `${y}px`,\n });\n }\n\n // ─── Event Handlers ───\n\n /** @internal */\n private _handleTriggerClick(e: MouseEvent): void {\n e.stopPropagation();\n if (this.open) {\n this._hide();\n } else {\n void this._show();\n }\n }\n\n /** @internal */\n private _handleTriggerKeydown(e: KeyboardEvent): void {\n if (e.key === 'Enter' || e.key === ' ' || e.key === 'ArrowDown') {\n e.preventDefault();\n void this._show();\n }\n }\n\n /** @internal */\n private _handleKeydown = (e: KeyboardEvent): void => {\n if (e.key === 'Escape' && this.open) {\n e.stopPropagation();\n this._hide(true); // return focus to trigger on Escape\n } else if (e.key === 'Tab' && this.open) {\n // P2-02: Do not return focus to trigger on Tab — let focus advance naturally to next page element.\n this._hide(false);\n } else if (\n this.open &&\n (e.key === 'ArrowDown' || e.key === 'ArrowUp' || e.key === 'Home' || e.key === 'End')\n ) {\n // P2-01: Arrow key roving within panel per APG Menu Button pattern.\n e.preventDefault();\n this._handleMenuNavigation(e.key);\n }\n };\n\n // P2-01: Move focus among menuitem elements using arrow keys.\n /** @internal */\n private _handleMenuNavigation(key: string): void {\n const items = this._getFocusableMenuItems();\n if (items.length === 0) return;\n const currentIndex = items.indexOf(document.activeElement as HTMLElement);\n let nextIndex: number;\n if (key === 'ArrowDown') {\n nextIndex = currentIndex < items.length - 1 ? currentIndex + 1 : 0;\n } else if (key === 'ArrowUp') {\n nextIndex = currentIndex > 0 ? currentIndex - 1 : items.length - 1;\n } else if (key === 'Home') {\n nextIndex = 0;\n } else {\n nextIndex = items.length - 1;\n }\n items[nextIndex]?.focus();\n }\n\n // P0-01 / P2-01: Get focusable menu items from slotted content.\n /** @internal */\n private _getFocusableMenuItems(): HTMLElement[] {\n const panel = this._panel;\n if (!panel) return [];\n const slot = panel.querySelector<HTMLSlotElement>('slot');\n const assignedNodes = slot?.assignedElements({ flatten: true }) ?? [];\n const items: HTMLElement[] = [];\n for (const node of assignedNodes) {\n if (!(node instanceof HTMLElement)) continue;\n if (node.matches('[role=\"menuitem\"]')) {\n items.push(node);\n } else {\n node.querySelectorAll<HTMLElement>('[role=\"menuitem\"]').forEach((item) => items.push(item));\n }\n }\n return items;\n }\n\n // P0-01: Find the first focusable element in slotted panel content.\n /** @internal */\n private _getFirstFocusableItem(): HTMLElement | null {\n const panel = this._panel;\n if (!panel) return null;\n const slot = panel.querySelector<HTMLSlotElement>('slot');\n const assignedNodes = slot?.assignedElements({ flatten: true }) ?? [];\n const focusableSelector =\n '[role=\"menuitem\"], button, [tabindex]:not([tabindex=\"-1\"]), a[href], input, select, textarea';\n for (const node of assignedNodes) {\n if (!(node instanceof HTMLElement)) continue;\n if (node.matches(focusableSelector)) return node;\n const found = node.querySelector<HTMLElement>(focusableSelector);\n if (found) return found;\n }\n return null;\n }\n\n /** @internal */\n private _handleOutsideClick = (e: MouseEvent): void => {\n const path = e.composedPath();\n if (!path.includes(this)) {\n this._hide();\n }\n };\n\n /** @internal */\n private _handlePanelClick(e: MouseEvent): void {\n const target = e.target as HTMLElement;\n // P2-06: Narrow selector — bare 'li' and 'button' cause spurious hx-select events.\n const item = target.closest<HTMLElement>('[role=\"menuitem\"], [data-value]');\n if (!item) return;\n\n const value = item.dataset['value'] ?? item.getAttribute('value') ?? null;\n const label = item.textContent?.trim() ?? '';\n\n this.dispatchEvent(\n new CustomEvent<{ value: string | null; label: string }>('hx-select', {\n bubbles: true,\n composed: true,\n detail: { value, label },\n }),\n );\n\n this._hide();\n }\n\n // ─── Render ───\n\n override render() {\n return html`\n <div\n part=\"trigger\"\n class=\"trigger-wrapper\"\n @click=${this._handleTriggerClick}\n @keydown=${this._handleTriggerKeydown}\n >\n <slot name=\"trigger\" @slotchange=${this._onTriggerSlotChange}></slot>\n </div>\n <div\n part=\"panel\"\n id=${this._panelId}\n role=\"menu\"\n aria-hidden=${this._panelVisible ? nothing : 'true'}\n aria-label=${this.label}\n class=${this._panelVisible ? 'panel panel--visible' : 'panel'}\n @click=${this._handlePanelClick}\n >\n <slot @slotchange=${this._onPanelSlotChange}></slot>\n </div>\n `;\n }\n\n // ─── Panel slot validation ───\n\n /** @internal */\n private _onPanelSlotChange(e: Event): void {\n const slot = e.target as HTMLSlotElement;\n const assigned = slot.assignedElements({ flatten: true });\n const nonItems = assigned.filter((el) => el.tagName.toLowerCase() !== 'hx-dropdown-item');\n if (nonItems.length > 0) {\n devWarn(\n 'hx-dropdown',\n `Default slot should contain only hx-dropdown-item elements. Found unexpected: ${nonItems.map((el) => `<${el.tagName.toLowerCase()}>`).join(', ')}. Non-hx-dropdown-item children will be included in keyboard navigation incorrectly.`,\n );\n }\n }\n\n // ─── ARIA setup for trigger slot ───\n\n /** @internal */\n private _onTriggerSlotChange(): void {\n this._setupTriggerAria();\n }\n\n override firstUpdated(): void {\n this._setupTriggerAria();\n }\n\n /** @internal */\n private _setupTriggerAria(): void {\n const slot = this.shadowRoot?.querySelector<HTMLSlotElement>('slot[name=\"trigger\"]');\n if (!slot) return;\n const trigger = slot.assignedElements()[0] as HTMLElement | undefined;\n if (trigger) {\n // P1-01: Use aria-haspopup=\"menu\" per ARIA 1.1+ / APG Menu Button pattern.\n trigger.setAttribute('aria-haspopup', 'menu');\n trigger.setAttribute('aria-expanded', String(this.open));\n // aria-controls is intentionally omitted: the panel lives in Shadow DOM and\n // IDREF values cannot be resolved across shadow boundaries by assistive technology.\n // P2-06: Remove host fallback when a trigger element is present.\n this.removeAttribute('aria-expanded');\n } else {\n // P2-06: Fallback — set aria-expanded on host when trigger slot is empty or unassigned.\n this.setAttribute('aria-expanded', String(this.open));\n }\n }\n\n override updated(changedProperties: PropertyValues<this>): void {\n super.updated(changedProperties);\n if (changedProperties.has('open')) {\n // Keep aria-expanded in sync\n const slot = this.shadowRoot?.querySelector<HTMLSlotElement>('slot[name=\"trigger\"]');\n const trigger = slot?.assignedElements()[0] as HTMLElement | undefined;\n if (trigger) {\n trigger.setAttribute('aria-expanded', String(this.open));\n } else {\n // P2-06: Fallback — keep host aria-expanded in sync when trigger slot is empty.\n this.setAttribute('aria-expanded', String(this.open));\n }\n }\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'hx-dropdown': HelixDropdown;\n }\n}\n"],"names":["helixDropdownStyles","css","HelixDropdown","LitElement","firstFocusable","returnFocus","slot","_a","trigger","reference","panel","floatingPlacement","x","y","computePosition","offset","flip","shift","key","items","currentIndex","nextIndex","assignedNodes","node","item","focusableSelector","found","value","label","html","nothing","nonItems","el","devWarn","changedProperties","__decorateClass","property","state","query","customElement"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"hx-dropdown-n5-XSmiV.js","sources":["../../src/components/hx-dropdown/hx-dropdown.styles.ts","../../src/components/hx-dropdown/hx-dropdown.ts"],"sourcesContent":["import { css } from 'lit';\n\nexport const helixDropdownStyles = css`\n :host {\n display: inline-block;\n position: relative;\n }\n\n :host([disabled]) {\n pointer-events: none;\n opacity: var(--hx-opacity-disabled, 0.5);\n }\n\n .trigger-wrapper {\n display: inline-block;\n }\n\n [part='panel'] {\n position: fixed;\n z-index: var(--hx-dropdown-panel-z-index, 1000);\n min-width: var(--hx-dropdown-panel-min-width, 160px);\n background: var(--hx-dropdown-panel-bg, var(--hx-color-neutral-0, #ffffff));\n border: 1px solid var(--hx-dropdown-panel-border-color, var(--hx-color-neutral-200, #e5e7eb));\n border-radius: var(--hx-dropdown-panel-border-radius, var(--hx-border-radius-md, 0.375rem));\n box-shadow: var(\n --hx-dropdown-panel-shadow,\n 0 4px 16px var(--hx-overlay-black-12, rgba(0, 0, 0, 0.12))\n );\n visibility: hidden;\n opacity: 0;\n pointer-events: none;\n transition:\n opacity var(--hx-transition-fast, 150ms ease),\n visibility var(--hx-transition-fast, 150ms ease);\n outline: none;\n }\n\n [part='panel'].panel--visible {\n visibility: visible;\n opacity: 1;\n pointer-events: auto;\n }\n\n @media (prefers-reduced-motion: reduce) {\n [part='panel'] {\n transition: none;\n }\n }\n`;\n","import { LitElement, html, nothing, type PropertyValues } from 'lit';\nimport '../../utilities/document-token-adoption.js';\nimport { customElement, property, state, query } from 'lit/decorators.js';\nimport { devWarn } from '../../utils/dev-warn.js';\nimport {\n computePosition,\n flip,\n shift,\n offset,\n type Placement as FloatingPlacement,\n} from '@floating-ui/dom';\nimport { helixDropdownStyles } from './hx-dropdown.styles.js';\n\n// P2-03: Export so TypeScript consumers can import this type for prop typing.\nexport type DropdownPlacement =\n | 'top'\n | 'top-start'\n | 'top-end'\n | 'bottom'\n | 'bottom-start'\n | 'bottom-end'\n | 'start'\n | 'end';\n\n/**\n * A dropdown component — a button that opens a floating panel on click.\n *\n * @summary Button that opens a floating menu panel on click.\n *\n * @tag hx-dropdown\n *\n * @slot trigger - The element that opens the dropdown (e.g. hx-button).\n * @slot - Default slot for dropdown panel content (e.g. menu items).\n *\n * @fires {CustomEvent<void>} hx-show - Dispatched when the dropdown is opened.\n * @fires {CustomEvent<void>} hx-hide - Dispatched when the dropdown is closed.\n * @fires {CustomEvent<{value: string | null; label: string}>} hx-select - Dispatched when a menu item is selected.\n *\n * @csspart trigger - The trigger wrapper element.\n * @csspart panel - The floating panel element.\n *\n * @cssprop [--hx-dropdown-panel-bg=var(--hx-color-neutral-0)] - Panel background color.\n * @cssprop [--hx-dropdown-panel-border-color=var(--hx-color-neutral-200)] - Panel border color.\n * @cssprop [--hx-dropdown-panel-border-radius=var(--hx-border-radius-md)] - Panel border radius.\n * @cssprop [--hx-dropdown-panel-shadow=0 4px 16px rgba(0,0,0,0.12)] - Panel box shadow.\n * @cssprop [--hx-dropdown-panel-z-index=1000] - Panel z-index.\n * @cssprop [--hx-dropdown-panel-min-width=160px] - Panel minimum width.\n *\n * @example\n * ```html\n * <hx-dropdown>\n * <button slot=\"trigger\">Open Menu</button>\n * <ul>\n * <li data-value=\"edit\">Edit</li>\n * <li data-value=\"delete\">Delete</li>\n * </ul>\n * </hx-dropdown>\n * ```\n */\n@customElement('hx-dropdown')\nexport class HelixDropdown extends LitElement {\n static override styles = [helixDropdownStyles];\n\n // ─── Public Properties ───\n\n /**\n * Whether the dropdown panel is open.\n * @attr open\n */\n @property({ type: Boolean, reflect: true })\n open = false;\n\n /**\n * Preferred placement of the panel relative to the trigger.\n * @attr placement\n */\n @property({ type: String, reflect: true })\n placement:\n | 'top'\n | 'top-start'\n | 'top-end'\n | 'bottom'\n | 'bottom-start'\n | 'bottom-end'\n | 'start'\n | 'end' = 'bottom-start';\n\n /**\n * Accessible label for the dropdown menu panel. Override for i18n.\n * @attr label\n */\n @property() label = 'Menu';\n\n /**\n * Whether the dropdown is disabled. Prevents opening.\n * @attr disabled\n */\n @property({ type: Boolean, reflect: true })\n disabled = false;\n\n /**\n * Gap in pixels between the trigger and the panel.\n * @attr distance\n */\n @property({ type: Number })\n distance = 4;\n\n // ─── Internal State ───\n\n /**\n * Whether the dropdown panel is currently visible.\n * @internal\n */\n @state() private _panelVisible = false;\n\n /**\n * Guards against accumulating multiple document click listeners when open state\n * changes faster than the microtask queue can process removeEventListener calls.\n * @internal\n */\n private _documentListenerAttached = false;\n\n // P1-02: Unique panel ID for aria-controls.\n /**\n * Monotonically incrementing counter used to generate unique panel IDs across instances.\n * @internal\n */\n private static _instanceCounter = 0;\n /**\n * Unique ID assigned to the floating panel element, referenced by `aria-controls` on the trigger.\n * @internal\n */\n private _panelId = `hx-dropdown-panel-${++HelixDropdown._instanceCounter}`;\n\n /**\n * Reference to the floating panel element inside the shadow DOM.\n * @internal\n */\n @query('[part=\"panel\"]') private _panel: HTMLElement | undefined;\n /**\n * Reference to the trigger wrapper element inside the shadow DOM.\n * @internal\n */\n @query('[part=\"trigger\"]') private _triggerWrapper: HTMLElement | undefined;\n\n // ─── Lifecycle ───\n\n override connectedCallback(): void {\n super.connectedCallback();\n this.addEventListener('keydown', this._handleKeydown);\n }\n\n override disconnectedCallback(): void {\n super.disconnectedCallback();\n this.removeEventListener('keydown', this._handleKeydown);\n if (this._documentListenerAttached) {\n document.removeEventListener('click', this._handleOutsideClick, { capture: true });\n this._documentListenerAttached = false;\n }\n }\n\n // ─── Open/Close ───\n\n /** @internal */\n private async _show(): Promise<void> {\n if (this.open || this.disabled) return;\n this.open = true;\n this._panelVisible = true;\n // Add outside-click listener synchronously before any await so it is registered\n // by the time the test fires an outside click after a single await el.updateComplete.\n if (!this._documentListenerAttached) {\n document.addEventListener('click', this._handleOutsideClick, { capture: true });\n this._documentListenerAttached = true;\n }\n await this.updateComplete;\n // P0-01: Fix focus management — use slot.assignedElements() to traverse slotted (light DOM) content.\n // Focus is set after updateComplete (panel is rendered) but before _updatePosition so\n // it executes in the same microtask as the test's await-continuation.\n const panel = this._panel;\n if (panel) {\n const firstFocusable = this._getFirstFocusableItem();\n firstFocusable?.focus();\n }\n await this._updatePosition();\n this.dispatchEvent(new CustomEvent<void>('hx-show', { bubbles: true, composed: true }));\n }\n\n // P2-02: returnFocus=true only on Escape; Tab should let focus advance naturally.\n /** @internal */\n private _hide(returnFocus = true): void {\n if (!this.open) return;\n this.open = false;\n this._panelVisible = false;\n if (this._documentListenerAttached) {\n document.removeEventListener('click', this._handleOutsideClick, { capture: true });\n this._documentListenerAttached = false;\n }\n this.dispatchEvent(new CustomEvent<void>('hx-hide', { bubbles: true, composed: true }));\n if (returnFocus) {\n const slot = this.shadowRoot?.querySelector<HTMLSlotElement>('slot[name=\"trigger\"]');\n const trigger = slot?.assignedElements()[0] as HTMLElement | undefined;\n trigger?.focus();\n }\n }\n\n // ─── Positioning ───\n\n /** @internal */\n private async _updatePosition(): Promise<void> {\n const reference = this._triggerWrapper;\n const panel = this._panel;\n if (!reference || !panel) return;\n\n // Map 'start' and 'end' to floating-ui's 'left'/'right'\n const floatingPlacement = this.placement\n .replace(/^start$/, 'left')\n .replace(/^end$/, 'right') as FloatingPlacement;\n\n const { x, y } = await computePosition(reference, panel, {\n placement: floatingPlacement,\n strategy: 'fixed',\n middleware: [offset(this.distance), flip(), shift({ padding: 8 })],\n });\n\n Object.assign(panel.style, {\n left: `${x}px`,\n top: `${y}px`,\n });\n }\n\n // ─── Event Handlers ───\n\n /** @internal */\n private _handleTriggerClick(e: MouseEvent): void {\n e.stopPropagation();\n if (this.open) {\n this._hide();\n } else {\n void this._show();\n }\n }\n\n /** @internal */\n private _handleTriggerKeydown(e: KeyboardEvent): void {\n if (e.key === 'Enter' || e.key === ' ' || e.key === 'ArrowDown') {\n e.preventDefault();\n void this._show();\n }\n }\n\n /** @internal */\n private _handleKeydown = (e: KeyboardEvent): void => {\n if (e.key === 'Escape' && this.open) {\n e.stopPropagation();\n this._hide(true); // return focus to trigger on Escape\n } else if (e.key === 'Tab' && this.open) {\n // P2-02: Do not return focus to trigger on Tab — let focus advance naturally to next page element.\n this._hide(false);\n } else if (\n this.open &&\n (e.key === 'ArrowDown' || e.key === 'ArrowUp' || e.key === 'Home' || e.key === 'End')\n ) {\n // P2-01: Arrow key roving within panel per APG Menu Button pattern.\n e.preventDefault();\n this._handleMenuNavigation(e.key);\n }\n };\n\n // P2-01: Move focus among menuitem elements using arrow keys.\n /** @internal */\n private _handleMenuNavigation(key: string): void {\n const items = this._getFocusableMenuItems();\n if (items.length === 0) return;\n const currentIndex = items.indexOf(document.activeElement as HTMLElement);\n let nextIndex: number;\n if (key === 'ArrowDown') {\n nextIndex = currentIndex < items.length - 1 ? currentIndex + 1 : 0;\n } else if (key === 'ArrowUp') {\n nextIndex = currentIndex > 0 ? currentIndex - 1 : items.length - 1;\n } else if (key === 'Home') {\n nextIndex = 0;\n } else {\n nextIndex = items.length - 1;\n }\n items[nextIndex]?.focus();\n }\n\n // P0-01 / P2-01: Get focusable menu items from slotted content.\n /** @internal */\n private _getFocusableMenuItems(): HTMLElement[] {\n const panel = this._panel;\n if (!panel) return [];\n const slot = panel.querySelector<HTMLSlotElement>('slot');\n const assignedNodes = slot?.assignedElements({ flatten: true }) ?? [];\n const items: HTMLElement[] = [];\n for (const node of assignedNodes) {\n if (!(node instanceof HTMLElement)) continue;\n if (node.matches('[role=\"menuitem\"]')) {\n items.push(node);\n } else {\n node.querySelectorAll<HTMLElement>('[role=\"menuitem\"]').forEach((item) => items.push(item));\n }\n }\n return items;\n }\n\n // P0-01: Find the first focusable element in slotted panel content.\n /** @internal */\n private _getFirstFocusableItem(): HTMLElement | null {\n const panel = this._panel;\n if (!panel) return null;\n const slot = panel.querySelector<HTMLSlotElement>('slot');\n const assignedNodes = slot?.assignedElements({ flatten: true }) ?? [];\n const focusableSelector =\n '[role=\"menuitem\"], button, [tabindex]:not([tabindex=\"-1\"]), a[href], input, select, textarea';\n for (const node of assignedNodes) {\n if (!(node instanceof HTMLElement)) continue;\n if (node.matches(focusableSelector)) return node;\n const found = node.querySelector<HTMLElement>(focusableSelector);\n if (found) return found;\n }\n return null;\n }\n\n /** @internal */\n private _handleOutsideClick = (e: MouseEvent): void => {\n const path = e.composedPath();\n if (!path.includes(this)) {\n this._hide();\n }\n };\n\n /** @internal */\n private _handlePanelClick(e: MouseEvent): void {\n const target = e.target as HTMLElement;\n // P2-06: Narrow selector — bare 'li' and 'button' cause spurious hx-select events.\n const item = target.closest<HTMLElement>('[role=\"menuitem\"], [data-value]');\n if (!item) return;\n\n const value = item.dataset['value'] ?? item.getAttribute('value') ?? null;\n const label = item.textContent?.trim() ?? '';\n\n this.dispatchEvent(\n new CustomEvent<{ value: string | null; label: string }>('hx-select', {\n bubbles: true,\n composed: true,\n detail: { value, label },\n }),\n );\n\n this._hide();\n }\n\n // ─── Render ───\n\n override render() {\n return html`\n <div\n part=\"trigger\"\n class=\"trigger-wrapper\"\n @click=${this._handleTriggerClick}\n @keydown=${this._handleTriggerKeydown}\n >\n <slot name=\"trigger\" @slotchange=${this._onTriggerSlotChange}></slot>\n </div>\n <div\n part=\"panel\"\n id=${this._panelId}\n role=\"menu\"\n aria-hidden=${this._panelVisible ? nothing : 'true'}\n aria-label=${this.label}\n class=${this._panelVisible ? 'panel panel--visible' : 'panel'}\n @click=${this._handlePanelClick}\n >\n <slot @slotchange=${this._onPanelSlotChange}></slot>\n </div>\n `;\n }\n\n // ─── Panel slot validation ───\n\n /** @internal */\n private _onPanelSlotChange(e: Event): void {\n const slot = e.target as HTMLSlotElement;\n const assigned = slot.assignedElements({ flatten: true });\n const nonItems = assigned.filter((el) => el.tagName.toLowerCase() !== 'hx-dropdown-item');\n if (nonItems.length > 0) {\n devWarn(\n 'hx-dropdown',\n `Default slot should contain only hx-dropdown-item elements. Found unexpected: ${nonItems.map((el) => `<${el.tagName.toLowerCase()}>`).join(', ')}. Non-hx-dropdown-item children will be included in keyboard navigation incorrectly.`,\n );\n }\n }\n\n // ─── ARIA setup for trigger slot ───\n\n /** @internal */\n private _onTriggerSlotChange(): void {\n this._setupTriggerAria();\n }\n\n override firstUpdated(): void {\n this._setupTriggerAria();\n }\n\n /** @internal */\n private _setupTriggerAria(): void {\n const slot = this.shadowRoot?.querySelector<HTMLSlotElement>('slot[name=\"trigger\"]');\n if (!slot) return;\n const trigger = slot.assignedElements()[0] as HTMLElement | undefined;\n if (trigger) {\n // P1-01: Use aria-haspopup=\"menu\" per ARIA 1.1+ / APG Menu Button pattern.\n trigger.setAttribute('aria-haspopup', 'menu');\n trigger.setAttribute('aria-expanded', String(this.open));\n // aria-controls is intentionally omitted: the panel lives in Shadow DOM and\n // IDREF values cannot be resolved across shadow boundaries by assistive technology.\n // P2-06: Remove host fallback when a trigger element is present.\n this.removeAttribute('aria-expanded');\n } else {\n // P2-06: Fallback — set aria-expanded on host when trigger slot is empty or unassigned.\n this.setAttribute('aria-expanded', String(this.open));\n }\n }\n\n override updated(changedProperties: PropertyValues<this>): void {\n super.updated(changedProperties);\n if (changedProperties.has('open')) {\n // Keep aria-expanded in sync\n const slot = this.shadowRoot?.querySelector<HTMLSlotElement>('slot[name=\"trigger\"]');\n const trigger = slot?.assignedElements()[0] as HTMLElement | undefined;\n if (trigger) {\n trigger.setAttribute('aria-expanded', String(this.open));\n } else {\n // P2-06: Fallback — keep host aria-expanded in sync when trigger slot is empty.\n this.setAttribute('aria-expanded', String(this.open));\n }\n }\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'hx-dropdown': HelixDropdown;\n }\n}\n"],"names":["helixDropdownStyles","css","HelixDropdown","LitElement","firstFocusable","returnFocus","slot","_a","trigger","reference","panel","floatingPlacement","x","y","computePosition","offset","flip","shift","key","items","currentIndex","nextIndex","assignedNodes","node","item","focusableSelector","found","value","label","html","nothing","nonItems","el","devWarn","changedProperties","__decorateClass","property","state","query","customElement"],"mappings":"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"}
|