notform 3.0.1 → 4.0.0-alpha.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (4) hide show
  1. package/README.md +14 -186
  2. package/dist/index.d.ts +459 -475
  3. package/dist/index.js +1103 -790
  4. package/package.json +19 -22
package/dist/index.d.ts CHANGED
@@ -1,560 +1,544 @@
1
1
  import { Component, MaybeRefOrGetter } from "vue";
2
2
  import { StandardSchemaV1 } from "@standard-schema/spec";
3
- import { ExcludeStrict, Get, PartialDeep, Paths } from "type-fest";
4
- //#region src/types/shared.d.ts
5
- /** Events that can trigger field validation. */
6
- type ValidationTrigger = 'onBlur' | 'onChange' | 'onInput' | 'onMount';
3
+ import { Get, PartialDeep, Paths } from "type-fest";
7
4
  /**
8
- * Recursively optional version of `TData`, including array items.
9
- * @template TData Source data type.
5
+ * A Standard Schema whose input AND output are objects.
6
+ *
7
+ * Forms require this because form values are always a keyed object, never a
8
+ * lone string or number.
10
9
  */
11
- type DeepPartial<TData> = PartialDeep<TData, {
12
- allowUndefinedInNonTupleArrays: true;
13
- recurseIntoArrays: true;
14
- }>;
10
+ type FormSchema = StandardSchemaV1 & {
11
+ '~standard': StandardSchemaV1['~standard'] & {
12
+ types?: {
13
+ input: object;
14
+ output: object;
15
+ };
16
+ };
17
+ };
15
18
  /**
16
- * Input type accepted by a Standard Schema.
17
- * @template TSchema Validation schema.
19
+ * The data a schema *accepts*: what the user types, before parsing,
20
+ * transforming or defaults. This is the shape of `form.values`.
21
+ * @template TSchema - Any Standard Schema compatible schema (Zod, Valibot, ArkType, ...).
22
+ * @example
23
+ * // A schema that turns the text '42' into the number 42:
24
+ * // SchemaInput -> { age: string }
25
+ * // SchemaOutput -> { age: number }
18
26
  */
19
- type InferInput<TSchema extends StandardSchemaV1> = StandardSchemaV1.InferInput<TSchema>;
27
+ type SchemaInput<TSchema extends StandardSchemaV1> = StandardSchemaV1.InferInput<TSchema>;
20
28
  /**
21
- * Output type produced by a Standard Schema.
22
- * @template TSchema Validation schema.
29
+ * The data a schema *produces* after a successful validation. This is the shape `onSubmit` receives.
30
+ * @template TSchema - Any Standard Schema compatible schema.
23
31
  */
24
- type InferOutput<TSchema extends StandardSchemaV1> = StandardSchemaV1.InferOutput<TSchema>;
25
- /** One issue from a Standard Schema validation run. */
26
- type Issue = StandardSchemaV1.Issue;
32
+ type SchemaOutput<TSchema extends StandardSchemaV1> = StandardSchemaV1.InferOutput<TSchema>;
27
33
  /**
28
- * Dot-notated field paths derived from a schema's input type.
34
+ * @file
35
+ * Vocabulary used across the library:
29
36
  *
30
- * The `| (string & {})` union member is deliberate: it keeps editor
31
- * autocomplete suggesting the schema's real paths, while still letting any
32
- * arbitrary string through the type checker — needed because a dynamically
33
- * built path (e.g. `` `${item.path}.name` ``) can't always be proven to match
34
- * the literal union `TypeFestPaths` computes.
35
- * @template TSchema Validation schema.
37
+ * - PATH A location written as dot-notation text, e.g. 'address.city' or 'tags.0'.
38
+ * This is what you pass to `form.field()`.
39
+ *
40
+ * - SEGMENTS The same location split into steps, e.g. ['address', 'city'] or ['tags', 0].
41
+ * Schema libraries report issue locations this way.
42
+ */
43
+ /**
44
+ * The item type of an array type. `never` when `TArray` is not an array.
45
+ * @template TArray - An array type, optionally `null` / `undefined`.
46
+ * @example
47
+ * // ArrayItem<string[] | undefined> -> string
48
+ */
49
+ type ArrayItem<TArray> = NonNullable<TArray> extends readonly (infer TItem)[] ? TItem : never;
50
+ /**
51
+ * Every valid path into the schema's INPUT data that points at an array.
52
+ * These are the paths accepted by `form.arrayField()`.
53
+ * @template TSchema - Any Standard Schema compatible schema.
54
+ */
55
+ type InputArrayPath<TSchema extends StandardSchemaV1> = ValueArrayPath<SchemaInput<TSchema>>;
56
+ /**
57
+ * Every valid path into the schema's INPUT data (the shape of `form.values`).
58
+ * These are the paths accepted by `form.field()` and `form.setValue()`.
59
+ * @template TSchema - Any Standard Schema compatible schema.
60
+ * @example
61
+ * // For z.object({ email: z.string(), tags: z.array(z.string()) }):
62
+ * // 'email' | 'tags' | `tags.${number}`
63
+ */
64
+ type InputPath<TSchema extends StandardSchemaV1> = ValuePath<SchemaInput<TSchema>>;
65
+ /**
66
+ * The type of the INPUT value found at `TPath`.
67
+ * @template TSchema - Any Standard Schema compatible schema.
68
+ * @template TPath - Dot-notation path, e.g. `'address.city'`.
69
+ */
70
+ type InputPathValue<TSchema extends StandardSchemaV1, TPath extends string> = ValuePathValue<SchemaInput<TSchema>, TPath>;
71
+ /**
72
+ * Every valid path into the schema's OUTPUT data (the shape `onSubmit` receives).
73
+ * @template TSchema - Any Standard Schema compatible schema.
74
+ */
75
+ type OutputPath<TSchema extends StandardSchemaV1> = ValuePath<SchemaOutput<TSchema>>;
76
+ /**
77
+ * The type of the OUTPUT value found at `TPath`.
78
+ * @template TSchema - Any Standard Schema compatible schema.
79
+ * @template TPath - Dot-notation path.
80
+ */
81
+ type OutputPathValue<TSchema extends StandardSchemaV1, TPath extends string> = ValuePathValue<SchemaOutput<TSchema>, TPath>;
82
+ /**
83
+ * Every dot-notation path inside `TValue` that points at an array.
84
+ * @template TValue - The object type to look into.
36
85
  */
