Skip to content

Commit

Permalink
feat: api changes
Browse files Browse the repository at this point in the history
  • Loading branch information
edmundhung committed Nov 21, 2023
1 parent ffec76b commit 90080f5
Show file tree
Hide file tree
Showing 23 changed files with 353 additions and 340 deletions.
18 changes: 10 additions & 8 deletions examples/remix/app/routes/login-fetcher.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ export async function action({ request }: ActionArgs) {

export default function Login() {
const fetcher = useFetcher<typeof action>();
const { form, fields } = useForm({
const form = useForm({
// Sync the result of last submission
lastResult: fetcher.data,

Expand All @@ -41,23 +41,25 @@ export default function Login() {
<div>
<label>Email</label>
<input
className={!fields.email.valid ? 'error' : ''}
{...conform.input(fields.email)}
className={!form.fields.email.valid ? 'error' : ''}
{...conform.input(form.fields.email)}
/>
<div>{fields.email.errors}</div>
<div>{form.fields.email.errors}</div>
</div>
<div>
<label>Password</label>
<input
className={!fields.password.valid ? 'error' : ''}
{...conform.input(fields.password, { type: 'password' })}
className={!form.fields.password.valid ? 'error' : ''}
{...conform.input(form.fields.password, { type: 'password' })}
/>
<div>{fields.password.errors}</div>
<div>{form.fields.password.errors}</div>
</div>
<label>
<div>
<span>Remember me</span>
<input {...conform.input(fields.remember, { type: 'checkbox' })} />
<input
{...conform.input(form.fields.remember, { type: 'checkbox' })}
/>
</div>
</label>
<hr />
Expand Down
18 changes: 10 additions & 8 deletions examples/remix/app/routes/login.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ export async function action({ request }: ActionArgs) {
export default function Login() {
// Last submission returned by the server
const lastResult = useActionData<typeof action>();
const { form, fields } = useForm({
const form = useForm({
// Sync the result of last submission
lastResult,

Expand All @@ -43,23 +43,25 @@ export default function Login() {
<div>
<label>Email</label>
<input
className={!fields.email.valid ? 'error' : ''}
{...conform.input(fields.email)}
className={!form.fields.email.valid ? 'error' : ''}
{...conform.input(form.fields.email)}
/>
<div>{fields.email.errors}</div>
<div>{form.fields.email.errors}</div>
</div>
<div>
<label>Password</label>
<input
className={!fields.password.valid ? 'error' : ''}
{...conform.input(fields.password, { type: 'password' })}
className={!form.fields.password.valid ? 'error' : ''}
{...conform.input(form.fields.password, { type: 'password' })}
/>
<div>{fields.password.errors}</div>
<div>{form.fields.password.errors}</div>
</div>
<label>
<div>
<span>Remember me</span>
<input {...conform.input(fields.remember, { type: 'checkbox' })} />
<input
{...conform.input(form.fields.remember, { type: 'checkbox' })}
/>
</div>
</label>
<hr />
Expand Down
20 changes: 10 additions & 10 deletions examples/remix/app/routes/signup.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ export async function action({ request }: ActionArgs) {

export default function Signup() {
const lastResult = useActionData<typeof action>();
const { form, fields } = useForm({
const form = useForm({
lastResult,
onValidate({ formData }) {
return parse(formData, {
Expand All @@ -89,26 +89,26 @@ export default function Signup() {
<label>
<div>Username</div>
<input
className={!fields.username.valid ? 'error' : ''}
{...conform.input(fields.username)}
className={!form.fields.username.valid ? 'error' : ''}
{...conform.input(form.fields.username)}
/>
<div>{fields.username.errors}</div>
<div>{form.fields.username.errors}</div>
</label>
<label>
<div>Password</div>
<input
className={!fields.password.valid ? 'error' : ''}
{...conform.input(fields.password, { type: 'password' })}
className={!form.fields.password.valid ? 'error' : ''}
{...conform.input(form.fields.password, { type: 'password' })}
/>
<div>{fields.password.errors}</div>
<div>{form.fields.password.errors}</div>
</label>
<label>
<div>Confirm Password</div>
<input
className={!fields.confirmPassword.valid ? 'error' : ''}
{...conform.input(fields.confirmPassword, { type: 'password' })}
className={!form.fields.confirmPassword.valid ? 'error' : ''}
{...conform.input(form.fields.confirmPassword, { type: 'password' })}
/>
<div>{fields.confirmPassword.errors}</div>
<div>{form.fields.confirmPassword.errors}</div>
</label>
<hr />
<button>Signup</button>
Expand Down
42 changes: 17 additions & 25 deletions examples/remix/app/routes/todos.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,9 @@ import type { Field } from '@conform-to/react';
import {
FormProvider,
useForm,
useFieldset,
useFieldList,
conform,
intent,
useField,
} from '@conform-to/react';
import { parse } from '@conform-to/zod';
import type { ActionArgs } from '@remix-run/node';
Expand Down Expand Up @@ -38,59 +37,52 @@ export async function action({ request }: ActionArgs) {

export default function TodoForm() {
const lastResult = useActionData<typeof action>();
const { form, fields, context } = useForm({
const form = useForm({
lastResult,
onValidate({ formData }) {
return parse(formData, { schema: todosSchema });
},
shouldValidate: 'onBlur',
});
const taskList = useFieldList({
formId: form.id,
name: fields.tasks.name,
context,
});
const tasks = form.fields.tasks;

return (
<FormProvider context={context}>
<FormProvider context={form.context}>
<Form method="post" {...conform.form(form)}>
<div>
<label>Title</label>
<input
className={!fields.title.valid ? 'error' : ''}
{...conform.input(fields.title)}
className={!form.fields.title.valid ? 'error' : ''}
{...conform.input(form.fields.title)}
/>
<div>{fields.title.errors}</div>
<div>{form.fields.title.errors}</div>
</div>
<hr />
<div className="form-error">{fields.tasks.errors}</div>
{taskList.map((task, index) => (
<div className="form-error">{tasks.errors}</div>
{tasks.items.map((task, index) => (
<div key={task.key}>
<TaskFieldset
title={`Task #${index + 1}`}
name={task.name}
formId={form.id}
/>
<button {...intent.list.remove(fields.tasks, { index })}>
Delete
</button>
<button
{...intent.list.reorder(fields.tasks, { from: index, to: 0 })}
>
<button {...intent.list.remove(tasks, { index })}>Delete</button>
<button {...intent.list.reorder(tasks, { from: index, to: 0 })}>
Move to top
</button>
<button
{...intent.list.replace(fields.tasks, {
index,
defaultValue: { content: '' },
{...intent.replace({
formId: form.id,
name: task.name,
value: { content: '' },
})}
>
Clear
</button>
</div>
))}
<button
{...intent.list.insert(fields.tasks, {
{...intent.list.insert(tasks, {
defaultValue: { content: '' },
})}
>
Expand All @@ -108,7 +100,7 @@ interface TaskFieldsetProps extends Field<z.input<typeof taskSchema>> {
}

function TaskFieldset({ title, name, formId }: TaskFieldsetProps) {
const fields = useFieldset({
const { fields } = useField({
formId,
name,
});
Expand Down
37 changes: 29 additions & 8 deletions packages/conform-dom/form.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ export type FormValue<Schema> = Schema extends
? Array<FormValue<InnerType>>
: Schema extends Record<string, any>
? { [Key in UnionKeyof<Schema>]?: FormValue<UnionKeyType<Schema, Key>> }
: any;
: unknown;

export type FieldName<Schema> = string & { __type?: Schema };

Expand Down Expand Up @@ -259,18 +259,39 @@ export function createForm<Schema extends Record<string, any> = any>(
initialized?: boolean,
): void {
switch (intent.type) {
case 'reset': {
const name = intent.payload.name ?? '';
const defaultValue = getValue(context.defaultValue, name);
case 'replace': {
if (typeof intent.payload.value !== 'undefined') {
const name = intent.payload.name ?? '';

context.initialValue = clone(context.initialValue);
context.initialValue = clone(context.initialValue);
context.key = clone(context.key);

setValue(context.initialValue, name, () => defaultValue);
setValue(context.value, name, () => defaultValue);
setValue(context.initialValue, name, () => intent.payload.value);
setValue(context.value, name, () => intent.payload.value);

if (initialized) {
if (
isPlainObject(intent.payload.value) ||
Array.isArray(intent.payload.value)
) {
setState(context.key, name, () => undefined);
}

context.key[name] = generateId();
}
break;
}
case 'reset': {
if (intent.payload.value ?? true) {
const name = intent.payload.name ?? '';
const defaultValue = getValue(context.defaultValue, name);

context.initialValue = clone(context.initialValue);
context.value = clone(context.value);
context.key = clone(context.key);

setValue(context.initialValue, name, () => defaultValue);
setValue(context.value, name, () => defaultValue);

if (isPlainObject(defaultValue) || Array.isArray(defaultValue)) {
setState(context.key, name, () => undefined);
}
Expand Down
Loading

0 comments on commit 90080f5

Please sign in to comment.