@axinom/mosaic-ui 0.56.0-rc.5 → 0.56.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.
- package/dist/components/Accordion/Accordion.d.ts.map +1 -1
- package/dist/components/Accordion/AccordionItem/AccordionItem.d.ts.map +1 -1
- package/dist/components/DynamicDataList/DynamicListDataEntry/DynamicListDataEntry.d.ts.map +1 -1
- package/dist/components/FormElements/BooleanView/BooleanViewField.d.ts.map +1 -1
- package/dist/components/FormElements/Checkbox/Checkbox.d.ts.map +1 -1
- package/dist/components/FormElements/CustomTags/CustomTags.d.ts.map +1 -1
- package/dist/components/FormElements/DateTimeField/DateTimeText.d.ts.map +1 -1
- package/dist/components/FormElements/DynamicDataListControl/DynamicDataListControl.d.ts.map +1 -1
- package/dist/components/FormElements/FormElementContainer/FormElementContainer.d.ts +2 -0
- package/dist/components/FormElements/FormElementContainer/FormElementContainer.d.ts.map +1 -1
- package/dist/components/FormElements/ReadOnlyText/ReadOnlyTextField.d.ts +1 -1
- package/dist/components/FormElements/ReadOnlyText/ReadOnlyTextField.d.ts.map +1 -1
- package/dist/components/FormElements/Select/Select.d.ts.map +1 -1
- package/dist/components/FormElements/SingleLineText/SingleLineText.d.ts.map +1 -1
- package/dist/components/FormElements/Tags/Tags.d.ts.map +1 -1
- package/dist/components/FormElements/TextArea/TextArea.d.ts.map +1 -1
- package/dist/components/FormElements/ToggleButton/ToggleButton.d.ts.map +1 -1
- package/dist/index.es.js +4 -4
- package/dist/index.es.js.map +1 -1
- package/dist/index.js +4 -4
- package/dist/index.js.map +1 -1
- package/package.json +5 -4
- package/src/components/Accordion/Accordion.scss +5 -0
- package/src/components/Accordion/Accordion.spec.tsx +5 -2
- package/src/components/Accordion/Accordion.tsx +4 -6
- package/src/components/Accordion/AccordionItem/AccordionItem.scss +7 -2
- package/src/components/Accordion/AccordionItem/AccordionItem.tsx +4 -2
- package/src/components/DynamicDataList/DynamicListDataEntry/DynamicListDataEntry.spec.tsx +24 -24
- package/src/components/DynamicDataList/DynamicListDataEntry/DynamicListDataEntry.tsx +32 -33
- package/src/components/FormElements/BooleanView/BooleanViewField.spec.tsx +4 -4
- package/src/components/FormElements/BooleanView/BooleanViewField.tsx +1 -5
- package/src/components/FormElements/Checkbox/Checkbox.stories.tsx +2 -2
- package/src/components/FormElements/Checkbox/Checkbox.tsx +2 -1
- package/src/components/FormElements/CustomTags/CustomTags.scss +2 -1
- package/src/components/FormElements/CustomTags/CustomTags.tsx +5 -2
- package/src/components/FormElements/DateTimeField/DateTimeText.stories.tsx +2 -2
- package/src/components/FormElements/DateTimeField/DateTimeText.tsx +2 -1
- package/src/components/FormElements/DynamicDataListControl/DynamicDataListControl.tsx +1 -0
- package/src/components/FormElements/FileUploadControl/FileUploadControl.tsx +2 -2
- package/src/components/FormElements/FormElementContainer/FormElementContainer.tsx +5 -1
- package/src/components/FormElements/ReadOnlyText/ReadOnlyTextField.tsx +3 -0
- package/src/components/FormElements/Select/Select.tsx +2 -1
- package/src/components/FormElements/SingleLineText/SingleLineText.tsx +2 -1
- package/src/components/FormElements/Tags/Tags.tsx +2 -1
- package/src/components/FormElements/TextArea/TextArea.tsx +2 -1
- package/src/components/FormElements/ToggleButton/ToggleButton.stories.tsx +1 -1
- package/src/components/FormElements/ToggleButton/ToggleButton.tsx +2 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@axinom/mosaic-ui",
|
|
3
|
-
"version": "0.56.0
|
|
3
|
+
"version": "0.56.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.29
|
|
35
|
+
"@axinom/mosaic-core": "^0.4.29",
|
|
36
36
|
"@faker-js/faker": "^7.4.0",
|
|
37
37
|
"@geoffcox/react-splitter": "^2.1.2",
|
|
38
38
|
"@mui/base": "5.0.0-beta.40",
|
|
@@ -40,6 +40,7 @@
|
|
|
40
40
|
"clsx": "^1.1.0",
|
|
41
41
|
"lodash": "^4.17.21",
|
|
42
42
|
"luxon": "^3.3.0",
|
|
43
|
+
"postcss": "^8.4.4",
|
|
43
44
|
"react-beautiful-dnd": "^13.1.1",
|
|
44
45
|
"react-calendar": "^3.3.1",
|
|
45
46
|
"react-content-loader": "^6.0.3",
|
|
@@ -93,7 +94,7 @@
|
|
|
93
94
|
"rimraf": "^3.0.2",
|
|
94
95
|
"rollup": "^2.28.1",
|
|
95
96
|
"rollup-plugin-peer-deps-external": "^2.2.3",
|
|
96
|
-
"rollup-plugin-postcss": "^
|
|
97
|
+
"rollup-plugin-postcss": "^4.0.2",
|
|
97
98
|
"rollup-plugin-terser": "^5.3.1",
|
|
98
99
|
"rollup-plugin-typescript2": "^0.29.0",
|
|
99
100
|
"rollup-plugin-visualizer": "^5.8.3",
|
|
@@ -107,5 +108,5 @@
|
|
|
107
108
|
"publishConfig": {
|
|
108
109
|
"access": "public"
|
|
109
110
|
},
|
|
110
|
-
"gitHead": "
|
|
111
|
+
"gitHead": "c3802f0be74822f25268d4fdf7497a1c1577309d"
|
|
111
112
|
}
|
|
@@ -85,7 +85,7 @@ describe('Accordion', () => {
|
|
|
85
85
|
});
|
|
86
86
|
});
|
|
87
87
|
|
|
88
|
-
it('displays
|
|
88
|
+
it('displays rotated ChevronRight icon when one or more children are expanded', () => {
|
|
89
89
|
const wrapper = mount(
|
|
90
90
|
<Accordion header={<b>Header</b>}>
|
|
91
91
|
<AccordionItem header={<b>Item 1</b>}>
|
|
@@ -103,6 +103,7 @@ describe('Accordion', () => {
|
|
|
103
103
|
let button = wrapper.find(Button).first();
|
|
104
104
|
|
|
105
105
|
expect(button.prop('icon')).toBe(IconName.ChevronRight);
|
|
106
|
+
expect(button.hasClass('rotated')).toBe(false);
|
|
106
107
|
|
|
107
108
|
const item = wrapper.find(AccordionItem).last();
|
|
108
109
|
|
|
@@ -110,12 +111,14 @@ describe('Accordion', () => {
|
|
|
110
111
|
|
|
111
112
|
button = wrapper.find(Button).first();
|
|
112
113
|
|
|
113
|
-
expect(button.prop('icon')).toBe(IconName.
|
|
114
|
+
expect(button.prop('icon')).toBe(IconName.ChevronRight);
|
|
115
|
+
expect(button.hasClass('rotated')).toBe(true);
|
|
114
116
|
|
|
115
117
|
item.find('button').simulate('click');
|
|
116
118
|
|
|
117
119
|
button = wrapper.find(Button).first();
|
|
118
120
|
|
|
119
121
|
expect(button.prop('icon')).toBe(IconName.ChevronRight);
|
|
122
|
+
expect(button.hasClass('rotated')).toBe(false);
|
|
120
123
|
});
|
|
121
124
|
});
|
|
@@ -95,11 +95,7 @@ export const Accordion: React.FC<AccordionProps> = ({
|
|
|
95
95
|
{header && (
|
|
96
96
|
<div className={clsx(classes.header)} data-test-id="accordion-header">
|
|
97
97
|
<Button
|
|
98
|
-
icon={
|
|
99
|
-
expandAll.isExpanded
|
|
100
|
-
? IconName.ChevronDown
|
|
101
|
-
: IconName.ChevronRight
|
|
102
|
-
}
|
|
98
|
+
icon={IconName.ChevronRight}
|
|
103
99
|
onButtonClicked={() => {
|
|
104
100
|
const updatedState = { ...expanded };
|
|
105
101
|
|
|
@@ -110,7 +106,9 @@ export const Accordion: React.FC<AccordionProps> = ({
|
|
|
110
106
|
setExpanded(updatedState);
|
|
111
107
|
expandAll.toggleExpanded();
|
|
112
108
|
}}
|
|
113
|
-
className={clsx(classes.button
|
|
109
|
+
className={clsx(classes.button, {
|
|
110
|
+
[classes.rotated]: expandAll.isExpanded,
|
|
111
|
+
})}
|
|
114
112
|
buttonContext={ButtonContext.None}
|
|
115
113
|
></Button>
|
|
116
114
|
{header}
|
|
@@ -6,10 +6,10 @@
|
|
|
6
6
|
align-items: center;
|
|
7
7
|
background-color: $light-gray;
|
|
8
8
|
margin-top: 4px;
|
|
9
|
-
transition: box-shadow 0.15s ease-in-out 0s;
|
|
10
9
|
height: 50px;
|
|
11
10
|
cursor: pointer;
|
|
12
11
|
color: var(--accordion-item-text-color, $accordion-item-text-color);
|
|
12
|
+
transition: background-color 200ms cubic-bezier(0.4, 0, 0.2, 1) 0s;
|
|
13
13
|
|
|
14
14
|
&:hover {
|
|
15
15
|
background-color: var(
|
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
|
|
31
31
|
.container {
|
|
32
32
|
overflow: hidden;
|
|
33
|
-
transition: max-height
|
|
33
|
+
transition: max-height 200ms cubic-bezier(0.4, 0, 0.2, 1);
|
|
34
34
|
}
|
|
35
35
|
|
|
36
36
|
.expanded {
|
|
@@ -52,9 +52,14 @@
|
|
|
52
52
|
.button {
|
|
53
53
|
svg {
|
|
54
54
|
height: 40%;
|
|
55
|
+
transition: transform 200ms cubic-bezier(0.4, 0, 0.2, 1);
|
|
55
56
|
}
|
|
56
57
|
|
|
57
58
|
svg * {
|
|
58
59
|
stroke: var(--accordion-item-arrow-color, $accordion-item-arrow-color);
|
|
59
60
|
}
|
|
61
|
+
|
|
62
|
+
&.rotated > svg {
|
|
63
|
+
transform: rotate(90deg);
|
|
64
|
+
}
|
|
60
65
|
}
|
|
@@ -62,8 +62,10 @@ export const AccordionItem: React.FC<AccordionItemProps> = ({
|
|
|
62
62
|
onClick={toggleExpanded}
|
|
63
63
|
>
|
|
64
64
|
<Button
|
|
65
|
-
icon={
|
|
66
|
-
className={classes.button
|
|
65
|
+
icon={IconName.ChevronRight}
|
|
66
|
+
className={clsx(classes.button, {
|
|
67
|
+
[classes.rotated]: isExpanded,
|
|
68
|
+
})}
|
|
67
69
|
buttonContext={ButtonContext.None}
|
|
68
70
|
/>
|
|
69
71
|
{header}
|
|
@@ -261,7 +261,7 @@ describe('DynamicListDataEntry', () => {
|
|
|
261
261
|
expect(input.prop('disabled')).toBe(true);
|
|
262
262
|
});
|
|
263
263
|
|
|
264
|
-
it('accepts default values and sets them', () => {
|
|
264
|
+
it('accepts default values and sets them', async () => {
|
|
265
265
|
const defaultData: Partial<TestData> = {
|
|
266
266
|
desc: 'Description',
|
|
267
267
|
};
|
|
@@ -280,15 +280,15 @@ describe('DynamicListDataEntry', () => {
|
|
|
280
280
|
|
|
281
281
|
const button = wrapper.find(Button);
|
|
282
282
|
|
|
283
|
-
act(() => {
|
|
283
|
+
await act(async () => {
|
|
284
284
|
// @ts-expect-error not full event args object
|
|
285
|
-
button.prop('onButtonClicked')?.(mockEvent);
|
|
285
|
+
await button.prop('onButtonClicked')?.(mockEvent);
|
|
286
286
|
});
|
|
287
287
|
|
|
288
288
|
expect(spy).toHaveBeenCalledWith(defaultData);
|
|
289
289
|
});
|
|
290
290
|
|
|
291
|
-
it(`does not emit onActionClicked if data is invalid`, () => {
|
|
291
|
+
it(`does not emit onActionClicked if data is invalid`, async () => {
|
|
292
292
|
const spy = jest.fn();
|
|
293
293
|
const mockEvent = {
|
|
294
294
|
e: 'event',
|
|
@@ -307,15 +307,15 @@ describe('DynamicListDataEntry', () => {
|
|
|
307
307
|
|
|
308
308
|
const button = wrapper.find(Button);
|
|
309
309
|
|
|
310
|
-
act(() => {
|
|
310
|
+
await act(async () => {
|
|
311
311
|
// @ts-expect-error not full event args object
|
|
312
|
-
button.prop('onButtonClicked')?.(mockEvent);
|
|
312
|
+
await button.prop('onButtonClicked')?.(mockEvent);
|
|
313
313
|
});
|
|
314
314
|
|
|
315
315
|
expect(spy).not.toHaveBeenCalled();
|
|
316
316
|
});
|
|
317
317
|
|
|
318
|
-
it(`emits onActionClicked with property name and new value if there is data to send`, () => {
|
|
318
|
+
it(`emits onActionClicked with property name and new value if there is data to send`, async () => {
|
|
319
319
|
const spy = jest.fn();
|
|
320
320
|
const mockNewValue = 'test-value';
|
|
321
321
|
const mockEvent = {
|
|
@@ -341,16 +341,16 @@ describe('DynamicListDataEntry', () => {
|
|
|
341
341
|
|
|
342
342
|
const button = wrapper.find(Button);
|
|
343
343
|
|
|
344
|
-
act(() => {
|
|
344
|
+
await act(async () => {
|
|
345
345
|
// @ts-expect-error not full event args object
|
|
346
|
-
button.prop('onButtonClicked')?.(mockEvent);
|
|
346
|
+
await button.prop('onButtonClicked')?.(mockEvent);
|
|
347
347
|
});
|
|
348
348
|
|
|
349
349
|
expect(spy).toHaveBeenCalledTimes(1);
|
|
350
350
|
expect(spy).toHaveBeenCalledWith({ [propertyName]: mockNewValue });
|
|
351
351
|
});
|
|
352
352
|
|
|
353
|
-
it(`emits row data and new position when 'allowReordering' is true, 'newDataPosition' is defined, and is 'positionKey' is defined`, () => {
|
|
353
|
+
it(`emits row data and new position when 'allowReordering' is true, 'newDataPosition' is defined, and is 'positionKey' is defined`, async () => {
|
|
354
354
|
const spy = jest.fn();
|
|
355
355
|
const mockEvent = {
|
|
356
356
|
e: 'event',
|
|
@@ -381,9 +381,9 @@ describe('DynamicListDataEntry', () => {
|
|
|
381
381
|
|
|
382
382
|
const button = wrapper.find(Button);
|
|
383
383
|
|
|
384
|
-
act(() => {
|
|
384
|
+
await act(async () => {
|
|
385
385
|
// @ts-expect-error not full event args object
|
|
386
|
-
button.prop('onButtonClicked')?.(mockEvent);
|
|
386
|
+
await button.prop('onButtonClicked')?.(mockEvent);
|
|
387
387
|
});
|
|
388
388
|
|
|
389
389
|
expect(spy).toHaveBeenCalledTimes(1);
|
|
@@ -393,7 +393,7 @@ describe('DynamicListDataEntry', () => {
|
|
|
393
393
|
});
|
|
394
394
|
});
|
|
395
395
|
|
|
396
|
-
it(`emits only row data when 'allowReordering' is false, 'newDataPosition' is defined, and is 'positionKey' is defined`, () => {
|
|
396
|
+
it(`emits only row data when 'allowReordering' is false, 'newDataPosition' is defined, and is 'positionKey' is defined`, async () => {
|
|
397
397
|
const spy = jest.fn();
|
|
398
398
|
const mockEvent = {
|
|
399
399
|
e: 'event',
|
|
@@ -423,9 +423,9 @@ describe('DynamicListDataEntry', () => {
|
|
|
423
423
|
|
|
424
424
|
const button = wrapper.find(Button);
|
|
425
425
|
|
|
426
|
-
act(() => {
|
|
426
|
+
await act(async () => {
|
|
427
427
|
// @ts-expect-error not full event args object
|
|
428
|
-
button.prop('onButtonClicked')?.(mockEvent);
|
|
428
|
+
await button.prop('onButtonClicked')?.(mockEvent);
|
|
429
429
|
});
|
|
430
430
|
|
|
431
431
|
expect(spy).toHaveBeenCalledTimes(1);
|
|
@@ -434,7 +434,7 @@ describe('DynamicListDataEntry', () => {
|
|
|
434
434
|
});
|
|
435
435
|
});
|
|
436
436
|
|
|
437
|
-
it(`emits only row data when 'allowReordering' is true, 'newDataPosition' is undefined, and is 'positionKey' is defined`, () => {
|
|
437
|
+
it(`emits only row data when 'allowReordering' is true, 'newDataPosition' is undefined, and is 'positionKey' is defined`, async () => {
|
|
438
438
|
const spy = jest.fn();
|
|
439
439
|
const mockEvent = {
|
|
440
440
|
e: 'event',
|
|
@@ -464,9 +464,9 @@ describe('DynamicListDataEntry', () => {
|
|
|
464
464
|
|
|
465
465
|
const button = wrapper.find(Button);
|
|
466
466
|
|
|
467
|
-
act(() => {
|
|
467
|
+
await act(async () => {
|
|
468
468
|
// @ts-expect-error not full event args object
|
|
469
|
-
button.prop('onButtonClicked')?.(mockEvent);
|
|
469
|
+
await button.prop('onButtonClicked')?.(mockEvent);
|
|
470
470
|
});
|
|
471
471
|
|
|
472
472
|
expect(spy).toHaveBeenCalledTimes(1);
|
|
@@ -475,7 +475,7 @@ describe('DynamicListDataEntry', () => {
|
|
|
475
475
|
});
|
|
476
476
|
});
|
|
477
477
|
|
|
478
|
-
it(`emits only row data when 'allowReordering' is true, 'newDataPosition' is defined, and is 'positionKey' is undefined`, () => {
|
|
478
|
+
it(`emits only row data when 'allowReordering' is true, 'newDataPosition' is defined, and is 'positionKey' is undefined`, async () => {
|
|
479
479
|
const spy = jest.fn();
|
|
480
480
|
const mockEvent = {
|
|
481
481
|
e: 'event',
|
|
@@ -504,9 +504,9 @@ describe('DynamicListDataEntry', () => {
|
|
|
504
504
|
|
|
505
505
|
const button = wrapper.find(Button);
|
|
506
506
|
|
|
507
|
-
act(() => {
|
|
507
|
+
await act(async () => {
|
|
508
508
|
// @ts-expect-error not full event args object
|
|
509
|
-
button.prop('onButtonClicked')?.(mockEvent);
|
|
509
|
+
await button.prop('onButtonClicked')?.(mockEvent);
|
|
510
510
|
});
|
|
511
511
|
|
|
512
512
|
expect(spy).toHaveBeenCalledTimes(1);
|
|
@@ -515,7 +515,7 @@ describe('DynamicListDataEntry', () => {
|
|
|
515
515
|
});
|
|
516
516
|
});
|
|
517
517
|
|
|
518
|
-
it(`transform property if 'onAddTransformer' is set as a column option`, () => {
|
|
518
|
+
it(`transform property if 'onAddTransformer' is set as a column option`, async () => {
|
|
519
519
|
const spy = jest.fn();
|
|
520
520
|
const mockNewValue = 'test-value1';
|
|
521
521
|
const mockEvent = {
|
|
@@ -550,9 +550,9 @@ describe('DynamicListDataEntry', () => {
|
|
|
550
550
|
|
|
551
551
|
const button = wrapper.find(Button);
|
|
552
552
|
|
|
553
|
-
act(() => {
|
|
553
|
+
await act(async () => {
|
|
554
554
|
// @ts-expect-error not full event args object
|
|
555
|
-
button.prop('onButtonClicked')?.(mockEvent);
|
|
555
|
+
await button.prop('onButtonClicked')?.(mockEvent);
|
|
556
556
|
});
|
|
557
557
|
|
|
558
558
|
expect(spy).toHaveBeenCalledTimes(1);
|
|
@@ -1,10 +1,5 @@
|
|
|
1
1
|
import clsx from 'clsx';
|
|
2
|
-
import React, {
|
|
3
|
-
PropsWithChildren,
|
|
4
|
-
ReactElement,
|
|
5
|
-
useEffect,
|
|
6
|
-
useState,
|
|
7
|
-
} from 'react';
|
|
2
|
+
import React, { PropsWithChildren, ReactElement, useState } from 'react';
|
|
8
3
|
import { ValidationError } from 'yup';
|
|
9
4
|
import { OptionalObjectSchema } from 'yup/lib/object';
|
|
10
5
|
import { noop } from '../../../helpers/utils';
|
|
@@ -110,27 +105,29 @@ export const DynamicListDataEntry = <T extends Data>({
|
|
|
110
105
|
const [isDirty, setIsDirty] = useState<boolean>(false);
|
|
111
106
|
const [error, setError] = useState<Record<string, string>>({});
|
|
112
107
|
|
|
113
|
-
|
|
114
|
-
if (rowValidationSchema
|
|
115
|
-
|
|
116
|
-
?.validate(state, { abortEarly: false })
|
|
117
|
-
.then(() => {
|
|
118
|
-
setError({});
|
|
119
|
-
})
|
|
120
|
-
.catch((e: ValidationError) => {
|
|
121
|
-
const newErrors: Record<string, string> = {};
|
|
122
|
-
e.inner.forEach((validationError) => {
|
|
123
|
-
if (validationError.path !== undefined) {
|
|
124
|
-
const path = validationError.path;
|
|
125
|
-
if (newErrors?.[path] === undefined) {
|
|
126
|
-
newErrors[path] = validationError.message;
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
});
|
|
130
|
-
setError(newErrors);
|
|
131
|
-
});
|
|
108
|
+
const validateSchema = async (data: T): Promise<boolean> => {
|
|
109
|
+
if (!rowValidationSchema) {
|
|
110
|
+
return true;
|
|
132
111
|
}
|
|
133
|
-
|
|
112
|
+
|
|
113
|
+
try {
|
|
114
|
+
await rowValidationSchema.validate(data, { abortEarly: false });
|
|
115
|
+
setError({});
|
|
116
|
+
|
|
117
|
+
return true;
|
|
118
|
+
} catch (e) {
|
|
119
|
+
const newErrors: Record<string, string> = {};
|
|
120
|
+
(e as ValidationError).inner.forEach((validationError) => {
|
|
121
|
+
const path = validationError.path;
|
|
122
|
+
if (path !== undefined && newErrors?.[path] === undefined) {
|
|
123
|
+
newErrors[path] = validationError.message;
|
|
124
|
+
}
|
|
125
|
+
});
|
|
126
|
+
setError(newErrors);
|
|
127
|
+
|
|
128
|
+
return false;
|
|
129
|
+
}
|
|
130
|
+
};
|
|
134
131
|
|
|
135
132
|
/**
|
|
136
133
|
* Updates new data object with supplied key/value pair
|
|
@@ -138,10 +135,12 @@ export const DynamicListDataEntry = <T extends Data>({
|
|
|
138
135
|
* @param value new value
|
|
139
136
|
*/
|
|
140
137
|
const valueChangedHandler = (property: keyof T, value: unknown): void => {
|
|
138
|
+
const newState = { ...state, [property]: value };
|
|
139
|
+
|
|
141
140
|
setIsDirty(true);
|
|
142
|
-
setState(
|
|
143
|
-
|
|
144
|
-
|
|
141
|
+
setState(newState);
|
|
142
|
+
|
|
143
|
+
validateSchema(newState);
|
|
145
144
|
};
|
|
146
145
|
|
|
147
146
|
/**
|
|
@@ -149,11 +148,11 @@ export const DynamicListDataEntry = <T extends Data>({
|
|
|
149
148
|
* @param data T
|
|
150
149
|
*/
|
|
151
150
|
const onAddItemHandler = async (): Promise<void> => {
|
|
152
|
-
|
|
153
|
-
|
|
151
|
+
const isValid = await validateSchema(state);
|
|
152
|
+
|
|
153
|
+
if (!isValid) {
|
|
154
154
|
setIsDirty(true);
|
|
155
|
-
|
|
156
|
-
return console.warn('Data not valid');
|
|
155
|
+
return;
|
|
157
156
|
}
|
|
158
157
|
|
|
159
158
|
let transformedState: T = state;
|
|
@@ -20,11 +20,11 @@ describe('BooleanViewField', () => {
|
|
|
20
20
|
|
|
21
21
|
it('displays default true, false label values', () => {
|
|
22
22
|
const wrapper1 = shallow(<BooleanViewField value={true} />);
|
|
23
|
-
const text1 = wrapper1.find('
|
|
23
|
+
const text1 = wrapper1.find('[data-test-id="form-field-value"]');
|
|
24
24
|
expect(text1.text()).toBe('True');
|
|
25
25
|
|
|
26
26
|
const wrapper2 = shallow(<BooleanViewField value={false} />);
|
|
27
|
-
const text2 = wrapper2.find('
|
|
27
|
+
const text2 = wrapper2.find('[data-test-id="form-field-value"]');
|
|
28
28
|
expect(text2.text()).toBe('False');
|
|
29
29
|
});
|
|
30
30
|
|
|
@@ -42,7 +42,7 @@ describe('BooleanViewField', () => {
|
|
|
42
42
|
|
|
43
43
|
const green = wrapper.find('.true');
|
|
44
44
|
const red = wrapper.find('.false');
|
|
45
|
-
const text = wrapper.find('
|
|
45
|
+
const text = wrapper.find('[data-test-id="form-field-value"]');
|
|
46
46
|
|
|
47
47
|
expect(green.exists()).toBe(true);
|
|
48
48
|
expect(red.exists()).toBe(false);
|
|
@@ -63,7 +63,7 @@ describe('BooleanViewField', () => {
|
|
|
63
63
|
|
|
64
64
|
const green = wrapper.find('.true');
|
|
65
65
|
const red = wrapper.find('.false');
|
|
66
|
-
const text = wrapper.find('
|
|
66
|
+
const text = wrapper.find('[data-test-id="form-field-value"]');
|
|
67
67
|
|
|
68
68
|
expect(green.exists()).toBe(false);
|
|
69
69
|
expect(red.exists()).toBe(true);
|
|
@@ -32,11 +32,7 @@ export const BooleanViewField: React.FC<BooleanViewFieldProps> = ({
|
|
|
32
32
|
>
|
|
33
33
|
<div className={clsx(classes.value)}>
|
|
34
34
|
<div className={clsx(value ? classes.true : classes.false)}></div>
|
|
35
|
-
<div
|
|
36
|
-
className={clsx(classes.text)}
|
|
37
|
-
data-test-id="form-field-value"
|
|
38
|
-
data-test-value={value}
|
|
39
|
-
>
|
|
35
|
+
<div data-test-id="form-field-value" data-test-value={value}>
|
|
40
36
|
{value ? trueLabel : falseLabel}
|
|
41
37
|
</div>
|
|
42
38
|
</div>
|
|
@@ -31,9 +31,9 @@ export default meta;
|
|
|
31
31
|
|
|
32
32
|
export const Main: StoryObj<typeof Checkbox> = {
|
|
33
33
|
args: {
|
|
34
|
-
label: '
|
|
34
|
+
label: 'Is Active?',
|
|
35
35
|
tooltipContent: faker.lorem.paragraph(2),
|
|
36
|
-
name: '
|
|
36
|
+
name: 'isActive',
|
|
37
37
|
},
|
|
38
38
|
render: (args) =>
|
|
39
39
|
React.createElement(() => {
|
|
@@ -65,9 +65,10 @@ export const Checkbox: React.FC<CheckboxProps> = ({
|
|
|
65
65
|
className={clsx(classes.container, 'checkbox-container', className)}
|
|
66
66
|
error={errorMsg}
|
|
67
67
|
dataTestFieldType="Checkbox"
|
|
68
|
+
htmlFor={id ?? name}
|
|
68
69
|
>
|
|
69
70
|
<input
|
|
70
|
-
id={id}
|
|
71
|
+
id={id ?? name}
|
|
71
72
|
name={name}
|
|
72
73
|
ref={setReferenceElement as React.LegacyRef<HTMLInputElement>}
|
|
73
74
|
type="checkbox"
|
|
@@ -295,6 +295,7 @@ export const CustomTags: React.FC<CustomTagsProps> = ({
|
|
|
295
295
|
className={clsx(classes.container, 'custom-tags-container', className)}
|
|
296
296
|
error={errorMessage}
|
|
297
297
|
dataTestFieldType="CustomTags"
|
|
298
|
+
htmlFor={id ?? name}
|
|
298
299
|
>
|
|
299
300
|
<div className={clsx(classes.tagsWrapper)} style={styles}>
|
|
300
301
|
<div className={clsx(classes.inputWrapper)}>
|
|
@@ -302,7 +303,7 @@ export const CustomTags: React.FC<CustomTagsProps> = ({
|
|
|
302
303
|
className={clsx({
|
|
303
304
|
[classes.hasError]: errorMessage !== undefined,
|
|
304
305
|
})}
|
|
305
|
-
id={id}
|
|
306
|
+
id={id ?? name}
|
|
306
307
|
name={name}
|
|
307
308
|
ref={textInput}
|
|
308
309
|
value={val}
|
|
@@ -324,7 +325,9 @@ export const CustomTags: React.FC<CustomTagsProps> = ({
|
|
|
324
325
|
onMouseDown={(event) =>
|
|
325
326
|
onSuggestionClickedHandler(event, suggestion)
|
|
326
327
|
}
|
|
327
|
-
className={clsx({
|
|
328
|
+
className={clsx({
|
|
329
|
+
[classes.selected]: cursorPos === idx,
|
|
330
|
+
})}
|
|
328
331
|
>
|
|
329
332
|
{suggestion}
|
|
330
333
|
</li>
|
|
@@ -89,11 +89,12 @@ export const DateTimeText: React.FC<DateTimeTextProps> = ({
|
|
|
89
89
|
className={clsx(classes.container, 'datetime-container', className)}
|
|
90
90
|
error={errorMsg}
|
|
91
91
|
dataTestFieldType="DateTime"
|
|
92
|
+
htmlFor={id ?? name}
|
|
92
93
|
>
|
|
93
94
|
<div className={clsx(classes.inputbutton)} ref={container}>
|
|
94
95
|
<input
|
|
95
96
|
className={clsx({ [classes.hasError]: errorMsg })}
|
|
96
|
-
id={id}
|
|
97
|
+
id={id ?? name}
|
|
97
98
|
name={name}
|
|
98
99
|
type={'text'}
|
|
99
100
|
value={display}
|
|
@@ -30,6 +30,7 @@ export const DynamicDataListControl = <T extends Data>({
|
|
|
30
30
|
{...rest}
|
|
31
31
|
className={clsx('dynamic-data-list-control-container', className)}
|
|
32
32
|
dataTestFieldType="DynamicDataListControl"
|
|
33
|
+
htmlFor={rest.id ?? rest.name}
|
|
33
34
|
>
|
|
34
35
|
<DynamicDataList {...rest} />
|
|
35
36
|
</FormElementContainer>
|
|
@@ -134,6 +134,7 @@ export const FileUploadControl: React.FC<FileUploadProps> = ({
|
|
|
134
134
|
)}
|
|
135
135
|
error={error}
|
|
136
136
|
dataTestFieldType="FileUpload"
|
|
137
|
+
htmlFor={id ?? name}
|
|
137
138
|
>
|
|
138
139
|
<div className={clsx(classes.content)}>
|
|
139
140
|
{dragging && !disabled ? (
|
|
@@ -157,12 +158,11 @@ export const FileUploadControl: React.FC<FileUploadProps> = ({
|
|
|
157
158
|
[classes.fileuploadbutton]: true,
|
|
158
159
|
[classes.disabled]: disabled,
|
|
159
160
|
})}
|
|
160
|
-
htmlFor={id}
|
|
161
161
|
>
|
|
162
162
|
<Icons icon={IconName.File} />
|
|
163
163
|
</label>
|
|
164
164
|
<input
|
|
165
|
-
id={id}
|
|
165
|
+
id={id ?? name}
|
|
166
166
|
type="file"
|
|
167
167
|
accept={accept}
|
|
168
168
|
disabled={disabled}
|
|
@@ -16,6 +16,9 @@ export type FormElementContainerProps = BaseFormElement & {
|
|
|
16
16
|
|
|
17
17
|
/** Stick to the top option */
|
|
18
18
|
stickyLabel?: boolean;
|
|
19
|
+
|
|
20
|
+
/** The value of the 'for' attribute of the label */
|
|
21
|
+
htmlFor?: string;
|
|
19
22
|
};
|
|
20
23
|
|
|
21
24
|
/**
|
|
@@ -35,6 +38,7 @@ export const FormElementContainer: React.FC<FormElementContainerProps> = ({
|
|
|
35
38
|
dataTestFieldType,
|
|
36
39
|
inlineMode = false,
|
|
37
40
|
stickyLabel = true,
|
|
41
|
+
htmlFor,
|
|
38
42
|
}) => {
|
|
39
43
|
const heightStyles: CSSProperties = {};
|
|
40
44
|
|
|
@@ -63,7 +67,7 @@ export const FormElementContainer: React.FC<FormElementContainerProps> = ({
|
|
|
63
67
|
)}
|
|
64
68
|
style={heightStyles}
|
|
65
69
|
>
|
|
66
|
-
<label data-test-id="form-field-label">
|
|
70
|
+
<label data-test-id="form-field-label" htmlFor={htmlFor}>
|
|
67
71
|
{label}
|
|
68
72
|
{tooltipContent && (
|
|
69
73
|
<InfoTooltip className={clsx(classes.tooltip)}>
|
|
@@ -27,6 +27,7 @@ export const ReadOnlyTextField = <T,>({
|
|
|
27
27
|
transform,
|
|
28
28
|
className = '',
|
|
29
29
|
hideCopyButton = false,
|
|
30
|
+
id,
|
|
30
31
|
...rest
|
|
31
32
|
}: PropsWithChildren<ReadOnlyTextFieldProps<T>>): JSX.Element => {
|
|
32
33
|
const nonNullableValue = value === null ? '' : value;
|
|
@@ -42,12 +43,14 @@ export const ReadOnlyTextField = <T,>({
|
|
|
42
43
|
{...rest}
|
|
43
44
|
className={clsx('read-only-field-container', className)}
|
|
44
45
|
dataTestFieldType="ReadOnlyText"
|
|
46
|
+
htmlFor={id}
|
|
45
47
|
>
|
|
46
48
|
<div className={clsx(classes.container)}>
|
|
47
49
|
<input
|
|
48
50
|
value={displayValue}
|
|
49
51
|
onChange={noop}
|
|
50
52
|
data-test-id="form-field-value"
|
|
53
|
+
id={id}
|
|
51
54
|
/>
|
|
52
55
|
{!hideCopyButton && (
|
|
53
56
|
<Button
|
|
@@ -86,13 +86,13 @@ export const Select: React.FC<SelectProps> = (props) => {
|
|
|
86
86
|
|
|
87
87
|
return (
|
|
88
88
|
<FormElementContainer
|
|
89
|
-
id={id}
|
|
90
89
|
label={label}
|
|
91
90
|
tooltipContent={tooltipContent}
|
|
92
91
|
inlineMode={inlineMode}
|
|
93
92
|
className={clsx(classes.container, 'select-container', className)}
|
|
94
93
|
error={error}
|
|
95
94
|
dataTestFieldType="Select"
|
|
95
|
+
htmlFor={id ?? name}
|
|
96
96
|
>
|
|
97
97
|
<div
|
|
98
98
|
ref={setAnchorEl}
|
|
@@ -101,6 +101,7 @@ export const Select: React.FC<SelectProps> = (props) => {
|
|
|
101
101
|
>
|
|
102
102
|
<input
|
|
103
103
|
{...getInputProps()}
|
|
104
|
+
id={id ?? name}
|
|
104
105
|
name={name}
|
|
105
106
|
className={clsx({ [classes.hasError]: Boolean(error) })}
|
|
106
107
|
autoFocus={autoFocus}
|