@saas-ui/forms 2.0.0-next.2 → 2.0.0-next.5
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 +36 -0
- package/README.md +53 -6
- package/dist/ajv/index.d.ts +1 -1
- package/dist/ajv/index.js.map +1 -1
- package/dist/ajv/index.mjs.map +1 -1
- package/dist/index.d.ts +265 -166
- package/dist/index.js +2821 -556
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +2814 -555
- package/dist/index.mjs.map +1 -1
- package/dist/yup/index.d.ts +98 -6
- package/dist/yup/index.js.map +1 -1
- package/dist/yup/index.mjs.map +1 -1
- package/dist/zod/index.d.ts +97 -4
- package/dist/zod/index.js.map +1 -1
- package/dist/zod/index.mjs.map +1 -1
- package/package.json +5 -3
- package/src/array-field.tsx +50 -30
- package/src/auto-form.tsx +7 -3
- package/src/base-field.tsx +59 -0
- package/src/create-field.tsx +143 -0
- package/src/create-form.tsx +31 -0
- package/src/default-fields.tsx +146 -0
- package/src/display-field.tsx +8 -9
- package/src/display-if.tsx +6 -5
- package/src/field-resolver.ts +1 -1
- package/src/field.tsx +14 -444
- package/src/fields-context.tsx +23 -0
- package/src/fields.tsx +18 -8
- package/src/form.tsx +27 -37
- package/src/index.ts +38 -0
- package/src/input-right-button/input-right-button.stories.tsx +1 -1
- package/src/input-right-button/input-right-button.tsx +0 -2
- package/src/layout.tsx +16 -11
- package/src/number-input/number-input.tsx +9 -5
- package/src/object-field.tsx +8 -7
- package/src/password-input/password-input.stories.tsx +23 -2
- package/src/password-input/password-input.tsx +5 -5
- package/src/pin-input/pin-input.tsx +1 -5
- package/src/radio/radio-input.stories.tsx +1 -1
- package/src/radio/radio-input.tsx +12 -10
- package/src/select/native-select.tsx +1 -4
- package/src/select/select.test.tsx +1 -1
- package/src/select/select.tsx +18 -14
- package/src/step-form.tsx +29 -11
- package/src/submit-button.tsx +5 -1
- package/src/types.ts +91 -0
- package/src/utils.ts +15 -0
- /package/src/radio/{radio.test.tsx → radio-input.test.tsx} +0 -0
package/src/index.ts
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
export * from './display-field'
|
2
2
|
export * from './field'
|
3
3
|
export * from './fields'
|
4
|
+
export * from './fields-context'
|
4
5
|
export * from './form'
|
5
6
|
export * from './auto-form'
|
6
7
|
export * from './layout'
|
@@ -16,6 +17,43 @@ export * from './watch-field'
|
|
16
17
|
export * from './input-right-button'
|
17
18
|
export * from './select'
|
18
19
|
export * from './password-input'
|
20
|
+
export * from './radio'
|
21
|
+
|
22
|
+
export * from './base-field'
|
23
|
+
|
24
|
+
export {
|
25
|
+
CheckboxField,
|
26
|
+
InputField,
|
27
|
+
NativeSelectField,
|
28
|
+
NumberInputField,
|
29
|
+
PasswordInputField,
|
30
|
+
PinField,
|
31
|
+
RadioField,
|
32
|
+
SelectField,
|
33
|
+
SwitchField,
|
34
|
+
TextareaField,
|
35
|
+
defaultFieldTypes,
|
36
|
+
} from './default-fields'
|
37
|
+
|
38
|
+
export type {
|
39
|
+
DefaultFields,
|
40
|
+
InputFieldProps,
|
41
|
+
NumberInputFieldProps,
|
42
|
+
PinFieldProps,
|
43
|
+
} from './default-fields'
|
44
|
+
|
45
|
+
export type {
|
46
|
+
FieldProps,
|
47
|
+
WithFields,
|
48
|
+
BaseFieldProps,
|
49
|
+
FieldOptions,
|
50
|
+
} from './types'
|
51
|
+
|
52
|
+
export { createForm } from './create-form'
|
53
|
+
export type { CreateFormProps } from './create-form'
|
54
|
+
|
55
|
+
export { createField } from './create-field'
|
56
|
+
export type { CreateFieldOptions } from './create-field'
|
19
57
|
|
20
58
|
export type {
|
21
59
|
BatchFieldArrayUpdate,
|
package/src/layout.tsx
CHANGED
@@ -1,9 +1,15 @@
|
|
1
1
|
import * as React from 'react'
|
2
2
|
|
3
|
-
import {
|
4
|
-
|
3
|
+
import {
|
4
|
+
chakra,
|
5
|
+
ResponsiveValue,
|
6
|
+
SimpleGrid,
|
7
|
+
SimpleGridProps,
|
8
|
+
useTheme,
|
9
|
+
} from '@chakra-ui/react'
|
10
|
+
import { cx } from '@chakra-ui/utils'
|
5
11
|
|
6
|
-
export
|
12
|
+
export interface FormLayoutProps extends SimpleGridProps {}
|
7
13
|
|
8
14
|
interface FormLayoutItemProps {
|
9
15
|
children: React.ReactNode
|
@@ -13,20 +19,21 @@ const FormLayoutItem: React.FC<FormLayoutItemProps> = ({ children }) => {
|
|
13
19
|
return <chakra.div>{children}</chakra.div>
|
14
20
|
}
|
15
21
|
|
16
|
-
|
17
|
-
FormLayoutItem.displayName = 'FormLayoutItem'
|
18
|
-
}
|
22
|
+
FormLayoutItem.displayName = 'FormLayoutItem'
|
19
23
|
|
20
24
|
/**
|
21
|
-
*
|
25
|
+
* Create consistent field spacing and positioning.
|
26
|
+
*
|
22
27
|
*
|
23
28
|
* Renders form items in a `SimpleGrid`
|
24
29
|
* @see https://chakra-ui.com/docs/layout/simple-grid
|
30
|
+
*
|
31
|
+
* @see https://saas-ui.dev/docs/components/forms/form
|
25
32
|
*/
|
26
33
|
export const FormLayout = ({ children, ...props }: FormLayoutProps) => {
|
27
34
|
const theme = useTheme()
|
28
35
|
|
29
|
-
const defaultProps = theme.components?.
|
36
|
+
const defaultProps = theme.components?.SuiFormLayout?.defaultProps ?? {
|
30
37
|
spacing: 4,
|
31
38
|
}
|
32
39
|
|
@@ -50,6 +57,4 @@ export const FormLayout = ({ children, ...props }: FormLayoutProps) => {
|
|
50
57
|
)
|
51
58
|
}
|
52
59
|
|
53
|
-
|
54
|
-
FormLayout.displayName = 'FormLayout'
|
55
|
-
}
|
60
|
+
FormLayout.displayName = 'FormLayout'
|
@@ -9,7 +9,8 @@ import {
|
|
9
9
|
NumberDecrementStepper,
|
10
10
|
NumberInputProps as ChakraNumberInputProps,
|
11
11
|
} from '@chakra-ui/react'
|
12
|
-
|
12
|
+
|
13
|
+
import { ChevronDownIcon, ChevronUpIcon } from '@saas-ui/core'
|
13
14
|
|
14
15
|
interface NumberInputOptions {
|
15
16
|
/**
|
@@ -31,7 +32,12 @@ export interface NumberInputProps
|
|
31
32
|
NumberInputOptions {}
|
32
33
|
|
33
34
|
export const NumberInput = forwardRef<NumberInputProps, 'div'>((props, ref) => {
|
34
|
-
const {
|
35
|
+
const {
|
36
|
+
hideStepper,
|
37
|
+
incrementIcon = <ChevronUpIcon />,
|
38
|
+
decrementIcon = <ChevronDownIcon />,
|
39
|
+
...rest
|
40
|
+
} = props
|
35
41
|
|
36
42
|
return (
|
37
43
|
<ChakraNumberInput {...rest} ref={ref}>
|
@@ -51,6 +57,4 @@ NumberInput.defaultProps = {
|
|
51
57
|
hideStepper: false,
|
52
58
|
}
|
53
59
|
|
54
|
-
|
55
|
-
NumberInput.displayName = 'NumberInput'
|
56
|
-
}
|
60
|
+
NumberInput.displayName = 'NumberInput'
|
package/src/object-field.tsx
CHANGED
@@ -6,14 +6,13 @@ import {
|
|
6
6
|
ResponsiveValue,
|
7
7
|
useStyleConfig,
|
8
8
|
} from '@chakra-ui/react'
|
9
|
-
import { __DEV__ } from '@chakra-ui/utils'
|
10
9
|
|
11
10
|
import { FormLayout } from './layout'
|
12
|
-
import {
|
11
|
+
import { BaseFieldProps } from './types'
|
13
12
|
|
14
13
|
import { mapNestedFields } from './utils'
|
15
14
|
|
16
|
-
export interface ObjectFieldProps extends
|
15
|
+
export interface ObjectFieldProps extends BaseFieldProps {
|
17
16
|
name: string
|
18
17
|
children: React.ReactNode
|
19
18
|
columns?: ResponsiveValue<number>
|
@@ -24,7 +23,11 @@ export const FormLegend = (props: FormLabelProps) => {
|
|
24
23
|
const styles = useStyleConfig('SuiFormLegend')
|
25
24
|
return <FormLabel as="legend" sx={styles} {...props} />
|
26
25
|
}
|
27
|
-
|
26
|
+
/**
|
27
|
+
* The object field component.
|
28
|
+
*
|
29
|
+
* @see Docs https://saas-ui.dev/docs/components/forms/object-field
|
30
|
+
*/
|
28
31
|
export const ObjectField: React.FC<ObjectFieldProps> = (props) => {
|
29
32
|
const { name, label, hideLabel, children, columns, spacing, ...fieldProps } =
|
30
33
|
props
|
@@ -39,6 +42,4 @@ export const ObjectField: React.FC<ObjectFieldProps> = (props) => {
|
|
39
42
|
)
|
40
43
|
}
|
41
44
|
|
42
|
-
|
43
|
-
ObjectField.displayName = 'ObjectField'
|
44
|
-
}
|
45
|
+
ObjectField.displayName = 'ObjectField'
|
@@ -1,8 +1,15 @@
|
|
1
|
-
import {
|
1
|
+
import {
|
2
|
+
Container,
|
3
|
+
FormControl,
|
4
|
+
FormLabel,
|
5
|
+
Icon,
|
6
|
+
InputLeftAddon,
|
7
|
+
InputLeftElement,
|
8
|
+
} from '@chakra-ui/react'
|
2
9
|
import { Story } from '@storybook/react'
|
3
10
|
import * as React from 'react'
|
4
11
|
|
5
|
-
import { FiEye, FiEyeOff } from 'react-icons/fi'
|
12
|
+
import { FiEye, FiEyeOff, FiLock } from 'react-icons/fi'
|
6
13
|
|
7
14
|
import { PasswordInput } from './password-input'
|
8
15
|
|
@@ -48,3 +55,17 @@ export const CustomWidth: Story = () => (
|
|
48
55
|
<PasswordInput name="password" width="200px" />
|
49
56
|
</FormControl>
|
50
57
|
)
|
58
|
+
|
59
|
+
export const LeftAddon: Story = () => (
|
60
|
+
<FormControl>
|
61
|
+
<FormLabel>Password</FormLabel>
|
62
|
+
<PasswordInput
|
63
|
+
name="password"
|
64
|
+
leftAddon={
|
65
|
+
<InputLeftElement>
|
66
|
+
<FiLock />
|
67
|
+
</InputLeftElement>
|
68
|
+
}
|
69
|
+
/>
|
70
|
+
</FormControl>
|
71
|
+
)
|
@@ -1,7 +1,7 @@
|
|
1
1
|
import React, { useState } from 'react'
|
2
2
|
|
3
3
|
import { forwardRef, InputGroup, Input, InputProps } from '@chakra-ui/react'
|
4
|
-
|
4
|
+
|
5
5
|
import { ViewIcon, ViewOffIcon } from '@chakra-ui/icons'
|
6
6
|
|
7
7
|
import { InputRightButton } from '../input-right-button'
|
@@ -9,6 +9,7 @@ import { InputRightButton } from '../input-right-button'
|
|
9
9
|
interface PasswordOptions {
|
10
10
|
viewIcon?: React.ReactNode
|
11
11
|
viewOffIcon?: React.ReactNode
|
12
|
+
leftAddon?: React.ReactNode
|
12
13
|
}
|
13
14
|
|
14
15
|
export interface PasswordInputProps extends InputProps, PasswordOptions {}
|
@@ -23,6 +24,7 @@ export const PasswordInput = forwardRef<PasswordInputProps, 'div'>(
|
|
23
24
|
width,
|
24
25
|
size,
|
25
26
|
variant,
|
27
|
+
leftAddon,
|
26
28
|
...inputProps
|
27
29
|
} = props
|
28
30
|
const [show, setShow] = useState(false)
|
@@ -45,13 +47,13 @@ export const PasswordInput = forwardRef<PasswordInputProps, 'div'>(
|
|
45
47
|
|
46
48
|
return (
|
47
49
|
<InputGroup {...groupProps}>
|
50
|
+
{leftAddon}
|
48
51
|
<Input
|
49
52
|
{...inputProps}
|
50
53
|
ref={ref}
|
51
54
|
type={show ? 'text' : 'password'}
|
52
55
|
autoComplete={show ? 'off' : autoComplete}
|
53
56
|
/>
|
54
|
-
|
55
57
|
<InputRightButton
|
56
58
|
onClick={handleClick}
|
57
59
|
aria-label={label}
|
@@ -64,6 +66,4 @@ export const PasswordInput = forwardRef<PasswordInputProps, 'div'>(
|
|
64
66
|
}
|
65
67
|
)
|
66
68
|
|
67
|
-
|
68
|
-
PasswordInput.displayName = 'PasswordInput'
|
69
|
-
}
|
69
|
+
PasswordInput.displayName = 'PasswordInput'
|
@@ -8,8 +8,6 @@ import {
|
|
8
8
|
SystemProps,
|
9
9
|
} from '@chakra-ui/react'
|
10
10
|
|
11
|
-
import { __DEV__ } from '@chakra-ui/utils'
|
12
|
-
|
13
11
|
interface PinInputOptions {
|
14
12
|
/**
|
15
13
|
* The pin length.
|
@@ -45,6 +43,4 @@ PinInput.defaultProps = {
|
|
45
43
|
pinLength: 4,
|
46
44
|
}
|
47
45
|
|
48
|
-
|
49
|
-
PinInput.displayName = 'PinInput'
|
50
|
-
}
|
46
|
+
PinInput.displayName = 'PinInput'
|
@@ -10,15 +10,17 @@ import {
|
|
10
10
|
SystemProps,
|
11
11
|
StackDirection,
|
12
12
|
} from '@chakra-ui/react'
|
13
|
-
import {
|
13
|
+
import { FieldOptions, FieldOption } from '../types'
|
14
|
+
import { mapOptions } from '../utils'
|
14
15
|
|
15
|
-
interface
|
16
|
-
value
|
17
|
-
|
18
|
-
|
16
|
+
export interface RadioOption
|
17
|
+
extends Omit<RadioProps, 'value' | 'label'>,
|
18
|
+
FieldOption {}
|
19
|
+
|
20
|
+
export type RadioOptions = FieldOptions<RadioOption>
|
19
21
|
|
20
22
|
interface RadioInputOptions {
|
21
|
-
options:
|
23
|
+
options: RadioOptions
|
22
24
|
spacing?: SystemProps['margin']
|
23
25
|
direction?: StackDirection
|
24
26
|
}
|
@@ -28,9 +30,11 @@ export interface RadioInputProps
|
|
28
30
|
RadioInputOptions {}
|
29
31
|
|
30
32
|
export const RadioInput = forwardRef<RadioInputProps, 'div'>(
|
31
|
-
({ options, spacing, direction, ...props }, ref) => {
|
33
|
+
({ options: optionsProp, spacing, direction, ...props }, ref) => {
|
32
34
|
const { onBlur, onChange, ...groupProps } = props
|
33
35
|
|
36
|
+
const options = mapOptions(optionsProp)
|
37
|
+
|
34
38
|
return (
|
35
39
|
<RadioGroup onChange={onChange} {...groupProps}>
|
36
40
|
<Stack spacing={spacing} direction={direction}>
|
@@ -53,6 +57,4 @@ export const RadioInput = forwardRef<RadioInputProps, 'div'>(
|
|
53
57
|
}
|
54
58
|
)
|
55
59
|
|
56
|
-
|
57
|
-
RadioInput.displayName = 'RadioInput'
|
58
|
-
}
|
60
|
+
RadioInput.displayName = 'RadioInput'
|
@@ -5,7 +5,6 @@ import {
|
|
5
5
|
Select as ChakraSelect,
|
6
6
|
SelectProps as ChakraSelectProps,
|
7
7
|
} from '@chakra-ui/react'
|
8
|
-
import { __DEV__ } from '@chakra-ui/utils'
|
9
8
|
|
10
9
|
interface Option {
|
11
10
|
value: string
|
@@ -37,6 +36,4 @@ export const NativeSelect = forwardRef<NativeSelectProps, 'select'>(
|
|
37
36
|
}
|
38
37
|
)
|
39
38
|
|
40
|
-
|
41
|
-
NativeSelect.displayName = 'NativeSelect'
|
42
|
-
}
|
39
|
+
NativeSelect.displayName = 'NativeSelect'
|
package/src/select/select.tsx
CHANGED
@@ -18,21 +18,24 @@ import {
|
|
18
18
|
SystemStyleObject,
|
19
19
|
useFormControl,
|
20
20
|
HTMLChakraProps,
|
21
|
+
MenuItemOptionProps,
|
21
22
|
} from '@chakra-ui/react'
|
22
|
-
import {
|
23
|
-
import {
|
23
|
+
import { cx } from '@chakra-ui/utils'
|
24
|
+
import { ChevronDownIcon } from '@saas-ui/core'
|
24
25
|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
26
|
+
import { FieldOptions, FieldOption } from '../types'
|
27
|
+
import { mapOptions } from '../utils'
|
28
|
+
|
29
|
+
export interface SelectOption
|
30
|
+
extends Omit<MenuItemOptionProps, 'value'>,
|
31
|
+
FieldOption {}
|
29
32
|
|
30
33
|
interface SelectOptions {
|
31
34
|
/**
|
32
35
|
* An array of options
|
33
36
|
* If you leave this empty the children prop will be rendered.
|
34
37
|
*/
|
35
|
-
options?:
|
38
|
+
options?: FieldOptions<SelectOption>
|
36
39
|
/**
|
37
40
|
* Props passed to the MenuList.
|
38
41
|
*/
|
@@ -80,14 +83,12 @@ const SelectButton = forwardRef((props, ref) => {
|
|
80
83
|
return <MenuButton as={Button} {...props} ref={ref} sx={buttonStyles} />
|
81
84
|
})
|
82
85
|
|
83
|
-
|
84
|
-
SelectButton.displayName = 'SelectButton'
|
85
|
-
}
|
86
|
+
SelectButton.displayName = 'SelectButton'
|
86
87
|
|
87
88
|
export const Select = forwardRef<SelectProps, 'select'>((props, ref) => {
|
88
89
|
const {
|
89
90
|
name,
|
90
|
-
options,
|
91
|
+
options: optionsProp,
|
91
92
|
children,
|
92
93
|
onChange,
|
93
94
|
defaultValue,
|
@@ -109,6 +110,11 @@ export const Select = forwardRef<SelectProps, 'select'>((props, ref) => {
|
|
109
110
|
|
110
111
|
const controlProps = useFormControl({ name } as HTMLChakraProps<'input'>)
|
111
112
|
|
113
|
+
const options = React.useMemo(
|
114
|
+
() => optionsProp && mapOptions(optionsProp),
|
115
|
+
[optionsProp]
|
116
|
+
)
|
117
|
+
|
112
118
|
const handleChange = (value: string | string[]) => {
|
113
119
|
setCurrentValue(value)
|
114
120
|
onChange?.(value)
|
@@ -180,6 +186,4 @@ export const Select = forwardRef<SelectProps, 'select'>((props, ref) => {
|
|
180
186
|
)
|
181
187
|
})
|
182
188
|
|
183
|
-
|
184
|
-
Select.displayName = 'Select'
|
185
|
-
}
|
189
|
+
Select.displayName = 'Select'
|
package/src/step-form.tsx
CHANGED
@@ -10,7 +10,7 @@ import {
|
|
10
10
|
ThemingProps,
|
11
11
|
} from '@chakra-ui/react'
|
12
12
|
|
13
|
-
import { callAllHandlers, runIfFn, cx
|
13
|
+
import { callAllHandlers, runIfFn, cx } from '@chakra-ui/utils'
|
14
14
|
|
15
15
|
import {
|
16
16
|
StepperProvider,
|
@@ -38,6 +38,11 @@ export interface StepFormProps<
|
|
38
38
|
TContext extends object = object
|
39
39
|
> extends UseStepFormProps<TFieldValues> {}
|
40
40
|
|
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
|
+
*/
|
41
46
|
export const StepForm = React.forwardRef(
|
42
47
|
<
|
43
48
|
TFieldValues extends FieldValues = FieldValues,
|
@@ -89,6 +94,11 @@ export interface FormStepperProps
|
|
89
94
|
extends StepperStepsProps,
|
90
95
|
ThemingProps<'Stepper'> {}
|
91
96
|
|
97
|
+
/**
|
98
|
+
* Renders a stepper that displays progress above the form.
|
99
|
+
*
|
100
|
+
* @see Docs https://saas-ui.dev/docs/components/forms/step-form
|
101
|
+
*/
|
92
102
|
export const FormStepper: React.FC<FormStepperProps> = (props) => {
|
93
103
|
const { activeIndex, setIndex } = useStepperContext()
|
94
104
|
|
@@ -139,7 +149,11 @@ export interface FormStepProps
|
|
139
149
|
Omit<HTMLChakraProps<'div'>, 'onSubmit'> {
|
140
150
|
onSubmit?: FormStepSubmitHandler
|
141
151
|
}
|
142
|
-
|
152
|
+
/**
|
153
|
+
* The form step containing fields for a specific step.
|
154
|
+
*
|
155
|
+
* @see Docs https://saas-ui.dev/docs/components/forms/step-form
|
156
|
+
*/
|
143
157
|
export const FormStep: React.FC<FormStepProps> = (props) => {
|
144
158
|
const { name, schema, resolver, children, className, onSubmit, ...rest } =
|
145
159
|
props
|
@@ -154,10 +168,13 @@ export const FormStep: React.FC<FormStepProps> = (props) => {
|
|
154
168
|
) : null
|
155
169
|
}
|
156
170
|
|
157
|
-
|
158
|
-
FormStep.displayName = 'FormStep'
|
159
|
-
}
|
171
|
+
FormStep.displayName = 'FormStep'
|
160
172
|
|
173
|
+
/**
|
174
|
+
* A button that this opens the previous step when clicked. Disabled on the first step.
|
175
|
+
*
|
176
|
+
* @see Docs https://saas-ui.dev/docs/components/forms/step-form
|
177
|
+
*/
|
161
178
|
export const PrevButton: React.FC<ButtonProps> = (props) => {
|
162
179
|
const { isFirstStep, isCompleted, prevStep } = useStepperContext()
|
163
180
|
|
@@ -172,15 +189,18 @@ export const PrevButton: React.FC<ButtonProps> = (props) => {
|
|
172
189
|
)
|
173
190
|
}
|
174
191
|
|
175
|
-
|
176
|
-
PrevButton.displayName = 'PrevButton'
|
177
|
-
}
|
192
|
+
PrevButton.displayName = 'PrevButton'
|
178
193
|
|
179
194
|
export interface NextButtonProps extends Omit<ButtonProps, 'children'> {
|
180
195
|
submitLabel?: string
|
181
196
|
label?: string
|
182
197
|
}
|
183
198
|
|
199
|
+
/**
|
200
|
+
* A button that submits the active step.
|
201
|
+
*
|
202
|
+
* @see Docs https://saas-ui.dev/docs/components/forms/step-form
|
203
|
+
*/
|
184
204
|
export const NextButton: React.FC<NextButtonProps> = (props) => {
|
185
205
|
const { label = 'Next', submitLabel = 'Complete', ...rest } = props
|
186
206
|
const { isLastStep, isCompleted } = useStepperContext()
|
@@ -196,6 +216,4 @@ export const NextButton: React.FC<NextButtonProps> = (props) => {
|
|
196
216
|
)
|
197
217
|
}
|
198
218
|
|
199
|
-
|
200
|
-
NextButton.displayName = 'NextButton'
|
201
|
-
}
|
219
|
+
NextButton.displayName = 'NextButton'
|
package/src/submit-button.tsx
CHANGED
@@ -20,7 +20,11 @@ export interface SubmitButtonProps extends ButtonProps {
|
|
20
20
|
*/
|
21
21
|
disableIfInvalid?: boolean
|
22
22
|
}
|
23
|
-
|
23
|
+
/**
|
24
|
+
* A button with type submit and default color scheme primary and isLoading state when the form is submitting.
|
25
|
+
*
|
26
|
+
* @see Docs https://saas-ui.dev/docs/components/forms/form
|
27
|
+
*/
|
24
28
|
export const SubmitButton = forwardRef<SubmitButtonProps, 'button'>(
|
25
29
|
(props, ref) => {
|
26
30
|
const {
|
package/src/types.ts
ADDED
@@ -0,0 +1,91 @@
|
|
1
|
+
import { FormControlProps } from '@chakra-ui/react'
|
2
|
+
import { MaybeRenderProp } from '@chakra-ui/react-utils'
|
3
|
+
import { FieldPath, FieldValues, RegisterOptions } from 'react-hook-form'
|
4
|
+
import { DefaultFields } from './default-fields'
|
5
|
+
import { FormProps, FormRenderContext } from './form'
|
6
|
+
|
7
|
+
export type FieldOption = { label: string; value: string }
|
8
|
+
export type FieldOptions<TOption extends FieldOption = FieldOption> =
|
9
|
+
| Array<string>
|
10
|
+
| Array<TOption>
|
11
|
+
|
12
|
+
export type ValueOf<T> = T[keyof T]
|
13
|
+
export type ShallowMerge<A, B> = Omit<A, keyof B> & B
|
14
|
+
|
15
|
+
export interface BaseFieldProps<
|
16
|
+
TFieldValues extends FieldValues = FieldValues,
|
17
|
+
TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>
|
18
|
+
> extends Omit<FormControlProps, 'label' | 'type'> {
|
19
|
+
/**
|
20
|
+
* The field name
|
21
|
+
*/
|
22
|
+
name: TName
|
23
|
+
/**
|
24
|
+
* The field label
|
25
|
+
*/
|
26
|
+
label?: string
|
27
|
+
/**
|
28
|
+
* Hide the field label
|
29
|
+
*/
|
30
|
+
hideLabel?: boolean
|
31
|
+
/**
|
32
|
+
* Field help text
|
33
|
+
*/
|
34
|
+
help?: string
|
35
|
+
/**
|
36
|
+
* React hook form rules
|
37
|
+
*/
|
38
|
+
rules?: Omit<
|
39
|
+
RegisterOptions<TFieldValues, TName>,
|
40
|
+
'valueAsNumber' | 'valueAsDate' | 'setValueAs' | 'disabled'
|
41
|
+
>
|
42
|
+
/**
|
43
|
+
* Build-in types:
|
44
|
+
* text, number, password, textarea, select, native-select, checkbox, radio, switch, pin
|
45
|
+
*
|
46
|
+
* Will default to a text field if there is no matching type.
|
47
|
+
*/
|
48
|
+
type?: string
|
49
|
+
/**
|
50
|
+
* The input placeholder
|
51
|
+
*/
|
52
|
+
placeholder?: string
|
53
|
+
}
|
54
|
+
|
55
|
+
type MergeFieldProps<
|
56
|
+
FieldDefs,
|
57
|
+
TFieldValues extends FieldValues = FieldValues
|
58
|
+
> = ValueOf<{
|
59
|
+
[K in keyof FieldDefs]: FieldDefs[K] extends React.FC<infer Props>
|
60
|
+
? { type?: K } & ShallowMerge<Props, BaseFieldProps<TFieldValues>>
|
61
|
+
: never
|
62
|
+
}>
|
63
|
+
|
64
|
+
export type FieldProps<TFieldValues extends FieldValues = FieldValues> =
|
65
|
+
MergeFieldProps<DefaultFields, TFieldValues>
|
66
|
+
|
67
|
+
export type FormChildren<
|
68
|
+
FieldDefs,
|
69
|
+
TFieldValues extends FieldValues = FieldValues,
|
70
|
+
TContext extends object = object
|
71
|
+
> = MaybeRenderProp<
|
72
|
+
FormRenderContext<
|
73
|
+
TFieldValues,
|
74
|
+
TContext,
|
75
|
+
MergeFieldProps<
|
76
|
+
FieldDefs extends never
|
77
|
+
? DefaultFields
|
78
|
+
: ShallowMerge<DefaultFields, FieldDefs>,
|
79
|
+
TFieldValues
|
80
|
+
>
|
81
|
+
>
|
82
|
+
>
|
83
|
+
|
84
|
+
export type WithFields<
|
85
|
+
TFormProps extends FormProps<any, any, any, any>,
|
86
|
+
FieldDefs
|
87
|
+
> = TFormProps extends FormProps<infer TFieldValues, infer TContext>
|
88
|
+
? Omit<TFormProps, 'children'> & {
|
89
|
+
children: FormChildren<FieldDefs, TFieldValues, TContext>
|
90
|
+
}
|
91
|
+
: never
|
package/src/utils.ts
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
import * as React from 'react'
|
2
|
+
import { FieldOption, FieldOptions } from './types'
|
2
3
|
|
3
4
|
export const mapNestedFields = (name: string, children: React.ReactNode) => {
|
4
5
|
return React.Children.map(children, (child) => {
|
@@ -11,3 +12,17 @@ export const mapNestedFields = (name: string, children: React.ReactNode) => {
|
|
11
12
|
return child
|
12
13
|
})
|
13
14
|
}
|
15
|
+
|
16
|
+
export const mapOptions = <TOption extends FieldOption = FieldOption>(
|
17
|
+
options: FieldOptions<TOption>
|
18
|
+
) => {
|
19
|
+
return options.map((option) => {
|
20
|
+
if (typeof option === 'string') {
|
21
|
+
return {
|
22
|
+
label: option,
|
23
|
+
value: option,
|
24
|
+
}
|
25
|
+
}
|
26
|
+
return option
|
27
|
+
})
|
28
|
+
}
|
File without changes
|