@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 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
- - "ui:addButtonOptions"
293
- - "ui:removeButtonOptions"
294
- - "ui:upButtonOptions"
295
- - "ui:downButtonOptions"
296
- - "ui:customButtonOptions"
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
- someArray: {
321
- "ui:addButtonOptions": {
322
- content: <b>Hello!</b>,
323
- props: { style: { background: "green" } },
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
  ...
@@ -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, ...(uiSchema?.["ui:removeButtonOptions"]?.props ?? {}), onClick: () => setValue(removeFromArray(value, index + schemas.items.length)), children: uiSchema?.["ui:removeButtonOptions"]?.content ?? "-" }), value.length > 1 && index > 0 && ((0, jsx_runtime_1.jsx)(ArrayFieldUpButton, { ...(uiSchema?.["ui:upButtonOptions"]?.props ?? {}), onClick: () => setValue(moveInArray(value, index + schemas.items.length, -1)), children: uiSchema?.["ui:upButtonOptions"]?.content ?? "↑" })), value.length > 1 &&
120
- index < value?.slice(schemas.items.length).length - 1 && ((0, jsx_runtime_1.jsx)(ArrayFieldDownButton, { ...(uiSchema?.["ui:downButtonOptions"]?.props ?? {}), onClick: () => setValue(moveInArray(value, index + schemas.items.length, 1)), children: uiSchema?.["ui:downButtonOptions"]?.content ?? "↓" }))] }))] }, index)) }), schemas.additionalItems && !preventManipulation && ((0, jsx_runtime_1.jsx)(ArrayFieldAddButton, { ...(uiSchema?.["ui:addButtonOptions"]?.props ?? {}), onClick: () => setValue(appendArray(value, schemas.additionalItems)), children: uiSchema?.["ui:addButtonOptions"]?.content ?? "+" }))] }));
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 isMultiSelect = enums.type === utils_1.EnumsTypes.MULTI_SELECT;
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: enums.values.map((v) => {
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)(uiSchema?.["ui:order"], propertyKeys);
40
- const hiddenProperties = (0, utils_1.getHiddenProperties)(uiSchema?.["ui:order"], propertyKeys);
41
- const orderedAdditionalProperties = (0, utils_1.orderAdditionalProperties)(uiSchema?.["ui:order"], additionalPropertyKeys);
42
- const hiddenAdditionalProperties = (0, utils_1.getHiddenProperties)(uiSchema?.["ui:order"], additionalPropertyKeys);
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, { ...(uiSchema?.["ui:addButtonOptions"]?.props ?? {}), onClick: onClick, children: uiSchema?.["ui:addButtonOptions"]?.content ?? "+" }));
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, { ...(uiSchema?.["ui:removeButtonOptions"]?.props ?? {}), onClick: onClick, children: uiSchema?.["ui:removeButtonOptions"]?.content ?? "-" }));
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, { ...(uiSchema?.["ui:upButtonOptions"]?.props ?? {}), onClick: onClick, children: uiSchema?.["ui:upButtonOptions"]?.content ?? "↑" }));
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, { ...(uiSchema?.["ui:downButtonOptions"]?.props ?? {}), onClick: onClick, children: uiSchema?.["ui:downButtonOptions"]?.content ?? "↓" }));
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, { ...(uiSchema?.["ui:customButtonOptions"]?.props ?? {}), onClick: onClick, children: uiSchema?.["ui:customButtonOptions"]?.content ?? "" }));
61
+ return ((0, jsx_runtime_1.jsx)(ObjectFieldButton, { ...(customButton?.props ?? {}), onClick: onClick, children: customButton?.content ?? "" }));
55
62
  }
56
63
  };
