All Downloads are FREE. Search and download functionalities are using the official Maven repository.

package.dist.index.mjs Maven / Gradle / Ivy

The newest version!
import { createAnatomy } from '@zag-js/anatomy';
import { getEventStep, isLeftClick, getEventPoint, addDomEvent, requestPointerLock, isModifierKey } from '@zag-js/dom-event';
import { createScope, isSafari, MAX_Z_INDEX, dataAttr, ariaAttr, isComposingEvent, observeAttributes, raf } from '@zag-js/dom-query';
import { roundToDevicePixel, wrap, isAtMin, isAtMax, isWithinRange, increment, clamp, decrement } from '@zag-js/number-utils';
import { createMachine, choose, ref, guards } from '@zag-js/core';
import { trackFormControl } from '@zag-js/form-utils';
import { compact, callAll, isEqual } from '@zag-js/utils';
import { NumberParser } from '@internationalized/number';

// src/number-input.anatomy.ts
var anatomy = createAnatomy("numberInput").parts(
  "root",
  "label",
  "input",
  "control",
  "valueText",
  "incrementTrigger",
  "decrementTrigger",
  "scrubber"
);
var parts = anatomy.build();
var dom = createScope({
  getRootId: (ctx) => ctx.ids?.root ?? `number-input:${ctx.id}`,
  getInputId: (ctx) => ctx.ids?.input ?? `number-input:${ctx.id}:input`,
  getIncrementTriggerId: (ctx) => ctx.ids?.incrementTrigger ?? `number-input:${ctx.id}:inc`,
  getDecrementTriggerId: (ctx) => ctx.ids?.decrementTrigger ?? `number-input:${ctx.id}:dec`,
  getScrubberId: (ctx) => ctx.ids?.scrubber ?? `number-input:${ctx.id}:scrubber`,
  getCursorId: (ctx) => `number-input:${ctx.id}:cursor`,
  getLabelId: (ctx) => ctx.ids?.label ?? `number-input:${ctx.id}:label`,
  getInputEl: (ctx) => dom.getById(ctx, dom.getInputId(ctx)),
  getIncrementTriggerEl: (ctx) => dom.getById(ctx, dom.getIncrementTriggerId(ctx)),
  getDecrementTriggerEl: (ctx) => dom.getById(ctx, dom.getDecrementTriggerId(ctx)),
  getScrubberEl: (ctx) => dom.getById(ctx, dom.getScrubberId(ctx)),
  getCursorEl: (ctx) => dom.getDoc(ctx).getElementById(dom.getCursorId(ctx)),
  getPressedTriggerEl: (ctx, hint = ctx.hint) => {
    let btnEl = null;
    if (hint === "increment") {
      btnEl = dom.getIncrementTriggerEl(ctx);
    }
    if (hint === "decrement") {
      btnEl = dom.getDecrementTriggerEl(ctx);
    }
    return btnEl;
  },
  setupVirtualCursor(ctx) {
    if (isSafari()) return;
    dom.createVirtualCursor(ctx);
    return () => {
      dom.getCursorEl(ctx)?.remove();
    };
  },
  preventTextSelection(ctx) {
    const doc = dom.getDoc(ctx);
    const html = doc.documentElement;
    const body = doc.body;
    body.style.pointerEvents = "none";
    html.style.userSelect = "none";
    html.style.cursor = "ew-resize";
    return () => {
      body.style.pointerEvents = "";
      html.style.userSelect = "";
      html.style.cursor = "";
      if (!html.style.length) {
        html.removeAttribute("style");
      }
      if (!body.style.length) {
        body.removeAttribute("style");
      }
    };
  },
  getMousementValue(ctx, event) {
    const x = roundToDevicePixel(event.movementX);
    const y = roundToDevicePixel(event.movementY);
    let hint = x > 0 ? "increment" : x < 0 ? "decrement" : null;
    if (ctx.isRtl && hint === "increment") hint = "decrement";
    if (ctx.isRtl && hint === "decrement") hint = "increment";
    const point = {
      x: ctx.scrubberCursorPoint.x + x,
      y: ctx.scrubberCursorPoint.y + y
    };
    const win = dom.getWin(ctx);
    const width = win.innerWidth;
    const half = roundToDevicePixel(7.5);
    point.x = wrap(point.x + half, width) - half;
    return { hint, point };
  },
  createVirtualCursor(ctx) {
    const doc = dom.getDoc(ctx);
    const el = doc.createElement("div");
    el.className = "scrubber--cursor";
    el.id = dom.getCursorId(ctx);
    Object.assign(el.style, {
      width: "15px",
      height: "15px",
      position: "fixed",
      pointerEvents: "none",
      left: "0px",
      top: "0px",
      zIndex: MAX_Z_INDEX,
      transform: ctx.scrubberCursorPoint ? `translate3d(${ctx.scrubberCursorPoint.x}px, ${ctx.scrubberCursorPoint.y}px, 0px)` : void 0,
      willChange: "transform"
    });
    el.innerHTML = `
        
          
            
            
          
        `;
    doc.body.appendChild(el);
  }
});

