sober
Version:
Sober is a library of UI components designed with reference to Material You.
116 lines (115 loc) • 3.17 kB
JavaScript
import { useElement, useProps } from './core/element.js';
import './ripple.js';
const name = 's-radio-button';
const props = useProps({
disabled: false,
checked: false,
name: '',
$value: ''
});
const style = /*css*/ `
:host{
display: inline-flex;
vertical-align: middle;
align-items: center;
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{
display: flex;
align-items: center;
justify-content: center;
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
}
.checked{
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([checked=true]:not([indeterminate=true])) .checked{
opacity: 1;
transform: scale(1);
}
.dot{
width: 60%;
height: 60%;
transform: scale(0.4);
background: currentColor;
border-radius: 50%;
}
.ripple{
aspect-ratio: 1;
-webkit-aspect-ratio: 1;
height: 100%;
width: auto;
border-radius: 50%;
}
svg,
::slotted(:is([slot=checked], [slot=unchecked])){
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="M480-80q-83 0-156-31.5T197-197q-54-54-85.5-127T80-480q0-83 31.5-156T197-763q54-54 127-85.5T480-880q83 0 156 31.5T763-763q54 54 85.5 127T880-480q0 83-31.5 156T763-197q-54 54-127 85.5T480-80Zm0-80q134 0 227-93t93-227q0-134-93-227t-227-93q-134 0-227 93t-93 227q0 134 93 227t227 93Zm0-320Z"></path>
</svg>
</slot>
<slot class="checked" name="checked">
<div class="dot"></div>
</slot>
</div>
<slot></slot>
<s-ripple class="ripple" attached="true" part="ripple"></s-ripple>
`;
export class RadioButton extends useElement({
style, template, props,
setup() {
this.addEventListener('click', () => {
this.checked = true;
if (this.name) {
document.querySelectorAll(`${this.tagName}[name='${this.name}']`).forEach((item) => {
if (item === this)
return;
item.checked = false;
});
}
this.dispatchEvent(new Event('change'));
});
}
}) {
}
RadioButton.define(name);