package.dist.index.mjs Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of number-input Show documentation
Show all versions of number-input Show documentation
Core logic for the number-input widget implemented as a state machine
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