numora-react 1.0.3 → 1.0.5

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/package.json CHANGED
@@ -1,15 +1,12 @@
1
1
  {
2
2
  "name": "numora-react",
3
- "version": "1.0.3",
3
+ "version": "1.0.5",
4
4
  "description": "Numora for React - Headless finance input library",
5
- "homepage": "https://numora.xyz/",
5
+ "homepage": "https://numora.netlify.app/",
6
6
  "type": "module",
7
7
  "main": "dist/index.cjs.js",
8
8
  "module": "dist/index.esm.js",
9
9
  "types": "dist/index.d.ts",
10
- "files": [
11
- "dist"
12
- ],
13
10
  "sideEffects": false,
14
11
  "repository": {
15
12
  "type": "git",
@@ -46,13 +43,6 @@
46
43
  }
47
44
  ],
48
45
  "license": "MIT",
49
- "peerDependencies": {
50
- "react": "^18.0.0 || ^19.0.0",
51
- "react-dom": "^18.0.0 || ^19.0.0"
52
- },
53
- "dependencies": {
54
- "numora": "^2.0.2"
55
- },
56
46
  "devDependencies": {
57
47
  "@babel/core": "^7.26.10",
58
48
  "@babel/preset-env": "^7.26.9",
@@ -66,13 +56,13 @@
66
56
  "rollup": "^4.38.0",
67
57
  "rollup-plugin-peer-deps-external": "^2.2.4",
68
58
  "tslib": "^2.8.1",
69
- "typescript": "^5.8.2",
59
+ "typescript": "^5.8.2"
60
+ },
61
+ "dependencies": {
62
+ "numora": "^2.0.2",
70
63
  "react": "^19.1.0",
71
64
  "react-dom": "^19.1.0"
72
65
  },
