@1doc/1ds-react 2.9.0 → 2.10.0
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/CHANGELOG.md +434 -0
- package/dist/components/Accordion/Accordion.css +13 -0
- package/dist/components/Accordion/Accordion.d.ts +3 -0
- package/dist/components/Accordion/Accordion.js +1 -0
- package/dist/components/AppSubheader/AppSubheader.css +10 -1
- package/dist/components/AttachmentCard/AttachmentCard.css +10 -8
- package/dist/components/AttachmentCard/AttachmentCard.d.ts +3 -0
- package/dist/components/AttachmentCard/AttachmentCard.js +8 -1
- package/dist/components/Badge/Badge.css +14 -1
- package/dist/components/Badge/Badge.d.ts +11 -2
- package/dist/components/Badge/Badge.js +3 -0
- package/dist/components/Calendar/Calendar.d.ts +7 -6
- package/dist/components/Coachmark/Coachmark.css +10 -0
- package/dist/components/Coachmark/Coachmark.d.ts +12 -0
- package/dist/components/Coachmark/Coachmark.js +46 -5
- package/dist/components/ColorPicker/ColorPicker.css +8 -1
- package/dist/components/ColorPicker/ColorPicker.d.ts +2 -2
- package/dist/components/DataTable/DataTable.css +174 -0
- package/dist/components/DataTable/DataTable.d.ts +63 -2
- package/dist/components/DataTable/DataTable.js +278 -6
- package/dist/components/DescriptionList/DescriptionList.css +14 -0
- package/dist/components/DescriptionList/DescriptionList.d.ts +3 -0
- package/dist/components/DescriptionList/DescriptionList.js +1 -0
- package/dist/components/EmptyState/EmptyState.d.ts +4 -2
- package/dist/components/EmptyState/EmptyState.js +2 -2
- package/dist/components/Input/Input.css +21 -0
- package/dist/components/Input/Input.d.ts +7 -0
- package/dist/components/Input/Input.js +2 -1
- package/dist/components/List/ListItem.d.ts +14 -2
- package/dist/components/List/ListItem.js +3 -2
- package/dist/components/RichTextEditor/RichTextEditor.css +47 -0
- package/dist/components/RichTextEditor/RichTextEditor.d.ts +22 -8
- package/dist/components/RichTextEditor/RichTextEditor.js +460 -3
- package/dist/components/SegmentedControl/SegmentedControl.css +24 -0
- package/dist/components/SegmentedControl/SegmentedControl.d.ts +2 -0
- package/dist/components/SegmentedControl/SegmentedControl.js +4 -1
- package/dist/components/Select/Select.css +94 -0
- package/dist/components/Select/Select.d.ts +26 -4
- package/dist/components/Select/Select.js +210 -35
- package/dist/components/StatCard/StatCard.css +65 -0
- package/dist/components/StatCard/StatCard.d.ts +9 -0
- package/dist/components/StatCard/StatCard.js +10 -1
- package/dist/components/Toast/Toast.css +32 -0
- package/dist/components/Toast/Toast.d.ts +18 -0
- package/dist/components/Toast/Toast.js +14 -1
- package/dist/components/Toast/ToastStack.js +8 -1
- package/dist/teste/AccordionTituloNeutro.test.d.ts +1 -0
- package/dist/teste/AccordionTituloNeutro.test.js +23 -0
- package/dist/teste/AppSubheaderRegiao.test.d.ts +1 -0
- package/dist/teste/AppSubheaderRegiao.test.js +13 -0
- package/dist/teste/AttachmentCardLista.test.d.ts +1 -0
- package/dist/teste/AttachmentCardLista.test.js +49 -0
- package/dist/teste/AttachmentCardSm.test.d.ts +1 -0
- package/dist/teste/AttachmentCardSm.test.js +26 -0
- package/dist/teste/BadgeNeutroColado.test.d.ts +1 -0
- package/dist/teste/BadgeNeutroColado.test.js +11 -0
- package/dist/teste/BadgeTag.test.js +13 -0
- package/dist/teste/CalendarCabecalho.test.d.ts +1 -0
- package/dist/teste/CalendarCabecalho.test.js +11 -0
- package/dist/teste/CoachmarkSemVeu.test.d.ts +1 -0
- package/dist/teste/CoachmarkSemVeu.test.js +85 -0
- package/dist/teste/ColorPickerXs.test.d.ts +1 -0
- package/dist/teste/ColorPickerXs.test.js +21 -0
- package/dist/teste/DataTableArvoreEVariantes.test.d.ts +1 -0
- package/dist/teste/DataTableArvoreEVariantes.test.js +190 -0
- package/dist/teste/DescriptionListCompacta.test.d.ts +1 -0
- package/dist/teste/DescriptionListCompacta.test.js +22 -0
- package/dist/teste/EmptyStateTituloRico.test.d.ts +1 -0
- package/dist/teste/EmptyStateTituloRico.test.js +23 -0
- package/dist/teste/InputAgrupado.test.d.ts +1 -0
- package/dist/teste/InputAgrupado.test.js +24 -0
- package/dist/teste/ListItemTooltipStandalone.test.d.ts +1 -0
- package/dist/teste/ListItemTooltipStandalone.test.js +39 -0
- package/dist/teste/RichTextEditorAlinhaImagemTabela.test.d.ts +1 -0
- package/dist/teste/RichTextEditorAlinhaImagemTabela.test.js +212 -0
- package/dist/teste/RichTextEditorEstiloDeTexto.test.d.ts +1 -0
- package/dist/teste/RichTextEditorEstiloDeTexto.test.js +120 -0
- package/dist/teste/SegmentedControlContador.test.d.ts +1 -0
- package/dist/teste/SegmentedControlContador.test.js +39 -0
- package/dist/teste/SelectAbertoControladoEFlutuante.test.d.ts +1 -0
- package/dist/teste/SelectAbertoControladoEFlutuante.test.js +145 -0
- package/dist/teste/SelectFiltroCorETamanho.test.d.ts +1 -0
- package/dist/teste/SelectFiltroCorETamanho.test.js +77 -0
- package/dist/teste/StatCardSecundariaETom.test.d.ts +1 -0
- package/dist/teste/StatCardSecundariaETom.test.js +45 -0
- package/dist/teste/ToastAcaoEDetalhes.test.d.ts +1 -0
- package/dist/teste/ToastAcaoEDetalhes.test.js +94 -0
- package/dist/utils/html-seguro.d.ts +19 -1
- package/dist/utils/html-seguro.js +113 -2
- package/dist/utils/toast.d.ts +10 -1
- package/dist/utils/toast.js +2 -1
- package/package.json +2 -2
- package/src/teste/AccordionTituloNeutro.test.tsx +25 -0
- package/src/teste/AppSubheaderRegiao.test.tsx +17 -0
- package/src/teste/AttachmentCardLista.test.tsx +53 -0
- package/src/teste/AttachmentCardSm.test.tsx +29 -0
- package/src/teste/BadgeNeutroColado.test.tsx +15 -0
- package/src/teste/BadgeTag.test.tsx +21 -0
- package/src/teste/CalendarCabecalho.test.tsx +11 -0
- package/src/teste/CoachmarkSemVeu.test.tsx +101 -0
- package/src/teste/ColorPickerXs.test.tsx +22 -0
- package/src/teste/DataTableArvoreEVariantes.test.tsx +240 -0
- package/src/teste/DescriptionListCompacta.test.tsx +24 -0
- package/src/teste/EmptyStateTituloRico.test.tsx +34 -0
- package/src/teste/InputAgrupado.test.tsx +26 -0
- package/src/teste/ListItemTooltipStandalone.test.tsx +64 -0
- package/src/teste/RichTextEditorAlinhaImagemTabela.test.tsx +238 -0
- package/src/teste/RichTextEditorEstiloDeTexto.test.tsx +137 -0
- package/src/teste/SegmentedControlContador.test.tsx +43 -0
- package/src/teste/SelectAbertoControladoEFlutuante.test.tsx +180 -0
- package/src/teste/SelectFiltroCorETamanho.test.tsx +90 -0
- package/src/teste/StatCardSecundariaETom.test.tsx +51 -0
- package/src/teste/ToastAcaoEDetalhes.test.tsx +109 -0
- package/src/utils/html-seguro.ts +105 -2
- package/src/utils/toast.ts +12 -2
|
@@ -23,6 +23,9 @@ import './StatCard.css';
|
|
|
23
23
|
* @property {string} trendLabel - Texto da variação (ex.: '12% em relação ao mês anterior')
|
|
24
24
|
* @property {string} description - Texto auxiliar abaixo do rótulo
|
|
25
25
|
* @property {string} labelPosition - Onde o rótulo aparece: 'bottom' (padrão, embaixo do número) | 'top' (no topo do cartão, acima do ícone e do número, com o número em 32/800). No HTML o número continua vindo antes do rótulo, então o leitor de tela anuncia igual.
|
|
26
|
+
* @property {string|number} secondaryValue - Segunda medida do cartão, menor, à direita da principal ("22,31%" do setor e "14,11%" do geral). Vem depois do resto no HTML. `0` aparece; vazio e ausente não.
|
|
27
|
+
* @property {string} secondaryLabel - O que a segunda medida significa ("Geral")
|
|
28
|
+
* @property {string} valueTone - Cor do número principal: 'default' (cor do texto) | 'primary' | 'positive' | 'negative' | 'info'. Usa as variantes escuras (contraste AA sobre o branco). Não confunda com `variant`, que pinta o ícone e a variação.
|
|
26
29
|
* @property {string} infoTooltip - Texto de ajuda: mostra um ⓘ ao lado do rótulo com um Tooltip escuro. É um botão dentro do cartão; com `onClick` no cartão, evite (botão dentro de botão).
|
|
27
30
|
* @property {string} infoLabel - Nome acessível do ⓘ. Troque para traduzir. Padrão: "Mais informações".
|
|
28
31
|
* @property {string} align - Alinhamento do conteúdo
|
|
@@ -66,6 +69,12 @@ export interface StatCardProps {
|
|
|
66
69
|
* @default 'bottom'
|
|
67
70
|
*/
|
|
68
71
|
labelPosition?: "bottom" | "top";
|
|
72
|
+
/** Segunda medida, menor, à direita da principal. 0 aparece; vazio e ausente não. */
|
|
73
|
+
secondaryValue?: string | number;
|
|
74
|
+
/** O que a segunda medida significa. */
|
|
75
|
+
secondaryLabel?: string;
|
|
76
|
+
/** Cor do número principal. @default 'default' */
|
|
77
|
+
valueTone?: "default" | "primary" | "positive" | "negative" | "info";
|
|
69
78
|
/**
|
|
70
79
|
* Texto de ajuda: mostra o ⓘ ao lado do rótulo, com um Tooltip escuro. É um
|
|
71
80
|
* botão focável dentro do cartão; com `onClick` no cartão, evite.
|
|
@@ -11,6 +11,10 @@ function StatCard(props) {
|
|
|
11
11
|
`umds-stat-card--${props.variant || "neutral"}`,
|
|
12
12
|
props.align === "center" ? "umds-stat-card--centro" : "",
|
|
13
13
|
props.labelPosition === "top" ? "umds-stat-card--rotulo-topo" : "",
|
|
14
|
+
temSecundaria() ? "umds-stat-card--com-secundaria" : "",
|
|
15
|
+
props.valueTone && props.valueTone !== "default"
|
|
16
|
+
? "umds-stat-card--valor-" + props.valueTone
|
|
17
|
+
: "",
|
|
14
18
|
props.onClick ? "umds-stat-card--acionavel" : "",
|
|
15
19
|
props.className,
|
|
16
20
|
]
|
|
@@ -38,6 +42,11 @@ function StatCard(props) {
|
|
|
38
42
|
return "↓";
|
|
39
43
|
return "→";
|
|
40
44
|
}
|
|
45
|
+
function temSecundaria() {
|
|
46
|
+
return (props.secondaryValue !== undefined &&
|
|
47
|
+
props.secondaryValue !== null &&
|
|
48
|
+
props.secondaryValue !== "");
|
|
49
|
+
}
|
|
41
50
|
function ehAcionavel() {
|
|
42
51
|
return !!props.onClick;
|
|
43
52
|
}
|
|
@@ -48,6 +57,6 @@ function StatCard(props) {
|
|
|
48
57
|
if (props.onClick)
|
|
49
58
|
props.onClick();
|
|
50
59
|
}
|
|
51
|
-
return (_jsxs("div", { className: classes(), onClick: (event) => aoClicar(), role: ehAcionavel() ? "button" : undefined, tabIndex: ehAcionavel() ? 0 : undefined, children: [props.icon ? (_jsx("span", { className: "umds-stat-card__icone", "aria-hidden": "true", children: _jsx(Icon, { size: "md", variant: "inherit", icon: props.icon }) })) : null, _jsxs("div", { className: "umds-stat-card__corpo", children: [_jsx("span", { className: "umds-stat-card__valor", children: props.value }), _jsxs("span", { className: "umds-stat-card__rotulo", children: [props.label, props.infoTooltip ? (_jsx(Tooltip, { variant: "dark", side: "top", content: props.infoTooltip, children: _jsx("button", { type: "button", className: "umds-stat-card__info", "aria-label": props.infoLabel || "Mais informações", children: _jsx(Icon, { variant: "inherit", customSize: "14px", icon: faCircleInfo }) }) })) : null] }), props.description ? (_jsx("span", { className: "umds-stat-card__descricao", children: props.description })) : null, props.trendLabel ? (_jsxs("span", { className: classesDaVariacao(), children: [_jsx("span", { "aria-hidden": "true", children: simboloDaVariacao() }), props.trendLabel] })) : null] })] }));
|
|
60
|
+
return (_jsxs("div", { className: classes(), onClick: (event) => aoClicar(), role: ehAcionavel() ? "button" : undefined, tabIndex: ehAcionavel() ? 0 : undefined, children: [props.icon ? (_jsx("span", { className: "umds-stat-card__icone", "aria-hidden": "true", children: _jsx(Icon, { size: "md", variant: "inherit", icon: props.icon }) })) : null, _jsxs("div", { className: "umds-stat-card__corpo", children: [_jsx("span", { className: "umds-stat-card__valor", children: props.value }), _jsxs("span", { className: "umds-stat-card__rotulo", children: [props.label, props.infoTooltip ? (_jsx(Tooltip, { variant: "dark", side: "top", content: props.infoTooltip, children: _jsx("button", { type: "button", className: "umds-stat-card__info", "aria-label": props.infoLabel || "Mais informações", children: _jsx(Icon, { variant: "inherit", customSize: "14px", icon: faCircleInfo }) }) })) : null] }), props.description ? (_jsx("span", { className: "umds-stat-card__descricao", children: props.description })) : null, props.trendLabel ? (_jsxs("span", { className: classesDaVariacao(), children: [_jsx("span", { "aria-hidden": "true", children: simboloDaVariacao() }), props.trendLabel] })) : null] }), temSecundaria() ? (_jsxs("div", { className: "umds-stat-card__secundaria", children: [_jsx("span", { className: "umds-stat-card__valor-secundario", children: props.secondaryValue }), props.secondaryLabel ? (_jsx("span", { className: "umds-stat-card__rotulo-secundario", children: props.secondaryLabel })) : null] })) : null] }));
|
|
52
61
|
}
|
|
53
62
|
export default StatCard;
|
|
@@ -123,6 +123,38 @@
|
|
|
123
123
|
line-height: 1.5;
|
|
124
124
|
}
|
|
125
125
|
|
|
126
|
+
/* ── Detalhes (details) e ação (actionLabel) ── */
|
|
127
|
+
.umds-toast__details {
|
|
128
|
+
margin: 0;
|
|
129
|
+
padding-left: var(--umds-primitive-spacing-xxxs); /* 16px */
|
|
130
|
+
font-size: var(--umds-primitive-font-size-xxxs); /* 12px */
|
|
131
|
+
line-height: 1.5;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
.umds-toast__action {
|
|
135
|
+
align-self: flex-start;
|
|
136
|
+
display: inline-flex;
|
|
137
|
+
align-items: center;
|
|
138
|
+
/* Alvo mínimo de 24px (WCAG 2.5.8). */
|
|
139
|
+
min-height: var(--umds-primitive-spacing-xxs);
|
|
140
|
+
margin: 0;
|
|
141
|
+
padding: 0;
|
|
142
|
+
border: none;
|
|
143
|
+
background: none;
|
|
144
|
+
color: inherit;
|
|
145
|
+
font-family: inherit;
|
|
146
|
+
font-size: var(--umds-primitive-font-size-xxxs); /* 12px */
|
|
147
|
+
font-weight: var(--umds-primitive-font-weight-bold);
|
|
148
|
+
text-decoration: underline;
|
|
149
|
+
cursor: pointer;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
.umds-toast__action:focus-visible {
|
|
153
|
+
outline: 2px solid currentColor;
|
|
154
|
+
outline-offset: 2px;
|
|
155
|
+
border-radius: var(--umds-primitive-border-radius-xs);
|
|
156
|
+
}
|
|
157
|
+
|
|
126
158
|
/* ── Fechar ── */
|
|
127
159
|
.umds-toast__close {
|
|
128
160
|
display: flex;
|
|
@@ -4,6 +4,12 @@ import './Toast.css';
|
|
|
4
4
|
* na raiz do documento (não fica presa ao overflow do elemento pai).
|
|
5
5
|
* Comunica o resultado de uma ação (sucesso, erro, aviso ou informação) e pode
|
|
6
6
|
* fechar automaticamente após um tempo.
|
|
7
|
+
*
|
|
8
|
+
* Com `actionLabel` e `onAction`, o toast ganha uma ação ("Desfazer", "Ver * processo"): um botão depois do texto. Acioná-la chama `onAction` e fecha o
|
|
9
|
+
* toast. Toast com ação não deve sumir sozinho antes de dar tempo de agir
|
|
10
|
+
* (WCAG 2.2.1): no `toast()` imperativo o padrão passa a ser `duration: 0`, e no
|
|
11
|
+
* declarativo vale o que você passar. `details` é uma lista de linhas
|
|
12
|
+
* curtas abaixo da descrição (o que deu errado, item a item).
|
|
7
13
|
* @quandoUsar Retorno TRANSITÓRIO e não-bloqueante de uma ação recém-executada: "Processo salvo", "Link copiado". Aparece sobreposto e some sozinho.
|
|
8
14
|
* @quandoNaoUsar Para mensagem que precisa continuar visível ou ser relida — use `Alert`. Para erro que impede o usuário de prosseguir, use `Alert` junto ao campo.
|
|
9
15
|
*/
|
|
@@ -28,6 +34,18 @@ export interface ToastProps {
|
|
|
28
34
|
* Descrição adicional exibida abaixo da mensagem.
|
|
29
35
|
*/
|
|
30
36
|
description?: string;
|
|
37
|
+
/**
|
|
38
|
+
* Lista de detalhes, uma linha por item, abaixo da descrição ("Anexo 3 acima * de 10 MB", "Despacho sem assunto").
|
|
39
|
+
*/
|
|
40
|
+
details?: string[];
|
|
41
|
+
/**
|
|
42
|
+
* Rótulo do botão de ação ("Desfazer"). O botão só aparece com `onAction`.
|
|
43
|
+
*/
|
|
44
|
+
actionLabel?: string;
|
|
45
|
+
/**
|
|
46
|
+
* Chamado ao acionar o botão de ação. Depois dele o toast fecha (`onClose`).
|
|
47
|
+
*/
|
|
48
|
+
onAction?: (event?: any) => void;
|
|
31
49
|
/**
|
|
32
50
|
* Posição na tela onde o toast é fixado.
|
|
33
51
|
* @default 'top-right'
|
|
@@ -31,6 +31,19 @@ function Toast(props) {
|
|
|
31
31
|
return faCircleXmark;
|
|
32
32
|
return faCircleInfo;
|
|
33
33
|
}
|
|
34
|
+
function detailList() {
|
|
35
|
+
return props.details || [];
|
|
36
|
+
}
|
|
37
|
+
function hasAction() {
|
|
38
|
+
return !!(props.actionLabel && props.onAction);
|
|
39
|
+
}
|
|
40
|
+
function handleAction(event) {
|
|
41
|
+
if (event)
|
|
42
|
+
event.stopPropagation();
|
|
43
|
+
if (props.onAction)
|
|
44
|
+
props.onAction(event);
|
|
45
|
+
handleClose(event);
|
|
46
|
+
}
|
|
34
47
|
function handleClose(event) {
|
|
35
48
|
if (event)
|
|
36
49
|
event.stopPropagation();
|
|
@@ -58,6 +71,6 @@ function Toast(props) {
|
|
|
58
71
|
}
|
|
59
72
|
};
|
|
60
73
|
}, []);
|
|
61
|
-
return (_jsx(Portal, { container: props.portalContainer, children: _jsx("div", { role: liveRole(), "aria-live": ariaLive(), children: props.open ? (_jsxs("div", { className: toastClasses(), children: [_jsx("div", { className: "umds-toast__icon-wrap", children: _jsx("span", { "aria-hidden": "true", className: "umds-toast__icon", children: _jsx(Icon, { variant: "inherit", customSize: "14px", icon: iconName() }) }) }), _jsxs("div", { className: "umds-toast__body", children: [_jsx("span", { className: "umds-toast__message", children: props.message }), props.description ? (_jsx("span", { className: "umds-toast__description", children: props.description })) : null] }), props.closable !== false ? (_jsx("button", { type: "button", className: "umds-toast__close", onClick: (event) => handleClose(event), "aria-label": props.closeLabel || "Fechar notificação", children: _jsx(Icon, { variant: "inherit", customSize: "18px", icon: faXmark }) })) : null] })) : null }) }));
|
|
74
|
+
return (_jsx(Portal, { container: props.portalContainer, children: _jsx("div", { role: liveRole(), "aria-live": ariaLive(), children: props.open ? (_jsxs("div", { className: toastClasses(), children: [_jsx("div", { className: "umds-toast__icon-wrap", children: _jsx("span", { "aria-hidden": "true", className: "umds-toast__icon", children: _jsx(Icon, { variant: "inherit", customSize: "14px", icon: iconName() }) }) }), _jsxs("div", { className: "umds-toast__body", children: [_jsx("span", { className: "umds-toast__message", children: props.message }), props.description ? (_jsx("span", { className: "umds-toast__description", children: props.description })) : null, detailList().length > 0 ? (_jsx("ul", { className: "umds-toast__details", children: detailList()?.map((detalhe) => (_jsx("li", { children: detalhe }, detalhe))) })) : null, hasAction() ? (_jsx("button", { type: "button", className: "umds-toast__action", onClick: (event) => handleAction(event), children: props.actionLabel })) : null] }), props.closable !== false ? (_jsx("button", { type: "button", className: "umds-toast__close", onClick: (event) => handleClose(event), "aria-label": props.closeLabel || "Fechar notificação", children: _jsx(Icon, { variant: "inherit", customSize: "18px", icon: faXmark }) })) : null] })) : null }) }));
|
|
62
75
|
}
|
|
63
76
|
export default Toast;
|
|
@@ -17,6 +17,13 @@ function ToastStack(props) {
|
|
|
17
17
|
.filter(Boolean)
|
|
18
18
|
.join(" ");
|
|
19
19
|
}
|
|
20
|
+
function actionLabelOf(item) {
|
|
21
|
+
return item.onAction ? item.actionLabel : undefined;
|
|
22
|
+
}
|
|
23
|
+
function handleItemAction(item) {
|
|
24
|
+
if (item.onAction)
|
|
25
|
+
item.onAction();
|
|
26
|
+
}
|
|
20
27
|
function handleItemClose(id) {
|
|
21
28
|
dismissToast(id);
|
|
22
29
|
}
|
|
@@ -33,6 +40,6 @@ function ToastStack(props) {
|
|
|
33
40
|
}
|
|
34
41
|
};
|
|
35
42
|
}, []);
|
|
36
|
-
return (_jsx("div", { ref: stackRef, className: stackClasses(), children: items?.map((item) => (_jsx(Toast, { open: true, message: item.message, description: item.description, variant: item.variant, duration: item.duration, closable: item.closable, portalContainer: stackRef.current, onClose: (event) => handleItemClose(item.id) }, item.id))) }));
|
|
43
|
+
return (_jsx("div", { ref: stackRef, className: stackClasses(), children: items?.map((item) => (_jsx(Toast, { open: true, message: item.message, description: item.description, details: item.details, actionLabel: actionLabelOf(item), onAction: (event) => handleItemAction(item), variant: item.variant, duration: item.duration, closable: item.closable, portalContainer: stackRef.current, onClose: (event) => handleItemClose(item.id) }, item.id))) }));
|
|
37
44
|
}
|
|
38
45
|
export default ToastStack;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { describe, expect, it } from "vitest";
|
|
3
|
+
import { render } from "@testing-library/react";
|
|
4
|
+
import Accordion from "../components/Accordion/Accordion";
|
|
5
|
+
const ITENS = [
|
|
6
|
+
{ id: "a", title: "Prazos", content: "Dez dias úteis." },
|
|
7
|
+
{ id: "b", title: "Anexos", content: "Até 10 MB." },
|
|
8
|
+
];
|
|
9
|
+
describe("Accordion · titleVariant", () => {
|
|
10
|
+
it("neutral liga a classe do título neutro; o padrão e default não", () => {
|
|
11
|
+
const { container, rerender } = render(_jsx(Accordion, { items: ITENS, titleVariant: "neutral" }));
|
|
12
|
+
const raiz = () => container.firstElementChild;
|
|
13
|
+
expect(raiz()).toHaveClass("umds-accordion--title-neutral");
|
|
14
|
+
rerender(_jsx(Accordion, { items: ITENS, titleVariant: "default" }));
|
|
15
|
+
expect(raiz()).not.toHaveClass("umds-accordion--title-neutral");
|
|
16
|
+
rerender(_jsx(Accordion, { items: ITENS }));
|
|
17
|
+
expect(raiz()).not.toHaveClass("umds-accordion--title-neutral");
|
|
18
|
+
});
|
|
19
|
+
it("combina com a variant do accordion", () => {
|
|
20
|
+
const { container } = render(_jsx(Accordion, { items: ITENS, variant: "separated", titleVariant: "neutral" }));
|
|
21
|
+
expect(container.firstElementChild).toHaveClass("umds-accordion--separated", "umds-accordion--title-neutral");
|
|
22
|
+
});
|
|
23
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { describe, expect, it } from "vitest";
|
|
3
|
+
import { render } from "@testing-library/react";
|
|
4
|
+
import AppSubheader from "../components/AppSubheader/AppSubheader";
|
|
5
|
+
import Breadcrumb from "../components/Breadcrumb/Breadcrumb";
|
|
6
|
+
/** O jsdom não tem layout: a geometria real é conferida pela story "Só a página atual" (play, no navegador); a regra de CSS, pelo teste do Vue. */
|
|
7
|
+
describe("AppSubheader · região do contexto", () => {
|
|
8
|
+
it("a trilha só com a página atual não tem nada focável dentro da região", () => {
|
|
9
|
+
const { container } = render(_jsx(AppSubheader, { children: _jsx(Breadcrumb, { items: [{ label: "Painel" }] }) }));
|
|
10
|
+
const contexto = container.querySelector(".umds-app-subheader__contexto");
|
|
11
|
+
expect(contexto.querySelector("a, button, [tabindex]")).toBeNull();
|
|
12
|
+
});
|
|
13
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { describe, expect, it } from "vitest";
|
|
3
|
+
import { render, screen } from "@testing-library/react";
|
|
4
|
+
import userEvent from "@testing-library/user-event";
|
|
5
|
+
import AttachmentCard from "../components/AttachmentCard/AttachmentCard";
|
|
6
|
+
const DETALHES = {
|
|
7
|
+
description: "Documento legível.",
|
|
8
|
+
fields: [
|
|
9
|
+
{ label: "Nome completo", value: "Marcos Vinícius Tavares", copyable: true },
|
|
10
|
+
{ label: "CPF", value: "123.456.789-09" },
|
|
11
|
+
],
|
|
12
|
+
};
|
|
13
|
+
async function abrirPainel() {
|
|
14
|
+
const usuario = userEvent.setup();
|
|
15
|
+
render(_jsx(AttachmentCard, { fileName: "cnh.pdf", documentType: "CNH", status: "positive", statusLabel: "Pr\u00E9-aprovado", statusDetails: DETALHES }));
|
|
16
|
+
await usuario.click(screen.getByRole("button", { name: /Pré-aprovado/ }));
|
|
17
|
+
return usuario;
|
|
18
|
+
}
|
|
19
|
+
describe("AttachmentCard · o <dl> do painel é válido (axe definition-list)", () => {
|
|
20
|
+
it("o dl só tem div filhos, e cada div só tem dt e dd, nessa ordem", async () => {
|
|
21
|
+
await abrirPainel();
|
|
22
|
+
const dl = document.querySelector(".umds-attachment-card__campos");
|
|
23
|
+
expect(dl.tagName).toBe("DL");
|
|
24
|
+
const grupos = [...dl.children];
|
|
25
|
+
expect(grupos).toHaveLength(2);
|
|
26
|
+
for (const grupo of grupos) {
|
|
27
|
+
expect(grupo.tagName).toBe("DIV");
|
|
28
|
+
expect([...grupo.children].map((f) => f.tagName)).toEqual(["DT", "DD"]);
|
|
29
|
+
}
|
|
30
|
+
});
|
|
31
|
+
it("o botão de copiar mora dentro do dd, ao lado do valor, e continua com nome", async () => {
|
|
32
|
+
await abrirPainel();
|
|
33
|
+
const dd = document.querySelector(".umds-attachment-card__campo-valor");
|
|
34
|
+
expect(dd.tagName).toBe("DD");
|
|
35
|
+
expect(dd.querySelector(".umds-attachment-card__campo-valor-texto")).toHaveTextContent("Marcos Vinícius Tavares");
|
|
36
|
+
const botao = dd.querySelector("button");
|
|
37
|
+
expect(botao).toHaveAttribute("aria-label", "Copiar Nome completo");
|
|
38
|
+
// nenhum botão solto direto num div do dl
|
|
39
|
+
for (const grupo of document.querySelectorAll(".umds-attachment-card__campo")) {
|
|
40
|
+
expect(grupo.querySelector(":scope > button")).toBeNull();
|
|
41
|
+
}
|
|
42
|
+
});
|
|
43
|
+
it("o campo sem copyable não tem botão e o valor segue no dd", async () => {
|
|
44
|
+
await abrirPainel();
|
|
45
|
+
const campos = document.querySelectorAll(".umds-attachment-card__campo");
|
|
46
|
+
expect(campos[1].querySelector("button")).toBeNull();
|
|
47
|
+
expect(campos[1].querySelector("dd")).toHaveTextContent("123.456.789-09");
|
|
48
|
+
});
|
|
49
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { describe, expect, it } from "vitest";
|
|
3
|
+
import { render } from "@testing-library/react";
|
|
4
|
+
import AttachmentCard from "../components/AttachmentCard/AttachmentCard";
|
|
5
|
+
const tamanho = (el) => el.style.width;
|
|
6
|
+
describe("AttachmentCard · size", () => {
|
|
7
|
+
it("md (padrão): ícone do preview de 48px e o do rodapé no sm do Icon", () => {
|
|
8
|
+
const { container } = render(_jsx(AttachmentCard, { fileName: "Protocolo 104-2026.pdf" }));
|
|
9
|
+
expect(container.firstElementChild).not.toHaveClass("umds-attachment-card--sm");
|
|
10
|
+
expect(tamanho(container.querySelector(".umds-attachment-card__preview .umds-icon"))).toBe("48px");
|
|
11
|
+
const rodape = container.querySelector(".umds-attachment-card__rodape-icone .umds-icon");
|
|
12
|
+
expect(rodape).toHaveClass("umds-icon--sm");
|
|
13
|
+
expect(rodape.style.width).toBe("");
|
|
14
|
+
});
|
|
15
|
+
it("sm: ícone do preview de 40px e o do rodapé de 12px", () => {
|
|
16
|
+
const { container } = render(_jsx(AttachmentCard, { fileName: "Protocolo 104-2026.pdf", size: "sm" }));
|
|
17
|
+
expect(container.firstElementChild).toHaveClass("umds-attachment-card--sm");
|
|
18
|
+
expect(tamanho(container.querySelector(".umds-attachment-card__preview .umds-icon"))).toBe("40px");
|
|
19
|
+
expect(tamanho(container.querySelector(".umds-attachment-card__rodape-icone .umds-icon"))).toBe("12px");
|
|
20
|
+
});
|
|
21
|
+
it("o ícone central escolhido continua valendo no sm", () => {
|
|
22
|
+
const { container } = render(_jsx(AttachmentCard, { fileName: "a.pdf", size: "sm", documentType: "CNH", status: "positive", statusLabel: "Pr\u00E9-aprovado" }));
|
|
23
|
+
expect(container.querySelector(".umds-attachment-card__tipo-texto")).toHaveTextContent("CNH");
|
|
24
|
+
expect(container.querySelector(".umds-attachment-card__status-texto")).toHaveTextContent("Pré-aprovado");
|
|
25
|
+
});
|
|
26
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { describe, expect, it } from "vitest";
|
|
3
|
+
import { render } from "@testing-library/react";
|
|
4
|
+
import Badge from "../components/Badge/Badge";
|
|
5
|
+
/** A cascata de CSS de arquivo não existe no jsdom: a regra é conferida na fonte pelo teste do Vue; aqui, as classes no DOM. */
|
|
6
|
+
describe("Badge attached neutral", () => {
|
|
7
|
+
it("o neutro colado e sólido leva as três classes que a regra de CSS escolhe", () => {
|
|
8
|
+
const { container } = render(_jsx(Badge, { attached: true, variant: "neutral", appearance: "solid", children: "Tarefa manual" }));
|
|
9
|
+
expect(container.firstElementChild).toHaveClass("umds-badge--attached", "umds-badge--neutral", "umds-badge--solid");
|
|
10
|
+
});
|
|
11
|
+
});
|
|
@@ -40,3 +40,16 @@ describe("Tag compacta, soft, pílula e novidade", () => {
|
|
|
40
40
|
expect(raiz(container)).toHaveClass("umds-tag--new", "umds-tag--soft");
|
|
41
41
|
});
|
|
42
42
|
});
|
|
43
|
+
describe("Badge attachedSide", () => {
|
|
44
|
+
it("right escreve o modificador do canto direito; left e o padrão não", () => {
|
|
45
|
+
const { container } = render(_jsxs(_Fragment, { children: [_jsx(Badge, { attached: true, attachedSide: "right", children: "A" }), _jsx(Badge, { attached: true, attachedSide: "left", children: "B" }), _jsx(Badge, { attached: true, children: "C" })] }));
|
|
46
|
+
expect(container.children[0]).toHaveClass("umds-badge--attached", "umds-badge--attached-right");
|
|
47
|
+
expect(container.children[1]).not.toHaveClass("umds-badge--attached-right");
|
|
48
|
+
expect(container.children[2]).not.toHaveClass("umds-badge--attached-right");
|
|
49
|
+
});
|
|
50
|
+
it("attachedSide sem attached não faz nada", () => {
|
|
51
|
+
const { container } = render(_jsx(Badge, { attachedSide: "right", children: "A" }));
|
|
52
|
+
expect(raiz(container)).not.toHaveClass("umds-badge--attached-right");
|
|
53
|
+
expect(raiz(container)).not.toHaveClass("umds-badge--attached");
|
|
54
|
+
});
|
|
55
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { describe, expect, it } from "vitest";
|
|
3
|
+
import { render, screen } from "@testing-library/react";
|
|
4
|
+
import Calendar from "../components/Calendar/Calendar";
|
|
5
|
+
describe("Calendar · cabeçalho", () => {
|
|
6
|
+
it("headerStart e headerEnd (React: props com nó) chegam ao cabeçalho", () => {
|
|
7
|
+
render(_jsx(Calendar, { events: [], defaultDate: "2026-10-08", headerStart: _jsx("span", { children: "Todos os documentos" }), headerEnd: _jsx("span", { children: "Legenda" }) }));
|
|
8
|
+
expect(screen.getByText("Todos os documentos")).toBeInTheDocument();
|
|
9
|
+
expect(screen.getByText("Legenda")).toBeInTheDocument();
|
|
10
|
+
});
|
|
11
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { describe, expect, it, vi } from "vitest";
|
|
3
|
+
import { fireEvent, render, screen, waitFor } from "@testing-library/react";
|
|
4
|
+
import Coachmark from "../components/Coachmark/Coachmark";
|
|
5
|
+
const PASSOS = [{ target: "#alvo-a", title: "Novo: arrastar", content: "Arraste a linha para trocar a ordem." }];
|
|
6
|
+
function Pagina(props) {
|
|
7
|
+
return (_jsxs("div", { children: [_jsx("button", { id: "alvo-a", children: "A" }), _jsx("button", { id: "fora", children: "Fora" }), _jsx(Coachmark, { steps: PASSOS, open: true, ...props })] }));
|
|
8
|
+
}
|
|
9
|
+
describe("Coachmark · modal={false}", () => {
|
|
10
|
+
it("sem véu nem recorte; o cartão é um diálogo não modal e a raiz deixa o ponteiro passar", () => {
|
|
11
|
+
const { baseElement } = render(_jsx(Pagina, { modal: false }));
|
|
12
|
+
expect(baseElement.querySelector(".umds-coachmark__veil")).toBeNull();
|
|
13
|
+
expect(baseElement.querySelector(".umds-coachmark__cutout")).toBeNull();
|
|
14
|
+
expect(baseElement.querySelector(".umds-coachmark")).toHaveClass("umds-coachmark--modeless");
|
|
15
|
+
expect(screen.getByRole("dialog", { name: "Novo: arrastar" })).toHaveAttribute("aria-modal", "false");
|
|
16
|
+
});
|
|
17
|
+
it("o padrão continua modal: véu, recorte e aria-modal verdadeiro", () => {
|
|
18
|
+
const { baseElement } = render(_jsx(Pagina, {}));
|
|
19
|
+
expect(baseElement.querySelector(".umds-coachmark__veil")).not.toBeNull();
|
|
20
|
+
expect(baseElement.querySelector(".umds-coachmark__cutout")).not.toBeNull();
|
|
21
|
+
expect(baseElement.querySelector(".umds-coachmark")).not.toHaveClass("umds-coachmark--modeless");
|
|
22
|
+
expect(screen.getByRole("dialog")).toHaveAttribute("aria-modal", "true");
|
|
23
|
+
const { unmount } = render(_jsx(Pagina, { modal: true }));
|
|
24
|
+
unmount();
|
|
25
|
+
});
|
|
26
|
+
it("o foco entra no cartão, mas o Tab não fica preso", async () => {
|
|
27
|
+
render(_jsx(Pagina, { modal: false }));
|
|
28
|
+
const cartao = screen.getByRole("dialog");
|
|
29
|
+
await waitFor(() => expect(cartao).toHaveFocus());
|
|
30
|
+
const concluir = screen.getByRole("button", { name: "Concluir" });
|
|
31
|
+
concluir.focus();
|
|
32
|
+
const evento = new KeyboardEvent("keydown", { key: "Tab", bubbles: true, cancelable: true });
|
|
33
|
+
concluir.dispatchEvent(evento);
|
|
34
|
+
expect(evento.defaultPrevented).toBe(false);
|
|
35
|
+
});
|
|
36
|
+
it("no modal o Tab continua preso (o último volta ao primeiro)", () => {
|
|
37
|
+
render(_jsx(Pagina, {}));
|
|
38
|
+
const concluir = screen.getByRole("button", { name: "Concluir" });
|
|
39
|
+
concluir.focus();
|
|
40
|
+
const evento = new KeyboardEvent("keydown", { key: "Tab", bubbles: true, cancelable: true });
|
|
41
|
+
concluir.dispatchEvent(evento);
|
|
42
|
+
expect(evento.defaultPrevented).toBe(true);
|
|
43
|
+
});
|
|
44
|
+
it("a página segue clicável: o clique fora não é capturado e o tour não fecha sozinho", () => {
|
|
45
|
+
const aoFechar = vi.fn();
|
|
46
|
+
render(_jsx(Pagina, { modal: false, onClose: aoFechar }));
|
|
47
|
+
fireEvent.click(screen.getByRole("button", { name: "Fora" }));
|
|
48
|
+
expect(aoFechar).not.toHaveBeenCalled();
|
|
49
|
+
expect(screen.getByRole("dialog")).toBeInTheDocument();
|
|
50
|
+
});
|
|
51
|
+
it("o Esc fecha de qualquer lugar da página, uma vez só", () => {
|
|
52
|
+
const aoFechar = vi.fn();
|
|
53
|
+
render(_jsx(Pagina, { modal: false, onClose: aoFechar }));
|
|
54
|
+
const fora = screen.getByRole("button", { name: "Fora" });
|
|
55
|
+
fora.focus();
|
|
56
|
+
fireEvent.keyDown(fora, { key: "Escape" });
|
|
57
|
+
expect(aoFechar).toHaveBeenCalledTimes(1);
|
|
58
|
+
expect(aoFechar).toHaveBeenCalledWith("escape");
|
|
59
|
+
});
|
|
60
|
+
it("o Esc dentro do cartão também fecha uma vez só", async () => {
|
|
61
|
+
const aoFechar = vi.fn();
|
|
62
|
+
render(_jsx(Pagina, { modal: false, onClose: aoFechar }));
|
|
63
|
+
await waitFor(() => expect(screen.getByRole("dialog")).toHaveFocus());
|
|
64
|
+
fireEvent.keyDown(screen.getByRole("dialog"), { key: "Escape" });
|
|
65
|
+
expect(aoFechar).toHaveBeenCalledTimes(1);
|
|
66
|
+
});
|
|
67
|
+
it("depois de fechar, o ouvinte do Esc sai do documento", () => {
|
|
68
|
+
const aoFechar = vi.fn();
|
|
69
|
+
const { rerender } = render(_jsx(Pagina, { modal: false, onClose: aoFechar }));
|
|
70
|
+
rerender(_jsx(Pagina, { modal: false, open: false, onClose: aoFechar }));
|
|
71
|
+
fireEvent.keyDown(document, { key: "Escape" });
|
|
72
|
+
expect(aoFechar).not.toHaveBeenCalled();
|
|
73
|
+
});
|
|
74
|
+
it("ao fechar, o foco volta ao elemento de antes, se a pessoa não foi a outro lugar", async () => {
|
|
75
|
+
const { rerender } = render(_jsx(Pagina, { modal: false, open: false }));
|
|
76
|
+
const gatilho = screen.getByRole("button", { name: "Fora" });
|
|
77
|
+
gatilho.focus();
|
|
78
|
+
expect(gatilho).toHaveFocus();
|
|
79
|
+
rerender(_jsx(Pagina, { modal: false, open: true }));
|
|
80
|
+
// O foco entra no cartão depois da montagem (um quadro de animação).
|
|
81
|
+
await waitFor(() => expect(screen.getByRole("dialog")).toHaveFocus());
|
|
82
|
+
rerender(_jsx(Pagina, { modal: false, open: false }));
|
|
83
|
+
await waitFor(() => expect(gatilho).toHaveFocus());
|
|
84
|
+
});
|
|
85
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { describe, expect, it } from "vitest";
|
|
3
|
+
import { render, screen } from "@testing-library/react";
|
|
4
|
+
import ColorPicker from "../components/ColorPicker/ColorPicker";
|
|
5
|
+
describe("ColorPicker · size xs", () => {
|
|
6
|
+
it("xs escreve a classe do tamanho; sm e md seguem como eram", () => {
|
|
7
|
+
const { container, rerender } = render(_jsx(ColorPicker, { ariaLabel: "Cor", size: "xs" }));
|
|
8
|
+
const raiz = () => container.firstElementChild;
|
|
9
|
+
expect(raiz()).toHaveClass("umds-color-picker--xs");
|
|
10
|
+
rerender(_jsx(ColorPicker, { ariaLabel: "Cor", size: "sm" }));
|
|
11
|
+
expect(raiz()).toHaveClass("umds-color-picker--sm");
|
|
12
|
+
expect(raiz()).not.toHaveClass("umds-color-picker--xs");
|
|
13
|
+
rerender(_jsx(ColorPicker, { ariaLabel: "Cor" }));
|
|
14
|
+
expect(raiz()).toHaveClass("umds-color-picker--md");
|
|
15
|
+
});
|
|
16
|
+
it("no xs a amostra escolhida mantém a marcação e o aria-checked", () => {
|
|
17
|
+
const { container } = render(_jsx(ColorPicker, { ariaLabel: "Cor", size: "xs", defaultValue: "--umds-primitive-red-pure" }));
|
|
18
|
+
expect(screen.getByRole("radio", { name: "Vermelho" })).toHaveAttribute("aria-checked", "true");
|
|
19
|
+
expect(container.querySelectorAll(".umds-color-picker__swatch--selected")).toHaveLength(1);
|
|
20
|
+
});
|
|
21
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|