@saas-ui/forms 1.0.0-rc.0 → 1.0.0-rc.11

Sign up to get free protection for your applications and to get access to all the features.
Files changed (50) hide show
  1. package/CHANGELOG.md +130 -0
  2. package/README.md +29 -0
  3. package/ajv/package.json +18 -0
  4. package/dist/ajv/ajv-resolver.d.ts +11 -0
  5. package/dist/ajv/ajv-resolver.d.ts.map +1 -0
  6. package/dist/ajv/index.d.ts +2 -0
  7. package/dist/ajv/index.d.ts.map +1 -0
  8. package/dist/ajv/index.js +104 -0
  9. package/dist/ajv/index.js.map +1 -0
  10. package/dist/ajv/index.modern.mjs +104 -0
  11. package/dist/ajv/index.modern.mjs.map +1 -0
  12. package/dist/array-field.d.ts +14 -3
  13. package/dist/array-field.d.ts.map +1 -1
  14. package/dist/auto-form.d.ts +13 -1
  15. package/dist/auto-form.d.ts.map +1 -1
  16. package/dist/field.d.ts +82 -27
  17. package/dist/field.d.ts.map +1 -1
  18. package/dist/form.d.ts.map +1 -1
  19. package/dist/index.js +1 -1
  20. package/dist/index.js.map +1 -1
  21. package/dist/index.modern.mjs +1 -1
  22. package/dist/index.modern.mjs.map +1 -1
  23. package/dist/step-form.d.ts +4 -4
  24. package/dist/step-form.d.ts.map +1 -1
  25. package/dist/submit-button.d.ts +2 -1
  26. package/dist/submit-button.d.ts.map +1 -1
  27. package/dist/use-step-form.d.ts +7 -3
  28. package/dist/use-step-form.d.ts.map +1 -1
  29. package/dist/yup/index.js +1 -1
  30. package/dist/yup/index.js.map +1 -1
  31. package/dist/yup/index.modern.mjs +1 -1
  32. package/dist/yup/index.modern.mjs.map +1 -1
  33. package/dist/zod/index.js +1 -1
  34. package/dist/zod/index.js.map +1 -1
  35. package/dist/zod/index.modern.mjs +1 -1
  36. package/dist/zod/index.modern.mjs.map +1 -1
  37. package/dist/zod/zod-resolver.d.ts +2 -2
  38. package/dist/zod/zod-resolver.d.ts.map +1 -1
  39. package/package.json +32 -17
  40. package/src/array-field.tsx +21 -22
  41. package/src/auto-form.tsx +22 -3
  42. package/src/field-resolver.ts +2 -2
  43. package/src/field.tsx +184 -73
  44. package/src/form.tsx +0 -1
  45. package/src/object-field.tsx +3 -3
  46. package/src/step-form.tsx +27 -20
  47. package/src/submit-button.tsx +32 -24
  48. package/src/use-step-form.tsx +27 -12
  49. package/yup/package.json +2 -2
  50. package/zod/package.json +4 -4
package/src/step-form.tsx CHANGED
@@ -2,13 +2,7 @@ import * as React from 'react'
2
2
 
3
3
  import { FieldValues, UseFormReturn } from 'react-hook-form'
4
4
 
5
- import {
6
- chakra,
7
- HTMLChakraProps,
8
- useMultiStyleConfig,
9
- StylesProvider,
10
- SystemStyleObject,
11
- } from '@chakra-ui/system'
5
+ import { chakra, HTMLChakraProps } from '@chakra-ui/system'
12
6
 
13
7
  import { callAllHandlers, runIfFn, cx, __DEV__ } from '@chakra-ui/utils'
14
8
 
@@ -18,10 +12,11 @@ import {
18
12
  StepperStepsProps,
19
13
  StepperStep,
20
14
  useStepperContext,
15
+ StepperContainer,
21
16
  } from '@saas-ui/stepper'
