@abgov/jsonforms-components 0.0.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 (75) hide show
  1. package/.babelrc +12 -0
  2. package/.eslintrc.json +36 -0
  3. package/.releaserc.json +25 -0
  4. package/README.md +251 -0
  5. package/jest.config.ts +11 -0
  6. package/package.json +17 -0
  7. package/project.json +55 -0
  8. package/rollup.config.js +14 -0
  9. package/src/index.ts +166 -0
  10. package/src/lib/Additional/HelpContent.tsx +95 -0
  11. package/src/lib/Additional/index.ts +1 -0
  12. package/src/lib/Additional/styled-components.ts +27 -0
  13. package/src/lib/Cells/DateCell.tsx +10 -0
  14. package/src/lib/Cells/IntegerCell.tsx +10 -0
  15. package/src/lib/Cells/NumberCell.tsx +10 -0
  16. package/src/lib/Cells/TextCell.tsx +10 -0
  17. package/src/lib/Cells/TimeCell.tsx +10 -0
  18. package/src/lib/Cells/index.tsx +14 -0
  19. package/src/lib/Context/index.tsx +172 -0
  20. package/src/lib/Controls/FileUploader/ContextMenu.tsx +50 -0
  21. package/src/lib/Controls/FileUploader/FileUploaderControl.tsx +131 -0
  22. package/src/lib/Controls/FileUploader/FileUploaderTester.tsx +3 -0
  23. package/src/lib/Controls/FileUploader/index.tsx +2 -0
  24. package/src/lib/Controls/FileUploader/styled-components.tsx +10 -0
  25. package/src/lib/Controls/FormStepper/FormStepperControl.tsx +269 -0
  26. package/src/lib/Controls/FormStepper/FormStepperTester.tsx +22 -0
  27. package/src/lib/Controls/FormStepper/index.tsx +2 -0
  28. package/src/lib/Controls/FormStepper/styled-components.tsx +17 -0
  29. package/src/lib/Controls/Inputs/InputBaseControl.tsx +52 -0
  30. package/src/lib/Controls/Inputs/InputBooleanControl.tsx +67 -0
  31. package/src/lib/Controls/Inputs/InputBooleanRadioControl.tsx +74 -0
  32. package/src/lib/Controls/Inputs/InputDateControl.tsx +90 -0
  33. package/src/lib/Controls/Inputs/InputDateTimeControl.tsx +46 -0
  34. package/src/lib/Controls/Inputs/InputEnum.tsx +74 -0
  35. package/src/lib/Controls/Inputs/InputEnumAutoComplete.tsx +73 -0
  36. package/src/lib/Controls/Inputs/InputEnumRadios.tsx +43 -0
  37. package/src/lib/Controls/Inputs/InputIntegerControl.tsx +63 -0
  38. package/src/lib/Controls/Inputs/InputMultiLineTextControl.tsx +63 -0
  39. package/src/lib/Controls/Inputs/InputNumberControl.tsx +63 -0
  40. package/src/lib/Controls/Inputs/InputTextControl.tsx +62 -0
  41. package/src/lib/Controls/Inputs/InputTimeControl.tsx +46 -0
  42. package/src/lib/Controls/Inputs/index.tsx +13 -0
  43. package/src/lib/Controls/Inputs/inputControl.spec.ts +84 -0
  44. package/src/lib/Controls/Inputs/type.ts +3 -0
  45. package/src/lib/Controls/ObjectArray/DeleteDialog.tsx +49 -0
  46. package/src/lib/Controls/ObjectArray/ObjectArray.tsx +59 -0
  47. package/src/lib/Controls/ObjectArray/ObjectArrayToolBar.tsx +51 -0
  48. package/src/lib/Controls/ObjectArray/ObjectListControl.tsx +368 -0
  49. package/src/lib/Controls/ObjectArray/index.tsx +1 -0
  50. package/src/lib/Controls/ObjectArray/styled-components.tsx +13 -0
  51. package/src/lib/Controls/index.tsx +4 -0
  52. package/src/lib/ErrorHandling/GoAErrorControl.tsx +53 -0
  53. package/src/lib/ErrorHandling/MessageControl.tsx +19 -0
  54. package/src/lib/ErrorHandling/categorizationValidation.spec.ts +98 -0
  55. package/src/lib/ErrorHandling/controlValildation.spec.ts +57 -0
  56. package/src/lib/ErrorHandling/errorCheck.spec.ts +185 -0
  57. package/src/lib/ErrorHandling/errorCheck.tsx +86 -0
  58. package/src/lib/ErrorHandling/layoutValildation.spec.ts +47 -0
  59. package/src/lib/ErrorHandling/otherValildation.spec.ts +74 -0
  60. package/src/lib/ErrorHandling/schemaValidation.ts +115 -0
  61. package/src/lib/common/Grid.tsx +55 -0
  62. package/src/lib/jsonforms-components.module.scss +7 -0
  63. package/src/lib/jsonforms-components.spec.tsx +10 -0
  64. package/src/lib/jsonforms-components.tsx +14 -0
  65. package/src/lib/layouts/GroupControl.tsx +25 -0
  66. package/src/lib/layouts/HorizontalLayoutControl.tsx +30 -0
  67. package/src/lib/layouts/VerticalLayoutControl.tsx +28 -0
  68. package/src/lib/layouts/index.ts +3 -0
  69. package/src/lib/util/layout.tsx +68 -0
  70. package/src/lib/util/schemaUtils.ts +9 -0
  71. package/src/lib/util/stringUtils.ts +98 -0
  72. package/src/lib/util/style-component.ts +8 -0
  73. package/tsconfig.json +20 -0
  74. package/tsconfig.lib.json +19 -0
  75. package/tsconfig.spec.json +20 -0
