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/CHANGELOG.md +144 -125
- package/CONTRIBUTING.md +119 -119
- package/README.md +221 -221
- package/dist/esm/index.js.map +1 -1
- package/dist/index.js.map +1 -1
- package/package.json +84 -80
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.
|
package/dist/esm/index.js.map
CHANGED
|
@@ -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);"]}
|