22
17
  import { Button, ButtonProps } from '@saas-ui/button'
23
18
 
24
- import { Form, FormProps } from './form'
19
+ import { Form } from './form'
25
20
  import { SubmitButton } from './submit-button'
26
21
 
27
22
  import {
@@ -29,7 +24,7 @@ import {
29
24
  useFormStep,
30
25
  StepFormProvider,
31
26
  UseStepFormProps,
32
- UseStepFormReturn,
27
+ FormStepSubmitHandler,
33
28
  } from './use-step-form'
34
29
 
35
30
  export interface StepFormProps<TFieldValues extends FieldValues = FieldValues>
@@ -59,7 +54,7 @@ export const StepForm = React.forwardRef(
59
54
  )
60
55
  }
61
56
  ) as <TFieldValues extends FieldValues>(
62
- props: FormProps<TFieldValues> & {
57
+ props: StepFormProps<TFieldValues> & {
63
58
  ref?: React.ForwardedRef<UseFormReturn<TFieldValues>>
64
59
  }
65
60
  ) => React.ReactElement
@@ -80,9 +75,9 @@ export interface FormStepOptions {
80
75
  }
81
76
 
82
77
  export const FormStepper: React.FC<StepperStepsProps> = (props) => {
83
- const styles = useMultiStyleConfig('Stepper', props)
78
+ const { activeIndex, setIndex } = useStepperContext()
84
79
 
85
- const { children } = props
80
+ const { children, orientation } = props
86
81
 
87
82
  const elements = React.Children.map(children, (child) => {
88
83
  if (React.isValidElement(child) && child?.type === FormStep) {
@@ -100,22 +95,33 @@ export const FormStepper: React.FC<StepperStepsProps> = (props) => {
100
95
  return child
101
96
  })
102
97
 
98
+ const onChange = React.useCallback((i: number) => {
99
+ setIndex(i)
100
+ }, [])
101
+
103
102
  return (
104
- <StylesProvider value={styles}>
103
+ <StepperContainer
104
+ orientation={orientation}
105
+ step={activeIndex}
106
+ onChange={onChange}
107
+ >
105
108
  <StepperSteps mb="4" {...props}>
106
109
  {elements}
107
110
  </StepperSteps>
108
- </StylesProvider>
111
+ </StepperContainer>
109
112
  )
110
113
  }
111
114
 
112
115
  export interface FormStepProps
113
116
  extends FormStepOptions,
114
- HTMLChakraProps<'div'> {}
117
+ Omit<HTMLChakraProps<'div'>, 'onSubmit'> {
118
+ onSubmit?: FormStepSubmitHandler
119
+ }
115
120
 
116
121
  export const FormStep: React.FC<FormStepProps> = (props) => {
117
- const { name, schema, resolver, children, className, ...rest } = props
118
- const step = useFormStep({ name, schema, resolver })
122
+ const { name, schema, resolver, children, className, onSubmit, ...rest } =
123
+ props
124
+ const step = useFormStep({ name, schema, resolver, onSubmit })
119
125
 
120
126
  const { isActive } = step
121
127
 
@@ -158,11 +164,12 @@ export const NextButton: React.FC<NextButtonProps> = (props) => {
158
164
 
159
165
  return (
160
166
  <SubmitButton
161
- isDisabled={isCompleted}
162
- label={isLastStep || isCompleted ? submitLabel : label}
163
167
  {...rest}
168
+ isDisabled={isCompleted}
164
169
  className={cx('saas-form__next-button', props.className)}
165
- />
170
+ >
171
+ {isLastStep || isCompleted ? submitLabel : label}
172
+ </SubmitButton>
166
173
  )
167
174
  }
168
175
 
@@ -4,7 +4,6 @@ import { useFormContext } from 'react-hook-form'
4
4
 
5
5
  import { Button, ButtonProps } from '@saas-ui/button'
6
6
 
7
- import { forwardRef } from '@chakra-ui/system'
8
7
  import { __DEV__ } from '@chakra-ui/utils'
9
8
 
10
9
  export interface SubmitButtonProps extends ButtonProps {
@@ -24,29 +23,38 @@ export interface SubmitButtonProps extends ButtonProps {
24
23
  disableIfInvalid?: boolean
25
24
  }
26
25
 
27
- export const SubmitButton = forwardRef<SubmitButtonProps, 'button'>(
28
- (props, ref) => {
29
- const { children, disableIfUntouched, disableIfInvalid, ...rest } = props
30
- const { formState } = useFormContext()
31
-
32
- const isDisabled =
33
- (disableIfUntouched && !formState.isDirty) ||
34
- (disableIfInvalid && !formState.isValid)
35
-
36
- return (
37
- <Button
38
- type="submit"
39
- isLoading={formState.isSubmitting}
40
- isPrimary
41
- ref={ref}
42
- isDisabled={isDisabled}
43
- {...rest}
44
- >
45
- {children}
46
- </Button>
47
- )
48
- }
49
- )
26
+ export const SubmitButton = React.forwardRef<
27
+ HTMLButtonElement,
28
+ SubmitButtonProps
29
+ >((props, ref) => {
30
+ const {
31
+ children,
32
+ disableIfUntouched,
33
+ disableIfInvalid,
34
+ isDisabled: isDisabledProp,
35
+ isLoading,
36
+ ...rest
37
+ } = props
38
+ const { formState } = useFormContext()
39
+
40
+ const isDisabled =
41
+ (disableIfUntouched && !formState.isDirty) ||
42
+ (disableIfInvalid && !formState.isValid) ||
43
+ isDisabledProp
44
+
45
+ return (
46
+ <Button
47
+ {...rest}
48
+ ref={ref}
49
+ variant="primary"
50
+ type="submit"
51
+ isLoading={formState.isSubmitting || isLoading}
52
+ isDisabled={isDisabled}
53
+ >
54
+ {children}
55
+ </Button>
56
+ )
57
+ })
50
58
 
51
59
  SubmitButton.defaultProps = {
52
60
  label: 'Submit',
@@ -1,6 +1,6 @@
1
1
  import * as React from 'react'
2
- import { FieldValues, SubmitHandler } from 'react-hook-form'
3
- import { createContext } from '@chakra-ui/react-utils'
2
+ import { FieldValues, SubmitHandler, UnpackNestedValue } from 'react-hook-form'
3
+ import { createContext, MaybeRenderProp } from '@chakra-ui/react-utils'
4
4
  import {
5
5
  useStepper,
6
6
  useStep,
@@ -14,8 +14,16 @@ export interface StepState {
14
14
  resolver?: any
15
15
  isActive?: boolean
16
16
  isCompleted?: boolean
17
+ onSubmit?: FormStepSubmitHandler
17
18
  }
18
19
 
20
+ export type FormStepSubmitHandler<
21
+ TFieldValues extends FieldValues = FieldValues
22
+ > = (
23
+ data: UnpackNestedValue<TFieldValues>,
24
+ stepper: UseStepperReturn
25
+ ) => Promise<void>
26
+
19
27
  export interface StepFormContext extends UseStepperReturn {
20
28
  updateStep(state: StepState): void
21
29
  steps: Record<string, StepState>
@@ -32,11 +40,9 @@ import { FormProps } from './form'
32
40
 
33
41
  export interface UseStepFormProps<
34
42
  TFieldValues extends FieldValues = FieldValues
35
- > extends UseStepperProps,
43
+ > extends Omit<UseStepperProps, 'onChange'>,
36
44
  Omit<FormProps<TFieldValues>, 'children'> {
37
- children:
38
- | React.ReactNode
39
- | ((stepper: UseStepFormReturn<TFieldValues>) => React.ReactElement)
45
+ children: MaybeRenderProp<UseStepFormReturn<TFieldValues>>
40
46
  }
41
47
 
42
48
  export interface UseStepFormReturn<
@@ -54,7 +60,8 @@ export interface UseStepFormReturn<
54
60
  export function useStepForm<TFieldValues extends FieldValues = FieldValues>(
55
61
  props: UseStepFormProps<TFieldValues>
56
62
  ): UseStepFormReturn<TFieldValues> {
57
- const stepper = useStepper(props)
63
+ const { onChange, ...rest } = props
64
+ const stepper = useStepper(rest)
58
65
 
59
66
  const { activeStep, isLastStep, nextStep } = stepper
60
67
 
@@ -62,11 +69,12 @@ export function useStepForm<TFieldValues extends FieldValues = FieldValues>(
62
69
 
63
70
  const onSubmitStep: SubmitHandler<TFieldValues> = React.useCallback(
64
71
  async (data) => {
72
+ const step = steps[activeStep]
73
+
65
74
  if (isLastStep) {
66
75
  return props
67
76
  .onSubmit?.(data)
68
77
  .then(() => {
69
- const step = steps[activeStep]
70
78
  updateStep({
71
79
  ...step,
72
80
  isCompleted: true,
@@ -75,9 +83,15 @@ export function useStepForm<TFieldValues extends FieldValues = FieldValues>(
75
83
  .then(nextStep) // Show completed step
76
84
  }
77
85
 
78
- nextStep()
86
+ try {
87
+ await step.onSubmit?.(data, stepper)
88
+
89
+ nextStep()
90
+ } catch (e) {
91
+ // Step submission failed.
92
+ }
79
93
  },
80
- [activeStep, isLastStep]
94
+ [steps, activeStep, isLastStep]
81
95
  )
82
96
 
83
97
  const getFormProps = React.useCallback(() => {
@@ -113,16 +127,17 @@ export interface UseFormStepProps {
113
127
  name: string
114
128
  schema?: any
115
129
  resolver?: any
130
+ onSubmit?: FormStepSubmitHandler
116
131
  }
117
132
 
118
133
  export function useFormStep(props: UseFormStepProps): StepState {
119
- const { name, schema, resolver } = props
134
+ const { name, schema, resolver, onSubmit } = props
120
135
  const step = useStep({ name })
121
136
 
122
137
  const { steps, updateStep } = useStepFormContext()
123
138
 
124
139
  React.useEffect(() => {
125
- updateStep({ name, schema, resolver })
140
+ updateStep({ name, schema, resolver, onSubmit })
126
141
  }, [name, schema])
127
142
 
128
143
  return {
package/yup/package.json CHANGED
@@ -10,8 +10,8 @@
10
10
  "author": "Eelco Wiersma <eelco@appulse.nl>",
11
11
  "license": "MIT",
12
12
  "peerDependencies": {
13
- "@hookform/resolvers": "^2.8.3",
14
- "react-hook-form": "^7.22.0",
13
+ "@hookform/resolvers": "^2.9.0",
14
+ "react-hook-form": "^7.31.3",
15
15
  "yup": "^0.32.11"
16
16
  }
17
17
  }
package/zod/package.json CHANGED
@@ -10,9 +10,9 @@
10
10
  "author": "Eelco Wiersma <eelco@appulse.nl>",
11
11
  "license": "MIT",
12
12
  "peerDependencies": {
13
- "@chakra-ui/utils": "^2.0.0",
14
- "@hookform/resolvers": "^2.8.3",
15
- "react-hook-form": "^7.22.0",
16
- "zod": "^3.14.4"
13
+ "@chakra-ui/utils": "^2.0.2",
14
+ "@hookform/resolvers": "^2.9.0",
15
+ "react-hook-form": "^7.31.3",
16
+ "zod": "^3.17.3"
17
17
  }
18
18
  }