37
- type Paths$1<TSchema extends StandardSchemaV1> = Extract<Paths<InferInput<TSchema>, {
86
+ type ValueArrayPath<TValue> = Extract<ArrayPathsOf<TValue, ValuePath<TValue>>, string>;
87
+ /**
88
+ * Every dot-notation path inside `TValue`.
89
+ * @template TValue - The object type to look into.
90
+ * @remarks Recursion is capped at depth 10 to keep TypeScript fast.
91
+ */
92
+ type ValuePath<TValue> = Extract<Paths<TValue, {
38
93
  maxRecursionDepth: 10;
39
- }>, string> | (string & {});
94
+ }>, string>;
40
95
  /**
41
- * Standard Schema constrained to object input.
42
- *
43
- * The `~standard.types.input` check exists purely at the type level, so that
44
- * `useNotForm`'s `TSchema` is only inferred when the schema's input type is
45
- * actually an `object` — this is what makes passing a non-object schema
46
- * (e.g. `z.string()`) a compile-time error rather than a runtime surprise.
47
- * @see {@linkcode https://github.com/standard-schema/standard-schema Standard Schema spec}
96
+ * The type found at `TPath` inside `TValue`.
97
+ * @template TValue - The object type to look into.
98
+ * @template TPath - Dot-notation path.
48
99
  */
49
- type ObjectSchema = StandardSchemaV1 & {
50
- '~standard': StandardSchemaV1['~standard'] & {
51
- types?: {
52
- input: object;
53
- };
54
- };
55
- };
56
- //#endregion
57
- //#region src/types/not-form-instance.d.ts
100
+ type ValuePathValue<TValue, TPath extends string> = Get<TValue, TPath, {
101
+ strict: false;
102
+ }>;
103
+ /** Keeps only the paths whose value is an array (distributes over the path union). */
104
+ type ArrayPathsOf<TValue, TPath extends string> = TPath extends unknown ? NonNullable<ValuePathValue<TValue, TPath>> extends readonly unknown[] ? TPath : never : never;
58
105
  /**
59
- * Full form instance used by field components. `useNotForm` returns {@linkcode NotFormAPI}.
60
- * @template TSchema The form schema.
106
+ * A single validation problem reported by a schema: a human-readable `message`
107
+ * and an optional `path` (in segments). An issue without a `path` applies to the whole form.
61
108
  */
