react-intl-number-input 0.8.6 → 0.9.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.
package/dist/esm/index.js CHANGED
@@ -1,272 +1,181 @@
1
1
  import React, { useState, useMemo, useCallback, useEffect, useLayoutEffect, useRef, useImperativeHandle, memo, forwardRef, } from 'react';
2
+ import { resolveLocale, clampToBounds, createDigitMap, stripAffixes, parseNumber, preserveAffixEdit, addStep, } from './number.js';
3
+ // Keep the historical affix normalization for compatibility.
2
4
  function sanitizeString(str) {
3
5
  return str.replace(/<[^>]*>/g, '').replace(/on\w+\s*=\s*["'][^"']*["']/g, '');
4
6
  }
5
- function resolveLocale(locale) {
6
- try {
7
- const supported = Intl.NumberFormat.supportedLocalesOf([locale]);
8
- return supported.length > 0 ? supported[0] : 'en-US';
9
- }
10
- catch (_a) {
11
- return 'en-US';
12
- }
13
- }
14
- function isValidNumber(value) {
15
- return Number.isFinite(value) && !Number.isNaN(value);
16
- }
17
- function clamp(value, min, max) {
18
- return Math.min(Math.max(value, min), max);
19
- }
20
- function clampToBounds(value, min, max) {
21
- let result = value;
22
- if (min !== undefined && result < min) {
23
- result = min;
24
- }
25
- if (max !== undefined && result > max) {
26
- result = max;
27
- }
28
- return result;
7
+ const useIsomorphicLayoutEffect = typeof window !== 'undefined' ? useLayoutEffect : useEffect;
8
+ function createChangeEvent(input) {
9
+ const nativeEvent = new Event('change', { bubbles: true, cancelable: true });
10
+ const event = {
11
+ target: input,
12
+ currentTarget: input,
13
+ nativeEvent,
14
+ bubbles: true,
15
+ bubble: true,
16
+ cancelable: nativeEvent.cancelable,
17
+ get defaultPrevented() { return nativeEvent.defaultPrevented; },
18
+ eventPhase: nativeEvent.eventPhase,
19
+ isTrusted: false,
20
+ timeStamp: nativeEvent.timeStamp,
21
+ type: 'change',
22
+ preventDefault: () => nativeEvent.preventDefault(),
23
+ stopPropagation: () => nativeEvent.stopPropagation(),
24
+ isDefaultPrevented: () => nativeEvent.defaultPrevented,
25
+ isPropagationStopped: () => nativeEvent.cancelBubble,
26
+ persist: () => { },
27
+ };
28
+ return event;
29
29
  }
30
- const IntlNumberInput = forwardRef(function IntlNumberInput({ locale = 'en-US', prefix = '', suffix = '', precision = 2, value, showStepButtons = false, step = 1, minValue, maxValue, inputMode: inputModeProp, onChange, onBlur, disabled = false, renderControls, ...inputProps }, ref) {
30
+ const IntlNumberInput = forwardRef(function IntlNumberInput({ locale = 'en-US', prefix = '', suffix = '', precision = 2, value, controlled = false, showStepButtons = false, step = 1, minValue, maxValue, inputMode: inputModeProp, onChange, onBlur, onKeyDown: onKeyDownProp, disabled = false, renderControls, ...inputProps }, ref) {
31
31
  const innerRef = useRef(null);
32
32
  useImperativeHandle(ref, () => innerRef.current);
33
- const safePrecision = useMemo(() => {
34
- if (typeof precision !== 'number' || Number.isNaN(precision))
35
- return 2;
36
- return clamp(Math.round(precision), 0, 20);
37
- }, [precision]);
38
- const safeStep = useMemo(() => {
39
- if (typeof step !== 'number' || Number.isNaN(step) || step <= 0)
40
- return 1;
41
- return step;
42
- }, [step]);
33
+ const safePrecision = typeof precision !== 'number' || Number.isNaN(precision)
34
+ ? 2 : Math.min(Math.max(Math.round(precision), 0), 20);
35
+ const safeStep = Number.isFinite(step) && step > 0 ? step : 1;
36
+ const safePrefix = useMemo(() => sanitizeString(prefix), [prefix]);
37
+ const safeSuffix = useMemo(() => sanitizeString(suffix), [suffix]);
38
+ const resolvedLocale = useMemo(() => resolveLocale(locale), [locale]);
39
+ const digitMap = useMemo(() => createDigitMap(resolvedLocale), [resolvedLocale]);
40
+ const numberFormatter = useMemo(() => new Intl.NumberFormat(resolvedLocale, {
41
+ minimumFractionDigits: safePrecision, maximumFractionDigits: safePrecision,
42
+ }), [resolvedLocale, safePrecision]);
43
43
  const [effectiveMin, effectiveMax] = useMemo(() => {
44
- if (minValue !== undefined && maxValue !== undefined && minValue > maxValue) {
45
- return [maxValue, minValue];
46
- }
47
- return [minValue, maxValue];
44
+ const min = Number.isFinite(minValue) ? minValue : undefined;
45
+ const max = Number.isFinite(maxValue) ? maxValue : undefined;
46
+ return min !== undefined && max !== undefined && min > max ? [max, min] : [min, max];
48
47
  }, [minValue, maxValue]);
49
- const getPrecisionValue = useCallback((p) => {
50
- return Math.pow(10, p);
51
- }, []);
52
- const getNumberValue = useCallback((strValue) => {
53
- const inputValue = String(strValue || '');
54
- const hasNegativeSign = inputValue.startsWith('-');
55
- const onlyDigits = inputValue.replace(/[^0-9]/g, '');
56
- if (!onlyDigits) {
57
- return hasNegativeSign ? -0 : 0;
58
- }
59
- const numberValue = Number(onlyDigits);
60
- const parsedValue = numberValue / getPrecisionValue(safePrecision);
61
- return hasNegativeSign ? -parsedValue : parsedValue;
62
- }, [getPrecisionValue, safePrecision]);
63
- const numberFormatter = useMemo(() => {
64
- const options = {
65
- style: 'decimal',
66
- minimumFractionDigits: safePrecision,
67
- maximumFractionDigits: safePrecision,
68
- };
69
- const resolvedLocale = resolveLocale(locale);
70
- return new Intl.NumberFormat(resolvedLocale, options);
71
- }, [locale, safePrecision]);
72
- const formatNumber = useCallback((val) => {
73
- let numberValue;
74
- if (typeof val === 'string') {
75
- numberValue = getNumberValue(val);
76
- }
77
- else {
78
- numberValue = val;
48
+ const normalize = useCallback((numeric) => clampToBounds(Number.isFinite(numeric) ? numeric : 0, effectiveMin, effectiveMax), [effectiveMin, effectiveMax]);
49
+ const getNumberValue = useCallback((text) => parseNumber(stripAffixes(text, safePrefix, safeSuffix), digitMap, safePrecision), [safePrefix, safeSuffix, digitMap, safePrecision]);
50
+ const fromProp = () => normalize(typeof value === 'string' ? getNumberValue(value) : value !== null && value !== void 0 ? value : 0);
51
+ const [state, setState] = useState(() => ({ source: value, numeric: fromProp() }));
52
+ const [editVersion, setEditVersion] = useState(0);
53
+ // Synchronize changed external values before rendering. An unchanged value retains
54
+ // the optimistic editing behavior of releases before controlled was introduced.
55
+ let numericValue = controlled ? fromProp() : normalize(state.numeric);
56
+ if (!Object.is(state.source, value)) {
57
+ numericValue = value === undefined && !controlled ? normalize(state.numeric) : fromProp();
58
+ setState({ source: value, numeric: numericValue });
59
+ }
60
+ else if (!controlled && !Object.is(state.numeric, numericValue)) {
61
+ setState({ source: value, numeric: numericValue });
62
+ }
63
+ const formatNumber = useCallback((numeric) => `${safePrefix}${numberFormatter.format(numeric)}${safeSuffix}`, [safePrefix, safeSuffix, numberFormatter]);
64
+ const maskedValue = formatNumber(numericValue);
65
+ // Cache for several custom-control calls in one event; rendered state is numericValue.
66
+ const numericValueRef = useRef(numericValue);
67
+ const selectionRef = useRef(null);
68
+ const countDigits = (text) => Array.from(text).filter((char) => digitMap.has(char)).length;
69
+ useIsomorphicLayoutEffect(() => {
70
+ numericValueRef.current = numericValue;
71
+ if (!selectionRef.current || !innerRef.current)
72
+ return;
73
+ const input = innerRef.current;
74
+ const { digitsBefore } = selectionRef.current;
75
+ const numericText = stripAffixes(input.value, safePrefix, safeSuffix);
76
+ let position = safePrefix.length;
77
+ let found = 0;
78
+ for (const character of numericText) {
79
+ if (found >= digitsBefore)
80
+ break;
81
+ position += character.length;
82
+ if (digitMap.has(character))
83
+ found++;
79
84
  }
80
- if (!isValidNumber(numberValue)) {
81
- numberValue = 0;
85
+ input.setSelectionRange(position, position);
86
+ selectionRef.current = null;
87
+ }, [numericValue, maskedValue, editVersion, safePrefix, safeSuffix, digitMap]);
88
+ const readOnly = !!inputProps.readOnly;
89
+ const commitValue = useCallback((next, event) => {
90
+ if (disabled || readOnly || !Number.isFinite(next))
91
+ return;
92
+ const nextValue = normalize(next);
93
+ const nextMasked = formatNumber(nextValue);
94
+ if (!controlled) {
95
+ numericValueRef.current = nextValue;
96
+ setState((previous) => ({ ...previous, numeric: nextValue }));
82
97
  }
83
- numberValue = clampToBounds(numberValue, effectiveMin, effectiveMax);
84
- const formattedNumber = numberFormatter.format(numberValue);
85
- const safePrefix = sanitizeString(prefix);
86
- const safeSuffix = sanitizeString(suffix);
87
- return `${safePrefix}${formattedNumber}${safeSuffix}`;
88
- }, [getNumberValue, numberFormatter, prefix, suffix, effectiveMin, effectiveMax]);
89
- const getInitialValue = useCallback(() => {
90
- const initial = value !== undefined ? value : 0;
91
- return formatNumber(initial);
92
- }, [value, formatNumber]);
93
- const getInitialNumericValue = useCallback(() => {
94
- const initial = value !== undefined ? value : 0;
95
- if (typeof initial === 'string') {
96
- return getNumberValue(initial);
98
+ // Reapply the caret even if normalization leaves the formatted value unchanged.
99
+ setEditVersion((previous) => previous + 1);
100
+ if (event) {
101
+ onChange === null || onChange === void 0 ? void 0 : onChange(event, nextValue, nextMasked);
97
102
  }
98
- return initial;
99
- }, [value, getNumberValue]);
100
- const [maskedValue, setMaskedValue] = useState(getInitialValue);
101
- const numericValueRef = useRef(getInitialNumericValue());
102
- const selectionRef = useRef(null);
103
- const useIsomorphicLayoutEffect = typeof window !== 'undefined' ? useLayoutEffect : useEffect;
104
- useIsomorphicLayoutEffect(() => {
105
- if (selectionRef.current && innerRef.current) {
106
- const { digitsBefore } = selectionRef.current;
107
- const newValue = innerRef.current.value;
108
- let newPos = 0;
109
- let digitsFound = 0;
110
- for (let i = 0; i < newValue.length; i++) {
111
- if (/\d/.test(newValue[i])) {
112
- digitsFound++;
113
- }
114
- newPos = i + 1;
115
- if (digitsFound >= digitsBefore) {
116
- break;
117
- }
103
+ else if (innerRef.current) {
104
+ const input = innerRef.current;
105
+ input.value = nextMasked;
106
+ try {
107
+ onChange === null || onChange === void 0 ? void 0 : onChange(createChangeEvent(input), nextValue, nextMasked);
108
+ }
109
+ finally {
110
+ input.value = controlled ? maskedValue : nextMasked;
118
111
  }
119
- innerRef.current.setSelectionRange(newPos, newPos);
120
- selectionRef.current = null;
121
112
  }
122
- }, [maskedValue]);
123
- useEffect(() => {
124
- if (value === undefined)
113
+ }, [disabled, readOnly, normalize, formatNumber, controlled, onChange, maskedValue]);
114
+ const handleChange = (event) => {
115
+ var _a;
116
+ if (disabled || readOnly)
125
117
  return;
126
- const numericVal = typeof value === 'string' ? getNumberValue(value) : value;
127
- const clamped = clampToBounds(numericVal, effectiveMin, effectiveMax);
128
- setMaskedValue(formatNumber(clamped));
129
- numericValueRef.current = clamped;
130
- }, [value, formatNumber, getNumberValue, effectiveMin, effectiveMax]);
131
- const handleChange = useCallback((event) => {
132
- const input = event.target;
133
- const selectionStart = input.selectionStart || 0;
134
- const valueBefore = input.value;
135
- const digitsBefore = valueBefore.substring(0, selectionStart).replace(/\D/g, '').length;
136
- selectionRef.current = { digitsBefore };
137
- const rawValue = event.target.value;
138
- const newValue = getNumberValue(rawValue);
139
- if (!isValidNumber(newValue)) {
118
+ const raw = preserveAffixEdit(maskedValue, event.target.value, safePrefix, safeSuffix);
119
+ const numericTextBeforeCaret = stripAffixes(raw.slice(0, (_a = event.target.selectionStart) !== null && _a !== void 0 ? _a : 0), safePrefix, '');
120
+ selectionRef.current = { digitsBefore: countDigits(numericTextBeforeCaret) };
121
+ const next = getNumberValue(raw);
122
+ if (!Number.isFinite(next)) {
123
+ selectionRef.current = null;
140
124
  return;
141
125
  }
142
- const clampedValue = clampToBounds(newValue, effectiveMin, effectiveMax);
143
- const newMaskedValue = formatNumber(clampedValue);
144
- setMaskedValue(newMaskedValue);
145
- numericValueRef.current = clampedValue;
146
- if (onChange) {
147
- onChange(event, clampedValue, newMaskedValue);
126
+ commitValue(next, event);
127
+ };
128
+ const handleBlur = (event) => {
129
+ const raw = event.target.value;
130
+ const parsed = raw === maskedValue || disabled || readOnly ? numericValue : getNumberValue(raw);
131
+ const nextValue = normalize(Number.isFinite(parsed) ? parsed : numericValue);
132
+ if (!controlled && !disabled && !readOnly) {
133
+ numericValueRef.current = nextValue;
134
+ setState((previous) => ({ ...previous, numeric: nextValue }));
148
135
  }
149
- }, [getNumberValue, formatNumber, effectiveMin, effectiveMax, onChange]);
150
- const handleBlur = useCallback((event) => {
151
- const rawValue = event.target.value;
152
- const currentValue = getNumberValue(rawValue);
153
- const clampedValue = clampToBounds(currentValue, effectiveMin, effectiveMax);
154
- const formattedValue = formatNumber(clampedValue);
155
- setMaskedValue(formattedValue);
156
- numericValueRef.current = clampedValue;
157
- if (onBlur) {
158
- onBlur(event, clampedValue, formattedValue);
159
- }
160
- }, [getNumberValue, formatNumber, effectiveMin, effectiveMax, onBlur]);
161
- const handleStep = useCallback((delta, multiplier = 1) => {
162
- if (disabled)
136
+ onBlur === null || onBlur === void 0 ? void 0 : onBlur(event, nextValue, formatNumber(nextValue));
137
+ };
138
+ const handleStep = useCallback((direction, multiplier = 1) => {
139
+ if (!Number.isFinite(multiplier))
163
140
  return;
164
- const currentValue = numericValueRef.current;
165
- const stepValue = (safeStep / Math.pow(10, safePrecision)) * multiplier;
166
- const newValue = clampToBounds(currentValue + delta * stepValue, effectiveMin, effectiveMax);
167
- const newMaskedValue = formatNumber(newValue);
168
- setMaskedValue(newMaskedValue);
169
- numericValueRef.current = newValue;
170
- const syntheticEvent = {
171
- target: {
172
- value: newMaskedValue,
173
- name: inputProps.name || '',
174
- id: inputProps.id || '',
175
- },
176
- currentTarget: {
177
- value: newMaskedValue,
178
- name: inputProps.name || '',
179
- id: inputProps.id || '',
180
- },
181
- persist: () => { },
182
- preventDefault: () => { },
183
- stopPropagation: () => { },
184
- bubble: true,
185
- cancelable: false,
186
- type: 'change',
187
- };
188
- if (onChange) {
189
- onChange(syntheticEvent, newValue, newMaskedValue);
190
- }
191
- }, [
192
- disabled,
193
- safeStep,
194
- safePrecision,
195
- effectiveMin,
196
- effectiveMax,
197
- formatNumber,
198
- onChange,
199
- inputProps.name,
200
- inputProps.id,
201
- ]);
141
+ const delta = direction * (safeStep / Math.pow(10, safePrecision)) * multiplier;
142
+ if (!Number.isFinite(delta))
143
+ return;
144
+ commitValue(addStep(numericValueRef.current, delta));
145
+ }, [safeStep, safePrecision, commitValue]);
202
146
  const increment = useCallback((multiplier = 1) => handleStep(1, multiplier), [handleStep]);
203
147
  const decrement = useCallback((multiplier = 1) => handleStep(-1, multiplier), [handleStep]);
204
- const setValue = useCallback((newValue) => {
205
- const clampedValue = clampToBounds(newValue, effectiveMin, effectiveMax);
206
- const newMaskedValue = formatNumber(clampedValue);
207
- setMaskedValue(newMaskedValue);
208
- numericValueRef.current = clampedValue;
209
- const syntheticEvent = {
210
- target: {
211
- value: newMaskedValue,
212
- name: inputProps.name || '',
213
- id: inputProps.id || '',
214
- },
215
- currentTarget: {
216
- value: newMaskedValue,
217
- name: inputProps.name || '',
218
- id: inputProps.id || '',
219
- },
220
- persist: () => { },
221
- preventDefault: () => { },
222
- stopPropagation: () => { },
223
- bubble: true,
224
- cancelable: false,
225
- type: 'change',
226
- };
227
- if (onChange) {
228
- onChange(syntheticEvent, clampedValue, newMaskedValue);
229
- }
230
- }, [effectiveMin, effectiveMax, formatNumber, onChange, inputProps.name, inputProps.id]);
231
- const inputMode = useMemo(() => {
232
- if (inputModeProp) {
233
- return inputModeProp;
148
+ const setValue = useCallback((next) => commitValue(next), [commitValue]);
149
+ const handleKeyDown = (event) => {
150
+ onKeyDownProp === null || onKeyDownProp === void 0 ? void 0 : onKeyDownProp(event);
151
+ if (event.defaultPrevented || disabled || readOnly)
152
+ return;
153
+ if (event.key === 'ArrowUp' || event.key === 'ArrowDown') {
154
+ event.preventDefault();
155
+ handleStep(event.key === 'ArrowUp' ? 1 : -1, event.shiftKey ? 10 : 1);
234
156
  }
235
- return safePrecision > 0 ? 'decimal' : 'numeric';
236
- }, [inputModeProp, safePrecision]);
237
- const inputElement = (React.createElement("input", { ref: innerRef, type: "text", role: "spinbutton", "aria-valuenow": isValidNumber(numericValueRef.current) ? numericValueRef.current : 0, "aria-valuemin": effectiveMin, "aria-valuemax": effectiveMax, inputMode: inputMode, value: maskedValue, disabled: disabled, onChange: handleChange, onBlur: handleBlur, ...inputProps }));
157
+ };
158
+ const inputElement = React.createElement("input", { ref: innerRef, type: "text", role: "spinbutton", "aria-valuenow": numericValue, "aria-valuemin": effectiveMin, "aria-valuemax": effectiveMax, "aria-valuetext": maskedValue, inputMode: inputModeProp || (safePrecision > 0 ? 'decimal' : 'numeric'), value: maskedValue, disabled: disabled, onChange: handleChange, onBlur: handleBlur, onKeyDown: handleKeyDown, ...inputProps });
238
159
  if (renderControls) {
239
- const controlsProps = {
240
- increment,
241
- decrement,
242
- setValue,
243
- value: numericValueRef.current,
244
- min: effectiveMin,
245
- max: effectiveMax,
246
- disabled,
247
- step: safeStep,
248
- precision: safePrecision,
249
- formattedValue: maskedValue,
250
- };
251
- return (React.createElement(React.Fragment, null,
160
+ return React.createElement(React.Fragment, null,
252
161
  inputElement,
253
- renderControls(controlsProps)));
162
+ renderControls({
163
+ increment, decrement, setValue, value: numericValue,
164
+ min: effectiveMin, max: effectiveMax, disabled, readOnly,
165
+ step: safeStep, precision: safePrecision, formattedValue: maskedValue,
166
+ }));
254
167
  }
255
- if (!showStepButtons) {
168
+ if (!showStepButtons)
256
169
  return inputElement;
257
- }
258
- return (React.createElement("div", { style: { display: 'inline-flex', alignItems: 'center', gap: '4px' } },
259
- React.createElement("button", { type: "button", onClick: () => handleStep(-1), disabled: disabled, "aria-label": "Decrease value", style: {
260
- padding: '4px 8px',
261
- cursor: disabled ? 'not-allowed' : 'pointer',
262
- opacity: disabled ? 0.5 : 1,
263
- } }, "-"),
170
+ const controlsDisabled = disabled || readOnly;
171
+ const buttonStyle = {
172
+ padding: '4px 8px', cursor: controlsDisabled ? 'not-allowed' : 'pointer',
173
+ opacity: controlsDisabled ? 0.5 : 1,
174
+ };
175
+ return React.createElement("div", { style: { display: 'inline-flex', alignItems: 'center', gap: '4px' } },
176
+ React.createElement("button", { type: "button", onClick: () => decrement(), disabled: controlsDisabled, "aria-label": "Decrease value", style: buttonStyle }, "-"),
264
177
  inputElement,
265
- React.createElement("button", { type: "button", onClick: () => handleStep(1), disabled: disabled, "aria-label": "Increase value", style: {
266
- padding: '4px 8px',
267
- cursor: disabled ? 'not-allowed' : 'pointer',
268
- opacity: disabled ? 0.5 : 1,
269
- } }, "+")));
178
+ React.createElement("button", { type: "button", onClick: () => increment(), disabled: controlsDisabled, "aria-label": "Increase value", style: buttonStyle }, "+"));
270
179
  });
271
180
  IntlNumberInput.displayName = 'IntlNumberInput';
272
181
  export default memo(IntlNumberInput);
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.tsx"],"names":[],"mappings":"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","sourcesContent":["import React, {\r\n useState,\r\n useMemo,\r\n useCallback,\r\n useEffect,\r\n useLayoutEffect,\r\n useRef,\r\n useImperativeHandle,\r\n memo,\r\n forwardRef,\r\n} from 'react';\r\n\r\nexport interface ControlsRenderProps {\r\n increment: (multiplier?: number) => void;\r\n decrement: (multiplier?: number) => void;\r\n setValue: (value: number) => void;\r\n value: number;\r\n min?: number;\r\n max?: number;\r\n disabled: boolean;\r\n step: number;\r\n precision: number;\r\n formattedValue: string;\r\n}\r\n\r\ntype IntlNumberInputOwnProps = {\r\n locale?: string;\r\n prefix?: string;\r\n suffix?: string;\r\n precision?: number;\r\n value?: number | string;\r\n showStepButtons?: boolean;\r\n step?: number;\r\n minValue?: number;\r\n maxValue?: number;\r\n inputMode?: 'numeric' | 'decimal';\r\n onChange?: (\r\n event: React.ChangeEvent<HTMLInputElement>,\r\n value: number,\r\n maskedValue: string\r\n ) => void;\r\n onBlur?: (\r\n event: React.FocusEvent<HTMLInputElement>,\r\n value: number,\r\n maskedValue: string\r\n ) => void;\r\n renderControls?: (props: ControlsRenderProps) => React.ReactNode;\r\n};\r\n\r\nexport type IntlNumberInputProps = IntlNumberInputOwnProps &\r\n Omit<\r\n React.ComponentPropsWithoutRef<'input'>,\r\n keyof IntlNumberInputOwnProps | 'value' | 'type' | 'defaultValue' | 'children'\r\n >;\r\n\r\nfunction sanitizeString(str: string): string {\r\n return str.replace(/<[^>]*>/g, '').replace(/on\\w+\\s*=\\s*[\"'][^\"']*[\"']/g, '');\r\n}\r\n\r\nfunction resolveLocale(locale: string): string {\r\n try {\r\n const supported = Intl.NumberFormat.supportedLocalesOf([locale]);\r\n return supported.length > 0 ? supported[0] : 'en-US';\r\n } catch {\r\n return 'en-US';\r\n }\r\n}\r\n\r\nfunction isValidNumber(value: number): boolean {\r\n return Number.isFinite(value) && !Number.isNaN(value);\r\n}\r\n\r\nfunction clamp(value: number, min: number, max: number): number {\r\n return Math.min(Math.max(value, min), max);\r\n}\r\n\r\nfunction clampToBounds(\r\n value: number,\r\n min: number | undefined,\r\n max: number | undefined\r\n): number {\r\n let result = value;\r\n\r\n if (min !== undefined && result < min) {\r\n result = min;\r\n }\r\n\r\n if (max !== undefined && result > max) {\r\n result = max;\r\n }\r\n\r\n return result;\r\n}\r\n\r\nconst IntlNumberInput = forwardRef<HTMLInputElement, IntlNumberInputProps>(\r\n function IntlNumberInput(\r\n {\r\n locale = 'en-US',\r\n prefix = '',\r\n suffix = '',\r\n precision = 2,\r\n value,\r\n showStepButtons = false,\r\n step = 1,\r\n minValue,\r\n maxValue,\r\n inputMode: inputModeProp,\r\n onChange,\r\n onBlur,\r\n disabled = false,\r\n renderControls,\r\n ...inputProps\r\n },\r\n ref\r\n ) {\r\n const innerRef = useRef<HTMLInputElement>(null);\r\n useImperativeHandle(ref, () => innerRef.current!);\r\n\r\n const safePrecision = useMemo(() => {\r\n if (typeof precision !== 'number' || Number.isNaN(precision)) return 2;\r\n return clamp(Math.round(precision), 0, 20);\r\n }, [precision]);\r\n\r\n const safeStep = useMemo(() => {\r\n if (typeof step !== 'number' || Number.isNaN(step) || step <= 0) return 1;\r\n return step;\r\n }, [step]);\r\n\r\n const [effectiveMin, effectiveMax] = useMemo(() => {\r\n if (minValue !== undefined && maxValue !== undefined && minValue > maxValue) {\r\n return [maxValue, minValue] as const;\r\n }\r\n return [minValue, maxValue] as const;\r\n }, [minValue, maxValue]);\r\n\r\n const getPrecisionValue = useCallback((p: number) => {\r\n return Math.pow(10, p);\r\n }, []);\r\n\r\n const getNumberValue = useCallback(\r\n (strValue: string): number => {\r\n const inputValue = String(strValue || '');\r\n const hasNegativeSign = inputValue.startsWith('-');\r\n\r\n const onlyDigits = inputValue.replace(/[^0-9]/g, '');\r\n\r\n if (!onlyDigits) {\r\n return hasNegativeSign ? -0 : 0;\r\n }\r\n\r\n const numberValue = Number(onlyDigits);\r\n const parsedValue = numberValue / getPrecisionValue(safePrecision);\r\n\r\n return hasNegativeSign ? -parsedValue : parsedValue;\r\n },\r\n [getPrecisionValue, safePrecision]\r\n );\r\n\r\n const numberFormatter = useMemo(() => {\r\n const options = {\r\n style: 'decimal' as const,\r\n minimumFractionDigits: safePrecision,\r\n maximumFractionDigits: safePrecision,\r\n };\r\n\r\n const resolvedLocale = resolveLocale(locale);\r\n return new Intl.NumberFormat(resolvedLocale, options);\r\n }, [locale, safePrecision]);\r\n\r\n const formatNumber = useCallback(\r\n (val: number | string): string => {\r\n let numberValue: number;\r\n\r\n if (typeof val === 'string') {\r\n numberValue = getNumberValue(val);\r\n } else {\r\n numberValue = val;\r\n }\r\n\r\n if (!isValidNumber(numberValue)) {\r\n numberValue = 0;\r\n }\r\n\r\n numberValue = clampToBounds(numberValue, effectiveMin, effectiveMax);\r\n\r\n const formattedNumber = numberFormatter.format(numberValue);\r\n const safePrefix = sanitizeString(prefix);\r\n const safeSuffix = sanitizeString(suffix);\r\n\r\n return `${safePrefix}${formattedNumber}${safeSuffix}`;\r\n },\r\n [getNumberValue, numberFormatter, prefix, suffix, effectiveMin, effectiveMax]\r\n );\r\n\r\n const getInitialValue = useCallback(() => {\r\n const initial = value !== undefined ? value : 0;\r\n return formatNumber(initial);\r\n }, [value, formatNumber]);\r\n\r\n const getInitialNumericValue = useCallback(() => {\r\n const initial = value !== undefined ? value : 0;\r\n if (typeof initial === 'string') {\r\n return getNumberValue(initial);\r\n }\r\n return initial;\r\n }, [value, getNumberValue]);\r\n\r\n const [maskedValue, setMaskedValue] = useState<string>(getInitialValue);\r\n const numericValueRef = useRef<number>(getInitialNumericValue());\r\n const selectionRef = useRef<{ digitsBefore: number } | null>(null);\r\n\r\n const useIsomorphicLayoutEffect =\r\n typeof window !== 'undefined' ? useLayoutEffect : useEffect;\r\n\r\n useIsomorphicLayoutEffect(() => {\r\n if (selectionRef.current && innerRef.current) {\r\n const { digitsBefore } = selectionRef.current;\r\n const newValue = innerRef.current.value;\r\n let newPos = 0;\r\n let digitsFound = 0;\r\n\r\n for (let i = 0; i < newValue.length; i++) {\r\n if (/\\d/.test(newValue[i])) {\r\n digitsFound++;\r\n }\r\n newPos = i + 1;\r\n if (digitsFound >= digitsBefore) {\r\n break;\r\n }\r\n }\r\n\r\n innerRef.current.setSelectionRange(newPos, newPos);\r\n selectionRef.current = null;\r\n }\r\n }, [maskedValue]);\r\n\r\n useEffect(() => {\r\n if (value === undefined) return;\r\n const numericVal = typeof value === 'string' ? getNumberValue(value) : value;\r\n const clamped = clampToBounds(numericVal, effectiveMin, effectiveMax);\r\n setMaskedValue(formatNumber(clamped));\r\n numericValueRef.current = clamped;\r\n }, [value, formatNumber, getNumberValue, effectiveMin, effectiveMax]);\r\n\r\n const handleChange = useCallback(\r\n (event: React.ChangeEvent<HTMLInputElement>) => {\r\n const input = event.target;\r\n const selectionStart = input.selectionStart || 0;\r\n const valueBefore = input.value;\r\n const digitsBefore = valueBefore.substring(0, selectionStart).replace(/\\D/g, '').length;\r\n\r\n selectionRef.current = { digitsBefore };\r\n\r\n const rawValue = event.target.value;\r\n const newValue = getNumberValue(rawValue);\r\n\r\n if (!isValidNumber(newValue)) {\r\n return;\r\n }\r\n\r\n const clampedValue = clampToBounds(newValue, effectiveMin, effectiveMax);\r\n const newMaskedValue = formatNumber(clampedValue);\r\n setMaskedValue(newMaskedValue);\r\n numericValueRef.current = clampedValue;\r\n\r\n if (onChange) {\r\n onChange(event, clampedValue, newMaskedValue);\r\n }\r\n },\r\n [getNumberValue, formatNumber, effectiveMin, effectiveMax, onChange]\r\n );\r\n\r\n const handleBlur = useCallback(\r\n (event: React.FocusEvent<HTMLInputElement>) => {\r\n const rawValue = event.target.value;\r\n const currentValue = getNumberValue(rawValue);\r\n const clampedValue = clampToBounds(currentValue, effectiveMin, effectiveMax);\r\n const formattedValue = formatNumber(clampedValue);\r\n\r\n setMaskedValue(formattedValue);\r\n numericValueRef.current = clampedValue;\r\n\r\n if (onBlur) {\r\n onBlur(event, clampedValue, formattedValue);\r\n }\r\n },\r\n [getNumberValue, formatNumber, effectiveMin, effectiveMax, onBlur]\r\n );\r\n\r\n const handleStep = useCallback(\r\n (delta: number, multiplier: number = 1) => {\r\n if (disabled) return;\r\n\r\n const currentValue = numericValueRef.current;\r\n const stepValue = (safeStep / Math.pow(10, safePrecision)) * multiplier;\r\n const newValue = clampToBounds(\r\n currentValue + delta * stepValue,\r\n effectiveMin,\r\n effectiveMax\r\n );\r\n\r\n const newMaskedValue = formatNumber(newValue);\r\n setMaskedValue(newMaskedValue);\r\n numericValueRef.current = newValue;\r\n\r\n const syntheticEvent = {\r\n target: {\r\n value: newMaskedValue,\r\n name: inputProps.name || '',\r\n id: inputProps.id || '',\r\n },\r\n currentTarget: {\r\n value: newMaskedValue,\r\n name: inputProps.name || '',\r\n id: inputProps.id || '',\r\n },\r\n persist: () => {},\r\n preventDefault: () => {},\r\n stopPropagation: () => {},\r\n bubble: true,\r\n cancelable: false,\r\n type: 'change',\r\n } as unknown as React.ChangeEvent<HTMLInputElement>;\r\n\r\n if (onChange) {\r\n onChange(syntheticEvent, newValue, newMaskedValue);\r\n }\r\n },\r\n [\r\n disabled,\r\n safeStep,\r\n safePrecision,\r\n effectiveMin,\r\n effectiveMax,\r\n formatNumber,\r\n onChange,\r\n inputProps.name,\r\n inputProps.id,\r\n ]\r\n );\r\n\r\n const increment = useCallback(\r\n (multiplier: number = 1) => handleStep(1, multiplier),\r\n [handleStep]\r\n );\r\n\r\n const decrement = useCallback(\r\n (multiplier: number = 1) => handleStep(-1, multiplier),\r\n [handleStep]\r\n );\r\n\r\n const setValue = useCallback(\r\n (newValue: number) => {\r\n const clampedValue = clampToBounds(newValue, effectiveMin, effectiveMax);\r\n const newMaskedValue = formatNumber(clampedValue);\r\n setMaskedValue(newMaskedValue);\r\n numericValueRef.current = clampedValue;\r\n\r\n const syntheticEvent = {\r\n target: {\r\n value: newMaskedValue,\r\n name: inputProps.name || '',\r\n id: inputProps.id || '',\r\n },\r\n currentTarget: {\r\n value: newMaskedValue,\r\n name: inputProps.name || '',\r\n id: inputProps.id || '',\r\n },\r\n persist: () => {},\r\n preventDefault: () => {},\r\n stopPropagation: () => {},\r\n bubble: true,\r\n cancelable: false,\r\n type: 'change',\r\n } as unknown as React.ChangeEvent<HTMLInputElement>;\r\n\r\n if (onChange) {\r\n onChange(syntheticEvent, clampedValue, newMaskedValue);\r\n }\r\n },\r\n [effectiveMin, effectiveMax, formatNumber, onChange, inputProps.name, inputProps.id]\r\n );\r\n\r\n const inputMode = useMemo(() => {\r\n if (inputModeProp) {\r\n return inputModeProp;\r\n }\r\n return safePrecision > 0 ? 'decimal' : 'numeric';\r\n }, [inputModeProp, safePrecision]);\r\n\r\n const inputElement = (\r\n <input\r\n ref={innerRef}\r\n type=\"text\"\r\n role=\"spinbutton\"\r\n aria-valuenow={isValidNumber(numericValueRef.current) ? numericValueRef.current : 0}\r\n aria-valuemin={effectiveMin}\r\n aria-valuemax={effectiveMax}\r\n inputMode={inputMode}\r\n value={maskedValue}\r\n disabled={disabled}\r\n onChange={handleChange}\r\n onBlur={handleBlur}\r\n {...inputProps}\r\n />\r\n );\r\n\r\n if (renderControls) {\r\n const controlsProps: ControlsRenderProps = {\r\n increment,\r\n decrement,\r\n setValue,\r\n value: numericValueRef.current,\r\n min: effectiveMin,\r\n max: effectiveMax,\r\n disabled,\r\n step: safeStep,\r\n precision: safePrecision,\r\n formattedValue: maskedValue,\r\n };\r\n\r\n return (\r\n <>\r\n {inputElement}\r\n {renderControls(controlsProps)}\r\n </>\r\n );\r\n }\r\n\r\n if (!showStepButtons) {\r\n return inputElement;\r\n }\r\n\r\n return (\r\n <div style={{ display: 'inline-flex', alignItems: 'center', gap: '4px' }}>\r\n <button\r\n type=\"button\"\r\n onClick={() => handleStep(-1)}\r\n disabled={disabled}\r\n aria-label=\"Decrease value\"\r\n style={{\r\n padding: '4px 8px',\r\n cursor: disabled ? 'not-allowed' : 'pointer',\r\n opacity: disabled ? 0.5 : 1,\r\n }}\r\n >\r\n -\r\n </button>\r\n {inputElement}\r\n <button\r\n type=\"button\"\r\n onClick={() => handleStep(1)}\r\n disabled={disabled}\r\n aria-label=\"Increase value\"\r\n style={{\r\n padding: '4px 8px',\r\n cursor: disabled ? 'not-allowed' : 'pointer',\r\n opacity: disabled ? 0.5 : 1,\r\n }}\r\n >\r\n +\r\n </button>\r\n </div>\r\n );\r\n }\r\n);\r\n\r\nIntlNumberInput.displayName = 'IntlNumberInput';\r\n\r\nexport default memo(IntlNumberInput);"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.tsx"],"names":[],"mappings":"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","sourcesContent":["import React, {\n useState, useMemo, useCallback, useEffect, useLayoutEffect, useRef,\n useImperativeHandle, memo, forwardRef,\n} from 'react';\nimport {\n resolveLocale, clampToBounds, createDigitMap, stripAffixes,\n parseNumber, preserveAffixEdit, addStep,\n} from './number.js';\n\nexport interface ControlsRenderProps {\n increment: (multiplier?: number) => void;\n decrement: (multiplier?: number) => void;\n setValue: (value: number) => void;\n value: number;\n min?: number;\n max?: number;\n disabled: boolean;\n readOnly?: boolean;\n step: number;\n precision: number;\n formattedValue: string;\n}\n\ntype IntlNumberInputOwnProps = {\n locale?: string;\n prefix?: string;\n suffix?: string;\n precision?: number;\n value?: number | string;\n /** Opt in to keeping value authoritative when the parent rejects an edit. */\n controlled?: boolean;\n showStepButtons?: boolean;\n step?: number;\n minValue?: number;\n maxValue?: number;\n inputMode?: 'numeric' | 'decimal';\n onChange?: (event: React.ChangeEvent<HTMLInputElement>, value: number, maskedValue: string) => void;\n onBlur?: (event: React.FocusEvent<HTMLInputElement>, value: number, maskedValue: string) => void;\n renderControls?: (props: ControlsRenderProps) => React.ReactNode;\n};\n\nexport type IntlNumberInputProps = IntlNumberInputOwnProps &\n Omit<React.ComponentPropsWithoutRef<'input'>,\n keyof IntlNumberInputOwnProps | 'value' | 'type' | 'defaultValue' | 'children'>;\n\n// Keep the historical affix normalization for compatibility.\nfunction sanitizeString(str: string): string {\n return str.replace(/<[^>]*>/g, '').replace(/on\\w+\\s*=\\s*[\"'][^\"']*[\"']/g, '');\n}\n\nconst useIsomorphicLayoutEffect = typeof window !== 'undefined' ? useLayoutEffect : useEffect;\n\nfunction createChangeEvent(input: HTMLInputElement): React.ChangeEvent<HTMLInputElement> {\n const nativeEvent = new Event('change', { bubbles: true, cancelable: true });\n const event: React.ChangeEvent<HTMLInputElement> & { bubble: boolean } = {\n target: input,\n currentTarget: input,\n nativeEvent,\n bubbles: true,\n bubble: true,\n cancelable: nativeEvent.cancelable,\n get defaultPrevented() { return nativeEvent.defaultPrevented; },\n eventPhase: nativeEvent.eventPhase,\n isTrusted: false,\n timeStamp: nativeEvent.timeStamp,\n type: 'change',\n preventDefault: () => nativeEvent.preventDefault(),\n stopPropagation: () => nativeEvent.stopPropagation(),\n isDefaultPrevented: () => nativeEvent.defaultPrevented,\n isPropagationStopped: () => nativeEvent.cancelBubble,\n persist: () => {},\n };\n return event;\n}\n\nconst IntlNumberInput = forwardRef<HTMLInputElement, IntlNumberInputProps>(\n function IntlNumberInput({\n locale = 'en-US', prefix = '', suffix = '', precision = 2, value,\n controlled = false, showStepButtons = false, step = 1, minValue, maxValue,\n inputMode: inputModeProp, onChange, onBlur, onKeyDown: onKeyDownProp,\n disabled = false, renderControls, ...inputProps\n }, ref) {\n const innerRef = useRef<HTMLInputElement>(null);\n useImperativeHandle(ref, () => innerRef.current!);\n const safePrecision = typeof precision !== 'number' || Number.isNaN(precision)\n ? 2 : Math.min(Math.max(Math.round(precision), 0), 20);\n const safeStep = Number.isFinite(step) && step > 0 ? step : 1;\n const safePrefix = useMemo(() => sanitizeString(prefix), [prefix]);\n const safeSuffix = useMemo(() => sanitizeString(suffix), [suffix]);\n const resolvedLocale = useMemo(() => resolveLocale(locale), [locale]);\n const digitMap = useMemo(() => createDigitMap(resolvedLocale), [resolvedLocale]);\n const numberFormatter = useMemo(() => new Intl.NumberFormat(resolvedLocale, {\n minimumFractionDigits: safePrecision, maximumFractionDigits: safePrecision,\n }), [resolvedLocale, safePrecision]);\n const [effectiveMin, effectiveMax] = useMemo(() => {\n const min = Number.isFinite(minValue) ? minValue : undefined;\n const max = Number.isFinite(maxValue) ? maxValue : undefined;\n return min !== undefined && max !== undefined && min > max ? [max, min] : [min, max];\n }, [minValue, maxValue]);\n const normalize = useCallback((numeric: number) =>\n clampToBounds(Number.isFinite(numeric) ? numeric : 0, effectiveMin, effectiveMax),\n [effectiveMin, effectiveMax]);\n const getNumberValue = useCallback((text: string) =>\n parseNumber(stripAffixes(text, safePrefix, safeSuffix), digitMap, safePrecision),\n [safePrefix, safeSuffix, digitMap, safePrecision]);\n const fromProp = () => normalize(typeof value === 'string' ? getNumberValue(value) : value ?? 0);\n const [state, setState] = useState(() => ({ source: value, numeric: fromProp() }));\n const [editVersion, setEditVersion] = useState(0);\n // Synchronize changed external values before rendering. An unchanged value retains\n // the optimistic editing behavior of releases before controlled was introduced.\n let numericValue = controlled ? fromProp() : normalize(state.numeric);\n if (!Object.is(state.source, value)) {\n numericValue = value === undefined && !controlled ? normalize(state.numeric) : fromProp();\n setState({ source: value, numeric: numericValue });\n } else if (!controlled && !Object.is(state.numeric, numericValue)) {\n setState({ source: value, numeric: numericValue });\n }\n const formatNumber = useCallback((numeric: number) =>\n `${safePrefix}${numberFormatter.format(numeric)}${safeSuffix}`,\n [safePrefix, safeSuffix, numberFormatter]);\n const maskedValue = formatNumber(numericValue);\n // Cache for several custom-control calls in one event; rendered state is numericValue.\n const numericValueRef = useRef(numericValue);\n const selectionRef = useRef<{ digitsBefore: number } | null>(null);\n const countDigits = (text: string) => Array.from(text).filter((char) => digitMap.has(char)).length;\n\n useIsomorphicLayoutEffect(() => {\n numericValueRef.current = numericValue;\n if (!selectionRef.current || !innerRef.current) return;\n const input = innerRef.current;\n const { digitsBefore } = selectionRef.current;\n const numericText = stripAffixes(input.value, safePrefix, safeSuffix);\n let position = safePrefix.length;\n let found = 0;\n for (const character of numericText) {\n if (found >= digitsBefore) break;\n position += character.length;\n if (digitMap.has(character)) found++;\n }\n input.setSelectionRange(position, position);\n selectionRef.current = null;\n }, [numericValue, maskedValue, editVersion, safePrefix, safeSuffix, digitMap]);\n\n const readOnly = !!inputProps.readOnly;\n const commitValue = useCallback((next: number, event?: React.ChangeEvent<HTMLInputElement>) => {\n if (disabled || readOnly || !Number.isFinite(next)) return;\n const nextValue = normalize(next);\n const nextMasked = formatNumber(nextValue);\n if (!controlled) {\n numericValueRef.current = nextValue;\n setState((previous) => ({ ...previous, numeric: nextValue }));\n }\n // Reapply the caret even if normalization leaves the formatted value unchanged.\n setEditVersion((previous) => previous + 1);\n if (event) {\n onChange?.(event, nextValue, nextMasked);\n } else if (innerRef.current) {\n const input = innerRef.current;\n input.value = nextMasked;\n try {\n onChange?.(createChangeEvent(input), nextValue, nextMasked);\n } finally {\n input.value = controlled ? maskedValue : nextMasked;\n }\n }\n }, [disabled, readOnly, normalize, formatNumber, controlled, onChange, maskedValue]);\n\n const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {\n if (disabled || readOnly) return;\n const raw = preserveAffixEdit(maskedValue, event.target.value, safePrefix, safeSuffix);\n const numericTextBeforeCaret = stripAffixes(raw.slice(0, event.target.selectionStart ?? 0), safePrefix, '');\n selectionRef.current = { digitsBefore: countDigits(numericTextBeforeCaret) };\n const next = getNumberValue(raw);\n if (!Number.isFinite(next)) {\n selectionRef.current = null;\n return;\n }\n commitValue(next, event);\n };\n\n const handleBlur = (event: React.FocusEvent<HTMLInputElement>) => {\n const raw = event.target.value;\n const parsed = raw === maskedValue || disabled || readOnly ? numericValue : getNumberValue(raw);\n const nextValue = normalize(Number.isFinite(parsed) ? parsed : numericValue);\n if (!controlled && !disabled && !readOnly) {\n numericValueRef.current = nextValue;\n setState((previous) => ({ ...previous, numeric: nextValue }));\n }\n onBlur?.(event, nextValue, formatNumber(nextValue));\n };\n\n const handleStep = useCallback((direction: number, multiplier = 1) => {\n if (!Number.isFinite(multiplier)) return;\n const delta = direction * (safeStep / Math.pow(10, safePrecision)) * multiplier;\n if (!Number.isFinite(delta)) return;\n commitValue(addStep(numericValueRef.current, delta));\n }, [safeStep, safePrecision, commitValue]);\n const increment = useCallback((multiplier = 1) => handleStep(1, multiplier), [handleStep]);\n const decrement = useCallback((multiplier = 1) => handleStep(-1, multiplier), [handleStep]);\n const setValue = useCallback((next: number) => commitValue(next), [commitValue]);\n const handleKeyDown = (event: React.KeyboardEvent<HTMLInputElement>) => {\n onKeyDownProp?.(event);\n if (event.defaultPrevented || disabled || readOnly) return;\n if (event.key === 'ArrowUp' || event.key === 'ArrowDown') {\n event.preventDefault();\n handleStep(event.key === 'ArrowUp' ? 1 : -1, event.shiftKey ? 10 : 1);\n }\n };\n\n const inputElement = <input\n ref={innerRef} type=\"text\" role=\"spinbutton\"\n aria-valuenow={numericValue} aria-valuemin={effectiveMin} aria-valuemax={effectiveMax}\n aria-valuetext={maskedValue}\n inputMode={inputModeProp || (safePrecision > 0 ? 'decimal' : 'numeric')}\n value={maskedValue} disabled={disabled}\n onChange={handleChange} onBlur={handleBlur} onKeyDown={handleKeyDown}\n {...inputProps}\n />;\n if (renderControls) {\n return <>{inputElement}{renderControls({\n increment, decrement, setValue, value: numericValue,\n min: effectiveMin, max: effectiveMax, disabled, readOnly,\n step: safeStep, precision: safePrecision, formattedValue: maskedValue,\n })}</>;\n }\n if (!showStepButtons) return inputElement;\n const controlsDisabled = disabled || readOnly;\n const buttonStyle = {\n padding: '4px 8px', cursor: controlsDisabled ? 'not-allowed' : 'pointer',\n opacity: controlsDisabled ? 0.5 : 1,\n };\n return <div style={{ display: 'inline-flex', alignItems: 'center', gap: '4px' }}>\n <button type=\"button\" onClick={() => decrement()} disabled={controlsDisabled}\n aria-label=\"Decrease value\" style={buttonStyle}>-</button>\n {inputElement}\n <button type=\"button\" onClick={() => increment()} disabled={controlsDisabled}\n aria-label=\"Increase value\" style={buttonStyle}>+</button>\n </div>;\n }\n);\n\nIntlNumberInput.displayName = 'IntlNumberInput';\nexport default memo(IntlNumberInput);\r\n"]}
@@ -0,0 +1,7 @@
1
+ export declare function resolveLocale(locale: string): string;
2
+ export declare function clampToBounds(value: number, min?: number, max?: number): number;
3
+ export declare function createDigitMap(locale: string): Map<string, string>;
4
+ export declare function stripAffixes(text: string, prefix: string, suffix: string): string;
5
+ export declare function parseNumber(text: string, digits: Map<string, string>, precision: number): number;
6
+ export declare function preserveAffixEdit(previous: string, next: string, prefix: string, suffix: string): string;
7
+ export declare function addStep(value: number, delta: number): number;
@@ -0,0 +1,73 @@
1
+ export function resolveLocale(locale) {
2
+ try {
3
+ return Intl.NumberFormat.supportedLocalesOf([locale])[0] || 'en-US';
4
+ }
5
+ catch (_a) {
6
+ return 'en-US';
7
+ }
8
+ }
9
+ export function clampToBounds(value, min, max) {
10
+ return Math.min(Math.max(value, min !== null && min !== void 0 ? min : -Infinity), max !== null && max !== void 0 ? max : Infinity);
11
+ }
12
+ export function createDigitMap(locale) {
13
+ const formatter = new Intl.NumberFormat(locale, { useGrouping: false });
14
+ const digits = new Map();
15
+ for (let digit = 0; digit <= 9; digit++) {
16
+ const ascii = String(digit);
17
+ const localized = formatter.formatToParts(digit)
18
+ .filter((part) => part.type === 'integer').map((part) => part.value).join('');
19
+ digits.set(ascii, ascii);
20
+ digits.set(localized, ascii);
21
+ }
22
+ return digits;
23
+ }
24
+ export function stripAffixes(text, prefix, suffix) {
25
+ if (prefix && text.startsWith(prefix))
26
+ text = text.slice(prefix.length);
27
+ if (suffix && text.endsWith(suffix))
28
+ text = text.slice(0, -suffix.length);
29
+ return text;
30
+ }
31
+ export function parseNumber(text, digits, precision) {
32
+ const negative = /[-\u2212]/.test(text);
33
+ const ascii = Array.from(text).map((character) => digits.get(character) || '').join('');
34
+ // Insert the implied decimal before conversion to avoid overflowing a digit string
35
+ // that represents a finite number after scaling, and unnecessary double rounding.
36
+ const padded = ascii.padStart(precision + 1, '0');
37
+ const decimal = precision === 0 ? padded
38
+ : `${padded.slice(0, -precision)}.${padded.slice(-precision)}`;
39
+ const numeric = Number(decimal);
40
+ return negative ? -numeric : numeric;
41
+ }
42
+ export function preserveAffixEdit(previous, next, prefix, suffix) {
43
+ let start = 0;
44
+ while (start < previous.length && start < next.length && previous[start] === next[start])
45
+ start++;
46
+ let end = previous.length;
47
+ let nextEnd = next.length;
48
+ while (end > start && nextEnd > start && previous[end - 1] === next[nextEnd - 1]) {
49
+ end--;
50
+ nextEnd--;
51
+ }
52
+ const numericEnd = previous.length - suffix.length;
53
+ const onlyPrefix = prefix.length > 0 && start < prefix.length && end <= prefix.length;
54
+ const onlySuffix = suffix.length > 0 && start >= numericEnd && end > numericEnd;
55
+ return onlyPrefix || onlySuffix ? previous : next;
56
+ }
57
+ function decimalPlaces(value) {
58
+ var _a;
59
+ const [mantissa, exponent = '0'] = String(value).toLowerCase().split('e');
60
+ return Math.max(0, (((_a = mantissa.split('.')[1]) === null || _a === void 0 ? void 0 : _a.length) || 0) - Number(exponent));
61
+ }
62
+ export function addStep(value, delta) {
63
+ const places = Math.max(decimalPlaces(value), decimalPlaces(delta));
64
+ const factor = Math.pow(10, places);
65
+ const scaledValue = Math.round(value * factor);
66
+ const scaledDelta = Math.round(delta * factor);
67
+ const sum = scaledValue + scaledDelta;
68
+ if (Number.isSafeInteger(scaledValue) && Number.isSafeInteger(scaledDelta) && Number.isSafeInteger(sum)) {
69
+ return sum / factor;
70
+ }
71
+ return value + delta;
72
+ }
73
+ //# sourceMappingURL=number.js.map