@axinom/mosaic-ui 0.34.0-rc.9 → 0.34.1

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 (57) hide show
  1. package/dist/components/Explorer/SelectionExplorer/SelectionExplorer.d.ts +3 -0
  2. package/dist/components/Explorer/SelectionExplorer/SelectionExplorer.d.ts.map +1 -1
  3. package/dist/components/FormElements/Checkbox/Checkbox.d.ts.map +1 -1
  4. package/dist/components/FormElements/Checkbox/CheckboxField.d.ts +1 -1
  5. package/dist/components/FormElements/Checkbox/CheckboxField.d.ts.map +1 -1
  6. package/dist/components/FormElements/CustomTags/CustomTagsField.d.ts.map +1 -1
  7. package/dist/components/FormElements/DateTimeField/DateTimeTextField.d.ts +1 -1
  8. package/dist/components/FormElements/DateTimeField/DateTimeTextField.d.ts.map +1 -1
  9. package/dist/components/FormElements/DynamicDataListControl/DynamicDataListField.d.ts.map +1 -1
  10. package/dist/components/FormElements/FileUploadControl/FileUploadField.d.ts.map +1 -1
  11. package/dist/components/FormElements/MaskedSingleLineText/MaskedSingleLineTextField.d.ts +1 -1
  12. package/dist/components/FormElements/MaskedSingleLineText/MaskedSingleLineTextField.d.ts.map +1 -1
  13. package/dist/components/FormElements/SingleLineText/SingleLineText.d.ts.map +1 -1
  14. package/dist/components/List/ListRow/ListRow.d.ts.map +1 -1
  15. package/dist/components/List/useColumnsSize.d.ts +1 -0
  16. package/dist/components/List/useColumnsSize.d.ts.map +1 -1
  17. package/dist/index.es.js +3 -3
  18. package/dist/index.es.js.map +1 -1
  19. package/dist/index.js +3 -3
  20. package/dist/index.js.map +1 -1
  21. package/dist/initialize.d.ts +3 -3
  22. package/dist/initialize.d.ts.map +1 -1
  23. package/package.json +3 -3
  24. package/src/components/DynamicDataList/DynamicListDataEntry/Renderers/createInputRenderer/createInputRenderer.spec.tsx +2 -2
  25. package/src/components/Explorer/SelectionExplorer/SelectionExplorer.spec.tsx +49 -0
  26. package/src/components/Explorer/SelectionExplorer/SelectionExplorer.stories.tsx +111 -45
  27. package/src/components/Explorer/SelectionExplorer/SelectionExplorer.tsx +24 -3
  28. package/src/components/FormElements/BooleanView/BooleanViewField.scss +4 -6
  29. package/src/components/FormElements/BooleanView/BooleanViewField.spec.tsx +6 -6
  30. package/src/components/FormElements/BooleanView/BooleanViewField.tsx +1 -1
  31. package/src/components/FormElements/Checkbox/Checkbox.tsx +1 -1
  32. package/src/components/FormElements/Checkbox/CheckboxField.tsx +4 -5
  33. package/src/components/FormElements/CustomTags/CustomTags.scss +15 -4
  34. package/src/components/FormElements/CustomTags/CustomTags.spec.tsx +3 -3
  35. package/src/components/FormElements/CustomTags/CustomTags.tsx +3 -3
  36. package/src/components/FormElements/CustomTags/CustomTagsField.tsx +1 -2
  37. package/src/components/FormElements/DateTimeField/DateTimeTextField.tsx +3 -3
  38. package/src/components/FormElements/DynamicDataListControl/DynamicDataListField.tsx +1 -2
  39. package/src/components/FormElements/FileUploadControl/FileUploadField.tsx +1 -2
  40. package/src/components/FormElements/FormElementContainer/FormElementContainer.scss +0 -1
  41. package/src/components/FormElements/MaskedSingleLineText/MaskedSingleLineTextField.tsx +1 -1
  42. package/src/components/FormElements/Radio/RadioField.tsx +2 -2
  43. package/src/components/FormElements/SingleLineText/SingleLineText.spec.tsx +5 -4
  44. package/src/components/FormElements/SingleLineText/SingleLineText.tsx +6 -1
  45. package/src/components/FormElements/Tags/Tags.scss +1 -1
  46. package/src/components/FormElements/ToggleButton/ToggleButton.scss +18 -7
  47. package/src/components/FormStation/FormStation.spec.tsx +12 -6
  48. package/src/components/FormStation/FormStation.tsx +6 -6
  49. package/src/components/InlineMenu/InlineMenu.scss +20 -5
  50. package/src/components/LandingPageTiles/TileLarge/TileLarge.scss +11 -6
  51. package/src/components/List/List.tsx +1 -1
  52. package/src/components/List/ListRow/ListRow.scss +4 -1
  53. package/src/components/List/ListRow/ListRow.spec.tsx +11 -6
  54. package/src/components/List/ListRow/ListRow.tsx +60 -47
  55. package/src/components/List/useColumnsSize.ts +20 -3
  56. package/src/initialize.ts +4 -4
  57. package/src/styles/variables.scss +11 -0
