// Mockup https://www.figma.com/design/zsq2ahat30acTnumyy9aqC/00.Small-System?node-id=944-30711&m=dev import { LitElement, css, html, nothing, unsafeCSS } from "lit"; import { customElement, property } from "lit/decorators.js"; import SliderStyle from "@styles/forms/slider.scss?inline"; export type TemsSliderProps = { type: string; value: number; valueMax: number; min: number; max: number; field: Element; rangeFieldMin: Element; rangeFieldMax: Element; }; @customElement("tems-slider") export class TemsSlider extends LitElement { static styles = css` ${unsafeCSS(SliderStyle)} `; @property({ attribute: "type", type: String, reflect: true }) type: TemsSliderProps["type"] = "single"; @property({ attribute: "value", type: Number, reflect: true }) value: TemsSliderProps["value"] = 0; @property({ attribute: "min", type: Number, reflect: true }) min: TemsSliderProps["min"] = 0; @property({ attribute: "max", type: Number, reflect: true }) max: TemsSliderProps["max"] = 100; @property({ attribute: "value-max", type: Number, reflect: true }) valueMax: TemsSliderProps["valueMax"] = 100; @property({ type: Element }) field: TemsSliderProps["field"] = document.createElement("input"); @property({ type: Element }) rangeFieldMin: TemsSliderProps["rangeFieldMin"] = document.createElement("input"); @property({ type: Element }) rangeFieldMax: TemsSliderProps["rangeFieldMax"] = document.createElement("input"); protected _fieldManager() { this.field.setAttribute("type", "range"); this.field.setAttribute("value", String(this.value)); this.field.setAttribute("min", String(this.min)); this.field.setAttribute("max", String(this.max)); } protected _fieldRangeMinManager() { this.rangeFieldMin.setAttribute("type", "range"); this.rangeFieldMin.classList.add("from-slider"); this.rangeFieldMin.setAttribute("min", String(this.min)); this.rangeFieldMin.setAttribute("max", String(this.max)); this.rangeFieldMin.setAttribute("value", String(this.value)); this.rangeFieldMin.value = this.value; } protected _fieldRangeMaxManager() { this.rangeFieldMax.setAttribute("type", "range"); this.rangeFieldMax.classList.add("to-slider"); this.rangeFieldMax.setAttribute("min", String(this.min)); this.rangeFieldMax.setAttribute("max", String(this.max)); this.rangeFieldMax.setAttribute("value", String(this.valueMax)); this.rangeFieldMax.value = this.valueMax; } protected updated() { if (!this.min) this.min = 0; if (this.type === "multiple") { if (typeof this.value !== "number" || this.value < this.min) { this.value = Number(this.min); } if (typeof this.valueMax !== "number" || this.valueMax > this.max) { this.valueMax = Number(this.max); } this._fieldRangeMinManager(); this._fieldRangeMaxManager(); } else { this._fieldManager(); } this._fillSlider(); } protected firstUpdated() { this.field.addEventListener("input", this._updateState.bind(this)); this.rangeFieldMin.addEventListener( "input", this._updatedMinSlider.bind(this) ); this.rangeFieldMin.addEventListener("change", this._fillSlider.bind(this)); this.rangeFieldMax.addEventListener( "input", this._updatedMaxSlider.bind(this) ); this.rangeFieldMax.addEventListener("change", this._fillSlider.bind(this)); } _fillSlider() { const from = this.rangeFieldMin; const to = this.rangeFieldMax; const rangeDistance = to.max - to.min; const fromPosition = from.value - to.min; const toPosition = to.value - to.min; to.style.background = `linear-gradient( to right, var(--color-surface-disabled) 0%, var(--color-surface-disabled) ${(fromPosition / rangeDistance) * 100}%, var(--color-icon-action) ${(fromPosition / rangeDistance) * 100}%, var(--color-icon-action) ${(toPosition / rangeDistance) * 100}%, var(--color-surface-disabled) ${(toPosition / rangeDistance) * 100}%, var(--color-surface-disabled) 100%)`; } _updatedMinSlider(e: Event) { const cb = () => { if (this.value > this.valueMax) { this.valueMax = this.value; } }; this._updateState(e, cb); } _updatedMaxSlider(e: Event) { const cb = () => { if (this.value > this.valueMax) { this.value = this.valueMax; } }; this._updateState(e, cb); } private _timer: number | undefined; _updateState(e: Event, cb = () => {}) { e.preventDefault(); if (this._timer) { clearTimeout(this._timer); } this._timer = window.setTimeout(() => { this.value = Number( this.type === "single" ? this.field.value : this.rangeFieldMin.value ); this.valueMax = Number(this.rangeFieldMax.value); cb(); this.dispatchEvent( new CustomEvent("change", { detail: this.type === "single" ? { value: this.value, } : { min: this.value, max: this.valueMax, }, }) ); this._timer = undefined; }, 5); } render() { if (typeof this.max === "undefined" || Number(this.min) > Number(this.max)) return nothing; return html`