orc-shared 5.99.0-dev.3 → 5.99.0-dev.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.
@@ -5,6 +5,8 @@ import InputBaseProps, { isInputProps } from "./InputBaseProps";
5
5
  import classNames from "classnames";
6
6
  import { NumericFormat, numericFormatter } from "react-number-format";
7
7
  import { trimSpacesAndLeadingZeros } from "../../../utils/inputHelper";
8
+ import Icon from "../DataDisplay/Icon";
9
+ import IconButton from "@material-ui/core/IconButton";
8
10
 
9
11
  export const useStyles = makeStyles(theme => ({
10
12
  container: {
@@ -39,11 +41,25 @@ export const useStyles = makeStyles(theme => ({
39
41
  maxWidth: "unset",
40
42
  minWidth: 0,
41
43
  border: `${theme.spacing(0.1)} solid ${theme.palette.grey.borders}`,
42
- borderRadius: props => (props.label ? theme.spacing(0, 0.5, 0.5, 0) : theme.spacing(0.5)),
44
+ borderRadius: props => {
45
+ const topLeft = props.label ? 0 : 0.5;
46
+ const topRight = props.isAdvancedNumericInput ? 0 : 0.5;
47
+ const bottomRight = topRight;
48
+ const bottomLeft = topLeft;
49
+
50
+ return theme.spacing(topLeft, topRight, bottomRight, bottomLeft);
51
+ },
43
52
  paddingLeft: theme.spacing(0.85),
44
53
  "&:focus, &:active": {
45
54
  border: `${theme.spacing(0.1)} solid ${theme.palette.focus}`,
46
- borderRadius: props => (props.label ? theme.spacing(0, 0.5, 0.5, 0) : theme.spacing(0.5)),
55
+ borderRadius: props => {
56
+ const topLeft = props.label ? 0 : 0.5;
57
+ const topRight = props.isAdvancedNumericInput ? 0 : 0.5;
58
+ const bottomRight = topRight;
59
+ const bottomLeft = topLeft;
60
+
61
+ return theme.spacing(topLeft, topRight, bottomRight, bottomLeft);
62
+ },
47
63
  },
48
64
  },
49
65
  errorInput: {
@@ -79,6 +95,41 @@ export const useStyles = makeStyles(theme => ({
79
95
  inputMultiline: {
80
96
  padding: theme.spacing(0.6, 0.6, 0.6, 0.85),
81
97
  },
98
+ numericSpinnerContainer: {
99
+ display: "flex",
100
+ backgroundColor: theme.palette.grey.light,
101
+ flexDirection: "column",
102
+ borderTopLeftRadius: 0,
103
+ borderBottomLeftRadius: 0,
104
+ borderTopRightRadius: theme.shape.borderRadius,
105
+ borderBottomRightRadius: theme.shape.borderRadius,
106
+ border: `${theme.spacing(0.1)} solid ${theme.palette.grey.borders}`,
107
+ padding: 0,
108
+ margin: "0 0 0 -1px",
109
+ },
110
+ numericSpinnerUp: {
111
+ fontSize: "8px",
112
+ padding: "0 3px",
113
+ borderBottom: "1px solid #CCCCCC",
114
+ borderRadius: 0,
115
+ flex: 1,
116
+ margin: 0,
117
+ width: "20px",
118
+ "& + .MuiButton-root, & + .MuiIconButton-root, & + .MuiInputBase-root": {
119
+ marginLeft: 0,
120
+ },
121
+ },
122
+ numericSpinnerDown: {
123
+ fontSize: "8px",
124
+ padding: "0 3px",
125
+ borderRadius: 0,
126
+ flex: 1,
127
+ margin: 0,
128
+ marginLeft: 0,
129
+ "& + .MuiButton-root, & + .MuiIconButton-root, & + .MuiInputBase-root": {
130
+ marginLeft: 0,
131
+ },
132
+ },
82
133
  }));
83
134
 
84
135
  export const AdvancedNumericInput = props => {
@@ -102,6 +153,29 @@ export const AdvancedNumericInput = props => {
102
153
  );
103
154
  };
104
155
 
156
+ export const AdvancedIntegerInput = props => {
157
+ const { integerButtons, ...other } = props;
158
+
159
+ return (
160
+ <div style={{ display: "flex" }} className="InputBase-input-wrapper">
161
+ <AdvancedNumericInput {...other} />
162
+ {integerButtons}
163
+ </div>
164
+ );
165
+ };
166
+
167
+ const getInputComponent = (isAdvancedNumericInput, decimalScale) => {
168
+ if (isAdvancedNumericInput) {
169
+ if (decimalScale === 0) {
170
+ return AdvancedIntegerInput;
171
+ }
172
+
173
+ return AdvancedNumericInput;
174
+ }
175
+
176
+ return undefined;
177
+ };
178
+
105
179
  const InputBase = ({ inputProps }) => {
106
180
  if (isInputProps(inputProps) === false) {
107
181
  throw new TypeError("inputProps property is not of type InputBaseProps");
@@ -127,8 +201,15 @@ const InputBase = ({ inputProps }) => {
127
201
  const numericInputProps = inputProps?.get(InputBaseProps.propNames.numericInputProps) || null;
128
202
 
129
203
  const isAdvancedNumericInput = type.toLowerCase() === "advancednumericinput";
130
- const inputComponent = isAdvancedNumericInput ? AdvancedNumericInput : undefined;
204
+ const decimalScale = numericInputProps?.decimalScale ?? 0;
205
+ const inputComponent = getInputComponent(isAdvancedNumericInput, decimalScale);
131
206
  const inputControlType = isAdvancedNumericInput ? "text" : type;
207
+ const [inputText, setInputText] = React.useState(null);
208
+ const textToDisplay = inputText ?? value;
209
+ const classes = useStyles({ label, errorPosition, isAdvancedNumericInput });
210
+
211
+ let onKeyDown = null;
212
+ let onWheel = null;
132
213
 
133
214
  if (isAdvancedNumericInput && numericInputProps) {
134
215
  Object.keys(numericInputProps).forEach(key => {
@@ -147,8 +228,6 @@ const InputBase = ({ inputProps }) => {
147
228
  inputAttributes.min = -2147483648;
148
229
  }
149
230
 
150
- const decimalScale = numericInputProps?.decimalScale ?? 0;
151
-
152
231
  const lengthForMin = Math.trunc(inputAttributes.min).toString().length;
153
232
  const lengthForMax = Math.trunc(inputAttributes.max).toString().length;
154
233
 
@@ -157,6 +236,115 @@ const InputBase = ({ inputProps }) => {
157
236
  inputAttributes.isAllowed = val => {
158
237
  return val.value === "" || val.value === "-" || val.value !== null;
159
238
  };
239
+
240
+ if (decimalScale === 0 && !disabled) {
241
+ const getInitialNumericValue = () => {
242
+ if (0 >= inputAttributes.min && 0 <= inputAttributes.max) {
243
+ return 0;
244
+ }
245
+
246
+ if (Math.abs(inputAttributes.min) < Math.abs(inputAttributes.max)) {
247
+ return inputAttributes.min;
248
+ }
249
+
250
+ return inputAttributes.max;
251
+ };
252
+
253
+ const increaseNumericValue = () => {
254
+ if (textToDisplay) {
255
+ const currentValue = parseInt(textToDisplay, 10);
256
+ if (currentValue + 1 <= inputAttributes.max) {
257
+ setInputText((currentValue + 1).toString());
258
+ }
259
+ } else {
260
+ let currentValue = getInitialNumericValue();
261
+ if (currentValue === 0 && currentValue + 1 <= inputAttributes.max) {
262
+ currentValue++;
263
+ }
264
+ setInputText(currentValue.toString());
265
+ }
266
+ };
267
+ const decreaseNumericValue = () => {
268
+ if (textToDisplay) {
269
+ const currentValue = parseInt(textToDisplay, 10);
270
+ if (currentValue - 1 >= inputAttributes.min) {
271
+ setInputText((currentValue - 1).toString());
272
+ }
273
+ } else {
274
+ let currentValue = getInitialNumericValue();
275
+ if (currentValue === 0 && currentValue - 1 >= inputAttributes.min) {
276
+ currentValue--;
277
+ }
278
+ setInputText(currentValue.toString());
279
+ }
280
+ };
281
+
282
+ const focusInput = target => {
283
+ target.closest(".InputBase-input-wrapper").getElementsByTagName("input")[0].focus();
284
+ };
285
+
286
+ inputAttributes.integerButtons = (
287
+ <div className={classes.numericSpinnerContainer}>
288
+ <IconButton
289
+ className={classes.numericSpinnerUp}
290
+ tabIndex="-1"
291
+ data-qa="increase"
292
+ disabled={disabled}
293
+ onMouseDown={event => event.preventDefault()} // prevent the button from stealing focus
294
+ onClick={event => {
295
+ event.preventDefault();
296
+ event.stopPropagation();
297
+ increaseNumericValue();
298
+ focusInput(event.target);
299
+ }}
300
+ >
301
+ <Icon id="chevron-up" />
302
+ </IconButton>
303
+
304
+ <IconButton
305
+ className={classes.numericSpinnerDown}
306
+ tabIndex="-1"
307
+ data-qa="decrease"
308
+ disabled={disabled}
309
+ onMouseDown={event => event.preventDefault()} // prevent the button from stealing focus
310
+ onClick={event => {
311
+ event.preventDefault();
312
+ event.stopPropagation();
313
+ decreaseNumericValue();
314
+ focusInput(event.target);
315
+ }}
316
+ >
317
+ <Icon id="chevron-down" />
318
+ </IconButton>
319
+ </div>
320
+ );
321
+
322
+ onKeyDown = event => {
323
+ if (event.key === "ArrowUp") {
324
+ event.preventDefault();
325
+ event.stopPropagation();
326
+
327
+ increaseNumericValue();
328
+ }
329
+ // Note Alex20260119: using an 'else if' caused issue with code coverage
330
+ if (event.key === "ArrowDown") {
331
+ event.preventDefault();
332
+ event.stopPropagation();
333
+
334
+ decreaseNumericValue();
335
+ }
336
+ };
337
+
338
+ onWheel = event => {
339
+ if (event.deltaY < 0) {
340
+ increaseNumericValue();
341
+ } else {
342
+ decreaseNumericValue();
343
+ }
344
+
345
+ focusInput(event.target);
346
+ };
347
+ }
160
348
  }
161
349
 
162
350
  const defaultRows = 4;
@@ -170,7 +358,6 @@ const InputBase = ({ inputProps }) => {
170
358
  // causing onBlur to never fire
171
359
  item.target.focus();
172
360
  };
173
- const classes = useStyles({ label, errorPosition });
174
361
 
175
362
  const onChangeHandler = event => {
176
363
  if (event.persist) {
@@ -222,8 +409,6 @@ const InputBase = ({ inputProps }) => {
222
409
 
223
410
  const inputBaseInputStyle = inputProps?.getStyle(InputBaseProps.ruleNames.input);
224
411
  const errorTextStyle = inputProps?.getStyle(InputBaseProps.ruleNames.errorText);
225
- const [inputText, setInputText] = React.useState(null);
226
- const textToDisplay = inputText ?? value;
227
412
 
228
413
  React.useEffect(() => {
229
414
  if (inputText === null || window.bypassDebounce === true) {
@@ -249,6 +434,21 @@ const InputBase = ({ inputProps }) => {
249
434
  // eslint-disable-next-line react-hooks/exhaustive-deps
250
435
  }, [inputText, metadata, timeoutDelay, update, value]);
251
436
 
437
+ if (onKeyDown) {
438
+ if (inputAttributes.onKeyDown) {
439
+ const originalKeyDown = inputAttributes.onKeyDown;
440
+ inputAttributes.onKeyDown = event => {
441
+ originalKeyDown(event);
442
+
443
+ if (!event.isDefaultPrevented()) {
444
+ onKeyDown(event);
445
+ }
446
+ };
447
+ } else {
448
+ inputAttributes.onKeyDown = onKeyDown;
449
+ }
450
+ }
451
+
252
452
  return (
253
453
  <div className={classes.container}>
254
454
  <div className={classes.inputContainer}>
@@ -267,6 +467,7 @@ const InputBase = ({ inputProps }) => {
267
467
  placeholder={placeholder}
268
468
  value={textToDisplay}
269
469
  fullWidth={true}
470
+ onWheel={onWheel}
270
471
  onChange={event => onChangeHandler(event)}
271
472
  error={!!error}
272
473
  inputProps={inputAttributes}