UNPKG

@aidenlx/player

Version:

Headless web components that make integrating media on the a web a breeze.

352 lines (351 loc) 11.8 kB
import { __decorateClass } from "../../chunks/chunk.LNH2V2XS.js"; import { clampNumber, DisposalBin, eventListener, focusVisiblePolyfill, get, getNumberOfDecimalPlaces, rafThrottle, round, setAttribute, setAttributeIfEmpty, setCSSProperty, vdsEvent } from "@vidstack/foundation"; import { html, LitElement } from "lit"; import { property } from "lit/decorators.js"; import { MediaRemoteControl } from "../../media"; import { sliderStoreContext } from "./store"; import { sliderElementStyles } from "./styles"; var SliderKeyDirection = /* @__PURE__ */ ((SliderKeyDirection2) => { SliderKeyDirection2[SliderKeyDirection2["Left"] = -1] = "Left"; SliderKeyDirection2[SliderKeyDirection2["ArrowLeft"] = -1] = "ArrowLeft"; SliderKeyDirection2[SliderKeyDirection2["Up"] = -1] = "Up"; SliderKeyDirection2[SliderKeyDirection2["ArrowUp"] = -1] = "ArrowUp"; SliderKeyDirection2[SliderKeyDirection2["Right"] = 1] = "Right"; SliderKeyDirection2[SliderKeyDirection2["ArrowRight"] = 1] = "ArrowRight"; SliderKeyDirection2[SliderKeyDirection2["Down"] = 1] = "Down"; SliderKeyDirection2[SliderKeyDirection2["ArrowDown"] = 1] = "ArrowDown"; return SliderKeyDirection2; })(SliderKeyDirection || {}); class SliderElement extends LitElement { constructor() { super(); this._sliderStoreProvider = sliderStoreContext.provide(this); this.disabled = false; this.value = 50; this._step = 1; this._keyboardStep = 1; this.shiftKeyMultiplier = 5; this.customValueText = false; this._mediaRemote = new MediaRemoteControl(this); this._disconnectDisposal = new DisposalBin(); this._handlePointerEnter = eventListener(this, "pointerenter", () => { if (this.disabled) return; this.setAttribute("pointing", ""); this.store.pointing.set(true); }); this._handlePointerMove = eventListener(this, "pointermove", (event) => { if (this.disabled || this.isDragging) return; const value = this._getValueBasedOnThumbPosition(event); this.store.pointerValue.set(value); this._dispatchPointerValueChange(event); }); this._handlePointerLeave = eventListener(this, "pointerleave", () => { if (this.disabled) return; this.removeAttribute("pointing"); this.store.pointing.set(false); }); this._handlePointerDown = eventListener(this, "pointerdown", (event) => { if (this.disabled) return; this._startDragging(event); this._onDrag(event); }); this._handleKeydown = eventListener(this, "keydown", (event) => { if (this.disabled) return; const { key, shiftKey } = event; const isValidKey = Object.keys(SliderKeyDirection).includes(key); if (!isValidKey) return; const modifiedStep = !shiftKey ? this.keyboardStep : this.keyboardStep * this.shiftKeyMultiplier; const direction = Number(SliderKeyDirection[key]); const diff = modifiedStep * direction; const steps = (this.value + diff) / this.step; const value = this.step * steps; this.value = this._getClampedValue(value); this._dispatchValueChange(event); }); this._handleFillValueChange = eventListener(this, "vds-slider-value-change", this._updateFillCSSProps.bind(this)); this._handlePointerValueChange = eventListener(this, "vds-slider-pointer-value-change", this._updatePointerCSSProps.bind(this)); this._onDrag = rafThrottle((event) => { if (this.disabled || !this.isDragging) return; const value = this._getValueBasedOnThumbPosition(event); this.store.pointerValue.set(value); this._dispatchPointerValueChange(event); }); this._handleDocumentPointerUp = eventListener(this, "pointerup", (event) => { if (this.disabled || !this.isDragging) return; this._stopDragging(event); }, { target: document }); this._handleDocumentTouchMove = eventListener(this, "touchmove", (event) => { if (this.disabled || !this.isDragging) return; event.preventDefault(); }, { target: document, passive: false }); this._handleDocumentPointerMove = eventListener(this, "pointermove", (event) => { if (this.disabled || !this.isDragging) return; this._onDrag(event); }, { target: document }); this._lastDispatchedValue = this.value; this._dispatchValueChange = rafThrottle((event) => { if (this.value === this._lastDispatchedValue) return; this.dispatchEvent(vdsEvent("vds-slider-value-change", { detail: this.value, triggerEvent: event })); this._lastDispatchedValue = this.value; }); this._lastDispatchedPointerValue = this.pointerValue; this._dispatchPointerValueChange = rafThrottle((event) => { if (this.pointerValue === this._lastDispatchedPointerValue) return; const events = [ "vds-slider-pointer-value-change", this.isDragging && "vds-slider-drag-value-change" ]; events.forEach((eventType) => { if (eventType) { this.dispatchEvent(vdsEvent(eventType, { detail: this.pointerValue, triggerEvent: event })); } }); this._lastDispatchedPointerValue = this.pointerValue; }); if (false) logElementLifecycle(this); focusVisiblePolyfill(this); } static get styles() { return [sliderElementStyles]; } static get parts() { return []; } get store() { return this._sliderStoreProvider.value; } get min() { return get(this.store.min); } set min(newMin) { this.store.min.set(newMin); } get max() { return get(this.store.max); } set max(newMax) { this.store.max.set(newMax); } get step() { return this._step; } set step(newStep) { this._step = newStep; } get keyboardStep() { return this._keyboardStep; } set keyboardStep(newStep) { this._keyboardStep = newStep; } get isDragging() { return get(this.store.dragging); } get fillRate() { const range = this.max - this.min, offset = this.value - this.min; return range > 0 ? offset / range : 0; } get fillPercent() { return this.fillRate * 100; } get pointerValue() { return get(this.store.pointerValue); } get pointerRate() { const range = this.max - this.min, offset = this.pointerValue - this.min; return range > 0 ? offset / range : 0; } get pointerPercent() { return this.pointerRate * 100; } connectedCallback() { super.connectedCallback(); this._setupAriaAttrs(); this._updateFillCSSProps(); this._updatePointerCSSProps(); this._disconnectDisposal.add(this.store.interactive.subscribe(($interactive) => { setAttribute(this, "interactive", $interactive); })); } willUpdate(changedProperties) { if (changedProperties.has("value") || changedProperties.has("min") || changedProperties.has("max")) { this.value = this._getClampedValue(this.value); this.store.value.set(this.value); this._updateFillCSSProps(); this._dispatchValueChange(); } if (changedProperties.has("disabled") && this.disabled) { this.store.dragging.set(false); this.store.pointing.set(false); this.removeAttribute("dragging"); this.removeAttribute("pointing"); this.removeAttribute("interactive"); setAttribute(this, "aria-disabled", this.disabled); } if (!this.customValueText) { this._updateAriaValueAttrs(); } super.willUpdate(changedProperties); } disconnectedCallback() { this._onDrag.cancel(); this._disconnectDisposal.empty(); super.disconnectedCallback(); } _updateFillCSSProps() { setCSSProperty(this, "slider-fill-value", `${this.value}`); setCSSProperty(this, "slider-fill-rate", `${this.fillRate}`); setCSSProperty(this, "slider-fill-percent", `${this.fillPercent}%`); } _updatePointerCSSProps() { setCSSProperty(this, "slider-pointer-value", `${this.pointerValue}`); setCSSProperty(this, "slider-pointer-rate", `${this.pointerRate}`); setCSSProperty(this, "slider-pointer-percent", `${this.pointerPercent}%`); } render() { return this._renderSlider(); } _renderSlider() { return html`${this._renderDefaultSlot()}`; } _renderDefaultSlot() { return html`<slot></slot>`; } _setupAriaAttrs() { setAttributeIfEmpty(this, "role", "slider"); setAttributeIfEmpty(this, "tabindex", "0"); setAttributeIfEmpty(this, "aria-orientation", "horizontal"); setAttributeIfEmpty(this, "autocomplete", "off"); } _updateAriaValueAttrs() { this.setAttribute("aria-valuemin", this._getValueMin()); this.setAttribute("aria-valuenow", this._getValueNow()); this.setAttribute("aria-valuemax", this._getValueMax()); this.setAttribute("aria-valuetext", this._getValueText()); } _getValueMin() { return String(this.min); } _getValueNow() { return String(this.value); } _getValueMax() { return String(this.max); } _getValueText() { return `${round(this.value / this.max * 100, 2)}%`; } _startDragging(event) { if (this.isDragging) return; this.store.dragging.set(true); this.setAttribute("dragging", ""); const value = this._getValueBasedOnThumbPosition(event); this.store.pointerValue.set(value); this._dispatchPointerValueChange(event); this.dispatchEvent(vdsEvent("vds-slider-drag-start", { triggerEvent: event, detail: this.value })); this._mediaRemote.pauseIdling(event); } _stopDragging(event) { if (!this.isDragging) return; this.store.dragging.set(false); this._dispatchValueChange.cancel(); this.removeAttribute("dragging"); const value = this._getValueBasedOnThumbPosition(event); this.value = value; this.store.pointerValue.set(value); this._dispatchValueChange(event); this._dispatchPointerValueChange(event); this.dispatchEvent(vdsEvent("vds-slider-drag-end", { triggerEvent: event, detail: this.value })); this._mediaRemote.resumeIdling(event); } _getClampedValue(value) { return clampNumber(this.min, round(value, getNumberOfDecimalPlaces(this.step)), this.max); } _getValueFromRate(rate) { const boundRate = clampNumber(0, rate, 1); const range = this.max - this.min; const fill = range * boundRate; const stepRatio = Math.round(fill / this.step); const steps = this.step * stepRatio; return this.min + steps; } _getValueBasedOnThumbPosition(event) { const thumbClientX = event.clientX; const { left: trackLeft, width: trackWidth } = this.getBoundingClientRect(); const thumbPositionRate = (thumbClientX - trackLeft) / trackWidth; return this._getValueFromRate(thumbPositionRate); } } __decorateClass([ property({ reflect: true, type: Number }) ], SliderElement.prototype, "min", 1); __decorateClass([ property({ reflect: true, type: Number }) ], SliderElement.prototype, "max", 1); __decorateClass([ property({ reflect: true, type: Boolean }) ], SliderElement.prototype, "disabled", 2); __decorateClass([ property({ reflect: true, type: Number }) ], SliderElement.prototype, "value", 2); __decorateClass([ property({ type: Number, reflect: true }) ], SliderElement.prototype, "step", 1); __decorateClass([ property({ attribute: "keyboard-step", type: Number }) ], SliderElement.prototype, "keyboardStep", 1); __decorateClass([ property({ attribute: "shift-key-multiplier", type: Number }) ], SliderElement.prototype, "shiftKeyMultiplier", 2); __decorateClass([ property({ type: Boolean, attribute: "custom-value-text" }) ], SliderElement.prototype, "customValueText", 2); export { SliderElement, SliderKeyDirection };