@nolwenture/formik-jsonschema-form 0.23.1 → 0.23.3

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
@@ -1009,5 +1009,6 @@ Wildcard `"*"` and `hidden fields` cannot be combined.
1009
1009
  components={components} // Override form components (e.g. wrappers) with custom ones
1010
1010
  formContext={formContext} // Form context
1011
1011
  useItemsAsAdditionalItems={true} // Allow "items" to be used as "additionalItems" in array fields that are missing "additionalItems", false by default
1012
+ hideSubmit={true} // hides submit-button of the form
1012
1013
  />
1013
1014
  ```
package/dist/Form.js CHANGED
@@ -30,7 +30,7 @@ export const Form = (props) => {
30
30
  "hideUnmarkedAdditionalProperties",
31
31
  ]);
32
32
  const { isSubmitting } = useFormikContext();
33
- const { schema, uiSchema = {}, className, children, fields = {}, templates = {}, components = {}, formContext = {}, useItemsAsAdditionalItems = false, hideUnmarkedAdditionalProperties = false, } = props;
33
+ const { schema, uiSchema = {}, className, children, fields = {}, templates = {}, components = {}, formContext = {}, useItemsAsAdditionalItems = false, hideUnmarkedAdditionalProperties = false, hideSubmit = false, } = props;
34
34
  const schemaDefinitions = schema.definitions;
35
35
  const uiSchemaDefinitions = uiSchema.definitions;
36
36
  const registry = {
@@ -45,5 +45,5 @@ export const Form = (props) => {
45
45
  };
46
46
  const { Form: FormEl, FormButton, FormButtonWrapper } = registry.components;
47
47
  const SchemaField = registry.fields.SchemaField;
48
- return (_jsx(FormRegistry.Provider, { value: registry, children: _jsxs(FormEl, { className: className, children: [_jsx(SchemaField, { name: "", schema: schema, uiSchema: uiSchema }), children ? (children) : (_jsx(FormButtonWrapper, { children: _jsx(FormButton, { type: "submit", disabled: isSubmitting, children: "Send" }) }))] }) }));
48
+ return (_jsx(FormRegistry.Provider, { value: registry, children: _jsxs(FormEl, { className: className, children: [_jsx(SchemaField, { name: "", schema: schema, uiSchema: uiSchema }), children ? (children) : (_jsx(FormButtonWrapper, { children: !hideSubmit && (_jsx(FormButton, { type: "submit", disabled: isSubmitting, children: "Send" })) }))] }) }));
49
49
  };
@@ -15,3 +15,4 @@ export declare const WithRefAndDefinitions: Story;
15
15
  export declare const MultipleChoice: Story;
16
16
  export declare const Collapsible: Story;
17
17
  export declare const FileUploadForm: Story;
18
+ export declare const HideSubmitButton: Story;
@@ -232,3 +232,10 @@ export const FileUploadForm = {
232
232
  uiSchema: fileUploadUiSchema,
233
233
  },
234
234
  };
235
+ export const HideSubmitButton = {
236
+ args: {
237
+ schema: simpleSchema,
238
+ uiSchema: simpleUiSchema,
239
+ hideSubmit: true,
240
+ },
241
+ };
@@ -2,10 +2,14 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { useContext } from "react";
3
3
  import { FormRegistry } from "../Form";
4
4
  import { useExtractUiSchema, useSetDefault } from "../hooks";
5
+ import { useFormikContext } from "formik";
5
6
  export const BooleanField = (props) => {
6
7
  const { templates: { FieldTemplate }, components: { FieldInput, BooleanFieldWrapper }, } = useContext(FormRegistry);
7
8
  useSetDefault(props);
8
9
  const { name, uiSchema } = props;
9
10
  const { label, props: inputProps } = useExtractUiSchema(uiSchema);
10
- return (_jsx(FieldTemplate, Object.assign({}, props, { "data-fjsf-boolean": name, children: _jsxs(BooleanFieldWrapper, { children: [_jsx(FieldInput, Object.assign({}, inputProps, { name: name, type: "checkbox" })), label] }) })));
11
+ const { values, setValues } = useFormikContext();
12
+ return (_jsx(FieldTemplate, Object.assign({}, props, { "data-fjsf-boolean": name, children: _jsxs(BooleanFieldWrapper, { children: [_jsx(FieldInput, Object.assign({}, inputProps, { name: name, type: "checkbox" })), _jsx("span", { onClick: () => {
13
+ setValues(Object.assign(Object.assign({}, values), { [name]: !(values === null || values === void 0 ? void 0 : values[name]) }));
14
+ }, children: label })] }) })));
11
15
  };
@@ -419,6 +419,7 @@ export const TextAreaInputField = ({ inputProps, name, className, }) => {
419
419
  };
420
420
  export const BooleanFieldWrapper = styled.div `
