@reckona/mreact-forms 0.0.97 → 0.0.98
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 +4 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +89 -67
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
- package/src/index.ts +97 -72
package/README.md
CHANGED
|
@@ -35,6 +35,8 @@ input({
|
|
|
35
35
|
});
|
|
36
36
|
```
|
|
37
37
|
|
|
38
|
+
Use `field.bind({ event: "change" })` for controls such as `<select>` that should update on change instead of input. `binding.value` is read live from form state, so repeated reads after validation or reset return the current value.
|
|
39
|
+
|
|
38
40
|
## Valibot And Standard Schema
|
|
39
41
|
|
|
40
42
|
`createForm` accepts Standard Schema compatible validators through the
|
|
@@ -105,9 +107,10 @@ await inviteForm.submit((values) => {
|
|
|
105
107
|
## Core APIs
|
|
106
108
|
|
|
107
109
|
- `createForm()` creates reactive form state.
|
|
108
|
-
- `form.field(name).bind()` returns `{ value, onInput, onChange, onBlur }` and handles string values and boolean checkbox-style values.
|
|
110
|
+
- `form.field(name).bind()` returns `{ value, onInput, onChange, onBlur }` and handles string values and boolean checkbox-style values. Pass `{ event: "change" }` to update from `onChange`; the default updates from `onInput`.
|
|
109
111
|
- Field state includes `validating`, which is true while the latest async field validator is pending. Slower stale validator results are ignored.
|
|
110
112
|
- `setServerErrors()` applies errors returned by a route handler or server action.
|
|
113
|
+
- `form.submit()` dedupes concurrent submissions and keeps `submitting` true until the active validation and handler finish.
|
|
111
114
|
- `form.reset()` restores the initial values.
|
|
112
115
|
- The `schema` option connects forms to Standard Schema compatible validators such as zod and valibot.
|
|
113
116
|
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -15,6 +15,7 @@ export function createForm(options) {
|
|
|
15
15
|
values: cloneValues(options.initialValues),
|
|
16
16
|
});
|
|
17
17
|
const validationGenerations = new Map();
|
|
18
|
+
let activeSubmit;
|
|
18
19
|
function commit(patch) {
|
|
19
20
|
const previous = state.get();
|
|
20
21
|
const next = {
|
|
@@ -84,6 +85,45 @@ export function createForm(options) {
|
|
|
84
85
|
await validateField(name);
|
|
85
86
|
}
|
|
86
87
|
}
|
|
88
|
+
async function validateForm() {
|
|
89
|
+
const values = state.get().values;
|
|
90
|
+
const errors = {};
|
|
91
|
+
for (const name of Object.keys(options.validate ?? {})) {
|
|
92
|
+
const validator = options.validate?.[name];
|
|
93
|
+
if (validator === undefined) {
|
|
94
|
+
continue;
|
|
95
|
+
}
|
|
96
|
+
const fieldErrors = normalizeFieldErrors(await validator(values[name], values));
|
|
97
|
+
if (fieldErrors.length > 0) {
|
|
98
|
+
errors[name] = fieldErrors;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
if (options.schema !== undefined) {
|
|
102
|
+
const result = await validateStandardSchema(options.schema, values);
|
|
103
|
+
if (!result.success) {
|
|
104
|
+
mergeIssueErrors(errors, result.issues);
|
|
105
|
+
}
|
|
106
|
+
else if (Object.keys(errors).length === 0) {
|
|
107
|
+
setErrors({});
|
|
108
|
+
return {
|
|
109
|
+
success: true,
|
|
110
|
+
value: result.value,
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
if (Object.keys(errors).length > 0) {
|
|
115
|
+
setErrors(errors);
|
|
116
|
+
return {
|
|
117
|
+
errors,
|
|
118
|
+
success: false,
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
setErrors({});
|
|
122
|
+
return {
|
|
123
|
+
success: true,
|
|
124
|
+
value: values,
|
|
125
|
+
};
|
|
126
|
+
}
|
|
87
127
|
return {
|
|
88
128
|
state,
|
|
89
129
|
field(name) {
|
|
@@ -91,18 +131,28 @@ export function createForm(options) {
|
|
|
91
131
|
state: {
|
|
92
132
|
get: () => fieldState(state.get(), name),
|
|
93
133
|
},
|
|
94
|
-
bind() {
|
|
134
|
+
bind(bindingOptions = {}) {
|
|
135
|
+
const bindingEvent = bindingOptions.event ?? "input";
|
|
136
|
+
const updateValue = async (inputEvent) => {
|
|
137
|
+
await setValue(name, eventValue(inputEvent, state.get().values[name]));
|
|
138
|
+
};
|
|
95
139
|
return {
|
|
96
140
|
onBlur: async () => {
|
|
97
141
|
await blurField(name);
|
|
98
142
|
},
|
|
99
143
|
onChange: async (event) => {
|
|
100
|
-
|
|
144
|
+
if (bindingEvent === "change") {
|
|
145
|
+
await updateValue(event);
|
|
146
|
+
}
|
|
101
147
|
},
|
|
102
148
|
onInput: async (event) => {
|
|
103
|
-
|
|
149
|
+
if (bindingEvent === "input") {
|
|
150
|
+
await updateValue(event);
|
|
151
|
+
}
|
|
152
|
+
},
|
|
153
|
+
get value() {
|
|
154
|
+
return state.get().values[name];
|
|
104
155
|
},
|
|
105
|
-
value: state.get().values[name],
|
|
106
156
|
};
|
|
107
157
|
},
|
|
108
158
|
async blur() {
|
|
@@ -144,73 +194,45 @@ export function createForm(options) {
|
|
|
144
194
|
},
|
|
145
195
|
setValue,
|
|
146
196
|
async submit(handler) {
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
submitting: true,
|
|
150
|
-
});
|
|
151
|
-
const validation = await this.validate();
|
|
152
|
-
if (!validation.success) {
|
|
153
|
-
commit({ submitting: false });
|
|
154
|
-
return {
|
|
155
|
-
errors: validation.errors,
|
|
156
|
-
status: "invalid",
|
|
157
|
-
};
|
|
197
|
+
if (activeSubmit !== undefined) {
|
|
198
|
+
return activeSubmit;
|
|
158
199
|
}
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
200
|
+
const task = (async () => {
|
|
201
|
+
commit({
|
|
202
|
+
submitCount: state.get().submitCount + 1,
|
|
203
|
+
submitting: true,
|
|
204
|
+
});
|
|
205
|
+
try {
|
|
206
|
+
const validation = await validateForm();
|
|
207
|
+
if (!validation.success) {
|
|
208
|
+
return {
|
|
209
|
+
errors: validation.errors,
|
|
210
|
+
status: "invalid",
|
|
211
|
+
};
|
|
212
|
+
}
|
|
213
|
+
try {
|
|
214
|
+
const data = await handler(validation.value);
|
|
215
|
+
return {
|
|
216
|
+
data,
|
|
217
|
+
status: "success",
|
|
218
|
+
};
|
|
219
|
+
}
|
|
220
|
+
catch (error) {
|
|
221
|
+
return {
|
|
222
|
+
error,
|
|
223
|
+
status: "error",
|
|
224
|
+
};
|
|
225
|
+
}
|
|
182
226
|
}
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
}
|
|
187
|
-
}
|
|
188
|
-
if (options.schema !== undefined) {
|
|
189
|
-
const result = await validateStandardSchema(options.schema, values);
|
|
190
|
-
if (!result.success) {
|
|
191
|
-
mergeIssueErrors(errors, result.issues);
|
|
227
|
+
finally {
|
|
228
|
+
activeSubmit = undefined;
|
|
229
|
+
commit({ submitting: false });
|
|
192
230
|
}
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
success: true,
|
|
197
|
-
value: result.value,
|
|
198
|
-
};
|
|
199
|
-
}
|
|
200
|
-
}
|
|
201
|
-
if (Object.keys(errors).length > 0) {
|
|
202
|
-
setErrors(errors);
|
|
203
|
-
return {
|
|
204
|
-
errors,
|
|
205
|
-
success: false,
|
|
206
|
-
};
|
|
207
|
-
}
|
|
208
|
-
setErrors({});
|
|
209
|
-
return {
|
|
210
|
-
success: true,
|
|
211
|
-
value: values,
|
|
212
|
-
};
|
|
231
|
+
})();
|
|
232
|
+
activeSubmit = task;
|
|
233
|
+
return task;
|
|
213
234
|
},
|
|
235
|
+
validate: validateForm,
|
|
214
236
|
};
|
|
215
237
|
}
|
|
216
238
|
function fieldState(formState, name) {
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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","sourcesContent":["import { cell, type ReadonlyCell } from \"@reckona/mreact-reactive-core\";\nimport { type StandardSchemaV1, validateStandardSchema } from \"./standard-schema.js\";\n\nexport type FormValues = Record<string, unknown>;\nexport type FieldName<TValues extends FormValues> = Extract<keyof TValues, string>;\nexport type FormErrors<TValues extends FormValues> = Partial<\n Record<FieldName<TValues> | \"root\", string[]>\n>;\nexport type FieldValidator<TValue, TValues extends FormValues> = (\n value: TValue,\n values: TValues,\n) => readonly string[] | string | undefined | Promise<readonly string[] | string | undefined>;\nexport type FormValidateMode = \"change\" | \"blur\" | \"submit\";\n\nexport interface FormState<TValues extends FormValues> {\n dirty: boolean;\n errors: FormErrors<TValues>;\n initialValues: TValues;\n submitCount: number;\n submitting: boolean;\n touched: Partial<Record<FieldName<TValues>, boolean>>;\n valid: boolean;\n validating: Partial<Record<FieldName<TValues>, boolean>>;\n values: TValues;\n}\n\nexport interface FieldState<TValue> {\n dirty: boolean;\n errors: string[];\n touched: boolean;\n validating: boolean;\n value: TValue;\n}\n\nexport interface FieldBinding<TValue> {\n onBlur(event: Event): Promise<void>;\n onChange(event: Event): Promise<void>;\n onInput(event: Event): Promise<void>;\n value: TValue;\n}\n\nexport interface FieldBindingOptions {\n event?: \"change\" | \"input\" | undefined;\n}\n\nexport interface FieldApi<TValues extends FormValues, Name extends FieldName<TValues>> {\n readonly state: ReadonlyCell<FieldState<TValues[Name]>>;\n bind(options?: FieldBindingOptions): FieldBinding<TValues[Name]>;\n blur(): Promise<void>;\n setValue(value: TValues[Name]): Promise<void>;\n}\n\ninterface BaseCreateFormOptions<TValues extends FormValues> {\n initialValues: TValues;\n validate?:\n | Partial<{\n [Name in FieldName<TValues>]: FieldValidator<TValues[Name], TValues>;\n }>\n | undefined;\n validateOn?: FormValidateMode | readonly FormValidateMode[] | undefined;\n}\n\nexport interface CreateFormOptionsWithoutSchema<TValues extends FormValues>\n extends BaseCreateFormOptions<TValues> {\n schema?: undefined;\n}\n\nexport interface CreateFormOptionsWithSchema<TValues extends FormValues, TSubmitValues>\n extends BaseCreateFormOptions<TValues> {\n schema: StandardSchemaV1<TValues, TSubmitValues>;\n}\n\nexport type CreateFormOptions<TValues extends FormValues, TSubmitValues = TValues> =\n | CreateFormOptionsWithoutSchema<TValues>\n | CreateFormOptionsWithSchema<TValues, TSubmitValues>;\n\nexport type FormValidationResult<TValues extends FormValues, TSubmitValues> =\n | {\n success: true;\n value: TSubmitValues;\n }\n | {\n errors: FormErrors<TValues>;\n success: false;\n };\n\nexport type FormSubmitResult<TValues extends FormValues, TResult> =\n | {\n data: TResult;\n status: \"success\";\n }\n | {\n errors: FormErrors<TValues>;\n status: \"invalid\";\n }\n | {\n error: unknown;\n status: \"error\";\n };\n\nexport interface ServerActionErrors<TValues extends FormValues> {\n fieldErrors?: Partial<Record<FieldName<TValues>, readonly string[]>> | undefined;\n formErrors?: readonly string[] | undefined;\n}\n\nexport interface FormApi<TValues extends FormValues, TSubmitValues> {\n readonly state: ReadonlyCell<FormState<TValues>>;\n field<Name extends FieldName<TValues>>(name: Name): FieldApi<TValues, Name>;\n getValues(): TValues;\n reset(values?: TValues): void;\n setErrors(errors: FormErrors<TValues>): void;\n setServerErrors(errors: ServerActionErrors<TValues>): void;\n setValue<Name extends FieldName<TValues>>(name: Name, value: TValues[Name]): Promise<void>;\n submit<TResult>(\n handler: (values: TSubmitValues) => Promise<TResult> | TResult,\n ): Promise<FormSubmitResult<TValues, TResult>>;\n validate(): Promise<FormValidationResult<TValues, TSubmitValues>>;\n}\n\nexport function createForm<TValues extends FormValues>(\n options: CreateFormOptionsWithoutSchema<TValues>,\n): FormApi<TValues, TValues>;\nexport function createForm<TValues extends FormValues, TSubmitValues>(\n options: CreateFormOptionsWithSchema<TValues, TSubmitValues>,\n): FormApi<TValues, TSubmitValues>;\nexport function createForm<TValues extends FormValues, TSubmitValues = TValues>(\n options: CreateFormOptions<TValues, TSubmitValues>,\n): FormApi<TValues, TSubmitValues> {\n const validateOn = new Set(\n Array.isArray(options.validateOn) ? options.validateOn : [options.validateOn ?? \"submit\"],\n );\n let initialValues = cloneValues(options.initialValues);\n const state = cell<FormState<TValues>>({\n dirty: false,\n errors: {},\n initialValues,\n submitCount: 0,\n submitting: false,\n touched: {},\n valid: true,\n validating: {},\n values: cloneValues(options.initialValues),\n });\n const validationGenerations = new Map<FieldName<TValues>, number>();\n\n function commit(patch: Partial<FormState<TValues>>): void {\n const previous = state.get();\n const next = {\n ...previous,\n ...patch,\n };\n next.dirty = isDirty(next.values, next.initialValues);\n next.valid = hasNoErrors(next.errors);\n state.set(next);\n }\n\n function setErrors(errors: FormErrors<TValues>): void {\n commit({ errors: normalizeErrors(errors) });\n }\n\n async function validateField<Name extends FieldName<TValues>>(name: Name): Promise<void> {\n const validator = options.validate?.[name];\n const generation = (validationGenerations.get(name) ?? 0) + 1;\n validationGenerations.set(name, generation);\n\n if (validator === undefined) {\n setFieldErrors(name, []);\n setFieldValidating(name, false);\n return;\n }\n\n const values = state.get().values;\n setFieldValidating(name, true);\n const errors = await validator(values[name], values);\n\n if (validationGenerations.get(name) !== generation) {\n return;\n }\n\n setFieldErrors(name, normalizeFieldErrors(errors));\n setFieldValidating(name, false);\n }\n\n function setFieldErrors<Name extends FieldName<TValues>>(\n name: Name,\n errors: readonly string[],\n ): void {\n const current = state.get().errors;\n setErrors({\n ...current,\n [name]: [...errors],\n } as FormErrors<TValues>);\n }\n\n function setFieldValidating<Name extends FieldName<TValues>>(\n name: Name,\n validating: boolean,\n ): void {\n const current = state.get().validating;\n commit({\n validating: {\n ...current,\n [name]: validating,\n },\n });\n }\n\n async function setValue<Name extends FieldName<TValues>>(\n name: Name,\n value: TValues[Name],\n ): Promise<void> {\n commit({\n values: {\n ...state.get().values,\n [name]: value,\n },\n });\n\n if (validateOn.has(\"change\")) {\n await validateField(name);\n }\n }\n\n async function blurField<Name extends FieldName<TValues>>(name: Name): Promise<void> {\n commit({\n touched: {\n ...state.get().touched,\n [name]: true,\n },\n });\n\n if (validateOn.has(\"blur\")) {\n await validateField(name);\n }\n }\n\n return {\n state,\n field<Name extends FieldName<TValues>>(name: Name): FieldApi<TValues, Name> {\n return {\n state: {\n get: () => fieldState(state.get(), name),\n },\n bind() {\n return {\n onBlur: async () => {\n await blurField(name);\n },\n onChange: async (event) => {\n await setValue(name, eventValue(event, state.get().values[name]) as TValues[Name]);\n },\n onInput: async (event) => {\n await setValue(name, eventValue(event, state.get().values[name]) as TValues[Name]);\n },\n value: state.get().values[name],\n };\n },\n async blur() {\n await blurField(name);\n },\n setValue: (value) => setValue(name, value),\n };\n },\n getValues() {\n return state.get().values;\n },\n reset(values = initialValues): void {\n for (const name of Object.keys(options.validate ?? {}) as Array<FieldName<TValues>>) {\n validationGenerations.set(name, (validationGenerations.get(name) ?? 0) + 1);\n }\n\n initialValues = cloneValues(values);\n commit({\n errors: {},\n initialValues,\n submitCount: 0,\n submitting: false,\n touched: {},\n validating: {},\n values: cloneValues(values),\n });\n },\n setErrors,\n setServerErrors(errors): void {\n const next: FormErrors<TValues> = {};\n\n for (const [name, messages] of Object.entries(errors.fieldErrors ?? {})) {\n if (messages !== undefined && messages.length > 0) {\n next[name as FieldName<TValues>] = [...messages];\n }\n }\n\n if (errors.formErrors !== undefined && errors.formErrors.length > 0) {\n next.root = [...errors.formErrors];\n }\n\n setErrors(next);\n },\n setValue,\n async submit<TResult>(\n handler: (values: TSubmitValues) => Promise<TResult> | TResult,\n ): Promise<FormSubmitResult<TValues, TResult>> {\n commit({\n submitCount: state.get().submitCount + 1,\n submitting: true,\n });\n\n const validation = await this.validate();\n\n if (!validation.success) {\n commit({ submitting: false });\n return {\n errors: validation.errors,\n status: \"invalid\",\n };\n }\n\n try {\n const data = await handler(validation.value);\n commit({ submitting: false });\n return {\n data,\n status: \"success\",\n };\n } catch (error) {\n commit({ submitting: false });\n return {\n error,\n status: \"error\",\n };\n }\n },\n async validate(): Promise<FormValidationResult<TValues, TSubmitValues>> {\n const values = state.get().values;\n const errors: FormErrors<TValues> = {};\n\n for (const name of Object.keys(options.validate ?? {}) as Array<FieldName<TValues>>) {\n const validator = options.validate?.[name];\n if (validator === undefined) {\n continue;\n }\n const fieldErrors = normalizeFieldErrors(await validator(values[name], values));\n if (fieldErrors.length > 0) {\n errors[name] = fieldErrors;\n }\n }\n\n if (options.schema !== undefined) {\n const result = await validateStandardSchema(options.schema, values);\n\n if (!result.success) {\n mergeIssueErrors(errors, result.issues);\n } else if (Object.keys(errors).length === 0) {\n setErrors({});\n return {\n success: true,\n value: result.value as TSubmitValues,\n };\n }\n }\n\n if (Object.keys(errors).length > 0) {\n setErrors(errors);\n return {\n errors,\n success: false,\n };\n }\n\n setErrors({});\n return {\n success: true,\n value: values as TValues & TSubmitValues,\n };\n },\n };\n}\n\nfunction fieldState<TValues extends FormValues, Name extends FieldName<TValues>>(\n formState: FormState<TValues>,\n name: Name,\n): FieldState<TValues[Name]> {\n return {\n dirty: !Object.is(formState.values[name], formState.initialValues[name]),\n errors: [...(formState.errors[name] ?? [])],\n touched: formState.touched[name] === true,\n validating: formState.validating[name] === true,\n value: formState.values[name],\n };\n}\n\nfunction eventValue(event: Event, currentValue: unknown): unknown {\n const target = event.currentTarget ?? event.target;\n\n if (target !== null && typeof target === \"object\") {\n if (typeof currentValue === \"boolean\" && \"checked\" in target) {\n return Boolean((target as { checked: unknown }).checked);\n }\n\n if (\"value\" in target) {\n return (target as { value: unknown }).value;\n }\n }\n\n return currentValue;\n}\n\nfunction mergeIssueErrors<TValues extends FormValues>(\n errors: FormErrors<TValues>,\n issues: ReadonlyArray<StandardSchemaV1.Issue>,\n): void {\n for (const issue of issues) {\n const key = issuePathKey(issue.path);\n const name = (key ?? \"root\") as FieldName<TValues> | \"root\";\n const messages = errors[name] ?? [];\n messages.push(issue.message);\n errors[name] = messages;\n }\n}\n\nfunction issuePathKey(\n path: ReadonlyArray<PropertyKey | StandardSchemaV1.PathSegment> | undefined,\n): string | undefined {\n const first = path?.[0];\n\n if (first === undefined) {\n return undefined;\n }\n\n return typeof first === \"object\" && first !== null && \"key\" in first\n ? String(first.key)\n : String(first);\n}\n\nfunction normalizeErrors<TValues extends FormValues>(\n errors: FormErrors<TValues>,\n): FormErrors<TValues> {\n return Object.fromEntries(\n Object.entries(errors).flatMap(([name, messages]) =>\n messages === undefined || messages.length === 0 ? [] : [[name, [...messages]]],\n ),\n ) as FormErrors<TValues>;\n}\n\nfunction hasNoErrors<TValues extends FormValues>(errors: FormErrors<TValues>): boolean {\n return (Object.values(errors) as Array<string[] | undefined>).every(\n (messages) => messages === undefined || messages.length === 0,\n );\n}\n\nfunction normalizeFieldErrors(errors: readonly string[] | string | undefined): string[] {\n if (errors === undefined) {\n return [];\n }\n\n return typeof errors === \"string\" ? [errors] : [...errors];\n}\n\nfunction isDirty<TValues extends FormValues>(values: TValues, initialValues: TValues): boolean {\n return Object.keys(values).some((key) => !Object.is(values[key], initialValues[key]));\n}\n\nfunction cloneValues<TValues extends FormValues>(values: TValues): TValues {\n return { ...values };\n}\n\nexport type {\n InferStandardSchemaInput,\n InferStandardSchemaOutput,\n StandardSchemaV1,\n} from \"./standard-schema.js\";\nexport { validateStandardSchema } from \"./standard-schema.js\";\n"]}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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","sourcesContent":["import { cell, type ReadonlyCell } from \"@reckona/mreact-reactive-core\";\nimport { type StandardSchemaV1, validateStandardSchema } from \"./standard-schema.js\";\n\nexport type FormValues = Record<string, unknown>;\nexport type FieldName<TValues extends FormValues> = Extract<keyof TValues, string>;\nexport type FormErrors<TValues extends FormValues> = Partial<\n Record<FieldName<TValues> | \"root\", string[]>\n>;\nexport type FieldValidator<TValue, TValues extends FormValues> = (\n value: TValue,\n values: TValues,\n) => readonly string[] | string | undefined | Promise<readonly string[] | string | undefined>;\nexport type FormValidateMode = \"change\" | \"blur\" | \"submit\";\n\nexport interface FormState<TValues extends FormValues> {\n dirty: boolean;\n errors: FormErrors<TValues>;\n initialValues: TValues;\n submitCount: number;\n submitting: boolean;\n touched: Partial<Record<FieldName<TValues>, boolean>>;\n valid: boolean;\n validating: Partial<Record<FieldName<TValues>, boolean>>;\n values: TValues;\n}\n\nexport interface FieldState<TValue> {\n dirty: boolean;\n errors: string[];\n touched: boolean;\n validating: boolean;\n value: TValue;\n}\n\nexport interface FieldBinding<TValue> {\n onBlur(event: Event): Promise<void>;\n onChange(event: Event): Promise<void>;\n onInput(event: Event): Promise<void>;\n value: TValue;\n}\n\nexport interface FieldBindingOptions {\n event?: \"change\" | \"input\" | undefined;\n}\n\nexport interface FieldApi<TValues extends FormValues, Name extends FieldName<TValues>> {\n readonly state: ReadonlyCell<FieldState<TValues[Name]>>;\n bind(options?: FieldBindingOptions): FieldBinding<TValues[Name]>;\n blur(): Promise<void>;\n setValue(value: TValues[Name]): Promise<void>;\n}\n\ninterface BaseCreateFormOptions<TValues extends FormValues> {\n initialValues: TValues;\n validate?:\n | Partial<{\n [Name in FieldName<TValues>]: FieldValidator<TValues[Name], TValues>;\n }>\n | undefined;\n validateOn?: FormValidateMode | readonly FormValidateMode[] | undefined;\n}\n\nexport interface CreateFormOptionsWithoutSchema<TValues extends FormValues>\n extends BaseCreateFormOptions<TValues> {\n schema?: undefined;\n}\n\nexport interface CreateFormOptionsWithSchema<TValues extends FormValues, TSubmitValues>\n extends BaseCreateFormOptions<TValues> {\n schema: StandardSchemaV1<TValues, TSubmitValues>;\n}\n\nexport type CreateFormOptions<TValues extends FormValues, TSubmitValues = TValues> =\n | CreateFormOptionsWithoutSchema<TValues>\n | CreateFormOptionsWithSchema<TValues, TSubmitValues>;\n\nexport type FormValidationResult<TValues extends FormValues, TSubmitValues> =\n | {\n success: true;\n value: TSubmitValues;\n }\n | {\n errors: FormErrors<TValues>;\n success: false;\n };\n\nexport type FormSubmitResult<TValues extends FormValues, TResult> =\n | {\n data: TResult;\n status: \"success\";\n }\n | {\n errors: FormErrors<TValues>;\n status: \"invalid\";\n }\n | {\n error: unknown;\n status: \"error\";\n };\n\nexport interface ServerActionErrors<TValues extends FormValues> {\n fieldErrors?: Partial<Record<FieldName<TValues>, readonly string[]>> | undefined;\n formErrors?: readonly string[] | undefined;\n}\n\nexport interface FormApi<TValues extends FormValues, TSubmitValues> {\n readonly state: ReadonlyCell<FormState<TValues>>;\n field<Name extends FieldName<TValues>>(name: Name): FieldApi<TValues, Name>;\n getValues(): TValues;\n reset(values?: TValues): void;\n setErrors(errors: FormErrors<TValues>): void;\n setServerErrors(errors: ServerActionErrors<TValues>): void;\n setValue<Name extends FieldName<TValues>>(name: Name, value: TValues[Name]): Promise<void>;\n submit<TResult>(\n handler: (values: TSubmitValues) => Promise<TResult> | TResult,\n ): Promise<FormSubmitResult<TValues, TResult>>;\n validate(): Promise<FormValidationResult<TValues, TSubmitValues>>;\n}\n\nexport function createForm<TValues extends FormValues>(\n options: CreateFormOptionsWithoutSchema<TValues>,\n): FormApi<TValues, TValues>;\nexport function createForm<TValues extends FormValues, TSubmitValues>(\n options: CreateFormOptionsWithSchema<TValues, TSubmitValues>,\n): FormApi<TValues, TSubmitValues>;\nexport function createForm<TValues extends FormValues, TSubmitValues = TValues>(\n options: CreateFormOptions<TValues, TSubmitValues>,\n): FormApi<TValues, TSubmitValues> {\n const validateOn = new Set(\n Array.isArray(options.validateOn) ? options.validateOn : [options.validateOn ?? \"submit\"],\n );\n let initialValues = cloneValues(options.initialValues);\n const state = cell<FormState<TValues>>({\n dirty: false,\n errors: {},\n initialValues,\n submitCount: 0,\n submitting: false,\n touched: {},\n valid: true,\n validating: {},\n values: cloneValues(options.initialValues),\n });\n const validationGenerations = new Map<FieldName<TValues>, number>();\n let activeSubmit: Promise<FormSubmitResult<TValues, unknown>> | undefined;\n\n function commit(patch: Partial<FormState<TValues>>): void {\n const previous = state.get();\n const next = {\n ...previous,\n ...patch,\n };\n next.dirty = isDirty(next.values, next.initialValues);\n next.valid = hasNoErrors(next.errors);\n state.set(next);\n }\n\n function setErrors(errors: FormErrors<TValues>): void {\n commit({ errors: normalizeErrors(errors) });\n }\n\n async function validateField<Name extends FieldName<TValues>>(name: Name): Promise<void> {\n const validator = options.validate?.[name];\n const generation = (validationGenerations.get(name) ?? 0) + 1;\n validationGenerations.set(name, generation);\n\n if (validator === undefined) {\n setFieldErrors(name, []);\n setFieldValidating(name, false);\n return;\n }\n\n const values = state.get().values;\n setFieldValidating(name, true);\n const errors = await validator(values[name], values);\n\n if (validationGenerations.get(name) !== generation) {\n return;\n }\n\n setFieldErrors(name, normalizeFieldErrors(errors));\n setFieldValidating(name, false);\n }\n\n function setFieldErrors<Name extends FieldName<TValues>>(\n name: Name,\n errors: readonly string[],\n ): void {\n const current = state.get().errors;\n setErrors({\n ...current,\n [name]: [...errors],\n } as FormErrors<TValues>);\n }\n\n function setFieldValidating<Name extends FieldName<TValues>>(\n name: Name,\n validating: boolean,\n ): void {\n const current = state.get().validating;\n commit({\n validating: {\n ...current,\n [name]: validating,\n },\n });\n }\n\n async function setValue<Name extends FieldName<TValues>>(\n name: Name,\n value: TValues[Name],\n ): Promise<void> {\n commit({\n values: {\n ...state.get().values,\n [name]: value,\n },\n });\n\n if (validateOn.has(\"change\")) {\n await validateField(name);\n }\n }\n\n async function blurField<Name extends FieldName<TValues>>(name: Name): Promise<void> {\n commit({\n touched: {\n ...state.get().touched,\n [name]: true,\n },\n });\n\n if (validateOn.has(\"blur\")) {\n await validateField(name);\n }\n }\n\n async function validateForm(): Promise<FormValidationResult<TValues, TSubmitValues>> {\n const values = state.get().values;\n const errors: FormErrors<TValues> = {};\n\n for (const name of Object.keys(options.validate ?? {}) as Array<FieldName<TValues>>) {\n const validator = options.validate?.[name];\n if (validator === undefined) {\n continue;\n }\n const fieldErrors = normalizeFieldErrors(await validator(values[name], values));\n if (fieldErrors.length > 0) {\n errors[name] = fieldErrors;\n }\n }\n\n if (options.schema !== undefined) {\n const result = await validateStandardSchema(options.schema, values);\n\n if (!result.success) {\n mergeIssueErrors(errors, result.issues);\n } else if (Object.keys(errors).length === 0) {\n setErrors({});\n return {\n success: true,\n value: result.value as TSubmitValues,\n };\n }\n }\n\n if (Object.keys(errors).length > 0) {\n setErrors(errors);\n return {\n errors,\n success: false,\n };\n }\n\n setErrors({});\n return {\n success: true,\n value: values as TValues & TSubmitValues,\n };\n }\n\n return {\n state,\n field<Name extends FieldName<TValues>>(name: Name): FieldApi<TValues, Name> {\n return {\n state: {\n get: () => fieldState(state.get(), name),\n },\n bind(bindingOptions = {}) {\n const bindingEvent = bindingOptions.event ?? \"input\";\n const updateValue = async (inputEvent: Event) => {\n await setValue(name, eventValue(inputEvent, state.get().values[name]) as TValues[Name]);\n };\n\n return {\n onBlur: async () => {\n await blurField(name);\n },\n onChange: async (event) => {\n if (bindingEvent === \"change\") {\n await updateValue(event);\n }\n },\n onInput: async (event) => {\n if (bindingEvent === \"input\") {\n await updateValue(event);\n }\n },\n get value() {\n return state.get().values[name];\n },\n };\n },\n async blur() {\n await blurField(name);\n },\n setValue: (value) => setValue(name, value),\n };\n },\n getValues() {\n return state.get().values;\n },\n reset(values = initialValues): void {\n for (const name of Object.keys(options.validate ?? {}) as Array<FieldName<TValues>>) {\n validationGenerations.set(name, (validationGenerations.get(name) ?? 0) + 1);\n }\n\n initialValues = cloneValues(values);\n commit({\n errors: {},\n initialValues,\n submitCount: 0,\n submitting: false,\n touched: {},\n validating: {},\n values: cloneValues(values),\n });\n },\n setErrors,\n setServerErrors(errors): void {\n const next: FormErrors<TValues> = {};\n\n for (const [name, messages] of Object.entries(errors.fieldErrors ?? {})) {\n if (messages !== undefined && messages.length > 0) {\n next[name as FieldName<TValues>] = [...messages];\n }\n }\n\n if (errors.formErrors !== undefined && errors.formErrors.length > 0) {\n next.root = [...errors.formErrors];\n }\n\n setErrors(next);\n },\n setValue,\n async submit<TResult>(\n handler: (values: TSubmitValues) => Promise<TResult> | TResult,\n ): Promise<FormSubmitResult<TValues, TResult>> {\n if (activeSubmit !== undefined) {\n return activeSubmit as Promise<FormSubmitResult<TValues, TResult>>;\n }\n\n const task = (async (): Promise<FormSubmitResult<TValues, TResult>> => {\n commit({\n submitCount: state.get().submitCount + 1,\n submitting: true,\n });\n\n try {\n const validation = await validateForm();\n\n if (!validation.success) {\n return {\n errors: validation.errors,\n status: \"invalid\",\n };\n }\n\n try {\n const data = await handler(validation.value);\n return {\n data,\n status: \"success\",\n };\n } catch (error) {\n return {\n error,\n status: \"error\",\n };\n }\n } finally {\n activeSubmit = undefined;\n commit({ submitting: false });\n }\n })();\n\n activeSubmit = task as Promise<FormSubmitResult<TValues, unknown>>;\n return task;\n },\n validate: validateForm,\n };\n}\n\nfunction fieldState<TValues extends FormValues, Name extends FieldName<TValues>>(\n formState: FormState<TValues>,\n name: Name,\n): FieldState<TValues[Name]> {\n return {\n dirty: !Object.is(formState.values[name], formState.initialValues[name]),\n errors: [...(formState.errors[name] ?? [])],\n touched: formState.touched[name] === true,\n validating: formState.validating[name] === true,\n value: formState.values[name],\n };\n}\n\nfunction eventValue(event: Event, currentValue: unknown): unknown {\n const target = event.currentTarget ?? event.target;\n\n if (target !== null && typeof target === \"object\") {\n if (typeof currentValue === \"boolean\" && \"checked\" in target) {\n return Boolean((target as { checked: unknown }).checked);\n }\n\n if (\"value\" in target) {\n return (target as { value: unknown }).value;\n }\n }\n\n return currentValue;\n}\n\nfunction mergeIssueErrors<TValues extends FormValues>(\n errors: FormErrors<TValues>,\n issues: ReadonlyArray<StandardSchemaV1.Issue>,\n): void {\n for (const issue of issues) {\n const key = issuePathKey(issue.path);\n const name = (key ?? \"root\") as FieldName<TValues> | \"root\";\n const messages = errors[name] ?? [];\n messages.push(issue.message);\n errors[name] = messages;\n }\n}\n\nfunction issuePathKey(\n path: ReadonlyArray<PropertyKey | StandardSchemaV1.PathSegment> | undefined,\n): string | undefined {\n const first = path?.[0];\n\n if (first === undefined) {\n return undefined;\n }\n\n return typeof first === \"object\" && first !== null && \"key\" in first\n ? String(first.key)\n : String(first);\n}\n\nfunction normalizeErrors<TValues extends FormValues>(\n errors: FormErrors<TValues>,\n): FormErrors<TValues> {\n return Object.fromEntries(\n Object.entries(errors).flatMap(([name, messages]) =>\n messages === undefined || messages.length === 0 ? [] : [[name, [...messages]]],\n ),\n ) as FormErrors<TValues>;\n}\n\nfunction hasNoErrors<TValues extends FormValues>(errors: FormErrors<TValues>): boolean {\n return (Object.values(errors) as Array<string[] | undefined>).every(\n (messages) => messages === undefined || messages.length === 0,\n );\n}\n\nfunction normalizeFieldErrors(errors: readonly string[] | string | undefined): string[] {\n if (errors === undefined) {\n return [];\n }\n\n return typeof errors === \"string\" ? [errors] : [...errors];\n}\n\nfunction isDirty<TValues extends FormValues>(values: TValues, initialValues: TValues): boolean {\n return Object.keys(values).some((key) => !Object.is(values[key], initialValues[key]));\n}\n\nfunction cloneValues<TValues extends FormValues>(values: TValues): TValues {\n return { ...values };\n}\n\nexport type {\n InferStandardSchemaInput,\n InferStandardSchemaOutput,\n StandardSchemaV1,\n} from \"./standard-schema.js\";\nexport { validateStandardSchema } from \"./standard-schema.js\";\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@reckona/mreact-forms",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.98",
|
|
4
4
|
"description": "Reactive form state and validation utilities for mreact.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"forms",
|
|
@@ -44,6 +44,6 @@
|
|
|
44
44
|
"access": "public"
|
|
45
45
|
},
|
|
46
46
|
"dependencies": {
|
|
47
|
-
"@reckona/mreact-reactive-core": "0.0.
|
|
47
|
+
"@reckona/mreact-reactive-core": "0.0.98"
|
|
48
48
|
}
|
|
49
49
|
}
|
package/src/index.ts
CHANGED
|
@@ -142,6 +142,7 @@ export function createForm<TValues extends FormValues, TSubmitValues = TValues>(
|
|
|
142
142
|
values: cloneValues(options.initialValues),
|
|
143
143
|
});
|
|
144
144
|
const validationGenerations = new Map<FieldName<TValues>, number>();
|
|
145
|
+
let activeSubmit: Promise<FormSubmitResult<TValues, unknown>> | undefined;
|
|
145
146
|
|
|
146
147
|
function commit(patch: Partial<FormState<TValues>>): void {
|
|
147
148
|
const previous = state.get();
|
|
@@ -234,6 +235,50 @@ export function createForm<TValues extends FormValues, TSubmitValues = TValues>(
|
|
|
234
235
|
}
|
|
235
236
|
}
|
|
236
237
|
|
|
238
|
+
async function validateForm(): Promise<FormValidationResult<TValues, TSubmitValues>> {
|
|
239
|
+
const values = state.get().values;
|
|
240
|
+
const errors: FormErrors<TValues> = {};
|
|
241
|
+
|
|
242
|
+
for (const name of Object.keys(options.validate ?? {}) as Array<FieldName<TValues>>) {
|
|
243
|
+
const validator = options.validate?.[name];
|
|
244
|
+
if (validator === undefined) {
|
|
245
|
+
continue;
|
|
246
|
+
}
|
|
247
|
+
const fieldErrors = normalizeFieldErrors(await validator(values[name], values));
|
|
248
|
+
if (fieldErrors.length > 0) {
|
|
249
|
+
errors[name] = fieldErrors;
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
if (options.schema !== undefined) {
|
|
254
|
+
const result = await validateStandardSchema(options.schema, values);
|
|
255
|
+
|
|
256
|
+
if (!result.success) {
|
|
257
|
+
mergeIssueErrors(errors, result.issues);
|
|
258
|
+
} else if (Object.keys(errors).length === 0) {
|
|
259
|
+
setErrors({});
|
|
260
|
+
return {
|
|
261
|
+
success: true,
|
|
262
|
+
value: result.value as TSubmitValues,
|
|
263
|
+
};
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
if (Object.keys(errors).length > 0) {
|
|
268
|
+
setErrors(errors);
|
|
269
|
+
return {
|
|
270
|
+
errors,
|
|
271
|
+
success: false,
|
|
272
|
+
};
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
setErrors({});
|
|
276
|
+
return {
|
|
277
|
+
success: true,
|
|
278
|
+
value: values as TValues & TSubmitValues,
|
|
279
|
+
};
|
|
280
|
+
}
|
|
281
|
+
|
|
237
282
|
return {
|
|
238
283
|
state,
|
|
239
284
|
field<Name extends FieldName<TValues>>(name: Name): FieldApi<TValues, Name> {
|
|
@@ -241,18 +286,29 @@ export function createForm<TValues extends FormValues, TSubmitValues = TValues>(
|
|
|
241
286
|
state: {
|
|
242
287
|
get: () => fieldState(state.get(), name),
|
|
243
288
|
},
|
|
244
|
-
bind() {
|
|
289
|
+
bind(bindingOptions = {}) {
|
|
290
|
+
const bindingEvent = bindingOptions.event ?? "input";
|
|
291
|
+
const updateValue = async (inputEvent: Event) => {
|
|
292
|
+
await setValue(name, eventValue(inputEvent, state.get().values[name]) as TValues[Name]);
|
|
293
|
+
};
|
|
294
|
+
|
|
245
295
|
return {
|
|
246
296
|
onBlur: async () => {
|
|
247
297
|
await blurField(name);
|
|
248
298
|
},
|
|
249
299
|
onChange: async (event) => {
|
|
250
|
-
|
|
300
|
+
if (bindingEvent === "change") {
|
|
301
|
+
await updateValue(event);
|
|
302
|
+
}
|
|
251
303
|
},
|
|
252
304
|
onInput: async (event) => {
|
|
253
|
-
|
|
305
|
+
if (bindingEvent === "input") {
|
|
306
|
+
await updateValue(event);
|
|
307
|
+
}
|
|
308
|
+
},
|
|
309
|
+
get value() {
|
|
310
|
+
return state.get().values[name];
|
|
254
311
|
},
|
|
255
|
-
value: state.get().values[name],
|
|
256
312
|
};
|
|
257
313
|
},
|
|
258
314
|
async blur() {
|
|
@@ -300,79 +356,48 @@ export function createForm<TValues extends FormValues, TSubmitValues = TValues>(
|
|
|
300
356
|
async submit<TResult>(
|
|
301
357
|
handler: (values: TSubmitValues) => Promise<TResult> | TResult,
|
|
302
358
|
): Promise<FormSubmitResult<TValues, TResult>> {
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
submitting: true,
|
|
306
|
-
});
|
|
307
|
-
|
|
308
|
-
const validation = await this.validate();
|
|
309
|
-
|
|
310
|
-
if (!validation.success) {
|
|
311
|
-
commit({ submitting: false });
|
|
312
|
-
return {
|
|
313
|
-
errors: validation.errors,
|
|
314
|
-
status: "invalid",
|
|
315
|
-
};
|
|
359
|
+
if (activeSubmit !== undefined) {
|
|
360
|
+
return activeSubmit as Promise<FormSubmitResult<TValues, TResult>>;
|
|
316
361
|
}
|
|
317
362
|
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
363
|
+
const task = (async (): Promise<FormSubmitResult<TValues, TResult>> => {
|
|
364
|
+
commit({
|
|
365
|
+
submitCount: state.get().submitCount + 1,
|
|
366
|
+
submitting: true,
|
|
367
|
+
});
|
|
368
|
+
|
|
369
|
+
try {
|
|
370
|
+
const validation = await validateForm();
|
|
371
|
+
|
|
372
|
+
if (!validation.success) {
|
|
373
|
+
return {
|
|
374
|
+
errors: validation.errors,
|
|
375
|
+
status: "invalid",
|
|
376
|
+
};
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
try {
|
|
380
|
+
const data = await handler(validation.value);
|
|
381
|
+
return {
|
|
382
|
+
data,
|
|
383
|
+
status: "success",
|
|
384
|
+
};
|
|
385
|
+
} catch (error) {
|
|
386
|
+
return {
|
|
387
|
+
error,
|
|
388
|
+
status: "error",
|
|
389
|
+
};
|
|
390
|
+
}
|
|
391
|
+
} finally {
|
|
392
|
+
activeSubmit = undefined;
|
|
393
|
+
commit({ submitting: false });
|
|
345
394
|
}
|
|
346
|
-
}
|
|
395
|
+
})();
|
|
347
396
|
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
if (!result.success) {
|
|
352
|
-
mergeIssueErrors(errors, result.issues);
|
|
353
|
-
} else if (Object.keys(errors).length === 0) {
|
|
354
|
-
setErrors({});
|
|
355
|
-
return {
|
|
356
|
-
success: true,
|
|
357
|
-
value: result.value as TSubmitValues,
|
|
358
|
-
};
|
|
359
|
-
}
|
|
360
|
-
}
|
|
361
|
-
|
|
362
|
-
if (Object.keys(errors).length > 0) {
|
|
363
|
-
setErrors(errors);
|
|
364
|
-
return {
|
|
365
|
-
errors,
|
|
366
|
-
success: false,
|
|
367
|
-
};
|
|
368
|
-
}
|
|
369
|
-
|
|
370
|
-
setErrors({});
|
|
371
|
-
return {
|
|
372
|
-
success: true,
|
|
373
|
-
value: values as TValues & TSubmitValues,
|
|
374
|
-
};
|
|
397
|
+
activeSubmit = task as Promise<FormSubmitResult<TValues, unknown>>;
|
|
398
|
+
return task;
|
|
375
399
|
},
|
|
400
|
+
validate: validateForm,
|
|
376
401
|
};
|
|
377
402
|
}
|
|
378
403
|
|