@axinom/mosaic-ui 0.31.0-rc.9 → 0.32.0-rc.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
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@axinom/mosaic-ui",
3
- "version": "0.31.0-rc.9",
3
+ "version": "0.32.0-rc.0",
4
4
  "description": "UI components for building Axinom Mosaic applications",
5
5
  "author": "Axinom",
6
6
  "license": "PROPRIETARY",
@@ -32,7 +32,7 @@
32
32
  "build-storybook": "storybook build"
33
33
  },
34
34
  "dependencies": {
35
- "@axinom/mosaic-core": "^0.4.4-rc.9",
35
+ "@axinom/mosaic-core": "^0.4.5-rc.0",
36
36
  "@faker-js/faker": "^7.4.0",
37
37
  "@popperjs/core": "^2.9.2",
38
38
  "clsx": "^1.1.0",
@@ -40,6 +40,7 @@
40
40
  "luxon": "^3.3.0",
41
41
  "react-calendar": "^3.3.1",
42
42
  "react-content-loader": "^6.0.3",
43
+ "react-imask": "^6.4.3",
43
44
  "react-popper": "^2.2.5",
44
45
  "react-transition-group": "^4.3.0",
45
46
  "yup": "^0.32.11"
@@ -101,5 +102,5 @@
101
102
  "publishConfig": {
102
103
  "access": "public"
103
104
  },
104
- "gitHead": "d6f35508b58053f75ec8fc8bd75236dbae206f1e"
105
+ "gitHead": "d99f62328986c3250b0491a0b8b5f55d89b66840"
105
106
  }
@@ -1,10 +1,10 @@
1
1
  import { mount, shallow } from 'enzyme';
2
2
  import React from 'react';
3
3
  import { act } from 'react-dom/test-utils';
4
- import { Link, BrowserRouter as Router } from 'react-router-dom';
4
+ import { BrowserRouter as Router, Link } from 'react-router-dom';
5
5
  import { noop } from '../../../helpers/utils';
6
6
  import { TextButton } from '../../Buttons';
7
- import { ConfirmDialog, ConfirmationConfig } from '../../ConfirmDialog';
7
+ import { ConfirmationConfig, ConfirmDialog } from '../../ConfirmDialog';
8
8
  import { IconName, Icons } from '../../Icons';
9
9
  import {
10
10
  Action,
@@ -2,8 +2,8 @@ import clsx from 'clsx';
2
2
  import React, { useEffect, useState } from 'react';
3
3
  import { Link } from 'react-router-dom';
4
4
  import {
5
- ConfirmDialog,
6
5
  ConfirmationConfig,
6
+ ConfirmDialog,
7
7
  useConfirmationDelay,
8
8
  } from '../../ConfirmDialog';
9
9
  import { IconName, Icons } from '../../Icons';
@@ -35,6 +35,8 @@
35
35
  white-space: nowrap;
36
36
  text-overflow: ellipsis;
37
37
  overflow: hidden;
38
+
39
+ padding: 2px;
38
40
  }
39
41
 
40
42
  .position,
@@ -56,6 +58,7 @@
56
58
  grid-template-columns: 1fr 1fr;
57
59
 
58
60
  justify-items: start;
61
+ align-items: center;
59
62
 
60
63
  opacity: 0.5;
61
64
 
@@ -110,8 +113,9 @@
110
113
  }
111
114
 
