@nolwenture/formik-jsonschema-form 0.7.1 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (82) hide show
  1. package/README.md +176 -1
  2. package/dist/Form.js +2 -1
  3. package/dist/Form.stories.d.ts +2 -0
  4. package/dist/Form.stories.js +15 -0
  5. package/dist/Form.test.d.ts +1 -1
  6. package/dist/Form.test.js +3 -1
  7. package/dist/fields/ArrayField.js +2 -1
  8. package/dist/fields/MultipleChoiceField.d.ts +3 -0
  9. package/dist/fields/MultipleChoiceField.js +13 -0
  10. package/dist/fields/ObjectField.js +3 -1
  11. package/dist/fields/SchemaField.js +7 -5
  12. package/dist/fields/StringField.js +1 -1
  13. package/dist/fields/index.d.ts +1 -0
  14. package/dist/fields/index.js +1 -0
  15. package/dist/fields/stories/AnyField.stories.d.ts +5 -0
  16. package/dist/fields/stories/AnyField.stories.js +79 -0
  17. package/dist/fields/stories/ArrayField.stories.d.ts +7 -0
  18. package/dist/fields/stories/ArrayField.stories.js +191 -0
  19. package/dist/fields/stories/BooleanField.stories.d.ts +5 -0
  20. package/dist/fields/stories/BooleanField.stories.js +36 -0
  21. package/dist/fields/stories/DateField.stories.d.ts +5 -0
  22. package/dist/fields/stories/DateField.stories.js +34 -0
  23. package/dist/fields/stories/NullField.stories.d.ts +5 -0
  24. package/dist/fields/stories/NullField.stories.js +38 -0
  25. package/dist/fields/stories/NumberField.stories.d.ts +5 -0
  26. package/dist/fields/stories/NumberField.stories.js +33 -0
  27. package/dist/fields/stories/ObjectField.stories.d.ts +5 -0
  28. package/dist/fields/stories/ObjectField.stories.js +76 -0
  29. package/dist/fields/stories/RadioField.stories.d.ts +5 -0
  30. package/dist/fields/stories/RadioField.stories.js +42 -0
  31. package/dist/fields/stories/SchemaField.stories.d.ts +1716 -0
  32. package/dist/fields/stories/SchemaField.stories.js +85 -0
  33. package/dist/fields/stories/SearchMultiTagSelectField.stories.d.ts +5 -0
  34. package/dist/fields/stories/SearchMultiTagSelectField.stories.js +58 -0
  35. package/dist/fields/stories/StringField.stories.d.ts +7 -0
  36. package/dist/fields/stories/StringField.stories.js +75 -0
  37. package/dist/fields/stories/ToggleField.stories.d.ts +5 -0
  38. package/dist/fields/stories/ToggleField.stories.js +34 -0
  39. package/dist/formEditorSchemas.js +177 -21
  40. package/dist/hooks/__tests__/useExtractUiSchema.test.d.ts +1 -0
  41. package/dist/hooks/__tests__/useExtractUiSchema.test.js +45 -0
  42. package/dist/hooks/__tests__/useSetDefault.test.d.ts +1 -0
  43. package/dist/hooks/__tests__/useSetDefault.test.js +65 -0
  44. package/dist/hooks/useExtractUiSchema.js +7 -3
  45. package/dist/sampleData/ageFieldDefinition.d.ts +2 -0
  46. package/dist/sampleData/ageFieldDefinition.js +5 -0
  47. package/dist/sampleData/multipleChoiceSchema.d.ts +3 -0
  48. package/dist/sampleData/multipleChoiceSchema.js +112 -0
  49. package/dist/sampleData/refDefSchema.d.ts +3 -0
  50. package/dist/sampleData/refDefSchema.js +219 -0
  51. package/dist/sampleData/requiredInputSchema.js +0 -5
  52. package/dist/styledComponents.d.ts +2 -1
  53. package/dist/styledComponents.js +8 -0
  54. package/dist/types.d.ts +19 -2
  55. package/dist/utils/__tests/createInitialValues.test.d.ts +1 -0
  56. package/dist/utils/__tests/createInitialValues.test.js +72 -0
  57. package/dist/utils/__tests/deepOverlap.test.d.ts +1 -0
  58. package/dist/utils/__tests/deepOverlap.test.js +41 -0
  59. package/dist/utils/__tests/getEnums.test.js +11 -16
  60. package/dist/utils/__tests/getTitleAndDescription.test.d.ts +1 -0
  61. package/dist/utils/__tests/getTitleAndDescription.test.js +53 -0
  62. package/dist/utils/__tests/getTypes.test.d.ts +1 -0
  63. package/dist/utils/__tests/getTypes.test.js +62 -0
  64. package/dist/utils/__tests/mergeSchemas.test.d.ts +1 -0
  65. package/dist/utils/__tests/mergeSchemas.test.js +40 -0
  66. package/dist/utils/__tests/resolveSchema.test.js +43 -33
  67. package/dist/utils/__tests/solveReferences.test.d.ts +1 -0
  68. package/dist/utils/__tests/solveReferences.test.js +12 -0
  69. package/dist/utils/__tests/testSchemas.d.ts +4 -0
  70. package/dist/utils/__tests/testSchemas.js +67 -0
  71. package/dist/utils/createInitialValues.d.ts +4 -0
  72. package/dist/utils/createInitialValues.js +27 -0
  73. package/dist/utils/getStyle.d.ts +5 -0
  74. package/dist/utils/getStyle.js +18 -0
  75. package/dist/utils/getTypes.js +1 -1
  76. package/dist/utils/index.d.ts +2 -0
  77. package/dist/utils/index.js +2 -0
  78. package/dist/utils/resolveSchema.d.ts +1 -1
  79. package/dist/utils/resolveSchema.js +88 -39
  80. package/dist/utils/solveReferences.d.ts +2 -0
  81. package/dist/utils/solveReferences.js +8 -0
  82. package/package.json +5 -2
