@axinom/mosaic-ui 0.31.0-rc.9 → 0.31.0

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.
Files changed (87) hide show
  1. package/dist/components/DynamicDataList/DynamicListDataEntry/Renderers/createInputRenderer/createInputRenderer.d.ts.map +1 -1
  2. package/dist/components/DynamicDataList/DynamicListDataEntry/Renderers/renderers.model.d.ts +5 -4
  3. package/dist/components/DynamicDataList/DynamicListDataEntry/Renderers/renderers.model.d.ts.map +1 -1
  4. package/dist/components/DynamicDataList/index.d.ts +1 -1
  5. package/dist/components/DynamicDataList/index.d.ts.map +1 -1
  6. package/dist/components/EmptyStation/EmptyStation.d.ts +1 -1
  7. package/dist/components/EmptyStation/EmptyStation.d.ts.map +1 -1
  8. package/dist/components/Explorer/Explorer.d.ts.map +1 -1
  9. package/dist/components/FormElements/Checkbox/Checkbox.d.ts.map +1 -1
  10. package/dist/components/FormElements/CustomTags/CustomTags.d.ts.map +1 -1
  11. package/dist/components/FormElements/DateTimeField/DateTimeText.d.ts.map +1 -1
  12. package/dist/components/FormElements/DateTimeField/DateTimeTextField.d.ts.map +1 -1
  13. package/dist/components/FormElements/Form.models.d.ts +4 -4
  14. package/dist/components/FormElements/Form.models.d.ts.map +1 -1
  15. package/dist/components/FormElements/FormElementContainer/FormElementContainer.d.ts.map +1 -1
  16. package/dist/components/FormElements/MaskedSingleLineText/MaskedSingleLineText.d.ts +20 -0
  17. package/dist/components/FormElements/MaskedSingleLineText/MaskedSingleLineText.d.ts.map +1 -0
  18. package/dist/components/FormElements/MaskedSingleLineText/MaskedSingleLineTextField.d.ts +15 -0
  19. package/dist/components/FormElements/MaskedSingleLineText/MaskedSingleLineTextField.d.ts.map +1 -0
  20. package/dist/components/FormElements/Radio/Radio.d.ts +1 -0
  21. package/dist/components/FormElements/Radio/Radio.d.ts.map +1 -1
  22. package/dist/components/FormElements/SingleLineText/SingleLineText.d.ts +5 -2
  23. package/dist/components/FormElements/SingleLineText/SingleLineText.d.ts.map +1 -1
  24. package/dist/components/FormElements/ToggleButton/ToggleButton.d.ts.map +1 -1
  25. package/dist/components/FormElements/index.d.ts +1 -0
  26. package/dist/components/FormElements/index.d.ts.map +1 -1
  27. package/dist/components/FormStation/FormStation.d.ts.map +1 -1
  28. package/dist/components/PageHeader/PageHeaderAction/PageHeaderAction.d.ts.map +1 -1
  29. package/dist/components/Utils/Postgraphile/index.d.ts +3 -3
  30. package/dist/components/Utils/Postgraphile/index.d.ts.map +1 -1
  31. package/dist/components/Utils/Transformers/Timestamp.d.ts.map +1 -1
  32. package/dist/components/index.d.ts +1 -1
  33. package/dist/components/index.d.ts.map +1 -1
  34. package/dist/helpers/utils.d.ts +8 -0
  35. package/dist/helpers/utils.d.ts.map +1 -1
  36. package/dist/index.es.js +4 -3
  37. package/dist/index.es.js.map +1 -0
  38. package/dist/index.js +4 -3
  39. package/dist/index.js.map +1 -0
  40. package/package.json +4 -3
  41. package/src/components/Actions/Action/Action.spec.tsx +2 -2
  42. package/src/components/Actions/Action/Action.tsx +1 -1
  43. package/src/components/DynamicDataList/DynamicListDataEntry/DynamicListDataEntry.scss +5 -1
  44. package/src/components/DynamicDataList/DynamicListDataEntry/Renderers/createInputRenderer/createInputRenderer.scss +0 -45
  45. package/src/components/DynamicDataList/DynamicListDataEntry/Renderers/createInputRenderer/createInputRenderer.spec.tsx +3 -61
  46. package/src/components/DynamicDataList/DynamicListDataEntry/Renderers/createInputRenderer/createInputRenderer.tsx +14 -15
  47. package/src/components/DynamicDataList/DynamicListDataEntry/Renderers/createSelectRenderer/createSelectRenderer.scss +2 -2
  48. package/src/components/DynamicDataList/DynamicListDataEntry/Renderers/renderers.model.ts +6 -4
  49. package/src/components/DynamicDataList/index.ts +2 -2
  50. package/src/components/EmptyStation/EmptyStation.spec.tsx +1 -1
  51. package/src/components/EmptyStation/EmptyStation.tsx +1 -1
  52. package/src/components/Explorer/Explorer.tsx +2 -2
  53. package/src/components/FormElements/Checkbox/Checkbox.scss +4 -1
  54. package/src/components/FormElements/Checkbox/Checkbox.tsx +1 -1
  55. package/src/components/FormElements/CustomTags/CustomTags.scss +0 -2
  56. package/src/components/FormElements/CustomTags/CustomTags.tsx +10 -4
  57. package/src/components/FormElements/DateTimeField/DateTimeText.tsx +1 -0
  58. package/src/components/FormElements/DateTimeField/DateTimeTextField.tsx +1 -2
  59. package/src/components/FormElements/Form.models.ts +4 -4
  60. package/src/components/FormElements/FormElementContainer/FormElementContainer.scss +6 -1
  61. package/src/components/FormElements/FormElementContainer/FormElementContainer.tsx +8 -1
  62. package/src/components/FormElements/MaskedSingleLineText/MaskedSingleLineText.spec.tsx +19 -0
  63. package/src/components/FormElements/MaskedSingleLineText/MaskedSingleLineText.stories.tsx +65 -0
  64. package/src/components/FormElements/MaskedSingleLineText/MaskedSingleLineText.tsx +60 -0
  65. package/src/components/FormElements/MaskedSingleLineText/MaskedSingleLineTextField.tsx +37 -0
  66. package/src/components/FormElements/Radio/Radio.scss +4 -0
  67. package/src/components/FormElements/Radio/Radio.spec.tsx +1 -1
  68. package/src/components/FormElements/Radio/Radio.tsx +30 -24
  69. package/src/components/FormElements/Select/Select.scss +10 -3
  70. package/src/components/FormElements/SingleLineText/SingleLineText.scss +1 -0
  71. package/src/components/FormElements/SingleLineText/SingleLineText.spec.tsx +2 -32
  72. package/src/components/FormElements/SingleLineText/SingleLineText.stories.tsx +9 -1
  73. package/src/components/FormElements/SingleLineText/SingleLineText.tsx +24 -32
  74. package/src/components/FormElements/Tags/Tags.scss +8 -1
  75. package/src/components/FormElements/ToggleButton/ToggleButton.scss +3 -2
  76. package/src/components/FormElements/ToggleButton/ToggleButton.tsx +1 -1
  77. package/src/components/FormElements/index.ts +1 -0
  78. package/src/components/FormStation/FormStation.stories.tsx +9 -0
  79. package/src/components/FormStation/FormStation.tsx +1 -1
  80. package/src/components/PageHeader/PageHeaderAction/PageHeaderAction.spec.tsx +1 -1
  81. package/src/components/PageHeader/PageHeaderAction/PageHeaderAction.tsx +1 -1
  82. package/src/components/Utils/Postgraphile/index.ts +3 -3
  83. package/src/components/Utils/Transformers/Timestamp.spec.ts +2 -2
  84. package/src/components/Utils/Transformers/Timestamp.ts +5 -1
  85. package/src/components/index.ts +1 -1
  86. package/src/helpers/utils.ts +17 -0
  87. package/src/styles/variables.scss +1 -0
