@helixui/library 3.1.0-next.72 → 3.2.0-next.100
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/custom-elements.json +165 -328
- package/dist/components/hx-accordion/hx-accordion-item.styles.d.ts.map +1 -1
- package/dist/components/hx-accordion/index.js +1 -1
- package/dist/components/hx-alert/index.js +1 -1
- package/dist/components/hx-banner/index.js +1 -1
- package/dist/components/hx-breadcrumb/hx-breadcrumb-item.styles.d.ts.map +1 -1
- package/dist/components/hx-breadcrumb/index.js +1 -1
- package/dist/components/hx-button/hx-button.d.ts +44 -49
- package/dist/components/hx-button/hx-button.d.ts.map +1 -1
- package/dist/components/hx-button/hx-button.styles.d.ts.map +1 -1
- package/dist/components/hx-button/index.js +1 -1
- package/dist/components/hx-card/hx-card.styles.d.ts.map +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-clinical-status/hx-clinical-status.styles.d.ts.map +1 -1
- package/dist/components/hx-clinical-status/index.js +1 -1
- package/dist/components/hx-code-snippet/hx-code-snippet.styles.d.ts.map +1 -1
- package/dist/components/hx-code-snippet/index.js +1 -1
- package/dist/components/hx-color-picker/hx-color-picker.styles.d.ts.map +1 -1
- package/dist/components/hx-color-picker/index.js +1 -1
- package/dist/components/hx-combobox/index.js +1 -1
- package/dist/components/hx-data-table/hx-data-table.styles.d.ts.map +1 -1
- package/dist/components/hx-data-table/index.js +1 -1
- package/dist/components/hx-date-picker/index.js +1 -1
- package/dist/components/hx-dialog/hx-dialog.styles.d.ts.map +1 -1
- package/dist/components/hx-dialog/index.js +1 -1
- package/dist/components/hx-drawer/hx-drawer.styles.d.ts.map +1 -1
- package/dist/components/hx-drawer/index.js +1 -1
- package/dist/components/hx-file-upload/hx-file-upload.styles.d.ts.map +1 -1
- package/dist/components/hx-file-upload/index.js +1 -1
- package/dist/components/hx-icon-button/hx-icon-button.styles.d.ts.map +1 -1
- package/dist/components/hx-icon-button/index.js +1 -1
- package/dist/components/hx-link/index.js +1 -1
- package/dist/components/hx-menu/hx-menu-item.styles.d.ts.map +1 -1
- package/dist/components/hx-menu/index.js +1 -1
- package/dist/components/hx-meter/hx-meter.styles.d.ts.map +1 -1
- package/dist/components/hx-meter/index.js +1 -1
- package/dist/components/hx-nav/hx-nav.styles.d.ts.map +1 -1
- package/dist/components/hx-nav/index.js +1 -1
- package/dist/components/hx-overflow-menu/hx-overflow-menu.styles.d.ts.map +1 -1
- package/dist/components/hx-overflow-menu/index.js +1 -1
- package/dist/components/hx-pagination/hx-pagination.styles.d.ts.map +1 -1
- package/dist/components/hx-pagination/index.js +1 -1
- package/dist/components/hx-phi-field/hx-phi-field.styles.d.ts.map +1 -1
- package/dist/components/hx-phi-field/index.js +1 -1
- package/dist/components/hx-popover/hx-popover.styles.d.ts.map +1 -1
- package/dist/components/hx-popover/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/hx-select.styles.d.ts.map +1 -1
- package/dist/components/hx-select/index.js +1 -1
- package/dist/components/hx-side-nav/hx-nav-item.d.ts +7 -5
- package/dist/components/hx-side-nav/hx-nav-item.d.ts.map +1 -1
- package/dist/components/hx-side-nav/hx-nav-item.styles.d.ts.map +1 -1
- package/dist/components/hx-side-nav/hx-side-nav.d.ts +9 -23
- package/dist/components/hx-side-nav/hx-side-nav.d.ts.map +1 -1
- package/dist/components/hx-side-nav/hx-side-nav.styles.d.ts.map +1 -1
- package/dist/components/hx-side-nav/index.js +1 -1
- package/dist/components/hx-slider/index.js +1 -1
- package/dist/components/hx-split-button/hx-split-button.d.ts +1 -1
- package/dist/components/hx-split-button/index.js +1 -1
- package/dist/components/hx-split-panel/hx-split-panel.styles.d.ts.map +1 -1
- package/dist/components/hx-split-panel/index.js +1 -1
- package/dist/components/hx-steps/hx-step.styles.d.ts.map +1 -1
- package/dist/components/hx-steps/index.js +1 -1
- package/dist/components/hx-switch/index.js +1 -1
- package/dist/components/hx-table/hx-table.styles.d.ts.map +1 -1
- package/dist/components/hx-table/index.js +1 -1
- package/dist/components/hx-tabs/index.js +1 -1
- package/dist/components/hx-text-input/hx-text-input.d.ts +18 -35
- package/dist/components/hx-text-input/hx-text-input.d.ts.map +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-time-picker/index.js +1 -1
- package/dist/components/hx-toast/hx-toast.d.ts +12 -8
- package/dist/components/hx-toast/hx-toast.d.ts.map +1 -1
- package/dist/components/hx-toast/hx-toast.styles.d.ts.map +1 -1
- package/dist/components/hx-toast/index.js +1 -1
- package/dist/components/hx-toggle-button/index.js +1 -1
- package/dist/components/hx-top-nav/hx-top-nav.styles.d.ts.map +1 -1
- package/dist/components/hx-top-nav/index.js +1 -1
- package/dist/components/hx-tree-view/hx-tree-item.styles.d.ts.map +1 -1
- package/dist/components/hx-tree-view/index.js +1 -1
- package/dist/css/helix-all.css +289 -237
- package/dist/css/helix-core.css +147 -53
- package/dist/css/helix-data.css +9 -14
- package/dist/css/helix-feedback.css +30 -20
- package/dist/css/helix-forms.css +53 -73
- package/dist/css/helix-layout.css +2 -8
- package/dist/css/helix-media.css +3 -3
- package/dist/css/helix-navigation.css +34 -41
- package/dist/css/helix-overlay.css +3 -12
- package/dist/css/helix-tokens.css +60 -5
- package/dist/css/helix-utility.css +5 -5
- package/dist/css/hx-alert.css +1 -1
- package/dist/css/hx-banner.css +2 -2
- package/dist/css/hx-button.css +143 -43
- package/dist/css/hx-card.css +1 -4
- package/dist/css/hx-carousel.css +3 -3
- package/dist/css/hx-checkbox.css +2 -2
- package/dist/css/hx-clinical-status.css +2 -4
- package/dist/css/hx-code-snippet.css +6 -4
- package/dist/css/hx-color-picker.css +3 -13
- package/dist/css/hx-combobox.css +7 -7
- package/dist/css/hx-data-table.css +2 -8
- package/dist/css/hx-date-picker.css +7 -7
- package/dist/css/hx-dialog.css +1 -4
- package/dist/css/hx-drawer.css +1 -4
- package/dist/css/hx-file-upload.css +4 -13
- package/dist/css/hx-icon-button.css +2 -5
- package/dist/css/hx-link.css +1 -1
- package/dist/css/hx-meter.css +1 -2
- package/dist/css/hx-nav.css +2 -8
- package/dist/css/hx-overflow-menu.css +2 -8
- package/dist/css/hx-pagination.css +2 -8
- package/dist/css/hx-phi-field.css +1 -4
- package/dist/css/hx-popover.css +1 -4
- package/dist/css/hx-rating.css +3 -3
- package/dist/css/hx-select.css +3 -4
- package/dist/css/hx-side-nav.css +26 -12
- package/dist/css/hx-slider.css +4 -4
- package/dist/css/hx-split-button.css +5 -5
- package/dist/css/hx-split-panel.css +2 -8
- package/dist/css/hx-switch.css +3 -3
- package/dist/css/hx-table.css +1 -2
- package/dist/css/hx-text-input.css +8 -8
- package/dist/css/hx-textarea.css +2 -2
- package/dist/css/hx-time-picker.css +3 -3
- package/dist/css/hx-toast.css +26 -15
- package/dist/css/hx-toggle-button.css +4 -4
- package/dist/css/hx-top-nav.css +1 -4
- package/dist/css/hx-tree-view.css +1 -1
- package/dist/css/index.css +1 -1
- package/dist/css/manifest.json +60 -46
- package/dist/index.js +44 -44
- package/dist/shared/{hx-accordion-cnKg4_la.js → hx-accordion-ZVzgDzTG.js} +4 -5
- package/dist/shared/hx-accordion-ZVzgDzTG.js.map +1 -0
- package/dist/shared/{hx-alert-BZH8iHQf.js → hx-alert-C597yHpD.js} +2 -2
- package/dist/shared/{hx-alert-BZH8iHQf.js.map → hx-alert-C597yHpD.js.map} +1 -1
- package/dist/shared/{hx-banner-DT7Zn9Bo.js → hx-banner-Cxd7eFUP.js} +3 -3
- package/dist/shared/{hx-banner-DT7Zn9Bo.js.map → hx-banner-Cxd7eFUP.js.map} +1 -1
- package/dist/shared/{hx-breadcrumb-item-COeYcB2x.js → hx-breadcrumb-item-3tKppF9h.js} +2 -5
- package/dist/shared/{hx-breadcrumb-item-COeYcB2x.js.map → hx-breadcrumb-item-3tKppF9h.js.map} +1 -1
- package/dist/shared/{hx-button-modUSOpY.js → hx-button-9OUjJnk7.js} +167 -68
- package/dist/shared/hx-button-9OUjJnk7.js.map +1 -0
- package/dist/shared/{hx-card-CU1QnjNb.js → hx-card-qNAM2QNV.js} +6 -9
- package/dist/shared/hx-card-qNAM2QNV.js.map +1 -0
- package/dist/shared/{hx-carousel-item-BaE4hpLl.js → hx-carousel-item-z1Lc24op.js} +4 -4
- package/dist/shared/hx-carousel-item-z1Lc24op.js.map +1 -0
- package/dist/shared/{hx-checkbox-C46TyXhM.js → hx-checkbox-DBD-gMoz.js} +3 -3
- package/dist/shared/{hx-checkbox-C46TyXhM.js.map → hx-checkbox-DBD-gMoz.js.map} +1 -1
- package/dist/shared/{hx-clinical-status-BmSjfSEN.js → hx-clinical-status-D3XQIOqX.js} +3 -5
- package/dist/shared/hx-clinical-status-D3XQIOqX.js.map +1 -0
- package/dist/shared/{hx-code-snippet-CJ0FbQYG.js → hx-code-snippet-B26RM1_C.js} +10 -8
- package/dist/shared/{hx-code-snippet-CJ0FbQYG.js.map → hx-code-snippet-B26RM1_C.js.map} +1 -1
- package/dist/shared/{hx-color-picker-DiDLZyvK.js → hx-color-picker-uRc865FJ.js} +23 -33
- package/dist/shared/hx-color-picker-uRc865FJ.js.map +1 -0
- package/dist/shared/{hx-combobox-DaA5dBC4.js → hx-combobox-ClhNRAS5.js} +8 -8
- package/dist/shared/hx-combobox-ClhNRAS5.js.map +1 -0
- package/dist/shared/{hx-data-table-Cq3t86Ic.js → hx-data-table-CLqVqdxr.js} +3 -9
- package/dist/shared/hx-data-table-CLqVqdxr.js.map +1 -0
- package/dist/shared/{hx-date-picker-DMqRQNSB.js → hx-date-picker-BJm7Yrda.js} +8 -8
- package/dist/shared/{hx-date-picker-DMqRQNSB.js.map → hx-date-picker-BJm7Yrda.js.map} +1 -1
- package/dist/shared/{hx-dialog-eIS8tcDm.js → hx-dialog-DRN_1-Y-.js} +2 -5
- package/dist/shared/hx-dialog-DRN_1-Y-.js.map +1 -0
- package/dist/shared/{hx-drawer-DDhDz7RI.js → hx-drawer-Y1Ui2IWJ.js} +2 -5
- package/dist/shared/hx-drawer-Y1Ui2IWJ.js.map +1 -0
- package/dist/shared/{hx-file-upload-zTDbjsRw.js → hx-file-upload-D3rKROK5.js} +17 -26
- package/dist/shared/hx-file-upload-D3rKROK5.js.map +1 -0
- package/dist/shared/{hx-icon-button-BmV97nqz.js → hx-icon-button-CGNdQSFM.js} +3 -6
- package/dist/shared/hx-icon-button-CGNdQSFM.js.map +1 -0
- package/dist/shared/{hx-link-DmiV-mPw.js → hx-link-9Ig2DW6L.js} +5 -5
- package/dist/shared/{hx-link-DmiV-mPw.js.map → hx-link-9Ig2DW6L.js.map} +1 -1
- package/dist/shared/{hx-menu-divider-j__TZjH2.js → hx-menu-divider-C2omnPtj.js} +2 -5
- package/dist/shared/hx-menu-divider-C2omnPtj.js.map +1 -0
- package/dist/shared/{hx-meter-Cm7k_Ro8.js → hx-meter-BPscsw5t.js} +2 -3
- package/dist/shared/hx-meter-BPscsw5t.js.map +1 -0
- package/dist/shared/{hx-nav-item-D8xHLVOs.js → hx-nav-item-CqbO5-T5.js} +140 -90
- package/dist/shared/hx-nav-item-CqbO5-T5.js.map +1 -0
- package/dist/shared/{hx-nav-LoyEKZQC.js → hx-nav-ldFM3Fle.js} +37 -43
- package/dist/shared/hx-nav-ldFM3Fle.js.map +1 -0
- package/dist/shared/{hx-overflow-menu-BmKyAp5D.js → hx-overflow-menu-DCLsdIBy.js} +3 -9
- package/dist/shared/hx-overflow-menu-DCLsdIBy.js.map +1 -0
- package/dist/shared/{hx-pagination-Dqw5dorC.js → hx-pagination-C7y8GVyU.js} +54 -60
- package/dist/shared/hx-pagination-C7y8GVyU.js.map +1 -0
- package/dist/shared/{hx-phi-field-Bf9TdtC1.js → hx-phi-field-C19oxlrr.js} +2 -5
- package/dist/shared/hx-phi-field-C19oxlrr.js.map +1 -0
- package/dist/shared/{hx-popover-B93rTAfr.js → hx-popover-B-FP3-wW.js} +8 -11
- package/dist/shared/hx-popover-B-FP3-wW.js.map +1 -0
- package/dist/shared/{hx-radio-N8xgDd_5.js → hx-radio-dFjUAost.js} +4 -4
- package/dist/shared/{hx-radio-N8xgDd_5.js.map → hx-radio-dFjUAost.js.map} +1 -1
- package/dist/shared/{hx-rating-i2FL1WUN.js → hx-rating-CGtsejNf.js} +4 -4
- package/dist/shared/{hx-rating-i2FL1WUN.js.map → hx-rating-CGtsejNf.js.map} +1 -1
- package/dist/shared/{hx-select-vgaBo1Ai.js → hx-select-Bf4usFts.js} +4 -5
- package/dist/shared/hx-select-Bf4usFts.js.map +1 -0
- package/dist/shared/{hx-slider-ydBamYhd.js → hx-slider-m0aEClH1.js} +5 -5
- package/dist/shared/{hx-slider-ydBamYhd.js.map → hx-slider-m0aEClH1.js.map} +1 -1
- package/dist/shared/{hx-split-button-BeMsmS6N.js → hx-split-button-BxDFfx4D.js} +6 -6
- package/dist/shared/{hx-split-button-BeMsmS6N.js.map → hx-split-button-BxDFfx4D.js.map} +1 -1
- package/dist/shared/{hx-split-panel-BVG1VWNT.js → hx-split-panel-B-u0Z3mm.js} +3 -9
- package/dist/shared/hx-split-panel-B-u0Z3mm.js.map +1 -0
- package/dist/shared/{hx-step-DL3PbOzm.js → hx-step-R2rjp1fT.js} +2 -5
- package/dist/shared/hx-step-R2rjp1fT.js.map +1 -0
- package/dist/shared/{hx-switch-Dougzsgp.js → hx-switch-DvAW4YY-.js} +4 -4
- package/dist/shared/{hx-switch-Dougzsgp.js.map → hx-switch-DvAW4YY-.js.map} +1 -1
- package/dist/shared/{hx-tab-panel-CbkO9VKu.js → hx-tab-panel-SWOEHuJc.js} +3 -3
- package/dist/shared/{hx-tab-panel-CbkO9VKu.js.map → hx-tab-panel-SWOEHuJc.js.map} +1 -1
- package/dist/shared/{hx-td-1zwTFLRw.js → hx-td-DnnEMIuA.js} +2 -3
- package/dist/shared/hx-td-DnnEMIuA.js.map +1 -0
- package/dist/shared/{hx-text-input-B-caO5fI.js → hx-text-input-Bn7Gn8CI.js} +24 -25
- package/dist/shared/hx-text-input-Bn7Gn8CI.js.map +1 -0
- package/dist/shared/{hx-textarea-D9O4U8cb.js → hx-textarea-Jx1xnhgv.js} +7 -7
- package/dist/shared/{hx-textarea-D9O4U8cb.js.map → hx-textarea-Jx1xnhgv.js.map} +1 -1
- package/dist/shared/{hx-time-picker-m0z4nFB-.js → hx-time-picker-BoEIZwzv.js} +4 -4
- package/dist/shared/{hx-time-picker-m0z4nFB-.js.map → hx-time-picker-BoEIZwzv.js.map} +1 -1
- package/dist/shared/{hx-toggle-button-Dd8clXB4.js → hx-toggle-button-DPAIh_Xo.js} +24 -24
- package/dist/shared/{hx-toggle-button-Dd8clXB4.js.map → hx-toggle-button-DPAIh_Xo.js.map} +1 -1
- package/dist/shared/{hx-top-nav-CchPYaiV.js → hx-top-nav-DP6OFS8C.js} +11 -14
- package/dist/shared/hx-top-nav-DP6OFS8C.js.map +1 -0
- package/dist/shared/{hx-tree-item-DtMC3DTa.js → hx-tree-item-Dt0Ozqyr.js} +4 -10
- package/dist/shared/hx-tree-item-Dt0Ozqyr.js.map +1 -0
- package/dist/shared/{toast-factory-DvDRAh0l.js → toast-factory-YSznocIV.js} +66 -56
- package/dist/shared/toast-factory-YSznocIV.js.map +1 -0
- package/figma-inventory.json +292 -444
- package/package.json +2 -2
- package/dist/shared/hx-accordion-cnKg4_la.js.map +0 -1
- package/dist/shared/hx-button-modUSOpY.js.map +0 -1
- package/dist/shared/hx-card-CU1QnjNb.js.map +0 -1
- package/dist/shared/hx-carousel-item-BaE4hpLl.js.map +0 -1
- package/dist/shared/hx-clinical-status-BmSjfSEN.js.map +0 -1
- package/dist/shared/hx-color-picker-DiDLZyvK.js.map +0 -1
- package/dist/shared/hx-combobox-DaA5dBC4.js.map +0 -1
- package/dist/shared/hx-data-table-Cq3t86Ic.js.map +0 -1
- package/dist/shared/hx-dialog-eIS8tcDm.js.map +0 -1
- package/dist/shared/hx-drawer-DDhDz7RI.js.map +0 -1
- package/dist/shared/hx-file-upload-zTDbjsRw.js.map +0 -1
- package/dist/shared/hx-icon-button-BmV97nqz.js.map +0 -1
- package/dist/shared/hx-menu-divider-j__TZjH2.js.map +0 -1
- package/dist/shared/hx-meter-Cm7k_Ro8.js.map +0 -1
- package/dist/shared/hx-nav-LoyEKZQC.js.map +0 -1
- package/dist/shared/hx-nav-item-D8xHLVOs.js.map +0 -1
- package/dist/shared/hx-overflow-menu-BmKyAp5D.js.map +0 -1
- package/dist/shared/hx-pagination-Dqw5dorC.js.map +0 -1
- package/dist/shared/hx-phi-field-Bf9TdtC1.js.map +0 -1
- package/dist/shared/hx-popover-B93rTAfr.js.map +0 -1
- package/dist/shared/hx-select-vgaBo1Ai.js.map +0 -1
- package/dist/shared/hx-split-panel-BVG1VWNT.js.map +0 -1
- package/dist/shared/hx-step-DL3PbOzm.js.map +0 -1
- package/dist/shared/hx-td-1zwTFLRw.js.map +0 -1
- package/dist/shared/hx-text-input-B-caO5fI.js.map +0 -1
- package/dist/shared/hx-top-nav-CchPYaiV.js.map +0 -1
- package/dist/shared/hx-tree-item-DtMC3DTa.js.map +0 -1
- package/dist/shared/toast-factory-DvDRAh0l.js.map +0 -1
package/dist/shared/{hx-breadcrumb-item-COeYcB2x.js.map → hx-breadcrumb-item-3tKppF9h.js.map}
RENAMED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hx-breadcrumb-item-COeYcB2x.js","sources":["../../src/components/hx-breadcrumb/hx-breadcrumb.styles.ts","../../src/components/hx-breadcrumb/hx-breadcrumb.ts","../../src/components/hx-breadcrumb/hx-breadcrumb-item.styles.ts","../../src/components/hx-breadcrumb/hx-breadcrumb-item.ts"],"sourcesContent":["import { css } from 'lit';\n\nexport const helixBreadcrumbStyles = css`\n :host {\n display: block;\n font-family: var(\n --hx-breadcrumb-font-family,\n var(--hx-font-family-sans, system-ui, sans-serif)\n );\n font-size: var(--hx-breadcrumb-font-size, var(--hx-font-size-sm, 0.875rem));\n }\n\n [part='nav'] {\n /* nav landmark — no additional styling needed */\n }\n\n [part='list'] {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n list-style: none;\n margin: 0;\n padding: 0;\n gap: 0;\n }\n\n /* Hide middle items when collapsed via maxItems */\n ::slotted([data-bc-hidden]) {\n display: none;\n }\n\n /*\n * Ellipsis ordering when collapsed (FS-014 fix):\n * The ellipsis <hx-breadcrumb-item> lives in shadow DOM to avoid mutating\n * the consumer's light DOM. CSS order places it between the first item\n * (order: 0, default) and the last item (order: 2) in the flex <ol>.\n */\n .hx-bc-ellipsis {\n order: 1;\n }\n\n ::slotted([data-bc-last]) {\n order: 2;\n }\n\n /* Visually hide the separator slot — used only to read text content.\n * display:none is intentional: the slot contains no interactive or focusable\n * content. If a future change adds focusable elements to this slot, switch to\n * visibility:hidden + position:absolute to preserve focus reachability. */\n .separator-slot {\n display: none;\n }\n\n /* ─── High Contrast Mode (forced-colors) ─── */\n\n /*\n * hx-breadcrumb is a nav container. Link colors and separators are handled\n * by hx-breadcrumb-item's own forced-colors block. No additional overrides needed\n * at the container level.\n */\n @media (forced-colors: active) {\n :host {\n forced-color-adjust: auto;\n }\n }\n`;\n","import { html, nothing, type PropertyValues } from 'lit';\nimport '../../utilities/document-token-adoption.js';\nimport { customElement, property, state } from 'lit/decorators.js';\nimport { HelixElement, createIdCounter } from '../../base/index.js';\nimport { forcedColorsInteractive } from '../../styles/forced-colors.js';\nimport { helixBreadcrumbStyles } from './hx-breadcrumb.styles.js';\n\n/** Typed schema.org ListItem entry for JSON-LD BreadcrumbList structured data. */\ninterface JsonLdListItem {\n '@type': string;\n position: number;\n name: string;\n item?: string;\n}\n\nconst _nextBreadcrumbId = createIdCounter('hx-breadcrumb');\n\n/**\n * Hierarchical page path navigation showing current location in site structure.\n *\n * @summary Navigation breadcrumb showing the page hierarchy. Works with Drupal's breadcrumb system.\n *\n * @tag hx-breadcrumb\n *\n * @slot - Default slot for hx-breadcrumb-item children.\n * @slot separator - Optional separator element. Its text content overrides the `separator` property.\n *\n * @csspart nav - The nav landmark element.\n * @csspart list - The ordered list containing items.\n *\n * @cssprop [--hx-breadcrumb-separator-content='/'] - Separator character between items.\n * NOTE: If overriding this custom property directly in CSS (rather than via the `separator`\n * attribute), the value MUST be quoted: `--hx-breadcrumb-separator-content: \">\"`. An unquoted\n * value is invalid for the CSS `content` property and will silently render nothing.\n * @cssprop [--hx-breadcrumb-separator-color=var(--hx-color-neutral-400)] - Separator color.\n * @cssprop [--hx-breadcrumb-separator-gap=var(--hx-space-1)] - Horizontal gap around separators.\n * @cssprop [--hx-breadcrumb-font-size=var(--hx-font-size-sm)] - Font size.\n * @cssprop [--hx-breadcrumb-link-color=var(--hx-color-primary-600)] - Link color.\n * @cssprop [--hx-breadcrumb-link-hover-color=var(--hx-color-primary-700)] - Link hover color.\n * @cssprop [--hx-breadcrumb-text-color=var(--hx-color-neutral-700)] - Current page text color.\n * @cssprop [--hx-breadcrumb-item-max-width] - Max-width for item text truncation (e.g. `12rem`).\n * @cssprop [--hx-breadcrumb-font-family] - CSS custom property.\n * @cssprop [--hx-font-family-sans] - Font family.\n * @cssprop [--hx-font-size-sm] - Font size.\n */\n@customElement('hx-breadcrumb')\nexport class HelixBreadcrumb extends HelixElement {\n static override styles = [helixBreadcrumbStyles, forcedColorsInteractive];\n\n /**\n * The separator character displayed between breadcrumb items.\n * @attr separator\n */\n @property({ type: String })\n separator = '/';\n\n /**\n * The accessible label for the nav landmark.\n * @attr label\n */\n @property({ type: String })\n label = 'Breadcrumb';\n\n /**\n * Maximum number of items to show before collapsing middle items with an ellipsis.\n * Set to 0 (default) to show all items. The ellipsis is a keyboard-accessible\n * button; activating it expands the full breadcrumb by setting maxItems to 0.\n * @attr max-items\n */\n @property({ type: Number, attribute: 'max-items' })\n maxItems = 0;\n\n /**\n * Accessible label for the expand ellipsis button. Override for i18n.\n * @attr label-ellipsis\n */\n @property({ attribute: 'label-ellipsis' }) labelEllipsis = 'Show all breadcrumb items';\n\n /**\n * When true, injects a JSON-LD BreadcrumbList structured data script into the document head.\n *\n * NOTE: Drupal manages `<head>` content via its own render pipeline. Injecting a\n * `<script>` directly via `document.head.appendChild()` in a Drupal context:\n * 1. Bypasses Drupal's deduplication and `hook_html_head_alter()` hook.\n * 2. Is not cacheable by Drupal's page cache.\n * 3. Will be wiped on BigPipe partial page replacements.\n *\n * For Drupal integrations, leave `json-ld` false and use the structured data\n * Twig template instead (see `hx-breadcrumb.twig` in the component directory).\n *\n * @attr json-ld\n */\n @property({ type: Boolean, attribute: 'json-ld' })\n jsonLd = false;\n\n /**\n * Whether the ellipsis expand button is currently shown (shadow DOM rendered).\n * Driven by maxItems collapse logic; replaces the old light-DOM ellipsis injection.\n * @internal\n */\n @state() private _showEllipsis = false;\n /** @internal */\n private _jsonLdScript: HTMLScriptElement | null = null;\n\n /**\n * Tracks which items had their `current` attribute set by this component\n * (as opposed to set by a consumer/Drupal template). This lets us re-evaluate\n * positional current-page detection on each slotchange without incorrectly\n * treating a previously component-set `current` attribute as a consumer-set\n * explicit override.\n * @internal\n */\n private readonly _managedCurrentItems = new WeakSet<Element>();\n\n /**\n * Stable per-instance ID used to tag the injected script element so that\n * multiple hx-breadcrumb instances on the same page don't produce conflicting\n * or duplicate structured-data blocks. Each instance owns exactly one script\n * tag identified by this ID; any stale tag from a previous render cycle is\n * removed before a new one is inserted.\n *\n * Uses a static counter (not Math.random()) so IDs are deterministic across\n * server and client renders, enabling SSR hydration matching.\n * @internal\n */\n private readonly _jsonLdId = `${_nextBreadcrumbId()}-ld`;\n\n // ─── Item Helpers ───\n\n /**\n * Returns only real breadcrumb items, excluding the managed ellipsis element.\n * @internal\n */\n private _getBreadcrumbItems(slot: HTMLSlotElement): Element[] {\n return slot\n .assignedElements({ flatten: true })\n .filter(\n (el) =>\n el.tagName.toLowerCase() === 'hx-breadcrumb-item' &&\n !el.classList.contains('hx-bc-ellipsis'),\n );\n }\n\n /**\n * Applies aria/state attributes to the item list.\n *\n * Current-page detection: if any item has an explicit `current` attribute\n * (e.g. set by a Drupal Twig template), that item is treated as the current\n * page. Otherwise the last item is the current page (default behaviour).\n *\n * This separation allows Drupal to control current-page marking without\n * relying on item order.\n * @internal\n */\n private _applyItemAttributes(items: Element[]): void {\n // Detect consumer-set 'current' attributes. An item has an explicit consumer\n // current if it has the 'current' attribute AND the component did not set it\n // (tracked via _managedCurrentItems). This prevents component-managed state\n // from being misread as a consumer override on subsequent slotchange events.\n const hasExplicitCurrent = items.some(\n (el) => el.hasAttribute('current') && !this._managedCurrentItems.has(el),\n );\n\n items.forEach((item, i) => {\n const el = item as HTMLElement;\n const isLast = i === items.length - 1;\n\n // Separator hiding: always positional — last item has no trailing separator.\n if (isLast) {\n el.setAttribute('data-bc-last', '');\n } else {\n el.removeAttribute('data-bc-last');\n }\n\n // Current-page marker: explicit consumer attribute wins over positional last.\n // The item component renders aria-current=\"page\" on its inner element\n // based on this attribute (see hx-breadcrumb-item.ts).\n if (!hasExplicitCurrent) {\n if (isLast) {\n el.setAttribute('current', '');\n this._managedCurrentItems.add(el);\n } else {\n el.removeAttribute('current');\n this._managedCurrentItems.delete(el);\n }\n }\n // When hasExplicitCurrent is true, leave 'current' attributes as-is so\n // consumer or Drupal template markup is not overridden.\n });\n }\n\n // ─── Slot Handling ───\n\n /** @internal */\n private _handleSlotChange(e: Event): void {\n if (!(e.target instanceof HTMLSlotElement)) return;\n const items = this._getBreadcrumbItems(e.target);\n\n // Handle collapse behaviour\n if (this.maxItems > 0 && items.length > this.maxItems) {\n this._applyCollapse(items);\n } else {\n this._removeCollapse(items);\n }\n\n this._applyItemAttributes(items);\n\n if (this.jsonLd) {\n this._updateJsonLd(items);\n }\n }\n\n /** @internal */\n private _handleSeparatorSlotChange(e: Event): void {\n if (!(e.target instanceof HTMLSlotElement)) return;\n const assigned = e.target.assignedElements({ flatten: true });\n if (assigned.length > 0) {\n const text = (assigned[0] as HTMLElement).textContent?.trim() ?? '';\n this.style.setProperty('--hx-breadcrumb-separator-content', JSON.stringify(text));\n }\n }\n\n // ─── Collapse ───\n\n /** @internal */\n private _applyCollapse(items: Element[]): void {\n // Show only first and last; hide all middle items via data attribute.\n // The ellipsis is rendered in shadow DOM (see render()) to avoid mutating\n // the consumer's light DOM structure (FS-014).\n items.forEach((item, i) => {\n const el = item as HTMLElement;\n if (i === 0 || i === items.length - 1) {\n el.removeAttribute('data-bc-hidden');\n } else {\n el.setAttribute('data-bc-hidden', '');\n }\n });\n\n this._showEllipsis = true;\n }\n\n /** @internal */\n private _removeCollapse(items: Element[]): void {\n items.forEach((item) => {\n (item as HTMLElement).removeAttribute('data-bc-hidden');\n });\n\n this._showEllipsis = false;\n }\n\n /**\n * Expands a collapsed breadcrumb by resetting maxItems to 0.\n * Called by the ellipsis expand button (click or Enter/Space).\n * @internal\n */\n private _expandBreadcrumb(): void {\n this.maxItems = 0;\n // updated() will detect the maxItems change and call _removeCollapse.\n }\n\n // ─── JSON-LD ───\n\n /**\n * JSON-LD ListItem entry with typed fields to avoid Record<string, unknown>.\n * @internal\n */\n private _buildListItem(item: Element, position: number): JsonLdListItem {\n const href = (item as HTMLElement).getAttribute('href');\n const name = (item as HTMLElement).textContent?.trim() ?? '';\n const entry: JsonLdListItem = {\n '@type': 'ListItem',\n position,\n name,\n };\n if (href) entry.item = href;\n return entry;\n }\n\n /** @internal */\n private _updateJsonLd(items: Element[]): void {\n const schema = {\n '@context': 'https://schema.org',\n '@type': 'BreadcrumbList',\n itemListElement: items.map((item, i) => this._buildListItem(item, i + 1)),\n };\n\n // Guard for SSR — document is unavailable server-side\n if (typeof document === 'undefined') return;\n\n if (!this._jsonLdScript) {\n // Dedup guard: remove any stale script with this instance's ID before\n // creating a fresh one. This handles the edge case where the element was\n // reconnected to the DOM after being disconnected without the script\n // reference being re-established.\n document.getElementById(this._jsonLdId)?.remove();\n\n this._jsonLdScript = document.createElement('script');\n this._jsonLdScript.type = 'application/ld+json';\n this._jsonLdScript.id = this._jsonLdId;\n this._jsonLdScript.setAttribute('data-hx-breadcrumb', '');\n document.head.appendChild(this._jsonLdScript);\n }\n\n this._jsonLdScript.textContent = JSON.stringify(schema);\n }\n\n /** @internal */\n private _removeJsonLd(): void {\n this._jsonLdScript?.remove();\n this._jsonLdScript = null;\n }\n\n // ─── Lifecycle ───\n\n override connectedCallback(): void {\n super.connectedCallback();\n // Do NOT set role=\"list\" on the host. The shadow-DOM <nav><ol> provides\n // both navigation landmark and list semantics. Setting role=\"list\" on\n // the host conflicts with the <nav> child — axe-core flags\n // aria-required-children because a list cannot own a navigation landmark.\n // Slotted items no longer need role=\"listitem\" either; the native <ol>\n // handles list semantics in the composed accessibility tree.\n }\n\n override disconnectedCallback(): void {\n super.disconnectedCallback();\n this._removeJsonLd();\n }\n\n override updated(changedProperties: PropertyValues<this>): void {\n super.updated(changedProperties);\n\n if (changedProperties.has('separator')) {\n // JSON.stringify wraps the string in quotes so the value is valid\n // for use in the CSS `content` property (e.g. '/' becomes '\"/\"').\n this.style.setProperty('--hx-breadcrumb-separator-content', JSON.stringify(this.separator));\n }\n\n if (changedProperties.has('maxItems')) {\n // Re-evaluate collapse state when maxItems changes programmatically\n // (e.g. when the expand button resets maxItems to 0).\n const slot = this.shadowRoot?.querySelector<HTMLSlotElement>('slot:not([name])');\n if (slot) {\n const items = this._getBreadcrumbItems(slot);\n if (this.maxItems > 0 && items.length > this.maxItems) {\n this._applyCollapse(items);\n } else {\n this._removeCollapse(items);\n }\n this._applyItemAttributes(items);\n }\n }\n\n if (changedProperties.has('jsonLd')) {\n if (this.jsonLd) {\n // json-ld toggled on after initial render — inject script immediately.\n const slot = this.shadowRoot?.querySelector<HTMLSlotElement>('slot:not([name])');\n if (slot) {\n this._updateJsonLd(this._getBreadcrumbItems(slot));\n }\n } else {\n // json-ld toggled off — remove existing script.\n this._removeJsonLd();\n }\n }\n }\n\n // ─── Render ───\n\n override render() {\n return html`\n <nav part=\"nav\" aria-label=${this.label}>\n <ol part=\"list\">\n <slot @slotchange=${this._handleSlotChange}></slot>\n ${this._showEllipsis\n ? html`\n <hx-breadcrumb-item class=\"hx-bc-ellipsis\">\n <button\n type=\"button\"\n aria-label=${this.labelEllipsis}\n @click=${this._expandBreadcrumb}\n >\n …\n </button>\n </hx-breadcrumb-item>\n `\n : nothing}\n </ol>\n </nav>\n <slot\n name=\"separator\"\n class=\"separator-slot\"\n @slotchange=${this._handleSeparatorSlotChange}\n ></slot>\n `;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'hx-breadcrumb': HelixBreadcrumb;\n }\n}\n","import { css } from 'lit';\n\nexport const helixBreadcrumbItemStyles = css`\n :host {\n display: inline-flex;\n align-items: center;\n }\n\n /*\n * display: contents removes [part='item'] from the box model entirely.\n * This is intentional — the wrapper exists only for slot selection purposes.\n * Consumers using ::part(item) CANNOT apply box-model properties (padding,\n * margin, background, border) to this part. Use ::part(link) or ::part(text)\n * for visual styling of breadcrumb item content.\n */\n [part='item'] {\n display: contents;\n }\n\n [part='link'] {\n color: var(--hx-breadcrumb-link-color, var(--hx-color-primary-600, #0f7078));\n text-decoration: none;\n cursor: pointer;\n font-family: inherit;\n font-size: inherit;\n max-width: var(--hx-breadcrumb-item-max-width);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n }\n\n [part='link']:hover {\n color: var(--hx-breadcrumb-link-hover-color, var(--hx-color-primary-700, #0f6363));\n text-decoration: underline;\n }\n\n [part='link']:focus-visible {\n outline: var(--hx-focus-ring-width, 2px) solid\n var(\n --hx-breadcrumb-link-focus-ring-color,\n var(--hx-focus-ring-color, var(--hx-color-primary-500, #429797))\n );\n outline-offset: var(--hx-focus-ring-offset, 2px);\n border-radius: var(--hx-border-radius-sm, 0.25rem);\n }\n\n [part='text'] {\n color: var(--hx-breadcrumb-text-color, var(--hx-color-text-strong, #202b39));\n font-family: inherit;\n font-size: inherit;\n max-width: var(--hx-breadcrumb-item-max-width);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n }\n\n .separator {\n margin-inline: var(--hx-breadcrumb-separator-gap, var(--hx-space-1, 0.25rem));\n color: var(--hx-breadcrumb-separator-color, var(--hx-color-text-muted, #4a5362));\n user-select: none;\n }\n\n .separator::before {\n content: var(--hx-breadcrumb-separator-content, '/');\n }\n\n /* Normalize buttons slotted into breadcrumb items (e.g. the expand-ellipsis button). */\n ::slotted(button) {\n background: none;\n border: none;\n cursor: pointer;\n font: inherit;\n color: inherit;\n padding: 0;\n }\n\n /* ─── Forced Colors (Windows High Contrast) ─── */\n\n @media (forced-colors: active) {\n [part='link'] {\n color: LinkText;\n }\n\n [part='link']:hover {\n color: LinkText;\n }\n\n .separator {\n color: CanvasText;\n }\n }\n`;\n","import { html, nothing } from 'lit';\nimport '../../utilities/document-token-adoption.js';\nimport { customElement, property } from 'lit/decorators.js';\nimport { HelixElement } from '../../base/index.js';\nimport { forcedColorsInteractive } from '../../styles/forced-colors.js';\nimport { helixBreadcrumbItemStyles } from './hx-breadcrumb-item.styles.js';\n\n/**\n * A single breadcrumb navigation item.\n *\n * @summary A navigation item within an hx-breadcrumb component. Renders as a link when `href` is\n * provided, or as static text for the current page item. The current page item is determined by\n * the `current` attribute (set explicitly or automatically by the parent `hx-breadcrumb`).\n *\n * @tag hx-breadcrumb-item\n *\n * @slot - The link or page text content. Accepts text, HTML, or icon elements.\n *\n * @csspart item - Wrapper around the link or text content.\n * @csspart link - The anchor element when href is provided (non-current items only).\n * @csspart text - The span element for the current page or items without href.\n * @csspart separator - The separator element rendered after non-last items.\n *\n * @cssprop [--hx-breadcrumb-link-color=var(--hx-color-primary-600)] - Link text color.\n * @cssprop [--hx-breadcrumb-link-hover-color=var(--hx-color-primary-700)] - Link hover text color.\n * @cssprop [--hx-breadcrumb-text-color=var(--hx-color-neutral-700)] - Current page text color.\n * @cssprop [--hx-breadcrumb-separator-content='/'] - Separator character displayed after non-last items.\n * @cssprop [--hx-breadcrumb-separator-color=var(--hx-color-neutral-400)] - Separator color.\n * @cssprop [--hx-breadcrumb-separator-gap=var(--hx-space-1)] - Horizontal margin around separator.\n * @cssprop [--hx-breadcrumb-item-max-width] - Optional max-width for text truncation.\n * @cssprop [--hx-breadcrumb-link-focus-ring-color=var(--hx-focus-ring-color, var(--hx-color-primary-500))] - Focus ring color for breadcrumb links.\n */\n@customElement('hx-breadcrumb-item')\nexport class HelixBreadcrumbItem extends HelixElement {\n static override styles = [helixBreadcrumbItemStyles, forcedColorsInteractive];\n\n override connectedCallback(): void {\n super.connectedCallback();\n // No explicit role needed. The shadow-DOM <ol> inside hx-breadcrumb\n // provides native list semantics; slotted items are projected into it.\n // Previously role=\"listitem\" was set here, but it conflicted with the\n // host's role=\"list\" + shadow-DOM <nav> structure (aria-required-children).\n // The native <ol> handles the accessibility tree correctly without\n // explicit ARIA roles on host or items.\n }\n\n /**\n * The URL for this breadcrumb link. Omit for the current page item.\n * When `current` is true, this attribute is ignored and the item always\n * renders as static text per WAI-ARIA APG breadcrumb guidance.\n * @attr href\n */\n @property({ type: String, reflect: true })\n href: string | undefined = undefined;\n\n /**\n * Whether this is the last item in the breadcrumb trail. Set by the parent\n * hx-breadcrumb component via the `data-bc-last` boolean attribute. When\n * present the trailing separator is hidden.\n *\n * @attr data-bc-last\n * @internal\n */\n @property({ type: Boolean, attribute: 'data-bc-last', reflect: true })\n dataBcLast = false;\n\n /**\n * Marks this item as the current page. When set, the item always renders as\n * static text (never a navigable link) and `aria-current=\"page\"` is placed on\n * the inner text element per WAI-ARIA APG breadcrumb guidance, yielding the\n * canonical AT announcement (\"current page, Patient Records\").\n *\n * Can be set explicitly by consumers (e.g. Drupal Twig templates) to override\n * the default positional last-item detection in `hx-breadcrumb`. When any item\n * in the breadcrumb has an explicit `current` attribute, the parent will not\n * override it.\n *\n * @attr current\n */\n @property({ type: Boolean, reflect: true })\n current = false;\n\n override render() {\n // Per WAI-ARIA APG, the current page item MUST NOT be a navigable link.\n // aria-current=\"page\" is placed on the inner element (not the listitem host)\n // for canonical AT announcement (\"current page, Patient Records\" vs\n // \"current page, list item\").\n return html`\n <span part=\"item\">\n ${this.current\n ? html`<span part=\"text\" aria-current=\"page\"><slot></slot></span>`\n : this.href\n ? html`<a part=\"link\" href=${this.href}><slot></slot></a>`\n : html`<span part=\"text\"><slot></slot></span>`}\n </span>\n ${!this.dataBcLast\n ? html`<span class=\"separator\" part=\"separator\" aria-hidden=\"true\"></span>`\n : nothing}\n `;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'hx-breadcrumb-item': HelixBreadcrumbItem;\n }\n}\n"],"names":["helixBreadcrumbStyles","css","_nextBreadcrumbId","createIdCounter","HelixBreadcrumb","HelixElement","slot","el","items","hasExplicitCurrent","item","i","isLast","e","assigned","text","_a","position","href","name","entry","schema","changedProperties","_b","html","nothing","forcedColorsInteractive","__decorateClass","property","state","customElement","helixBreadcrumbItemStyles","HelixBreadcrumbItem"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"hx-breadcrumb-item-3tKppF9h.js","sources":["../../src/components/hx-breadcrumb/hx-breadcrumb.styles.ts","../../src/components/hx-breadcrumb/hx-breadcrumb.ts","../../src/components/hx-breadcrumb/hx-breadcrumb-item.styles.ts","../../src/components/hx-breadcrumb/hx-breadcrumb-item.ts"],"sourcesContent":["import { css } from 'lit';\n\nexport const helixBreadcrumbStyles = css`\n :host {\n display: block;\n font-family: var(\n --hx-breadcrumb-font-family,\n var(--hx-font-family-sans, system-ui, sans-serif)\n );\n font-size: var(--hx-breadcrumb-font-size, var(--hx-font-size-sm, 0.875rem));\n }\n\n [part='nav'] {\n /* nav landmark — no additional styling needed */\n }\n\n [part='list'] {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n list-style: none;\n margin: 0;\n padding: 0;\n gap: 0;\n }\n\n /* Hide middle items when collapsed via maxItems */\n ::slotted([data-bc-hidden]) {\n display: none;\n }\n\n /*\n * Ellipsis ordering when collapsed (FS-014 fix):\n * The ellipsis <hx-breadcrumb-item> lives in shadow DOM to avoid mutating\n * the consumer's light DOM. CSS order places it between the first item\n * (order: 0, default) and the last item (order: 2) in the flex <ol>.\n */\n .hx-bc-ellipsis {\n order: 1;\n }\n\n ::slotted([data-bc-last]) {\n order: 2;\n }\n\n /* Visually hide the separator slot — used only to read text content.\n * display:none is intentional: the slot contains no interactive or focusable\n * content. If a future change adds focusable elements to this slot, switch to\n * visibility:hidden + position:absolute to preserve focus reachability. */\n .separator-slot {\n display: none;\n }\n\n /* ─── High Contrast Mode (forced-colors) ─── */\n\n /*\n * hx-breadcrumb is a nav container. Link colors and separators are handled\n * by hx-breadcrumb-item's own forced-colors block. No additional overrides needed\n * at the container level.\n */\n @media (forced-colors: active) {\n :host {\n forced-color-adjust: auto;\n }\n }\n`;\n","import { html, nothing, type PropertyValues } from 'lit';\nimport '../../utilities/document-token-adoption.js';\nimport { customElement, property, state } from 'lit/decorators.js';\nimport { HelixElement, createIdCounter } from '../../base/index.js';\nimport { forcedColorsInteractive } from '../../styles/forced-colors.js';\nimport { helixBreadcrumbStyles } from './hx-breadcrumb.styles.js';\n\n/** Typed schema.org ListItem entry for JSON-LD BreadcrumbList structured data. */\ninterface JsonLdListItem {\n '@type': string;\n position: number;\n name: string;\n item?: string;\n}\n\nconst _nextBreadcrumbId = createIdCounter('hx-breadcrumb');\n\n/**\n * Hierarchical page path navigation showing current location in site structure.\n *\n * @summary Navigation breadcrumb showing the page hierarchy. Works with Drupal's breadcrumb system.\n *\n * @tag hx-breadcrumb\n *\n * @slot - Default slot for hx-breadcrumb-item children.\n * @slot separator - Optional separator element. Its text content overrides the `separator` property.\n *\n * @csspart nav - The nav landmark element.\n * @csspart list - The ordered list containing items.\n *\n * @cssprop [--hx-breadcrumb-separator-content='/'] - Separator character between items.\n * NOTE: If overriding this custom property directly in CSS (rather than via the `separator`\n * attribute), the value MUST be quoted: `--hx-breadcrumb-separator-content: \">\"`. An unquoted\n * value is invalid for the CSS `content` property and will silently render nothing.\n * @cssprop [--hx-breadcrumb-separator-color=var(--hx-color-neutral-400)] - Separator color.\n * @cssprop [--hx-breadcrumb-separator-gap=var(--hx-space-1)] - Horizontal gap around separators.\n * @cssprop [--hx-breadcrumb-font-size=var(--hx-font-size-sm)] - Font size.\n * @cssprop [--hx-breadcrumb-link-color=var(--hx-color-primary-600)] - Link color.\n * @cssprop [--hx-breadcrumb-link-hover-color=var(--hx-color-primary-700)] - Link hover color.\n * @cssprop [--hx-breadcrumb-text-color=var(--hx-color-neutral-700)] - Current page text color.\n * @cssprop [--hx-breadcrumb-item-max-width] - Max-width for item text truncation (e.g. `12rem`).\n * @cssprop [--hx-breadcrumb-font-family] - CSS custom property.\n * @cssprop [--hx-font-family-sans] - Font family.\n * @cssprop [--hx-font-size-sm] - Font size.\n */\n@customElement('hx-breadcrumb')\nexport class HelixBreadcrumb extends HelixElement {\n static override styles = [helixBreadcrumbStyles, forcedColorsInteractive];\n\n /**\n * The separator character displayed between breadcrumb items.\n * @attr separator\n */\n @property({ type: String })\n separator = '/';\n\n /**\n * The accessible label for the nav landmark.\n * @attr label\n */\n @property({ type: String })\n label = 'Breadcrumb';\n\n /**\n * Maximum number of items to show before collapsing middle items with an ellipsis.\n * Set to 0 (default) to show all items. The ellipsis is a keyboard-accessible\n * button; activating it expands the full breadcrumb by setting maxItems to 0.\n * @attr max-items\n */\n @property({ type: Number, attribute: 'max-items' })\n maxItems = 0;\n\n /**\n * Accessible label for the expand ellipsis button. Override for i18n.\n * @attr label-ellipsis\n */\n @property({ attribute: 'label-ellipsis' }) labelEllipsis = 'Show all breadcrumb items';\n\n /**\n * When true, injects a JSON-LD BreadcrumbList structured data script into the document head.\n *\n * NOTE: Drupal manages `<head>` content via its own render pipeline. Injecting a\n * `<script>` directly via `document.head.appendChild()` in a Drupal context:\n * 1. Bypasses Drupal's deduplication and `hook_html_head_alter()` hook.\n * 2. Is not cacheable by Drupal's page cache.\n * 3. Will be wiped on BigPipe partial page replacements.\n *\n * For Drupal integrations, leave `json-ld` false and use the structured data\n * Twig template instead (see `hx-breadcrumb.twig` in the component directory).\n *\n * @attr json-ld\n */\n @property({ type: Boolean, attribute: 'json-ld' })\n jsonLd = false;\n\n /**\n * Whether the ellipsis expand button is currently shown (shadow DOM rendered).\n * Driven by maxItems collapse logic; replaces the old light-DOM ellipsis injection.\n * @internal\n */\n @state() private _showEllipsis = false;\n /** @internal */\n private _jsonLdScript: HTMLScriptElement | null = null;\n\n /**\n * Tracks which items had their `current` attribute set by this component\n * (as opposed to set by a consumer/Drupal template). This lets us re-evaluate\n * positional current-page detection on each slotchange without incorrectly\n * treating a previously component-set `current` attribute as a consumer-set\n * explicit override.\n * @internal\n */\n private readonly _managedCurrentItems = new WeakSet<Element>();\n\n /**\n * Stable per-instance ID used to tag the injected script element so that\n * multiple hx-breadcrumb instances on the same page don't produce conflicting\n * or duplicate structured-data blocks. Each instance owns exactly one script\n * tag identified by this ID; any stale tag from a previous render cycle is\n * removed before a new one is inserted.\n *\n * Uses a static counter (not Math.random()) so IDs are deterministic across\n * server and client renders, enabling SSR hydration matching.\n * @internal\n */\n private readonly _jsonLdId = `${_nextBreadcrumbId()}-ld`;\n\n // ─── Item Helpers ───\n\n /**\n * Returns only real breadcrumb items, excluding the managed ellipsis element.\n * @internal\n */\n private _getBreadcrumbItems(slot: HTMLSlotElement): Element[] {\n return slot\n .assignedElements({ flatten: true })\n .filter(\n (el) =>\n el.tagName.toLowerCase() === 'hx-breadcrumb-item' &&\n !el.classList.contains('hx-bc-ellipsis'),\n );\n }\n\n /**\n * Applies aria/state attributes to the item list.\n *\n * Current-page detection: if any item has an explicit `current` attribute\n * (e.g. set by a Drupal Twig template), that item is treated as the current\n * page. Otherwise the last item is the current page (default behaviour).\n *\n * This separation allows Drupal to control current-page marking without\n * relying on item order.\n * @internal\n */\n private _applyItemAttributes(items: Element[]): void {\n // Detect consumer-set 'current' attributes. An item has an explicit consumer\n // current if it has the 'current' attribute AND the component did not set it\n // (tracked via _managedCurrentItems). This prevents component-managed state\n // from being misread as a consumer override on subsequent slotchange events.\n const hasExplicitCurrent = items.some(\n (el) => el.hasAttribute('current') && !this._managedCurrentItems.has(el),\n );\n\n items.forEach((item, i) => {\n const el = item as HTMLElement;\n const isLast = i === items.length - 1;\n\n // Separator hiding: always positional — last item has no trailing separator.\n if (isLast) {\n el.setAttribute('data-bc-last', '');\n } else {\n el.removeAttribute('data-bc-last');\n }\n\n // Current-page marker: explicit consumer attribute wins over positional last.\n // The item component renders aria-current=\"page\" on its inner element\n // based on this attribute (see hx-breadcrumb-item.ts).\n if (!hasExplicitCurrent) {\n if (isLast) {\n el.setAttribute('current', '');\n this._managedCurrentItems.add(el);\n } else {\n el.removeAttribute('current');\n this._managedCurrentItems.delete(el);\n }\n }\n // When hasExplicitCurrent is true, leave 'current' attributes as-is so\n // consumer or Drupal template markup is not overridden.\n });\n }\n\n // ─── Slot Handling ───\n\n /** @internal */\n private _handleSlotChange(e: Event): void {\n if (!(e.target instanceof HTMLSlotElement)) return;\n const items = this._getBreadcrumbItems(e.target);\n\n // Handle collapse behaviour\n if (this.maxItems > 0 && items.length > this.maxItems) {\n this._applyCollapse(items);\n } else {\n this._removeCollapse(items);\n }\n\n this._applyItemAttributes(items);\n\n if (this.jsonLd) {\n this._updateJsonLd(items);\n }\n }\n\n /** @internal */\n private _handleSeparatorSlotChange(e: Event): void {\n if (!(e.target instanceof HTMLSlotElement)) return;\n const assigned = e.target.assignedElements({ flatten: true });\n if (assigned.length > 0) {\n const text = (assigned[0] as HTMLElement).textContent?.trim() ?? '';\n this.style.setProperty('--hx-breadcrumb-separator-content', JSON.stringify(text));\n }\n }\n\n // ─── Collapse ───\n\n /** @internal */\n private _applyCollapse(items: Element[]): void {\n // Show only first and last; hide all middle items via data attribute.\n // The ellipsis is rendered in shadow DOM (see render()) to avoid mutating\n // the consumer's light DOM structure (FS-014).\n items.forEach((item, i) => {\n const el = item as HTMLElement;\n if (i === 0 || i === items.length - 1) {\n el.removeAttribute('data-bc-hidden');\n } else {\n el.setAttribute('data-bc-hidden', '');\n }\n });\n\n this._showEllipsis = true;\n }\n\n /** @internal */\n private _removeCollapse(items: Element[]): void {\n items.forEach((item) => {\n (item as HTMLElement).removeAttribute('data-bc-hidden');\n });\n\n this._showEllipsis = false;\n }\n\n /**\n * Expands a collapsed breadcrumb by resetting maxItems to 0.\n * Called by the ellipsis expand button (click or Enter/Space).\n * @internal\n */\n private _expandBreadcrumb(): void {\n this.maxItems = 0;\n // updated() will detect the maxItems change and call _removeCollapse.\n }\n\n // ─── JSON-LD ───\n\n /**\n * JSON-LD ListItem entry with typed fields to avoid Record<string, unknown>.\n * @internal\n */\n private _buildListItem(item: Element, position: number): JsonLdListItem {\n const href = (item as HTMLElement).getAttribute('href');\n const name = (item as HTMLElement).textContent?.trim() ?? '';\n const entry: JsonLdListItem = {\n '@type': 'ListItem',\n position,\n name,\n };\n if (href) entry.item = href;\n return entry;\n }\n\n /** @internal */\n private _updateJsonLd(items: Element[]): void {\n const schema = {\n '@context': 'https://schema.org',\n '@type': 'BreadcrumbList',\n itemListElement: items.map((item, i) => this._buildListItem(item, i + 1)),\n };\n\n // Guard for SSR — document is unavailable server-side\n if (typeof document === 'undefined') return;\n\n if (!this._jsonLdScript) {\n // Dedup guard: remove any stale script with this instance's ID before\n // creating a fresh one. This handles the edge case where the element was\n // reconnected to the DOM after being disconnected without the script\n // reference being re-established.\n document.getElementById(this._jsonLdId)?.remove();\n\n this._jsonLdScript = document.createElement('script');\n this._jsonLdScript.type = 'application/ld+json';\n this._jsonLdScript.id = this._jsonLdId;\n this._jsonLdScript.setAttribute('data-hx-breadcrumb', '');\n document.head.appendChild(this._jsonLdScript);\n }\n\n this._jsonLdScript.textContent = JSON.stringify(schema);\n }\n\n /** @internal */\n private _removeJsonLd(): void {\n this._jsonLdScript?.remove();\n this._jsonLdScript = null;\n }\n\n // ─── Lifecycle ───\n\n override connectedCallback(): void {\n super.connectedCallback();\n // Do NOT set role=\"list\" on the host. The shadow-DOM <nav><ol> provides\n // both navigation landmark and list semantics. Setting role=\"list\" on\n // the host conflicts with the <nav> child — axe-core flags\n // aria-required-children because a list cannot own a navigation landmark.\n // Slotted items no longer need role=\"listitem\" either; the native <ol>\n // handles list semantics in the composed accessibility tree.\n }\n\n override disconnectedCallback(): void {\n super.disconnectedCallback();\n this._removeJsonLd();\n }\n\n override updated(changedProperties: PropertyValues<this>): void {\n super.updated(changedProperties);\n\n if (changedProperties.has('separator')) {\n // JSON.stringify wraps the string in quotes so the value is valid\n // for use in the CSS `content` property (e.g. '/' becomes '\"/\"').\n this.style.setProperty('--hx-breadcrumb-separator-content', JSON.stringify(this.separator));\n }\n\n if (changedProperties.has('maxItems')) {\n // Re-evaluate collapse state when maxItems changes programmatically\n // (e.g. when the expand button resets maxItems to 0).\n const slot = this.shadowRoot?.querySelector<HTMLSlotElement>('slot:not([name])');\n if (slot) {\n const items = this._getBreadcrumbItems(slot);\n if (this.maxItems > 0 && items.length > this.maxItems) {\n this._applyCollapse(items);\n } else {\n this._removeCollapse(items);\n }\n this._applyItemAttributes(items);\n }\n }\n\n if (changedProperties.has('jsonLd')) {\n if (this.jsonLd) {\n // json-ld toggled on after initial render — inject script immediately.\n const slot = this.shadowRoot?.querySelector<HTMLSlotElement>('slot:not([name])');\n if (slot) {\n this._updateJsonLd(this._getBreadcrumbItems(slot));\n }\n } else {\n // json-ld toggled off — remove existing script.\n this._removeJsonLd();\n }\n }\n }\n\n // ─── Render ───\n\n override render() {\n return html`\n <nav part=\"nav\" aria-label=${this.label}>\n <ol part=\"list\">\n <slot @slotchange=${this._handleSlotChange}></slot>\n ${this._showEllipsis\n ? html`\n <hx-breadcrumb-item class=\"hx-bc-ellipsis\">\n <button\n type=\"button\"\n aria-label=${this.labelEllipsis}\n @click=${this._expandBreadcrumb}\n >\n …\n </button>\n </hx-breadcrumb-item>\n `\n : nothing}\n </ol>\n </nav>\n <slot\n name=\"separator\"\n class=\"separator-slot\"\n @slotchange=${this._handleSeparatorSlotChange}\n ></slot>\n `;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'hx-breadcrumb': HelixBreadcrumb;\n }\n}\n","import { css } from 'lit';\n\nexport const helixBreadcrumbItemStyles = css`\n :host {\n display: inline-flex;\n align-items: center;\n }\n\n /*\n * display: contents removes [part='item'] from the box model entirely.\n * This is intentional — the wrapper exists only for slot selection purposes.\n * Consumers using ::part(item) CANNOT apply box-model properties (padding,\n * margin, background, border) to this part. Use ::part(link) or ::part(text)\n * for visual styling of breadcrumb item content.\n */\n [part='item'] {\n display: contents;\n }\n\n [part='link'] {\n color: var(--hx-breadcrumb-link-color, var(--hx-color-primary-600, #0f7078));\n text-decoration: none;\n cursor: pointer;\n font-family: inherit;\n font-size: inherit;\n max-width: var(--hx-breadcrumb-item-max-width);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n }\n\n [part='link']:hover {\n color: var(--hx-breadcrumb-link-hover-color, var(--hx-color-primary-700, #0f6363));\n text-decoration: underline;\n }\n\n [part='link']:focus-visible {\n outline: var(--hx-focus-ring-width, 2px) solid\n var(--hx-breadcrumb-link-focus-ring-color, var(--hx-focus-ring-color, #0f7078));\n outline-offset: var(--hx-focus-ring-offset, 2px);\n border-radius: var(--hx-border-radius-sm, 0.25rem);\n }\n\n [part='text'] {\n color: var(--hx-breadcrumb-text-color, var(--hx-color-text-strong, #202b39));\n font-family: inherit;\n font-size: inherit;\n max-width: var(--hx-breadcrumb-item-max-width);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n }\n\n .separator {\n margin-inline: var(--hx-breadcrumb-separator-gap, var(--hx-space-1, 0.25rem));\n color: var(--hx-breadcrumb-separator-color, var(--hx-color-text-muted, #4a5362));\n user-select: none;\n }\n\n .separator::before {\n content: var(--hx-breadcrumb-separator-content, '/');\n }\n\n /* Normalize buttons slotted into breadcrumb items (e.g. the expand-ellipsis button). */\n ::slotted(button) {\n background: none;\n border: none;\n cursor: pointer;\n font: inherit;\n color: inherit;\n padding: 0;\n }\n\n /* ─── Forced Colors (Windows High Contrast) ─── */\n\n @media (forced-colors: active) {\n [part='link'] {\n color: LinkText;\n }\n\n [part='link']:hover {\n color: LinkText;\n }\n\n .separator {\n color: CanvasText;\n }\n }\n`;\n","import { html, nothing } from 'lit';\nimport '../../utilities/document-token-adoption.js';\nimport { customElement, property } from 'lit/decorators.js';\nimport { HelixElement } from '../../base/index.js';\nimport { forcedColorsInteractive } from '../../styles/forced-colors.js';\nimport { helixBreadcrumbItemStyles } from './hx-breadcrumb-item.styles.js';\n\n/**\n * A single breadcrumb navigation item.\n *\n * @summary A navigation item within an hx-breadcrumb component. Renders as a link when `href` is\n * provided, or as static text for the current page item. The current page item is determined by\n * the `current` attribute (set explicitly or automatically by the parent `hx-breadcrumb`).\n *\n * @tag hx-breadcrumb-item\n *\n * @slot - The link or page text content. Accepts text, HTML, or icon elements.\n *\n * @csspart item - Wrapper around the link or text content.\n * @csspart link - The anchor element when href is provided (non-current items only).\n * @csspart text - The span element for the current page or items without href.\n * @csspart separator - The separator element rendered after non-last items.\n *\n * @cssprop [--hx-breadcrumb-link-color=var(--hx-color-primary-600)] - Link text color.\n * @cssprop [--hx-breadcrumb-link-hover-color=var(--hx-color-primary-700)] - Link hover text color.\n * @cssprop [--hx-breadcrumb-text-color=var(--hx-color-neutral-700)] - Current page text color.\n * @cssprop [--hx-breadcrumb-separator-content='/'] - Separator character displayed after non-last items.\n * @cssprop [--hx-breadcrumb-separator-color=var(--hx-color-neutral-400)] - Separator color.\n * @cssprop [--hx-breadcrumb-separator-gap=var(--hx-space-1)] - Horizontal margin around separator.\n * @cssprop [--hx-breadcrumb-item-max-width] - Optional max-width for text truncation.\n * @cssprop [--hx-breadcrumb-link-focus-ring-color=var(--hx-focus-ring-color, var(--hx-color-primary-500))] - Focus ring color for breadcrumb links.\n */\n@customElement('hx-breadcrumb-item')\nexport class HelixBreadcrumbItem extends HelixElement {\n static override styles = [helixBreadcrumbItemStyles, forcedColorsInteractive];\n\n override connectedCallback(): void {\n super.connectedCallback();\n // No explicit role needed. The shadow-DOM <ol> inside hx-breadcrumb\n // provides native list semantics; slotted items are projected into it.\n // Previously role=\"listitem\" was set here, but it conflicted with the\n // host's role=\"list\" + shadow-DOM <nav> structure (aria-required-children).\n // The native <ol> handles the accessibility tree correctly without\n // explicit ARIA roles on host or items.\n }\n\n /**\n * The URL for this breadcrumb link. Omit for the current page item.\n * When `current` is true, this attribute is ignored and the item always\n * renders as static text per WAI-ARIA APG breadcrumb guidance.\n * @attr href\n */\n @property({ type: String, reflect: true })\n href: string | undefined = undefined;\n\n /**\n * Whether this is the last item in the breadcrumb trail. Set by the parent\n * hx-breadcrumb component via the `data-bc-last` boolean attribute. When\n * present the trailing separator is hidden.\n *\n * @attr data-bc-last\n * @internal\n */\n @property({ type: Boolean, attribute: 'data-bc-last', reflect: true })\n dataBcLast = false;\n\n /**\n * Marks this item as the current page. When set, the item always renders as\n * static text (never a navigable link) and `aria-current=\"page\"` is placed on\n * the inner text element per WAI-ARIA APG breadcrumb guidance, yielding the\n * canonical AT announcement (\"current page, Patient Records\").\n *\n * Can be set explicitly by consumers (e.g. Drupal Twig templates) to override\n * the default positional last-item detection in `hx-breadcrumb`. When any item\n * in the breadcrumb has an explicit `current` attribute, the parent will not\n * override it.\n *\n * @attr current\n */\n @property({ type: Boolean, reflect: true })\n current = false;\n\n override render() {\n // Per WAI-ARIA APG, the current page item MUST NOT be a navigable link.\n // aria-current=\"page\" is placed on the inner element (not the listitem host)\n // for canonical AT announcement (\"current page, Patient Records\" vs\n // \"current page, list item\").\n return html`\n <span part=\"item\">\n ${this.current\n ? html`<span part=\"text\" aria-current=\"page\"><slot></slot></span>`\n : this.href\n ? html`<a part=\"link\" href=${this.href}><slot></slot></a>`\n : html`<span part=\"text\"><slot></slot></span>`}\n </span>\n ${!this.dataBcLast\n ? html`<span class=\"separator\" part=\"separator\" aria-hidden=\"true\"></span>`\n : nothing}\n `;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'hx-breadcrumb-item': HelixBreadcrumbItem;\n }\n}\n"],"names":["helixBreadcrumbStyles","css","_nextBreadcrumbId","createIdCounter","HelixBreadcrumb","HelixElement","slot","el","items","hasExplicitCurrent","item","i","isLast","e","assigned","text","_a","position","href","name","entry","schema","changedProperties","_b","html","nothing","forcedColorsInteractive","__decorateClass","property","state","customElement","helixBreadcrumbItemStyles","HelixBreadcrumbItem"],"mappings":"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"}
|
|
@@ -1,12 +1,11 @@
|
|
|
1
|
-
import { css as
|
|
2
|
-
import { property as a, customElement as
|
|
3
|
-
import { classMap as
|
|
4
|
-
import { ifDefined as
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
|
|
9
|
-
const y = f`
|
|
1
|
+
import { css as v, html as d, nothing as s } from "lit";
|
|
2
|
+
import { property as a, customElement as f } from "lit/decorators.js";
|
|
3
|
+
import { classMap as c } from "lit/directives/class-map.js";
|
|
4
|
+
import { ifDefined as u } from "lit/directives/if-defined.js";
|
|
5
|
+
import { d as p } from "./dev-warn-YlwPHjtX.js";
|
|
6
|
+
import { m as g } from "./aria-delegation-Doq6RRUy.js";
|
|
7
|
+
import { H as x } from "./helix-element-BNEYeiys.js";
|
|
8
|
+
const m = v`
|
|
10
9
|
:host {
|
|
11
10
|
display: inline-block;
|
|
12
11
|
}
|
|
@@ -54,10 +53,7 @@ const y = f`
|
|
|
54
53
|
|
|
55
54
|
.button:focus-visible {
|
|
56
55
|
outline: var(--hx-focus-ring-width, 2px) solid
|
|
57
|
-
var(
|
|
58
|
-
--hx-button-focus-ring-color,
|
|
59
|
-
var(--hx-focus-ring-color, var(--hx-color-primary-500, #429797))
|
|
60
|
-
);
|
|
56
|
+
var(--hx-button-focus-ring-color, var(--hx-focus-ring-color, #0f7078));
|
|
61
57
|
outline-offset: var(--hx-focus-ring-offset, 2px);
|
|
62
58
|
}
|
|
63
59
|
|
|
@@ -95,21 +91,24 @@ const y = f`
|
|
|
95
91
|
/* ─── Style Variants ─── */
|
|
96
92
|
|
|
97
93
|
.button--primary {
|
|
98
|
-
--hx-button-bg: var(--hx-color-primary-
|
|
99
|
-
|
|
94
|
+
--hx-button-bg: var(--hx-color-action-primary-bg, #429797);
|
|
95
|
+
/* Inline #0d1825 matches text.on-primary's resolved primitive (neutral-900);
|
|
96
|
+
cold-start without the semantic still paints AA-tuned dark-on-primary
|
|
97
|
+
rather than white-on-primary (3.43:1 fail). */
|
|
98
|
+
--hx-button-color: var(--hx-color-text-on-primary, #0d1825);
|
|
100
99
|
--hx-button-border-color: transparent;
|
|
101
100
|
}
|
|
102
101
|
|
|
103
102
|
.button--secondary {
|
|
104
103
|
--hx-button-bg: transparent;
|
|
105
|
-
/* primary-500 (#429797) text on white surface = 3.
|
|
106
|
-
primary-600 (#0F7078) on white =
|
|
107
|
-
--hx-button-color: var(--hx-color-
|
|
108
|
-
--hx-button-border-color: var(--hx-color-
|
|
104
|
+
/* primary-500 (#429797) text on white surface = 3.44:1 — fails AA.
|
|
105
|
+
primary-600 (#0F7078) on white = 5.82:1 — AA pass. */
|
|
106
|
+
--hx-button-color: var(--hx-color-action-secondary-fg, #0f7078);
|
|
107
|
+
--hx-button-border-color: var(--hx-color-action-secondary-border, #0f7078);
|
|
109
108
|
}
|
|
110
109
|
|
|
111
110
|
.button--secondary:hover {
|
|
112
|
-
--hx-button-bg: var(--hx-button-hover-bg, var(--hx-color-
|
|
111
|
+
--hx-button-bg: var(--hx-button-hover-bg, var(--hx-color-action-secondary-bg-hover, #ebf8f8));
|
|
113
112
|
}
|
|
114
113
|
|
|
115
114
|
.button--tertiary {
|
|
@@ -123,36 +122,52 @@ const y = f`
|
|
|
123
122
|
}
|
|
124
123
|
|
|
125
124
|
.button--danger {
|
|
126
|
-
--hx-button-bg: var(--hx-color-
|
|
127
|
-
|
|
125
|
+
--hx-button-bg: var(--hx-color-action-danger-bg, #e5493e);
|
|
126
|
+
/* Inline #0d1825 matches text.on-error's resolved primitive (neutral-900);
|
|
127
|
+
cold-start without the semantic still paints AA-tuned dark-on-error
|
|
128
|
+
rather than white-on-error (3.92:1 fail). */
|
|
129
|
+
--hx-button-color: var(--hx-color-text-on-error, #0d1825);
|
|
128
130
|
--hx-button-border-color: transparent;
|
|
129
131
|
}
|
|
130
132
|
|
|
131
133
|
/* on-error tokens are tuned for error-500 (neutral-900 on #E5493E ≈ 4.59:1).
|
|
132
|
-
error-600 (#C92A2A) drops that to
|
|
133
|
-
|
|
134
|
-
(commit 300e21ab0)
|
|
134
|
+
error-600 (#C92A2A) drops that to 3.28:1 — AA fail. text.on-error-strong
|
|
135
|
+
resolves to neutral-0 across modes (no dark flip) so the darker hover fill
|
|
136
|
+
stays legible. Mirrors hx-toast precedent (commit 300e21ab0); routed
|
|
137
|
+
through the semantic tier in 3.2.1 token-cascade remediation. */
|
|
135
138
|
.button--danger:hover {
|
|
136
|
-
--hx-button-bg: var(--hx-button-hover-bg, var(--hx-color-
|
|
137
|
-
--hx-button-color: var(--hx-color-
|
|
139
|
+
--hx-button-bg: var(--hx-button-hover-bg, var(--hx-color-action-danger-bg-hover, #c92a2a));
|
|
140
|
+
--hx-button-color: var(--hx-color-text-on-error-strong, #ffffff);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/* Pressed state binds explicitly to action.danger.bg-active (error-700,
|
|
144
|
+
#A21312) + text.on-error-strong (neutral-0) = 7.96:1 AA. Base
|
|
145
|
+
.button:active filter:brightness(0.8) would compound on top of bg-hover
|
|
146
|
+
(#C92A2A) and produce ~3.3:1 sub-AA on the bound colors. Override the
|
|
147
|
+
filter to none. HC override on action.danger.bg-active flips to HC
|
|
148
|
+
error-500 so the on-error-strong (HC = #000) pair is AA in HC too. */
|
|
149
|
+
.button--danger:active {
|
|
150
|
+
--hx-button-bg: var(--hx-button-active-bg, var(--hx-color-action-danger-bg-active, #a21312));
|
|
151
|
+
--hx-button-color: var(--hx-color-text-on-error-strong, #ffffff);
|
|
152
|
+
filter: none;
|
|
138
153
|
}
|
|
139
154
|
|
|
140
155
|
.button--ghost {
|
|
141
156
|
--hx-button-bg: transparent;
|
|
142
|
-
/* primary-500 (#429797) text on white surface = 3.
|
|
143
|
-
primary-600 (#0F7078) on white =
|
|
144
|
-
--hx-button-color: var(--hx-color-
|
|
157
|
+
/* primary-500 (#429797) text on white surface = 3.44:1 — fails AA.
|
|
158
|
+
primary-600 (#0F7078) on white = 5.82:1 — AA pass. */
|
|
159
|
+
--hx-button-color: var(--hx-color-action-ghost-fg, #0f7078);
|
|
145
160
|
--hx-button-border-color: transparent;
|
|
146
161
|
}
|
|
147
162
|
|
|
148
163
|
.button--ghost:hover {
|
|
149
|
-
--hx-button-bg: var(--hx-button-hover-bg, var(--hx-color-
|
|
164
|
+
--hx-button-bg: var(--hx-button-hover-bg, var(--hx-color-action-ghost-bg-hover, #ebf8f8));
|
|
150
165
|
}
|
|
151
166
|
|
|
152
167
|
.button--outline {
|
|
153
168
|
--hx-button-bg: transparent;
|
|
154
169
|
--hx-button-color: var(--hx-color-text-primary, #0d1825);
|
|
155
|
-
--hx-button-border-color: var(--hx-color-border-strong, #
|
|
170
|
+
--hx-button-border-color: var(--hx-color-border-strong, #66787b);
|
|
156
171
|
}
|
|
157
172
|
|
|
158
173
|
.button--outline:hover {
|
|
@@ -160,12 +175,24 @@ const y = f`
|
|
|
160
175
|
}
|
|
161
176
|
|
|
162
177
|
/* on-primary token resolves to neutral-900 (#0D1825) — tuned for primary-500.
|
|
163
|
-
primary-600 (#0F7078) drops the pair to 3.07:1 — AA fail.
|
|
164
|
-
neutral-0 for the darker hover fill.
|
|
165
|
-
(commit 300e21ab0)
|
|
178
|
+
primary-600 (#0F7078) drops the pair to 3.07:1 — AA fail. text.on-primary-strong
|
|
179
|
+
resolves to neutral-0 across modes (no dark flip) for the darker hover fill.
|
|
180
|
+
Mirrors hx-toast precedent (commit 300e21ab0); routed through the semantic
|
|
181
|
+
tier in 3.2.1 token-cascade remediation. */
|
|
166
182
|
.button--primary:hover {
|
|
167
|
-
--hx-button-bg: var(--hx-button-hover-bg, var(--hx-color-primary-
|
|
168
|
-
--hx-button-color: var(--hx-color-
|
|
183
|
+
--hx-button-bg: var(--hx-button-hover-bg, var(--hx-color-action-primary-bg-hover, #0f7078));
|
|
184
|
+
--hx-button-color: var(--hx-color-text-on-primary-strong, #ffffff);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/* Pressed state binds explicitly to action.primary.bg-active (primary-700,
|
|
188
|
+
#0F6363) + text.on-primary-strong (neutral-0) = 7.03:1 AA. The base
|
|
189
|
+
.button:active filter:brightness(0.8) would compound on top of bg-hover
|
|
190
|
+
(#0F7078) and produce ~3.7:1 sub-AA on the bound colors. Override the
|
|
191
|
+
filter to none so the action.*.bg-active token is what actually paints. */
|
|
192
|
+
.button--primary:active {
|
|
193
|
+
--hx-button-bg: var(--hx-button-active-bg, var(--hx-color-action-primary-bg-active, #0f6363));
|
|
194
|
+
--hx-button-color: var(--hx-color-text-on-primary-strong, #ffffff);
|
|
195
|
+
filter: none;
|
|
169
196
|
}
|
|
170
197
|
|
|
171
198
|
/* ─── Disabled ─── */
|
|
@@ -209,9 +236,19 @@ const y = f`
|
|
|
209
236
|
|
|
210
237
|
/* ─── Inverted Mode ─── */
|
|
211
238
|
|
|
239
|
+
/* Inline-fallback contract for --hx-color-border-on-dark-* in this section:
|
|
240
|
+
the literal rgba(255, 255, 255, 0.X) arms are a LIGHT-MODE-only last
|
|
241
|
+
resort (cold-start, CSS-not-loaded). At runtime, hx-theme injects
|
|
242
|
+
dark.color.border.on-dark-* as overlay-black-* so dark-mode inverted
|
|
243
|
+
buttons stay visible on the now-light surface.inverse (#EBEEE9). The
|
|
244
|
+
inline white overlays would render invisible (≈1.1:1) on a light surface,
|
|
245
|
+
but they never paint when the theme is mounted. If a future change moves
|
|
246
|
+
these into a context where hx-theme is not guaranteed, replace with
|
|
247
|
+
mode-aware tokens. */
|
|
248
|
+
|
|
212
249
|
/* Override text color and filter-based hover/active for all variants */
|
|
213
250
|
:host([inverted]) .button {
|
|
214
|
-
color: var(--hx-button-inverted-color, var(--hx-color-
|
|
251
|
+
color: var(--hx-button-inverted-color, var(--hx-color-text-inverse, #ffffff));
|
|
215
252
|
filter: none;
|
|
216
253
|
}
|
|
217
254
|
|
|
@@ -224,37 +261,89 @@ const y = f`
|
|
|
224
261
|
}
|
|
225
262
|
|
|
226
263
|
:host([inverted]) .button:focus-visible {
|
|
264
|
+
/* WCAG 1.4.11: focus indicator needs ≥3:1 against adjacent colors.
|
|
265
|
+
border-on-dark-default (overlay-white-30) ≈ 2.7:1 on neutral-900 — fails.
|
|
266
|
+
border-on-dark-strong (overlay-white-70) ≈ 5:1 — passes. */
|
|
227
267
|
outline-color: var(
|
|
228
268
|
--hx-button-inverted-focus-ring-color,
|
|
229
|
-
var(--hx-
|
|
269
|
+
var(--hx-color-border-on-dark-strong, rgba(255, 255, 255, 0.7))
|
|
230
270
|
);
|
|
231
271
|
}
|
|
232
272
|
|
|
233
|
-
/* Primary inverted —
|
|
234
|
-
|
|
235
|
-
|
|
273
|
+
/* Primary inverted — resting bg routes through action.primary.bg-inverted-rest
|
|
274
|
+
so dark mode can flip the fill to primary-600. surface.inverse becomes light
|
|
275
|
+
(#EBEEE9) in dark mode; primary-500 on #EBEEE9 = 2.94:1 (sub-3:1 UI floor
|
|
276
|
+
fail for the inverted-button boundary). primary-600 on #EBEEE9 = 4.97:1
|
|
277
|
+
(AA pass). Light mode tracks action.primary.bg (primary-500, 5.20:1 on
|
|
278
|
+
dark surface.inverse). */
|
|
279
|
+
:host([inverted]) .button--primary {
|
|
280
|
+
--hx-button-bg: var(--hx-color-action-primary-bg-inverted-rest, #429797);
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
/* Primary inverted — hover/pressed lift to action.primary.bg-inverted-hover
|
|
284
|
+
(primary-400, light teal). The base :host([inverted]) .button rule binds
|
|
285
|
+
color to text.inverse, which flips by mode (neutral-0 in light, neutral-900
|
|
286
|
+
in dark). On a permanent light-teal fill, white text drops to 2.4:1 in
|
|
287
|
+
light mode (AA fail). Pin color to text.on-primary (neutral-900, no
|
|
288
|
+
dark-mode flip) for both hover and active so the foreground is dark in
|
|
289
|
+
both modes — neutral-900 on primary-400 = 7.27:1 (AA pass).
|
|
290
|
+
Pressed === hover visually in inverted mode is acceptable UX (the
|
|
291
|
+
transient absence of pointer over the button signals release).
|
|
292
|
+
The fallback chain wraps --hx-button-active-bg (highest precedence) and
|
|
293
|
+
--hx-button-hover-bg so consumer overrides on either prop apply under
|
|
294
|
+
:host([inverted]) — the two share a paint here, so either knob is
|
|
295
|
+
honored, with active-bg winning when both are set. */
|
|
296
|
+
:host([inverted]) .button--primary:hover,
|
|
297
|
+
:host([inverted]) .button--primary:active {
|
|
298
|
+
--hx-button-bg: var(
|
|
299
|
+
--hx-button-active-bg,
|
|
300
|
+
var(--hx-button-hover-bg, var(--hx-color-action-primary-bg-inverted-hover, #6ab1b1))
|
|
301
|
+
);
|
|
302
|
+
color: var(
|
|
303
|
+
--hx-button-inverted-primary-interactive-color,
|
|
304
|
+
var(--hx-color-text-on-primary, #0d1825)
|
|
305
|
+
);
|
|
236
306
|
}
|
|
237
307
|
|
|
238
|
-
/*
|
|
308
|
+
/* Danger inverted — sister to primary. Hover/pressed lift to
|
|
309
|
+
action.danger.bg-inverted-hover (error-400, #FC7264). Same foreground
|
|
310
|
+
contract: text.inverse fails in light mode (white on light red ≈ 2.6:1);
|
|
311
|
+
pin to text.on-error (neutral-900, no dark-mode flip) for 6.58:1 in both
|
|
312
|
+
modes. Same active-bg → hover-bg → semantic fallback chain as primary. */
|
|
313
|
+
:host([inverted]) .button--danger:hover,
|
|
314
|
+
:host([inverted]) .button--danger:active {
|
|
315
|
+
--hx-button-bg: var(
|
|
316
|
+
--hx-button-active-bg,
|
|
317
|
+
var(--hx-button-hover-bg, var(--hx-color-action-danger-bg-inverted-hover, #fc7264))
|
|
318
|
+
);
|
|
319
|
+
color: var(
|
|
320
|
+
--hx-button-inverted-danger-interactive-color,
|
|
321
|
+
var(--hx-color-text-on-error, #0d1825)
|
|
322
|
+
);
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
/* Secondary inverted — white border and translucent hover fill */
|
|
239
326
|
:host([inverted]) .button--secondary {
|
|
240
|
-
--hx-button-border-color: var(--hx-
|
|
327
|
+
--hx-button-border-color: var(--hx-color-border-on-dark-strong, rgba(255, 255, 255, 0.7));
|
|
241
328
|
}
|
|
242
329
|
|
|
243
330
|
:host([inverted]) .button--secondary:hover {
|
|
244
|
-
--hx-button-bg: var(--hx-
|
|
331
|
+
--hx-button-bg: var(--hx-color-border-on-dark-default, rgba(255, 255, 255, 0.3));
|
|
245
332
|
}
|
|
246
333
|
|
|
247
|
-
/* Tertiary inverted
|
|
334
|
+
/* Tertiary inverted — resting at subtle (10%) lifts to default (30%) on hover
|
|
335
|
+
so the runtime hover delta is visually distinct, not collapsed onto a
|
|
336
|
+
single token. */
|
|
248
337
|
:host([inverted]) .button--tertiary {
|
|
249
|
-
--hx-button-bg: var(--hx-
|
|
338
|
+
--hx-button-bg: var(--hx-color-border-on-dark-subtle, rgba(255, 255, 255, 0.1));
|
|
250
339
|
--hx-button-border-color: transparent;
|
|
251
340
|
}
|
|
252
341
|
|
|
253
342
|
:host([inverted]) .button--tertiary:hover {
|
|
254
|
-
--hx-button-bg: var(--hx-
|
|
343
|
+
--hx-button-bg: var(--hx-color-border-on-dark-default, rgba(255, 255, 255, 0.3));
|
|
255
344
|
}
|
|
256
345
|
|
|
257
|
-
/* Ghost inverted — transparent base,
|
|
346
|
+
/* Ghost inverted — transparent base, translucent hover bg */
|
|
258
347
|
:host([inverted]) .button--ghost {
|
|
259
348
|
--hx-button-bg: transparent;
|
|
260
349
|
--hx-button-border-color: transparent;
|
|
@@ -263,17 +352,17 @@ const y = f`
|
|
|
263
352
|
:host([inverted]) .button--ghost:hover {
|
|
264
353
|
--hx-button-bg: var(
|
|
265
354
|
--hx-button-inverted-ghost-hover-bg,
|
|
266
|
-
var(--hx-
|
|
355
|
+
var(--hx-color-border-on-dark-default, rgba(255, 255, 255, 0.3))
|
|
267
356
|
);
|
|
268
357
|
}
|
|
269
358
|
|
|
270
359
|
/* Outline inverted — white border */
|
|
271
360
|
:host([inverted]) .button--outline {
|
|
272
|
-
--hx-button-border-color: var(--hx-
|
|
361
|
+
--hx-button-border-color: var(--hx-color-border-on-dark-strong, rgba(255, 255, 255, 0.7));
|
|
273
362
|
}
|
|
274
363
|
|
|
275
364
|
:host([inverted]) .button--outline:hover {
|
|
276
|
-
--hx-button-bg: var(--hx-
|
|
365
|
+
--hx-button-bg: var(--hx-color-border-on-dark-default, rgba(255, 255, 255, 0.3));
|
|
277
366
|
}
|
|
278
367
|
|
|
279
368
|
/* ─── Prefix / Suffix / Label ─── */
|
|
@@ -301,6 +390,16 @@ const y = f`
|
|
|
301
390
|
border: 2px solid ButtonText;
|
|
302
391
|
}
|
|
303
392
|
|
|
393
|
+
.button:hover {
|
|
394
|
+
/* Hover affordance must survive in HC. Highlight/HighlightText is the
|
|
395
|
+
OS-level "selected" pair, mirroring the forcedColorsInteractive mixin's
|
|
396
|
+
hover contract — kept inline since this component owns its bespoke HC
|
|
397
|
+
block (XOR rule). */
|
|
398
|
+
background-color: Highlight;
|
|
399
|
+
color: HighlightText;
|
|
400
|
+
border-color: Highlight;
|
|
401
|
+
}
|
|
402
|
+
|
|
304
403
|
.button:focus-visible {
|
|
305
404
|
outline: 3px solid Highlight;
|
|
306
405
|
outline-offset: 2px;
|
|
@@ -323,12 +422,12 @@ const y = f`
|
|
|
323
422
|
}
|
|
324
423
|
}
|
|
325
424
|
`;
|
|
326
|
-
var
|
|
327
|
-
for (var o = i > 1 ? void 0 : i ?
|
|
425
|
+
var y = Object.defineProperty, k = Object.getOwnPropertyDescriptor, n = (t, r, h, i) => {
|
|
426
|
+
for (var o = i > 1 ? void 0 : i ? k(r, h) : r, l = t.length - 1, b; l >= 0; l--)
|
|
328
427
|
(b = t[l]) && (o = (i ? b(r, h, o) : b(o)) || o);
|
|
329
|
-
return i && o &&
|
|
428
|
+
return i && o && y(r, h, o), o;
|
|
330
429
|
};
|
|
331
|
-
let e = class extends
|
|
430
|
+
let e = class extends g(x) {
|
|
332
431
|
constructor() {
|
|
333
432
|
super(...arguments), this.variant = "primary", this.size = "md", this.disabled = !1, this.loading = !1, this.type = "button", this.href = void 0, this.target = void 0, this.name = void 0, this.value = void 0, this.full = !1, this.inverted = !1, this.accessibleLabel = "", this._emptySlotWarnEmitted = !1;
|
|
334
433
|
}
|
|
@@ -359,7 +458,7 @@ let e = class extends m(g) {
|
|
|
359
458
|
updated(t) {
|
|
360
459
|
if (super.updated(t), t.has("variant")) {
|
|
361
460
|
const r = [...e._VALID_VARIANTS];
|
|
362
|
-
r.includes(this.variant) || (
|
|
461
|
+
r.includes(this.variant) || (p(
|
|
363
462
|
"hx-button",
|
|
364
463
|
`Invalid variant "${this.variant}". Expected one of: ${r.join(", ")}. Clamping to "primary".`
|
|
365
464
|
), this.variant = "primary");
|
|
@@ -398,7 +497,7 @@ let e = class extends m(g) {
|
|
|
398
497
|
* @internal
|
|
399
498
|
*/
|
|
400
499
|
_renderSpinner() {
|
|
401
|
-
return
|
|
500
|
+
return d`
|
|
402
501
|
<svg
|
|
403
502
|
class="button__spinner"
|
|
404
503
|
part="spinner"
|
|
@@ -430,7 +529,7 @@ let e = class extends m(g) {
|
|
|
430
529
|
* @internal
|
|
431
530
|
*/
|
|
432
531
|
_renderInner() {
|
|
433
|
-
return
|
|
532
|
+
return d`
|
|
434
533
|
${this.loading ? this._renderSpinner() : s}
|
|
435
534
|
<span part="prefix" class="button__prefix">
|
|
436
535
|
<slot name="prefix"></slot>
|
|
@@ -451,12 +550,12 @@ let e = class extends m(g) {
|
|
|
451
550
|
[`button--${this.size}`]: !0,
|
|
452
551
|
"button--loading": this.loading
|
|
453
552
|
};
|
|
454
|
-
return this.href !== void 0 ?
|
|
553
|
+
return this.href !== void 0 ? d`
|
|
455
554
|
<a
|
|
456
555
|
part="button"
|
|
457
|
-
class=${
|
|
458
|
-
href=${this.disabled || this.loading ? s :
|
|
459
|
-
target=${
|
|
556
|
+
class=${c(t)}
|
|
557
|
+
href=${this.disabled || this.loading ? s : u(this.href)}
|
|
558
|
+
target=${u(this.target)}
|
|
460
559
|
rel=${this.target === "_blank" ? "noopener noreferrer" : s}
|
|
461
560
|
aria-label=${this._effectiveLabel || s}
|
|
462
561
|
aria-disabled=${this.disabled ? "true" : s}
|
|
@@ -466,10 +565,10 @@ let e = class extends m(g) {
|
|
|
466
565
|
>
|
|
467
566
|
${this._renderInner()}
|
|
468
567
|
</a>
|
|
469
|
-
` :
|
|
568
|
+
` : d`
|
|
470
569
|
<button
|
|
471
570
|
part="button"
|
|
472
|
-
class=${
|
|
571
|
+
class=${c(t)}
|
|
473
572
|
?disabled=${this.disabled}
|
|
474
573
|
type=${this.type}
|
|
475
574
|
aria-label=${this._effectiveLabel || s}
|
|
@@ -481,7 +580,7 @@ let e = class extends m(g) {
|
|
|
481
580
|
`;
|
|
482
581
|
}
|
|
483
582
|
};
|
|
484
|
-
e.styles = [
|
|
583
|
+
e.styles = [m];
|
|
485
584
|
e.formAssociated = !0;
|
|
486
585
|
e._VALID_VARIANTS = [
|
|
487
586
|
"primary",
|
|
@@ -528,9 +627,9 @@ n([
|
|
|
528
627
|
a({ type: String, attribute: "accessible-label" })
|
|
529
628
|
], e.prototype, "accessibleLabel", 2);
|
|
530
629
|
e = n([
|
|
531
|
-
|
|
630
|
+
f("hx-button")
|
|
532
631
|
], e);
|
|
533
632
|
export {
|
|
534
633
|
e as H
|
|
535
634
|
};
|
|
536
|
-
//# sourceMappingURL=hx-button-
|
|
635
|
+
//# sourceMappingURL=hx-button-9OUjJnk7.js.map
|