diff --git a/packages/web/src/scss/components/TextField/README.md b/packages/web/src/scss/components/TextField/README.md index 1a289d6dfa..d1372bb88b 100644 --- a/packages/web/src/scss/components/TextField/README.md +++ b/packages/web/src/scss/components/TextField/README.md @@ -93,7 +93,7 @@ The `size` attribute is supported on inputs of the following types: `email`, This option is generally recommended for inputs with a limited value length (e.g. numeric representation of day, month, year). Supported values are `2`, `3` and `4` (characters). If you need any other value or prefer using `em` unit -instead of default `ch`, define a `--width` CSS custom property on the `` +instead of default `ch`, define a `--text-field-input-width` CSS custom property on the `` element: ```html @@ -110,7 +110,7 @@ element: class="TextField__input" name="sizeEm" placeholder="Placeholder" - style="--width: 4em;" + style="--text-field-input-width: 4em;" /> ``` diff --git a/packages/web/src/scss/components/TextField/_TextField.scss b/packages/web/src/scss/components/TextField/_TextField.scss index f598c6cf11..8c2c3e6f19 100644 --- a/packages/web/src/scss/components/TextField/_TextField.scss +++ b/packages/web/src/scss/components/TextField/_TextField.scss @@ -1,3 +1,20 @@ +// 1. We pass the input arrows width if the input type is number. +// 2. If the input has a size attribute, we calculate the width based on the input width, padding, border width and arrows width. +// 3. We generate the input width based on the number of characters. +// 4. We position the password toggle button next to the input and use pseudo-element for border styling. +// We do this because password managers place their icon buttons inside the password input. +// 5. Because the button is next to the input, we need to use pseudo element to style the border around both of them. +// 6. We need to set the same background color for the button when the input is hovered, active or focused. +// 7. We toggle icons of the password toggle and we disable the no-descending-specificity to make the code more readable. +// 8. To make the 5. work, we need to style the input and the button when the input is focused. +// 9. The password toggle button should have its own focus-visible style. +// 10. Disabled input and its optional password toggle should have the same disabled style. +// The code is more comprehensible when styling elements in this order: +// 1. input (with a pseudo-element), +// 2. password toggle button, +// 3. validation text. +// Also, high-specificity selectors are necessary to achieve the desired result. + @use '../../settings/cursors'; @use '../../theme/form-fields' as form-fields-theme; @use '../../tools/form-fields' as form-fields-tools; @@ -35,20 +52,23 @@ $_field-name: 'TextField'; appearance: none; } + // 1. &[type='number'] { - --arrows-width: #{theme.$input-number-arrows-width}; + --text-field-arrows-width: #{theme.$input-number-arrows-width}; } + // 2. &[size] { width: calc( - var(--width) + 2 * #{form-fields-theme.$box-field-input-padding-x} + 2 * #{form-fields-theme.$box-field-input-border-width} + - var(--arrows-width, 0px) + var(--text-field-input-width) + 2 * #{form-fields-theme.$box-field-input-padding-x} + 2 * #{form-fields-theme.$box-field-input-border-width} + + var(--text-field-arrows-width, 0px) ); } + // 3. @each $size in theme.$input-size-characters { &[size='#{$size}'] { - --width: #{$size}ch; + --text-field-input-width: #{$size}ch; } } } @@ -70,8 +90,7 @@ $_field-name: 'TextField'; border-bottom-right-radius: 0; } -// We position the button next to the input and use pseudo-element for border styling. -// We do this because password managers place their icon buttons inside the password input. +// 4. .TextField__passwordToggle__button { @include reset.button(); @@ -81,19 +100,30 @@ $_field-name: 'TextField'; padding: theme.$input-password-toggle-padding; color: form-fields-theme.$box-field-input-color-default; border-radius: 0 form-fields-theme.$box-field-input-border-radius form-fields-theme.$box-field-input-border-radius 0; - background-color: form-fields-theme.$box-field-input-background; + background-color: form-fields-theme.$input-background-color; + // 5. &::before { content: ''; position: absolute; inset: 0; border: form-fields-theme.$box-field-input-border-width form-fields-theme.$box-field-input-border-style - form-fields-theme.$box-field-input-border-color-default; + form-fields-theme.$input-border-color; border-radius: form-fields-theme.$box-field-input-border-radius; pointer-events: none; } } +// 6. +.TextField__input:hover + .TextField__passwordToggle__button { + background-color: form-fields-theme.$input-background-color-hover; +} + +.TextField__input:active + .TextField__passwordToggle__button, +.TextField__input:focus-within + .TextField__passwordToggle__button { + background-color: form-fields-theme.$input-background-color-active; +} + .TextField__passwordToggle__icon { pointer-events: none; } @@ -103,13 +133,13 @@ $_field-name: 'TextField'; display: block; } -// stylelint-disable-next-line no-descending-specificity -- In this case ↕️, the code is more readable this way. +// stylelint-disable-next-line no-descending-specificity -- 7. .TextField__passwordToggle__icon--shown, .TextField__passwordToggle__button[aria-pressed='true'] > .TextField__passwordToggle__icon--hidden { display: none; } -// stylelint-disable selector-max-specificity, selector-max-class, selector-max-compound-selectors -- We need high-specificity selectors here. +// stylelint-disable selector-max-specificity, selector-max-class, selector-max-compound-selectors -- 8. .TextField > .TextField__input:focus-visible, .TextField > .TextField__passwordToggle > .TextField__input:focus-visible ~ .TextField__passwordToggle__button::before { @include form-fields-tools.box-field-focus-visible(); @@ -121,6 +151,7 @@ $_field-name: 'TextField'; outline: 0; } +// 9. .TextField__passwordToggle__button:focus-visible::after { content: ''; position: absolute; @@ -153,36 +184,36 @@ $_field-name: 'TextField'; @include form-fields-tools.box-field-disabled-input(); } -// stylelint-disable no-descending-specificity, selector-max-specificity, selector-max-class, selector-max-compound-selectors -// -- The code is more comprehensible when styling elements in this order: -// 1. input (with a pseudo-element), -// 2. password toggle button, -// 3. validation text. -// Also, high-specificity selectors are necessary to achieve the desired result. +// stylelint-disable no-descending-specificity, selector-max-specificity, selector-max-class, selector-max-compound-selectors -- 10. +.TextField > .TextField__passwordToggle > .TextField__input:disabled, +:is(.TextField--disabled, .TextField.is-disabled) > .TextField__passwordToggle > .TextField__input { + border-color: transparent; +} + .TextField > .TextField__input:disabled, :is(.TextField--disabled, .TextField.is-disabled) > .TextField__input, .TextField .TextField__passwordToggle .TextField__input:disabled ~ .TextField__passwordToggle__button::before, :is(.TextField--disabled, .TextField.is-disabled) .TextField__passwordToggle .TextField__passwordToggle__button::before { - border-color: theme.$input-border-color-disabled; + border-color: form-fields-theme.$input-border-color-disabled; } .TextField .TextField__input:disabled ~ .TextField__passwordToggle__button, :is(.TextField--disabled, .TextField.is-disabled) .TextField__passwordToggle__button { @include form-fields-tools.input-disabled(); - background-color: form-fields-theme.$box-field-input-background-disabled; + background-color: form-fields-theme.$input-background-color-disabled; pointer-events: none; cursor: cursors.$disabled; } // stylelint-enable +:is(.TextField--disabled, .TextField.is-disabled) > :is(.TextField__helperText) { + @include form-fields-tools.helper-text-disabled(); +} + :is(.TextField--disabled, .TextField.is-disabled) > :is(.TextField__validationText, [data-spirit-element='validation_text']) { @include form-fields-tools.validation-text-disabled(); } - -:is(.TextField--disabled, .TextField.is-disabled) > :is(.TextField__helperText) { - @include form-fields-tools.helper-text-disabled(); -} diff --git a/packages/web/src/scss/components/TextField/_theme.scss b/packages/web/src/scss/components/TextField/_theme.scss index cf733cfc77..1686280c7e 100644 --- a/packages/web/src/scss/components/TextField/_theme.scss +++ b/packages/web/src/scss/components/TextField/_theme.scss @@ -1,7 +1,7 @@ -@use '@tokens' as tokens; +@use '@global' as global-tokens; +@use '../../settings/globals'; -$input-border-color-disabled: tokens.$border-primary-disabled; $input-number-arrows-width: 1.25rem; -$input-password-toggle-padding: tokens.$space-400; -$input-password-toggle-icon-size: tokens.$space-700; +$input-password-toggle-padding: global-tokens.$space-500; +$input-password-toggle-icon-size: global-tokens.$space-900; $input-size-characters: (2, 3, 4); diff --git a/packages/web/src/scss/components/TextField/index.html b/packages/web/src/scss/components/TextField/index.html index afb3709864..625730672d 100644 --- a/packages/web/src/scss/components/TextField/index.html +++ b/packages/web/src/scss/components/TextField/index.html @@ -284,6 +284,7 @@

Password Toggle

aria-pressed="false" aria-label="Show password" data-spirit-toggle="password" + disabled >