57
- const SelectedObjectFieldTemplate = (props.uiSchema?.["ui:template"] &&
58
- templates[props.uiSchema?.["ui:template"]]) ??
59
- (props.uiSchema?.["ui:options"]?.isCollapsible
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.jsx)(ObjectFieldItemButtons, { children: getObjectFieldButton({
110
- purpose: types_1.ObjectFieldButtonPurpose.REMOVE,
111
- onClick: () => {
112
- const { [childName]: _removedProperty, ...newValue } = value;
113
- setValue(newValue);
114
- },
115
- uiSchema: uiSchema,
116
- }) })] }, childName));
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
- setValue({ ...value, [key]: undefined });
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: 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
- : {}, uiSchema: uiSchema }) }, index)) : ((0, jsx_runtime_1.jsx)(ArrayFieldItem, { children: (0, jsx_runtime_1.jsx)("div", { "data-keyword": item, children: getValue(item) }) }, item)) }));
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: allValues }) }));
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
- const anyOf = schema.anyOf;
176
- // anyOf is optional, therefore we cannot change it to array.mixedOf() aka tuple
177
- const anyOfSchema = Yup.array().of(Yup.lazy(() => {
178
- // value has to match with one of the anyOf values in the schema
179
- return Yup.mixed().oneOf(anyOf.map((item) => item.const));
180
- }));
181
- // In case the property is required, there should be at least one item in the array
182
- yupSchema = isRequired ? anyOfSchema.min(1, "Required") : anyOfSchema;
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
- const additionalItemSchema = (() => {
186
- const additionalItems = schema.additionalItems;
187
- if (!additionalItems) {
188
- return undefined;
189
- }
190
- // Yup.lazy() enables validation for infinitely nested schemas
191
- // aka references that refer to themselves or in circular references
192
- return Yup.lazy(() => {
193
- return getValue(schema?.additionalItems, "#ignore-this", true);
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
+ }
@@ -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);
@@ -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, ...(uiSchema?.["ui:removeButtonOptions"]?.props ?? {}), onClick: () => setValue(removeFromArray(value, index + schemas.items.length)), children: uiSchema?.["ui:removeButtonOptions"]?.content ?? "-" }), value.length > 1 && index > 0 && (_jsx(ArrayFieldUpButton, { ...(uiSchema?.["ui:upButtonOptions"]?.props ?? {}), onClick: () => setValue(moveInArray(value, index + schemas.items.length, -1)), children: uiSchema?.["ui:upButtonOptions"]?.content ?? "↑" })), value.length > 1 &&
117
- index < value?.slice(schemas.items.length).length - 1 && (_jsx(ArrayFieldDownButton, { ...(uiSchema?.["ui:downButtonOptions"]?.props ?? {}), onClick: () => setValue(moveInArray(value, index + schemas.items.length, 1)), children: uiSchema?.["ui:downButtonOptions"]?.content ?? "↓" }))] }))] }, index)) }), schemas.additionalItems && !preventManipulation && (_jsx(ArrayFieldAddButton, { ...(uiSchema?.["ui:addButtonOptions"]?.props ?? {}), onClick: () => setValue(appendArray(value, schemas.additionalItems)), children: uiSchema?.["ui:addButtonOptions"]?.content ?? "+" }))] }));
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 isMultiSelect = enums.type === EnumsTypes.MULTI_SELECT;
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: enums.values.map((v) => {
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(uiSchema?.["ui:order"], propertyKeys);
37
- const hiddenProperties = getHiddenProperties(uiSchema?.["ui:order"], propertyKeys);
38
- const orderedAdditionalProperties = orderAdditionalProperties(uiSchema?.["ui:order"], additionalPropertyKeys);
39
- const hiddenAdditionalProperties = getHiddenProperties(uiSchema?.["ui:order"], additionalPropertyKeys);
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, { ...(uiSchema?.["ui:addButtonOptions"]?.props ?? {}), onClick: onClick, children: uiSchema?.["ui:addButtonOptions"]?.content ?? "+" }));
50
+ return (_jsx(ObjectFieldAddButton, { ...(addButton?.props ?? {}), onClick: onClick, children: addButton?.content ?? "+" }));
44
51
  case ObjectFieldButtonPurpose.REMOVE:
45
- return (_jsx(ObjectFieldRemoveButton, { ...(uiSchema?.["ui:removeButtonOptions"]?.props ?? {}), onClick: onClick, children: uiSchema?.["ui:removeButtonOptions"]?.content ?? "-" }));
52
+ return (_jsx(ObjectFieldRemoveButton, { ...(removeButton?.props ?? {}), onClick: onClick, children: removeButton?.content ?? "-" }));
46
53
  case ObjectFieldButtonPurpose.MOVE_UP:
47
- return (_jsx(ObjectFieldUpButton, { ...(uiSchema?.["ui:upButtonOptions"]?.props ?? {}), onClick: onClick, children: uiSchema?.["ui:upButtonOptions"]?.content ?? "↑" }));
54
+ return (_jsx(ObjectFieldUpButton, { ...(upButton?.props ?? {}), onClick: onClick, children: upButton?.content ?? "↑" }));
48
55
  case ObjectFieldButtonPurpose.MOVE_DOWN:
49
- return (_jsx(ObjectFieldDownButton, { ...(uiSchema?.["ui:downButtonOptions"]?.props ?? {}), onClick: onClick, children: uiSchema?.["ui:downButtonOptions"]?.content ?? "↓" }));
56
+ return (_jsx(ObjectFieldDownButton, { ...(downButton?.props ?? {}), onClick: onClick, children: downButton?.content ?? "↓" }));
50
57
  default:
51
- return (_jsx(ObjectFieldButton, { ...(uiSchema?.["ui:customButtonOptions"]?.props ?? {}), onClick: onClick, children: uiSchema?.["ui:customButtonOptions"]?.content ?? "" }));
58
+ return (_jsx(ObjectFieldButton, { ...(customButton?.props ?? {}), onClick: onClick, children: customButton?.content ?? "" }));
52
59
  }
53
60
  };
54
- const SelectedObjectFieldTemplate = (props.uiSchema?.["ui:template"] &&
55
- templates[props.uiSchema?.["ui:template"]]) ??
56
- (props.uiSchema?.["ui:options"]?.isCollapsible
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), _jsx(ObjectFieldItemButtons, { children: getObjectFieldButton({
107
- purpose: ObjectFieldButtonPurpose.REMOVE,
108
- onClick: () => {
109
- const { [childName]: _removedProperty, ...newValue } = value;
110
- setValue(newValue);
111
- },
112
- uiSchema: uiSchema,
113
- }) })] }, childName));
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
- setValue({ ...value, [key]: undefined });
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: 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
- : {}, uiSchema: uiSchema }) }, index)) : (_jsx(ArrayFieldItem, { children: _jsx("div", { "data-keyword": item, children: getValue(item) }) }, item)) }));
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: allValues }) }));
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
- const anyOf = schema.anyOf;
140
- // anyOf is optional, therefore we cannot change it to array.mixedOf() aka tuple
141
- const anyOfSchema = Yup.array().of(Yup.lazy(() => {
142
- // value has to match with one of the anyOf values in the schema
143
- return Yup.mixed().oneOf(anyOf.map((item) => item.const));
144
- }));
145
- // In case the property is required, there should be at least one item in the array
146
- yupSchema = isRequired ? anyOfSchema.min(1, "Required") : anyOfSchema;
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
- const additionalItemSchema = (() => {
150
- const additionalItems = schema.additionalItems;
151
- if (!additionalItems) {
152
- return undefined;
153
- }
154
- // Yup.lazy() enables validation for infinitely nested schemas
155
- // aka references that refer to themselves or in circular references
156
- return Yup.lazy(() => {
157
- return getValue(schema?.additionalItems, "#ignore-this", true);
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);
@@ -0,0 +1,7 @@
1
+ export function immutablySwapItems(items, firstIndex, secondIndex) {
2
+ const results = items.slice();
3
+ const firstItem = items[firstIndex];
4
+ results[firstIndex] = items[secondIndex];
5
+ results[secondIndex] = firstItem;
6
+ return results;
7
+ }
@@ -12,3 +12,4 @@ export * from "./createValidationSchema";
12
12
  export * from "./orderByUiSchema";
13
13
  export * from "./orderAdditionalProperties";
14
14
  export * from "./setTitleValues";
15
+ export * from "./immutablySwapItems";
@@ -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[];
@@ -12,3 +12,4 @@ export * from "./createValidationSchema";
12
12
  export * from "./orderByUiSchema";
13
13
  export * from "./orderAdditionalProperties";
14
14
  export * from "./setTitleValues";
15
+ export * from "./immutablySwapItems";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nolwenture/formik-jsonschema-form",
3
- "version": "1.3.4",
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
+ }