// src/number-input.connect.ts
function connect(state, send, normalize) {
  const focused = state.hasTag("focus");
  const disabled = state.context.isDisabled;
  const readOnly = state.context.readOnly;
  const empty = state.context.isValueEmpty;
  const invalid = state.context.isOutOfRange || !!state.context.invalid;
  const isIncrementDisabled = disabled || !state.context.canIncrement || readOnly;
  const isDecrementDisabled = disabled || !state.context.canDecrement || readOnly;
  const translations = state.context.translations;
  return {
    focused,
    invalid,
    empty,
    value: state.context.formattedValue,
    valueAsNumber: state.context.valueAsNumber,
    setValue(value) {
      send({ type: "VALUE.SET", value });
    },
    clearValue() {
      send("VALUE.CLEAR");
    },
    increment() {
      send("VALUE.INCREMENT");
    },
    decrement() {
      send("VALUE.DECREMENT");
    },
    setToMax() {
      send({ type: "VALUE.SET", value: state.context.max });
    },
    setToMin() {
      send({ type: "VALUE.SET", value: state.context.min });
    },
    focus() {
      dom.getInputEl(state.context)?.focus();
    },
    getRootProps() {
      return normalize.element({
        id: dom.getRootId(state.context),
        ...parts.root.attrs,
        dir: state.context.dir,
        "data-disabled": dataAttr(disabled),
        "data-focus": dataAttr(focused),
        "data-invalid": dataAttr(invalid)
      });
    },
    getLabelProps() {
      return normalize.label({
        ...parts.label.attrs,
        dir: state.context.dir,
        "data-disabled": dataAttr(disabled),
        "data-focus": dataAttr(focused),
        "data-invalid": dataAttr(invalid),
        id: dom.getLabelId(state.context),
        htmlFor: dom.getInputId(state.context)
      });
    },
    getControlProps() {
      return normalize.element({
        ...parts.control.attrs,
        dir: state.context.dir,
        role: "group",
        "aria-disabled": disabled,
        "data-focus": dataAttr(focused),
        "data-disabled": dataAttr(disabled),
        "data-invalid": dataAttr(invalid),
        "aria-invalid": ariaAttr(state.context.invalid)
      });
    },
    getValueTextProps() {
      return normalize.element({
        ...parts.valueText.attrs,
        dir: state.context.dir,
        "data-disabled": dataAttr(disabled),
        "data-invalid": dataAttr(invalid),
        "data-focus": dataAttr(focused)
      });
    },
    getInputProps() {
      return normalize.input({
        ...parts.input.attrs,
        dir: state.context.dir,
        name: state.context.name,
        form: state.context.form,
        id: dom.getInputId(state.context),
        role: "spinbutton",
        defaultValue: state.context.formattedValue,
        pattern: state.context.pattern,
        inputMode: state.context.inputMode,
        "aria-invalid": ariaAttr(invalid),
        "data-invalid": dataAttr(invalid),
        disabled,
        "data-disabled": dataAttr(disabled),
        readOnly: state.context.readOnly,
        required: state.context.required,
        autoComplete: "off",
        autoCorrect: "off",
        spellCheck: "false",
        type: "text",
        "aria-roledescription": "numberfield",
        "aria-valuemin": state.context.min,
        "aria-valuemax": state.context.max,
        "aria-valuenow": Number.isNaN(state.context.valueAsNumber) ? void 0 : state.context.valueAsNumber,
        "aria-valuetext": state.context.valueText,
        onFocus() {
          send("INPUT.FOCUS");
        },
        onBlur() {
          send("INPUT.BLUR");
        },
        onChange(event) {
          send({ type: "INPUT.CHANGE", target: event.currentTarget, hint: "set" });
        },
        onBeforeInput(event) {
          try {
            const { selectionStart, selectionEnd, value } = event.currentTarget;
            const nextValue = value.slice(0, selectionStart) + (event.data ?? "") + value.slice(selectionEnd);
            const isValid = state.context.parser.isValidPartialNumber(nextValue);
            if (!isValid) {
              event.preventDefault();
            }
          } catch {
          }
        },
        onKeyDown(event) {
          if (event.defaultPrevented) return;
          if (readOnly) return;
          if (isComposingEvent(event)) return;
          const step = getEventStep(event) * state.context.step;
          const keyMap = {
            ArrowUp() {
              send({ type: "INPUT.ARROW_UP", step });
              event.preventDefault();
            },
            ArrowDown() {
              send({ type: "INPUT.ARROW_DOWN", step });
              event.preventDefault();
            },
            Home() {
              if (isModifierKey(event)) return;
              send("INPUT.HOME");
              event.preventDefault();
            },
            End() {
              if (isModifierKey(event)) return;
              send("INPUT.END");
              event.preventDefault();
            },
            Enter() {
              send("INPUT.ENTER");
            }
          };
          const exec = keyMap[event.key];
          exec?.(event);
        }
      });
    },
    getDecrementTriggerProps() {
      return normalize.button({
        ...parts.decrementTrigger.attrs,
        dir: state.context.dir,
        id: dom.getDecrementTriggerId(state.context),
        disabled: isDecrementDisabled,
        "data-disabled": dataAttr(isDecrementDisabled),
        "aria-label": translations.decrementLabel,
        type: "button",
        tabIndex: -1,
        "aria-controls": dom.getInputId(state.context),
        onPointerDown(event) {
          if (isDecrementDisabled || !isLeftClick(event)) return;
          send({ type: "TRIGGER.PRESS_DOWN", hint: "decrement", pointerType: event.pointerType });
          if (event.pointerType === "mouse") {
            event.preventDefault();
          }
          if (event.pointerType === "touch") {
            event.currentTarget?.focus({ preventScroll: true });
          }
        },
        onPointerUp(event) {
          send({ type: "TRIGGER.PRESS_UP", hint: "decrement", pointerType: event.pointerType });
        },
        onPointerLeave() {
          if (isDecrementDisabled) return;
          send({ type: "TRIGGER.PRESS_UP", hint: "decrement" });
        }
      });
    },
    getIncrementTriggerProps() {
      return normalize.button({
        ...parts.incrementTrigger.attrs,
        dir: state.context.dir,
        id: dom.getIncrementTriggerId(state.context),
        disabled: isIncrementDisabled,
        "data-disabled": dataAttr(isIncrementDisabled),
        "aria-label": translations.incrementLabel,
        type: "button",
        tabIndex: -1,
        "aria-controls": dom.getInputId(state.context),
        onPointerDown(event) {
          if (isIncrementDisabled || !isLeftClick(event)) return;
          send({ type: "TRIGGER.PRESS_DOWN", hint: "increment", pointerType: event.pointerType });
          if (event.pointerType === "mouse") {
            event.preventDefault();
          }
          if (event.pointerType === "touch") {
            event.currentTarget?.focus({ preventScroll: true });
          }
        },
        onPointerUp(event) {
          send({ type: "TRIGGER.PRESS_UP", hint: "increment", pointerType: event.pointerType });
        },
        onPointerLeave(event) {
          send({ type: "TRIGGER.PRESS_UP", hint: "increment", pointerType: event.pointerType });
        }
      });
    },
    getScrubberProps() {
      return normalize.element({
        ...parts.scrubber.attrs,
        dir: state.context.dir,
        "data-disabled": dataAttr(disabled),
        id: dom.getScrubberId(state.context),
        role: "presentation",
        onMouseDown(event) {
          if (disabled) return;
          const point = getEventPoint(event);
          point.x = point.x - roundToDevicePixel(7.5);
          point.y = point.y - roundToDevicePixel(7.5);
          send({ type: "SCRUBBER.PRESS_DOWN", point });
          event.preventDefault();
        },
        style: {
          cursor: disabled ? void 0 : "ew-resize"
        }
      });
    }
  };
}

