@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
package/CHANGELOG.md CHANGED
@@ -1,5 +1,1545 @@
1
1
  # @1doc/1ds-react
2
2
 
3
+ ## 2.10.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 12c65e9: feat(accordion): `titleVariant="neutral"`, o título de texto
8
+
9
+ `titleVariant` aceita `default` (o título como era) e `neutral`: 14px na cor do texto
10
+ (`neutral-dark-pure`), peso médio, também no hover e no aberto, sem cor de ação. O chevron
11
+ aberto continua azul (é o sinal do estado). Combina com qualquer `variant`.
12
+
13
+ ```vue
14
+ <Accordion :items="itens" variant="separated" titleVariant="neutral" />
15
+ ```
16
+
17
+ - 6df8835: feat(attachmentcard): `size="sm"`, o cartão compacto do CrisDoc
18
+
19
+ `size="sm"` leva o ícone do preview a 40px (no `md`, 48px) e o ícone do rodapé a
20
+ 12px (no `md`, o `sm` do `Icon`). A largura do cartão, os selos e o painel não
21
+ mudam. Sem `size`, ou com `md`, o cartão é o mesmo.
22
+
23
+ ```vue
24
+ <AttachmentCard
25
+ fileName="Protocolo 104-2026.pdf"
26
+ documentType="Parecer"
27
+ size="sm"
28
+ :onOpen="abrir"
29
+ />
30
+ ```
31
+
32
+ - 4ab330c: feat(badge): `attachedSide="left" | "right"` no `Badge attached`
33
+
34
+ O rótulo colado no topo do card pode ir para o canto direito. Sem a prop, ou com
35
+ `left`, continua no esquerdo. Só vale com `attached`.
36
+
37
+ ```vue
38
+ <Badge
39
+ :attached="true"
40
+ attachedSide="right"
41
+ size="sm"
42
+ appearance="solid"
43
+ variant="primary"
44
+ >Prazo hoje</Badge>
45
+ ```
46
+
47
+ - 1f805cd: feat(coachmark): `modal={false}`, o cartão sem véu nem foco preso, para dica pontual
48
+
49
+ Com `modal={false}` não há véu, recorte nem foco preso: o cartão é um popover
50
+ ancorado no alvo (`role="dialog"` com `aria-modal="false"`). A página segue
51
+ clicável, o foco entra no cartão ao abrir mas o Tab pode sair dele, e o Esc fecha de
52
+ qualquer lugar da página (uma vez só, com o motivo `escape`). Ao fechar, o foco só
53
+ volta ao elemento de antes se a pessoa não foi a outro lugar. Sem a prop, o tour é
54
+ modal como sempre (no Vue, `modal` é `any` para a ausência não virar `false`).
55
+
56
+ Corrige também o elemento de antes guardado duas vezes no React (o segundo
57
+ `sincronizar`, antes de o `active` valer, guardava o próprio cartão e o foco não voltava).
58
+
59
+ ```vue
60
+ <Coachmark
61
+ :open="aberto"
62
+ :modal="false"
63
+ :hideSkip="true"
64
+ finishLabel="Entendi"
65
+ :steps="[{ target: '#salvar', title: 'Novo: salvar com Ctrl+S' }]"
66
+ :onClose="() => (aberto = false)"
67
+ />
68
+ ```
69
+
70
+ - 46b3b42: feat(colorpicker): `size="xs"`, a amostra de 20px do CrisDoc
71
+
72
+ `size` ganha `xs` (20px), além de `sm` (24px) e `md` (32px). O anel de seleção (o anel duplo)
73
+ e o roving tabindex são os mesmos nos três tamanhos. O `sm` segue em 24px: o `xs` é o 20px do
74
+ CrisDoc.
75
+
76
+ ```vue
77
+ <ColorPicker
78
+ ariaLabel="Marcador"
79
+ size="xs"
80
+ :families="['blue', 'red']"
81
+ defaultValue="--umds-primitive-red-pure"
82
+ />
83
+ ```
84
+
85
+ - 82e85c5: feat(datatable): cabeçalho escuro, zebra, destaque de linha, vazio com ícone, `hideHeader` e linhas hierárquicas (`treeData`)
86
+
87
+ Tudo opt-in; sem as props novas a tabela é a mesma.
88
+
89
+ - `headerVariant="dark"`: cabeçalho navy com texto claro (`background-dark` e
90
+ `neutral-light-pure`, então o tema acompanha). `headerUppercase`: caixa alta
91
+ nos rótulos, vale para qualquer cabeçalho.
92
+ - `striped`: zebra nas linhas ímpares.
93
+ - `selectedRowKeys` (com `rowKey`) e `isRowSelected(row, index)`: destacam a linha
94
+ sem checkbox (fundo, barra de 4px à esquerda e `aria-selected`). Serve à linha
95
+ "aberta" de uma lista mestre-detalhe. `selectedKeys` segue sendo o checkbox.
96
+ - `emptyIcon` (objeto Font Awesome, padrão `faInbox`) e `emptyDescription`.
97
+ - `hideHeader`: o cabeçalho some da tela e as colunas continuam nomeadas para o
98
+ leitor de tela (a linha fica visualmente oculta, não removida).
99
+ - `density="compact"` + `variant="document"`: fonte de 12px e célula de 4px × 8px.
100
+ A escala do DS não tem 13px, então o compacto da tabela de interface segue em 14.
101
+ - `treeData` + `childrenKey`: linhas hierárquicas. A tabela vira `role="treegrid"`,
102
+ as linhas ganham `aria-level`, `aria-posinset`, `aria-setsize` e `aria-expanded`,
103
+ e a primeira coluna leva recuo por nível, fios (tee, cotovelo e linha contínua) e o
104
+ botão de expandir/recolher. Teclado: ↓ ↑ andam, → expande (ou desce à primeira
105
+ filha), ← recolhe (ou sobe ao pai), Home e End. Uma linha por vez na ordem de Tab.
106
+ Estado: `expandedKeys` (controlado), `defaultExpandedKeys`, `defaultExpandAll` e
107
+ `onExpand(chaves, linha, expandida)`. A chave é o `rowKey`; sem ele, o caminho de
108
+ índices. `expandLabel` e `collapseLabel` traduzem o botão. Com `treeData`, os índices
109
+ dos callbacks contam as linhas visíveis.
110
+
111
+ O slot `#cell-<key>` do Vue segue valendo na coluna da árvore (o `postbuild` agora
112
+ liga as duas ocorrências da célula).
113
+
114
+ ```vue
115
+ <DataTable
116
+ :columns="colunas"
117
+ :data="setores"
118
+ rowKey="id"
119
+ :treeData="true"
120
+ headerVariant="dark"
121
+ :headerUppercase="true"
122
+ :striped="true"
123
+ :defaultExpandedKeys="['gab']"
124
+ :onExpand="aoExpandir"
125
+ >
126
+ <template #cell-nome="{ row }"><strong>{{ row.sigla }}</strong> {{ row.nome }}</template>
127
+ </DataTable>
128
+ ```
129
+
130
+ - 1c9f7cb: feat(descriptionlist): `density="compact"`, a fonte de 12px do CrisDoc
131
+
132
+ `density="compact"` leva a fonte da lista de 14 para 12px (nos dois desenhos), aperta o
133
+ espaço entre os pares do `stacked` (de 16 para 12px) e o padding do valor com `bordered`.
134
+ Sem a prop, ou com `default`, a lista é a mesma.
135
+
136
+ ```vue
137
+ <DescriptionList
138
+ :items="dados"
139
+ layout="stacked"
140
+ :bordered="true"
141
+ density="compact"
142
+ />
143
+ ```
144
+
145
+ - d062029: feat(emptystate): título com conteúdo rico (elemento no React, slot `title` no Vue)
146
+
147
+ O `title` do `EmptyState` aceita conteúdo (negrito, link, ícone). No React é um
148
+ elemento na própria prop; no Vue é o slot `title`, com a prop como texto de reserva.
149
+ O título passa a ser um `div` (antes um `p`), com a mesma classe e o mesmo visual,
150
+ para o conteúdo de bloco não virar HTML inválido. `title` deixou de ser obrigatório
151
+ na tipagem: no Vue o slot basta.
152
+
153
+ ```vue
154
+ <EmptyState :icon="faMagnifyingGlass" description="Ajuste o filtro de setor.">
155
+ <template #title>Nenhum processo para <strong>SOBR</strong></template>
156
+ </EmptyState>
157
+ ```
158
+
159
+ - 29955dd: feat(input): `grouped`, o campo dentro de um contêiner que já tem moldura e foco (campo de chips)
160
+
161
+ Opt-in. `grouped` implica `borderless` e tira a altura de campo, o padding e o anel
162
+ de foco próprio do `Input`: a altura vem do conteúdo (a linha cresce com as tags), o
163
+ campo ocupa o espaço que sobra (`flex: 1 1 80px`, sem `fullWidth`) e quem mostra o foco é
164
+ o contêiner, com `:focus-within`. O `borderless` sozinho continua como era: com altura de
165
+ campo e o contorno de foco para dentro. Sem o foco no contêiner, quem usa teclado perde o
166
+ indicador (WCAG 2.4.7): a doc da prop avisa.
167
+
168
+ ```vue
169
+ <div class="chips-campo"> <!-- a moldura e o :focus-within são seus -->
170
+ <Tag label="SADM" size="sm" />
171
+ <Input ariaLabel="Adicionar setor" :grouped="true" size="sm" />
172
+ </div>
173
+ ```
174
+
175
+ - 76c0087: feat(listitem): `tooltip`, `standalone` e atributos HTML só no elemento interativo
176
+
177
+ - `tooltip`: vira o atributo HTML `title` do `button`, `a` ou `div` (a dica nativa do
178
+ navegador). `title` continua sendo o título da linha, não o atributo.
179
+ - `standalone`: renderiza sem o `li`, só o elemento interativo, para usar fora de um
180
+ `List` (botão de número de página, item de carrossel). `class` (Vue) ou `className`
181
+ vai ao elemento.
182
+ - Correção no Vue: `aria-*`, `role`, `data-*` e `style` iam ao `li` além do elemento
183
+ interativo (o `aria-label` aparecia duas vezes e o `li` ganhava um `role` que não era
184
+ dele). Agora o `inheritAttrs` está desligado e esses atributos vão só ao elemento
185
+ interativo, como no React. O `class` do Vue continua no `li`, como sempre. Por baixo,
186
+ o ListItem passa a ter duas raízes (com `li` e `standalone`), então o HTML do servidor
187
+ abre com marcador de fragmento.
188
+
189
+ ```vue
190
+ <ListItem
191
+ :standalone="true"
192
+ title="12"
193
+ tooltip="Página 12"
194
+ :selected="pagina === 12"
195
+ :onClick="irPara"
196
+ />
197
+ ```
198
+
199
+ - 3500910: feat(richtexteditor): alinhamento, imagem e tabela simples na `toolbar`
200
+
201
+ Opt-in: a barra padrão não muda. Entram na `toolbar` por nome:
202
+
203
+ - `alignLeft`, `alignCenter`, `alignRight`, `alignJustify`: botões de liga/desliga
204
+ que seguem o cursor (`aria-pressed`). O valor guarda `text-align` nos blocos.
205
+ - `image`: abre um painel (como o do link) com o endereço da imagem, o arquivo
206
+ (PNG, JPEG, GIF ou WebP até 2 MB, que entra como `data:` URL) e o texto
207
+ alternativo. Endereço e arquivo inválidos mostram o erro e o painel continua aberto.
208
+ - `table`: abre um painel com linhas e colunas (1 a 20 e 1 a 10, padrão 3 × 3) e
209
+ insere a tabela. Com o cursor numa célula aparece a barra de adicionar e remover
210
+ linha e coluna e remover a tabela (mexe no DOM, então fica fora do desfazer).
211
+
212
+ A higienização do valor passou a aceitar `text-align` nos blocos (também pelo
213
+ atributo `align`), `img` e a tabela (`table`, `thead`, `tbody`, `tr`, `th`, `td`
214
+ com `colspan` e `rowspan`). Imagem só vale com `http(s)`, caminho (`/x`, `./x`,
215
+ `../x`) ou `data:image` em base64 de PNG, JPEG, GIF e WebP; SVG, `javascript:`,
216
+ `//host` e o resto saem inteiros. Colar continua entrando como texto puro.
217
+
218
+ Todos os textos novos vêm por `labels` (`imageUrl`, `imageAlt`, `imageFile`,
219
+ `imageApply`, `imageCancel`, `imageInvalid`, `imageType`, `imageTooLarge`,
220
+ `tableRows`, `tableCols`, `tableApply`, `tableCancel`, `tableInvalid`,
221
+ `tableActions`, `tableAddRow`, `tableRemoveRow`, `tableAddCol`, `tableRemoveCol`,
222
+ `tableRemove` e o nome de cada ferramenta nova).
223
+
224
+ ```vue
225
+ <RichTextEditor
226
+ label="Parecer"
227
+ :defaultValue="html"
228
+ :toolbar="[
229
+ 'bold',
230
+ 'italic',
231
+ '|',
232
+ 'alignLeft',
233
+ 'alignCenter',
234
+ 'alignRight',
235
+ 'alignJustify',
236
+ '|',
237
+ 'link',
238
+ 'image',
239
+ 'table',
240
+ ]"
241
+ />
242
+ ```
243
+
244
+ - af0d976: feat(richtexteditor): família, tamanho de fonte e cor do texto, por token do DS
245
+
246
+ Opt-in na `toolbar`: `fontFamily`, `fontSize` e `textColor`. Cada um abre um painel abaixo da
247
+ barra e aplica ao texto selecionado, embrulhando-o num `<span style="...">`:
248
+
249
+ - `fontFamily`: padrão ou monoespaçada (`var(--umds-semantic-font-family-base|mono)`), num `Select`.
250
+ - `fontSize`: 12, 14, 16, 20 e 24px, os degraus da escala do DS (`var(--umds-primitive-font-size-*)`).
251
+ - `textColor`: a paleta do DS, num `ColorPicker` `xs`; o valor guarda o `var()` do token escolhido.
252
+
253
+ Sem texto selecionado o painel pede a seleção e não aplica nada. Esc fecha só a lista do `Select`
254
+ aberta; o seguinte fecha o painel. Para voltar ao padrão, use `clear`.
255
+
256
+ A higienização aceita `color`, `font-size` e `font-family` só em `<span>` e só com token do DS: cor
257
+ em hex, `rgb()` ou nome, tamanho em px e fonte por nome saem, e o resto do `style` também.
258
+
259
+ Textos novos por `labels`: `fontFamily`, `fontSize`, `textColor`, `fontFamilyBase`,
260
+ `fontFamilyMono`, `styleClose` e `styleNeedsSelection`.
261
+
262
+ ```vue
263
+ <RichTextEditor
264
+ label="Parecer"
265
+ :toolbar="['bold', 'italic', '|', 'fontFamily', 'fontSize', 'textColor']"
266
+ />
267
+ ```
268
+
269
+ - 992f59a: feat(segmentedcontrol): `count` por item, a pílula do contador como a do `Tab`
270
+
271
+ Cada opção aceita `count` (número ou texto): uma pílula de 18px depois do rótulo,
272
+ cinza no segmento solto e branca sobre o azul do escolhido (o mesmo desenho do
273
+ contador do `Tab`). `0` aparece; vazio e ausente não. O contador entra no nome
274
+ acessível do segmento ("Todas 31"). Sem `count`, o segmento é o mesmo.
275
+
276
+ ```vue
277
+ <SegmentedControl
278
+ label="Fila"
279
+ :value="fila"
280
+ :onChange="(v) => (fila = v)"
281
+ :options="[
282
+ { label: 'Todas', value: 'todas', count: 31 },
283
+ { label: 'Minhas', value: 'minhas', count: 12 },
284
+ ]"
285
+ />
286
+ ```
287
+
288
+ - 22a79d8: feat(select): `open`/`onOpenChange`, gatilho com ícone e amostra de cor, variantes `search` e `combo`, lista por cima de diálogo e `placement="auto"` que mede o ancestral
289
+
290
+ Tudo opt-in; o Select sem as props novas se comporta como antes, fora de diálogo.
291
+
292
+ - `open` e `onOpenChange(open)`: a lista controlada de fora. O clique, o teclado,
293
+ o clique fora, o Esc e a escolha de uma opção avisam o pai, que decide o novo
294
+ `open`. Sem `open`, o Select abre e fecha sozinho e também avisa. É o que deixa o
295
+ filtro com ação no rodapé fechar a lista antes de abrir um modal.
296
+ - `triggerIcon` (objeto Font Awesome) e `triggerSwatch` (um token de cor): ícone e
297
+ amostra de cor à esquerda do texto do gatilho, decorativos.
298
+ - `variant="search"` (o filtro numa barra de busca: altura de campo e contorno neutro)
299
+ e `variant="combo"` (colado a outro controle, sem borda nem raio próprios). Os dois
300
+ são filtro: busca focada ao abrir, `emptyOptionLabel` e o rodapé valem.
301
+ - Dentro de um diálogo (`role="dialog"` ou `aria-modal`), a lista abre por cima dele:
302
+ `position: fixed` ancorada no gatilho pelo `@floating-ui/dom`, com a largura do
303
+ gatilho e a altura limitada ao espaço da janela. O `overflow` do corpo do modal
304
+ não corta mais a lista.
305
+ - `placement="auto"` agora mede também cada ancestral que rola ou corta (um corpo de
306
+ modal, um painel com `overflow`), não só a janela, e limita a altura da lista ao
307
+ espaço que sobra (mínimo de 96px).
308
+ - `required` repassa `aria-required` ao combobox.
309
+
310
+ ```vue
311
+ <Select
312
+ variant="filter"
313
+ ariaLabel="Marcadores"
314
+ placeholder="Marcadores"
315
+ :triggerIcon="faTag"
316
+ :open="aberto"
317
+ :onOpenChange="(v) => (aberto = v)"
318
+ :options="marcadores"
319
+ :value="valor"
320
+ :onChange="(v) => (valor = v)"
321
+ >
322
+ <template #footer>
323
+ <Button variant="text" size="sm" @click="abrirGerenciador">Gerenciar marcadores</Button>
324
+ </template>
325
+ </Select>
326
+ ```
327
+
328
+ - f7fa5dd: feat(select): o filtro no tamanho do CrisDoc, com cor por opção (`option.color`)
329
+
330
+ Para substituir o `FiltroSelect` do app:
331
+
332
+ - As variantes de filtro (`filter`, `search`, `combo`) nascem no tamanho `sm` (32px, fonte de
333
+ 12px) quando `size` não é passado; `size="md"` continua valendo. O `Select` padrão não muda.
334
+ - O gatilho do `filter` tem fundo branco com contorno azul. O azul-claro só vem depois de
335
+ escolhido um valor (a classe `umds-select--has-value`), que é quando o filtro está
336
+ recortando a lista. `search` e `combo` mantêm o fundo deles.
337
+ - `option.color` (um token, `var(--umds-semantic-color-...)`): uma amostra de 12px antes do
338
+ texto de cada opção na lista e, com a opção escolhida (seleção única), no gatilho.
339
+ `triggerSwatch` explícito manda sobre ela. A cor é decorativa: o nome da opção continua
340
+ sendo o texto.
341
+ - O `useStore` do `Select` passou a checar o gatilho antes do `autoUpdate` (o `tsc` do React
342
+ acusava o `null`).
343
+
344
+ ```vue
345
+ <Select
346
+ variant="filter"
347
+ ariaLabel="Marcadores"
348
+ placeholder="Marcadores"
349
+ :triggerIcon="faFilter"
350
+ :options="[
351
+ {
352
+ label: 'Urgente',
353
+ value: 'urgente',
354
+ color: 'var(--umds-semantic-color-feedback-negative-pure)',
355
+ },
356
+ ]"
357
+ />
358
+ ```
359
+
360
+ - b9f0813: feat(statcard): segunda medida (`secondaryValue`/`secondaryLabel`) e `valueTone`
361
+
362
+ - `secondaryValue` e `secondaryLabel`: a segunda medida do cartão, menor (20px), à direita da
363
+ principal, separada por um filete ("22,31% Meu Setor | 14,11% Geral"). No HTML vem depois do
364
+ resto, então o leitor de tela lê a medida principal inteira antes. `0` aparece; vazio e
365
+ ausente não. Com `labelPosition="top"` a grade ganha uma terceira coluna.
366
+ - `valueTone`: cor do número principal, `default` | `primary` | `positive` | `negative` |
367
+ `info`, pelas variantes escuras (contraste AA no branco). Não mexe na `variant`, que segue
368
+ pintando o ícone e a variação.
369
+
370
+ ```vue
371
+ <StatCard
372
+ labelPosition="top"
373
+ label="Eficiência"
374
+ value="22,31%"
375
+ description="Meu Setor"
376
+ secondaryValue="14,11%"
377
+ secondaryLabel="Geral"
378
+ valueTone="primary"
379
+ />
380
+ ```
381
+
382
+ - a4b6bb7: feat(toast): ação (`actionLabel`/`onAction`) e lista de detalhes (`details`)
383
+
384
+ - `actionLabel` + `onAction`: um botão depois do texto ("Desfazer", "Ver processo").
385
+ Acionar chama `onAction` e depois fecha o toast (`onClose`). O botão só aparece com os
386
+ dois. O botão de fechar continua ao lado.
387
+ - `details`: lista de linhas curtas abaixo da descrição ("Anexo 1 acima de 10 MB").
388
+ - No `toast()` imperativo e no `ToastStack`, as três opções passam adiante. Toast com ação
389
+ tem `duration: 0` por padrão (não some antes de dar tempo de agir, WCAG 2.2.1); sem ação
390
+ continua em 5000, e um `duration` explícito vale sempre.
391
+
392
+ ```ts
393
+ toast({
394
+ message: "Despacho enviado",
395
+ variant: "positive",
396
+ actionLabel: "Desfazer",
397
+ onAction: desfazer,
398
+ });
399
+ ```
400
+
401
+ ### Patch Changes
402
+
403
+ - 6c12a37: fix(appsubheader): a região do contexto ocupa a altura da barra e só rola na horizontal
404
+
405
+ Com a trilha só na página atual (um `Breadcrumb` sem link), o axe acusava
406
+ `scrollable-region-focusable`. Medido no navegador: a região do contexto tinha 12px de
407
+ altura (a do item do Breadcrumb, `line-height: 1` em 12px) e `scrollHeight` de 14, e como
408
+ `overflow-x: auto` faz o `overflow-y` computar para `auto`, ela virava uma região rolável
409
+ sem nenhum elemento focável dentro. Agora a região ocupa a altura da barra
410
+ (`align-self: stretch`, 41px, com o conteúdo centralizado) e corta o eixo vertical
411
+ (`overflow-y: hidden`): não há o que rolar na vertical. A rolagem horizontal da trilha longa
412
+ continua igual. Story nova "Só a página atual" confere `scrollHeight` e `scrollWidth`.
413
+
414
+ - e8f1894: fix(attachmentcard): o `dl` do painel de conferência passa no axe (`definition-list`)
415
+
416
+ Cada campo do painel era `div > (div > dt + dd) + button`: o `dl` só aceita `div` com `dt` e
417
+ `dd` direto dentro, então o axe acusava `definition-list`. Agora é `div > dt + dd`, e o
418
+ botão de copiar mora dentro do `dd`, ao lado do valor (o valor passou a ter o próprio
419
+ `span`, `umds-attachment-card__campo-valor-texto`). O visual muda só no detalhe: o botão
420
+ de copiar fica alinhado à linha do valor, não ao centro das duas linhas do campo.
421
+
422
+ - 04d5a43: fix(badge): o neutro colado é o cinza claro com texto escuro
423
+
424
+ `<Badge attached variant="neutral" appearance="solid">` ficava no cinza escuro do `solid`
425
+ neutro, pesado demais para o rótulo de um card. Agora o neutro colado e sólido é o cinza claro
426
+ com texto escuro (o "Tarefa manual" do CrisDoc). O `solid` neutro fora do `attached` não muda.
427
+
428
+ - e5896d9: docs(calendar): os slots do cabeçalho no Vue são `#header-start` e `#header-end`
429
+
430
+ O `index.d.ts` e a documentação diziam `headerStart` e `headerEnd` para os dois
431
+ frameworks, mas no Vue só os nomes com hífen chegam ao cabeçalho (o Vue lê o nome do
432
+ slot como está: `#headerStart` é descartado em silêncio). A doc do componente, o
433
+ comentário das props e os `argTypes` dos Storybooks agora dizem: no React, as props
434
+ `headerStart` e `headerEnd` (um nó); no Vue, os slots `#header-start` e `#header-end`.
435
+ Sem mudança de comportamento.
436
+
437
+ ## 2.9.0
438
+
439
+ ### Minor Changes
440
+
441
+ - 704af0c: feat(accordion): conteúdo livre por item no Vue (slot `content-<id>`)
442
+
443
+ No React o `content` do item já aceitava qualquer nó. No Vue ele era interpolado
444
+ como texto, então o painel só aceitava string. Agora, no Vue, cada item pode ter
445
+ um slot com o próprio conteúdo.
446
+
447
+ - `#content-<id>`: slot com escopo por item (`<id>` é o `id` do item), que recebe
448
+ `{ item }` e vale sobre o `content` de texto daquele item. Itens sem slot
449
+ continuam mostrando o texto. O `postbuild` liga o slot ao `Accordion.vue`
450
+ gerado, como já faz com o `DataTable`, e falha o build se o gerado mudar de
451
+ forma.
452
+ - Título: o título do item **já é neutro** no 1DS (14/600, `neutral-dark-pure`;
453
+ só o chevron fica azul quando abre), então não há opção de cor a acrescentar.
454
+ Se o CrisDoc mediu azul de 16px, era outra peça ou uma versão antiga.
455
+
456
+ ```vue
457
+ <Accordion :items="[{ id: 'campos', title: 'Seção 01', content: '' }]">
458
+ <template #content-campos>
459
+ <Input label="Nome" fullWidth />
460
+ </template>
461
+ </Accordion>
462
+ ```
463
+
464
+ - 3d9472d: feat(attachmentcard): `status="ai"`, painel livre (`panel`), `panelWidth` e `closePanelOnAction`
465
+
466
+ Opt-in; sem as props novas o cartão é o mesmo.
467
+
468
+ - `status="ai"`: selo de recurso de IA, no roxo da IA (`ai-light` / `ai-dark`, os
469
+ mesmos tokens do `AILabel`), com a varinha como ícone padrão (`statusIcon`
470
+ continua mandando). O ícone do painel também é a varinha.
471
+ - `panel`: conteúdo livre do painel do selo, no lugar do resultado da conferência
472
+ (ações, campos, texto). React: o elemento; Vue: o slot `panel`. Com ele o selo
473
+ vira botão mesmo sem `statusDetails`. Sem título interno, o painel é nomeado
474
+ pelo selo (o mesmo nome que o botão tem, "Recursos IA: conferência de ...").
475
+ - `panelWidth` (px): largura do painel; padrão 300.
476
+ - `closePanelOnAction`: ao acionar um botão ou link de dentro do painel (o
477
+ "Aplicar sugestão"), o painel fecha e o foco volta ao selo. A ação do app roda
478
+ antes. O botão de copiar um campo não conta. Sem a prop, o painel fica aberto
479
+ até Esc, clique fora ou o foco sair.
480
+
481
+ Por baixo, o `postbuild` ganhou `slotsNoScriptVue`: o Vue que recebe só o slot
482
+ enxergava `props.panel` como `undefined` no script e o selo não virava botão. O
483
+ gancho troca `props.<prop>` por `(props.<prop> || slots['<slot>'])` nos arquivos
484
+ listados e falha o build se o gerado não tiver o formato esperado.
485
+
486
+ ```vue
487
+ <AttachmentCard
488
+ fileName="Protocolo 104-2026.pdf"
489
+ status="ai"
490
+ statusLabel="Recursos IA"
491
+ :panelWidth="280"
492
+ :closePanelOnAction="true"
493
+ >
494
+ <template #panel>
495
+ <Text>A IA sugere "Recurso Administrativo".</Text>
496
+ <Button size="sm" @click="aplicar">Aplicar sugestão</Button>
497
+ </template>
498
+ </AttachmentCard>
499
+ ```
500
+
501
+ - 2c0dafb: feat(avatargroup): `overlap`, `ring` e `overflowCount`
502
+
503
+ Opt-in; sem as props novas o grupo é o mesmo.
504
+
505
+ - `overflowCount`: quantas pessoas existem além das de `avatars`. O "+N" deixa de
506
+ exigir N itens-fantasma: com 16 responsáveis, passe os 4 primeiros e
507
+ `overflowCount={12}`. Soma com o que passar de `max` dentro de `avatars`, e os
508
+ textos traduzíveis (`overflowTitle`, `overflowAriaLabel`) recebem o total.
509
+ - `overlap` (px): quanto cada avatar avança sobre o anterior. O padrão segue 8
510
+ (`spacing-nano`); 6 é o do CrisDoc e corta menos as iniciais. O recuo do
511
+ último item acompanha.
512
+ - `ring` (px): largura do anel (a borda da cor do fundo). O padrão segue 1,5; 1 é
513
+ o do CrisDoc.
514
+
515
+ As duas últimas escrevem `--umds-avatar-group-overlap` e `--umds-avatar-group-ring`
516
+ no próprio grupo (os padrões vivem no CSS), então só aparece `style` quando você
517
+ as usa.
518
+
519
+ ```vue
520
+ <AvatarGroup
521
+ :avatars="primeiros4"
522
+ :max="4"
523
+ :overlap="6"
524
+ :ring="1"
525
+ :overflowCount="12"
526
+ />
527
+ ```
528
+
529
+ - 8ff3652: feat(badge, tag): tamanhos compactos, `Tag soft` e `pill`, variante `new` e `Badge attached`
530
+
531
+ Tudo opt-in: sem as props novas, o HTML e o visual são os mesmos.
532
+
533
+ **Badge**
534
+
535
+ - `size="2xs"`: 16px de altura, fonte de 10px, raio 4. A fonte de 10px não está
536
+ na escala do DS (o menor degrau é 12px), então é um literal comentado no CSS;
537
+ se o mínimo de 12px for decisão de acessibilidade, o 2xs é o que sai.
538
+ - `variant="new"` (a "novidade" do CrisDoc): amarelo, caixa alta, 800, pílula.
539
+ Solid e soft usam o fundo amarelo; outlined, o contorno. O DS não tem token
540
+ semântico de amarelo, então usa os primitivos `yellow-*` (com o `yellow-light`
541
+ já corrigido) e `gray-darkest` para o texto, que não mudam com o tema
542
+ (contraste 8:1). Candidato a token semântico de destaque.
543
+ - `attached`: rótulo colado no canto superior esquerdo de um card, com os cantos
544
+ de baixo arredondados e os de cima retos. Posiciona em `absolute`: o pai
545
+ precisa de `position: relative`.
546
+
547
+ **Tag**
548
+
549
+ - `size="xs"`: 18px (`line-height: 1`, padding 2 e 8, fonte 12, ícone 12). Foi
550
+ criado um tamanho novo em vez de mexer no `sm` (27px), para não encolher quem
551
+ já usa `sm`. O × e o ícone clicável mantêm o alvo de 24px com margem negativa.
552
+ - `appearance="soft"`: fundo claro da cor da variante, sem contorno.
553
+ - `pill`: cantos totalmente arredondados, em qualquer aparência e tamanho.
554
+ - `variant="new"`: amarelo, nas três aparências (soft = `yellow-light` com texto
555
+ `yellow-dark`).
556
+
557
+ ```vue
558
+ <Badge size="2xs" appearance="solid">SOBR</Badge>
559
+ <Badge variant="new" size="xs">Novidade</Badge>
560
+ <div
561
+ style="position: relative"
562
+ ><Badge attached variant="info" appearance="solid">Tarefa pendente</Badge></div>
563
+ <Tag size="xs" appearance="soft" variant="primary" pill label="SEFIN" />
564
+ <Tag size="xs" appearance="soft" variant="new" pill label="Dado simulado" />
565
+ ```
566
+
567
+ - dd0e159: feat(box): item flex (`grow`, `shrink`, `basis`...) e prop `as`
568
+
569
+ O `Box` ganha as props de item flex do `Stack` e a troca de elemento, com os
570
+ mesmos nomes e valores. Sem as props novas, o HTML e as classes são os mesmos.
571
+
572
+ - `as`: `div` (padrão), `span`, `ul`, `ol`, `li`, `section`, `nav`, `header`,
573
+ `footer`, `form`. `ul` e `ol` saem sem marcador, margem e recuo (o padding do
574
+ Box continua valendo) e com `role="list"`. Com `as="form"`, `onSubmit` recebe
575
+ o evento. Uma linha com borda e fundo dentro de uma lista é `<Box as="li">`.
576
+ - Item flex: `grow`, `shrink` (`"0"` | `"1"`), `basis` (`"auto"`, `"0"`, `"25"`,
577
+ `"33"`, `"50"`, `"66"`, `"75"`, `"100"`; os números são %), `minWidth` (`"0"`
578
+ | `"auto"`; o Box já nasce com `min-width: 0`), `overflow`, `overflowX`,
579
+ `overflowY` e `fullHeight` (o `fullWidth` já existia).
580
+
581
+ Vue: com `as`, o Box passa a ter raiz múltipla, e o Vue não repassa atributos
582
+ de fallthrough a esse tipo de componente. Por isso `class` entra no mesmo
583
+ repasse de `style`, `title`, `role`, `data-*` e `aria-*` (o `Stack` também). Ouvintes
584
+ (`@click`) não caem mais no raiz: ponha-os num filho.
585
+
586
+ ```tsx
587
+ <Box direction="horizontal" gap="xxxs" padding="md">
588
+ <Box shrink="0" basis="25">Filtros</Box>
589
+ <Box grow overflowY="auto" fullHeight>Resultados</Box>
590
+ </Box>
591
+ <Box as="ul" aria-label="Setores"><Box as="li" bordered padding="xxxs">SADM</Box></Box>
592
+ ```
593
+
594
+ - a6872d9: feat(box): `direction`, `gap`, `align`, `justify` e `wrap` (a caixa também é layout)
595
+
596
+ Uma linha, cartão ou região com borda, fundo e padding passa a ser UM componente,
597
+ sem `Stack` por dentro nem flex no CSS do produto. As cinco props têm os mesmos
598
+ nomes e valores do `Stack`; qualquer uma delas liga o `display: flex`. Sem
599
+ nenhuma, o `Box` segue sendo um bloco comum (API antiga intacta).
600
+
601
+ - `direction`: `"vertical"` (padrão quando o flex está ligado) | `"horizontal"`.
602
+ - `gap`: degraus da escala, mais `"none"`. Diferente do `Stack`, não tem valor
603
+ padrão: sem `gap` os filhos ficam colados.
604
+ - `align`, `justify`, `wrap`: como no `Stack`.
605
+ - Também passam a ir para o elemento raiz: `id`, `style`, `title`, `role`,
606
+ `tabIndex`, `data-*` e `aria-*` (uma região pede `role` e `aria-label`).
607
+
608
+ ```tsx
609
+ <Box
610
+ direction="horizontal"
611
+ gap="xxxs"
612
+ align="center"
613
+ justify="between"
614
+ padding="xs"
615
+ background="surface"
616
+ radius="sm"
617
+ bordered
618
+ >
619
+ <Text variant="body2">
620
+ Reforma da cobertura do Ginásio Poliesportivo Municipal
621
+ </Text>
622
+ <Button variant="secondary" size="sm">
623
+ Abrir
624
+ </Button>
625
+ </Box>
626
+ ```
627
+
628
+ Para o elemento semântico (`ul`, `nav`, `section`), continue usando `Stack` com `as`.
629
+
630
+ - d466e57: feat(button): variante `neutral-text` e tamanho `xs`
631
+
632
+ Para barra de ações (editor, filtros, linha de card), onde nenhum botão é a
633
+ ação principal e o azul atrapalha. Sem as props novas, nada muda.
634
+
635
+ - `variant="neutral-text"`: texto cinza (`neutral-dark-down`), sem borda e sem
636
+ fundo; hover em `neutral-light-medium`. O `neutral` continua sendo o
637
+ contornado cinza, então "neutro" cobre os dois: contornado (`neutral`) e
638
+ texto (`neutral-text`). O nome segue o par `negative` / `negative-outlined`.
639
+ - `size="xs"`: 26px de altura, padding lateral 12, fonte 12 e ícone de 12px
640
+ (também no `variant="icon"`, que fica 26 x 26). Os 26px do CrisDoc não estão
641
+ na escala de espaço, então a altura é `calc(spacing-xxs + spacing-micro)`
642
+ (24 + 2), sem token novo.
643
+
644
+ ```vue
645
+ <Button
646
+ variant="neutral-text"
647
+ size="xs"
648
+ :start-icon="faPlus"
649
+ >Nova linha</Button>
650
+ <Button variant="neutral" size="xs">Ordenar: mais recentes</Button>
651
+ <Button size="xs">Resolver</Button>
652
+ ```
653
+
654
+ - d278363: feat(calendar): novo `Calendar`, a agenda com eventos por dia
655
+
656
+ Peça nova: visão de mês e de semana, com eventos por dia, sem biblioteca de
657
+ datas (o `Intl` escreve os nomes de mês e de dia).
658
+
659
+ - `events`: lista plana `{ date, title, color?, time?, id? }`. `date` é
660
+ `YYYY-MM-DD`, data-hora ISO ou `Date`. A grade agrupa por dia e ordena por
661
+ `time`.
662
+ - Cor de DADO por token: `color="--umds-primitive-blue-pure"` (o mesmo valor do
663
+ `ColorPicker`), num chip de fundo suave (a cor a 16% sobre o branco) com barra
664
+ do lado. O texto é sempre escuro: a cor nunca é a única informação e o contraste
665
+ não depende do tom. Sem `color`, o primário.
666
+ - Mês: até `maxVisible` (3) eventos por dia e um "+N" (`onMoreClick(dia,
667
+ escondidos)`). O corte é por QUANTIDADE, não por altura. Semana: sete colunas
668
+ com todos os eventos.
669
+ - Grade acessível (`role="grid"`): um Tab entra no dia em foco (hoje, ou o
670
+ primeiro) e depois nos eventos dele; setas movem de dia (e trocam de mês ou de
671
+ semana na borda), Home e End vão às pontas da semana, PageUp e PageDown trocam
672
+ de mês (ou de semana), Enter e Espaço acionam `onDayClick`. Cada dia tem nome
673
+ ("segunda-feira, 11 de maio de 2026, 2 eventos", `dayLabel` troca) e o de hoje
674
+ leva `aria-current="date"`.
675
+ - `date` e `view` controláveis (`onDateChange`, `onViewChange`) ou internos
676
+ (`defaultDate`, `defaultView`); `selectedDate` marca um dia; `today` fixa o
677
+ "hoje" (testes, demonstração); `weekStartsOn` 0 (domingo) ou 1.
678
+ - Cabeçalho com anterior, próximo, "Hoje" e o seletor Mês/Semana
679
+ (`hideViewSwitcher` esconde), mais dois slots: `headerStart` (filtro de escopo)
680
+ e `headerEnd` (legenda). No Vue são `#header-start` e `#header-end`.
681
+ - Textos por prop: `previousLabel`, `nextLabel`, `todayLabel`, `monthLabel`,
682
+ `weekLabel`, `viewLabel`, `moreLabel` (`{count}`), `moreAriaLabel` (`{count}` e
683
+ `{date}`); `locale` (padrão `pt-BR`).
684
+
685
+ Não faz: eixo de horas (é agenda por dia, não por hora), evento que atravessa
686
+ vários dias e arrastar para reagendar.
687
+
688
+ ```vue
689
+ <Calendar
690
+ :events="[
691
+ {
692
+ date: '2026-05-04',
693
+ title: 'Proc. Administrativo 002/2020',
694
+ color: '--umds-primitive-blue-pure',
695
+ },
696
+ {
697
+ date: '2026-05-11',
698
+ title: 'Ofício 001/2020',
699
+ color: '--umds-primitive-red-pure',
700
+ time: '08:00',
701
+ },
702
+ ]"
703
+ :onEventClick="abrir"
704
+ >
705
+ <template #header-start><Select … /></template>
706
+ <template #header-end><Button variant="secondary" size="sm">Legenda</Button></template>
707
+ </Calendar>
708
+ ```
709
+
710
+ - 33719b6: feat(chips): `size="xs"` e × com moldura circular (`circularRemove`)
711
+
712
+ Opt-in; sem as props novas o `Chips` é o mesmo.
713
+
714
+ - `size="xs"`: 20px de altura, padding lateral 8, fonte de 12px e × de 8px. A
715
+ altura é `calc(spacing-xxxs + spacing-quarck)` (16 + 4), sem token novo. O
716
+ CrisDoc usa fonte de 11px, que não está na escala do DS; fica o degrau de 12px.
717
+ - `circularRemove`: o × dos chips removíveis vai dentro de um círculo de 14px
718
+ tingido da cor do texto do chip (o `::before` usa `currentColor` com 15% de
719
+ opacidade, então acompanha todas as variantes e os temas). É o mesmo botão,
720
+ com o mesmo nome acessível ("Remover <rótulo>") e o mesmo clique; só vale com
721
+ `removable`.
722
+
723
+ ```vue
724
+ <Chips
725
+ label="Processos Inteligentes"
726
+ size="xs"
727
+ variant="primary"
728
+ removable
729
+ circularRemove
730
+ :onRemove="remover"
731
+ />
732
+ ```
733
+
734
+ - 80904af: feat(coachmark): novo `Coachmark`, o tour guiado
735
+
736
+ Peça nova: uma sequência de passos, cada um apontando um elemento da tela com
737
+ um cartão, enquanto o resto da página escurece e o alvo fica destacado num
738
+ recorte (uma caixa transparente cuja sombra escurece o resto, sem máscara nem
739
+ SVG).
740
+
741
+ - `steps`: `{ target?, title, content?, placement? }`. `target` é um seletor CSS
742
+ (`"#aba-fluxos"`), um elemento, uma ref do React (`{ current }`), uma ref do Vue
743
+ (`{ value }`) ou uma função que devolve um deles. Sem alvo (ou alvo que não
744
+ existe), o cartão fica no centro e a página inteira escurece.
745
+ - Posição por `@floating-ui/dom` (já era dependência): `placement` com inversão
746
+ automática, e o recorte e o cartão acompanham rolagem, redimensionamento e
747
+ mudança de tamanho do alvo. O alvo é trazido à tela se estiver fora dela.
748
+ - Controlado por `open`; `onClose(motivo)` com `"finish"` (Concluir no último
749
+ passo), `"skip"` (Sair do tour) ou `"escape"` (Esc). Passo atual interno
750
+ (`defaultStep`) ou controlado (`step` + `onStepChange`). Reabrir recomeça do
751
+ primeiro passo.
752
+ - Acessibilidade: cartão `role="dialog"` com `aria-modal`, nomeado pelo título e
753
+ descrito pelo texto. O foco entra no cartão, o Tab fica preso nele, Esc sai,
754
+ setas esquerda e direita voltam e avançam, e o foco volta ao elemento de antes
755
+ ao fechar. A cada passo o leitor de tela ouve "2 de 8: título" (`aria-live`).
756
+ - Textos por prop: `nextLabel`, `previousLabel`, `finishLabel`, `skipLabel`,
757
+ `counterLabel` ("{current} de {total}"). `hideSkip` esconde o Sair do tour.
758
+ - `padding` (px) é a folga do recorte em torno do alvo (padrão 8).
759
+
760
+ Limite: a página atrás fica inerte durante o tour (o véu captura o clique), então
761
+ o alvo não é clicável. O scrim usa o mesmo `rgba` do Modal, que ainda não tem
762
+ token (candidato a novo token).
763
+
764
+ ```vue
765
+ <Coachmark
766
+ :open="tourAberto"
767
+ :steps="[
768
+ {
769
+ target: '#aba-fluxos',
770
+ title: 'Cada item aberto é uma aba',
771
+ content: 'Fluxos e formulários abrem em abas.',
772
+ },
773
+ { title: 'Pronto', content: 'Sem alvo: o cartão fica no centro.' },
774
+ ]"
775
+ :onClose="() => (tourAberto = false)"
776
+ />
777
+ ```
778
+
779
+ - 390c707: feat(colorpicker): novo `ColorPicker`, as amostras da paleta do 1DS
780
+
781
+ Peça nova. Uma grade de amostras dos primitivos de cor (6 famílias de 4 tons e os
782
+ 7 cinzas, 31 no total), uma linha por família. O valor é o NOME DO TOKEN
783
+ (`--umds-primitive-blue-pure`): guarde o nome e pinte com `var(${valor})`. Como
784
+ primitivo não muda com o tema, a cor escolhida é a mesma no claro e no escuro, o
785
+ que é o certo para cor de dado (marcador, tipo de documento, setor).
786
+
787
+ - `radiogroup`: Tab entra na amostra escolhida (ou na primeira), setas movem a
788
+ escolha, Home e End vão às pontas, amostra desabilitada é pulada. Cada amostra
789
+ tem nome acessível ("Azul escuro") e a escolhida ganha ícone de marcação e anel
790
+ duplo, então a seleção não depende só da cor.
791
+ - `value` / `defaultValue` / `onChange(valor)`; `label` ou `ariaLabel`.
792
+ - `allowCustom` (desligado por padrão): campo de cor livre em hexadecimal
793
+ `#RRGGBB`, que sai em maiúsculas. Textos por prop: `customLabel` e
794
+ `customErrorMessage`.
795
+ - `families` recorta a paleta (`["blue", "gray"]`); `swatches` troca a lista
796
+ inteira (nomes traduzidos, recorte livre). `COLOR_PALETTE` e `isHexColor` saem
797
+ exportados.
798
+ - `size` `sm` (24px) ou `md` (32px, padrão); raio 8px, anel de 1px na amostra.
799
+
800
+ Requer `@1doc/1ds-tokens` com `yellow-light` e `purple-pure` corrigidos (ver o
801
+ changeset `tokens-primitivos-amarelo-roxo`): a paleta lista os 31 primitivos, e
802
+ com o tokens 0.4.3 essas duas amostras saem na cor errada.
803
+
804
+ ```vue
805
+ <ColorPicker
806
+ label="Cor do marcador"
807
+ :value="cor"
808
+ :onChange="(c) => (cor = c)"
809
+ allowCustom
810
+ />
811
+ ```
812
+
813
+ - e3d82fc: feat(datatable): célula livre por coluna, linha de grupo e tipos exportados no Vue
814
+
815
+ A `DataTable` passa a aceitar markup na célula nos dois frameworks. API antiga
816
+ intacta: sem as props e slots novos, o HTML e as classes são os mesmos.
817
+
818
+ - Célula livre. No React, `column.render(row, rowIndex)` já devolvia nó e
819
+ continua assim (o docblock agora diz). No Vue, o retorno do `render` continua
820
+ sendo tratado como texto, e a célula com markup vem do slot `#cell-<key>`,
821
+ que recebe `{ row, value, rowIndex }`. Com `render` e slot na mesma coluna, o
822
+ slot vale.
823
+ - Linha de grupo: `rowGroup` (nome do campo ou função `(row, rowIndex) =>
824
+ rótulo`) abre um `<th scope="rowgroup">` que atravessa a tabela antes de cada
825
+ sequência de linhas com o mesmo rótulo. A tabela não reordena: passe `data` já
826
+ ordenada pelo grupo. O conteúdo do grupo é o rótulo, ou `renderRowGroup(label,
827
+ row, rowIndex)` no React, ou o slot `#row-group` (`{ label, row, rowIndex }`)
828
+ no Vue. A linha de grupo não entra na seleção nem no `onRowClick`.
829
+ - Vue (tipos): o `index.d.ts` do pacote passa a trazer todo tipo exportado pelos
830
+ componentes. Antes só saíam as `*Props`, `*Action` e `*Option`, e a `DataTableProps`
831
+ apontava para um `DataTableColumn` que não existia no arquivo. Agora
832
+ `DataTableColumn`, `DropdownItem`, `AccordionItemData` (e os demais, como
833
+ `StackSpacing`, `BoxSpacing` e `ChartDatum`) podem ser importados de
834
+ `@1doc/1ds-vue`. No React eles já eram exportados.
835
+
836
+ ```vue
837
+ <DataTable :columns="colunas" :data="usuarios" rowGroup="setor">
838
+ <template #cell-nome="{ row }">
839
+ <Avatar type="letter" size="sm">{{ row.nome[0] }}</Avatar> {{ row.nome }}
840
+ </template>
841
+ <template #cell-setores="{ value }">
842
+ <Tag v-for="setor in value" :key="setor" :label="setor" size="sm" />
843
+ </template>
844
+ <template #row-group="{ label }">Setor {{ label }}</template>
845
+ </DataTable>
846
+ ```
847
+
848
+ - a5fe6fe: feat(datatable,descriptionlist): `DataTable variant="document"` e novo `DescriptionList`
849
+
850
+ Para o que é CONTEÚDO de documento (se lê e se imprime), não interface.
851
+
852
+ **`DataTable variant="document"`** (padrão `default`, nada muda sem a prop):
853
+ tabela sem interação, com grade de bordas finas em todas as células, sem hover,
854
+ sem cabeçalho grudado e sem raio. `sortable`, `selectable` e `onRowClick` são
855
+ ignorados: sem botão de ordenar, sem `aria-sort`, sem checkbox, linha fora da
856
+ ordem de Tab. Na impressão (`@media print`) o cabeçalho se repete a cada página,
857
+ uma linha nunca é cortada ao meio e as cores saem (`print-color-adjust`).
858
+ `columns`, `data`, `align`, `width`, `render`/`#cell-<key>` e `density` valem
859
+ como sempre.
860
+
861
+ **`DescriptionList`**, para os pares rótulo/valor (o `DocPares` do CrisDoc não
862
+ cabia na tabela: não tem cabeçalho de coluna). `<dl>` com `<dt>` e `<dd>`:
863
+
864
+ - `items`: `{ label, value, id? }`. Valor vazio mostra "—" (`emptyValue`).
865
+ - `layout="inline"` (padrão): grade de bordas finas, rótulo pintado e sem quebra
866
+ à esquerda, valor à direita; `fit` encolhe até o conteúdo.
867
+ - `layout="stacked"`: rótulo pequeno em cima, valor embaixo, `columns` de 1 a 4
868
+ (vira 1 em tela estreita); `bordered` põe o valor na caixa de um campo
869
+ somente leitura.
870
+ - `ariaLabel` ou `ariaLabelledby`. No Vue o `value` é texto (valor com marcação:
871
+ monte com `Stack` e `Text`).
872
+
873
+ ```vue
874
+ <DataTable variant="document" :columns="colunas" :data="itens" />
875
+ <DescriptionList
876
+ ariaLabel="Dados de empenho"
877
+ :items="[
878
+ { label: 'Empenho', value: '2026NE000184' },
879
+ { label: 'Valor empenhado', value: 'R$ 51.840,00' },
880
+ ]"
881
+ />
882
+ ```
883
+
884
+ - 801c5c2: feat(fileinput): `variant="trigger"`, o seletor aberto por outro controle
885
+
886
+ Para o "Anexar arquivo" de um botão ou o "Alterar foto" de um link, sem a caixa
887
+ de arrastar. Opt-in; `base` e `card` não mudam.
888
+
889
+ - `variant="trigger"`: o conteúdo que você passa (React: `children`; Vue: slot
890
+ padrão) é o gatilho. O clique nele abre o seletor (o clique sobe até o
891
+ envoltório, então o Enter num `Button` também funciona), e `accept`,
892
+ `multiple`, `name`, `files`, `onChange` e `onRemove` funcionam igual. O input
893
+ nativo fica oculto ao lado, fora do Tab (o gatilho é quem recebe o foco) e
894
+ com nome acessível (`label` ou `selectFileLabel`). `disabled` não abre.
895
+ - O `label` visível não aparece no `trigger`: o gatilho é o próprio conteúdo; o
896
+ `label` serve de nome acessível do input.
897
+ - Não há `open()` exposto: o Mitosis não tem como expor método imperativo nos
898
+ dois frameworks. O `trigger` cobre o caso (botão ou link que abre o seletor).
899
+
900
+ ```vue
901
+ <FileInput
902
+ variant="trigger"
903
+ accept=".pdf,.docx"
904
+ :multiple="true"
905
+ :onChange="anexar"
906
+ >
907
+ <Button variant="secondary" startIcon="paperclip">Anexar arquivo</Button>
908
+ </FileInput>
909
+ ```
910
+
911
+ - 0e89b88: feat(iconpicker): novo `IconPicker`, a grade de ícones com busca
912
+
913
+ Peça nova, sem dependência: os ícones vêm por prop.
914
+
915
+ - `icons`: objetos do Font Awesome importados (`faUser`, `faFolder`...), ou
916
+ `{ icon, label?, keywords? }` quando o nome ou a busca precisam de ajuda. O nome
917
+ de um ícone sem `label` é o `iconName` sem hífen ("file lines"); `iconLabel`
918
+ traduz.
919
+ - O valor é o NOME do ícone (`"user"`, `"file-lines"`): `value`/`defaultValue`,
920
+ `onChange(nome, item)`. Guarde o nome e resolva de volta para o objeto na hora de
921
+ desenhar.
922
+ - `radiogroup`: Tab entra no ícone escolhido (ou no primeiro); setas movem a
923
+ escolha (esquerda e direita um ícone, cima e baixo uma linha: `columns`, padrão
924
+ 8), Home e End vão às pontas. O escolhido ganha fundo e borda do primário e
925
+ `aria-checked`.
926
+ - Busca (ligada; `hideSearch` esconde) por nome, rótulo e palavras-chave, sem
927
+ acento nem caixa. A seta para baixo no campo leva à grade, e o número de
928
+ resultados é anunciado (`role="status"`). Sem resultado, mostra `emptyText`.
929
+ - `maxHeight` (px) limita a grade e rola dentro dela; `size` `sm` ou `md`;
930
+ `disabled`.
931
+ - Textos por prop: `searchLabel`, `searchPlaceholder`, `emptyText`, `resultsLabel`
932
+ (`{count}`).
933
+
934
+ ```vue
935
+ <IconPicker
936
+ label="Ícone da categoria"
937
+ :icons="[
938
+ faFolder,
939
+ faFileLines,
940
+ { icon: faBuilding, label: 'Órgão', keywords: ['prefeitura'] },
941
+ ]"
942
+ :value="icone"
943
+ :onChange="(nome) => (icone = nome)"
944
+ />
945
+ ```
946
+
947
+ - 4d0cb08: feat(input): `onChange` a cada tecla no Vue, `mask`, `iconRight` e `borderless`
948
+
949
+ - **`onChange` a cada tecla no Vue (paridade com o React).** O campo passa a
950
+ escutar `input` além de `change`. Antes, no Vue, `onChange` só disparava quando
951
+ o campo perdia o foco (o evento `change` nativo). Os dois eventos entram no
952
+ mesmo tratador, que descarta o repetido: no React os dois disparam para o
953
+ mesmo evento nativo, e no Vue o `change` do blur repete o valor que o `input`
954
+ da última tecla já entregou. O resultado é uma chamada por tecla nos dois
955
+ frameworks. Um `change` disparado à mão com valor novo (testes de quem
956
+ consome) também chega. `onBlur` segue sendo o evento de saída do campo.
957
+ Quem contornava o blur no Vue com `@input` por fora pode tirar o contorno.
958
+ - `mask`: `"cpf"`, `"cnpj"`, `"cep"` ou `"phone"` (10 ou 11 dígitos). O valor
959
+ exibido e o que chega em `onChange` já vêm formatados; para só os dígitos,
960
+ `valor.replace(/\D/g, "")`. Aceita só dígitos, limita o tamanho (`maxlength`) e
961
+ abre o teclado numérico no celular (`inputmode="numeric"`). Valor controlado
962
+ só com dígitos também aparece formatado. Cursor: reformatar no meio do texto
963
+ leva o cursor ao fim (suficiente para digitar do início ao fim).
964
+ - `iconRight`: ícone decorativo à direita, `aria-hidden`, sem clique. Para ação,
965
+ continua `iconsRight`.
966
+ - `borderless`: sem borda, fundo e raio, para o campo dentro de um grupo que já
967
+ tem a moldura (um `Select` e um `Input` lado a lado numa caixa). O foco não
968
+ some: vira contorno de 2px para dentro. Com erro, a borda vermelha fica.
969
+
970
+ ```vue
971
+ <Input label="CPF" mask="cpf" :onChange="(v) => (cpf = v)" />
972
+ <Input
973
+ ariaLabel="Número"
974
+ placeholder="Número"
975
+ borderless
976
+ fullWidth
977
+ iconRight="search"
978
+ />
979
+ ```
980
+
981
+ - cfb8c4a: feat(kbd,codeblock): novos `Kbd` e `CodeBlock`, e o token de fonte monoespaçada
982
+
983
+ **Token novo** (`@1doc/1ds-tokens`): `--umds-primitive-font-family-mono` e o
984
+ semântico `--umds-semantic-font-family-mono` (`ui-monospace, SFMono-Regular,
985
+ Menlo, Consolas, 'Liberation Mono', monospace`). É a pilha de fontes do sistema:
986
+ nenhuma fonte baixada, então nenhum pedido de rede novo. O produto cita o
987
+ semântico; os dois componentes abaixo já o usam.
988
+
989
+ **`Kbd`**: uma tecla ou uma combinação, em `<kbd>`.
990
+
991
+ - Uma tecla vai como conteúdo (`<Kbd>Esc</Kbd>`); uma combinação em `keys`
992
+ (`["Ctrl", "Shift", "P"]`), com `separator` entre as teclas (padrão `+`). Cada
993
+ tecla é um `<kbd>` dentro do `<kbd>` do conjunto, que é como o HTML diz
994
+ "combinação". O leitor de tela lê "Ctrl + Shift + P".
995
+ - Caixa cinza com borda e base mais grossa, fonte monoespaçada; `size` `sm` ou
996
+ `md`. Raiz única: `title`, `data-*`, `aria-*` e ouvintes chegam ao elemento.
997
+
998
+ **`CodeBlock`**: trecho de código, JSON ou log, com borda, rolagem e cópia.
999
+
1000
+ - O texto vem por `code` ou como conteúdo, com espaços e quebras mantidos. Linha
1001
+ longa rola na horizontal, ou quebra com `wrap`; `maxHeight` (px) limita a
1002
+ altura e rola na vertical.
1003
+ - A área de rolagem é `role="region"` focável (Tab) e nomeada (`ariaLabel`, senão
1004
+ a `language`, senão "Código"): quem usa o teclado consegue rolar.
1005
+ - `copyable` mostra o botão de copiar no cabeçalho: copia o texto inteiro (não só
1006
+ o que está à vista), troca para "Copiado" por dois segundos e anuncia ao leitor
1007
+ de tela. Usa `navigator.clipboard`, e recorre a `execCommand("copy")` quando ele falha.
1008
+ `onCopy(texto)` avisa. `copyLabel` e `copiedLabel` por prop.
1009
+ - `language` é só rótulo no topo. Não colore sintaxe (pede uma biblioteca); fundo
1010
+ claro e texto escuro nos dois temas.
1011
+
1012
+ ```vue
1013
+ <Kbd :keys="['Ctrl', 'K']" size="sm" />
1014
+ <CodeBlock language="JSON" :code="envio" copyable />
1015
+ ```
1016
+
1017
+ - fcd9c32: feat(list): estado vazio dentro da lista (`isEmpty`)
1018
+
1019
+ O `List` passa a trazer o estado vazio. Com `isEmpty`, as linhas dão lugar a um
1020
+ `EmptyState` DENTRO da lista: o título do cartão, a busca, os filtros e a
1021
+ paginação ao redor continuam montados (e o foco no campo de busca não se perde),
1022
+ porque só o miolo troca. A lista não conta filhos: `isEmpty` é a decisão de
1023
+ quem a usa (`:is-empty="!itens.length"`).
1024
+
1025
+ - Texto: `emptyTitle` (padrão "Nenhum item encontrado"), `emptyDescription`,
1026
+ `emptyIcon` (objeto do Font Awesome), `emptySize` (`sm` padrão, `md`, `lg`).
1027
+ - Ação: `emptyActionLabel` com `onEmptyAction`. Sem o callback o botão não
1028
+ aparece.
1029
+ - Conteúdo próprio: slot `empty` (no React, a prop `empty`) no lugar do
1030
+ `EmptyState`.
1031
+ - Acessibilidade: o bloco vazio é `role="status"`, então a lista esvaziar é
1032
+ anunciada. Sem itens não há `ul` vazia no DOM.
1033
+
1034
+ ```vue
1035
+ <List
1036
+ ariaLabelledby="titulo"
1037
+ :isEmpty="!docs.length"
1038
+ emptyTitle="Nenhum documento"
1039
+ emptyDescription="Tudo em dia."
1040
+ :emptyIcon="faInbox"
1041
+ emptyActionLabel="Atualizar"
1042
+ @emptyAction="recarregar"
1043
+ >
1044
+ <ListItem v-for="d in docs" :key="d.id" :title="d.titulo" />
1045
+ </List>
1046
+ ```
1047
+
1048
+ - 4b57ca7: feat(list): novos `ListItem` e `List`, a linha de lista inteira clicável
1049
+
1050
+ Peça nova. O `ListItem` é a linha cujo alvo de clique e de foco é a linha
1051
+ toda, com conteúdo livre. Renderiza um `<li>` com UM `button`, `a` ou `div`
1052
+ dentro, por isso vive num `List` (ou num `ul`/`ol`, como `Stack as="ul"`).
1053
+
1054
+ - `as`: `button` | `a` | `div`. Sem `as`, vira `a` quando há `href` e `button`
1055
+ nos outros casos. `div` é a linha que só mostra; com `onClick` ganha
1056
+ role="button", tabindex 0, Enter e Espaço. `target="_blank"` põe
1057
+ `rel="noopener noreferrer"` sozinho.
1058
+ - Conteúdo: `start`, `title`, `subtitle`, `meta`, `end` e o conteúdo padrão (abaixo
1059
+ de `meta`). `title`, `subtitle` e `meta` aceitam texto por prop ou nó por slot.
1060
+ No Vue os slots se chamam igual (`#start`, `#title`...); no React são as
1061
+ props. Região vazia não desenha nada.
1062
+ - Estados: hover e foco visível (anel interno), `selected` (fundo de seleção e
1063
+ `aria-current="true"`), `disabled` (button desabilitado; link perde o `href` e
1064
+ ganha `aria-disabled`).
1065
+ - `id`, `style`, `role`, `tabIndex`, `data-*` e `aria-*` vão para o elemento
1066
+ interativo (é nele que entra o `aria-label`). `title` é o título da linha, não
1067
+ o atributo HTML.
1068
+ - `List`: `ul` (padrão) ou `ol`, sempre com `role="list"` (o Safari tira a
1069
+ semântica de `list-style: none`), `gap` na escala do DS (padrão `quarck`),
1070
+ `ariaLabel` ou `ariaLabelledby`.
1071
+
1072
+ Medidas: padding 8 12 (o 10 12 do CrisDoc não existe na escala), raio 8, título
1073
+ 14/600, subtítulo 14 e meta 12, todos pelo `Text`.
1074
+
1075
+ ```vue
1076
+ <List ariaLabel="Documentos não lidos" gap="nano">
1077
+ <ListItem selected title="Memorando 114/2025" subtitle="Novo contrato - Governo"
1078
+ meta="23 de agosto de 2025" @click="abrir(doc)">
1079
+ <template #start><Avatar type="letter" size="sm">I</Avatar></template>
1080
+ <template #end><Badge variant="info" size="sm">novo</Badge></template>
1081
+ </ListItem>
1082
+ </List>
1083
+ ```
1084
+
1085
+ - eeb6a16: feat(modal): `variant="primary"`, `width`/`maxWidth`, `windowControls` em lista e `responsive`; o Esc respeita quem já o usou
1086
+
1087
+ Tudo opt-in; sem as props novas o modal é o mesmo.
1088
+
1089
+ - `variant="primary"`: cabeçalho cheio na cor primária (título, subtítulo e
1090
+ controles em `neutral-light-pure`, hover em `primary-dark`). É o modal base com
1091
+ as três faixas, não o diálogo de feedback.
1092
+ - `width` e `maxWidth`: qualquer valor CSS. `width` sozinho solta o teto do
1093
+ `size` (o 498px do `md` não segura mais) e passa a ser limitado pela tela.
1094
+ Com `windowControls`, valem só no modo normal.
1095
+ - `windowControls` aceita `true` (o conjunto inteiro, como antes) ou uma lista
1096
+ com os controles que quiser: `["expand", "fullscreen"]`. Nomes: `normal`,
1097
+ `expand`, `fullscreen`, `minimize`. Em lista, sem `normal`, clicar de novo no
1098
+ modo ativo volta ao normal, e o modo normal usa o tamanho do próprio modal
1099
+ (não os 780px do conjunto inteiro). O divisor só aparece com algum controle e
1100
+ com o ×. `onMinimize` só existe se `minimize` estiver na lista.
1101
+ - `responsive` e `responsiveBreakpoint` (padrão 640, lido na montagem): abaixo
1102
+ da largura, o modal vira um painel que sobe pela borda de baixo (largura
1103
+ total, cantos de cima arredondados, alça, entrada por baixo), como o
1104
+ `BottomSheet`; acima, continua centralizado. É o mesmo componente reorganizado
1105
+ (não monta um `BottomSheet` por dentro, porque o Mitosis não repassa slot de
1106
+ um componente a outro), então não tem o gesto de arrastar. No painel os
1107
+ controles de janela e a largura livre somem.
1108
+ - Esc: o ouvinte do `document` passa a rodar no borbulho e a ignorar a tecla se
1109
+ `defaultPrevented`. `Select`, `Combobox`, `Popover` e `Dropdown` já faziam
1110
+ `preventDefault`; `DatePicker` e `MultiSelect` passaram a fazer. Resultado: um
1111
+ `Select` ou `DatePicker` aberto dentro do modal fecha só a lista, e o modal
1112
+ fica. Quem tinha contorno para isso pode tirá-lo.
1113
+
1114
+ ```vue
1115
+ <Modal
1116
+ open
1117
+ variant="primary"
1118
+ width="600px"
1119
+ :window-controls="['expand', 'fullscreen']"
1120
+ title="Verificar rotas e quilometragem"
1121
+ responsive
1122
+ >
1123
+ ...
1124
+ </Modal>
1125
+ ```
1126
+
1127
+ - 56229f0: feat(orgchart): novo `OrgChart`, o organograma com conectores
1128
+
1129
+ Peça nova: uma árvore desenhada de cima para baixo, com linhas ligando cada pai
1130
+ aos filhos, em que os nós com filhos expandem e recolhem. Sem dependência.
1131
+
1132
+ - `nodes`: lista de nós raiz `{ id, title, subtitle?, children? }`. Mais de uma
1133
+ raiz funciona (floresta).
1134
+ - O desenho é calculado, não aninhado (o Mitosis não gera componente recursivo de
1135
+ forma confiável): cada nó tem largura e altura fixas (`nodeWidth` 176,
1136
+ `nodeHeight` 64, em px), os filhos se distribuem sob o pai (`gapX` 16) e o pai se
1137
+ centra sobre eles; um nível desce `gapY` (40). Os conectores são um SVG de uma
1138
+ linha por pai. O container rola quando o organograma passa da largura.
1139
+ - Visual: a raiz cheia na cor primária, os demais em tom claro; `selectedId` marca
1140
+ um nó. O título e o subtítulo cortam com reticências (o texto inteiro vai no
1141
+ tooltip).
1142
+ - Conteúdo livre do nó: no React `renderNode(nó, { level, expanded })`; no Vue o
1143
+ slot `node` com escopo `{ node, level, expanded }` (ligado no `postbuild.js`,
1144
+ como o do `DataTable`). O conteúdo precisa caber na caixa do nó.
1145
+ - Expandir e recolher: tudo aberto por padrão; `defaultCollapsedIds` (ou
1146
+ `collapsedIds` controlado) escolhe o que começa recolhido, e
1147
+ `onCollapsedChange(ids)` avisa. O botão +/− no pé do nó é para o mouse.
1148
+ - Acessibilidade: `role="tree"` com nós `treeitem` (`aria-level`,
1149
+ `aria-posinset`, `aria-setsize`, `aria-expanded`, `aria-selected`). Um Tab entra
1150
+ no nó em foco; Baixo vai ao primeiro filho (e abre o nó, se recolhido), Cima ao
1151
+ pai, Esquerda e Direita aos irmãos, Home e End ao primeiro e ao último irmão,
1152
+ Espaço expande ou recolhe, Enter aciona `onNodeClick`.
1153
+ - Textos por prop: `ariaLabel` ("Organograma"), `expandLabel`, `collapseLabel`.
1154
+
1155
+ Limites do primeiro corte: só de cima para baixo; sem zoom nem arrastar; nó de
1156
+ altura variável não cabe (use `nodeHeight` para o maior). Para navegar e escolher
1157
+ em hierarquias grandes, o `Tree` é mais denso e acessível.
1158
+
1159
+ ```vue
1160
+ <OrgChart :nodes="setores" ariaLabel="Setores da COPIRN" :onNodeClick="abrir">
1161
+ <template #node="{ node }"><Avatar size="sm">{{ node.title }}</Avatar></template>
1162
+ </OrgChart>
1163
+ ```
1164
+
1165
+ - e8453bc: feat(otpinput): novo `OtpInput`, o código de verificação em caixas
1166
+
1167
+ Peça nova para códigos curtos recebidos por outro canal (autenticação em duas
1168
+ etapas, confirmação de e-mail ou telefone).
1169
+
1170
+ - `length` caixas (6 por padrão). Digitar avança o foco; Backspace apaga e, em
1171
+ caixa vazia, volta e apaga a anterior; setas, Home e End movem.
1172
+ - Colar o código inteiro em qualquer caixa distribui os caracteres (um pedaço
1173
+ entra a partir da caixa atual). O preenchimento automático do SMS também,
1174
+ porque a primeira caixa leva `autocomplete="one-time-code"`.
1175
+ - Sem buraco: focar uma caixa à frente da primeira vazia manda o foco de volta a
1176
+ ela.
1177
+ - Valor em string: `value`/`defaultValue`, `onChange(codigo)` a cada mudança e
1178
+ `onComplete(codigo)` quando as caixas enchem (uma vez por código novo).
1179
+ - `type="numeric"` (padrão, teclado numérico no celular) ou `"alphanumeric"`
1180
+ (letras e dígitos, em maiúsculas).
1181
+ - Acessibilidade: `role="group"` nomeado por `label` ou `ariaLabel`; cada caixa
1182
+ tem nome próprio (`digitLabel`, padrão "Dígito {n} de {total}", traduzível);
1183
+ `errorMessage`/`invalid` ligam `aria-invalid` e `aria-describedby`.
1184
+ - `size` `sm` ou `md`; foco e erro seguem os tokens de campo.
1185
+
1186
+ ```vue
1187
+ <OtpInput
1188
+ label="Código de verificação"
1189
+ :length="6"
1190
+ :onComplete="(codigo) => verificar(codigo)"
1191
+ errorMessage="Código inválido ou expirado."
1192
+ />
1193
+ ```
1194
+
1195
+ - d89ebe3: feat(popover): `maxHeight` para o corpo do painel
1196
+
1197
+ - `maxHeight`: altura máxima do corpo, que rola além dela. Número vira px; texto
1198
+ vai como CSS (`"60vh"`). `"none"` deixa o corpo crescer com o conteúdo, como
1199
+ no painel "Colunas do card" do CrisDoc.
1200
+ - Sem a prop, **o teto de 300px continua**: tirá-lo por padrão faria todo painel
1201
+ existente com lista longa estourar a tela sem rolagem. Quem quer o corpo livre
1202
+ passa `maxHeight="none"`. O cabeçalho e o × não rolam junto, como antes.
1203
+
1204
+ ```vue
1205
+ <Popover title="Colunas do card" maxHeight="none" :width="260">
1206
+ <Button>Personalizar</Button>
1207
+ <template #content>...</template>
1208
+ </Popover>
1209
+ ```
1210
+
1211
+ - 3c482fa: feat(richtexteditor): novo `RichTextEditor`, texto rico leve sem biblioteca
1212
+
1213
+ Peça nova, sobre `contenteditable` e `document.execCommand`. Sem dependência
1214
+ nova: o primeiro corte é o que as telas de despacho, resposta e descrição de
1215
+ serviço pedem.
1216
+
1217
+ - Ferramentas: negrito, itálico, sublinhado, tachado, lista com marcadores, lista
1218
+ numerada, link, desfazer, refazer e limpar formatação. A barra se escolhe por
1219
+ `toolbar` (a ordem do array é a da tela, `"|"` é um separador): a padrão traz
1220
+ negrito, itálico, sublinhado, listas, link, desfazer e refazer;
1221
+ `["bold", "italic", "underline", "ul", "ol", "link"]` é a compacta e
1222
+ `["bold", "italic"]` a mínima.
1223
+ - `value`/`defaultValue`/`onChange` em HTML. O HTML é SEMPRE higienizado, tanto o
1224
+ que entra por `value` quanto o que se cola: ficam só `a`, `b`/`strong`,
1225
+ `i`/`em`, `u`, `s`/`strike`/`del`, `ul`, `ol`, `li`, `p`, `br`, `div`, `span`,
1226
+ títulos e citação; `script`, `style`, `onerror`, `class` e `javascript:` saem.
1227
+ Colar entra como texto puro. Link só aceita `http(s)`, `mailto`, `tel`, caminho
1228
+ e âncora, e ganha `rel="noopener noreferrer"`. `sanitizarHtml`, `enderecoSeguro`
1229
+ e `normalizarEndereco` vivem em `utils/html-seguro`.
1230
+ - A barra é `role="toolbar"` (Tab numa parada só, setas, Home e End entre as
1231
+ ferramentas). Negrito, itálico, sublinhado, tachado e as listas são botões de
1232
+ liga/desliga (`aria-pressed`) que seguem o cursor. A área é `role="textbox"`
1233
+ multilinha, com `label` ou `ariaLabel`, `aria-invalid` e `aria-describedby`
1234
+ (`errorMessage`, `helperText`). Ctrl+K abre o link.
1235
+ - Link sem modal: um campo logo abaixo da barra (endereço, Aplicar, Remover link,
1236
+ Cancelar; Esc fecha). Sem texto escolhido, o endereço vira o texto do link.
1237
+ Endereço sem esquema ganha `https://`; endereço perigoso mostra o erro e não
1238
+ vira link.
1239
+ - `footer` (slot): a assinatura do autor, dentro da moldura; `resizable` e
1240
+ `minHeight` (px); `readOnly` (sem barra) e `disabled`; `invalid`.
1241
+ - Textos por prop: `placeholder`, `toolbarLabel` e `labels` (parcial: `bold`,
1242
+ `italic`, `underline`, `strike`, `ul`, `ol`, `link`, `undo`, `redo`, `clear`,
1243
+ `linkAddress`, `linkApply`, `linkRemove`, `linkCancel`, `linkInvalid`).
1244
+
1245
+ Fora deste corte, por tamanho: tabela, imagem, cor, fonte, tamanho e
1246
+ alinhamento. Limite técnico: `document.execCommand` é obsoleto no padrão, mas
1247
+ todos os navegadores o mantêm; o histórico do desfazer varia um pouco entre eles.
1248
+
1249
+ ```vue
1250
+ <RichTextEditor
1251
+ label="Despacho"
1252
+ :value="html"
1253
+ :onChange="(h) => (html = h)"
1254
+ :toolbar="['bold', 'italic', 'underline', '|', 'ul', 'ol', '|', 'link']"
1255
+ >
1256
+ <template #footer>Ana Paula Souza, SADM</template>
1257
+ </RichTextEditor>
1258
+ ```
1259
+
1260
+ - b02f4ff: feat(select): `placement` (a lista abre para cima) e variante `filter` com opção "sem filtro" e rodapé
1261
+
1262
+ Tudo opt-in; sem as props novas o `Select` é o mesmo.
1263
+
1264
+ - `placement`: `bottom` (padrão), `top` ou `auto`. O `auto` mede o espaço na hora
1265
+ de abrir e abre para cima só se a lista (altura estimada, no máximo os 300px
1266
+ do CSS) não cabe embaixo e há mais espaço em cima, como o campo no rodapé de
1267
+ um modal numa janela baixa. A lista continua dentro do campo (posição
1268
+ absoluta), então um contêiner com `overflow` ainda pode cortá-la, igual
1269
+ antes.
1270
+ - `variant="filter"`: botão de filtro de barra de ferramentas, contornado em
1271
+ azul (`primary-pure` sobre `primary-light`), largura do conteúdo, lista de no
1272
+ mínimo 240px, busca focada ao abrir. Combina com `searchable`.
1273
+ - `emptyOptionLabel`: opção "sem filtro" no topo da lista (seleção única).
1274
+ Aparece marcada enquanto nada está escolhido; escolhê-la chama `onChange("")` e
1275
+ o campo volta a mostrar o `placeholder`, que é o nome do filtro.
1276
+ - `footer`: rodapé fixo da lista, com ações ("Gerenciar marcadores"). React:
1277
+ elemento; Vue: slot `footer`. Clicar nele não fecha a lista.
1278
+
1279
+ ```vue
1280
+ <Select
1281
+ variant="filter"
1282
+ size="sm"
1283
+ placeholder="Marcadores"
1284
+ :searchable="true"
1285
+ emptyOptionLabel="Todos os marcadores"
1286
+ :options="marcadores"
1287
+ :value="filtro"
1288
+ :onChange="(v) => (filtro = v)"
1289
+ placement="auto"
1290
+ >
1291
+ <template #footer><Button variant="text" size="sm">Gerenciar marcadores</Button></template>
1292
+ </Select>
1293
+ ```
1294
+
1295
+ - e45ce94: feat(stack): `gap="none"`, prop `as`, props de item flex e atributos HTML
1296
+
1297
+ O `Stack` passa a cobrir o que o produto ainda escrevia em CSS próprio. API
1298
+ antiga intacta: sem as props novas, o HTML e as classes são os mesmos.
1299
+
1300
+ - `gap="none"` zera o espaço (antes só havia os degraus da escala).
1301
+ - `as`: `div` (padrão), `span`, `ul`, `ol`, `li`, `section`, `nav`, `header`,
1302
+ `footer`, `form`. `ul` e `ol` saem sem marcador, margem e recuo, com
1303
+ `role="list"` (o Safari tira a semântica de lista de `list-style: none`).
1304
+ Com `as="form"`, `onSubmit` recebe o evento.
1305
+ - Atributos HTML (`id`, `style`, `title`, `role`, `tabIndex`, `data-*`,
1306
+ `aria-*`) vão para o elemento raiz. Sem isso `as="nav"` não tinha como levar
1307
+ `aria-label`.
1308
+ - Props do próprio Stack como item de outro Stack/flex: `grow`, `shrink`
1309
+ (`"0"` | `"1"`), `basis` (`"auto"`, `"0"`, `"25"`, `"33"`, `"50"`, `"66"`,
1310
+ `"75"`, `"100"`; os números são %), `minWidth` (`"0"` | `"auto"`; o Stack
1311
+ já nasce com `min-width: 0`), `overflow`, `overflowX`, `overflowY`,
1312
+ `fullHeight` e `fullWidth`.
1313
+
1314
+ Decisão: não existe `Stack.Item`. Quem precisa crescer, encolher ou ocupar a
1315
+ altura aninha um Stack com as mesmas props. Subcomponente por ponto não
1316
+ sobrevive aos dois geradores do Mitosis, e o Stack aninhado já é um item flex.
1317
+
1318
+ ```tsx
1319
+ <Stack as="nav" aria-label="Atalhos" fullHeight>
1320
+ <Stack as="ul" gap="none">
1321
+ <Stack as="li">...</Stack>
1322
+ </Stack>
1323
+ <Stack grow overflowY="auto">
1324
+ ...
1325
+ </Stack>
1326
+ <Stack shrink="0">...</Stack>
1327
+ </Stack>
1328
+ ```
1329
+
1330
+ - 1d59843: feat(statcard): `labelPosition="top"` e `infoTooltip`
1331
+
1332
+ Opt-in; sem as props novas o `StatCard` é o mesmo.
1333
+
1334
+ - `labelPosition="top"`: o rótulo vai para o topo do cartão, acima do ícone e do
1335
+ número, e o número passa a 32/800 (o degrau `font-size-lg` do DS), como no
1336
+ painel da 1Doc. Só a posição visual muda: no HTML o número continua antes do
1337
+ rótulo, então o leitor de tela anuncia na mesma ordem. Por baixo, o corpo vira
1338
+ `display: contents` e o cartão uma grade de duas colunas.
1339
+ - `infoTooltip`: texto de ajuda; mostra um ⓘ ao lado do rótulo com o `Tooltip`
1340
+ `dark`. É um botão focável (`infoLabel` traduz o nome, "Mais informações" por
1341
+ padrão) e a ajuda chega ao leitor de tela como descrição do botão. Dentro de
1342
+ um cartão com `onClick` seria botão dentro de botão: evite a combinação.
1343
+
1344
+ ```vue
1345
+ <StatCard
1346
+ labelPosition="top"
1347
+ :value="44"
1348
+ label="Não lidos"
1349
+ :icon="faEyeSlash"
1350
+ variant="primary"
1351
+ infoTooltip="Documentos que você ainda não abriu."
1352
+ />
1353
+ ```
1354
+
1355
+ - 3d6dd1d: feat(tabs): contador em pílula (`count`) e aba fechável (`closable`) com botão "+" (`onAdd`)
1356
+
1357
+ Tudo opt-in. Sem as props novas, a aba e a barra se comportam como antes (cada
1358
+ `Tab` ganha um `<span role="presentation">` com `display: contents`, que não
1359
+ muda o layout, e o `Tabs` ganha uma `div` de barra com o mesmo comportamento).
1360
+
1361
+ **Tab**
1362
+
1363
+ - `count` (número ou texto): pílula de 18px ao lado do texto, azul na aba ativa
1364
+ (`primary-pure`) e cinza nas outras (`neutral-light-medium`). O `0` aparece. O
1365
+ número entra no nome acessível da aba ("Todas 31").
1366
+ - `closable`: × num botão próprio, irmão da aba (não dentro dela, para não
1367
+ aninhar botão), círculo de 20px. A tecla Delete na aba focada faz o mesmo.
1368
+ O × não é uma parada de Tab (a aba já tem o Delete); tem nome "Fechar <aba>".
1369
+ - `onClose(index, event)`: quem remove a aba é o app. Clicar no × não troca de aba.
1370
+ - `closeLabel`: prefixo do nome acessível do ×, para traduzir ("Close Doc 1").
1371
+
1372
+ **Tabs**
1373
+
1374
+ - `onAdd(event)`: mostra o "+" logo depois da última aba, **fora** do
1375
+ `role="tablist"` (o tablist só pode ter abas). `addLabel` traduz o nome
1376
+ ("Adicionar aba" por padrão).
1377
+
1378
+ ```vue
1379
+ <Tabs
1380
+ :value="atual"
1381
+ :onChange="mudar"
1382
+ :onAdd="adicionar"
1383
+ addLabel="Adicionar aba"
1384
+ >
1385
+ <Tab label="Todas" index="0" :count="31" />
1386
+ <Tab v-for="a in abas" :key="a.id" :label="a.nome" :index="a.id"
1387
+ :closable="true" closeLabel="Fechar" :onClose="fechar" />
1388
+ </Tabs>
1389
+ ```
1390
+
1391
+ Ficou de fora desta rodada: o ponto
1392
+ de estado da aba (a bolinha ao lado do nome); a rolagem horizontal das abas já existia.
1393
+
1394
+ - 96e752b: feat(tooltip): `variant="dark"` compacto e `maxWidth`
1395
+
1396
+ Opt-in; sem as props novas o `Tooltip` é o mesmo.
1397
+
1398
+ - `variant="dark"`: balão escuro e compacto (padding 4/8, raio 4, teto de 220px)
1399
+ para ícone, sigla e botão de barra de ferramentas. Fundo `background-dark` e
1400
+ texto `neutral-light-pure`: o par invertido do tema, então o contraste vale nos
1401
+ temas claros, no escuro e no alto contraste (sem cor fixa). A fonte é a de
1402
+ 12px do DS (o CrisDoc usa 11px, que não está na escala). A seta acompanha a cor.
1403
+ - `maxWidth`: largura máxima do balão, qualquer valor CSS, vence o teto de cada
1404
+ variante (280px no padrão, 220px no dark).
1405
+
1406
+ ```vue
1407
+ <Tooltip variant="dark" content="Atualizar" maxWidth="200px">
1408
+ <Button variant="neutral-text" size="xs">Atualizar</Button>
1409
+ </Tooltip>
1410
+ ```
1411
+
1412
+ ### Patch Changes
1413
+
1414
+ - 2259459: fix(ailabel): `defaultOpen` passa a funcionar
1415
+
1416
+ A prop era declarada e documentada, mas nunca lida. Agora o painel nasce
1417
+ aberto com `defaultOpen` (também no HTML do servidor) e o clique continua
1418
+ abrindo e fechando. `open` controlado segue vencendo.
1419
+
1420
+ - e00b163: fix(combobox): placeholder do campo somente leitura passa 4,5:1
1421
+
1422
+ Sobre o fundo de somente leitura o placeholder dava 4,20:1 no 1doc (e
1423
+ 4,21–4,31:1 nos temas claros de cor). Agora usa `neutral-dark-down`: 6,78:1 no
1424
+ 1doc, 10,83:1 no 1doc-dark e 16,48:1 no alto contraste.
1425
+
1426
+ - 19ff160: fix(datepicker): placeholder do campo somente leitura passa 4,5:1
1427
+
1428
+ Sobre o fundo de somente leitura o placeholder dava 4,2:1 nos temas claros e
1429
+ o axe reprovava (`color-contrast`). Agora usa `neutral-dark-down`: 6,78:1 no
1430
+ 1doc, 10,83:1 no 1doc-dark e 16,48:1 no alto contraste.
1431
+
1432
+ - 9315dd7: fix(datepicker): `value` e `defaultValue` chegam ao campo no modo single
1433
+
1434
+ No modo single o componente só lia `range`: `value` e `defaultValue` eram
1435
+ ignorados e o campo mostrava o placeholder. Agora `value` controla o campo e
1436
+ `defaultValue` semeia o modo não-controlado. O modo range não muda.
1437
+
1438
+ - 2250bb4: fix(input): placeholder do campo somente leitura passa 4,5:1
1439
+
1440
+ Sobre o fundo de somente leitura o placeholder dava 4,20:1 no 1doc (e
1441
+ 4,21–4,31:1 nos temas claros de cor). Agora usa `neutral-dark-down`: 6,78:1 no
1442
+ 1doc, 10,83:1 no 1doc-dark e 16,48:1 no alto contraste.
1443
+
1444
+ - ef321dc: fix(kanban): quadro não faz a página rolar na horizontal em tela estreita
1445
+
1446
+ O texto só para leitor de tela de cada coluna é `position: absolute` e, sem
1447
+ ancestral posicionado, escapava da rolagem do quadro: a 375px a página ganhava
1448
+ rolagem lateral. `.umds-kanban` passa a ser `position: relative`; o visual não
1449
+ muda.
1450
+
1451
+ - 978ad95: fix(multiselect): placeholder do campo somente leitura passa 4,5:1
1452
+
1453
+ Sobre o fundo de somente leitura o placeholder dava 4,20:1 no 1doc (e
1454
+ 4,21–4,31:1 nos temas claros de cor). Agora usa `neutral-dark-down`: 6,78:1 no
1455
+ 1doc, 10,83:1 no 1doc-dark e 16,48:1 no alto contraste.
1456
+
1457
+ - 31d3005: fix(a11y): Select, MultiSelect e SegmentedControl com nome acessível no HTML do servidor
1458
+
1459
+ O id automático desses componentes só nasce no `onMount`, e o nome acessível
1460
+ vinha de `aria-labelledby` apontando para ele: no HTML do servidor, e até a
1461
+ hidratação, o combobox (e os radios do SegmentedControl) ficavam sem nome
1462
+ (axe `aria-input-field-name`). Enquanto não há id, o nome sai do texto do
1463
+ label via `aria-label`; depois do mount volta ao `aria-labelledby`. Servidor e
1464
+ primeira renderização do cliente continuam idênticos. Sem mudança visual.
1465
+
1466
+ - 7f58f04: fix(phoneinput): placeholder do campo somente leitura passa 4,5:1
1467
+
1468
+ Sobre o fundo de somente leitura o placeholder dava 4,20:1 no 1doc (e
1469
+ 4,21–4,31:1 nos temas claros de cor). Agora usa `neutral-dark-down`: 6,78:1 no
1470
+ 1doc, 10,83:1 no 1doc-dark e 16,48:1 no alto contraste.
1471
+
1472
+ - 98e9bf0: fix(select): placeholder do campo somente leitura passa 4,5:1
1473
+
1474
+ Sobre o fundo de somente leitura o placeholder dava 4,20:1 no 1doc (e
1475
+ 4,21–4,31:1 nos temas claros de cor). Agora usa `neutral-dark-down`: 6,78:1 no
1476
+ 1doc, 10,83:1 no 1doc-dark e 16,48:1 no alto contraste.
1477
+
1478
+ - c33298c: fix(stack,box): raiz única no Vue, repassa ouvintes e atributos
1479
+
1480
+ No Vue, `Stack` e `Box` saíam com raiz em FRAGMENTO: o Mitosis gera um
1481
+ `<template v-if="elementTag === ...">` por tag, e o Vue não repassa atributo nem
1482
+ ouvinte a um componente de raiz múltipla. Só sobrevivia uma lista fixa
1483
+ (`data-*`, `aria-*`, `style`, `class`, `title`, `role`, `tabIndex`). No 2.8.0
1484
+ publicado a raiz era um `<div>` único e o Vue repassava tudo, então foi uma
1485
+ regressão silenciosa das props novas (`as`, `gap="none"`...).
1486
+
1487
+ Descartados em silêncio, antes desta correção:
1488
+
1489
+ - ouvintes: `@click`, `@keydown`, `@dragstart`, `@drop`, `@paste`, `@mousedown`...
1490
+ - atributos fora da lista: `tabindex` (minúsculo), `draggable`...
1491
+ - `v-show` e o `$el` do `ref` do componente (apontavam para o nó de âncora do
1492
+ fragmento, não para o elemento).
1493
+
1494
+ Agora o template gerado é um `<component :is="elementTag">` só (ligado no
1495
+ `postbuild.js`, como o do `DataTable`), e o fallthrough do Vue leva ao elemento
1496
+ tudo o que o consumidor passa. Continuam como estavam: `as` com as 10 tags,
1497
+ `role="list"` em `ul`/`ol` (o `role` do consumidor vence), `onSubmit` do
1498
+ `as="form"`, `id`, `style` e `className`. O React não muda.
1499
+
1500
+ Novo teste do pacote Vue, `stack-box-raiz-unica.test.mjs`, que monta o
1501
+ componente num DOM (jsdom) e dispara os eventos. O helper `dom.mjs` serve para
1502
+ qualquer teste de comportamento no Vue; não adiciona dependência (usa o jsdom do
1503
+ pacote React e o `vue/compiler-sfc`).
1504
+
1505
+ Outros componentes do 1DS com raiz em fragmento têm o mesmo limite (ex.: `List`,
1506
+ quando troca entre vazio e `ul`/`ol`); este changeset trata só `Stack` e `Box`.
1507
+
1508
+ - 81cb08e: fix(textarea): placeholder do campo somente leitura passa 4,5:1
1509
+
1510
+ Sobre o fundo de somente leitura o placeholder dava 4,20:1 no 1doc (e
1511
+ 4,21–4,31:1 nos temas claros de cor). Agora usa `neutral-dark-down`: 6,78:1 no
1512
+ 1doc, 10,83:1 no 1doc-dark e 16,48:1 no alto contraste.
1513
+
1514
+ - f7645bf: fix(timepicker): placeholder do campo somente leitura passa 4,5:1
1515
+
1516
+ Sobre o fundo de somente leitura o placeholder dava 4,20:1 no 1doc (e
1517
+ 4,21–4,31:1 nos temas claros de cor). Agora usa `neutral-dark-down`: 6,78:1 no
1518
+ 1doc, 10,83:1 no 1doc-dark e 16,48:1 no alto contraste.
1519
+
1520
+ - 0fc7a82: fix(vue): `Text`, `Grid` e `Logo` repassam `title`, `style` e `aria-*`; `Button` e `DataTable` param de sujar o DOM
1521
+
1522
+ Quatro defeitos que só existiam no Vue gerado (o React estava certo):
1523
+
1524
+ - `Text`, `Grid` e `Logo` descartavam `title`, `style`, `aria-*` e `data-*`. O
1525
+ laço `for (k in props)` do `htmlAttrs` compilava para `props.props`, que não
1526
+ existe. O passo `postbuild` do core passa a ler `props` e `useAttrs()` (o que
1527
+ não está declarado na interface chega por `attrs`, não por `props`). Nos
1528
+ `.lite.tsx` de `Text` e `Grid` o getter `style` virou `estiloInline`: o Mitosis
1529
+ trocava toda ocorrência da palavra por `style.value` e o estilo do
1530
+ consumidor deixava de passar.
1531
+ - `DataTable` escrevia a classe `umds-datatable__row--selected.value`. O getter
1532
+ `selected` colidia com a palavra dentro da string; virou `selectedIndexes`.
1533
+ - `Button` escrevia `autofocus="false"`. `autoFocus` só vai ao DOM quando
1534
+ verdadeiro.
1535
+ - Tipos do Vue: `setTheme`, `getTheme`, `initTheme`, `getAvailableThemes` e
1536
+ `onThemeChange` estavam tipados com `'light' | 'dark' | 'system'`. Agora
1537
+ `Theme` e `ThemeName` são lidos de `core/src/utils/theme.ts` (`'1doc'`,
1538
+ `'1doc-dark'`, `'1doc-high-contrast'`...), e `registerTheme` foi declarado.
1539
+
1540
+ Testes: `pnpm --filter @1doc/1ds-vue test` (novo, `node:test` com SSR, sem
1541
+ dependência nova) e `AtributosRepassados.test.tsx` no React.
1542
+
3
1543
  ## 2.8.0
4
1544
 
5
1545
  ### Minor Changes