import {
  arraysDiffer,
  getNormalizedValueFromClientX,
  numericSort
} from "./chunk.D3YSIVTB.js";
import {
  defaultValue
} from "./chunk.GI7VDIWX.js";
import {
  FormControlController
} from "./chunk.C3WIBDGG.js";
import {
  HasSlotController
} from "./chunk.IVMQWO2L.js";
import {
  LocalizeController
} from "./chunk.X3FE7OHE.js";
import {
  SolidElement,
  customElement
} from "./chunk.H53WQBDK.js";
import {
  __decorateClass
} from "./chunk.S3NI7NKU.js";

// src/components/range/range.ts
import { css, html } from "lit";
import { ifDefined } from "lit/directives/if-defined.js";
import { property, query, queryAll } from "lit/decorators.js";
import cx from "classix";
var SdRange = class extends SolidElement {
  constructor() {
    super();
    this.formControlController = new FormControlController(this);
    this.hasSlotController = new HasSlotController(this, "label", "help-text");
    this.localize = new LocalizeController(this);
    this.name = "";
    this.label = "";
    this.helpText = "";
    this.min = 0;
    this.max = 100;
    this.step = 1;
    this.disabled = false;
    this.visuallyDisabled = false;
    this.noTrackBar = false;
    this.tooltip = "on-interaction";
    this.defaultValue = "";
    this._value = [0];
    this._rangeValues = /* @__PURE__ */ new Map();
    this._lastChangeValue = [];
    this._hasFocus = false;
    this._dragStyleElement = null;
    this._preventSelectStart = (e) => e.preventDefault();
    this.tooltipFormatter = this.localize.number.bind(this.localize);
  }
  set value(value) {
    this._value = value ? value.split(" ").map(Number).sort(numericSort) : [];
  }
  get value() {
    return this._value.slice().sort(numericSort).join(" ");
  }
  /** Gets or sets the current values of the range as an array of numbers */
  set valueAsArray(value) {
    const oldValue = this._value;
    this._value = Array.isArray(value) ? value.slice().sort(numericSort) : value || [];
    if (arraysDiffer(oldValue, this._value)) {
      this.requestUpdate("value", oldValue.join(" "));
    }
  }
  get valueAsArray() {
    return [...this._value].sort(numericSort);
  }
  get rtl() {
    return this.localize.dir() === "rtl";
  }
  disconnectedCallback() {
    super.disconnectedCallback();
    this._restoreTextSelection();
  }
  firstUpdated() {
    this.formControlController.updateValidity();
    this._lastChangeValue = Array.from(this._value);
    this.thumbs.forEach(async (thumb) => {
      var _a, _b;
      const tooltip = thumb.parentElement;
      await tooltip.updateComplete;
      (_b = (_a = tooltip.shadowRoot) == null ? void 0 : _a.querySelector("sd-popup")) == null ? void 0 : _b.setAttribute("distance", "14");
    });
  }
  willUpdate(changedProperties) {
    super.willUpdate(changedProperties);
    if (this.min > this.max) {
      [this.min, this.max] = [this.max, this.min];
    }
    if (this.step > this.max - this.min) {
      this.step = this.max - this.min;
    }
    if (this.step <= 0) {
      this.step = 1;
    }
    const adjustedValue = this._value.map((value) => {
      if (value <= this.min) return this.min;
      if (value >= this.max) return this.max;
      const nextValue = this.min + this.step * Math.round((value - this.min) / this.step);
      if (nextValue > this.max) return this.max;
      return nextValue;
    });
    if (arraysDiffer(this._value, adjustedValue)) {
      this._value = adjustedValue;
    }
  }
  updated(changedProperties) {
    super.updated(changedProperties);
    for (const thumb of this.thumbs) {
      const rangeId = +thumb.dataset.rangeId;
      if (!this._rangeValues.has(rangeId)) continue;
      this.moveThumb(thumb, this._rangeValues.get(rangeId));
      if (this.tooltip === "always-visible") {
        thumb.parentElement.closeTrigger = "manual";
        thumb.parentElement.show();
      }
    }
    this.updateActiveTrack();
  }
  focus(options) {
    const firstThumb = this.thumbs.item(0);
    if (firstThumb) {
      firstThumb.focus(options);
    } else {
      super.focus(options);
    }
  }
  /** Gets the validity state object */
  get validity() {
    return this.input.validity;
  }
  /** Checks for validity but does not show the browser's validation message. */
  checkValidity() {
    var _a;
    return (_a = this.input) == null ? void 0 : _a.checkValidity();
  }
  /** Checks for validity and shows the browser's validation message if the control is invalid. */
  reportValidity() {
    this.formControlController.fakeUserInteraction();
    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();
  }
  updateTooltip(thumb) {
    const rangeId = +thumb.dataset.rangeId;
    if (!this._rangeValues.has(rangeId)) return;
    const value = this._rangeValues.get(rangeId);
    const tooltip = thumb.parentElement;
    tooltip.content = this.tooltipFormatter(value);
  }
  updateActiveTrack() {
    const { activeTrack } = this;
    if (!activeTrack) return;
    if (this.min === this.max) {
      activeTrack.style.insetInlineStart = "0%";
      activeTrack.style.insetInlineEnd = "0%";
      return;
    }
    if (this._value.length === 1) {
      const start2 = getComputedStyle(this).getPropertyValue("--track-active-offset") || "0%";
      const end2 = 100 * (this._value[0] - this.min) / (this.max - this.min);
      activeTrack.style.insetInlineStart = `min(${start2}, ${end2}%)`;
      activeTrack.style.insetInlineEnd = `min(calc(100% - ${start2}), calc(100% - ${end2}%))`;
      return;
    }
    const sortedValues = this._value.slice().sort(numericSort);
    const start = 100 * (sortedValues[0] - this.min) / (this.max - this.min);
    const end = 100 * (sortedValues[sortedValues.length - 1] - this.min) / (this.max - this.min);
    activeTrack.style.insetInlineStart = `${start}%`;
    activeTrack.style.insetInlineEnd = `calc(100% - ${end}%)`;
  }
  moveThumb(thumb, value) {
    thumb.setAttribute("aria-valuenow", value.toString());
    thumb.setAttribute("aria-valuetext", this.tooltipFormatter(value));
    const pos = (value - this.min) / (this.max - this.min);
    thumb.style.insetInlineStart = `calc(${100 * pos}% - 8px)`;
    this.updateTooltip(thumb);
  }
  /**
   * Get the boundaries of a given thumb
   * @param thumb The thumb element that was moved
   * @param value The current value of a thumb
   * @returns An object containing information about the current boundaries
   */
  movementBoundariesForThumb(thumb, value) {
    const values = this.valueAsArray;
    const thumbs = Array.from(this.thumbs);
    const thumbIndex = thumbs.indexOf(thumb);
    const prevValue = values[thumbIndex - 1] || this.min;
    const nextValue = values[thumbIndex + 1] || this.max;
    const isRestricted = value < prevValue || value > nextValue;
    const finalValue = Math.max(prevValue, Math.min(nextValue, value));
    return {
      finalValue,
      isRestricted,
      nextValue,
      prevValue
    };
  }
  handleInvalid(event) {
    this.formControlController.setValidity(false);
    this.formControlController.emitInvalidEvent(event);
  }
  onClickTrack(event, focusThumb = true) {
    if (this.disabled || this.visuallyDisabled) return;
    const { clientX } = event;
    const thumbs = Array.from(this.thumbs);
    const pos = getNormalizedValueFromClientX(this.inputWrapper, clientX);
    const unit = this.step / (this.max - this.min);
    const nextValue = this.min + this.step * Math.round(pos / unit);
    const thumb = thumbs.reduce((prev, curr) => {
      const currValue = this._rangeValues.get(+curr.dataset.rangeId);
      const prevValue2 = this._rangeValues.get(+prev.dataset.rangeId);
      const currDiff = Math.abs(currValue - nextValue);
      const prevDiff = Math.abs(prevValue2 - nextValue);
      if (currDiff === prevDiff) {
        return currValue < nextValue ? curr : prev;
      }
      return currDiff < prevDiff ? curr : prev;
    });
    const rangeId = +thumb.dataset.rangeId;
    if (!rangeId) return;
    this._rangeValues.set(rangeId, nextValue);
    this.moveThumb(thumb, nextValue);
    const prevValue = this._value;
    this._value = Array.from(this._rangeValues.values());
    this.updateActiveTrack();
    if (arraysDiffer(prevValue, this._value)) {
      this._lastChangeValue = Array.from(this._value);
      this.emit("sd-input");
      this.emit("sd-change");
    }
    const newEvent = new PointerEvent("pointerdown", event);
    if (focusThumb) {
      if (thumb.dispatchEvent(newEvent)) {
        this.updateTooltip(thumb);
      }
    }
  }
  /**
   * Special method for handling clicks on track items
   * When clicking track items, we do not want the thumb to have focus
   */
  onClickTrackItem(event) {
    this.onClickTrack(event, false);
  }
  /**
   * Prevents text selection on the entire page during a drag.
   * Uses an injected <style> with !important to ensure no CSS specificity overrides it,
   * plus a selectstart event listener as a fallback.
   */
  _preventTextSelection() {
    if (!this._dragStyleElement) {
      const style = document.createElement("style");
      style.setAttribute("data-sd-range-drag", "");
      style.textContent = "*, *::before, *::after { user-select: none !important; -webkit-user-select: none !important; }";
      document.head.appendChild(style);
      this._dragStyleElement = style;
    }
    document.addEventListener("selectstart", this._preventSelectStart);
  }
  _restoreTextSelection() {
    if (this._dragStyleElement) {
      this._dragStyleElement.remove();
      this._dragStyleElement = null;
    }
    document.removeEventListener("selectstart", this._preventSelectStart);
  }
  async onClickThumb(event) {
    if (this.disabled || this.visuallyDisabled) return;
    const thumb = event.target;
    this.updateTooltip(thumb);
    if (thumb.dataset.pointerId) {
      try {
        thumb.releasePointerCapture(+thumb.dataset.pointerId);
      } catch (e) {
      }
    }
    thumb.dataset.pointerId = event.pointerId.toString();
    thumb.setPointerCapture(event.pointerId);
    this._preventTextSelection();
    thumb.classList.add("grabbed");
    if (this.tooltip === "on-interaction") {
      await thumb.parentElement.show();
    }
  }
  onDragThumb(event) {
    if (this.disabled || this.visuallyDisabled) return;
    const thumb = event.target;
    const rangeId = +thumb.dataset.rangeId;
    if (!this._rangeValues.has(rangeId)) return;
    const pointerId = thumb.dataset.pointerId ? +thumb.dataset.pointerId : null;
    if (pointerId !== event.pointerId) return;
    const pos = getNormalizedValueFromClientX(this.inputWrapper, event.clientX);
    const unit = this.step / (this.max - this.min);
    let value = this.min + this.step * Math.round(pos / unit);
    const sdMove = this.emit("sd-move", {
      cancelable: true,
      detail: {
        element: thumb,
        value
      }
    });
    if (sdMove.defaultPrevented) {
      return;
    }
    const movementData = this.movementBoundariesForThumb(thumb, value);
    if (movementData.isRestricted) {
      value = movementData.finalValue;
      thumb.style.zIndex = (3 + this.thumbs.length).toFixed(0);
    } else {
      thumb.style.zIndex = "3";
    }
    this._rangeValues.set(rangeId, value);
    this.moveThumb(thumb, value);
    const prevValue = this._value;
    this._value = Array.from(this._rangeValues.values());
    this.updateActiveTrack();
    if (arraysDiffer(prevValue, this._value)) {
      this.emit("sd-input");
    }
  }
  async onReleaseThumb(event) {
    const thumb = event.target;
    if (!thumb.dataset.pointerId || event.pointerId !== +thumb.dataset.pointerId) return;
    thumb.classList.remove("grabbed");
    thumb.releasePointerCapture(event.pointerId);
    this._restoreTextSelection();
    delete thumb.dataset.pointerId;
    if (arraysDiffer(this._lastChangeValue, this._value)) {
      this._lastChangeValue = Array.from(this._value);
      this.emit("sd-change");
    }
    if (this.tooltip === "on-interaction") {
      await thumb.parentElement.hide();
    }
  }
  onKeyPress(event) {
    const thumb = event.target;
    const rangeId = +thumb.dataset.rangeId;
    const currentValue = this._rangeValues.get(rangeId);
    if (currentValue === void 0) return;
    let value = currentValue;
    switch (event.key) {
      case "ArrowUp":
      case "Up":
        value = Math.min(currentValue + this.step, this.max);
        break;
      case "ArrowDown":
      case "Down":
        value = Math.max(currentValue - this.step, this.min);
        break;
      case "ArrowLeft":
      case "Left":
        value = this.rtl ? Math.min(currentValue + this.step, this.max) : Math.max(currentValue - this.step, this.min);
        break;
      case "ArrowRight":
      case "Right":
        value = this.rtl ? Math.max(currentValue - this.step, this.min) : Math.min(currentValue + this.step, this.max);
        break;
      case "PageUp":
        value = Math.min(currentValue + (this.max - this.min) / 5, this.max);
        break;
      case "PageDown":
        value = Math.max(currentValue - (this.max - this.min) / 5, this.min);
        break;
      case "Home":
        value = this.min;
        break;
      case "End":
        value = this.max;
        break;
      default:
        return;
    }
    if (value !== currentValue) {
      const sdMove = this.emit("sd-move", {
        cancelable: true,
        detail: {
          element: thumb,
          value
        }
      });
      if (sdMove.defaultPrevented) {
        return;
      }
      const movementData = this.movementBoundariesForThumb(thumb, value);
      if (movementData.isRestricted) {
        value = movementData.finalValue;
      }
      this.moveThumb(thumb, value);
      this._rangeValues.set(rangeId, value);
      this._value = Array.from(this._rangeValues.values());
      this.updateActiveTrack();
      this.updateTooltip(thumb);
      this._lastChangeValue = Array.from(this._value);
      this.emit("sd-input");
      this.emit("sd-change");
    }
    event.preventDefault();
  }
  onBlur(event) {
    var _a;
    if (event.relatedTarget && ((_a = this.shadowRoot) == null ? void 0 : _a.contains(event.relatedTarget))) return;
    this.emit("sd-blur");
    this._hasFocus = false;
  }
  onFocusThumb(event) {
    var _a;
    if (this.disabled || this.visuallyDisabled) return;
    if (!this._hasFocus) {
      this._hasFocus = true;
      this.emit("sd-focus");
    }
    const thumb = event.target;
    if (!((_a = thumb == null ? void 0 : thumb.dataset) == null ? void 0 : _a.rangeId)) return;
    this.updateTooltip(thumb);
  }
  renderThumbs(hasLabel) {
    const isMultiple = this._value.length > 1;
    this._rangeValues.clear();
    return this._value.map((value, index) => {
      const rangeId = index + 1;
      this._rangeValues.set(rangeId, value);
      const id = `thumb-${rangeId}`;
      let ariaLabel = "";
      let ariaLabeledBy = "";
      if (!isMultiple) {
        ariaLabeledBy = hasLabel ? "label aria-label-hidden" : "";
      } else {
        ariaLabeledBy = hasLabel ? `label aria-label-hidden ${id}` : `aria-label-hidden ${id}`;
        if (index === 0) {
          ariaLabel = `${this.localize.term("minimum")} (${this.tooltipFormatter(value)})`;
        } else if (index === this._value.length - 1) {
          ariaLabel = `${this.localize.term("maximum")} (${this.tooltipFormatter(value)})`;
        } else {
          ariaLabel = this.tooltipFormatter(value);
        }
      }
      return html`<sd-tooltip trigger="${this.tooltip === "on-interaction" ? "focus" : "manual"}" disabled="${ifDefined(this.disabled || this.visuallyDisabled || this.tooltip === "hidden" ? true : void 0)}"><div id="${id}" part="thumb" role="slider" tabindex="${this.disabled || this.visuallyDisabled ? -1 : 0}" aria-disabled="${ifDefined(this.disabled || this.visuallyDisabled ? "true" : void 0)}" aria-labelledby="${ariaLabeledBy}" aria-label="${ariaLabel}" aria-valuemax="${this.max}" aria-valuemin="${this.min}" aria-valuenow="${value}" aria-valuetext="${this.tooltipFormatter(value)}" data-range-id="${rangeId}" data-disabled="${ifDefined(this.disabled || this.visuallyDisabled || void 0)}" @pointerdown="${this.onClickThumb}" @pointermove="${this.onDragThumb}" @pointerup="${this.onReleaseThumb}" @pointercancel="${this.onReleaseThumb}" @keydown="${this.onKeyPress}" @focus="${this.onFocusThumb}" class="${cx(
        "rounded-full absolute top-0 size-4 hover:cursor-grab after:-inset-2",
        this.disabled || this.visuallyDisabled ? "outline-none" : "cursor-pointer focus-visible:focus-outline"
      )}"></div></sd-tooltip>`;
    });
  }
  render() {
    const slots = {
      label: this.hasSlotController.test("label"),
      helpText: this.hasSlotController.test("help-text")
    };
    const hasLabel = !!(this.label || slots["label"]);
    const hasHelpText = !!(this.helpText || slots["helpText"]);
    return html`<div part="form-control" @focusout="${this.onBlur}" class="flex flex-col">${hasLabel ? html`<div class="flex items-center gap-1"><label id="label" part="form-control-label" aria-hidden="${hasLabel ? "false" : "true"}" class="${cx("w-full text-start", hasLabel ? "inline-block" : "hidden")}" @click="${this.focus}"><slot name="label">${this.label}</slot></label></div>` : null} <label id="aria-label-hidden" class="sr-only">(${this._value.map(this.tooltipFormatter).join(" - ")})</label><div part="base" class="${cx("inline-flex w-full", this.visuallyDisabled && "focus-visible:focus-outline")}" tabindex="${ifDefined(this.visuallyDisabled ? "0" : void 0)}"><div part="input-wrapper" class="relative flex-1 mx-2 mb-[10px]"><input id="input" tabindex="-1" hidden @invalid="${this.handleInvalid}"><div part="track-wrapper" role="presentation" @pointerdown="${this.onClickTrack}" class="relative cursor-pointer -mx-2"><div part="track-click-helper" class="absolute -inset-y-2 inset-x-0"></div><div part="track" data-disabled="${ifDefined(this.disabled || this.visuallyDisabled || void 0)}" class="${cx("h-1 my-[6px]")}"></div><div part="active-track" hidden="${ifDefined(this.noTrackBar ? true : void 0)}" data-disabled="${ifDefined(this.disabled || this.visuallyDisabled || void 0)}" class="${cx("absolute top-0 h-1")}"></div></div>${this.renderThumbs(hasLabel)}<div class="-mt-[10px]" part="scale-ticks" @pointerdown="${this.onClickTrackItem}" role="presentation"><slot name="scale-ticks"></slot></div></div></div><slot></slot><slot name="help-text" part="form-control-help-text" id="help-text" class="${cx("text-sm text-neutral-700 mt-1", hasHelpText ? "block" : "hidden")}" aria-hidden="${!hasHelpText}">${this.helpText}</slot></div>`;
  }
};
SdRange.styles = [
  ...SolidElement.styles,
  css`/*! tailwindcss v4.3.0 | MIT License | https://tailwindcss.com */@layer theme,base,components,utilities;
[part='base']{touch-action:none;-webkit-touch-callout:none;-webkit-user-select:none;-moz-user-select:none;user-select:none}[part=thumb]{background-color:rgba(var(--sd-color-icon-fill-primary,rgba(var(--sd-color-primary))))}[part=thumb]:hover{background-color:rgba(var(--sd-color-icon-fill-primary-500,rgba(var(--sd-color-primary-500))))}[part=thumb].grabbed{background-color:rgba(var(--sd-color-icon-fill-primary-800,rgba(var(--sd-color-primary-800))))}[part=thumb][data-disabled]{background-color:rgba(var(--sd-color-background-neutral-500,rgba(var(--sd-color-neutral-500))))}[part=track]{background-color:rgba(var(--sd-color-border-neutral-400,rgba(var(--sd-color-neutral-400))))}[part=track][data-disabled]{background-color:rgba(var(--sd-color-background-neutral-500,rgba(var(--sd-color-neutral-500))))}[part=active-track]{background-color:rgba(var(--sd-color-icon-fill-primary,rgba(var(--sd-color-primary))))}[part=active-track][data-disabled]{background-color:rgba(var(--sd-color-background-neutral-500,rgba(var(--sd-color-neutral-500))))}`
];
__decorateClass([
  query("#input")
], SdRange.prototype, "input", 2);
__decorateClass([
  query('[part="active-track"]')
], SdRange.prototype, "activeTrack", 2);
__decorateClass([
  query('[part="input-wrapper"]')
], SdRange.prototype, "inputWrapper", 2);
__decorateClass([
  queryAll('[part="thumb"]')
], SdRange.prototype, "thumbs", 2);
__decorateClass([
  property({ attribute: false })
], SdRange.prototype, "tooltipFormatter", 2);
__decorateClass([
  property({ type: String, reflect: true })
], SdRange.prototype, "name", 2);
__decorateClass([
  property({ type: String, reflect: true })
], SdRange.prototype, "label", 2);
__decorateClass([
  property({ attribute: "help-text", reflect: true })
], SdRange.prototype, "helpText", 2);
__decorateClass([
  property({ type: Number, reflect: true })
], SdRange.prototype, "min", 2);
__decorateClass([
  property({ type: Number, reflect: true })
], SdRange.prototype, "max", 2);
__decorateClass([
  property({ type: Number, reflect: true })
], SdRange.prototype, "step", 2);
__decorateClass([
  property({ type: Boolean, reflect: true })
], SdRange.prototype, "disabled", 2);
__decorateClass([
  property({ attribute: "visually-disabled", type: Boolean, reflect: true })
], SdRange.prototype, "visuallyDisabled", 2);
__decorateClass([
  property({ attribute: "no-track-bar", type: Boolean, reflect: true })
], SdRange.prototype, "noTrackBar", 2);
__decorateClass([
  property({ attribute: "tooltip", type: String, reflect: true })
], SdRange.prototype, "tooltip", 2);
__decorateClass([
  defaultValue()
], SdRange.prototype, "defaultValue", 2);
__decorateClass([
  property({ type: String })
], SdRange.prototype, "value", 1);
SdRange = __decorateClass([
  customElement("sd-range")
], SdRange);

export {
  SdRange
};
