@nolwenture/formik-jsonschema-form 0.7.0 → 0.8.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 (67) hide show
  1. package/README.md +52 -1
  2. package/dist/Form.stories.d.ts +1 -0
  3. package/dist/Form.stories.js +8 -0
  4. package/dist/Form.test.d.ts +1 -1
  5. package/dist/Form.test.js +3 -1
  6. package/dist/fields/ArrayField.js +1 -1
  7. package/dist/fields/MultipleChoiceField.d.ts +3 -0
  8. package/dist/fields/MultipleChoiceField.js +15 -0
  9. package/dist/fields/ObjectField.js +3 -1
  10. package/dist/fields/StringField.js +1 -1
  11. package/dist/fields/index.d.ts +1 -0
  12. package/dist/fields/index.js +1 -0
  13. package/dist/fields/stories/AnyField.stories.d.ts +5 -0
  14. package/dist/fields/stories/AnyField.stories.js +79 -0
  15. package/dist/fields/stories/ArrayField.stories.d.ts +7 -0
  16. package/dist/fields/stories/ArrayField.stories.js +191 -0
  17. package/dist/fields/stories/BooleanField.stories.d.ts +5 -0
  18. package/dist/fields/stories/BooleanField.stories.js +36 -0
  19. package/dist/fields/stories/DateField.stories.d.ts +5 -0
  20. package/dist/fields/stories/DateField.stories.js +34 -0
  21. package/dist/fields/stories/NullField.stories.d.ts +5 -0
  22. package/dist/fields/stories/NullField.stories.js +38 -0
  23. package/dist/fields/stories/NumberField.stories.d.ts +5 -0
  24. package/dist/fields/stories/NumberField.stories.js +33 -0
  25. package/dist/fields/stories/ObjectField.stories.d.ts +5 -0
  26. package/dist/fields/stories/ObjectField.stories.js +76 -0
  27. package/dist/fields/stories/RadioField.stories.d.ts +5 -0
  28. package/dist/fields/stories/RadioField.stories.js +42 -0
  29. package/dist/fields/stories/SchemaField.stories.d.ts +1673 -0
  30. package/dist/fields/stories/SchemaField.stories.js +39 -0
  31. package/dist/fields/stories/SearchMultiTagSelectField.stories.d.ts +5 -0
  32. package/dist/fields/stories/SearchMultiTagSelectField.stories.js +58 -0
  33. package/dist/fields/stories/StringField.stories.d.ts +7 -0
  34. package/dist/fields/stories/StringField.stories.js +75 -0
  35. package/dist/fields/stories/ToggleField.stories.d.ts +5 -0
  36. package/dist/fields/stories/ToggleField.stories.js +34 -0
  37. package/dist/hooks/__tests__/useExtractUiSchema.test.d.ts +1 -0
  38. package/dist/hooks/__tests__/useExtractUiSchema.test.js +45 -0
  39. package/dist/hooks/__tests__/useSetDefault.test.d.ts +1 -0
  40. package/dist/hooks/__tests__/useSetDefault.test.js +65 -0
  41. package/dist/hooks/useExtractUiSchema.js +7 -3
  42. package/dist/sampleData/multipleChoiceSchema.d.ts +3 -0
  43. package/dist/sampleData/multipleChoiceSchema.js +112 -0
  44. package/dist/sampleData/requiredInputSchema.js +0 -5
  45. package/dist/styledComponents.d.ts +2 -1
  46. package/dist/styledComponents.js +15 -9
  47. package/dist/types.d.ts +15 -0
  48. package/dist/utils/__tests/createInitialValues.test.d.ts +1 -0
  49. package/dist/utils/__tests/createInitialValues.test.js +72 -0
  50. package/dist/utils/__tests/deepOverlap.test.d.ts +1 -0
  51. package/dist/utils/__tests/deepOverlap.test.js +41 -0
  52. package/dist/utils/__tests/getEnums.test.js +11 -16
  53. package/dist/utils/__tests/getTitleAndDescription.test.d.ts +1 -0
  54. package/dist/utils/__tests/getTitleAndDescription.test.js +53 -0
  55. package/dist/utils/__tests/getTypes.test.d.ts +1 -0
  56. package/dist/utils/__tests/getTypes.test.js +62 -0
  57. package/dist/utils/__tests/mergeSchemas.test.d.ts +1 -0
  58. package/dist/utils/__tests/mergeSchemas.test.js +40 -0
  59. package/dist/utils/__tests/resolveSchema.test.js +28 -28
  60. package/dist/utils/createInitialValues.d.ts +4 -0
  61. package/dist/utils/createInitialValues.js +27 -0
  62. package/dist/utils/getStyle.d.ts +5 -0
  63. package/dist/utils/getStyle.js +18 -0
  64. package/dist/utils/getTypes.js +1 -1
  65. package/dist/utils/index.d.ts +1 -0
  66. package/dist/utils/index.js +1 -0
  67. package/package.json +5 -2
