diff --git a/packages/conform-dom/dom.ts b/packages/conform-dom/dom.ts index 725ec324..e84aeb6e 100644 --- a/packages/conform-dom/dom.ts +++ b/packages/conform-dom/dom.ts @@ -143,9 +143,9 @@ export function requestSubmit( export function syncFieldValue( element: FieldElement, value: unknown, - updateDefaultValue: boolean, + defaultValue: unknown, ): void { - const fieldValue = + const getInputValue = (value: unknown): string[] => typeof value === 'string' ? [value] : Array.isArray(value) && value.every((item) => typeof item === 'string') @@ -154,27 +154,22 @@ export function syncFieldValue( if (element instanceof HTMLSelectElement) { for (const option of element.options) { - option.selected = fieldValue.includes(option.value); - - if (updateDefaultValue) { - option.defaultSelected = option.selected; - } + option.selected = getInputValue(value).includes(option.value); + option.defaultSelected = getInputValue(defaultValue).includes( + option.value, + ); } } else if ( element instanceof HTMLInputElement && (element.type === 'checkbox' || element.type === 'radio') ) { - element.checked = fieldValue.includes(element.value); - - if (updateDefaultValue) { - element.defaultChecked = element.checked; - } + element.checked = getInputValue(value).includes(element.value); + element.defaultChecked = getInputValue(defaultValue).includes( + element.value, + ); } else { - element.value = fieldValue[0] ?? ''; - - if (updateDefaultValue) { - element.defaultValue = element.value; - } + element.value = getInputValue(value)[0] ?? ''; + element.defaultValue = getInputValue(defaultValue)[0] ?? ''; } } diff --git a/packages/conform-dom/form.ts b/packages/conform-dom/form.ts index eedbe552..64ecaade 100644 --- a/packages/conform-dom/form.ts +++ b/packages/conform-dom/form.ts @@ -118,7 +118,6 @@ export type Constraint = { export type FormMeta = { formId: string; - isResetting: boolean; isValueUpdated: boolean; submissionStatus?: 'error' | 'success'; defaultValue: Record; @@ -272,7 +271,6 @@ function createFormMeta( const initialValue = lastResult?.initialValue ?? defaultValue; const result: FormMeta = { formId: options.formId, - isResetting: !!isResetting, isValueUpdated: false, submissionStatus: lastResult?.status, defaultValue, @@ -671,7 +669,6 @@ export function createFormContext< return { submissionStatus: next.submissionStatus, - isResetting: next.isResetting, defaultValue, initialValue, value, @@ -1091,7 +1088,7 @@ export function syncFormState( syncFieldValue( element, stateSnapshot.initialValue[element.name], - isInitializing || stateSnapshot.isResetting, + stateSnapshot.defaultValue[element.name], ); } } diff --git a/playground/app/routes/sync-form-state.tsx b/playground/app/routes/sync-form-state.tsx index 5e6a2ff5..a7deed56 100644 --- a/playground/app/routes/sync-form-state.tsx +++ b/playground/app/routes/sync-form-state.tsx @@ -3,21 +3,21 @@ import { parseWithZod } from '@conform-to/zod'; import type { ActionFunctionArgs } from '@remix-run/node'; import { json } from '@remix-run/node'; import { Form, useActionData } from '@remix-run/react'; +import { useState } from 'react'; import { z } from 'zod'; import { Playground, Field } from '~/components'; const schema = z.object({ - text: z.string({ required_error: 'Text is required' }), - textarea: z.string({ required_error: 'Textarea is required' }), - select: z.string({ required_error: 'Select is required' }), - multiSelect: z.array(z.string(), { - required_error: 'Multi select is required', + input: z.object({ + text: z.string(), + number: z.number(), }), - checkbox: z.boolean({ required_error: 'Checkbox is required' }), - checkboxGroup: z.array(z.string(), { - required_error: 'Checkbox group is required', - }), - radioGroup: z.string({ required_error: 'Radio is required' }), + textarea: z.string(), + select: z.string(), + multiSelect: z.array(z.string()), + checkbox: z.boolean(), + checkboxGroup: z.array(z.string()), + radioGroup: z.string(), }); export async function action({ request }: ActionFunctionArgs) { @@ -29,7 +29,10 @@ export async function action({ request }: ActionFunctionArgs) { resetForm: true, }), defaultValue: { - text: 'Default text', + input: { + text: 'Default text', + number: 4, + }, textarea: 'You need to write something here', select: 'red', multiSelect: ['apple', 'banana', 'cherry'], @@ -47,7 +50,10 @@ export default function Example() { shouldValidate: 'onBlur', onValidate: ({ formData }) => parseWithZod(formData, { schema }), defaultValue: actionData?.defaultValue ?? { - text: 'Hello World', + input: { + text: 'Hello World', + number: 2, + }, textarea: 'Once upon a time', select: 'green', multiSelect: ['banana', 'cherry'], @@ -56,11 +62,13 @@ export default function Example() { radioGroup: 'Deutsch', }, constraint: { - text: { + 'input.text': { required: true, minLength: 5, maxLength: 30, pattern: '[a-zA-Z]+', + }, + 'input.number': { min: 5, max: 10, step: 1, @@ -74,7 +82,6 @@ export default function Example() { required: true, }, multiSelect: { - required: true, multiple: true, }, checkbox: { @@ -91,6 +98,8 @@ export default function Example() { return element.name !== 'token'; }, }); + const inputFields = fields.input.getFieldset(); + const [showNumberField, setShowNumberField] = useState(true); return (
@@ -98,9 +107,14 @@ export default function Example() { - - + + + {showNumberField ? ( + + + + ) : null}