@@ -0,0 +1,37 @@
1
+ import { useField } from 'formik';
2
+ import React from 'react';
3
+ import { useFormikError } from '../useFormikError';
4
+ import {
5
+ MaskedSingleLineText,
6
+ MaskedSingleLineTextProps,
7
+ } from './MaskedSingleLineText';
8
+ /**
9
+ * This component should be used to render a Masked TextBox inside a Formik form.
10
+ *
11
+ * @example
12
+ * <Field
13
+ * name="title"
14
+ * label="Title"
15
+ * as={MaskedSingleLineTextField}
16
+ mask={'00:00:00.000'},
17
+ placeholderChar={'0'}, />
18
+ */
19
+ export const MaskedSingleLineTextField: React.FC<
20
+ Omit<MaskedSingleLineTextProps, 'error'>
21
+ > = (props) => {
22
+ const error = useFormikError(props.name);
23
+
24
+ const [, meta, helpers] = useField(props.name);
25
+
26
+ const handleChange = (value: string): void => {
27
+ helpers.setValue(value);
28
+
29
+ if (value === meta.initialValue) {
30
+ helpers.setTouched(false);
31
+ }
32
+ };
33
+
34
+ return (
35
+ <MaskedSingleLineText {...props} onChange={handleChange} error={error} />
36
+ );
37
+ };
@@ -30,6 +30,10 @@
30
30
  align-items: center;
