mm.site/src/components/RangeSlider.js

118 lines
2.9 KiB
JavaScript

import { LitElement, css, html, unsafeCSS } from 'lit'
import { live } from 'lit/directives/live.js'
import MainCSS from '../assets/styles/main.scss?inline'
class RangeSlider extends LitElement {
static properties = {
min: { type: Number },
max: { type: Number },
value: { type: Number },
step: { type: Number },
disabled: { type: Boolean },
thumb: { type: Boolean },
sliderEl: { state: true }
}
constructor() {
super()
this.min = 0
this.max = 1
this.value = 0
this.step = 0.01
this.disabled = false
this.thumb = true
this.sliderEl = null
}
firstUpdated() {
this.sliderEl = this.shadowRoot.querySelector('input')
this.sliderEl.style.setProperty('--progress', `${(this.sliderEl.value / this.sliderEl.max) * 100}%`)
}
draw({ target: sliderEl }) {
const progress = (sliderEl.value / sliderEl.max) * 100
sliderEl.style.setProperty('--progress', `${progress}%`)
const event = new CustomEvent('input', {
bubbles: true, composed: true,
detail: { value: sliderEl.value }
})
this.dispatchEvent(event)
}
willUpdate(changedProperties) {
if (changedProperties.has('value') && this.sliderEl) {
const progress = (this.value / this.max) * 100
this.sliderEl.style.setProperty('--progress', `${progress}%`)
}
}
render() {
return html`
<input type="range"
min=${live(this.min || 0)}
.max=${live(this.max || 1)}
.step=${live(this.step || 0.01)}
.value=${live(this.value || 0)}
@input=${this.draw}
></input>
`
}
static styles = [ css`${unsafeCSS(MainCSS)}`, css`
:host {
--thumb-size: 1.5em;
--track-height: 0.5em;
--track-progress: white;
--track-color: grey;
--thumb-color: white;
--progress: 0%;
}
input {
display: block;
appearance: none;
background: none;
cursor: pointer;
width: 100%;
border-radius: 100vmax;
height: var(--track-height);
background: linear-gradient(to right, var(--track-progress), var(--progress), var(--track-color) var(--progress));
}
input::-webkit-slider-thumb {
-webkit-appearance: none;
appearance: none;
height: var(--thumb-size);
aspect-ratio: 1;
background-color: var(--thumb-color);
border-radius: 100vmax;
border: none;
}
input::-webkit-slider-thumb {
-webkit-appearance: none;
appearance: none;
height: var(--thumb-size);
aspect-ratio: 1;
background-color: var(--thumb-color);
border-radius: 100vmax;
border: none;
}
input::-moz-range-thumb {
appearance: none;
height: var(--thumb-size);
aspect-ratio: 1;
background-color: var(--thumb-color);
border-radius: 100vmax;
border: none;
}
` ]
}
customElements.define('mm-range', RangeSlider)