@zag-js/number-input 1.43.0 → 2.0.0-next.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.mts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/number-input.anatomy.d.mts +2 -2
- package/dist/number-input.anatomy.d.ts +2 -2
- package/dist/number-input.anatomy.js +2 -1
- package/dist/number-input.anatomy.mjs +2 -1
- package/dist/number-input.connect.js +76 -35
- package/dist/number-input.connect.mjs +78 -36
- package/dist/number-input.dom.d.mts +10 -8
- package/dist/number-input.dom.d.ts +10 -8
- package/dist/number-input.dom.js +60 -64
- package/dist/number-input.dom.mjs +57 -59
- package/dist/number-input.machine.js +70 -28
- package/dist/number-input.machine.mjs +73 -29
- package/dist/number-input.props.js +4 -0
- package/dist/number-input.props.mjs +4 -0
- package/dist/number-input.types.d.mts +115 -12
- package/dist/number-input.types.d.ts +115 -12
- package/package.json +6 -6
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import { memo, setup } from "@zag-js/core";
|
|
3
3
|
import {
|
|
4
4
|
addDomEvent,
|
|
5
|
+
isFirefox,
|
|
5
6
|
isSafari,
|
|
6
7
|
observeAttributes,
|
|
7
8
|
raf,
|
|
@@ -16,7 +17,8 @@ import {
|
|
|
16
17
|
incrementValue,
|
|
17
18
|
isValueAtMax,
|
|
18
19
|
isValueAtMin,
|
|
19
|
-
isValueWithinRange
|
|
20
|
+
isValueWithinRange,
|
|
21
|
+
snapValueToStep
|
|
20
22
|
} from "@zag-js/utils";
|
|
21
23
|
import { recordCursor, restoreCursor } from "./cursor.mjs";
|
|
22
24
|
import * as dom from "./number-input.dom.mjs";
|
|
@@ -39,6 +41,9 @@ var machine = createMachine({
|
|
|
39
41
|
min: Number.MIN_SAFE_INTEGER,
|
|
40
42
|
max: Number.MAX_SAFE_INTEGER,
|
|
41
43
|
spinOnPress: true,
|
|
44
|
+
scrubberPixelSensitivity: 2,
|
|
45
|
+
scrubberDirection: "horizontal",
|
|
46
|
+
snapOnStep: false,
|
|
42
47
|
...props,
|
|
43
48
|
largeStep: props.largeStep ?? 10 * step,
|
|
44
49
|
smallStep: props.smallStep ?? step / 10,
|
|
@@ -70,7 +75,10 @@ var machine = createMachine({
|
|
|
70
75
|
return value ? `x:${value.x}, y:${value.y}` : "";
|
|
71
76
|
}
|
|
72
77
|
})),
|
|
73
|
-
fieldsetDisabled: bindable(() => ({ defaultValue: false }))
|
|
78
|
+
fieldsetDisabled: bindable(() => ({ defaultValue: false })),
|
|
79
|
+
cumulativeDelta: bindable(() => ({ defaultValue: 0 })),
|
|
80
|
+
isPointerLockSupported: bindable(() => ({ defaultValue: false })),
|
|
81
|
+
visualScale: bindable(() => ({ defaultValue: 1 }))
|
|
74
82
|
};
|
|
75
83
|
},
|
|
76
84
|
computed: {
|
|
@@ -105,7 +113,7 @@ var machine = createMachine({
|
|
|
105
113
|
action(["setVirtualCursorPosition"]);
|
|
106
114
|
});
|
|
107
115
|
},
|
|
108
|
-
effects: ["trackFormControl"],
|
|
116
|
+
effects: ["trackFormControl", "detectPointerLock"],
|
|
109
117
|
on: {
|
|
110
118
|
"VALUE.SET": {
|
|
111
119
|
actions: ["setRawValue"]
|
|
@@ -228,22 +236,16 @@ var machine = createMachine({
|
|
|
228
236
|
},
|
|
229
237
|
scrubbing: {
|
|
230
238
|
tags: ["focus"],
|
|
231
|
-
effects: ["activatePointerLock", "trackMousemove", "
|
|
239
|
+
effects: ["activatePointerLock", "trackMousemove", "preventTextSelection", "trackVisualViewport"],
|
|
240
|
+
entry: ["clearCumulativeDelta"],
|
|
232
241
|
on: {
|
|
233
242
|
"SCRUBBER.POINTER_UP": {
|
|
234
243
|
target: "focused",
|
|
235
|
-
actions: ["focusInput", "clearCursorPoint"]
|
|
244
|
+
actions: ["focusInput", "clearCursorPoint", "clearCumulativeDelta"]
|
|
236
245
|
},
|
|
237
|
-
"SCRUBBER.POINTER_MOVE":
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
actions: ["increment", "setCursorPoint"]
|
|
241
|
-
},
|
|
242
|
-
{
|
|
243
|
-
guard: "isDecrementHint",
|
|
244
|
-
actions: ["decrement", "setCursorPoint"]
|
|
245
|
-
}
|
|
246
|
-
]
|
|
246
|
+
"SCRUBBER.POINTER_MOVE": {
|
|
247
|
+
actions: ["accumulateDelta", "setCursorPoint"]
|
|
248
|
+
}
|
|
247
249
|
}
|
|
248
250
|
}
|
|
249
251
|
},
|
|
@@ -270,6 +272,9 @@ var machine = createMachine({
|
|
|
270
272
|
}, 50);
|
|
271
273
|
return () => clearInterval(id);
|
|
272
274
|
},
|
|
275
|
+
detectPointerLock({ context }) {
|
|
276
|
+
context.set("isPointerLockSupported", !isSafari());
|
|
277
|
+
},
|
|
273
278
|
trackFormControl({ context, scope }) {
|
|
274
279
|
const inputEl = dom.getInputEl(scope);
|
|
275
280
|
return trackFormControl(inputEl, {
|
|
@@ -281,12 +286,8 @@ var machine = createMachine({
|
|
|
281
286
|
}
|
|
282
287
|
});
|
|
283
288
|
},
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
return dom.setupVirtualCursor(scope, point);
|
|
287
|
-
},
|
|
288
|
-
preventTextSelection({ scope }) {
|
|
289
|
-
return dom.preventTextSelection(scope);
|
|
289
|
+
preventTextSelection({ scope, prop }) {
|
|
290
|
+
return dom.preventTextSelection(scope, prop("scrubberDirection"));
|
|
290
291
|
},
|
|
291
292
|
trackButtonDisabled({ context, scope, send }) {
|
|
292
293
|
const hint = context.get("hint");
|
|
@@ -312,21 +313,39 @@ var machine = createMachine({
|
|
|
312
313
|
}
|
|
313
314
|
return addDomEvent(inputEl, "wheel", onWheel, { passive: false });
|
|
314
315
|
},
|
|
316
|
+
trackVisualViewport({ scope, context }) {
|
|
317
|
+
const vV = scope.getWin().visualViewport;
|
|
318
|
+
if (!vV) return;
|
|
319
|
+
function onResize() {
|
|
320
|
+
context.set("visualScale", vV.scale);
|
|
321
|
+
}
|
|
322
|
+
onResize();
|
|
323
|
+
return addDomEvent(vV, "resize", onResize);
|
|
324
|
+
},
|
|
315
325
|
activatePointerLock({ scope }) {
|
|
316
326
|
if (isSafari()) return;
|
|
317
|
-
|
|
327
|
+
const cleanup = requestPointerLock(scope.getDoc());
|
|
328
|
+
return () => {
|
|
329
|
+
if (isFirefox()) {
|
|
330
|
+
setTimeout(() => cleanup?.(), 20);
|
|
331
|
+
} else {
|
|
332
|
+
cleanup?.();
|
|
333
|
+
}
|
|
334
|
+
};
|
|
318
335
|
},
|
|
319
|
-
trackMousemove({ scope, send, context, computed }) {
|
|
336
|
+
trackMousemove({ scope, send, context, computed, prop }) {
|
|
320
337
|
const doc = scope.getDoc();
|
|
321
338
|
function onMousemove(event) {
|
|
322
339
|
const point = context.get("scrubberCursorPoint");
|
|
323
340
|
const isRtl = computed("isRtl");
|
|
324
|
-
const
|
|
325
|
-
|
|
341
|
+
const direction = prop("scrubberDirection");
|
|
342
|
+
const teleportDistance = prop("scrubberTeleportDistance");
|
|
343
|
+
const value = dom.getMousemoveValue(scope, { point, isRtl, event, direction, teleportDistance });
|
|
326
344
|
send({
|
|
327
345
|
type: "SCRUBBER.POINTER_MOVE",
|
|
328
346
|
hint: value.hint,
|
|
329
|
-
point: value.point
|
|
347
|
+
point: value.point,
|
|
348
|
+
delta: value.delta
|
|
330
349
|
});
|
|
331
350
|
}
|
|
332
351
|
function onMouseup() {
|
|
@@ -345,11 +364,15 @@ var machine = createMachine({
|
|
|
345
364
|
increment({ context, event, prop, computed }) {
|
|
346
365
|
let nextValue = incrementValue(computed("valueAsNumber"), event.step ?? prop("step"));
|
|
347
366
|
if (!prop("allowOverflow")) nextValue = clampValue(nextValue, prop("min"), prop("max"));
|
|
367
|
+
if (prop("snapOnStep"))
|
|
368
|
+
nextValue = snapValueToStep(nextValue, prop("min"), prop("max"), event.step ?? prop("step"));
|
|
348
369
|
context.set("value", formatValue(nextValue, { computed, prop }));
|
|
349
370
|
},
|
|
350
371
|
decrement({ context, event, prop, computed }) {
|
|
351
372
|
let nextValue = decrementValue(computed("valueAsNumber"), event.step ?? prop("step"));
|
|
352
373
|
if (!prop("allowOverflow")) nextValue = clampValue(nextValue, prop("min"), prop("max"));
|
|
374
|
+
if (prop("snapOnStep"))
|
|
375
|
+
nextValue = snapValueToStep(nextValue, prop("min"), prop("max"), event.step ?? prop("step"));
|
|
353
376
|
context.set("value", formatValue(nextValue, { computed, prop }));
|
|
354
377
|
},
|
|
355
378
|
setClampedValue({ context, prop, computed }) {
|
|
@@ -431,10 +454,31 @@ var machine = createMachine({
|
|
|
431
454
|
context.set("scrubberCursorPoint", null);
|
|
432
455
|
},
|
|
433
456
|
setVirtualCursorPosition({ context, scope }) {
|
|
434
|
-
const
|
|
457
|
+
const scrubberEl = dom.getScrubberEl(scope);
|
|
435
458
|
const point = context.get("scrubberCursorPoint");
|
|
436
|
-
if (!
|
|
437
|
-
|
|
459
|
+
if (!scrubberEl || !point) return;
|
|
460
|
+
scrubberEl.style.setProperty("--scrubber-x", `${point.x}px`);
|
|
461
|
+
scrubberEl.style.setProperty("--scrubber-y", `${point.y}px`);
|
|
462
|
+
},
|
|
463
|
+
accumulateDelta({ context, event, prop, send }) {
|
|
464
|
+
const delta = event.delta ?? 0;
|
|
465
|
+
const newDelta = context.get("cumulativeDelta") + delta;
|
|
466
|
+
const sensitivity = prop("scrubberPixelSensitivity");
|
|
467
|
+
if (Math.abs(newDelta) >= sensitivity) {
|
|
468
|
+
const step = prop("step");
|
|
469
|
+
const hint = event.hint;
|
|
470
|
+
if (hint === "increment") {
|
|
471
|
+
send({ type: "VALUE.INCREMENT", step });
|
|
472
|
+
} else if (hint === "decrement") {
|
|
473
|
+
send({ type: "VALUE.DECREMENT", step });
|
|
474
|
+
}
|
|
475
|
+
context.set("cumulativeDelta", newDelta % sensitivity);
|
|
476
|
+
} else {
|
|
477
|
+
context.set("cumulativeDelta", newDelta);
|
|
478
|
+
}
|
|
479
|
+
},
|
|
480
|
+
clearCumulativeDelta({ context }) {
|
|
481
|
+
context.set("cumulativeDelta", 0);
|
|
438
482
|
}
|
|
439
483
|
}
|
|
440
484
|
}
|
|
@@ -52,7 +52,11 @@ var props = (0, import_types.createProps)()([
|
|
|
52
52
|
"pattern",
|
|
53
53
|
"required",
|
|
54
54
|
"readOnly",
|
|
55
|
+
"scrubberDirection",
|
|
56
|
+
"scrubberPixelSensitivity",
|
|
57
|
+
"scrubberTeleportDistance",
|
|
55
58
|
"smallStep",
|
|
59
|
+
"snapOnStep",
|
|
56
60
|
"spinOnPress",
|
|
57
61
|
"step",
|
|
58
62
|
"translations",
|
|
@@ -21,6 +21,7 @@ type ElementIds = Partial<{
|
|
|
21
21
|
incrementTrigger: string;
|
|
22
22
|
decrementTrigger: string;
|
|
23
23
|
scrubber: string;
|
|
24
|
+
scrubberCursor: string;
|
|
24
25
|
}>;
|
|
25
26
|
interface IntlTranslations {
|
|
26
27
|
/**
|
|
@@ -96,16 +97,6 @@ interface NumberInputProps extends LocaleProperties, CommonProperties {
|
|
|
96
97
|
* @default 1
|
|
97
98
|
*/
|
|
98
99
|
step?: number | undefined;
|
|
99
|
-
/**
|
|
100
|
-
* The amount to increment or decrement the value by when the `Shift` key is held.
|
|
101
|
-
* @default 10 * step
|
|
102
|
-
*/
|
|
103
|
-
largeStep?: number | undefined;
|
|
104
|
-
/**
|
|
105
|
-
* The amount to increment or decrement the value by when the `Alt` key is held.
|
|
106
|
-
* @default step / 10
|
|
107
|
-
*/
|
|
108
|
-
smallStep?: number | undefined;
|
|
109
100
|
/**
|
|
110
101
|
* Whether to allow mouse wheel to change the value
|
|
111
102
|
*/
|
|
@@ -160,8 +151,39 @@ interface NumberInputProps extends LocaleProperties, CommonProperties {
|
|
|
160
151
|
* @default true
|
|
161
152
|
*/
|
|
162
153
|
spinOnPress?: boolean | undefined;
|
|
154
|
+
/**
|
|
155
|
+
* Step value when Shift key is held (large increments).
|
|
156
|
+
* @default step * 10
|
|
157
|
+
*/
|
|
158
|
+
largeStep?: number | undefined;
|
|
159
|
+
/**
|
|
160
|
+
* Step value when Alt/Option key is held (fine control).
|
|
161
|
+
* @default step * 0.1
|
|
162
|
+
*/
|
|
163
|
+
smallStep?: number | undefined;
|
|
164
|
+
/**
|
|
165
|
+
* How many pixels the pointer must move to change the value by one step.
|
|
166
|
+
* Higher values mean more precise control. Lower values mean more sensitivity.
|
|
167
|
+
* @default 2
|
|
168
|
+
*/
|
|
169
|
+
scrubberPixelSensitivity?: number | undefined;
|
|
170
|
+
/**
|
|
171
|
+
* Distance in pixels before the virtual cursor wraps around.
|
|
172
|
+
* When not set, the viewport bounds are used (default behavior).
|
|
173
|
+
*/
|
|
174
|
+
scrubberTeleportDistance?: number | undefined;
|
|
175
|
+
/**
|
|
176
|
+
* The direction of scrubbing.
|
|
177
|
+
* @default "horizontal"
|
|
178
|
+
*/
|
|
179
|
+
scrubberDirection?: "horizontal" | "vertical" | undefined;
|
|
180
|
+
/**
|
|
181
|
+
* Whether values snap to step multiples when scrubbing.
|
|
182
|
+
* @default false
|
|
183
|
+
*/
|
|
184
|
+
snapOnStep?: boolean | undefined;
|
|
163
185
|
}
|
|
164
|
-
type PropsWithDefault = "dir" | "locale" | "focusInputOnChange" | "clampValueOnBlur" | "allowOverflow" | "inputMode" | "pattern" | "translations" | "step" | "largeStep" | "smallStep" | "spinOnPress" | "min" | "max";
|
|
186
|
+
type PropsWithDefault = "dir" | "locale" | "focusInputOnChange" | "clampValueOnBlur" | "allowOverflow" | "inputMode" | "pattern" | "translations" | "step" | "largeStep" | "smallStep" | "spinOnPress" | "min" | "max" | "scrubberPixelSensitivity" | "scrubberDirection" | "snapOnStep";
|
|
165
187
|
type ComputedContext = Readonly<{
|
|
166
188
|
/**
|
|
167
189
|
* The value of the input as a number
|
|
@@ -237,6 +259,18 @@ interface PrivateContext {
|
|
|
237
259
|
* The value of the input
|
|
238
260
|
*/
|
|
239
261
|
value: string;
|
|
262
|
+
/**
|
|
263
|
+
* The accumulated delta for pixel sensitivity tracking
|
|
264
|
+
*/
|
|
265
|
+
cumulativeDelta: number;
|
|
266
|
+
/**
|
|
267
|
+
* Whether the browser supports pointer lock (false on Safari, false during SSR)
|
|
268
|
+
*/
|
|
269
|
+
isPointerLockSupported: boolean;
|
|
270
|
+
/**
|
|
271
|
+
* The visual viewport scale (for pinch-zoom compensation on the cursor)
|
|
272
|
+
*/
|
|
273
|
+
visualScale: number;
|
|
240
274
|
}
|
|
241
275
|
interface NumberInputSchema {
|
|
242
276
|
state: "idle" | "focused" | "spinning" | "before:spin" | "scrubbing";
|
|
@@ -251,11 +285,63 @@ interface NumberInputSchema {
|
|
|
251
285
|
}
|
|
252
286
|
type NumberInputService = Service<NumberInputSchema>;
|
|
253
287
|
type NumberInputMachine = Machine<NumberInputSchema>;
|
|
288
|
+
interface RootState {
|
|
289
|
+
/**
|
|
290
|
+
* Whether the number input is disabled.
|
|
291
|
+
*/
|
|
292
|
+
disabled: boolean;
|
|
293
|
+
/**
|
|
294
|
+
* Whether the number input is focused.
|
|
295
|
+
*/
|
|
296
|
+
focused: boolean;
|
|
297
|
+
/**
|
|
298
|
+
* Whether the number input is invalid.
|
|
299
|
+
*/
|
|
300
|
+
invalid: boolean;
|
|
301
|
+
/**
|
|
302
|
+
* Whether the number input is being scrubbed.
|
|
303
|
+
*/
|
|
304
|
+
scrubbing: boolean;
|
|
305
|
+
}
|
|
306
|
+
interface InputState {
|
|
307
|
+
/**
|
|
308
|
+
* Whether the input is disabled.
|
|
309
|
+
*/
|
|
310
|
+
disabled: boolean;
|
|
311
|
+
/**
|
|
312
|
+
* Whether the input is invalid.
|
|
313
|
+
*/
|
|
314
|
+
invalid: boolean;
|
|
315
|
+
/**
|
|
316
|
+
* Whether the input is read-only.
|
|
317
|
+
*/
|
|
318
|
+
readOnly: boolean;
|
|
319
|
+
/**
|
|
320
|
+
* Whether the input is being scrubbed.
|
|
321
|
+
*/
|
|
322
|
+
scrubbing: boolean;
|
|
323
|
+
}
|
|
324
|
+
interface IncrementTriggerState {
|
|
325
|
+
/**
|
|
326
|
+
* Whether the increment trigger is disabled.
|
|
327
|
+
*/
|
|
328
|
+
disabled: boolean;
|
|
329
|
+
}
|
|
330
|
+
interface DecrementTriggerState {
|
|
331
|
+
/**
|
|
332
|
+
* Whether the decrement trigger is disabled.
|
|
333
|
+
*/
|
|
334
|
+
disabled: boolean;
|
|
335
|
+
}
|
|
254
336
|
interface NumberInputApi<T extends PropTypes = PropTypes> {
|
|
255
337
|
/**
|
|
256
338
|
* Whether the input is focused.
|
|
257
339
|
*/
|
|
258
340
|
focused: boolean;
|
|
341
|
+
/**
|
|
342
|
+
* Whether the input is being scrubbed.
|
|
343
|
+
*/
|
|
344
|
+
scrubbing: boolean;
|
|
259
345
|
/**
|
|
260
346
|
* Whether the input is invalid.
|
|
261
347
|
*/
|
|
@@ -300,14 +386,31 @@ interface NumberInputApi<T extends PropTypes = PropTypes> {
|
|
|
300
386
|
* Function to focus the input.
|
|
301
387
|
*/
|
|
302
388
|
focus: VoidFunction;
|
|
389
|
+
/**
|
|
390
|
+
* Returns the state of the root.
|
|
391
|
+
*/
|
|
392
|
+
getRootState: () => RootState;
|
|
303
393
|
getRootProps: () => T["element"];
|
|
304
394
|
getLabelProps: () => T["label"];
|
|
305
395
|
getControlProps: () => T["element"];
|
|
306
396
|
getValueTextProps: () => T["element"];
|
|
397
|
+
/**
|
|
398
|
+
* Returns the state of the input.
|
|
399
|
+
*/
|
|
400
|
+
getInputState: () => InputState;
|
|
307
401
|
getInputProps: () => T["input"];
|
|
402
|
+
/**
|
|
403
|
+
* Returns the state of the decrement trigger.
|
|
404
|
+
*/
|
|
405
|
+
getDecrementTriggerState: () => DecrementTriggerState;
|
|
308
406
|
getDecrementTriggerProps: () => T["button"];
|
|
407
|
+
/**
|
|
408
|
+
* Returns the state of the increment trigger.
|
|
409
|
+
*/
|
|
410
|
+
getIncrementTriggerState: () => IncrementTriggerState;
|
|
309
411
|
getIncrementTriggerProps: () => T["button"];
|
|
310
412
|
getScrubberProps: () => T["element"];
|
|
413
|
+
getScrubberCursorProps: () => T["element"];
|
|
311
414
|
}
|
|
312
415
|
|
|
313
|
-
export type { ElementIds, FocusChangeDetails, HintValue, InputMode, IntlTranslations, NumberInputApi, NumberInputMachine, NumberInputProps, NumberInputSchema, NumberInputService, ValidityState, ValueChangeDetails, ValueInvalidDetails };
|
|
416
|
+
export type { DecrementTriggerState, ElementIds, FocusChangeDetails, HintValue, IncrementTriggerState, InputMode, InputState, IntlTranslations, NumberInputApi, NumberInputMachine, NumberInputProps, NumberInputSchema, NumberInputService, RootState, ValidityState, ValueChangeDetails, ValueInvalidDetails };
|
|
@@ -21,6 +21,7 @@ type ElementIds = Partial<{
|
|
|
21
21
|
incrementTrigger: string;
|
|
22
22
|
decrementTrigger: string;
|
|
23
23
|
scrubber: string;
|
|
24
|
+
scrubberCursor: string;
|
|
24
25
|
}>;
|
|
25
26
|
interface IntlTranslations {
|
|
26
27
|
/**
|
|
@@ -96,16 +97,6 @@ interface NumberInputProps extends LocaleProperties, CommonProperties {
|
|
|
96
97
|
* @default 1
|
|
97
98
|
*/
|
|
98
99
|
step?: number | undefined;
|
|
99
|
-
/**
|
|
100
|
-
* The amount to increment or decrement the value by when the `Shift` key is held.
|
|
101
|
-
* @default 10 * step
|
|
102
|
-
*/
|
|
103
|
-
largeStep?: number | undefined;
|
|
104
|
-
/**
|
|
105
|
-
* The amount to increment or decrement the value by when the `Alt` key is held.
|
|
106
|
-
* @default step / 10
|
|
107
|
-
*/
|
|
108
|
-
smallStep?: number | undefined;
|
|
109
100
|
/**
|
|
110
101
|
* Whether to allow mouse wheel to change the value
|
|
111
102
|
*/
|
|
@@ -160,8 +151,39 @@ interface NumberInputProps extends LocaleProperties, CommonProperties {
|
|
|
160
151
|
* @default true
|
|
161
152
|
*/
|
|
162
153
|
spinOnPress?: boolean | undefined;
|
|
154
|
+
/**
|
|
155
|
+
* Step value when Shift key is held (large increments).
|
|
156
|
+
* @default step * 10
|
|
157
|
+
*/
|
|
158
|
+
largeStep?: number | undefined;
|
|
159
|
+
/**
|
|
160
|
+
* Step value when Alt/Option key is held (fine control).
|
|
161
|
+
* @default step * 0.1
|
|
162
|
+
*/
|
|
163
|
+
smallStep?: number | undefined;
|
|
164
|
+
/**
|
|
165
|
+
* How many pixels the pointer must move to change the value by one step.
|
|
166
|
+
* Higher values mean more precise control. Lower values mean more sensitivity.
|
|
167
|
+
* @default 2
|
|
168
|
+
*/
|
|
169
|
+
scrubberPixelSensitivity?: number | undefined;
|
|
170
|
+
/**
|
|
171
|
+
* Distance in pixels before the virtual cursor wraps around.
|
|
172
|
+
* When not set, the viewport bounds are used (default behavior).
|
|
173
|
+
*/
|
|
174
|
+
scrubberTeleportDistance?: number | undefined;
|
|
175
|
+
/**
|
|
176
|
+
* The direction of scrubbing.
|
|
177
|
+
* @default "horizontal"
|
|
178
|
+
*/
|
|
179
|
+
scrubberDirection?: "horizontal" | "vertical" | undefined;
|
|
180
|
+
/**
|
|
181
|
+
* Whether values snap to step multiples when scrubbing.
|
|
182
|
+
* @default false
|
|
183
|
+
*/
|
|
184
|
+
snapOnStep?: boolean | undefined;
|
|
163
185
|
}
|
|
164
|
-
type PropsWithDefault = "dir" | "locale" | "focusInputOnChange" | "clampValueOnBlur" | "allowOverflow" | "inputMode" | "pattern" | "translations" | "step" | "largeStep" | "smallStep" | "spinOnPress" | "min" | "max";
|
|
186
|
+
type PropsWithDefault = "dir" | "locale" | "focusInputOnChange" | "clampValueOnBlur" | "allowOverflow" | "inputMode" | "pattern" | "translations" | "step" | "largeStep" | "smallStep" | "spinOnPress" | "min" | "max" | "scrubberPixelSensitivity" | "scrubberDirection" | "snapOnStep";
|
|
165
187
|
type ComputedContext = Readonly<{
|
|
166
188
|
/**
|
|
167
189
|
* The value of the input as a number
|
|
@@ -237,6 +259,18 @@ interface PrivateContext {
|
|
|
237
259
|
* The value of the input
|
|
238
260
|
*/
|
|
239
261
|
value: string;
|
|
262
|
+
/**
|
|
263
|
+
* The accumulated delta for pixel sensitivity tracking
|
|
264
|
+
*/
|
|
265
|
+
cumulativeDelta: number;
|
|
266
|
+
/**
|
|
267
|
+
* Whether the browser supports pointer lock (false on Safari, false during SSR)
|
|
268
|
+
*/
|
|
269
|
+
isPointerLockSupported: boolean;
|
|
270
|
+
/**
|
|
271
|
+
* The visual viewport scale (for pinch-zoom compensation on the cursor)
|
|
272
|
+
*/
|
|
273
|
+
visualScale: number;
|
|
240
274
|
}
|
|
241
275
|
interface NumberInputSchema {
|
|
242
276
|
state: "idle" | "focused" | "spinning" | "before:spin" | "scrubbing";
|
|
@@ -251,11 +285,63 @@ interface NumberInputSchema {
|
|
|
251
285
|
}
|
|
252
286
|
type NumberInputService = Service<NumberInputSchema>;
|
|
253
287
|
type NumberInputMachine = Machine<NumberInputSchema>;
|
|
288
|
+
interface RootState {
|
|
289
|
+
/**
|
|
290
|
+
* Whether the number input is disabled.
|
|
291
|
+
*/
|
|
292
|
+
disabled: boolean;
|
|
293
|
+
/**
|
|
294
|
+
* Whether the number input is focused.
|
|
295
|
+
*/
|
|
296
|
+
focused: boolean;
|
|
297
|
+
/**
|
|
298
|
+
* Whether the number input is invalid.
|
|
299
|
+
*/
|
|
300
|
+
invalid: boolean;
|
|
301
|
+
/**
|
|
302
|
+
* Whether the number input is being scrubbed.
|
|
303
|
+
*/
|
|
304
|
+
scrubbing: boolean;
|
|
305
|
+
}
|
|
306
|
+
interface InputState {
|
|
307
|
+
/**
|
|
308
|
+
* Whether the input is disabled.
|
|
309
|
+
*/
|
|
310
|
+
disabled: boolean;
|
|
311
|
+
/**
|
|
312
|
+
* Whether the input is invalid.
|
|
313
|
+
*/
|
|
314
|
+
invalid: boolean;
|
|
315
|
+
/**
|
|
316
|
+
* Whether the input is read-only.
|
|
317
|
+
*/
|
|
318
|
+
readOnly: boolean;
|
|
319
|
+
/**
|
|
320
|
+
* Whether the input is being scrubbed.
|
|
321
|
+
*/
|
|
322
|
+
scrubbing: boolean;
|
|
323
|
+
}
|
|
324
|
+
interface IncrementTriggerState {
|
|
325
|
+
/**
|
|
326
|
+
* Whether the increment trigger is disabled.
|
|
327
|
+
*/
|
|
328
|
+
disabled: boolean;
|
|
329
|
+
}
|
|
330
|
+
interface DecrementTriggerState {
|
|
331
|
+
/**
|
|
332
|
+
* Whether the decrement trigger is disabled.
|
|
333
|
+
*/
|
|
334
|
+
disabled: boolean;
|
|
335
|
+
}
|
|
254
336
|
interface NumberInputApi<T extends PropTypes = PropTypes> {
|
|
255
337
|
/**
|
|
256
338
|
* Whether the input is focused.
|
|
257
339
|
*/
|
|
258
340
|
focused: boolean;
|
|
341
|
+
/**
|
|
342
|
+
* Whether the input is being scrubbed.
|
|
343
|
+
*/
|
|
344
|
+
scrubbing: boolean;
|
|
259
345
|
/**
|
|
260
346
|
* Whether the input is invalid.
|
|
261
347
|
*/
|
|
@@ -300,14 +386,31 @@ interface NumberInputApi<T extends PropTypes = PropTypes> {
|
|
|
300
386
|
* Function to focus the input.
|
|
301
387
|
*/
|
|
302
388
|
focus: VoidFunction;
|
|
389
|
+
/**
|
|
390
|
+
* Returns the state of the root.
|
|
391
|
+
*/
|
|
392
|
+
getRootState: () => RootState;
|
|
303
393
|
getRootProps: () => T["element"];
|
|
304
394
|
getLabelProps: () => T["label"];
|
|
305
395
|
getControlProps: () => T["element"];
|
|
306
396
|
getValueTextProps: () => T["element"];
|
|
397
|
+
/**
|
|
398
|
+
* Returns the state of the input.
|
|
399
|
+
*/
|
|
400
|
+
getInputState: () => InputState;
|
|
307
401
|
getInputProps: () => T["input"];
|
|
402
|
+
/**
|
|
403
|
+
* Returns the state of the decrement trigger.
|
|
404
|
+
*/
|
|
405
|
+
getDecrementTriggerState: () => DecrementTriggerState;
|
|
308
406
|
getDecrementTriggerProps: () => T["button"];
|
|
407
|
+
/**
|
|
408
|
+
* Returns the state of the increment trigger.
|
|
409
|
+
*/
|
|
410
|
+
getIncrementTriggerState: () => IncrementTriggerState;
|
|
309
411
|
getIncrementTriggerProps: () => T["button"];
|
|
310
412
|
getScrubberProps: () => T["element"];
|
|
413
|
+
getScrubberCursorProps: () => T["element"];
|
|
311
414
|
}
|
|
312
415
|
|
|
313
|
-
export type { ElementIds, FocusChangeDetails, HintValue, InputMode, IntlTranslations, NumberInputApi, NumberInputMachine, NumberInputProps, NumberInputSchema, NumberInputService, ValidityState, ValueChangeDetails, ValueInvalidDetails };
|
|
416
|
+
export type { DecrementTriggerState, ElementIds, FocusChangeDetails, HintValue, IncrementTriggerState, InputMode, InputState, IntlTranslations, NumberInputApi, NumberInputMachine, NumberInputProps, NumberInputSchema, NumberInputService, RootState, ValidityState, ValueChangeDetails, ValueInvalidDetails };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zag-js/number-input",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.0-next.1",
|
|
4
4
|
"description": "Core logic for the number-input widget implemented as a state machine",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"js",
|
|
@@ -30,11 +30,11 @@
|
|
|
30
30
|
},
|
|
31
31
|
"dependencies": {
|
|
32
32
|
"@internationalized/number": "3.6.7",
|
|
33
|
-
"@zag-js/anatomy": "
|
|
34
|
-
"@zag-js/core": "
|
|
35
|
-
"@zag-js/dom-query": "
|
|
36
|
-
"@zag-js/types": "
|
|
37
|
-
"@zag-js/utils": "
|
|
33
|
+
"@zag-js/anatomy": "2.0.0-next.1",
|
|
34
|
+
"@zag-js/core": "2.0.0-next.1",
|
|
35
|
+
"@zag-js/dom-query": "2.0.0-next.1",
|
|
36
|
+
"@zag-js/types": "2.0.0-next.1",
|
|
37
|
+
"@zag-js/utils": "2.0.0-next.1"
|
|
38
38
|
},
|
|
39
39
|
"devDependencies": {
|
|
40
40
|
"clean-package": "2.2.0"
|