mirror of
https://github.com/material-components/material-web.git
synced 2026-03-09 00:09:23 +08:00
307 lines
7.1 KiB
SCSS
307 lines
7.1 KiB
SCSS
//
|
|
// Copyright 2021 Google LLC
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
//
|
|
|
|
// stylelint-disable selector-class-pattern --
|
|
// Selector '.md3-*' should only be used in this project.
|
|
|
|
// PUBLIC PROPERTIES
|
|
|
|
@use 'sass:map';
|
|
@use '../../focus/focus-ring';
|
|
@use '../../motion/animation';
|
|
@use '../../sass/color';
|
|
@use '../../sass/resolvers';
|
|
@use '../../sass/shape';
|
|
@use '../../sass/theme';
|
|
@use '../../sass/touch-target';
|
|
@use '../../sass/var';
|
|
@use '../../tokens';
|
|
|
|
@use './track';
|
|
@use './handle';
|
|
@use './icon';
|
|
|
|
// TODO(b/230768994): update animation timing
|
|
$animation-duration: 75ms;
|
|
$icon-exit-duration: 0.4 * $animation-duration;
|
|
$icon-enter-duration: $animation-duration - $icon-exit-duration;
|
|
|
|
$_touch-target-size: 48px;
|
|
|
|
$_forced-colors-theme: (
|
|
disabled-selected-icon-color: GrayText,
|
|
disabled-selected-icon-opacity: 1,
|
|
disabled-selected-track-color: GrayText,
|
|
disabled-track-opacity: 1,
|
|
disabled-unselected-handle-color: GrayText,
|
|
disabled-unselected-handle-opacity: 1,
|
|
disabled-unselected-icon-color: Canvas,
|
|
disabled-unselected-icon-opacity: 1,
|
|
selected-focus-track-color: ButtonText,
|
|
selected-hover-track-color: ButtonText,
|
|
selected-icon-color: ButtonText,
|
|
selected-pressed-track-color: ButtonText,
|
|
selected-track-color: ButtonText,
|
|
unselected-focus-handle-color: ButtonText,
|
|
unselected-handle-color: ButtonText,
|
|
unselected-hover-handle-color: ButtonText,
|
|
unselected-icon-color: Canvas,
|
|
unselected-pressed-handle-color: ButtonText,
|
|
);
|
|
|
|
@mixin theme($tokens) {
|
|
$tokens: _warn-of-not-implemented($tokens);
|
|
$tokens: theme.validate-theme(tokens.md-comp-switch-values(), $tokens);
|
|
$tokens: _resolve-tokens($tokens);
|
|
$tokens: theme.create-theme-vars($tokens, switch);
|
|
|
|
@include theme.emit-theme-vars($tokens);
|
|
}
|
|
|
|
@mixin styles() {
|
|
$tokens: tokens.md-comp-switch-values();
|
|
$tokens: _resolve-tokens($tokens);
|
|
$tokens: theme.create-theme-vars($tokens, switch);
|
|
|
|
:host {
|
|
@each $token, $value in $tokens {
|
|
--_#{$token}: #{$value};
|
|
}
|
|
|
|
// TODO(b/230630968): create a forced-colors-mode mixin
|
|
@media screen and (forced-colors: active) {
|
|
@include theme($_forced-colors-theme);
|
|
}
|
|
|
|
display: inline-flex;
|
|
outline: none;
|
|
-webkit-tap-highlight-color: transparent;
|
|
}
|
|
|
|
md-focus-ring {
|
|
// TODO(b/231741594): use `track-shape` once this is not deleted.
|
|
@include focus-ring.theme(
|
|
(
|
|
shape: (
|
|
var(--_track-shape-start-start),
|
|
var(--_track-shape-start-end),
|
|
var(--_track-shape-end-start),
|
|
var(--_track-shape-end-end),
|
|
),
|
|
)
|
|
);
|
|
}
|
|
|
|
.md3-switch {
|
|
align-items: center;
|
|
background: none;
|
|
border: none;
|
|
cursor: pointer;
|
|
display: inline-flex;
|
|
flex-shrink: 0; // Stop from collapsing in flex containers
|
|
margin: 0;
|
|
outline: none;
|
|
padding: 0;
|
|
position: relative;
|
|
width: var(--_track-width);
|
|
height: var(--_track-height);
|
|
|
|
// Track shape
|
|
border-start-start-radius: var(--_track-shape-start-start);
|
|
border-start-end-radius: var(--_track-shape-start-end);
|
|
border-end-end-radius: var(--_track-shape-end-end);
|
|
border-end-start-radius: var(--_track-shape-end-start);
|
|
}
|
|
|
|
// Track
|
|
.md3-switch__handle,
|
|
.md3-switch__track {
|
|
&::before {
|
|
content: '';
|
|
display: flex;
|
|
position: absolute;
|
|
height: 100%;
|
|
width: 100%;
|
|
border-radius: inherit;
|
|
box-sizing: border-box;
|
|
|
|
transition-property: opacity;
|
|
transition-duration: #{$animation-duration};
|
|
}
|
|
}
|
|
|
|
.md3-switch__track {
|
|
position: relative;
|
|
width: 100%;
|
|
height: 100%;
|
|
box-sizing: border-box;
|
|
|
|
border-radius: inherit;
|
|
|
|
// Center content
|
|
display: flex;
|
|
justify-content: center;
|
|
align-items: center;
|
|
|
|
&::before {
|
|
border-style: solid;
|
|
|
|
.md3-switch--selected & {
|
|
// When selected, turn off ::before
|
|
opacity: 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Handle container
|
|
.md3-switch__handle-container {
|
|
position: relative;
|
|
transition: animation.standard(margin, $animation-duration);
|
|
}
|
|
|
|
// Handle
|
|
.md3-switch__handle {
|
|
transform-origin: center;
|
|
transition: animation.standard(transform, $animation-duration);
|
|
|
|
&::before {
|
|
.md3-switch--selected & {
|
|
// When selected, turn off ::before
|
|
opacity: 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Ripple
|
|
.md3-switch__ripple {
|
|
position: absolute;
|
|
display: inline-flex;
|
|
left: 50%;
|
|
top: 50%;
|
|
transform: translate(-50%, -50%);
|
|
}
|
|
|
|
// Icons
|
|
.md3-switch__icons {
|
|
position: relative;
|
|
height: 100%;
|
|
width: 100%;
|
|
}
|
|
|
|
.md3-switch__icon {
|
|
position: absolute;
|
|
inset: 0;
|
|
margin: auto;
|
|
|
|
transition-property: fill;
|
|
transition-duration: #{$animation-duration};
|
|
opacity: 0;
|
|
}
|
|
|
|
.md3-switch--selected .md3-switch__icon--on,
|
|
.md3-switch--unselected .md3-switch__icon--off {
|
|
opacity: 1;
|
|
}
|
|
|
|
// Touch target
|
|
.md3-switch__touch {
|
|
@include touch-target.touch-target();
|
|
}
|
|
|
|
// Disabled
|
|
.md3-switch:disabled {
|
|
cursor: default;
|
|
pointer-events: none;
|
|
}
|
|
|
|
// Disabled - Track
|
|
.md3-switch__track {
|
|
.md3-switch:disabled & {
|
|
background-color: transparent;
|
|
border-color: transparent;
|
|
|
|
&::before {
|
|
background-clip: content-box;
|
|
}
|
|
}
|
|
.md3-switch--selected:disabled & {
|
|
background-clip: border-box;
|
|
}
|
|
}
|
|
|
|
.md3-switch__input {
|
|
display: none;
|
|
}
|
|
|
|
@include track.styles();
|
|
@include handle.styles();
|
|
@include icon.styles();
|
|
}
|
|
|
|
@function _resolve-tokens($theme) {
|
|
$theme: shape.resolve-theme(
|
|
$theme,
|
|
map.get(resolvers.$material, shape),
|
|
track-shape,
|
|
handle-shape
|
|
);
|
|
$theme: _flatten-disable-colors($theme);
|
|
@return $theme;
|
|
}
|
|
|
|
@function _flatten-disable-colors($theme) {
|
|
@return color.join-color-and-opacity-pairs(
|
|
$theme,
|
|
(
|
|
// Disabled Handle
|
|
(
|
|
color-key: disabled-selected-handle-color,
|
|
opacity-key: disabled-selected-handle-opacity
|
|
),
|
|
(
|
|
color-key: disabled-unselected-handle-color,
|
|
opacity-key: disabled-unselected-handle-opacity
|
|
),
|
|
// Disabled Track
|
|
(
|
|
color-key: disabled-selected-track-color,
|
|
opacity-key: disabled-track-opacity
|
|
),
|
|
(
|
|
color-key: disabled-unselected-track-color,
|
|
opacity-key: disabled-track-opacity
|
|
),
|
|
(
|
|
color-key: disabled-unselected-track-outline-color,
|
|
opacity-key: disabled-track-opacity
|
|
),
|
|
// Disabled Icon
|
|
(
|
|
color-key: disabled-selected-icon-color,
|
|
opacity-key: disabled-selected-icon-opacity
|
|
),
|
|
(
|
|
color-key: disabled-unselected-icon-color,
|
|
opacity-key: disabled-unselected-icon-opacity
|
|
)
|
|
)
|
|
);
|
|
}
|
|
|
|
@function _warn-of-not-implemented($theme) {
|
|
// TODO(b/230484095): remove this warning once these are implemented.
|
|
@if (
|
|
map.get($theme, selected-handle-height) or
|
|
map.get($theme, selected-handle-width) or
|
|
map.get($theme, unselected-handle-height) or
|
|
map.get($theme, unselected-handle-width) or
|
|
map.get($theme, pressed-handle-height) or
|
|
map.get($theme, pressed-handle-width)
|
|
) {
|
|
@warn '`handle-height` and `handle-width` are not yet implemented. see b/230484095';
|
|
}
|
|
@return $theme;
|
|
}
|