import '../templating.js'; import { attr, css, element, html, listen, query } from '@joist/element'; import { effect } from '@joist/observable'; import { bind } from '@joist/templating'; declare global { interface HTMLElementTagNameMap { 'usa-range-slider': USARangeSliderElement; } } @element({ tagName: 'usa-range-slider', shadowDom: [ css` :host { display: flex; flex-direction: column; max-width: 30rem; } input { height: 2.5rem; -webkit-appearance: none; /* Hides the slider so that custom slider can be made */ width: 100%; /* Specific width is required for Firefox. */ background: transparent; /* Otherwise white in Chrome */ border-radius: 0; color: #1b1b1b; display: block; margin-top: 0.5rem; } input:focus { outline: 0.25rem solid #2491ff; outline-offset: 0; } input::-webkit-slider-thumb { height: 1.25rem; border-radius: 99rem; width: 1.25rem; background: #f0f0f0; border: 0; box-shadow: 0 0 0 2px #757575; cursor: pointer; -webkit-appearance: none; appearance: none; margin-top: -0.19rem; } input::-webkit-slider-runnable-track { background-color: #f0f0f0; border-radius: 99rem; border: 1px solid #757575; cursor: pointer; height: 1rem; width: 100%; } `, html` `, ], }) export class USARangeSliderElement extends HTMLElement { static formAssociated = true; @attr() @bind() accessor name = ''; @attr() @bind() accessor value = '0'; @attr() @bind() accessor min = '0'; @attr() @bind() accessor max = '100'; @attr() @bind() accessor step = '1'; #input = query('input'); #internals = this.attachInternals(); connectedCallback() { this.#syncFormState(); } @effect() onChange() { this.#syncFormState(); } @listen('change') onInputChange() { const input = this.#input(); this.value = input.value; } #syncFormState() { const input = this.#input(); this.#internals.setValidity({}); this.#internals.setFormValue(this.value); if (input.validationMessage) { this.#internals.setValidity({ customError: true }, input.validationMessage, input); } } }