react-form-action 2.5.0 → 2.5.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 CHANGED
@@ -8,11 +8,13 @@ End-to-end typesafe success, error & validation state control for Next.js form a
8
8
 
9
9
  - ✅ Provides envelope objects with `"initial" | "invalid" | "success" | "failure"` response types.
10
10
  - ✅ Define generic payload for each of the response type.
11
+ - ✅ Bind action arguments.
11
12
 
12
13
  **tRPC-like Form Action builder**
13
14
 
14
15
  - ✅ Define payload schema with the `.input(zodSchema)` to validate the `formData`
15
16
  - ✅ Reuse business logic with the `.use(middleware)` method.
17
+ - ✅ Define bindable arguments with the `.args([])` method.
16
18
  - ✅ Reuse error handling with the `.error(handler)`.
17
19
 
18
20
  **React Context access with the `<Action action={myFormAction} />` component**
@@ -183,6 +185,46 @@ export const signUp = authAction
183
185
  });
184
186
  ```
185
187
 
188
+ #### Args binding
189
+
190
+ The `formAction` builder supports action arguments binding:
191
+
192
+ ```ts
193
+ // app/update-user/[userId]/action.tsx
194
+ import { formAction } from "react-form-action";
195
+
196
+ export const updateUser = formAction
197
+ .args([z.string().uuid()])
198
+ .run(async ({ args: [userId] }) => {
199
+ return userId;
200
+ // ^? string
201
+ });
202
+ ```
203
+
204
+ ```tsx
205
+ // app/update-user/[userId]/page.tsx
206
+ import { Action } from "react-form-action/client";
207
+
208
+ import { updateUser } from "./action";
209
+ import { UpdateUserForm } from "./form";
210
+
211
+ export default function Page({
212
+ params,
213
+ }: {
214
+ params: Promise<{ userId: string }>;
215
+ }) {
216
+ const { userId } = await params;
217
+
218
+ const action = updateUser.bind(null, userId);
219
+
220
+ return (
221
+ <Action action={action} initialData="">
222
+ <SubscribeForm />
223
+ </Action>
224
+ );
225
+ }
226
+ ```
227
+
186
228
  ### Action Creator
187
229
 
188
230
  Low-level action creator, which provides the `success`, `failure` and `invalid` envelope constructors. With the `createFormAction` you must handle the native `FormData` by yourself.
@@ -0,0 +1 @@
1
+ function u(a){return{type:"initial",data:a,error:null,validationError:null}}function d(a){function t(r){return{type:"success",data:r,error:null,validationError:null}}function o(r){return{type:"failure",data:null,error:r,validationError:null}}function n(r){return{type:"invalid",data:null,error:null,validationError:r}}return(...r)=>{let e=r.pop(),i=r.pop(),l=[...r];return a({success:t,failure:o,invalid:n},...l)(i,e)}}export{u as a,d as b};
package/dist/client.d.mts CHANGED
@@ -1,6 +1,6 @@
1
1
  import * as React from 'react';
2
2
  import React__default, { PropsWithChildren, JSX } from 'react';
3
- import { F as FormAction, A as ActionState, I as InitialState, a as InvalidState, b as FailureState, S as SuccessState } from './createFormAction-DkNsdAwU.mjs';
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 { ZodFormattedError } from 'zod';
5
5
  import { RenderProp, RP } from 'react-render-prop-type';
6
6
 
package/dist/client.mjs CHANGED
@@ -1 +1 @@
1
- "use client";import{a as m}from"./chunk-MQGUMLBX.mjs";import y from"react";import{createContext as P,use as S}from"react";import{useActionState as F}from"react";var p={isInitial:!1,isInvalid:!1,isFailure:!1,isSuccess:!1},u=P(null);function a(o){let t=S(u);if(!t)throw new Error("ActionContext must be initialized before use. Is your useActionContext hook wrapped with an <Action> Component?");return t}function I({children:o,action:t,initialData:i,permalink:e}){let[r,n,s]=F(t,m(i),e),l=r.type==="initial"?{...r,...p,action:n,isPending:s,isInitial:!0}:r.type==="invalid"?{...r,...p,action:n,isPending:s,isInvalid:!0}:r.type==="failure"?{...r,...p,action:n,isPending:s,isFailure:!0}:{...r,...p,action:n,isPending:s,isSuccess:!0};return y.createElement(u,{value:l},o)}import A,{startTransition as C}from"react";function V({autoReset:o=!1,...t}){let{action:i}=a();return A.createElement("form",{...o?{action:i}:{onSubmit:r=>{r.preventDefault();let n=r.currentTarget;C(()=>{i(new FormData(n))})}},...t})}import c from"react";import f from"react";var h=".",d=Object.freeze({_errors:Object.freeze([])});function E({errors:o,name:t,children:i=({error:e})=>f.createElement(f.Fragment,null,e)}){if(t.length===0)return i({name:t,error:o._errors[0],errors:o._errors});let e=t.split(h),r=o;for(;e.length;){let n=e.shift();r=r[n]??d}return i({name:t,error:r._errors[0],errors:r._errors})}function $(o){function t({name:e,children:r}){let{isInvalid:n,validationError:s}=a(o);return c.createElement(E,{errors:s??d,name:e},r??(({error:x})=>n&&c.createElement(c.Fragment,null,x)))}function i({children:e}){let{isSuccess:r,data:n}=a(o);return typeof e=="function"?e(r?{isSuccess:r,data:n}:{isSuccess:r,data:n}):r&&e}return{FieldError:t,Success:i}}function X({children:o}){let{isPending:t}=a();return typeof o=="function"?o({isPending:t}):t&&o}export{I as Action,V as Form,X as Pending,E as ZodFieldError,$ as createComponents,d as noError,a as useActionContext};
1
+ "use client";import{a as m}from"./chunk-LPB4R2UB.mjs";import y from"react";import{createContext as P,use as S}from"react";import{useActionState as F}from"react";var p={isInitial:!1,isInvalid:!1,isFailure:!1,isSuccess:!1},u=P(null);function a(o){let t=S(u);if(!t)throw new Error("ActionContext must be initialized before use. Is your useActionContext hook wrapped with an <Action> Component?");return t}function I({children:o,action:t,initialData:i,permalink:e}){let[r,n,s]=F(t,m(i),e),l=r.type==="initial"?{...r,...p,action:n,isPending:s,isInitial:!0}:r.type==="invalid"?{...r,...p,action:n,isPending:s,isInvalid:!0}:r.type==="failure"?{...r,...p,action:n,isPending:s,isFailure:!0}:{...r,...p,action:n,isPending:s,isSuccess:!0};return y.createElement(u,{value:l},o)}import A,{startTransition as C}from"react";function V({autoReset:o=!1,...t}){let{action:i}=a();return A.createElement("form",{...o?{action:i}:{onSubmit:r=>{r.preventDefault();let n=r.currentTarget;C(()=>{i(new FormData(n))})}},...t})}import c from"react";import f from"react";var h=".",d=Object.freeze({_errors:Object.freeze([])});function E({errors:o,name:t,children:i=({error:e})=>f.createElement(f.Fragment,null,e)}){if(t.length===0)return i({name:t,error:o._errors[0],errors:o._errors});let e=t.split(h),r=o;for(;e.length;){let n=e.shift();r=r[n]??d}return i({name:t,error:r._errors[0],errors:r._errors})}function $(o){function t({name:e,children:r}){let{isInvalid:n,validationError:s}=a(o);return c.createElement(E,{errors:s??d,name:e},r??(({error:x})=>n&&c.createElement(c.Fragment,null,x)))}function i({children:e}){let{isSuccess:r,data:n}=a(o);return typeof e=="function"?e(r?{isSuccess:r,data:n}:{isSuccess:r,data:n}):r&&e}return{FieldError:t,Success:i}}function X({children:o}){let{isPending:t}=a();return typeof o=="function"?o({isPending:t}):t&&o}export{I as Action,V as Form,X as Pending,E as ZodFieldError,$ as createComponents,d as noError,a as useActionContext};
@@ -22,11 +22,7 @@ type SuccessState<T> = {
22
22
  error: null;
23
23
  validationError: null;
24
24
  };
25
- type Flatten<T> = Identity<{
26
- [K in keyof T]: T[K];
27
- }>;
28
- type Identity<T> = T;
29
- type ActionState<Data, Error, ValidationError = Record<string, never>> = Flatten<InitialState<Data> | InvalidState<ValidationError> | FailureState<Error> | SuccessState<Data>>;
25
+ type ActionState<Data, Error, ValidationError = Record<string, never>> = InitialState<Data> | InvalidState<ValidationError> | FailureState<Error> | SuccessState<Data>;
30
26
  type FormAction<Data, Error = Data, ValidationError = Record<string, never>, Payload = FormData, Arguments extends unknown[] = []> = (...args: [
31
27
  ...Arguments,
32
28
  state: ActionState<Data, Error, ValidationError>,
package/dist/index.d.mts CHANGED
@@ -1,5 +1,5 @@
1
- import { A as ActionState, a as InvalidState, b as FailureState, S as SuccessState } from './createFormAction-DkNsdAwU.mjs';
2
- export { F as FormAction, I as InitialState, c as createFormAction, i as initial } from './createFormAction-DkNsdAwU.mjs';
1
+ import { A as ActionState, a as InvalidState, b as FailureState, S as SuccessState } from './createFormAction-DjhozgiG.mjs';
2
+ export { F as FormAction, I as InitialState, c as createFormAction, i as initial } from './createFormAction-DjhozgiG.mjs';
3
3
  import { z, ZodTypeAny, AnyZodTuple, ZodTuple, ZodType, ZodObject, ZodRawShape, objectUtil, ZodSchema, ZodEffects } from 'zod';
4
4
 
5
5
  declare const emptyInput: unique symbol;
@@ -39,9 +39,9 @@ type FormActionBuilder<Schema extends ZodTypeAny | EmptyInput, Err = Error, Cont
39
39
  */
40
40
  run: Schema extends ZodTypeAny ? <Data>(action: SchemaAction<Data, Flatten<Context>, Args, Schema>) => (...args: [
41
41
  ...z.infer<Args>,
42
- state: ActionState<Data, Error, z.inferFormattedError<Schema> | z.inferFormattedError<Args>>,
42
+ state: ActionState<Data, Error, z.inferFormattedError<Schema> & z.inferFormattedError<Args>>,
43
43
  payload: FormData
44
- ]) => Promise<Flatten<InvalidState<z.inferFormattedError<Schema> | z.inferFormattedError<Args>> | FailureState<Err> | SuccessState<Data>>> : <Data>(action: Action<Data, Flatten<Context>, Args>) => (...args: [
44
+ ]) => Promise<Flatten<InvalidState<z.inferFormattedError<Schema> & z.inferFormattedError<Args>> | FailureState<Err> | SuccessState<Data>>> : <Data>(action: Action<Data, Flatten<Context>, Args>) => (...args: [
45
45
  ...z.infer<Args>,
46
46
  state: ActionState<Data, Error, z.inferFormattedError<Args>>,
47
47
  payload: FormData
package/dist/index.mjs CHANGED
@@ -1 +1 @@
1
- import{a as w,b as y}from"./chunk-MQGUMLBX.mjs";import{z as S,ZodFirstPartyTypeKind as h}from"zod";import{zfd as C}from"zod-form-data";var p=Symbol();function c(e,s=[],o,a){async function A(t){let r={formData:t};for(let d of s){let i=await d({ctx:r});r={...r,...i}}return r}return{args(t){return c(e,s,o,S.tuple(t))},input(t){if(e===p)return c(t,s,o,a);if(e._def.effect)throw new Error("Previous input is not augmentable because it contains an effect.");if(t._def.effect)throw new Error("Your input contains effect which prevents merging it with the previous inputs.");if(e._def.typeName===h.ZodObject){let r=e.merge(t);return c(r,s)}else throw Error("Merging inputs works only for object schemas without effects.")},use(t){return c(e,[...s,t],o,a)},error(t){return c(e,s,t,a)},run:e===p?t=>y(({success:r,failure:d,invalid:i},...u)=>async(l,E)=>{let f=await A(E);if(a){let n=a.safeParse(u);if(!n.success){let x=n.error.flatten();return i(x.fieldErrors)}}try{return r(await t({args:u,ctx:f}))}catch(n){if(o)return d(await o({error:n,ctx:f}));throw n}}):e===p?void 0:t=>y(({success:r,failure:d,invalid:i},...u)=>{let l=C.formData(e);return async(E,f)=>{let n=await A(f);if(a){let m=a.safeParse(u);if(!m.success)return i(m.error.format())}let x=l.safeParse(f);if(!x.success)return i(x.error.format());let g=x.data;try{return r(await t({args:u,input:g,ctx:n}))}catch(m){if(o)return d(await o({error:m,ctx:n}));throw m}}})}}var N=c(p);export{y as createFormAction,N as formAction,w as initial};
1
+ import{a as w,b as y}from"./chunk-LPB4R2UB.mjs";import{z as S,ZodFirstPartyTypeKind as h}from"zod";import{zfd as C}from"zod-form-data";var x=Symbol();function c(e,s=[],o,a){async function A(t){let r={formData:t};for(let d of s){let i=await d({ctx:r});r={...r,...i}}return r}return{args(t){return c(e,s,o,S.tuple(t))},input(t){if(e===x)return c(t,s,o,a);if(e._def.effect)throw new Error("Previous input is not augmentable because it contains an effect.");if(t._def.effect)throw new Error("Your input contains effect which prevents merging it with the previous inputs.");if(e._def.typeName===h.ZodObject){let r=e.merge(t);return c(r,s)}else throw Error("Merging inputs works only for object schemas without effects.")},use(t){return c(e,[...s,t],o,a)},error(t){return c(e,s,t,a)},run:e===x?t=>y(({success:r,failure:d,invalid:i},...u)=>async(l,E)=>{let m=await A(E);if(a){let n=a.safeParse(u);if(!n.success)return i(n.error.format())}try{return r(await t({args:u,ctx:m}))}catch(n){if(o)return d(await o({error:n,ctx:m}));throw n}}):e===x?void 0:t=>y(({success:r,failure:d,invalid:i},...u)=>{let l=C.formData(e);return async(E,m)=>{let n=await A(m);if(a){let f=a.safeParse(u);if(!f.success)return i(f.error.format())}let p=l.safeParse(m);if(!p.success)return i(p.error.format());let g=p.data;try{return r(await t({args:u,input:g,ctx:n}))}catch(f){if(o)return d(await o({error:f,ctx:n}));throw f}}})}}var k=c(x);export{y as createFormAction,k as formAction,w as initial};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-form-action",
3
- "version": "2.5.0",
3
+ "version": "2.5.1",
4
4
  "description": "State management helpers for the react form actions.",
5
5
  "repository": {
6
6
  "type": "git",
@@ -1 +0,0 @@
1
- function d(a){return{type:"initial",data:a,error:null,validationError:null}}function u(a){function t(r){return{type:"success",data:r,error:null,validationError:null}}function e(r){return{type:"failure",data:null,error:r,validationError:null}}function o(r){return{type:"invalid",data:null,error:null,validationError:r}}return(...r)=>{let[n,i,...l]=r.reverse();return a({success:t,failure:e,invalid:o},...l)(i,n)}}export{d as a,u as b};