@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":";AAIA,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;AAM9D,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,4NA0IvB,CAAC"}
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 = '.', }, } = { NumberFormat: {} },] = (0, react_ioc_1.useOptionalDependencies)(culture_1.CULTURE_TOKEN);
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
- const updateValue = (value, silent = false) => {
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":"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"}
1
+ {"version":3,"file":"number-input.js","sourceRoot":"","sources":["../../src/number-input/number-input.tsx"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;AAAA,iCAQe;AAEf,uDAAkE;AAElE,+DAAmF;AACnF,mDAAsD;AAEtD,mDAA+C;AAC/C,iEAA0E;AAE1E,2CAAiE;AAEjE,wDAAgC;AAEhC,MAAM,YAAY,GAAG,EAAE,CAAC;AACxB,MAAM,cAAc,GAAG,EAAE,CAAC;AAC1B,MAAM,aAAa,GAAG,GAAG,CAAC;AAenB,MAAM,WAAW,GAAG,CAA4B,EAa5B,EAAE,EAAE;QAbwB,EACnD,KAAK,EACL,QAAQ,EACR,OAAO,EACP,MAAM,EACN,UAAU,EACV,aAAa,EACb,0BAA0B,EAC1B,GAAG,EACH,GAAG,EACH,qBAAqB,EACrB,YAAY,GAAG,yBAAmB,OAEX,EADpB,KAAK,cAZ2C,8JAatD,CADW;IAER,MAAM,CACF,EACI,YAAY,EAAE,EACV,oBAAoB,EAAE,kBAAkB,GAAG,GAAG,EAC9C,sBAAsB,EAAE,gBAAgB,GAAG,GAAG,GACjD,GAAG,EAAE,GACT,GAAG,EAAE,EACT,GAAG,IAAA,mCAAuB,EAAC,uBAAa,CAAC,CAAC;IAE3C,MAAM,iBAAiB,GAAG,IAAA,mBAAW,EACjC,GAAG,EAAE,CACD,IAAA,yCAAkB,EACd,KAAK,EACL;QACI,UAAU;QACV,SAAS,EAAE,aAAa;QACxB,UAAU,EAAE;YACR,QAAQ,EAAE,0BAA0B,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,kBAAkB;YAC9D,OAAO,EAAE,gBAAgB;SAC5B;KACJ,EACD,YAAY,CACf,EACL;QACI,aAAa;QACb,gBAAgB;QAChB,UAAU;QACV,kBAAkB;QAClB,0BAA0B;QAC1B,KAAK;QACL,YAAY;KACf,CACJ,CAAC;IAEF,MAAM,CAAC,SAAS,EAAE,YAAY,CAAC,GAAG,IAAA,gBAAQ,EAAC,KAAK,CAAC,CAAC;IAClD,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,GAAG,IAAA,gBAAQ,EAAC;QAC/B,WAAW,EAAE,KAAK;QAClB,WAAW,EAAE,iBAAiB,EAAE;KACnC,CAAC,CAAC;IAEH,IAAA,iBAAS,EAAC,GAAG,EAAE;QACX,IAAI,SAAS,EAAE;YACX,OAAO;SACV;QAED,QAAQ,CAAC;YACL,WAAW,EAAE,KAAK;YAClB,WAAW,EAAE,iBAAiB,EAAE;SACnC,CAAC,CAAC;IACP,CAAC,EAAE,CAAC,KAAK,EAAE,iBAAiB,EAAE,SAAS,CAAC,CAAC,CAAC;IAE1C,MAAM,YAAY,GAAG,CAAC,EAAoC,EAAE,EAAE,KAAK,EAAqB,EAAE,EAAE;QACxF,WAAW,CAAC,KAAK,CAAC,CAAC;IACvB,CAAC,CAAC;IAEF,MAAM,aAAa,GAAG,CAAC,KAAsC,EAAE,EAAE;;QAC7D,IAAI,KAAK,CAAC,OAAO,KAAK,YAAY,IAAI,KAAK,CAAC,OAAO,KAAK,cAAc,EAAE;YACpE,MAAM,QAAQ,GAAG,CAAC,MAAA,KAAK,CAAC,WAAW,mCAAI,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,OAAO,KAAK,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;YAEtF,WAAW,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC;YAC9B,KAAK,CAAC,cAAc,EAAE,CAAC;SAC1B;IACL,CAAC,CAAC;IAEF;;;;;OAKG;IACH,MAAM,oBAAoB,GAAG,CAAC,KAAa,EAAE,MAAM,GAAG,KAAK,EAAE,EAAE;QAC3D,MAAM,QAAQ,GAAG,IAAA,4BAAY,EACzB,KAAK,EACL;YACI,UAAU;YACV,SAAS,EAAE,aAAa;YACxB,UAAU,EAAE;gBACR,QAAQ,EAAE,kBAAkB;gBAC5B,OAAO,EAAE,gBAAgB;aAC5B;SACJ,EACD,YAAY,CACf,CAAC;QAEF,QAAQ,CAAC,QAAQ,CAAC,CAAC;QAEnB,IAAI,CAAC,MAAM,EAAE;YACT,QAAQ,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC;SAClC;IACL,CAAC,CAAC;IAEF,MAAM,2BAA2B,GAAG,IAAA,cAAM,GAA4C,CAAC;IAEvF,IAAA,iBAAS,EAAC,GAAG,EAAE;QACX,IAAI,SAAS,GAAG,IAAI,CAAC;QAErB,MAAM,kBAAkB,GAAG,CAAC,KAAa,EAAE,MAAM,GAAG,KAAK,EAAE,EAAE;YACzD,IAAI,SAAS,EAAE;gBACX,MAAM,QAAQ,GAAG,IAAA,4BAAY,EACzB,KAAK,EACL;oBACI,UAAU;oBACV,SAAS,EAAE,aAAa;oBACxB,UAAU,EAAE;wBACR,QAAQ,EAAE,kBAAkB;wBAC5B,OAAO,EAAE,gBAAgB;qBAC5B;oBACD,KAAK,EAAE,EAAE,GAAG,EAAE,GAAG,EAAE;iBACtB,EACD,YAAY,CACf,CAAC;gBAEF,QAAQ,CAAC,QAAQ,CAAC,CAAC;gBAEnB,IAAI,CAAC,MAAM,EAAE;oBACT,QAAQ,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC;iBAClC;aACJ;QACL,CAAC,CAAC;QAEF,2BAA2B,CAAC,OAAO,GAAG,IAAA,kBAAQ,EAAC,kBAAkB,EAAE,aAAa,CAAC,CAAC;QAElF,OAAO,GAAG,EAAE;YACR,SAAS,GAAG,KAAK,CAAC;QACtB,CAAC,CAAC;IACN,CAAC,EAAE;QACC,UAAU;QACV,aAAa;QACb,kBAAkB;QAClB,gBAAgB;QAChB,GAAG;QACH,GAAG;QACH,YAAY;QACZ,QAAQ;KACX,CAAC,CAAC;IAEH,MAAM,WAAW,GAAG,CAAC,KAAa,EAAE,MAAM,GAAG,KAAK,EAAE,EAAE;;QAClD,oBAAoB,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;QACpC,MAAA,2BAA2B,CAAC,OAAO,+CAAnC,2BAA2B,EAAW,KAAK,EAAE,MAAM,CAAC,CAAC;IACzD,CAAC,CAAC;IAEF,MAAM,WAAW,GAAG,CAAC,KAAmC,EAAE,EAAE;QACxD,IAAI,KAAK,CAAC,WAAW,KAAK,SAAS,EAAE;YACjC,WAAW,CAAC,MAAM,CAAC,KAAK,CAAC,WAAW,CAAC,EAAE,IAAI,CAAC,CAAC;SAChD;QAED,YAAY,CAAC,IAAI,CAAC,CAAC;QAEnB,IAAI,OAAO,EAAE;YACT,OAAO,CAAC,KAAK,CAAC,CAAC;SAClB;IACL,CAAC,CAAC;IAEF,MAAM,UAAU,GAAG,CAAC,KAAmC,EAAE,EAAE;QACvD,QAAQ,CAAC;YACL,WAAW,EAAE,KAAK;YAClB,WAAW,EAAE,iBAAiB,EAAE;SACnC,CAAC,CAAC;QAEH,YAAY,CAAC,KAAK,CAAC,CAAC;QAEpB,IAAI,MAAM,EAAE;YACR,MAAM,CAAC,KAAK,CAAC,CAAC;SACjB;IACL,CAAC,CAAC;IAEF,OAAO,CACH,uBAAC,qBAAK,oBACE,KAAK,IACT,KAAK,EAAE,KAAK,CAAC,WAAW,EACxB,QAAQ,EAAE,YAAY,EACtB,OAAO,EAAE,WAAW,EACpB,MAAM,EAAE,UAAU,EAClB,SAAS,EAAE,qBAAqB,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,SAAS,YAC9D,CACL,CAAC;AACN,CAAC,CAAC;AA9LW,QAAA,WAAW,eA8LtB"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@servicetitan/form",
3
- "version": "17.0.0",
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.0.0",
19
- "@servicetitan/culture": "^17.0.0",
20
- "@servicetitan/data-query": "^17.0.0",
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.0.0",
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.24",
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": "afe94cb5a9f840f311627751e23fb71fd2c6fe4e"
68
+ "gitHead": "4a3151bd82763b1a8d4407bcabc675bb17d6a629"
69
69
  }
@@ -1,4 +1,12 @@
1
- import { useCallback, useState, useEffect, SyntheticEvent, KeyboardEvent, FocusEvent } from 'react';
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
- } = { NumberFormat: {} },
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
- const updateValue = (value: string, silent = false) => {
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);