@ttoss/forms 0.25.6 → 0.26.1
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/LICENSE +21 -674
- package/dist/Brazil/index.d.ts +24 -0
- package/dist/FormFieldPatternFormat-CkcL14ho.d.ts +10 -0
- package/dist/MultistepForm/index.d.ts +65 -0
- package/dist/esm/Brazil/index.js +51 -0
- package/dist/esm/MultistepForm/index.js +2502 -0
- package/dist/esm/chunk-6U527R3X.js +741 -0
- package/dist/esm/index.js +3 -0
- package/dist/index.d.ts +107 -0
- package/{src/yup/typings.d.ts → dist/typings.d-HZBqJJjn.d.ts} +1 -3
- package/package.json +11 -11
- package/src/Brazil/FormFieldCEP.tsx +0 -25
- package/src/Brazil/FormFieldCNPJ.tsx +0 -93
- package/src/Brazil/FormFieldPhone.tsx +0 -41
- package/src/Brazil/index.ts +0 -4
- package/src/Form.tsx +0 -29
- package/src/FormErrorMessage.tsx +0 -60
- package/src/FormField.tsx +0 -86
- package/src/FormFieldCheckbox.tsx +0 -49
- package/src/FormFieldCreditCardNumber.tsx +0 -25
- package/src/FormFieldCurrencyInput.tsx +0 -36
- package/src/FormFieldInput.tsx +0 -43
- package/src/FormFieldNumericFormat.tsx +0 -35
- package/src/FormFieldPassword.tsx +0 -43
- package/src/FormFieldPatternFormat.tsx +0 -36
- package/src/FormFieldRadio.tsx +0 -57
- package/src/FormFieldSelect.tsx +0 -47
- package/src/FormFieldTextarea.tsx +0 -36
- package/src/FormGroup.tsx +0 -136
- package/src/MultistepForm/MultistepFlowMessage.tsx +0 -14
- package/src/MultistepForm/MultistepFlowMessageImageText.tsx +0 -37
- package/src/MultistepForm/MultistepFooter.tsx +0 -18
- package/src/MultistepForm/MultistepForm.tsx +0 -117
- package/src/MultistepForm/MultistepFormStepper.tsx +0 -70
- package/src/MultistepForm/MultistepHeader.tsx +0 -78
- package/src/MultistepForm/MultistepNavigation.tsx +0 -38
- package/src/MultistepForm/MultistepQuestion.tsx +0 -28
- package/src/MultistepForm/index.ts +0 -1
- package/src/MultistepForm/types.ts +0 -7
- package/src/index.ts +0 -35
- package/src/yup/i18n.ts +0 -31
- package/src/yup/schema.ts +0 -26
- package/src/yup/yup.ts +0 -4
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
import { FormField } from './FormField';
|
|
2
|
-
import { Input } from '@ttoss/ui';
|
|
3
|
-
import { NumericFormat, NumericFormatProps } from 'react-number-format';
|
|
4
|
-
|
|
5
|
-
export type FormFieldNumericFormatProps = {
|
|
6
|
-
label?: string;
|
|
7
|
-
name: string;
|
|
8
|
-
} & NumericFormatProps;
|
|
9
|
-
|
|
10
|
-
export const FormFieldNumericFormat = ({
|
|
11
|
-
label,
|
|
12
|
-
name,
|
|
13
|
-
...numericFormatProps
|
|
14
|
-
}: FormFieldNumericFormatProps) => {
|
|
15
|
-
return (
|
|
16
|
-
<FormField
|
|
17
|
-
label={label}
|
|
18
|
-
name={name}
|
|
19
|
-
render={({ field }) => {
|
|
20
|
-
return (
|
|
21
|
-
<NumericFormat
|
|
22
|
-
name={field.name}
|
|
23
|
-
value={field.value}
|
|
24
|
-
onBlur={field.onBlur}
|
|
25
|
-
onValueChange={(values) => {
|
|
26
|
-
field.onChange(values.floatValue);
|
|
27
|
-
}}
|
|
28
|
-
customInput={Input}
|
|
29
|
-
{...numericFormatProps}
|
|
30
|
-
/>
|
|
31
|
-
);
|
|
32
|
-
}}
|
|
33
|
-
/>
|
|
34
|
-
);
|
|
35
|
-
};
|
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
import { FieldPath, FieldPathValue, FieldValues } from 'react-hook-form';
|
|
2
|
-
import { FormField, type FormFieldProps } from './FormField';
|
|
3
|
-
import { InputPassword, type InputPasswordProps } from '@ttoss/ui';
|
|
4
|
-
|
|
5
|
-
export type FormFieldPasswordProps<TName> = {
|
|
6
|
-
label?: string;
|
|
7
|
-
name: TName;
|
|
8
|
-
} & InputPasswordProps &
|
|
9
|
-
FormFieldProps;
|
|
10
|
-
|
|
11
|
-
export const FormFieldPassword = <
|
|
12
|
-
TFieldValues extends FieldValues = FieldValues,
|
|
13
|
-
TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>,
|
|
14
|
-
>({
|
|
15
|
-
label,
|
|
16
|
-
name,
|
|
17
|
-
tooltip,
|
|
18
|
-
onTooltipClick,
|
|
19
|
-
sx,
|
|
20
|
-
defaultValue = '',
|
|
21
|
-
...inputProps
|
|
22
|
-
}: FormFieldPasswordProps<TName>) => {
|
|
23
|
-
return (
|
|
24
|
-
<FormField
|
|
25
|
-
name={name}
|
|
26
|
-
label={label}
|
|
27
|
-
disabled={inputProps.disabled}
|
|
28
|
-
tooltip={tooltip}
|
|
29
|
-
onTooltipClick={onTooltipClick}
|
|
30
|
-
sx={sx}
|
|
31
|
-
defaultValue={defaultValue as FieldPathValue<TFieldValues, TName>}
|
|
32
|
-
render={({ field, fieldState }) => {
|
|
33
|
-
return (
|
|
34
|
-
<InputPassword
|
|
35
|
-
{...inputProps}
|
|
36
|
-
{...field}
|
|
37
|
-
aria-invalid={fieldState.error ? 'true' : undefined}
|
|
38
|
-
/>
|
|
39
|
-
);
|
|
40
|
-
}}
|
|
41
|
-
/>
|
|
42
|
-
);
|
|
43
|
-
};
|
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
import { FormField } from './FormField';
|
|
2
|
-
import { Input } from '@ttoss/ui';
|
|
3
|
-
import { PatternFormat, PatternFormatProps } from 'react-number-format';
|
|
4
|
-
|
|
5
|
-
export type FormFieldPatternFormatProps = {
|
|
6
|
-
label?: string;
|
|
7
|
-
name: string;
|
|
8
|
-
} & PatternFormatProps;
|
|
9
|
-
|
|
10
|
-
export const FormFieldPatternFormat = ({
|
|
11
|
-
label,
|
|
12
|
-
name,
|
|
13
|
-
...patternFormatProps
|
|
14
|
-
}: FormFieldPatternFormatProps) => {
|
|
15
|
-
return (
|
|
16
|
-
<FormField
|
|
17
|
-
name={name}
|
|
18
|
-
label={label}
|
|
19
|
-
render={({ field, fieldState }) => {
|
|
20
|
-
return (
|
|
21
|
-
<PatternFormat
|
|
22
|
-
name={field.name}
|
|
23
|
-
value={field.value}
|
|
24
|
-
onBlur={field.onBlur}
|
|
25
|
-
onValueChange={(values) => {
|
|
26
|
-
field.onChange(values.value);
|
|
27
|
-
}}
|
|
28
|
-
customInput={Input}
|
|
29
|
-
aria-invalid={Boolean(fieldState.error).valueOf()}
|
|
30
|
-
{...patternFormatProps}
|
|
31
|
-
/>
|
|
32
|
-
);
|
|
33
|
-
}}
|
|
34
|
-
/>
|
|
35
|
-
);
|
|
36
|
-
};
|
package/src/FormFieldRadio.tsx
DELETED
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
import { Box, Flex, Label, Radio, type RadioProps } from '@ttoss/ui';
|
|
2
|
-
import { FieldPath, FieldValues, useController } from 'react-hook-form';
|
|
3
|
-
import { FormErrorMessage } from './FormErrorMessage';
|
|
4
|
-
|
|
5
|
-
type FormRadioOption = {
|
|
6
|
-
value: string | number;
|
|
7
|
-
label: string;
|
|
8
|
-
};
|
|
9
|
-
|
|
10
|
-
export const FormFieldRadio = <TFieldValues extends FieldValues = FieldValues>({
|
|
11
|
-
label,
|
|
12
|
-
name,
|
|
13
|
-
options,
|
|
14
|
-
sx,
|
|
15
|
-
...radioProps
|
|
16
|
-
}: {
|
|
17
|
-
label?: string;
|
|
18
|
-
name: FieldPath<TFieldValues>;
|
|
19
|
-
options: FormRadioOption[];
|
|
20
|
-
} & RadioProps) => {
|
|
21
|
-
const {
|
|
22
|
-
field: { onChange, onBlur, value, ref },
|
|
23
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
24
|
-
} = useController<any>({
|
|
25
|
-
name,
|
|
26
|
-
defaultValue: '',
|
|
27
|
-
});
|
|
28
|
-
|
|
29
|
-
return (
|
|
30
|
-
<Flex sx={{ flexDirection: 'column', width: '100%', ...sx }}>
|
|
31
|
-
{label && <Label sx={{ marginBottom: 'md' }}>{label}</Label>}
|
|
32
|
-
<Box>
|
|
33
|
-
{options.map((option: FormRadioOption) => {
|
|
34
|
-
const id = `form-field-radio-${name}-${option.value}`;
|
|
35
|
-
|
|
36
|
-
return (
|
|
37
|
-
<Label key={id} htmlFor={id}>
|
|
38
|
-
<Radio
|
|
39
|
-
ref={ref}
|
|
40
|
-
onChange={onChange}
|
|
41
|
-
onBlur={onBlur}
|
|
42
|
-
value={option.value}
|
|
43
|
-
checked={value === option.value}
|
|
44
|
-
name={name}
|
|
45
|
-
id={id}
|
|
46
|
-
{...radioProps}
|
|
47
|
-
/>
|
|
48
|
-
{option.label}
|
|
49
|
-
</Label>
|
|
50
|
-
);
|
|
51
|
-
})}
|
|
52
|
-
</Box>
|
|
53
|
-
|
|
54
|
-
<FormErrorMessage name={name} />
|
|
55
|
-
</Flex>
|
|
56
|
-
);
|
|
57
|
-
};
|
package/src/FormFieldSelect.tsx
DELETED
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
import { FieldPath, FieldValues } from 'react-hook-form';
|
|
2
|
-
import { FormField, FormFieldProps } from './FormField';
|
|
3
|
-
import { Select, type SelectProps } from '@ttoss/ui';
|
|
4
|
-
|
|
5
|
-
type FormFieldSelectProps<
|
|
6
|
-
TFieldValues extends FieldValues = FieldValues,
|
|
7
|
-
TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>,
|
|
8
|
-
> = Omit<SelectProps, 'defaultValue'> & FormFieldProps<TFieldValues, TName>;
|
|
9
|
-
|
|
10
|
-
export const FormFieldSelect = <
|
|
11
|
-
TFieldValues extends FieldValues = FieldValues,
|
|
12
|
-
>({
|
|
13
|
-
label,
|
|
14
|
-
name,
|
|
15
|
-
id,
|
|
16
|
-
defaultValue,
|
|
17
|
-
sx,
|
|
18
|
-
css,
|
|
19
|
-
disabled,
|
|
20
|
-
tooltip,
|
|
21
|
-
onTooltipClick,
|
|
22
|
-
...selectProps
|
|
23
|
-
}: FormFieldSelectProps<TFieldValues>) => {
|
|
24
|
-
return (
|
|
25
|
-
<FormField
|
|
26
|
-
name={name}
|
|
27
|
-
label={label}
|
|
28
|
-
id={id}
|
|
29
|
-
defaultValue={defaultValue}
|
|
30
|
-
disabled={disabled}
|
|
31
|
-
tooltip={tooltip}
|
|
32
|
-
onTooltipClick={onTooltipClick}
|
|
33
|
-
sx={sx}
|
|
34
|
-
css={css}
|
|
35
|
-
render={({ field, fieldState }) => {
|
|
36
|
-
return (
|
|
37
|
-
<Select
|
|
38
|
-
{...selectProps}
|
|
39
|
-
{...field}
|
|
40
|
-
isDisabled={disabled}
|
|
41
|
-
aria-invalid={fieldState.error ? 'true' : undefined}
|
|
42
|
-
/>
|
|
43
|
-
);
|
|
44
|
-
}}
|
|
45
|
-
/>
|
|
46
|
-
);
|
|
47
|
-
};
|
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
import { FieldPath, FieldValues } from 'react-hook-form';
|
|
2
|
-
import { FormField } from './FormField';
|
|
3
|
-
import { Textarea, type TextareaProps } from '@ttoss/ui';
|
|
4
|
-
|
|
5
|
-
export const FormFieldTextarea = <
|
|
6
|
-
TFieldValues extends FieldValues = FieldValues,
|
|
7
|
-
TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>
|
|
8
|
-
>({
|
|
9
|
-
label,
|
|
10
|
-
name,
|
|
11
|
-
sx,
|
|
12
|
-
...textareaProps
|
|
13
|
-
}: {
|
|
14
|
-
label?: string;
|
|
15
|
-
name: TName;
|
|
16
|
-
} & TextareaProps) => {
|
|
17
|
-
const id = `form-field-textarea-${name}`;
|
|
18
|
-
|
|
19
|
-
return (
|
|
20
|
-
<FormField
|
|
21
|
-
label={label}
|
|
22
|
-
name={name}
|
|
23
|
-
id={id}
|
|
24
|
-
sx={sx}
|
|
25
|
-
render={({ field, fieldState }) => {
|
|
26
|
-
return (
|
|
27
|
-
<Textarea
|
|
28
|
-
{...field}
|
|
29
|
-
{...textareaProps}
|
|
30
|
-
aria-invalid={fieldState.error ? 'true' : undefined}
|
|
31
|
-
/>
|
|
32
|
-
);
|
|
33
|
-
}}
|
|
34
|
-
/>
|
|
35
|
-
);
|
|
36
|
-
};
|
package/src/FormGroup.tsx
DELETED
|
@@ -1,136 +0,0 @@
|
|
|
1
|
-
import * as React from 'react';
|
|
2
|
-
import { Box, BoxProps, Flex, FlexProps, Text } from '@ttoss/ui';
|
|
3
|
-
import { FormErrorMessage } from './FormErrorMessage';
|
|
4
|
-
|
|
5
|
-
type FormGroupLevelsManagerContextType = {
|
|
6
|
-
levelsLength: number;
|
|
7
|
-
registerChild: (level: number) => void;
|
|
8
|
-
};
|
|
9
|
-
|
|
10
|
-
const FormGroupLevelsManagerContext =
|
|
11
|
-
React.createContext<FormGroupLevelsManagerContextType>({
|
|
12
|
-
levelsLength: 1,
|
|
13
|
-
registerChild: () => {
|
|
14
|
-
return null;
|
|
15
|
-
},
|
|
16
|
-
});
|
|
17
|
-
|
|
18
|
-
const FormGroupLevelsManager = ({
|
|
19
|
-
children,
|
|
20
|
-
}: {
|
|
21
|
-
children: React.ReactNode;
|
|
22
|
-
}) => {
|
|
23
|
-
const [levelsLength, setLevelsLength] = React.useState(0);
|
|
24
|
-
|
|
25
|
-
const registerChild = React.useCallback(
|
|
26
|
-
(level: number) => {
|
|
27
|
-
if (level + 1 > levelsLength) {
|
|
28
|
-
setLevelsLength(level + 1);
|
|
29
|
-
}
|
|
30
|
-
},
|
|
31
|
-
[levelsLength]
|
|
32
|
-
);
|
|
33
|
-
|
|
34
|
-
return (
|
|
35
|
-
<FormGroupLevelsManagerContext.Provider
|
|
36
|
-
value={{ levelsLength, registerChild }}
|
|
37
|
-
>
|
|
38
|
-
{children}
|
|
39
|
-
</FormGroupLevelsManagerContext.Provider>
|
|
40
|
-
);
|
|
41
|
-
};
|
|
42
|
-
|
|
43
|
-
type FormGroupContextType = {
|
|
44
|
-
parentLevel?: number;
|
|
45
|
-
};
|
|
46
|
-
|
|
47
|
-
const FormGroupContext = React.createContext<FormGroupContextType>({});
|
|
48
|
-
|
|
49
|
-
export const useFormGroup = () => {
|
|
50
|
-
const { parentLevel } = React.useContext(FormGroupContext);
|
|
51
|
-
const { levelsLength } = React.useContext(FormGroupLevelsManagerContext);
|
|
52
|
-
|
|
53
|
-
return {
|
|
54
|
-
level: parentLevel,
|
|
55
|
-
levelsLength,
|
|
56
|
-
};
|
|
57
|
-
};
|
|
58
|
-
|
|
59
|
-
type FormGroupProps = {
|
|
60
|
-
name?: string;
|
|
61
|
-
title?: string;
|
|
62
|
-
direction?: 'column' | 'row';
|
|
63
|
-
} & BoxProps;
|
|
64
|
-
|
|
65
|
-
const FormGroupWrapper = ({
|
|
66
|
-
title,
|
|
67
|
-
direction,
|
|
68
|
-
children,
|
|
69
|
-
name,
|
|
70
|
-
...boxProps
|
|
71
|
-
}: FormGroupProps) => {
|
|
72
|
-
const { level } = useFormGroup();
|
|
73
|
-
|
|
74
|
-
const { registerChild } = React.useContext(FormGroupLevelsManagerContext);
|
|
75
|
-
|
|
76
|
-
React.useEffect(() => {
|
|
77
|
-
/**
|
|
78
|
-
* We can't use if(level) because level can be 0 and we want to register
|
|
79
|
-
* it anyway.
|
|
80
|
-
*/
|
|
81
|
-
if (typeof level === 'number') {
|
|
82
|
-
registerChild(level);
|
|
83
|
-
}
|
|
84
|
-
}, [level, registerChild]);
|
|
85
|
-
|
|
86
|
-
const childrenContainerSx: FlexProps['sx'] = {
|
|
87
|
-
flexDirection: direction || 'column',
|
|
88
|
-
gap: 'md',
|
|
89
|
-
width: '100%',
|
|
90
|
-
};
|
|
91
|
-
|
|
92
|
-
return (
|
|
93
|
-
<Box
|
|
94
|
-
aria-level={level}
|
|
95
|
-
{...boxProps}
|
|
96
|
-
sx={{
|
|
97
|
-
marginTop: level === 0 ? 'none' : 'lg',
|
|
98
|
-
marginBottom: 'lg',
|
|
99
|
-
...boxProps.sx,
|
|
100
|
-
}}
|
|
101
|
-
>
|
|
102
|
-
{title && (
|
|
103
|
-
<Box sx={{ marginBottom: 'md' }}>
|
|
104
|
-
<Text
|
|
105
|
-
sx={{
|
|
106
|
-
fontSize: '2xl',
|
|
107
|
-
fontWeight: 'bold',
|
|
108
|
-
}}
|
|
109
|
-
>
|
|
110
|
-
{title}
|
|
111
|
-
</Text>
|
|
112
|
-
</Box>
|
|
113
|
-
)}
|
|
114
|
-
<Flex sx={childrenContainerSx}>{children}</Flex>
|
|
115
|
-
{name && <FormErrorMessage name={name} />}
|
|
116
|
-
</Box>
|
|
117
|
-
);
|
|
118
|
-
};
|
|
119
|
-
|
|
120
|
-
export const FormGroup = (props: FormGroupProps) => {
|
|
121
|
-
const { level } = useFormGroup();
|
|
122
|
-
|
|
123
|
-
const currentLevel = level === undefined ? 0 : level + 1;
|
|
124
|
-
|
|
125
|
-
return (
|
|
126
|
-
<FormGroupContext.Provider value={{ parentLevel: currentLevel }}>
|
|
127
|
-
{currentLevel === 0 ? (
|
|
128
|
-
<FormGroupLevelsManager>
|
|
129
|
-
<FormGroupWrapper {...props} />
|
|
130
|
-
</FormGroupLevelsManager>
|
|
131
|
-
) : (
|
|
132
|
-
<FormGroupWrapper {...props} />
|
|
133
|
-
)}
|
|
134
|
-
</FormGroupContext.Provider>
|
|
135
|
-
);
|
|
136
|
-
};
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
MultistepFlowMessageImageText,
|
|
3
|
-
MultistepFlowMessageImageTextProps,
|
|
4
|
-
} from './MultistepFlowMessageImageText';
|
|
5
|
-
|
|
6
|
-
export type MultistepFlowMessageProps = MultistepFlowMessageImageTextProps;
|
|
7
|
-
|
|
8
|
-
export const MultistepFlowMessage = (props: MultistepFlowMessageProps) => {
|
|
9
|
-
if (props.variant === 'image-text') {
|
|
10
|
-
return <MultistepFlowMessageImageText {...props} />;
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
return null;
|
|
14
|
-
};
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
import * as React from 'react';
|
|
2
|
-
import { Flex, Image, Text } from '@ttoss/ui';
|
|
3
|
-
import { MultistepFlowMessageBase } from './types';
|
|
4
|
-
|
|
5
|
-
export type MultistepFlowMessageImageTextProps = MultistepFlowMessageBase & {
|
|
6
|
-
variant: 'image-text';
|
|
7
|
-
src: string;
|
|
8
|
-
description: string | React.ReactNode;
|
|
9
|
-
};
|
|
10
|
-
|
|
11
|
-
export const MultistepFlowMessageImageText = ({
|
|
12
|
-
src,
|
|
13
|
-
description,
|
|
14
|
-
}: MultistepFlowMessageImageTextProps) => {
|
|
15
|
-
return (
|
|
16
|
-
<Flex
|
|
17
|
-
sx={{
|
|
18
|
-
flexDirection: 'column',
|
|
19
|
-
paddingY: 'xl',
|
|
20
|
-
paddingX: '2xl',
|
|
21
|
-
gap: 'xl',
|
|
22
|
-
}}
|
|
23
|
-
>
|
|
24
|
-
<Image
|
|
25
|
-
src={src}
|
|
26
|
-
sx={{
|
|
27
|
-
width: '184px',
|
|
28
|
-
height: '184px',
|
|
29
|
-
objectFit: 'cover',
|
|
30
|
-
alignSelf: 'center',
|
|
31
|
-
}}
|
|
32
|
-
/>
|
|
33
|
-
|
|
34
|
-
<Text sx={{ textAlign: 'center' }}>{description}</Text>
|
|
35
|
-
</Flex>
|
|
36
|
-
);
|
|
37
|
-
};
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
import { Flex, Text } from '@ttoss/ui';
|
|
2
|
-
|
|
3
|
-
export const MultistepFooter = ({ footer }: { footer: string }) => {
|
|
4
|
-
return (
|
|
5
|
-
<Flex sx={{ display: 'flex', justifyContent: 'center' }}>
|
|
6
|
-
<Text
|
|
7
|
-
sx={{
|
|
8
|
-
textAlign: 'center',
|
|
9
|
-
marginTop: '4xl',
|
|
10
|
-
marginBottom: 'lg',
|
|
11
|
-
marginX: '2xl',
|
|
12
|
-
}}
|
|
13
|
-
>
|
|
14
|
-
{footer}
|
|
15
|
-
</Text>
|
|
16
|
-
</Flex>
|
|
17
|
-
);
|
|
18
|
-
};
|
|
@@ -1,117 +0,0 @@
|
|
|
1
|
-
import * as React from 'react';
|
|
2
|
-
import { Flex } from '@ttoss/ui';
|
|
3
|
-
import { MultistepFlowMessageProps } from './MultistepFlowMessage';
|
|
4
|
-
import { MultistepFooter } from './MultistepFooter';
|
|
5
|
-
import {
|
|
6
|
-
MultistepFormStepper,
|
|
7
|
-
type MultistepFormStepperProps,
|
|
8
|
-
} from './MultistepFormStepper';
|
|
9
|
-
import { MultistepHeader, type MultistepHeaderProps } from './MultistepHeader';
|
|
10
|
-
import { MultistepNavigation } from './MultistepNavigation';
|
|
11
|
-
|
|
12
|
-
export type MultistepStep = {
|
|
13
|
-
question: string;
|
|
14
|
-
flowMessage: MultistepFlowMessageProps;
|
|
15
|
-
label: string;
|
|
16
|
-
fields: React.ReactNode | React.ReactNode[];
|
|
17
|
-
schema?: MultistepFormStepperProps['schema'];
|
|
18
|
-
defaultValues?: MultistepFormStepperProps['defaultValues'];
|
|
19
|
-
};
|
|
20
|
-
|
|
21
|
-
export type MultistepFormProps<FormValues = unknown> = {
|
|
22
|
-
header: MultistepHeaderProps;
|
|
23
|
-
steps: MultistepStep[];
|
|
24
|
-
footer?: string;
|
|
25
|
-
onSubmit: (data: FormValues) => void;
|
|
26
|
-
nextStepButtonLabel?: string;
|
|
27
|
-
submitButtonLabel?: string;
|
|
28
|
-
};
|
|
29
|
-
|
|
30
|
-
export const MultistepForm = ({
|
|
31
|
-
nextStepButtonLabel = 'Next',
|
|
32
|
-
submitButtonLabel = 'Send',
|
|
33
|
-
...props
|
|
34
|
-
}: MultistepFormProps) => {
|
|
35
|
-
const amountOfSteps = props.steps.length;
|
|
36
|
-
const [currentStep, setCurrentStep] = React.useState(1);
|
|
37
|
-
|
|
38
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
39
|
-
const [form, setForm] = React.useState<any>({});
|
|
40
|
-
|
|
41
|
-
const nextStep = () => {
|
|
42
|
-
if (currentStep < amountOfSteps) {
|
|
43
|
-
setCurrentStep((step) => {
|
|
44
|
-
return step + 1;
|
|
45
|
-
});
|
|
46
|
-
}
|
|
47
|
-
};
|
|
48
|
-
|
|
49
|
-
const backStep = () => {
|
|
50
|
-
if (currentStep > 1) {
|
|
51
|
-
setCurrentStep((step) => {
|
|
52
|
-
return step - 1;
|
|
53
|
-
});
|
|
54
|
-
}
|
|
55
|
-
};
|
|
56
|
-
|
|
57
|
-
return (
|
|
58
|
-
<Flex
|
|
59
|
-
sx={{
|
|
60
|
-
flexDirection: 'column',
|
|
61
|
-
maxWidth: '390px',
|
|
62
|
-
background: '#fff',
|
|
63
|
-
}}
|
|
64
|
-
>
|
|
65
|
-
<MultistepHeader {...props.header} />
|
|
66
|
-
{props.steps.map((step, stepIndex) => {
|
|
67
|
-
const isLastStep = stepIndex + 1 === amountOfSteps;
|
|
68
|
-
const isCurrentStep = stepIndex + 1 === currentStep;
|
|
69
|
-
|
|
70
|
-
return (
|
|
71
|
-
<Flex
|
|
72
|
-
sx={{
|
|
73
|
-
flexDirection: 'column',
|
|
74
|
-
display: isCurrentStep ? 'flex' : 'none',
|
|
75
|
-
}}
|
|
76
|
-
key={`form-step-${step.question}`}
|
|
77
|
-
aria-hidden={!isCurrentStep}
|
|
78
|
-
>
|
|
79
|
-
<MultistepFormStepper
|
|
80
|
-
{...step}
|
|
81
|
-
stepNumber={stepIndex + 1}
|
|
82
|
-
isLastStep={isLastStep}
|
|
83
|
-
// isCurrentStep={isCurrentStep}
|
|
84
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
85
|
-
onSubmit={(data: any) => {
|
|
86
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
87
|
-
const newValue = { ...form, ...data };
|
|
88
|
-
|
|
89
|
-
setForm(newValue);
|
|
90
|
-
|
|
91
|
-
if (isLastStep) {
|
|
92
|
-
props.onSubmit(newValue);
|
|
93
|
-
} else {
|
|
94
|
-
nextStep();
|
|
95
|
-
}
|
|
96
|
-
}}
|
|
97
|
-
submitLabel={isLastStep ? submitButtonLabel : nextStepButtonLabel}
|
|
98
|
-
/>
|
|
99
|
-
</Flex>
|
|
100
|
-
);
|
|
101
|
-
})}
|
|
102
|
-
|
|
103
|
-
{currentStep > 1 && (
|
|
104
|
-
<MultistepNavigation
|
|
105
|
-
amountOfSteps={amountOfSteps}
|
|
106
|
-
currentStepNumber={currentStep}
|
|
107
|
-
onBack={backStep}
|
|
108
|
-
stepsLabel={props.steps.map((s) => {
|
|
109
|
-
return s.label;
|
|
110
|
-
})}
|
|
111
|
-
/>
|
|
112
|
-
)}
|
|
113
|
-
|
|
114
|
-
{props.footer && <MultistepFooter footer={props.footer} />}
|
|
115
|
-
</Flex>
|
|
116
|
-
);
|
|
117
|
-
};
|
|
@@ -1,70 +0,0 @@
|
|
|
1
|
-
import * as React from 'react';
|
|
2
|
-
import { Button } from '@ttoss/ui';
|
|
3
|
-
import { Form, useForm, yup, yupResolver } from '../';
|
|
4
|
-
import {
|
|
5
|
-
MultistepFlowMessage,
|
|
6
|
-
MultistepFlowMessageProps,
|
|
7
|
-
} from './MultistepFlowMessage';
|
|
8
|
-
import { MultistepQuestion } from './MultistepQuestion';
|
|
9
|
-
|
|
10
|
-
export type MultistepFormStepperProps = {
|
|
11
|
-
flowMessage: MultistepFlowMessageProps;
|
|
12
|
-
onSubmit: (data: unknown) => void;
|
|
13
|
-
question: string;
|
|
14
|
-
isLastStep: boolean;
|
|
15
|
-
fields: React.ReactNode | React.ReactNode[];
|
|
16
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
17
|
-
schema?: yup.ObjectSchema<any>;
|
|
18
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
19
|
-
defaultValues?: any;
|
|
20
|
-
submitLabel: string;
|
|
21
|
-
stepNumber: number;
|
|
22
|
-
// isCurrentStep: boolean;
|
|
23
|
-
};
|
|
24
|
-
|
|
25
|
-
export const MultistepFormStepper = ({
|
|
26
|
-
flowMessage,
|
|
27
|
-
fields,
|
|
28
|
-
onSubmit,
|
|
29
|
-
question,
|
|
30
|
-
submitLabel,
|
|
31
|
-
schema,
|
|
32
|
-
isLastStep,
|
|
33
|
-
defaultValues,
|
|
34
|
-
stepNumber,
|
|
35
|
-
// isCurrentStep,
|
|
36
|
-
}: MultistepFormStepperProps) => {
|
|
37
|
-
const formMethods = useForm({
|
|
38
|
-
resolver: schema ? yupResolver(schema) : undefined,
|
|
39
|
-
defaultValues,
|
|
40
|
-
});
|
|
41
|
-
|
|
42
|
-
return (
|
|
43
|
-
<Form
|
|
44
|
-
{...formMethods}
|
|
45
|
-
sx={{
|
|
46
|
-
display: 'flex',
|
|
47
|
-
flexDirection: 'column',
|
|
48
|
-
}}
|
|
49
|
-
onSubmit={onSubmit}
|
|
50
|
-
>
|
|
51
|
-
<MultistepFlowMessage {...flowMessage} />
|
|
52
|
-
|
|
53
|
-
<MultistepQuestion fields={fields} question={question} />
|
|
54
|
-
|
|
55
|
-
<Button
|
|
56
|
-
sx={{
|
|
57
|
-
justifyContent: 'center',
|
|
58
|
-
marginTop: '2xl',
|
|
59
|
-
marginBottom: 'xl',
|
|
60
|
-
marginX: '2xl',
|
|
61
|
-
}}
|
|
62
|
-
rightIcon={isLastStep ? undefined : 'nav-right'}
|
|
63
|
-
aria-label={`btn-step-${stepNumber}`}
|
|
64
|
-
type="submit"
|
|
65
|
-
>
|
|
66
|
-
{submitLabel}
|
|
67
|
-
</Button>
|
|
68
|
-
</Form>
|
|
69
|
-
);
|
|
70
|
-
};
|