@1doc/1ds-react 2.8.0 → 2.9.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 +1106 -0
- package/dist/components/AILabel/AILabel.js +1 -1
- package/dist/components/Accordion/Accordion.d.ts +6 -2
- package/dist/components/AttachmentCard/AttachmentCard.css +16 -0
- package/dist/components/AttachmentCard/AttachmentCard.d.ts +19 -2
- package/dist/components/AttachmentCard/AttachmentCard.js +40 -3
- package/dist/components/Avatar/Avatar.css +7 -2
- package/dist/components/Avatar/AvatarGroup.d.ts +17 -0
- package/dist/components/Avatar/AvatarGroup.js +22 -8
- package/dist/components/Badge/Badge.css +54 -2
- package/dist/components/Badge/Badge.d.ts +14 -4
- package/dist/components/Badge/Badge.js +1 -0
- package/dist/components/Box/Box.css +83 -0
- package/dist/components/Box/Box.d.ts +82 -2
- package/dist/components/Box/Box.js +42 -2
- package/dist/components/Button/Button.css +29 -0
- package/dist/components/Button/Button.d.ts +4 -4
- package/dist/components/Button/Button.js +4 -1
- package/dist/components/Calendar/Calendar.css +245 -0
- package/dist/components/Calendar/Calendar.d.ts +125 -0
- package/dist/components/Calendar/Calendar.js +320 -0
- package/dist/components/Chips/Chips.css +38 -0
- package/dist/components/Chips/Chips.d.ts +5 -2
- package/dist/components/Chips/Chips.js +2 -1
- package/dist/components/Coachmark/Coachmark.css +118 -0
- package/dist/components/Coachmark/Coachmark.d.ts +75 -0
- package/dist/components/Coachmark/Coachmark.js +321 -0
- package/dist/components/CodeBlock/CodeBlock.css +96 -0
- package/dist/components/CodeBlock/CodeBlock.d.ts +47 -0
- package/dist/components/CodeBlock/CodeBlock.js +103 -0
- package/dist/components/ColorPicker/ColorPicker.css +133 -0
- package/dist/components/ColorPicker/ColorPicker.d.ts +73 -0
- package/dist/components/ColorPicker/ColorPicker.js +219 -0
- package/dist/components/Combobox/Combobox.css +8 -0
- package/dist/components/DataTable/DataTable.css +80 -0
- package/dist/components/DataTable/DataTable.d.ts +19 -4
- package/dist/components/DataTable/DataTable.js +59 -15
- package/dist/components/DatePicker/DatePicker.css +8 -0
- package/dist/components/DatePicker/DatePicker.js +10 -1
- package/dist/components/DescriptionList/DescriptionList.css +113 -0
- package/dist/components/DescriptionList/DescriptionList.d.ts +59 -0
- package/dist/components/DescriptionList/DescriptionList.js +51 -0
- package/dist/components/FileInput/FileInput.css +16 -0
- package/dist/components/FileInput/FileInput.d.ts +4 -2
- package/dist/components/FileInput/FileInput.js +8 -2
- package/dist/components/Grid/Grid.js +5 -5
- package/dist/components/IconPicker/IconPicker.css +107 -0
- package/dist/components/IconPicker/IconPicker.d.ts +74 -0
- package/dist/components/IconPicker/IconPicker.js +194 -0
- package/dist/components/Input/Input.css +38 -0
- package/dist/components/Input/Input.d.ts +10 -1
- package/dist/components/Input/Input.js +66 -5
- package/dist/components/Kanban/Kanban.css +4 -0
- package/dist/components/Kbd/Kbd.css +66 -0
- package/dist/components/Kbd/Kbd.d.ts +32 -0
- package/dist/components/Kbd/Kbd.js +40 -0
- package/dist/components/List/List.css +136 -0
- package/dist/components/List/List.d.ts +82 -0
- package/dist/components/List/List.js +53 -0
- package/dist/components/List/ListItem.d.ts +85 -0
- package/dist/components/List/ListItem.js +81 -0
- package/dist/components/Modal/Modal.css +80 -0
- package/dist/components/Modal/Modal.d.ts +33 -6
- package/dist/components/Modal/Modal.js +101 -6
- package/dist/components/MultiSelect/MultiSelect.css +8 -0
- package/dist/components/MultiSelect/MultiSelect.js +10 -1
- package/dist/components/OrgChart/OrgChart.css +149 -0
- package/dist/components/OrgChart/OrgChart.d.ts +83 -0
- package/dist/components/OrgChart/OrgChart.js +297 -0
- package/dist/components/OtpInput/OtpInput.css +93 -0
- package/dist/components/OtpInput/OtpInput.d.ts +60 -0
- package/dist/components/OtpInput/OtpInput.js +215 -0
- package/dist/components/PhoneInput/PhoneInput.css +8 -0
- package/dist/components/Popover/Popover.d.ts +7 -0
- package/dist/components/Popover/Popover.js +11 -1
- package/dist/components/RichTextEditor/RichTextEditor.css +203 -0
- package/dist/components/RichTextEditor/RichTextEditor.d.ts +83 -0
- package/dist/components/RichTextEditor/RichTextEditor.js +494 -0
- package/dist/components/SegmentedControl/SegmentedControl.js +7 -2
- package/dist/components/Select/Select.css +70 -0
- package/dist/components/Select/Select.d.ts +12 -0
- package/dist/components/Select/Select.js +59 -4
- package/dist/components/Stack/Stack.css +49 -0
- package/dist/components/Stack/Stack.d.ts +65 -7
- package/dist/components/Stack/Stack.js +30 -2
- package/dist/components/StatCard/StatCard.css +73 -0
- package/dist/components/StatCard/StatCard.d.ts +17 -0
- package/dist/components/StatCard/StatCard.js +4 -1
- package/dist/components/Tabs/Tab.d.ts +15 -0
- package/dist/components/Tabs/Tab.js +30 -1
- package/dist/components/Tabs/Tabs.css +132 -0
- package/dist/components/Tabs/Tabs.d.ts +7 -0
- package/dist/components/Tabs/Tabs.js +13 -2
- package/dist/components/Tag/Tag.css +85 -2
- package/dist/components/Tag/Tag.d.ts +13 -6
- package/dist/components/Tag/Tag.js +1 -0
- package/dist/components/Text/Text.js +2 -2
- package/dist/components/Textarea/Textarea.css +8 -0
- package/dist/components/TimePicker/TimePicker.css +8 -0
- package/dist/components/Tooltip/Tooltip.css +25 -0
- package/dist/components/Tooltip/Tooltip.d.ts +11 -0
- package/dist/components/Tooltip/Tooltip.js +18 -3
- package/dist/index.d.ts +25 -0
- package/dist/index.js +14 -0
- package/dist/teste/AILabel.test.d.ts +1 -0
- package/dist/teste/AILabel.test.js +33 -0
- package/dist/teste/AccordionConteudoLivre.test.d.ts +1 -0
- package/dist/teste/AccordionConteudoLivre.test.js +29 -0
- package/dist/teste/AtributosRepassados.test.d.ts +1 -0
- package/dist/teste/AtributosRepassados.test.js +52 -0
- package/dist/teste/AttachmentCardIA.test.d.ts +1 -0
- package/dist/teste/AttachmentCardIA.test.js +89 -0
- package/dist/teste/AvatarGroupOverlap.test.d.ts +1 -0
- package/dist/teste/AvatarGroupOverlap.test.js +56 -0
- package/dist/teste/BadgeTag.test.d.ts +1 -0
- package/dist/teste/BadgeTag.test.js +42 -0
- package/dist/teste/BoxItemFlex.test.d.ts +1 -0
- package/dist/teste/BoxItemFlex.test.js +54 -0
- package/dist/teste/BoxLayout.test.d.ts +1 -0
- package/dist/teste/BoxLayout.test.js +35 -0
- package/dist/teste/Button.test.d.ts +1 -0
- package/dist/teste/Button.test.js +27 -0
- package/dist/teste/Calendar.test.d.ts +1 -0
- package/dist/teste/Calendar.test.js +221 -0
- package/dist/teste/ChipsXs.test.d.ts +1 -0
- package/dist/teste/ChipsXs.test.js +31 -0
- package/dist/teste/Coachmark.test.d.ts +1 -0
- package/dist/teste/Coachmark.test.js +149 -0
- package/dist/teste/ColorPicker.test.d.ts +1 -0
- package/dist/teste/ColorPicker.test.js +132 -0
- package/dist/teste/DataTableCelulaLivre.test.d.ts +1 -0
- package/dist/teste/DataTableCelulaLivre.test.js +76 -0
- package/dist/teste/DataTableDocumento.test.d.ts +1 -0
- package/dist/teste/DataTableDocumento.test.js +92 -0
- package/dist/teste/DatePicker.test.js +23 -0
- package/dist/teste/FileInputTrigger.test.d.ts +1 -0
- package/dist/teste/FileInputTrigger.test.js +53 -0
- package/dist/teste/IconPicker.test.d.ts +1 -0
- package/dist/teste/IconPicker.test.js +130 -0
- package/dist/teste/InputMascaraEAfins.test.d.ts +1 -0
- package/dist/teste/InputMascaraEAfins.test.js +99 -0
- package/dist/teste/KbdCodeBlock.test.d.ts +1 -0
- package/dist/teste/KbdCodeBlock.test.js +95 -0
- package/dist/teste/List.test.d.ts +1 -0
- package/dist/teste/List.test.js +153 -0
- package/dist/teste/ModalVariantes.test.d.ts +1 -0
- package/dist/teste/ModalVariantes.test.js +151 -0
- package/dist/teste/NomeAcessivelSsr.test.d.ts +1 -0
- package/dist/teste/NomeAcessivelSsr.test.js +88 -0
- package/dist/teste/OrgChart.test.d.ts +1 -0
- package/dist/teste/OrgChart.test.js +162 -0
- package/dist/teste/OtpInput.test.d.ts +1 -0
- package/dist/teste/OtpInput.test.js +143 -0
- package/dist/teste/PopoverMaxHeight.test.d.ts +1 -0
- package/dist/teste/PopoverMaxHeight.test.js +38 -0
- package/dist/teste/RichTextEditor.test.d.ts +1 -0
- package/dist/teste/RichTextEditor.test.js +287 -0
- package/dist/teste/SelectPlacementFiltro.test.d.ts +1 -0
- package/dist/teste/SelectPlacementFiltro.test.js +88 -0
- package/dist/teste/Stack.test.d.ts +1 -0
- package/dist/teste/Stack.test.js +57 -0
- package/dist/teste/StatCardRotuloTopo.test.d.ts +1 -0
- package/dist/teste/StatCardRotuloTopo.test.js +34 -0
- package/dist/teste/TabsContadorFechavel.test.d.ts +1 -0
- package/dist/teste/TabsContadorFechavel.test.js +79 -0
- package/dist/teste/TooltipDark.test.d.ts +1 -0
- package/dist/teste/TooltipDark.test.js +31 -0
- package/dist/utils/calendario.d.ts +28 -0
- package/dist/utils/calendario.js +73 -0
- package/dist/utils/html-seguro.d.ts +27 -0
- package/dist/utils/html-seguro.js +97 -0
- package/dist/utils/paleta-de-cores.d.ts +26 -0
- package/dist/utils/paleta-de-cores.js +10 -0
- package/dist/utils/texto.d.ts +5 -0
- package/dist/utils/texto.js +5 -0
- package/package.json +3 -3
- package/src/index.ts +26 -0
- package/src/teste/AILabel.test.tsx +41 -0
- package/src/teste/AccordionConteudoLivre.test.tsx +39 -0
- package/src/teste/AtributosRepassados.test.tsx +73 -0
- package/src/teste/AttachmentCardIA.test.tsx +126 -0
- package/src/teste/AvatarGroupOverlap.test.tsx +74 -0
- package/src/teste/BadgeTag.test.tsx +64 -0
- package/src/teste/BoxItemFlex.test.tsx +81 -0
- package/src/teste/BoxLayout.test.tsx +50 -0
- package/src/teste/Button.test.tsx +39 -0
- package/src/teste/Calendar.test.tsx +282 -0
- package/src/teste/ChipsXs.test.tsx +41 -0
- package/src/teste/Coachmark.test.tsx +198 -0
- package/src/teste/ColorPicker.test.tsx +153 -0
- package/src/teste/DataTableCelulaLivre.test.tsx +103 -0
- package/src/teste/DataTableDocumento.test.tsx +102 -0
- package/src/teste/DatePicker.test.tsx +38 -0
- package/src/teste/FileInputTrigger.test.tsx +89 -0
- package/src/teste/IconPicker.test.tsx +145 -0
- package/src/teste/InputMascaraEAfins.test.tsx +124 -0
- package/src/teste/KbdCodeBlock.test.tsx +106 -0
- package/src/teste/List.test.tsx +269 -0
- package/src/teste/ModalVariantes.test.tsx +173 -0
- package/src/teste/NomeAcessivelSsr.test.tsx +110 -0
- package/src/teste/OrgChart.test.tsx +183 -0
- package/src/teste/OtpInput.test.tsx +163 -0
- package/src/teste/PopoverMaxHeight.test.tsx +47 -0
- package/src/teste/RichTextEditor.test.tsx +329 -0
- package/src/teste/SelectPlacementFiltro.test.tsx +110 -0
- package/src/teste/Stack.test.tsx +80 -0
- package/src/teste/StatCardRotuloTopo.test.tsx +44 -0
- package/src/teste/TabsContadorFechavel.test.tsx +144 -0
- package/src/teste/TooltipDark.test.tsx +51 -0
- package/src/utils/calendario.ts +78 -0
- package/src/utils/html-seguro.ts +94 -0
- package/src/utils/paleta-de-cores.ts +34 -0
- package/src/utils/texto.ts +5 -0
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { describe, expect, it } from "vitest";
|
|
3
|
+
import { render, screen } from "@testing-library/react";
|
|
4
|
+
import StatCard from "../components/StatCard/StatCard";
|
|
5
|
+
const raiz = (c) => c.firstElementChild;
|
|
6
|
+
describe("StatCard · labelPosition", () => {
|
|
7
|
+
it("top escreve a classe; sem a prop o cartão é o de antes", () => {
|
|
8
|
+
const { container } = render(_jsxs(_Fragment, { children: [_jsx(StatCard, { value: 44, label: "N\u00E3o lidos", labelPosition: "top" }), _jsx(StatCard, { value: 44, label: "N\u00E3o lidos" })] }));
|
|
9
|
+
expect(container.children[0]).toHaveClass("umds-stat-card--rotulo-topo");
|
|
10
|
+
expect(container.children[1]).not.toHaveClass("umds-stat-card--rotulo-topo");
|
|
11
|
+
});
|
|
12
|
+
it("o número continua antes do rótulo no HTML (ordem do leitor de tela)", () => {
|
|
13
|
+
const { container } = render(_jsx(StatCard, { value: 44, label: "N\u00E3o lidos", labelPosition: "top" }));
|
|
14
|
+
const valor = container.querySelector(".umds-stat-card__valor");
|
|
15
|
+
const rotulo = container.querySelector(".umds-stat-card__rotulo");
|
|
16
|
+
expect(valor.compareDocumentPosition(rotulo) & Node.DOCUMENT_POSITION_FOLLOWING).toBeTruthy();
|
|
17
|
+
});
|
|
18
|
+
});
|
|
19
|
+
describe("StatCard · infoTooltip", () => {
|
|
20
|
+
it("mostra o ⓘ como botão nomeado, dentro do rótulo, descrito pelo texto de ajuda", () => {
|
|
21
|
+
const { container } = render(_jsx(StatCard, { value: 44, label: "N\u00E3o lidos", infoTooltip: "Ainda n\u00E3o abertos por voc\u00EA." }));
|
|
22
|
+
const info = screen.getByRole("button", { name: "Mais informações" });
|
|
23
|
+
expect(container.querySelector(".umds-stat-card__rotulo")?.contains(info)).toBe(true);
|
|
24
|
+
expect(info).toHaveAccessibleDescription("Ainda não abertos por você.");
|
|
25
|
+
});
|
|
26
|
+
it("infoLabel traduz o nome do ⓘ", () => {
|
|
27
|
+
render(_jsx(StatCard, { value: 1, label: "Unread", infoTooltip: "Not opened yet.", infoLabel: "More info" }));
|
|
28
|
+
expect(screen.getByRole("button", { name: "More info" })).toBeInTheDocument();
|
|
29
|
+
});
|
|
30
|
+
it("sem infoTooltip não há botão", () => {
|
|
31
|
+
render(_jsx(StatCard, { value: 1, label: "x" }));
|
|
32
|
+
expect(screen.queryByRole("button")).toBeNull();
|
|
33
|
+
});
|
|
34
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,79 @@
|
|
|
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 } from "@testing-library/react";
|
|
4
|
+
import Tabs from "../components/Tabs/Tabs";
|
|
5
|
+
import Tab from "../components/Tabs/Tab";
|
|
6
|
+
describe("Tab · count", () => {
|
|
7
|
+
it("mostra o contador em pílula e ele entra no nome da aba", () => {
|
|
8
|
+
render(_jsxs(Tabs, { value: "0", ariaLabel: "Tarefas", children: [_jsx(Tab, { label: "Todas", index: "0", count: 31 }), _jsx(Tab, { label: "Atribu\u00EDdas", index: "1", count: 9 })] }));
|
|
9
|
+
expect(screen.getByRole("tab", { name: "Todas 31" })).toBeInTheDocument();
|
|
10
|
+
expect(screen.getByRole("tab", { name: "Atribuídas 9" })).toBeInTheDocument();
|
|
11
|
+
});
|
|
12
|
+
it("o 0 aparece; sem count, não há pílula", () => {
|
|
13
|
+
const { container } = render(_jsxs(Tabs, { value: "0", children: [_jsx(Tab, { label: "Conclu\u00EDdas", index: "0", count: 0 }), _jsx(Tab, { label: "Sem contador", index: "1" })] }));
|
|
14
|
+
const pilulas = container.querySelectorAll(".umds-tabs__count");
|
|
15
|
+
expect(pilulas).toHaveLength(1);
|
|
16
|
+
expect(pilulas[0].textContent).toBe("0");
|
|
17
|
+
});
|
|
18
|
+
it("a pílula fica dentro da aba selecionada (que a pinta de azul pelo CSS)", () => {
|
|
19
|
+
const { container } = render(_jsxs(Tabs, { value: "1", children: [_jsx(Tab, { label: "A", index: "0", count: 1 }), _jsx(Tab, { label: "B", index: "1", count: 2 })] }));
|
|
20
|
+
const selecionada = container.querySelector(".umds-tabs__tab--selected");
|
|
21
|
+
expect(selecionada?.querySelector(".umds-tabs__count")?.textContent).toBe("2");
|
|
22
|
+
});
|
|
23
|
+
});
|
|
24
|
+
describe("Tab · closable", () => {
|
|
25
|
+
it("o × é um botão irmão da aba, com o nome 'Fechar <aba>'", () => {
|
|
26
|
+
render(_jsx(Tabs, { value: "0", children: _jsx(Tab, { label: "Documento 1", index: "0", closable: true }) }));
|
|
27
|
+
const fechar = screen.getByRole("button", { name: "Fechar Documento 1" });
|
|
28
|
+
const aba = screen.getByRole("tab");
|
|
29
|
+
expect(aba.contains(fechar)).toBe(false);
|
|
30
|
+
expect(fechar.parentElement).toBe(aba.parentElement);
|
|
31
|
+
});
|
|
32
|
+
it("o rótulo do × vem por prop", () => {
|
|
33
|
+
render(_jsx(Tabs, { value: "0", children: _jsx(Tab, { label: "Doc 1", index: "0", closable: true, closeLabel: "Close" }) }));
|
|
34
|
+
expect(screen.getByRole("button", { name: "Close Doc 1" })).toBeInTheDocument();
|
|
35
|
+
});
|
|
36
|
+
it("clicar no × chama onClose com o index e não troca de aba", () => {
|
|
37
|
+
const aoFechar = vi.fn();
|
|
38
|
+
const aoTrocar = vi.fn();
|
|
39
|
+
render(_jsxs(Tabs, { value: "0", onChange: aoTrocar, children: [_jsx(Tab, { label: "Um", index: "0" }), _jsx(Tab, { label: "Dois", index: "1", closable: true, onClose: aoFechar })] }));
|
|
40
|
+
fireEvent.click(screen.getByRole("button", { name: "Fechar Dois" }));
|
|
41
|
+
expect(aoFechar).toHaveBeenCalledTimes(1);
|
|
42
|
+
expect(aoFechar.mock.calls[0][0]).toBe("1");
|
|
43
|
+
expect(aoTrocar).not.toHaveBeenCalled();
|
|
44
|
+
});
|
|
45
|
+
it("Delete na aba focada fecha; sem closable, não", () => {
|
|
46
|
+
const aoFechar = vi.fn();
|
|
47
|
+
render(_jsxs(Tabs, { value: "0", children: [_jsx(Tab, { label: "Fech\u00E1vel", index: "0", closable: true, onClose: aoFechar }), _jsx(Tab, { label: "Fixa", index: "1", onClose: aoFechar })] }));
|
|
48
|
+
fireEvent.keyDown(screen.getByRole("tab", { name: "Fechável" }), { key: "Delete" });
|
|
49
|
+
expect(aoFechar).toHaveBeenCalledTimes(1);
|
|
50
|
+
fireEvent.keyDown(screen.getByRole("tab", { name: "Fixa" }), { key: "Delete" });
|
|
51
|
+
expect(aoFechar).toHaveBeenCalledTimes(1);
|
|
52
|
+
});
|
|
53
|
+
it("sem closable não há ×", () => {
|
|
54
|
+
render(_jsx(Tabs, { value: "0", children: _jsx(Tab, { label: "Fixa", index: "0" }) }));
|
|
55
|
+
expect(screen.queryByRole("button")).toBeNull();
|
|
56
|
+
});
|
|
57
|
+
it("o tablist só tem abas como filhas de papel (o × não é tab)", () => {
|
|
58
|
+
render(_jsxs(Tabs, { value: "0", children: [_jsx(Tab, { label: "A", index: "0", closable: true }), _jsx(Tab, { label: "B", index: "1", closable: true })] }));
|
|
59
|
+
expect(screen.getAllByRole("tab")).toHaveLength(2);
|
|
60
|
+
});
|
|
61
|
+
});
|
|
62
|
+
describe("Tabs · onAdd", () => {
|
|
63
|
+
it("mostra o + fora do tablist e chama onAdd", () => {
|
|
64
|
+
const aoAdicionar = vi.fn();
|
|
65
|
+
render(_jsx(Tabs, { value: "0", onAdd: aoAdicionar, children: _jsx(Tab, { label: "A", index: "0" }) }));
|
|
66
|
+
const mais = screen.getByRole("button", { name: "Adicionar aba" });
|
|
67
|
+
expect(screen.getByRole("tablist").contains(mais)).toBe(false);
|
|
68
|
+
fireEvent.click(mais);
|
|
69
|
+
expect(aoAdicionar).toHaveBeenCalledTimes(1);
|
|
70
|
+
});
|
|
71
|
+
it("o rótulo do + vem por prop", () => {
|
|
72
|
+
render(_jsx(Tabs, { value: "0", onAdd: () => { }, addLabel: "New tab", children: _jsx(Tab, { label: "A", index: "0" }) }));
|
|
73
|
+
expect(screen.getByRole("button", { name: "New tab" })).toBeInTheDocument();
|
|
74
|
+
});
|
|
75
|
+
it("sem onAdd não há botão", () => {
|
|
76
|
+
render(_jsx(Tabs, { value: "0", children: _jsx(Tab, { label: "A", index: "0" }) }));
|
|
77
|
+
expect(screen.queryByRole("button")).toBeNull();
|
|
78
|
+
});
|
|
79
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { describe, expect, it } from "vitest";
|
|
3
|
+
import { render, screen, waitFor } from "@testing-library/react";
|
|
4
|
+
import Tooltip from "../components/Tooltip/Tooltip";
|
|
5
|
+
async function abrir(ui) {
|
|
6
|
+
render(ui);
|
|
7
|
+
screen.getByRole("button").focus();
|
|
8
|
+
await waitFor(() => expect(screen.getByRole("tooltip")).toHaveClass("umds-tooltip__bubble--open"));
|
|
9
|
+
return screen.getByRole("tooltip");
|
|
10
|
+
}
|
|
11
|
+
describe("Tooltip · variant dark e maxWidth", () => {
|
|
12
|
+
it("dark escreve a classe no balão e no wrapper flutuante", async () => {
|
|
13
|
+
const balao = await abrir(_jsx(Tooltip, { content: "Atualizar", variant: "dark", children: _jsx("button", { type: "button", children: "Atualizar" }) }));
|
|
14
|
+
expect(balao).toHaveClass("umds-tooltip__bubble--dark");
|
|
15
|
+
expect(balao.parentElement).toHaveClass("umds-tooltip__floating--dark");
|
|
16
|
+
});
|
|
17
|
+
it("sem variant o balão é o padrão", async () => {
|
|
18
|
+
const balao = await abrir(_jsx(Tooltip, { content: "Atualizar", children: _jsx("button", { type: "button", children: "Atualizar" }) }));
|
|
19
|
+
expect(balao).not.toHaveClass("umds-tooltip__bubble--dark");
|
|
20
|
+
expect(balao.parentElement).not.toHaveClass("umds-tooltip__floating--dark");
|
|
21
|
+
expect(balao.parentElement?.style.maxWidth).toBe("");
|
|
22
|
+
});
|
|
23
|
+
it("maxWidth vai ao wrapper flutuante, em qualquer variante", async () => {
|
|
24
|
+
const balao = await abrir(_jsx(Tooltip, { content: "Texto longo", variant: "dark", maxWidth: "140px", children: _jsx("button", { type: "button", children: "x" }) }));
|
|
25
|
+
expect(balao.parentElement?.style.maxWidth).toBe("140px");
|
|
26
|
+
});
|
|
27
|
+
it("a descrição acessível não muda com a variante", () => {
|
|
28
|
+
render(_jsx(Tooltip, { content: "Atualizar", variant: "dark", children: _jsx("button", { type: "button", children: "Recarregar" }) }));
|
|
29
|
+
expect(screen.getByRole("button")).toHaveAccessibleDescription("Atualizar");
|
|
30
|
+
});
|
|
31
|
+
});
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Datas do `Calendar`, em ISO local (`YYYY-MM-DD`) e sem biblioteca.
|
|
3
|
+
*
|
|
4
|
+
* Tudo aqui trabalha com o DIA como texto: `"2026-05-15"`. O `Date` só aparece
|
|
5
|
+
* por dentro, sempre à meia-noite LOCAL (`new Date(ano, mes, dia)`), nunca
|
|
6
|
+
* `new Date("2026-05-15")`, que o JavaScript lê como UTC e, no fuso do Brasil,
|
|
7
|
+
* devolve o dia anterior.
|
|
8
|
+
*/
|
|
9
|
+
/** `Date` local → `YYYY-MM-DD`. */
|
|
10
|
+
export declare const toIso: (data: Date) => string;
|
|
11
|
+
/** `YYYY-MM-DD` → `Date` à meia-noite local. */
|
|
12
|
+
export declare const parseIso: (iso: string) => Date;
|
|
13
|
+
/** Aceita `Date` ou texto (`2026-05-15` e `2026-05-15T10:00`) e devolve `YYYY-MM-DD`; "" se não der. */
|
|
14
|
+
export declare const normalizeIso: (valor: any) => string;
|
|
15
|
+
export declare const addDays: (iso: string, dias: number) => string;
|
|
16
|
+
/** Soma meses mantendo o dia, ou o último dia do mês de chegada (31/01 + 1 mês = 28/02). */
|
|
17
|
+
export declare const addMonths: (iso: string, meses: number) => string;
|
|
18
|
+
/** Dia da semana: 0 = domingo. */
|
|
19
|
+
export declare const weekdayOf: (iso: string) => number;
|
|
20
|
+
/** Primeiro dia da semana que contém `iso`, dado o dia em que a semana começa (0 = domingo, 1 = segunda). */
|
|
21
|
+
export declare const startOfWeek: (iso: string, comecaEm: number) => string;
|
|
22
|
+
export declare const startOfMonth: (iso: string) => string;
|
|
23
|
+
export declare const endOfMonth: (iso: string) => string;
|
|
24
|
+
export declare const isSameMonth: (a: string, b: string) => boolean;
|
|
25
|
+
/** Os sete dias da semana que contém `iso`. */
|
|
26
|
+
export declare const weekDays: (iso: string, comecaEm: number) => string[];
|
|
27
|
+
/** O mês de `iso` em semanas inteiras (de 4 a 6 linhas), com os dias dos meses vizinhos que completam as pontas. */
|
|
28
|
+
export declare const monthMatrix: (iso: string, comecaEm: number) => string[][];
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Datas do `Calendar`, em ISO local (`YYYY-MM-DD`) e sem biblioteca.
|
|
3
|
+
*
|
|
4
|
+
* Tudo aqui trabalha com o DIA como texto: `"2026-05-15"`. O `Date` só aparece
|
|
5
|
+
* por dentro, sempre à meia-noite LOCAL (`new Date(ano, mes, dia)`), nunca
|
|
6
|
+
* `new Date("2026-05-15")`, que o JavaScript lê como UTC e, no fuso do Brasil,
|
|
7
|
+
* devolve o dia anterior.
|
|
8
|
+
*/
|
|
9
|
+
const doisDigitos = (n) => n < 10 ? "0" + n : String(n);
|
|
10
|
+
/** `Date` local → `YYYY-MM-DD`. */
|
|
11
|
+
export const toIso = (data) => data.getFullYear() + "-" + doisDigitos(data.getMonth() + 1) + "-" + doisDigitos(data.getDate());
|
|
12
|
+
/** `YYYY-MM-DD` → `Date` à meia-noite local. */
|
|
13
|
+
export const parseIso = (iso) => {
|
|
14
|
+
const partes = iso.slice(0, 10).split("-");
|
|
15
|
+
return new Date(Number(partes[0]), Number(partes[1]) - 1, Number(partes[2]));
|
|
16
|
+
};
|
|
17
|
+
/** Aceita `Date` ou texto (`2026-05-15` e `2026-05-15T10:00`) e devolve `YYYY-MM-DD`; "" se não der. */
|
|
18
|
+
export const normalizeIso = (valor) => {
|
|
19
|
+
if (!valor)
|
|
20
|
+
return "";
|
|
21
|
+
if (typeof valor === "string")
|
|
22
|
+
return /^\d{4}-\d{2}-\d{2}/.test(valor) ? valor.slice(0, 10) : "";
|
|
23
|
+
if (valor instanceof Date && !isNaN(valor.getTime()))
|
|
24
|
+
return toIso(valor);
|
|
25
|
+
return "";
|
|
26
|
+
};
|
|
27
|
+
export const addDays = (iso, dias) => {
|
|
28
|
+
const data = parseIso(iso);
|
|
29
|
+
data.setDate(data.getDate() + dias);
|
|
30
|
+
return toIso(data);
|
|
31
|
+
};
|
|
32
|
+
/** Soma meses mantendo o dia, ou o último dia do mês de chegada (31/01 + 1 mês = 28/02). */
|
|
33
|
+
export const addMonths = (iso, meses) => {
|
|
34
|
+
const data = parseIso(iso);
|
|
35
|
+
const dia = data.getDate();
|
|
36
|
+
data.setDate(1);
|
|
37
|
+
data.setMonth(data.getMonth() + meses);
|
|
38
|
+
const ultimo = new Date(data.getFullYear(), data.getMonth() + 1, 0).getDate();
|
|
39
|
+
data.setDate(Math.min(dia, ultimo));
|
|
40
|
+
return toIso(data);
|
|
41
|
+
};
|
|
42
|
+
/** Dia da semana: 0 = domingo. */
|
|
43
|
+
export const weekdayOf = (iso) => parseIso(iso).getDay();
|
|
44
|
+
/** Primeiro dia da semana que contém `iso`, dado o dia em que a semana começa (0 = domingo, 1 = segunda). */
|
|
45
|
+
export const startOfWeek = (iso, comecaEm) => {
|
|
46
|
+
const recuo = (weekdayOf(iso) - comecaEm + 7) % 7;
|
|
47
|
+
return addDays(iso, -recuo);
|
|
48
|
+
};
|
|
49
|
+
export const startOfMonth = (iso) => iso.slice(0, 8) + "01";
|
|
50
|
+
export const endOfMonth = (iso) => {
|
|
51
|
+
const data = parseIso(iso);
|
|
52
|
+
return toIso(new Date(data.getFullYear(), data.getMonth() + 1, 0));
|
|
53
|
+
};
|
|
54
|
+
export const isSameMonth = (a, b) => a.slice(0, 7) === b.slice(0, 7);
|
|
55
|
+
/** Os sete dias da semana que contém `iso`. */
|
|
56
|
+
export const weekDays = (iso, comecaEm) => {
|
|
57
|
+
const inicio = startOfWeek(iso, comecaEm);
|
|
58
|
+
const dias = [];
|
|
59
|
+
for (let i = 0; i < 7; i++)
|
|
60
|
+
dias.push(addDays(inicio, i));
|
|
61
|
+
return dias;
|
|
62
|
+
};
|
|
63
|
+
/** O mês de `iso` em semanas inteiras (de 4 a 6 linhas), com os dias dos meses vizinhos que completam as pontas. */
|
|
64
|
+
export const monthMatrix = (iso, comecaEm) => {
|
|
65
|
+
const ultimo = endOfMonth(iso);
|
|
66
|
+
let cursor = startOfWeek(startOfMonth(iso), comecaEm);
|
|
67
|
+
const semanas = [];
|
|
68
|
+
while (cursor <= ultimo) {
|
|
69
|
+
semanas.push(weekDays(cursor, comecaEm));
|
|
70
|
+
cursor = addDays(cursor, 7);
|
|
71
|
+
}
|
|
72
|
+
return semanas;
|
|
73
|
+
};
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* HTML seguro para o `RichTextEditor`.
|
|
3
|
+
*
|
|
4
|
+
* O editor devolve HTML (`onChange`) e recebe HTML (`value`). HTML que vem de
|
|
5
|
+
* fora (um valor guardado, um texto colado) pode trazer `<img onerror>`,
|
|
6
|
+
* `<a href="javascript:...">`, `<script>`, `style` e classes de outro site. Este
|
|
7
|
+
* módulo reduz o HTML ao que o editor sabe escrever: negrito, itálico,
|
|
8
|
+
* sublinhado, tachado, listas, parágrafos, quebras, títulos, citação e link.
|
|
9
|
+
*
|
|
10
|
+
* Roda no navegador (precisa de DOM). Dentro de um `<template>` o HTML é inerte:
|
|
11
|
+
* nada executa e nenhuma imagem carrega enquanto se higieniza. Sem DOM
|
|
12
|
+
* (servidor), devolve o texto escapado.
|
|
13
|
+
*/
|
|
14
|
+
/**
|
|
15
|
+
* Endereço de link que o editor aceita: `http:`, `https:`, `mailto:`, `tel:`,
|
|
16
|
+
* caminho (`/x`, `./x`, `../x`) ou âncora (`#x`). Devolve o endereço limpo, ou ""
|
|
17
|
+
* se for perigoso (`javascript:`, `data:`, `vbscript:`...).
|
|
18
|
+
*/
|
|
19
|
+
export declare const enderecoSeguro: (bruto: string) => string;
|
|
20
|
+
/** Devolve o endereço pronto para `href`: o seguro como veio, ou `https://` + o texto quando não tem esquema. "" se perigoso ou vazio. */
|
|
21
|
+
export declare const normalizarEndereco: (bruto: string) => string;
|
|
22
|
+
/** Reduz `html` ao que o editor escreve. Sem DOM, devolve o texto escapado. */
|
|
23
|
+
export declare const sanitizarHtml: (html: string) => string;
|
|
24
|
+
/** O editor está "vazio": sem texto, sem lista e sem quebra solta (o `<br>` que o navegador deixa). */
|
|
25
|
+
export declare const htmlVazio: (html: string) => boolean;
|
|
26
|
+
/** O `<a>` que o editor escreve quando o link não tem texto escolhido: o endereço (já seguro) é o href e o texto. */
|
|
27
|
+
export declare const htmlDoLink: (endereco: string) => string;
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* HTML seguro para o `RichTextEditor`.
|
|
3
|
+
*
|
|
4
|
+
* O editor devolve HTML (`onChange`) e recebe HTML (`value`). HTML que vem de
|
|
5
|
+
* fora (um valor guardado, um texto colado) pode trazer `<img onerror>`,
|
|
6
|
+
* `<a href="javascript:...">`, `<script>`, `style` e classes de outro site. Este
|
|
7
|
+
* módulo reduz o HTML ao que o editor sabe escrever: negrito, itálico,
|
|
8
|
+
* sublinhado, tachado, listas, parágrafos, quebras, títulos, citação e link.
|
|
9
|
+
*
|
|
10
|
+
* Roda no navegador (precisa de DOM). Dentro de um `<template>` o HTML é inerte:
|
|
11
|
+
* nada executa e nenhuma imagem carrega enquanto se higieniza. Sem DOM
|
|
12
|
+
* (servidor), devolve o texto escapado.
|
|
13
|
+
*/
|
|
14
|
+
const PERMITIDAS = ["A", "B", "STRONG", "I", "EM", "U", "S", "STRIKE", "DEL", "UL", "OL", "LI", "P", "BR", "DIV", "SPAN", "H1", "H2", "H3", "H4", "BLOCKQUOTE"];
|
|
15
|
+
const DESCARTADAS = ["SCRIPT", "STYLE", "IFRAME", "OBJECT", "EMBED", "LINK", "META", "TEMPLATE", "NOSCRIPT", "SVG", "MATH", "FORM", "INPUT", "BUTTON", "TEXTAREA", "SELECT"];
|
|
16
|
+
const escapar = (texto) => texto.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
17
|
+
/**
|
|
18
|
+
* Endereço de link que o editor aceita: `http:`, `https:`, `mailto:`, `tel:`,
|
|
19
|
+
* caminho (`/x`, `./x`, `../x`) ou âncora (`#x`). Devolve o endereço limpo, ou ""
|
|
20
|
+
* se for perigoso (`javascript:`, `data:`, `vbscript:`...).
|
|
21
|
+
*/
|
|
22
|
+
export const enderecoSeguro = (bruto) => {
|
|
23
|
+
const texto = (bruto || "").trim();
|
|
24
|
+
if (!texto)
|
|
25
|
+
return "";
|
|
26
|
+
// Caracteres de controle e espaços no meio do esquema são o truque clássico (`java\nscript:`).
|
|
27
|
+
const semControle = texto.replace(/[\u0000-\u001f\u007f\s]+/g, "");
|
|
28
|
+
if (/^(https?:\/\/|mailto:|tel:|\/|\.\.?\/|#)/i.test(semControle))
|
|
29
|
+
return texto;
|
|
30
|
+
if (/^[a-z][a-z0-9+.-]*:/i.test(semControle))
|
|
31
|
+
return "";
|
|
32
|
+
return "";
|
|
33
|
+
};
|
|
34
|
+
/** Devolve o endereço pronto para `href`: o seguro como veio, ou `https://` + o texto quando não tem esquema. "" se perigoso ou vazio. */
|
|
35
|
+
export const normalizarEndereco = (bruto) => {
|
|
36
|
+
const texto = (bruto || "").trim();
|
|
37
|
+
if (!texto)
|
|
38
|
+
return "";
|
|
39
|
+
const seguro = enderecoSeguro(texto);
|
|
40
|
+
if (seguro)
|
|
41
|
+
return seguro;
|
|
42
|
+
const semControle = texto.replace(/[\u0000-\u001f\u007f\s]+/g, "");
|
|
43
|
+
if (/^[a-z][a-z0-9+.-]*:/i.test(semControle))
|
|
44
|
+
return "";
|
|
45
|
+
return "https://" + texto;
|
|
46
|
+
};
|
|
47
|
+
const limparNo = (no, saida, documento) => {
|
|
48
|
+
const filhos = Array.prototype.slice.call(no.childNodes);
|
|
49
|
+
for (let i = 0; i < filhos.length; i++) {
|
|
50
|
+
const filho = filhos[i];
|
|
51
|
+
if (filho.nodeType === 3) {
|
|
52
|
+
saida.appendChild(documento.createTextNode(filho.nodeValue));
|
|
53
|
+
continue;
|
|
54
|
+
}
|
|
55
|
+
if (filho.nodeType !== 1)
|
|
56
|
+
continue;
|
|
57
|
+
const tag = String(filho.tagName).toUpperCase();
|
|
58
|
+
if (DESCARTADAS.indexOf(tag) !== -1)
|
|
59
|
+
continue;
|
|
60
|
+
if (PERMITIDAS.indexOf(tag) === -1) {
|
|
61
|
+
// Tag desconhecida: some a tag, fica o conteúdo.
|
|
62
|
+
limparNo(filho, saida, documento);
|
|
63
|
+
continue;
|
|
64
|
+
}
|
|
65
|
+
const novo = documento.createElement(tag.toLowerCase());
|
|
66
|
+
if (tag === "A") {
|
|
67
|
+
const href = enderecoSeguro(filho.getAttribute("href") || "");
|
|
68
|
+
if (href) {
|
|
69
|
+
novo.setAttribute("href", href);
|
|
70
|
+
novo.setAttribute("rel", "noopener noreferrer");
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
limparNo(filho, novo, documento);
|
|
74
|
+
saida.appendChild(novo);
|
|
75
|
+
}
|
|
76
|
+
};
|
|
77
|
+
/** Reduz `html` ao que o editor escreve. Sem DOM, devolve o texto escapado. */
|
|
78
|
+
export const sanitizarHtml = (html) => {
|
|
79
|
+
const bruto = html || "";
|
|
80
|
+
if (typeof document === "undefined")
|
|
81
|
+
return escapar(bruto);
|
|
82
|
+
const molde = document.createElement("template");
|
|
83
|
+
molde.innerHTML = bruto;
|
|
84
|
+
const saida = document.createElement("div");
|
|
85
|
+
limparNo(molde.content, saida, document);
|
|
86
|
+
return saida.innerHTML;
|
|
87
|
+
};
|
|
88
|
+
/** O editor está "vazio": sem texto, sem lista e sem quebra solta (o `<br>` que o navegador deixa). */
|
|
89
|
+
export const htmlVazio = (html) => {
|
|
90
|
+
const texto = (html || "").replace(/<br\s*\/?>/gi, "").replace(/<\/?(div|p|span)[^>]*>/gi, "").trim();
|
|
91
|
+
return texto === "";
|
|
92
|
+
};
|
|
93
|
+
/** O `<a>` que o editor escreve quando o link não tem texto escolhido: o endereço (já seguro) é o href e o texto. */
|
|
94
|
+
export const htmlDoLink = (endereco) => {
|
|
95
|
+
const seguro = escapar(endereco);
|
|
96
|
+
return '<a href="' + seguro + '">' + seguro + "</a>";
|
|
97
|
+
};
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Paleta de cor categórica do 1DS: os primitivos `--umds-primitive-<família>-<tom>`.
|
|
3
|
+
*
|
|
4
|
+
* É a lista que o `ColorPicker` mostra por padrão. Ela existe como constante
|
|
5
|
+
* exportada para o app mapear o valor guardado (o nome do token) de volta para
|
|
6
|
+
* um rótulo, ou montar a própria lista a partir dela (`COLOR_PALETTE.filter(...)`).
|
|
7
|
+
*
|
|
8
|
+
* Primitivo não muda com o tema: é o certo para cor de DADO (marcador, tipo de
|
|
9
|
+
* documento, setor), que precisa ser a mesma no claro e no escuro. Para cor com
|
|
10
|
+
* PAPEL (primário, erro, sucesso) use os semânticos `--umds-semantic-color-*`,
|
|
11
|
+
* que não entram aqui.
|
|
12
|
+
*/
|
|
13
|
+
export type PaletteColor = {
|
|
14
|
+
/** Nome da variável CSS, ex.: `--umds-primitive-blue-pure`. Use como `var(${value})`. */
|
|
15
|
+
value: string;
|
|
16
|
+
/** Nome em português, ex.: "Azul escuro". */
|
|
17
|
+
label: string;
|
|
18
|
+
/** Família: blue, red, green, orange, yellow, purple ou gray. */
|
|
19
|
+
family: string;
|
|
20
|
+
/** Tom claro o bastante para o ícone de marcação sair escuro (contraste mínimo de 3:1). */
|
|
21
|
+
onLight: boolean;
|
|
22
|
+
};
|
|
23
|
+
/** Os 31 primitivos de cor (6 famílias x 4 tons + 7 cinzas), do mais escuro ao mais claro. */
|
|
24
|
+
export declare const COLOR_PALETTE: PaletteColor[];
|
|
25
|
+
/** `#RRGGBB` completo (o `#` é opcional). Hexadecimal curto (`#FFF`) não vale. */
|
|
26
|
+
export declare const isHexColor: (texto: string) => boolean;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
const cor = (family, tone, label, onLight) => ({
|
|
2
|
+
value: "--umds-primitive-" + family + "-" + tone,
|
|
3
|
+
label,
|
|
4
|
+
family,
|
|
5
|
+
onLight
|
|
6
|
+
});
|
|
7
|
+
/** Os 31 primitivos de cor (6 famílias x 4 tons + 7 cinzas), do mais escuro ao mais claro. */
|
|
8
|
+
export const COLOR_PALETTE = [cor("blue", "dark", "Azul escuro", false), cor("blue", "pure", "Azul", false), cor("blue", "medium", "Azul médio", false), cor("blue", "light", "Azul claro", true), cor("red", "dark", "Vermelho escuro", false), cor("red", "pure", "Vermelho", false), cor("red", "medium", "Vermelho médio", false), cor("red", "light", "Vermelho claro", true), cor("green", "dark", "Verde escuro", false), cor("green", "pure", "Verde", false), cor("green", "medium", "Verde médio", false), cor("green", "light", "Verde claro", true), cor("orange", "dark", "Laranja escuro", false), cor("orange", "pure", "Laranja", false), cor("orange", "medium", "Laranja médio", true), cor("orange", "light", "Laranja claro", true), cor("yellow", "dark", "Amarelo escuro", false), cor("yellow", "pure", "Amarelo", true), cor("yellow", "medium", "Amarelo médio", true), cor("yellow", "light", "Amarelo claro", true), cor("purple", "dark", "Roxo escuro", false), cor("purple", "pure", "Roxo", false), cor("purple", "medium", "Roxo médio", false), cor("purple", "light", "Roxo claro", true), cor("gray", "darkest", "Cinza muito escuro", false), cor("gray", "darker", "Cinza escuro", false), cor("gray", "dark", "Cinza", false), cor("gray", "medium", "Cinza médio", true), cor("gray", "light", "Cinza claro", true), cor("gray", "lighter", "Cinza mais claro", true), cor("gray", "lightest", "Cinza muito claro", true)];
|
|
9
|
+
/** `#RRGGBB` completo (o `#` é opcional). Hexadecimal curto (`#FFF`) não vale. */
|
|
10
|
+
export const isHexColor = (texto) => /^#?[0-9a-fA-F]{6}$/.test((texto || "").trim());
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Texto para comparar: minúsculo, sem acento e sem espaço nas pontas. É o que a
|
|
3
|
+
* busca do `IconPicker` usa para achar "usuario" em "Usuário".
|
|
4
|
+
*/
|
|
5
|
+
export const semAcento = (texto) => String(texto || "").normalize("NFD").replace(/[̀-ͯ]/g, "").toLowerCase().trim();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@1doc/1ds-react",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.9.0",
|
|
4
4
|
"main": "dist/index.js",
|
|
5
5
|
"sideEffects": [
|
|
6
6
|
"**/*.css"
|
|
@@ -45,8 +45,8 @@
|
|
|
45
45
|
"react-dom": "^18.0.0",
|
|
46
46
|
"typescript": "^5.0.0",
|
|
47
47
|
"vitest": "^3.2.7",
|
|
48
|
-
"@1doc/1ds-core": "2.
|
|
49
|
-
"@1doc/1ds-tokens": "0.
|
|
48
|
+
"@1doc/1ds-core": "2.9.0",
|
|
49
|
+
"@1doc/1ds-tokens": "0.5.0"
|
|
50
50
|
},
|
|
51
51
|
"publishConfig": {
|
|
52
52
|
"access": "public"
|
package/src/index.ts
CHANGED
|
@@ -5,6 +5,8 @@ export * from "./utils/theme";
|
|
|
5
5
|
export * from "./utils/toast";
|
|
6
6
|
// Densidade global (modo touch ≥44px via data-density)
|
|
7
7
|
export * from "./utils/density";
|
|
8
|
+
// Paleta de cor categórica (primitivos) do ColorPicker
|
|
9
|
+
export * from "./utils/paleta-de-cores";
|
|
8
10
|
// FontAwesome
|
|
9
11
|
export { library } from "@fortawesome/fontawesome-svg-core";
|
|
10
12
|
|
|
@@ -12,6 +14,9 @@ export { library } from "@fortawesome/fontawesome-svg-core";
|
|
|
12
14
|
export { default as Accordion } from "./components/Accordion/Accordion";
|
|
13
15
|
export { default as AILabel } from "./components/AILabel/AILabel";
|
|
14
16
|
export { default as AIContent } from "./components/AIContent/AIContent";
|
|
17
|
+
export { default as Calendar } from "./components/Calendar/Calendar";
|
|
18
|
+
export { default as Coachmark } from "./components/Coachmark/Coachmark";
|
|
19
|
+
export { default as CodeBlock } from "./components/CodeBlock/CodeBlock";
|
|
15
20
|
export { default as ConfirmAIAction } from "./components/ConfirmAIAction/ConfirmAIAction";
|
|
16
21
|
export { default as Alert } from "./components/Alert/Alert";
|
|
17
22
|
export { default as AppHeader } from "./components/AppHeader/AppHeader";
|
|
@@ -33,11 +38,13 @@ export { default as Button } from "./components/Button/Button";
|
|
|
33
38
|
export { default as Card } from "./components/Card/Card";
|
|
34
39
|
export { default as Checkbox } from "./components/Checkbox/Checkbox";
|
|
35
40
|
export { default as Chips } from "./components/Chips/Chips";
|
|
41
|
+
export { default as ColorPicker } from "./components/ColorPicker/ColorPicker";
|
|
36
42
|
export { default as Combobox } from "./components/Combobox/Combobox";
|
|
37
43
|
export { default as ConfirmDialog } from "./components/ConfirmDialog/ConfirmDialog";
|
|
38
44
|
export { default as Container } from "./components/Container/Container";
|
|
39
45
|
export { default as DataTable } from "./components/DataTable/DataTable";
|
|
40
46
|
export { default as DatePicker } from "./components/DatePicker/DatePicker";
|
|
47
|
+
export { default as DescriptionList } from "./components/DescriptionList/DescriptionList";
|
|
41
48
|
export { default as Divider } from "./components/Divider/Divider";
|
|
42
49
|
export { default as DonutChart } from "./components/Chart/DonutChart";
|
|
43
50
|
export { default as Drawer } from "./components/Drawer/Drawer";
|
|
@@ -46,15 +53,21 @@ export { default as EmptyState } from "./components/EmptyState/EmptyState";
|
|
|
46
53
|
export { default as FileInput } from "./components/FileInput/FileInput";
|
|
47
54
|
export { default as Grid } from "./components/Grid/Grid";
|
|
48
55
|
export { default as Icon } from "./components/Icon/Icon";
|
|
56
|
+
export { default as IconPicker } from "./components/IconPicker/IconPicker";
|
|
49
57
|
export { default as Input } from "./components/Input/Input";
|
|
50
58
|
export { default as Kanban } from "./components/Kanban/Kanban";
|
|
51
59
|
export { default as KanbanCard } from "./components/Kanban/KanbanCard";
|
|
52
60
|
export { default as KanbanColumn } from "./components/Kanban/KanbanColumn";
|
|
61
|
+
export { default as Kbd } from "./components/Kbd/Kbd";
|
|
53
62
|
export { default as Link } from "./components/Link/Link";
|
|
54
63
|
export { default as LineChart } from "./components/Chart/LineChart";
|
|
64
|
+
export { default as List } from "./components/List/List";
|
|
65
|
+
export { default as ListItem } from "./components/List/ListItem";
|
|
55
66
|
export { default as Logo } from "./components/Logo/Logo";
|
|
56
67
|
export { default as Modal } from "./components/Modal/Modal";
|
|
57
68
|
export { default as MultiSelect } from "./components/MultiSelect/MultiSelect";
|
|
69
|
+
export { default as OrgChart } from "./components/OrgChart/OrgChart";
|
|
70
|
+
export { default as OtpInput } from "./components/OtpInput/OtpInput";
|
|
58
71
|
export { default as PageHeader } from "./components/PageHeader/PageHeader";
|
|
59
72
|
export { default as Pagination } from "./components/Pagination/Pagination";
|
|
60
73
|
export { default as PhoneInput } from "./components/PhoneInput/PhoneInput";
|
|
@@ -62,6 +75,7 @@ export { default as Podium } from "./components/Podium/Podium";
|
|
|
62
75
|
export { default as ProgressBar } from "./components/ProgressBar/ProgressBar";
|
|
63
76
|
export { default as Radio } from "./components/Radio/Radio";
|
|
64
77
|
export { default as RadioGroup } from "./components/Radio/RadioGroup";
|
|
78
|
+
export { default as RichTextEditor } from "./components/RichTextEditor/RichTextEditor";
|
|
65
79
|
export { default as SegmentedControl } from "./components/SegmentedControl/SegmentedControl";
|
|
66
80
|
export { default as Select } from "./components/Select/Select";
|
|
67
81
|
export { default as SidePanel } from "./components/SidePanel/SidePanel";
|
|
@@ -94,6 +108,9 @@ export { default as Tree } from "./components/Tree/Tree";
|
|
|
94
108
|
export type * from "./components/Accordion/Accordion";
|
|
95
109
|
export type * from "./components/AILabel/AILabel";
|
|
96
110
|
export type * from "./components/AIContent/AIContent";
|
|
111
|
+
export type * from "./components/Calendar/Calendar";
|
|
112
|
+
export type * from "./components/Coachmark/Coachmark";
|
|
113
|
+
export type * from "./components/CodeBlock/CodeBlock";
|
|
97
114
|
export type * from "./components/ConfirmAIAction/ConfirmAIAction";
|
|
98
115
|
export type * from "./components/Alert/Alert";
|
|
99
116
|
export type * from "./components/AppHeader/AppHeader";
|
|
@@ -115,11 +132,13 @@ export type * from "./components/Button/Button";
|
|
|
115
132
|
export type * from "./components/Card/Card";
|
|
116
133
|
export type * from "./components/Checkbox/Checkbox";
|
|
117
134
|
export type * from "./components/Chips/Chips";
|
|
135
|
+
export type * from "./components/ColorPicker/ColorPicker";
|
|
118
136
|
export type * from "./components/Combobox/Combobox";
|
|
119
137
|
export type * from "./components/ConfirmDialog/ConfirmDialog";
|
|
120
138
|
export type * from "./components/Container/Container";
|
|
121
139
|
export type * from "./components/DataTable/DataTable";
|
|
122
140
|
export type * from "./components/DatePicker/DatePicker";
|
|
141
|
+
export type * from "./components/DescriptionList/DescriptionList";
|
|
123
142
|
export type * from "./components/Divider/Divider";
|
|
124
143
|
export type * from "./components/Chart/DonutChart";
|
|
125
144
|
export type * from "./components/Drawer/Drawer";
|
|
@@ -128,15 +147,21 @@ export type * from "./components/EmptyState/EmptyState";
|
|
|
128
147
|
export type * from "./components/FileInput/FileInput";
|
|
129
148
|
export type * from "./components/Grid/Grid";
|
|
130
149
|
export type * from "./components/Icon/Icon";
|
|
150
|
+
export type * from "./components/IconPicker/IconPicker";
|
|
131
151
|
export type * from "./components/Input/Input";
|
|
132
152
|
export type * from "./components/Kanban/Kanban";
|
|
133
153
|
export type * from "./components/Kanban/KanbanCard";
|
|
134
154
|
export type * from "./components/Kanban/KanbanColumn";
|
|
155
|
+
export type * from "./components/Kbd/Kbd";
|
|
135
156
|
export type * from "./components/Link/Link";
|
|
136
157
|
export type * from "./components/Chart/LineChart";
|
|
158
|
+
export type * from "./components/List/List";
|
|
159
|
+
export type * from "./components/List/ListItem";
|
|
137
160
|
export type * from "./components/Logo/Logo";
|
|
138
161
|
export type * from "./components/Modal/Modal";
|
|
139
162
|
export type * from "./components/MultiSelect/MultiSelect";
|
|
163
|
+
export type * from "./components/OrgChart/OrgChart";
|
|
164
|
+
export type * from "./components/OtpInput/OtpInput";
|
|
140
165
|
export type * from "./components/PageHeader/PageHeader";
|
|
141
166
|
export type * from "./components/Pagination/Pagination";
|
|
142
167
|
export type * from "./components/PhoneInput/PhoneInput";
|
|
@@ -144,6 +169,7 @@ export type * from "./components/Podium/Podium";
|
|
|
144
169
|
export type * from "./components/ProgressBar/ProgressBar";
|
|
145
170
|
export type * from "./components/Radio/Radio";
|
|
146
171
|
export type * from "./components/Radio/RadioGroup";
|
|
172
|
+
export type * from "./components/RichTextEditor/RichTextEditor";
|
|
147
173
|
export type * from "./components/SegmentedControl/SegmentedControl";
|
|
148
174
|
export type * from "./components/Select/Select";
|
|
149
175
|
export type * from "./components/SidePanel/SidePanel";
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { describe, expect, it, vi } from "vitest";
|
|
2
|
+
import { render, screen } from "@testing-library/react";
|
|
3
|
+
import userEvent from "@testing-library/user-event";
|
|
4
|
+
import AILabel from "../components/AILabel/AILabel";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* `defaultOpen` era declarado e documentado, mas nunca lido: o painel nascia
|
|
8
|
+
* fechado de qualquer jeito, e a story "Em inglês" usava `open` (controlado)
|
|
9
|
+
* para contornar — o que travava o clique.
|
|
10
|
+
*/
|
|
11
|
+
describe("AILabel · defaultOpen", () => {
|
|
12
|
+
it("abre o painel na montagem", () => {
|
|
13
|
+
render(<AILabel explanation="Resumo dos despachos." defaultOpen />);
|
|
14
|
+
expect(screen.getByRole("region")).toHaveTextContent("Resumo dos despachos.");
|
|
15
|
+
expect(screen.getByRole("button", { name: "Conteúdo gerado por IA" })).toHaveAttribute(
|
|
16
|
+
"aria-expanded",
|
|
17
|
+
"true",
|
|
18
|
+
);
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
it("continua não-controlado: o clique fecha e avisa", async () => {
|
|
22
|
+
const usuario = userEvent.setup();
|
|
23
|
+
const onOpenChange = vi.fn();
|
|
24
|
+
render(
|
|
25
|
+
<AILabel explanation="Resumo." defaultOpen onOpenChange={onOpenChange} />,
|
|
26
|
+
);
|
|
27
|
+
await usuario.click(screen.getByRole("button", { name: "Conteúdo gerado por IA" }));
|
|
28
|
+
expect(screen.queryByRole("region")).not.toBeInTheDocument();
|
|
29
|
+
expect(onOpenChange).toHaveBeenCalledWith(false);
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
it("sem defaultOpen nasce fechado", () => {
|
|
33
|
+
render(<AILabel explanation="Resumo." />);
|
|
34
|
+
expect(screen.queryByRole("region")).not.toBeInTheDocument();
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
it("`open` controlado vence o defaultOpen", () => {
|
|
38
|
+
render(<AILabel explanation="Resumo." defaultOpen open={false} />);
|
|
39
|
+
expect(screen.queryByRole("region")).not.toBeInTheDocument();
|
|
40
|
+
});
|
|
41
|
+
});
|