@saas-ui/forms 2.0.0-next.9 → 2.0.0-rc.23

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/src/step-form.tsx CHANGED
@@ -1,6 +1,6 @@
1
1
  import * as React from 'react'
2
2
 
3
- import { FieldValues, UseFormReturn } from 'react-hook-form'
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, runIfFn, cx } from '@chakra-ui/utils'
13
+ import { callAllHandlers, cx } from '@chakra-ui/utils'
14
14
 
15
15
  import {
16
- StepperProvider,
17
- StepperSteps,
18
- StepperStepsProps,
19
- StepperStep,
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
- > extends UseStepFormProps<TFieldValues> {}
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: string
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
- extends StepperStepsProps,
95
- ThemingProps<'Stepper'> {}
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 { children, orientation, variant, colorScheme, size, ...rest } = props
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
- <StepperStep
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
- </StepperStep>
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
- <StepperContainer
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
- <StepperSteps mb="4" {...props}>
141
- {elements}
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: React.FC<FormStepProps> = (props) => {
158
- const { name, schema, resolver, children, className, onSubmit, ...rest } =
159
- props
160
- const step = useFormStep({ name, schema, resolver, onSubmit })
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
- label="Back"
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
- > = TFormProps extends FormProps<infer TFieldValues, infer TContext>
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
@@ -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
- TFieldValues extends FieldValues = FieldValues
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
- children: MaybeRenderProp<UseStepFormReturn<TFieldValues>>
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<TFieldValues extends FieldValues = FieldValues>(
58
- props: UseStepFormProps<TFieldValues>
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?.resolver,
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]: step,
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 {