vue-form-submit 5.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2023 Ilya Semenov
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,348 @@
1
+ # vue-form-submit
2
+
3
+ Simple Vue 3 composables for handling form submission.
4
+
5
+ Supports optional validation with any [Standard Schema](https://standardschema.dev/) compatible validation library, such as [Zod](https://zod.dev), [Valibot](https://valibot.dev/), [ArkType](https://arktype.io/), and others.
6
+
7
+ Unlike FormKit, VeeValidate, and similar libraries, this keeps things simple and doesn't interfere with either data storage or the UI workflow.
8
+
9
+ Full TypeScript support with type inference.
10
+
11
+ ## Install
12
+
13
+ ```sh
14
+ npm install vue-form-submit
15
+ ```
16
+
17
+ ## Use
18
+
19
+ ```vue
20
+ <script setup lang="ts">
21
+ import * as v from "valibot"
22
+ import { useSubmit } from "vue-form-submit"
23
+
24
+ // Store input data however you prefer, e.g. with Vue reactive or ref.
25
+ const fields = reactive({
26
+ name: "",
27
+ })
28
+
29
+ const { form, submit, submitting, errors } = useSubmit({
30
+ input: fields,
31
+ // Schema is optional but usually recommended.
32
+ // Use any Standard Schema compatible library (Valibot in this example).
33
+ schema: v.object({
34
+ name: v.pipe(v.string(), v.trim(), v.minLength(1, "Please enter your name.")),
35
+ }),
36
+ async onSubmit(input) {
37
+ // Input is validated against the schema and typed accordingly.
38
+ await api.post(input)
39
+ },
40
+ })
41
+ </script>
42
+
43
+ <template>
44
+ <form ref="form" @submit.prevent="submit">
45
+ <!-- No special syntax for input fields — just use what you prefer. -->
46
+ Name: <input v-model="fields.name" />
47
+
48
+ <button type="submit" :disabled="submitting">Submit</button>
49
+
50
+ <!-- Raw validation errors. See below for how to flatten or structure them. -->
51
+ <div v-for="error in errors">{{ error }}</div>
52
+ </form>
53
+ </template>
54
+ ```
55
+
56
+ ## useSubmit composable
57
+
58
+ ```ts
59
+ const {
60
+ // All return values are optional to use.
61
+ form,
62
+ submit,
63
+ submitting,
64
+ submitted,
65
+ errors,
66
+ } = useSubmit({
67
+ // All options are optional.
68
+ input,
69
+ schema,
70
+ onSubmit,
71
+ onErrors,
72
+ // Optional overrides for the return value refs.
73
+ form,
74
+ submitting,
75
+ submitted,
76
+ errors,
77
+ })
78
+ ```
79
+
80
+ ## useSubmit options
81
+
82
+ ### `input`
83
+
84
+ (Optional) The data to be validated and/or passed to `submit`. Can be a plain value, a ref, or a getter.
85
+
86
+ ### `schema`
87
+
88
+ (Optional) A Standard Schema compatible schema (or a function returning a schema, useful when the schema depends on context). Works with Zod, Valibot, ArkType, and other Standard Schema compatible libraries.
89
+
90
+ ### `onSubmit`
91
+
92
+ (Optional) `onSubmit` callback.
93
+
94
+ Only called if:
95
+
96
+ - The form is not already being submitted (`submitting.value` is falsy).
97
+ - HTML5 validation passes (if enabled).
98
+ - Schema validation passes (if used).
99
+
100
+ If `input` and/or `schema` are provided, the first argument passed to the `onSubmit` callback is the (possibly validated) form input. Any remaining arguments are the submit function arguments.
101
+
102
+ While submission is in progress, `submitting` is true.
103
+ After successful execution, `submitted` is true.
104
+
105
+ ### `formatErrors`
106
+
107
+ (Optional) Error formatter function that transforms raw Standard Schema issues into the desired format.
108
+
109
+ See _"Formatting errors"_ below.
110
+
111
+ ### `onErrors`
112
+
113
+ (Optional) Error callback.
114
+
115
+ Called (and awaited) when validation fails or when `errors.value` is set by the `onSubmit` handler.
116
+
117
+ ### `form`, `submitting`, `submitted`, `errors`
118
+
119
+ Normally, `useSubmit` creates and returns these refs (see below), but you can optionally provide your own.
120
+
121
+ For example, you can share a single `submitting` flag between multiple forms:
122
+
123
+ ```ts
124
+ const submitting = ref(false)
125
+
126
+ const { submit: submit1 } = useSubmit({
127
+ submitting,
128
+ async onSubmit() { /* ... */ }
129
+ })
130
+
131
+ const { submit: submit2 } = useSubmit({
132
+ submitting,
133
+ async onSubmit() { /* ... */ }
134
+ })
135
+
136
+ // `submitting` will be true during submission of either form.
137
+ ```
138
+
139
+ ## useSubmit with a separate onSubmit handler
140
+
141
+ The `onSubmit` handler can be passed as a separate argument — either alone or together with an options object:
142
+
143
+ ```ts
144
+ // onSubmit handler only (shortcut):
145
+ const { submit, submitting } = useSubmit(async () => {
146
+ await api.post()
147
+ })
148
+
149
+ // onSubmit handler with options:
150
+ const { submit, submitting } = useSubmit({ input, schema }, async (input) => {
151
+ await api.post(input)
152
+ },)
153
+ ```
154
+
155
+ ## useSubmit return
156
+
157
+ ### `form`
158
+
159
+ The form element ref.
160
+
161
+ Binding it with `<form ref="form">` enables HTML5 validation on submit.
162
+
163
+ ### `submit`
164
+
165
+ The form submit function. Use it like:
166
+
167
+ - `<form @submit.prevent="submit">`
168
+ - `<button @click="submit">`
169
+
170
+ It will:
171
+
172
+ - Run HTML5 validation (if the form ref is set).
173
+ - Validate against the schema (if provided).
174
+ - Call the `onSubmit` callback (if provided).
175
+
176
+ Arguments passed to this function are forwarded to the `onSubmit` callback, prepended with the form input (if `input` and/or `schema` are provided).
177
+
178
+ While submission is in progress, `submitting` is true. After successful execution, `submitted` is true.
179
+
180
+ ### `submitting`
181
+
182
+ Whether a submission is currently in progress.
183
+
184
+ Use this to disable the submit button.
185
+
186
+ `useSubmit` will also skip submission if this is already `true`.
187
+
188
+ Type: `Ref<boolean>`.
189
+
190
+ ### `submitted`
191
+
192
+ Whether the form has been successfully submitted.
193
+
194
+ Feel free to reset this manually. `useSubmit` doesn't depend on this value.
195
+
196
+ Type: `Ref<boolean>`.
197
+
198
+ ### `errors`
199
+
200
+ Validation errors, either from schema validation or set manually in the `onSubmit` callback.
201
+
202
+ ## Formatting errors
203
+
204
+ By default, errors are returned as raw Standard Schema issues.
205
+
206
+ Use the `formatErrors` option to format or structure them differently. For example, use the built-in `flatten` to convert them to `FlatErrors` (compatible with Valibot's `flatten()`):
207
+
208
+ ```vue
209
+ <script setup lang="ts">
210
+ import * as v from "valibot"
211
+ import { flatten, useSubmit } from "vue-form-submit"
212
+
213
+ const fields = reactive({
214
+ name: "",
215
+ })
216
+
217
+ const { form, submit, submitting, errors } = useSubmit({
218
+ input: fields,
219
+ schema: v.object({
220
+ name: v.pipe(v.string(), v.trim(), v.minLength(1, "Please enter your name.")),
221
+ }),
222
+ formatErrors: flatten, // <--- Custom error formatter.
223
+ async onSubmit(input) {
224
+ await api.post(input)
225
+ },
226
+ })
227
+ </script>
228
+
229
+ <template>
230
+ <form ref="form" @submit.prevent="submit">
231
+ Name: <input v-model="fields.name" />
232
+
233
+ <!-- Field errors. -->
234
+ <div v-for="error in errors?.nested?.name">{{ error }}</div>
235
+
236
+ <button type="submit" :disabled="submitting">Submit</button>
237
+
238
+ <!-- Form-level errors. -->
239
+ <div v-for="error in errors?.root">{{ error }}</div>
240
+ </form>
241
+ </template>
242
+ ```
243
+
244
+ ## Submit with arguments
245
+
246
+ Additional arguments passed to `submit` are forwarded to the `onSubmit` callback after `input`:
247
+
248
+ ```ts
249
+ const { submit } = useSubmit({
250
+ input,
251
+ schema,
252
+ async onSubmit(input, chargeImmediately = false) {
253
+ await api.post({ ...input, chargeImmediately })
254
+ },
255
+ })
256
+ ```
257
+
258
+ Then in the template:
259
+
260
+ ```html
261
+ <form ref="form" @submit.prevent="submit">
262
+ <!-- Input fields omitted for brevity. -->
263
+ <button type="submit">Submit</button>
264
+ <button type="button" @click="submit(true)">
265
+ Submit and Charge Immediately
266
+ </button>
267
+ </form>
268
+ ```
269
+
270
+ If no `input` option was provided, all arguments are passed through directly:
271
+
272
+ ```ts
273
+ const { submit, submitting } = useSubmit(
274
+ async (arg1: number, arg2: string, arg3 = false) => {
275
+ // Note: no `input` argument.
276
+ await api.post({ arg1, arg2, arg3 })
277
+ },
278
+ )
279
+
280
+ // Arguments are type-checked:
281
+ submit(10, "foo")
282
+ submit(20, "bar", true)
283
+ ```
284
+
285
+ ## Custom submit errors
286
+
287
+ You can set `errors` inside the `onSubmit` handler. These are treated the same way as schema validation errors.
288
+
289
+ This is particularly useful together with `onErrors`:
290
+
291
+ ```ts
292
+ const { submit, errors } = useSubmit({
293
+ input,
294
+ schema,
295
+ onSubmit(input) {
296
+ if (!validateInput(input)) {
297
+ errors.value = [{ message: "Input is invalid." }]
298
+ }
299
+ },
300
+ onErrors(errors) {
301
+ // Errors here come from either schema validation or the onSubmit handler.
302
+ console.error(errors)
303
+ },
304
+ })
305
+ ```
306
+
307
+ ## useParse
308
+
309
+ `useParse` reactively runs Standard Schema validation on every input change.
310
+
311
+ It can be used together with `useSubmit` or independently.
312
+
313
+ Example with Valibot:
314
+
315
+ ```vue
316
+ <script setup lang="ts">
317
+ import * as v from "valibot"
318
+ import { flatten, useParse } from "vue-form-submit"
319
+
320
+ const input = reactive({
321
+ age: "" as string | number,
322
+ })
323
+
324
+ // By default, returns raw Standard Schema issues.
325
+ const { errors: presubmitErrors } = useParse({
326
+ input,
327
+ schema: v.object({
328
+ age: v.number(),
329
+ })
330
+ })
331
+
332
+ // Or use flatten for Valibot-style errors.
333
+ const { errors: presubmitErrors } = useParse({
334
+ input,
335
+ schema: v.object({
336
+ age: v.number(),
337
+ }),
338
+ formatErrors: flatten
339
+ })
340
+ </script>
341
+
342
+ <template>
343
+ <form @submit="...">
344
+ Age: <input v-model.number="age" type="number">
345
+ <button type="submit" :disabled="!presubmitErrors">Submit</button>
346
+ </form>
347
+ </template>
348
+ ```
package/dist/index.cjs ADDED
@@ -0,0 +1,115 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2
+ let _standard_schema_utils = require("@standard-schema/utils");
3
+ let _vue_reactivity = require("@vue/reactivity");
4
+ let _vue_runtime_core = require("@vue/runtime-core");
5
+
6
+ //#region src/errors/flatten.ts
7
+ /**
8
+ * Built-in error formatter that converts Standard Schema issues to FlatErrors format,
9
+ * compatible with Valibot's flatten() function.
10
+ */
11
+ function flatten(issues) {
12
+ const errors = {};
13
+ for (const issue of issues) {
14
+ const dotPath = (0, _standard_schema_utils.getDotPath)(issue);
15
+ if (dotPath) {
16
+ errors.nested ??= {};
17
+ errors.nested[dotPath] ??= [];
18
+ errors.nested[dotPath].push(issue.message);
19
+ } else {
20
+ errors.root ??= [];
21
+ errors.root.push(issue.message);
22
+ }
23
+ }
24
+ return errors;
25
+ }
26
+
27
+ //#endregion
28
+ //#region src/parse.ts
29
+ function useParse(options, watchOptions) {
30
+ const result = (0, _vue_reactivity.ref)();
31
+ const output = (0, _vue_reactivity.ref)();
32
+ const errors = (0, _vue_reactivity.ref)();
33
+ const formatErrors = options.formatErrors ?? ((issues) => issues);
34
+ function applyResult(r) {
35
+ result.value = r;
36
+ if (r.issues) {
37
+ output.value = void 0;
38
+ errors.value = formatErrors(r.issues);
39
+ } else {
40
+ output.value = r.value;
41
+ errors.value = void 0;
42
+ }
43
+ }
44
+ (0, _vue_runtime_core.watchEffect)((onCleanup) => {
45
+ const schema = (0, _vue_reactivity.toValue)(options.schema);
46
+ const input = (0, _vue_reactivity.toValue)(options.input);
47
+ const resultOrPromise = schema["~standard"].validate(input);
48
+ if (resultOrPromise instanceof Promise) {
49
+ let cancelled = false;
50
+ onCleanup(() => {
51
+ cancelled = true;
52
+ });
53
+ resultOrPromise.then((r) => {
54
+ if (!cancelled) applyResult(r);
55
+ });
56
+ } else applyResult(resultOrPromise);
57
+ }, watchOptions);
58
+ return {
59
+ result,
60
+ output,
61
+ errors
62
+ };
63
+ }
64
+
65
+ //#endregion
66
+ //#region src/submit.ts
67
+ function useSubmit(optionsOrOnSubmit, externalOnSubmit) {
68
+ const options = (typeof optionsOrOnSubmit === "function" ? void 0 : optionsOrOnSubmit) ?? {};
69
+ const onSubmitCallback = typeof optionsOrOnSubmit === "function" ? optionsOrOnSubmit : externalOnSubmit ?? options?.onSubmit;
70
+ const hasInput = options.input !== void 0;
71
+ const form = options.form ?? (0, _vue_reactivity.ref)();
72
+ const errors = options.errors ?? (0, _vue_reactivity.ref)();
73
+ const submitting = options.submitting ?? (0, _vue_reactivity.ref)(false);
74
+ const submitted = options.submitted ?? (0, _vue_reactivity.ref)(false);
75
+ const formatErrors = options.formatErrors ?? ((issues) => issues);
76
+ async function submit(...args) {
77
+ if (submitting.value) return;
78
+ submitted.value = false;
79
+ errors.value = void 0;
80
+ if (form.value && !form.value.checkValidity()) {
81
+ form.value.reportValidity();
82
+ return;
83
+ }
84
+ submitting.value = true;
85
+ try {
86
+ const input = (0, _vue_reactivity.toValue)(options.input);
87
+ const schema = (0, _vue_reactivity.toValue)(options.schema);
88
+ const parseResult = schema ? await schema["~standard"].validate(input) : void 0;
89
+ if (parseResult && parseResult.issues) {
90
+ errors.value = formatErrors(parseResult.issues);
91
+ await options.onErrors?.(errors.value);
92
+ } else {
93
+ const returnValue = await (hasInput || parseResult ? onSubmitCallback?.(parseResult ? parseResult.value : input, ...args) : onSubmitCallback?.(...args));
94
+ if (errors.value) await options.onErrors?.(errors.value);
95
+ else submitted.value = true;
96
+ return returnValue;
97
+ }
98
+ } finally {
99
+ submitting.value = false;
100
+ }
101
+ }
102
+ return {
103
+ form,
104
+ submit,
105
+ submitting,
106
+ submitted,
107
+ errors
108
+ };
109
+ }
110
+
111
+ //#endregion
112
+ exports.flatten = flatten;
113
+ exports.useParse = useParse;
114
+ exports.useSubmit = useSubmit;
115
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.cjs","names":[],"sources":["../src/errors/flatten.ts","../src/parse.ts","../src/submit.ts"],"sourcesContent":["import { getDotPath } from \"@standard-schema/utils\"\n\nimport type { StandardErrors } from \"./base\"\n\n/**\n * The FlatErrors interface, compatible with Valibot.\n *\n * TODO: accept Schema as a generic parameter, allow typed errors.\n */\nexport interface FlatErrors {\n /**\n * Root-level errors.\n *\n * Contains error messages from issues without a path (belonging to the root of the schema).\n */\n root?: string[]\n /**\n * Nested field errors.\n *\n * Contains error messages from issues with a path (belonging to nested parts\n * of the schema), keyed by their dot-notation path.\n */\n nested?: Partial<{\n [key: string]: string[]\n }>\n}\n\n/**\n * Built-in error formatter that converts Standard Schema issues to FlatErrors format,\n * compatible with Valibot's flatten() function.\n */\nexport function flatten(issues: StandardErrors): FlatErrors {\n const errors: FlatErrors = {}\n for (const issue of issues) {\n const dotPath = getDotPath(issue)\n if (dotPath) {\n errors.nested ??= {}\n errors.nested[dotPath] ??= []\n errors.nested[dotPath]!.push(issue.message)\n } else {\n errors.root ??= []\n errors.root.push(issue.message)\n }\n }\n\n return errors\n}\n","import type { StandardSchemaV1 } from \"@standard-schema/spec\"\nimport { ref, toValue } from \"@vue/reactivity\"\nimport type { MaybeRefOrGetter, Ref, WatchOptionsBase } from \"@vue/runtime-core\"\nimport { watchEffect } from \"@vue/runtime-core\"\n\nimport type { ErrorsFormatter, StandardErrors } from \"./errors\"\n\nexport type UseParseReturn<TSchema extends StandardSchemaV1, TErrors = StandardErrors> = {\n result: Ref<StandardSchemaV1.Result<StandardSchemaV1.InferOutput<TSchema>>>\n output: Ref<StandardSchemaV1.InferOutput<TSchema> | undefined>\n errors: Ref<TErrors | undefined>\n}\n\nexport function useParse<TSchema extends StandardSchemaV1, TErrors = StandardErrors>(\n options: {\n /**\n * The input data to validate (plain value, ref, or getter).\n */\n input?: unknown\n /**\n * A Standard Schema compatible schema (plain value, ref, or getter).\n */\n schema: MaybeRefOrGetter<TSchema>\n /**\n * Error formatter function that transforms raw Standard Schema issues into the desired format.\n */\n formatErrors?: ErrorsFormatter<TErrors>\n },\n watchOptions?: WatchOptionsBase,\n): UseParseReturn<TSchema, TErrors> {\n type Output = StandardSchemaV1.InferOutput<TSchema>\n const result = ref<StandardSchemaV1.Result<Output>>() as Ref<StandardSchemaV1.Result<Output>>\n const output = ref<Output>()\n const errors = ref<TErrors | undefined>()\n const formatErrors = options.formatErrors ?? ((issues: StandardErrors) => issues as TErrors)\n\n function applyResult(r: StandardSchemaV1.Result<Output>) {\n result.value = r\n if (r.issues) {\n output.value = undefined\n errors.value = formatErrors(r.issues)\n } else {\n output.value = r.value\n errors.value = undefined\n }\n }\n\n watchEffect((onCleanup) => {\n const schema = toValue(options.schema)\n const input = toValue(options.input)\n const resultOrPromise = schema[\"~standard\"].validate(input)\n\n if (resultOrPromise instanceof Promise) {\n let cancelled = false\n onCleanup(() => {\n cancelled = true\n })\n resultOrPromise.then((r) => {\n if (!cancelled) {\n applyResult(r)\n }\n })\n } else {\n applyResult(resultOrPromise)\n }\n }, watchOptions)\n\n return { result, output, errors }\n}\n","import type { StandardSchemaV1 } from \"@standard-schema/spec\"\nimport type { MaybeRefOrGetter, Ref } from \"@vue/reactivity\"\nimport { ref, toValue } from \"@vue/reactivity\"\n\nimport type { ErrorsFormatter, StandardErrors } from \"./errors\"\n\nexport interface UseSubmitReturn<TArgs extends any[], TResult, TErrors> {\n /**\n * The form element ref.\n *\n * Using it with `<form ref=\"form\">` will enable HTML5 validation on submit.\n */\n form: Ref<HTMLFormElement | undefined>\n /**\n * The form submit function. Use it like:\n *\n * - `<form @submit.prevent=\"submit\">`\n * - `<button @click=\"submit\">`\n *\n * It will:\n *\n * - Run HTML5 validation (if the form ref is set).\n * - Run Standard Schema validation (if the schema is provided).\n * - Call the `onSubmit` callback (if provided).\n *\n * Arguments passed to this function are forwarded to the `onSubmit` callback,\n * prepended with the (possibly validated) form input (unless using the shortcut variant of `useSubmit`).\n *\n * While submission is in progress, `submitting` is true.\n * After successful execution, `submitted` is true.\n */\n submit: (...args: TArgs) => Promise<TResult | undefined>\n /**\n * Whether a submission is currently in progress.\n *\n * Use this to disable the submit button.\n *\n * `useSubmit` will also skip submission if this is already `true`.\n */\n submitting: Ref<boolean>\n /**\n * Has the form been successfully submitted?\n *\n * Feel free to reset. `useSubmit` doesn't depend on this value.\n */\n submitted: Ref<boolean>\n /**\n * Validation errors.\n */\n errors: Ref<TErrors | undefined>\n}\n\ninterface BaseOptions<TErrors> {\n /**\n * Error formatter function that transforms raw Standard Schema issues into the desired format.\n */\n formatErrors?: ErrorsFormatter<TErrors>\n /**\n * Error callback.\n *\n * Called (and awaited) when validation fails or when `errors.value` is set by the `onSubmit` handler.\n */\n onErrors?: (errors: TErrors) => any\n /**\n * User-provided ref for the `form` return value.\n */\n form?: Ref<HTMLFormElement | undefined>\n /**\n * User-provided ref for the `submitting` return value.\n */\n submitting?: Ref<boolean>\n /**\n * User-provided ref for the `submitted` return value.\n */\n submitted?: Ref<boolean>\n /**\n * User-provided ref for the `errors` return value.\n */\n errors?: Ref<TErrors | undefined>\n}\n\ntype SubmitCallback<Args extends any[], Result> = (\n ...args: Args\n) => Result | PromiseLike<Result>\n\n//\n// No input.\n//\n\n/**\n * Vue 3 composable for handling form submission.\n */\nexport function useSubmit<Args extends unknown[], Result, TErrors = StandardErrors>(\n options: BaseOptions<TErrors> & {\n input?: never\n schema?: never\n /**\n * onSubmit callback.\n *\n * Only called if:\n * - The form is not already being submitted (`submitting.value` is falsy).\n * - HTML5 validation passes (if enabled).\n *\n * Arguments are passed through from the submit function.\n *\n * While submission is in progress, `submitting` is true.\n * After successful execution, `submitted` is true.\n */\n onSubmit?: SubmitCallback<Args, Result>\n },\n): UseSubmitReturn<Args, Result, TErrors>\n\n//\n// Input only (no schema).\n//\n\n/**\n * Vue 3 composable for handling form submission.\n *\n * Validates the input using Standard Schema.\n */\nexport function useSubmit<TInput, TArgs extends any[], TResult, TErrors = StandardErrors>(\n options: BaseOptions<TErrors> & {\n /**\n * The input data: a plain value, ref, or getter.\n */\n input: MaybeRefOrGetter<TInput>\n schema?: never\n /**\n * onSubmit callback.\n *\n * Only called if:\n * - The form is not already being submitted (`submitting.value` is falsy).\n * - HTML5 validation passes (if enabled).\n *\n * The first argument is the form input; the remaining arguments are passed through from the submit function.\n *\n * While submission is in progress, `submitting` is true.\n * After successful execution, `submitted` is true.\n */\n onSubmit?: SubmitCallback<[TInput, ...TArgs], TResult>\n },\n): UseSubmitReturn<TArgs, TResult, TErrors>\n\n//\n// Schema.\n//\n\n/**\n * Vue 3 composable for handling form submission.\n *\n * Validates the input using Standard Schema.\n */\nexport function useSubmit<TSchema extends StandardSchemaV1, TArgs extends any[], TResult, TErrors = StandardErrors>(\n options: BaseOptions<TErrors> & {\n /**\n * The input data to validate (plain value, ref, or getter).\n */\n input?: unknown\n /**\n * A Standard Schema compatible schema (plain value, ref, or getter).\n */\n schema: MaybeRefOrGetter<TSchema>\n /**\n * onSubmit callback.\n *\n * Only called if:\n * - The form is not already being submitted (`submitting.value` is falsy).\n * - HTML5 validation passes (if enabled).\n * - Standard Schema validation passes.\n *\n * The first argument is the validated input; the remaining arguments are passed through from the submit function.\n *\n * While submission is in progress, `submitting` is true.\n * After successful execution, `submitted` is true.\n */\n onSubmit?: SubmitCallback<[StandardSchemaV1.InferOutput<TSchema>, ...TArgs], TResult>\n },\n): UseSubmitReturn<TArgs, TResult, TErrors>\n\n//\n// No input, separate submit.\n//\n\n/**\n * Vue 3 composable for handling form submission.\n */\nexport function useSubmit<Args extends unknown[], Result, TErrors = StandardErrors>(\n options: BaseOptions<TErrors> & {\n input?: never\n schema?: never\n onSubmit?: never\n },\n onSubmit: SubmitCallback<Args, Result>,\n): UseSubmitReturn<Args, Result, TErrors>\n\n//\n// Input only (no schema), separate submit.\n//\n\n/**\n * Vue 3 composable for handling form submission.\n */\nexport function useSubmit<TInput, TArgs extends any[], TResult, TErrors = StandardErrors>(\n options: BaseOptions<TErrors> & {\n input: MaybeRefOrGetter<TInput>\n schema?: never\n onSubmit?: never\n },\n onSubmit: SubmitCallback<[TInput, ...TArgs], TResult>,\n): UseSubmitReturn<TArgs, TResult, TErrors>\n\n//\n// Schema, separate submit.\n//\n\n/**\n * Vue 3 composable for handling form submission.\n */\nexport function useSubmit<TSchema extends StandardSchemaV1, TArgs extends any[], TResult, TErrors = StandardErrors>(\n options: BaseOptions<TErrors> & {\n input?: unknown\n schema: MaybeRefOrGetter<TSchema>\n onSubmit?: never\n },\n onSubmit: SubmitCallback<[StandardSchemaV1.InferOutput<TSchema>, ...TArgs], TResult>,\n): UseSubmitReturn<TArgs, TResult, TErrors>\n\n//\n// No input, callback only.\n//\n\n/**\n * Vue 3 composable for handling form submission.\n */\nexport function useSubmit<TArgs extends any[], TResult>(\n/**\n * onSubmit callback.\n *\n * Only called if:\n * - The form is not already being submitted (`submitting.value` is falsy).\n * - HTML5 validation passes (if enabled).\n *\n * Arguments are passed through from the submit function.\n *\n * While submission is in progress, `submitting` is true.\n * After successful execution, `submitted` is true.\n */\n onSubmit?: SubmitCallback<TArgs, TResult>,\n): UseSubmitReturn<TArgs, TResult, StandardErrors>\n\n//\n// Implementation.\n//\n\nexport function useSubmit(\n optionsOrOnSubmit?:\n | (BaseOptions<unknown> & {\n input?: unknown\n schema?: MaybeRefOrGetter<StandardSchemaV1>\n onSubmit?: SubmitCallback<unknown[], unknown>\n })\n | SubmitCallback<unknown[], unknown>,\n externalOnSubmit?: SubmitCallback<unknown[], unknown>,\n): UseSubmitReturn<unknown[], unknown, unknown> {\n const options\n = (typeof optionsOrOnSubmit === \"function\" ? undefined : optionsOrOnSubmit) ?? {}\n const onSubmitCallback\n = typeof optionsOrOnSubmit === \"function\" ? optionsOrOnSubmit : externalOnSubmit ?? options?.onSubmit\n const hasInput = options.input !== undefined\n\n const form = options.form ?? ref<HTMLFormElement>()\n const errors = options.errors ?? ref()\n const submitting = options.submitting ?? ref(false)\n const submitted = options.submitted ?? ref(false)\n\n const formatErrors = options.formatErrors ?? ((issues: StandardErrors) => issues)\n\n async function submit(...args: unknown[]) {\n if (submitting.value) {\n return\n }\n submitted.value = false\n errors.value = undefined\n if (form.value && !form.value.checkValidity()) {\n form.value.reportValidity()\n return\n }\n submitting.value = true\n try {\n const input = toValue(options.input)\n const schema = toValue(options.schema)\n const parseResult = schema ? await schema[\"~standard\"].validate(input) : undefined\n if (parseResult && parseResult.issues) {\n errors.value = formatErrors(parseResult.issues)\n await options.onErrors?.(errors.value)\n } else {\n const returnValue = await (\n hasInput || parseResult\n ? onSubmitCallback?.(parseResult ? parseResult.value : input, ...args)\n : onSubmitCallback?.(...args)\n )\n if (errors.value) {\n await options.onErrors?.(errors.value)\n } else {\n submitted.value = true\n }\n return returnValue\n }\n } finally {\n submitting.value = false\n }\n }\n\n return { form, submit, submitting, submitted, errors }\n}\n"],"mappings":";;;;;;;;;;AA+BA,SAAgB,QAAQ,QAAoC;CAC1D,MAAM,SAAqB,EAAE;AAC7B,MAAK,MAAM,SAAS,QAAQ;EAC1B,MAAM,iDAAqB,MAAM;AACjC,MAAI,SAAS;AACX,UAAO,WAAW,EAAE;AACpB,UAAO,OAAO,aAAa,EAAE;AAC7B,UAAO,OAAO,SAAU,KAAK,MAAM,QAAQ;SACtC;AACL,UAAO,SAAS,EAAE;AAClB,UAAO,KAAK,KAAK,MAAM,QAAQ;;;AAInC,QAAO;;;;;AChCT,SAAgB,SACd,SAcA,cACkC;CAElC,MAAM,mCAA+C;CACrD,MAAM,mCAAsB;CAC5B,MAAM,mCAAmC;CACzC,MAAM,eAAe,QAAQ,kBAAkB,WAA2B;CAE1E,SAAS,YAAY,GAAoC;AACvD,SAAO,QAAQ;AACf,MAAI,EAAE,QAAQ;AACZ,UAAO,QAAQ;AACf,UAAO,QAAQ,aAAa,EAAE,OAAO;SAChC;AACL,UAAO,QAAQ,EAAE;AACjB,UAAO,QAAQ;;;AAInB,qCAAa,cAAc;EACzB,MAAM,sCAAiB,QAAQ,OAAO;EACtC,MAAM,qCAAgB,QAAQ,MAAM;EACpC,MAAM,kBAAkB,OAAO,aAAa,SAAS,MAAM;AAE3D,MAAI,2BAA2B,SAAS;GACtC,IAAI,YAAY;AAChB,mBAAgB;AACd,gBAAY;KACZ;AACF,mBAAgB,MAAM,MAAM;AAC1B,QAAI,CAAC,UACH,aAAY,EAAE;KAEhB;QAEF,aAAY,gBAAgB;IAE7B,aAAa;AAEhB,QAAO;EAAE;EAAQ;EAAQ;EAAQ;;;;;AC4LnC,SAAgB,UACd,mBAOA,kBAC8C;CAC9C,MAAM,WACD,OAAO,sBAAsB,aAAa,SAAY,sBAAsB,EAAE;CACnF,MAAM,mBACF,OAAO,sBAAsB,aAAa,oBAAoB,oBAAoB,SAAS;CAC/F,MAAM,WAAW,QAAQ,UAAU;CAEnC,MAAM,OAAO,QAAQ,kCAA8B;CACnD,MAAM,SAAS,QAAQ,oCAAe;CACtC,MAAM,aAAa,QAAQ,uCAAkB,MAAM;CACnD,MAAM,YAAY,QAAQ,sCAAiB,MAAM;CAEjD,MAAM,eAAe,QAAQ,kBAAkB,WAA2B;CAE1E,eAAe,OAAO,GAAG,MAAiB;AACxC,MAAI,WAAW,MACb;AAEF,YAAU,QAAQ;AAClB,SAAO,QAAQ;AACf,MAAI,KAAK,SAAS,CAAC,KAAK,MAAM,eAAe,EAAE;AAC7C,QAAK,MAAM,gBAAgB;AAC3B;;AAEF,aAAW,QAAQ;AACnB,MAAI;GACF,MAAM,qCAAgB,QAAQ,MAAM;GACpC,MAAM,sCAAiB,QAAQ,OAAO;GACtC,MAAM,cAAc,SAAS,MAAM,OAAO,aAAa,SAAS,MAAM,GAAG;AACzE,OAAI,eAAe,YAAY,QAAQ;AACrC,WAAO,QAAQ,aAAa,YAAY,OAAO;AAC/C,UAAM,QAAQ,WAAW,OAAO,MAAM;UACjC;IACL,MAAM,cAAc,OAClB,YAAY,cACR,mBAAmB,cAAc,YAAY,QAAQ,OAAO,GAAG,KAAK,GACpE,mBAAmB,GAAG,KAAK;AAEjC,QAAI,OAAO,MACT,OAAM,QAAQ,WAAW,OAAO,MAAM;QAEtC,WAAU,QAAQ;AAEpB,WAAO;;YAED;AACR,cAAW,QAAQ;;;AAIvB,QAAO;EAAE;EAAM;EAAQ;EAAY;EAAW;EAAQ"}
@@ -0,0 +1,252 @@
1
+ import { StandardSchemaV1 } from "@standard-schema/spec";
2
+ import { MaybeRefOrGetter, Ref, WatchOptionsBase } from "@vue/runtime-core";
3
+ import { MaybeRefOrGetter as MaybeRefOrGetter$1, Ref as Ref$1 } from "@vue/reactivity";
4
+
5
+ //#region src/errors/base.d.ts
6
+ type StandardErrors = readonly StandardSchemaV1.Issue[];
7
+ type ErrorsFormatter<TErrors> = (issues: StandardErrors) => TErrors;
8
+ //#endregion
9
+ //#region src/errors/flatten.d.ts
10
+ /**
11
+ * The FlatErrors interface, compatible with Valibot.
12
+ *
13
+ * TODO: accept Schema as a generic parameter, allow typed errors.
14
+ */
15
+ interface FlatErrors {
16
+ /**
17
+ * Root-level errors.
18
+ *
19
+ * Contains error messages from issues without a path (belonging to the root of the schema).
20
+ */
21
+ root?: string[];
22
+ /**
23
+ * Nested field errors.
24
+ *
25
+ * Contains error messages from issues with a path (belonging to nested parts
26
+ * of the schema), keyed by their dot-notation path.
27
+ */
28
+ nested?: Partial<{
29
+ [key: string]: string[];
30
+ }>;
31
+ }
32
+ /**
33
+ * Built-in error formatter that converts Standard Schema issues to FlatErrors format,
34
+ * compatible with Valibot's flatten() function.
35
+ */
36
+ declare function flatten(issues: StandardErrors): FlatErrors;
37
+ //#endregion
38
+ //#region src/parse.d.ts
39
+ type UseParseReturn<TSchema extends StandardSchemaV1, TErrors = StandardErrors> = {
40
+ result: Ref<StandardSchemaV1.Result<StandardSchemaV1.InferOutput<TSchema>>>;
41
+ output: Ref<StandardSchemaV1.InferOutput<TSchema> | undefined>;
42
+ errors: Ref<TErrors | undefined>;
43
+ };
44
+ declare function useParse<TSchema extends StandardSchemaV1, TErrors = StandardErrors>(options: {
45
+ /**
46
+ * The input data to validate (plain value, ref, or getter).
47
+ */
48
+ input?: unknown;
49
+ /**
50
+ * A Standard Schema compatible schema (plain value, ref, or getter).
51
+ */
52
+ schema: MaybeRefOrGetter<TSchema>;
53
+ /**
54
+ * Error formatter function that transforms raw Standard Schema issues into the desired format.
55
+ */
56
+ formatErrors?: ErrorsFormatter<TErrors>;
57
+ }, watchOptions?: WatchOptionsBase): UseParseReturn<TSchema, TErrors>;
58
+ //#endregion
59
+ //#region src/submit.d.ts
60
+ interface UseSubmitReturn<TArgs extends any[], TResult, TErrors> {
61
+ /**
62
+ * The form element ref.
63
+ *
64
+ * Using it with `<form ref="form">` will enable HTML5 validation on submit.
65
+ */
66
+ form: Ref$1<HTMLFormElement | undefined>;
67
+ /**
68
+ * The form submit function. Use it like:
69
+ *
70
+ * - `<form @submit.prevent="submit">`
71
+ * - `<button @click="submit">`
72
+ *
73
+ * It will:
74
+ *
75
+ * - Run HTML5 validation (if the form ref is set).
76
+ * - Run Standard Schema validation (if the schema is provided).
77
+ * - Call the `onSubmit` callback (if provided).
78
+ *
79
+ * Arguments passed to this function are forwarded to the `onSubmit` callback,
80
+ * prepended with the (possibly validated) form input (unless using the shortcut variant of `useSubmit`).
81
+ *
82
+ * While submission is in progress, `submitting` is true.
83
+ * After successful execution, `submitted` is true.
84
+ */
85
+ submit: (...args: TArgs) => Promise<TResult | undefined>;
86
+ /**
87
+ * Whether a submission is currently in progress.
88
+ *
89
+ * Use this to disable the submit button.
90
+ *
91
+ * `useSubmit` will also skip submission if this is already `true`.
92
+ */
93
+ submitting: Ref$1<boolean>;
94
+ /**
95
+ * Has the form been successfully submitted?
96
+ *
97
+ * Feel free to reset. `useSubmit` doesn't depend on this value.
98
+ */
99
+ submitted: Ref$1<boolean>;
100
+ /**
101
+ * Validation errors.
102
+ */
103
+ errors: Ref$1<TErrors | undefined>;
104
+ }
105
+ interface BaseOptions<TErrors> {
106
+ /**
107
+ * Error formatter function that transforms raw Standard Schema issues into the desired format.
108
+ */
109
+ formatErrors?: ErrorsFormatter<TErrors>;
110
+ /**
111
+ * Error callback.
112
+ *
113
+ * Called (and awaited) when validation fails or when `errors.value` is set by the `onSubmit` handler.
114
+ */
115
+ onErrors?: (errors: TErrors) => any;
116
+ /**
117
+ * User-provided ref for the `form` return value.
118
+ */
119
+ form?: Ref$1<HTMLFormElement | undefined>;
120
+ /**
121
+ * User-provided ref for the `submitting` return value.
122
+ */
123
+ submitting?: Ref$1<boolean>;
124
+ /**
125
+ * User-provided ref for the `submitted` return value.
126
+ */
127
+ submitted?: Ref$1<boolean>;
128
+ /**
129
+ * User-provided ref for the `errors` return value.
130
+ */
131
+ errors?: Ref$1<TErrors | undefined>;
132
+ }
133
+ type SubmitCallback<Args extends any[], Result> = (...args: Args) => Result | PromiseLike<Result>;
134
+ /**
135
+ * Vue 3 composable for handling form submission.
136
+ */
137
+ declare function useSubmit<Args extends unknown[], Result, TErrors = StandardErrors>(options: BaseOptions<TErrors> & {
138
+ input?: never;
139
+ schema?: never;
140
+ /**
141
+ * onSubmit callback.
142
+ *
143
+ * Only called if:
144
+ * - The form is not already being submitted (`submitting.value` is falsy).
145
+ * - HTML5 validation passes (if enabled).
146
+ *
147
+ * Arguments are passed through from the submit function.
148
+ *
149
+ * While submission is in progress, `submitting` is true.
150
+ * After successful execution, `submitted` is true.
151
+ */
152
+ onSubmit?: SubmitCallback<Args, Result>;
153
+ }): UseSubmitReturn<Args, Result, TErrors>;
154
+ /**
155
+ * Vue 3 composable for handling form submission.
156
+ *
157
+ * Validates the input using Standard Schema.
158
+ */
159
+ declare function useSubmit<TInput, TArgs extends any[], TResult, TErrors = StandardErrors>(options: BaseOptions<TErrors> & {
160
+ /**
161
+ * The input data: a plain value, ref, or getter.
162
+ */
163
+ input: MaybeRefOrGetter$1<TInput>;
164
+ schema?: never;
165
+ /**
166
+ * onSubmit callback.
167
+ *
168
+ * Only called if:
169
+ * - The form is not already being submitted (`submitting.value` is falsy).
170
+ * - HTML5 validation passes (if enabled).
171
+ *
172
+ * The first argument is the form input; the remaining arguments are passed through from the submit function.
173
+ *
174
+ * While submission is in progress, `submitting` is true.
175
+ * After successful execution, `submitted` is true.
176
+ */
177
+ onSubmit?: SubmitCallback<[TInput, ...TArgs], TResult>;
178
+ }): UseSubmitReturn<TArgs, TResult, TErrors>;
179
+ /**
180
+ * Vue 3 composable for handling form submission.
181
+ *
182
+ * Validates the input using Standard Schema.
183
+ */
184
+ declare function useSubmit<TSchema extends StandardSchemaV1, TArgs extends any[], TResult, TErrors = StandardErrors>(options: BaseOptions<TErrors> & {
185
+ /**
186
+ * The input data to validate (plain value, ref, or getter).
187
+ */
188
+ input?: unknown;
189
+ /**
190
+ * A Standard Schema compatible schema (plain value, ref, or getter).
191
+ */
192
+ schema: MaybeRefOrGetter$1<TSchema>;
193
+ /**
194
+ * onSubmit callback.
195
+ *
196
+ * Only called if:
197
+ * - The form is not already being submitted (`submitting.value` is falsy).
198
+ * - HTML5 validation passes (if enabled).
199
+ * - Standard Schema validation passes.
200
+ *
201
+ * The first argument is the validated input; the remaining arguments are passed through from the submit function.
202
+ *
203
+ * While submission is in progress, `submitting` is true.
204
+ * After successful execution, `submitted` is true.
205
+ */
206
+ onSubmit?: SubmitCallback<[StandardSchemaV1.InferOutput<TSchema>, ...TArgs], TResult>;
207
+ }): UseSubmitReturn<TArgs, TResult, TErrors>;
208
+ /**
209
+ * Vue 3 composable for handling form submission.
210
+ */
211
+ declare function useSubmit<Args extends unknown[], Result, TErrors = StandardErrors>(options: BaseOptions<TErrors> & {
212
+ input?: never;
213
+ schema?: never;
214
+ onSubmit?: never;
215
+ }, onSubmit: SubmitCallback<Args, Result>): UseSubmitReturn<Args, Result, TErrors>;
216
+ /**
217
+ * Vue 3 composable for handling form submission.
218
+ */
219
+ declare function useSubmit<TInput, TArgs extends any[], TResult, TErrors = StandardErrors>(options: BaseOptions<TErrors> & {
220
+ input: MaybeRefOrGetter$1<TInput>;
221
+ schema?: never;
222
+ onSubmit?: never;
223
+ }, onSubmit: SubmitCallback<[TInput, ...TArgs], TResult>): UseSubmitReturn<TArgs, TResult, TErrors>;
224
+ /**
225
+ * Vue 3 composable for handling form submission.
226
+ */
227
+ declare function useSubmit<TSchema extends StandardSchemaV1, TArgs extends any[], TResult, TErrors = StandardErrors>(options: BaseOptions<TErrors> & {
228
+ input?: unknown;
229
+ schema: MaybeRefOrGetter$1<TSchema>;
230
+ onSubmit?: never;
231
+ }, onSubmit: SubmitCallback<[StandardSchemaV1.InferOutput<TSchema>, ...TArgs], TResult>): UseSubmitReturn<TArgs, TResult, TErrors>;
232
+ /**
233
+ * Vue 3 composable for handling form submission.
234
+ */
235
+ declare function useSubmit<TArgs extends any[], TResult>(
236
+ /**
237
+ * onSubmit callback.
238
+ *
239
+ * Only called if:
240
+ * - The form is not already being submitted (`submitting.value` is falsy).
241
+ * - HTML5 validation passes (if enabled).
242
+ *
243
+ * Arguments are passed through from the submit function.
244
+ *
245
+ * While submission is in progress, `submitting` is true.
246
+ * After successful execution, `submitted` is true.
247
+ */
248
+
249
+ onSubmit?: SubmitCallback<TArgs, TResult>): UseSubmitReturn<TArgs, TResult, StandardErrors>;
250
+ //#endregion
251
+ export { ErrorsFormatter, FlatErrors, StandardErrors, UseParseReturn, UseSubmitReturn, flatten, useParse, useSubmit };
252
+ //# sourceMappingURL=index.d.cts.map
@@ -0,0 +1,252 @@
1
+ import { MaybeRefOrGetter, Ref } from "@vue/reactivity";
2
+ import { MaybeRefOrGetter as MaybeRefOrGetter$1, Ref as Ref$1, WatchOptionsBase } from "@vue/runtime-core";
3
+ import { StandardSchemaV1 } from "@standard-schema/spec";
4
+
5
+ //#region src/errors/base.d.ts
6
+ type StandardErrors = readonly StandardSchemaV1.Issue[];
7
+ type ErrorsFormatter<TErrors> = (issues: StandardErrors) => TErrors;
8
+ //#endregion
9
+ //#region src/errors/flatten.d.ts
10
+ /**
11
+ * The FlatErrors interface, compatible with Valibot.
12
+ *
13
+ * TODO: accept Schema as a generic parameter, allow typed errors.
14
+ */
15
+ interface FlatErrors {
16
+ /**
17
+ * Root-level errors.
18
+ *
19
+ * Contains error messages from issues without a path (belonging to the root of the schema).
20
+ */
21
+ root?: string[];
22
+ /**
23
+ * Nested field errors.
24
+ *
25
+ * Contains error messages from issues with a path (belonging to nested parts
26
+ * of the schema), keyed by their dot-notation path.
27
+ */
28
+ nested?: Partial<{
29
+ [key: string]: string[];
30
+ }>;
31
+ }
32
+ /**
33
+ * Built-in error formatter that converts Standard Schema issues to FlatErrors format,
34
+ * compatible with Valibot's flatten() function.
35
+ */
36
+ declare function flatten(issues: StandardErrors): FlatErrors;
37
+ //#endregion
38
+ //#region src/parse.d.ts
39
+ type UseParseReturn<TSchema extends StandardSchemaV1, TErrors = StandardErrors> = {
40
+ result: Ref$1<StandardSchemaV1.Result<StandardSchemaV1.InferOutput<TSchema>>>;
41
+ output: Ref$1<StandardSchemaV1.InferOutput<TSchema> | undefined>;
42
+ errors: Ref$1<TErrors | undefined>;
43
+ };
44
+ declare function useParse<TSchema extends StandardSchemaV1, TErrors = StandardErrors>(options: {
45
+ /**
46
+ * The input data to validate (plain value, ref, or getter).
47
+ */
48
+ input?: unknown;
49
+ /**
50
+ * A Standard Schema compatible schema (plain value, ref, or getter).
51
+ */
52
+ schema: MaybeRefOrGetter$1<TSchema>;
53
+ /**
54
+ * Error formatter function that transforms raw Standard Schema issues into the desired format.
55
+ */
56
+ formatErrors?: ErrorsFormatter<TErrors>;
57
+ }, watchOptions?: WatchOptionsBase): UseParseReturn<TSchema, TErrors>;
58
+ //#endregion
59
+ //#region src/submit.d.ts
60
+ interface UseSubmitReturn<TArgs extends any[], TResult, TErrors> {
61
+ /**
62
+ * The form element ref.
63
+ *
64
+ * Using it with `<form ref="form">` will enable HTML5 validation on submit.
65
+ */
66
+ form: Ref<HTMLFormElement | undefined>;
67
+ /**
68
+ * The form submit function. Use it like:
69
+ *
70
+ * - `<form @submit.prevent="submit">`
71
+ * - `<button @click="submit">`
72
+ *
73
+ * It will:
74
+ *
75
+ * - Run HTML5 validation (if the form ref is set).
76
+ * - Run Standard Schema validation (if the schema is provided).
77
+ * - Call the `onSubmit` callback (if provided).
78
+ *
79
+ * Arguments passed to this function are forwarded to the `onSubmit` callback,
80
+ * prepended with the (possibly validated) form input (unless using the shortcut variant of `useSubmit`).
81
+ *
82
+ * While submission is in progress, `submitting` is true.
83
+ * After successful execution, `submitted` is true.
84
+ */
85
+ submit: (...args: TArgs) => Promise<TResult | undefined>;
86
+ /**
87
+ * Whether a submission is currently in progress.
88
+ *
89
+ * Use this to disable the submit button.
90
+ *
91
+ * `useSubmit` will also skip submission if this is already `true`.
92
+ */
93
+ submitting: Ref<boolean>;
94
+ /**
95
+ * Has the form been successfully submitted?
96
+ *
97
+ * Feel free to reset. `useSubmit` doesn't depend on this value.
98
+ */
99
+ submitted: Ref<boolean>;
100
+ /**
101
+ * Validation errors.
102
+ */
103
+ errors: Ref<TErrors | undefined>;
104
+ }
105
+ interface BaseOptions<TErrors> {
106
+ /**
107
+ * Error formatter function that transforms raw Standard Schema issues into the desired format.
108
+ */
109
+ formatErrors?: ErrorsFormatter<TErrors>;
110
+ /**
111
+ * Error callback.
112
+ *
113
+ * Called (and awaited) when validation fails or when `errors.value` is set by the `onSubmit` handler.
114
+ */
115
+ onErrors?: (errors: TErrors) => any;
116
+ /**
117
+ * User-provided ref for the `form` return value.
118
+ */
119
+ form?: Ref<HTMLFormElement | undefined>;
120
+ /**
121
+ * User-provided ref for the `submitting` return value.
122
+ */
123
+ submitting?: Ref<boolean>;
124
+ /**
125
+ * User-provided ref for the `submitted` return value.
126
+ */
127
+ submitted?: Ref<boolean>;
128
+ /**
129
+ * User-provided ref for the `errors` return value.
130
+ */
131
+ errors?: Ref<TErrors | undefined>;
132
+ }
133
+ type SubmitCallback<Args extends any[], Result> = (...args: Args) => Result | PromiseLike<Result>;
134
+ /**
135
+ * Vue 3 composable for handling form submission.
136
+ */
137
+ declare function useSubmit<Args extends unknown[], Result, TErrors = StandardErrors>(options: BaseOptions<TErrors> & {
138
+ input?: never;
139
+ schema?: never;
140
+ /**
141
+ * onSubmit callback.
142
+ *
143
+ * Only called if:
144
+ * - The form is not already being submitted (`submitting.value` is falsy).
145
+ * - HTML5 validation passes (if enabled).
146
+ *
147
+ * Arguments are passed through from the submit function.
148
+ *
149
+ * While submission is in progress, `submitting` is true.
150
+ * After successful execution, `submitted` is true.
151
+ */
152
+ onSubmit?: SubmitCallback<Args, Result>;
153
+ }): UseSubmitReturn<Args, Result, TErrors>;
154
+ /**
155
+ * Vue 3 composable for handling form submission.
156
+ *
157
+ * Validates the input using Standard Schema.
158
+ */
159
+ declare function useSubmit<TInput, TArgs extends any[], TResult, TErrors = StandardErrors>(options: BaseOptions<TErrors> & {
160
+ /**
161
+ * The input data: a plain value, ref, or getter.
162
+ */
163
+ input: MaybeRefOrGetter<TInput>;
164
+ schema?: never;
165
+ /**
166
+ * onSubmit callback.
167
+ *
168
+ * Only called if:
169
+ * - The form is not already being submitted (`submitting.value` is falsy).
170
+ * - HTML5 validation passes (if enabled).
171
+ *
172
+ * The first argument is the form input; the remaining arguments are passed through from the submit function.
173
+ *
174
+ * While submission is in progress, `submitting` is true.
175
+ * After successful execution, `submitted` is true.
176
+ */
177
+ onSubmit?: SubmitCallback<[TInput, ...TArgs], TResult>;
178
+ }): UseSubmitReturn<TArgs, TResult, TErrors>;
179
+ /**
180
+ * Vue 3 composable for handling form submission.
181
+ *
182
+ * Validates the input using Standard Schema.
183
+ */
184
+ declare function useSubmit<TSchema extends StandardSchemaV1, TArgs extends any[], TResult, TErrors = StandardErrors>(options: BaseOptions<TErrors> & {
185
+ /**
186
+ * The input data to validate (plain value, ref, or getter).
187
+ */
188
+ input?: unknown;
189
+ /**
190
+ * A Standard Schema compatible schema (plain value, ref, or getter).
191
+ */
192
+ schema: MaybeRefOrGetter<TSchema>;
193
+ /**
194
+ * onSubmit callback.
195
+ *
196
+ * Only called if:
197
+ * - The form is not already being submitted (`submitting.value` is falsy).
198
+ * - HTML5 validation passes (if enabled).
199
+ * - Standard Schema validation passes.
200
+ *
201
+ * The first argument is the validated input; the remaining arguments are passed through from the submit function.
202
+ *
203
+ * While submission is in progress, `submitting` is true.
204
+ * After successful execution, `submitted` is true.
205
+ */
206
+ onSubmit?: SubmitCallback<[StandardSchemaV1.InferOutput<TSchema>, ...TArgs], TResult>;
207
+ }): UseSubmitReturn<TArgs, TResult, TErrors>;
208
+ /**
209
+ * Vue 3 composable for handling form submission.
210
+ */
211
+ declare function useSubmit<Args extends unknown[], Result, TErrors = StandardErrors>(options: BaseOptions<TErrors> & {
212
+ input?: never;
213
+ schema?: never;
214
+ onSubmit?: never;
215
+ }, onSubmit: SubmitCallback<Args, Result>): UseSubmitReturn<Args, Result, TErrors>;
216
+ /**
217
+ * Vue 3 composable for handling form submission.
218
+ */
219
+ declare function useSubmit<TInput, TArgs extends any[], TResult, TErrors = StandardErrors>(options: BaseOptions<TErrors> & {
220
+ input: MaybeRefOrGetter<TInput>;
221
+ schema?: never;
222
+ onSubmit?: never;
223
+ }, onSubmit: SubmitCallback<[TInput, ...TArgs], TResult>): UseSubmitReturn<TArgs, TResult, TErrors>;
224
+ /**
225
+ * Vue 3 composable for handling form submission.
226
+ */
227
+ declare function useSubmit<TSchema extends StandardSchemaV1, TArgs extends any[], TResult, TErrors = StandardErrors>(options: BaseOptions<TErrors> & {
228
+ input?: unknown;
229
+ schema: MaybeRefOrGetter<TSchema>;
230
+ onSubmit?: never;
231
+ }, onSubmit: SubmitCallback<[StandardSchemaV1.InferOutput<TSchema>, ...TArgs], TResult>): UseSubmitReturn<TArgs, TResult, TErrors>;
232
+ /**
233
+ * Vue 3 composable for handling form submission.
234
+ */
235
+ declare function useSubmit<TArgs extends any[], TResult>(
236
+ /**
237
+ * onSubmit callback.
238
+ *
239
+ * Only called if:
240
+ * - The form is not already being submitted (`submitting.value` is falsy).
241
+ * - HTML5 validation passes (if enabled).
242
+ *
243
+ * Arguments are passed through from the submit function.
244
+ *
245
+ * While submission is in progress, `submitting` is true.
246
+ * After successful execution, `submitted` is true.
247
+ */
248
+
249
+ onSubmit?: SubmitCallback<TArgs, TResult>): UseSubmitReturn<TArgs, TResult, StandardErrors>;
250
+ //#endregion
251
+ export { ErrorsFormatter, FlatErrors, StandardErrors, UseParseReturn, UseSubmitReturn, flatten, useParse, useSubmit };
252
+ //# sourceMappingURL=index.d.mts.map
package/dist/index.mjs ADDED
@@ -0,0 +1,112 @@
1
+ import { getDotPath } from "@standard-schema/utils";
2
+ import { ref, toValue } from "@vue/reactivity";
3
+ import { watchEffect } from "@vue/runtime-core";
4
+
5
+ //#region src/errors/flatten.ts
6
+ /**
7
+ * Built-in error formatter that converts Standard Schema issues to FlatErrors format,
8
+ * compatible with Valibot's flatten() function.
9
+ */
10
+ function flatten(issues) {
11
+ const errors = {};
12
+ for (const issue of issues) {
13
+ const dotPath = getDotPath(issue);
14
+ if (dotPath) {
15
+ errors.nested ??= {};
16
+ errors.nested[dotPath] ??= [];
17
+ errors.nested[dotPath].push(issue.message);
18
+ } else {
19
+ errors.root ??= [];
20
+ errors.root.push(issue.message);
21
+ }
22
+ }
23
+ return errors;
24
+ }
25
+
26
+ //#endregion
27
+ //#region src/parse.ts
28
+ function useParse(options, watchOptions) {
29
+ const result = ref();
30
+ const output = ref();
31
+ const errors = ref();
32
+ const formatErrors = options.formatErrors ?? ((issues) => issues);
33
+ function applyResult(r) {
34
+ result.value = r;
35
+ if (r.issues) {
36
+ output.value = void 0;
37
+ errors.value = formatErrors(r.issues);
38
+ } else {
39
+ output.value = r.value;
40
+ errors.value = void 0;
41
+ }
42
+ }
43
+ watchEffect((onCleanup) => {
44
+ const schema = toValue(options.schema);
45
+ const input = toValue(options.input);
46
+ const resultOrPromise = schema["~standard"].validate(input);
47
+ if (resultOrPromise instanceof Promise) {
48
+ let cancelled = false;
49
+ onCleanup(() => {
50
+ cancelled = true;
51
+ });
52
+ resultOrPromise.then((r) => {
53
+ if (!cancelled) applyResult(r);
54
+ });
55
+ } else applyResult(resultOrPromise);
56
+ }, watchOptions);
57
+ return {
58
+ result,
59
+ output,
60
+ errors
61
+ };
62
+ }
63
+
64
+ //#endregion
65
+ //#region src/submit.ts
66
+ function useSubmit(optionsOrOnSubmit, externalOnSubmit) {
67
+ const options = (typeof optionsOrOnSubmit === "function" ? void 0 : optionsOrOnSubmit) ?? {};
68
+ const onSubmitCallback = typeof optionsOrOnSubmit === "function" ? optionsOrOnSubmit : externalOnSubmit ?? options?.onSubmit;
69
+ const hasInput = options.input !== void 0;
70
+ const form = options.form ?? ref();
71
+ const errors = options.errors ?? ref();
72
+ const submitting = options.submitting ?? ref(false);
73
+ const submitted = options.submitted ?? ref(false);
74
+ const formatErrors = options.formatErrors ?? ((issues) => issues);
75
+ async function submit(...args) {
76
+ if (submitting.value) return;
77
+ submitted.value = false;
78
+ errors.value = void 0;
79
+ if (form.value && !form.value.checkValidity()) {
80
+ form.value.reportValidity();
81
+ return;
82
+ }
83
+ submitting.value = true;
84
+ try {
85
+ const input = toValue(options.input);
86
+ const schema = toValue(options.schema);
87
+ const parseResult = schema ? await schema["~standard"].validate(input) : void 0;
88
+ if (parseResult && parseResult.issues) {
89
+ errors.value = formatErrors(parseResult.issues);
90
+ await options.onErrors?.(errors.value);
91
+ } else {
92
+ const returnValue = await (hasInput || parseResult ? onSubmitCallback?.(parseResult ? parseResult.value : input, ...args) : onSubmitCallback?.(...args));
93
+ if (errors.value) await options.onErrors?.(errors.value);
94
+ else submitted.value = true;
95
+ return returnValue;
96
+ }
97
+ } finally {
98
+ submitting.value = false;
99
+ }
100
+ }
101
+ return {
102
+ form,
103
+ submit,
104
+ submitting,
105
+ submitted,
106
+ errors
107
+ };
108
+ }
109
+
110
+ //#endregion
111
+ export { flatten, useParse, useSubmit };
112
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../src/errors/flatten.ts","../src/parse.ts","../src/submit.ts"],"sourcesContent":["import { getDotPath } from \"@standard-schema/utils\"\n\nimport type { StandardErrors } from \"./base\"\n\n/**\n * The FlatErrors interface, compatible with Valibot.\n *\n * TODO: accept Schema as a generic parameter, allow typed errors.\n */\nexport interface FlatErrors {\n /**\n * Root-level errors.\n *\n * Contains error messages from issues without a path (belonging to the root of the schema).\n */\n root?: string[]\n /**\n * Nested field errors.\n *\n * Contains error messages from issues with a path (belonging to nested parts\n * of the schema), keyed by their dot-notation path.\n */\n nested?: Partial<{\n [key: string]: string[]\n }>\n}\n\n/**\n * Built-in error formatter that converts Standard Schema issues to FlatErrors format,\n * compatible with Valibot's flatten() function.\n */\nexport function flatten(issues: StandardErrors): FlatErrors {\n const errors: FlatErrors = {}\n for (const issue of issues) {\n const dotPath = getDotPath(issue)\n if (dotPath) {\n errors.nested ??= {}\n errors.nested[dotPath] ??= []\n errors.nested[dotPath]!.push(issue.message)\n } else {\n errors.root ??= []\n errors.root.push(issue.message)\n }\n }\n\n return errors\n}\n","import type { StandardSchemaV1 } from \"@standard-schema/spec\"\nimport { ref, toValue } from \"@vue/reactivity\"\nimport type { MaybeRefOrGetter, Ref, WatchOptionsBase } from \"@vue/runtime-core\"\nimport { watchEffect } from \"@vue/runtime-core\"\n\nimport type { ErrorsFormatter, StandardErrors } from \"./errors\"\n\nexport type UseParseReturn<TSchema extends StandardSchemaV1, TErrors = StandardErrors> = {\n result: Ref<StandardSchemaV1.Result<StandardSchemaV1.InferOutput<TSchema>>>\n output: Ref<StandardSchemaV1.InferOutput<TSchema> | undefined>\n errors: Ref<TErrors | undefined>\n}\n\nexport function useParse<TSchema extends StandardSchemaV1, TErrors = StandardErrors>(\n options: {\n /**\n * The input data to validate (plain value, ref, or getter).\n */\n input?: unknown\n /**\n * A Standard Schema compatible schema (plain value, ref, or getter).\n */\n schema: MaybeRefOrGetter<TSchema>\n /**\n * Error formatter function that transforms raw Standard Schema issues into the desired format.\n */\n formatErrors?: ErrorsFormatter<TErrors>\n },\n watchOptions?: WatchOptionsBase,\n): UseParseReturn<TSchema, TErrors> {\n type Output = StandardSchemaV1.InferOutput<TSchema>\n const result = ref<StandardSchemaV1.Result<Output>>() as Ref<StandardSchemaV1.Result<Output>>\n const output = ref<Output>()\n const errors = ref<TErrors | undefined>()\n const formatErrors = options.formatErrors ?? ((issues: StandardErrors) => issues as TErrors)\n\n function applyResult(r: StandardSchemaV1.Result<Output>) {\n result.value = r\n if (r.issues) {\n output.value = undefined\n errors.value = formatErrors(r.issues)\n } else {\n output.value = r.value\n errors.value = undefined\n }\n }\n\n watchEffect((onCleanup) => {\n const schema = toValue(options.schema)\n const input = toValue(options.input)\n const resultOrPromise = schema[\"~standard\"].validate(input)\n\n if (resultOrPromise instanceof Promise) {\n let cancelled = false\n onCleanup(() => {\n cancelled = true\n })\n resultOrPromise.then((r) => {\n if (!cancelled) {\n applyResult(r)\n }\n })\n } else {\n applyResult(resultOrPromise)\n }\n }, watchOptions)\n\n return { result, output, errors }\n}\n","import type { StandardSchemaV1 } from \"@standard-schema/spec\"\nimport type { MaybeRefOrGetter, Ref } from \"@vue/reactivity\"\nimport { ref, toValue } from \"@vue/reactivity\"\n\nimport type { ErrorsFormatter, StandardErrors } from \"./errors\"\n\nexport interface UseSubmitReturn<TArgs extends any[], TResult, TErrors> {\n /**\n * The form element ref.\n *\n * Using it with `<form ref=\"form\">` will enable HTML5 validation on submit.\n */\n form: Ref<HTMLFormElement | undefined>\n /**\n * The form submit function. Use it like:\n *\n * - `<form @submit.prevent=\"submit\">`\n * - `<button @click=\"submit\">`\n *\n * It will:\n *\n * - Run HTML5 validation (if the form ref is set).\n * - Run Standard Schema validation (if the schema is provided).\n * - Call the `onSubmit` callback (if provided).\n *\n * Arguments passed to this function are forwarded to the `onSubmit` callback,\n * prepended with the (possibly validated) form input (unless using the shortcut variant of `useSubmit`).\n *\n * While submission is in progress, `submitting` is true.\n * After successful execution, `submitted` is true.\n */\n submit: (...args: TArgs) => Promise<TResult | undefined>\n /**\n * Whether a submission is currently in progress.\n *\n * Use this to disable the submit button.\n *\n * `useSubmit` will also skip submission if this is already `true`.\n */\n submitting: Ref<boolean>\n /**\n * Has the form been successfully submitted?\n *\n * Feel free to reset. `useSubmit` doesn't depend on this value.\n */\n submitted: Ref<boolean>\n /**\n * Validation errors.\n */\n errors: Ref<TErrors | undefined>\n}\n\ninterface BaseOptions<TErrors> {\n /**\n * Error formatter function that transforms raw Standard Schema issues into the desired format.\n */\n formatErrors?: ErrorsFormatter<TErrors>\n /**\n * Error callback.\n *\n * Called (and awaited) when validation fails or when `errors.value` is set by the `onSubmit` handler.\n */\n onErrors?: (errors: TErrors) => any\n /**\n * User-provided ref for the `form` return value.\n */\n form?: Ref<HTMLFormElement | undefined>\n /**\n * User-provided ref for the `submitting` return value.\n */\n submitting?: Ref<boolean>\n /**\n * User-provided ref for the `submitted` return value.\n */\n submitted?: Ref<boolean>\n /**\n * User-provided ref for the `errors` return value.\n */\n errors?: Ref<TErrors | undefined>\n}\n\ntype SubmitCallback<Args extends any[], Result> = (\n ...args: Args\n) => Result | PromiseLike<Result>\n\n//\n// No input.\n//\n\n/**\n * Vue 3 composable for handling form submission.\n */\nexport function useSubmit<Args extends unknown[], Result, TErrors = StandardErrors>(\n options: BaseOptions<TErrors> & {\n input?: never\n schema?: never\n /**\n * onSubmit callback.\n *\n * Only called if:\n * - The form is not already being submitted (`submitting.value` is falsy).\n * - HTML5 validation passes (if enabled).\n *\n * Arguments are passed through from the submit function.\n *\n * While submission is in progress, `submitting` is true.\n * After successful execution, `submitted` is true.\n */\n onSubmit?: SubmitCallback<Args, Result>\n },\n): UseSubmitReturn<Args, Result, TErrors>\n\n//\n// Input only (no schema).\n//\n\n/**\n * Vue 3 composable for handling form submission.\n *\n * Validates the input using Standard Schema.\n */\nexport function useSubmit<TInput, TArgs extends any[], TResult, TErrors = StandardErrors>(\n options: BaseOptions<TErrors> & {\n /**\n * The input data: a plain value, ref, or getter.\n */\n input: MaybeRefOrGetter<TInput>\n schema?: never\n /**\n * onSubmit callback.\n *\n * Only called if:\n * - The form is not already being submitted (`submitting.value` is falsy).\n * - HTML5 validation passes (if enabled).\n *\n * The first argument is the form input; the remaining arguments are passed through from the submit function.\n *\n * While submission is in progress, `submitting` is true.\n * After successful execution, `submitted` is true.\n */\n onSubmit?: SubmitCallback<[TInput, ...TArgs], TResult>\n },\n): UseSubmitReturn<TArgs, TResult, TErrors>\n\n//\n// Schema.\n//\n\n/**\n * Vue 3 composable for handling form submission.\n *\n * Validates the input using Standard Schema.\n */\nexport function useSubmit<TSchema extends StandardSchemaV1, TArgs extends any[], TResult, TErrors = StandardErrors>(\n options: BaseOptions<TErrors> & {\n /**\n * The input data to validate (plain value, ref, or getter).\n */\n input?: unknown\n /**\n * A Standard Schema compatible schema (plain value, ref, or getter).\n */\n schema: MaybeRefOrGetter<TSchema>\n /**\n * onSubmit callback.\n *\n * Only called if:\n * - The form is not already being submitted (`submitting.value` is falsy).\n * - HTML5 validation passes (if enabled).\n * - Standard Schema validation passes.\n *\n * The first argument is the validated input; the remaining arguments are passed through from the submit function.\n *\n * While submission is in progress, `submitting` is true.\n * After successful execution, `submitted` is true.\n */\n onSubmit?: SubmitCallback<[StandardSchemaV1.InferOutput<TSchema>, ...TArgs], TResult>\n },\n): UseSubmitReturn<TArgs, TResult, TErrors>\n\n//\n// No input, separate submit.\n//\n\n/**\n * Vue 3 composable for handling form submission.\n */\nexport function useSubmit<Args extends unknown[], Result, TErrors = StandardErrors>(\n options: BaseOptions<TErrors> & {\n input?: never\n schema?: never\n onSubmit?: never\n },\n onSubmit: SubmitCallback<Args, Result>,\n): UseSubmitReturn<Args, Result, TErrors>\n\n//\n// Input only (no schema), separate submit.\n//\n\n/**\n * Vue 3 composable for handling form submission.\n */\nexport function useSubmit<TInput, TArgs extends any[], TResult, TErrors = StandardErrors>(\n options: BaseOptions<TErrors> & {\n input: MaybeRefOrGetter<TInput>\n schema?: never\n onSubmit?: never\n },\n onSubmit: SubmitCallback<[TInput, ...TArgs], TResult>,\n): UseSubmitReturn<TArgs, TResult, TErrors>\n\n//\n// Schema, separate submit.\n//\n\n/**\n * Vue 3 composable for handling form submission.\n */\nexport function useSubmit<TSchema extends StandardSchemaV1, TArgs extends any[], TResult, TErrors = StandardErrors>(\n options: BaseOptions<TErrors> & {\n input?: unknown\n schema: MaybeRefOrGetter<TSchema>\n onSubmit?: never\n },\n onSubmit: SubmitCallback<[StandardSchemaV1.InferOutput<TSchema>, ...TArgs], TResult>,\n): UseSubmitReturn<TArgs, TResult, TErrors>\n\n//\n// No input, callback only.\n//\n\n/**\n * Vue 3 composable for handling form submission.\n */\nexport function useSubmit<TArgs extends any[], TResult>(\n/**\n * onSubmit callback.\n *\n * Only called if:\n * - The form is not already being submitted (`submitting.value` is falsy).\n * - HTML5 validation passes (if enabled).\n *\n * Arguments are passed through from the submit function.\n *\n * While submission is in progress, `submitting` is true.\n * After successful execution, `submitted` is true.\n */\n onSubmit?: SubmitCallback<TArgs, TResult>,\n): UseSubmitReturn<TArgs, TResult, StandardErrors>\n\n//\n// Implementation.\n//\n\nexport function useSubmit(\n optionsOrOnSubmit?:\n | (BaseOptions<unknown> & {\n input?: unknown\n schema?: MaybeRefOrGetter<StandardSchemaV1>\n onSubmit?: SubmitCallback<unknown[], unknown>\n })\n | SubmitCallback<unknown[], unknown>,\n externalOnSubmit?: SubmitCallback<unknown[], unknown>,\n): UseSubmitReturn<unknown[], unknown, unknown> {\n const options\n = (typeof optionsOrOnSubmit === \"function\" ? undefined : optionsOrOnSubmit) ?? {}\n const onSubmitCallback\n = typeof optionsOrOnSubmit === \"function\" ? optionsOrOnSubmit : externalOnSubmit ?? options?.onSubmit\n const hasInput = options.input !== undefined\n\n const form = options.form ?? ref<HTMLFormElement>()\n const errors = options.errors ?? ref()\n const submitting = options.submitting ?? ref(false)\n const submitted = options.submitted ?? ref(false)\n\n const formatErrors = options.formatErrors ?? ((issues: StandardErrors) => issues)\n\n async function submit(...args: unknown[]) {\n if (submitting.value) {\n return\n }\n submitted.value = false\n errors.value = undefined\n if (form.value && !form.value.checkValidity()) {\n form.value.reportValidity()\n return\n }\n submitting.value = true\n try {\n const input = toValue(options.input)\n const schema = toValue(options.schema)\n const parseResult = schema ? await schema[\"~standard\"].validate(input) : undefined\n if (parseResult && parseResult.issues) {\n errors.value = formatErrors(parseResult.issues)\n await options.onErrors?.(errors.value)\n } else {\n const returnValue = await (\n hasInput || parseResult\n ? onSubmitCallback?.(parseResult ? parseResult.value : input, ...args)\n : onSubmitCallback?.(...args)\n )\n if (errors.value) {\n await options.onErrors?.(errors.value)\n } else {\n submitted.value = true\n }\n return returnValue\n }\n } finally {\n submitting.value = false\n }\n }\n\n return { form, submit, submitting, submitted, errors }\n}\n"],"mappings":";;;;;;;;;AA+BA,SAAgB,QAAQ,QAAoC;CAC1D,MAAM,SAAqB,EAAE;AAC7B,MAAK,MAAM,SAAS,QAAQ;EAC1B,MAAM,UAAU,WAAW,MAAM;AACjC,MAAI,SAAS;AACX,UAAO,WAAW,EAAE;AACpB,UAAO,OAAO,aAAa,EAAE;AAC7B,UAAO,OAAO,SAAU,KAAK,MAAM,QAAQ;SACtC;AACL,UAAO,SAAS,EAAE;AAClB,UAAO,KAAK,KAAK,MAAM,QAAQ;;;AAInC,QAAO;;;;;AChCT,SAAgB,SACd,SAcA,cACkC;CAElC,MAAM,SAAS,KAAsC;CACrD,MAAM,SAAS,KAAa;CAC5B,MAAM,SAAS,KAA0B;CACzC,MAAM,eAAe,QAAQ,kBAAkB,WAA2B;CAE1E,SAAS,YAAY,GAAoC;AACvD,SAAO,QAAQ;AACf,MAAI,EAAE,QAAQ;AACZ,UAAO,QAAQ;AACf,UAAO,QAAQ,aAAa,EAAE,OAAO;SAChC;AACL,UAAO,QAAQ,EAAE;AACjB,UAAO,QAAQ;;;AAInB,cAAa,cAAc;EACzB,MAAM,SAAS,QAAQ,QAAQ,OAAO;EACtC,MAAM,QAAQ,QAAQ,QAAQ,MAAM;EACpC,MAAM,kBAAkB,OAAO,aAAa,SAAS,MAAM;AAE3D,MAAI,2BAA2B,SAAS;GACtC,IAAI,YAAY;AAChB,mBAAgB;AACd,gBAAY;KACZ;AACF,mBAAgB,MAAM,MAAM;AAC1B,QAAI,CAAC,UACH,aAAY,EAAE;KAEhB;QAEF,aAAY,gBAAgB;IAE7B,aAAa;AAEhB,QAAO;EAAE;EAAQ;EAAQ;EAAQ;;;;;AC4LnC,SAAgB,UACd,mBAOA,kBAC8C;CAC9C,MAAM,WACD,OAAO,sBAAsB,aAAa,SAAY,sBAAsB,EAAE;CACnF,MAAM,mBACF,OAAO,sBAAsB,aAAa,oBAAoB,oBAAoB,SAAS;CAC/F,MAAM,WAAW,QAAQ,UAAU;CAEnC,MAAM,OAAO,QAAQ,QAAQ,KAAsB;CACnD,MAAM,SAAS,QAAQ,UAAU,KAAK;CACtC,MAAM,aAAa,QAAQ,cAAc,IAAI,MAAM;CACnD,MAAM,YAAY,QAAQ,aAAa,IAAI,MAAM;CAEjD,MAAM,eAAe,QAAQ,kBAAkB,WAA2B;CAE1E,eAAe,OAAO,GAAG,MAAiB;AACxC,MAAI,WAAW,MACb;AAEF,YAAU,QAAQ;AAClB,SAAO,QAAQ;AACf,MAAI,KAAK,SAAS,CAAC,KAAK,MAAM,eAAe,EAAE;AAC7C,QAAK,MAAM,gBAAgB;AAC3B;;AAEF,aAAW,QAAQ;AACnB,MAAI;GACF,MAAM,QAAQ,QAAQ,QAAQ,MAAM;GACpC,MAAM,SAAS,QAAQ,QAAQ,OAAO;GACtC,MAAM,cAAc,SAAS,MAAM,OAAO,aAAa,SAAS,MAAM,GAAG;AACzE,OAAI,eAAe,YAAY,QAAQ;AACrC,WAAO,QAAQ,aAAa,YAAY,OAAO;AAC/C,UAAM,QAAQ,WAAW,OAAO,MAAM;UACjC;IACL,MAAM,cAAc,OAClB,YAAY,cACR,mBAAmB,cAAc,YAAY,QAAQ,OAAO,GAAG,KAAK,GACpE,mBAAmB,GAAG,KAAK;AAEjC,QAAI,OAAO,MACT,OAAM,QAAQ,WAAW,OAAO,MAAM;QAEtC,WAAU,QAAQ;AAEpB,WAAO;;YAED;AACR,cAAW,QAAQ;;;AAIvB,QAAO;EAAE;EAAM;EAAQ;EAAY;EAAW;EAAQ"}
package/package.json ADDED
@@ -0,0 +1,59 @@
1
+ {
2
+ "name": "vue-form-submit",
3
+ "type": "module",
4
+ "version": "5.0.0",
5
+ "packageManager": "bun@1.3.9",
6
+ "description": "Vue3 composables for handling form submit with Standard Schema validation support",
7
+ "author": "Ilya Semenov",
8
+ "license": "MIT",
9
+ "repository": {
10
+ "type": "git",
11
+ "url": "git+https://github.com/IlyaSemenov/vue-form-submit.git"
12
+ },
13
+ "exports": {
14
+ ".": {
15
+ "import": "./dist/index.mjs",
16
+ "require": "./dist/index.cjs"
17
+ },
18
+ "./package.json": "./package.json"
19
+ },
20
+ "main": "./dist/index.cjs",
21
+ "module": "./dist/index.mjs",
22
+ "types": "./dist/index.d.cts",
23
+ "files": [
24
+ "README.md",
25
+ "dist"
26
+ ],
27
+ "scripts": {
28
+ "build": "tsdown",
29
+ "lint": "eslint --fix .",
30
+ "prepare": "lefthook install",
31
+ "prepublishOnly": "bun run build",
32
+ "test": "bun test && bun run types",
33
+ "types": "tsgo"
34
+ },
35
+ "peerDependencies": {
36
+ "@vue/reactivity": "^3",
37
+ "@vue/runtime-core": "^3"
38
+ },
39
+ "dependencies": {
40
+ "@standard-schema/spec": "^1.0.0",
41
+ "@standard-schema/utils": "^0.3.0"
42
+ },
43
+ "devDependencies": {
44
+ "@arethetypeswrong/core": "^0.18.2",
45
+ "@changesets/cli": "^2.26.2",
46
+ "@ilyasemenov/eslint-config": "^1.4.2",
47
+ "@tsconfig/bun": "^1.0.10",
48
+ "@types/bun": "^1.3.10",
49
+ "@typescript/native-preview": "^7.0.0-dev.20260311.1",
50
+ "@vue/reactivity": "^3.4.29",
51
+ "@vue/runtime-core": "^3.4.29",
52
+ "eslint": "^9.35.0",
53
+ "publint": "^0.3.18",
54
+ "tsdown": "^0.20.3",
55
+ "typescript": "^5.4.5",
56
+ "valibot": "^1.1.0",
57
+ "zod": "^4.1.7"
58
+ }
59
+ }