@octanejs/tanstack-form 0.0.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.
@@ -0,0 +1,864 @@
1
+ import { createContext, useContext, useMemo } from 'octane';
2
+ import { useForm } from './useForm.tsrx';
3
+ import { useFieldGroup } from './useFieldGroup.tsrx';
4
+ import type {
5
+ AnyFieldApi,
6
+ AnyFormApi,
7
+ BaseFormOptions,
8
+ DeepKeysOfType,
9
+ FieldApi,
10
+ FieldsMap,
11
+ FormAsyncValidateOrFn,
12
+ FormOptions,
13
+ FormValidateOrFn,
14
+ } from '@tanstack/form-core';
15
+ import type { Context } from 'octane';
16
+ import type { FieldComponent } from './useField.tsrx';
17
+ import type { OctaneFormExtendedApi } from './useForm.tsrx';
18
+ import type { AppFieldExtendedOctaneFieldGroupApi } from './useFieldGroup.tsrx';
19
+
20
+ type HookRenderable = unknown;
21
+ type HookPropsWithChildren<P = object> = P & { children?: HookRenderable };
22
+ type HookFunctionComponent<P = object> = (props: P) => HookRenderable;
23
+ type HookComponentType<P = object> = HookFunctionComponent<P>;
24
+
25
+ // We should never hit the `null` case here
26
+ const fieldContext = createContext<AnyFieldApi>(null as never);
27
+ const formContext = createContext<AnyFormApi>(null as never);
28
+
29
+ /**
30
+ * TypeScript inferencing is weird.
31
+ *
32
+ * If you have:
33
+ *
34
+ * @example
35
+ *
36
+ * interface Args<T> {
37
+ * arg?: T
38
+ * }
39
+ *
40
+ * function test<T>(arg?: Partial<Args<T>>): T {
41
+ * return 0 as any;
42
+ * }
43
+ *
44
+ * const a = test({});
45
+ *
46
+ * Then `T` will default to `unknown`.
47
+ *
48
+ * However, if we change `test` to be:
49
+ *
50
+ * @example
51
+ *
52
+ * function test<T extends undefined>(arg?: Partial<Args<T>>): T;
53
+ *
54
+ * Then `T` becomes `undefined`.
55
+ *
56
+ * Here, we are checking if the passed type `T` extends `DefaultT` and **only**
57
+ * `DefaultT`, as if that's the case we assume that inferencing has not occurred.
58
+ */
59
+ type UnwrapOrAny<T> = [unknown] extends [T] ? any : T;
60
+ type UnwrapDefaultOrAny<DefaultT, T> = [DefaultT] extends [T]
61
+ ? [T] extends [DefaultT]
62
+ ? any
63
+ : T
64
+ : T;
65
+
66
+ function useFormContext() {
67
+ const form = useContext(formContext);
68
+
69
+ // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
70
+ if (!form) {
71
+ throw new Error(
72
+ '`formContext` only works when within a `formComponent` passed to `createFormHook`',
73
+ );
74
+ }
75
+
76
+ return form as OctaneFormExtendedApi<
77
+ // If you need access to the form data, you need to use `withForm` instead
78
+ Record<string, never>,
79
+ any,
80
+ any,
81
+ any,
82
+ any,
83
+ any,
84
+ any,
85
+ any,
86
+ any,
87
+ any,
88
+ any,
89
+ any
90
+ >;
91
+ }
92
+
93
+ export function createFormHookContexts() {
94
+ function useFieldContext<TData>() {
95
+ const field = useContext(fieldContext);
96
+
97
+ // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
98
+ if (!field) {
99
+ throw new Error(
100
+ '`fieldContext` only works when within a `fieldComponent` passed to `createFormHook`',
101
+ );
102
+ }
103
+
104
+ return field as FieldApi<
105
+ any,
106
+ string,
107
+ TData,
108
+ any,
109
+ any,
110
+ any,
111
+ any,
112
+ any,
113
+ any,
114
+ any,
115
+ any,
116
+ any,
117
+ any,
118
+ any,
119
+ any,
120
+ any,
121
+ any,
122
+ any,
123
+ any,
124
+ any,
125
+ any,
126
+ any,
127
+ any
128
+ >;
129
+ }
130
+
131
+ return { fieldContext, useFieldContext, useFormContext, formContext };
132
+ }
133
+
134
+ interface CreateFormHookProps<
135
+ TFieldComponents extends Record<string, HookComponentType<any>>,
136
+ TFormComponents extends Record<string, HookComponentType<any>>,
137
+ > {
138
+ fieldComponents: TFieldComponents;
139
+ fieldContext: Context<AnyFieldApi>;
140
+ formComponents: TFormComponents;
141
+ formContext: Context<AnyFormApi>;
142
+ }
143
+
144
+ /**
145
+ * @private
146
+ */
147
+ export type AppFieldExtendedOctaneFormApi<
148
+ TFormData,
149
+ TOnMount extends undefined | FormValidateOrFn<TFormData>,
150
+ TOnChange extends undefined | FormValidateOrFn<TFormData>,
151
+ TOnChangeAsync extends undefined | FormAsyncValidateOrFn<TFormData>,
152
+ TOnBlur extends undefined | FormValidateOrFn<TFormData>,
153
+ TOnBlurAsync extends undefined | FormAsyncValidateOrFn<TFormData>,
154
+ TOnSubmit extends undefined | FormValidateOrFn<TFormData>,
155
+ TOnSubmitAsync extends undefined | FormAsyncValidateOrFn<TFormData>,
156
+ TOnDynamic extends undefined | FormValidateOrFn<TFormData>,
157
+ TOnDynamicAsync extends undefined | FormAsyncValidateOrFn<TFormData>,
158
+ TOnServer extends undefined | FormAsyncValidateOrFn<TFormData>,
159
+ TSubmitMeta,
160
+ TFieldComponents extends Record<string, HookComponentType<any>>,
161
+ TFormComponents extends Record<string, HookComponentType<any>>,
162
+ > = OctaneFormExtendedApi<
163
+ TFormData,
164
+ TOnMount,
165
+ TOnChange,
166
+ TOnChangeAsync,
167
+ TOnBlur,
168
+ TOnBlurAsync,
169
+ TOnSubmit,
170
+ TOnSubmitAsync,
171
+ TOnDynamic,
172
+ TOnDynamicAsync,
173
+ TOnServer,
174
+ TSubmitMeta
175
+ > &
176
+ NoInfer<TFormComponents> & {
177
+ AppField: FieldComponent<
178
+ TFormData,
179
+ TOnMount,
180
+ TOnChange,
181
+ TOnChangeAsync,
182
+ TOnBlur,
183
+ TOnBlurAsync,
184
+ TOnSubmit,
185
+ TOnSubmitAsync,
186
+ TOnDynamic,
187
+ TOnDynamicAsync,
188
+ TOnServer,
189
+ TSubmitMeta,
190
+ NoInfer<TFieldComponents>
191
+ >;
192
+ AppForm: HookComponentType<
193
+ // Keep children optional in the renderer-facing component props.
194
+ HookPropsWithChildren<{}>
195
+ >;
196
+ };
197
+
198
+ export interface WithFormProps<
199
+ TFormData,
200
+ TOnMount extends undefined | FormValidateOrFn<TFormData>,
201
+ TOnChange extends undefined | FormValidateOrFn<TFormData>,
202
+ TOnChangeAsync extends undefined | FormAsyncValidateOrFn<TFormData>,
203
+ TOnBlur extends undefined | FormValidateOrFn<TFormData>,
204
+ TOnBlurAsync extends undefined | FormAsyncValidateOrFn<TFormData>,
205
+ TOnSubmit extends undefined | FormValidateOrFn<TFormData>,
206
+ TOnSubmitAsync extends undefined | FormAsyncValidateOrFn<TFormData>,
207
+ TOnDynamic extends undefined | FormValidateOrFn<TFormData>,
208
+ TOnDynamicAsync extends undefined | FormAsyncValidateOrFn<TFormData>,
209
+ TOnServer extends undefined | FormAsyncValidateOrFn<TFormData>,
210
+ TSubmitMeta,
211
+ TFieldComponents extends Record<string, HookComponentType<any>>,
212
+ TFormComponents extends Record<string, HookComponentType<any>>,
213
+ TRenderProps extends object = Record<string, never>,
214
+ > extends FormOptions<
215
+ TFormData,
216
+ TOnMount,
217
+ TOnChange,
218
+ TOnChangeAsync,
219
+ TOnBlur,
220
+ TOnBlurAsync,
221
+ TOnSubmit,
222
+ TOnSubmitAsync,
223
+ TOnDynamic,
224
+ TOnDynamicAsync,
225
+ TOnServer,
226
+ TSubmitMeta
227
+ > {
228
+ // Optional, but adds props to the `render` function outside of `form`
229
+ props?: TRenderProps;
230
+ render: HookFunctionComponent<
231
+ HookPropsWithChildren<
232
+ NoInfer<TRenderProps> & {
233
+ form: AppFieldExtendedOctaneFormApi<
234
+ TFormData,
235
+ TOnMount,
236
+ TOnChange,
237
+ TOnChangeAsync,
238
+ TOnBlur,
239
+ TOnBlurAsync,
240
+ TOnSubmit,
241
+ TOnSubmitAsync,
242
+ TOnDynamic,
243
+ TOnDynamicAsync,
244
+ TOnServer,
245
+ TSubmitMeta,
246
+ TFieldComponents,
247
+ TFormComponents
248
+ >;
249
+ }
250
+ >
251
+ >;
252
+ }
253
+
254
+ export interface WithFieldGroupProps<
255
+ TFieldGroupData,
256
+ TFieldComponents extends Record<string, HookComponentType<any>>,
257
+ TFormComponents extends Record<string, HookComponentType<any>>,
258
+ TSubmitMeta,
259
+ TRenderProps extends object = Record<string, never>,
260
+ > extends BaseFormOptions<TFieldGroupData, TSubmitMeta> {
261
+ // Optional, but adds props to the `render` function outside of `form`
262
+ props?: TRenderProps;
263
+ render: HookFunctionComponent<
264
+ HookPropsWithChildren<
265
+ NoInfer<TRenderProps> & {
266
+ group: AppFieldExtendedOctaneFieldGroupApi<
267
+ unknown,
268
+ TFieldGroupData,
269
+ string | FieldsMap<unknown, TFieldGroupData>,
270
+ undefined | FormValidateOrFn<unknown>,
271
+ undefined | FormValidateOrFn<unknown>,
272
+ undefined | FormAsyncValidateOrFn<unknown>,
273
+ undefined | FormValidateOrFn<unknown>,
274
+ undefined | FormAsyncValidateOrFn<unknown>,
275
+ undefined | FormValidateOrFn<unknown>,
276
+ undefined | FormAsyncValidateOrFn<unknown>,
277
+ undefined | FormValidateOrFn<unknown>,
278
+ undefined | FormAsyncValidateOrFn<unknown>,
279
+ undefined | FormAsyncValidateOrFn<unknown>,
280
+ // this types it as 'never' in the render prop. It should prevent any
281
+ // untyped meta passed to the handleSubmit by accident.
282
+ unknown extends TSubmitMeta ? never : TSubmitMeta,
283
+ TFieldComponents,
284
+ TFormComponents
285
+ >;
286
+ }
287
+ >
288
+ >;
289
+ }
290
+
291
+ type UseAppForm<
292
+ TComponents extends Record<string, HookComponentType<any>>,
293
+ TFormComponents extends Record<string, HookComponentType<any>>,
294
+ > = <
295
+ TFormData,
296
+ TOnMount extends undefined | FormValidateOrFn<TFormData>,
297
+ TOnChange extends undefined | FormValidateOrFn<TFormData>,
298
+ TOnChangeAsync extends undefined | FormAsyncValidateOrFn<TFormData>,
299
+ TOnBlur extends undefined | FormValidateOrFn<TFormData>,
300
+ TOnBlurAsync extends undefined | FormAsyncValidateOrFn<TFormData>,
301
+ TOnSubmit extends undefined | FormValidateOrFn<TFormData>,
302
+ TOnSubmitAsync extends undefined | FormAsyncValidateOrFn<TFormData>,
303
+ TOnDynamic extends undefined | FormValidateOrFn<TFormData>,
304
+ TOnDynamicAsync extends undefined | FormAsyncValidateOrFn<TFormData>,
305
+ TOnServer extends undefined | FormAsyncValidateOrFn<TFormData>,
306
+ TSubmitMeta,
307
+ >(
308
+ props: FormOptions<
309
+ TFormData,
310
+ TOnMount,
311
+ TOnChange,
312
+ TOnChangeAsync,
313
+ TOnBlur,
314
+ TOnBlurAsync,
315
+ TOnSubmit,
316
+ TOnSubmitAsync,
317
+ TOnDynamic,
318
+ TOnDynamicAsync,
319
+ TOnServer,
320
+ TSubmitMeta
321
+ >,
322
+ ) => AppFieldExtendedOctaneFormApi<
323
+ TFormData,
324
+ TOnMount,
325
+ TOnChange,
326
+ TOnChangeAsync,
327
+ TOnBlur,
328
+ TOnBlurAsync,
329
+ TOnSubmit,
330
+ TOnSubmitAsync,
331
+ TOnDynamic,
332
+ TOnDynamicAsync,
333
+ TOnServer,
334
+ TSubmitMeta,
335
+ TComponents,
336
+ TFormComponents
337
+ >;
338
+
339
+ type WithForm<
340
+ TComponents extends Record<string, HookComponentType<any>>,
341
+ TFormComponents extends Record<string, HookComponentType<any>>,
342
+ > = <
343
+ TFormData,
344
+ TOnMount extends undefined | FormValidateOrFn<TFormData>,
345
+ TOnChange extends undefined | FormValidateOrFn<TFormData>,
346
+ TOnChangeAsync extends undefined | FormAsyncValidateOrFn<TFormData>,
347
+ TOnBlur extends undefined | FormValidateOrFn<TFormData>,
348
+ TOnBlurAsync extends undefined | FormAsyncValidateOrFn<TFormData>,
349
+ TOnSubmit extends undefined | FormValidateOrFn<TFormData>,
350
+ TOnSubmitAsync extends undefined | FormAsyncValidateOrFn<TFormData>,
351
+ TOnDynamic extends undefined | FormValidateOrFn<TFormData>,
352
+ TOnDynamicAsync extends undefined | FormAsyncValidateOrFn<TFormData>,
353
+ TOnServer extends undefined | FormAsyncValidateOrFn<TFormData>,
354
+ TSubmitMeta,
355
+ TRenderProps extends object = {},
356
+ >(
357
+ props: WithFormProps<
358
+ TFormData,
359
+ TOnMount,
360
+ TOnChange,
361
+ TOnChangeAsync,
362
+ TOnBlur,
363
+ TOnBlurAsync,
364
+ TOnSubmit,
365
+ TOnSubmitAsync,
366
+ TOnDynamic,
367
+ TOnDynamicAsync,
368
+ TOnServer,
369
+ TSubmitMeta,
370
+ TComponents,
371
+ TFormComponents,
372
+ TRenderProps
373
+ >,
374
+ ) => WithFormProps<
375
+ UnwrapOrAny<TFormData>,
376
+ UnwrapDefaultOrAny<undefined | FormValidateOrFn<TFormData>, TOnMount>,
377
+ UnwrapDefaultOrAny<undefined | FormValidateOrFn<TFormData>, TOnChange>,
378
+ UnwrapDefaultOrAny<undefined | FormValidateOrFn<TFormData>, TOnChangeAsync>,
379
+ UnwrapDefaultOrAny<undefined | FormValidateOrFn<TFormData>, TOnBlur>,
380
+ UnwrapDefaultOrAny<undefined | FormValidateOrFn<TFormData>, TOnBlurAsync>,
381
+ UnwrapDefaultOrAny<undefined | FormValidateOrFn<TFormData>, TOnSubmit>,
382
+ UnwrapDefaultOrAny<undefined | FormValidateOrFn<TFormData>, TOnSubmitAsync>,
383
+ UnwrapDefaultOrAny<undefined | FormValidateOrFn<TFormData>, TOnDynamic>,
384
+ UnwrapDefaultOrAny<undefined | FormValidateOrFn<TFormData>, TOnDynamicAsync>,
385
+ UnwrapDefaultOrAny<undefined | FormValidateOrFn<TFormData>, TOnServer>,
386
+ UnwrapOrAny<TSubmitMeta>,
387
+ UnwrapOrAny<TComponents>,
388
+ UnwrapOrAny<TFormComponents>,
389
+ UnwrapOrAny<TRenderProps>
390
+ >['render'];
391
+
392
+ type WithFieldGroup<
393
+ TComponents extends Record<string, HookComponentType<any>>,
394
+ TFormComponents extends Record<string, HookComponentType<any>>,
395
+ > = <TFieldGroupData, TSubmitMeta, TRenderProps extends object = {}>(
396
+ props: WithFieldGroupProps<
397
+ TFieldGroupData,
398
+ TComponents,
399
+ TFormComponents,
400
+ TSubmitMeta,
401
+ TRenderProps
402
+ >,
403
+ ) => <
404
+ TFormData,
405
+ TFields extends
406
+ | DeepKeysOfType<TFormData, TFieldGroupData | null | undefined>
407
+ | FieldsMap<TFormData, TFieldGroupData>,
408
+ TOnMount extends undefined | FormValidateOrFn<TFormData>,
409
+ TOnChange extends undefined | FormValidateOrFn<TFormData>,
410
+ TOnChangeAsync extends undefined | FormAsyncValidateOrFn<TFormData>,
411
+ TOnBlur extends undefined | FormValidateOrFn<TFormData>,
412
+ TOnBlurAsync extends undefined | FormAsyncValidateOrFn<TFormData>,
413
+ TOnSubmit extends undefined | FormValidateOrFn<TFormData>,
414
+ TOnSubmitAsync extends undefined | FormAsyncValidateOrFn<TFormData>,
415
+ TOnDynamic extends undefined | FormValidateOrFn<TFormData>,
416
+ TOnDynamicAsync extends undefined | FormAsyncValidateOrFn<TFormData>,
417
+ TOnServer extends undefined | FormAsyncValidateOrFn<TFormData>,
418
+ TFormSubmitMeta,
419
+ >(
420
+ params: HookPropsWithChildren<
421
+ NoInfer<TRenderProps> & {
422
+ form:
423
+ | AppFieldExtendedOctaneFormApi<
424
+ TFormData,
425
+ TOnMount,
426
+ TOnChange,
427
+ TOnChangeAsync,
428
+ TOnBlur,
429
+ TOnBlurAsync,
430
+ TOnSubmit,
431
+ TOnSubmitAsync,
432
+ TOnDynamic,
433
+ TOnDynamicAsync,
434
+ TOnServer,
435
+ unknown extends TSubmitMeta ? TFormSubmitMeta : TSubmitMeta,
436
+ TComponents,
437
+ TFormComponents
438
+ >
439
+ | AppFieldExtendedOctaneFieldGroupApi<
440
+ unknown,
441
+ TFormData,
442
+ string | FieldsMap<unknown, TFormData>,
443
+ any,
444
+ any,
445
+ any,
446
+ any,
447
+ any,
448
+ any,
449
+ any,
450
+ any,
451
+ any,
452
+ any,
453
+ unknown extends TSubmitMeta ? TFormSubmitMeta : TSubmitMeta,
454
+ TComponents,
455
+ TFormComponents
456
+ >;
457
+ fields: TFields;
458
+ }
459
+ >,
460
+ ) => ReturnType<HookFunctionComponent>;
461
+
462
+ type UseTypedAppFormContext<
463
+ TComponents extends Record<string, HookComponentType<any>>,
464
+ TFormComponents extends Record<string, HookComponentType<any>>,
465
+ > = <
466
+ TFormData,
467
+ TOnMount extends undefined | FormValidateOrFn<TFormData>,
468
+ TOnChange extends undefined | FormValidateOrFn<TFormData>,
469
+ TOnChangeAsync extends undefined | FormAsyncValidateOrFn<TFormData>,
470
+ TOnBlur extends undefined | FormValidateOrFn<TFormData>,
471
+ TOnBlurAsync extends undefined | FormAsyncValidateOrFn<TFormData>,
472
+ TOnSubmit extends undefined | FormValidateOrFn<TFormData>,
473
+ TOnSubmitAsync extends undefined | FormAsyncValidateOrFn<TFormData>,
474
+ TOnDynamic extends undefined | FormValidateOrFn<TFormData>,
475
+ TOnDynamicAsync extends undefined | FormAsyncValidateOrFn<TFormData>,
476
+ TOnServer extends undefined | FormAsyncValidateOrFn<TFormData>,
477
+ TSubmitMeta,
478
+ >(
479
+ props: FormOptions<
480
+ TFormData,
481
+ TOnMount,
482
+ TOnChange,
483
+ TOnChangeAsync,
484
+ TOnBlur,
485
+ TOnBlurAsync,
486
+ TOnSubmit,
487
+ TOnSubmitAsync,
488
+ TOnDynamic,
489
+ TOnDynamicAsync,
490
+ TOnServer,
491
+ TSubmitMeta
492
+ >,
493
+ ) => AppFieldExtendedOctaneFormApi<
494
+ TFormData,
495
+ TOnMount,
496
+ TOnChange,
497
+ TOnChangeAsync,
498
+ TOnBlur,
499
+ TOnBlurAsync,
500
+ TOnSubmit,
501
+ TOnSubmitAsync,
502
+ TOnDynamic,
503
+ TOnDynamicAsync,
504
+ TOnServer,
505
+ TSubmitMeta,
506
+ TComponents,
507
+ TFormComponents
508
+ >;
509
+
510
+ type FieldComponentExtension<TComponents extends Record<string, HookComponentType<any>>> =
511
+ Record<string, HookComponentType<any>> & {
512
+ [K in keyof TComponents]?: 'Error: field component names must be unique — this key already exists in the base form';
513
+ };
514
+
515
+ type FormComponentExtension<TComponents extends Record<string, HookComponentType<any>>> =
516
+ Record<string, HookComponentType<any>> & {
517
+ [K in keyof TComponents]?: 'Error: form component names must be unique — this key already exists in the base form';
518
+ };
519
+
520
+ export interface CreateFormHookReturn<
521
+ TComponents extends Record<string, HookComponentType<any>>,
522
+ TFormComponents extends Record<string, HookComponentType<any>>,
523
+ > {
524
+ useAppForm: UseAppForm<TComponents, TFormComponents>;
525
+ withForm: WithForm<TComponents, TFormComponents>;
526
+ withFieldGroup: WithFieldGroup<TComponents, TFormComponents>;
527
+ useTypedAppFormContext: UseTypedAppFormContext<TComponents, TFormComponents>;
528
+ extendForm: <
529
+ TNewField extends FieldComponentExtension<TComponents>,
530
+ TNewForm extends FormComponentExtension<TFormComponents>,
531
+ >(extension: {
532
+ fieldComponents?: TNewField;
533
+ formComponents?: TNewForm;
534
+ }) => CreateFormHookReturn<TComponents & TNewField, TFormComponents & TNewForm>;
535
+ }
536
+
537
+ export function createFormHook<
538
+ TComponents extends Record<string, HookComponentType<any>>,
539
+ TFormComponents extends Record<string, HookComponentType<any>>,
540
+ >({
541
+ fieldComponents,
542
+ fieldContext,
543
+ formContext,
544
+ formComponents,
545
+ }: CreateFormHookProps<TComponents, TFormComponents>): CreateFormHookReturn<
546
+ TComponents,
547
+ TFormComponents
548
+ > {
549
+ function useAppForm<
550
+ TFormData,
551
+ TOnMount extends undefined | FormValidateOrFn<TFormData>,
552
+ TOnChange extends undefined | FormValidateOrFn<TFormData>,
553
+ TOnChangeAsync extends undefined | FormAsyncValidateOrFn<TFormData>,
554
+ TOnBlur extends undefined | FormValidateOrFn<TFormData>,
555
+ TOnBlurAsync extends undefined | FormAsyncValidateOrFn<TFormData>,
556
+ TOnSubmit extends undefined | FormValidateOrFn<TFormData>,
557
+ TOnSubmitAsync extends undefined | FormAsyncValidateOrFn<TFormData>,
558
+ TOnDynamic extends undefined | FormValidateOrFn<TFormData>,
559
+ TOnDynamicAsync extends undefined | FormAsyncValidateOrFn<TFormData>,
560
+ TOnServer extends undefined | FormAsyncValidateOrFn<TFormData>,
561
+ TSubmitMeta,
562
+ >(
563
+ props: FormOptions<
564
+ TFormData,
565
+ TOnMount,
566
+ TOnChange,
567
+ TOnChangeAsync,
568
+ TOnBlur,
569
+ TOnBlurAsync,
570
+ TOnSubmit,
571
+ TOnSubmitAsync,
572
+ TOnDynamic,
573
+ TOnDynamicAsync,
574
+ TOnServer,
575
+ TSubmitMeta
576
+ >,
577
+ ): AppFieldExtendedOctaneFormApi<
578
+ TFormData,
579
+ TOnMount,
580
+ TOnChange,
581
+ TOnChangeAsync,
582
+ TOnBlur,
583
+ TOnBlurAsync,
584
+ TOnSubmit,
585
+ TOnSubmitAsync,
586
+ TOnDynamic,
587
+ TOnDynamicAsync,
588
+ TOnServer,
589
+ TSubmitMeta,
590
+ TComponents,
591
+ TFormComponents
592
+ > {
593
+ const form = useForm(props);
594
+
595
+ // Keep children optional in the renderer-facing component props.
596
+ const AppForm = useMemo<HookComponentType<HookPropsWithChildren<{}>>>(() => {
597
+ return ({ children }) => {
598
+ return <formContext.Provider value={form}>{children}</formContext.Provider>;
599
+ };
600
+ }, [form]);
601
+
602
+ const AppField = useMemo(() => {
603
+ const AppField = (({ children, ...props }) => {
604
+ return (
605
+ <form.Field {...props}>
606
+ {(field) => (
607
+ <fieldContext.Provider value={field}>
608
+ {children(Object.assign(field, fieldComponents))}
609
+ </fieldContext.Provider>
610
+ )}
611
+ </form.Field>
612
+ );
613
+ }) as FieldComponent<
614
+ TFormData,
615
+ TOnMount,
616
+ TOnChange,
617
+ TOnChangeAsync,
618
+ TOnBlur,
619
+ TOnBlurAsync,
620
+ TOnSubmit,
621
+ TOnSubmitAsync,
622
+ TOnDynamic,
623
+ TOnDynamicAsync,
624
+ TOnServer,
625
+ TSubmitMeta,
626
+ TComponents
627
+ >;
628
+ return AppField;
629
+ }, [form]);
630
+
631
+ const extendedForm = useMemo(() => {
632
+ return Object.assign(form, {
633
+ AppField,
634
+ AppForm,
635
+ ...formComponents,
636
+ });
637
+ }, [form, AppField, AppForm]);
638
+
639
+ return extendedForm;
640
+ }
641
+
642
+ function withForm<
643
+ TFormData,
644
+ TOnMount extends undefined | FormValidateOrFn<TFormData>,
645
+ TOnChange extends undefined | FormValidateOrFn<TFormData>,
646
+ TOnChangeAsync extends undefined | FormAsyncValidateOrFn<TFormData>,
647
+ TOnBlur extends undefined | FormValidateOrFn<TFormData>,
648
+ TOnBlurAsync extends undefined | FormAsyncValidateOrFn<TFormData>,
649
+ TOnSubmit extends undefined | FormValidateOrFn<TFormData>,
650
+ TOnSubmitAsync extends undefined | FormAsyncValidateOrFn<TFormData>,
651
+ TOnDynamic extends undefined | FormValidateOrFn<TFormData>,
652
+ TOnDynamicAsync extends undefined | FormAsyncValidateOrFn<TFormData>,
653
+ TOnServer extends undefined | FormAsyncValidateOrFn<TFormData>,
654
+ TSubmitMeta,
655
+ TRenderProps extends object = {},
656
+ >({
657
+ render,
658
+ props,
659
+ }: WithFormProps<
660
+ TFormData,
661
+ TOnMount,
662
+ TOnChange,
663
+ TOnChangeAsync,
664
+ TOnBlur,
665
+ TOnBlurAsync,
666
+ TOnSubmit,
667
+ TOnSubmitAsync,
668
+ TOnDynamic,
669
+ TOnDynamicAsync,
670
+ TOnServer,
671
+ TSubmitMeta,
672
+ TComponents,
673
+ TFormComponents,
674
+ TRenderProps
675
+ >): WithFormProps<
676
+ UnwrapOrAny<TFormData>,
677
+ UnwrapDefaultOrAny<undefined | FormValidateOrFn<TFormData>, TOnMount>,
678
+ UnwrapDefaultOrAny<undefined | FormValidateOrFn<TFormData>, TOnChange>,
679
+ UnwrapDefaultOrAny<undefined | FormValidateOrFn<TFormData>, TOnChangeAsync>,
680
+ UnwrapDefaultOrAny<undefined | FormValidateOrFn<TFormData>, TOnBlur>,
681
+ UnwrapDefaultOrAny<undefined | FormValidateOrFn<TFormData>, TOnBlurAsync>,
682
+ UnwrapDefaultOrAny<undefined | FormValidateOrFn<TFormData>, TOnSubmit>,
683
+ UnwrapDefaultOrAny<undefined | FormValidateOrFn<TFormData>, TOnSubmitAsync>,
684
+ UnwrapDefaultOrAny<undefined | FormValidateOrFn<TFormData>, TOnDynamic>,
685
+ UnwrapDefaultOrAny<undefined | FormValidateOrFn<TFormData>, TOnDynamicAsync>,
686
+ UnwrapDefaultOrAny<undefined | FormValidateOrFn<TFormData>, TOnServer>,
687
+ UnwrapOrAny<TSubmitMeta>,
688
+ UnwrapOrAny<TComponents>,
689
+ UnwrapOrAny<TFormComponents>,
690
+ UnwrapOrAny<TRenderProps>
691
+ >['render'] {
692
+ return function Render(innerProps) {
693
+ return render({ ...props, ...innerProps });
694
+ };
695
+ }
696
+
697
+ function withFieldGroup<TFieldGroupData, TSubmitMeta, TRenderProps extends object = {}>({
698
+ render,
699
+ props,
700
+ defaultValues,
701
+ }: WithFieldGroupProps<
702
+ TFieldGroupData,
703
+ TComponents,
704
+ TFormComponents,
705
+ TSubmitMeta,
706
+ TRenderProps
707
+ >): <
708
+ TFormData,
709
+ TFields extends
710
+ | DeepKeysOfType<TFormData, TFieldGroupData | null | undefined>
711
+ | FieldsMap<TFormData, TFieldGroupData>,
712
+ TOnMount extends undefined | FormValidateOrFn<TFormData>,
713
+ TOnChange extends undefined | FormValidateOrFn<TFormData>,
714
+ TOnChangeAsync extends undefined | FormAsyncValidateOrFn<TFormData>,
715
+ TOnBlur extends undefined | FormValidateOrFn<TFormData>,
716
+ TOnBlurAsync extends undefined | FormAsyncValidateOrFn<TFormData>,
717
+ TOnSubmit extends undefined | FormValidateOrFn<TFormData>,
718
+ TOnSubmitAsync extends undefined | FormAsyncValidateOrFn<TFormData>,
719
+ TOnDynamic extends undefined | FormValidateOrFn<TFormData>,
720
+ TOnDynamicAsync extends undefined | FormAsyncValidateOrFn<TFormData>,
721
+ TOnServer extends undefined | FormAsyncValidateOrFn<TFormData>,
722
+ TFormSubmitMeta,
723
+ >(
724
+ params: HookPropsWithChildren<
725
+ NoInfer<TRenderProps> & {
726
+ form:
727
+ | AppFieldExtendedOctaneFormApi<
728
+ TFormData,
729
+ TOnMount,
730
+ TOnChange,
731
+ TOnChangeAsync,
732
+ TOnBlur,
733
+ TOnBlurAsync,
734
+ TOnSubmit,
735
+ TOnSubmitAsync,
736
+ TOnDynamic,
737
+ TOnDynamicAsync,
738
+ TOnServer,
739
+ unknown extends TSubmitMeta ? TFormSubmitMeta : TSubmitMeta,
740
+ TComponents,
741
+ TFormComponents
742
+ >
743
+ | AppFieldExtendedOctaneFieldGroupApi<
744
+ // Since this only occurs if you nest it within other field groups, it can be more
745
+ // lenient with the types.
746
+ unknown,
747
+ TFormData,
748
+ string | FieldsMap<unknown, TFormData>,
749
+ any,
750
+ any,
751
+ any,
752
+ any,
753
+ any,
754
+ any,
755
+ any,
756
+ any,
757
+ any,
758
+ any,
759
+ unknown extends TSubmitMeta ? TFormSubmitMeta : TSubmitMeta,
760
+ TComponents,
761
+ TFormComponents
762
+ >;
763
+ fields: TFields;
764
+ }
765
+ >,
766
+ ) => ReturnType<HookFunctionComponent> {
767
+ return function Render(innerProps) {
768
+ const fieldGroupProps = useMemo(() => {
769
+ return {
770
+ form: innerProps.form,
771
+ fields: innerProps.fields,
772
+ defaultValues,
773
+ formComponents,
774
+ };
775
+ }, [innerProps.form, innerProps.fields]);
776
+ const fieldGroupApi = useFieldGroup(fieldGroupProps as any);
777
+
778
+ return render({ ...props, ...innerProps, group: fieldGroupApi as any });
779
+ };
780
+ }
781
+
782
+ /**
783
+ * ⚠️ **Use withForm whenever possible.**
784
+ *
785
+ * Gets a typed form from the `<form.AppForm />` context.
786
+ */
787
+ function useTypedAppFormContext<
788
+ TFormData,
789
+ TOnMount extends undefined | FormValidateOrFn<TFormData>,
790
+ TOnChange extends undefined | FormValidateOrFn<TFormData>,
791
+ TOnChangeAsync extends undefined | FormAsyncValidateOrFn<TFormData>,
792
+ TOnBlur extends undefined | FormValidateOrFn<TFormData>,
793
+ TOnBlurAsync extends undefined | FormAsyncValidateOrFn<TFormData>,
794
+ TOnSubmit extends undefined | FormValidateOrFn<TFormData>,
795
+ TOnSubmitAsync extends undefined | FormAsyncValidateOrFn<TFormData>,
796
+ TOnDynamic extends undefined | FormValidateOrFn<TFormData>,
797
+ TOnDynamicAsync extends undefined | FormAsyncValidateOrFn<TFormData>,
798
+ TOnServer extends undefined | FormAsyncValidateOrFn<TFormData>,
799
+ TSubmitMeta,
800
+ >(
801
+ _props: FormOptions<
802
+ TFormData,
803
+ TOnMount,
804
+ TOnChange,
805
+ TOnChangeAsync,
806
+ TOnBlur,
807
+ TOnBlurAsync,
808
+ TOnSubmit,
809
+ TOnSubmitAsync,
810
+ TOnDynamic,
811
+ TOnDynamicAsync,
812
+ TOnServer,
813
+ TSubmitMeta
814
+ >,
815
+ ): AppFieldExtendedOctaneFormApi<
816
+ TFormData,
817
+ TOnMount,
818
+ TOnChange,
819
+ TOnChangeAsync,
820
+ TOnBlur,
821
+ TOnBlurAsync,
822
+ TOnSubmit,
823
+ TOnSubmitAsync,
824
+ TOnDynamic,
825
+ TOnDynamicAsync,
826
+ TOnServer,
827
+ TSubmitMeta,
828
+ TComponents,
829
+ TFormComponents
830
+ > {
831
+ const form = useFormContext();
832
+
833
+ return form as never;
834
+ }
835
+
836
+ function extendForm<
837
+ TNewField extends FieldComponentExtension<TComponents>,
838
+ TNewForm extends FormComponentExtension<TFormComponents>,
839
+ >(extension: {
840
+ fieldComponents?: TNewField;
841
+ formComponents?: TNewForm;
842
+ }): CreateFormHookReturn<TComponents & TNewField, TFormComponents & TNewForm> {
843
+ return createFormHook({
844
+ fieldContext,
845
+ formContext,
846
+ fieldComponents: {
847
+ ...fieldComponents,
848
+ ...extension.fieldComponents,
849
+ } as TComponents & TNewField,
850
+ formComponents: {
851
+ ...formComponents,
852
+ ...extension.formComponents,
853
+ } as TFormComponents & TNewForm,
854
+ });
855
+ }
856
+
857
+ return {
858
+ useAppForm,
859
+ withForm,
860
+ withFieldGroup,
861
+ useTypedAppFormContext,
862
+ extendForm,
863
+ } as CreateFormHookReturn<TComponents, TFormComponents>;
864
+ }