numora-react 1.0.0 → 1.0.2
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 +289 -47
- package/dist/index.cjs.js +71 -434
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.d.ts +16 -7
- package/dist/index.esm.js +65 -435
- package/dist/index.esm.js.map +1 -1
- package/package.json +17 -7
- package/dist/types/index.d.ts +0 -2
- package/rollup.config.mjs +0 -38
- package/src/index.tsx +0 -50
- package/tsconfig.json +0 -18
package/README.md
CHANGED
|
@@ -1,73 +1,315 @@
|
|
|
1
|
-
# numora
|
|
1
|
+
# numora-react
|
|
2
2
|
|
|
3
|
-
[](https://www.npmjs.com/package/numora)
|
|
3
|
+
[](https://www.npmjs.com/package/numora-react)
|
|
4
|
+
[](https://www.npmjs.com/package/numora-react)
|
|
4
5
|
|
|
5
|
-
|
|
6
|
+
React component wrapper for [Numora](https://github.com/Sharqiewicz/numora) - a precision-first numeric input library for DeFi and financial applications.
|
|
6
7
|
|
|
7
|
-
|
|
8
|
-
- **Type safety** - fully typed API for better developer experience
|
|
9
|
-
- **Framework agnostic** - use with any framework or vanilla JavaScript
|
|
10
|
-
- **Customizable** - extensive options to fit your specific needs
|
|
8
|
+
## Features
|
|
11
9
|
|
|
12
|
-
|
|
10
|
+
| Feature | Description |
|
|
11
|
+
|---------|-------------|
|
|
12
|
+
| **React Component** | Drop-in replacement for `<input>` with numeric formatting |
|
|
13
|
+
| **Decimal Precision Control** | Configure maximum decimal places with `maxDecimals` prop |
|
|
14
|
+
| **Thousand Separators** | Customizable thousand separators with `thousandsSeparator` prop |
|
|
15
|
+
| **Grouping Styles** | Support for different grouping styles (`thousand`, `lakh`, `wan`) |
|
|
16
|
+
| **Format on Blur/Change** | Choose when to apply formatting: on blur or on change |
|
|
17
|
+
| **Compact Notation Expansion** | When enabled via `shorthandParsing`, expands compact notation during paste (e.g., `"1k"` → `"1000"`, `"1.5m"` → `"1500000"`) |
|
|
18
|
+
| **Scientific Notation Expansion** | Always automatically expands scientific notation (e.g., `"1.5e-7"` → `"0.00000015"`, `"2e+5"` → `"200000"`) |
|
|
19
|
+
| **Paste Event Handling** | Intelligent paste handling with automatic sanitization, formatting, and cursor positioning |
|
|
20
|
+
| **Cursor Position Preservation** | Smart cursor positioning that works with thousand separators, even during formatting |
|
|
21
|
+
| **Thousand Separator Skipping** | On delete/backspace, cursor automatically skips over thousand separators for better UX |
|
|
22
|
+
| **Mobile Keyboard Optimization** | Automatic `inputmode="decimal"` for mobile numeric keyboards |
|
|
23
|
+
| **Mobile Keyboard Filtering** | Automatically filters non-breaking spaces and Unicode whitespace artifacts from mobile keyboards |
|
|
24
|
+
| **Non-numeric Character Filtering** | Automatic removal of invalid characters |
|
|
25
|
+
| **Comma/Dot Conversion** | When `thousandsGroupStyle` is not set (or `None`), typing comma or dot automatically converts to the configured decimal separator |
|
|
26
|
+
| **TypeScript Support** | Full TypeScript definitions included |
|
|
27
|
+
| **Ref Forwarding** | Supports React ref forwarding for direct input access |
|
|
28
|
+
| **Standard Input Props** | Accepts all standard HTMLInputElement props |
|
|
13
29
|
|
|
14
|
-
|
|
30
|
+
**Note:** Some advanced features from the core package (like `decimalMinLength`, `enableNegative`, `enableLeadingZeros`, `rawValueMode`) are not yet exposed through the React component props. For full control, consider using the core `numora` package directly.
|
|
15
31
|
|
|
16
|
-
##
|
|
32
|
+
## Comparison
|
|
17
33
|
|
|
18
|
-
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
34
|
+
| Feature | numora-react | react-number-format | Native Number Input |
|
|
35
|
+
|---------|--------------|---------------------|---------------------|
|
|
36
|
+
| **React Component** | ✅ Yes | ✅ Yes | ⚠️ Basic |
|
|
37
|
+
| **Decimal Precision Control** | ✅ Max | ✅ Max | ❌ Limited |
|
|
38
|
+
| **Thousand Separators** | ✅ Customizable | ✅ Yes | ❌ No |
|
|
39
|
+
| **Custom Decimal Separator** | ✅ Yes | ✅ Yes | ❌ No (always `.`) |
|
|
40
|
+
| **Formatting Options** | ✅ Blur/Change modes | ✅ Multiple modes | ❌ No |
|
|
41
|
+
| **Cursor Preservation** | ✅ Advanced | ✅ Basic | ❌ N/A |
|
|
42
|
+
| **Mobile Support** | ✅ Yes | ✅ Yes | ⚠️ Limited |
|
|
43
|
+
| **TypeScript Support** | ✅ Yes | ✅ Yes | ⚠️ Partial |
|
|
44
|
+
| **Dependencies** | ⚠️ React + numora | ⚠️ React required | ✅ None |
|
|
45
|
+
| **Framework Support** | ✅ React | ❌ React only | ✅ All |
|
|
46
|
+
| **Scientific Notation** | ✅ Auto-expand | ⚠️ Limited | ❌ No |
|
|
47
|
+
| **Compact Notation** | ✅ Yes (on paste when enabled) | ❌ No | ❌ No |
|
|
48
|
+
| **Paste Handling** | ✅ Intelligent | ✅ Yes | ⚠️ Basic |
|
|
49
|
+
| **Ref Forwarding** | ✅ Yes | ✅ Yes | ✅ Yes |
|
|
50
|
+
| **Grouping Styles** | ✅ Thousand/Lakh/Wan | ⚠️ Thousand only | ❌ No |
|
|
51
|
+
| **Comma/Dot Conversion** | ✅ Yes | ⚠️ Limited | ❌ No |
|
|
25
52
|
|
|
26
53
|
## Installation
|
|
27
54
|
|
|
28
55
|
```bash
|
|
29
|
-
npm install numora
|
|
56
|
+
npm install numora-react
|
|
30
57
|
# or
|
|
31
|
-
yarn add numora
|
|
58
|
+
yarn add numora-react
|
|
32
59
|
# or
|
|
33
|
-
pnpm add numora
|
|
60
|
+
pnpm add numora-react
|
|
34
61
|
```
|
|
35
62
|
|
|
63
|
+
**Note:** `numora-react` depends on `numora` core package, which will be installed automatically.
|
|
64
|
+
|
|
36
65
|
## Usage
|
|
37
66
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
}
|
|
67
|
+
### Basic Example
|
|
68
|
+
|
|
69
|
+
```tsx
|
|
70
|
+
import { NumericInput } from 'numora-react';
|
|
71
|
+
|
|
72
|
+
function App() {
|
|
73
|
+
return (
|
|
74
|
+
<NumericInput
|
|
75
|
+
maxDecimals={2}
|
|
76
|
+
onChange={(e) => {
|
|
77
|
+
console.log('Value:', e.target.value);
|
|
78
|
+
}}
|
|
79
|
+
/>
|
|
80
|
+
);
|
|
81
|
+
}
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
### Advanced Example
|
|
85
|
+
|
|
86
|
+
```tsx
|
|
87
|
+
import { NumericInput } from 'numora-react';
|
|
88
|
+
import { useRef } from 'react';
|
|
89
|
+
|
|
90
|
+
function PaymentForm() {
|
|
91
|
+
const inputRef = useRef<HTMLInputElement>(null);
|
|
92
|
+
|
|
93
|
+
return (
|
|
94
|
+
<NumericInput
|
|
95
|
+
ref={inputRef}
|
|
96
|
+
maxDecimals={18}
|
|
97
|
+
formatOn="change"
|
|
98
|
+
thousandsSeparator=","
|
|
99
|
+
thousandsGroupStyle="thousand"
|
|
100
|
+
shorthandParsing={true} // Enable compact notation expansion on paste
|
|
101
|
+
placeholder="Enter amount"
|
|
102
|
+
className="payment-input"
|
|
103
|
+
onChange={(e) => {
|
|
104
|
+
const value = e.target.value;
|
|
105
|
+
console.log('Formatted value:', value);
|
|
106
|
+
}}
|
|
107
|
+
onFocus={(e) => {
|
|
108
|
+
console.log('Input focused');
|
|
109
|
+
}}
|
|
110
|
+
onBlur={(e) => {
|
|
111
|
+
console.log('Input blurred');
|
|
112
|
+
}}
|
|
113
|
+
/>
|
|
114
|
+
);
|
|
115
|
+
}
|
|
53
116
|
```
|
|
54
117
|
|
|
55
|
-
|
|
118
|
+
### Compact Notation Example
|
|
119
|
+
|
|
120
|
+
```tsx
|
|
121
|
+
import { NumericInput } from 'numora-react';
|
|
122
|
+
|
|
123
|
+
function App() {
|
|
124
|
+
return (
|
|
125
|
+
<NumericInput
|
|
126
|
+
maxDecimals={18}
|
|
127
|
+
shorthandParsing={true} // Enable compact notation expansion
|
|
128
|
+
onChange={(e) => {
|
|
129
|
+
console.log('Value:', e.target.value);
|
|
130
|
+
}}
|
|
131
|
+
/>
|
|
132
|
+
);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// When user pastes "1.5k", it automatically expands to "1500"
|
|
136
|
+
// Scientific notation like "1.5e-7" is always automatically expanded
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
### Scientific Notation Example
|
|
140
|
+
|
|
141
|
+
```tsx
|
|
142
|
+
import { NumericInput } from 'numora-react';
|
|
143
|
+
|
|
144
|
+
function App() {
|
|
145
|
+
return (
|
|
146
|
+
<NumericInput
|
|
147
|
+
maxDecimals={18}
|
|
148
|
+
onChange={(e) => {
|
|
149
|
+
console.log('Value:', e.target.value);
|
|
150
|
+
}}
|
|
151
|
+
/>
|
|
152
|
+
);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
// Scientific notation is ALWAYS automatically expanded
|
|
156
|
+
// User can paste "1.5e-7" and it becomes "0.00000015"
|
|
157
|
+
// User can paste "2e+5" and it becomes "200000"
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
### With Form Libraries
|
|
161
|
+
|
|
162
|
+
#### React Hook Form
|
|
163
|
+
|
|
164
|
+
```tsx
|
|
165
|
+
import { useForm } from 'react-hook-form';
|
|
166
|
+
import { NumericInput } from 'numora-react';
|
|
167
|
+
|
|
168
|
+
function Form() {
|
|
169
|
+
const { register, handleSubmit } = useForm();
|
|
170
|
+
|
|
171
|
+
return (
|
|
172
|
+
<form onSubmit={handleSubmit((data) => console.log(data))}>
|
|
173
|
+
<NumericInput
|
|
174
|
+
{...register('amount')}
|
|
175
|
+
maxDecimals={2}
|
|
176
|
+
thousandsSeparator=","
|
|
177
|
+
/>
|
|
178
|
+
<button type="submit">Submit</button>
|
|
179
|
+
</form>
|
|
180
|
+
);
|
|
181
|
+
}
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
#### Formik
|
|
185
|
+
|
|
186
|
+
```tsx
|
|
187
|
+
import { useFormik } from 'formik';
|
|
188
|
+
import { NumericInput } from 'numora-react';
|
|
56
189
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
190
|
+
function Form() {
|
|
191
|
+
const formik = useFormik({
|
|
192
|
+
initialValues: { amount: '' },
|
|
193
|
+
onSubmit: (values) => {
|
|
194
|
+
console.log(values);
|
|
195
|
+
},
|
|
196
|
+
});
|
|
63
197
|
|
|
64
|
-
|
|
198
|
+
return (
|
|
199
|
+
<form onSubmit={formik.handleSubmit}>
|
|
200
|
+
<NumericInput
|
|
201
|
+
name="amount"
|
|
202
|
+
value={formik.values.amount}
|
|
203
|
+
onChange={formik.handleChange}
|
|
204
|
+
onBlur={formik.handleBlur}
|
|
205
|
+
maxDecimals={2}
|
|
206
|
+
thousandsSeparator=","
|
|
207
|
+
/>
|
|
208
|
+
<button type="submit">Submit</button>
|
|
209
|
+
</form>
|
|
210
|
+
);
|
|
211
|
+
}
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
### Controlled Component
|
|
215
|
+
|
|
216
|
+
```tsx
|
|
217
|
+
import { NumericInput } from 'numora-react';
|
|
218
|
+
import { useState } from 'react';
|
|
219
|
+
|
|
220
|
+
function ControlledInput() {
|
|
221
|
+
const [value, setValue] = useState('');
|
|
222
|
+
|
|
223
|
+
return (
|
|
224
|
+
<NumericInput
|
|
225
|
+
value={value}
|
|
226
|
+
onChange={(e) => setValue(e.target.value)}
|
|
227
|
+
maxDecimals={2}
|
|
228
|
+
thousandsSeparator=","
|
|
229
|
+
/>
|
|
230
|
+
);
|
|
231
|
+
}
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
### Uncontrolled Component
|
|
235
|
+
|
|
236
|
+
```tsx
|
|
237
|
+
import { NumericInput } from 'numora-react';
|
|
238
|
+
import { useRef } from 'react';
|
|
239
|
+
|
|
240
|
+
function UncontrolledInput() {
|
|
241
|
+
const inputRef = useRef<HTMLInputElement>(null);
|
|
242
|
+
|
|
243
|
+
const handleSubmit = () => {
|
|
244
|
+
const value = inputRef.current?.value;
|
|
245
|
+
console.log('Value:', value);
|
|
246
|
+
};
|
|
247
|
+
|
|
248
|
+
return (
|
|
249
|
+
<>
|
|
250
|
+
<NumericInput
|
|
251
|
+
ref={inputRef}
|
|
252
|
+
maxDecimals={2}
|
|
253
|
+
thousandsSeparator=","
|
|
254
|
+
/>
|
|
255
|
+
<button onClick={handleSubmit}>Get Value</button>
|
|
256
|
+
</>
|
|
257
|
+
);
|
|
258
|
+
}
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
## Props
|
|
262
|
+
|
|
263
|
+
| Prop | Type | Default | Description |
|
|
264
|
+
|------|------|---------|-------------|
|
|
265
|
+
| `maxDecimals` | `number` | `2` | Maximum number of decimal places allowed |
|
|
266
|
+
| `formatOn` | `'blur' \| 'change'` | `'blur'` | When to apply formatting: `'blur'` or `'change'` |
|
|
267
|
+
| `thousandsSeparator` | `string` | `','` | Character used as thousand separator |
|
|
268
|
+
| `thousandsGroupStyle` | `'thousand' \| 'lakh' \| 'wan'` | `'thousand'` | Grouping style for thousand separators |
|
|
269
|
+
| `shorthandParsing` | `boolean` | `false` | Enable compact notation expansion (e.g., `"1k"` → `"1000"`) on paste |
|
|
270
|
+
| `onChange` | `(e: ChangeEvent<HTMLInputElement> \| ClipboardEvent<HTMLInputElement>) => void` | `undefined` | Callback when value changes |
|
|
271
|
+
| `additionalStyle` | `string` | `undefined` | Additional CSS styles (deprecated, use `style` prop) |
|
|
272
|
+
|
|
273
|
+
All standard HTMLInputElement props are also supported (e.g., `placeholder`, `className`, `disabled`, `id`, `onFocus`, `onBlur`, etc.), except:
|
|
274
|
+
- `type` - Always set to `'text'` (required for formatting)
|
|
275
|
+
- `inputMode` - Always set to `'decimal'` (for mobile keyboards)
|
|
276
|
+
|
|
277
|
+
**Note:** Scientific notation expansion (e.g., `"1.5e-7"` → `"0.00000015"`) always happens automatically and is not configurable.
|
|
278
|
+
|
|
279
|
+
## API Reference
|
|
280
|
+
|
|
281
|
+
### NumericInput
|
|
282
|
+
|
|
283
|
+
A React component that wraps the core Numora functionality in a React-friendly API.
|
|
284
|
+
|
|
285
|
+
**Props:** See [Props](#props) section above.
|
|
286
|
+
|
|
287
|
+
**Ref:** The component forwards refs to the underlying `<input>` element.
|
|
288
|
+
|
|
289
|
+
## TypeScript
|
|
290
|
+
|
|
291
|
+
Full TypeScript support is included. The component is typed with proper interfaces:
|
|
292
|
+
|
|
293
|
+
```tsx
|
|
294
|
+
import { NumericInput } from 'numora-react';
|
|
295
|
+
|
|
296
|
+
// All props are fully typed
|
|
297
|
+
const input = (
|
|
298
|
+
<NumericInput
|
|
299
|
+
maxDecimals={18} // ✅ TypeScript knows this is a number
|
|
300
|
+
formatOn="change" // ✅ TypeScript knows valid values
|
|
301
|
+
shorthandParsing={true} // ✅ TypeScript knows this is boolean
|
|
302
|
+
onChange={(e) => {
|
|
303
|
+
// ✅ e is properly typed as ChangeEvent<HTMLInputElement>
|
|
304
|
+
console.log(e.target.value);
|
|
305
|
+
}}
|
|
306
|
+
/>
|
|
307
|
+
);
|
|
308
|
+
```
|
|
65
309
|
|
|
66
|
-
|
|
310
|
+
## Related Packages
|
|
67
311
|
|
|
68
|
-
-
|
|
69
|
-
- Vue: `numora-vue` (in progress)
|
|
70
|
-
- Svelte: `numora`
|
|
312
|
+
- [`numora`](../core/README.md) - Core framework-agnostic library with full feature set and display formatting utilities
|
|
71
313
|
|
|
72
314
|
## License
|
|
73
315
|
|