base-ui-vue 0.2.0 → 0.4.0

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 (109) hide show
  1. package/dist/button/ToolbarButton.cjs +6 -0
  2. package/dist/button/ToolbarButton.js +1 -1
  3. package/dist/content/ScrollAreaContent.cjs +168 -0
  4. package/dist/content/ScrollAreaContent.cjs.map +1 -0
  5. package/dist/content/ScrollAreaContent.js +133 -0
  6. package/dist/content/ScrollAreaContent.js.map +1 -0
  7. package/dist/control/SliderControl.js +2 -2
  8. package/dist/corner/ScrollAreaCorner.cjs +77 -0
  9. package/dist/corner/ScrollAreaCorner.cjs.map +1 -0
  10. package/dist/corner/ScrollAreaCorner.js +72 -0
  11. package/dist/corner/ScrollAreaCorner.js.map +1 -0
  12. package/dist/decrement/NumberFieldDecrement.cjs +861 -0
  13. package/dist/decrement/NumberFieldDecrement.cjs.map +1 -0
  14. package/dist/decrement/NumberFieldDecrement.js +700 -0
  15. package/dist/decrement/NumberFieldDecrement.js.map +1 -0
  16. package/dist/fallback/AvatarFallback.cjs +2 -46
  17. package/dist/fallback/AvatarFallback.cjs.map +1 -1
  18. package/dist/fallback/AvatarFallback.js +3 -41
  19. package/dist/fallback/AvatarFallback.js.map +1 -1
  20. package/dist/group/NumberFieldGroup.cjs +72 -0
  21. package/dist/group/NumberFieldGroup.cjs.map +1 -0
  22. package/dist/group/NumberFieldGroup.js +67 -0
  23. package/dist/group/NumberFieldGroup.js.map +1 -0
  24. package/dist/increment/NumberFieldIncrement.cjs +112 -0
  25. package/dist/increment/NumberFieldIncrement.cjs.map +1 -0
  26. package/dist/increment/NumberFieldIncrement.js +107 -0
  27. package/dist/increment/NumberFieldIncrement.js.map +1 -0
  28. package/dist/index.cjs +52 -0
  29. package/dist/index.d.cts +1761 -430
  30. package/dist/index.d.cts.map +1 -1
  31. package/dist/index.d.ts +1761 -430
  32. package/dist/index.d.ts.map +1 -1
  33. package/dist/index.js +7 -2
  34. package/dist/index2.cjs +4065 -60
  35. package/dist/index2.cjs.map +1 -1
  36. package/dist/index2.js +3955 -184
  37. package/dist/index2.js.map +1 -1
  38. package/package.json +1 -1
  39. package/src/index.ts +6 -0
  40. package/src/input/Input.vue +37 -0
  41. package/src/input/InputDataAttributes.ts +30 -0
  42. package/src/input/index.ts +4 -0
  43. package/src/meter/index.ts +16 -0
  44. package/src/meter/indicator/MeterIndicator.vue +65 -0
  45. package/src/meter/label/MeterLabel.vue +63 -0
  46. package/src/meter/root/MeterRoot.vue +131 -0
  47. package/src/meter/root/MeterRootContext.ts +41 -0
  48. package/src/meter/track/MeterTrack.vue +46 -0
  49. package/src/meter/value/MeterValue.vue +85 -0
  50. package/src/number-field/decrement/NumberFieldDecrement.vue +109 -0
  51. package/src/number-field/group/NumberFieldGroup.vue +47 -0
  52. package/src/number-field/increment/NumberFieldIncrement.vue +109 -0
  53. package/src/number-field/index.ts +42 -0
  54. package/src/number-field/input/NumberFieldInput.vue +455 -0
  55. package/src/number-field/root/NumberFieldRoot.vue +626 -0
  56. package/src/number-field/root/NumberFieldRootContext.ts +94 -0
  57. package/src/number-field/root/useNumberFieldButton.ts +171 -0
  58. package/src/number-field/scrub-area/NumberFieldScrubArea.vue +359 -0
  59. package/src/number-field/scrub-area/NumberFieldScrubAreaContext.ts +26 -0
  60. package/src/number-field/scrub-area-cursor/NumberFieldScrubAreaCursor.vue +75 -0
  61. package/src/number-field/utils/constants.ts +4 -0
  62. package/src/number-field/utils/getViewportRect.ts +34 -0
  63. package/src/number-field/utils/parse.ts +248 -0
  64. package/src/number-field/utils/stateAttributesMapping.ts +9 -0
  65. package/src/number-field/utils/subscribeToVisualViewportResize.ts +27 -0
  66. package/src/number-field/utils/types.ts +24 -0
  67. package/src/number-field/utils/validate.ts +120 -0
  68. package/src/otp-field/index.ts +22 -0
  69. package/src/otp-field/input/OtpFieldInput.vue +336 -0
  70. package/src/otp-field/root/OtpFieldRoot.vue +583 -0
  71. package/src/otp-field/root/OtpFieldRootContext.ts +81 -0
  72. package/src/otp-field/utils/otp.ts +135 -0
  73. package/src/otp-field/utils/stateAttributesMapping.ts +16 -0
  74. package/src/progress/index.ts +23 -0
  75. package/src/progress/indicator/ProgressIndicator.vue +74 -0
  76. package/src/progress/label/ProgressLabel.vue +63 -0
  77. package/src/progress/root/ProgressRoot.vue +160 -0
  78. package/src/progress/root/ProgressRootContext.ts +51 -0
  79. package/src/progress/root/ProgressRootDataAttributes.ts +14 -0
  80. package/src/progress/root/stateAttributesMapping.ts +18 -0
  81. package/src/progress/track/ProgressTrack.vue +48 -0
  82. package/src/progress/value/ProgressValue.vue +92 -0
  83. package/src/scroll-area/constants.ts +2 -0
  84. package/src/scroll-area/content/ScrollAreaContent.vue +87 -0
  85. package/src/scroll-area/corner/ScrollAreaCorner.vue +64 -0
  86. package/src/scroll-area/index.ts +25 -0
  87. package/src/scroll-area/root/ScrollAreaRoot.vue +297 -0
  88. package/src/scroll-area/root/ScrollAreaRootContext.ts +89 -0
  89. package/src/scroll-area/root/ScrollAreaRootCssVars.ts +4 -0
  90. package/src/scroll-area/root/ScrollAreaRootDataAttributes.ts +9 -0
  91. package/src/scroll-area/root/stateAttributes.ts +14 -0
  92. package/src/scroll-area/scrollbar/ScrollAreaScrollbar.vue +263 -0
  93. package/src/scroll-area/scrollbar/ScrollAreaScrollbarContext.ts +20 -0
  94. package/src/scroll-area/scrollbar/ScrollAreaScrollbarCssVars.ts +4 -0
  95. package/src/scroll-area/scrollbar/ScrollAreaScrollbarDataAttributes.ts +11 -0
  96. package/src/scroll-area/thumb/ScrollAreaThumb.vue +120 -0
  97. package/src/scroll-area/thumb/ScrollAreaThumbDataAttributes.ts +3 -0
  98. package/src/scroll-area/utils/getOffset.ts +34 -0
  99. package/src/scroll-area/viewport/ScrollAreaViewport.vue +379 -0
  100. package/src/scroll-area/viewport/ScrollAreaViewportContext.ts +20 -0
  101. package/src/scroll-area/viewport/ScrollAreaViewportCssVars.ts +6 -0
  102. package/src/scroll-area/viewport/ScrollAreaViewportDataAttributes.ts +9 -0
  103. package/src/utils/detectBrowser.ts +15 -0
  104. package/src/utils/formatNumber.ts +60 -2
  105. package/src/utils/scrollEdges.ts +33 -0
  106. package/src/utils/styles.ts +28 -0
  107. package/src/utils/useInterval.ts +45 -0
  108. package/src/utils/usePressAndHold.ts +260 -0
  109. package/src/utils/useValueChanged.ts +21 -0
