diff --git a/CHANGELOG.md b/CHANGELOG.md index 94ac116b76..0311a48f01 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -58,6 +58,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - [Hero] New information element below the hero for photographer credits - [StatusLabel] Added SCSS support and scss files are exported too. See documentation about usage. +- [Checkbox] Added SCSS support and scss files are exported too. See documentation about usage. #### Changed diff --git a/packages/core/src/components/all.css b/packages/core/src/components/all.css index ae92620365..e9b404e07f 100644 --- a/packages/core/src/components/all.css +++ b/packages/core/src/components/all.css @@ -1,7 +1,7 @@ @import url('./breadcrumb/breadcrumb.css'); @import url('./button/button.css'); @import url('./card/card.css'); -@import url('./checkbox/checkbox.css'); +@import url('./checkbox/checkbox.scss'); @import url('./container/container.css'); @import url('./error-summary/error-summary.css'); @import url('./fieldset/fieldset.css'); diff --git a/packages/core/src/components/checkbox/_checkbox-mixin.scss b/packages/core/src/components/checkbox/_checkbox-mixin.scss new file mode 100644 index 0000000000..3a91899b32 --- /dev/null +++ b/packages/core/src/components/checkbox/_checkbox-mixin.scss @@ -0,0 +1,332 @@ +@use '../../utils/bem' as BemUtil; + +@mixin base { + --size: 24px; + + // icon size relative to the checkbox size (--size) + --icon-scale: 1; + --border-width: 2px; + --outline-width: 3px; + --label-font-size: var(--fontsize-body-m); + --label-padding: var(--spacing-2-xs); + --background-unselected: transparent; + --background-selected: var(--color-bus); + --background-hover: var(--color-bus-dark); + --background-disabled: var(--color-black-10); + --border-color-selected: var(--color-bus); + --border-color-selected-hover: var(--color-bus-dark); + --border-color-selected-focus: var(--color-bus); + --border-color-unselected: var(--color-black-50); + --border-color-unselected-hover: var(--color-black-90); + --border-color-unselected-focus: var(--color-black-90); + --border-color-disabled: var(--color-black-10); + --icon-color-unselected: transparent; + --icon-color-selected: var(--color-white); + --icon-color-disabled: var(--color-white); + --label-color: var(--color-black-90); + --label-color-disabled: var(--color-black-40); + --icon-size: var(--spacing-m); + + display: flex; + flex-wrap: wrap; + min-height: var(--size); + position: relative; + + &, + & *, + & *:before, + & *:after { + box-sizing: border-box; + } + + /* stylelint-disable no-descending-specificity */ + &:not(:first-of-type) { + margin-top: var(--spacing-2-xs); + } +} + +@mixin input { + -moz-appearance: none; + -webkit-appearance: none; + appearance: none; + cursor: pointer; + + // Normalize.css rules + // Change the font styles in all browsers. + font-family: inherit; // 1 + font-size: 100%; // 1 + height: var(--size); + left: 0; + + // Normalize.css rules + // 1. Change the font styles in all browsers. + // 2. Remove the margin in Firefox and Safari. + line-height: 1.15; // 1 + margin: 0; // 2 + outline: none; + position: absolute; + top: 0; + width: var(--size); + + &:before { + content: ""; + left: 0; + position: absolute; + top: 0; + + // checkbox icon + background-color: var(--icon-color-unselected); + height: var(--size); + mask-image: url("data:image/svg+xml;charset=utf-8,%3Csvg role='img' xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E %3Cg fill='none' fill-rule='evenodd'%3E %3Crect width='24' height='24'/%3E %3Cpolygon fill='currentColor' points='21 7 10 18 4.5 12.5 6 11 10 15 19.5 5.5'/%3E %3C/g%3E %3C/svg%3E"); + mask-position: center; + mask-repeat: no-repeat; + mask-size: calc(var(--size) * var(--icon-scale)); + transform: scale(0.6); + width: var(--size); + z-index: 1; + } +} + +@mixin inputCustom { + // CUSTOM CHECKBOX + + // checkbox icon - selected + &:checked:before { + background-color: var(--icon-color-selected); + transform: scale(1); + } + + // checkbox icon - indeterminated + &:not(:checked):indeterminate:before { + background-color: var(--icon-color-selected); + mask-image: url("data:image/svg+xml;charset=utf-8,%3Csvg role='img' xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cg fill='none' fill-rule='evenodd'%3E%3Cpath d='M0 0h24v24H0z'/%3E%3Cpath fill='currentColor' d='M6 11h12v2H6z'/%3E%3C/g%3E%3C/svg%3E"); + transform: scale(1); + } + + // background - selected or indeterminated + &:checked + label:after, + &:indeterminate + label:after { + background-color: var(--background-selected); + border-color: var(--border-color-selected); + } + + // background + &:disabled + label:after { + background-color: var(--background-disabled); + border-color: var(--border-color-disabled); + } + + // background - unselected - focus + &:not(:disabled):focus + label:after { + border-color: var(--border-color-unselected-focus); + } + + // background - unselected - hover + &:not(:disabled):hover + label:after, + &:not(:disabled):hover:focus + label:after { + border-color: var(--border-color-unselected-hover); + } + + // background - selected - focus + &:not(:disabled):checked:focus + label:after, + &:not(:disabled):indeterminate:focus + label:after { + border-color: var(--border-color-selected-focus); + } + + // background - selected - hover + &:not(:disabled):checked:hover + label:after, + &:not(:disabled):indeterminate:hover + label:after, + &:not(:disabled):checked:hover:focus + label:after, + &:not(:disabled):indeterminate:hover:focus + label:after { + background-color: var(--background-hover); + border-color: var(--border-color-selected-hover); + } +} + +@mixin inputDisabled { + &:disabled + label { + color: var(--label-color-disabled); + } + + &:checked:disabled:before { + background-color: var(--icon-color-disabled); + } + + &:disabled, + &:disabled + label { + cursor: not-allowed; + } +} + +@mixin inputTransitions { + // checkbox transitions + &:hover:before, + &:focus:before, + &:hover + label:after, + &:focus + label:after { + transition: 85ms ease-out; + transition-property: background-color, border-color, transform; + } + + &:focus + label:before { + box-shadow: 0 0 0 var(--outline-width) var(--color-focus-outline); + transform: translate3d(0, 0, 0); + transition: 85ms ease-out; + transition-property: box-shadow, transform; + } +} + + +@mixin label { + color: var(--label-color); + cursor: pointer; + font-size: var(--label-font-size); + line-height: var(--lineheight-m); + padding-left: calc(var(--size) + var(--label-padding)); + padding-top: calc((var(--size) - (var(--label-font-size) * var(--lineheight-m))) / 2); + position: relative; + + &:before, + &:after { + content: ""; + left: 0; + position: absolute; + top: 0; + } + + // focus outline + &:before { + height: var(--size); + width: var(--size); + } + + // background + &:after { + background-color: var(--background-unselected); + border: var(--border-width) solid var(--border-color-unselected); + height: var(--size); + width: var(--size); + } +} + +@mixin noLabel { + & { + padding-left: var(--size); + } +} + +@mixin error-text { + background-color: var(--color-error-light); + border-left: 8px solid var(--color-error); + color: var(--color-black); + display: flex; + flex-basis: 100%; + font-size: var(--fontsize-body-m); + margin-top: var(--spacing-2-xs); + padding: var(--spacing-2-xs); + position: relative; + + &:before { + background: var(--color-error); + content: ''; + display: inline-block; + height: var(--icon-size); + margin-right: var(--spacing-2-xs); + -webkit-mask-image: url("data:image/svg+xml;charset=utf-8,%3Csvg role='img' xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E %3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M11.175 3.45608C11.5239 2.86969 12.3977 2.84875 12.7842 3.39325L12.825 3.45608L21.8771 18.6666C22.2202 19.2432 21.8055 19.951 21.1235 19.9976L21.052 20H2.94799C2.24813 20 1.7987 19.3114 2.09013 18.7267L2.12295 18.6666L11.175 3.45608ZM13 16V18H11V16H13ZM13 8.5V14.5H11V8.5H13Z' fill='currentColor'%3E%3C/path%3E %3C/svg%3E"); + mask-image: url("data:image/svg+xml;charset=utf-8,%3Csvg role='img' xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E %3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M11.175 3.45608C11.5239 2.86969 12.3977 2.84875 12.7842 3.39325L12.825 3.45608L21.8771 18.6666C22.2202 19.2432 21.8055 19.951 21.1235 19.9976L21.052 20H2.94799C2.24813 20 1.7987 19.3114 2.09013 18.7267L2.12295 18.6666L11.175 3.45608ZM13 16V18H11V16H13ZM13 8.5V14.5H11V8.5H13Z' fill='currentColor'%3E%3C/path%3E %3C/svg%3E"); + pointer-events: none; + width: var(--icon-size); + } +} + +@mixin checkbox( + $all: true, + $base: false, + $input: false, + $label: false, + $noLabel: false, + $error-text: false, + $override: null, + $react: false +) { + $className: 'checkbox'; + + @if $override { + $className: $override; + } + + @if $all or $base { + @include BemUtil.block($className, if($override, true, false), $react) { + @include base; + } + } + + @if $all or $input { + @if $react { + @include BemUtil.unscopedElement($className, 'input', true) { + @include input; + @include inputDisabled; + @include inputTransitions; + @include inputCustom; + } + } @else { + @include BemUtil.block($className, if($override, true, false), false) { + & #{&} { + @include BemUtil.element('input') { + @include input; + @include inputDisabled; + @include inputTransitions; + @include inputCustom; + } + } + } + } + } + + @if $all or $label { + @if $react { + @include BemUtil.unscopedElement($className, 'label', true) { + @include label; + } + } @else { + @include BemUtil.block($className, if($override, true, false), false) { + & #{&} { + @include BemUtil.element('label') { + @include label; + } + } + } + } + } + + @if $all or $noLabel { + @if $react { + @include BemUtil.unscopedElement($className, 'label', true) { + @include noLabel; + } + } @else { + @include BemUtil.unscopedElement($className, 'label') { + & #{&}--hidden { + @include noLabel; + } + } + } + } + + @if $all or $error-text { + @if $react { + @include BemUtil.unscopedElement($className, 'error-text', true) { + @include error-text; + } + } @else { + @include BemUtil.block($className, if($override, true, false), false) { + & #{&} { + @include BemUtil.element('error-text') { + @include error-text; + } + } + } + } + } + +} diff --git a/packages/core/src/components/checkbox/checkbox.css b/packages/core/src/components/checkbox/checkbox.css deleted file mode 100644 index 4c7076fe4b..0000000000 --- a/packages/core/src/components/checkbox/checkbox.css +++ /dev/null @@ -1,236 +0,0 @@ -.hds-checkbox { - --size: 24px; - - /* icon size relative to the checkbox size (--size) */ - --icon-scale: 1; - --border-width: 2px; - --outline-width: 3px; - --label-font-size: var(--fontsize-body-m); - --label-padding: var(--spacing-2-xs); - --background-unselected: transparent; - --background-selected: var(--color-bus); - --background-hover: var(--color-bus-dark); - --background-disabled: var(--color-black-10); - --border-color-selected: var(--color-bus); - --border-color-selected-hover: var(--color-bus-dark); - --border-color-selected-focus: var(--color-bus); - --border-color-unselected: var(--color-black-50); - --border-color-unselected-hover: var(--color-black-90); - --border-color-unselected-focus: var(--color-black-90); - --border-color-disabled: var(--color-black-10); - --icon-color-unselected: transparent; - --icon-color-selected: var(--color-white); - --icon-color-disabled: var(--color-white); - --label-color: var(--color-black-90); - --label-color-disabled: var(--color-black-40); - --icon-size: var(--spacing-m); - - display: flex; - flex-wrap: wrap; - min-height: var(--size); - position: relative; -} - -.hds-checkbox, -.hds-checkbox *, -.hds-checkbox *:before, -.hds-checkbox *:after { - box-sizing: border-box; -} - -.hds-checkbox:not(:first-of-type) { - margin-top: var(--spacing-2-xs); -} - -.hds-checkbox .hds-checkbox__input:before, -.hds-checkbox .hds-checkbox__label:before, -.hds-checkbox .hds-checkbox__label:after { - content: ""; - left: 0; - position: absolute; - top: 0; -} - -/* checkbox icon */ -.hds-checkbox .hds-checkbox__input:before { - background-color: var(--icon-color-unselected); - height: var(--size); - mask-image: url("data:image/svg+xml;charset=utf-8,%3Csvg role='img' xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E %3Cg fill='none' fill-rule='evenodd'%3E %3Crect width='24' height='24'/%3E %3Cpolygon fill='currentColor' points='21 7 10 18 4.5 12.5 6 11 10 15 19.5 5.5'/%3E %3C/g%3E %3C/svg%3E"); - mask-position: center; - mask-repeat: no-repeat; - mask-size: calc(var(--size) * var(--icon-scale)); - transform: scale(0.6); - width: var(--size); - z-index: 1; -} - - -/* focus outline */ -.hds-checkbox .hds-checkbox__label:before { - height: var(--size); - width: var(--size); -} - -/* background */ -.hds-checkbox .hds-checkbox__label:after { - background-color: var(--background-unselected); - border: var(--border-width) solid var(--border-color-unselected); - height: var(--size); - width: var(--size); -} - -/* checkbox transitions */ -.hds-checkbox .hds-checkbox__input:hover:before, -.hds-checkbox .hds-checkbox__input:focus:before, -.hds-checkbox .hds-checkbox__input:hover + .hds-checkbox__label:after, -.hds-checkbox .hds-checkbox__input:focus + .hds-checkbox__label:after { - transition: 85ms ease-out; - transition-property: background-color, border-color, transform; -} - -.hds-checkbox .hds-checkbox__input:focus + .hds-checkbox__label:before { - box-shadow: 0 0 0 var(--outline-width) var(--color-focus-outline); - transform: translate3d(0, 0, 0); - transition: 85ms ease-out; - transition-property: box-shadow, transform; -} - -.hds-checkbox .hds-checkbox__input { - -moz-appearance: none; - -webkit-appearance: none; - appearance: none; - cursor: pointer; - - /* - * Normalize.css rules - * 1. Change the font styles in all browsers. - */ - font-family: inherit; /* 1 */ - font-size: 100%; /* 1 */ - height: var(--size); - left: 0; - - /* - * Normalize.css rules - * 1. Change the font styles in all browsers. - * 2. Remove the margin in Firefox and Safari. - */ - line-height: 1.15; /* 1 */ - margin: 0; /* 2 */ - outline: none; - position: absolute; - top: 0; - width: var(--size); -} - -/* LABEL */ - -.hds-checkbox .hds-checkbox__label { - color: var(--label-color); - cursor: pointer; - font-size: var(--label-font-size); - line-height: var(--lineheight-m); - padding-left: calc(var(--size) + var(--label-padding)); - padding-top: calc((var(--size) - (var(--label-font-size) * var(--lineheight-m))) / 2); - position: relative; -} - -.hds-checkbox .hds-checkbox__label--hidden { - padding-left: var(--size); -} - -/* ERROR */ -.hds-checkbox__error-text { - background-color: var(--color-error-light); - border-left: 8px solid var(--color-error); - color: var(--color-black); - display: flex; - flex-basis: 100%; - font-size: var(--fontsize-body-m); - margin-top: var(--spacing-2-xs); - padding: var(--spacing-2-xs); - position: relative; -} - -.hds-checkbox__error-text:before { - background: var(--color-error); - content: ''; - display: inline-block; - height: var(--icon-size); - margin-right: var(--spacing-2-xs); - -webkit-mask-image: url("data:image/svg+xml;charset=utf-8,%3Csvg role='img' xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E %3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M11.175 3.45608C11.5239 2.86969 12.3977 2.84875 12.7842 3.39325L12.825 3.45608L21.8771 18.6666C22.2202 19.2432 21.8055 19.951 21.1235 19.9976L21.052 20H2.94799C2.24813 20 1.7987 19.3114 2.09013 18.7267L2.12295 18.6666L11.175 3.45608ZM13 16V18H11V16H13ZM13 8.5V14.5H11V8.5H13Z' fill='currentColor'%3E%3C/path%3E %3C/svg%3E"); - mask-image: url("data:image/svg+xml;charset=utf-8,%3Csvg role='img' xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E %3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M11.175 3.45608C11.5239 2.86969 12.3977 2.84875 12.7842 3.39325L12.825 3.45608L21.8771 18.6666C22.2202 19.2432 21.8055 19.951 21.1235 19.9976L21.052 20H2.94799C2.24813 20 1.7987 19.3114 2.09013 18.7267L2.12295 18.6666L11.175 3.45608ZM13 16V18H11V16H13ZM13 8.5V14.5H11V8.5H13Z' fill='currentColor'%3E%3C/path%3E %3C/svg%3E"); - pointer-events: none; - width: var(--icon-size); -} - -/* CUSTOM CHECKBOX */ - -/* checkbox icon - selected */ -.hds-checkbox .hds-checkbox__input:checked:before { - background-color: var(--icon-color-selected); - transform: scale(1); -} - -/* checkbox icon - indeterminated */ -.hds-checkbox .hds-checkbox__input:not(:checked):indeterminate:before { - background-color: var(--icon-color-selected); - mask-image: url("data:image/svg+xml;charset=utf-8,%3Csvg role='img' xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cg fill='none' fill-rule='evenodd'%3E%3Cpath d='M0 0h24v24H0z'/%3E%3Cpath fill='currentColor' d='M6 11h12v2H6z'/%3E%3C/g%3E%3C/svg%3E"); - transform: scale(1); -} - -/* background - selected or indeterminated */ -.hds-checkbox .hds-checkbox__input:checked + .hds-checkbox__label:after, -.hds-checkbox .hds-checkbox__input:indeterminate + .hds-checkbox__label:after { - background-color: var(--background-selected); - border-color: var(--border-color-selected); -} - -/* background */ -.hds-checkbox .hds-checkbox__input:disabled + .hds-checkbox__label:after { - background-color: var(--background-disabled); - border-color: var(--border-color-disabled); -} - -/* background - unselected - focus */ -.hds-checkbox .hds-checkbox__input:not(:disabled):focus + .hds-checkbox__label:after { - border-color: var(--border-color-unselected-focus); -} - -/* background - unselected - hover */ -.hds-checkbox .hds-checkbox__input:not(:disabled):hover + .hds-checkbox__label:after, -.hds-checkbox .hds-checkbox__input:not(:disabled):hover:focus + .hds-checkbox__label:after { - border-color: var(--border-color-unselected-hover); -} - -/* background - selected - focus */ -.hds-checkbox .hds-checkbox__input:not(:disabled):checked:focus + .hds-checkbox__label:after, -.hds-checkbox .hds-checkbox__input:not(:disabled):indeterminate:focus + .hds-checkbox__label:after { - border-color: var(--border-color-selected-focus); -} - -/* background - selected - hover */ -.hds-checkbox .hds-checkbox__input:not(:disabled):checked:hover + .hds-checkbox__label:after, -.hds-checkbox .hds-checkbox__input:not(:disabled):indeterminate:hover + .hds-checkbox__label:after, -.hds-checkbox .hds-checkbox__input:not(:disabled):checked:hover:focus + .hds-checkbox__label:after, -.hds-checkbox .hds-checkbox__input:not(:disabled):indeterminate:hover:focus + .hds-checkbox__label:after { - background-color: var(--background-hover); - border-color: var(--border-color-selected-hover); -} - -/* DISABLED */ - -/* label */ -.hds-checkbox .hds-checkbox__input:disabled + .hds-checkbox__label { - color: var(--label-color-disabled); -} - -/* checkbox icon - disabled */ -.hds-checkbox .hds-checkbox__input:checked:disabled:before { - background-color: var(--icon-color-disabled); -} - -.hds-checkbox .hds-checkbox__input:disabled, -.hds-checkbox .hds-checkbox__input:disabled + .hds-checkbox__label { - cursor: not-allowed; -} diff --git a/packages/core/src/components/checkbox/checkbox.scss b/packages/core/src/components/checkbox/checkbox.scss new file mode 100644 index 0000000000..0e9263f044 --- /dev/null +++ b/packages/core/src/components/checkbox/checkbox.scss @@ -0,0 +1,2 @@ +@use './checkbox-mixin' as *; +@include checkbox; diff --git a/packages/core/src/components/checkbox/checkbox.stories.js b/packages/core/src/components/checkbox/checkbox.stories.js index e391c59742..4b48b2b5f0 100644 --- a/packages/core/src/components/checkbox/checkbox.stories.js +++ b/packages/core/src/components/checkbox/checkbox.stories.js @@ -1,5 +1,5 @@ import { useEffect } from "@storybook/client-api"; -import './checkbox.css'; +import './checkbox.scss'; import '../selection-group/selection-group.css'; const errorTextId = 'checkbox-error-text'; diff --git a/packages/core/src/utils/_bem.scss b/packages/core/src/utils/_bem.scss index a7d4189b41..854b91e88c 100644 --- a/packages/core/src/utils/_bem.scss +++ b/packages/core/src/utils/_bem.scss @@ -71,16 +71,20 @@ $elementDelimeter: '__'; // prefix added by HDS // use for creating classes like .hds-<$block> // set $noPrefix to false to create classes like .-<$block> -@mixin block($block, $noPrefix: false) { +@mixin block($block, $noPrefix: false, $react: false) { $className: $block; @if not($noPrefix) { $className: #{$blockPrefix + $block}; } - @at-root { - .#{$className} { - @content; + @if $react { + @content; + } @else { + @at-root { + .#{$className} { + @content; + } } } } @@ -148,19 +152,40 @@ $elementDelimeter: '__'; // end of sass-easy-bem // HDS add-on to create .hds---modifier instead of .hds-.hds---modifier -@mixin unscopedModifier($block, $modifier) { - @at-root { - .#{$blockPrefix + $block}#{$modifierDelimeter}#{$modifier} { - @content; +@mixin unscopedModifier($block, $modifier, $react: false) { + @if $react { + @content; + } @else { + @at-root { + .#{$blockPrefix + $block}#{$modifierDelimeter}#{$modifier} { + @content; + } } } } // HDS add-on to create .hds-__element instead of .hds-.hds-__element -@mixin unscopedElement($block, $element) { - @at-root { - .#{$blockPrefix + $block}#{$elementDelimeter}#{$element} { - @content; +@mixin unscopedElement($block, $element, $react: false) { + @if $react { + @content; + } @else { + @at-root { + .#{$blockPrefix + $block}#{$elementDelimeter}#{$element} { + @content; + } } } } + +// HDS add-on to create .hds---modifier.hds---theme { +@mixin unscopedModifierWithTheme($block, $modifier, $theme, $react: false) { + @if $react { + @content; + } @else { + @at-root { + .#{$blockPrefix + $block}#{$modifierDelimeter}#{$modifier}.#{$blockPrefix + $block}#{$modifierDelimeter}#{$theme} { + @content; + } + } + } +} \ No newline at end of file diff --git a/packages/react/src/components/checkbox/Checkbox.module.css b/packages/react/src/components/checkbox/Checkbox.module.css deleted file mode 100644 index 0476ac160e..0000000000 --- a/packages/react/src/components/checkbox/Checkbox.module.css +++ /dev/null @@ -1,28 +0,0 @@ -.checkbox { - composes: hds-checkbox from 'hds-core/lib/components/checkbox/checkbox.css'; -} - -.input { - composes: hds-checkbox__input from 'hds-core/lib/components/checkbox/checkbox.css'; -} - -.label { - composes: hds-checkbox__label from 'hds-core/lib/components/checkbox/checkbox.css'; -} - -.noLabel { - composes: hds-checkbox__label--hidden from 'hds-core/lib/components/checkbox/checkbox.css'; -} - -.errorText { - composes: hds-checkbox__error-text from 'hds-core/lib/components/checkbox/checkbox.css'; -} - -.helperText { - composes: helper-text from 'hds-core/lib/utils/helpers.css'; -} - -.tooltipButton { - display: inline-block; - margin-left: var(--spacing-2-xs); -} diff --git a/packages/react/src/components/checkbox/Checkbox.module.scss b/packages/react/src/components/checkbox/Checkbox.module.scss new file mode 100644 index 0000000000..7e0e4bf5c2 --- /dev/null +++ b/packages/react/src/components/checkbox/Checkbox.module.scss @@ -0,0 +1,30 @@ +@use 'hds-core/lib/components/checkbox/_checkbox-mixin' as CoreSass; + +.checkbox { + @include CoreSass.checkbox($all: false, $base: true, $react: true); +} + +.input { + @include CoreSass.checkbox($all: false, $input: true, $react: true); +} + +.label { + @include CoreSass.checkbox($all: false, $label: true, $react: true); +} + +.noLabel { + @include CoreSass.checkbox($all: false, $noLabel: true, $react: true); +} + +.errorText { + @include CoreSass.checkbox($all: false, $error-text: true, $react: true); +} + +.helperText { + composes: helper-text from 'hds-core/lib/utils/helpers.css'; +} + +.tooltipButton { + display: inline-block; + margin-left: var(--spacing-2-xs); +} diff --git a/packages/react/src/components/checkbox/Checkbox.tsx b/packages/react/src/components/checkbox/Checkbox.tsx index 7f4f8f14ca..38c9ef4b3f 100644 --- a/packages/react/src/components/checkbox/Checkbox.tsx +++ b/packages/react/src/components/checkbox/Checkbox.tsx @@ -1,7 +1,7 @@ import React, { useEffect, useRef } from 'react'; import '../../styles/base.module.css'; -import styles from './Checkbox.module.css'; +import styles from './Checkbox.module.scss'; import classNames from '../../utils/classNames'; import mergeRefWithInternalRef from '../../utils/mergeRefWithInternalRef'; import { Tooltip } from '../tooltip'; diff --git a/site/src/docs/components/checkbox/scss.mdx b/site/src/docs/components/checkbox/scss.mdx new file mode 100644 index 0000000000..d3429ee0d0 --- /dev/null +++ b/site/src/docs/components/checkbox/scss.mdx @@ -0,0 +1,107 @@ +--- +slug: '/components/checkbox/scss' +title: 'Checkbox - SCSS' +--- + +import { Checkbox } from 'hds-react'; +import TabsLayout from './tabs.mdx'; +import ExternalLink from '../../../components/ExternalLink'; +import AnchorLink from '../../../components/AnchorLink'; + +export default ({ children, pageContext }) => {children}; + +## SCSS + +Styles of the `Checkbox` are exported as SCSS mixins and are reusable anywhere. + +### Mixins + +| Mixin | Description | Arguments | +| ------------------- | ----------------------------------------------------------- | --------------------------------------------------------------------------- | +| `checkbox` | The root mixin to output all or only selected styles. | See Table 2. | +| `base` | Outputs the base styles. | - | +| `input` | Outputs the styles of the input element. | - | +| `inputCustom` | Outputs the styles the custom input element. | - | +| `inputDisabled` | Outputs the styles disabled variation of the input element. | - | +| `inputTransitions` | Outputs the styles of the input element transitions. | - | +| `label` | Outputs the styles of the label element. | - | +| `noLabel` | Outputs the styles of the no label variation. | - | +| `error-text` | Outputs the styles of the error-text element. | - | +| [Table 1:Checkbox SCSS mixins] | + +### Usage with the root mixin + +```scss +@use 'hds-core/components/checkbox/_checkbox-mixin' as CoreSass; + +@include checkbox( + $all: true, + $base: false, + $input: false, + $label: false, + $noLabel: false, + $error-text: false, + $override: null, + $react: false +); +``` + +### Parameters of the checkbox mixin + +| Property | Description | Values | Default value | +| ------------- | -------------------------------------------------------------- | ------------------ | ------------- | +| `all` | Should all styles of all variations be outputted. | `boolean` | `true` | +| `base` | Should the base styles be outputted. | `boolean` | `false` | +| `input` | Should the styles of the input element be outputted. | `boolean` | `false` | +| `label` | Should the styles of the label element be outputted. | `boolean` | `false` | +| `noLabel` | Should the styles of the no label variation be outputted. | `boolean` | `false` | +| `error-text` | Should the styles of the error-text element be outputted. | `boolean` | `false` | +| `override` | Override the default className `checkbox`. | `null` or `string` | `null` | +| `react` | Use this when included in the SCSS class of a React component. | `boolean` | `false` | +| [Table 2: The checkbox mixin parameters] | + +#### The output of the checkbox mixin + +Helsinki Design System uses BEM, and class names follow its methodology. + +Class names are prefixed with `hds-`, followed by the component name (`checkbox`) and the proper BEM naming. + +Note that variations of the `Checkbox` styles are not compound classes of the base class `.hds-checkbox`. But the variations only alter the CSS variables, so they are quite useless without the base class. + +```scss +.hds-checkbox { + //... all base styles +} + +.hds-checkbox__input { + //... styles of the input element +} +``` + +#### Custom output + +Changing the boolean parameters affects which styles are outputted, and the `override` parameter will change how classes are named. + +```scss +@include checkbox($all: true, $override: 'my-class'); + +.my-class { + //... all base styles +} + +.my-class__input { + //... styles of the input element +} +``` + +### Usage with custom classes + +The base and variation mixins can be included in any class. + +```scss +@use 'hds-core/components/checkbox/_checkbox-mixin' as CoreSass; + +.checkbox { + @include CoreSass.checkbox($all: false, $base: true, $react: true); +} +``` diff --git a/site/src/docs/components/checkbox/tabs.mdx b/site/src/docs/components/checkbox/tabs.mdx index 1a018d8eea..a28479e10b 100644 --- a/site/src/docs/components/checkbox/tabs.mdx +++ b/site/src/docs/components/checkbox/tabs.mdx @@ -25,6 +25,7 @@ import StatusLabel from '../../../components/StatusLabel'; Code Accessibility Customisation + SCSS {props.children}