react-form-action 2.9.2 → 2.11.0

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
@@ -22,6 +22,7 @@ End-to-end typesafe success, error & validation state control for Next.js form a
22
22
  - ✅ The `React.useActionState()` accessible via the `useActionContext()` hook.
23
23
  - ✅ Computes progress flags like `isInvalid`, `isSuccess` based on the envelope type.
24
24
  - ✅ Binds the action with the arguments from the _args_ prop.
25
+ - ✅ Has an optional `validate` prop to validate the form data client-side before calling the server action.
25
26
 
26
27
  **Context-bound `<Form />` component**
27
28
 
@@ -101,7 +102,6 @@ export function SubscribeForm() {
101
102
 
102
103
  ```tsx
103
104
  // app/subscribe/page.tsx
104
-
105
105
  import { Action } from "react-form-action/client";
106
106
 
107
107
  import { subscribeAction } from "./action";
@@ -231,112 +231,6 @@ export default function Page({
231
231
  }
232
232
  ```
233
233
 
234
- ### Action Creator
235
-
236
- Low-level action creator, which provides the `success`, `failure` and `invalid` envelope constructors. With the `createFormAction` you must handle the native `FormData` by yourself.
237
-
238
- ```ts
239
- "use server";
240
-
241
- import { createFormAction } from "react-form-action";
242
- import { z } from "zod";
243
-
244
- // Define custom serializable error & success data types
245
- type ErrorData = {
246
- message: string;
247
- };
248
-
249
- type SuccessData = {
250
- message: string;
251
- };
252
-
253
- type ValiationError = {
254
- name?: string;
255
- };
256
-
257
- const updateUserSchema = z.object({ name: z.string() });
258
-
259
- export const updateUser = createFormAction<
260
- SuccessData,
261
- ErrorData,
262
- ValiationError
263
- >(({ success, failure, invalid }) =>
264
- // success and failure helper functions create wrappers for success & error data respectively
265
- async (prevState, formData) => {
266
- if (prevState.type === "initial") {
267
- // use the initialData passed to <Form /> here
268
- // prevState.data === "foobar"
269
- }
270
-
271
- try {
272
- const { name } = updateUserSchema.parse({
273
- name: formData.get("name"),
274
- });
275
-
276
- const user = await updateCurrentUser(name);
277
-
278
- if (user) {
279
- // {type: "success", data: "Your profile has been updated.", error: null, validationError: null}
280
- return success({
281
- message: "Your profile has been updated.",
282
- });
283
- } else {
284
- // {type: "error", data: null, error: { message: "No current user." }, validationError: null}
285
- return failure({ message: "No current user." });
286
- }
287
- } catch (error) {
288
- if (error instanceof ZodError) {
289
- // {type: "invalid", data: null, error: null, validationError: {name: "Invalid input"}}
290
- return invalid({
291
- name: error.issues[0]?.message ?? "Validation error",
292
- });
293
- }
294
-
295
- return failure({ message: "Failed to update user." });
296
- }
297
- },
298
- );
299
- ```
300
-
301
- The action creator supports arguments binding:
302
-
303
- ```ts
304
- export const updateUser = createFormAction(
305
- (
306
- { success, failure, invalid },
307
- userId: string /* Here you can specify multiple arguments */,
308
- ) =>
309
- async (prevState, formData) => {
310
- try {
311
- const { name } = updateUserSchema.parse({
312
- name: formData.get("name"),
313
- });
314
-
315
- const user = await db.users.findById(userId);
316
-
317
- if (!user) {
318
- return failure({ message: "No such user." });
319
- }
320
-
321
- const updated = await user.update({ name });
322
-
323
- if (updated) {
324
- return success({
325
- message: "User has been updated.",
326
- });
327
- } else {
328
- return failure({ message: "Failed to update." });
329
- }
330
- } catch (error) {
331
- // handle error
332
- }
333
- },
334
- );
335
-
336
- // call bind as usuall, the "123" becomes the "userId"
337
- updateUser.bind(null, "123");
338
- ```
339
-
340
234
  ### Action Context
341
235
 
342
236
  The `<Action>` components enables you to access your `action`'s state with the `useActionContext()` hook:
@@ -384,6 +278,63 @@ export function SignupForm() {
384
278
  }
385
279
  ```
386
280
 
281
+ #### Client-side validation
282
+
283
+ The `<Action validate={} />` prop enables you to tap into the `formData` before they are passed to the server action.
284
+
285
+ ```tsx
286
+ "use client"; // NOTE: The <Action> renders a context provider (a client component)
287
+
288
+ import type { PropsWithChildren } from "react";
289
+ import { Action } from "react-form-action/client";
290
+ import { z } from "zod";
291
+ import { zfd } from "zod-form-data";
292
+ import { signUp } from "./action";
293
+ import { signUpSchema } from "./schema";
294
+
295
+ export function SignUpAction({ children }: PropsWithChildren) {
296
+ return (
297
+ <Action
298
+ action={signUp}
299
+ initialData={undefined}
300
+ validate={(formData) => {
301
+ const result = zfd.formData(signUpSchema).safeParse(formData);
302
+
303
+ // NOTE: the return must be of the same type as your action's ValidationError type
304
+ if (result.error) {
305
+ return z.treeifyError(result.error);
306
+ }
307
+
308
+ return null;
309
+ }}
310
+ >
311
+ {children}
312
+ </Action>
313
+ );
314
+ }
315
+ ```
316
+
317
+ Use the `validateSchema` to avoid the zod-form-data boilerplate:
318
+
319
+ ```tsx
320
+ import { validateSchema } from "react-form-action";
321
+
322
+ import { signUpSchema } from "./schema";
323
+
324
+ export function SignUpAction({ children }: PropsWithChildren) {
325
+ return (
326
+ <Action
327
+ action={signUp}
328
+ initialData={undefined}
329
+ validate={validateSchema(signUpSchema)}
330
+ >
331
+ {children}
332
+ </Action>
333
+ );
334
+ }
335
+ ```
336
+
337
+
387
338
  ### `<Form>` Component
388
339
 
389
340
  The `<form>` submits the action in `onSubmit` handler to [prevent automatic form reset](https://github.com/facebook/react/issues/29034).
@@ -544,3 +495,111 @@ function SubmitButton() {
544
495
  );
545
496
  };
546
497
  ```
498
+
499
+
500
+
501
+ ### Action Creator
502
+
503
+ Low-level action creator, which provides the `success`, `failure` and `invalid` envelope constructors. With the `createFormAction` you must handle the native `FormData` by yourself.
504
+
505
+ ```ts
506
+ "use server";
507
+
508
+ import { createFormAction } from "react-form-action";
509
+ import { z } from "zod";
510
+
511
+ // Define custom serializable error & success data types
512
+ type ErrorData = {
513
+ message: string;
514
+ };
515
+
516
+ type SuccessData = {
517
+ message: string;
518
+ };
519
+
520
+ type ValiationError = {
521
+ name?: string;
522
+ };
523
+
524
+ const updateUserSchema = z.object({ name: z.string() });
525
+
526
+ export const updateUser = createFormAction<
527
+ SuccessData,
528
+ ErrorData,
529
+ ValiationError
530
+ >(({ success, failure, invalid }) =>
531
+ // success and failure helper functions create wrappers for success & error data respectively
532
+ async (prevState, formData) => {
533
+ if (prevState.type === "initial") {
534
+ // use the initialData passed to <Form /> here
535
+ // prevState.data === "foobar"
536
+ }
537
+
538
+ try {
539
+ const { name } = updateUserSchema.parse({
540
+ name: formData.get("name"),
541
+ });
542
+
543
+ const user = await updateCurrentUser(name);
544
+
545
+ if (user) {
546
+ // {type: "success", data: "Your profile has been updated.", error: null, validationError: null}
547
+ return success({
548
+ message: "Your profile has been updated.",
549
+ });
550
+ } else {
551
+ // {type: "error", data: null, error: { message: "No current user." }, validationError: null}
552
+ return failure({ message: "No current user." });
553
+ }
554
+ } catch (error) {
555
+ if (error instanceof ZodError) {
556
+ // {type: "invalid", data: null, error: null, validationError: {name: "Invalid input"}}
557
+ return invalid({
558
+ name: error.issues[0]?.message ?? "Validation error",
559
+ });
560
+ }
561
+
562
+ return failure({ message: "Failed to update user." });
563
+ }
564
+ },
565
+ );
566
+ ```
567
+
568
+ The action creator supports arguments binding:
569
+
570
+ ```ts
571
+ export const updateUser = createFormAction(
572
+ (
573
+ { success, failure, invalid },
574
+ userId: string /* Here you can specify multiple arguments */,
575
+ ) =>
576
+ async (prevState, formData) => {
577
+ try {
578
+ const { name } = updateUserSchema.parse({
579
+ name: formData.get("name"),
580
+ });
581
+
582
+ const user = await db.users.findById(userId);
583
+
584
+ if (!user) {
585
+ return failure({ message: "No such user." });
586
+ }
587
+
588
+ const updated = await user.update({ name });
589
+
590
+ if (updated) {
591
+ return success({
592
+ message: "User has been updated.",
593
+ });
594
+ } else {
595
+ return failure({ message: "Failed to update." });
596
+ }
597
+ } catch (error) {
598
+ // handle error
599
+ }
600
+ },
601
+ );
602
+
603
+ // call bind as usuall, the "123" becomes the "userId"
604
+ updateUser.bind(null, "123");
605
+ ```
package/dist/client.d.mts CHANGED
@@ -7,11 +7,13 @@ type ActionProps<Data, Error, ValidationError, Arguments extends unknown[] = []>
7
7
  args: Arguments;
8
8
  initialData: Data;
9
9
  permalink?: string;
10
+ validate?: (payload: FormData) => null | ValidationError;
10
11
  } : {
11
12
  action: FormAction<Data, Error, ValidationError, FormData, Arguments>;
12
13
  initialData: Data;
13
14
  args?: undefined;
14
15
  permalink?: string;
16
+ validate?: (payload: FormData) => null | ValidationError;
15
17
  }>;
