@helixui/library 3.6.0 → 3.8.0
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 +2633 -805
- package/dist/components/hx-action-bar/hx-action-bar.d.ts +18 -0
- package/dist/components/hx-action-bar/hx-action-bar.d.ts.map +1 -1
- package/dist/components/hx-action-bar/hx-action-bar.styles.d.ts.map +1 -1
- package/dist/components/hx-action-bar/index.js +1 -1
- package/dist/components/hx-alert/hx-alert.d.ts +18 -0
- package/dist/components/hx-alert/hx-alert.d.ts.map +1 -1
- package/dist/components/hx-badge/index.js +1 -1
- package/dist/components/hx-banner/hx-banner.d.ts +19 -0
- package/dist/components/hx-banner/hx-banner.d.ts.map +1 -1
- package/dist/components/hx-breadcrumb/hx-breadcrumb-item.d.ts.map +1 -1
- package/dist/components/hx-breadcrumb/hx-breadcrumb-item.styles.d.ts.map +1 -1
- package/dist/components/hx-breadcrumb/hx-breadcrumb.d.ts +18 -0
- package/dist/components/hx-breadcrumb/hx-breadcrumb.d.ts.map +1 -1
- package/dist/components/hx-breadcrumb/index.js +1 -1
- package/dist/components/hx-button/hx-button.d.ts +18 -0
- package/dist/components/hx-button/hx-button.d.ts.map +1 -1
- package/dist/components/hx-button/hx-button.styles.d.ts.map +1 -1
- package/dist/components/hx-button/index.js +1 -1
- package/dist/components/hx-button-group/hx-button-group.d.ts +47 -0
- package/dist/components/hx-button-group/hx-button-group.d.ts.map +1 -1
- package/dist/components/hx-button-group/index.js +1 -1
- package/dist/components/hx-checkbox/hx-checkbox.d.ts +18 -0
- package/dist/components/hx-checkbox/hx-checkbox.d.ts.map +1 -1
- package/dist/components/hx-checkbox/hx-checkbox.styles.d.ts.map +1 -1
- package/dist/components/hx-checkbox/index.js +1 -1
- package/dist/components/hx-checkbox-group/hx-checkbox-group.d.ts +36 -0
- package/dist/components/hx-checkbox-group/hx-checkbox-group.d.ts.map +1 -1
- package/dist/components/hx-checkbox-group/hx-checkbox-group.styles.d.ts.map +1 -1
- package/dist/components/hx-checkbox-group/index.js +1 -1
- package/dist/components/hx-clinical-status/hx-clinical-status.d.ts +19 -0
- package/dist/components/hx-clinical-status/hx-clinical-status.d.ts.map +1 -1
- package/dist/components/hx-color-picker/hx-color-picker.d.ts +18 -0
- package/dist/components/hx-color-picker/hx-color-picker.d.ts.map +1 -1
- package/dist/components/hx-color-picker/hx-color-picker.styles.d.ts.map +1 -1
- package/dist/components/hx-color-picker/index.js +1 -1
- package/dist/components/hx-combobox/hx-combobox.d.ts +18 -0
- package/dist/components/hx-combobox/hx-combobox.d.ts.map +1 -1
- package/dist/components/hx-copy-button/hx-copy-button.d.ts +18 -0
- package/dist/components/hx-copy-button/hx-copy-button.d.ts.map +1 -1
- package/dist/components/hx-copy-button/hx-copy-button.styles.d.ts.map +1 -1
- package/dist/components/hx-copy-button/index.js +1 -1
- package/dist/components/hx-date-picker/hx-date-picker.d.ts +18 -0
- package/dist/components/hx-date-picker/hx-date-picker.d.ts.map +1 -1
- package/dist/components/hx-date-picker/hx-date-picker.styles.d.ts.map +1 -1
- package/dist/components/hx-date-picker/index.js +1 -1
- package/dist/components/hx-dialog/hx-dialog.d.ts +18 -0
- package/dist/components/hx-dialog/hx-dialog.d.ts.map +1 -1
- package/dist/components/hx-drawer/hx-drawer.d.ts +18 -0
- package/dist/components/hx-drawer/hx-drawer.d.ts.map +1 -1
- package/dist/components/hx-dropdown/hx-dropdown.d.ts +18 -0
- package/dist/components/hx-dropdown/hx-dropdown.d.ts.map +1 -1
- package/dist/components/hx-dropdown/hx-dropdown.styles.d.ts.map +1 -1
- package/dist/components/hx-dropdown/index.js +1 -1
- package/dist/components/hx-field/hx-field.d.ts +17 -0
- package/dist/components/hx-field/hx-field.d.ts.map +1 -1
- package/dist/components/hx-field-label/hx-field-label.d.ts +17 -0
- package/dist/components/hx-field-label/hx-field-label.d.ts.map +1 -1
- package/dist/components/hx-file-upload/hx-file-upload.d.ts +18 -0
- package/dist/components/hx-file-upload/hx-file-upload.d.ts.map +1 -1
- package/dist/components/hx-form/hx-form.d.ts +19 -0
- package/dist/components/hx-form/hx-form.d.ts.map +1 -1
- package/dist/components/hx-help-text/hx-help-text.d.ts +17 -0
- package/dist/components/hx-help-text/hx-help-text.d.ts.map +1 -1
- package/dist/components/hx-icon-button/hx-icon-button.d.ts +18 -0
- package/dist/components/hx-icon-button/hx-icon-button.d.ts.map +1 -1
- package/dist/components/hx-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-menu/hx-menu.d.ts +18 -0
- package/dist/components/hx-menu/hx-menu.d.ts.map +1 -1
- package/dist/components/hx-nav/hx-nav.d.ts +18 -0
- package/dist/components/hx-nav/hx-nav.d.ts.map +1 -1
- package/dist/components/hx-nav/hx-nav.styles.d.ts.map +1 -1
- package/dist/components/hx-nav/index.js +1 -1
- package/dist/components/hx-number-input/hx-number-input.d.ts +18 -0
- package/dist/components/hx-number-input/hx-number-input.d.ts.map +1 -1
- package/dist/components/hx-number-input/index.js +1 -1
- package/dist/components/hx-overflow-menu/hx-overflow-menu.d.ts +18 -0
- package/dist/components/hx-overflow-menu/hx-overflow-menu.d.ts.map +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-popover/hx-popover.d.ts +18 -0
- package/dist/components/hx-popover/hx-popover.d.ts.map +1 -1
- package/dist/components/hx-popover/hx-popover.styles.d.ts.map +1 -1
- package/dist/components/hx-popover/index.js +1 -1
- package/dist/components/hx-popup/hx-popup.d.ts +18 -0
- package/dist/components/hx-popup/hx-popup.d.ts.map +1 -1
- package/dist/components/hx-popup/hx-popup.styles.d.ts.map +1 -1
- package/dist/components/hx-popup/index.js +1 -1
- package/dist/components/hx-radio-group/hx-radio-group.d.ts +18 -0
- package/dist/components/hx-radio-group/hx-radio-group.d.ts.map +1 -1
- package/dist/components/hx-radio-group/hx-radio-group.styles.d.ts.map +1 -1
- package/dist/components/hx-radio-group/hx-radio.styles.d.ts.map +1 -1
- package/dist/components/hx-radio-group/index.js +1 -1
- package/dist/components/hx-rating/hx-rating.d.ts +19 -0
- package/dist/components/hx-rating/hx-rating.d.ts.map +1 -1
- package/dist/components/hx-select/hx-select.d.ts +18 -0
- package/dist/components/hx-select/hx-select.d.ts.map +1 -1
- package/dist/components/hx-side-nav/hx-side-nav.d.ts +18 -0
- package/dist/components/hx-side-nav/hx-side-nav.d.ts.map +1 -1
- package/dist/components/hx-side-nav/hx-side-nav.styles.d.ts.map +1 -1
- package/dist/components/hx-side-nav/index.js +1 -1
- package/dist/components/hx-slider/hx-slider.d.ts +19 -0
- package/dist/components/hx-slider/hx-slider.d.ts.map +1 -1
- package/dist/components/hx-split-button/hx-split-button.d.ts +18 -0
- package/dist/components/hx-split-button/hx-split-button.d.ts.map +1 -1
- package/dist/components/hx-split-button/hx-split-button.styles.d.ts.map +1 -1
- package/dist/components/hx-split-button/index.js +1 -1
- package/dist/components/hx-steps/index.js +1 -1
- package/dist/components/hx-switch/hx-switch.d.ts +18 -0
- package/dist/components/hx-switch/hx-switch.d.ts.map +1 -1
- package/dist/components/hx-switch/hx-switch.styles.d.ts.map +1 -1
- package/dist/components/hx-switch/index.js +1 -1
- package/dist/components/hx-tabs/hx-tab.styles.d.ts.map +1 -1
- package/dist/components/hx-tabs/hx-tabs.d.ts +18 -0
- package/dist/components/hx-tabs/hx-tabs.d.ts.map +1 -1
- package/dist/components/hx-tabs/index.js +1 -1
- package/dist/components/hx-text-input/hx-text-input.d.ts +18 -0
- package/dist/components/hx-text-input/hx-text-input.d.ts.map +1 -1
- package/dist/components/hx-text-input/hx-text-input.styles.d.ts.map +1 -1
- package/dist/components/hx-text-input/index.js +1 -1
- package/dist/components/hx-textarea/hx-textarea.d.ts +18 -0
- package/dist/components/hx-textarea/hx-textarea.d.ts.map +1 -1
- package/dist/components/hx-time-picker/hx-time-picker.d.ts +18 -0
- package/dist/components/hx-time-picker/hx-time-picker.d.ts.map +1 -1
- package/dist/components/hx-time-picker/hx-time-picker.styles.d.ts.map +1 -1
- package/dist/components/hx-time-picker/index.js +1 -1
- package/dist/components/hx-toast/hx-toast.d.ts +19 -0
- package/dist/components/hx-toast/hx-toast.d.ts.map +1 -1
- package/dist/components/hx-toggle-button/hx-toggle-button.d.ts +18 -0
- package/dist/components/hx-toggle-button/hx-toggle-button.d.ts.map +1 -1
- package/dist/components/hx-toggle-button/hx-toggle-button.styles.d.ts.map +1 -1
- package/dist/components/hx-toggle-button/index.js +1 -1
- package/dist/components/hx-tooltip/hx-tooltip.d.ts +18 -0
- package/dist/components/hx-tooltip/hx-tooltip.d.ts.map +1 -1
- package/dist/components/hx-tooltip/hx-tooltip.styles.d.ts.map +1 -1
- package/dist/components/hx-tooltip/index.js +1 -1
- package/dist/components/hx-top-nav/hx-top-nav.d.ts +18 -0
- package/dist/components/hx-top-nav/hx-top-nav.d.ts.map +1 -1
- package/dist/components/hx-top-nav/hx-top-nav.styles.d.ts.map +1 -1
- package/dist/components/hx-top-nav/index.js +1 -1
- package/dist/css/helix-all.css +298 -64
- package/dist/css/helix-core.css +24 -15
- package/dist/css/helix-forms.css +133 -32
- package/dist/css/helix-navigation.css +49 -5
- package/dist/css/helix-overlay.css +53 -0
- package/dist/css/helix-tokens.css +15 -13
- package/dist/css/helix-utility.css +39 -12
- package/dist/css/hx-action-bar.css +12 -0
- package/dist/css/hx-badge.css +5 -5
- package/dist/css/hx-button.css +15 -5
- package/dist/css/hx-checkbox-group.css +11 -0
- package/dist/css/hx-checkbox.css +20 -4
- package/dist/css/hx-color-picker.css +14 -1
- package/dist/css/hx-copy-button.css +5 -2
- package/dist/css/hx-date-picker.css +11 -3
- package/dist/css/hx-dropdown.css +13 -0
- package/dist/css/hx-icon-button.css +4 -5
- package/dist/css/hx-nav.css +24 -2
- package/dist/css/hx-number-input.css +8 -8
- package/dist/css/hx-pagination.css +6 -3
- package/dist/css/hx-popover.css +13 -0
- package/dist/css/hx-popup.css +14 -0
- package/dist/css/hx-radio-group.css +10 -0
- package/dist/css/hx-side-nav.css +7 -0
- package/dist/css/hx-split-button.css +22 -10
- package/dist/css/hx-switch.css +19 -1
- package/dist/css/hx-text-input.css +4 -1
- package/dist/css/hx-time-picker.css +7 -2
- package/dist/css/hx-toggle-button.css +29 -12
- package/dist/css/hx-tooltip.css +13 -0
- package/dist/css/hx-top-nav.css +12 -0
- package/dist/css/index.css +1 -1
- package/dist/css/manifest.json +57 -20
- package/dist/index.js +28 -28
- package/dist/shared/{hx-action-bar-CitgcpGv.js → hx-action-bar-BlEG4aZv.js} +41 -29
- package/dist/shared/hx-action-bar-BlEG4aZv.js.map +1 -0
- package/dist/shared/hx-alert-Bto8-TIi.js.map +1 -1
- package/dist/shared/{hx-badge-JlFtAdxS.js → hx-badge-DFL35nzi.js} +16 -16
- package/dist/shared/hx-badge-DFL35nzi.js.map +1 -0
- package/dist/shared/hx-banner-fpRnciIO.js.map +1 -1
- package/dist/shared/{hx-breadcrumb-item-3tKppF9h.js → hx-breadcrumb-item-D8xYqe3s.js} +56 -43
- package/dist/shared/hx-breadcrumb-item-D8xYqe3s.js.map +1 -0
- package/dist/shared/{hx-button-BOwAEcF1.js → hx-button-DOZTZnz-.js} +29 -19
- package/dist/shared/hx-button-DOZTZnz-.js.map +1 -0
- package/dist/shared/hx-button-group-D3QUmSzl.js +248 -0
- package/dist/shared/hx-button-group-D3QUmSzl.js.map +1 -0
- package/dist/shared/{hx-checkbox-CYd0YV_u.js → hx-checkbox-DcgyGS9V.js} +27 -11
- package/dist/shared/hx-checkbox-DcgyGS9V.js.map +1 -0
- package/dist/shared/{hx-checkbox-group-D5piJLY8.js → hx-checkbox-group-C0q6HDqn.js} +101 -58
- package/dist/shared/hx-checkbox-group-C0q6HDqn.js.map +1 -0
- package/dist/shared/hx-clinical-status-D3XQIOqX.js.map +1 -1
- package/dist/shared/{hx-color-picker-DBwJzT5f.js → hx-color-picker-CYjx8i8R.js} +97 -84
- package/dist/shared/hx-color-picker-CYjx8i8R.js.map +1 -0
- package/dist/shared/hx-combobox-NgJaLbs2.js.map +1 -1
- package/dist/shared/{hx-copy-button-sUVuikyH.js → hx-copy-button-DJirFCUL.js} +18 -15
- package/dist/shared/hx-copy-button-DJirFCUL.js.map +1 -0
- package/dist/shared/{hx-date-picker-B49yo4Vm.js → hx-date-picker-0PtEav0K.js} +71 -63
- package/dist/shared/hx-date-picker-0PtEav0K.js.map +1 -0
- package/dist/shared/hx-dialog-B4weoj_1.js.map +1 -1
- package/dist/shared/hx-drawer-CM_upadk.js.map +1 -1
- package/dist/shared/{hx-dropdown-D626S2ZG.js → hx-dropdown-xHwTJecv.js} +44 -31
- package/dist/shared/hx-dropdown-xHwTJecv.js.map +1 -0
- package/dist/shared/hx-field-label-BVRyyKeh.js.map +1 -1
- package/dist/shared/hx-field-zw0U1KVi.js.map +1 -1
- package/dist/shared/hx-file-upload-D3rKROK5.js.map +1 -1
- package/dist/shared/hx-form-CkChEATa.js.map +1 -1
- package/dist/shared/hx-help-text-Xb2Yr8x2.js.map +1 -1
- package/dist/shared/{hx-icon-button-a6OpeQz5.js → hx-icon-button-B2BdVdyK.js} +10 -11
- package/dist/shared/hx-icon-button-B2BdVdyK.js.map +1 -0
- package/dist/shared/hx-menu-divider-A6Guuzi_.js.map +1 -1
- package/dist/shared/{hx-nav-ldFM3Fle.js → hx-nav-ChMTfn7o.js} +66 -44
- package/dist/shared/hx-nav-ChMTfn7o.js.map +1 -0
- package/dist/shared/{hx-nav-item-CODtUlew.js → hx-nav-item-ClN17f1y.js} +62 -55
- package/dist/shared/hx-nav-item-ClN17f1y.js.map +1 -0
- package/dist/shared/{hx-number-input-yUzFOSC1.js → hx-number-input-MggsT7F0.js} +13 -13
- package/dist/shared/hx-number-input-MggsT7F0.js.map +1 -0
- package/dist/shared/hx-overflow-menu-DFjJAziP.js.map +1 -1
- package/dist/shared/{hx-pagination-C7y8GVyU.js → hx-pagination-D726PyTM.js} +7 -4
- package/dist/shared/hx-pagination-D726PyTM.js.map +1 -0
- package/dist/shared/{hx-popover-BAlAFOH9.js → hx-popover-BjB0nkcq.js} +51 -38
- package/dist/shared/hx-popover-BjB0nkcq.js.map +1 -0
- package/dist/shared/{hx-popup-COUXXZ9X.js → hx-popup-BiV_2evC.js} +59 -45
- package/dist/shared/hx-popup-BiV_2evC.js.map +1 -0
- package/dist/shared/{hx-radio-C7eTj5YI.js → hx-radio-BY4zpwdh.js} +81 -63
- package/dist/shared/hx-radio-BY4zpwdh.js.map +1 -0
- package/dist/shared/hx-rating-C3QP53k9.js.map +1 -1
- package/dist/shared/hx-select-DahFehiZ.js.map +1 -1
- package/dist/shared/hx-slider-Blmv_rwS.js.map +1 -1
- package/dist/shared/{hx-split-button-Ddle8iVx.js → hx-split-button-CdNz1XAu.js} +62 -50
- package/dist/shared/hx-split-button-CdNz1XAu.js.map +1 -0
- package/dist/shared/{hx-step-R2rjp1fT.js → hx-step-CUzliIK_.js} +3 -3
- package/dist/shared/hx-step-CUzliIK_.js.map +1 -0
- package/dist/shared/{hx-switch-TvKGvZJz.js → hx-switch-BCXuNxEH.js} +42 -24
- package/dist/shared/hx-switch-BCXuNxEH.js.map +1 -0
- package/dist/shared/{hx-tab-panel-DzsX8BHV.js → hx-tab-panel-BfisavKo.js} +47 -32
- package/dist/shared/hx-tab-panel-BfisavKo.js.map +1 -0
- package/dist/shared/{hx-text-input-D6FlOZM-.js → hx-text-input-V5sQOpDh.js} +5 -2
- package/dist/shared/hx-text-input-V5sQOpDh.js.map +1 -0
- package/dist/shared/hx-textarea-CNG590KY.js.map +1 -1
- package/dist/shared/{hx-time-picker-Bo7FWzmf.js → hx-time-picker-DfJkBwcX.js} +41 -36
- package/dist/shared/hx-time-picker-DfJkBwcX.js.map +1 -0
- package/dist/shared/{hx-toggle-button-DwBers3A.js → hx-toggle-button-xNVYeA3X.js} +64 -47
- package/dist/shared/hx-toggle-button-xNVYeA3X.js.map +1 -0
- package/dist/shared/{hx-tooltip-DVqtKPCD.js → hx-tooltip-CamO-9nd.js} +24 -11
- package/dist/shared/hx-tooltip-CamO-9nd.js.map +1 -0
- package/dist/shared/{hx-top-nav-DP6OFS8C.js → hx-top-nav-CsTxOtVI.js} +26 -14
- package/dist/shared/hx-top-nav-CsTxOtVI.js.map +1 -0
- package/dist/shared/toast-factory-Dht3pVsw.js.map +1 -1
- package/figma-inventory.json +1258 -386
- package/package.json +2 -2
- package/dist/shared/hx-action-bar-CitgcpGv.js.map +0 -1
- package/dist/shared/hx-badge-JlFtAdxS.js.map +0 -1
- package/dist/shared/hx-breadcrumb-item-3tKppF9h.js.map +0 -1
- package/dist/shared/hx-button-BOwAEcF1.js.map +0 -1
- package/dist/shared/hx-button-group-4NUBpkyC.js +0 -181
- package/dist/shared/hx-button-group-4NUBpkyC.js.map +0 -1
- package/dist/shared/hx-checkbox-CYd0YV_u.js.map +0 -1
- package/dist/shared/hx-checkbox-group-D5piJLY8.js.map +0 -1
- package/dist/shared/hx-color-picker-DBwJzT5f.js.map +0 -1
- package/dist/shared/hx-copy-button-sUVuikyH.js.map +0 -1
- package/dist/shared/hx-date-picker-B49yo4Vm.js.map +0 -1
- package/dist/shared/hx-dropdown-D626S2ZG.js.map +0 -1
- package/dist/shared/hx-icon-button-a6OpeQz5.js.map +0 -1
- package/dist/shared/hx-nav-item-CODtUlew.js.map +0 -1
- package/dist/shared/hx-nav-ldFM3Fle.js.map +0 -1
- package/dist/shared/hx-number-input-yUzFOSC1.js.map +0 -1
- package/dist/shared/hx-pagination-C7y8GVyU.js.map +0 -1
- package/dist/shared/hx-popover-BAlAFOH9.js.map +0 -1
- package/dist/shared/hx-popup-COUXXZ9X.js.map +0 -1
- package/dist/shared/hx-radio-C7eTj5YI.js.map +0 -1
- package/dist/shared/hx-split-button-Ddle8iVx.js.map +0 -1
- package/dist/shared/hx-step-R2rjp1fT.js.map +0 -1
- package/dist/shared/hx-switch-TvKGvZJz.js.map +0 -1
- package/dist/shared/hx-tab-panel-DzsX8BHV.js.map +0 -1
- package/dist/shared/hx-text-input-D6FlOZM-.js.map +0 -1
- package/dist/shared/hx-time-picker-Bo7FWzmf.js.map +0 -1
- package/dist/shared/hx-toggle-button-DwBers3A.js.map +0 -1
- package/dist/shared/hx-tooltip-DVqtKPCD.js.map +0 -1
- package/dist/shared/hx-top-nav-DP6OFS8C.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hx-form-CkChEATa.js","sources":["../../src/styles/form/form.scoped.css?raw","../../src/components/hx-form/hx-form.styles.ts","../../src/components/hx-form/hx-form.ts"],"sourcesContent":["export default \"hx-form{display:flex;flex-direction:column;gap:var(--hx-form-gap, var(--hx-space-4, 1rem));max-width:var(--hx-form-max-width, none);padding:var(--hx-form-padding, 0)}hx-form .hx-form-error-summary{border:var(--hx-border-width-thin, 1px) solid var(--hx-input-error-color, var(--hx-color-error-500, #dc3545));border-radius:var(--hx-border-radius-md, .375rem);background-color:var(--hx-color-error-50, #fef2f2);color:var(--hx-input-error-color, var(--hx-color-error-text, #c92a2a));padding:var(--hx-space-3, .75rem) var(--hx-space-4, 1rem);font-size:var(--hx-font-size-sm, .875rem);line-height:var(--hx-line-height-normal, 1.5);font-family:var(--hx-input-font-family, var(--hx-font-family-sans, sans-serif))}hx-form .hx-form-error-summary ul{margin:0;padding:0 0 0 var(--hx-space-4, 1rem)}hx-form .hx-form-error-summary li{margin-bottom:var(--hx-space-1, .25rem)}hx-form .hx-form-error-summary li:last-child{margin-bottom:0}hx-form .form-item{display:flex;flex-direction:column;gap:var(--hx-space-1, .25rem);font-family:var(--hx-input-font-family, var(--hx-font-family-sans, sans-serif))}hx-form .form-item+.form-item{margin-top:var(--hx-space-4, 1rem)}hx-form label{display:flex;align-items:baseline;gap:var(--hx-space-1, .25rem);font-size:var(--hx-font-size-sm, .875rem);font-weight:var(--hx-font-weight-medium, 500);color:var(--hx-input-label-color, var(--hx-color-neutral-700, #343a40));line-height:var(--hx-line-height-normal, 1.5)}hx-form .form-required{color:var(--hx-input-error-color, var(--hx-color-error-500, #dc3545));font-weight:var(--hx-font-weight-bold, 700)}hx-form .description{font-size:var(--hx-font-size-xs, .75rem);color:var(--hx-color-neutral-500, #6c757d);line-height:var(--hx-line-height-normal, 1.5)}hx-form .form-item :is(*,*:before,*:after){box-sizing:border-box}hx-form :is(input:is([type=text],[type=email],[type=password],[type=tel],[type=url],[type=search],[type=number]),textarea){display:block;width:100%;border:var(--hx-border-width-thin, 1px) solid var(--hx-input-border-color, var(--hx-color-neutral-300, #ced4da));border-radius:var(--hx-input-border-radius, var(--hx-border-radius-md, .375rem));background-color:var(--hx-input-bg, var(--hx-color-neutral-0, #ffffff));padding:var(--hx-space-2, .5rem) var(--hx-space-3, .75rem);font-family:var(--hx-input-font-family, var(--hx-font-family-sans, sans-serif));font-size:var(--hx-font-size-md, 1rem);color:var(--hx-input-color, var(--hx-color-neutral-800, #212529));line-height:var(--hx-line-height-normal, 1.5);transition:border-color var(--hx-transition-fast, .15s ease),box-shadow var(--hx-transition-fast, .15s ease)}hx-form input:is([type=text],[type=email],[type=password],[type=tel],[type=url],[type=search],[type=number]){min-height:var(--hx-size-10, 2.5rem)}hx-form :is(input:is([type=text],[type=email],[type=password],[type=tel],[type=url],[type=search],[type=number]),textarea)::placeholder{color:var(--hx-color-neutral-400, #adb5bd)}hx-form :is(input:is([type=text],[type=email],[type=password],[type=tel],[type=url],[type=search],[type=number]),textarea):focus{outline:0;border-color:var(--hx-input-focus-ring-color, var(--hx-focus-ring-color, #2563eb));box-shadow:0 0 0 var(--hx-focus-ring-width, 2px) color-mix(in srgb,var(--hx-input-focus-ring-color, var(--hx-focus-ring-color, #2563eb)) calc(var(--hx-focus-ring-opacity, .25) * 100%),transparent)}hx-form :is(input:is([type=text],[type=email],[type=password],[type=tel],[type=url],[type=search],[type=number]),textarea):disabled{opacity:var(--hx-opacity-disabled, .5);cursor:not-allowed;pointer-events:none}hx-form :is(input:is([type=text],[type=email],[type=password],[type=tel],[type=url],[type=search],[type=number]),textarea):read-only{background-color:var(--hx-color-neutral-100, #e9ecef)}hx-form input[type=search]::-webkit-search-decoration,hx-form input[type=search]::-webkit-search-cancel-button,hx-form input[type=search]::-webkit-search-results-button,hx-form input[type=search]::-webkit-search-results-decoration{-webkit-appearance:none}hx-form input[type=number]::-webkit-inner-spin-button,hx-form input[type=number]::-webkit-outer-spin-button{-webkit-appearance:none;margin:0}hx-form input[type=number]{appearance:textfield}hx-form textarea{min-height:var(--hx-textarea-min-height, var(--hx-size-20, 5rem));resize:vertical}hx-form select{display:block;width:100%;border:var(--hx-border-width-thin, 1px) solid var(--hx-select-border-color, var(--hx-color-neutral-300, #ced4da));border-radius:var(--hx-select-border-radius, var(--hx-border-radius-md, .375rem));background-color:var(--hx-select-bg, var(--hx-color-neutral-0, #ffffff));padding:var(--hx-space-2, .5rem) var(--hx-space-8, 2rem) var(--hx-space-2, .5rem) var(--hx-space-3, .75rem);font-family:var(--hx-select-font-family, var(--hx-font-family-sans, sans-serif));font-size:var(--hx-font-size-md, 1rem);color:var(--hx-select-color, var(--hx-color-neutral-800, #212529));line-height:var(--hx-line-height-normal, 1.5);min-height:var(--hx-input-height-md, var(--hx-size-10, 2.5rem));cursor:pointer;transition:border-color var(--hx-transition-fast, .15s ease),box-shadow var(--hx-transition-fast, .15s ease);appearance:none;-webkit-appearance:none;-moz-appearance:none;background-image:url(\\\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8'%3E%3Cpath d='M1 1.5L6 6.5L11 1.5' stroke='%236c757d' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round' fill='none'/%3E%3C/svg%3E\\\");background-repeat:no-repeat;background-position:right var(--hx-space-3, .75rem) center;background-size:12px 8px}hx-form select:focus{outline:0;border-color:var(--hx-select-focus-ring-color, var(--hx-focus-ring-color, #2563eb));box-shadow:0 0 0 var(--hx-focus-ring-width, 2px) color-mix(in srgb,var(--hx-select-focus-ring-color, var(--hx-focus-ring-color, #2563eb)) calc(var(--hx-focus-ring-opacity, .25) * 100%),transparent)}hx-form select:disabled{opacity:var(--hx-opacity-disabled, .5);cursor:not-allowed;pointer-events:none}hx-form select[multiple]{min-height:var(--hx-size-20, 5rem);padding-right:var(--hx-space-3, .75rem);background-image:none}hx-form select[multiple] option{padding:var(--hx-space-1, .25rem) var(--hx-space-2, .5rem)}hx-form select::-ms-expand{display:none}hx-form :is(input[type=checkbox],input[type=radio]){appearance:none;-webkit-appearance:none;-moz-appearance:none;display:inline-flex;align-items:center;justify-content:center;flex-shrink:0;margin:0;background-color:var(--hx-color-neutral-0, #ffffff);cursor:pointer;vertical-align:middle;transition:background-color var(--hx-transition-fast, .15s ease),border-color var(--hx-transition-fast, .15s ease),box-shadow var(--hx-transition-fast, .15s ease)}hx-form input[type=checkbox]{width:var(--hx-checkbox-size, var(--hx-size-5, 1.25rem));height:var(--hx-checkbox-size, var(--hx-size-5, 1.25rem));border:var(--hx-border-width-medium, 2px) solid var(--hx-checkbox-border-color, var(--hx-color-neutral-300, #ced4da));border-radius:var(--hx-checkbox-border-radius, var(--hx-border-radius-sm, .25rem))}hx-form input[type=checkbox]:checked{background-color:var(--hx-checkbox-checked-bg, var(--hx-color-primary-500, #2563eb));border-color:var(--hx-checkbox-checked-border-color, var(--hx-color-primary-500, #2563eb));background-image:url(\\\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none'%3E%3Cpath d='M3.5 8.5L6.5 11.5L12.5 4.5' stroke='%23ffffff' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E\\\");background-repeat:no-repeat;background-position:center;background-size:100%}hx-form input[type=checkbox]:indeterminate{background-color:var(--hx-checkbox-checked-bg, var(--hx-color-primary-500, #2563eb));border-color:var(--hx-checkbox-checked-border-color, var(--hx-color-primary-500, #2563eb));background-image:url(\\\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none'%3E%3Cpath d='M4 8H12' stroke='%23ffffff' stroke-width='2' stroke-linecap='round'/%3E%3C/svg%3E\\\");background-repeat:no-repeat;background-position:center;background-size:100%}hx-form input[type=checkbox]:focus-visible{outline:var(--hx-focus-ring-width, 2px) solid var(--hx-checkbox-focus-ring-color, var(--hx-focus-ring-color, #2563eb));outline-offset:var(--hx-focus-ring-offset, 2px)}hx-form input[type=checkbox]:hover:not(:disabled){border-color:var(--hx-color-primary-500, #2563eb)}hx-form input[type=checkbox]:checked:hover:not(:disabled){filter:brightness(var(--hx-filter-brightness-hover, .9))}hx-form :is(input[type=checkbox],input[type=radio]):disabled{opacity:var(--hx-opacity-disabled, .5);cursor:not-allowed;pointer-events:none}hx-form :is(.form-type-checkbox,.form-type-checkbox-toggle){display:flex;align-items:flex-start;gap:var(--hx-space-2, .5rem)}hx-form :is(.form-type-checkbox,.form-type-checkbox-toggle) label{font-size:var(--hx-font-size-sm, .875rem);font-weight:var(--hx-font-weight-medium, 500);color:var(--hx-checkbox-label-color, var(--hx-color-neutral-700, #343a40));line-height:var(--hx-line-height-normal, 1.5);cursor:pointer;user-select:none;-webkit-user-select:none}hx-form input[type=radio]{width:var(--hx-radio-size, var(--hx-size-5, 1.25rem));height:var(--hx-radio-size, var(--hx-size-5, 1.25rem));border:var(--hx-border-width-medium, 2px) solid var(--hx-radio-border-color, var(--hx-color-neutral-300, #ced4da));border-radius:var(--hx-border-radius-full, 9999px)}hx-form input[type=radio]:checked{border-color:var(--hx-radio-checked-border-color, var(--hx-color-primary-500, #2563eb));background-color:var(--hx-radio-checked-bg, var(--hx-color-primary-500, #2563eb));box-shadow:inset 0 0 0 calc(var(--hx-radio-size, var(--hx-size-5, 1.25rem)) * .3) var(--hx-radio-dot-color, var(--hx-color-neutral-0, #ffffff))}hx-form input[type=radio]:focus-visible{outline:var(--hx-focus-ring-width, 2px) solid var(--hx-radio-focus-ring-color, var(--hx-focus-ring-color, #2563eb));outline-offset:var(--hx-focus-ring-offset, 2px)}hx-form input[type=radio]:hover:not(:disabled):not(:checked){border-color:var(--hx-color-neutral-400, #adb5bd)}hx-form .form-type-radio{display:inline-flex;align-items:center;gap:var(--hx-space-2, .5rem)}hx-form .form-type-radio label{font-size:var(--hx-font-size-md, 1rem);color:var(--hx-radio-label-color, var(--hx-color-neutral-700, #343a40));line-height:var(--hx-line-height-normal, 1.5);cursor:pointer;user-select:none;-webkit-user-select:none}hx-form .form-radios{display:flex;flex-direction:column;gap:var(--hx-radio-group-gap, var(--hx-space-3, .75rem))}hx-form .form-radios--horizontal{flex-direction:row;flex-wrap:wrap}hx-form .form-type-switch{display:flex;flex-direction:column;gap:var(--hx-space-1, .25rem);font-family:var(--hx-font-family-sans, sans-serif)}hx-form .form-type-switch .switch__control-row{display:flex;align-items:center;gap:var(--hx-space-2, .5rem)}hx-form .form-type-switch input[type=checkbox]{position:relative;width:var(--hx-switch-track-width-md, var(--hx-size-10, 2.5rem));height:var(--hx-switch-track-height-md, var(--hx-size-5-5, 1.375rem));border:none;border-radius:var(--hx-border-radius-full, 9999px);background-color:var(--hx-switch-track-bg, var(--hx-color-neutral-300, #ced4da));transition:background-color var(--hx-transition-fast, .15s ease);background-image:none}hx-form .form-type-switch input[type=checkbox]:before{content:\\\"\\\";position:absolute;top:50%;left:var(--hx-switch-thumb-offset, var(--hx-space-0-5, .125rem));transform:translateY(-50%);width:var(--hx-switch-thumb-size-md, var(--hx-size-4-5, 1.125rem));height:var(--hx-switch-thumb-size-md, var(--hx-size-4-5, 1.125rem));border-radius:var(--hx-border-radius-full, 9999px);background-color:var(--hx-switch-thumb-bg, var(--hx-color-neutral-0, #ffffff));box-shadow:var(--hx-switch-thumb-shadow, var(--hx-shadow-sm, 0 1px 2px 0 rgb(0 0 0 / .05)));transition:transform var(--hx-transition-fast, .15s ease)}hx-form .form-type-switch input[type=checkbox]:checked{background-color:var(--hx-switch-track-checked-bg, var(--hx-color-primary-500, #2563eb));background-image:none}hx-form .form-type-switch input[type=checkbox]:checked:before{transform:translateY(-50%) translate(var(--hx-switch-thumb-size-md, var(--hx-size-4-5, 1.125rem)))}hx-form .form-type-switch input[type=checkbox]:focus-visible{outline:var(--hx-focus-ring-width, 2px) solid var(--hx-switch-focus-ring-color, var(--hx-focus-ring-color, #2563eb));outline-offset:var(--hx-focus-ring-offset, 2px)}hx-form .form-type-switch input[type=checkbox]:disabled{opacity:var(--hx-opacity-disabled, .5);cursor:not-allowed;pointer-events:none}hx-form .form-type-switch label{font-size:var(--hx-font-size-sm, .875rem);font-weight:var(--hx-font-weight-medium, 500);color:var(--hx-switch-label-color, var(--hx-color-neutral-700, #343a40));line-height:var(--hx-line-height-normal, 1.5);cursor:pointer;user-select:none;-webkit-user-select:none}hx-form .form-type-switch--sm input[type=checkbox]{width:var(--hx-switch-track-width-sm, var(--hx-size-8, 2rem));height:var(--hx-switch-track-height-sm, var(--hx-size-4-5, 1.125rem))}hx-form .form-type-switch--sm input[type=checkbox]:before{width:var(--hx-switch-thumb-size-sm, var(--hx-size-3-5, .875rem));height:var(--hx-switch-thumb-size-sm, var(--hx-size-3-5, .875rem))}hx-form .form-type-switch--sm input[type=checkbox]:checked:before{transform:translateY(-50%) translate(var(--hx-switch-thumb-size-sm, var(--hx-size-3-5, .875rem)))}hx-form .form-type-switch--lg input[type=checkbox]{width:var(--hx-switch-track-width-lg, var(--hx-size-12, 3rem));height:var(--hx-switch-track-height-lg, var(--hx-size-6-5, 1.625rem))}hx-form .form-type-switch--lg input[type=checkbox]:before{width:var(--hx-switch-thumb-size-lg, var(--hx-size-5-5, 1.375rem));height:var(--hx-switch-thumb-size-lg, var(--hx-size-5-5, 1.375rem))}hx-form .form-type-switch--lg input[type=checkbox]:checked:before{transform:translateY(-50%) translate(var(--hx-switch-thumb-size-lg, var(--hx-size-5-5, 1.375rem)))}hx-form form{display:flex;flex-direction:column;gap:var(--hx-form-gap, var(--hx-space-4, 1rem));font-family:var(--hx-input-font-family, var(--hx-font-family-sans, sans-serif))}hx-form fieldset{border:var(--hx-border-width-thin, 1px) solid var(--hx-color-neutral-200, #dee2e6);border-radius:var(--hx-border-radius-md, .375rem);padding:var(--hx-space-4, 1rem);margin:0;display:flex;flex-direction:column;gap:var(--hx-space-4, 1rem)}hx-form :is(legend,summary){font-size:var(--hx-font-size-sm, .875rem);font-weight:var(--hx-font-weight-semibold, 600);color:var(--hx-color-neutral-700, #343a40);line-height:var(--hx-line-height-normal, 1.5)}hx-form legend{display:flex;align-items:baseline;gap:var(--hx-space-1, .25rem);padding:0 var(--hx-space-1, .25rem)}hx-form details{border:var(--hx-border-width-thin, 1px) solid var(--hx-color-neutral-200, #dee2e6);border-radius:var(--hx-border-radius-md, .375rem);padding:var(--hx-space-4, 1rem);margin:0}hx-form summary{cursor:pointer;padding:var(--hx-space-1, .25rem) 0;user-select:none;-webkit-user-select:none}hx-form summary:focus-visible{outline:var(--hx-focus-ring-width, 2px) solid var(--hx-focus-ring-color, #2563eb);outline-offset:var(--hx-focus-ring-offset, 2px);border-radius:var(--hx-border-radius-sm, .25rem)}hx-form .form-actions{display:flex;align-items:center;gap:var(--hx-space-3, .75rem);padding-top:var(--hx-space-4, 1rem)}hx-form .form-actions--end{justify-content:flex-end}hx-form .form-actions--between{justify-content:space-between}hx-form .form-columns{display:grid;gap:var(--hx-space-4, 1rem)}hx-form .form-columns--2{grid-template-columns:repeat(2,1fr)}hx-form .form-columns--3{grid-template-columns:repeat(3,1fr)}hx-form .form-columns--4{grid-template-columns:repeat(4,1fr)}@media(max-width:640px){hx-form .form-columns--2,hx-form .form-columns--3,hx-form .form-columns--4{grid-template-columns:1fr}}hx-form .form-item--full{grid-column:1 / -1}hx-form .form-inline{display:flex;flex-wrap:wrap;align-items:flex-end;gap:var(--hx-space-3, .75rem)}hx-form .form-inline .form-item{flex:1;min-width:0}hx-form .form-inline .form-item+.form-item{margin-top:0}hx-form .form-divider{border:none;border-top:var(--hx-border-width-thin, 1px) solid var(--hx-color-neutral-200, #dee2e6);margin:var(--hx-space-2, .5rem) 0}hx-form :is(.form-item.error,.form-item.has-error,.form-item--error) label{color:var(--hx-input-error-color, var(--hx-color-error-text, #c92a2a))}hx-form :is(.form-item.error,.form-item.has-error,.form-item--error) :is(input:is([type=text],[type=email],[type=password],[type=tel],[type=url],[type=search],[type=number]),textarea,select){border-color:var(--hx-input-error-color, var(--hx-color-error-500, #dc3545))}hx-form :is(.form-item.error,.form-item.has-error,.form-item--error) :is(input:is([type=text],[type=email],[type=password],[type=tel],[type=url],[type=search],[type=number]),textarea,select):focus{border-color:var(--hx-input-error-color, var(--hx-color-error-500, #dc3545));box-shadow:0 0 0 var(--hx-focus-ring-width, 2px) color-mix(in srgb,var(--hx-input-error-color, var(--hx-color-error-500, #dc3545)) calc(var(--hx-focus-ring-opacity, .25) * 100%),transparent)}hx-form :is(.form-item.error,.form-item.has-error,.form-item--error) input[type=checkbox]{border-color:var(--hx-checkbox-error-color, var(--hx-color-error-500, #dc3545))}hx-form :is(.form-item.error,.form-item.has-error,.form-item--error) input[type=checkbox]:checked{background-color:var(--hx-checkbox-error-color, var(--hx-color-error-500, #dc3545));border-color:var(--hx-checkbox-error-color, var(--hx-color-error-500, #dc3545))}hx-form :is(.form-item.error,.form-item.has-error,.form-item--error) input[type=radio]{border-color:var(--hx-color-error-500, #dc3545)}hx-form :is(.form-item__error-message,.form-item .error-message,.error-message,.form-item__success-message,.form-item .success-message,.success-message){font-size:var(--hx-font-size-xs, .75rem);line-height:var(--hx-line-height-normal, 1.5)}hx-form :is(.form-item__error-message,.form-item .error-message,.error-message){color:var(--hx-input-error-color, var(--hx-color-error-text, #c92a2a))}hx-form :is(.form-item__success-message,.form-item .success-message,.success-message){color:var(--hx-color-success-500, #198754)}hx-form :is(.form-item.success,.form-item.has-success,.form-item--success) label{color:var(--hx-color-success-500, #198754)}hx-form :is(.form-item.success,.form-item.has-success,.form-item--success) :is(input:is([type=text],[type=email],[type=password],[type=tel],[type=url],[type=search],[type=number]),textarea,select){border-color:var(--hx-color-success-500, #198754)}hx-form :is(.form-item.success,.form-item.has-success,.form-item--success) :is(input:is([type=text],[type=email],[type=password],[type=tel],[type=url],[type=search],[type=number]),textarea,select):focus{border-color:var(--hx-color-success-500, #198754);box-shadow:0 0 0 var(--hx-focus-ring-width, 2px) color-mix(in srgb,var(--hx-color-success-500, #198754) calc(var(--hx-focus-ring-opacity, .25) * 100%),transparent)}hx-form :is(.messages--error,.messages--status,.messages--warning){border:var(--hx-border-width-thin, 1px) solid;border-radius:var(--hx-border-radius-md, .375rem);padding:var(--hx-space-3, .75rem) var(--hx-space-4, 1rem);font-size:var(--hx-font-size-sm, .875rem);line-height:var(--hx-line-height-normal, 1.5)}hx-form .messages--error{border-color:var(--hx-input-error-color, var(--hx-color-error-500, #dc3545));background-color:var(--hx-color-error-50, #fef2f2);color:var(--hx-input-error-color, var(--hx-color-error-text, #c92a2a))}hx-form .messages--status{border-color:var(--hx-color-success-500, #198754);background-color:var(--hx-color-success-50, #f0fdf4);color:var(--hx-color-success-500, #198754)}hx-form .messages--warning{border-color:var(--hx-color-warning-500, #ffc107);background-color:var(--hx-color-warning-50, #fffbeb);color:var(--hx-color-warning-700, #92400e)}@media(forced-colors:active){hx-form :is(input:is([type=text],[type=email],[type=password],[type=tel],[type=url],[type=search],[type=number]),textarea,select):focus{outline:2px solid CanvasText;outline-offset:2px}hx-form .hx-form-error-summary{border-color:LinkText}}\\n\"","import formScopedCss from '../../styles/form/form.scoped.css?raw';\n\n/**\n * Scoped CSS for hx-form (applied to light DOM via CSSStyleSheet adoption).\n *\n * @media (forced-colors: active) rules are authored directly in\n * `../../styles/form/form.scoped.css` so they remain co-located with the\n * selectors they override. See the bottom of that file for the complete\n * forced-colors block.\n */\nexport const helixFormScopedCss = formScopedCss;\n","import { html, nothing } from 'lit';\nimport { customElement, property, state } from 'lit/decorators.js';\nimport { ifDefined } from 'lit/directives/if-defined.js';\nimport { HelixElement } from '../../base/index.js';\nimport { AdoptedStylesheetsController } from '../../controllers/adopted-stylesheets.js';\nimport { helixFormScopedCss } from './hx-form.styles.js';\n\n/**\n * A Light DOM form wrapper that styles native HTML form elements and\n * hx-* components with the design system's form styles.\n *\n * When `action` is set, renders a `<form>` wrapper around slotted content.\n * When no `action` is set (the Drupal pattern), renders only a `<slot>`\n * so Drupal can provide its own `<form>` tag.\n *\n * Uses adopted stylesheets to inject scoped CSS into the document without\n * Shadow DOM, keeping native form participation and Drupal compatibility.\n *\n * @summary Light DOM form wrapper with scoped styles for native and hx-* form elements.\n *\n * @tag hx-form\n *\n * @slot - Default slot for form fields and controls.\n *\n * @fires {CustomEvent<{valid: boolean, values: Record<string, FormDataEntryValue | FormDataEntryValue[]>, formData: FormData}>} hx-submit - Dispatched on valid client-side submit when no action is set.\n * @fires {CustomEvent<{errors: Array<{name: string, message: string}>}>} hx-invalid - Dispatched when validation fails on submit.\n * @fires {CustomEvent} hx-reset - Dispatched when the form is reset.\n *\n * @cssprop [--hx-form-gap=var(--hx-space-4)] - Gap between form fields.\n * @cssprop [--hx-form-max-width=none] - Maximum width of the form.\n * @cssprop [--hx-form-padding=0] - Internal padding of the form.\n */\n@customElement('hx-form')\nexport class HelixForm extends HelixElement {\n // ─── Light DOM ───\n\n override createRenderRoot(): HTMLElement {\n return this;\n }\n\n // ─── Adopted Stylesheets ───\n\n /**\n * Controller that injects scoped CSS into the document via adopted stylesheets for Light DOM styling.\n * @internal\n */\n private _styles = new AdoptedStylesheetsController(this, helixFormScopedCss, document);\n\n // ─── Internal State ───\n\n /**\n * Current list of validation errors rendered in the error summary and used to set aria-invalid on fields.\n * @internal\n */\n @state()\n private _validationErrors: Array<{ name: string; message: string }> = [];\n\n // ─── Lifecycle ───\n\n override connectedCallback(): void {\n super.connectedCallback();\n this.addEventListener('submit', this._handleSubmit);\n this.addEventListener('reset', this._handleReset);\n }\n\n override disconnectedCallback(): void {\n super.disconnectedCallback();\n this.removeEventListener('submit', this._handleSubmit);\n this.removeEventListener('reset', this._handleReset);\n }\n\n // ─── Properties ───\n\n /**\n * The URL to submit the form to. When empty, the form handles\n * submission client-side only and dispatches `hx-submit`.\n * @attr action\n */\n @property({ type: String })\n action = '';\n\n /**\n * The HTTP method used when submitting the form.\n * @attr method\n */\n @property({ type: String })\n method: 'get' | 'post' = 'post';\n\n /**\n * When true, disables the browser's built-in constraint validation\n * on form submission.\n * @attr novalidate\n */\n @property({ type: Boolean })\n novalidate = false;\n\n /**\n * Identifies the form for scripting and form discovery.\n * @attr name\n */\n @property({ type: String })\n name = '';\n\n /**\n * The encoding type for form submission. Only used when `action` is set.\n * Use `multipart/form-data` for forms with file uploads.\n * @attr enctype\n */\n @property({ type: String })\n enctype: 'application/x-www-form-urlencoded' | 'multipart/form-data' | 'text/plain' =\n 'application/x-www-form-urlencoded';\n\n // ─── Public Methods ───\n\n /**\n * Checks the validity of all child form elements without showing\n * validation UI. Returns `true` if all elements are valid.\n */\n checkValidity(): boolean {\n const formElements = this._getAllValidatableElements();\n return formElements.every((el) => {\n if ('checkValidity' in el && typeof el.checkValidity === 'function') {\n return (el as HTMLInputElement).checkValidity();\n }\n return true;\n });\n }\n\n /**\n * Checks validity and triggers the browser's constraint validation UI\n * on each invalid element. Returns `true` if all elements are valid.\n */\n reportValidity(): boolean {\n const formElements = this._getAllValidatableElements();\n let allValid = true;\n for (const el of formElements) {\n if ('reportValidity' in el && typeof el.reportValidity === 'function') {\n if (!(el as HTMLInputElement).reportValidity()) {\n allValid = false;\n }\n }\n }\n return allValid;\n }\n\n /**\n * Collects form data from all child form elements (native and hx-*).\n * Returns a `FormData` object.\n */\n getFormData(): FormData {\n // If there is a native <form> child, use it directly\n const formEl = this.querySelector('form');\n if (formEl) {\n return new FormData(formEl);\n }\n\n // Otherwise, manually collect from all named inputs\n const formData = new FormData();\n const elements = this.getNativeFormElements();\n for (const el of elements) {\n const input = el as HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement;\n if (!input.name) continue;\n\n if (input instanceof HTMLInputElement) {\n if (input.type === 'checkbox' || input.type === 'radio') {\n if (input.checked) {\n formData.append(input.name, input.value || 'on');\n }\n } else {\n formData.append(input.name, input.value);\n }\n } else {\n formData.append(input.name, input.value);\n }\n }\n\n return formData;\n }\n\n /**\n * Returns all child hx-* form components that implement the form\n * component contract (hx-text-input, hx-select, hx-checkbox, hx-textarea,\n * hx-radio-group, hx-switch).\n *\n * Note: This uses a hardcoded allowlist. When a new hx-* form component\n * is added, update this selector to include it.\n */\n getFormElements(): HTMLElement[] {\n return Array.from(\n this.querySelectorAll<HTMLElement>(\n 'hx-text-input, hx-select, hx-checkbox, hx-textarea, hx-radio-group, hx-switch',\n ),\n );\n }\n\n /**\n * Returns all native form elements (input, select, textarea, button)\n * found within this component's light DOM.\n */\n getNativeFormElements(): Array<\n HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement | HTMLButtonElement\n > {\n return Array.from(\n this.querySelectorAll<\n HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement | HTMLButtonElement\n >('input, select, textarea, button'),\n );\n }\n\n /**\n * Programmatically sets server-side validation errors on the form.\n * Renders an error summary and sets `aria-invalid=\"true\"` on named fields.\n *\n * Useful for surfacing Drupal server-side validation responses.\n *\n * @param errors - Array of `{name, message}` pairs matching field `name` attributes.\n */\n setErrors(errors: Array<{ name: string; message: string }>): void {\n this._validationErrors = errors;\n this._applyAriaInvalidFromErrors(errors);\n }\n\n /**\n * Programmatically sets a single field error. Merges with any existing errors.\n *\n * @param name - The `name` attribute of the field.\n * @param message - The error message to display.\n */\n setFieldError(name: string, message: string): void {\n const existing = this._validationErrors.filter((e) => e.name !== name);\n this.setErrors([...existing, { name, message }]);\n }\n\n /**\n * Clears all validation errors from the error summary and removes\n * `aria-invalid` from all fields.\n */\n clearErrors(): void {\n this._clearAriaInvalid();\n this._validationErrors = [];\n }\n\n // ─── Private Helpers ───\n\n /**\n * Returns all elements that support constraint validation, including\n * both native form elements and hx-* components with `checkValidity`.\n * @internal\n */\n private _getAllValidatableElements(): HTMLElement[] {\n const native = Array.from(this.querySelectorAll<HTMLElement>('input, select, textarea'));\n const wcElements = this.getFormElements().filter(\n (el): el is HTMLElement & { checkValidity: () => boolean } =>\n 'checkValidity' in el &&\n typeof (el as { checkValidity: unknown }).checkValidity === 'function',\n );\n return [...native, ...wcElements];\n }\n\n /**\n * Sets `aria-invalid=\"true\"` on fields with errors, removes it from valid fields.\n * @internal\n */\n private _applyAriaInvalidFromErrors(errors: Array<{ name: string; message: string }>): void {\n const errorNames = new Set(errors.map((e) => e.name));\n const allElements = this._getAllValidatableElements();\n for (const el of allElements) {\n const named = el as HTMLElement & { name?: string };\n const fieldName = named.name ?? el.tagName.toLowerCase();\n if (errorNames.has(fieldName)) {\n el.setAttribute('aria-invalid', 'true');\n } else {\n el.removeAttribute('aria-invalid');\n }\n }\n }\n\n /**\n * Sets `aria-invalid` based on native constraint validation state.\n * @internal\n */\n private _applyAriaInvalidFromValidity(): void {\n const allElements = this._getAllValidatableElements();\n for (const el of allElements) {\n if ('validity' in el) {\n const validatable = el as HTMLInputElement;\n if (!validatable.validity.valid) {\n el.setAttribute('aria-invalid', 'true');\n } else {\n el.removeAttribute('aria-invalid');\n }\n }\n }\n }\n\n /**\n * Removes `aria-invalid` from all validatable elements.\n * @internal\n */\n private _clearAriaInvalid(): void {\n const allElements = this._getAllValidatableElements();\n for (const el of allElements) {\n el.removeAttribute('aria-invalid');\n }\n }\n\n // ─── Event Handling ───\n\n /**\n * Handles native form submit events, intercepting for client-side validation and hx-submit dispatch.\n * @internal\n */\n private _handleSubmit = (e: Event): void => {\n // If there is an action, let native form submission happen\n if (this.action) {\n return;\n }\n\n // Client-side only: prevent default and dispatch hx-submit or hx-invalid\n e.preventDefault();\n\n if (!this.novalidate && !this.checkValidity()) {\n const errors = this._collectValidationErrors();\n this._validationErrors = errors;\n this._applyAriaInvalidFromValidity();\n\n // Move focus to the error summary after it renders so screen readers announce it\n // immediately. tabindex=\"-1\" on the summary allows programmatic focus (WCAG 2.4.3).\n void this.updateComplete.then(() => {\n const summary = this.querySelector<HTMLElement>('.hx-form-error-summary');\n summary?.focus();\n });\n\n /**\n * Dispatched when validation fails on submit.\n * @event hx-invalid\n */\n this.dispatchEvent(\n new CustomEvent<{ errors: Array<{ name: string; message: string }> }>('hx-invalid', {\n bubbles: true,\n composed: true,\n detail: { errors },\n }),\n );\n return;\n }\n\n // Clear any previous errors on successful submit\n this._validationErrors = [];\n this._clearAriaInvalid();\n\n const formData = this.getFormData();\n const values: Record<string, FormDataEntryValue | FormDataEntryValue[]> = {};\n for (const key of new Set(formData.keys())) {\n const all = formData.getAll(key);\n if (all.length === 1 && all[0] !== undefined) {\n values[key] = all[0];\n } else {\n values[key] = all;\n }\n }\n\n /**\n * Dispatched on valid client-side submit.\n * @event hx-submit\n */\n this.dispatchEvent(\n new CustomEvent<{\n valid: boolean;\n values: Record<string, FormDataEntryValue | FormDataEntryValue[]>;\n formData: FormData;\n }>('hx-submit', {\n bubbles: true,\n composed: true,\n detail: { valid: true, values, formData },\n }),\n );\n };\n\n /**\n * Handles native form reset events, clearing validation errors and dispatching hx-reset.\n * @internal\n */\n private _handleReset = (): void => {\n this._validationErrors = [];\n this._clearAriaInvalid();\n\n /**\n * Dispatched when the form is reset.\n * @event hx-reset\n */\n this.dispatchEvent(\n new CustomEvent<void>('hx-reset', {\n bubbles: true,\n composed: true,\n }),\n );\n };\n\n /**\n * Collects constraint validation errors from all validatable elements after a failed submit attempt.\n * @internal\n */\n private _collectValidationErrors(): Array<{ name: string; message: string }> {\n const errors: Array<{ name: string; message: string }> = [];\n const elements = this._getAllValidatableElements();\n\n for (const el of elements) {\n if ('validity' in el && 'validationMessage' in el) {\n const validatable = el as HTMLInputElement;\n if (!validatable.validity.valid) {\n errors.push({\n name: validatable.name || validatable.tagName.toLowerCase(),\n message: validatable.validationMessage,\n });\n }\n }\n }\n\n return errors;\n }\n\n // ─── Render ───\n\n override render() {\n const errorSummary =\n this._validationErrors.length > 0\n ? html`\n <div class=\"hx-form-error-summary\" role=\"alert\" aria-atomic=\"true\" tabindex=\"-1\">\n <ul>\n ${this._validationErrors.map(\n (error) => html`<li>${error.message || error.name}</li>`,\n )}\n </ul>\n </div>\n `\n : nothing;\n\n if (this.action) {\n return html`\n ${errorSummary}\n <form\n action=${this.action}\n method=${this.method}\n enctype=${this.enctype}\n name=${ifDefined(this.name || undefined)}\n ?novalidate=${this.novalidate}\n >\n <slot></slot>\n </form>\n `;\n }\n\n return html`${errorSummary}<slot></slot>`;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'hx-form': HelixForm;\n }\n}\n"],"names":["formScopedCss","helixFormScopedCss","HelixForm","HelixElement","AdoptedStylesheetsController","errors","summary","formData","values","key","all","el","formElements","allValid","formEl","elements","input","name","message","existing","e","native","wcElements","errorNames","allElements","fieldName","validatable","errorSummary","html","error","nothing","ifDefined","__decorateClass","state","property","customElement"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"hx-form-CkChEATa.js","sources":["../../src/styles/form/form.scoped.css?raw","../../src/components/hx-form/hx-form.styles.ts","../../src/components/hx-form/hx-form.ts"],"sourcesContent":["export default \"hx-form{display:flex;flex-direction:column;gap:var(--hx-form-gap, var(--hx-space-4, 1rem));max-width:var(--hx-form-max-width, none);padding:var(--hx-form-padding, 0)}hx-form .hx-form-error-summary{border:var(--hx-border-width-thin, 1px) solid var(--hx-input-error-color, var(--hx-color-error-500, #dc3545));border-radius:var(--hx-border-radius-md, .375rem);background-color:var(--hx-color-error-50, #fef2f2);color:var(--hx-input-error-color, var(--hx-color-error-text, #c92a2a));padding:var(--hx-space-3, .75rem) var(--hx-space-4, 1rem);font-size:var(--hx-font-size-sm, .875rem);line-height:var(--hx-line-height-normal, 1.5);font-family:var(--hx-input-font-family, var(--hx-font-family-sans, sans-serif))}hx-form .hx-form-error-summary ul{margin:0;padding:0 0 0 var(--hx-space-4, 1rem)}hx-form .hx-form-error-summary li{margin-bottom:var(--hx-space-1, .25rem)}hx-form .hx-form-error-summary li:last-child{margin-bottom:0}hx-form .form-item{display:flex;flex-direction:column;gap:var(--hx-space-1, .25rem);font-family:var(--hx-input-font-family, var(--hx-font-family-sans, sans-serif))}hx-form .form-item+.form-item{margin-top:var(--hx-space-4, 1rem)}hx-form label{display:flex;align-items:baseline;gap:var(--hx-space-1, .25rem);font-size:var(--hx-font-size-sm, .875rem);font-weight:var(--hx-font-weight-medium, 500);color:var(--hx-input-label-color, var(--hx-color-neutral-700, #343a40));line-height:var(--hx-line-height-normal, 1.5)}hx-form .form-required{color:var(--hx-input-error-color, var(--hx-color-error-500, #dc3545));font-weight:var(--hx-font-weight-bold, 700)}hx-form .description{font-size:var(--hx-font-size-xs, .75rem);color:var(--hx-color-neutral-500, #6c757d);line-height:var(--hx-line-height-normal, 1.5)}hx-form .form-item :is(*,*:before,*:after){box-sizing:border-box}hx-form :is(input:is([type=text],[type=email],[type=password],[type=tel],[type=url],[type=search],[type=number]),textarea){display:block;width:100%;border:var(--hx-border-width-thin, 1px) solid var(--hx-input-border-color, var(--hx-color-neutral-300, #ced4da));border-radius:var(--hx-input-border-radius, var(--hx-border-radius-md, .375rem));background-color:var(--hx-input-bg, var(--hx-color-neutral-0, #ffffff));padding:var(--hx-space-2, .5rem) var(--hx-space-3, .75rem);font-family:var(--hx-input-font-family, var(--hx-font-family-sans, sans-serif));font-size:var(--hx-font-size-md, 1rem);color:var(--hx-input-color, var(--hx-color-neutral-800, #212529));line-height:var(--hx-line-height-normal, 1.5);transition:border-color var(--hx-transition-fast, .15s ease),box-shadow var(--hx-transition-fast, .15s ease)}hx-form input:is([type=text],[type=email],[type=password],[type=tel],[type=url],[type=search],[type=number]){min-height:var(--hx-size-10, 2.5rem)}hx-form :is(input:is([type=text],[type=email],[type=password],[type=tel],[type=url],[type=search],[type=number]),textarea)::placeholder{color:var(--hx-color-neutral-400, #adb5bd)}hx-form :is(input:is([type=text],[type=email],[type=password],[type=tel],[type=url],[type=search],[type=number]),textarea):focus{outline:0;border-color:var(--hx-input-focus-ring-color, var(--hx-focus-ring-color, #2563eb));box-shadow:0 0 0 var(--hx-focus-ring-width, 2px) color-mix(in srgb,var(--hx-input-focus-ring-color, var(--hx-focus-ring-color, #2563eb)) calc(var(--hx-focus-ring-opacity, .25) * 100%),transparent)}hx-form :is(input:is([type=text],[type=email],[type=password],[type=tel],[type=url],[type=search],[type=number]),textarea):disabled{opacity:var(--hx-opacity-disabled, .5);cursor:not-allowed;pointer-events:none}hx-form :is(input:is([type=text],[type=email],[type=password],[type=tel],[type=url],[type=search],[type=number]),textarea):read-only{background-color:var(--hx-color-neutral-100, #e9ecef)}hx-form input[type=search]::-webkit-search-decoration,hx-form input[type=search]::-webkit-search-cancel-button,hx-form input[type=search]::-webkit-search-results-button,hx-form input[type=search]::-webkit-search-results-decoration{-webkit-appearance:none}hx-form input[type=number]::-webkit-inner-spin-button,hx-form input[type=number]::-webkit-outer-spin-button{-webkit-appearance:none;margin:0}hx-form input[type=number]{appearance:textfield}hx-form textarea{min-height:var(--hx-textarea-min-height, var(--hx-size-20, 5rem));resize:vertical}hx-form select{display:block;width:100%;border:var(--hx-border-width-thin, 1px) solid var(--hx-select-border-color, var(--hx-color-neutral-300, #ced4da));border-radius:var(--hx-select-border-radius, var(--hx-border-radius-md, .375rem));background-color:var(--hx-select-bg, var(--hx-color-neutral-0, #ffffff));padding:var(--hx-space-2, .5rem) var(--hx-space-8, 2rem) var(--hx-space-2, .5rem) var(--hx-space-3, .75rem);font-family:var(--hx-select-font-family, var(--hx-font-family-sans, sans-serif));font-size:var(--hx-font-size-md, 1rem);color:var(--hx-select-color, var(--hx-color-neutral-800, #212529));line-height:var(--hx-line-height-normal, 1.5);min-height:var(--hx-input-height-md, var(--hx-size-10, 2.5rem));cursor:pointer;transition:border-color var(--hx-transition-fast, .15s ease),box-shadow var(--hx-transition-fast, .15s ease);appearance:none;-webkit-appearance:none;-moz-appearance:none;background-image:url(\\\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8'%3E%3Cpath d='M1 1.5L6 6.5L11 1.5' stroke='%236c757d' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round' fill='none'/%3E%3C/svg%3E\\\");background-repeat:no-repeat;background-position:right var(--hx-space-3, .75rem) center;background-size:12px 8px}hx-form select:focus{outline:0;border-color:var(--hx-select-focus-ring-color, var(--hx-focus-ring-color, #2563eb));box-shadow:0 0 0 var(--hx-focus-ring-width, 2px) color-mix(in srgb,var(--hx-select-focus-ring-color, var(--hx-focus-ring-color, #2563eb)) calc(var(--hx-focus-ring-opacity, .25) * 100%),transparent)}hx-form select:disabled{opacity:var(--hx-opacity-disabled, .5);cursor:not-allowed;pointer-events:none}hx-form select[multiple]{min-height:var(--hx-size-20, 5rem);padding-right:var(--hx-space-3, .75rem);background-image:none}hx-form select[multiple] option{padding:var(--hx-space-1, .25rem) var(--hx-space-2, .5rem)}hx-form select::-ms-expand{display:none}hx-form :is(input[type=checkbox],input[type=radio]){appearance:none;-webkit-appearance:none;-moz-appearance:none;display:inline-flex;align-items:center;justify-content:center;flex-shrink:0;margin:0;background-color:var(--hx-color-neutral-0, #ffffff);cursor:pointer;vertical-align:middle;transition:background-color var(--hx-transition-fast, .15s ease),border-color var(--hx-transition-fast, .15s ease),box-shadow var(--hx-transition-fast, .15s ease)}hx-form input[type=checkbox]{width:var(--hx-checkbox-size, var(--hx-size-5, 1.25rem));height:var(--hx-checkbox-size, var(--hx-size-5, 1.25rem));border:var(--hx-border-width-medium, 2px) solid var(--hx-checkbox-border-color, var(--hx-color-neutral-300, #ced4da));border-radius:var(--hx-checkbox-border-radius, var(--hx-border-radius-sm, .25rem))}hx-form input[type=checkbox]:checked{background-color:var(--hx-checkbox-checked-bg, var(--hx-color-primary-500, #2563eb));border-color:var(--hx-checkbox-checked-border-color, var(--hx-color-primary-500, #2563eb));background-image:url(\\\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none'%3E%3Cpath d='M3.5 8.5L6.5 11.5L12.5 4.5' stroke='%23ffffff' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E\\\");background-repeat:no-repeat;background-position:center;background-size:100%}hx-form input[type=checkbox]:indeterminate{background-color:var(--hx-checkbox-checked-bg, var(--hx-color-primary-500, #2563eb));border-color:var(--hx-checkbox-checked-border-color, var(--hx-color-primary-500, #2563eb));background-image:url(\\\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none'%3E%3Cpath d='M4 8H12' stroke='%23ffffff' stroke-width='2' stroke-linecap='round'/%3E%3C/svg%3E\\\");background-repeat:no-repeat;background-position:center;background-size:100%}hx-form input[type=checkbox]:focus-visible{outline:var(--hx-focus-ring-width, 2px) solid var(--hx-checkbox-focus-ring-color, var(--hx-focus-ring-color, #2563eb));outline-offset:var(--hx-focus-ring-offset, 2px)}hx-form input[type=checkbox]:hover:not(:disabled){border-color:var(--hx-color-primary-500, #2563eb)}hx-form input[type=checkbox]:checked:hover:not(:disabled){filter:brightness(var(--hx-filter-brightness-hover, .9))}hx-form :is(input[type=checkbox],input[type=radio]):disabled{opacity:var(--hx-opacity-disabled, .5);cursor:not-allowed;pointer-events:none}hx-form :is(.form-type-checkbox,.form-type-checkbox-toggle){display:flex;align-items:flex-start;gap:var(--hx-space-2, .5rem)}hx-form :is(.form-type-checkbox,.form-type-checkbox-toggle) label{font-size:var(--hx-font-size-sm, .875rem);font-weight:var(--hx-font-weight-medium, 500);color:var(--hx-checkbox-label-color, var(--hx-color-neutral-700, #343a40));line-height:var(--hx-line-height-normal, 1.5);cursor:pointer;user-select:none;-webkit-user-select:none}hx-form input[type=radio]{width:var(--hx-radio-size, var(--hx-size-5, 1.25rem));height:var(--hx-radio-size, var(--hx-size-5, 1.25rem));border:var(--hx-border-width-medium, 2px) solid var(--hx-radio-border-color, var(--hx-color-neutral-300, #ced4da));border-radius:var(--hx-border-radius-full, 9999px)}hx-form input[type=radio]:checked{border-color:var(--hx-radio-checked-border-color, var(--hx-color-primary-500, #2563eb));background-color:var(--hx-radio-checked-bg, var(--hx-color-primary-500, #2563eb));box-shadow:inset 0 0 0 calc(var(--hx-radio-size, var(--hx-size-5, 1.25rem)) * .3) var(--hx-radio-dot-color, var(--hx-color-neutral-0, #ffffff))}hx-form input[type=radio]:focus-visible{outline:var(--hx-focus-ring-width, 2px) solid var(--hx-radio-focus-ring-color, var(--hx-focus-ring-color, #2563eb));outline-offset:var(--hx-focus-ring-offset, 2px)}hx-form input[type=radio]:hover:not(:disabled):not(:checked){border-color:var(--hx-color-neutral-400, #adb5bd)}hx-form .form-type-radio{display:inline-flex;align-items:center;gap:var(--hx-space-2, .5rem)}hx-form .form-type-radio label{font-size:var(--hx-font-size-md, 1rem);color:var(--hx-radio-label-color, var(--hx-color-neutral-700, #343a40));line-height:var(--hx-line-height-normal, 1.5);cursor:pointer;user-select:none;-webkit-user-select:none}hx-form .form-radios{display:flex;flex-direction:column;gap:var(--hx-radio-group-gap, var(--hx-space-3, .75rem))}hx-form .form-radios--horizontal{flex-direction:row;flex-wrap:wrap}hx-form .form-type-switch{display:flex;flex-direction:column;gap:var(--hx-space-1, .25rem);font-family:var(--hx-font-family-sans, sans-serif)}hx-form .form-type-switch .switch__control-row{display:flex;align-items:center;gap:var(--hx-space-2, .5rem)}hx-form .form-type-switch input[type=checkbox]{position:relative;width:var(--hx-switch-track-width-md, var(--hx-size-10, 2.5rem));height:var(--hx-switch-track-height-md, var(--hx-size-5-5, 1.375rem));border:none;border-radius:var(--hx-border-radius-full, 9999px);background-color:var(--hx-switch-track-bg, var(--hx-color-neutral-300, #ced4da));transition:background-color var(--hx-transition-fast, .15s ease);background-image:none}hx-form .form-type-switch input[type=checkbox]:before{content:\\\"\\\";position:absolute;top:50%;left:var(--hx-switch-thumb-offset, var(--hx-space-0-5, .125rem));transform:translateY(-50%);width:var(--hx-switch-thumb-size-md, var(--hx-size-4-5, 1.125rem));height:var(--hx-switch-thumb-size-md, var(--hx-size-4-5, 1.125rem));border-radius:var(--hx-border-radius-full, 9999px);background-color:var(--hx-switch-thumb-bg, var(--hx-color-neutral-0, #ffffff));box-shadow:var(--hx-switch-thumb-shadow, var(--hx-shadow-sm, 0 1px 2px 0 rgb(0 0 0 / .05)));transition:transform var(--hx-transition-fast, .15s ease)}hx-form .form-type-switch input[type=checkbox]:checked{background-color:var(--hx-switch-track-checked-bg, var(--hx-color-primary-500, #2563eb));background-image:none}hx-form .form-type-switch input[type=checkbox]:checked:before{transform:translateY(-50%) translate(var(--hx-switch-thumb-size-md, var(--hx-size-4-5, 1.125rem)))}hx-form .form-type-switch input[type=checkbox]:focus-visible{outline:var(--hx-focus-ring-width, 2px) solid var(--hx-switch-focus-ring-color, var(--hx-focus-ring-color, #2563eb));outline-offset:var(--hx-focus-ring-offset, 2px)}hx-form .form-type-switch input[type=checkbox]:disabled{opacity:var(--hx-opacity-disabled, .5);cursor:not-allowed;pointer-events:none}hx-form .form-type-switch label{font-size:var(--hx-font-size-sm, .875rem);font-weight:var(--hx-font-weight-medium, 500);color:var(--hx-switch-label-color, var(--hx-color-neutral-700, #343a40));line-height:var(--hx-line-height-normal, 1.5);cursor:pointer;user-select:none;-webkit-user-select:none}hx-form .form-type-switch--sm input[type=checkbox]{width:var(--hx-switch-track-width-sm, var(--hx-size-8, 2rem));height:var(--hx-switch-track-height-sm, var(--hx-size-4-5, 1.125rem))}hx-form .form-type-switch--sm input[type=checkbox]:before{width:var(--hx-switch-thumb-size-sm, var(--hx-size-3-5, .875rem));height:var(--hx-switch-thumb-size-sm, var(--hx-size-3-5, .875rem))}hx-form .form-type-switch--sm input[type=checkbox]:checked:before{transform:translateY(-50%) translate(var(--hx-switch-thumb-size-sm, var(--hx-size-3-5, .875rem)))}hx-form .form-type-switch--lg input[type=checkbox]{width:var(--hx-switch-track-width-lg, var(--hx-size-12, 3rem));height:var(--hx-switch-track-height-lg, var(--hx-size-6-5, 1.625rem))}hx-form .form-type-switch--lg input[type=checkbox]:before{width:var(--hx-switch-thumb-size-lg, var(--hx-size-5-5, 1.375rem));height:var(--hx-switch-thumb-size-lg, var(--hx-size-5-5, 1.375rem))}hx-form .form-type-switch--lg input[type=checkbox]:checked:before{transform:translateY(-50%) translate(var(--hx-switch-thumb-size-lg, var(--hx-size-5-5, 1.375rem)))}hx-form form{display:flex;flex-direction:column;gap:var(--hx-form-gap, var(--hx-space-4, 1rem));font-family:var(--hx-input-font-family, var(--hx-font-family-sans, sans-serif))}hx-form fieldset{border:var(--hx-border-width-thin, 1px) solid var(--hx-color-neutral-200, #dee2e6);border-radius:var(--hx-border-radius-md, .375rem);padding:var(--hx-space-4, 1rem);margin:0;display:flex;flex-direction:column;gap:var(--hx-space-4, 1rem)}hx-form :is(legend,summary){font-size:var(--hx-font-size-sm, .875rem);font-weight:var(--hx-font-weight-semibold, 600);color:var(--hx-color-neutral-700, #343a40);line-height:var(--hx-line-height-normal, 1.5)}hx-form legend{display:flex;align-items:baseline;gap:var(--hx-space-1, .25rem);padding:0 var(--hx-space-1, .25rem)}hx-form details{border:var(--hx-border-width-thin, 1px) solid var(--hx-color-neutral-200, #dee2e6);border-radius:var(--hx-border-radius-md, .375rem);padding:var(--hx-space-4, 1rem);margin:0}hx-form summary{cursor:pointer;padding:var(--hx-space-1, .25rem) 0;user-select:none;-webkit-user-select:none}hx-form summary:focus-visible{outline:var(--hx-focus-ring-width, 2px) solid var(--hx-focus-ring-color, #2563eb);outline-offset:var(--hx-focus-ring-offset, 2px);border-radius:var(--hx-border-radius-sm, .25rem)}hx-form .form-actions{display:flex;align-items:center;gap:var(--hx-space-3, .75rem);padding-top:var(--hx-space-4, 1rem)}hx-form .form-actions--end{justify-content:flex-end}hx-form .form-actions--between{justify-content:space-between}hx-form .form-columns{display:grid;gap:var(--hx-space-4, 1rem)}hx-form .form-columns--2{grid-template-columns:repeat(2,1fr)}hx-form .form-columns--3{grid-template-columns:repeat(3,1fr)}hx-form .form-columns--4{grid-template-columns:repeat(4,1fr)}@media(max-width:640px){hx-form .form-columns--2,hx-form .form-columns--3,hx-form .form-columns--4{grid-template-columns:1fr}}hx-form .form-item--full{grid-column:1 / -1}hx-form .form-inline{display:flex;flex-wrap:wrap;align-items:flex-end;gap:var(--hx-space-3, .75rem)}hx-form .form-inline .form-item{flex:1;min-width:0}hx-form .form-inline .form-item+.form-item{margin-top:0}hx-form .form-divider{border:none;border-top:var(--hx-border-width-thin, 1px) solid var(--hx-color-neutral-200, #dee2e6);margin:var(--hx-space-2, .5rem) 0}hx-form :is(.form-item.error,.form-item.has-error,.form-item--error) label{color:var(--hx-input-error-color, var(--hx-color-error-text, #c92a2a))}hx-form :is(.form-item.error,.form-item.has-error,.form-item--error) :is(input:is([type=text],[type=email],[type=password],[type=tel],[type=url],[type=search],[type=number]),textarea,select){border-color:var(--hx-input-error-color, var(--hx-color-error-500, #dc3545))}hx-form :is(.form-item.error,.form-item.has-error,.form-item--error) :is(input:is([type=text],[type=email],[type=password],[type=tel],[type=url],[type=search],[type=number]),textarea,select):focus{border-color:var(--hx-input-error-color, var(--hx-color-error-500, #dc3545));box-shadow:0 0 0 var(--hx-focus-ring-width, 2px) color-mix(in srgb,var(--hx-input-error-color, var(--hx-color-error-500, #dc3545)) calc(var(--hx-focus-ring-opacity, .25) * 100%),transparent)}hx-form :is(.form-item.error,.form-item.has-error,.form-item--error) input[type=checkbox]{border-color:var(--hx-checkbox-error-color, var(--hx-color-error-500, #dc3545))}hx-form :is(.form-item.error,.form-item.has-error,.form-item--error) input[type=checkbox]:checked{background-color:var(--hx-checkbox-error-color, var(--hx-color-error-500, #dc3545));border-color:var(--hx-checkbox-error-color, var(--hx-color-error-500, #dc3545))}hx-form :is(.form-item.error,.form-item.has-error,.form-item--error) input[type=radio]{border-color:var(--hx-color-error-500, #dc3545)}hx-form :is(.form-item__error-message,.form-item .error-message,.error-message,.form-item__success-message,.form-item .success-message,.success-message){font-size:var(--hx-font-size-xs, .75rem);line-height:var(--hx-line-height-normal, 1.5)}hx-form :is(.form-item__error-message,.form-item .error-message,.error-message){color:var(--hx-input-error-color, var(--hx-color-error-text, #c92a2a))}hx-form :is(.form-item__success-message,.form-item .success-message,.success-message){color:var(--hx-color-success-500, #198754)}hx-form :is(.form-item.success,.form-item.has-success,.form-item--success) label{color:var(--hx-color-success-500, #198754)}hx-form :is(.form-item.success,.form-item.has-success,.form-item--success) :is(input:is([type=text],[type=email],[type=password],[type=tel],[type=url],[type=search],[type=number]),textarea,select){border-color:var(--hx-color-success-500, #198754)}hx-form :is(.form-item.success,.form-item.has-success,.form-item--success) :is(input:is([type=text],[type=email],[type=password],[type=tel],[type=url],[type=search],[type=number]),textarea,select):focus{border-color:var(--hx-color-success-500, #198754);box-shadow:0 0 0 var(--hx-focus-ring-width, 2px) color-mix(in srgb,var(--hx-color-success-500, #198754) calc(var(--hx-focus-ring-opacity, .25) * 100%),transparent)}hx-form :is(.messages--error,.messages--status,.messages--warning){border:var(--hx-border-width-thin, 1px) solid;border-radius:var(--hx-border-radius-md, .375rem);padding:var(--hx-space-3, .75rem) var(--hx-space-4, 1rem);font-size:var(--hx-font-size-sm, .875rem);line-height:var(--hx-line-height-normal, 1.5)}hx-form .messages--error{border-color:var(--hx-input-error-color, var(--hx-color-error-500, #dc3545));background-color:var(--hx-color-error-50, #fef2f2);color:var(--hx-input-error-color, var(--hx-color-error-text, #c92a2a))}hx-form .messages--status{border-color:var(--hx-color-success-500, #198754);background-color:var(--hx-color-success-50, #f0fdf4);color:var(--hx-color-success-500, #198754)}hx-form .messages--warning{border-color:var(--hx-color-warning-500, #ffc107);background-color:var(--hx-color-warning-50, #fffbeb);color:var(--hx-color-warning-700, #92400e)}@media(forced-colors:active){hx-form :is(input:is([type=text],[type=email],[type=password],[type=tel],[type=url],[type=search],[type=number]),textarea,select):focus{outline:2px solid CanvasText;outline-offset:2px}hx-form .hx-form-error-summary{border-color:LinkText}}\\n\"","import formScopedCss from '../../styles/form/form.scoped.css?raw';\n\n/**\n * Scoped CSS for hx-form (applied to light DOM via CSSStyleSheet adoption).\n *\n * @media (forced-colors: active) rules are authored directly in\n * `../../styles/form/form.scoped.css` so they remain co-located with the\n * selectors they override. See the bottom of that file for the complete\n * forced-colors block.\n */\nexport const helixFormScopedCss = formScopedCss;\n","import { html, nothing } from 'lit';\nimport { customElement, property, state } from 'lit/decorators.js';\nimport { ifDefined } from 'lit/directives/if-defined.js';\nimport { HelixElement } from '../../base/index.js';\nimport { AdoptedStylesheetsController } from '../../controllers/adopted-stylesheets.js';\nimport { helixFormScopedCss } from './hx-form.styles.js';\n\n/**\n * A Light DOM form wrapper that styles native HTML form elements and\n * hx-* components with the design system's form styles.\n *\n * When `action` is set, renders a `<form>` wrapper around slotted content.\n * When no `action` is set (the Drupal pattern), renders only a `<slot>`\n * so Drupal can provide its own `<form>` tag.\n *\n * Uses adopted stylesheets to inject scoped CSS into the document without\n * Shadow DOM, keeping native form participation and Drupal compatibility.\n *\n * @summary Light DOM form wrapper with scoped styles for native and hx-* form elements.\n *\n * @tag hx-form\n *\n * @slot - Default slot for form fields and controls.\n *\n * @fires {CustomEvent<{valid: boolean, values: Record<string, FormDataEntryValue | FormDataEntryValue[]>, formData: FormData}>} hx-submit - Dispatched on valid client-side submit when no action is set.\n * @fires {CustomEvent<{errors: Array<{name: string, message: string}>}>} hx-invalid - Dispatched when validation fails on submit.\n * @fires {CustomEvent} hx-reset - Dispatched when the form is reset.\n *\n * @cssprop [--hx-form-gap=var(--hx-space-4)] - Gap between form fields.\n * @cssprop [--hx-form-max-width=none] - Maximum width of the form.\n * @cssprop [--hx-form-padding=0] - Internal padding of the form.\n *\n * @aaa-certified 2026-05-09\n * @aaa-criteria 1.4.6, 1.4.9, 2.1.3, 2.3.3, 2.4.12, 2.4.13, 2.5.5, 3.2.5, 3.3.6, forced-colors, apg-keyboard\n * @aaa-audit src/components/hx-form/AAA-AUDIT.md\n * @keyboard-contract submit=Enter\n * @aria-pattern form\n * @aria-pattern-source https://www.w3.org/WAI/ARIA/apg/patterns/landmarks/form.html\n * @forced-colors-supported true\n * @stability stable\n * @since 3.7.0\n * @form-associated false\n * @theme-aware true\n * @brand-aware true\n * @drupal-sdc-eligible true\n * @react-wrapper-status complete\n * @figma-component-name hx-form\n * @priority-tier P0\n * @phi-handles false\n * @clinical-context none\n */\n@customElement('hx-form')\nexport class HelixForm extends HelixElement {\n // ─── Light DOM ───\n\n override createRenderRoot(): HTMLElement {\n return this;\n }\n\n // ─── Adopted Stylesheets ───\n\n /**\n * Controller that injects scoped CSS into the document via adopted stylesheets for Light DOM styling.\n * @internal\n */\n private _styles = new AdoptedStylesheetsController(this, helixFormScopedCss, document);\n\n // ─── Internal State ───\n\n /**\n * Current list of validation errors rendered in the error summary and used to set aria-invalid on fields.\n * @internal\n */\n @state()\n private _validationErrors: Array<{ name: string; message: string }> = [];\n\n // ─── Lifecycle ───\n\n override connectedCallback(): void {\n super.connectedCallback();\n this.addEventListener('submit', this._handleSubmit);\n this.addEventListener('reset', this._handleReset);\n }\n\n override disconnectedCallback(): void {\n super.disconnectedCallback();\n this.removeEventListener('submit', this._handleSubmit);\n this.removeEventListener('reset', this._handleReset);\n }\n\n // ─── Properties ───\n\n /**\n * The URL to submit the form to. When empty, the form handles\n * submission client-side only and dispatches `hx-submit`.\n * @attr action\n */\n @property({ type: String })\n action = '';\n\n /**\n * The HTTP method used when submitting the form.\n * @attr method\n */\n @property({ type: String })\n method: 'get' | 'post' = 'post';\n\n /**\n * When true, disables the browser's built-in constraint validation\n * on form submission.\n * @attr novalidate\n */\n @property({ type: Boolean })\n novalidate = false;\n\n /**\n * Identifies the form for scripting and form discovery.\n * @attr name\n */\n @property({ type: String })\n name = '';\n\n /**\n * The encoding type for form submission. Only used when `action` is set.\n * Use `multipart/form-data` for forms with file uploads.\n * @attr enctype\n */\n @property({ type: String })\n enctype: 'application/x-www-form-urlencoded' | 'multipart/form-data' | 'text/plain' =\n 'application/x-www-form-urlencoded';\n\n // ─── Public Methods ───\n\n /**\n * Checks the validity of all child form elements without showing\n * validation UI. Returns `true` if all elements are valid.\n */\n checkValidity(): boolean {\n const formElements = this._getAllValidatableElements();\n return formElements.every((el) => {\n if ('checkValidity' in el && typeof el.checkValidity === 'function') {\n return (el as HTMLInputElement).checkValidity();\n }\n return true;\n });\n }\n\n /**\n * Checks validity and triggers the browser's constraint validation UI\n * on each invalid element. Returns `true` if all elements are valid.\n */\n reportValidity(): boolean {\n const formElements = this._getAllValidatableElements();\n let allValid = true;\n for (const el of formElements) {\n if ('reportValidity' in el && typeof el.reportValidity === 'function') {\n if (!(el as HTMLInputElement).reportValidity()) {\n allValid = false;\n }\n }\n }\n return allValid;\n }\n\n /**\n * Collects form data from all child form elements (native and hx-*).\n * Returns a `FormData` object.\n */\n getFormData(): FormData {\n // If there is a native <form> child, use it directly\n const formEl = this.querySelector('form');\n if (formEl) {\n return new FormData(formEl);\n }\n\n // Otherwise, manually collect from all named inputs\n const formData = new FormData();\n const elements = this.getNativeFormElements();\n for (const el of elements) {\n const input = el as HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement;\n if (!input.name) continue;\n\n if (input instanceof HTMLInputElement) {\n if (input.type === 'checkbox' || input.type === 'radio') {\n if (input.checked) {\n formData.append(input.name, input.value || 'on');\n }\n } else {\n formData.append(input.name, input.value);\n }\n } else {\n formData.append(input.name, input.value);\n }\n }\n\n return formData;\n }\n\n /**\n * Returns all child hx-* form components that implement the form\n * component contract (hx-text-input, hx-select, hx-checkbox, hx-textarea,\n * hx-radio-group, hx-switch).\n *\n * Note: This uses a hardcoded allowlist. When a new hx-* form component\n * is added, update this selector to include it.\n */\n getFormElements(): HTMLElement[] {\n return Array.from(\n this.querySelectorAll<HTMLElement>(\n 'hx-text-input, hx-select, hx-checkbox, hx-textarea, hx-radio-group, hx-switch',\n ),\n );\n }\n\n /**\n * Returns all native form elements (input, select, textarea, button)\n * found within this component's light DOM.\n */\n getNativeFormElements(): Array<\n HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement | HTMLButtonElement\n > {\n return Array.from(\n this.querySelectorAll<\n HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement | HTMLButtonElement\n >('input, select, textarea, button'),\n );\n }\n\n /**\n * Programmatically sets server-side validation errors on the form.\n * Renders an error summary and sets `aria-invalid=\"true\"` on named fields.\n *\n * Useful for surfacing Drupal server-side validation responses.\n *\n * @param errors - Array of `{name, message}` pairs matching field `name` attributes.\n */\n setErrors(errors: Array<{ name: string; message: string }>): void {\n this._validationErrors = errors;\n this._applyAriaInvalidFromErrors(errors);\n }\n\n /**\n * Programmatically sets a single field error. Merges with any existing errors.\n *\n * @param name - The `name` attribute of the field.\n * @param message - The error message to display.\n */\n setFieldError(name: string, message: string): void {\n const existing = this._validationErrors.filter((e) => e.name !== name);\n this.setErrors([...existing, { name, message }]);\n }\n\n /**\n * Clears all validation errors from the error summary and removes\n * `aria-invalid` from all fields.\n */\n clearErrors(): void {\n this._clearAriaInvalid();\n this._validationErrors = [];\n }\n\n // ─── Private Helpers ───\n\n /**\n * Returns all elements that support constraint validation, including\n * both native form elements and hx-* components with `checkValidity`.\n * @internal\n */\n private _getAllValidatableElements(): HTMLElement[] {\n const native = Array.from(this.querySelectorAll<HTMLElement>('input, select, textarea'));\n const wcElements = this.getFormElements().filter(\n (el): el is HTMLElement & { checkValidity: () => boolean } =>\n 'checkValidity' in el &&\n typeof (el as { checkValidity: unknown }).checkValidity === 'function',\n );\n return [...native, ...wcElements];\n }\n\n /**\n * Sets `aria-invalid=\"true\"` on fields with errors, removes it from valid fields.\n * @internal\n */\n private _applyAriaInvalidFromErrors(errors: Array<{ name: string; message: string }>): void {\n const errorNames = new Set(errors.map((e) => e.name));\n const allElements = this._getAllValidatableElements();\n for (const el of allElements) {\n const named = el as HTMLElement & { name?: string };\n const fieldName = named.name ?? el.tagName.toLowerCase();\n if (errorNames.has(fieldName)) {\n el.setAttribute('aria-invalid', 'true');\n } else {\n el.removeAttribute('aria-invalid');\n }\n }\n }\n\n /**\n * Sets `aria-invalid` based on native constraint validation state.\n * @internal\n */\n private _applyAriaInvalidFromValidity(): void {\n const allElements = this._getAllValidatableElements();\n for (const el of allElements) {\n if ('validity' in el) {\n const validatable = el as HTMLInputElement;\n if (!validatable.validity.valid) {\n el.setAttribute('aria-invalid', 'true');\n } else {\n el.removeAttribute('aria-invalid');\n }\n }\n }\n }\n\n /**\n * Removes `aria-invalid` from all validatable elements.\n * @internal\n */\n private _clearAriaInvalid(): void {\n const allElements = this._getAllValidatableElements();\n for (const el of allElements) {\n el.removeAttribute('aria-invalid');\n }\n }\n\n // ─── Event Handling ───\n\n /**\n * Handles native form submit events, intercepting for client-side validation and hx-submit dispatch.\n * @internal\n */\n private _handleSubmit = (e: Event): void => {\n // If there is an action, let native form submission happen\n if (this.action) {\n return;\n }\n\n // Client-side only: prevent default and dispatch hx-submit or hx-invalid\n e.preventDefault();\n\n if (!this.novalidate && !this.checkValidity()) {\n const errors = this._collectValidationErrors();\n this._validationErrors = errors;\n this._applyAriaInvalidFromValidity();\n\n // Move focus to the error summary after it renders so screen readers announce it\n // immediately. tabindex=\"-1\" on the summary allows programmatic focus (WCAG 2.4.3).\n void this.updateComplete.then(() => {\n const summary = this.querySelector<HTMLElement>('.hx-form-error-summary');\n summary?.focus();\n });\n\n /**\n * Dispatched when validation fails on submit.\n * @event hx-invalid\n */\n this.dispatchEvent(\n new CustomEvent<{ errors: Array<{ name: string; message: string }> }>('hx-invalid', {\n bubbles: true,\n composed: true,\n detail: { errors },\n }),\n );\n return;\n }\n\n // Clear any previous errors on successful submit\n this._validationErrors = [];\n this._clearAriaInvalid();\n\n const formData = this.getFormData();\n const values: Record<string, FormDataEntryValue | FormDataEntryValue[]> = {};\n for (const key of new Set(formData.keys())) {\n const all = formData.getAll(key);\n if (all.length === 1 && all[0] !== undefined) {\n values[key] = all[0];\n } else {\n values[key] = all;\n }\n }\n\n /**\n * Dispatched on valid client-side submit.\n * @event hx-submit\n */\n this.dispatchEvent(\n new CustomEvent<{\n valid: boolean;\n values: Record<string, FormDataEntryValue | FormDataEntryValue[]>;\n formData: FormData;\n }>('hx-submit', {\n bubbles: true,\n composed: true,\n detail: { valid: true, values, formData },\n }),\n );\n };\n\n /**\n * Handles native form reset events, clearing validation errors and dispatching hx-reset.\n * @internal\n */\n private _handleReset = (): void => {\n this._validationErrors = [];\n this._clearAriaInvalid();\n\n /**\n * Dispatched when the form is reset.\n * @event hx-reset\n */\n this.dispatchEvent(\n new CustomEvent<void>('hx-reset', {\n bubbles: true,\n composed: true,\n }),\n );\n };\n\n /**\n * Collects constraint validation errors from all validatable elements after a failed submit attempt.\n * @internal\n */\n private _collectValidationErrors(): Array<{ name: string; message: string }> {\n const errors: Array<{ name: string; message: string }> = [];\n const elements = this._getAllValidatableElements();\n\n for (const el of elements) {\n if ('validity' in el && 'validationMessage' in el) {\n const validatable = el as HTMLInputElement;\n if (!validatable.validity.valid) {\n errors.push({\n name: validatable.name || validatable.tagName.toLowerCase(),\n message: validatable.validationMessage,\n });\n }\n }\n }\n\n return errors;\n }\n\n // ─── Render ───\n\n override render() {\n const errorSummary =\n this._validationErrors.length > 0\n ? html`\n <div class=\"hx-form-error-summary\" role=\"alert\" aria-atomic=\"true\" tabindex=\"-1\">\n <ul>\n ${this._validationErrors.map(\n (error) => html`<li>${error.message || error.name}</li>`,\n )}\n </ul>\n </div>\n `\n : nothing;\n\n if (this.action) {\n return html`\n ${errorSummary}\n <form\n action=${this.action}\n method=${this.method}\n enctype=${this.enctype}\n name=${ifDefined(this.name || undefined)}\n ?novalidate=${this.novalidate}\n >\n <slot></slot>\n </form>\n `;\n }\n\n return html`${errorSummary}<slot></slot>`;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'hx-form': HelixForm;\n }\n}\n"],"names":["formScopedCss","helixFormScopedCss","HelixForm","HelixElement","AdoptedStylesheetsController","errors","summary","formData","values","key","all","el","formElements","allValid","formEl","elements","input","name","message","existing","e","native","wcElements","errorNames","allElements","fieldName","validatable","errorSummary","html","error","nothing","ifDefined","__decorateClass","state","property","customElement"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hx-help-text-Xb2Yr8x2.js","sources":["../../src/components/hx-help-text/hx-help-text.styles.ts","../../src/components/hx-help-text/hx-help-text.ts"],"sourcesContent":["import { css } from 'lit';\n\nexport const helixHelpTextStyles = css`\n :host {\n display: block;\n }\n\n .help-text {\n display: inline-flex;\n align-items: baseline;\n gap: var(--hx-help-text-icon-gap, 0.375rem);\n font-family: var(--hx-help-text-font-family, var(--hx-font-family-sans, sans-serif));\n font-size: var(--hx-help-text-font-size, var(--hx-font-size-sm, 0.875rem));\n font-weight: var(--hx-help-text-font-weight, var(--hx-font-weight-normal, 400));\n line-height: var(--hx-help-text-line-height, var(--hx-line-height-normal, 1.5));\n color: var(--hx-help-text-color, var(--hx-color-text-muted, #4a5362));\n margin: 0;\n }\n\n .help-text__icon {\n flex-shrink: 0;\n display: inline-flex;\n align-items: center;\n }\n\n .help-text__text {\n min-width: 0;\n }\n\n /* ─── Variant: default ─── */\n\n .help-text--default {\n --hx-help-text-color: var(--hx-color-text-muted, #4a5362);\n }\n\n /* ─── Variant: error ─── */\n\n .help-text--error {\n --hx-help-text-color: var(--hx-color-error-600, #c92a2a);\n }\n\n /* ─── Variant: warning ─── */\n\n .help-text--warning {\n --hx-help-text-color: var(--hx-color-warning-700, #804605);\n }\n\n /* ─── Variant: success ─── */\n\n .help-text--success {\n --hx-help-text-color: var(--hx-color-success-700, #146831);\n }\n\n /* ─── High Contrast Mode (forced-colors) ─── */\n\n @media (forced-colors: active) {\n .help-text {\n color: GrayText;\n }\n\n .help-text--error {\n color: LinkText;\n }\n\n .help-text--warning {\n color: CanvasText;\n }\n\n .help-text--success {\n color: CanvasText;\n }\n }\n`;\n","import { html, nothing } from 'lit';\nimport '../../utilities/document-token-adoption.js';\nimport { customElement, property } from 'lit/decorators.js';\nimport { classMap } from 'lit/directives/class-map.js';\nimport { ifDefined } from 'lit/directives/if-defined.js';\nimport { HelixElement } from '../../base/index.js';\nimport { helixHelpTextStyles } from './hx-help-text.styles.js';\nimport { forcedColorsSurface } from '../../styles/forced-colors.js';\n\n/** Icon SVG for error variant (circle with exclamation mark). */\nconst errorIcon = html`<svg viewBox=\"0 0 16 16\" aria-hidden=\"true\" width=\"1em\" height=\"1em\">\n <circle cx=\"8\" cy=\"8\" r=\"7\" stroke=\"currentColor\" stroke-width=\"1.5\" fill=\"none\" />\n <line\n x1=\"8\"\n y1=\"4.5\"\n x2=\"8\"\n y2=\"8.5\"\n stroke=\"currentColor\"\n stroke-width=\"1.5\"\n stroke-linecap=\"round\"\n />\n <circle cx=\"8\" cy=\"11\" r=\"0.75\" fill=\"currentColor\" />\n</svg>`;\n\n/** Icon SVG for warning variant (triangle with exclamation mark). */\nconst warningIcon = html`<svg viewBox=\"0 0 16 16\" aria-hidden=\"true\" width=\"1em\" height=\"1em\">\n <path\n d=\"M7.134 2.5a1 1 0 011.732 0l5.196 9a1 1 0 01-.866 1.5H2.804a1 1 0 01-.866-1.5l5.196-9z\"\n stroke=\"currentColor\"\n stroke-width=\"1.25\"\n fill=\"none\"\n />\n <line\n x1=\"8\"\n y1=\"6\"\n x2=\"8\"\n y2=\"9\"\n stroke=\"currentColor\"\n stroke-width=\"1.25\"\n stroke-linecap=\"round\"\n />\n <circle cx=\"8\" cy=\"11\" r=\"0.625\" fill=\"currentColor\" />\n</svg>`;\n\n/** Icon SVG for success variant (circle with checkmark). */\nconst successIcon = html`<svg viewBox=\"0 0 16 16\" aria-hidden=\"true\" width=\"1em\" height=\"1em\">\n <circle cx=\"8\" cy=\"8\" r=\"7\" stroke=\"currentColor\" stroke-width=\"1.5\" fill=\"none\" />\n <path\n d=\"M5.25 8.25l1.75 1.75 3.75-3.75\"\n stroke=\"currentColor\"\n stroke-width=\"1.5\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n fill=\"none\"\n />\n</svg>`;\n\n/** Map of variant to icon template. Default has no icon. */\nconst variantIcons = {\n default: nothing,\n error: errorIcon,\n warning: warningIcon,\n success: successIcon,\n} as const;\n\n/**\n * Standardized help/hint text displayed below form fields.\n * Used by hx-field as a consistent sub-component for guidance and validation messages.\n *\n * Non-default variants render an inline icon alongside the text to satisfy\n * WCAG 1.4.1 (color is not the sole visual indicator). The `error` variant\n * uses `role=\"alert\"` for immediate screen-reader announcement; `warning`\n * and `success` use `aria-live=\"polite\"` for non-intrusive announcements.\n *\n * @summary Help text displayed below form controls for guidance or validation feedback.\n *\n * @tag hx-help-text\n *\n * @slot - The help text content.\n *\n * @csspart base - The root element of the help text.\n * @csspart icon - The icon wrapper (only rendered for non-default variants).\n * @csspart text - The text wrapper around the default slot.\n *\n * @cssprop [--hx-help-text-color=var(--hx-color-neutral-500)] - Text color.\n * @cssprop [--hx-help-text-font-family=var(--hx-font-family-sans)] - Font family.\n * @cssprop [--hx-help-text-font-size=var(--hx-font-size-sm)] - Font size.\n * @cssprop [--hx-help-text-font-weight=var(--hx-font-weight-normal)] - Font weight.\n * @cssprop [--hx-help-text-line-height=var(--hx-line-height-normal)] - Line height.\n * @cssprop [--hx-help-text-icon-gap=0.375rem] - Gap between icon and text.\n * @cssprop [--hx-font-family-sans] - Font family.\n * @cssprop [--hx-font-size-sm] - Font size.\n * @cssprop [--hx-font-weight-normal] - Font weight.\n * @cssprop [--hx-line-height-normal] - Line height.\n * @cssprop [--hx-color-neutral-500] - Color.\n * @cssprop [--hx-color-error-600] - Color.\n * @cssprop [--hx-color-warning-700] - Color.\n * @cssprop [--hx-color-success-700] - Color.\n */\n@customElement('hx-help-text')\nexport class HelixHelpText extends HelixElement {\n static override styles = [helixHelpTextStyles, forcedColorsSurface];\n\n /**\n * Visual variant that determines the text color and icon.\n * Use `error` for validation errors, `warning` for cautions, `success` for confirmation.\n * @attr variant\n */\n @property({ type: String, reflect: true })\n variant: 'default' | 'error' | 'warning' | 'success' = 'default';\n\n override render() {\n const classes = {\n 'help-text': true,\n [`help-text--${this.variant}`]: true,\n };\n\n const icon = variantIcons[this.variant];\n const role = this.variant === 'error' ? 'alert' : undefined;\n const ariaLive =\n this.variant === 'warning' || this.variant === 'success' ? 'polite' : undefined;\n\n return html`<span\n part=\"base\"\n class=${classMap(classes)}\n role=${ifDefined(role)}\n aria-live=${ifDefined(ariaLive)}\n >${icon !== nothing\n ? html`<span part=\"icon\" class=\"help-text__icon\">${icon}</span>`\n : nothing}<span part=\"text\" class=\"help-text__text\"><slot></slot></span>\n </span>`;\n }\n}\n\n/** Canonical type alias for the hx-help-text component. */\nexport type HxHelpText = HelixHelpText;\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'hx-help-text': HelixHelpText;\n }\n}\n"],"names":["helixHelpTextStyles","css","errorIcon","html","warningIcon","successIcon","variantIcons","nothing","HelixHelpText","HelixElement","classes","icon","role","ariaLive","classMap","ifDefined","forcedColorsSurface","__decorateClass","property","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;;;;;;ACQnC,MAAMC,IAAYC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,SAeZC,IAAcD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,SAoBdE,IAAcF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,SAadG,IAAe;AAAA,EACnB,SAASC;AAAA,EACT,OAAOL;AAAA,EACP,SAASE;AAAA,EACT,SAASC;AACX;
|
|
1
|
+
{"version":3,"file":"hx-help-text-Xb2Yr8x2.js","sources":["../../src/components/hx-help-text/hx-help-text.styles.ts","../../src/components/hx-help-text/hx-help-text.ts"],"sourcesContent":["import { css } from 'lit';\n\nexport const helixHelpTextStyles = css`\n :host {\n display: block;\n }\n\n .help-text {\n display: inline-flex;\n align-items: baseline;\n gap: var(--hx-help-text-icon-gap, 0.375rem);\n font-family: var(--hx-help-text-font-family, var(--hx-font-family-sans, sans-serif));\n font-size: var(--hx-help-text-font-size, var(--hx-font-size-sm, 0.875rem));\n font-weight: var(--hx-help-text-font-weight, var(--hx-font-weight-normal, 400));\n line-height: var(--hx-help-text-line-height, var(--hx-line-height-normal, 1.5));\n color: var(--hx-help-text-color, var(--hx-color-text-muted, #4a5362));\n margin: 0;\n }\n\n .help-text__icon {\n flex-shrink: 0;\n display: inline-flex;\n align-items: center;\n }\n\n .help-text__text {\n min-width: 0;\n }\n\n /* ─── Variant: default ─── */\n\n .help-text--default {\n --hx-help-text-color: var(--hx-color-text-muted, #4a5362);\n }\n\n /* ─── Variant: error ─── */\n\n .help-text--error {\n --hx-help-text-color: var(--hx-color-error-600, #c92a2a);\n }\n\n /* ─── Variant: warning ─── */\n\n .help-text--warning {\n --hx-help-text-color: var(--hx-color-warning-700, #804605);\n }\n\n /* ─── Variant: success ─── */\n\n .help-text--success {\n --hx-help-text-color: var(--hx-color-success-700, #146831);\n }\n\n /* ─── High Contrast Mode (forced-colors) ─── */\n\n @media (forced-colors: active) {\n .help-text {\n color: GrayText;\n }\n\n .help-text--error {\n color: LinkText;\n }\n\n .help-text--warning {\n color: CanvasText;\n }\n\n .help-text--success {\n color: CanvasText;\n }\n }\n`;\n","import { html, nothing } from 'lit';\nimport '../../utilities/document-token-adoption.js';\nimport { customElement, property } from 'lit/decorators.js';\nimport { classMap } from 'lit/directives/class-map.js';\nimport { ifDefined } from 'lit/directives/if-defined.js';\nimport { HelixElement } from '../../base/index.js';\nimport { helixHelpTextStyles } from './hx-help-text.styles.js';\nimport { forcedColorsSurface } from '../../styles/forced-colors.js';\n\n/** Icon SVG for error variant (circle with exclamation mark). */\nconst errorIcon = html`<svg viewBox=\"0 0 16 16\" aria-hidden=\"true\" width=\"1em\" height=\"1em\">\n <circle cx=\"8\" cy=\"8\" r=\"7\" stroke=\"currentColor\" stroke-width=\"1.5\" fill=\"none\" />\n <line\n x1=\"8\"\n y1=\"4.5\"\n x2=\"8\"\n y2=\"8.5\"\n stroke=\"currentColor\"\n stroke-width=\"1.5\"\n stroke-linecap=\"round\"\n />\n <circle cx=\"8\" cy=\"11\" r=\"0.75\" fill=\"currentColor\" />\n</svg>`;\n\n/** Icon SVG for warning variant (triangle with exclamation mark). */\nconst warningIcon = html`<svg viewBox=\"0 0 16 16\" aria-hidden=\"true\" width=\"1em\" height=\"1em\">\n <path\n d=\"M7.134 2.5a1 1 0 011.732 0l5.196 9a1 1 0 01-.866 1.5H2.804a1 1 0 01-.866-1.5l5.196-9z\"\n stroke=\"currentColor\"\n stroke-width=\"1.25\"\n fill=\"none\"\n />\n <line\n x1=\"8\"\n y1=\"6\"\n x2=\"8\"\n y2=\"9\"\n stroke=\"currentColor\"\n stroke-width=\"1.25\"\n stroke-linecap=\"round\"\n />\n <circle cx=\"8\" cy=\"11\" r=\"0.625\" fill=\"currentColor\" />\n</svg>`;\n\n/** Icon SVG for success variant (circle with checkmark). */\nconst successIcon = html`<svg viewBox=\"0 0 16 16\" aria-hidden=\"true\" width=\"1em\" height=\"1em\">\n <circle cx=\"8\" cy=\"8\" r=\"7\" stroke=\"currentColor\" stroke-width=\"1.5\" fill=\"none\" />\n <path\n d=\"M5.25 8.25l1.75 1.75 3.75-3.75\"\n stroke=\"currentColor\"\n stroke-width=\"1.5\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n fill=\"none\"\n />\n</svg>`;\n\n/** Map of variant to icon template. Default has no icon. */\nconst variantIcons = {\n default: nothing,\n error: errorIcon,\n warning: warningIcon,\n success: successIcon,\n} as const;\n\n/**\n * Standardized help/hint text displayed below form fields.\n * Used by hx-field as a consistent sub-component for guidance and validation messages.\n *\n * Non-default variants render an inline icon alongside the text to satisfy\n * WCAG 1.4.1 (color is not the sole visual indicator). The `error` variant\n * uses `role=\"alert\"` for immediate screen-reader announcement; `warning`\n * and `success` use `aria-live=\"polite\"` for non-intrusive announcements.\n *\n * @summary Help text displayed below form controls for guidance or validation feedback.\n *\n * @tag hx-help-text\n *\n * @slot - The help text content.\n *\n * @csspart base - The root element of the help text.\n * @csspart icon - The icon wrapper (only rendered for non-default variants).\n * @csspart text - The text wrapper around the default slot.\n *\n * @cssprop [--hx-help-text-color=var(--hx-color-neutral-500)] - Text color.\n * @cssprop [--hx-help-text-font-family=var(--hx-font-family-sans)] - Font family.\n * @cssprop [--hx-help-text-font-size=var(--hx-font-size-sm)] - Font size.\n * @cssprop [--hx-help-text-font-weight=var(--hx-font-weight-normal)] - Font weight.\n * @cssprop [--hx-help-text-line-height=var(--hx-line-height-normal)] - Line height.\n * @cssprop [--hx-help-text-icon-gap=0.375rem] - Gap between icon and text.\n * @cssprop [--hx-font-family-sans] - Font family.\n * @cssprop [--hx-font-size-sm] - Font size.\n * @cssprop [--hx-font-weight-normal] - Font weight.\n * @cssprop [--hx-line-height-normal] - Line height.\n * @cssprop [--hx-color-neutral-500] - Color.\n * @cssprop [--hx-color-error-600] - Color.\n * @cssprop [--hx-color-warning-700] - Color.\n * @cssprop [--hx-color-success-700] - Color.\n *\n * @aaa-certified 2026-05-09\n * @aaa-criteria 1.4.6, 1.4.9, 2.1.3, 2.3.3, 2.4.12, 2.4.13, 2.5.5, 3.2.5, 3.3.6, forced-colors, apg-keyboard\n * @aaa-audit src/components/hx-help-text/AAA-AUDIT.md\n * @aria-pattern label\n * @forced-colors-supported true\n * @stability stable\n * @since 3.7.0\n * @form-associated false\n * @theme-aware true\n * @brand-aware true\n * @drupal-sdc-eligible true\n * @react-wrapper-status complete\n * @figma-component-name hx-help-text\n * @priority-tier P0\n * @phi-handles false\n * @clinical-context none\n */\n@customElement('hx-help-text')\nexport class HelixHelpText extends HelixElement {\n static override styles = [helixHelpTextStyles, forcedColorsSurface];\n\n /**\n * Visual variant that determines the text color and icon.\n * Use `error` for validation errors, `warning` for cautions, `success` for confirmation.\n * @attr variant\n */\n @property({ type: String, reflect: true })\n variant: 'default' | 'error' | 'warning' | 'success' = 'default';\n\n override render() {\n const classes = {\n 'help-text': true,\n [`help-text--${this.variant}`]: true,\n };\n\n const icon = variantIcons[this.variant];\n const role = this.variant === 'error' ? 'alert' : undefined;\n const ariaLive =\n this.variant === 'warning' || this.variant === 'success' ? 'polite' : undefined;\n\n return html`<span\n part=\"base\"\n class=${classMap(classes)}\n role=${ifDefined(role)}\n aria-live=${ifDefined(ariaLive)}\n >${icon !== nothing\n ? html`<span part=\"icon\" class=\"help-text__icon\">${icon}</span>`\n : nothing}<span part=\"text\" class=\"help-text__text\"><slot></slot></span>\n </span>`;\n }\n}\n\n/** Canonical type alias for the hx-help-text component. */\nexport type HxHelpText = HelixHelpText;\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'hx-help-text': HelixHelpText;\n }\n}\n"],"names":["helixHelpTextStyles","css","errorIcon","html","warningIcon","successIcon","variantIcons","nothing","HelixHelpText","HelixElement","classes","icon","role","ariaLive","classMap","ifDefined","forcedColorsSurface","__decorateClass","property","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;;;;;;ACQnC,MAAMC,IAAYC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,SAeZC,IAAcD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,SAoBdE,IAAcF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,SAadG,IAAe;AAAA,EACnB,SAASC;AAAA,EACT,OAAOL;AAAA,EACP,SAASE;AAAA,EACT,SAASC;AACX;AAsDO,IAAMG,IAAN,cAA4BC,EAAa;AAAA,EAAzC,cAAA;AAAA,UAAA,GAAA,SAAA,GASL,KAAA,UAAuD;AAAA,EAAA;AAAA,EAE9C,SAAS;AAChB,UAAMC,IAAU;AAAA,MACd,aAAa;AAAA,MACb,CAAC,cAAc,KAAK,OAAO,EAAE,GAAG;AAAA,IAAA,GAG5BC,IAAOL,EAAa,KAAK,OAAO,GAChCM,IAAO,KAAK,YAAY,UAAU,UAAU,QAC5CC,IACJ,KAAK,YAAY,aAAa,KAAK,YAAY,YAAY,WAAW;AAExE,WAAOV;AAAA;AAAA,cAEGW,EAASJ,CAAO,CAAC;AAAA,aAClBK,EAAUH,CAAI,CAAC;AAAA,kBACVG,EAAUF,CAAQ,CAAC;AAAA,SAC5BF,MAASJ,IACRJ,8CAAiDQ,CAAI,YACrDJ,CAAO;AAAA;AAAA,EAEf;AACF;AAhCaC,EACK,SAAS,CAACR,GAAqBgB,CAAmB;AAQlEC,EAAA;AAAA,EADCC,EAAS,EAAE,MAAM,QAAQ,SAAS,IAAM;AAAA,GAR9BV,EASX,WAAA,WAAA,CAAA;AATWA,IAANS,EAAA;AAAA,EADNE,EAAc,cAAc;AAAA,GAChBX,CAAA;"}
|
|
@@ -2,9 +2,9 @@ import { css as p, html as u, nothing as d } from "lit";
|
|
|
2
2
|
import { property as n, customElement as x } from "lit/decorators.js";
|
|
3
3
|
import { classMap as b } from "lit/directives/class-map.js";
|
|
4
4
|
import { ifDefined as t } from "lit/directives/if-defined.js";
|
|
5
|
-
import { f } from "./forced-colors-CTEDFRGa.js";
|
|
6
|
-
import { m } from "./aria-delegation-Doq6RRUy.js";
|
|
7
|
-
import { H as
|
|
5
|
+
import { f as v } from "./forced-colors-CTEDFRGa.js";
|
|
6
|
+
import { m as f } from "./aria-delegation-Doq6RRUy.js";
|
|
7
|
+
import { H as m } from "./helix-element-BNEYeiys.js";
|
|
8
8
|
const g = p`
|
|
9
9
|
:host {
|
|
10
10
|
display: inline-block;
|
|
@@ -81,16 +81,15 @@ const g = p`
|
|
|
81
81
|
/* ─── Style Variants ─── */
|
|
82
82
|
|
|
83
83
|
.button--primary {
|
|
84
|
-
--hx-icon-button-bg: var(--hx-color-primary-
|
|
84
|
+
--hx-icon-button-bg: var(--hx-color-action-primary-bg, #0f7078);
|
|
85
85
|
--hx-icon-button-color: var(--hx-color-text-on-primary, #ffffff);
|
|
86
86
|
--hx-icon-button-border-color: transparent;
|
|
87
87
|
}
|
|
88
88
|
|
|
89
|
-
/*
|
|
90
|
-
|
|
91
|
-
icons. Pin fg at neutral-0 (5.82:1 on primary-600). Mirrors hx-button. */
|
|
89
|
+
/* Hover deepens to action.primary.bg-hover (primary-700) + neutral-0 = 7.03:1 AA.
|
|
90
|
+
Mirrors hx-button. */
|
|
92
91
|
.button--primary:hover {
|
|
93
|
-
--hx-icon-button-bg: var(--hx-color-primary-
|
|
92
|
+
--hx-icon-button-bg: var(--hx-color-action-primary-bg-hover, #0f6363);
|
|
94
93
|
--hx-icon-button-color: var(--hx-color-neutral-0, #ffffff);
|
|
95
94
|
}
|
|
96
95
|
|
|
@@ -228,7 +227,7 @@ var y = Object.defineProperty, _ = Object.getOwnPropertyDescriptor, i = (r, a, h
|
|
|
228
227
|
(l = r[c]) && (e = (s ? l(a, h, e) : l(e)) || e);
|
|
229
228
|
return s && e && y(a, h, e), e;
|
|
230
229
|
};
|
|
231
|
-
let o = class extends m
|
|
230
|
+
let o = class extends f(m) {
|
|
232
231
|
constructor() {
|
|
233
232
|
super(...arguments), this.label = "", this.variant = "ghost", this.size = "md", this.type = "button", this.disabled = !1, this.loading = !1, this.href = void 0, this.name = void 0, this.value = void 0;
|
|
234
233
|
}
|
|
@@ -347,7 +346,7 @@ let o = class extends m(v) {
|
|
|
347
346
|
`;
|
|
348
347
|
}
|
|
349
348
|
};
|
|
350
|
-
o.styles = [g,
|
|
349
|
+
o.styles = [g, v];
|
|
351
350
|
o.formAssociated = !0;
|
|
352
351
|
i([
|
|
353
352
|
n({ type: String })
|
|
@@ -382,4 +381,4 @@ o = i([
|
|
|
382
381
|
export {
|
|
383
382
|
o as H
|
|
384
383
|
};
|
|
385
|
-
//# sourceMappingURL=hx-icon-button-
|
|
384
|
+
//# sourceMappingURL=hx-icon-button-B2BdVdyK.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hx-icon-button-B2BdVdyK.js","sources":["../../src/components/hx-icon-button/hx-icon-button.styles.ts","../../src/components/hx-icon-button/hx-icon-button.ts"],"sourcesContent":["import { css } from 'lit';\n\nexport const helixIconButtonStyles = css`\n :host {\n display: inline-block;\n }\n\n :host([disabled]) {\n pointer-events: none;\n opacity: var(--hx-opacity-disabled, 0.5);\n }\n\n .button {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n border: var(--hx-border-width-thin, 1px) solid var(--hx-icon-button-border-color, transparent);\n border-radius: var(--hx-icon-button-border-radius, var(--hx-border-radius-md, 0.375rem));\n background-color: var(--hx-icon-button-bg, transparent);\n color: var(--hx-icon-button-color, var(--hx-color-primary-500, #429797));\n cursor: pointer;\n transition:\n background-color var(--hx-transition-fast, 150ms ease),\n color var(--hx-transition-fast, 150ms ease),\n border-color var(--hx-transition-fast, 150ms ease),\n box-shadow var(--hx-transition-fast, 150ms ease);\n text-decoration: none;\n user-select: none;\n -webkit-user-select: none;\n flex-shrink: 0;\n }\n\n .button:focus-visible {\n outline: var(--hx-focus-ring-width, 2px) solid\n var(--hx-icon-button-focus-ring-color, var(--hx-focus-ring-color, #0f7078));\n outline-offset: var(--hx-focus-ring-offset, 2px);\n }\n\n .button:active {\n filter: brightness(var(--hx-filter-brightness-active, 0.8));\n }\n\n /* ─── Size Variants ─── */\n\n /* WCAG 2.5.5 (healthcare mandate): minimum 44x44px touch target for all sizes.\n min-width/min-height override the explicit size tokens when they fall below\n the 2.75rem (44px) threshold, preserving the visual icon size via font-size. */\n\n .button--sm {\n padding: var(--hx-space-1, 0.25rem);\n width: var(--hx-icon-button-size, var(--hx-size-8, 2rem));\n height: var(--hx-icon-button-size, var(--hx-size-8, 2rem));\n min-width: var(--hx-touch-target-min, 2.75rem);\n min-height: var(--hx-touch-target-min, 2.75rem);\n font-size: var(--hx-font-size-sm, 0.875rem);\n }\n\n .button--md {\n padding: var(--hx-space-2, 0.5rem);\n width: var(--hx-icon-button-size, var(--hx-size-10, 2.5rem));\n height: var(--hx-icon-button-size, var(--hx-size-10, 2.5rem));\n min-width: var(--hx-touch-target-min, 2.75rem);\n min-height: var(--hx-touch-target-min, 2.75rem);\n font-size: var(--hx-font-size-md, 1rem);\n }\n\n .button--lg {\n padding: var(--hx-space-3, 0.75rem);\n width: var(--hx-icon-button-size, var(--hx-size-12, 3rem));\n height: var(--hx-icon-button-size, var(--hx-size-12, 3rem));\n min-width: var(--hx-touch-target-min, 2.75rem);\n min-height: var(--hx-touch-target-min, 2.75rem);\n font-size: var(--hx-font-size-lg, 1.125rem);\n }\n\n /* ─── Style Variants ─── */\n\n .button--primary {\n --hx-icon-button-bg: var(--hx-color-action-primary-bg, #0f7078);\n --hx-icon-button-color: var(--hx-color-text-on-primary, #ffffff);\n --hx-icon-button-border-color: transparent;\n }\n\n /* Hover deepens to action.primary.bg-hover (primary-700) + neutral-0 = 7.03:1 AA.\n Mirrors hx-button. */\n .button--primary:hover {\n --hx-icon-button-bg: var(--hx-color-action-primary-bg-hover, #0f6363);\n --hx-icon-button-color: var(--hx-color-neutral-0, #ffffff);\n }\n\n .button--secondary {\n --hx-icon-button-bg: transparent;\n --hx-icon-button-color: var(--hx-color-primary-500, #429797);\n --hx-icon-button-border-color: var(--hx-color-primary-500, #429797);\n }\n\n .button--secondary:hover {\n --hx-icon-button-bg: var(--hx-color-primary-50, #ebf8f8);\n }\n\n .button--tertiary {\n --hx-icon-button-bg: transparent;\n --hx-icon-button-color: var(--hx-color-text-strong, #202b39);\n --hx-icon-button-border-color: var(--hx-color-border-strong, #66787b);\n }\n\n .button--tertiary:hover {\n --hx-icon-button-bg: var(--hx-color-surface-sunken, #ebeee9);\n }\n\n .button--danger {\n --hx-icon-button-bg: var(--hx-color-error-500, #e5493e);\n --hx-icon-button-color: var(--hx-color-text-on-error, #ffffff);\n --hx-icon-button-border-color: transparent;\n }\n\n /* on-error tokens are tuned for error-500. error-600 + on-error drops\n icon contrast to 2.25:1 — fails AA. Pin fg at neutral-0\n (6.47:1 on error-600). Mirrors hx-button danger:hover. */\n .button--danger:hover {\n --hx-icon-button-bg: var(--hx-color-error-600, #c92a2a);\n --hx-icon-button-color: var(--hx-color-neutral-0, #ffffff);\n }\n\n .button--ghost {\n --hx-icon-button-bg: transparent;\n --hx-icon-button-color: var(--hx-color-primary-500, #429797);\n --hx-icon-button-border-color: transparent;\n }\n\n .button--ghost:hover {\n --hx-icon-button-bg: var(--hx-color-surface-raised, #f5f8f3);\n }\n\n /* ─── Icon Container ─── */\n\n .icon {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 1em;\n height: 1em;\n line-height: 1;\n pointer-events: none;\n }\n\n /* ─── Disabled ─── */\n\n .button[disabled] {\n cursor: not-allowed;\n /* P1-02 fix: opacity is set only on :host([disabled]) above to prevent\n multiplicative stacking (0.5 * 0.5 = 0.25). Do not add opacity here. */\n }\n\n /* ─── Loading State ─── */\n\n .button--loading {\n position: relative;\n cursor: wait;\n }\n\n .button__spinner {\n width: 1em;\n height: 1em;\n flex-shrink: 0;\n animation: hx-icon-button-spin var(--hx-duration-spinner, 750ms) linear infinite;\n }\n\n @keyframes hx-icon-button-spin {\n to {\n transform: rotate(360deg);\n }\n }\n\n /* ─── Reduced Motion ─── */\n\n @media (prefers-reduced-motion: reduce) {\n .button {\n transition: none;\n }\n\n .button__spinner {\n animation: none;\n opacity: var(--hx-opacity-muted, 0.6);\n }\n }\n\n /* ─── High Contrast Mode (forced-colors) ─── */\n\n @media (forced-colors: active) {\n .button {\n forced-color-adjust: none;\n background-color: ButtonFace;\n color: ButtonText;\n border: 2px solid ButtonText;\n }\n\n .button:focus-visible {\n outline: 3px solid Highlight;\n outline-offset: 2px;\n }\n\n .button[disabled] {\n background-color: ButtonFace;\n color: GrayText;\n border-color: GrayText;\n opacity: 1;\n }\n\n :host([disabled]) {\n opacity: 1;\n }\n\n .button--loading .button__spinner {\n stroke: ButtonText;\n forced-color-adjust: none;\n }\n }\n`;\n","import { html, nothing, type TemplateResult } from 'lit';\nimport '../../utilities/document-token-adoption.js';\nimport { customElement, property } from 'lit/decorators.js';\nimport { classMap } from 'lit/directives/class-map.js';\nimport { ifDefined } from 'lit/directives/if-defined.js';\nimport { HelixElement } from '../../base/index.js';\nimport { mixinDelegatesAria } from '../../mixins/index.js';\nimport { helixIconButtonStyles } from './hx-icon-button.styles.js';\nimport { forcedColorsInteractive } from '../../styles/forced-colors.js';\nimport { devWarn } from '../../utils/dev-warn.js';\n\n/**\n * An icon-only button component for compact, accessible actions.\n * Renders a square button or anchor element containing a single icon.\n * The `label` property is required and provides the accessible name\n * via `aria-label` and a native tooltip via the `title` attribute.\n *\n * @summary Icon-only action button with full accessibility support.\n *\n * @tag hx-icon-button\n *\n * @slot - Icon element to display (hx-icon, svg, or img).\n *\n * @fires {CustomEvent<{originalEvent: MouseEvent}>} hx-click - Dispatched when the button is clicked (not disabled).\n *\n * @csspart button - The native button or anchor element.\n * @csspart icon - The icon container span wrapping the default slot.\n * @csspart spinner - The loading spinner SVG element shown when `loading` is true.\n *\n * @cssprop [--hx-icon-button-bg=transparent] - Button background color.\n * @cssprop [--hx-icon-button-color=var(--hx-color-primary-500)] - Icon color.\n * @cssprop [--hx-icon-button-border-color=transparent] - Button border color.\n * @cssprop [--hx-icon-button-border-radius=var(--hx-border-radius-md)] - Button border radius.\n * @cssprop [--hx-icon-button-size] - Explicit width and height override for the button.\n * @cssprop [--hx-icon-button-focus-ring-color=var(--hx-focus-ring-color)] - Focus ring color.\n * @cssprop [--hx-opacity-disabled] - Opacity.\n * @cssprop [--hx-border-width-thin] - Width.\n * @cssprop [--hx-border-radius-md] - CSS custom property.\n * @cssprop [--hx-color-primary-500] - Color.\n * @cssprop [--hx-transition-fast] - Transition timing.\n * @cssprop [--hx-focus-ring-width] - Width.\n * @cssprop [--hx-focus-ring-color] - Color.\n * @cssprop [--hx-focus-ring-offset] - CSS custom property.\n * @cssprop [--hx-filter-brightness-active] - CSS filter.\n * @cssprop [--hx-space-1] - Spacing token.\n * @cssprop [--hx-size-8] - Size token.\n * @cssprop [--hx-touch-target-min] - Minimum touch target size.\n * @cssprop [--hx-font-size-sm] - Font size.\n * @cssprop [--hx-space-2] - Spacing token.\n * @cssprop [--hx-size-10] - Size token.\n * @cssprop [--hx-font-size-md] - Font size.\n * @cssprop [--hx-space-3] - Spacing token.\n * @cssprop [--hx-size-12] - Size token.\n * @cssprop [--hx-font-size-lg] - Font size.\n * @cssprop [--hx-color-neutral-0] - Color.\n * @cssprop [--hx-color-primary-600] - Color.\n * @cssprop [--hx-color-primary-50] - Color.\n * @cssprop [--hx-color-neutral-700] - Color.\n * @cssprop [--hx-color-neutral-300] - Color.\n * @cssprop [--hx-color-neutral-100] - Color.\n * @cssprop [--hx-color-error-500] - Color.\n * @cssprop [--hx-color-error-600] - Color.\n * @aaa-certified 2026-05-08\n * @aaa-criteria 1.4.6, 1.4.9, 2.1.3, 2.3.3, 2.4.12, 2.4.13, 2.5.5, 3.2.5, 3.3.6, forced-colors, apg-keyboard\n * @aaa-audit src/components/hx-icon-button/AAA-AUDIT.md\n * @keyboard-contract activate=Enter,Space; disabled-suppresses=true\n * @aria-pattern button\n * @aria-pattern-source https://www.w3.org/WAI/ARIA/apg/patterns/button/\n * @forced-colors-supported true\n * @stability stable\n * @since 3.7.0\n * @form-associated true\n * @theme-aware true\n * @brand-aware true\n * @drupal-sdc-eligible true\n * @react-wrapper-status complete\n * @figma-component-name hx-icon-button\n * @priority-tier P0\n * @phi-handles false\n * @clinical-context none\n */\n@customElement('hx-icon-button')\nexport class HelixIconButton extends mixinDelegatesAria(HelixElement) {\n static override styles = [helixIconButtonStyles, forcedColorsInteractive];\n\n /**\n * Accessible name for the button. Required. Rendered as `aria-label` and\n * `title` on the underlying element. The component renders nothing when absent,\n * and a console warning is emitted to alert developers during authoring.\n * @attr label\n */\n @property({ type: String })\n label = '';\n\n /**\n * Visual style variant of the button.\n * @attr variant\n */\n @property({ type: String, reflect: true })\n variant: 'primary' | 'secondary' | 'tertiary' | 'danger' | 'ghost' = 'ghost';\n\n /**\n * Size of the button.\n * @attr hx-size\n */\n @property({ type: String, reflect: true, attribute: 'hx-size' })\n size: 'sm' | 'md' | 'lg' = 'md';\n\n /**\n * The type attribute for the underlying button element.\n * Has no effect when `href` is set.\n * @attr type\n */\n @property({ type: String })\n type: 'button' | 'submit' | 'reset' = 'button';\n\n /**\n * Whether the button is disabled.\n * @attr disabled\n */\n @property({ type: Boolean, reflect: true })\n disabled = false;\n\n /**\n * Whether the button is in a loading state. Shows the spinner, prevents\n * activation, and sets `aria-busy=\"true\"` on the inner element. Does NOT\n * set the native `disabled` attribute (loading is transient; disabled is\n * persistent, and AT announces them differently).\n * @attr loading\n */\n @property({ type: Boolean, reflect: true })\n loading = false;\n\n /**\n * When set, renders an `<a>` element instead of a `<button>`.\n * @attr href\n */\n @property({ type: String })\n href: string | undefined = undefined;\n\n /**\n * Name submitted with form data. Only applicable when rendering as a button.\n * @attr name\n */\n @property({ type: String })\n name: string | undefined = undefined;\n\n /**\n * Value submitted with form data. Only applicable when rendering as a button.\n * @attr value\n */\n @property({ type: String })\n value: string | undefined = undefined;\n\n // ─── Form Association ───\n\n /** Marks this element as form-associated for ElementInternals support. @internal */\n static override formAssociated = true;\n\n protected override _onFormDisabled(disabled: boolean): void {\n this.disabled = disabled;\n }\n\n // ─── Event Handling ───\n\n /** @internal */\n private _handleClick(e: MouseEvent): void {\n if (this.disabled || this.loading) {\n e.preventDefault();\n e.stopPropagation();\n return;\n }\n\n /**\n * Dispatched when the button is clicked.\n * @event hx-click\n */\n this.dispatchEvent(\n new CustomEvent<{ originalEvent: MouseEvent }>('hx-click', {\n bubbles: true,\n composed: true,\n detail: { originalEvent: e },\n }),\n );\n\n // Handle form submission/reset if form-associated and not in href/link mode\n if (!this.href) {\n if (this.type === 'submit' && this._internals.form) {\n this._internals.form.requestSubmit();\n } else if (this.type === 'reset' && this._internals.form) {\n this._internals.form.reset();\n }\n }\n }\n\n // ─── Render Helpers ───\n\n /** @internal */\n private _normalizedLabel(): string {\n return this.label.trim();\n }\n\n /** @internal */\n private _classes() {\n return {\n button: true,\n [`button--${this.variant}`]: true,\n [`button--${this.size}`]: true,\n 'button--loading': this.loading,\n };\n }\n\n /** @internal */\n private _iconSlot() {\n return html`<span part=\"icon\" class=\"icon\"><slot></slot></span>`;\n }\n\n /** @internal */\n private _renderSpinner(): TemplateResult {\n return html`\n <svg\n class=\"button__spinner\"\n part=\"spinner\"\n aria-hidden=\"true\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n >\n <circle\n class=\"button__spinner-track\"\n cx=\"12\"\n cy=\"12\"\n r=\"10\"\n stroke=\"currentColor\"\n stroke-width=\"3\"\n opacity=\"0.3\"\n />\n <path\n class=\"button__spinner-arc\"\n d=\"M12 2a10 10 0 0 1 10 10\"\n stroke=\"currentColor\"\n stroke-width=\"3\"\n stroke-linecap=\"round\"\n />\n </svg>\n `;\n }\n\n // ─── Render ───\n\n override render() {\n const normalizedLabel = this._normalizedLabel();\n if (!normalizedLabel) {\n devWarn(\n 'hx-icon-button',\n 'The `label` property is required for accessibility. Render suppressed.',\n );\n return nothing;\n }\n\n // mixinDelegatesAria forwarding: consumer-set aria-* (aria-pressed,\n // aria-expanded, aria-haspopup, aria-controls, aria-describedby) lands\n // in data-aria-* on the host. Project them onto the inner element so the\n // a11y tree sees them on the role-bearing native element.\n const projectedDescribedBy = this.getAttribute('data-aria-describedby');\n const projectedPressed = this.getAttribute('data-aria-pressed');\n const projectedExpanded = this.getAttribute('data-aria-expanded');\n const projectedHasPopup = this.getAttribute('data-aria-haspopup');\n const projectedControls = this.getAttribute('data-aria-controls');\n const projectedCurrent = this.getAttribute('data-aria-current');\n\n if (this.href !== undefined) {\n // P1-03 fix: disabled anchor must set tabindex=\"-1\" explicitly — an <a>\n // without href is non-focusable by default in most browsers, but this is\n // browser-dependent. Explicit tabindex=\"-1\" guarantees keyboard exclusion\n // across all conforming browsers. Loading anchors are also tab-skipped\n // for consistency with disabled.\n // P1-07 note: aria-disabled IS required on the anchor branch because\n // <a> elements have no native disabled attribute; aria-disabled is the\n // only AT signal available.\n return html`\n <a\n part=\"button\"\n class=${classMap(this._classes())}\n href=${ifDefined(this.disabled || this.loading ? undefined : this.href)}\n aria-label=${normalizedLabel}\n title=${normalizedLabel}\n aria-disabled=${this.disabled ? 'true' : nothing}\n aria-busy=${this.loading ? 'true' : nothing}\n aria-pressed=${ifDefined(projectedPressed ?? undefined)}\n aria-expanded=${ifDefined(projectedExpanded ?? undefined)}\n aria-haspopup=${ifDefined(projectedHasPopup ?? undefined)}\n aria-controls=${ifDefined(projectedControls ?? undefined)}\n aria-describedby=${ifDefined(projectedDescribedBy ?? undefined)}\n aria-current=${ifDefined(projectedCurrent ?? undefined)}\n tabindex=${this.disabled || this.loading ? '-1' : nothing}\n @click=${this._handleClick}\n >\n ${this.loading ? this._renderSpinner() : this._iconSlot()}\n </a>\n `;\n }\n\n // P1-07 fix: aria-disabled is redundant on a natively disabled <button>.\n // The native disabled attribute already exposes aria-disabled=\"true\"\n // implicitly in the accessibility tree. Duplicate explicit aria-disabled\n // creates ambiguity about design intent. Keep only native ?disabled.\n return html`\n <button\n part=\"button\"\n class=${classMap(this._classes())}\n ?disabled=${this.disabled}\n type=${this.type}\n aria-label=${normalizedLabel}\n title=${normalizedLabel}\n aria-busy=${this.loading ? 'true' : nothing}\n aria-pressed=${ifDefined(projectedPressed ?? undefined)}\n aria-expanded=${ifDefined(projectedExpanded ?? undefined)}\n aria-haspopup=${ifDefined(projectedHasPopup ?? undefined)}\n aria-controls=${ifDefined(projectedControls ?? undefined)}\n aria-describedby=${ifDefined(projectedDescribedBy ?? undefined)}\n aria-current=${ifDefined(projectedCurrent ?? undefined)}\n name=${ifDefined(this.name)}\n value=${ifDefined(this.value)}\n @click=${this._handleClick}\n >\n ${this.loading ? this._renderSpinner() : this._iconSlot()}\n </button>\n `;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'hx-icon-button': HelixIconButton;\n }\n interface HTMLElementEventMap {\n 'hx-click': CustomEvent<{ originalEvent: MouseEvent }>;\n }\n}\n"],"names":["helixIconButtonStyles","css","HelixIconButton","mixinDelegatesAria","HelixElement","disabled","e","html","normalizedLabel","nothing","projectedDescribedBy","projectedPressed","projectedExpanded","projectedHasPopup","projectedControls","projectedCurrent","classMap","ifDefined","forcedColorsInteractive","__decorateClass","property","customElement"],"mappings":"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"}
|