@saas-ui/forms 1.0.0-rc.1 → 1.0.0-rc.10

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.
Files changed (44) hide show
  1. package/CHANGELOG.md +107 -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 +97 -0
  9. package/dist/ajv/index.js.map +1 -0
  10. package/dist/ajv/index.modern.mjs +97 -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/layout.d.ts +0 -1
  24. package/dist/layout.d.ts.map +1 -1
  25. package/dist/step-form.d.ts +4 -4
  26. package/dist/step-form.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/zod/index.js +1 -1
  30. package/dist/zod/index.js.map +1 -1
  31. package/dist/zod/index.modern.mjs +1 -1
  32. package/dist/zod/index.modern.mjs.map +1 -1
  33. package/package.json +32 -17
  34. package/src/array-field.tsx +21 -22
  35. package/src/auto-form.tsx +22 -3
  36. package/src/field-resolver.ts +2 -2
  37. package/src/field.tsx +186 -71
  38. package/src/form.tsx +0 -1
  39. package/src/object-field.tsx +3 -3
  40. package/src/step-form.tsx +23 -17
  41. package/src/submit-button.tsx +1 -1
  42. package/src/use-step-form.tsx +27 -12
  43. package/yup/package.json +2 -2
  44. package/zod/package.json +4 -4
@@ -1,11 +1,11 @@
1
1
  import * as React from 'react'
2
2
 
3
- import { chakra, ResponsiveValue } from '@chakra-ui/system'
3
+ import { chakra, ResponsiveValue, forwardRef } from '@chakra-ui/system'
4
4
  import { __DEV__ } from '@chakra-ui/utils'
5
5
  import { AddIcon, MinusIcon } from '@chakra-ui/icons'
6
6
  import { IconButton, ButtonProps } from '@saas-ui/button'
7
7
 
8
- import { FormLayout } from './layout'
8
+ import { FormLayout, FormLayoutProps } from './layout'
9
9
  import { BaseField, FieldProps } from './field'
10
10
 
11
11
  import { mapNestedFields } from './utils'
@@ -28,7 +28,7 @@ interface ArrayField {
28
28
  [key: string]: unknown
29
29
  }
30
30
 
