@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,30 @@
1
+ import React from 'react';
2
+ import { LayoutProps, RankedTester, rankWith, uiTypeIs, HorizontalLayout } from '@jsonforms/core';
3
+ import { LayoutRenderer, LayoutRendererProps } from '../util/layout';
4
+ import { withJsonFormsLayoutProps } from '@jsonforms/react';
5
+
6
+ export const materialHorizontalLayoutTester: RankedTester = rankWith(2, uiTypeIs('HorizontalLayout'));
7
+
8
+ export const GoAHorizontalLayoutComponent = ({
9
+ uischema,
10
+ renderers,
11
+ cells,
12
+ schema,
13
+ path,
14
+ enabled,
15
+ visible,
16
+ }: LayoutProps) => {
17
+ const layout = uischema as HorizontalLayout;
18
+ const childProps: LayoutRendererProps = {
19
+ elements: layout.elements,
20
+ schema,
21
+ path,
22
+ enabled,
23
+ direction: 'row',
24
+ visible,
25
+ };
26
+
27
+ return <LayoutRenderer {...childProps} renderers={renderers} cells={cells} />;
28
+ };
29
+
30
+ export const GoAHorizontalLayout = withJsonFormsLayoutProps(GoAHorizontalLayoutComponent, true);
@@ -0,0 +1,28 @@
1
+ import React from 'react';
2
+ import { LayoutProps, VerticalLayout } from '@jsonforms/core';
3
+ import { LayoutRenderer, LayoutRendererProps } from '../util/layout';
4
+ import { withJsonFormsLayoutProps } from '@jsonforms/react';
5
+
6
+ export const GoAVerticalLayoutComponent = ({
7
+ uischema,
8
+ schema,
9
+ path,
10
+ enabled,
11
+ renderers,
12
+ cells,
13
+ visible,
14
+ }: LayoutProps) => {
15
+ const verticalLayout = uischema as VerticalLayout;
16
+ const childProps: LayoutRendererProps = {
17
+ elements: verticalLayout.elements,
18
+ schema,
19
+ path,
20
+ enabled,
21
+ direction: 'column',
22
+ visible,
23
+ };
24
+
25
+ return <LayoutRenderer {...childProps} renderers={renderers} cells={cells} />;
26
+ };
27
+
28
+ export const GoAVerticalLayout = withJsonFormsLayoutProps(GoAVerticalLayoutComponent, true);
@@ -0,0 +1,3 @@
1
+ export * from './HorizontalLayoutControl';
2
+ export * from './VerticalLayoutControl';
3
+ export * from './GroupControl';
@@ -0,0 +1,68 @@
1
+ import isEmpty from 'lodash/isEmpty';
2
+ import React from 'react';
3
+
4
+ import type { UISchemaElement } from '@jsonforms/core';
5
+ import {
6
+ JsonFormsCellRendererRegistryEntry,
7
+ JsonFormsRendererRegistryEntry,
8
+ JsonSchema,
9
+ OwnPropsOfRenderer,
10
+ } from '@jsonforms/core';
11
+ import { JsonFormsDispatch } from '@jsonforms/react';
12
+ import { GoAGrid } from '@abgov/react-components-new';
13
+ import { Hidden } from '@mui/material';
14
+
15
+ export const renderLayoutElements = (
16
+ elements: UISchemaElement[],
17
+ schema?: JsonSchema,
18
+ path?: string,
19
+ enabled?: boolean,
20
+ renderers?: JsonFormsRendererRegistryEntry[],
21
+ cells?: JsonFormsCellRendererRegistryEntry[]
22
+ ) => {
23
+ return elements.map((child, index) => (
24
+ <div key={index}>
25
+ <JsonFormsDispatch
26
+ uischema={child}
27
+ schema={schema}
28
+ key={path}
29
+ path={path}
30
+ enabled={enabled}
31
+ renderers={renderers}
32
+ cells={cells}
33
+ />
34
+ </div>
35
+ ));
36
+ };
37
+
38
+ export interface LayoutRendererProps extends OwnPropsOfRenderer {
39
+ elements: UISchemaElement[];
40
+ direction: 'row' | 'column';
41
+ }
42
+
43
+ export const LayoutRenderer = ({
44
+ elements,
45
+ schema,
46
+ path,
47
+ enabled,
48
+ direction,
49
+ renderers,
50
+ cells,
51
+ visible,
52
+ }: LayoutRendererProps) => {
53
+ if (isEmpty(elements)) {
54
+ return null;
55
+ } else {
56
+ if (direction === 'row') {
57
+ return (
58
+ <Hidden xsUp={!visible}>
59
+ <GoAGrid minChildWidth="10ch">
60
+ {renderLayoutElements(elements, schema, path, enabled, renderers, cells)}
61
+ </GoAGrid>
62
+ </Hidden>
63
+ );
64
+ } else {
65
+ return <Hidden xsUp={!visible}>{renderLayoutElements(elements, schema, path, enabled, renderers, cells)}</Hidden>;
66
+ }
67
+ }
68
+ };
@@ -0,0 +1,9 @@
1
+ export const parseSchema = (schema: string) => {
2
+ try {
3
+ return JSON.parse(schema);
4
+ } catch (e) {
5
+ const err = e as Error;
6
+ console.debug(err.message);
7
+ return {};
8
+ }
9
+ };
@@ -0,0 +1,98 @@
1
+ import { ControlProps, JsonSchema } from '@jsonforms/core';
2
+
3
+ /**
4
+ * Sets the first word to be capitalized so that it is sentence cased.
5
+ * @param words
6
+ * @returns sentence word string.
7
+ */
8
+ export const capitalizeFirstLetter = (words: string) => {
9
+ const value = words.charAt(0).toUpperCase() + words.slice(1).toLowerCase();
10
+ return value;
11
+ };
12
+
13
+ /**
14
+ * Compares the scope name and the label to determine if it matches so that it can be sentence case.
15
+ * @param scope - format eg: '#/properties/firstName'
16
+ * @param label - The label text
17
+ * @returns true if the scope and label matches, otherwise false
18
+ */
19
+ export const controlScopeMatchesLabel = (scope: string, label: string) => {
20
+ // Get the property name in the string from the scope
21
+ const splitIdName = scope.replace(' ', '').split('/')?.at(-1)?.toLowerCase() ?? '';
22
+ const labelWithNoSpaces = label.replace(' ', '').toLowerCase();
23
+ if (splitIdName === labelWithNoSpaces) {
24
+ return true;
25
+ }
26
+ return false;
27
+ };
28
+
29
+ /**
30
+ * Gets the label text in sentence case
31
+ * @param scope
32
+ * @param label
33
+ * @returns
34
+ */
35
+ export const getLabelText = (scope: string, label: string): string => {
36
+ let labelToUpdate: string = '';
37
+
38
+ if (controlScopeMatchesLabel(scope, label || '')) {
39
+ labelToUpdate = capitalizeFirstLetter(label || '');
40
+ } else {
41
+ labelToUpdate = label || '';
42
+ }
43
+
44
+ return labelToUpdate;
45
+ };
46
+ // This message is thrown when the isNotEmpty is triggered by Ajv checkInput.ts configuration
47
+ export const FIELD_REQUIRED = 'data should pass "isNotEmpty" keyword validation';
48
+
49
+ const isEmptyBoolean = (schema: JsonSchema, data: unknown): boolean => {
50
+ return schema.type !== undefined && schema.type === 'boolean' && (data === null || data === undefined);
51
+ };
52
+ const isEmptyNumber = (schema: JsonSchema, data: unknown): boolean => {
53
+ return (
54
+ data === '' ||
55
+ data === undefined ||
56
+ data === null ||
57
+ ((schema.type === 'number' || schema.type === 'integer') && isNaN(+data))
58
+ );
59
+ };
60
+ /**
61
+ * Check if a required, defined input value is valid. Returns an appropriate
62
+ * error message if not.
63
+ * @param props
64
+ * @returns error message
65
+ */
66
+ export const checkFieldValidity = (props: ControlProps): string => {
67
+ const { data, errors: ajvErrors, required, label, uischema, schema } = props;
68
+ const labelToUpdate = getLabelText(uischema.scope, label);
69
+
70
+ if (required) {
71
+ if (data === undefined) return '';
72
+
73
+ if (schema) {
74
+ if (isEmptyBoolean(schema, data)) {
75
+ return `${labelToUpdate} is required`;
76
+ }
77
+
78
+ if (isEmptyNumber(schema, data)) {
79
+ return `${labelToUpdate} is required`;
80
+ }
81
+ }
82
+ }
83
+
84
+ return ajvErrors;
85
+ };
86
+
87
+ /**
88
+ * Check if the date is a valid date/time
89
+ */
90
+ export const isValidDate = function (date: Date | string) {
91
+ if (date instanceof Date && isFinite(date.getTime())) {
92
+ return true;
93
+ } else if (typeof date === 'string' && date.length > 0) {
94
+ return true;
95
+ } else {
96
+ return false;
97
+ }
98
+ };
@@ -0,0 +1,8 @@
1
+ import styled from 'styled-components';
2
+
3
+ export const VerticalLayout = styled.div`
4
+ height: 70vh;
5
+ overflow-y: auto;
6
+ padding-left: 0.2rem;
7
+ padding-right: 0.2rem;
8
+ `;
package/tsconfig.json ADDED
@@ -0,0 +1,20 @@
1
+ {
2
+ "compilerOptions": {
3
+ "jsx": "react-jsx",
4
+ "allowJs": false,
5
+ "esModuleInterop": false,
6
+ "allowSyntheticDefaultImports": true,
7
+ "strict": true
8
+ },
9
+ "files": [],
10
+ "include": [],
11
+ "references": [
12
+ {
13
+ "path": "./tsconfig.lib.json"
14
+ },
15
+ {
16
+ "path": "./tsconfig.spec.json"
17
+ }
18
+ ],
19
+ "extends": "../../tsconfig.base.json"
20
+ }
@@ -0,0 +1,19 @@
1
+ {
2
+ "extends": "./tsconfig.json",
3
+ "compilerOptions": {
4
+ "outDir": "../../dist/out-tsc",
5
+ "types": ["node", "../../node_modules/@nx/react/typings/cssmodule.d.ts", "../../node_modules/@nx/react/typings/image.d.ts"]
6
+ },
7
+ "exclude": [
8
+ "jest.config.ts",
9
+ "src/**/*.spec.ts",
10
+ "src/**/*.test.ts",
11
+ "src/**/*.spec.tsx",
12
+ "src/**/*.test.tsx",
13
+ "src/**/*.spec.js",
14
+ "src/**/*.test.js",
15
+ "src/**/*.spec.jsx",
16
+ "src/**/*.test.jsx"
17
+ ],
18
+ "include": ["src/**/*.js", "src/**/*.jsx", "src/**/*.ts", "src/**/*.tsx"]
19
+ }
@@ -0,0 +1,20 @@
1
+ {
2
+ "extends": "./tsconfig.json",
3
+ "compilerOptions": {
4
+ "outDir": "../../dist/out-tsc",
5
+ "module": "commonjs",
6
+ "types": ["jest", "node"]
7
+ },
8
+ "include": [
9
+ "jest.config.ts",
10
+ "src/**/*.test.ts",
11
+ "src/**/*.spec.ts",
12
+ "src/**/*.test.tsx",
13
+ "src/**/*.spec.tsx",
14
+ "src/**/*.test.js",
15
+ "src/**/*.spec.js",
16
+ "src/**/*.test.jsx",
17
+ "src/**/*.spec.jsx",
18
+ "src/**/*.d.ts"
19
+ ]
20
+ }