@conform-to/react 1.18.0 → 1.19.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.
@@ -1,4 +1,4 @@
1
- import type { FieldName, FormError, FormValue, Serialize, SubmissionResult, ValidationAttributes } from '@conform-to/dom/future';
1
+ import type { CustomSerialize, FieldName, FormError, FormValue, Serialize, SubmissionResult, ValidationAttributes } from '@conform-to/dom/future';
2
2
  import type { StandardSchemaV1 } from './standard-schema';
3
3
  export type Prettify<T> = {
4
4
  [K in keyof T]: T[K];
@@ -111,7 +111,7 @@ export type CustomControlOptions<Value = unknown, DefaultValue = Value> = {
111
111
  * Use this to coerce unknown DOM-derived data into a typed shape.
112
112
  * Any thrown error is surfaced to the caller.
113
113
  */
114
- parse: (payload: unknown) => Value | null | undefined;
114
+ parse: (payload: unknown) => Value | null;
115
115
  /**
116
116
  * Optional serializer to convert the parsed payload back to a form value for populating the base control(s).
117
117
  */
@@ -139,7 +139,7 @@ export type UseFormDataOptions<Value = undefined> = {
139
139
  export type DefaultValue<Shape> = Shape extends Record<string, any> ? {
140
140
  [Key in keyof Shape]?: DefaultValue<Shape[Key]>;
141
141
  } | null | undefined : Shape extends Array<infer Item> ? Array<DefaultValue<Item>> | null | undefined : Shape extends File | File[] ? null | undefined : Shape | string | null | undefined;
142
- export type FormState<ErrorShape extends BaseErrorShape = DefaultErrorShape> = {
142
+ export type FormState<ErrorShape = any> = {
143
143
  /** Unique identifier that changes on form reset to trigger reset side effects */
144
144
  resetKey: string;
145
145
  /** Initial form values */
@@ -157,7 +157,7 @@ export type FormState<ErrorShape extends BaseErrorShape = DefaultErrorShape> = {
157
157
  /** Mapping of array field names to their item keys for React list rendering */
158
158
  listKeys: Record<string, string[]>;
159
159
  };
160
- export type FormAction<ErrorShape extends BaseErrorShape = DefaultErrorShape, Intent extends UnknownIntent | null | undefined = UnknownIntent | null, Context = {}> = SubmissionResult<ErrorShape> & {
160
+ export type FormAction<ErrorShape = any, Intent extends UnknownIntent | null | undefined = UnknownIntent | null, Context = {}> = SubmissionResult<ErrorShape> & {
161
161
  type: 'initialize' | 'server' | 'client';
162
162
  intent: Intent;
163
163
  ctx: Context;
@@ -165,7 +165,7 @@ export type FormAction<ErrorShape extends BaseErrorShape = DefaultErrorShape, In
165
165
  /**
166
166
  * Augment this interface to customize schema type inference for your schema library.
167
167
  *
168
- * @example
168
+ * **Example:**
169
169
  * ```ts
170
170
  * import type { ZodTypeAny, input, output } from 'zod';
171
171
  * import type { ZodSchemaOptions } from '@conform-to/zod/v3/future';
@@ -239,16 +239,16 @@ export type ExtractFieldConditions<T extends Record<string, FieldShapeGuard<any>
239
239
  * Resolved configuration from configureForms factory.
240
240
  * Properties with defaults are required, others remain optional.
241
241
  */
242
- export type FormsConfig<BaseErrorShape, BaseSchema, CustomFormMetadata extends Record<string, unknown>, CustomFieldMetadata extends Record<string, unknown>> = {
242
+ export type FormsConfig<BaseErrorShape, BaseSchema, SchemaErrorShape, CustomFormMetadata extends Record<string, unknown>, CustomFieldMetadata extends Record<string, unknown>> = {
243
243
  /**
244
244
  * The name of the submit button field that indicates the submission intent.
245
245
  * @default "__intent__"
246
246
  */
247
247
  intentName: string;
248
248
  /**
249
- * A custom serialization function for converting form data.
249
+ * A custom serializer for converting form values.
250
250
  */
251
- serialize: Serialize;
251
+ serialize?: CustomSerialize | undefined;
252
252
  /**
253
253
  * Determines when validation should run for the first time on a field.
254
254
  * @default "onSubmit"
@@ -263,7 +263,7 @@ export type FormsConfig<BaseErrorShape, BaseSchema, CustomFormMetadata extends R
263
263
  * Runtime type guard to check if a value is a schema.
264
264
  * Used to determine if the first argument to useForm is a schema or options object.
265
265
  *
266
- * @example
266
+ * **Example:**
267
267
  * ```ts
268
268
  * import { configureForms } from '@conform-to/react/future';
269
269
  * import {
@@ -284,7 +284,7 @@ export type FormsConfig<BaseErrorShape, BaseSchema, CustomFormMetadata extends R
284
284
  * Validates a schema against form payload.
285
285
  */
286
286
  validateSchema: <Schema extends BaseSchema>(schema: Schema, payload: Record<string, FormValue>, options?: InferOptions<Schema>) => MaybePromise<{
287
- error: FormError<string> | null;
287
+ error: FormError<SchemaErrorShape> | null;
288
288
  value?: InferOutput<Schema>;
289
289
  }>;
290
290
  /**
@@ -308,35 +308,6 @@ export type FormsConfig<BaseErrorShape, BaseSchema, CustomFormMetadata extends R
308
308
  when: DefineConditionalField;
309
309
  }) => CustomFieldMetadata;
310
310
  };
311
- export type GlobalFormOptions = {
312
- /**
313
- * The name of the submit button field that indicates the submission intent.
314
- *
315
- * @default "__intent__"
316
- */
317
- intentName: string;
318
- /**
319
- * A custom serialization function for converting form data.
320
- */
321
- serialize: Serialize;
322
- /**
323
- * Determines when validation should run for the first time on a field.
324
- *
325
- * @default "onSubmit"
326
- */
327
- shouldValidate: 'onSubmit' | 'onBlur' | 'onInput';
328
- /**
329
- * Determines when validation should run again after the field has been validated once.
330
- *
331
- * @default Same as shouldValidate
332
- */
333
- shouldRevalidate?: 'onSubmit' | 'onBlur' | 'onInput';
334
- /**
335
- * A function that defines custom metadata properties for form fields.
336
- * Useful for integrating with UI libraries or custom form components.
337
- */
338
- defineCustomMetadata?: CustomMetadataDefinition;
339
- };
340
311
  export type NonPartial<T> = {
341
312
  [K in keyof Required<T>]: T[K];
342
313
  };
@@ -352,6 +323,7 @@ export type BaseSchemaType = StandardSchemaV1<any, any>;
352
323
  export type InferInput<Schema> = Schema extends StandardSchemaV1 ? StandardSchemaV1.InferInput<Schema> : CustomSchemaTypes<Schema> extends {
353
324
  input: infer T;
354
325
  } ? T : Record<string, any>;
326
+ export type InferFormShape<Schema> = InferInput<Schema> extends Record<string, any> ? InferInput<Schema> : Record<string, any>;
355
327
  /**
356
328
  * Infer schema output type.
357
329
  * For StandardSchemaV1 schemas (zod, valibot, etc.), uses StandardSchemaV1.InferOutput.
@@ -360,7 +332,7 @@ export type InferInput<Schema> = Schema extends StandardSchemaV1 ? StandardSchem
360
332
  export type InferOutput<Schema> = Schema extends StandardSchemaV1 ? StandardSchemaV1.InferOutput<Schema> : CustomSchemaTypes<Schema> extends {
361
333
  output: infer T;
362
334
  } ? T : undefined;
363
- export type BaseFormOptions<FormShape extends Record<string, any> = Record<string, any>, ErrorShape extends BaseErrorShape = string extends BaseErrorShape ? string : BaseErrorShape, Value = undefined, Schema = unknown> = {
335
+ export type FormOptions<FormShape extends Record<string, any> = Record<string, any>, ErrorShape = any, Value = undefined, Schema = unknown, SchemaErrorShape = ErrorShape> = {
364
336
  /** Optional form identifier. If not provided, a unique ID is automatically generated. */
365
337
  id?: string | undefined;
366
338
  /** Optional key for form state reset. When the key changes, the form resets to its initial state. */
@@ -371,6 +343,11 @@ export type BaseFormOptions<FormShape extends Record<string, any> = Record<strin
371
343
  onSubmit?: SubmitHandler<FormShape, NoInfer<ErrorShape>, NoInfer<Value>> | undefined;
372
344
  /** Initial form values. Can be a partial object matching your form structure. */
373
345
  defaultValue?: DefaultValue<FormShape> | undefined;
346
+ /**
347
+ * Override serialization for specific fields on this form and delegate the rest
348
+ * to the configured global serializer.
349
+ */
350
+ serialize?: CustomSerialize | undefined;
374
351
  /** HTML validation attributes for fields (required, minLength, pattern, etc.). */
375
352
  constraint?: Record<string, ValidationAttributes> | undefined;
376
353
  /**
@@ -380,16 +357,16 @@ export type BaseFormOptions<FormShape extends Record<string, any> = Record<strin
380
357
  schemaOptions?: InferOptions<Schema>;
381
358
  /**
382
359
  * Determines when validation should run for the first time on a field.
383
- * Overrides the global default set by FormOptionsProvider if provided.
360
+ * Overrides the default configured through `configureForms()` if provided.
384
361
  *
385
- * @default Inherits from FormOptionsProvider, or "onSubmit" if not configured
362
+ * @default Inherits from `configureForms()`, or "onSubmit" if not configured
386
363
  */
387
364
  shouldValidate?: 'onSubmit' | 'onBlur' | 'onInput' | undefined;
388
365
  /**
389
366
  * Determines when validation should run again after the field has been validated once.
390
- * Overrides the global default set by FormOptionsProvider if provided.
367
+ * Overrides the default configured through `configureForms()` if provided.
391
368
  *
392
- * @default Inherits from FormOptionsProvider, or same as shouldValidate
369
+ * @default Inherits from `configureForms()`, or same as shouldValidate
393
370
  */
394
371
  shouldRevalidate?: 'onSubmit' | 'onBlur' | 'onInput' | undefined;
395
372
  /** Error handling callback triggered when validation errors occur. By default, it focuses the first invalid field. */
@@ -398,15 +375,28 @@ export type BaseFormOptions<FormShape extends Record<string, any> = Record<strin
398
375
  onInput?: InputHandler | undefined;
399
376
  /** Blur event handler for custom focus handling logic. */
400
377
  onBlur?: BlurHandler | undefined;
401
- /** Custom validation handler. Can be skipped if using the schema property, or combined with schema to customize validation errors. */
402
- onValidate?: ValidateHandler<ErrorShape, Value, InferOutput<Schema>> | undefined;
378
+ /** Custom validation handler. Can be skipped when a schema is passed as the first argument, or combined with schema validation to customize errors. */
379
+ onValidate?: ValidateHandler<ErrorShape, Value, InferOutput<Schema>, SchemaErrorShape> | undefined;
380
+ };
381
+ /**
382
+ * The object returned by `useForm()`, containing form-level metadata,
383
+ * typed field metadata, and the intent dispatcher for programmatic updates.
384
+ */
385
+ export type FormHandle<FormShape extends Record<string, any>, ErrorShape, CustomFormMetadata extends Record<string, unknown> = {}, CustomFieldMetadata extends Record<string, unknown> = {}> = {
386
+ /** Form-level metadata and helpers. */
387
+ form: FormMetadata<ErrorShape, CustomFormMetadata, CustomFieldMetadata>;
388
+ /** Field metadata mapped from the form shape. */
389
+ fields: Fieldset<FormShape, ErrorShape, CustomFieldMetadata>;
390
+ /** Intent dispatcher for validate, reset, insert, remove, reorder, and update actions. */
391
+ intent: IntentDispatcher<FormShape>;
403
392
  };
404
- export type FormOptions<FormShape extends Record<string, any> = Record<string, any>, ErrorShape extends BaseErrorShape = string extends BaseErrorShape ? string : BaseErrorShape, Value = undefined, Schema = unknown, RequiredKeys extends keyof BaseFormOptions<FormShape, ErrorShape, Value, Schema> = never> = RequireKey<BaseFormOptions<FormShape, ErrorShape, Value, Schema>, RequiredKeys>;
405
- export interface FormContext<ErrorShape extends BaseErrorShape = DefaultErrorShape> {
393
+ export interface FormContext<ErrorShape = any> {
406
394
  /** The form's unique identifier */
407
395
  formId: string;
408
396
  /** Internal form state with validation results and field data */
409
397
  state: FormState<ErrorShape>;
398
+ /** Serializer used to derive field defaults and sync values for this form. */
399
+ serialize: Serialize;
410
400
  /** HTML validation attributes for fields */
411
401
  constraint: Record<string, ValidationAttributes> | null;
412
402
  /** Form submission event handler */
@@ -433,7 +423,7 @@ export interface IntentDispatcher<FormShape extends Record<string, any> = Record
433
423
  *
434
424
  * @param options.defaultValue - The value to reset the form to. Pass `null` to clear all fields, or omit to reset to the initial default value from `useForm`.
435
425
  *
436
- * @example
426
+ * **Example:**
437
427
  * ```tsx
438
428
  * // Reset to initial default value
439
429
  * intent.reset()
@@ -557,8 +547,8 @@ export type FormIntent<Dispatcher extends IntentDispatcher = IntentDispatcher> =
557
547
  export type IntentHandler<Signature extends (payload: any) => void = (payload: any) => void> = {
558
548
  validate?(...args: UnknownArgs<Parameters<Signature>>): boolean;
559
549
  resolve?(value: Record<string, FormValue>, ...args: Parameters<Signature>): Record<string, FormValue> | undefined;
560
- apply?<ErrorShape extends BaseErrorShape>(result: SubmissionResult<ErrorShape>, ...args: Parameters<Signature>): SubmissionResult<ErrorShape>;
561
- update?<ErrorShape extends BaseErrorShape>(state: FormState<ErrorShape>, action: FormAction<ErrorShape, {
550
+ apply?<ErrorShape>(result: SubmissionResult<ErrorShape>, ...args: Parameters<Signature>): SubmissionResult<ErrorShape>;
551
+ update?<ErrorShape>(state: FormState<ErrorShape>, action: FormAction<ErrorShape, {
562
552
  type: string;
563
553
  payload: Signature extends (payload: infer Payload) => void ? Payload : undefined;
564
554
  }, {
@@ -570,36 +560,9 @@ type BaseCombine<T, K extends PropertyKey = T extends unknown ? keyof T : never>
570
560
  export type Combine<T> = {
571
561
  [K in keyof BaseCombine<T>]: BaseCombine<T>[K];
572
562
  };
573
- /**
574
- * Extend this interface to define the base error shape for validation.
575
- *
576
- * @example
577
- * ```ts
578
- * declare module '@conform-to/react/future' {
579
- * interface CustomTypes {
580
- * errorShape: { message: string; code: string };
581
- * }
582
- * }
583
- * ```
584
- */
585
- export interface CustomTypes {
586
- }
587
- export type BaseErrorShape = CustomTypes extends {
588
- errorShape: infer Shape;
589
- } ? Shape : unknown;
590
- export type DefaultErrorShape = CustomTypes extends {
591
- errorShape: infer Shape;
592
- } ? Shape : string;
593
563
  export type SatisfyComponentProps<ElementType extends React.ElementType, CustomProps extends React.ComponentPropsWithoutRef<ElementType>> = CustomProps;
594
- /**
595
- * Interface for extending field metadata with additional properties.
596
- * @deprecated Use `configureForms()` with the `extendFieldMetadata` option for full type inference support.
597
- */
598
- export interface CustomMetadata<FieldShape = any, ErrorShape extends BaseErrorShape = DefaultErrorShape> {
599
- }
600
- export type DefaultCustomMetadata<FieldShape, ErrorShape> = keyof CustomMetadata<FieldShape, ErrorShape> extends never ? {} : CustomMetadata<FieldShape, ErrorShape>;
601
564
  /** Field metadata object containing field state, validation attributes, and nested field access methods. */
602
- export type FieldMetadata<FieldShape, ErrorShape extends BaseErrorShape = DefaultErrorShape, CustomFieldMetadata extends Record<string, unknown> = DefaultCustomMetadata<FieldShape, ErrorShape>> = Readonly<Prettify<ValidationAttributes & {
565
+ export type FieldMetadata<FieldShape, ErrorShape = any, CustomFieldMetadata extends Record<string, unknown> = {}> = Readonly<Prettify<ValidationAttributes & {
603
566
  /** Unique key for React list rendering (for array fields). */
604
567
  key: string | undefined;
605
568
  /** The field name path exactly as provided. */
@@ -647,10 +610,10 @@ export type FieldMetadata<FieldShape, ErrorShape extends BaseErrorShape = Defaul
647
610
  valid: boolean;
648
611
  /** @deprecated Use `.valid` instead. This was not an intentionl breaking change and would be removed in the next minor version soon */
649
612
  invalid: boolean;
650
- /** Array of validation error messages for this field. */
651
- errors: ErrorShape[] | undefined;
652
- /** Object containing errors for all touched subfields. */
653
- fieldErrors: Record<string, ErrorShape[]>;
613
+ /** Validation error for this field. */
614
+ errors: ErrorShape | undefined;
615
+ /** Object containing validation errors for all touched subfields. */
616
+ fieldErrors: Record<string, ErrorShape>;
654
617
  /** Boolean value for the `aria-invalid` attribute. Indicates whether the field has validation errors for screen readers. */
655
618
  ariaInvalid: boolean | undefined;
656
619
  /** String value for the `aria-describedby` attribute. Contains the errorId when invalid, undefined otherwise. Merge with descriptionId manually if needed (e.g. `${metadata.descriptionId} ${metadata.ariaDescribedBy}`). */
@@ -666,21 +629,13 @@ export type FieldMetadata<FieldShape, ErrorShape extends BaseErrorShape = Defaul
666
629
  * Field metadata without custom extensions. This is the type received in `extendFieldMetadata`.
667
630
  * Equivalent to `FieldMetadata<FieldShape, ErrorShape, {}>`.
668
631
  */
669
- export type BaseFieldMetadata<FieldShape, ErrorShape extends BaseErrorShape> = FieldMetadata<FieldShape, ErrorShape, {}>;
670
- /**
671
- * @deprecated Renamed to `BaseFieldMetadata`. This will be removed in the next minor version.
672
- */
673
- export type BaseMetadata<FieldShape, ErrorShape extends BaseErrorShape> = BaseFieldMetadata<FieldShape, ErrorShape>;
674
- /**
675
- * @deprecated Use `configureForms()` with the `extendFieldMetadata` option instead.
676
- */
677
- export type CustomMetadataDefinition = <FieldShape, ErrorShape extends BaseErrorShape>(metadata: BaseFieldMetadata<FieldShape, ErrorShape>) => keyof CustomMetadata<FieldShape, ErrorShape> extends never ? {} : CustomMetadata<any, any>;
632
+ export type BaseFieldMetadata<FieldShape, ErrorShape = any> = FieldMetadata<FieldShape, ErrorShape, {}>;
678
633
  /** Fieldset object containing all form fields as properties with their respective field metadata. */
679
- export type Fieldset<FieldShape, ErrorShape extends BaseErrorShape = DefaultErrorShape, CustomFieldMetadata extends Record<string, unknown> = DefaultCustomMetadata<FieldShape, ErrorShape>> = {
634
+ export type Fieldset<FieldShape, ErrorShape = any, CustomFieldMetadata extends Record<string, unknown> = {}> = {
680
635
  [Key in keyof Combine<FieldShape>]-?: FieldMetadata<Combine<FieldShape>[Key], ErrorShape, CustomFieldMetadata>;
681
636
  };
682
637
  /** Form-level metadata and state object containing validation status, errors, and field access methods. */
683
- export type FormMetadata<ErrorShape extends BaseErrorShape = DefaultErrorShape, CustomFormMetadata extends Record<string, unknown> = {}, CustomFieldMetadata extends Record<string, unknown> = {}> = Readonly<{
638
+ export type FormMetadata<ErrorShape = any, CustomFormMetadata extends Record<string, unknown> = {}, CustomFieldMetadata extends Record<string, unknown> = {}> = Readonly<{
684
639
  /** Unique identifier that changes on form reset */
685
640
  key: string;
686
641
  /** The form's unique identifier. */
@@ -695,10 +650,10 @@ export type FormMetadata<ErrorShape extends BaseErrorShape = DefaultErrorShape,
695
650
  valid: boolean;
696
651
  /** @deprecated Use `.valid` instead. This was not an intentional breaking change and would be removed in the next minor version soon */
697
652
  invalid: boolean;
698
- /** Form-level validation errors, if any exist. */
699
- errors: ErrorShape[] | undefined;
700
- /** Object containing errors for all touched fields. */
701
- fieldErrors: Record<string, ErrorShape[]>;
653
+ /** Form-level validation error, if any exists. */
654
+ errors: ErrorShape | undefined;
655
+ /** Object containing validation errors for all touched fields. */
656
+ fieldErrors: Record<string, ErrorShape>;
702
657
  /** The form's initial default values. */
703
658
  defaultValue: Record<string, unknown>;
704
659
  /** Form props object for spreading onto the <form> element. */
@@ -724,12 +679,12 @@ export type FormMetadata<ErrorShape extends BaseErrorShape = DefaultErrorShape,
724
679
  * Form metadata without custom extensions. This is the type received in `extendFormMetadata`.
725
680
  * Equivalent to `FormMetadata<ErrorShape, {}, CustomFieldMetadata>`.
726
681
  */
727
- export type BaseFormMetadata<ErrorShape extends BaseErrorShape = DefaultErrorShape, CustomFieldMetadata extends Record<string, unknown> = {}> = FormMetadata<ErrorShape, {}, CustomFieldMetadata>;
682
+ export type BaseFormMetadata<ErrorShape = any, CustomFieldMetadata extends Record<string, unknown> = {}> = FormMetadata<ErrorShape, {}, CustomFieldMetadata>;
728
683
  export type ValidateResult<ErrorShape, Value> = FormError<ErrorShape> | null | {
729
684
  error: FormError<ErrorShape> | null;
730
685
  value?: Value;
731
686
  };
732
- export type ValidateContext<SchemaValue> = {
687
+ export type ValidateContext<SchemaValue, SchemaErrorShape> = {
733
688
  /**
734
689
  * The submitted values mapped by field name.
735
690
  * Supports nested names like `user.email` and indexed names like `items[0].id`.
@@ -739,7 +694,7 @@ export type ValidateContext<SchemaValue> = {
739
694
  * Form error object. Initially empty, but populated with schema validation
740
695
  * errors when a schema is provided and validation fails.
741
696
  */
742
- error: FormError<string>;
697
+ error: FormError<SchemaErrorShape>;
743
698
  /**
744
699
  * The submission intent derived from the button that triggered the form submission.
745
700
  */
@@ -762,7 +717,7 @@ export type ValidateContext<SchemaValue> = {
762
717
  */
763
718
  schemaValue: SchemaValue;
764
719
  };
765
- export type ValidateHandler<ErrorShape, Value, SchemaValue = undefined> = (ctx: ValidateContext<SchemaValue>) => ValidateResult<ErrorShape, Value> | Promise<ValidateResult<ErrorShape, Value>> | [
720
+ export type ValidateHandler<ErrorShape, Value, SchemaValue = undefined, SchemaErrorShape = ErrorShape> = (ctx: ValidateContext<SchemaValue, SchemaErrorShape>) => ValidateResult<ErrorShape, Value> | Promise<ValidateResult<ErrorShape, Value>> | [
766
721
  ValidateResult<ErrorShape, Value> | undefined,
767
722
  Promise<ValidateResult<ErrorShape, Value>> | undefined
768
723
  ] | undefined;
@@ -783,7 +738,7 @@ export type ErrorContext<ErrorShape> = {
783
738
  export type ErrorHandler<ErrorShape> = (ctx: ErrorContext<ErrorShape>) => void;
784
739
  export type InputHandler = (event: FormInputEvent) => void;
785
740
  export type BlurHandler = (event: FormFocusEvent) => void;
786
- export type SubmitContext<FormShape extends Record<string, any> = Record<string, any>, ErrorShape extends BaseErrorShape = DefaultErrorShape, Value = undefined> = {
741
+ export type SubmitContext<FormShape extends Record<string, any> = Record<string, any>, ErrorShape = any, Value = undefined> = {
787
742
  formData: FormData;
788
743
  value: Value;
789
744
  update: (options: {
@@ -792,22 +747,22 @@ export type SubmitContext<FormShape extends Record<string, any> = Record<string,
792
747
  reset?: boolean | undefined;
793
748
  }) => void;
794
749
  };
795
- export type SubmitHandler<FormShape extends Record<string, any> = Record<string, any>, ErrorShape extends BaseErrorShape = DefaultErrorShape, Value = undefined> = (event: React.FormEvent<HTMLFormElement>, ctx: SubmitContext<FormShape, ErrorShape, Value>) => void | Promise<void>;
750
+ export type SubmitHandler<FormShape extends Record<string, any> = Record<string, any>, ErrorShape = any, Value = undefined> = (event: React.FormEvent<HTMLFormElement>, ctx: SubmitContext<FormShape, ErrorShape, Value>) => void | Promise<void>;
796
751
  /**
797
752
  * Infer the base error shape from a FormsConfig.
798
753
  *
799
- * @example
754
+ * **Example:**
800
755
  * ```ts
801
756
  * const { config } = configureForms({ isError: shape<{ message: string }>() });
802
757
  * type ErrorShape = InferBaseErrorShape<typeof config>; // { message: string }
803
758
  * ```
804
759
  */
805
- export type InferBaseErrorShape<Config> = Config extends FormsConfig<infer ErrorShape, any, any, any> ? ErrorShape : string;
760
+ export type InferBaseErrorShape<Config> = Config extends FormsConfig<infer ErrorShape, any, any, any, any> ? ErrorShape : string;
806
761
  /**
807
762
  * Infer the custom form metadata extension from a FormsConfig.
808
763
  * Use this to compose with FormMetadata, FieldMetadata, or Fieldset types.
809
764
  *
810
- * @example
765
+ * **Example:**
811
766
  * ```ts
812
767
  * const { config } = configureForms({
813
768
  * extendFormMetadata: (meta) => ({ customProp: meta.id })
@@ -819,12 +774,12 @@ export type InferBaseErrorShape<Config> = Config extends FormsConfig<infer Error
819
774
  * >;
820
775
  * ```
821
776
  */
822
- export type InferCustomFormMetadata<Config> = Config extends FormsConfig<any, any, infer CustomFormMetadata, any> ? CustomFormMetadata : {};
777
+ export type InferCustomFormMetadata<Config> = Config extends FormsConfig<any, any, any, infer CustomFormMetadata, any> ? CustomFormMetadata : {};
823
778
  /**
824
779
  * Infer the custom field metadata extension from a FormsConfig.
825
780
  * Use this to compose with FieldMetadata or Fieldset types.
826
781
  *
827
- * @example
782
+ * **Example:**
828
783
  * ```ts
829
784
  * const { config } = configureForms({
830
785
  * extendFieldMetadata: (meta) => ({ inputProps: { name: meta.name } })
@@ -833,13 +788,13 @@ export type InferCustomFormMetadata<Config> = Config extends FormsConfig<any, an
833
788
  * type MyFieldset<T> = Fieldset<T, InferBaseErrorShape<typeof config>, InferCustomFieldMetadata<typeof config>>;
834
789
  * ```
835
790
  */
836
- export type InferCustomFieldMetadata<Config> = Config extends FormsConfig<any, any, any, infer CustomFieldMetadata> ? CustomFieldMetadata : {};
791
+ export type InferCustomFieldMetadata<Config> = Config extends FormsConfig<any, any, any, any, infer CustomFieldMetadata> ? CustomFieldMetadata : {};
837
792
  /**
838
793
  * Transform a type to make specific keys conditional based on FieldShape.
839
794
  * Keys in ConditionalKeys will only be present when FieldShape extends the specified type.
840
795
  * Uses ConditionalFieldMetadata wrapper that RestoreFieldShape will detect and evaluate.
841
796
  *
842
- * @example
797
+ * **Example:**
843
798
  * ```ts
844
799
  * type Result = MakeConditional<
845
800
  * { textFieldProps: {...}, dateRangePickerProps: {...} },
@@ -1,4 +1,4 @@
1
- import type { FormError } from '@conform-to/dom/future';
1
+ import type { CustomSerialize, FormError, Serialize } from '@conform-to/dom/future';
2
2
  import type { StandardSchemaV1 } from './standard-schema';
3
3
  import { ValidateHandler, ValidateResult, BaseFieldMetadata, ConditionalFieldMetadata } from './types';
4
4
  export declare function isUndefined(value: unknown): value is undefined;
@@ -17,11 +17,7 @@ export declare function updatePathValue<Data>(data: Record<string, Data>, name:
17
17
  * Returns null to remove fields, or updated path with new index.
18
18
  */
19
19
  export declare function createPathIndexUpdater(listName: string, update: (index: number) => number | null): (name: string) => string | null;
20
- /**
21
- * Returns null if error object has no actual error messages,
22
- * otherwise returns the error as-is.
23
- */
24
- export declare function normalizeFormError<ErrorShape>(error: FormError<ErrorShape> | null): FormError<ErrorShape> | null;
20
+ export declare function resolveSerialize(customSerialize: CustomSerialize | undefined, defaultSerialize: Serialize): Serialize;
25
21
  export declare function normalizeValidateResult<ErrorShape, Value>(result: ValidateResult<ErrorShape, Value>): {
26
22
  error: FormError<ErrorShape> | null;
27
23
  value?: Value;
@@ -46,7 +42,7 @@ export declare function resolveValidateResult<ErrorShape, Value>(result: ReturnT
46
42
  * Resolves a StandardSchema validation result to conform's format.
47
43
  */
48
44
  export declare function resolveStandardSchemaResult<Value>(result: StandardSchemaV1.Result<Value>): {
49
- error: FormError<string> | null;
45
+ error: FormError<string[]> | null;
50
46
  value?: Value;
51
47
  };
52
48
  /**
@@ -79,14 +75,14 @@ export declare function generateUniqueKey(): string;
79
75
  * - `isError`: Specify the error shape for type inference
80
76
  * - `when`: Narrow field metadata to specific shapes for conditional props
81
77
  *
82
- * @example Specify error shape
78
+ * **Example: Specify error shape**
83
79
  * ```ts
84
80
  * configureForms({
85
- * isError: shape<string>(), // errors are strings
81
+ * isError: shape<string[]>(), // errors are string arrays
86
82
  * });
87
83
  * ```
88
84
  *
89
- * @example Conditional field metadata
85
+ * **Example: Conditional field metadata**
90
86
  * ```ts
91
87
  * extendFieldMetadata(metadata, { when }) {
92
88
  * return {
@@ -70,29 +70,26 @@ function createPathIndexUpdater(listName, update) {
70
70
  return name;
71
71
  };
72
72
  }
73
-
74
- /**
75
- * Returns null if error object has no actual error messages,
76
- * otherwise returns the error as-is.
77
- */
78
- function normalizeFormError(error) {
79
- if (error && error.formErrors.length === 0 && Object.entries(error.fieldErrors).every(_ref => {
80
- var [, messages] = _ref;
81
- return Array.isArray(messages) ? messages.length === 0 : !messages;
82
- })) {
83
- return null;
73
+ function resolveSerialize(customSerialize, _defaultSerialize) {
74
+ if (typeof customSerialize === 'undefined') {
75
+ return _defaultSerialize;
84
76
  }
85
- return error;
77
+ return function serializeValue(value, context) {
78
+ return customSerialize(value, {
79
+ name: context.name,
80
+ defaultSerialize: value => _defaultSerialize(value, context)
81
+ });
82
+ };
86
83
  }
87
84
  function normalizeValidateResult(result) {
88
85
  if (result !== null && 'error' in result) {
89
86
  return {
90
- error: normalizeFormError(result.error),
87
+ error: future.normalizeFormError(result.error),
91
88
  value: result.value
92
89
  };
93
90
  }
94
91
  return {
95
- error: normalizeFormError(result)
92
+ error: future.normalizeFormError(result)
96
93
  };
97
94
  }
98
95
 
@@ -138,8 +135,8 @@ function resolveStandardSchemaResult(result) {
138
135
  * Create a copy of the object with the updated properties if there is any change
139
136
  */
140
137
  function merge(obj, update) {
141
- if (obj === update || Object.entries(update).every(_ref2 => {
142
- var [key, value] = _ref2;
138
+ if (obj === update || Object.entries(update).every(_ref => {
139
+ var [key, value] = _ref;
143
140
  return obj[key] === value;
144
141
  })) {
145
142
  return obj;
@@ -201,14 +198,14 @@ function generateUniqueKey() {
201
198
  * - `isError`: Specify the error shape for type inference
202
199
  * - `when`: Narrow field metadata to specific shapes for conditional props
203
200
  *
204
- * @example Specify error shape
201
+ * **Example: Specify error shape**
205
202
  * ```ts
206
203
  * configureForms({
207
- * isError: shape<string>(), // errors are strings
204
+ * isError: shape<string[]>(), // errors are string arrays
208
205
  * });
209
206
  * ```
210
207
  *
211
- * @example Conditional field metadata
208
+ * **Example: Conditional field metadata**
212
209
  * ```ts
213
210
  * extendFieldMetadata(metadata, { when }) {
214
211
  * return {
@@ -256,8 +253,8 @@ exports.isStandardSchemaV1 = isStandardSchemaV1;
256
253
  exports.isString = isString;
257
254
  exports.isUndefined = isUndefined;
258
255
  exports.merge = merge;
259
- exports.normalizeFormError = normalizeFormError;
260
256
  exports.normalizeValidateResult = normalizeValidateResult;
257
+ exports.resolveSerialize = resolveSerialize;
261
258
  exports.resolveStandardSchemaResult = resolveStandardSchemaResult;
262
259
  exports.resolveValidateResult = resolveValidateResult;
263
260
  exports.shape = shape;
@@ -1,4 +1,4 @@
1
- import { formatIssues, getPathValue, isPlainObject, setPathValue, parsePath, formatPath } from '@conform-to/dom/future';
1
+ import { formatIssues, normalizeFormError, getPathValue, isPlainObject, setPathValue, parsePath, formatPath } from '@conform-to/dom/future';
2
2
 
3
3
  function isUndefined(value) {
4
4
  return value === undefined;
@@ -66,19 +66,16 @@ function createPathIndexUpdater(listName, update) {
66
66
  return name;
67
67
  };
68
68
  }
69
-
70
- /**
71
- * Returns null if error object has no actual error messages,
72
- * otherwise returns the error as-is.
73
- */
74
- function normalizeFormError(error) {
75
- if (error && error.formErrors.length === 0 && Object.entries(error.fieldErrors).every(_ref => {
76
- var [, messages] = _ref;
77
- return Array.isArray(messages) ? messages.length === 0 : !messages;
78
- })) {
79
- return null;
69
+ function resolveSerialize(customSerialize, _defaultSerialize) {
70
+ if (typeof customSerialize === 'undefined') {
71
+ return _defaultSerialize;
80
72
  }
81
- return error;
73
+ return function serializeValue(value, context) {
74
+ return customSerialize(value, {
75
+ name: context.name,
76
+ defaultSerialize: value => _defaultSerialize(value, context)
77
+ });
78
+ };
82
79
  }
83
80
  function normalizeValidateResult(result) {
84
81
  if (result !== null && 'error' in result) {
@@ -134,8 +131,8 @@ function resolveStandardSchemaResult(result) {
134
131
  * Create a copy of the object with the updated properties if there is any change
135
132
  */
136
133
  function merge(obj, update) {
137
- if (obj === update || Object.entries(update).every(_ref2 => {
138
- var [key, value] = _ref2;
134
+ if (obj === update || Object.entries(update).every(_ref => {
135
+ var [key, value] = _ref;
139
136
  return obj[key] === value;
140
137
  })) {
141
138
  return obj;
@@ -197,14 +194,14 @@ function generateUniqueKey() {
197
194
  * - `isError`: Specify the error shape for type inference
198
195
  * - `when`: Narrow field metadata to specific shapes for conditional props
199
196
  *
200
- * @example Specify error shape
197
+ * **Example: Specify error shape**
201
198
  * ```ts
202
199
  * configureForms({
203
- * isError: shape<string>(), // errors are strings
200
+ * isError: shape<string[]>(), // errors are string arrays
204
201
  * });
205
202
  * ```
206
203
  *
207
- * @example Conditional field metadata
204
+ * **Example: Conditional field metadata**
208
205
  * ```ts
209
206
  * extendFieldMetadata(metadata, { when }) {
210
207
  * return {
@@ -240,4 +237,4 @@ function validateStandardSchemaV1(schema, payload) {
240
237
  return resolveStandardSchemaResult(result);
241
238
  }
242
239
 
243
- export { appendUniqueItem, compactMap, createPathIndexUpdater, generateUniqueKey, getPathArray, isNullable, isNumber, isOptional, isStandardSchemaV1, isString, isUndefined, merge, normalizeFormError, normalizeValidateResult, resolveStandardSchemaResult, resolveValidateResult, shape, transformKeys, updatePathValue, validateStandardSchemaV1, when };
240
+ export { appendUniqueItem, compactMap, createPathIndexUpdater, generateUniqueKey, getPathArray, isNullable, isNumber, isOptional, isStandardSchemaV1, isString, isUndefined, merge, normalizeValidateResult, resolveSerialize, resolveStandardSchemaResult, resolveValidateResult, shape, transformKeys, updatePathValue, validateStandardSchemaV1, when };