@remoteoss/json-schema-form 0.1.1-dev.20230619163824 → 0.3.0-beta.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/CHANGELOG.md +24 -0
- package/dist/index.cjs +4 -4
- package/dist/index.js +4 -4
- package/dist/standalone.js +787 -359
- package/json-schema-form.d.ts +115 -0
- package/package.json +3 -1
- package/src/tests/createHeadlessForm.test.js +18 -4
- package/src/tests/helpers.js +15 -0
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shorthand to lookup for keys with `x-jsf-*` preffix.
|
|
3
|
+
*/
|
|
4
|
+
export function pickXKey(node: Object, key: 'presentation' | 'errorMessage'): Object | undefined;
|
|
5
|
+
|
|
6
|
+
type ValidationTypes =
|
|
7
|
+
| 'type'
|
|
8
|
+
| 'minimum'
|
|
9
|
+
| 'maximum'
|
|
10
|
+
| 'minLength'
|
|
11
|
+
| 'maxLength'
|
|
12
|
+
| 'pattern'
|
|
13
|
+
| 'maxFileSize'
|
|
14
|
+
| 'accept'
|
|
15
|
+
| 'required';
|
|
16
|
+
|
|
17
|
+
type JSFConfig = {
|
|
18
|
+
/**
|
|
19
|
+
* Initial json values to prefill the form fields.
|
|
20
|
+
* This influences the initial visibility of conditional fields.
|
|
21
|
+
*/
|
|
22
|
+
initialValues?: Record<string, unknown>;
|
|
23
|
+
/**
|
|
24
|
+
* It inforces all json properties (fields) to have x-jsf-presentation.inputType.
|
|
25
|
+
@default true
|
|
26
|
+
*/
|
|
27
|
+
strictInputType?: boolean;
|
|
28
|
+
/**
|
|
29
|
+
* Customize the output of a given named Field.
|
|
30
|
+
* Useful if you want to enhance the UI/UX of a particular field.
|
|
31
|
+
* @example
|
|
32
|
+
* { has_pet: { "optionsDirection": "horizontal" } }
|
|
33
|
+
*/
|
|
34
|
+
customProperties?: {
|
|
35
|
+
description?: (description: string, field: $TSFixMe) => string | string;
|
|
36
|
+
[key: string]: unknown;
|
|
37
|
+
};
|
|
38
|
+
/**
|
|
39
|
+
* Customize the config for each inputType
|
|
40
|
+
*/
|
|
41
|
+
inputTypes?: {
|
|
42
|
+
/**
|
|
43
|
+
* Customize the error error message of this input type.
|
|
44
|
+
* @example
|
|
45
|
+
* { required: "This number is required." }
|
|
46
|
+
*/
|
|
47
|
+
errorMessage?: Partial<Record<ValidationTypes, string>>;
|
|
48
|
+
};
|
|
49
|
+
};
|
|
50
|
+
type Fields = Record<string, unknown>[]; //TODO: Type the field based on the given JSON Schema properties.
|
|
51
|
+
|
|
52
|
+
type $TSFixMe = any;
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Returns the Yup schema structure of given fields.
|
|
56
|
+
* These fields must be the same from
|
|
57
|
+
* const { fields } = createHeadlessForm()
|
|
58
|
+
*/
|
|
59
|
+
export function buildCompleteYupSchema(fields: Fields, config: JSFConfig): $TSFixMe; //TODO: We need to update Yup to 1.0 which supports TS.
|
|
60
|
+
|
|
61
|
+
type HeadlessFormOutput = {
|
|
62
|
+
/**
|
|
63
|
+
* List of Fields. Each Field corresponds to a form input from the json schema.
|
|
64
|
+
* @example
|
|
65
|
+
* [
|
|
66
|
+
{
|
|
67
|
+
name: "has_pet",
|
|
68
|
+
label: "Has Pet",
|
|
69
|
+
options: [
|
|
70
|
+
{ label: "Yes", value: "yes" },
|
|
71
|
+
{ label: "No", value: "no" }
|
|
72
|
+
],
|
|
73
|
+
required: true,
|
|
74
|
+
inputType: "radio",
|
|
75
|
+
jsonType: "string",
|
|
76
|
+
description: "Do you have a pet?",
|
|
77
|
+
errorMessage: {},
|
|
78
|
+
isVisible: true
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
type: "text",
|
|
82
|
+
label: "Pet's name",
|
|
83
|
+
description: "What's your pet's name?",
|
|
84
|
+
required: false,
|
|
85
|
+
inputType: "text",
|
|
86
|
+
jsonType: "string",
|
|
87
|
+
isVisible: false
|
|
88
|
+
}
|
|
89
|
+
* ]
|
|
90
|
+
*/
|
|
91
|
+
fields: Fields;
|
|
92
|
+
/**
|
|
93
|
+
* Validates given values and returns the respective errors.
|
|
94
|
+
* @example
|
|
95
|
+
* const { formErrors } = handleValidation({ has_pet: "yes" });
|
|
96
|
+
* console.log(formErrors) // { pet_name: "Required field." }
|
|
97
|
+
*/
|
|
98
|
+
handleValidation: (values: Record<string, unknown>) => {
|
|
99
|
+
yupError: $TSFixMe;
|
|
100
|
+
formErrors: $TSFixMe;
|
|
101
|
+
};
|
|
102
|
+
isError: boolean;
|
|
103
|
+
error?: Error;
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
type JSONSchemaObjectType = Record<string, unknown>;
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Generates the Headless form based on the provided JSON schema
|
|
110
|
+
*/
|
|
111
|
+
export function createHeadlessForm(
|
|
112
|
+
/** A JSON Schema of type object */
|
|
113
|
+
jsonSchema: JSONSchemaObjectType,
|
|
114
|
+
customConfig?: JSFConfig
|
|
115
|
+
): HeadlessFormOutput;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@remoteoss/json-schema-form",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0-beta.0",
|
|
4
4
|
"description": "Headless UI form powered by JSON Schemas",
|
|
5
5
|
"author": "Remote.com <engineering@remote.com> (https://remote.com/)",
|
|
6
6
|
"license": "MIT",
|
|
@@ -11,10 +11,12 @@
|
|
|
11
11
|
},
|
|
12
12
|
"main": "dist/index.cjs",
|
|
13
13
|
"module": "dist/index.js",
|
|
14
|
+
"typings": "./json-schema-form.d.ts",
|
|
14
15
|
"files": [
|
|
15
16
|
"dist",
|
|
16
17
|
"src/tests",
|
|
17
18
|
"json-schema-form.schema.json",
|
|
19
|
+
"json-schema-form.d.ts",
|
|
18
20
|
"README.md",
|
|
19
21
|
"CHANGELOG.md",
|
|
20
22
|
"LICENSE.md"
|
|
@@ -16,6 +16,7 @@ import {
|
|
|
16
16
|
schemaInputTypeSelectMultiple,
|
|
17
17
|
schemaInputTypeSelectMultipleOptional,
|
|
18
18
|
schemaInputTypeNumber,
|
|
19
|
+
schemaInputTypeNumberZeroMaximum,
|
|
19
20
|
schemaInputTypeDate,
|
|
20
21
|
schemaInputTypeEmail,
|
|
21
22
|
schemaInputWithStatement,
|
|
@@ -435,10 +436,10 @@ describe('createHeadlessForm', () => {
|
|
|
435
436
|
});
|
|
436
437
|
|
|
437
438
|
const fieldValidator = fields[0].schema;
|
|
438
|
-
expect(fieldValidator.isValidSync('CI007'
|
|
439
|
-
expect(fieldValidator.isValidSync(true
|
|
440
|
-
expect(fieldValidator.isValidSync(1
|
|
441
|
-
expect(fieldValidator.isValidSync(0
|
|
439
|
+
expect(fieldValidator.isValidSync('CI007')).toBe(true);
|
|
440
|
+
expect(fieldValidator.isValidSync(true)).toBe(false);
|
|
441
|
+
expect(fieldValidator.isValidSync(1)).toBe(false);
|
|
442
|
+
expect(fieldValidator.isValidSync(0)).toBe(false);
|
|
442
443
|
|
|
443
444
|
expect(handleValidation({ id_number: 1 }).formErrors).toEqual({
|
|
444
445
|
id_number: 'id_number must be a `string` type, but the final value was: `1`.',
|
|
@@ -1843,6 +1844,19 @@ describe('createHeadlessForm', () => {
|
|
|
1843
1844
|
).resolves.toEqual(assertObj);
|
|
1844
1845
|
});
|
|
1845
1846
|
});
|
|
1847
|
+
describe('and maximum is set to zero', () => {
|
|
1848
|
+
it('shows the correct validation', () => {
|
|
1849
|
+
const { handleValidation } = createHeadlessForm(schemaInputTypeNumberZeroMaximum);
|
|
1850
|
+
const validateForm = (vals) => friendlyError(handleValidation(vals));
|
|
1851
|
+
|
|
1852
|
+
expect(validateForm({ tabs: '0' })).toBeUndefined();
|
|
1853
|
+
expect(validateForm({ tabs: '-10' })).toBeUndefined();
|
|
1854
|
+
|
|
1855
|
+
expect(validateForm({ tabs: 1 })).toEqual({
|
|
1856
|
+
tabs: 'Must be smaller or equal to 0',
|
|
1857
|
+
});
|
|
1858
|
+
});
|
|
1859
|
+
});
|
|
1846
1860
|
});
|
|
1847
1861
|
|
|
1848
1862
|
describe('when a field has a maxLength of 10', () => {
|
package/src/tests/helpers.js
CHANGED
|
@@ -46,6 +46,21 @@ export const mockNumberInput = {
|
|
|
46
46
|
type: 'number',
|
|
47
47
|
};
|
|
48
48
|
|
|
49
|
+
export const schemaInputTypeNumberZeroMaximum = {
|
|
50
|
+
properties: {
|
|
51
|
+
tabs: {
|
|
52
|
+
title: 'Tabs',
|
|
53
|
+
description: 'How many open tabs do you have?',
|
|
54
|
+
'x-jsf-presentation': {
|
|
55
|
+
inputType: 'number',
|
|
56
|
+
},
|
|
57
|
+
minimum: -100,
|
|
58
|
+
maximum: 0,
|
|
59
|
+
type: 'number',
|
|
60
|
+
},
|
|
61
|
+
},
|
|
62
|
+
};
|
|
63
|
+
|
|
49
64
|
export const mockNumberInputWithPercentage = {
|
|
50
65
|
title: 'Shares',
|
|
51
66
|
description: 'What % of shares do you own?',
|