@rsc-kit/core 0.30.21 → 0.30.23
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.
- package/dist/js/Form.js +19 -2
- package/dist/js/Form.js.map +1 -1
- package/dist/js/RouteErrorBoundary.d.ts +5 -1
- package/dist/js/RouteErrorBoundary.js +17 -5
- package/dist/js/RouteErrorBoundary.js.map +1 -1
- package/dist/js/createViteRscApp.js +2 -2
- package/dist/js/createViteRscApp.js.map +1 -1
- package/dist/js/navigate.d.ts +9 -2
- package/dist/js/navigate.js +33 -18
- package/dist/js/navigate.js.map +1 -1
- package/dist/js/segmentStore.d.ts +1 -1
- package/dist/js/segmentStore.js +14 -9
- package/dist/js/segmentStore.js.map +1 -1
- package/dist/request.d.ts +1 -0
- package/dist/request.js.map +1 -1
- package/dist/routes.d.ts +13 -1
- package/dist/routes.js.map +1 -1
- package/dist/served.d.ts +35 -0
- package/dist/served.js +80 -0
- package/dist/served.js.map +1 -0
- package/dist/vite.d.ts +33 -5
- package/dist/vite.js +51 -19
- package/dist/vite.js.map +1 -1
- package/package.json +1 -1
package/dist/js/Form.js
CHANGED
|
@@ -168,6 +168,10 @@ function boundSubmit(action) {
|
|
|
168
168
|
* FormData in document order, a file by its name and size: enough to say
|
|
169
169
|
* whether anything changed, which is all `dirty` asks.
|
|
170
170
|
*/
|
|
171
|
+
/** Whether a GET form's action is the page on screen, whatever query it carries. */
|
|
172
|
+
function isThisPage(action) {
|
|
173
|
+
return new URL(action, window.location.origin).pathname === window.location.pathname;
|
|
174
|
+
}
|
|
171
175
|
function serializeForm(form) {
|
|
172
176
|
const parts = [];
|
|
173
177
|
for (const [name, value] of new FormData(form)) {
|
|
@@ -361,13 +365,14 @@ fields: _fields, store: providedStore, prefetch = "hover", cacheFor, replace = f
|
|
|
361
365
|
queueMicrotask(measureDirty);
|
|
362
366
|
}, [store, measureDirty]);
|
|
363
367
|
useEffect(() => {
|
|
364
|
-
if (isGetForm && prefetch === "mount") {
|
|
368
|
+
if (isGetForm && prefetch === "mount" && !isThisPage(action)) {
|
|
365
369
|
const fn = window.__rsc_prefetch;
|
|
366
370
|
fn?.(action, cacheFor);
|
|
367
371
|
}
|
|
368
372
|
}, [isGetForm, prefetch, action, cacheFor]);
|
|
369
373
|
const doPrefetch = useCallback(() => {
|
|
370
|
-
|
|
374
|
+
// The page on screen is not a shell to show: it is already shown.
|
|
375
|
+
if (!isGetForm || isThisPage(action))
|
|
371
376
|
return;
|
|
372
377
|
const fn = window.__rsc_prefetch;
|
|
373
378
|
fn?.(action, cacheFor);
|
|
@@ -391,6 +396,18 @@ fields: _fields, store: providedStore, prefetch = "hover", cacheFor, replace = f
|
|
|
391
396
|
const shell = action;
|
|
392
397
|
const nav = window.__rsc_navigate;
|
|
393
398
|
const prefetched = window.__rsc_is_prefetched;
|
|
399
|
+
// A search on the page it is on. There is no other page whose shell
|
|
400
|
+
// could stand in while the query runs - the shell would be this page
|
|
401
|
+
// with nothing in it - so the page stays, results and all, until the
|
|
402
|
+
// new ones replace them, and the form says it is working. The
|
|
403
|
+
// transition is what keeps pending true until they have: the
|
|
404
|
+
// navigation's own update joins it, and commits with it.
|
|
405
|
+
if (isThisPage(shell)) {
|
|
406
|
+
startTransition(async () => {
|
|
407
|
+
await nav?.(path, { replace, preserveScroll, inPlace: true })?.catch(() => { });
|
|
408
|
+
});
|
|
409
|
+
return;
|
|
410
|
+
}
|
|
394
411
|
// The route without its query is that route's shell: the layout, the
|
|
395
412
|
// chrome, and whatever it renders with nothing to show yet. Prefetching
|
|
396
413
|
// on hover put it in the cache, so going there first costs no request
|
package/dist/js/Form.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Form.js","sourceRoot":"","sources":["../../src/js/Form.tsx"],"names":[],"mappings":"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","sourcesContent":["\"use client\";\n\nimport type { Route } from \"../routes.js\";\nimport {\n type FormHTMLAttributes,\n type FormEvent,\n type ReactNode,\n type Ref,\n createContext,\n useCallback,\n useContext,\n useEffect,\n useLayoutEffect,\n useMemo,\n useRef,\n useActionState,\n useState,\n useSyncExternalStore,\n useTransition,\n} from \"react\";\nimport { submitForm } from \"../formSubmit\";\nimport { ActionRefusedError, ServerValidationError, ServerDumpError, ServerRedirectError, redirectedTo } from \"./errors\";\nimport { buildFormData, decodeFormData } from \"./formEncoding\";\nimport { createFormStore } from \"./formStore\";\nimport type { FormStore } from \"./formStore\";\nimport { validateWith } from \"./standardSchema\";\nimport type { StandardSchemaV1 } from \"./standardSchema\";\n\n/**\n * How long a blur that leaves the form waits before checking the field. A\n * dialog's exit animation is shorter than this; a form still on screen after\n * it is one somebody is looking at.\n */\nconst LEAVE_FORM_SETTLE_MS = 300;\n\ntype PrefetchStrategy = \"hover\" | \"mount\" | \"none\";\n\n/**\n * What `field(name)` hands a control, spread straight onto it.\n *\n * The same four things react-hook-form's `<Controller>` gives, because it is\n * the same job: a component with no native control behind it needs a value and\n * a way to report a new one.\n */\ninterface FieldBinding<V> {\n name: string;\n value: V;\n /**\n * Either shape: a DOM event, or the value itself.\n *\n * A native input passes the event; a Radix select or a rich editor passes\n * what was chosen. A binder understanding only one of them would work on\n * half the controls anyone actually uses.\n */\n onChange: (next: V | { target: { value: V } }) => void;\n onBlur: () => void;\n}\n\n/**\n * A field's name: one the form declared, suggested by the editor - or any\n * path, because a nested or indexed field (`address.city`, `items[0].name`)\n * is a real name no defaultValues object can declare. The typo that matters\n * is caught on `field()`, which is closed to the declared names.\n */\ntype FieldPath<T> = (keyof T & string) | (string & {});\n\n/** Dots deep, so a self-referential or very wide input type cannot run the compiler out. */\ntype Depth = [never, 0, 1, 2, 3];\n\n/**\n * Every name an error can be filed under in a value: its keys, a nested object's\n * `address.city`, and a list's `items.0.sku` - the shape a Standard Schema\n * issue and a backend's validation both produce.\n */\ntype Paths<T, D extends number = 3> = [D] extends [never]\n ? never\n : T extends readonly (infer U)[]\n ? `${number}` | `${number}.${Paths<U, Depth[D]>}`\n : T extends object\n ? { [K in keyof T & string]: K | (T[K] extends object ? `${K}.${Paths<T[K], Depth[D]>}` : never) }[keyof T & string]\n : never;\n\n/**\n * What an action takes, read off the action: a generated stub's typed overload,\n * or the input of one built with `createActionClient().input(schema)`. Unknown\n * when it does not say - a url, or a function of a FormData - and then nothing\n * is claimed about its fields.\n */\ntype InputOfAction<A> = [A] extends [never]\n ? unknown // `action={signup as never}`: a cast says nothing about the input\n : 0 extends 1 & A\n ? unknown // any\n : A extends { (input: infer I): Promise<unknown>; (form: FormData): Promise<unknown> }\n ? Described<I>\n : A extends (input: infer I) => Promise<unknown>\n ? Described<I>\n : unknown;\n\n/** An action's parameter, without the FormData a form posts it as; unknown if that was all it said. */\ntype Described<I> = [Exclude<I, FormData | undefined>] extends [never] ? unknown : Exclude<I, FormData | undefined>;\n\ndeclare const NAMES: unique symbol;\n\n/**\n * A form's FormData, naming its fields.\n *\n * For an action the app writes that takes a form and passes it on - to a stub\n * whose parameters are plain strings, say - which says nothing of its fields to\n * anything reading its type. Declared on the parameter, where the names live\n * with the code that reads them:\n *\n * export async function createApp(form: FormFields<'name' | 'region'>) {\n * return await appsCreate(String(form.get('name')), String(form.get('region')))\n * }\n *\n * and `<Form action={createApp}>` closes `error()` to those names. Nothing runs:\n * it is a FormData, and every FormData is one. The names are a claim the types\n * keep, not a check the browser makes.\n */\nexport interface FormFields<Name extends string> extends FormData {\n readonly [NAMES]?: Name;\n}\n\n/** The names a form-taking action declared with FormFields, or never when it did not. */\ntype DeclaredNames<A> = A extends (form: FormFields<infer N>, ...rest: never[]) => Promise<unknown>\n ? string extends N\n ? never\n : N\n : never;\n\n/**\n * The names an action's validation can be read under, for `error()` and\n * `clearErrors()`: the input's own paths, the names a wrapper declared, and the\n * form's declared values.\n *\n * Closed when the action says what it takes, so `error('nmae')` fails the\n * typecheck rather than showing nothing, ever. Open, as it always was, when it\n * does not - a field is only a typo if something could have said so.\n */\ntype FieldNameOf<T, A, F extends string = never> = [F] extends [never]\n ? unknown extends InputOfAction<A>\n ? [DeclaredNames<A>] extends [never]\n ? FieldPath<T>\n : DeclaredKeys<T> | DeclaredNames<A>\n : DeclaredKeys<T> | Paths<InputOfAction<A>> | DeclaredNames<A>\n : // Named on the form itself: closed to these, beside everything else that names a field.\n F | DeclaredKeys<T> | DeclaredNames<A> | (unknown extends InputOfAction<A> ? never : Paths<InputOfAction<A>>);\n\n/** The form's declared values count - but T is the open record when it declared none, and all of `string` is not a name. */\ntype DeclaredKeys<T> = string extends keyof T ? never : keyof T & string;\n\n/** The field names an action's validation can name, for a component below a form to type. */\nexport type FieldNamesOf<A> = unknown extends InputOfAction<A>\n ? [DeclaredNames<A>] extends [never]\n ? string\n : DeclaredNames<A>\n : Paths<InputOfAction<A>> | DeclaredNames<A>;\n\ninterface FormRenderProps<\n T extends Record<string, unknown> = Record<string, unknown>,\n Refusal = unknown,\n Name extends string = FieldPath<T>,\n> {\n pending: boolean;\n /** What is being submitted, while it is. */\n data: T;\n /**\n * A field's error, or undefined: the one way to read one.\n *\n * {error('title') && <p>{error('title')}</p>}\n * <Field data-invalid={!!error('title')}>\n *\n * Nested paths join with dots - `error('address.city')`, the key a Standard\n * Schema issue for that field produces. A field is checked when it is left\n * and when the form is submitted, so an error never appears on a field\n * nobody has reached yet.\n */\n error: (field: Name) => string | undefined;\n /**\n * The refusal that is not about a field: the action's `serverError` - a\n * 402, a 409, \"that slot was just taken\" - or a validation message for the\n * form as a whole. Undefined otherwise. Cleared by the next submit, by a\n * success, and by `clearErrors()` and `reset()`, like a field's.\n *\n * {formError && <p role=\"alert\">{formError}</p>}\n *\n * Only what the action returned: a failure thrown on the way, the network\n * or a crash, goes to `onError` as before, where a production message is\n * React's stand-in and not something to show.\n */\n formError: string | undefined;\n /**\n * What the action's refusal carried beside `formError` - the records\n * blocking a delete, say - when the action refused with `refuse()` and\n * declared its shape with `.refusal(schema)`. Typed from the form's\n * `action` in its render prop; in a component below, `useForm<T, R>()`.\n * Goes when `formError` does.\n */\n formRefusal: Refusal | undefined;\n clearErrors: (...fields: Name[]) => void;\n reset: () => void;\n /**\n * Whether anything differs from what the form started with.\n *\n * For the Save button that stays quiet until there is something to save,\n * and the Discard that appears beside it. Read from the form itself - a\n * snapshot of its FormData on mount, compared on every input - so an\n * uncontrolled field counts, which nothing outside the form can do. A\n * successful submit makes the current values the new baseline; `reset()`\n * goes back to the first one.\n */\n dirty: boolean;\n /** Whether the last submit was accepted. */\n succeeded: boolean;\n /**\n * The same thing, for two seconds.\n *\n * The \"Saved ✓\" that appears and fades. Worth having as state rather than a\n * timer in every form that wants one, because the timer has to be cleared\n * when the component goes away and that is the part people forget.\n */\n recentlySucceeded: boolean;\n /**\n * Bind one field so this component holds its value.\n *\n * Most fields need nothing: they are uncontrolled, the DOM holds the value,\n * and it is read back as FormData on submit. Reach for this when the DOM\n * cannot hold it for you — a control with no native element behind it, or a\n * value you want to read as it is typed:\n *\n * <Input {...field('title')} />\n * <span>{field('body').value.length}/100</span>\n *\n * A bound field is still an ordinary named input, so it arrives in FormData\n * with everything else. Nothing merges; there is one source of truth.\n */\n field: <K extends keyof T & string>(name: K) => FieldBinding<T[K]>;\n}\n\n/** What a form can submit to: a url, or a server action. */\ntype FormAction = Route | ((formData: FormData) => Promise<unknown>);\n\n/**\n * What the action's refusal carries, read off the action itself - its\n * `.refusal(schema)` - so `formRefusal` is typed without a cast. Unknown for a\n * url, or for an action that does not say.\n */\ntype RefusalOf<A> = A extends (...args: never[]) => Promise<infer R>\n ? R extends { refusal?: infer F }\n ? F\n : unknown\n : unknown;\n\ninterface FormProps<\n T extends Record<string, unknown> = Record<string, unknown>,\n A extends FormAction = FormAction,\n F extends string = never,\n> extends Omit<\n FormHTMLAttributes<HTMLFormElement>,\n \"action\" | \"method\" | \"children\" | \"onSubmit\" | \"onError\"\n> {\n action: A;\n method?: \"get\" | \"post\";\n /**\n * The <form> element, for a caller that needs it - to focus, to scroll to,\n * to hand a library. The form keeps its own handle beside it; a caller's\n * never replaces it.\n */\n ref?: Ref<HTMLFormElement>;\n /**\n * Starting values for fields bound with `field()`.\n *\n * Uncontrolled fields do not need this — they take React's own\n * `defaultValue`, and the DOM keeps whatever is typed into them.\n */\n defaultValues?: Partial<T>;\n /**\n * The names `error()` and `clearErrors()` may be asked for, when nothing else\n * says: a form that posts nothing (its values live in React state, or it is a\n * button) has no FormData for an action to declare them on.\n *\n * <Form action={resize} fields={['size', 'copies']}>\n * {({ error }) => error('size')} // error('sise') fails the typecheck\n *\n * Types only: nothing is checked in the browser, and a name is a claim about\n * what the action's validation reports. Closes the set; names the action's own\n * input or `FormFields` declare, and `defaultValues` keys, are in it too.\n */\n fields?: readonly F[];\n /**\n * A store created above this form, from `useFormStore()`.\n *\n * For the one case the context cannot reach: something that is not a\n * descendant — a top bar showing unsaved changes, a sidebar preview — needs\n * the values to exist above both of them. Create the store where they share\n * an ancestor and hand it down.\n *\n * Without it the form makes its own, which is what almost every form wants.\n */\n store?: FormStore;\n prefetch?: PrefetchStrategy;\n cacheFor?: number;\n replace?: boolean;\n preserveScroll?: boolean;\n resetOnSuccess?: boolean;\n /**\n * Check the fields before submitting, with any Standard Schema — Zod,\n * Valibot, ArkType.\n *\n * A failure fills `errors` and the action is never called, so a mistake\n * costs no round trip. It is a courtesy and not a control: the same action\n * is reachable without this form, so the server still has to check.\n */\n schema?: StandardSchemaV1;\n /** Transform form data before submitting to the server action. */\n transform?: (data: T) => Record<string, unknown>;\n /** Called inside the transition with typed form data. Use it to call your useOptimistic setter. */\n optimistic?: (data: T) => void;\n onSuccess?: (result: unknown) => void;\n /**\n * Called when a submit does not succeed.\n *\n * Validation failures arrive as field errors, with no second argument.\n * Anything else arrives as an empty error map and the thrown value — there\n * are no field errors to report, but the form still has to say so.\n */\n onError?: (errors: Record<string, string[]>, error?: unknown) => void;\n onSubmit?: (formData: FormData) => void | false;\n children: ReactNode | ((form: FormRenderProps<T, RefusalOf<A>, FieldNameOf<T, A, F>>) => ReactNode);\n}\n\n/**\n * What an action built with createActionClient answers with.\n *\n * Recognised rather than thrown, because React serialises a rejected server\n * action opaquely: production strips the message and the fields it named are\n * gone. A returned object crosses intact, so a form reads it.\n */\nfunction resultOf(\n value: unknown,\n): { errors?: Record<string, string[]>; serverError?: string; refusal?: unknown; redirected?: string } | null {\n if (typeof value !== \"object\" || value === null) return null;\n\n const result = value as {\n validationErrors?: Record<string, string[]>;\n serverError?: string;\n refusal?: unknown;\n redirected?: string;\n };\n\n if (result.validationErrors) return { errors: result.validationErrors };\n if (result.serverError) return { serverError: result.serverError, refusal: result.refusal };\n if (typeof result.redirected === \"string\") return { redirected: result.redirected };\n\n return null;\n}\n\nconst FormStatusContext = createContext<FormRenderProps>({\n pending: false,\n data: {},\n dirty: false,\n error: () => undefined,\n formError: undefined,\n formRefusal: undefined,\n clearErrors: () => {},\n reset: () => {},\n succeeded: false,\n recentlySucceeded: false,\n // Outside a Form there is nothing holding a value, so a binding that reported\n // one would be lying. Name only, which is the part that is still true.\n field: ((name: string) => ({\n name,\n value: \"\",\n onChange: () => {},\n onBlur: () => {},\n })) as FormRenderProps[\"field\"],\n});\n\n/**\n * The store, on its own context.\n *\n * Separate from the status context because that one holds a fresh object every\n * render, so anything reading it re-renders with the form. The store is stable\n * for the life of the form, which is what lets a subscriber below it re-render\n * alone.\n */\nconst FormStoreContext = createContext<{\n store: FormStore;\n touch: (name: string) => void;\n} | null>(null);\n\n/**\n * A value store created above the form rather than by it.\n *\n * const store = useFormStore({ title: '' })\n *\n * <TopBar store={store} /> // not inside the form\n * <Form action={save} store={store}>…</Form>\n *\n * For the one case the context cannot reach. `<Form>` makes its own otherwise,\n * and almost every form should let it — this exists so that a component which\n * is not a descendant can still read the values, which is the flexibility\n * react-hook-form and TanStack Form get from `useForm()` being yours to call.\n *\n * Deliberately not reactive itself: creating the store does not subscribe to\n * it, so the component holding it does not re-render on every keystroke and\n * take the whole subtree with it. Read a field from it with `useField(name, store)`.\n */\nexport function useFormStore<T extends Record<string, unknown>>(\n initial: Partial<T> = {},\n): FormStore {\n const ref = useRef<FormStore | null>(null);\n\n ref.current ??= createFormStore({ ...initial });\n\n return ref.current;\n}\n\n/**\n * The form this component is inside: the same object `<Form>`'s render prop\n * gets, so a field split into its own component is written exactly as it\n * was inline.\n *\n * function Title() {\n * const { field, error } = useForm()\n *\n * return (\n * <>\n * <input name=\"title\" />\n * {error('title') && <p>{error('title')}</p>}\n * </>\n * )\n * }\n *\n * Not React's `useFormStatus`, which is a different hook with a different\n * answer - which is why this one is not called that.\n */\nexport function useForm<\n T extends Record<string, unknown> = Record<string, unknown>,\n Refusal = unknown,\n>(): FormRenderProps<T, Refusal> {\n return useContext(FormStatusContext) as FormRenderProps<T, Refusal>;\n}\n\n/**\n * One field, subscribed on its own - for a large controlled form.\n *\n * The same two words as everywhere else, for one name: `field` to spread,\n * `error` to show. The component re-renders when this field changes and at no\n * other time, where `useForm()` re-renders with the whole form. Reach for it\n * when re-rendering all of a form per keystroke is real:\n *\n * function Title() {\n * const { field, error } = useField('title')\n *\n * return <Input {...field} aria-invalid={!!error} />\n * }\n *\n * Given a store, it reads a form from outside it - see useFormStore.\n */\nexport function useField(\n name: string,\n store?: FormStore,\n): { field: FieldBinding<string>; error: string | undefined } {\n const ctx = useContext(FormStoreContext);\n const status = useContext(FormStatusContext);\n\n if (!ctx && !store) {\n throw new Error(\n \"useField() was called outside a <Form>. It reads that form's values, so there has to be one above it.\",\n );\n }\n\n const source = store ?? ctx!.store;\n const touch = ctx?.touch;\n\n const value = useSyncExternalStore(\n source.subscribe,\n () => (source.get(name) ?? \"\") as string,\n () => \"\",\n );\n\n return {\n field: {\n name,\n value,\n onChange: (next) => {\n source.set(\n name,\n typeof next === \"object\" && next !== null && \"target\" in next\n ? (next as { target: { value: string } }).target.value\n : next,\n );\n },\n onBlur: () => void touch?.(name),\n },\n error: status.error(name as never),\n };\n}\n\n/**\n * submitForm bound to an action, once per action.\n *\n * Bound on every render, it was a fresh function with a fresh promise for\n * its bound arguments each time - and React, seating a posted form's state\n * during the server render, suspends on that promise until it settles, then\n * renders the component again, which bound again. A render that never\n * finished, on every page a form was posted to without javascript. One\n * bound function per action, and the promise settles once.\n */\nconst boundSubmits = new WeakMap<Function, (previous: unknown, formData: FormData) => Promise<unknown>>();\n\nfunction boundSubmit(action: (formData: FormData) => Promise<unknown>) {\n let bound = boundSubmits.get(action);\n\n if (!bound) {\n bound = submitForm.bind(null, action);\n boundSubmits.set(action, bound);\n }\n\n return bound;\n}\n\n/**\n * A form's values as one comparable string.\n *\n * FormData in document order, a file by its name and size: enough to say\n * whether anything changed, which is all `dirty` asks.\n */\nfunction serializeForm(form: HTMLFormElement): string {\n const parts: string[] = [];\n\n for (const [name, value] of new FormData(form)) {\n parts.push(\n name + \"=\" + (typeof value === \"string\" ? value : \"file:\" + value.name + \":\" + value.size),\n );\n }\n\n return parts.join(\"\\n\");\n}\n\n/**\n * Also exported by name, and re-exported below, because both spellings are in\n * use: `import Form from` and `import { Form } from`.\n */\nexport default function Form<\n T extends Record<string, unknown> = Record<string, unknown>,\n A extends FormAction = FormAction,\n const F extends string = never,\n>({\n action,\n method: methodProp,\n defaultValues,\n // A type-level claim only. Named so it is not passed on to the <form>.\n fields: _fields,\n store: providedStore,\n prefetch = \"hover\",\n cacheFor,\n replace = false,\n preserveScroll = false,\n resetOnSuccess = true,\n schema,\n transform,\n optimistic,\n onSuccess,\n onError,\n onSubmit,\n children,\n ref: callerRef,\n ...rest\n}: FormProps<T, A, F>) {\n void _fields;\n const isGetForm = typeof action === \"string\";\n const method = methodProp ?? (isGetForm ? \"get\" : \"post\");\n\n // The answer to this form posted without a runtime, seated by React into\n // the form that posted it - which is the only way a visitor with no\n // javascript sees a refusal. Registered through submitForm, bound to the\n // action, because React hands a form-state action a (previous, formData)\n // pair and the action takes the FormData alone. On the server a plain\n // function - a closure, not a server reference - cannot be bound into a\n // form; the form falls back to the action itself, and posts nothing\n // seatable, which is all a closure could ever have done.\n const bindable =\n typeof action === \"function\" && (typeof window !== \"undefined\" || \"$$FORM_ACTION\" in action);\n const [posted, formAction] = useActionState(\n bindable ? boundSubmit(action as (formData: FormData) => Promise<unknown>) : async () => null,\n null as unknown,\n );\n const postedRefusal = resultOf(posted);\n const [errors, setErrors] = useState<Record<string, string[]>>(() => postedRefusal?.errors ?? {});\n // A refusal's data, tied to the exact form-level error it came with: when\n // that entry is cleared or replaced - the next submit, a success,\n // clearErrors() - the data goes with it, without every place that touches\n // the errors having to know.\n const [refusal, setRefusal] = useState<{ for: string[]; data: unknown } | null>(null);\n const [touched, setTouched] = useState<Record<string, boolean>>({});\n\n /**\n * Mark a field visited, and check it.\n *\n * Checking on blur rather than on every keystroke, because an error that\n * appears while someone is halfway through typing an email address is a form\n * arguing with them. Leaving the field is the moment they have finished\n * saying what they meant.\n *\n * The whole object is validated and only this field's issues are kept: a\n * Standard Schema has no notion of one field, and filtering by path is the\n * honest way to ask it about one. Everything else's errors are left as they\n * were, so blurring an empty field does not light up the rest of the form.\n */\n const touch = useCallback(\n async (name: string) => {\n setTouched((prev) => (prev[name] ? prev : { ...prev, [name]: true }));\n\n if (!schema || !formRef.current) return;\n\n const invalid = await validateWith(\n schema,\n decodeFormData(new FormData(formRef.current), schema),\n );\n\n setErrors((prev) => {\n const next = { ...prev };\n\n if (invalid?.[name]) next[name] = invalid[name];\n else delete next[name];\n\n return next;\n });\n },\n [schema],\n );\n\n const [succeeded, setSucceeded] = useState(false);\n const [recentlySucceeded, setRecentlySucceeded] = useState(false);\n const recentTimer = useRef<ReturnType<typeof setTimeout> | undefined>(\n undefined,\n );\n\n // Cleared on unmount: a timer that fires into a component that has gone is\n // the warning nobody reads and the leak nobody finds.\n useEffect(() => () => clearTimeout(recentTimer.current), []);\n\n // Only the fields someone bound. Everything else is the DOM's.\n //\n // A store rather than state, so a component using `useField` can re-render\n // for one field while this one does not. See formStore.ts.\n const storeRef = useRef<FormStore | null>(null);\n\n storeRef.current ??= createFormStore({\n ...(defaultValues as Record<string, unknown> | undefined),\n });\n\n const store = providedStore ?? storeRef.current;\n\n // Which names the render prop read through `field()`. A change to one of\n // those has to re-render this component, because that is where the value is\n // being displayed; a change to anything else does not, which is what lets a\n // `useField` child stand on its own.\n const readHere = useRef(new Set<string>());\n const [, bump] = useState(0);\n\n useEffect(\n () =>\n store.subscribe((name) => {\n if (name === \"\" || readHere.current.has(name)) bump((n) => n + 1);\n }),\n [store],\n );\n const [currentData, setCurrentData] = useState<T>({} as T);\n const [isPending, startTransition] = useTransition();\n const formRef = useRef<HTMLFormElement>(null);\n // Read by the delayed blur check, which runs after the render that set it:\n // the value its closure captured is the one from before the submit began.\n const pendingRef = useRef(false);\n pendingRef.current = isPending;\n\n // A reset owed by a successful submit, performed in the commit that ends\n // it. The action resolves a tick before React commits its transition - the\n // result, whatever the action revalidated, pending going false - and a\n // reset done on resolve was a DOM write with a frame of its own: a chat's\n // composer emptied before the reply it was answered with appeared. In a\n // layout effect of the commit where pending turns false, it lands in the\n // same frame as the result, before the browser paints.\n const resetOwed = useRef<{ result: unknown } | null>(null);\n\n // What the form started with, as its FormData reads: the baseline `dirty`\n // is measured against. Taken on mount, retaken after a successful submit.\n const baseline = useRef<string | null>(null);\n const [dirty, setDirty] = useState(false);\n // Only a form that reads `dirty` pays for it: the flip from clean to dirty\n // is a render of the whole form, and a field that subscribes for itself\n // is promised that typing in it renders it alone.\n const dirtyRead = useRef(false);\n\n const snapshot = useCallback(() => {\n if (!formRef.current) return;\n\n baseline.current = serializeForm(formRef.current);\n setDirty(false);\n }, []);\n\n const measureDirty = useCallback(() => {\n if (!dirtyRead.current || !formRef.current || baseline.current === null) return;\n\n const now = serializeForm(formRef.current) !== baseline.current;\n\n setDirty((was) => (was === now ? was : now));\n }, []);\n\n useEffect(snapshot, [snapshot]);\n\n // A bound control with no native element behind it changes through the\n // store, not through an input event - a Radix select - so the store is\n // watched too. Its input, if it has one, is read back with the rest. In\n // a microtask: the fields subscribed before this effect ran, so React's\n // own flush of their update is queued ahead of the measure, and the\n // element is read after it was written.\n useEffect(() => store.subscribe(() => queueMicrotask(measureDirty)), [store, measureDirty]);\n\n // A reset writes every bound field at once, through a render of this\n // component; the measure has to read the elements after that commit,\n // and a microtask queued during the reset ran before it. Marked here,\n // measured by the effect below once the render lands.\n const remeasure = useRef(false);\n\n useEffect(() => {\n if (!remeasure.current) return;\n\n remeasure.current = false;\n measureDirty();\n });\n\n useLayoutEffect(() => {\n const owed = resetOwed.current;\n\n if (!owed || isPending) return;\n\n resetOwed.current = null;\n store.reset();\n formRef.current?.reset();\n setTouched({});\n setCurrentData({} as T);\n snapshot();\n // After the reset, as it always ran: an onSuccess that fills or focuses a\n // field must not have the reset undo it.\n onSuccess?.(owed.result);\n });\n\n // Both handles, one element. React 19 hands a function component its ref\n // as a prop, and spread after the form's own it replaced it - every\n // FormData read then found null. A caller's ref is filled beside ours.\n const attachForm = useCallback(\n (element: HTMLFormElement | null) => {\n formRef.current = element;\n\n if (typeof callerRef === \"function\") callerRef(element);\n else if (callerRef) callerRef.current = element;\n },\n [callerRef],\n );\n\n const error = useCallback(\n (field: FieldPath<T>): string | undefined => errors[field]?.[0],\n [errors],\n );\n\n const clearErrors = useCallback((...fields: FieldPath<T>[]) => {\n if (fields.length === 0) {\n setErrors({});\n } else {\n setErrors((prev) => {\n const next = { ...prev };\n for (const f of fields) {\n delete next[f];\n }\n return next;\n });\n }\n }, []);\n\n // The store first, then the DOM. A bound field renders from the store, so\n // a DOM reset alone put its default in the element for one frame and the\n // typed value back on the next render: a port's Discard left the name as\n // typed while the dirty flag went clean beside it.\n const resetForm = useCallback(() => {\n remeasure.current = true;\n store.reset();\n formRef.current?.reset();\n setErrors({});\n setCurrentData({} as T);\n queueMicrotask(measureDirty);\n }, [store, measureDirty]);\n\n useEffect(() => {\n if (isGetForm && prefetch === \"mount\") {\n const fn = (window as any).__rsc_prefetch;\n fn?.(action, cacheFor);\n }\n }, [isGetForm, prefetch, action, cacheFor]);\n\n const doPrefetch = useCallback(() => {\n if (!isGetForm) return;\n const fn = (window as any).__rsc_prefetch;\n fn?.(action as string, cacheFor);\n }, [isGetForm, action, cacheFor]);\n\n const handleSubmit = useCallback(\n async (e: FormEvent<HTMLFormElement>) => {\n e.preventDefault();\n const formData = new FormData(e.currentTarget);\n const data = decodeFormData<T>(formData, schema);\n setCurrentData(data);\n\n if (onSubmit?.(formData) === false) {\n return;\n }\n\n if (isGetForm && method === \"get\") {\n const url = new URL(action as string, window.location.origin);\n for (const [key, value] of formData.entries()) {\n if (typeof value === \"string\" && value !== \"\") {\n url.searchParams.set(key, value);\n }\n }\n\n const path = url.pathname + url.search;\n const shell = action as string;\n const nav = (window as any).__rsc_navigate;\n const prefetched = (window as any).__rsc_is_prefetched;\n\n // The route without its query is that route's shell: the layout, the\n // chrome, and whatever it renders with nothing to show yet. Prefetching\n // on hover put it in the cache, so going there first costs no request\n // and puts the page on screen while the real query is still running.\n //\n // The query itself is never prefetched. It is the expensive half, and\n // hovering a search button is not a reason to run someone's search.\n if (path !== shell && prefetched?.(shell)) {\n // Awaited rather than raced: navigate() aborts whatever is in flight,\n // so starting the real one first would cancel the shell before it\n // could render. It is a cache hit, so this is a render, not a wait.\n Promise.resolve(nav?.(shell, { replace, preserveScroll })).then(() =>\n // Replaces, so the shell does not become a back-button stop of its\n // own — the pair leaves exactly one entry behind.\n nav?.(path, { replace: true, preserveScroll }),\n );\n\n return;\n }\n\n nav?.(path, { replace, preserveScroll });\n return;\n }\n\n const serverAction = action as (formData: FormData) => Promise<unknown>;\n\n // Rebuilt rather than edited: transform returns the values to send, so\n // whatever was in the form and is not in the result should not go.\n if (transform) {\n for (const key of [...formData.keys()]) formData.delete(key);\n\n for (const [key, value] of buildFormData(transform(data))) {\n formData.append(key, value);\n }\n }\n\n setErrors({});\n\n // Before the transition, so a failure neither runs the optimistic\n // update nor leaves the form looking like it is submitting.\n const invalid = await validateWith(schema, data);\n\n if (invalid) {\n setErrors(invalid);\n onError?.(invalid);\n\n return;\n }\n\n startTransition(async () => {\n try {\n // Call optimistic updater inside the transition so React's\n // useOptimistic picks it up and auto-reverts on settle.\n optimistic?.(data);\n\n // Whatever an earlier call noted is not this action's: a redirect\n // from another form, or from an action no form was waiting for - a\n // logout button - is left behind until someone reads it, and the\n // next form to succeed took it for its own and skipped onSuccess.\n redirectedTo();\n\n const result = await serverAction(formData);\n const refused = resultOf(result);\n // Read every time, which is what clears it. Behind the || below it\n // went unread whenever the answer already said \"redirected\", and\n // stayed for the next form.\n const redirected = redirectedTo();\n\n // The action answered with somewhere to go, and callServer has\n // already started the navigation. Not an error for a form to\n // show, and not a save to announce either: signing in and going\n // to the dashboard is the whole success.\n if (refused?.redirected !== undefined || redirected !== null) return;\n\n if (refused) {\n if (refused.errors) {\n setErrors(refused.errors);\n onError?.(refused.errors);\n } else {\n // Under the form's own key, so every place that clears the\n // errors clears it too.\n const formLevel = [refused.serverError ?? \"The action was refused.\"];\n\n setErrors({ \"\": formLevel });\n setRefusal(refused.refusal === undefined ? null : { for: formLevel, data: refused.refusal });\n onError?.({}, new Error(refused.serverError));\n }\n\n return;\n }\n\n // Owed, not done: see resetOwed. Saved, so what is in the form is\n // what the server has - measured after the reset where there is one.\n if (resetOnSuccess) resetOwed.current = { result };\n else snapshot();\n\n setErrors({});\n setSucceeded(true);\n setRecentlySucceeded(true);\n\n clearTimeout(recentTimer.current);\n recentTimer.current = setTimeout(\n () => setRecentlySucceeded(false),\n 2_000,\n );\n\n if (!resetOnSuccess) onSuccess?.(result);\n } catch (err) {\n // A redirect no longer arrives here - callServer resolves after\n // performing it - but an action called through something older\n // than that still may.\n if (err instanceof ServerRedirectError) return;\n\n if (err instanceof ServerValidationError) {\n setErrors(err.errors);\n onError?.(err.errors);\n } else if (err instanceof ActionRefusedError) {\n // A backend turned a generated stub down: its message, written for\n // the person asking, is the form's error.\n setErrors({ \"\": [err.message] });\n setRefusal(null);\n onError?.({}, err);\n } else if (err instanceof ServerDumpError) {\n // Dump overlay is already shown — silently swallow\n } else if (onError) {\n // Not rethrown. A rejected action never settles, and until it\n // settles React keeps the optimistic update on screen — so an\n // unexpected failure left the row showing as though the write had\n // worked. Settling is what takes it back.\n onError({}, err);\n } else {\n // Nothing is handling it, and swallowing here would lose it\n // entirely — the reason this used to rethrow.\n console.error(\"[rsc-kit] form submit failed\", err);\n }\n }\n });\n },\n [\n action,\n isGetForm,\n method,\n replace,\n preserveScroll,\n resetOnSuccess,\n store,\n schema,\n transform,\n optimistic,\n onSubmit,\n onSuccess,\n onError,\n ],\n );\n\n const field = useCallback(\n <K extends keyof T & string>(name: K): FieldBinding<T[K]> => {\n // Recorded during render, deliberately: this is how the form knows which\n // values it is the one displaying. Idempotent, so a double render in\n // development records the same name twice and means the same thing.\n readHere.current.add(name);\n\n return {\n name,\n value: (store.get(name) ?? \"\") as T[K],\n onChange: (next: unknown) => {\n const value =\n typeof next === \"object\" && next !== null && \"target\" in next\n ? (next as { target: { value: string } }).target.value\n : next;\n\n store.set(name, value);\n },\n onBlur: () => void touch(name),\n };\n },\n [store, touch],\n );\n\n\n // Stable, so a subscriber below does not re-render because this one did.\n const storeContext = useMemo(() => ({ store, touch }), [store, touch]);\n\n const formStatus: FormRenderProps<T, RefusalOf<A>, FieldNameOf<T, A, F>> = {\n pending: isPending,\n data: currentData,\n get dirty() {\n dirtyRead.current = true;\n\n return dirty;\n },\n succeeded,\n recentlySucceeded,\n field,\n error,\n formError: errors[\"\"]?.[0],\n formRefusal: (refusal && errors[\"\"] === refusal.for ? refusal.data : undefined) as RefusalOf<A> | undefined,\n clearErrors,\n reset: resetForm,\n };\n\n return (\n <FormStoreContext.Provider value={storeContext}>\n <FormStatusContext.Provider value={formStatus as FormRenderProps}>\n <form\n ref={attachForm}\n // On the element as well as in the handler, which is what makes this\n // work before hydration. React emits a form a browser can submit on its\n // own for a server action, and an ordinary action/method pair for a\n // url — so a submit that happens before the javascript arrives still\n // reaches the server.\n //\n // The two do not fight: handleSubmit calls preventDefault() first, and\n // React does not run a form action when the submit event was cancelled.\n // So the enhanced path wins whenever there is one, and the native path\n // is what is left when there is not.\n action={(bindable ? formAction : action) as never}\n // Only for a url. React sets the method itself for a server action, and\n // passing one alongside is what it warns about.\n method={isGetForm ? method : undefined}\n onSubmit={handleSubmit}\n // Every keystroke and every toggle, from any control in the form,\n // uncontrolled ones included: React's onInput here is the bubbling\n // `input` event. A caller's own handler still runs.\n onInput={(event) => {\n rest.onInput?.(event);\n measureDirty();\n }}\n onChange={(event) => {\n rest.onChange?.(event);\n measureDirty();\n }}\n // On the form, not only on the bound fields. `focusout` bubbles where\n // `blur` does not, so React's onBlur here sees every control that was\n // left — including the uncontrolled ones, which are most of them and\n // would otherwise never be marked touched at all.\n onBlur={(event) => {\n const target = event.target as unknown as {\n name?: string;\n value?: string;\n };\n const name = target.name;\n\n if (!name) return;\n\n // Leaving a field is the moment to check it; leaving the form is\n // not the same moment. Focus going to nothing, or to something\n // outside the form, is a click on the page - most often a dialog\n // closing - and an error painted into a dialog as it animates out\n // reads as a submit that nobody made. An empty field left that way\n // is not checked at all. One with something in it is, but only\n // once the dust settles: if the form is gone or hidden by then, it\n // was a dialog closing, and nobody is there to read the error.\n const left = event.relatedTarget as Node | null;\n const stillInForm = !!left && !!formRef.current?.contains(left);\n\n if (stillInForm) {\n void touch(name);\n\n return;\n }\n\n if (!target.value) return;\n\n setTimeout(() => {\n const form = formRef.current;\n\n if (\n !form ||\n !form.isConnected ||\n form.getClientRects().length === 0\n )\n return;\n // A submit in flight is not a dialog closing, and its answer is\n // the verdict on every field. On iOS a tap on the submit button\n // does not focus it, so the last field's blur arrives here as\n // \"left the form\" - and by now the fields may be disabled for\n // the pending submit, missing from its data, and judged absent:\n // \"last name is required\" flashed on the way to the next step.\n if (pendingRef.current) return;\n // Nor a field disabled by now, for the same reason: its value is\n // not in the form's data, so it would always read as missing.\n if ((event.target as { disabled?: boolean }).disabled) return;\n if (\n form.closest(\n \"[hidden], [aria-hidden='true'], [data-ending-style], [data-closed]\",\n )\n )\n return;\n\n void touch(name);\n }, LEAVE_FORM_SETTLE_MS);\n }}\n onMouseEnter={prefetch === \"hover\" ? doPrefetch : undefined}\n data-pending={isPending ? \"\" : undefined}\n {...rest}\n >\n {typeof children === \"function\" ? children(formStatus) : children}\n </form>\n </FormStatusContext.Provider>\n </FormStoreContext.Provider>\n );\n}\n\n// Also by name, because both spellings are in use: `import Form` and\n// `import { Form }`. This was a re-export of \"./Form\" — from inside Form.tsx,\n// so the module named itself. It survived on the bundler tolerating a circular\n// self-reference, left over from when a separate barrel re-exported a\n// FormComponent.tsx that a case-insensitive filesystem would not let be called\n// Form.ts. There is one file now, and it can just export what it declares.\nexport { Form };\n"]}
|
|
1
|
+
{"version":3,"file":"Form.js","sourceRoot":"","sources":["../../src/js/Form.tsx"],"names":[],"mappings":"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","sourcesContent":["\"use client\";\n\nimport type { Route } from \"../routes.js\";\nimport {\n type FormHTMLAttributes,\n type FormEvent,\n type ReactNode,\n type Ref,\n createContext,\n useCallback,\n useContext,\n useEffect,\n useLayoutEffect,\n useMemo,\n useRef,\n useActionState,\n useState,\n useSyncExternalStore,\n useTransition,\n} from \"react\";\nimport { submitForm } from \"../formSubmit\";\nimport { ActionRefusedError, ServerValidationError, ServerDumpError, ServerRedirectError, redirectedTo } from \"./errors\";\nimport { buildFormData, decodeFormData } from \"./formEncoding\";\nimport { createFormStore } from \"./formStore\";\nimport type { FormStore } from \"./formStore\";\nimport { validateWith } from \"./standardSchema\";\nimport type { StandardSchemaV1 } from \"./standardSchema\";\n\n/**\n * How long a blur that leaves the form waits before checking the field. A\n * dialog's exit animation is shorter than this; a form still on screen after\n * it is one somebody is looking at.\n */\nconst LEAVE_FORM_SETTLE_MS = 300;\n\ntype PrefetchStrategy = \"hover\" | \"mount\" | \"none\";\n\n/**\n * What `field(name)` hands a control, spread straight onto it.\n *\n * The same four things react-hook-form's `<Controller>` gives, because it is\n * the same job: a component with no native control behind it needs a value and\n * a way to report a new one.\n */\ninterface FieldBinding<V> {\n name: string;\n value: V;\n /**\n * Either shape: a DOM event, or the value itself.\n *\n * A native input passes the event; a Radix select or a rich editor passes\n * what was chosen. A binder understanding only one of them would work on\n * half the controls anyone actually uses.\n */\n onChange: (next: V | { target: { value: V } }) => void;\n onBlur: () => void;\n}\n\n/**\n * A field's name: one the form declared, suggested by the editor - or any\n * path, because a nested or indexed field (`address.city`, `items[0].name`)\n * is a real name no defaultValues object can declare. The typo that matters\n * is caught on `field()`, which is closed to the declared names.\n */\ntype FieldPath<T> = (keyof T & string) | (string & {});\n\n/** Dots deep, so a self-referential or very wide input type cannot run the compiler out. */\ntype Depth = [never, 0, 1, 2, 3];\n\n/**\n * Every name an error can be filed under in a value: its keys, a nested object's\n * `address.city`, and a list's `items.0.sku` - the shape a Standard Schema\n * issue and a backend's validation both produce.\n */\ntype Paths<T, D extends number = 3> = [D] extends [never]\n ? never\n : T extends readonly (infer U)[]\n ? `${number}` | `${number}.${Paths<U, Depth[D]>}`\n : T extends object\n ? { [K in keyof T & string]: K | (T[K] extends object ? `${K}.${Paths<T[K], Depth[D]>}` : never) }[keyof T & string]\n : never;\n\n/**\n * What an action takes, read off the action: a generated stub's typed overload,\n * or the input of one built with `createActionClient().input(schema)`. Unknown\n * when it does not say - a url, or a function of a FormData - and then nothing\n * is claimed about its fields.\n */\ntype InputOfAction<A> = [A] extends [never]\n ? unknown // `action={signup as never}`: a cast says nothing about the input\n : 0 extends 1 & A\n ? unknown // any\n : A extends { (input: infer I): Promise<unknown>; (form: FormData): Promise<unknown> }\n ? Described<I>\n : A extends (input: infer I) => Promise<unknown>\n ? Described<I>\n : unknown;\n\n/** An action's parameter, without the FormData a form posts it as; unknown if that was all it said. */\ntype Described<I> = [Exclude<I, FormData | undefined>] extends [never] ? unknown : Exclude<I, FormData | undefined>;\n\ndeclare const NAMES: unique symbol;\n\n/**\n * A form's FormData, naming its fields.\n *\n * For an action the app writes that takes a form and passes it on - to a stub\n * whose parameters are plain strings, say - which says nothing of its fields to\n * anything reading its type. Declared on the parameter, where the names live\n * with the code that reads them:\n *\n * export async function createApp(form: FormFields<'name' | 'region'>) {\n * return await appsCreate(String(form.get('name')), String(form.get('region')))\n * }\n *\n * and `<Form action={createApp}>` closes `error()` to those names. Nothing runs:\n * it is a FormData, and every FormData is one. The names are a claim the types\n * keep, not a check the browser makes.\n */\nexport interface FormFields<Name extends string> extends FormData {\n readonly [NAMES]?: Name;\n}\n\n/** The names a form-taking action declared with FormFields, or never when it did not. */\ntype DeclaredNames<A> = A extends (form: FormFields<infer N>, ...rest: never[]) => Promise<unknown>\n ? string extends N\n ? never\n : N\n : never;\n\n/**\n * The names an action's validation can be read under, for `error()` and\n * `clearErrors()`: the input's own paths, the names a wrapper declared, and the\n * form's declared values.\n *\n * Closed when the action says what it takes, so `error('nmae')` fails the\n * typecheck rather than showing nothing, ever. Open, as it always was, when it\n * does not - a field is only a typo if something could have said so.\n */\ntype FieldNameOf<T, A, F extends string = never> = [F] extends [never]\n ? unknown extends InputOfAction<A>\n ? [DeclaredNames<A>] extends [never]\n ? FieldPath<T>\n : DeclaredKeys<T> | DeclaredNames<A>\n : DeclaredKeys<T> | Paths<InputOfAction<A>> | DeclaredNames<A>\n : // Named on the form itself: closed to these, beside everything else that names a field.\n F | DeclaredKeys<T> | DeclaredNames<A> | (unknown extends InputOfAction<A> ? never : Paths<InputOfAction<A>>);\n\n/** The form's declared values count - but T is the open record when it declared none, and all of `string` is not a name. */\ntype DeclaredKeys<T> = string extends keyof T ? never : keyof T & string;\n\n/** The field names an action's validation can name, for a component below a form to type. */\nexport type FieldNamesOf<A> = unknown extends InputOfAction<A>\n ? [DeclaredNames<A>] extends [never]\n ? string\n : DeclaredNames<A>\n : Paths<InputOfAction<A>> | DeclaredNames<A>;\n\ninterface FormRenderProps<\n T extends Record<string, unknown> = Record<string, unknown>,\n Refusal = unknown,\n Name extends string = FieldPath<T>,\n> {\n pending: boolean;\n /** What is being submitted, while it is. */\n data: T;\n /**\n * A field's error, or undefined: the one way to read one.\n *\n * {error('title') && <p>{error('title')}</p>}\n * <Field data-invalid={!!error('title')}>\n *\n * Nested paths join with dots - `error('address.city')`, the key a Standard\n * Schema issue for that field produces. A field is checked when it is left\n * and when the form is submitted, so an error never appears on a field\n * nobody has reached yet.\n */\n error: (field: Name) => string | undefined;\n /**\n * The refusal that is not about a field: the action's `serverError` - a\n * 402, a 409, \"that slot was just taken\" - or a validation message for the\n * form as a whole. Undefined otherwise. Cleared by the next submit, by a\n * success, and by `clearErrors()` and `reset()`, like a field's.\n *\n * {formError && <p role=\"alert\">{formError}</p>}\n *\n * Only what the action returned: a failure thrown on the way, the network\n * or a crash, goes to `onError` as before, where a production message is\n * React's stand-in and not something to show.\n */\n formError: string | undefined;\n /**\n * What the action's refusal carried beside `formError` - the records\n * blocking a delete, say - when the action refused with `refuse()` and\n * declared its shape with `.refusal(schema)`. Typed from the form's\n * `action` in its render prop; in a component below, `useForm<T, R>()`.\n * Goes when `formError` does.\n */\n formRefusal: Refusal | undefined;\n clearErrors: (...fields: Name[]) => void;\n reset: () => void;\n /**\n * Whether anything differs from what the form started with.\n *\n * For the Save button that stays quiet until there is something to save,\n * and the Discard that appears beside it. Read from the form itself - a\n * snapshot of its FormData on mount, compared on every input - so an\n * uncontrolled field counts, which nothing outside the form can do. A\n * successful submit makes the current values the new baseline; `reset()`\n * goes back to the first one.\n */\n dirty: boolean;\n /** Whether the last submit was accepted. */\n succeeded: boolean;\n /**\n * The same thing, for two seconds.\n *\n * The \"Saved ✓\" that appears and fades. Worth having as state rather than a\n * timer in every form that wants one, because the timer has to be cleared\n * when the component goes away and that is the part people forget.\n */\n recentlySucceeded: boolean;\n /**\n * Bind one field so this component holds its value.\n *\n * Most fields need nothing: they are uncontrolled, the DOM holds the value,\n * and it is read back as FormData on submit. Reach for this when the DOM\n * cannot hold it for you — a control with no native element behind it, or a\n * value you want to read as it is typed:\n *\n * <Input {...field('title')} />\n * <span>{field('body').value.length}/100</span>\n *\n * A bound field is still an ordinary named input, so it arrives in FormData\n * with everything else. Nothing merges; there is one source of truth.\n */\n field: <K extends keyof T & string>(name: K) => FieldBinding<T[K]>;\n}\n\n/** What a form can submit to: a url, or a server action. */\ntype FormAction = Route | ((formData: FormData) => Promise<unknown>);\n\n/**\n * What the action's refusal carries, read off the action itself - its\n * `.refusal(schema)` - so `formRefusal` is typed without a cast. Unknown for a\n * url, or for an action that does not say.\n */\ntype RefusalOf<A> = A extends (...args: never[]) => Promise<infer R>\n ? R extends { refusal?: infer F }\n ? F\n : unknown\n : unknown;\n\ninterface FormProps<\n T extends Record<string, unknown> = Record<string, unknown>,\n A extends FormAction = FormAction,\n F extends string = never,\n> extends Omit<\n FormHTMLAttributes<HTMLFormElement>,\n \"action\" | \"method\" | \"children\" | \"onSubmit\" | \"onError\"\n> {\n action: A;\n method?: \"get\" | \"post\";\n /**\n * The <form> element, for a caller that needs it - to focus, to scroll to,\n * to hand a library. The form keeps its own handle beside it; a caller's\n * never replaces it.\n */\n ref?: Ref<HTMLFormElement>;\n /**\n * Starting values for fields bound with `field()`.\n *\n * Uncontrolled fields do not need this — they take React's own\n * `defaultValue`, and the DOM keeps whatever is typed into them.\n */\n defaultValues?: Partial<T>;\n /**\n * The names `error()` and `clearErrors()` may be asked for, when nothing else\n * says: a form that posts nothing (its values live in React state, or it is a\n * button) has no FormData for an action to declare them on.\n *\n * <Form action={resize} fields={['size', 'copies']}>\n * {({ error }) => error('size')} // error('sise') fails the typecheck\n *\n * Types only: nothing is checked in the browser, and a name is a claim about\n * what the action's validation reports. Closes the set; names the action's own\n * input or `FormFields` declare, and `defaultValues` keys, are in it too.\n */\n fields?: readonly F[];\n /**\n * A store created above this form, from `useFormStore()`.\n *\n * For the one case the context cannot reach: something that is not a\n * descendant — a top bar showing unsaved changes, a sidebar preview — needs\n * the values to exist above both of them. Create the store where they share\n * an ancestor and hand it down.\n *\n * Without it the form makes its own, which is what almost every form wants.\n */\n store?: FormStore;\n prefetch?: PrefetchStrategy;\n cacheFor?: number;\n replace?: boolean;\n preserveScroll?: boolean;\n resetOnSuccess?: boolean;\n /**\n * Check the fields before submitting, with any Standard Schema — Zod,\n * Valibot, ArkType.\n *\n * A failure fills `errors` and the action is never called, so a mistake\n * costs no round trip. It is a courtesy and not a control: the same action\n * is reachable without this form, so the server still has to check.\n */\n schema?: StandardSchemaV1;\n /** Transform form data before submitting to the server action. */\n transform?: (data: T) => Record<string, unknown>;\n /** Called inside the transition with typed form data. Use it to call your useOptimistic setter. */\n optimistic?: (data: T) => void;\n onSuccess?: (result: unknown) => void;\n /**\n * Called when a submit does not succeed.\n *\n * Validation failures arrive as field errors, with no second argument.\n * Anything else arrives as an empty error map and the thrown value — there\n * are no field errors to report, but the form still has to say so.\n */\n onError?: (errors: Record<string, string[]>, error?: unknown) => void;\n onSubmit?: (formData: FormData) => void | false;\n children: ReactNode | ((form: FormRenderProps<T, RefusalOf<A>, FieldNameOf<T, A, F>>) => ReactNode);\n}\n\n/**\n * What an action built with createActionClient answers with.\n *\n * Recognised rather than thrown, because React serialises a rejected server\n * action opaquely: production strips the message and the fields it named are\n * gone. A returned object crosses intact, so a form reads it.\n */\nfunction resultOf(\n value: unknown,\n): { errors?: Record<string, string[]>; serverError?: string; refusal?: unknown; redirected?: string } | null {\n if (typeof value !== \"object\" || value === null) return null;\n\n const result = value as {\n validationErrors?: Record<string, string[]>;\n serverError?: string;\n refusal?: unknown;\n redirected?: string;\n };\n\n if (result.validationErrors) return { errors: result.validationErrors };\n if (result.serverError) return { serverError: result.serverError, refusal: result.refusal };\n if (typeof result.redirected === \"string\") return { redirected: result.redirected };\n\n return null;\n}\n\nconst FormStatusContext = createContext<FormRenderProps>({\n pending: false,\n data: {},\n dirty: false,\n error: () => undefined,\n formError: undefined,\n formRefusal: undefined,\n clearErrors: () => {},\n reset: () => {},\n succeeded: false,\n recentlySucceeded: false,\n // Outside a Form there is nothing holding a value, so a binding that reported\n // one would be lying. Name only, which is the part that is still true.\n field: ((name: string) => ({\n name,\n value: \"\",\n onChange: () => {},\n onBlur: () => {},\n })) as FormRenderProps[\"field\"],\n});\n\n/**\n * The store, on its own context.\n *\n * Separate from the status context because that one holds a fresh object every\n * render, so anything reading it re-renders with the form. The store is stable\n * for the life of the form, which is what lets a subscriber below it re-render\n * alone.\n */\nconst FormStoreContext = createContext<{\n store: FormStore;\n touch: (name: string) => void;\n} | null>(null);\n\n/**\n * A value store created above the form rather than by it.\n *\n * const store = useFormStore({ title: '' })\n *\n * <TopBar store={store} /> // not inside the form\n * <Form action={save} store={store}>…</Form>\n *\n * For the one case the context cannot reach. `<Form>` makes its own otherwise,\n * and almost every form should let it — this exists so that a component which\n * is not a descendant can still read the values, which is the flexibility\n * react-hook-form and TanStack Form get from `useForm()` being yours to call.\n *\n * Deliberately not reactive itself: creating the store does not subscribe to\n * it, so the component holding it does not re-render on every keystroke and\n * take the whole subtree with it. Read a field from it with `useField(name, store)`.\n */\nexport function useFormStore<T extends Record<string, unknown>>(\n initial: Partial<T> = {},\n): FormStore {\n const ref = useRef<FormStore | null>(null);\n\n ref.current ??= createFormStore({ ...initial });\n\n return ref.current;\n}\n\n/**\n * The form this component is inside: the same object `<Form>`'s render prop\n * gets, so a field split into its own component is written exactly as it\n * was inline.\n *\n * function Title() {\n * const { field, error } = useForm()\n *\n * return (\n * <>\n * <input name=\"title\" />\n * {error('title') && <p>{error('title')}</p>}\n * </>\n * )\n * }\n *\n * Not React's `useFormStatus`, which is a different hook with a different\n * answer - which is why this one is not called that.\n */\nexport function useForm<\n T extends Record<string, unknown> = Record<string, unknown>,\n Refusal = unknown,\n>(): FormRenderProps<T, Refusal> {\n return useContext(FormStatusContext) as FormRenderProps<T, Refusal>;\n}\n\n/**\n * One field, subscribed on its own - for a large controlled form.\n *\n * The same two words as everywhere else, for one name: `field` to spread,\n * `error` to show. The component re-renders when this field changes and at no\n * other time, where `useForm()` re-renders with the whole form. Reach for it\n * when re-rendering all of a form per keystroke is real:\n *\n * function Title() {\n * const { field, error } = useField('title')\n *\n * return <Input {...field} aria-invalid={!!error} />\n * }\n *\n * Given a store, it reads a form from outside it - see useFormStore.\n */\nexport function useField(\n name: string,\n store?: FormStore,\n): { field: FieldBinding<string>; error: string | undefined } {\n const ctx = useContext(FormStoreContext);\n const status = useContext(FormStatusContext);\n\n if (!ctx && !store) {\n throw new Error(\n \"useField() was called outside a <Form>. It reads that form's values, so there has to be one above it.\",\n );\n }\n\n const source = store ?? ctx!.store;\n const touch = ctx?.touch;\n\n const value = useSyncExternalStore(\n source.subscribe,\n () => (source.get(name) ?? \"\") as string,\n () => \"\",\n );\n\n return {\n field: {\n name,\n value,\n onChange: (next) => {\n source.set(\n name,\n typeof next === \"object\" && next !== null && \"target\" in next\n ? (next as { target: { value: string } }).target.value\n : next,\n );\n },\n onBlur: () => void touch?.(name),\n },\n error: status.error(name as never),\n };\n}\n\n/**\n * submitForm bound to an action, once per action.\n *\n * Bound on every render, it was a fresh function with a fresh promise for\n * its bound arguments each time - and React, seating a posted form's state\n * during the server render, suspends on that promise until it settles, then\n * renders the component again, which bound again. A render that never\n * finished, on every page a form was posted to without javascript. One\n * bound function per action, and the promise settles once.\n */\nconst boundSubmits = new WeakMap<Function, (previous: unknown, formData: FormData) => Promise<unknown>>();\n\nfunction boundSubmit(action: (formData: FormData) => Promise<unknown>) {\n let bound = boundSubmits.get(action);\n\n if (!bound) {\n bound = submitForm.bind(null, action);\n boundSubmits.set(action, bound);\n }\n\n return bound;\n}\n\n/**\n * A form's values as one comparable string.\n *\n * FormData in document order, a file by its name and size: enough to say\n * whether anything changed, which is all `dirty` asks.\n */\n/** Whether a GET form's action is the page on screen, whatever query it carries. */\nfunction isThisPage(action: string): boolean {\n return new URL(action, window.location.origin).pathname === window.location.pathname;\n}\n\nfunction serializeForm(form: HTMLFormElement): string {\n const parts: string[] = [];\n\n for (const [name, value] of new FormData(form)) {\n parts.push(\n name + \"=\" + (typeof value === \"string\" ? value : \"file:\" + value.name + \":\" + value.size),\n );\n }\n\n return parts.join(\"\\n\");\n}\n\n/**\n * Also exported by name, and re-exported below, because both spellings are in\n * use: `import Form from` and `import { Form } from`.\n */\nexport default function Form<\n T extends Record<string, unknown> = Record<string, unknown>,\n A extends FormAction = FormAction,\n const F extends string = never,\n>({\n action,\n method: methodProp,\n defaultValues,\n // A type-level claim only. Named so it is not passed on to the <form>.\n fields: _fields,\n store: providedStore,\n prefetch = \"hover\",\n cacheFor,\n replace = false,\n preserveScroll = false,\n resetOnSuccess = true,\n schema,\n transform,\n optimistic,\n onSuccess,\n onError,\n onSubmit,\n children,\n ref: callerRef,\n ...rest\n}: FormProps<T, A, F>) {\n void _fields;\n const isGetForm = typeof action === \"string\";\n const method = methodProp ?? (isGetForm ? \"get\" : \"post\");\n\n // The answer to this form posted without a runtime, seated by React into\n // the form that posted it - which is the only way a visitor with no\n // javascript sees a refusal. Registered through submitForm, bound to the\n // action, because React hands a form-state action a (previous, formData)\n // pair and the action takes the FormData alone. On the server a plain\n // function - a closure, not a server reference - cannot be bound into a\n // form; the form falls back to the action itself, and posts nothing\n // seatable, which is all a closure could ever have done.\n const bindable =\n typeof action === \"function\" && (typeof window !== \"undefined\" || \"$$FORM_ACTION\" in action);\n const [posted, formAction] = useActionState(\n bindable ? boundSubmit(action as (formData: FormData) => Promise<unknown>) : async () => null,\n null as unknown,\n );\n const postedRefusal = resultOf(posted);\n const [errors, setErrors] = useState<Record<string, string[]>>(() => postedRefusal?.errors ?? {});\n // A refusal's data, tied to the exact form-level error it came with: when\n // that entry is cleared or replaced - the next submit, a success,\n // clearErrors() - the data goes with it, without every place that touches\n // the errors having to know.\n const [refusal, setRefusal] = useState<{ for: string[]; data: unknown } | null>(null);\n const [touched, setTouched] = useState<Record<string, boolean>>({});\n\n /**\n * Mark a field visited, and check it.\n *\n * Checking on blur rather than on every keystroke, because an error that\n * appears while someone is halfway through typing an email address is a form\n * arguing with them. Leaving the field is the moment they have finished\n * saying what they meant.\n *\n * The whole object is validated and only this field's issues are kept: a\n * Standard Schema has no notion of one field, and filtering by path is the\n * honest way to ask it about one. Everything else's errors are left as they\n * were, so blurring an empty field does not light up the rest of the form.\n */\n const touch = useCallback(\n async (name: string) => {\n setTouched((prev) => (prev[name] ? prev : { ...prev, [name]: true }));\n\n if (!schema || !formRef.current) return;\n\n const invalid = await validateWith(\n schema,\n decodeFormData(new FormData(formRef.current), schema),\n );\n\n setErrors((prev) => {\n const next = { ...prev };\n\n if (invalid?.[name]) next[name] = invalid[name];\n else delete next[name];\n\n return next;\n });\n },\n [schema],\n );\n\n const [succeeded, setSucceeded] = useState(false);\n const [recentlySucceeded, setRecentlySucceeded] = useState(false);\n const recentTimer = useRef<ReturnType<typeof setTimeout> | undefined>(\n undefined,\n );\n\n // Cleared on unmount: a timer that fires into a component that has gone is\n // the warning nobody reads and the leak nobody finds.\n useEffect(() => () => clearTimeout(recentTimer.current), []);\n\n // Only the fields someone bound. Everything else is the DOM's.\n //\n // A store rather than state, so a component using `useField` can re-render\n // for one field while this one does not. See formStore.ts.\n const storeRef = useRef<FormStore | null>(null);\n\n storeRef.current ??= createFormStore({\n ...(defaultValues as Record<string, unknown> | undefined),\n });\n\n const store = providedStore ?? storeRef.current;\n\n // Which names the render prop read through `field()`. A change to one of\n // those has to re-render this component, because that is where the value is\n // being displayed; a change to anything else does not, which is what lets a\n // `useField` child stand on its own.\n const readHere = useRef(new Set<string>());\n const [, bump] = useState(0);\n\n useEffect(\n () =>\n store.subscribe((name) => {\n if (name === \"\" || readHere.current.has(name)) bump((n) => n + 1);\n }),\n [store],\n );\n const [currentData, setCurrentData] = useState<T>({} as T);\n const [isPending, startTransition] = useTransition();\n const formRef = useRef<HTMLFormElement>(null);\n // Read by the delayed blur check, which runs after the render that set it:\n // the value its closure captured is the one from before the submit began.\n const pendingRef = useRef(false);\n pendingRef.current = isPending;\n\n // A reset owed by a successful submit, performed in the commit that ends\n // it. The action resolves a tick before React commits its transition - the\n // result, whatever the action revalidated, pending going false - and a\n // reset done on resolve was a DOM write with a frame of its own: a chat's\n // composer emptied before the reply it was answered with appeared. In a\n // layout effect of the commit where pending turns false, it lands in the\n // same frame as the result, before the browser paints.\n const resetOwed = useRef<{ result: unknown } | null>(null);\n\n // What the form started with, as its FormData reads: the baseline `dirty`\n // is measured against. Taken on mount, retaken after a successful submit.\n const baseline = useRef<string | null>(null);\n const [dirty, setDirty] = useState(false);\n // Only a form that reads `dirty` pays for it: the flip from clean to dirty\n // is a render of the whole form, and a field that subscribes for itself\n // is promised that typing in it renders it alone.\n const dirtyRead = useRef(false);\n\n const snapshot = useCallback(() => {\n if (!formRef.current) return;\n\n baseline.current = serializeForm(formRef.current);\n setDirty(false);\n }, []);\n\n const measureDirty = useCallback(() => {\n if (!dirtyRead.current || !formRef.current || baseline.current === null) return;\n\n const now = serializeForm(formRef.current) !== baseline.current;\n\n setDirty((was) => (was === now ? was : now));\n }, []);\n\n useEffect(snapshot, [snapshot]);\n\n // A bound control with no native element behind it changes through the\n // store, not through an input event - a Radix select - so the store is\n // watched too. Its input, if it has one, is read back with the rest. In\n // a microtask: the fields subscribed before this effect ran, so React's\n // own flush of their update is queued ahead of the measure, and the\n // element is read after it was written.\n useEffect(() => store.subscribe(() => queueMicrotask(measureDirty)), [store, measureDirty]);\n\n // A reset writes every bound field at once, through a render of this\n // component; the measure has to read the elements after that commit,\n // and a microtask queued during the reset ran before it. Marked here,\n // measured by the effect below once the render lands.\n const remeasure = useRef(false);\n\n useEffect(() => {\n if (!remeasure.current) return;\n\n remeasure.current = false;\n measureDirty();\n });\n\n useLayoutEffect(() => {\n const owed = resetOwed.current;\n\n if (!owed || isPending) return;\n\n resetOwed.current = null;\n store.reset();\n formRef.current?.reset();\n setTouched({});\n setCurrentData({} as T);\n snapshot();\n // After the reset, as it always ran: an onSuccess that fills or focuses a\n // field must not have the reset undo it.\n onSuccess?.(owed.result);\n });\n\n // Both handles, one element. React 19 hands a function component its ref\n // as a prop, and spread after the form's own it replaced it - every\n // FormData read then found null. A caller's ref is filled beside ours.\n const attachForm = useCallback(\n (element: HTMLFormElement | null) => {\n formRef.current = element;\n\n if (typeof callerRef === \"function\") callerRef(element);\n else if (callerRef) callerRef.current = element;\n },\n [callerRef],\n );\n\n const error = useCallback(\n (field: FieldPath<T>): string | undefined => errors[field]?.[0],\n [errors],\n );\n\n const clearErrors = useCallback((...fields: FieldPath<T>[]) => {\n if (fields.length === 0) {\n setErrors({});\n } else {\n setErrors((prev) => {\n const next = { ...prev };\n for (const f of fields) {\n delete next[f];\n }\n return next;\n });\n }\n }, []);\n\n // The store first, then the DOM. A bound field renders from the store, so\n // a DOM reset alone put its default in the element for one frame and the\n // typed value back on the next render: a port's Discard left the name as\n // typed while the dirty flag went clean beside it.\n const resetForm = useCallback(() => {\n remeasure.current = true;\n store.reset();\n formRef.current?.reset();\n setErrors({});\n setCurrentData({} as T);\n queueMicrotask(measureDirty);\n }, [store, measureDirty]);\n\n useEffect(() => {\n if (isGetForm && prefetch === \"mount\" && !isThisPage(action)) {\n const fn = (window as any).__rsc_prefetch;\n fn?.(action, cacheFor);\n }\n }, [isGetForm, prefetch, action, cacheFor]);\n\n const doPrefetch = useCallback(() => {\n // The page on screen is not a shell to show: it is already shown.\n if (!isGetForm || isThisPage(action as string)) return;\n const fn = (window as any).__rsc_prefetch;\n fn?.(action as string, cacheFor);\n }, [isGetForm, action, cacheFor]);\n\n const handleSubmit = useCallback(\n async (e: FormEvent<HTMLFormElement>) => {\n e.preventDefault();\n const formData = new FormData(e.currentTarget);\n const data = decodeFormData<T>(formData, schema);\n setCurrentData(data);\n\n if (onSubmit?.(formData) === false) {\n return;\n }\n\n if (isGetForm && method === \"get\") {\n const url = new URL(action as string, window.location.origin);\n for (const [key, value] of formData.entries()) {\n if (typeof value === \"string\" && value !== \"\") {\n url.searchParams.set(key, value);\n }\n }\n\n const path = url.pathname + url.search;\n const shell = action as string;\n const nav = (window as any).__rsc_navigate;\n const prefetched = (window as any).__rsc_is_prefetched;\n\n // A search on the page it is on. There is no other page whose shell\n // could stand in while the query runs - the shell would be this page\n // with nothing in it - so the page stays, results and all, until the\n // new ones replace them, and the form says it is working. The\n // transition is what keeps pending true until they have: the\n // navigation's own update joins it, and commits with it.\n if (isThisPage(shell)) {\n startTransition(async () => {\n await nav?.(path, { replace, preserveScroll, inPlace: true })?.catch(() => {});\n });\n\n return;\n }\n\n // The route without its query is that route's shell: the layout, the\n // chrome, and whatever it renders with nothing to show yet. Prefetching\n // on hover put it in the cache, so going there first costs no request\n // and puts the page on screen while the real query is still running.\n //\n // The query itself is never prefetched. It is the expensive half, and\n // hovering a search button is not a reason to run someone's search.\n if (path !== shell && prefetched?.(shell)) {\n // Awaited rather than raced: navigate() aborts whatever is in flight,\n // so starting the real one first would cancel the shell before it\n // could render. It is a cache hit, so this is a render, not a wait.\n Promise.resolve(nav?.(shell, { replace, preserveScroll })).then(() =>\n // Replaces, so the shell does not become a back-button stop of its\n // own — the pair leaves exactly one entry behind.\n nav?.(path, { replace: true, preserveScroll }),\n );\n\n return;\n }\n\n nav?.(path, { replace, preserveScroll });\n return;\n }\n\n const serverAction = action as (formData: FormData) => Promise<unknown>;\n\n // Rebuilt rather than edited: transform returns the values to send, so\n // whatever was in the form and is not in the result should not go.\n if (transform) {\n for (const key of [...formData.keys()]) formData.delete(key);\n\n for (const [key, value] of buildFormData(transform(data))) {\n formData.append(key, value);\n }\n }\n\n setErrors({});\n\n // Before the transition, so a failure neither runs the optimistic\n // update nor leaves the form looking like it is submitting.\n const invalid = await validateWith(schema, data);\n\n if (invalid) {\n setErrors(invalid);\n onError?.(invalid);\n\n return;\n }\n\n startTransition(async () => {\n try {\n // Call optimistic updater inside the transition so React's\n // useOptimistic picks it up and auto-reverts on settle.\n optimistic?.(data);\n\n // Whatever an earlier call noted is not this action's: a redirect\n // from another form, or from an action no form was waiting for - a\n // logout button - is left behind until someone reads it, and the\n // next form to succeed took it for its own and skipped onSuccess.\n redirectedTo();\n\n const result = await serverAction(formData);\n const refused = resultOf(result);\n // Read every time, which is what clears it. Behind the || below it\n // went unread whenever the answer already said \"redirected\", and\n // stayed for the next form.\n const redirected = redirectedTo();\n\n // The action answered with somewhere to go, and callServer has\n // already started the navigation. Not an error for a form to\n // show, and not a save to announce either: signing in and going\n // to the dashboard is the whole success.\n if (refused?.redirected !== undefined || redirected !== null) return;\n\n if (refused) {\n if (refused.errors) {\n setErrors(refused.errors);\n onError?.(refused.errors);\n } else {\n // Under the form's own key, so every place that clears the\n // errors clears it too.\n const formLevel = [refused.serverError ?? \"The action was refused.\"];\n\n setErrors({ \"\": formLevel });\n setRefusal(refused.refusal === undefined ? null : { for: formLevel, data: refused.refusal });\n onError?.({}, new Error(refused.serverError));\n }\n\n return;\n }\n\n // Owed, not done: see resetOwed. Saved, so what is in the form is\n // what the server has - measured after the reset where there is one.\n if (resetOnSuccess) resetOwed.current = { result };\n else snapshot();\n\n setErrors({});\n setSucceeded(true);\n setRecentlySucceeded(true);\n\n clearTimeout(recentTimer.current);\n recentTimer.current = setTimeout(\n () => setRecentlySucceeded(false),\n 2_000,\n );\n\n if (!resetOnSuccess) onSuccess?.(result);\n } catch (err) {\n // A redirect no longer arrives here - callServer resolves after\n // performing it - but an action called through something older\n // than that still may.\n if (err instanceof ServerRedirectError) return;\n\n if (err instanceof ServerValidationError) {\n setErrors(err.errors);\n onError?.(err.errors);\n } else if (err instanceof ActionRefusedError) {\n // A backend turned a generated stub down: its message, written for\n // the person asking, is the form's error.\n setErrors({ \"\": [err.message] });\n setRefusal(null);\n onError?.({}, err);\n } else if (err instanceof ServerDumpError) {\n // Dump overlay is already shown — silently swallow\n } else if (onError) {\n // Not rethrown. A rejected action never settles, and until it\n // settles React keeps the optimistic update on screen — so an\n // unexpected failure left the row showing as though the write had\n // worked. Settling is what takes it back.\n onError({}, err);\n } else {\n // Nothing is handling it, and swallowing here would lose it\n // entirely — the reason this used to rethrow.\n console.error(\"[rsc-kit] form submit failed\", err);\n }\n }\n });\n },\n [\n action,\n isGetForm,\n method,\n replace,\n preserveScroll,\n resetOnSuccess,\n store,\n schema,\n transform,\n optimistic,\n onSubmit,\n onSuccess,\n onError,\n ],\n );\n\n const field = useCallback(\n <K extends keyof T & string>(name: K): FieldBinding<T[K]> => {\n // Recorded during render, deliberately: this is how the form knows which\n // values it is the one displaying. Idempotent, so a double render in\n // development records the same name twice and means the same thing.\n readHere.current.add(name);\n\n return {\n name,\n value: (store.get(name) ?? \"\") as T[K],\n onChange: (next: unknown) => {\n const value =\n typeof next === \"object\" && next !== null && \"target\" in next\n ? (next as { target: { value: string } }).target.value\n : next;\n\n store.set(name, value);\n },\n onBlur: () => void touch(name),\n };\n },\n [store, touch],\n );\n\n\n // Stable, so a subscriber below does not re-render because this one did.\n const storeContext = useMemo(() => ({ store, touch }), [store, touch]);\n\n const formStatus: FormRenderProps<T, RefusalOf<A>, FieldNameOf<T, A, F>> = {\n pending: isPending,\n data: currentData,\n get dirty() {\n dirtyRead.current = true;\n\n return dirty;\n },\n succeeded,\n recentlySucceeded,\n field,\n error,\n formError: errors[\"\"]?.[0],\n formRefusal: (refusal && errors[\"\"] === refusal.for ? refusal.data : undefined) as RefusalOf<A> | undefined,\n clearErrors,\n reset: resetForm,\n };\n\n return (\n <FormStoreContext.Provider value={storeContext}>\n <FormStatusContext.Provider value={formStatus as FormRenderProps}>\n <form\n ref={attachForm}\n // On the element as well as in the handler, which is what makes this\n // work before hydration. React emits a form a browser can submit on its\n // own for a server action, and an ordinary action/method pair for a\n // url — so a submit that happens before the javascript arrives still\n // reaches the server.\n //\n // The two do not fight: handleSubmit calls preventDefault() first, and\n // React does not run a form action when the submit event was cancelled.\n // So the enhanced path wins whenever there is one, and the native path\n // is what is left when there is not.\n action={(bindable ? formAction : action) as never}\n // Only for a url. React sets the method itself for a server action, and\n // passing one alongside is what it warns about.\n method={isGetForm ? method : undefined}\n onSubmit={handleSubmit}\n // Every keystroke and every toggle, from any control in the form,\n // uncontrolled ones included: React's onInput here is the bubbling\n // `input` event. A caller's own handler still runs.\n onInput={(event) => {\n rest.onInput?.(event);\n measureDirty();\n }}\n onChange={(event) => {\n rest.onChange?.(event);\n measureDirty();\n }}\n // On the form, not only on the bound fields. `focusout` bubbles where\n // `blur` does not, so React's onBlur here sees every control that was\n // left — including the uncontrolled ones, which are most of them and\n // would otherwise never be marked touched at all.\n onBlur={(event) => {\n const target = event.target as unknown as {\n name?: string;\n value?: string;\n };\n const name = target.name;\n\n if (!name) return;\n\n // Leaving a field is the moment to check it; leaving the form is\n // not the same moment. Focus going to nothing, or to something\n // outside the form, is a click on the page - most often a dialog\n // closing - and an error painted into a dialog as it animates out\n // reads as a submit that nobody made. An empty field left that way\n // is not checked at all. One with something in it is, but only\n // once the dust settles: if the form is gone or hidden by then, it\n // was a dialog closing, and nobody is there to read the error.\n const left = event.relatedTarget as Node | null;\n const stillInForm = !!left && !!formRef.current?.contains(left);\n\n if (stillInForm) {\n void touch(name);\n\n return;\n }\n\n if (!target.value) return;\n\n setTimeout(() => {\n const form = formRef.current;\n\n if (\n !form ||\n !form.isConnected ||\n form.getClientRects().length === 0\n )\n return;\n // A submit in flight is not a dialog closing, and its answer is\n // the verdict on every field. On iOS a tap on the submit button\n // does not focus it, so the last field's blur arrives here as\n // \"left the form\" - and by now the fields may be disabled for\n // the pending submit, missing from its data, and judged absent:\n // \"last name is required\" flashed on the way to the next step.\n if (pendingRef.current) return;\n // Nor a field disabled by now, for the same reason: its value is\n // not in the form's data, so it would always read as missing.\n if ((event.target as { disabled?: boolean }).disabled) return;\n if (\n form.closest(\n \"[hidden], [aria-hidden='true'], [data-ending-style], [data-closed]\",\n )\n )\n return;\n\n void touch(name);\n }, LEAVE_FORM_SETTLE_MS);\n }}\n onMouseEnter={prefetch === \"hover\" ? doPrefetch : undefined}\n data-pending={isPending ? \"\" : undefined}\n {...rest}\n >\n {typeof children === \"function\" ? children(formStatus) : children}\n </form>\n </FormStatusContext.Provider>\n </FormStoreContext.Provider>\n );\n}\n\n// Also by name, because both spellings are in use: `import Form` and\n// `import { Form }`. This was a re-export of \"./Form\" — from inside Form.tsx,\n// so the module named itself. It survived on the bundler tolerating a circular\n// self-reference, left over from when a separate barrel re-exported a\n// FormComponent.tsx that a case-insensitive filesystem would not let be called\n// Form.ts. There is one file now, and it can just export what it declares.\nexport { Form };\n"]}
|
|
@@ -4,7 +4,10 @@ export interface RouteErrorProps {
|
|
|
4
4
|
error: Error & {
|
|
5
5
|
digest?: string;
|
|
6
6
|
};
|
|
7
|
-
/**
|
|
7
|
+
/**
|
|
8
|
+
* Ask the server for the page again and render what it says now. For a
|
|
9
|
+
* failure that might not happen twice.
|
|
10
|
+
*/
|
|
8
11
|
reset: () => void;
|
|
9
12
|
}
|
|
10
13
|
interface Props {
|
|
@@ -35,6 +38,7 @@ export declare class RouteErrorBoundary extends Component<Props, State> {
|
|
|
35
38
|
componentDidCatch(error: Error & {
|
|
36
39
|
digest?: string;
|
|
37
40
|
}): void;
|
|
41
|
+
retry: () => void;
|
|
38
42
|
render(): ReactNode;
|
|
39
43
|
}
|
|
40
44
|
export {};
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
// One of these wraps each segment that has an error.tsx above it, innermost
|
|
10
10
|
// first, so the nearest file to the failure is the one that answers — the same
|
|
11
11
|
// rule loading.tsx follows.
|
|
12
|
-
import { Component, createElement } from 'react';
|
|
12
|
+
import { Component, createElement, startTransition } from 'react';
|
|
13
13
|
import { parseRedirectDigest } from '../redirectDigest.js';
|
|
14
14
|
import { isNotFoundDigest } from '../notFound.js';
|
|
15
15
|
export class RouteErrorBoundary extends Component {
|
|
@@ -44,14 +44,26 @@ export class RouteErrorBoundary extends Component {
|
|
|
44
44
|
// nothing in the console for whoever has to find the cause.
|
|
45
45
|
console.error(error);
|
|
46
46
|
}
|
|
47
|
+
// Redrawing the children alone redrew the rows that had already failed: a
|
|
48
|
+
// payload's error is in the payload, so "Try again" sent nothing and showed
|
|
49
|
+
// the error again, and a page could never recover from a service that was
|
|
50
|
+
// down for a moment. Every boundary sits inside the page, below the layouts,
|
|
51
|
+
// which is what refresh() asks the server for again. The error is cleared
|
|
52
|
+
// in the same transition as the new page, so the old rows are never
|
|
53
|
+
// redrawn on the way. A refresh that fails clears it too: the page throws
|
|
54
|
+
// again, and the error is what is shown.
|
|
55
|
+
retry = () => {
|
|
56
|
+
const refresh = window.__rsc_refresh;
|
|
57
|
+
startTransition(async () => {
|
|
58
|
+
await refresh?.().catch(() => { });
|
|
59
|
+
startTransition(() => this.setState({ error: null }));
|
|
60
|
+
});
|
|
61
|
+
};
|
|
47
62
|
render() {
|
|
48
63
|
const { error } = this.state;
|
|
49
64
|
if (!error)
|
|
50
65
|
return this.props.children;
|
|
51
|
-
return createElement(this.props.fallback, {
|
|
52
|
-
error,
|
|
53
|
-
reset: () => this.setState({ error: null }),
|
|
54
|
-
});
|
|
66
|
+
return createElement(this.props.fallback, { error, reset: this.retry });
|
|
55
67
|
}
|
|
56
68
|
}
|
|
57
69
|
//# sourceMappingURL=RouteErrorBoundary.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RouteErrorBoundary.js","sourceRoot":"","sources":["../../src/js/RouteErrorBoundary.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAA;AAEZ,kDAAkD;AAClD,EAAE;AACF,+EAA+E;AAC/E,8EAA8E;AAC9E,2EAA2E;AAC3E,SAAS;AACT,EAAE;AACF,4EAA4E;AAC5E,+EAA+E;AAC/E,4BAA4B;AAE5B,OAAO,EAAE,SAAS,EAAE,aAAa,EAAkB,MAAM,OAAO,CAAA;
|
|
1
|
+
{"version":3,"file":"RouteErrorBoundary.js","sourceRoot":"","sources":["../../src/js/RouteErrorBoundary.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAA;AAEZ,kDAAkD;AAClD,EAAE;AACF,+EAA+E;AAC/E,8EAA8E;AAC9E,2EAA2E;AAC3E,SAAS;AACT,EAAE;AACF,4EAA4E;AAC5E,+EAA+E;AAC/E,4BAA4B;AAE5B,OAAO,EAAE,SAAS,EAAE,aAAa,EAAE,eAAe,EAAkB,MAAM,OAAO,CAAA;AACjF,OAAO,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAA;AAC1D,OAAO,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAA;AA+BjD,MAAM,OAAO,kBAAmB,SAAQ,SAAuB;IAC7D,KAAK,GAAU,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE,EAAE,CAAA;IAExC,MAAM,CAAC,wBAAwB,CAAC,KAAkC;QAChE,yEAAyE;QACzE,yEAAyE;QACzE,0EAA0E;QAC1E,kEAAkE;QAClE,IAAI,mBAAmB,CAAC,KAAK,EAAE,MAAM,CAAC,IAAI,gBAAgB,CAAC,KAAK,EAAE,MAAM,CAAC;YAAE,OAAO,IAAI,CAAA;QAEtF,OAAO,EAAE,KAAK,EAAE,CAAA;IAClB,CAAC;IAED,MAAM,CAAC,wBAAwB,CAAC,KAAY,EAAE,KAAY;QACxD,2EAA2E;QAC3E,2EAA2E;QAC3E,uCAAuC;QACvC,IAAI,KAAK,CAAC,KAAK,IAAI,KAAK,CAAC,IAAI,KAAK,KAAK,CAAC,QAAQ;YAAE,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,CAAC,QAAQ,EAAE,CAAA;QAC9F,IAAI,KAAK,CAAC,IAAI,KAAK,KAAK,CAAC,QAAQ;YAAE,OAAO,EAAE,IAAI,EAAE,KAAK,CAAC,QAAQ,EAAE,CAAA;QAElE,OAAO,IAAI,CAAA;IACb,CAAC;IAED,iBAAiB,CAAC,KAAkC;QAClD,0EAA0E;QAC1E,wEAAwE;QACxE,sEAAsE;QACtE,wDAAwD;QACxD,IAAI,mBAAmB,CAAC,KAAK,EAAE,MAAM,CAAC,IAAI,gBAAgB,CAAC,KAAK,EAAE,MAAM,CAAC;YAAE,MAAM,KAAK,CAAA;QAEtF,0EAA0E;QAC1E,4DAA4D;QAC5D,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,CAAA;IACtB,CAAC;IAED,0EAA0E;IAC1E,4EAA4E;IAC5E,0EAA0E;IAC1E,6EAA6E;IAC7E,0EAA0E;IAC1E,oEAAoE;IACpE,0EAA0E;IAC1E,yCAAyC;IACzC,KAAK,GAAG,GAAS,EAAE;QACjB,MAAM,OAAO,GAAI,MAAkD,CAAC,aAAa,CAAA;QAEjF,eAAe,CAAC,KAAK,IAAI,EAAE;YACzB,MAAM,OAAO,EAAE,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAA;YACjC,eAAe,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,CAAA;QACvD,CAAC,CAAC,CAAA;IACJ,CAAC,CAAA;IAED,MAAM;QACJ,MAAM,EAAE,KAAK,EAAE,GAAG,IAAI,CAAC,KAAK,CAAA;QAE5B,IAAI,CAAC,KAAK;YAAE,OAAO,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAA;QAEtC,OAAO,aAAa,CAAC,IAAI,CAAC,KAAK,CAAC,QAAQ,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,CAAC,CAAA;IACzE,CAAC;CACF","sourcesContent":["'use client'\n\n// The boundary an `error.tsx` is rendered inside.\n//\n// A class, because catching a render error is the one thing React still has no\n// hook for. It is a CLIENT component and has to be: a server component cannot\n// catch what happens in the browser, and `reset` is a callback the browser\n// calls.\n//\n// One of these wraps each segment that has an error.tsx above it, innermost\n// first, so the nearest file to the failure is the one that answers — the same\n// rule loading.tsx follows.\n\nimport { Component, createElement, startTransition, type ReactNode } from 'react'\nimport { parseRedirectDigest } from '../redirectDigest.js'\nimport { isNotFoundDigest } from '../notFound.js'\n\nexport interface RouteErrorProps {\n /** What was thrown. In production React replaces the message with a digest. */\n error: Error & { digest?: string }\n /**\n * Ask the server for the page again and render what it says now. For a\n * failure that might not happen twice.\n */\n reset: () => void\n}\n\ninterface Props {\n fallback: (props: RouteErrorProps) => ReactNode\n children?: ReactNode\n /**\n * Changes when the route does.\n *\n * Without it a boundary that caught an error stays caught: navigating away\n * from a broken page would leave its error on screen over the new one, and\n * the only way out would be a reload.\n */\n resetKey: string\n}\n\ninterface State {\n error: (Error & { digest?: string }) | null\n /** The route the error belongs to, so a new one clears it. */\n from: string\n}\n\nexport class RouteErrorBoundary extends Component<Props, State> {\n state: State = { error: null, from: '' }\n\n static getDerivedStateFromError(error: Error & { digest?: string }): Partial<State> | null {\n // A redirect decided inside a Suspense boundary arrives as an error with\n // the destination in its digest. It is not a failure for an error.tsx to\n // show - it is the page's answer - and the boundary that performs it sits\n // above this one. Left alone here; componentDidCatch hands it up.\n if (parseRedirectDigest(error?.digest) || isNotFoundDigest(error?.digest)) return null\n\n return { error }\n }\n\n static getDerivedStateFromProps(props: Props, state: State): Partial<State> | null {\n // A navigation clears it. Compared rather than keyed from outside, because\n // remounting the boundary on every navigation would throw away the subtree\n // it is wrapping along with the error.\n if (state.error && state.from !== props.resetKey) return { error: null, from: props.resetKey }\n if (state.from !== props.resetKey) return { from: props.resetKey }\n\n return null\n }\n\n componentDidCatch(error: Error & { digest?: string }): void {\n // Rethrown so the RedirectBoundary above turns it back into a navigation.\n // A missing page is the same: it is the page's answer, and the boundary\n // above asks for not-found.tsx - an error.tsx showing \"something went\n // wrong\" over a record that does not exist was the bug.\n if (parseRedirectDigest(error?.digest) || isNotFoundDigest(error?.digest)) throw error\n\n // Reported as well as rendered. A boundary that swallows the error leaves\n // nothing in the console for whoever has to find the cause.\n console.error(error)\n }\n\n // Redrawing the children alone redrew the rows that had already failed: a\n // payload's error is in the payload, so \"Try again\" sent nothing and showed\n // the error again, and a page could never recover from a service that was\n // down for a moment. Every boundary sits inside the page, below the layouts,\n // which is what refresh() asks the server for again. The error is cleared\n // in the same transition as the new page, so the old rows are never\n // redrawn on the way. A refresh that fails clears it too: the page throws\n // again, and the error is what is shown.\n retry = (): void => {\n const refresh = (window as { __rsc_refresh?: () => Promise<void> }).__rsc_refresh\n\n startTransition(async () => {\n await refresh?.().catch(() => {})\n startTransition(() => this.setState({ error: null }))\n })\n }\n\n render(): ReactNode {\n const { error } = this.state\n\n if (!error) return this.props.children\n\n return createElement(this.props.fallback, { error, reset: this.retry })\n }\n}\n"]}
|
|
@@ -367,12 +367,12 @@ export async function createViteRscApp(container = document, interceptEntries =
|
|
|
367
367
|
// Depth 0 is a whole document and replaces the root. Anything deeper is one
|
|
368
368
|
// segment: handing it to the boundary at that depth leaves the layouts above
|
|
369
369
|
// it mounted, which is the point of asking for a partial render at all.
|
|
370
|
-
setNavigateHandler((tree, key, segmentDepth, inPlaceOf) => {
|
|
370
|
+
setNavigateHandler((tree, key, segmentDepth, inPlaceOf, keepsPrevious) => {
|
|
371
371
|
const newTree = tree;
|
|
372
372
|
// From here on the boundary animates; the seed commit before this did not.
|
|
373
373
|
noteNavigation();
|
|
374
374
|
if (segmentDepth > 0) {
|
|
375
|
-
setSegment(segmentDepth, key, newTree, inPlaceOf);
|
|
375
|
+
setSegment(segmentDepth, key, newTree, inPlaceOf, keepsPrevious);
|
|
376
376
|
return;
|
|
377
377
|
}
|
|
378
378
|
clearSegments();
|