@nolwenture/formik-jsonschema-form 1.3.4 → 1.3.6
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/README.md +13 -10
- package/dist/cjs/Form/Form.js +2 -1
- package/dist/cjs/Form/fields/ArrayField/ArrayField.js +3 -4
- package/dist/cjs/Form/fields/MultipleChoiceField/MultipleChoiceFieldInput.js +3 -2
- package/dist/cjs/Form/fields/ObjectField/ObjectField.js +59 -25
- package/dist/cjs/FormView/fields/ArrayField.js +3 -1
- package/dist/cjs/FormView/fields/MultipleChoiceField.js +5 -2
- package/dist/cjs/utils/createValidationSchema.js +37 -24
- package/dist/cjs/utils/immutablySwapItems.js +10 -0
- package/dist/cjs/utils/index.js +1 -0
- package/dist/esm/Form/Form.js +2 -1
- package/dist/esm/Form/fields/ArrayField/ArrayField.js +3 -4
- package/dist/esm/Form/fields/MultipleChoiceField/MultipleChoiceFieldInput.js +3 -2
- package/dist/esm/Form/fields/ObjectField/ObjectField.js +60 -26
- package/dist/esm/FormView/fields/ArrayField.js +3 -1
- package/dist/esm/FormView/fields/MultipleChoiceField.js +5 -2
- package/dist/esm/utils/createValidationSchema.js +37 -24
- package/dist/esm/utils/immutablySwapItems.js +7 -0
- package/dist/esm/utils/index.js +1 -0
- package/dist/types/Form/types/FormRegistryContext.d.ts +1 -0
- package/dist/types/common/types/Form.d.ts +2 -0
- package/dist/types/common/types/Schemas.d.ts +0 -45
- package/dist/types/utils/immutablySwapItems.d.ts +1 -0
- package/dist/types/utils/index.d.ts +1 -0
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -287,13 +287,13 @@ return (
|
|
|
287
287
|
|
|
288
288
|
The style for buttons to add and remove (and move) array or object items can be overridden within the uiSchema by giving inline style.
|
|
289
289
|
|
|
290
|
-
The buttons that can be customized that way are:
|
|
290
|
+
The buttons that can be customized that way are by defining these under "ui:options":
|
|
291
291
|
|
|
292
|
-
- "
|
|
293
|
-
- "
|
|
294
|
-
- "
|
|
295
|
-
- "
|
|
296
|
-
- "
|
|
292
|
+
- "addButton"
|
|
293
|
+
- "removeButton"
|
|
294
|
+
- "upButton"
|
|
295
|
+
- "downButton"
|
|
296
|
+
- "customButton"
|
|
297
297
|
|
|
298
298
|
`content` takes a ReactNode as input.
|
|
299
299
|
|
|
@@ -317,11 +317,14 @@ const schema = {
|
|
|
317
317
|
const uiSchema = {
|
|
318
318
|
"ui:description": "Form description",
|
|
319
319
|
// make a green ADD button for someArray that reads "Hello!"
|
|
320
|
-
|
|
321
|
-
"ui:
|
|
322
|
-
|
|
323
|
-
|
|
320
|
+
someArray: {
|
|
321
|
+
"ui:options": {
|
|
322
|
+
addButton: {
|
|
323
|
+
content: <b>Hello!</b>,
|
|
324
|
+
props: { style: { background: "green" } },
|
|
325
|
+
},
|
|
324
326
|
},
|
|
327
|
+
}
|
|
325
328
|
};
|
|
326
329
|
|
|
327
330
|
...
|
package/dist/cjs/Form/Form.js
CHANGED
|
@@ -9,7 +9,7 @@ const fields_1 = require("./fields");
|
|
|
9
9
|
const templates_1 = require("./templates");
|
|
10
10
|
const Form = (props) => {
|
|
11
11
|
const { isSubmitting } = (0, formik_1.useFormikContext)();
|
|
12
|
-
const { schema, uiSchema = {}, className, children, fields = {}, templates = {}, components = {}, formContext = {}, formOptions = {}, formLocalization = {}, useItemsAsAdditionalItems = false, hideUnmarkedAdditionalProperties = false, hideSubmit = false, } = props;
|
|
12
|
+
const { schema, uiSchema = {}, className, children, fields = {}, templates = {}, components = {}, formContext = {}, formOptions = {}, formLocalization = {}, useItemsAsAdditionalItems = false, hideUnmarkedAdditionalProperties = false, onAdditionalPropertyOrderChange, hideSubmit = false, } = props;
|
|
13
13
|
const schemaDefinitions = schema.definitions;
|
|
14
14
|
const uiSchemaDefinitions = uiSchema?.definitions;
|
|
15
15
|
const registry = {
|
|
@@ -29,6 +29,7 @@ const Form = (props) => {
|
|
|
29
29
|
formLocalization,
|
|
30
30
|
useItemsAsAdditionalItems,
|
|
31
31
|
hideUnmarkedAdditionalProperties,
|
|
32
|
+
onAdditionalPropertyOrderChange,
|
|
32
33
|
};
|
|
33
34
|
const { Form: FormEl, FormButton, FormButtonWrapper } = registry.components;
|
|
34
35
|
const SchemaField = registry.fields.SchemaField;
|
|
@@ -37,7 +37,7 @@ const ArrayField = (props) => {
|
|
|
37
37
|
const { fields: { SchemaField }, templates, components: { SelectFieldInput, ArrayFieldItem, ArrayFieldItemButtons, ArrayFieldAddButton, ArrayFieldRemoveButton, ArrayFieldUpButton, ArrayFieldDownButton, }, useItemsAsAdditionalItems, } = (0, react_1.useContext)(FormRegistry_1.FormRegistry);
|
|
38
38
|
(0, hooks_1.useSetDefault)(props);
|
|
39
39
|
const { name, schema, uiSchema } = props;
|
|
40
|
-
const { type, props: inputProps } = (0, react_1.useMemo)(() => (0, utils_1.extractUiSchema)(uiSchema), [uiSchema]);
|
|
40
|
+
const { type, props: inputProps, disabled, removeButton, upButton, downButton, addButton, } = (0, react_1.useMemo)(() => (0, utils_1.extractUiSchema)(uiSchema), [uiSchema]);
|
|
41
41
|
const [{ value }, _, { setValue }] = (0, formik_1.useField)(name);
|
|
42
42
|
const schemas = (0, react_1.useMemo)(() => {
|
|
43
43
|
let items = schema.items && typeof schema.items !== "boolean" ? schema.items : [];
|
|
@@ -98,7 +98,6 @@ const ArrayField = (props) => {
|
|
|
98
98
|
// [schema]
|
|
99
99
|
// );
|
|
100
100
|
// Backwards compatibility ends
|
|
101
|
-
const { disabled } = (0, react_1.useMemo)(() => (0, utils_1.extractUiSchema)(uiSchema), [uiSchema]);
|
|
102
101
|
const valueArray = Array.isArray(value) ? value : undefined;
|
|
103
102
|
const preventManipulation = disabled || schema.readOnly;
|
|
104
103
|
const SelectedFieldTemplate = (props.uiSchema?.["ui:template"] &&
|
|
@@ -116,8 +115,8 @@ const ArrayField = (props) => {
|
|
|
116
115
|
},
|
|
117
116
|
// "true" will prevent validation for required array fields
|
|
118
117
|
// since a value always exists in the array
|
|
119
|
-
forceDefaultValue: index >= schemas.items.length }), !preventManipulation && index >= schemas.items.length && ((0, jsx_runtime_1.jsxs)(ArrayFieldItemButtons, { children: [(0, jsx_runtime_1.jsx)(ArrayFieldRemoveButton, { id: value?.[index + schemas.items.length]?.name, ...(
|
|
120
|
-
index < value?.slice(schemas.items.length).length - 1 && ((0, jsx_runtime_1.jsx)(ArrayFieldDownButton, { ...(
|
|
118
|
+
forceDefaultValue: index >= schemas.items.length }), !preventManipulation && index >= schemas.items.length && ((0, jsx_runtime_1.jsxs)(ArrayFieldItemButtons, { children: [(0, jsx_runtime_1.jsx)(ArrayFieldRemoveButton, { id: value?.[index + schemas.items.length]?.name, ...(removeButton?.props ?? {}), onClick: () => setValue(removeFromArray(value, index + schemas.items.length)), children: removeButton?.content ?? "-" }), value.length > 1 && index > 0 && ((0, jsx_runtime_1.jsx)(ArrayFieldUpButton, { ...(upButton?.props ?? {}), onClick: () => setValue(moveInArray(value, index + schemas.items.length, -1)), children: upButton?.content ?? "↑" })), value.length > 1 &&
|
|
119
|
+
index < value?.slice(schemas.items.length).length - 1 && ((0, jsx_runtime_1.jsx)(ArrayFieldDownButton, { ...(downButton?.props ?? {}), onClick: () => setValue(moveInArray(value, index + schemas.items.length, 1)), children: downButton?.content ?? "↓" }))] }))] }, index)) }), schemas.additionalItems && !preventManipulation && ((0, jsx_runtime_1.jsx)(ArrayFieldAddButton, { ...(addButton?.props ?? {}), onClick: () => setValue(appendArray(value, schemas.additionalItems)), children: addButton?.content ?? "+" }))] }));
|
|
121
120
|
};
|
|
122
121
|
exports.ArrayField = ArrayField;
|
|
123
122
|
function prepareChildSchema(childSchema, parentSchema) {
|
|
@@ -8,7 +8,8 @@ const FormRegistry_1 = require("../../FormRegistry");
|
|
|
8
8
|
const utils_1 = require("../../../utils");
|
|
9
9
|
const MultipleChoiceFieldInput = ({ inputProps, name, className, enums, style, value, form, }) => {
|
|
10
10
|
const { components: { MultipleChoiceFieldContainer, MultipleChoiceFieldElement, MultipleChoiceFieldInputElement, MultipleChoiceFieldLabel, }, } = (0, react_1.useContext)(FormRegistry_1.FormRegistry);
|
|
11
|
-
const
|
|
11
|
+
const safeEnums = enums ?? { type: "", values: [] };
|
|
12
|
+
const isMultiSelect = safeEnums.type === utils_1.EnumsTypes.MULTI_SELECT;
|
|
12
13
|
const currentValue = isMultiSelect
|
|
13
14
|
? Array.isArray(value)
|
|
14
15
|
? value
|
|
@@ -31,7 +32,7 @@ const MultipleChoiceFieldInput = ({ inputProps, name, className, enums, style, v
|
|
|
31
32
|
form?.setFieldValue(name, optionValue);
|
|
32
33
|
}
|
|
33
34
|
};
|
|
34
|
-
return ((0, jsx_runtime_1.jsx)(MultipleChoiceFieldContainer, { className: className, style: (0, getStyle_1.getStyle)(style ?? ""), children:
|
|
35
|
+
return ((0, jsx_runtime_1.jsx)(MultipleChoiceFieldContainer, { className: className, style: (0, getStyle_1.getStyle)(style ?? ""), children: (safeEnums.values ?? []).map((v) => {
|
|
35
36
|
const optionValue = v.const;
|
|
36
37
|
return ((0, jsx_runtime_1.jsxs)(MultipleChoiceFieldElement, { "data-fjsf-enum-value": optionValue, children: [(0, jsx_runtime_1.jsx)(MultipleChoiceFieldInputElement, { ...inputProps, name: name, type: isMultiSelect ? "checkbox" : "radio", value: optionValue !== undefined ? optionValue.toString() : "", checked: isChecked(optionValue), onChange: () => handleChange(optionValue) }), (0, jsx_runtime_1.jsx)(MultipleChoiceFieldLabel, { children: v.title })] }, optionValue !== undefined ? optionValue.toString() : "undefined"));
|
|
37
38
|
}) }));
|
|
@@ -9,6 +9,11 @@ const utils_1 = require("../../../utils");
|
|
|
9
9
|
const hooks_1 = require("../../hooks");
|
|
10
10
|
const FormRegistry_1 = require("../../FormRegistry");
|
|
11
11
|
const types_1 = require("./types");
|
|
12
|
+
const DEFAULT_FIELD = {
|
|
13
|
+
type: "string",
|
|
14
|
+
_fieldType: "string",
|
|
15
|
+
"ui:title": "New Field",
|
|
16
|
+
};
|
|
12
17
|
const useObjectField = (name) => {
|
|
13
18
|
if (!name) {
|
|
14
19
|
const { values = {}, setValues } = (0, formik_1.useFormikContext)();
|
|
@@ -18,9 +23,10 @@ const useObjectField = (name) => {
|
|
|
18
23
|
return { value, setValue };
|
|
19
24
|
};
|
|
20
25
|
const ObjectField = (props) => {
|
|
21
|
-
const { fields: { SchemaField }, templates, components: { ObjectFieldItem, ObjectFieldItemButtons, ObjectFieldButton, ObjectFieldAddButton, ObjectFieldRemoveButton, ObjectFieldUpButton, ObjectFieldDownButton, ObjectFieldSection, }, hideUnmarkedAdditionalProperties, } = (0, react_1.useContext)(FormRegistry_1.FormRegistry);
|
|
26
|
+
const { fields: { SchemaField }, templates, components: { ObjectFieldItem, ObjectFieldItemButtons, ObjectFieldButton, ObjectFieldAddButton, ObjectFieldRemoveButton, ObjectFieldUpButton, ObjectFieldDownButton, ObjectFieldSection, }, hideUnmarkedAdditionalProperties, onAdditionalPropertyOrderChange, } = (0, react_1.useContext)(FormRegistry_1.FormRegistry);
|
|
22
27
|
(0, hooks_1.useSetDefault)(props);
|
|
23
28
|
const { name, schema, uiSchema } = props;
|
|
29
|
+
const { type, props: inputProps, isCollapsible, order, disabled, } = (0, react_1.useMemo)(() => (0, utils_1.extractUiSchema)(uiSchema), [uiSchema]);
|
|
24
30
|
const { value, setValue } = useObjectField(name);
|
|
25
31
|
const [{ properties, additionalProperties, required }, valuesToRemove] = (0, react_1.useMemo)(() => {
|
|
26
32
|
return (0, utils_1.resolveSchema)(schema, value);
|
|
@@ -36,27 +42,28 @@ const ObjectField = (props) => {
|
|
|
36
42
|
}, [valuesToRemove]);
|
|
37
43
|
const propertyKeys = (0, react_1.useMemo)(() => Object.keys(properties || {}), [properties]);
|
|
38
44
|
const additionalPropertyKeys = (0, react_1.useMemo)(() => Object.keys(value || {}).filter((key) => !propertyKeys.includes(key)), [value, propertyKeys]);
|
|
39
|
-
const orderedProperties = (0, utils_1.orderByUiSchema)(
|
|
40
|
-
const hiddenProperties = (0, utils_1.getHiddenProperties)(
|
|
41
|
-
const orderedAdditionalProperties = (0, utils_1.orderAdditionalProperties)(
|
|
42
|
-
const hiddenAdditionalProperties = (0, utils_1.getHiddenProperties)(
|
|
45
|
+
const orderedProperties = (0, utils_1.orderByUiSchema)(order, propertyKeys);
|
|
46
|
+
const hiddenProperties = (0, utils_1.getHiddenProperties)(order, propertyKeys);
|
|
47
|
+
const orderedAdditionalProperties = (0, utils_1.orderAdditionalProperties)(order, additionalPropertyKeys);
|
|
48
|
+
const hiddenAdditionalProperties = (0, utils_1.getHiddenProperties)(order, additionalPropertyKeys);
|
|
43
49
|
const getObjectFieldButton = ({ purpose, onClick, uiSchema, }) => {
|
|
50
|
+
const { removeButton, upButton, downButton, addButton, customButton } = (0, utils_1.extractUiSchema)(uiSchema);
|
|
44
51
|
switch (purpose) {
|
|
45
52
|
case types_1.ObjectFieldButtonPurpose.ADD:
|
|
46
|
-
return ((0, jsx_runtime_1.jsx)(ObjectFieldAddButton, { ...(
|
|
53
|
+
return ((0, jsx_runtime_1.jsx)(ObjectFieldAddButton, { ...(addButton?.props ?? {}), onClick: onClick, children: addButton?.content ?? "+" }));
|
|
47
54
|
case types_1.ObjectFieldButtonPurpose.REMOVE:
|
|
48
|
-
return ((0, jsx_runtime_1.jsx)(ObjectFieldRemoveButton, { ...(
|
|
55
|
+
return ((0, jsx_runtime_1.jsx)(ObjectFieldRemoveButton, { ...(removeButton?.props ?? {}), onClick: onClick, children: removeButton?.content ?? "-" }));
|
|
49
56
|
case types_1.ObjectFieldButtonPurpose.MOVE_UP:
|
|
50
|
-
return ((0, jsx_runtime_1.jsx)(ObjectFieldUpButton, { ...(
|
|
57
|
+
return ((0, jsx_runtime_1.jsx)(ObjectFieldUpButton, { ...(upButton?.props ?? {}), onClick: onClick, children: upButton?.content ?? "↑" }));
|
|
51
58
|
case types_1.ObjectFieldButtonPurpose.MOVE_DOWN:
|
|
52
|
-
return ((0, jsx_runtime_1.jsx)(ObjectFieldDownButton, { ...(
|
|
59
|
+
return ((0, jsx_runtime_1.jsx)(ObjectFieldDownButton, { ...(downButton?.props ?? {}), onClick: onClick, children: downButton?.content ?? "↓" }));
|
|
53
60
|
default:
|
|
54
|
-
return ((0, jsx_runtime_1.jsx)(ObjectFieldButton, { ...(
|
|
61
|
+
return ((0, jsx_runtime_1.jsx)(ObjectFieldButton, { ...(customButton?.props ?? {}), onClick: onClick, children: customButton?.content ?? "" }));
|
|
55
62
|
}
|
|
56
63
|
};
|
|
57
|
-
const SelectedObjectFieldTemplate = (
|
|
58
|
-
templates[
|
|
59
|
-
(
|
|
64
|
+
const SelectedObjectFieldTemplate = (uiSchema?.["ui:template"] &&
|
|
65
|
+
templates[uiSchema?.["ui:template"]]) ??
|
|
66
|
+
(isCollapsible
|
|
60
67
|
? templates.CollapsibleObjectFieldTemplate
|
|
61
68
|
: templates.ObjectFieldTemplate);
|
|
62
69
|
const showAdditionalProperties = !hideUnmarkedAdditionalProperties || !!additionalProperties;
|
|
@@ -97,7 +104,7 @@ const ObjectField = (props) => {
|
|
|
97
104
|
},
|
|
98
105
|
}, style: { display: "none" } }, child));
|
|
99
106
|
}), showAdditionalProperties &&
|
|
100
|
-
orderedAdditionalProperties.map((childName) => {
|
|
107
|
+
orderedAdditionalProperties.map((childName, index) => {
|
|
101
108
|
let correctUiSchema = uiSchema?.[childName];
|
|
102
109
|
if (uiSchema?.properties?.["ui:order"] !== undefined &&
|
|
103
110
|
uiSchema?.[childName]?.["ui:order"] === undefined) {
|
|
@@ -106,14 +113,34 @@ const ObjectField = (props) => {
|
|
|
106
113
|
"ui:order": uiSchema.properties?.["ui:order"],
|
|
107
114
|
};
|
|
108
115
|
}
|
|
109
|
-
return ((0, jsx_runtime_1.jsxs)(ObjectFieldItem, { children: [(0, jsx_runtime_1.jsx)(SchemaField, { required: required?.includes(childName), name: name ? [name, childName].join(".") : childName, schema: prepareChildSchema(schema.additionalProperties, schema), uiSchema: correctUiSchema }, childName), (0, jsx_runtime_1.
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
116
|
+
return ((0, jsx_runtime_1.jsxs)(ObjectFieldItem, { children: [(0, jsx_runtime_1.jsx)(SchemaField, { required: required?.includes(childName), name: name ? [name, childName].join(".") : childName, schema: prepareChildSchema(schema.additionalProperties, schema), uiSchema: correctUiSchema }, childName), (0, jsx_runtime_1.jsxs)(ObjectFieldItemButtons, { children: [onAdditionalPropertyOrderChange &&
|
|
117
|
+
index > 0 &&
|
|
118
|
+
getObjectFieldButton({
|
|
119
|
+
purpose: types_1.ObjectFieldButtonPurpose.MOVE_UP,
|
|
120
|
+
onClick: () => {
|
|
121
|
+
onAdditionalPropertyOrderChange(name, orderedAdditionalProperties, (0, utils_1.immutablySwapItems)(orderedAdditionalProperties, index, index - 1));
|
|
122
|
+
},
|
|
123
|
+
uiSchema,
|
|
124
|
+
}), onAdditionalPropertyOrderChange &&
|
|
125
|
+
index < orderedAdditionalProperties.length - 1 &&
|
|
126
|
+
getObjectFieldButton({
|
|
127
|
+
purpose: types_1.ObjectFieldButtonPurpose.MOVE_DOWN,
|
|
128
|
+
onClick: () => {
|
|
129
|
+
onAdditionalPropertyOrderChange(name, orderedAdditionalProperties, (0, utils_1.immutablySwapItems)(orderedAdditionalProperties, index, index + 1));
|
|
130
|
+
},
|
|
131
|
+
uiSchema,
|
|
132
|
+
}), getObjectFieldButton({
|
|
133
|
+
purpose: types_1.ObjectFieldButtonPurpose.REMOVE,
|
|
134
|
+
onClick: () => {
|
|
135
|
+
const { [childName]: _removedProperty, ...newValue } = value;
|
|
136
|
+
setValue(newValue);
|
|
137
|
+
if (onAdditionalPropertyOrderChange) {
|
|
138
|
+
const nextOrder = orderedAdditionalProperties.filter((k) => k !== childName);
|
|
139
|
+
onAdditionalPropertyOrderChange(name, orderedAdditionalProperties, nextOrder);
|
|
140
|
+
}
|
|
141
|
+
},
|
|
142
|
+
uiSchema,
|
|
143
|
+
})] })] }, childName));
|
|
117
144
|
}), showAdditionalProperties &&
|
|
118
145
|
hiddenAdditionalProperties.map((childName) => {
|
|
119
146
|
let correctUiSchema = uiSchema?.[childName];
|
|
@@ -130,11 +157,18 @@ const ObjectField = (props) => {
|
|
|
130
157
|
purpose: types_1.ObjectFieldButtonPurpose.ADD,
|
|
131
158
|
onClick: () => {
|
|
132
159
|
const key = prompt("Give key");
|
|
133
|
-
if (key)
|
|
134
|
-
|
|
160
|
+
if (!key)
|
|
161
|
+
return;
|
|
162
|
+
if (Object.prototype.hasOwnProperty.call(value, key))
|
|
163
|
+
return;
|
|
164
|
+
const newValue = { ...value, [key]: DEFAULT_FIELD };
|
|
165
|
+
setValue(newValue);
|
|
166
|
+
if (onAdditionalPropertyOrderChange) {
|
|
167
|
+
const nextOrder = [...orderedAdditionalProperties, key];
|
|
168
|
+
onAdditionalPropertyOrderChange(name, orderedAdditionalProperties, nextOrder);
|
|
135
169
|
}
|
|
136
170
|
},
|
|
137
|
-
uiSchema
|
|
171
|
+
uiSchema,
|
|
138
172
|
})] }) }));
|
|
139
173
|
};
|
|
140
174
|
exports.ObjectField = ObjectField;
|
|
@@ -25,6 +25,8 @@ const ArrayField = (props) => {
|
|
|
25
25
|
templates.ArrayFieldTemplate;
|
|
26
26
|
return ((0, jsx_runtime_1.jsx)(SelectedArrayFieldTemplate, { ...props, items: value, renderItem: (item, index) => typeof item === "object" ? ((0, jsx_runtime_1.jsx)(ArrayFieldItem, { children: (0, jsx_runtime_1.jsx)(SchemaField, { name: `${name}[${index}]`, schema: typeof props.schema.additionalItems !== "boolean"
|
|
27
27
|
? props.schema.additionalItems
|
|
28
|
-
: {},
|
|
28
|
+
: {},
|
|
29
|
+
// TODO: check how form and form view array field handles items and additionalItems schema/uiSchema
|
|
30
|
+
uiSchema: uiSchema?.[index] || uiSchema?.items }) }, index)) : ((0, jsx_runtime_1.jsx)(ArrayFieldItem, { children: (0, jsx_runtime_1.jsx)("div", { "data-keyword": item, children: getValue(item) }) }, item)) }));
|
|
29
31
|
};
|
|
30
32
|
exports.ArrayField = ArrayField;
|
|
@@ -9,7 +9,7 @@ const FormViewRegistry_1 = require("../FormViewRegistry");
|
|
|
9
9
|
const MultipleChoiceField = (props) => {
|
|
10
10
|
const { templates, components: { MultipleChoiceFieldValue }, } = (0, react_1.useContext)(FormViewRegistry_1.FormViewRegistry);
|
|
11
11
|
const { name, uiSchema } = props;
|
|
12
|
-
const { props: inputProps, style } = (0, react_1.useMemo)(() => (0, utils_1.extractUiSchema)(uiSchema), [uiSchema]);
|
|
12
|
+
const { props: inputProps, style, onlyShowSelected, } = (0, react_1.useMemo)(() => (0, utils_1.extractUiSchema)(uiSchema), [uiSchema]);
|
|
13
13
|
const enums = (0, react_1.useMemo)(() => (0, utils_1.getEnums)(props), [props]);
|
|
14
14
|
const { values } = (0, formik_1.useFormikContext)();
|
|
15
15
|
const value = (0, formik_1.getIn)(values, name);
|
|
@@ -19,9 +19,12 @@ const MultipleChoiceField = (props) => {
|
|
|
19
19
|
? value.includes(v.const)
|
|
20
20
|
: value === v.const,
|
|
21
21
|
})) ?? [];
|
|
22
|
+
const displayedValues = onlyShowSelected
|
|
23
|
+
? allValues.filter((v) => v.selected)
|
|
24
|
+
: allValues;
|
|
22
25
|
const SelectedFieldTemplate = (props.uiSchema?.["ui:template"] &&
|
|
23
26
|
templates[props.uiSchema?.["ui:template"]]) ??
|
|
24
27
|
templates.FieldTemplate;
|
|
25
|
-
return ((0, jsx_runtime_1.jsx)(SelectedFieldTemplate, { ...props, children: (0, jsx_runtime_1.jsx)(MultipleChoiceFieldValue, { inputProps: inputProps, name: name, style: style, values:
|
|
28
|
+
return ((0, jsx_runtime_1.jsx)(SelectedFieldTemplate, { ...props, children: (0, jsx_runtime_1.jsx)(MultipleChoiceFieldValue, { inputProps: inputProps, name: name, style: style, values: displayedValues }) }));
|
|
26
29
|
};
|
|
27
30
|
exports.MultipleChoiceField = MultipleChoiceField;
|
|
@@ -41,6 +41,9 @@ const solveReferences_1 = require("./solveReferences");
|
|
|
41
41
|
// @ts-expect-error
|
|
42
42
|
Yup.addMethod(Yup.array, "mixedOf", function ({ itemSchemas, additionalItemSchema }) {
|
|
43
43
|
return Yup.lazy((value) => {
|
|
44
|
+
if (value === undefined) {
|
|
45
|
+
return Yup.mixed().notRequired();
|
|
46
|
+
}
|
|
44
47
|
const valueLength = value?.length ?? 0;
|
|
45
48
|
const numOfAdditionalItems = itemSchemas.length > valueLength ? 0 : valueLength - itemSchemas.length;
|
|
46
49
|
const additionalSchemas = additionalItemSchema
|
|
@@ -172,33 +175,43 @@ function createValidationSchema(schema, definitions = {}, conditionsContext = {}
|
|
|
172
175
|
type = type ?? "object";
|
|
173
176
|
}
|
|
174
177
|
else if (type === "array" && schema.anyOf) {
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
178
|
+
if (!schema.items && !schema.additionalItems) {
|
|
179
|
+
yupSchema = Yup.array();
|
|
180
|
+
}
|
|
181
|
+
else {
|
|
182
|
+
const anyOf = schema.anyOf;
|
|
183
|
+
// anyOf is optional, therefore we cannot change it to array.mixedOf() aka tuple
|
|
184
|
+
const anyOfSchema = Yup.array().of(Yup.lazy(() => {
|
|
185
|
+
// value has to match with one of the anyOf values in the schema
|
|
186
|
+
return Yup.mixed().oneOf(anyOf.map((item) => item.const));
|
|
187
|
+
}));
|
|
188
|
+
// In case the property is required, there should be at least one item in the array
|
|
189
|
+
yupSchema = isRequired ? anyOfSchema.min(1, "Required") : anyOfSchema;
|
|
190
|
+
}
|
|
183
191
|
}
|
|
184
192
|
else if (type === "array") {
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
193
|
+
if (!schema.items && !schema.additionalItems) {
|
|
194
|
+
yupSchema = Yup.array();
|
|
195
|
+
}
|
|
196
|
+
else {
|
|
197
|
+
const additionalItemSchema = (() => {
|
|
198
|
+
const additionalItems = schema.additionalItems;
|
|
199
|
+
if (!additionalItems) {
|
|
200
|
+
return undefined;
|
|
201
|
+
}
|
|
202
|
+
// Yup.lazy() enables validation for infinitely nested schemas
|
|
203
|
+
// aka references that refer to themselves or in circular references
|
|
204
|
+
return Yup.lazy(() => {
|
|
205
|
+
return getValue(schema?.additionalItems, "#ignore-this", true);
|
|
206
|
+
});
|
|
207
|
+
})();
|
|
208
|
+
const schemaItems = schema?.items ?? [];
|
|
209
|
+
const items = Array.isArray(schemaItems) ? schemaItems : [schemaItems];
|
|
210
|
+
yupSchema = Yup.array().mixedOf({
|
|
211
|
+
itemSchemas: items.map((item) => getValue(item, "#ignore-this", true)),
|
|
212
|
+
additionalItemSchema,
|
|
194
213
|
});
|
|
195
|
-
}
|
|
196
|
-
const schemaItems = schema?.items ?? [];
|
|
197
|
-
const items = Array.isArray(schemaItems) ? schemaItems : [schemaItems];
|
|
198
|
-
yupSchema = Yup.array().mixedOf({
|
|
199
|
-
itemSchemas: items.map((item) => getValue(item, "#ignore-this", true)),
|
|
200
|
-
additionalItemSchema,
|
|
201
|
-
});
|
|
214
|
+
}
|
|
202
215
|
}
|
|
203
216
|
else {
|
|
204
217
|
yupSchema = getYupType(schema);
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.immutablySwapItems = immutablySwapItems;
|
|
4
|
+
function immutablySwapItems(items, firstIndex, secondIndex) {
|
|
5
|
+
const results = items.slice();
|
|
6
|
+
const firstItem = items[firstIndex];
|
|
7
|
+
results[firstIndex] = items[secondIndex];
|
|
8
|
+
results[secondIndex] = firstItem;
|
|
9
|
+
return results;
|
|
10
|
+
}
|
package/dist/cjs/utils/index.js
CHANGED
|
@@ -28,3 +28,4 @@ __exportStar(require("./createValidationSchema"), exports);
|
|
|
28
28
|
__exportStar(require("./orderByUiSchema"), exports);
|
|
29
29
|
__exportStar(require("./orderAdditionalProperties"), exports);
|
|
30
30
|
__exportStar(require("./setTitleValues"), exports);
|
|
31
|
+
__exportStar(require("./immutablySwapItems"), exports);
|
package/dist/esm/Form/Form.js
CHANGED
|
@@ -6,7 +6,7 @@ import { fields as defaultFields } from "./fields";
|
|
|
6
6
|
import { templates as defaultTemplates } from "./templates";
|
|
7
7
|
export const Form = (props) => {
|
|
8
8
|
const { isSubmitting } = useFormikContext();
|
|
9
|
-
const { schema, uiSchema = {}, className, children, fields = {}, templates = {}, components = {}, formContext = {}, formOptions = {}, formLocalization = {}, useItemsAsAdditionalItems = false, hideUnmarkedAdditionalProperties = false, hideSubmit = false, } = props;
|
|
9
|
+
const { schema, uiSchema = {}, className, children, fields = {}, templates = {}, components = {}, formContext = {}, formOptions = {}, formLocalization = {}, useItemsAsAdditionalItems = false, hideUnmarkedAdditionalProperties = false, onAdditionalPropertyOrderChange, hideSubmit = false, } = props;
|
|
10
10
|
const schemaDefinitions = schema.definitions;
|
|
11
11
|
const uiSchemaDefinitions = uiSchema?.definitions;
|
|
12
12
|
const registry = {
|
|
@@ -26,6 +26,7 @@ export const Form = (props) => {
|
|
|
26
26
|
formLocalization,
|
|
27
27
|
useItemsAsAdditionalItems,
|
|
28
28
|
hideUnmarkedAdditionalProperties,
|
|
29
|
+
onAdditionalPropertyOrderChange,
|
|
29
30
|
};
|
|
30
31
|
const { Form: FormEl, FormButton, FormButtonWrapper } = registry.components;
|
|
31
32
|
const SchemaField = registry.fields.SchemaField;
|
|
@@ -34,7 +34,7 @@ export const ArrayField = (props) => {
|
|
|
34
34
|
const { fields: { SchemaField }, templates, components: { SelectFieldInput, ArrayFieldItem, ArrayFieldItemButtons, ArrayFieldAddButton, ArrayFieldRemoveButton, ArrayFieldUpButton, ArrayFieldDownButton, }, useItemsAsAdditionalItems, } = useContext(FormRegistry);
|
|
35
35
|
useSetDefault(props);
|
|
36
36
|
const { name, schema, uiSchema } = props;
|
|
37
|
-
const { type, props: inputProps } = useMemo(() => extractUiSchema(uiSchema), [uiSchema]);
|
|
37
|
+
const { type, props: inputProps, disabled, removeButton, upButton, downButton, addButton, } = useMemo(() => extractUiSchema(uiSchema), [uiSchema]);
|
|
38
38
|
const [{ value }, _, { setValue }] = useField(name);
|
|
39
39
|
const schemas = useMemo(() => {
|
|
40
40
|
let items = schema.items && typeof schema.items !== "boolean" ? schema.items : [];
|
|
@@ -95,7 +95,6 @@ export const ArrayField = (props) => {
|
|
|
95
95
|
// [schema]
|
|
96
96
|
// );
|
|
97
97
|
// Backwards compatibility ends
|
|
98
|
-
const { disabled } = useMemo(() => extractUiSchema(uiSchema), [uiSchema]);
|
|
99
98
|
const valueArray = Array.isArray(value) ? value : undefined;
|
|
100
99
|
const preventManipulation = disabled || schema.readOnly;
|
|
101
100
|
const SelectedFieldTemplate = (props.uiSchema?.["ui:template"] &&
|
|
@@ -113,8 +112,8 @@ export const ArrayField = (props) => {
|
|
|
113
112
|
},
|
|
114
113
|
// "true" will prevent validation for required array fields
|
|
115
114
|
// since a value always exists in the array
|
|
116
|
-
forceDefaultValue: index >= schemas.items.length }), !preventManipulation && index >= schemas.items.length && (_jsxs(ArrayFieldItemButtons, { children: [_jsx(ArrayFieldRemoveButton, { id: value?.[index + schemas.items.length]?.name, ...(
|
|
117
|
-
index < value?.slice(schemas.items.length).length - 1 && (_jsx(ArrayFieldDownButton, { ...(
|
|
115
|
+
forceDefaultValue: index >= schemas.items.length }), !preventManipulation && index >= schemas.items.length && (_jsxs(ArrayFieldItemButtons, { children: [_jsx(ArrayFieldRemoveButton, { id: value?.[index + schemas.items.length]?.name, ...(removeButton?.props ?? {}), onClick: () => setValue(removeFromArray(value, index + schemas.items.length)), children: removeButton?.content ?? "-" }), value.length > 1 && index > 0 && (_jsx(ArrayFieldUpButton, { ...(upButton?.props ?? {}), onClick: () => setValue(moveInArray(value, index + schemas.items.length, -1)), children: upButton?.content ?? "↑" })), value.length > 1 &&
|
|
116
|
+
index < value?.slice(schemas.items.length).length - 1 && (_jsx(ArrayFieldDownButton, { ...(downButton?.props ?? {}), onClick: () => setValue(moveInArray(value, index + schemas.items.length, 1)), children: downButton?.content ?? "↓" }))] }))] }, index)) }), schemas.additionalItems && !preventManipulation && (_jsx(ArrayFieldAddButton, { ...(addButton?.props ?? {}), onClick: () => setValue(appendArray(value, schemas.additionalItems)), children: addButton?.content ?? "+" }))] }));
|
|
118
117
|
};
|
|
119
118
|
function prepareChildSchema(childSchema, parentSchema) {
|
|
120
119
|
if (!childSchema || typeof childSchema === "boolean") {
|
|
@@ -5,7 +5,8 @@ import { FormRegistry } from "../../FormRegistry";
|
|
|
5
5
|
import { EnumsTypes } from "../../../utils";
|
|
6
6
|
export const MultipleChoiceFieldInput = ({ inputProps, name, className, enums, style, value, form, }) => {
|
|
7
7
|
const { components: { MultipleChoiceFieldContainer, MultipleChoiceFieldElement, MultipleChoiceFieldInputElement, MultipleChoiceFieldLabel, }, } = useContext(FormRegistry);
|
|
8
|
-
const
|
|
8
|
+
const safeEnums = enums ?? { type: "", values: [] };
|
|
9
|
+
const isMultiSelect = safeEnums.type === EnumsTypes.MULTI_SELECT;
|
|
9
10
|
const currentValue = isMultiSelect
|
|
10
11
|
? Array.isArray(value)
|
|
11
12
|
? value
|
|
@@ -28,7 +29,7 @@ export const MultipleChoiceFieldInput = ({ inputProps, name, className, enums, s
|
|
|
28
29
|
form?.setFieldValue(name, optionValue);
|
|
29
30
|
}
|
|
30
31
|
};
|
|
31
|
-
return (_jsx(MultipleChoiceFieldContainer, { className: className, style: getStyle(style ?? ""), children:
|
|
32
|
+
return (_jsx(MultipleChoiceFieldContainer, { className: className, style: getStyle(style ?? ""), children: (safeEnums.values ?? []).map((v) => {
|
|
32
33
|
const optionValue = v.const;
|
|
33
34
|
return (_jsxs(MultipleChoiceFieldElement, { "data-fjsf-enum-value": optionValue, children: [_jsx(MultipleChoiceFieldInputElement, { ...inputProps, name: name, type: isMultiSelect ? "checkbox" : "radio", value: optionValue !== undefined ? optionValue.toString() : "", checked: isChecked(optionValue), onChange: () => handleChange(optionValue) }), _jsx(MultipleChoiceFieldLabel, { children: v.title })] }, optionValue !== undefined ? optionValue.toString() : "undefined"));
|
|
34
35
|
}) }));
|
|
@@ -2,10 +2,15 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
2
2
|
import { useField, useFormikContext } from "formik";
|
|
3
3
|
import { useContext, useEffect, useMemo } from "react";
|
|
4
4
|
import { ObjectFieldWrapper } from "./styledComponents";
|
|
5
|
-
import { getHiddenProperties, orderAdditionalProperties, orderByUiSchema, resolveSchema, } from "../../../utils";
|
|
5
|
+
import { extractUiSchema, getHiddenProperties, immutablySwapItems, orderAdditionalProperties, orderByUiSchema, resolveSchema, } from "../../../utils";
|
|
6
6
|
import { useSetDefault } from "../../hooks";
|
|
7
7
|
import { FormRegistry } from "../../FormRegistry";
|
|
8
8
|
import { ObjectFieldButtonPurpose } from "./types";
|
|
9
|
+
const DEFAULT_FIELD = {
|
|
10
|
+
type: "string",
|
|
11
|
+
_fieldType: "string",
|
|
12
|
+
"ui:title": "New Field",
|
|
13
|
+
};
|
|
9
14
|
const useObjectField = (name) => {
|
|
10
15
|
if (!name) {
|
|
11
16
|
const { values = {}, setValues } = useFormikContext();
|
|
@@ -15,9 +20,10 @@ const useObjectField = (name) => {
|
|
|
15
20
|
return { value, setValue };
|
|
16
21
|
};
|
|
17
22
|
export const ObjectField = (props) => {
|
|
18
|
-
const { fields: { SchemaField }, templates, components: { ObjectFieldItem, ObjectFieldItemButtons, ObjectFieldButton, ObjectFieldAddButton, ObjectFieldRemoveButton, ObjectFieldUpButton, ObjectFieldDownButton, ObjectFieldSection, }, hideUnmarkedAdditionalProperties, } = useContext(FormRegistry);
|
|
23
|
+
const { fields: { SchemaField }, templates, components: { ObjectFieldItem, ObjectFieldItemButtons, ObjectFieldButton, ObjectFieldAddButton, ObjectFieldRemoveButton, ObjectFieldUpButton, ObjectFieldDownButton, ObjectFieldSection, }, hideUnmarkedAdditionalProperties, onAdditionalPropertyOrderChange, } = useContext(FormRegistry);
|
|
19
24
|
useSetDefault(props);
|
|
20
25
|
const { name, schema, uiSchema } = props;
|
|
26
|
+
const { type, props: inputProps, isCollapsible, order, disabled, } = useMemo(() => extractUiSchema(uiSchema), [uiSchema]);
|
|
21
27
|
const { value, setValue } = useObjectField(name);
|
|
22
28
|
const [{ properties, additionalProperties, required }, valuesToRemove] = useMemo(() => {
|
|
23
29
|
return resolveSchema(schema, value);
|
|
@@ -33,27 +39,28 @@ export const ObjectField = (props) => {
|
|
|
33
39
|
}, [valuesToRemove]);
|
|
34
40
|
const propertyKeys = useMemo(() => Object.keys(properties || {}), [properties]);
|
|
35
41
|
const additionalPropertyKeys = useMemo(() => Object.keys(value || {}).filter((key) => !propertyKeys.includes(key)), [value, propertyKeys]);
|
|
36
|
-
const orderedProperties = orderByUiSchema(
|
|
37
|
-
const hiddenProperties = getHiddenProperties(
|
|
38
|
-
const orderedAdditionalProperties = orderAdditionalProperties(
|
|
39
|
-
const hiddenAdditionalProperties = getHiddenProperties(
|
|
42
|
+
const orderedProperties = orderByUiSchema(order, propertyKeys);
|
|
43
|
+
const hiddenProperties = getHiddenProperties(order, propertyKeys);
|
|
44
|
+
const orderedAdditionalProperties = orderAdditionalProperties(order, additionalPropertyKeys);
|
|
45
|
+
const hiddenAdditionalProperties = getHiddenProperties(order, additionalPropertyKeys);
|
|
40
46
|
const getObjectFieldButton = ({ purpose, onClick, uiSchema, }) => {
|
|
47
|
+
const { removeButton, upButton, downButton, addButton, customButton } = extractUiSchema(uiSchema);
|
|
41
48
|
switch (purpose) {
|
|
42
49
|
case ObjectFieldButtonPurpose.ADD:
|
|
43
|
-
return (_jsx(ObjectFieldAddButton, { ...(
|
|
50
|
+
return (_jsx(ObjectFieldAddButton, { ...(addButton?.props ?? {}), onClick: onClick, children: addButton?.content ?? "+" }));
|
|
44
51
|
case ObjectFieldButtonPurpose.REMOVE:
|
|
45
|
-
return (_jsx(ObjectFieldRemoveButton, { ...(
|
|
52
|
+
return (_jsx(ObjectFieldRemoveButton, { ...(removeButton?.props ?? {}), onClick: onClick, children: removeButton?.content ?? "-" }));
|
|
46
53
|
case ObjectFieldButtonPurpose.MOVE_UP:
|
|
47
|
-
return (_jsx(ObjectFieldUpButton, { ...(
|
|
54
|
+
return (_jsx(ObjectFieldUpButton, { ...(upButton?.props ?? {}), onClick: onClick, children: upButton?.content ?? "↑" }));
|
|
48
55
|
case ObjectFieldButtonPurpose.MOVE_DOWN:
|
|
49
|
-
return (_jsx(ObjectFieldDownButton, { ...(
|
|
56
|
+
return (_jsx(ObjectFieldDownButton, { ...(downButton?.props ?? {}), onClick: onClick, children: downButton?.content ?? "↓" }));
|
|
50
57
|
default:
|
|
51
|
-
return (_jsx(ObjectFieldButton, { ...(
|
|
58
|
+
return (_jsx(ObjectFieldButton, { ...(customButton?.props ?? {}), onClick: onClick, children: customButton?.content ?? "" }));
|
|
52
59
|
}
|
|
53
60
|
};
|
|
54
|
-
const SelectedObjectFieldTemplate = (
|
|
55
|
-
templates[
|
|
56
|
-
(
|
|
61
|
+
const SelectedObjectFieldTemplate = (uiSchema?.["ui:template"] &&
|
|
62
|
+
templates[uiSchema?.["ui:template"]]) ??
|
|
63
|
+
(isCollapsible
|
|
57
64
|
? templates.CollapsibleObjectFieldTemplate
|
|
58
65
|
: templates.ObjectFieldTemplate);
|
|
59
66
|
const showAdditionalProperties = !hideUnmarkedAdditionalProperties || !!additionalProperties;
|
|
@@ -94,7 +101,7 @@ export const ObjectField = (props) => {
|
|
|
94
101
|
},
|
|
95
102
|
}, style: { display: "none" } }, child));
|
|
96
103
|
}), showAdditionalProperties &&
|
|
97
|
-
orderedAdditionalProperties.map((childName) => {
|
|
104
|
+
orderedAdditionalProperties.map((childName, index) => {
|
|
98
105
|
let correctUiSchema = uiSchema?.[childName];
|
|
99
106
|
if (uiSchema?.properties?.["ui:order"] !== undefined &&
|
|
100
107
|
uiSchema?.[childName]?.["ui:order"] === undefined) {
|
|
@@ -103,14 +110,34 @@ export const ObjectField = (props) => {
|
|
|
103
110
|
"ui:order": uiSchema.properties?.["ui:order"],
|
|
104
111
|
};
|
|
105
112
|
}
|
|
106
|
-
return (_jsxs(ObjectFieldItem, { children: [_jsx(SchemaField, { required: required?.includes(childName), name: name ? [name, childName].join(".") : childName, schema: prepareChildSchema(schema.additionalProperties, schema), uiSchema: correctUiSchema }, childName),
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
113
|
+
return (_jsxs(ObjectFieldItem, { children: [_jsx(SchemaField, { required: required?.includes(childName), name: name ? [name, childName].join(".") : childName, schema: prepareChildSchema(schema.additionalProperties, schema), uiSchema: correctUiSchema }, childName), _jsxs(ObjectFieldItemButtons, { children: [onAdditionalPropertyOrderChange &&
|
|
114
|
+
index > 0 &&
|
|
115
|
+
getObjectFieldButton({
|
|
116
|
+
purpose: ObjectFieldButtonPurpose.MOVE_UP,
|
|
117
|
+
onClick: () => {
|
|
118
|
+
onAdditionalPropertyOrderChange(name, orderedAdditionalProperties, immutablySwapItems(orderedAdditionalProperties, index, index - 1));
|
|
119
|
+
},
|
|
120
|
+
uiSchema,
|
|
121
|
+
}), onAdditionalPropertyOrderChange &&
|
|
122
|
+
index < orderedAdditionalProperties.length - 1 &&
|
|
123
|
+
getObjectFieldButton({
|
|
124
|
+
purpose: ObjectFieldButtonPurpose.MOVE_DOWN,
|
|
125
|
+
onClick: () => {
|
|
126
|
+
onAdditionalPropertyOrderChange(name, orderedAdditionalProperties, immutablySwapItems(orderedAdditionalProperties, index, index + 1));
|
|
127
|
+
},
|
|
128
|
+
uiSchema,
|
|
129
|
+
}), getObjectFieldButton({
|
|
130
|
+
purpose: ObjectFieldButtonPurpose.REMOVE,
|
|
131
|
+
onClick: () => {
|
|
132
|
+
const { [childName]: _removedProperty, ...newValue } = value;
|
|
133
|
+
setValue(newValue);
|
|
134
|
+
if (onAdditionalPropertyOrderChange) {
|
|
135
|
+
const nextOrder = orderedAdditionalProperties.filter((k) => k !== childName);
|
|
136
|
+
onAdditionalPropertyOrderChange(name, orderedAdditionalProperties, nextOrder);
|
|
137
|
+
}
|
|
138
|
+
},
|
|
139
|
+
uiSchema,
|
|
140
|
+
})] })] }, childName));
|
|
114
141
|
}), showAdditionalProperties &&
|
|
115
142
|
hiddenAdditionalProperties.map((childName) => {
|
|
116
143
|
let correctUiSchema = uiSchema?.[childName];
|
|
@@ -127,11 +154,18 @@ export const ObjectField = (props) => {
|
|
|
127
154
|
purpose: ObjectFieldButtonPurpose.ADD,
|
|
128
155
|
onClick: () => {
|
|
129
156
|
const key = prompt("Give key");
|
|
130
|
-
if (key)
|
|
131
|
-
|
|
157
|
+
if (!key)
|
|
158
|
+
return;
|
|
159
|
+
if (Object.prototype.hasOwnProperty.call(value, key))
|
|
160
|
+
return;
|
|
161
|
+
const newValue = { ...value, [key]: DEFAULT_FIELD };
|
|
162
|
+
setValue(newValue);
|
|
163
|
+
if (onAdditionalPropertyOrderChange) {
|
|
164
|
+
const nextOrder = [...orderedAdditionalProperties, key];
|
|
165
|
+
onAdditionalPropertyOrderChange(name, orderedAdditionalProperties, nextOrder);
|
|
132
166
|
}
|
|
133
167
|
},
|
|
134
|
-
uiSchema
|
|
168
|
+
uiSchema,
|
|
135
169
|
})] }) }));
|
|
136
170
|
};
|
|
137
171
|
function prepareChildSchema(childSchema, parentSchema) {
|
|
@@ -22,5 +22,7 @@ export const ArrayField = (props) => {
|
|
|
22
22
|
templates.ArrayFieldTemplate;
|
|
23
23
|
return (_jsx(SelectedArrayFieldTemplate, { ...props, items: value, renderItem: (item, index) => typeof item === "object" ? (_jsx(ArrayFieldItem, { children: _jsx(SchemaField, { name: `${name}[${index}]`, schema: typeof props.schema.additionalItems !== "boolean"
|
|
24
24
|
? props.schema.additionalItems
|
|
25
|
-
: {},
|
|
25
|
+
: {},
|
|
26
|
+
// TODO: check how form and form view array field handles items and additionalItems schema/uiSchema
|
|
27
|
+
uiSchema: uiSchema?.[index] || uiSchema?.items }) }, index)) : (_jsx(ArrayFieldItem, { children: _jsx("div", { "data-keyword": item, children: getValue(item) }) }, item)) }));
|
|
26
28
|
};
|
|
@@ -6,7 +6,7 @@ import { FormViewRegistry } from "../FormViewRegistry";
|
|
|
6
6
|
export const MultipleChoiceField = (props) => {
|
|
7
7
|
const { templates, components: { MultipleChoiceFieldValue }, } = useContext(FormViewRegistry);
|
|
8
8
|
const { name, uiSchema } = props;
|
|
9
|
-
const { props: inputProps, style } = useMemo(() => extractUiSchema(uiSchema), [uiSchema]);
|
|
9
|
+
const { props: inputProps, style, onlyShowSelected, } = useMemo(() => extractUiSchema(uiSchema), [uiSchema]);
|
|
10
10
|
const enums = useMemo(() => getEnums(props), [props]);
|
|
11
11
|
const { values } = useFormikContext();
|
|
12
12
|
const value = getIn(values, name);
|
|
@@ -16,8 +16,11 @@ export const MultipleChoiceField = (props) => {
|
|
|
16
16
|
? value.includes(v.const)
|
|
17
17
|
: value === v.const,
|
|
18
18
|
})) ?? [];
|
|
19
|
+
const displayedValues = onlyShowSelected
|
|
20
|
+
? allValues.filter((v) => v.selected)
|
|
21
|
+
: allValues;
|
|
19
22
|
const SelectedFieldTemplate = (props.uiSchema?.["ui:template"] &&
|
|
20
23
|
templates[props.uiSchema?.["ui:template"]]) ??
|
|
21
24
|
templates.FieldTemplate;
|
|
22
|
-
return (_jsx(SelectedFieldTemplate, { ...props, children: _jsx(MultipleChoiceFieldValue, { inputProps: inputProps, name: name, style: style, values:
|
|
25
|
+
return (_jsx(SelectedFieldTemplate, { ...props, children: _jsx(MultipleChoiceFieldValue, { inputProps: inputProps, name: name, style: style, values: displayedValues }) }));
|
|
23
26
|
};
|
|
@@ -5,6 +5,9 @@ import { solveReferences } from "./solveReferences";
|
|
|
5
5
|
// @ts-expect-error
|
|
6
6
|
Yup.addMethod(Yup.array, "mixedOf", function ({ itemSchemas, additionalItemSchema }) {
|
|
7
7
|
return Yup.lazy((value) => {
|
|
8
|
+
if (value === undefined) {
|
|
9
|
+
return Yup.mixed().notRequired();
|
|
10
|
+
}
|
|
8
11
|
const valueLength = value?.length ?? 0;
|
|
9
12
|
const numOfAdditionalItems = itemSchemas.length > valueLength ? 0 : valueLength - itemSchemas.length;
|
|
10
13
|
const additionalSchemas = additionalItemSchema
|
|
@@ -136,33 +139,43 @@ export function createValidationSchema(schema, definitions = {}, conditionsConte
|
|
|
136
139
|
type = type ?? "object";
|
|
137
140
|
}
|
|
138
141
|
else if (type === "array" && schema.anyOf) {
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
142
|
+
if (!schema.items && !schema.additionalItems) {
|
|
143
|
+
yupSchema = Yup.array();
|
|
144
|
+
}
|
|
145
|
+
else {
|
|
146
|
+
const anyOf = schema.anyOf;
|
|
147
|
+
// anyOf is optional, therefore we cannot change it to array.mixedOf() aka tuple
|
|
148
|
+
const anyOfSchema = Yup.array().of(Yup.lazy(() => {
|
|
149
|
+
// value has to match with one of the anyOf values in the schema
|
|
150
|
+
return Yup.mixed().oneOf(anyOf.map((item) => item.const));
|
|
151
|
+
}));
|
|
152
|
+
// In case the property is required, there should be at least one item in the array
|
|
153
|
+
yupSchema = isRequired ? anyOfSchema.min(1, "Required") : anyOfSchema;
|
|
154
|
+
}
|
|
147
155
|
}
|
|
148
156
|
else if (type === "array") {
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
157
|
+
if (!schema.items && !schema.additionalItems) {
|
|
158
|
+
yupSchema = Yup.array();
|
|
159
|
+
}
|
|
160
|
+
else {
|
|
161
|
+
const additionalItemSchema = (() => {
|
|
162
|
+
const additionalItems = schema.additionalItems;
|
|
163
|
+
if (!additionalItems) {
|
|
164
|
+
return undefined;
|
|
165
|
+
}
|
|
166
|
+
// Yup.lazy() enables validation for infinitely nested schemas
|
|
167
|
+
// aka references that refer to themselves or in circular references
|
|
168
|
+
return Yup.lazy(() => {
|
|
169
|
+
return getValue(schema?.additionalItems, "#ignore-this", true);
|
|
170
|
+
});
|
|
171
|
+
})();
|
|
172
|
+
const schemaItems = schema?.items ?? [];
|
|
173
|
+
const items = Array.isArray(schemaItems) ? schemaItems : [schemaItems];
|
|
174
|
+
yupSchema = Yup.array().mixedOf({
|
|
175
|
+
itemSchemas: items.map((item) => getValue(item, "#ignore-this", true)),
|
|
176
|
+
additionalItemSchema,
|
|
158
177
|
});
|
|
159
|
-
}
|
|
160
|
-
const schemaItems = schema?.items ?? [];
|
|
161
|
-
const items = Array.isArray(schemaItems) ? schemaItems : [schemaItems];
|
|
162
|
-
yupSchema = Yup.array().mixedOf({
|
|
163
|
-
itemSchemas: items.map((item) => getValue(item, "#ignore-this", true)),
|
|
164
|
-
additionalItemSchema,
|
|
165
|
-
});
|
|
178
|
+
}
|
|
166
179
|
}
|
|
167
180
|
else {
|
|
168
181
|
yupSchema = getYupType(schema);
|
package/dist/esm/utils/index.js
CHANGED
|
@@ -19,4 +19,5 @@ export type FormRegistryContext = {
|
|
|
19
19
|
formOptions?: Record<string, any>;
|
|
20
20
|
useItemsAsAdditionalItems: boolean;
|
|
21
21
|
hideUnmarkedAdditionalProperties: boolean;
|
|
22
|
+
onAdditionalPropertyOrderChange?: (fieldName: string, oldOrder: string[], newOrder: string[]) => void;
|
|
22
23
|
};
|
|
@@ -8,6 +8,8 @@ export type FormProps<T> = React.PropsWithChildren<{
|
|
|
8
8
|
useItemsAsAdditionalItems?: boolean | undefined;
|
|
9
9
|
/** If true, properties in object fields' data that aren't in the schema will only be displayed if `additionalProperties` is enabled in the schema */
|
|
10
10
|
hideUnmarkedAdditionalProperties?: boolean;
|
|
11
|
+
/** If passed, enables the ordering of the additional properties in ObjectField. Actual ordering logic needs to be handled by this function as it involvces manipulating uiSchema, which is out side of the ObjectFields control*/
|
|
12
|
+
onAdditionalPropertyOrderChange?: (fieldName: string, oldOrder: string[], newOrder: string[]) => void;
|
|
11
13
|
className?: string | undefined;
|
|
12
14
|
/** Form schema */
|
|
13
15
|
schema: Schema;
|
|
@@ -43,51 +43,6 @@ export type UiSchema = {
|
|
|
43
43
|
[key: string]: any;
|
|
44
44
|
};
|
|
45
45
|
};
|
|
46
|
-
/**
|
|
47
|
-
* @deprecated Will be moved to "ui:options"
|
|
48
|
-
*/
|
|
49
|
-
"ui:addButtonOptions"?: {
|
|
50
|
-
props?: {
|
|
51
|
-
[key: string]: any;
|
|
52
|
-
};
|
|
53
|
-
content?: React.ReactNode | string;
|
|
54
|
-
};
|
|
55
|
-
/**
|
|
56
|
-
* @deprecated Will be moved to "ui:options"
|
|
57
|
-
*/
|
|
58
|
-
"ui:removeButtonOptions"?: {
|
|
59
|
-
props?: {
|
|
60
|
-
[key: string]: any;
|
|
61
|
-
};
|
|
62
|
-
content?: React.ReactNode | string;
|
|
63
|
-
};
|
|
64
|
-
/**
|
|
65
|
-
* @deprecated Will be moved to "ui:options"
|
|
66
|
-
*/
|
|
67
|
-
"ui:upButtonOptions"?: {
|
|
68
|
-
props?: {
|
|
69
|
-
[key: string]: any;
|
|
70
|
-
};
|
|
71
|
-
content?: React.ReactNode | string;
|
|
72
|
-
};
|
|
73
|
-
/**
|
|
74
|
-
* @deprecated Will be moved to "ui:options"
|
|
75
|
-
*/
|
|
76
|
-
"ui:downButtonOptions"?: {
|
|
77
|
-
props?: {
|
|
78
|
-
[key: string]: any;
|
|
79
|
-
};
|
|
80
|
-
content?: React.ReactNode | string;
|
|
81
|
-
};
|
|
82
|
-
/**
|
|
83
|
-
* @deprecated Will be moved to "ui:options"
|
|
84
|
-
*/
|
|
85
|
-
"ui:customButtonOptions"?: {
|
|
86
|
-
props?: {
|
|
87
|
-
[key: string]: any;
|
|
88
|
-
};
|
|
89
|
-
content?: React.ReactNode | string;
|
|
90
|
-
};
|
|
91
46
|
} & {
|
|
92
47
|
[key: string]: UiSchema | any;
|
|
93
48
|
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function immutablySwapItems<T>(items: T[], firstIndex: number, secondIndex: number): T[];
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nolwenture/formik-jsonschema-form",
|
|
3
|
-
"version": "1.3.
|
|
3
|
+
"version": "1.3.6",
|
|
4
4
|
"description": "Formik form generation from json schema",
|
|
5
5
|
"author": "anttivikman <antti.vikman@nolwenture.com>",
|
|
6
6
|
"contributors": [
|
|
@@ -125,4 +125,4 @@
|
|
|
125
125
|
"last 1 safari version"
|
|
126
126
|
]
|
|
127
127
|
}
|
|
128
|
-
}
|
|
128
|
+
}
|