@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-pagination-DBovb97q.js","sources":["../../src/components/hx-pagination/hx-pagination.styles.ts","../../src/components/hx-pagination/hx-pagination.ts"],"sourcesContent":["import { css } from 'lit';\n\nexport const helixPaginationStyles = css`\n :host {\n display: block;\n font-family: var(--hx-font-family-sans, sans-serif);\n }\n\n .pagination-root {\n display: flex;\n align-items: center;\n gap: var(--hx-space-4, 1rem);\n flex-wrap: wrap;\n }\n\n nav {\n display: flex;\n align-items: center;\n justify-content: center;\n }\n\n .list {\n display: flex;\n align-items: center;\n gap: var(--hx-pagination-gap, var(--hx-space-1, 0.25rem));\n list-style: none;\n margin: 0;\n padding: 0;\n }\n\n .item {\n display: flex;\n }\n\n .button {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n min-width: var(--hx-pagination-button-size, 2.25rem);\n height: var(--hx-pagination-button-size, 2.25rem);\n padding: 0 var(--hx-space-2, 0.5rem);\n border: var(--hx-border-width-thin, 1px) solid\n var(--hx-pagination-border-color, var(--hx-color-neutral-300, #d1d5db));\n border-radius: var(--hx-pagination-border-radius, var(--hx-border-radius-md, 0.375rem));\n background: var(--hx-pagination-bg, var(--hx-color-neutral-0, #ffffff));\n color: var(--hx-pagination-color, var(--hx-color-neutral-900, #111827));\n font-size: var(--hx-font-size-sm, 0.875rem);\n font-family: inherit;\n cursor: pointer;\n transition:\n background-color var(--hx-transition-fast, 150ms) ease,\n border-color var(--hx-transition-fast, 150ms) ease,\n color var(--hx-transition-fast, 150ms) ease;\n text-decoration: none;\n white-space: nowrap;\n }\n\n .button:hover:not(:disabled) {\n background: var(--hx-pagination-hover-bg, var(--hx-color-neutral-100, #f3f4f6));\n border-color: var(--hx-pagination-hover-border-color, var(--hx-color-primary-500, #2563eb));\n }\n\n .button:focus-visible {\n outline: var(--hx-focus-ring-width, 2px) solid\n var(--hx-pagination-focus-ring-color, var(--hx-focus-ring-color, var(--hx-color-primary-500)));\n outline-offset: var(--hx-focus-ring-offset, 2px);\n }\n\n .button[aria-current='page'] {\n background: var(--hx-pagination-active-bg, var(--hx-color-primary-500, #2563eb));\n border-color: var(\n --hx-pagination-active-border-color,\n var(--hx-pagination-active-bg, var(--hx-color-primary-500, #2563eb))\n );\n color: var(--hx-pagination-active-color, var(--hx-color-neutral-0, #ffffff));\n font-weight: var(--hx-font-weight-semibold, 600);\n cursor: default;\n pointer-events: none;\n }\n\n .button:disabled {\n opacity: var(--hx-opacity-disabled, 0.5);\n pointer-events: none;\n }\n\n .ellipsis {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n min-width: var(--hx-pagination-button-size, 2.25rem);\n height: var(--hx-pagination-button-size, 2.25rem);\n color: var(--hx-pagination-ellipsis-color, var(--hx-color-neutral-500, #6b7280));\n font-size: var(--hx-font-size-sm, 0.875rem);\n user-select: none;\n }\n\n .button[aria-disabled='true'] {\n cursor: default;\n pointer-events: none;\n }\n\n /* Page size selector */\n .page-size-wrapper {\n display: flex;\n align-items: center;\n }\n\n .page-size-label {\n display: flex;\n align-items: center;\n gap: var(--hx-space-2, 0.5rem);\n font-size: var(--hx-font-size-sm, 0.875rem);\n color: var(--hx-color-neutral-500, #6b7280);\n white-space: nowrap;\n }\n\n .page-size-select {\n height: var(--hx-pagination-button-size, 2.25rem);\n padding: 0 var(--hx-space-2, 0.5rem);\n border: var(--hx-border-width-thin, 1px) solid\n var(--hx-pagination-border-color, var(--hx-color-neutral-300, #d1d5db));\n border-radius: var(--hx-pagination-border-radius, var(--hx-border-radius-md, 0.375rem));\n background: var(--hx-pagination-bg, var(--hx-color-neutral-0, #ffffff));\n color: var(--hx-pagination-color, var(--hx-color-neutral-900, #111827));\n font-size: var(--hx-font-size-sm, 0.875rem);\n font-family: inherit;\n cursor: pointer;\n }\n\n .page-size-select:focus-visible {\n outline: var(--hx-focus-ring-width, 2px) solid\n var(--hx-pagination-focus-ring-color, var(--hx-focus-ring-color, var(--hx-color-primary-500)));\n outline-offset: var(--hx-focus-ring-offset, 2px);\n }\n\n /* Visually hidden — used for aria-live status messages */\n .visually-hidden {\n position: absolute;\n width: 1px;\n height: 1px;\n padding: 0;\n margin: -1px;\n overflow: hidden;\n clip: rect(0, 0, 0, 0);\n white-space: nowrap;\n border: 0;\n }\n\n @media (prefers-reduced-motion: reduce) {\n .button {\n transition: none;\n }\n }\n\n /* Windows High Contrast / forced-colors support */\n @media (forced-colors: active) {\n .button {\n border: 1px solid ButtonText;\n color: ButtonText;\n background: ButtonFace;\n forced-color-adjust: none;\n }\n\n .button:hover:not(:disabled) {\n border-color: Highlight;\n color: Highlight;\n }\n\n .button:focus-visible {\n outline-color: Highlight;\n }\n\n .button[aria-current='page'] {\n background: Highlight;\n border-color: Highlight;\n color: HighlightText;\n }\n\n .button:disabled {\n color: GrayText;\n border-color: GrayText;\n opacity: 1;\n }\n\n .button[aria-disabled='true'] {\n color: GrayText;\n }\n\n .page-size-select {\n border-color: ButtonText;\n color: ButtonText;\n background: ButtonFace;\n forced-color-adjust: none;\n }\n }\n`;\n","import { LitElement, html, nothing } from 'lit';\nimport '../../utilities/document-token-adoption.js';\nimport { customElement, property, state } from 'lit/decorators.js';\nimport { classMap } from 'lit/directives/class-map.js';\nimport { repeat } from 'lit/directives/repeat.js';\nimport { helixPaginationStyles } from './hx-pagination.styles.js';\n\n/**\n * A pagination component for navigating content listings.\n *\n * @summary Page navigation with page numbers, prev/next, and ellipsis.\n *\n * @tag hx-pagination\n *\n * @csspart nav - The wrapping `<nav>` element.\n * @csspart list - The `<ul>` containing pagination items.\n * @csspart item - Each `<li>` item.\n * @csspart button - Each page button or prev/next control.\n * @csspart ellipsis - The ellipsis (`…`) span between page groups.\n * @csspart page-size-wrapper - The wrapper `<div>` around the page-size selector.\n * @csspart page-size-label - The `<label>` element for the page-size selector.\n * @csspart page-size-select - The `<select>` element for page-size.\n *\n * @cssprop [--hx-pagination-gap=0.25rem] - Gap between pagination buttons. Inherits from --hx-spacing-1.\n * @cssprop [--hx-pagination-button-size=2.25rem] - Minimum width and height of each button.\n * @cssprop [--hx-pagination-border-color] - Border color of buttons. Inherits from --hx-color-border (final fallback: #d1d5db).\n * @cssprop [--hx-pagination-border-radius] - Border radius of buttons. Inherits from --hx-border-radius-md (final fallback: 0.375rem).\n * @cssprop [--hx-pagination-bg] - Background color of buttons. Inherits from --hx-color-surface (final fallback: #ffffff).\n * @cssprop [--hx-pagination-color] - Text color of buttons. Inherits from --hx-color-text-primary (final fallback: #111827).\n * @cssprop [--hx-pagination-hover-bg] - Background color of buttons on hover. Inherits from --hx-color-surface-hover (final fallback: #f3f4f6).\n * @cssprop [--hx-pagination-hover-border-color] - Border color of buttons on hover. Inherits from --hx-color-primary (final fallback: #2563eb).\n * @cssprop [--hx-pagination-active-bg] - Background color of the active/current page button. Inherits from --hx-color-primary (final fallback: #2563eb).\n * @cssprop [--hx-pagination-active-color] - Text color of the active/current page button. Inherits from --hx-color-surface (final fallback: #ffffff).\n * @cssprop [--hx-pagination-active-border-color] - Border color of the active/current page button. Defaults to --hx-pagination-active-bg.\n * @cssprop [--hx-pagination-ellipsis-color] - Color of ellipsis characters. Inherits from --hx-color-text-secondary (final fallback: #6b7280).\n * @cssprop [--hx-transition-fast=150ms] - Duration used for hover/focus transitions.\n *\n * @fires {CustomEvent<{ page: number }>} hx-page-change - Fired when the user navigates to a new page.\n * @fires {CustomEvent<{ pageSize: number }>} hx-page-size-change - Fired when the user selects a new page size.\n *\n * @example\n * ```html\n * <hx-pagination total-pages=\"10\" current-page=\"1\"></hx-pagination>\n * ```\n *\n * @example Drupal / Twig integration\n * ```twig\n * {#\n * Drupal's pager uses 0-based page index in the URL (?page=N).\n * This component is 1-based, so add 1 to the Drupal page value.\n * Listen to hx-page-change and update the URL query param:\n * element.addEventListener('hx-page-change', (e) => {\n * const params = new URLSearchParams(location.search);\n * params.set('page', e.detail.page - 1); // convert back to 0-based\n * history.pushState({}, '', '?' + params.toString());\n * });\n * #}\n * <hx-pagination\n * total-pages=\"{{ total_pages }}\"\n * current-page=\"{{ pager.current_page + 1 }}\"\n * label=\"{{ 'Pagination'|t }}\"\n * {{ show_first_last ? 'show-first-last' : '' }}\n * ></hx-pagination>\n * ```\n */\n@customElement('hx-pagination')\nexport class HelixPagination extends LitElement {\n static override styles = [helixPaginationStyles];\n\n /**\n * Total number of pages.\n * @attr total-pages\n */\n @property({ type: Number, attribute: 'total-pages', reflect: true })\n totalPages = 1;\n\n /**\n * The currently active page (1-based).\n * @attr current-page\n */\n @property({ type: Number, attribute: 'current-page' })\n currentPage = 1;\n\n /**\n * Number of page buttons shown on each side of the current page.\n * @attr sibling-count\n */\n @property({ type: Number, attribute: 'sibling-count', reflect: true })\n siblingCount = 1;\n\n /**\n * Number of pages always shown at the start and end of the list.\n * @attr boundary-count\n */\n @property({ type: Number, attribute: 'boundary-count', reflect: true })\n boundaryCount = 1;\n\n /**\n * Whether to show First and Last page buttons.\n * @attr show-first-last\n */\n @property({ type: Boolean, attribute: 'show-first-last', reflect: true })\n showFirstLast = false;\n\n /**\n * Accessible label for the `<nav>` element.\n * @attr label\n */\n @property({ type: String, reflect: true })\n label = 'Pagination';\n\n /**\n * The number of items displayed per page. When set, a page-size selector\n * `<select>` is rendered. Set `show-page-size` to display the selector.\n * @attr page-size\n */\n @property({ type: Number, attribute: 'page-size', reflect: true })\n pageSize = 25;\n\n /**\n * Whether to show the page-size selector UI.\n * @attr show-page-size\n */\n @property({ type: Boolean, attribute: 'show-page-size', reflect: true })\n showPageSize = false;\n\n /**\n * Label text for the rows-per-page selector.\n * @attr label-rows-per-page\n */\n @property({ type: String, attribute: 'label-rows-per-page' })\n labelRowsPerPage = 'Rows per page:';\n\n /**\n * Accessible label for the \"First page\" navigation button.\n * @attr first-page-label\n */\n @property({ attribute: 'first-page-label' })\n firstPageLabel = 'First page';\n\n /**\n * Accessible label for the \"Previous page\" navigation button.\n * @attr previous-page-label\n */\n @property({ attribute: 'previous-page-label' })\n previousPageLabel = 'Previous page';\n\n /**\n * Accessible label for the \"Next page\" navigation button.\n * @attr next-page-label\n */\n @property({ attribute: 'next-page-label' })\n nextPageLabel = 'Next page';\n\n /**\n * Accessible label for the \"Last page\" navigation button.\n * @attr last-page-label\n */\n @property({ attribute: 'last-page-label' })\n lastPageLabel = 'Last page';\n\n /**\n * Function to format the page navigation announcement. Override for i18n.\n */\n @property({ attribute: false })\n labelPageMessage: (current: number, total: number) => string = (current, total) =>\n `Page ${current} of ${total}`;\n\n /**\n * Function to format page button aria-labels. Override for i18n.\n */\n @property({ attribute: false })\n labelPageButton: (page: number) => string = (page) => `Page ${page}`;\n\n /** Tracks the roving tabindex target. Null means default to currentPage. */\n /** @internal */\n @state() private _rovingKey: number | string | null = null;\n\n /** Text for the aria-live region, updated on navigation. */\n /** @internal */\n @state() private _liveMessage = '';\n\n /** Memoization cache for _buildPageRange. */\n /** @internal */\n private _pageRangeCache: { key: string; result: Array<number | 'ellipsis'> } | null = null;\n\n // ─── Helpers ───\n\n /** @internal */\n private _buildPageRange(): Array<number | 'ellipsis'> {\n const key = `${this.totalPages}-${this.currentPage}-${this.siblingCount}-${this.boundaryCount}`;\n if (this._pageRangeCache?.key === key) return this._pageRangeCache.result;\n\n const total = Math.max(1, this.totalPages);\n const current = Math.min(Math.max(1, this.currentPage), total);\n const boundary = Math.max(0, this.boundaryCount);\n const sibling = Math.max(0, this.siblingCount);\n\n const startPages = this._range(1, Math.min(boundary, total));\n const endPages = this._range(Math.max(total - boundary + 1, boundary + 1), total);\n\n const siblingStart = Math.max(\n Math.min(current - sibling, total - boundary - sibling * 2 - 1),\n boundary + 2,\n );\n const siblingEnd = Math.min(\n Math.max(current + sibling, boundary + sibling * 2 + 2),\n endPages.length > 0 ? (endPages[0] ?? total) - 2 : total - 1,\n );\n\n const items: Array<number | 'ellipsis'> = [];\n\n for (const p of startPages) items.push(p);\n\n if (siblingStart > boundary + 2) {\n items.push('ellipsis');\n } else if (boundary + 1 < siblingStart) {\n items.push(boundary + 1);\n }\n\n for (const p of this._range(siblingStart, siblingEnd)) items.push(p);\n\n if (siblingEnd < total - boundary - 1) {\n items.push('ellipsis');\n } else if (siblingEnd < total - boundary) {\n items.push(total - boundary);\n }\n\n for (const p of endPages) items.push(p);\n\n this._pageRangeCache = { key, result: items };\n return items;\n }\n\n /** @internal */\n private _range(start: number, end: number): number[] {\n const result: number[] = [];\n for (let i = start; i <= end; i++) result.push(i);\n return result;\n }\n\n /** @internal */\n private _navigate(page: number): void {\n const clamped = Math.min(Math.max(1, page), this.totalPages);\n if (clamped === this.currentPage) return;\n\n this.currentPage = clamped;\n this._rovingKey = null; // reset so focus follows the new current page\n this._liveMessage = this.labelPageMessage(clamped, this.totalPages);\n this.dispatchEvent(\n new CustomEvent<{ page: number }>('hx-page-change', {\n detail: { page: clamped },\n bubbles: true,\n composed: true,\n }),\n );\n\n // PAGINATION-005: restore focus to the new current-page button after render\n void this.updateComplete.then(() => {\n const btn = this.shadowRoot?.querySelector<HTMLButtonElement>(\n `button[data-roving-key=\"${clamped}\"]`,\n );\n btn?.focus();\n });\n }\n\n /** @internal */\n private _handlePageSizeChange(e: Event): void {\n const select = e.target as HTMLSelectElement;\n const newSize = Number(select.value);\n if (newSize === this.pageSize) return;\n\n this.pageSize = newSize;\n this.dispatchEvent(\n new CustomEvent<{ pageSize: number }>('hx-page-size-change', {\n detail: { pageSize: newSize },\n bubbles: true,\n composed: true,\n }),\n );\n }\n\n /** @internal */\n private get _effectiveRovingKey(): number | string {\n return this._rovingKey ?? this.currentPage;\n }\n\n /** @internal */\n private _handleFocusin(e: FocusEvent): void {\n const btn = e.target as HTMLElement;\n if (btn.tagName !== 'BUTTON') return;\n const key = btn.dataset['rovingKey'];\n if (key === undefined) return;\n this._rovingKey = isNaN(Number(key)) ? key : Number(key);\n }\n\n /** @internal */\n private _handleKeydown(e: KeyboardEvent): void {\n if (e.key !== 'ArrowLeft' && e.key !== 'ArrowRight' && e.key !== 'Home' && e.key !== 'End')\n return;\n e.preventDefault();\n\n const list = this.shadowRoot?.querySelector('.list');\n if (!list) return;\n\n // Collect all non-disabled buttons (disabled prev/next excluded; aria-disabled current page included)\n const buttons = Array.from(list.querySelectorAll<HTMLButtonElement>('button:not([disabled])'));\n const focused = this.shadowRoot?.activeElement as HTMLButtonElement | null;\n const currentIdx = focused ? buttons.indexOf(focused) : 0;\n\n let nextIdx: number;\n if (e.key === 'Home') {\n nextIdx = 0;\n } else if (e.key === 'End') {\n nextIdx = buttons.length - 1;\n } else {\n nextIdx =\n e.key === 'ArrowLeft'\n ? Math.max(0, currentIdx - 1)\n : Math.min(buttons.length - 1, currentIdx + 1);\n }\n\n if (nextIdx !== currentIdx || e.key === 'Home' || e.key === 'End') {\n const nextBtn = buttons[nextIdx];\n if (!nextBtn) return;\n const key = nextBtn.dataset['rovingKey'];\n if (key !== undefined) {\n this._rovingKey = isNaN(Number(key)) ? key : Number(key);\n }\n nextBtn.focus();\n }\n }\n\n // ─── Render ───\n\n override render() {\n const pages = this._buildPageRange();\n const isFirst = this.currentPage <= 1;\n const isLast = this.currentPage >= this.totalPages;\n const rovingKey = this._effectiveRovingKey;\n\n return html`\n <div class=\"pagination-root\">\n ${this.showPageSize\n ? html`\n <div part=\"page-size-wrapper\" class=\"page-size-wrapper\">\n <label part=\"page-size-label\" class=\"page-size-label\">\n ${this.labelRowsPerPage}\n <select\n part=\"page-size-select\"\n class=\"page-size-select\"\n @change=${this._handlePageSizeChange}\n >\n ${[10, 25, 50, 100].map(\n (n) =>\n html`<option value=${n} ?selected=${n === this.pageSize}>${n}</option>`,\n )}\n </select>\n </label>\n </div>\n `\n : nothing}\n\n <nav part=\"nav\" aria-label=${this.label}>\n <span class=\"visually-hidden\" aria-live=\"polite\" aria-atomic=\"true\"\n >${this._liveMessage}</span\n >\n <ul\n part=\"list\"\n class=\"list\"\n role=\"list\"\n @keydown=${this._handleKeydown}\n @focusin=${this._handleFocusin}\n >\n ${this.showFirstLast\n ? html`\n <li part=\"item\" class=\"item\">\n <button\n part=\"button\"\n class=\"button\"\n ?disabled=${isFirst}\n tabindex=${rovingKey === 'first' ? 0 : -1}\n data-roving-key=\"first\"\n aria-label=${this.firstPageLabel}\n @click=${() => this._navigate(1)}\n >\n «\n </button>\n </li>\n `\n : nothing}\n\n <li part=\"item\" class=\"item\">\n <button\n part=\"button\"\n class=\"button\"\n ?disabled=${isFirst}\n tabindex=${rovingKey === 'prev' ? 0 : -1}\n data-roving-key=\"prev\"\n aria-label=${this.previousPageLabel}\n @click=${() => this._navigate(this.currentPage - 1)}\n >\n ‹\n </button>\n </li>\n\n ${repeat(\n pages,\n (page, i) => (page === 'ellipsis' ? `ellipsis-${i}` : `page-${page}`),\n (page) => {\n if (page === 'ellipsis') {\n return html`\n <li part=\"item\" class=\"item\">\n <span part=\"ellipsis\" class=\"ellipsis\" aria-hidden=\"true\">…</span>\n </li>\n `;\n }\n const isCurrent = page === this.currentPage;\n return html`\n <li part=\"item\" class=\"item\">\n <button\n part=\"button\"\n class=${classMap({ button: true })}\n aria-disabled=${isCurrent ? 'true' : nothing}\n tabindex=${rovingKey === page ? 0 : -1}\n data-roving-key=${page}\n aria-current=${isCurrent ? 'page' : nothing}\n aria-label=${this.labelPageButton(page)}\n @click=${() => this._navigate(page)}\n >\n ${page}\n </button>\n </li>\n `;\n },\n )}\n\n <li part=\"item\" class=\"item\">\n <button\n part=\"button\"\n class=\"button\"\n ?disabled=${isLast}\n tabindex=${rovingKey === 'next' ? 0 : -1}\n data-roving-key=\"next\"\n aria-label=${this.nextPageLabel}\n @click=${() => this._navigate(this.currentPage + 1)}\n >\n ›\n </button>\n </li>\n\n ${this.showFirstLast\n ? html`\n <li part=\"item\" class=\"item\">\n <button\n part=\"button\"\n class=\"button\"\n ?disabled=${isLast}\n tabindex=${rovingKey === 'last' ? 0 : -1}\n data-roving-key=\"last\"\n aria-label=${this.lastPageLabel}\n @click=${() => this._navigate(this.totalPages)}\n >\n »\n </button>\n </li>\n `\n : nothing}\n </ul>\n </nav>\n </div>\n `;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'hx-pagination': HelixPagination;\n }\n}\n\n/** Canonical type alias for HelixPagination. Use this when typing hx-pagination element references. */\nexport type HxPagination = HelixPagination;\n"],"names":["helixPaginationStyles","css","HelixPagination","LitElement","current","total","page","key","_a","boundary","sibling","startPages","endPages","siblingStart","siblingEnd","items","p","start","end","result","i","clamped","btn","e","select","newSize","list","buttons","focused","_b","currentIdx","nextIdx","nextBtn","pages","isFirst","isLast","rovingKey","html","n","nothing","repeat","isCurrent","classMap","__decorateClass","property","state","customElement"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"hx-pagination-BNtx-LG6.js","sources":["../../src/components/hx-pagination/hx-pagination.styles.ts","../../src/components/hx-pagination/hx-pagination.ts"],"sourcesContent":["import { css } from 'lit';\n\nexport const helixPaginationStyles = css`\n :host {\n display: block;\n font-family: var(--hx-font-family-sans, sans-serif);\n }\n\n .pagination-root {\n display: flex;\n align-items: center;\n gap: var(--hx-space-4, 1rem);\n flex-wrap: wrap;\n }\n\n nav {\n display: flex;\n align-items: center;\n justify-content: center;\n }\n\n .list {\n display: flex;\n align-items: center;\n gap: var(--hx-pagination-gap, var(--hx-space-1, 0.25rem));\n list-style: none;\n margin: 0;\n padding: 0;\n }\n\n .item {\n display: flex;\n }\n\n .button {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n min-width: var(--hx-pagination-button-size, 2.25rem);\n height: var(--hx-pagination-button-size, 2.25rem);\n padding: 0 var(--hx-space-2, 0.5rem);\n border: var(--hx-border-width-thin, 1px) solid\n var(--hx-pagination-border-color, var(--hx-color-neutral-300, #d1d5db));\n border-radius: var(--hx-pagination-border-radius, var(--hx-border-radius-md, 0.375rem));\n background: var(--hx-pagination-bg, var(--hx-color-neutral-0, #ffffff));\n color: var(--hx-pagination-color, var(--hx-color-neutral-900, #111827));\n font-size: var(--hx-font-size-sm, 0.875rem);\n font-family: inherit;\n cursor: pointer;\n transition:\n background-color var(--hx-transition-fast, 150ms) ease,\n border-color var(--hx-transition-fast, 150ms) ease,\n color var(--hx-transition-fast, 150ms) ease;\n text-decoration: none;\n white-space: nowrap;\n }\n\n .button:hover:not(:disabled) {\n background: var(--hx-pagination-hover-bg, var(--hx-color-neutral-100, #f3f4f6));\n border-color: var(--hx-pagination-hover-border-color, var(--hx-color-primary-500, #2563eb));\n }\n\n .button:focus-visible {\n outline: var(--hx-focus-ring-width, 2px) solid\n var(--hx-pagination-focus-ring-color, var(--hx-focus-ring-color, var(--hx-color-primary-500)));\n outline-offset: var(--hx-focus-ring-offset, 2px);\n }\n\n .button[aria-current='page'] {\n background: var(--hx-pagination-active-bg, var(--hx-color-primary-500, #2563eb));\n border-color: var(\n --hx-pagination-active-border-color,\n var(--hx-pagination-active-bg, var(--hx-color-primary-500, #2563eb))\n );\n color: var(--hx-pagination-active-color, var(--hx-color-neutral-0, #ffffff));\n font-weight: var(--hx-font-weight-semibold, 600);\n cursor: default;\n pointer-events: none;\n }\n\n .button:disabled {\n opacity: var(--hx-opacity-disabled, 0.5);\n pointer-events: none;\n }\n\n .ellipsis {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n min-width: var(--hx-pagination-button-size, 2.25rem);\n height: var(--hx-pagination-button-size, 2.25rem);\n color: var(--hx-pagination-ellipsis-color, var(--hx-color-neutral-500, #6b7280));\n font-size: var(--hx-font-size-sm, 0.875rem);\n user-select: none;\n }\n\n .button[aria-disabled='true'] {\n cursor: default;\n pointer-events: none;\n }\n\n /* Page size selector */\n .page-size-wrapper {\n display: flex;\n align-items: center;\n }\n\n .page-size-label {\n display: flex;\n align-items: center;\n gap: var(--hx-space-2, 0.5rem);\n font-size: var(--hx-font-size-sm, 0.875rem);\n color: var(--hx-color-neutral-500, #6b7280);\n white-space: nowrap;\n }\n\n .page-size-select {\n height: var(--hx-pagination-button-size, 2.25rem);\n padding: 0 var(--hx-space-2, 0.5rem);\n border: var(--hx-border-width-thin, 1px) solid\n var(--hx-pagination-border-color, var(--hx-color-neutral-300, #d1d5db));\n border-radius: var(--hx-pagination-border-radius, var(--hx-border-radius-md, 0.375rem));\n background: var(--hx-pagination-bg, var(--hx-color-neutral-0, #ffffff));\n color: var(--hx-pagination-color, var(--hx-color-neutral-900, #111827));\n font-size: var(--hx-font-size-sm, 0.875rem);\n font-family: inherit;\n cursor: pointer;\n }\n\n .page-size-select:focus-visible {\n outline: var(--hx-focus-ring-width, 2px) solid\n var(--hx-pagination-focus-ring-color, var(--hx-focus-ring-color, var(--hx-color-primary-500)));\n outline-offset: var(--hx-focus-ring-offset, 2px);\n }\n\n /* Visually hidden — used for aria-live status messages */\n .visually-hidden {\n position: absolute;\n width: 1px;\n height: 1px;\n padding: 0;\n margin: -1px;\n overflow: hidden;\n clip: rect(0, 0, 0, 0);\n white-space: nowrap;\n border: 0;\n }\n\n @media (prefers-reduced-motion: reduce) {\n .button {\n transition: none;\n }\n }\n\n /* Windows High Contrast / forced-colors support */\n @media (forced-colors: active) {\n .button {\n border: 1px solid ButtonText;\n color: ButtonText;\n background: ButtonFace;\n forced-color-adjust: none;\n }\n\n .button:hover:not(:disabled) {\n border-color: Highlight;\n color: Highlight;\n }\n\n .button:focus-visible {\n outline-color: Highlight;\n }\n\n .button[aria-current='page'] {\n background: Highlight;\n border-color: Highlight;\n color: HighlightText;\n }\n\n .button:disabled {\n color: GrayText;\n border-color: GrayText;\n opacity: 1;\n }\n\n .button[aria-disabled='true'] {\n color: GrayText;\n }\n\n .page-size-select {\n border-color: ButtonText;\n color: ButtonText;\n background: ButtonFace;\n forced-color-adjust: none;\n }\n }\n`;\n","import { LitElement, html, nothing } from 'lit';\nimport '../../utilities/document-token-adoption.js';\nimport { customElement, property, state } from 'lit/decorators.js';\nimport { classMap } from 'lit/directives/class-map.js';\nimport { repeat } from 'lit/directives/repeat.js';\nimport { helixPaginationStyles } from './hx-pagination.styles.js';\n\n/**\n * A pagination component for navigating content listings.\n *\n * @summary Page navigation with page numbers, prev/next, and ellipsis.\n *\n * @tag hx-pagination\n *\n * @csspart nav - The wrapping `<nav>` element.\n * @csspart list - The `<ul>` containing pagination items.\n * @csspart item - Each `<li>` item.\n * @csspart button - Each page button or prev/next control.\n * @csspart ellipsis - The ellipsis (`…`) span between page groups.\n * @csspart page-size-wrapper - The wrapper `<div>` around the page-size selector.\n * @csspart page-size-label - The `<label>` element for the page-size selector.\n * @csspart page-size-select - The `<select>` element for page-size.\n *\n * @cssprop [--hx-pagination-gap=0.25rem] - Gap between pagination buttons. Inherits from --hx-spacing-1.\n * @cssprop [--hx-pagination-button-size=2.25rem] - Minimum width and height of each button.\n * @cssprop [--hx-pagination-border-color] - Border color of buttons. Inherits from --hx-color-border (final fallback: #d1d5db).\n * @cssprop [--hx-pagination-border-radius] - Border radius of buttons. Inherits from --hx-border-radius-md (final fallback: 0.375rem).\n * @cssprop [--hx-pagination-bg] - Background color of buttons. Inherits from --hx-color-surface (final fallback: #ffffff).\n * @cssprop [--hx-pagination-color] - Text color of buttons. Inherits from --hx-color-text-primary (final fallback: #111827).\n * @cssprop [--hx-pagination-hover-bg] - Background color of buttons on hover. Inherits from --hx-color-surface-hover (final fallback: #f3f4f6).\n * @cssprop [--hx-pagination-hover-border-color] - Border color of buttons on hover. Inherits from --hx-color-primary (final fallback: #2563eb).\n * @cssprop [--hx-pagination-active-bg] - Background color of the active/current page button. Inherits from --hx-color-primary (final fallback: #2563eb).\n * @cssprop [--hx-pagination-active-color] - Text color of the active/current page button. Inherits from --hx-color-surface (final fallback: #ffffff).\n * @cssprop [--hx-pagination-active-border-color] - Border color of the active/current page button. Defaults to --hx-pagination-active-bg.\n * @cssprop [--hx-pagination-ellipsis-color] - Color of ellipsis characters. Inherits from --hx-color-text-secondary (final fallback: #6b7280).\n * @cssprop [--hx-transition-fast=150ms] - Duration used for hover/focus transitions.\n *\n * @fires {CustomEvent<{ page: number }>} hx-page-change - Fired when the user navigates to a new page.\n * @fires {CustomEvent<{ pageSize: number }>} hx-page-size-change - Fired when the user selects a new page size.\n *\n * @example\n * ```html\n * <hx-pagination total-pages=\"10\" current-page=\"1\"></hx-pagination>\n * ```\n *\n * @example Drupal / Twig integration\n * ```twig\n * {#\n * Drupal's pager uses 0-based page index in the URL (?page=N).\n * This component is 1-based, so add 1 to the Drupal page value.\n * Listen to hx-page-change and update the URL query param:\n * element.addEventListener('hx-page-change', (e) => {\n * const params = new URLSearchParams(location.search);\n * params.set('page', e.detail.page - 1); // convert back to 0-based\n * history.pushState({}, '', '?' + params.toString());\n * });\n * #}\n * <hx-pagination\n * total-pages=\"{{ total_pages }}\"\n * current-page=\"{{ pager.current_page + 1 }}\"\n * label=\"{{ 'Pagination'|t }}\"\n * {{ show_first_last ? 'show-first-last' : '' }}\n * ></hx-pagination>\n * ```\n */\n@customElement('hx-pagination')\nexport class HelixPagination extends LitElement {\n static override styles = [helixPaginationStyles];\n\n /**\n * Total number of pages.\n * @attr total-pages\n */\n @property({ type: Number, attribute: 'total-pages', reflect: true })\n totalPages = 1;\n\n /**\n * The currently active page (1-based).\n * @attr current-page\n */\n @property({ type: Number, attribute: 'current-page' })\n currentPage = 1;\n\n /**\n * Number of page buttons shown on each side of the current page.\n * @attr sibling-count\n */\n @property({ type: Number, attribute: 'sibling-count', reflect: true })\n siblingCount = 1;\n\n /**\n * Number of pages always shown at the start and end of the list.\n * @attr boundary-count\n */\n @property({ type: Number, attribute: 'boundary-count', reflect: true })\n boundaryCount = 1;\n\n /**\n * Whether to show First and Last page buttons.\n * @attr show-first-last\n */\n @property({ type: Boolean, attribute: 'show-first-last', reflect: true })\n showFirstLast = false;\n\n /**\n * Accessible label for the `<nav>` element.\n * @attr label\n */\n @property({ type: String, reflect: true })\n label = 'Pagination';\n\n /**\n * The number of items displayed per page. When set, a page-size selector\n * `<select>` is rendered. Set `show-page-size` to display the selector.\n * @attr page-size\n */\n @property({ type: Number, attribute: 'page-size', reflect: true })\n pageSize = 25;\n\n /**\n * Whether to show the page-size selector UI.\n * @attr show-page-size\n */\n @property({ type: Boolean, attribute: 'show-page-size', reflect: true })\n showPageSize = false;\n\n /**\n * Label text for the rows-per-page selector.\n * @attr label-rows-per-page\n */\n @property({ type: String, attribute: 'label-rows-per-page' })\n labelRowsPerPage = 'Rows per page:';\n\n /**\n * Accessible label for the \"First page\" navigation button.\n * @attr first-page-label\n */\n @property({ attribute: 'first-page-label' })\n firstPageLabel = 'First page';\n\n /**\n * Accessible label for the \"Previous page\" navigation button.\n * @attr previous-page-label\n */\n @property({ attribute: 'previous-page-label' })\n previousPageLabel = 'Previous page';\n\n /**\n * Accessible label for the \"Next page\" navigation button.\n * @attr next-page-label\n */\n @property({ attribute: 'next-page-label' })\n nextPageLabel = 'Next page';\n\n /**\n * Accessible label for the \"Last page\" navigation button.\n * @attr last-page-label\n */\n @property({ attribute: 'last-page-label' })\n lastPageLabel = 'Last page';\n\n /**\n * Function to format the page navigation announcement. Override for i18n.\n */\n @property({ attribute: false })\n labelPageMessage: (current: number, total: number) => string = (current, total) =>\n `Page ${current} of ${total}`;\n\n /**\n * Function to format page button aria-labels. Override for i18n.\n */\n @property({ attribute: false })\n labelPageButton: (page: number) => string = (page) => `Page ${page}`;\n\n /** Tracks the roving tabindex target. Null means default to currentPage. */\n /** @internal */\n @state() private _rovingKey: number | string | null = null;\n\n /** Text for the aria-live region, updated on navigation. */\n /** @internal */\n @state() private _liveMessage = '';\n\n /** Memoization cache for _buildPageRange. */\n /** @internal */\n private _pageRangeCache: { key: string; result: Array<number | 'ellipsis'> } | null = null;\n\n // ─── Helpers ───\n\n /** @internal */\n private _buildPageRange(): Array<number | 'ellipsis'> {\n const key = `${this.totalPages}-${this.currentPage}-${this.siblingCount}-${this.boundaryCount}`;\n if (this._pageRangeCache?.key === key) return this._pageRangeCache.result;\n\n const total = Math.max(1, this.totalPages);\n const current = Math.min(Math.max(1, this.currentPage), total);\n const boundary = Math.max(0, this.boundaryCount);\n const sibling = Math.max(0, this.siblingCount);\n\n const startPages = this._range(1, Math.min(boundary, total));\n const endPages = this._range(Math.max(total - boundary + 1, boundary + 1), total);\n\n const siblingStart = Math.max(\n Math.min(current - sibling, total - boundary - sibling * 2 - 1),\n boundary + 2,\n );\n const siblingEnd = Math.min(\n Math.max(current + sibling, boundary + sibling * 2 + 2),\n endPages.length > 0 ? (endPages[0] ?? total) - 2 : total - 1,\n );\n\n const items: Array<number | 'ellipsis'> = [];\n\n for (const p of startPages) items.push(p);\n\n if (siblingStart > boundary + 2) {\n items.push('ellipsis');\n } else if (boundary + 1 < siblingStart) {\n items.push(boundary + 1);\n }\n\n for (const p of this._range(siblingStart, siblingEnd)) items.push(p);\n\n if (siblingEnd < total - boundary - 1) {\n items.push('ellipsis');\n } else if (siblingEnd < total - boundary) {\n items.push(total - boundary);\n }\n\n for (const p of endPages) items.push(p);\n\n this._pageRangeCache = { key, result: items };\n return items;\n }\n\n /** @internal */\n private _range(start: number, end: number): number[] {\n const result: number[] = [];\n for (let i = start; i <= end; i++) result.push(i);\n return result;\n }\n\n /** @internal */\n private _navigate(page: number): void {\n const clamped = Math.min(Math.max(1, page), this.totalPages);\n if (clamped === this.currentPage) return;\n\n this.currentPage = clamped;\n this._rovingKey = null; // reset so focus follows the new current page\n this._liveMessage = this.labelPageMessage(clamped, this.totalPages);\n this.dispatchEvent(\n new CustomEvent<{ page: number }>('hx-page-change', {\n detail: { page: clamped },\n bubbles: true,\n composed: true,\n }),\n );\n\n // PAGINATION-005: restore focus to the new current-page button after render\n void this.updateComplete.then(() => {\n const btn = this.shadowRoot?.querySelector<HTMLButtonElement>(\n `button[data-roving-key=\"${clamped}\"]`,\n );\n btn?.focus();\n });\n }\n\n /** @internal */\n private _handlePageSizeChange(e: Event): void {\n const select = e.target as HTMLSelectElement;\n const newSize = Number(select.value);\n if (newSize === this.pageSize) return;\n\n this.pageSize = newSize;\n this.dispatchEvent(\n new CustomEvent<{ pageSize: number }>('hx-page-size-change', {\n detail: { pageSize: newSize },\n bubbles: true,\n composed: true,\n }),\n );\n }\n\n /** @internal */\n private get _effectiveRovingKey(): number | string {\n return this._rovingKey ?? this.currentPage;\n }\n\n /** @internal */\n private _handleFocusin(e: FocusEvent): void {\n const btn = e.target as HTMLElement;\n if (btn.tagName !== 'BUTTON') return;\n const key = btn.dataset['rovingKey'];\n if (key === undefined) return;\n this._rovingKey = isNaN(Number(key)) ? key : Number(key);\n }\n\n /** @internal */\n private _handleKeydown(e: KeyboardEvent): void {\n if (e.key !== 'ArrowLeft' && e.key !== 'ArrowRight' && e.key !== 'Home' && e.key !== 'End')\n return;\n e.preventDefault();\n\n const list = this.shadowRoot?.querySelector('.list');\n if (!list) return;\n\n // Collect all non-disabled buttons (disabled prev/next excluded; aria-disabled current page included)\n const buttons = Array.from(list.querySelectorAll<HTMLButtonElement>('button:not([disabled])'));\n const focused = this.shadowRoot?.activeElement as HTMLButtonElement | null;\n const currentIdx = focused ? buttons.indexOf(focused) : 0;\n\n let nextIdx: number;\n if (e.key === 'Home') {\n nextIdx = 0;\n } else if (e.key === 'End') {\n nextIdx = buttons.length - 1;\n } else {\n nextIdx =\n e.key === 'ArrowLeft'\n ? Math.max(0, currentIdx - 1)\n : Math.min(buttons.length - 1, currentIdx + 1);\n }\n\n if (nextIdx !== currentIdx || e.key === 'Home' || e.key === 'End') {\n const nextBtn = buttons[nextIdx];\n if (!nextBtn) return;\n const key = nextBtn.dataset['rovingKey'];\n if (key !== undefined) {\n this._rovingKey = isNaN(Number(key)) ? key : Number(key);\n }\n nextBtn.focus();\n }\n }\n\n // ─── Render ───\n\n override render() {\n const pages = this._buildPageRange();\n const isFirst = this.currentPage <= 1;\n const isLast = this.currentPage >= this.totalPages;\n const rovingKey = this._effectiveRovingKey;\n\n return html`\n <div class=\"pagination-root\">\n ${this.showPageSize\n ? html`\n <div part=\"page-size-wrapper\" class=\"page-size-wrapper\">\n <label part=\"page-size-label\" class=\"page-size-label\">\n ${this.labelRowsPerPage}\n <select\n part=\"page-size-select\"\n class=\"page-size-select\"\n @change=${this._handlePageSizeChange}\n >\n ${[10, 25, 50, 100].map(\n (n) =>\n html`<option value=${n} ?selected=${n === this.pageSize}>${n}</option>`,\n )}\n </select>\n </label>\n </div>\n `\n : nothing}\n\n <nav part=\"nav\" aria-label=${this.label}>\n <span class=\"visually-hidden\" aria-live=\"polite\" aria-atomic=\"true\"\n >${this._liveMessage}</span\n >\n <ul\n part=\"list\"\n class=\"list\"\n role=\"list\"\n @keydown=${this._handleKeydown}\n @focusin=${this._handleFocusin}\n >\n ${this.showFirstLast\n ? html`\n <li part=\"item\" class=\"item\">\n <button\n part=\"button\"\n class=\"button\"\n ?disabled=${isFirst}\n tabindex=${rovingKey === 'first' ? 0 : -1}\n data-roving-key=\"first\"\n aria-label=${this.firstPageLabel}\n @click=${() => this._navigate(1)}\n >\n «\n </button>\n </li>\n `\n : nothing}\n\n <li part=\"item\" class=\"item\">\n <button\n part=\"button\"\n class=\"button\"\n ?disabled=${isFirst}\n tabindex=${rovingKey === 'prev' ? 0 : -1}\n data-roving-key=\"prev\"\n aria-label=${this.previousPageLabel}\n @click=${() => this._navigate(this.currentPage - 1)}\n >\n ‹\n </button>\n </li>\n\n ${repeat(\n pages,\n (page, i) => (page === 'ellipsis' ? `ellipsis-${i}` : `page-${page}`),\n (page) => {\n if (page === 'ellipsis') {\n return html`\n <li part=\"item\" class=\"item\">\n <span part=\"ellipsis\" class=\"ellipsis\" aria-hidden=\"true\">…</span>\n </li>\n `;\n }\n const isCurrent = page === this.currentPage;\n return html`\n <li part=\"item\" class=\"item\">\n <button\n part=\"button\"\n class=${classMap({ button: true })}\n aria-disabled=${isCurrent ? 'true' : nothing}\n tabindex=${rovingKey === page ? 0 : -1}\n data-roving-key=${page}\n aria-current=${isCurrent ? 'page' : nothing}\n aria-label=${this.labelPageButton(page)}\n @click=${() => this._navigate(page)}\n >\n ${page}\n </button>\n </li>\n `;\n },\n )}\n\n <li part=\"item\" class=\"item\">\n <button\n part=\"button\"\n class=\"button\"\n ?disabled=${isLast}\n tabindex=${rovingKey === 'next' ? 0 : -1}\n data-roving-key=\"next\"\n aria-label=${this.nextPageLabel}\n @click=${() => this._navigate(this.currentPage + 1)}\n >\n ›\n </button>\n </li>\n\n ${this.showFirstLast\n ? html`\n <li part=\"item\" class=\"item\">\n <button\n part=\"button\"\n class=\"button\"\n ?disabled=${isLast}\n tabindex=${rovingKey === 'last' ? 0 : -1}\n data-roving-key=\"last\"\n aria-label=${this.lastPageLabel}\n @click=${() => this._navigate(this.totalPages)}\n >\n »\n </button>\n </li>\n `\n : nothing}\n </ul>\n </nav>\n </div>\n `;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'hx-pagination': HelixPagination;\n }\n}\n\n/** Canonical type alias for HelixPagination. Use this when typing hx-pagination element references. */\nexport type HxPagination = HelixPagination;\n"],"names":["helixPaginationStyles","css","HelixPagination","LitElement","current","total","page","key","_a","boundary","sibling","startPages","endPages","siblingStart","siblingEnd","items","p","start","end","result","i","clamped","btn","e","select","newSize","list","buttons","focused","_b","currentIdx","nextIdx","nextBtn","pages","isFirst","isLast","rovingKey","html","n","nothing","repeat","isCurrent","classMap","__decorateClass","property","state","customElement"],"mappings":"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"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { css as c, LitElement as v, nothing as p, html as b } from "lit";
|
|
2
|
-
import "./document-token-adoption-
|
|
2
|
+
import "./document-token-adoption-DuYNKd4k.js";
|
|
3
3
|
import { property as a, state as f, query as h, customElement as u } from "lit/decorators.js";
|
|
4
4
|
const _ = c`
|
|
5
5
|
:host {
|
|
@@ -294,4 +294,4 @@ t = i([
|
|
|
294
294
|
export {
|
|
295
295
|
t as H
|
|
296
296
|
};
|
|
297
|
-
//# sourceMappingURL=hx-patient-banner-
|
|
297
|
+
//# sourceMappingURL=hx-patient-banner-BKiN7nIE.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hx-patient-banner-DLeU2pC2.js","sources":["../../src/components/hx-patient-banner/hx-patient-banner.styles.ts","../../src/components/hx-patient-banner/hx-patient-banner.ts"],"sourcesContent":["import { css } from 'lit';\n\nexport const helixPatientBannerStyles = css`\n :host {\n display: block;\n width: 100%;\n\n /* ─── Private token vars (3-tier cascade) ─── */\n --_bg: var(--hx-patient-banner-bg, var(--hx-color-neutral-50, #f9fafb));\n --_border-color: var(--hx-patient-banner-border-color, var(--hx-color-neutral-200, #e5e7eb));\n --_padding: var(\n --hx-patient-banner-padding,\n var(--hx-space-3, 0.75rem) var(--hx-space-4, 1rem)\n );\n --_gap: var(--hx-patient-banner-gap, var(--hx-space-4, 1rem));\n --_font-family: var(--hx-patient-banner-font-family, var(--hx-font-family-sans, sans-serif));\n --_label-color: var(--hx-patient-banner-label-color, var(--hx-color-neutral-500, #6b7280));\n --_label-font-size: var(--hx-patient-banner-label-font-size, var(--hx-font-size-xs, 0.75rem));\n --_value-color: var(--hx-patient-banner-value-color, var(--hx-color-neutral-900, #111827));\n --_value-font-size: var(--hx-patient-banner-value-font-size, var(--hx-font-size-sm, 0.875rem));\n --_photo-size: var(--hx-patient-banner-photo-size, var(--hx-space-10, 2.5rem));\n --_photo-bg: var(--hx-patient-banner-photo-bg, var(--hx-color-neutral-200, #e5e7eb));\n }\n\n * {\n box-sizing: border-box;\n }\n\n /* ─── Banner Container ─── */\n\n .banner {\n display: flex;\n align-items: center;\n gap: var(--_gap);\n padding: var(--_padding);\n background-color: var(--_bg);\n border-bottom: var(--hx-border-width-thin, 1px) solid var(--_border-color);\n font-family: var(--_font-family);\n width: 100%;\n position: relative;\n }\n\n /* ─── Photo Area ─── */\n\n .banner__photo-area {\n flex-shrink: 0;\n width: var(--_photo-size);\n height: var(--_photo-size);\n /* Minimum 44x44px touch target for interactive photo content. */\n min-width: 44px;\n min-height: 44px;\n border-radius: var(--hx-border-radius-full, 9999px);\n overflow: hidden;\n display: flex;\n align-items: center;\n justify-content: center;\n background-color: var(--_photo-bg);\n }\n\n /* ─── Fields Grid ─── */\n\n .banner__fields {\n display: flex;\n flex-wrap: wrap;\n gap: var(--_gap);\n flex: 1;\n min-width: 0;\n }\n\n /* ─── Individual Field ─── */\n\n .field {\n display: flex;\n flex-direction: column;\n gap: var(--hx-space-1, 0.25rem);\n min-width: 0;\n }\n\n .field__label {\n font-size: var(--_label-font-size);\n color: var(--_label-color);\n font-weight: var(--hx-font-weight-medium, 500);\n line-height: var(--hx-line-height-tight, 1.25);\n white-space: nowrap;\n }\n\n .field__value {\n font-size: var(--_value-font-size);\n color: var(--_value-color);\n font-weight: var(--hx-font-weight-normal, 400);\n line-height: var(--hx-line-height-normal, 1.5);\n display: flex;\n align-items: center;\n gap: var(--hx-space-1, 0.25rem);\n }\n\n /* ─── Identifier Rule Violation ─── */\n /* Visual indicator when Joint Commission two-identifier rule is not met. */\n\n :host([aria-invalid='true']) .banner {\n border-bottom-color: var(--hx-color-error-400, #f87171);\n background-color: var(--hx-color-error-50, #fef2f2);\n /* Darken label color to maintain 4.5:1 contrast on error-50 background. */\n --_label-color: var(--hx-patient-banner-label-color, var(--hx-color-neutral-700, #374151));\n }\n\n :host([aria-invalid='true']) .banner::before {\n content: '';\n display: block;\n position: absolute;\n inset-inline-start: 0;\n top: 0;\n bottom: 0;\n width: var(--hx-border-width-thick, 4px);\n background-color: var(--hx-color-error-500, #ef4444);\n border-radius: 0;\n }\n\n /* ─── Visually-hidden violation live region ─── */\n /* Announces identifier rule violations to screen readers without visible text. */\n\n .violation-message {\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-width: 0;\n }\n\n /* ─── Motion reduction ─── */\n\n @media (prefers-reduced-motion: reduce) {\n * {\n transition: none !important;\n animation: none !important;\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 { helixPatientBannerStyles } from './hx-patient-banner.styles.js';\n\n/**\n * Patient identification banner implementing Joint Commission NPSG.01.01.01 two-identifier rule.\n * Renders as a landmark region containing named slots for patient identification fields.\n * Integrates with hx-phi-field for HIPAA-compliant display of masked identifiers.\n * Note: hx-phi-access events fired by slotted hx-phi-field elements bubble through this\n * component via composed: true — no re-dispatch is required.\n *\n * @summary Patient identification banner with two-identifier rule enforcement.\n *\n * @tag hx-patient-banner\n *\n * @slot photo - Optional patient photo slot.\n * @slot name - Patient name field content.\n * @slot mrn - Medical record number field content. Use hx-phi-field for HIPAA compliance.\n * @slot dob - Date of birth field content. Use hx-phi-field for HIPAA compliance.\n * @slot allergies - Allergy status/flag content.\n * @slot code-status - Code status content.\n *\n * @csspart banner - The outer banner container.\n * @csspart photo-area - The photo slot wrapper.\n * @csspart fields - The fields grid container.\n * @csspart field - An individual field container (applied to all field wrappers).\n * @csspart field-label - The field label element.\n * @csspart field-value - The field value slot wrapper.\n * @csspart violation-message - The visually-hidden identifier rule violation status message.\n *\n * @fires {CustomEvent<PatientIdentifierRuleViolationDetail>} hx-identifier-rule-violation - Fired when fewer than 2 identifier slots are populated and enforce-identifier-rule is true.\n *\n * @cssprop [--hx-patient-banner-bg=var(--hx-color-neutral-50,#f9fafb)] - Banner background color.\n * @cssprop [--hx-patient-banner-border-color=var(--hx-color-neutral-200,#e5e7eb)] - Banner border color.\n * @cssprop [--hx-patient-banner-padding=var(--hx-space-3,0.75rem) var(--hx-space-4,1rem)] - Banner padding.\n * @cssprop [--hx-patient-banner-gap=var(--hx-space-4,1rem)] - Gap between banner fields.\n * @cssprop [--hx-patient-banner-font-family=var(--hx-font-family-sans,sans-serif)] - Banner font family.\n * @cssprop [--hx-patient-banner-label-color=var(--hx-color-neutral-500,#6b7280)] - Field label color.\n * @cssprop [--hx-patient-banner-label-font-size=var(--hx-font-size-xs,0.75rem)] - Field label font size.\n * @cssprop [--hx-patient-banner-value-color=var(--hx-color-neutral-900,#111827)] - Field value color.\n * @cssprop [--hx-patient-banner-value-font-size=var(--hx-font-size-sm,0.875rem)] - Field value font size.\n * @cssprop [--hx-patient-banner-photo-size=var(--hx-space-10,2.5rem)] - Photo area size.\n * @cssprop [--hx-patient-banner-photo-bg=var(--hx-color-neutral-200,#e5e7eb)] - Photo area background color when empty.\n */\n@customElement('hx-patient-banner')\nexport class HelixPatientBanner extends LitElement {\n static override styles = [helixPatientBannerStyles];\n\n // ─── Public Properties ───\n\n /**\n * Optional patient ID used as context in identifier rule violation events.\n * @attr patient-id\n */\n @property({ type: String, attribute: 'patient-id' })\n patientId: string = '';\n\n /**\n * Accessible label for the banner landmark region.\n * @attr label-patient\n */\n @property({ type: String, attribute: 'label-patient' })\n labelPatient: string = 'Patient identification';\n\n /**\n * Visible label for the name field.\n * @attr label-name\n */\n @property({ type: String, attribute: 'label-name' })\n labelName: string = 'Patient name';\n\n /**\n * Visible label for the MRN field.\n * @attr label-mrn\n */\n @property({ type: String, attribute: 'label-mrn' })\n labelMrn: string = 'MRN';\n\n /**\n * Visible label for the date of birth field.\n * @attr label-dob\n */\n @property({ type: String, attribute: 'label-dob' })\n labelDob: string = 'Date of birth';\n\n /**\n * Visible label for the allergies field.\n * @attr label-allergies\n */\n @property({ type: String, attribute: 'label-allergies' })\n labelAllergies: string = 'Allergies';\n\n /**\n * Visible label for the code status field.\n * @attr label-code-status\n */\n @property({ type: String, attribute: 'label-code-status' })\n labelCodeStatus: string = 'Code status';\n\n /**\n * Whether to enforce the Joint Commission NPSG.01.01.01 two-identifier rule.\n * When true, fires hx-identifier-rule-violation if fewer than 2 identifier\n * slots (name, mrn, dob) are populated.\n * @attr enforce-identifier-rule\n */\n @property({\n attribute: 'enforce-identifier-rule',\n reflect: true,\n converter: {\n fromAttribute: (value: string | null) => value !== 'false',\n toAttribute: (value: boolean) => String(value),\n },\n })\n enforceIdentifierRule: boolean = true;\n\n // ─── Internal State ───\n\n /** @internal */\n @state() private _identifierCount: number = 0;\n\n /** @internal */\n @state() private _isViolating: boolean = false;\n\n // ─── Slot Queries ───\n\n /** @internal */\n @query('slot[name=\"name\"]') private _nameSlot!: HTMLSlotElement;\n\n /** @internal */\n @query('slot[name=\"mrn\"]') private _mrnSlot!: HTMLSlotElement;\n\n /** @internal */\n @query('slot[name=\"dob\"]') private _dobSlot!: HTMLSlotElement;\n\n // ─── Lifecycle ───\n\n override connectedCallback(): void {\n super.connectedCallback();\n this.setAttribute('role', 'banner');\n this.setAttribute('aria-label', this.labelPatient);\n }\n\n protected override updated(changedProperties: PropertyValues<this>): void {\n super.updated(changedProperties);\n\n if (changedProperties.has('labelPatient')) {\n this.setAttribute('aria-label', this.labelPatient);\n }\n\n if (changedProperties.has('enforceIdentifierRule')) {\n this._checkIdentifierRule();\n }\n }\n\n // ─── Private Helpers ───\n\n private _countPopulatedIdentifiers(): number {\n let count = 0;\n\n const slots = [this._nameSlot, this._mrnSlot, this._dobSlot];\n for (const slot of slots) {\n if (slot && slot.assignedNodes({ flatten: true }).length > 0) {\n count++;\n }\n }\n\n return count;\n }\n\n private _checkIdentifierRule(): void {\n const count = this._countPopulatedIdentifiers();\n this._identifierCount = count;\n\n if (this.enforceIdentifierRule && count < 2) {\n this._isViolating = true;\n this.setAttribute('aria-invalid', 'true');\n this.dispatchEvent(\n new CustomEvent<PatientIdentifierRuleViolationDetail>('hx-identifier-rule-violation', {\n bubbles: true,\n composed: true,\n detail: {\n populatedIdentifiers: count,\n requiredIdentifiers: 2,\n patientId: this.patientId,\n },\n }),\n );\n } else {\n this._isViolating = false;\n this.removeAttribute('aria-invalid');\n }\n }\n\n // ─── Event Handlers ───\n\n private _handleSlotChange(): void {\n this._checkIdentifierRule();\n }\n\n // ─── Render ───\n\n override render() {\n const violationMessage = this._isViolating\n ? `Warning: patient identification incomplete. ${this._identifierCount} of 2 required identifiers present.`\n : nothing;\n\n return html`\n <div part=\"banner\" class=\"banner\">\n <div part=\"photo-area\" class=\"banner__photo-area\" aria-hidden=\"true\">\n <slot name=\"photo\"></slot>\n </div>\n\n <div part=\"fields\" class=\"banner__fields\">\n <div part=\"field\" class=\"field\">\n <span part=\"field-label\" class=\"field__label\">${this.labelName}</span>\n <div part=\"field-value\" class=\"field__value\">\n <slot name=\"name\" @slotchange=${this._handleSlotChange}></slot>\n </div>\n </div>\n\n <div part=\"field\" class=\"field\">\n <span part=\"field-label\" class=\"field__label\">${this.labelMrn}</span>\n <div part=\"field-value\" class=\"field__value\">\n <slot name=\"mrn\" @slotchange=${this._handleSlotChange}></slot>\n </div>\n </div>\n\n <div part=\"field\" class=\"field\">\n <span part=\"field-label\" class=\"field__label\">${this.labelDob}</span>\n <div part=\"field-value\" class=\"field__value\">\n <slot name=\"dob\" @slotchange=${this._handleSlotChange}></slot>\n </div>\n </div>\n\n <div part=\"field\" class=\"field\">\n <span part=\"field-label\" class=\"field__label\">${this.labelAllergies}</span>\n <div part=\"field-value\" class=\"field__value\">\n <slot name=\"allergies\"></slot>\n </div>\n </div>\n\n <div part=\"field\" class=\"field\">\n <span part=\"field-label\" class=\"field__label\">${this.labelCodeStatus}</span>\n <div part=\"field-value\" class=\"field__value\">\n <slot name=\"code-status\"></slot>\n </div>\n </div>\n </div>\n </div>\n\n ${violationMessage !== nothing\n ? html`<div\n part=\"violation-message\"\n class=\"violation-message\"\n role=\"alert\"\n aria-live=\"assertive\"\n >\n ${violationMessage}\n </div>`\n : nothing}\n `;\n }\n}\n\nexport interface PatientIdentifierRuleViolationDetail {\n populatedIdentifiers: number;\n requiredIdentifiers: number;\n patientId: string;\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'hx-patient-banner': HelixPatientBanner;\n }\n}\n"],"names":["helixPatientBannerStyles","css","HelixPatientBanner","LitElement","changedProperties","count","slots","slot","violationMessage","nothing","html","__decorateClass","property","value","state","query","customElement"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"hx-patient-banner-BKiN7nIE.js","sources":["../../src/components/hx-patient-banner/hx-patient-banner.styles.ts","../../src/components/hx-patient-banner/hx-patient-banner.ts"],"sourcesContent":["import { css } from 'lit';\n\nexport const helixPatientBannerStyles = css`\n :host {\n display: block;\n width: 100%;\n\n /* ─── Private token vars (3-tier cascade) ─── */\n --_bg: var(--hx-patient-banner-bg, var(--hx-color-neutral-50, #f9fafb));\n --_border-color: var(--hx-patient-banner-border-color, var(--hx-color-neutral-200, #e5e7eb));\n --_padding: var(\n --hx-patient-banner-padding,\n var(--hx-space-3, 0.75rem) var(--hx-space-4, 1rem)\n );\n --_gap: var(--hx-patient-banner-gap, var(--hx-space-4, 1rem));\n --_font-family: var(--hx-patient-banner-font-family, var(--hx-font-family-sans, sans-serif));\n --_label-color: var(--hx-patient-banner-label-color, var(--hx-color-neutral-500, #6b7280));\n --_label-font-size: var(--hx-patient-banner-label-font-size, var(--hx-font-size-xs, 0.75rem));\n --_value-color: var(--hx-patient-banner-value-color, var(--hx-color-neutral-900, #111827));\n --_value-font-size: var(--hx-patient-banner-value-font-size, var(--hx-font-size-sm, 0.875rem));\n --_photo-size: var(--hx-patient-banner-photo-size, var(--hx-space-10, 2.5rem));\n --_photo-bg: var(--hx-patient-banner-photo-bg, var(--hx-color-neutral-200, #e5e7eb));\n }\n\n * {\n box-sizing: border-box;\n }\n\n /* ─── Banner Container ─── */\n\n .banner {\n display: flex;\n align-items: center;\n gap: var(--_gap);\n padding: var(--_padding);\n background-color: var(--_bg);\n border-bottom: var(--hx-border-width-thin, 1px) solid var(--_border-color);\n font-family: var(--_font-family);\n width: 100%;\n position: relative;\n }\n\n /* ─── Photo Area ─── */\n\n .banner__photo-area {\n flex-shrink: 0;\n width: var(--_photo-size);\n height: var(--_photo-size);\n /* Minimum 44x44px touch target for interactive photo content. */\n min-width: 44px;\n min-height: 44px;\n border-radius: var(--hx-border-radius-full, 9999px);\n overflow: hidden;\n display: flex;\n align-items: center;\n justify-content: center;\n background-color: var(--_photo-bg);\n }\n\n /* ─── Fields Grid ─── */\n\n .banner__fields {\n display: flex;\n flex-wrap: wrap;\n gap: var(--_gap);\n flex: 1;\n min-width: 0;\n }\n\n /* ─── Individual Field ─── */\n\n .field {\n display: flex;\n flex-direction: column;\n gap: var(--hx-space-1, 0.25rem);\n min-width: 0;\n }\n\n .field__label {\n font-size: var(--_label-font-size);\n color: var(--_label-color);\n font-weight: var(--hx-font-weight-medium, 500);\n line-height: var(--hx-line-height-tight, 1.25);\n white-space: nowrap;\n }\n\n .field__value {\n font-size: var(--_value-font-size);\n color: var(--_value-color);\n font-weight: var(--hx-font-weight-normal, 400);\n line-height: var(--hx-line-height-normal, 1.5);\n display: flex;\n align-items: center;\n gap: var(--hx-space-1, 0.25rem);\n }\n\n /* ─── Identifier Rule Violation ─── */\n /* Visual indicator when Joint Commission two-identifier rule is not met. */\n\n :host([aria-invalid='true']) .banner {\n border-bottom-color: var(--hx-color-error-400, #f87171);\n background-color: var(--hx-color-error-50, #fef2f2);\n /* Darken label color to maintain 4.5:1 contrast on error-50 background. */\n --_label-color: var(--hx-patient-banner-label-color, var(--hx-color-neutral-700, #374151));\n }\n\n :host([aria-invalid='true']) .banner::before {\n content: '';\n display: block;\n position: absolute;\n inset-inline-start: 0;\n top: 0;\n bottom: 0;\n width: var(--hx-border-width-thick, 4px);\n background-color: var(--hx-color-error-500, #ef4444);\n border-radius: 0;\n }\n\n /* ─── Visually-hidden violation live region ─── */\n /* Announces identifier rule violations to screen readers without visible text. */\n\n .violation-message {\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-width: 0;\n }\n\n /* ─── Motion reduction ─── */\n\n @media (prefers-reduced-motion: reduce) {\n * {\n transition: none !important;\n animation: none !important;\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 { helixPatientBannerStyles } from './hx-patient-banner.styles.js';\n\n/**\n * Patient identification banner implementing Joint Commission NPSG.01.01.01 two-identifier rule.\n * Renders as a landmark region containing named slots for patient identification fields.\n * Integrates with hx-phi-field for HIPAA-compliant display of masked identifiers.\n * Note: hx-phi-access events fired by slotted hx-phi-field elements bubble through this\n * component via composed: true — no re-dispatch is required.\n *\n * @summary Patient identification banner with two-identifier rule enforcement.\n *\n * @tag hx-patient-banner\n *\n * @slot photo - Optional patient photo slot.\n * @slot name - Patient name field content.\n * @slot mrn - Medical record number field content. Use hx-phi-field for HIPAA compliance.\n * @slot dob - Date of birth field content. Use hx-phi-field for HIPAA compliance.\n * @slot allergies - Allergy status/flag content.\n * @slot code-status - Code status content.\n *\n * @csspart banner - The outer banner container.\n * @csspart photo-area - The photo slot wrapper.\n * @csspart fields - The fields grid container.\n * @csspart field - An individual field container (applied to all field wrappers).\n * @csspart field-label - The field label element.\n * @csspart field-value - The field value slot wrapper.\n * @csspart violation-message - The visually-hidden identifier rule violation status message.\n *\n * @fires {CustomEvent<PatientIdentifierRuleViolationDetail>} hx-identifier-rule-violation - Fired when fewer than 2 identifier slots are populated and enforce-identifier-rule is true.\n *\n * @cssprop [--hx-patient-banner-bg=var(--hx-color-neutral-50,#f9fafb)] - Banner background color.\n * @cssprop [--hx-patient-banner-border-color=var(--hx-color-neutral-200,#e5e7eb)] - Banner border color.\n * @cssprop [--hx-patient-banner-padding=var(--hx-space-3,0.75rem) var(--hx-space-4,1rem)] - Banner padding.\n * @cssprop [--hx-patient-banner-gap=var(--hx-space-4,1rem)] - Gap between banner fields.\n * @cssprop [--hx-patient-banner-font-family=var(--hx-font-family-sans,sans-serif)] - Banner font family.\n * @cssprop [--hx-patient-banner-label-color=var(--hx-color-neutral-500,#6b7280)] - Field label color.\n * @cssprop [--hx-patient-banner-label-font-size=var(--hx-font-size-xs,0.75rem)] - Field label font size.\n * @cssprop [--hx-patient-banner-value-color=var(--hx-color-neutral-900,#111827)] - Field value color.\n * @cssprop [--hx-patient-banner-value-font-size=var(--hx-font-size-sm,0.875rem)] - Field value font size.\n * @cssprop [--hx-patient-banner-photo-size=var(--hx-space-10,2.5rem)] - Photo area size.\n * @cssprop [--hx-patient-banner-photo-bg=var(--hx-color-neutral-200,#e5e7eb)] - Photo area background color when empty.\n */\n@customElement('hx-patient-banner')\nexport class HelixPatientBanner extends LitElement {\n static override styles = [helixPatientBannerStyles];\n\n // ─── Public Properties ───\n\n /**\n * Optional patient ID used as context in identifier rule violation events.\n * @attr patient-id\n */\n @property({ type: String, attribute: 'patient-id' })\n patientId: string = '';\n\n /**\n * Accessible label for the banner landmark region.\n * @attr label-patient\n */\n @property({ type: String, attribute: 'label-patient' })\n labelPatient: string = 'Patient identification';\n\n /**\n * Visible label for the name field.\n * @attr label-name\n */\n @property({ type: String, attribute: 'label-name' })\n labelName: string = 'Patient name';\n\n /**\n * Visible label for the MRN field.\n * @attr label-mrn\n */\n @property({ type: String, attribute: 'label-mrn' })\n labelMrn: string = 'MRN';\n\n /**\n * Visible label for the date of birth field.\n * @attr label-dob\n */\n @property({ type: String, attribute: 'label-dob' })\n labelDob: string = 'Date of birth';\n\n /**\n * Visible label for the allergies field.\n * @attr label-allergies\n */\n @property({ type: String, attribute: 'label-allergies' })\n labelAllergies: string = 'Allergies';\n\n /**\n * Visible label for the code status field.\n * @attr label-code-status\n */\n @property({ type: String, attribute: 'label-code-status' })\n labelCodeStatus: string = 'Code status';\n\n /**\n * Whether to enforce the Joint Commission NPSG.01.01.01 two-identifier rule.\n * When true, fires hx-identifier-rule-violation if fewer than 2 identifier\n * slots (name, mrn, dob) are populated.\n * @attr enforce-identifier-rule\n */\n @property({\n attribute: 'enforce-identifier-rule',\n reflect: true,\n converter: {\n fromAttribute: (value: string | null) => value !== 'false',\n toAttribute: (value: boolean) => String(value),\n },\n })\n enforceIdentifierRule: boolean = true;\n\n // ─── Internal State ───\n\n /** @internal */\n @state() private _identifierCount: number = 0;\n\n /** @internal */\n @state() private _isViolating: boolean = false;\n\n // ─── Slot Queries ───\n\n /** @internal */\n @query('slot[name=\"name\"]') private _nameSlot!: HTMLSlotElement;\n\n /** @internal */\n @query('slot[name=\"mrn\"]') private _mrnSlot!: HTMLSlotElement;\n\n /** @internal */\n @query('slot[name=\"dob\"]') private _dobSlot!: HTMLSlotElement;\n\n // ─── Lifecycle ───\n\n override connectedCallback(): void {\n super.connectedCallback();\n this.setAttribute('role', 'banner');\n this.setAttribute('aria-label', this.labelPatient);\n }\n\n protected override updated(changedProperties: PropertyValues<this>): void {\n super.updated(changedProperties);\n\n if (changedProperties.has('labelPatient')) {\n this.setAttribute('aria-label', this.labelPatient);\n }\n\n if (changedProperties.has('enforceIdentifierRule')) {\n this._checkIdentifierRule();\n }\n }\n\n // ─── Private Helpers ───\n\n private _countPopulatedIdentifiers(): number {\n let count = 0;\n\n const slots = [this._nameSlot, this._mrnSlot, this._dobSlot];\n for (const slot of slots) {\n if (slot && slot.assignedNodes({ flatten: true }).length > 0) {\n count++;\n }\n }\n\n return count;\n }\n\n private _checkIdentifierRule(): void {\n const count = this._countPopulatedIdentifiers();\n this._identifierCount = count;\n\n if (this.enforceIdentifierRule && count < 2) {\n this._isViolating = true;\n this.setAttribute('aria-invalid', 'true');\n this.dispatchEvent(\n new CustomEvent<PatientIdentifierRuleViolationDetail>('hx-identifier-rule-violation', {\n bubbles: true,\n composed: true,\n detail: {\n populatedIdentifiers: count,\n requiredIdentifiers: 2,\n patientId: this.patientId,\n },\n }),\n );\n } else {\n this._isViolating = false;\n this.removeAttribute('aria-invalid');\n }\n }\n\n // ─── Event Handlers ───\n\n private _handleSlotChange(): void {\n this._checkIdentifierRule();\n }\n\n // ─── Render ───\n\n override render() {\n const violationMessage = this._isViolating\n ? `Warning: patient identification incomplete. ${this._identifierCount} of 2 required identifiers present.`\n : nothing;\n\n return html`\n <div part=\"banner\" class=\"banner\">\n <div part=\"photo-area\" class=\"banner__photo-area\" aria-hidden=\"true\">\n <slot name=\"photo\"></slot>\n </div>\n\n <div part=\"fields\" class=\"banner__fields\">\n <div part=\"field\" class=\"field\">\n <span part=\"field-label\" class=\"field__label\">${this.labelName}</span>\n <div part=\"field-value\" class=\"field__value\">\n <slot name=\"name\" @slotchange=${this._handleSlotChange}></slot>\n </div>\n </div>\n\n <div part=\"field\" class=\"field\">\n <span part=\"field-label\" class=\"field__label\">${this.labelMrn}</span>\n <div part=\"field-value\" class=\"field__value\">\n <slot name=\"mrn\" @slotchange=${this._handleSlotChange}></slot>\n </div>\n </div>\n\n <div part=\"field\" class=\"field\">\n <span part=\"field-label\" class=\"field__label\">${this.labelDob}</span>\n <div part=\"field-value\" class=\"field__value\">\n <slot name=\"dob\" @slotchange=${this._handleSlotChange}></slot>\n </div>\n </div>\n\n <div part=\"field\" class=\"field\">\n <span part=\"field-label\" class=\"field__label\">${this.labelAllergies}</span>\n <div part=\"field-value\" class=\"field__value\">\n <slot name=\"allergies\"></slot>\n </div>\n </div>\n\n <div part=\"field\" class=\"field\">\n <span part=\"field-label\" class=\"field__label\">${this.labelCodeStatus}</span>\n <div part=\"field-value\" class=\"field__value\">\n <slot name=\"code-status\"></slot>\n </div>\n </div>\n </div>\n </div>\n\n ${violationMessage !== nothing\n ? html`<div\n part=\"violation-message\"\n class=\"violation-message\"\n role=\"alert\"\n aria-live=\"assertive\"\n >\n ${violationMessage}\n </div>`\n : nothing}\n `;\n }\n}\n\nexport interface PatientIdentifierRuleViolationDetail {\n populatedIdentifiers: number;\n requiredIdentifiers: number;\n patientId: string;\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'hx-patient-banner': HelixPatientBanner;\n }\n}\n"],"names":["helixPatientBannerStyles","css","HelixPatientBanner","LitElement","changedProperties","count","slots","slot","violationMessage","nothing","html","__decorateClass","property","value","state","query","customElement"],"mappings":"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"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { css as c, LitElement as p, html as h } from "lit";
|
|
2
|
-
import "./document-token-adoption-
|
|
2
|
+
import "./document-token-adoption-DuYNKd4k.js";
|
|
3
3
|
import { property as n, state as u, customElement as f } from "lit/decorators.js";
|
|
4
4
|
const m = c`
|
|
5
5
|
:host {
|
|
@@ -292,4 +292,4 @@ a = s([
|
|
|
292
292
|
export {
|
|
293
293
|
a as H
|
|
294
294
|
};
|
|
295
|
-
//# sourceMappingURL=hx-phi-field-
|
|
295
|
+
//# sourceMappingURL=hx-phi-field-BiJH3V-k.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hx-phi-field-BwlVKfHI.js","sources":["../../src/components/hx-phi-field/hx-phi-field.styles.ts","../../src/components/hx-phi-field/hx-phi-field.ts"],"sourcesContent":["import { css } from 'lit';\n\nexport const helixPhiFieldStyles = css`\n :host {\n display: inline-flex;\n }\n\n /* ─── Container ─── */\n\n .phi-field {\n display: inline-flex;\n align-items: center;\n gap: var(--hx-space-2, 0.5rem);\n font-family: var(--hx-phi-field-font-family, var(--hx-font-family-mono, monospace));\n }\n\n /* ─── Value ─── */\n\n .phi-field__value--masked {\n user-select: none;\n -webkit-user-select: none;\n color: var(--hx-phi-field-masked-color, var(--hx-color-neutral-500, #6b7280));\n letter-spacing: 0.1em;\n }\n\n .phi-field__value--revealed {\n color: var(--hx-phi-field-value-color, var(--hx-color-neutral-900, #111827));\n }\n\n /* ─── Screen Reader Status ─── */\n\n .phi-field__status {\n position: absolute;\n width: 1px;\n height: 1px;\n overflow: hidden;\n clip: rect(0, 0, 0, 0);\n white-space: nowrap;\n border: 0;\n padding: 0;\n margin: -1px;\n }\n\n /* ─── Toggle Button ─── */\n\n .phi-field__toggle {\n display: inline-flex;\n align-items: center;\n background: none;\n border: none;\n padding: var(--hx-space-1, 0.25rem);\n color: var(--hx-phi-field-toggle-color, var(--hx-color-primary-500, #2563eb));\n cursor: pointer;\n line-height: 1;\n border-radius: var(--hx-border-radius-sm, 0.25rem);\n }\n\n .phi-field__toggle:focus-visible {\n outline: var(--hx-focus-ring-width, 2px) solid\n var(\n --hx-phi-field-focus-ring-color,\n var(--hx-focus-ring-color, var(--hx-color-primary-500, #2563eb))\n );\n outline-offset: var(--hx-focus-ring-offset, 2px);\n }\n\n .phi-field__toggle:hover {\n opacity: var(--hx-opacity-90, 0.9);\n }\n\n .phi-field__toggle:active {\n opacity: var(--hx-opacity-50, 0.5);\n }\n\n .phi-field__toggle svg {\n width: 1em;\n height: 1em;\n pointer-events: none;\n }\n\n /* ─── Disabled State ─── */\n\n :host([disabled]) {\n opacity: var(--hx-phi-field-disabled-opacity, var(--hx-opacity-50, 0.5));\n pointer-events: none;\n cursor: not-allowed;\n }\n\n .phi-field--disabled .phi-field__toggle {\n cursor: not-allowed;\n }\n\n /* ─── Reduced Motion ─── */\n\n @media (prefers-reduced-motion: reduce) {\n .phi-field__toggle {\n transition: none;\n }\n }\n`;\n","import { LitElement, html, type TemplateResult } from 'lit';\nimport '../../utilities/document-token-adoption.js';\nimport { customElement, property, state } from 'lit/decorators.js';\nimport { helixPhiFieldStyles } from './hx-phi-field.styles.js';\n\n/**\n * HIPAA-compliant field component for rendering masked Protected Health Information (PHI).\n * PHI is masked by default and only rendered to the DOM when explicitly revealed. Access\n * events are fired on reveal, hide, and clipboard auto-clear for audit trail purposes.\n *\n * @summary HIPAA-compliant field for rendering masked Protected Health Information.\n *\n * @tag hx-phi-field\n *\n * @csspart container - The outer wrapper element.\n * @csspart value - The value display span (masked or revealed).\n * @csspart toggle - The reveal/hide toggle button.\n *\n * @fires {CustomEvent<PhiAccessEventDetail>} hx-phi-access - Fired on reveal, hide, and clipboard-clear actions.\n *\n * @cssprop [--hx-phi-field-font-family=var(--hx-font-family-mono,monospace)] - Font family for the masked value.\n * @cssprop [--hx-phi-field-value-color=var(--hx-color-neutral-900,#111827)] - Value text color.\n * @cssprop [--hx-phi-field-masked-color=var(--hx-color-neutral-500,#6b7280)] - Masked value text color.\n * @cssprop [--hx-phi-field-toggle-color=var(--hx-color-primary-500,#2563eb)] - Toggle button color.\n * @cssprop [--hx-phi-field-focus-ring-color=var(--hx-focus-ring-color,var(--hx-color-primary-500,#2563eb))] - Focus ring color.\n * @cssprop [--hx-phi-field-disabled-opacity=var(--hx-opacity-50,0.5)] - Opacity applied when the field is disabled.\n */\n@customElement('hx-phi-field')\nexport class HelixPhiField extends LitElement {\n static override styles = [helixPhiFieldStyles];\n\n // ─── Public Properties ───\n\n /**\n * The Protected Health Information value to display or mask.\n * @attr data\n */\n @property({ type: String })\n data: string = '';\n\n /**\n * The type of PHI field. Controls the masking pattern applied.\n * @attr field-type\n */\n @property({ type: String, reflect: true, attribute: 'field-type' })\n fieldType: 'ssn' | 'mrn' | 'dob' | 'insurance' = 'ssn';\n\n /**\n * Identifier used in audit events. Falls back to the element's id attribute.\n * @attr field-id\n */\n @property({ type: String, attribute: 'field-id' })\n fieldId: string = '';\n\n /**\n * Milliseconds after clipboard write before the clipboard is automatically cleared.\n * Defaults to 30000 (30 seconds).\n * @attr clipboard-timeout\n */\n @property({ type: Number, attribute: 'clipboard-timeout' })\n clipboardTimeout: number = 30000;\n\n /**\n * Accessible label describing the PHI field. Used as a prefix in screen reader\n * announcements (e.g., \"Social Security Number is masked\").\n * @attr label\n */\n @property({ type: String })\n label: string = '';\n\n /**\n * When set, disables all interaction with the field and prevents reveal.\n * @attr disabled\n * @reflect\n */\n @property({ type: Boolean, reflect: true })\n disabled: boolean = false;\n\n // ─── Internal State ───\n\n /** @internal */\n @state() private _masked = true;\n\n /** @internal */\n private _clipboardTimer: ReturnType<typeof setTimeout> | null = null;\n\n // ─── Lifecycle ───\n\n override connectedCallback(): void {\n super.connectedCallback();\n // Enforce HIPAA compliance: prevent browser autofill on the host element\n this.setAttribute('autocomplete', 'off');\n }\n\n override disconnectedCallback(): void {\n super.disconnectedCallback();\n this._cancelClipboardTimer();\n }\n\n // ─── Private Helpers ───\n\n /** @internal */\n private _cancelClipboardTimer(): void {\n if (this._clipboardTimer !== null) {\n clearTimeout(this._clipboardTimer);\n this._clipboardTimer = null;\n }\n }\n\n /** @internal */\n private _scheduleClipboardClear(): void {\n this._cancelClipboardTimer();\n this._clipboardTimer = setTimeout(() => {\n this._clearClipboard();\n }, this.clipboardTimeout);\n }\n\n /** @internal */\n private _clearClipboard(): void {\n this._clipboardTimer = null;\n if (typeof navigator !== 'undefined' && navigator.clipboard) {\n navigator?.clipboard?.writeText('').catch(() => {\n // Clipboard clear failure is non-fatal — silently ignore\n });\n }\n this.dispatchEvent(\n new CustomEvent<PhiAccessEventDetail>('hx-phi-access', {\n bubbles: true,\n composed: true,\n detail: {\n fieldId: this.fieldId || this.id || '',\n action: 'clipboard-clear',\n timestamp: new Date().toISOString(),\n fieldType: this.fieldType,\n },\n }),\n );\n this._masked = true;\n }\n\n /** @internal */\n private _getMaskedValue(): string {\n if (!this.data) return '';\n\n switch (this.fieldType) {\n case 'ssn': {\n // Format: xxx-xx-xxxx → ***-**-xxxx (show last 4 digits)\n // Match the separator-delimited pattern first\n const ssnMatch = this.data.match(/^(\\d{3})(-?)(\\d{2})(-?)(\\d{4})$/);\n if (ssnMatch) {\n return `***${ssnMatch[2]}**${ssnMatch[4]}${ssnMatch[5]}`;\n }\n // Fallback: mask all but last 4 chars\n return this.data.slice(0, -4).replace(/\\d/g, '*') + this.data.slice(-4);\n }\n\n case 'mrn': {\n // Mask all but last 4 alphanumeric characters, preserve separators\n const chars = this.data.split('');\n const alphanumericIndices: number[] = [];\n chars.forEach((ch, i) => {\n if (/[a-zA-Z0-9]/.test(ch)) {\n alphanumericIndices.push(i);\n }\n });\n const revealCount = Math.min(4, alphanumericIndices.length);\n const maskUntilIdx = alphanumericIndices.length - revealCount;\n const indicesToMask = new Set(alphanumericIndices.slice(0, maskUntilIdx));\n return chars.map((ch, i) => (indicesToMask.has(i) ? '*' : ch)).join('');\n }\n\n case 'dob': {\n // Replace ALL digits with *, preserve separators\n return this.data.replace(/\\d/g, '*');\n }\n\n case 'insurance': {\n // Format: xxxx-xxxx-xxxx-xxxx → ****-****-****-xxxx (show last 4 digits)\n const insMatch = this.data.match(/^(\\d{4})(-?)(\\d{4})(-?)(\\d{4})(-?)(\\d{4})$/);\n if (insMatch) {\n return `****${insMatch[2]}****${insMatch[4]}****${insMatch[6]}${insMatch[7]}`;\n }\n // Fallback: mask all but last 4 chars\n return this.data.slice(0, -4).replace(/[a-zA-Z0-9]/g, '*') + this.data.slice(-4);\n }\n\n default: {\n // Exhaustive check — fieldType is typed, but guard defensively\n const _exhaustive: never = this.fieldType;\n return _exhaustive;\n }\n }\n }\n\n // ─── Event Handlers ───\n\n /** @internal */\n private _handleToggle(): void {\n if (this.disabled) return;\n\n // Dispatch BEFORE toggling state so action reflects the upcoming state\n this.dispatchEvent(\n new CustomEvent<PhiAccessEventDetail>('hx-phi-access', {\n bubbles: true,\n composed: true,\n detail: {\n fieldId: this.fieldId || this.id || '',\n action: this._masked ? 'reveal' : 'hide',\n timestamp: new Date().toISOString(),\n fieldType: this.fieldType,\n },\n }),\n );\n\n if (this._masked) {\n // Revealing: start clipboard clear timer\n this._masked = false;\n this._scheduleClipboardClear();\n } else {\n // Hiding: cancel any pending clipboard clear\n this._cancelClipboardTimer();\n this._masked = true;\n }\n }\n\n /** @internal */\n private _handleCopy(e: ClipboardEvent): void {\n if (this._masked) {\n e.preventDefault();\n }\n }\n\n /** @internal */\n private _handlePaste(e: ClipboardEvent): void {\n if (this._masked) {\n e.preventDefault();\n }\n }\n\n // ─── Render Helpers ───\n\n /** @internal */\n private _renderEyeIcon(): TemplateResult {\n return html`\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\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 <path d=\"M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z\" />\n <circle cx=\"12\" cy=\"12\" r=\"3\" />\n </svg>\n `;\n }\n\n /** @internal */\n private _renderEyeOffIcon(): TemplateResult {\n return html`\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\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 <path d=\"M17.94 17.94A10.07 10.07 0 0 1 12 20c-7 0-11-8-11-8a18.45 18.45 0 0 1 5.06-5.94\" />\n <path d=\"M9.9 4.24A9.12 9.12 0 0 1 12 4c7 0 11 8 11 8a18.5 18.5 0 0 1-2.16 3.19\" />\n <line x1=\"1\" y1=\"1\" x2=\"23\" y2=\"23\" />\n </svg>\n `;\n }\n\n // ─── Render ───\n\n override render() {\n const fieldLabel = this.label || 'Protected health information';\n const maskedLabel = `${fieldLabel} is masked`;\n const revealedLabel = `${fieldLabel} is revealed`;\n const revealActionLabel = `Reveal ${fieldLabel.toLowerCase()}`;\n const hideActionLabel = `Hide ${fieldLabel.toLowerCase()}`;\n\n return html`\n <div\n part=\"container\"\n class=\"phi-field${this.disabled ? ' phi-field--disabled' : ''}\"\n @copy=${this._handleCopy}\n @paste=${this._handlePaste}\n >\n ${this._masked\n ? html`<span part=\"value\" class=\"phi-field__value phi-field__value--masked\"\n >${this._getMaskedValue()}</span\n >`\n : html`<span part=\"value\" class=\"phi-field__value phi-field__value--revealed\"\n >${this.data}</span\n >`}\n <span role=\"status\" aria-live=\"polite\" aria-atomic=\"true\" class=\"phi-field__status\">\n ${this._masked ? maskedLabel : revealedLabel}\n </span>\n <button\n part=\"toggle\"\n class=\"phi-field__toggle\"\n type=\"button\"\n ?disabled=${this.disabled}\n aria-label=${this._masked ? revealActionLabel : hideActionLabel}\n aria-pressed=${String(!this._masked)}\n @click=${this._handleToggle}\n >\n ${this._masked ? this._renderEyeIcon() : this._renderEyeOffIcon()}\n </button>\n </div>\n `;\n }\n}\n\nexport interface PhiAccessEventDetail {\n fieldId: string;\n /** The action that triggered the audit event. */\n action: 'reveal' | 'hide' | 'clipboard-clear';\n timestamp: string;\n fieldType: 'ssn' | 'mrn' | 'dob' | 'insurance';\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'hx-phi-field': HelixPhiField;\n }\n}\n"],"names":["helixPhiFieldStyles","css","HelixPhiField","LitElement","_a","ssnMatch","chars","alphanumericIndices","ch","i","revealCount","maskUntilIdx","indicesToMask","insMatch","html","fieldLabel","maskedLabel","revealedLabel","revealActionLabel","hideActionLabel","__decorateClass","property","state","customElement"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"hx-phi-field-BiJH3V-k.js","sources":["../../src/components/hx-phi-field/hx-phi-field.styles.ts","../../src/components/hx-phi-field/hx-phi-field.ts"],"sourcesContent":["import { css } from 'lit';\n\nexport const helixPhiFieldStyles = css`\n :host {\n display: inline-flex;\n }\n\n /* ─── Container ─── */\n\n .phi-field {\n display: inline-flex;\n align-items: center;\n gap: var(--hx-space-2, 0.5rem);\n font-family: var(--hx-phi-field-font-family, var(--hx-font-family-mono, monospace));\n }\n\n /* ─── Value ─── */\n\n .phi-field__value--masked {\n user-select: none;\n -webkit-user-select: none;\n color: var(--hx-phi-field-masked-color, var(--hx-color-neutral-500, #6b7280));\n letter-spacing: 0.1em;\n }\n\n .phi-field__value--revealed {\n color: var(--hx-phi-field-value-color, var(--hx-color-neutral-900, #111827));\n }\n\n /* ─── Screen Reader Status ─── */\n\n .phi-field__status {\n position: absolute;\n width: 1px;\n height: 1px;\n overflow: hidden;\n clip: rect(0, 0, 0, 0);\n white-space: nowrap;\n border: 0;\n padding: 0;\n margin: -1px;\n }\n\n /* ─── Toggle Button ─── */\n\n .phi-field__toggle {\n display: inline-flex;\n align-items: center;\n background: none;\n border: none;\n padding: var(--hx-space-1, 0.25rem);\n color: var(--hx-phi-field-toggle-color, var(--hx-color-primary-500, #2563eb));\n cursor: pointer;\n line-height: 1;\n border-radius: var(--hx-border-radius-sm, 0.25rem);\n }\n\n .phi-field__toggle:focus-visible {\n outline: var(--hx-focus-ring-width, 2px) solid\n var(\n --hx-phi-field-focus-ring-color,\n var(--hx-focus-ring-color, var(--hx-color-primary-500, #2563eb))\n );\n outline-offset: var(--hx-focus-ring-offset, 2px);\n }\n\n .phi-field__toggle:hover {\n opacity: var(--hx-opacity-90, 0.9);\n }\n\n .phi-field__toggle:active {\n opacity: var(--hx-opacity-50, 0.5);\n }\n\n .phi-field__toggle svg {\n width: 1em;\n height: 1em;\n pointer-events: none;\n }\n\n /* ─── Disabled State ─── */\n\n :host([disabled]) {\n opacity: var(--hx-phi-field-disabled-opacity, var(--hx-opacity-50, 0.5));\n pointer-events: none;\n cursor: not-allowed;\n }\n\n .phi-field--disabled .phi-field__toggle {\n cursor: not-allowed;\n }\n\n /* ─── Reduced Motion ─── */\n\n @media (prefers-reduced-motion: reduce) {\n .phi-field__toggle {\n transition: none;\n }\n }\n`;\n","import { LitElement, html, type TemplateResult } from 'lit';\nimport '../../utilities/document-token-adoption.js';\nimport { customElement, property, state } from 'lit/decorators.js';\nimport { helixPhiFieldStyles } from './hx-phi-field.styles.js';\n\n/**\n * HIPAA-compliant field component for rendering masked Protected Health Information (PHI).\n * PHI is masked by default and only rendered to the DOM when explicitly revealed. Access\n * events are fired on reveal, hide, and clipboard auto-clear for audit trail purposes.\n *\n * @summary HIPAA-compliant field for rendering masked Protected Health Information.\n *\n * @tag hx-phi-field\n *\n * @csspart container - The outer wrapper element.\n * @csspart value - The value display span (masked or revealed).\n * @csspart toggle - The reveal/hide toggle button.\n *\n * @fires {CustomEvent<PhiAccessEventDetail>} hx-phi-access - Fired on reveal, hide, and clipboard-clear actions.\n *\n * @cssprop [--hx-phi-field-font-family=var(--hx-font-family-mono,monospace)] - Font family for the masked value.\n * @cssprop [--hx-phi-field-value-color=var(--hx-color-neutral-900,#111827)] - Value text color.\n * @cssprop [--hx-phi-field-masked-color=var(--hx-color-neutral-500,#6b7280)] - Masked value text color.\n * @cssprop [--hx-phi-field-toggle-color=var(--hx-color-primary-500,#2563eb)] - Toggle button color.\n * @cssprop [--hx-phi-field-focus-ring-color=var(--hx-focus-ring-color,var(--hx-color-primary-500,#2563eb))] - Focus ring color.\n * @cssprop [--hx-phi-field-disabled-opacity=var(--hx-opacity-50,0.5)] - Opacity applied when the field is disabled.\n */\n@customElement('hx-phi-field')\nexport class HelixPhiField extends LitElement {\n static override styles = [helixPhiFieldStyles];\n\n // ─── Public Properties ───\n\n /**\n * The Protected Health Information value to display or mask.\n * @attr data\n */\n @property({ type: String })\n data: string = '';\n\n /**\n * The type of PHI field. Controls the masking pattern applied.\n * @attr field-type\n */\n @property({ type: String, reflect: true, attribute: 'field-type' })\n fieldType: 'ssn' | 'mrn' | 'dob' | 'insurance' = 'ssn';\n\n /**\n * Identifier used in audit events. Falls back to the element's id attribute.\n * @attr field-id\n */\n @property({ type: String, attribute: 'field-id' })\n fieldId: string = '';\n\n /**\n * Milliseconds after clipboard write before the clipboard is automatically cleared.\n * Defaults to 30000 (30 seconds).\n * @attr clipboard-timeout\n */\n @property({ type: Number, attribute: 'clipboard-timeout' })\n clipboardTimeout: number = 30000;\n\n /**\n * Accessible label describing the PHI field. Used as a prefix in screen reader\n * announcements (e.g., \"Social Security Number is masked\").\n * @attr label\n */\n @property({ type: String })\n label: string = '';\n\n /**\n * When set, disables all interaction with the field and prevents reveal.\n * @attr disabled\n * @reflect\n */\n @property({ type: Boolean, reflect: true })\n disabled: boolean = false;\n\n // ─── Internal State ───\n\n /** @internal */\n @state() private _masked = true;\n\n /** @internal */\n private _clipboardTimer: ReturnType<typeof setTimeout> | null = null;\n\n // ─── Lifecycle ───\n\n override connectedCallback(): void {\n super.connectedCallback();\n // Enforce HIPAA compliance: prevent browser autofill on the host element\n this.setAttribute('autocomplete', 'off');\n }\n\n override disconnectedCallback(): void {\n super.disconnectedCallback();\n this._cancelClipboardTimer();\n }\n\n // ─── Private Helpers ───\n\n /** @internal */\n private _cancelClipboardTimer(): void {\n if (this._clipboardTimer !== null) {\n clearTimeout(this._clipboardTimer);\n this._clipboardTimer = null;\n }\n }\n\n /** @internal */\n private _scheduleClipboardClear(): void {\n this._cancelClipboardTimer();\n this._clipboardTimer = setTimeout(() => {\n this._clearClipboard();\n }, this.clipboardTimeout);\n }\n\n /** @internal */\n private _clearClipboard(): void {\n this._clipboardTimer = null;\n if (typeof navigator !== 'undefined' && navigator.clipboard) {\n navigator?.clipboard?.writeText('').catch(() => {\n // Clipboard clear failure is non-fatal — silently ignore\n });\n }\n this.dispatchEvent(\n new CustomEvent<PhiAccessEventDetail>('hx-phi-access', {\n bubbles: true,\n composed: true,\n detail: {\n fieldId: this.fieldId || this.id || '',\n action: 'clipboard-clear',\n timestamp: new Date().toISOString(),\n fieldType: this.fieldType,\n },\n }),\n );\n this._masked = true;\n }\n\n /** @internal */\n private _getMaskedValue(): string {\n if (!this.data) return '';\n\n switch (this.fieldType) {\n case 'ssn': {\n // Format: xxx-xx-xxxx → ***-**-xxxx (show last 4 digits)\n // Match the separator-delimited pattern first\n const ssnMatch = this.data.match(/^(\\d{3})(-?)(\\d{2})(-?)(\\d{4})$/);\n if (ssnMatch) {\n return `***${ssnMatch[2]}**${ssnMatch[4]}${ssnMatch[5]}`;\n }\n // Fallback: mask all but last 4 chars\n return this.data.slice(0, -4).replace(/\\d/g, '*') + this.data.slice(-4);\n }\n\n case 'mrn': {\n // Mask all but last 4 alphanumeric characters, preserve separators\n const chars = this.data.split('');\n const alphanumericIndices: number[] = [];\n chars.forEach((ch, i) => {\n if (/[a-zA-Z0-9]/.test(ch)) {\n alphanumericIndices.push(i);\n }\n });\n const revealCount = Math.min(4, alphanumericIndices.length);\n const maskUntilIdx = alphanumericIndices.length - revealCount;\n const indicesToMask = new Set(alphanumericIndices.slice(0, maskUntilIdx));\n return chars.map((ch, i) => (indicesToMask.has(i) ? '*' : ch)).join('');\n }\n\n case 'dob': {\n // Replace ALL digits with *, preserve separators\n return this.data.replace(/\\d/g, '*');\n }\n\n case 'insurance': {\n // Format: xxxx-xxxx-xxxx-xxxx → ****-****-****-xxxx (show last 4 digits)\n const insMatch = this.data.match(/^(\\d{4})(-?)(\\d{4})(-?)(\\d{4})(-?)(\\d{4})$/);\n if (insMatch) {\n return `****${insMatch[2]}****${insMatch[4]}****${insMatch[6]}${insMatch[7]}`;\n }\n // Fallback: mask all but last 4 chars\n return this.data.slice(0, -4).replace(/[a-zA-Z0-9]/g, '*') + this.data.slice(-4);\n }\n\n default: {\n // Exhaustive check — fieldType is typed, but guard defensively\n const _exhaustive: never = this.fieldType;\n return _exhaustive;\n }\n }\n }\n\n // ─── Event Handlers ───\n\n /** @internal */\n private _handleToggle(): void {\n if (this.disabled) return;\n\n // Dispatch BEFORE toggling state so action reflects the upcoming state\n this.dispatchEvent(\n new CustomEvent<PhiAccessEventDetail>('hx-phi-access', {\n bubbles: true,\n composed: true,\n detail: {\n fieldId: this.fieldId || this.id || '',\n action: this._masked ? 'reveal' : 'hide',\n timestamp: new Date().toISOString(),\n fieldType: this.fieldType,\n },\n }),\n );\n\n if (this._masked) {\n // Revealing: start clipboard clear timer\n this._masked = false;\n this._scheduleClipboardClear();\n } else {\n // Hiding: cancel any pending clipboard clear\n this._cancelClipboardTimer();\n this._masked = true;\n }\n }\n\n /** @internal */\n private _handleCopy(e: ClipboardEvent): void {\n if (this._masked) {\n e.preventDefault();\n }\n }\n\n /** @internal */\n private _handlePaste(e: ClipboardEvent): void {\n if (this._masked) {\n e.preventDefault();\n }\n }\n\n // ─── Render Helpers ───\n\n /** @internal */\n private _renderEyeIcon(): TemplateResult {\n return html`\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\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 <path d=\"M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z\" />\n <circle cx=\"12\" cy=\"12\" r=\"3\" />\n </svg>\n `;\n }\n\n /** @internal */\n private _renderEyeOffIcon(): TemplateResult {\n return html`\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\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 <path d=\"M17.94 17.94A10.07 10.07 0 0 1 12 20c-7 0-11-8-11-8a18.45 18.45 0 0 1 5.06-5.94\" />\n <path d=\"M9.9 4.24A9.12 9.12 0 0 1 12 4c7 0 11 8 11 8a18.5 18.5 0 0 1-2.16 3.19\" />\n <line x1=\"1\" y1=\"1\" x2=\"23\" y2=\"23\" />\n </svg>\n `;\n }\n\n // ─── Render ───\n\n override render() {\n const fieldLabel = this.label || 'Protected health information';\n const maskedLabel = `${fieldLabel} is masked`;\n const revealedLabel = `${fieldLabel} is revealed`;\n const revealActionLabel = `Reveal ${fieldLabel.toLowerCase()}`;\n const hideActionLabel = `Hide ${fieldLabel.toLowerCase()}`;\n\n return html`\n <div\n part=\"container\"\n class=\"phi-field${this.disabled ? ' phi-field--disabled' : ''}\"\n @copy=${this._handleCopy}\n @paste=${this._handlePaste}\n >\n ${this._masked\n ? html`<span part=\"value\" class=\"phi-field__value phi-field__value--masked\"\n >${this._getMaskedValue()}</span\n >`\n : html`<span part=\"value\" class=\"phi-field__value phi-field__value--revealed\"\n >${this.data}</span\n >`}\n <span role=\"status\" aria-live=\"polite\" aria-atomic=\"true\" class=\"phi-field__status\">\n ${this._masked ? maskedLabel : revealedLabel}\n </span>\n <button\n part=\"toggle\"\n class=\"phi-field__toggle\"\n type=\"button\"\n ?disabled=${this.disabled}\n aria-label=${this._masked ? revealActionLabel : hideActionLabel}\n aria-pressed=${String(!this._masked)}\n @click=${this._handleToggle}\n >\n ${this._masked ? this._renderEyeIcon() : this._renderEyeOffIcon()}\n </button>\n </div>\n `;\n }\n}\n\nexport interface PhiAccessEventDetail {\n fieldId: string;\n /** The action that triggered the audit event. */\n action: 'reveal' | 'hide' | 'clipboard-clear';\n timestamp: string;\n fieldType: 'ssn' | 'mrn' | 'dob' | 'insurance';\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'hx-phi-field': HelixPhiField;\n }\n}\n"],"names":["helixPhiFieldStyles","css","HelixPhiField","LitElement","_a","ssnMatch","chars","alphanumericIndices","ch","i","revealCount","maskUntilIdx","indicesToMask","insMatch","html","fieldLabel","maskedLabel","revealedLabel","revealActionLabel","hideActionLabel","__decorateClass","property","state","customElement"],"mappings":"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"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { css as H, LitElement as k, nothing as $, html as y } from "lit";
|
|
2
|
-
import "./document-token-adoption-
|
|
2
|
+
import "./document-token-adoption-DuYNKd4k.js";
|
|
3
3
|
import { property as d, state as C, customElement as P } from "lit/decorators.js";
|
|
4
4
|
const D = H`
|
|
5
5
|
:host {
|
|
@@ -298,4 +298,4 @@ a = h([
|
|
|
298
298
|
export {
|
|
299
299
|
a as H
|
|
300
300
|
};
|
|
301
|
-
//# sourceMappingURL=hx-popover-
|
|
301
|
+
//# sourceMappingURL=hx-popover-D63RXn5H.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hx-popover-DdjLdSr8.js","sources":["../../src/components/hx-popover/hx-popover.styles.ts","../../src/components/hx-popover/hx-popover.ts"],"sourcesContent":["import { css } from 'lit';\n\nexport const helixPopoverStyles = css`\n :host {\n /* P2-05: display:contents lets the trigger-wrapper control layout inline;\n position:relative was vestigial — body uses position:fixed via Floating UI */\n display: contents;\n }\n\n .trigger-wrapper {\n display: inline-block;\n }\n\n [part='body'] {\n position: fixed;\n z-index: var(--hx-popover-z-index, 9999);\n max-width: var(--hx-popover-max-width, 320px);\n padding: var(--hx-popover-padding, var(--hx-space-3, 0.75rem));\n background: var(--hx-popover-bg, var(--hx-color-neutral-0, #ffffff));\n color: var(--hx-popover-color, var(--hx-color-neutral-900, #111827));\n font-family: var(--hx-font-family-sans, sans-serif);\n font-size: var(--hx-popover-font-size, var(--hx-font-size-sm, 0.875rem));\n line-height: var(--hx-line-height-normal, 1.5);\n border: 1px solid var(--hx-popover-border-color, var(--hx-color-neutral-200, #e5e7eb));\n border-radius: var(--hx-popover-border-radius, var(--hx-border-radius-md, 0.375rem));\n box-shadow: var(\n --hx-popover-shadow,\n var(--hx-shadow-md, 0 4px 16px var(--hx-overlay-black-12, rgba(0, 0, 0, 0.12)))\n );\n visibility: hidden;\n opacity: 0;\n transition:\n opacity var(--hx-popover-transition-duration, 0.2s) ease,\n visibility var(--hx-popover-transition-duration, 0.2s) ease;\n word-wrap: break-word;\n }\n\n [part='body'].visible {\n visibility: visible;\n opacity: 1;\n }\n\n [part='body']:focus-visible {\n outline: var(--hx-focus-ring-width, 2px) solid\n var(--hx-popover-focus-ring-color, var(--hx-focus-ring-color, var(--hx-color-primary-500)));\n outline-offset: var(--hx-focus-ring-offset, 2px);\n }\n\n [part='arrow'] {\n position: absolute;\n width: var(--hx-popover-arrow-size, 10px);\n height: var(--hx-popover-arrow-size, 10px);\n background: var(--hx-popover-bg, var(--hx-color-neutral-0, #ffffff));\n border: 1px solid var(--hx-popover-border-color, var(--hx-color-neutral-200, #e5e7eb));\n transform: rotate(45deg);\n pointer-events: none;\n }\n\n @media (prefers-reduced-motion: reduce) {\n [part='body'] {\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 } from 'lit/decorators.js';\nimport { helixPopoverStyles } from './hx-popover.styles.js';\n\nlet _popoverCounter = 0;\n\n/**\n * A popover that displays rich floating content attached to a trigger element.\n *\n * @summary Rich floating overlay attached to a trigger element.\n *\n * @tag hx-popover\n *\n * @slot anchor - The trigger element that opens the popover.\n * @slot - Default slot for popover body content.\n *\n * @csspart body - The popover body container element.\n * @csspart arrow - The arrow indicator element.\n *\n * @cssprop [--hx-popover-bg=var(--hx-color-neutral-0)] - Popover background color.\n * @cssprop [--hx-popover-color=var(--hx-color-neutral-900)] - Popover text color.\n * @cssprop [--hx-popover-font-size=var(--hx-font-size-sm)] - Popover font size.\n * @cssprop [--hx-popover-max-width=320px] - Maximum popover width.\n * @cssprop [--hx-popover-padding] - Popover padding.\n * @cssprop [--hx-popover-border-color=var(--hx-color-neutral-200)] - Popover border color.\n * @cssprop [--hx-popover-border-radius=var(--hx-border-radius-md)] - Popover border radius.\n * @cssprop [--hx-popover-shadow] - Popover box shadow.\n * @cssprop [--hx-popover-z-index=9999] - Popover z-index.\n * @cssprop [--hx-popover-transition-duration=0.2s] - Show/hide transition duration.\n * @cssprop [--hx-popover-arrow-size=10px] - Size of the arrow indicator.\n *\n * @fires {CustomEvent} hx-show - Emitted when the popover begins to show.\n * @fires {CustomEvent} hx-after-show - Emitted after the popover is fully visible.\n * @fires {CustomEvent} hx-hide - Emitted when the popover begins to hide.\n * @fires {CustomEvent} hx-after-hide - Emitted after the popover is fully hidden.\n *\n * @example\n * ```html\n * <hx-popover placement=\"bottom\" trigger=\"click\">\n * <button slot=\"anchor\">Open Popover</button>\n * <p>Rich popover content here.</p>\n * </hx-popover>\n * ```\n */\n\n@customElement('hx-popover')\nexport class HelixPopover extends LitElement {\n static override styles = [helixPopoverStyles];\n\n /**\n * Whether the popover is open.\n * @attr open\n */\n @property({ type: Boolean, reflect: true })\n open = false;\n\n /**\n * Preferred placement of the popover relative to the anchor.\n * @attr placement\n */\n @property({ type: String, reflect: true })\n placement:\n | 'top'\n | 'top-start'\n | 'top-end'\n | 'right'\n | 'right-start'\n | 'right-end'\n | 'bottom'\n | 'bottom-start'\n | 'bottom-end'\n | 'left'\n | 'left-start'\n | 'left-end' = 'bottom';\n\n /**\n * How the popover is triggered.\n * @attr trigger\n */\n @property({ type: String, reflect: true })\n trigger: 'click' | 'hover' | 'focus' | 'manual' = 'click';\n\n /**\n * Distance in pixels between the popover and the anchor.\n * @attr distance\n */\n @property({ type: Number, reflect: true })\n distance = 8;\n\n /**\n * Alignment offset in pixels along the anchor.\n * @attr skidding\n */\n @property({ type: Number, reflect: true })\n skidding = 0;\n\n /**\n * Whether to show an arrow pointing to the anchor.\n * @attr arrow\n */\n @property({ type: Boolean, reflect: true })\n arrow = false;\n\n /**\n * Accessible label for the popover body (sets aria-label on the dialog).\n * @attr label\n */\n @property({ type: String, reflect: true })\n label = 'Popover';\n\n /**\n * Tracks whether the popover body is currently visible.\n * @internal\n */\n @state() private _visible = false;\n\n /**\n * The element that held focus before the popover opened, used to restore focus on close.\n * @internal\n */\n private _previousFocus: HTMLElement | null = null;\n\n /**\n * Unique ID assigned to the popover body element.\n * @internal\n */\n private readonly _popoverId = `hx-popover-${++_popoverCounter}`;\n\n /**\n * Timer ID for the deferred document click listener registration in _show().\n * Stored so it can be cancelled in disconnectedCallback to prevent leaks.\n * @internal\n */\n private _showTimer: ReturnType<typeof setTimeout> | null = null;\n\n /**\n * Timer ID for the hover-triggered hide delay.\n * WCAG 1.4.13: hoverable content must remain visible while the pointer is\n * over it. A 150 ms delay allows the pointer to move from the anchor into\n * the popover body without the content dismissing prematurely.\n * @internal\n */\n private _hoverHideTimer: ReturnType<typeof setTimeout> | null = null;\n\n // ─── Lifecycle ───\n\n override disconnectedCallback(): void {\n super.disconnectedCallback();\n if (this._showTimer !== null) {\n clearTimeout(this._showTimer);\n this._showTimer = null;\n }\n if (this._hoverHideTimer !== null) {\n clearTimeout(this._hoverHideTimer);\n this._hoverHideTimer = null;\n }\n document.removeEventListener('click', this._handleDocumentClick);\n document.removeEventListener('keydown', this._handleDocumentKeydown);\n }\n\n override firstUpdated(): void {\n // HIGH-02: set aria-haspopup=\"dialog\" once on the anchor so assistive technology\n // announces the control's popup type before it is ever opened.\n this._setAnchorAriaAttributes(false);\n // Sync initial open state\n if (this.open) {\n void this._show();\n }\n }\n\n override updated(changedProperties: PropertyValues<this>): void {\n if (changedProperties.has('open')) {\n if (this.open) {\n void this._show();\n } else {\n void this._hide();\n }\n }\n }\n\n // ─── ARIA setup ───\n\n // HIGH-02: set aria-haspopup=\"dialog\" on firstUpdated and keep aria-expanded in sync\n /** @internal */\n private _setAnchorAriaAttributes(expanded: boolean): void {\n const anchorSlot = this.shadowRoot?.querySelector(\n 'slot[name=\"anchor\"]',\n ) as HTMLSlotElement | null;\n if (!anchorSlot) return;\n const anchorEl = anchorSlot.assignedElements()[0] as HTMLElement | undefined;\n if (anchorEl) {\n anchorEl.setAttribute('aria-expanded', String(expanded));\n anchorEl.setAttribute('aria-haspopup', 'dialog');\n // aria-controls is omitted: the body lives in Shadow DOM and axe-core\n // cannot resolve cross-root IDREF values, which causes a critical violation.\n }\n }\n\n // ─── Focus helpers ───\n\n /** Return all keyboard-focusable elements inside the popover body's slotted content. */\n /** @internal */\n private _getFocusableElements(): HTMLElement[] {\n const bodyEl = this.shadowRoot?.querySelector('[part=\"body\"]') as HTMLElement | null;\n if (!bodyEl) return [];\n\n // Gather focusable elements from the default slot's assigned nodes\n const defaultSlot = bodyEl.querySelector('slot:not([name])') as HTMLSlotElement | null;\n if (!defaultSlot) return [];\n\n const assigned = defaultSlot.assignedElements({ flatten: true });\n const focusableSelector =\n 'a[href], area[href], button:not([disabled]), input:not([disabled]), select:not([disabled]), textarea:not([disabled]), [tabindex]:not([tabindex=\"-1\"]), details > summary';\n\n const result: HTMLElement[] = [];\n for (const el of assigned) {\n if (el.matches(focusableSelector)) {\n result.push(el as HTMLElement);\n }\n const nested = el.querySelectorAll<HTMLElement>(focusableSelector);\n result.push(...nested);\n }\n return result;\n }\n\n // ─── Show/Hide ───\n\n /** @internal */\n private async _show(): Promise<void> {\n if (this._visible) return;\n // P0-02: save focus target before moving focus into dialog\n this._previousFocus = document.activeElement as HTMLElement | null;\n this.dispatchEvent(new CustomEvent<void>('hx-show', { bubbles: true, composed: true }));\n this._visible = true;\n this.open = true;\n this._setAnchorAriaAttributes(true);\n // P1-03 / HIGH-01: single keydown listener handles both Escape and focus trap.\n // Registered synchronously before any await so it is in place before the first\n // await el.updateComplete in tests.\n document.addEventListener('keydown', this._handleDocumentKeydown);\n await this.updateComplete;\n // hx-after-show fires after Lit has rendered the visible state. Dispatching here\n // (before _updatePosition) ensures it fires in the same microtask as the test's\n // await-continuation, so tests can rely on a single await el.updateComplete.\n this.dispatchEvent(new CustomEvent<void>('hx-after-show', { bubbles: true, composed: true }));\n // WCAG 2.4.3: only move focus into the popover when it contains interactive\n // content. For non-interactive (informational) popovers, stealing focus from\n // the trigger is unexpected and disruptive for keyboard users.\n const bodyEl = this.shadowRoot?.querySelector('[part=\"body\"]') as HTMLElement | null;\n if (bodyEl) {\n const hasInteractive = this._getFocusableElements().length > 0;\n if (hasInteractive) {\n bodyEl.focus();\n }\n }\n // P0-01: listen for outside clicks; deferred to avoid catching the opening click\n if (this._showTimer !== null) {\n clearTimeout(this._showTimer);\n }\n this._showTimer = setTimeout(() => {\n this._showTimer = null;\n document.addEventListener('click', this._handleDocumentClick);\n }, 0);\n await this._updatePosition();\n }\n\n // HIGH-03: _hideWithFocusRestore controls whether _previousFocus is restored.\n // Escape and programmatic close restore focus; click-outside does not.\n /** @internal */\n private async _hide(restoreFocus = true): Promise<void> {\n if (!this._visible) return;\n document.removeEventListener('click', this._handleDocumentClick);\n document.removeEventListener('keydown', this._handleDocumentKeydown);\n this.dispatchEvent(new CustomEvent<void>('hx-hide', { bubbles: true, composed: true }));\n this._visible = false;\n this.open = false;\n this._setAnchorAriaAttributes(false);\n // HIGH-03: only restore focus on Escape / programmatic close\n if (restoreFocus) {\n this._previousFocus?.focus();\n }\n this._previousFocus = null;\n await this.updateComplete;\n this.dispatchEvent(new CustomEvent<void>('hx-after-hide', { bubbles: true, composed: true }));\n }\n\n // ─── Positioning ───\n\n /** @internal */\n private async _updatePosition(): Promise<void> {\n const anchorSlot = this.shadowRoot?.querySelector(\n 'slot[name=\"anchor\"]',\n ) as HTMLSlotElement | null;\n if (!anchorSlot) return;\n const anchorEl = anchorSlot.assignedElements()[0] as HTMLElement | undefined;\n const bodyEl = this.shadowRoot?.querySelector('[part=\"body\"]') as HTMLElement | null;\n const arrowEl = this.arrow\n ? (this.shadowRoot?.querySelector('[part=\"arrow\"]') as HTMLElement | null)\n : null;\n\n if (!anchorEl || !bodyEl) return;\n\n const { computePosition, flip, shift, offset, arrow } = await import('@floating-ui/dom');\n\n const middleware = [\n offset({ mainAxis: this.distance, crossAxis: this.skidding }),\n flip(),\n shift({ padding: 8 }),\n ];\n\n if (arrowEl) {\n middleware.push(arrow({ element: arrowEl }));\n }\n\n const { x, y, placement, middlewareData } = await computePosition(anchorEl, bodyEl, {\n placement: this.placement,\n strategy: 'fixed',\n middleware,\n });\n\n Object.assign(bodyEl.style, {\n left: `${x}px`,\n top: `${y}px`,\n });\n\n if (arrowEl && middlewareData.arrow) {\n const arrowData = middlewareData.arrow;\n const basePlacement = placement.split('-')[0] ?? 'bottom';\n const oppositeSide: Record<string, string> = {\n top: 'bottom',\n right: 'left',\n bottom: 'top',\n left: 'right',\n };\n const staticSide = oppositeSide[basePlacement] ?? 'bottom';\n\n Object.assign(arrowEl.style, {\n left: arrowData.x != null ? `${arrowData.x}px` : '',\n top: arrowData.y != null ? `${arrowData.y}px` : '',\n right: '',\n bottom: '',\n [staticSide]: '-5px',\n });\n\n // P2-02: hide the two border sides facing the popover body so only\n // the outward-facing corner is visible (avoids the inner border line).\n // Reset all four sides first, then make the two inner-facing ones transparent.\n const borderSides = ['border-top', 'border-right', 'border-bottom', 'border-left'] as const;\n for (const side of borderSides) {\n arrowEl.style.setProperty(side, '');\n }\n // Maps base placement → the two sides that face inward toward the popover body\n const innerBorderMap: Record<string, readonly [string, string]> = {\n bottom: ['border-bottom', 'border-right'],\n top: ['border-top', 'border-left'],\n right: ['border-top', 'border-right'],\n left: ['border-bottom', 'border-left'],\n };\n const innerSides = innerBorderMap[basePlacement] ?? ['border-bottom', 'border-right'];\n arrowEl.style.setProperty(innerSides[0], '1px solid transparent');\n arrowEl.style.setProperty(innerSides[1], '1px solid transparent');\n }\n }\n\n // ─── Event Handlers ───\n\n // P1-03 / P0-01 / HIGH-01: single document-level keydown handler while popover is open.\n // Handles Escape (close) and Tab (focus trap) in one listener to reduce overhead.\n /**\n * Handles Escape to close the popover and Tab/Shift+Tab to trap focus within it.\n * @internal\n */\n private _handleDocumentKeydown = (e: KeyboardEvent): void => {\n if (!this._visible) return;\n\n if (e.key === 'Escape') {\n // HIGH-03: Escape always restores focus to the prior element\n void this._hide(true);\n return;\n }\n\n if (e.key === 'Tab') {\n // HIGH-01: trap Tab/Shift+Tab focus within the popover body\n const focusable = this._getFocusableElements();\n if (focusable.length === 0) return;\n\n const bodyEl = this.shadowRoot?.querySelector('[part=\"body\"]') as HTMLElement | null;\n const allFocusable = bodyEl ? [bodyEl, ...focusable] : focusable;\n if (allFocusable.length === 0) return;\n\n const first = allFocusable[0] as HTMLElement;\n const last = allFocusable[allFocusable.length - 1] as HTMLElement;\n\n if (e.shiftKey) {\n if (document.activeElement === first || this.shadowRoot?.activeElement === first) {\n e.preventDefault();\n last.focus();\n }\n } else {\n if (document.activeElement === last || this.shadowRoot?.activeElement === last) {\n e.preventDefault();\n first.focus();\n }\n }\n }\n };\n\n // P0-01: close when click target is outside this component\n /**\n * Closes the popover when a click occurs outside the component boundary.\n * @internal\n */\n private _handleDocumentClick = (e: Event): void => {\n // Shadow DOM retargets events from within to the host at document level,\n // so a click on the trigger wrapper appears as e.target === this.\n if (e.target !== this && !this.contains(e.target as Node)) {\n // HIGH-03: click-outside does NOT restore focus — let browser handle naturally\n void this._hide(false);\n }\n };\n\n /**\n * Toggles the popover open/closed when the anchor is clicked in click trigger mode.\n * @internal\n */\n private _handleAnchorClick = (): void => {\n if (this.trigger !== 'click') return;\n if (this._visible) {\n void this._hide(true);\n } else {\n void this._show();\n }\n };\n\n /**\n * Opens the popover when the anchor receives a mouseenter event in hover trigger mode.\n * @internal\n */\n private _handleAnchorMouseEnter = (): void => {\n if (this.trigger !== 'hover') return;\n void this._show();\n };\n\n /**\n * Closes the popover when the anchor receives a mouseleave event in hover trigger mode.\n * WCAG 1.4.13: applies a 150 ms delay so the pointer can move from anchor\n * into the popover body without the content dismissing prematurely.\n * @internal\n */\n private _handleAnchorMouseLeave = (): void => {\n if (this.trigger !== 'hover') return;\n this._scheduleHoverHide();\n };\n\n // CRITICAL-02: body hover handlers so moving the pointer from anchor into\n // the popover content does not trigger a hide.\n /** @internal */\n private _handleBodyMouseEnter = (): void => {\n // Cancel a pending hide that would have fired from the anchor's mouseleave.\n if (this.trigger !== 'hover') return;\n this._cancelHoverHide();\n };\n\n /** @internal */\n private _handleBodyMouseLeave = (): void => {\n if (this.trigger !== 'hover') return;\n this._scheduleHoverHide();\n };\n\n /**\n * Schedules a hide with a 150 ms delay for hover-triggered dismissal.\n * WCAG 1.4.13: the delay allows the pointer to travel between the anchor\n * and the popover body without the content disappearing.\n * @internal\n */\n private _scheduleHoverHide(): void {\n this._cancelHoverHide();\n this._hoverHideTimer = setTimeout(() => {\n this._hoverHideTimer = null;\n void this._hide(false);\n }, 150);\n }\n\n /**\n * Cancels any pending hover-triggered hide.\n * @internal\n */\n private _cancelHoverHide(): void {\n if (this._hoverHideTimer !== null) {\n clearTimeout(this._hoverHideTimer);\n this._hoverHideTimer = null;\n }\n }\n\n /** @internal */\n private _handleAnchorFocusIn = (): void => {\n // CRITICAL-02: keyboard users trigger hover-mode popovers via focusin\n if (this.trigger !== 'focus' && this.trigger !== 'hover') return;\n void this._show();\n };\n\n /** @internal */\n private _handleAnchorFocusOut = (e: FocusEvent): void => {\n // CRITICAL-02: for hover mode, only hide when focus leaves both the anchor\n // and the popover body (i.e. relatedTarget is outside the component).\n if (this.trigger !== 'focus' && this.trigger !== 'hover') return;\n const related = e.relatedTarget as Node | null;\n // If focus is moving into the shadow root (body element), keep popover open\n if (related && (this.contains(related) || this.shadowRoot?.contains(related))) return;\n void this._hide(true);\n };\n\n /** @internal */\n private _handleAnchorSlotChange(): void {\n this._setAnchorAriaAttributes(this._visible);\n }\n\n // ─── Render ───\n\n override render() {\n return html`\n <div\n class=\"trigger-wrapper\"\n @click=${this._handleAnchorClick}\n @mouseenter=${this._handleAnchorMouseEnter}\n @mouseleave=${this._handleAnchorMouseLeave}\n @focusin=${this._handleAnchorFocusIn}\n @focusout=${this._handleAnchorFocusOut}\n >\n <slot name=\"anchor\" @slotchange=${this._handleAnchorSlotChange}></slot>\n </div>\n <div\n part=\"body\"\n id=${this._popoverId}\n role=\"dialog\"\n aria-label=${this.label}\n aria-hidden=${!this._visible ? 'true' : nothing}\n tabindex=\"-1\"\n ?inert=${!this._visible}\n class=${this._visible ? 'visible' : ''}\n @mouseenter=${this._handleBodyMouseEnter}\n @mouseleave=${this._handleBodyMouseLeave}\n >\n <slot></slot>\n ${this.arrow ? html`<div part=\"arrow\"></div>` : ''}\n </div>\n `;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'hx-popover': HelixPopover;\n }\n}\n"],"names":["helixPopoverStyles","css","_popoverCounter","HelixPopover","LitElement","focusable","bodyEl","_a","allFocusable","first","last","_b","_c","related","changedProperties","expanded","anchorSlot","anchorEl","defaultSlot","assigned","focusableSelector","result","el","nested","restoreFocus","arrowEl","computePosition","flip","shift","offset","arrow","middleware","y","placement","middlewareData","arrowData","basePlacement","staticSide","borderSides","side","innerSides","html","nothing","__decorateClass","property","state","customElement"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"hx-popover-D63RXn5H.js","sources":["../../src/components/hx-popover/hx-popover.styles.ts","../../src/components/hx-popover/hx-popover.ts"],"sourcesContent":["import { css } from 'lit';\n\nexport const helixPopoverStyles = css`\n :host {\n /* P2-05: display:contents lets the trigger-wrapper control layout inline;\n position:relative was vestigial — body uses position:fixed via Floating UI */\n display: contents;\n }\n\n .trigger-wrapper {\n display: inline-block;\n }\n\n [part='body'] {\n position: fixed;\n z-index: var(--hx-popover-z-index, 9999);\n max-width: var(--hx-popover-max-width, 320px);\n padding: var(--hx-popover-padding, var(--hx-space-3, 0.75rem));\n background: var(--hx-popover-bg, var(--hx-color-neutral-0, #ffffff));\n color: var(--hx-popover-color, var(--hx-color-neutral-900, #111827));\n font-family: var(--hx-font-family-sans, sans-serif);\n font-size: var(--hx-popover-font-size, var(--hx-font-size-sm, 0.875rem));\n line-height: var(--hx-line-height-normal, 1.5);\n border: 1px solid var(--hx-popover-border-color, var(--hx-color-neutral-200, #e5e7eb));\n border-radius: var(--hx-popover-border-radius, var(--hx-border-radius-md, 0.375rem));\n box-shadow: var(\n --hx-popover-shadow,\n var(--hx-shadow-md, 0 4px 16px var(--hx-overlay-black-12, rgba(0, 0, 0, 0.12)))\n );\n visibility: hidden;\n opacity: 0;\n transition:\n opacity var(--hx-popover-transition-duration, 0.2s) ease,\n visibility var(--hx-popover-transition-duration, 0.2s) ease;\n word-wrap: break-word;\n }\n\n [part='body'].visible {\n visibility: visible;\n opacity: 1;\n }\n\n [part='body']:focus-visible {\n outline: var(--hx-focus-ring-width, 2px) solid\n var(--hx-popover-focus-ring-color, var(--hx-focus-ring-color, var(--hx-color-primary-500)));\n outline-offset: var(--hx-focus-ring-offset, 2px);\n }\n\n [part='arrow'] {\n position: absolute;\n width: var(--hx-popover-arrow-size, 10px);\n height: var(--hx-popover-arrow-size, 10px);\n background: var(--hx-popover-bg, var(--hx-color-neutral-0, #ffffff));\n border: 1px solid var(--hx-popover-border-color, var(--hx-color-neutral-200, #e5e7eb));\n transform: rotate(45deg);\n pointer-events: none;\n }\n\n @media (prefers-reduced-motion: reduce) {\n [part='body'] {\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 } from 'lit/decorators.js';\nimport { helixPopoverStyles } from './hx-popover.styles.js';\n\nlet _popoverCounter = 0;\n\n/**\n * A popover that displays rich floating content attached to a trigger element.\n *\n * @summary Rich floating overlay attached to a trigger element.\n *\n * @tag hx-popover\n *\n * @slot anchor - The trigger element that opens the popover.\n * @slot - Default slot for popover body content.\n *\n * @csspart body - The popover body container element.\n * @csspart arrow - The arrow indicator element.\n *\n * @cssprop [--hx-popover-bg=var(--hx-color-neutral-0)] - Popover background color.\n * @cssprop [--hx-popover-color=var(--hx-color-neutral-900)] - Popover text color.\n * @cssprop [--hx-popover-font-size=var(--hx-font-size-sm)] - Popover font size.\n * @cssprop [--hx-popover-max-width=320px] - Maximum popover width.\n * @cssprop [--hx-popover-padding] - Popover padding.\n * @cssprop [--hx-popover-border-color=var(--hx-color-neutral-200)] - Popover border color.\n * @cssprop [--hx-popover-border-radius=var(--hx-border-radius-md)] - Popover border radius.\n * @cssprop [--hx-popover-shadow] - Popover box shadow.\n * @cssprop [--hx-popover-z-index=9999] - Popover z-index.\n * @cssprop [--hx-popover-transition-duration=0.2s] - Show/hide transition duration.\n * @cssprop [--hx-popover-arrow-size=10px] - Size of the arrow indicator.\n *\n * @fires {CustomEvent} hx-show - Emitted when the popover begins to show.\n * @fires {CustomEvent} hx-after-show - Emitted after the popover is fully visible.\n * @fires {CustomEvent} hx-hide - Emitted when the popover begins to hide.\n * @fires {CustomEvent} hx-after-hide - Emitted after the popover is fully hidden.\n *\n * @example\n * ```html\n * <hx-popover placement=\"bottom\" trigger=\"click\">\n * <button slot=\"anchor\">Open Popover</button>\n * <p>Rich popover content here.</p>\n * </hx-popover>\n * ```\n */\n\n@customElement('hx-popover')\nexport class HelixPopover extends LitElement {\n static override styles = [helixPopoverStyles];\n\n /**\n * Whether the popover is open.\n * @attr open\n */\n @property({ type: Boolean, reflect: true })\n open = false;\n\n /**\n * Preferred placement of the popover relative to the anchor.\n * @attr placement\n */\n @property({ type: String, reflect: true })\n placement:\n | 'top'\n | 'top-start'\n | 'top-end'\n | 'right'\n | 'right-start'\n | 'right-end'\n | 'bottom'\n | 'bottom-start'\n | 'bottom-end'\n | 'left'\n | 'left-start'\n | 'left-end' = 'bottom';\n\n /**\n * How the popover is triggered.\n * @attr trigger\n */\n @property({ type: String, reflect: true })\n trigger: 'click' | 'hover' | 'focus' | 'manual' = 'click';\n\n /**\n * Distance in pixels between the popover and the anchor.\n * @attr distance\n */\n @property({ type: Number, reflect: true })\n distance = 8;\n\n /**\n * Alignment offset in pixels along the anchor.\n * @attr skidding\n */\n @property({ type: Number, reflect: true })\n skidding = 0;\n\n /**\n * Whether to show an arrow pointing to the anchor.\n * @attr arrow\n */\n @property({ type: Boolean, reflect: true })\n arrow = false;\n\n /**\n * Accessible label for the popover body (sets aria-label on the dialog).\n * @attr label\n */\n @property({ type: String, reflect: true })\n label = 'Popover';\n\n /**\n * Tracks whether the popover body is currently visible.\n * @internal\n */\n @state() private _visible = false;\n\n /**\n * The element that held focus before the popover opened, used to restore focus on close.\n * @internal\n */\n private _previousFocus: HTMLElement | null = null;\n\n /**\n * Unique ID assigned to the popover body element.\n * @internal\n */\n private readonly _popoverId = `hx-popover-${++_popoverCounter}`;\n\n /**\n * Timer ID for the deferred document click listener registration in _show().\n * Stored so it can be cancelled in disconnectedCallback to prevent leaks.\n * @internal\n */\n private _showTimer: ReturnType<typeof setTimeout> | null = null;\n\n /**\n * Timer ID for the hover-triggered hide delay.\n * WCAG 1.4.13: hoverable content must remain visible while the pointer is\n * over it. A 150 ms delay allows the pointer to move from the anchor into\n * the popover body without the content dismissing prematurely.\n * @internal\n */\n private _hoverHideTimer: ReturnType<typeof setTimeout> | null = null;\n\n // ─── Lifecycle ───\n\n override disconnectedCallback(): void {\n super.disconnectedCallback();\n if (this._showTimer !== null) {\n clearTimeout(this._showTimer);\n this._showTimer = null;\n }\n if (this._hoverHideTimer !== null) {\n clearTimeout(this._hoverHideTimer);\n this._hoverHideTimer = null;\n }\n document.removeEventListener('click', this._handleDocumentClick);\n document.removeEventListener('keydown', this._handleDocumentKeydown);\n }\n\n override firstUpdated(): void {\n // HIGH-02: set aria-haspopup=\"dialog\" once on the anchor so assistive technology\n // announces the control's popup type before it is ever opened.\n this._setAnchorAriaAttributes(false);\n // Sync initial open state\n if (this.open) {\n void this._show();\n }\n }\n\n override updated(changedProperties: PropertyValues<this>): void {\n if (changedProperties.has('open')) {\n if (this.open) {\n void this._show();\n } else {\n void this._hide();\n }\n }\n }\n\n // ─── ARIA setup ───\n\n // HIGH-02: set aria-haspopup=\"dialog\" on firstUpdated and keep aria-expanded in sync\n /** @internal */\n private _setAnchorAriaAttributes(expanded: boolean): void {\n const anchorSlot = this.shadowRoot?.querySelector(\n 'slot[name=\"anchor\"]',\n ) as HTMLSlotElement | null;\n if (!anchorSlot) return;\n const anchorEl = anchorSlot.assignedElements()[0] as HTMLElement | undefined;\n if (anchorEl) {\n anchorEl.setAttribute('aria-expanded', String(expanded));\n anchorEl.setAttribute('aria-haspopup', 'dialog');\n // aria-controls is omitted: the body lives in Shadow DOM and axe-core\n // cannot resolve cross-root IDREF values, which causes a critical violation.\n }\n }\n\n // ─── Focus helpers ───\n\n /** Return all keyboard-focusable elements inside the popover body's slotted content. */\n /** @internal */\n private _getFocusableElements(): HTMLElement[] {\n const bodyEl = this.shadowRoot?.querySelector('[part=\"body\"]') as HTMLElement | null;\n if (!bodyEl) return [];\n\n // Gather focusable elements from the default slot's assigned nodes\n const defaultSlot = bodyEl.querySelector('slot:not([name])') as HTMLSlotElement | null;\n if (!defaultSlot) return [];\n\n const assigned = defaultSlot.assignedElements({ flatten: true });\n const focusableSelector =\n 'a[href], area[href], button:not([disabled]), input:not([disabled]), select:not([disabled]), textarea:not([disabled]), [tabindex]:not([tabindex=\"-1\"]), details > summary';\n\n const result: HTMLElement[] = [];\n for (const el of assigned) {\n if (el.matches(focusableSelector)) {\n result.push(el as HTMLElement);\n }\n const nested = el.querySelectorAll<HTMLElement>(focusableSelector);\n result.push(...nested);\n }\n return result;\n }\n\n // ─── Show/Hide ───\n\n /** @internal */\n private async _show(): Promise<void> {\n if (this._visible) return;\n // P0-02: save focus target before moving focus into dialog\n this._previousFocus = document.activeElement as HTMLElement | null;\n this.dispatchEvent(new CustomEvent<void>('hx-show', { bubbles: true, composed: true }));\n this._visible = true;\n this.open = true;\n this._setAnchorAriaAttributes(true);\n // P1-03 / HIGH-01: single keydown listener handles both Escape and focus trap.\n // Registered synchronously before any await so it is in place before the first\n // await el.updateComplete in tests.\n document.addEventListener('keydown', this._handleDocumentKeydown);\n await this.updateComplete;\n // hx-after-show fires after Lit has rendered the visible state. Dispatching here\n // (before _updatePosition) ensures it fires in the same microtask as the test's\n // await-continuation, so tests can rely on a single await el.updateComplete.\n this.dispatchEvent(new CustomEvent<void>('hx-after-show', { bubbles: true, composed: true }));\n // WCAG 2.4.3: only move focus into the popover when it contains interactive\n // content. For non-interactive (informational) popovers, stealing focus from\n // the trigger is unexpected and disruptive for keyboard users.\n const bodyEl = this.shadowRoot?.querySelector('[part=\"body\"]') as HTMLElement | null;\n if (bodyEl) {\n const hasInteractive = this._getFocusableElements().length > 0;\n if (hasInteractive) {\n bodyEl.focus();\n }\n }\n // P0-01: listen for outside clicks; deferred to avoid catching the opening click\n if (this._showTimer !== null) {\n clearTimeout(this._showTimer);\n }\n this._showTimer = setTimeout(() => {\n this._showTimer = null;\n document.addEventListener('click', this._handleDocumentClick);\n }, 0);\n await this._updatePosition();\n }\n\n // HIGH-03: _hideWithFocusRestore controls whether _previousFocus is restored.\n // Escape and programmatic close restore focus; click-outside does not.\n /** @internal */\n private async _hide(restoreFocus = true): Promise<void> {\n if (!this._visible) return;\n document.removeEventListener('click', this._handleDocumentClick);\n document.removeEventListener('keydown', this._handleDocumentKeydown);\n this.dispatchEvent(new CustomEvent<void>('hx-hide', { bubbles: true, composed: true }));\n this._visible = false;\n this.open = false;\n this._setAnchorAriaAttributes(false);\n // HIGH-03: only restore focus on Escape / programmatic close\n if (restoreFocus) {\n this._previousFocus?.focus();\n }\n this._previousFocus = null;\n await this.updateComplete;\n this.dispatchEvent(new CustomEvent<void>('hx-after-hide', { bubbles: true, composed: true }));\n }\n\n // ─── Positioning ───\n\n /** @internal */\n private async _updatePosition(): Promise<void> {\n const anchorSlot = this.shadowRoot?.querySelector(\n 'slot[name=\"anchor\"]',\n ) as HTMLSlotElement | null;\n if (!anchorSlot) return;\n const anchorEl = anchorSlot.assignedElements()[0] as HTMLElement | undefined;\n const bodyEl = this.shadowRoot?.querySelector('[part=\"body\"]') as HTMLElement | null;\n const arrowEl = this.arrow\n ? (this.shadowRoot?.querySelector('[part=\"arrow\"]') as HTMLElement | null)\n : null;\n\n if (!anchorEl || !bodyEl) return;\n\n const { computePosition, flip, shift, offset, arrow } = await import('@floating-ui/dom');\n\n const middleware = [\n offset({ mainAxis: this.distance, crossAxis: this.skidding }),\n flip(),\n shift({ padding: 8 }),\n ];\n\n if (arrowEl) {\n middleware.push(arrow({ element: arrowEl }));\n }\n\n const { x, y, placement, middlewareData } = await computePosition(anchorEl, bodyEl, {\n placement: this.placement,\n strategy: 'fixed',\n middleware,\n });\n\n Object.assign(bodyEl.style, {\n left: `${x}px`,\n top: `${y}px`,\n });\n\n if (arrowEl && middlewareData.arrow) {\n const arrowData = middlewareData.arrow;\n const basePlacement = placement.split('-')[0] ?? 'bottom';\n const oppositeSide: Record<string, string> = {\n top: 'bottom',\n right: 'left',\n bottom: 'top',\n left: 'right',\n };\n const staticSide = oppositeSide[basePlacement] ?? 'bottom';\n\n Object.assign(arrowEl.style, {\n left: arrowData.x != null ? `${arrowData.x}px` : '',\n top: arrowData.y != null ? `${arrowData.y}px` : '',\n right: '',\n bottom: '',\n [staticSide]: '-5px',\n });\n\n // P2-02: hide the two border sides facing the popover body so only\n // the outward-facing corner is visible (avoids the inner border line).\n // Reset all four sides first, then make the two inner-facing ones transparent.\n const borderSides = ['border-top', 'border-right', 'border-bottom', 'border-left'] as const;\n for (const side of borderSides) {\n arrowEl.style.setProperty(side, '');\n }\n // Maps base placement → the two sides that face inward toward the popover body\n const innerBorderMap: Record<string, readonly [string, string]> = {\n bottom: ['border-bottom', 'border-right'],\n top: ['border-top', 'border-left'],\n right: ['border-top', 'border-right'],\n left: ['border-bottom', 'border-left'],\n };\n const innerSides = innerBorderMap[basePlacement] ?? ['border-bottom', 'border-right'];\n arrowEl.style.setProperty(innerSides[0], '1px solid transparent');\n arrowEl.style.setProperty(innerSides[1], '1px solid transparent');\n }\n }\n\n // ─── Event Handlers ───\n\n // P1-03 / P0-01 / HIGH-01: single document-level keydown handler while popover is open.\n // Handles Escape (close) and Tab (focus trap) in one listener to reduce overhead.\n /**\n * Handles Escape to close the popover and Tab/Shift+Tab to trap focus within it.\n * @internal\n */\n private _handleDocumentKeydown = (e: KeyboardEvent): void => {\n if (!this._visible) return;\n\n if (e.key === 'Escape') {\n // HIGH-03: Escape always restores focus to the prior element\n void this._hide(true);\n return;\n }\n\n if (e.key === 'Tab') {\n // HIGH-01: trap Tab/Shift+Tab focus within the popover body\n const focusable = this._getFocusableElements();\n if (focusable.length === 0) return;\n\n const bodyEl = this.shadowRoot?.querySelector('[part=\"body\"]') as HTMLElement | null;\n const allFocusable = bodyEl ? [bodyEl, ...focusable] : focusable;\n if (allFocusable.length === 0) return;\n\n const first = allFocusable[0] as HTMLElement;\n const last = allFocusable[allFocusable.length - 1] as HTMLElement;\n\n if (e.shiftKey) {\n if (document.activeElement === first || this.shadowRoot?.activeElement === first) {\n e.preventDefault();\n last.focus();\n }\n } else {\n if (document.activeElement === last || this.shadowRoot?.activeElement === last) {\n e.preventDefault();\n first.focus();\n }\n }\n }\n };\n\n // P0-01: close when click target is outside this component\n /**\n * Closes the popover when a click occurs outside the component boundary.\n * @internal\n */\n private _handleDocumentClick = (e: Event): void => {\n // Shadow DOM retargets events from within to the host at document level,\n // so a click on the trigger wrapper appears as e.target === this.\n if (e.target !== this && !this.contains(e.target as Node)) {\n // HIGH-03: click-outside does NOT restore focus — let browser handle naturally\n void this._hide(false);\n }\n };\n\n /**\n * Toggles the popover open/closed when the anchor is clicked in click trigger mode.\n * @internal\n */\n private _handleAnchorClick = (): void => {\n if (this.trigger !== 'click') return;\n if (this._visible) {\n void this._hide(true);\n } else {\n void this._show();\n }\n };\n\n /**\n * Opens the popover when the anchor receives a mouseenter event in hover trigger mode.\n * @internal\n */\n private _handleAnchorMouseEnter = (): void => {\n if (this.trigger !== 'hover') return;\n void this._show();\n };\n\n /**\n * Closes the popover when the anchor receives a mouseleave event in hover trigger mode.\n * WCAG 1.4.13: applies a 150 ms delay so the pointer can move from anchor\n * into the popover body without the content dismissing prematurely.\n * @internal\n */\n private _handleAnchorMouseLeave = (): void => {\n if (this.trigger !== 'hover') return;\n this._scheduleHoverHide();\n };\n\n // CRITICAL-02: body hover handlers so moving the pointer from anchor into\n // the popover content does not trigger a hide.\n /** @internal */\n private _handleBodyMouseEnter = (): void => {\n // Cancel a pending hide that would have fired from the anchor's mouseleave.\n if (this.trigger !== 'hover') return;\n this._cancelHoverHide();\n };\n\n /** @internal */\n private _handleBodyMouseLeave = (): void => {\n if (this.trigger !== 'hover') return;\n this._scheduleHoverHide();\n };\n\n /**\n * Schedules a hide with a 150 ms delay for hover-triggered dismissal.\n * WCAG 1.4.13: the delay allows the pointer to travel between the anchor\n * and the popover body without the content disappearing.\n * @internal\n */\n private _scheduleHoverHide(): void {\n this._cancelHoverHide();\n this._hoverHideTimer = setTimeout(() => {\n this._hoverHideTimer = null;\n void this._hide(false);\n }, 150);\n }\n\n /**\n * Cancels any pending hover-triggered hide.\n * @internal\n */\n private _cancelHoverHide(): void {\n if (this._hoverHideTimer !== null) {\n clearTimeout(this._hoverHideTimer);\n this._hoverHideTimer = null;\n }\n }\n\n /** @internal */\n private _handleAnchorFocusIn = (): void => {\n // CRITICAL-02: keyboard users trigger hover-mode popovers via focusin\n if (this.trigger !== 'focus' && this.trigger !== 'hover') return;\n void this._show();\n };\n\n /** @internal */\n private _handleAnchorFocusOut = (e: FocusEvent): void => {\n // CRITICAL-02: for hover mode, only hide when focus leaves both the anchor\n // and the popover body (i.e. relatedTarget is outside the component).\n if (this.trigger !== 'focus' && this.trigger !== 'hover') return;\n const related = e.relatedTarget as Node | null;\n // If focus is moving into the shadow root (body element), keep popover open\n if (related && (this.contains(related) || this.shadowRoot?.contains(related))) return;\n void this._hide(true);\n };\n\n /** @internal */\n private _handleAnchorSlotChange(): void {\n this._setAnchorAriaAttributes(this._visible);\n }\n\n // ─── Render ───\n\n override render() {\n return html`\n <div\n class=\"trigger-wrapper\"\n @click=${this._handleAnchorClick}\n @mouseenter=${this._handleAnchorMouseEnter}\n @mouseleave=${this._handleAnchorMouseLeave}\n @focusin=${this._handleAnchorFocusIn}\n @focusout=${this._handleAnchorFocusOut}\n >\n <slot name=\"anchor\" @slotchange=${this._handleAnchorSlotChange}></slot>\n </div>\n <div\n part=\"body\"\n id=${this._popoverId}\n role=\"dialog\"\n aria-label=${this.label}\n aria-hidden=${!this._visible ? 'true' : nothing}\n tabindex=\"-1\"\n ?inert=${!this._visible}\n class=${this._visible ? 'visible' : ''}\n @mouseenter=${this._handleBodyMouseEnter}\n @mouseleave=${this._handleBodyMouseLeave}\n >\n <slot></slot>\n ${this.arrow ? html`<div part=\"arrow\"></div>` : ''}\n </div>\n `;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'hx-popover': HelixPopover;\n }\n}\n"],"names":["helixPopoverStyles","css","_popoverCounter","HelixPopover","LitElement","focusable","bodyEl","_a","allFocusable","first","last","_b","_c","related","changedProperties","expanded","anchorSlot","anchorEl","defaultSlot","assigned","focusableSelector","result","el","nested","restoreFocus","arrowEl","computePosition","flip","shift","offset","arrow","middleware","y","placement","middlewareData","arrowData","basePlacement","staticSide","borderSides","side","innerSides","html","nothing","__decorateClass","property","state","customElement"],"mappings":"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"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { css as b, LitElement as v, html as d } from "lit";
|
|
2
|
-
import "./document-token-adoption-
|
|
2
|
+
import "./document-token-adoption-DuYNKd4k.js";
|
|
3
3
|
import { property as r, customElement as x } from "lit/decorators.js";
|
|
4
4
|
import { autoUpdate as g, offset as w, autoPlacement as _, flip as S, shift as A, arrow as z, size as P, computePosition as E } from "@floating-ui/dom";
|
|
5
5
|
const U = b`
|
|
@@ -209,4 +209,4 @@ s = a([
|
|
|
209
209
|
export {
|
|
210
210
|
s as H
|
|
211
211
|
};
|
|
212
|
-
//# sourceMappingURL=hx-popup-
|
|
212
|
+
//# sourceMappingURL=hx-popup-BQWMhvMO.js.map
|