@1doc/1ds-react 2.8.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.
Files changed (287) hide show
  1. package/CHANGELOG.md +1540 -0
  2. package/dist/components/AILabel/AILabel.js +1 -1
  3. package/dist/components/Accordion/Accordion.css +13 -0
  4. package/dist/components/Accordion/Accordion.d.ts +9 -2
  5. package/dist/components/Accordion/Accordion.js +1 -0
  6. package/dist/components/AppSubheader/AppSubheader.css +10 -1
  7. package/dist/components/AttachmentCard/AttachmentCard.css +26 -8
  8. package/dist/components/AttachmentCard/AttachmentCard.d.ts +22 -2
  9. package/dist/components/AttachmentCard/AttachmentCard.js +47 -3
  10. package/dist/components/Avatar/Avatar.css +7 -2
  11. package/dist/components/Avatar/AvatarGroup.d.ts +17 -0
  12. package/dist/components/Avatar/AvatarGroup.js +22 -8
  13. package/dist/components/Badge/Badge.css +67 -2
  14. package/dist/components/Badge/Badge.d.ts +23 -4
  15. package/dist/components/Badge/Badge.js +4 -0
  16. package/dist/components/Box/Box.css +83 -0
  17. package/dist/components/Box/Box.d.ts +82 -2
  18. package/dist/components/Box/Box.js +42 -2
  19. package/dist/components/Button/Button.css +29 -0
  20. package/dist/components/Button/Button.d.ts +4 -4
  21. package/dist/components/Button/Button.js +4 -1
  22. package/dist/components/Calendar/Calendar.css +245 -0
  23. package/dist/components/Calendar/Calendar.d.ts +126 -0
  24. package/dist/components/Calendar/Calendar.js +320 -0
  25. package/dist/components/Chips/Chips.css +38 -0
  26. package/dist/components/Chips/Chips.d.ts +5 -2
  27. package/dist/components/Chips/Chips.js +2 -1
  28. package/dist/components/Coachmark/Coachmark.css +128 -0
  29. package/dist/components/Coachmark/Coachmark.d.ts +87 -0
  30. package/dist/components/Coachmark/Coachmark.js +362 -0
  31. package/dist/components/CodeBlock/CodeBlock.css +96 -0
  32. package/dist/components/CodeBlock/CodeBlock.d.ts +47 -0
  33. package/dist/components/CodeBlock/CodeBlock.js +103 -0
  34. package/dist/components/ColorPicker/ColorPicker.css +140 -0
  35. package/dist/components/ColorPicker/ColorPicker.d.ts +73 -0
  36. package/dist/components/ColorPicker/ColorPicker.js +219 -0
  37. package/dist/components/Combobox/Combobox.css +8 -0
  38. package/dist/components/DataTable/DataTable.css +254 -0
  39. package/dist/components/DataTable/DataTable.d.ts +81 -5
  40. package/dist/components/DataTable/DataTable.js +335 -19
  41. package/dist/components/DatePicker/DatePicker.css +8 -0
  42. package/dist/components/DatePicker/DatePicker.js +10 -1
  43. package/dist/components/DescriptionList/DescriptionList.css +127 -0
  44. package/dist/components/DescriptionList/DescriptionList.d.ts +62 -0
  45. package/dist/components/DescriptionList/DescriptionList.js +52 -0
  46. package/dist/components/EmptyState/EmptyState.d.ts +4 -2
  47. package/dist/components/EmptyState/EmptyState.js +2 -2
  48. package/dist/components/FileInput/FileInput.css +16 -0
  49. package/dist/components/FileInput/FileInput.d.ts +4 -2
  50. package/dist/components/FileInput/FileInput.js +8 -2
  51. package/dist/components/Grid/Grid.js +5 -5
  52. package/dist/components/IconPicker/IconPicker.css +107 -0
  53. package/dist/components/IconPicker/IconPicker.d.ts +74 -0
  54. package/dist/components/IconPicker/IconPicker.js +194 -0
  55. package/dist/components/Input/Input.css +59 -0
  56. package/dist/components/Input/Input.d.ts +17 -1
  57. package/dist/components/Input/Input.js +67 -5
  58. package/dist/components/Kanban/Kanban.css +4 -0
  59. package/dist/components/Kbd/Kbd.css +66 -0
  60. package/dist/components/Kbd/Kbd.d.ts +32 -0
  61. package/dist/components/Kbd/Kbd.js +40 -0
  62. package/dist/components/List/List.css +136 -0
  63. package/dist/components/List/List.d.ts +82 -0
  64. package/dist/components/List/List.js +53 -0
  65. package/dist/components/List/ListItem.d.ts +97 -0
  66. package/dist/components/List/ListItem.js +82 -0
  67. package/dist/components/Modal/Modal.css +80 -0
  68. package/dist/components/Modal/Modal.d.ts +33 -6
  69. package/dist/components/Modal/Modal.js +101 -6
  70. package/dist/components/MultiSelect/MultiSelect.css +8 -0
  71. package/dist/components/MultiSelect/MultiSelect.js +10 -1
  72. package/dist/components/OrgChart/OrgChart.css +149 -0
  73. package/dist/components/OrgChart/OrgChart.d.ts +83 -0
  74. package/dist/components/OrgChart/OrgChart.js +297 -0
  75. package/dist/components/OtpInput/OtpInput.css +93 -0
  76. package/dist/components/OtpInput/OtpInput.d.ts +60 -0
  77. package/dist/components/OtpInput/OtpInput.js +215 -0
  78. package/dist/components/PhoneInput/PhoneInput.css +8 -0
  79. package/dist/components/Popover/Popover.d.ts +7 -0
  80. package/dist/components/Popover/Popover.js +11 -1
  81. package/dist/components/RichTextEditor/RichTextEditor.css +250 -0
  82. package/dist/components/RichTextEditor/RichTextEditor.d.ts +97 -0
  83. package/dist/components/RichTextEditor/RichTextEditor.js +951 -0
  84. package/dist/components/SegmentedControl/SegmentedControl.css +24 -0
  85. package/dist/components/SegmentedControl/SegmentedControl.d.ts +2 -0
  86. package/dist/components/SegmentedControl/SegmentedControl.js +10 -2
  87. package/dist/components/Select/Select.css +164 -0
  88. package/dist/components/Select/Select.d.ts +34 -0
  89. package/dist/components/Select/Select.js +258 -28
  90. package/dist/components/Stack/Stack.css +49 -0
  91. package/dist/components/Stack/Stack.d.ts +65 -7
  92. package/dist/components/Stack/Stack.js +30 -2
  93. package/dist/components/StatCard/StatCard.css +138 -0
  94. package/dist/components/StatCard/StatCard.d.ts +26 -0
  95. package/dist/components/StatCard/StatCard.js +13 -1
  96. package/dist/components/Tabs/Tab.d.ts +15 -0
  97. package/dist/components/Tabs/Tab.js +30 -1
  98. package/dist/components/Tabs/Tabs.css +132 -0
  99. package/dist/components/Tabs/Tabs.d.ts +7 -0
  100. package/dist/components/Tabs/Tabs.js +13 -2
  101. package/dist/components/Tag/Tag.css +85 -2
  102. package/dist/components/Tag/Tag.d.ts +13 -6
  103. package/dist/components/Tag/Tag.js +1 -0
  104. package/dist/components/Text/Text.js +2 -2
  105. package/dist/components/Textarea/Textarea.css +8 -0
  106. package/dist/components/TimePicker/TimePicker.css +8 -0
  107. package/dist/components/Toast/Toast.css +32 -0
  108. package/dist/components/Toast/Toast.d.ts +18 -0
  109. package/dist/components/Toast/Toast.js +14 -1
  110. package/dist/components/Toast/ToastStack.js +8 -1
  111. package/dist/components/Tooltip/Tooltip.css +25 -0
  112. package/dist/components/Tooltip/Tooltip.d.ts +11 -0
  113. package/dist/components/Tooltip/Tooltip.js +18 -3
  114. package/dist/index.d.ts +25 -0
  115. package/dist/index.js +14 -0
  116. package/dist/teste/AILabel.test.d.ts +1 -0
  117. package/dist/teste/AILabel.test.js +33 -0
  118. package/dist/teste/AccordionConteudoLivre.test.d.ts +1 -0
  119. package/dist/teste/AccordionConteudoLivre.test.js +29 -0
  120. package/dist/teste/AccordionTituloNeutro.test.d.ts +1 -0
  121. package/dist/teste/AccordionTituloNeutro.test.js +23 -0
  122. package/dist/teste/AppSubheaderRegiao.test.d.ts +1 -0
  123. package/dist/teste/AppSubheaderRegiao.test.js +13 -0
  124. package/dist/teste/AtributosRepassados.test.d.ts +1 -0
  125. package/dist/teste/AtributosRepassados.test.js +52 -0
  126. package/dist/teste/AttachmentCardIA.test.d.ts +1 -0
  127. package/dist/teste/AttachmentCardIA.test.js +89 -0
  128. package/dist/teste/AttachmentCardLista.test.d.ts +1 -0
  129. package/dist/teste/AttachmentCardLista.test.js +49 -0
  130. package/dist/teste/AttachmentCardSm.test.d.ts +1 -0
  131. package/dist/teste/AttachmentCardSm.test.js +26 -0
  132. package/dist/teste/AvatarGroupOverlap.test.d.ts +1 -0
  133. package/dist/teste/AvatarGroupOverlap.test.js +56 -0
  134. package/dist/teste/BadgeNeutroColado.test.d.ts +1 -0
  135. package/dist/teste/BadgeNeutroColado.test.js +11 -0
  136. package/dist/teste/BadgeTag.test.d.ts +1 -0
  137. package/dist/teste/BadgeTag.test.js +55 -0
  138. package/dist/teste/BoxItemFlex.test.d.ts +1 -0
  139. package/dist/teste/BoxItemFlex.test.js +54 -0
  140. package/dist/teste/BoxLayout.test.d.ts +1 -0
  141. package/dist/teste/BoxLayout.test.js +35 -0
  142. package/dist/teste/Button.test.d.ts +1 -0
  143. package/dist/teste/Button.test.js +27 -0
  144. package/dist/teste/Calendar.test.d.ts +1 -0
  145. package/dist/teste/Calendar.test.js +221 -0
  146. package/dist/teste/CalendarCabecalho.test.d.ts +1 -0
  147. package/dist/teste/CalendarCabecalho.test.js +11 -0
  148. package/dist/teste/ChipsXs.test.d.ts +1 -0
  149. package/dist/teste/ChipsXs.test.js +31 -0
  150. package/dist/teste/Coachmark.test.d.ts +1 -0
  151. package/dist/teste/Coachmark.test.js +149 -0
  152. package/dist/teste/CoachmarkSemVeu.test.d.ts +1 -0
  153. package/dist/teste/CoachmarkSemVeu.test.js +85 -0
  154. package/dist/teste/ColorPicker.test.d.ts +1 -0
  155. package/dist/teste/ColorPicker.test.js +132 -0
  156. package/dist/teste/ColorPickerXs.test.d.ts +1 -0
  157. package/dist/teste/ColorPickerXs.test.js +21 -0
  158. package/dist/teste/DataTableArvoreEVariantes.test.d.ts +1 -0
  159. package/dist/teste/DataTableArvoreEVariantes.test.js +190 -0
  160. package/dist/teste/DataTableCelulaLivre.test.d.ts +1 -0
  161. package/dist/teste/DataTableCelulaLivre.test.js +76 -0
  162. package/dist/teste/DataTableDocumento.test.d.ts +1 -0
  163. package/dist/teste/DataTableDocumento.test.js +92 -0
  164. package/dist/teste/DatePicker.test.js +23 -0
  165. package/dist/teste/DescriptionListCompacta.test.d.ts +1 -0
  166. package/dist/teste/DescriptionListCompacta.test.js +22 -0
  167. package/dist/teste/EmptyStateTituloRico.test.d.ts +1 -0
  168. package/dist/teste/EmptyStateTituloRico.test.js +23 -0
  169. package/dist/teste/FileInputTrigger.test.d.ts +1 -0
  170. package/dist/teste/FileInputTrigger.test.js +53 -0
  171. package/dist/teste/IconPicker.test.d.ts +1 -0
  172. package/dist/teste/IconPicker.test.js +130 -0
  173. package/dist/teste/InputAgrupado.test.d.ts +1 -0
  174. package/dist/teste/InputAgrupado.test.js +24 -0
  175. package/dist/teste/InputMascaraEAfins.test.d.ts +1 -0
  176. package/dist/teste/InputMascaraEAfins.test.js +99 -0
  177. package/dist/teste/KbdCodeBlock.test.d.ts +1 -0
  178. package/dist/teste/KbdCodeBlock.test.js +95 -0
  179. package/dist/teste/List.test.d.ts +1 -0
  180. package/dist/teste/List.test.js +153 -0
  181. package/dist/teste/ListItemTooltipStandalone.test.d.ts +1 -0
  182. package/dist/teste/ListItemTooltipStandalone.test.js +39 -0
  183. package/dist/teste/ModalVariantes.test.d.ts +1 -0
  184. package/dist/teste/ModalVariantes.test.js +151 -0
  185. package/dist/teste/NomeAcessivelSsr.test.d.ts +1 -0
  186. package/dist/teste/NomeAcessivelSsr.test.js +88 -0
  187. package/dist/teste/OrgChart.test.d.ts +1 -0
  188. package/dist/teste/OrgChart.test.js +162 -0
  189. package/dist/teste/OtpInput.test.d.ts +1 -0
  190. package/dist/teste/OtpInput.test.js +143 -0
  191. package/dist/teste/PopoverMaxHeight.test.d.ts +1 -0
  192. package/dist/teste/PopoverMaxHeight.test.js +38 -0
  193. package/dist/teste/RichTextEditor.test.d.ts +1 -0
  194. package/dist/teste/RichTextEditor.test.js +287 -0
  195. package/dist/teste/RichTextEditorAlinhaImagemTabela.test.d.ts +1 -0
  196. package/dist/teste/RichTextEditorAlinhaImagemTabela.test.js +212 -0
  197. package/dist/teste/RichTextEditorEstiloDeTexto.test.d.ts +1 -0
  198. package/dist/teste/RichTextEditorEstiloDeTexto.test.js +120 -0
  199. package/dist/teste/SegmentedControlContador.test.d.ts +1 -0
  200. package/dist/teste/SegmentedControlContador.test.js +39 -0
  201. package/dist/teste/SelectAbertoControladoEFlutuante.test.d.ts +1 -0
  202. package/dist/teste/SelectAbertoControladoEFlutuante.test.js +145 -0
  203. package/dist/teste/SelectFiltroCorETamanho.test.d.ts +1 -0
  204. package/dist/teste/SelectFiltroCorETamanho.test.js +77 -0
  205. package/dist/teste/SelectPlacementFiltro.test.d.ts +1 -0
  206. package/dist/teste/SelectPlacementFiltro.test.js +88 -0
  207. package/dist/teste/Stack.test.d.ts +1 -0
  208. package/dist/teste/Stack.test.js +57 -0
  209. package/dist/teste/StatCardRotuloTopo.test.d.ts +1 -0
  210. package/dist/teste/StatCardRotuloTopo.test.js +34 -0
  211. package/dist/teste/StatCardSecundariaETom.test.d.ts +1 -0
  212. package/dist/teste/StatCardSecundariaETom.test.js +45 -0
  213. package/dist/teste/TabsContadorFechavel.test.d.ts +1 -0
  214. package/dist/teste/TabsContadorFechavel.test.js +79 -0
  215. package/dist/teste/ToastAcaoEDetalhes.test.d.ts +1 -0
  216. package/dist/teste/ToastAcaoEDetalhes.test.js +94 -0
  217. package/dist/teste/TooltipDark.test.d.ts +1 -0
  218. package/dist/teste/TooltipDark.test.js +31 -0
  219. package/dist/utils/calendario.d.ts +28 -0
  220. package/dist/utils/calendario.js +73 -0
  221. package/dist/utils/html-seguro.d.ts +45 -0
  222. package/dist/utils/html-seguro.js +208 -0
  223. package/dist/utils/paleta-de-cores.d.ts +26 -0
  224. package/dist/utils/paleta-de-cores.js +10 -0
  225. package/dist/utils/texto.d.ts +5 -0
  226. package/dist/utils/texto.js +5 -0
  227. package/dist/utils/toast.d.ts +10 -1
  228. package/dist/utils/toast.js +2 -1
  229. package/package.json +3 -3
  230. package/src/index.ts +26 -0
  231. package/src/teste/AILabel.test.tsx +41 -0
  232. package/src/teste/AccordionConteudoLivre.test.tsx +39 -0
  233. package/src/teste/AccordionTituloNeutro.test.tsx +25 -0
  234. package/src/teste/AppSubheaderRegiao.test.tsx +17 -0
  235. package/src/teste/AtributosRepassados.test.tsx +73 -0
  236. package/src/teste/AttachmentCardIA.test.tsx +126 -0
  237. package/src/teste/AttachmentCardLista.test.tsx +53 -0
  238. package/src/teste/AttachmentCardSm.test.tsx +29 -0
  239. package/src/teste/AvatarGroupOverlap.test.tsx +74 -0
  240. package/src/teste/BadgeNeutroColado.test.tsx +15 -0
  241. package/src/teste/BadgeTag.test.tsx +85 -0
  242. package/src/teste/BoxItemFlex.test.tsx +81 -0
  243. package/src/teste/BoxLayout.test.tsx +50 -0
  244. package/src/teste/Button.test.tsx +39 -0
  245. package/src/teste/Calendar.test.tsx +282 -0
  246. package/src/teste/CalendarCabecalho.test.tsx +11 -0
  247. package/src/teste/ChipsXs.test.tsx +41 -0
  248. package/src/teste/Coachmark.test.tsx +198 -0
  249. package/src/teste/CoachmarkSemVeu.test.tsx +101 -0
  250. package/src/teste/ColorPicker.test.tsx +153 -0
  251. package/src/teste/ColorPickerXs.test.tsx +22 -0
  252. package/src/teste/DataTableArvoreEVariantes.test.tsx +240 -0
  253. package/src/teste/DataTableCelulaLivre.test.tsx +103 -0
  254. package/src/teste/DataTableDocumento.test.tsx +102 -0
  255. package/src/teste/DatePicker.test.tsx +38 -0
  256. package/src/teste/DescriptionListCompacta.test.tsx +24 -0
  257. package/src/teste/EmptyStateTituloRico.test.tsx +34 -0
  258. package/src/teste/FileInputTrigger.test.tsx +89 -0
  259. package/src/teste/IconPicker.test.tsx +145 -0
  260. package/src/teste/InputAgrupado.test.tsx +26 -0
  261. package/src/teste/InputMascaraEAfins.test.tsx +124 -0
  262. package/src/teste/KbdCodeBlock.test.tsx +106 -0
  263. package/src/teste/List.test.tsx +269 -0
  264. package/src/teste/ListItemTooltipStandalone.test.tsx +64 -0
  265. package/src/teste/ModalVariantes.test.tsx +173 -0
  266. package/src/teste/NomeAcessivelSsr.test.tsx +110 -0
  267. package/src/teste/OrgChart.test.tsx +183 -0
  268. package/src/teste/OtpInput.test.tsx +163 -0
  269. package/src/teste/PopoverMaxHeight.test.tsx +47 -0
  270. package/src/teste/RichTextEditor.test.tsx +329 -0
  271. package/src/teste/RichTextEditorAlinhaImagemTabela.test.tsx +238 -0
  272. package/src/teste/RichTextEditorEstiloDeTexto.test.tsx +137 -0
  273. package/src/teste/SegmentedControlContador.test.tsx +43 -0
  274. package/src/teste/SelectAbertoControladoEFlutuante.test.tsx +180 -0
  275. package/src/teste/SelectFiltroCorETamanho.test.tsx +90 -0
  276. package/src/teste/SelectPlacementFiltro.test.tsx +110 -0
  277. package/src/teste/Stack.test.tsx +80 -0
  278. package/src/teste/StatCardRotuloTopo.test.tsx +44 -0
  279. package/src/teste/StatCardSecundariaETom.test.tsx +51 -0
  280. package/src/teste/TabsContadorFechavel.test.tsx +144 -0
  281. package/src/teste/ToastAcaoEDetalhes.test.tsx +109 -0
  282. package/src/teste/TooltipDark.test.tsx +51 -0
  283. package/src/utils/calendario.ts +78 -0
  284. package/src/utils/html-seguro.ts +197 -0
  285. package/src/utils/paleta-de-cores.ts +34 -0
  286. package/src/utils/texto.ts +5 -0
  287. package/src/utils/toast.ts +12 -2
