@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.
Files changed (43) hide show
  1. package/LICENSE +21 -674
  2. package/dist/Brazil/index.d.ts +24 -0
  3. package/dist/FormFieldPatternFormat-CkcL14ho.d.ts +10 -0
  4. package/dist/MultistepForm/index.d.ts +65 -0
  5. package/dist/esm/Brazil/index.js +51 -0
  6. package/dist/esm/MultistepForm/index.js +2502 -0
  7. package/dist/esm/chunk-6U527R3X.js +741 -0
  8. package/dist/esm/index.js +3 -0
  9. package/dist/index.d.ts +107 -0
  10. package/{src/yup/typings.d.ts → dist/typings.d-HZBqJJjn.d.ts} +1 -3
  11. package/package.json +11 -11
  12. package/src/Brazil/FormFieldCEP.tsx +0 -25
  13. package/src/Brazil/FormFieldCNPJ.tsx +0 -93
  14. package/src/Brazil/FormFieldPhone.tsx +0 -41
  15. package/src/Brazil/index.ts +0 -4
  16. package/src/Form.tsx +0 -29
  17. package/src/FormErrorMessage.tsx +0 -60
  18. package/src/FormField.tsx +0 -86
  19. package/src/FormFieldCheckbox.tsx +0 -49
  20. package/src/FormFieldCreditCardNumber.tsx +0 -25
  21. package/src/FormFieldCurrencyInput.tsx +0 -36
  22. package/src/FormFieldInput.tsx +0 -43
  23. package/src/FormFieldNumericFormat.tsx +0 -35
  24. package/src/FormFieldPassword.tsx +0 -43
  25. package/src/FormFieldPatternFormat.tsx +0 -36
  26. package/src/FormFieldRadio.tsx +0 -57
  27. package/src/FormFieldSelect.tsx +0 -47
  28. package/src/FormFieldTextarea.tsx +0 -36
  29. package/src/FormGroup.tsx +0 -136
  30. package/src/MultistepForm/MultistepFlowMessage.tsx +0 -14
  31. package/src/MultistepForm/MultistepFlowMessageImageText.tsx +0 -37
  32. package/src/MultistepForm/MultistepFooter.tsx +0 -18
  33. package/src/MultistepForm/MultistepForm.tsx +0 -117
  34. package/src/MultistepForm/MultistepFormStepper.tsx +0 -70
  35. package/src/MultistepForm/MultistepHeader.tsx +0 -78
  36. package/src/MultistepForm/MultistepNavigation.tsx +0 -38
  37. package/src/MultistepForm/MultistepQuestion.tsx +0 -28
  38. package/src/MultistepForm/index.ts +0 -1
  39. package/src/MultistepForm/types.ts +0 -7
  40. package/src/index.ts +0 -35
  41. package/src/yup/i18n.ts +0 -31
  42. package/src/yup/schema.ts +0 -26
  43. 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
- };
@@ -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
- };