@goodie-forms/react 1.2.6-alpha → 1.3.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 +169 -0
- package/dist/components/FieldRenderer.d.ts +4 -9
- package/dist/components/FieldRenderer.d.ts.map +1 -1
- package/dist/hooks/useForm.d.ts +0 -4
- package/dist/hooks/useForm.d.ts.map +1 -1
- package/dist/hooks/useFormField.d.ts +1 -1
- package/dist/hooks/useFormField.d.ts.map +1 -1
- package/dist/index.d.ts +0 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +111 -135
- package/dist/index.js.map +1 -1
- package/package.json +12 -2
- package/dist/hooks/useRenderControl.d.ts +0 -5
- package/dist/hooks/useRenderControl.d.ts.map +0 -1
package/README.md
ADDED
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
<!-- Logo -->
|
|
2
|
+
<p align="center">
|
|
3
|
+
<img src="https://raw.githubusercontent.com/iGoodie/goodie-forms/master/.github/assets/logo.svg" height="200px" alt="Logo"/>
|
|
4
|
+
</p>
|
|
5
|
+
|
|
6
|
+
<!-- Slogan -->
|
|
7
|
+
<p align="center">
|
|
8
|
+
An unopinionated modern form state and data management library
|
|
9
|
+
</p>
|
|
10
|
+
<!-- Badges -->
|
|
11
|
+
<p align="center">
|
|
12
|
+
|
|
13
|
+
<!-- Main Badges -->
|
|
14
|
+
<img src="https://raw.githubusercontent.com/iGoodie/paper-editor/master/.github/assets/main-badge.svg" height="20px"/>
|
|
15
|
+
<a href="https://www.npmjs.com/package/@goodie-forms/react">
|
|
16
|
+
<img src="https://img.shields.io/npm/v/@goodie-forms/react"/>
|
|
17
|
+
</a>
|
|
18
|
+
<a href="https://github.com/iGoodie/goodie-forms/tags">
|
|
19
|
+
<img src="https://img.shields.io/github/v/tag/iGoodie/goodie-forms"/>
|
|
20
|
+
</a>
|
|
21
|
+
<a href="https://github.com/iGoodie/goodie-forms">
|
|
22
|
+
<img src="https://img.shields.io/github/languages/top/iGoodie/goodie-forms"/>
|
|
23
|
+
</a>
|
|
24
|
+
|
|
25
|
+
<br/>
|
|
26
|
+
|
|
27
|
+
<!-- Github Badges -->
|
|
28
|
+
<img src="https://raw.githubusercontent.com/iGoodie/paper-editor/master/.github/assets/github-badge.svg" height="20px"/>
|
|
29
|
+
<a href="https://github.com/iGoodie/goodie-forms/commits/master">
|
|
30
|
+
<img src="https://img.shields.io/github/last-commit/iGoodie/goodie-forms"/>
|
|
31
|
+
</a>
|
|
32
|
+
<a href="https://github.com/iGoodie/goodie-forms/issues">
|
|
33
|
+
<img src="https://img.shields.io/github/issues/iGoodie/goodie-forms"/>
|
|
34
|
+
</a>
|
|
35
|
+
<a href="https://github.com/iGoodie/goodie-forms/tree/master/src">
|
|
36
|
+
<img src="https://img.shields.io/github/languages/code-size/iGoodie/goodie-forms"/>
|
|
37
|
+
</a>
|
|
38
|
+
|
|
39
|
+
<br/>
|
|
40
|
+
|
|
41
|
+
<!-- Support Badges -->
|
|
42
|
+
<img src="https://raw.githubusercontent.com/iGoodie/paper-editor/master/.github/assets/support-badge.svg" height="20px"/>
|
|
43
|
+
<a href="https://discord.gg/KNxxdvN">
|
|
44
|
+
<img src="https://img.shields.io/discord/610497509437210624?label=discord"/>
|
|
45
|
+
</a>
|
|
46
|
+
<a href="https://www.patreon.com/iGoodie">
|
|
47
|
+
<img src="https://img.shields.io/endpoint.svg?url=https%3A%2F%2Fshieldsio-patreon.vercel.app%2Fapi%3Fusername%3DiGoodie%26type%3Dpatrons"/>
|
|
48
|
+
</a>
|
|
49
|
+
</p>
|
|
50
|
+
|
|
51
|
+
# Description
|
|
52
|
+
|
|
53
|
+
React package of Goodie Forms.
|
|
54
|
+
|
|
55
|
+
# Quick Example
|
|
56
|
+
|
|
57
|
+
```tsx
|
|
58
|
+
import { useForm } from "@goodie-forms/react";
|
|
59
|
+
import z from "zod";
|
|
60
|
+
|
|
61
|
+
// 1. Define a schema for your form data
|
|
62
|
+
const userRegisterSchema = z.object({
|
|
63
|
+
name: z.string().min(1, "Name is required"),
|
|
64
|
+
email: z.string().email("Invalid email address"),
|
|
65
|
+
password: z.string().min(6, "Password must be at least 6 characters"),
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
export function App() {
|
|
69
|
+
// 2. Create a form with the schema
|
|
70
|
+
const form = useForm(
|
|
71
|
+
{
|
|
72
|
+
validationSchema: userRegisterSchema,
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
validationMode: "onBlur",
|
|
76
|
+
revalidationMode: "onChange",
|
|
77
|
+
},
|
|
78
|
+
);
|
|
79
|
+
|
|
80
|
+
// 3. Create a submit handler
|
|
81
|
+
const handleSubmit = form.createSubmitHandler(async (data) => {
|
|
82
|
+
console.log("Form submitted successfully with data:", data);
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
return (
|
|
86
|
+
// 4. Bind submit handler to the form element
|
|
87
|
+
<form onClick={handleSubmit}>
|
|
88
|
+
{/* 5. Render fields */}
|
|
89
|
+
<FieldRenderer
|
|
90
|
+
form={form}
|
|
91
|
+
path={form.path.of("name")}
|
|
92
|
+
defaultValue=""
|
|
93
|
+
render={({ fieldProps, field, form }) => (
|
|
94
|
+
<div>
|
|
95
|
+
<input
|
|
96
|
+
{...fieldProps}
|
|
97
|
+
type="text"
|
|
98
|
+
disabled={form.controller.isSubmitting}
|
|
99
|
+
/>
|
|
100
|
+
{field.issues.length > 0 && (
|
|
101
|
+
<div className="issues">
|
|
102
|
+
{field.issues.map((issue) => (
|
|
103
|
+
<p key={issue.id}>{issue.message}</p>
|
|
104
|
+
))}
|
|
105
|
+
</div>
|
|
106
|
+
)}
|
|
107
|
+
</div>
|
|
108
|
+
)}
|
|
109
|
+
/>
|
|
110
|
+
|
|
111
|
+
{/* 5. Render fields */}
|
|
112
|
+
<FieldRenderer
|
|
113
|
+
form={form}
|
|
114
|
+
path={form.path.of("email")}
|
|
115
|
+
defaultValue=""
|
|
116
|
+
render={({ fieldProps, field }) => (
|
|
117
|
+
<div>
|
|
118
|
+
<input
|
|
119
|
+
{...fieldProps}
|
|
120
|
+
type="email"
|
|
121
|
+
disabled={form.controller.isSubmitting}
|
|
122
|
+
/>
|
|
123
|
+
{field.issues.length > 0 && (
|
|
124
|
+
<div className="issues">
|
|
125
|
+
{field.issues.map((issue) => (
|
|
126
|
+
<p key={issue.id}>{issue.message}</p>
|
|
127
|
+
))}
|
|
128
|
+
</div>
|
|
129
|
+
)}
|
|
130
|
+
</div>
|
|
131
|
+
)}
|
|
132
|
+
/>
|
|
133
|
+
|
|
134
|
+
{/* 5. Render fields */}
|
|
135
|
+
<FieldRenderer
|
|
136
|
+
form={form}
|
|
137
|
+
path={form.path.of("password")}
|
|
138
|
+
defaultValue=""
|
|
139
|
+
render={({ fieldProps, field }) => (
|
|
140
|
+
<div>
|
|
141
|
+
<input
|
|
142
|
+
{...fieldProps}
|
|
143
|
+
type="password"
|
|
144
|
+
disabled={form.controller.isSubmitting}
|
|
145
|
+
/>
|
|
146
|
+
{field.issues.length > 0 && (
|
|
147
|
+
<div className="issues">
|
|
148
|
+
{field.issues.map((issue) => (
|
|
149
|
+
<p key={issue.id}>{issue.message}</p>
|
|
150
|
+
))}
|
|
151
|
+
</div>
|
|
152
|
+
)}
|
|
153
|
+
</div>
|
|
154
|
+
)}
|
|
155
|
+
/>
|
|
156
|
+
|
|
157
|
+
<button type="submit">Submit</button>
|
|
158
|
+
</form>
|
|
159
|
+
);
|
|
160
|
+
}
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
## License
|
|
164
|
+
|
|
165
|
+
© 2026 Taha Anılcan Metinyurt (iGoodie)
|
|
166
|
+
|
|
167
|
+
For any part of this work for which the license is applicable, this work is licensed under the [Attribution-ShareAlike 4.0 International](http://creativecommons.org/licenses/by-sa/4.0/) license. (See LICENSE).
|
|
168
|
+
|
|
169
|
+
<a rel="license" href="http://creativecommons.org/licenses/by-sa/4.0/"><img alt="Creative Commons License" style="border-width:0" src="https://i.creativecommons.org/l/by-sa/4.0/88x31.png" /></a>
|
|
@@ -13,18 +13,13 @@ export interface RenderParams<TOutput extends object, TValue> {
|
|
|
13
13
|
field: FormField<TOutput, TValue>;
|
|
14
14
|
form: UseForm<TOutput>;
|
|
15
15
|
}
|
|
16
|
-
|
|
17
|
-
defaultValue?: Suppliable<TValue>;
|
|
18
|
-
} : {
|
|
19
|
-
defaultValue: Suppliable<TValue>;
|
|
20
|
-
};
|
|
21
|
-
export type FieldRendererProps<TOutput extends object, TPath extends FieldPath.Segments> = DefaultValueProps<FieldPath.Resolve<TOutput, TPath>> & {
|
|
16
|
+
export interface FieldRendererProps<TOutput extends object, TPath extends FieldPath.Segments> {
|
|
22
17
|
form: UseForm<TOutput>;
|
|
23
18
|
path: TPath;
|
|
19
|
+
defaultValue?: Suppliable<FieldPath.Resolve<TOutput, TPath>>;
|
|
24
20
|
overrideInitialValue?: boolean;
|
|
25
|
-
|
|
21
|
+
unregisterOnUnmount?: boolean;
|
|
26
22
|
render: (params: RenderParams<TOutput, FieldPath.Resolve<TOutput, TPath>>) => ReactNode;
|
|
27
|
-
}
|
|
23
|
+
}
|
|
28
24
|
export declare function FieldRenderer<TOutput extends object, const TPath extends FieldPath.Segments>(props: FieldRendererProps<TOutput, TPath>): import("react/jsx-runtime").JSX.Element;
|
|
29
|
-
export {};
|
|
30
25
|
//# sourceMappingURL=FieldRenderer.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FieldRenderer.d.ts","sourceRoot":"","sources":["../../src/components/FieldRenderer.tsx"],"names":[],"mappings":"AAAA,OAAO,EACL,YAAY,EACZ,SAAS,EACT,SAAS,EACT,UAAU,EACX,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,GAAG,EAAqB,MAAM,OAAO,CAAC;AACvE,OAAO,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAI3C,MAAM,WAAW,YAAY,CAAC,OAAO,SAAS,MAAM,EAAE,MAAM;IAC1D,UAAU,EAAE;QACV,GAAG,EAAE,GAAG,CAAC,GAAG,GAAG,IAAI,CAAC,CAAC;QAErB,IAAI,EAAE,MAAM,CAAC;QAEb,KAAK,EAAE,YAAY,CAAC,MAAM,CAAC,GAAG,SAAS,CAAC;QAExC,QAAQ,EAAE,CAAC,KAAK,EAAE,WAAW,CAAC,WAAW,CAAC,GAAG,MAAM,KAAK,IAAI,CAAC;QAC7D,OAAO,EAAE,MAAM,IAAI,CAAC;QACpB,MAAM,EAAE,MAAM,IAAI,CAAC;KACpB,CAAC;IAEF,KAAK,EAAE,SAAS,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;IAElC,IAAI,EAAE,OAAO,CAAC,OAAO,CAAC,CAAC;CACxB;AAED,
|
|
1
|
+
{"version":3,"file":"FieldRenderer.d.ts","sourceRoot":"","sources":["../../src/components/FieldRenderer.tsx"],"names":[],"mappings":"AAAA,OAAO,EACL,YAAY,EACZ,SAAS,EACT,SAAS,EACT,UAAU,EACX,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,GAAG,EAAqB,MAAM,OAAO,CAAC;AACvE,OAAO,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAI3C,MAAM,WAAW,YAAY,CAAC,OAAO,SAAS,MAAM,EAAE,MAAM;IAC1D,UAAU,EAAE;QACV,GAAG,EAAE,GAAG,CAAC,GAAG,GAAG,IAAI,CAAC,CAAC;QAErB,IAAI,EAAE,MAAM,CAAC;QAEb,KAAK,EAAE,YAAY,CAAC,MAAM,CAAC,GAAG,SAAS,CAAC;QAExC,QAAQ,EAAE,CAAC,KAAK,EAAE,WAAW,CAAC,WAAW,CAAC,GAAG,MAAM,KAAK,IAAI,CAAC;QAC7D,OAAO,EAAE,MAAM,IAAI,CAAC;QACpB,MAAM,EAAE,MAAM,IAAI,CAAC;KACpB,CAAC;IAEF,KAAK,EAAE,SAAS,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;IAElC,IAAI,EAAE,OAAO,CAAC,OAAO,CAAC,CAAC;CACxB;AAED,MAAM,WAAW,kBAAkB,CACjC,OAAO,SAAS,MAAM,EACtB,KAAK,SAAS,SAAS,CAAC,QAAQ;IAEhC,IAAI,EAAE,OAAO,CAAC,OAAO,CAAC,CAAC;IACvB,IAAI,EAAE,KAAK,CAAC;IACZ,YAAY,CAAC,EAAE,UAAU,CAAC,SAAS,CAAC,OAAO,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC,CAAC;IAC7D,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAC/B,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,MAAM,EAAE,CACN,MAAM,EAAE,YAAY,CAAC,OAAO,EAAE,SAAS,CAAC,OAAO,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC,KAC7D,SAAS,CAAC;CAChB;AAED,wBAAgB,aAAa,CAC3B,OAAO,SAAS,MAAM,EACtB,KAAK,CAAC,KAAK,SAAS,SAAS,CAAC,QAAQ,EACtC,KAAK,EAAE,kBAAkB,CAAC,OAAO,EAAE,KAAK,CAAC,2CAqF1C"}
|
package/dist/hooks/useForm.d.ts
CHANGED
|
@@ -2,15 +2,11 @@ import { FormController } from '../../../core/src';
|
|
|
2
2
|
export declare function useForm<TOutput extends object>(formConfigs: FormController.Configs<TOutput>, hookConfigs?: {
|
|
3
3
|
validateMode?: "onChange" | "onBlur" | "onSubmit";
|
|
4
4
|
revalidateMode?: "onChange" | "onBlur" | "onSubmit";
|
|
5
|
-
watchIssues?: boolean;
|
|
6
|
-
watchValues?: boolean;
|
|
7
5
|
}): {
|
|
8
6
|
formConfigs: FormController.Configs<TOutput>;
|
|
9
7
|
hookConfigs: {
|
|
10
8
|
validateMode?: "onChange" | "onBlur" | "onSubmit";
|
|
11
9
|
revalidateMode?: "onChange" | "onBlur" | "onSubmit";
|
|
12
|
-
watchIssues?: boolean;
|
|
13
|
-
watchValues?: boolean;
|
|
14
10
|
} | undefined;
|
|
15
11
|
controller: FormController<TOutput>;
|
|
16
12
|
path: import('../../../core/src').FieldPathBuilder<TOutput>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useForm.d.ts","sourceRoot":"","sources":["../../src/hooks/useForm.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"useForm.d.ts","sourceRoot":"","sources":["../../src/hooks/useForm.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAIpD,wBAAgB,OAAO,CAAC,OAAO,SAAS,MAAM,EAC5C,WAAW,EAAE,cAAc,CAAC,OAAO,CAAC,OAAO,CAAC,EAC5C,WAAW,CAAC,EAAE;IACZ,YAAY,CAAC,EAAE,UAAU,GAAG,QAAQ,GAAG,UAAU,CAAC;IAClD,cAAc,CAAC,EAAE,UAAU,GAAG,QAAQ,GAAG,UAAU,CAAC;CACrD;;;uBAFgB,UAAU,GAAG,QAAQ,GAAG,UAAU;yBAChC,UAAU,GAAG,QAAQ,GAAG,UAAU;;;;;;iBAgC9B,CAAC,4RACX,CAAC,aACD,WAAW;;;;;;;;;;;;;UAAsC,CAAC,MAAM,CAAC;EAqBvE;AAED,MAAM,MAAM,OAAO,CAAC,OAAO,SAAS,MAAM,IAAI,UAAU,CACtD,OAAO,OAAO,CAAC,OAAO,CAAC,CACxB,CAAC"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { FieldPath, FormField } from '../../../core/src';
|
|
2
2
|
import { UseForm } from '../hooks/useForm';
|
|
3
3
|
export declare function useFormField<TOutput extends object, TPath extends FieldPath.Segments>(form: UseForm<TOutput>, path: TPath): FormField<TOutput, FieldPath.Resolve<TOutput, TPath>> | undefined;
|
|
4
|
-
export declare function useFormField<TOutput extends object, TPath extends FieldPath.Segments>(form: UseForm<TOutput>, path: TPath,
|
|
4
|
+
export declare function useFormField<TOutput extends object, TPath extends FieldPath.Segments>(form: UseForm<TOutput>, path: TPath, registerConfig: Parameters<typeof form.controller.registerField<TPath>>[1]): FormField<TOutput, FieldPath.Resolve<TOutput, TPath>>;
|
|
5
5
|
//# sourceMappingURL=useFormField.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useFormField.d.ts","sourceRoot":"","sources":["../../src/hooks/useFormField.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAE1D,OAAO,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"useFormField.d.ts","sourceRoot":"","sources":["../../src/hooks/useFormField.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAE1D,OAAO,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAI3C,wBAAgB,YAAY,CAC1B,OAAO,SAAS,MAAM,EACtB,KAAK,SAAS,SAAS,CAAC,QAAQ,EAEhC,IAAI,EAAE,OAAO,CAAC,OAAO,CAAC,EACtB,IAAI,EAAE,KAAK,GACV,SAAS,CAAC,OAAO,EAAE,SAAS,CAAC,OAAO,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC,GAAG,SAAS,CAAC;AAErE,wBAAgB,YAAY,CAC1B,OAAO,SAAS,MAAM,EACtB,KAAK,SAAS,SAAS,CAAC,QAAQ,EAEhC,IAAI,EAAE,OAAO,CAAC,OAAO,CAAC,EACtB,IAAI,EAAE,KAAK,EACX,cAAc,EAAE,UAAU,CAAC,OAAO,IAAI,CAAC,UAAU,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,GACzE,SAAS,CAAC,OAAO,EAAE,SAAS,CAAC,OAAO,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC,CAAC"}
|
package/dist/index.d.ts
CHANGED
|
@@ -2,6 +2,5 @@ export * from './hooks/useForm';
|
|
|
2
2
|
export * from './hooks/useFormField';
|
|
3
3
|
export * from './hooks/useFieldValue';
|
|
4
4
|
export * from './hooks/useFieldIssues';
|
|
5
|
-
export * from './hooks/useRenderControl';
|
|
6
5
|
export * from './components/FieldRenderer';
|
|
7
6
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,iBAAiB,CAAC;AAChC,cAAc,sBAAsB,CAAC;AACrC,cAAc,uBAAuB,CAAC;AACtC,cAAc,wBAAwB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,iBAAiB,CAAC;AAChC,cAAc,sBAAsB,CAAC;AACrC,cAAc,uBAAuB,CAAC;AACtC,cAAc,wBAAwB,CAAC;AAEvC,cAAc,4BAA4B,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -1,164 +1,141 @@
|
|
|
1
|
-
import { FormController as
|
|
2
|
-
import { useRef as
|
|
3
|
-
import { jsx as
|
|
4
|
-
function
|
|
5
|
-
const e =
|
|
6
|
-
(
|
|
7
|
-
e.current++,
|
|
1
|
+
import { FormController as V, FieldPath as i } from "@goodie-forms/core";
|
|
2
|
+
import { useRef as v, useCallback as d, useSyncExternalStore as f, useState as g, useEffect as m } from "react";
|
|
3
|
+
import { jsx as U, Fragment as I } from "react/jsx-runtime";
|
|
4
|
+
function a(u, n) {
|
|
5
|
+
const e = v(0), l = d(
|
|
6
|
+
(r) => u(() => {
|
|
7
|
+
e.current++, r();
|
|
8
8
|
}),
|
|
9
|
-
[
|
|
10
|
-
),
|
|
11
|
-
return
|
|
9
|
+
[u]
|
|
10
|
+
), o = d(() => e.current, []);
|
|
11
|
+
return f(l, o, o), n();
|
|
12
12
|
}
|
|
13
|
-
function
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
};
|
|
18
|
-
}
|
|
19
|
-
function E(n, t) {
|
|
20
|
-
const [e] = F(() => new q(n)), s = f(
|
|
21
|
-
(r) => {
|
|
22
|
-
const d = () => {
|
|
23
|
-
};
|
|
24
|
-
return v(
|
|
25
|
-
e.events.on("submissionStatusChange", r),
|
|
26
|
-
t?.watchIssues ? e.events.on("fieldIssuesUpdated", r) : d,
|
|
27
|
-
t?.watchValues ? e.events.on("fieldValueChanged", r) : d
|
|
28
|
-
);
|
|
29
|
-
},
|
|
30
|
-
[e, t?.watchIssues, t?.watchValues]
|
|
13
|
+
function M(u, n) {
|
|
14
|
+
const [e] = g(() => new V(u)), l = d(
|
|
15
|
+
(t) => e.events.on("submissionStatusChange", t),
|
|
16
|
+
[e]
|
|
31
17
|
);
|
|
32
|
-
|
|
33
|
-
const
|
|
34
|
-
(
|
|
18
|
+
a(l, () => e);
|
|
19
|
+
const o = () => f(
|
|
20
|
+
(t) => e.events.on("fieldValueChanged", t),
|
|
35
21
|
() => e.data,
|
|
36
22
|
() => e.data
|
|
37
|
-
),
|
|
38
|
-
(
|
|
23
|
+
), r = () => f(
|
|
24
|
+
(t) => e.events.on("fieldIssuesUpdated", t),
|
|
39
25
|
() => e.issues,
|
|
40
26
|
() => e.issues
|
|
41
|
-
),
|
|
42
|
-
(
|
|
43
|
-
|
|
27
|
+
), s = (t, F) => a(
|
|
28
|
+
(b) => e.events.on(t, (...q) => {
|
|
29
|
+
F?.(...q), b();
|
|
44
30
|
}),
|
|
45
31
|
() => {
|
|
46
32
|
}
|
|
47
33
|
);
|
|
48
34
|
return {
|
|
49
|
-
formConfigs:
|
|
50
|
-
hookConfigs:
|
|
35
|
+
formConfigs: u,
|
|
36
|
+
hookConfigs: n,
|
|
51
37
|
controller: e,
|
|
52
38
|
path: e.path,
|
|
53
|
-
watchValues:
|
|
54
|
-
watchIssues:
|
|
55
|
-
watchEvent:
|
|
39
|
+
watchValues: o,
|
|
40
|
+
watchIssues: r,
|
|
41
|
+
watchEvent: s
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
function c(...u) {
|
|
45
|
+
return () => {
|
|
46
|
+
for (const n of u)
|
|
47
|
+
n();
|
|
56
48
|
};
|
|
57
49
|
}
|
|
58
|
-
function
|
|
59
|
-
const { controller:
|
|
60
|
-
|
|
61
|
-
const
|
|
50
|
+
function R(u, n, e) {
|
|
51
|
+
const { controller: l } = u;
|
|
52
|
+
g(() => (!l.getField(n) && e && l.registerField(n, e), null));
|
|
53
|
+
const o = d(
|
|
62
54
|
(r) => {
|
|
63
|
-
const { events:
|
|
64
|
-
return
|
|
65
|
-
|
|
66
|
-
|
|
55
|
+
const { events: s } = l;
|
|
56
|
+
return c(
|
|
57
|
+
s.on("fieldRegistered", (t) => {
|
|
58
|
+
i.equals(t, n) && r();
|
|
67
59
|
}),
|
|
68
|
-
|
|
69
|
-
|
|
60
|
+
s.on("fieldUnregistered", (t) => {
|
|
61
|
+
i.equals(t, n) && r();
|
|
70
62
|
}),
|
|
71
|
-
|
|
72
|
-
(
|
|
63
|
+
s.on("fieldValueChanged", (t) => {
|
|
64
|
+
(i.equals(t, n) || i.isDescendant(t, n)) && r();
|
|
73
65
|
}),
|
|
74
|
-
|
|
75
|
-
|
|
66
|
+
s.on("fieldTouchUpdated", (t) => {
|
|
67
|
+
i.equals(t, n) && r();
|
|
76
68
|
}),
|
|
77
|
-
|
|
78
|
-
|
|
69
|
+
s.on("fieldDirtyUpdated", (t) => {
|
|
70
|
+
i.equals(t, n) && r();
|
|
79
71
|
}),
|
|
80
|
-
|
|
81
|
-
|
|
72
|
+
s.on("fieldIssuesUpdated", (t) => {
|
|
73
|
+
i.equals(t, n) && r();
|
|
82
74
|
})
|
|
83
75
|
);
|
|
84
76
|
},
|
|
85
|
-
[
|
|
86
|
-
)
|
|
87
|
-
return a(
|
|
77
|
+
[l, n]
|
|
78
|
+
);
|
|
79
|
+
return a(o, () => l.getField(n));
|
|
88
80
|
}
|
|
89
|
-
function
|
|
90
|
-
const { controller: e } =
|
|
91
|
-
(
|
|
92
|
-
const { events:
|
|
93
|
-
return
|
|
94
|
-
|
|
95
|
-
|
|
81
|
+
function S(u, n) {
|
|
82
|
+
const { controller: e } = u, l = d(
|
|
83
|
+
(r) => {
|
|
84
|
+
const { events: s } = e;
|
|
85
|
+
return c(
|
|
86
|
+
s.on("fieldRegistered", (t) => {
|
|
87
|
+
i.equals(n, t) && r();
|
|
96
88
|
}),
|
|
97
|
-
|
|
98
|
-
|
|
89
|
+
s.on("fieldUnregistered", (t) => {
|
|
90
|
+
i.equals(n, t) && r();
|
|
99
91
|
}),
|
|
100
|
-
|
|
101
|
-
(
|
|
92
|
+
s.on("fieldValueChanged", (t) => {
|
|
93
|
+
(i.equals(t, n) || i.isDescendant(t, n)) && r();
|
|
102
94
|
})
|
|
103
95
|
);
|
|
104
96
|
},
|
|
105
|
-
[e,
|
|
106
|
-
),
|
|
107
|
-
return
|
|
97
|
+
[e, n]
|
|
98
|
+
), o = d(() => e.getField(n)?.value, [e, n]);
|
|
99
|
+
return f(l, o, o);
|
|
108
100
|
}
|
|
109
|
-
function
|
|
110
|
-
const { controller: e } =
|
|
111
|
-
(
|
|
112
|
-
const { events:
|
|
113
|
-
return
|
|
114
|
-
|
|
115
|
-
|
|
101
|
+
function k(u, n) {
|
|
102
|
+
const { controller: e } = u, l = d(
|
|
103
|
+
(r) => {
|
|
104
|
+
const { events: s } = e;
|
|
105
|
+
return c(
|
|
106
|
+
s.on("fieldRegistered", (t) => {
|
|
107
|
+
i.equals(n, t) && r();
|
|
116
108
|
}),
|
|
117
|
-
|
|
118
|
-
|
|
109
|
+
s.on("fieldUnregistered", (t) => {
|
|
110
|
+
i.equals(n, t) && r();
|
|
119
111
|
}),
|
|
120
|
-
|
|
121
|
-
|
|
112
|
+
s.on("fieldIssuesUpdated", (t) => {
|
|
113
|
+
i.equals(n, t) && r();
|
|
122
114
|
})
|
|
123
115
|
);
|
|
124
116
|
},
|
|
125
|
-
[e,
|
|
126
|
-
),
|
|
127
|
-
return
|
|
128
|
-
}
|
|
129
|
-
function W() {
|
|
130
|
-
const [, n] = F(0), t = m(0), e = m(!1);
|
|
131
|
-
t.current++;
|
|
132
|
-
const s = () => {
|
|
133
|
-
e.current || (e.current = !0, queueMicrotask(() => {
|
|
134
|
-
I(() => {
|
|
135
|
-
n((u) => u + 1);
|
|
136
|
-
}), e.current = !1;
|
|
137
|
-
}));
|
|
138
|
-
};
|
|
139
|
-
return {
|
|
140
|
-
renderCount: t.current,
|
|
141
|
-
forceRerender: s
|
|
142
|
-
};
|
|
117
|
+
[e, n]
|
|
118
|
+
), o = d(() => e.getField(n)?.issues ?? [], [e, n]);
|
|
119
|
+
return f(l, o, o);
|
|
143
120
|
}
|
|
144
|
-
function
|
|
145
|
-
const
|
|
146
|
-
overrideInitialValue:
|
|
147
|
-
defaultValue:
|
|
148
|
-
}),
|
|
121
|
+
function w(u) {
|
|
122
|
+
const n = v(null), e = R(u.form, u.path, {
|
|
123
|
+
overrideInitialValue: u.overrideInitialValue ?? !0,
|
|
124
|
+
defaultValue: u.defaultValue
|
|
125
|
+
}), l = u.form.controller.triedSubmitting ? u.form.hookConfigs?.revalidateMode ?? u.form.hookConfigs?.validateMode : u.form.hookConfigs?.validateMode, o = u.render({
|
|
149
126
|
fieldProps: {
|
|
150
|
-
ref:
|
|
127
|
+
ref: n,
|
|
151
128
|
name: e.stringPath,
|
|
152
129
|
value: e.value,
|
|
153
|
-
onChange(
|
|
154
|
-
let
|
|
155
|
-
if (typeof
|
|
156
|
-
const { target:
|
|
157
|
-
if (
|
|
158
|
-
|
|
130
|
+
onChange(r) {
|
|
131
|
+
let s;
|
|
132
|
+
if (typeof r == "object" && "target" in r) {
|
|
133
|
+
const { target: t } = r;
|
|
134
|
+
if (t !== e.boundElement || !("value" in t) || typeof t.value != "string") return;
|
|
135
|
+
s = t.value;
|
|
159
136
|
} else
|
|
160
|
-
|
|
161
|
-
e.setValue(
|
|
137
|
+
s = r;
|
|
138
|
+
e.setValue(s, {
|
|
162
139
|
shouldTouch: !0,
|
|
163
140
|
shouldMarkDirty: !0
|
|
164
141
|
});
|
|
@@ -167,29 +144,28 @@ function S(n) {
|
|
|
167
144
|
e.touch();
|
|
168
145
|
},
|
|
169
146
|
onBlur() {
|
|
170
|
-
(e.issues.length !== 0 ||
|
|
147
|
+
(e.issues.length !== 0 || l === "onBlur" || l === "onChange") && u.form.controller.validateField(u.path);
|
|
171
148
|
}
|
|
172
149
|
},
|
|
173
150
|
field: e,
|
|
174
|
-
form:
|
|
151
|
+
form: u.form
|
|
175
152
|
});
|
|
176
|
-
return
|
|
177
|
-
const { events:
|
|
178
|
-
return
|
|
179
|
-
|
|
180
|
-
!
|
|
153
|
+
return m(() => {
|
|
154
|
+
const { events: r } = u.form.controller;
|
|
155
|
+
return c(
|
|
156
|
+
r.on("fieldValueChanged", (s) => {
|
|
157
|
+
!i.equals(s, u.path) && !i.isDescendant(s, u.path) || (e.issues.length !== 0 || l === "onChange") && u.form.controller.validateField(u.path);
|
|
181
158
|
})
|
|
182
159
|
);
|
|
183
|
-
}, [
|
|
184
|
-
|
|
185
|
-
}), []), /* @__PURE__ */
|
|
160
|
+
}, [l]), m(() => (e.bindElement(n.current), () => {
|
|
161
|
+
u.unregisterOnUnmount && u.form.controller.unregisterField(u.path);
|
|
162
|
+
}), []), /* @__PURE__ */ U(I, { children: o });
|
|
186
163
|
}
|
|
187
164
|
export {
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
W as useRenderControl
|
|
165
|
+
w as FieldRenderer,
|
|
166
|
+
k as useFieldIssues,
|
|
167
|
+
S as useFieldValue,
|
|
168
|
+
M as useForm,
|
|
169
|
+
R as useFormField
|
|
194
170
|
};
|
|
195
171
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":["../src/hooks/useSyncMutableStore.ts","../src/utils/composeFns.ts","../src/hooks/useForm.tsx","../src/hooks/useFormField.tsx","../src/hooks/useFieldValue.ts","../src/hooks/useFieldIssues.ts","../src/hooks/useRenderControl.tsx","../src/components/FieldRenderer.tsx"],"sourcesContent":["import { useCallback, useRef, useSyncExternalStore } from \"react\";\r\n\r\nexport function useSyncMutableStore<T>(\r\n subscribe: (onVersionChange: () => void) => () => void,\r\n getValue: () => T,\r\n) {\r\n const versionRef = useRef(0);\r\n\r\n const subscribeWithVersion = useCallback(\r\n (onStoreChange: () => void) => {\r\n return subscribe(() => {\r\n versionRef.current++;\r\n onStoreChange();\r\n });\r\n },\r\n [subscribe],\r\n );\r\n\r\n const getSnapshot = useCallback(() => {\r\n return versionRef.current;\r\n }, []);\r\n\r\n useSyncExternalStore(subscribeWithVersion, getSnapshot, getSnapshot);\r\n\r\n return getValue();\r\n}\r\n","export function composeFns<TFns extends (() => void)[]>(...fns: TFns) {\r\n return () => {\r\n for (const fn of fns) {\r\n fn();\r\n }\r\n };\r\n}\r\n","import { FormController } from \"@goodie-forms/core\";\r\nimport { useCallback, useState, useSyncExternalStore } from \"react\";\r\nimport { useSyncMutableStore } from \"../hooks/useSyncMutableStore\";\r\nimport { composeFns } from \"../utils/composeFns\";\r\n\r\nexport function useForm<TOutput extends object>(\r\n formConfigs: FormController.Configs<TOutput>,\r\n hookConfigs?: {\r\n validateMode?: \"onChange\" | \"onBlur\" | \"onSubmit\";\r\n revalidateMode?: \"onChange\" | \"onBlur\" | \"onSubmit\";\r\n watchIssues?: boolean;\r\n watchValues?: boolean;\r\n },\r\n) {\r\n const [controller] = useState(() => new FormController(formConfigs));\r\n\r\n const subscribe = useCallback(\r\n (onVersionChange: () => void) => {\r\n const noop = () => {};\r\n\r\n return composeFns(\r\n controller.events.on(\"submissionStatusChange\", onVersionChange),\r\n hookConfigs?.watchIssues\r\n ? controller.events.on(\"fieldIssuesUpdated\", onVersionChange)\r\n : noop,\r\n hookConfigs?.watchValues\r\n ? controller.events.on(\"fieldValueChanged\", onVersionChange)\r\n : noop,\r\n );\r\n },\r\n [controller, hookConfigs?.watchIssues, hookConfigs?.watchValues],\r\n );\r\n\r\n useSyncMutableStore(subscribe, () => controller);\r\n\r\n const useWatchValues = () => {\r\n return useSyncExternalStore(\r\n (onStoreChange) =>\r\n controller.events.on(\"fieldValueChanged\", onStoreChange),\r\n () => controller.data,\r\n () => controller.data,\r\n );\r\n };\r\n\r\n const useWatchIssues = () => {\r\n return useSyncExternalStore(\r\n (onStoreChange) =>\r\n controller.events.on(\"fieldIssuesUpdated\", onStoreChange),\r\n () => controller.issues,\r\n () => controller.issues,\r\n );\r\n };\r\n\r\n const useWatchEvent = <E extends keyof typeof controller.events.events>(\r\n eventName: E,\r\n listener?: NonNullable<(typeof controller.events.events)[E]>[number],\r\n ) => {\r\n return useSyncMutableStore(\r\n (onVersionChange) =>\r\n controller.events.on(eventName, (...args: any[]) => {\r\n (listener as any)?.(...args);\r\n onVersionChange();\r\n }),\r\n () => undefined,\r\n );\r\n };\r\n\r\n return {\r\n formConfigs,\r\n hookConfigs,\r\n controller,\r\n path: controller.path,\r\n watchValues: useWatchValues,\r\n watchIssues: useWatchIssues,\r\n watchEvent: useWatchEvent,\r\n };\r\n}\r\n\r\nexport type UseForm<TOutput extends object> = ReturnType<\r\n typeof useForm<TOutput>\r\n>;\r\n","import { FieldPath, FormField } from \"@goodie-forms/core\";\r\nimport { useCallback, useRef, useState, useSyncExternalStore } from \"react\";\r\nimport { UseForm } from \"../hooks/useForm\";\r\nimport { composeFns } from \"../utils/composeFns\";\r\n\r\nexport function useFormField<\r\n TOutput extends object,\r\n TPath extends FieldPath.Segments,\r\n>(\r\n form: UseForm<TOutput>,\r\n path: TPath,\r\n): FormField<TOutput, FieldPath.Resolve<TOutput, TPath>> | undefined;\r\n\r\nexport function useFormField<\r\n TOutput extends object,\r\n TPath extends FieldPath.Segments,\r\n>(\r\n form: UseForm<TOutput>,\r\n path: TPath,\r\n bindingConfig: Parameters<typeof form.controller.registerField<TPath>>[1],\r\n): FormField<TOutput, FieldPath.Resolve<TOutput, TPath>>;\r\n\r\nexport function useFormField<\r\n TOutput extends object,\r\n TPath extends FieldPath.Segments,\r\n>(\r\n form: UseForm<TOutput>,\r\n path: TPath,\r\n bindingConfig?: Parameters<typeof form.controller.registerField<TPath>>[1],\r\n) {\r\n const { controller } = form;\r\n\r\n const version = useRef(0);\r\n\r\n useState(() => {\r\n let existing = controller.getField(path);\r\n\r\n if (!existing && bindingConfig) {\r\n controller.registerField(path, bindingConfig);\r\n }\r\n\r\n return null;\r\n });\r\n\r\n const subscribe = useCallback(\r\n (onStoreChange: () => void) => {\r\n const { events } = controller;\r\n\r\n return composeFns(\r\n events.on(\"fieldRegistered\", (_path) => {\r\n if (FieldPath.equals(_path, path)) {\r\n version.current++;\r\n onStoreChange();\r\n }\r\n }),\r\n events.on(\"fieldUnregistered\", (_path) => {\r\n if (FieldPath.equals(_path, path)) {\r\n version.current++;\r\n onStoreChange();\r\n }\r\n }),\r\n events.on(\"fieldValueChanged\", (changedPath) => {\r\n if (\r\n FieldPath.equals(changedPath, path) ||\r\n FieldPath.isDescendant(changedPath, path)\r\n ) {\r\n version.current++;\r\n onStoreChange();\r\n }\r\n }),\r\n events.on(\"fieldTouchUpdated\", (_path) => {\r\n if (FieldPath.equals(_path, path)) {\r\n version.current++;\r\n onStoreChange();\r\n }\r\n }),\r\n events.on(\"fieldDirtyUpdated\", (_path) => {\r\n if (FieldPath.equals(_path, path)) {\r\n version.current++;\r\n onStoreChange();\r\n }\r\n }),\r\n events.on(\"fieldIssuesUpdated\", (_path) => {\r\n if (FieldPath.equals(_path, path)) {\r\n version.current++;\r\n onStoreChange();\r\n }\r\n }),\r\n );\r\n },\r\n [controller, path],\r\n );\r\n\r\n const getSnapshot = useCallback(() => version.current, [controller, path]);\r\n\r\n useSyncExternalStore(subscribe, getSnapshot, getSnapshot);\r\n\r\n return controller.getField(path);\r\n}\r\n","import { FieldPath } from \"@goodie-forms/core\";\r\nimport { useCallback, useSyncExternalStore } from \"react\";\r\nimport { UseForm } from \"../hooks/useForm\";\r\nimport { composeFns } from \"../utils/composeFns\";\r\n\r\nexport function useFieldValue<\r\n TOutput extends object,\r\n TPath extends FieldPath.Segments,\r\n>(form: UseForm<TOutput>, path: TPath) {\r\n const { controller } = form;\r\n\r\n const subscribe = useCallback(\r\n (onStoreChange: () => void) => {\r\n const { events } = controller;\r\n\r\n return composeFns(\r\n events.on(\"fieldRegistered\", (fieldPath) => {\r\n if (FieldPath.equals(path, fieldPath)) {\r\n onStoreChange();\r\n }\r\n }),\r\n events.on(\"fieldUnregistered\", (fieldPath) => {\r\n if (FieldPath.equals(path, fieldPath)) {\r\n onStoreChange();\r\n }\r\n }),\r\n events.on(\"fieldValueChanged\", (changedPath) => {\r\n if (\r\n FieldPath.equals(changedPath, path) ||\r\n FieldPath.isDescendant(changedPath, path)\r\n ) {\r\n onStoreChange();\r\n }\r\n }),\r\n );\r\n },\r\n [controller, path],\r\n );\r\n\r\n const getSnapshot = useCallback(() => {\r\n return controller.getField(path)?.value;\r\n }, [controller, path]);\r\n\r\n return useSyncExternalStore(subscribe, getSnapshot, getSnapshot);\r\n}\r\n","import { FieldPath } from \"@goodie-forms/core\";\r\nimport { useCallback, useSyncExternalStore } from \"react\";\r\nimport { composeFns } from \"../utils/composeFns\";\r\nimport { UseForm } from \"./useForm\";\r\n\r\nexport function useFieldIssues<\r\n TOutput extends object,\r\n TPath extends FieldPath.Segments,\r\n>(form: UseForm<TOutput>, path: TPath) {\r\n const { controller } = form;\r\n\r\n const subscribe = useCallback(\r\n (onStoreChange: () => void) => {\r\n const { events } = controller;\r\n\r\n return composeFns(\r\n events.on(\"fieldRegistered\", (fieldPath) => {\r\n if (FieldPath.equals(path, fieldPath)) {\r\n onStoreChange();\r\n }\r\n }),\r\n events.on(\"fieldUnregistered\", (fieldPath) => {\r\n if (FieldPath.equals(path, fieldPath)) {\r\n onStoreChange();\r\n }\r\n }),\r\n events.on(\"fieldIssuesUpdated\", (fieldPath) => {\r\n if (FieldPath.equals(path, fieldPath)) {\r\n onStoreChange();\r\n }\r\n }),\r\n );\r\n },\r\n [controller, path],\r\n );\r\n\r\n const getSnapshot = useCallback(() => {\r\n return controller.getField(path)?.issues ?? [];\r\n }, [controller, path]);\r\n\r\n return useSyncExternalStore(subscribe, getSnapshot, getSnapshot);\r\n}\r\n","import { startTransition, useRef, useState } from \"react\";\r\n\r\nexport function useRenderControl() {\r\n const [, rerender] = useState(0);\r\n const renderCount = useRef(0);\r\n const renderScheduled = useRef(false);\r\n renderCount.current++;\r\n\r\n const scheduleRerender = () => {\r\n if (renderScheduled.current) return;\r\n renderScheduled.current = true;\r\n\r\n queueMicrotask(() => {\r\n startTransition(() => {\r\n rerender((i) => i + 1);\r\n });\r\n\r\n renderScheduled.current = false;\r\n });\r\n };\r\n\r\n return {\r\n renderCount: renderCount.current,\r\n forceRerender: scheduleRerender,\r\n };\r\n}\r\n","import {\r\n DeepReadonly,\r\n FieldPath,\r\n FormField,\r\n Suppliable,\r\n} from \"@goodie-forms/core\";\r\nimport { ChangeEvent, ReactNode, Ref, useEffect, useRef } from \"react\";\r\nimport { UseForm } from \"../hooks/useForm\";\r\nimport { useFormField } from \"../hooks/useFormField\";\r\nimport { composeFns } from \"../utils/composeFns\";\r\n\r\nexport interface RenderParams<TOutput extends object, TValue> {\r\n fieldProps: {\r\n ref: Ref<any | null>;\r\n\r\n name: string;\r\n\r\n value: DeepReadonly<TValue> | undefined;\r\n\r\n onChange: (event: ChangeEvent<EventTarget> | TValue) => void;\r\n onFocus: () => void;\r\n onBlur: () => void;\r\n };\r\n\r\n field: FormField<TOutput, TValue>;\r\n\r\n form: UseForm<TOutput>;\r\n}\r\n\r\ntype DefaultValueProps<TValue> = undefined extends TValue\r\n ? { defaultValue?: Suppliable<TValue> }\r\n : { defaultValue: Suppliable<TValue> };\r\n\r\nexport type FieldRendererProps<\r\n TOutput extends object,\r\n TPath extends FieldPath.Segments,\r\n> = DefaultValueProps<FieldPath.Resolve<TOutput, TPath>> & {\r\n form: UseForm<TOutput>;\r\n path: TPath;\r\n overrideInitialValue?: boolean;\r\n unbindOnUnmount?: boolean;\r\n render: (\r\n params: RenderParams<TOutput, FieldPath.Resolve<TOutput, TPath>>,\r\n ) => ReactNode;\r\n};\r\n\r\nexport function FieldRenderer<\r\n TOutput extends object,\r\n const TPath extends FieldPath.Segments,\r\n>(props: FieldRendererProps<TOutput, TPath>) {\r\n type TValue = FieldPath.Resolve<TOutput, TPath>;\r\n\r\n const elementRef = useRef<HTMLElement>(null);\r\n\r\n const field = useFormField(props.form, props.path, {\r\n overrideInitialValue: props.overrideInitialValue ?? true,\r\n defaultValue: props.defaultValue,\r\n })!;\r\n\r\n const currentValidateMode = props.form.controller.triedSubmitting\r\n ? (props.form.hookConfigs?.revalidateMode ??\r\n props.form.hookConfigs?.validateMode)\r\n : props.form.hookConfigs?.validateMode;\r\n\r\n const renderedJsx = props.render({\r\n fieldProps: {\r\n ref: elementRef,\r\n name: field.stringPath,\r\n value: field.value,\r\n onChange(arg) {\r\n let newValue: TValue;\r\n\r\n if (typeof arg === \"object\" && \"target\" in arg) {\r\n const { target } = arg;\r\n if (target !== field.boundElement) return;\r\n if (!(\"value\" in target)) return;\r\n if (typeof target.value !== \"string\") return;\r\n newValue = target.value as TValue;\r\n } else {\r\n newValue = arg;\r\n }\r\n\r\n field.setValue(newValue, {\r\n shouldTouch: true,\r\n shouldMarkDirty: true,\r\n });\r\n },\r\n onFocus() {\r\n field.touch();\r\n },\r\n onBlur() {\r\n if (\r\n field.issues.length !== 0 ||\r\n currentValidateMode === \"onBlur\" ||\r\n currentValidateMode === \"onChange\"\r\n ) {\r\n props.form.controller.validateField(props.path);\r\n }\r\n },\r\n },\r\n field: field as any,\r\n form: props.form,\r\n });\r\n\r\n useEffect(() => {\r\n const { events } = props.form.controller;\r\n\r\n return composeFns(\r\n events.on(\"fieldValueChanged\", (_path) => {\r\n if (\r\n !FieldPath.equals(_path, props.path) &&\r\n !FieldPath.isDescendant(_path, props.path)\r\n ) {\r\n return;\r\n }\r\n\r\n if (field.issues.length !== 0 || currentValidateMode === \"onChange\") {\r\n props.form.controller.validateField(props.path);\r\n }\r\n }),\r\n );\r\n }, [currentValidateMode]);\r\n\r\n useEffect(() => {\r\n field.bindElement(elementRef.current!);\r\n\r\n return () => {\r\n if (props.unbindOnUnmount) {\r\n props.form.controller.unregisterField(props.path);\r\n }\r\n };\r\n }, []);\r\n\r\n return <>{renderedJsx}</>;\r\n}\r\n\r\n/* ---- TESTS ---------------- */\r\n\r\n// function TestComp() {\r\n// const form = useForm<{ a?: { b: 99 } }>({});\r\n\r\n// const jsx = (\r\n// <>\r\n// <FieldRenderer\r\n// form={form}\r\n// path={form.paths.fromProxy((data) => data.a.b)}\r\n// defaultValue={() => 99 as const}\r\n// render={({ fieldProps, field }) => {\r\n// // ^?\r\n// return <input {...fieldProps} />;\r\n// }}\r\n// />\r\n\r\n// {/* defaultField olmayabilir, çünkü \"a\" nullable */}\r\n// <FieldRenderer\r\n// form={form}\r\n// path={form.paths.fromProxy((data) => data.a)}\r\n// render={({ ref, value, handlers, field }) => {\r\n// // ^?\r\n// return <></>;\r\n// }}\r\n// />\r\n\r\n// <FieldRenderer\r\n// form={form}\r\n// path={form.paths.fromStringPath(\"a.b\")}\r\n// defaultValue={() => 99 as const}\r\n// render={({ ref, value, handlers, field }) => {\r\n// // ^?\r\n// return <></>;\r\n// }}\r\n// />\r\n// </>\r\n// );\r\n// }\r\n"],"names":["useSyncMutableStore","subscribe","getValue","versionRef","useRef","subscribeWithVersion","useCallback","onStoreChange","getSnapshot","useSyncExternalStore","composeFns","fns","fn","useForm","formConfigs","hookConfigs","controller","useState","FormController","onVersionChange","noop","useWatchValues","useWatchIssues","useWatchEvent","eventName","listener","args","useFormField","form","path","bindingConfig","version","events","_path","FieldPath","changedPath","useFieldValue","fieldPath","useFieldIssues","useRenderControl","rerender","renderCount","renderScheduled","scheduleRerender","startTransition","i","FieldRenderer","props","elementRef","field","currentValidateMode","renderedJsx","arg","newValue","target","useEffect"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../src/hooks/useSyncMutableStore.ts","../src/hooks/useForm.tsx","../src/utils/composeFns.ts","../src/hooks/useFormField.tsx","../src/hooks/useFieldValue.ts","../src/hooks/useFieldIssues.ts","../src/components/FieldRenderer.tsx"],"sourcesContent":["import { useCallback, useRef, useSyncExternalStore } from \"react\";\r\n\r\nexport function useSyncMutableStore<T>(\r\n subscribe: (onVersionChange: () => void) => () => void,\r\n getValue: () => T,\r\n) {\r\n const versionRef = useRef(0);\r\n\r\n const subscribeWithVersion = useCallback(\r\n (onStoreChange: () => void) => {\r\n return subscribe(() => {\r\n versionRef.current++;\r\n onStoreChange();\r\n });\r\n },\r\n [subscribe],\r\n );\r\n\r\n const getSnapshot = useCallback(() => {\r\n return versionRef.current;\r\n }, []);\r\n\r\n useSyncExternalStore(subscribeWithVersion, getSnapshot, getSnapshot);\r\n\r\n return getValue();\r\n}\r\n","import { FormController } from \"@goodie-forms/core\";\r\nimport { useCallback, useState, useSyncExternalStore } from \"react\";\r\nimport { useSyncMutableStore } from \"../hooks/useSyncMutableStore\";\r\n\r\nexport function useForm<TOutput extends object>(\r\n formConfigs: FormController.Configs<TOutput>,\r\n hookConfigs?: {\r\n validateMode?: \"onChange\" | \"onBlur\" | \"onSubmit\";\r\n revalidateMode?: \"onChange\" | \"onBlur\" | \"onSubmit\";\r\n },\r\n) {\r\n const [controller] = useState(() => new FormController(formConfigs));\r\n\r\n const subscribe = useCallback(\r\n (onVersionChange: () => void) => {\r\n return controller.events.on(\"submissionStatusChange\", onVersionChange);\r\n },\r\n [controller],\r\n );\r\n\r\n useSyncMutableStore(subscribe, () => controller);\r\n\r\n const useWatchValues = () => {\r\n return useSyncExternalStore(\r\n (onStoreChange) =>\r\n controller.events.on(\"fieldValueChanged\", onStoreChange),\r\n () => controller.data,\r\n () => controller.data,\r\n );\r\n };\r\n\r\n const useWatchIssues = () => {\r\n return useSyncExternalStore(\r\n (onStoreChange) =>\r\n controller.events.on(\"fieldIssuesUpdated\", onStoreChange),\r\n () => controller.issues,\r\n () => controller.issues,\r\n );\r\n };\r\n\r\n const useWatchEvent = <E extends keyof typeof controller.events.events>(\r\n eventName: E,\r\n listener?: NonNullable<(typeof controller.events.events)[E]>[number],\r\n ) => {\r\n return useSyncMutableStore(\r\n (onVersionChange) =>\r\n controller.events.on(eventName, (...args: any[]) => {\r\n (listener as any)?.(...args);\r\n onVersionChange();\r\n }),\r\n () => undefined,\r\n );\r\n };\r\n\r\n return {\r\n formConfigs,\r\n hookConfigs,\r\n controller,\r\n path: controller.path,\r\n watchValues: useWatchValues,\r\n watchIssues: useWatchIssues,\r\n watchEvent: useWatchEvent,\r\n };\r\n}\r\n\r\nexport type UseForm<TOutput extends object> = ReturnType<\r\n typeof useForm<TOutput>\r\n>;\r\n","export function composeFns<TFns extends (() => void)[]>(...fns: TFns) {\r\n return () => {\r\n for (const fn of fns) {\r\n fn();\r\n }\r\n };\r\n}\r\n","import { FieldPath, FormField } from \"@goodie-forms/core\";\r\nimport { useCallback, useState } from \"react\";\r\nimport { UseForm } from \"../hooks/useForm\";\r\nimport { useSyncMutableStore } from \"../hooks/useSyncMutableStore\";\r\nimport { composeFns } from \"../utils/composeFns\";\r\n\r\nexport function useFormField<\r\n TOutput extends object,\r\n TPath extends FieldPath.Segments,\r\n>(\r\n form: UseForm<TOutput>,\r\n path: TPath,\r\n): FormField<TOutput, FieldPath.Resolve<TOutput, TPath>> | undefined;\r\n\r\nexport function useFormField<\r\n TOutput extends object,\r\n TPath extends FieldPath.Segments,\r\n>(\r\n form: UseForm<TOutput>,\r\n path: TPath,\r\n registerConfig: Parameters<typeof form.controller.registerField<TPath>>[1],\r\n): FormField<TOutput, FieldPath.Resolve<TOutput, TPath>>;\r\n\r\nexport function useFormField<\r\n TOutput extends object,\r\n TPath extends FieldPath.Segments,\r\n>(\r\n form: UseForm<TOutput>,\r\n path: TPath,\r\n registerConfig?: Parameters<typeof form.controller.registerField<TPath>>[1],\r\n) {\r\n const { controller } = form;\r\n\r\n useState(() => {\r\n let existing = controller.getField(path);\r\n\r\n if (!existing && registerConfig) {\r\n controller.registerField(path, registerConfig);\r\n }\r\n\r\n return null;\r\n });\r\n\r\n const subscribe = useCallback(\r\n (onVersionChange: () => void) => {\r\n const { events } = controller;\r\n\r\n return composeFns(\r\n events.on(\"fieldRegistered\", (_path) => {\r\n if (FieldPath.equals(_path, path)) {\r\n onVersionChange();\r\n }\r\n }),\r\n events.on(\"fieldUnregistered\", (_path) => {\r\n if (FieldPath.equals(_path, path)) {\r\n onVersionChange();\r\n }\r\n }),\r\n events.on(\"fieldValueChanged\", (changedPath) => {\r\n if (\r\n FieldPath.equals(changedPath, path) ||\r\n FieldPath.isDescendant(changedPath, path)\r\n ) {\r\n onVersionChange();\r\n }\r\n }),\r\n events.on(\"fieldTouchUpdated\", (_path) => {\r\n if (FieldPath.equals(_path, path)) {\r\n onVersionChange();\r\n }\r\n }),\r\n events.on(\"fieldDirtyUpdated\", (_path) => {\r\n if (FieldPath.equals(_path, path)) {\r\n onVersionChange();\r\n }\r\n }),\r\n events.on(\"fieldIssuesUpdated\", (_path) => {\r\n if (FieldPath.equals(_path, path)) {\r\n onVersionChange();\r\n }\r\n }),\r\n );\r\n },\r\n [controller, path],\r\n );\r\n\r\n return useSyncMutableStore(subscribe, () => controller.getField(path));\r\n}\r\n","import { FieldPath } from \"@goodie-forms/core\";\r\nimport { useCallback, useSyncExternalStore } from \"react\";\r\nimport { UseForm } from \"../hooks/useForm\";\r\nimport { composeFns } from \"../utils/composeFns\";\r\n\r\nexport function useFieldValue<\r\n TOutput extends object,\r\n TPath extends FieldPath.Segments,\r\n>(form: UseForm<TOutput>, path: TPath) {\r\n const { controller } = form;\r\n\r\n const subscribe = useCallback(\r\n (onStoreChange: () => void) => {\r\n const { events } = controller;\r\n\r\n return composeFns(\r\n events.on(\"fieldRegistered\", (fieldPath) => {\r\n if (FieldPath.equals(path, fieldPath)) {\r\n onStoreChange();\r\n }\r\n }),\r\n events.on(\"fieldUnregistered\", (fieldPath) => {\r\n if (FieldPath.equals(path, fieldPath)) {\r\n onStoreChange();\r\n }\r\n }),\r\n events.on(\"fieldValueChanged\", (changedPath) => {\r\n if (\r\n FieldPath.equals(changedPath, path) ||\r\n FieldPath.isDescendant(changedPath, path)\r\n ) {\r\n onStoreChange();\r\n }\r\n }),\r\n );\r\n },\r\n [controller, path],\r\n );\r\n\r\n const getSnapshot = useCallback(() => {\r\n return controller.getField(path)?.value;\r\n }, [controller, path]);\r\n\r\n return useSyncExternalStore(subscribe, getSnapshot, getSnapshot);\r\n}\r\n","import { FieldPath } from \"@goodie-forms/core\";\r\nimport { useCallback, useSyncExternalStore } from \"react\";\r\nimport { composeFns } from \"../utils/composeFns\";\r\nimport { UseForm } from \"./useForm\";\r\n\r\nexport function useFieldIssues<\r\n TOutput extends object,\r\n TPath extends FieldPath.Segments,\r\n>(form: UseForm<TOutput>, path: TPath) {\r\n const { controller } = form;\r\n\r\n const subscribe = useCallback(\r\n (onStoreChange: () => void) => {\r\n const { events } = controller;\r\n\r\n return composeFns(\r\n events.on(\"fieldRegistered\", (fieldPath) => {\r\n if (FieldPath.equals(path, fieldPath)) {\r\n onStoreChange();\r\n }\r\n }),\r\n events.on(\"fieldUnregistered\", (fieldPath) => {\r\n if (FieldPath.equals(path, fieldPath)) {\r\n onStoreChange();\r\n }\r\n }),\r\n events.on(\"fieldIssuesUpdated\", (fieldPath) => {\r\n if (FieldPath.equals(path, fieldPath)) {\r\n onStoreChange();\r\n }\r\n }),\r\n );\r\n },\r\n [controller, path],\r\n );\r\n\r\n const getSnapshot = useCallback(() => {\r\n return controller.getField(path)?.issues ?? [];\r\n }, [controller, path]);\r\n\r\n return useSyncExternalStore(subscribe, getSnapshot, getSnapshot);\r\n}\r\n","import {\r\n DeepReadonly,\r\n FieldPath,\r\n FormField,\r\n Suppliable,\r\n} from \"@goodie-forms/core\";\r\nimport { ChangeEvent, ReactNode, Ref, useEffect, useRef } from \"react\";\r\nimport { UseForm } from \"../hooks/useForm\";\r\nimport { useFormField } from \"../hooks/useFormField\";\r\nimport { composeFns } from \"../utils/composeFns\";\r\n\r\nexport interface RenderParams<TOutput extends object, TValue> {\r\n fieldProps: {\r\n ref: Ref<any | null>;\r\n\r\n name: string;\r\n\r\n value: DeepReadonly<TValue> | undefined;\r\n\r\n onChange: (event: ChangeEvent<EventTarget> | TValue) => void;\r\n onFocus: () => void;\r\n onBlur: () => void;\r\n };\r\n\r\n field: FormField<TOutput, TValue>;\r\n\r\n form: UseForm<TOutput>;\r\n}\r\n\r\nexport interface FieldRendererProps<\r\n TOutput extends object,\r\n TPath extends FieldPath.Segments,\r\n> {\r\n form: UseForm<TOutput>;\r\n path: TPath;\r\n defaultValue?: Suppliable<FieldPath.Resolve<TOutput, TPath>>;\r\n overrideInitialValue?: boolean;\r\n unregisterOnUnmount?: boolean;\r\n render: (\r\n params: RenderParams<TOutput, FieldPath.Resolve<TOutput, TPath>>,\r\n ) => ReactNode;\r\n}\r\n\r\nexport function FieldRenderer<\r\n TOutput extends object,\r\n const TPath extends FieldPath.Segments,\r\n>(props: FieldRendererProps<TOutput, TPath>) {\r\n type TValue = FieldPath.Resolve<TOutput, TPath>;\r\n\r\n const elementRef = useRef<HTMLElement>(null);\r\n\r\n const field = useFormField(props.form, props.path, {\r\n overrideInitialValue: props.overrideInitialValue ?? true,\r\n defaultValue: props.defaultValue,\r\n })!;\r\n\r\n const currentValidateMode = props.form.controller.triedSubmitting\r\n ? (props.form.hookConfigs?.revalidateMode ??\r\n props.form.hookConfigs?.validateMode)\r\n : props.form.hookConfigs?.validateMode;\r\n\r\n const renderedJsx = props.render({\r\n fieldProps: {\r\n ref: elementRef,\r\n name: field.stringPath,\r\n value: field.value,\r\n onChange(arg) {\r\n let newValue: TValue;\r\n\r\n if (typeof arg === \"object\" && \"target\" in arg) {\r\n const { target } = arg;\r\n if (target !== field.boundElement) return;\r\n if (!(\"value\" in target)) return;\r\n if (typeof target.value !== \"string\") return;\r\n newValue = target.value as TValue;\r\n } else {\r\n newValue = arg;\r\n }\r\n\r\n field.setValue(newValue, {\r\n shouldTouch: true,\r\n shouldMarkDirty: true,\r\n });\r\n },\r\n onFocus() {\r\n field.touch();\r\n },\r\n onBlur() {\r\n if (\r\n field.issues.length !== 0 ||\r\n currentValidateMode === \"onBlur\" ||\r\n currentValidateMode === \"onChange\"\r\n ) {\r\n props.form.controller.validateField(props.path);\r\n }\r\n },\r\n },\r\n field: field as any,\r\n form: props.form,\r\n });\r\n\r\n useEffect(() => {\r\n const { events } = props.form.controller;\r\n\r\n return composeFns(\r\n events.on(\"fieldValueChanged\", (_path) => {\r\n if (\r\n !FieldPath.equals(_path, props.path) &&\r\n !FieldPath.isDescendant(_path, props.path)\r\n ) {\r\n return;\r\n }\r\n\r\n if (field.issues.length !== 0 || currentValidateMode === \"onChange\") {\r\n props.form.controller.validateField(props.path);\r\n }\r\n }),\r\n );\r\n }, [currentValidateMode]);\r\n\r\n useEffect(() => {\r\n field.bindElement(elementRef.current!);\r\n\r\n return () => {\r\n if (props.unregisterOnUnmount) {\r\n props.form.controller.unregisterField(props.path);\r\n }\r\n };\r\n }, []);\r\n\r\n return <>{renderedJsx}</>;\r\n}\r\n\r\n/* ---- TESTS ---------------- */\r\n\r\n// function TestComp() {\r\n// const form = useForm<{ a?: { b: 99 } }>({});\r\n\r\n// const jsx = (\r\n// <>\r\n// <FieldRenderer\r\n// form={form}\r\n// path={form.paths.fromProxy((data) => data.a.b)}\r\n// defaultValue={() => 99 as const}\r\n// render={({ fieldProps, field }) => {\r\n// // ^?\r\n// return <input {...fieldProps} />;\r\n// }}\r\n// />\r\n\r\n// {/* defaultField olmayabilir, çünkü \"a\" nullable */}\r\n// <FieldRenderer\r\n// form={form}\r\n// path={form.paths.fromProxy((data) => data.a)}\r\n// render={({ ref, value, handlers, field }) => {\r\n// // ^?\r\n// return <></>;\r\n// }}\r\n// />\r\n\r\n// <FieldRenderer\r\n// form={form}\r\n// path={form.paths.fromStringPath(\"a.b\")}\r\n// defaultValue={() => 99 as const}\r\n// render={({ ref, value, handlers, field }) => {\r\n// // ^?\r\n// return <></>;\r\n// }}\r\n// />\r\n// </>\r\n// );\r\n// }\r\n"],"names":["useSyncMutableStore","subscribe","getValue","versionRef","useRef","subscribeWithVersion","useCallback","onStoreChange","getSnapshot","useSyncExternalStore","useForm","formConfigs","hookConfigs","controller","useState","FormController","onVersionChange","useWatchValues","useWatchIssues","useWatchEvent","eventName","listener","args","composeFns","fns","fn","useFormField","form","path","registerConfig","events","_path","FieldPath","changedPath","useFieldValue","fieldPath","useFieldIssues","FieldRenderer","props","elementRef","field","currentValidateMode","renderedJsx","arg","newValue","target","useEffect"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,16 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@goodie-forms/react",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.3.1",
|
|
4
|
+
"repository": {
|
|
5
|
+
"type": "git",
|
|
6
|
+
"url": "https://github.com/iGoodie/goodie-forms"
|
|
7
|
+
},
|
|
8
|
+
"author": {
|
|
9
|
+
"name": "Taha Anılcan Metinyurt",
|
|
10
|
+
"email": "igoodie@programmer.net",
|
|
11
|
+
"url": "https://github.com/iGoodie"
|
|
12
|
+
},
|
|
13
|
+
"license": "CC BY-SA 4.0",
|
|
4
14
|
"type": "module",
|
|
5
15
|
"main": "dist/index.js",
|
|
6
16
|
"types": "dist/index.d.ts",
|
|
@@ -21,7 +31,7 @@
|
|
|
21
31
|
"react-dom": "^18 || ^19"
|
|
22
32
|
},
|
|
23
33
|
"dependencies": {
|
|
24
|
-
"@goodie-forms/core": "1.
|
|
34
|
+
"@goodie-forms/core": "1.3.1"
|
|
25
35
|
},
|
|
26
36
|
"devDependencies": {
|
|
27
37
|
"@types/react": "^19.2.9",
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"useRenderControl.d.ts","sourceRoot":"","sources":["../../src/hooks/useRenderControl.tsx"],"names":[],"mappings":"AAEA,wBAAgB,gBAAgB;;;EAuB/B"}
|