From fd0a868dfd8273275deb8bf556484067fa640980 Mon Sep 17 00:00:00 2001 From: Stoyan Paskalev Date: Thu, 11 Aug 2022 09:37:14 +0300 Subject: [PATCH] feat(radiobutton): add radio button styles --- packages/fluent/scss/index.scss | 4 +- packages/fluent/scss/radio/_layout.scss | 277 +++++++++++++++++++++ packages/fluent/scss/radio/_theme.scss | 114 +++++++++ packages/fluent/scss/radio/_variables.scss | 200 +++++++++++++++ packages/fluent/scss/radio/index.scss | 26 ++ 5 files changed, 619 insertions(+), 2 deletions(-) create mode 100644 packages/fluent/scss/radio/_layout.scss create mode 100644 packages/fluent/scss/radio/_theme.scss create mode 100644 packages/fluent/scss/radio/_variables.scss create mode 100644 packages/fluent/scss/radio/index.scss diff --git a/packages/fluent/scss/index.scss b/packages/fluent/scss/index.scss index 9d540bd5d98..58c7912ca27 100644 --- a/packages/fluent/scss/index.scss +++ b/packages/fluent/scss/index.scss @@ -51,7 +51,7 @@ @use "checkbox"; @use "listbox"; // @use "progressbar"; -// @use "radio"; +@use "radio"; @use "slider"; @@ -213,7 +213,7 @@ @include checkbox.styles(); @include listbox.styles(); // @include progressbar.styles(); - // @include radio.styles(); + @include radio.styles(); @include slider.styles(); diff --git a/packages/fluent/scss/radio/_layout.scss b/packages/fluent/scss/radio/_layout.scss new file mode 100644 index 00000000000..ded1801d397 --- /dev/null +++ b/packages/fluent/scss/radio/_layout.scss @@ -0,0 +1,277 @@ +@use "_variables.scss" as *; +@use "../core/_variables.scss" as *; +@use "../core/mixins/border-radius" as *; +@use "../core/mixins/disabled" as *; + +@mixin kendo-radio--layout() { + + .k-radio { + @include border-radius( $kendo-radio-border-radius ); + width: var( --INTERNAL-kendo-radio-width, #{ $kendo-radio-width } ); + height: var( --INTERNAL-kendo-radio-height, #{ $kendo-radio-height } ); + margin: 0; + padding: 0; + line-height: initial; + border-width: var( --kendo-radio-border-width, #{ $kendo-radio-border-width }); + border-style: solid; + outline: 0; + box-sizing: border-box; + background-position: center; + background-repeat: no-repeat; + background-size: contain; + display: inline-block; + flex: none; + vertical-align: middle; + position: relative; + cursor: pointer; + -webkit-appearance: none; + + &::before { + font-size: var( --INTERNAL-kendo-radio-font-size, #{ $kendo-radio-font-size } ) + } + } + + + // Radio indicator + .k-radio::before { + @if $kendo-radio-indicator-type == "glyph" { + content: var( --kendo-radio-checked-glyph, #{ $kendo-radio-checked-glyph } ); + width: 1em; + height: 1em; + font-family: var( --kendo-radio-glyph-font-family, #{ $kendo-radio-glyph-font-family } ); + line-height: 1; + transform: scale(0) translate(-50%, -50%); + overflow: hidden; + position: absolute; + top: 50%; + left: 50%; + } + } + + // Focus state + .k-radio:focus, + .k-radio.k-focus { + &::before { + content: ''; + display: block; + position: absolute; + margin: -4px; + top: 0; + bottom: 0; + left: 0; + right: 0; + border: 1px solid; + } + } + + + .k-radio:hover, + .k-radio.k-hover { + &:not( + .k-radio.k-disabled, .k-radio:disabled, + .k-radio.k-invalid, .k-radio:invalid + )::after { + content: ""; + width: var( --INTERNAL-kendo-radio-checked-width, #{ $kendo-radio-checked-width } ); + height: var( --INTERNAL-kendo-radio-checked-height, #{ $kendo-radio-checked-height } ); + border-width: var( --INTERNAL-kendo-radio-checked-border-width, #{ $kendo-radio-checked-border-width } ); + border-style: solid; + border-radius: var( --kendo-radio-border-radius, #{ $kendo-radio-border-radius } ); + box-sizing: border-box; + position: absolute; + top: var(--INTERNAL-kendo-radio-checked-top, #{ $kendo-radio-checked-top } ); + left: var(--INTERNAL-kendo-radio-checked-left, #{ $kendo-radio-checked-left } ); + } + } + + // Checked and Hover state + .k-radio:checked, + .k-radio.k-checked { + &::after { + content: ""; + width: var( --INTERNAL-kendo-radio-checked-width, #{ $kendo-radio-checked-width } ); + height: var( --INTERNAL-kendo-radio-checked-height, #{ $kendo-radio-checked-height } ); + border-width: var( --INTERNAL-kendo-radio-checked-border-width, #{ $kendo-radio-checked-border-width } ); + border-style: solid; + border-radius: var( --kendo-radio-border-radius, #{ $kendo-radio-border-radius } ); + box-sizing: border-box; + position: absolute; + top: var(--INTERNAL-kendo-radio-checked-top, #{ $kendo-radio-checked-top } ); + left: var(--INTERNAL-kendo-radio-checked-left, #{ $kendo-radio-checked-left } ); + } + + @if $kendo-radio-indicator-type == "glyph" { + &::before { + transform: scale(1) translate(-50%, -50%); + } + } + } + + + .k-radio:disabled:checked, + .k-radio.k-disabled.k-checked { + @if $kendo-radio-indicator-type == "image" { + background-image: var( --kendo-radio-disabled-checked-image, #{ $kendo-radio-disabled-checked-image } ); + } + } + + + // Radio wrap + .k-radio-wrap { + flex: none; + display: inline-flex; + flex-flow: row nowrap; + gap: 0; + align-items: center; + align-self: start; + vertical-align: middle; + position: relative; + + &::before { + content: "\200b"; + width: 0px; + overflow: hidden; + flex: none; + display: inline-block; + vertical-align: top; + } + } + + + // Radio label + .k-radio-label { + margin: 0; + padding: 0; + display: inline-flex; + align-items: flex-start; + gap: var( --kendo-radio-label-spacing, #{ $kendo-radio-label-spacing } ); + vertical-align: middle; + position: relative; + cursor: pointer; + + .k-ripple { + // Hide ripple temporarily + visibility: hidden !important; // sass-lint:disable-line no-important + } + } + .k-radio + .k-label, + .k-radio-wrap + .k-label, + .k-radio + .k-radio-label, + .k-radio-wrap + .k-radio-label { + display: inline; + margin-inline-start: var( --kendo-radio-label-spacing, #{ $kendo-radio-label-spacing } ); + } + + + // Empty label + .k-radio-label:empty { + display: none !important; // sass-lint:disable-line no-important + } + .k-radio-label.k-no-text { + min-width: 1px; + } + + + // Radio list + .k-radio-list { + margin: 0; + padding: 0; + display: flex; + flex-flow: column nowrap; + gap: 0; + list-style: none; + } + + + .k-radio-item, + .k-radio-list-item { + padding-inline: var( --kendo-radio-list-item-padding-x, #{ $kendo-radio-list-item-padding-x } ); + padding-block: var( --kendo-radio-list-item-padding-y, #{ $kendo-radio-list-item-padding-y } ); + display: flex; + flex-flow: row nowrap; + align-items: center; + align-content: center; + gap: var( --kendo-radio-list-item-gap, #{ $kendo-radio-list-item-gap } ); + + .k-radio-label { + margin: 0; + } + } + + + .k-radio-list-horizontal, + .k-radio-list.k-list-horizontal { + display: flex; + flex-flow: row wrap; + gap: var( --kendo-radio-list-spacing, #{ $kendo-radio-list-spacing } ); + } + + + // Ripple + .k-ripple-container { + .k-radio::after { + content: ""; + width: var( --INTERNAL-kendo-radio-ripple-width, #{ $kendo-radio-ripple-width } ); + height: var( --INTERNAL-kendo-radio-ripple-height, #{ $kendo-radio-ripple-height } ); + display: block; + position: absolute; + left: 50%; + top: 50%; + border-radius: 100%; + z-index: -1; + transition: opacity 100ms linear, transform 150ms cubic-bezier(.4, 0, .2, 1); + transform: translate(-50%, -50%) scale(0); + transform-origin: center center; + } + + .k-radio:disabled::after, + .k-radio.k-disabled::after { + display: none; + } + + .k-radio:disabled::after, + .k-radio.k-disabled::after { + display: none; + } + } + + + // Radio size + @each $size, $size-props in $kendo-radio-sizes { + $_size: map-get( $size-props, size ); + $_glyph-size: map-get( $size-props, glyph-size ); + $_ripple-size: map-get( $size-props, ripple-size ); + $_checked-border-width: map-get( $size-props, checked-border-width); + $_checked-position: map-get( $size-props, checked-position); + + .k-radio-#{$size} { + --INTERNAL-kendo-radio-width: #{ $_size }; + --INTERNAL-kendo-radio-height: #{ $_size }; + + &::before { + --INTERNAL-kendo-radio-font-size: #{ $_glyph-size }; + } + } + + .k-radio-#{$size}.k-checked, + .k-radio-#{$size}:checked, + .k-radio-#{$size}.k-hover, + .k-radio-#{$size}:hover { + &::after { + --INTERNAL-kendo-radio-checked-width: calc( #{ $_size } / 2 ); + --INTERNAL-kendo-radio-checked-height: calc( #{ $_size } / 2 ); + --INTERNAL-kendo-radio-checked-border-width: #{ $_checked-border-width }; + --INTERNAL-kendo-radio-checked-top: #{ $_checked-position }; + --INTERNAL-kendo-radio-checked-left: #{ $_checked-position }; + } + } + + .k-ripple-container { + .k-radio-#{$size}::after { + --INTERNAL-kendo-radio-ripple-width: #{ $_ripple-size }; + --INTERNAL-kendo-radio-ripple-height: #{ $_ripple-size }; + } + } + } + +} diff --git a/packages/fluent/scss/radio/_theme.scss b/packages/fluent/scss/radio/_theme.scss new file mode 100644 index 00000000000..c8e6c8bf004 --- /dev/null +++ b/packages/fluent/scss/radio/_theme.scss @@ -0,0 +1,114 @@ +@use "_variables.scss" as *; +@use "../core/mixins/" as *; + +@mixin kendo-radio--theme() { + + // Radio + .k-radio { + @include fill( + var( --kendo-radio-text, #{ $kendo-radio-text } ), + var( --kendo-radio-bg, #{ $kendo-radio-bg } ), + var( --kendo-radio-border, #{ $kendo-radio-border } ) + ); + } + + + // Hover state + .k-radio:hover, + .k-radio.k-hover { + @include fill( + $border: var( --kendo-radio-hover-border, #{ $kendo-radio-hover-border } ) + ); + + &::after { + @include fill( + $border: var( --kendo-radio-hover-border, #{ $kendo-radio-hover-border } ) + ); + } + } + + + // Checked and Hover state + .k-radio:checked:hover, + .k-radio.k-checked.k-hover { + @include fill( + $border: var( --kendo-radio-checked-hover-border, #{ $kendo-radio-checked-hover-border } ) + ); + + &::after { + @include fill( + $border: var( --kendo-radio-checked-hover-border, #{ $kendo-radio-checked-hover-border } ) + ); + } + } + + + // Focus state + .k-radio:focus, + .k-radio.k-focus { + &::before { + @include fill( $border: var( --kendo-radio-focus-checked-border, #{ $kendo-radio-focus-checked-border }) ); + } + } + + + // Invalid state + .k-radio.k-invalid, + .k-radio.ng-invalid.ng-touched, + .k-radio.ng-invalid.ng-dirty { + @include fill( $border: var( --kendo-radio-invalid-border, #{ $kendo-radio-invalid-border } ) ); + } + .k-radio.k-invalid + .k-radio-label, + .k-radio.ng-invalid.ng-touched + .k-radio-label, + .k-radio.ng-invalid.ng-dirty + .k-radio-label { + @include fill( $color: var( --kendo-radio-invalid-text, #{ $kendo-radio-invalid-text } ) ); + } + + + // Checked + .k-radio:checked, + .k-radio.k-checked { + @include fill( + var( --kendo-radio-checked-text, #{ $kendo-radio-checked-text } ), + var( --kendo-radio-checked-bg, #{ $kendo-radio-checked-bg } ), + var( --kendo-radio-checked-border, #{ $kendo-radio-checked-border } ) + ); + } + + + // Disabled + .k-radio:disabled, + .k-radio.k-disabled { + @include fill( + var( --kendo-radio-disabled-border, #{ $kendo-radio-disabled-border } ) + ); + } + + + // Checked and disabled + .k-radio:checked:disabled, + .k-radio.k-checked.k-disabled { + @include fill( + var( --kendo-radio-disabled-checked-text, #{ $kendo-radio-disabled-checked-text } ), + var( --kendo-radio-disabled-checked-bg, #{ $kendo-radio-disabled-checked-bg } ), + var( --kendo-radio-disabled-checked-border, #{ $kendo-radio-disabled-checked-border } ) + ); + + &::after { + @include fill( + var( --kendo-radio-disabled-checked-text, #{ $kendo-radio-disabled-checked-text } ), + var( --kendo-radio-disabled-checked-bg, #{ $kendo-radio-disabled-checked-bg } ), + var( --kendo-radio-disabled-checked-border, #{ $kendo-radio-disabled-checked-border } ) + ); + } + } + + + // Ripple + .k-ripple-container { + .k-radio::after { + background: var( --kendo-radio-checked-bg, #{ $kendo-radio-checked-bg } ); + opacity: var( --kendo-radio-ripple-opacity, #{ $kendo-radio-ripple-opacity } ); + } + } +} diff --git a/packages/fluent/scss/radio/_variables.scss b/packages/fluent/scss/radio/_variables.scss new file mode 100644 index 00000000000..3ba01369377 --- /dev/null +++ b/packages/fluent/scss/radio/_variables.scss @@ -0,0 +1,200 @@ +@use "../core/color-system" as *; +@use "../core/_variables.scss" as *; +@use "../core/functions/" as *; +@use "../checkbox/_variables.scss" as *; +@use "../list/_variables.scss" as *; + +// Radio button + +/// Border radius of radio button. +/// @group radio +$kendo-radio-border-radius: 50% !default; +/// Border width of radio button. +/// @group radio +$kendo-radio-border-width: 1px !default; + +// Radio button sizes +$kendo-radio-sizes: ( + sm: ( + size: map-get( $kendo-spacing, 4 ), + glyph-size: ( map-get( $kendo-spacing, 4 ) - map-get( $kendo-spacing, thin ) ), + ripple-size: map-get( $kendo-spacing, 4 ) * 3, + checked-border-width: map-get( $kendo-spacing, 1 ), + checked-position: ( map-get( $kendo-spacing, 1 ) - map-get( $kendo-spacing, hair )) + ), + md: ( + size: map-get( $kendo-spacing, 5 ), + glyph-size: ( map-get( $kendo-spacing, 5 ) - map-get( $kendo-spacing, thin ) ), + ripple-size: map-get( $kendo-spacing, 5 ) * 3, + checked-border-width: ( map-get( $kendo-spacing, 1 ) + map-get( $kendo-spacing, hair )), + checked-position: map-get( $kendo-spacing, 1 ) + ), + lg: ( + size: map-get( $kendo-spacing, 6 ), + glyph-size: ( map-get( $kendo-spacing, 6 ) - map-get( $kendo-spacing, thin ) ), + ripple-size: map-get( $kendo-spacing, 6 ) * 3, + checked-border-width: ( map-get( $kendo-spacing, 1) + map-get( $kendo-spacing, thin )), + checked-position: ( map-get( $kendo-spacing, 1) + map-get( $kendo-spacing, hair )) + ) +) !default; + +/// Default width of radio button. +/// @group radio +$kendo-radio-width: map-get( $kendo-spacing, 5 ) !default; +/// Default height of radio button. +/// @group radio +$kendo-radio-height: map-get( $kendo-spacing, 5 ) !default; +/// Default font size of radio button. +/// @group radio +$kendo-radio-font-size: ( map-get( $kendo-spacing, 5 ) - map-get( $kendo-spacing, thin ) ) !default; +/// Default ripple width of radio button. +/// @group radio +$kendo-radio-ripple-width: calc( map-get( $kendo-spacing, 5 ) * 3 ) !default; +/// Default ripple height of radio button. +/// @group radio +$kendo-radio-ripple-height: calc( map-get( $kendo-spacing, 5 ) * 3 ) !default; + +/// Background color of radio button. +/// @group radio +$kendo-radio-bg: $kendo-checkbox-bg !default; +/// Color of radio button. +/// @group radio +$kendo-radio-text: $kendo-checkbox-text !default; +/// Border color of radio button. +/// @group radio +$kendo-radio-border: $kendo-checkbox-border !default; + +/// Background color of hovered radio button. +/// @group radio +$kendo-radio-hover-bg: $kendo-checkbox-hover-bg !default; +/// Color of hovered radio button. +/// @group radio +$kendo-radio-hover-text: $kendo-checkbox-hover-text !default; +/// Border color of hovered radio button. +/// @group radio +$kendo-radio-hover-border: get-theme-color-var( neutral-130 ) !default; + +/// Border of hovered and checked radio. +/// @group checkbox +$kendo-radio-checked-hover-border: get-theme-color-var( primary-150 ) !default; + +/// Top position of checked radio button. +/// @group checked +$kendo-radio-checked-top: map-get( $kendo-spacing, 1 ) !default; +/// Left position of checked radio button. +/// @group checked +$kendo-radio-checked-left: map-get( $kendo-spacing, 1 ) !default; +/// Border width of checked radio button. +/// @group radio +$kendo-radio-checked-border-width: ( map-get( $kendo-spacing, 1) + map-get( $kendo-spacing, hair) ) !default; +/// Width of checked radio button. +/// @group radio +$kendo-radio-checked-width: calc( $kendo-radio-width / 2 ) !default; +/// Height of checked radio button. +/// @group radio +$kendo-radio-checked-height: calc( $kendo-radio-height / 2 ) !default; +/// Background color of checked radio button. +/// @group radio +$kendo-radio-checked-bg: var( --kendo-component-bg, initial ) !default; +/// Color of checked radio button. +/// @group radio +$kendo-radio-checked-text: get-theme-color-var( primary-130 ) !default; +/// Border color of checked radio button. +/// @group radio +$kendo-radio-checked-border: $kendo-checkbox-checked-border !default; + +/// Border color of focused radio button. +/// @group radio +$kendo-radio-focus-border: $kendo-checkbox-focus-border !default; +/// Box shadow of focused radio button. +/// @group radio +$kendo-radio-focus-shadow: $kendo-checkbox-focus-shadow !default; +/// Border color of focused and checked radio button. +/// @group radio +$kendo-radio-focus-checked-border: get-theme-color-var( neutral-130 ) !default; +/// Box shadow of focused and checked radio button. +/// @group radio +$kendo-radio-focus-checked-shadow: $kendo-checkbox-focus-checked-shadow !default; + +/// Background color of disabled radio button. +/// @group radio +$kendo-radio-disabled-bg: $kendo-checkbox-disabled-bg !default; +/// Color of disabled radio button. +/// @group radio +$kendo-radio-disabled-text: $kendo-checkbox-disabled-text !default; +/// Border color of disabled radio button. +/// @group radio +$kendo-radio-disabled-border: get-theme-color( neutral, 60 ) !default; + +/// Background color of disabled and checked radio button. +/// @group radio +$kendo-radio-disabled-checked-bg: $kendo-radio-checked-bg !default; +/// Color of disabled and checked radio button. +/// @group radio +$kendo-radio-disabled-checked-text: $kendo-checkbox-disabled-checked-text !default; +/// Border color of disabled and checked radio button. +/// @group radio +$kendo-radio-disabled-checked-border: $kendo-checkbox-disabled-checked-border !default; + +/// Background color of invalid radio button. +/// @group radio +$kendo-radio-invalid-bg: $kendo-checkbox-invalid-bg !default; +/// Color of invalid radio button. +/// @group radio +$kendo-radio-invalid-text: $kendo-checkbox-invalid-text !default; +/// Border color of invalid radio button. +/// @group radio +$kendo-radio-invalid-border: $kendo-checkbox-invalid-border !default; + + +// Radio indicator + +/// Type of radio button indicator. +/// @group radio +$kendo-radio-indicator-type: image !default; + +/// Glyph font family of radio button indicator. +/// @group radio +$kendo-radio-glyph-font-family: "WebComponentsIcons", monospace !default; +/// Glyph of radio button indicator. +/// @group radio +$kendo-radio-checked-glyph: "\e308" !default; + +/// Image of checked radio button indicator. +/// @group radio +$kendo-radio-checked-image: escape-svg( url("data:image/svg+xml,") ) !default; +/// Image of disabled and checked radio button indicator. +/// @group radio +$kendo-radio-disabled-checked-image: null !default; + + +// Radio label + +/// The horizontal margin of the radio button inside of a label. +/// @group radio +$kendo-radio-label-spacing: map-get( $kendo-spacing, 2 ) !default; + + +// Radio list + +/// The horizontal list item margin of radio button. +/// @group radio +$kendo-radio-list-spacing: map-get( $kendo-spacing, 4 ) !default; +/// The horizontal list item padding of radio button. +/// @group radio +$kendo-radio-list-item-padding-x: 0px !default; +/// The vertical list item padding of radio button. +/// @group radio +$kendo-radio-list-item-padding-y: $kendo-list-item-padding-y-md !default; +/// +/// @group radio +$kendo-radio-list-item-gap: map-get( $kendo-spacing, 2 ) !default; + +// Radio ripple + +/// Background color of radio button ripple. +/// @group radio +$kendo-radio-ripple-bg: $kendo-radio-checked-bg !default; +/// Opacity of radio button ripple. +/// @group radio +$kendo-radio-ripple-opacity: .25 !default; diff --git a/packages/fluent/scss/radio/index.scss b/packages/fluent/scss/radio/index.scss new file mode 100644 index 00000000000..bd652ed0202 --- /dev/null +++ b/packages/fluent/scss/radio/index.scss @@ -0,0 +1,26 @@ +// Module meta +$_kendo-module-meta: ( + name: "radio", + dependencies: ( + 'checkbox', + 'list' + ) +); + + +// Component +@forward "_variables.scss"; +@use "_layout.scss" as *; +@use "_theme.scss" as *; + +// Register +@use "../core/module-system" as module; +@include module.register( $_kendo-module-meta... ); + +// Expose +@mixin styles() { + @include module.render( "radio" ) { + @include kendo-radio--layout(); + @include kendo-radio--theme(); + } +}