react-form-action 1.1.1 → 1.2.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
@@ -50,7 +50,7 @@ const i18nMiddleware = async () => {
50
50
  const authAction = formAction
51
51
  .use(i18nMiddleware)
52
52
  .use(async ({ ctx: { t } }) =>
53
- console.log("🎉 context enhanced by previous middlewares 🎉", t),
53
+ console.log("🎉 context enhanced by previous middlewares 🎉", t)
54
54
  )
55
55
  .error(({ error }) => {
56
56
  if (error instanceof DbError) {
@@ -85,7 +85,7 @@ export const signUp = authAction
85
85
  .refine((data) => data.password === data.confirm, {
86
86
  message: "Passwords don't match",
87
87
  path: ["confirm"],
88
- }),
88
+ })
89
89
  ) // if using refinement, only one input call is permited, as schema with ZodEffects is not extendable.
90
90
  .run(async ({ ctx: { t }, input: { email, password } }) => {
91
91
  // 🎉 passwords match!
@@ -161,7 +161,7 @@ export const updateUser = createFormAction<
161
161
 
162
162
  return failure({ message: "Failed to update user." });
163
163
  }
164
- },
164
+ }
165
165
  );
166
166
  ```
167
167
 
@@ -206,6 +206,55 @@ export function UpdateUserForm() {
206
206
  }
207
207
  ```
208
208
 