// src/cursor.ts
function recordCursor(inputEl) {
  if (inputEl.ownerDocument.activeElement !== inputEl) return;
  try {
    const { selectionStart: start, selectionEnd: end, value } = inputEl;
    const beforeTxt = value.substring(0, start);
    const afterTxt = value.substring(end);
    return {
      start,
      end,
      value,
      beforeTxt,
      afterTxt
    };
  } catch {
  }
}
function restoreCursor(inputEl, selection) {
  if (inputEl.ownerDocument.activeElement !== inputEl) return;
  if (!selection) {
    inputEl.setSelectionRange(inputEl.value.length, inputEl.value.length);
    return;
  }
  try {
    const { value } = inputEl;
    const { beforeTxt = "", afterTxt = "", start } = selection;
    let startPos = value.length;
    if (value.endsWith(afterTxt)) {
      startPos = value.length - afterTxt.length;
    } else if (value.startsWith(beforeTxt)) {
      startPos = beforeTxt.length;
    } else if (start != null) {
      const beforeLastChar = beforeTxt[start - 1];
      const newIndex = value.indexOf(beforeLastChar, start - 1);
      if (newIndex !== -1) {
        startPos = newIndex + 1;
      }
    }
    inputEl.setSelectionRange(startPos, startPos);
  } catch {
  }
}
var createFormatter = (locale, options = {}) => {
  return ref(new Intl.NumberFormat(locale, options));
};
var createParser = (locale, options = {}) => {
  return ref(new NumberParser(locale, options));
};
var parseValue = (ctx, value) => {
  if (!ctx.formatOptions) return parseFloat(value);
  return ctx.parser.parse(String(value));
};
var formatValue = (ctx, value) => {
  if (Number.isNaN(value)) return "";
  if (!ctx.formatOptions) return value.toString();
  return ctx.formatter.format(value);
};

