@helixui/library 3.2.0-next.91 → 3.2.0-next.94
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 +1 -1
- package/dist/components/hx-accordion/hx-accordion-item.styles.d.ts.map +1 -1
- package/dist/components/hx-accordion/index.js +1 -1
- package/dist/components/hx-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.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-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/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/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/index.js +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/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-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 +94 -149
- package/dist/css/helix-core.css +16 -12
- package/dist/css/helix-data.css +7 -14
- package/dist/css/helix-feedback.css +4 -5
- package/dist/css/helix-forms.css +42 -52
- package/dist/css/helix-layout.css +2 -8
- package/dist/css/helix-navigation.css +12 -33
- package/dist/css/helix-overlay.css +3 -12
- package/dist/css/helix-tokens.css +16 -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 +12 -2
- package/dist/css/hx-card.css +1 -4
- package/dist/css/hx-checkbox.css +2 -2
- package/dist/css/hx-clinical-status.css +2 -4
- package/dist/css/hx-code-snippet.css +4 -4
- package/dist/css/hx-color-picker.css +3 -13
- package/dist/css/hx-combobox.css +4 -4
- 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 +1 -1
- 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 +2 -2
- package/dist/css/hx-side-nav.css +4 -4
- 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 +4 -4
- package/dist/css/hx-textarea.css +2 -2
- package/dist/css/hx-time-picker.css +3 -3
- 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 +27 -25
- package/dist/index.js +42 -42
- 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-ebUV8KhT.js → hx-button-D3gC-OJb.js} +13 -3
- package/dist/shared/hx-button-D3gC-OJb.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-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-CJrFeyz0.js} +5 -5
- package/dist/shared/{hx-code-snippet-CJ0FbQYG.js.map → hx-code-snippet-CJrFeyz0.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-M1yregCS.js} +5 -5
- package/dist/shared/{hx-combobox-DaA5dBC4.js.map → hx-combobox-M1yregCS.js.map} +1 -1
- 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-B4L_Nkm-.js} +11 -11
- package/dist/shared/{hx-file-upload-zTDbjsRw.js.map → hx-file-upload-B4L_Nkm-.js.map} +1 -1
- 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-CvTxO3Sa.js → hx-nav-item-DH2tXcj1.js} +6 -6
- package/dist/shared/{hx-nav-item-CvTxO3Sa.js.map → hx-nav-item-DH2tXcj1.js.map} +1 -1
- 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-zfIRr9qM.js} +3 -3
- package/dist/shared/{hx-select-vgaBo1Ai.js.map → hx-select-zfIRr9qM.js.map} +1 -1
- 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-ClrrmoE1.js → hx-text-input-Bn7Gn8CI.js} +5 -5
- package/dist/shared/{hx-text-input-ClrrmoE1.js.map → hx-text-input-Bn7Gn8CI.js.map} +1 -1
- 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/figma-inventory.json +3 -3
- package/package.json +2 -2
- package/dist/shared/hx-accordion-cnKg4_la.js.map +0 -1
- package/dist/shared/hx-button-ebUV8KhT.js.map +0 -1
- package/dist/shared/hx-card-CU1QnjNb.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-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-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-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-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-top-nav-CchPYaiV.js.map +0 -1
- package/dist/shared/hx-tree-item-DtMC3DTa.js.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hx-td-DnnEMIuA.js","sources":["../../src/components/hx-table/hx-table.styles.ts","../../src/components/hx-table/hx-table.ts","../../src/components/hx-table/hx-thead.ts","../../src/components/hx-table/hx-tbody.ts","../../src/components/hx-table/hx-tfoot.ts","../../src/components/hx-table/hx-tr.ts","../../src/components/hx-table/hx-th.ts","../../src/components/hx-table/hx-td.ts"],"sourcesContent":["import { css } from 'lit';\n\nexport const helixTableStyles = css`\n :host {\n display: block;\n overflow-x: auto;\n font-family: var(--hx-table-font-family, var(--hx-font-family-sans, sans-serif));\n font-size: var(--hx-font-size-sm, 0.875rem);\n }\n\n /* ─── Scroll Wrapper ─── */\n\n .table-wrapper {\n min-width: 0;\n width: 100%;\n }\n\n /* ─── Table ─── */\n\n table {\n border-collapse: collapse;\n border-spacing: 0;\n }\n\n :host([full-width]) table {\n width: 100%;\n }\n\n /* ─── Caption ─── */\n\n caption {\n caption-side: top;\n text-align: start;\n padding: var(--hx-space-2, 0.5rem) var(--hx-space-4, 1rem);\n font-weight: var(--hx-font-weight-semibold, 600);\n color: var(--hx-table-header-color, var(--hx-color-text-strong, #202b39));\n font-size: var(--hx-font-size-md, 1rem);\n }\n\n /* ─── Slotted sub-component styling ─── */\n\n /*\n * ::slotted() only matches DIRECT slot assignees. hx-table's direct\n * slot children are hx-thead, hx-tbody, and hx-tfoot — never hx-tr,\n * hx-th, or hx-td. CSS custom properties inherit through shadow DOM\n * boundaries, so variables set on section elements cascade to their\n * slotted row and cell descendants automatically.\n */\n\n /* Header background via CSS vars that cascade through display:contents */\n ::slotted(hx-thead) {\n --_hx-table-cell-bg: var(--hx-table-header-bg, var(--hx-color-surface-raised, #f5f8f3));\n }\n\n /* Striped variant: set stripe signal on hx-tbody (direct slotted child) so hx-tbody can apply to even rows */\n :host([variant='striped']) ::slotted(hx-tbody) {\n --_hx-table-row-stripe-bg: var(--hx-table-stripe-bg, var(--hx-color-surface-raised, #f5f8f3));\n }\n\n /* Hover variant: set hover bg variable on direct slotted section elements */\n :host([variant='hover']) ::slotted(hx-tbody),\n :host([variant='hover']) ::slotted(hx-thead),\n :host([variant='striped']) ::slotted(hx-tbody),\n :host([variant='striped']) ::slotted(hx-thead),\n :host([variant='default']) ::slotted(hx-tbody),\n :host([variant='default']) ::slotted(hx-thead) {\n --_hx-table-row-hover-bg: var(--hx-table-row-hover-bg, var(--hx-color-surface-raised, #f5f8f3));\n }\n\n /* Compact variant: reduced padding signal set on section elements that cascade to cells */\n :host([variant='compact']) ::slotted(hx-thead),\n :host([variant='compact']) ::slotted(hx-tbody),\n :host([variant='compact']) ::slotted(hx-tfoot) {\n --_hx-table-cell-padding: var(--hx-space-2, 0.5rem) var(--hx-space-3, 0.75rem);\n }\n\n /* ─── Sticky Header ─── */\n\n :host([sticky-header]) ::slotted(hx-thead) {\n --_hx-table-th-position: sticky;\n --_hx-table-th-top: 0;\n --_hx-table-th-z-index: 1;\n --_hx-table-th-bg: var(--hx-table-header-bg, var(--hx-color-surface-raised, #f5f8f3));\n }\n\n /* ─── Focus ─── */\n\n ::slotted(:focus-visible) {\n outline: var(--hx-focus-ring-width, 2px) solid var(--hx-focus-ring-color, #0f7078);\n outline-offset: var(--hx-focus-ring-offset, -2px);\n }\n\n /* ─── Responsive Mobile Card Layout ─── */\n\n @media (max-width: 768px) {\n .table-wrapper {\n overflow-x: visible;\n }\n }\n\n /* ─── Reduced Motion ─── */\n\n @media (prefers-reduced-motion: reduce) {\n ::slotted(*) {\n transition: none !important;\n }\n }\n\n /* ─── Forced Colors (Windows High Contrast) ─── */\n\n @media (forced-colors: active) {\n table {\n border: 1px solid CanvasText;\n }\n }\n`;\n\n/**\n * Styles shared by sub-components (hx-th, hx-td) for cell layout.\n * Exported so sub-components can import them directly.\n */\nexport const helixTableCellBaseStyles = css`\n :host {\n display: contents;\n }\n`;\n\nexport const helixTableRowBaseStyles = css`\n :host {\n display: contents;\n }\n`;\n\nexport const helixTableSectionBaseStyles = css`\n :host {\n display: contents;\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 } from '../../base/index.js';\nimport { helixTableStyles } from './hx-table.styles.js';\nimport { forcedColorsSurface } from '../../styles/forced-colors.js';\nimport { devWarn } from '../../utils/dev-warn.js';\n\n/**\n * A semantic table container with variant styling and accessibility support.\n * Compose with `hx-thead`, `hx-tbody`, `hx-tfoot`, `hx-tr`, `hx-th`, and `hx-td`.\n *\n * @summary Semantic HTML table with variant styling, sticky header, and responsive layout.\n *\n * @tag hx-table\n *\n * @slot - Default slot for `hx-thead`, `hx-tbody`, and `hx-tfoot` sub-components.\n * @slot caption - Custom caption content rendered inside the `<caption>` element.\n *\n * @csspart table - The `<table>` element.\n * @csspart caption - The `<caption>` element.\n *\n * @cssprop [--hx-table-border-color=var(--hx-color-neutral-200, #D6DBD5)] - Cell border color.\n * @cssprop [--hx-table-header-bg=var(--hx-color-neutral-50, #F5F8F3)] - Header row background.\n * @cssprop [--hx-table-header-color=var(--hx-color-neutral-700, #313E4B)] - Header text color.\n * @cssprop [--hx-table-cell-color=var(--hx-color-neutral-900, #0D1825)] - Cell text color.\n * @cssprop [--hx-table-row-hover-bg=var(--hx-color-neutral-50, #F5F8F3)] - Row hover background.\n * @cssprop [--hx-table-stripe-bg=var(--hx-color-neutral-50, #F5F8F3)] - Striped row background.\n * @cssprop [--hx-table-font-family=var(--hx-font-family-sans)] - CSS custom property.\n * @cssprop [--hx-font-family-sans] - Font family.\n * @cssprop [--hx-font-size-sm] - Font size.\n * @cssprop [--hx-space-2] - Spacing token.\n * @cssprop [--hx-space-4] - Spacing token.\n * @cssprop [--hx-font-weight-semibold] - Font weight.\n * @cssprop [--hx-color-neutral-700] - Color.\n * @cssprop [--hx-font-size-md] - Font size.\n * @cssprop [--hx-color-neutral-50] - Color.\n * @cssprop [--hx-space-3] - Spacing token.\n * @cssprop [--hx-focus-ring-width] - Width.\n * @cssprop [--hx-focus-ring-color] - Color.\n * @cssprop [--hx-color-primary-500] - Color.\n * @cssprop [--hx-focus-ring-offset] - CSS custom property.\n */\n@customElement('hx-table')\nexport class HelixTable extends HelixElement {\n static override styles = [helixTableStyles, forcedColorsSurface];\n\n // ─── Public Properties ───\n\n /**\n * Accessible name for the table (WCAG 4.1.2 requirement).\n * Exposed via `aria-label` on the `<table>` element.\n * @attr label\n */\n @property({ type: String })\n label = '';\n\n /**\n * Visible caption text. When set, renders a `<caption>` element.\n * Use the `caption` slot for richer caption content.\n * @attr caption\n */\n @property({ type: String })\n caption = '';\n\n /**\n * Visual variant that controls row styling.\n * @attr variant\n */\n @property({ type: String, reflect: true })\n variant: 'default' | 'striped' | 'hover' | 'compact' = 'default';\n\n /**\n * When true, the header row stays fixed while the table body scrolls.\n * @attr sticky-header\n */\n @property({ type: Boolean, reflect: true, attribute: 'sticky-header' })\n stickyHeader = false;\n\n /**\n * When true, the table expands to fill 100% of its container width.\n * @attr full-width\n */\n @property({ type: Boolean, reflect: true, attribute: 'full-width' })\n fullWidth = true;\n\n // ─── Internal State ───\n\n /** @internal */\n @state() private _hasCaptionSlot = false;\n\n // ─── Lifecycle ───\n\n override connectedCallback(): void {\n super.connectedCallback();\n this._hasCaptionSlot = this.querySelector('[slot=\"caption\"]') !== null;\n }\n\n override firstUpdated(changedProperties: PropertyValues<this>): void {\n super.firstUpdated(changedProperties);\n // WCAG 4.1.2: warn when neither label nor caption provides an accessible name.\n // A table without an accessible name cannot be identified by screen reader users.\n if (!this.label && !this.caption && !this._hasCaptionSlot) {\n devWarn(\n 'hx-table',\n 'No accessible name provided. Set the `label` or `caption` attribute, or use the `caption` slot, so screen readers can identify this table (WCAG 4.1.2 Name, Role, Value).',\n );\n }\n }\n\n override willUpdate(changed: PropertyValues<this>): void {\n if (changed.has('label') && !this.label && changed.get('label') !== undefined) {\n devWarn(\n 'hx-table',\n 'No accessible name provided. Set the `label` attribute so screen readers can identify this table (WCAG 4.1.2).',\n );\n }\n }\n\n /** @internal */\n private _onCaptionSlotChange(e: Event): void {\n const slot = e.target as HTMLSlotElement;\n this._hasCaptionSlot = slot.assignedNodes({ flatten: true }).length > 0;\n }\n\n // ─── Render ───\n\n override render() {\n const hasCaption = this.caption || this._hasCaptionSlot;\n\n return html`\n <div class=\"table-wrapper\">\n <!-- role=\"table\" is required: sub-components use display:contents which can confuse assistive technology in Shadow DOM -->\n <table part=\"table\" role=\"table\" aria-label=${this.label || nothing}>\n ${hasCaption\n ? html`<caption part=\"caption\">\n <slot name=\"caption\" @slotchange=${this._onCaptionSlotChange}>${this.caption}</slot>\n </caption>`\n : nothing}\n <slot></slot>\n </table>\n </div>\n `;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'hx-table': HelixTable;\n }\n}\n","import { html } from 'lit';\nimport '../../utilities/document-token-adoption.js';\nimport { customElement } from 'lit/decorators.js';\nimport { HelixElement } from '../../base/index.js';\nimport { helixTableSectionBaseStyles } from './hx-table.styles.js';\n\n/**\n * Semantic table head section. Must be a direct child of `hx-table`.\n * Contains `hx-tr` rows with `hx-th` header cells.\n *\n * @summary Table head section (`<thead>`) for use inside `hx-table`.\n *\n * @tag hx-thead\n *\n * @slot - Default slot for `hx-tr` elements.\n *\n * @csspart thead - The `<thead>` element.\n */\n@customElement('hx-thead')\nexport class HelixTableHead extends HelixElement {\n static override styles = [helixTableSectionBaseStyles];\n\n override render() {\n return html`<thead part=\"thead\" role=\"rowgroup\">\n <slot></slot>\n </thead>`;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'hx-thead': HelixTableHead;\n }\n}\n","import { html, css } from 'lit';\nimport '../../utilities/document-token-adoption.js';\nimport { customElement } from 'lit/decorators.js';\nimport { HelixElement } from '../../base/index.js';\n\n/**\n * Semantic table body section. Must be a direct child of `hx-table`.\n * Contains `hx-tr` rows with `hx-td` data cells.\n *\n * @summary Table body section (`<tbody>`) for use inside `hx-table`.\n *\n * @tag hx-tbody\n *\n * @slot - Default slot for `hx-tr` elements.\n *\n * @csspart tbody - The `<tbody>` element.\n */\n@customElement('hx-tbody')\nexport class HelixTableBody extends HelixElement {\n static override styles = [\n css`\n :host {\n display: contents;\n }\n\n /*\n * Striped rows: only applies when the parent hx-table sets\n * --_hx-table-row-stripe-bg (via variant=\"striped\"). Falls back\n * to transparent so non-striped variants are unaffected.\n */\n ::slotted(hx-tr:nth-child(even)) {\n --_hx-table-row-bg: var(--_hx-table-row-stripe-bg, transparent);\n }\n `,\n ];\n\n override render() {\n return html`<tbody part=\"tbody\" role=\"rowgroup\">\n <slot></slot>\n </tbody>`;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'hx-tbody': HelixTableBody;\n }\n}\n","import { html } from 'lit';\nimport '../../utilities/document-token-adoption.js';\nimport { customElement } from 'lit/decorators.js';\nimport { HelixElement } from '../../base/index.js';\nimport { helixTableSectionBaseStyles } from './hx-table.styles.js';\n\n/**\n * Semantic table foot section. Must be a direct child of `hx-table`.\n * Typically contains summary or totals rows.\n *\n * @summary Table foot section (`<tfoot>`) for use inside `hx-table`.\n *\n * @tag hx-tfoot\n *\n * @slot - Default slot for `hx-tr` elements.\n *\n * @csspart tfoot - The `<tfoot>` element.\n */\n@customElement('hx-tfoot')\nexport class HelixTableFoot extends HelixElement {\n static override styles = [helixTableSectionBaseStyles];\n\n override render() {\n return html`<tfoot part=\"tfoot\" role=\"rowgroup\">\n <slot></slot>\n </tfoot>`;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'hx-tfoot': HelixTableFoot;\n }\n}\n","import { html, nothing, css } from 'lit';\nimport '../../utilities/document-token-adoption.js';\nimport { customElement, property } from 'lit/decorators.js';\nimport { HelixElement } from '../../base/index.js';\n\n/**\n * Semantic table row. Must be a child of `hx-thead`, `hx-tbody`, or `hx-tfoot`.\n * Contains `hx-th` or `hx-td` cells.\n *\n * @summary Table row (`<tr>`) for use inside `hx-thead`, `hx-tbody`, or `hx-tfoot`.\n *\n * @tag hx-tr\n *\n * @slot - Default slot for `hx-th` and `hx-td` elements.\n *\n * @csspart row - The `<tr>` element.\n */\n@customElement('hx-tr')\nexport class HelixTableRow extends HelixElement {\n static override styles = [\n css`\n :host {\n display: contents;\n }\n\n tr {\n background-color: var(--_hx-table-row-bg, transparent);\n transition: background-color var(--hx-transition-fast, 150ms ease);\n }\n\n tr:hover {\n background-color: var(--_hx-table-row-hover-bg, var(--hx-table-row-hover-bg, transparent));\n }\n\n :host([selected]) tr {\n background-color: var(--hx-table-row-selected-bg, var(--hx-color-primary-50, #ebf8f8));\n }\n\n :host([disabled]) tr {\n opacity: 0.5;\n pointer-events: none;\n }\n\n @media (prefers-reduced-motion: reduce) {\n tr {\n transition: none;\n }\n }\n `,\n ];\n\n /**\n * When true, marks the row as selected and applies selected styling.\n * @attr selected\n */\n @property({ type: Boolean, reflect: true })\n selected = false;\n\n /**\n * When true, the row is visually disabled and non-interactive.\n * @attr disabled\n */\n @property({ type: Boolean, reflect: true })\n disabled = false;\n\n override render() {\n return html`\n <tr\n part=\"row\"\n role=\"row\"\n aria-selected=${this.selected ? 'true' : nothing}\n aria-disabled=${this.disabled ? 'true' : nothing}\n >\n <slot></slot>\n </tr>\n `;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'hx-tr': HelixTableRow;\n }\n}\n","import { html, nothing, css } from 'lit';\nimport '../../utilities/document-token-adoption.js';\nimport { customElement, property } from 'lit/decorators.js';\nimport { ifDefined } from 'lit/directives/if-defined.js';\nimport { HelixElement } from '../../base/index.js';\n\n/**\n * Detail type for `hx-sort` events dispatched from `hx-th`.\n */\nexport interface HxTableSortDetail {\n direction: 'asc' | 'desc';\n}\n\n/**\n * Semantic table header cell. Must be a child of `hx-tr`.\n * Supports sortable columns with accessible sort state.\n *\n * @summary Table header cell (`<th>`) with optional sort support.\n *\n * @tag hx-th\n *\n * @slot - Default slot for header label content.\n *\n * @fires {CustomEvent<HxTableSortDetail>} hx-sort - Dispatched when a sortable header is activated.\n *\n * @csspart header - The `<th>` element.\n * @csspart sort-icon - The sort indicator icon `<span>` inside sortable headers.\n */\n@customElement('hx-th')\nexport class HelixTableHeader extends HelixElement {\n static override styles = [\n css`\n :host {\n display: contents;\n }\n\n th {\n padding: var(--_hx-table-cell-padding, var(--hx-space-3, 0.75rem) var(--hx-space-4, 1rem));\n text-align: left;\n font-weight: var(--hx-font-weight-semibold, 600);\n color: var(--hx-table-header-color, var(--hx-color-neutral-700, #313e4b));\n background-color: var(\n --_hx-table-cell-bg,\n var(--hx-table-header-bg, var(--hx-color-neutral-50, #f5f8f3))\n );\n border-bottom: var(--hx-border-width-thin, 1px) solid\n var(--hx-table-border-color, var(--hx-color-neutral-200, #d6dbd5));\n white-space: nowrap;\n vertical-align: middle;\n position: var(--_hx-table-th-position, static);\n top: var(--_hx-table-th-top, auto);\n z-index: var(--_hx-table-th-z-index, auto);\n }\n\n :host([sortable]) th {\n cursor: pointer;\n }\n\n /* ─── Sort Button ─── */\n\n .sort-btn {\n display: inline-flex;\n align-items: center;\n gap: var(--hx-space-1, 0.25rem);\n background: none;\n border: none;\n padding: 0;\n font: inherit;\n font-weight: inherit;\n color: inherit;\n cursor: pointer;\n white-space: nowrap;\n width: 100%;\n }\n\n .sort-btn:focus-visible {\n outline: var(--hx-focus-ring-width, 2px) solid\n var(--hx-focus-ring-color, var(--hx-color-primary-500, #429797));\n outline-offset: var(--hx-focus-ring-offset, 2px);\n border-radius: var(--hx-border-radius-sm, 2px);\n }\n\n /* ─── Sort Icon ─── */\n\n .sort-icon {\n display: inline-flex;\n align-items: center;\n flex-shrink: 0;\n width: 1em;\n height: 1em;\n opacity: 0.4;\n transition:\n opacity var(--hx-transition-fast, 150ms ease),\n transform var(--hx-transition-fast, 150ms ease);\n }\n\n .sort-icon--active {\n opacity: 1;\n color: var(--hx-color-primary-500, #429797);\n }\n\n .sort-icon--desc {\n transform: rotate(180deg);\n }\n\n @media (prefers-reduced-motion: reduce) {\n .sort-icon {\n transition: none;\n }\n }\n\n /* ─── Mobile card layout ─── */\n\n @media (max-width: 768px) {\n /*\n * Visually hide the header cell on mobile while keeping it in the\n * accessibility tree. Screen readers can then associate column\n * headers with data cells via the semantic table structure\n * (scope=\"col\", role=\"columnheader\"), satisfying WCAG 2.1 AA.\n * Using display:none would remove headers from the a11y tree entirely.\n */\n th {\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 `,\n ];\n\n /**\n * When true, the header renders a sort button and emits `hx-sort` on activation.\n * @attr sortable\n */\n @property({ type: Boolean, reflect: true })\n sortable = false;\n\n /**\n * Current sort direction. Reflected for CSS targeting.\n * @attr sort-direction\n */\n @property({ type: String, reflect: true, attribute: 'sort-direction' })\n sortDirection: 'asc' | 'desc' | 'none' = 'none';\n\n /**\n * The `scope` attribute for the underlying `<th>` element.\n * @attr scope\n */\n @property({ type: String })\n scope: 'col' | 'row' | 'colgroup' | 'rowgroup' = 'col';\n\n /**\n * Number of columns this header spans.\n * @attr colspan\n */\n @property({ type: Number })\n colspan = 0;\n\n /**\n * Number of rows this header spans.\n * @attr rowspan\n */\n @property({ type: Number })\n rowspan = 0;\n\n // ─── Event Handlers ───\n\n /** @internal */\n private _handleSort(): void {\n const next: 'asc' | 'desc' = this.sortDirection === 'asc' ? 'desc' : 'asc';\n this.sortDirection = next;\n this.dispatchEvent(\n new CustomEvent<HxTableSortDetail>('hx-sort', {\n bubbles: true,\n composed: true,\n detail: { direction: next },\n }),\n );\n }\n\n // ─── Render Helpers ───\n\n /** @internal */\n private _renderSortIcon() {\n const isActive = this.sortDirection !== 'none';\n const iconClass = [\n 'sort-icon',\n isActive ? 'sort-icon--active' : '',\n this.sortDirection === 'desc' ? 'sort-icon--desc' : '',\n ]\n .filter(Boolean)\n .join(' ');\n\n return html`\n <span part=\"sort-icon\" class=${iconClass} aria-hidden=\"true\">\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 16 16\"\n fill=\"currentColor\"\n width=\"16\"\n height=\"16\"\n >\n <path d=\"M8 3L5 7h6L8 3zM8 13l3-4H5l3 4z\" fill-rule=\"evenodd\" />\n </svg>\n </span>\n `;\n }\n\n /** @internal */\n private _ariaSort(): 'ascending' | 'descending' | 'none' | typeof nothing {\n if (!this.sortable) return nothing;\n if (this.sortDirection === 'asc') return 'ascending';\n if (this.sortDirection === 'desc') return 'descending';\n return 'none';\n }\n\n /** @internal */\n private _sortLabel(): string {\n if (this.sortDirection === 'asc') return 'Sort descending';\n if (this.sortDirection === 'desc') return 'Sort ascending';\n return 'Sort';\n }\n\n override render() {\n return html`\n <th\n part=\"header\"\n role=\"columnheader\"\n scope=${this.scope}\n colspan=${ifDefined(this.colspan > 0 ? this.colspan : undefined)}\n rowspan=${ifDefined(this.rowspan > 0 ? this.rowspan : undefined)}\n aria-sort=${this._ariaSort()}\n >\n ${this.sortable\n ? html`\n <button class=\"sort-btn\" @click=${this._handleSort} aria-label=${this._sortLabel()}>\n <slot></slot>\n ${this._renderSortIcon()}\n </button>\n `\n : html`<slot></slot>`}\n </th>\n `;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'hx-th': HelixTableHeader;\n }\n}\n","import { html, css } from 'lit';\nimport '../../utilities/document-token-adoption.js';\nimport { customElement, property } from 'lit/decorators.js';\nimport { ifDefined } from 'lit/directives/if-defined.js';\nimport { HelixElement } from '../../base/index.js';\n\n/**\n * Semantic table data cell. Must be a child of `hx-tr`.\n *\n * @summary Table data cell (`<td>`) for use inside `hx-tr`.\n *\n * @tag hx-td\n *\n * @slot - Default slot for cell content.\n *\n * @csspart cell - The `<td>` element.\n *\n * @cssprop [--hx-table-cell-color=var(--hx-color-neutral-900, #0D1825)] - Cell text color.\n */\n@customElement('hx-td')\nexport class HelixTableCell extends HelixElement {\n static override styles = [\n css`\n :host {\n display: contents;\n }\n\n td {\n padding: var(--_hx-table-cell-padding, var(--hx-space-3, 0.75rem) var(--hx-space-4, 1rem));\n text-align: left;\n color: var(--hx-table-cell-color, var(--hx-color-neutral-900, #0d1825));\n border-bottom: var(--hx-border-width-thin, 1px) solid\n var(--hx-table-border-color, var(--hx-color-neutral-200, #d6dbd5));\n vertical-align: middle;\n }\n\n :host([align='center']) td {\n text-align: center;\n }\n\n :host([align='right']) td {\n text-align: right;\n }\n\n td:focus-visible {\n outline: var(--hx-focus-ring-width, 2px) solid\n var(--hx-focus-ring-color, var(--hx-color-primary-500, #429797));\n outline-offset: var(--hx-focus-ring-offset, -2px);\n border-radius: var(--hx-border-radius-sm, 2px);\n }\n\n /* ─── Mobile card layout ─── */\n\n @media (max-width: 768px) {\n :host {\n display: block;\n }\n\n td {\n display: block;\n text-align: right;\n padding: var(--hx-space-2, 0.5rem) var(--hx-space-3, 0.75rem);\n border-bottom: none;\n position: relative;\n }\n\n td::before {\n content: attr(data-label);\n font-weight: var(--hx-font-weight-semibold, 600);\n float: left;\n color: var(--hx-table-header-color, var(--hx-color-neutral-700, #313e4b));\n }\n }\n `,\n ];\n\n /**\n * Horizontal alignment for cell content.\n * @attr align\n */\n @property({ type: String, reflect: true })\n align: 'left' | 'center' | 'right' = 'left';\n\n /**\n * Number of columns this cell spans.\n * @attr colspan\n */\n @property({ type: Number })\n colspan = 0;\n\n /**\n * Number of rows this cell spans.\n * @attr rowspan\n */\n @property({ type: Number })\n rowspan = 0;\n\n /**\n * Column header label for this cell. Forwarded as `data-label` on the native `<td>` for\n * the mobile card layout (`td::before { content: attr(data-label) }`) and as `aria-label`\n * so screen readers identify the column when the header row is hidden.\n * @attr label\n */\n @property({ type: String, attribute: 'label' })\n label = '';\n\n override render() {\n return html`\n <td\n part=\"cell\"\n role=\"cell\"\n data-label=${ifDefined(this.label || undefined)}\n colspan=${ifDefined(this.colspan > 0 ? this.colspan : undefined)}\n rowspan=${ifDefined(this.rowspan > 0 ? this.rowspan : undefined)}\n >\n <slot></slot>\n </td>\n `;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'hx-td': HelixTableCell;\n }\n}\n"],"names":["helixTableStyles","css","helixTableSectionBaseStyles","HelixTable","HelixElement","changedProperties","changed","slot","hasCaption","html","nothing","forcedColorsSurface","__decorateClass","property","state","customElement","HelixTableHead","HelixTableBody","HelixTableFoot","HelixTableRow","HelixTableHeader","next","iconClass","ifDefined","HelixTableCell"],"mappings":"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"}
|
|
@@ -87,17 +87,17 @@ const T = (e) => {
|
|
|
87
87
|
/* Border */
|
|
88
88
|
--_text-input-border-color: var(
|
|
89
89
|
--hx-text-input-border-color,
|
|
90
|
-
var(--hx-input-border-color, var(--hx-color-border-strong, #
|
|
90
|
+
var(--hx-input-border-color, var(--hx-color-border-strong, #66787b))
|
|
91
91
|
);
|
|
92
92
|
--_text-input-border-color-hover: var(
|
|
93
93
|
--hx-text-input-border-color-hover,
|
|
94
|
-
var(--hx-color-border-strong, #
|
|
94
|
+
var(--hx-color-border-strong, #66787b)
|
|
95
95
|
);
|
|
96
96
|
--_text-input-border-color-focus: var(
|
|
97
97
|
--hx-text-input-border-color-focus,
|
|
98
98
|
var(
|
|
99
99
|
--hx-input-focus-ring-color,
|
|
100
|
-
var(--hx-focus-ring-color, var(--hx-color-primary-
|
|
100
|
+
var(--hx-focus-ring-color, var(--hx-color-primary-600, #0f7078))
|
|
101
101
|
)
|
|
102
102
|
);
|
|
103
103
|
--_text-input-border-color-invalid: var(
|
|
@@ -126,7 +126,7 @@ const T = (e) => {
|
|
|
126
126
|
--hx-text-input-focus-ring-color,
|
|
127
127
|
var(
|
|
128
128
|
--hx-input-focus-ring-color,
|
|
129
|
-
var(--hx-focus-ring-color, var(--hx-color-primary-
|
|
129
|
+
var(--hx-focus-ring-color, var(--hx-color-primary-600, #0f7078))
|
|
130
130
|
)
|
|
131
131
|
);
|
|
132
132
|
--_text-input-focus-ring-width: var(
|
|
@@ -713,4 +713,4 @@ export {
|
|
|
713
713
|
T as F,
|
|
714
714
|
r as H
|
|
715
715
|
};
|
|
716
|
-
//# sourceMappingURL=hx-text-input-
|
|
716
|
+
//# sourceMappingURL=hx-text-input-Bn7Gn8CI.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hx-text-input-ClrrmoE1.js","sources":["../../src/mixins/FocusMixin.ts","../../src/components/hx-text-input/hx-text-input.styles.ts","../../src/components/hx-text-input/hx-text-input.ts"],"sourcesContent":["import { LitElement, type PropertyValues } from 'lit';\nimport { property } from 'lit/decorators.js';\n\n/**\n * Mixin constructor type — must use `any[]` args per TypeScript mixin requirements (TS2545).\n * @internal\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype Constructor<T = object> = new (...args: any[]) => T;\n\n/**\n * The public interface added by FocusMixin.\n * Consumers can use this type for typed references.\n *\n * @public\n */\nexport interface FocusMixinInterface {\n /** True when the component host has focus (including descendant focus). */\n readonly focused: boolean;\n /** True when focus arrived via keyboard (not pointer). */\n readonly focusedVisible: boolean;\n}\n\n/**\n * FocusMixin — standardized focus delegation for HELiX web components.\n *\n * Modeled after Lion's `FocusMixin` and Material Web's `mixinDelegatesAria`.\n * Provides:\n * - `_focusableNode` getter for subclasses to declare the inner focusable element\n * - `focused` reflected attribute as a styling hook for `:host([focused])`\n * - `focusedVisible` reflected attribute for keyboard-only focus rings\n * - Delegated `focus()` / `blur()` routing to the inner element\n * - Autofocus support after first render\n *\n * ### Usage\n *\n * ```ts\n * class MyInput extends FocusMixin(HelixElement) {\n * @query('input') private _input: HTMLInputElement | undefined;\n *\n * protected override get _focusableNode(): HTMLElement | null {\n * return this._input ?? null;\n * }\n * }\n * ```\n *\n * @param superClass - A Lit element constructor to mix into\n * @returns A new class with focus management capabilities\n *\n * @public\n */\nexport const FocusMixin = <T extends Constructor<LitElement>>(superClass: T) => {\n class FocusMixinClass extends superClass implements FocusMixinInterface {\n /**\n * True when the component or any of its descendants has focus.\n * Reflects to attribute `focused` for CSS selector use.\n *\n * @attr focused\n */\n @property({ type: Boolean, reflect: true })\n focused = false;\n\n /**\n * True when focus was reached via keyboard navigation (Tab / Shift+Tab)\n * rather than pointer interaction. Reflects to attribute `focused-visible`\n * for rendering keyboard-only focus rings.\n *\n * @attr focused-visible\n */\n @property({ type: Boolean, reflect: true, attribute: 'focused-visible' })\n focusedVisible = false;\n\n /** @internal — whether a `focus()` call was queued before first render */\n private _focusPending = false;\n\n /**\n * @internal — tracks whether the most recent interaction toward this\n * element was via pointer (true) or keyboard (false).\n *\n * Set to false on `pointerdown` so that the subsequent `focusin` can\n * determine it is not keyboard-initiated.\n */\n private _lastInteractionWasPointer = false;\n\n /**\n * Returns the inner focusable element that `focus()` and `blur()` will\n * delegate to. Subclasses MUST override this getter.\n *\n * @returns The inner focusable element, or `null` if not yet rendered.\n * @internal\n */\n protected get _focusableNode(): HTMLElement | null {\n return null;\n }\n\n /**\n * Delegates focus to the inner focusable element.\n * If the element has not yet rendered, queues the focus call for\n * `firstUpdated`.\n */\n override focus(options?: FocusOptions): void {\n const node = this._focusableNode;\n if (node !== null) {\n node.focus(options);\n } else {\n this._focusPending = true;\n }\n }\n\n /** Delegates blur to the inner focusable element. */\n override blur(): void {\n this._focusableNode?.blur();\n }\n\n override connectedCallback(): void {\n super.connectedCallback();\n this.addEventListener('focusin', this._handleFocusIn);\n this.addEventListener('focusout', this._handleFocusOut);\n this.addEventListener('pointerdown', this._handlePointerDown);\n this.addEventListener('keydown', this._handleKeyDown);\n }\n\n override disconnectedCallback(): void {\n super.disconnectedCallback();\n this.removeEventListener('focusin', this._handleFocusIn);\n this.removeEventListener('focusout', this._handleFocusOut);\n this.removeEventListener('pointerdown', this._handlePointerDown);\n this.removeEventListener('keydown', this._handleKeyDown);\n }\n\n override firstUpdated(changedProperties: PropertyValues): void {\n super.firstUpdated(changedProperties);\n\n // Honour the native `autofocus` attribute after the first render cycle\n if (this.hasAttribute('autofocus')) {\n this.focus();\n }\n\n // Flush any focus() call that arrived before the shadow DOM was stamped\n if (this._focusPending) {\n this._focusPending = false;\n this.focus();\n }\n }\n\n // ─── Private Event Handlers ────────────────────────────────────────────────\n\n /** @internal */\n private _handleFocusIn = (): void => {\n this.focused = true;\n // focusedVisible is true only when focus arrived via keyboard\n this.focusedVisible = !this._lastInteractionWasPointer;\n };\n\n /** @internal */\n private _handleFocusOut = (): void => {\n this.focused = false;\n this.focusedVisible = false;\n // Reset for the next interaction cycle\n this._lastInteractionWasPointer = false;\n };\n\n /**\n * Marks the next focusin as pointer-initiated.\n * @internal\n */\n private _handlePointerDown = (): void => {\n this._lastInteractionWasPointer = true;\n };\n\n /**\n * Ensures that keyboard navigation (Tab / Shift+Tab arriving from outside)\n * is correctly flagged as keyboard-initiated even when no prior `pointerdown`\n * fired on this element.\n *\n * This fires BEFORE `focusin` so the flag is in the correct state when\n * `_handleFocusIn` runs.\n * @internal\n */\n private _handleKeyDown = (): void => {\n this._lastInteractionWasPointer = false;\n };\n }\n\n return FocusMixinClass as unknown as T & Constructor<FocusMixinInterface>;\n};\n","import { css } from 'lit';\n\n/**\n * hx-text-input styles.\n *\n * Component-tier tokens introduced in 3.2.0 — every visual property exposes\n * `--hx-text-input-*` overrides while preserving backward-compatible\n * `--hx-input-*` aliases that earlier consumers may already use.\n *\n * Two-level var() fallback pattern is canonical:\n * var(--hx-text-input-{prop}, var(--hx-color-{semantic}, #hex))\n * Inner hex fallbacks track the \"precision cool\" palette (primary-600=#0F7078,\n * neutral-200=#D6DBD5, etc.) introduced in the same release.\n */\nexport const helixTextInputStyles = css`\n :host {\n display: block;\n\n /* ─── Component tokens (3.2.0) ──────────────────────────────────── */\n\n /* Surface */\n --_text-input-bg: var(\n --hx-text-input-bg,\n var(--hx-input-bg, var(--hx-color-surface-default, #ffffff))\n );\n --_text-input-color: var(\n --hx-text-input-color,\n var(--hx-input-color, var(--hx-color-text-strong, #202b39))\n );\n --_text-input-placeholder-color: var(\n --hx-text-input-placeholder-color,\n var(--hx-color-text-placeholder, #66787b)\n );\n\n /* Border */\n --_text-input-border-color: var(\n --hx-text-input-border-color,\n var(--hx-input-border-color, var(--hx-color-border-strong, #8e9c98))\n );\n --_text-input-border-color-hover: var(\n --hx-text-input-border-color-hover,\n var(--hx-color-border-strong, #8e9c98)\n );\n --_text-input-border-color-focus: var(\n --hx-text-input-border-color-focus,\n var(\n --hx-input-focus-ring-color,\n var(--hx-focus-ring-color, var(--hx-color-primary-400, #6ab1b1))\n )\n );\n --_text-input-border-color-invalid: var(\n --hx-text-input-border-color-invalid,\n var(--hx-input-error-color, var(--hx-color-error-600, #c92a2a))\n );\n --_text-input-border-width: var(--hx-text-input-border-width, var(--hx-border-width-thin, 1px));\n --_text-input-border-radius: var(\n --hx-text-input-border-radius,\n var(--hx-input-border-radius, var(--hx-border-radius-md, 0.375rem))\n );\n\n /* Spacing */\n --_text-input-padding-x: var(--hx-text-input-padding-x, var(--hx-space-3, 0.75rem));\n --_text-input-padding-y: var(--hx-text-input-padding-y, var(--hx-space-2, 0.5rem));\n\n /* Typography */\n --_text-input-font-family: var(\n --hx-text-input-font-family,\n var(--hx-input-font-family, var(--hx-font-family-sans, sans-serif))\n );\n --_text-input-font-size: var(--hx-text-input-font-size, var(--hx-font-size-md, 1rem));\n\n /* Focus ring */\n --_text-input-focus-ring-color: var(\n --hx-text-input-focus-ring-color,\n var(\n --hx-input-focus-ring-color,\n var(--hx-focus-ring-color, var(--hx-color-primary-400, #6ab1b1))\n )\n );\n --_text-input-focus-ring-width: var(\n --hx-text-input-focus-ring-width,\n var(--hx-focus-ring-width, 2px)\n );\n --_text-input-focus-ring-offset: var(\n --hx-text-input-focus-ring-offset,\n var(--hx-focus-ring-offset, 0px)\n );\n\n /* Disabled */\n --_text-input-disabled-bg: var(\n --hx-text-input-disabled-bg,\n var(--hx-color-surface-sunken, #ebeee9)\n );\n --_text-input-disabled-color: var(\n --hx-text-input-disabled-color,\n var(--hx-color-text-disabled, #8e9c98)\n );\n\n /* Label / help / error */\n --_text-input-label-color: var(\n --hx-text-input-label-color,\n var(--hx-input-label-color, var(--hx-color-text-strong, #202b39))\n );\n --_text-input-help-text-color: var(\n --hx-text-input-help-text-color,\n var(--hx-color-text-muted, #4a5362)\n );\n --_text-input-error-color: var(\n --hx-text-input-error-color,\n var(--hx-input-error-color, var(--hx-color-error-text, #c92a2a))\n );\n }\n\n :host([disabled]) {\n opacity: var(--hx-opacity-disabled, 0.5);\n pointer-events: none;\n }\n\n /*\n * Attribute-based focus hooks set by FocusMixin.\n * :host([focused]) — fires whenever the component or any descendant has focus.\n * :host([focused-visible]) — fires only for keyboard-initiated focus.\n * These complement the :focus-within rules on .field__input-wrapper and are\n * exposed as theming hooks for consumers who target the host element.\n */\n :host([focused]) .field__input-wrapper,\n :host([focused-visible]) .field__input-wrapper {\n border-color: var(--_text-input-border-color-focus);\n box-shadow: 0 0 0 var(--_text-input-focus-ring-width)\n color-mix(\n in srgb,\n var(--_text-input-border-color-focus) calc(var(--hx-focus-ring-opacity, 0.25) * 100%),\n transparent\n );\n }\n\n * {\n box-sizing: border-box;\n }\n\n .field {\n display: flex;\n flex-direction: column;\n gap: var(--hx-space-1, 0.25rem);\n font-family: var(--_text-input-font-family);\n }\n\n /* ─── Label ─── */\n\n .field__label-wrapper {\n display: contents;\n }\n\n .field__label {\n display: flex;\n align-items: baseline;\n gap: var(--hx-space-1, 0.25rem);\n font-size: var(--hx-font-size-sm, 0.875rem);\n font-weight: var(--hx-font-weight-medium, 500);\n color: var(--_text-input-label-color);\n line-height: var(--hx-line-height-normal, 1.5);\n }\n\n .field__required-marker {\n color: var(--_text-input-error-color);\n font-weight: var(--hx-font-weight-bold, 700);\n }\n\n /* ─── Input Wrapper ─── */\n\n .field__input-wrapper {\n display: flex;\n align-items: center;\n border: var(--_text-input-border-width) solid var(--_text-input-border-color);\n border-radius: var(--_text-input-border-radius);\n background-color: var(--_text-input-bg);\n transition:\n border-color var(--hx-transition-fast, 150ms ease),\n box-shadow var(--hx-transition-fast, 150ms ease);\n overflow: hidden;\n }\n\n .field__input-wrapper:hover {\n border-color: var(--_text-input-border-color-hover);\n }\n\n .field__input-wrapper:focus-within {\n border-color: var(--_text-input-border-color-focus);\n box-shadow: 0 0 0 var(--_text-input-focus-ring-width)\n color-mix(\n in srgb,\n var(--_text-input-border-color-focus) calc(var(--hx-focus-ring-opacity, 0.25) * 100%),\n transparent\n );\n }\n\n /* ─── Error State ─── */\n\n .field--error .field__input-wrapper {\n border-color: var(--_text-input-border-color-invalid);\n }\n\n .field--error .field__input-wrapper:focus-within {\n border-color: var(--_text-input-border-color-invalid);\n box-shadow: 0 0 0 var(--_text-input-focus-ring-width)\n color-mix(\n in srgb,\n var(--_text-input-border-color-invalid) calc(var(--hx-focus-ring-opacity, 0.25) * 100%),\n transparent\n );\n }\n\n /* ─── Slots (Prefix / Suffix) ─── */\n\n .field__prefix,\n .field__suffix {\n display: flex;\n align-items: center;\n color: var(--hx-color-text-muted, #4a5362);\n flex-shrink: 0;\n }\n\n /* Only add padding when slot has content — avoids phantom space on empty slots */\n .field__prefix--filled {\n padding: 0 var(--_text-input-padding-x);\n }\n\n .field__suffix--filled {\n padding: 0 var(--_text-input-padding-x);\n }\n\n /* ─── Native Input ─── */\n\n .field__input {\n flex: 1;\n border: none;\n outline: none;\n background: transparent;\n padding: var(--_text-input-padding-y) var(--_text-input-padding-x);\n font-family: inherit;\n font-size: var(--_text-input-font-size);\n color: var(--_text-input-color);\n line-height: var(--hx-line-height-normal, 1.5);\n min-height: var(--hx-size-10, 2.5rem);\n width: 100%;\n }\n\n .field__input::placeholder {\n color: var(--_text-input-placeholder-color);\n }\n\n .field__input:focus-visible {\n outline: none; /* wrapper ring handles keyboard focus indication */\n }\n\n .field__input:disabled {\n cursor: not-allowed;\n background-color: var(--_text-input-disabled-bg);\n color: var(--_text-input-disabled-color);\n }\n\n :host([disabled]) .field__input-wrapper {\n background-color: var(--_text-input-disabled-bg);\n }\n\n /* ─── Size Variants ─── */\n\n .field--size-sm .field__input {\n padding: var(--hx-space-1, 0.25rem) var(--hx-space-2, 0.5rem);\n min-height: var(--hx-size-8, 2rem);\n font-size: var(--hx-text-input-sm-font-size, var(--hx-input-sm-font-size, 0.875rem));\n }\n\n .field--size-md .field__input {\n /* md is the default — no overrides needed */\n }\n\n .field--size-lg .field__input {\n padding: var(--hx-space-3, 0.75rem) var(--hx-space-4, 1rem);\n min-height: var(--hx-size-12, 3rem);\n font-size: var(--hx-text-input-lg-font-size, var(--hx-input-lg-font-size, 1.125rem));\n }\n\n /* ─── Help Text & Error Messages ─── */\n\n .field__help-text {\n font-size: var(--hx-font-size-xs, 0.75rem);\n color: var(--_text-input-help-text-color);\n line-height: var(--hx-line-height-normal, 1.5);\n }\n\n .field__error {\n font-size: var(--hx-font-size-xs, 0.75rem);\n color: var(--_text-input-error-color);\n line-height: var(--hx-line-height-normal, 1.5);\n }\n\n /* ─── Motion ─── */\n\n @media (prefers-reduced-motion: reduce) {\n .field__input-wrapper {\n transition: none;\n }\n }\n\n /* ─── High Contrast Mode (forced-colors) ───\n *\n * Bespoke block — sole owner of forced-colors deference for hx-text-input.\n * Covers wrapper/input/placeholder/focus/disabled/error/label/help-text;\n * strictly more than forcedColorsField. The mixin is intentionally NOT\n * composed (XOR rule — see styles/forced-colors.ts COMPOSITION RULES).\n */\n\n @media (forced-colors: active) {\n .field__input-wrapper {\n forced-color-adjust: none;\n background-color: Field;\n color: FieldText;\n border: 2px solid ButtonText;\n }\n\n .field__input {\n color: FieldText;\n }\n\n .field__input::placeholder {\n color: GrayText;\n }\n\n .field__input-wrapper:focus-within {\n border-color: Highlight;\n box-shadow: none;\n }\n\n .field__input:focus-visible {\n outline: 3px solid Highlight;\n outline-offset: -3px;\n }\n\n :host([disabled]) {\n opacity: 1;\n }\n\n :host([disabled]) .field__input-wrapper {\n border-color: GrayText;\n color: GrayText;\n }\n\n :host([disabled]) .field__input {\n color: GrayText;\n }\n\n .field--error .field__input-wrapper {\n border-color: LinkText;\n }\n\n .field__label {\n color: CanvasText;\n }\n\n .field__help-text {\n color: GrayText;\n }\n\n .field__error {\n color: LinkText;\n }\n }\n`;\n","import { html, nothing, type PropertyValues } from 'lit';\nimport '../../utilities/document-token-adoption.js';\nimport { customElement, property, query, state } from 'lit/decorators.js';\nimport { classMap } from 'lit/directives/class-map.js';\nimport { ifDefined } from 'lit/directives/if-defined.js';\nimport { live } from 'lit/directives/live.js';\nimport { HelixElement, createIdCounter } from '../../base/index.js';\nimport { FocusMixin } from '../../mixins/index.js';\nimport { FormMixin } from '../../mixins/FormMixin.js';\nimport { helixTextInputStyles } from './hx-text-input.styles.js';\nimport { devWarn } from '../../utils/dev-warn.js';\n\n// Module-level counter for stable, SSR-compatible IDs (avoids Math.random() hydration mismatch)\nconst _nextTextInputId = createIdCounter('hx-text-input');\n\n/** Detail for hx-input and hx-change events dispatched by hx-text-input. */\nexport interface HxTextInputDetail {\n value: string;\n}\n\n/**\n * A text input component with label, validation, and form association.\n * Supports accessible labeling via `label` property, `aria-label` attribute, or the `label` slot.\n * Uses `aria-invalid` and `aria-describedby` on the native input for screen reader support. Native `required` provides implicit aria-required mapping per HTML-AAM.\n * Error messages are announced via `role=\"alert\"`. Keyboard navigation follows native input behavior.\n *\n * @summary Form-associated text input with built-in label, error, and help text.\n *\n * @tag hx-text-input\n *\n * @slot label - Custom label content (overrides the label property). Use for Drupal Form API rendered labels.\n * @slot prefix - Content rendered before the input (e.g., icon).\n * @slot suffix - Content rendered after the input (e.g., icon or button).\n * @slot help-text - Custom help text content (overrides the helpText property).\n * @slot error - Custom error content (overrides the error property). Use for Drupal Form API rendered errors.\n *\n * @fires {CustomEvent<{value: string}>} hx-input - Dispatched on every keystroke as the user types.\n * @fires {CustomEvent<{value: string}>} hx-change - Dispatched when the input loses focus after its value changed.\n *\n * @csspart field - The outer field container.\n * @csspart label - The label element.\n * @csspart input-wrapper - The wrapper around prefix, input, and suffix.\n * @csspart input - The native input element.\n * @csspart help-text - The help text container.\n * @csspart error - The error message container.\n *\n * @cssprop [--hx-input-bg=var(--hx-color-surface-default)] - Input background color.\n * @cssprop [--hx-input-color=var(--hx-color-text-strong)] - Input text color.\n * @cssprop [--hx-input-border-color=var(--hx-color-border-strong)] - Input border color.\n * @cssprop [--hx-input-border-radius=var(--hx-border-radius-md)] - Input border radius.\n * @cssprop [--hx-input-font-family=var(--hx-font-family-sans)] - Input font family.\n * @cssprop [--hx-input-focus-ring-color=var(--hx-focus-ring-color)] - Focus ring color.\n * @cssprop [--hx-input-error-color=var(--hx-color-error-text)] - Error state color.\n * @cssprop [--hx-input-label-color=var(--hx-color-text-strong)] - Label text color.\n * @cssprop [--hx-input-sm-font-size=0.875rem] - Font size for the sm size variant.\n * @cssprop [--hx-input-lg-font-size=1.125rem] - Font size for the lg size variant.\n *\n * @cssprop [--hx-text-input-border-width=var(--hx-border-width-thin)] - Outer border-width override (canonical hx-{tag}-* prefix; sits above --hx-input-* aliases in the cascade).\n * @cssprop [--hx-text-input-padding-x=var(--hx-space-3)] - Outer horizontal padding override.\n * @cssprop [--hx-text-input-padding-y=var(--hx-space-2)] - Outer vertical padding override.\n * @cssprop [--hx-text-input-font-size=var(--hx-font-size-md)] - Outer font-size override.\n * @cssprop [--hx-text-input-sm-font-size] - Outer sm-variant font-size override (falls through to --hx-input-sm-font-size).\n * @cssprop [--hx-text-input-lg-font-size] - Outer lg-variant font-size override (falls through to --hx-input-lg-font-size).\n *\n * @cssprop [--hx-color-surface-default] - Resting field surface (semantic).\n * @cssprop [--hx-color-text-strong] - Resting input text + label color (semantic).\n * @cssprop [--hx-color-border-strong] - Resting border color (semantic).\n * @cssprop [--hx-color-error-text] - Error state text + border color (semantic).\n * @cssprop [--hx-color-error-600] - Error border primitive fallback inside the invalid-state cascade.\n */\n@customElement('hx-text-input')\nexport class HelixTextInput extends FocusMixin(FormMixin(HelixElement)) {\n // 3.2.1: forced-colors deference is owned by the bespoke @media block in\n // hx-text-input.styles.ts (covers wrapper/input/placeholder/focus/disabled/\n // error/label/help-text — strictly more than the shared mixin). XOR rule:\n // do NOT also compose forcedColorsField — overlapping selectors inside the\n // same media query create a fragile specificity war.\n static override styles = [helixTextInputStyles];\n\n // ─── Form Association ───\n\n /** @internal */\n static override formAssociated = true;\n\n // ─── Properties ───\n\n /**\n * The visible label text for the input.\n * @attr label\n */\n @property({ type: String })\n label = '';\n\n /**\n * Placeholder text shown when the input is empty.\n * @attr placeholder\n */\n @property({ type: String })\n placeholder = '';\n\n /**\n * The current value of the input.\n * @attr value\n * @remarks When `null` is passed programmatically, Lit coerces it to an empty string.\n * This is expected behavior — the input treats null as equivalent to an empty string value.\n */\n @property({ type: String })\n value = '';\n\n /**\n * The type of the native input element.\n * @attr type\n */\n @property({ type: String })\n type: 'text' | 'email' | 'password' | 'tel' | 'url' | 'search' | 'number' | 'date' = 'text';\n\n /**\n * Whether the input is required for form submission.\n * @attr required\n */\n @property({ type: Boolean, reflect: true })\n required = false;\n\n /**\n * Whether the input is disabled.\n * @attr disabled\n */\n @property({ type: Boolean, reflect: true })\n disabled = false;\n\n /**\n * Error message to display. When set, the input enters an error state.\n * @attr error\n */\n @property({ type: String })\n error = '';\n\n /**\n * Help text displayed below the input for guidance.\n * @attr help-text\n */\n @property({ type: String, attribute: 'help-text' })\n helpText = '';\n\n /**\n * The name of the input, used for form submission.\n * @attr name\n */\n @property({ type: String, reflect: true })\n name = '';\n\n /**\n * Accessible name for screen readers, if different from the visible label.\n * Uses `accessible-label` attribute instead of `aria-label` to avoid\n * ARIAMixin shadowing on the host element. The value is forwarded to the\n * internal native input's `aria-label`.\n *\n * Note: `mixinDelegatesAria` is not applied to this component because form\n * inputs with associated labels delegate accessible naming via `<label>`\n * association and `aria-labelledby`, not host-level ARIA delegation. The\n * `accessible-label` attribute is a fallback for label-free usage.\n * @attr accessible-label\n */\n @property({ type: String, attribute: 'accessible-label' })\n accessibleLabel: string | null = null;\n\n /**\n * Whether the input is read-only.\n * @attr readonly\n */\n @property({ type: Boolean, reflect: true })\n readonly = false;\n\n /**\n * Minimum number of characters allowed.\n * @attr minlength\n */\n @property({ type: Number })\n minlength: number | undefined = undefined;\n\n /**\n * Maximum number of characters allowed.\n * @attr maxlength\n */\n @property({ type: Number })\n maxlength: number | undefined = undefined;\n\n /**\n * A regular expression pattern the value must match for form validation.\n * @attr pattern\n */\n @property({ type: String })\n pattern = '';\n\n /**\n * Hint for the browser's autocomplete feature. Accepts standard HTML autocomplete values.\n * @attr autocomplete\n */\n @property({ type: String })\n autocomplete = '';\n\n /**\n * Validation message shown when the field is required but empty.\n * @attr required-message\n */\n @property({ attribute: 'required-message' })\n requiredMessage = 'This field is required.';\n\n /**\n * Visual size of the input field.\n * @attr hx-size\n */\n @property({ type: String, attribute: 'hx-size', reflect: true })\n size: 'sm' | 'md' | 'lg' = 'md';\n\n // ─── Internal References ───\n\n /** @internal */\n @query('.field__input')\n private _input: HTMLInputElement | undefined;\n\n // ─── FocusMixin integration ───\n\n /**\n * Declares the inner focusable element for FocusMixin delegation.\n * @internal\n */\n protected get _focusableNode(): HTMLElement | null {\n return this._input ?? null;\n }\n\n // ─── Slot Tracking ───\n\n /** @internal */\n @state() private _hasLabelSlot = false;\n /** @internal */\n @state() private _hasErrorSlot = false;\n /** @internal */\n @state() private _hasPrefixSlot = false;\n /** @internal */\n @state() private _hasSuffixSlot = false;\n /** @internal */\n @state() private _hasHelpTextSlot = false;\n\n /** @internal */\n private _handleLabelSlotChange(e: Event): void {\n const slot = e.target as HTMLSlotElement;\n this._hasLabelSlot = slot.assignedElements().length > 0;\n if (this._hasLabelSlot) {\n const slottedLabel = slot.assignedElements()[0];\n if (slottedLabel && !slottedLabel.id) {\n slottedLabel.id = `${this._inputId}-slotted-label`;\n }\n }\n }\n\n /** @internal */\n private _handleErrorSlotChange(e: Event): void {\n const slot = e.target as HTMLSlotElement;\n this._hasErrorSlot = slot.assignedElements().length > 0;\n }\n\n /** @internal */\n private _handlePrefixSlotChange(e: Event): void {\n const slot = e.target as HTMLSlotElement;\n this._hasPrefixSlot = slot.assignedElements().length > 0;\n }\n\n /** @internal */\n private _handleSuffixSlotChange(e: Event): void {\n const slot = e.target as HTMLSlotElement;\n this._hasSuffixSlot = slot.assignedElements().length > 0;\n }\n\n /** @internal */\n private _handleHelpTextSlotChange(e: Event): void {\n const slot = e.target as HTMLSlotElement;\n this._hasHelpTextSlot = slot.assignedElements().length > 0;\n }\n\n // ─── Lifecycle ───\n\n override updated(changedProperties: PropertyValues<this>): void {\n super.updated(changedProperties);\n if (changedProperties.has('value')) {\n this._internals.setFormValue(this.value);\n }\n if (\n (changedProperties.has('value') || changedProperties.has('type')) &&\n this.type === 'number' &&\n this.value !== '' &&\n isNaN(Number(this.value))\n ) {\n devWarn(\n 'hx-text-input',\n `type=\"number\" received non-numeric value \"${this.value}\". Browser will display empty input.`,\n );\n }\n }\n\n // ─── Form Integration ───\n\n /** Returns the associated form element, if any. */\n override get form(): HTMLFormElement | null {\n return this._internals.form;\n }\n\n /** Returns the validation message. */\n override get validationMessage(): string {\n return this._internals.validationMessage;\n }\n\n /** Returns the ValidityState object. */\n override get validity(): ValidityState {\n return this._internals.validity;\n }\n\n /** @internal */\n _updateValidity(): void {\n if (this.required && !this.value) {\n this._internals.setValidity(\n { valueMissing: true },\n this.error || this.requiredMessage,\n this._input,\n );\n } else if (\n this.minlength !== undefined &&\n this.value.length > 0 &&\n this.value.length < this.minlength\n ) {\n this._internals.setValidity(\n { tooShort: true },\n this.error || `Please lengthen this text to ${this.minlength} characters or more.`,\n this._input,\n );\n } else if (this.maxlength !== undefined && this.value.length > this.maxlength) {\n this._internals.setValidity(\n { tooLong: true },\n this.error || `Please shorten this text to ${this.maxlength} characters or fewer.`,\n this._input,\n );\n } else {\n this._internals.setValidity({});\n }\n }\n\n // ─── Form Lifecycle Hooks ───\n\n protected override _onFormReset(): void {\n this.value = '';\n this._internals.setFormValue('');\n this._resetInteractionState();\n }\n\n protected override _onFormStateRestore(\n state: File | string | FormData | null,\n _mode: 'restore' | 'autocomplete',\n ): void {\n if (typeof state === 'string') {\n this.value = state;\n }\n }\n\n protected override _onFormDisabled(disabled: boolean): void {\n this.disabled = disabled;\n }\n\n // ─── Event Handling ───\n\n /** @internal */\n private _handleInput(e: Event): void {\n const target = e.target as HTMLInputElement;\n this.value = target.value;\n this._internals.setFormValue(this.value);\n this._handleInteractionInput();\n\n /**\n * Dispatched on every keystroke as the user types.\n * @event hx-input\n */\n this.dispatchEvent(\n new CustomEvent<{ value: string }>('hx-input', {\n bubbles: true,\n composed: true,\n detail: { value: this.value },\n }),\n );\n }\n\n /** @internal */\n private _handleChange(e: Event): void {\n const target = e.target as HTMLInputElement;\n this.value = target.value;\n this._internals.setFormValue(this.value);\n this._handleInteractionBlur();\n\n /**\n * Dispatched when the input loses focus after its value changed.\n * @event hx-change\n */\n this.dispatchEvent(\n new CustomEvent<{ value: string }>('hx-change', {\n bubbles: true,\n composed: true,\n detail: { value: this.value },\n }),\n );\n }\n\n // ─── Public Methods ───\n\n /** Selects all text in the input. */\n select(): void {\n this._input?.select();\n }\n\n // ─── Render ───\n\n /** @internal */\n private _inputId = _nextTextInputId();\n /** @internal */\n private _helpTextId = `${this._inputId}-help`;\n /** @internal */\n private _errorId = `${this._inputId}-error`;\n\n override render() {\n const hasError = !!this.error || this._hasErrorSlot;\n\n const fieldClasses = {\n field: true,\n 'field--error': hasError,\n 'field--disabled': this.disabled,\n 'field--required': this.required,\n [`field--size-${this.size}`]: true,\n };\n\n const describedBy =\n [\n hasError ? this._errorId : null,\n this.helpText || this._hasHelpTextSlot ? this._helpTextId : null,\n ]\n .filter(Boolean)\n .join(' ') || undefined;\n\n return html`\n <div part=\"field\" class=${classMap(fieldClasses)}>\n <div class=\"field__label-wrapper\">\n <slot name=\"label\" @slotchange=${this._handleLabelSlotChange}>\n ${this.label\n ? html`\n <label part=\"label\" class=\"field__label\" for=${this._inputId}>\n ${this.label}\n ${this.required\n ? html`<span class=\"field__required-marker\" aria-hidden=\"true\">*</span>`\n : nothing}\n </label>\n `\n : nothing}\n </slot>\n </div>\n\n <div part=\"input-wrapper\" class=\"field__input-wrapper\">\n <span\n class=${classMap({\n field__prefix: true,\n 'field__prefix--filled': this._hasPrefixSlot,\n })}\n >\n <slot name=\"prefix\" @slotchange=${this._handlePrefixSlotChange}></slot>\n </span>\n\n <input\n part=\"input\"\n class=\"field__input\"\n id=${this._inputId}\n type=${this.type}\n .value=${live(this.value)}\n placeholder=${ifDefined(this.placeholder || undefined)}\n ?required=${this.required}\n ?disabled=${this.disabled}\n ?readonly=${this.readonly}\n name=${ifDefined(this.name || undefined)}\n minlength=${ifDefined(this.minlength)}\n maxlength=${ifDefined(this.maxlength)}\n pattern=${ifDefined(this.pattern || undefined)}\n autocomplete=${ifDefined(this.autocomplete || undefined)}\n aria-label=${ifDefined(this.accessibleLabel || undefined)}\n aria-labelledby=${ifDefined(\n this._hasLabelSlot ? `${this._inputId}-slotted-label` : undefined,\n )}\n aria-invalid=${hasError ? 'true' : nothing}\n aria-describedby=${ifDefined(describedBy)}\n @input=${this._handleInput}\n @change=${this._handleChange}\n />\n\n <span\n class=${classMap({\n field__suffix: true,\n 'field__suffix--filled': this._hasSuffixSlot,\n })}\n >\n <slot name=\"suffix\" @slotchange=${this._handleSuffixSlotChange}></slot>\n </span>\n </div>\n\n ${hasError\n ? html`<div\n part=\"error\"\n class=\"field__error\"\n id=${this._errorId}\n role=\"alert\"\n aria-atomic=\"true\"\n >\n <slot name=\"error\" @slotchange=${this._handleErrorSlotChange}>${this.error}</slot>\n </div>`\n : html`<slot name=\"error\" @slotchange=${this._handleErrorSlotChange}></slot>`}\n ${this._hasHelpTextSlot\n ? html`\n <div part=\"help-text\" class=\"field__help-text\" id=${this._helpTextId}>\n <slot name=\"help-text\" @slotchange=${this._handleHelpTextSlotChange}>\n ${this.helpText}\n </slot>\n </div>\n `\n : this.helpText && !hasError\n ? html`\n <div part=\"help-text\" class=\"field__help-text\" id=${this._helpTextId}>\n <slot name=\"help-text\" @slotchange=${this._handleHelpTextSlotChange}>\n ${this.helpText}\n </slot>\n </div>\n `\n : html`<slot name=\"help-text\" @slotchange=${this._handleHelpTextSlotChange}></slot>`}\n </div>\n `;\n }\n}\n\n/**\n * Per-component event map for type-safe addEventListener on hx-text-input.\n * The `hx-change` detail is `{ value: string }` only — no `checked` property.\n */\nexport interface HxTextInputEventMap {\n 'hx-input': CustomEvent<{ value: string }>;\n 'hx-change': CustomEvent<{ value: string }>;\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'hx-text-input': HelixTextInput;\n }\n interface HTMLElementEventMap {\n 'hx-input': CustomEvent<{ value: string }>;\n }\n}\n\n/** Primary type alias for hx-text-input */\nexport type HxTextInput = HelixTextInput;\n"],"names":["FocusMixin","superClass","FocusMixinClass","options","node","_a","changedProperties","__decorateClass","property","helixTextInputStyles","css","_nextTextInputId","createIdCounter","HelixTextInput","FormMixin","HelixElement","slot","slottedLabel","devWarn","state","_mode","disabled","target","hasError","fieldClasses","describedBy","html","classMap","nothing","live","ifDefined","query","customElement"],"mappings":";;;;;;;;;;;;;;AAmDO,MAAMA,IAAa,CAAoCC,MAAkB;AAAA,EAC9E,MAAMC,UAAwBD,EAA0C;AAAA,IAAxE,cAAA;AAAA,YAAA,GAAA,SAAA,GAQE,KAAA,UAAU,IAUV,KAAA,iBAAiB,IAGjB,KAAQ,gBAAgB,IASxB,KAAQ,6BAA6B,IAkErC,KAAQ,iBAAiB,MAAY;AACnC,aAAK,UAAU,IAEf,KAAK,iBAAiB,CAAC,KAAK;AAAA,MAC9B,GAGA,KAAQ,kBAAkB,MAAY;AACpC,aAAK,UAAU,IACf,KAAK,iBAAiB,IAEtB,KAAK,6BAA6B;AAAA,MACpC,GAMA,KAAQ,qBAAqB,MAAY;AACvC,aAAK,6BAA6B;AAAA,MACpC,GAWA,KAAQ,iBAAiB,MAAY;AACnC,aAAK,6BAA6B;AAAA,MACpC;AAAA,IAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IA1FA,IAAc,iBAAqC;AACjD,aAAO;AAAA,IACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAOS,MAAME,GAA8B;AAC3C,YAAMC,IAAO,KAAK;AAClB,MAAIA,MAAS,OACXA,EAAK,MAAMD,CAAO,IAElB,KAAK,gBAAgB;AAAA,IAEzB;AAAA;AAAA,IAGS,OAAa;;AACpB,OAAAE,IAAA,KAAK,mBAAL,QAAAA,EAAqB;AAAA,IACvB;AAAA,IAES,oBAA0B;AACjC,YAAM,kBAAA,GACN,KAAK,iBAAiB,WAAW,KAAK,cAAc,GACpD,KAAK,iBAAiB,YAAY,KAAK,eAAe,GACtD,KAAK,iBAAiB,eAAe,KAAK,kBAAkB,GAC5D,KAAK,iBAAiB,WAAW,KAAK,cAAc;AAAA,IACtD;AAAA,IAES,uBAA6B;AACpC,YAAM,qBAAA,GACN,KAAK,oBAAoB,WAAW,KAAK,cAAc,GACvD,KAAK,oBAAoB,YAAY,KAAK,eAAe,GACzD,KAAK,oBAAoB,eAAe,KAAK,kBAAkB,GAC/D,KAAK,oBAAoB,WAAW,KAAK,cAAc;AAAA,IACzD;AAAA,IAES,aAAaC,GAAyC;AAC7D,YAAM,aAAaA,CAAiB,GAGhC,KAAK,aAAa,WAAW,KAC/B,KAAK,MAAA,GAIH,KAAK,kBACP,KAAK,gBAAgB,IACrB,KAAK,MAAA;AAAA,IAET;AAAA,EAAA;AAnFAC,SAAAA,EAAA;AAAA,IADCC,EAAS,EAAE,MAAM,SAAS,SAAS,IAAM;AAAA,EAAA,GAPtCN,EAQJ,WAAA,SAAA,GAUAK,EAAA;AAAA,IADCC,EAAS,EAAE,MAAM,SAAS,SAAS,IAAM,WAAW,mBAAmB;AAAA,EAAA,GAjBpEN,EAkBJ,WAAA,gBAAA,GAkHKA;AACT,GC3KaO,IAAuBC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;;;;ACDpC,MAAMC,IAAmBC,EAAgB,eAAe;AA0DjD,IAAMC,IAAN,cAA6Bb,EAAWc,EAAUC,CAAY,CAAC,EAAE;AAAA,EAAjE,cAAA;AAAA,UAAA,GAAA,SAAA,GAoBL,KAAA,QAAQ,IAOR,KAAA,cAAc,IASd,KAAA,QAAQ,IAOR,KAAA,OAAqF,QAOrF,KAAA,WAAW,IAOX,KAAA,WAAW,IAOX,KAAA,QAAQ,IAOR,KAAA,WAAW,IAOX,KAAA,OAAO,IAeP,KAAA,kBAAiC,MAOjC,KAAA,WAAW,IAOX,KAAA,YAAgC,QAOhC,KAAA,YAAgC,QAOhC,KAAA,UAAU,IAOV,KAAA,eAAe,IAOf,KAAA,kBAAkB,2BAOlB,KAAA,OAA2B,MAqBlB,KAAQ,gBAAgB,IAExB,KAAQ,gBAAgB,IAExB,KAAQ,iBAAiB,IAEzB,KAAQ,iBAAiB,IAEzB,KAAQ,mBAAmB,IAiLpC,KAAQ,WAAWJ,EAAA,GAEnB,KAAQ,cAAc,GAAG,KAAK,QAAQ,SAEtC,KAAQ,WAAW,GAAG,KAAK,QAAQ;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EApMnC,IAAc,iBAAqC;AACjD,WAAO,KAAK,UAAU;AAAA,EACxB;AAAA;AAAA,EAgBQ,uBAAuB,GAAgB;AAC7C,UAAMK,IAAO,EAAE;AAEf,QADA,KAAK,gBAAgBA,EAAK,iBAAA,EAAmB,SAAS,GAClD,KAAK,eAAe;AACtB,YAAMC,IAAeD,EAAK,iBAAA,EAAmB,CAAC;AAC9C,MAAIC,KAAgB,CAACA,EAAa,OAChCA,EAAa,KAAK,GAAG,KAAK,QAAQ;AAAA,IAEtC;AAAA,EACF;AAAA;AAAA,EAGQ,uBAAuB,GAAgB;AAC7C,UAAMD,IAAO,EAAE;AACf,SAAK,gBAAgBA,EAAK,iBAAA,EAAmB,SAAS;AAAA,EACxD;AAAA;AAAA,EAGQ,wBAAwB,GAAgB;AAC9C,UAAMA,IAAO,EAAE;AACf,SAAK,iBAAiBA,EAAK,iBAAA,EAAmB,SAAS;AAAA,EACzD;AAAA;AAAA,EAGQ,wBAAwB,GAAgB;AAC9C,UAAMA,IAAO,EAAE;AACf,SAAK,iBAAiBA,EAAK,iBAAA,EAAmB,SAAS;AAAA,EACzD;AAAA;AAAA,EAGQ,0BAA0B,GAAgB;AAChD,UAAMA,IAAO,EAAE;AACf,SAAK,mBAAmBA,EAAK,iBAAA,EAAmB,SAAS;AAAA,EAC3D;AAAA;AAAA,EAIS,QAAQV,GAA+C;AAC9D,UAAM,QAAQA,CAAiB,GAC3BA,EAAkB,IAAI,OAAO,KAC/B,KAAK,WAAW,aAAa,KAAK,KAAK,IAGtCA,EAAkB,IAAI,OAAO,KAAKA,EAAkB,IAAI,MAAM,MAC/D,KAAK,SAAS,YACd,KAAK,UAAU,MACf,MAAM,OAAO,KAAK,KAAK,CAAC,KAExBY;AAAA,MACE;AAAA,MACA,6CAA6C,KAAK,KAAK;AAAA,IAAA;AAAA,EAG7D;AAAA;AAAA;AAAA,EAKA,IAAa,OAA+B;AAC1C,WAAO,KAAK,WAAW;AAAA,EACzB;AAAA;AAAA,EAGA,IAAa,oBAA4B;AACvC,WAAO,KAAK,WAAW;AAAA,EACzB;AAAA;AAAA,EAGA,IAAa,WAA0B;AACrC,WAAO,KAAK,WAAW;AAAA,EACzB;AAAA;AAAA,EAGA,kBAAwB;AACtB,IAAI,KAAK,YAAY,CAAC,KAAK,QACzB,KAAK,WAAW;AAAA,MACd,EAAE,cAAc,GAAA;AAAA,MAChB,KAAK,SAAS,KAAK;AAAA,MACnB,KAAK;AAAA,IAAA,IAGP,KAAK,cAAc,UACnB,KAAK,MAAM,SAAS,KACpB,KAAK,MAAM,SAAS,KAAK,YAEzB,KAAK,WAAW;AAAA,MACd,EAAE,UAAU,GAAA;AAAA,MACZ,KAAK,SAAS,gCAAgC,KAAK,SAAS;AAAA,MAC5D,KAAK;AAAA,IAAA,IAEE,KAAK,cAAc,UAAa,KAAK,MAAM,SAAS,KAAK,YAClE,KAAK,WAAW;AAAA,MACd,EAAE,SAAS,GAAA;AAAA,MACX,KAAK,SAAS,+BAA+B,KAAK,SAAS;AAAA,MAC3D,KAAK;AAAA,IAAA,IAGP,KAAK,WAAW,YAAY,EAAE;AAAA,EAElC;AAAA;AAAA,EAImB,eAAqB;AACtC,SAAK,QAAQ,IACb,KAAK,WAAW,aAAa,EAAE,GAC/B,KAAK,uBAAA;AAAA,EACP;AAAA,EAEmB,oBACjBC,GACAC,GACM;AACN,IAAI,OAAOD,KAAU,aACnB,KAAK,QAAQA;AAAAA,EAEjB;AAAA,EAEmB,gBAAgBE,GAAyB;AAC1D,SAAK,WAAWA;AAAA,EAClB;AAAA;AAAA;AAAA,EAKQ,aAAa,GAAgB;AACnC,UAAMC,IAAS,EAAE;AACjB,SAAK,QAAQA,EAAO,OACpB,KAAK,WAAW,aAAa,KAAK,KAAK,GACvC,KAAK,wBAAA,GAML,KAAK;AAAA,MACH,IAAI,YAA+B,YAAY;AAAA,QAC7C,SAAS;AAAA,QACT,UAAU;AAAA,QACV,QAAQ,EAAE,OAAO,KAAK,MAAA;AAAA,MAAM,CAC7B;AAAA,IAAA;AAAA,EAEL;AAAA;AAAA,EAGQ,cAAc,GAAgB;AACpC,UAAMA,IAAS,EAAE;AACjB,SAAK,QAAQA,EAAO,OACpB,KAAK,WAAW,aAAa,KAAK,KAAK,GACvC,KAAK,uBAAA,GAML,KAAK;AAAA,MACH,IAAI,YAA+B,aAAa;AAAA,QAC9C,SAAS;AAAA,QACT,UAAU;AAAA,QACV,QAAQ,EAAE,OAAO,KAAK,MAAA;AAAA,MAAM,CAC7B;AAAA,IAAA;AAAA,EAEL;AAAA;AAAA;AAAA,EAKA,SAAe;;AACb,KAAAjB,IAAA,KAAK,WAAL,QAAAA,EAAa;AAAA,EACf;AAAA,EAWS,SAAS;AAChB,UAAMkB,IAAW,CAAC,CAAC,KAAK,SAAS,KAAK,eAEhCC,IAAe;AAAA,MACnB,OAAO;AAAA,MACP,gBAAgBD;AAAA,MAChB,mBAAmB,KAAK;AAAA,MACxB,mBAAmB,KAAK;AAAA,MACxB,CAAC,eAAe,KAAK,IAAI,EAAE,GAAG;AAAA,IAAA,GAG1BE,IACJ;AAAA,MACEF,IAAW,KAAK,WAAW;AAAA,MAC3B,KAAK,YAAY,KAAK,mBAAmB,KAAK,cAAc;AAAA,IAAA,EAE3D,OAAO,OAAO,EACd,KAAK,GAAG,KAAK;AAElB,WAAOG;AAAA,gCACqBC,EAASH,CAAY,CAAC;AAAA;AAAA,2CAEX,KAAK,sBAAsB;AAAA,cACxD,KAAK,QACHE;AAAA,iEACiD,KAAK,QAAQ;AAAA,sBACxD,KAAK,KAAK;AAAA,sBACV,KAAK,WACHA,sEACAE,CAAO;AAAA;AAAA,oBAGfA,CAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,oBAMHD,EAAS;AAAA,MACf,eAAe;AAAA,MACf,yBAAyB,KAAK;AAAA,IAAA,CAC/B,CAAC;AAAA;AAAA,8CAEgC,KAAK,uBAAuB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,iBAMzD,KAAK,QAAQ;AAAA,mBACX,KAAK,IAAI;AAAA,qBACPE,EAAK,KAAK,KAAK,CAAC;AAAA,0BACXC,EAAU,KAAK,eAAe,MAAS,CAAC;AAAA,wBAC1C,KAAK,QAAQ;AAAA,wBACb,KAAK,QAAQ;AAAA,wBACb,KAAK,QAAQ;AAAA,mBAClBA,EAAU,KAAK,QAAQ,MAAS,CAAC;AAAA,wBAC5BA,EAAU,KAAK,SAAS,CAAC;AAAA,wBACzBA,EAAU,KAAK,SAAS,CAAC;AAAA,sBAC3BA,EAAU,KAAK,WAAW,MAAS,CAAC;AAAA,2BAC/BA,EAAU,KAAK,gBAAgB,MAAS,CAAC;AAAA,yBAC3CA,EAAU,KAAK,mBAAmB,MAAS,CAAC;AAAA,8BACvCA;AAAA,MAChB,KAAK,gBAAgB,GAAG,KAAK,QAAQ,mBAAmB;AAAA,IAAA,CACzD;AAAA,2BACcP,IAAW,SAASK,CAAO;AAAA,+BACvBE,EAAUL,CAAW,CAAC;AAAA,qBAChC,KAAK,YAAY;AAAA,sBAChB,KAAK,aAAa;AAAA;AAAA;AAAA;AAAA,oBAIpBE,EAAS;AAAA,MACf,eAAe;AAAA,MACf,yBAAyB,KAAK;AAAA,IAAA,CAC/B,CAAC;AAAA;AAAA,8CAEgC,KAAK,uBAAuB;AAAA;AAAA;AAAA;AAAA,UAIhEJ,IACEG;AAAA;AAAA;AAAA,mBAGO,KAAK,QAAQ;AAAA;AAAA;AAAA;AAAA,+CAIe,KAAK,sBAAsB,IAAI,KAAK,KAAK;AAAA,sBAE5EA,mCAAsC,KAAK,sBAAsB,UAAU;AAAA,UAC7E,KAAK,mBACHA;AAAA,kEACsD,KAAK,WAAW;AAAA,qDAC7B,KAAK,yBAAyB;AAAA,oBAC/D,KAAK,QAAQ;AAAA;AAAA;AAAA,gBAIrB,KAAK,YAAY,CAACH,IAChBG;AAAA,oEACsD,KAAK,WAAW;AAAA,uDAC7B,KAAK,yBAAyB;AAAA,sBAC/D,KAAK,QAAQ;AAAA;AAAA;AAAA,kBAIrBA,uCAA0C,KAAK,yBAAyB,UAAU;AAAA;AAAA;AAAA,EAG9F;AACF;AAldab,EAMK,SAAS,CAACJ,CAAoB;AANnCI,EAWK,iBAAiB;AASjCN,EAAA;AAAA,EADCC,EAAS,EAAE,MAAM,OAAA,CAAQ;AAAA,GAnBfK,EAoBX,WAAA,SAAA,CAAA;AAOAN,EAAA;AAAA,EADCC,EAAS,EAAE,MAAM,OAAA,CAAQ;AAAA,GA1BfK,EA2BX,WAAA,eAAA,CAAA;AASAN,EAAA;AAAA,EADCC,EAAS,EAAE,MAAM,OAAA,CAAQ;AAAA,GAnCfK,EAoCX,WAAA,SAAA,CAAA;AAOAN,EAAA;AAAA,EADCC,EAAS,EAAE,MAAM,OAAA,CAAQ;AAAA,GA1CfK,EA2CX,WAAA,QAAA,CAAA;AAOAN,EAAA;AAAA,EADCC,EAAS,EAAE,MAAM,SAAS,SAAS,IAAM;AAAA,GAjD/BK,EAkDX,WAAA,YAAA,CAAA;AAOAN,EAAA;AAAA,EADCC,EAAS,EAAE,MAAM,SAAS,SAAS,IAAM;AAAA,GAxD/BK,EAyDX,WAAA,YAAA,CAAA;AAOAN,EAAA;AAAA,EADCC,EAAS,EAAE,MAAM,OAAA,CAAQ;AAAA,GA/DfK,EAgEX,WAAA,SAAA,CAAA;AAOAN,EAAA;AAAA,EADCC,EAAS,EAAE,MAAM,QAAQ,WAAW,aAAa;AAAA,GAtEvCK,EAuEX,WAAA,YAAA,CAAA;AAOAN,EAAA;AAAA,EADCC,EAAS,EAAE,MAAM,QAAQ,SAAS,IAAM;AAAA,GA7E9BK,EA8EX,WAAA,QAAA,CAAA;AAeAN,EAAA;AAAA,EADCC,EAAS,EAAE,MAAM,QAAQ,WAAW,oBAAoB;AAAA,GA5F9CK,EA6FX,WAAA,mBAAA,CAAA;AAOAN,EAAA;AAAA,EADCC,EAAS,EAAE,MAAM,SAAS,SAAS,IAAM;AAAA,GAnG/BK,EAoGX,WAAA,YAAA,CAAA;AAOAN,EAAA;AAAA,EADCC,EAAS,EAAE,MAAM,OAAA,CAAQ;AAAA,GA1GfK,EA2GX,WAAA,aAAA,CAAA;AAOAN,EAAA;AAAA,EADCC,EAAS,EAAE,MAAM,OAAA,CAAQ;AAAA,GAjHfK,EAkHX,WAAA,aAAA,CAAA;AAOAN,EAAA;AAAA,EADCC,EAAS,EAAE,MAAM,OAAA,CAAQ;AAAA,GAxHfK,EAyHX,WAAA,WAAA,CAAA;AAOAN,EAAA;AAAA,EADCC,EAAS,EAAE,MAAM,OAAA,CAAQ;AAAA,GA/HfK,EAgIX,WAAA,gBAAA,CAAA;AAOAN,EAAA;AAAA,EADCC,EAAS,EAAE,WAAW,mBAAA,CAAoB;AAAA,GAtIhCK,EAuIX,WAAA,mBAAA,CAAA;AAOAN,EAAA;AAAA,EADCC,EAAS,EAAE,MAAM,QAAQ,WAAW,WAAW,SAAS,IAAM;AAAA,GA7IpDK,EA8IX,WAAA,QAAA,CAAA;AAMQN,EAAA;AAAA,EADPwB,EAAM,eAAe;AAAA,GAnJXlB,EAoJH,WAAA,UAAA,CAAA;AAeSN,EAAA;AAAA,EAAhBY,EAAA;AAAM,GAnKIN,EAmKM,WAAA,iBAAA,CAAA;AAEAN,EAAA;AAAA,EAAhBY,EAAA;AAAM,GArKIN,EAqKM,WAAA,iBAAA,CAAA;AAEAN,EAAA;AAAA,EAAhBY,EAAA;AAAM,GAvKIN,EAuKM,WAAA,kBAAA,CAAA;AAEAN,EAAA;AAAA,EAAhBY,EAAA;AAAM,GAzKIN,EAyKM,WAAA,kBAAA,CAAA;AAEAN,EAAA;AAAA,EAAhBY,EAAA;AAAM,GA3KIN,EA2KM,WAAA,oBAAA,CAAA;AA3KNA,IAANN,EAAA;AAAA,EADNyB,EAAc,eAAe;AAAA,GACjBnB,CAAA;"}
|
|
1
|
+
{"version":3,"file":"hx-text-input-Bn7Gn8CI.js","sources":["../../src/mixins/FocusMixin.ts","../../src/components/hx-text-input/hx-text-input.styles.ts","../../src/components/hx-text-input/hx-text-input.ts"],"sourcesContent":["import { LitElement, type PropertyValues } from 'lit';\nimport { property } from 'lit/decorators.js';\n\n/**\n * Mixin constructor type — must use `any[]` args per TypeScript mixin requirements (TS2545).\n * @internal\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype Constructor<T = object> = new (...args: any[]) => T;\n\n/**\n * The public interface added by FocusMixin.\n * Consumers can use this type for typed references.\n *\n * @public\n */\nexport interface FocusMixinInterface {\n /** True when the component host has focus (including descendant focus). */\n readonly focused: boolean;\n /** True when focus arrived via keyboard (not pointer). */\n readonly focusedVisible: boolean;\n}\n\n/**\n * FocusMixin — standardized focus delegation for HELiX web components.\n *\n * Modeled after Lion's `FocusMixin` and Material Web's `mixinDelegatesAria`.\n * Provides:\n * - `_focusableNode` getter for subclasses to declare the inner focusable element\n * - `focused` reflected attribute as a styling hook for `:host([focused])`\n * - `focusedVisible` reflected attribute for keyboard-only focus rings\n * - Delegated `focus()` / `blur()` routing to the inner element\n * - Autofocus support after first render\n *\n * ### Usage\n *\n * ```ts\n * class MyInput extends FocusMixin(HelixElement) {\n * @query('input') private _input: HTMLInputElement | undefined;\n *\n * protected override get _focusableNode(): HTMLElement | null {\n * return this._input ?? null;\n * }\n * }\n * ```\n *\n * @param superClass - A Lit element constructor to mix into\n * @returns A new class with focus management capabilities\n *\n * @public\n */\nexport const FocusMixin = <T extends Constructor<LitElement>>(superClass: T) => {\n class FocusMixinClass extends superClass implements FocusMixinInterface {\n /**\n * True when the component or any of its descendants has focus.\n * Reflects to attribute `focused` for CSS selector use.\n *\n * @attr focused\n */\n @property({ type: Boolean, reflect: true })\n focused = false;\n\n /**\n * True when focus was reached via keyboard navigation (Tab / Shift+Tab)\n * rather than pointer interaction. Reflects to attribute `focused-visible`\n * for rendering keyboard-only focus rings.\n *\n * @attr focused-visible\n */\n @property({ type: Boolean, reflect: true, attribute: 'focused-visible' })\n focusedVisible = false;\n\n /** @internal — whether a `focus()` call was queued before first render */\n private _focusPending = false;\n\n /**\n * @internal — tracks whether the most recent interaction toward this\n * element was via pointer (true) or keyboard (false).\n *\n * Set to false on `pointerdown` so that the subsequent `focusin` can\n * determine it is not keyboard-initiated.\n */\n private _lastInteractionWasPointer = false;\n\n /**\n * Returns the inner focusable element that `focus()` and `blur()` will\n * delegate to. Subclasses MUST override this getter.\n *\n * @returns The inner focusable element, or `null` if not yet rendered.\n * @internal\n */\n protected get _focusableNode(): HTMLElement | null {\n return null;\n }\n\n /**\n * Delegates focus to the inner focusable element.\n * If the element has not yet rendered, queues the focus call for\n * `firstUpdated`.\n */\n override focus(options?: FocusOptions): void {\n const node = this._focusableNode;\n if (node !== null) {\n node.focus(options);\n } else {\n this._focusPending = true;\n }\n }\n\n /** Delegates blur to the inner focusable element. */\n override blur(): void {\n this._focusableNode?.blur();\n }\n\n override connectedCallback(): void {\n super.connectedCallback();\n this.addEventListener('focusin', this._handleFocusIn);\n this.addEventListener('focusout', this._handleFocusOut);\n this.addEventListener('pointerdown', this._handlePointerDown);\n this.addEventListener('keydown', this._handleKeyDown);\n }\n\n override disconnectedCallback(): void {\n super.disconnectedCallback();\n this.removeEventListener('focusin', this._handleFocusIn);\n this.removeEventListener('focusout', this._handleFocusOut);\n this.removeEventListener('pointerdown', this._handlePointerDown);\n this.removeEventListener('keydown', this._handleKeyDown);\n }\n\n override firstUpdated(changedProperties: PropertyValues): void {\n super.firstUpdated(changedProperties);\n\n // Honour the native `autofocus` attribute after the first render cycle\n if (this.hasAttribute('autofocus')) {\n this.focus();\n }\n\n // Flush any focus() call that arrived before the shadow DOM was stamped\n if (this._focusPending) {\n this._focusPending = false;\n this.focus();\n }\n }\n\n // ─── Private Event Handlers ────────────────────────────────────────────────\n\n /** @internal */\n private _handleFocusIn = (): void => {\n this.focused = true;\n // focusedVisible is true only when focus arrived via keyboard\n this.focusedVisible = !this._lastInteractionWasPointer;\n };\n\n /** @internal */\n private _handleFocusOut = (): void => {\n this.focused = false;\n this.focusedVisible = false;\n // Reset for the next interaction cycle\n this._lastInteractionWasPointer = false;\n };\n\n /**\n * Marks the next focusin as pointer-initiated.\n * @internal\n */\n private _handlePointerDown = (): void => {\n this._lastInteractionWasPointer = true;\n };\n\n /**\n * Ensures that keyboard navigation (Tab / Shift+Tab arriving from outside)\n * is correctly flagged as keyboard-initiated even when no prior `pointerdown`\n * fired on this element.\n *\n * This fires BEFORE `focusin` so the flag is in the correct state when\n * `_handleFocusIn` runs.\n * @internal\n */\n private _handleKeyDown = (): void => {\n this._lastInteractionWasPointer = false;\n };\n }\n\n return FocusMixinClass as unknown as T & Constructor<FocusMixinInterface>;\n};\n","import { css } from 'lit';\n\n/**\n * hx-text-input styles.\n *\n * Component-tier tokens introduced in 3.2.0 — every visual property exposes\n * `--hx-text-input-*` overrides while preserving backward-compatible\n * `--hx-input-*` aliases that earlier consumers may already use.\n *\n * Two-level var() fallback pattern is canonical:\n * var(--hx-text-input-{prop}, var(--hx-color-{semantic}, #hex))\n * Inner hex fallbacks track the \"precision cool\" palette (primary-600=#0F7078,\n * neutral-200=#D6DBD5, etc.) introduced in the same release.\n */\nexport const helixTextInputStyles = css`\n :host {\n display: block;\n\n /* ─── Component tokens (3.2.0) ──────────────────────────────────── */\n\n /* Surface */\n --_text-input-bg: var(\n --hx-text-input-bg,\n var(--hx-input-bg, var(--hx-color-surface-default, #ffffff))\n );\n --_text-input-color: var(\n --hx-text-input-color,\n var(--hx-input-color, var(--hx-color-text-strong, #202b39))\n );\n --_text-input-placeholder-color: var(\n --hx-text-input-placeholder-color,\n var(--hx-color-text-placeholder, #66787b)\n );\n\n /* Border */\n --_text-input-border-color: var(\n --hx-text-input-border-color,\n var(--hx-input-border-color, var(--hx-color-border-strong, #66787b))\n );\n --_text-input-border-color-hover: var(\n --hx-text-input-border-color-hover,\n var(--hx-color-border-strong, #66787b)\n );\n --_text-input-border-color-focus: var(\n --hx-text-input-border-color-focus,\n var(\n --hx-input-focus-ring-color,\n var(--hx-focus-ring-color, var(--hx-color-primary-600, #0f7078))\n )\n );\n --_text-input-border-color-invalid: var(\n --hx-text-input-border-color-invalid,\n var(--hx-input-error-color, var(--hx-color-error-600, #c92a2a))\n );\n --_text-input-border-width: var(--hx-text-input-border-width, var(--hx-border-width-thin, 1px));\n --_text-input-border-radius: var(\n --hx-text-input-border-radius,\n var(--hx-input-border-radius, var(--hx-border-radius-md, 0.375rem))\n );\n\n /* Spacing */\n --_text-input-padding-x: var(--hx-text-input-padding-x, var(--hx-space-3, 0.75rem));\n --_text-input-padding-y: var(--hx-text-input-padding-y, var(--hx-space-2, 0.5rem));\n\n /* Typography */\n --_text-input-font-family: var(\n --hx-text-input-font-family,\n var(--hx-input-font-family, var(--hx-font-family-sans, sans-serif))\n );\n --_text-input-font-size: var(--hx-text-input-font-size, var(--hx-font-size-md, 1rem));\n\n /* Focus ring */\n --_text-input-focus-ring-color: var(\n --hx-text-input-focus-ring-color,\n var(\n --hx-input-focus-ring-color,\n var(--hx-focus-ring-color, var(--hx-color-primary-600, #0f7078))\n )\n );\n --_text-input-focus-ring-width: var(\n --hx-text-input-focus-ring-width,\n var(--hx-focus-ring-width, 2px)\n );\n --_text-input-focus-ring-offset: var(\n --hx-text-input-focus-ring-offset,\n var(--hx-focus-ring-offset, 0px)\n );\n\n /* Disabled */\n --_text-input-disabled-bg: var(\n --hx-text-input-disabled-bg,\n var(--hx-color-surface-sunken, #ebeee9)\n );\n --_text-input-disabled-color: var(\n --hx-text-input-disabled-color,\n var(--hx-color-text-disabled, #8e9c98)\n );\n\n /* Label / help / error */\n --_text-input-label-color: var(\n --hx-text-input-label-color,\n var(--hx-input-label-color, var(--hx-color-text-strong, #202b39))\n );\n --_text-input-help-text-color: var(\n --hx-text-input-help-text-color,\n var(--hx-color-text-muted, #4a5362)\n );\n --_text-input-error-color: var(\n --hx-text-input-error-color,\n var(--hx-input-error-color, var(--hx-color-error-text, #c92a2a))\n );\n }\n\n :host([disabled]) {\n opacity: var(--hx-opacity-disabled, 0.5);\n pointer-events: none;\n }\n\n /*\n * Attribute-based focus hooks set by FocusMixin.\n * :host([focused]) — fires whenever the component or any descendant has focus.\n * :host([focused-visible]) — fires only for keyboard-initiated focus.\n * These complement the :focus-within rules on .field__input-wrapper and are\n * exposed as theming hooks for consumers who target the host element.\n */\n :host([focused]) .field__input-wrapper,\n :host([focused-visible]) .field__input-wrapper {\n border-color: var(--_text-input-border-color-focus);\n box-shadow: 0 0 0 var(--_text-input-focus-ring-width)\n color-mix(\n in srgb,\n var(--_text-input-border-color-focus) calc(var(--hx-focus-ring-opacity, 0.25) * 100%),\n transparent\n );\n }\n\n * {\n box-sizing: border-box;\n }\n\n .field {\n display: flex;\n flex-direction: column;\n gap: var(--hx-space-1, 0.25rem);\n font-family: var(--_text-input-font-family);\n }\n\n /* ─── Label ─── */\n\n .field__label-wrapper {\n display: contents;\n }\n\n .field__label {\n display: flex;\n align-items: baseline;\n gap: var(--hx-space-1, 0.25rem);\n font-size: var(--hx-font-size-sm, 0.875rem);\n font-weight: var(--hx-font-weight-medium, 500);\n color: var(--_text-input-label-color);\n line-height: var(--hx-line-height-normal, 1.5);\n }\n\n .field__required-marker {\n color: var(--_text-input-error-color);\n font-weight: var(--hx-font-weight-bold, 700);\n }\n\n /* ─── Input Wrapper ─── */\n\n .field__input-wrapper {\n display: flex;\n align-items: center;\n border: var(--_text-input-border-width) solid var(--_text-input-border-color);\n border-radius: var(--_text-input-border-radius);\n background-color: var(--_text-input-bg);\n transition:\n border-color var(--hx-transition-fast, 150ms ease),\n box-shadow var(--hx-transition-fast, 150ms ease);\n overflow: hidden;\n }\n\n .field__input-wrapper:hover {\n border-color: var(--_text-input-border-color-hover);\n }\n\n .field__input-wrapper:focus-within {\n border-color: var(--_text-input-border-color-focus);\n box-shadow: 0 0 0 var(--_text-input-focus-ring-width)\n color-mix(\n in srgb,\n var(--_text-input-border-color-focus) calc(var(--hx-focus-ring-opacity, 0.25) * 100%),\n transparent\n );\n }\n\n /* ─── Error State ─── */\n\n .field--error .field__input-wrapper {\n border-color: var(--_text-input-border-color-invalid);\n }\n\n .field--error .field__input-wrapper:focus-within {\n border-color: var(--_text-input-border-color-invalid);\n box-shadow: 0 0 0 var(--_text-input-focus-ring-width)\n color-mix(\n in srgb,\n var(--_text-input-border-color-invalid) calc(var(--hx-focus-ring-opacity, 0.25) * 100%),\n transparent\n );\n }\n\n /* ─── Slots (Prefix / Suffix) ─── */\n\n .field__prefix,\n .field__suffix {\n display: flex;\n align-items: center;\n color: var(--hx-color-text-muted, #4a5362);\n flex-shrink: 0;\n }\n\n /* Only add padding when slot has content — avoids phantom space on empty slots */\n .field__prefix--filled {\n padding: 0 var(--_text-input-padding-x);\n }\n\n .field__suffix--filled {\n padding: 0 var(--_text-input-padding-x);\n }\n\n /* ─── Native Input ─── */\n\n .field__input {\n flex: 1;\n border: none;\n outline: none;\n background: transparent;\n padding: var(--_text-input-padding-y) var(--_text-input-padding-x);\n font-family: inherit;\n font-size: var(--_text-input-font-size);\n color: var(--_text-input-color);\n line-height: var(--hx-line-height-normal, 1.5);\n min-height: var(--hx-size-10, 2.5rem);\n width: 100%;\n }\n\n .field__input::placeholder {\n color: var(--_text-input-placeholder-color);\n }\n\n .field__input:focus-visible {\n outline: none; /* wrapper ring handles keyboard focus indication */\n }\n\n .field__input:disabled {\n cursor: not-allowed;\n background-color: var(--_text-input-disabled-bg);\n color: var(--_text-input-disabled-color);\n }\n\n :host([disabled]) .field__input-wrapper {\n background-color: var(--_text-input-disabled-bg);\n }\n\n /* ─── Size Variants ─── */\n\n .field--size-sm .field__input {\n padding: var(--hx-space-1, 0.25rem) var(--hx-space-2, 0.5rem);\n min-height: var(--hx-size-8, 2rem);\n font-size: var(--hx-text-input-sm-font-size, var(--hx-input-sm-font-size, 0.875rem));\n }\n\n .field--size-md .field__input {\n /* md is the default — no overrides needed */\n }\n\n .field--size-lg .field__input {\n padding: var(--hx-space-3, 0.75rem) var(--hx-space-4, 1rem);\n min-height: var(--hx-size-12, 3rem);\n font-size: var(--hx-text-input-lg-font-size, var(--hx-input-lg-font-size, 1.125rem));\n }\n\n /* ─── Help Text & Error Messages ─── */\n\n .field__help-text {\n font-size: var(--hx-font-size-xs, 0.75rem);\n color: var(--_text-input-help-text-color);\n line-height: var(--hx-line-height-normal, 1.5);\n }\n\n .field__error {\n font-size: var(--hx-font-size-xs, 0.75rem);\n color: var(--_text-input-error-color);\n line-height: var(--hx-line-height-normal, 1.5);\n }\n\n /* ─── Motion ─── */\n\n @media (prefers-reduced-motion: reduce) {\n .field__input-wrapper {\n transition: none;\n }\n }\n\n /* ─── High Contrast Mode (forced-colors) ───\n *\n * Bespoke block — sole owner of forced-colors deference for hx-text-input.\n * Covers wrapper/input/placeholder/focus/disabled/error/label/help-text;\n * strictly more than forcedColorsField. The mixin is intentionally NOT\n * composed (XOR rule — see styles/forced-colors.ts COMPOSITION RULES).\n */\n\n @media (forced-colors: active) {\n .field__input-wrapper {\n forced-color-adjust: none;\n background-color: Field;\n color: FieldText;\n border: 2px solid ButtonText;\n }\n\n .field__input {\n color: FieldText;\n }\n\n .field__input::placeholder {\n color: GrayText;\n }\n\n .field__input-wrapper:focus-within {\n border-color: Highlight;\n box-shadow: none;\n }\n\n .field__input:focus-visible {\n outline: 3px solid Highlight;\n outline-offset: -3px;\n }\n\n :host([disabled]) {\n opacity: 1;\n }\n\n :host([disabled]) .field__input-wrapper {\n border-color: GrayText;\n color: GrayText;\n }\n\n :host([disabled]) .field__input {\n color: GrayText;\n }\n\n .field--error .field__input-wrapper {\n border-color: LinkText;\n }\n\n .field__label {\n color: CanvasText;\n }\n\n .field__help-text {\n color: GrayText;\n }\n\n .field__error {\n color: LinkText;\n }\n }\n`;\n","import { html, nothing, type PropertyValues } from 'lit';\nimport '../../utilities/document-token-adoption.js';\nimport { customElement, property, query, state } from 'lit/decorators.js';\nimport { classMap } from 'lit/directives/class-map.js';\nimport { ifDefined } from 'lit/directives/if-defined.js';\nimport { live } from 'lit/directives/live.js';\nimport { HelixElement, createIdCounter } from '../../base/index.js';\nimport { FocusMixin } from '../../mixins/index.js';\nimport { FormMixin } from '../../mixins/FormMixin.js';\nimport { helixTextInputStyles } from './hx-text-input.styles.js';\nimport { devWarn } from '../../utils/dev-warn.js';\n\n// Module-level counter for stable, SSR-compatible IDs (avoids Math.random() hydration mismatch)\nconst _nextTextInputId = createIdCounter('hx-text-input');\n\n/** Detail for hx-input and hx-change events dispatched by hx-text-input. */\nexport interface HxTextInputDetail {\n value: string;\n}\n\n/**\n * A text input component with label, validation, and form association.\n * Supports accessible labeling via `label` property, `aria-label` attribute, or the `label` slot.\n * Uses `aria-invalid` and `aria-describedby` on the native input for screen reader support. Native `required` provides implicit aria-required mapping per HTML-AAM.\n * Error messages are announced via `role=\"alert\"`. Keyboard navigation follows native input behavior.\n *\n * @summary Form-associated text input with built-in label, error, and help text.\n *\n * @tag hx-text-input\n *\n * @slot label - Custom label content (overrides the label property). Use for Drupal Form API rendered labels.\n * @slot prefix - Content rendered before the input (e.g., icon).\n * @slot suffix - Content rendered after the input (e.g., icon or button).\n * @slot help-text - Custom help text content (overrides the helpText property).\n * @slot error - Custom error content (overrides the error property). Use for Drupal Form API rendered errors.\n *\n * @fires {CustomEvent<{value: string}>} hx-input - Dispatched on every keystroke as the user types.\n * @fires {CustomEvent<{value: string}>} hx-change - Dispatched when the input loses focus after its value changed.\n *\n * @csspart field - The outer field container.\n * @csspart label - The label element.\n * @csspart input-wrapper - The wrapper around prefix, input, and suffix.\n * @csspart input - The native input element.\n * @csspart help-text - The help text container.\n * @csspart error - The error message container.\n *\n * @cssprop [--hx-input-bg=var(--hx-color-surface-default)] - Input background color.\n * @cssprop [--hx-input-color=var(--hx-color-text-strong)] - Input text color.\n * @cssprop [--hx-input-border-color=var(--hx-color-border-strong)] - Input border color.\n * @cssprop [--hx-input-border-radius=var(--hx-border-radius-md)] - Input border radius.\n * @cssprop [--hx-input-font-family=var(--hx-font-family-sans)] - Input font family.\n * @cssprop [--hx-input-focus-ring-color=var(--hx-focus-ring-color)] - Focus ring color.\n * @cssprop [--hx-input-error-color=var(--hx-color-error-text)] - Error state color.\n * @cssprop [--hx-input-label-color=var(--hx-color-text-strong)] - Label text color.\n * @cssprop [--hx-input-sm-font-size=0.875rem] - Font size for the sm size variant.\n * @cssprop [--hx-input-lg-font-size=1.125rem] - Font size for the lg size variant.\n *\n * @cssprop [--hx-text-input-border-width=var(--hx-border-width-thin)] - Outer border-width override (canonical hx-{tag}-* prefix; sits above --hx-input-* aliases in the cascade).\n * @cssprop [--hx-text-input-padding-x=var(--hx-space-3)] - Outer horizontal padding override.\n * @cssprop [--hx-text-input-padding-y=var(--hx-space-2)] - Outer vertical padding override.\n * @cssprop [--hx-text-input-font-size=var(--hx-font-size-md)] - Outer font-size override.\n * @cssprop [--hx-text-input-sm-font-size] - Outer sm-variant font-size override (falls through to --hx-input-sm-font-size).\n * @cssprop [--hx-text-input-lg-font-size] - Outer lg-variant font-size override (falls through to --hx-input-lg-font-size).\n *\n * @cssprop [--hx-color-surface-default] - Resting field surface (semantic).\n * @cssprop [--hx-color-text-strong] - Resting input text + label color (semantic).\n * @cssprop [--hx-color-border-strong] - Resting border color (semantic).\n * @cssprop [--hx-color-error-text] - Error state text + border color (semantic).\n * @cssprop [--hx-color-error-600] - Error border primitive fallback inside the invalid-state cascade.\n */\n@customElement('hx-text-input')\nexport class HelixTextInput extends FocusMixin(FormMixin(HelixElement)) {\n // 3.2.1: forced-colors deference is owned by the bespoke @media block in\n // hx-text-input.styles.ts (covers wrapper/input/placeholder/focus/disabled/\n // error/label/help-text — strictly more than the shared mixin). XOR rule:\n // do NOT also compose forcedColorsField — overlapping selectors inside the\n // same media query create a fragile specificity war.\n static override styles = [helixTextInputStyles];\n\n // ─── Form Association ───\n\n /** @internal */\n static override formAssociated = true;\n\n // ─── Properties ───\n\n /**\n * The visible label text for the input.\n * @attr label\n */\n @property({ type: String })\n label = '';\n\n /**\n * Placeholder text shown when the input is empty.\n * @attr placeholder\n */\n @property({ type: String })\n placeholder = '';\n\n /**\n * The current value of the input.\n * @attr value\n * @remarks When `null` is passed programmatically, Lit coerces it to an empty string.\n * This is expected behavior — the input treats null as equivalent to an empty string value.\n */\n @property({ type: String })\n value = '';\n\n /**\n * The type of the native input element.\n * @attr type\n */\n @property({ type: String })\n type: 'text' | 'email' | 'password' | 'tel' | 'url' | 'search' | 'number' | 'date' = 'text';\n\n /**\n * Whether the input is required for form submission.\n * @attr required\n */\n @property({ type: Boolean, reflect: true })\n required = false;\n\n /**\n * Whether the input is disabled.\n * @attr disabled\n */\n @property({ type: Boolean, reflect: true })\n disabled = false;\n\n /**\n * Error message to display. When set, the input enters an error state.\n * @attr error\n */\n @property({ type: String })\n error = '';\n\n /**\n * Help text displayed below the input for guidance.\n * @attr help-text\n */\n @property({ type: String, attribute: 'help-text' })\n helpText = '';\n\n /**\n * The name of the input, used for form submission.\n * @attr name\n */\n @property({ type: String, reflect: true })\n name = '';\n\n /**\n * Accessible name for screen readers, if different from the visible label.\n * Uses `accessible-label` attribute instead of `aria-label` to avoid\n * ARIAMixin shadowing on the host element. The value is forwarded to the\n * internal native input's `aria-label`.\n *\n * Note: `mixinDelegatesAria` is not applied to this component because form\n * inputs with associated labels delegate accessible naming via `<label>`\n * association and `aria-labelledby`, not host-level ARIA delegation. The\n * `accessible-label` attribute is a fallback for label-free usage.\n * @attr accessible-label\n */\n @property({ type: String, attribute: 'accessible-label' })\n accessibleLabel: string | null = null;\n\n /**\n * Whether the input is read-only.\n * @attr readonly\n */\n @property({ type: Boolean, reflect: true })\n readonly = false;\n\n /**\n * Minimum number of characters allowed.\n * @attr minlength\n */\n @property({ type: Number })\n minlength: number | undefined = undefined;\n\n /**\n * Maximum number of characters allowed.\n * @attr maxlength\n */\n @property({ type: Number })\n maxlength: number | undefined = undefined;\n\n /**\n * A regular expression pattern the value must match for form validation.\n * @attr pattern\n */\n @property({ type: String })\n pattern = '';\n\n /**\n * Hint for the browser's autocomplete feature. Accepts standard HTML autocomplete values.\n * @attr autocomplete\n */\n @property({ type: String })\n autocomplete = '';\n\n /**\n * Validation message shown when the field is required but empty.\n * @attr required-message\n */\n @property({ attribute: 'required-message' })\n requiredMessage = 'This field is required.';\n\n /**\n * Visual size of the input field.\n * @attr hx-size\n */\n @property({ type: String, attribute: 'hx-size', reflect: true })\n size: 'sm' | 'md' | 'lg' = 'md';\n\n // ─── Internal References ───\n\n /** @internal */\n @query('.field__input')\n private _input: HTMLInputElement | undefined;\n\n // ─── FocusMixin integration ───\n\n /**\n * Declares the inner focusable element for FocusMixin delegation.\n * @internal\n */\n protected get _focusableNode(): HTMLElement | null {\n return this._input ?? null;\n }\n\n // ─── Slot Tracking ───\n\n /** @internal */\n @state() private _hasLabelSlot = false;\n /** @internal */\n @state() private _hasErrorSlot = false;\n /** @internal */\n @state() private _hasPrefixSlot = false;\n /** @internal */\n @state() private _hasSuffixSlot = false;\n /** @internal */\n @state() private _hasHelpTextSlot = false;\n\n /** @internal */\n private _handleLabelSlotChange(e: Event): void {\n const slot = e.target as HTMLSlotElement;\n this._hasLabelSlot = slot.assignedElements().length > 0;\n if (this._hasLabelSlot) {\n const slottedLabel = slot.assignedElements()[0];\n if (slottedLabel && !slottedLabel.id) {\n slottedLabel.id = `${this._inputId}-slotted-label`;\n }\n }\n }\n\n /** @internal */\n private _handleErrorSlotChange(e: Event): void {\n const slot = e.target as HTMLSlotElement;\n this._hasErrorSlot = slot.assignedElements().length > 0;\n }\n\n /** @internal */\n private _handlePrefixSlotChange(e: Event): void {\n const slot = e.target as HTMLSlotElement;\n this._hasPrefixSlot = slot.assignedElements().length > 0;\n }\n\n /** @internal */\n private _handleSuffixSlotChange(e: Event): void {\n const slot = e.target as HTMLSlotElement;\n this._hasSuffixSlot = slot.assignedElements().length > 0;\n }\n\n /** @internal */\n private _handleHelpTextSlotChange(e: Event): void {\n const slot = e.target as HTMLSlotElement;\n this._hasHelpTextSlot = slot.assignedElements().length > 0;\n }\n\n // ─── Lifecycle ───\n\n override updated(changedProperties: PropertyValues<this>): void {\n super.updated(changedProperties);\n if (changedProperties.has('value')) {\n this._internals.setFormValue(this.value);\n }\n if (\n (changedProperties.has('value') || changedProperties.has('type')) &&\n this.type === 'number' &&\n this.value !== '' &&\n isNaN(Number(this.value))\n ) {\n devWarn(\n 'hx-text-input',\n `type=\"number\" received non-numeric value \"${this.value}\". Browser will display empty input.`,\n );\n }\n }\n\n // ─── Form Integration ───\n\n /** Returns the associated form element, if any. */\n override get form(): HTMLFormElement | null {\n return this._internals.form;\n }\n\n /** Returns the validation message. */\n override get validationMessage(): string {\n return this._internals.validationMessage;\n }\n\n /** Returns the ValidityState object. */\n override get validity(): ValidityState {\n return this._internals.validity;\n }\n\n /** @internal */\n _updateValidity(): void {\n if (this.required && !this.value) {\n this._internals.setValidity(\n { valueMissing: true },\n this.error || this.requiredMessage,\n this._input,\n );\n } else if (\n this.minlength !== undefined &&\n this.value.length > 0 &&\n this.value.length < this.minlength\n ) {\n this._internals.setValidity(\n { tooShort: true },\n this.error || `Please lengthen this text to ${this.minlength} characters or more.`,\n this._input,\n );\n } else if (this.maxlength !== undefined && this.value.length > this.maxlength) {\n this._internals.setValidity(\n { tooLong: true },\n this.error || `Please shorten this text to ${this.maxlength} characters or fewer.`,\n this._input,\n );\n } else {\n this._internals.setValidity({});\n }\n }\n\n // ─── Form Lifecycle Hooks ───\n\n protected override _onFormReset(): void {\n this.value = '';\n this._internals.setFormValue('');\n this._resetInteractionState();\n }\n\n protected override _onFormStateRestore(\n state: File | string | FormData | null,\n _mode: 'restore' | 'autocomplete',\n ): void {\n if (typeof state === 'string') {\n this.value = state;\n }\n }\n\n protected override _onFormDisabled(disabled: boolean): void {\n this.disabled = disabled;\n }\n\n // ─── Event Handling ───\n\n /** @internal */\n private _handleInput(e: Event): void {\n const target = e.target as HTMLInputElement;\n this.value = target.value;\n this._internals.setFormValue(this.value);\n this._handleInteractionInput();\n\n /**\n * Dispatched on every keystroke as the user types.\n * @event hx-input\n */\n this.dispatchEvent(\n new CustomEvent<{ value: string }>('hx-input', {\n bubbles: true,\n composed: true,\n detail: { value: this.value },\n }),\n );\n }\n\n /** @internal */\n private _handleChange(e: Event): void {\n const target = e.target as HTMLInputElement;\n this.value = target.value;\n this._internals.setFormValue(this.value);\n this._handleInteractionBlur();\n\n /**\n * Dispatched when the input loses focus after its value changed.\n * @event hx-change\n */\n this.dispatchEvent(\n new CustomEvent<{ value: string }>('hx-change', {\n bubbles: true,\n composed: true,\n detail: { value: this.value },\n }),\n );\n }\n\n // ─── Public Methods ───\n\n /** Selects all text in the input. */\n select(): void {\n this._input?.select();\n }\n\n // ─── Render ───\n\n /** @internal */\n private _inputId = _nextTextInputId();\n /** @internal */\n private _helpTextId = `${this._inputId}-help`;\n /** @internal */\n private _errorId = `${this._inputId}-error`;\n\n override render() {\n const hasError = !!this.error || this._hasErrorSlot;\n\n const fieldClasses = {\n field: true,\n 'field--error': hasError,\n 'field--disabled': this.disabled,\n 'field--required': this.required,\n [`field--size-${this.size}`]: true,\n };\n\n const describedBy =\n [\n hasError ? this._errorId : null,\n this.helpText || this._hasHelpTextSlot ? this._helpTextId : null,\n ]\n .filter(Boolean)\n .join(' ') || undefined;\n\n return html`\n <div part=\"field\" class=${classMap(fieldClasses)}>\n <div class=\"field__label-wrapper\">\n <slot name=\"label\" @slotchange=${this._handleLabelSlotChange}>\n ${this.label\n ? html`\n <label part=\"label\" class=\"field__label\" for=${this._inputId}>\n ${this.label}\n ${this.required\n ? html`<span class=\"field__required-marker\" aria-hidden=\"true\">*</span>`\n : nothing}\n </label>\n `\n : nothing}\n </slot>\n </div>\n\n <div part=\"input-wrapper\" class=\"field__input-wrapper\">\n <span\n class=${classMap({\n field__prefix: true,\n 'field__prefix--filled': this._hasPrefixSlot,\n })}\n >\n <slot name=\"prefix\" @slotchange=${this._handlePrefixSlotChange}></slot>\n </span>\n\n <input\n part=\"input\"\n class=\"field__input\"\n id=${this._inputId}\n type=${this.type}\n .value=${live(this.value)}\n placeholder=${ifDefined(this.placeholder || undefined)}\n ?required=${this.required}\n ?disabled=${this.disabled}\n ?readonly=${this.readonly}\n name=${ifDefined(this.name || undefined)}\n minlength=${ifDefined(this.minlength)}\n maxlength=${ifDefined(this.maxlength)}\n pattern=${ifDefined(this.pattern || undefined)}\n autocomplete=${ifDefined(this.autocomplete || undefined)}\n aria-label=${ifDefined(this.accessibleLabel || undefined)}\n aria-labelledby=${ifDefined(\n this._hasLabelSlot ? `${this._inputId}-slotted-label` : undefined,\n )}\n aria-invalid=${hasError ? 'true' : nothing}\n aria-describedby=${ifDefined(describedBy)}\n @input=${this._handleInput}\n @change=${this._handleChange}\n />\n\n <span\n class=${classMap({\n field__suffix: true,\n 'field__suffix--filled': this._hasSuffixSlot,\n })}\n >\n <slot name=\"suffix\" @slotchange=${this._handleSuffixSlotChange}></slot>\n </span>\n </div>\n\n ${hasError\n ? html`<div\n part=\"error\"\n class=\"field__error\"\n id=${this._errorId}\n role=\"alert\"\n aria-atomic=\"true\"\n >\n <slot name=\"error\" @slotchange=${this._handleErrorSlotChange}>${this.error}</slot>\n </div>`\n : html`<slot name=\"error\" @slotchange=${this._handleErrorSlotChange}></slot>`}\n ${this._hasHelpTextSlot\n ? html`\n <div part=\"help-text\" class=\"field__help-text\" id=${this._helpTextId}>\n <slot name=\"help-text\" @slotchange=${this._handleHelpTextSlotChange}>\n ${this.helpText}\n </slot>\n </div>\n `\n : this.helpText && !hasError\n ? html`\n <div part=\"help-text\" class=\"field__help-text\" id=${this._helpTextId}>\n <slot name=\"help-text\" @slotchange=${this._handleHelpTextSlotChange}>\n ${this.helpText}\n </slot>\n </div>\n `\n : html`<slot name=\"help-text\" @slotchange=${this._handleHelpTextSlotChange}></slot>`}\n </div>\n `;\n }\n}\n\n/**\n * Per-component event map for type-safe addEventListener on hx-text-input.\n * The `hx-change` detail is `{ value: string }` only — no `checked` property.\n */\nexport interface HxTextInputEventMap {\n 'hx-input': CustomEvent<{ value: string }>;\n 'hx-change': CustomEvent<{ value: string }>;\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'hx-text-input': HelixTextInput;\n }\n interface HTMLElementEventMap {\n 'hx-input': CustomEvent<{ value: string }>;\n }\n}\n\n/** Primary type alias for hx-text-input */\nexport type HxTextInput = HelixTextInput;\n"],"names":["FocusMixin","superClass","FocusMixinClass","options","node","_a","changedProperties","__decorateClass","property","helixTextInputStyles","css","_nextTextInputId","createIdCounter","HelixTextInput","FormMixin","HelixElement","slot","slottedLabel","devWarn","state","_mode","disabled","target","hasError","fieldClasses","describedBy","html","classMap","nothing","live","ifDefined","query","customElement"],"mappings":"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"}
|
|
@@ -2,8 +2,8 @@ import { css as u, nothing as d, html as l } from "lit";
|
|
|
2
2
|
import { property as o, query as _, state as x, customElement as f } from "lit/decorators.js";
|
|
3
3
|
import { classMap as v } from "lit/directives/class-map.js";
|
|
4
4
|
import { ifDefined as n } from "lit/directives/if-defined.js";
|
|
5
|
-
import { live as
|
|
6
|
-
import { F as
|
|
5
|
+
import { live as m } from "lit/directives/live.js";
|
|
6
|
+
import { F as b } from "./FormMixin-B8PXk5RQ.js";
|
|
7
7
|
import { b as g } from "./forced-colors-CTEDFRGa.js";
|
|
8
8
|
import { H as y } from "./helix-element-BNEYeiys.js";
|
|
9
9
|
import { c as w } from "./id-counter-DuX8vsui.js";
|
|
@@ -22,13 +22,13 @@ const $ = u`
|
|
|
22
22
|
);
|
|
23
23
|
--_textarea-border-color: var(
|
|
24
24
|
--hx-textarea-border-color,
|
|
25
|
-
var(--hx-input-border-color, var(--hx-color-border-strong, #
|
|
25
|
+
var(--hx-input-border-color, var(--hx-color-border-strong, #66787b))
|
|
26
26
|
);
|
|
27
27
|
--_textarea-border-color-focus: var(
|
|
28
28
|
--hx-textarea-border-color-focus,
|
|
29
29
|
var(
|
|
30
30
|
--hx-input-focus-ring-color,
|
|
31
|
-
var(--hx-focus-ring-color, var(--hx-color-primary-
|
|
31
|
+
var(--hx-focus-ring-color, var(--hx-color-primary-600, #0f7078))
|
|
32
32
|
)
|
|
33
33
|
);
|
|
34
34
|
--_textarea-border-color-invalid: var(
|
|
@@ -289,7 +289,7 @@ var T = Object.defineProperty, S = Object.getOwnPropertyDescriptor, a = (e, t, i
|
|
|
289
289
|
return h && s && T(t, i, s), s;
|
|
290
290
|
};
|
|
291
291
|
const z = w("hx-textarea");
|
|
292
|
-
let r = class extends
|
|
292
|
+
let r = class extends b(y) {
|
|
293
293
|
constructor() {
|
|
294
294
|
super(...arguments), this.label = "", this.placeholder = "", this.value = "", this.required = !1, this.disabled = !1, this.error = "", this.helpText = "", this.name = "", this.rows = 4, this.readonly = !1, this.resize = "vertical", this.showCount = !1, this.requiredMessage = "This field is required.", this.accessibleLabel = null, this._hasLabelSlot = !1, this._hasErrorSlot = !1, this._hasHelpTextSlot = !1, this._liveAnnouncement = "", this._announceTimer = null, this._textareaId = z(), this._helpTextId = `${this._textareaId}-help`, this._errorId = `${this._textareaId}-error`, this._counterId = `${this._textareaId}-counter`;
|
|
295
295
|
}
|
|
@@ -423,7 +423,7 @@ let r = class extends m(y) {
|
|
|
423
423
|
part="textarea"
|
|
424
424
|
class="field__textarea"
|
|
425
425
|
id=${this._textareaId}
|
|
426
|
-
.value=${
|
|
426
|
+
.value=${m(this.value)}
|
|
427
427
|
placeholder=${n(this.placeholder || void 0)}
|
|
428
428
|
?required=${this.required}
|
|
429
429
|
?disabled=${this.disabled}
|
|
@@ -532,4 +532,4 @@ r = a([
|
|
|
532
532
|
export {
|
|
533
533
|
r as H
|
|
534
534
|
};
|
|
535
|
-
//# sourceMappingURL=hx-textarea-
|
|
535
|
+
//# sourceMappingURL=hx-textarea-Jx1xnhgv.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hx-textarea-D9O4U8cb.js","sources":["../../src/components/hx-textarea/hx-textarea.styles.ts","../../src/components/hx-textarea/hx-textarea.ts"],"sourcesContent":["import { css } from 'lit';\n\nexport const helixTextareaStyles = css`\n :host {\n display: block;\n\n /* ─── Component tokens (3.2.0) ──────────────────────────────────── */\n --_textarea-bg: var(\n --hx-textarea-bg,\n var(--hx-input-bg, var(--hx-color-surface-default, #ffffff))\n );\n --_textarea-color: var(\n --hx-textarea-color,\n var(--hx-input-color, var(--hx-color-text-strong, #202b39))\n );\n --_textarea-border-color: var(\n --hx-textarea-border-color,\n var(--hx-input-border-color, var(--hx-color-border-strong, #8e9c98))\n );\n --_textarea-border-color-focus: var(\n --hx-textarea-border-color-focus,\n var(\n --hx-input-focus-ring-color,\n var(--hx-focus-ring-color, var(--hx-color-primary-400, #6ab1b1))\n )\n );\n --_textarea-border-color-invalid: var(\n --hx-textarea-border-color-invalid,\n var(--hx-input-error-color, var(--hx-color-error-600, #c92a2a))\n );\n --_textarea-border-radius: var(\n --hx-textarea-border-radius,\n var(--hx-input-border-radius, var(--hx-border-radius-md, 0.375rem))\n );\n --_textarea-padding-x: var(--hx-textarea-padding-x, var(--hx-space-3, 0.75rem));\n --_textarea-padding-y: var(--hx-textarea-padding-y, var(--hx-space-2, 0.5rem));\n --_textarea-font-size: var(--hx-textarea-font-size, var(--hx-font-size-md, 1rem));\n --_textarea-placeholder-color: var(\n --hx-textarea-placeholder-color,\n var(--hx-color-text-placeholder, #66787b)\n );\n }\n\n :host([disabled]) {\n opacity: var(--hx-opacity-disabled, 0.5);\n pointer-events: none;\n }\n\n * {\n box-sizing: border-box;\n }\n\n .field {\n display: flex;\n flex-direction: column;\n gap: var(--hx-space-1, 0.25rem);\n font-family: var(\n --hx-textarea-font-family,\n var(--hx-input-font-family, var(--hx-font-family-sans, sans-serif))\n );\n }\n\n /* --- Label --- */\n\n .field__label-wrapper {\n display: contents;\n }\n\n .field__label {\n display: flex;\n align-items: baseline;\n gap: var(--hx-space-1, 0.25rem);\n font-size: var(--hx-font-size-sm, 0.875rem);\n font-weight: var(--hx-font-weight-medium, 500);\n color: var(\n --hx-textarea-label-color,\n var(--hx-input-label-color, var(--hx-color-text-strong, #202b39))\n );\n line-height: var(--hx-line-height-normal, 1.5);\n }\n\n .field__required-marker {\n color: var(\n --hx-textarea-error-color,\n var(--hx-input-error-color, var(--hx-color-error-text, #c92a2a))\n );\n font-weight: var(--hx-font-weight-bold, 700);\n }\n\n /* --- Textarea Wrapper --- */\n\n .field__textarea-wrapper {\n display: flex;\n flex-direction: column;\n border: var(--hx-border-width-thin, 1px) solid var(--_textarea-border-color);\n border-radius: var(--_textarea-border-radius);\n background-color: var(--_textarea-bg);\n transition:\n border-color var(--hx-transition-fast, 150ms ease),\n box-shadow var(--hx-transition-fast, 150ms ease);\n overflow: hidden;\n }\n\n .field__textarea-wrapper:focus-within {\n border-color: var(--_textarea-border-color-focus);\n box-shadow: 0 0 0 var(--hx-focus-ring-width, 2px)\n color-mix(\n in srgb,\n var(--_textarea-border-color-focus) calc(var(--hx-focus-ring-opacity, 0.25) * 100%),\n transparent\n );\n }\n\n /* --- Error State --- */\n\n .field--error .field__textarea-wrapper {\n border-color: var(--_textarea-border-color-invalid);\n }\n\n .field--error .field__textarea-wrapper:focus-within {\n border-color: var(--_textarea-border-color-invalid);\n box-shadow: 0 0 0 var(--hx-focus-ring-width, 2px)\n color-mix(\n in srgb,\n var(--_textarea-border-color-invalid) calc(var(--hx-focus-ring-opacity, 0.25) * 100%),\n transparent\n );\n }\n\n /* --- Native Textarea --- */\n\n .field__textarea {\n border: none;\n outline: none;\n background: transparent;\n padding: var(--_textarea-padding-y) var(--_textarea-padding-x);\n font-family: inherit;\n font-size: var(--_textarea-font-size);\n color: var(--_textarea-color);\n line-height: var(--hx-line-height-normal, 1.5);\n min-height: var(--hx-textarea-min-height, var(--hx-size-20, 5rem));\n width: 100%;\n resize: vertical;\n }\n\n .field__textarea::placeholder {\n color: var(--_textarea-placeholder-color);\n }\n\n .field__textarea:focus-visible {\n outline: none; /* wrapper ring handles keyboard focus indication */\n }\n\n .field__textarea:disabled {\n cursor: not-allowed;\n }\n\n @media (prefers-reduced-motion: reduce) {\n .field__textarea-wrapper {\n transition: none;\n }\n }\n\n /* --- Resize Variants --- */\n\n :host([resize='none']) .field__textarea {\n resize: none;\n }\n\n /* resize: vertical is the base default — no override needed for [resize='vertical'] */\n\n :host([resize='both']) .field__textarea {\n resize: both;\n }\n\n :host([resize='auto']) .field__textarea {\n resize: none;\n overflow: hidden;\n }\n\n /* --- Character Counter --- */\n\n .field__counter {\n font-size: var(--hx-font-size-xs, 0.75rem);\n color: var(--hx-textarea-counter-color, var(--hx-color-text-muted, #4a5362));\n line-height: var(--hx-line-height-normal, 1.5);\n text-align: end;\n }\n\n /* --- Visually Hidden (screen reader only) --- */\n\n .sr-only {\n position: absolute;\n width: 1px;\n height: 1px;\n padding: 0;\n margin: -1px;\n overflow: hidden;\n clip: rect(0, 0, 0, 0);\n white-space: nowrap;\n border: 0;\n }\n\n /* --- Help Text & Error Messages --- */\n\n .field__help-text {\n font-size: var(--hx-font-size-xs, 0.75rem);\n color: var(--hx-textarea-help-text-color, var(--hx-color-text-muted, #4a5362));\n line-height: var(--hx-line-height-normal, 1.5);\n }\n\n .field__error {\n font-size: var(--hx-font-size-xs, 0.75rem);\n color: var(\n --hx-textarea-error-color,\n var(--hx-input-error-color, var(--hx-color-error-text, #c92a2a))\n );\n line-height: var(--hx-line-height-normal, 1.5);\n }\n\n /* ─── High Contrast Mode (forced-colors) ─── */\n\n @media (forced-colors: active) {\n .field__textarea-wrapper {\n forced-color-adjust: none;\n background-color: Field;\n color: FieldText;\n border: 2px solid ButtonText;\n }\n\n .field__textarea {\n color: FieldText;\n }\n\n .field__textarea::placeholder {\n color: GrayText;\n }\n\n .field__textarea-wrapper:focus-within {\n border-color: Highlight;\n box-shadow: none;\n }\n\n .field__textarea:focus-visible {\n outline: 3px solid Highlight;\n outline-offset: -3px;\n }\n\n :host([disabled]) {\n opacity: 1;\n }\n\n :host([disabled]) .field__textarea-wrapper {\n border-color: GrayText;\n color: GrayText;\n }\n\n :host([disabled]) .field__textarea {\n color: GrayText;\n }\n\n .field--error .field__textarea-wrapper {\n border-color: LinkText;\n }\n\n .field__label {\n color: CanvasText;\n }\n\n .field__help-text {\n color: GrayText;\n }\n\n .field__error {\n color: LinkText;\n }\n }\n`;\n","import { html, nothing, type PropertyValues } from 'lit';\nimport '../../utilities/document-token-adoption.js';\nimport { customElement, property, query, state } from 'lit/decorators.js';\nimport { classMap } from 'lit/directives/class-map.js';\nimport { ifDefined } from 'lit/directives/if-defined.js';\nimport { live } from 'lit/directives/live.js';\nimport { HelixElement, createIdCounter } from '../../base/index.js';\nimport { FormMixin } from '../../mixins/FormMixin.js';\nimport { helixTextareaStyles } from './hx-textarea.styles.js';\nimport { forcedColorsField } from '../../styles/forced-colors.js';\n\nconst _nextTextareaId = createIdCounter('hx-textarea');\n\n/** Detail for hx-input and hx-change events dispatched by hx-textarea. */\nexport interface HxTextareaDetail {\n value: string;\n}\n\n/**\n * A multi-line text area component with label, validation, and form association.\n *\n * Uses `aria-invalid` to convey error state and `aria-describedby` to link\n * error/help text to the textarea. Label association is handled through\n * `aria-labelledby` (for slotted labels) or the standard `<label for>` pattern.\n * Supports `aria-label` for cases where a visible label is not present.\n * Validation errors are announced via `role=\"alert\"` (assertive live region).\n *\n * @summary Form-associated textarea with built-in label, error, help text, character counter, and auto-resize.\n *\n * @tag hx-textarea\n *\n * @slot label - Custom label content (overrides the label property). Use for Drupal Form API rendered labels.\n * @slot help-text - Custom help text content (overrides the helpText property).\n * @slot error - Custom error content (overrides the error property). Use for Drupal Form API rendered errors.\n *\n * @fires {CustomEvent<{value: string}>} hx-input - Dispatched on every keystroke as the user types.\n * @fires {CustomEvent<{value: string}>} hx-change - Dispatched when the textarea loses focus after its value changed.\n *\n * @csspart field - The outer field container.\n * @csspart label - The label element.\n * @csspart textarea-wrapper - The wrapper around the textarea.\n * @csspart textarea - The native textarea element.\n * @csspart counter - The character count display.\n * @csspart help-text - The help text container.\n * @csspart error - The error message container.\n *\n * @cssprop [--hx-input-bg=var(--hx-color-neutral-0)] - Input background color.\n * @cssprop [--hx-input-color=var(--hx-color-neutral-800)] - Input text color.\n * @cssprop [--hx-input-border-color=var(--hx-color-neutral-300)] - Input border color.\n * @cssprop [--hx-input-border-radius=var(--hx-border-radius-md)] - Input border radius.\n * @cssprop [--hx-input-font-family=var(--hx-font-family-sans)] - Input font family.\n * @cssprop [--hx-input-focus-ring-color=var(--hx-focus-ring-color)] - Focus ring color.\n * @cssprop [--hx-input-error-color=var(--hx-color-error-500)] - Error state color.\n * @cssprop [--hx-input-label-color=var(--hx-color-neutral-700)] - Label text color.\n * @cssprop [--hx-textarea-min-height=var(--hx-size-20, 5rem)] - Minimum textarea height.\n * @cssprop [--hx-opacity-disabled] - Opacity.\n * @cssprop [--hx-space-1] - Spacing token.\n * @cssprop [--hx-font-family-sans] - Font family.\n * @cssprop [--hx-font-size-sm] - Font size.\n * @cssprop [--hx-font-weight-medium] - Font weight.\n * @cssprop [--hx-color-neutral-700] - Color.\n * @cssprop [--hx-line-height-normal] - Line height.\n * @cssprop [--hx-color-error-text] - Color.\n * @cssprop [--hx-font-weight-bold] - Font weight.\n * @cssprop [--hx-border-width-thin] - Width.\n * @cssprop [--hx-color-neutral-300] - Color.\n * @cssprop [--hx-border-radius-md] - CSS custom property.\n * @cssprop [--hx-color-neutral-0] - Color.\n * @cssprop [--hx-transition-fast] - Transition timing.\n * @cssprop [--hx-focus-ring-color] - Color.\n * @cssprop [--hx-color-primary-400] - Color.\n * @cssprop [--hx-focus-ring-width] - Width.\n * @cssprop [--hx-focus-ring-opacity] - CSS custom property.\n * @cssprop [--hx-color-error-500] - Color.\n * @cssprop [--hx-space-2] - Spacing token.\n * @cssprop [--hx-space-3] - Spacing token.\n * @cssprop [--hx-font-size-md] - Font size.\n * @cssprop [--hx-color-neutral-800] - Color.\n * @cssprop [--hx-size-20] - Size token.\n * @cssprop [--hx-color-neutral-400] - Color.\n * @cssprop [--hx-font-size-xs] - Font size.\n * @cssprop [--hx-color-neutral-500] - Color.\n */\n@customElement('hx-textarea')\nexport class HelixTextarea extends FormMixin(HelixElement) {\n static override styles = [helixTextareaStyles, forcedColorsField];\n\n // ─── Form Association ───\n\n /** @internal */\n static override formAssociated = true;\n\n // ─── Properties ───\n\n /**\n * The visible label text for the textarea.\n * @attr label\n */\n @property({ type: String })\n label = '';\n\n /**\n * Placeholder text shown when the textarea is empty.\n * @attr placeholder\n */\n @property({ type: String })\n placeholder = '';\n\n /**\n * The current value of the textarea.\n * @attr value\n */\n @property({ type: String })\n value = '';\n\n /**\n * Whether the textarea is required for form submission.\n * @attr required\n */\n @property({ type: Boolean, reflect: true })\n required = false;\n\n /**\n * Whether the textarea is disabled.\n * @attr disabled\n */\n @property({ type: Boolean, reflect: true })\n disabled = false;\n\n /**\n * Error message to display. When set, the textarea enters an error state.\n * @attr error\n */\n @property({ type: String })\n error = '';\n\n /**\n * Help text displayed below the textarea for guidance.\n * @attr help-text\n */\n @property({ type: String, attribute: 'help-text' })\n helpText = '';\n\n /**\n * The name of the textarea, used for form submission.\n * @attr name\n */\n @property({ type: String, reflect: true })\n name = '';\n\n /**\n * The number of visible text rows. Must be a positive integer (minimum 1).\n * Invalid values are clamped to the nearest valid value.\n * @attr rows\n */\n @property({ type: Number })\n rows = 4;\n\n /**\n * Minimum number of characters required.\n * @attr minlength\n */\n @property({ type: Number, attribute: 'minlength' })\n minlength: number | undefined;\n\n /**\n * Maximum number of characters allowed.\n * @attr maxlength\n */\n @property({ type: Number, attribute: 'maxlength' })\n maxlength: number | undefined;\n\n /**\n * Whether the textarea is read-only. Read-only fields are visible but\n * cannot be edited by the user. Common in healthcare for displaying\n * non-editable patient data inline with editable fields.\n * @attr readonly\n */\n @property({ type: Boolean, reflect: true })\n readonly = false;\n\n /**\n * Controls how the textarea can be resized. Use 'auto' for auto-grow behavior.\n * @attr resize\n */\n @property({ type: String, reflect: true })\n resize: 'none' | 'vertical' | 'both' | 'auto' = 'vertical';\n\n /**\n * Whether to show a character count below the textarea.\n * @attr show-count\n */\n @property({ type: Boolean, attribute: 'show-count' })\n showCount = false;\n\n /**\n * Validation message shown when the field is required but empty.\n * @attr required-message\n */\n @property({ attribute: 'required-message' })\n requiredMessage = 'This field is required.';\n\n /**\n * Accessible name for screen readers, if different from the visible label.\n * Uses `accessible-label` attribute instead of `aria-label` to avoid\n * ARIAMixin shadowing on the host element.\n *\n * Note: `mixinDelegatesAria` is not applied to this component because form\n * inputs with associated labels delegate accessible naming via `<label>`\n * association and `aria-labelledby`, not host-level ARIA delegation. The\n * `accessible-label` attribute is a fallback for label-free usage. The value is forwarded to the\n * internal native textarea's `aria-label`.\n * @attr accessible-label\n */\n @property({ type: String, attribute: 'accessible-label' })\n accessibleLabel: string | null = null;\n\n // ─── Internal References ───\n\n /** @internal */\n @query('.field__textarea')\n private _textarea: HTMLTextAreaElement | undefined;\n\n // ─── Slot Tracking ───\n\n /** @internal */\n @state() private _hasLabelSlot = false;\n /** @internal */\n @state() private _hasErrorSlot = false;\n /** @internal */\n @state() private _hasHelpTextSlot = false;\n\n // ─── Live Announcement ───\n\n /**\n * Debounced announcement text for the hidden polite live region.\n * Only populated when the user is approaching the character limit.\n * @internal\n */\n @state() private _liveAnnouncement = '';\n\n /** Timer handle for the debounced character-count announcement. @internal */\n private _announceTimer: ReturnType<typeof setTimeout> | null = null;\n\n /** @internal */\n private _handleLabelSlotChange(e: Event): void {\n const slot = e.target as HTMLSlotElement;\n this._hasLabelSlot = slot.assignedElements().length > 0;\n if (this._hasLabelSlot) {\n const slottedLabel = slot.assignedElements()[0];\n if (slottedLabel && !slottedLabel.id) {\n slottedLabel.id = `${this._textareaId}-slotted-label`;\n }\n }\n }\n\n /** @internal */\n private _handleErrorSlotChange(e: Event): void {\n const slot = e.target as HTMLSlotElement;\n this._hasErrorSlot = slot.assignedElements().length > 0;\n }\n\n /** @internal */\n private _handleHelpTextSlotChange(e: Event): void {\n const slot = e.target as HTMLSlotElement;\n this._hasHelpTextSlot = slot.assignedElements().length > 0;\n }\n\n // ─── Lifecycle ───\n\n override disconnectedCallback(): void {\n super.disconnectedCallback();\n if (this._announceTimer !== null) {\n clearTimeout(this._announceTimer);\n this._announceTimer = null;\n }\n }\n\n override updated(changedProperties: PropertyValues<this>): void {\n super.updated(changedProperties);\n if (changedProperties.has('rows')) {\n const clamped = Math.max(1, Math.round(this.rows));\n if (clamped !== this.rows) {\n this.rows = clamped;\n }\n }\n if (changedProperties.has('value')) {\n this._internals.setFormValue(this.value);\n }\n // Auto-grow: respond to programmatic value changes\n if (changedProperties.has('value') && this.resize === 'auto' && this._textarea) {\n this._textarea.style.height = 'auto';\n this._textarea.style.height = `${this._textarea.scrollHeight}px`;\n }\n }\n\n // ─── Form Integration ───\n\n /** @internal */\n override _updateValidity(): void {\n const anchor = this._textarea ?? undefined;\n if (this.required && !this.value) {\n this._internals.setValidity(\n { valueMissing: true },\n this.error || this.requiredMessage,\n anchor,\n );\n } else if (\n this.minlength !== undefined &&\n this.value.length > 0 &&\n this.value.length < this.minlength\n ) {\n this._internals.setValidity(\n { tooShort: true },\n this.error || `Value must be at least ${this.minlength} characters.`,\n anchor,\n );\n } else if (this.maxlength !== undefined && this.value.length > this.maxlength) {\n this._internals.setValidity(\n { tooLong: true },\n this.error || `Value must be ${this.maxlength} characters or fewer.`,\n anchor,\n );\n } else {\n this._internals.setValidity({});\n }\n }\n\n /** @internal */\n protected override _onFormReset(): void {\n this.value = '';\n this._internals.setFormValue('');\n this._resetInteractionState();\n }\n\n /** @internal */\n protected override _onFormStateRestore(\n state: File | string | FormData | null,\n _mode: 'restore' | 'autocomplete',\n ): void {\n if (typeof state === 'string') {\n this.value = state;\n }\n }\n\n /** @internal */\n protected override _onFormDisabled(disabled: boolean): void {\n this.disabled = disabled;\n }\n\n // ─── Event Handling ───\n\n /** @internal */\n private _handleInput(e: Event): void {\n const target = e.target as HTMLTextAreaElement;\n this.value = target.value;\n this._handleInteractionInput();\n // Note: setFormValue is called in updated() via the value change — no double-call here (P1-06 fix)\n\n // Auto-grow: reset height then set to scrollHeight\n if (this.resize === 'auto') {\n target.style.height = 'auto';\n target.style.height = `${target.scrollHeight}px`;\n }\n\n // Debounced character-count announcement (WCAG 4.1.3):\n // Only announce when near/at the maxlength limit; suppress every-keystroke noise.\n if (this._announceTimer !== null) {\n clearTimeout(this._announceTimer);\n }\n this._announceTimer = setTimeout(() => {\n this._announceTimer = null;\n if (this.maxlength !== undefined && this.value.length >= this.maxlength * 0.8) {\n this._liveAnnouncement = `${this.value.length} of ${this.maxlength} characters`;\n } else {\n this._liveAnnouncement = '';\n }\n }, 1000);\n\n /**\n * Dispatched on every keystroke as the user types.\n * @event hx-input\n */\n this.dispatchEvent(\n new CustomEvent<{ value: string }>('hx-input', {\n bubbles: true,\n composed: true,\n detail: { value: this.value },\n }),\n );\n }\n\n /** @internal */\n private _handleChange(e: Event): void {\n const target = e.target as HTMLTextAreaElement;\n this.value = target.value;\n this._internals.setFormValue(this.value);\n this._handleInteractionBlur();\n\n /**\n * Dispatched when the textarea loses focus after its value changed.\n * @event hx-change\n */\n this.dispatchEvent(\n new CustomEvent<{ value: string }>('hx-change', {\n bubbles: true,\n composed: true,\n detail: { value: this.value },\n }),\n );\n }\n\n // ─── Public Methods ───\n\n /** Moves focus to the textarea element. */\n override focus(options?: FocusOptions): void {\n this._textarea?.focus(options);\n }\n\n /** Selects all text in the textarea. */\n select(): void {\n this._textarea?.select();\n }\n\n // ─── Render ───\n\n /** @internal */\n private _textareaId = _nextTextareaId();\n /** @internal */\n private _helpTextId = `${this._textareaId}-help`;\n /** @internal */\n private _errorId = `${this._textareaId}-error`;\n /** @internal */\n private _counterId = `${this._textareaId}-counter`;\n\n /** @internal */\n private _renderCounter() {\n if (!this.showCount) return nothing;\n\n // Use Array.from() to count grapheme clusters (handles emoji correctly)\n const count = Array.from(this.value ?? '').length;\n const display = this.maxlength !== undefined ? `${count} / ${this.maxlength}` : `${count}`;\n\n // aria-live=\"polite\" announces counter changes without interrupting the user.\n // The debounced _liveAnnouncement region provides additional context when nearing the limit.\n return html`\n <div part=\"counter\" class=\"field__counter\" id=${this._counterId} aria-hidden=\"true\">\n ${display}\n </div>\n `;\n }\n\n override render() {\n const hasError = !!this.error || this._hasErrorSlot;\n\n const fieldClasses = {\n field: true,\n 'field--error': hasError,\n 'field--disabled': this.disabled,\n 'field--required': this.required,\n };\n\n // P0-02 fix: help text container renders when slot is used OR property is set\n const hasHelpText = (!!this.helpText || this._hasHelpTextSlot) && !hasError;\n\n // Do NOT include the counter in aria-describedby: the counter element has\n // aria-hidden=\"true\" (it is a visual-only display), and referencing an\n // aria-hidden element from aria-describedby is a WCAG conflict.\n // Screen reader users receive character-count announcements via the\n // debounced aria-live=\"polite\" region (_liveAnnouncement) instead.\n const describedBy =\n [hasError ? this._errorId : null, hasHelpText ? this._helpTextId : null]\n .filter(Boolean)\n .join(' ') || undefined;\n\n return html`\n <div part=\"field\" class=${classMap(fieldClasses)}>\n <div class=\"field__label-wrapper\">\n <slot name=\"label\" @slotchange=${this._handleLabelSlotChange}>\n ${this.label\n ? html`\n <label part=\"label\" class=\"field__label\" for=${this._textareaId}>\n ${this.label}\n ${this.required\n ? html`<span class=\"field__required-marker\" aria-hidden=\"true\">*</span>`\n : nothing}\n </label>\n `\n : nothing}\n </slot>\n </div>\n\n <div part=\"textarea-wrapper\" class=\"field__textarea-wrapper\">\n <textarea\n part=\"textarea\"\n class=\"field__textarea\"\n id=${this._textareaId}\n .value=${live(this.value)}\n placeholder=${ifDefined(this.placeholder || undefined)}\n ?required=${this.required}\n ?disabled=${this.disabled}\n ?readonly=${this.readonly}\n rows=${this.rows}\n minlength=${ifDefined(this.minlength)}\n maxlength=${ifDefined(this.maxlength)}\n name=${ifDefined(this.name || undefined)}\n aria-label=${ifDefined(this.accessibleLabel ?? undefined)}\n aria-labelledby=${ifDefined(\n this._hasLabelSlot ? `${this._textareaId}-slotted-label` : undefined,\n )}\n aria-invalid=${hasError ? 'true' : nothing}\n aria-describedby=${ifDefined(describedBy)}\n @input=${this._handleInput}\n @change=${this._handleChange}\n ></textarea>\n </div>\n\n ${this._renderCounter()}\n <div aria-live=\"polite\" aria-atomic=\"true\" class=\"sr-only\">${this._liveAnnouncement}</div>\n ${hasError\n ? html`\n <div part=\"error\" class=\"field__error\" id=${this._errorId} role=\"alert\">\n <slot name=\"error\" @slotchange=${this._handleErrorSlotChange}>${this.error}</slot>\n </div>\n `\n : html`<slot name=\"error\" @slotchange=${this._handleErrorSlotChange}></slot>`}\n ${hasHelpText\n ? html`\n <div part=\"help-text\" class=\"field__help-text\" id=${this._helpTextId}>\n <slot name=\"help-text\" @slotchange=${this._handleHelpTextSlotChange}>\n ${this.helpText}\n </slot>\n </div>\n `\n : html`<slot name=\"help-text\" @slotchange=${this._handleHelpTextSlotChange}></slot>`}\n </div>\n `;\n }\n}\n\n/**\n * Per-component event map for type-safe addEventListener on hx-textarea.\n * The `hx-change` detail is `{ value: string }` only — no `checked` property.\n */\nexport interface HxTextareaEventMap {\n 'hx-input': CustomEvent<{ value: string }>;\n 'hx-change': CustomEvent<{ value: string }>;\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'hx-textarea': HelixTextarea;\n }\n interface HTMLElementEventMap {\n 'hx-input': CustomEvent<{ value: string }>;\n }\n}\n\n/** Canonical type alias for the hx-textarea component. */\nexport type HxTextarea = HelixTextarea;\n"],"names":["helixTextareaStyles","css","_nextTextareaId","createIdCounter","HelixTextarea","FormMixin","HelixElement","slot","slottedLabel","changedProperties","clamped","anchor","state","_mode","disabled","target","options","_a","nothing","count","display","html","hasError","fieldClasses","hasHelpText","describedBy","classMap","live","ifDefined","forcedColorsField","__decorateClass","property","query","customElement"],"mappings":";;;;;;;;;AAEO,MAAMA,IAAsBC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAA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"}
|
|
1
|
+
{"version":3,"file":"hx-textarea-Jx1xnhgv.js","sources":["../../src/components/hx-textarea/hx-textarea.styles.ts","../../src/components/hx-textarea/hx-textarea.ts"],"sourcesContent":["import { css } from 'lit';\n\nexport const helixTextareaStyles = css`\n :host {\n display: block;\n\n /* ─── Component tokens (3.2.0) ──────────────────────────────────── */\n --_textarea-bg: var(\n --hx-textarea-bg,\n var(--hx-input-bg, var(--hx-color-surface-default, #ffffff))\n );\n --_textarea-color: var(\n --hx-textarea-color,\n var(--hx-input-color, var(--hx-color-text-strong, #202b39))\n );\n --_textarea-border-color: var(\n --hx-textarea-border-color,\n var(--hx-input-border-color, var(--hx-color-border-strong, #66787b))\n );\n --_textarea-border-color-focus: var(\n --hx-textarea-border-color-focus,\n var(\n --hx-input-focus-ring-color,\n var(--hx-focus-ring-color, var(--hx-color-primary-600, #0f7078))\n )\n );\n --_textarea-border-color-invalid: var(\n --hx-textarea-border-color-invalid,\n var(--hx-input-error-color, var(--hx-color-error-600, #c92a2a))\n );\n --_textarea-border-radius: var(\n --hx-textarea-border-radius,\n var(--hx-input-border-radius, var(--hx-border-radius-md, 0.375rem))\n );\n --_textarea-padding-x: var(--hx-textarea-padding-x, var(--hx-space-3, 0.75rem));\n --_textarea-padding-y: var(--hx-textarea-padding-y, var(--hx-space-2, 0.5rem));\n --_textarea-font-size: var(--hx-textarea-font-size, var(--hx-font-size-md, 1rem));\n --_textarea-placeholder-color: var(\n --hx-textarea-placeholder-color,\n var(--hx-color-text-placeholder, #66787b)\n );\n }\n\n :host([disabled]) {\n opacity: var(--hx-opacity-disabled, 0.5);\n pointer-events: none;\n }\n\n * {\n box-sizing: border-box;\n }\n\n .field {\n display: flex;\n flex-direction: column;\n gap: var(--hx-space-1, 0.25rem);\n font-family: var(\n --hx-textarea-font-family,\n var(--hx-input-font-family, var(--hx-font-family-sans, sans-serif))\n );\n }\n\n /* --- Label --- */\n\n .field__label-wrapper {\n display: contents;\n }\n\n .field__label {\n display: flex;\n align-items: baseline;\n gap: var(--hx-space-1, 0.25rem);\n font-size: var(--hx-font-size-sm, 0.875rem);\n font-weight: var(--hx-font-weight-medium, 500);\n color: var(\n --hx-textarea-label-color,\n var(--hx-input-label-color, var(--hx-color-text-strong, #202b39))\n );\n line-height: var(--hx-line-height-normal, 1.5);\n }\n\n .field__required-marker {\n color: var(\n --hx-textarea-error-color,\n var(--hx-input-error-color, var(--hx-color-error-text, #c92a2a))\n );\n font-weight: var(--hx-font-weight-bold, 700);\n }\n\n /* --- Textarea Wrapper --- */\n\n .field__textarea-wrapper {\n display: flex;\n flex-direction: column;\n border: var(--hx-border-width-thin, 1px) solid var(--_textarea-border-color);\n border-radius: var(--_textarea-border-radius);\n background-color: var(--_textarea-bg);\n transition:\n border-color var(--hx-transition-fast, 150ms ease),\n box-shadow var(--hx-transition-fast, 150ms ease);\n overflow: hidden;\n }\n\n .field__textarea-wrapper:focus-within {\n border-color: var(--_textarea-border-color-focus);\n box-shadow: 0 0 0 var(--hx-focus-ring-width, 2px)\n color-mix(\n in srgb,\n var(--_textarea-border-color-focus) calc(var(--hx-focus-ring-opacity, 0.25) * 100%),\n transparent\n );\n }\n\n /* --- Error State --- */\n\n .field--error .field__textarea-wrapper {\n border-color: var(--_textarea-border-color-invalid);\n }\n\n .field--error .field__textarea-wrapper:focus-within {\n border-color: var(--_textarea-border-color-invalid);\n box-shadow: 0 0 0 var(--hx-focus-ring-width, 2px)\n color-mix(\n in srgb,\n var(--_textarea-border-color-invalid) calc(var(--hx-focus-ring-opacity, 0.25) * 100%),\n transparent\n );\n }\n\n /* --- Native Textarea --- */\n\n .field__textarea {\n border: none;\n outline: none;\n background: transparent;\n padding: var(--_textarea-padding-y) var(--_textarea-padding-x);\n font-family: inherit;\n font-size: var(--_textarea-font-size);\n color: var(--_textarea-color);\n line-height: var(--hx-line-height-normal, 1.5);\n min-height: var(--hx-textarea-min-height, var(--hx-size-20, 5rem));\n width: 100%;\n resize: vertical;\n }\n\n .field__textarea::placeholder {\n color: var(--_textarea-placeholder-color);\n }\n\n .field__textarea:focus-visible {\n outline: none; /* wrapper ring handles keyboard focus indication */\n }\n\n .field__textarea:disabled {\n cursor: not-allowed;\n }\n\n @media (prefers-reduced-motion: reduce) {\n .field__textarea-wrapper {\n transition: none;\n }\n }\n\n /* --- Resize Variants --- */\n\n :host([resize='none']) .field__textarea {\n resize: none;\n }\n\n /* resize: vertical is the base default — no override needed for [resize='vertical'] */\n\n :host([resize='both']) .field__textarea {\n resize: both;\n }\n\n :host([resize='auto']) .field__textarea {\n resize: none;\n overflow: hidden;\n }\n\n /* --- Character Counter --- */\n\n .field__counter {\n font-size: var(--hx-font-size-xs, 0.75rem);\n color: var(--hx-textarea-counter-color, var(--hx-color-text-muted, #4a5362));\n line-height: var(--hx-line-height-normal, 1.5);\n text-align: end;\n }\n\n /* --- Visually Hidden (screen reader only) --- */\n\n .sr-only {\n position: absolute;\n width: 1px;\n height: 1px;\n padding: 0;\n margin: -1px;\n overflow: hidden;\n clip: rect(0, 0, 0, 0);\n white-space: nowrap;\n border: 0;\n }\n\n /* --- Help Text & Error Messages --- */\n\n .field__help-text {\n font-size: var(--hx-font-size-xs, 0.75rem);\n color: var(--hx-textarea-help-text-color, var(--hx-color-text-muted, #4a5362));\n line-height: var(--hx-line-height-normal, 1.5);\n }\n\n .field__error {\n font-size: var(--hx-font-size-xs, 0.75rem);\n color: var(\n --hx-textarea-error-color,\n var(--hx-input-error-color, var(--hx-color-error-text, #c92a2a))\n );\n line-height: var(--hx-line-height-normal, 1.5);\n }\n\n /* ─── High Contrast Mode (forced-colors) ─── */\n\n @media (forced-colors: active) {\n .field__textarea-wrapper {\n forced-color-adjust: none;\n background-color: Field;\n color: FieldText;\n border: 2px solid ButtonText;\n }\n\n .field__textarea {\n color: FieldText;\n }\n\n .field__textarea::placeholder {\n color: GrayText;\n }\n\n .field__textarea-wrapper:focus-within {\n border-color: Highlight;\n box-shadow: none;\n }\n\n .field__textarea:focus-visible {\n outline: 3px solid Highlight;\n outline-offset: -3px;\n }\n\n :host([disabled]) {\n opacity: 1;\n }\n\n :host([disabled]) .field__textarea-wrapper {\n border-color: GrayText;\n color: GrayText;\n }\n\n :host([disabled]) .field__textarea {\n color: GrayText;\n }\n\n .field--error .field__textarea-wrapper {\n border-color: LinkText;\n }\n\n .field__label {\n color: CanvasText;\n }\n\n .field__help-text {\n color: GrayText;\n }\n\n .field__error {\n color: LinkText;\n }\n }\n`;\n","import { html, nothing, type PropertyValues } from 'lit';\nimport '../../utilities/document-token-adoption.js';\nimport { customElement, property, query, state } from 'lit/decorators.js';\nimport { classMap } from 'lit/directives/class-map.js';\nimport { ifDefined } from 'lit/directives/if-defined.js';\nimport { live } from 'lit/directives/live.js';\nimport { HelixElement, createIdCounter } from '../../base/index.js';\nimport { FormMixin } from '../../mixins/FormMixin.js';\nimport { helixTextareaStyles } from './hx-textarea.styles.js';\nimport { forcedColorsField } from '../../styles/forced-colors.js';\n\nconst _nextTextareaId = createIdCounter('hx-textarea');\n\n/** Detail for hx-input and hx-change events dispatched by hx-textarea. */\nexport interface HxTextareaDetail {\n value: string;\n}\n\n/**\n * A multi-line text area component with label, validation, and form association.\n *\n * Uses `aria-invalid` to convey error state and `aria-describedby` to link\n * error/help text to the textarea. Label association is handled through\n * `aria-labelledby` (for slotted labels) or the standard `<label for>` pattern.\n * Supports `aria-label` for cases where a visible label is not present.\n * Validation errors are announced via `role=\"alert\"` (assertive live region).\n *\n * @summary Form-associated textarea with built-in label, error, help text, character counter, and auto-resize.\n *\n * @tag hx-textarea\n *\n * @slot label - Custom label content (overrides the label property). Use for Drupal Form API rendered labels.\n * @slot help-text - Custom help text content (overrides the helpText property).\n * @slot error - Custom error content (overrides the error property). Use for Drupal Form API rendered errors.\n *\n * @fires {CustomEvent<{value: string}>} hx-input - Dispatched on every keystroke as the user types.\n * @fires {CustomEvent<{value: string}>} hx-change - Dispatched when the textarea loses focus after its value changed.\n *\n * @csspart field - The outer field container.\n * @csspart label - The label element.\n * @csspart textarea-wrapper - The wrapper around the textarea.\n * @csspart textarea - The native textarea element.\n * @csspart counter - The character count display.\n * @csspart help-text - The help text container.\n * @csspart error - The error message container.\n *\n * @cssprop [--hx-input-bg=var(--hx-color-neutral-0)] - Input background color.\n * @cssprop [--hx-input-color=var(--hx-color-neutral-800)] - Input text color.\n * @cssprop [--hx-input-border-color=var(--hx-color-neutral-300)] - Input border color.\n * @cssprop [--hx-input-border-radius=var(--hx-border-radius-md)] - Input border radius.\n * @cssprop [--hx-input-font-family=var(--hx-font-family-sans)] - Input font family.\n * @cssprop [--hx-input-focus-ring-color=var(--hx-focus-ring-color)] - Focus ring color.\n * @cssprop [--hx-input-error-color=var(--hx-color-error-500)] - Error state color.\n * @cssprop [--hx-input-label-color=var(--hx-color-neutral-700)] - Label text color.\n * @cssprop [--hx-textarea-min-height=var(--hx-size-20, 5rem)] - Minimum textarea height.\n * @cssprop [--hx-opacity-disabled] - Opacity.\n * @cssprop [--hx-space-1] - Spacing token.\n * @cssprop [--hx-font-family-sans] - Font family.\n * @cssprop [--hx-font-size-sm] - Font size.\n * @cssprop [--hx-font-weight-medium] - Font weight.\n * @cssprop [--hx-color-neutral-700] - Color.\n * @cssprop [--hx-line-height-normal] - Line height.\n * @cssprop [--hx-color-error-text] - Color.\n * @cssprop [--hx-font-weight-bold] - Font weight.\n * @cssprop [--hx-border-width-thin] - Width.\n * @cssprop [--hx-color-neutral-300] - Color.\n * @cssprop [--hx-border-radius-md] - CSS custom property.\n * @cssprop [--hx-color-neutral-0] - Color.\n * @cssprop [--hx-transition-fast] - Transition timing.\n * @cssprop [--hx-focus-ring-color] - Color.\n * @cssprop [--hx-color-primary-400] - Color.\n * @cssprop [--hx-focus-ring-width] - Width.\n * @cssprop [--hx-focus-ring-opacity] - CSS custom property.\n * @cssprop [--hx-color-error-500] - Color.\n * @cssprop [--hx-space-2] - Spacing token.\n * @cssprop [--hx-space-3] - Spacing token.\n * @cssprop [--hx-font-size-md] - Font size.\n * @cssprop [--hx-color-neutral-800] - Color.\n * @cssprop [--hx-size-20] - Size token.\n * @cssprop [--hx-color-neutral-400] - Color.\n * @cssprop [--hx-font-size-xs] - Font size.\n * @cssprop [--hx-color-neutral-500] - Color.\n */\n@customElement('hx-textarea')\nexport class HelixTextarea extends FormMixin(HelixElement) {\n static override styles = [helixTextareaStyles, forcedColorsField];\n\n // ─── Form Association ───\n\n /** @internal */\n static override formAssociated = true;\n\n // ─── Properties ───\n\n /**\n * The visible label text for the textarea.\n * @attr label\n */\n @property({ type: String })\n label = '';\n\n /**\n * Placeholder text shown when the textarea is empty.\n * @attr placeholder\n */\n @property({ type: String })\n placeholder = '';\n\n /**\n * The current value of the textarea.\n * @attr value\n */\n @property({ type: String })\n value = '';\n\n /**\n * Whether the textarea is required for form submission.\n * @attr required\n */\n @property({ type: Boolean, reflect: true })\n required = false;\n\n /**\n * Whether the textarea is disabled.\n * @attr disabled\n */\n @property({ type: Boolean, reflect: true })\n disabled = false;\n\n /**\n * Error message to display. When set, the textarea enters an error state.\n * @attr error\n */\n @property({ type: String })\n error = '';\n\n /**\n * Help text displayed below the textarea for guidance.\n * @attr help-text\n */\n @property({ type: String, attribute: 'help-text' })\n helpText = '';\n\n /**\n * The name of the textarea, used for form submission.\n * @attr name\n */\n @property({ type: String, reflect: true })\n name = '';\n\n /**\n * The number of visible text rows. Must be a positive integer (minimum 1).\n * Invalid values are clamped to the nearest valid value.\n * @attr rows\n */\n @property({ type: Number })\n rows = 4;\n\n /**\n * Minimum number of characters required.\n * @attr minlength\n */\n @property({ type: Number, attribute: 'minlength' })\n minlength: number | undefined;\n\n /**\n * Maximum number of characters allowed.\n * @attr maxlength\n */\n @property({ type: Number, attribute: 'maxlength' })\n maxlength: number | undefined;\n\n /**\n * Whether the textarea is read-only. Read-only fields are visible but\n * cannot be edited by the user. Common in healthcare for displaying\n * non-editable patient data inline with editable fields.\n * @attr readonly\n */\n @property({ type: Boolean, reflect: true })\n readonly = false;\n\n /**\n * Controls how the textarea can be resized. Use 'auto' for auto-grow behavior.\n * @attr resize\n */\n @property({ type: String, reflect: true })\n resize: 'none' | 'vertical' | 'both' | 'auto' = 'vertical';\n\n /**\n * Whether to show a character count below the textarea.\n * @attr show-count\n */\n @property({ type: Boolean, attribute: 'show-count' })\n showCount = false;\n\n /**\n * Validation message shown when the field is required but empty.\n * @attr required-message\n */\n @property({ attribute: 'required-message' })\n requiredMessage = 'This field is required.';\n\n /**\n * Accessible name for screen readers, if different from the visible label.\n * Uses `accessible-label` attribute instead of `aria-label` to avoid\n * ARIAMixin shadowing on the host element.\n *\n * Note: `mixinDelegatesAria` is not applied to this component because form\n * inputs with associated labels delegate accessible naming via `<label>`\n * association and `aria-labelledby`, not host-level ARIA delegation. The\n * `accessible-label` attribute is a fallback for label-free usage. The value is forwarded to the\n * internal native textarea's `aria-label`.\n * @attr accessible-label\n */\n @property({ type: String, attribute: 'accessible-label' })\n accessibleLabel: string | null = null;\n\n // ─── Internal References ───\n\n /** @internal */\n @query('.field__textarea')\n private _textarea: HTMLTextAreaElement | undefined;\n\n // ─── Slot Tracking ───\n\n /** @internal */\n @state() private _hasLabelSlot = false;\n /** @internal */\n @state() private _hasErrorSlot = false;\n /** @internal */\n @state() private _hasHelpTextSlot = false;\n\n // ─── Live Announcement ───\n\n /**\n * Debounced announcement text for the hidden polite live region.\n * Only populated when the user is approaching the character limit.\n * @internal\n */\n @state() private _liveAnnouncement = '';\n\n /** Timer handle for the debounced character-count announcement. @internal */\n private _announceTimer: ReturnType<typeof setTimeout> | null = null;\n\n /** @internal */\n private _handleLabelSlotChange(e: Event): void {\n const slot = e.target as HTMLSlotElement;\n this._hasLabelSlot = slot.assignedElements().length > 0;\n if (this._hasLabelSlot) {\n const slottedLabel = slot.assignedElements()[0];\n if (slottedLabel && !slottedLabel.id) {\n slottedLabel.id = `${this._textareaId}-slotted-label`;\n }\n }\n }\n\n /** @internal */\n private _handleErrorSlotChange(e: Event): void {\n const slot = e.target as HTMLSlotElement;\n this._hasErrorSlot = slot.assignedElements().length > 0;\n }\n\n /** @internal */\n private _handleHelpTextSlotChange(e: Event): void {\n const slot = e.target as HTMLSlotElement;\n this._hasHelpTextSlot = slot.assignedElements().length > 0;\n }\n\n // ─── Lifecycle ───\n\n override disconnectedCallback(): void {\n super.disconnectedCallback();\n if (this._announceTimer !== null) {\n clearTimeout(this._announceTimer);\n this._announceTimer = null;\n }\n }\n\n override updated(changedProperties: PropertyValues<this>): void {\n super.updated(changedProperties);\n if (changedProperties.has('rows')) {\n const clamped = Math.max(1, Math.round(this.rows));\n if (clamped !== this.rows) {\n this.rows = clamped;\n }\n }\n if (changedProperties.has('value')) {\n this._internals.setFormValue(this.value);\n }\n // Auto-grow: respond to programmatic value changes\n if (changedProperties.has('value') && this.resize === 'auto' && this._textarea) {\n this._textarea.style.height = 'auto';\n this._textarea.style.height = `${this._textarea.scrollHeight}px`;\n }\n }\n\n // ─── Form Integration ───\n\n /** @internal */\n override _updateValidity(): void {\n const anchor = this._textarea ?? undefined;\n if (this.required && !this.value) {\n this._internals.setValidity(\n { valueMissing: true },\n this.error || this.requiredMessage,\n anchor,\n );\n } else if (\n this.minlength !== undefined &&\n this.value.length > 0 &&\n this.value.length < this.minlength\n ) {\n this._internals.setValidity(\n { tooShort: true },\n this.error || `Value must be at least ${this.minlength} characters.`,\n anchor,\n );\n } else if (this.maxlength !== undefined && this.value.length > this.maxlength) {\n this._internals.setValidity(\n { tooLong: true },\n this.error || `Value must be ${this.maxlength} characters or fewer.`,\n anchor,\n );\n } else {\n this._internals.setValidity({});\n }\n }\n\n /** @internal */\n protected override _onFormReset(): void {\n this.value = '';\n this._internals.setFormValue('');\n this._resetInteractionState();\n }\n\n /** @internal */\n protected override _onFormStateRestore(\n state: File | string | FormData | null,\n _mode: 'restore' | 'autocomplete',\n ): void {\n if (typeof state === 'string') {\n this.value = state;\n }\n }\n\n /** @internal */\n protected override _onFormDisabled(disabled: boolean): void {\n this.disabled = disabled;\n }\n\n // ─── Event Handling ───\n\n /** @internal */\n private _handleInput(e: Event): void {\n const target = e.target as HTMLTextAreaElement;\n this.value = target.value;\n this._handleInteractionInput();\n // Note: setFormValue is called in updated() via the value change — no double-call here (P1-06 fix)\n\n // Auto-grow: reset height then set to scrollHeight\n if (this.resize === 'auto') {\n target.style.height = 'auto';\n target.style.height = `${target.scrollHeight}px`;\n }\n\n // Debounced character-count announcement (WCAG 4.1.3):\n // Only announce when near/at the maxlength limit; suppress every-keystroke noise.\n if (this._announceTimer !== null) {\n clearTimeout(this._announceTimer);\n }\n this._announceTimer = setTimeout(() => {\n this._announceTimer = null;\n if (this.maxlength !== undefined && this.value.length >= this.maxlength * 0.8) {\n this._liveAnnouncement = `${this.value.length} of ${this.maxlength} characters`;\n } else {\n this._liveAnnouncement = '';\n }\n }, 1000);\n\n /**\n * Dispatched on every keystroke as the user types.\n * @event hx-input\n */\n this.dispatchEvent(\n new CustomEvent<{ value: string }>('hx-input', {\n bubbles: true,\n composed: true,\n detail: { value: this.value },\n }),\n );\n }\n\n /** @internal */\n private _handleChange(e: Event): void {\n const target = e.target as HTMLTextAreaElement;\n this.value = target.value;\n this._internals.setFormValue(this.value);\n this._handleInteractionBlur();\n\n /**\n * Dispatched when the textarea loses focus after its value changed.\n * @event hx-change\n */\n this.dispatchEvent(\n new CustomEvent<{ value: string }>('hx-change', {\n bubbles: true,\n composed: true,\n detail: { value: this.value },\n }),\n );\n }\n\n // ─── Public Methods ───\n\n /** Moves focus to the textarea element. */\n override focus(options?: FocusOptions): void {\n this._textarea?.focus(options);\n }\n\n /** Selects all text in the textarea. */\n select(): void {\n this._textarea?.select();\n }\n\n // ─── Render ───\n\n /** @internal */\n private _textareaId = _nextTextareaId();\n /** @internal */\n private _helpTextId = `${this._textareaId}-help`;\n /** @internal */\n private _errorId = `${this._textareaId}-error`;\n /** @internal */\n private _counterId = `${this._textareaId}-counter`;\n\n /** @internal */\n private _renderCounter() {\n if (!this.showCount) return nothing;\n\n // Use Array.from() to count grapheme clusters (handles emoji correctly)\n const count = Array.from(this.value ?? '').length;\n const display = this.maxlength !== undefined ? `${count} / ${this.maxlength}` : `${count}`;\n\n // aria-live=\"polite\" announces counter changes without interrupting the user.\n // The debounced _liveAnnouncement region provides additional context when nearing the limit.\n return html`\n <div part=\"counter\" class=\"field__counter\" id=${this._counterId} aria-hidden=\"true\">\n ${display}\n </div>\n `;\n }\n\n override render() {\n const hasError = !!this.error || this._hasErrorSlot;\n\n const fieldClasses = {\n field: true,\n 'field--error': hasError,\n 'field--disabled': this.disabled,\n 'field--required': this.required,\n };\n\n // P0-02 fix: help text container renders when slot is used OR property is set\n const hasHelpText = (!!this.helpText || this._hasHelpTextSlot) && !hasError;\n\n // Do NOT include the counter in aria-describedby: the counter element has\n // aria-hidden=\"true\" (it is a visual-only display), and referencing an\n // aria-hidden element from aria-describedby is a WCAG conflict.\n // Screen reader users receive character-count announcements via the\n // debounced aria-live=\"polite\" region (_liveAnnouncement) instead.\n const describedBy =\n [hasError ? this._errorId : null, hasHelpText ? this._helpTextId : null]\n .filter(Boolean)\n .join(' ') || undefined;\n\n return html`\n <div part=\"field\" class=${classMap(fieldClasses)}>\n <div class=\"field__label-wrapper\">\n <slot name=\"label\" @slotchange=${this._handleLabelSlotChange}>\n ${this.label\n ? html`\n <label part=\"label\" class=\"field__label\" for=${this._textareaId}>\n ${this.label}\n ${this.required\n ? html`<span class=\"field__required-marker\" aria-hidden=\"true\">*</span>`\n : nothing}\n </label>\n `\n : nothing}\n </slot>\n </div>\n\n <div part=\"textarea-wrapper\" class=\"field__textarea-wrapper\">\n <textarea\n part=\"textarea\"\n class=\"field__textarea\"\n id=${this._textareaId}\n .value=${live(this.value)}\n placeholder=${ifDefined(this.placeholder || undefined)}\n ?required=${this.required}\n ?disabled=${this.disabled}\n ?readonly=${this.readonly}\n rows=${this.rows}\n minlength=${ifDefined(this.minlength)}\n maxlength=${ifDefined(this.maxlength)}\n name=${ifDefined(this.name || undefined)}\n aria-label=${ifDefined(this.accessibleLabel ?? undefined)}\n aria-labelledby=${ifDefined(\n this._hasLabelSlot ? `${this._textareaId}-slotted-label` : undefined,\n )}\n aria-invalid=${hasError ? 'true' : nothing}\n aria-describedby=${ifDefined(describedBy)}\n @input=${this._handleInput}\n @change=${this._handleChange}\n ></textarea>\n </div>\n\n ${this._renderCounter()}\n <div aria-live=\"polite\" aria-atomic=\"true\" class=\"sr-only\">${this._liveAnnouncement}</div>\n ${hasError\n ? html`\n <div part=\"error\" class=\"field__error\" id=${this._errorId} role=\"alert\">\n <slot name=\"error\" @slotchange=${this._handleErrorSlotChange}>${this.error}</slot>\n </div>\n `\n : html`<slot name=\"error\" @slotchange=${this._handleErrorSlotChange}></slot>`}\n ${hasHelpText\n ? html`\n <div part=\"help-text\" class=\"field__help-text\" id=${this._helpTextId}>\n <slot name=\"help-text\" @slotchange=${this._handleHelpTextSlotChange}>\n ${this.helpText}\n </slot>\n </div>\n `\n : html`<slot name=\"help-text\" @slotchange=${this._handleHelpTextSlotChange}></slot>`}\n </div>\n `;\n }\n}\n\n/**\n * Per-component event map for type-safe addEventListener on hx-textarea.\n * The `hx-change` detail is `{ value: string }` only — no `checked` property.\n */\nexport interface HxTextareaEventMap {\n 'hx-input': CustomEvent<{ value: string }>;\n 'hx-change': CustomEvent<{ value: string }>;\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'hx-textarea': HelixTextarea;\n }\n interface HTMLElementEventMap {\n 'hx-input': CustomEvent<{ value: string }>;\n }\n}\n\n/** Canonical type alias for the hx-textarea component. */\nexport type HxTextarea = HelixTextarea;\n"],"names":["helixTextareaStyles","css","_nextTextareaId","createIdCounter","HelixTextarea","FormMixin","HelixElement","slot","slottedLabel","changedProperties","clamped","anchor","state","_mode","disabled","target","options","_a","nothing","count","display","html","hasError","fieldClasses","hasHelpText","describedBy","classMap","live","ifDefined","forcedColorsField","__decorateClass","property","query","customElement"],"mappings":";;;;;;;;;AAEO,MAAMA,IAAsBC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAA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"}
|