@zag-js/number-input 1.34.1 → 1.35.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.
Files changed (37) hide show
  1. package/dist/cursor.d.mts +12 -0
  2. package/dist/cursor.d.ts +12 -0
  3. package/dist/cursor.js +111 -0
  4. package/dist/cursor.mjs +84 -0
  5. package/dist/index.d.mts +9 -314
  6. package/dist/index.d.ts +9 -314
  7. package/dist/index.js +37 -931
  8. package/dist/index.mjs +9 -926
  9. package/dist/number-input.anatomy.d.mts +6 -0
  10. package/dist/number-input.anatomy.d.ts +6 -0
  11. package/dist/number-input.anatomy.js +43 -0
  12. package/dist/number-input.anatomy.mjs +17 -0
  13. package/dist/number-input.connect.d.mts +8 -0
  14. package/dist/number-input.connect.d.ts +8 -0
  15. package/dist/number-input.connect.js +308 -0
  16. package/dist/number-input.connect.mjs +284 -0
  17. package/dist/number-input.dom.d.mts +34 -0
  18. package/dist/number-input.dom.d.ts +34 -0
  19. package/dist/number-input.dom.js +150 -0
  20. package/dist/number-input.dom.mjs +109 -0
  21. package/dist/number-input.machine.d.mts +8 -0
  22. package/dist/number-input.machine.d.ts +8 -0
  23. package/dist/number-input.machine.js +460 -0
  24. package/dist/number-input.machine.mjs +441 -0
  25. package/dist/number-input.props.d.mts +9 -0
  26. package/dist/number-input.props.d.ts +9 -0
  27. package/dist/number-input.props.js +65 -0
  28. package/dist/number-input.props.mjs +39 -0
  29. package/dist/number-input.types.d.mts +303 -0
  30. package/dist/number-input.types.d.ts +303 -0
  31. package/dist/number-input.types.js +18 -0
  32. package/dist/number-input.types.mjs +0 -0
  33. package/dist/number-input.utils.d.mts +13 -0
  34. package/dist/number-input.utils.d.ts +13 -0
  35. package/dist/number-input.utils.js +63 -0
  36. package/dist/number-input.utils.mjs +34 -0
  37. package/package.json +17 -7
