diff --git a/.changeset/four-lemons-warn.md b/.changeset/four-lemons-warn.md new file mode 100644 index 00000000000..fc03f8dbc89 --- /dev/null +++ b/.changeset/four-lemons-warn.md @@ -0,0 +1,28 @@ +--- +"@spectrum-css/combobox": major +--- + +### Combobox S2 Migration + +#### New Changes + +- Removed quiet styling variant +- Updated corner radius to match S2 specifications +- Changed outline thickness for better visibility +- Replaced picker button with in-field button component +- Added help text along with invalid state + +### New tokens + +`--spectrum-combobox-font-weight` +`--spectrum-combobox-line-height-cjk` +`--spectrum-combobox-spacing-alert-icon-to-text` +`--spectrum-combobox-spacing-to-help-text` + +### New mods + +`--mod-combobox-line-height-cjk` +`--mod-combobox-popover-animation-distance` +`--mod-combobox-spacing-alert-icon-to-text` +`--mod-combobox-spacing-to-help-text` +`--mod-combobox-textfield-background-color` diff --git a/components/combobox/dist/metadata.json b/components/combobox/dist/metadata.json index c0626f6390e..1c37d51221a 100644 --- a/components/combobox/dist/metadata.json +++ b/components/combobox/dist/metadata.json @@ -4,22 +4,17 @@ ".spectrum-Combobox", ".spectrum-Combobox .spectrum-Combobox-button.spectrum-PickerButton--quiet .spectrum-PickerButton-fill", ".spectrum-Combobox .spectrum-Combobox-button.spectrum-PickerButton--quiet .spectrum-PickerButton-icon", - ".spectrum-Combobox .spectrum-Popover.is-open", - ".spectrum-Combobox--quiet", - ".spectrum-Combobox--quiet .spectrum-Combobox-input", - ".spectrum-Combobox--quiet .spectrum-Combobox-textfield.is-invalid .spectrum-Combobox-input", - ".spectrum-Combobox--quiet .spectrum-Combobox-textfield.is-invalid .spectrum-Textfield-validationIcon", - ".spectrum-Combobox--quiet .spectrum-Combobox-textfield.is-loading .spectrum-Combobox-input", - ".spectrum-Combobox--quiet .spectrum-Combobox-textfield.is-readOnly .spectrum-Combobox-input:read-only", - ".spectrum-Combobox--quiet .spectrum-Combobox-textfield.is-readOnly.is-disabled .spectrum-Combobox-input:read-only", - ".spectrum-Combobox--quiet .spectrum-Combobox-textfield.is-readOnly.is-invalid > .spectrum-Combobox-input:read-only", - ".spectrum-Combobox--quiet.spectrum-Combobox--sizeL", - ".spectrum-Combobox--quiet.spectrum-Combobox--sizeM", - ".spectrum-Combobox--quiet.spectrum-Combobox--sizeS", - ".spectrum-Combobox--quiet.spectrum-Combobox--sizeXL", + ".spectrum-Combobox ~ .spectrum-Popover.is-open", + ".spectrum-Combobox--sideLabel .spectrum-Combobox-content", + ".spectrum-Combobox--sideLabel .spectrum-Combobox-helptext", + ".spectrum-Combobox--sideLabel .spectrum-Combobox-label", + ".spectrum-Combobox--sideLabel .spectrum-Combobox-textfield", ".spectrum-Combobox--sizeL", + ".spectrum-Combobox--sizeL ~ .spectrum-Combobox-popover", ".spectrum-Combobox--sizeS", + ".spectrum-Combobox--sizeS ~ .spectrum-Combobox-popover", ".spectrum-Combobox--sizeXL", + ".spectrum-Combobox--sizeXL ~ .spectrum-Combobox-popover", ".spectrum-Combobox-button", ".spectrum-Combobox-button.is-focused:not(:disabled, .is-invalid, .spectrum-PickerButton--quiet)", ".spectrum-Combobox-button.is-focused:not(:disabled, .is-invalid, .spectrum-PickerButton--quiet):hover", @@ -39,15 +34,21 @@ ".spectrum-Combobox-button:not(:disabled, .is-invalid, .spectrum-PickerButton--quiet):focus-visible", ".spectrum-Combobox-button:not(:disabled, .is-invalid, .spectrum-PickerButton--quiet):focus:hover", ".spectrum-Combobox-button:not(:disabled, .is-invalid, .spectrum-PickerButton--quiet):hover", + ".spectrum-Combobox-content", + ".spectrum-Combobox-helptext", + ".spectrum-Combobox-helptext .spectrum-HelpText-text", ".spectrum-Combobox-input", ".spectrum-Combobox-input::placeholder", ".spectrum-Combobox-input:active", ".spectrum-Combobox-input:focus", ".spectrum-Combobox-input:focus:hover", ".spectrum-Combobox-input:hover", + ".spectrum-Combobox-input:lang(ja)", + ".spectrum-Combobox-input:lang(ko)", + ".spectrum-Combobox-input:lang(zh)", + ".spectrum-Combobox-label", ".spectrum-Combobox-progress-circle", ".spectrum-Combobox-progress-circle:dir(rtl)", - ".spectrum-Combobox-textfield", ".spectrum-Combobox-textfield.is-focused .spectrum-Combobox-input", ".spectrum-Combobox-textfield.is-focused .spectrum-Combobox-input:hover", ".spectrum-Combobox-textfield.is-invalid .spectrum-Combobox-input", @@ -61,12 +62,12 @@ ".spectrum-Combobox.is-focused:hover .spectrum-Combobox-button:not(:disabled, .is-invalid, .spectrum-PickerButton--quiet)", ".spectrum-Combobox.is-keyboardFocused .spectrum-Combobox-button.is-invalid:not(:disabled, .spectrum-PickerButton--quiet)", ".spectrum-Combobox.is-keyboardFocused .spectrum-Combobox-button:not(:disabled, .is-invalid, .spectrum-PickerButton--quiet)", - ".spectrum-Combobox.is-readOnly.is-disabled:not(.spectrum-Combobox--quiet) .spectrum-Combobox-input:read-only", - ".spectrum-Combobox.is-readOnly.is-disabled:not(.spectrum-Combobox--quiet) .spectrum-Combobox-input:read-only:hover", - ".spectrum-Combobox.is-readOnly.is-invalid:not(.spectrum-Combobox--quiet) .spectrum-Combobox-input:read-only", - ".spectrum-Combobox.is-readOnly:not(.spectrum-Combobox--quiet) .spectrum-Combobox-input:read-only", - ".spectrum-Combobox.is-readOnly:not(.spectrum-Combobox--quiet) .spectrum-Combobox-input:read-only:hover", - ".spectrum-Combobox.is-readOnly:not(.spectrum-Combobox--quiet) .spectrum-Combobox-textfield.is-keyboardFocused .spectrum-Combobox-input", + ".spectrum-Combobox.is-readOnly .spectrum-Combobox-input:read-only", + ".spectrum-Combobox.is-readOnly .spectrum-Combobox-input:read-only:hover", + ".spectrum-Combobox.is-readOnly .spectrum-Combobox-textfield.is-keyboardFocused .spectrum-Combobox-input", + ".spectrum-Combobox.is-readOnly.is-disabled .spectrum-Combobox-input:read-only", + ".spectrum-Combobox.is-readOnly.is-disabled .spectrum-Combobox-input:read-only:hover", + ".spectrum-Combobox.is-readOnly.is-invalid .spectrum-Combobox-input:read-only", ".spectrum-Combobox:has(:active) .spectrum-Combobox-button.is-invalid:not(:disabled, .spectrum-PickerButton--quiet)", ".spectrum-Combobox:has(:active) .spectrum-Combobox-button:not(:disabled, .is-invalid, .spectrum-PickerButton--quiet)", ".spectrum-Combobox:has(:focus) .spectrum-Combobox-button.is-invalid:not(:disabled, .spectrum-PickerButton--quiet)", @@ -123,25 +124,24 @@ "--mod-combobox-icon-size", "--mod-combobox-inline-size", "--mod-combobox-line-height", + "--mod-combobox-line-height-cjk", "--mod-combobox-min-inline-size", + "--mod-combobox-popover-animation-distance", "--mod-combobox-readonly-border-color-disabled", - "--mod-combobox-readonly-input-border-color", + "--mod-combobox-spacing-alert-icon-to-text", "--mod-combobox-spacing-block-end-edge-to-text", "--mod-combobox-spacing-block-start-edge-to-text", - "--mod-combobox-spacing-edge-to-menu", "--mod-combobox-spacing-inline-end-edge-to-text", "--mod-combobox-spacing-inline-icon-to-button", "--mod-combobox-spacing-inline-start-edge-to-text", - "--mod-combobox-spacing-label-to-combobox" + "--mod-combobox-spacing-label-to-combobox", + "--mod-combobox-spacing-to-help-text", + "--mod-combobox-textfield-background-color" ], "component": [ "--spectrum-combo-box-minimum-width-multiplier", - "--spectrum-combo-box-quiet-minimum-width-multiplier", - "--spectrum-combo-box-visual-to-field-button-extra-large", - "--spectrum-combo-box-visual-to-field-button-large", - "--spectrum-combo-box-visual-to-field-button-medium", - "--spectrum-combo-box-visual-to-field-button-quiet", - "--spectrum-combo-box-visual-to-field-button-small", + "--spectrum-combo-box-visual-to-field-button", + "--spectrum-combobox-background-color-default", "--spectrum-combobox-background-color-disabled", "--spectrum-combobox-block-size", "--spectrum-combobox-block-spacing-edge-to-alert", @@ -159,16 +159,17 @@ "--spectrum-combobox-border-color-key-focus", "--spectrum-combobox-border-radius", "--spectrum-combobox-border-width", - "--spectrum-combobox-button-inline-offset", "--spectrum-combobox-button-width", "--spectrum-combobox-focus-indicator-color", "--spectrum-combobox-focus-indicator-gap", "--spectrum-combobox-focus-indicator-thickness", "--spectrum-combobox-font-size", "--spectrum-combobox-font-style", + "--spectrum-combobox-font-weight", "--spectrum-combobox-icon-size", "--spectrum-combobox-inline-size", "--spectrum-combobox-line-height", + "--spectrum-combobox-line-height-cjk", "--spectrum-combobox-min-inline-size", "--spectrum-combobox-readonly-background-color-disabled", "--spectrum-combobox-readonly-border-color-disabled", @@ -176,16 +177,18 @@ "--spectrum-combobox-readonly-input-background-color", "--spectrum-combobox-readonly-input-border-color", "--spectrum-combobox-readonly-text-color-disabled", + "--spectrum-combobox-spacing-alert-icon-to-text", "--spectrum-combobox-spacing-block-end-edge-to-text", "--spectrum-combobox-spacing-block-start-edge-to-text", - "--spectrum-combobox-spacing-edge-to-menu", "--spectrum-combobox-spacing-inline-end-edge-to-text", "--spectrum-combobox-spacing-inline-icon-to-button", "--spectrum-combobox-spacing-inline-start-edge-to-text", - "--spectrum-combobox-spacing-label-to-combobox" + "--spectrum-combobox-spacing-label-to-combobox", + "--spectrum-combobox-spacing-to-help-text" ], "global": [ - "--spectrum-border-width-100", + "--spectrum-border-width-200", + "--spectrum-cjk-line-height-100", "--spectrum-component-bottom-to-text-100", "--spectrum-component-bottom-to-text-200", "--spectrum-component-bottom-to-text-300", @@ -206,26 +209,27 @@ "--spectrum-component-top-to-text-200", "--spectrum-component-top-to-text-300", "--spectrum-component-top-to-text-75", - "--spectrum-corner-radius-100", + "--spectrum-component-top-to-workflow-icon-100", + "--spectrum-component-top-to-workflow-icon-200", + "--spectrum-component-top-to-workflow-icon-300", + "--spectrum-component-top-to-workflow-icon-75", + "--spectrum-corner-radius-medium-size-extra-large", + "--spectrum-corner-radius-medium-size-large", + "--spectrum-corner-radius-medium-size-medium", + "--spectrum-corner-radius-medium-size-small", "--spectrum-default-font-style", "--spectrum-disabled-background-color", "--spectrum-disabled-border-color", "--spectrum-disabled-content-color", - "--spectrum-field-edge-to-text-quiet", "--spectrum-field-label-to-component", - "--spectrum-field-label-to-component-quiet-extra-large", - "--spectrum-field-label-to-component-quiet-large", - "--spectrum-field-label-to-component-quiet-medium", - "--spectrum-field-label-to-component-quiet-small", - "--spectrum-field-top-to-alert-icon-extra-large", - "--spectrum-field-top-to-alert-icon-large", - "--spectrum-field-top-to-alert-icon-medium", - "--spectrum-field-top-to-alert-icon-small", "--spectrum-field-top-to-progress-circle-extra-large", "--spectrum-field-top-to-progress-circle-large", "--spectrum-field-top-to-progress-circle-medium", "--spectrum-field-top-to-progress-circle-small", - "--spectrum-field-width", + "--spectrum-field-width-extra-large", + "--spectrum-field-width-large", + "--spectrum-field-width-medium", + "--spectrum-field-width-small", "--spectrum-focus-indicator-color", "--spectrum-focus-indicator-gap", "--spectrum-focus-indicator-thickness", @@ -234,17 +238,22 @@ "--spectrum-font-size-300", "--spectrum-font-size-75", "--spectrum-gray-25", - "--spectrum-gray-50", - "--spectrum-gray-500", - "--spectrum-gray-600", + "--spectrum-gray-300", + "--spectrum-gray-400", "--spectrum-gray-800", "--spectrum-gray-900", + "--spectrum-help-text-to-component", "--spectrum-line-height-100", "--spectrum-negative-border-color-default", "--spectrum-negative-border-color-focus", "--spectrum-negative-border-color-focus-hover", "--spectrum-negative-border-color-hover", "--spectrum-negative-border-color-key-focus", + "--spectrum-regular-font-weight", + "--spectrum-text-to-visual-100", + "--spectrum-text-to-visual-200", + "--spectrum-text-to-visual-300", + "--spectrum-text-to-visual-75", "--spectrum-workflow-icon-size-100", "--spectrum-workflow-icon-size-200", "--spectrum-workflow-icon-size-300", @@ -253,12 +262,11 @@ "passthroughs": [ "--mod-picker-button-background-color", "--mod-picker-button-background-color-disabled", - "--mod-picker-button-background-color-quiet", "--mod-picker-button-border-color", "--mod-picker-button-border-color-disabled", - "--mod-picker-button-border-color-quiet", "--mod-picker-button-border-width", "--mod-picker-button-font-color-disabled", + "--mod-popover-animation-distance", "--mod-textfield-background-color", "--mod-textfield-background-color-disabled", "--mod-textfield-border-color", @@ -287,8 +295,10 @@ "--mod-textfield-text-color-keyboard-focus" ], "high-contrast": [ + "--highcontrast-combobox-background-color-default", "--highcontrast-combobox-border-color-highlight", "--highcontrast-combobox-border-color-invalid", + "--highcontrast-combobox-readonly-border-color", "--highcontrast-textfield-border-color-invalid-default", "--highcontrast-textfield-text-color-disabled" ] diff --git a/components/combobox/index.css b/components/combobox/index.css index a1e1797971b..7e683ceaeb7 100644 --- a/components/combobox/index.css +++ b/components/combobox/index.css @@ -16,16 +16,19 @@ --spectrum-combobox-icon-size: var(--spectrum-workflow-icon-size-100); --spectrum-combobox-font-size: var(--spectrum-font-size-100); - --spectrum-combobox-spacing-inline-icon-to-button: var(--spectrum-combo-box-visual-to-field-button-medium); + --spectrum-combobox-spacing-inline-icon-to-button: var(--spectrum-combo-box-visual-to-field-button); --spectrum-combobox-block-spacing-edge-to-progress-circle: var(--spectrum-field-top-to-progress-circle-medium); - --spectrum-combobox-block-spacing-edge-to-alert: var(--spectrum-field-top-to-alert-icon-medium); - --spectrum-combobox-spacing-edge-to-menu: var(--spectrum-component-to-menu-medium); + --spectrum-combobox-block-spacing-edge-to-alert: var(--spectrum-component-top-to-workflow-icon-100); --spectrum-combobox-spacing-block-start-edge-to-text: var(--spectrum-component-top-to-text-100); --spectrum-combobox-spacing-block-end-edge-to-text: var(--spectrum-component-bottom-to-text-100); --spectrum-combobox-spacing-inline-start-edge-to-text: var(--spectrum-component-edge-to-text-100); --spectrum-combobox-spacing-inline-end-edge-to-text: var(--spectrum-component-edge-to-text-100); + --spectrum-combobox-spacing-alert-icon-to-text: var(--spectrum-text-to-visual-100); - --spectrum-combobox-inline-size: var(--spectrum-field-width); + /* TODO - need to add this token to library */ + --spectrum-combobox-spacing-to-help-text: var(--spectrum-help-text-to-component); + + --spectrum-combobox-inline-size: var(--spectrum-field-width-medium); --spectrum-combobox-min-inline-size: calc(var(--spectrum-combo-box-minimum-width-multiplier) * var(--spectrum-combobox-block-size)); --spectrum-combobox-button-width: var(--spectrum-combobox-block-size); @@ -33,18 +36,21 @@ --spectrum-combobox-focus-indicator-gap: var(--spectrum-focus-indicator-gap); --spectrum-combobox-focus-indicator-color: var(--spectrum-focus-indicator-color); - --spectrum-combobox-border-radius: var(--spectrum-corner-radius-100); - --spectrum-combobox-border-width: var(--spectrum-border-width-100); + --spectrum-combobox-border-radius: var(--spectrum-corner-radius-medium-size-medium); + --spectrum-combobox-border-width: var(--spectrum-border-width-200); --spectrum-combobox-spacing-label-to-combobox: var(--spectrum-field-label-to-component); --spectrum-combobox-font-style: var(--spectrum-default-font-style); + --spectrum-combobox-font-weight: var(--spectrum-regular-font-weight); --spectrum-combobox-line-height: var(--spectrum-line-height-100); + --spectrum-combobox-line-height-cjk: var(--spectrum-cjk-line-height-100); --spectrum-combobox-background-color-disabled: var(--spectrum-gray-25); - --spectrum-combobox-border-color-default: var(--spectrum-gray-500); - --spectrum-combobox-border-color-hover: var(--spectrum-gray-600); + --spectrum-combobox-background-color-default: var(--spectrum-gray-25); + --spectrum-combobox-border-color-default: var(--spectrum-gray-300); + --spectrum-combobox-border-color-hover: var(--spectrum-gray-400); --spectrum-combobox-border-color-focus: var(--spectrum-gray-800); --spectrum-combobox-border-color-focus-hover: var(--spectrum-gray-900); --spectrum-combobox-border-color-key-focus: var(--spectrum-gray-800); @@ -101,11 +107,12 @@ /* @passthroughs end -- settings for nested Picker Button component */ /*** Read-only Colors ***/ - --spectrum-combobox-readonly-input-background-color: var(--spectrum-gray-50); + --spectrum-combobox-readonly-input-background-color: var(--spectrum-combobox-background-color-default); --spectrum-combobox-readonly-border-color-invalid-default: var(--spectrum-negative-border-color-default); --spectrum-combobox-readonly-background-color-disabled: var(--spectrum-disabled-background-color); --spectrum-combobox-readonly-text-color-disabled: var(--spectrum-disabled-content-color); --spectrum-combobox-readonly-border-color-disabled: var(--spectrum-disabled-border-color); + --spectrum-combobox-readonly-input-border-color: var(--spectrum-combobox-border-color-default); } .spectrum-Combobox--sizeS { @@ -113,14 +120,19 @@ --spectrum-combobox-icon-size: var(--spectrum-workflow-icon-size-75); --spectrum-combobox-font-size: var(--spectrum-font-size-75); - --spectrum-combobox-spacing-inline-icon-to-button: var(--spectrum-combo-box-visual-to-field-button-small); --spectrum-combobox-block-spacing-edge-to-progress-circle: var(--spectrum-field-top-to-progress-circle-small); - --spectrum-combobox-block-spacing-edge-to-alert: var(--spectrum-field-top-to-alert-icon-small); - --spectrum-combobox-spacing-edge-to-menu: var(--spectrum-component-to-menu-small); + --spectrum-combobox-block-spacing-edge-to-alert: var(--spectrum-component-top-to-workflow-icon-75); --spectrum-combobox-spacing-block-start-edge-to-text: var(--spectrum-component-top-to-text-75); --spectrum-combobox-spacing-block-end-edge-to-text: var(--spectrum-component-bottom-to-text-75); --spectrum-combobox-spacing-inline-start-edge-to-text: var(--spectrum-component-edge-to-text-75); --spectrum-combobox-spacing-inline-end-edge-to-text: var(--spectrum-component-edge-to-text-75); + --spectrum-combobox-spacing-alert-icon-to-text: var(--spectrum-text-to-visual-75); + --spectrum-combobox-inline-size: var(--spectrum-field-width-small); + --spectrum-combobox-border-radius: var(--spectrum-corner-radius-medium-size-small); + + ~ .spectrum-Combobox-popover { + --mod-combobox-popover-animation-distance: var(--spectrum-component-to-menu-small); + } } .spectrum-Combobox--sizeL { @@ -128,14 +140,19 @@ --spectrum-combobox-icon-size: var(--spectrum-workflow-icon-size-200); --spectrum-combobox-font-size: var(--spectrum-font-size-200); - --spectrum-combobox-spacing-inline-icon-to-button: var(--spectrum-combo-box-visual-to-field-button-large); --spectrum-combobox-block-spacing-edge-to-progress-circle: var(--spectrum-field-top-to-progress-circle-large); - --spectrum-combobox-block-spacing-edge-to-alert: var(--spectrum-field-top-to-alert-icon-large); - --spectrum-combobox-spacing-edge-to-menu: var(--spectrum-component-to-menu-large); + --spectrum-combobox-block-spacing-edge-to-alert: var(--spectrum-component-top-to-workflow-icon-200); --spectrum-combobox-spacing-block-start-edge-to-text: var(--spectrum-component-top-to-text-200); --spectrum-combobox-spacing-block-end-edge-to-text: var(--spectrum-component-bottom-to-text-200); --spectrum-combobox-spacing-inline-start-edge-to-text: var(--spectrum-component-edge-to-text-200); --spectrum-combobox-spacing-inline-end-edge-to-text: var(--spectrum-component-edge-to-text-200); + --spectrum-combobox-spacing-alert-icon-to-text: var(--spectrum-text-to-visual-200); + --spectrum-combobox-inline-size: var(--spectrum-field-width-large); + --spectrum-combobox-border-radius: var(--spectrum-corner-radius-medium-size-large); + + ~ .spectrum-Combobox-popover { + --mod-combobox-popover-animation-distance: var(--spectrum-component-to-menu-large); + } } .spectrum-Combobox--sizeXL { @@ -143,81 +160,37 @@ --spectrum-combobox-icon-size: var(--spectrum-workflow-icon-size-300); --spectrum-combobox-font-size: var(--spectrum-font-size-300); - --spectrum-combobox-spacing-inline-icon-to-button: var(--spectrum-combo-box-visual-to-field-button-extra-large); --spectrum-combobox-block-spacing-edge-to-progress-circle: var(--spectrum-field-top-to-progress-circle-extra-large); - --spectrum-combobox-block-spacing-edge-to-alert: var(--spectrum-field-top-to-alert-icon-extra-large); - --spectrum-combobox-spacing-edge-to-menu: var(--spectrum-component-to-menu-extra-large); + --spectrum-combobox-block-spacing-edge-to-alert: var(--spectrum-component-top-to-workflow-icon-300); --spectrum-combobox-spacing-block-start-edge-to-text: var(--spectrum-component-top-to-text-300); --spectrum-combobox-spacing-block-end-edge-to-text: var(--spectrum-component-bottom-to-text-300); --spectrum-combobox-spacing-inline-start-edge-to-text: var(--spectrum-component-edge-to-text-300); --spectrum-combobox-spacing-inline-end-edge-to-text: var(--spectrum-component-edge-to-text-300); -} - -.spectrum-Combobox--quiet { - --spectrum-combobox-min-inline-size: calc(var(--spectrum-combo-box-quiet-minimum-width-multiplier) * var(--spectrum-combobox-block-size)); - --spectrum-combobox-spacing-inline-icon-to-button: var(--spectrum-combo-box-visual-to-field-button-quiet); - --spectrum-combobox-spacing-inline-start-edge-to-text: var(--spectrum-field-edge-to-text-quiet); - --spectrum-combobox-spacing-label-to-combobox: var(--spectrum-field-label-to-component-quiet-medium); - --spectrum-combobox-button-inline-offset: calc((var(--mod-combobox-block-size, var(--spectrum-combobox-block-size)) / 2) - (var(--mod-combobox-icon-size, var(--spectrum-combobox-icon-size)) / 2)); - - --mod-textfield-border-color-disabled: var(--mod-combobox-border-color-disabled, initial); + --spectrum-combobox-spacing-alert-icon-to-text: var(--spectrum-text-to-visual-300); + --spectrum-combobox-inline-size: var(--spectrum-field-width-extra-large); + --spectrum-combobox-border-radius: var(--spectrum-corner-radius-medium-size-extra-large); - /* Settings for nested Picker Button component. */ - --mod-picker-button-background-color-quiet: transparent; - --mod-picker-button-border-color-quiet: transparent; - - &.spectrum-Combobox--sizeS { - --spectrum-combobox-spacing-label-to-combobox: var(--spectrum-field-label-to-component-quiet-small); - } - - &.spectrum-Combobox--sizeM { - --spectrum-combobox-spacing-label-to-combobox: var(--spectrum-field-label-to-component-quiet-medium); - } - - &.spectrum-Combobox--sizeL { - --spectrum-combobox-spacing-label-to-combobox: var(--spectrum-field-label-to-component-quiet-large); - } - - &.spectrum-Combobox--sizeXL { - --spectrum-combobox-spacing-label-to-combobox: var(--spectrum-field-label-to-component-quiet-extra-large); - } -} - -@media (forced-colors: active) { - .spectrum-Combobox { - --highcontrast-combobox-border-color-highlight: Highlight; - --highcontrast-combobox-border-color-invalid: Highlight; - - .spectrum-Combobox-button.spectrum-PickerButton--quiet { - .spectrum-PickerButton-fill { - forced-color-adjust: none; - } - - .spectrum-PickerButton-icon { - /* Should match foreground color of the Textfield. */ - color: CanvasText; - } - } + ~ .spectrum-Combobox-popover { + --mod-combobox-popover-animation-distance: var(--spectrum-component-to-menu-extra-large); } } .spectrum-Combobox { position: relative; - display: inline-flex; + display: inline-grid; flex-flow: row nowrap; inline-size: var(--mod-combobox-inline-size, var(--spectrum-combobox-inline-size)); min-inline-size: var(--mod-combobox-min-inline-size, var(--spectrum-combobox-min-inline-size)); - block-size: var(--mod-combobox-block-size, var(--spectrum-combobox-block-size)); margin-block-start: var(--mod-combobox-spacing-label-to-combobox, var(--spectrum-combobox-spacing-label-to-combobox)); border-radius: var(--mod-combobox-border-radius, var(--spectrum-combobox-border-radius)); - .spectrum-Popover.is-open { - transform: translateY(var(--mod-combobox-spacing-edge-to-menu, var(--spectrum-combobox-spacing-edge-to-menu))); + ~ .spectrum-Popover.is-open { + --mod-popover-animation-distance: var(--mod-combobox-popover-animation-distance, var(--spectrum-component-to-menu-medium)); } - &.is-readOnly:not(.spectrum-Combobox--quiet) { + &.is-readOnly { .spectrum-Combobox-textfield { &.is-keyboardFocused .spectrum-Combobox-input { outline-offset: var(--mod-textfield-focus-indicator-gap); @@ -227,8 +200,8 @@ } .spectrum-Combobox-input:read-only { - background-color: var(--spectrum-combobox-readonly-input-background-color); - border-color: var(--spectrum-combobox-readonly-input-border-color); + background-color: var(--highcontrast-combobox-background-color-default, var(--spectrum-combobox-readonly-input-background-color)); + border-color: var(--highcontrast-combobox-readonly-border-color, var(--spectrum-combobox-readonly-input-border-color)); &:hover { background-color: revert; @@ -257,6 +230,7 @@ inset-inline-end: calc(var(--mod-combobox-spacing-inline-icon-to-button, var(--spectrum-combobox-spacing-inline-icon-to-button)) + var(--mod-combobox-button-width, var(--spectrum-combobox-button-width))); inset-block-start: var(--mod-combobox-block-spacing-edge-to-progress-circle, var(--spectrum-combobox-block-spacing-edge-to-progress-circle)); inset-block-end: var(--mod-combobox-block-spacing-edge-to-alert, var(--spectrum-combobox-block-spacing-edge-to-alert)); + padding-inline-start: var(--mod-combobox-spacing-alert-icon-to-text, var(--spectrum-combobox-spacing-alert-icon-to-text)); &:dir(rtl) { inset-inline-end: inherit; @@ -264,10 +238,16 @@ } } +.spectrum-Combobox-label { + display: flex; + align-items: center; + justify-content: space-between; +} + /* PICKER BUTTON */ .spectrum-Combobox-button { position: absolute; - inset-inline-end: calc(-1 * var(--mod-combobox-button-inline-offset, var(--spectrum-combobox-button-inline-offset, 0px))); + inset-inline-end: 0; /* Default */ &:not(:disabled, .is-invalid, .spectrum-PickerButton--quiet) { @@ -334,18 +314,20 @@ } } -/* TEXTFIELD (wrapper) */ -.spectrum-Combobox-textfield { - inline-size: 100%; +.spectrum-Combobox-content { + display: flex; + block-size: var(--mod-combobox-block-size, var(--spectrum-combobox-block-size)); } /* TEXT INPUT */ .spectrum-Combobox-input { + background-color: var(--highcontrast-combobox-background-color-default, var(--mod-combobox-textfield-background-color, var(--spectrum-combobox-background-color-default))); padding-block-start: calc(var(--mod-combobox-spacing-block-start-edge-to-text, var(--spectrum-combobox-spacing-block-start-edge-to-text)) - var(--mod-combobox-border-width, var(--spectrum-combobox-border-width))); padding-block-end: calc(var(--mod-combobox-spacing-block-end-edge-to-text, var(--spectrum-combobox-spacing-block-end-edge-to-text)) - var(--mod-combobox-border-width, var(--spectrum-combobox-border-width))); padding-inline-start: calc(var(--mod-combobox-spacing-inline-start-edge-to-text, var(--spectrum-combobox-spacing-inline-start-edge-to-text)) - var(--mod-combobox-border-width, var(--spectrum-combobox-border-width))); padding-inline-end: calc(var(--mod-combobox-button-width, var(--spectrum-combobox-button-width)) + var(--mod-combobox-spacing-inline-end-edge-to-text, var(--spectrum-combobox-spacing-inline-end-edge-to-text)) - (var(--mod-combobox-border-width, var(--spectrum-combobox-border-width)) * 2)); backface-visibility: hidden; + font-weight: var(--mod-combobox-font-weight, var(--spectrum-combobox-font-weight)); line-height: var(--mod-combobox-line-height, var(--spectrum-combobox-line-height)); font-size: var(--mod-combobox-font-size, var(--spectrum-combobox-font-size)); font-style: var(--mod-combobox-font-style, var(--spectrum-combobox-font-style)); @@ -384,10 +366,46 @@ .spectrum-Combobox-textfield.is-invalid &, .spectrum-Combobox-textfield.is-loading & { padding-inline-end: calc( - var(--mod-combobox-button-width, var(--spectrum-combobox-button-width)) + var(--mod-combobox-spacing-inline-icon-to-button, var(--spectrum-combobox-spacing-inline-icon-to-button)) + var(--mod-combobox-icon-size, var(--spectrum-combobox-icon-size)) + var(--mod-combobox-spacing-inline-end-edge-to-text, var(--spectrum-combobox-spacing-inline-end-edge-to-text)) - var(--mod-combobox-button-inline-offset, var(--spectrum-combobox-button-inline-offset, 0px)) - - (var(--mod-combobox-border-width, var(--spectrum-combobox-border-width)) * 2) + var(--mod-combobox-button-width, var(--spectrum-combobox-button-width)) + var(--mod-combobox-spacing-inline-icon-to-button, var(--spectrum-combobox-spacing-inline-icon-to-button)) + var(--mod-combobox-icon-size, var(--spectrum-combobox-icon-size)) + var(--mod-combobox-spacing-inline-end-edge-to-text, var(--spectrum-combobox-spacing-inline-end-edge-to-text)) - var(--mod-combobox-button-inline-offset, 0px) - (var(--mod-combobox-border-width, var(--spectrum-combobox-border-width)) * 2) ); } + + &:lang(ja), + &:lang(zh), + &:lang(ko) { + --mod-combobox-line-height: var(--mod-combobox-line-height-cjk, var(--spectrum-combobox-line-height-cjk)); + } +} + +.spectrum-Combobox-helptext { + inset-block-start: var(--mod-combobox-spacing-to-help-text, var(--spectrum-combobox-spacing-to-help-text)); + + .spectrum-HelpText-text { + inline-size: 100%; + word-wrap: break-word; + text-wrap: wrap; + } +} + +.spectrum-Combobox--sideLabel { + .spectrum-Combobox-textfield { + inline-size: auto; + } + + .spectrum-Combobox-label { + grid-row: 1 / span 2; + grid-column: 1 / span 1; + } + + .spectrum-Combobox-content { + grid-row: 1 / span 1; + grid-column: 2 / span 1; + } + + .spectrum-Combobox-helptext { + grid-row: 2 / span 1; + grid-column: 2 / span 1; + } } /* VALIDATION ICON */ @@ -399,6 +417,7 @@ inset-block-start: var(--mod-combobox-block-spacing-edge-to-alert, var(--spectrum-combobox-block-spacing-edge-to-alert)); inset-block-end: var(--mod-combobox-block-spacing-edge-to-alert, var(--spectrum-combobox-block-spacing-edge-to-alert)); inset-inline-end: calc(var(--mod-combobox-spacing-inline-icon-to-button, var(--spectrum-combobox-spacing-inline-icon-to-button)) + var(--mod-combobox-button-width, var(--spectrum-combobox-button-width))); + padding-inline-start: var(--mod-combobox-spacing-alert-icon-to-text, var(--spectrum-combobox-spacing-alert-icon-to-text)); } .spectrum-Textfield.is-disabled &, @@ -408,43 +427,22 @@ } } -/* QUIET VARIATION (no visible background) */ -.spectrum-Combobox--quiet { - border-radius: 0; - - .spectrum-Combobox-textfield { - &.is-invalid .spectrum-Textfield-validationIcon { - inset-inline-end: var(--mod-combobox-button-width, var(--spectrum-combobox-button-width)); - } - - &.is-readOnly { - .spectrum-Combobox-input:read-only { - border-block-end: var(--mod-combobox-border-width, var(--spectrum-combobox-border-width)) solid var(--mod-combobox-readonly-input-border-color, var(--spectrum-combobox-readonly-input-border-color)); - } +@media (forced-colors: active) { + .spectrum-Combobox { + --highcontrast-combobox-border-color-highlight: Highlight; + --highcontrast-combobox-border-color-invalid: Highlight; + --highcontrast-combobox-background-color-default: Canvas; + --highcontrast-combobox-readonly-border-color: CanvasText; - &.is-invalid > .spectrum-Combobox-input:read-only { - border-color: var(--highcontrast-textfield-border-color-invalid-default, var(--mod-textfield-border-color-invalid-default, var(--spectrum-combobox-readonly-border-color-invalid-default))); + .spectrum-Combobox-button.spectrum-PickerButton--quiet { + .spectrum-PickerButton-fill { + forced-color-adjust: none; } - &.is-disabled .spectrum-Combobox-input:read-only { - color: var(--highcontrast-textfield-text-color-disabled, var(--mod-textfield-text-color-disabled, var(--spectrum-combobox-readonly-text-color-disabled))); - border-color: var(--mod-textfield-border-color-disabled, var(--spectrum-combobox-readonly-border-color-disabled)); + .spectrum-PickerButton-icon { + /* Should match foreground color of the Textfield. */ + color: CanvasText; } } } - - .spectrum-Combobox-input { - border-block-end-width: var(--mod-combobox-border-width, var(--spectrum-combobox-border-width)); - - padding-block-start: var(--mod-combobox-spacing-block-start-edge-to-text, var(--spectrum-combobox-spacing-block-start-edge-to-text)); - padding-block-end: calc(var(--mod-combobox-spacing-block-end-edge-to-text, var(--spectrum-combobox-spacing-block-end-edge-to-text)) - var(--mod-combobox-border-width, var(--spectrum-combobox-border-width))); - - padding-inline-start: var(--mod-combobox-spacing-inline-start-edge-to-text, var(--spectrum-combobox-spacing-inline-start-edge-to-text)); - padding-inline-end: calc(var(--mod-combobox-button-width, var(--spectrum-combobox-button-width)) + var(--mod-combobox-spacing-inline-end-edge-to-text, var(--spectrum-combobox-spacing-inline-end-edge-to-text)) - var(--mod-combobox-button-inline-offset, var(--spectrum-combobox-button-inline-offset, 0px))); - } - - .spectrum-Combobox-textfield.is-invalid .spectrum-Combobox-input, - .spectrum-Combobox-textfield.is-loading .spectrum-Combobox-input { - padding-inline-end: calc(var(--mod-combobox-button-width, var(--spectrum-combobox-button-width)) + var(--mod-combobox-spacing-inline-icon-to-button, var(--spectrum-combobox-spacing-inline-icon-to-button)) + var(--mod-combobox-icon-size, var(--spectrum-combobox-icon-size)) + var(--mod-combobox-spacing-inline-end-edge-to-text, var(--spectrum-combobox-spacing-inline-end-edge-to-text)) - var(--mod-combobox-button-inline-offset, var(--spectrum-combobox-button-inline-offset, 0px))); - } } diff --git a/components/combobox/stories/combobox.stories.js b/components/combobox/stories/combobox.stories.js index df57778d72d..37a0d31b411 100644 --- a/components/combobox/stories/combobox.stories.js +++ b/components/combobox/stories/combobox.stories.js @@ -1,11 +1,12 @@ import { Template as Menu } from "@spectrum-css/menu/stories/template.js"; +import { Sizes, withDownStateDimensionCapture } from "@spectrum-css/preview/decorators"; import { disableDefaultModes } from "@spectrum-css/preview/modes"; -import { isDisabled, isFocused, isInvalid, isKeyboardFocused, isLoading, isOpen, isQuiet, isReadOnly, size } from "@spectrum-css/preview/types"; +import { isDisabled, isFocused, isInvalid, isKeyboardFocused, isLoading, isOpen, isReadOnly, size } from "@spectrum-css/preview/types"; import { within } from "@storybook/test"; import metadata from "../dist/metadata.json"; import packageJson from "../package.json"; import { ComboBoxGroup } from "./combobox.test.js"; -import { Template, VariantGroup } from "./template.js"; +import { HelpTextTemplate, Template, VariantGroup } from "./template.js"; /** * Comboboxes combine a text entry with a picker menu, allowing users to filter longer lists to only the selections matching a query. @@ -14,11 +15,11 @@ import { Template, VariantGroup } from "./template.js"; * * ### General notes * - * - Combobox uses `.spectrum-PickerButton` instead of a `.spectrum-Picker` + * - Combobox uses `.spectrum-InfieldButton` instead of a `.spectrum-PickerButton` * - The following classes must be added: * - `.spectrum-Combobox-textfield` is required on the Textfield outer element (`.spectrum-Textfield`) * - `.spectrum-Combobox-input` is required on the `` element inside of Textfields (`.spectrum-Textfield-input`) - * - `.spectrum-Combobox-button` is required on the FieldButton (`.spectrum-ActionButton spectrum-ActionButton--sizeM`) + * - `.spectrum-Combobox-button` is required on the InfieldButton (`.spectrum-InfieldButton`) * * ### Indicating validity and focus * @@ -27,7 +28,7 @@ import { Template, VariantGroup } from "./template.js"; * - `.is-focused` - when the input or button is focused with the mouse * - `.is-keyboardFocused` - when the input or button is focused with the keyboard * - `.is-valid` - when the input has an explicit valid state - * - `.is-invalid` - when the input has an explicit invalid state + * - `.is-invalid` - when the input has an explicit invalid state; should also show help text for error messaging * - `.is-disabled` - when the control is disabled; should also add to the `.spectrum-Combobox-textfield` and include a `[disabled]` attribute to the `.spectrum-Combobox-button` * - `.is-loading` - when the progress circle is being shown * @@ -45,13 +46,22 @@ export default { ...isOpen, if: { arg: "isReadOnly", truthy: false }, }, - isQuiet, isInvalid, isFocused, isKeyboardFocused, isLoading, isDisabled, isReadOnly, + isLabelRequired: { + name: "Label required", + type: { name: "boolean" }, + table: { + type: { summary: "boolean" }, + category: "Component", + }, + control: "boolean", + if: { arg: "showFieldLabel", truthy: true }, + }, showFieldLabel: { name: "Show field label", type: { name: "boolean" }, @@ -82,6 +92,25 @@ export default { control: "select", if: { arg: "showFieldLabel", truthy: true }, }, + showHelpText: { + name: "Show help text", + type: { name: "boolean" }, + table: { + type: { summary: "boolean" }, + category: "Component", + }, + control: "boolean", + }, + helpText: { + name: "Help text", + type: { name: "text" }, + table: { + type: { summary: "text" }, + category: "Component", + }, + control: "text", + if: { arg: "showHelpText", truthy: true }, + }, value: { name: "Value", description: "The value shows the option that a user has selected.", @@ -98,15 +127,19 @@ export default { rootClass: "spectrum-Combobox", size: "m", isOpen: false, - isQuiet: false, isInvalid: false, isFocused: false, isKeyboardFocused: false, isLoading: false, isDisabled: false, isReadOnly: false, + isLabelRequired: false, showFieldLabel: false, + showHelpText: false, testId: "combobox", + fieldLabelText: "Select location", + helpText: "This is a help text. Select an option", + value: "Ballard", content: [ (passthroughs, context) => Menu({ role: "listbox", @@ -142,9 +175,19 @@ export default { type: "figma", url: "https://www.figma.com/design/Mngz9H7WZLbrCvGQf3GnsY/S2-%2F-Desktop?node-id=727-2550", }, + downState: { + selectors: [".spectrum-InfieldButton:not(:disabled)"], + }, + status: { + type: "migrated", + }, + tags: ["migrated"], packageJson, metadata, }, + decorators: [ + withDownStateDimensionCapture, + ], play: async ({ canvasElement }) => { const canvas = within(canvasElement); @@ -155,11 +198,7 @@ export default { export const Default = ComboBoxGroup.bind({}); Default.tags = ["!autodocs"]; -Default.args = { - isOpen: true, - fieldLabelText: "Select location", - value: "Ballard", -}; +Default.args = {}; Default.parameters = { chromatic: { delay: 1000 } }; @@ -167,7 +206,9 @@ Default.parameters = { // ********* DOCS ONLY ********* // export const DefaultGroup = VariantGroup.bind({}); DefaultGroup.storyName = "Default"; -DefaultGroup.args = Default.args; +DefaultGroup.args = { + isOpen: true, +}; DefaultGroup.tags = ["!dev"]; DefaultGroup.parameters = { chromatic: { disableSnapshot: true }, @@ -178,22 +219,21 @@ DefaultGroup.parameters = { }, }; -export const QuietGroup = VariantGroup.bind({}); -QuietGroup.storyName = "Quiet"; -QuietGroup.args = { - ...Default.args, - isQuiet: true, -}; -QuietGroup.tags = ["!dev"]; -QuietGroup.parameters = { - chromatic: { disableSnapshot: true }, - docs: { - story: { - height: "360px", - }, - }, +/** + * Comboboxes can show help text to provide feedback to users. The description in the help text is flexible and encompasses a range of guidance. Sometimes this guidance is about what to input, and sometime it’s about how to input. This includes information such as: + * + * - An overall description of the input field + * - Hints for what kind of information needs to be input + * - Specific formatting examples or requirements + */ +export const HelpText = HelpTextTemplate.bind({}); +HelpText.tags = ["!dev"]; +HelpText.args = { + showHelpText: true, + helpText: "This is a help text. Select an option", }; + /** * Comboboxes have a read-only option for when content in the disabled state still needs to be shown. This allows for content to be copied, but not interacted with or changed. A combobox does not have a read-only option if no selection has been made. To enable this feature, add the `.isReadOnly` class to the combobox. To enable this feature, add the .isReadOnly class to the combobox. Then within the nested textfield component, add the .isReadOnly class and readonly attribute to the `` element. */ @@ -209,6 +249,17 @@ ReadOnly.parameters = { ReadOnly.storyName = "Read-only"; +export const Sizing = (args, context) => Sizes({ + Template, + withBorder: false, + withHeading: false, + ...args, +}, context); +Sizing.tags = ["!dev"]; +Sizing.parameters = { + chromatic: { disableSnapshot: true }, +}; + // ********* VRT ONLY ********* // export const WithForcedColors = ComboBoxGroup.bind({}); WithForcedColors.tags = ["!autodocs", "!dev"]; diff --git a/components/combobox/stories/combobox.test.js b/components/combobox/stories/combobox.test.js index b74a71a388b..901e2ca6dde 100644 --- a/components/combobox/stories/combobox.test.js +++ b/components/combobox/stories/combobox.test.js @@ -9,11 +9,6 @@ export const ComboBoxGroup = Variants({ testHeading: "Default", isOpen: false, }, - { - testHeading: "Quiet", - isQuiet: true, - isOpen: false, - }, { testHeading: "Open", isOpen: true, @@ -22,18 +17,17 @@ export const ComboBoxGroup = Variants({ }, }, { - testHeading: "Quiet + open", - isQuiet: true, - isOpen: true, - wrapperStyles: { - "min-block-size": "250px", - }, + testHeading: "With field label top", + showFieldLabel: true, + isOpen: false, + fieldLabelPosition: "top", }, { - testHeading: "With field label top", + testHeading: "With field label top + help text", showFieldLabel: true, isOpen: false, fieldLabelPosition: "top", + showHelpText: true, }, { testHeading: "With field label left", @@ -42,14 +36,15 @@ export const ComboBoxGroup = Variants({ fieldLabelPosition: "left", }, { - testHeading: "Truncation", + testHeading: "With field label left + help text ", + showFieldLabel: true, isOpen: false, - value: "United States of America and to the republic", + fieldLabelPosition: "left", + showHelpText: true, }, { - testHeading: "Quiet + truncation", + testHeading: "Truncation", isOpen: false, - isQuiet: true, value: "United States of America and to the republic", }, ], diff --git a/components/combobox/stories/template.js b/components/combobox/stories/template.js index f8cc0dbc1b1..6f2e7532998 100644 --- a/components/combobox/stories/template.js +++ b/components/combobox/stories/template.js @@ -1,5 +1,6 @@ import { Template as FieldLabel } from "@spectrum-css/fieldlabel/stories/template.js"; -import { Template as PickerButton } from "@spectrum-css/pickerbutton/stories/template.js"; +import { Template as HelpText } from "@spectrum-css/helptext/stories/template.js"; +import { Template as InfieldButton } from "@spectrum-css/infieldbutton/stories/template.js"; import { Template as Popover } from "@spectrum-css/popover/stories/template.js"; import { Container, getRandomId } from "@spectrum-css/preview/decorators"; import { Template as TextField } from "@spectrum-css/textfield/stories/template.js"; @@ -20,15 +21,38 @@ const Combobox = ({ size = "m", isOpen = true, isInvalid = false, - isQuiet = false, isDisabled = false, isFocused = false, isKeyboardFocused = false, isLoading = false, isReadOnly = false, + showHelpText = false, + helpText = "This is a help text", + fieldLabelText = "Select location", + fieldLabelPosition = "top", + isLabelRequired = false, + showFieldLabel = false, value = "", } = {}, context = {}) => { const { updateArgs } = context; + const comboboxId = id || getRandomId("combobox"); + + // Handle click outside of the combobox to close it + if (typeof window !== "undefined" && isOpen) { + // Use setTimeout to allow DOM to render first + setTimeout(() => { + const comboboxEl = document.getElementById(comboboxId); + + const handleClickOutside = (event) => { + if (comboboxEl && !comboboxEl.contains(event.target)) { + updateArgs({ isOpen: false }); + document.removeEventListener("mousedown", handleClickOutside); + } + }; + + document.addEventListener("mousedown", handleClickOutside); + }, 0); + } return html`