118 lines
2.9 KiB
JavaScript
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)
|