73
- "publishConfig": {
74
- "access": "public"
75
- },
76
66
  "scripts": {
77
67
  "build": "rollup -c",
78
68
  "watch": "rollup -c -w"
@@ -0,0 +1,38 @@
1
+ import resolve from '@rollup/plugin-node-resolve';
2
+ import commonjs from '@rollup/plugin-commonjs';
3
+ import babel from '@rollup/plugin-babel';
4
+ import typescript from '@rollup/plugin-typescript';
5
+ import peerDepsExternal from 'rollup-plugin-peer-deps-external';
6
+ import packageJson from './package.json' assert { type: 'json' };
7
+
8
+ export default {
9
+ input: 'src/index.tsx',
10
+ output: [
11
+ {
12
+ file: packageJson.main,
13
+ format: 'cjs',
14
+ sourcemap: true,
15
+ },
16
+ {
17
+ file: packageJson.module,
18
+ format: 'esm',
19
+ sourcemap: true,
20
+ },
21
+ ],
22
+ plugins: [
23
+ peerDepsExternal(),
24
+ resolve(),
25
+ commonjs(),
26
+ typescript({ tsconfig: './tsconfig.json' }),
27
+ babel({
28
+ exclude: 'node_modules/**',
29
+ extensions: ['.js', '.jsx', '.ts', '.tsx'],
30
+ babelHelpers: 'bundled',
31
+ presets: [
32
+ ['@babel/preset-env', { targets: 'defaults' }],
33
+ ['@babel/preset-react', { runtime: 'automatic' }],
34
+ ],
35
+ }),
36
+ ],
37
+ external: ['react', 'react-dom', 'numora'],
38
+ };
package/src/index.tsx ADDED
@@ -0,0 +1,144 @@
1
+ import React, { ChangeEvent, ClipboardEvent, forwardRef } from 'react';
2
+ import {
3
+ handleOnChangeNumoraInput,
4
+ handleOnPasteNumoraInput,
5
+ handleOnKeyDownNumoraInput,
6
+ FormatOn,
7
+ ThousandStyle,
8
+ type FormattingOptions,
9
+ type CaretPositionInfo,
10
+ } from 'numora';
11
+
12
+ interface NumericInputProps extends Omit<React.InputHTMLAttributes<HTMLInputElement>, 'onChange' | 'type' | 'inputMode'> {
13
+ maxDecimals?: number;
14
+ onChange?: (e: ChangeEvent<HTMLInputElement> | ClipboardEvent<HTMLInputElement>) => void;
15
+
16
+ // Formatting options
17
+ formatOn?: FormatOn;
18
+ thousandSeparator?: string;
19
+ thousandStyle?: ThousandStyle;
20
+ decimalSeparator?: string;
21
+ decimalMinLength?: number;
22
+
23
+ // Feature flags
24
+ enableCompactNotation?: boolean;
25
+ enableNegative?: boolean;
26
+ enableLeadingZeros?: boolean;
27
+ rawValueMode?: boolean;
28
+ }
29
+
30
+ const DEFAULT_PROPS = {
31
+ autoComplete: 'off',
32
+ autoCorrect: 'off',
33
+ autoCapitalize: 'none',
34
+ minLength: 1,
35
+ placeholder: '0.0',
36
+ pattern: '^[0-9]*[.,]?[0-9]*$',
37
+ spellCheck: false,
38
+ step: 'any',
39
+ };
40
+
41
+ const NumoraInput = forwardRef<HTMLInputElement, NumericInputProps>(
42
+ ({
43
+ maxDecimals = 2,
44
+ onChange,
45
+ formatOn = FormatOn.Blur,
46
+ thousandSeparator = ',',
47
+ thousandStyle = ThousandStyle.Thousand,
48
+ decimalSeparator = '.',
49
+ decimalMinLength,
50
+ enableCompactNotation = false,
51
+ enableNegative = false,
52
+ enableLeadingZeros = false,
53
+ rawValueMode = false,
54
+ ...props
55
+ }: NumericInputProps, ref) => {
56
+ const [caretPositionBeforeChange, setCaretPositionBeforeChange] =
57
+ React.useState<CaretPositionInfo>();
58
+
59
+ const formattingOptions: FormattingOptions = {
60
+ formatOn,
61
+ thousandSeparator,
62
+ ThousandStyle: thousandStyle as any,
63
+ decimalSeparator,
64
+ decimalMinLength,
65
+ enableCompactNotation,
66
+ enableNegative,
67
+ enableLeadingZeros,
68
+ rawValueMode,
69
+ };
70
+
71
+ function handleOnKeyDown(e: React.KeyboardEvent<HTMLInputElement>): void {
72
+ const caretInfo = handleOnKeyDownNumoraInput(e.nativeEvent, formattingOptions);
73
+
74
+ if (caretInfo) {
75
+ setCaretPositionBeforeChange(caretInfo);
76
+ } else {
77
+ const input = e.currentTarget;
78
+ setCaretPositionBeforeChange({
79
+ selectionStart: input.selectionStart ?? 0,
80
+ selectionEnd: input.selectionEnd ?? 0,
81
+ });
82
+ }
83
+
84
+ if (props.onKeyDown) {
85
+ props.onKeyDown(e);
86
+ }
87
+ }
88
+
89
+ function handleOnChange(e: ChangeEvent<HTMLInputElement>): void {
90
+ handleOnChangeNumoraInput(
91
+ e.nativeEvent,
92
+ maxDecimals,
93
+ caretPositionBeforeChange,
94
+ formattingOptions
95
+ );
96
+ setCaretPositionBeforeChange(undefined);
97
+ if (onChange) onChange(e);
98
+ }
99
+
100
+ function handleOnPaste(e: ClipboardEvent<HTMLInputElement>): void {
101
+ handleOnPasteNumoraInput(e.nativeEvent, maxDecimals, formattingOptions);
102
+ if (onChange) onChange(e);
103
+ }
104
+
105
+ function handleOnFocus(e: React.FocusEvent<HTMLInputElement>): void {
106
+ if (formatOn === FormatOn.Blur && thousandSeparator) {
107
+ const target = e.currentTarget;
108
+ target.value = target.value.replace(
109
+ new RegExp(thousandSeparator.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'), 'g'),
110
+ ''
111
+ );
112
+ }
113
+
114
+ if (props.onFocus) {
115
+ props.onFocus(e);
116
+ }
117
+ }
118
+
119
+ function handleOnBlur(e: React.FocusEvent<HTMLInputElement>): void {
120
+ if (props.onBlur) {
121
+ props.onBlur(e);
122
+ }
123
+ }
124
+
125
+ return (
126
+ <input
127
+ {...DEFAULT_PROPS}
128
+ {...props}
129
+ ref={ref}
130
+ onChange={handleOnChange}
131
+ onKeyDown={handleOnKeyDown}
132
+ onPaste={handleOnPaste}
133
+ onFocus={handleOnFocus}
134
+ onBlur={handleOnBlur}
135
+ type="text"
136
+ inputMode="decimal"
137
+ />
138
+ );
139
+ }
140
+ );
141
+
142
+ NumoraInput.displayName = 'NumoraInput';
143
+
144
+ export default NumoraInput;
package/tsconfig.json ADDED
@@ -0,0 +1,18 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ESNext",
4
+ "module": "ESNext",
5
+ "jsx": "react-jsx",
6
+ "declaration": true,
7
+ "outDir": "./dist",
8
+ "rootDir": "./src",
9
+ "strict": true,
10
+ "esModuleInterop": true,
11
+ "skipLibCheck": true,
12
+ "moduleResolution": "node",
13
+ "allowSyntheticDefaultImports": true,
14
+ "lib": ["ESNext", "DOM"]
15
+ },
16
+ "include": ["src/**/*"],
17
+ "exclude": ["node_modules", "dist"]
18
+ }