16
18
  type ActionStatusFlags<T extends ActionState<unknown, unknown, unknown>["type"] | unknown = unknown> = {
17
19
  isInitial: T extends "initial" ? true : false;
@@ -33,20 +35,8 @@ type SpreadActionContext<Data = unknown, Error = unknown, ValidationError = unkn
33
35
  /**
34
36
  * A hook to consume the form action state from the context.
35
37
  */
36
- declare function useActionContext<Data, Error, ValidationError, Args extends unknown[] = []>(action?: FormAction<Data, Error, ValidationError, FormData, Args>): SpreadActionContext<Data, Error, ValidationError>;
37
- declare function Action<Data, Error, ValidationError, Args extends unknown[] = []>({ children, action: formAction, initialData, args, permalink }: ActionProps<Data, Error, ValidationError, Args>): React$1.JSX.Element;
38
- //#endregion
39
- //#region src/Form.d.ts
40
- type FormProps = Omit<JSX.IntrinsicElements["form"], "action"> & {
41
- /**
42
- * Opt-in into automatic form reset by using the form "action" prop.
43
- * By default, the onSubmit with a custom transition which opts-out of the implicit form reset.
44
- * See for more. https://github.com/facebook/react/issues/29034
45
- * @default false
46
- */
47
- autoReset?: boolean;
48
- };
49
- declare function Form({ autoReset, ...props }: FormProps): JSX.Element;
38
+ declare function useActionContext<Data, Error, ValidationError, Args extends unknown[] = []>(_action?: FormAction<Data, Error, ValidationError, FormData, Args>): SpreadActionContext<Data, Error, ValidationError>;
39
+ declare function Action<Data, Error, ValidationError, Args extends unknown[] = []>({ children, action: formAction, initialData, args, permalink, validate }: ActionProps<Data, Error, ValidationError, Args>): import("react").JSX.Element;
50
40
  //#endregion
51
41
  //#region src/ZodFieldError.d.ts
52
42
  declare const SEPARATOR: ".";
@@ -96,6 +86,18 @@ declare function createComponents<Data, Error, ValidationError extends $ZodError
96
86
  }) => React$1.ReactNode;
