react-form-action 2.8.0 → 2.9.1
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/README.md +14 -18
- package/dist/client.d.mts +1 -1
- package/dist/client.mjs +1 -1
- package/dist/index.d.mts +22 -22
- package/dist/index.mjs +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -17,10 +17,11 @@ End-to-end typesafe success, error & validation state control for Next.js form a
|
|
|
17
17
|
- ✅ Define bindable arguments with the `.args([])` method.
|
|
18
18
|
- ✅ Reuse error handling with the `.error(handler)`.
|
|
19
19
|
|
|
20
|
-
**React Context access with the `<Action action={myFormAction} />` component**
|
|
20
|
+
**React Context access with the `<Action action={myFormAction} args={[...]} />` component**
|
|
21
21
|
|
|
22
|
-
- ✅ The `useActionState()` accessible via the `useActionContext()` hook.
|
|
22
|
+
- ✅ The `React.useActionState()` accessible via the `useActionContext()` hook.
|
|
23
23
|
- ✅ Computes progress flags like `isInvalid`, `isSuccess` based on the envelope type.
|
|
24
|
+
- ✅ Binds the action with the arguments from the _args_ prop.
|
|
24
25
|
|
|
25
26
|
**Context-bound `<Form />` component**
|
|
26
27
|
|
|
@@ -193,16 +194,17 @@ export const signUp = authAction
|
|
|
193
194
|
The `formAction` builder supports action arguments binding:
|
|
194
195
|
|
|
195
196
|
```ts
|
|
196
|
-
// app/[locale]/update-user/[userId]/action.tsx
|
|
197
197
|
import { formAction } from "react-form-action";
|
|
198
198
|
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
199
|
+
const i18nAction = formAction.args([z.enum("fr", "en")]);
|
|
200
|
+
|
|
201
|
+
export const updateUser = i18nAction
|
|
202
|
+
.args([z.string().uuid()])
|
|
203
|
+
.run(async ({ args: [_, userId] }) => {
|
|
204
|
+
// ^? ["fr" | "en", string]
|
|
205
|
+
// ...
|
|
204
206
|
})
|
|
205
|
-
.error(({ args: [
|
|
207
|
+
.error(({ args: [locale] }) => {
|
|
206
208
|
return locale === "fr"
|
|
207
209
|
? "Échec de la mise à jour de l'utilisateur"
|
|
208
210
|
: "Failed to update user";
|
|
@@ -210,26 +212,20 @@ export const updateUser = formAction
|
|
|
210
212
|
```
|
|
211
213
|
|
|
212
214
|
```tsx
|
|
213
|
-
// app/[locale]/update-user/[userId]/page.tsx
|
|
214
215
|
import { Action } from "react-form-action/client";
|
|
216
|
+
import { locale } from "next/root-params";
|
|
215
217
|
|
|
216
|
-
import { locale as localeParam } from "next/root-params";
|
|
217
218
|
import { updateUser } from "./action";
|
|
218
219
|
import { UpdateUserForm } from "./form";
|
|
219
220
|
|
|
220
221
|
export default function Page({
|
|
221
222
|
params,
|
|
222
223
|
}: PageProps<"/[locale]/update-user/[userId]">) {
|
|
223
|
-
const locale = await localeParam();
|
|
224
224
|
const { userId } = await params;
|
|
225
225
|
|
|
226
226
|
return (
|
|
227
|
-
<Action
|
|
228
|
-
|
|
229
|
-
args={[userId, await localeParam()]}
|
|
230
|
-
initialData=""
|
|
231
|
-
>
|
|
232
|
-
<SubscribeForm />
|
|
227
|
+
<Action action={updateUser} args={[await locale(), userId]} initialData="">
|
|
228
|
+
<UpdateUserForm />
|
|
233
229
|
</Action>
|
|
234
230
|
);
|
|
235
231
|
}
|
package/dist/client.d.mts
CHANGED
|
@@ -3,7 +3,7 @@ import React__default, { PropsWithChildren, JSX } from 'react';
|
|
|
3
3
|
import { F as FormAction, A as ActionState, I as InitialState, a as InvalidState, b as FailureState, S as SuccessState } from './createFormAction-DjhozgiG.mjs';
|
|
4
4
|
import { $ZodErrorTree } from 'zod/v4/core';
|
|
5
5
|
|
|
6
|
-
type ActionProps<Data, Error, ValidationError, Arguments extends unknown[] = []> = PropsWithChildren<Arguments extends [unknown] ? {
|
|
6
|
+
type ActionProps<Data, Error, ValidationError, Arguments extends unknown[] = []> = PropsWithChildren<Arguments extends [unknown, ...unknown[]] ? {
|
|
7
7
|
action: FormAction<Data, Error, ValidationError, FormData, Arguments>;
|
|
8
8
|
args: Arguments;
|
|
9
9
|
initialData: Data;
|
package/dist/client.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use client";import{a as f}from"./chunk-LPB4R2UB.mjs";import S from"react";import{useActionState as F,createContext as P,use as y}from"react";var c={isInitial:!1,isInvalid:!1,isFailure:!1,isSuccess:!1},E=P(null);function s(e){let t=y(E);if(!t)throw new Error("ActionContext must be initialized before use. Is your useActionContext hook wrapped with an <Action> Component?");return t}function v({children:e,action:t,initialData:a,args:i,permalink:r}){let o=i?t.bind(null,...i):t,[n,l,d]=F(o,f(a),r),u=n.type==="initial"?{...n,...c,action:l,isPending:d,isInitial:!0}:n.type==="invalid"?{...n,...c,action:l,isPending:d,isInvalid:!0}:n.type==="failure"?{...n,...c,action:l,isPending:d,isFailure:!0}:{...n,...c,action:l,isPending:d,isSuccess:!0};return S.createElement(E,{value:u},e)}import h,{startTransition as g}from"react";function I({autoReset:e=!1,...t}){let{action:a}=s();return h.createElement("form",{...e?{action:a}:{onSubmit:r=>{r.preventDefault();let o=r.currentTarget;g(()=>{a(new FormData(o))})}},...t})}import m from"react";import x from"react";var
|
|
1
|
+
"use client";import{a as f}from"./chunk-LPB4R2UB.mjs";import S from"react";import{useActionState as F,createContext as P,use as y}from"react";var c={isInitial:!1,isInvalid:!1,isFailure:!1,isSuccess:!1},E=P(null);function s(e){let t=y(E);if(!t)throw new Error("ActionContext must be initialized before use. Is your useActionContext hook wrapped with an <Action> Component?");return t}function v({children:e,action:t,initialData:a,args:i,permalink:r}){let o=i?t.bind(null,...i):t,[n,l,d]=F(o,f(a),r),u=n.type==="initial"?{...n,...c,action:l,isPending:d,isInitial:!0}:n.type==="invalid"?{...n,...c,action:l,isPending:d,isInvalid:!0}:n.type==="failure"?{...n,...c,action:l,isPending:d,isFailure:!0}:{...n,...c,action:l,isPending:d,isSuccess:!0};return S.createElement(E,{value:u},e)}import h,{startTransition as g}from"react";function I({autoReset:e=!1,...t}){let{action:a}=s();return h.createElement("form",{...e?{action:a}:{onSubmit:r=>{r.preventDefault();let o=r.currentTarget;g(()=>{a(new FormData(o))})}},...t})}import m from"react";import x from"react";var k=".",p=Object.freeze({errors:Object.freeze([])});function A({errors:e,name:t,children:a=({error:i})=>x.createElement(x.Fragment,null,i)}){if(t.length===0)return a({name:t,error:e.errors[0],errors:e.errors});let i=t.split(k),r=e;for(;i.length;){let o=i.shift();if(!r.properties){r=p;break}r=r.properties[o]??p}return a({name:t,error:r.errors[0],errors:r.errors})}function J(e){function t({name:r,children:o}){let{isInvalid:n,validationError:l}=s(e);return m.createElement(A,{errors:l??p,name:r},o??(({error:u})=>n&&m.createElement(m.Fragment,null,u)))}function a({children:r}){let{isSuccess:o,data:n}=s(e);return typeof r=="function"?r(o?{isSuccess:o,data:n}:{isSuccess:o,data:n}):o&&r}function i({children:r}){let{isInvalid:o,validationError:n}=s(e);return typeof r=="function"?r(o?{isInvalid:o,validationError:n}:{isInvalid:o,validationError:n}):o&&r}return{FieldError:t,Success:a,Invalid:i}}function q({children:e}){let{isPending:t}=s();return typeof e=="function"?e({isPending:t}):t&&e}export{v as Action,I as Form,q as Pending,A as ZodFieldError,J as createComponents,p as noError,s as useActionContext};
|
package/dist/index.d.mts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { A as ActionState, a as InvalidState, b as FailureState, S as SuccessState } from './createFormAction-DjhozgiG.mjs';
|
|
2
2
|
export { F as FormAction, I as InitialState, c as createFormAction, i as initial } from './createFormAction-DjhozgiG.mjs';
|
|
3
|
-
import { ZodType, ZodTuple, ZodObject
|
|
4
|
-
import { $ZodShape, $ZodErrorTree } from 'zod/v4/core';
|
|
3
|
+
import { ZodType, z, ZodTuple, ZodObject } from 'zod/v4';
|
|
4
|
+
import { $ZodType, $ZodShape, $ZodErrorTree } from 'zod/v4/core';
|
|
5
5
|
|
|
6
6
|
declare const emptyInput: unique symbol;
|
|
7
7
|
type EmptyInput = typeof emptyInput;
|
|
@@ -9,44 +9,44 @@ type Flatten<T> = Identity<{
|
|
|
9
9
|
[K in keyof T]: T[K];
|
|
10
10
|
}>;
|
|
11
11
|
type Identity<T> = T;
|
|
12
|
-
type ErrorHandler<Context, Err, Args
|
|
12
|
+
type ErrorHandler<Context, Err, Args> = (params: {
|
|
13
13
|
error: unknown;
|
|
14
14
|
ctx: Context;
|
|
15
|
-
args:
|
|
15
|
+
args: Args;
|
|
16
16
|
}) => Promise<Err>;
|
|
17
17
|
type InitialContext = Record<"formData", FormData>;
|
|
18
18
|
/**
|
|
19
19
|
* Action without schema has no input.
|
|
20
20
|
*/
|
|
21
|
-
type Action<Data, Context, Args extends
|
|
22
|
-
args:
|
|
21
|
+
type Action<Data, Context, Args extends unknown[]> = (params: {
|
|
22
|
+
args: Args;
|
|
23
23
|
ctx: Context;
|
|
24
24
|
}) => Promise<Data>;
|
|
25
25
|
/**
|
|
26
26
|
* Action with schema will get parsed formData as the input.
|
|
27
27
|
*/
|
|
28
|
-
type SchemaAction<Data, Context, Args extends
|
|
29
|
-
args:
|
|
28
|
+
type SchemaAction<Data, Context, Args extends unknown[], Schema extends ZodType> = (params: {
|
|
29
|
+
args: Args;
|
|
30
30
|
ctx: Context;
|
|
31
|
-
input: z.
|
|
31
|
+
input: z.output<Schema>;
|
|
32
32
|
}) => Promise<Data>;
|
|
33
|
-
type FormActionBuilder<Schema extends ZodType | EmptyInput, TErr = unknown, Context = InitialContext,
|
|
34
|
-
args: <T extends [ZodType,
|
|
35
|
-
input: <T extends ZodObject>(newInput: T extends ZodObject ? T : "The schema output must be an object.") => FormActionBuilder<Schema extends ZodObject<infer O1 extends $ZodShape> ? T extends ZodObject<infer O2 extends $ZodShape> ? ZodObject<O1 & O2> : never : T, TErr, Context
|
|
33
|
+
type FormActionBuilder<Schema extends ZodType | EmptyInput, Args extends $ZodType[] = [], TErr = unknown, Context = InitialContext, PlainArgs extends unknown[] = z.output<ZodTuple<Args, null>>> = {
|
|
34
|
+
args: <T extends [$ZodType, ...$ZodType[]]>(args: T) => FormActionBuilder<Schema, [...Args, ...T], TErr, Context>;
|
|
35
|
+
input: <T extends ZodObject>(newInput: T extends ZodObject ? T : "The schema output must be an object.") => FormActionBuilder<Schema extends ZodObject<infer O1 extends $ZodShape> ? T extends ZodObject<infer O2 extends $ZodShape> ? ZodObject<O1 & O2> : never : T, Args, TErr, Context>;
|
|
36
36
|
/**
|
|
37
37
|
* A finishing call on the builder completing your action.
|
|
38
38
|
* @param action async function to execute. It will receive parsed formData as input, when the builder was initialized with a schema.
|
|
39
39
|
* @returns runnable server action exportable from a module.
|
|
40
40
|
*/
|
|
41
|
-
run: Schema extends ZodType ? <Data>(action: SchemaAction<Data, Flatten<Context>,
|
|
42
|
-
...
|
|
43
|
-
state: ActionState<Data, TErr, $ZodErrorTree<z.output<Schema>> & $ZodErrorTree<
|
|
41
|
+
run: Schema extends ZodType ? <Data>(action: SchemaAction<Data, Flatten<Context>, PlainArgs, Schema>) => (...args: [
|
|
42
|
+
...PlainArgs,
|
|
43
|
+
state: ActionState<Data, TErr, $ZodErrorTree<z.output<Schema>> & $ZodErrorTree<PlainArgs>>,
|
|
44
44
|
payload: FormData
|
|
45
|
-
]) => Promise<Flatten<InvalidState<$ZodErrorTree<z.output<Schema>> & $ZodErrorTree<
|
|
46
|
-
...
|
|
47
|
-
state: ActionState<Data, TErr, $ZodErrorTree<
|
|
45
|
+
]) => Promise<Flatten<InvalidState<$ZodErrorTree<z.output<Schema>> & $ZodErrorTree<PlainArgs>> | FailureState<TErr> | SuccessState<Data>>> : <Data>(action: Action<Data, Flatten<Context>, PlainArgs>) => (...args: [
|
|
46
|
+
...PlainArgs,
|
|
47
|
+
state: ActionState<Data, TErr, $ZodErrorTree<PlainArgs>>,
|
|
48
48
|
payload: FormData
|
|
49
|
-
]) => Promise<Flatten<InvalidState<$ZodErrorTree<
|
|
49
|
+
]) => Promise<Flatten<InvalidState<$ZodErrorTree<PlainArgs>> | FailureState<TErr> | SuccessState<Data>>>;
|
|
50
50
|
/**
|
|
51
51
|
* A chainable context enhancing helper.
|
|
52
52
|
* @param middleware A function which receives the current context, and returns an object which will be added to the context.
|
|
@@ -54,15 +54,15 @@ type FormActionBuilder<Schema extends ZodType | EmptyInput, TErr = unknown, Cont
|
|
|
54
54
|
*/
|
|
55
55
|
use: <NewContext extends Record<string, unknown>>(middleware: ({ ctx }: {
|
|
56
56
|
ctx: Context;
|
|
57
|
-
}) => Promise<NewContext>) => FormActionBuilder<Schema, TErr, Context & NewContext
|
|
57
|
+
}) => Promise<NewContext>) => FormActionBuilder<Schema, Args, TErr, Context & NewContext>;
|
|
58
58
|
/**
|
|
59
59
|
* A chainable error handler to handle errors thrown while running the action passed to .run().
|
|
60
60
|
* It does not receive errors thrown from the context/middleware.
|
|
61
61
|
* @param processError A function which receives action's errors.
|
|
62
62
|
* @returns FormActionBuilder
|
|
63
63
|
*/
|
|
64
|
-
error: <TErr>(processError: ErrorHandler<Context, TErr,
|
|
64
|
+
error: <TErr>(processError: ErrorHandler<Context, TErr, PlainArgs>) => FormActionBuilder<Schema, Args, TErr, Context>;
|
|
65
65
|
};
|
|
66
|
-
declare const formAction: FormActionBuilder<typeof emptyInput, unknown, InitialContext,
|
|
66
|
+
declare const formAction: FormActionBuilder<typeof emptyInput, [], unknown, InitialContext, []>;
|
|
67
67
|
|
|
68
68
|
export { ActionState, FailureState, InvalidState, SuccessState, formAction };
|
package/dist/index.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{a as
|
|
1
|
+
import{a as w,b as A}from"./chunk-LPB4R2UB.mjs";import{z as c}from"zod/v4";import{zfd as C}from"zod-form-data";var T=Symbol();function d(r,i=[],a,n){async function f(t){let e={formData:t};for(let p of i){let u=await p({ctx:e});e={...e,...u}}return e}return{args(t){let e=n?[...n,...t]:t;return d(r,i,a,e)},input(t){if(r===T)return d(t,i,a,n);if(r._zod.def.checks)throw new Error("Previous input is not augmentable because it contains an effect.");if(t._zod.def.checks)throw new Error("Your input contains effect which prevents merging it with the previous inputs.");if(r._zod.def.type==="object"){let e=c.object({...r.shape,...t.shape});return d(e,i)}else throw Error("Merging inputs works only for object schemas without effects.")},use(t){return d(r,[...i,t],a,n)},error(t){return d(r,i,t,n)},run:r===T?t=>A(({success:e,failure:p,invalid:u},...s)=>async(y,g)=>{let x=await f(g);if(n){let o=c.tuple(n).safeParse(s);if(!o.success)return u(c.treeifyError(o.error))}try{return e(await t({args:s,ctx:x}))}catch(o){if(a)return p(await a({args:s,error:o,ctx:x}));throw o}}):r===T?void 0:t=>A(({success:e,failure:p,invalid:u},...s)=>{let y=C.formData(r);return async(g,x)=>{let o=await f(x);if(n){let l=c.tuple(n).safeParse(s);if(!l.success)return u(c.treeifyError(l.error))}let m=y.safeParse(x);if(!m.success)return u(c.treeifyError(m.error));let E=m.data;try{return e(await t({args:s,input:E,ctx:o}))}catch(l){if(a)return p(await a({args:s,error:l,ctx:o}));throw l}}})}}var k=d(T);export{A as createFormAction,k as formAction,w as initial};
|