sober
Version:
Sober is a library of UI components designed with reference to Material You.
120 lines (119 loc) • 3.63 kB
JavaScript
import { useElement, useProps } from './core/element.js';
const name = 's-rate';
const props = useProps({
readOnly: false,
$max: 10,
$min: 0,
$value: 5,
$step: 1
});
const style = /*css*/ `
:host{
display: inline-flex;
vertical-align: middle;
overflow: hidden;
position: relative;
font-size: 24px;
width: calc(1em * 5);
height: 1em;
}
.track{
width: 100%;
display: flex;
}
.track svg,
::slotted([slot=track]){
fill: var(--s-color-secondary-container, ${"#CFE6F1" /* Theme.colorSecondaryContainer */});
filter: drop-shadow(1em 0 0 var(--s-color-secondary-container, ${"#CFE6F1" /* Theme.colorSecondaryContainer */})) drop-shadow(2em 0 0 var(--s-color-secondary-container, ${"#CFE6F1" /* Theme.colorSecondaryContainer */})) drop-shadow(3em 0 0 var(--s-color-secondary-container, ${"#CFE6F1" /* Theme.colorSecondaryContainer */}));
}
.indicator{
position: absolute;
left: 0;
top: 0;
height: 100%;
width: 50%;
overflow: hidden;
display: flex;
}
.indicator svg,
::slotted([slot=indicator]){
fill: var(--s-color-primary, ${"#006782" /* Theme.colorPrimary */});
filter: drop-shadow(1em 0 0 var(--s-color-primary, ${"#006782" /* Theme.colorPrimary */})) drop-shadow(2em 0 0 var(--s-color-primary, ${"#006782" /* Theme.colorPrimary */})) drop-shadow(3em 0 0 var(--s-color-primary, ${"#006782" /* Theme.colorPrimary */})) drop-shadow(4em 0 0 var(--s-color-primary, ${"#006782" /* Theme.colorPrimary */}));
}
svg,
::slotted(*){
height: 100%;
aspect-ratio: 1;
-webkit-aspect-ratio: 1;
flex-shrink: 0;
}
input{
position: absolute;
left: 0;
top: 0;
height: 100%;
width: 100%;
cursor: pointer;
opacity: 0;
margin: 0;
}
:host([readonly=true]) input{
display: none;
}
`;
const template = /*html*/ `
<slot name="track" class="track" part="track">
<svg viewBox="0 -960 960 960">
<path d="m354-287 126-76 126 77-33-144 111-96-146-13-58-136-58 135-146 13 111 97-33 143ZM233-120l65-281L80-590l288-25 112-265 112 265 288 25-218 189 65 281-247-149-247 149Zm247-350Z"/>
</svg>
</slot>
<slot name="indicator" class="indicator" part="indicator">
<svg viewBox="0 -960 960 960">
<path d="m233-120 65-281L80-590l288-25 112-265 112 265 288 25-218 189 65 281-247-149-247 149Z"/>
</svg>
</slot>
<input
type="range"
max="${props.max}"
min="${props.min}"
step="${props.step}"
value="${props.value}"
/>
`;
export class Rate extends useElement({
style, template, props,
setup(shadowRoot) {
const indicator = shadowRoot.querySelector('.indicator');
const input = shadowRoot.querySelector('input');
const update = () => {
const value = Number(input.value);
const percentage = ((value - this.min) * 100) / this.max - this.min;
indicator.style.width = `${percentage}%`;
};
input.onchange = () => this.dispatchEvent(new Event('change'));
input.oninput = () => {
this.value = Number(input.value);
this.dispatchEvent(new Event('input'));
};
return {
max: (value) => {
input.max = String(value);
update();
},
min: (value) => {
input.min = String(value);
update();
},
step: (value) => {
input.step = String(value);
update();
},
value: (value) => {
input.value = String(value);
update();
}
};
}
}) {
}
Rate.define(name);