97
87
  };
98
88
  //#endregion
89
+ //#region src/Form.d.ts
90
+ type FormProps = Omit<JSX.IntrinsicElements["form"], "action"> & {
91
+ /**
92
+ * Opt-in into automatic form reset by using the form "action" prop.
93
+ * By default, the onSubmit with a custom transition which opts-out of the implicit form reset.
94
+ * See for more. https://github.com/facebook/react/issues/29034
95
+ * @default false
96
+ */
97
+ autoReset?: boolean;
98
+ };
99
+ declare function Form({ autoReset, ...props }: FormProps): JSX.Element;
100
+ //#endregion
99
101
  //#region src/Pending.d.ts
100
102
  /**
101
103
  * Conditionally renders the children, when the form action is in the "pending" state.
package/dist/client.mjs CHANGED
@@ -1 +1 @@
1
- "use client";import{n as e}from"./createFormAction-BwMYAzm2.mjs";import t,{createContext as n,startTransition as r,use as i,useActionState as a}from"react";const o={isInitial:!1,isInvalid:!1,isFailure:!1,isSuccess:!1},s=n(null);function c(e){let t=i(s);if(!t)throw Error(`ActionContext must be initialized before use. Is your useActionContext hook wrapped with an <Action> Component?`);return t}function l({children:n,action:r,initialData:i,args:c,permalink:l}){let[u,d,f]=a(c?r.bind(null,...c):r,e(i),l),p=u.type===`initial`?{...u,...o,action:d,isPending:f,isInitial:!0}:u.type===`invalid`?{...u,...o,action:d,isPending:f,isInvalid:!0}:u.type===`failure`?{...u,...o,action:d,isPending:f,isFailure:!0}:{...u,...o,action:d,isPending:f,isSuccess:!0};return t.createElement(s,{value:p},n)}function u({autoReset:e=!1,...n}){let{action:i}=c(),a=e?{action:i}:{onSubmit:e=>{e.preventDefault();let t=e.currentTarget;r(()=>{i(new FormData(t))})}};return t.createElement(`form`,{...a,...n})}const d=Object.freeze({errors:Object.freeze([])});function f({errors:e,name:n,children:r=({error:e})=>t.createElement(t.Fragment,null,e)}){if(n.length===0)return r({name:n,error:e.errors[0],errors:e.errors});let i=n.split(`.`),a=e;for(;i.length;){let e=i.shift();if(!a.properties){a=d;break}a=a.properties[e]??d}return r({name:n,error:a.errors[0],errors:a.errors})}function p(e){function n({name:n,children:r}){let{isInvalid:i,validationError:a}=c(e);return t.createElement(f,{errors:a??d,name:n},r??(({error:e})=>i&&t.createElement(t.Fragment,null,e)))}function r({children:t}){let{isSuccess:n,data:r}=c(e);return typeof t==`function`?t({isSuccess:n,data:r}):n&&t}function i({children:t}){let{isInvalid:n,validationError:r}=c(e);return typeof t==`function`?t({isInvalid:n,validationError:r}):n&&t}return{FieldError:n,Success:r,Invalid:i}}function m({children:e}){let{isPending:t}=c();return typeof e==`function`?e({isPending:t}):t&&e}export{l as Action,u as Form,m as Pending,f as ZodFieldError,p as createComponents,d as noError,c as useActionContext};
1
+ "use client";import{n as e,t}from"./createFormAction-BwMYAzm2.mjs";import{createContext as n,startTransition as r,use as i,useActionState as a}from"react";import{Fragment as o,jsx as s}from"react/jsx-runtime";const c={isInitial:!1,isInvalid:!1,isFailure:!1,isSuccess:!1},l=n(null);function u(e){let t=i(l);if(!t)throw Error(`ActionContext must be initialized before use. Is your useActionContext hook wrapped with an <Action> Component?`);return t}function d({children:n,action:r,initialData:i,args:o,permalink:u,validate:d}){let f=o?r.bind(null,...o):r,[p,m,h]=a(async(e,n)=>{if(d){let r=await t(({invalid:e,success:t})=>async(n,r)=>{let i=d(r);return i?e(i):t(!0)})(e,n);if(r.type===`invalid`)return r}return f(e,n)},e(i),u),g=p.type===`initial`?{...p,...c,action:m,isPending:h,isInitial:!0}:p.type===`invalid`?{...p,...c,action:m,isPending:h,isInvalid:!0}:p.type===`failure`?{...p,...c,action:m,isPending:h,isFailure:!0}:{...p,...c,action:m,isPending:h,isSuccess:!0};return s(l,{value:g,children:n})}const f=Object.freeze({errors:Object.freeze([])});function p({errors:e,name:t,children:n=({error:e})=>s(o,{children:e})}){if(t.length===0)return n({name:t,error:e.errors[0],errors:e.errors});let r=t.split(`.`),i=e;for(let e of r){if(!i.properties){i=f;break}i=i.properties[e]??f}return n({name:t,error:i.errors[0],errors:i.errors})}function m(e){function t({name:t,children:n}){let{isInvalid:r,validationError:i}=u(e);return s(p,{errors:i??f,name:t,children:n??(({error:e})=>r&&s(o,{children:e}))})}function n({children:t}){let{isSuccess:n,data:r}=u(e);return typeof t==`function`?t({isSuccess:n,data:r}):n&&t}function r({children:t}){let{isInvalid:n,validationError:r}=u(e);return typeof t==`function`?t({isInvalid:n,validationError:r}):n&&t}return{FieldError:t,Success:n,Invalid:r}}function h({autoReset:e=!1,...t}){let{action:n}=u();return s(`form`,{...e?{action:n}:{onSubmit:e=>{e.preventDefault();let t=e.currentTarget;r(()=>{n(new FormData(t))})}},...t})}function g({children:e}){let{isPending:t}=u();return typeof e==`function`?e({isPending:t}):t&&e}export{d as Action,h as Form,g as Pending,p as ZodFieldError,m as createComponents,f as noError,u as useActionContext};
package/dist/index.d.mts CHANGED
@@ -1,5 +1,6 @@
1
1
  import { a as InvalidState, c as initial, i as InitialState, n as FailureState, o as SuccessState, r as FormAction, s as createFormAction, t as ActionState } from "./createFormAction-4p5Fvn2A.mjs";
2
2
  import { ZodObject, ZodTuple, ZodType, z } from "zod/v4";
3
+ import { ZodObject as ZodObject$1, z as z$1 } from "zod";
3
4
  import { $ZodErrorTree, $ZodShape, $ZodType } from "zod/v4/core";
4
5
  //#region src/formAction.d.ts
5
6
  declare const emptyInput: unique symbol;
@@ -54,4 +55,12 @@ type FormActionBuilder<Schema extends ZodType | EmptyInput, Args extends $ZodTyp
54
55
  };
55
56
  declare const formAction: FormActionBuilder<typeof emptyInput, [], unknown, InitialContext, []>;
56
57
  //#endregion
57
- export { ActionState, FailureState, FormAction, InitialState, InvalidState, SuccessState, createFormAction, formAction, initial };
58
+ //#region src/validateSchema.d.ts
59
+ /**
60
+ * A helper to make a validate function for the client validation with <Action validate={} /> prop.
61
+ * @param schema z.object(...) schema
62
+ * @returns validate function
63
+ */
64
+ declare function validateSchema<T extends ZodObject$1>(schema: T): (formData: FormData) => z$1.core.$ZodErrorTree<z$1.TypeOf<T>, string> | null;
65
+ //#endregion
66
+ export { ActionState, FailureState, FormAction, InitialState, InvalidState, SuccessState, createFormAction, formAction, initial, validateSchema };
package/dist/index.mjs CHANGED
@@ -1 +1 @@
1
- import{n as e,t}from"./createFormAction-BwMYAzm2.mjs";import{z as n}from"zod/v4";import{zfd as r}from"zod-form-data";const i=Symbol();function a(e,o=[],s,c){async function l(e){let t={formData:e};for(let e of o){let n=await e({ctx:t});t={...t,...n}}return t}return{args(t){return a(e,o,s,c?[...c,...t]:t)},input(t){if(e===i)return a(t,o,s,c);if(e._zod.def.checks)throw Error(`Previous input is not augmentable because it contains an effect.`);if(t._zod.def.checks)throw Error(`Your input contains effect which prevents merging it with the previous inputs.`);if(e._zod.def.type===`object`)return a(n.object({...e.shape,...t.shape}),o,s,c);throw Error(`Merging inputs works only for object schemas without effects.`)},use(t){return a(e,[...o,t],s,c)},error(t){return a(e,o,t,c)},run:e===i?e=>t(({success:t,failure:r,invalid:i},...a)=>async(o,u)=>{let d=await l(u);if(c){let e=n.tuple(c).safeParse(a);if(!e.success)return i(n.treeifyError(e.error))}try{return t(await e({args:a,ctx:d}))}catch(e){if(s)return r(await s({args:a,error:e,ctx:d}));throw e}}):e===i?void 0:i=>t(({success:t,failure:a,invalid:o},...u)=>{let d=r.formData(e);return async(e,r)=>{let f=await l(r);if(c){let e=n.tuple(c).safeParse(u);if(!e.success)return o(n.treeifyError(e.error))}let p=d.safeParse(r);if(!p.success)return o(n.treeifyError(p.error));let m=p.data;try{return t(await i({args:u,input:m,ctx:f}))}catch(e){if(s)return a(await s({args:u,error:e,ctx:f}));throw e}}})}}const o=a(i);export{t as createFormAction,o as formAction,e as initial};
1
+ import{n as e,t}from"./createFormAction-BwMYAzm2.mjs";import{z as n}from"zod/v4";import{zfd as r}from"zod-form-data";import{z as i}from"zod";const a=Symbol();function o(e,i=[],s,c){async function l(e){let t={formData:e};for(let e of i){let n=await e({ctx:t});t={...t,...n}}return t}return{args(t){return o(e,i,s,c?[...c,...t]:t)},input(t){if(e===a)return o(t,i,s,c);if(e._zod.def.checks)throw Error(`Previous input is not augmentable because it contains an effect.`);if(t._zod.def.checks)throw Error(`Your input contains effect which prevents merging it with the previous inputs.`);if(e._zod.def.type===`object`)return o(n.object({...e.shape,...t.shape}),i,s,c);throw Error(`Merging inputs works only for object schemas without effects.`)},use(t){return o(e,[...i,t],s,c)},error(t){return o(e,i,t,c)},run:e===a?e=>t(({success:t,failure:r,invalid:i},...a)=>async(o,u)=>{let d=await l(u);if(c){let e=n.tuple(c).safeParse(a);if(!e.success)return i(n.treeifyError(e.error))}try{return t(await e({args:a,ctx:d}))}catch(e){if(s)return r(await s({args:a,error:e,ctx:d}));throw e}}):e===a?void 0:i=>t(({success:t,failure:a,invalid:o},...u)=>{let d=r.formData(e);return async(e,r)=>{let f=await l(r);if(c){let e=n.tuple(c).safeParse(u);if(!e.success)return o(n.treeifyError(e.error))}let p=d.safeParse(r);if(!p.success)return o(n.treeifyError(p.error));let m=p.data;try{return t(await i({args:u,input:m,ctx:f}))}catch(e){if(s)return a(await s({args:u,error:e,ctx:f}));throw e}}})}}const s=o(a);function c(e){return t=>{let n=r.formData(e).safeParse(t);return n.error?i.treeifyError(n.error):null}}export{t as createFormAction,s as formAction,e as initial,c as validateSchema};
package/package.json CHANGED
@@ -1,76 +1,78 @@
1
- {
2
- "name": "react-form-action",
3
- "version": "2.9.2",
4
- "description": "State management helpers for the react form actions.",
5
- "repository": {
6
- "type": "git",
7
- "url": "https://github.com/MiroslavPetrik/react-form-action.git"
8
- },
9
- "main": "dist/index.js",
10
- "module": "dist/index.mjs",
11
- "files": [
12
- "/dist"
13
- ],
14
- "scripts": {
15
- "build": "tsdown src/index.ts src/client.ts --minify",
16
- "test": "vitest",
17
- "typecheck": "vitest --typecheck",
18
- "format": "prettier . --write",
19
- "format:check": "prettier . --check",
20
- "ncu": "ncu --interactive --format group",
21
- "pub:next": "npm publish --tag next"
22
- },
23
- "exports": {
24
- ".": {
25
- "import": "./dist/index.mjs",
26
- "module": "./dist/index.mjs",
27
- "types": "./dist/index.d.mts",
28
- "default": "./dist/index.mjs"
29
- },
30
- "./client": {
31
- "import": "./dist/client.mjs",
32
- "module": "./dist/client.mjs",
33
- "types": "./dist/client.d.mts",
34
- "default": "./dist/client.mjs"
35
- }
36
- },
37
- "publishConfig": {
38
- "access": "public"
39
- },
40
- "keywords": [
41
- "react",
42
- "form-action",
43
- "react-form-action",
44
- "next",
45
- "next-form-action",
46
- "nextjs",
47
- "server-action"
48
- ],
49
- "author": "Miroslav Petrik",
50
- "license": "MIT",
51
- "peerDependencies": {
52
- "react": ">=19",
53
- "react-dom": ">=19",
54
- "zod": "^3.25.0 || ^4.0.0",
55
- "zod-form-data": "^3.0.0"
56
- },
57
- "devDependencies": {
58
- "@testing-library/dom": "^10.4.1",
59
- "@testing-library/jest-dom": "^7.0.0",
60
- "@testing-library/react": "^16.3.2",
61
- "@testing-library/user-event": "^14.6.1",
62
- "@types/react": "^19.2.17",
63
- "@types/react-dom": "^19.2.3",
64
- "@vitejs/plugin-react": "^6.0.3",
65
- "happy-dom": "^20.11.0",
66
- "npm-check-updates": "^22.2.9",
67
- "prettier": "^3.9.6",
68
- "react": "^19.2.7",
69
- "react-dom": "^19.2.7",
70
- "tsdown": "^0.22.12",
71
- "typescript": "^6.0.3",
72
- "vitest": "^4.1.10",
73
- "zod": "^3.25.0",
74
- "zod-form-data": "^3.0.3"
75
- }
76
- }
1
+ {
2
+ "name": "react-form-action",
3
+ "version": "2.11.0",
4
+ "description": "State management helpers for the react form actions.",
5
+ "repository": {
6
+ "type": "git",
7
+ "url": "https://github.com/MiroslavPetrik/react-form-action.git"
8
+ },
9
+ "main": "dist/index.js",
10
+ "module": "dist/index.mjs",
11
+ "files": [
12
+ "/dist"
13
+ ],
14
+ "scripts": {
15
+ "build": "tsdown src/index.ts src/client.ts --minify",
16
+ "test": "vitest",
17
+ "typecheck": "vitest --typecheck",
18
+ "lint": "biome lint ./src",
19
+ "lint:write": "biome lint ./src --write",
20
+ "format": "biome format --write .",
21
+ "format:check": "biome check .",
22
+ "ncu": "ncu --interactive --format group",
23
+ "pub:next": "npm publish --tag next"
24
+ },
25
+ "exports": {
26
+ ".": {
27
+ "import": "./dist/index.mjs",
28
+ "module": "./dist/index.mjs",
29
+ "types": "./dist/index.d.mts",
30
+ "default": "./dist/index.mjs"
31
+ },
32
+ "./client": {
33
+ "import": "./dist/client.mjs",
34
+ "module": "./dist/client.mjs",
35
+ "types": "./dist/client.d.mts",
36
+ "default": "./dist/client.mjs"
37
+ }
38
+ },
39
+ "publishConfig": {
40
+ "access": "public"
41
+ },
42
+ "keywords": [
43
+ "react",
44
+ "form-action",
45
+ "react-form-action",
46
+ "next",
47
+ "next-form-action",
48
+ "nextjs",
49
+ "server-action"
50
+ ],
51
+ "author": "Miroslav Petrik",
52
+ "license": "MIT",
53
+ "peerDependencies": {
54
+ "react": ">=19",
55
+ "react-dom": ">=19",
56
+ "zod": "^3.25.0 || ^4.0.0",
57
+ "zod-form-data": "^3.0.0"
58
+ },
59
+ "devDependencies": {
60
+ "@biomejs/biome": "^2.5.8",
61
+ "@testing-library/dom": "^10.4.1",
62
+ "@testing-library/jest-dom": "^7.0.1",
63
+ "@testing-library/react": "^16.3.2",
64
+ "@testing-library/user-event": "^14.6.4",
65
+ "@types/react": "^19.2.18",
66
+ "@types/react-dom": "^19.2.4",
67
+ "@vitejs/plugin-react": "^6.0.5",
68
+ "happy-dom": "^20.11.2",
69
+ "npm-check-updates": "^23.0.2",
70
+ "react": "^19.2.8",
71
+ "react-dom": "^19.2.8",
72
+ "tsdown": "^0.22.14",
73
+ "typescript": "^7.0.2",
74
+ "vitest": "^4.1.10",
75
+ "zod": "^4.4.3",
76
+ "zod-form-data": "^3.0.3"
77
+ }
78
+ }