@saas-ui/forms 2.0.0-next.9 → 2.0.0-rc.23
Sign up to get free protection for your applications and to get access to all the features.
- package/CHANGELOG.md +139 -0
- package/dist/ajv/index.d.ts +15 -350
- package/dist/ajv/index.js.map +1 -1
- package/dist/ajv/index.mjs.map +1 -1
- package/dist/index.d.ts +182 -144
- package/dist/index.js +202 -147
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +202 -148
- package/dist/index.mjs.map +1 -1
- package/dist/yup/index.d.ts +218 -274
- package/dist/yup/index.js +22 -6
- package/dist/yup/index.js.map +1 -1
- package/dist/yup/index.mjs +20 -5
- package/dist/yup/index.mjs.map +1 -1
- package/dist/zod/index.d.ts +246 -303
- package/dist/zod/index.js +16 -1
- package/dist/zod/index.js.map +1 -1
- package/dist/zod/index.mjs +17 -3
- package/dist/zod/index.mjs.map +1 -1
- package/package.json +20 -6
- package/src/array-field.tsx +6 -3
- package/src/create-form.tsx +33 -19
- package/src/create-step-form.tsx +100 -0
- package/src/form-context.tsx +1 -1
- package/src/form.tsx +12 -10
- package/src/index.ts +20 -6
- package/src/object-field.tsx +22 -5
- package/src/select/select.tsx +2 -2
- package/src/step-form.tsx +52 -70
- package/src/types.ts +8 -3
- package/src/use-step-form.tsx +54 -9
package/src/step-form.tsx
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
import * as React from 'react'
|
2
2
|
|
3
|
-
import { FieldValues
|
3
|
+
import { FieldValues } from 'react-hook-form'
|
4
4
|
|
5
5
|
import {
|
6
6
|
chakra,
|
@@ -10,76 +10,48 @@ import {
|
|
10
10
|
ThemingProps,
|
11
11
|
} from '@chakra-ui/react'
|
12
12
|
|
13
|
-
import { callAllHandlers,
|
13
|
+
import { callAllHandlers, cx } from '@chakra-ui/utils'
|
14
14
|
|
15
15
|
import {
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
16
|
+
Steps,
|
17
|
+
StepsItem,
|
18
|
+
StepsItemProps,
|
19
|
+
StepsProps,
|
20
20
|
useStepperContext,
|
21
|
-
StepperContainer,
|
22
|
-
StepperProps,
|
23
21
|
} from '@saas-ui/core'
|
24
22
|
|
25
|
-
import { Form } from './form'
|
26
23
|
import { SubmitButton } from './submit-button'
|
27
24
|
|
28
25
|
import {
|
29
|
-
useStepForm,
|
30
26
|
useFormStep,
|
31
|
-
StepFormProvider,
|
32
27
|
UseStepFormProps,
|
33
28
|
FormStepSubmitHandler,
|
34
29
|
} from './use-step-form'
|
30
|
+
import { FieldProps } from './types'
|
31
|
+
|
32
|
+
export type StepsOptions<TSchema, TName extends string = string> = {
|
33
|
+
/**
|
34
|
+
* The step name
|
35
|
+
*/
|
36
|
+
name: TName
|
37
|
+
/**
|
38
|
+
* Schema
|
39
|
+
*/
|
40
|
+
schema?: TSchema
|
41
|
+
}[]
|
35
42
|
|
36
43
|
export interface StepFormProps<
|
44
|
+
TSteps extends StepsOptions<any> = StepsOptions<any>,
|
37
45
|
TFieldValues extends FieldValues = FieldValues,
|
38
|
-
TContext extends object = object
|
39
|
-
|
46
|
+
TContext extends object = object,
|
47
|
+
TFieldTypes = FieldProps<TFieldValues>
|
48
|
+
> extends UseStepFormProps<TSteps, TFieldValues, TContext, TFieldTypes> {}
|
40
49
|
|
41
|
-
|
42
|
-
* The wrapper component provides context, state, and focus management.
|
43
|
-
*
|
44
|
-
* @see Docs https://saas-ui.dev/docs/components/forms/step-form
|
45
|
-
*/
|
46
|
-
export const StepForm = React.forwardRef(
|
47
|
-
<
|
48
|
-
TFieldValues extends FieldValues = FieldValues,
|
49
|
-
TContext extends object = object
|
50
|
-
>(
|
51
|
-
props: StepFormProps<TFieldValues, TContext>,
|
52
|
-
ref: React.ForwardedRef<HTMLFormElement>
|
53
|
-
) => {
|
54
|
-
const { children, ...rest } = props
|
55
|
-
|
56
|
-
const stepper = useStepForm<TFieldValues>(props)
|
57
|
-
|
58
|
-
const { getFormProps, ...ctx } = stepper
|
59
|
-
|
60
|
-
const context = React.useMemo(() => ctx, [ctx])
|
61
|
-
|
62
|
-
return (
|
63
|
-
<StepperProvider value={context}>
|
64
|
-
<StepFormProvider value={context}>
|
65
|
-
<Form ref={ref} {...rest} {...getFormProps()}>
|
66
|
-
{runIfFn(children, stepper)}
|
67
|
-
</Form>
|
68
|
-
</StepFormProvider>
|
69
|
-
</StepperProvider>
|
70
|
-
)
|
71
|
-
}
|
72
|
-
) as <TFieldValues extends FieldValues>(
|
73
|
-
props: StepFormProps<TFieldValues> & {
|
74
|
-
ref?: React.ForwardedRef<HTMLFormElement>
|
75
|
-
}
|
76
|
-
) => React.ReactElement
|
77
|
-
|
78
|
-
export interface FormStepOptions {
|
50
|
+
export interface FormStepOptions<TName extends string = string> {
|
79
51
|
/**
|
80
52
|
* The step name
|
81
53
|
*/
|
82
|
-
name:
|
54
|
+
name: TName
|
83
55
|
/**
|
84
56
|
* Schema
|
85
57
|
*/
|
@@ -90,9 +62,9 @@ export interface FormStepOptions {
|
|
90
62
|
resolver?: any
|
91
63
|
}
|
92
64
|
|
93
|
-
export interface FormStepperProps
|
94
|
-
|
95
|
-
|
65
|
+
export interface FormStepperProps extends StepsProps, ThemingProps<'Stepper'> {
|
66
|
+
render?: StepsItemProps['render']
|
67
|
+
}
|
96
68
|
|
97
69
|
/**
|
98
70
|
* Renders a stepper that displays progress above the form.
|
@@ -102,7 +74,16 @@ export interface FormStepperProps
|
|
102
74
|
export const FormStepper: React.FC<FormStepperProps> = (props) => {
|
103
75
|
const { activeIndex, setIndex } = useStepperContext()
|
104
76
|
|
105
|
-
const {
|
77
|
+
const {
|
78
|
+
children,
|
79
|
+
orientation,
|
80
|
+
variant,
|
81
|
+
colorScheme,
|
82
|
+
size,
|
83
|
+
onChange: onChangeProp,
|
84
|
+
render,
|
85
|
+
...rest
|
86
|
+
} = props
|
106
87
|
|
107
88
|
const elements = React.Children.map(children, (child) => {
|
108
89
|
if (
|
@@ -111,14 +92,15 @@ export const FormStepper: React.FC<FormStepperProps> = (props) => {
|
|
111
92
|
) {
|
112
93
|
const { isCompleted } = useFormStep(child.props) // Register this step
|
113
94
|
return (
|
114
|
-
<
|
95
|
+
<StepsItem
|
96
|
+
render={render}
|
115
97
|
name={child.props.name}
|
116
98
|
title={child.props.title}
|
117
99
|
isCompleted={isCompleted}
|
118
100
|
{...rest}
|
119
101
|
>
|
120
102
|
{child.props.children}
|
121
|
-
</
|
103
|
+
</StepsItem>
|
122
104
|
)
|
123
105
|
}
|
124
106
|
return child
|
@@ -126,10 +108,11 @@ export const FormStepper: React.FC<FormStepperProps> = (props) => {
|
|
126
108
|
|
127
109
|
const onChange = React.useCallback((i: number) => {
|
128
110
|
setIndex(i)
|
111
|
+
onChangeProp?.(i)
|
129
112
|
}, [])
|
130
113
|
|
131
114
|
return (
|
132
|
-
<
|
115
|
+
<Steps
|
133
116
|
orientation={orientation}
|
134
117
|
step={activeIndex}
|
135
118
|
variant={variant}
|
@@ -137,15 +120,13 @@ export const FormStepper: React.FC<FormStepperProps> = (props) => {
|
|
137
120
|
size={size}
|
138
121
|
onChange={onChange}
|
139
122
|
>
|
140
|
-
|
141
|
-
|
142
|
-
</StepperSteps>
|
143
|
-
</StepperContainer>
|
123
|
+
{elements}
|
124
|
+
</Steps>
|
144
125
|
)
|
145
126
|
}
|
146
127
|
|
147
|
-
export interface FormStepProps
|
148
|
-
extends FormStepOptions
|
128
|
+
export interface FormStepProps<TName extends string = string>
|
129
|
+
extends FormStepOptions<TName>,
|
149
130
|
Omit<HTMLChakraProps<'div'>, 'onSubmit'> {
|
150
131
|
onSubmit?: FormStepSubmitHandler
|
151
132
|
}
|
@@ -154,10 +135,11 @@ export interface FormStepProps
|
|
154
135
|
*
|
155
136
|
* @see Docs https://saas-ui.dev/docs/components/forms/step-form
|
156
137
|
*/
|
157
|
-
export const FormStep
|
158
|
-
|
159
|
-
|
160
|
-
const
|
138
|
+
export const FormStep = <TName extends string = string>(
|
139
|
+
props: FormStepProps<TName>
|
140
|
+
) => {
|
141
|
+
const { name, children, className, onSubmit, ...rest } = props
|
142
|
+
const step = useFormStep({ name, onSubmit })
|
161
143
|
|
162
144
|
const { isActive } = step
|
163
145
|
|
@@ -181,7 +163,7 @@ export const PrevButton: React.FC<ButtonProps> = (props) => {
|
|
181
163
|
return (
|
182
164
|
<Button
|
183
165
|
isDisabled={isFirstStep || isCompleted}
|
184
|
-
|
166
|
+
children="Back"
|
185
167
|
{...props}
|
186
168
|
className={cx('sui-form__prev-button', props.className)}
|
187
169
|
onClick={callAllHandlers(props.onClick, prevStep)}
|
package/src/types.ts
CHANGED
@@ -133,12 +133,17 @@ export type FieldOverrides<
|
|
133
133
|
|
134
134
|
export type WithFields<
|
135
135
|
TFormProps extends FormProps<any, any, any, any>,
|
136
|
-
FieldDefs
|
137
|
-
|
136
|
+
FieldDefs,
|
137
|
+
ExtraOverrides = object
|
138
|
+
> = TFormProps extends FormProps<
|
139
|
+
infer TSchema,
|
140
|
+
infer TFieldValues,
|
141
|
+
infer TContext
|
142
|
+
>
|
138
143
|
? Omit<TFormProps, 'children' | 'fields'> & {
|
139
144
|
children?: FormChildren<FieldDefs, TFieldValues, TContext>
|
140
145
|
fields?: FieldOverrides<FieldDefs, TFieldValues> & {
|
141
146
|
submit?: SubmitButtonProps
|
142
|
-
}
|
147
|
+
} & ExtraOverrides
|
143
148
|
}
|
144
149
|
: never
|
package/src/use-step-form.tsx
CHANGED
@@ -34,12 +34,43 @@ export const [StepFormProvider, useStepFormContext] =
|
|
34
34
|
})
|
35
35
|
|
36
36
|
import { FormProps } from './form'
|
37
|
+
import { FormStepProps, StepsOptions } from './step-form'
|
38
|
+
import { FieldProps } from './types'
|
39
|
+
import { FocusableElement } from '@chakra-ui/utils'
|
40
|
+
import { DisplayIfProps } from './display-if'
|
41
|
+
import { ArrayFieldProps } from './array-field'
|
42
|
+
import { UseArrayFieldReturn } from './use-array-field'
|
43
|
+
import { ObjectFieldProps } from './object-field'
|
44
|
+
|
45
|
+
type StepName<T extends { [k: number]: { readonly name: string } }> =
|
46
|
+
T[number]['name']
|
47
|
+
|
48
|
+
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
|
+
}
|
37
62
|
|
38
63
|
export interface UseStepFormProps<
|
39
|
-
|
64
|
+
TSteps extends StepsOptions<any> = StepsOptions<any>,
|
65
|
+
TFieldValues extends FieldValues = FieldValues,
|
66
|
+
TContext extends object = object,
|
67
|
+
TFieldTypes = FieldProps<TFieldValues>
|
40
68
|
> extends Omit<UseStepperProps, 'onChange'>,
|
41
|
-
Omit<FormProps<TFieldValues>, 'children'> {
|
42
|
-
|
69
|
+
Omit<FormProps<any, TFieldValues, TContext, TFieldTypes>, 'children'> {
|
70
|
+
steps?: TSteps
|
71
|
+
children: MaybeRenderProp<
|
72
|
+
StepFormRenderContext<TSteps, TFieldValues, TContext, TFieldTypes>
|
73
|
+
>
|
43
74
|
}
|
44
75
|
|
45
76
|
export interface UseStepFormReturn<
|
@@ -54,12 +85,19 @@ export interface UseStepFormReturn<
|
|
54
85
|
steps: Record<string, any>
|
55
86
|
}
|
56
87
|
|
57
|
-
export function useStepForm<
|
58
|
-
|
88
|
+
export function useStepForm<
|
89
|
+
TSteps extends StepsOptions<any> = StepsOptions<any>,
|
90
|
+
TFieldValues extends FieldValues = FieldValues,
|
91
|
+
TContext extends object = object,
|
92
|
+
TFieldTypes = FieldProps<TFieldValues>
|
93
|
+
>(
|
94
|
+
props: UseStepFormProps<TSteps, TFieldValues, TContext, TFieldTypes>
|
59
95
|
): UseStepFormReturn<TFieldValues> {
|
60
|
-
const { onChange, ...rest } = props
|
96
|
+
const { onChange, steps: stepsOptions, resolver, ...rest } = props
|
61
97
|
const stepper = useStepper(rest)
|
62
98
|
|
99
|
+
const [options, setOptions] = React.useState<TSteps | undefined>(stepsOptions)
|
100
|
+
|
63
101
|
const { activeStep, isLastStep, nextStep } = stepper
|
64
102
|
|
65
103
|
const [steps, updateSteps] = React.useState<Record<string, StepState>>({})
|
@@ -93,23 +131,30 @@ export function useStepForm<TFieldValues extends FieldValues = FieldValues>(
|
|
93
131
|
|
94
132
|
const getFormProps = React.useCallback(() => {
|
95
133
|
const step = steps[activeStep]
|
134
|
+
|
96
135
|
return {
|
97
136
|
onSubmit: onSubmitStep,
|
98
137
|
schema: step?.schema,
|
99
|
-
resolver: step?.
|
138
|
+
resolver: step?.schema
|
139
|
+
? /* @todo fix resolver type */ (resolver as any)?.(step.schema)
|
140
|
+
: undefined,
|
100
141
|
}
|
101
142
|
}, [steps, onSubmitStep, activeStep])
|
102
143
|
|
103
144
|
const updateStep = React.useCallback(
|
104
145
|
(step: StepState) => {
|
146
|
+
const stepOptions = options?.find((s) => s.name === step.name)
|
105
147
|
updateSteps((steps) => {
|
106
148
|
return {
|
107
149
|
...steps,
|
108
|
-
[step.name]:
|
150
|
+
[step.name]: {
|
151
|
+
...step,
|
152
|
+
schema: stepOptions?.schema,
|
153
|
+
},
|
109
154
|
}
|
110
155
|
})
|
111
156
|
},
|
112
|
-
[steps]
|
157
|
+
[steps, options]
|
113
158
|
)
|
114
159
|
|
115
160
|
return {
|