421
421
  display: flex;
422
+ cursor: pointer;
422
423
  `;
423
424
  const ClickableEl = styled.button `
424
425
  background: none;
@@ -15,6 +15,7 @@ import { FormRegistry } from "../Form";
15
15
  import { getDescription, getTitle } from "../utils";
16
16
  import { useExtractUiSchema } from "../hooks";
17
17
  import { RequiredIndicator } from "../styledComponents";
18
+ import { getIn, useFormikContext } from "formik";
18
19
  export const ArrayFieldTemplate = (props) => {
19
20
  const { components: { ArrayFieldWrapper, ArrayFieldTitle, FieldDescription, ErrorMessage, FieldHelp, InfoFieldButton, }, } = useContext(FormRegistry);
20
21
  const { name, uiSchema, children } = props, otherProps = __rest(props, ["name", "uiSchema", "children"]);
@@ -30,5 +31,12 @@ export const ArrayFieldTemplate = (props) => {
30
31
  return acc;
31
32
  }, {});
32
33
  const mergedWrapperProps = Object.assign(Object.assign({}, wrapperProps), dataAttributes);
33
- return (_jsxs(ArrayFieldWrapper, Object.assign({}, mergedWrapperProps, { children: [title && (_jsxs(ArrayFieldTitle, Object.assign({}, titleProps, { htmlFor: name, children: [title, (props === null || props === void 0 ? void 0 : props.required) && _jsx(RequiredIndicator, { children: "*" })] }))), info && _jsx(InfoFieldButton, Object.assign({}, info)), description && (_jsx(FieldDescription, Object.assign({}, descriptionProps, { children: description }))), children, help && _jsx(FieldHelp, Object.assign({}, helpProps, { children: help })), _jsx(ErrorMessage, Object.assign({}, errorProps, { name: name }))] })));
34
+ // These lines make sure the error message is a string, which means the error
35
+ // is actually for the whole Array component, not for one of the children.
36
+ const { errors } = useFormikContext();
37
+ const error = getIn(errors, name);
38
+ // In case of array of objects, it will give error message as an object value,
39
+ // which is incorrect value for React, causing UI to crash.
40
+ const errorIsString = typeof error === "string";
41
+ return (_jsxs(ArrayFieldWrapper, Object.assign({}, mergedWrapperProps, { children: [title && (_jsxs(ArrayFieldTitle, Object.assign({}, titleProps, { htmlFor: name, children: [title, (props === null || props === void 0 ? void 0 : props.required) && _jsx(RequiredIndicator, { children: "*" })] }))), info && _jsx(InfoFieldButton, Object.assign({}, info)), description && (_jsx(FieldDescription, Object.assign({}, descriptionProps, { children: description }))), children, help && _jsx(FieldHelp, Object.assign({}, helpProps, { children: help })), errorIsString && _jsx(ErrorMessage, Object.assign({}, errorProps, { name: name }))] })));
34
42
  };
package/dist/types.d.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  import { FormikContextType, FormikErrors } from "formik";
2
2
  import type { JSONSchema7, JSONSchema7Definition } from "json-schema";
3
3
  import React, { MouseEventHandler } from "react";