112
115
  .actionButtonContainer {
116
+ display: grid;
113
117
  height: 100%;
114
- align-items: start;
118
+ align-items: center;
115
119
 
116
120
  .actionButton {
117
121
  height: 50px;
@@ -7,49 +7,4 @@
7
7
  display: grid;
8
8
  grid-template-columns: 1fr;
9
9
  grid-template-rows: min-content min-content;
10
-
11
- input {
12
- width: 100%;
13
- box-sizing: border-box;
14
- height: var(--dynamic-list-input-height, $dynamic-list-input-height);
15
- padding: 0 6px;
16
-
17
- color: var(--input-color, $input-color);
18
- font-size: var(--label-font-size, $label-font-size);
19
-
20
- border: 1px solid var(--input-border-color, $input-border-color);
21
- outline: none;
22
-
23
- overflow: hidden;
24
- white-space: nowrap;
25
- text-overflow: ellipsis;
26
-
27
- transition: box-shadow 0.15s ease-in-out 0s;
28
-
29
- padding: 0 12px 0 12px;
30
-
31
- &.hasError {
32
- border: 1px solid
33
- var(--input-invalid-border-color, $input-invalid-border-color);
34
- }
35
- }
36
-
37
- input:hover:enabled,
38
- input:focus {
39
- border: 1px solid var(--input-hover-color, $input-hover-color);
40
- box-shadow: inset 0 0 0 2px var(--input-hover-color, $input-hover-color);
41
-
42
- &.hasError {
43
- border: 1px solid
44
- var(--input-invalid-border-color, $input-invalid-border-color);
45
- box-shadow: inset 0 0 0 2px
46
- var(--input-invalid-hover-color, $input-invalid-hover-color);
47
- }
48
- }
49
-
50
- > small {
51
- padding: 6px 0;
52
- white-space: normal;
53
- color: var(--input-invalid-color, $input-invalid-color);
54
- }
55
10
  }
@@ -43,66 +43,6 @@ describe('createInputRenderer', () => {
43
43
  expect(wrapper).toBeTruthy();
44
44
  });
45
45
 
46
- it(`renders an 'id' attribute on the 'input' element if set`, () => {
47
- const mockId = 'test-id';
48
- const wrapper = mount(<RendererWrapper id={mockId} />);
49
-
50
- const input = wrapper.find('input');
51
-
52
- expect(input.prop('id')).toBe(mockId);
53
- });
54
-
55
- it(`renders a 'name' attribute on the 'input' element if set`, () => {
56
- const mockName = 'test-name';
57
- const wrapper = mount(<RendererWrapper name={mockName} />);
58
-
59
- const input = wrapper.find('input');
60
-
61
- expect(input.prop('name')).toBe(mockName);
62
- });
63
-
64
- it(`renders a 'type' attribute on the 'input' element if set`, () => {
65
- const mockType = 'test-type';
66
- const wrapper = mount(<RendererWrapper type={mockType} />);
67
-
68
- const input = wrapper.find('input');
69
-
70
- expect(input.prop('type')).toBe(mockType);
71
- });
72
-
73
- it('renders "disabled" attribute on the "input" element with value "false" if not set otherwise', () => {
74
- const wrapper = mount(<RendererWrapper />);
75
-
76
- const input = wrapper.find('input');
77
-
78
- expect(input.prop('disabled')).toBe(false);
79
- });
80
-
81
- it('renders "disabled" attribute on the "input" element if set', () => {
82
- const wrapper = mount(<RendererWrapper disabled={true} />);
83
-
84
- const input = wrapper.find('input');
85
-
86
- expect(input.prop('disabled')).toBe(true);
87
- });
88
-
89
- it(`doesn't render placeholder by default`, () => {
90
- const wrapper = mount(<RendererWrapper />);
91
-
92
- const input = wrapper.find('input');
93
-
94
- expect(input.prop('placeholder')).toBeUndefined();
95
- });
96
-
97
- it(`renders a 'placeholder' attribute on the 'input' element if set`, () => {
98
- const mockPlaceholder = 'test-placeholder';
99
- const wrapper = mount(<RendererWrapper placeholder={mockPlaceholder} />);
100
-
101
- const input = wrapper.find('input');
102
-
103
- expect(input.prop('placeholder')).toBe(mockPlaceholder);
104
- });
105
-
106
46
  it(`sets 'input' value to current value`, () => {
107
47
  const mockValue = 'test-value';
108
48
  const wrapper = mount(<RendererWrapper currentValue={mockValue} />);
@@ -144,7 +84,9 @@ describe('createInputRenderer', () => {
144
84
  const input = wrapper.find('input');
145
85
 
146
86
  act(() => {
147
- input.simulate('change', { target: { value: mockStringifiedNumber } });
87
+ input.simulate('change', {
88
+ target: { value: mockStringifiedNumber },
89
+ });
148
90
  });
149
91
 
150
92
  expect(onValueChangeSpy).toHaveBeenCalledTimes(1);
@@ -1,6 +1,6 @@
1
- import clsx from 'clsx';
2
1
  import React, { ChangeEvent } from 'react';
3
2
  import { DynamicListDataEntryRenderer } from '../../../../DynamicDataList/DynamicDataList.model';
3
+ import { SingleLineText } from '../../../../FormElements';
4
4
  import { CreateInputRendererConfig } from '../renderers.model';
5
5
  import classes from './createInputRenderer.scss';
6
6
 
@@ -11,7 +11,7 @@ import classes from './createInputRenderer.scss';
11
11
  */
12
12
  export const createInputRenderer = ({
13
13
  id,
14
- name,
14
+ name = '',
15
15
  placeholder,
16
16
  type = 'text',
17
17
  transform = (value: string) => value,
@@ -27,19 +27,18 @@ export const createInputRenderer = ({
27
27
  };
28
28
 
29
29
  return (
30
- <div className={classes.container}>
31
- <input
32
- id={id}
33
- name={name}
34
- type={type}
35
- placeholder={placeholder}
36
- value={(currentValue as string) ?? ''}
37
- onChange={onChangeHandler}
38
- className={clsx({ [classes.hasError]: error !== undefined })}
39
- disabled={disabled}
40
- />
41
- {error !== undefined && <small>{error}</small>}
42
- </div>
30
+ <SingleLineText
31
+ id={id}
32
+ name={name}
33
+ type={type}
34
+ disabled={disabled}
35
+ placeholder={placeholder}
36
+ onChange={onChangeHandler}
37
+ inlineMode={true}
38
+ error={error}
39
+ className={classes.container}
40
+ value={(currentValue as string) ?? ''}
41
+ />
43
42
  );
44
43
  };
45
44
 
@@ -50,12 +50,12 @@
50
50
 
51
51
  select:hover {
52
52
  border: 1px solid var(--input-hover-color, $input-hover-color);
53
- box-shadow: inset 0 0 0 2px var(--input-hover-color, $input-hover-color);
53
+ box-shadow: 0 0 0 2px var(--input-hover-color, $input-hover-color);
54
54
 
55
55
  &.hasError {
56
56
  border: 1px solid
57
57
  var(--input-invalid-border-color, $input-invalid-border-color);
58
- box-shadow: inset 0 0 0 2px
58
+ box-shadow: 0 0 0 2px
59
59
  var(--input-invalid-hover-color, $input-invalid-hover-color);
60
60
  }
61
61
  }
@@ -1,8 +1,10 @@
1
+ import { BaseFormControl, SingleLineTextProps } from '../../../FormElements';
2
+
1
3
  export interface BaseRendererConfig {
2
4
  /** id html element id attribute */
3
- id?: string;
5
+ id?: BaseFormControl['id'];
4
6
  /** element name attribute */
5
- name?: string;
7
+ name?: BaseFormControl['name'];
6
8
  /** element placeholder attribute */
7
9
  placeholder?: string;
8
10
  /** Optional transformer that will change the final value to match the return value */
@@ -10,8 +12,8 @@ export interface BaseRendererConfig {
10
12
  }
11
13
 
12
14
  export interface CreateInputRendererConfig extends BaseRendererConfig {
13
- /** input element type attribute */
14
- type?: string;
15
+ /** Input element type */
16
+ type?: SingleLineTextProps['type'];
15
17
  /** optional transformer that will change the current value with each keypress. does not work with 'mask' prop. mainly used for trim(). */
16
18
  transform?: (value: string) => unknown;
17
19
  }
@@ -2,8 +2,8 @@ export * from './DynamicDataList';
2
2
  export * from './DynamicDataList.model';
3
3
  export * from './DynamicListDataEntry';
4
4
  export {
5
- CreateInputRendererConfig,
6
- CreateSelectRendererConfig,
7
5
  createInputRenderer,
6
+ CreateInputRendererConfig,
8
7
  createSelectRenderer,
8
+ CreateSelectRendererConfig,
9
9
  } from './DynamicListDataEntry/Renderers';
@@ -1,8 +1,8 @@
1
1
  import { mount, shallow } from 'enzyme';
2
2
  import React from 'react';
3
3
  import { MessageBar } from '../MessageBar';
4
- import { PageHeader } from '../PageHeader';
5
4
  import { StationError } from '../models';
5
+ import { PageHeader } from '../PageHeader';
6
6
  import { EmptyStation, EmptyStationProps } from './EmptyStation';
7
7
 
8
8
  describe('EmptyStation', () => {
@@ -1,8 +1,8 @@
1
1
  import clsx from 'clsx';
2
2
  import React, { PropsWithChildren } from 'react';
3
3
  import { MessageBar, MessageBarProps } from '../MessageBar';
4
- import { PageHeader, PageHeaderProps } from '../PageHeader';
5
4
  import { StationError } from '../models';
5
+ import { PageHeader, PageHeaderProps } from '../PageHeader';
6
6
  import classes from './EmptyStation.scss';
7
7
 
8
8
  export type EmptyStationProps = PageHeaderProps & {
@@ -1,8 +1,8 @@
1
1
  import clsx from 'clsx';
2
2
  import { LocationDescriptor } from 'history';
3
3
  import {
4
- ForwardedRef,
5
4
  default as React,
5
+ ForwardedRef,
6
6
  useCallback,
7
7
  useEffect,
8
8
  useState,
@@ -22,9 +22,9 @@ import {
22
22
  ListSelectMode,
23
23
  SortData,
24
24
  } from '../List';
25
+ import { ErrorType } from '../models';
25
26
  import { PageHeader, PageHeaderActionProps } from '../PageHeader';
26
27
  import { getState, storeState } from '../Utils/State/GlobalState';
27
- import { ErrorType } from '../models';
28
28
  import {
29
29
  ExplorerBulkAction,
30
30
  ExplorerDataProvider,
@@ -5,7 +5,6 @@
5
5
  -moz-appearance: none;
6
6
  -webkit-appearance: none;
7
7
  appearance: none;
8
- cursor: pointer;
9
8
  color: var(--input-color, $input-color);
10
9
  border: 1px solid var(--input-border-color, $input-border-color);
11
10
  width: max-content;
@@ -34,6 +33,10 @@
34
33
  border: 1px solid
35
34
  var(--input-invalid-border-color, $input-invalid-border-color);
36
35
  }
36
+
37
+ &:enabled {
38
+ cursor: pointer;
39
+ }
37
40
  }
38
41
 
39
42
  input:hover:enabled {
@@ -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';
@@ -83,8 +83,6 @@
83
83
  list-style-type: none;
84
84
  z-index: 10;
85
85
 
86
- // -webkit-box-shadow: 0px 0px 9px -2px rgba(0, 0, 0, 0.87);
87
-
88
86
  border: 1px solid gray;
89
87
  background-color: #ffffff;
90
88
 
@@ -1,5 +1,11 @@
1
1
  import clsx from 'clsx';
2
- import React, { FormEvent, useEffect, useRef, useState } from 'react';
2
+ import React, {
3
+ ChangeEvent,
4
+ FormEvent,
5
+ useEffect,
6
+ useRef,
7
+ useState,
8
+ } from 'react';
3
9
  import { CSSTransition, TransitionGroup } from 'react-transition-group';
4
10
  import { noop } from '../../../helpers/utils';
5
11
  import { useDebounce } from '../../../hooks/useDebounce/useDebounce';
@@ -84,7 +90,7 @@ export const CustomTags: React.FC<CustomTagsProps> = ({
84
90
  ...ref.current,
85
91
 
86
92
  currentTarget: { value: currentTags as unknown as string },
87
- } as React.FormEvent<HTMLInputElement>);
93
+ } as React.ChangeEvent<HTMLInputElement>);
88
94
 
89
95
  // Resets event data
90
96
  ref.current = undefined;
@@ -266,7 +272,7 @@ export const CustomTags: React.FC<CustomTagsProps> = ({
266
272
  * Called when a user focuses out of the input
267
273
  * @param e Input form event
268
274
  */
269
- const onBlurHandler = (e: FormEvent<HTMLInputElement>): void => {
275
+ const onBlurHandler = (e: ChangeEvent<HTMLInputElement>): void => {
270
276
  onBlur(e);
271
277
 
272
278
  // reset input if value is only whitespaces
@@ -280,7 +286,7 @@ export const CustomTags: React.FC<CustomTagsProps> = ({
280
286
  currentTarget: {
281
287
  value: textInput.current?.value ?? '',
282
288
  },
283
- } as FormEvent<HTMLInputElement>);
289
+ } as ChangeEvent<HTMLInputElement>);
284
290
  };
285
291
 
286
292
  return (
@@ -108,6 +108,7 @@ export const DateTimeText: React.FC<DateTimeTextProps> = ({
108
108
  type="button"
109
109
  icon={IconName.Calendar}
110
110
  buttonContext={ButtonContext.Icon}
111
+ disabled={disabled}
111
112
  className={clsx(classes.button)}
112
113
  onButtonClicked={(e) => {
113
114
  e.persist();
@@ -12,8 +12,7 @@ export const DateTimeTextField: React.FC<Omit<DateTimeTextProps, 'error'>> = (
12
12
  props,
13
13
  ) => {
14
14
  const error = useFormikError(props.name);
15
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
16
- const [field, meta, helpers] = useField(props.name);
15
+ const [, meta, helpers] = useField(props.name);
17
16
 
18
17
  const handleChange = (value: string | null, valid?: boolean): void => {
19
18
  if (!valid) {
@@ -1,4 +1,4 @@
1
- import { FormEvent, ReactNode } from 'react';
1
+ import { ChangeEvent, FormEvent, ReactNode } from 'react';
2
2
 
3
3
  export interface BaseFormElement {
4
4
  /** Form control id */
@@ -24,11 +24,11 @@ export interface BaseFormControl extends BaseFormElement {
24
24
 
25
25
  export interface BaseInputEvents {
26
26
  /** Raised when the value has changed */
27
- onChange?: (event: FormEvent<HTMLInputElement>) => void;
27
+ onChange?: (event: ChangeEvent<HTMLInputElement>) => void;
28
28
  /** Raised when the element has been selected */
29
- onBlur?: (event: FormEvent<HTMLInputElement>) => void;
29
+ onBlur?: (event: ChangeEvent<HTMLInputElement>) => void;
30
30
  /** Raised when the element has been de-selected */
31
- onFocus?: (event: FormEvent<HTMLInputElement>) => void;
31
+ onFocus?: (event: ChangeEvent<HTMLInputElement>) => void;
32
32
  }
33
33
 
34
34
  export interface BaseSelectEvents {
@@ -45,10 +45,15 @@
45
45
  }
46
46
  }
47
47
 
48
- > small {
48
+ .error {
49
49
  padding-top: 6px;
50
50
  grid-row: 2;
51
51
  grid-column: 2;
52
52
  color: var(--input-invalid-color, $input-invalid-color);
53
+ white-space: normal;
54
+
55
+ &.inlineMode {
56
+ grid-column: 1;
57
+ }
53
58
  }
54
59
  }
@@ -78,7 +78,14 @@ export const FormElementContainer: React.FC<FormElementContainerProps> = ({
78
78
  >
79
79
  {children}
80
80
  </div>
81
- {error && <small data-test-id="form-field-error">{error}</small>}
81
+ {error && (
82
+ <small
83
+ className={clsx({ [classes.inlineMode]: inlineMode }, classes.error)}
84
+ data-test-id="form-field-error"
85
+ >
86
+ {error}
87
+ </small>
88
+ )}
82
89
  </div>
83
90
  );
84
91
  };
@@ -0,0 +1,19 @@
1
+ import { shallow } from 'enzyme';
2
+ import React from 'react';
3
+ import { noop } from '../../../helpers/utils';
4
+ import { MaskedSingleLineText } from './MaskedSingleLineText';
5
+
6
+ const defaultProps = {
7
+ name: 'timestamp',
8
+ label: 'Timestamp',
9
+ mask: '000',
10
+ onChange: noop,
11
+ };
12
+
13
+ describe('MaskedSingleLineText', () => {
14
+ it('should render the component without crashing', () => {
15
+ const wrapper = shallow(<MaskedSingleLineText {...defaultProps} />);
16
+
17
+ expect(wrapper).toBeTruthy();
18
+ });
19
+ });
@@ -0,0 +1,65 @@
1
+ import { action } from '@storybook/addon-actions';
2
+ import { Meta, StoryObj } from '@storybook/react';
3
+ import React, { useState } from 'react';
4
+ import { createGroups } from '../../../helpers/storybook';
5
+ import { MaskedSingleLineText } from './MaskedSingleLineText';
6
+
7
+ const groups = createGroups({
8
+ Behavior: [
9
+ 'autoComplete',
10
+ 'autoFocus',
11
+ 'disabled',
12
+ 'inlineMode',
13
+ 'name',
14
+ 'id',
15
+ 'innerRef',
16
+ 'mask',
17
+ 'overwrite',
18
+ 'placeholderChar',
19
+ 'lazy',
20
+ ],
21
+ Content: [
22
+ 'label',
23
+ 'placeholder',
24
+ 'error',
25
+ 'tooltipContent',
26
+ 'value',
27
+ 'defaultValue',
28
+ ],
29
+ Styling: ['className'],
30
+ Events: ['onChange', 'onBlur', 'onFocus'],
31
+ });
32
+
33
+ const meta: Meta<typeof MaskedSingleLineText> = {
34
+ title: 'Primary Components/Form Elements/MaskedSingleLineText',
35
+ component: MaskedSingleLineText,
36
+ argTypes: {
37
+ ...groups,
38
+ },
39
+ };
40
+ export default meta;
41
+
42
+ export const Main: StoryObj<typeof MaskedSingleLineText> = {
43
+ args: {
44
+ name: 'timestamp',
45
+ label: 'Timestamp',
46
+ mask: '00:00:00.000',
47
+ placeholderChar: '0',
48
+ lazy: false,
49
+ },
50
+ render: (args) =>
51
+ React.createElement(() => {
52
+ const [value, setValue] = useState<string>();
53
+
54
+ return (
55
+ <MaskedSingleLineText
56
+ {...args}
57
+ value={value}
58
+ onChange={(e) => {
59
+ action('onChange')(e);
60
+ setValue(value);
61
+ }}
62
+ />
63
+ );
64
+ }),
65
+ };
@@ -0,0 +1,60 @@
1
+ import React, { useEffect } from 'react';
2
+ import { useIMask } from 'react-imask';
3
+ import {
4
+ SingleLineText,
5
+ SingleLineTextProps,
6
+ } from '../SingleLineText/SingleLineText';
7
+
8
+ export interface MaskedSingleLineTextProps
9
+ extends Omit<SingleLineTextProps, 'onChange' | 'type' | 'value' | 'isSet'> {
10
+ /** Expression to be used as a validator.
11
+ * Refer https://imask.js.org/guide.html#masked-pattern for examples
12
+ */
13
+ mask: string;
14
+
15
+ /** Placeholder character for the mask */
16
+ placeholderChar?: string;
17
+
18
+ /** Current value the form control has */
19
+ value?: string;
20
+
21
+ /** Whether the mask should not be shown by default. (default: true) */
22
+ lazy?: boolean;
23
+
24
+ /** Whether new inputs should overwrite existing text. (default: false) */
25
+ overwrite?: boolean;
26
+
27
+ /** Raised when the value has changed */
28
+ onChange: (value: string) => unknown;
29
+ }
30
+
31
+ export const MaskedSingleLineText: React.FC<MaskedSingleLineTextProps> = ({
32
+ onChange,
33
+ mask,
34
+ placeholderChar = '_',
35
+ value: formikValue = '',
36
+ lazy = true,
37
+ overwrite = false,
38
+ ...props
39
+ }) => {
40
+ const { ref, maskRef } = useIMask(
41
+ { mask, placeholderChar, lazy, overwrite },
42
+ {
43
+ onAccept: (value, _ref, e) => {
44
+ // OnChange shouldn't be used https://github.com/uNmAnNeR/imaskjs/issues/318
45
+ // OnAccept fires during initial load making the form dirty. However, the synthetic event is not
46
+ // present when this happens so we check for the event to see if it's actually a keyboard event
47
+ // that triggered onAccept.
48
+ if (e) {
49
+ onChange(value);
50
+ }
51
+ },
52
+ },
53
+ );
54
+
55
+ useEffect(() => {
56
+ maskRef.current.value = formikValue as string;
57
+ }, [formikValue, maskRef]);
58
+
59
+ return <SingleLineText innerRef={ref} type="text" {...props} />;
60
+ };