31
- interface ArrayFieldRowProps {
31
+ interface ArrayFieldRowProps extends FormLayoutProps {
32
32
  /**
33
33
  * Amount of field columns
34
34
  */
@@ -41,21 +41,20 @@ interface ArrayFieldRowProps {
41
41
  * The array index
42
42
  */
43
43
  index: number
44
-
44
+ /**
45
+ * The fields
46
+ */
45
47
  children: React.ReactNode
46
48
  }
47
49
 
48
50
  export const ArrayFieldRow: React.FC<ArrayFieldRowProps> = ({
49
51
  children,
50
- columns,
51
- spacing,
52
52
  index,
53
+ ...rowFieldsProps
53
54
  }) => {
54
55
  return (
55
56
  <ArrayFieldRowContainer index={index}>
56
- <ArrayFieldRowFields columns={columns} spacing={spacing}>
57
- {children}
58
- </ArrayFieldRowFields>
57
+ <ArrayFieldRowFields {...rowFieldsProps}>{children}</ArrayFieldRowFields>
59
58
  <ArrayFieldRemoveButton />
60
59
  </ArrayFieldRowContainer>
61
60
  )
@@ -65,7 +64,7 @@ if (__DEV__) {
65
64
  ArrayFieldRow.displayName = 'ArrayFieldRow'
66
65
  }
67
66
 
68
- export interface ArrayFieldRowFieldsProps {
67
+ export interface ArrayFieldRowFieldsProps extends FormLayoutProps {
69
68
  /**
70
69
  * Amount of field columns
71
70
  */
@@ -74,25 +73,19 @@ export interface ArrayFieldRowFieldsProps {
74
73
  * Spacing between fields
75
74
  */
76
75
  spacing?: ResponsiveValue<string | number>
77
-
76
+ /**
77
+ * The fields
78
+ */
78
79
  children: React.ReactNode
79
80
  }
80
81
 
81
82
  export const ArrayFieldRowFields: React.FC<ArrayFieldRowFieldsProps> = ({
82
83
  children,
83
- columns,
84
- spacing,
85
84
  ...layoutProps
86
85
  }) => {
87
86
  const { name } = useArrayFieldRowContext()
88
87
  return (
89
- <FormLayout
90
- flex="1"
91
- columns={columns}
92
- gridGap={spacing}
93
- mr="2"
94
- {...layoutProps}
95
- >
88
+ <FormLayout flex="1" mr="2" {...layoutProps}>
96
89
  {mapNestedFields(name, children)}
97
90
  </FormLayout>
98
91
  )
@@ -162,7 +155,7 @@ export interface ArrayFieldProps
162
155
  extends ArrayFieldOptions,
163
156
  Omit<FieldProps, 'defaultValue'> {}
164
157
 
165
- export const ArrayField = React.forwardRef(
158
+ export const ArrayField = forwardRef(
166
159
  (props: ArrayFieldProps, ref: React.ForwardedRef<UseArrayFieldReturn>) => {
167
160
  const { children, ...containerProps } = props
168
161
 
@@ -183,7 +176,13 @@ export const ArrayField = React.forwardRef(
183
176
  </ArrayFieldContainer>
184
177
  )
185
178
  }
186
- )
179
+ ) as ((
180
+ props: ArrayFieldProps & {
181
+ ref?: React.ForwardedRef<UseArrayFieldReturn>
182
+ }
183
+ ) => React.ReactElement) & {
184
+ displayName: string
185
+ }
187
186
 
188
187
  if (__DEV__) {
189
188
  ArrayField.displayName = 'ArrayField'
package/src/auto-form.tsx CHANGED
@@ -6,12 +6,24 @@ import { __DEV__ } from '@chakra-ui/utils'
6
6
  import { Form, FormProps } from './form'
7
7
  import { FormLayout } from './layout'
8
8
  import { Fields } from './fields'
9
- import { SubmitButton } from './submit-button'
9
+ import { SubmitButton, SubmitButtonProps } from './submit-button'
10
10
  import { FieldResolver } from '.'
11
11
 
12
12
  interface AutoFormOptions {
13
- submitLabel?: false | string
13
+ /**
14
+ * The submit button label.
15
+ * Pass `null` to render no submit button.
16
+ */
17
+ submitLabel?: React.ReactNode
18
+ /**
19
+ * The schema.
20
+ * Supports object schema, Yup or Zod.
21
+ * @see https://www.saas-ui.dev/docs/forms/auto-form
22
+ */
14
23
  schema: any
24
+ /**
25
+ * The field resolver.
26
+ */
15
27
  fieldResolver?: any
16
28
  }
17
29
 
@@ -24,13 +36,20 @@ export const AutoForm = forwardRef(
24
36
  props: AutoFormProps<TFieldValues>,
25
37
  ref: React.ForwardedRef<UseFormReturn<TFieldValues>>
26
38
  ) => {
27
- const { schema, submitLabel = 'Submit', fieldResolver, ...rest } = props
39
+ const {
40
+ schema,
41
+ submitLabel = 'Submit',
42
+ fieldResolver,
43
+ children,
44
+ ...rest
45
+ } = props
28
46
 
29
47
  return (
30
48
  <Form {...rest} schema={schema} ref={ref}>
31
49
  <FormLayout>
32
50
  {<Fields schema={schema} fieldResolver={fieldResolver} />}
33
51
  {submitLabel && <SubmitButton label={submitLabel} />}
52
+ {children}
34
53
  </FormLayout>
35
54
  </Form>
36
55
  )
@@ -14,9 +14,9 @@ interface SchemaField extends FieldProps {
14
14
 
15
15
  export type ObjectSchema = Record<string, SchemaField>
16
16
 
17
- const mapFields = (schema: ObjectSchema) =>
17
+ const mapFields = (schema: ObjectSchema): FieldProps[] =>
18
18
  schema &&
19
- Object.entries(schema).map(([name, field]) => {
19
+ Object.entries(schema).map(([name, { items, ...field }]) => {
20
20
  return {
21
21
  ...field,
22
22
  name,
package/src/field.tsx CHANGED
@@ -22,14 +22,30 @@ import {
22
22
  Checkbox,
23
23
  Switch,
24
24
  useMergeRefs,
25
+ InputGroup,
26
+ InputProps,
27
+ TextareaProps,
28
+ SwitchProps,
29
+ CheckboxProps,
30
+ PinInputProps,
31
+ PinInputField,
32
+ HStack,
33
+ PinInput,
34
+ UsePinInputProps,
35
+ SystemProps,
25
36
  } from '@chakra-ui/react'
26
37
  import { __DEV__ } from '@chakra-ui/utils'
27
38
 
28
- import { NumberInput } from '@saas-ui/number-input'
29
- import { PasswordInput } from '@saas-ui/password-input'
30
- import { RadioInput } from '@saas-ui/radio'
31
- import { PinInput } from '@saas-ui/pin-input'
32
- import { Select, NativeSelect } from '@saas-ui/select'
39
+ import { NumberInput, NumberInputProps } from '@saas-ui/number-input'
40
+ import { PasswordInput, PasswordInputProps } from '@saas-ui/password-input'
41
+ import { RadioInput, RadioInputProps } from '@saas-ui/radio'
42
+
43
+ import {
44
+ Select,
45
+ SelectProps,
46
+ NativeSelect,
47
+ NativeSelectProps,
48
+ } from '@saas-ui/select'
33
49
  import { FocusableElement } from '@chakra-ui/utils'
34
50
 
35
51
  export interface Option {
@@ -43,19 +59,6 @@ export type FieldRules = Pick<
43
59
  'required' | 'min' | 'max' | 'maxLength' | 'minLength' | 'pattern'
44
60
  >
45
61
 
46
- export type FieldTypes =
47
- | 'text'
48
- | 'number'
49
- | 'password'
50
- | 'textarea'
51
- | 'select'
52
- | 'native-select'
53
- | 'checkbox'
54
- | 'radio'
55
- | 'switch'
56
- | 'pin'
57
- | string
58
-
59
62
  export interface FieldProps<
60
63
  TFieldValues extends FieldValues = FieldValues,
61
64
  TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>
@@ -84,11 +87,6 @@ export interface FieldProps<
84
87
  'valueAsNumber' | 'valueAsDate' | 'setValueAs' | 'disabled'
85
88
  >
86
89
  /**
87
- * Options used for selects and radio fields
88
- */
89
- options?: Option[]
90
- /**
91
- * The field type
92
90
  * Build-in types:
93
91
  * - text
94
92
  * - number
@@ -102,16 +100,15 @@ export interface FieldProps<
102
100
  * - pin
103
101
  *
104
102
  * Will default to a text field if there is no matching type.
105
- * @default 'text'
106
103
  */
107
- type?: FieldTypes
104
+ type?: string
108
105
  /**
109
106
  * The input placeholder
110
107
  */
111
108
  placeholder?: string
112
109
  }
113
110
 
114
- const inputTypes: Record<FieldTypes, any> = {}
111
+ const inputTypes: Record<string, React.FC<any>> = {}
115
112
 
116
113
  const defaultInputType = 'text'
117
114
 
@@ -160,11 +157,30 @@ if (__DEV__) {
160
157
  BaseField.displayName = 'BaseField'
161
158
  }
162
159
 
163
- export const Field = forwardRef(
160
+ export type As<Props = any> = React.ElementType<Props>
161
+
162
+ export type PropsOf<T extends As> = React.ComponentPropsWithoutRef<T> & {
163
+ type?: FieldTypes
164
+ }
165
+
166
+ /**
167
+ * Build-in types:
168
+ * - text
169
+ * - number
170
+ * - password
171
+ * - textarea
172
+ * - select
173
+ * - native-select
174
+ * - checkbox
175
+ * - radio
176
+ * - switch
177
+ * - pin
178
+ *
179
+ * Will default to a text field if there is no matching type.
180
+ */
181
+ export const Field = React.forwardRef(
164
182
  <TFieldValues extends FieldValues = FieldValues>(
165
- props: FieldProps<TFieldValues> & {
166
- [key: string]: unknown // Make sure attributes of custom components work. Need to change this to a global typedef at some point.
167
- },
183
+ props: FieldProps<TFieldValues> | FieldTypeProps,
168
184
  ref: React.ForwardedRef<FocusableElement>
169
185
  ) => {
170
186
  const { type = defaultInputType } = props
@@ -172,13 +188,14 @@ export const Field = forwardRef(
172
188
 
173
189
  return <InputComponent ref={ref} {...props} />
174
190
  }
175
- ) as <TFieldValues extends FieldValues>(
176
- props: FieldProps<TFieldValues> & {
177
- [key: string]: unknown
178
- } & {
179
- ref?: React.ForwardedRef<FocusableElement>
180
- }
181
- ) => React.ReactElement
191
+ ) as (<TFieldValues extends FieldValues>(
192
+ props: FieldProps<TFieldValues> &
193
+ FieldTypeProps & {
194
+ ref?: React.ForwardedRef<FocusableElement>
195
+ }
196
+ ) => React.ReactElement) & {
197
+ displayName?: string
198
+ }
182
199
 
183
200
  interface CreateFieldProps {
184
201
  displayName: string
@@ -190,7 +207,7 @@ const createField = (
190
207
  InputComponent: React.FC<any>,
191
208
  { displayName, hideLabel, BaseField }: CreateFieldProps
192
209
  ) => {
193
- const Field = forwardRef<FieldProps, typeof FormControl>((props, ref) => {
210
+ const Field = forwardRef((props, ref) => {
194
211
  const {
195
212
  id,
196
213
  name,
@@ -200,6 +217,7 @@ const createField = (
200
217
  isInvalid,
201
218
  isReadOnly,
202
219
  isRequired,
220
+ isOptional,
203
221
  rules,
204
222
  variant,
205
223
  ...inputProps
@@ -221,13 +239,14 @@ const createField = (
221
239
  isInvalid={isInvalid}
222
240
  isReadOnly={isReadOnly}
223
241
  isRequired={isRequired}
242
+ isOptional={isOptional}
224
243
  variant={variant}
225
244
  >
226
245
  <InputComponent
227
246
  ref={ref}
228
247
  id={id}
229
248
  name={name}
230
- label={label}
249
+ label={hideLabel ? label : undefined} // Only pass down the label when it should be inline.
231
250
  rules={inputRules}
232
251
  {...inputProps}
233
252
  />
@@ -239,7 +258,7 @@ const createField = (
239
258
  return Field
240
259
  }
241
260
 
242
- export const withControlledInput = (InputComponent: any) => {
261
+ export const withControlledInput = (InputComponent: React.FC<any>) => {
243
262
  return forwardRef<FieldProps, typeof InputComponent>(
244
263
  ({ name, rules, ...inputProps }, ref) => {
245
264
  const { control } = useFormContext()
@@ -262,7 +281,7 @@ export const withControlledInput = (InputComponent: any) => {
262
281
  )
263
282
  }
264
283
 
265
- export const withUncontrolledInput = (InputComponent: any) => {
284
+ export const withUncontrolledInput = (InputComponent: React.FC<any>) => {
266
285
  return forwardRef<FieldProps, typeof InputComponent>(
267
286
  ({ name, rules, ...inputProps }, ref) => {
268
287
  const { register } = useFormContext()
@@ -292,11 +311,11 @@ export interface RegisterFieldTypeOptions {
292
311
  * @param component The React component
293
312
  * @param options
294
313
  * @param options.isControlled Set this to true if this is a controlled field.
295
- * @param options.hideLabel Hide the field label, for example for checkbox or switch field.
314
+ * @param options.hideLabel Hide the field label, for example for the checkbox field.
296
315
  */
297
- export const registerFieldType = (
316
+ export const registerFieldType = <T extends object>(
298
317
  type: string,
299
- component: React.FC<any>,
318
+ component: React.FC<T>,
300
319
  options?: RegisterFieldTypeOptions
301
320
  ) => {
302
321
  let InputComponent
@@ -313,41 +332,75 @@ export const registerFieldType = (
313
332
  .join('')}Field`,
314
333
  hideLabel: options?.hideLabel,
315
334
  BaseField: options?.BaseField || BaseField,
316
- })
335
+ }) as React.FC<T & FieldProps>
317
336
 
318
337
  inputTypes[type] = Field
319
338
 
320
339
  return Field
321
340
  }
322
341
 
323
- // @todo Consider not registering all fields by default to lower the package size and computations.
324
- // Not all types may be required in a project.
325
- export const InputField = registerFieldType('text', Input)
326
- export const NumberInputField = registerFieldType('number', NumberInput, {
327
- isControlled: true,
328
- })
329
- export const PasswordInputFIeld = registerFieldType('password', PasswordInput)
330
- export const TextareaField = registerFieldType('textarea', Textarea)
331
- export const SwitchField = registerFieldType(
342
+ export interface InputFieldProps extends InputProps {
343
+ type?: string
344
+ leftAddon?: React.ReactNode
345
+ rightAddon?: React.ReactNode
346
+ }
347
+
348
+ export const InputField = registerFieldType<InputFieldProps>(
349
+ 'text',
350
+ forwardRef(({ type = 'text', leftAddon, rightAddon, size, ...rest }, ref) => {
351
+ const input = <Input type={type} size={size} {...rest} ref={ref} />
352
+ if (leftAddon || rightAddon) {
353
+ return (
354
+ <InputGroup size={size}>
355
+ {leftAddon}
356
+ {input}
357
+ {rightAddon}
358
+ </InputGroup>
359
+ )
360
+ }
361
+ return input
362
+ })
363
+ )
364
+
365
+ export interface NumberInputFieldProps extends NumberInputProps {
366
+ type: 'number'
367
+ }
368
+
369
+ export const NumberInputField = registerFieldType<NumberInputFieldProps>(
370
+ 'number',
371
+ NumberInput,
372
+ {
373
+ isControlled: true,
374
+ }
375
+ )
376
+
377
+ export const PasswordInputField = registerFieldType<PasswordInputProps>(
378
+ 'password',
379
+ forwardRef((props, ref) => <PasswordInput ref={ref} {...props} />)
380
+ )
381
+
382
+ export const TextareaField = registerFieldType<TextareaProps>(
383
+ 'textarea',
384
+ Textarea
385
+ )
386
+
387
+ export const SwitchField = registerFieldType<SwitchProps>(
332
388
  'switch',
333
- forwardRef(({ label, ...props }: { label?: string }, ref) => {
334
- return (
335
- <Switch ref={ref} {...props}>
336
- {label}
337
- </Switch>
338
- )
389
+ forwardRef(({ type, ...rest }, ref) => {
390
+ return <Switch {...rest} ref={ref} />
339
391
  }),
340
392
  {
341
393
  isControlled: true,
342
- hideLabel: true,
343
394
  }
344
395
  )
345
- export const SelectField = registerFieldType('select', Select, {
396
+
397
+ export const SelectField = registerFieldType<SelectProps>('select', Select, {
346
398
  isControlled: true,
347
399
  })
348
- export const CheckboxField = registerFieldType(
400
+
401
+ export const CheckboxField = registerFieldType<CheckboxProps>(
349
402
  'checkbox',
350
- forwardRef(({ label, ...props }: { label?: string }, ref) => {
403
+ forwardRef(({ label, type, ...props }, ref) => {
351
404
  return (
352
405
  <Checkbox ref={ref} {...props}>
353
406
  {label}
@@ -358,14 +411,76 @@ export const CheckboxField = registerFieldType(
358
411
  hideLabel: true,
359
412
  }
360
413
  )
361
- export const RadioField = registerFieldType('radio', RadioInput, {
362
- isControlled: true,
363
- })
364
- export const PinField = registerFieldType('pin', PinInput, {
365
- isControlled: true,
366
- })
367
- export const NativeSelectField = registerFieldType(
414
+
415
+ export const RadioField = registerFieldType<RadioInputProps>(
416
+ 'radio',
417
+ RadioInput,
418
+ {
419
+ isControlled: true,
420
+ }
421
+ )
422
+
423
+ export const NativeSelectField = registerFieldType<NativeSelectProps>(
368
424
  'native-select',
369
425
  NativeSelect,
370
426
  { isControlled: true }
371
427
  )
428
+
429
+ export interface PinFieldProps extends Omit<UsePinInputProps, 'type'> {
430
+ pinLength?: number
431
+ pinType?: 'alphanumeric' | 'number'
432
+ spacing?: SystemProps['margin']
433
+ }
434
+
435
+ export const PinField = registerFieldType<PinFieldProps>(
436
+ 'pin',
437
+ forwardRef((props, ref) => {
438
+ const { pinLength = 4, pinType, spacing, ...inputProps } = props
439
+
440
+ const inputs: React.ReactNode[] = []
441
+ for (let i = 0; i < pinLength; i++) {
442
+ inputs.push(<PinInputField key={i} ref={ref} />)
443
+ }
444
+
445
+ return (
446
+ <HStack spacing={spacing}>
447
+ <PinInput {...inputProps} type={pinType}>
448
+ {inputs}
449
+ </PinInput>
450
+ </HStack>
451
+ )
452
+ }),
453
+ {
454
+ isControlled: true,
455
+ }
456
+ )
457
+
458
+ const fieldTypes = {
459
+ text: InputField,
460
+ email: InputField,
461
+ url: InputField,
462
+ phone: InputField,
463
+ number: NumberInputField,
464
+ password: PasswordInputField,
465
+ textarea: TextareaField,
466
+ switch: SwitchField,
467
+ checkbox: CheckboxField,
468
+ radio: RadioField,
469
+ pin: PinField,
470
+ select: SelectField,
471
+ 'native-select': NativeSelectField,
472
+ }
473
+
474
+ type FieldTypes = typeof fieldTypes
475
+
476
+ type FieldType<Props = any> = React.ElementType<Props>
477
+
478
+ type TypeProps<P extends FieldType, T> = React.ComponentPropsWithoutRef<P> & {
479
+ type: T
480
+ }
481
+
482
+ type FieldTypeProps =
483
+ | {
484
+ [Property in keyof FieldTypes]: TypeProps<FieldTypes[Property], Property>
485
+ }[keyof FieldTypes]
486
+ | { type?: string }
package/src/form.tsx CHANGED
@@ -16,7 +16,6 @@ import {
16
16
  ResolverResult,
17
17
  } from 'react-hook-form'
18
18
  import { objectFieldResolver, FieldResolver } from './field-resolver'
19
- import { css } from '@emotion/react'
20
19
 
21
20
  export type { UseFormReturn, FieldValues, SubmitHandler }
22
21
 
@@ -4,7 +4,7 @@ import {
4
4
  FormLabel,
5
5
  FormLabelProps,
6
6
  ResponsiveValue,
7
- useStyles,
7
+ useStyleConfig,
8
8
  } from '@chakra-ui/react'
9
9
  import { __DEV__ } from '@chakra-ui/utils'
10
10
 
@@ -21,8 +21,8 @@ export interface ObjectFieldProps extends FieldProps {
21
21
  }
22
22
 
23
23
  export const FormLegend = (props: FormLabelProps) => {
24
- const styles = useStyles()
25
- return <FormLabel as="legend" sx={styles.legend} {...props} />
24
+ const styles = useStyleConfig('FormLegend')
25
+ return <FormLabel as="legend" sx={styles} {...props} />
26
26
  }
27
27
 
28
28
  export const ObjectField: React.FC<ObjectFieldProps> = (props) => {
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
 
@@ -37,7 +37,7 @@ export const SubmitButton = forwardRef<SubmitButtonProps, 'button'>(
37
37
  <Button
38
38
  type="submit"
39
39
  isLoading={formState.isSubmitting}
40
- isPrimary
40
+ colorScheme="primary"
41
41
  ref={ref}
42
42
  isDisabled={isDisabled}
43
43
  {...rest}