Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

expose a FormFragment component for use in complex components #129

Open
wants to merge 10 commits into
base: main
Choose a base branch
from
7 changes: 6 additions & 1 deletion src/FieldContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,11 @@ export function FieldContextProvider({
);
}

export function useMaybeFieldName() {
Copy link
Collaborator Author

@scamden scamden Jul 18, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

let us automatically derive the name from context if there are any Fields already provided above us

const context = useContext(FieldContext);
return context?.name;
}

function useContextProt(name: string) {
const context = useContext(FieldContext);
if (!context)
Expand Down Expand Up @@ -471,4 +476,4 @@ export function useNumberFieldInfo() {
},
"useNumberFieldInfo"
);
}
}
71 changes: 70 additions & 1 deletion src/__tests__/createSchemaForm.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {
} from "./utils/testForm";
import {
createTsForm,
createTsFormAndFragment,
noMatchingSchemaErrorMessage,
useFormResultValueChangedErrorMesssage,
} from "../createSchemaForm";
Expand Down Expand Up @@ -1479,7 +1480,7 @@ describe("createSchemaForm", () => {
return createUniqueFieldSchema(z.date().min(min).max(max), uniqueId);
},
get component() {
const { min,max, label, uniqueId } = this;
const { min, max, label, uniqueId } = this;

const ArrayDateFieldComponent = () => {
const fieldInfo = useDateFieldInfo();
Expand Down Expand Up @@ -1847,4 +1848,72 @@ describe("createSchemaForm", () => {
const inputs = screen.getAllByTestId(/dynamic-array-input/);
expect(inputs.length).toBe(3);
});
it("should provide a nested renderer for use in complex components", async () => {
const NumberSchema = createUniqueFieldSchema(z.number(), "number");
const mockOnSubmit = jest.fn();

function TextField({}: { b?: "1" }) {
const { error } = useTsController<string>();
return (
<>
<div>text</div>
<div data-testid="error">{error?.errorMessage}</div>
</>
);
}

function NumberField({}: { a?: 1 }) {
return <div>number</div>;
}

function ComplexField({}: { complexProp1: boolean }) {
return (
<div>
<FormFragment schema={objectSchema2} props={{ num: { a: 1 } }} />
</div>
);
}

const objectSchema2 = z.object({
num: NumberSchema,
str: z.string(),
});

const mapping = [
[z.string(), TextField],
[NumberSchema, NumberField],
[objectSchema2, ComplexField],
] as const;

const [Form, FormFragment] = createTsFormAndFragment(mapping);

const schema = z.object({
nestedField2: objectSchema2,
});
const defaultValues = {
nestedField2: { num: 4, str: "this" },
};
// TODO: test validation
render(
<Form
schema={schema}
onSubmit={mockOnSubmit}
defaultValues={defaultValues}
props={{
nestedField2: { complexProp1: true },
}}
renderAfter={() => <button type="submit">submit</button>}
/>
);
screen.debug();
const button = screen.getByText("submit");
await userEvent.click(button);

const textNodes = screen.queryByText("text");
expect(textNodes).toBeInTheDocument();
const numberNodes = screen.queryByText("number");
expect(numberNodes).toBeInTheDocument();
expect(screen.queryByTestId("error")).toHaveTextContent("");
expect(mockOnSubmit).toHaveBeenCalledWith(defaultValues);
});
});
Loading