/* COPYRIGHT Esri - https://js.arcgis.com/5.1/LICENSE.txt */
import { c as customElement } from "../../chunks/runtime.js";
import { keyed } from "lit/directives/keyed.js";
import { css, html } from "lit";
import { createRef, ref } from "lit/directives/ref.js";
import { LitElement, safeClassMap, safeStyleMap } from "@arcgis/lumina";
import { n as numberStringFormatter } from "../../chunks/locale.js";
import { z as intersects } from "../../chunks/dom.js";
import { c as createObserver } from "../../chunks/observers.js";
import { u as useT9n } from "../../chunks/useT9n.js";
const CSS = {
  container: "container",
  fill: "fill",
  stepLine: "step-line",
  label: "label",
  labelHidden: "label-hidden",
  labelRange: "label-range",
  labelValue: "label-value",
  unitLabel: "unit-label",
  stepsVisible: "steps-visible",
  valueVisible: "value-visible",
  success: "fill-success",
  warning: "fill-warning",
  danger: "fill-danger"
};
const styles = css`:host([disabled]){cursor:default;-webkit-user-select:none;user-select:none;opacity:var(--calcite-opacity-disabled)}:host([disabled]) *,:host([disabled]) ::slotted(*){pointer-events:none}:host([hidden]){display:none}[hidden]{display:none}:host([disabled]) ::slotted([calcite-hydrated][disabled]),:host([disabled]) [calcite-hydrated][disabled]{opacity:1}.interaction-container{display:contents}:host{display:flex;--calcite-internal-meter-space: var(--calcite-spacing-base);--calcite-internal-meter-height: var(--calcite-spacing-lg);--calcite-internal-meter-font-size: var(--calcite-font-size--1);--calcite-internal-meter-fill-color: var(--calcite-meter-fill-color, var(--calcite-color-brand));--calcite-internal-meter-background-color: var(--calcite-meter-background-color, var(--calcite-color-foreground-2));--calcite-internal-meter-border-color: var(--calcite-meter-border-color, var(--calcite-color-border-2));--calcite-internal-meter-shadow: var(--calcite-meter-shadow, var(--calcite-shadow-none));--calcite-internal-meter-corner-radius: var(--calcite-meter-corner-radius, 9999px);--calcite-internal-meter-value-text-color: var(--calcite-meter-value-text-color, var(--calcite-color-text-1));--calcite-internal-meter-range-text-color: var(--calcite-meter-range-text-color, var(--calcite-color-text-3));--calcite-internal-meter-label-line-height: var(--calcite-font-line-height-base)}:host([scale=s]){--calcite-internal-meter-height: var(--calcite-spacing-md);--calcite-internal-meter-font-size: var(--calcite-font-size--2)}:host([scale=l]){--calcite-internal-meter-height: var(--calcite-spacing-xxl);--calcite-internal-meter-font-size: var(--calcite-font-size-0);--calcite-internal-meter-label-line-height: var(--calcite-font-line-height-md)}:host([appearance=solid]){--calcite-internal-meter-border-color: var(--calcite-color-foreground-3);--calcite-internal-meter-background-color: var(--calcite-color-foreground-3)}:host([appearance=outline]){--calcite-internal-meter-background-color: transparent}.fill{--calcite-internal-meter-fill-color: var(--calcite-meter-fill-color, var(--calcite-color-brand))}.fill-danger{--calcite-internal-meter-fill-color: var(--calcite-meter-fill-color, var(--calcite-color-status-danger))}.fill-success{--calcite-internal-meter-fill-color: var(--calcite-meter-fill-color, var(--calcite-color-status-success))}.fill-warning{--calcite-internal-meter-fill-color: var(--calcite-meter-fill-color, var(--calcite-color-status-warning))}.container{position:relative;display:flex;align-items:center;margin:0;inline-size:var(--calcite-container-size-content-fluid);block-size:var(--calcite-internal-meter-height);background-color:var(--calcite-internal-meter-background-color);border:var(--calcite-border-width-sm) solid var(--calcite-internal-meter-border-color);border-radius:var(--calcite-internal-meter-corner-radius);box-shadow:var(--calcite-internal-meter-shadow)}.value-visible{margin-block-start:var(--calcite-spacing-xxl)}.steps-visible{margin-block-end:var(--calcite-spacing-xxl)}.step-line{position:absolute;inset-block:0px;display:block;inline-size:var(--calcite-internal-meter-space);background-color:var(--calcite-internal-meter-border-color)}.label{position:absolute;display:flex;gap:var(--calcite-spacing-xxs);font-size:var(--calcite-internal-meter-font-size);line-height:var(--calcite-internal-meter-label-line-height)}.label-hidden{visibility:hidden;opacity:0}.label-value{inset-block-end:calc(100% + .5em);font-weight:var(--calcite-font-weight-bold);color:var(--calcite-internal-meter-value-text-color)}.label-range{color:var(--calcite-internal-meter-range-text-color);inset-block-start:calc(100% + .5em)}.label-range .unit-label{font-weight:var(--calcite-font-weight-medium)}.fill{position:absolute;z-index:var(--calcite-z-index);display:block;transition-timing-function:cubic-bezier(.4,0,.2,1);inset-inline-start:var(--calcite-internal-meter-space);inset-block:var(--calcite-internal-meter-space);border-radius:var(--calcite-internal-meter-corner-radius);max-inline-size:calc(100% - var(--calcite-internal-meter-space) * 2);min-inline-size:calc(var(--calcite-internal-meter-height) - var(--calcite-internal-meter-space) * 2);background-color:var(--calcite-internal-meter-fill-color);transition-property:inline-size,background-color,box-shadow}.solid .fill{inset-block:0;inset-inline-start:0;max-inline-size:100%;min-inline-size:calc(var(--calcite-internal-meter-height));box-shadow:0 0 0 1px var(--calcite-internal-meter-fill-color)}`;
class Meter extends LitElement {
  constructor() {
    super(...arguments);
    this.highLabelRef = createRef();
    this.labelFlipMax = 0.8;
    this.labelFlipProximity = 0.15;
    this.lowLabelRef = createRef();
    this.maxLabelRef = createRef();
    this.maxPercent = 100;
    this.messages = useT9n({ name: null });
    this.meterContainerRef = createRef();
    this.minLabelRef = createRef();
    this.minPercent = 0;
    this.resizeObserver = createObserver("resize", () => this.resizeHandler());
    this.valueLabelRef = createRef();
    this.currentPercent = 0;
    this.highActive = false;
    this.highPercent = 100;
    this.lowActive = false;
    this.lowPercent = 0;
    this.appearance = "outline-fill";
    this.disabled = false;
    this.fillType = "range";
    this.groupSeparator = false;
    this.max = 100;
    this.min = 0;
    this.rangeLabelType = "percent";
    this.rangeLabels = false;
    this.scale = "m";
    this.unitLabel = "";
    this.valueLabel = false;
    this.valueLabelType = "percent";
  }
  static {
    this.properties = { currentPercent: [16, {}, { state: true }], highActive: [16, {}, { state: true }], highPercent: [16, {}, { state: true }], lowActive: [16, {}, { state: true }], lowPercent: [16, {}, { state: true }], appearance: [3, {}, { reflect: true }], disabled: [7, {}, { reflect: true, type: Boolean }], fillType: [3, {}, { reflect: true }], form: [3, {}, { reflect: true }], groupSeparator: [7, {}, { reflect: true, type: Boolean }], high: [11, {}, { reflect: true, type: Number }], label: 1, low: [11, {}, { reflect: true, type: Number }], max: [11, {}, { reflect: true, type: Number }], min: [11, {}, { reflect: true, type: Number }], name: [3, {}, { reflect: true }], numberingSystem: 1, rangeLabelType: [3, {}, { reflect: true }], rangeLabels: [7, {}, { reflect: true, type: Boolean }], scale: [3, {}, { reflect: true }], unitLabel: 1, value: [9, {}, { type: Number }], valueLabel: [7, {}, { reflect: true, type: Boolean }], valueLabelType: [3, {}, { reflect: true }] };
  }
  static {
    this.styles = styles;
  }
  connectedCallback() {
    super.connectedCallback();
    this.resizeObserver?.observe(this.el);
  }
  load() {
    this.calculateValues();
  }
  willUpdate(changes) {
    if (changes.has("min") && (this.hasUpdated || this.min !== 0) || changes.has("max") && (this.hasUpdated || this.max !== 100) || changes.has("low") || changes.has("high") || changes.has("value")) {
      this.handleRangeChange();
    }
    if (changes.has("rangeLabels") && (this.hasUpdated || this.rangeLabels !== false) || changes.has("rangeLabelType") && (this.hasUpdated || this.rangeLabelType !== "percent") || changes.has("unitLabel") && (this.hasUpdated || this.unitLabel !== "") || changes.has("valueLabel") && (this.hasUpdated || this.valueLabel !== false) || changes.has("valueLabelType") && (this.hasUpdated || this.valueLabelType !== "percent")) {
      this.updateLabels();
    }
  }
  loaded() {
    this.updateLabels();
  }
  disconnectedCallback() {
    super.disconnectedCallback();
    this.resizeObserver?.disconnect();
  }
  handleRangeChange() {
    this.calculateValues();
    this.updateLabels();
  }
  resizeHandler() {
    this.updateLabels();
  }
  updateLabels() {
    this.determineValueLabelPosition();
    this.determineVisibleLabels();
  }
  calculateValues() {
    const { min, max, low, high, value } = this;
    const lowPercent = 100 * (low - min) / (max - min);
    const highPercent = 100 * (high - min) / (max - min);
    const currentPercent = 100 * (value - min) / (max - min);
    if (!low || low < min || low > high || low > max) {
      this.low = min;
    }
    if (!high || high > max || high < low || high < min) {
      this.high = max;
    }
    if (!value) {
      this.value = min;
    }
    this.lowPercent = lowPercent;
    this.highPercent = highPercent;
    this.currentPercent = value ? currentPercent : 0;
    this.lowActive = !!low && low > min && (!value || low > value) && (!high || low < high);
    this.highActive = !!high && min <= high && high < max && (!value || high > value) && (!low || high > low);
  }
  formatLabel(value, labelType) {
    if (labelType === "percent") {
      if (!this.percentFormatting) {
        const locale = this.messages._lang;
        const formatter = new Intl.NumberFormat(locale, {
          useGrouping: this.groupSeparator,
          style: "percent"
        });
        this.percentFormatting = { formatter, locale };
      }
      return this.percentFormatting.formatter.format(value);
    } else {
      numberStringFormatter.numberFormatOptions = {
        locale: this.messages._lang,
        numberingSystem: this.numberingSystem,
        useGrouping: this.groupSeparator
      };
      return numberStringFormatter.localize(value.toString());
    }
  }
  getMeterKindCssClass() {
    const { low, high, min, max, value } = this;
    const lowest = low ? low : min;
    const highest = high ? high : max;
    const aboveLowest = value >= lowest;
    const belowLowest = value < lowest;
    const aboveHighest = value >= highest;
    const belowHighest = value < highest;
    if (!value || !low && belowHighest || belowLowest) {
      return CSS.success;
    } else if (aboveLowest && belowHighest) {
      return CSS.warning;
    } else if (aboveHighest) {
      return CSS.danger;
    } else {
      return CSS.success;
    }
  }
  intersects(el1, el2) {
    return !!(el1 && el2 && intersects(el1.getBoundingClientRect(), el2.getBoundingClientRect()));
  }
  determineVisibleLabels() {
    if (!this.rangeLabels) {
      return;
    }
    const { minLabelRef: { value: minLabelEl }, lowLabelRef: { value: lowLabelEl }, highLabelRef: { value: highLabelEl }, maxLabelRef: { value: maxLabelEl } } = this;
    const highMaxOverlap = this.intersects(highLabelEl, maxLabelEl);
    const lowHighOverlap = this.intersects(lowLabelEl, highLabelEl);
    const lowMaxOverlap = this.intersects(lowLabelEl, maxLabelEl);
    const minHighOverlap = this.intersects(minLabelEl, highLabelEl);
    const minLowOverlap = this.intersects(minLabelEl, lowLabelEl);
    const minMaxOverlap = this.intersects(minLabelEl, maxLabelEl);
    const hiddenClass = CSS.labelHidden;
    if (lowLabelEl) {
      if (minLowOverlap || lowMaxOverlap || lowHighOverlap) {
        lowLabelEl.classList.add(hiddenClass);
      } else {
        lowLabelEl.classList.remove(hiddenClass);
      }
    }
    if (highLabelEl) {
      if (minHighOverlap || lowMaxOverlap || highMaxOverlap) {
        highLabelEl.classList.add(hiddenClass);
      } else {
        highLabelEl.classList.remove(hiddenClass);
      }
    }
    if (minLabelEl && maxLabelEl) {
      if (minMaxOverlap) {
        maxLabelEl.classList.add(hiddenClass);
      } else {
        maxLabelEl.classList.remove(hiddenClass);
      }
    }
  }
  determineValueLabelPosition() {
    const { valueLabelRef: { value: valueLabelEl }, meterContainerRef: { value: meterContainerEl }, currentPercent } = this;
    if (!valueLabelEl || !meterContainerEl) {
      return;
    }
    const valuePosition = currentPercent > 100 ? 100 : currentPercent > 0 ? currentPercent : 0;
    const valueLabelWidth = valueLabelEl.getBoundingClientRect().width;
    const containerWidth = meterContainerEl.getBoundingClientRect().width;
    const labelWidthPercent = 100 * (valueLabelWidth - 0) / (containerWidth - 0);
    if (valuePosition + labelWidthPercent >= 100) {
      valueLabelEl.style.insetInlineEnd = "0%";
      valueLabelEl.style.removeProperty("inset-inline-start");
    } else {
      valueLabelEl.style.insetInlineStart = `${valuePosition}% `;
      valueLabelEl.style.removeProperty("inset-inline-end");
    }
  }
  renderMeterFill() {
    const { currentPercent, fillType } = this;
    const kindClass = this.getMeterKindCssClass();
    return html`<div class=${safeClassMap({ [CSS.fill]: true, [kindClass]: fillType !== "single" })} style=${safeStyleMap({ width: `${currentPercent}%` })}></div>`;
  }
  renderRangeLine(position) {
    const style = { insetInlineStart: `${position}%` };
    return html`<div class=${safeClassMap(CSS.stepLine)} style=${safeStyleMap(style)}></div>`;
  }
  renderValueLabel() {
    const { currentPercent, valueLabelType, unitLabel, value } = this;
    const label = this.formatLabel(valueLabelType === "percent" ? currentPercent / 100 : value || 0, valueLabelType);
    return keyed("low-label-line", html`<div class=${safeClassMap({ [CSS.label]: true, [CSS.labelValue]: true })} ${ref(this.valueLabelRef)}>${label}${unitLabel && valueLabelType !== "percent" && html`<span class=${safeClassMap(CSS.unitLabel)}>${unitLabel}</span>` || ""}</div>`);
  }
  renderMinLabel() {
    const { rangeLabelType, min, minPercent, unitLabel } = this;
    const style = { insetInlineStart: `${minPercent}%` };
    const labelMin = this.formatLabel(rangeLabelType === "percent" ? minPercent : min, rangeLabelType);
    return keyed("min-label-line", html`<div class=${safeClassMap({ [CSS.label]: true, [CSS.labelRange]: true })} style=${safeStyleMap(style)} ${ref(this.minLabelRef)}>${labelMin}${unitLabel && rangeLabelType !== "percent" && html`<span class=${safeClassMap(CSS.unitLabel)}>${unitLabel}</span>` || ""}</div>`);
  }
  renderLowLabel() {
    const { rangeLabelType, low, lowPercent, highPercent, labelFlipProximity } = this;
    const label = low ? this.formatLabel(rangeLabelType === "percent" ? lowPercent / 100 : low, rangeLabelType) : "";
    const styleDefault = { insetInlineStart: `${lowPercent}%` };
    const styleFlipped = { insetInlineEnd: `${100 - lowPercent}%` };
    const style = (highPercent - lowPercent) / 100 < labelFlipProximity ? styleFlipped : styleDefault;
    return keyed("low-label-line", html`<div class=${safeClassMap({ [CSS.label]: true, [CSS.labelRange]: true })} style=${safeStyleMap(style)} ${ref(this.lowLabelRef)}>${label}</div>`);
  }
  renderHighLabel() {
    const { rangeLabelType, high, highPercent, labelFlipMax } = this;
    const label = high ? this.formatLabel(rangeLabelType === "percent" ? highPercent / 100 : high, rangeLabelType) : "";
    const styleDefault = { insetInlineStart: `${highPercent}%` };
    const styleFlipped = { insetInlineEnd: `${100 - highPercent}%` };
    const style = highPercent / 100 >= labelFlipMax ? styleFlipped : styleDefault;
    return keyed("high-label-line", html`<div class=${safeClassMap({ [CSS.label]: true, [CSS.labelRange]: true })} style=${safeStyleMap(style)} ${ref(this.highLabelRef)}>${label}</div>`);
  }
  renderMaxLabel() {
    const { rangeLabelType, max, maxPercent } = this;
    const style = { insetInlineEnd: `${100 - maxPercent}%` };
    const labelMax = this.formatLabel(rangeLabelType === "percent" ? maxPercent / 100 : max, rangeLabelType);
    return keyed("max-label-line", html`<div class=${safeClassMap({ [CSS.label]: true, [CSS.labelRange]: true })} style=${safeStyleMap(style)} ${ref(this.maxLabelRef)}>${labelMax}</div>`);
  }
  render() {
    const { appearance, currentPercent, highActive, highPercent, label, lowActive, lowPercent, max, maxPercent, min, minPercent, rangeLabels, rangeLabelType, unitLabel, value, valueLabel, valueLabelType } = this;
    const textPercentLabelWithPercent = this.formatLabel(currentPercent / 100, "percent");
    const textUnitLabel = `${value} ${unitLabel}`;
    const valueText = valueLabelType === "percent" ? textPercentLabelWithPercent : unitLabel ? textUnitLabel : void 0;
    return html`<div .ariaLabel=${label} .ariaValueMax=${rangeLabelType === "percent" ? maxPercent : max} .ariaValueMin=${rangeLabelType === "percent" ? minPercent : min} .ariaValueNow=${valueLabelType === "percent" ? currentPercent : value} .ariaValueText=${valueText} class=${safeClassMap({
      [CSS.container]: true,
      [CSS.stepsVisible]: rangeLabels,
      [CSS.valueVisible]: valueLabel,
      [appearance]: appearance !== "outline-fill"
    })} role=meter ${ref(this.meterContainerRef)}>${this.renderMeterFill()}${valueLabel && this.renderValueLabel() || ""}${lowActive && this.renderRangeLine(lowPercent) || ""}${highActive && this.renderRangeLine(highPercent) || ""}${rangeLabels && this.renderMinLabel() || ""}${rangeLabels && lowActive && this.renderLowLabel() || ""}${rangeLabels && highActive && this.renderHighLabel() || ""}${rangeLabels && this.renderMaxLabel() || ""}</div>`;
  }
}
customElement("calcite-meter", Meter);
export {
  Meter
};
