@servicetitan/form 17.0.0 → 17.2.0
Sign up to get free protection for your applications and to get access to all the features.
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"number-input.d.ts","sourceRoot":"","sources":["../../src/number-input/number-input.tsx"],"names":[],"mappings":";
|
1
|
+
{"version":3,"file":"number-input.d.ts","sourceRoot":"","sources":["../../src/number-input/number-input.tsx"],"names":[],"mappings":";AAYA,OAAO,EAAS,UAAU,EAAqB,MAAM,6BAA6B,CAAC;AAInF,OAAO,EAAE,YAAY,EAAsB,MAAM,wBAAwB,CAAC;AAC1E,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAS9D,MAAM,WAAW,gBAAgB,CAAC,MAAM,SAAS,UAAU,CACvD,SAAQ,IAAI,CAAC,UAAU,EAAE,OAAO,GAAG,UAAU,CAAC;IAC9C,KAAK,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;IAC3B,UAAU,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,0BAA0B,CAAC,EAAE,OAAO,CAAC;IACrC,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,qBAAqB,CAAC,EAAE,OAAO,CAAC;IAChC,YAAY,CAAC,EAAE,YAAY,CAAC;IAC5B,QAAQ,CAAC,KAAK,EAAE,WAAW,CAAC,MAAM,CAAC,GAAG,IAAI,CAAC;CAC9C;AAED,eAAO,MAAM,WAAW,4NA8LvB,CAAC"}
|
@@ -10,6 +10,9 @@ var __rest = (this && this.__rest) || function (s, e) {
|
|
10
10
|
}
|
11
11
|
return t;
|
12
12
|
};
|
13
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
14
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
15
|
+
};
|
13
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
14
17
|
exports.NumberInput = void 0;
|
15
18
|
const jsx_runtime_1 = require("react/jsx-runtime");
|
@@ -20,11 +23,13 @@ const culture_1 = require("@servicetitan/culture");
|
|
20
23
|
const process_value_1 = require("./process-value");
|
21
24
|
const get_formatted_string_1 = require("./get-formatted-string");
|
22
25
|
const accounting_1 = require("accounting");
|
26
|
+
const debounce_1 = __importDefault(require("debounce"));
|
23
27
|
const ARROW_UP_KEY = 38;
|
24
28
|
const ARROW_DOWN_KEY = 40;
|
29
|
+
const DEBOUNCE_WAIT = 300;
|
25
30
|
const NumberInput = (_a) => {
|
26
31
|
var { value, onChange, onFocus, onBlur, emptyValue, decimalPlaces, useEmptyThousandsSeparator, min, max, useKeyboardNavigation, formatNumber = accounting_1.formatNumber } = _a, props = __rest(_a, ["value", "onChange", "onFocus", "onBlur", "emptyValue", "decimalPlaces", "useEmptyThousandsSeparator", "min", "max", "useKeyboardNavigation", "formatNumber"]);
|
27
|
-
const [{ NumberFormat: { NumberGroupSeparator: thousandsSeparator = ',', NumberDecimalSeparator: decimalSeparator = '.', }, } = {
|
32
|
+
const [{ NumberFormat: { NumberGroupSeparator: thousandsSeparator = ',', NumberDecimalSeparator: decimalSeparator = '.', } = {}, } = {},] = (0, react_ioc_1.useOptionalDependencies)(culture_1.CULTURE_TOKEN);
|
28
33
|
const getFormattedValue = (0, react_1.useCallback)(() => (0, get_formatted_string_1.getFormattedString)(value, {
|
29
34
|
emptyValue,
|
30
35
|
precision: decimalPlaces,
|
@@ -66,7 +71,13 @@ const NumberInput = (_a) => {
|
|
66
71
|
event.preventDefault();
|
67
72
|
}
|
68
73
|
};
|
69
|
-
|
74
|
+
/*
|
75
|
+
** "updateImmediateValue" updates the value immediately without clamping min/max,
|
76
|
+
** then "updateClampedValueDebounced" updates applying the min/max after debounce delay
|
77
|
+
**
|
78
|
+
** Example: User can type "100" if min is "5" without the "1" immediately being clamped
|
79
|
+
*/
|
80
|
+
const updateImmediateValue = (value, silent = false) => {
|
70
81
|
const newState = (0, process_value_1.processValue)(value, {
|
71
82
|
emptyValue,
|
72
83
|
precision: decimalPlaces,
|
@@ -74,16 +85,51 @@ const NumberInput = (_a) => {
|
|
74
85
|
thousand: thousandsSeparator,
|
75
86
|
decimal: decimalSeparator,
|
76
87
|
},
|
77
|
-
range: {
|
78
|
-
min,
|
79
|
-
max,
|
80
|
-
},
|
81
88
|
}, formatNumber);
|
82
89
|
setState(newState);
|
83
90
|
if (!silent) {
|
84
91
|
onChange(newState.numberValue);
|
85
92
|
}
|
86
93
|
};
|
94
|
+
const updateClampedValueDebounced = (0, react_1.useRef)();
|
95
|
+
(0, react_1.useEffect)(() => {
|
96
|
+
let isCurrent = true;
|
97
|
+
const updateClampedValue = (value, silent = false) => {
|
98
|
+
if (isCurrent) {
|
99
|
+
const newState = (0, process_value_1.processValue)(value, {
|
100
|
+
emptyValue,
|
101
|
+
precision: decimalPlaces,
|
102
|
+
separators: {
|
103
|
+
thousand: thousandsSeparator,
|
104
|
+
decimal: decimalSeparator,
|
105
|
+
},
|
106
|
+
range: { min, max },
|
107
|
+
}, formatNumber);
|
108
|
+
setState(newState);
|
109
|
+
if (!silent) {
|
110
|
+
onChange(newState.numberValue);
|
111
|
+
}
|
112
|
+
}
|
113
|
+
};
|
114
|
+
updateClampedValueDebounced.current = (0, debounce_1.default)(updateClampedValue, DEBOUNCE_WAIT);
|
115
|
+
return () => {
|
116
|
+
isCurrent = false;
|
117
|
+
};
|
118
|
+
}, [
|
119
|
+
emptyValue,
|
120
|
+
decimalPlaces,
|
121
|
+
thousandsSeparator,
|
122
|
+
decimalSeparator,
|
123
|
+
min,
|
124
|
+
max,
|
125
|
+
formatNumber,
|
126
|
+
onChange,
|
127
|
+
]);
|
128
|
+
const updateValue = (value, silent = false) => {
|
129
|
+
var _a;
|
130
|
+
updateImmediateValue(value, silent);
|
131
|
+
(_a = updateClampedValueDebounced.current) === null || _a === void 0 ? void 0 : _a.call(updateClampedValueDebounced, value, silent);
|
132
|
+
};
|
87
133
|
const handleFocus = (event) => {
|
88
134
|
if (state.numberValue !== undefined) {
|
89
135
|
updateValue(String(state.numberValue), true);
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"number-input.js","sourceRoot":"","sources":["../../src/number-input/number-input.tsx"],"names":[],"mappings":"
|
1
|
+
{"version":3,"file":"number-input.js","sourceRoot":"","sources":["../../src/number-input/number-input.tsx"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@servicetitan/form",
|
3
|
-
"version": "17.
|
3
|
+
"version": "17.2.0",
|
4
4
|
"description": "",
|
5
5
|
"homepage": "https://docs.st.dev/docs/frontend/form",
|
6
6
|
"repository": {
|
@@ -15,14 +15,14 @@
|
|
15
15
|
"src"
|
16
16
|
],
|
17
17
|
"devDependencies": {
|
18
|
-
"@servicetitan/confirm": "^17.
|
19
|
-
"@servicetitan/culture": "^17.
|
20
|
-
"@servicetitan/data-query": "^17.
|
18
|
+
"@servicetitan/confirm": "^17.2.0",
|
19
|
+
"@servicetitan/culture": "^17.2.0",
|
20
|
+
"@servicetitan/data-query": "^17.2.0",
|
21
21
|
"@servicetitan/design-system": "~10.3.3",
|
22
|
-
"@servicetitan/react-ioc": "^17.
|
22
|
+
"@servicetitan/react-ioc": "^17.2.0",
|
23
23
|
"@servicetitan/tokens": "~10.3.3",
|
24
24
|
"@types/debounce": "~1.2.1",
|
25
|
-
"@types/react": "~17.0.
|
25
|
+
"@types/react": "~17.0.27",
|
26
26
|
"@types/react-input-mask": "~2.0.5",
|
27
27
|
"@types/uuid": "~8.3.1",
|
28
28
|
"accounting": "~0.4.1",
|
@@ -65,5 +65,5 @@
|
|
65
65
|
"cli": {
|
66
66
|
"webpack": false
|
67
67
|
},
|
68
|
-
"gitHead": "
|
68
|
+
"gitHead": "4a3151bd82763b1a8d4407bcabc675bb17d6a629"
|
69
69
|
}
|
@@ -1,4 +1,12 @@
|
|
1
|
-
import {
|
1
|
+
import {
|
2
|
+
useCallback,
|
3
|
+
useState,
|
4
|
+
useEffect,
|
5
|
+
useRef,
|
6
|
+
SyntheticEvent,
|
7
|
+
KeyboardEvent,
|
8
|
+
FocusEvent,
|
9
|
+
} from 'react';
|
2
10
|
|
3
11
|
import { useOptionalDependencies } from '@servicetitan/react-ioc';
|
4
12
|
|
@@ -10,8 +18,11 @@ import { FormatNumber, getFormattedString } from './get-formatted-string';
|
|
10
18
|
import { EmptyValue, NumberValue } from './common-interfaces';
|
11
19
|
import { formatNumber as formatNumberDefault } from 'accounting';
|
12
20
|
|
21
|
+
import debounce from 'debounce';
|
22
|
+
|
13
23
|
const ARROW_UP_KEY = 38;
|
14
24
|
const ARROW_DOWN_KEY = 40;
|
25
|
+
const DEBOUNCE_WAIT = 300;
|
15
26
|
|
16
27
|
export interface NumberInputProps<TEmpty extends EmptyValue>
|
17
28
|
extends Omit<InputProps, 'value' | 'onChange'> {
|
@@ -45,8 +56,8 @@ export const NumberInput = <TEmpty extends EmptyValue>({
|
|
45
56
|
NumberFormat: {
|
46
57
|
NumberGroupSeparator: thousandsSeparator = ',',
|
47
58
|
NumberDecimalSeparator: decimalSeparator = '.',
|
48
|
-
},
|
49
|
-
} = {
|
59
|
+
} = {},
|
60
|
+
} = {},
|
50
61
|
] = useOptionalDependencies(CULTURE_TOKEN);
|
51
62
|
|
52
63
|
const getFormattedValue = useCallback(
|
@@ -104,7 +115,13 @@ export const NumberInput = <TEmpty extends EmptyValue>({
|
|
104
115
|
}
|
105
116
|
};
|
106
117
|
|
107
|
-
|
118
|
+
/*
|
119
|
+
** "updateImmediateValue" updates the value immediately without clamping min/max,
|
120
|
+
** then "updateClampedValueDebounced" updates applying the min/max after debounce delay
|
121
|
+
**
|
122
|
+
** Example: User can type "100" if min is "5" without the "1" immediately being clamped
|
123
|
+
*/
|
124
|
+
const updateImmediateValue = (value: string, silent = false) => {
|
108
125
|
const newState = processValue(
|
109
126
|
value,
|
110
127
|
{
|
@@ -114,10 +131,6 @@ export const NumberInput = <TEmpty extends EmptyValue>({
|
|
114
131
|
thousand: thousandsSeparator,
|
115
132
|
decimal: decimalSeparator,
|
116
133
|
},
|
117
|
-
range: {
|
118
|
-
min,
|
119
|
-
max,
|
120
|
-
},
|
121
134
|
},
|
122
135
|
formatNumber
|
123
136
|
);
|
@@ -129,6 +142,56 @@ export const NumberInput = <TEmpty extends EmptyValue>({
|
|
129
142
|
}
|
130
143
|
};
|
131
144
|
|
145
|
+
const updateClampedValueDebounced = useRef<(value: string, silent: boolean) => void>();
|
146
|
+
|
147
|
+
useEffect(() => {
|
148
|
+
let isCurrent = true;
|
149
|
+
|
150
|
+
const updateClampedValue = (value: string, silent = false) => {
|
151
|
+
if (isCurrent) {
|
152
|
+
const newState = processValue(
|
153
|
+
value,
|
154
|
+
{
|
155
|
+
emptyValue,
|
156
|
+
precision: decimalPlaces,
|
157
|
+
separators: {
|
158
|
+
thousand: thousandsSeparator,
|
159
|
+
decimal: decimalSeparator,
|
160
|
+
},
|
161
|
+
range: { min, max },
|
162
|
+
},
|
163
|
+
formatNumber
|
164
|
+
);
|
165
|
+
|
166
|
+
setState(newState);
|
167
|
+
|
168
|
+
if (!silent) {
|
169
|
+
onChange(newState.numberValue);
|
170
|
+
}
|
171
|
+
}
|
172
|
+
};
|
173
|
+
|
174
|
+
updateClampedValueDebounced.current = debounce(updateClampedValue, DEBOUNCE_WAIT);
|
175
|
+
|
176
|
+
return () => {
|
177
|
+
isCurrent = false;
|
178
|
+
};
|
179
|
+
}, [
|
180
|
+
emptyValue,
|
181
|
+
decimalPlaces,
|
182
|
+
thousandsSeparator,
|
183
|
+
decimalSeparator,
|
184
|
+
min,
|
185
|
+
max,
|
186
|
+
formatNumber,
|
187
|
+
onChange,
|
188
|
+
]);
|
189
|
+
|
190
|
+
const updateValue = (value: string, silent = false) => {
|
191
|
+
updateImmediateValue(value, silent);
|
192
|
+
updateClampedValueDebounced.current?.(value, silent);
|
193
|
+
};
|
194
|
+
|
132
195
|
const handleFocus = (event: FocusEvent<HTMLInputElement>) => {
|
133
196
|
if (state.numberValue !== undefined) {
|
134
197
|
updateValue(String(state.numberValue), true);
|