31
31
 
32
32
  user-select: none;
33
+
34
+ &.disabled {
35
+ cursor: default;
36
+ }
33
37
  }
34
38
 
35
39
  input {
@@ -224,7 +224,7 @@ describe('Radio', () => {
224
224
  expect(confirmation.exists()).toBe(true);
225
225
 
226
226
  expect(radioSVG.at(0).hasClass('hasConfirm')).toBe(true);
227
- expect(radioSVG.at(0).hasClass('unSelectable')).toBe(false);
227
+ expect(radioSVG.at(0).hasClass('unSelectable')).toBe(true);
228
228
  expect(radioSVG.at(1).hasClass('hasConfirm')).toBe(false);
229
229
  expect(radioSVG.at(1).hasClass('unSelectable')).toBe(true);
230
230
  expect(radioSVG.at(2).hasClass('hasConfirm')).toBe(false);
@@ -1,9 +1,9 @@
1
1
  import clsx from 'clsx';
2
2
  import React, { useRef, useState } from 'react';
3
3
  import {
4
- ConfirmDialog,
5
4
  ConfirmationConfig,
6
5
  ConfirmationMode,
6
+ ConfirmDialog,
7
7
  } from '../../ConfirmDialog';
8
8
  import { BaseFormControl, BaseInputEvents } from '../Form.models';
9
9
  import { FormElementContainer } from '../FormElementContainer';
@@ -31,6 +31,8 @@ interface RadioButtonProps {
31
31
  inputValue?: string | number;
32
32
  /** The new value currently stored as the confirmation dialog is rendered */
33
33
  confirmValue?: string | number;
34
+
35
+ disabled?: boolean;
34
36
  }
35
37
 
36
38
  export const RadioButton: React.FC<RadioButtonProps> = ({
@@ -38,27 +40,27 @@ export const RadioButton: React.FC<RadioButtonProps> = ({
38
40
  hasError,
39
41
  inputValue,
40
42
  confirmValue,
41
- }) => {
42
- return (
43
- <svg
44
- className={clsx(classes.buttonContainer, {
45
- [classes.checked]: checked,
46
- [classes.hasError]: hasError,
47
- [classes.hasConfirm]:
48
- confirmValue !== undefined &&
49
- String(inputValue) === String(confirmValue),
50
- [classes.unSelectable]:
51
- confirmValue !== undefined &&
52
- String(inputValue) !== String(confirmValue),
53
- })}
54
- preserveAspectRatio="xMidYMid meet"
55
- viewBox="0 0 34 34"
56
- >
57
- <circle className={classes.radioOutline} cx="17" cy="17" r="15" />
58
- <circle className={classes.radioDot} cx="17" cy="17" r="10" />
59
- </svg>
60
- );
61
- };
43
+ disabled = false,
44
+ }) => (
45
+ <svg
46
+ className={clsx(classes.buttonContainer, {
47
+ [classes.checked]: checked,
48
+ [classes.hasError]: hasError,
49
+ [classes.hasConfirm]:
50
+ confirmValue !== undefined &&
51
+ String(inputValue) === String(confirmValue),
52
+ [classes.unSelectable]:
53
+ (confirmValue !== undefined &&
54
+ String(inputValue) !== String(confirmValue)) ||
55
+ disabled,
56
+ })}
57
+ preserveAspectRatio="xMidYMid meet"
58
+ viewBox="0 0 34 34"
59
+ >
60
+ <circle className={classes.radioOutline} cx="17" cy="17" r="15" />
61
+ <circle className={classes.radioDot} cx="17" cy="17" r="10" />
62
+ </svg>
63
+ );
62
64
 
63
65
  /**
64
66
  * Radio input form control
@@ -108,7 +110,7 @@ export const Radio: React.FC<RadioProps> = ({
108
110
  currentTarget: { value: confirmValue as unknown as string },
109
111
  } as React.ChangeEvent<HTMLInputElement>;
110
112
 
111
- onChange && onChange(confirmed as React.FormEvent<HTMLInputElement>);
113
+ onChange && onChange(confirmed as React.ChangeEvent<HTMLInputElement>);
112
114
 
113
115
  setConfirmation(false);
114
116
  ref.current = undefined;
@@ -156,12 +158,16 @@ export const Radio: React.FC<RadioProps> = ({
156
158
  onBlur={onBlur}
157
159
  onFocus={onFocus}
158
160
  />
159
- <label htmlFor={radioId}>
161
+ <label
162
+ htmlFor={radioId}
163
+ className={clsx({ [classes.disabled]: disabled })}
164
+ >
160
165
  <RadioButton
161
166
  checked={checked}
162
167
  hasError={errorMsg !== undefined}
163
168
  inputValue={val}
164
169
  confirmValue={confirmValue}
170
+ disabled={disabled}
165
171
  />
166
172
  {labe}
167
173
  </label>
@@ -1,7 +1,7 @@
1
1
  @import '../../../styles/common.scss';
2
2
 
3
3
  @function svg-arrow-glyph($color) {
4
- @return url('data:image/svg+xml;utf8,<svg stroke="'+$color+'" version="1.1" xmlns="http://www.w3.org/2000/svg" width="40px" height="20px" viewBox="0 0 40 40"><path vector-effect="non-scaling-stroke" fill="none" stroke-width="2" d="M38.5,9.5L20,30.5L1.5,9.5" /></svg>');
4
+ @return url('data:image/svg+xml;utf8,<svg stroke="' + $color + '" version="1.1" xmlns="http://www.w3.org/2000/svg" width="40px" height="20px" viewBox="0 0 40 40"><path vector-effect="non-scaling-stroke" fill="none" stroke-width="2" d="M38.5,9.5L20,30.5L1.5,9.5" /></svg>');
5
5
  }
6
6
 
7
7
  .container {
@@ -37,6 +37,13 @@
37
37
  border: 1px solid
38
38
  var(--input-invalid-border-color, $input-invalid-border-color);
39
39
  }
40
+
41
+ &:disabled {
42
+ cursor: default;
43
+ background-image: svg-arrow-glyph(
44
+ var(--select-arrow-color, encodecolor($select-disabled-arrow-color))
45
+ );
46
+ }
40
47
  }
41
48
 
42
49
  select,
@@ -47,8 +54,8 @@
47
54
  text-overflow: ellipsis;
48
55
  }
49
56
 
50
- select:hover,
51
- select:focus {
57
+ select:hover:enabled,
58
+ select:focus:enabled {
52
59
  border: 1px solid var(--input-hover-color, $input-hover-color);
53
60
  box-shadow: 0 0 0 2px var(--input-hover-color, $input-hover-color);
54
61
 
@@ -9,6 +9,7 @@
9
9
  font-size: var(--label-font-size, $label-font-size);
10
10
  outline: none;
11
11
  height: 50px;
12
+ width: 100%;
12
13
  max-width: var(--input-max-width, $input-max-width);
13
14
 
14
15
  transition: box-shadow 0.15s ease-in-out 0s;
@@ -38,25 +38,6 @@ describe('TextField', () => {
38
38
  expect(spy).toHaveBeenCalledWith({ target: { value: mockValueUpdated } });
39
39
  });
40
40
 
41
- it(`defaults to an empty string if prop value is 'null'`, () => {
42
- // @ts-expect-error intentional null value
43
- const wrapper = shallow(<SingleLineText name={'test-name'} value={null} />);
44
-
45
- const input = wrapper.find('input');
46
-
47
- expect(input.prop('value')).toBe('');
48
- });
49
-
50
- it(`defaults to an empty string if prop value is 'undefined'`, () => {
51
- const wrapper = shallow(
52
- <SingleLineText name={'test-name'} value={undefined} />,
53
- );
54
-
55
- const input = wrapper.find('input');
56
-
57
- expect(input.prop('value')).toBe('');
58
- });
59
-
60
41
  it('uses optional props when passed in', () => {
61
42
  const mockProps = {
62
43
  autoComplete: 'on',
@@ -124,9 +105,9 @@ describe('TextField', () => {
124
105
  <SingleLineText name={'test-pwd'} type="password" isSet={true} />,
125
106
  );
126
107
 
127
- const input = wrapper.find('input');
108
+ const input = wrapper.find('input').getDOMNode<HTMLInputElement>();
128
109
 
129
- expect(input.prop('value')).toBe(dummyPwd);
110
+ expect(input.value).toBe(dummyPwd);
130
111
  });
131
112
 
132
113
  it('when user changes the value it should be displayed, when type is password', () => {
@@ -152,15 +133,4 @@ describe('TextField', () => {
152
133
  }),
153
134
  );
154
135
  });
155
-
156
- it('renders an empty string if value is not provided, when type is password', () => {
157
- const initialVal = undefined;
158
- const wrapper = mount(
159
- <SingleLineText name={'test-pwd'} type="password" value={initialVal} />,
160
- );
161
-
162
- const input = wrapper.find('input');
163
-
164
- expect(input.prop('value')).toBe('');
165
- });
166
136
  });
@@ -15,8 +15,16 @@ const groups = createGroups({
15
15
  'inlineMode',
16
16
  'name',
17
17
  'id',
18
+ 'innerRef',
19
+ ],
20
+ Content: [
21
+ 'label',
22
+ 'placeholder',
23
+ 'error',
24
+ 'tooltipContent',
25
+ 'value',
26
+ 'defaultValue',
18
27
  ],
19
- Content: ['label', 'placeholder', 'error', 'tooltipContent', 'value'],
20
28
  Styling: ['className'],
21
29
  Events: ['onChange', 'onBlur', 'onFocus'],
22
30
  });
@@ -1,5 +1,6 @@
1
1
  import clsx from 'clsx';
2
- import React, { ChangeEvent, useEffect, useState } from 'react';
2
+ import React, { ChangeEvent, InputHTMLAttributes, useEffect } from 'react';
3
+ import { executeIfRefAvailable } from '../../../helpers/utils';
3
4
  import { BaseFormControl, BaseInputEvents } from '../Form.models';
4
5
  import { FormElementContainer } from '../FormElementContainer';
5
6
  import classes from './SingleLineText.scss';
@@ -16,13 +17,17 @@ export interface SingleLineTextProps extends BaseFormControl, BaseInputEvents {
16
17
  */
17
18
  isSet?: boolean;
18
19
  /** Current value the form control has */
19
- value?: string | number | string[] | undefined;
20
+ value?: InputHTMLAttributes<HTMLInputElement>['value'];
21
+ /** Default value for the form control */
22
+ defaultValue?: InputHTMLAttributes<HTMLInputElement>['defaultValue'];
20
23
  /** Input placeholder */
21
24
  placeholder?: string;
22
25
  /** Whether or not the control should start focused (default: false) */
23
26
  autoFocus?: boolean;
24
27
  /** Whether or not the control supports auto complete */
25
28
  autoComplete?: 'on' | 'off';
29
+
30
+ innerRef?: React.RefObject<HTMLInputElement>;
26
31
  }
27
32
 
28
33
  /**
@@ -40,6 +45,8 @@ export const SingleLineText: React.FC<SingleLineTextProps> = ({
40
45
  error,
41
46
  autoFocus = false,
42
47
  autoComplete,
48
+ innerRef = React.createRef(),
49
+ defaultValue,
43
50
  onChange,
44
51
  onBlur,
45
52
  onFocus,
@@ -47,47 +54,30 @@ export const SingleLineText: React.FC<SingleLineTextProps> = ({
47
54
  ...rest
48
55
  }) => {
49
56
  const errorMsg: string | undefined = error;
50
- const [val, setVal] = useState(value ?? '');
51
- const [isDirty, setDirty] = useState(false);
52
57
  const DUMMY_PWD = '0000000000';
53
58
  const isPasswordField = type === 'password' ? true : false;
54
59
 
55
60
  useEffect(() => {
56
- // For password type, display dummy val at initial rendering and allow user to change it
57
- if (isPasswordField) {
58
- if (isDirty) {
59
- setVal(value as string);
60
- } else if (!isSet) {
61
- setVal('');
62
- } else {
63
- setVal(DUMMY_PWD);
64
- }
65
- } else {
66
- setVal(value as string);
61
+ if (isPasswordField && isSet) {
62
+ executeIfRefAvailable(innerRef, (input) => {
63
+ input.value = DUMMY_PWD;
64
+ });
67
65
  }
68
- }, [isDirty, isPasswordField, isSet, type, value]);
69
-
70
- const handlePwdChange = (e: ChangeEvent<HTMLInputElement>): void => {
71
- // For type === password, once user changed the pwd, show the actual value entered by the user.
72
- setDirty(true);
73
- setVal(e.target.value);
74
- onChange && onChange(e);
75
- };
76
-
77
- const handleTextChange = (e: ChangeEvent<HTMLInputElement>): void => {
78
- setVal(e.target.value);
79
- onChange && onChange(e);
80
- };
66
+ }, [innerRef, isPasswordField, isSet]);
81
67
 
82
68
  const onFocusWrapper = (e: ChangeEvent<HTMLInputElement>): void => {
83
69
  if (type === 'password' && isSet && !value) {
84
- setVal('');
70
+ executeIfRefAvailable(innerRef, (input) => {
71
+ input.value = '';
72
+ });
85
73
  }
86
74
  onFocus?.(e);
87
75
  };
88
76
  const onBlurWrapper = (e: ChangeEvent<HTMLInputElement>): void => {
89
77
  if (type === 'password' && isSet && !value) {
90
- setVal(DUMMY_PWD);
78
+ executeIfRefAvailable(innerRef, (input) => {
79
+ input.value = DUMMY_PWD;
80
+ });
91
81
  }
92
82
  onBlur?.(e);
93
83
  };
@@ -108,12 +98,14 @@ export const SingleLineText: React.FC<SingleLineTextProps> = ({
108
98
  id={id}
109
99
  name={name}
110
100
  type={type}
111
- value={val ?? ''}
101
+ ref={innerRef}
102
+ value={value}
103
+ defaultValue={defaultValue}
112
104
  disabled={disabled}
113
105
  placeholder={placeholder}
114
106
  autoFocus={autoFocus}
115
107
  autoComplete={autoComplete}
116
- onChange={isPasswordField ? handlePwdChange : handleTextChange}
108
+ onChange={onChange}
117
109
  onBlur={onBlurWrapper}
118
110
  onFocus={onFocusWrapper}
119
111
  />
@@ -72,6 +72,13 @@
72
72
  border: 1px solid
73
73
  var(--input-invalid-border-color, $input-invalid-border-color);
74
74
  }
75
+
76
+ &:disabled {
77
+ cursor: default;
78
+ background-image: svg-arrow-glyph(
79
+ var(--select-arrow-color, encodecolor($select-disabled-arrow-color))
80
+ );
81
+ }
75
82
  }
76
83
 
77
84
  select,
@@ -82,7 +89,7 @@
82
89
  text-overflow: ellipsis;
83
90
  }
84
91
 
85
- select:hover {
92
+ select:hover:enabled {
86
93
  border: 1px solid var(--input-hover-color, $input-hover-color);
87
94
  box-shadow: 0 0 0 2px var(--input-hover-color, $input-hover-color);
88
95
 
@@ -16,7 +16,8 @@
16
16
  background-color: white;
17
17
  cursor: pointer;
18
18
 
19
- &:hover {
19
+ &:hover:enabled {
20
+ transition: box-shadow 0.15s ease-in-out 0s;
20
21
  box-shadow: 0 0 0 2px $blue;
21
22
  }
22
23
 
@@ -65,7 +66,7 @@
65
66
  }
66
67
 
67
68
  &:disabled {
68
- cursor: not-allowed;
69
+ cursor: default;
69
70
  opacity: 0.5;
70
71
  }
71
72
 
@@ -3,9 +3,9 @@ import React, { useEffect, useState } from 'react';
3
3
  import { noop } from '../../../helpers/utils';
4
4
  import { BaseButtonOptions } from '../../Buttons/Button.model';
5
5
  import {
6
- ConfirmDialog,
7
6
  ConfirmationConfig,
8
7
  ConfirmationMode,
8
+ ConfirmDialog,
9
9
  } from '../../ConfirmDialog';
10
10
  import { BaseFormControl } from '../Form.models';
11
11
  import { FormElementContainer } from '../FormElementContainer';
@@ -29,6 +29,7 @@ export {
29
29
  export { FormikDebug } from './FormikDebug/FormikDebug';
30
30
  export { GenericField, GenericFieldProps } from './GenericField/GenericField';
31
31
  export { LinkField, LinkFieldProps } from './Link/LinkField';
32
+ export { MaskedSingleLineText } from './MaskedSingleLineText/MaskedSingleLineText';
32
33
  export { Radio, RadioProps } from './Radio/Radio';
33
34
  export { RadioField } from './Radio/RadioField';
34
35
  export { ReadOnlyField, ReadOnlyFieldProps } from './ReadOnly/ReadOnlyField';
@@ -22,6 +22,7 @@ import {
22
22
  } from '../FormElements';
23
23
  import { CheckboxField } from '../FormElements/Checkbox/CheckboxField';
24
24
  import { DynamicDataListField } from '../FormElements/DynamicDataListControl/DynamicDataListField';
25
+ import { MaskedSingleLineTextField } from '../FormElements/MaskedSingleLineText/MaskedSingleLineTextField';
25
26
  import { InfoPanel, Paragraph, Section } from '../InfoPanel';
26
27
  import { ErrorType } from '../models';
27
28
  import { Details, DetailsProps } from './Details/Details';
@@ -129,6 +130,7 @@ interface DetailsValues {
129
130
  released?: string;
130
131
  list?: DynamicListStoryData[];
131
132
  archived?: boolean;
133
+ timestamp?: string;
132
134
  }
133
135
 
134
136
  export const Extended: StoryObj<typeof Details> = (() => {
@@ -167,6 +169,7 @@ export const Extended: StoryObj<typeof Details> = (() => {
167
169
  released: '2020-04-03T00:00:00.000+00:00',
168
170
  list: listData,
169
171
  archived: false,
172
+ timestamp: '00:00:00.001',
170
173
  },
171
174
  },
172
175
  infoPanel: (
@@ -279,6 +282,12 @@ export const Extended: StoryObj<typeof Details> = (() => {
279
282
  as={DynamicDataListField}
280
283
  />
281
284
  <Field name="archived" label="Set Archived" as={CheckboxField} />
285
+ <Field
286
+ name="timestamp"
287
+ label="Timestamp"
288
+ mask="00:00:00.000"
289
+ as={MaskedSingleLineTextField}
290
+ />
282
291
  </>
283
292
  ),
284
293
  },
@@ -22,12 +22,12 @@ import { Actions, ActionsProps } from '../Actions';
22
22
  import { isNavigationAction } from '../Actions/Action/Action';
23
23
  import { IconName } from '../Icons';
24
24
  import { MessageBar } from '../MessageBar';
25
+ import { ErrorType, StationError, StationMessage } from '../models';
25
26
  import {
26
27
  PageHeader,
27
28
  PageHeaderActionType,
28
29
  PageHeaderProps,
29
30
  } from '../PageHeader';
30
- import { ErrorType, StationError, StationMessage } from '../models';
31
31
  import { FormActionData, InitialFormData } from './FormStation.models';
32
32
  import classes from './FormStation.scss';
33
33
  import { SaveOnNavigate } from './SaveOnNavigate/SaveOnNavigate';
@@ -3,7 +3,7 @@ import React from 'react';
3
3
  import { act } from 'react-dom/test-utils';
4
4
  import { noop } from '../../../helpers/utils';
5
5
  import { TextButton } from '../../Buttons';
6
- import { ConfirmDialog, ConfirmationConfig } from '../../ConfirmDialog';
6
+ import { ConfirmationConfig, ConfirmDialog } from '../../ConfirmDialog';
7
7
  import { IconName } from '../../Icons';
8
8
  import {
9
9
  PageHeaderAction,
@@ -2,9 +2,9 @@ import clsx from 'clsx';
2
2
  import React, { useEffect, useState } from 'react';
3
3
  import { noop } from '../../../helpers/utils';
4
4
  import {
5
- ConfirmDialog,
6
5
  ConfirmationConfig,
7
6
  ConfirmationMode,
7
+ ConfirmDialog,
8
8
  useConfirmationDelay,
9
9
  } from '../../ConfirmDialog';
10
10
  import { IconName, Icons } from '../../Icons';
@@ -1,8 +1,8 @@
1
1
  export * from './CreateConnectionRenderer';
2
2
  export * from './FilterTransformer';
3
- export * from './RangeTransformer';
4
- export * from './SortTransformer';
5
- export * from './UpdateGQLFragmentGenerator';
6
3
  export * from './generateArrayMutations';
7
4
  export * from './getArrayDiff';
8
5
  export * from './getFormDiff';
6
+ export * from './RangeTransformer';
7
+ export * from './SortTransformer';
8
+ export * from './UpdateGQLFragmentGenerator';
@@ -1,8 +1,8 @@
1
1
  import {
2
- TIMESTAMP_DEFAULT,
3
- Timestamp,
4
2
  formatSecondsToTimestamp,
3
+ Timestamp,
5
4
  timestampToSeconds,
5
+ TIMESTAMP_DEFAULT,
6
6
  } from './Timestamp';
7
7
 
8
8
  const timeStamp: Timestamp = '00:02:00.000';
@@ -13,7 +13,11 @@ export const formatSecondsToTimestamp: TransformerFunction<
13
13
  number,
14
14
  Timestamp
15
15
  > = (timeInSeconds?: number | null): Timestamp => {
16
- if (timeInSeconds === null || timeInSeconds === undefined) {
16
+ if (
17
+ timeInSeconds === null ||
18
+ timeInSeconds === undefined ||
19
+ typeof timeInSeconds !== 'number'
20
+ ) {
17
21
  return TIMESTAMP_DEFAULT;
18
22
  }
19
23
 
@@ -19,8 +19,8 @@ export * from './List';
19
19
  export * from './Loaders';
20
20
  export * from './MessageBar';
21
21
  export * from './Modal';
22
+ export * from './models';
22
23
  export * from './NavigationAwareStation';
23
24
  export * from './PageHeader';
24
25
  export * from './ProgressBar';
25
26
  export * from './Utils';
26
- export * from './models';
@@ -11,6 +11,7 @@ export function noop(): void {}
11
11
  */
12
12
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
13
13
  export const assertNever = (_type: never): void => {
14
+ // eslint-disable-next-line no-console
14
15
  console.error(`Switch was not exhaustive`);
15
16
  };
16
17
 
@@ -25,3 +26,19 @@ export type Maybe<T> = T | null;
25
26
  export type Nullable<T> = {
26
27
  [P in keyof T]: T[P] | null;
27
28
  };
29
+
30
+ /**
31
+ * Checks if the ref is available before executing the provided function.
32
+ * @param ref Mutable Ref Object to check
33
+ * @param fn Function to execute
34
+ * @param args Arguments for the function
35
+ */
36
+ export const executeIfRefAvailable = async <U, T = never>(
37
+ ref: React.RefObject<U>,
38
+ fn: (arg0: U, ...args: T[]) => void,
39
+ ...args: T[]
40
+ ): Promise<void> => {
41
+ if (ref.current) {
42
+ fn(ref.current, ...args);
43
+ }
44
+ };
@@ -182,6 +182,7 @@ $tag-font-color: $dark-gray;
182
182
  $tag-background-color: $light-gray-2;
183
183
  $form-error-color: $red;
184
184
  $select-arrow-color: $blue;
185
+ $select-disabled-arrow-color: $light-gray;
185
186
  $label-font-size: 16px;
186
187
  $file-upload-progress: $blue;
187
188
  $file-upload-progress-background: $light-gray-2;