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 CHANGED
@@ -1,73 +1,315 @@
1
- # numora
1
+ # numora-react
2
2
 
3
- [![npm version](https://img.shields.io/npm/v/numora.svg)](https://www.npmjs.com/package/numora)
3
+ [![npm version](https://img.shields.io/npm/v/numora-react.svg)](https://www.npmjs.com/package/numora-react)
4
+ [![npm downloads](https://img.shields.io/npm/dm/numora-react.svg)](https://www.npmjs.com/package/numora-react)
4
5
 
5
- A lightweight, framework-agnostic numeric input library for handling currency and decimal inputs in **financial/DeFi** applications. Built with TypeScript and designed for modern web applications with:
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
- - **Zero dependencies** - minimal footprint for your bundle
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
- ## Demo
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
- Check out the [live demo](https://numora.netlify.app/) to see Numora in action.
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
- ## Features
32
+ ## Comparison
17
33
 
18
- - Validates and sanitizes numeric input
19
- - Limits decimal places
20
- - Handles paste events
21
- - Converts commas to dots
22
- - Prevents multiple decimal points
23
- - Customizable with various options
24
- - Framework-agnostic core with adapters for popular frameworks
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
- ```typescript
39
- import { NumericInput } from 'numora';
40
-
41
- // Get the container element where you want to mount the input
42
- const container = document.querySelector('#my-input-container');
43
-
44
- // Create a new NumericInput instance
45
- const numericInput = new NumericInput(container, {
46
- maxDecimals: 2,
47
- onChange: (value) => {
48
- console.log('Value changed:', value);
49
- // Do something with the value
50
- },
51
- // ... all other input properties you want
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
- ## Options
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
- The NumericInput constructor accepts the following options:
58
- | Option | Type | Default | Description |
59
- | --------------- | -------- | --------- | -------------------------------------------------------- |
60
- | maxDecimals | number | 2 | Maximum number of decimal places allowed |
61
- | onChange | function | undefined | Callback function that runs when the input value changes |
62
- | supports all input properties | - | - | - |
190
+ function Form() {
191
+ const formik = useFormik({
192
+ initialValues: { amount: '' },
193
+ onSubmit: (values) => {
194
+ console.log(values);
195
+ },
196
+ });
63
197
 
64
- ## Framework Adapters
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
- Numora is also available for popular frameworks:
310
+ ## Related Packages
67
311
 
68
- - React: `numora-react` (in progress)
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