@@ -0,0 +1,39 @@
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 { userEvent, expect } from "@storybook/test";
12
+ import { Formik, Form } from "formik";
13
+ import { SchemaField } from "./../SchemaField";
14
+ export default {
15
+ title: "Fields/SchemaField",
16
+ component: SchemaField,
17
+ decorators: [
18
+ (Story) => (_jsx(Formik, { initialValues: {}, onSubmit: () => { }, children: _jsx(Form, { children: Story() }) })),
19
+ ],
20
+ };
21
+ const Template = {
22
+ args: {
23
+ name: "myField",
24
+ schema: {
25
+ type: "string",
26
+ },
27
+ uiSchema: {},
28
+ },
29
+ };
30
+ export const StringField = Object.assign(Object.assign({}, Template), { args: Object.assign(Object.assign({}, Template.args), { schema: { type: "string", title: "My String Field" }, uiSchema: { "ui:help": "Enter a string" } }), play: (_a) => __awaiter(void 0, [_a], void 0, function* ({ canvasElement }) {
31
+ const input = canvasElement.querySelector('input[name="myField"]');
32
+ yield userEvent.type(input, "Hello World");
33
+ expect(input).toHaveValue("Hello World");
34
+ }) });
35
+ export const NumberField = Object.assign(Object.assign({}, Template), { args: Object.assign(Object.assign({}, Template.args), { schema: { type: "number", title: "My Number Field" }, uiSchema: { "ui:help": "Enter a number" } }), play: (_b) => __awaiter(void 0, [_b], void 0, function* ({ canvasElement }) {
36
+ const input = canvasElement.querySelector('input[name="myField"]');
37
+ yield userEvent.type(input, "123");
38
+ expect(input).toHaveValue(123);
39
+ }) });
@@ -0,0 +1,5 @@
1
+ import { StoryObj } from "@storybook/react";
2
+ import { SearchMultiTagSelectField } from "./../SearchMultiTagSelectField";
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 SearchMultiTagSelectField>;
@@ -0,0 +1,58 @@
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 { SearchMultiTagSelectField } from "./../SearchMultiTagSelectField";
13
+ import { Formik, Form } from "formik";
14
+ export default {
15
+ title: "Components/SearchMultiTagSelectField",
16
+ component: SearchMultiTagSelectField,
17
+ decorators: [
18
+ (Story) => (_jsx(Formik, { initialValues: { tags: [] }, onSubmit: () => { }, children: _jsx(Form, { children: Story() }) })),
19
+ ],
20
+ };
21
+ export const Default = {
22
+ args: {
23
+ name: "tags",
24
+ schema: {
25
+ type: "string",
26
+ title: "Enum searchable tag select anyOf",
27
+ anyOf: [
28
+ { const: "1", title: "First tag" },
29
+ { const: "2", title: "Second tag" },
30
+ { const: "3", title: "Third tag" },
31
+ ],
32
+ },
33
+ uiSchema: {
34
+ "ui:placeholder": "Search tags...",
35
+ "ui:emptySearchMessage": "No tags found",
36
+ },
37
+ },
38
+ play: (_a) => __awaiter(void 0, [_a], void 0, function* ({ canvasElement }) {
39
+ const canvas = within(canvasElement);
40
+ const input = canvas.getByPlaceholderText("Search tags...");
41
+ yield userEvent.type(input, "First tag");
42
+ const option = yield canvas.findByText("First tag");
43
+ yield userEvent.click(option);
44
+ yield userEvent.type(input, "Third tag");
45
+ const option2 = yield canvas.findByText("Third tag");
46
+ yield userEvent.click(option2);
47
+ const firstTag = canvas.queryByText("First tag");
48
+ const secondTag = canvas.queryByText("Second tag");
49
+ const thirdTag = canvas.queryByText("Third tag");
50
+ expect(firstTag).toBeInTheDocument();
51
+ expect(secondTag).not.toBeInTheDocument();
52
+ expect(thirdTag).toBeInTheDocument();
53
+ // await userEvent.click(firstTag.nextElementSibling as Element);
54
+ // await userEvent.click(thirdTag.nextSibling as Element);
55
+ // expect(firstTag).not.toBeInTheDocument();
56
+ // expect(thirdTag).not.toBeInTheDocument();
57
+ }),
58
+ };
@@ -0,0 +1,7 @@
1
+ import { StoryObj } from "@storybook/react";
2
+ import { StringField } from "./../StringField";
3
+ declare const _default: import("@storybook/types").ComponentAnnotations<import("@storybook/react").ReactRenderer, import("../../types").FieldProps>;
4
+ export default _default;
5
+ export declare const TextInput: StoryObj<typeof StringField>;
6
+ export declare const SelectInput: StoryObj<typeof StringField>;
7
+ export declare const MultiSelect: StoryObj<typeof StringField>;
@@ -0,0 +1,75 @@
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 { userEvent, expect } from "@storybook/test";
12
+ import { StringField } from "./../StringField";
13
+ import { Formik, Form } from "formik";
14
+ export default {
15
+ title: "Components/StringField",
16
+ component: StringField,
17
+ decorators: [
18
+ (Story) => (_jsx(Formik, { initialValues: { name: "" }, onSubmit: () => { }, children: _jsx(Form, { children: Story() }) })),
19
+ ],
20
+ };
21
+ // Story for a regular text input
22
+ export const TextInput = {
23
+ args: {
24
+ name: "name",
25
+ schema: { type: "string" },
26
+ uiSchema: {},
27
+ },
28
+ play: (_a) => __awaiter(void 0, [_a], void 0, function* ({ canvasElement }) {
29
+ const input = canvasElement.querySelector('input[name="name"]');
30
+ yield userEvent.type(input, "John Doe");
31
+ yield expect(input).toHaveValue("John Doe");
32
+ }),
33
+ };
34
+ export const SelectInput = {
35
+ args: {
36
+ name: "select",
37
+ schema: {
38
+ type: "string",
39
+ oneOf: [
40
+ { const: "1", title: "Option 1" },
41
+ { const: "2", title: "Option 2" },
42
+ ],
43
+ },
44
+ uiSchema: {},
45
+ },
46
+ play: (_b) => __awaiter(void 0, [_b], void 0, function* ({ canvasElement }) {
47
+ const select = canvasElement.querySelector('select[name="select"]');
48
+ yield userEvent.selectOptions(select, "1");
49
+ yield expect(select).toHaveValue("1");
50
+ yield expect(select).toHaveDisplayValue("Option 1");
51
+ yield userEvent.selectOptions(select, "2");
52
+ yield expect(select).toHaveValue("2");
53
+ yield expect(select).toHaveDisplayValue("Option 2");
54
+ }),
55
+ };
56
+ export const MultiSelect = {
57
+ args: {
58
+ name: "multiSelect",
59
+ schema: {
60
+ type: "array",
61
+ anyOf: [
62
+ { const: "1", title: "Option 1" },
63
+ { const: "2", title: "Option 2" },
64
+ { const: "3", title: "Option 3" },
65
+ ],
66
+ },
67
+ uiSchema: {},
68
+ },
69
+ play: (_c) => __awaiter(void 0, [_c], void 0, function* ({ canvasElement }) {
70
+ const multiSelect = canvasElement.querySelector('select[name="multiSelect"]');
71
+ yield userEvent.selectOptions(multiSelect, ["1", "3"]);
72
+ yield expect(multiSelect).toHaveValue(["1", "3"]);
73
+ yield expect(multiSelect).not.toHaveValue(["2"]);
74
+ }),
75
+ };
@@ -0,0 +1,5 @@
1
+ import { StoryObj } from "@storybook/react";
2
+ import { ToggleField } from "../ToggleField";
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 ToggleField>;
@@ -0,0 +1,34 @@
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 { userEvent, expect } from "@storybook/test";
12
+ import { ToggleField } from "../ToggleField";
13
+ import { Formik, Form } from "formik";
14
+ export default {
15
+ title: "Components/ToggleField",
16
+ component: ToggleField,
17
+ decorators: [
18
+ (Story) => (_jsx(Formik, { initialValues: { toggle: false }, onSubmit: () => { }, children: _jsx(Form, { children: Story() }) })),
19
+ ],
20
+ };
21
+ export const Default = {
22
+ args: {
23
+ name: "toggle",
24
+ schema: { type: "boolean", default: false },
25
+ uiSchema: {},
26
+ },
27
+ play: (_a) => __awaiter(void 0, [_a], void 0, function* ({ canvasElement }) {
28
+ const toggleSwitch = canvasElement.querySelector('input[type="checkbox"][name="toggle"]');
29
+ yield userEvent.click(toggleSwitch);
30
+ yield expect(toggleSwitch).toBeChecked();
31
+ yield userEvent.click(toggleSwitch);
32
+ yield expect(toggleSwitch).not.toBeChecked();
33
+ }),
34
+ };
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,45 @@
1
+ import { renderHook } from "@testing-library/react";
2
+ import { useExtractUiSchema } from "../useExtractUiSchema"; // Adjust the import path as needed
3
+ describe("useExtractUiSchema", () => {
4
+ it("should return an empty object when provided with an empty object", () => {
5
+ const { result } = renderHook(() => useExtractUiSchema({}));
6
+ expect(result.current).toEqual({});
7
+ });
8
+ it("should correctly extract ui:field and ui:props", () => {
9
+ const uiSchema = {
10
+ "ui:field": "TextField",
11
+ "ui:props": { className: "test-class" },
12
+ };
13
+ const { result } = renderHook(() => useExtractUiSchema(uiSchema));
14
+ expect(result.current.field).toBe("TextField");
15
+ expect(result.current.props).toEqual({ className: "test-class" });
16
+ });
17
+ it("should handle ui:options and merge them into the result", () => {
18
+ const uiSchema = {
19
+ "ui:options": {
20
+ anotherProp: "value",
21
+ },
22
+ };
23
+ const { result } = renderHook(() => useExtractUiSchema(uiSchema));
24
+ expect(result.current.anotherProp).toBe("value");
25
+ });
26
+ it("should remove 'ui:' prefix from keys", () => {
27
+ const uiSchema = {
28
+ "ui:title": "Test Title",
29
+ "ui:description": "Test Description",
30
+ };
31
+ const { result } = renderHook(() => useExtractUiSchema(uiSchema));
32
+ expect(result.current.title).toBe("Test Title");
33
+ expect(result.current.description).toBe("Test Description");
34
+ });
35
+ it("does not crash if schema is frozen by React", () => {
36
+ const uiSchema = { props: { not: { freezed: true } } };
37
+ const frozen = Object.freeze(uiSchema);
38
+ const { result } = renderHook(() => useExtractUiSchema(frozen));
39
+ expect(result.current.props).toEqual({ not: { freezed: true } });
40
+ const uiSchema2 = { props: { is: { extendable: true } } };
41
+ const notExtendable = Object.preventExtensions(uiSchema2);
42
+ const { result: result2 } = renderHook(() => useExtractUiSchema(notExtendable));
43
+ expect(result2.current.props).toEqual({ is: { extendable: true } });
44
+ });
45
+ });
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,65 @@
1
+ import { renderHook } from "@testing-library/react";
2
+ import { useField } from "formik";
3
+ import { useSetDefault } from "../useSetDefault";
4
+ import { getDefaultValueForType } from "../../utils/getTypes";
5
+ jest.mock("formik", () => ({
6
+ useField: jest.fn(),
7
+ }));
8
+ jest.mock("../../utils/getTypes", () => ({
9
+ getDefaultValueForType: jest.fn(),
10
+ }));
11
+ describe("useSetDefault", () => {
12
+ beforeEach(() => {
13
+ jest.clearAllMocks();
14
+ });
15
+ test("sets default value from schema if present", () => {
16
+ const mockSetValue = jest.fn();
17
+ useField.mockReturnValue([
18
+ { value: "" },
19
+ {},
20
+ { setValue: mockSetValue },
21
+ ]);
22
+ const fieldProps = {
23
+ name: "testField",
24
+ schema: { default: "defaultValue" },
25
+ uiSchema: {},
26
+ forceDefaultValue: false,
27
+ };
28
+ renderHook(() => useSetDefault(fieldProps));
29
+ expect(mockSetValue).toHaveBeenCalledWith("defaultValue");
30
+ });
31
+ test("sets default value using getDefaultValueForType if forceDefaultValue is true and no default is provided in schema", () => {
32
+ const mockSetValue = jest.fn();
33
+ useField.mockReturnValue([
34
+ { value: "" },
35
+ {},
36
+ { setValue: mockSetValue },
37
+ ]);
38
+ getDefaultValueForType.mockReturnValue("generatedDefaultValue");
39
+ const fieldProps = {
40
+ name: "testField",
41
+ schema: { type: [] },
42
+ uiSchema: {},
43
+ forceDefaultValue: true,
44
+ };
45
+ renderHook(() => useSetDefault(fieldProps));
46
+ expect(mockSetValue).toHaveBeenCalledWith("generatedDefaultValue");
47
+ expect(getDefaultValueForType).toHaveBeenCalledWith([]);
48
+ });
49
+ test("does not set default value if value is already set", () => {
50
+ const mockSetValue = jest.fn();
51
+ useField.mockReturnValue([
52
+ { value: "existingValue" },
53
+ {},
54
+ { setValue: mockSetValue },
55
+ ]);
56
+ const fieldProps = {
57
+ name: "testField",
58
+ schema: { default: "defaultValue" },
59
+ uiSchema: {},
60
+ forceDefaultValue: true,
61
+ };
62
+ renderHook(() => useSetDefault(fieldProps));
63
+ expect(mockSetValue).not.toHaveBeenCalled();
64
+ });
65
+ });
@@ -12,11 +12,15 @@ var __rest = (this && this.__rest) || function (s, e) {
12
12
  import { useMemo } from "react";
13
13
  export const useExtractUiSchema = (props = {}) => {
14
14
  var _a, _b;
15
- if (props.props !== undefined) {
16
- props["ui:props"] = Object.assign(Object.assign({}, ((_a = props["ui:props"]) !== null && _a !== void 0 ? _a : {})), ((_b = props.props) !== null && _b !== void 0 ? _b : {}));
15
+ // props is frozen by React, so it needs to be copied
16
+ const schema = Object.assign({}, props);
17
+ if (schema.props !== undefined) {
18
+ schema["ui:props"] = Object.assign(Object.assign({}, ((_a = schema["ui:props"]) !== null && _a !== void 0 ? _a : {})), ((_b = schema.props) !== null && _b !== void 0 ? _b : {}));
17
19
  }
18
20
  return useMemo(() => {
19
- const { "ui:options": options = {} } = props, uiSchema = __rest(props, ["ui:options"]);
21
+ const { "ui:options": options = {} } = schema, uiSchema = __rest(schema, ["ui:options"]);
20
22
  return Object.assign(Object.assign({}, Object.keys(uiSchema || {}).reduce((result, key) => (Object.assign(Object.assign({}, result), { [key.replace("ui:", "")]: uiSchema[key] })), {})), options);
23
+ // Input props needs to be relied, not schema. Otherwise, it will be recomputed on every render.
24
+ // eslint-disable-next-line react-hooks/exhaustive-deps
21
25
  }, [props]);
22
26
  };
@@ -0,0 +1,3 @@
1
+ import type { Schema, UiSchema } from "../types";
2
+ export declare const multipleChoiceSchema: Schema;
3
+ export declare const multipleChoiceUiSchema: UiSchema;
@@ -0,0 +1,112 @@
1
+ export const multipleChoiceSchema = {
2
+ title: "TITLE",
3
+ required: ["lastName", "requiredNestedObject", "requiredArray"],
4
+ properties: {
5
+ weather: {
6
+ type: "string",
7
+ title: "What is the weather like today? (no style given)",
8
+ oneOf: [
9
+ { const: "sunny", title: "Sunny" },
10
+ { const: "cloudy", title: "Cloudy" },
11
+ { const: "rainy", title: "Rainy" },
12
+ { const: "windy", title: "Windy" },
13
+ ],
14
+ },
15
+ feeling: {
16
+ type: "string",
17
+ title: "How are you feeling today? (style: inline)",
18
+ oneOf: [
19
+ { const: "happy", title: "Happy" },
20
+ { const: "creative", title: "Creative" },
21
+ { const: "tired", title: "Tired" },
22
+ { const: "nope", title: "Please don't even ask..." },
23
+ ],
24
+ },
25
+ food: {
26
+ type: "string",
27
+ title: "What would you like to eat today? (style: oneColumn)",
28
+ anyOf: [
29
+ { const: "breakfast", title: "Breakfast" },
30
+ { const: "secondBreakfast", title: "What about second breakfast?" },
31
+ { const: "elevenses", title: "Elevenses" },
32
+ { const: "luncheon", title: "Luncheon" },
33
+ { const: "afternoonTea", title: "Afternoon tea" },
34
+ { const: "dinner", title: "Dinner" },
35
+ { const: "supper", title: "Supper" },
36
+ ],
37
+ },
38
+ drinks: {
39
+ type: "string",
40
+ title: "What would you like to drink today? (style: twoColumns)",
41
+ anyOf: [
42
+ { const: "water", title: "Water" },
43
+ { const: "coffee", title: "Coffee" },
44
+ { const: "tea", title: "Tea" },
45
+ { const: "milk", title: "Milk" },
46
+ { const: "nonMilk", title: "Non-dairy milk" },
47
+ { const: "juice", title: "Juice" },
48
+ { const: "beer", title: "Beer" },
49
+ { const: "wine", title: "Wine" },
50
+ { const: "cocktail", title: "Cocktail" },
51
+ { const: "mocktail", title: "Mocktail" },
52
+ { const: "somethingElse", title: "Something else" },
53
+ ],
54
+ },
55
+ flowers: {
56
+ type: "string",
57
+ title: "Pick some flowers (style: threeColumns)",
58
+ anyOf: [
59
+ { const: "lily", title: "Lily" },
60
+ { const: "rose", title: "Rose" },
61
+ { const: "iris", title: "Iris" },
62
+ { const: "tulip", title: "Tulip" },
63
+ { const: "dahlia", title: "Dahlia" },
64
+ { const: "daisy", title: "Daisy" },
65
+ { const: "sunflower", title: "Sunflower" },
66
+ { const: "orchid", title: "Orchid" },
67
+ { const: "carnation", title: "Carnation" },
68
+ { const: "poppy", title: "Poppy" },
69
+ { const: "gerbera", title: "Gerbera" },
70
+ { const: "camellia", title: "Camellia" },
71
+ { const: "aster", title: "Aster" },
72
+ { const: "marigold", title: "Marigold" },
73
+ { const: "calendula", title: "Calendula" },
74
+ { const: "lilac", title: "Lilac" },
75
+ { const: "primrose", title: "Primrose" },
76
+ { const: "daffodil", title: "Daffodil" },
77
+ { const: "oleander", title: "Oleander" },
78
+ { const: "buttercups", title: "Buttercups" },
79
+ { const: "lotus", title: "Lotus" },
80
+ ],
81
+ },
82
+ },
83
+ };
84
+ export const multipleChoiceUiSchema = {
85
+ weather: {
86
+ "ui:field": "MultipleChoiceField",
87
+ },
88
+ feeling: {
89
+ "ui:field": "MultipleChoiceField",
90
+ "ui:option": {
91
+ style: "inline",
92
+ },
93
+ },
94
+ food: {
95
+ "ui:field": "MultipleChoiceField",
96
+ "ui:option": {
97
+ style: "oneColumn",
98
+ },
99
+ },
100
+ drinks: {
101
+ "ui:field": "MultipleChoiceField",
102
+ "ui:option": {
103
+ style: "twoColumns",
104
+ },
105
+ },
106
+ flowers: {
107
+ "ui:field": "MultipleChoiceField",
108
+ "ui:option": {
109
+ style: "threeColumns",
110
+ },
111
+ },
112
+ };
@@ -4,7 +4,6 @@ export const requiredInputSchema = {
4
4
  properties: {
5
5
  firstName: { type: "string", title: "First name" },
6
6
  lastName: { type: "string", title: "Last name" },
7
- feeling: { type: "boolean", title: "Feeling happy today?" },
8
7
  vibes: { type: "boolean", title: "Turn on the good vibes" },
9
8
  arrayOfObject: {
10
9
  type: "array",
@@ -62,10 +61,6 @@ export const requiredInputSchema = {
62
61
  },
63
62
  };
64
63
  export const requiredInputUiSchema = {
65
- feeling: {
66
- "ui:field": "RadioField",
67
- "ui:label": { true: "yes", false: "no" },
68
- },
69
64
  vibes: {
70
65
  "ui:field": "ToggleField",
71
66
  },
@@ -1,5 +1,5 @@
1
1
  /// <reference types="hoist-non-react-statics" />
2
- import type { ArrayFieldButtonProps, InfoFieldButtonProps, ObjectFieldButtonProps, RadioButtonFieldProps, ToggleSwitchFieldProps, SelectFieldProps } from "./types";
2
+ import type { ArrayFieldButtonProps, InfoFieldButtonProps, ObjectFieldButtonProps, RadioButtonFieldProps, ToggleSwitchFieldProps, SelectFieldProps, MultipleChoiceFieldProps } from "./types";
3
3
  import React from "react";
4
4
  import * as formik from "formik";
5
5
  export declare const Form: import("styled-components").IStyledComponent<"web", import("styled-components/dist/types").FastOmit<Omit<Omit<React.DetailedHTMLProps<React.FormHTMLAttributes<HTMLFormElement>, HTMLFormElement>, "ref"> & React.RefAttributes<HTMLFormElement>, "ref"> & {
@@ -166,6 +166,7 @@ export declare const RadioButtonField: {
166
166
  }, never>> & Omit<import("styled-components").IStyledComponent<"web", import("styled-components/dist/types").FastOmit<React.DetailedHTMLProps<React.HTMLAttributes<HTMLSpanElement>, HTMLSpanElement>, never>>, keyof React.Component<any, {}, any>>;
167
167
  };
168
168
  };
169
+ export declare const MultipleChoiceField: ({ inputProps, name, className, enums, style, }: MultipleChoiceFieldProps) => import("react/jsx-runtime").JSX.Element;
169
170
  export declare const MultiSelectContainer: import("styled-components").IStyledComponent<"web", import("styled-components/dist/types").FastOmit<React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, never>>;
170
171
  export declare const MultiSelectInput: import("styled-components").IStyledComponent<"web", import("styled-components/dist/types").FastOmit<Omit<import("styled-components/dist/types").FastOmit<Omit<Omit<any, "as">, "ref"> & {
171
172
  ref?: unknown;
@@ -15,6 +15,7 @@ import styled from "styled-components";
15
15
  import * as formik from "formik";
16
16
  import { FormRegistry } from "./Form";
17
17
  import { ArrayFieldButtonPurpose, ObjectFieldButtonPurpose } from "./types";
18
+ import { getStyle } from "./utils/getStyle";
18
19
  export const Form = styled(formik.Form) ``;
19
20
  export const FormButtonWrapper = styled.div ``;
20
21
  export const FormButton = styled.button ``;
@@ -289,6 +290,15 @@ export const RadioButtonField = ({ label, inputProps, name, className, }) => {
289
290
  var _a, _b;
290
291
  return (_jsxs(RadioButtonFieldContainer, { className: className, children: [_jsxs(RadioButtonFieldElement, { children: [_jsx(RadioButtonFieldInput, Object.assign({}, inputProps, { name: name, type: "radio", value: "true" })), _jsx(ButtonLabelTrue, { children: (_a = label === null || label === void 0 ? void 0 : label.true) !== null && _a !== void 0 ? _a : "true" })] }), _jsxs(RadioButtonFieldElement, { children: [_jsx(RadioButtonFieldInput, Object.assign({}, inputProps, { name: name, type: "radio", value: "false" })), _jsx(ButtonLabelFalse, { children: (_b = label === null || label === void 0 ? void 0 : label.false) !== null && _b !== void 0 ? _b : "false" })] })] }));
291
292
  };
293
+ const MultipleChoiceFieldContainer = styled(RadioButtonFieldContainer) ``;
294
+ const MultipleChoiceFieldElement = styled(RadioButtonFieldElement) ``;
295
+ const MultipleChoiceFieldInput = styled(RadioButtonFieldInput) ``;
296
+ const MultipleChoiceFieldLabel = styled(ButtonLabel) ``;
297
+ export const MultipleChoiceField = ({ inputProps, name, className, enums, style, }) => {
298
+ console.log("style", style);
299
+ console.log("function", getStyle(style !== null && style !== void 0 ? style : ""));
300
+ return (_jsx(MultipleChoiceFieldContainer, { className: className, style: getStyle(style !== null && style !== void 0 ? style : ""), children: enums.values.map((v) => (_jsxs(MultipleChoiceFieldElement, { children: [_jsx(MultipleChoiceFieldInput, Object.assign({}, inputProps, { name: name, type: enums.type === "multiSelect" ? "checkbox" : "radio", value: typeof v === "string" || typeof v === "number" ? v : v.const })), _jsx(MultipleChoiceFieldLabel, { children: typeof v === "string" || typeof v === "number" ? v : v.title })] }, typeof v === "string" || typeof v === "number" ? v : v.const))) }));
301
+ };
292
302
  RadioButtonField.styles = {
293
303
  RadioButtonFieldContainerStyle: RadioButtonFieldContainer,
294
304
  RadioButtonFieldElementStyle: RadioButtonFieldElement,
@@ -352,22 +362,18 @@ export const SearchableMultiTagSelectField = ({ name, placeholder, enums, emptyS
352
362
  const hasValue = enums === null || enums === void 0 ? void 0 : enums.values.map((value) => value.title.toLowerCase().includes(search.toLowerCase()));
353
363
  return hasValue === null || hasValue === void 0 ? void 0 : hasValue.includes(true);
354
364
  };
355
- return (_jsx(formik.Field, { className: className, name: name, multiple: true, children: ({ field, form: { setValues }, meta, }) => {
365
+ return (_jsx(formik.Field, { className: className, name: name, multiple: true, children: ({ field, form: { setFieldValue }, meta, }) => {
356
366
  var _a;
357
367
  return (_jsxs(MultiSelectContainer, { className: className, children: [_jsx(FieldInput, Object.assign({ type: "hidden" }, field)), _jsx(MultiSelectInput, { className: className, type: "text", onChange: (e) => {
358
368
  setSearch(e.currentTarget.value);
359
369
  }, placeholder: placeholder, value: search }), _jsx(MultiSelectBadgeContainer, { children: ((_a = field.value) !== null && _a !== void 0 ? _a : []).map((value) => {
360
370
  var _a;
361
- return (_jsxs(MultiSelectBadge, { children: [(_a = enums === null || enums === void 0 ? void 0 : enums.values.find((option) => option.const === value)) === null || _a === void 0 ? void 0 : _a.title, _jsx(MultiSelectBadgeCloseElement, { onClick: () => setValues({
362
- [name]: field.value.filter((v) => v !== value),
363
- }), children: closeElement !== null && closeElement !== void 0 ? closeElement : "x" })] }, value));
371
+ return (_jsxs(MultiSelectBadge, { children: [(_a = enums === null || enums === void 0 ? void 0 : enums.values.find((option) => option.const === value)) === null || _a === void 0 ? void 0 : _a.title, _jsx(MultiSelectBadgeCloseElement, { onClick: () => setFieldValue(name, field.value.filter((v) => v !== value)), children: closeElement !== null && closeElement !== void 0 ? closeElement : "x" })] }, value));
364
372
  }) }), search.length > 0 && (_jsx(MultiSelectOptionList, { children: searchIncludedInEnum() ? (enums === null || enums === void 0 ? void 0 : enums.values.filter((item) => { var _a; return !((_a = field.value) !== null && _a !== void 0 ? _a : []).includes(item.const); }).filter((value) => value.title.toLowerCase().includes(search.toLowerCase())).map((option, index) => (_jsx(MultiSelectOptionListItem, { value: option.const, onClick: () => {
365
373
  var _a;
366
- setValues({
367
- [name]: [
368
- ...new Set([...((_a = field.value) !== null && _a !== void 0 ? _a : []), option.const]),
369
- ],
370
- });
374
+ setFieldValue(name, [
375
+ ...new Set([...((_a = field.value) !== null && _a !== void 0 ? _a : []), option.const]),
376
+ ]);
371
377
  setSearch("");
372
378
  }, children: option.title }, index)))) : (_jsx(MultiSelectOptionListWithoutItem, { children: emptySearchMessage !== null && emptySearchMessage !== void 0 ? emptySearchMessage : "No match found" })) })), meta.touched && meta.error && (_jsx("div", { className: "error", children: meta.error }))] }));
373
379
  } }));
package/dist/types.d.ts CHANGED
@@ -127,6 +127,7 @@ export type ComponentsType = {
127
127
  FieldInput: React.FunctionComponent<any>;
128
128
  RequiredIndicator: React.FunctionComponent<any>;
129
129
  RadioButtonField: React.FunctionComponent<any>;
130
+ MultipleChoiceField: React.FunctionComponent<any>;
130
131
  ToggleSwitchField: React.FunctionComponent<any>;
131
132
  SearchableMultiTagSelectField: React.FunctionComponent<any>;
132
133
  };
@@ -169,6 +170,20 @@ export type RadioButtonFieldProps = {
169
170
  name?: React.ReactNode;
170
171
  className?: string;
171
172
  };
173
+ type Enum = {
174
+ type: string;
175
+ values: {
176
+ const: number | string;
177
+ title: string;
178
+ }[] | number[] | string[];
179
+ };
180
+ export type MultipleChoiceFieldProps = {
181
+ inputProps?: any;
182
+ name?: React.ReactNode;
183
+ className?: string;
184
+ enums: Enum;
185
+ style?: string;
186
+ };
172
187
  export type ToggleSwitchFieldProps = {
173
188
  inputProps: any;
174
189
  name: React.ReactNode;
@@ -0,0 +1 @@
1
+ export {};