@@ -0,0 +1,57 @@
1
+ import { errMalformedScope, errMissingScope, errUnknownScope, getUISchemaErrors } from './schemaValidation';
2
+
3
+ const dataSchema = {
4
+ type: 'object',
5
+ properties: {
6
+ firstName: {
7
+ type: 'string',
8
+ },
9
+ birthDate: {
10
+ type: 'string',
11
+ format: 'date',
12
+ },
13
+ },
14
+ };
15
+
16
+ const validControl = {
17
+ type: 'Control',
18
+ scope: '#/properties/firstName',
19
+ };
20
+
21
+ const malformedScope = {
22
+ type: 'Control',
23
+ scope: '#properties/firstName',
24
+ };
25
+
26
+ const unknownScope = {
27
+ type: 'Control',
28
+ scope: '#/properties/ouch/unknown/scope',
29
+ };
30
+
31
+ const missingScope = {
32
+ type: 'Control',
33
+ };
34
+
35
+ describe('check error processing', () => {
36
+ describe('control validation', () => {
37
+ it('ignores valid control schema', () => {
38
+ const err = getUISchemaErrors(validControl, dataSchema);
39
+ expect(err).toBe(null);
40
+ });
41
+
42
+ it('has malformed scope', () => {
43
+ const err = getUISchemaErrors(malformedScope, dataSchema);
44
+ expect(err).toBe(errMalformedScope(malformedScope.scope));
45
+ });
46
+
47
+ it('has unknown scope', () => {
48
+ const err = getUISchemaErrors(unknownScope, dataSchema);
49
+ expect(err).toBe(errUnknownScope(unknownScope.scope));
50
+ });
51
+
52
+ it('has missing scope', () => {
53
+ const err = getUISchemaErrors(missingScope, dataSchema);
54
+ expect(err).toBe(errMissingScope);
55
+ });
56
+ });
57
+ });
@@ -0,0 +1,185 @@
1
+ import {
2
+ hasElements,
3
+ hasVariant,
4
+ isCategorization,
5
+ isControlWithNoScope,
6
+ isEmptyElements,
7
+ isKnownType,
8
+ isLayoutType,
9
+ isScopedPrefixed,
10
+ isValidScope,
11
+ } from './errorCheck';
12
+
13
+ const dataSchema = {
14
+ type: 'object',
15
+ properties: {
16
+ firstName: {
17
+ type: 'string',
18
+ },
19
+ birthDate: {
20
+ type: 'string',
21
+ format: 'date',
22
+ },
23
+ },
24
+ };
25
+
26
+ // Note: The number in the description is the element index, and it
27
+ // is used to refer to the element in the unit tests. Please keep them
28
+ // up to date.
29
+ const uiSchema = {
30
+ type: 'VerticalLayout',
31
+ elements: [
32
+ {
33
+ type: 'Control',
34
+ scope: '#/properties/firstName',
35
+ description: 'valid scope test (0)',
36
+ },
37
+ {
38
+ type: 'Control',
39
+ scope: '#/properties/lastName',
40
+ description: 'missing property test (1)',
41
+ },
42
+ {
43
+ type: 'Control',
44
+ scope: '#/properties/birthDate',
45
+ description: 'Date test (2)',
46
+ options: {
47
+ componentProps: {
48
+ name: 'Calendar name',
49
+ min: '2023-02-01',
50
+ max: '2025-02-01',
51
+ },
52
+ },
53
+ },
54
+ {
55
+ type: 'Bob',
56
+ scope: 'properties/bob',
57
+ description: 'malformed scope test (3)',
58
+ },
59
+ {
60
+ type: 'Control',
61
+ description: 'missing scope test (4)',
62
+ },
63
+ {
64
+ type: 'HorizontalLayout',
65
+ description: 'Layout with no elements (5)',
66
+ },
67
+ {
68
+ type: 'VerticalLayout',
69
+ elements: [],
70
+ description: 'Layout with empty elements (6)',
71
+ },
72
+ {
73
+ type: 'Categorization',
74
+ description: 'Valid Categorization (7)',
75
+ elements: [
76
+ {
77
+ type: 'Category',
78
+ elements: [
79
+ {
80
+ type: 'Category',
81
+ elements: [
82
+ {
83
+ type: 'Control',
84
+ scope: '#/properties/firstName',
85
+ },
86
+ ],
87
+ },
88
+ ],
89
+ },
90
+ ],
91
+ options: {
92
+ variant: 'stepper',
93
+ },
94
+ },
95
+ ],
96
+ };
97
+
98
+ describe('check error processing', () => {
99
+ describe('data schema', () => {
100
+ it('parses correctly', () => {
101
+ expect(dataSchema).toEqual(
102
+ expect.objectContaining({
103
+ type: 'object',
104
+ properties: expect.objectContaining({
105
+ firstName: expect.objectContaining({ type: 'string' }),
106
+ }),
107
+ })
108
+ );
109
+ });
110
+ });
111
+
112
+ describe('ui schema', () => {
113
+ it('parses correctly', () => {
114
+ expect(uiSchema).toEqual(
115
+ expect.objectContaining({
116
+ type: 'VerticalLayout',
117
+ elements: expect.arrayContaining([
118
+ expect.objectContaining({ scope: expect.stringContaining('#/properties/firstName') }),
119
+ expect.objectContaining({ scope: expect.stringContaining('#/properties/birthDate') }),
120
+ ]),
121
+ })
122
+ );
123
+ });
124
+ });
125
+
126
+ describe('testing scope', () => {
127
+ it('can verify valid scope', () => {
128
+ const isValid = isValidScope(uiSchema.elements[0], dataSchema);
129
+ expect(isValid).toBe(true);
130
+ });
131
+
132
+ it('can detect missing property', () => {
133
+ const isValid = isValidScope(uiSchema.elements[1], dataSchema);
134
+ expect(isValid).toBe(false);
135
+ });
136
+
137
+ it('can detect malformed scope', () => {
138
+ const isValid = isScopedPrefixed(uiSchema.elements[3].scope as string);
139
+ expect(isValid).toBe(false);
140
+ });
141
+
142
+ it('can detect missing scope', () => {
143
+ const isValid = isControlWithNoScope(uiSchema.elements[4]);
144
+ expect(isValid).toBe(true);
145
+ });
146
+ });
147
+
148
+ describe('testing layout', () => {
149
+ it('can verify a valid layout', () => {
150
+ const isValid = isLayoutType(uiSchema);
151
+ expect(isValid).toBe(true);
152
+ });
153
+
154
+ it('can verify layout has elements', () => {
155
+ const isValid = hasElements(uiSchema);
156
+ expect(isValid).toBe(true);
157
+ });
158
+
159
+ it('can detect layout without elements', () => {
160
+ const subSchema = uiSchema.elements[5];
161
+ const isValid = isKnownType(subSchema) && hasElements(subSchema);
162
+ expect(isValid).toBe(false);
163
+ });
164
+
165
+ it('can detect layout with an empty set of elements', () => {
166
+ const subSchema = uiSchema.elements[6];
167
+ const isValid = isKnownType(subSchema) && isEmptyElements(subSchema);
168
+ expect(isValid).toBe(true);
169
+ });
170
+ });
171
+
172
+ describe('testing categorization', () => {
173
+ it('can verify categorization', () => {
174
+ const subSchema = uiSchema.elements[7];
175
+ const isValid = isCategorization(subSchema);
176
+ expect(isValid).toBe(true);
177
+ });
178
+
179
+ it('can detect categorization variant', () => {
180
+ const subSchema = uiSchema.elements[7];
181
+ const isValid = hasVariant(subSchema);
182
+ expect(isValid).toBe(true);
183
+ });
184
+ });
185
+ });
@@ -0,0 +1,86 @@
1
+ import { JsonSchema, UISchemaElement, hasType, isControl } from '@jsonforms/core';
2
+
3
+ export const isNullSchema = (schema: unknown): boolean => {
4
+ return schema === undefined || schema === null;
5
+ };
6
+
7
+ export const isValidScope = (uiSchema: UISchemaElement, schema: JsonSchema): boolean => {
8
+ if (!('scope' in uiSchema)) {
9
+ return false;
10
+ }
11
+ const scopeComponents = (uiSchema.scope as string).split('/');
12
+ // get rid of the '#' at the beginning of scope
13
+ scopeComponents.shift();
14
+
15
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
16
+ let obj = schema as any;
17
+ // iterate through the schema to ensure each property exists
18
+ for (const key of scopeComponents) {
19
+ if (obj && typeof obj === 'object' && key in obj) {
20
+ obj = obj[key];
21
+ } else {
22
+ return false;
23
+ }
24
+ }
25
+ return true;
26
+ };
27
+
28
+ export const isLayoutType = (schema: UISchemaElement): boolean => {
29
+ return (
30
+ hasType(schema, 'VerticalLayout') ||
31
+ hasType(schema, 'HorizontalLayout') ||
32
+ hasType(schema, 'Categorization') ||
33
+ hasType(schema, 'Group')
34
+ );
35
+ };
36
+
37
+ export const isKnownType = (schema: UISchemaElement): boolean => {
38
+ return (
39
+ hasType(schema, 'Control') || isLayoutType(schema) || hasType(schema, 'HelpContent') || isListWithDetail(schema)
40
+ );
41
+ };
42
+
43
+ export const isListWithDetail = (schema: UISchemaElement): boolean => {
44
+ return hasType(schema, 'ListWithDetail');
45
+ };
46
+
47
+ export const isScopedPrefixed = (scope: string): boolean => {
48
+ const scopeComponents = scope.split('/');
49
+ return scopeComponents.length > 1 && scopeComponents[0] === '#';
50
+ };
51
+
52
+ export const isEmptyObject = (schema: object): boolean => {
53
+ return Object.keys(schema).length === 0;
54
+ };
55
+
56
+ export const isControlWithNoScope = (uiSchema: UISchemaElement): boolean => {
57
+ return 'type' in uiSchema && uiSchema.type === 'Control' && !('scope' in uiSchema);
58
+ };
59
+
60
+ export const isCategorization = (uiSchema: UISchemaElement): boolean => {
61
+ return uiSchema.type === 'Categorization';
62
+ };
63
+
64
+ export const hasElements = (schema: object): boolean => {
65
+ return 'elements' in schema && Array.isArray(schema.elements);
66
+ };
67
+
68
+ export const isEmptyElements = (schema: object): boolean => {
69
+ return (
70
+ 'elements' in schema &&
71
+ schema.elements !== undefined &&
72
+ schema.elements !== null &&
73
+ Object.keys(schema.elements).length === 0
74
+ );
75
+ };
76
+
77
+ export const hasVariant = (schema: UISchemaElement): boolean => {
78
+ return 'options' in schema && schema.options !== undefined && schema.options !== null && 'variant' in schema.options;
79
+ };
80
+
81
+ export const isValidJsonObject = (schema: JsonSchema): boolean => {
82
+ return (
83
+ (typeof schema === 'object' && Object.keys(schema).length === 0) ||
84
+ ('properties' in schema && (('type' in schema && schema.type === 'object') || !('type' in schema)))
85
+ );
86
+ };
@@ -0,0 +1,47 @@
1
+ import { errNoElements, getUISchemaErrors } from './schemaValidation';
2
+
3
+ const dataSchema = {
4
+ type: 'object',
5
+ properties: {
6
+ firstName: {
7
+ type: 'string',
8
+ },
9
+ birthDate: {
10
+ type: 'string',
11
+ format: 'date',
12
+ },
13
+ },
14
+ };
15
+
16
+ const validLayout = {
17
+ type: 'VerticalLayout',
18
+ elements: [{ type: 'Control', scope: '#/properties/firstName' }],
19
+ };
20
+
21
+ const hasNoElements = {
22
+ type: 'HorizontalLayout',
23
+ };
24
+
25
+ const hasEmptyElement = {
26
+ type: 'HorizontalLayout',
27
+ elements: [],
28
+ };
29
+
30
+ describe('check error processing', () => {
31
+ describe('layout validation', () => {
32
+ it('ignores valid layout schema', () => {
33
+ const err = getUISchemaErrors(validLayout, dataSchema);
34
+ expect(err).toBe(null);
35
+ });
36
+
37
+ it('has no elements', () => {
38
+ const err = getUISchemaErrors(hasNoElements, dataSchema);
39
+ expect(err).toBe(errNoElements(hasNoElements.type));
40
+ });
41
+
42
+ it('has empty elements', () => {
43
+ const err = getUISchemaErrors(hasEmptyElement, dataSchema);
44
+ expect(err).toBe(errNoElements(hasEmptyElement.type));
45
+ });
46
+ });
47
+ });
@@ -0,0 +1,74 @@
1
+ import { UISchemaElement } from '@jsonforms/core';
2
+ import {
3
+ errMissingScope,
4
+ errMissingType,
5
+ errUnknownScope,
6
+ errUnknownType,
7
+ getUISchemaErrors,
8
+ } from './schemaValidation';
9
+
10
+ const dataSchema = {
11
+ type: 'object',
12
+ properties: {
13
+ firstName: {
14
+ type: 'string',
15
+ },
16
+ birthDate: {
17
+ type: 'string',
18
+ format: 'date',
19
+ },
20
+ },
21
+ };
22
+
23
+ const missingType = {
24
+ elements: [{ type: 'Control', scope: '#/properties/firstName' }],
25
+ };
26
+
27
+ const unknownType = {
28
+ type: 'BobsYerUncle',
29
+ elements: [{ type: 'Control', scope: '#/properties/firstName' }],
30
+ };
31
+
32
+ const validListWithDetails = {
33
+ type: 'ListWithDetail',
34
+ scope: '#/properties/firstName',
35
+ };
36
+ const listWithDetailsNoScope = {
37
+ type: 'ListWithDetail',
38
+ };
39
+
40
+ const listWithDetailsInvalidScope = {
41
+ type: 'ListWithDetail',
42
+ scope: '#/properties/Yabadabadooo',
43
+ };
44
+
45
+ describe('check error processing', () => {
46
+ describe('type validation', () => {
47
+ it('detects missing type', () => {
48
+ const err = getUISchemaErrors(missingType as unknown as UISchemaElement, dataSchema);
49
+ expect(err).toBe(errMissingType);
50
+ });
51
+
52
+ it('detects unknown type', () => {
53
+ const err = getUISchemaErrors(unknownType, dataSchema);
54
+ expect(err).toBe(errUnknownType(unknownType.type));
55
+ });
56
+ });
57
+
58
+ describe('List with Detail validation', () => {
59
+ it('likes valid ListWithDetails', () => {
60
+ const err = getUISchemaErrors(validListWithDetails, dataSchema);
61
+ expect(err).toBe(null);
62
+ });
63
+
64
+ it('detects no scope', () => {
65
+ const err = getUISchemaErrors(listWithDetailsNoScope, dataSchema);
66
+ expect(err).toBe(errMissingScope);
67
+ });
68
+
69
+ it('detects unknown scope', () => {
70
+ const err = getUISchemaErrors(listWithDetailsInvalidScope, dataSchema);
71
+ expect(err).toBe(errUnknownScope(listWithDetailsInvalidScope.scope));
72
+ });
73
+ });
74
+ });
@@ -0,0 +1,115 @@
1
+ import { JsonSchema, UISchemaElement, hasType, isCategorization, isControl, isLayout } from '@jsonforms/core';
2
+ import {
3
+ hasElements,
4
+ hasVariant,
5
+ isControlWithNoScope,
6
+ isEmptyElements,
7
+ isEmptyObject,
8
+ isKnownType,
9
+ isLayoutType,
10
+ isListWithDetail,
11
+ isNullSchema,
12
+ isScopedPrefixed,
13
+ isValidScope,
14
+ } from './errorCheck';
15
+
16
+ export const errCategorizationHasNonCategories = "Each element of 'Categorizations' must be of type 'Category'";
17
+ export const errCategorizationHasNoElements = 'A Categorization must contain Categories.';
18
+ export const errNoElements = (type: string) => `A ${type} must contain elements.`;
19
+ export const errCategorizationHasNoVariant = 'A Categorization must contain Options with a variant.';
20
+ export const errMissingScope = 'A Control must have a scope';
21
+ export const errMalformedScope = (scope: string): string => `Scope ${scope} must be prefixed with '#/'.`;
22
+ export const errUnknownScope = (scope: string): string => `Failed to render: unknown scope ${scope}`;
23
+ export const errMissingType = 'UI schema element must have a type';
24
+ export const errUnknownType = (type: string) => `Unknown schema type: ${type}. (Names are case sensitive)`;
25
+
26
+ export const getUISchemaErrors = (uiSchema: UISchemaElement, schema: JsonSchema): string | null => {
27
+ // Sometimes the UISchema is null. Ignore those cases, as all checks are done on the UIschema.
28
+ if (isNullSchema(uiSchema)) {
29
+ return null;
30
+ }
31
+
32
+ // silently ignore empty objects
33
+ if (isEmptyObject(uiSchema)) {
34
+ return '';
35
+ }
36
+
37
+ // Check control elements
38
+ if (isControl(uiSchema) && hasType(uiSchema, 'Control')) {
39
+ if (!isScopedPrefixed(uiSchema.scope)) {
40
+ return errMalformedScope(uiSchema.scope);
41
+ }
42
+ if (!isValidScope(uiSchema, schema)) {
43
+ return errUnknownScope(uiSchema.scope);
44
+ }
45
+ }
46
+
47
+ // isControl will fail if scope is not present, so make the test explicit...
48
+ if (isControlWithNoScope(uiSchema)) {
49
+ return errMissingScope;
50
+ }
51
+
52
+ if (isListWithDetail(uiSchema)) {
53
+ if ('scope' in uiSchema) {
54
+ const scope = uiSchema.scope as string;
55
+ if (!isValidScope(uiSchema, schema)) {
56
+ return errUnknownScope(scope);
57
+ }
58
+ } else {
59
+ return errMissingScope;
60
+ }
61
+ }
62
+
63
+ // Make an explicit check for Categorization, as this requires Category elements.
64
+ // Is layout will fail if some of these conditions are not met, so we do that
65
+ // check later.
66
+ if (isCategorization(uiSchema)) {
67
+ if (!hasElements(uiSchema)) {
68
+ return errCategorizationHasNoElements;
69
+ }
70
+
71
+ if (!hasVariant(uiSchema)) {
72
+ return errCategorizationHasNoVariant;
73
+ }
74
+
75
+ // ensure each element has type Category, and that each category
76
+ // has elements
77
+ if (isLayout(uiSchema)) {
78
+ const invalidCategorizations: string[] = [];
79
+ const invalidCategories: UISchemaElement[] = [];
80
+ (uiSchema.elements as UISchemaElement[]).forEach((e) => {
81
+ if (e.type !== 'Category') {
82
+ invalidCategorizations.push(e.type);
83
+ }
84
+ if (!hasElements(e) || isEmptyElements(e)) {
85
+ invalidCategories.push(e);
86
+ }
87
+ });
88
+ if (invalidCategorizations.length > 0) {
89
+ return errCategorizationHasNonCategories;
90
+ }
91
+ if (invalidCategories.length > 0) {
92
+ return errNoElements('Category');
93
+ }
94
+ }
95
+ }
96
+
97
+ // Check layout
98
+ if (isLayoutType(uiSchema)) {
99
+ if (!hasElements(uiSchema)) {
100
+ return errNoElements(uiSchema.type);
101
+ }
102
+ if (isEmptyElements(uiSchema)) {
103
+ return errNoElements(uiSchema.type);
104
+ }
105
+ }
106
+
107
+ if (!isKnownType(uiSchema)) {
108
+ if (uiSchema.type === undefined || uiSchema.type.length < 1) {
109
+ return errMissingType;
110
+ }
111
+ return errUnknownType(uiSchema.type);
112
+ }
113
+
114
+ return null;
115
+ };
@@ -0,0 +1,55 @@
1
+ import styled from 'styled-components';
2
+
3
+ export const Grid = styled.div`
4
+ display: flex;
5
+ flex-direction: row;
6
+ flex-wrap: wrap;
7
+ justify-content: space-between;
8
+ align-items: stretch;
9
+ `;
10
+
11
+ interface GridItemProps {
12
+ sm?: number;
13
+ md?: number;
14
+ lg?: number;
15
+ xl?: number;
16
+
17
+ hSpacing?: number;
18
+ vSpacing?: number;
19
+ }
20
+
21
+ export const GridItem = styled.div<GridItemProps>`
22
+ margin-bottom: ${(props: GridItemProps) => `${props.vSpacing ?? 0}rem`};
23
+
24
+ > .goa-card {
25
+ height: 100% !important;
26
+ width: 100% !important;
27
+ }
28
+
29
+ > img {
30
+ width: 100%;
31
+ }
32
+
33
+ flex: 0 1
34
+ ${(props: GridItemProps) =>
35
+ props.sm === 12 || props.sm === undefined
36
+ ? '100%'
37
+ : `calc(${(100 * (props?.sm ?? 12)) / 12}% - ${props.hSpacing ?? 0}rem)`};
38
+
39
+ @media (min-width: 768px) {
40
+ flex-basis: ${(props: GridItemProps) =>
41
+ props.md === 12 ? '100%' : `calc(${(100 * (props?.md ?? props.sm ?? 12)) / 12}% - ${props.hSpacing ?? 0}rem)`};
42
+ }
43
+ @media (min-width: 1024px) {
44
+ flex-basis: ${(props: GridItemProps) =>
45
+ props.lg === 12
46
+ ? '100%'
47
+ : `calc(${(100 * (props?.lg ?? props?.md ?? props.sm ?? 12)) / 12}% - ${props.hSpacing ?? 0}rem)`};
48
+ }
49
+ @media (min-width: 1280px) {
50
+ flex-basis: ${(props: GridItemProps) =>
51
+ props.xl === 12
52
+ ? '100%'
53
+ : `calc(${(100 * (props?.xl ?? props?.md ?? props.sm ?? 12)) / 12}% - ${props.hSpacing ?? 0}rem)`};
54
+ }
55
+ `;
@@ -0,0 +1,7 @@
1
+ /*
2
+ * Replace this with your own classes
3
+ *
4
+ * e.g.
5
+ * .container {
6
+ * }
7
+ */
@@ -0,0 +1,10 @@
1
+ import { render } from '@testing-library/react';
2
+
3
+ import JsonformsComponents from './jsonforms-components';
4
+
5
+ describe('JsonformsComponents', () => {
6
+ it('should render successfully', () => {
7
+ const { baseElement } = render(<JsonformsComponents />);
8
+ expect(baseElement).toBeTruthy();
9
+ });
10
+ });
@@ -0,0 +1,14 @@
1
+ import styles from './jsonforms-components.module.scss';
2
+
3
+ /* eslint-disable-next-line */
4
+ export interface JsonformsComponentsProps {}
5
+
6
+ export function JsonformsComponents(props: JsonformsComponentsProps) {
7
+ return (
8
+ <div className={styles['container']}>
9
+ <h1>Welcome to JsonformsComponents!</h1>
10
+ </div>
11
+ );
12
+ }
13
+
14
+ export default JsonformsComponents;
@@ -0,0 +1,25 @@
1
+ import React from 'react';
2
+ import { GoAContainer } from '@abgov/react-components-new';
3
+ import { GroupLayout, LayoutProps, RankedTester, rankWith, uiTypeIs, withIncreasedRank } from '@jsonforms/core';
4
+ import { withJsonFormsLayoutProps } from '@jsonforms/react';
5
+ import { renderLayoutElements } from '../util/layout';
6
+ import { Hidden } from '@mui/material';
7
+
8
+ export const groupTester: RankedTester = rankWith(1, uiTypeIs('Group'));
9
+
10
+ const GoAGroupControlComponent = (props: LayoutProps): JSX.Element => {
11
+ const { uischema, schema, path, enabled, renderers, cells, visible } = props;
12
+ const group = uischema as GroupLayout;
13
+
14
+ return (
15
+ <Hidden xsUp={!visible}>
16
+ <GoAContainer {...group.options} {...uischema?.options?.componentProps}>
17
+ {renderLayoutElements(group.elements, schema, path, enabled, renderers, cells)}
18
+ </GoAContainer>
19
+ </Hidden>
20
+ );
21
+ };
22
+
23
+ export const GoAGroupLayoutTester: RankedTester = withIncreasedRank(1, groupTester);
24
+
25
+ export const GoAGroupControl = withJsonFormsLayoutProps(GoAGroupControlComponent);