sober
Version:
Sober is a library of UI components designed with reference to Material You.
115 lines (114 loc) • 3.36 kB
JavaScript
import { useElement, useProps } from './core/element.js';
import './ripple.js';
const name = 's-checkbox';
const props = useProps({
disabled: false,
checked: false,
indeterminate: false
});
const style = /*css*/ `
:host{
display: inline-flex;
align-items: center;
vertical-align: middle;
cursor: pointer;
position: relative;
height: 40px;
color: var(--s-color-on-surface-variant, ${"#40484C" /* Theme.colorOnSurfaceVariant */});
}
:host([checked=true]){
color: var(--s-color-primary, ${"#006782" /* Theme.colorPrimary */});
}
:host([disabled=true]){
pointer-events: none;
}
.container{
position: relative;
height: 100%;
aspect-ratio: 1;
-webkit-aspect-ratio: 1;
border-radius: 50%;
overflow: hidden;
flex-shrink: 0;
}
:host([disabled=true]) .container{
color: var(--s-color-on-surface, ${"#191C1E" /* Theme.colorOnSurface */}) !important;
opacity: .38 !important;
}
.unchecked,
.checked,
.indeterminate{
display: flex;
align-items: center;
justify-content: center;
position: absolute;
inset: 0;
width: 100%;
height: 100%;
}
.checked,
.indeterminate{
position: absolute;
transform: scale(.5);
opacity: 0;
transition-property: transform, opacity;
transition-timing-function: var(--s-motion-easing-emphasized, ${"cubic-bezier(0.2, 0, 0, 1.0)" /* Theme.motionEasingEmphasized */});
transition-duration: var(--s-motion-duration-short4, ${"200ms" /* Theme.motionDurationShort4 */});
}
:host([indeterminate=true]) .unchecked{
opacity: 0;
}
:host([checked=true]:not([indeterminate=true])) .checked,
:host([indeterminate=true]) .indeterminate{
opacity: 1;
transform: scale(1);
}
.ripple{
aspect-ratio: 1;
-webkit-aspect-ratio: 1;
height: 100%;
width: auto;
border-radius: 50%;
}
svg,
::slotted(:is([slot=checked], [slot=unchecked], [slot=indeterminate])){
color: currentColor;
fill: currentColor;
width: 60%;
height: 60%;
}
`;
const template = /*html*/ `
<div class="container" part="container">
<slot class="unchecked" name="unchecked">
<svg viewBox="0 -960 960 960">
<path d="M200-120q-33 0-56.5-23.5T120-200v-560q0-33 23.5-56.5T200-840h560q33 0 56.5 23.5T840-760v560q0 33-23.5 56.5T760-120H200Zm0-80h560v-560H200v560Z"></path>
</svg>
</slot>
<slot class="checked" name="checked">
<svg viewBox="0 -960 960 960">
<path d="m424-312 282-282-56-56-226 226-114-114-56 56 170 170ZM200-120q-33 0-56.5-23.5T120-200v-560q0-33 23.5-56.5T200-840h560q33 0 56.5 23.5T840-760v560q0 33-23.5 56.5T760-120H200Z"></path>
</svg>
</slot>
<slot class="indeterminate" name="indeterminate">
<svg viewBox="0 -960 960 960">
<path d="M280-440h400v-80H280v80Zm-80 320q-33 0-56.5-23.5T120-200v-560q0-33 23.5-56.5T200-840h560q33 0 56.5 23.5T840-760v560q0 33-23.5 56.5T760-120H200Z"></path>
</svg>
</slot>
</div>
<slot></slot>
<s-ripple class="ripple" attached="true" part="ripple"></s-ripple>
`;
export class Checkbox extends useElement({
style, template, props,
setup() {
this.addEventListener('click', () => {
if (this.indeterminate)
this.indeterminate = false;
this.checked = !this.checked;
this.dispatchEvent(new Event('change'));
});
}
}) {
}
Checkbox.define(name);