@granto-umbrella/umbrella-components 3.0.55 → 3.0.57
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/dist/umbrella-components.es.js +23837 -23609
- package/dist/umbrella-components.umd.js +673 -633
- package/package.json +1 -2
- package/src/components/atoms/Button/Button.types.ts +27 -27
- package/src/components/atoms/Checkbox/Checkbox.types.ts +13 -13
- package/src/components/atoms/EditableDurationSelect/EditableDurationSelect.styles.ts +50 -0
- package/src/components/atoms/EditableDurationSelect/EditableDurationSelect.tsx +136 -0
- package/src/components/atoms/EditableDurationSelect/EditableDurationSelect.types.ts +18 -0
- package/src/components/atoms/EditableDurationSelect/index.tsx +1 -0
- package/src/components/atoms/Textarea/Textarea.types.ts +6 -6
- package/src/components/atoms/Tooltip/Tooltip.tsx +60 -60
- package/src/components/atoms/Tooltip/Tootip.styles.ts +153 -153
- package/src/components/atoms/Tooltip/tooltip.types.ts +8 -8
- package/src/components/molecules/RadioGroupField/RadioGroupField.types.ts +0 -2
- package/src/components/molecules/TimeLine/TimeLine.mapper.ts +86 -69
- package/src/components/molecules/TimeLine/TimeLine.registry.ts +66 -0
- package/src/components/molecules/TimeLine/TimeLine.styles.ts +184 -154
- package/src/components/molecules/TimeLine/TimeLine.tsx +100 -96
- package/src/components/molecules/TimeLine/TimeLine.types.ts +65 -124
- package/src/index.ts +161 -159
- package/src/styles/tokens/colors.ts +601 -601
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@granto-umbrella/umbrella-components",
|
|
3
|
-
"version": "3.0.
|
|
3
|
+
"version": "3.0.57",
|
|
4
4
|
"description": "Umbrella Components for React",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "src/index.js",
|
|
@@ -79,7 +79,6 @@
|
|
|
79
79
|
"@storybook/addon-docs": "10.1.6",
|
|
80
80
|
"@storybook/addon-essentials": "^8.6.14",
|
|
81
81
|
"@storybook/addon-onboarding": "10.1.6",
|
|
82
|
-
"@storybook/cli": "^10.1.10",
|
|
83
82
|
"@storybook/react-vite": "^10.1.6",
|
|
84
83
|
"@storybook/test": "^8.6.14",
|
|
85
84
|
"@testing-library/dom": "^10.4.1",
|
|
@@ -1,27 +1,27 @@
|
|
|
1
|
-
export interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
|
|
2
|
-
size?: 'sm' | 'md' | 'lg';
|
|
3
|
-
variant?:
|
|
4
|
-
| 'primary'
|
|
5
|
-
| 'outline'
|
|
6
|
-
| 'outline_ghost'
|
|
7
|
-
| 'outline_ghost_disabled'
|
|
8
|
-
| 'outline_danger'
|
|
9
|
-
| 'danger'
|
|
10
|
-
| 'ghost'
|
|
11
|
-
| 'ghost_alert'
|
|
12
|
-
| 'alert'
|
|
13
|
-
| 'danger-no-fill'
|
|
14
|
-
| 'accent-outline'
|
|
15
|
-
| 'accent-fill'
|
|
16
|
-
| 'secondary-outline'
|
|
17
|
-
| 'danger-fill';
|
|
18
|
-
radius?: string;
|
|
19
|
-
isLoading?: boolean;
|
|
20
|
-
leftIcon?: string;
|
|
21
|
-
rightIcon?: string;
|
|
22
|
-
iconSize?: string;
|
|
23
|
-
fontSize?: string;
|
|
24
|
-
width?: string;
|
|
25
|
-
height?: string;
|
|
26
|
-
testId?: string;
|
|
27
|
-
}
|
|
1
|
+
export interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
|
|
2
|
+
size?: 'sm' | 'md' | 'lg';
|
|
3
|
+
variant?:
|
|
4
|
+
| 'primary'
|
|
5
|
+
| 'outline'
|
|
6
|
+
| 'outline_ghost'
|
|
7
|
+
| 'outline_ghost_disabled'
|
|
8
|
+
| 'outline_danger'
|
|
9
|
+
| 'danger'
|
|
10
|
+
| 'ghost'
|
|
11
|
+
| 'ghost_alert'
|
|
12
|
+
| 'alert'
|
|
13
|
+
| 'danger-no-fill'
|
|
14
|
+
| 'accent-outline'
|
|
15
|
+
| 'accent-fill'
|
|
16
|
+
| 'secondary-outline'
|
|
17
|
+
| 'danger-fill';
|
|
18
|
+
radius?: string;
|
|
19
|
+
isLoading?: boolean;
|
|
20
|
+
leftIcon?: string;
|
|
21
|
+
rightIcon?: string;
|
|
22
|
+
iconSize?: string;
|
|
23
|
+
fontSize?: string;
|
|
24
|
+
width?: string;
|
|
25
|
+
height?: string;
|
|
26
|
+
testId?: string;
|
|
27
|
+
}
|
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
export interface CheckboxProps extends React.InputHTMLAttributes<HTMLInputElement> {
|
|
2
|
-
label?: string;
|
|
3
|
-
checked?: boolean;
|
|
4
|
-
onChange?: () => void;
|
|
5
|
-
disabled?: boolean;
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
export interface CheckboxGroupProps {
|
|
9
|
-
options: { label: string; value: string }[];
|
|
10
|
-
selected: string[];
|
|
11
|
-
setSelected: (values: string[]) => void;
|
|
12
|
-
direction?: 'vertical' | 'horizontal';
|
|
13
|
-
}
|
|
1
|
+
export interface CheckboxProps extends React.InputHTMLAttributes<HTMLInputElement> {
|
|
2
|
+
label?: string;
|
|
3
|
+
checked?: boolean;
|
|
4
|
+
onChange?: () => void;
|
|
5
|
+
disabled?: boolean;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export interface CheckboxGroupProps {
|
|
9
|
+
options: { label: string; value: string }[];
|
|
10
|
+
selected: string[];
|
|
11
|
+
setSelected: (values: string[]) => void;
|
|
12
|
+
direction?: 'vertical' | 'horizontal';
|
|
13
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import styled from 'styled-components';
|
|
2
|
+
import {
|
|
3
|
+
primitiveSizes,
|
|
4
|
+
semanticBorders,
|
|
5
|
+
semanticColors,
|
|
6
|
+
semanticRadius,
|
|
7
|
+
semanticShadows,
|
|
8
|
+
typographyTokens,
|
|
9
|
+
} from '../../../styles/tokens';
|
|
10
|
+
import CreatableSelect from 'react-select/creatable';
|
|
11
|
+
|
|
12
|
+
export const Container = styled.div`
|
|
13
|
+
display: flex;
|
|
14
|
+
flex-direction: column;
|
|
15
|
+
gap: ${primitiveSizes.size.x1};
|
|
16
|
+
width: 100%;
|
|
17
|
+
`;
|
|
18
|
+
|
|
19
|
+
export const Label = styled.label`
|
|
20
|
+
font-size: ${typographyTokens.fontSizes.labelS};
|
|
21
|
+
font-weight: ${typographyTokens.fontWeights.medium};
|
|
22
|
+
color: ${semanticColors.global.text.subtitle.enabled};
|
|
23
|
+
`;
|
|
24
|
+
|
|
25
|
+
export const SupportingText = styled.span<{ $error?: boolean }>`
|
|
26
|
+
font-size: ${typographyTokens.fontSizes.captionM};
|
|
27
|
+
color: ${({ $error }) =>
|
|
28
|
+
$error
|
|
29
|
+
? semanticColors.global.text.feedback.strong.error
|
|
30
|
+
: semanticColors.global.text.subtitle.enabled};
|
|
31
|
+
`;
|
|
32
|
+
|
|
33
|
+
export const CustomSelect = styled(CreatableSelect)<{
|
|
34
|
+
$error?: boolean;
|
|
35
|
+
$size?: 'sm' | 'md' | 'lg';
|
|
36
|
+
}>`
|
|
37
|
+
.react-select__control {
|
|
38
|
+
min-height: ${primitiveSizes.size.x12};
|
|
39
|
+
border-radius: ${semanticRadius.global.radius.md};
|
|
40
|
+
border: ${semanticBorders.global.sm} solid
|
|
41
|
+
${({ $error }) =>
|
|
42
|
+
$error
|
|
43
|
+
? semanticColors.global.border.danger.enabled
|
|
44
|
+
: semanticColors.global.border.medium};
|
|
45
|
+
|
|
46
|
+
&:focus-within {
|
|
47
|
+
box-shadow: ${semanticShadows.shadow.md};
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
`;
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { useMemo, useState } from 'react';
|
|
4
|
+
import type { InputActionMeta } from 'react-select';
|
|
5
|
+
import {
|
|
6
|
+
Container,
|
|
7
|
+
Label,
|
|
8
|
+
SupportingText,
|
|
9
|
+
CustomSelect,
|
|
10
|
+
} from './EditableDurationSelect.styles';
|
|
11
|
+
import {
|
|
12
|
+
DurationOption,
|
|
13
|
+
EditableDurationSelectProps,
|
|
14
|
+
} from './EditableDurationSelect.types';
|
|
15
|
+
|
|
16
|
+
const DAYS_IN_YEAR = 365;
|
|
17
|
+
const BASE_LIMIT = 5;
|
|
18
|
+
|
|
19
|
+
function parseDuration(input: string): DurationOption | null {
|
|
20
|
+
if (!input) return null;
|
|
21
|
+
|
|
22
|
+
const normalized = input.trim().toLowerCase();
|
|
23
|
+
|
|
24
|
+
if (/^\d+$/.test(normalized)) {
|
|
25
|
+
const amount = Number(normalized);
|
|
26
|
+
if (amount <= 0) return null;
|
|
27
|
+
|
|
28
|
+
const isYear = amount <= BASE_LIMIT;
|
|
29
|
+
|
|
30
|
+
return {
|
|
31
|
+
label: isYear
|
|
32
|
+
? `${amount} ${amount > 1 ? 'anos' : 'ano'}`
|
|
33
|
+
: `${amount} ${amount > 1 ? 'dias' : 'dia'}`,
|
|
34
|
+
value: normalized,
|
|
35
|
+
days: isYear ? amount * DAYS_IN_YEAR : amount,
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const match = normalized.match(/^(\d+)\s*(dia|dias|ano|anos)$/);
|
|
40
|
+
if (!match) return null;
|
|
41
|
+
|
|
42
|
+
const amount = Number(match[1]);
|
|
43
|
+
const unit = match[2];
|
|
44
|
+
|
|
45
|
+
if (amount <= 0) return null;
|
|
46
|
+
|
|
47
|
+
const isYear = unit.startsWith('ano');
|
|
48
|
+
|
|
49
|
+
return {
|
|
50
|
+
label: `${amount} ${isYear ? (amount > 1 ? 'anos' : 'ano') : amount > 1 ? 'dias' : 'dia'}`,
|
|
51
|
+
value: normalized,
|
|
52
|
+
days: isYear ? amount * DAYS_IN_YEAR : amount,
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export default function EditableDurationSelect({
|
|
57
|
+
label,
|
|
58
|
+
supportingText,
|
|
59
|
+
value,
|
|
60
|
+
onChange,
|
|
61
|
+
options = [],
|
|
62
|
+
disabled,
|
|
63
|
+
error,
|
|
64
|
+
size = 'md',
|
|
65
|
+
testId,
|
|
66
|
+
baseLimit = BASE_LIMIT,
|
|
67
|
+
}: EditableDurationSelectProps) {
|
|
68
|
+
const [inputValue, setInputValue] = useState('');
|
|
69
|
+
|
|
70
|
+
const parsedInput = useMemo(() => parseDuration(inputValue), [inputValue]);
|
|
71
|
+
|
|
72
|
+
const dynamicOption = useMemo(() => {
|
|
73
|
+
if (!parsedInput) return [];
|
|
74
|
+
return [
|
|
75
|
+
{
|
|
76
|
+
label: parsedInput.label,
|
|
77
|
+
value: parsedInput.value,
|
|
78
|
+
days: parsedInput.days,
|
|
79
|
+
},
|
|
80
|
+
];
|
|
81
|
+
}, [parsedInput]);
|
|
82
|
+
|
|
83
|
+
const mergedOptions = useMemo(() => {
|
|
84
|
+
return [
|
|
85
|
+
...dynamicOption.filter((d) => !options.some((o) => o.days === d.days)),
|
|
86
|
+
...options,
|
|
87
|
+
];
|
|
88
|
+
}, [dynamicOption, options]);
|
|
89
|
+
|
|
90
|
+
const helperText = useMemo(() => {
|
|
91
|
+
if (!inputValue) return supportingText;
|
|
92
|
+
|
|
93
|
+
if (!parsedInput) return 'Valor inválido';
|
|
94
|
+
|
|
95
|
+
return parsedInput.days > baseLimit * DAYS_IN_YEAR
|
|
96
|
+
? `Valores acima de ${baseLimit} são considerados dias`
|
|
97
|
+
: `Valores até ${baseLimit} são considerados anos`;
|
|
98
|
+
}, [baseLimit, inputValue, parsedInput, supportingText]);
|
|
99
|
+
|
|
100
|
+
function handleInputChange(value: string, meta: InputActionMeta) {
|
|
101
|
+
if (meta.action === 'input-change') {
|
|
102
|
+
setInputValue(value);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
function handleChange(option: DurationOption | null) {
|
|
107
|
+
if (!option) return;
|
|
108
|
+
onChange?.(option);
|
|
109
|
+
setInputValue('');
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
return (
|
|
113
|
+
<Container data-testid={testId}>
|
|
114
|
+
{label && <Label>{label}</Label>}
|
|
115
|
+
|
|
116
|
+
<CustomSelect
|
|
117
|
+
isSearchable
|
|
118
|
+
isDisabled={disabled}
|
|
119
|
+
$size={size}
|
|
120
|
+
$error={error}
|
|
121
|
+
options={mergedOptions}
|
|
122
|
+
value={value}
|
|
123
|
+
placeholder="Digite ou selecione"
|
|
124
|
+
onInputChange={handleInputChange}
|
|
125
|
+
onChange={(opt) => handleChange(opt as DurationOption | null)}
|
|
126
|
+
formatCreateLabel={() => null}
|
|
127
|
+
/>
|
|
128
|
+
|
|
129
|
+
{helperText && (
|
|
130
|
+
<SupportingText $error={error || helperText === 'Valor inválido'}>
|
|
131
|
+
{helperText}
|
|
132
|
+
</SupportingText>
|
|
133
|
+
)}
|
|
134
|
+
</Container>
|
|
135
|
+
);
|
|
136
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export type DurationOption = {
|
|
2
|
+
label: string;
|
|
3
|
+
value: string;
|
|
4
|
+
days: number;
|
|
5
|
+
};
|
|
6
|
+
|
|
7
|
+
export interface EditableDurationSelectProps {
|
|
8
|
+
label?: string;
|
|
9
|
+
supportingText?: string;
|
|
10
|
+
value?: DurationOption | null;
|
|
11
|
+
onChange?: (value: DurationOption | null) => void;
|
|
12
|
+
options?: DurationOption[];
|
|
13
|
+
disabled?: boolean;
|
|
14
|
+
error?: boolean;
|
|
15
|
+
size?: 'sm' | 'md' | 'lg';
|
|
16
|
+
testId?: string;
|
|
17
|
+
baseLimit?: number;
|
|
18
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from './EditableDurationSelect';
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
export interface TextareaProps extends React.TextareaHTMLAttributes<HTMLTextAreaElement> {
|
|
2
|
-
label?: string;
|
|
3
|
-
supportingText?: string;
|
|
4
|
-
testId?: string;
|
|
5
|
-
info?: string;
|
|
6
|
-
}
|
|
1
|
+
export interface TextareaProps extends React.TextareaHTMLAttributes<HTMLTextAreaElement> {
|
|
2
|
+
label?: string;
|
|
3
|
+
supportingText?: string;
|
|
4
|
+
testId?: string;
|
|
5
|
+
info?: string;
|
|
6
|
+
}
|
|
@@ -1,60 +1,60 @@
|
|
|
1
|
-
import React, { useState } from 'react';
|
|
2
|
-
import {
|
|
3
|
-
TooltipContainer,
|
|
4
|
-
TooltipTrigger,
|
|
5
|
-
TooltipContent,
|
|
6
|
-
TooltipText,
|
|
7
|
-
TooltipLink,
|
|
8
|
-
} from '../Tooltip/Tootip.styles';
|
|
9
|
-
import { TooltipProps } from './tooltip.types';
|
|
10
|
-
import { ArrowSquareOut } from '@phosphor-icons/react';
|
|
11
|
-
import info from '../../../assets/info.png';
|
|
12
|
-
|
|
13
|
-
const Tooltip: React.FC<TooltipProps> = ({
|
|
14
|
-
children,
|
|
15
|
-
content,
|
|
16
|
-
position = 'top',
|
|
17
|
-
helpLink,
|
|
18
|
-
}) => {
|
|
19
|
-
const [visible, setVisible] = useState(false);
|
|
20
|
-
|
|
21
|
-
const handleMouseEnter = () => {
|
|
22
|
-
setVisible(true);
|
|
23
|
-
};
|
|
24
|
-
|
|
25
|
-
const handleMouseLeave = () => {
|
|
26
|
-
setVisible(false);
|
|
27
|
-
};
|
|
28
|
-
|
|
29
|
-
return (
|
|
30
|
-
<TooltipContainer>
|
|
31
|
-
{children}
|
|
32
|
-
<TooltipTrigger
|
|
33
|
-
onMouseEnter={handleMouseEnter}
|
|
34
|
-
onMouseLeave={handleMouseLeave}
|
|
35
|
-
>
|
|
36
|
-
<img src={info} alt="Informação" />
|
|
37
|
-
</TooltipTrigger>
|
|
38
|
-
<TooltipContent
|
|
39
|
-
$position={position}
|
|
40
|
-
$visible={visible}
|
|
41
|
-
onMouseEnter={handleMouseEnter}
|
|
42
|
-
onMouseLeave={handleMouseLeave}
|
|
43
|
-
>
|
|
44
|
-
<TooltipText>{content}</TooltipText>
|
|
45
|
-
{helpLink && (
|
|
46
|
-
<TooltipLink
|
|
47
|
-
href={helpLink}
|
|
48
|
-
target="_blank"
|
|
49
|
-
rel="noopener noreferrer"
|
|
50
|
-
>
|
|
51
|
-
Saiba mais
|
|
52
|
-
<ArrowSquareOut size={12} weight="bold" />
|
|
53
|
-
</TooltipLink>
|
|
54
|
-
)}
|
|
55
|
-
</TooltipContent>
|
|
56
|
-
</TooltipContainer>
|
|
57
|
-
);
|
|
58
|
-
};
|
|
59
|
-
|
|
60
|
-
export default Tooltip;
|
|
1
|
+
import React, { useState } from 'react';
|
|
2
|
+
import {
|
|
3
|
+
TooltipContainer,
|
|
4
|
+
TooltipTrigger,
|
|
5
|
+
TooltipContent,
|
|
6
|
+
TooltipText,
|
|
7
|
+
TooltipLink,
|
|
8
|
+
} from '../Tooltip/Tootip.styles';
|
|
9
|
+
import { TooltipProps } from './tooltip.types';
|
|
10
|
+
import { ArrowSquareOut } from '@phosphor-icons/react';
|
|
11
|
+
import info from '../../../assets/info.png';
|
|
12
|
+
|
|
13
|
+
const Tooltip: React.FC<TooltipProps> = ({
|
|
14
|
+
children,
|
|
15
|
+
content,
|
|
16
|
+
position = 'top',
|
|
17
|
+
helpLink,
|
|
18
|
+
}) => {
|
|
19
|
+
const [visible, setVisible] = useState(false);
|
|
20
|
+
|
|
21
|
+
const handleMouseEnter = () => {
|
|
22
|
+
setVisible(true);
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
const handleMouseLeave = () => {
|
|
26
|
+
setVisible(false);
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
return (
|
|
30
|
+
<TooltipContainer>
|
|
31
|
+
{children}
|
|
32
|
+
<TooltipTrigger
|
|
33
|
+
onMouseEnter={handleMouseEnter}
|
|
34
|
+
onMouseLeave={handleMouseLeave}
|
|
35
|
+
>
|
|
36
|
+
<img src={info} alt="Informação" />
|
|
37
|
+
</TooltipTrigger>
|
|
38
|
+
<TooltipContent
|
|
39
|
+
$position={position}
|
|
40
|
+
$visible={visible}
|
|
41
|
+
onMouseEnter={handleMouseEnter}
|
|
42
|
+
onMouseLeave={handleMouseLeave}
|
|
43
|
+
>
|
|
44
|
+
<TooltipText>{content}</TooltipText>
|
|
45
|
+
{helpLink && (
|
|
46
|
+
<TooltipLink
|
|
47
|
+
href={helpLink}
|
|
48
|
+
target="_blank"
|
|
49
|
+
rel="noopener noreferrer"
|
|
50
|
+
>
|
|
51
|
+
Saiba mais
|
|
52
|
+
<ArrowSquareOut size={12} weight="bold" />
|
|
53
|
+
</TooltipLink>
|
|
54
|
+
)}
|
|
55
|
+
</TooltipContent>
|
|
56
|
+
</TooltipContainer>
|
|
57
|
+
);
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
export default Tooltip;
|