UNPKG

@shoelace-style/shoelace

Version:

A forward-thinking library of web components.

338 lines (333 loc) 10.3 kB
import { range_styles_default } from "./chunk.5D6IT2SR.js"; import { defaultValue } from "./chunk.GI7VDIWX.js"; import { form_control_styles_default } from "./chunk.SI4ACBFK.js"; import { FormControlController } from "./chunk.2RCF7SLU.js"; import { LocalizeController } from "./chunk.WLV3FVBR.js"; import { HasSlotController } from "./chunk.NYIIDP5N.js"; import { watch } from "./chunk.CCJUT23E.js"; import { component_styles_default } from "./chunk.TUVJKY7S.js"; import { ShoelaceElement } from "./chunk.UYAO2JRR.js"; import { __decorateClass } from "./chunk.B3BW2AY6.js"; // src/components/range/range.component.ts import { classMap } from "lit/directives/class-map.js"; import { eventOptions, property, query, state } from "lit/decorators.js"; import { html } from "lit"; import { ifDefined } from "lit/directives/if-defined.js"; import { live } from "lit/directives/live.js"; var SlRange = class extends ShoelaceElement { constructor() { super(...arguments); this.formControlController = new FormControlController(this); this.hasSlotController = new HasSlotController(this, "help-text", "label"); this.localize = new LocalizeController(this); this.hasFocus = false; this.hasTooltip = false; this.title = ""; this.name = ""; this.value = 0; this.label = ""; this.helpText = ""; this.disabled = false; this.min = 0; this.max = 100; this.step = 1; this.tooltip = "top"; this.tooltipFormatter = (value) => value.toString(); this.form = ""; this.defaultValue = 0; } /** Gets the validity state object */ get validity() { return this.input.validity; } /** Gets the validation message */ get validationMessage() { return this.input.validationMessage; } connectedCallback() { super.connectedCallback(); this.resizeObserver = new ResizeObserver(() => this.syncRange()); if (this.value < this.min) { this.value = this.min; } if (this.value > this.max) { this.value = this.max; } this.updateComplete.then(() => { this.syncRange(); this.resizeObserver.observe(this.input); }); } disconnectedCallback() { var _a; super.disconnectedCallback(); (_a = this.resizeObserver) == null ? void 0 : _a.unobserve(this.input); } handleChange() { this.emit("sl-change"); } handleInput() { this.value = parseFloat(this.input.value); this.emit("sl-input"); this.syncRange(); } handleBlur() { this.hasFocus = false; this.hasTooltip = false; this.emit("sl-blur"); } handleFocus() { this.hasFocus = true; this.hasTooltip = true; this.emit("sl-focus"); } handleThumbDragStart() { this.hasTooltip = true; } handleThumbDragEnd() { this.hasTooltip = false; } syncProgress(percent) { this.input.style.setProperty("--percent", `${percent * 100}%`); } syncTooltip(percent) { if (this.output !== null) { const inputWidth = this.input.offsetWidth; const tooltipWidth = this.output.offsetWidth; const thumbSize = getComputedStyle(this.input).getPropertyValue("--thumb-size"); const isRtl = this.localize.dir() === "rtl"; const percentAsWidth = inputWidth * percent; if (isRtl) { const x = `${inputWidth - percentAsWidth}px + ${percent} * ${thumbSize}`; this.output.style.translate = `calc((${x} - ${tooltipWidth / 2}px - ${thumbSize} / 2))`; } else { const x = `${percentAsWidth}px - ${percent} * ${thumbSize}`; this.output.style.translate = `calc(${x} - ${tooltipWidth / 2}px + ${thumbSize} / 2)`; } } } handleValueChange() { this.formControlController.updateValidity(); this.input.value = this.value.toString(); this.value = parseFloat(this.input.value); this.syncRange(); } handleDisabledChange() { this.formControlController.setValidity(this.disabled); } syncRange() { const percent = Math.max(0, (this.value - this.min) / (this.max - this.min)); this.syncProgress(percent); if (this.tooltip !== "none") { this.updateComplete.then(() => this.syncTooltip(percent)); } } handleInvalid(event) { this.formControlController.setValidity(false); this.formControlController.emitInvalidEvent(event); } /** Sets focus on the range. */ focus(options) { this.input.focus(options); } /** Removes focus from the range. */ blur() { this.input.blur(); } /** Increments the value of the range by the value of the step attribute. */ stepUp() { this.input.stepUp(); if (this.value !== Number(this.input.value)) { this.value = Number(this.input.value); } } /** Decrements the value of the range by the value of the step attribute. */ stepDown() { this.input.stepDown(); if (this.value !== Number(this.input.value)) { this.value = Number(this.input.value); } } /** Checks for validity but does not show a validation message. Returns `true` when valid and `false` when invalid. */ checkValidity() { return this.input.checkValidity(); } /** Gets the associated form, if one exists. */ getForm() { return this.formControlController.getForm(); } /** Checks for validity and shows the browser's validation message if the control is invalid. */ reportValidity() { return this.input.reportValidity(); } /** Sets a custom validation message. Pass an empty string to restore validity. */ setCustomValidity(message) { this.input.setCustomValidity(message); this.formControlController.updateValidity(); } render() { const hasLabelSlot = this.hasSlotController.test("label"); const hasHelpTextSlot = this.hasSlotController.test("help-text"); const hasLabel = this.label ? true : !!hasLabelSlot; const hasHelpText = this.helpText ? true : !!hasHelpTextSlot; return html` <div part="form-control" class=${classMap({ "form-control": true, "form-control--medium": true, // range only has one size "form-control--has-label": hasLabel, "form-control--has-help-text": hasHelpText })} > <label part="form-control-label" class="form-control__label" for="input" aria-hidden=${hasLabel ? "false" : "true"} > <slot name="label">${this.label}</slot> </label> <div part="form-control-input" class="form-control-input"> <div part="base" class=${classMap({ range: true, "range--disabled": this.disabled, "range--focused": this.hasFocus, "range--rtl": this.localize.dir() === "rtl", "range--tooltip-visible": this.hasTooltip, "range--tooltip-top": this.tooltip === "top", "range--tooltip-bottom": this.tooltip === "bottom" })} @mousedown=${this.handleThumbDragStart} @mouseup=${this.handleThumbDragEnd} @touchstart=${this.handleThumbDragStart} @touchend=${this.handleThumbDragEnd} > <input part="input" id="input" class="range__control" title=${this.title} type="range" name=${ifDefined(this.name)} ?disabled=${this.disabled} min=${ifDefined(this.min)} max=${ifDefined(this.max)} step=${ifDefined(this.step)} .value=${live(this.value.toString())} aria-describedby="help-text" @change=${this.handleChange} @focus=${this.handleFocus} @input=${this.handleInput} @invalid=${this.handleInvalid} @blur=${this.handleBlur} /> ${this.tooltip !== "none" && !this.disabled ? html` <output part="tooltip" class="range__tooltip"> ${typeof this.tooltipFormatter === "function" ? this.tooltipFormatter(this.value) : this.value} </output> ` : ""} </div> </div> <div part="form-control-help-text" id="help-text" class="form-control__help-text" aria-hidden=${hasHelpText ? "false" : "true"} > <slot name="help-text">${this.helpText}</slot> </div> </div> `; } }; SlRange.styles = [component_styles_default, form_control_styles_default, range_styles_default]; __decorateClass([ query(".range__control") ], SlRange.prototype, "input", 2); __decorateClass([ query(".range__tooltip") ], SlRange.prototype, "output", 2); __decorateClass([ state() ], SlRange.prototype, "hasFocus", 2); __decorateClass([ state() ], SlRange.prototype, "hasTooltip", 2); __decorateClass([ property() ], SlRange.prototype, "title", 2); __decorateClass([ property() ], SlRange.prototype, "name", 2); __decorateClass([ property({ type: Number }) ], SlRange.prototype, "value", 2); __decorateClass([ property() ], SlRange.prototype, "label", 2); __decorateClass([ property({ attribute: "help-text" }) ], SlRange.prototype, "helpText", 2); __decorateClass([ property({ type: Boolean, reflect: true }) ], SlRange.prototype, "disabled", 2); __decorateClass([ property({ type: Number }) ], SlRange.prototype, "min", 2); __decorateClass([ property({ type: Number }) ], SlRange.prototype, "max", 2); __decorateClass([ property({ type: Number }) ], SlRange.prototype, "step", 2); __decorateClass([ property() ], SlRange.prototype, "tooltip", 2); __decorateClass([ property({ attribute: false }) ], SlRange.prototype, "tooltipFormatter", 2); __decorateClass([ property({ reflect: true }) ], SlRange.prototype, "form", 2); __decorateClass([ defaultValue() ], SlRange.prototype, "defaultValue", 2); __decorateClass([ eventOptions({ passive: true }) ], SlRange.prototype, "handleThumbDragStart", 1); __decorateClass([ watch("value", { waitUntilFirstUpdate: true }) ], SlRange.prototype, "handleValueChange", 1); __decorateClass([ watch("disabled", { waitUntilFirstUpdate: true }) ], SlRange.prototype, "handleDisabledChange", 1); __decorateClass([ watch("hasTooltip", { waitUntilFirstUpdate: true }) ], SlRange.prototype, "syncRange", 1); export { SlRange };