@zag-js/number-input 0.82.2 → 1.0.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.js CHANGED
@@ -5,6 +5,7 @@ var domQuery = require('@zag-js/dom-query');
5
5
  var utils = require('@zag-js/utils');
6
6
  var core = require('@zag-js/core');
7
7
  var number = require('@internationalized/number');
8
+ var types = require('@zag-js/types');
8
9
 
9
10
  // src/number-input.anatomy.ts
10
11
  var anatomy = anatomy$1.createAnatomy("numberInput").parts(
@@ -18,140 +19,136 @@ var anatomy = anatomy$1.createAnatomy("numberInput").parts(
18
19
  "scrubber"
19
20
  );
20
21
  var parts = anatomy.build();
21
- var dom = domQuery.createScope({
22
- getRootId: (ctx) => ctx.ids?.root ?? `number-input:${ctx.id}`,
23
- getInputId: (ctx) => ctx.ids?.input ?? `number-input:${ctx.id}:input`,
24
- getIncrementTriggerId: (ctx) => ctx.ids?.incrementTrigger ?? `number-input:${ctx.id}:inc`,
25
- getDecrementTriggerId: (ctx) => ctx.ids?.decrementTrigger ?? `number-input:${ctx.id}:dec`,
26
- getScrubberId: (ctx) => ctx.ids?.scrubber ?? `number-input:${ctx.id}:scrubber`,
27
- getCursorId: (ctx) => `number-input:${ctx.id}:cursor`,
28
- getLabelId: (ctx) => ctx.ids?.label ?? `number-input:${ctx.id}:label`,
29
- getInputEl: (ctx) => dom.getById(ctx, dom.getInputId(ctx)),
30
- getIncrementTriggerEl: (ctx) => dom.getById(ctx, dom.getIncrementTriggerId(ctx)),
31
- getDecrementTriggerEl: (ctx) => dom.getById(ctx, dom.getDecrementTriggerId(ctx)),
32
- getScrubberEl: (ctx) => dom.getById(ctx, dom.getScrubberId(ctx)),
33
- getCursorEl: (ctx) => dom.getDoc(ctx).getElementById(dom.getCursorId(ctx)),
34
- getPressedTriggerEl: (ctx, hint = ctx.hint) => {
35
- let btnEl = null;
36
- if (hint === "increment") {
37
- btnEl = dom.getIncrementTriggerEl(ctx);
22
+ var getRootId = (ctx) => ctx.ids?.root ?? `number-input:${ctx.id}`;
23
+ var getInputId = (ctx) => ctx.ids?.input ?? `number-input:${ctx.id}:input`;
24
+ var getIncrementTriggerId = (ctx) => ctx.ids?.incrementTrigger ?? `number-input:${ctx.id}:inc`;
25
+ var getDecrementTriggerId = (ctx) => ctx.ids?.decrementTrigger ?? `number-input:${ctx.id}:dec`;
26
+ var getScrubberId = (ctx) => ctx.ids?.scrubber ?? `number-input:${ctx.id}:scrubber`;
27
+ var getCursorId = (ctx) => `number-input:${ctx.id}:cursor`;
28
+ var getLabelId = (ctx) => ctx.ids?.label ?? `number-input:${ctx.id}:label`;
29
+ var getInputEl = (ctx) => ctx.getById(getInputId(ctx));
30
+ var getIncrementTriggerEl = (ctx) => ctx.getById(getIncrementTriggerId(ctx));
31
+ var getDecrementTriggerEl = (ctx) => ctx.getById(getDecrementTriggerId(ctx));
32
+ var getCursorEl = (ctx) => ctx.getDoc().getElementById(getCursorId(ctx));
33
+ var getPressedTriggerEl = (ctx, hint) => {
34
+ let btnEl = null;
35
+ if (hint === "increment") {
36
+ btnEl = getIncrementTriggerEl(ctx);
37
+ }
38
+ if (hint === "decrement") {
39
+ btnEl = getDecrementTriggerEl(ctx);
40
+ }
41
+ return btnEl;
42
+ };
43
+ var setupVirtualCursor = (ctx, point) => {
44
+ if (domQuery.isSafari()) return;
45
+ createVirtualCursor(ctx, point);
46
+ return () => {
47
+ getCursorEl(ctx)?.remove();
48
+ };
49
+ };
50
+ var preventTextSelection = (ctx) => {
51
+ const doc = ctx.getDoc();
52
+ const html = doc.documentElement;
53
+ const body = doc.body;
54
+ body.style.pointerEvents = "none";
55
+ html.style.userSelect = "none";
56
+ html.style.cursor = "ew-resize";
57
+ return () => {
58
+ body.style.pointerEvents = "";
59
+ html.style.userSelect = "";
60
+ html.style.cursor = "";
61
+ if (!html.style.length) {
62
+ html.removeAttribute("style");
38
63
  }
39
- if (hint === "decrement") {
40
- btnEl = dom.getDecrementTriggerEl(ctx);
64
+ if (!body.style.length) {
65
+ body.removeAttribute("style");
41
66
  }
42
- return btnEl;
43
- },
44
- setupVirtualCursor(ctx) {
45
- if (domQuery.isSafari()) return;
46
- dom.createVirtualCursor(ctx);
47
- return () => {
48
- dom.getCursorEl(ctx)?.remove();
49
- };
50
- },
51
- preventTextSelection(ctx) {
52
- const doc = dom.getDoc(ctx);
53
- const html = doc.documentElement;
54
- const body = doc.body;
55
- body.style.pointerEvents = "none";
56
- html.style.userSelect = "none";
57
- html.style.cursor = "ew-resize";
58
- return () => {
59
- body.style.pointerEvents = "";
60
- html.style.userSelect = "";
61
- html.style.cursor = "";
62
- if (!html.style.length) {
63
- html.removeAttribute("style");
64
- }
65
- if (!body.style.length) {
66
- body.removeAttribute("style");
67
- }
68
- };
69
- },
70
- getMousemoveValue(ctx, event) {
71
- const win = dom.getWin(ctx);
72
- const x = utils.roundToDpr(event.movementX, win.devicePixelRatio);
73
- const y = utils.roundToDpr(event.movementY, win.devicePixelRatio);
74
- let hint = x > 0 ? "increment" : x < 0 ? "decrement" : null;
75
- if (ctx.isRtl && hint === "increment") hint = "decrement";
76
- if (ctx.isRtl && hint === "decrement") hint = "increment";
77
- const point = {
78
- x: ctx.scrubberCursorPoint.x + x,
79
- y: ctx.scrubberCursorPoint.y + y
80
- };
81
- const width = win.innerWidth;
82
- const half = utils.roundToDpr(7.5, win.devicePixelRatio);
83
- point.x = utils.wrap(point.x + half, width) - half;
84
- return { hint, point };
85
- },
86
- createVirtualCursor(ctx) {
87
- const doc = dom.getDoc(ctx);
88
- const el = doc.createElement("div");
89
- el.className = "scrubber--cursor";
90
- el.id = dom.getCursorId(ctx);
91
- Object.assign(el.style, {
92
- width: "15px",
93
- height: "15px",
94
- position: "fixed",
95
- pointerEvents: "none",
96
- left: "0px",
97
- top: "0px",
98
- zIndex: domQuery.MAX_Z_INDEX,
99
- transform: ctx.scrubberCursorPoint ? `translate3d(${ctx.scrubberCursorPoint.x}px, ${ctx.scrubberCursorPoint.y}px, 0px)` : void 0,
100
- willChange: "transform"
101
- });
102
- el.innerHTML = `
103
- <svg width="46" height="15" style="left: -15.5px; position: absolute; top: 0; filter: drop-shadow(rgba(0, 0, 0, 0.4) 0px 1px 1.1px);">
104
- <g transform="translate(2 3)">
105
- <path fill-rule="evenodd" d="M 15 4.5L 15 2L 11.5 5.5L 15 9L 15 6.5L 31 6.5L 31 9L 34.5 5.5L 31 2L 31 4.5Z" style="stroke-width: 2px; stroke: white;"></path>
106
- <path fill-rule="evenodd" d="M 15 4.5L 15 2L 11.5 5.5L 15 9L 15 6.5L 31 6.5L 31 9L 34.5 5.5L 31 2L 31 4.5Z"></path>
107
- </g>
108
- </svg>`;
109
- doc.body.appendChild(el);
110
- }
111
- });
67
+ };
68
+ };
69
+ var getMousemoveValue = (ctx, opts) => {
70
+ const { point, isRtl, event } = opts;
71
+ const win = ctx.getWin();
72
+ const x = utils.roundToDpr(event.movementX, win.devicePixelRatio);
73
+ const y = utils.roundToDpr(event.movementY, win.devicePixelRatio);
74
+ let hint = x > 0 ? "increment" : x < 0 ? "decrement" : null;
75
+ if (isRtl && hint === "increment") hint = "decrement";
76
+ if (isRtl && hint === "decrement") hint = "increment";
77
+ const newPoint = { x: point.x + x, y: point.y + y };
78
+ const width = win.innerWidth;
79
+ const half = utils.roundToDpr(7.5, win.devicePixelRatio);
80
+ newPoint.x = utils.wrap(newPoint.x + half, width) - half;
81
+ return { hint, point: newPoint };
82
+ };
83
+ var createVirtualCursor = (ctx, point) => {
84
+ const doc = ctx.getDoc();
85
+ const el = doc.createElement("div");
86
+ el.className = "scrubber--cursor";
87
+ el.id = getCursorId(ctx);
88
+ Object.assign(el.style, {
89
+ width: "15px",
90
+ height: "15px",
91
+ position: "fixed",
92
+ pointerEvents: "none",
93
+ left: "0px",
94
+ top: "0px",
95
+ zIndex: domQuery.MAX_Z_INDEX,
96
+ transform: point ? `translate3d(${point.x}px, ${point.y}px, 0px)` : void 0,
97
+ willChange: "transform"
98
+ });
99
+ el.innerHTML = `
100
+ <svg width="46" height="15" style="left: -15.5px; position: absolute; top: 0; filter: drop-shadow(rgba(0, 0, 0, 0.4) 0px 1px 1.1px);">
101
+ <g transform="translate(2 3)">
102
+ <path fill-rule="evenodd" d="M 15 4.5L 15 2L 11.5 5.5L 15 9L 15 6.5L 31 6.5L 31 9L 34.5 5.5L 31 2L 31 4.5Z" style="stroke-width: 2px; stroke: white;"></path>
103
+ <path fill-rule="evenodd" d="M 15 4.5L 15 2L 11.5 5.5L 15 9L 15 6.5L 31 6.5L 31 9L 34.5 5.5L 31 2L 31 4.5Z"></path>
104
+ </g>
105
+ </svg>`;
106
+ doc.body.appendChild(el);
107
+ };
112
108
 
113
109
  // src/number-input.connect.ts
114
- function connect(state, send, normalize) {
110
+ function connect(service, normalize) {
111
+ const { state, send, prop, scope, computed } = service;
115
112
  const focused = state.hasTag("focus");
116
- const disabled = state.context.isDisabled;
117
- const readOnly = state.context.readOnly;
118
- const empty = state.context.isValueEmpty;
119
- const invalid = state.context.isOutOfRange || !!state.context.invalid;
120
- const isIncrementDisabled = disabled || !state.context.canIncrement || readOnly;
121
- const isDecrementDisabled = disabled || !state.context.canDecrement || readOnly;
122
- const translations = state.context.translations;
113
+ const disabled = computed("isDisabled");
114
+ const readOnly = prop("readOnly");
115
+ const empty = computed("isValueEmpty");
116
+ const invalid = computed("isOutOfRange") || !!prop("invalid");
117
+ const isIncrementDisabled = disabled || !computed("canIncrement") || readOnly;
118
+ const isDecrementDisabled = disabled || !computed("canDecrement") || readOnly;
119
+ const translations = prop("translations");
123
120
  return {
124
121
  focused,
125
122
  invalid,
126
123
  empty,
127
- value: state.context.formattedValue,
128
- valueAsNumber: state.context.valueAsNumber,
124
+ value: computed("formattedValue"),
125
+ valueAsNumber: computed("valueAsNumber"),
129
126
  setValue(value) {
130
127
  send({ type: "VALUE.SET", value });
131
128
  },
132
129
  clearValue() {
133
- send("VALUE.CLEAR");
130
+ send({ type: "VALUE.CLEAR" });
134
131
  },
135
132
  increment() {
136
- send("VALUE.INCREMENT");
133
+ send({ type: "VALUE.INCREMENT" });
137
134
  },
138
135
  decrement() {
139
- send("VALUE.DECREMENT");
136
+ send({ type: "VALUE.DECREMENT" });
140
137
  },
141
138
  setToMax() {
142
- send({ type: "VALUE.SET", value: state.context.max });
139
+ send({ type: "VALUE.SET", value: prop("max") });
143
140
  },
144
141
  setToMin() {
145
- send({ type: "VALUE.SET", value: state.context.min });
142
+ send({ type: "VALUE.SET", value: prop("min") });
146
143
  },
147
144
  focus() {
148
- dom.getInputEl(state.context)?.focus();
145
+ getInputEl(scope)?.focus();
149
146
  },
150
147
  getRootProps() {
151
148
  return normalize.element({
152
- id: dom.getRootId(state.context),
149
+ id: getRootId(scope),
153
150
  ...parts.root.attrs,
154
- dir: state.context.dir,
151
+ dir: prop("dir"),
155
152
  "data-disabled": domQuery.dataAttr(disabled),
156
153
  "data-focus": domQuery.dataAttr(focused),
157
154
  "data-invalid": domQuery.dataAttr(invalid)
@@ -160,30 +157,30 @@ function connect(state, send, normalize) {
160
157
  getLabelProps() {
161
158
  return normalize.label({
162
159
  ...parts.label.attrs,
163
- dir: state.context.dir,
160
+ dir: prop("dir"),
164
161
  "data-disabled": domQuery.dataAttr(disabled),
165
162
  "data-focus": domQuery.dataAttr(focused),
166
163
  "data-invalid": domQuery.dataAttr(invalid),
167
- id: dom.getLabelId(state.context),
168
- htmlFor: dom.getInputId(state.context)
164
+ id: getLabelId(scope),
165
+ htmlFor: getInputId(scope)
169
166
  });
170
167
  },
171
168
  getControlProps() {
172
169
  return normalize.element({
173
170
  ...parts.control.attrs,
174
- dir: state.context.dir,
171
+ dir: prop("dir"),
175
172
  role: "group",
176
173
  "aria-disabled": disabled,
177
174
  "data-focus": domQuery.dataAttr(focused),
178
175
  "data-disabled": domQuery.dataAttr(disabled),
179
176
  "data-invalid": domQuery.dataAttr(invalid),
180
- "aria-invalid": domQuery.ariaAttr(state.context.invalid)
177
+ "aria-invalid": domQuery.ariaAttr(invalid)
181
178
  });
182
179
  },
183
180
  getValueTextProps() {
184
181
  return normalize.element({
185
182
  ...parts.valueText.attrs,
186
- dir: state.context.dir,
183
+ dir: prop("dir"),
187
184
  "data-disabled": domQuery.dataAttr(disabled),
188
185
  "data-invalid": domQuery.dataAttr(invalid),
189
186
  "data-focus": domQuery.dataAttr(focused)
@@ -192,34 +189,34 @@ function connect(state, send, normalize) {
192
189
  getInputProps() {
193
190
  return normalize.input({
194
191
  ...parts.input.attrs,
195
- dir: state.context.dir,
196
- name: state.context.name,
197
- form: state.context.form,
198
- id: dom.getInputId(state.context),
192
+ dir: prop("dir"),
193
+ name: prop("name"),
194
+ form: prop("form"),
195
+ id: getInputId(scope),
199
196
  role: "spinbutton",
200
- defaultValue: state.context.formattedValue,
201
- pattern: state.context.pattern,
202
- inputMode: state.context.inputMode,
197
+ defaultValue: computed("formattedValue"),
198
+ pattern: prop("pattern"),
199
+ inputMode: prop("inputMode"),
203
200
  "aria-invalid": domQuery.ariaAttr(invalid),
204
201
  "data-invalid": domQuery.dataAttr(invalid),
205
202
  disabled,
206
203
  "data-disabled": domQuery.dataAttr(disabled),
207
- readOnly: state.context.readOnly,
208
- required: state.context.required,
204
+ readOnly,
205
+ required: prop("required"),
209
206
  autoComplete: "off",
210
207
  autoCorrect: "off",
211
208
  spellCheck: "false",
212
209
  type: "text",
213
210
  "aria-roledescription": "numberfield",
214
- "aria-valuemin": state.context.min,
215
- "aria-valuemax": state.context.max,
216
- "aria-valuenow": Number.isNaN(state.context.valueAsNumber) ? void 0 : state.context.valueAsNumber,
217
- "aria-valuetext": state.context.valueText,
211
+ "aria-valuemin": prop("min"),
212
+ "aria-valuemax": prop("max"),
213
+ "aria-valuenow": Number.isNaN(computed("valueAsNumber")) ? void 0 : computed("valueAsNumber"),
214
+ "aria-valuetext": computed("valueText"),
218
215
  onFocus() {
219
- send("INPUT.FOCUS");
216
+ send({ type: "INPUT.FOCUS" });
220
217
  },
221
218
  onBlur() {
222
- send("INPUT.BLUR");
219
+ send({ type: "INPUT.BLUR" });
223
220
  },
224
221
  onInput(event) {
225
222
  send({ type: "INPUT.CHANGE", target: event.currentTarget, hint: "set" });
@@ -228,7 +225,7 @@ function connect(state, send, normalize) {
228
225
  try {
229
226
  const { selectionStart, selectionEnd, value } = event.currentTarget;
230
227
  const nextValue = value.slice(0, selectionStart) + (event.data ?? "") + value.slice(selectionEnd);
231
- const isValid = state.context.parser.isValidPartialNumber(nextValue);
228
+ const isValid = computed("parser").isValidPartialNumber(nextValue);
232
229
  if (!isValid) {
233
230
  event.preventDefault();
234
231
  }
@@ -239,7 +236,7 @@ function connect(state, send, normalize) {
239
236
  if (event.defaultPrevented) return;
240
237
  if (readOnly) return;
241
238
  if (domQuery.isComposingEvent(event)) return;
242
- const step = domQuery.getEventStep(event) * state.context.step;
239
+ const step = domQuery.getEventStep(event) * prop("step");
243
240
  const keyMap = {
244
241
  ArrowUp() {
245
242
  send({ type: "INPUT.ARROW_UP", step });
@@ -251,16 +248,16 @@ function connect(state, send, normalize) {
251
248
  },
252
249
  Home() {
253
250
  if (domQuery.isModifierKey(event)) return;
254
- send("INPUT.HOME");
251
+ send({ type: "INPUT.HOME" });
255
252
  event.preventDefault();
256
253
  },
257
254
  End() {
258
255
  if (domQuery.isModifierKey(event)) return;
259
- send("INPUT.END");
256
+ send({ type: "INPUT.END" });
260
257
  event.preventDefault();
261
258
  },
262
259
  Enter() {
263
- send("INPUT.ENTER");
260
+ send({ type: "INPUT.ENTER" });
264
261
  }
265
262
  };
266
263
  const exec = keyMap[event.key];
@@ -271,14 +268,14 @@ function connect(state, send, normalize) {
271
268
  getDecrementTriggerProps() {
272
269
  return normalize.button({
273
270
  ...parts.decrementTrigger.attrs,
274
- dir: state.context.dir,
275
- id: dom.getDecrementTriggerId(state.context),
271
+ dir: prop("dir"),
272
+ id: getDecrementTriggerId(scope),
276
273
  disabled: isDecrementDisabled,
277
274
  "data-disabled": domQuery.dataAttr(isDecrementDisabled),
278
275
  "aria-label": translations.decrementLabel,
279
276
  type: "button",
280
277
  tabIndex: -1,
281
- "aria-controls": dom.getInputId(state.context),
278
+ "aria-controls": getInputId(scope),
282
279
  onPointerDown(event) {
283
280
  if (isDecrementDisabled || !domQuery.isLeftClick(event)) return;
284
281
  send({ type: "TRIGGER.PRESS_DOWN", hint: "decrement", pointerType: event.pointerType });
@@ -301,14 +298,14 @@ function connect(state, send, normalize) {
301
298
  getIncrementTriggerProps() {
302
299
  return normalize.button({
303
300
  ...parts.incrementTrigger.attrs,
304
- dir: state.context.dir,
305
- id: dom.getIncrementTriggerId(state.context),
301
+ dir: prop("dir"),
302
+ id: getIncrementTriggerId(scope),
306
303
  disabled: isIncrementDisabled,
307
304
  "data-disabled": domQuery.dataAttr(isIncrementDisabled),
308
305
  "aria-label": translations.incrementLabel,
309
306
  type: "button",
310
307
  tabIndex: -1,
311
- "aria-controls": dom.getInputId(state.context),
308
+ "aria-controls": getInputId(scope),
312
309
  onPointerDown(event) {
313
310
  if (isIncrementDisabled || !domQuery.isLeftClick(event)) return;
314
311
  send({ type: "TRIGGER.PRESS_DOWN", hint: "increment", pointerType: event.pointerType });
@@ -330,9 +327,9 @@ function connect(state, send, normalize) {
330
327
  getScrubberProps() {
331
328
  return normalize.element({
332
329
  ...parts.scrubber.attrs,
333
- dir: state.context.dir,
330
+ dir: prop("dir"),
334
331
  "data-disabled": domQuery.dataAttr(disabled),
335
- id: dom.getScrubberId(state.context),
332
+ id: getScrubberId(scope),
336
333
  role: "presentation",
337
334
  onMouseDown(event) {
338
335
  if (disabled) return;
@@ -354,7 +351,7 @@ function connect(state, send, normalize) {
354
351
 
355
352
  // src/cursor.ts
356
353
  function recordCursor(inputEl) {
357
- if (inputEl.ownerDocument.activeElement !== inputEl) return;
354
+ if (!inputEl || inputEl.ownerDocument.activeElement !== inputEl) return;
358
355
  try {
359
356
  const { selectionStart: start, selectionEnd: end, value } = inputEl;
360
357
  const beforeTxt = value.substring(0, start);
@@ -370,7 +367,7 @@ function recordCursor(inputEl) {
370
367
  }
371
368
  }
372
369
  function restoreCursor(inputEl, selection) {
373
- if (inputEl.ownerDocument.activeElement !== inputEl) return;
370
+ if (!inputEl || inputEl.ownerDocument.activeElement !== inputEl) return;
374
371
  if (!selection) {
375
372
  inputEl.setSelectionRange(inputEl.value.length, inputEl.value.length);
376
373
  return;
@@ -395,432 +392,464 @@ function restoreCursor(inputEl, selection) {
395
392
  }
396
393
  }
397
394
  var createFormatter = (locale, options = {}) => {
398
- return core.ref(new Intl.NumberFormat(locale, options));
395
+ return new Intl.NumberFormat(locale, options);
399
396
  };
400
397
  var createParser = (locale, options = {}) => {
401
- return core.ref(new number.NumberParser(locale, options));
398
+ return new number.NumberParser(locale, options);
402
399
  };
403
- var parseValue = (ctx, value) => {
404
- if (!ctx.formatOptions) return parseFloat(value);
405
- return ctx.parser.parse(String(value));
400
+ var parseValue = (value, params) => {
401
+ const { prop, computed } = params;
402
+ if (!prop("formatOptions")) return parseFloat(value);
403
+ return computed("parser").parse(String(value));
406
404
  };
407
- var formatValue = (ctx, value) => {
405
+ var formatValue = (value, params) => {
406
+ const { prop, computed } = params;
408
407
  if (Number.isNaN(value)) return "";
409
- if (!ctx.formatOptions) return value.toString();
410
- return ctx.formatter.format(value);
408
+ if (!prop("formatOptions")) return value.toString();
409
+ return computed("formatter").format(value);
411
410
  };
412
411
 
413
412
  // src/number-input.machine.ts
414
- var { not, and } = core.guards;
415
- function machine(userContext) {
416
- const ctx = utils.compact(userContext);
417
- return core.createMachine(
418
- {
419
- id: "number-input",
420
- initial: "idle",
421
- context: {
422
- dir: "ltr",
423
- locale: "en-US",
424
- focusInputOnChange: true,
425
- clampValueOnBlur: true,
426
- allowOverflow: false,
427
- inputMode: "decimal",
428
- pattern: "[0-9]*(.[0-9]+)?",
429
- value: "",
430
- step: 1,
431
- min: Number.MIN_SAFE_INTEGER,
432
- max: Number.MAX_SAFE_INTEGER,
433
- invalid: false,
434
- spinOnPress: true,
435
- disabled: false,
436
- readOnly: false,
437
- ...ctx,
438
- hint: null,
439
- scrubberCursorPoint: null,
440
- fieldsetDisabled: false,
441
- formatter: createFormatter(ctx.locale || "en-US", ctx.formatOptions),
442
- parser: createParser(ctx.locale || "en-US", ctx.formatOptions),
443
- translations: {
444
- incrementLabel: "increment value",
445
- decrementLabel: "decrease value",
446
- ...ctx.translations
413
+ var { choose, guards, createMachine } = core.setup();
414
+ var { not, and } = guards;
415
+ var machine = createMachine({
416
+ props({ props: props2 }) {
417
+ return {
418
+ dir: "ltr",
419
+ locale: "en-US",
420
+ focusInputOnChange: true,
421
+ clampValueOnBlur: true,
422
+ allowOverflow: false,
423
+ inputMode: "decimal",
424
+ pattern: "[0-9]*(.[0-9]+)?",
425
+ defaultValue: "",
426
+ step: 1,
427
+ min: Number.MIN_SAFE_INTEGER,
428
+ max: Number.MAX_SAFE_INTEGER,
429
+ spinOnPress: true,
430
+ ...utils.compact(props2),
431
+ translations: {
432
+ incrementLabel: "increment value",
433
+ decrementLabel: "decrease value",
434
+ ...props2.translations
435
+ }
436
+ };
437
+ },
438
+ initialState() {
439
+ return "idle";
440
+ },
441
+ context({ prop, bindable, getComputed }) {
442
+ return {
443
+ value: bindable(() => ({
444
+ defaultValue: prop("defaultValue"),
445
+ prop: prop("value"),
446
+ onChange(value) {
447
+ const computed = getComputed();
448
+ prop("onValueChange")?.({ value, valueAsNumber: computed("valueAsNumber") });
447
449
  }
448
- },
449
- computed: {
450
- isRtl: (ctx2) => ctx2.dir === "rtl",
451
- valueAsNumber: (ctx2) => parseValue(ctx2, ctx2.value),
452
- formattedValue: (ctx2) => formatValue(ctx2, ctx2.valueAsNumber),
453
- isAtMin: (ctx2) => utils.isValueAtMin(ctx2.valueAsNumber, ctx2.min),
454
- isAtMax: (ctx2) => utils.isValueAtMax(ctx2.valueAsNumber, ctx2.max),
455
- isOutOfRange: (ctx2) => !utils.isValueWithinRange(ctx2.valueAsNumber, ctx2.min, ctx2.max),
456
- isValueEmpty: (ctx2) => ctx2.value === "",
457
- isDisabled: (ctx2) => !!ctx2.disabled || ctx2.fieldsetDisabled,
458
- canIncrement: (ctx2) => ctx2.allowOverflow || !ctx2.isAtMax,
459
- canDecrement: (ctx2) => ctx2.allowOverflow || !ctx2.isAtMin,
460
- valueText: (ctx2) => ctx2.translations.valueText?.(ctx2.value)
461
- },
462
- watch: {
463
- formatOptions: ["setFormatterAndParser", "syncInputElement"],
464
- locale: ["setFormatterAndParser", "syncInputElement"],
465
- value: ["syncInputElement"],
466
- isOutOfRange: ["invokeOnInvalid"],
467
- scrubberCursorPoint: ["setVirtualCursorPosition"]
468
- },
469
- activities: ["trackFormControl"],
450
+ })),
451
+ hint: bindable(() => ({ defaultValue: null })),
452
+ scrubberCursorPoint: bindable(() => ({
453
+ defaultValue: null,
454
+ hash(value) {
455
+ return value ? `x:${value.x}, y:${value.y}` : "";
456
+ }
457
+ })),
458
+ fieldsetDisabled: bindable(() => ({ defaultValue: false }))
459
+ };
460
+ },
461
+ computed: {
462
+ isRtl: ({ prop }) => prop("dir") === "rtl",
463
+ valueAsNumber: ({ context, computed, prop }) => parseValue(context.get("value"), { computed, prop }),
464
+ formattedValue: ({ computed, prop }) => formatValue(computed("valueAsNumber"), { computed, prop }),
465
+ isAtMin: ({ computed, prop }) => utils.isValueAtMin(computed("valueAsNumber"), prop("min")),
466
+ isAtMax: ({ computed, prop }) => utils.isValueAtMax(computed("valueAsNumber"), prop("max")),
467
+ isOutOfRange: ({ computed, prop }) => !utils.isValueWithinRange(computed("valueAsNumber"), prop("min"), prop("max")),
468
+ isValueEmpty: ({ context }) => context.get("value") === "",
469
+ isDisabled: ({ prop, context }) => !!prop("disabled") || context.get("fieldsetDisabled"),
470
+ canIncrement: ({ prop, computed }) => prop("allowOverflow") || !computed("isAtMax"),
471
+ canDecrement: ({ prop, computed }) => prop("allowOverflow") || !computed("isAtMin"),
472
+ valueText: ({ prop, context }) => prop("translations").valueText?.(context.get("value")),
473
+ formatter: core.memo(
474
+ ({ prop }) => [prop("locale"), prop("formatOptions")],
475
+ (locale, formatOptions) => createFormatter(locale, formatOptions)
476
+ ),
477
+ parser: core.memo(
478
+ ({ prop }) => [prop("locale"), prop("formatOptions")],
479
+ (locale, formatOptions) => createParser(locale, formatOptions)
480
+ )
481
+ },
482
+ watch({ track, action, context, computed, prop }) {
483
+ track([() => context.get("value"), () => prop("locale")], () => {
484
+ action(["syncInputElement"]);
485
+ });
486
+ track([() => computed("isOutOfRange")], () => {
487
+ action(["invokeOnInvalid"]);
488
+ });
489
+ track([() => context.hash("scrubberCursorPoint")], () => {
490
+ action(["setVirtualCursorPosition"]);
491
+ });
492
+ },
493
+ effects: ["trackFormControl"],
494
+ on: {
495
+ "VALUE.SET": {
496
+ actions: ["setRawValue", "setHintToSet"]
497
+ },
498
+ "VALUE.CLEAR": {
499
+ actions: ["clearValue"]
500
+ },
501
+ "VALUE.INCREMENT": {
502
+ actions: ["increment"]
503
+ },
504
+ "VALUE.DECREMENT": {
505
+ actions: ["decrement"]
506
+ }
507
+ },
508
+ states: {
509
+ idle: {
470
510
  on: {
471
- "VALUE.SET": {
472
- actions: ["setRawValue", "setHintToSet"]
473
- },
474
- "VALUE.CLEAR": {
475
- actions: ["clearValue"]
476
- },
477
- "VALUE.INCREMENT": {
511
+ "TRIGGER.PRESS_DOWN": [
512
+ { guard: "isTouchPointer", target: "before:spin", actions: ["setHint"] },
513
+ {
514
+ target: "before:spin",
515
+ actions: ["focusInput", "invokeOnFocus", "setHint"]
516
+ }
517
+ ],
518
+ "SCRUBBER.PRESS_DOWN": {
519
+ target: "scrubbing",
520
+ actions: ["focusInput", "invokeOnFocus", "setHint", "setCursorPoint"]
521
+ },
522
+ "INPUT.FOCUS": {
523
+ target: "focused",
524
+ actions: ["focusInput", "invokeOnFocus"]
525
+ }
526
+ }
527
+ },
528
+ focused: {
529
+ tags: ["focus"],
530
+ effects: ["attachWheelListener"],
531
+ on: {
532
+ "TRIGGER.PRESS_DOWN": [
533
+ { guard: "isTouchPointer", target: "before:spin", actions: ["setHint"] },
534
+ { target: "before:spin", actions: ["focusInput", "setHint"] }
535
+ ],
536
+ "SCRUBBER.PRESS_DOWN": {
537
+ target: "scrubbing",
538
+ actions: ["focusInput", "setHint", "setCursorPoint"]
539
+ },
540
+ "INPUT.ARROW_UP": {
478
541
  actions: ["increment"]
479
542
  },
480
- "VALUE.DECREMENT": {
543
+ "INPUT.ARROW_DOWN": {
481
544
  actions: ["decrement"]
482
- }
483
- },
484
- states: {
485
- idle: {
486
- on: {
487
- "TRIGGER.PRESS_DOWN": [
488
- { guard: "isTouchPointer", target: "before:spin", actions: ["setHint"] },
489
- {
490
- target: "before:spin",
491
- actions: ["focusInput", "invokeOnFocus", "setHint"]
492
- }
493
- ],
494
- "SCRUBBER.PRESS_DOWN": {
495
- target: "scrubbing",
496
- actions: ["focusInput", "invokeOnFocus", "setHint", "setCursorPoint"]
497
- },
498
- "INPUT.FOCUS": {
499
- target: "focused",
500
- actions: ["focusInput", "invokeOnFocus"]
501
- }
502
- }
503
545
  },
504
- focused: {
505
- tags: "focus",
506
- activities: "attachWheelListener",
507
- on: {
508
- "TRIGGER.PRESS_DOWN": [
509
- { guard: "isTouchPointer", target: "before:spin", actions: ["setHint"] },
510
- { target: "before:spin", actions: ["focusInput", "setHint"] }
511
- ],
512
- "SCRUBBER.PRESS_DOWN": {
513
- target: "scrubbing",
514
- actions: ["focusInput", "setHint", "setCursorPoint"]
515
- },
516
- "INPUT.ARROW_UP": {
517
- actions: "increment"
518
- },
519
- "INPUT.ARROW_DOWN": {
520
- actions: "decrement"
521
- },
522
- "INPUT.HOME": {
523
- actions: "decrementToMin"
524
- },
525
- "INPUT.END": {
526
- actions: "incrementToMax"
527
- },
528
- "INPUT.CHANGE": {
529
- actions: ["setValue", "setHint"]
530
- },
531
- "INPUT.BLUR": [
532
- {
533
- guard: and("clampValueOnBlur", not("isInRange")),
534
- target: "idle",
535
- actions: ["setClampedValue", "clearHint", "invokeOnBlur"]
536
- },
537
- {
538
- target: "idle",
539
- actions: ["setFormattedValue", "clearHint", "invokeOnBlur"]
540
- }
541
- ],
542
- "INPUT.ENTER": {
543
- actions: ["setFormattedValue", "clearHint", "invokeOnBlur"]
544
- }
545
- }
546
+ "INPUT.HOME": {
547
+ actions: ["decrementToMin"]
546
548
  },
547
- "before:spin": {
548
- tags: "focus",
549
- activities: "trackButtonDisabled",
550
- entry: core.choose([
551
- { guard: "isIncrementHint", actions: "increment" },
552
- { guard: "isDecrementHint", actions: "decrement" }
553
- ]),
554
- after: {
555
- CHANGE_DELAY: {
556
- target: "spinning",
557
- guard: and("isInRange", "spinOnPress")
558
- }
559
- },
560
- on: {
561
- "TRIGGER.PRESS_UP": [
562
- { guard: "isTouchPointer", target: "focused", actions: "clearHint" },
563
- { target: "focused", actions: ["focusInput", "clearHint"] }
564
- ]
565
- }
549
+ "INPUT.END": {
550
+ actions: ["incrementToMax"]
566
551
  },
567
- spinning: {
568
- tags: "focus",
569
- activities: "trackButtonDisabled",
570
- every: [
571
- {
572
- delay: "CHANGE_INTERVAL",
573
- guard: and(not("isAtMin"), "isIncrementHint"),
574
- actions: "increment"
575
- },
576
- {
577
- delay: "CHANGE_INTERVAL",
578
- guard: and(not("isAtMax"), "isDecrementHint"),
579
- actions: "decrement"
580
- }
581
- ],
582
- on: {
583
- "TRIGGER.PRESS_UP": {
584
- target: "focused",
585
- actions: ["focusInput", "clearHint"]
586
- }
587
- }
552
+ "INPUT.CHANGE": {
553
+ actions: ["setValue", "setHint"]
588
554
  },
589
- scrubbing: {
590
- tags: "focus",
591
- activities: ["activatePointerLock", "trackMousemove", "setupVirtualCursor", "preventTextSelection"],
592
- on: {
593
- "SCRUBBER.POINTER_UP": {
594
- target: "focused",
595
- actions: ["focusInput", "clearCursorPoint"]
596
- },
597
- "SCRUBBER.POINTER_MOVE": [
598
- {
599
- guard: "isIncrementHint",
600
- actions: ["increment", "setCursorPoint"]
601
- },
602
- {
603
- guard: "isDecrementHint",
604
- actions: ["decrement", "setCursorPoint"]
605
- }
606
- ]
555
+ "INPUT.BLUR": [
556
+ {
557
+ guard: and("clampValueOnBlur", not("isInRange")),
558
+ target: "idle",
559
+ actions: ["setClampedValue", "clearHint", "invokeOnBlur"]
560
+ },
561
+ {
562
+ target: "idle",
563
+ actions: ["setFormattedValue", "clearHint", "invokeOnBlur"]
564
+ }
565
+ ],
566
+ "INPUT.ENTER": {
567
+ actions: ["setFormattedValue", "clearHint", "invokeOnBlur"]
568
+ }
569
+ }
570
+ },
571
+ "before:spin": {
572
+ tags: ["focus"],
573
+ effects: ["trackButtonDisabled", "waitForChangeDelay"],
574
+ entry: choose([
575
+ { guard: "isIncrementHint", actions: ["increment"] },
576
+ { guard: "isDecrementHint", actions: ["decrement"] }
577
+ ]),
578
+ on: {
579
+ CHANGE_DELAY: {
580
+ target: "spinning",
581
+ guard: and("isInRange", "spinOnPress")
582
+ },
583
+ "TRIGGER.PRESS_UP": [
584
+ { guard: "isTouchPointer", target: "focused", actions: ["clearHint"] },
585
+ { target: "focused", actions: ["focusInput", "clearHint"] }
586
+ ]
587
+ }
588
+ },
589
+ spinning: {
590
+ tags: ["focus"],
591
+ effects: ["trackButtonDisabled", "spinValue"],
592
+ on: {
593
+ SPIN: [
594
+ {
595
+ guard: and(not("isAtMin"), "isIncrementHint"),
596
+ actions: ["increment"]
597
+ },
598
+ {
599
+ guard: and(not("isAtMax"), "isDecrementHint"),
600
+ actions: ["decrement"]
607
601
  }
602
+ ],
603
+ "TRIGGER.PRESS_UP": {
604
+ target: "focused",
605
+ actions: ["focusInput", "clearHint"]
608
606
  }
609
607
  }
610
608
  },
611
- {
612
- delays: {
613
- CHANGE_INTERVAL: 50,
614
- CHANGE_DELAY: 300
609
+ scrubbing: {
610
+ tags: ["focus"],
611
+ effects: ["activatePointerLock", "trackMousemove", "setupVirtualCursor", "preventTextSelection"],
612
+ on: {
613
+ "SCRUBBER.POINTER_UP": {
614
+ target: "focused",
615
+ actions: ["focusInput", "clearCursorPoint"]
616
+ },
617
+ "SCRUBBER.POINTER_MOVE": [
618
+ {
619
+ guard: "isIncrementHint",
620
+ actions: ["increment", "setCursorPoint"]
621
+ },
622
+ {
623
+ guard: "isDecrementHint",
624
+ actions: ["decrement", "setCursorPoint"]
625
+ }
626
+ ]
627
+ }
628
+ }
629
+ },
630
+ implementations: {
631
+ guards: {
632
+ clampValueOnBlur: ({ prop }) => prop("clampValueOnBlur"),
633
+ isAtMin: ({ computed }) => computed("isAtMin"),
634
+ spinOnPress: ({ prop }) => !!prop("spinOnPress"),
635
+ isAtMax: ({ computed }) => computed("isAtMax"),
636
+ isInRange: ({ computed }) => !computed("isOutOfRange"),
637
+ isDecrementHint: ({ context, event }) => (event.hint ?? context.get("hint")) === "decrement",
638
+ isIncrementHint: ({ context, event }) => (event.hint ?? context.get("hint")) === "increment",
639
+ isTouchPointer: ({ event }) => event.pointerType === "touch"
640
+ },
641
+ effects: {
642
+ waitForChangeDelay({ send }) {
643
+ const id = setTimeout(() => {
644
+ send({ type: "CHANGE_DELAY" });
645
+ }, 300);
646
+ return () => clearTimeout(id);
615
647
  },
616
- guards: {
617
- clampValueOnBlur: (ctx2) => ctx2.clampValueOnBlur,
618
- isAtMin: (ctx2) => ctx2.isAtMin,
619
- spinOnPress: (ctx2) => !!ctx2.spinOnPress,
620
- isAtMax: (ctx2) => ctx2.isAtMax,
621
- isInRange: (ctx2) => !ctx2.isOutOfRange,
622
- isDecrementHint: (ctx2, evt) => (evt.hint ?? ctx2.hint) === "decrement",
623
- isIncrementHint: (ctx2, evt) => (evt.hint ?? ctx2.hint) === "increment",
624
- isTouchPointer: (_ctx, evt) => evt.pointerType === "touch"
648
+ spinValue({ send }) {
649
+ const id = setInterval(() => {
650
+ send({ type: "SPIN" });
651
+ }, 50);
652
+ return () => clearInterval(id);
625
653
  },
626
- activities: {
627
- trackFormControl(ctx2, _evt, { initialContext }) {
628
- const inputEl = dom.getInputEl(ctx2);
629
- return domQuery.trackFormControl(inputEl, {
630
- onFieldsetDisabledChange(disabled) {
631
- ctx2.fieldsetDisabled = disabled;
632
- },
633
- onFormReset() {
634
- set.value(ctx2, initialContext.value);
635
- }
636
- });
637
- },
638
- setupVirtualCursor(ctx2) {
639
- return dom.setupVirtualCursor(ctx2);
640
- },
641
- preventTextSelection(ctx2) {
642
- return dom.preventTextSelection(ctx2);
643
- },
644
- trackButtonDisabled(ctx2, _evt, { send }) {
645
- const btn = dom.getPressedTriggerEl(ctx2, ctx2.hint);
646
- return domQuery.observeAttributes(btn, {
647
- attributes: ["disabled"],
648
- callback() {
649
- send({ type: "TRIGGER.PRESS_UP", src: "attr" });
650
- }
651
- });
652
- },
653
- attachWheelListener(ctx2, _evt, { send }) {
654
- const inputEl = dom.getInputEl(ctx2);
655
- if (!inputEl || !dom.isActiveElement(ctx2, inputEl) || !ctx2.allowMouseWheel) return;
656
- function onWheel(event) {
657
- event.preventDefault();
658
- const dir = Math.sign(event.deltaY) * -1;
659
- if (dir === 1) {
660
- send("VALUE.INCREMENT");
661
- } else if (dir === -1) {
662
- send("VALUE.DECREMENT");
663
- }
654
+ trackFormControl({ context, scope }) {
655
+ const inputEl = getInputEl(scope);
656
+ return domQuery.trackFormControl(inputEl, {
657
+ onFieldsetDisabledChange(disabled) {
658
+ context.set("fieldsetDisabled", disabled);
659
+ },
660
+ onFormReset() {
661
+ context.set("value", context.initial("value"));
664
662
  }
665
- return domQuery.addDomEvent(inputEl, "wheel", onWheel, { passive: false });
666
- },
667
- activatePointerLock(ctx2) {
668
- if (domQuery.isSafari()) return;
669
- return domQuery.requestPointerLock(dom.getDoc(ctx2));
670
- },
671
- trackMousemove(ctx2, _evt, { send }) {
672
- const doc = dom.getDoc(ctx2);
673
- function onMousemove(event) {
674
- if (!ctx2.scrubberCursorPoint) return;
675
- const value = dom.getMousemoveValue(ctx2, event);
676
- if (!value.hint) return;
677
- send({
678
- type: "SCRUBBER.POINTER_MOVE",
679
- hint: value.hint,
680
- point: value.point
681
- });
663
+ });
664
+ },
665
+ setupVirtualCursor({ context, scope }) {
666
+ const point = context.get("scrubberCursorPoint");
667
+ return setupVirtualCursor(scope, point);
668
+ },
669
+ preventTextSelection({ scope }) {
670
+ return preventTextSelection(scope);
671
+ },
672
+ trackButtonDisabled({ context, scope, send }) {
673
+ const hint = context.get("hint");
674
+ const btn = getPressedTriggerEl(scope, hint);
675
+ return domQuery.observeAttributes(btn, {
676
+ attributes: ["disabled"],
677
+ callback() {
678
+ send({ type: "TRIGGER.PRESS_UP", src: "attr" });
682
679
  }
683
- function onMouseup() {
684
- send("SCRUBBER.POINTER_UP");
680
+ });
681
+ },
682
+ attachWheelListener({ scope, send, prop }) {
683
+ const inputEl = getInputEl(scope);
684
+ if (!inputEl || !scope.isActiveElement(inputEl) || !prop("allowMouseWheel")) return;
685
+ function onWheel(event) {
686
+ event.preventDefault();
687
+ const dir = Math.sign(event.deltaY) * -1;
688
+ if (dir === 1) {
689
+ send({ type: "VALUE.INCREMENT" });
690
+ } else if (dir === -1) {
691
+ send({ type: "VALUE.DECREMENT" });
685
692
  }
686
- return utils.callAll(
687
- domQuery.addDomEvent(doc, "mousemove", onMousemove, false),
688
- domQuery.addDomEvent(doc, "mouseup", onMouseup, false)
689
- );
690
693
  }
694
+ return domQuery.addDomEvent(inputEl, "wheel", onWheel, { passive: false });
691
695
  },
692
- actions: {
693
- focusInput(ctx2) {
694
- if (!ctx2.focusInputOnChange) return;
695
- const inputEl = dom.getInputEl(ctx2);
696
- if (dom.isActiveElement(ctx2, inputEl)) return;
697
- domQuery.raf(() => inputEl?.focus({ preventScroll: true }));
698
- },
699
- increment(ctx2, evt) {
700
- const nextValue = utils.incrementValue(ctx2.valueAsNumber, evt.step ?? ctx2.step);
701
- const value = formatValue(ctx2, utils.clampValue(nextValue, ctx2.min, ctx2.max));
702
- set.value(ctx2, value);
703
- },
704
- decrement(ctx2, evt) {
705
- const nextValue = utils.decrementValue(ctx2.valueAsNumber, evt.step ?? ctx2.step);
706
- const value = formatValue(ctx2, utils.clampValue(nextValue, ctx2.min, ctx2.max));
707
- set.value(ctx2, value);
708
- },
709
- setClampedValue(ctx2) {
710
- const nextValue = utils.clampValue(ctx2.valueAsNumber, ctx2.min, ctx2.max);
711
- set.value(ctx2, formatValue(ctx2, nextValue));
712
- },
713
- setRawValue(ctx2, evt) {
714
- const parsedValue = parseValue(ctx2, evt.value);
715
- const value = formatValue(ctx2, utils.clampValue(parsedValue, ctx2.min, ctx2.max));
716
- set.value(ctx2, value);
717
- },
718
- setValue(ctx2, evt) {
719
- const value = evt.target?.value ?? evt.value;
720
- set.value(ctx2, value);
721
- },
722
- clearValue(ctx2) {
723
- set.value(ctx2, "");
724
- },
725
- incrementToMax(ctx2) {
726
- const value = formatValue(ctx2, ctx2.max);
727
- set.value(ctx2, value);
728
- },
729
- decrementToMin(ctx2) {
730
- const value = formatValue(ctx2, ctx2.min);
731
- set.value(ctx2, value);
732
- },
733
- setHint(ctx2, evt) {
734
- ctx2.hint = evt.hint;
735
- },
736
- clearHint(ctx2) {
737
- ctx2.hint = null;
738
- },
739
- setHintToSet(ctx2) {
740
- ctx2.hint = "set";
741
- },
742
- invokeOnFocus(ctx2) {
743
- ctx2.onFocusChange?.({
744
- focused: true,
745
- value: ctx2.formattedValue,
746
- valueAsNumber: ctx2.valueAsNumber
747
- });
748
- },
749
- invokeOnBlur(ctx2) {
750
- ctx2.onFocusChange?.({
751
- focused: false,
752
- value: ctx2.formattedValue,
753
- valueAsNumber: ctx2.valueAsNumber
754
- });
755
- },
756
- invokeOnInvalid(ctx2) {
757
- if (!ctx2.isOutOfRange) return;
758
- const reason = ctx2.valueAsNumber > ctx2.max ? "rangeOverflow" : "rangeUnderflow";
759
- ctx2.onValueInvalid?.({
760
- reason,
761
- value: ctx2.formattedValue,
762
- valueAsNumber: ctx2.valueAsNumber
696
+ activatePointerLock({ scope }) {
697
+ if (domQuery.isSafari()) return;
698
+ return domQuery.requestPointerLock(scope.getDoc());
699
+ },
700
+ trackMousemove({ scope, send, context, computed }) {
701
+ const doc = scope.getDoc();
702
+ function onMousemove(event) {
703
+ const point = context.get("scrubberCursorPoint");
704
+ const isRtl = computed("isRtl");
705
+ const value = getMousemoveValue(scope, { point, isRtl, event });
706
+ if (!value.hint) return;
707
+ send({
708
+ type: "SCRUBBER.POINTER_MOVE",
709
+ hint: value.hint,
710
+ point: value.point
763
711
  });
764
- },
765
- syncInputElement(ctx2, evt) {
766
- const value = evt.type.endsWith("CHANGE") ? ctx2.value : ctx2.formattedValue;
767
- sync.input(ctx2, value);
768
- },
769
- setFormattedValue(ctx2) {
770
- set.value(ctx2, ctx2.formattedValue);
771
- },
772
- setCursorPoint(ctx2, evt) {
773
- ctx2.scrubberCursorPoint = evt.point;
774
- },
775
- clearCursorPoint(ctx2) {
776
- ctx2.scrubberCursorPoint = null;
777
- },
778
- setVirtualCursorPosition(ctx2) {
779
- const cursorEl = dom.getCursorEl(ctx2);
780
- if (!cursorEl || !ctx2.scrubberCursorPoint) return;
781
- const { x, y } = ctx2.scrubberCursorPoint;
782
- cursorEl.style.transform = `translate3d(${x}px, ${y}px, 0px)`;
783
- },
784
- setFormatterAndParser(ctx2) {
785
- if (!ctx2.locale) return;
786
- ctx2.formatter = createFormatter(ctx2.locale, ctx2.formatOptions);
787
- ctx2.parser = createParser(ctx2.locale, ctx2.formatOptions);
788
712
  }
713
+ function onMouseup() {
714
+ send({ type: "SCRUBBER.POINTER_UP" });
715
+ }
716
+ return utils.callAll(domQuery.addDomEvent(doc, "mousemove", onMousemove, false), domQuery.addDomEvent(doc, "mouseup", onMouseup, false));
717
+ }
718
+ },
719
+ actions: {
720
+ focusInput({ scope, prop }) {
721
+ if (!prop("focusInputOnChange")) return;
722
+ const inputEl = getInputEl(scope);
723
+ if (scope.isActiveElement(inputEl)) return;
724
+ domQuery.raf(() => inputEl?.focus({ preventScroll: true }));
725
+ },
726
+ increment({ context, event, prop, computed }) {
727
+ const nextValue = utils.incrementValue(computed("valueAsNumber"), event.step ?? prop("step"));
728
+ const value = formatValue(utils.clampValue(nextValue, prop("min"), prop("max")), { computed, prop });
729
+ context.set("value", value);
730
+ },
731
+ decrement({ context, event, prop, computed }) {
732
+ const nextValue = utils.decrementValue(computed("valueAsNumber"), event.step ?? prop("step"));
733
+ const value = formatValue(utils.clampValue(nextValue, prop("min"), prop("max")), { computed, prop });
734
+ context.set("value", value);
735
+ },
736
+ setClampedValue({ context, prop, computed }) {
737
+ const nextValue = utils.clampValue(computed("valueAsNumber"), prop("min"), prop("max"));
738
+ context.set("value", formatValue(nextValue, { computed, prop }));
739
+ },
740
+ setRawValue({ context, event, prop, computed }) {
741
+ const parsedValue = parseValue(event.value, { computed, prop });
742
+ const value = formatValue(utils.clampValue(parsedValue, prop("min"), prop("max")), { computed, prop });
743
+ context.set("value", value);
744
+ },
745
+ setValue({ context, event }) {
746
+ const value = event.target?.value ?? event.value;
747
+ context.set("value", value);
748
+ },
749
+ clearValue({ context }) {
750
+ context.set("value", "");
751
+ },
752
+ incrementToMax({ context, prop, computed }) {
753
+ const value = formatValue(prop("max"), { computed, prop });
754
+ context.set("value", value);
789
755
  },
790
- compareFns: {
791
- formatOptions: (a, b) => utils.isEqual(a, b),
792
- scrubberCursorPoint: (a, b) => utils.isEqual(a, b)
756
+ decrementToMin({ context, prop, computed }) {
757
+ const value = formatValue(prop("min"), { computed, prop });
758
+ context.set("value", value);
759
+ },
760
+ setHint({ context, event }) {
761
+ context.set("hint", event.hint);
762
+ },
763
+ clearHint({ context }) {
764
+ context.set("hint", null);
765
+ },
766
+ setHintToSet({ context }) {
767
+ context.set("hint", "set");
768
+ },
769
+ invokeOnFocus({ computed, prop }) {
770
+ prop("onFocusChange")?.({
771
+ focused: true,
772
+ value: computed("formattedValue"),
773
+ valueAsNumber: computed("valueAsNumber")
774
+ });
775
+ },
776
+ invokeOnBlur({ computed, prop }) {
777
+ prop("onFocusChange")?.({
778
+ focused: false,
779
+ value: computed("formattedValue"),
780
+ valueAsNumber: computed("valueAsNumber")
781
+ });
782
+ },
783
+ invokeOnInvalid({ computed, prop }) {
784
+ if (!computed("isOutOfRange")) return;
785
+ const reason = computed("valueAsNumber") > prop("max") ? "rangeOverflow" : "rangeUnderflow";
786
+ prop("onValueInvalid")?.({
787
+ reason,
788
+ value: computed("formattedValue"),
789
+ valueAsNumber: computed("valueAsNumber")
790
+ });
791
+ },
792
+ syncInputElement({ context, event, computed, scope }) {
793
+ const value = event.type.endsWith("CHANGE") ? context.get("value") : computed("formattedValue");
794
+ const inputEl = getInputEl(scope);
795
+ const sel = recordCursor(inputEl);
796
+ domQuery.raf(() => {
797
+ domQuery.setElementValue(inputEl, value);
798
+ restoreCursor(inputEl, sel);
799
+ });
800
+ },
801
+ setFormattedValue({ context, computed }) {
802
+ context.set("value", computed("formattedValue"));
803
+ },
804
+ setCursorPoint({ context, event }) {
805
+ context.set("scrubberCursorPoint", event.point);
806
+ },
807
+ clearCursorPoint({ context }) {
808
+ context.set("scrubberCursorPoint", null);
809
+ },
810
+ setVirtualCursorPosition({ context, scope }) {
811
+ const cursorEl = getCursorEl(scope);
812
+ const point = context.get("scrubberCursorPoint");
813
+ if (!cursorEl || !point) return;
814
+ cursorEl.style.transform = `translate3d(${point.x}px, ${point.y}px, 0px)`;
793
815
  }
794
816
  }
795
- );
796
- }
797
- var sync = {
798
- input(ctx, value) {
799
- const inputEl = dom.getInputEl(ctx);
800
- if (!inputEl) return;
801
- const sel = recordCursor(inputEl);
802
- domQuery.raf(() => {
803
- domQuery.setElementValue(inputEl, value);
804
- restoreCursor(inputEl, sel);
805
- });
806
- }
807
- };
808
- var invoke = {
809
- onChange: (ctx) => {
810
- ctx.onValueChange?.({
811
- value: ctx.value,
812
- valueAsNumber: ctx.valueAsNumber
813
- });
814
- }
815
- };
816
- var set = {
817
- value: (ctx, value) => {
818
- if (utils.isEqual(ctx.value, value)) return;
819
- ctx.value = value;
820
- invoke.onChange(ctx);
821
817
  }
822
- };
818
+ });
819
+ var props = types.createProps()([
820
+ "allowMouseWheel",
821
+ "allowOverflow",
822
+ "clampValueOnBlur",
823
+ "dir",
824
+ "disabled",
825
+ "focusInputOnChange",
826
+ "form",
827
+ "formatOptions",
828
+ "getRootNode",
829
+ "id",
830
+ "ids",
831
+ "inputMode",
832
+ "invalid",
833
+ "locale",
834
+ "max",
835
+ "min",
836
+ "name",
837
+ "onFocusChange",
838
+ "onValueChange",
839
+ "onValueInvalid",
840
+ "pattern",
841
+ "required",
842
+ "readOnly",
843
+ "spinOnPress",
844
+ "step",
845
+ "translations",
846
+ "value",
847
+ "defaultValue"
848
+ ]);
849
+ var splitProps = utils.createSplitProps(props);
823
850
 
824
851
  exports.anatomy = anatomy;
825
852
  exports.connect = connect;
826
853
  exports.machine = machine;
854
+ exports.props = props;
855
+ exports.splitProps = splitProps;