4
+ import Yup from "yup";
4
5
  export type FormProps<T> = React.PropsWithChildren<{
5
6
  /** If true, disabled prop is passed down to each field on the form */
6
7
  disabled?: boolean | undefined;
@@ -26,6 +27,7 @@ export type FormProps<T> = React.PropsWithChildren<{
26
27
  * @default false
27
28
  */
28
29
  noHtml5Validate?: boolean | undefined;
30
+ hideSubmit?: boolean | undefined;
29
31
  }>;
30
32
  export type Schema = JSONSchema7;
31
33
  export type UiSchema = {
@@ -297,4 +299,13 @@ export type FileUploadFieldProps = {
297
299
  export type FormValues = {
298
300
  [key: string]: string | number | boolean | number[] | string[] | FormValues | FormValues[];
299
301
  };
302
+ export type MixedOfProps = {
303
+ itemSchemas: Yup.ISchema<unknown, any, any, any>[];
304
+ additionalItemSchema?: Yup.ISchema<unknown, any, any, any>;
305
+ };
306
+ declare module "yup" {
307
+ interface ArraySchema<TIn extends any[] | null | undefined, TContext, TDefault = undefined, TFlags extends Yup.Flags = ""> extends Yup.Schema<TIn, TContext, TDefault, TFlags> {
308
+ mixedOf(schemas: MixedOfProps): this;
309
+ }
310
+ }
300
311
  export {};
@@ -66,7 +66,7 @@ describe("Create Initial Values", () => {
66
66
  name: "",
67
67
  age: 0,
68
68
  number: 0,
69
- feeling: false,
69
+ feeling: "",
70
70
  arrayOfObject: [],
71
71
  nestedObject: {
72
72
  hobbies: "",
@@ -95,17 +95,17 @@ describe("Create Initial Values", () => {
95
95
  // @ts-expect-error
96
96
  // Should only accept boolean false
97
97
  booleanIncorrect: true,
98
- booleanCorrect: false,
98
+ booleanCorrect: "",
99
99
  object: {
100
100
  string: "",
101
101
  number: 0,
102
102
  array: [],
103
- boolean: false,
103
+ boolean: "",
104
104
  nested: {
105
105
  string: "",
106
106
  number: 0,
107
107
  array: [],
108
- boolean: false,
108
+ boolean: "",
109
109
  },
110
110
  },
111
111
  };
@@ -66,7 +66,11 @@ const simpleExampleSchema = {
66
66
  lastName: { type: "string", title: "Last name" },
67
67
  age: { type: "number", title: "Age" },
68
68
  drinksCoffee: { type: "boolean", title: "Do you drink coffee?" },
69
- simpleArray: { type: "array", title: "Simple array" },
69
+ simpleArray: {
70
+ type: "array",
71
+ title: "Simple array",
72
+ items: [{ type: "string" }],
73
+ },
70
74
  },
71
75
  };
72
76
  const dependenciesExampleSchema = {
@@ -260,15 +264,15 @@ const nestedRequiredConditionalExampleSchema = {
260
264
  ],
261
265
  };
262
266
  describe("Create Validation Schema", () => {
263
- function listErrors(schema, data) {
267
+ function listErrors(schema, data, definitions) {
264
268
  var _a;
265
- const yupSchema = createValidationSchema(schema);
269
+ const yupSchema = createValidationSchema(schema, definitions);
266
270
  try {
267
271
  yupSchema.validateSync(data, { abortEarly: false });
268
272
  }
269
273
  catch (err) {
270
274
  const error = err;
271
- return (_a = error === null || error === void 0 ? void 0 : error.inner) === null || _a === void 0 ? void 0 : _a.map((aa) => aa.path);
275
+ return (_a = error === null || error === void 0 ? void 0 : error.inner) === null || _a === void 0 ? void 0 : _a.map((e, i) => { var _a; return `${e.path}: ${error.errors[i].replace((_a = e === null || e === void 0 ? void 0 : e.path) !== null && _a !== void 0 ? _a : "", "").trim()}`; });
272
276
  }
273
277
  }
274
278
  it("creates yup validationSchema based on given JSON schema", () => __awaiter(void 0, void 0, void 0, function* () {
@@ -332,7 +336,7 @@ describe("Create Validation Schema", () => {
332
336
  age: 17,
333
337
  drinksCoffee: false,
334
338
  simpleArray: "Hello :)",
335
- }, { strict: true })).rejects.toThrow('simpleArray must be a `array` type, but the final value was: `"Hello :)"`.');
339
+ }, { strict: true })).rejects.toThrow('simpleArray must be a `tuple` type, but the final value was: `"Hello :)"`.');
336
340
  }));
337
341
  describe("Conditionals", () => {
338
342
  it("generates validation for dependencies without oneOf", () => {
@@ -443,11 +447,11 @@ describe("Create Validation Schema", () => {
443
447
  customerType: "BUSINESS",
444
448
  });
445
449
  expect(faultyBusiness).toEqual(expect.arrayContaining([
446
- "address.country",
447
- "address.city",
448
- "address.streetName",
449
- "businessName",
450
- "code",
450
+ "address.country: Required",
451
+ "address.city: Required",
452
+ "address.streetName: Required",
453
+ "businessName: Required",
454
+ "code: Required",
451
455
  ]));
452
456
  const business = listErrors(allOfExample, {
453
457
  customerType: "BUSINESS",
@@ -464,11 +468,11 @@ describe("Create Validation Schema", () => {
464
468
  customerType: "INDIVIDUAL",
465
469
  });
466
470
  expect(faultyIndividual).toEqual(expect.arrayContaining([
467
- "address.country",
468
- "address.city",
469
- "address.streetName",
470
- "firstName",
471
- "code",
471
+ "address.country: Required",
472
+ "address.city: Required",
473
+ "address.streetName: Required",
474
+ "firstName: Required",
475
+ "code: Required",
472
476
  ]));
473
477
  const individual = listErrors(allOfExample, {
474
478
  customerType: "INDIVIDUAL",
@@ -485,11 +489,11 @@ describe("Create Validation Schema", () => {
485
489
  customerType: "UNKNOWN",
486
490
  });
487
491
  expect(faultyUnknown).toEqual(expect.arrayContaining([
488
- "address.country",
489
- "address.city",
490
- "address.streetName",
491
- "newCustomer",
492
- "code",
492
+ "address.country: Required",
493
+ "address.city: Required",
494
+ "address.streetName: Required",
495
+ "newCustomer: Required",
496
+ "code: Required",
493
497
  ]));
494
498
  const unknown = listErrors(allOfExample, {
495
499
  customerType: "UNKNOWN",
@@ -530,4 +534,228 @@ describe("Create Validation Schema", () => {
530
534
  expect(isValidWhenConditionMetAndRequiredFieldsAreFilled).toEqual(true);
531
535
  });
532
536
  });
537
+ describe("Array", () => {
538
+ const createArraySchema = ({ items, additionalItems, }) => ({
539
+ title: "Array of objects Schema",
540
+ required: ["arrayOfObjects"],
541
+ properties: {
542
+ arrayOfObjects: Object.assign({ type: "array", title: "A list of fixed items", items }, (additionalItems ? { additionalItems } : {})),
543
+ },
544
+ });
545
+ it("requires fields with array items and additionalItems", () => __awaiter(void 0, void 0, void 0, function* () {
546
+ const arraySchema = createArraySchema({
547
+ items: [
548
+ { title: "A string value", type: "string" },
549
+ { title: "An integer value", type: "integer" },
550
+ { title: "A number value", type: "number" },
551
+ {
552
+ title: "An arrayContaining value",
553
+ type: "array",
554
+ items: [{ title: "A string value", type: "string" }],
555
+ },
556
+ { title: "a boolean value", type: "boolean" },
557
+ {
558
+ type: "object",
559
+ title: "User",
560
+ required: ["name"],
561
+ properties: {
562
+ name: { type: "string", title: "Name" },
563
+ age: { type: "number", title: "Age" },
564
+ },
565
+ },
566
+ ],
567
+ additionalItems: {
568
+ title: "Additional item",
569
+ type: "number",
570
+ },
571
+ });
572
+ const faultyItem1 = listErrors(arraySchema, {
573
+ arrayOfObjects: [
574
+ true,
575
+ 123.123,
576
+ 456,
577
+ ["array"],
578
+ false,
579
+ { name: "John", age: 27 },
580
+ ],
581
+ });
582
+ expect(faultyItem1).toEqual([
583
+ "arrayOfObjects[0]: must be a `string` type, but the final value was: `true`.",
584
+ ]);
585
+ const faultyItem2 = listErrors(arraySchema, {
586
+ arrayOfObjects: [
587
+ "string",
588
+ false,
589
+ 456,
590
+ ["array"],
591
+ false,
592
+ { name: "John", age: 27 },
593
+ ],
594
+ });
595
+ expect(faultyItem2).toEqual([
596
+ "arrayOfObjects[1]: must be a `number` type, but the final value was: `false`.",
597
+ ]);
598
+ const faultyItem3 = listErrors(arraySchema, {
599
+ arrayOfObjects: [
600
+ "string",
601
+ 123.123,
602
+ "incorrect",
603
+ ["array"],
604
+ false,
605
+ { name: "John", age: 27 },
606
+ ],
607
+ });
608
+ expect(faultyItem3).toEqual([
609
+ 'arrayOfObjects[2]: must be a `number` type, but the final value was: `"incorrect"`.',
610
+ ]);
611
+ const faultyItem4 = listErrors(arraySchema, {
612
+ arrayOfObjects: [
613
+ "string",
614
+ 123.123,
615
+ 456,
616
+ { id: 123 },
617
+ false,
618
+ { name: "John", age: 27 },
619
+ ],
620
+ });
621
+ expect(faultyItem4).toEqual([
622
+ 'arrayOfObjects[3]: must be a `tuple` type, but the final value was: `{\n "id": "123"\n}`.',
623
+ ]);
624
+ const faultyItem5 = listErrors(arraySchema, {
625
+ arrayOfObjects: [
626
+ "string",
627
+ 123.123,
628
+ 456,
629
+ ["array"],
630
+ 3.154,
631
+ { name: "John", age: 27 },
632
+ ],
633
+ });
634
+ expect(faultyItem5).toEqual([
635
+ "arrayOfObjects[4]: must be a `boolean` type, but the final value was: `3.154`.",
636
+ ]);
637
+ const faultyItem6 = listErrors(arraySchema, {
638
+ arrayOfObjects: [
639
+ "string",
640
+ 123.123,
641
+ 456,
642
+ ["array"],
643
+ false,
644
+ "faulty value",
645
+ ],
646
+ });
647
+ expect(faultyItem6).toEqual([
648
+ 'arrayOfObjects[5]: must be a `object` type, but the final value was: `"faulty value"`.',
649
+ ]);
650
+ const objectPropertyRequired = listErrors(arraySchema, {
651
+ arrayOfObjects: ["string", 123.123, 456, ["array"], false, { age: 27 }],
652
+ });
653
+ expect(objectPropertyRequired).toEqual([
654
+ "arrayOfObjects[5].name: Required",
655
+ ]);
656
+ const allRequired = listErrors(arraySchema, {
657
+ arrayOfObjects: [
658
+ undefined,
659
+ undefined,
660
+ undefined,
661
+ [],
662
+ undefined,
663
+ undefined,
664
+ ],
665
+ });
666
+ expect(allRequired).toEqual([
667
+ "arrayOfObjects[0]: Required",
668
+ "arrayOfObjects[1]: Required",
669
+ "arrayOfObjects[2]: Required",
670
+ "arrayOfObjects[3]: tuple value has too few items, expected a length of 1 but got 0 for value: `[]`",
671
+ "arrayOfObjects[4]: Required",
672
+ "arrayOfObjects[5]: Required",
673
+ ]);
674
+ const correct = listErrors(arraySchema, {
675
+ arrayOfObjects: [
676
+ "string",
677
+ 123.123,
678
+ 456,
679
+ ["array"],
680
+ false,
681
+ { name: "John", age: 27 },
682
+ ],
683
+ });
684
+ expect(correct).toEqual(undefined);
685
+ }));
686
+ it("required fields with array items only", () => __awaiter(void 0, void 0, void 0, function* () {
687
+ const arraySchema = createArraySchema({
688
+ items: [
689
+ { title: "A string value", type: "string" },
690
+ { title: "An integer value", type: "integer" },
691
+ { title: "A boolean value", type: "boolean" },
692
+ { title: "A number value", type: "number" },
693
+ ],
694
+ });
695
+ const faulty = listErrors(arraySchema, {
696
+ arrayOfObjects: ["name", undefined, undefined, false],
697
+ });
698
+ expect(faulty).toEqual([
699
+ "arrayOfObjects[1]: Required",
700
+ "arrayOfObjects[2]: Required",
701
+ "arrayOfObjects[3]: must be a `number` type, but the final value was: `false`.",
702
+ ]);
703
+ const coprrecorrect = listErrors(arraySchema, {
704
+ arrayOfObjects: ["name", 123, true, 123.141241],
705
+ });
706
+ expect(coprrecorrect).toEqual(undefined);
707
+ }));
708
+ it.only("requires fields with array items and additionalItems with definitions", () => __awaiter(void 0, void 0, void 0, function* () {
709
+ const arraySchema = {
710
+ title: "TITLE",
711
+ properties: {
712
+ arrayOfDefinitions: {
713
+ type: "array",
714
+ title: "Array of objects",
715
+ items: [{ $ref: "#/definitions/commodity" }],
716
+ additionalItems: { $ref: "#/definitions/commodity" },
717
+ },
718
+ },
719
+ };
720
+ const definitions = {
721
+ commodity: {
722
+ type: "object",
723
+ title: "Item",
724
+ required: ["commodityId"],
725
+ properties: {
726
+ commodityId: {
727
+ $ref: "#/definitions/selection",
728
+ },
729
+ insuredValue: {
730
+ type: "number",
731
+ title: "Insured value in USD",
732
+ },
733
+ },
734
+ },
735
+ selection: {
736
+ type: "string",
737
+ title: "HS Code",
738
+ oneOf: [
739
+ { const: "1", title: "One" },
740
+ { const: "2", title: "Two" },
741
+ { const: "3", title: "Three" },
742
+ ],
743
+ },
744
+ };
745
+ const faulty = listErrors(arraySchema, { arrayOfDefinitions: [true, 123, []] }, definitions);
746
+ expect(faulty).toEqual([
747
+ "arrayOfDefinitions[0]: must be a `object` type, but the final value was: `true`.",
748
+ "arrayOfDefinitions[1]: must be a `object` type, but the final value was: `123`.",
749
+ "arrayOfDefinitions[2]: must be a `object` type, but the final value was: `[]`.",
750
+ ]);
751
+ const correct = listErrors(arraySchema, {
752
+ arrayOfDefinitions: [
753
+ { commodityId: "1", insuredValue: "123" },
754
+ { commodityId: "2", insuredValue: "456" },
755
+ { commodityId: "3", insuredValue: "789" },
756
+ ],
757
+ }, definitions);
758
+ expect(correct).toEqual(undefined);
759
+ }));
760
+ });
533
761
  });
@@ -1,5 +1,5 @@
1
1
  import { JSONSchema7 } from "json-schema";
2
- type PropertyValue = 0 | "" | false | never[] | InitialValuesType;
2
+ type PropertyValue = 0 | "" | never[] | InitialValuesType;
3
3
  export interface InitialValuesType {
4
4
  [key: string]: PropertyValue;
5
5
  }
@@ -13,12 +13,11 @@ export function createInitialValues(schema, definitions = {}) {
13
13
  switch (type) {
14
14
  case "array":
15
15
  return [];
16
- case "boolean":
17
- return false;
18
- case "null":
19
- return "";
20
16
  case "number":
21
17
  return 0;
18
+ // Boolean cannot be true/false by default, since that is a valid value
19
+ case "boolean":
20
+ case "null":
22
21
  case "string":
23
22
  return "";
24
23
  default:
@@ -12,6 +12,19 @@ var __rest = (this && this.__rest) || function (s, e) {
12
12
  import * as Yup from "yup";
13
13
  import { resolveOneOfValue } from "./resolveSchema";
14
14
  import { solveReferences } from "./solveReferences";
15
+ // Difficult to solve
16
+ // @ts-expect-error
17
+ Yup.addMethod(Yup.array, "mixedOf", function ({ itemSchemas, additionalItemSchema }) {
18
+ return Yup.lazy((value) => {
19
+ var _a;
20
+ const valueLength = (_a = value === null || value === void 0 ? void 0 : value.length) !== null && _a !== void 0 ? _a : 0;
21
+ const numOfAdditionalItems = itemSchemas.length > valueLength ? 0 : valueLength - itemSchemas.length;
22
+ const additionalSchemas = additionalItemSchema
23
+ ? Array(numOfAdditionalItems).fill(additionalItemSchema)
24
+ : [];
25
+ return Yup.tuple([...itemSchemas, ...additionalSchemas]).typeError("Required");
26
+ });
27
+ });
15
28
  function getConditionalValidations(schema) {
16
29
  const { dependencies, allOf } = schema;
17
30
  let conditionalValidations = [];
@@ -96,7 +109,8 @@ function getConditionalValidations(schema) {
96
109
  }
97
110
  return conditionalValidations;
98
111
  }
99
- function getYupType(type) {
112
+ function getYupType(schema) {
113
+ const type = schema === null || schema === void 0 ? void 0 : schema.type;
100
114
  switch (type) {
101
115
  case "object":
102
116
  return Yup.object();
@@ -112,7 +126,8 @@ function getYupType(type) {
112
126
  case "string":
113
127
  return Yup.string();
114
128
  default:
115
- throw new Error("Unsupported schema type");
129
+ console.error({ schema });
130
+ throw new Error(`Unsupported schema type: ${type}`);
116
131
  }
117
132
  }
118
133
  export function createValidationSchema(schema, definitions = {}, conditionsContext = {}, condition) {
@@ -122,38 +137,43 @@ export function createValidationSchema(schema, definitions = {}, conditionsConte
122
137
  }
123
138
  const schemaDefinitions = Object.assign(Object.assign({}, definitions), ((_a = schema.definitions) !== null && _a !== void 0 ? _a : {}));
124
139
  const requiredFields = schema.required;
125
- function getValue(schema, key) {
126
- var _a;
140
+ function getValue(givenSchema, key, required) {
141
+ var _a, _b;
142
+ const { schema } = solveReferences(givenSchema, schemaDefinitions, {}, {});
127
143
  let type = schema.type;
128
144
  let yupSchema;
129
145
  if (schema.properties) {
130
146
  yupSchema = createValidationSchema(schema, schemaDefinitions, conditionsContext);
131
147
  type = type !== null && type !== void 0 ? type : "object";
132
148
  }
149
+ else if (type === "array") {
150
+ const schemaItems = (_a = schema === null || schema === void 0 ? void 0 : schema.items) !== null && _a !== void 0 ? _a : [];
151
+ const items = Array.isArray(schemaItems) ? schemaItems : [schemaItems];
152
+ yupSchema = Yup.array().mixedOf({
153
+ itemSchemas: items.map((item) => getValue(item, "#ignore-this", true)),
154
+ additionalItemSchema: (schema === null || schema === void 0 ? void 0 : schema.additionalItems)
155
+ ? getValue(schema === null || schema === void 0 ? void 0 : schema.additionalItems, "#ignore-this", true)
156
+ : undefined,
157
+ });
158
+ }
133
159
  else {
134
- yupSchema = getYupType(type);
160
+ yupSchema = getYupType(schema);
135
161
  }
136
162
  if (type === "null")
137
163
  yupSchema.nullable();
138
- if (requiredFields === null || requiredFields === void 0 ? void 0 : requiredFields.includes(key)) {
139
- if (type === "array") {
140
- yupSchema = yupSchema
141
- .min(1, "Required")
142
- .required("Required");
143
- }
144
- else {
145
- yupSchema = yupSchema["required"]("Required");
146
- }
164
+ const isRequired = (requiredFields === null || requiredFields === void 0 ? void 0 : requiredFields.includes(key)) || required === true;
165
+ if (isRequired && type !== "array") {
166
+ yupSchema = yupSchema.required("Required");
147
167
  }
148
168
  if (!condition) {
149
169
  return yupSchema;
150
170
  }
151
- const existing = (_a = conditionsContext[key]) !== null && _a !== void 0 ? _a : [];
171
+ const existing = (_b = conditionsContext[key]) !== null && _b !== void 0 ? _b : [];
152
172
  conditionsContext[key] = [...existing, { yupSchema, condition }];
153
173
  // TODO: The latest given type for duplicate field is used.
154
174
  // This might become a problem at some point, but testing has not
155
175
  // shown any problems so far.
156
- const yupType = getYupType(type).when(condition.dependentKeys, {
176
+ const yupType = getYupType(schema).when(condition.dependentKeys, {
157
177
  is: condition.conditionFn,
158
178
  then: () => yupSchema,
159
179
  });
@@ -172,8 +192,7 @@ export function createValidationSchema(schema, definitions = {}, conditionsConte
172
192
  const baseValidationSchema = Object.keys(schema.properties).reduce((validationSchema, key) => {
173
193
  var _a;
174
194
  const value = (_a = schema.properties) === null || _a === void 0 ? void 0 : _a[key];
175
- const solvedValue = solveReferences(value, schemaDefinitions, {}, {});
176
- return validationSchema.concat(Yup.object().shape({ [key]: getValue(solvedValue.schema, key) }));
195
+ return validationSchema.concat(Yup.object().shape({ [key]: getValue(value, key) }));
177
196
  }, Yup.object().shape({}));
178
197
  return getConditionalValidations(schema).reduce((validationSchema, conditionalValidation) => {
179
198
  const solvedSchemas = solveReferences(conditionalValidation.schema, schemaDefinitions, {}, {});
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nolwenture/formik-jsonschema-form",
3
- "version": "0.23.1",
3
+ "version": "0.23.3",
4
4
  "description": "Formik form generation from json schema",
5
5
  "author": "Antti Vikman <antti.vikman@nolwenture.com>",
6
6
  "contributors": [