@ttoss/forms 0.26.0 → 0.26.2

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 (35) hide show
  1. package/LICENSE +21 -674
  2. package/package.json +11 -11
  3. package/src/Brazil/FormFieldCEP.tsx +0 -25
  4. package/src/Brazil/FormFieldCNPJ.tsx +0 -93
  5. package/src/Brazil/FormFieldPhone.tsx +0 -41
  6. package/src/Brazil/index.ts +0 -4
  7. package/src/Form.tsx +0 -29
  8. package/src/FormErrorMessage.tsx +0 -60
  9. package/src/FormField.tsx +0 -86
  10. package/src/FormFieldCheckbox.tsx +0 -49
  11. package/src/FormFieldCreditCardNumber.tsx +0 -25
  12. package/src/FormFieldCurrencyInput.tsx +0 -36
  13. package/src/FormFieldInput.tsx +0 -43
  14. package/src/FormFieldNumericFormat.tsx +0 -35
  15. package/src/FormFieldPassword.tsx +0 -43
  16. package/src/FormFieldPatternFormat.tsx +0 -36
  17. package/src/FormFieldRadio.tsx +0 -57
  18. package/src/FormFieldSelect.tsx +0 -47
  19. package/src/FormFieldTextarea.tsx +0 -36
  20. package/src/FormGroup.tsx +0 -136
  21. package/src/MultistepForm/MultistepFlowMessage.tsx +0 -14
  22. package/src/MultistepForm/MultistepFlowMessageImageText.tsx +0 -37
  23. package/src/MultistepForm/MultistepFooter.tsx +0 -18
  24. package/src/MultistepForm/MultistepForm.tsx +0 -117
  25. package/src/MultistepForm/MultistepFormStepper.tsx +0 -70
  26. package/src/MultistepForm/MultistepHeader.tsx +0 -78
  27. package/src/MultistepForm/MultistepNavigation.tsx +0 -38
  28. package/src/MultistepForm/MultistepQuestion.tsx +0 -28
  29. package/src/MultistepForm/index.ts +0 -1
  30. package/src/MultistepForm/types.ts +0 -7
  31. package/src/index.ts +0 -35
  32. package/src/yup/i18n.ts +0 -31
  33. package/src/yup/schema.ts +0 -26
  34. package/src/yup/typings.d.ts +0 -14
  35. package/src/yup/yup.ts +0 -4
@@ -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
- };
@@ -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
- };
@@ -1,78 +0,0 @@
1
- import { CloseButton, Flex, Image, Text } from '@ttoss/ui';
2
- import { Icon, type IconType } from '@ttoss/react-icons';
3
-
4
- type MultistepHeaderTitledProps = {
5
- variant: 'titled';
6
- title: string;
7
- leftIcon: IconType;
8
- rightIcon: IconType;
9
- onLeftIconClick: () => void;
10
- onRightIconClick: () => void;
11
- };
12
-
13
- const MultistepHeaderTitled = ({
14
- title,
15
- leftIcon,
16
- onLeftIconClick,
17
- rightIcon,
18
- onRightIconClick,
19
- }: MultistepHeaderTitledProps) => {
20
- return (
21
- <Flex
22
- sx={{
23
- display: 'flex',
24
- justifyContent: 'space-between',
25
- paddingX: 'xl',
26
- paddingY: 'lg',
27
- alignItems: 'center',
28
- }}
29
- >
30
- <Icon icon={leftIcon} onClick={onLeftIconClick} />
31
- <Text sx={{ fontWeight: 'bold', fontSize: 'lg' }}>{title}</Text>
32
- <Icon icon={rightIcon} onClick={onRightIconClick} />
33
- </Flex>
34
- );
35
- };
36
-
37
- type MultistepHeaderLogoProps = {
38
- variant: 'logo';
39
- src: string;
40
- onClose?: () => void;
41
- };
42
-
43
- const MultistepHeaderLogo = ({ onClose, src }: MultistepHeaderLogoProps) => {
44
- return (
45
- <Flex
46
- sx={{
47
- justifyContent: 'space-between',
48
- alignItems: 'center',
49
- paddingX: 'xl',
50
- paddingY: 'lg',
51
- }}
52
- >
53
- <Image
54
- width={115}
55
- height={32}
56
- sx={{ objectFit: 'cover', width: 115, height: 32 }}
57
- src={src}
58
- />
59
- {onClose && <CloseButton onClick={onClose} />}
60
- </Flex>
61
- );
62
- };
63
-
64
- export type MultistepHeaderProps =
65
- | MultistepHeaderLogoProps
66
- | MultistepHeaderTitledProps;
67
-
68
- export const MultistepHeader = (props: MultistepHeaderProps) => {
69
- if (props.variant === 'logo') {
70
- return <MultistepHeaderLogo {...props} />;
71
- }
72
-
73
- if (props.variant === 'titled') {
74
- return <MultistepHeaderTitled {...props} />;
75
- }
76
-
77
- return null;
78
- };
@@ -1,38 +0,0 @@
1
- import { Flex, Text } from '@ttoss/ui';
2
- import { Icon } from '@ttoss/react-icons';
3
-
4
- export type MultistepNavigationProps = {
5
- amountOfSteps: number;
6
- currentStepNumber: number;
7
- onBack: () => void;
8
- stepsLabel: string[];
9
- };
10
-
11
- export const MultistepNavigation = ({
12
- amountOfSteps,
13
- currentStepNumber,
14
- onBack,
15
- stepsLabel,
16
- }: MultistepNavigationProps) => {
17
- return (
18
- <Flex
19
- sx={{
20
- justifyContent: 'space-between',
21
- marginX: '2xl',
22
- }}
23
- >
24
- <Flex onClick={onBack} sx={{ alignItems: 'center', cursor: 'pointer' }}>
25
- <Text sx={{ color: '#ACADB7', display: 'flex' }}>
26
- <Icon icon="nav-left" />
27
- </Text>
28
- <Text sx={{ color: '#ACADB7' }}>
29
- {stepsLabel[currentStepNumber - 2]}
30
- </Text>
31
- </Flex>
32
-
33
- <Text sx={{ alignItems: 'center', color: '#ACADB7' }}>
34
- {currentStepNumber}/{amountOfSteps}
35
- </Text>
36
- </Flex>
37
- );
38
- };
@@ -1,28 +0,0 @@
1
- import * as React from 'react';
2
- import { Flex, Text } from '@ttoss/ui';
3
-
4
- type MultistepQuestionProps = {
5
- question: string;
6
- fields: React.ReactNode | React.ReactNode[];
7
- };
8
-
9
- export const MultistepQuestion = ({
10
- fields,
11
- question,
12
- }: MultistepQuestionProps) => {
13
- return (
14
- <Flex
15
- sx={{
16
- flexDirection: 'column',
17
- paddingTop: 'xl',
18
- paddingX: '2xl',
19
- }}
20
- >
21
- <Text sx={{ textAlign: 'center', fontSize: 'lg', marginBottom: 'xl' }}>
22
- {question}
23
- </Text>
24
-
25
- <Flex sx={{ flexDirection: 'column', gap: 'xl' }}>{fields}</Flex>
26
- </Flex>
27
- );
28
- };
@@ -1 +0,0 @@
1
- export { MultistepForm, type MultistepFormProps } from './MultistepForm';
@@ -1,7 +0,0 @@
1
- export type MultistepFlowMessageVariant =
2
- | 'image-text'
3
- | 'heading-and-subheading';
4
-
5
- export type MultistepFlowMessageBase = {
6
- variant: MultistepFlowMessageVariant;
7
- };