@conform-to/react 1.11.0 → 1.12.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,4 +1,4 @@
1
- import type { FormError, FormValue, SubmissionResult, ValidationAttributes } from '@conform-to/dom/future';
1
+ import type { 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];
@@ -64,10 +64,10 @@ export type UseFormDataOptions = {
64
64
  */
65
65
  acceptFiles?: boolean;
66
66
  };
67
- export type DefaultValue<FormShape> = FormShape extends string | number | boolean | Date | File | bigint | null | undefined ? FormShape | null | undefined : FormShape extends Array<infer Item> | null | undefined ? Array<DefaultValue<Item>> | null | undefined : FormShape extends Record<string, any> | null | undefined ? {
67
+ export type DefaultValue<FormShape> = FormShape extends Record<string, any> ? {
68
68
  [Key in keyof FormShape]?: DefaultValue<FormShape[Key]>;
69
- } | null | undefined : unknown;
70
- export type FormState<ErrorShape> = {
69
+ } | null | undefined : FormShape extends Array<infer Item> ? Array<DefaultValue<Item>> | null | undefined : FormShape | string | null | undefined;
70
+ export type FormState<ErrorShape extends BaseErrorShape = DefaultErrorShape> = {
71
71
  /** Unique identifier that changes on form reset to trigger reset side effects */
72
72
  resetKey: string;
73
73
  /** Form values from client actions that will be synced to the DOM */
@@ -83,12 +83,41 @@ export type FormState<ErrorShape> = {
83
83
  /** Mapping of array field names to their item keys for React list rendering */
84
84
  listKeys: Record<string, string[]>;
85
85
  };
86
- export type FormAction<ErrorShape, Intent extends UnknownIntent | null | undefined = UnknownIntent | null, Context = {}> = SubmissionResult<ErrorShape> & {
86
+ export type FormAction<ErrorShape extends BaseErrorShape = DefaultErrorShape, Intent extends UnknownIntent | null | undefined = UnknownIntent | null, Context = {}> = SubmissionResult<ErrorShape> & {
87
87
  type: 'initialize' | 'server' | 'client';
88
88
  intent: Intent;
89
89
  ctx: Context;
90
90
  };
91
- export interface FormOptions<FormShape, ErrorShape = string, Value = undefined> {
91
+ export type GlobalFormOptions = {
92
+ /**
93
+ * The name of the submit button field that indicates the submission intent.
94
+ *
95
+ * @default "__intent__"
96
+ */
97
+ intentName: string;
98
+ /**
99
+ * A custom serialization function for converting form data.
100
+ */
101
+ serialize: Serialize;
102
+ /**
103
+ * Determines when validation should run for the first time on a field.
104
+ *
105
+ * @default "onSubmit"
106
+ */
107
+ shouldValidate: 'onSubmit' | 'onBlur' | 'onInput';
108
+ /**
109
+ * Determines when validation should run again after the field has been validated once.
110
+ *
111
+ * @default Same as shouldValidate
112
+ */
113
+ shouldRevalidate?: 'onSubmit' | 'onBlur' | 'onInput';
114
+ /**
115
+ * A function that defines custom metadata properties for form fields.
116
+ * Useful for integrating with UI libraries or custom form components.
117
+ */
118
+ defineCustomMetadata?: CustomMetadataDefinition;
119
+ };
120
+ export type FormOptions<FormShape extends Record<string, any> = Record<string, any>, ErrorShape extends BaseErrorShape = string extends BaseErrorShape ? string : BaseErrorShape, Value = undefined> = {
92
121
  /** Optional form identifier. If not provided, a unique ID is automatically generated. */
93
122
  id?: string;
94
123
  /** Optional key for form state reset. When the key changes, the form resets to its initial state. */
@@ -100,23 +129,21 @@ export interface FormOptions<FormShape, ErrorShape = string, Value = undefined>
100
129
  /** HTML validation attributes for fields (required, minLength, pattern, etc.). */
101
130
  constraint?: Record<string, ValidationAttributes>;
102
131
  /**
103
- * Define when conform should start validation.
104
- * Support "onSubmit", "onInput", "onBlur".
132
+ * Determines when validation should run for the first time on a field.
133
+ * Overrides the global default set by FormOptionsProvider if provided.
105
134
  *
106
- * @default "onSubmit"
135
+ * @default Inherits from FormOptionsProvider, or "onSubmit" if not configured
107
136
  */
108
137
  shouldValidate?: 'onSubmit' | 'onBlur' | 'onInput';
109
138
  /**
110
- * Define when conform should revalidate again.
111
- * Support "onSubmit", "onInput", "onBlur".
139
+ * Determines when validation should run again after the field has been validated once.
140
+ * Overrides the global default set by FormOptionsProvider if provided.
112
141
  *
113
- * @default Same as shouldValidate, or "onSubmit" if shouldValidate is not provided.
142
+ * @default Inherits from FormOptionsProvider, or same as shouldValidate
114
143
  */
115
144
  shouldRevalidate?: 'onSubmit' | 'onBlur' | 'onInput';
116
145
  /** Server-side submission result for form state synchronization. */
117
146
  lastResult?: SubmissionResult<NoInfer<ErrorShape>> | null;
118
- /** Custom validation handler. Can be skipped if using the schema property, or combined with schema to customize validation errors. */
119
- onValidate?: ValidateHandler<ErrorShape, Value>;
120
147
  /** Error handling callback triggered when validation errors occur. By default, it focuses the first invalid field. */
121
148
  onError?: ErrorHandler<ErrorShape>;
122
149
  /** Form submission handler called when the form is submitted with no validation errors. */
@@ -125,14 +152,20 @@ export interface FormOptions<FormShape, ErrorShape = string, Value = undefined>
125
152
  onInput?: InputHandler;
126
153
  /** Blur event handler for custom focus handling logic. */
127
154
  onBlur?: BlurHandler;
128
- }
129
- export interface FormContext<ErrorShape = string> {
155
+ } & (string extends ErrorShape ? {
156
+ /** Custom validation handler. Can be skipped if using the schema property, or combined with schema to customize validation errors. */
157
+ onValidate?: ValidateHandler<ErrorShape, Value>;
158
+ } : {
159
+ /** Custom validation handler. Can be skipped if using the schema property, or combined with schema to customize validation errors. */
160
+ onValidate: ValidateHandler<ErrorShape, Value>;
161
+ });
162
+ export interface FormContext<ErrorShape extends BaseErrorShape = DefaultErrorShape> {
130
163
  /** The form's unique identifier */
131
164
  formId: string;
132
165
  /** Internal form state with validation results and field data */
133
166
  state: FormState<ErrorShape>;
134
167
  /** Initial form values */
135
- defaultValue: NonNullable<DefaultValue<Record<string, any>>> | null;
168
+ defaultValue: Record<string, any> | null;
136
169
  /** HTML validation attributes for fields */
137
170
  constraint: Record<string, ValidationAttributes> | null;
138
171
  /** Form submission event handler */
@@ -174,11 +207,11 @@ export interface IntentDispatcher {
174
207
  /**
175
208
  * Specify the index of the item to update if the field is an array.
176
209
  */
177
- index?: [FieldShape] extends [Array<any> | null | undefined] ? number : never;
210
+ index?: FieldShape extends Array<any> ? number : never;
178
211
  /**
179
212
  * The new value for the field or fieldset.
180
213
  */
181
- value: Partial<FieldShape>;
214
+ value: DefaultValue<FieldShape>;
182
215
  }): void;
183
216
  /**
184
217
  * Insert a new item into an array field.
@@ -196,9 +229,7 @@ export interface IntentDispatcher {
196
229
  /**
197
230
  * The default value for the new item.
198
231
  */
199
- defaultValue?: [FieldShape] extends [
200
- Array<infer ItemShape> | null | undefined
201
- ] ? Partial<ItemShape> : never;
232
+ defaultValue?: FieldShape extends Array<infer ItemShape> ? DefaultValue<ItemShape> : never;
202
233
  }): void;
203
234
  /**
204
235
  * Remove an item from an array field.
@@ -231,7 +262,7 @@ export type FormIntent<Dispatcher extends IntentDispatcher = IntentDispatcher> =
231
262
  export type ActionHandler<Signature extends (payload: any) => void = (payload: any) => void> = {
232
263
  validatePayload?(...args: UnknownArgs<Parameters<Signature>>): boolean;
233
264
  onApply?(value: Record<string, FormValue>, ...args: Parameters<Signature>): Record<string, FormValue> | null;
234
- onUpdate?<ErrorShape>(state: FormState<ErrorShape>, action: FormAction<ErrorShape, {
265
+ onUpdate?<ErrorShape extends BaseErrorShape>(state: FormState<ErrorShape>, action: FormAction<ErrorShape, {
235
266
  type: string;
236
267
  payload: Signature extends (payload: infer Payload) => void ? Payload : undefined;
237
268
  }>): FormState<ErrorShape>;
@@ -240,27 +271,84 @@ type BaseCombine<T, K extends PropertyKey = T extends unknown ? keyof T : never>
240
271
  export type Combine<T> = {
241
272
  [K in keyof BaseCombine<T>]: BaseCombine<T>[K];
242
273
  };
243
- /** Field metadata object containing field state, validation attributes, and nested field access methods. */
244
- export type FieldMetadata<FieldShape, ErrorShape = string> = Readonly<DefaultMetadata<ErrorShape> & {
274
+ /**
275
+ * Extend this interface to define the base error shape for validation.
276
+ *
277
+ * @example
278
+ * ```ts
279
+ * declare module '@conform-to/react/future' {
280
+ * interface CustomTypes {
281
+ * errorShape: { message: string; code: string };
282
+ * }
283
+ * }
284
+ * ```
285
+ */
286
+ export interface CustomTypes {
287
+ }
288
+ export type BaseErrorShape = CustomTypes extends {
289
+ errorShape: infer Shape;
290
+ } ? Shape : unknown;
291
+ export type DefaultErrorShape = CustomTypes extends {
292
+ errorShape: infer Shape;
293
+ } ? Shape : string;
294
+ /** Base field metadata object containing field state, validation attributes, and accessibility IDs. */
295
+ export type BaseMetadata<FieldShape, ErrorShape extends BaseErrorShape> = ValidationAttributes & {
245
296
  /** Unique key for React list rendering (for array fields). */
246
297
  key: string | undefined;
247
298
  /** The field name path exactly as provided. */
248
299
  name: FieldName<FieldShape>;
300
+ /** The field's unique identifier, automatically generated as {formId}-field-{fieldName}. */
301
+ id: string;
302
+ /** Auto-generated ID for associating field descriptions via aria-describedby. */
303
+ descriptionId: string;
304
+ /** Auto-generated ID for associating field errors via aria-describedby. */
305
+ errorId: string;
306
+ /** The form's unique identifier for associating field via the `form` attribute. */
307
+ formId: string;
308
+ /** The field's default value as a string. */
309
+ defaultValue: string | undefined;
310
+ /** Default selected options for multi-select fields or checkbox group. */
311
+ defaultOptions: string[] | undefined;
312
+ /** Default checked state for checkbox/radio inputs. */
313
+ defaultChecked: boolean | undefined;
314
+ /** Whether this field has been touched (through intent.validate() or the shouldValidate option). */
315
+ touched: boolean;
316
+ /** Whether this field currently has no validation errors. */
317
+ valid: boolean;
318
+ /** @deprecated Use `.valid` instead. This was not an intentionl breaking change and would be removed in the next minor version soon */
319
+ invalid: boolean;
320
+ /** Array of validation error messages for this field. */
321
+ errors: ErrorShape[] | undefined;
322
+ /** Object containing errors for all touched subfields. */
323
+ fieldErrors: Record<string, ErrorShape[]>;
324
+ /** Boolean value for the `aria-invalid` attribute. Indicates whether the field has validation errors for screen readers. */
325
+ ariaInvalid: boolean | undefined;
326
+ /** 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}`). */
327
+ ariaDescribedBy: string | undefined;
249
328
  /** Method to get nested fieldset for object fields under this field. */
250
- getFieldset(): Fieldset<[
251
- FieldShape
252
- ] extends [Record<string, unknown> | null | undefined] ? FieldShape : unknown, ErrorShape>;
329
+ getFieldset<FieldsetShape = [FieldShape] extends [
330
+ Record<string, unknown> | null | undefined
331
+ ] ? FieldShape : unknown>(): Fieldset<FieldsetShape, ErrorShape>;
253
332
  /** Method to get array of fields for list/array fields under this field. */
254
- getFieldList(): Array<FieldMetadata<[
255
- FieldShape
256
- ] extends [Array<infer ItemShape> | null | undefined] ? ItemShape : unknown, ErrorShape>>;
257
- }>;
333
+ getFieldList<FieldItemShape = [FieldShape] extends [
334
+ Array<infer ItemShape> | null | undefined
335
+ ] ? ItemShape : unknown>(): Array<FieldMetadata<FieldItemShape, ErrorShape>>;
336
+ };
337
+ export type SatisfyComponentProps<ElementType extends React.ElementType, CustomProps extends React.ComponentPropsWithoutRef<ElementType>> = CustomProps;
338
+ /**
339
+ * Interface for extending field metadata with additional properties.
340
+ */
341
+ export interface CustomMetadata<FieldShape = any, ErrorShape extends BaseErrorShape = DefaultErrorShape> {
342
+ }
343
+ export type CustomMetadataDefinition = <FieldShape, ErrorShape extends BaseErrorShape>(metadata: BaseMetadata<FieldShape, ErrorShape>) => keyof CustomMetadata<FieldShape, ErrorShape> extends never ? {} : CustomMetadata<any, any>;
344
+ /** Field metadata object containing field state, validation attributes, and nested field access methods. */
345
+ export type FieldMetadata<FieldShape, ErrorShape extends BaseErrorShape = DefaultErrorShape> = Readonly<(keyof CustomMetadata<FieldShape, ErrorShape> extends never ? {} : CustomMetadata<FieldShape, ErrorShape>) & BaseMetadata<FieldShape, ErrorShape>>;
258
346
  /** Fieldset object containing all form fields as properties with their respective field metadata. */
259
- export type Fieldset<FieldShape, ErrorShape = string> = {
347
+ export type Fieldset<FieldShape, ErrorShape extends BaseErrorShape = DefaultErrorShape> = {
260
348
  [Key in keyof Combine<FieldShape>]-?: FieldMetadata<Combine<FieldShape>[Key], ErrorShape>;
261
349
  };
262
350
  /** Form-level metadata and state object containing validation status, errors, and field access methods. */
263
- export type FormMetadata<ErrorShape = string> = Readonly<{
351
+ export type FormMetadata<ErrorShape extends BaseErrorShape = DefaultErrorShape> = Readonly<{
264
352
  /** Unique identifier that changes on form reset */
265
353
  key: string;
266
354
  /** The form's unique identifier. */
@@ -300,33 +388,6 @@ export type FormMetadata<ErrorShape = string> = Readonly<{
300
388
  FieldShape
301
389
  ] extends [Array<infer ItemShape> | null | undefined] ? ItemShape : unknown, ErrorShape>>;
302
390
  }>;
303
- /** Default field metadata object containing field state, validation attributes, and accessibility IDs. */
304
- export type DefaultMetadata<ErrorShape> = Readonly<ValidationAttributes & {
305
- /** The field's unique identifier, automatically generated as {formId}-field-{fieldName}. */
306
- id: string;
307
- /** Auto-generated ID for associating field descriptions via aria-describedby. */
308
- descriptionId: string;
309
- /** Auto-generated ID for associating field errors via aria-describedby. */
310
- errorId: string;
311
- /** The form's unique identifier for associating field via the `form` attribute. */
312
- formId: string;
313
- /** The field's default value as a string. */
314
- defaultValue: string | undefined;
315
- /** Default selected options for multi-select fields or checkbox group. */
316
- defaultOptions: string[] | undefined;
317
- /** Default checked state for checkbox/radio inputs. */
318
- defaultChecked: boolean | undefined;
319
- /** Whether this field has been touched (through intent.validate() or the shouldValidate option). */
320
- touched: boolean;
321
- /** Whether this field currently has no validation errors. */
322
- valid: boolean;
323
- /** @deprecated Use `.valid` instead. This was not an intentionl breaking change and would be removed in the next minor version soon */
324
- invalid: boolean;
325
- /** Array of validation error messages for this field. */
326
- errors: ErrorShape[] | undefined;
327
- /** Object containing errors for all touched subfields. */
328
- fieldErrors: Record<string, ErrorShape[]>;
329
- }>;
330
391
  export type ValidateResult<ErrorShape, Value> = FormError<ErrorShape> | null | {
331
392
  error: FormError<ErrorShape> | null;
332
393
  value?: Value;
@@ -385,7 +446,7 @@ export type ErrorContext<ErrorShape> = {
385
446
  export type ErrorHandler<ErrorShape> = (ctx: ErrorContext<ErrorShape>) => void;
386
447
  export type InputHandler = (event: FormInputEvent) => void;
387
448
  export type BlurHandler = (event: FormFocusEvent) => void;
388
- export type SubmitContext<ErrorShape = string, Value = undefined> = {
449
+ export type SubmitContext<ErrorShape extends BaseErrorShape = DefaultErrorShape, Value = undefined> = {
389
450
  formData: FormData;
390
451
  value: Value;
391
452
  update: (options: {
@@ -393,6 +454,6 @@ export type SubmitContext<ErrorShape = string, Value = undefined> = {
393
454
  reset?: boolean;
394
455
  }) => void;
395
456
  };
396
- export type SubmitHandler<ErrorShape = string, Value = undefined> = (event: React.FormEvent<HTMLFormElement>, ctx: SubmitContext<ErrorShape, Value>) => void | Promise<void>;
457
+ export type SubmitHandler<ErrorShape extends BaseErrorShape = DefaultErrorShape, Value = undefined> = (event: React.FormEvent<HTMLFormElement>, ctx: SubmitContext<ErrorShape, Value>) => void | Promise<void>;
397
458
  export {};
398
459
  //# sourceMappingURL=types.d.ts.map
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "description": "Conform view adapter for react",
4
4
  "homepage": "https://conform.guide",
5
5
  "license": "MIT",
6
- "version": "1.11.0",
6
+ "version": "1.12.1",
7
7
  "main": "./dist/index.js",
8
8
  "module": "./dist/index.mjs",
9
9
  "types": "./dist/index.d.ts",
@@ -41,7 +41,7 @@
41
41
  "url": "https://github.com/edmundhung/conform/issues"
42
42
  },
43
43
  "dependencies": {
44
- "@conform-to/dom": "1.11.0"
44
+ "@conform-to/dom": "1.12.1"
45
45
  },
46
46
  "devDependencies": {
47
47
  "@babel/core": "^7.17.8",