@formisch/react 0.4.6 → 0.5.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/README.md CHANGED
@@ -59,7 +59,13 @@ In addition, Formisch offers several functions (we call them "methods") that can
59
59
 
60
60
  ## Comparison
61
61
 
62
- What makes Formisch unique is its framework-agnostic core, which is fully native to the framework you are using. It works by inserting framework-specific reactivity blocks when the core package is built. The result is a small bundle size and native performance for any UI update. This feature, along with a few others, distinguishes Formisch from other form libraries. My vision for Formisch is to create a framework-agnostic platform similar to [Vite](https://vite.dev/), but for forms.
62
+ What makes Formisch unique is its framework-agnostic core, which is fully native to the framework you are using. It works by inserting framework-specific reactivity blocks when the core package is built, giving you native performance for any UI update. A modular methods API keeps bundles starting at just ~2.5 kB by only including the methods you import, and end-to-end type safety covers deeply nested paths and field arrays with TypeScript inference that stays fast even as forms grow.
63
+
64
+ For a side-by-side look at how Formisch compares to React Hook Form and TanStack Form, see the [comparison guide](https://formisch.dev/react/guides/comparison/).
65
+
66
+ ## Vision
67
+
68
+ My vision for Formisch is to create a framework-agnostic platform similar to [Vite](https://vite.dev/), but for forms — a shared core that lets the same mental model and codebase work natively across every modern UI framework.
63
69
 
64
70
  ## Partners
65
71
 
package/dist/index.d.ts CHANGED
@@ -8,6 +8,31 @@ import { ChangeEventHandler, FocusEventHandler, FormEvent, FormHTMLAttributes, R
8
8
  * Schema type.
9
9
  */
10
10
  type Schema = v.GenericSchema | v.GenericSchemaAsync;
11
+ /**
12
+ * Object schema type.
13
+ */
14
+ type ObjectSchema = v.LooseObjectSchema<v.ObjectEntries, v.ErrorMessage<v.LooseObjectIssue> | undefined> | v.ObjectSchema<v.ObjectEntries, v.ErrorMessage<v.ObjectIssue> | undefined> | v.StrictObjectSchema<v.ObjectEntries, v.ErrorMessage<v.StrictObjectIssue> | undefined> | v.VariantSchema<string, v.VariantOptions<string>, v.ErrorMessage<v.VariantIssue> | undefined>;
15
+ /**
16
+ * Object schema async type.
17
+ */
18
+ type ObjectSchemaAsync = v.LooseObjectSchemaAsync<v.ObjectEntriesAsync, v.ErrorMessage<v.LooseObjectIssue> | undefined> | v.ObjectSchemaAsync<v.ObjectEntriesAsync, v.ErrorMessage<v.ObjectIssue> | undefined> | v.StrictObjectSchemaAsync<v.ObjectEntriesAsync, v.ErrorMessage<v.StrictObjectIssue> | undefined> | v.VariantSchemaAsync<string, v.VariantOptionsAsync<string>, v.ErrorMessage<v.VariantIssue> | undefined>;
19
+ /**
20
+ * Object root schema type.
21
+ */
22
+ type ObjectRootSchema = ObjectSchema | v.IntersectSchema<ObjectSchema[], v.ErrorMessage<v.IntersectIssue> | undefined> | v.UnionSchema<ObjectSchema[], v.ErrorMessage<v.UnionIssue<v.BaseIssue<unknown>>> | undefined>;
23
+ /**
24
+ * Object root schema async type.
25
+ */
26
+ type ObjectRootSchemaAsync = ObjectSchemaAsync | v.IntersectSchemaAsync<(ObjectSchema | ObjectSchemaAsync)[], v.ErrorMessage<v.IntersectIssue> | undefined> | v.UnionSchemaAsync<(ObjectSchema | ObjectSchemaAsync)[], v.ErrorMessage<v.UnionIssue<v.BaseIssue<unknown>>> | undefined>;
27
+ /**
28
+ * Form schema type.
29
+ *
30
+ * Hint: Forms must have an object root, so only object schemas (sync or async),
31
+ * combinators (intersect, union, variant) whose options resolve to objects, and
32
+ * `lazy` schemas wrapping any of these are allowed at the top level. Use
33
+ * {@link Schema} for nested field schemas.
34
+ */
35
+ type FormSchema = ObjectRootSchema | ObjectRootSchemaAsync | v.LazySchema<ObjectRootSchema> | v.LazySchemaAsync<ObjectRootSchema | ObjectRootSchemaAsync>;
11
36
  //#endregion
12
37
  //#region src/types/signal/signal.d.ts
13
38
  /**
@@ -224,7 +249,7 @@ type ValidationMode = "initial" | "touch" | "input" | "change" | "blur" | "submi
224
249
  /**
225
250
  * Form config interface.
226
251
  */
227
- interface FormConfig<TSchema extends Schema = Schema> {
252
+ interface FormConfig<TSchema extends FormSchema = FormSchema> {
228
253
  /**
229
254
  * The schema of the form.
230
255
  */
@@ -245,7 +270,7 @@ interface FormConfig<TSchema extends Schema = Schema> {
245
270
  /**
246
271
  * Internal form store interface.
247
272
  */
248
- interface InternalFormStore<TSchema extends Schema = Schema> extends InternalObjectStore {
273
+ interface InternalFormStore<TSchema extends FormSchema = FormSchema> extends InternalObjectStore {
249
274
  /**
250
275
  * The element of the form.
251
276
  */
@@ -282,7 +307,7 @@ interface InternalFormStore<TSchema extends Schema = Schema> extends InternalObj
282
307
  /**
283
308
  * Base form store interface.
284
309
  */
285
- interface BaseFormStore<TSchema extends Schema = Schema> {
310
+ interface BaseFormStore<TSchema extends FormSchema = FormSchema> {
286
311
  /**
287
312
  * The internal form store.
288
313
  *
@@ -295,11 +320,11 @@ interface BaseFormStore<TSchema extends Schema = Schema> {
295
320
  /**
296
321
  * Submit handler type.
297
322
  */
298
- type SubmitHandler<TSchema extends Schema> = (output: v.InferOutput<TSchema>) => MaybePromise<unknown>;
323
+ type SubmitHandler<TSchema extends FormSchema> = (output: v.InferOutput<TSchema>) => MaybePromise<unknown>;
299
324
  /**
300
325
  * Submit event handler type.
301
326
  */
302
- type SubmitEventHandler<TSchema extends Schema> = (output: v.InferOutput<TSchema>, event: FormEvent<HTMLFormElement>) => MaybePromise<unknown>;
327
+ type SubmitEventHandler<TSchema extends FormSchema> = (output: v.InferOutput<TSchema>, event: FormEvent<HTMLFormElement>) => MaybePromise<unknown>;
303
328
  //#endregion
304
329
  //#region src/types/path/path.d.ts
305
330
  /**
@@ -402,6 +427,28 @@ type LazyArrayPath<TValue, TPathToCheck extends Path, TValidPath extends Path =
402
427
  * based on the given value.
403
428
  */
404
429
  type ValidArrayPath<TValue, TPath extends RequiredPath> = TPath extends LazyArrayPath<Required<TValue>, TPath> ? TPath : LazyArrayPath<Required<TValue>, TPath>;
430
+ /**
431
+ * Recursive helper for `DirtyPath` that prepends `TKey` to each deeper path,
432
+ * or falls through to `never` when the child is not an object.
433
+ */
434
+ type DeepDirtyPath<TChild, TKey$1 extends PathKey, TDepth extends 0[]> = TChild extends Record<PropertyKey, unknown> ? readonly [TKey$1, ...DirtyPath<TChild, [...TDepth, 0]>] : never;
435
+ /**
436
+ * Returns the union of all `RequiredPath`s that `getDirtyPaths` can emit
437
+ * for a given input type. Object fields contribute their own path and the
438
+ * paths of their descendants; arrays and tuples are atomic and contribute
439
+ * only their own path, because dirty arrays are returned as complete units.
440
+ *
441
+ * Narrowing is exact for the first 5 levels of nesting; deeper paths fall
442
+ * back to `RequiredPath` to keep the result a complete superset of any
443
+ * path the runtime can address.
444
+ *
445
+ * Hint: Arrays and tuples are atomic because they don't structurally
446
+ * extend `Record<PropertyKey, unknown>` and so fall through to `never`
447
+ * via `DeepDirtyPath` — no explicit array check is needed. `TDepth` is
448
+ * a tuple-length counter capped at 5 to bound TypeScript instantiation
449
+ * cost.
450
+ */
451
+ type DirtyPath<TValue, TDepth extends 0[] = []> = TDepth["length"] extends 5 ? RequiredPath : TValue extends Record<PropertyKey, unknown> ? { [TKey in ExactKeysOf<TValue>]: readonly [TKey] | DeepDirtyPath<NonNullable<PropertiesOf<TValue>[TKey]>, TKey, TDepth> }[ExactKeysOf<TValue>] : never;
405
452
  //#endregion
406
453
  //#region src/array/copyItemState/copyItemState.d.ts
407
454
  /**
@@ -419,7 +466,7 @@ type ValidArrayPath<TValue, TPath extends RequiredPath> = TPath extends LazyArra
419
466
  /**
420
467
  * Focus field config interface.
421
468
  */
422
- interface FocusFieldConfig<TSchema extends Schema, TFieldPath extends RequiredPath> {
469
+ interface FocusFieldConfig<TSchema extends FormSchema, TFieldPath extends RequiredPath> {
423
470
  /**
424
471
  * The path to the field to focus.
425
472
  */
@@ -433,7 +480,7 @@ interface FocusFieldConfig<TSchema extends Schema, TFieldPath extends RequiredPa
433
480
  * @param form The form store containing the field.
434
481
  * @param config The focus field configuration.
435
482
  */
436
- declare function focus<TSchema extends Schema, TFieldPath extends RequiredPath>(form: BaseFormStore<TSchema>, config: FocusFieldConfig<TSchema, TFieldPath>): void;
483
+ declare function focus<TSchema extends FormSchema, TFieldPath extends RequiredPath>(form: BaseFormStore<TSchema>, config: FocusFieldConfig<TSchema, TFieldPath>): void;
437
484
  //#endregion
438
485
  //#region src/getAllErrors/getAllErrors.d.ts
439
486
  /**
@@ -447,6 +494,93 @@ declare function focus<TSchema extends Schema, TFieldPath extends RequiredPath>(
447
494
  */
448
495
  declare function getAllErrors(form: BaseFormStore): [string, ...string[]] | null;
449
496
  //#endregion
497
+ //#region src/getDirtyInput/getDirtyInput.d.ts
498
+ /**
499
+ * Get form dirty input config interface.
500
+ */
501
+ interface GetFormDirtyInputConfig {
502
+ /**
503
+ * The path to a field. Leave undefined to get the dirty input of the entire
504
+ * form.
505
+ */
506
+ readonly path?: undefined;
507
+ }
508
+ /**
509
+ * Get field dirty input config interface.
510
+ */
511
+ interface GetFieldDirtyInputConfig<TSchema extends FormSchema, TFieldPath extends RequiredPath> {
512
+ /**
513
+ * The path to the field to retrieve the dirty input from.
514
+ */
515
+ readonly path: ValidPath<v.InferInput<TSchema>, TFieldPath>;
516
+ }
517
+ /**
518
+ * Retrieves only the dirty input values of a specific field or the entire
519
+ * form. Arrays are treated as atomic and returned in full if any item is
520
+ * dirty, while object keys without a dirty descendant are omitted. Returns
521
+ * `undefined` if no field in the inspected subtree is dirty.
522
+ *
523
+ * @param form The form store to retrieve dirty input from.
524
+ *
525
+ * @returns The dirty input of the form or specified field, or `undefined`.
526
+ */
527
+ declare function getDirtyInput<TSchema extends FormSchema>(form: BaseFormStore<TSchema>): DeepPartial<v.InferInput<TSchema>> | undefined;
528
+ /**
529
+ * Retrieves only the dirty input values of a specific field or the entire
530
+ * form. Arrays are treated as atomic and returned in full if any item is
531
+ * dirty, while object keys without a dirty descendant are omitted. Returns
532
+ * `undefined` if no field in the inspected subtree is dirty.
533
+ *
534
+ * @param form The form store to retrieve dirty input from.
535
+ * @param config The get dirty input configuration.
536
+ *
537
+ * @returns The dirty input of the form or specified field, or `undefined`.
538
+ */
539
+ declare function getDirtyInput<TSchema extends FormSchema, TFieldPath extends RequiredPath | undefined = undefined>(form: BaseFormStore<TSchema>, config: TFieldPath extends RequiredPath ? GetFieldDirtyInputConfig<TSchema, TFieldPath> : GetFormDirtyInputConfig): DeepPartial<TFieldPath extends RequiredPath ? PathValue<v.InferInput<TSchema>, TFieldPath> : v.InferInput<TSchema>> | undefined;
540
+ //#endregion
541
+ //#region src/getDirtyPaths/getDirtyPaths.d.ts
542
+ /**
543
+ * Get form dirty paths config interface.
544
+ */
545
+ interface GetFormDirtyPathsConfig {
546
+ /**
547
+ * The path to a field. Leave undefined to inspect the entire form.
548
+ */
549
+ readonly path?: undefined;
550
+ }
551
+ /**
552
+ * Get field dirty paths config interface.
553
+ */
554
+ interface GetFieldDirtyPathsConfig<TSchema extends FormSchema, TFieldPath extends RequiredPath> {
555
+ /**
556
+ * The path to the field to inspect.
557
+ */
558
+ readonly path: ValidPath<v.InferInput<TSchema>, TFieldPath>;
559
+ }
560
+ /**
561
+ * Returns a list of paths to the dirty fields of a specific field or the
562
+ * entire form. Arrays are treated as atomic and contribute only their own
563
+ * path if any item is dirty, while object branches are recursed into. Returns
564
+ * an empty list if no field in the inspected subtree is dirty.
565
+ *
566
+ * @param form The form store to inspect.
567
+ *
568
+ * @returns The list of paths to the dirty fields.
569
+ */
570
+ declare function getDirtyPaths<TSchema extends FormSchema>(form: BaseFormStore<TSchema>): DirtyPath<v.InferInput<TSchema>>[];
571
+ /**
572
+ * Returns a list of paths to the dirty fields of a specific field or the
573
+ * entire form. Arrays are treated as atomic and contribute only their own
574
+ * path if any item is dirty, while object branches are recursed into. Returns
575
+ * an empty list if no field in the inspected subtree is dirty.
576
+ *
577
+ * @param form The form store to inspect.
578
+ * @param config The get dirty paths configuration.
579
+ *
580
+ * @returns The list of paths to the dirty fields.
581
+ */
582
+ declare function getDirtyPaths<TSchema extends FormSchema, TFieldPath extends RequiredPath | undefined = undefined>(form: BaseFormStore<TSchema>, config: TFieldPath extends RequiredPath ? GetFieldDirtyPathsConfig<TSchema, TFieldPath> : GetFormDirtyPathsConfig): DirtyPath<v.InferInput<TSchema>>[];
583
+ //#endregion
450
584
  //#region src/getErrors/getErrors.d.ts
451
585
  /**
452
586
  * Get form errors config interface.
@@ -460,7 +594,7 @@ interface GetFormErrorsConfig {
460
594
  /**
461
595
  * Get field errors config interface.
462
596
  */
463
- interface GetFieldErrorsConfig<TSchema extends Schema, TFieldPath extends RequiredPath> {
597
+ interface GetFieldErrorsConfig<TSchema extends FormSchema, TFieldPath extends RequiredPath> {
464
598
  /**
465
599
  * The path to the field to retrieve errors from.
466
600
  */
@@ -475,7 +609,7 @@ interface GetFieldErrorsConfig<TSchema extends Schema, TFieldPath extends Requir
475
609
  *
476
610
  * @returns A non-empty array of error messages, or null if no errors exist.
477
611
  */
478
- declare function getErrors<TSchema extends Schema>(form: BaseFormStore<TSchema>): [string, ...string[]] | null;
612
+ declare function getErrors<TSchema extends FormSchema>(form: BaseFormStore<TSchema>): [string, ...string[]] | null;
479
613
  /**
480
614
  * Retrieves error messages from the form. When called without a config,
481
615
  * returns form-level errors. When called with a path, returns errors for
@@ -486,7 +620,7 @@ declare function getErrors<TSchema extends Schema>(form: BaseFormStore<TSchema>)
486
620
  *
487
621
  * @returns A non-empty array of error messages, or null if no errors exist.
488
622
  */
489
- declare function getErrors<TSchema extends Schema, TFieldPath extends RequiredPath | undefined = undefined>(form: BaseFormStore<TSchema>, config: TFieldPath extends RequiredPath ? GetFieldErrorsConfig<TSchema, TFieldPath> : GetFormErrorsConfig): [string, ...string[]] | null;
623
+ declare function getErrors<TSchema extends FormSchema, TFieldPath extends RequiredPath | undefined = undefined>(form: BaseFormStore<TSchema>, config: TFieldPath extends RequiredPath ? GetFieldErrorsConfig<TSchema, TFieldPath> : GetFormErrorsConfig): [string, ...string[]] | null;
490
624
  //#endregion
491
625
  //#region src/getInput/getInput.d.ts
492
626
  /**
@@ -501,7 +635,7 @@ interface GetFormInputConfig {
501
635
  /**
502
636
  * Get field input config interface.
503
637
  */
504
- interface GetFieldInputConfig<TSchema extends Schema, TFieldPath extends RequiredPath> {
638
+ interface GetFieldInputConfig<TSchema extends FormSchema, TFieldPath extends RequiredPath> {
505
639
  /**
506
640
  * The path to the field to retrieve input from.
507
641
  */
@@ -515,7 +649,7 @@ interface GetFieldInputConfig<TSchema extends Schema, TFieldPath extends Require
515
649
  *
516
650
  * @returns The partial input values of the form or the specified field.
517
651
  */
518
- declare function getInput<TSchema extends Schema>(form: BaseFormStore<TSchema>): PartialValues<v.InferInput<TSchema>>;
652
+ declare function getInput<TSchema extends FormSchema>(form: BaseFormStore<TSchema>): PartialValues<v.InferInput<TSchema>>;
519
653
  /**
520
654
  * Retrieves the current input value of a specific field or the entire form.
521
655
  * Returns a partial object as not all fields may have been set.
@@ -525,7 +659,7 @@ declare function getInput<TSchema extends Schema>(form: BaseFormStore<TSchema>):
525
659
  *
526
660
  * @returns The partial input values of the form or the specified field.
527
661
  */
528
- declare function getInput<TSchema extends Schema, TFieldPath extends RequiredPath | undefined = undefined>(form: BaseFormStore<TSchema>, config: TFieldPath extends RequiredPath ? GetFieldInputConfig<TSchema, TFieldPath> : GetFormInputConfig): PartialValues<TFieldPath extends RequiredPath ? PathValue<v.InferInput<TSchema>, TFieldPath> : v.InferInput<TSchema>>;
662
+ declare function getInput<TSchema extends FormSchema, TFieldPath extends RequiredPath | undefined = undefined>(form: BaseFormStore<TSchema>, config: TFieldPath extends RequiredPath ? GetFieldInputConfig<TSchema, TFieldPath> : GetFormInputConfig): PartialValues<TFieldPath extends RequiredPath ? PathValue<v.InferInput<TSchema>, TFieldPath> : v.InferInput<TSchema>>;
529
663
  //#endregion
530
664
  //#region src/handleSubmit/handleSubmit.react.d.ts
531
665
  /**
@@ -538,7 +672,7 @@ declare function getInput<TSchema extends Schema, TFieldPath extends RequiredPat
538
672
  *
539
673
  * @returns A submit event handler function to attach to the form element.
540
674
  */
541
- declare function handleSubmit<TSchema extends Schema>(form: BaseFormStore<TSchema>, handler: SubmitHandler<TSchema>): () => Promise<void>;
675
+ declare function handleSubmit<TSchema extends FormSchema>(form: BaseFormStore<TSchema>, handler: SubmitHandler<TSchema>): () => Promise<void>;
542
676
  /**
543
677
  * Creates a submit event handler for the form that prevents default browser
544
678
  * submission, validates the form input, and calls the provided handler if
@@ -549,13 +683,13 @@ declare function handleSubmit<TSchema extends Schema>(form: BaseFormStore<TSchem
549
683
  *
550
684
  * @returns A submit event handler function to attach to the form element.
551
685
  */
552
- declare function handleSubmit<TSchema extends Schema>(form: BaseFormStore<TSchema>, handler: SubmitEventHandler<TSchema>): (event: FormEvent<HTMLFormElement>) => Promise<void>;
686
+ declare function handleSubmit<TSchema extends FormSchema>(form: BaseFormStore<TSchema>, handler: SubmitEventHandler<TSchema>): (event: FormEvent<HTMLFormElement>) => Promise<void>;
553
687
  //#endregion
554
688
  //#region src/insert/insert.d.ts
555
689
  /**
556
690
  * Insert array field config interface.
557
691
  */
558
- interface InsertConfig<TSchema extends Schema, TFieldArrayPath extends RequiredPath> {
692
+ interface InsertConfig<TSchema extends FormSchema, TFieldArrayPath extends RequiredPath> {
559
693
  /**
560
694
  * The path to the field array to insert into.
561
695
  */
@@ -576,13 +710,13 @@ interface InsertConfig<TSchema extends Schema, TFieldArrayPath extends RequiredP
576
710
  * @param form The form store containing the field array.
577
711
  * @param config The insert configuration specifying the path, index, and initial value.
578
712
  */
579
- declare function insert<TSchema extends Schema, TFieldArrayPath extends RequiredPath>(form: BaseFormStore<TSchema>, config: InsertConfig<TSchema, TFieldArrayPath>): void;
713
+ declare function insert<TSchema extends FormSchema, TFieldArrayPath extends RequiredPath>(form: BaseFormStore<TSchema>, config: InsertConfig<TSchema, TFieldArrayPath>): void;
580
714
  //#endregion
581
715
  //#region src/move/move.d.ts
582
716
  /**
583
717
  * Move array field config interface.
584
718
  */
585
- interface MoveConfig<TSchema extends Schema, TFieldArrayPath extends RequiredPath> {
719
+ interface MoveConfig<TSchema extends FormSchema, TFieldArrayPath extends RequiredPath> {
586
720
  /**
587
721
  * The path to the field array to move an item within.
588
722
  */
@@ -603,13 +737,38 @@ interface MoveConfig<TSchema extends Schema, TFieldArrayPath extends RequiredPat
603
737
  * @param form The form store containing the field array.
604
738
  * @param config The move configuration specifying the path and source/destination indices.
605
739
  */
606
- declare function move<TSchema extends Schema, TFieldArrayPath extends RequiredPath>(form: BaseFormStore<TSchema>, config: MoveConfig<TSchema, TFieldArrayPath>): void;
740
+ declare function move<TSchema extends FormSchema, TFieldArrayPath extends RequiredPath>(form: BaseFormStore<TSchema>, config: MoveConfig<TSchema, TFieldArrayPath>): void;
741
+ //#endregion
742
+ //#region src/pickDirty/pickDirty.d.ts
743
+ /**
744
+ * Pick dirty config interface.
745
+ */
746
+ interface PickDirtyConfig<TValue extends object> {
747
+ /**
748
+ * The value to filter down to its dirty parts. Must be structurally
749
+ * compatible with the form's schema.
750
+ */
751
+ readonly from: TValue;
752
+ }
753
+ /**
754
+ * Picks only the dirty parts of the given value, using the form's dirty fields
755
+ * as a structural mask. Arrays are treated as atomic and object keys without a
756
+ * dirty descendant are omitted. Returns `undefined` if no field is dirty.
757
+ * Useful for filtering a validated output down to its changed parts before
758
+ * submitting.
759
+ *
760
+ * @param form The form store providing the dirty mask.
761
+ * @param config The pick dirty configuration.
762
+ *
763
+ * @returns The dirty parts of the value, or `undefined`.
764
+ */
765
+ declare function pickDirty<TSchema extends FormSchema, TValue extends object>(form: BaseFormStore<TSchema>, config: PickDirtyConfig<TValue>): DeepPartial<TValue> | undefined;
607
766
  //#endregion
608
767
  //#region src/remove/remove.d.ts
609
768
  /**
610
769
  * Remove array field config interface.
611
770
  */
612
- interface RemoveConfig<TSchema extends Schema, TFieldArrayPath extends RequiredPath> {
771
+ interface RemoveConfig<TSchema extends FormSchema, TFieldArrayPath extends RequiredPath> {
613
772
  /**
614
773
  * The path to the field array to remove an item from.
615
774
  */
@@ -626,13 +785,13 @@ interface RemoveConfig<TSchema extends Schema, TFieldArrayPath extends RequiredP
626
785
  * @param form The form store containing the field array.
627
786
  * @param config The remove configuration specifying the path and index.
628
787
  */
629
- declare function remove<TSchema extends Schema, TFieldArrayPath extends RequiredPath>(form: BaseFormStore<TSchema>, config: RemoveConfig<TSchema, TFieldArrayPath>): void;
788
+ declare function remove<TSchema extends FormSchema, TFieldArrayPath extends RequiredPath>(form: BaseFormStore<TSchema>, config: RemoveConfig<TSchema, TFieldArrayPath>): void;
630
789
  //#endregion
631
790
  //#region src/replace/replace.d.ts
632
791
  /**
633
792
  * Replace array field config interface.
634
793
  */
635
- interface ReplaceConfig<TSchema extends Schema, TFieldArrayPath extends RequiredPath> {
794
+ interface ReplaceConfig<TSchema extends FormSchema, TFieldArrayPath extends RequiredPath> {
636
795
  /**
637
796
  * The path to the field array to replace an item within.
638
797
  */
@@ -652,7 +811,7 @@ interface ReplaceConfig<TSchema extends Schema, TFieldArrayPath extends Required
652
811
  * @param form The form store containing the field array.
653
812
  * @param config The replace configuration specifying the path, index, and initial input.
654
813
  */
655
- declare function replace<TSchema extends Schema, TFieldArrayPath extends RequiredPath>(form: BaseFormStore<TSchema>, config: ReplaceConfig<TSchema, TFieldArrayPath>): void;
814
+ declare function replace<TSchema extends FormSchema, TFieldArrayPath extends RequiredPath>(form: BaseFormStore<TSchema>, config: ReplaceConfig<TSchema, TFieldArrayPath>): void;
656
815
  //#endregion
657
816
  //#region src/reset/reset.d.ts
658
817
  /**
@@ -675,7 +834,7 @@ interface ResetBaseConfig {
675
834
  /**
676
835
  * Reset form config interface.
677
836
  */
678
- interface ResetFormConfig<TSchema extends Schema> extends ResetBaseConfig {
837
+ interface ResetFormConfig<TSchema extends FormSchema> extends ResetBaseConfig {
679
838
  /**
680
839
  * The path to a field. Leave undefined to reset the entire form.
681
840
  */
@@ -693,7 +852,7 @@ interface ResetFormConfig<TSchema extends Schema> extends ResetBaseConfig {
693
852
  /**
694
853
  * Reset field config interface.
695
854
  */
696
- interface ResetFieldConfig<TSchema extends Schema, TFieldPath extends RequiredPath> extends ResetBaseConfig {
855
+ interface ResetFieldConfig<TSchema extends FormSchema, TFieldPath extends RequiredPath> extends ResetBaseConfig {
697
856
  /**
698
857
  * The path to the field to reset.
699
858
  */
@@ -720,7 +879,7 @@ declare function reset(form: BaseFormStore): void;
720
879
  * @param form The form store to reset.
721
880
  * @param config The reset configuration specifying what to reset and what to keep.
722
881
  */
723
- declare function reset<TSchema extends Schema, TFieldPath extends RequiredPath | undefined = undefined>(form: BaseFormStore<TSchema>, config: TFieldPath extends RequiredPath ? ResetFieldConfig<TSchema, TFieldPath> : ResetFormConfig<TSchema>): void;
882
+ declare function reset<TSchema extends FormSchema, TFieldPath extends RequiredPath | undefined = undefined>(form: BaseFormStore<TSchema>, config: TFieldPath extends RequiredPath ? ResetFieldConfig<TSchema, TFieldPath> : ResetFormConfig<TSchema>): void;
724
883
  //#endregion
725
884
  //#region src/setErrors/setErrors.d.ts
726
885
  /**
@@ -739,7 +898,7 @@ interface SetFormErrorsConfig {
739
898
  /**
740
899
  * Set field errors config interface.
741
900
  */
742
- interface SetFieldErrorsConfig<TSchema extends Schema, TFieldPath extends RequiredPath> {
901
+ interface SetFieldErrorsConfig<TSchema extends FormSchema, TFieldPath extends RequiredPath> {
743
902
  /**
744
903
  * The path to the field to set errors on.
745
904
  */
@@ -757,13 +916,13 @@ interface SetFieldErrorsConfig<TSchema extends Schema, TFieldPath extends Requir
757
916
  * @param form The form store to set errors on.
758
917
  * @param config The set errors configuration specifying the path and error messages.
759
918
  */
760
- declare function setErrors<TSchema extends Schema, TFieldPath extends RequiredPath | undefined = undefined>(form: BaseFormStore<TSchema>, config: TFieldPath extends RequiredPath ? SetFieldErrorsConfig<TSchema, TFieldPath> : SetFormErrorsConfig): void;
919
+ declare function setErrors<TSchema extends FormSchema, TFieldPath extends RequiredPath | undefined = undefined>(form: BaseFormStore<TSchema>, config: TFieldPath extends RequiredPath ? SetFieldErrorsConfig<TSchema, TFieldPath> : SetFormErrorsConfig): void;
761
920
  //#endregion
762
921
  //#region src/setInput/setInput.d.ts
763
922
  /**
764
923
  * Set form input config interface.
765
924
  */
766
- interface SetFormInputConfig<TSchema extends Schema> {
925
+ interface SetFormInputConfig<TSchema extends FormSchema> {
767
926
  /**
768
927
  * The path to a field. Leave undefined to set the entire form input.
769
928
  */
@@ -776,7 +935,7 @@ interface SetFormInputConfig<TSchema extends Schema> {
776
935
  /**
777
936
  * Set field input config interface.
778
937
  */
779
- interface SetFieldInputConfig<TSchema extends Schema, TFieldPath extends RequiredPath> {
938
+ interface SetFieldInputConfig<TSchema extends FormSchema, TFieldPath extends RequiredPath> {
780
939
  /**
781
940
  * The path to the field to set input on.
782
941
  */
@@ -796,7 +955,7 @@ interface SetFieldInputConfig<TSchema extends Schema, TFieldPath extends Require
796
955
  * @param form The form store to set input on.
797
956
  * @param config The set form input configuration specifying the new input values.
798
957
  */
799
- declare function setInput<TSchema extends Schema>(form: BaseFormStore<TSchema>, config: SetFormInputConfig<TSchema>): void;
958
+ declare function setInput<TSchema extends FormSchema>(form: BaseFormStore<TSchema>, config: SetFormInputConfig<TSchema>): void;
800
959
  /**
801
960
  * Sets the input value of a specific field or the entire form. This updates
802
961
  * the field value(s) and triggers validation if required by the form's
@@ -805,7 +964,7 @@ declare function setInput<TSchema extends Schema>(form: BaseFormStore<TSchema>,
805
964
  * @param form The form store to set input on.
806
965
  * @param config The set input configuration specifying the path and new value.
807
966
  */
808
- declare function setInput<TSchema extends Schema, TFieldPath extends RequiredPath | undefined = undefined>(form: BaseFormStore<TSchema>, config: TFieldPath extends RequiredPath ? SetFieldInputConfig<TSchema, TFieldPath> : SetFormInputConfig<TSchema>): void;
967
+ declare function setInput<TSchema extends FormSchema, TFieldPath extends RequiredPath | undefined = undefined>(form: BaseFormStore<TSchema>, config: TFieldPath extends RequiredPath ? SetFieldInputConfig<TSchema, TFieldPath> : SetFormInputConfig<TSchema>): void;
809
968
  //#endregion
810
969
  //#region src/submit/submit.d.ts
811
970
  /**
@@ -820,7 +979,7 @@ declare function submit(form: BaseFormStore): void;
820
979
  /**
821
980
  * Swap array field config interface.
822
981
  */
823
- interface SwapConfig<TSchema extends Schema, TFieldArrayPath extends RequiredPath> {
982
+ interface SwapConfig<TSchema extends FormSchema, TFieldArrayPath extends RequiredPath> {
824
983
  /**
825
984
  * The path to the field array to swap items within.
826
985
  */
@@ -840,7 +999,7 @@ interface SwapConfig<TSchema extends Schema, TFieldArrayPath extends RequiredPat
840
999
  * @param form The form store containing the field array.
841
1000
  * @param config The swap configuration specifying the path and indices to swap.
842
1001
  */
843
- declare function swap<TSchema extends Schema, TFieldArrayPath extends RequiredPath>(form: BaseFormStore<TSchema>, config: SwapConfig<TSchema, TFieldArrayPath>): void;
1002
+ declare function swap<TSchema extends FormSchema, TFieldArrayPath extends RequiredPath>(form: BaseFormStore<TSchema>, config: SwapConfig<TSchema, TFieldArrayPath>): void;
844
1003
  //#endregion
845
1004
  //#region src/validate/validate.d.ts
846
1005
  /**
@@ -862,7 +1021,7 @@ interface ValidateFormConfig {
862
1021
  *
863
1022
  * @returns A promise resolving to the validation result.
864
1023
  */
865
- declare function validate<TSchema extends Schema>(form: BaseFormStore<TSchema>, config?: ValidateFormConfig): Promise<v.SafeParseResult<TSchema>>;
1024
+ declare function validate<TSchema extends FormSchema>(form: BaseFormStore<TSchema>, config?: ValidateFormConfig): Promise<v.SafeParseResult<TSchema>>;
866
1025
  //#endregion
867
1026
  //#endregion
868
1027
  //#region src/types/field.d.ts
@@ -898,7 +1057,7 @@ interface FieldElementProps {
898
1057
  /**
899
1058
  * Field store interface.
900
1059
  */
901
- interface FieldStore<TSchema extends Schema = Schema, TFieldPath extends RequiredPath = RequiredPath> {
1060
+ interface FieldStore<TSchema extends FormSchema = FormSchema, TFieldPath extends RequiredPath = RequiredPath> {
902
1061
  /**
903
1062
  * The path to the field within the form.
904
1063
  */
@@ -935,7 +1094,7 @@ interface FieldStore<TSchema extends Schema = Schema, TFieldPath extends Require
935
1094
  /**
936
1095
  * Field array store interface.
937
1096
  */
938
- interface FieldArrayStore<TSchema extends Schema = Schema, TFieldArrayPath extends RequiredPath = RequiredPath> {
1097
+ interface FieldArrayStore<TSchema extends FormSchema = FormSchema, TFieldArrayPath extends RequiredPath = RequiredPath> {
939
1098
  /**
940
1099
  * The path to the array field within the form.
941
1100
  */
@@ -966,7 +1125,7 @@ interface FieldArrayStore<TSchema extends Schema = Schema, TFieldArrayPath exten
966
1125
  /**
967
1126
  * Form store interface.
968
1127
  */
969
- interface FormStore<TSchema extends Schema = Schema> extends BaseFormStore<TSchema> {
1128
+ interface FormStore<TSchema extends FormSchema = FormSchema> extends BaseFormStore<TSchema> {
970
1129
  /**
971
1130
  * Whether the form is currently submitting.
972
1131
  */
@@ -1004,7 +1163,7 @@ interface FormStore<TSchema extends Schema = Schema> extends BaseFormStore<TSche
1004
1163
  /**
1005
1164
  * Field component props interface.
1006
1165
  */
1007
- interface FieldProps<TSchema extends Schema = Schema, TFieldPath extends RequiredPath = RequiredPath> {
1166
+ interface FieldProps<TSchema extends FormSchema = FormSchema, TFieldPath extends RequiredPath = RequiredPath> {
1008
1167
  /**
1009
1168
  * The form store to which the field belongs.
1010
1169
  */
@@ -1027,7 +1186,7 @@ interface FieldProps<TSchema extends Schema = Schema, TFieldPath extends Require
1027
1186
  *
1028
1187
  * @returns The UI of the field to be rendered.
1029
1188
  */
1030
- declare function Field<TSchema extends Schema, TFieldPath extends RequiredPath>({
1189
+ declare function Field<TSchema extends FormSchema, TFieldPath extends RequiredPath>({
1031
1190
  of,
1032
1191
  path,
1033
1192
  children
@@ -1037,7 +1196,7 @@ declare function Field<TSchema extends Schema, TFieldPath extends RequiredPath>(
1037
1196
  /**
1038
1197
  * FieldArray component props interface.
1039
1198
  */
1040
- interface FieldArrayProps<TSchema extends Schema = Schema, TFieldArrayPath extends RequiredPath = RequiredPath> {
1199
+ interface FieldArrayProps<TSchema extends FormSchema = FormSchema, TFieldArrayPath extends RequiredPath = RequiredPath> {
1041
1200
  /**
1042
1201
  * The form store to which the field array belongs.
1043
1202
  */
@@ -1061,7 +1220,7 @@ interface FieldArrayProps<TSchema extends Schema = Schema, TFieldArrayPath exten
1061
1220
  *
1062
1221
  * @returns The UI of the field array to be rendered.
1063
1222
  */
1064
- declare function FieldArray<TSchema extends Schema, TFieldArrayPath extends RequiredPath>({
1223
+ declare function FieldArray<TSchema extends FormSchema, TFieldArrayPath extends RequiredPath>({
1065
1224
  of,
1066
1225
  path,
1067
1226
  children
@@ -1071,7 +1230,7 @@ declare function FieldArray<TSchema extends Schema, TFieldArrayPath extends Requ
1071
1230
  /**
1072
1231
  * Form component props type.
1073
1232
  */
1074
- type FormProps<TSchema extends Schema = Schema> = Omit<FormHTMLAttributes<HTMLFormElement>, "onSubmit" | "novalidate" | "noValidate"> & {
1233
+ type FormProps<TSchema extends FormSchema = FormSchema> = Omit<FormHTMLAttributes<HTMLFormElement>, "onSubmit" | "novalidate" | "noValidate"> & {
1075
1234
  /**
1076
1235
  * The form store instance.
1077
1236
  */
@@ -1089,13 +1248,13 @@ type FormProps<TSchema extends Schema = Schema> = Omit<FormHTMLAttributes<HTMLFo
1089
1248
  *
1090
1249
  * @returns The a native form element.
1091
1250
  */
1092
- declare function Form<TSchema extends Schema>(props: FormProps<TSchema>): ReactElement;
1251
+ declare function Form<TSchema extends FormSchema>(props: FormProps<TSchema>): ReactElement;
1093
1252
  //#endregion
1094
1253
  //#region src/hooks/useField/useField.d.ts
1095
1254
  /**
1096
1255
  * Use field config interface.
1097
1256
  */
1098
- interface UseFieldConfig<TSchema extends Schema = Schema, TFieldPath extends RequiredPath = RequiredPath> {
1257
+ interface UseFieldConfig<TSchema extends FormSchema = FormSchema, TFieldPath extends RequiredPath = RequiredPath> {
1099
1258
  /**
1100
1259
  * The path to the field within the form schema.
1101
1260
  */
@@ -1109,13 +1268,13 @@ interface UseFieldConfig<TSchema extends Schema = Schema, TFieldPath extends Req
1109
1268
  *
1110
1269
  * @returns The field store with reactive properties and element props.
1111
1270
  */
1112
- declare function useField<TSchema extends Schema, TFieldPath extends RequiredPath>(form: FormStore<TSchema>, config: UseFieldConfig<TSchema, TFieldPath>): FieldStore<TSchema, TFieldPath>;
1271
+ declare function useField<TSchema extends FormSchema, TFieldPath extends RequiredPath>(form: FormStore<TSchema>, config: UseFieldConfig<TSchema, TFieldPath>): FieldStore<TSchema, TFieldPath>;
1113
1272
  //#endregion
1114
1273
  //#region src/hooks/useFieldArray/useFieldArray.d.ts
1115
1274
  /**
1116
1275
  * Use field array config interface.
1117
1276
  */
1118
- interface UseFieldArrayConfig<TSchema extends Schema = Schema, TFieldArrayPath extends RequiredPath = RequiredPath> {
1277
+ interface UseFieldArrayConfig<TSchema extends FormSchema = FormSchema, TFieldArrayPath extends RequiredPath = RequiredPath> {
1119
1278
  /**
1120
1279
  * The path to the array field within the form schema.
1121
1280
  */
@@ -1129,7 +1288,7 @@ interface UseFieldArrayConfig<TSchema extends Schema = Schema, TFieldArrayPath e
1129
1288
  *
1130
1289
  * @returns The field array store with reactive properties for array management.
1131
1290
  */
1132
- declare function useFieldArray<TSchema extends Schema, TFieldArrayPath extends RequiredPath>(form: FormStore<TSchema>, config: UseFieldArrayConfig<TSchema, TFieldArrayPath>): FieldArrayStore<TSchema, TFieldArrayPath>;
1291
+ declare function useFieldArray<TSchema extends FormSchema, TFieldArrayPath extends RequiredPath>(form: FormStore<TSchema>, config: UseFieldArrayConfig<TSchema, TFieldArrayPath>): FieldArrayStore<TSchema, TFieldArrayPath>;
1133
1292
  //#endregion
1134
1293
  //#region src/hooks/useForm/useForm.d.ts
1135
1294
  /**
@@ -1140,6 +1299,6 @@ declare function useFieldArray<TSchema extends Schema, TFieldArrayPath extends R
1140
1299
  *
1141
1300
  * @returns The form store with reactive properties.
1142
1301
  */
1143
- declare function useForm<TSchema extends Schema>(config: FormConfig<TSchema>): FormStore<TSchema>;
1302
+ declare function useForm<TSchema extends FormSchema>(config: FormConfig<TSchema>): FormStore<TSchema>;
1144
1303
  //#endregion
1145
- export { type DeepPartial, Field, FieldArray, FieldArrayProps, FieldArrayStore, type FieldElement, FieldElementProps, FieldProps, FieldStore, FocusFieldConfig, Form, type FormConfig, FormProps, FormStore, GetFieldErrorsConfig, GetFieldInputConfig, GetFormErrorsConfig, GetFormInputConfig, InsertConfig, MoveConfig, type PartialValues, type PathValue, RemoveConfig, ReplaceConfig, type RequiredPath, ResetFieldConfig, ResetFormConfig, type Schema, SetFieldErrorsConfig, type SetFieldInputConfig, SetFormErrorsConfig, type SetFormInputConfig, type SubmitEventHandler, type SubmitHandler, SwapConfig, UseFieldArrayConfig, UseFieldConfig, type ValidArrayPath, type ValidPath, ValidateFormConfig, type ValidationMode, focus, getAllErrors, getErrors, getInput, handleSubmit, insert, move, remove, replace, reset, setErrors, setInput, submit, swap, useField, useFieldArray, useForm, validate };
1304
+ export { type DeepPartial, Field, FieldArray, FieldArrayProps, FieldArrayStore, type FieldElement, FieldElementProps, FieldProps, FieldStore, FocusFieldConfig, Form, type FormConfig, FormProps, type FormSchema, FormStore, GetFieldDirtyInputConfig, GetFieldDirtyPathsConfig, GetFieldErrorsConfig, GetFieldInputConfig, GetFormDirtyInputConfig, GetFormDirtyPathsConfig, GetFormErrorsConfig, GetFormInputConfig, InsertConfig, MoveConfig, type PartialValues, type PathValue, PickDirtyConfig, RemoveConfig, ReplaceConfig, type RequiredPath, ResetFieldConfig, ResetFormConfig, type Schema, SetFieldErrorsConfig, type SetFieldInputConfig, SetFormErrorsConfig, type SetFormInputConfig, type SubmitEventHandler, type SubmitHandler, SwapConfig, UseFieldArrayConfig, UseFieldConfig, type ValidArrayPath, type ValidPath, ValidateFormConfig, type ValidationMode, focus, getAllErrors, getDirtyInput, getDirtyPaths, getErrors, getInput, handleSubmit, insert, move, pickDirty, remove, replace, reset, setErrors, setInput, submit, swap, useField, useFieldArray, useForm, validate };
package/dist/index.js CHANGED
@@ -319,6 +319,63 @@ function swapItemState(firstInternalFieldStore, secondInternalFieldStore) {
319
319
  });
320
320
  }
321
321
  /**
322
+ * Returns whether the specified boolean property is true for the field store
323
+ * or any of its nested children. Recursively checks arrays and objects.
324
+ *
325
+ * @param internalFieldStore The field store to check.
326
+ * @param type The boolean property type to check.
327
+ *
328
+ * @returns Whether the property is true.
329
+ */
330
+ /* @__NO_SIDE_EFFECTS__ */
331
+ function getFieldBool(internalFieldStore, type) {
332
+ if (internalFieldStore[type].value) return true;
333
+ if (internalFieldStore.kind === "array") {
334
+ for (let index = 0; index < internalFieldStore.items.value.length; index++) if (/* @__PURE__ */ getFieldBool(internalFieldStore.children[index], type)) return true;
335
+ return false;
336
+ }
337
+ if (internalFieldStore.kind == "object") {
338
+ for (const key in internalFieldStore.children) if (/* @__PURE__ */ getFieldBool(internalFieldStore.children[key], type)) return true;
339
+ return false;
340
+ }
341
+ return false;
342
+ }
343
+ /**
344
+ * Returns only the dirty input of the field store. Arrays are treated as
345
+ * atomic and returned in full if any item is dirty, while object keys without
346
+ * a dirty descendant are omitted. Returns `undefined` if no descendant is
347
+ * dirty.
348
+ *
349
+ * @param internalFieldStore The field store to get dirty input from.
350
+ * @param dirtyOnly Whether to only include dirty fields. Defaults to `true`.
351
+ *
352
+ * @returns The dirty input, or `undefined` if no descendant is dirty.
353
+ */
354
+ /* @__NO_SIDE_EFFECTS__ */
355
+ function getDirtyFieldInput(internalFieldStore, dirtyOnly = true) {
356
+ if (dirtyOnly && !/* @__PURE__ */ getFieldBool(internalFieldStore, "isDirty")) return;
357
+ if (internalFieldStore.kind === "array") {
358
+ if (internalFieldStore.input.value) {
359
+ const value = [];
360
+ for (let index = 0; index < internalFieldStore.items.value.length; index++) value[index] = /* @__PURE__ */ getDirtyFieldInput(internalFieldStore.children[index], false);
361
+ return value;
362
+ }
363
+ return internalFieldStore.input.value;
364
+ }
365
+ if (internalFieldStore.kind === "object") {
366
+ if (internalFieldStore.input.value) {
367
+ const value = {};
368
+ for (const key in internalFieldStore.children) {
369
+ const child = internalFieldStore.children[key];
370
+ if (!dirtyOnly || /* @__PURE__ */ getFieldBool(child, "isDirty")) value[key] = /* @__PURE__ */ getDirtyFieldInput(child, dirtyOnly);
371
+ }
372
+ return value;
373
+ }
374
+ return internalFieldStore.input.value;
375
+ }
376
+ return internalFieldStore.input.value;
377
+ }
378
+ /**
322
379
  * Returns the current input of the field store. For arrays and objects,
323
380
  * recursively collects input from all children. Returns `null` or `undefined`
324
381
  * for nullish array/object inputs, or the primitive value for value fields.
@@ -375,28 +432,6 @@ function getElementInput(element, internalFieldStore) {
375
432
  return element.value;
376
433
  }
377
434
  /**
378
- * Returns whether the specified boolean property is true for the field store
379
- * or any of its nested children. Recursively checks arrays and objects.
380
- *
381
- * @param internalFieldStore The field store to check.
382
- * @param type The boolean property type to check.
383
- *
384
- * @returns Whether the property is true.
385
- */
386
- /* @__NO_SIDE_EFFECTS__ */
387
- function getFieldBool(internalFieldStore, type) {
388
- if (internalFieldStore[type].value) return true;
389
- if (internalFieldStore.kind === "array") {
390
- for (let index = 0; index < internalFieldStore.items.value.length; index++) if (/* @__PURE__ */ getFieldBool(internalFieldStore.children[index], type)) return true;
391
- return false;
392
- }
393
- if (internalFieldStore.kind == "object") {
394
- for (const key in internalFieldStore.children) if (/* @__PURE__ */ getFieldBool(internalFieldStore.children[key], type)) return true;
395
- return false;
396
- }
397
- return false;
398
- }
399
- /**
400
435
  * Returns the field store at the specified path by traversing the form store's
401
436
  * children hierarchy.
402
437
  *
@@ -653,6 +688,17 @@ function getAllErrors(form) {
653
688
  return allErrors;
654
689
  }
655
690
  /* @__NO_SIDE_EFFECTS__ */
691
+ function getDirtyInput(form, config) {
692
+ return getDirtyFieldInput(config?.path ? getFieldStore(form[INTERNAL], config.path) : form[INTERNAL]);
693
+ }
694
+ /* @__NO_SIDE_EFFECTS__ */
695
+ function getDirtyPaths(form, config) {
696
+ config?.path ? getFieldStore(form[INTERNAL], config.path) : form[INTERNAL];
697
+ const paths = [];
698
+ config?.path && [...config.path];
699
+ return paths;
700
+ }
701
+ /* @__NO_SIDE_EFFECTS__ */
656
702
  function getErrors(form, config) {
657
703
  return (config?.path ? getFieldStore(form[INTERNAL], config.path) : form[INTERNAL]).errors.value;
658
704
  }
@@ -750,6 +796,48 @@ function move(form, config) {
750
796
  });
751
797
  }
752
798
  /**
799
+ * Picks only the dirty parts of the given value, using the form's dirty fields
800
+ * as a structural mask. Arrays are treated as atomic and object keys without a
801
+ * dirty descendant are omitted. Returns `undefined` if no field is dirty.
802
+ * Useful for filtering a validated output down to its changed parts before
803
+ * submitting.
804
+ *
805
+ * @param form The form store providing the dirty mask.
806
+ * @param config The pick dirty configuration.
807
+ *
808
+ * @returns The dirty parts of the value, or `undefined`.
809
+ */
810
+ /* @__NO_SIDE_EFFECTS__ */
811
+ function pickDirty(form, config) {
812
+ if (!getFieldBool(form[INTERNAL], "isDirty")) return;
813
+ const result = /* @__PURE__ */ pickFieldValue(form[INTERNAL], config.from);
814
+ return Object.keys(result).length ? result : void 0;
815
+ }
816
+ /**
817
+ * Recursively picks the dirty parts of a value using the field store as a
818
+ * structural mask, reading from the supplied value rather than the form's own
819
+ * input. Objects with non-nullish input recurse into their dirty children that
820
+ * are present in the value, while arrays, primitives, nullish-cleared fields
821
+ * and shape-diverging values are returned as-is.
822
+ *
823
+ * @param internalFieldStore The field store used as the dirty mask.
824
+ * @param value The value to pick the dirty parts from.
825
+ *
826
+ * @returns The dirty parts of the value.
827
+ */
828
+ /* @__NO_SIDE_EFFECTS__ */
829
+ function pickFieldValue(internalFieldStore, value) {
830
+ if (internalFieldStore.kind === "object" && internalFieldStore.input.value && value && typeof value === "object" && !Array.isArray(value)) {
831
+ const result = {};
832
+ for (const key in internalFieldStore.children) {
833
+ const child = internalFieldStore.children[key];
834
+ if (getFieldBool(child, "isDirty") && key in value) result[key] = /* @__PURE__ */ pickFieldValue(child, value[key]);
835
+ }
836
+ return result;
837
+ }
838
+ return value;
839
+ }
840
+ /**
753
841
  * Removes an item from a field array at the specified index. All items after
754
842
  * the removed item are shifted down by one index.
755
843
  *
@@ -1070,4 +1158,4 @@ function Form({ of, onSubmit, ...other }) {
1070
1158
  }
1071
1159
 
1072
1160
  //#endregion
1073
- export { Field, FieldArray, Form, focus, getAllErrors, getErrors, getInput, handleSubmit, insert, move, remove, replace, reset, setErrors, setInput, submit, swap, useField, useFieldArray, useForm, validate };
1161
+ export { Field, FieldArray, Form, focus, getAllErrors, getDirtyInput, getDirtyPaths, getErrors, getInput, handleSubmit, insert, move, pickDirty, remove, replace, reset, setErrors, setInput, submit, swap, useField, useFieldArray, useForm, validate };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@formisch/react",
3
3
  "description": "The lightweight, schema-first, and fully type-safe form library for React",
4
- "version": "0.4.6",
4
+ "version": "0.5.0",
5
5
  "license": "MIT",
6
6
  "author": "Fabian Hiller",
7
7
  "homepage": "https://formisch.dev",
@@ -68,7 +68,7 @@
68
68
  "react": "^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0",
69
69
  "react-dom": "^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0",
70
70
  "typescript": ">=5",
71
- "valibot": "^1.0.0"
71
+ "valibot": "^1.4.1"
72
72
  },
73
73
  "peerDependenciesMeta": {
74
74
  "typescript": {