@formisch/react 0.1.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/dist/index.js ADDED
@@ -0,0 +1,1039 @@
1
+ import * as v from "valibot";
2
+ import { useEffect, useLayoutEffect, useMemo, useState } from "react";
3
+ import { jsx } from "react/jsx-runtime";
4
+
5
+ //#region ../../packages/core/dist/index.vanilla.js
6
+ /**
7
+ * The current framework being used.
8
+ */
9
+ const framework = "vanilla";
10
+ /**
11
+ * Creates a unique identifier string.
12
+ *
13
+ * @returns The unique identifier.
14
+ */
15
+ /* @__NO_SIDE_EFFECTS__ */
16
+ function createId() {
17
+ return Math.random().toString(36).slice(2);
18
+ }
19
+ /**
20
+ * The current listener being tracked.
21
+ */
22
+ let listener;
23
+ /**
24
+ * Sets the current listener being tracked.
25
+ *
26
+ * @param newListener The new listener to set.
27
+ */
28
+ function setListener(newListener) {
29
+ listener = newListener;
30
+ }
31
+ /**
32
+ * Subscribers collected during a batch.
33
+ */
34
+ let batchSubscribers;
35
+ /**
36
+ * Creates a reactive signal with an initial value.
37
+ *
38
+ * @param value The initial value.
39
+ *
40
+ * @returns The created signal.
41
+ */
42
+ /* @__NO_SIDE_EFFECTS__ */
43
+ function createSignal(value) {
44
+ const subscribers = /* @__PURE__ */ new Set();
45
+ return {
46
+ get value() {
47
+ if (listener) {
48
+ subscribers.add(listener);
49
+ listener[1].add(subscribers);
50
+ }
51
+ return value;
52
+ },
53
+ set value(newValue) {
54
+ if (newValue !== value) {
55
+ value = newValue;
56
+ const localSubscribers = [];
57
+ for (const subscriber of subscribers) {
58
+ if (batchSubscribers) batchSubscribers.add(subscriber);
59
+ else localSubscribers.push(subscriber);
60
+ subscriber[1].delete(subscribers);
61
+ }
62
+ subscribers.clear();
63
+ for (const subscriber of localSubscribers) subscriber[0]();
64
+ }
65
+ }
66
+ };
67
+ }
68
+ let batchDepth = 0;
69
+ /**
70
+ * Batches multiple signal updates into a single update cycle.
71
+ *
72
+ * @param fn The function to execute in batch.
73
+ *
74
+ * @returns The return value of the function.
75
+ */
76
+ function batch(fn) {
77
+ batchDepth++;
78
+ if (!batchSubscribers) batchSubscribers = /* @__PURE__ */ new Set();
79
+ try {
80
+ return fn();
81
+ } finally {
82
+ batchDepth--;
83
+ if (batchDepth === 0) {
84
+ const subscribers = batchSubscribers;
85
+ batchSubscribers = void 0;
86
+ for (const subscriber of subscribers) subscriber[0]();
87
+ }
88
+ }
89
+ }
90
+ /**
91
+ * Executes a function without tracking reactive dependencies.
92
+ *
93
+ * @param fn The function to execute without tracking.
94
+ *
95
+ * @returns The return value of the function.
96
+ */
97
+ function untrack(fn) {
98
+ const prev = listener;
99
+ listener = void 0;
100
+ try {
101
+ return fn();
102
+ } finally {
103
+ listener = prev;
104
+ }
105
+ }
106
+ /**
107
+ * Initializes a field store recursively based on the schema structure. Handles
108
+ * array, object, and value schemas, setting up all necessary signals and
109
+ * children. Supports wrapped schemas and schema options.
110
+ *
111
+ * @param internalFieldStore The partial field store to initialize.
112
+ * @param schema The Valibot schema defining the field structure.
113
+ * @param initialInput The initial input value.
114
+ * @param path The path to the field in the form.
115
+ * @param nullish Whether the schema is wrapped in a nullish schema.
116
+ */
117
+ function initializeFieldStore(internalFieldStore, schema, initialInput, path, nullish = false) {
118
+ if (framework === "qwik" && schema.type === "lazy" || schema.type === "object_with_rest" || schema.type === "record" || schema.type === "tuple_with_rest" || schema.type === "promise") throw new Error(`"${schema.type}" schema is not supported`);
119
+ else if (schema.type === "lazy") initializeFieldStore(internalFieldStore, schema.getter(void 0), initialInput, path);
120
+ else if (schema.type === "exact_optional" || schema.type === "nullable" || schema.type === "nullish" || schema.type === "optional" || schema.type === "undefinedable") initializeFieldStore(internalFieldStore, schema.wrapped, initialInput ?? v.getDefault(schema), path, true);
121
+ else if (schema.type === "non_nullable" || schema.type === "non_nullish" || schema.type === "non_optional") initializeFieldStore(internalFieldStore, schema.wrapped, initialInput, path);
122
+ else if (schema.type === "intersect" || schema.type === "union" || schema.type === "variant") for (const schemaOption of schema.options) initializeFieldStore(internalFieldStore, schemaOption, initialInput, path);
123
+ else {
124
+ internalFieldStore.schema = schema;
125
+ internalFieldStore.name = JSON.stringify(path);
126
+ const initialElements = [];
127
+ internalFieldStore.initialElements = initialElements;
128
+ internalFieldStore.elements = initialElements;
129
+ internalFieldStore.errors = /* @__PURE__ */ createSignal(null);
130
+ internalFieldStore.isTouched = /* @__PURE__ */ createSignal(false);
131
+ internalFieldStore.isDirty = /* @__PURE__ */ createSignal(false);
132
+ if (schema.type === "array" || schema.type === "loose_tuple" || schema.type === "strict_tuple" || schema.type === "tuple") {
133
+ if (internalFieldStore.kind && internalFieldStore.kind !== "array") throw new Error(`Store initialized as "${internalFieldStore.kind}" cannot be reinitialized as "array"`);
134
+ internalFieldStore.kind = "array";
135
+ if (internalFieldStore.kind === "array") {
136
+ internalFieldStore.children ??= [];
137
+ if (schema.type === "array") {
138
+ if (initialInput) for (let index = 0; index < initialInput.length; index++) {
139
+ internalFieldStore.children[index] = {};
140
+ path.push(index);
141
+ initializeFieldStore(internalFieldStore.children[index], schema.item, initialInput[index], path);
142
+ path.pop();
143
+ }
144
+ } else for (let index = 0; index < schema.items; index++) {
145
+ internalFieldStore.children[index] = {};
146
+ path.push(index);
147
+ initializeFieldStore(internalFieldStore.children[index], schema.items[index], initialInput?.[index], path);
148
+ path.pop();
149
+ }
150
+ const arrayInput = nullish && initialInput == null ? initialInput : true;
151
+ internalFieldStore.initialInput = /* @__PURE__ */ createSignal(arrayInput);
152
+ internalFieldStore.startInput = /* @__PURE__ */ createSignal(arrayInput);
153
+ internalFieldStore.input = /* @__PURE__ */ createSignal(arrayInput);
154
+ const initialItems = internalFieldStore.children.map(createId);
155
+ internalFieldStore.initialItems = /* @__PURE__ */ createSignal(initialItems);
156
+ internalFieldStore.startItems = /* @__PURE__ */ createSignal(initialItems);
157
+ internalFieldStore.items = /* @__PURE__ */ createSignal(initialItems);
158
+ }
159
+ } else if (schema.type === "loose_object" || schema.type === "object" || schema.type === "strict_object") {
160
+ if (internalFieldStore.kind && internalFieldStore.kind !== "object") throw new Error(`Store initialized as "${internalFieldStore.kind}" cannot be reinitialized as "object"`);
161
+ internalFieldStore.kind = "object";
162
+ if (internalFieldStore.kind === "object") {
163
+ internalFieldStore.children ??= {};
164
+ for (const key in schema.entries) {
165
+ internalFieldStore.children[key] = {};
166
+ path.push(key);
167
+ initializeFieldStore(internalFieldStore.children[key], schema.entries[key], initialInput?.[key], path);
168
+ path.pop();
169
+ }
170
+ const objectInput = nullish && initialInput == null ? initialInput : true;
171
+ internalFieldStore.initialInput = /* @__PURE__ */ createSignal(objectInput);
172
+ internalFieldStore.startInput = /* @__PURE__ */ createSignal(objectInput);
173
+ internalFieldStore.input = /* @__PURE__ */ createSignal(objectInput);
174
+ }
175
+ } else {
176
+ internalFieldStore.kind = "value";
177
+ if (internalFieldStore.kind === "value") {
178
+ internalFieldStore.initialInput = /* @__PURE__ */ createSignal(initialInput);
179
+ internalFieldStore.startInput = /* @__PURE__ */ createSignal(initialInput);
180
+ internalFieldStore.input = /* @__PURE__ */ createSignal(initialInput);
181
+ }
182
+ }
183
+ }
184
+ }
185
+ /**
186
+ * Copies the deeply nested state (signal values) from one field store to
187
+ * another. This includes the `elements`, `errors`, `startInput`, `input`,
188
+ * `isTouched`, `isDirty`, and for arrays `startItems` and `items` properties.
189
+ * Recursively walks through the field stores and copies all signal values.
190
+ *
191
+ * @param fromInternalFieldStore The source field store to copy from.
192
+ * @param toInternalFieldStore The destination field store to copy to.
193
+ */
194
+ function copyItemState(fromInternalFieldStore, toInternalFieldStore) {
195
+ batch(() => {
196
+ untrack(() => {
197
+ toInternalFieldStore.elements = fromInternalFieldStore.elements;
198
+ toInternalFieldStore.errors.value = fromInternalFieldStore.errors.value;
199
+ toInternalFieldStore.startInput.value = fromInternalFieldStore.startInput.value;
200
+ toInternalFieldStore.input.value = fromInternalFieldStore.input.value;
201
+ toInternalFieldStore.isTouched.value = fromInternalFieldStore.isTouched.value;
202
+ toInternalFieldStore.isDirty.value = fromInternalFieldStore.isDirty.value;
203
+ if (fromInternalFieldStore.kind === "array" && toInternalFieldStore.kind === "array") {
204
+ const fromItems = fromInternalFieldStore.items.value;
205
+ toInternalFieldStore.startItems.value = fromInternalFieldStore.startItems.value;
206
+ toInternalFieldStore.items.value = fromItems;
207
+ let path;
208
+ for (let index = 0; index < fromItems.length; index++) {
209
+ if (!toInternalFieldStore.children[index]) {
210
+ path ??= JSON.parse(toInternalFieldStore.name);
211
+ toInternalFieldStore.children[index] = {};
212
+ path.push(index);
213
+ initializeFieldStore(toInternalFieldStore.children[index], toInternalFieldStore.schema.item, void 0, path);
214
+ path.pop();
215
+ }
216
+ copyItemState(fromInternalFieldStore.children[index], toInternalFieldStore.children[index]);
217
+ }
218
+ } else if (fromInternalFieldStore.kind === "object" && toInternalFieldStore.kind === "object") for (const key in fromInternalFieldStore.children) copyItemState(fromInternalFieldStore.children[key], toInternalFieldStore.children[key]);
219
+ });
220
+ });
221
+ }
222
+ /**
223
+ * Resets the state of a field store (signal values) deeply nested. Sets
224
+ * `elements` to empty array, `errors` to `null`, `isTouched` and `isDirty` to
225
+ * `false`, and `startInput`, `input`, `startItems`, and `items` to the new
226
+ * input value. Keeps the `initialInput` and `initialItems` state unchanged for
227
+ * form reset functionality.
228
+ *
229
+ * @param internalFieldStore The field store to reset.
230
+ * @param initialInput The new input value (can be any type including array or object).
231
+ */
232
+ function resetItemState(internalFieldStore, initialInput) {
233
+ batch(() => {
234
+ internalFieldStore.elements = [];
235
+ internalFieldStore.errors.value = null;
236
+ internalFieldStore.isTouched.value = false;
237
+ internalFieldStore.isDirty.value = false;
238
+ if (internalFieldStore.kind === "array" || internalFieldStore.kind === "object") {
239
+ const objectInput = initialInput == null ? initialInput : true;
240
+ internalFieldStore.startInput.value = objectInput;
241
+ internalFieldStore.input.value = objectInput;
242
+ if (internalFieldStore.kind === "array") if (initialInput) {
243
+ const newItems = initialInput.map(createId);
244
+ internalFieldStore.startItems.value = newItems;
245
+ internalFieldStore.items.value = newItems;
246
+ for (let index = 0; index < initialInput.length; index++) if (internalFieldStore.children[index]) resetItemState(internalFieldStore.children[index], initialInput[index]);
247
+ } else {
248
+ internalFieldStore.startItems.value = [];
249
+ internalFieldStore.items.value = [];
250
+ }
251
+ else for (const key in internalFieldStore.children) resetItemState(internalFieldStore.children[key], initialInput?.[key]);
252
+ } else {
253
+ internalFieldStore.startInput.value = initialInput;
254
+ internalFieldStore.input.value = initialInput;
255
+ }
256
+ });
257
+ }
258
+ /**
259
+ * Swaps the deeply nested state (signal values) between two field stores. This
260
+ * includes the `elements`, `errors`, `startInput`, `input`, `isTouched`,
261
+ * `isDirty`, and for arrays `startItems` and `items` properties. Recursively
262
+ * walks through the field stores and swaps all signal values.
263
+ *
264
+ * @param firstInternalFieldStore The first field store to swap.
265
+ * @param secondInternalFieldStore The second field store to swap.
266
+ */
267
+ function swapItemState(firstInternalFieldStore, secondInternalFieldStore) {
268
+ batch(() => {
269
+ untrack(() => {
270
+ const tempElements = firstInternalFieldStore.elements;
271
+ firstInternalFieldStore.elements = secondInternalFieldStore.elements;
272
+ secondInternalFieldStore.elements = tempElements;
273
+ const tempErrors = firstInternalFieldStore.errors.value;
274
+ firstInternalFieldStore.errors.value = secondInternalFieldStore.errors.value;
275
+ secondInternalFieldStore.errors.value = tempErrors;
276
+ const tempStartInput = firstInternalFieldStore.startInput.value;
277
+ firstInternalFieldStore.startInput.value = secondInternalFieldStore.startInput.value;
278
+ secondInternalFieldStore.startInput.value = tempStartInput;
279
+ const tempInput = firstInternalFieldStore.input.value;
280
+ firstInternalFieldStore.input.value = secondInternalFieldStore.input.value;
281
+ secondInternalFieldStore.input.value = tempInput;
282
+ const tempIsTouched = firstInternalFieldStore.isTouched.value;
283
+ firstInternalFieldStore.isTouched.value = secondInternalFieldStore.isTouched.value;
284
+ secondInternalFieldStore.isTouched.value = tempIsTouched;
285
+ const tempIsDirty = firstInternalFieldStore.isDirty.value;
286
+ firstInternalFieldStore.isDirty.value = secondInternalFieldStore.isDirty.value;
287
+ secondInternalFieldStore.isDirty.value = tempIsDirty;
288
+ if (firstInternalFieldStore.kind === "array" && secondInternalFieldStore.kind === "array") {
289
+ const firstItems = firstInternalFieldStore.items.value;
290
+ const secondItems = secondInternalFieldStore.items.value;
291
+ const tempStartItems = firstInternalFieldStore.startItems.value;
292
+ firstInternalFieldStore.startItems.value = secondInternalFieldStore.startItems.value;
293
+ secondInternalFieldStore.startItems.value = tempStartItems;
294
+ firstInternalFieldStore.items.value = secondItems;
295
+ secondInternalFieldStore.items.value = firstItems;
296
+ const maxLength = Math.max(firstItems.length, secondItems.length);
297
+ let firstPath;
298
+ let secondPath;
299
+ for (let index = 0; index < maxLength; index++) {
300
+ if (!firstInternalFieldStore.children[index]) {
301
+ firstPath ??= JSON.parse(firstInternalFieldStore.name);
302
+ firstInternalFieldStore.children[index] = {};
303
+ firstPath.push(index);
304
+ initializeFieldStore(firstInternalFieldStore.children[index], firstInternalFieldStore.schema.item, void 0, firstPath);
305
+ firstPath.pop();
306
+ }
307
+ if (!secondInternalFieldStore.children[index]) {
308
+ secondPath ??= JSON.parse(secondInternalFieldStore.name);
309
+ secondInternalFieldStore.children[index] = {};
310
+ secondPath.push(index);
311
+ initializeFieldStore(secondInternalFieldStore.children[index], secondInternalFieldStore.schema.item, void 0, secondPath);
312
+ secondPath.pop();
313
+ }
314
+ swapItemState(firstInternalFieldStore.children[index], secondInternalFieldStore.children[index]);
315
+ }
316
+ } else if (firstInternalFieldStore.kind === "object" && secondInternalFieldStore.kind === "object") for (const key in firstInternalFieldStore.children) swapItemState(firstInternalFieldStore.children[key], secondInternalFieldStore.children[key]);
317
+ });
318
+ });
319
+ }
320
+ /**
321
+ * Returns the current input of the field store. For arrays and objects,
322
+ * recursively collects input from all children. Returns `null` or `undefined`
323
+ * for nullish array/object inputs, or the primitive value for value fields.
324
+ *
325
+ * @param internalFieldStore The field store to get input from.
326
+ *
327
+ * @returns The field input.
328
+ */
329
+ /* @__NO_SIDE_EFFECTS__ */
330
+ function getFieldInput(internalFieldStore) {
331
+ if (internalFieldStore.kind === "array") {
332
+ if (internalFieldStore.input.value) {
333
+ const value = [];
334
+ for (let index = 0; index < internalFieldStore.items.value.length; index++) value[index] = /* @__PURE__ */ getFieldInput(internalFieldStore.children[index]);
335
+ return value;
336
+ }
337
+ return internalFieldStore.input.value;
338
+ }
339
+ if (internalFieldStore.kind === "object") {
340
+ if (internalFieldStore.input.value) {
341
+ const value = {};
342
+ for (const key in internalFieldStore.children) value[key] = /* @__PURE__ */ getFieldInput(internalFieldStore.children[key]);
343
+ return value;
344
+ }
345
+ return internalFieldStore.input.value;
346
+ }
347
+ return internalFieldStore.input.value;
348
+ }
349
+ /**
350
+ * Returns the current input of the element. Handles special cases for select
351
+ * multiple, checkbox groups, radio groups, and file inputs.
352
+ *
353
+ * @param element The field element.
354
+ * @param internalFieldStore The internal field store.
355
+ *
356
+ * @returns The element input.
357
+ */
358
+ /* @__NO_SIDE_EFFECTS__ */
359
+ function getElementInput(element, internalFieldStore) {
360
+ if (element.options && element.multiple) return [...element.options].filter((option) => option.selected && !option.disabled).map((option) => option.value);
361
+ if (element.type === "checkbox") {
362
+ const options = document.getElementsByName(element.name);
363
+ if (options.length > 1) return [...options].filter((option) => option.checked).map((option) => option.value);
364
+ return element.checked;
365
+ }
366
+ if (element.type === "radio") {
367
+ if (element.checked) return element.value;
368
+ return untrack(() => /* @__PURE__ */ getFieldInput(internalFieldStore));
369
+ }
370
+ if (element.type === "file") {
371
+ if (element.multiple) return [...element.files];
372
+ return element.files[0];
373
+ }
374
+ return element.value;
375
+ }
376
+ /**
377
+ * Returns whether the specified boolean property is true for the field store
378
+ * or any of its nested children. Recursively checks arrays and objects.
379
+ *
380
+ * @param internalFieldStore The field store to check.
381
+ * @param type The boolean property type to check.
382
+ *
383
+ * @returns Whether the property is true.
384
+ */
385
+ /* @__NO_SIDE_EFFECTS__ */
386
+ function getFieldBool(internalFieldStore, type) {
387
+ if (internalFieldStore[type].value) return true;
388
+ if (internalFieldStore.kind === "array") {
389
+ for (let index = 0; index < internalFieldStore.items.value.length; index++) if (/* @__PURE__ */ getFieldBool(internalFieldStore.children[index], type)) return true;
390
+ return false;
391
+ }
392
+ if (internalFieldStore.kind == "object") {
393
+ for (const key in internalFieldStore.children) if (/* @__PURE__ */ getFieldBool(internalFieldStore.children[key], type)) return true;
394
+ return false;
395
+ }
396
+ return false;
397
+ }
398
+ /**
399
+ * Returns the field store at the specified path by traversing the form store's
400
+ * children hierarchy.
401
+ *
402
+ * @param internalFormStore The form store to traverse.
403
+ * @param path The path to the field store.
404
+ *
405
+ * @returns The field store.
406
+ */
407
+ /* @__NO_SIDE_EFFECTS__ */
408
+ function getFieldStore(internalFormStore, path) {
409
+ let internalFieldStore = internalFormStore;
410
+ for (const key of path) internalFieldStore = internalFieldStore.children[key];
411
+ return internalFieldStore;
412
+ }
413
+ /**
414
+ * Sets the specified boolean property for the field store and all nested
415
+ * children. Recursively updates arrays and objects.
416
+ *
417
+ * @param internalFieldStore The field store to update.
418
+ * @param type The boolean property type to set.
419
+ * @param bool The boolean value to set.
420
+ */
421
+ function setFieldBool(internalFieldStore, type, bool) {
422
+ batch(() => {
423
+ if (internalFieldStore.kind === "array") {
424
+ internalFieldStore[type].value = bool;
425
+ for (let index = 0; index < untrack(() => internalFieldStore.items.value).length; index++) setFieldBool(internalFieldStore.children[index], type, bool);
426
+ } else if (internalFieldStore.kind == "object") for (const key in internalFieldStore.children) setFieldBool(internalFieldStore.children[key], type, bool);
427
+ else internalFieldStore[type].value = bool;
428
+ });
429
+ }
430
+ /**
431
+ * Sets the input for a nested field store and all its children, updating
432
+ * touched and dirty states accordingly. Handles dynamic array resizing.
433
+ *
434
+ * @param internalFieldStore The field store to update.
435
+ * @param input The new input value.
436
+ */
437
+ function setNestedInput(internalFieldStore, input) {
438
+ internalFieldStore.isTouched.value = true;
439
+ if (internalFieldStore.kind === "array") {
440
+ const arrayInput = input ?? [];
441
+ const items = internalFieldStore.items.value;
442
+ if (arrayInput.length < items.length) internalFieldStore.items.value = items.slice(0, arrayInput.length);
443
+ else if (arrayInput.length > items.length) {
444
+ if (arrayInput.length > internalFieldStore.children.length) {
445
+ const path = JSON.parse(internalFieldStore.name);
446
+ for (let index = internalFieldStore.children.length; index < arrayInput.length; index++) {
447
+ internalFieldStore.children[index] = {};
448
+ path.push(index);
449
+ initializeFieldStore(internalFieldStore.children[index], internalFieldStore.schema.item, arrayInput[index], path);
450
+ path.pop();
451
+ }
452
+ }
453
+ internalFieldStore.items.value = [...items, ...arrayInput.slice(items.length).map(createId)];
454
+ }
455
+ for (let index = 0; index < arrayInput.length; index++) setNestedInput(internalFieldStore.children[index], arrayInput[index]);
456
+ internalFieldStore.input.value = input == null ? input : true;
457
+ internalFieldStore.isDirty.value = internalFieldStore.startInput.value !== internalFieldStore.input.value || internalFieldStore.startItems.value.length !== items.length;
458
+ } else if (internalFieldStore.kind === "object") {
459
+ for (const key in internalFieldStore.children) setNestedInput(internalFieldStore.children[key], input?.[key]);
460
+ internalFieldStore.input.value = input == null ? input : true;
461
+ internalFieldStore.isDirty.value = internalFieldStore.startInput.value !== internalFieldStore.input.value;
462
+ } else {
463
+ internalFieldStore.input.value = input;
464
+ const startInput = internalFieldStore.startInput.value;
465
+ internalFieldStore.isDirty.value = startInput !== input && (startInput != null || input !== "" && !Number.isNaN(input));
466
+ }
467
+ }
468
+ /**
469
+ * Sets the input for a field at the specified path in the form store,
470
+ * traversing the path and updating all parent fields along the way.
471
+ *
472
+ * @param internalFormStore The form store containing the field.
473
+ * @param path The path to the field.
474
+ * @param input The new input value.
475
+ */
476
+ function setFieldInput(internalFormStore, path, input) {
477
+ batch(() => {
478
+ untrack(() => {
479
+ let internalFieldStore = internalFormStore;
480
+ for (let index = 0; index < path.length; index++) {
481
+ internalFieldStore = internalFieldStore.children[path[index]];
482
+ if (index < path.length - 1) internalFieldStore.input.value = true;
483
+ else setNestedInput(internalFieldStore, input);
484
+ }
485
+ });
486
+ });
487
+ }
488
+ /**
489
+ * Sets the initial input for a field store and all its children recursively.
490
+ * For arrays, initializes missing children if needed. Updates `initialInput`
491
+ * and `initialItems` properties.
492
+ *
493
+ * @param internalFieldStore The field store to update.
494
+ * @param initialInput The initial input value.
495
+ */
496
+ function setInitialFieldInput(internalFieldStore, initialInput) {
497
+ batch(() => {
498
+ if (internalFieldStore.kind === "array") {
499
+ internalFieldStore.input.value = initialInput == null ? initialInput : true;
500
+ const initialArrayInput = initialInput ?? [];
501
+ if (initialArrayInput.length > internalFieldStore.children.length) {
502
+ const path = JSON.parse(internalFieldStore.name);
503
+ for (let index = internalFieldStore.children.length; index < initialArrayInput.length; index++) {
504
+ internalFieldStore.children[index] = {};
505
+ path.push(index);
506
+ initializeFieldStore(internalFieldStore.children[index], internalFieldStore.schema.item, initialArrayInput[index], path);
507
+ path.pop();
508
+ }
509
+ }
510
+ internalFieldStore.initialItems.value = initialArrayInput.map(createId);
511
+ for (let index = 0; index < internalFieldStore.children.length; index++) setInitialFieldInput(internalFieldStore.children[index], initialArrayInput[index]);
512
+ } else if (internalFieldStore.kind === "object") {
513
+ internalFieldStore.input.value = initialInput == null ? initialInput : true;
514
+ for (const key in internalFieldStore.children) setInitialFieldInput(internalFieldStore.children[key], initialInput?.[key]);
515
+ } else internalFieldStore.initialInput.value = initialInput;
516
+ });
517
+ }
518
+ /**
519
+ * Walks through the field store and all nested children, calling the callback
520
+ * for each field store in depth-first order.
521
+ *
522
+ * @param internalFieldStore The field store to walk.
523
+ * @param callback The callback to invoke for each field store.
524
+ */
525
+ function walkFieldStore(internalFieldStore, callback) {
526
+ callback(internalFieldStore);
527
+ if (internalFieldStore.kind === "array") for (let index = 0; index < untrack(() => internalFieldStore.items.value).length; index++) walkFieldStore(internalFieldStore.children[index], callback);
528
+ else if (internalFieldStore.kind === "object") for (const key in internalFieldStore.children) walkFieldStore(internalFieldStore.children[key], callback);
529
+ }
530
+ /**
531
+ * Creates a new internal form store from the provided configuration.
532
+ * Initializes the field store hierarchy, sets validation modes, and
533
+ * creates form state signals.
534
+ *
535
+ * @param config The form configuration.
536
+ * @param parse The schema parse function.
537
+ *
538
+ * @returns The internal form store.
539
+ */
540
+ function createFormStore(config, parse) {
541
+ const store = {};
542
+ initializeFieldStore(store, config.schema, config.initialInput, []);
543
+ store.validators = 0;
544
+ store.validate = config.validate ?? "submit";
545
+ store.revalidate = config.revalidate ?? "input";
546
+ store.parse = parse;
547
+ store.isSubmitting = /* @__PURE__ */ createSignal(false);
548
+ store.isSubmitted = /* @__PURE__ */ createSignal(false);
549
+ store.isValidating = /* @__PURE__ */ createSignal(false);
550
+ return store;
551
+ }
552
+ /**
553
+ * Validates the form input using the configured Valibot schema. Parses the
554
+ * current form input, processes validation issues, assigns errors to fields,
555
+ * and optionally focuses the first field with an error.
556
+ *
557
+ * @param internalFormStore The form store to validate.
558
+ * @param config The validation configuration.
559
+ *
560
+ * @returns The Valibot validation result.
561
+ */
562
+ async function validateFormInput(internalFormStore, config) {
563
+ internalFormStore.validators++;
564
+ internalFormStore.isValidating.value = true;
565
+ const result = await internalFormStore.parse(untrack(() => /* @__PURE__ */ getFieldInput(internalFormStore)));
566
+ let rootErrors;
567
+ let nestedErrors;
568
+ if (result.issues) {
569
+ nestedErrors = {};
570
+ for (const issue of result.issues) if (issue.path) {
571
+ const path = [];
572
+ for (const pathItem of issue.path) {
573
+ const key = pathItem.key;
574
+ const keyType = typeof key;
575
+ const itemType = pathItem.type;
576
+ if (keyType !== "string" && keyType !== "number" || itemType === "map" || itemType === "set") break;
577
+ path.push(key);
578
+ }
579
+ const name = JSON.stringify(path);
580
+ const fieldErrors = nestedErrors[name];
581
+ if (fieldErrors) fieldErrors.push(issue.message);
582
+ else nestedErrors[name] = [issue.message];
583
+ } else if (rootErrors) rootErrors.push(issue.message);
584
+ else rootErrors = [issue.message];
585
+ }
586
+ let shouldFocus = config?.shouldFocus ?? false;
587
+ batch(() => {
588
+ walkFieldStore(internalFormStore, (internalFieldStore) => {
589
+ if (internalFieldStore.name === "[]") internalFieldStore.errors.value = rootErrors ?? null;
590
+ else {
591
+ const fieldErrors = nestedErrors?.[internalFieldStore.name] ?? null;
592
+ internalFieldStore.errors.value = fieldErrors;
593
+ if (shouldFocus && fieldErrors) {
594
+ internalFieldStore.elements[0]?.focus();
595
+ shouldFocus = false;
596
+ }
597
+ }
598
+ });
599
+ internalFormStore.validators--;
600
+ internalFormStore.isValidating.value = internalFormStore.validators > 0;
601
+ });
602
+ return result;
603
+ }
604
+ /**
605
+ * Validates the form input if required based on the validation mode and form
606
+ * state. Determines whether to use initial validation mode, revalidation mode,
607
+ * or skip validation entirely.
608
+ *
609
+ * @param internalFormStore The form store to validate.
610
+ * @param internalFieldStore The field store that triggered validation.
611
+ * @param validationMode The validation mode that triggered this check.
612
+ */
613
+ function validateIfRequired(internalFormStore, internalFieldStore, validationMode) {
614
+ if (validationMode === (internalFormStore.validate === "initial" || (internalFormStore.validate === "submit" ? untrack(() => internalFormStore.isSubmitted.value) : untrack(() => /* @__PURE__ */ getFieldBool(internalFieldStore, "errors"))) ? internalFormStore.revalidate : internalFormStore.validate)) validateFormInput(internalFormStore);
615
+ }
616
+ /**
617
+ * Internal symbol constant.
618
+ */
619
+ const INTERNAL = "~internal";
620
+
621
+ //#endregion
622
+ //#region ../../packages/methods/dist/index.vanilla.js
623
+ /**
624
+ * Focuses the first input element of a field. This is useful for
625
+ * programmatically setting focus to a specific field, such as after
626
+ * validation errors or user interactions.
627
+ *
628
+ * @param form The form store containing the field.
629
+ * @param config The focus field configuration.
630
+ */
631
+ function focus(form, config) {
632
+ getFieldStore(form[INTERNAL], config.path).elements[0]?.focus();
633
+ }
634
+ /**
635
+ * Retrieves all error messages from all fields in the form by walking through
636
+ * the entire field store tree. This is useful for displaying a summary of all
637
+ * validation errors across the form.
638
+ *
639
+ * @param form The form store to retrieve errors from.
640
+ *
641
+ * @returns A non-empty array of error messages, or null if no errors exist.
642
+ */
643
+ /* @__NO_SIDE_EFFECTS__ */
644
+ function getAllErrors(form) {
645
+ let allErrors = null;
646
+ walkFieldStore(form[INTERNAL], (internalFieldStore) => {
647
+ const errors = internalFieldStore.errors.value;
648
+ if (errors) if (allErrors) allErrors.push(...errors);
649
+ else allErrors = [...errors];
650
+ });
651
+ return allErrors;
652
+ }
653
+ /* @__NO_SIDE_EFFECTS__ */
654
+ function getErrors(form, config) {
655
+ return (config?.path ? getFieldStore(form[INTERNAL], config.path) : form[INTERNAL]).errors.value;
656
+ }
657
+ /* @__NO_SIDE_EFFECTS__ */
658
+ function getInput(form, config) {
659
+ return getFieldInput(config?.path ? getFieldStore(form[INTERNAL], config.path) : form[INTERNAL]);
660
+ }
661
+ /* @__NO_SIDE_EFFECTS__ */
662
+ function handleSubmit(form, handler) {
663
+ return async (event) => {
664
+ event.preventDefault();
665
+ const internalFormStore = form[INTERNAL];
666
+ internalFormStore.isSubmitted.value = true;
667
+ internalFormStore.isSubmitting.value = true;
668
+ try {
669
+ const result = await validateFormInput(internalFormStore, { shouldFocus: true });
670
+ if (result.success) await handler(result.output, event);
671
+ } catch (error) {
672
+ internalFormStore.errors.value = [error && typeof error === "object" && "message" in error && typeof error.message === "string" ? error.message : "An unknown error has occurred."];
673
+ } finally {
674
+ internalFormStore.isSubmitting.value = false;
675
+ }
676
+ };
677
+ }
678
+ /**
679
+ * Inserts a new item into a field array at the specified index. All items at
680
+ * or after the insertion point are shifted up by one index.
681
+ *
682
+ * @param form The form store containing the field array.
683
+ * @param config The insert configuration specifying the path, index, and initial value.
684
+ */
685
+ function insert(form, config) {
686
+ const internalFormStore = form[INTERNAL];
687
+ let internalFieldStore = internalFormStore;
688
+ for (let index = 0; index < config.path.length; index++) {
689
+ internalFieldStore = internalFieldStore.children[config.path[index]];
690
+ if (index < config.path.length - 1) internalFieldStore.input.value = true;
691
+ }
692
+ const internalArrayStore = internalFieldStore;
693
+ const items = untrack(() => internalArrayStore.items.value);
694
+ const insertIndex = config.at === void 0 ? items.length : config.at;
695
+ if (insertIndex >= 0 && insertIndex <= items.length) batch(() => {
696
+ const newItems = [...items];
697
+ newItems.splice(insertIndex, 0, createId());
698
+ internalArrayStore.items.value = newItems;
699
+ for (let index = items.length; index > insertIndex; index--) copyItemState(internalArrayStore.children[index - 1], internalArrayStore.children[index]);
700
+ if (!internalArrayStore.children[insertIndex]) {
701
+ const path = JSON.parse(internalArrayStore.name);
702
+ internalArrayStore.children[insertIndex] = {};
703
+ path.push(insertIndex);
704
+ initializeFieldStore(internalArrayStore.children[insertIndex], internalArrayStore.schema.item, config.initialInput, path);
705
+ } else resetItemState(internalArrayStore.children[insertIndex], config.initialInput);
706
+ internalArrayStore.input.value = true;
707
+ internalArrayStore.isTouched.value = true;
708
+ internalArrayStore.isDirty.value = true;
709
+ validateIfRequired(internalFormStore, internalArrayStore, "input");
710
+ });
711
+ }
712
+ /**
713
+ * Moves an item from one index to another within a field array. All items
714
+ * between the source and destination indices are shifted accordingly.
715
+ *
716
+ * @param form The form store containing the field array.
717
+ * @param config The move configuration specifying the path and source/destination indices.
718
+ */
719
+ function move(form, config) {
720
+ const internalFormStore = form[INTERNAL];
721
+ const internalArrayStore = getFieldStore(internalFormStore, config.path);
722
+ const items = untrack(() => internalArrayStore.items.value);
723
+ if (config.from >= 0 && config.from <= items.length - 1 && config.to >= 0 && config.to <= items.length - 1 && config.from !== config.to) batch(() => {
724
+ const newItems = [...items];
725
+ newItems.splice(config.to, 0, newItems.splice(config.from, 1)[0]);
726
+ internalArrayStore.items.value = newItems;
727
+ const tempInternalFieldStore = {};
728
+ initializeFieldStore(tempInternalFieldStore, internalArrayStore.schema.item, void 0, []);
729
+ copyItemState(internalArrayStore.children[config.from], tempInternalFieldStore);
730
+ if (config.from < config.to) for (let index = config.from; index < config.to; index++) copyItemState(internalArrayStore.children[index + 1], internalArrayStore.children[index]);
731
+ else for (let index = config.from; index > config.to; index--) copyItemState(internalArrayStore.children[index - 1], internalArrayStore.children[index]);
732
+ copyItemState(tempInternalFieldStore, internalArrayStore.children[config.to]);
733
+ internalArrayStore.isTouched.value = true;
734
+ internalArrayStore.isDirty.value = internalArrayStore.startItems.value.join() !== newItems.join();
735
+ validateIfRequired(internalFormStore, internalArrayStore, "input");
736
+ });
737
+ }
738
+ /**
739
+ * Removes an item from a field array at the specified index. All items after
740
+ * the removed item are shifted down by one index.
741
+ *
742
+ * @param form The form store containing the field array.
743
+ * @param config The remove configuration specifying the path and index.
744
+ */
745
+ function remove(form, config) {
746
+ const internalFormStore = form[INTERNAL];
747
+ const internalArrayStore = getFieldStore(internalFormStore, config.path);
748
+ const items = untrack(() => internalArrayStore.items.value);
749
+ if (config.at >= 0 && config.at <= items.length - 1) batch(() => {
750
+ const newItems = [...items];
751
+ newItems.splice(config.at, 1);
752
+ internalArrayStore.items.value = newItems;
753
+ for (let index = config.at; index < items.length - 1; index++) copyItemState(internalArrayStore.children[index + 1], internalArrayStore.children[index]);
754
+ internalArrayStore.isTouched.value = true;
755
+ internalArrayStore.isDirty.value = internalArrayStore.startItems.value.join() !== newItems.join();
756
+ validateIfRequired(internalFormStore, internalArrayStore, "input");
757
+ });
758
+ }
759
+ /**
760
+ * Replaces an item in a field array at the specified index with new initial input.
761
+ *
762
+ * @param form The form store containing the field array.
763
+ * @param config The replace configuration specifying the path, index, and initial input.
764
+ */
765
+ function replace(form, config) {
766
+ const internalFormStore = form[INTERNAL];
767
+ const internalArrayStore = getFieldStore(internalFormStore, config.path);
768
+ const items = untrack(() => internalArrayStore.items.value);
769
+ if (config.at >= 0 && config.at <= items.length - 1) batch(() => {
770
+ const newItems = [...items];
771
+ newItems[config.at] = createId();
772
+ internalArrayStore.items.value = newItems;
773
+ resetItemState(internalArrayStore.children[config.at], config.initialInput);
774
+ internalArrayStore.isTouched.value = true;
775
+ internalArrayStore.isDirty.value = true;
776
+ validateIfRequired(internalFormStore, internalArrayStore, "input");
777
+ });
778
+ }
779
+ function reset(form, config) {
780
+ batch(() => {
781
+ untrack(() => {
782
+ const internalFormStore = form[INTERNAL];
783
+ const internalFieldStore = config?.path ? getFieldStore(internalFormStore, config.path) : internalFormStore;
784
+ if (config?.initialInput) setInitialFieldInput(internalFieldStore, config.initialInput);
785
+ walkFieldStore(internalFieldStore, (internalFieldStore$1) => {
786
+ internalFieldStore$1.elements = internalFieldStore$1.initialElements;
787
+ if (!config?.keepErrors) internalFieldStore$1.errors.value = null;
788
+ if (!config?.keepTouched) internalFieldStore$1.isTouched.value = false;
789
+ internalFieldStore$1.startInput.value = internalFieldStore$1.initialInput.value;
790
+ if (!config?.keepInput) internalFieldStore$1.input.value = internalFieldStore$1.initialInput.value;
791
+ if (internalFieldStore$1.kind === "array") {
792
+ internalFieldStore$1.startItems.value = internalFieldStore$1.initialItems.value;
793
+ if (!config?.keepInput || internalFieldStore$1.startItems.value.length === internalFieldStore$1.items.value.length) internalFieldStore$1.items.value = internalFieldStore$1.initialItems.value;
794
+ internalFieldStore$1.isDirty.value = internalFieldStore$1.startInput.value !== internalFieldStore$1.input.value || internalFieldStore$1.startItems.value !== internalFieldStore$1.items.value;
795
+ } else if (internalFieldStore$1.kind === "object") internalFieldStore$1.isDirty.value = internalFieldStore$1.startInput.value !== internalFieldStore$1.input.value;
796
+ else {
797
+ const startInput = internalFieldStore$1.startInput.value;
798
+ const input = internalFieldStore$1.input.value;
799
+ internalFieldStore$1.isDirty.value = startInput !== input && (startInput != null || input !== "" && !Number.isNaN(input));
800
+ for (const element of internalFieldStore$1.elements) if (element.type === "file") element.value = "";
801
+ }
802
+ });
803
+ if (!config?.path) {
804
+ if (!config?.keepSubmitted) internalFormStore.isSubmitted.value = false;
805
+ if (internalFormStore.validate === "initial") validateFormInput(internalFormStore);
806
+ }
807
+ });
808
+ });
809
+ }
810
+ function setErrors(form, config) {
811
+ (config.path ? getFieldStore(form[INTERNAL], config.path) : form[INTERNAL]).errors.value = config.errors;
812
+ }
813
+ function setInput(form, config) {
814
+ batch(() => {
815
+ const internalFormStore = form[INTERNAL];
816
+ setFieldInput(internalFormStore, config.path ?? [], config.input);
817
+ validateIfRequired(internalFormStore, config.path ? getFieldStore(internalFormStore, config.path) : internalFormStore, "input");
818
+ });
819
+ }
820
+ /**
821
+ * Programmatically requests form submission by calling the native
822
+ * `requestSubmit()` method on the underlying form element.
823
+ *
824
+ * @param form The form store to submit.
825
+ */
826
+ function submit(form) {
827
+ form[INTERNAL].element?.requestSubmit();
828
+ }
829
+ /**
830
+ * Swaps two items in a field array by exchanging their positions.
831
+ *
832
+ * @param form The form store containing the field array.
833
+ * @param config The swap configuration specifying the path and indices to swap.
834
+ */
835
+ function swap(form, config) {
836
+ const internalFormStore = form[INTERNAL];
837
+ const internalArrayStore = getFieldStore(internalFormStore, config.path);
838
+ const items = untrack(() => internalArrayStore.items.value);
839
+ if (config.at >= 0 && config.at <= items.length - 1 && config.and >= 0 && config.and <= items.length - 1 && config.at !== config.and) batch(() => {
840
+ const newItems = [...items];
841
+ const tempItemId = newItems[config.at];
842
+ newItems[config.at] = newItems[config.and];
843
+ newItems[config.and] = tempItemId;
844
+ internalArrayStore.items.value = newItems;
845
+ swapItemState(internalArrayStore.children[config.at], internalArrayStore.children[config.and]);
846
+ internalArrayStore.isTouched.value = true;
847
+ internalArrayStore.isDirty.value = internalArrayStore.startItems.value.join() !== newItems.join();
848
+ validateIfRequired(internalFormStore, internalArrayStore, "input");
849
+ });
850
+ }
851
+ /**
852
+ * Validates the entire form input against its schema. Returns a safe parse result
853
+ * indicating success or failure with detailed issues. Optionally focuses the first
854
+ * field with validation errors.
855
+ *
856
+ * @param form The form store to validate.
857
+ * @param config The validate form configuration specifying focus behavior.
858
+ *
859
+ * @returns A promise resolving to the validation result.
860
+ */
861
+ function validate(form, config) {
862
+ return validateFormInput(form[INTERNAL], config);
863
+ }
864
+
865
+ //#endregion
866
+ //#region src/hooks/useSignals/useSignals.ts
867
+ /**
868
+ * Hook to enable reactive signals within a React component.
869
+ */
870
+ function useSignals() {
871
+ const [, setTick] = useState({});
872
+ const listener$1 = useMemo(() => [() => setTick({}), /* @__PURE__ */ new Set()], []);
873
+ for (const subscriber of listener$1[1]) subscriber.delete(listener$1);
874
+ setListener(listener$1);
875
+ useLayoutEffect(() => setListener(void 0));
876
+ }
877
+
878
+ //#endregion
879
+ //#region src/hooks/useField/useField.ts
880
+ /* @__NO_SIDE_EFFECTS__ */
881
+ function useField(form, config) {
882
+ useSignals();
883
+ const internalFormStore = form[INTERNAL];
884
+ const internalFieldStore = getFieldStore(internalFormStore, config.path);
885
+ useEffect(() => {
886
+ return () => {
887
+ internalFieldStore.elements = internalFieldStore.elements.filter((element) => element.isConnected);
888
+ };
889
+ }, [internalFieldStore]);
890
+ return {
891
+ path: config.path,
892
+ get input() {
893
+ return getFieldInput(internalFieldStore);
894
+ },
895
+ get errors() {
896
+ return internalFieldStore.errors.value;
897
+ },
898
+ get isTouched() {
899
+ return getFieldBool(internalFieldStore, "isTouched");
900
+ },
901
+ get isDirty() {
902
+ return getFieldBool(internalFieldStore, "isDirty");
903
+ },
904
+ get isValid() {
905
+ return !getFieldBool(internalFieldStore, "errors");
906
+ },
907
+ props: {
908
+ name: internalFieldStore.name,
909
+ autoFocus: !!internalFieldStore.errors.value,
910
+ ref(element) {
911
+ if (element) internalFieldStore.elements.push(element);
912
+ },
913
+ onFocus() {
914
+ setFieldBool(internalFieldStore, "isTouched", true);
915
+ validateIfRequired(internalFormStore, internalFieldStore, "touch");
916
+ },
917
+ onChange(event) {
918
+ setFieldInput(internalFormStore, config.path, getElementInput(event.currentTarget, internalFieldStore));
919
+ validateIfRequired(internalFormStore, internalFieldStore, "input");
920
+ validateIfRequired(internalFormStore, internalFieldStore, "change");
921
+ },
922
+ onBlur() {
923
+ validateIfRequired(internalFormStore, internalFieldStore, "blur");
924
+ }
925
+ }
926
+ };
927
+ }
928
+
929
+ //#endregion
930
+ //#region src/hooks/useFieldArray/useFieldArray.ts
931
+ /* @__NO_SIDE_EFFECTS__ */
932
+ function useFieldArray(form, config) {
933
+ useSignals();
934
+ const internalFormStore = form[INTERNAL];
935
+ const internalFieldStore = getFieldStore(internalFormStore, config.path);
936
+ return {
937
+ path: config.path,
938
+ get items() {
939
+ return internalFieldStore.items.value;
940
+ },
941
+ get errors() {
942
+ return internalFieldStore.errors.value;
943
+ },
944
+ get isTouched() {
945
+ return getFieldBool(internalFieldStore, "isTouched");
946
+ },
947
+ get isDirty() {
948
+ return getFieldBool(internalFieldStore, "isDirty");
949
+ },
950
+ get isValid() {
951
+ return !getFieldBool(internalFieldStore, "errors");
952
+ }
953
+ };
954
+ }
955
+
956
+ //#endregion
957
+ //#region src/hooks/useForm/useForm.ts
958
+ /* @__NO_SIDE_EFFECTS__ */
959
+ function useForm(config) {
960
+ useSignals();
961
+ const internalFormStore = useMemo(() => createFormStore(config, (input) => v.safeParseAsync(config.schema, input)), []);
962
+ useLayoutEffect(() => {
963
+ if (config.validate === "initial") validateFormInput(internalFormStore);
964
+ }, []);
965
+ return {
966
+ [INTERNAL]: internalFormStore,
967
+ get isSubmitting() {
968
+ return internalFormStore.isSubmitting.value;
969
+ },
970
+ get isSubmitted() {
971
+ return internalFormStore.isSubmitted.value;
972
+ },
973
+ get isValidating() {
974
+ return internalFormStore.isValidating.value;
975
+ },
976
+ get isTouched() {
977
+ return getFieldBool(internalFormStore, "isTouched");
978
+ },
979
+ get isDirty() {
980
+ return getFieldBool(internalFormStore, "isDirty");
981
+ },
982
+ get isValid() {
983
+ return !getFieldBool(internalFormStore, "errors");
984
+ },
985
+ get errors() {
986
+ return internalFormStore.errors.value;
987
+ }
988
+ };
989
+ }
990
+
991
+ //#endregion
992
+ //#region src/components/Field/Field.tsx
993
+ /**
994
+ * Headless form field component that provides reactive properties and state.
995
+ * The field component takes a form store, path to field, and a render function
996
+ * that receives a field store to display field state and handle user interactions.
997
+ *
998
+ * @param props The field component props.
999
+ *
1000
+ * @returns The UI of the field to be rendered.
1001
+ */
1002
+ /* @__NO_SIDE_EFFECTS__ */
1003
+ function Field({ of, path, children }) {
1004
+ return children(/* @__PURE__ */ useField(of, { path }));
1005
+ }
1006
+
1007
+ //#endregion
1008
+ //#region src/components/FieldArray/FieldArray.tsx
1009
+ /**
1010
+ * Headless field array component that provides reactive properties and state.
1011
+ * The field array component takes a form store, path to array field, and a render
1012
+ * function that receives a field array store to manage array items and handle
1013
+ * array operations.
1014
+ *
1015
+ * @param props The field array component props.
1016
+ *
1017
+ * @returns The UI of the field array to be rendered.
1018
+ */
1019
+ /* @__NO_SIDE_EFFECTS__ */
1020
+ function FieldArray({ of, path, children }) {
1021
+ return children(/* @__PURE__ */ useFieldArray(of, { path }));
1022
+ }
1023
+
1024
+ //#endregion
1025
+ //#region src/components/Form/Form.tsx
1026
+ /* @__NO_SIDE_EFFECTS__ */
1027
+ function Form({ of, onSubmit, ...other }) {
1028
+ return /* @__PURE__ */ jsx("form", {
1029
+ ...other,
1030
+ noValidate: true,
1031
+ ref: (element) => {
1032
+ if (element) of[INTERNAL].element = element;
1033
+ },
1034
+ onSubmit: handleSubmit(of, onSubmit)
1035
+ });
1036
+ }
1037
+
1038
+ //#endregion
1039
+ export { Field, FieldArray, Form, focus, getAllErrors, getErrors, getInput, handleSubmit, insert, move, remove, replace, reset, setErrors, setInput, submit, swap, useField, useFieldArray, useForm, validate };