@saas-ui/forms 3.0.0-alpha.1 → 3.0.0-alpha.2
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/CHANGELOG.md +12 -0
- package/dist/index.js.map +1 -1
- package/dist/index.mjs.map +1 -1
- package/package.json +8 -28
- package/dist/ajv/index.d.mts +0 -35
- package/dist/ajv/index.d.ts +0 -35
- package/dist/ajv/index.js +0 -57
- package/dist/ajv/index.js.map +0 -1
- package/dist/ajv/index.mjs +0 -30
- package/dist/ajv/index.mjs.map +0 -1
- package/src/array-field.tsx +0 -266
- package/src/auto-form.tsx +0 -71
- package/src/base-field.tsx +0 -69
- package/src/create-field.tsx +0 -171
- package/src/create-form.tsx +0 -100
- package/src/create-step-form.tsx +0 -118
- package/src/default-fields.tsx +0 -233
- package/src/display-field.tsx +0 -46
- package/src/display-if.tsx +0 -69
- package/src/field-resolver.ts +0 -66
- package/src/field.tsx +0 -44
- package/src/fields-context.tsx +0 -33
- package/src/fields.tsx +0 -93
- package/src/form-context.tsx +0 -80
- package/src/form-layout.tsx +0 -59
- package/src/form.tsx +0 -252
- package/src/index.ts +0 -310
- package/src/object-field.tsx +0 -58
- package/src/step-form.tsx +0 -191
- package/src/submit-button.tsx +0 -71
- package/src/types.ts +0 -242
- package/src/use-array-field.tsx +0 -158
- package/src/use-form.tsx +0 -24
- package/src/use-step-form.tsx +0 -201
- package/src/utils.ts +0 -35
- package/src/watch-field.tsx +0 -37
package/src/types.ts
DELETED
@@ -1,242 +0,0 @@
|
|
1
|
-
import type { MaybeRenderProp } from '@saas-ui/core/utils'
|
2
|
-
import type { FieldPath, FieldValues, RegisterOptions } from 'react-hook-form'
|
3
|
-
|
4
|
-
import type { ArrayFieldProps } from './array-field'
|
5
|
-
import type { DefaultFields } from './default-fields'
|
6
|
-
import type { FormProps, FormRenderContext } from './form'
|
7
|
-
import type { ObjectFieldProps } from './object-field'
|
8
|
-
import type { StepsOptions } from './step-form'
|
9
|
-
import type { SubmitButtonProps } from './submit-button'
|
10
|
-
import type { StepFormRenderContext, UseStepFormProps } from './use-step-form'
|
11
|
-
|
12
|
-
export interface FocusableElement {
|
13
|
-
focus(options?: FocusOptions): void
|
14
|
-
}
|
15
|
-
|
16
|
-
export type FieldOption = { label?: string; value: string }
|
17
|
-
export type FieldOptions<TOption extends FieldOption = FieldOption> =
|
18
|
-
Array<TOption>
|
19
|
-
|
20
|
-
export type ValueOf<T> = T[keyof T]
|
21
|
-
export type ShallowMerge<A, B> = Omit<A, keyof B> & B
|
22
|
-
|
23
|
-
type Split<S extends string, D extends string> = string extends S
|
24
|
-
? string[]
|
25
|
-
: S extends ''
|
26
|
-
? []
|
27
|
-
: S extends `${infer T}${D}${infer U}`
|
28
|
-
? [T, ...Split<U, D>]
|
29
|
-
: [S]
|
30
|
-
|
31
|
-
type MapPath<T extends string[]> = T extends [infer U, ...infer R]
|
32
|
-
? U extends string
|
33
|
-
? `${U extends `${number}` ? '$' : U}${R[0] extends string
|
34
|
-
? '.'
|
35
|
-
: ''}${R extends string[] ? MapPath<R> : ''}`
|
36
|
-
: ''
|
37
|
-
: ''
|
38
|
-
|
39
|
-
type TransformPath<T extends string> = MapPath<Split<T, '.'>>
|
40
|
-
|
41
|
-
export type ArrayFieldPath<Name extends string> = Name extends string
|
42
|
-
? TransformPath<Name>
|
43
|
-
: never
|
44
|
-
|
45
|
-
export interface BaseFieldProps<
|
46
|
-
TFieldValues extends FieldValues = FieldValues,
|
47
|
-
TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>,
|
48
|
-
> {
|
49
|
-
/**
|
50
|
-
* The field name
|
51
|
-
*/
|
52
|
-
name: TName | ArrayFieldPath<TName>
|
53
|
-
/**
|
54
|
-
* The field label
|
55
|
-
*/
|
56
|
-
label?: string
|
57
|
-
/**
|
58
|
-
* Hide the field label
|
59
|
-
*/
|
60
|
-
hideLabel?: boolean
|
61
|
-
/**
|
62
|
-
* Field help text
|
63
|
-
*/
|
64
|
-
help?: string
|
65
|
-
/**
|
66
|
-
* React hook form rules
|
67
|
-
*/
|
68
|
-
rules?: Omit<
|
69
|
-
RegisterOptions<TFieldValues, TName>,
|
70
|
-
'valueAsNumber' | 'valueAsDate' | 'setValueAs' | 'disabled'
|
71
|
-
>
|
72
|
-
/**
|
73
|
-
* Build-in types:
|
74
|
-
* text, number, password, textarea, select, native-select, checkbox, radio, switch, pin
|
75
|
-
*
|
76
|
-
* Will default to a text field if there is no matching type.
|
77
|
-
*/
|
78
|
-
type?: string
|
79
|
-
/**
|
80
|
-
* The input placeholder
|
81
|
-
*/
|
82
|
-
placeholder?: string
|
83
|
-
/**
|
84
|
-
* React children
|
85
|
-
*/
|
86
|
-
children?: React.ReactNode
|
87
|
-
}
|
88
|
-
|
89
|
-
export type GetBaseField<TProps extends object = object> = () => {
|
90
|
-
extraProps: string[]
|
91
|
-
BaseField: React.FC<
|
92
|
-
Omit<BaseFieldProps, 'name'> & {
|
93
|
-
name: string
|
94
|
-
children: React.ReactNode
|
95
|
-
} & TProps
|
96
|
-
>
|
97
|
-
}
|
98
|
-
|
99
|
-
type FieldPathWithArray<
|
100
|
-
TFieldValues extends FieldValues,
|
101
|
-
TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>,
|
102
|
-
> = TName | ArrayFieldPath<TName>
|
103
|
-
|
104
|
-
export type MergeFieldProps<
|
105
|
-
FieldDefs,
|
106
|
-
TFieldValues extends FieldValues = FieldValues,
|
107
|
-
TExtraFieldProps extends object = object,
|
108
|
-
TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>,
|
109
|
-
> = ValueOf<{
|
110
|
-
[K in keyof FieldDefs]: FieldDefs[K] extends React.FC<infer Props>
|
111
|
-
? { type?: K } & ShallowMerge<
|
112
|
-
Props,
|
113
|
-
BaseFieldProps<TFieldValues, TName>
|
114
|
-
> & { [key in keyof TExtraFieldProps]: TExtraFieldProps[key] }
|
115
|
-
: never
|
116
|
-
}>
|
117
|
-
|
118
|
-
export type FieldProps<
|
119
|
-
TFieldValues extends FieldValues = FieldValues,
|
120
|
-
TExtraFieldProps extends object = object,
|
121
|
-
> = MergeFieldProps<DefaultFields, TFieldValues, TExtraFieldProps>
|
122
|
-
|
123
|
-
export type FormChildren<
|
124
|
-
FieldDefs,
|
125
|
-
TFieldValues extends FieldValues = FieldValues,
|
126
|
-
TContext extends object = object,
|
127
|
-
TExtraFieldProps extends object = object,
|
128
|
-
> = MaybeRenderProp<
|
129
|
-
FormRenderContext<
|
130
|
-
TFieldValues,
|
131
|
-
TContext,
|
132
|
-
MergeFieldProps<
|
133
|
-
FieldDefs extends never
|
134
|
-
? DefaultFields
|
135
|
-
: ShallowMerge<DefaultFields, FieldDefs>,
|
136
|
-
TFieldValues,
|
137
|
-
TExtraFieldProps
|
138
|
-
>
|
139
|
-
>
|
140
|
-
>
|
141
|
-
|
142
|
-
export type DefaultFieldOverrides = {
|
143
|
-
submit?: SubmitButtonProps
|
144
|
-
[key: string]: any
|
145
|
-
}
|
146
|
-
|
147
|
-
type MergeOverrideFieldProps<
|
148
|
-
FieldDefs,
|
149
|
-
TFieldValues extends FieldValues = FieldValues,
|
150
|
-
TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>,
|
151
|
-
> = ValueOf<{
|
152
|
-
[K in keyof FieldDefs]: FieldDefs[K] extends React.FC<infer Props>
|
153
|
-
? { type?: K } & Omit<
|
154
|
-
ShallowMerge<Props, BaseFieldProps<TFieldValues, TName>>,
|
155
|
-
'name'
|
156
|
-
>
|
157
|
-
: never
|
158
|
-
}>
|
159
|
-
|
160
|
-
export type FieldOverrides<
|
161
|
-
FieldDefs,
|
162
|
-
TFieldValues extends FieldValues = FieldValues,
|
163
|
-
TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>,
|
164
|
-
> = {
|
165
|
-
[K in FieldPathWithArray<TFieldValues, TName>]?:
|
166
|
-
| MergeOverrideFieldProps<
|
167
|
-
FieldDefs extends never
|
168
|
-
? DefaultFields
|
169
|
-
: ShallowMerge<DefaultFields, FieldDefs>,
|
170
|
-
TFieldValues
|
171
|
-
>
|
172
|
-
| ({ type?: 'object' } & Omit<
|
173
|
-
ObjectFieldProps<TFieldValues>,
|
174
|
-
'name' | 'children'
|
175
|
-
>)
|
176
|
-
| ({ type?: 'array' } & Omit<
|
177
|
-
ArrayFieldProps<TFieldValues>,
|
178
|
-
'name' | 'children'
|
179
|
-
>)
|
180
|
-
}
|
181
|
-
|
182
|
-
export type WithFields<
|
183
|
-
TFormProps extends FormProps<any, any, any, any, any>,
|
184
|
-
FieldDefs,
|
185
|
-
ExtraOverrides = object,
|
186
|
-
> =
|
187
|
-
TFormProps extends FormProps<
|
188
|
-
infer _TSchema,
|
189
|
-
infer TFieldValues,
|
190
|
-
infer TContext,
|
191
|
-
infer TExtraFieldProps
|
192
|
-
>
|
193
|
-
? Omit<TFormProps, 'children' | 'fields'> & {
|
194
|
-
children?: FormChildren<
|
195
|
-
FieldDefs,
|
196
|
-
TFieldValues,
|
197
|
-
TContext,
|
198
|
-
TExtraFieldProps
|
199
|
-
>
|
200
|
-
fields?: FieldOverrides<FieldDefs, TFieldValues> & {
|
201
|
-
submit?: SubmitButtonProps
|
202
|
-
} & ExtraOverrides
|
203
|
-
}
|
204
|
-
: never
|
205
|
-
|
206
|
-
// StepForm types
|
207
|
-
export type StepFormChildren<
|
208
|
-
FieldDefs,
|
209
|
-
TSteps extends StepsOptions<any> = StepsOptions<any>,
|
210
|
-
TFieldValues extends FieldValues = FieldValues,
|
211
|
-
TContext extends object = object,
|
212
|
-
> = MaybeRenderProp<
|
213
|
-
StepFormRenderContext<
|
214
|
-
TSteps,
|
215
|
-
TFieldValues,
|
216
|
-
TContext,
|
217
|
-
MergeFieldProps<
|
218
|
-
FieldDefs extends never
|
219
|
-
? DefaultFields
|
220
|
-
: ShallowMerge<DefaultFields, FieldDefs>,
|
221
|
-
TFieldValues
|
222
|
-
>
|
223
|
-
>
|
224
|
-
>
|
225
|
-
|
226
|
-
export type WithStepFields<
|
227
|
-
TStepFormProps extends UseStepFormProps<any, any, any>,
|
228
|
-
FieldDefs,
|
229
|
-
ExtraOverrides = object,
|
230
|
-
> =
|
231
|
-
TStepFormProps extends UseStepFormProps<
|
232
|
-
infer TSteps,
|
233
|
-
infer TFieldValues,
|
234
|
-
infer TContext
|
235
|
-
>
|
236
|
-
? Omit<TStepFormProps, 'children' | 'fields'> & {
|
237
|
-
children?: StepFormChildren<FieldDefs, TSteps, TFieldValues, TContext>
|
238
|
-
fields?: FieldOverrides<FieldDefs, TFieldValues> & {
|
239
|
-
submit?: SubmitButtonProps
|
240
|
-
} & ExtraOverrides
|
241
|
-
}
|
242
|
-
: never
|
package/src/use-array-field.tsx
DELETED
@@ -1,158 +0,0 @@
|
|
1
|
-
import * as React from 'react'
|
2
|
-
|
3
|
-
import { createContext } from '@saas-ui/core/utils'
|
4
|
-
import {
|
5
|
-
FieldPath,
|
6
|
-
FieldValues,
|
7
|
-
UseFieldArrayReturn,
|
8
|
-
useFieldArray,
|
9
|
-
} from 'react-hook-form'
|
10
|
-
|
11
|
-
import { useFormContext } from './form-context'
|
12
|
-
|
13
|
-
export interface UseArrayFieldReturn extends UseFieldArrayReturn {
|
14
|
-
/**
|
15
|
-
* The array field name
|
16
|
-
*/
|
17
|
-
name: string
|
18
|
-
/**
|
19
|
-
* The default value for new items
|
20
|
-
*/
|
21
|
-
defaultValue: Record<string, any>
|
22
|
-
/**
|
23
|
-
* Min amount of items
|
24
|
-
*/
|
25
|
-
min?: number
|
26
|
-
/**
|
27
|
-
* Max amount of items
|
28
|
-
*/
|
29
|
-
max?: number
|
30
|
-
}
|
31
|
-
|
32
|
-
export const [ArrayFieldProvider, useArrayFieldContext] =
|
33
|
-
createContext<UseArrayFieldReturn>({
|
34
|
-
name: 'ArrayFieldContext',
|
35
|
-
})
|
36
|
-
|
37
|
-
export interface UseArrayFieldRowReturn {
|
38
|
-
/**
|
39
|
-
* Name of the array field including the index, eg 'field.0'
|
40
|
-
*/
|
41
|
-
name: string
|
42
|
-
/**
|
43
|
-
* The field index
|
44
|
-
*/
|
45
|
-
index: number
|
46
|
-
/**
|
47
|
-
* Remove this array item
|
48
|
-
*/
|
49
|
-
remove: () => void
|
50
|
-
/**
|
51
|
-
* True if this is the first item
|
52
|
-
*/
|
53
|
-
isFirst: boolean
|
54
|
-
/**
|
55
|
-
* True if this is the last item
|
56
|
-
*/
|
57
|
-
isLast: boolean
|
58
|
-
}
|
59
|
-
|
60
|
-
export const [ArrayFieldRowProvider, useArrayFieldRowContext] =
|
61
|
-
createContext<UseArrayFieldRowReturn>({
|
62
|
-
name: 'ArrayFieldRowContext',
|
63
|
-
})
|
64
|
-
|
65
|
-
export interface ArrayFieldOptions<
|
66
|
-
TFieldValues extends FieldValues = FieldValues,
|
67
|
-
TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>,
|
68
|
-
> {
|
69
|
-
/**
|
70
|
-
* The field name
|
71
|
-
*/
|
72
|
-
name: TName
|
73
|
-
/**
|
74
|
-
* Default value for new values in the array
|
75
|
-
*/
|
76
|
-
defaultValue?: Record<string, any>
|
77
|
-
/**
|
78
|
-
* Default key name for rows, change this if your data uses a different 'id' field
|
79
|
-
* @default "id"
|
80
|
-
*/
|
81
|
-
keyName?: string
|
82
|
-
min?: number
|
83
|
-
max?: number
|
84
|
-
}
|
85
|
-
|
86
|
-
export const useArrayField = ({
|
87
|
-
name,
|
88
|
-
defaultValue = {},
|
89
|
-
keyName,
|
90
|
-
min,
|
91
|
-
max,
|
92
|
-
}: ArrayFieldOptions) => {
|
93
|
-
const { control } = useFormContext()
|
94
|
-
|
95
|
-
const context = useFieldArray({
|
96
|
-
control,
|
97
|
-
name,
|
98
|
-
keyName,
|
99
|
-
})
|
100
|
-
return {
|
101
|
-
...context,
|
102
|
-
name,
|
103
|
-
defaultValue,
|
104
|
-
min,
|
105
|
-
max,
|
106
|
-
}
|
107
|
-
}
|
108
|
-
|
109
|
-
export interface UseArrayFieldRowProps {
|
110
|
-
index: number
|
111
|
-
}
|
112
|
-
|
113
|
-
export const useArrayFieldRow = ({ index }: UseArrayFieldRowProps) => {
|
114
|
-
const { clearErrors } = useFormContext()
|
115
|
-
const { name, remove, fields } = useArrayFieldContext()
|
116
|
-
|
117
|
-
React.useEffect(() => {
|
118
|
-
// reset errors, to make sure min/max errors reset correctly
|
119
|
-
clearErrors(name)
|
120
|
-
}, [])
|
121
|
-
|
122
|
-
return {
|
123
|
-
index,
|
124
|
-
isFirst: index === 0,
|
125
|
-
isLast: index === fields.length - 1,
|
126
|
-
name: `${name}.${index}`,
|
127
|
-
remove: React.useCallback(() => {
|
128
|
-
clearErrors(name)
|
129
|
-
remove(index)
|
130
|
-
}, [index]),
|
131
|
-
}
|
132
|
-
}
|
133
|
-
|
134
|
-
export const useArrayFieldRemoveButton = () => {
|
135
|
-
const { isFirst, remove } = useArrayFieldRowContext()
|
136
|
-
const { min, fields } = useArrayFieldContext()
|
137
|
-
|
138
|
-
const isDisabled = isFirst && !!(min && fields.length <= min)
|
139
|
-
|
140
|
-
return {
|
141
|
-
onClick: () => remove(),
|
142
|
-
isDisabled,
|
143
|
-
}
|
144
|
-
}
|
145
|
-
|
146
|
-
export const useArrayFieldAddButton = () => {
|
147
|
-
const { append, defaultValue, max, fields } = useArrayFieldContext()
|
148
|
-
|
149
|
-
const isDisabled = !!(max && fields.length >= max)
|
150
|
-
|
151
|
-
return {
|
152
|
-
onClick: () =>
|
153
|
-
append(defaultValue, {
|
154
|
-
shouldFocus: false,
|
155
|
-
}),
|
156
|
-
isDisabled,
|
157
|
-
}
|
158
|
-
}
|
package/src/use-form.tsx
DELETED
@@ -1,24 +0,0 @@
|
|
1
|
-
import {
|
2
|
-
type FieldValues,
|
3
|
-
UseFormProps as UseHookFormProps,
|
4
|
-
useForm as useHookForm,
|
5
|
-
} from 'react-hook-form'
|
6
|
-
|
7
|
-
import { Field } from './field.tsx'
|
8
|
-
|
9
|
-
export interface UseFormProps<
|
10
|
-
TFieldValues extends FieldValues,
|
11
|
-
TContext extends object,
|
12
|
-
> extends UseHookFormProps<TFieldValues, TContext> {}
|
13
|
-
|
14
|
-
export function useForm<
|
15
|
-
TFieldValues extends FieldValues,
|
16
|
-
TContext extends object,
|
17
|
-
>(props: UseFormProps<TFieldValues, TContext> = {}) {
|
18
|
-
const form = useHookForm<TFieldValues, TContext>(props)
|
19
|
-
|
20
|
-
return {
|
21
|
-
...form,
|
22
|
-
Field,
|
23
|
-
}
|
24
|
-
}
|
package/src/use-step-form.tsx
DELETED
@@ -1,201 +0,0 @@
|
|
1
|
-
import * as React from 'react'
|
2
|
-
|
3
|
-
import { createContext } from '@chakra-ui/react'
|
4
|
-
import {
|
5
|
-
type UseStepperProps,
|
6
|
-
type UseStepperReturn,
|
7
|
-
useStep,
|
8
|
-
useStepper,
|
9
|
-
} from '@saas-ui/core'
|
10
|
-
import { FieldValues, SubmitHandler } from 'react-hook-form'
|
11
|
-
|
12
|
-
import { ArrayFieldProps } from './array-field'
|
13
|
-
import { DisplayIfProps } from './display-if'
|
14
|
-
import { FormProps } from './form'
|
15
|
-
import { ObjectFieldProps } from './object-field'
|
16
|
-
import { FormStepProps, StepsOptions } from './step-form'
|
17
|
-
import { FieldProps, type FocusableElement, StepFormChildren } from './types'
|
18
|
-
import { UseArrayFieldReturn } from './use-array-field'
|
19
|
-
|
20
|
-
export interface StepState {
|
21
|
-
name: string
|
22
|
-
schema?: any
|
23
|
-
resolver?: any
|
24
|
-
isActive?: boolean
|
25
|
-
isCompleted?: boolean
|
26
|
-
onSubmit?: FormStepSubmitHandler
|
27
|
-
}
|
28
|
-
|
29
|
-
export type FormStepSubmitHandler<
|
30
|
-
TFieldValues extends FieldValues = FieldValues,
|
31
|
-
> = (data: TFieldValues, stepper: UseStepperReturn) => Promise<void>
|
32
|
-
|
33
|
-
export interface StepFormContext extends UseStepperReturn {
|
34
|
-
updateStep(state: StepState): void
|
35
|
-
steps: Record<string, StepState>
|
36
|
-
}
|
37
|
-
|
38
|
-
export const [StepFormProvider, useStepFormContext] =
|
39
|
-
createContext<StepFormContext>({
|
40
|
-
name: 'StepFormContext',
|
41
|
-
errorMessage:
|
42
|
-
'useStepFormContext: `context` is undefined. Seems you forgot to wrap step form components in `<StepForm />`',
|
43
|
-
})
|
44
|
-
|
45
|
-
type StepName<T extends { [k: number]: { readonly name: string } }> =
|
46
|
-
T[number]['name']
|
47
|
-
|
48
|
-
export interface StepFormRenderContext<
|
49
|
-
TSteps extends StepsOptions<any> = StepsOptions<any>,
|
50
|
-
TFieldValues extends FieldValues = FieldValues,
|
51
|
-
TContext extends object = object,
|
52
|
-
TFieldTypes = FieldProps<TFieldValues>,
|
53
|
-
> extends UseStepFormReturn<TFieldValues> {
|
54
|
-
Field: React.FC<TFieldTypes & React.RefAttributes<FocusableElement>>
|
55
|
-
FormStep: React.FC<FormStepProps<StepName<TSteps>>>
|
56
|
-
DisplayIf: React.FC<DisplayIfProps<TFieldValues>>
|
57
|
-
ArrayField: React.FC<
|
58
|
-
ArrayFieldProps<TFieldValues> & React.RefAttributes<UseArrayFieldReturn>
|
59
|
-
>
|
60
|
-
ObjectField: React.FC<ObjectFieldProps<TFieldValues>>
|
61
|
-
}
|
62
|
-
|
63
|
-
export interface UseStepFormProps<
|
64
|
-
TSteps extends StepsOptions<any> = StepsOptions<any>,
|
65
|
-
TFieldValues extends FieldValues = FieldValues,
|
66
|
-
TContext extends object = object,
|
67
|
-
> extends Omit<UseStepperProps, 'onChange'>,
|
68
|
-
Omit<FormProps<any, TFieldValues, TContext>, 'children'> {
|
69
|
-
steps?: TSteps
|
70
|
-
children: StepFormChildren<any, TSteps, TFieldValues, TContext>
|
71
|
-
}
|
72
|
-
|
73
|
-
export interface UseStepFormReturn<
|
74
|
-
TFieldValues extends FieldValues = FieldValues,
|
75
|
-
> extends UseStepperReturn {
|
76
|
-
getFormProps(): {
|
77
|
-
onSubmit: SubmitHandler<TFieldValues>
|
78
|
-
schema?: any
|
79
|
-
resolver?: any
|
80
|
-
}
|
81
|
-
updateStep(step: any): void
|
82
|
-
steps: Record<string, any>
|
83
|
-
}
|
84
|
-
|
85
|
-
export function useStepForm<
|
86
|
-
TSteps extends StepsOptions<any> = StepsOptions<any>,
|
87
|
-
TFieldValues extends FieldValues = FieldValues,
|
88
|
-
TContext extends object = object,
|
89
|
-
>(
|
90
|
-
props: UseStepFormProps<TSteps, TFieldValues, TContext>,
|
91
|
-
): UseStepFormReturn<TFieldValues> {
|
92
|
-
const {
|
93
|
-
onChange,
|
94
|
-
steps: stepsOptions,
|
95
|
-
resolver,
|
96
|
-
fieldResolver,
|
97
|
-
...rest
|
98
|
-
} = props
|
99
|
-
const stepper = useStepper(rest)
|
100
|
-
|
101
|
-
const [options] = React.useState<TSteps | undefined>(stepsOptions)
|
102
|
-
|
103
|
-
const { activeStep, isLastStep, nextStep } = stepper
|
104
|
-
|
105
|
-
const [steps, updateSteps] = React.useState<Record<string, StepState>>({})
|
106
|
-
|
107
|
-
const mergedData = React.useRef<TFieldValues>({} as any)
|
108
|
-
|
109
|
-
const onSubmitStep: SubmitHandler<TFieldValues> = React.useCallback(
|
110
|
-
async (data) => {
|
111
|
-
try {
|
112
|
-
const step = steps[activeStep]
|
113
|
-
|
114
|
-
mergedData.current = {
|
115
|
-
...mergedData.current,
|
116
|
-
...data,
|
117
|
-
}
|
118
|
-
|
119
|
-
if (isLastStep) {
|
120
|
-
await props.onSubmit?.(mergedData.current)
|
121
|
-
|
122
|
-
updateStep({
|
123
|
-
...step,
|
124
|
-
isCompleted: true,
|
125
|
-
})
|
126
|
-
|
127
|
-
nextStep() // show completed step
|
128
|
-
return
|
129
|
-
}
|
130
|
-
|
131
|
-
await step.onSubmit?.(data, stepper)
|
132
|
-
|
133
|
-
nextStep()
|
134
|
-
} catch (e) {
|
135
|
-
// Step submission failed.
|
136
|
-
}
|
137
|
-
},
|
138
|
-
[steps, activeStep, isLastStep, mergedData],
|
139
|
-
)
|
140
|
-
|
141
|
-
const getFormProps = React.useCallback(() => {
|
142
|
-
const step = steps[activeStep]
|
143
|
-
|
144
|
-
return {
|
145
|
-
onSubmit: onSubmitStep,
|
146
|
-
schema: step?.schema,
|
147
|
-
resolver: step?.schema
|
148
|
-
? /* @todo fix resolver type */ (resolver as any)?.(step.schema)
|
149
|
-
: undefined,
|
150
|
-
fieldResolver: step?.schema
|
151
|
-
? (fieldResolver as any)?.(step.schema)
|
152
|
-
: undefined,
|
153
|
-
}
|
154
|
-
}, [steps, onSubmitStep, activeStep, resolver, fieldResolver])
|
155
|
-
|
156
|
-
const updateStep = React.useCallback(
|
157
|
-
(step: StepState) => {
|
158
|
-
const stepOptions = options?.find((s) => s.name === step.name)
|
159
|
-
updateSteps((steps) => {
|
160
|
-
return {
|
161
|
-
...steps,
|
162
|
-
[step.name]: {
|
163
|
-
...step,
|
164
|
-
schema: stepOptions?.schema,
|
165
|
-
},
|
166
|
-
}
|
167
|
-
})
|
168
|
-
},
|
169
|
-
[steps, options],
|
170
|
-
)
|
171
|
-
|
172
|
-
return {
|
173
|
-
getFormProps,
|
174
|
-
updateStep,
|
175
|
-
steps,
|
176
|
-
...stepper,
|
177
|
-
}
|
178
|
-
}
|
179
|
-
|
180
|
-
export interface UseFormStepProps {
|
181
|
-
name: string
|
182
|
-
schema?: any
|
183
|
-
resolver?: any
|
184
|
-
onSubmit?: FormStepSubmitHandler
|
185
|
-
}
|
186
|
-
|
187
|
-
export function useFormStep(props: UseFormStepProps): StepState {
|
188
|
-
const { name, schema, resolver, onSubmit } = props
|
189
|
-
const step = useStep({ name })
|
190
|
-
|
191
|
-
const { steps, updateStep } = useStepFormContext()
|
192
|
-
|
193
|
-
React.useEffect(() => {
|
194
|
-
updateStep({ name, schema, resolver, onSubmit })
|
195
|
-
}, [name, schema])
|
196
|
-
|
197
|
-
return {
|
198
|
-
...step,
|
199
|
-
...(steps[name] || { name, schema }),
|
200
|
-
}
|
201
|
-
}
|
package/src/utils.ts
DELETED
@@ -1,35 +0,0 @@
|
|
1
|
-
import * as React from 'react'
|
2
|
-
import { FieldOption, FieldOptions } from './types'
|
3
|
-
|
4
|
-
export const mapNestedFields = (name: string, children: React.ReactNode) => {
|
5
|
-
return React.Children.map(children, (child) => {
|
6
|
-
if (React.isValidElement(child) && child.props.name) {
|
7
|
-
let childName = child.props.name
|
8
|
-
if (childName.includes('.')) {
|
9
|
-
childName = childName.replace(/^.*\.(.*)/, '$1')
|
10
|
-
} else if (childName.includes('.$')) {
|
11
|
-
childName = childName.replace(/^.*\.\$(.*)/, '$1')
|
12
|
-
}
|
13
|
-
|
14
|
-
return React.cloneElement(child, {
|
15
|
-
...child.props,
|
16
|
-
name: `${name}.${childName}`,
|
17
|
-
})
|
18
|
-
}
|
19
|
-
return child
|
20
|
-
})
|
21
|
-
}
|
22
|
-
|
23
|
-
export const mapOptions = <TOption extends FieldOption = FieldOption>(
|
24
|
-
options: FieldOptions<TOption>
|
25
|
-
) => {
|
26
|
-
return options.map((option) => {
|
27
|
-
if (typeof option === 'string') {
|
28
|
-
return {
|
29
|
-
label: option,
|
30
|
-
value: option,
|
31
|
-
}
|
32
|
-
}
|
33
|
-
return option
|
34
|
-
})
|
35
|
-
}
|
package/src/watch-field.tsx
DELETED
@@ -1,37 +0,0 @@
|
|
1
|
-
import { FieldValues, useWatch } from 'react-hook-form'
|
2
|
-
import { useFormContext, UseFormReturn } from './form-context'
|
3
|
-
|
4
|
-
export interface WatchFieldProps<
|
5
|
-
Value = unknown,
|
6
|
-
TFieldValues extends FieldValues = FieldValues,
|
7
|
-
TContext extends object = object,
|
8
|
-
> {
|
9
|
-
name: string
|
10
|
-
defaultValue?: Value
|
11
|
-
isDisabled?: boolean
|
12
|
-
isExact?: boolean
|
13
|
-
children: (
|
14
|
-
value: Value,
|
15
|
-
form: UseFormReturn<TFieldValues, TContext>
|
16
|
-
) => React.ReactElement | void
|
17
|
-
}
|
18
|
-
|
19
|
-
export const WatchField = <
|
20
|
-
Value = unknown,
|
21
|
-
TFieldValues extends FieldValues = FieldValues,
|
22
|
-
TContext extends object = object,
|
23
|
-
>(
|
24
|
-
props: WatchFieldProps<Value, TFieldValues, TContext>
|
25
|
-
) => {
|
26
|
-
const { name, defaultValue, isDisabled, isExact } = props
|
27
|
-
const form = useFormContext<TFieldValues, TContext>()
|
28
|
-
|
29
|
-
const field = useWatch({
|
30
|
-
name,
|
31
|
-
defaultValue,
|
32
|
-
disabled: isDisabled,
|
33
|
-
exact: isExact,
|
34
|
-
})
|
35
|
-
|
36
|
-
return props.children(field, form) || null
|
37
|
-
}
|