62
- interface NotFormInstance<TSchema extends ObjectSchema> {
63
- /** Live field values. */
64
- values: InferInput<TSchema>;
109
+ type ValidationIssue = StandardSchemaV1.Issue;
110
+ /**
111
+ * The raw Standard Schema result: `{ value }` on success, `{ issues }` on failure.
112
+ * @template TValue - Type of the validated value on success.
113
+ */
114
+ type ValidationResult<TValue> = StandardSchemaV1.Result<TValue>;
115
+ /**
116
+ * Per-field behavior, passed as the second argument of `form.field()` / `form.arrayField()`.
117
+ * @remarks Read once, when the field is first created.
118
+ * @example
119
+ * form.field('email', { debounce: 300, validateOn: { input: true } })
120
+ */
121
+ type FieldConfig = {
122
+ /** Milliseconds to wait after the last `input` / `change` before validating. `blur` always validates immediately. */
123
+ debounce?: number;
124
+ /** Which events trigger validation. Omitted events keep their defaults (`blur` and `change` on, `input` off). */
125
+ validateOn?: Partial<Record<FieldValidationEvent, boolean>>;
65
126
  /**
66
- * Sets a field value by path. Does not validate — validation still only
67
- * runs through a field's own configured triggers, or an explicit
68
- * {@linkcode validate}/{@linkcode validateField} call.
69
- * @template TPath Field path.
70
- * @param path Dot path.
71
- * @param value Value to assign.
127
+ * - `'eager'`: once the field has errors, every `input` and `change` re-validates it,
128
+ * so the error disappears as soon as the value is fixed.
129
+ *
130
+ * - `'lazy'`: only the events enabled in `validateOn` validate.
131
+ * @default 'eager'
72
132
  */
73
- setValue: <TPath extends Paths$1<TSchema>>(path: TPath, value: Get<InferInput<TSchema>, TPath, {
74
- strict: false;
75
- }>) => void;
76
- /** Whether any field is touched. */
133
+ validationMode?: 'eager' | 'lazy';
134
+ };
135
+ /** Handlers to spread onto an input: `<input v-bind="field.events">`. */
136
+ type FieldEvents = Record<`on${Capitalize<FieldValidationEvent>}`, () => void>;
137
+ /**
138
+ * A single form field, bound to one value inside the form.
139
+ *
140
+ * Created by `form.field('some.path')`. The instance is cached, so asking for the
141
+ * same path again returns the same field with the same `id`.
142
+ * @template TValue - Type of the value this field holds.
143
+ */
144
+ type FieldInstance<TValue> = {
145
+ /** Issues reported exactly at this field's path (not those of nested fields). */
146
+ errors: ValidationIssue[];
147
+ /** Handlers for `blur` / `change` / `input`; they mark the field touched and trigger validation. */
148
+ events: FieldEvents;
149
+ /** Stable identity. Safe as a `v-for` key; does not change when the field's path does. */
150
+ id: symbol;
151
+ /** `true` when the value differs (deep comparison) from the initial value at the field's path. */
152
+ isDirty: boolean;
153
+ /** `true` once the field was blurred, or the form was submitted. */
77
154
  isTouched: boolean;
155
+ /** `true` when {@link FieldInstance.errors} is empty. */
156
+ isValid: boolean;
157
+ /** `true` while this field, a field nested in it, or the whole form is being validated. */
158
+ isValidating: boolean;
159
+ /** The field's value. Assign to it (or `v-model` it) to write straight into `form.values`. */
160
+ model: TValue;
161
+ /** Current dot-notation location, e.g. `'address.city'`. Follows the field when array items move. */
162
+ path: string;
78
163
  /**
79
- * Touched field paths.
80
- * @internal
164
+ * Validates this field now, skipping any pending debounce.
165
+ * @returns `{ value }` with the current value, or `{ issues }` for this field.
81
166
  */
82
- touchedFields: Set<Paths$1<TSchema>>;
167
+ validate: () => Promise<ValidationResult<TValue>>;
168
+ };
169
+ /**
170
+ * Props of the `<Field>` component.
171
+ * @template TValue - Type of the value the field holds.
172
+ */
173
+ type FieldProps<TValue> = {
174
+ /** The field created by `form.field('some.path')`, or an array item. */
175
+ field: FieldInstance<TValue>;
176
+ };
177
+ /**
178
+ * Slots of the `<Field>` component.
179
+ * @template TValue - Type of the value the field holds.
180
+ */
181
+ type FieldSlots<TValue> = {
182
+ /** Receives the `field`. Extra attributes set on `<Field>` arrive as additional slot props. */
183
+ default?: (props: {
184
+ field: FieldInstance<TValue>;
185
+ }) => void;
186
+ };
187
+ /** Events that can trigger a field's validation. See {@link FieldConfig.validateOn}. */
188
+ type FieldValidationEvent = 'blur' | 'change' | 'input';
189
+ /**
190
+ * A field for an array: the usual field state for the array itself (`errors` are
191
+ * array-level issues such as "at least one item"), plus the list of items and
192
+ * the mutations to change it.
193
+ *
194
+ * Mutate through this object (not `values.list.push()`) so items keep their identity,
195
+ * touched state and errors. Inserted values are deep-cloned.
196
+ * @template TItem - Type of one array item.
197
+ */
198
+ type ArrayFieldInstance<TItem> = FieldInstance<TItem[]> & {
83
199
  /**
84
- * Marks a field as touched.
85
- * @internal
86
- * @param path Dot path.
200
+ * Adds an item at the end.
201
+ * @param value The new item.
87
202
  */
88
- markFieldAsTouched: (path: Paths$1<TSchema>) => void;
203
+ append: (value: TItem) => void;
89
204
  /**
90
- * Marks every current leaf field as touched. "Current" matters for arrays:
91
- * an empty array contributes no leaf paths, so an item appended afterward
92
- * (e.g. via `<NotArrayField>`'s `append`) starts untouched even though
93
- * this was already called.
94
- * @internal
205
+ * Adds an item at `index`; later items shift up.
206
+ * @param index Where to insert. Clamped into `0..length`.
207
+ * @param value The new item.
95
208
  */
96
- markAllFieldsAsTouched: () => void;
209
+ insert: (index: number, value: TItem) => void;
210
+ /** One entry per array item, in order. Use `item.id` as the `v-for` key. */
211
+ items: ArrayItemInstance<TItem>[];
97
212
  /**
98
- * Clears touched state for one field.
99
- * @internal
100
- * @param path Dot path.
213
+ * Moves an item to another position. Ignored if an index is out of range.
214
+ * @param from Current index of the item.
215
+ * @param to Index it should end up at.
101
216
  */
102
- unmarkFieldAsTouched: (path: Paths$1<TSchema>) => void;
217
+ move: (from: number, to: number) => void;
103
218
  /**
104
- * Clears touched state for all fields.
105
- * @internal
219
+ * Adds an item at the start.
220
+ * @param value The new item.
106
221
  */
107
- unmarkAllFieldsAsTouched: () => void;
222
+ prepend: (value: TItem) => void;
108
223
  /**
109
- * Paths whose value differs from the baseline.
110
- * @internal
224
+ * Removes an item. Ignored if `index` is out of range.
225
+ * @param index Index of the item.
111
226
  */
112
- dirtyFields: Set<Paths$1<TSchema>>;
113
- /** Whether any field is dirty. */
114
- isDirty: boolean;
227
+ remove: (index: number) => void;
115
228
  /**
116
- * Updates dirty state by comparing current and baseline values.
117
- * @internal
118
- * @param path Dot path.
229
+ * Swaps two items. Ignored if an index is out of range.
230
+ * @param indexA Index of the first item.
231
+ * @param indexB Index of the second item.
119
232
  */
120
- syncDirtyState: (path: Paths$1<TSchema>) => void;
233
+ swap: (indexA: number, indexB: number) => void;
121
234
  /**
122
- * Updates dirty state for every current leaf field. Subject to the same
123
- * "current shape only" caveat as {@linkcode markAllFieldsAsTouched}.
124
- * @internal
235
+ * Replaces an item in place. The item keeps its id and touched state; its old errors are dropped.
236
+ * Ignored if `index` is out of range.
237
+ * @param index Index of the item.
238
+ * @param value The new value.
125
239
  */
126
- syncAllDirtyStates: () => void;
240
+ update: (index: number, value: TItem) => void;
241
+ };
242
+ /**
243
+ * Props of the `<ArrayField>` component.
244
+ * @template TItem - Type of one array item.
245
+ */
246
+ type ArrayFieldProps<TItem> = {
247
+ /** The array field created by `form.arrayField('some.path')`. */
248
+ arrayField: ArrayFieldInstance<TItem>;
249
+ };
250
+ /**
251
+ * Slots of the `<ArrayField>` component.
252
+ * @template TItem - Type of one array item.
253
+ */
254
+ type ArrayFieldSlots<TItem> = {
255
+ /** Receives the `arrayField`. Extra attributes set on `<ArrayField>` arrive as additional slot props. */
256
+ default?: (props: {
257
+ arrayField: ArrayFieldInstance<TItem>;
258
+ }) => void;
259
+ };
260
+ /**
261
+ * One item of an array field. It is a regular field for the item's value (pass it
262
+ * straight to `<Field>`), plus its position and shortcuts to change it.
263
+ *
264
+ * Its `id` never changes; `index` and `path` follow the item when the array is reordered.
265
+ * @template TItem - Type of the item.
266
+ */
267
+ type ArrayItemInstance<TItem> = FieldInstance<TItem> & {
127
268
  /**
128
- * Forces a field dirty.
129
- * @internal
130
- * @param path Dot path.
269
+ * Creates an array field nested in this item (e.g. a `tags` list inside a contact).
270
+ * Cached per path; follows the item when it moves.
271
+ * @param path Path relative to the item, e.g. `'tags'`.
272
+ * @param config Optional per-field behavior.
273
+ * @returns The nested array field.
131
274
  */
132
- markFieldAsDirty: (path: Paths$1<TSchema>) => void;
275
+ arrayField: <TPath extends ValueArrayPath<TItem>>(path: TPath, config?: FieldConfig) => ArrayFieldInstance<ArrayItem<ValuePathValue<TItem, TPath>>>;
133
276
  /**
134
- * Forces every current leaf field dirty. Subject to the same
135
- * "current shape only" caveat as {@linkcode markAllFieldsAsTouched}.
136
- * @internal
277
+ * Creates a field nested in this item (e.g. `'email'` inside a contact).
278
+ * Cached per path; follows the item when it moves.
279
+ * @param path Path relative to the item, e.g. `'email'`.
280
+ * @param config Optional per-field behavior.
281
+ * @returns The nested field.
137
282
  */
138
- markAllFieldsAsDirty: () => void;
283
+ field: <TPath extends ValuePath<TItem>>(path: TPath, config?: FieldConfig) => FieldInstance<ValuePathValue<TItem, TPath>>;
284
+ /** Current position in the array. */
285
+ index: number;
286
+ };
287
+ declare const __VLS_export$3: <TItem>(__VLS_props: NonNullable<Awaited<typeof __VLS_setup>>["props"], __VLS_ctx?: __VLS_PrettifyLocal$2<Pick<NonNullable<Awaited<typeof __VLS_setup>>, "attrs" | "emit" | "slots">>, __VLS_exposed?: NonNullable<Awaited<typeof __VLS_setup>>["expose"], __VLS_setup?: Promise<{
288
+ props: import("vue").PublicProps & __VLS_PrettifyLocal$2<ArrayFieldProps<TItem>> & (typeof globalThis extends {
289
+ __VLS_PROPS_FALLBACK: infer P;
290
+ } ? P : {});
291
+ expose: (exposed: {}) => void;
292
+ attrs: any;
293
+ slots: ArrayFieldSlots<TItem>;
294
+ emit: {};
295
+ }>) => import("vue").VNode & {
296
+ __ctx?: NonNullable<Awaited<typeof __VLS_setup>>;
297
+ };
298
+ declare const _default: typeof __VLS_export$3;
299
+ type __VLS_PrettifyLocal$2<T> = (T extends any ? { [K in keyof T]: T[K]; } : { [K in keyof T as K]: T[K]; }) & {};
300
+ /** Props of the `<FieldError>` component. */
301
+ type FieldErrorProps = {
139
302
  /**
140
- * Clears dirty state for one field.
141
- * @internal
142
- * @param path Dot path.
303
+ * HTML tag name or Vue component used to render the message.
304
+ * @default 'span'
143
305
  */
144
- unmarkFieldAsDirty: (path: Paths$1<TSchema>) => void;
306
+ as?: Component | string;
307
+ /** A list of issues, or anything that has one (a field, an array field, an array item). Only the first message is shown. */
308
+ errors: ValidationIssue[] | {
309
+ readonly errors: ValidationIssue[];
310
+ };
311
+ };
312
+ /** Slots of the `<FieldError>` component. */
313
+ type FieldErrorSlots = {
314
+ /** Receives the `message` to display. */
315
+ default?: (props: {
316
+ message?: string;
317
+ }) => void;
318
+ };
319
+ type __VLS_Slots = FieldErrorSlots;
320
+ declare const __VLS_base: import("vue").DefineComponent<FieldErrorProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<FieldErrorProps> & Readonly<{}>, {
321
+ as: string | import("vue").Component;
322
+ }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
323
+ declare const __VLS_export$2: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
324
+ declare const _default$2: typeof __VLS_export$2;
325
+ type __VLS_WithSlots<T, S> = T & {
326
+ new (): {
327
+ $slots: S;
328
+ };
329
+ };
330
+ declare const __VLS_export$1: <TValue>(__VLS_props: NonNullable<Awaited<typeof __VLS_setup>>["props"], __VLS_ctx?: __VLS_PrettifyLocal$1<Pick<NonNullable<Awaited<typeof __VLS_setup>>, "attrs" | "emit" | "slots">>, __VLS_exposed?: NonNullable<Awaited<typeof __VLS_setup>>["expose"], __VLS_setup?: Promise<{
331
+ props: import("vue").PublicProps & __VLS_PrettifyLocal$1<FieldProps<TValue>> & (typeof globalThis extends {
332
+ __VLS_PROPS_FALLBACK: infer P;
333
+ } ? P : {});
334
+ expose: (exposed: {}) => void;
335
+ attrs: any;
336
+ slots: FieldSlots<TValue>;
337
+ emit: {};
338
+ }>) => import("vue").VNode & {
339
+ __ctx?: NonNullable<Awaited<typeof __VLS_setup>>;
340
+ };
341
+ declare const _default$1: typeof __VLS_export$1;
342
+ type __VLS_PrettifyLocal$1<T> = (T extends any ? { [K in keyof T]: T[K]; } : { [K in keyof T as K]: T[K]; }) & {};
343
+ /**
344
+ * Makes every property optional, at every depth (including items inside arrays).
345
+ *
346
+ * Used for initial form values: a form can start empty or half-filled even
347
+ * though the schema eventually demands complete data.
348
+ * @template TValue - The type to make deeply optional.
349
+ */
350
+ type DeepPartial<TValue> = PartialDeep<TValue, {
351
+ allowUndefinedInNonTupleArrays: true;
352
+ recurseIntoArrays: true;
353
+ }>;
354
+ /**
355
+ * Options accepted by `useForm()`.
356
+ * @template TSchema - The schema describing the form's data (must be an object schema).
357
+ */
358
+ type FormConfig<TSchema extends FormSchema> = {
359
+ /** Errors to show from the start (e.g. returned by the server). */
360
+ initialErrors?: ValidationIssue[];
361
+ /** Values to start with. May be partial; the schema is only enforced on validation. */
362
+ initialValues?: DeepPartial<SchemaInput<TSchema>>;
363
+ /** Called with the validated, parsed data after a successful submit. */
364
+ onSubmit?: (data: SchemaOutput<TSchema>) => Promise<void> | void;
365
+ /** The schema to validate against. Accepts a value, a ref, or a getter, so it can change reactively. */
366
+ schema: MaybeRefOrGetter<TSchema>;
367
+ };
368
+ /**
369
+ * A reactive form: its values, errors, state flags, and the actions to change them.
370
+ * @template TSchema - The schema describing the form's data (must be an object schema).
371
+ */
372
+ type FormInstance<TSchema extends FormSchema> = {
145
373
  /**
146
- * Clears dirty state for all fields.
147
- * @internal
374
+ * Gets or creates the array field at `path`. Cached: the same path always returns the same field.
375
+ * @param path Dot-notation path to an array, e.g. `'tags'`.
376
+ * @param config Optional per-field behavior, read when the field is first created.
377
+ * @returns A reactive array field to pass to `<ArrayField>`.
148
378
  */
149
- unmarkAllFieldsAsDirty: () => void;
150
- /** Issues from the last validation that wrote errors. */
151
- errors: Array<Issue>;
379
+ arrayField: <TPath extends InputArrayPath<TSchema>>(path: TPath, config?: FieldConfig) => ArrayFieldInstance<ArrayItem<InputPathValue<TSchema, TPath>>>;
380
+ /** Removes every error from the form. */
381
+ clearErrors: () => void;
382
+ /** Current validation errors of the whole form. Empty when everything is valid. */
383
+ errors: ValidationIssue[];
152
384
  /**
153
- * Upserts an issue at the same path, or appends it.
154
- * @param error Issue to set.
385
+ * Gets or creates the field at `path`. Cached: the same path always returns the
386
+ * same field (same `id`, same touched state), so it is safe to call inside a template.
387
+ * @param path Dot-notation path to the value, e.g. `'address.city'`.
388
+ * @param config Optional per-field behavior, read when the field is first created.
389
+ * @returns A reactive field to pass to `<Field>`.
155
390
  */
156
- setError: (error: Issue) => void;
391
+ field: <TPath extends InputPath<TSchema>>(path: TPath, config?: FieldConfig) => FieldInstance<InputPathValue<TSchema, TPath>>;
157
392
  /**
158
- * Replaces the entire error list.
159
- * @internal
160
- * @param errors Replacement issues.
393
+ * Reads the issues reported exactly at `path`.
394
+ * @param path Dot-notation path.
395
+ * @returns The matching issues.
161
396
  */
162
- replaceErrors: (errors: Array<Issue>) => void;
397
+ getFieldErrors: <TPath extends InputPath<TSchema>>(path: TPath) => ValidationIssue[];
163
398
  /**
164
- * Removes every issue.
165
- * @internal
399
+ * Reads the live value at `path`.
400
+ * @param path Dot-notation path.
401
+ * @returns The current value.
166
402
  */
167
- clearErrors: () => void;
403
+ getValue: <TPath extends InputPath<TSchema>>(path: TPath) => InputPathValue<TSchema, TPath>;
404
+ /** The errors the form started with. Replaced as a whole by `reset(values, errors)`. */
405
+ initialErrors: ValidationIssue[];
406
+ /** The values the form started with; `isDirty` compares against them. Replaced as a whole by `reset(values)`. */
407
+ initialValues: DeepPartial<SchemaInput<TSchema>>;
408
+ /** `true` when `values` differ (deep comparison) from `initialValues`. */
409
+ isDirty: boolean;
168
410
  /**
169
- * Issues whose path exactly equals `path` — not issues nested underneath it.
170
- *
171
- * `getFieldErrors('groups.0')` will not return an issue reported at
172
- * `groups.0.name`.
173
- *
174
- * `<NotArrayField>`'s `isValid`/`isTouched`/`isDirty`/
175
- * `isValidating` aggregate recursively instead, for exactly this reason.
176
- * @param path Dot path.
177
- * @returns Matching issues.
411
+ * Tells whether a validation concerning `path` is running: a whole-form run, a run on
412
+ * the path itself, or a run on a field nested inside it.
413
+ * @param path Dot-notation path.
414
+ * @returns `true` while one is running.
178
415
  */
179
- getFieldErrors: (path: Paths$1<TSchema>) => Array<Issue>;
180
- /** Whether any validation is in flight. */
181
- isValidating: boolean;
182
- /** Whether there are zero issues. */
416
+ isFieldValidating: <TPath extends InputPath<TSchema>>(path: TPath) => boolean;
417
+ /** `true` once a submit was attempted, even if validation failed. */
418
+ isSubmitted: boolean;
419
+ /** `true` while a submit is running (validating, or waiting for `onSubmit`). */
420
+ isSubmitting: boolean;
421
+ /** `true` once any field was blurred or a submit was attempted. */
422
+ isTouched: boolean;
423
+ /** `true` when there are no errors. Reflects the last validation; reading it does not validate. */
183
424
  isValid: boolean;
425
+ /** `true` while any validation is running. */
426
+ isValidating: boolean;
184
427
  /**
185
- * Paths currently validating.
186
- * @internal
428
+ * Replaces all current errors.
429
+ * @param nextErrors The errors the form should now show (e.g. from the server).
187
430
  */
188
- validatingFields: Set<Paths$1<TSchema>>;
431
+ replaceErrors: (nextErrors: ValidationIssue[]) => void;
189
432
  /**
190
- * Validates the whole form and replaces all errors.
191
- *
192
- * Concurrent calls are last-write-wins: each call still resolves with its
193
- * own result, but only the most recently started call's result is written
194
- * to `errors` — an older call that resolves later has its result silently
195
- * discarded from shared state.
196
- * @returns Standard Schema result.
433
+ * Resets values, errors, touched state and submit state, and cancels pending validations.
434
+ * Array items get fresh identities.
435
+ * @param nextValues New starting values. Omit to go back to the current `initialValues`.
436
+ * @param nextErrors New starting errors. Omit to go back to the current `initialErrors`.
197
437
  */
198
- validate: () => Promise<StandardSchemaV1.Result<InferOutput<TSchema>>>;
438
+ reset: {
439
+ (nextValues?: DeepPartial<SchemaInput<TSchema>>, nextErrors?: ValidationIssue[]): void;
440
+ /** Overload so it can be used directly as an event handler: `@reset.prevent="form.reset"`. */
441
+ (event: Event): void;
442
+ };
443
+ /** How many times the form was reset. Handy as a `:key` to remount inputs. */
444
+ resetCount: number;
199
445
  /**
200
- * Validates the form and writes issues only for `path`.
201
- *
202
- * `path` can be any granularity — a leaf field, an entire array field, or
203
- * a specific item inside one; `<NotField>` and `<NotArrayField>` both call
204
- * this with their own `path` internally.
205
- *
206
- * Concurrent calls for the same `path` are last-write-wins, the same as
207
- * {@linkcode validate}; a call started after this one, or a whole-form
208
- * {@linkcode validate} call, supersedes it.
209
- * @param path Dot path.
210
- * @returns Standard Schema result.
446
+ * Sets an error. Replaces the errors already on the same path.
447
+ * @param error The issue to show. Without a `path` it is a form-level error.
211
448
  */
212
- validateField: (path: Paths$1<TSchema>) => Promise<StandardSchemaV1.Result<InferOutput<TSchema>>>;
213
- /** Whether `onSubmit` is running. */
214
- isSubmitting: boolean;
449
+ setError: (error: ValidationIssue) => void;
215
450
  /**
216
- * Touches all fields, validates, then runs `onSubmit` when valid.
217
- * @param event Optional submit event. When given, `event.preventDefault()`
218
- * is called immediately, before anything else — including before checking
219
- * whether a submission is already in flight or whether validation passes.
451
+ * Writes `value` into the form at `path`.
452
+ * @param path Dot-notation path.
453
+ * @param value The new value (typed from the schema).
220
454
  */
221
- submit: (event?: SubmitEvent) => Promise<void>;
455
+ setValue: <TPath extends InputPath<TSchema>>(path: TPath, value: InputPathValue<TSchema, TPath>) => void;
222
456
  /**
223
- * Restores values/errors to the baseline. Optional arguments become the
224
- * new baseline, and reset to it immediately.
225
- *
226
- * `values`/`errors`, when given, fully replace the previous baseline —
227
- * they are not merged with it. Any top-level key present in the old
228
- * baseline but missing from `values` is simply gone afterward, the same
229
- * way `initialValues`/`initialErrors` passed to `useNotForm` become the
230
- * literal starting baseline rather than defaults merged with something
231
- * else.
232
- *
233
- * Also bumps the internal validation generation, so any `validate()`/
234
- * `validateField()` call already in flight when this runs will still
235
- * resolve with its own result, but will not write its issues to `errors`.
236
- * @param values New baseline values.
237
- * @param errors New baseline issues.
457
+ * Validates the whole form and, if valid, calls `onSubmit`. Safe to use as a `<form v-on:submit>` handler.
458
+ * Ignored while a submit is already running.
459
+ * @param event The browser submit event; its default page reload is prevented.
460
+ * @returns Resolves when the submit finished. Rejects with whatever `onSubmit` throws.
238
461
  */
239
- reset: (values?: DeepPartial<InferInput<TSchema>>, errors?: Array<Issue>) => void;
240
- }
241
- //#endregion
242
- //#region src/types/not-form-api.d.ts
243
- /**
244
- * Public API from `useNotForm`: {@linkcode NotFormInstance} without `@internal` members.
245
- *
246
- * The excluded members are the path-set accessors and mutation helpers that
247
- * `<NotField>` and `<NotArrayField>` use directly — `touchedFields`,
248
- * `markFieldAsTouched`, `dirtyFields`, `syncDirtyState`, `validatingFields`,
249
- * `replaceErrors`, `clearErrors`, and their siblings. Application code
250
- * normally reaches the same information through `isTouched`/`isDirty`/
251
- * `isValidating`, or through a specific field's own slot props, rather than
252
- * these lower-level sets and setters directly.
253
- * @template TSchema The form schema.
254
- */
255
- type NotFormAPI<TSchema extends ObjectSchema> = Pick<NotFormInstance<TSchema>, 'errors' | 'getFieldErrors' | 'isDirty' | 'isSubmitting' | 'isTouched' | 'isValid' | 'isValidating' | 'reset' | 'setError' | 'setValue' | 'submit' | 'validate' | 'validateField' | 'values'>;
256
- //#endregion
257
- //#region src/types/not-array-field.d.ts
258
- /**
259
- * One array item from `<NotArrayField>`'s default slot.
260
- * @template TSchema The form schema.
261
- */
262
- interface NotArrayFieldItem<TSchema extends ObjectSchema> {
263
- /** Stable identity for `v-for` `:key`. Independent of the current index. */
264
- key: string;
265
- /** Dot path of this item at its **current** index. */
266
- path: Paths$1<TSchema>;
267
- /** Current position in the array. */
268
- index: number;
269
- }
270
- /**
271
- * Props for `<NotArrayField>`.
272
- * @template TSchema The form schema.
273
- * @template TItemSchema Item schema used only to type mutation helpers.
274
- */
275
- interface NotArrayFieldProps<TSchema extends ObjectSchema, TItemSchema extends StandardSchemaV1 = StandardSchemaV1> {
276
- /** Dot path of the array field. */
277
- path: Paths$1<TSchema>;
278
- /**
279
- * Item schema for type inference only; never read at runtime. Does not
280
- * validate items — array items are still validated through the form's
281
- * own schema, the same as any other field.
282
- */
283
- itemSchema?: TItemSchema;
284
- /** Form instance. Overrides `<NotForm>` inject. Required outside `<NotForm>`. */
285
- form?: NotFormAPI<TSchema>;
286
- }
287
- /**
288
- * Slot props for `<NotArrayField>`.
289
- * @template TSchema The form schema.
290
- * @template TItemSchema Item schema used only to type mutation helpers.
291
- */
292
- interface NotArrayFieldSlots<TSchema extends ObjectSchema, TItemSchema extends StandardSchemaV1 = StandardSchemaV1> {
293
- default?: (props: {
294
- /** Dot path of the array field. */
295
- path: string;
296
- /** Current items, each with a stable key and current path. */
297
- items: Array<NotArrayFieldItem<TSchema>>;
298
- /**
299
- * Issues reported exactly at the array field's own path — not issues
300
- * from individual items.
301
- *
302
- * The same exact-match behavior as `<NotField>`'s `errors`.
303
- *
304
- * See {@linkcode isValid} for the aggregate that also accounts for item-level issues.
305
- */
306
- errors: Array<Issue>;
307
- /**
308
- * Whether the array field's own path, and every path nested underneath
309
- * it, have no issues — an item's own value, a field inside an object
310
- * item, or an item inside a nested array, at any depth.
311
- *
312
- * Unlike {@linkcode errors}, this recurses.
313
- */
314
- isValid: boolean;
315
- /**
316
- * Whether the array field's own path, or any path nested underneath it, has been touched.
317
- *
318
- * Recurses the same way as {@linkcode isValid}.
319
- */
320
- isTouched: boolean;
321
- /**
322
- * Whether the array field's own path, or any path nested underneath it, differs from the baseline.
323
- *
324
- * Recurses the same way as {@linkcode isValid}.
325
- */
326
- isDirty: boolean;
327
- /**
328
- * Whether the array field's own path, or any path nested underneath it, is currently validating.
329
- *
330
- * Recurses the same way as {@linkcode isValid}.
331
- */
332
- isValidating: boolean;
333
- /**
334
- * Appends a value at the end.
335
- * @param value Value to append.
336
- */
337
- append: (value: InferInput<TItemSchema>) => void;
338
- /**
339
- * Inserts a value at the start. Shifts every existing item's own
340
- * state — at any depth underneath it — forward by one position along
341
- * with it.
342
- * @param value Value to prepend.
343
- */
344
- prepend: (value: InferInput<TItemSchema>) => void;
345
- /**
346
- * Inserts a value at `index`, shifting later items — and their own
347
- * state, at any depth underneath them — back by one position.
348
- * @param index Insertion index.
349
- * @param value Value to insert.
350
- */
351
- insert: (index: number, value: InferInput<TItemSchema>) => void;
352
- /**
353
- * Removes the item at `index`. That item's own state — at any depth
354
- * underneath it — is discarded along with it; every later item's state
355
- * shifts back by one position to follow it to its new index.
356
- * @param index Index to remove.
357
- */
358
- remove: (index: number) => void;
359
- /**
360
- * Replaces the value at `index` without changing its key.
361
- * @param index Index to update.
362
- * @param value New value.
363
- */
364
- update: (index: number, value: InferInput<TItemSchema>) => void;
365
- /**
366
- * Swaps two items, moving keys and form state — at any depth
367
- * underneath each item — with them.
368
- * @param indexA First index.
369
- * @param indexB Second index.
370
- */
371
- swap: (indexA: number, indexB: number) => void;
372
- /**
373
- * Moves an item from `from` to `to`, moving keys and form state — at
374
- * any depth underneath it — with it.
375
- * @param from Current index.
376
- * @param to Destination index.
377
- */
378
- move: (from: number, to: number) => void;
379
- }) => void;
380
- }
381
- //#endregion
382
- //#region src/components/not-array-field.vue.d.ts
383
- declare const __VLS_export$3: <TSchema extends ObjectSchema, TItemSchema extends StandardSchemaV1 = StandardSchemaV1>(__VLS_props: NonNullable<Awaited<typeof __VLS_setup>>["props"], __VLS_ctx?: __VLS_PrettifyLocal$3<Pick<NonNullable<Awaited<typeof __VLS_setup>>, "attrs" | "emit" | "slots">>, __VLS_exposed?: NonNullable<Awaited<typeof __VLS_setup>>["expose"], __VLS_setup?: Promise<{
384
- props: import("vue").PublicProps & __VLS_PrettifyLocal$3<NotArrayFieldProps<TSchema, TItemSchema>> & (typeof globalThis extends {
385
- __VLS_PROPS_FALLBACK: infer P;
386
- } ? P : {});
387
- expose: (exposed: {}) => void;
388
- attrs: any;
389
- slots: NotArrayFieldSlots<TSchema, TItemSchema>;
390
- emit: {};
391
- }>) => import("vue").VNode & {
392
- __ctx?: NonNullable<Awaited<typeof __VLS_setup>>;
393
- };
394
- declare const _default: typeof __VLS_export$3;
395
- type __VLS_PrettifyLocal$3<T> = (T extends any ? { [K in keyof T]: T[K]; } : { [K in keyof T as K]: T[K]; }) & {};
396
- //#endregion
397
- //#region src/types/not-field.d.ts
398
- /**
399
- * Props for `<NotField>`.
400
- * @template TSchema The form schema.
401
- */
402
- interface NotFieldProps<TSchema extends ObjectSchema> {
403
- /** Dot path of this field. */
404
- path: Paths$1<TSchema>;
405
- /** Form instance. Overrides `<NotForm>` inject. Required outside `<NotForm>`. */
406
- form?: NotFormAPI<TSchema>;
462
+ submit: (event?: SubmitEvent) => Promise<void>;
463
+ /** How many times a submit was attempted. */
464
+ submitCount: number;
407
465
  /**
408
- * Validation triggers merged over `{ onBlur: true, onChange: true }`.
409
- *
410
- * `onMount` is also a valid trigger here, even though it has no matching
411
- * entry in `events` slot prop — there's no DOM event to bind for "the field
412
- * just appeared," so it runs automatically, once, when the field mounts.
413
- * @default { onBlur: true, onChange: true }
466
+ * Validates the whole form and replaces all errors with the outcome. Does not call `onSubmit`.
467
+ * @returns `{ value }` (the parsed output) when valid, otherwise `{ issues }`.
414
468
  */
415
- validateOn?: Partial<Record<ValidationTrigger, boolean>>;
469
+ validate: () => Promise<ValidationResult<SchemaOutput<TSchema>>>;
416
470
  /**
417
- * `lazy` — blur/submit only. `eager` — also revalidate on change/input while invalid.
418
- * @default 'eager'
471
+ * Validates the whole form against the schema but updates only the errors at `path`.
472
+ * @param path Dot-notation path.
473
+ * @returns `{ value }` (the current input value) when the field is valid, otherwise `{ issues }`
474
+ * for that field. A result made obsolete by a newer run is returned but not applied.
419
475
  */
420
- validationMode?: 'eager' | 'lazy';
421
- /** Debounce in ms for input/change validation. Blur always runs immediately. */
422
- debounce?: number;
423
- }
424
- /** Slot props for `<NotField>`. */
425
- interface NotFieldSlots {
426
- default?: (props: {
427
- /** Issues for this field path. */
428
- errors: Array<Issue>;
429
- /**
430
- * Handlers to bind to the input. `onMount` is deliberately excluded —
431
- * see the note on `validateOn` prop for why.
432
- */
433
- events: Record<ExcludeStrict<ValidationTrigger, 'onMount'>, () => void>;
434
- /** Whether the value differs from the baseline. */
435
- isDirty: boolean;
436
- /** Whether the user has interacted with this field. */
437
- isTouched: boolean;
438
- /** Whether this field has no issues. */
439
- isValid: boolean;
440
- /** Whether this field is currently validating. */
441
- isValidating: boolean;
442
- /** Dot path of this field. */
443
- path: string;
444
- }) => void;
445
- }
446
- //#endregion
447
- //#region src/components/not-field.vue.d.ts
448
- declare const __VLS_export$2: <TSchema extends ObjectSchema>(__VLS_props: NonNullable<Awaited<typeof __VLS_setup>>["props"], __VLS_ctx?: __VLS_PrettifyLocal$2<Pick<NonNullable<Awaited<typeof __VLS_setup>>, "attrs" | "emit" | "slots">>, __VLS_exposed?: NonNullable<Awaited<typeof __VLS_setup>>["expose"], __VLS_setup?: Promise<{
449
- props: import("vue").PublicProps & __VLS_PrettifyLocal$2<NotFieldProps<TSchema>> & (typeof globalThis extends {
450
- __VLS_PROPS_FALLBACK: infer P;
451
- } ? P : {});
452
- expose: (exposed: {}) => void;
453
- attrs: any;
454
- slots: NotFieldSlots;
455
- emit: {};
456
- }>) => import("vue").VNode & {
457
- __ctx?: NonNullable<Awaited<typeof __VLS_setup>>;
476
+ validateField: <TPath extends InputPath<TSchema>>(path: TPath) => Promise<ValidationResult<InputPathValue<TSchema, TPath>>>;
477
+ /** The live form data. Edit it directly, through `setValue`, or through field models. */
478
+ values: SchemaInput<TSchema>;
458
479
  };
459
- declare const _default$1: typeof __VLS_export$2;
460
- type __VLS_PrettifyLocal$2<T> = (T extends any ? { [K in keyof T]: T[K]; } : { [K in keyof T as K]: T[K]; }) & {};
461
- //#endregion
462
- //#region src/types/not-form.d.ts
463
480
  /**
464
- * Props for `<NotForm>`.
465
- * @template TSchema The form schema.
481
+ * Props of the `<Form>` component.
482
+ * @template TSchema - The schema describing the form's data.
466
483
  */
467
- interface NotFormProps<TSchema extends ObjectSchema> {
468
- /** Form instance provided to descendant field components. */
469
- form: NotFormAPI<TSchema>;
470
- }
471
- /** Slot props for `<NotForm>`. */
472
- interface NotFormSlots {
484
+ type FormProps<TSchema extends FormSchema> = {
485
+ /** The form returned by `useForm()`. */
486
+ form: UseFormInstance<TSchema>;
487
+ };
488
+ /** Slots of the `<Form>` component. */
489
+ type FormSlots = {
490
+ /** The form's contents (fields, buttons, ...). */
473
491
  default?: () => void;
474
- }
475
- //#endregion
476
- //#region src/components/not-form.vue.d.ts
477
- declare const __VLS_export$1: <TSchema extends ObjectSchema>(__VLS_props: NonNullable<Awaited<typeof __VLS_setup>>["props"], __VLS_ctx?: __VLS_PrettifyLocal$1<Pick<NonNullable<Awaited<typeof __VLS_setup>>, "attrs" | "emit" | "slots">>, __VLS_exposed?: NonNullable<Awaited<typeof __VLS_setup>>["expose"], __VLS_setup?: Promise<{
478
- props: import("vue").PublicProps & __VLS_PrettifyLocal$1<NotFormProps<TSchema>> & (typeof globalThis extends {
479
- __VLS_PROPS_FALLBACK: infer P;
480
- } ? P : {});
481
- expose: (exposed: {}) => void;
482
- attrs: any;
483
- slots: NotFormSlots;
484
- emit: {};
485
- }>) => import("vue").VNode & {
486
- __ctx?: NonNullable<Awaited<typeof __VLS_setup>>;
487
492
  };
488
- declare const _default$2: typeof __VLS_export$1;
489
- type __VLS_PrettifyLocal$1<T> = (T extends any ? { [K in keyof T]: T[K]; } : { [K in keyof T as K]: T[K]; }) & {};
490
- //#endregion
491
- //#region src/types/not-message.d.ts
492
493
  /**
493
- * Props for `<NotMessage>`.
494
- * @template TSchema The form schema.
494
+ * A subset of `FormInstance` that is safe to expose to consumers of `useForm()`.
495
+ * It omits internal methods that change the form's state, so they cannot be called from outside.
496
+ * @template TSchema - The schema describing the form's data.
495
497
  */
496
- interface NotMessageProps<TSchema extends ObjectSchema> {
497
- /**
498
- * Root element or component. When a component is given, the message is
499
- * passed to it as **default slot content**, not as a prop — a component
500
- * expecting a `message` prop instead will render with no visible text.
501
- * @default 'span'
502
- */
503
- as?: Component | string;
504
- /** Field path whose first error message is shown. */
505
- path: Paths$1<TSchema>;
506
- /** Form instance. Overrides `<NotForm>` inject. Required outside `<NotForm>`. */
507
- form?: NotFormAPI<TSchema>;
508
- }
509
- /** Slot props for `<NotMessage>`. */
510
- interface NotMessageSlots {
511
- default?: (props: {
512
- /** First active error message for `path`. */
513
- message?: string;
514
- }) => void;
515
- }
516
- //#endregion
517
- //#region src/components/not-message.vue.d.ts
518
- declare const __VLS_export: <TSchema extends ObjectSchema>(__VLS_props: NonNullable<Awaited<typeof __VLS_setup>>["props"], __VLS_ctx?: __VLS_PrettifyLocal<Pick<NonNullable<Awaited<typeof __VLS_setup>>, "attrs" | "emit" | "slots">>, __VLS_exposed?: NonNullable<Awaited<typeof __VLS_setup>>["expose"], __VLS_setup?: Promise<{
519
- props: import("vue").PublicProps & __VLS_PrettifyLocal<NotMessageProps<TSchema>> & (typeof globalThis extends {
498
+ type UseFormInstance<TSchema extends FormSchema> = Pick<FormInstance<TSchema>, 'arrayField' | 'errors' | 'field' | 'isDirty' | 'isSubmitted' | 'isSubmitting' | 'isTouched' | 'isValid' | 'isValidating' | 'reset' | 'resetCount' | 'setError' | 'setValue' | 'submit' | 'submitCount' | 'validate' | 'values'>;
499
+ declare const __VLS_export: <TSchema extends FormSchema>(__VLS_props: NonNullable<Awaited<typeof __VLS_setup>>["props"], __VLS_ctx?: __VLS_PrettifyLocal<Pick<NonNullable<Awaited<typeof __VLS_setup>>, "attrs" | "emit" | "slots">>, __VLS_exposed?: NonNullable<Awaited<typeof __VLS_setup>>["expose"], __VLS_setup?: Promise<{
500
+ props: import("vue").PublicProps & __VLS_PrettifyLocal<FormProps<TSchema>> & (typeof globalThis extends {
520
501
  __VLS_PROPS_FALLBACK: infer P;
521
502
  } ? P : {});
522
503
  expose: (exposed: {}) => void;
523
504
  attrs: any;
524
- slots: NotMessageSlots;
505
+ slots: FormSlots;
525
506
  emit: {};
526
507
  }>) => import("vue").VNode & {
527
508
  __ctx?: NonNullable<Awaited<typeof __VLS_setup>>;
528
509
  };
529
510
  declare const _default$3: typeof __VLS_export;
530
511
  type __VLS_PrettifyLocal<T> = (T extends any ? { [K in keyof T]: T[K]; } : { [K in keyof T as K]: T[K]; }) & {};
531
- //#endregion
532
- //#region src/types/not-form-config.d.ts
533
- /**
534
- * Options passed to `useNotForm`.
535
- * @template TSchema Validation schema.
536
- */
537
- interface UseNotFormConfig<TSchema extends ObjectSchema> {
538
- /** Schema used to parse and validate values. */
539
- schema: MaybeRefOrGetter<TSchema>;
540
- /** Starting values; deep-cloned before use. */
541
- initialValues?: DeepPartial<InferInput<TSchema>>;
542
- /** Issues shown before the first validation run. */
543
- initialErrors?: Array<Issue>;
544
- /**
545
- * Called after a successful submit validation.
546
- * @param data Validated output.
547
- */
548
- onSubmit?: (data: InferOutput<TSchema>) => Promise<void> | void;
549
- }
550
- //#endregion
551
- //#region src/composables/use-not-form.d.ts
552
512
  /**
553
- * Creates a form instance and returns the public {@linkcode NotFormAPI}.
554
- * @template TSchema The form schema.
555
- * @param config Schema, initial values/errors, and submit handler.
556
- * @returns Public form API. Child components still inject the full instance via `<NotForm>`.
513
+ * Creates a reactive, schema-validated form. Call it inside `setup()`, so its
514
+ * watchers and pending timers are cleaned up when the component unmounts.
515
+ * @template TSchema - A Standard Schema (Zod, Valibot, ArkType, ...) describing the form's data. Must be an object schema.
516
+ * @param config The schema, optional starting values/errors, and an optional submit handler.
517
+ * @returns The form. Pass it to `<Form :form />` and use `form.field(path)` / `form.arrayField(path)` to create fields.
518
+ * @example
519
+ * ```vue
520
+ * <script setup lang="ts">
521
+ * import { z } from 'zod'
522
+ * import { Field, Form, useForm } from 'notform'
523
+ *
524
+ * const form = useForm({
525
+ * schema: z.object({ email: z.email() }),
526
+ * initialValues: { email: '' },
527
+ * onSubmit: async (data) => {
528
+ * await api.signUp(data) // `data` is the validated output
529
+ * },
530
+ * })
531
+ * </script>
532
+ *
533
+ * <template>
534
+ * <Form :form>
535
+ * <Field v-slot="{ field }" :field="form.field('email')">
536
+ * <input v-model="field.model" v-bind="field.events" type="email">
537
+ * </Field>
538
+ * <button type="submit" :disabled="form.isSubmitting">Sign up</button>
539
+ * </Form>
540
+ * </template>
541
+ * ```
557
542
  */
558
- declare function useNotForm<TSchema extends ObjectSchema>(config: UseNotFormConfig<TSchema>): NotFormAPI<TSchema>;
559
- //#endregion
560
- export { _default as NotArrayField, type NotArrayFieldItem, type NotArrayFieldProps, type NotArrayFieldSlots, _default$1 as NotField, type NotFieldProps, type NotFieldSlots, _default$2 as NotForm, type NotFormAPI, type NotFormProps, type NotFormSlots, _default$3 as NotMessage, type NotMessageProps, type NotMessageSlots, type UseNotFormConfig, useNotForm };
543
+ export declare function useForm<TSchema extends FormSchema>(config: FormConfig<TSchema>): UseFormInstance<TSchema>;
544
+ export { _default as ArrayField, type ArrayFieldInstance, type ArrayFieldProps, type ArrayFieldSlots, type ArrayItem, type ArrayItemInstance, _default$1 as Field, type FieldConfig, _default$2 as FieldError, type FieldErrorProps, type FieldErrorSlots, type FieldEvents, type FieldInstance, type FieldProps, type FieldSlots, type FieldValidationEvent, _default$3 as Form, type FormConfig, type FormInstance, type FormProps, type FormSchema, type FormSlots, type InputArrayPath, type InputPath, type InputPathValue, type OutputPath, type OutputPathValue, type SchemaInput, type SchemaOutput, type UseFormInstance, type ValidationIssue, type ValidationResult };