@@ -0,0 +1,198 @@
1
+ import { describe, expect, it, vi } from "vitest";
2
+ import { useRef, useState } from "react";
3
+ import { render, screen, waitFor } from "@testing-library/react";
4
+ import userEvent from "@testing-library/user-event";
5
+ import Coachmark from "../components/Coachmark/Coachmark";
6
+
7
+ const PASSOS = [
8
+ { target: "#alvo-a", title: "Cada item é uma aba", content: "Fluxos e formulários abrem em abas." },
9
+ { target: "#alvo-b", title: "Salvo sozinho", content: "Tudo fica neste navegador." },
10
+ { title: "Pronto", content: "Sem alvo: o cartão fica no centro." },
11
+ ];
12
+
13
+ function Pagina(props: any) {
14
+ return (
15
+ <div>
16
+ <button id="alvo-a">A</button>
17
+ <button id="alvo-b">B</button>
18
+ <Coachmark steps={PASSOS} {...props} />
19
+ </div>
20
+ );
21
+ }
22
+
23
+ describe("Coachmark", () => {
24
+ it("fechado não desenha nada", () => {
25
+ render(<Pagina open={false} />);
26
+ expect(screen.queryByRole("dialog")).toBeNull();
27
+ });
28
+
29
+ it("aberto é um diálogo modal nomeado pelo título, com contador e texto", () => {
30
+ render(<Pagina open />);
31
+ const dialogo = screen.getByRole("dialog", { name: "Cada item é uma aba" });
32
+ expect(dialogo).toHaveAttribute("aria-modal", "true");
33
+ expect(dialogo).toHaveAccessibleDescription("Fluxos e formulários abrem em abas.");
34
+ expect(screen.getAllByText("1 de 3").length).toBeGreaterThan(0);
35
+ expect(screen.getByRole("button", { name: "Próximo" })).toBeInTheDocument();
36
+ expect(screen.queryByRole("button", { name: "Anterior" })).toBeNull();
37
+ });
38
+
39
+ it("o foco entra no cartão ao abrir", () => {
40
+ render(<Pagina open />);
41
+ expect(screen.getByRole("dialog")).toHaveFocus();
42
+ });
43
+
44
+ it("Próximo e Anterior trocam de passo e avisam em onStepChange", async () => {
45
+ const usuario = userEvent.setup();
46
+ const aoMudar = vi.fn();
47
+ render(<Pagina open onStepChange={aoMudar} />);
48
+ await usuario.click(screen.getByRole("button", { name: "Próximo" }));
49
+ expect(aoMudar).toHaveBeenLastCalledWith(1);
50
+ expect(screen.getByRole("dialog", { name: "Salvo sozinho" })).toBeInTheDocument();
51
+ await usuario.click(screen.getByRole("button", { name: "Anterior" }));
52
+ expect(aoMudar).toHaveBeenLastCalledWith(0);
53
+ expect(screen.getByRole("dialog", { name: "Cada item é uma aba" })).toBeInTheDocument();
54
+ });
55
+
56
+ it("setas direita e esquerda avançam e voltam", async () => {
57
+ const usuario = userEvent.setup();
58
+ render(<Pagina open />);
59
+ await usuario.keyboard("{ArrowRight}");
60
+ expect(screen.getByRole("dialog", { name: "Salvo sozinho" })).toBeInTheDocument();
61
+ await usuario.keyboard("{ArrowLeft}");
62
+ expect(screen.getByRole("dialog", { name: "Cada item é uma aba" })).toBeInTheDocument();
63
+ });
64
+
65
+ it("o último passo troca Próximo por Concluir e fecha com 'finish'", async () => {
66
+ const usuario = userEvent.setup();
67
+ const aoFechar = vi.fn();
68
+ render(<Pagina open defaultStep={2} onClose={aoFechar} />);
69
+ expect(screen.queryByRole("button", { name: "Próximo" })).toBeNull();
70
+ await usuario.click(screen.getByRole("button", { name: "Concluir" }));
71
+ expect(aoFechar).toHaveBeenCalledWith("finish");
72
+ });
73
+
74
+ it("Sair do tour fecha com 'skip' e hideSkip esconde o botão", async () => {
75
+ const usuario = userEvent.setup();
76
+ const aoFechar = vi.fn();
77
+ const { rerender } = render(<Pagina open onClose={aoFechar} />);
78
+ await usuario.click(screen.getByRole("button", { name: "Sair do tour" }));
79
+ expect(aoFechar).toHaveBeenCalledWith("skip");
80
+ rerender(<Pagina open hideSkip onClose={aoFechar} />);
81
+ expect(screen.queryByRole("button", { name: "Sair do tour" })).toBeNull();
82
+ });
83
+
84
+ it("Esc fecha com 'escape'", async () => {
85
+ const usuario = userEvent.setup();
86
+ const aoFechar = vi.fn();
87
+ render(<Pagina open onClose={aoFechar} />);
88
+ await usuario.keyboard("{Escape}");
89
+ expect(aoFechar).toHaveBeenCalledWith("escape");
90
+ });
91
+
92
+ it("o foco fica preso no cartão: Tab gira e Shift+Tab volta", async () => {
93
+ const usuario = userEvent.setup();
94
+ render(<Pagina open />);
95
+ const sair = screen.getByRole("button", { name: "Sair do tour" });
96
+ const proximo = screen.getByRole("button", { name: "Próximo" });
97
+ proximo.focus();
98
+ await usuario.tab();
99
+ expect(sair).toHaveFocus();
100
+ await usuario.tab({ shift: true });
101
+ expect(proximo).toHaveFocus();
102
+ });
103
+
104
+ it("todos os textos vêm por prop", () => {
105
+ render(
106
+ <Pagina
107
+ open
108
+ defaultStep={1}
109
+ nextLabel="Next"
110
+ previousLabel="Back"
111
+ skipLabel="Skip tour"
112
+ counterLabel="{current} of {total}"
113
+ />,
114
+ );
115
+ expect(screen.getByRole("button", { name: "Next" })).toBeInTheDocument();
116
+ expect(screen.getByRole("button", { name: "Back" })).toBeInTheDocument();
117
+ expect(screen.getByRole("button", { name: "Skip tour" })).toBeInTheDocument();
118
+ expect(screen.getAllByText("2 of 3").length).toBeGreaterThan(0);
119
+ });
120
+
121
+ it("finishLabel troca o texto do último passo", () => {
122
+ render(<Pagina open defaultStep={2} finishLabel="Done" />);
123
+ expect(screen.getByRole("button", { name: "Done" })).toBeInTheDocument();
124
+ });
125
+
126
+ it("com alvo, desenha o recorte; sem alvo (ou alvo que não existe), não", () => {
127
+ const { container, rerender } = render(<Pagina open />);
128
+ expect(document.querySelector(".umds-coachmark__cutout")).not.toBeNull();
129
+ rerender(<Pagina open step={2} />);
130
+ expect(document.querySelector(".umds-coachmark__cutout")).toBeNull();
131
+ expect(document.querySelector(".umds-coachmark--no-target")).not.toBeNull();
132
+ void container;
133
+ });
134
+
135
+ it("alvo por ref do React e por elemento", () => {
136
+ function ComRef() {
137
+ const ref = useRef<HTMLButtonElement>(null);
138
+ return (
139
+ <div>
140
+ <button ref={ref}>Alvo</button>
141
+ <Coachmark open steps={[{ target: ref, title: "Por ref" }]} />
142
+ </div>
143
+ );
144
+ }
145
+ render(<ComRef />);
146
+ expect(screen.getByRole("dialog", { name: "Por ref" })).toBeInTheDocument();
147
+ expect(document.querySelector(".umds-coachmark__cutout")).not.toBeNull();
148
+ });
149
+
150
+ it("step controlado manda no passo atual", () => {
151
+ render(<Pagina open step={1} />);
152
+ expect(screen.getByRole("dialog", { name: "Salvo sozinho" })).toBeInTheDocument();
153
+ });
154
+
155
+ it("ao fechar, o foco volta ao elemento de antes", async () => {
156
+ const usuario = userEvent.setup();
157
+ function Dono() {
158
+ const [aberto, setAberto] = useState(false);
159
+ return (
160
+ <div>
161
+ <button id="abrir" onClick={() => setAberto(true)}>
162
+ Fazer o tour
163
+ </button>
164
+ <Coachmark open={aberto} steps={PASSOS} onClose={() => setAberto(false)} />
165
+ </div>
166
+ );
167
+ }
168
+ render(<Dono />);
169
+ const abrir = screen.getByRole("button", { name: "Fazer o tour" });
170
+ await usuario.click(abrir);
171
+ expect(screen.getByRole("dialog")).toBeInTheDocument();
172
+ // O foco entra no cartão depois da montagem (um quadro de animação): na CI,
173
+ // mais lenta, o Esc chegava antes e caía no body.
174
+ await waitFor(() => expect(screen.getByRole("dialog").contains(document.activeElement)).toBe(true));
175
+ await usuario.keyboard("{Escape}");
176
+ await waitFor(() => expect(screen.queryByRole("dialog")).toBeNull());
177
+ expect(abrir).toHaveFocus();
178
+ });
179
+
180
+ it("reabrir recomeça do primeiro passo", async () => {
181
+ const usuario = userEvent.setup();
182
+ function Dono() {
183
+ const [aberto, setAberto] = useState(true);
184
+ return (
185
+ <div>
186
+ <button onClick={() => setAberto(true)}>Reabrir</button>
187
+ <Coachmark open={aberto} steps={PASSOS} onClose={() => setAberto(false)} />
188
+ </div>
189
+ );
190
+ }
191
+ render(<Dono />);
192
+ await usuario.keyboard("{ArrowRight}");
193
+ expect(screen.getByRole("dialog", { name: "Salvo sozinho" })).toBeInTheDocument();
194
+ await usuario.keyboard("{Escape}");
195
+ await usuario.click(screen.getByRole("button", { name: "Reabrir" }));
196
+ expect(screen.getByRole("dialog", { name: "Cada item é uma aba" })).toBeInTheDocument();
197
+ });
198
+ });
@@ -0,0 +1,101 @@
1
+ import { describe, expect, it, vi } from "vitest";
2
+ import { fireEvent, render, screen, waitFor } from "@testing-library/react";
3
+ import Coachmark from "../components/Coachmark/Coachmark";
4
+
5
+ const PASSOS = [{ target: "#alvo-a", title: "Novo: arrastar", content: "Arraste a linha para trocar a ordem." }];
6
+
7
+ function Pagina(props: any) {
8
+ return (
9
+ <div>
10
+ <button id="alvo-a">A</button>
11
+ <button id="fora">Fora</button>
12
+ <Coachmark steps={PASSOS} open {...props} />
13
+ </div>
14
+ );
15
+ }
16
+
17
+ describe("Coachmark · modal={false}", () => {
18
+ it("sem véu nem recorte; o cartão é um diálogo não modal e a raiz deixa o ponteiro passar", () => {
19
+ const { baseElement } = render(<Pagina modal={false} />);
20
+ expect(baseElement.querySelector(".umds-coachmark__veil")).toBeNull();
21
+ expect(baseElement.querySelector(".umds-coachmark__cutout")).toBeNull();
22
+ expect(baseElement.querySelector(".umds-coachmark")).toHaveClass("umds-coachmark--modeless");
23
+ expect(screen.getByRole("dialog", { name: "Novo: arrastar" })).toHaveAttribute("aria-modal", "false");
24
+ });
25
+
26
+ it("o padrão continua modal: véu, recorte e aria-modal verdadeiro", () => {
27
+ const { baseElement } = render(<Pagina />);
28
+ expect(baseElement.querySelector(".umds-coachmark__veil")).not.toBeNull();
29
+ expect(baseElement.querySelector(".umds-coachmark__cutout")).not.toBeNull();
30
+ expect(baseElement.querySelector(".umds-coachmark")).not.toHaveClass("umds-coachmark--modeless");
31
+ expect(screen.getByRole("dialog")).toHaveAttribute("aria-modal", "true");
32
+ const { unmount } = render(<Pagina modal />);
33
+ unmount();
34
+ });
35
+
36
+ it("o foco entra no cartão, mas o Tab não fica preso", async () => {
37
+ render(<Pagina modal={false} />);
38
+ const cartao = screen.getByRole("dialog");
39
+ await waitFor(() => expect(cartao).toHaveFocus());
40
+ const concluir = screen.getByRole("button", { name: "Concluir" });
41
+ concluir.focus();
42
+ const evento = new KeyboardEvent("keydown", { key: "Tab", bubbles: true, cancelable: true });
43
+ concluir.dispatchEvent(evento);
44
+ expect(evento.defaultPrevented).toBe(false);
45
+ });
46
+
47
+ it("no modal o Tab continua preso (o último volta ao primeiro)", () => {
48
+ render(<Pagina />);
49
+ const concluir = screen.getByRole("button", { name: "Concluir" });
50
+ concluir.focus();
51
+ const evento = new KeyboardEvent("keydown", { key: "Tab", bubbles: true, cancelable: true });
52
+ concluir.dispatchEvent(evento);
53
+ expect(evento.defaultPrevented).toBe(true);
54
+ });
55
+
56
+ it("a página segue clicável: o clique fora não é capturado e o tour não fecha sozinho", () => {
57
+ const aoFechar = vi.fn();
58
+ render(<Pagina modal={false} onClose={aoFechar} />);
59
+ fireEvent.click(screen.getByRole("button", { name: "Fora" }));
60
+ expect(aoFechar).not.toHaveBeenCalled();
61
+ expect(screen.getByRole("dialog")).toBeInTheDocument();
62
+ });
63
+
64
+ it("o Esc fecha de qualquer lugar da página, uma vez só", () => {
65
+ const aoFechar = vi.fn();
66
+ render(<Pagina modal={false} onClose={aoFechar} />);
67
+ const fora = screen.getByRole("button", { name: "Fora" });
68
+ fora.focus();
69
+ fireEvent.keyDown(fora, { key: "Escape" });
70
+ expect(aoFechar).toHaveBeenCalledTimes(1);
71
+ expect(aoFechar).toHaveBeenCalledWith("escape");
72
+ });
73
+
74
+ it("o Esc dentro do cartão também fecha uma vez só", async () => {
75
+ const aoFechar = vi.fn();
76
+ render(<Pagina modal={false} onClose={aoFechar} />);
77
+ await waitFor(() => expect(screen.getByRole("dialog")).toHaveFocus());
78
+ fireEvent.keyDown(screen.getByRole("dialog"), { key: "Escape" });
79
+ expect(aoFechar).toHaveBeenCalledTimes(1);
80
+ });
81
+
82
+ it("depois de fechar, o ouvinte do Esc sai do documento", () => {
83
+ const aoFechar = vi.fn();
84
+ const { rerender } = render(<Pagina modal={false} onClose={aoFechar} />);
85
+ rerender(<Pagina modal={false} open={false} onClose={aoFechar} />);
86
+ fireEvent.keyDown(document, { key: "Escape" });
87
+ expect(aoFechar).not.toHaveBeenCalled();
88
+ });
89
+
90
+ it("ao fechar, o foco volta ao elemento de antes, se a pessoa não foi a outro lugar", async () => {
91
+ const { rerender } = render(<Pagina modal={false} open={false} />);
92
+ const gatilho = screen.getByRole("button", { name: "Fora" });
93
+ gatilho.focus();
94
+ expect(gatilho).toHaveFocus();
95
+ rerender(<Pagina modal={false} open />);
96
+ // O foco entra no cartão depois da montagem (um quadro de animação).
97
+ await waitFor(() => expect(screen.getByRole("dialog")).toHaveFocus());
98
+ rerender(<Pagina modal={false} open={false} />);
99
+ await waitFor(() => expect(gatilho).toHaveFocus());
100
+ });
101
+ });
@@ -0,0 +1,153 @@
1
+ import { describe, expect, it, vi } from "vitest";
2
+ import { useState } from "react";
3
+ import { render, screen } from "@testing-library/react";
4
+ import userEvent from "@testing-library/user-event";
5
+ import ColorPicker from "../components/ColorPicker/ColorPicker";
6
+ import { COLOR_PALETTE } from "../utils/paleta-de-cores";
7
+
8
+ describe("ColorPicker", () => {
9
+ it("é um radiogroup com uma amostra por primitivo de cor, cada uma com nome", () => {
10
+ render(<ColorPicker ariaLabel="Cor do marcador" />);
11
+ const grupo = screen.getByRole("radiogroup", { name: "Cor do marcador" });
12
+ expect(grupo.querySelectorAll('[role="radio"]')).toHaveLength(COLOR_PALETTE.length);
13
+ expect(COLOR_PALETTE).toHaveLength(31);
14
+ expect(screen.getByRole("radio", { name: "Azul escuro" })).toBeInTheDocument();
15
+ expect(screen.getByRole("radio", { name: "Cinza muito claro" })).toBeInTheDocument();
16
+ });
17
+
18
+ it("pinta cada amostra com a variável do token", () => {
19
+ render(<ColorPicker ariaLabel="Cor" />);
20
+ const azul = screen.getByRole("radio", { name: "Azul" }) as HTMLElement;
21
+ expect(azul.style.backgroundColor).toBe("var(--umds-primitive-blue-pure)");
22
+ });
23
+
24
+ it("clicar escolhe e entrega o NOME do token em onChange", async () => {
25
+ const usuario = userEvent.setup();
26
+ const aoMudar = vi.fn();
27
+ render(<ColorPicker ariaLabel="Cor" onChange={aoMudar} />);
28
+ await usuario.click(screen.getByRole("radio", { name: "Verde" }));
29
+ expect(aoMudar).toHaveBeenCalledWith("--umds-primitive-green-pure");
30
+ expect(screen.getByRole("radio", { name: "Verde" })).toHaveAttribute("aria-checked", "true");
31
+ });
32
+
33
+ it("não escolhido tem aria-checked false e só a escolhida mostra a marcação", () => {
34
+ const { container } = render(<ColorPicker ariaLabel="Cor" defaultValue="--umds-primitive-red-pure" />);
35
+ expect(screen.getByRole("radio", { name: "Vermelho" })).toHaveAttribute("aria-checked", "true");
36
+ expect(screen.getByRole("radio", { name: "Azul" })).toHaveAttribute("aria-checked", "false");
37
+ expect(container.querySelectorAll(".umds-color-picker__swatch svg")).toHaveLength(1);
38
+ });
39
+
40
+ it("Tab entra na amostra escolhida (roving tabindex)", () => {
41
+ render(<ColorPicker ariaLabel="Cor" value="--umds-primitive-orange-pure" />);
42
+ const radios = screen.getAllByRole("radio");
43
+ const comTab = radios.filter((r) => r.getAttribute("tabindex") === "0");
44
+ expect(comTab).toHaveLength(1);
45
+ expect(comTab[0]).toHaveAccessibleName("Laranja");
46
+ });
47
+
48
+ it("sem valor, Tab entra na primeira amostra", () => {
49
+ render(<ColorPicker ariaLabel="Cor" />);
50
+ expect(screen.getAllByRole("radio")[0]).toHaveAttribute("tabindex", "0");
51
+ });
52
+
53
+ it("setas movem a escolha e o foco; Home e End vão às pontas; dá a volta", async () => {
54
+ const usuario = userEvent.setup();
55
+ const aoMudar = vi.fn();
56
+ render(<ColorPicker ariaLabel="Cor" families={["blue"]} defaultValue="--umds-primitive-blue-dark" onChange={aoMudar} />);
57
+ const radios = screen.getAllByRole("radio");
58
+ radios[0].focus();
59
+ await usuario.keyboard("{ArrowRight}");
60
+ expect(aoMudar).toHaveBeenLastCalledWith("--umds-primitive-blue-pure");
61
+ expect(radios[1]).toHaveFocus();
62
+ await usuario.keyboard("{ArrowLeft}{ArrowLeft}");
63
+ expect(aoMudar).toHaveBeenLastCalledWith("--umds-primitive-blue-light");
64
+ expect(radios[3]).toHaveFocus();
65
+ await usuario.keyboard("{Home}");
66
+ expect(radios[0]).toHaveFocus();
67
+ await usuario.keyboard("{End}");
68
+ expect(radios[3]).toHaveFocus();
69
+ await usuario.keyboard("{ArrowDown}");
70
+ expect(radios[0]).toHaveFocus();
71
+ });
72
+
73
+ it("pula amostra desabilitada no teclado", async () => {
74
+ const usuario = userEvent.setup();
75
+ const aoMudar = vi.fn();
76
+ render(
77
+ <ColorPicker
78
+ ariaLabel="Cor"
79
+ defaultValue="a"
80
+ onChange={aoMudar}
81
+ swatches={[
82
+ { value: "a", label: "A" },
83
+ { value: "b", label: "B", disabled: true },
84
+ { value: "c", label: "C" },
85
+ ]}
86
+ />,
87
+ );
88
+ screen.getByRole("radio", { name: "A" }).focus();
89
+ await usuario.keyboard("{ArrowRight}");
90
+ expect(aoMudar).toHaveBeenLastCalledWith("c");
91
+ });
92
+
93
+ it("families recorta a paleta", () => {
94
+ render(<ColorPicker ariaLabel="Cor" families={["blue", "gray"]} />);
95
+ expect(screen.getAllByRole("radio")).toHaveLength(11);
96
+ });
97
+
98
+ it("swatches substitui a paleta (nomes traduzidos)", () => {
99
+ render(<ColorPicker ariaLabel="Color" swatches={[{ value: "--umds-primitive-blue-pure", label: "Blue" }]} />);
100
+ expect(screen.getAllByRole("radio")).toHaveLength(1);
101
+ expect(screen.getByRole("radio", { name: "Blue" })).toBeInTheDocument();
102
+ });
103
+
104
+ it("disabled desabilita todas as amostras", () => {
105
+ render(<ColorPicker ariaLabel="Cor" disabled />);
106
+ for (const r of screen.getAllByRole("radio")) expect(r).toBeDisabled();
107
+ });
108
+
109
+ it("label visível nomeia o grupo", () => {
110
+ render(<ColorPicker label="Cor de fundo" id="cp" />);
111
+ expect(screen.getByRole("radiogroup", { name: "Cor de fundo" })).toBeInTheDocument();
112
+ });
113
+
114
+ it("cor livre vem desligada: sem campo de hexadecimal", () => {
115
+ render(<ColorPicker ariaLabel="Cor" />);
116
+ expect(screen.queryByLabelText(/hexadecimal/i)).toBeNull();
117
+ });
118
+
119
+ it("allowCustom: hexadecimal completo vira #RRGGBB em maiúsculas; incompleto não emite", async () => {
120
+ const usuario = userEvent.setup();
121
+ const aoMudar = vi.fn();
122
+ render(<ColorPicker ariaLabel="Cor" allowCustom onChange={aoMudar} />);
123
+ const campo = screen.getByLabelText("Cor livre (hexadecimal)");
124
+ await usuario.type(campo, "0058d");
125
+ expect(aoMudar).not.toHaveBeenCalled();
126
+ await usuario.type(campo, "b");
127
+ expect(aoMudar).toHaveBeenCalledTimes(1);
128
+ expect(aoMudar).toHaveBeenCalledWith("#0058DB");
129
+ });
130
+
131
+ it("allowCustom: hexadecimal inválido mostra a mensagem ao sair do campo", async () => {
132
+ const usuario = userEvent.setup();
133
+ render(<ColorPicker ariaLabel="Cor" allowCustom customErrorMessage="Formato inválido" />);
134
+ const campo = screen.getByLabelText("Cor livre (hexadecimal)");
135
+ await usuario.type(campo, "xyz");
136
+ expect(screen.queryByText("Formato inválido")).toBeNull();
137
+ await usuario.tab();
138
+ expect(screen.getByText("Formato inválido")).toBeInTheDocument();
139
+ });
140
+
141
+ it("controlado: reflete o value e escolher uma amostra limpa o campo livre", async () => {
142
+ const usuario = userEvent.setup();
143
+ function Controlado() {
144
+ const [valor, setValor] = useState("#336699");
145
+ return <ColorPicker ariaLabel="Cor" allowCustom value={valor} onChange={setValor} />;
146
+ }
147
+ render(<Controlado />);
148
+ const campo = screen.getByLabelText("Cor livre (hexadecimal)") as HTMLInputElement;
149
+ expect(campo.value).toBe("#336699");
150
+ await usuario.click(screen.getByRole("radio", { name: "Azul" }));
151
+ expect(campo.value).toBe("");
152
+ });
153
+ });
@@ -0,0 +1,22 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import { render, screen } from "@testing-library/react";
3
+ import ColorPicker from "../components/ColorPicker/ColorPicker";
4
+
5
+ describe("ColorPicker · size xs", () => {
6
+ it("xs escreve a classe do tamanho; sm e md seguem como eram", () => {
7
+ const { container, rerender } = render(<ColorPicker ariaLabel="Cor" size="xs" />);
8
+ const raiz = () => container.firstElementChild as HTMLElement;
9
+ expect(raiz()).toHaveClass("umds-color-picker--xs");
10
+ rerender(<ColorPicker ariaLabel="Cor" size="sm" />);
11
+ expect(raiz()).toHaveClass("umds-color-picker--sm");
12
+ expect(raiz()).not.toHaveClass("umds-color-picker--xs");
13
+ rerender(<ColorPicker ariaLabel="Cor" />);
14
+ expect(raiz()).toHaveClass("umds-color-picker--md");
15
+ });
16
+
17
+ it("no xs a amostra escolhida mantém a marcação e o aria-checked", () => {
18
+ const { container } = render(<ColorPicker ariaLabel="Cor" size="xs" defaultValue="--umds-primitive-red-pure" />);
19
+ expect(screen.getByRole("radio", { name: "Vermelho" })).toHaveAttribute("aria-checked", "true");
20
+ expect(container.querySelectorAll(".umds-color-picker__swatch--selected")).toHaveLength(1);
21
+ });
22
+ });