package/README.md CHANGED
@@ -14,6 +14,26 @@ With yarn:
14
14
  yarn add @nolwenture/formik-jsonschema-form
15
15
  ```
16
16
 
17
+ ## Testing
18
+
19
+ Run unit tests:
20
+
21
+ ```text
22
+ npm run test
23
+ ```
24
+
25
+ To run storybook tests make sure you have Playwright installed:
26
+
27
+ ```text
28
+ npx playwright install
29
+ ```
30
+
31
+ Run storybook tests:
32
+
33
+ ```text
34
+ npm run test-storybook
35
+ ```
36
+
17
37
  ## Usage
18
38
 
19
39
  ### Basic usage
@@ -400,7 +420,9 @@ const uiSchema = {
400
420
  ### Alternative fields
401
421
 
402
422
  There are alternative fields available for certain types.
403
- For `type: "string"` there is `DateField`, that has a "dd.mm.yyyy" date input field and a calendar date picker and will save the date input as "yyyy-mm-dd" string.
423
+ For `type: "string"` there is `DateField` and `MultipleChoiceField`.
424
+
425
+ `DateField` has a "dd.mm.yyyy" date input field and a calendar date picker and will save the date input as "yyyy-mm-dd" string.
404
426
 
405
427
  ```tsx
406
428
  const schema = {
@@ -414,6 +436,35 @@ const uiSchema = {
414
436
  };
415
437
  ```
416
438
 
439
+ `MultipleChoiceField` takes an array of `oneOf` or `anyOf`. The choices provided inside an `oneOf`array will be presented on the UI as Radio button selectables and only one of the given values can be selected. The choices provided inside an `anyOf` array will be presented on the UI as Checkbox selectables and multiple values can be selected.
440
+ `MultipleChoiceField` comes with a small number of predefined styles, which are `inline`, `oneColumn`, `twoColumns` and `threeColumns`. When no style is given, the choice options are listed in a row under the title.
441
+
442
+ ```tsx
443
+ const schema = {
444
+ properties: {
445
+ feeling: {
446
+ type: "string",
447
+ title: "How are you feeling today?",
448
+ oneOf: [
449
+ { const: "happy", title: "Happy" },
450
+ { const: "creative", title: "Creative" },
451
+ { const: "tired", title: "Tired" },
452
+ { const: "nope", title: "Please don't even ask..." },
453
+ ],
454
+ },
455
+ },
456
+ };
457
+
458
+ const uiSchema = {
459
+ feeling: {
460
+ "ui:field": "MultipleChoiceField",
461
+ "ui:option": {
462
+ style: "twoColumns",
463
+ },
464
+ },
465
+ };
466
+ ```
467
+
417
468
  For `type: "boolean"` there is `RadioField` and `ToggleField`.
418
469
  `RadioField` can take labels for the "true" and "false" options. If left empty, the default labels will be "true" and "false".
419
470
 
@@ -527,6 +578,130 @@ export const conditionsSchema = {
527
578
  };
528
579
  ```
529
580
 
581
+ Another option to give conditional fields is using `dependencies`-object inside the main schema.
582
+ Dependencies can either be triggered by the conditional-giving property being present in the form values, or by the conditional-giving property having a certain value.
583
+
584
+ To have value-dependent conditionals, the `dependencies`-object needs to have an `oneOf`-array listing the possible conditional-giving values matching the enum-values of the conditional-giving field. Each case in in the `oneOf` array can either have no conditional fields, then the only key-value pair given inside `properties` is the matching conditional (see "no type"), or an unlimited amount of conditional fields listed after the matching conditional.
585
+
586
+ ```tsx
587
+ export const refDefSchema: Schema = {
588
+ type: "object",
589
+ properties: {
590
+ creditCard: {
591
+ type: "number",
592
+ title: "Credit card number",
593
+ description:
594
+ "Giving any input to this field will trigger its dependent field 'billing_address'",
595
+ },
596
+ fieldType: {
597
+ type: "string",
598
+ description:
599
+ "Selecting an option in this field will render the correct dependent field from the provided oneOf-array",
600
+ enum: ["string", "object", "array"],
601
+ },
602
+ },
603
+ dependencies: {
604
+ creditCard: {
605
+ properties: {
606
+ billing_address: {
607
+ type: "object",
608
+ description: "This object depends on creditCard field input",
609
+ properties: {
610
+ street: { type: "string", title: "Street" },
611
+ city: { type: "string", title: "City" },
612
+ postalCode: { type: "number", title: "Postal code" },
613
+ },
614
+ },
615
+ },
616
+ required: ["billing_address"],
617
+ },
618
+ fieldType: {
619
+ oneOf: [
620
+ {
621
+ properties: {
622
+ fieldType: {
623
+ enum: ["no type"],
624
+ },
625
+ },
626
+ },
627
+ {
628
+ properties: {
629
+ fieldType: {
630
+ enum: ["string"],
631
+ },
632
+ stringField: {
633
+ type: "string",
634
+ title: "StringField",
635
+ },
636
+ },
637
+ },
638
+ {
639
+ properties: {
640
+ fieldType: {
641
+ enum: ["object"],
642
+ },
643
+ objectField: {
644
+ type: "object",
645
+ properties: {
646
+ objectString: {
647
+ type: "string",
648
+ title: "StringField in Object",
649
+ },
650
+ },
651
+ },
652
+ },
653
+ },
654
+ {
655
+ properties: {
656
+ fieldType: {
657
+ enum: ["array"],
658
+ },
659
+ arrayField: {
660
+ type: "array",
661
+ items: [{ type: "string", title: "StringField in fixed array" }],
662
+ },
663
+ },
664
+ },
665
+ ],
666
+ },
667
+ },
668
+ };
669
+ ```
670
+
671
+ Using `if-else-then` or `dependencies` depends mostly on the use case. For recursion, a combination of `$ref` and `dependencies`is recommended.
672
+
673
+ ### Schema reference $ref
674
+
675
+ Schemas can be referenced. A referenced schema can be given to a property using `$ref` keyword. The definition for the referenced schema needs to be inside `definitions` object inside the main schema. The value-string given to $ref-key must always look like this:
676
+ `'#/definitions/{addMatchingKeyHere}'`
677
+
678
+ ```tsx
679
+ const ageFieldDefinition: Schema = {
680
+ type: "number",
681
+ title: "Age",
682
+ };
683
+
684
+ export const refDefSchema: Schema = {
685
+ title: "References and Definitions",
686
+ type: "object",
687
+ properties: {
688
+ name: {
689
+ $ref: "#/definitions/name",
690
+ },
691
+ age: {
692
+ $ref: "#/definitions/age",
693
+ },
694
+ },
695
+ definitions: {
696
+ name: {
697
+ type: "string",
698
+ title: "Name",
699
+ },
700
+ age: ageFieldDefinition,
701
+ },
702
+ };
703
+ ```
704
+
530
705
  ### Ordering fields
531
706
 
532
707
  The order of fields can be set using `"ui:order": ["fieldName"]` inside the uiSchema.
package/dist/Form.js CHANGED
@@ -30,11 +30,12 @@ export const Form = (props) => {
30
30
  ]);
