import { BaseCustomWebComponentConstructorAppend, css, html, TypedEvent } from '@node-projects/base-custom-webcomponent';
import { combineNumericStyleInputValue, formatNumericStyleInputNumber, getNumericStyleInputUnitLabel, normalizeNumericStyleInputOptionValues, parseNumericStyleInputValue, resolveNumericStyleInputSelectedUnit, resolveNumericStyleInputStep } from './NumericStyleInputValueHelpers.js';
export { parseNumericStyleInputValue, formatNumericStyleInputNumber, combineNumericStyleInputValue } from './NumericStyleInputValueHelpers.js';
const customOptionValue = '__node-projects-custom-value__';
const dragHandleGlyph = '⋮';
export class NumericStyleInput extends BaseCustomWebComponentConstructorAppend {
    static style = css `
    :host {
      display: block;
      width: 100%;
      min-width: 0;
    }

    #container {
      display: grid;
      gap: 0;
      grid-template-columns: minmax(0, 1fr) auto 16px;
      width: 100%;
      height: 24px;
      align-items: stretch;
    }

    #value-wrapper {
      display: grid;
      grid-template-columns: 14px minmax(0, 1fr);
      min-width: 0;
    }

    #scrubber,
    #input,
    #select,
    #stepper button {
      /* border: 1px solid var(--input-border-color, #596c7a); */
      border: none;
      box-sizing: border-box;
      height: 24px;
      min-height: 24px;
      background: transparent;
      color: inherit;
      font: inherit;
      outline: none;
      box-shadow: none;
    }

    #scrubber,
    #stepper button {
      padding: 0;
      line-height: 1;
    }

    #scrubber {
      border-right: 0;
      cursor: ns-resize;
      font-size: 11px;
      letter-spacing: -1px;
    }

    #input {
      border-left: 0;
      border-right: 0;
      min-width: 0;
      text-align: right;
    }

    #input:focus,
    #select:focus,
    #scrubber:focus,
    #stepper button:focus {
      outline: none;
      box-shadow: none;
      border-color: var(--input-border-color, #596c7a);
    }

    #input[disabled],
    #scrubber[disabled] {
      cursor: default;
    }

    #input[disabled] {
      color: inherit;
      opacity: 1;
      -webkit-text-fill-color: currentColor;
    }

    #select {
      border-left: 0;
      padding: 0 15px 0 2px;
      line-height: 1;
      -webkit-appearance: none;
      appearance: none;
      background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='8' height='4'%3E%3Cpath d='M0 0l4 4 4-4z' fill='%23999'/%3E%3C/svg%3E") no-repeat right 2px center;
    }

    #measure {
      position: absolute;
      visibility: hidden;
      white-space: nowrap;
      font: inherit;
      pointer-events: none;
    }

    #stepper {
      display: grid;
      height: 24px;
      min-height: 24px;
      overflow: hidden;
      grid-template-rows: repeat(2, minmax(0, 1fr));
    }

    #stepper button {
      height: auto;
      min-height: 0;
      width: 16px;
      min-width: 16px;
      font-size: 10px;
    }
  `;
    static template = html `
    <div id="container">
      <div id="value-wrapper">
        <button id="scrubber" type="button" aria-label="Drag to change value">${dragHandleGlyph}</button>
        <input id="input" type="text" spellcheck="false">
      </div>
      <select id="select"></select>
      <div id="stepper">
        <button id="increase" type="button" aria-label="Increase value">+</button>
        <button id="decrease" type="button" aria-label="Decrease value">-</button>
      </div>
      <span id="measure"></span>
    </div>
  `;
    _value = '';
    get value() {
        return this._value;
    }
    set value(value) {
        this._setValue(value, false, false);
    }
    valueChanged = new TypedEvent();
    valuePreviewChanged = new TypedEvent();
    valuePreviewFinished = new TypedEvent();
    _units = ['px', '%', 'pt'];
    get units() {
        return [...this._units];
    }
    set units(value) {
        this._units = this._normalizeOptionValues(value);
        this._lastNumericUnit = this._units[0] ?? this._lastNumericUnit;
        this._updateValue();
    }
    _fixedValues = [];
    get fixedValues() {
        return [...this._fixedValues];
    }
    set fixedValues(value) {
        this._fixedValues = this._normalizeOptionValues(value);
        this._updateValue();
    }
    _step = 1;
    get step() {
        return this._step;
    }
    set step(value) {
        this._step = Number.isFinite(value) && value > 0 ? value : 1;
    }
    _unitSteps = {};
    get unitSteps() {
        return { ...this._unitSteps };
    }
    set unitSteps(value) {
        this._unitSteps = value ?? {};
    }
    _min = null;
    get min() {
        return this._min;
    }
    set min(value) {
        this._min = Number.isFinite(value) ? value : null;
    }
    _max = null;
    get max() {
        return this._max;
    }
    set max(value) {
        this._max = Number.isFinite(value) ? value : null;
    }
    _readOnly = false;
    get readOnly() {
        return this._readOnly;
    }
    set readOnly(value) {
        this._readOnly = value;
        this._applyReadonlyState();
    }
    get isInPreview() {
        return this._previewStartValue != null;
    }
    _allowCustomValue = true;
    get allowCustomValue() {
        return this._allowCustomValue;
    }
    set allowCustomValue(value) {
        this._allowCustomValue = value;
        this._updateValue();
    }
    _unitValueConverter;
    get unitValueConverter() {
        return this._unitValueConverter;
    }
    set unitValueConverter(value) {
        this._unitValueConverter = value;
    }
    _input;
    _select;
    _measure;
    _scrubberButton;
    _increaseButton;
    _decreaseButton;
    _lastNumericValue = 0;
    _lastNumericUnit = 'px';
    _dragPointerId = null;
    _dragStartY = 0;
    _dragStartNumericValue = 0;
    _appliedDragSteps = 0;
    _previewStartValue = null;
    _previewChanged = false;
    _displayValueLock = null;
    _stepperPointerId = null;
    _stepperDirection = 0;
    _stepperRepeatTimeout = null;
    _stepperRepeatInterval = null;
    _windowDragPointerMoveHandler = (event) => this._handleWindowDragPointerMove(event);
    _windowDragPointerUpHandler = (event) => this._finishDragInteractionForPointerEvent(event, false);
    _windowDragPointerCancelHandler = (event) => this._finishDragInteractionForPointerEvent(event, true);
    _windowDragBlurHandler = () => this._finishDragInteraction(false);
    _windowPointerUpHandler = (event) => this._handleWindowStepperPointerEnd(event);
    _windowPointerCancelHandler = (event) => this._handleWindowStepperPointerEnd(event);
    _windowBlurHandler = () => this._finishStepperInteraction(false);
    _preferCustomMode = false;
    constructor() {
        super();
        this._restoreCachedInititalValues();
        this._input = this._getDomElement('input');
        this._select = this._getDomElement('select');
        this._measure = this._getDomElement('measure');
        this._scrubberButton = this._getDomElement('scrubber');
        this._increaseButton = this._getDomElement('increase');
        this._decreaseButton = this._getDomElement('decrease');
    }
    ready() {
        this._parseAttributesToProperties();
        this._wireEvents();
        this._updateValue();
    }
    _wireEvents() {
        this._input.addEventListener('change', () => this._applyTypedValue());
        this._input.addEventListener('keydown', e => {
            if (e.key === 'Enter') {
                this._applyTypedValue();
                this._input.blur();
            }
        });
        this._scrubberButton.addEventListener('pointerdown', e => this._handlePointerDown(e));
        this._select.addEventListener('change', () => this._applySelectedMode());
        this._increaseButton.addEventListener('pointerdown', e => this._handleStepperPointerDown(e, 1));
        this._decreaseButton.addEventListener('pointerdown', e => this._handleStepperPointerDown(e, -1));
    }
    _handlePointerDown(event) {
        if (this._readOnly)
            return;
        if (!this._isSelectedUnitMode()) {
            if (!this._switchToUnitModeForInteraction())
                return;
        }
        this._dragPointerId = event.pointerId;
        this._dragStartY = event.clientY;
        this._dragStartNumericValue = this._readEditableNumericValue(this._select.value);
        this._appliedDragSteps = 0;
        this._startPreviewSession();
        this._attachDragWindowListeners();
        try {
            this._scrubberButton.setPointerCapture(event.pointerId);
        }
        catch {
        }
        event.preventDefault();
    }
    _handleWindowDragPointerMove(event) {
        if (this._dragPointerId !== event.pointerId || !this._isSelectedUnitMode())
            return;
        const stepCount = this._calculateDraggedStepCount(this._dragStartY - event.clientY);
        if (stepCount === this._appliedDragSteps)
            return;
        this._appliedDragSteps = stepCount;
        const unit = this._select.value;
        const step = this._getEffectiveStep(unit);
        this._previewNumericValue(this._getInteractiveStepValue(this._dragStartNumericValue, stepCount, step), unit, step);
        event.preventDefault();
    }
    _finishDragInteractionForPointerEvent(event, wasCancelled) {
        if (this._dragPointerId !== event.pointerId)
            return;
        this._finishDragInteraction(wasCancelled, event.pointerId);
    }
    _finishDragInteraction(wasCancelled, pointerId) {
        if (this._dragPointerId == null)
            return;
        this._dragPointerId = null;
        this._appliedDragSteps = 0;
        this._detachDragWindowListeners();
        if (pointerId != null) {
            try {
                if (this._scrubberButton.hasPointerCapture(pointerId))
                    this._scrubberButton.releasePointerCapture(pointerId);
            }
            catch {
            }
        }
        this._finishPreviewSession(wasCancelled);
    }
    _handleStepperPointerDown(event, direction) {
        if (this._readOnly)
            return;
        if (!this._isSelectedUnitMode()) {
            if (!this._switchToUnitModeForInteraction())
                return;
        }
        this._finishStepperInteraction(true);
        this._stepperPointerId = event.pointerId;
        this._stepperDirection = direction;
        this._attachStepperWindowListeners();
        this._startPreviewSession();
        this._applyStepPreview(direction);
        this._stepperRepeatTimeout = window.setTimeout(() => {
            this._stepperRepeatInterval = window.setInterval(() => this._applyStepPreview(this._stepperDirection), 50);
        }, 350);
        event.preventDefault();
    }
    _handleWindowStepperPointerEnd(event) {
        if (this._stepperPointerId !== event.pointerId)
            return;
        this._finishStepperInteraction(false);
    }
    _finishStepperInteraction(wasCancelled) {
        if (this._stepperPointerId == null)
            return;
        this._stepperPointerId = null;
        this._stepperDirection = 0;
        this._detachStepperWindowListeners();
        this._stopStepperRepeat();
        this._finishPreviewSession(wasCancelled);
    }
    _applySelectedMode() {
        const selectedOption = this._select.selectedOptions.item(0);
        if (!selectedOption)
            return;
        const selectedKind = selectedOption.dataset['kind'];
        if (selectedKind === 'fixed') {
            this._commitValue(selectedOption.value);
            return;
        }
        if (selectedKind === 'custom') {
            this._preferCustomMode = true;
            this._updateValue();
            requestAnimationFrame(() => {
                this._input.focus();
                this._input.select();
            });
            return;
        }
        const selectedUnit = selectedOption.value;
        this._lastNumericUnit = selectedUnit;
        this._preferCustomMode = false;
        const parsedValue = parseNumericStyleInputValue(this._value);
        if (parsedValue.kind === 'numeric') {
            const convertedValue = this._convertNumericValue(parsedValue, selectedUnit);
            this._commitValue(convertedValue);
            return;
        }
        const resolvedCurrentValue = this._resolveCurrentValueForUnit(selectedUnit);
        if (resolvedCurrentValue != null) {
            this._commitValue(resolvedCurrentValue);
            return;
        }
        if (parsedValue.kind === 'empty') {
            this._updateValue();
            this._input.focus();
            return;
        }
        const typedNumericValue = Number(this._input.value);
        if (!Number.isNaN(typedNumericValue)) {
            this._applyNumericValue(typedNumericValue, selectedUnit);
            return;
        }
        // Switching from a non-numeric value (e.g. unset/inherit) to a unit:
        // clear the value so the unit mode is shown with an empty input
        this._commitValue('');
        this._input.focus();
    }
    _applyTypedValue() {
        const selectedOption = this._select.selectedOptions.item(0);
        const selectedKind = selectedOption?.dataset['kind'];
        if (selectedKind === 'fixed')
            return;
        if (selectedKind === 'custom') {
            this._commitValue(this._input.value);
            return;
        }
        const numberText = this._input.value?.trim() ?? '';
        if (!numberText) {
            this._commitValue('');
            return;
        }
        const numericValue = Number(numberText);
        if (!Number.isNaN(numericValue))
            this._lastNumericValue = this._clampNumericValue(numericValue);
        this._commitValue(combineNumericStyleInputValue(numberText, selectedOption?.value ?? ''));
    }
    _updateValue() {
        if (!this._input || !this._select)
            return;
        if (this._previewStartValue == null)
            this._renderSelectOptions();
        const displayState = this._getDisplayState(this._displayValueLock ?? this._value);
        this._input.value = displayState.inputValue;
        this._input.style.display = displayState.inputVisible ? '' : 'none';
        this._input.disabled = this._readOnly || !displayState.inputEnabled;
        this._select.value = displayState.selectValue;
        this._autoSizeSelect();
        if (displayState.mode === 'unit' && displayState.selectedUnit != null)
            this._lastNumericUnit = displayState.selectedUnit;
        if (displayState.mode === 'unit' && displayState.inputValue !== '') {
            const typedNumericValue = Number(displayState.inputValue);
            if (!Number.isNaN(typedNumericValue))
                this._lastNumericValue = this._clampNumericValue(typedNumericValue);
        }
        const hasUnits = this._units.length > 0;
        const interactionDisabled = this._readOnly || (!hasUnits || (displayState.mode === 'custom'));
        this._scrubberButton.disabled = interactionDisabled;
        this._increaseButton.disabled = interactionDisabled;
        this._decreaseButton.disabled = interactionDisabled;
        this._applyReadonlyState();
    }
    _getDisplayState(value) {
        const parsedValue = parseNumericStyleInputValue(value);
        if (parsedValue.kind === 'numeric') {
            if (this._preferCustomMode)
                return this._createCustomDisplayState(parsedValue.numberText);
            if (parsedValue.unit && this._units.length && !this._units.includes(parsedValue.unit))
                return this._createCustomDisplayState(value);
            const selectedUnit = resolveNumericStyleInputSelectedUnit(parsedValue.unit, this._lastNumericUnit, this._units) ?? '';
            return {
                mode: 'unit',
                inputValue: parsedValue.numberText,
                inputVisible: true,
                inputEnabled: true,
                selectValue: this._units.includes(selectedUnit) ? selectedUnit : (this._select.value || customOptionValue),
                selectedUnit
            };
        }
        if (parsedValue.kind === 'text') {
            if (!this._preferCustomMode && this._fixedValues.includes(parsedValue.text)) {
                return {
                    mode: 'fixed',
                    inputValue: '',
                    inputVisible: true,
                    inputEnabled: false,
                    selectValue: parsedValue.text
                };
            }
            return this._createCustomDisplayState(parsedValue.text);
        }
        if (this._preferCustomMode)
            return this._createCustomDisplayState('');
        const selectedUnit = this._lastNumericUnit ?? this._units[0] ?? '';
        if (this._units.includes(selectedUnit)) {
            return {
                mode: 'unit',
                inputValue: '',
                inputVisible: true,
                inputEnabled: true,
                selectValue: selectedUnit,
                selectedUnit
            };
        }
        return this._createCustomDisplayState('');
    }
    _createCustomDisplayState(text) {
        if (!this._allowCustomValue && this._units.length) {
            return {
                mode: 'unit',
                inputValue: text,
                inputVisible: true,
                inputEnabled: true,
                selectValue: this._units[0],
                selectedUnit: this._units[0]
            };
        }
        return {
            mode: 'custom',
            inputValue: text,
            inputVisible: true,
            inputEnabled: true,
            selectValue: customOptionValue
        };
    }
    _renderSelectOptions() {
        const selectedValue = this._select.value;
        this._select.replaceChildren();
        if (this._units.length) {
            const group = document.createElement('optgroup');
            group.label = 'Units';
            for (const unit of this._units)
                group.appendChild(this._createOption(getNumericStyleInputUnitLabel(unit), unit, 'unit'));
            this._select.appendChild(group);
        }
        if (this._fixedValues.length) {
            const group = document.createElement('optgroup');
            group.label = 'Values';
            for (const fixedValue of this._fixedValues)
                group.appendChild(this._createOption(fixedValue, fixedValue, 'fixed'));
            this._select.appendChild(group);
        }
        if (this._allowCustomValue || this._select.options.length === 0)
            this._select.appendChild(this._createOption('custom', customOptionValue, 'custom'));
        if (selectedValue !== '')
            this._select.value = selectedValue;
        else if (this._select.querySelector('option[value=""]'))
            this._select.value = '';
    }
    _createOption(label, value, kind) {
        const option = document.createElement('option');
        option.text = label;
        option.value = value;
        option.dataset['kind'] = kind;
        return option;
    }
    _autoSizeSelect() {
        if (!this._measure || !this._select)
            return;
        const selectedOption = this._select.selectedOptions.item(0);
        this._measure.textContent = selectedOption?.text ?? '';
        const textWidth = this._measure.offsetWidth;
        if (textWidth > 0) {
            // 14px accounts for the custom dropdown arrow + padding
            this._select.style.width = (textWidth + 17) + 'px';
        }
        else {
            // Element not yet laid out, defer measurement
            requestAnimationFrame(() => this._autoSizeSelect());
        }
    }
    _applyReadonlyState() {
        if (!this._input || !this._select)
            return;
        this._input.readOnly = this._readOnly;
        this._select.disabled = this._readOnly;
    }
    _convertNumericValue(parsedValue, selectedUnit) {
        if (selectedUnit == null)
            return this._value;
        const fromUnit = parsedValue.unit;
        const convertedValue = this._unitValueConverter?.({
            value: parsedValue.value,
            numberText: parsedValue.numberText,
            rawValue: this._value,
            fromUnit,
            toUnit: selectedUnit
        });
        return convertedValue ?? combineNumericStyleInputValue(parsedValue.numberText, selectedUnit);
    }
    _resolveCurrentValueForUnit(selectedUnit) {
        if (selectedUnit == null)
            return null;
        const convertedValue = this._unitValueConverter?.({
            value: Number.NaN,
            numberText: '',
            rawValue: this._value,
            fromUnit: '',
            toUnit: selectedUnit
        })?.trim();
        return convertedValue ? convertedValue : null;
    }
    _readEditableNumericValue(selectedUnit) {
        const parsedValue = parseNumericStyleInputValue(this._value);
        if (parsedValue.kind === 'numeric') {
            const convertedValue = this._convertNumericValue(parsedValue, selectedUnit);
            const convertedParsedValue = parseNumericStyleInputValue(convertedValue);
            if (convertedParsedValue.kind === 'numeric')
                return convertedParsedValue.value;
            return parsedValue.value;
        }
        if (this._input.value?.trim()) {
            const typedNumericValue = Number(this._input.value);
            if (!Number.isNaN(typedNumericValue))
                return typedNumericValue;
        }
        return this._lastNumericValue;
    }
    _applyNumericValue(value, unit) {
        this._lastNumericValue = this._clampNumericValue(value);
        this._lastNumericUnit = unit;
        this._commitValue(combineNumericStyleInputValue(formatNumericStyleInputNumber(this._lastNumericValue), unit));
    }
    _previewNumericValue(value, unit, step) {
        this._lastNumericValue = this._clampNumericValue(value);
        this._lastNumericUnit = unit;
        const effectiveStep = step ?? this._getEffectiveStep(unit);
        this._setValue(combineNumericStyleInputValue(this._formatInteractiveNumericValue(this._lastNumericValue, effectiveStep), unit), false, true);
    }
    _commitValue(value) {
        this._setValue(value, true, false);
    }
    _setValue(value, emitCommit, emitPreview) {
        const normalizedValue = value ?? '';
        if (!emitCommit && !emitPreview && this._previewStartValue != null)
            return;
        const oldValue = this._value;
        this._value = normalizedValue;
        if (emitPreview)
            this._displayValueLock = normalizedValue;
        else if (this._displayValueLock != null) {
            if (normalizedValue === this._displayValueLock || normalizedValue !== oldValue)
                this._displayValueLock = null;
        }
        this._preferCustomMode = false;
        this._updateValue();
        if (oldValue !== normalizedValue) {
            if (emitPreview) {
                this._previewChanged = true;
                this.valuePreviewChanged.emit({ newValue: normalizedValue, oldValue: oldValue });
            }
            if (emitCommit)
                this.valueChanged.emit({ newValue: normalizedValue, oldValue: oldValue });
        }
    }
    _startPreviewSession() {
        if (this._previewStartValue == null) {
            this._previewStartValue = this._value;
            this._previewChanged = false;
        }
    }
    _finishPreviewSession(wasCancelled) {
        if (this._previewStartValue == null)
            return;
        const oldValue = this._previewStartValue;
        const newValue = this._displayValueLock ?? this._value;
        const changed = this._previewChanged && oldValue !== newValue;
        const finalWasCancelled = wasCancelled || !changed;
        this._previewStartValue = null;
        this._previewChanged = false;
        if (finalWasCancelled) {
            this._displayValueLock = null;
            this._value = oldValue;
            this._updateValue();
        }
        else {
            this._displayValueLock = newValue;
            this._updateValue();
        }
        this.valuePreviewFinished.emit({ newValue, oldValue, wasCancelled: finalWasCancelled });
    }
    _applyStepPreview(direction) {
        const unit = this._select.value;
        const step = this._getEffectiveStep(unit);
        this._previewNumericValue(this._getInteractiveStepValue(this._readEditableNumericValue(unit), direction, step), unit, step);
    }
    _stopStepperRepeat() {
        if (this._stepperRepeatTimeout != null) {
            window.clearTimeout(this._stepperRepeatTimeout);
            this._stepperRepeatTimeout = null;
        }
        if (this._stepperRepeatInterval != null) {
            window.clearInterval(this._stepperRepeatInterval);
            this._stepperRepeatInterval = null;
        }
    }
    _attachStepperWindowListeners() {
        window.addEventListener('pointerup', this._windowPointerUpHandler, true);
        window.addEventListener('pointercancel', this._windowPointerCancelHandler, true);
        window.addEventListener('blur', this._windowBlurHandler);
    }
    _attachDragWindowListeners() {
        window.addEventListener('pointermove', this._windowDragPointerMoveHandler, true);
        window.addEventListener('pointerup', this._windowDragPointerUpHandler, true);
        window.addEventListener('pointercancel', this._windowDragPointerCancelHandler, true);
        window.addEventListener('blur', this._windowDragBlurHandler);
    }
    _detachStepperWindowListeners() {
        window.removeEventListener('pointerup', this._windowPointerUpHandler, true);
        window.removeEventListener('pointercancel', this._windowPointerCancelHandler, true);
        window.removeEventListener('blur', this._windowBlurHandler);
    }
    _detachDragWindowListeners() {
        window.removeEventListener('pointermove', this._windowDragPointerMoveHandler, true);
        window.removeEventListener('pointerup', this._windowDragPointerUpHandler, true);
        window.removeEventListener('pointercancel', this._windowDragPointerCancelHandler, true);
        window.removeEventListener('blur', this._windowDragBlurHandler);
    }
    _calculateDraggedStepCount(pixelDelta) {
        const absolutePixels = Math.abs(pixelDelta);
        const fineSteps = Math.min(absolutePixels, 20) / 5;
        const mediumSteps = Math.max(Math.min(absolutePixels - 20, 40), 0) / 3;
        const coarseSteps = Math.max(absolutePixels - 60, 0) / 2;
        const stepCount = Math.trunc(fineSteps + mediumSteps + coarseSteps);
        return Math.sign(pixelDelta) * stepCount;
    }
    _getEffectiveStep(unit) {
        return resolveNumericStyleInputStep(this._unitSteps, this._step, unit);
    }
    _getInteractiveStepValue(value, stepCount, step) {
        const effectiveStep = step ?? this._step;
        const clampedValue = this._clampNumericValue(value);
        if (!Number.isFinite(clampedValue) || !Number.isFinite(stepCount) || stepCount === 0)
            return clampedValue;
        const stepBase = this._min ?? 0;
        const quotient = (clampedValue - stepBase) / effectiveStep;
        const roundedQuotient = Math.round(quotient);
        const isAligned = Math.abs(quotient - roundedQuotient) < 1e-9;
        let targetIndex;
        if (stepCount > 0) {
            const firstIndex = isAligned ? roundedQuotient + 1 : Math.ceil(quotient);
            targetIndex = firstIndex + stepCount - 1;
        }
        else {
            const firstIndex = isAligned ? roundedQuotient - 1 : Math.floor(quotient);
            targetIndex = firstIndex + stepCount + 1;
        }
        const targetValue = stepBase + (targetIndex * effectiveStep);
        return this._clampNumericValue(this._roundToStepPrecision(targetValue, effectiveStep));
    }
    _formatInteractiveNumericValue(value, step) {
        const effectiveStep = step ?? this._step;
        return formatNumericStyleInputNumber(this._roundToStepPrecision(value, effectiveStep), this._getStepPrecision(effectiveStep));
    }
    _roundToStepPrecision(value, step) {
        const precision = this._getStepPrecision(step);
        const factor = 10 ** precision;
        return Math.round(value * factor) / factor;
    }
    _getStepPrecision(step) {
        const stepText = `${step ?? this._step}`.toLowerCase();
        if (stepText.includes('e-')) {
            const [coefficientText, exponentText] = stepText.split('e-');
            const exponent = Number(exponentText);
            const decimalPartLength = coefficientText.includes('.') ? coefficientText.length - coefficientText.indexOf('.') - 1 : 0;
            return exponent + decimalPartLength;
        }
        const decimalIndex = stepText.indexOf('.');
        return decimalIndex >= 0 ? stepText.length - decimalIndex - 1 : 0;
    }
    _switchToUnitModeForInteraction() {
        const targetUnit = this._lastNumericUnit ?? this._units[0];
        if (targetUnit == null)
            return false;
        this._preferCustomMode = false;
        const resolved = this._resolveCurrentValueForUnit(targetUnit);
        if (resolved != null) {
            this._commitValue(resolved);
            return this._isSelectedUnitMode();
        }
        this._applyNumericValue(this._lastNumericValue, targetUnit);
        return this._isSelectedUnitMode();
    }
    _isSelectedUnitMode() {
        return this._select.selectedOptions.item(0)?.dataset['kind'] === 'unit';
    }
    _normalizeOptionValues(values) {
        return normalizeNumericStyleInputOptionValues(values);
    }
    _clampNumericValue(value) {
        let result = value;
        if (this._min != null)
            result = Math.max(this._min, result);
        if (this._max != null)
            result = Math.min(this._max, result);
        return result;
    }
}
customElements.define('node-projects-numeric-style-input', NumericStyleInput);
//# sourceMappingURL=NumericStyleInput.js.map