@saas-ui/forms 0.3.3 → 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- package/CHANGELOG.md +35 -0
- package/dist/display-field.d.ts +3 -0
- package/dist/display-field.d.ts.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/index.modern.js +1 -1
- package/dist/index.modern.js.map +1 -1
- package/dist/step-form.d.ts +32 -0
- package/dist/step-form.d.ts.map +1 -0
- package/dist/use-step-form.d.ts +44 -0
- package/dist/use-step-form.d.ts.map +1 -0
- package/package.json +9 -8
- package/src/display-field.tsx +8 -3
- package/src/index.ts +2 -0
- package/src/step-form.tsx +165 -0
- package/src/use-step-form.tsx +118 -0
@@ -0,0 +1,32 @@
|
|
1
|
+
import * as React from 'react';
|
2
|
+
import { FieldValues, UseFormReturn } from 'react-hook-form';
|
3
|
+
import { HTMLChakraProps } from '@chakra-ui/system';
|
4
|
+
import { StepperStepsProps } from '@saas-ui/stepper';
|
5
|
+
import { ButtonProps } from '@saas-ui/button';
|
6
|
+
import { FormProps } from '.';
|
7
|
+
import { UseStepFormProps } from './use-step-form';
|
8
|
+
export interface StepFormProps<TFieldValues extends FieldValues = FieldValues> extends UseStepFormProps<TFieldValues>, FormProps<TFieldValues> {
|
9
|
+
}
|
10
|
+
export declare const StepForm: <TFieldValues extends FieldValues>(props: FormProps<TFieldValues> & {
|
11
|
+
ref?: React.ForwardedRef<UseFormReturn<TFieldValues, object>> | undefined;
|
12
|
+
}) => React.ReactElement;
|
13
|
+
export interface FormStepOptions {
|
14
|
+
/**
|
15
|
+
* The step name
|
16
|
+
*/
|
17
|
+
name: string;
|
18
|
+
/**
|
19
|
+
* Schema
|
20
|
+
*/
|
21
|
+
schema?: any;
|
22
|
+
}
|
23
|
+
export declare const FormStepper: React.FC<StepperStepsProps>;
|
24
|
+
export interface FormStepProps extends FormStepOptions, HTMLChakraProps<'div'> {
|
25
|
+
}
|
26
|
+
export declare const FormStep: React.FC<FormStepProps>;
|
27
|
+
export declare const PrevButton: React.FC<ButtonProps>;
|
28
|
+
export interface NextButtonProps extends ButtonProps {
|
29
|
+
submitLabel?: string;
|
30
|
+
}
|
31
|
+
export declare const NextButton: React.FC<NextButtonProps>;
|
32
|
+
//# sourceMappingURL=step-form.d.ts.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"step-form.d.ts","sourceRoot":"","sources":["../src/step-form.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAE9B,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAA;AAE5D,OAAO,EAEL,eAAe,EAGhB,MAAM,mBAAmB,CAAA;AAI1B,OAAO,EAGL,iBAAiB,EAGlB,MAAM,kBAAkB,CAAA;AACzB,OAAO,EAAU,WAAW,EAAE,MAAM,iBAAiB,CAAA;AAErD,OAAO,EAAQ,SAAS,EAAgB,MAAM,GAAG,CAAA;AAEjD,OAAO,EAIL,gBAAgB,EACjB,MAAM,iBAAiB,CAAA;AAExB,MAAM,WAAW,aAAa,CAAC,YAAY,SAAS,WAAW,GAAG,WAAW,CAC3E,SAAQ,gBAAgB,CAAC,YAAY,CAAC,EACpC,SAAS,CAAC,YAAY,CAAC;CAAG;AAE9B,eAAO,MAAM,QAAQ;;MA2BhB,MAAM,YAAY,CAAA;AAEvB,MAAM,WAAW,eAAe;IAC9B;;OAEG;IACH,IAAI,EAAE,MAAM,CAAA;IACZ;;OAEG;IACH,MAAM,CAAC,EAAE,GAAG,CAAA;CACb;AAED,eAAO,MAAM,WAAW,EAAE,KAAK,CAAC,EAAE,CAAC,iBAAiB,CA4BnD,CAAA;AAED,MAAM,WAAW,aACf,SAAQ,eAAe,EACrB,eAAe,CAAC,KAAK,CAAC;CAAG;AAE7B,eAAO,MAAM,QAAQ,EAAE,KAAK,CAAC,EAAE,CAAC,aAAa,CAW5C,CAAA;AAMD,eAAO,MAAM,UAAU,EAAE,KAAK,CAAC,EAAE,CAAC,WAAW,CAY5C,CAAA;AAMD,MAAM,WAAW,eAAgB,SAAQ,WAAW;IAClD,WAAW,CAAC,EAAE,MAAM,CAAA;CACrB;AAED,eAAO,MAAM,UAAU,EAAE,KAAK,CAAC,EAAE,CAAC,eAAe,CAYhD,CAAA"}
|
@@ -0,0 +1,44 @@
|
|
1
|
+
import * as React from 'react';
|
2
|
+
import { FieldValues, SubmitHandler } from 'react-hook-form';
|
3
|
+
import { UseStepperProps, UseStepperReturn } from '@saas-ui/stepper';
|
4
|
+
export interface StepState {
|
5
|
+
name: string;
|
6
|
+
schema?: any;
|
7
|
+
isActive?: boolean;
|
8
|
+
isCompleted?: boolean;
|
9
|
+
}
|
10
|
+
export interface StepFormContext extends UseStepperReturn {
|
11
|
+
updateStep(state: StepState): void;
|
12
|
+
steps: Record<string, StepState>;
|
13
|
+
}
|
14
|
+
export declare const StepFormProvider: React.Provider<StepFormContext>, useStepFormContext: () => StepFormContext;
|
15
|
+
import { FormProps } from './form';
|
16
|
+
export interface UseStepFormProps<TFieldValues extends FieldValues = FieldValues> extends UseStepperProps, FormProps<TFieldValues> {
|
17
|
+
}
|
18
|
+
export declare function useStepForm<TFieldValues extends FieldValues = FieldValues>(props: UseStepFormProps<TFieldValues>): {
|
19
|
+
stepsRef: React.MutableRefObject<string[]>;
|
20
|
+
activeStep: string;
|
21
|
+
activeIndex: number;
|
22
|
+
isFirstStep: boolean;
|
23
|
+
isLastStep: boolean;
|
24
|
+
isCompleted: boolean;
|
25
|
+
setIndex: React.Dispatch<React.SetStateAction<number>>;
|
26
|
+
setStep: (name: string) => void;
|
27
|
+
nextStep: () => void;
|
28
|
+
prevStep: () => void;
|
29
|
+
registerStep: (name: string) => void;
|
30
|
+
unregisterStep: (name: string) => void;
|
31
|
+
getFormProps: (props: any) => {
|
32
|
+
onSubmit: SubmitHandler<TFieldValues>;
|
33
|
+
schema: any;
|
34
|
+
};
|
35
|
+
updateStep: (step: any) => void;
|
36
|
+
steps: {};
|
37
|
+
};
|
38
|
+
export declare type UseStepFormReturn = ReturnType<typeof useStepForm>;
|
39
|
+
export interface UseFormStepProps {
|
40
|
+
name: string;
|
41
|
+
schema?: any;
|
42
|
+
}
|
43
|
+
export declare function useFormStep(props: UseFormStepProps): StepState;
|
44
|
+
//# sourceMappingURL=use-step-form.d.ts.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"use-step-form.d.ts","sourceRoot":"","sources":["../src/use-step-form.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAC9B,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAA;AAE5D,OAAO,EAGL,eAAe,EACf,gBAAgB,EACjB,MAAM,kBAAkB,CAAA;AAEzB,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAA;IACZ,MAAM,CAAC,EAAE,GAAG,CAAA;IACZ,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,WAAW,CAAC,EAAE,OAAO,CAAA;CACtB;AAED,MAAM,WAAW,eAAgB,SAAQ,gBAAgB;IACvD,UAAU,CAAC,KAAK,EAAE,SAAS,GAAG,IAAI,CAAA;IAClC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,CAAA;CACjC;AAED,eAAO,MAAO,gBAAgB,mCAAE,kBAAkB,uBAK9C,CAAA;AAEJ,OAAO,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAA;AAElC,MAAM,WAAW,gBAAgB,CAC/B,YAAY,SAAS,WAAW,GAAG,WAAW,CAC9C,SAAQ,eAAe,EACrB,SAAS,CAAC,YAAY,CAAC;CAAG;AAE9B,wBAAgB,WAAW,CAAC,YAAY,SAAS,WAAW,GAAG,WAAW,EACxE,KAAK,EAAE,gBAAgB,CAAC,YAAY,CAAC;;;;;;;;;;;;;;;;;;;EAyDtC;AAED,oBAAY,iBAAiB,GAAG,UAAU,CAAC,OAAO,WAAW,CAAC,CAAA;AAE9D,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,CAAA;IACZ,MAAM,CAAC,EAAE,GAAG,CAAA;CACb;AAED,wBAAgB,WAAW,CAAC,KAAK,EAAE,gBAAgB,GAAG,SAAS,CAc9D"}
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@saas-ui/forms",
|
3
|
-
"version": "0.
|
3
|
+
"version": "0.5.0",
|
4
4
|
"description": "Theme and components agnostic SaasProvider",
|
5
5
|
"source": "src/index.ts",
|
6
6
|
"exports": {
|
@@ -65,13 +65,14 @@
|
|
65
65
|
"@chakra-ui/icons": "^1.1.1",
|
66
66
|
"@chakra-ui/react-utils": "^1.2.1",
|
67
67
|
"@hookform/resolvers": "^2.8.3",
|
68
|
-
"@saas-ui/button": "0.
|
69
|
-
"@saas-ui/input-right-button": "0.
|
70
|
-
"@saas-ui/number-input": "0.
|
71
|
-
"@saas-ui/password-input": "0.
|
72
|
-
"@saas-ui/pin-input": "0.
|
73
|
-
"@saas-ui/radio": "0.
|
74
|
-
"@saas-ui/
|
68
|
+
"@saas-ui/button": "0.3.0",
|
69
|
+
"@saas-ui/input-right-button": "0.3.0",
|
70
|
+
"@saas-ui/number-input": "0.3.0",
|
71
|
+
"@saas-ui/password-input": "0.3.0",
|
72
|
+
"@saas-ui/pin-input": "0.3.0",
|
73
|
+
"@saas-ui/radio": "0.3.0",
|
74
|
+
"@saas-ui/react-utils": "0.1.0",
|
75
|
+
"@saas-ui/select": "0.3.0",
|
75
76
|
"react-hook-form": "^7.22.0"
|
76
77
|
},
|
77
78
|
"peerDependencies": {
|
package/src/display-field.tsx
CHANGED
@@ -20,12 +20,17 @@ export const DisplayField: React.FC<DisplayFieldProps> = ({
|
|
20
20
|
placeholder,
|
21
21
|
...props
|
22
22
|
}) => {
|
23
|
-
const { getValues } = useFormContext()
|
24
|
-
|
25
23
|
return (
|
26
24
|
<FormControl {...props}>
|
27
25
|
{label ? <FormLabel htmlFor={name}>{label}</FormLabel> : null}
|
28
|
-
<Text fontSize="md">
|
26
|
+
<Text fontSize="md">
|
27
|
+
<FormValue name={name} />
|
28
|
+
</Text>
|
29
29
|
</FormControl>
|
30
30
|
)
|
31
31
|
}
|
32
|
+
|
33
|
+
export const FormValue: React.FC<{ name: string }> = ({ name }) => {
|
34
|
+
const { getValues } = useFormContext()
|
35
|
+
return getValues(name) || null
|
36
|
+
}
|
package/src/index.ts
CHANGED
@@ -0,0 +1,165 @@
|
|
1
|
+
import * as React from 'react'
|
2
|
+
|
3
|
+
import { FieldValues, UseFormReturn } from 'react-hook-form'
|
4
|
+
|
5
|
+
import {
|
6
|
+
chakra,
|
7
|
+
HTMLChakraProps,
|
8
|
+
useMultiStyleConfig,
|
9
|
+
StylesProvider,
|
10
|
+
} from '@chakra-ui/system'
|
11
|
+
|
12
|
+
import { callAllHandlers, runIfFn, cx, __DEV__ } from '@chakra-ui/utils'
|
13
|
+
|
14
|
+
import {
|
15
|
+
StepperProvider,
|
16
|
+
StepperSteps,
|
17
|
+
StepperStepsProps,
|
18
|
+
StepperStep,
|
19
|
+
useStepperContext,
|
20
|
+
} from '@saas-ui/stepper'
|
21
|
+
import { Button, ButtonProps } from '@saas-ui/button'
|
22
|
+
|
23
|
+
import { Form, FormProps, SubmitButton } from '.'
|
24
|
+
|
25
|
+
import {
|
26
|
+
useStepForm,
|
27
|
+
useFormStep,
|
28
|
+
StepFormProvider,
|
29
|
+
UseStepFormProps,
|
30
|
+
} from './use-step-form'
|
31
|
+
|
32
|
+
export interface StepFormProps<TFieldValues extends FieldValues = FieldValues>
|
33
|
+
extends UseStepFormProps<TFieldValues>,
|
34
|
+
FormProps<TFieldValues> {}
|
35
|
+
|
36
|
+
export const StepForm = React.forwardRef(
|
37
|
+
<TFieldValues extends FieldValues = FieldValues>(
|
38
|
+
props: StepFormProps<TFieldValues>,
|
39
|
+
ref: React.ForwardedRef<UseFormReturn<TFieldValues>>
|
40
|
+
) => {
|
41
|
+
const { children, onSubmit, ...rest } = props
|
42
|
+
|
43
|
+
const stepper = useStepForm<TFieldValues>(props)
|
44
|
+
|
45
|
+
const { getFormProps, ...ctx } = stepper
|
46
|
+
|
47
|
+
const context = React.useMemo(() => ctx, [ctx])
|
48
|
+
|
49
|
+
return (
|
50
|
+
<StepperProvider value={context}>
|
51
|
+
<StepFormProvider value={context}>
|
52
|
+
<Form ref={ref} {...rest} {...getFormProps(props)}>
|
53
|
+
{runIfFn(children, stepper)}
|
54
|
+
</Form>
|
55
|
+
</StepFormProvider>
|
56
|
+
</StepperProvider>
|
57
|
+
)
|
58
|
+
}
|
59
|
+
) as <TFieldValues extends FieldValues>(
|
60
|
+
props: FormProps<TFieldValues> & {
|
61
|
+
ref?: React.ForwardedRef<UseFormReturn<TFieldValues>>
|
62
|
+
}
|
63
|
+
) => React.ReactElement
|
64
|
+
|
65
|
+
export interface FormStepOptions {
|
66
|
+
/**
|
67
|
+
* The step name
|
68
|
+
*/
|
69
|
+
name: string
|
70
|
+
/**
|
71
|
+
* Schema
|
72
|
+
*/
|
73
|
+
schema?: any
|
74
|
+
}
|
75
|
+
|
76
|
+
export const FormStepper: React.FC<StepperStepsProps> = (props) => {
|
77
|
+
const styles = useMultiStyleConfig('Stepper', props)
|
78
|
+
|
79
|
+
const { children } = props
|
80
|
+
|
81
|
+
const elements = React.Children.map(children, (child) => {
|
82
|
+
if (React.isValidElement(child) && child?.type === FormStep) {
|
83
|
+
const { isCompleted } = useFormStep(child.props) // Register this step
|
84
|
+
return (
|
85
|
+
<StepperStep
|
86
|
+
name={child.props.name}
|
87
|
+
title={child.props.title}
|
88
|
+
isCompleted={isCompleted}
|
89
|
+
>
|
90
|
+
{child.props.children}
|
91
|
+
</StepperStep>
|
92
|
+
)
|
93
|
+
}
|
94
|
+
return child
|
95
|
+
})
|
96
|
+
|
97
|
+
return (
|
98
|
+
<StylesProvider value={styles}>
|
99
|
+
<StepperSteps mb="4" {...props}>
|
100
|
+
{elements}
|
101
|
+
</StepperSteps>
|
102
|
+
</StylesProvider>
|
103
|
+
)
|
104
|
+
}
|
105
|
+
|
106
|
+
export interface FormStepProps
|
107
|
+
extends FormStepOptions,
|
108
|
+
HTMLChakraProps<'div'> {}
|
109
|
+
|
110
|
+
export const FormStep: React.FC<FormStepProps> = (props) => {
|
111
|
+
const { name, schema, children, className, ...rest } = props
|
112
|
+
const step = useFormStep({ name, schema })
|
113
|
+
|
114
|
+
const { isActive } = step
|
115
|
+
|
116
|
+
return isActive ? (
|
117
|
+
<chakra.div {...rest} className={cx('saas-form__step', className)}>
|
118
|
+
{children}
|
119
|
+
</chakra.div>
|
120
|
+
) : null
|
121
|
+
}
|
122
|
+
|
123
|
+
if (__DEV__) {
|
124
|
+
FormStep.displayName = 'FormStep'
|
125
|
+
}
|
126
|
+
|
127
|
+
export const PrevButton: React.FC<ButtonProps> = (props) => {
|
128
|
+
const { isFirstStep, isCompleted, prevStep } = useStepperContext()
|
129
|
+
|
130
|
+
return (
|
131
|
+
<Button
|
132
|
+
isDisabled={isFirstStep || isCompleted}
|
133
|
+
label="Back"
|
134
|
+
{...props}
|
135
|
+
className={cx('saas-form__prev-button', props.className)}
|
136
|
+
onClick={callAllHandlers(props.onClick, prevStep)}
|
137
|
+
/>
|
138
|
+
)
|
139
|
+
}
|
140
|
+
|
141
|
+
if (__DEV__) {
|
142
|
+
PrevButton.displayName = 'PrevButton'
|
143
|
+
}
|
144
|
+
|
145
|
+
export interface NextButtonProps extends ButtonProps {
|
146
|
+
submitLabel?: string
|
147
|
+
}
|
148
|
+
|
149
|
+
export const NextButton: React.FC<NextButtonProps> = (props) => {
|
150
|
+
const { label = 'Next', submitLabel = 'Complete', ...rest } = props
|
151
|
+
const { isLastStep, isCompleted } = useStepperContext()
|
152
|
+
|
153
|
+
return (
|
154
|
+
<SubmitButton
|
155
|
+
isDisabled={isCompleted}
|
156
|
+
label={isLastStep || isCompleted ? submitLabel : label}
|
157
|
+
{...rest}
|
158
|
+
className={cx('saas-form__next-button', props.className)}
|
159
|
+
/>
|
160
|
+
)
|
161
|
+
}
|
162
|
+
|
163
|
+
if (__DEV__) {
|
164
|
+
NextButton.displayName = 'NextButton'
|
165
|
+
}
|
@@ -0,0 +1,118 @@
|
|
1
|
+
import * as React from 'react'
|
2
|
+
import { FieldValues, SubmitHandler } from 'react-hook-form'
|
3
|
+
import { createContext } from '@chakra-ui/react-utils'
|
4
|
+
import {
|
5
|
+
useStepper,
|
6
|
+
useStep,
|
7
|
+
UseStepperProps,
|
8
|
+
UseStepperReturn,
|
9
|
+
} from '@saas-ui/stepper'
|
10
|
+
|
11
|
+
export interface StepState {
|
12
|
+
name: string
|
13
|
+
schema?: any
|
14
|
+
isActive?: boolean
|
15
|
+
isCompleted?: boolean
|
16
|
+
}
|
17
|
+
|
18
|
+
export interface StepFormContext extends UseStepperReturn {
|
19
|
+
updateStep(state: StepState): void
|
20
|
+
steps: Record<string, StepState>
|
21
|
+
}
|
22
|
+
|
23
|
+
export const [StepFormProvider, useStepFormContext] =
|
24
|
+
createContext<StepFormContext>({
|
25
|
+
name: 'StepFormContext',
|
26
|
+
errorMessage:
|
27
|
+
'useStepFormContext: `context` is undefined. Seems you forgot to wrap step form components in `<StepForm />`',
|
28
|
+
})
|
29
|
+
|
30
|
+
import { FormProps } from './form'
|
31
|
+
|
32
|
+
export interface UseStepFormProps<
|
33
|
+
TFieldValues extends FieldValues = FieldValues
|
34
|
+
> extends UseStepperProps,
|
35
|
+
FormProps<TFieldValues> {}
|
36
|
+
|
37
|
+
export function useStepForm<TFieldValues extends FieldValues = FieldValues>(
|
38
|
+
props: UseStepFormProps<TFieldValues>
|
39
|
+
) {
|
40
|
+
const stepper = useStepper(props)
|
41
|
+
|
42
|
+
const { activeStep, isLastStep, nextStep } = stepper
|
43
|
+
|
44
|
+
const [steps, updateSteps] = React.useState({})
|
45
|
+
|
46
|
+
const onSubmitStep: SubmitHandler<TFieldValues> = React.useCallback(
|
47
|
+
async (data) => {
|
48
|
+
if (isLastStep) {
|
49
|
+
return props
|
50
|
+
.onSubmit?.(data)
|
51
|
+
.then(() => {
|
52
|
+
const step = steps[activeStep]
|
53
|
+
updateStep({
|
54
|
+
...step,
|
55
|
+
isCompleted: true,
|
56
|
+
})
|
57
|
+
})
|
58
|
+
.then(nextStep) // Show completed step
|
59
|
+
}
|
60
|
+
|
61
|
+
nextStep()
|
62
|
+
},
|
63
|
+
[activeStep, isLastStep]
|
64
|
+
)
|
65
|
+
|
66
|
+
const getFormProps = React.useCallback(
|
67
|
+
(props) => {
|
68
|
+
const step = steps[activeStep]
|
69
|
+
return {
|
70
|
+
onSubmit: onSubmitStep,
|
71
|
+
schema: step?.schema,
|
72
|
+
}
|
73
|
+
},
|
74
|
+
[steps, onSubmitStep, activeStep]
|
75
|
+
)
|
76
|
+
|
77
|
+
const updateStep = React.useCallback(
|
78
|
+
(step) => {
|
79
|
+
updateSteps((steps) => {
|
80
|
+
return {
|
81
|
+
...steps,
|
82
|
+
[step.name]: step,
|
83
|
+
}
|
84
|
+
})
|
85
|
+
},
|
86
|
+
[steps]
|
87
|
+
)
|
88
|
+
|
89
|
+
return {
|
90
|
+
getFormProps,
|
91
|
+
updateStep,
|
92
|
+
steps,
|
93
|
+
...stepper,
|
94
|
+
}
|
95
|
+
}
|
96
|
+
|
97
|
+
export type UseStepFormReturn = ReturnType<typeof useStepForm>
|
98
|
+
|
99
|
+
export interface UseFormStepProps {
|
100
|
+
name: string
|
101
|
+
schema?: any
|
102
|
+
}
|
103
|
+
|
104
|
+
export function useFormStep(props: UseFormStepProps): StepState {
|
105
|
+
const { name, schema } = props
|
106
|
+
const step = useStep({ name })
|
107
|
+
|
108
|
+
const { steps, updateStep } = useStepFormContext()
|
109
|
+
|
110
|
+
React.useEffect(() => {
|
111
|
+
updateStep({ name, schema })
|
112
|
+
}, [name, schema])
|
113
|
+
|
114
|
+
return {
|
115
|
+
...step,
|
116
|
+
...(steps[name] || {}),
|
117
|
+
}
|
118
|
+
}
|