// src/number-input.machine.ts
var { not, and } = guards;
function machine(userContext) {
  const ctx = compact(userContext);
  return createMachine(
    {
      id: "number-input",
      initial: "idle",
      context: {
        dir: "ltr",
        locale: "en-US",
        focusInputOnChange: true,
        clampValueOnBlur: true,
        allowOverflow: false,
        inputMode: "decimal",
        pattern: "[0-9]*(.[0-9]+)?",
        value: "",
        step: 1,
        min: Number.MIN_SAFE_INTEGER,
        max: Number.MAX_SAFE_INTEGER,
        invalid: false,
        spinOnPress: true,
        disabled: false,
        readOnly: false,
        ...ctx,
        hint: null,
        scrubberCursorPoint: null,
        fieldsetDisabled: false,
        formatter: createFormatter(ctx.locale || "en-US", ctx.formatOptions),
        parser: createParser(ctx.locale || "en-US", ctx.formatOptions),
        translations: {
          incrementLabel: "increment value",
          decrementLabel: "decrease value",
          ...ctx.translations
        }
      },
      computed: {
        isRtl: (ctx2) => ctx2.dir === "rtl",
        valueAsNumber: (ctx2) => parseValue(ctx2, ctx2.value),
        formattedValue: (ctx2) => formatValue(ctx2, ctx2.valueAsNumber),
        isAtMin: (ctx2) => isAtMin(ctx2.valueAsNumber, ctx2),
        isAtMax: (ctx2) => isAtMax(ctx2.valueAsNumber, ctx2),
        isOutOfRange: (ctx2) => !isWithinRange(ctx2.valueAsNumber, ctx2),
        isValueEmpty: (ctx2) => ctx2.value === "",
        isDisabled: (ctx2) => !!ctx2.disabled || ctx2.fieldsetDisabled,
        canIncrement: (ctx2) => ctx2.allowOverflow || !ctx2.isAtMax,
        canDecrement: (ctx2) => ctx2.allowOverflow || !ctx2.isAtMin,
        valueText: (ctx2) => ctx2.translations.valueText?.(ctx2.value)
      },
      watch: {
        formatOptions: ["setFormatterAndParser", "syncInputElement"],
        locale: ["setFormatterAndParser", "syncInputElement"],
        value: ["syncInputElement"],
        isOutOfRange: ["invokeOnInvalid"],
        scrubberCursorPoint: ["setVirtualCursorPosition"]
      },
      activities: ["trackFormControl"],
      on: {
        "VALUE.SET": {
          actions: ["setRawValue", "setHintToSet"]
        },
        "VALUE.CLEAR": {
          actions: ["clearValue"]
        },
        "VALUE.INCREMENT": {
          actions: ["increment"]
        },
        "VALUE.DECREMENT": {
          actions: ["decrement"]
        }
      },
      states: {
        idle: {
          on: {
            "TRIGGER.PRESS_DOWN": [
              { guard: "isTouchPointer", target: "before:spin", actions: ["setHint"] },
              {
                target: "before:spin",
                actions: ["focusInput", "invokeOnFocus", "setHint"]
              }
            ],
            "SCRUBBER.PRESS_DOWN": {
              target: "scrubbing",
              actions: ["focusInput", "invokeOnFocus", "setHint", "setCursorPoint"]
            },
            "INPUT.FOCUS": {
              target: "focused",
              actions: ["focusInput", "invokeOnFocus"]
            }
          }
        },
        focused: {
          tags: "focus",
          activities: "attachWheelListener",
          on: {
            "TRIGGER.PRESS_DOWN": [
              { guard: "isTouchPointer", target: "before:spin", actions: ["setHint"] },
              { target: "before:spin", actions: ["focusInput", "setHint"] }
            ],
            "SCRUBBER.PRESS_DOWN": {
              target: "scrubbing",
              actions: ["focusInput", "setHint", "setCursorPoint"]
            },
            "INPUT.ARROW_UP": {
              actions: "increment"
            },
            "INPUT.ARROW_DOWN": {
              actions: "decrement"
            },
            "INPUT.HOME": {
              actions: "decrementToMin"
            },
            "INPUT.END": {
              actions: "incrementToMax"
            },
            "INPUT.CHANGE": {
              actions: ["setValue", "setHint"]
            },
            "INPUT.BLUR": [
              {
                guard: and("clampValueOnBlur", not("isInRange")),
                target: "idle",
                actions: ["setClampedValue", "clearHint", "invokeOnBlur"]
              },
              {
                target: "idle",
                actions: ["setFormattedValue", "clearHint", "invokeOnBlur"]
              }
            ],
            "INPUT.ENTER": {
              actions: ["setFormattedValue", "clearHint", "invokeOnBlur"]
            }
          }
        },
        "before:spin": {
          tags: "focus",
          activities: "trackButtonDisabled",
          entry: choose([
            { guard: "isIncrementHint", actions: "increment" },
            { guard: "isDecrementHint", actions: "decrement" }
          ]),
          after: {
            CHANGE_DELAY: {
              target: "spinning",
              guard: and("isInRange", "spinOnPress")
            }
          },
          on: {
            "TRIGGER.PRESS_UP": [
              { guard: "isTouchPointer", target: "focused", actions: "clearHint" },
              { target: "focused", actions: ["focusInput", "clearHint"] }
            ]
          }
        },
        spinning: {
          tags: "focus",
          activities: "trackButtonDisabled",
          every: [
            {
              delay: "CHANGE_INTERVAL",
              guard: and(not("isAtMin"), "isIncrementHint"),
              actions: "increment"
            },
            {
              delay: "CHANGE_INTERVAL",
              guard: and(not("isAtMax"), "isDecrementHint"),
              actions: "decrement"
            }
          ],
          on: {
            "TRIGGER.PRESS_UP": {
              target: "focused",
              actions: ["focusInput", "clearHint"]
            }
          }
        },
        scrubbing: {
          tags: "focus",
          activities: ["activatePointerLock", "trackMousemove", "setupVirtualCursor", "preventTextSelection"],
          on: {
            "SCRUBBER.POINTER_UP": {
              target: "focused",
              actions: ["focusInput", "clearCursorPoint"]
            },
            "SCRUBBER.POINTER_MOVE": [
              {
                guard: "isIncrementHint",
                actions: ["increment", "setCursorPoint"]
              },
              {
                guard: "isDecrementHint",
                actions: ["decrement", "setCursorPoint"]
              }
            ]
          }
        }
      }
    },
    {
      delays: {
        CHANGE_INTERVAL: 50,
        CHANGE_DELAY: 300
      },
      guards: {
        clampValueOnBlur: (ctx2) => ctx2.clampValueOnBlur,
        isAtMin: (ctx2) => ctx2.isAtMin,
        spinOnPress: (ctx2) => !!ctx2.spinOnPress,
        isAtMax: (ctx2) => ctx2.isAtMax,
        isInRange: (ctx2) => !ctx2.isOutOfRange,
        isDecrementHint: (ctx2, evt) => (evt.hint ?? ctx2.hint) === "decrement",
        isIncrementHint: (ctx2, evt) => (evt.hint ?? ctx2.hint) === "increment",
        isTouchPointer: (_ctx, evt) => evt.pointerType === "touch"
      },
      activities: {
        trackFormControl(ctx2, _evt, { initialContext }) {
          const inputEl = dom.getInputEl(ctx2);
          return trackFormControl(inputEl, {
            onFieldsetDisabledChange(disabled) {
              ctx2.fieldsetDisabled = disabled;
            },
            onFormReset() {
              set.value(ctx2, initialContext.value);
            }
          });
        },
        setupVirtualCursor(ctx2) {
          return dom.setupVirtualCursor(ctx2);
        },
        preventTextSelection(ctx2) {
          return dom.preventTextSelection(ctx2);
        },
        trackButtonDisabled(ctx2, _evt, { send }) {
          const btn = dom.getPressedTriggerEl(ctx2, ctx2.hint);
          return observeAttributes(btn, {
            attributes: ["disabled"],
            callback() {
              send({ type: "TRIGGER.PRESS_UP", src: "attr" });
            }
          });
        },
        attachWheelListener(ctx2, _evt, { send }) {
          const inputEl = dom.getInputEl(ctx2);
          if (!inputEl || !dom.isActiveElement(ctx2, inputEl) || !ctx2.allowMouseWheel) return;
          function onWheel(event) {
            event.preventDefault();
            const dir = Math.sign(event.deltaY) * -1;
            if (dir === 1) {
              send("VALUE.INCREMENT");
            } else if (dir === -1) {
              send("VALUE.DECREMENT");
            }
          }
          return addDomEvent(inputEl, "wheel", onWheel, { passive: false });
        },
        activatePointerLock(ctx2) {
          if (isSafari()) return;
          return requestPointerLock(dom.getDoc(ctx2));
        },
        trackMousemove(ctx2, _evt, { send }) {
          const doc = dom.getDoc(ctx2);
          function onMousemove(event) {
            if (!ctx2.scrubberCursorPoint) return;
            const value = dom.getMousementValue(ctx2, event);
            if (!value.hint) return;
            send({
              type: "SCRUBBER.POINTER_MOVE",
              hint: value.hint,
              point: value.point
            });
          }
          function onMouseup() {
            send("SCRUBBER.POINTER_UP");
          }
          return callAll(
            addDomEvent(doc, "mousemove", onMousemove, false),
            addDomEvent(doc, "mouseup", onMouseup, false)
          );
        }
      },
      actions: {
        focusInput(ctx2) {
          if (!ctx2.focusInputOnChange) return;
          const inputEl = dom.getInputEl(ctx2);
          if (dom.isActiveElement(ctx2, inputEl)) return;
          raf(() => inputEl?.focus({ preventScroll: true }));
        },
        increment(ctx2, evt) {
          const nextValue = increment(ctx2.valueAsNumber, evt.step ?? ctx2.step);
          const value = formatValue(ctx2, clamp(nextValue, ctx2));
          set.value(ctx2, value);
        },
        decrement(ctx2, evt) {
          const nextValue = decrement(ctx2.valueAsNumber, evt.step ?? ctx2.step);
          const value = formatValue(ctx2, clamp(nextValue, ctx2));
          set.value(ctx2, value);
        },
        setClampedValue(ctx2) {
          const nextValue = clamp(ctx2.valueAsNumber, ctx2);
          set.value(ctx2, formatValue(ctx2, nextValue));
        },
        setRawValue(ctx2, evt) {
          const parsedValue = parseValue(ctx2, evt.value);
          const value = formatValue(ctx2, clamp(parsedValue, ctx2));
          set.value(ctx2, value);
        },
        setValue(ctx2, evt) {
          const value = evt.target?.value ?? evt.value;
          set.value(ctx2, value);
        },
        clearValue(ctx2) {
          set.value(ctx2, "");
        },
        incrementToMax(ctx2) {
          const value = formatValue(ctx2, ctx2.max);
          set.value(ctx2, value);
        },
        decrementToMin(ctx2) {
          const value = formatValue(ctx2, ctx2.min);
          set.value(ctx2, value);
        },
        setHint(ctx2, evt) {
          ctx2.hint = evt.hint;
        },
        clearHint(ctx2) {
          ctx2.hint = null;
        },
        setHintToSet(ctx2) {
          ctx2.hint = "set";
        },
        invokeOnFocus(ctx2) {
          ctx2.onFocusChange?.({
            focused: true,
            value: ctx2.formattedValue,
            valueAsNumber: ctx2.valueAsNumber
          });
        },
        invokeOnBlur(ctx2) {
          ctx2.onFocusChange?.({
            focused: false,
            value: ctx2.formattedValue,
            valueAsNumber: ctx2.valueAsNumber
          });
        },
        invokeOnInvalid(ctx2) {
          if (!ctx2.isOutOfRange) return;
          const reason = ctx2.valueAsNumber > ctx2.max ? "rangeOverflow" : "rangeUnderflow";
          ctx2.onValueInvalid?.({
            reason,
            value: ctx2.formattedValue,
            valueAsNumber: ctx2.valueAsNumber
          });
        },
        syncInputElement(ctx2, evt) {
          const value = evt.type.endsWith("CHANGE") ? ctx2.value : ctx2.formattedValue;
          sync.input(ctx2, value);
        },
        setFormattedValue(ctx2) {
          set.value(ctx2, ctx2.formattedValue);
        },
        setCursorPoint(ctx2, evt) {
          ctx2.scrubberCursorPoint = evt.point;
        },
        clearCursorPoint(ctx2) {
          ctx2.scrubberCursorPoint = null;
        },
        setVirtualCursorPosition(ctx2) {
          const cursorEl = dom.getCursorEl(ctx2);
          if (!cursorEl || !ctx2.scrubberCursorPoint) return;
          const { x, y } = ctx2.scrubberCursorPoint;
          cursorEl.style.transform = `translate3d(${x}px, ${y}px, 0px)`;
        },
        setFormatterAndParser(ctx2) {
          if (!ctx2.locale) return;
          ctx2.formatter = createFormatter(ctx2.locale, ctx2.formatOptions);
          ctx2.parser = createParser(ctx2.locale, ctx2.formatOptions);
        }
      },
      compareFns: {
        formatOptions: (a, b) => isEqual(a, b),
        scrubberCursorPoint: (a, b) => isEqual(a, b)
      }
    }
  );
}
var sync = {
  input(ctx, value) {
    const inputEl = dom.getInputEl(ctx);
    if (!inputEl) return;
    const sel = recordCursor(inputEl);
    raf(() => {
      dom.setValue(inputEl, value);
      restoreCursor(inputEl, sel);
    });
  }
};
var invoke = {
  onChange: (ctx) => {
    ctx.onValueChange?.({
      value: ctx.value,
      valueAsNumber: ctx.valueAsNumber
    });
  }
};
var set = {
  value: (ctx, value) => {
    if (isEqual(ctx.value, value)) return;
    ctx.value = value;
    invoke.onChange(ctx);
  }
};

export { anatomy, connect, machine };




© 2015 - 2025 Weber Informatics LLC | Privacy Policy