@@ -1,5 +1,5 @@
1
1
  import { AddIndicator, CustomEventEmitter, RemoveIndicator, ShowNotification } from './types/ui-config';
2
- export declare enum IndicatorType {
2
+ export declare enum SaveIndicatorType {
3
3
  Saving = "saving",
4
4
  Inactive = "inactive",
5
5
  Dirty = "dirty"
@@ -8,7 +8,7 @@ export declare let showNotification: ShowNotification | (() => void);
8
8
  export declare let addIndicator: AddIndicator | (() => void);
9
9
  export declare let removeIndicator: RemoveIndicator | (() => void);
10
10
  export declare let on: CustomEventEmitter['on'] | (() => void);
11
- export declare let setSaveIndicator: (type: IndicatorType) => void;
11
+ export declare let setSaveIndicator: (type: SaveIndicatorType) => void;
12
12
  /**
13
13
  * Passes the PiralApi methods to the UI library.
14
14
  * @param app {UiConfig} object containing PiralApi methods for use in UI library.
@@ -19,6 +19,6 @@ export interface UiConfig {
19
19
  addIndicator: AddIndicator;
20
20
  removeIndicator: RemoveIndicator;
21
21
  on: CustomEventEmitter['on'];
22
- setSaveIndicator: (type: IndicatorType) => void;
22
+ setSaveIndicator: (type: SaveIndicatorType) => void;
23
23
  }
24
24
  //# sourceMappingURL=initialize.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"initialize.d.ts","sourceRoot":"","sources":["../src/initialize.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,YAAY,EACZ,kBAAkB,EAClB,eAAe,EACf,gBAAgB,EACjB,MAAM,mBAAmB,CAAC;AAE3B,oBAAY,aAAa;IACvB,MAAM,WAAW;IACjB,QAAQ,aAAa;IACrB,KAAK,UAAU;CAChB;AAED,eAAO,IAAI,gBAAgB,EAAE,gBAAgB,GAAG,CAAC,MAAM,IAAI,CAC7B,CAAC;AAE/B,eAAO,IAAI,YAAY,EAAE,YAAY,GAAG,CAAC,MAAM,IAAI,CAA4B,CAAC;AAEhF,eAAO,IAAI,eAAe,EAAE,eAAe,GAAG,CAAC,MAAM,IAAI,CAC5B,CAAC;AAE9B,eAAO,IAAI,EAAE,EAAE,kBAAkB,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,IAAI,CAAkB,CAAC;AAExE,eAAO,IAAI,gBAAgB,EAAE,CAAC,IAAI,EAAE,aAAa,KAAK,IACvB,CAAC;AAEhC;;;GAGG;AACH,wBAAgB,YAAY,CAAC,GAAG,EAAE,QAAQ,GAAG,IAAI,CAQhD;AAED,MAAM,WAAW,QAAQ;IACvB,gBAAgB,EAAE,gBAAgB,CAAC;IACnC,YAAY,EAAE,YAAY,CAAC;IAC3B,eAAe,EAAE,eAAe,CAAC;IACjC,EAAE,EAAE,kBAAkB,CAAC,IAAI,CAAC,CAAC;IAC7B,gBAAgB,EAAE,CAAC,IAAI,EAAE,aAAa,KAAK,IAAI,CAAC;CACjD"}
1
+ {"version":3,"file":"initialize.d.ts","sourceRoot":"","sources":["../src/initialize.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,YAAY,EACZ,kBAAkB,EAClB,eAAe,EACf,gBAAgB,EACjB,MAAM,mBAAmB,CAAC;AAE3B,oBAAY,iBAAiB;IAC3B,MAAM,WAAW;IACjB,QAAQ,aAAa;IACrB,KAAK,UAAU;CAChB;AAED,eAAO,IAAI,gBAAgB,EAAE,gBAAgB,GAAG,CAAC,MAAM,IAAI,CAC7B,CAAC;AAE/B,eAAO,IAAI,YAAY,EAAE,YAAY,GAAG,CAAC,MAAM,IAAI,CAA4B,CAAC;AAEhF,eAAO,IAAI,eAAe,EAAE,eAAe,GAAG,CAAC,MAAM,IAAI,CAC5B,CAAC;AAE9B,eAAO,IAAI,EAAE,EAAE,kBAAkB,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,IAAI,CAAkB,CAAC;AAExE,eAAO,IAAI,gBAAgB,EAAE,CAAC,IAAI,EAAE,iBAAiB,KAAK,IAC5B,CAAC;AAE/B;;;GAGG;AACH,wBAAgB,YAAY,CAAC,GAAG,EAAE,QAAQ,GAAG,IAAI,CAQhD;AAED,MAAM,WAAW,QAAQ;IACvB,gBAAgB,EAAE,gBAAgB,CAAC;IACnC,YAAY,EAAE,YAAY,CAAC;IAC3B,eAAe,EAAE,eAAe,CAAC;IACjC,EAAE,EAAE,kBAAkB,CAAC,IAAI,CAAC,CAAC;IAC7B,gBAAgB,EAAE,CAAC,IAAI,EAAE,iBAAiB,KAAK,IAAI,CAAC;CACrD"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@axinom/mosaic-ui",
3
- "version": "0.34.0-rc.9",
3
+ "version": "0.34.1",
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.7-rc.9",
35
+ "@axinom/mosaic-core": "^0.4.7",
36
36
  "@faker-js/faker": "^7.4.0",
37
37
  "@popperjs/core": "^2.9.2",
38
38
  "clsx": "^1.1.0",
@@ -102,5 +102,5 @@
102
102
  "publishConfig": {
103
103
  "access": "public"
104
104
  },
105
- "gitHead": "94ff309a76a395dfa2c13eed746c6603c15df0bd"
105
+ "gitHead": "26de70cf028138cec5bf4a5cccc73c61ce105e47"
106
106
  }
@@ -49,7 +49,7 @@ describe('createInputRenderer', () => {
49
49
 
50
50
  const input = wrapper.find('input');
51
51
 
52
- expect(input.prop('value')).toBe(mockValue);
52
+ expect(input.getDOMNode<HTMLInputElement>().value).toBe(mockValue);
53
53
  });
54
54
 
55
55
  it(`emits 'onValueChange' with the new value when 'input' value has changed`, () => {
@@ -59,7 +59,7 @@ describe('createInputRenderer', () => {
59
59
 
60
60
  const input = wrapper.find('input');
61
61
 
62
- expect(input.prop('value')).toBe('');
62
+ expect(input.getDOMNode<HTMLInputElement>().value).toBe('');
63
63
 
64
64
  act(() => {
65
65
  input.simulate('change', { target: { value: mockValueUpdated } });
@@ -1,4 +1,5 @@
1
1
  import { mount, shallow } from 'enzyme';
2
+ import { noop } from 'lodash';
2
3
  import React from 'react';
3
4
  import { act } from 'react-dom/test-utils';
4
5
  import { actWithReturn } from '../../../helpers/testing';
@@ -165,4 +166,52 @@ describe('SelectionExplorer', () => {
165
166
  mode: 'SINGLE_ITEMS',
166
167
  });
167
168
  });
169
+
170
+ it('shows inline menu with link to details page when `generateItemLink` is set', () => {
171
+ const [provider] = getDataProvider();
172
+ const path = '/test';
173
+
174
+ const wrapper = shallow(
175
+ <SelectionExplorer
176
+ columns={mockListColumns}
177
+ dataProvider={provider}
178
+ stationKey="mock-key"
179
+ onSelection={noop}
180
+ generateItemLink={() => path}
181
+ />,
182
+ );
183
+
184
+ const actions =
185
+ wrapper.find(Explorer).prop('inlineMenuActions')?.({}) || [];
186
+ expect(actions[0].path).toBe(path);
187
+ expect(actions[0].openInNewTab).toBe(true);
188
+ });
189
+
190
+ it('adds details page inline menu action when `inlineMenuActions` and `generateItemLink` is defined', () => {
191
+ const [provider] = getDataProvider();
192
+ const path = '/test';
193
+ const inlineAction = {
194
+ label: 'Test Action',
195
+ onActionSelected: noop,
196
+ };
197
+
198
+ const wrapper = shallow(
199
+ <SelectionExplorer
200
+ columns={mockListColumns}
201
+ dataProvider={provider}
202
+ stationKey="mock-key"
203
+ onSelection={noop}
204
+ inlineMenuActions={() => [inlineAction]}
205
+ generateItemLink={() => path}
206
+ />,
207
+ );
208
+
209
+ const actions =
210
+ wrapper.find(Explorer).prop('inlineMenuActions')?.({}) || [];
211
+
212
+ expect(actions[0]).toBe(inlineAction);
213
+
214
+ expect(actions[1].path).toBe(path);
215
+ expect(actions[1].openInNewTab).toBe(true);
216
+ });
168
217
  });
@@ -1,15 +1,20 @@
1
1
  import { faker } from '@faker-js/faker';
2
2
  import { action } from '@storybook/addon-actions';
3
3
  import { Meta, StoryObj } from '@storybook/react';
4
+ import { noop } from 'lodash';
4
5
  import React, { useMemo } from 'react';
6
+ import { MemoryRouter } from 'react-router';
5
7
  import {
6
8
  createGroups,
7
9
  generateItemArray,
8
10
  randomDate,
9
11
  } from '../../../helpers/storybook';
10
12
  import { FilterType, FilterTypes } from '../../Filters/Filters.model';
11
- import { ExplorerDataProvider } from '../Explorer.model';
12
- import { ExplorerStoryData } from '../ExplorerStoryType';
13
+ import { IconName } from '../../Icons';
14
+ import {
15
+ ExplorerDataProvider,
16
+ ExplorerDataProviderConfiguration,
17
+ } from '../Explorer.model';
13
18
  import {
14
19
  createInMemoryDataProvider,
15
20
  findAnywhereInStringCaseInsensitive,
@@ -77,7 +82,7 @@ export default meta;
77
82
  const generateData = (
78
83
  amount: number,
79
84
  { startIndex = 1, usePrefix = true } = {},
80
- ): ExplorerStoryData[] =>
85
+ ): SelectExplorerStoryData[] =>
81
86
  generateItemArray(amount, (i) => {
82
87
  const index = i + startIndex;
83
88
  return {
@@ -92,6 +97,49 @@ const generateData = (
92
97
  };
93
98
  });
94
99
 
100
+ const generateDataProvider =
101
+ (): ExplorerDataProvider<SelectExplorerStoryData> => {
102
+ const pageSize = 20;
103
+
104
+ const actualProvider = createInMemoryDataProvider<SelectExplorerStoryData>(
105
+ generateData(100, {
106
+ usePrefix: false,
107
+ }),
108
+ {
109
+ filterFunctions: {
110
+ title: findAnywhereInStringCaseInsensitive,
111
+ desc: findAnywhereInStringCaseInsensitive,
112
+ },
113
+ },
114
+ );
115
+ return {
116
+ loadData: async (
117
+ config: ExplorerDataProviderConfiguration<SelectExplorerStoryData>,
118
+ ) => {
119
+ // Report the call
120
+ action('loadData')(config);
121
+
122
+ const currentPage = (config.pagingInformation as number) ?? 0;
123
+
124
+ // Use the in memory provider to do the heavy lifting
125
+ const { totalCount, filteredCount, data } =
126
+ await actualProvider.loadData(config);
127
+
128
+ // Apply paging to the results
129
+ return {
130
+ totalCount: totalCount,
131
+ filteredCount: filteredCount,
132
+ data: data.slice(
133
+ pageSize * currentPage,
134
+ pageSize * (currentPage + 1),
135
+ ),
136
+ pagingInformation: currentPage + 1,
137
+ hasMoreData: currentPage < 9,
138
+ };
139
+ },
140
+ };
141
+ };
142
+
95
143
  const freeTextFilter: FilterType<SelectExplorerStoryData> = {
96
144
  label: 'Title',
97
145
  property: 'title',
@@ -114,8 +162,7 @@ const optionFilter: FilterType<SelectExplorerStoryData> = {
114
162
  ],
115
163
  };
116
164
 
117
- export const SelectExplorer: StoryObj<SelectionExplorerStoryType> = {
118
- name: 'Selection Explorer',
165
+ export const Default: StoryObj<SelectionExplorerStoryType> = {
119
166
  args: {
120
167
  title: 'Selection Explorer',
121
168
  columns: [
@@ -141,46 +188,7 @@ export const SelectExplorer: StoryObj<SelectionExplorerStoryType> = {
141
188
  render: (args) =>
142
189
  React.createElement(() => {
143
190
  const dataProvider: ExplorerDataProvider<SelectExplorerStoryData> =
144
- useMemo(() => {
145
- const pageSize = 20;
146
-
147
- const actualProvider =
148
- createInMemoryDataProvider<SelectExplorerStoryData>(
149
- generateData(100, {
150
- usePrefix: false,
151
- }),
152
- {
153
- filterFunctions: {
154
- title: findAnywhereInStringCaseInsensitive,
155
- desc: findAnywhereInStringCaseInsensitive,
156
- },
157
- },
158
- );
159
- return {
160
- loadData: async (config) => {
161
- // Report the call
162
- action('loadData')(config);
163
-
164
- const currentPage = (config.pagingInformation as number) ?? 0;
165
-
166
- // Use the in memory provider to do the heavy lifting
167
- const { totalCount, filteredCount, data } =
168
- await actualProvider.loadData(config);
169
-
170
- // Apply paging to the results
171
- return {
172
- totalCount: totalCount,
173
- filteredCount: filteredCount,
174
- data: data.slice(
175
- pageSize * currentPage,
176
- pageSize * (currentPage + 1),
177
- ),
178
- pagingInformation: currentPage + 1,
179
- hasMoreData: currentPage < 9,
180
- };
181
- },
182
- };
183
- }, []);
191
+ useMemo(generateDataProvider, []);
184
192
 
185
193
  return (
186
194
  <SelectionExplorer<SelectExplorerStoryData>
@@ -190,3 +198,61 @@ export const SelectExplorer: StoryObj<SelectionExplorerStoryType> = {
190
198
  );
191
199
  }),
192
200
  };
201
+
202
+ export const WithOpenDetailsInlineAction: StoryObj<SelectionExplorerStoryType> =
203
+ {
204
+ args: {
205
+ ...Default.args,
206
+ stationKey: 'SelectionStoryBookExplorer_WithOpenDetailsInlineAction',
207
+ generateItemLink: () => `#`,
208
+ },
209
+ render: (args) =>
210
+ React.createElement(() => {
211
+ const dataProvider: ExplorerDataProvider<SelectExplorerStoryData> =
212
+ useMemo(generateDataProvider, []);
213
+
214
+ return (
215
+ <MemoryRouter>
216
+ <SelectionExplorer<SelectExplorerStoryData>
217
+ {...args}
218
+ dataProvider={dataProvider}
219
+ />
220
+ </MemoryRouter>
221
+ );
222
+ }),
223
+ };
224
+
225
+ export const WithInlineActions: StoryObj<SelectionExplorerStoryType> = {
226
+ args: {
227
+ ...Default.args,
228
+ stationKey: 'SelectionStoryBookExplorer_WithInlineActions',
229
+ inlineMenuActions: () => {
230
+ return [
231
+ {
232
+ label: 'Navigation Action',
233
+ icon: IconName.NavigateRight,
234
+ path: '#',
235
+ },
236
+ {
237
+ label: 'Context Action',
238
+ icon: IconName.Ellipsis,
239
+ onActionSelected: noop,
240
+ },
241
+ ];
242
+ },
243
+ },
244
+ render: (args) =>
245
+ React.createElement(() => {
246
+ const dataProvider: ExplorerDataProvider<SelectExplorerStoryData> =
247
+ useMemo(generateDataProvider, []);
248
+
249
+ return (
250
+ <MemoryRouter>
251
+ <SelectionExplorer<SelectExplorerStoryData>
252
+ {...args}
253
+ dataProvider={dataProvider}
254
+ />
255
+ </MemoryRouter>
256
+ );
257
+ }),
258
+ };
@@ -1,6 +1,8 @@
1
+ import { LocationDescriptor } from 'history';
1
2
  import React, { ForwardedRef } from 'react';
2
3
  import { noop } from '../../../helpers/utils';
3
4
  import { Data } from '../../../types/data';
5
+ import { ActionData } from '../../Actions/Actions.models';
4
6
  import { IconName } from '../../Icons';
5
7
  import { ListSelectMode } from '../../List';
6
8
  import { Explorer, ExplorerProps } from '../Explorer';
@@ -23,6 +25,9 @@ export interface SelectionExplorerProps<T extends Data>
23
25
  * The selected item (or items) will be passed as argument to the callback.
24
26
  */
25
27
  onSelection?: (selection: ItemSelection<T>) => void;
28
+
29
+ /** When set, this function is used to generate inline menu link that navigates user to details page for each item. */
30
+ generateItemLink?: (data: T) => LocationDescriptor<unknown>;
26
31
  }
27
32
 
28
33
  /**
@@ -38,14 +43,14 @@ export interface SelectionExplorerProps<T extends Data>
38
43
  export const SelectionExplorer = React.forwardRef(function SelectionExplorer<
39
44
  T extends Data,
40
45
  >(
41
- props: SelectionExplorerProps<T>,
46
+ { generateItemLink, inlineMenuActions, ...rest }: SelectionExplorerProps<T>,
42
47
  ref: ForwardedRef<ExplorerDataProviderConnection<T>>,
43
48
  ): JSX.Element {
44
49
  const {
45
50
  allowBulkSelect = false,
46
51
  onSelection = noop,
47
52
  modalMode = true,
48
- } = props;
53
+ } = rest;
49
54
 
50
55
  const onItemClickedHandler = (item: T, mode?: ListSelectMode): void => {
51
56
  // only if the list is not in Multi mode is this executed
@@ -54,10 +59,25 @@ export const SelectionExplorer = React.forwardRef(function SelectionExplorer<
54
59
  }
55
60
  };
56
61
 
62
+ let selectionExplorerActions = inlineMenuActions;
63
+
64
+ if (generateItemLink) {
65
+ selectionExplorerActions = (data: T): ActionData[] => {
66
+ return [
67
+ ...(inlineMenuActions?.(data) ?? []),
68
+ {
69
+ label: 'Open Details',
70
+ path: generateItemLink(data),
71
+ openInNewTab: true,
72
+ },
73
+ ];
74
+ };
75
+ }
76
+
57
77
  return (
58
78
  <Explorer<T>
79
+ {...rest}
59
80
  ref={ref}
60
- {...props}
61
81
  modalMode={modalMode}
62
82
  bulkActions={[
63
83
  ...(allowBulkSelect
@@ -75,6 +95,7 @@ export const SelectionExplorer = React.forwardRef(function SelectionExplorer<
75
95
  ]}
76
96
  selectionMode={ListSelectMode.Single}
77
97
  onItemClicked={onItemClickedHandler}
98
+ inlineMenuActions={selectionExplorerActions}
78
99
  />
79
100
  );
80
101
  });
@@ -8,18 +8,16 @@
8
8
  font-size: var(--label-font-size, $label-font-size);
9
9
  align-items: center;
10
10
 
11
- .red {
12
- background-color: $red;
11
+ .false {
12
+ background-image: url("data:image/svg+xml, %3Csvg version='1.1' xmlns='http://www.w3.org/2000/svg' viewBox='0 0 40 40' %3E%3Cpath vector-effect='non-scaling-stroke' fill='none' stroke='%23707070' stroke-width='2' d='M20.1,2.4c9.9,0,18,8.1,18,18s-8.1,18-18,18s-18-8.1-18-18 S10.2,2.4,20.1,2.4z M28.6,20H11.4'/%3E%3C/svg%3E");
13
13
  height: 20px;
14
14
  width: 20px;
15
- border-radius: 100%;
16
15
  }
17
16
 
18
- .green {
19
- background-color: $green;
17
+ .true {
18
+ background-image: url("data:image/svg+xml, %3Csvg version='1.1' xmlns='http://www.w3.org/2000/svg' viewBox='0 0 40 40' %3E%3Cpath vector-effect='non-scaling-stroke' fill='none' stroke='%2395C842' stroke-width='2' d='M20,2c9.9,0,18,8.1,18,18s-8.1,18-18,18S2,29.9,2,20S10.1,2,20,2z M29,13.5 L17.8,26.3L11,19.1'/%3E%3C/svg%3E");
20
19
  height: 20px;
21
20
  width: 20px;
22
- border-radius: 100%;
23
21
  }
24
22
  }
25
23
  }
@@ -40,8 +40,8 @@ describe('BooleanViewField', () => {
40
40
  />,
41
41
  );
42
42
 
43
- const green = wrapper.find('.green');
44
- const red = wrapper.find('.red');
43
+ const green = wrapper.find('.true');
44
+ const red = wrapper.find('.false');
45
45
  const text = wrapper.find('.text');
46
46
 
47
47
  expect(green.exists()).toBe(true);
@@ -61,8 +61,8 @@ describe('BooleanViewField', () => {
61
61
  />,
62
62
  );
63
63
 
64
- const green = wrapper.find('.green');
65
- const red = wrapper.find('.red');
64
+ const green = wrapper.find('.true');
65
+ const red = wrapper.find('.false');
66
66
  const text = wrapper.find('.text');
67
67
 
68
68
  expect(green.exists()).toBe(false);
@@ -73,8 +73,8 @@ describe('BooleanViewField', () => {
73
73
  it('defaults to show red circle', () => {
74
74
  const wrapper = shallow(<BooleanViewField />);
75
75
 
76
- const green = wrapper.find('.green');
77
- const red = wrapper.find('.red');
76
+ const green = wrapper.find('.true');
77
+ const red = wrapper.find('.false');
78
78
 
79
79
  expect(green.exists()).toBe(false);
80
80
  expect(red.exists()).toBe(true);
@@ -31,7 +31,7 @@ export const BooleanViewField: React.FC<BooleanViewFieldProps> = ({
31
31
  dataTestFieldType="BooleanView"
32
32
  >
33
33
  <div className={clsx(classes.value)}>
34
- <div className={clsx(value ? classes.green : classes.red)}></div>
34
+ <div className={clsx(value ? classes.true : classes.false)}></div>
35
35
  <div
36
36
  className={clsx(classes.text)}
37
37
  data-test-id="form-field-value"
@@ -1,9 +1,9 @@
1
1
  import clsx from 'clsx';
2
2
  import React, { useRef, useState } from 'react';
3
3
  import {
4
+ ConfirmDialog,
4
5
  ConfirmationConfig,
5
6
  ConfirmationMode,
6
- ConfirmDialog,
7
7
  } from '../../ConfirmDialog';
8
8
  import { BaseFormControl, BaseInputEvents } from '../Form.models';
9
9
  import { FormElementContainer } from '../FormElementContainer';
@@ -2,12 +2,11 @@ import { useField } from 'formik';
2
2
  import React from 'react';
3
3
  import { useFormikError } from '../useFormikError';
4
4
  import { Checkbox, CheckboxProps } from './Checkbox';
5
- export const CheckboxField: React.FC<Omit<CheckboxProps, 'error'>> = (
6
- props,
7
- ) => {
8
- const { name } = props;
5
+ export const CheckboxField: React.FC<
6
+ Omit<CheckboxProps, 'error' | 'onChange'>
7
+ > = (props) => {
9
8
  const error = useFormikError(props.name);
10
- const [field, , helpers] = useField(name);
9
+ const [field, , helpers] = useField(props.name);
11
10
 
12
11
  return (
13
12
  <Checkbox
@@ -127,7 +127,10 @@
127
127
  stroke: white;
128
128
  }
129
129
 
130
- background-color: $blue;
130
+ background-color: var(
131
+ --tag-plus-button-bg-color,
132
+ $tag-plus-button-bg-color
133
+ );
131
134
  position: absolute;
132
135
  right: 1px;
133
136
  top: 1px;
@@ -146,8 +149,16 @@
146
149
 
147
150
  &:enabled {
148
151
  &:hover {
149
- border: 1px solid $blue;
150
- box-shadow: 0 0 0 2px $blue;
152
+ border: 1px solid
153
+ var(
154
+ --tag-plus-button-hover-stroke-color,
155
+ $tag-plus-button-hover-stroke-color
156
+ );
157
+ box-shadow: 0 0 0 2px
158
+ var(
159
+ --tag-plus-button-hover-stroke-color,
160
+ $tag-plus-button-hover-stroke-color
161
+ );
151
162
 
152
163
  &.hasError {
153
164
  border: 1px solid
@@ -164,7 +175,7 @@
164
175
 
165
176
  .customTagEnter {
166
177
  opacity: 0;
167
- background-color: rgba($blue, 0.25) !important;
178
+ background-color: var(--tag-enter-color, $tag-enter-color) !important;
168
179
  }
169
180
 
170
181
  .customTagEnterActive {
@@ -70,7 +70,7 @@ describe('CustomTags', () => {
70
70
 
71
71
  it('displays a tag for each currently selected tag', () => {
72
72
  const mockCurrentTags = ['1', '2', '3'];
73
- const wrapper = shallow(
73
+ const wrapper = mount(
74
74
  <CustomTags name={'test-name'} value={mockCurrentTags} />,
75
75
  );
76
76
 
@@ -361,7 +361,7 @@ describe('CustomTags', () => {
361
361
  const onChangeSpy = jest.fn();
362
362
  const mockCurrentTags = ['1', '2', '3'];
363
363
  const mockTag = '';
364
- const wrapper = shallow(
364
+ const wrapper = mount(
365
365
  <CustomTags
366
366
  name={'test-name'}
367
367
  onChange={onChangeSpy}
@@ -394,7 +394,7 @@ describe('CustomTags', () => {
394
394
  const onChangeSpy = jest.fn();
395
395
  const mockCurrentTags = ['1', '2', '3'];
396
396
  const mockTag = '2';
397
- const wrapper = shallow(
397
+ const wrapper = mount(
398
398
  <CustomTags
399
399
  name={'test-name'}
400
400
  onChange={onChangeSpy}
@@ -56,7 +56,7 @@ export const CustomTags: React.FC<CustomTagsProps> = ({
56
56
  id,
57
57
  name,
58
58
  type = 'text',
59
- value = [],
59
+ value,
60
60
  disabled = false,
61
61
  placeholder,
62
62
  error = undefined,
@@ -70,12 +70,12 @@ export const CustomTags: React.FC<CustomTagsProps> = ({
70
70
  className = '',
71
71
  ...rest
72
72
  }) => {
73
- const [currentTags, setCurrentTags] = useState<string[]>(value); // Current tags the user has selected
73
+ const [currentTags, setCurrentTags] = useState<string[]>([]); // Current tags the user has selected
74
74
  const [shouldAnimate, setShouldAnimate] = useState<boolean>(false);
75
75
  const ref = useRef<FormEvent<HTMLInputElement>>();
76
76
 
77
77
  useEffect(() => {
78
- setCurrentTags((current) => (current === value ? current : value));
78
+ setCurrentTags(value ?? []);
79
79
  }, [value]);
80
80
 
81
81
  const styles = {
@@ -6,9 +6,8 @@ import { CustomTags, CustomTagsProps } from './CustomTags';
6
6
  export const CustomTagsField: React.FC<
7
7
  Omit<CustomTagsProps, 'error' | 'onChange'>
8
8
  > = (props) => {
9
- const { name } = props;
10
9
  const error = useFormikError(props.name);
11
- const [field, , helpers] = useField(name);
10
+ const [field, , helpers] = useField(props.name);
12
11
 
13
12
  return (
14
13
  <CustomTags
@@ -8,9 +8,9 @@ import { DateTimeText, DateTimeTextProps } from './DateTimeText';
8
8
  * @example
9
9
  * <Field name="title" label="Title" as={DateTimeTextField} />
10
10
  */
11
- export const DateTimeTextField: React.FC<Omit<DateTimeTextProps, 'error'>> = (
12
- props,
13
- ) => {
11
+ export const DateTimeTextField: React.FC<
12
+ Omit<DateTimeTextProps, 'error' | 'onChange'>
13
+ > = (props) => {
14
14
  const error = useFormikError(props.name);
15
15
  const [, meta, helpers] = useField(props.name);
16
16
 
@@ -24,9 +24,8 @@ export const DynamicDataListField = <T extends Data>(
24
24
  Omit<DynamicDataListControlProps<T>, 'error' | 'onChange'>
25
25
  >,
26
26
  ): JSX.Element => {
27
- const { name } = props;
28
27
  const error = useFormikError(props.name);
29
- const [field, , helpers] = useField(name);
28
+ const [field, , helpers] = useField(props.name);
30
29
 
31
30
  return (
32
31
  <DynamicDataListControl
@@ -6,9 +6,8 @@ import { FileUploadControl, FileUploadProps } from './FileUploadControl';
6
6
  export const FileUploadField: React.FC<
7
7
  Omit<FileUploadProps, 'onFileSelected' | 'error'>
8
8
  > = (props) => {
9
- const { name } = props;
10
9
  const error = useFormikError(props.name);
11
- const [field, , helpers] = useField(name);
10
+ const [field, , helpers] = useField(props.name);
12
11
 
13
12
  return (
14
13
  <FileUploadControl
@@ -19,7 +19,6 @@
19
19
  font-size: var(--label-font-size, $label-font-size);
20
20
  color: var(--input-color, $input-color);
21
21
  max-width: 100%;
22
- overflow: auto;
23
22
  }
24
23
 
25
24
  .label {
@@ -17,7 +17,7 @@ import {
17
17
  placeholderChar={'0'}, />
18
18
  */
19
19
  export const MaskedSingleLineTextField: React.FC<
20
- Omit<MaskedSingleLineTextProps, 'error'>
20
+ Omit<MaskedSingleLineTextProps, 'error' | 'onChange'>
21
21
  > = (props) => {
22
22
  const error = useFormikError(props.name);
23
23