numora 3.0.2 → 3.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +33 -244
- package/dist/NumoraInput.d.ts +0 -1
- package/dist/features/compact-notation.d.ts +6 -2
- package/dist/features/formatting/cursor-position.d.ts +44 -1
- package/dist/features/formatting/digit-counting.d.ts +35 -12
- package/dist/features/formatting/index.d.ts +0 -4
- package/dist/features/non-numeric-characters.d.ts +1 -0
- package/dist/features/sanitization.d.ts +1 -1
- package/dist/features/scientific-notation.d.ts +4 -0
- package/dist/index.d.ts +3 -3
- package/dist/index.js +1 -1
- package/dist/index.mjs +595 -901
- package/dist/types.d.ts +2 -1
- package/dist/utils/locale.d.ts +14 -0
- package/dist/utils/regex-cache.d.ts +40 -0
- package/dist/validation.d.ts +1 -2
- package/package.json +5 -3
- package/dist/features/formatting/character-equivalence.d.ts +0 -9
- package/dist/features/formatting/large-number.d.ts +0 -39
- package/dist/features/formatting/numeric-formatting-utils.d.ts +0 -24
- package/dist/features/formatting/percent.d.ts +0 -45
- package/dist/features/formatting/subscript-notation.d.ts +0 -20
package/README.md
CHANGED
|
@@ -3,281 +3,70 @@
|
|
|
3
3
|
[](https://www.npmjs.com/package/numora)
|
|
4
4
|
[](https://www.npmjs.com/package/numora)
|
|
5
5
|
|
|
6
|
-
A lightweight, framework-agnostic numeric input library
|
|
6
|
+
A lightweight, framework-agnostic numeric input library. Zero dependencies, TypeScript-first.
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
- **Type safety** - fully typed API for better developer experience
|
|
10
|
-
- **Framework agnostic** - use with any framework or vanilla JavaScript
|
|
11
|
-
- **Customizable** - extensive options to fit your specific needs
|
|
12
|
-
|
|
13
|
-
## Demo
|
|
14
|
-
|
|
15
|
-
Check out the [live demo](https://numora.xyz/) to see Numora in action.
|
|
16
|
-
|
|
17
|
-
## Features
|
|
18
|
-
|
|
19
|
-
| Feature | Description |
|
|
20
|
-
|---------|-------------|
|
|
21
|
-
| **⭐️ Zero Dependencies** | No external dependencies, minimal bundle size |
|
|
22
|
-
| **⭐️ Framework Agnostic** | Works with any framework or vanilla JavaScript |
|
|
23
|
-
| **Decimal Precision Control** | Configure minimum and maximum decimal places (`decimalMinLength`, `decimalMaxLength`) |
|
|
24
|
-
| **Minimum Decimal Places** | Automatically pad values with zeros to ensure minimum decimal places (e.g., `"1"` with `decimalMinLength: 2` becomes `"1.00"`) |
|
|
25
|
-
| **Thousand Separators** | Customizable thousand separators with multiple grouping styles (`Thousand`, `Lakh`, `Wan`, `None`) |
|
|
26
|
-
| **Custom Decimal Separator** | Support for different decimal separators (e.g., `.` or `,`) |
|
|
27
|
-
| **Format on Blur/Change** | Choose when to apply formatting: `on blur (clean editing)` or `on change (real-time)` |
|
|
28
|
-
| **Compact Notation Expansion** | When enabled, expands compact notation during paste/setValue (e.g., `"1k"` → `"1000"`, `"1.5m"` → `"1500000"`, `"2B"` → `"2000000000"`) |
|
|
29
|
-
| **Scientific Notation Expansion** | Always automatically expands scientific notation (e.g., `"1.5e-7"` → `"0.00000015"`, `"2e+5"` → `"200000"`) |
|
|
30
|
-
| **Negative Number Support** | Optional support for negative numbers with `enableNegative` |
|
|
31
|
-
| **Leading Zeros Support** | Control leading zero behavior with `enableLeadingZeros` |
|
|
32
|
-
| **Raw Value Mode** | Get unformatted numeric values while displaying formatted values |
|
|
33
|
-
| **Paste Event Handling** | Intelligent paste handling with automatic sanitization, formatting, and cursor positioning |
|
|
34
|
-
| **Cursor Position Preservation** | Smart cursor positioning that works with thousand separators, even during formatting |
|
|
35
|
-
| **Thousand Separator Skipping** | On delete/backspace, cursor automatically skips over thousand separators for better UX |
|
|
36
|
-
| **Mobile Keyboard Optimization** | Automatic `inputmode="decimal"` for mobile numeric keyboards |
|
|
37
|
-
| **Mobile Keyboard Filtering** | Automatically filters non-breaking spaces and Unicode whitespace artifacts from mobile keyboards |
|
|
38
|
-
| **Non-numeric Character Filtering** | Automatic removal of invalid characters |
|
|
39
|
-
| **Comma/Dot Conversion** | When `thousandStyle` is `None`, typing comma or dot automatically converts to the configured `decimalSeparator` |
|
|
40
|
-
| **Character Equivalence** | Automatic conversion of commas to dots (or custom decimal separator) for easier input |
|
|
41
|
-
| **Sanitization** | Comprehensive input sanitization for security and data integrity |
|
|
42
|
-
| **TypeScript Support** | Full TypeScript definitions included |
|
|
43
|
-
|
|
44
|
-
## Display Formatting Utilities
|
|
45
|
-
|
|
46
|
-
Numora also exports utility functions for formatting numbers for display (outside of the input component):
|
|
47
|
-
|
|
48
|
-
| Utility | Description | Example |
|
|
49
|
-
|---------|-------------|---------|
|
|
50
|
-
| `formatPercent` | Format decimal values as percentages | `formatPercent("0.01", 2)` → `"1.00%"` |
|
|
51
|
-
| `formatLargePercent` | Format large percentages with scale notation (k, M, T, etc.) | `formatLargePercent("1000", 2)` → `"100000%"` |
|
|
52
|
-
| `formatLargeNumber` | Format large numbers with scale notation | `formatLargeNumber("1234")` → `"1.23k"` |
|
|
53
|
-
| `condenseDecimalZeros` | Condense leading decimal zeros to subscript notation | `condenseDecimalZeros("0.000001", 8)` → `"0₆1"` |
|
|
54
|
-
|
|
55
|
-
These utilities use string arithmetic to avoid floating-point precision issues.
|
|
56
|
-
|
|
57
|
-
## 📊 Comparison
|
|
58
|
-
|
|
59
|
-
| Feature | Numora | react-number-format | Native Number Input |
|
|
60
|
-
|---------|--------|---------------------|---------------------|
|
|
61
|
-
| **Framework Support** | ✅ All frameworks | ❌ React only | ✅ All frameworks |
|
|
62
|
-
| **Dependencies** | ✅ Zero | ⚠️ React required | ✅ Zero |
|
|
63
|
-
| **Raw Value Mode** | ✅ Yes | ⚠️ Limited | ❌ No |
|
|
64
|
-
| **Comma/Dot Conversion** | ✅ Yes | ⚠️ Limited | ❌ No |
|
|
65
|
-
| **Scientific Notation** | ✅ Auto-expand | ❌ No | ❌ No |
|
|
66
|
-
| **Display Formatting Utils** | ✅ Yes | ❌ No | ❌ No |
|
|
67
|
-
| **Compact Notation** | ✅ Auto-expand | ❌ No | ❌ No |
|
|
68
|
-
| **Mobile Support** | ✅ Yes | ✅ Yes | ⚠️ Limited |
|
|
69
|
-
| **Decimal Precision Control** | ✅ Yes | ✅ Yes | ❌ Limited |
|
|
70
|
-
| **Thousand Separators** | ✅ Customizable | ✅ Yes | ❌ No |
|
|
71
|
-
| **Custom Decimal Separator** | ✅ Yes | ✅ Yes | ❌ No (always `.`) |
|
|
72
|
-
| **Formatting Options** | ✅ Blur/Change modes | ✅ Multiple modes | ❌ No |
|
|
73
|
-
| **Cursor Preservation** | ✅ Advanced | ✅ Basic | ❌ N/A |
|
|
74
|
-
| **TypeScript Support** | ✅ Yes | ✅ Yes | ⚠️ Partial |
|
|
75
|
-
| **Paste Handling** | ✅ Intelligent | ✅ Yes | ⚠️ Basic |
|
|
76
|
-
| **Grouping Styles** | ✅ Thousand/Lakh/Wan | ✅ Thousand/Lakh/Wan | ❌ No |
|
|
77
|
-
| **Leading Zeros Control** | ✅ Yes | ✅ Yes | ❌ No |
|
|
78
|
-
|
|
79
|
-
## Installation
|
|
8
|
+
## Install
|
|
80
9
|
|
|
81
10
|
```bash
|
|
82
11
|
npm install numora
|
|
83
|
-
# or
|
|
84
|
-
bun add numora
|
|
85
|
-
# or
|
|
86
|
-
pnpm add numora
|
|
12
|
+
# or pnpm add numora / bun add numora
|
|
87
13
|
```
|
|
88
14
|
|
|
89
15
|
## Usage
|
|
90
16
|
|
|
91
|
-
### Basic Example
|
|
92
|
-
|
|
93
|
-
```typescript
|
|
94
|
-
import { NumoraInput } from 'numora';
|
|
95
|
-
|
|
96
|
-
// Get the container element where you want to mount the input
|
|
97
|
-
const container = document.querySelector('#my-input-container');
|
|
98
|
-
|
|
99
|
-
// Create a new NumoraInput instance
|
|
100
|
-
const numoraInput = new NumoraInput(container, {
|
|
101
|
-
decimalMaxLength: 2,
|
|
102
|
-
onChange: (value) => {
|
|
103
|
-
console.log('Value changed:', value);
|
|
104
|
-
},
|
|
105
|
-
});
|
|
106
|
-
```
|
|
107
|
-
|
|
108
|
-
### Advanced Example
|
|
109
|
-
|
|
110
17
|
```typescript
|
|
111
18
|
import { NumoraInput, FormatOn, ThousandStyle } from 'numora';
|
|
112
19
|
|
|
113
|
-
const
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
// Decimal options
|
|
117
|
-
decimalMaxLength: 18,
|
|
118
|
-
decimalMinLength: 2, // Pads with zeros: "1" becomes "1.00"
|
|
119
|
-
decimalSeparator: '.',
|
|
120
|
-
|
|
121
|
-
// Thousand separator options
|
|
20
|
+
const input = new NumoraInput(document.querySelector('#amount'), {
|
|
21
|
+
decimalMaxLength: 2,
|
|
22
|
+
decimalMinLength: 2,
|
|
122
23
|
thousandSeparator: ',',
|
|
123
24
|
thousandStyle: ThousandStyle.Thousand,
|
|
124
|
-
formatOn: FormatOn.
|
|
125
|
-
|
|
126
|
-
// Additional features
|
|
127
|
-
enableCompactNotation: true, // Expands "1k" → "1000" on paste/setValue
|
|
128
|
-
enableNegative: false,
|
|
129
|
-
enableLeadingZeros: false,
|
|
130
|
-
rawValueMode: true, // Get unformatted values in onChange
|
|
131
|
-
|
|
132
|
-
// Standard input properties
|
|
133
|
-
placeholder: 'Enter amount',
|
|
134
|
-
className: 'numora-input',
|
|
135
|
-
|
|
136
|
-
// Event handler
|
|
137
|
-
onChange: (value) => {
|
|
138
|
-
console.log('Raw value:', value); // Unformatted if rawValueMode is true
|
|
139
|
-
console.log('Display value:', numoraInput.value); // Formatted display value
|
|
140
|
-
console.log('As number:', numoraInput.valueAsNumber); // Parsed as number
|
|
141
|
-
},
|
|
142
|
-
});
|
|
143
|
-
```
|
|
144
|
-
|
|
145
|
-
### Compact Notation Example
|
|
146
|
-
|
|
147
|
-
```typescript
|
|
148
|
-
import { NumoraInput } from 'numora';
|
|
149
|
-
|
|
150
|
-
const container = document.querySelector('#my-input-container');
|
|
151
|
-
|
|
152
|
-
const numoraInput = new NumoraInput(container, {
|
|
153
|
-
enableCompactNotation: true,
|
|
154
|
-
onChange: (value) => {
|
|
155
|
-
console.log('Value:', value);
|
|
156
|
-
},
|
|
157
|
-
});
|
|
158
|
-
|
|
159
|
-
// When user pastes "1.5k" or you call setValue("1.5k")
|
|
160
|
-
// It automatically expands to "1500"
|
|
161
|
-
numoraInput.setValue('1.5k'); // Display: "1,500" (if thousand separator enabled)
|
|
162
|
-
```
|
|
163
|
-
|
|
164
|
-
### Scientific Notation Example
|
|
165
|
-
|
|
166
|
-
```typescript
|
|
167
|
-
import { NumoraInput } from 'numora';
|
|
168
|
-
|
|
169
|
-
const container = document.querySelector('#my-input-container');
|
|
170
|
-
|
|
171
|
-
const numoraInput = new NumoraInput(container, {
|
|
172
|
-
decimalMaxLength: 18,
|
|
173
|
-
onChange: (value) => {
|
|
174
|
-
console.log('Value:', value);
|
|
175
|
-
},
|
|
176
|
-
});
|
|
177
|
-
|
|
178
|
-
// Scientific notation is ALWAYS automatically expanded
|
|
179
|
-
// User can paste "1.5e-7" and it becomes "0.00000015"
|
|
180
|
-
// User can paste "2e+5" and it becomes "200000"
|
|
181
|
-
```
|
|
182
|
-
|
|
183
|
-
### Comma/Dot Conversion Example
|
|
184
|
-
|
|
185
|
-
```typescript
|
|
186
|
-
import { NumoraInput, ThousandStyle } from 'numora';
|
|
187
|
-
|
|
188
|
-
const container = document.querySelector('#my-input-container');
|
|
189
|
-
|
|
190
|
-
const numoraInput = new NumoraInput(container, {
|
|
191
|
-
decimalSeparator: ',', // European format
|
|
192
|
-
thousandStyle: ThousandStyle.None, // Required for comma/dot conversion
|
|
193
|
-
decimalMaxLength: 2,
|
|
25
|
+
formatOn: FormatOn.Blur,
|
|
26
|
+
onChange: (value) => console.log(value),
|
|
194
27
|
});
|
|
195
28
|
|
|
196
|
-
//
|
|
197
|
-
|
|
198
|
-
//
|
|
199
|
-
// This makes it easier for users without knowing the exact separator
|
|
29
|
+
// Get / set value
|
|
30
|
+
input.value = '1234.56';
|
|
31
|
+
console.log(input.valueAsNumber); // 1234.56
|
|
200
32
|
```
|
|
201
33
|
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
```typescript
|
|
205
|
-
import { formatPercent, formatLargePercent, formatLargeNumber, condenseDecimalZeros } from 'numora';
|
|
206
|
-
|
|
207
|
-
// Format as percentage
|
|
208
|
-
const percent = formatPercent('0.01', 2); // "1.00%"
|
|
209
|
-
const largePercent = formatLargePercent('1000', 2); // "100000%"
|
|
210
|
-
|
|
211
|
-
// Format large numbers with scale notation
|
|
212
|
-
const large = formatLargeNumber('1234567'); // "1.23M"
|
|
213
|
-
const small = formatLargeNumber('1234'); // "1.23k"
|
|
214
|
-
|
|
215
|
-
// Condense decimal zeros
|
|
216
|
-
const condensed = condenseDecimalZeros('0.000001', 8); // "0₆1"
|
|
217
|
-
const condensed2 = condenseDecimalZeros('0.000123', 8); // "0₃123"
|
|
218
|
-
```
|
|
219
|
-
|
|
220
|
-
### Programmatic Value Control
|
|
221
|
-
|
|
222
|
-
```typescript
|
|
223
|
-
// Get the current value
|
|
224
|
-
const currentValue = numoraInput.getValue();
|
|
225
|
-
// or
|
|
226
|
-
const currentValue = numoraInput.value;
|
|
227
|
-
|
|
228
|
-
// Set a new value
|
|
229
|
-
numoraInput.setValue('1234.56');
|
|
230
|
-
// or
|
|
231
|
-
numoraInput.value = '1234.56';
|
|
232
|
-
|
|
233
|
-
// Set from a number
|
|
234
|
-
numoraInput.valueAsNumber = 1234.56;
|
|
235
|
-
|
|
236
|
-
// Get as a number
|
|
237
|
-
const numericValue = numoraInput.valueAsNumber;
|
|
238
|
-
|
|
239
|
-
// Enable/disable the input
|
|
240
|
-
numoraInput.disable();
|
|
241
|
-
numoraInput.enable();
|
|
34
|
+
## Features
|
|
242
35
|
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
36
|
+
- [Sanitization](https://numora.xyz/docs/numora/features/sanitization) - filters invalid characters and mobile keyboard artifacts
|
|
37
|
+
- [Formatting](https://numora.xyz/docs/numora/features/formatting) - thousand separators (Thousand/Lakh/Wan), format on blur or change
|
|
38
|
+
- [Decimals](https://numora.xyz/docs/numora/features/decimals) - min/max decimal places, custom decimal separator, raw value mode
|
|
39
|
+
- [Compact Notation](https://numora.xyz/docs/numora/features/compact-notation) - expands "1k" → "1000" on paste/setValue (opt-in)
|
|
40
|
+
- [Scientific Notation](https://numora.xyz/docs/numora/features/scientific-notation) - always expands "1.5e-7" → "0.00000015" automatically
|
|
41
|
+
- [Leading Zeros](https://numora.xyz/docs/numora/features/leading-zeros) - configurable leading zero behavior
|
|
249
42
|
|
|
250
43
|
## Options
|
|
251
44
|
|
|
252
|
-
The NumoraInput constructor accepts the following options:
|
|
253
|
-
|
|
254
45
|
| Option | Type | Default | Description |
|
|
255
46
|
|--------|------|---------|-------------|
|
|
256
|
-
| `decimalMaxLength` | `number` | `2` | Maximum
|
|
257
|
-
| `decimalMinLength` | `number` | `0` | Minimum
|
|
258
|
-
| `decimalSeparator` | `string` | `'.'` |
|
|
259
|
-
| `thousandSeparator` | `string` | `','` |
|
|
47
|
+
| `decimalMaxLength` | `number` | `2` | Maximum decimal places allowed |
|
|
48
|
+
| `decimalMinLength` | `number` | `0` | Minimum decimal places (pads with zeros) |
|
|
49
|
+
| `decimalSeparator` | `string` | `'.'` | Decimal separator character |
|
|
50
|
+
| `thousandSeparator` | `string` | `','` | Thousand separator character |
|
|
260
51
|
| `thousandStyle` | `ThousandStyle` | `ThousandStyle.None` | Grouping style: `Thousand`, `Lakh`, `Wan`, or `None` |
|
|
261
52
|
| `formatOn` | `FormatOn` | `FormatOn.Blur` | When to apply formatting: `Blur` or `Change` |
|
|
262
|
-
| `enableCompactNotation` | `boolean` | `false` |
|
|
53
|
+
| `enableCompactNotation` | `boolean` | `false` | Expand compact notation on paste/setValue |
|
|
263
54
|
| `enableNegative` | `boolean` | `false` | Allow negative numbers |
|
|
264
|
-
| `enableLeadingZeros` | `boolean` | `false` | Allow leading zeros
|
|
265
|
-
| `rawValueMode` | `boolean` | `false` | Return unformatted values in `onChange`
|
|
266
|
-
| `onChange` | `(value: string) => void` | `undefined` |
|
|
267
|
-
| `value` | `string` | `undefined` | Initial value (controlled
|
|
268
|
-
| `defaultValue` | `string` | `undefined` | Initial
|
|
55
|
+
| `enableLeadingZeros` | `boolean` | `false` | Allow leading zeros |
|
|
56
|
+
| `rawValueMode` | `boolean` | `false` | Return unformatted values in `onChange` |
|
|
57
|
+
| `onChange` | `(value: string) => void` | `undefined` | Called when value changes |
|
|
58
|
+
| `value` | `string` | `undefined` | Initial value (controlled) |
|
|
59
|
+
| `defaultValue` | `string` | `undefined` | Initial value (uncontrolled) |
|
|
269
60
|
|
|
270
|
-
All standard HTMLInputElement properties are also supported (
|
|
61
|
+
All standard `HTMLInputElement` properties are also supported (`placeholder`, `className`, `disabled`, etc.).
|
|
271
62
|
|
|
272
|
-
|
|
63
|
+
## Documentation
|
|
273
64
|
|
|
274
|
-
|
|
65
|
+
Full docs and live demo at [numora.xyz/docs/numora](https://numora.xyz/docs/numora).
|
|
275
66
|
|
|
276
|
-
|
|
67
|
+
## Framework Adapters
|
|
277
68
|
|
|
278
|
-
- **React**: [`numora-react`](../react/README.md)
|
|
279
|
-
- **Vue**: Coming soon
|
|
280
|
-
- **Svelte**: Use the core package directly
|
|
69
|
+
- **React**: [`numora-react`](../react/README.md)
|
|
281
70
|
|
|
282
71
|
## License
|
|
283
72
|
|
package/dist/NumoraInput.d.ts
CHANGED
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
2
|
+
* Static regex patterns for compact notation processing.
|
|
3
|
+
* Defined at module level to avoid recompilation on each function call.
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Expands compact notation (k, m, b, t) to full numbers using string manipulation.
|
|
7
|
+
* Handles formats like: 1k, 1.5m, 2B, 1M, 2.5T (case-insensitive)
|
|
4
8
|
* Uses string arithmetic to avoid precision loss with large numbers.
|
|
5
9
|
*
|
|
6
10
|
* @param value - The string value that may contain compact notation
|
|
@@ -1,6 +1,48 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Advanced cursor position calculation for formatted numeric inputs.
|
|
3
3
|
* Handles cursor preservation during formatting changes, insertion, and deletion operations.
|
|
4
|
+
*
|
|
5
|
+
* ## Algorithm Overview
|
|
6
|
+
*
|
|
7
|
+
* The cursor position calculation uses a "meaningful digit" approach:
|
|
8
|
+
* 1. Count the number of actual digits (0-9) before the cursor, ignoring separators
|
|
9
|
+
* 2. After formatting, find the position that has the same number of digits before it
|
|
10
|
+
* 3. Apply adjustments for separator boundaries and special cases
|
|
11
|
+
*
|
|
12
|
+
* ## Processing Flow
|
|
13
|
+
*
|
|
14
|
+
* ```
|
|
15
|
+
* calculateCursorPositionAfterFormatting()
|
|
16
|
+
* ├── Guard clauses (empty values, out of bounds)
|
|
17
|
+
* ├── Compact notation detection (1k → 1000)
|
|
18
|
+
* ├── Character mapping approach (optional, for complex transformations)
|
|
19
|
+
* └── Route to handler based on operation type:
|
|
20
|
+
* ├── handleDeletion() - for backspace/delete operations
|
|
21
|
+
* │ ├── handleSeparatorDeletion() - cursor was on separator
|
|
22
|
+
* │ ├── Calculate target digit count
|
|
23
|
+
* │ └── Find new position + fine-tune for separators
|
|
24
|
+
* └── handleInsertion() - for typing/paste operations
|
|
25
|
+
* ├── Handle cursor at end
|
|
26
|
+
* └── Find position maintaining digit-relative position
|
|
27
|
+
* ```
|
|
28
|
+
*
|
|
29
|
+
* ## Key Concepts
|
|
30
|
+
*
|
|
31
|
+
* - **Meaningful digits**: Numeric characters (0-9) that represent actual value
|
|
32
|
+
* - **Separators**: Thousand separators that are formatting-only (not part of value)
|
|
33
|
+
* - **Digit index**: The nth digit from the start (ignoring separators)
|
|
34
|
+
* - **ChangeRange**: Info about what was typed/deleted to distinguish Delete vs Backspace
|
|
35
|
+
*
|
|
36
|
+
* ## Edge Cases Handled
|
|
37
|
+
*
|
|
38
|
+
* - Cursor at start/end of input
|
|
39
|
+
* - Cursor on separator during deletion
|
|
40
|
+
* - Delete key vs Backspace key (different cursor behavior)
|
|
41
|
+
* - Compact notation expansion (1k → 1000)
|
|
42
|
+
* - Integer/decimal part transitions
|
|
43
|
+
* - Boundary constraints (prefix/suffix)
|
|
44
|
+
*
|
|
45
|
+
* @module cursor-position
|
|
4
46
|
*/
|
|
5
47
|
import type { ChangeRange } from './constants';
|
|
6
48
|
import { ThousandStyle } from '@/types';
|
|
@@ -15,6 +57,7 @@ export type IsCharacterEquivalent = (char1: string, char2: string, context: {
|
|
|
15
57
|
oldIndex: number;
|
|
16
58
|
newIndex: number;
|
|
17
59
|
}) => boolean;
|
|
60
|
+
export declare const defaultIsCharacterEquivalent: IsCharacterEquivalent;
|
|
18
61
|
/**
|
|
19
62
|
* Options for cursor position calculation.
|
|
20
63
|
*/
|
|
@@ -36,7 +79,7 @@ export interface CursorPositionOptions {
|
|
|
36
79
|
* @param newFormattedValue - The formatted value after formatting
|
|
37
80
|
* @param oldCursorPosition - The cursor position in the old formatted value
|
|
38
81
|
* @param separator - The thousand separator character used in formatting
|
|
39
|
-
*
|
|
82
|
+
* Will be removed in a future major version. Pass any value; it is ignored.
|
|
40
83
|
* @param changeRange - Optional change range info to distinguish Delete vs Backspace
|
|
41
84
|
* @param decimalSeparator - The decimal separator character (default: '.')
|
|
42
85
|
* @param options - Additional options for cursor calculation
|
|
@@ -1,23 +1,48 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Utilities for counting and locating meaningful digits in formatted numbers.
|
|
3
|
-
*
|
|
3
|
+
*
|
|
4
|
+
* ## Core Concept
|
|
5
|
+
*
|
|
6
|
+
* "Meaningful digits" are the actual numeric characters (0-9) in a formatted string,
|
|
7
|
+
* excluding formatting characters like thousand separators and decimal points.
|
|
8
|
+
*
|
|
9
|
+
* For example, in "1,234.56":
|
|
10
|
+
* - Meaningful digits: 1, 2, 3, 4, 5, 6 (count = 6)
|
|
11
|
+
* - Non-meaningful: comma (,) and period (.)
|
|
12
|
+
*
|
|
13
|
+
* ## Usage in Cursor Positioning
|
|
14
|
+
*
|
|
15
|
+
* These utilities enable cursor preservation during formatting by:
|
|
16
|
+
* 1. Counting digits before cursor in OLD value
|
|
17
|
+
* 2. Finding position with same digit count in NEW value
|
|
18
|
+
*
|
|
19
|
+
* Example: Typing "0" in "99|" (cursor at end)
|
|
20
|
+
* - Old value: "99" → 2 digits before cursor
|
|
21
|
+
* - User types: "0" → becomes "990"
|
|
22
|
+
* - Formatting: "990" → "990" (no separator yet)
|
|
23
|
+
* - New cursor: position after 3rd digit = position 3
|
|
24
|
+
*
|
|
25
|
+
* Example: Typing "9" in "99|9" → "9,999"
|
|
26
|
+
* - Old value: "999" → 3 digits before cursor at position 2
|
|
27
|
+
* - After formatting: "9,999"
|
|
28
|
+
* - Find position with 3 digits before it → position 4 (after "9,99")
|
|
29
|
+
*
|
|
30
|
+
* @module digit-counting
|
|
4
31
|
*/
|
|
5
32
|
/**
|
|
6
|
-
* Counts meaningful
|
|
33
|
+
* Counts meaningful non-thousand-separator characters (digits and decimal separator) before a position.
|
|
7
34
|
* This is the core digit counting logic used throughout cursor positioning.
|
|
8
35
|
*
|
|
9
36
|
* @param value - The formatted string value
|
|
10
37
|
* @param position - The position to count up to
|
|
11
38
|
* @param separator - The thousand separator character
|
|
12
|
-
* @param decimalSeparator - The decimal separator character (default: '.')
|
|
13
39
|
* @returns The count of meaningful digits before the position
|
|
14
40
|
*
|
|
15
41
|
* @example
|
|
16
42
|
* countMeaningfulDigitsBeforePosition("1,234", 3, ",") // Returns: 2 (digits "1" and "2")
|
|
17
|
-
* countMeaningfulDigitsBeforePosition("1,234.56", 8, ",") // Returns:
|
|
18
|
-
* countMeaningfulDigitsBeforePosition("1.234,56", 8, ".", ",") // Returns: 6
|
|
43
|
+
* countMeaningfulDigitsBeforePosition("1,234.56", 8, ",") // Returns: 7
|
|
19
44
|
*/
|
|
20
|
-
export declare function countMeaningfulDigitsBeforePosition(value: string, position: number, separator: string
|
|
45
|
+
export declare function countMeaningfulDigitsBeforePosition(value: string, position: number, separator: string): number;
|
|
21
46
|
/**
|
|
22
47
|
* Finds the position in the string for a specific digit index.
|
|
23
48
|
* Returns the position AFTER the digit at targetDigitIndex.
|
|
@@ -25,13 +50,12 @@ export declare function countMeaningfulDigitsBeforePosition(value: string, posit
|
|
|
25
50
|
* @param value - The formatted string value
|
|
26
51
|
* @param targetDigitIndex - The zero-based index of the target digit
|
|
27
52
|
* @param separator - The thousand separator character
|
|
28
|
-
* @param decimalSeparator - The decimal separator character (default: '.')
|
|
29
53
|
* @returns The position after the target digit
|
|
30
54
|
*
|
|
31
55
|
* @example
|
|
32
|
-
* findPositionForDigitIndex("1,234",
|
|
56
|
+
* findPositionForDigitIndex("1,234", 3, ",") // Returns: 4 (after digit "3")
|
|
33
57
|
*/
|
|
34
|
-
export declare function findPositionForDigitIndex(value: string, targetDigitIndex: number, separator: string
|
|
58
|
+
export declare function findPositionForDigitIndex(value: string, targetDigitIndex: number, separator: string): number;
|
|
35
59
|
/**
|
|
36
60
|
* Finds the position in the string where the digit count equals targetDigitCount.
|
|
37
61
|
* Returns the position after reaching the target count.
|
|
@@ -39,13 +63,12 @@ export declare function findPositionForDigitIndex(value: string, targetDigitInde
|
|
|
39
63
|
* @param value - The formatted string value
|
|
40
64
|
* @param targetDigitCount - The target number of digits
|
|
41
65
|
* @param separator - The thousand separator character
|
|
42
|
-
* @param decimalSeparator - The decimal separator character (default: '.')
|
|
43
66
|
* @returns The position where digit count equals target
|
|
44
67
|
*
|
|
45
68
|
* @example
|
|
46
|
-
* findPositionWithMeaningfulDigitCount("1,234", 3, ",") // Returns:
|
|
69
|
+
* findPositionWithMeaningfulDigitCount("1,234", 3, ",") // Returns: 4 (after "2,3")
|
|
47
70
|
*/
|
|
48
|
-
export declare function findPositionWithMeaningfulDigitCount(value: string, targetDigitCount: number, separator: string
|
|
71
|
+
export declare function findPositionWithMeaningfulDigitCount(value: string, targetDigitCount: number, separator: string): number;
|
|
49
72
|
/**
|
|
50
73
|
* Checks if a position in the string is on a separator character.
|
|
51
74
|
*
|
|
@@ -14,7 +14,3 @@ export { findChangedRangeFromCaretPositions, findChangeRange } from './change-de
|
|
|
14
14
|
export { getCaretBoundary, getCaretPosInBoundary } from './cursor-boundary';
|
|
15
15
|
export { setCaretPosition, setCaretPositionWithRetry, getInputCaretPosition, updateCursorPosition, skipOverThousandSeparatorOnDelete } from './caret-position-utils';
|
|
16
16
|
export { countMeaningfulDigitsBeforePosition, findPositionForDigitIndex, findPositionWithMeaningfulDigitCount, isPositionOnSeparator, } from './digit-counting';
|
|
17
|
-
export { formatPercent, formatLargePercent } from './percent';
|
|
18
|
-
export { condenseDecimalZeros } from './subscript-notation';
|
|
19
|
-
export { formatLargeNumber, type FormatLargeNumberOptions } from './large-number';
|
|
20
|
-
export { applyDecimalPrecision, applyScaleNotation, compareStrings, isVeryLarge } from './numeric-formatting-utils';
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { FormattingOptions, Separators } from '@/types';
|
|
2
2
|
/**
|
|
3
3
|
* Removes all occurrences of thousand separator from a string.
|
|
4
|
-
*
|
|
4
|
+
* Uses cached regex for performance optimization.
|
|
5
5
|
*
|
|
6
6
|
* @param value - The string to remove separators from
|
|
7
7
|
* @param thousandSeparator - The thousand separator character to remove
|
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Static regex patterns for scientific notation processing.
|
|
3
|
+
* Defined at module level to avoid recompilation on each function call.
|
|
4
|
+
*/
|
|
1
5
|
/**
|
|
2
6
|
* Expands scientific notation to decimal notation using string manipulation only.
|
|
3
7
|
* Handles formats like: 1.5e-7, 2e+5, 1.23e-4, etc.
|
package/dist/index.d.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
export * from './NumoraInput';
|
|
2
2
|
export { ThousandStyle, FormatOn } from './types';
|
|
3
|
+
export { getSeparatorsFromLocale, resolveLocaleOptions } from './utils/locale';
|
|
3
4
|
export { handleOnChangeNumoraInput, handleOnPasteNumoraInput, handleOnKeyDownNumoraInput, } from './utils/event-handlers';
|
|
4
5
|
export { formatValueForDisplay, formatInputValue, } from './utils/format-utils';
|
|
5
6
|
export type { FormattingOptions, CaretPositionInfo } from './types';
|
|
6
|
-
export { formatPercent, formatLargePercent } from './features/formatting/percent';
|
|
7
|
-
export { formatLargeNumber, type FormatLargeNumberOptions } from './features/formatting/large-number';
|
|
8
|
-
export { condenseDecimalZeros } from './features/formatting/subscript-notation';
|
|
9
7
|
export { removeThousandSeparators } from './features/sanitization';
|
|
8
|
+
export { validateNumoraInputOptions } from './validation';
|
|
9
|
+
export { getNumoraPattern } from './utils/input-pattern';
|