@@ -0,0 +1,12 @@
1
+ import { Scope } from '@zag-js/core';
2
+
3
+ interface Selection {
4
+ start: number;
5
+ end: number;
6
+ value: string;
7
+ }
8
+ declare function recordCursor(inputEl: HTMLInputElement | null, scope: Scope): Selection | undefined;
9
+ declare function restoreCursor(inputEl: HTMLInputElement | null, selection: Selection | undefined, scope: Scope): void;
10
+ declare function getNextCursorPosition(oldValue: string, newValue: string, oldPosition: number): number;
11
+
12
+ export { getNextCursorPosition, recordCursor, restoreCursor };
@@ -0,0 +1,12 @@
1
+ import { Scope } from '@zag-js/core';
2
+
3
+ interface Selection {
4
+ start: number;
5
+ end: number;
6
+ value: string;
7
+ }
8
+ declare function recordCursor(inputEl: HTMLInputElement | null, scope: Scope): Selection | undefined;
9
+ declare function restoreCursor(inputEl: HTMLInputElement | null, selection: Selection | undefined, scope: Scope): void;
10
+ declare function getNextCursorPosition(oldValue: string, newValue: string, oldPosition: number): number;
11
+
12
+ export { getNextCursorPosition, recordCursor, restoreCursor };
package/dist/cursor.js ADDED
@@ -0,0 +1,111 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/cursor.ts
21
+ var cursor_exports = {};
22
+ __export(cursor_exports, {
23
+ getNextCursorPosition: () => getNextCursorPosition,
24
+ recordCursor: () => recordCursor,
25
+ restoreCursor: () => restoreCursor
26
+ });
27
+ module.exports = __toCommonJS(cursor_exports);
28
+ function recordCursor(inputEl, scope) {
29
+ if (!inputEl || !scope.isActiveElement(inputEl)) return;
30
+ try {
31
+ const { selectionStart: start, selectionEnd: end, value } = inputEl;
32
+ if (start == null || end == null) return void 0;
33
+ return { start, end, value };
34
+ } catch {
35
+ return void 0;
36
+ }
37
+ }
38
+ function restoreCursor(inputEl, selection, scope) {
39
+ if (!inputEl || !scope.isActiveElement(inputEl)) return;
40
+ if (!selection) {
41
+ const len = inputEl.value.length;
42
+ inputEl.setSelectionRange(len, len);
43
+ return;
44
+ }
45
+ try {
46
+ const newValue = inputEl.value;
47
+ const { start, end, value: oldValue } = selection;
48
+ if (newValue === oldValue) {
49
+ inputEl.setSelectionRange(start, end);
50
+ return;
51
+ }
52
+ const newStart = getNextCursorPosition(oldValue, newValue, start);
53
+ const newEnd = start === end ? newStart : getNextCursorPosition(oldValue, newValue, end);
54
+ const clampedStart = Math.max(0, Math.min(newStart, newValue.length));
55
+ const clampedEnd = Math.max(clampedStart, Math.min(newEnd, newValue.length));
56
+ inputEl.setSelectionRange(clampedStart, clampedEnd);
57
+ } catch {
58
+ const len = inputEl.value.length;
59
+ inputEl.setSelectionRange(len, len);
60
+ }
61
+ }
62
+ function getNextCursorPosition(oldValue, newValue, oldPosition) {
63
+ const beforeCursor = oldValue.slice(0, oldPosition);
64
+ const afterCursor = oldValue.slice(oldPosition);
65
+ let prefixLength = 0;
66
+ const maxPrefixLength = Math.min(beforeCursor.length, newValue.length);
67
+ for (let i = 0; i < maxPrefixLength; i++) {
68
+ if (beforeCursor[i] === newValue[i]) {
69
+ prefixLength = i + 1;
70
+ } else {
71
+ break;
72
+ }
73
+ }
74
+ let suffixLength = 0;
75
+ const maxSuffixLength = Math.min(afterCursor.length, newValue.length - prefixLength);
76
+ for (let i = 0; i < maxSuffixLength; i++) {
77
+ const oldIndex = afterCursor.length - 1 - i;
78
+ const newIndex = newValue.length - 1 - i;
79
+ if (afterCursor[oldIndex] === newValue[newIndex]) {
80
+ suffixLength = i + 1;
81
+ } else {
82
+ break;
83
+ }
84
+ }
85
+ if (beforeCursor.length > 0 && prefixLength >= beforeCursor.length) {
86
+ return prefixLength;
87
+ }
88
+ if (suffixLength >= afterCursor.length) {
89
+ return newValue.length - suffixLength;
90
+ }
91
+ if (prefixLength > 0) {
92
+ return prefixLength;
93
+ }
94
+ if (suffixLength > 0) {
95
+ return newValue.length - suffixLength;
96
+ }
97
+ if (oldPosition === 0 && prefixLength === 0 && suffixLength === 0) {
98
+ return newValue.length;
99
+ }
100
+ if (oldValue.length > 0) {
101
+ const ratio = oldPosition / oldValue.length;
102
+ return Math.round(ratio * newValue.length);
103
+ }
104
+ return newValue.length;
105
+ }
106
+ // Annotate the CommonJS export names for ESM import in node:
107
+ 0 && (module.exports = {
108
+ getNextCursorPosition,
109
+ recordCursor,
110
+ restoreCursor
111
+ });
@@ -0,0 +1,84 @@
1
+ // src/cursor.ts
2
+ function recordCursor(inputEl, scope) {
3
+ if (!inputEl || !scope.isActiveElement(inputEl)) return;
4
+ try {
5
+ const { selectionStart: start, selectionEnd: end, value } = inputEl;
6
+ if (start == null || end == null) return void 0;
7
+ return { start, end, value };
8
+ } catch {
9
+ return void 0;
10
+ }
11
+ }
12
+ function restoreCursor(inputEl, selection, scope) {
13
+ if (!inputEl || !scope.isActiveElement(inputEl)) return;
14
+ if (!selection) {
15
+ const len = inputEl.value.length;
16
+ inputEl.setSelectionRange(len, len);
17
+ return;
18
+ }
19
+ try {
20
+ const newValue = inputEl.value;
21
+ const { start, end, value: oldValue } = selection;
22
+ if (newValue === oldValue) {
23
+ inputEl.setSelectionRange(start, end);
24
+ return;
25
+ }
26
+ const newStart = getNextCursorPosition(oldValue, newValue, start);
27
+ const newEnd = start === end ? newStart : getNextCursorPosition(oldValue, newValue, end);
28
+ const clampedStart = Math.max(0, Math.min(newStart, newValue.length));
29
+ const clampedEnd = Math.max(clampedStart, Math.min(newEnd, newValue.length));
30
+ inputEl.setSelectionRange(clampedStart, clampedEnd);
31
+ } catch {
32
+ const len = inputEl.value.length;
33
+ inputEl.setSelectionRange(len, len);
34
+ }
35
+ }
36
+ function getNextCursorPosition(oldValue, newValue, oldPosition) {
37
+ const beforeCursor = oldValue.slice(0, oldPosition);
38
+ const afterCursor = oldValue.slice(oldPosition);
39
+ let prefixLength = 0;
40
+ const maxPrefixLength = Math.min(beforeCursor.length, newValue.length);
41
+ for (let i = 0; i < maxPrefixLength; i++) {
42
+ if (beforeCursor[i] === newValue[i]) {
43
+ prefixLength = i + 1;
44
+ } else {
45
+ break;
46
+ }
47
+ }
48
+ let suffixLength = 0;
49
+ const maxSuffixLength = Math.min(afterCursor.length, newValue.length - prefixLength);
50
+ for (let i = 0; i < maxSuffixLength; i++) {
51
+ const oldIndex = afterCursor.length - 1 - i;
52
+ const newIndex = newValue.length - 1 - i;
53
+ if (afterCursor[oldIndex] === newValue[newIndex]) {
54
+ suffixLength = i + 1;
55
+ } else {
56
+ break;
57
+ }
58
+ }
59
+ if (beforeCursor.length > 0 && prefixLength >= beforeCursor.length) {
60
+ return prefixLength;
61
+ }
62
+ if (suffixLength >= afterCursor.length) {
63
+ return newValue.length - suffixLength;
64
+ }
65
+ if (prefixLength > 0) {
66
+ return prefixLength;
67
+ }
68
+ if (suffixLength > 0) {
69
+ return newValue.length - suffixLength;
70
+ }
71
+ if (oldPosition === 0 && prefixLength === 0 && suffixLength === 0) {
72
+ return newValue.length;
73
+ }
74
+ if (oldValue.length > 0) {
75
+ const ratio = oldPosition / oldValue.length;
76
+ return Math.round(ratio * newValue.length);
77
+ }
78
+ return newValue.length;
79
+ }
80
+ export {
81
+ getNextCursorPosition,
82
+ recordCursor,
83
+ restoreCursor
84
+ };
package/dist/index.d.mts CHANGED
@@ -1,314 +1,9 @@
1
- import * as _zag_js_anatomy from '@zag-js/anatomy';
2
- import { PropTypes, RequiredBy, LocaleProperties, CommonProperties, NormalizeProps } from '@zag-js/types';
3
- import { NumberFormatter, NumberParser } from '@internationalized/number';
4
- import * as _zag_js_core from '@zag-js/core';
5
- import { Machine, EventObject, Service } from '@zag-js/core';
6
-
7
- declare const anatomy: _zag_js_anatomy.AnatomyInstance<"root" | "label" | "input" | "control" | "valueText" | "incrementTrigger" | "decrementTrigger" | "scrubber">;
8
-
9
- interface ValueChangeDetails {
10
- value: string;
11
- valueAsNumber: number;
12
- }
13
- interface FocusChangeDetails extends ValueChangeDetails {
14
- focused: boolean;
15
- }
16
- type ValidityState = "rangeUnderflow" | "rangeOverflow";
17
- interface ValueInvalidDetails extends ValueChangeDetails {
18
- reason: ValidityState;
19
- }
20
- type InputMode = "text" | "tel" | "numeric" | "decimal";
21
- type ElementIds = Partial<{
22
- root: string;
23
- label: string;
24
- input: string;
25
- incrementTrigger: string;
26
- decrementTrigger: string;
27
- scrubber: string;
28
- }>;
29
- interface IntlTranslations {
30
- /**
31
- * Function that returns the human-readable value.
32
- * It is used to set the `aria-valuetext` property of the input
33
- */
34
- valueText?: ((value: string) => string) | undefined;
35
- /**
36
- * The label foe the increment button
37
- */
38
- incrementLabel?: string | undefined;
39
- /**
40
- * The label for the decrement button
41
- */
42
- decrementLabel?: string | undefined;
43
- }
44
- interface NumberInputProps extends LocaleProperties, CommonProperties {
45
- /**
46
- * The ids of the elements in the number input. Useful for composition.
47
- */
48
- ids?: ElementIds | undefined;
49
- /**
50
- * The name attribute of the number input. Useful for form submission.
51
- */
52
- name?: string | undefined;
53
- /**
54
- * The associate form of the input element.
55
- */
56
- form?: string | undefined;
57
- /**
58
- * Whether the number input is disabled.
59
- */
60
- disabled?: boolean | undefined;
61
- /**
62
- * Whether the number input is readonly
63
- */
64
- readOnly?: boolean | undefined;
65
- /**
66
- * Whether the number input value is invalid.
67
- */
68
- invalid?: boolean | undefined;
69
- /**
70
- * Whether the number input is required
71
- */
72
- required?: boolean | undefined;
73
- /**
74
- * The pattern used to check the <input> element's value against
75
- *
76
- * @default "-?[0-9]*(.[0-9]+)?"
77
- */
78
- pattern?: string | undefined;
79
- /**
80
- * The controlled value of the input
81
- */
82
- value?: string | undefined;
83
- /**
84
- * The initial value of the input when rendered.
85
- * Use when you don't need to control the value of the input.
86
- */
87
- defaultValue?: string | undefined;
88
- /**
89
- * The minimum value of the number input
90
- * @default Number.MIN_SAFE_INTEGER
91
- */
92
- min?: number | undefined;
93
- /**
94
- * The maximum value of the number input
95
- * @default Number.MAX_SAFE_INTEGER
96
- */
97
- max?: number | undefined;
98
- /**
99
- * The amount to increment or decrement the value by
100
- * @default 1
101
- */
102
- step?: number | undefined;
103
- /**
104
- * Whether to allow mouse wheel to change the value
105
- */
106
- allowMouseWheel?: boolean | undefined;
107
- /**
108
- * Whether to allow the value overflow the min/max range
109
- * @default true
110
- */
111
- allowOverflow?: boolean | undefined;
112
- /**
113
- * Whether to clamp the value when the input loses focus (blur)
114
- * @default true
115
- */
116
- clampValueOnBlur?: boolean | undefined;
117
- /**
118
- * Whether to focus input when the value changes
119
- * @default true
120
- */
121
- focusInputOnChange?: boolean | undefined;
122
- /**
123
- * Specifies the localized strings that identifies the accessibility elements and their states
124
- */
125
- translations?: IntlTranslations | undefined;
126
- /**
127
- * The options to pass to the `Intl.NumberFormat` constructor
128
- */
129
- formatOptions?: Intl.NumberFormatOptions | undefined;
130
- /**
131
- * Hints at the type of data that might be entered by the user. It also determines
132
- * the type of keyboard shown to the user on mobile devices
133
- * @default "decimal"
134
- */
135
- inputMode?: InputMode | undefined;
136
- /**
137
- * Function invoked when the value changes
138
- */
139
- onValueChange?: ((details: ValueChangeDetails) => void) | undefined;
140
- /**
141
- * Function invoked when the value overflows or underflows the min/max range
142
- */
143
- onValueInvalid?: ((details: ValueInvalidDetails) => void) | undefined;
144
- /**
145
- * Function invoked when the number input is focused
146
- */
147
- onFocusChange?: ((details: FocusChangeDetails) => void) | undefined;
148
- /**
149
- * Function invoked when the value is committed (when the input is blurred or the Enter key is pressed)
150
- */
151
- onValueCommit?: ((details: ValueChangeDetails) => void) | undefined;
152
- /**
153
- * Whether to spin the value when the increment/decrement button is pressed
154
- * @default true
155
- */
156
- spinOnPress?: boolean | undefined;
157
- }
158
- type PropsWithDefault = "dir" | "locale" | "focusInputOnChange" | "clampValueOnBlur" | "allowOverflow" | "inputMode" | "pattern" | "translations" | "step" | "spinOnPress" | "min" | "max" | "step" | "translations";
159
- type ComputedContext = Readonly<{
160
- /**
161
- * The value of the input as a number
162
- */
163
- valueAsNumber: number;
164
- /**
165
- * Whether the value is at the min
166
- */
167
- isAtMin: boolean;
168
- /**
169
- * Whether the value is at the max
170
- */
171
- isAtMax: boolean;
172
- /**
173
- * Whether the value is out of the min/max range
174
- */
175
- isOutOfRange: boolean;
176
- /**
177
- * Whether the value is empty
178
- */
179
- isValueEmpty: boolean;
180
- /**
181
- * Whether the color picker is disabled
182
- */
183
- isDisabled: boolean;
184
- /**
185
- * Whether the increment button is enabled
186
- */
187
- canIncrement: boolean;
188
- /**
189
- * Whether the decrement button is enabled
190
- */
191
- canDecrement: boolean;
192
- /**
193
- * The `aria-valuetext` attribute of the input
194
- */
195
- valueText: string | undefined;
196
- /**
197
- * The formatted value of the input
198
- */
199
- formattedValue: string;
200
- /**
201
- * Whether the writing direction is RTL
202
- */
203
- isRtl: boolean;
204
- /**
205
- * The number i18n formatter
206
- */
207
- formatter: NumberFormatter;
208
- /**
209
- * The number i18n parser
210
- */
211
- parser: NumberParser;
212
- }>;
213
- type HintValue = "increment" | "decrement";
214
- interface PrivateContext {
215
- /**
216
- * The hint that determines if we're incrementing or decrementing
217
- */
218
- hint: HintValue | null;
219
- /**
220
- * The scrubber cursor position
221
- */
222
- scrubberCursorPoint: {
223
- x: number;
224
- y: number;
225
- } | null;
226
- /**
227
- * Whether the checkbox's fieldset is disabled
228
- */
229
- fieldsetDisabled: boolean;
230
- /**
231
- * The value of the input
232
- */
233
- value: string;
234
- }
235
- interface NumberInputSchema {
236
- state: "idle" | "focused" | "spinning" | "before:spin" | "scrubbing";
237
- tag: "focus";
238
- props: RequiredBy<NumberInputProps, PropsWithDefault>;
239
- context: PrivateContext;
240
- computed: ComputedContext;
241
- action: string;
242
- event: EventObject;
243
- guard: string;
244
- effect: string;
245
- }
246
- type NumberInputService = Service<NumberInputSchema>;
247
- type NumberInputMachine = Machine<NumberInputSchema>;
248
- interface NumberInputApi<T extends PropTypes = PropTypes> {
249
- /**
250
- * Whether the input is focused.
251
- */
252
- focused: boolean;
253
- /**
254
- * Whether the input is invalid.
255
- */
256
- invalid: boolean;
257
- /**
258
- * Whether the input value is empty.
259
- */
260
- empty: boolean;
261
- /**
262
- * The formatted value of the input.
263
- */
264
- value: string;
265
- /**
266
- * The value of the input as a number.
267
- */
268
- valueAsNumber: number;
269
- /**
270
- * Function to set the value of the input.
271
- */
272
- setValue: (value: number) => void;
273
- /**
274
- * Function to clear the value of the input.
275
- */
276
- clearValue: VoidFunction;
277
- /**
278
- * Function to increment the value of the input by the step.
279
- */
280
- increment: VoidFunction;
281
- /**
282
- * Function to decrement the value of the input by the step.
283
- */
284
- decrement: VoidFunction;
285
- /**
286
- * Function to set the value of the input to the max.
287
- */
288
- setToMax: VoidFunction;
289
- /**
290
- * Function to set the value of the input to the min.
291
- */
292
- setToMin: VoidFunction;
293
- /**
294
- * Function to focus the input.
295
- */
296
- focus: VoidFunction;
297
- getRootProps: () => T["element"];
298
- getLabelProps: () => T["label"];
299
- getControlProps: () => T["element"];
300
- getValueTextProps: () => T["element"];
301
- getInputProps: () => T["input"];
302
- getDecrementTriggerProps: () => T["button"];
303
- getIncrementTriggerProps: () => T["button"];
304
- getScrubberProps: () => T["element"];
305
- }
306
-
307
- declare function connect<T extends PropTypes>(service: NumberInputService, normalize: NormalizeProps<T>): NumberInputApi<T>;
308
-
309
- declare const machine: _zag_js_core.Machine<NumberInputSchema>;
310
-
311
- declare const props: (keyof NumberInputProps)[];
312
- declare const splitProps: <Props extends Partial<NumberInputProps>>(props: Props) => [Partial<NumberInputProps>, Omit<Props, keyof NumberInputProps>];
313
-
314
- export { type NumberInputApi as Api, type ElementIds, type FocusChangeDetails, type HintValue, type InputMode, type IntlTranslations, type NumberInputMachine as Machine, type NumberInputProps as Props, type NumberInputService as Service, type ValidityState, type ValueChangeDetails, type ValueInvalidDetails, anatomy, connect, machine, props, splitProps };
1
+ export { anatomy } from './number-input.anatomy.mjs';
2
+ export { connect } from './number-input.connect.mjs';
3
+ export { machine } from './number-input.machine.mjs';
4
+ export { props, splitProps } from './number-input.props.mjs';
5
+ export { NumberInputApi as Api, ElementIds, FocusChangeDetails, HintValue, InputMode, IntlTranslations, NumberInputMachine as Machine, NumberInputProps as Props, NumberInputService as Service, ValidityState, ValueChangeDetails, ValueInvalidDetails } from './number-input.types.mjs';
6
+ import '@zag-js/anatomy';
7
+ import '@zag-js/types';
8
+ import '@zag-js/core';
9
+ import '@internationalized/number';