numora-react 1.0.2 → 1.0.3
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/dist/index.cjs.js +46 -16
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.esm.js +48 -18
- package/dist/index.esm.js.map +1 -1
- package/package.json +2 -2
package/dist/index.cjs.js
CHANGED
|
@@ -14,22 +14,24 @@ const DEFAULT_PROPS = {
|
|
|
14
14
|
spellCheck: false,
|
|
15
15
|
step: 'any'
|
|
16
16
|
};
|
|
17
|
-
const NumoraInput = /*#__PURE__*/React.forwardRef((
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
} = _ref;
|
|
17
|
+
const NumoraInput = /*#__PURE__*/React.forwardRef(({
|
|
18
|
+
maxDecimals = 2,
|
|
19
|
+
onChange,
|
|
20
|
+
formatOn = numora.FormatOn.Blur,
|
|
21
|
+
thousandSeparator = ',',
|
|
22
|
+
thousandStyle = numora.ThousandStyle.Thousand,
|
|
23
|
+
decimalSeparator = '.',
|
|
24
|
+
decimalMinLength,
|
|
25
|
+
enableCompactNotation = false,
|
|
26
|
+
enableNegative = false,
|
|
27
|
+
enableLeadingZeros = false,
|
|
28
|
+
rawValueMode = false,
|
|
29
|
+
...props
|
|
30
|
+
}, ref) => {
|
|
32
31
|
const [caretPositionBeforeChange, setCaretPositionBeforeChange] = React.useState();
|
|
32
|
+
const inputRef = React.useRef(null);
|
|
33
|
+
const isUserInputRef = React.useRef(false);
|
|
34
|
+
const previousValueRef = React.useRef(typeof props.value === 'string' ? props.value : props.value?.toString());
|
|
33
35
|
const formattingOptions = {
|
|
34
36
|
formatOn,
|
|
35
37
|
thousandSeparator,
|
|
@@ -41,6 +43,23 @@ const NumoraInput = /*#__PURE__*/React.forwardRef((_ref, ref) => {
|
|
|
41
43
|
enableLeadingZeros,
|
|
42
44
|
rawValueMode
|
|
43
45
|
};
|
|
46
|
+
// Handle programmatic value changes (when value prop changes externally)
|
|
47
|
+
React.useEffect(() => {
|
|
48
|
+
const input = inputRef.current;
|
|
49
|
+
if (!input) return;
|
|
50
|
+
const currentValue = typeof props.value === 'string' ? props.value : props.value !== undefined ? String(props.value) : undefined;
|
|
51
|
+
const previousValue = previousValueRef.current;
|
|
52
|
+
// Only format if value changed externally (not from user input)
|
|
53
|
+
if (!isUserInputRef.current && currentValue !== previousValue && currentValue !== undefined) {
|
|
54
|
+
const formatted = numora.formatValueForNumora(currentValue, maxDecimals, formattingOptions);
|
|
55
|
+
// Only update if formatted value differs from current input value
|
|
56
|
+
if (input.value !== formatted) {
|
|
57
|
+
input.value = formatted;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
previousValueRef.current = currentValue;
|
|
61
|
+
isUserInputRef.current = false;
|
|
62
|
+
}, [props.value, maxDecimals, formatOn, thousandSeparator, thousandStyle, decimalSeparator, decimalMinLength, enableCompactNotation, enableNegative, enableLeadingZeros, rawValueMode]);
|
|
44
63
|
function handleOnKeyDown(e) {
|
|
45
64
|
const caretInfo = numora.handleOnKeyDownNumoraInput(e.nativeEvent, formattingOptions);
|
|
46
65
|
if (caretInfo) {
|
|
@@ -57,11 +76,13 @@ const NumoraInput = /*#__PURE__*/React.forwardRef((_ref, ref) => {
|
|
|
57
76
|
}
|
|
58
77
|
}
|
|
59
78
|
function handleOnChange(e) {
|
|
79
|
+
isUserInputRef.current = true;
|
|
60
80
|
numora.handleOnChangeNumoraInput(e.nativeEvent, maxDecimals, caretPositionBeforeChange, formattingOptions);
|
|
61
81
|
setCaretPositionBeforeChange(undefined);
|
|
62
82
|
if (onChange) onChange(e);
|
|
63
83
|
}
|
|
64
84
|
function handleOnPaste(e) {
|
|
85
|
+
isUserInputRef.current = true;
|
|
65
86
|
numora.handleOnPasteNumoraInput(e.nativeEvent, maxDecimals, formattingOptions);
|
|
66
87
|
if (onChange) onChange(e);
|
|
67
88
|
}
|
|
@@ -79,10 +100,19 @@ const NumoraInput = /*#__PURE__*/React.forwardRef((_ref, ref) => {
|
|
|
79
100
|
props.onBlur(e);
|
|
80
101
|
}
|
|
81
102
|
}
|
|
103
|
+
// Combine refs: forward the ref and also store it internally
|
|
104
|
+
const setRefs = React.useCallback(node => {
|
|
105
|
+
inputRef.current = node;
|
|
106
|
+
if (typeof ref === 'function') {
|
|
107
|
+
ref(node);
|
|
108
|
+
} else if (ref) {
|
|
109
|
+
ref.current = node;
|
|
110
|
+
}
|
|
111
|
+
}, [ref]);
|
|
82
112
|
return jsxRuntime.jsx("input", {
|
|
83
113
|
...DEFAULT_PROPS,
|
|
84
114
|
...props,
|
|
85
|
-
ref:
|
|
115
|
+
ref: setRefs,
|
|
86
116
|
onChange: handleOnChange,
|
|
87
117
|
onKeyDown: handleOnKeyDown,
|
|
88
118
|
onPaste: handleOnPaste,
|
package/dist/index.cjs.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.cjs.js","sources":["../src/index.tsx"],"sourcesContent":["import React, { ChangeEvent, ClipboardEvent, forwardRef } from 'react';\nimport {\n NumoraInput,\n FormatOn,\n ThousandStyle,\n FormattingOptions,\n CaretPositionInfo,\n handleOnChangeNumoraInput,\n handleOnPasteNumoraInput,\n handleOnKeyDownNumoraInput,\n} from 'numora';\n\ninterface NumoraInputProps extends Omit<React.InputHTMLAttributes<HTMLInputElement>, 'onChange' | 'type' | 'inputMode'> {\n maxDecimals?: number;\n onChange?: (e: ChangeEvent<HTMLInputElement> | ClipboardEvent<HTMLInputElement>) => void;\n\n // Formatting options\n formatOn?: FormatOn;\n thousandSeparator?: string;\n thousandStyle?: ThousandStyle;\n decimalSeparator?: string;\n decimalMinLength?: number;\n\n // Feature flags\n enableCompactNotation?: boolean;\n enableNegative?: boolean;\n enableLeadingZeros?: boolean;\n rawValueMode?: boolean;\n}\n\nconst DEFAULT_PROPS = {\n autoComplete: 'off',\n autoCorrect: 'off',\n autoCapitalize: 'none',\n minLength: 1,\n placeholder: '0.0',\n pattern: '^[0-9]*[.,]?[0-9]*$',\n spellCheck: false,\n step: 'any',\n};\n\nconst NumoraInput = forwardRef<HTMLInputElement, NumoraInputProps>(\n ({\n maxDecimals = 2,\n onChange,\n formatOn = FormatOn.Blur,\n thousandSeparator = ',',\n thousandStyle = ThousandStyle.Thousand,\n decimalSeparator = '.',\n decimalMinLength,\n enableCompactNotation = false,\n enableNegative = false,\n enableLeadingZeros = false,\n rawValueMode = false,\n ...props\n }: NumoraInputProps, ref: React.Ref<HTMLInputElement>) => {\n const [caretPositionBeforeChange, setCaretPositionBeforeChange] =\n React.useState<CaretPositionInfo>();\n\n const formattingOptions: FormattingOptions = {\n formatOn,\n thousandSeparator,\n ThousandStyle: thousandStyle as any,\n decimalSeparator,\n decimalMinLength,\n enableCompactNotation,\n enableNegative,\n enableLeadingZeros,\n rawValueMode,\n };\n\n function handleOnKeyDown(e: React.KeyboardEvent<HTMLInputElement>): void {\n const caretInfo = handleOnKeyDownNumoraInput(e.nativeEvent, formattingOptions);\n\n if (caretInfo) {\n setCaretPositionBeforeChange(caretInfo);\n } else {\n const input = e.currentTarget;\n setCaretPositionBeforeChange({\n selectionStart: input.selectionStart ?? 0,\n selectionEnd: input.selectionEnd ?? 0,\n });\n }\n\n if (props.onKeyDown) {\n props.onKeyDown(e);\n }\n }\n\n function handleOnChange(e: ChangeEvent<HTMLInputElement>): void {\n handleOnChangeNumoraInput(\n e.nativeEvent,\n maxDecimals,\n caretPositionBeforeChange,\n formattingOptions\n );\n setCaretPositionBeforeChange(undefined);\n if (onChange) onChange(e);\n }\n\n function handleOnPaste(e: ClipboardEvent<HTMLInputElement>): void {\n handleOnPasteNumoraInput(e.nativeEvent, maxDecimals, formattingOptions);\n if (onChange) onChange(e);\n }\n\n function handleOnFocus(e: React.FocusEvent<HTMLInputElement>): void {\n if (formatOn === FormatOn.Blur && thousandSeparator) {\n const target = e.currentTarget;\n target.value = target.value.replace(\n new RegExp(thousandSeparator.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&'), 'g'),\n ''\n );\n }\n\n if (props.onFocus) {\n props.onFocus(e);\n }\n }\n\n function handleOnBlur(e: React.FocusEvent<HTMLInputElement>): void {\n if (props.onBlur) {\n props.onBlur(e);\n }\n }\n\n return (\n <input\n {...DEFAULT_PROPS}\n {...props}\n ref={ref}\n onChange={handleOnChange}\n onKeyDown={handleOnKeyDown}\n onPaste={handleOnPaste}\n onFocus={handleOnFocus}\n onBlur={handleOnBlur}\n type=\"text\"\n inputMode=\"decimal\"\n />\n );\n }\n);\n\nNumoraInput.displayName = 'NumoraInput';\n\nexport { NumoraInput };\nexport { FormatOn, ThousandStyle } from 'numora';\nexport type { FormattingOptions, CaretPositionInfo } from 'numora';\n"],"names":["DEFAULT_PROPS","autoComplete","autoCorrect","autoCapitalize","minLength","placeholder","pattern","spellCheck","step","NumoraInput","forwardRef","_ref","ref","maxDecimals","onChange","formatOn","FormatOn","Blur","thousandSeparator","thousandStyle","ThousandStyle","Thousand","decimalSeparator","decimalMinLength","enableCompactNotation","enableNegative","enableLeadingZeros","rawValueMode","props","caretPositionBeforeChange","setCaretPositionBeforeChange","React","useState","formattingOptions","handleOnKeyDown","e","caretInfo","handleOnKeyDownNumoraInput","nativeEvent","input","currentTarget","selectionStart","selectionEnd","onKeyDown","handleOnChange","handleOnChangeNumoraInput","undefined","handleOnPaste","handleOnPasteNumoraInput","handleOnFocus","target","value","replace","RegExp","onFocus","handleOnBlur","onBlur","_jsx","onPaste","type","inputMode","displayName"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.cjs.js","sources":["../src/index.tsx"],"sourcesContent":["import React, { ChangeEvent, ClipboardEvent, forwardRef, useEffect, useRef } from 'react';\nimport {\n FormatOn,\n ThousandStyle,\n FormattingOptions,\n CaretPositionInfo,\n handleOnChangeNumoraInput,\n handleOnPasteNumoraInput,\n handleOnKeyDownNumoraInput,\n formatValueForNumora,\n} from 'numora';\n\ninterface NumoraInputProps extends Omit<React.InputHTMLAttributes<HTMLInputElement>, 'onChange' | 'type' | 'inputMode'> {\n maxDecimals?: number;\n onChange?: (e: ChangeEvent<HTMLInputElement> | ClipboardEvent<HTMLInputElement>) => void;\n\n // Formatting options\n formatOn?: FormatOn;\n thousandSeparator?: string;\n thousandStyle?: ThousandStyle;\n decimalSeparator?: string;\n decimalMinLength?: number;\n\n // Feature flags\n enableCompactNotation?: boolean;\n enableNegative?: boolean;\n enableLeadingZeros?: boolean;\n rawValueMode?: boolean;\n}\n\nconst DEFAULT_PROPS = {\n autoComplete: 'off',\n autoCorrect: 'off',\n autoCapitalize: 'none',\n minLength: 1,\n placeholder: '0.0',\n pattern: '^[0-9]*[.,]?[0-9]*$',\n spellCheck: false,\n step: 'any',\n};\n\nconst NumoraInput = forwardRef<HTMLInputElement, NumoraInputProps>(\n ({\n maxDecimals = 2,\n onChange,\n formatOn = FormatOn.Blur,\n thousandSeparator = ',',\n thousandStyle = ThousandStyle.Thousand,\n decimalSeparator = '.',\n decimalMinLength,\n enableCompactNotation = false,\n enableNegative = false,\n enableLeadingZeros = false,\n rawValueMode = false,\n ...props\n }: NumoraInputProps, ref: React.Ref<HTMLInputElement>) => {\n const [caretPositionBeforeChange, setCaretPositionBeforeChange] =\n React.useState<CaretPositionInfo>();\n const inputRef = React.useRef<HTMLInputElement>(null);\n const isUserInputRef = useRef(false);\n const previousValueRef = useRef<string | undefined>(\n typeof props.value === 'string' ? props.value : props.value?.toString()\n );\n\n const formattingOptions: FormattingOptions = {\n formatOn,\n thousandSeparator,\n ThousandStyle: thousandStyle as any,\n decimalSeparator,\n decimalMinLength,\n enableCompactNotation,\n enableNegative,\n enableLeadingZeros,\n rawValueMode,\n };\n\n // Handle programmatic value changes (when value prop changes externally)\n useEffect(() => {\n const input = inputRef.current;\n if (!input) return;\n\n const currentValue = typeof props.value === 'string'\n ? props.value\n : props.value !== undefined\n ? String(props.value)\n : undefined;\n const previousValue = previousValueRef.current;\n\n // Only format if value changed externally (not from user input)\n if (!isUserInputRef.current && currentValue !== previousValue && currentValue !== undefined) {\n const formatted = formatValueForNumora(\n currentValue,\n maxDecimals,\n formattingOptions\n );\n\n // Only update if formatted value differs from current input value\n if (input.value !== formatted) {\n input.value = formatted;\n }\n }\n\n previousValueRef.current = currentValue;\n isUserInputRef.current = false;\n }, [props.value, maxDecimals, formatOn, thousandSeparator, thousandStyle, decimalSeparator, decimalMinLength, enableCompactNotation, enableNegative, enableLeadingZeros, rawValueMode]);\n\n function handleOnKeyDown(e: React.KeyboardEvent<HTMLInputElement>): void {\n const caretInfo = handleOnKeyDownNumoraInput(e.nativeEvent, formattingOptions);\n\n if (caretInfo) {\n setCaretPositionBeforeChange(caretInfo);\n } else {\n const input = e.currentTarget;\n setCaretPositionBeforeChange({\n selectionStart: input.selectionStart ?? 0,\n selectionEnd: input.selectionEnd ?? 0,\n });\n }\n\n if (props.onKeyDown) {\n props.onKeyDown(e);\n }\n }\n\n function handleOnChange(e: ChangeEvent<HTMLInputElement>): void {\n isUserInputRef.current = true;\n handleOnChangeNumoraInput(\n e.nativeEvent,\n maxDecimals,\n caretPositionBeforeChange,\n formattingOptions\n );\n setCaretPositionBeforeChange(undefined);\n if (onChange) onChange(e);\n }\n\n function handleOnPaste(e: ClipboardEvent<HTMLInputElement>): void {\n isUserInputRef.current = true;\n handleOnPasteNumoraInput(e.nativeEvent, maxDecimals, formattingOptions);\n if (onChange) onChange(e);\n }\n\n function handleOnFocus(e: React.FocusEvent<HTMLInputElement>): void {\n if (formatOn === FormatOn.Blur && thousandSeparator) {\n const target = e.currentTarget;\n target.value = target.value.replace(\n new RegExp(thousandSeparator.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&'), 'g'),\n ''\n );\n }\n\n if (props.onFocus) {\n props.onFocus(e);\n }\n }\n\n function handleOnBlur(e: React.FocusEvent<HTMLInputElement>): void {\n if (props.onBlur) {\n props.onBlur(e);\n }\n }\n\n // Combine refs: forward the ref and also store it internally\n const setRefs = React.useCallback((node: HTMLInputElement | null) => {\n inputRef.current = node;\n if (typeof ref === 'function') {\n ref(node);\n } else if (ref) {\n ref.current = node;\n }\n }, [ref]);\n\n return (\n <input\n {...DEFAULT_PROPS}\n {...props}\n ref={setRefs}\n onChange={handleOnChange}\n onKeyDown={handleOnKeyDown}\n onPaste={handleOnPaste}\n onFocus={handleOnFocus}\n onBlur={handleOnBlur}\n type=\"text\"\n inputMode=\"decimal\"\n />\n );\n }\n);\n\nNumoraInput.displayName = 'NumoraInput';\n\nexport { NumoraInput };\nexport { FormatOn, ThousandStyle } from 'numora';\nexport type { FormattingOptions, CaretPositionInfo } from 'numora';\n"],"names":["DEFAULT_PROPS","autoComplete","autoCorrect","autoCapitalize","minLength","placeholder","pattern","spellCheck","step","NumoraInput","forwardRef","maxDecimals","onChange","formatOn","FormatOn","Blur","thousandSeparator","thousandStyle","ThousandStyle","Thousand","decimalSeparator","decimalMinLength","enableCompactNotation","enableNegative","enableLeadingZeros","rawValueMode","props","ref","caretPositionBeforeChange","setCaretPositionBeforeChange","React","useState","inputRef","useRef","isUserInputRef","previousValueRef","value","toString","formattingOptions","useEffect","input","current","currentValue","undefined","String","previousValue","formatted","formatValueForNumora","handleOnKeyDown","e","caretInfo","handleOnKeyDownNumoraInput","nativeEvent","currentTarget","selectionStart","selectionEnd","onKeyDown","handleOnChange","handleOnChangeNumoraInput","handleOnPaste","handleOnPasteNumoraInput","handleOnFocus","target","replace","RegExp","onFocus","handleOnBlur","onBlur","setRefs","useCallback","node","_jsx","onPaste","type","inputMode","displayName"],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import React, { ChangeEvent, ClipboardEvent } from 'react';
|
|
2
|
-
import {
|
|
2
|
+
import { FormatOn, ThousandStyle } from 'numora';
|
|
3
3
|
interface NumoraInputProps extends Omit<React.InputHTMLAttributes<HTMLInputElement>, 'onChange' | 'type' | 'inputMode'> {
|
|
4
4
|
maxDecimals?: number;
|
|
5
5
|
onChange?: (e: ChangeEvent<HTMLInputElement> | ClipboardEvent<HTMLInputElement>) => void;
|
package/dist/index.esm.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { jsx } from 'react/jsx-runtime';
|
|
2
|
-
import React, { forwardRef } from 'react';
|
|
3
|
-
import {
|
|
2
|
+
import React, { forwardRef, useRef, useEffect } from 'react';
|
|
3
|
+
import { formatValueForNumora, ThousandStyle, FormatOn, handleOnPasteNumoraInput, handleOnKeyDownNumoraInput, handleOnChangeNumoraInput } from 'numora';
|
|
4
4
|
export { FormatOn, ThousandStyle } from 'numora';
|
|
5
5
|
|
|
6
6
|
const DEFAULT_PROPS = {
|
|
@@ -13,22 +13,24 @@ const DEFAULT_PROPS = {
|
|
|
13
13
|
spellCheck: false,
|
|
14
14
|
step: 'any'
|
|
15
15
|
};
|
|
16
|
-
const NumoraInput = /*#__PURE__*/forwardRef((
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
} = _ref;
|
|
16
|
+
const NumoraInput = /*#__PURE__*/forwardRef(({
|
|
17
|
+
maxDecimals = 2,
|
|
18
|
+
onChange,
|
|
19
|
+
formatOn = FormatOn.Blur,
|
|
20
|
+
thousandSeparator = ',',
|
|
21
|
+
thousandStyle = ThousandStyle.Thousand,
|
|
22
|
+
decimalSeparator = '.',
|
|
23
|
+
decimalMinLength,
|
|
24
|
+
enableCompactNotation = false,
|
|
25
|
+
enableNegative = false,
|
|
26
|
+
enableLeadingZeros = false,
|
|
27
|
+
rawValueMode = false,
|
|
28
|
+
...props
|
|
29
|
+
}, ref) => {
|
|
31
30
|
const [caretPositionBeforeChange, setCaretPositionBeforeChange] = React.useState();
|
|
31
|
+
const inputRef = React.useRef(null);
|
|
32
|
+
const isUserInputRef = useRef(false);
|
|
33
|
+
const previousValueRef = useRef(typeof props.value === 'string' ? props.value : props.value?.toString());
|
|
32
34
|
const formattingOptions = {
|
|
33
35
|
formatOn,
|
|
34
36
|
thousandSeparator,
|
|
@@ -40,6 +42,23 @@ const NumoraInput = /*#__PURE__*/forwardRef((_ref, ref) => {
|
|
|
40
42
|
enableLeadingZeros,
|
|
41
43
|
rawValueMode
|
|
42
44
|
};
|
|
45
|
+
// Handle programmatic value changes (when value prop changes externally)
|
|
46
|
+
useEffect(() => {
|
|
47
|
+
const input = inputRef.current;
|
|
48
|
+
if (!input) return;
|
|
49
|
+
const currentValue = typeof props.value === 'string' ? props.value : props.value !== undefined ? String(props.value) : undefined;
|
|
50
|
+
const previousValue = previousValueRef.current;
|
|
51
|
+
// Only format if value changed externally (not from user input)
|
|
52
|
+
if (!isUserInputRef.current && currentValue !== previousValue && currentValue !== undefined) {
|
|
53
|
+
const formatted = formatValueForNumora(currentValue, maxDecimals, formattingOptions);
|
|
54
|
+
// Only update if formatted value differs from current input value
|
|
55
|
+
if (input.value !== formatted) {
|
|
56
|
+
input.value = formatted;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
previousValueRef.current = currentValue;
|
|
60
|
+
isUserInputRef.current = false;
|
|
61
|
+
}, [props.value, maxDecimals, formatOn, thousandSeparator, thousandStyle, decimalSeparator, decimalMinLength, enableCompactNotation, enableNegative, enableLeadingZeros, rawValueMode]);
|
|
43
62
|
function handleOnKeyDown(e) {
|
|
44
63
|
const caretInfo = handleOnKeyDownNumoraInput(e.nativeEvent, formattingOptions);
|
|
45
64
|
if (caretInfo) {
|
|
@@ -56,11 +75,13 @@ const NumoraInput = /*#__PURE__*/forwardRef((_ref, ref) => {
|
|
|
56
75
|
}
|
|
57
76
|
}
|
|
58
77
|
function handleOnChange(e) {
|
|
78
|
+
isUserInputRef.current = true;
|
|
59
79
|
handleOnChangeNumoraInput(e.nativeEvent, maxDecimals, caretPositionBeforeChange, formattingOptions);
|
|
60
80
|
setCaretPositionBeforeChange(undefined);
|
|
61
81
|
if (onChange) onChange(e);
|
|
62
82
|
}
|
|
63
83
|
function handleOnPaste(e) {
|
|
84
|
+
isUserInputRef.current = true;
|
|
64
85
|
handleOnPasteNumoraInput(e.nativeEvent, maxDecimals, formattingOptions);
|
|
65
86
|
if (onChange) onChange(e);
|
|
66
87
|
}
|
|
@@ -78,10 +99,19 @@ const NumoraInput = /*#__PURE__*/forwardRef((_ref, ref) => {
|
|
|
78
99
|
props.onBlur(e);
|
|
79
100
|
}
|
|
80
101
|
}
|
|
102
|
+
// Combine refs: forward the ref and also store it internally
|
|
103
|
+
const setRefs = React.useCallback(node => {
|
|
104
|
+
inputRef.current = node;
|
|
105
|
+
if (typeof ref === 'function') {
|
|
106
|
+
ref(node);
|
|
107
|
+
} else if (ref) {
|
|
108
|
+
ref.current = node;
|
|
109
|
+
}
|
|
110
|
+
}, [ref]);
|
|
81
111
|
return jsx("input", {
|
|
82
112
|
...DEFAULT_PROPS,
|
|
83
113
|
...props,
|
|
84
|
-
ref:
|
|
114
|
+
ref: setRefs,
|
|
85
115
|
onChange: handleOnChange,
|
|
86
116
|
onKeyDown: handleOnKeyDown,
|
|
87
117
|
onPaste: handleOnPaste,
|
package/dist/index.esm.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.esm.js","sources":["../src/index.tsx"],"sourcesContent":["import React, { ChangeEvent, ClipboardEvent, forwardRef } from 'react';\nimport {\n NumoraInput,\n FormatOn,\n ThousandStyle,\n FormattingOptions,\n CaretPositionInfo,\n handleOnChangeNumoraInput,\n handleOnPasteNumoraInput,\n handleOnKeyDownNumoraInput,\n} from 'numora';\n\ninterface NumoraInputProps extends Omit<React.InputHTMLAttributes<HTMLInputElement>, 'onChange' | 'type' | 'inputMode'> {\n maxDecimals?: number;\n onChange?: (e: ChangeEvent<HTMLInputElement> | ClipboardEvent<HTMLInputElement>) => void;\n\n // Formatting options\n formatOn?: FormatOn;\n thousandSeparator?: string;\n thousandStyle?: ThousandStyle;\n decimalSeparator?: string;\n decimalMinLength?: number;\n\n // Feature flags\n enableCompactNotation?: boolean;\n enableNegative?: boolean;\n enableLeadingZeros?: boolean;\n rawValueMode?: boolean;\n}\n\nconst DEFAULT_PROPS = {\n autoComplete: 'off',\n autoCorrect: 'off',\n autoCapitalize: 'none',\n minLength: 1,\n placeholder: '0.0',\n pattern: '^[0-9]*[.,]?[0-9]*$',\n spellCheck: false,\n step: 'any',\n};\n\nconst NumoraInput = forwardRef<HTMLInputElement, NumoraInputProps>(\n ({\n maxDecimals = 2,\n onChange,\n formatOn = FormatOn.Blur,\n thousandSeparator = ',',\n thousandStyle = ThousandStyle.Thousand,\n decimalSeparator = '.',\n decimalMinLength,\n enableCompactNotation = false,\n enableNegative = false,\n enableLeadingZeros = false,\n rawValueMode = false,\n ...props\n }: NumoraInputProps, ref: React.Ref<HTMLInputElement>) => {\n const [caretPositionBeforeChange, setCaretPositionBeforeChange] =\n React.useState<CaretPositionInfo>();\n\n const formattingOptions: FormattingOptions = {\n formatOn,\n thousandSeparator,\n ThousandStyle: thousandStyle as any,\n decimalSeparator,\n decimalMinLength,\n enableCompactNotation,\n enableNegative,\n enableLeadingZeros,\n rawValueMode,\n };\n\n function handleOnKeyDown(e: React.KeyboardEvent<HTMLInputElement>): void {\n const caretInfo = handleOnKeyDownNumoraInput(e.nativeEvent, formattingOptions);\n\n if (caretInfo) {\n setCaretPositionBeforeChange(caretInfo);\n } else {\n const input = e.currentTarget;\n setCaretPositionBeforeChange({\n selectionStart: input.selectionStart ?? 0,\n selectionEnd: input.selectionEnd ?? 0,\n });\n }\n\n if (props.onKeyDown) {\n props.onKeyDown(e);\n }\n }\n\n function handleOnChange(e: ChangeEvent<HTMLInputElement>): void {\n handleOnChangeNumoraInput(\n e.nativeEvent,\n maxDecimals,\n caretPositionBeforeChange,\n formattingOptions\n );\n setCaretPositionBeforeChange(undefined);\n if (onChange) onChange(e);\n }\n\n function handleOnPaste(e: ClipboardEvent<HTMLInputElement>): void {\n handleOnPasteNumoraInput(e.nativeEvent, maxDecimals, formattingOptions);\n if (onChange) onChange(e);\n }\n\n function handleOnFocus(e: React.FocusEvent<HTMLInputElement>): void {\n if (formatOn === FormatOn.Blur && thousandSeparator) {\n const target = e.currentTarget;\n target.value = target.value.replace(\n new RegExp(thousandSeparator.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&'), 'g'),\n ''\n );\n }\n\n if (props.onFocus) {\n props.onFocus(e);\n }\n }\n\n function handleOnBlur(e: React.FocusEvent<HTMLInputElement>): void {\n if (props.onBlur) {\n props.onBlur(e);\n }\n }\n\n return (\n <input\n {...DEFAULT_PROPS}\n {...props}\n ref={ref}\n onChange={handleOnChange}\n onKeyDown={handleOnKeyDown}\n onPaste={handleOnPaste}\n onFocus={handleOnFocus}\n onBlur={handleOnBlur}\n type=\"text\"\n inputMode=\"decimal\"\n />\n );\n }\n);\n\nNumoraInput.displayName = 'NumoraInput';\n\nexport { NumoraInput };\nexport { FormatOn, ThousandStyle } from 'numora';\nexport type { FormattingOptions, CaretPositionInfo } from 'numora';\n"],"names":["DEFAULT_PROPS","autoComplete","autoCorrect","autoCapitalize","minLength","placeholder","pattern","spellCheck","step","NumoraInput","forwardRef","_ref","ref","maxDecimals","onChange","formatOn","FormatOn","Blur","thousandSeparator","thousandStyle","ThousandStyle","Thousand","decimalSeparator","decimalMinLength","enableCompactNotation","enableNegative","enableLeadingZeros","rawValueMode","props","caretPositionBeforeChange","setCaretPositionBeforeChange","React","useState","formattingOptions","handleOnKeyDown","e","caretInfo","handleOnKeyDownNumoraInput","nativeEvent","input","currentTarget","selectionStart","selectionEnd","onKeyDown","handleOnChange","handleOnChangeNumoraInput","undefined","handleOnPaste","handleOnPasteNumoraInput","handleOnFocus","target","value","replace","RegExp","onFocus","handleOnBlur","onBlur","_jsx","onPaste","type","inputMode","displayName"],"mappings":";;;;;AA8BA,MAAMA,aAAa,GAAG;AACpBC,EAAAA,YAAY,EAAE,KAAK;AACnBC,EAAAA,WAAW,EAAE,KAAK;AAClBC,EAAAA,cAAc,EAAE,MAAM;AACtBC,EAAAA,SAAS,EAAE,CAAC;AACZC,EAAAA,WAAW,EAAE,KAAK;AAClBC,EAAAA,OAAO,EAAE,qBAAqB;AAC9BC,EAAAA,UAAU,EAAE,KAAK;AACjBC,EAAAA,IAAI,EAAE;CACP;AAEKC,MAAAA,WAAW,gBAAGC,UAAU,CAC5B,CAAAC,IAAA,EAaqBC,GAAgC,KAAI;EAAA,IAbxD;AACCC,IAAAA,WAAW,GAAG,CAAC;IACfC,QAAQ;IACRC,QAAQ,GAAGC,QAAQ,CAACC,IAAI;AACxBC,IAAAA,iBAAiB,GAAG,GAAG;IACvBC,aAAa,GAAGC,aAAa,CAACC,QAAQ;AACtCC,IAAAA,gBAAgB,GAAG,GAAG;IACtBC,gBAAgB;AAChBC,IAAAA,qBAAqB,GAAG,KAAK;AAC7BC,IAAAA,cAAc,GAAG,KAAK;AACtBC,IAAAA,kBAAkB,GAAG,KAAK;AAC1BC,IAAAA,YAAY,GAAG,KAAK;IACpB,GAAGC;AACc,GAAA,GAAAjB,IAAA;EACjB,MAAM,CAACkB,yBAAyB,EAAEC,4BAA4B,CAAC,GAC7DC,KAAK,CAACC,QAAQ,EAAqB;AAErC,EAAA,MAAMC,iBAAiB,GAAsB;IAC3ClB,QAAQ;IACRG,iBAAiB;AACjBE,IAAAA,aAAa,EAAED,aAAoB;IACnCG,gBAAgB;IAChBC,gBAAgB;IAChBC,qBAAqB;IACrBC,cAAc;IACdC,kBAAkB;AAClBC,IAAAA;GACD;EAED,SAASO,eAAeA,CAACC,CAAwC,EAAA;IAC/D,MAAMC,SAAS,GAAGC,0BAA0B,CAACF,CAAC,CAACG,WAAW,EAAEL,iBAAiB,CAAC;AAE9E,IAAA,IAAIG,SAAS,EAAE;MACbN,4BAA4B,CAACM,SAAS,CAAC;AACzC,KAAC,MAAM;AACL,MAAA,MAAMG,KAAK,GAAGJ,CAAC,CAACK,aAAa;AAC7BV,MAAAA,4BAA4B,CAAC;AAC3BW,QAAAA,cAAc,EAAEF,KAAK,CAACE,cAAc,IAAI,CAAC;AACzCC,QAAAA,YAAY,EAAEH,KAAK,CAACG,YAAY,IAAI;AACrC,OAAA,CAAC;AACJ;IAEA,IAAId,KAAK,CAACe,SAAS,EAAE;AACnBf,MAAAA,KAAK,CAACe,SAAS,CAACR,CAAC,CAAC;AACpB;AACF;EAEA,SAASS,cAAcA,CAACT,CAAgC,EAAA;IACtDU,yBAAyB,CACvBV,CAAC,CAACG,WAAW,EACbzB,WAAW,EACXgB,yBAAyB,EACzBI,iBAAiB,CAClB;IACDH,4BAA4B,CAACgB,SAAS,CAAC;AACvC,IAAA,IAAIhC,QAAQ,EAAEA,QAAQ,CAACqB,CAAC,CAAC;AAC3B;EAEA,SAASY,aAAaA,CAACZ,CAAmC,EAAA;IACxDa,wBAAwB,CAACb,CAAC,CAACG,WAAW,EAAEzB,WAAW,EAAEoB,iBAAiB,CAAC;AACvE,IAAA,IAAInB,QAAQ,EAAEA,QAAQ,CAACqB,CAAC,CAAC;AAC3B;EAEA,SAASc,aAAaA,CAACd,CAAqC,EAAA;AAC1D,IAAA,IAAIpB,QAAQ,KAAKC,QAAQ,CAACC,IAAI,IAAIC,iBAAiB,EAAE;AACnD,MAAA,MAAMgC,MAAM,GAAGf,CAAC,CAACK,aAAa;MAC9BU,MAAM,CAACC,KAAK,GAAGD,MAAM,CAACC,KAAK,CAACC,OAAO,CACjC,IAAIC,MAAM,CAACnC,iBAAiB,CAACkC,OAAO,CAAC,qBAAqB,EAAE,MAAM,CAAC,EAAE,GAAG,CAAC,EACzE,EAAE,CACH;AACH;IAEA,IAAIxB,KAAK,CAAC0B,OAAO,EAAE;AACjB1B,MAAAA,KAAK,CAAC0B,OAAO,CAACnB,CAAC,CAAC;AAClB;AACF;EAEA,SAASoB,YAAYA,CAACpB,CAAqC,EAAA;IACzD,IAAIP,KAAK,CAAC4B,MAAM,EAAE;AAChB5B,MAAAA,KAAK,CAAC4B,MAAM,CAACrB,CAAC,CAAC;AACjB;AACF;EAEA,OACEsB,GACM,CAAA,OAAA,EAAA;AAAA,IAAA,GAAAzD,aAAa;AACb,IAAA,GAAA4B,KAAK;AACThB,IAAAA,GAAG,EAAEA,GAAG;AACRE,IAAAA,QAAQ,EAAE8B,cAAc;AACxBD,IAAAA,SAAS,EAAET,eAAe;AAC1BwB,IAAAA,OAAO,EAAEX,aAAa;AACtBO,IAAAA,OAAO,EAAEL,aAAa;AACtBO,IAAAA,MAAM,EAAED,YAAY;AACpBI,IAAAA,IAAI,EAAC,MAAM;AACXC,IAAAA,SAAS,EAAC;AAAS,GAAA,CACnB;AAEN,CAAC;AAGHnD,WAAW,CAACoD,WAAW,GAAG,aAAa;;;;"}
|
|
1
|
+
{"version":3,"file":"index.esm.js","sources":["../src/index.tsx"],"sourcesContent":["import React, { ChangeEvent, ClipboardEvent, forwardRef, useEffect, useRef } from 'react';\nimport {\n FormatOn,\n ThousandStyle,\n FormattingOptions,\n CaretPositionInfo,\n handleOnChangeNumoraInput,\n handleOnPasteNumoraInput,\n handleOnKeyDownNumoraInput,\n formatValueForNumora,\n} from 'numora';\n\ninterface NumoraInputProps extends Omit<React.InputHTMLAttributes<HTMLInputElement>, 'onChange' | 'type' | 'inputMode'> {\n maxDecimals?: number;\n onChange?: (e: ChangeEvent<HTMLInputElement> | ClipboardEvent<HTMLInputElement>) => void;\n\n // Formatting options\n formatOn?: FormatOn;\n thousandSeparator?: string;\n thousandStyle?: ThousandStyle;\n decimalSeparator?: string;\n decimalMinLength?: number;\n\n // Feature flags\n enableCompactNotation?: boolean;\n enableNegative?: boolean;\n enableLeadingZeros?: boolean;\n rawValueMode?: boolean;\n}\n\nconst DEFAULT_PROPS = {\n autoComplete: 'off',\n autoCorrect: 'off',\n autoCapitalize: 'none',\n minLength: 1,\n placeholder: '0.0',\n pattern: '^[0-9]*[.,]?[0-9]*$',\n spellCheck: false,\n step: 'any',\n};\n\nconst NumoraInput = forwardRef<HTMLInputElement, NumoraInputProps>(\n ({\n maxDecimals = 2,\n onChange,\n formatOn = FormatOn.Blur,\n thousandSeparator = ',',\n thousandStyle = ThousandStyle.Thousand,\n decimalSeparator = '.',\n decimalMinLength,\n enableCompactNotation = false,\n enableNegative = false,\n enableLeadingZeros = false,\n rawValueMode = false,\n ...props\n }: NumoraInputProps, ref: React.Ref<HTMLInputElement>) => {\n const [caretPositionBeforeChange, setCaretPositionBeforeChange] =\n React.useState<CaretPositionInfo>();\n const inputRef = React.useRef<HTMLInputElement>(null);\n const isUserInputRef = useRef(false);\n const previousValueRef = useRef<string | undefined>(\n typeof props.value === 'string' ? props.value : props.value?.toString()\n );\n\n const formattingOptions: FormattingOptions = {\n formatOn,\n thousandSeparator,\n ThousandStyle: thousandStyle as any,\n decimalSeparator,\n decimalMinLength,\n enableCompactNotation,\n enableNegative,\n enableLeadingZeros,\n rawValueMode,\n };\n\n // Handle programmatic value changes (when value prop changes externally)\n useEffect(() => {\n const input = inputRef.current;\n if (!input) return;\n\n const currentValue = typeof props.value === 'string'\n ? props.value\n : props.value !== undefined\n ? String(props.value)\n : undefined;\n const previousValue = previousValueRef.current;\n\n // Only format if value changed externally (not from user input)\n if (!isUserInputRef.current && currentValue !== previousValue && currentValue !== undefined) {\n const formatted = formatValueForNumora(\n currentValue,\n maxDecimals,\n formattingOptions\n );\n\n // Only update if formatted value differs from current input value\n if (input.value !== formatted) {\n input.value = formatted;\n }\n }\n\n previousValueRef.current = currentValue;\n isUserInputRef.current = false;\n }, [props.value, maxDecimals, formatOn, thousandSeparator, thousandStyle, decimalSeparator, decimalMinLength, enableCompactNotation, enableNegative, enableLeadingZeros, rawValueMode]);\n\n function handleOnKeyDown(e: React.KeyboardEvent<HTMLInputElement>): void {\n const caretInfo = handleOnKeyDownNumoraInput(e.nativeEvent, formattingOptions);\n\n if (caretInfo) {\n setCaretPositionBeforeChange(caretInfo);\n } else {\n const input = e.currentTarget;\n setCaretPositionBeforeChange({\n selectionStart: input.selectionStart ?? 0,\n selectionEnd: input.selectionEnd ?? 0,\n });\n }\n\n if (props.onKeyDown) {\n props.onKeyDown(e);\n }\n }\n\n function handleOnChange(e: ChangeEvent<HTMLInputElement>): void {\n isUserInputRef.current = true;\n handleOnChangeNumoraInput(\n e.nativeEvent,\n maxDecimals,\n caretPositionBeforeChange,\n formattingOptions\n );\n setCaretPositionBeforeChange(undefined);\n if (onChange) onChange(e);\n }\n\n function handleOnPaste(e: ClipboardEvent<HTMLInputElement>): void {\n isUserInputRef.current = true;\n handleOnPasteNumoraInput(e.nativeEvent, maxDecimals, formattingOptions);\n if (onChange) onChange(e);\n }\n\n function handleOnFocus(e: React.FocusEvent<HTMLInputElement>): void {\n if (formatOn === FormatOn.Blur && thousandSeparator) {\n const target = e.currentTarget;\n target.value = target.value.replace(\n new RegExp(thousandSeparator.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&'), 'g'),\n ''\n );\n }\n\n if (props.onFocus) {\n props.onFocus(e);\n }\n }\n\n function handleOnBlur(e: React.FocusEvent<HTMLInputElement>): void {\n if (props.onBlur) {\n props.onBlur(e);\n }\n }\n\n // Combine refs: forward the ref and also store it internally\n const setRefs = React.useCallback((node: HTMLInputElement | null) => {\n inputRef.current = node;\n if (typeof ref === 'function') {\n ref(node);\n } else if (ref) {\n ref.current = node;\n }\n }, [ref]);\n\n return (\n <input\n {...DEFAULT_PROPS}\n {...props}\n ref={setRefs}\n onChange={handleOnChange}\n onKeyDown={handleOnKeyDown}\n onPaste={handleOnPaste}\n onFocus={handleOnFocus}\n onBlur={handleOnBlur}\n type=\"text\"\n inputMode=\"decimal\"\n />\n );\n }\n);\n\nNumoraInput.displayName = 'NumoraInput';\n\nexport { NumoraInput };\nexport { FormatOn, ThousandStyle } from 'numora';\nexport type { FormattingOptions, CaretPositionInfo } from 'numora';\n"],"names":["DEFAULT_PROPS","autoComplete","autoCorrect","autoCapitalize","minLength","placeholder","pattern","spellCheck","step","NumoraInput","forwardRef","maxDecimals","onChange","formatOn","FormatOn","Blur","thousandSeparator","thousandStyle","ThousandStyle","Thousand","decimalSeparator","decimalMinLength","enableCompactNotation","enableNegative","enableLeadingZeros","rawValueMode","props","ref","caretPositionBeforeChange","setCaretPositionBeforeChange","React","useState","inputRef","useRef","isUserInputRef","previousValueRef","value","toString","formattingOptions","useEffect","input","current","currentValue","undefined","String","previousValue","formatted","formatValueForNumora","handleOnKeyDown","e","caretInfo","handleOnKeyDownNumoraInput","nativeEvent","currentTarget","selectionStart","selectionEnd","onKeyDown","handleOnChange","handleOnChangeNumoraInput","handleOnPaste","handleOnPasteNumoraInput","handleOnFocus","target","replace","RegExp","onFocus","handleOnBlur","onBlur","setRefs","useCallback","node","_jsx","onPaste","type","inputMode","displayName"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "numora-react",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.3",
|
|
4
4
|
"description": "Numora for React - Headless finance input library",
|
|
5
5
|
"homepage": "https://numora.xyz/",
|
|
6
6
|
"type": "module",
|
|
@@ -51,7 +51,7 @@
|
|
|
51
51
|
"react-dom": "^18.0.0 || ^19.0.0"
|
|
52
52
|
},
|
|
53
53
|
"dependencies": {
|
|
54
|
-
"numora": "2.0.
|
|
54
|
+
"numora": "^2.0.2"
|
|
55
55
|
},
|
|
56
56
|
"devDependencies": {
|
|
57
57
|
"@babel/core": "^7.26.10",
|