react-form-action 0.2.0 → 0.3.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
|
@@ -2,6 +2,23 @@
|
|
|
2
2
|
|
|
3
3
|
End-to-end typesafe success, error & validation state control for Next.js 14 form actions.
|
|
4
4
|
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
**Action Creator**
|
|
8
|
+
|
|
9
|
+
- ✅ Provides `"invalid" | "success" | "failure"` response objects.
|
|
10
|
+
- ✅ Define generic payload for each of the response type.
|
|
11
|
+
|
|
12
|
+
**Form Action builder**
|
|
13
|
+
|
|
14
|
+
- ✅ tRPC-like builder API for `.input(zodSchema)` & context `.use(middleware)`
|
|
15
|
+
- ✅ Parses `formData` with [`zod-form-data`](https://www.npmjs.com/package/zod-form-data)
|
|
16
|
+
|
|
17
|
+
**Stateful `<Form />`**
|
|
18
|
+
|
|
19
|
+
- ✅ `<Form />` component reads the action's response.
|
|
20
|
+
- ✅ Computes progress meta-state like `isInvalid`, `isSuccess` and more.
|
|
21
|
+
|
|
5
22
|
## Install
|
|
6
23
|
|
|
7
24
|
```
|
|
@@ -28,12 +45,13 @@ const i18nMiddleware = async () => {
|
|
|
28
45
|
return { t };
|
|
29
46
|
};
|
|
30
47
|
|
|
31
|
-
const authAction = formAction
|
|
48
|
+
const authAction = formAction
|
|
49
|
+
.input(emailschema)
|
|
32
50
|
.use(i18nMiddleware)
|
|
33
51
|
.use(async ({ ctx: { t } }) =>
|
|
34
52
|
console.log("🎉 context enhanced by previous middlewares 🎉", t)
|
|
35
53
|
)
|
|
36
|
-
.error((error) => {
|
|
54
|
+
.error(({ error }) => {
|
|
37
55
|
if (error instanceof DbError) {
|
|
38
56
|
return error.custom.code;
|
|
39
57
|
} else {
|
|
@@ -53,15 +71,16 @@ export const resendVerifyEmailAction = authAction.run(
|
|
|
53
71
|
}
|
|
54
72
|
);
|
|
55
73
|
|
|
56
|
-
export const
|
|
57
|
-
|
|
74
|
+
export const signUp = authAction
|
|
75
|
+
// extend the input
|
|
76
|
+
.input(z.object({ password: z.string() }))
|
|
77
|
+
.run(async ({ ctx: { t }, input: { email, password } }) => {
|
|
58
78
|
// do custom work
|
|
59
|
-
await db.
|
|
79
|
+
await db.signupWithEmailAndPassword({ email, password });
|
|
60
80
|
|
|
61
81
|
// return translated success message
|
|
62
|
-
return t("
|
|
63
|
-
}
|
|
64
|
-
);
|
|
82
|
+
return t("signUp.success");
|
|
83
|
+
});
|
|
65
84
|
```
|
|
66
85
|
|
|
67
86
|
### Server Action (usable in Next.js)
|
package/dist/client.d.mts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
import React__default, { FormHTMLAttributes } from 'react';
|
|
3
3
|
import { RenderProp } from 'react-render-prop-type';
|
|
4
|
-
import {
|
|
4
|
+
import { b as InitialState, I as InvalidState, a as FailureState, S as SuccessState, F as FormState } from './createFormAction-3a51310f.js';
|
|
5
5
|
import { useFormStatus } from 'react-dom';
|
|
6
6
|
|
|
7
7
|
type FormStateProps<Data, ValidationError, Error, Payload> = {
|
|
@@ -29,4 +29,4 @@ declare function createFormAction<Data, Error = Data, ValidationError = Record<s
|
|
|
29
29
|
invalid: (validationError: ValidationError) => InvalidState<ValidationError>;
|
|
30
30
|
}) => (state: FormState<Data, Error, ValidationError>, payload: Payload) => Promise<FormState<Data, Error, ValidationError>>): (state: FormState<Data, Error, ValidationError>, payload: Payload) => Promise<FormState<Data, Error, ValidationError>>;
|
|
31
31
|
|
|
32
|
-
export { FormState as F,
|
|
32
|
+
export { FormState as F, InvalidState as I, SuccessState as S, FailureState as a, InitialState as b, createFormAction as c };
|
package/dist/index.d.mts
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
import { F as FormState } from './createFormAction-
|
|
2
|
-
export { b as
|
|
3
|
-
import {
|
|
1
|
+
import { F as FormState, a as FailureState, S as SuccessState, I as InvalidState } from './createFormAction-3a51310f.js';
|
|
2
|
+
export { b as InitialState, c as createFormAction } from './createFormAction-3a51310f.js';
|
|
3
|
+
import { z, ZodRawShape, ZodObject, objectUtil, ZodSchema } from 'zod';
|
|
4
4
|
|
|
5
|
-
type
|
|
6
|
-
|
|
7
|
-
}
|
|
5
|
+
type Flatten<T> = Identity<{
|
|
6
|
+
[K in keyof T]: T[K];
|
|
7
|
+
}>;
|
|
8
|
+
type Identity<T> = T;
|
|
8
9
|
type InitialContext = Record<"formData", FormData>;
|
|
9
10
|
/**
|
|
10
11
|
* Action without schema has no input.
|
|
@@ -19,13 +20,15 @@ type SchemaAction<Data, Context, Schema extends ZodSchema> = (params: {
|
|
|
19
20
|
ctx: Context;
|
|
20
21
|
input: z.infer<Schema>;
|
|
21
22
|
}) => Promise<Data>;
|
|
22
|
-
type
|
|
23
|
+
type EmptyZodObject = ZodObject<ZodRawShape>;
|
|
24
|
+
type FormActionBuilder<Schema extends EmptyZodObject, Err = Error, Context = InitialContext> = {
|
|
25
|
+
input: <T extends ZodRawShape>(schema: ZodObject<T>) => FormActionBuilder<ZodObject<objectUtil.extendShape<T, Schema["shape"]>>, Err, Context>;
|
|
23
26
|
/**
|
|
24
27
|
* A finishing call on the builder completing your action.
|
|
25
28
|
* @param action async function to execute. It will receive parsed formData as input, when the builder was initialized with a schema.
|
|
26
29
|
* @returns runnable server action exportable from a module.
|
|
27
30
|
*/
|
|
28
|
-
run: Schema extends undefined ? <Data>(action: Action<Data, Context>) => (state: FormState<Data, Err>, payload: FormData) => Promise<
|
|
31
|
+
run: Schema extends undefined ? <Data>(action: Action<Data, Context>) => (state: FormState<Data, Err>, payload: FormData) => Promise<Flatten<FailureState<Err> | SuccessState<Data>>> : <Data>(action: SchemaAction<Data, Context, Schema>) => (state: FormState<Data, Err, z.inferFlattenedErrors<Schema>>, payload: FormData) => Promise<Flatten<InvalidState<z.inferFlattenedErrors<Schema>> | FailureState<Err> | SuccessState<Data>>>;
|
|
29
32
|
/**
|
|
30
33
|
* A chainable context enhancing helper.
|
|
31
34
|
* @param middleware A function which receives the current context, and returns an object which will be added to the context.
|
|
@@ -40,19 +43,11 @@ type FormActionBuilder<Schema extends ZodSchema = ZodUndefined, Err = Error, Con
|
|
|
40
43
|
* @param processError A function which receives action's errors.
|
|
41
44
|
* @returns FormActionBuilder
|
|
42
45
|
*/
|
|
43
|
-
error: <Err>(processError: (
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
* @private
|
|
48
|
-
*/
|
|
49
|
-
middleware?: MiddlewareFn<Context, NewContext>[],
|
|
50
|
-
/**
|
|
51
|
-
* @private
|
|
52
|
-
*/
|
|
53
|
-
processError?: (error: unknown) => Err): FormActionBuilder<Schema, Err, Context>;
|
|
54
|
-
type ZodErrorMessages<Schema extends ZodSchema> = {
|
|
55
|
-
[k in keyof z.infer<Schema>]?: string;
|
|
46
|
+
error: <Err>(processError: (params: {
|
|
47
|
+
error: unknown;
|
|
48
|
+
ctx: Context;
|
|
49
|
+
}) => Err) => FormActionBuilder<Schema, Err, Context>;
|
|
56
50
|
};
|
|
51
|
+
declare const formAction: FormActionBuilder<z.ZodObject<{}, "strip", z.ZodTypeAny, {}, {}>, Error, InitialContext>;
|
|
57
52
|
|
|
58
|
-
export { FormState, formAction };
|
|
53
|
+
export { FailureState, FormState, InvalidState, SuccessState, formAction };
|
package/dist/index.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
function
|
|
1
|
+
function p(a){function o(e){return{type:"success",data:e,error:null,validationError:null}}function n(e){return{type:"failure",data:null,error:e,validationError:null}}function l(e){return{type:"invalid",data:null,error:null,validationError:e}}return(e,s)=>a({success:o,failure:n,invalid:l})(e,s)}import{z as D}from"zod";import{zfd as h}from"zod-form-data";function u(a,o=[],n){async function l(t){let r={formData:t};for(let i of o){let d=await i({ctx:r});r={...r,...d}}return r}let e=t=>p(({success:r,failure:i})=>async(d,x)=>{let m=await l(x);try{return r(await t({ctx:m}))}catch(c){if(n)return i(n({error:c,ctx:m}));throw c}}),s=t=>p(({success:r,failure:i,invalid:d})=>{let x=h.formData(a);return async(m,c)=>{let E=await l(c),S=x.safeParse(c);if(!S.success)return d(S.error.flatten());let y=S.data;try{return r(await t({input:y,ctx:E}))}catch(C){if(n)return i(n({error:C,ctx:E}));throw C}}});return{input(t){let r=a.merge(t);return u(r,o)},use(t){return u(a,[...o,t])},error(t){return u(a,o,t)},run:Object.keys(a.shape).length===0?e:s}}var j=u(D.object({}));export{p as createFormAction,j as formAction};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-form-action",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "State management helpers for the react form actions.",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -43,7 +43,8 @@
|
|
|
43
43
|
"peerDependencies": {
|
|
44
44
|
"react": ">=18.2",
|
|
45
45
|
"react-dom": ">=18.2",
|
|
46
|
-
"zod": "^3"
|
|
46
|
+
"zod": "^3",
|
|
47
|
+
"zod-form-data": "^2"
|
|
47
48
|
},
|
|
48
49
|
"devDependencies": {
|
|
49
50
|
"@types/react": "^18.2.37",
|