209
+ ### `<ZodFieldError>` Component
210
+
211
+ Actions created with `formAction` builder will have the `validationError` of [`ZodFormattedError`](https://zod.dev/ERROR_HANDLING?id=formatting-errors) type.
212
+ To easily access the nested error, use the helper `<ZodFieldError>` component:
213
+
214
+ ```tsx
215
+ "use client";
216
+ import { Form, ZodFieldError } from "react-form-action/client";
217
+
218
+ export const signUp = authAction
219
+ .input(
220
+ z
221
+ .object({
222
+ user: z.object({
223
+ email: z.string().email(),
224
+ name: z.string(),
225
+ }),
226
+ password: z.string().min(8),
227
+ confirm: z.string(),
228
+ })
229
+ .refine((data) => data.password === data.confirm, {
230
+ message: "Passwords don't match",
231
+ })
232
+ )
233
+ .run(async ({ ctx, input }) => {
234
+ // implementation
235
+ });
236
+
237
+ export function SignUpForm() {
238
+ return (
239
+ <Form action={signUp} initialData="">
240
+ {({ error, data, validationError }) => (
241
+ <>
242
+ {/*
243
+ When the "name" prop is ommited, the top-level error will be rendered e.g.:
244
+ "Passwords don't match"
245
+ */}
246
+ <ZodFieldError errors={validationError} />
247
+ {/* Access fields by their name: */}
248
+ <ZodFieldError errors={validationError} name="password" />
249
+ {/* Access nested fields by dot access notation: */}
250
+ <ZodFieldError errors={validationError} name="user.email" />
251
+ </>
252
+ )}
253
+ </Form>
254
+ );
255
+ }
256
+ ```
257
+
209
258
  ### Bonus `<FormStatus>`
210
259
 
211
260
  The `useFormStatus` hook data exposed via render prop:
package/dist/client.d.mts CHANGED
@@ -3,6 +3,7 @@ import React__default, { FormHTMLAttributes } from 'react';
3
3
  import { RenderProp } from 'react-render-prop-type';
4
4
  import { F as FormState, b as InitialState, I as InvalidState, a as FailureState, S as SuccessState } from './createFormAction-3a51310f.js';
5
5
  import { useFormStatus } from 'react-dom';
6
+ import { ZodFormattedError } from 'zod';
6
7
 
7
8
  type FormStateProps<Data, Error, ValidationError, Payload> = {
8
9
  action: (state: FormState<Data, Error, ValidationError>, payload: Payload) => Promise<FormState<Data, Error, ValidationError>>;
@@ -24,4 +25,16 @@ declare function Form<Data, Error, ValidationError>({ children, action, initialD
24
25
 
25
26
  declare function FormStatus({ children, }: RenderProp<ReturnType<typeof useFormStatus>>): React.ReactNode;
26
27
 
27
- export { Form, FormProps, FormStateProps, FormStatus, initial };
28
+ declare const SEPARATOR: ".";
29
+ type Paths<Err extends object> = {
30
+ [k in keyof Err]: k extends string ? Err[k] extends object ? `${k}${typeof SEPARATOR}${Paths<Err[k]>}` : k : never;
31
+ }[keyof Err];
32
+ type ZodFieldErrorProps<Errors extends ZodFormattedError<any>> = Errors extends ZodFormattedError<infer E extends object> ? {
33
+ errors: Errors;
34
+ name?: "" | Paths<E>;
35
+ } & Partial<RenderProp<{
36
+ errors: readonly string[];
37
+ }>> : any;
38
+ declare function ZodFieldError<Errors extends ZodFormattedError<any>>({ errors, name, children, }: ZodFieldErrorProps<Errors>): React__default.ReactNode;
39
+
40
+ export { Form, FormProps, FormStateProps, FormStatus, ZodFieldError, ZodFieldErrorProps, initial };
package/dist/client.mjs CHANGED
@@ -1 +1 @@
1
- "use client";import o from"react";import{useActionState as F}from"react";import{useFormStatus as S}from"react-dom";function e({children:r}){return r(S())}function c(r){return{type:"initial",data:r,error:null,validationError:null}}var a={isInitial:!1,isInvalid:!1,isFailure:!1,isSuccess:!1};function x({children:r,action:i,initialData:n,permalink:s,...l}){let[t,m]=F(i,c(n),s),u=t.type==="initial"?{...t,...a,isInitial:!0}:t.type==="invalid"?{...t,...a,isInvalid:!0}:t.type==="failure"?{...t,...a,isFailure:!0}:{...t,...a,isSuccess:!0};return o.createElement("form",{action:m,...l},o.createElement(e,null,({pending:p})=>r({...u,isPending:p})))}export{x as Form,e as FormStatus,c as initial};
1
+ "use client";import l from"react";import{useActionState as F}from"react";import{useFormStatus as c}from"react-dom";function s({children:t}){return t(c())}function f(t){return{type:"initial",data:t,error:null,validationError:null}}var i={isInitial:!1,isInvalid:!1,isFailure:!1,isSuccess:!1};function T({children:t,action:a,initialData:n,permalink:e,...o}){let[r,m]=F(a,f(n),e),d=r.type==="initial"?{...r,...i,isInitial:!0}:r.type==="invalid"?{...r,...i,isInvalid:!0}:r.type==="failure"?{...r,...i,isFailure:!0}:{...r,...i,isSuccess:!0};return l.createElement("form",{action:m,...o},l.createElement(s,null,({pending:u})=>t({...d,isPending:u})))}import p from"react";var E=".",S=Object.freeze({_errors:Object.freeze([])});function v({errors:t,name:a="",children:n=({errors:e})=>p.createElement(p.Fragment,null,e[0])}){if(a.length===0)return n({errors:t._errors});let e=a.split(E),o=t;for(;e.length;){let r=e.shift();o=o[r]??S}return n({errors:o._errors})}export{T as Form,s as FormStatus,v as ZodFieldError,f as initial};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-form-action",
3
- "version": "1.1.1",
3
+ "version": "1.2.1",
4
4
  "description": "State management helpers for the react form actions.",
5
5
  "repository": {
6
6
  "type": "git",
@@ -16,7 +16,8 @@
16
16
  "test": "vitest",
17
17
  "typecheck": "vitest --typecheck",
18
18
  "format": "prettier . --write",
19
- "format:check": "prettier . --check"
19
+ "format:check": "prettier . --check",
20
+ "ncu": "ncu --interactive --format group"
20
21
  },
21
22
  "exports": {
22
23
  ".": {
@@ -44,20 +45,27 @@
44
45
  "author": "Miroslav Petrik",
45
46
  "license": "MIT",
46
47
  "peerDependencies": {
47
- "react": ">=18.3",
48
- "react-dom": ">=18.3",
48
+ "react": ">=19",
49
+ "react-dom": ">=19",
49
50
  "zod": "^3",
50
51
  "zod-form-data": "^2"
51
52
  },
52
53
  "devDependencies": {
53
- "@types/react": "^18.3.5",
54
- "@types/react-dom": "^18.3.0",
55
- "next": "^14.0.2",
54
+ "@testing-library/dom": "^10.4.0",
55
+ "@testing-library/jest-dom": "^6.6.3",
56
+ "@testing-library/react": "^16.1.0",
57
+ "@types/react": "^19.0.0",
58
+ "@types/react-dom": "^19.0.1",
59
+ "@vitejs/plugin-react": "^4.3.4",
60
+ "happy-dom": "^15.11.7",
61
+ "npm-check-updates": "^17.1.11",
56
62
  "prettier": "^3.3.3",
63
+ "react": "^19.0.0",
64
+ "react-dom": "^19.0.0",
57
65
  "react-render-prop-type": "^0.1.0",
58
66
  "tsup": "^7.2.0",
59
67
  "typescript": "^5.2.2",
60
- "vitest": "^1.2.2",
68
+ "vitest": "^1.3.1",
61
69
  "zod": "^3.22.4",
62
70
  "zod-form-data": "^2.0.2"
63
71
  }