31
31
  const { isSubmitting } = useFormikContext();
32
32
  const { schema, uiSchema = {}, className, children, fields = {}, templates = {}, components = {}, formContext = {}, useItemsAsAdditionalItems = false, hideUnmarkedAdditionalProperties = false, } = props;
33
+ const schemaDefinitions = schema.definitions;
33
34
  const registry = {
34
35
  fields: Object.assign(Object.assign({}, defaultFields), fields),
35
36
  templates: Object.assign(Object.assign({}, defaultTemplates), templates),
36
37
  components: Object.assign(Object.assign({}, defaultComponents), components),
37
- definitions: {},
38
+ definitions: schemaDefinitions,
38
39
  formContext,
39
40
  useItemsAsAdditionalItems,
40
41
  hideUnmarkedAdditionalProperties,
@@ -11,3 +11,5 @@ export declare const StylesCustomized: () => import("react/jsx-runtime").JSX.Ele
11
11
  export declare const WithGeneratedSchema: Story;
12
12
  export declare const WithRequiredInput: Story;
13
13
  export declare const WithConditions: Story;
14
+ export declare const WithRefAndDefinitions: Story;
15
+ export declare const MultipleChoice: Story;
@@ -25,6 +25,8 @@ import { Formik, useFormikContext } from "formik";
25
25
  import { InfoFieldButton, SearchableMultiTagSelectField, } from "./styledComponents";
26
26
  import { completeSchema, completeUiSchema, simpleSchema, simpleUiSchema, generatedSchema, requiredInputSchema, requiredInputUiSchema, conditionsSchema, conditionsUiSchema, } from "./sampleData";
27
27
  import { Form, styledComponents } from "./";
28
+ import { refDefSchema, refDefUiSchema } from "./sampleData/refDefSchema";
29
+ import { multipleChoiceSchema, multipleChoiceUiSchema, } from "./sampleData/multipleChoiceSchema";
28
30
  const meta = {
29
31
  title: "Form",
30
32
  component: Form,
@@ -46,6 +48,7 @@ export default meta;
46
48
  export const Simple = {
47
49
  args: {
48
50
  schema: simpleSchema,
51
+ uiSchema: simpleUiSchema,
49
52
  },
50
53
  };
51
54
  const InfoFieldButtonNew = styled(InfoFieldButton) `
@@ -183,3 +186,15 @@ export const WithConditions = {
183
186
  hideUnmarkedAdditionalProperties: true,
184
187
  },
185
188
  };
189
+ export const WithRefAndDefinitions = {
190
+ args: {
191
+ schema: refDefSchema,
192
+ uiSchema: refDefUiSchema,
193
+ },
194
+ };
195
+ export const MultipleChoice = {
196
+ args: {
197
+ schema: multipleChoiceSchema,
198
+ uiSchema: multipleChoiceUiSchema,
199
+ },
200
+ };
@@ -1 +1 @@
1
- export {};
1
+ import "@testing-library/jest-dom";
package/dist/Form.test.js CHANGED
@@ -1,9 +1,11 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
+ import "@testing-library/jest-dom";
2
3
  import { render, screen } from "@testing-library/react";
4
+ import { Formik } from "formik";
3
5
  import { Form } from "./Form";
4
6
  import { simpleSchema } from "./sampleData";
5
7
  test("renders title", () => {
6
- render(_jsx(Form, { schema: simpleSchema }));
8
+ render(_jsx(Formik, { initialValues: {}, onSubmit: () => { }, children: _jsx(Form, { schema: simpleSchema }) }));
7
9
  const titleElement = screen.getByText(/TITLE/i);
8
10
  expect(titleElement).toBeInTheDocument();
9
11
  });
@@ -93,7 +93,8 @@ export const ArrayField = (props) => {
93
93
  // );
94
94
  // Bacwards compatibility ends
95
95
  const { disabled } = useExtractUiSchema(uiSchema);
96
- return (_jsxs(ArrayFieldTemplate, Object.assign({}, props, { children: [_jsxs(ArrayFieldList, { children: [(items || []).map((itemSchema, index) => (_jsx(ArrayFieldItem, { children: _jsx(SchemaField, { name: `${name}[${index}]`, schema: typeof itemSchema !== "boolean" ? itemSchema : {}, uiSchema: (uiSchema === null || uiSchema === void 0 ? void 0 : uiSchema[index]) || (uiSchema === null || uiSchema === void 0 ? void 0 : uiSchema.items), forceDefaultValue: true }) }, index))), ((value === null || value === void 0 ? void 0 : value.slice(items.length)) || []).map((_, index) => (_jsxs(ArrayFieldItem, { children: [_jsx(SchemaField, { name: `${name}[${index + items.length}]`, schema: additionalItems && typeof additionalItems !== "boolean"
96
+ const valueArray = Array.isArray(value) ? value : undefined;
97
+ return (_jsxs(ArrayFieldTemplate, Object.assign({}, props, { children: [_jsxs(ArrayFieldList, { children: [(items || []).map((itemSchema, index) => (_jsx(ArrayFieldItem, { children: _jsx(SchemaField, { name: `${name}[${index}]`, schema: typeof itemSchema !== "boolean" ? itemSchema : {}, uiSchema: (uiSchema === null || uiSchema === void 0 ? void 0 : uiSchema[index]) || (uiSchema === null || uiSchema === void 0 ? void 0 : uiSchema.items), forceDefaultValue: true }) }, index))), ((valueArray === null || valueArray === void 0 ? void 0 : valueArray.slice(items.length)) || []).map((_, index) => (_jsxs(ArrayFieldItem, { children: [_jsx(SchemaField, { name: `${name}[${index + items.length}]`, schema: additionalItems && typeof additionalItems !== "boolean"
97
98
  ? additionalItems
98
99
  : {}, uiSchema: Object.assign({ disabled }, ((uiSchema === null || uiSchema === void 0 ? void 0 : uiSchema[index + items.length]) || (uiSchema === null || uiSchema === void 0 ? void 0 : uiSchema.items))) }), _jsxs(ArrayFieldItemButtons, { children: [GetArrayFieldButton({
99
100
  purpose: ArrayFieldButtonPurpose.REMOVE,
@@ -0,0 +1,3 @@
1
+ import type { FieldProps } from "../types";
2
+ import React from "react";
3
+ export declare const MultipleChoiceField: React.FC<FieldProps>;
@@ -0,0 +1,13 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { useContext, useMemo } from "react";
3
+ import { FormRegistry } from "../Form";
4
+ import { useExtractUiSchema, useSetDefault } from "../hooks";
5
+ import { getEnums } from "../utils/getEnums";
6
+ export const MultipleChoiceField = (props) => {
7
+ const { templates: { FieldTemplate }, components: { MultipleChoiceField }, } = useContext(FormRegistry);
8
+ useSetDefault(props);
9
+ const { name, uiSchema } = props;
10
+ const { props: inputProps, option } = useExtractUiSchema(uiSchema);
11
+ const enums = useMemo(() => getEnums(props), [props]);
12
+ return (_jsx(FieldTemplate, Object.assign({}, props, { children: _jsx(MultipleChoiceField, { inputProps: inputProps, name: name, enums: enums, style: option === null || option === void 0 ? void 0 : option.style }) })));
13
+ };
@@ -53,7 +53,9 @@ export const ObjectField = (props) => {
53
53
  return (_jsx(SchemaField, { required: required === null || required === void 0 ? void 0 : required.includes(childName), name: name ? [name, childName].join(".") : childName, schema: typeof childSchema !== "boolean" ? childSchema : {}, uiSchema: uiSchema === null || uiSchema === void 0 ? void 0 : uiSchema[childName] }, childName));
54
54
  })
55
55
  .filter((x) => x), (!hideUnmarkedAdditionalProperties || additionalProperties) &&
56
- Object.entries(additionalValues || {}).map(([childName, childSchema]) => (_jsxs(ObjectFieldItem, { children: [_jsx(SchemaField, { required: required === null || required === void 0 ? void 0 : required.includes(childName), name: name ? [name, childName].join(".") : childName, schema: typeof childSchema !== "boolean" ? childSchema : {}, uiSchema: uiSchema === null || uiSchema === void 0 ? void 0 : uiSchema[childName] }, childName), _jsx(ObjectFieldItemButtons, { children: getObjectFieldButton({
56
+ Object.entries(additionalValues || {}).map(([childName]) => (_jsxs(ObjectFieldItem, { children: [_jsx(SchemaField, { required: required === null || required === void 0 ? void 0 : required.includes(childName), name: name ? [name, childName].join(".") : childName, schema: typeof schema.additionalProperties !== "boolean"
57
+ ? schema.additionalProperties
58
+ : {}, uiSchema: uiSchema === null || uiSchema === void 0 ? void 0 : uiSchema[childName] }, childName), _jsx(ObjectFieldItemButtons, { children: getObjectFieldButton({
57
59
  purpose: ObjectFieldButtonPurpose.REMOVE,
58
60
  onClick: () => {
59
61
  const _a = value, _b = childName, _removedProperty = _a[_b], newValue = __rest(_a, [typeof _b === "symbol" ? _b : _b + ""]);
@@ -1,6 +1,6 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
- import { useContext } from "react";
3
- import { getSchemaType } from "../utils";
2
+ import { useContext, useMemo } from "react";
3
+ import { getSchemaType, solveReferences } from "../utils";
4
4
  import { useExtractUiSchema } from "../hooks";
5
5
  import { FormRegistry } from "../Form";
6
6
  import { COMPONENT_TYPES } from "./types";
@@ -23,7 +23,9 @@ const useFieldComponent = (schema, uiSchema, fields) => {
23
23
  };
24
24
  export const SchemaField = (props) => {
25
25
  const { schema, uiSchema } = props;
26
- const { fields } = useContext(FormRegistry);
27
- const FieldComponent = useFieldComponent(schema, uiSchema, fields);
28
- return _jsx(FieldComponent, Object.assign({}, props));
26
+ const { fields, definitions } = useContext(FormRegistry);
27
+ const schemaSolvedForReferences = useMemo(() => solveReferences(schema, definitions), [schema, definitions]);
28
+ const FieldComponent = useFieldComponent(schemaSolvedForReferences, uiSchema, fields);
29
+ const newProps = Object.assign(Object.assign({}, props), { schema: schemaSolvedForReferences });
30
+ return _jsx(FieldComponent, Object.assign({}, newProps));
29
31
  };
@@ -13,7 +13,7 @@ export const StringField = (props) => {
13
13
  switch (enums === null || enums === void 0 ? void 0 : enums.type) {
14
14
  case "select":
15
15
  case "multiSelect":
16
- return (_jsx(FieldTemplate, Object.assign({}, props, { children: _jsxs(FieldInput, Object.assign({ type }, inputProps, { name: name, formikAs: "select", multiple: enums.type === "multiSelect" }, (enums.type !== "multiSelect" ? { defaultValue: "" } : {}), { children: [enums.type !== "multiSelect" && (_jsx("option", Object.assign({ value: "", disabled: true,
16
+ return (_jsx(FieldTemplate, Object.assign({}, props, { children: _jsxs(FieldInput, Object.assign({ type }, inputProps, { name: name, formikAs: "select", multiple: enums.type === "multiSelect", children: [enums.type !== "multiSelect" && (_jsx("option", Object.assign({ value: "", disabled: true,
17
17
  hidden: true }, (_a = uiSchema["ui:placeholderOptionOptions"]) === null || _a === void 0 ? void 0 : _a.props, { children: placeholder }))), enums === null || enums === void 0 ? void 0 : enums.values.map((option, index) => (_jsx("option", { value: option.const, children: option.title }, index)))] })) })));
18
18
  default:
19
19
  return (_jsx(FieldTemplate, Object.assign({}, props, { children: _jsx(FieldInput, Object.assign({ type,
@@ -10,3 +10,4 @@ export * from "./AnyField";
10
10
  export * from "./RadioField";
11
11
  export * from "./ToggleField";
12
12
  export * from "./SearchMultiTagSelectField";
13
+ export * from "./MultipleChoiceField";
@@ -10,3 +10,4 @@ export * from "./AnyField";
10
10
  export * from "./RadioField";
11
11
  export * from "./ToggleField";
12
12
  export * from "./SearchMultiTagSelectField";
13
+ export * from "./MultipleChoiceField";
@@ -0,0 +1,5 @@
1
+ import { StoryObj } from "@storybook/react";
2
+ import { AnyField } from "./../AnyField";
3
+ declare const _default: import("@storybook/types").ComponentAnnotations<import("@storybook/react").ReactRenderer, import("../../types").FieldProps>;
4
+ export default _default;
5
+ export declare const Default: StoryObj<typeof AnyField>;
@@ -0,0 +1,79 @@
1
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
+ return new (P || (P = Promise))(function (resolve, reject) {
4
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
8
+ });
9
+ };
10
+ import { jsx as _jsx } from "react/jsx-runtime";
11
+ import { within, userEvent, expect } from "@storybook/test";
12
+ import { Formik, Form } from "formik";
13
+ import { AnyField } from "./../AnyField";
14
+ export default {
15
+ title: "Fields/AnyField",
16
+ component: AnyField,
17
+ decorators: [
18
+ (Story) => (_jsx(Formik, { initialValues: { dynamicField: "" }, onSubmit: (values) => console.log(values), children: _jsx(Form, { children: Story() }) })),
19
+ ],
20
+ };
21
+ export const Default = {
22
+ args: {
23
+ name: "dynamicField",
24
+ schema: {},
25
+ uiSchema: {},
26
+ },
27
+ play: (_a) => __awaiter(void 0, [_a], void 0, function* ({ canvasElement }) {
28
+ const canvas = within(canvasElement);
29
+ const select = canvasElement.querySelector("select");
30
+ // Null
31
+ yield userEvent.selectOptions(select, "null");
32
+ const allInputs = canvasElement.querySelectorAll("input");
33
+ expect(allInputs).toHaveLength(0);
34
+ // AnyField
35
+ yield userEvent.selectOptions(select, "any");
36
+ const anySelect = canvasElement.querySelectorAll("select");
37
+ const input = canvasElement.querySelector('input[name="dynamicField"]');
38
+ yield userEvent.type(input, "testString");
39
+ expect(input).toHaveValue("testString");
40
+ yield userEvent.selectOptions(anySelect[1], "boolean");
41
+ yield userEvent.click(input);
42
+ expect(input).toBeChecked;
43
+ // StringField
44
+ yield userEvent.selectOptions(select, "string");
45
+ yield userEvent.type(input, "testString");
46
+ expect(input).toHaveValue("testString");
47
+ // IntegerField
48
+ yield userEvent.selectOptions(select, "integer");
49
+ const integerInput = canvasElement.querySelector('input[name="dynamicField"]');
50
+ yield userEvent.type(integerInput, "321");
51
+ expect(integerInput).toHaveValue(321);
52
+ // NumberField
53
+ yield userEvent.selectOptions(select, "number");
54
+ const numberInput = canvasElement.querySelector('input[name="dynamicField"]');
55
+ yield userEvent.clear(numberInput);
56
+ yield userEvent.type(numberInput, "123");
57
+ expect(numberInput).toHaveValue(123);
58
+ // BooleanField
59
+ yield userEvent.selectOptions(select, "boolean");
60
+ const checkBox = canvasElement.querySelector('input[name="dynamicField"]');
61
+ yield userEvent.click(checkBox);
62
+ expect(checkBox).toBeChecked();
63
+ // ObjectField
64
+ // TODO Find out how to handle modal
65
+ // ArrayField
66
+ yield userEvent.selectOptions(select, "array");
67
+ const addButton = canvas.getByText("+");
68
+ yield userEvent.click(addButton);
69
+ yield userEvent.click(addButton);
70
+ const downArrow = canvas.queryAllByText("↓");
71
+ const inputFirst = canvasElement.querySelector('input[name="dynamicField[0]"]');
72
+ const inputSecond = canvasElement.querySelector('input[name="dynamicField[1]"]');
73
+ yield userEvent.type(inputFirst, "first");
74
+ yield userEvent.type(inputSecond, "second");
75
+ yield userEvent.click(downArrow[0]);
76
+ expect(inputFirst).toHaveValue("second");
77
+ expect(inputSecond).toHaveValue("first");
78
+ }),
79
+ };
@@ -0,0 +1,7 @@
1
+ import { StoryObj } from "@storybook/react";
2
+ import { ArrayField } from "./../ArrayField";
3
+ declare const _default: import("@storybook/types").ComponentAnnotations<import("@storybook/react").ReactRenderer, import("../../types").FieldProps>;
4
+ export default _default;
5
+ export declare const BasicArray: StoryObj<typeof ArrayField>;
6
+ export declare const EnumArray: StoryObj<typeof ArrayField>;
7
+ export declare const ObjectArray: StoryObj<typeof ArrayField>;
@@ -0,0 +1,191 @@
1
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
+ return new (P || (P = Promise))(function (resolve, reject) {
4
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
8
+ });
9
+ };
10
+ import { jsx as _jsx } from "react/jsx-runtime";
11
+ import { within, userEvent, expect } from "@storybook/test";
12
+ import { Formik, Form } from "formik";
13
+ import { ArrayField } from "./../ArrayField";
14
+ export default {
15
+ title: "Fields/ArrayField",
16
+ component: ArrayField,
17
+ decorators: [
18
+ (Story) => (_jsx(Formik, { initialValues: { itemsList: [] }, onSubmit: (values) => console.log(values), children: _jsx(Form, { children: Story() }) })),
19
+ ],
20
+ };
21
+ export const BasicArray = {
22
+ args: {
23
+ name: "itemsList",
24
+ schema: {
25
+ type: "array",
26
+ title: "Array",
27
+ description: "Array description",
28
+ additionalItems: { type: "boolean" },
29
+ },
30
+ uiSchema: {},
31
+ },
32
+ play: (_a) => __awaiter(void 0, [_a], void 0, function* ({ canvasElement }) {
33
+ const canvas = within(canvasElement);
34
+ // Add three items
35
+ const addButton = canvas.getByText("+");
36
+ yield userEvent.click(addButton);
37
+ yield userEvent.click(addButton);
38
+ yield userEvent.click(addButton);
39
+ const allDownArrows = canvas.queryAllByText("↓");
40
+ const allUpArrows = canvas.queryAllByText("↑");
41
+ const firstCheckbox = canvasElement.querySelector('input[name="itemsList[0]"]');
42
+ const secondCheckbox = canvasElement.querySelector('input[name="itemsList[1]"]');
43
+ const thirdCheckbox = canvasElement.querySelector('input[name="itemsList[2]"]');
44
+ const allLabelsAfterAdd = canvasElement.querySelectorAll('[name^="itemsList["]');
45
+ expect(allLabelsAfterAdd.length).toEqual(3);
46
+ // Check that moving items work
47
+ yield userEvent.click(firstCheckbox);
48
+ expect(firstCheckbox).toBeChecked();
49
+ expect(secondCheckbox).not.toBeChecked();
50
+ expect(thirdCheckbox).not.toBeChecked();
51
+ yield userEvent.click(allDownArrows[0]);
52
+ expect(firstCheckbox).not.toBeChecked();
53
+ expect(secondCheckbox).toBeChecked();
54
+ expect(thirdCheckbox).not.toBeChecked();
55
+ yield userEvent.click(allDownArrows[1]);
56
+ expect(firstCheckbox).not.toBeChecked();
57
+ expect(secondCheckbox).not.toBeChecked();
58
+ expect(thirdCheckbox).toBeChecked();
59
+ yield userEvent.click(allUpArrows[1]);
60
+ expect(firstCheckbox).not.toBeChecked();
61
+ expect(secondCheckbox).toBeChecked();
62
+ expect(thirdCheckbox).not.toBeChecked();
63
+ // Remove items
64
+ const removeButton = canvas.queryAllByText("-");
65
+ yield userEvent.click(removeButton[2]);
66
+ yield userEvent.click(removeButton[1]);
67
+ yield userEvent.click(removeButton[0]);
68
+ const allLabelsAfterRemove = canvasElement.querySelectorAll('[name^="itemsList["]');
69
+ expect(allLabelsAfterRemove.length).toEqual(0);
70
+ }),
71
+ };
72
+ export const EnumArray = {
73
+ args: {
74
+ name: "itemsList",
75
+ schema: {
76
+ type: "array",
77
+ title: "Enum array",
78
+ description: "Enum array description",
79
+ additionalItems: {
80
+ type: "number",
81
+ enum: [1, 2, 3, 4],
82
+ },
83
+ },
84
+ uiSchema: {},
85
+ },
86
+ play: (_b) => __awaiter(void 0, [_b], void 0, function* ({ canvasElement }) {
87
+ const canvas = within(canvasElement);
88
+ // Add three items
89
+ const addButton = canvas.getByText("+");
90
+ yield userEvent.click(addButton);
91
+ yield userEvent.click(addButton);
92
+ yield userEvent.click(addButton);
93
+ const allDownArrows = canvas.queryAllByText("↓");
94
+ const allUpArrows = canvas.queryAllByText("↑");
95
+ const firstSelect = canvasElement.querySelector('select[name="itemsList[0]"]');
96
+ const secondSelect = canvasElement.querySelector('select[name="itemsList[1]"]');
97
+ const thirdSelect = canvasElement.querySelector('select[name="itemsList[2]"]');
98
+ const allLabelsAfterAdd = canvasElement.querySelectorAll('[name^="itemsList["]');
99
+ expect(allLabelsAfterAdd.length).toEqual(3);
100
+ yield userEvent.selectOptions(firstSelect, "1");
101
+ yield userEvent.selectOptions(secondSelect, "2");
102
+ yield userEvent.selectOptions(thirdSelect, "3");
103
+ // Check that moving items work
104
+ yield expect(firstSelect).toHaveValue("1");
105
+ yield expect(secondSelect).toHaveValue("2");
106
+ yield expect(thirdSelect).toHaveValue("3");
107
+ yield userEvent.click(allDownArrows[0]);
108
+ yield expect(firstSelect).toHaveValue("2");
109
+ yield expect(secondSelect).toHaveValue("1");
110
+ yield expect(thirdSelect).toHaveValue("3");
111
+ yield userEvent.click(allDownArrows[1]);
112
+ yield expect(firstSelect).toHaveValue("2");
113
+ yield expect(secondSelect).toHaveValue("3");
114
+ yield expect(thirdSelect).toHaveValue("1");
115
+ yield userEvent.click(allUpArrows[1]);
116
+ yield expect(firstSelect).toHaveValue("2");
117
+ yield expect(secondSelect).toHaveValue("1");
118
+ yield expect(thirdSelect).toHaveValue("3");
119
+ // Remove items
120
+ const removeButton = canvas.queryAllByText("-");
121
+ yield userEvent.click(removeButton[2]);
122
+ yield userEvent.click(removeButton[1]);
123
+ yield userEvent.click(removeButton[0]);
124
+ const allLabelsAfterRemove = canvasElement.querySelectorAll('[name^="itemsList["]');
125
+ expect(allLabelsAfterRemove.length).toEqual(0);
126
+ }),
127
+ };
128
+ export const ObjectArray = {
129
+ args: {
130
+ name: "itemsList",
131
+ schema: {
132
+ type: "array",
133
+ title: "Object array",
134
+ description: "Object array description",
135
+ additionalItems: {
136
+ type: "object",
137
+ title: "Item title",
138
+ description: "Item description",
139
+ properties: {
140
+ string: {
141
+ type: "string",
142
+ title: "String field",
143
+ description: "String description",
144
+ },
145
+ number: {
146
+ type: "number",
147
+ title: "Number field",
148
+ description: "Number description",
149
+ },
150
+ },
151
+ },
152
+ },
153
+ uiSchema: {},
154
+ },
155
+ play: (_c) => __awaiter(void 0, [_c], void 0, function* ({ canvasElement }) {
156
+ const canvas = within(canvasElement);
157
+ // Add two items
158
+ const addButton = canvas.getByText("+");
159
+ yield userEvent.click(addButton);
160
+ yield userEvent.click(addButton);
161
+ const allDownArrows = canvas.queryAllByText("↓");
162
+ const allUpArrows = canvas.queryAllByText("↑");
163
+ const firstStringInput = canvasElement.querySelector('input[name="itemsList[0].string"]');
164
+ const secondStringInput = canvasElement.querySelector('input[name="itemsList[1].string"]');
165
+ const firstNumberInput = canvasElement.querySelector('input[name="itemsList[0].number"]');
166
+ const secondNumberInput = canvasElement.querySelector('input[name="itemsList[1].number"]');
167
+ const allLabelsAfterAdd = canvasElement.querySelectorAll('[name^="itemsList["]');
168
+ expect(allLabelsAfterAdd.length).toEqual(4);
169
+ yield userEvent.type(firstStringInput, "first");
170
+ yield userEvent.type(firstNumberInput, "1");
171
+ yield userEvent.type(secondStringInput, "second");
172
+ yield userEvent.type(secondNumberInput, "2");
173
+ // Check that moving items work
174
+ yield userEvent.click(allDownArrows[0]);
175
+ yield expect(firstStringInput).toHaveValue("second");
176
+ yield expect(firstNumberInput).toHaveValue(2);
177
+ yield expect(secondStringInput).toHaveValue("first");
178
+ yield expect(secondNumberInput).toHaveValue(1);
179
+ yield userEvent.click(allUpArrows[0]);
180
+ yield expect(firstStringInput).toHaveValue("first");
181
+ yield expect(firstNumberInput).toHaveValue(1);
182
+ yield expect(secondStringInput).toHaveValue("second");
183
+ yield expect(secondNumberInput).toHaveValue(2);
184
+ // Remove items
185
+ const removeButton = canvas.queryAllByText("-");
186
+ yield userEvent.click(removeButton[1]);
187
+ yield userEvent.click(removeButton[0]);
188
+ const allLabelsAfterRemove = canvasElement.querySelectorAll('[name^="itemsList["]');
189
+ expect(allLabelsAfterRemove.length).toEqual(0);
190
+ }),
191
+ };
@@ -0,0 +1,5 @@
1
+ import { StoryObj } from "@storybook/react";
2
+ import { BooleanField } from "./../BooleanField";
3
+ declare const _default: import("@storybook/types").ComponentAnnotations<import("@storybook/react").ReactRenderer, import("../../types").FieldProps>;
4
+ export default _default;
5
+ export declare const Default: StoryObj<typeof BooleanField>;