From 2dab9d73b98a15c56c4c8298867fc35943109d8d Mon Sep 17 00:00:00 2001 From: Romain Lenzotti Date: Tue, 7 Jan 2025 08:54:22 +0100 Subject: [PATCH 01/12] chore: update storybook configuration --- .storybook/main.ts | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/.storybook/main.ts b/.storybook/main.ts index 233c8d4..8ef62ef 100644 --- a/.storybook/main.ts +++ b/.storybook/main.ts @@ -6,9 +6,20 @@ const config: StorybookConfig = { stories: [ "../stories/Getting-started.mdx", "../stories/**/*.mdx", - "../packages/{tailwind-formio,react-formio}/src/**/*.mdx", - "../packages/{tailwind-formio,react-formio}/src/**/*.stories.@(js|jsx|ts|tsx)", - "../packages/{tailwind-formio,react-formio}/src/**/*.story.@(js|jsx|ts|tsx)" + { + titlePrefix: "Molecules", + directory: "../packages/react-formio/src/molecules" + }, + // { + // titlePrefix: "@tsed/react-formio/Organisms", + // directory: "../packages/react-formio/src/organisms/**/*.stories.@(js|jsx|ts|tsx)" + // }, + "../packages/react-formio/src/components/**/*.mdx", + "../packages/react-formio/src/components/**/*.stories.@(js|jsx|ts|tsx)", + "../packages/react-formio/src/components/**/*.story.@(js|jsx|ts|tsx)", + "../packages/tailwind-formio/src/**/*.mdx", + "../packages/tailwind-formio/src/**/*.stories.@(js|jsx|ts|tsx)", + "../packages/tailwind-formio/src/**/*.story.@(js|jsx|ts|tsx)" ], addons: [ From ca1abb387ccdd61162bafca721c350eb6f7a5dcb Mon Sep 17 00:00:00 2001 From: Romain Lenzotti Date: Tue, 7 Jan 2025 08:59:35 +0100 Subject: [PATCH 02/12] fix: fix typing issue --- .../form-action/formAction.component.tsx | 2 +- .../src/components/form/useForm.hook.ts | 20 +++++++++---------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/packages/react-formio/src/components/form-action/formAction.component.tsx b/packages/react-formio/src/components/form-action/formAction.component.tsx index d537160..a790bc6 100644 --- a/packages/react-formio/src/components/form-action/formAction.component.tsx +++ b/packages/react-formio/src/components/form-action/formAction.component.tsx @@ -51,7 +51,7 @@ export function FormAction({ actionInfo, children, onSubmit, options, ...props }
{children} -
+ form={form} submission={submission} onSubmit={onSubmit} options={options} /> {children}
diff --git a/packages/react-formio/src/components/form/useForm.hook.ts b/packages/react-formio/src/components/form/useForm.hook.ts index cddc608..7758787 100644 --- a/packages/react-formio/src/components/form/useForm.hook.ts +++ b/packages/react-formio/src/components/form/useForm.hook.ts @@ -12,21 +12,21 @@ export interface UseFormProps; // TODO: once events is typed correctly in @formio/js options, we can remove this override options?: FormOptions; FormClass?: any; onFormReady?: (instance: Webform) => void; - onPrevPage?: (page: number, submission: SubmissionType) => void; - onNextPage?: (page: number, submission: SubmissionType) => void; + onPrevPage?: (page: number, submission: SubmissionType) => void; + onNextPage?: (page: number, submission: SubmissionType) => void; onCancelSubmit?: () => void; onCancelComponent?: (component: ComponentType) => void; onChange?: (value: ChangedSubmission, flags: any, modified: boolean) => void; onCustomEvent?: (event: FormCustomEvent) => void; onComponentChange?: (changed: { instance: Webform; component: Webform; value: any; flags: any }) => void; - onSubmit?: (submission: SubmissionType, saved?: boolean) => void; - onAsyncSubmit?: (submission: SubmissionType) => void; - onSubmitDone?: (submission: SubmissionType) => void; + onSubmit?: (submission: SubmissionType, saved?: boolean) => void; + onAsyncSubmit?: (submission: SubmissionType) => void; + onSubmitDone?: (submission: SubmissionType) => void; onSubmitError?: (error: EventError) => void; onFormLoad?: (form: JSON) => void; onError?: (error: EventError | false) => void; @@ -37,11 +37,11 @@ export interface UseFormProps void; onInitialized?: () => void; onLanguageChanged?: () => void; - onBeforeSetSubmission?: (submission: SubmissionType) => void; + onBeforeSetSubmission?: (submission: SubmissionType) => void; onSaveDraftBegin?: () => void; - onSaveDraft?: (submission: SubmissionType) => void; - onRestoreDraft?: (submission: SubmissionType | null) => void; - onSubmissionDeleted?: (submission: SubmissionType) => void; + onSaveDraft?: (submission: SubmissionType) => void; + onRestoreDraft?: (submission: SubmissionType | null) => void; + onSubmissionDeleted?: (submission: SubmissionType) => void; onRequestDone?: () => void; otherEvents?: { [event: string]: (...args: any[]) => void; From d204bb93ca6f11d11b3d4b96dff964692eac903b Mon Sep 17 00:00:00 2001 From: Romain Lenzotti Date: Tue, 7 Jan 2025 09:33:53 +0100 Subject: [PATCH 03/12] refactor(react-formio): move Alert in molecules --- .../src/views/form.view.tsx | 5 ++- .../src/views/forms.view.tsx | 5 ++- .../src/components/alert/alert.stories.tsx | 16 -------- packages/react-formio/src/components/index.ts | 1 - .../alert/Alert.spec.tsx} | 22 ++++++----- .../src/molecules/alert/Alert.stories.tsx | 39 +++++++++++++++++++ .../alert/Alert.tsx} | 17 ++++---- 7 files changed, 68 insertions(+), 37 deletions(-) delete mode 100644 packages/react-formio/src/components/alert/alert.stories.tsx rename packages/react-formio/src/{components/alert/alert.component.spec.tsx => molecules/alert/Alert.spec.tsx} (86%) create mode 100644 packages/react-formio/src/molecules/alert/Alert.stories.tsx rename packages/react-formio/src/{components/alert/alert.component.tsx => molecules/alert/Alert.tsx} (86%) diff --git a/packages/react-formio-container/src/views/form.view.tsx b/packages/react-formio-container/src/views/form.view.tsx index cf3acd1..1ffabb0 100644 --- a/packages/react-formio-container/src/views/form.view.tsx +++ b/packages/react-formio-container/src/views/form.view.tsx @@ -1,4 +1,5 @@ -import { Alert, Loader, RemoveModal, Tabs } from "@tsed/react-formio"; +import { Loader, RemoveModal, Tabs } from "@tsed/react-formio"; +import { Alert } from "@tsed/react-formio/molecules/alert/Alert"; import { Route, Switch, useParams } from "react-router"; import { useForm } from "../hooks/useForm.hook"; @@ -13,7 +14,7 @@ function FormComponent({ className, ...props }: ReturnType) { return (
- +
diff --git a/packages/react-formio-container/src/views/forms.view.tsx b/packages/react-formio-container/src/views/forms.view.tsx index e5b281d..bb0832f 100644 --- a/packages/react-formio-container/src/views/forms.view.tsx +++ b/packages/react-formio-container/src/views/forms.view.tsx @@ -1,4 +1,5 @@ -import { Alert, FormsTable } from "@tsed/react-formio"; +import { FormsTable } from "@tsed/react-formio"; +import { Alert } from "@tsed/react-formio/molecules/alert/Alert"; import { useForms, UseFormsProps } from "../hooks/useForms.hook"; @@ -39,7 +40,7 @@ export function FormsComponent({ return (
- + { - return ; -}; - -Sandbox.args = { - error: "error placeholder" -}; diff --git a/packages/react-formio/src/components/index.ts b/packages/react-formio/src/components/index.ts index f0e82ae..cb5b4f8 100644 --- a/packages/react-formio/src/components/index.ts +++ b/packages/react-formio/src/components/index.ts @@ -1,5 +1,4 @@ export * from "./actions-table/actionsTable.component"; -export * from "./alert/alert.component"; export * from "./card/card.component"; export * from "./form/form.component"; export * from "./form/useForm.hook"; diff --git a/packages/react-formio/src/components/alert/alert.component.spec.tsx b/packages/react-formio/src/molecules/alert/Alert.spec.tsx similarity index 86% rename from packages/react-formio/src/components/alert/alert.component.spec.tsx rename to packages/react-formio/src/molecules/alert/Alert.spec.tsx index 5bbe512..2f005c6 100644 --- a/packages/react-formio/src/components/alert/alert.component.spec.tsx +++ b/packages/react-formio/src/molecules/alert/Alert.spec.tsx @@ -1,10 +1,14 @@ import { render, screen } from "@testing-library/react"; -import { Sandbox } from "./alert.stories"; +import { Alert } from "./Alert"; + +const args = { + error: "error placeholder" +}; describe("Alert component", () => { it("should NOT display the alert component when no error is received.", () => { - const { container } = render(); + const { container } = render(); expect(container).toBeEmptyDOMElement(); }); @@ -12,7 +16,7 @@ describe("Alert component", () => { it("should display an error when the error is in string format", () => { const error = "error in string format"; - render(); + render(); const alert = screen.getByRole("alert") as HTMLDivElement; @@ -24,7 +28,7 @@ describe("Alert component", () => { it("should display error(s) when the error is an array", () => { const arrayOfErrors = ["first error", "second error", "third error"]; const joinedErrors = arrayOfErrors.map((error) => error).join(""); - render(); + render(); const alert = screen.getByRole("alert") as HTMLDivElement; @@ -41,7 +45,7 @@ describe("Alert component", () => { { name: "third error", path: "/path", message: "message" } ] }; - render(); + render(); const alert = screen.getByRole("alert") as HTMLDivElement; @@ -52,7 +56,7 @@ describe("Alert component", () => { it("should display an error message when the error is a standard error", () => { const standardError = { message: "first error" }; - render(); + render(); const alert = screen.getByRole("alert") as HTMLDivElement; @@ -63,7 +67,7 @@ describe("Alert component", () => { it("should display error(s) message(s) when the error is a joi validation error", () => { const joiValidationError = { name: "ValidationError", details: [{ message: "message 1" }, { message: "message 2" }] }; - render(); + render(); const alert = screen.getByRole("alert") as HTMLDivElement; @@ -76,7 +80,7 @@ describe("Alert component", () => { it("should display a custom error message that asks to reload the form when a conflict error occurs in a form", () => { const error = { _id: "some id", display: "some value" }; const messageReturned = "Another user has saved this form already. Please reload and re-apply your changes."; - render(); + render(); const alert = screen.getByRole("alert") as HTMLDivElement; @@ -87,7 +91,7 @@ describe("Alert component", () => { it("should display an error message by default when the error format does not match any of the conditions of the formatError() handler", () => { const messageError: string = "An error occurred. See console logs for details."; - render(); + render(); const alert = screen.getByRole("alert") as HTMLDivElement; diff --git a/packages/react-formio/src/molecules/alert/Alert.stories.tsx b/packages/react-formio/src/molecules/alert/Alert.stories.tsx new file mode 100644 index 0000000..03ca06e --- /dev/null +++ b/packages/react-formio/src/molecules/alert/Alert.stories.tsx @@ -0,0 +1,39 @@ +import { Alert } from "./Alert"; + +/** + * Alerts display brief messages for the user without interrupting their use of the app. + * + * ```tsx + * import {Alert} from "@tsed/react-formio/molecules/alert/Alert"; + * + * + * Message + * + * ``` + */ +export default { + title: "Alert", + component: Alert, + argTypes: { + message: { + control: { + type: "text" + } + }, + type: { + control: { + type: "select", + options: ["primary", "secondary", "success", "danger", "warning", "info", "light", "dark"] + } + } + }, + parameters: {}, + tags: ["autodocs"] +}; + +export const Sandbox = { + args: { + type: "danger", + message: "error placeholder" + } +}; diff --git a/packages/react-formio/src/components/alert/alert.component.tsx b/packages/react-formio/src/molecules/alert/Alert.tsx similarity index 86% rename from packages/react-formio/src/components/alert/alert.component.tsx rename to packages/react-formio/src/molecules/alert/Alert.tsx index 9f3d3d0..edfc833 100644 --- a/packages/react-formio/src/components/alert/alert.component.tsx +++ b/packages/react-formio/src/molecules/alert/Alert.tsx @@ -1,4 +1,10 @@ +import { PropsWithChildren } from "react"; + function formatError(error: any): any { + if (!error || (Array.isArray(error) && !error.length)) { + return ""; + } + if (typeof error === "string") { return error; } @@ -42,18 +48,15 @@ function formatError(error: any): any { } export interface AlertProps { - error?: any | any[]; + message?: string | any | string[]; type?: string; } -export function Alert({ error, type = "danger" }: AlertProps) { - if (!error || (Array.isArray(error) && !error.length)) { - return null; - } - +export function Alert({ children, message, type = "danger" }: PropsWithChildren) { return (
- {formatError(error)} + {formatError(message)} + {children}
); } From abfdaebeb5395460a108df077fd8e9698f4b29d5 Mon Sep 17 00:00:00 2001 From: Romain Lenzotti Date: Tue, 7 Jan 2025 09:41:53 +0100 Subject: [PATCH 04/12] refactor(react-formio): move Card in molecules --- .../components/form-access/formAccess.component.tsx | 3 +-- packages/react-formio/src/components/index.ts | 1 - .../card/Card.spec.tsx} | 5 +++-- .../card/Card.stories.tsx} | 11 +++++++++-- .../card.component.tsx => molecules/card/Card.tsx} | 0 5 files changed, 13 insertions(+), 7 deletions(-) rename packages/react-formio/src/{components/card/card.component.spec.tsx => molecules/card/Card.spec.tsx} (74%) rename packages/react-formio/src/{components/card/card.stories.tsx => molecules/card/Card.stories.tsx} (52%) rename packages/react-formio/src/{components/card/card.component.tsx => molecules/card/Card.tsx} (100%) diff --git a/packages/react-formio/src/components/form-access/formAccess.component.tsx b/packages/react-formio/src/components/form-access/formAccess.component.tsx index f4baa3f..58b72bf 100644 --- a/packages/react-formio/src/components/form-access/formAccess.component.tsx +++ b/packages/react-formio/src/components/form-access/formAccess.component.tsx @@ -1,7 +1,7 @@ import { PropsWithChildren, useCallback, useEffect, useMemo, useState } from "react"; import type { FormOptions, FormType, SubmissionType } from "../../interfaces"; -import { Card } from "../card/card.component"; +import { Card } from "../../molecules/card/Card"; import { Form } from "../form/form.component"; import { AccessRolesType, @@ -70,7 +70,6 @@ function NamedFormAccess({ name, form, submissions, options, onChange, onSubmit, return ( <> - name={name} form={form[name]} submission={submissions[name]} onChange={({ data, isValid }) => { diff --git a/packages/react-formio/src/components/index.ts b/packages/react-formio/src/components/index.ts index cb5b4f8..de57560 100644 --- a/packages/react-formio/src/components/index.ts +++ b/packages/react-formio/src/components/index.ts @@ -1,5 +1,4 @@ export * from "./actions-table/actionsTable.component"; -export * from "./card/card.component"; export * from "./form/form.component"; export * from "./form/useForm.hook"; export * from "./form-access/formAccess.component"; diff --git a/packages/react-formio/src/components/card/card.component.spec.tsx b/packages/react-formio/src/molecules/card/Card.spec.tsx similarity index 74% rename from packages/react-formio/src/components/card/card.component.spec.tsx rename to packages/react-formio/src/molecules/card/Card.spec.tsx index 198d42a..e8a7ad0 100644 --- a/packages/react-formio/src/components/card/card.component.spec.tsx +++ b/packages/react-formio/src/molecules/card/Card.spec.tsx @@ -1,10 +1,11 @@ import { render, screen } from "@testing-library/react"; -import { Sandbox } from "./card.stories"; +import { Card } from "./Card"; +import { Sandbox } from "./Card.stories"; describe("Card", () => { it("should render the card component", () => { - render(); + render(); const title = screen.getByRole("heading"); const body = screen.getByRole("article"); diff --git a/packages/react-formio/src/components/card/card.stories.tsx b/packages/react-formio/src/molecules/card/Card.stories.tsx similarity index 52% rename from packages/react-formio/src/components/card/card.stories.tsx rename to packages/react-formio/src/molecules/card/Card.stories.tsx index b397a43..30fdf51 100644 --- a/packages/react-formio/src/components/card/card.stories.tsx +++ b/packages/react-formio/src/molecules/card/Card.stories.tsx @@ -1,7 +1,14 @@ -import { Card } from "./card.component"; +import { Card } from "./Card"; +/** + * Cards contain content and actions about a single subject. + * + * ```ts + * import {Card} from "@tsed/react-formio/molecules/card/Card"; + * ``` + */ export default { - title: "@tsed/react-formio/Card", + title: "Card", component: Card, argTypes: {}, parameters: {} diff --git a/packages/react-formio/src/components/card/card.component.tsx b/packages/react-formio/src/molecules/card/Card.tsx similarity index 100% rename from packages/react-formio/src/components/card/card.component.tsx rename to packages/react-formio/src/molecules/card/Card.tsx From da55ccb27080e62fd1956dcc7d8bdf8427e267eb Mon Sep 17 00:00:00 2001 From: Romain Lenzotti Date: Tue, 7 Jan 2025 10:15:50 +0100 Subject: [PATCH 05/12] refactor(react-formio): move InputTags,InputText,FormControl inside molecules --- .../form-control/formControl.stories.tsx | 63 ------------ .../form-edit/formParameters.component.tsx | 4 +- .../src/components/form/form.stories.tsx | 2 +- packages/react-formio/src/components/index.ts | 3 - .../input-tags/inputTags.stories.tsx | 97 ------------------- .../modal/removeModal.component.tsx | 2 +- .../components/select/select.component.tsx | 2 +- .../filters/defaultColumnFilter.component.tsx | 2 +- .../molecules/__fixtures__/useValue.hook.ts | 14 +++ .../forms/form-control/FormControl.spec.tsx} | 17 ++-- .../form-control/FormControl.stories.tsx | 64 ++++++++++++ .../forms/form-control/FormControl.tsx} | 0 .../forms/input-tags/InputTags.stories.tsx | 95 ++++++++++++++++++ .../forms/input-tags/InputTags.tsx} | 2 +- .../forms/input-text/InputText.spec.tsx} | 4 +- .../forms/input-text/InputText.stories.tsx} | 29 +++--- .../forms/input-text/InputText.tsx} | 4 +- packages/tailwind-formio/styles/choices.css | 2 +- 18 files changed, 205 insertions(+), 201 deletions(-) delete mode 100644 packages/react-formio/src/components/form-control/formControl.stories.tsx delete mode 100644 packages/react-formio/src/components/input-tags/inputTags.stories.tsx create mode 100644 packages/react-formio/src/molecules/__fixtures__/useValue.hook.ts rename packages/react-formio/src/{components/form-control/formControl.component.spec.tsx => molecules/forms/form-control/FormControl.spec.tsx} (81%) create mode 100644 packages/react-formio/src/molecules/forms/form-control/FormControl.stories.tsx rename packages/react-formio/src/{components/form-control/formControl.component.tsx => molecules/forms/form-control/FormControl.tsx} (100%) create mode 100644 packages/react-formio/src/molecules/forms/input-tags/InputTags.stories.tsx rename packages/react-formio/src/{components/input-tags/inputTags.component.tsx => molecules/forms/input-tags/InputTags.tsx} (94%) rename packages/react-formio/src/{components/input-text/inputText.component.spec.tsx => molecules/forms/input-text/InputText.spec.tsx} (95%) rename packages/react-formio/src/{components/input-text/inputText.stories.tsx => molecules/forms/input-text/InputText.stories.tsx} (90%) rename packages/react-formio/src/{components/input-text/inputText.component.tsx => molecules/forms/input-text/InputText.tsx} (91%) diff --git a/packages/react-formio/src/components/form-control/formControl.stories.tsx b/packages/react-formio/src/components/form-control/formControl.stories.tsx deleted file mode 100644 index 31dda9a..0000000 --- a/packages/react-formio/src/components/form-control/formControl.stories.tsx +++ /dev/null @@ -1,63 +0,0 @@ -import { iconClass } from "../../utils/iconClass"; -import { FormControl } from "./formControl.component"; - -export default { - title: "@tsed/react-formio/FormControl", - component: FormControl, - argTypes: { - label: { - control: { - type: "text" - } - }, - name: { - control: { - type: "text" - } - }, - children: { - control: { - type: HTMLElement || HTMLCollection - } - } - }, - parameters: {} -}; - -export const Sandbox = (args: any) => { - return ; -}; - -Sandbox.args = { - label: "Label", - children: -}; - -export const WithPrefix = (args: any) => { - return ; -}; - -WithPrefix.args = { - label: "Label", - children: , - prefix: -}; - -export const WithSuffix = (args: any) => { - return ; -}; - -WithSuffix.args = { - label: "Label", - children: , - suffix: -}; - -export const WithDescription = (args: any) => { - return ; -}; - -WithDescription.args = { - label: "Label", - children: -}; diff --git a/packages/react-formio/src/components/form-edit/formParameters.component.tsx b/packages/react-formio/src/components/form-edit/formParameters.component.tsx index bbc5557..758e140 100644 --- a/packages/react-formio/src/components/form-edit/formParameters.component.tsx +++ b/packages/react-formio/src/components/form-edit/formParameters.component.tsx @@ -1,8 +1,8 @@ import { ReactElement } from "react"; import { FormType } from "../../interfaces/FormType"; -import { InputTags } from "../input-tags/inputTags.component"; -import { InputText } from "../input-text/inputText.component"; +import { InputTags } from "../../molecules/forms/input-tags/InputTags"; +import { InputText } from "../../molecules/forms/input-text/InputText"; import { Select } from "../select/select.component"; export const defaultDisplayChoices = [ diff --git a/packages/react-formio/src/components/form/form.stories.tsx b/packages/react-formio/src/components/form/form.stories.tsx index 1ee3c4f..55b6db7 100644 --- a/packages/react-formio/src/components/form/form.stories.tsx +++ b/packages/react-formio/src/components/form/form.stories.tsx @@ -3,10 +3,10 @@ import { expect, fn, userEvent, waitFor, within } from "@storybook/test"; import { useEffect, useState } from "react"; import { SubmissionType } from "../../interfaces"; +import { InputText } from "../../molecules/forms/input-text/InputText"; import form from "../__fixtures__/form.fixture.json"; import formFirstname from "../__fixtures__/form-firstname.fixture.json"; import { useEditForm } from "../__fixtures__/useEditForm"; -import { InputText } from "../input-text/inputText.component"; import { Form } from "./form.component"; async function delay(number: number) { diff --git a/packages/react-formio/src/components/index.ts b/packages/react-formio/src/components/index.ts index de57560..b4a96b8 100644 --- a/packages/react-formio/src/components/index.ts +++ b/packages/react-formio/src/components/index.ts @@ -4,15 +4,12 @@ export * from "./form/useForm.hook"; export * from "./form-access/formAccess.component"; export * from "./form-action/formAction.component"; export * from "./form-builder/formBuilder.component"; -export * from "./form-control/formControl.component"; export * from "./form-edit/formCtas.component"; export * from "./form-edit/formEdit.component"; export * from "./form-edit/formParameters.component"; export * from "./form-edit/useFormEdit.hook"; export * from "./form-settings/formSettings.component"; export * from "./forms-table/formsTable.component"; -export * from "./input-tags/inputTags.component"; -export * from "./input-text/inputText.component"; export * from "./loader/loader.component"; export * from "./modal/modal.component"; export * from "./modal/removeModal.component"; diff --git a/packages/react-formio/src/components/input-tags/inputTags.stories.tsx b/packages/react-formio/src/components/input-tags/inputTags.stories.tsx deleted file mode 100644 index ef0b7f1..0000000 --- a/packages/react-formio/src/components/input-tags/inputTags.stories.tsx +++ /dev/null @@ -1,97 +0,0 @@ -import { useState } from "react"; - -import { iconClass } from "../../utils/iconClass"; -import { InputTags } from "./inputTags.component"; - -const useValue = (args: any) => { - const [value, setValue] = useState(args.value); - - return { - ...args, - value, - onChange(name: string, value: any) { - setValue(value); - args.onChange(name, value); - } - }; -}; - -export default { - title: "@tsed/react-formio/InputTags", - component: InputTags, - argTypes: { - label: { - control: { - type: "text" - } - }, - name: { - control: { - type: "text" - } - }, - value: { - control: { - type: "object" - } - }, - size: { - control: { - type: "select", - options: ["sm", "normal"] - } - }, - placeholder: { - control: { - type: "text" - } - }, - choices: { - control: { - type: "object" - } - }, - description: { - control: { - type: "text" - } - } - }, - parameters: {} -}; - -export const Sandbox = (args: any) => { - return ; -}; - -Sandbox.args = { - name: "name", - label: "Label", - value: ["test"], - size: "", - placeholder: "Placeholder" -}; - -export const WithPrefix = (args: any) => { - return } {...useValue(args)} />; -}; - -WithPrefix.args = { - label: "Label", - value: [], - name: "name", - size: "", - placeholder: "Placeholder" -}; - -export const WithSuffix = (args: any) => { - return } {...useValue(args)} />; -}; - -WithSuffix.args = { - label: "Label", - value: [], - name: "name", - size: "", - placeholder: "Placeholder" -}; diff --git a/packages/react-formio/src/components/modal/removeModal.component.tsx b/packages/react-formio/src/components/modal/removeModal.component.tsx index 5aa4d05..2af8d63 100644 --- a/packages/react-formio/src/components/modal/removeModal.component.tsx +++ b/packages/react-formio/src/components/modal/removeModal.component.tsx @@ -1,8 +1,8 @@ import classnames from "classnames"; import { PropsWithChildren, useState } from "react"; +import { InputText } from "../../molecules/forms/input-text/InputText"; import { iconClass } from "../../utils/iconClass"; -import { InputText } from "../input-text/inputText.component"; import { Modal, ModalProps } from "./modal.component"; function RemoveModalFooter({ value, valueToCompare, onSubmit, onClose, i18n = (f: string) => f }: ModalProps) { diff --git a/packages/react-formio/src/components/select/select.component.tsx b/packages/react-formio/src/components/select/select.component.tsx index 83d989a..bb8f500 100644 --- a/packages/react-formio/src/components/select/select.component.tsx +++ b/packages/react-formio/src/components/select/select.component.tsx @@ -2,8 +2,8 @@ import Choices from "@formio/choices.js"; import classnames from "classnames"; import { HTMLAttributes, ReactElement, useEffect, useRef } from "react"; +import { FormControl, FormControlProps } from "../../molecules/forms/form-control/FormControl"; import { getEventValue } from "../../utils/getEventValue"; -import { FormControl, FormControlProps } from "../form-control/formControl.component"; export interface SelectProps extends FormControlProps, Omit, "onChange" | "prefix"> { size?: string; diff --git a/packages/react-formio/src/components/table/filters/defaultColumnFilter.component.tsx b/packages/react-formio/src/components/table/filters/defaultColumnFilter.component.tsx index 1467920..61f0ff7 100644 --- a/packages/react-formio/src/components/table/filters/defaultColumnFilter.component.tsx +++ b/packages/react-formio/src/components/table/filters/defaultColumnFilter.component.tsx @@ -1,7 +1,7 @@ import { useState } from "react"; import { FilterProps } from "react-table"; -import { InputText } from "../../input-text/inputText.component"; +import { InputText } from "../../../molecules/forms/input-text/InputText"; export function DefaultColumnFilter = {}>( props: FilterProps & { diff --git a/packages/react-formio/src/molecules/__fixtures__/useValue.hook.ts b/packages/react-formio/src/molecules/__fixtures__/useValue.hook.ts new file mode 100644 index 0000000..96443ad --- /dev/null +++ b/packages/react-formio/src/molecules/__fixtures__/useValue.hook.ts @@ -0,0 +1,14 @@ +import { useState } from "react"; + +export const useValue = (args: any) => { + const [value, setValue] = useState(args.value); + + return { + ...args, + value, + onChange(name: string, value: any) { + setValue(value); + args.onChange(name, value); + } + }; +}; diff --git a/packages/react-formio/src/components/form-control/formControl.component.spec.tsx b/packages/react-formio/src/molecules/forms/form-control/FormControl.spec.tsx similarity index 81% rename from packages/react-formio/src/components/form-control/formControl.component.spec.tsx rename to packages/react-formio/src/molecules/forms/form-control/FormControl.spec.tsx index 02fc0b3..fcb1ece 100644 --- a/packages/react-formio/src/components/form-control/formControl.component.spec.tsx +++ b/packages/react-formio/src/molecules/forms/form-control/FormControl.spec.tsx @@ -1,11 +1,12 @@ import { render, screen } from "@testing-library/react"; -import { iconClass } from "../../utils/iconClass"; -import { Sandbox, WithDescription, WithPrefix, WithSuffix } from "./formControl.stories"; +import { iconClass } from "../../../utils/iconClass"; +import { FormControl } from "./FormControl"; +import { Sandbox } from "./FormControl.stories"; describe("form-control", () => { it("should display form control component", () => { - render(); + render(); const formGroup = screen.getByTestId("form-group-test") as HTMLFormElement; @@ -14,7 +15,7 @@ describe("form-control", () => { it("should NOT display form-control component without a name attribute defined", () => { const name = ""; - render(); + render(); const formGroup = screen.queryByTestId(`form-group-${name}`) as HTMLFormElement; @@ -22,7 +23,7 @@ describe("form-control", () => { }); it("should display form-control component with className 'field-required' when the props 'required' is set to true", () => { - render(); + render(); const formGroup = screen.getByTestId("form-group-test") as HTMLFormElement; const formControlLabel = screen.getByTestId(`form-control-label`) as HTMLLabelElement; @@ -35,7 +36,7 @@ describe("form-control", () => { it("should display prefix", () => { const fontAwsomeCalendarIcon = "fa fa-calendar"; const prefix = () as JSX.Element; - render(); + render(); const formGroup = screen.getByTestId("form-group-testPrefix") as HTMLFormElement; const formControlPrefix = screen.getByTestId("form-control-prefix") as HTMLSpanElement; @@ -49,7 +50,7 @@ describe("form-control", () => { it("should display suffix", () => { const fontAwsomeCalendarIcon = "fa fa-calendar"; const suffix = () as JSX.Element; - render(); + render(); const formGroup = screen.getByTestId("form-group-testSuffix") as HTMLFormElement; const formControlSuffix = screen.getByTestId("form-control-suffix") as HTMLSpanElement; @@ -62,7 +63,7 @@ describe("form-control", () => { it("should display description", () => { const description = "test description"; - render(); + render(); const formGroup = screen.getByTestId("form-group-testDescription") as HTMLFormElement; const formControlDescription = screen.getByTestId("form-control-description") as HTMLDivElement; diff --git a/packages/react-formio/src/molecules/forms/form-control/FormControl.stories.tsx b/packages/react-formio/src/molecules/forms/form-control/FormControl.stories.tsx new file mode 100644 index 0000000..b457bb3 --- /dev/null +++ b/packages/react-formio/src/molecules/forms/form-control/FormControl.stories.tsx @@ -0,0 +1,64 @@ +import { Meta, StoryObj } from "@storybook/react"; + +import { iconClass } from "../../../utils/iconClass"; +import { FormControl } from "./FormControl"; +/** + * ```tsx + * import {FormControl} from "@tsed/react-formio/molecules/forms/form-control/FormControl"; + * ``` + */ +export default { + title: "forms/FormControl", + component: FormControl, + argTypes: { + label: { + control: { + type: "text" + } + }, + name: { + control: { + type: "text" + } + }, + children: { + control: { + type: "object" + } + } + }, + parameters: {}, + tags: ["autodocs"] +} satisfies Meta; + +type Story = StoryObj; + +export const Sandbox: Story = { + args: { + label: "Label", + children: "[TEXTFIELD]" + } +}; + +export const Usage: Story = { + args: { + label: "Label", + children: "[TEXTFIELD]", + prefix: + } +}; + +export const WithSuffix: Story = { + args: { + label: "Label", + children: "[TEXTFIELD]", + suffix: + } +}; + +export const WithDescription: Story = { + args: { + label: "Label", + children: "[TEXTFIELD]" + } +}; diff --git a/packages/react-formio/src/components/form-control/formControl.component.tsx b/packages/react-formio/src/molecules/forms/form-control/FormControl.tsx similarity index 100% rename from packages/react-formio/src/components/form-control/formControl.component.tsx rename to packages/react-formio/src/molecules/forms/form-control/FormControl.tsx diff --git a/packages/react-formio/src/molecules/forms/input-tags/InputTags.stories.tsx b/packages/react-formio/src/molecules/forms/input-tags/InputTags.stories.tsx new file mode 100644 index 0000000..6895599 --- /dev/null +++ b/packages/react-formio/src/molecules/forms/input-tags/InputTags.stories.tsx @@ -0,0 +1,95 @@ +import type { Meta, StoryObj } from "@storybook/react"; + +import { iconClass } from "../../../utils/iconClass"; +import { useValue } from "../../__fixtures__/useValue.hook"; +import { InputTags } from "./InputTags"; + +/** + * ```tsx + * import {InputTags} from "@tsed/react-formio/molecules/forms/input-tags/InputTags"; + * ``` + */ +export default { + title: "forms/InputTags", + component: InputTags, + argTypes: { + label: { + control: { + type: "text" + } + }, + name: { + control: { + type: "text" + } + }, + value: { + control: { + type: "object" + } + }, + size: { + control: { + type: "select", + options: ["sm", "normal"] + } + }, + placeholder: { + control: { + type: "text" + } + }, + choices: { + control: { + type: "object" + } + }, + description: { + control: { + type: "text" + } + } + }, + parameters: {}, + tags: ["autodocs"] +} satisfies Meta; + +type Story = StoryObj; + +export const Usage: Story = { + args: { + name: "name", + label: "Label", + value: ["test"], + size: "", + placeholder: "Placeholder" + } +}; + +export const WithPrefix: Story = { + render(args) { + // eslint-disable-next-line react-hooks/rules-of-hooks + return } {...useValue(args)} />; + }, + args: { + label: "Label", + value: [], + name: "name", + size: "", + placeholder: "Placeholder" + } +}; + +export const WithSuffix: Story = { + render(args) { + // eslint-disable-next-line react-hooks/rules-of-hooks + return } {...useValue(args)} />; + }, + args: { + label: "Label", + value: [], + name: "name", + size: "", + placeholder: "Placeholder" + } +}; diff --git a/packages/react-formio/src/components/input-tags/inputTags.component.tsx b/packages/react-formio/src/molecules/forms/input-tags/InputTags.tsx similarity index 94% rename from packages/react-formio/src/components/input-tags/inputTags.component.tsx rename to packages/react-formio/src/molecules/forms/input-tags/InputTags.tsx index 6d27e31..bcd2f4e 100644 --- a/packages/react-formio/src/components/input-tags/inputTags.component.tsx +++ b/packages/react-formio/src/molecules/forms/input-tags/InputTags.tsx @@ -2,7 +2,7 @@ import Choices from "@formio/choices.js"; import uniq from "lodash/uniq"; import { useEffect, useRef } from "react"; -import { FormControl, FormControlProps } from "../form-control/formControl.component"; +import { FormControl, FormControlProps } from "../form-control/FormControl"; export interface InputTagsProps extends Omit { value?: T; diff --git a/packages/react-formio/src/components/input-text/inputText.component.spec.tsx b/packages/react-formio/src/molecules/forms/input-text/InputText.spec.tsx similarity index 95% rename from packages/react-formio/src/components/input-text/inputText.component.spec.tsx rename to packages/react-formio/src/molecules/forms/input-text/InputText.spec.tsx index 7644493..b9e8c86 100644 --- a/packages/react-formio/src/components/input-text/inputText.component.spec.tsx +++ b/packages/react-formio/src/molecules/forms/input-text/InputText.spec.tsx @@ -1,7 +1,7 @@ import { fireEvent, render, screen } from "@testing-library/react"; -import { InputText } from "./inputText.component"; -import { Usage } from "./inputText.stories"; +import { InputText } from "./InputText"; +import { Usage } from "./InputText.stories"; describe("input-text", () => { it("should display the input-text component", () => { diff --git a/packages/react-formio/src/components/input-text/inputText.stories.tsx b/packages/react-formio/src/molecules/forms/input-text/InputText.stories.tsx similarity index 90% rename from packages/react-formio/src/components/input-text/inputText.stories.tsx rename to packages/react-formio/src/molecules/forms/input-text/InputText.stories.tsx index c0c88bb..31e4a43 100644 --- a/packages/react-formio/src/components/input-text/inputText.stories.tsx +++ b/packages/react-formio/src/molecules/forms/input-text/InputText.stories.tsx @@ -1,27 +1,20 @@ import type { Meta, StoryObj } from "@storybook/react"; import { expect, userEvent, within } from "@storybook/test"; -import { useState } from "react"; -import { iconClass } from "../../utils/iconClass"; -import { InputText } from "./inputText.component"; +import { iconClass } from "../../../utils/iconClass"; +import { useValue } from "../../__fixtures__/useValue.hook"; +import { InputText } from "./InputText"; const delay = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms)); - -const useValue = (args: any) => { - const [value, setValue] = useState(args.value); - - return { - ...args, - value, - onChange(name: string, value: any) { - setValue(value); - args.onChange(name, value); - } - }; -}; - +/** + * Text Fields let users enter and edit text. + * + * ```tsx + * import {InputTags} from "@tsed/react-formio/molecules/forms/input-text/InputText"; + * ``` + */ export default { - title: "@tsed/react-formio/InputText", + title: "forms/InputText", component: InputText, argTypes: { label: { diff --git a/packages/react-formio/src/components/input-text/inputText.component.tsx b/packages/react-formio/src/molecules/forms/input-text/InputText.tsx similarity index 91% rename from packages/react-formio/src/components/input-text/inputText.component.tsx rename to packages/react-formio/src/molecules/forms/input-text/InputText.tsx index 2534ff5..ea7b6fb 100644 --- a/packages/react-formio/src/components/input-text/inputText.component.tsx +++ b/packages/react-formio/src/molecules/forms/input-text/InputText.tsx @@ -2,8 +2,8 @@ import classnames from "classnames"; import { useEffect, useState } from "react"; import { useDebouncedCallback } from "use-debounce"; -import { getEventValue } from "../../utils/getEventValue"; -import { FormControl, FormControlProps } from "../form-control/formControl.component"; +import { getEventValue } from "../../../utils/getEventValue"; +import { FormControl, FormControlProps } from "../form-control/FormControl"; export interface InputTextProps extends FormControlProps { type?: string; diff --git a/packages/tailwind-formio/styles/choices.css b/packages/tailwind-formio/styles/choices.css index 91cab86..5b40ac4 100644 --- a/packages/tailwind-formio/styles/choices.css +++ b/packages/tailwind-formio/styles/choices.css @@ -201,7 +201,7 @@ } .choices__item { - @apply inline-block align-middle rounded py-1 px-2.5 text-xs font-semibold mr-1 mb-1 bg-primary-500 border-1 border-solid border-primary-600 text-white ; + @apply inline-flex align-middle rounded py-1 px-2.5 text-xs font-semibold mr-1 mb-1 bg-primary-500 border-1 border-solid border-primary-600 text-white ; word-break: break-all; box-sizing: border-box; From 471566840d9a2cabe506ce88e0b352f5efa5a891 Mon Sep 17 00:00:00 2001 From: Romain Lenzotti Date: Tue, 7 Jan 2025 10:29:58 +0100 Subject: [PATCH 06/12] refactor(react-formio): move Select inside molecules --- packages/react-formio-container/package.json | 3 +- .../src/views/formPreview.view.tsx | 5 +- .../src/views/submission.view.tsx | 11 +- .../actions-table/actionsTable.component.tsx | 2 +- .../form-edit/formParameters.component.tsx | 2 +- packages/react-formio/src/components/index.ts | 1 - .../pagination/pagination.component.tsx | 2 +- .../src/components/select/select.stories.tsx | 173 ------------------ .../filters/selectColumnFilter.component.tsx | 2 +- .../forms/select/Select.spec.tsx} | 21 ++- .../molecules/forms/select/Select.stories.tsx | 167 +++++++++++++++++ .../forms/select/Select.tsx} | 4 +- packages/redux-utils/package.json | 3 +- packages/tailwind-formio/package.json | 4 +- tools/typescript/package.json | 5 +- tools/vitest/package.json | 4 +- 16 files changed, 211 insertions(+), 198 deletions(-) delete mode 100644 packages/react-formio/src/components/select/select.stories.tsx rename packages/react-formio/src/{components/select/select.component.spec.tsx => molecules/forms/select/Select.spec.tsx} (74%) create mode 100644 packages/react-formio/src/molecules/forms/select/Select.stories.tsx rename packages/react-formio/src/{components/select/select.component.tsx => molecules/forms/select/Select.tsx} (93%) diff --git a/packages/react-formio-container/package.json b/packages/react-formio-container/package.json index 13eef75..3dfbf9f 100644 --- a/packages/react-formio-container/package.json +++ b/packages/react-formio-container/package.json @@ -97,5 +97,6 @@ "tooltip.js": { "optional": false } - } + }, + "dependencies": {} } diff --git a/packages/react-formio-container/src/views/formPreview.view.tsx b/packages/react-formio-container/src/views/formPreview.view.tsx index be4f0dd..4dc5e81 100644 --- a/packages/react-formio-container/src/views/formPreview.view.tsx +++ b/packages/react-formio-container/src/views/formPreview.view.tsx @@ -1,4 +1,5 @@ -import { Card, Form } from "@tsed/react-formio"; +import { Form, FormType } from "@tsed/react-formio"; +import { Card } from "@tsed/react-formio/molecules/card/Card"; import { useForm } from "../hooks"; @@ -6,7 +7,7 @@ export function FormPreviewView({ form, i18n }: ReturnType) { return (
- +
); diff --git a/packages/react-formio-container/src/views/submission.view.tsx b/packages/react-formio-container/src/views/submission.view.tsx index 6fc795c..47e49ae 100644 --- a/packages/react-formio-container/src/views/submission.view.tsx +++ b/packages/react-formio-container/src/views/submission.view.tsx @@ -1,4 +1,4 @@ -import { Form, iconClass, Loader, RemoveModal, useTooltip } from "@tsed/react-formio"; +import { Form, FormType, iconClass, Loader, RemoveModal, useTooltip } from "@tsed/react-formio"; import classnames from "classnames"; import { useParams } from "react-router"; @@ -62,7 +62,14 @@ export function SubmissionComponent(props: ReturnType) {
- + {submissionAction === "delete" && ( { - const [value, setValue] = useState(args.value); - - return { - ...args, - value, - onChange(name: string, value: any) { - setValue(value); - args.onChange(name, value); - } - }; -}; - -export default { - title: "@tsed/react-formio/Select", - component: Select, - argTypes: { - label: { - control: { - type: "text" - } - }, - name: { - control: { - type: "text" - } - }, - value: { - control: { - type: "select", - options: choices - } - }, - size: { - control: { - type: "select", - options: ["sm", "normal"] - } - }, - layout: { - control: { - type: "select", - options: ["html5", "choicesjs"] - } - }, - placeholder: { - control: { - type: "text" - } - }, - choices: { - control: { - type: "object" - } - } - }, - parameters: {} -}; - -export const Sandbox = (args: any) => { - return ; -}; - -Choicesjs.args = { - label: "Label", - value: "", - size: "", - layout: "choicesjs", - placeholder: "Placeholder", - choices -}; - -export const ChoicesjsPrefix = (args: any) => { - return } {...useValue(args)} />; -}; - -WithPrefix.args = { - label: "Label", - value: "", - size: "", - placeholder: "Placeholder", - choices -}; - -export const WithSuffix = (args: any) => { - return ; -}; - -TypeMultiple.args = { - label: "Label", - name: "name", - value: [], - size: "", - multiple: true, - placeholder: "Placeholder", - description: "Select multiple values", - choices -}; - -export const ChoicesjsMultiple = (args: any) => { - return } {...useValue(args)} />; -}; - -Sizing.args = { - label: "Label", - value: "", - size: "sm", - placeholder: "Placeholder", - description: "Use dollars!", - choices -}; diff --git a/packages/react-formio/src/components/table/filters/selectColumnFilter.component.tsx b/packages/react-formio/src/components/table/filters/selectColumnFilter.component.tsx index 9369f56..bd5f94a 100644 --- a/packages/react-formio/src/components/table/filters/selectColumnFilter.component.tsx +++ b/packages/react-formio/src/components/table/filters/selectColumnFilter.component.tsx @@ -1,6 +1,6 @@ import { FilterProps } from "react-table"; -import { Select } from "../../select/select.component"; +import { Select } from "../../../molecules/forms/select/Select"; export function useSelectColumnFilter = {}>(props: FilterProps) { const { column } = props; diff --git a/packages/react-formio/src/components/select/select.component.spec.tsx b/packages/react-formio/src/molecules/forms/select/Select.spec.tsx similarity index 74% rename from packages/react-formio/src/components/select/select.component.spec.tsx rename to packages/react-formio/src/molecules/forms/select/Select.spec.tsx index d6b4e2d..93ddda6 100644 --- a/packages/react-formio/src/components/select/select.component.spec.tsx +++ b/packages/react-formio/src/molecules/forms/select/Select.spec.tsx @@ -1,17 +1,22 @@ import { fireEvent, render, screen } from "@testing-library/react"; -import { Choicesjs, Sandbox } from "./select.stories"; +import { Select } from "./Select"; +import { Choicesjs, Usage } from "./Select.stories"; +const choices = [ + { label: "label1", value: "value1" }, + { label: "label2", value: "value2" } +]; describe("Select", () => { describe("select component Usage version", () => { it("should render the select component", () => { - render(); + render(); const select = screen.getByTestId("select_test-sandbox"); expect(select).toBeInTheDocument(); expect(select).toHaveClass("form-control-small"); @@ -25,7 +30,7 @@ describe("Select", () => { const placeHolderTest = "Placeholder test"; - render(); + render(); const option = screen.getByRole("option", { name: placeHolderTest }) as HTMLOptionElement; expect(option.selected).toBeTruthy(); @@ -53,7 +58,7 @@ describe("Select", () => { const placeHolderTest = "Placeholder test"; const onChange = vi.fn(); - render(); + render(); expect(screen.getByRole("option", { name: "test1" })).toBeInTheDocument(); }); diff --git a/packages/react-formio/src/molecules/forms/select/Select.stories.tsx b/packages/react-formio/src/molecules/forms/select/Select.stories.tsx new file mode 100644 index 0000000..9ee076b --- /dev/null +++ b/packages/react-formio/src/molecules/forms/select/Select.stories.tsx @@ -0,0 +1,167 @@ +import { Meta, StoryObj } from "@storybook/react"; + +import { iconClass } from "../../../utils/iconClass"; +import { useValue } from "../../__fixtures__/useValue.hook"; +import { Select } from "./Select"; + +const choices = [ + { label: "label1", value: "value1" }, + { label: "label2", value: "value2" } +]; + +/** + * Select components are used for collecting user provided information from a list of options. + * + * ```tsx + * import {Select} from "@tsed/react-formio/molecules/forms/select/Select"; + * ``` + */ +export default { + title: "forms/Select", + component: Select, + argTypes: { + label: { + control: { + type: "text" + } + }, + name: { + control: { + type: "text" + } + }, + value: { + control: { + type: "select", + options: choices + } + }, + size: { + control: { + type: "select", + options: ["sm", "normal"] + } + }, + layout: { + control: { + type: "select", + options: ["html5", "choicesjs"] + } + }, + placeholder: { + control: { + type: "text" + } + }, + choices: { + control: { + type: "object" + } + } + }, + parameters: {}, + render(args: any) { + // eslint-disable-next-line react-hooks/rules-of-hooks + return