@@ -0,0 +1,700 @@
1
+ import { mergeProps as mergeProps$1, useButton, useRenderElement } from "../button/Button.js";
2
+ import { REASONS, createChangeEventDetails, createGenericEventDetails } from "../checkbox/index.js";
3
+ import { fieldValidityMapping } from "../checkbox-group/CheckboxGroup.js";
4
+ import { ownerWindow } from "../control/SliderControl.js";
5
+ import { computed, createBlock, createCommentVNode, defineComponent, inject, mergeProps, onUnmounted, openBlock, renderSlot, resolveDynamicComponent, toValue, unref, useAttrs, withCtx } from "vue";
6
+
7
+ //#region src/utils/useTimeout.ts
8
+ const EMPTY$1 = 0;
9
+ var Timeout = class Timeout {
10
+ currentId = EMPTY$1;
11
+ static create() {
12
+ return new Timeout();
13
+ }
14
+ /**
15
+ * Executes `fn` after `delay`, clearing any previously scheduled call.
16
+ */
17
+ start(delay, fn) {
18
+ this.clear();
19
+ this.currentId = setTimeout(() => {
20
+ this.currentId = EMPTY$1;
21
+ fn();
22
+ }, delay);
23
+ }
24
+ isStarted() {
25
+ return this.currentId !== EMPTY$1;
26
+ }
27
+ clear = () => {
28
+ if (this.currentId !== EMPTY$1) {
29
+ clearTimeout(this.currentId);
30
+ this.currentId = EMPTY$1;
31
+ }
32
+ };
33
+ };
34
+ /**
35
+ * A `setTimeout` with automatic cleanup on unmount.
36
+ */
37
+ function useTimeout() {
38
+ const timeout = Timeout.create();
39
+ onUnmounted(() => {
40
+ timeout.clear();
41
+ });
42
+ return timeout;
43
+ }
44
+
45
+ //#endregion
46
+ //#region src/utils/formatNumber.ts
47
+ const formatterCache = /* @__PURE__ */ new Map();
48
+ /**
49
+ * Returns a memoized `Intl.NumberFormat` for the given locale/options.
50
+ */
51
+ function getFormatter(locale, options) {
52
+ const optionsString = JSON.stringify({
53
+ locale,
54
+ options
55
+ });
56
+ const cachedFormatter = formatterCache.get(optionsString);
57
+ if (cachedFormatter) return cachedFormatter;
58
+ const formatter = new Intl.NumberFormat(locale, options);
59
+ formatterCache.set(optionsString, formatter);
60
+ return formatter;
61
+ }
62
+ function formatNumber(value, locale, options) {
63
+ if (value == null) return "";
64
+ return getFormatter(locale, options).format(value);
65
+ }
66
+ function formatNumberMaxPrecision(value, locale, options) {
67
+ return formatNumber(value, locale, {
68
+ ...options,
69
+ maximumFractionDigits: 20
70
+ });
71
+ }
72
+ /**
73
+ * Formats a numeric value for display inside Base UI Vue components.
74
+ *
75
+ * When no `format` is provided, the value is interpreted as a percentage
76
+ * in the 0-100 range (matching React's Base UI semantics for
77
+ * `<Meter.Root>` / `<Progress.Root>`).
78
+ *
79
+ * Returns an empty string when the value is `null`.
80
+ */
81
+ function formatNumberValue(value, locale, format) {
82
+ if (value == null) return "";
83
+ if (!format) return formatNumber(value / 100, locale, { style: "percent" });
84
+ return formatNumber(value, locale, format);
85
+ }
86
+
87
+ //#endregion
88
+ //#region src/number-field/root/NumberFieldRootContext.ts
89
+ const numberFieldRootContextKey = Symbol("NumberFieldRootContext");
90
+ function useNumberFieldRootContext() {
91
+ const context = inject(numberFieldRootContextKey, void 0);
92
+ if (context === void 0) throw new Error("Base UI Vue: NumberFieldRootContext is missing. NumberField parts must be placed within <NumberFieldRoot>.");
93
+ return context;
94
+ }
95
+
96
+ //#endregion
97
+ //#region src/utils/useInterval.ts
98
+ const EMPTY = 0;
99
+ var Interval = class Interval {
100
+ currentId = EMPTY;
101
+ static create() {
102
+ return new Interval();
103
+ }
104
+ /**
105
+ * Repeatedly executes `fn` every `delay` ms, clearing any previously scheduled interval.
106
+ */
107
+ start(delay, fn) {
108
+ this.clear();
109
+ this.currentId = setInterval(fn, delay);
110
+ }
111
+ isStarted() {
112
+ return this.currentId !== EMPTY;
113
+ }
114
+ clear = () => {
115
+ if (this.currentId !== EMPTY) {
116
+ clearInterval(this.currentId);
117
+ this.currentId = EMPTY;
118
+ }
119
+ };
120
+ };
121
+ /**
122
+ * A `setInterval` with automatic cleanup on unmount.
123
+ */
124
+ function useInterval() {
125
+ const interval = Interval.create();
126
+ onUnmounted(() => {
127
+ interval.clear();
128
+ });
129
+ return interval;
130
+ }
131
+
132
+ //#endregion
133
+ //#region src/utils/usePressAndHold.ts
134
+ const DEFAULT_TICK_DELAY = 60;
135
+ const DEFAULT_START_DELAY = 400;
136
+ const DEFAULT_SCROLL_DISTANCE = 8;
137
+ const TOUCH_TIMEOUT = 50;
138
+ const MAX_POINTER_MOVES_AFTER_TOUCH = 3;
139
+ function isTouchLikePointerType$1(pointerType) {
140
+ return pointerType === "touch" || pointerType === "pen";
141
+ }
142
+ /**
143
+ * Adds press-and-hold behavior to a button element.
144
+ * On pointer down, performs one action immediately, then after a delay starts
145
+ * continuous repeated actions at a fixed interval. Handles mouse, touch, and pen inputs.
146
+ */
147
+ function usePressAndHold(params) {
148
+ const { tick, onStop, tickDelay = DEFAULT_TICK_DELAY, startDelay = DEFAULT_START_DELAY, scrollDistance = DEFAULT_SCROLL_DISTANCE, elementRef } = params;
149
+ const isDisabled = () => toValue(params.disabled);
150
+ const isReadOnly = () => toValue(params.readOnly ?? false);
151
+ const startTickTimeout = useTimeout();
152
+ const tickInterval = useInterval();
153
+ const intentionalTouchCheckTimeout = useTimeout();
154
+ let isPressed = false;
155
+ let movesAfterTouch = 0;
156
+ let downCoords = {
157
+ x: 0,
158
+ y: 0
159
+ };
160
+ let isTouchingButton = false;
161
+ let ignoreClick = false;
162
+ let pointerType = "";
163
+ let unsubscribeFromGlobalContextMenu = () => {};
164
+ function stopAutoChange() {
165
+ intentionalTouchCheckTimeout.clear();
166
+ startTickTimeout.clear();
167
+ tickInterval.clear();
168
+ unsubscribeFromGlobalContextMenu();
169
+ unsubscribeFromGlobalContextMenu = () => {};
170
+ movesAfterTouch = 0;
171
+ }
172
+ function startAutoChange(triggerNativeEvent) {
173
+ stopAutoChange();
174
+ const element = elementRef.value;
175
+ if (!element) return;
176
+ const win = ownerWindow(element);
177
+ function handleContextMenu(event) {
178
+ event.preventDefault();
179
+ }
180
+ win.addEventListener("contextmenu", handleContextMenu);
181
+ unsubscribeFromGlobalContextMenu = () => {
182
+ win.removeEventListener("contextmenu", handleContextMenu);
183
+ };
184
+ function handlePointerUp(event) {
185
+ isPressed = false;
186
+ stopAutoChange();
187
+ onStop?.(event);
188
+ }
189
+ win.addEventListener("pointerup", handlePointerUp, { once: true });
190
+ if (!tick(triggerNativeEvent)) {
191
+ stopAutoChange();
192
+ return;
193
+ }
194
+ startTickTimeout.start(startDelay, () => {
195
+ tickInterval.start(tickDelay, () => {
196
+ if (!tick(triggerNativeEvent)) stopAutoChange();
197
+ });
198
+ });
199
+ }
200
+ onUnmounted(() => stopAutoChange());
201
+ const pointerHandlers = {
202
+ onTouchstart() {
203
+ isTouchingButton = true;
204
+ },
205
+ onTouchend() {
206
+ isTouchingButton = false;
207
+ },
208
+ onPointerdown(event) {
209
+ const isMainButton = !event.button || event.button === 0;
210
+ if (event.defaultPrevented || !isMainButton || isDisabled() || isReadOnly()) return;
211
+ pointerType = event.pointerType;
212
+ ignoreClick = false;
213
+ isPressed = true;
214
+ downCoords = {
215
+ x: event.clientX,
216
+ y: event.clientY
217
+ };
218
+ if (!isTouchLikePointerType$1(event.pointerType)) {
219
+ event.preventDefault();
220
+ startAutoChange(event);
221
+ } else intentionalTouchCheckTimeout.start(TOUCH_TIMEOUT, () => {
222
+ const moves = movesAfterTouch;
223
+ movesAfterTouch = 0;
224
+ if (isPressed && moves < MAX_POINTER_MOVES_AFTER_TOUCH) {
225
+ startAutoChange(event);
226
+ ignoreClick = true;
227
+ } else {
228
+ ignoreClick = false;
229
+ stopAutoChange();
230
+ }
231
+ });
232
+ },
233
+ onPointerup(event) {
234
+ if (isTouchLikePointerType$1(event.pointerType)) isPressed = false;
235
+ },
236
+ onPointermove(event) {
237
+ if (isDisabled() || isReadOnly() || !isTouchLikePointerType$1(event.pointerType) || !isPressed) return;
238
+ movesAfterTouch += 1;
239
+ const { x, y } = downCoords;
240
+ const dx = x - event.clientX;
241
+ const dy = y - event.clientY;
242
+ if (dx ** 2 + dy ** 2 > scrollDistance ** 2) stopAutoChange();
243
+ },
244
+ onMouseenter(event) {
245
+ if (event.defaultPrevented || isDisabled() || isReadOnly() || !isPressed || isTouchingButton || isTouchLikePointerType$1(pointerType)) return;
246
+ startAutoChange(event);
247
+ },
248
+ onMouseleave() {
249
+ if (isTouchingButton) return;
250
+ stopAutoChange();
251
+ },
252
+ onMouseup() {
253
+ if (isTouchingButton) return;
254
+ stopAutoChange();
255
+ }
256
+ };
257
+ function shouldSkipClick(event) {
258
+ if (event.defaultPrevented) return true;
259
+ if (isTouchLikePointerType$1(pointerType)) return ignoreClick;
260
+ return event.detail !== 0;
261
+ }
262
+ return {
263
+ pointerHandlers,
264
+ shouldSkipClick
265
+ };
266
+ }
267
+
268
+ //#endregion
269
+ //#region src/number-field/utils/constants.ts
270
+ const CHANGE_VALUE_TICK_DELAY = 60;
271
+ const START_AUTO_CHANGE_DELAY = 400;
272
+ const SCROLLING_POINTER_MOVE_DISTANCE = 8;
273
+ const DEFAULT_STEP = 1;
274
+
275
+ //#endregion
276
+ //#region src/number-field/utils/parse.ts
277
+ const HAN_NUMERALS = [
278
+ "零",
279
+ "〇",
280
+ "一",
281
+ "二",
282
+ "三",
283
+ "四",
284
+ "五",
285
+ "六",
286
+ "七",
287
+ "八",
288
+ "九"
289
+ ];
290
+ const HAN_NUMERAL_TO_DIGIT = {
291
+ 零: "0",
292
+ 〇: "0",
293
+ 一: "1",
294
+ 二: "2",
295
+ 三: "3",
296
+ 四: "4",
297
+ 五: "5",
298
+ 六: "6",
299
+ 七: "7",
300
+ 八: "8",
301
+ 九: "9"
302
+ };
303
+ const ARABIC_NUMERALS = [
304
+ "٠",
305
+ "١",
306
+ "٢",
307
+ "٣",
308
+ "٤",
309
+ "٥",
310
+ "٦",
311
+ "٧",
312
+ "٨",
313
+ "٩"
314
+ ];
315
+ const PERSIAN_NUMERALS = [
316
+ "۰",
317
+ "۱",
318
+ "۲",
319
+ "۳",
320
+ "۴",
321
+ "۵",
322
+ "۶",
323
+ "۷",
324
+ "۸",
325
+ "۹"
326
+ ];
327
+ const FULLWIDTH_NUMERALS = [
328
+ "0",
329
+ "1",
330
+ "2",
331
+ "3",
332
+ "4",
333
+ "5",
334
+ "6",
335
+ "7",
336
+ "8",
337
+ "9"
338
+ ];
339
+ const PERCENTAGES = [
340
+ "%",
341
+ "٪",
342
+ "%",
343
+ "﹪"
344
+ ];
345
+ const PERMILLE = ["‰", "؉"];
346
+ const UNICODE_MINUS_SIGNS = [
347
+ "−",
348
+ "-",
349
+ "‒",
350
+ "–",
351
+ "—",
352
+ "﹣"
353
+ ];
354
+ const UNICODE_PLUS_SIGNS = ["+", "﹢"];
355
+ const FULLWIDTH_DECIMAL = ".";
356
+ const FULLWIDTH_GROUP = ",";
357
+ const ARABIC_RE = new RegExp(`[${ARABIC_NUMERALS.join("")}]`, "g");
358
+ const PERSIAN_RE = new RegExp(`[${PERSIAN_NUMERALS.join("")}]`, "g");
359
+ const FULLWIDTH_RE = new RegExp(`[${FULLWIDTH_NUMERALS.join("")}]`, "g");
360
+ const HAN_RE = new RegExp(`[${HAN_NUMERALS.join("")}]`, "g");
361
+ const PERCENT_RE = new RegExp(`[${PERCENTAGES.join("")}]`);
362
+ const PERMILLE_RE = new RegExp(`[${PERMILLE.join("")}]`);
363
+ const PERCENT_GLOBAL_RE = new RegExp(PERCENT_RE.source, "g");
364
+ const PERMILLE_GLOBAL_RE = new RegExp(PERMILLE_RE.source, "g");
365
+ const ARABIC_DETECT_RE = /[٠١٢٣٤٥٦٧٨٩]/;
366
+ const PERSIAN_DETECT_RE = /[۰۱۲۳۴۵۶۷۸۹]/;
367
+ const HAN_DETECT_RE = /[零〇一二三四五六七八九]/;
368
+ const FULLWIDTH_DETECT_RE = new RegExp(`[${FULLWIDTH_NUMERALS.join("")}]`);
369
+ const BASE_NON_NUMERIC_SYMBOLS = [
370
+ ".",
371
+ ",",
372
+ FULLWIDTH_DECIMAL,
373
+ FULLWIDTH_GROUP,
374
+ "٫",
375
+ "٬"
376
+ ];
377
+ const SPACE_SEPARATOR_RE = /\p{Zs}/u;
378
+ const PLUS_SIGNS_WITH_ASCII = ["+", ...UNICODE_PLUS_SIGNS];
379
+ const MINUS_SIGNS_WITH_ASCII = ["-", ...UNICODE_MINUS_SIGNS];
380
+ function escapeRegExp(s) {
381
+ return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
382
+ }
383
+ function escapeClassChar(s) {
384
+ return s.replace(/[-\\\]^]/g, (m) => `\\${m}`);
385
+ }
386
+ function shiftDecimal(value, exponentDelta) {
387
+ const [coefficient, exponent = "0"] = String(value).split("e");
388
+ return Number(`${coefficient}e${Number(exponent) + exponentDelta}`);
389
+ }
390
+ function charClassFrom(chars) {
391
+ return `[${chars.map(escapeClassChar).join("")}]`;
392
+ }
393
+ const ANY_MINUS_CLASS = charClassFrom(["-"].concat(UNICODE_MINUS_SIGNS));
394
+ const ANY_PLUS_CLASS = charClassFrom(["+"].concat(UNICODE_PLUS_SIGNS));
395
+ const ANY_MINUS_RE = new RegExp(ANY_MINUS_CLASS, "gu");
396
+ const ANY_PLUS_RE = new RegExp(ANY_PLUS_CLASS, "gu");
397
+ const ANY_MINUS_DETECT_RE = new RegExp(ANY_MINUS_CLASS);
398
+ const ANY_PLUS_DETECT_RE = new RegExp(ANY_PLUS_CLASS);
399
+ function getNumberLocaleDetails(locale, options) {
400
+ const parts = getFormatter(locale, options).formatToParts(11111.1);
401
+ const result = {};
402
+ parts.forEach((part) => {
403
+ result[part.type] = part.value;
404
+ });
405
+ getFormatter(locale).formatToParts(.1).forEach((part) => {
406
+ if (part.type === "decimal") result[part.type] = part.value;
407
+ });
408
+ return result;
409
+ }
410
+ function parseNumber(formattedNumber, locale, options) {
411
+ if (formattedNumber == null) return null;
412
+ let input = String(formattedNumber).replace(/\p{Cf}/gu, "").trim();
413
+ input = input.replace(ANY_MINUS_RE, "-").replace(ANY_PLUS_RE, "+");
414
+ let isNegative = false;
415
+ const trailing = input.match(/([+-])\s*$/);
416
+ if (trailing) {
417
+ if (trailing[1] === "-") isNegative = true;
418
+ input = input.replace(/([+-])\s*$/, "");
419
+ }
420
+ const leading = input.match(/^\s*([+-])/);
421
+ if (leading) {
422
+ if (leading[1] === "-") isNegative = true;
423
+ input = input.replace(/^\s*[+-]/, "");
424
+ }
425
+ let computedLocale = locale;
426
+ if (computedLocale === void 0) {
427
+ if (ARABIC_DETECT_RE.test(input) || PERSIAN_DETECT_RE.test(input)) computedLocale = "ar";
428
+ else if (HAN_DETECT_RE.test(input)) computedLocale = "zh";
429
+ }
430
+ const { group, decimal, currency, exponentSeparator } = getNumberLocaleDetails(computedLocale, options);
431
+ const unitParts = getFormatter(computedLocale, options).formatToParts(1).filter((p) => p.type === "unit").map((p) => escapeRegExp(p.value));
432
+ const unitRegex = unitParts.length ? new RegExp(unitParts.join("|"), "g") : null;
433
+ let groupRegex = null;
434
+ if (group) {
435
+ const isSpaceGroup = /\p{Zs}/u.test(group);
436
+ const isApostropheGroup = group === "'" || group === "’";
437
+ if (isSpaceGroup) groupRegex = /\p{Zs}/gu;
438
+ else if (isApostropheGroup) groupRegex = /['’]/g;
439
+ else groupRegex = new RegExp(escapeRegExp(group), "g");
440
+ }
441
+ let unformatted = [
442
+ {
443
+ regex: group ? groupRegex : null,
444
+ replacement: ""
445
+ },
446
+ {
447
+ regex: decimal ? new RegExp(escapeRegExp(decimal), "g") : null,
448
+ replacement: "."
449
+ },
450
+ {
451
+ regex: /./g,
452
+ replacement: "."
453
+ },
454
+ {
455
+ regex: /,/g,
456
+ replacement: ""
457
+ },
458
+ {
459
+ regex: /٫/g,
460
+ replacement: "."
461
+ },
462
+ {
463
+ regex: /٬/g,
464
+ replacement: ""
465
+ },
466
+ {
467
+ regex: currency ? new RegExp(escapeRegExp(currency), "g") : null,
468
+ replacement: ""
469
+ },
470
+ {
471
+ regex: unitRegex,
472
+ replacement: ""
473
+ },
474
+ {
475
+ regex: PERCENT_GLOBAL_RE,
476
+ replacement: ""
477
+ },
478
+ {
479
+ regex: PERMILLE_GLOBAL_RE,
480
+ replacement: ""
481
+ },
482
+ {
483
+ regex: exponentSeparator ? new RegExp(escapeRegExp(exponentSeparator), "g") : null,
484
+ replacement: "e"
485
+ },
486
+ {
487
+ regex: ARABIC_RE,
488
+ replacement: (ch) => String(ARABIC_NUMERALS.indexOf(ch))
489
+ },
490
+ {
491
+ regex: PERSIAN_RE,
492
+ replacement: (ch) => String(PERSIAN_NUMERALS.indexOf(ch))
493
+ },
494
+ {
495
+ regex: FULLWIDTH_RE,
496
+ replacement: (ch) => String(FULLWIDTH_NUMERALS.indexOf(ch))
497
+ },
498
+ {
499
+ regex: HAN_RE,
500
+ replacement: (ch) => HAN_NUMERAL_TO_DIGIT[ch]
501
+ }
502
+ ].reduce((acc, { regex, replacement }) => {
503
+ return regex ? acc.replace(regex, replacement) : acc;
504
+ }, input);
505
+ const lastDot = unformatted.lastIndexOf(".");
506
+ if (lastDot !== -1) unformatted = `${unformatted.slice(0, lastDot).replace(/\./g, "")}.${unformatted.slice(lastDot + 1).replace(/\./g, "")}`;
507
+ if (/^[+-]?Infinity$/i.test(input) || /∞/.test(input)) return null;
508
+ const parseTarget = (isNegative ? "-" : "") + unformatted;
509
+ let num = Number.parseFloat(parseTarget);
510
+ const style = options?.style;
511
+ const isUnitPercent = style === "unit" && options?.unit === "percent";
512
+ const hasPercentSymbol = PERCENT_RE.test(formattedNumber) || style === "percent";
513
+ if (PERMILLE_RE.test(formattedNumber)) num = shiftDecimal(num, -3);
514
+ else if (!isUnitPercent && hasPercentSymbol) num = shiftDecimal(num, -2);
515
+ if (!Number.isFinite(num)) return null;
516
+ return num;
517
+ }
518
+
519
+ //#endregion
520
+ //#region src/number-field/root/useNumberFieldButton.ts
521
+ function isTouchLikePointerType(pointerType) {
522
+ return pointerType === "touch" || pointerType === "pen";
523
+ }
524
+ function useNumberFieldButton(params) {
525
+ const { allowInputSyncRef, formatOptionsRef, getStepAmount, incrementValue, inputRef, inputValue, isIncrement, locale, setValue, valueRef, lastChangedValueRef, onValueCommitted } = params;
526
+ const disabled = () => params.disabled();
527
+ const readOnly = () => params.readOnly();
528
+ const pressReason = isIncrement ? REASONS.incrementPress : REASONS.decrementPress;
529
+ function commitValue(nativeEvent) {
530
+ allowInputSyncRef.value = true;
531
+ const parsedValue = parseNumber(inputValue(), locale(), formatOptionsRef.value);
532
+ if (parsedValue !== null) {
533
+ valueRef.value = parsedValue;
534
+ setValue(parsedValue, createChangeEventDetails(pressReason, nativeEvent, void 0, { direction: isIncrement ? 1 : -1 }));
535
+ }
536
+ }
537
+ const { pointerHandlers, shouldSkipClick } = usePressAndHold({
538
+ disabled: () => disabled() || readOnly(),
539
+ elementRef: inputRef,
540
+ tickDelay: CHANGE_VALUE_TICK_DELAY,
541
+ startDelay: START_AUTO_CHANGE_DELAY,
542
+ scrollDistance: SCROLLING_POINTER_MOVE_DISTANCE,
543
+ tick(triggerEvent) {
544
+ return incrementValue(getStepAmount(triggerEvent) ?? DEFAULT_STEP, {
545
+ direction: isIncrement ? 1 : -1,
546
+ event: triggerEvent,
547
+ reason: pressReason
548
+ });
549
+ },
550
+ onStop(nativeEvent) {
551
+ onValueCommitted(lastChangedValueRef.value ?? valueRef.value, createGenericEventDetails(pressReason, nativeEvent));
552
+ }
553
+ });
554
+ return computed(() => ({
555
+ "disabled": disabled(),
556
+ "aria-readonly": readOnly() || void 0,
557
+ "aria-label": isIncrement ? "Increase" : "Decrease",
558
+ "aria-controls": params.id(),
559
+ "tabindex": -1,
560
+ "style": {
561
+ WebkitUserSelect: "none",
562
+ userSelect: "none"
563
+ },
564
+ ...pointerHandlers,
565
+ onClick(event) {
566
+ const isDisabled = disabled() || readOnly();
567
+ if (event.defaultPrevented || isDisabled || shouldSkipClick(event)) return;
568
+ commitValue(event);
569
+ const amount = getStepAmount(event) ?? DEFAULT_STEP;
570
+ const prev = valueRef.value;
571
+ incrementValue(amount, {
572
+ direction: isIncrement ? 1 : -1,
573
+ event,
574
+ reason: pressReason
575
+ });
576
+ const committed = lastChangedValueRef.value ?? valueRef.value;
577
+ if (committed !== prev) onValueCommitted(committed, createGenericEventDetails(pressReason, event));
578
+ },
579
+ onPointerdown(event) {
580
+ const isMainButton = !event.button || event.button === 0;
581
+ if (event.defaultPrevented || readOnly() || !isMainButton || disabled()) return;
582
+ commitValue(event);
583
+ if (!isTouchLikePointerType(event.pointerType)) inputRef.value?.focus();
584
+ pointerHandlers.onPointerdown(event);
585
+ }
586
+ }));
587
+ }
588
+
589
+ //#endregion
590
+ //#region src/number-field/utils/stateAttributesMapping.ts
591
+ const stateAttributesMapping = {
592
+ inputValue: () => null,
593
+ value: () => null,
594
+ ...fieldValidityMapping
595
+ };
596
+
597
+ //#endregion
598
+ //#region src/number-field/decrement/NumberFieldDecrement.vue?vue&type=script&setup=true&lang.ts
599
+ var NumberFieldDecrement_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ */ defineComponent({
600
+ name: "NumberFieldDecrement",
601
+ inheritAttrs: false,
602
+ __name: "NumberFieldDecrement",
603
+ props: {
604
+ disabled: {
605
+ type: Boolean,
606
+ required: false,
607
+ default: false
608
+ },
609
+ nativeButton: {
610
+ type: Boolean,
611
+ required: false,
612
+ default: true
613
+ },
614
+ as: {
615
+ type: null,
616
+ required: false,
617
+ default: "button"
618
+ },
619
+ class: {
620
+ type: Function,
621
+ required: false,
622
+ skipCheck: true
623
+ },
624
+ style: {
625
+ type: [
626
+ Boolean,
627
+ null,
628
+ String,
629
+ Object,
630
+ Array,
631
+ Function
632
+ ],
633
+ required: false,
634
+ skipCheck: true
635
+ }
636
+ },
637
+ setup(__props) {
638
+ const props = __props;
639
+ const attrsObject = useAttrs();
640
+ const { allowInputSyncRef, disabled: contextDisabled, formatOptionsRef, getStepAmount, id, incrementValue, inputRef, inputValue, minWithDefault, readOnly, setValue, state, value, valueRef, locale, lastChangedValueRef, onValueCommitted } = useNumberFieldRootContext();
641
+ const isMin = computed(() => value.value != null && value.value <= minWithDefault.value);
642
+ const disabled = computed(() => props.disabled || contextDisabled.value || isMin.value);
643
+ const buttonProps = useNumberFieldButton({
644
+ isIncrement: false,
645
+ inputRef,
646
+ inputValue: () => inputValue.value,
647
+ disabled: () => disabled.value,
648
+ readOnly: () => readOnly.value,
649
+ id: () => id.value,
650
+ setValue,
651
+ getStepAmount,
652
+ incrementValue,
653
+ allowInputSyncRef,
654
+ formatOptionsRef,
655
+ valueRef,
656
+ locale: () => locale.value,
657
+ lastChangedValueRef,
658
+ onValueCommitted
659
+ });
660
+ const { getButtonProps, buttonRef } = useButton({
661
+ disabled: () => disabled.value,
662
+ native: () => props.nativeButton,
663
+ focusableWhenDisabled: true
664
+ });
665
+ const buttonState = computed(() => ({
666
+ ...state.value,
667
+ disabled: disabled.value
668
+ }));
669
+ const { tag, mergedProps, renderless, ref: renderRef } = useRenderElement({
670
+ componentProps: props,
671
+ state: buttonState,
672
+ props: computed(() => mergeProps$1(buttonProps.value, attrsObject, getButtonProps())),
673
+ stateAttributesMapping,
674
+ defaultTagName: "button",
675
+ ref: buttonRef
676
+ });
677
+ return (_ctx, _cache) => {
678
+ return unref(renderless) ? renderSlot(_ctx.$slots, "default", {
679
+ key: 0,
680
+ ref: unref(renderRef),
681
+ props: unref(mergedProps),
682
+ state: buttonState.value
683
+ }) : (openBlock(), createBlock(resolveDynamicComponent(unref(tag)), mergeProps({
684
+ key: 1,
685
+ ref: unref(renderRef)
686
+ }, unref(mergedProps)), {
687
+ default: withCtx(() => [renderSlot(_ctx.$slots, "default", { state: buttonState.value })]),
688
+ _: 3
689
+ }, 16));
690
+ };
691
+ }
692
+ });
693
+
694
+ //#endregion
695
+ //#region src/number-field/decrement/NumberFieldDecrement.vue
696
+ var NumberFieldDecrement_default = NumberFieldDecrement_vue_vue_type_script_setup_true_lang_default;
697
+
698
+ //#endregion
699
+ export { ANY_MINUS_DETECT_RE, ANY_MINUS_RE, ANY_PLUS_DETECT_RE, ANY_PLUS_RE, ARABIC_DETECT_RE, BASE_NON_NUMERIC_SYMBOLS, DEFAULT_STEP, FULLWIDTH_DETECT_RE, HAN_DETECT_RE, MINUS_SIGNS_WITH_ASCII, NumberFieldDecrement_default, PERCENTAGES, PERMILLE, PERSIAN_DETECT_RE, PLUS_SIGNS_WITH_ASCII, SPACE_SEPARATOR_RE, formatNumber, formatNumberMaxPrecision, formatNumberValue, getFormatter, getNumberLocaleDetails, numberFieldRootContextKey, parseNumber, stateAttributesMapping, useNumberFieldButton, useNumberFieldRootContext, useTimeout };
700
+ //# sourceMappingURL=NumberFieldDecrement.js.map