sober
Version:
Sober is a library of UI components designed with reference to Material You.
136 lines (135 loc) • 4.67 kB
JavaScript
import { useElement, useProps } from './core/element.js';
import './ripple.js';
const name = 's-switch';
const props = useProps({
disabled: false,
checked: false
});
const style = /*css*/ `
:host{
display: inline-flex;
vertical-align: middle;
align-items: center;
position: relative;
cursor: pointer;
color: var(--s-color-primary, ${"#006782" /* Theme.colorPrimary */});
width: 52px;
aspect-ratio: 1.625;
-webkit-aspect-ratio: 1.625;
border-radius: 16px;
}
:host([disabled=true]){
pointer-events: none;
}
.track{
width: 100%;
height: 100%;
border: solid 2px var(--s-color-outline, ${"#70787D" /* Theme.colorOutline */});
box-sizing: border-box;
border-radius: inherit;
}
:host([disabled=true]) .track{
border-color: color-mix(in srgb, var(--s-color-on-surface, ${"#191C1E" /* Theme.colorOnSurface */}) 12%, transparent) !important;
}
:host([checked=true]) .track{
border-width: 0;
background: currentColor;
}
:host([disabled=true][checked=true]) .track{
background: color-mix(in srgb, var(--s-color-on-surface, ${"#191C1E" /* Theme.colorOnSurface */}) 12%, transparent) !important;
}
.ripple{
height: 125%;
width: auto;
aspect-ratio: 1;
-webkit-aspect-ratio: 1;
border-radius: 50%;
inset: auto;
transition: transform var(--s-motion-duration-short4, ${"200ms" /* Theme.motionDurationShort4 */}) var(--s-motion-easing-emphasized, ${"cubic-bezier(0.2, 0, 0, 1.0)" /* Theme.motionEasingEmphasized */});
display: flex;
justify-content: center;
align-items: center;
box-sizing: border-box;
color: var(--s-color-outline, ${"#70787D" /* Theme.colorOutline */});
transform: translateX(-10%);
}
:host([checked=true]) .ripple{
transform: translateX(40%);
color: currentColor;
}
.thumb{
background: var(--s-color-outline, ${"#70787D" /* Theme.colorOutline */});
border-radius: 50%;
width: 40%;
height: 40%;
transition: transform var(--s-motion-duration-short4, ${"200ms" /* Theme.motionDurationShort4 */}) var(--s-motion-easing-emphasized, ${"cubic-bezier(0.2, 0, 0, 1.0)" /* Theme.motionEasingEmphasized */});
position: relative;
}
:host([disabled=true]) .thumb{
background: color-mix(in srgb, var(--s-color-on-surface, ${"#191C1E" /* Theme.colorOnSurface */}) 38%, transparent);
}
:host([checked=true]) .thumb{
background: var(--s-color-on-primary, ${"#ffffff" /* Theme.colorOnPrimary */});
transform: scale(1.5);
box-shadow: var(--s-elevation-level1, ${"0 3px 1px -2px rgba(0, 0, 0, .2), 0 2px 2px 0 rgba(0, 0, 0, .14), 0 1px 5px 0 rgba(0, 0, 0, .12)" /* Theme.elevationLevel1 */});
}
:host([disabled=true][checked=true]) .thumb{
background: var(--s-color-surface, ${"#F8F9FB" /* Theme.colorSurface */});
box-shadow: none;
}
.icon{
display: flex;
height: 100%;
justify-content: center;
align-items: center;
opacity: 0;
transition: opacity var(--s-motion-duration-short4, ${"200ms" /* Theme.motionDurationShort4 */}) var(--s-motion-easing-emphasized, ${"cubic-bezier(0.2, 0, 0, 1.0)" /* Theme.motionEasingEmphasized */});
color: currentColor;
}
::slotted([slot=icon]),
svg{
color: currentColor;
fill: currentColor;
width: 70%;
height: 70%;
}
:host([checked=true]) .icon{
opacity: 1;
}
:host([checked=true][disabled=true]) .icon{
color: color-mix(in srgb, var(--s-color-on-surface, ${"#191C1E" /* Theme.colorOnSurface */}) 12%, transparent);
}
not (color: color-mix(in srgb, black, white)){
:host([disabled=true]) .track{
border-color: var(--s-color-surface-container-highest, ${"#E1E3E4" /* Theme.colorSurfaceContainerHighest */}) !important;
}
:host([disabled=true][checked=true]) .track{
background: var(--s-color-surface-container-highest, ${"#E1E3E4" /* Theme.colorSurfaceContainerHighest */}) !important;
}
:host([disabled=true]) .thumb{
background: var(--s-color-surface-container-highest, ${"#E1E3E4" /* Theme.colorSurfaceContainerHighest */}) !important;
}
:host([disabled=true][checked=true]) .thumb{
background: var(--s-color-surface, ${"#F8F9FB" /* Theme.colorSurface */}) !important;
}
}
`;
const template = /*html*/ `
<div class="track" part="track"></div>
<s-ripple attached="true" class="ripple" part="ripple">
<div class="thumb" part="thumb">
<slot name="icon" class="icon"></slot>
</div>
</s-ripple>
`;
export class Switch extends useElement({
style, template, props,
setup() {
this.addEventListener('click', () => {
this.checked = !this.checked;
this.dispatchEvent(new Event('change'));
});
}
}) {
}
Switch.define(name);