react-intl-number-input 0.8.4 → 0.8.6

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/README.md CHANGED
@@ -1,222 +1,222 @@
1
- # react-intl-number-input
2
-
3
- A React component for masked and formatted number input with `Intl.NumberFormat` locale support.
4
-
5
- [Demo](https://nandorip.github.io/react-intl-number-input/example/dist/)
6
-
7
- ## Requirements
8
-
9
- - React: `>=16.8.0 <20`
10
-
11
- ## Install
12
-
13
- ```bash
14
- npm install react-intl-number-input
15
- ```
16
-
17
- ## Usage
18
-
19
- ```javascript
20
- import React, { useState } from 'react';
21
- import IntlNumberInput from 'react-intl-number-input';
22
-
23
- function App() {
24
- const [value, setValue] = useState(0);
25
- const [maskedValue, setMaskedValue] = useState('0.00');
26
-
27
- const handleChange = (event, nextValue, nextMaskedValue) => {
28
- setValue(nextValue);
29
- setMaskedValue(nextMaskedValue);
30
- };
31
-
32
- return (
33
- <div>
34
- <IntlNumberInput onChange={handleChange} />
35
- <p>value: {value}</p>
36
- <p>maskedValue: {maskedValue}</p>
37
- </div>
38
- );
39
- }
40
- ```
41
-
42
- ### TypeScript
43
-
44
- ```tsx
45
- import React, { useState } from 'react';
46
- import IntlNumberInput, {
47
- IntlNumberInputProps,
48
- } from 'react-intl-number-input';
49
-
50
- function App() {
51
- const [value, setValue] = useState<number>(0);
52
-
53
- const handleChange: IntlNumberInputProps['onChange'] = (event, val, masked) => {
54
- setValue(val);
55
- console.log('Numeric:', val, 'Masked:', masked);
56
- };
57
-
58
- return <IntlNumberInput value={value} onChange={handleChange} locale="pt-BR" />;
59
- }
60
- ```
61
-
62
- React 18+:
63
-
64
- ```javascript
65
- import { createRoot } from 'react-dom/client';
66
-
67
- const root = createRoot(document.getElementById('root'));
68
- root.render(<App />);
69
- ```
70
-
71
- React 16/17:
72
-
73
- ```javascript
74
- import ReactDOM from 'react-dom';
75
-
76
- ReactDOM.render(<App />, document.getElementById('root'));
77
- ```
78
-
79
- ## Properties
80
-
81
- | Name | Type | Default | Description |
82
- | --- | --- | :---: | --- |
83
- | value | `number` \| `string` | `0` | Controlled numeric value |
84
- | locale | `string` | `'en-US'` | BCP 47 language tag ([Intl locales](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl#locale_identification_and_negotiation)) |
85
- | prefix | `string` | `''` | Prefix shown in the masked value |
86
- | suffix | `string` | `''` | Suffix shown in the masked value |
87
- | precision | `number` | `2` | Fraction digits (clamped to `0`–`20`) |
88
- | onChange | `function` | — | `(event, value, maskedValue) => void` |
89
- | onBlur | `function` | — | `(event, value, maskedValue) => void` |
90
- | disabled | `boolean` | `false` | Disables the input |
91
- | autoFocus | `boolean` | — | Native input autofocus |
92
- | minValue | `number` | — | Minimum allowed value |
93
- | maxValue | `number` | — | Maximum allowed value |
94
- | showStepButtons | `boolean` | `false` | Renders built-in +/- step buttons (ignored when `renderControls` is set) |
95
- | renderControls | `function` | — | `(props: ControlsRenderProps) => ReactNode` — custom stepper UI |
96
- | step | `number` | `1` | Step increment in display units (e.g. `1` with `precision={2}` adds `0.01`) |
97
- | inputMode | `'numeric'` \| `'decimal'` | auto | Overrides mobile keyboard mode |
98
- | className | `string` | — | Input CSS class |
99
- | style | `object` | — | Input inline styles |
100
- | id | `string` | — | Input id |
101
- | name | `string` | — | Input name |
102
- | placeholder | `string` | — | Input placeholder |
103
- | readOnly | `boolean` | — | Read-only input |
104
- | required | `boolean` | — | Required input |
105
- | tabIndex | `number` | — | Input tab index |
106
-
107
- The component also accepts standard `<input>` attributes such as `ref`, `onFocus`, `onKeyDown`, `aria-*`, `data-*`, and `autoComplete`. Custom `onChange` and `onBlur` callbacks receive the clamped numeric value and the formatted masked string.
108
-
109
- ## Accessibility (a11y)
110
-
111
- The component is built with accessibility in mind:
112
- - Uses `role="spinbutton"` to identify as a numeric input.
113
- - Provides `aria-valuenow`, `aria-valuemin`, and `aria-valuemax` attributes.
114
- - Support for `forwardRef` allows linking labels and managing focus programmatically.
115
- - Built-in step buttons have descriptive `aria-label` attributes.
116
-
117
- ## Examples
118
-
119
- ### Basic Usage
120
-
121
- ```javascript
122
- // maskedValue: 1,234,567.89
123
- <IntlNumberInput />
124
- ```
125
-
126
- ```javascript
127
- // maskedValue: 12,345.6789
128
- <IntlNumberInput precision={4} />
129
- ```
130
-
131
- ```javascript
132
- // maskedValue: $1,234,567.89
133
- <IntlNumberInput prefix="$" />
134
- ```
135
-
136
- ```javascript
137
- // maskedValue: 1,234%
138
- <IntlNumberInput suffix="%" precision={0} />
139
- ```
140
-
141
- ```javascript
142
- // maskedValue: 12.50% — type digits only; decimal is implied by precision
143
- <IntlNumberInput suffix="%" precision={2} />
144
- ```
145
-
146
- ```javascript
147
- // maskedValue: R$ 1.234.567,89
148
- <IntlNumberInput locale="pt-BR" prefix="R$ " precision={2} />
149
- ```
150
-
151
- ```javascript
152
- // With min/max and step buttons
153
- <IntlNumberInput
154
- value={50}
155
- minValue={0}
156
- maxValue={100}
157
- step={5}
158
- precision={0}
159
- showStepButtons
160
- onChange={(event, value) => console.log(value)}
161
- />
162
- ```
163
-
164
- ```javascript
165
- // Custom controls (layout is up to you — wrap in a parent div as needed)
166
- <div className="amount-field">
167
- <IntlNumberInput
168
- value={12.34}
169
- precision={2}
170
- step={1}
171
- minValue={0}
172
- maxValue={100}
173
- onChange={(event, value) => console.log(value)}
174
- renderControls={({ increment, decrement, setValue, value, formattedValue, min, max, disabled }) => (
175
- <div className="amount-controls">
176
- <button type="button" onClick={() => decrement()} disabled={disabled}>-</button>
177
- <span>{formattedValue}</span>
178
- <button type="button" onClick={() => increment()} disabled={disabled}>+</button>
179
- <button type="button" onClick={() => setValue(max ?? value)} disabled={disabled}>
180
- Max
181
- </button>
182
- </div>
183
- )}
184
- />
185
- </div>
186
- ```
187
-
188
- ### Programmatic Focus (ref)
189
-
190
- ```javascript
191
- import React, { useRef } from 'react';
192
- import IntlNumberInput from 'react-intl-number-input';
193
-
194
- function FocusExample() {
195
- const inputRef = useRef(null);
196
-
197
- return (
198
- <>
199
- <IntlNumberInput ref={inputRef} />
200
- <button onClick={() => inputRef.current?.focus()}>
201
- Focus Input
202
- </button>
203
- </>
204
- );
205
- }
206
- ```
207
-
208
- `renderControls` replaces `showStepButtons` when both are provided. The component renders the `<input>` and your controls as siblings (no wrapper), so you control layout in the parent.
209
-
210
- ## How input works
211
-
212
- Users type digits; the component applies locale formatting and optional prefix/suffix. For `precision={2}`, typing `1234` becomes `12.34`. Negative values are supported when `-` is present in the input.
213
-
214
- ## Contributing
215
-
216
- See [CONTRIBUTING.md](CONTRIBUTING.md) for development setup, testing, and publishing instructions.
217
-
218
- Local development requires Node.js 20+. The published package has no Node.js version constraint for consumers.
219
-
220
- ## Changelog
221
-
1
+ # react-intl-number-input
2
+
3
+ A React component for masked and formatted number input with `Intl.NumberFormat` locale support.
4
+
5
+ [Demo](https://nandorip.github.io/react-intl-number-input/example/dist/)
6
+
7
+ ## Requirements
8
+
9
+ - React: `>=16.8.0 <20`
10
+
11
+ ## Install
12
+
13
+ ```bash
14
+ npm install react-intl-number-input
15
+ ```
16
+
17
+ ## Usage
18
+
19
+ ```javascript
20
+ import React, { useState } from 'react';
21
+ import IntlNumberInput from 'react-intl-number-input';
22
+
23
+ function App() {
24
+ const [value, setValue] = useState(0);
25
+ const [maskedValue, setMaskedValue] = useState('0.00');
26
+
27
+ const handleChange = (event, nextValue, nextMaskedValue) => {
28
+ setValue(nextValue);
29
+ setMaskedValue(nextMaskedValue);
30
+ };
31
+
32
+ return (
33
+ <div>
34
+ <IntlNumberInput onChange={handleChange} />
35
+ <p>value: {value}</p>
36
+ <p>maskedValue: {maskedValue}</p>
37
+ </div>
38
+ );
39
+ }
40
+ ```
41
+
42
+ ### TypeScript
43
+
44
+ ```tsx
45
+ import React, { useState } from 'react';
46
+ import IntlNumberInput, {
47
+ IntlNumberInputProps,
48
+ } from 'react-intl-number-input';
49
+
50
+ function App() {
51
+ const [value, setValue] = useState<number>(0);
52
+
53
+ const handleChange: IntlNumberInputProps['onChange'] = (event, val, masked) => {
54
+ setValue(val);
55
+ console.log('Numeric:', val, 'Masked:', masked);
56
+ };
57
+
58
+ return <IntlNumberInput value={value} onChange={handleChange} locale="pt-BR" />;
59
+ }
60
+ ```
61
+
62
+ React 18+:
63
+
64
+ ```javascript
65
+ import { createRoot } from 'react-dom/client';
66
+
67
+ const root = createRoot(document.getElementById('root'));
68
+ root.render(<App />);
69
+ ```
70
+
71
+ React 16/17:
72
+
73
+ ```javascript
74
+ import ReactDOM from 'react-dom';
75
+
76
+ ReactDOM.render(<App />, document.getElementById('root'));
77
+ ```
78
+
79
+ ## Properties
80
+
81
+ | Name | Type | Default | Description |
82
+ | --- | --- | :---: | --- |
83
+ | value | `number` \| `string` | `0` | Controlled numeric value |
84
+ | locale | `string` | `'en-US'` | BCP 47 language tag ([Intl locales](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl#locale_identification_and_negotiation)) |
85
+ | prefix | `string` | `''` | Prefix shown in the masked value |
86
+ | suffix | `string` | `''` | Suffix shown in the masked value |
87
+ | precision | `number` | `2` | Fraction digits (clamped to `0`–`20`) |
88
+ | onChange | `function` | — | `(event, value, maskedValue) => void` |
89
+ | onBlur | `function` | — | `(event, value, maskedValue) => void` |
90
+ | disabled | `boolean` | `false` | Disables the input |
91
+ | autoFocus | `boolean` | — | Native input autofocus |
92
+ | minValue | `number` | — | Minimum allowed value |
93
+ | maxValue | `number` | — | Maximum allowed value |
94
+ | showStepButtons | `boolean` | `false` | Renders built-in +/- step buttons (ignored when `renderControls` is set) |
95
+ | renderControls | `function` | — | `(props: ControlsRenderProps) => ReactNode` — custom stepper UI |
96
+ | step | `number` | `1` | Step increment in display units (e.g. `1` with `precision={2}` adds `0.01`) |
97
+ | inputMode | `'numeric'` \| `'decimal'` | auto | Overrides mobile keyboard mode |
98
+ | className | `string` | — | Input CSS class |
99
+ | style | `object` | — | Input inline styles |
100
+ | id | `string` | — | Input id |
101
+ | name | `string` | — | Input name |
102
+ | placeholder | `string` | — | Input placeholder |
103
+ | readOnly | `boolean` | — | Read-only input |
104
+ | required | `boolean` | — | Required input |
105
+ | tabIndex | `number` | — | Input tab index |
106
+
107
+ The component also accepts standard `<input>` attributes such as `ref`, `onFocus`, `onKeyDown`, `aria-*`, `data-*`, and `autoComplete`. Custom `onChange` and `onBlur` callbacks receive the clamped numeric value and the formatted masked string.
108
+
109
+ ## Accessibility (a11y)
110
+
111
+ The component is built with accessibility in mind:
112
+ - Uses `role="spinbutton"` to identify as a numeric input.
113
+ - Provides `aria-valuenow`, `aria-valuemin`, and `aria-valuemax` attributes.
114
+ - Support for `forwardRef` allows linking labels and managing focus programmatically.
115
+ - Built-in step buttons have descriptive `aria-label` attributes.
116
+
117
+ ## Examples
118
+
119
+ ### Basic Usage
120
+
121
+ ```javascript
122
+ // maskedValue: 1,234,567.89
123
+ <IntlNumberInput />
124
+ ```
125
+
126
+ ```javascript
127
+ // maskedValue: 12,345.6789
128
+ <IntlNumberInput precision={4} />
129
+ ```
130
+
131
+ ```javascript
132
+ // maskedValue: $1,234,567.89
133
+ <IntlNumberInput prefix="$" />
134
+ ```
135
+
136
+ ```javascript
137
+ // maskedValue: 1,234%
138
+ <IntlNumberInput suffix="%" precision={0} />
139
+ ```
140
+
141
+ ```javascript
142
+ // maskedValue: 12.50% — type digits only; decimal is implied by precision
143
+ <IntlNumberInput suffix="%" precision={2} />
144
+ ```
145
+
146
+ ```javascript
147
+ // maskedValue: R$ 1.234.567,89
148
+ <IntlNumberInput locale="pt-BR" prefix="R$ " precision={2} />
149
+ ```
150
+
151
+ ```javascript
152
+ // With min/max and step buttons
153
+ <IntlNumberInput
154
+ value={50}
155
+ minValue={0}
156
+ maxValue={100}
157
+ step={5}
158
+ precision={0}
159
+ showStepButtons
160
+ onChange={(event, value) => console.log(value)}
161
+ />
162
+ ```
163
+
164
+ ```javascript
165
+ // Custom controls (layout is up to you — wrap in a parent div as needed)
166
+ <div className="amount-field">
167
+ <IntlNumberInput
168
+ value={12.34}
169
+ precision={2}
170
+ step={1}
171
+ minValue={0}
172
+ maxValue={100}
173
+ onChange={(event, value) => console.log(value)}
174
+ renderControls={({ increment, decrement, setValue, value, formattedValue, min, max, disabled }) => (
175
+ <div className="amount-controls">
176
+ <button type="button" onClick={() => decrement()} disabled={disabled}>-</button>
177
+ <span>{formattedValue}</span>
178
+ <button type="button" onClick={() => increment()} disabled={disabled}>+</button>
179
+ <button type="button" onClick={() => setValue(max ?? value)} disabled={disabled}>
180
+ Max
181
+ </button>
182
+ </div>
183
+ )}
184
+ />
185
+ </div>
186
+ ```
187
+
188
+ ### Programmatic Focus (ref)
189
+
190
+ ```javascript
191
+ import React, { useRef } from 'react';
192
+ import IntlNumberInput from 'react-intl-number-input';
193
+
194
+ function FocusExample() {
195
+ const inputRef = useRef(null);
196
+
197
+ return (
198
+ <>
199
+ <IntlNumberInput ref={inputRef} />
200
+ <button onClick={() => inputRef.current?.focus()}>
201
+ Focus Input
202
+ </button>
203
+ </>
204
+ );
205
+ }
206
+ ```
207
+
208
+ `renderControls` replaces `showStepButtons` when both are provided. The component renders the `<input>` and your controls as siblings (no wrapper), so you control layout in the parent.
209
+
210
+ ## How input works
211
+
212
+ Users type digits; the component applies locale formatting and optional prefix/suffix. For `precision={2}`, typing `1234` becomes `12.34`. Negative values are supported when `-` is present in the input.
213
+
214
+ ## Contributing
215
+
216
+ See [CONTRIBUTING.md](CONTRIBUTING.md) for development setup, testing, and publishing instructions.
217
+
218
+ Local development requires Node.js 20+. The published package has no Node.js version constraint for consumers.
219
+
220
+ ## Changelog
221
+
222
222
  See [CHANGELOG.md](CHANGELOG.md) for release history.
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.tsx"],"names":[],"mappings":"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","sourcesContent":["import React, {\n useState,\n useMemo,\n useCallback,\n useEffect,\n useLayoutEffect,\n useRef,\n useImperativeHandle,\n memo,\n forwardRef,\n} from 'react';\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 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 showStepButtons?: boolean;\n step?: number;\n minValue?: number;\n maxValue?: number;\n inputMode?: 'numeric' | 'decimal';\n onChange?: (\n event: React.ChangeEvent<HTMLInputElement>,\n value: number,\n maskedValue: string\n ) => void;\n onBlur?: (\n event: React.FocusEvent<HTMLInputElement>,\n value: number,\n maskedValue: string\n ) => void;\n renderControls?: (props: ControlsRenderProps) => React.ReactNode;\n};\n\nexport type IntlNumberInputProps = IntlNumberInputOwnProps &\n Omit<\n React.ComponentPropsWithoutRef<'input'>,\n keyof IntlNumberInputOwnProps | 'value' | 'type' | 'defaultValue' | 'children'\n >;\n\nfunction sanitizeString(str: string): string {\n return str.replace(/<[^>]*>/g, '').replace(/on\\w+\\s*=\\s*[\"'][^\"']*[\"']/g, '');\n}\n\nfunction resolveLocale(locale: string): string {\n try {\n const supported = Intl.NumberFormat.supportedLocalesOf([locale]);\n return supported.length > 0 ? supported[0] : 'en-US';\n } catch {\n return 'en-US';\n }\n}\n\nfunction isValidNumber(value: number): boolean {\n return Number.isFinite(value) && !Number.isNaN(value);\n}\n\nfunction clamp(value: number, min: number, max: number): number {\n return Math.min(Math.max(value, min), max);\n}\n\nfunction clampToBounds(\n value: number,\n min: number | undefined,\n max: number | undefined\n): number {\n let result = value;\n\n if (min !== undefined && result < min) {\n result = min;\n }\n\n if (max !== undefined && result > max) {\n result = max;\n }\n\n return result;\n}\n\nconst IntlNumberInput = forwardRef<HTMLInputElement, IntlNumberInputProps>(\n function IntlNumberInput(\n {\n locale = 'en-US',\n prefix = '',\n suffix = '',\n precision = 2,\n value,\n showStepButtons = false,\n step = 1,\n minValue,\n maxValue,\n inputMode: inputModeProp,\n onChange,\n onBlur,\n disabled = false,\n renderControls,\n ...inputProps\n },\n ref\n ) {\n const innerRef = useRef<HTMLInputElement>(null);\n useImperativeHandle(ref, () => innerRef.current!);\n\n const safePrecision = useMemo(() => {\n if (typeof precision !== 'number' || Number.isNaN(precision)) return 2;\n return clamp(Math.round(precision), 0, 20);\n }, [precision]);\n\n const safeStep = useMemo(() => {\n if (typeof step !== 'number' || Number.isNaN(step) || step <= 0) return 1;\n return step;\n }, [step]);\n\n const [effectiveMin, effectiveMax] = useMemo(() => {\n if (minValue !== undefined && maxValue !== undefined && minValue > maxValue) {\n return [maxValue, minValue] as const;\n }\n return [minValue, maxValue] as const;\n }, [minValue, maxValue]);\n\n const getPrecisionValue = useCallback((p: number) => {\n return Math.pow(10, p);\n }, []);\n\n const getNumberValue = useCallback(\n (strValue: string): number => {\n const inputValue = String(strValue || '');\n const hasNegativeSign = inputValue.startsWith('-');\n\n const onlyDigits = inputValue.replace(/[^0-9]/g, '');\n\n if (!onlyDigits) {\n return hasNegativeSign ? -0 : 0;\n }\n\n const numberValue = Number(onlyDigits);\n const parsedValue = numberValue / getPrecisionValue(safePrecision);\n\n return hasNegativeSign ? -parsedValue : parsedValue;\n },\n [getPrecisionValue, safePrecision]\n );\n\n const numberFormatter = useMemo(() => {\n const options = {\n style: 'decimal' as const,\n minimumFractionDigits: safePrecision,\n maximumFractionDigits: safePrecision,\n };\n\n const resolvedLocale = resolveLocale(locale);\n return new Intl.NumberFormat(resolvedLocale, options);\n }, [locale, safePrecision]);\n\n const formatNumber = useCallback(\n (val: number | string): string => {\n let numberValue: number;\n\n if (typeof val === 'string') {\n numberValue = getNumberValue(val);\n } else {\n numberValue = val;\n }\n\n if (!isValidNumber(numberValue)) {\n numberValue = 0;\n }\n\n numberValue = clampToBounds(numberValue, effectiveMin, effectiveMax);\n\n const formattedNumber = numberFormatter.format(numberValue);\n const safePrefix = sanitizeString(prefix);\n const safeSuffix = sanitizeString(suffix);\n\n return `${safePrefix}${formattedNumber}${safeSuffix}`;\n },\n [getNumberValue, numberFormatter, prefix, suffix, effectiveMin, effectiveMax]\n );\n\n const getInitialValue = useCallback(() => {\n const initial = value !== undefined ? value : 0;\n return formatNumber(initial);\n }, [value, formatNumber]);\n\n const getInitialNumericValue = useCallback(() => {\n const initial = value !== undefined ? value : 0;\n if (typeof initial === 'string') {\n return getNumberValue(initial);\n }\n return initial;\n }, [value, getNumberValue]);\n\n const [maskedValue, setMaskedValue] = useState<string>(getInitialValue);\n const numericValueRef = useRef<number>(getInitialNumericValue());\n const selectionRef = useRef<{ digitsBefore: number } | null>(null);\n\n const useIsomorphicLayoutEffect =\n typeof window !== 'undefined' ? useLayoutEffect : useEffect;\n\n useIsomorphicLayoutEffect(() => {\n if (selectionRef.current && innerRef.current) {\n const { digitsBefore } = selectionRef.current;\n const newValue = innerRef.current.value;\n let newPos = 0;\n let digitsFound = 0;\n\n for (let i = 0; i < newValue.length; i++) {\n if (/\\d/.test(newValue[i])) {\n digitsFound++;\n }\n newPos = i + 1;\n if (digitsFound >= digitsBefore) {\n break;\n }\n }\n\n innerRef.current.setSelectionRange(newPos, newPos);\n selectionRef.current = null;\n }\n }, [maskedValue]);\n\n useEffect(() => {\n if (value === undefined) return;\n const numericVal = typeof value === 'string' ? getNumberValue(value) : value;\n const clamped = clampToBounds(numericVal, effectiveMin, effectiveMax);\n setMaskedValue(formatNumber(clamped));\n numericValueRef.current = clamped;\n }, [value, formatNumber, getNumberValue, effectiveMin, effectiveMax]);\n\n const handleChange = useCallback(\n (event: React.ChangeEvent<HTMLInputElement>) => {\n const input = event.target;\n const selectionStart = input.selectionStart || 0;\n const valueBefore = input.value;\n const digitsBefore = valueBefore.substring(0, selectionStart).replace(/\\D/g, '').length;\n\n selectionRef.current = { digitsBefore };\n\n const rawValue = event.target.value;\n const newValue = getNumberValue(rawValue);\n\n if (!isValidNumber(newValue)) {\n return;\n }\n\n const clampedValue = clampToBounds(newValue, effectiveMin, effectiveMax);\n const newMaskedValue = formatNumber(clampedValue);\n setMaskedValue(newMaskedValue);\n numericValueRef.current = clampedValue;\n\n if (onChange) {\n onChange(event, clampedValue, newMaskedValue);\n }\n },\n [getNumberValue, formatNumber, effectiveMin, effectiveMax, onChange]\n );\n\n const handleBlur = useCallback(\n (event: React.FocusEvent<HTMLInputElement>) => {\n const rawValue = event.target.value;\n const currentValue = getNumberValue(rawValue);\n const clampedValue = clampToBounds(currentValue, effectiveMin, effectiveMax);\n const formattedValue = formatNumber(clampedValue);\n\n setMaskedValue(formattedValue);\n numericValueRef.current = clampedValue;\n\n if (onBlur) {\n onBlur(event, clampedValue, formattedValue);\n }\n },\n [getNumberValue, formatNumber, effectiveMin, effectiveMax, onBlur]\n );\n\n const handleStep = useCallback(\n (delta: number, multiplier: number = 1) => {\n if (disabled) return;\n\n const currentValue = numericValueRef.current;\n const stepValue = (safeStep / Math.pow(10, safePrecision)) * multiplier;\n const newValue = clampToBounds(\n currentValue + delta * stepValue,\n effectiveMin,\n effectiveMax\n );\n\n const newMaskedValue = formatNumber(newValue);\n setMaskedValue(newMaskedValue);\n numericValueRef.current = newValue;\n\n const syntheticEvent = {\n target: {\n value: newMaskedValue,\n name: inputProps.name || '',\n id: inputProps.id || '',\n },\n currentTarget: {\n value: newMaskedValue,\n name: inputProps.name || '',\n id: inputProps.id || '',\n },\n persist: () => {},\n preventDefault: () => {},\n stopPropagation: () => {},\n bubble: true,\n cancelable: false,\n type: 'change',\n } as unknown as React.ChangeEvent<HTMLInputElement>;\n\n if (onChange) {\n onChange(syntheticEvent, newValue, newMaskedValue);\n }\n },\n [\n disabled,\n safeStep,\n safePrecision,\n effectiveMin,\n effectiveMax,\n formatNumber,\n onChange,\n inputProps.name,\n inputProps.id,\n ]\n );\n\n const increment = useCallback(\n (multiplier: number = 1) => handleStep(1, multiplier),\n [handleStep]\n );\n\n const decrement = useCallback(\n (multiplier: number = 1) => handleStep(-1, multiplier),\n [handleStep]\n );\n\n const setValue = useCallback(\n (newValue: number) => {\n const clampedValue = clampToBounds(newValue, effectiveMin, effectiveMax);\n const newMaskedValue = formatNumber(clampedValue);\n setMaskedValue(newMaskedValue);\n numericValueRef.current = clampedValue;\n\n const syntheticEvent = {\n target: {\n value: newMaskedValue,\n name: inputProps.name || '',\n id: inputProps.id || '',\n },\n currentTarget: {\n value: newMaskedValue,\n name: inputProps.name || '',\n id: inputProps.id || '',\n },\n persist: () => {},\n preventDefault: () => {},\n stopPropagation: () => {},\n bubble: true,\n cancelable: false,\n type: 'change',\n } as unknown as React.ChangeEvent<HTMLInputElement>;\n\n if (onChange) {\n onChange(syntheticEvent, clampedValue, newMaskedValue);\n }\n },\n [effectiveMin, effectiveMax, formatNumber, onChange, inputProps.name, inputProps.id]\n );\n\n const inputMode = useMemo(() => {\n if (inputModeProp) {\n return inputModeProp;\n }\n return safePrecision > 0 ? 'decimal' : 'numeric';\n }, [inputModeProp, safePrecision]);\n\n const inputElement = (\n <input\n ref={innerRef}\n type=\"text\"\n role=\"spinbutton\"\n aria-valuenow={isValidNumber(numericValueRef.current) ? numericValueRef.current : 0}\n aria-valuemin={effectiveMin}\n aria-valuemax={effectiveMax}\n inputMode={inputMode}\n value={maskedValue}\n disabled={disabled}\n onChange={handleChange}\n onBlur={handleBlur}\n {...inputProps}\n />\n );\n\n if (renderControls) {\n const controlsProps: ControlsRenderProps = {\n increment,\n decrement,\n setValue,\n value: numericValueRef.current,\n min: effectiveMin,\n max: effectiveMax,\n disabled,\n step: safeStep,\n precision: safePrecision,\n formattedValue: maskedValue,\n };\n\n return (\n <>\n {inputElement}\n {renderControls(controlsProps)}\n </>\n );\n }\n\n if (!showStepButtons) {\n return inputElement;\n }\n\n return (\n <div style={{ display: 'inline-flex', alignItems: 'center', gap: '4px' }}>\n <button\n type=\"button\"\n onClick={() => handleStep(-1)}\n disabled={disabled}\n aria-label=\"Decrease value\"\n style={{\n padding: '4px 8px',\n cursor: disabled ? 'not-allowed' : 'pointer',\n opacity: disabled ? 0.5 : 1,\n }}\n >\n -\n </button>\n {inputElement}\n <button\n type=\"button\"\n onClick={() => handleStep(1)}\n disabled={disabled}\n aria-label=\"Increase value\"\n style={{\n padding: '4px 8px',\n cursor: disabled ? 'not-allowed' : 'pointer',\n opacity: disabled ? 0.5 : 1,\n }}\n >\n +\n </button>\n </div>\n );\n }\n);\n\nIntlNumberInput.displayName = 'IntlNumberInput';\n\nexport default memo(IntlNumberInput);"]}
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);"]}