From 6db85838b9cf15e3f50f2c28d9ccaececc7716d5 Mon Sep 17 00:00:00 2001 From: Scott Weber Date: Fri, 25 Sep 2020 14:55:34 -0400 Subject: [PATCH] [WNMGDS-529] Error styling on radio button and checkbox options (#810) * Add styles for border color of check and radio * Add error class to fieldset when errorMessage used * Remove commented out line * update disabled border - remove right to left * Update choice test remove right to left * update class for choice error * add class to choice div when errored * PR feedback - update className * update html markup to match React * update error border to not show on checked items * update example * comment out styling of choice error * add error class to choice input to be consistent * more organizing of choice styles * remove divs from plain html examples * Update packages/design-system-docs/src/pages/components/ChoiceList/checkbox-radio.example.html Co-authored-by: Bernard * Update examples to not have error state and checked choices * Reorder CSS classes, add some commments and remove some unnecessary code * Disable error style * PR feedback * Fix last error message inconsistency * Add back checkChild styling Co-authored-by: Bernard Co-authored-by: bernardwang --- .../ChoiceList/ChoiceList.example.jsx | 3 +- .../ChoiceList/checkbox-radio.example.html | 18 +- .../TextField/textfield.example.html | 2 +- .../src/components/ChoiceList/Choice.test.jsx | 1 - .../src/components/ChoiceList/ChoiceList.jsx | 3 + .../src/styles/components/_Choice.scss | 233 +++++++++--------- 6 files changed, 134 insertions(+), 126 deletions(-) diff --git a/packages/design-system-docs/src/pages/components/ChoiceList/ChoiceList.example.jsx b/packages/design-system-docs/src/pages/components/ChoiceList/ChoiceList.example.jsx index a32f572dfe..37221b26ee 100644 --- a/packages/design-system-docs/src/pages/components/ChoiceList/ChoiceList.example.jsx +++ b/packages/design-system-docs/src/pages/components/ChoiceList/ChoiceList.example.jsx @@ -18,7 +18,7 @@ ReactDOM.render( /> - +
@@ -85,19 +90,18 @@ Helpful hint text Example error message Choice 2 Error field Helpful hint text - Error message example + Example error message diff --git a/packages/design-system/src/components/ChoiceList/Choice.test.jsx b/packages/design-system/src/components/ChoiceList/Choice.test.jsx index 7b85b80038..87df260cd1 100644 --- a/packages/design-system/src/components/ChoiceList/Choice.test.jsx +++ b/packages/design-system/src/components/ChoiceList/Choice.test.jsx @@ -113,7 +113,6 @@ describe('Choice', () => { const input = wrapper.find('input'); expect(input.hasClass('ds-c-choice')).toBe(true); - expect(input.hasClass('ds-c-choice--right')).toBe(false); }); it('applies small className to input', () => { diff --git a/packages/design-system/src/components/ChoiceList/ChoiceList.jsx b/packages/design-system/src/components/ChoiceList/ChoiceList.jsx index d3eb7d268e..11ff35ea06 100644 --- a/packages/design-system/src/components/ChoiceList/ChoiceList.jsx +++ b/packages/design-system/src/components/ChoiceList/ChoiceList.jsx @@ -37,6 +37,9 @@ export class ChoiceList extends React.PureComponent { choiceProps.onChange = this.props.onChange; choiceProps.size = this.props.size; choiceProps.type = this.props.type; + choiceProps.inputClassName = classNames(choiceProps.inputClassName, { + 'ds-c-choice--error': this.props.errorMessage, + }); choiceProps.disabled = choiceProps.disabled || this.props.disabled; // Individual choices can be disabled as well as the entire field choiceProps.inputRef = (ref) => { this.choiceRefs.push(ref); diff --git a/packages/design-system/src/styles/components/_Choice.scss b/packages/design-system/src/styles/components/_Choice.scss index 42a1f2d6d3..93a4de0961 100644 --- a/packages/design-system/src/styles/components/_Choice.scss +++ b/packages/design-system/src/styles/components/_Choice.scss @@ -2,111 +2,63 @@ $ds-c-inset-border-width: $spacer-half; -// Hide the default browser checkbox/radio button since we'll -// create our own custom version +// Order of the choice styles is important to ensure styles have the correct precedent +// normal < errored < checked < disabled < focused .ds-c-choice { + // Hide the default browser checkbox/radio button + // We create our own custom version using '+ label::before' left: -999em; opacity: 0; position: absolute; - // Checked children container - &__checkedChild { - border-left: $ds-c-inset-border-width solid $color-primary; - margin-bottom: $spacer-2; - margin-left: ($choice-size / 2) - ($ds-c-inset-border-width / 2); - padding: $spacer-2; - - // Checked children container on dark background - &--inverse { - border-left-color: $color-white; - } - - // Small input variant - &--small { - margin-left: $spacer-1; - } + // Choice label + + label { + align-items: center; + cursor: pointer; + display: flex; + flex-wrap: wrap; + font-weight: $font-normal; + margin: $spacer-1 0; + max-width: $measure-base; + min-height: $choice-size; + padding-left: $choice-size + $spacer-1; + position: relative; } -} - -.ds-c-choice + label { - align-items: center; - cursor: pointer; - display: flex; - flex-wrap: wrap; - font-weight: $font-normal; - margin: $spacer-1 0; - max-width: $measure-base; - min-height: $choice-size; - padding-left: $choice-size + $spacer-1; - position: relative; -} -// Create a custom checkbox/radio button -.ds-c-choice + label::before { - background-color: $color-background; - border: $choice-border-width solid $choice-border-color; - box-sizing: border-box; - content: '\a0'; - height: $choice-size; - left: 0; - line-height: $choice-size; - position: absolute; - text-indent: 0.15em; - top: 0; - width: $choice-size; -} - -.ds-c-choice--inverse + label::before { - background-color: transparent; - border-color: $choice-border-color-inverse; -} - -// Display an outline -.ds-c-choice:focus + label::before { - @if $ds-include-focus-styles { - border-color: $color-base; - border-width: 3px; - box-shadow: 0 0 0 3px $focus-color; - // Transparent outline for Windows High Contrast Mode - outline: 3px solid transparent; - outline-offset: 3px; - } @else { - box-shadow: 0 0 0 2px $color-background, 0 0 2px 4px $color-focus; + // Choice checkbox/radio button + + label::before { + background-color: $color-background; + border: $choice-border-width solid $choice-border-color; + box-sizing: border-box; + content: '\a0'; + height: $choice-size; + left: 0; + line-height: $choice-size; + position: absolute; + text-indent: 0.15em; + top: 0; + width: $choice-size; } -} -@if $ds-include-focus-styles { - .ds-c-choice--small:focus + label::before { - border-width: 2px; - } - .ds-c-choice:checked:focus + label::before { - border-color: $color-primary-darker; - } -} + // Errored checkbox/radio button + // Currently only enabled in HC.gov DS + // &.ds-c-choice--error + label::before { + // border-color: $color-error; + // } -.ds-c-choice--inverse:focus + label::before { - @if $ds-include-focus-styles { - border-color: $choice-border-color-inverse; - box-shadow: 0 0 0 3px $focus-color-inverse; - } @else { - box-shadow: 0 0 0 2px $color-background-inverse, 0 0 2px 4px $color-focus-inverse; + // Checked checkbox/radio button + &:checked + label::before { + background-color: $choice-checked-background-color; + background-image: url('#{$image-path}/checkmark-white.svg'); + background-position: 50%; + background-repeat: no-repeat; + background-size: $choice-size - $spacer-1; + border-color: $choice-checked-background-color; } -} - -// Display a checkmark -.ds-c-choice:checked + label::before { - background-color: $choice-checked-background-color; - background-image: url('#{$image-path}/checkmark-white.svg'); - background-position: 50%; - background-repeat: no-repeat; - background-size: $choice-size - $spacer-1; - border-color: $choice-checked-background-color; -} -// Fade the checkbox and label -.ds-c-choice:disabled { - + label { + // Disabled checkbox/radio button and label + &:disabled + label { color: $color-muted; &::before { @@ -115,14 +67,57 @@ $ds-c-inset-border-width: $spacer-half; cursor: not-allowed; } } + + // Focused checkbox/radio button + &:focus + label::before { + @if $ds-include-focus-styles { + border-color: $color-base; + border-width: 3px; + box-shadow: 0 0 0 3px $focus-color; + // Transparent outline for Windows High Contrast Mode + outline: 3px solid transparent; + outline-offset: 3px; + } @else { + box-shadow: 0 0 0 2px $color-background, 0 0 2px 4px $color-focus; + } + } } -.ds-c-choice--inverse:disabled { - + label { +.ds-c-choice--inverse { + // Choice checkbox/radio button + + label::before { + background-color: transparent; + border-color: $choice-border-color-inverse; + } + + // Errored checkbox/radio button + // Currently only enabled in HC.gov DS + // &.ds-c-choice--error + label::before { + // border-color: $color-error-light; + // } + + // Checked checkbox/radio button + &:checked + label::before { + border-color: $choice-checked-background-color; + } + + // Disabled checkbox/radio button and label + &:disabled + label { color: $color-muted-inverse; &::before { background-color: rgba($color-muted-inverse, 0.15); + border-color: $color-gray-light; + } + } + + // Focused checkbox/radio button + &:focus + label::before { + @if $ds-include-focus-styles { + border-color: $choice-border-color-inverse; + box-shadow: 0 0 0 3px $focus-color-inverse; + } @else { + box-shadow: 0 0 0 2px $color-background-inverse, 0 0 2px 4px $color-focus-inverse; } } } @@ -132,24 +127,7 @@ $ds-c-inset-border-width: $spacer-half; border-radius: 100%; } -/* -Right-to-Left -*/ - -.ds-c-choice--right + label { - padding-left: 0; - padding-right: $choice-size + $spacer-1; - - &::before { - left: auto; - right: 0; - } -} - -/* -Size variants -*/ - +// Size variants .ds-c-choice--small { + label { min-height: $choice-size-small; @@ -166,9 +144,34 @@ Size variants &:checked + label::before { background-size: $choice-size-small; } +} + +@if $ds-include-focus-styles { + .ds-c-choice--small:focus + label::before { + border-width: 2px; + } + .ds-c-choice:checked:focus + label::before { + border-color: $color-primary-darker; + } +} + +// TODO: rename to .ds-c-choice__checked-child +/* stylelint-disable selector-class-pattern */ + +// Checked children container +.ds-c-choice__checkedChild { + border-left: $ds-c-inset-border-width solid $color-primary; + margin-bottom: $spacer-2; + margin-left: ($choice-size / 2) - ($ds-c-inset-border-width / 2); + padding: $spacer-2; + + &--inverse { + border-left-color: $color-white; + } - &.ds-c-choice--right + label { - padding-left: 0; - padding-right: $choice-size-small + $spacer-1; + &--small { + margin-left: $spacer-1; } } + +/* stylelint-enable selector-class-pattern */