@1doc/1ds-react 2.7.2 → 2.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (302) hide show
  1. package/CHANGELOG.md +1280 -0
  2. package/dist/components/AIContent/AIContent.d.ts +10 -0
  3. package/dist/components/AIContent/AIContent.js +1 -1
  4. package/dist/components/AILabel/AILabel.d.ts +4 -0
  5. package/dist/components/AILabel/AILabel.js +2 -2
  6. package/dist/components/Accordion/Accordion.d.ts +6 -2
  7. package/dist/components/Alert/Alert.css +2 -0
  8. package/dist/components/Alert/Alert.d.ts +3 -1
  9. package/dist/components/Alert/Alert.js +7 -1
  10. package/dist/components/AppHeader/AppHeader.css +82 -8
  11. package/dist/components/AppHeader/AppHeader.d.ts +12 -1
  12. package/dist/components/AppHeader/AppHeader.js +186 -1
  13. package/dist/components/AppNavItem/AppNavItem.css +11 -3
  14. package/dist/components/AppShell/AppShell.css +9 -0
  15. package/dist/components/AppShell/AppShell.d.ts +8 -0
  16. package/dist/components/AppShell/AppShell.js +4 -1
  17. package/dist/components/AppSidebar/AppSidebar.css +1 -1
  18. package/dist/components/AppSidebar/AppSidebar.d.ts +4 -0
  19. package/dist/components/AppSidebar/AppSidebar.js +3 -1
  20. package/dist/components/AttachmentCard/AttachmentCard.css +17 -1
  21. package/dist/components/AttachmentCard/AttachmentCard.d.ts +29 -2
  22. package/dist/components/AttachmentCard/AttachmentCard.js +88 -20
  23. package/dist/components/Avatar/Avatar.css +7 -2
  24. package/dist/components/Avatar/AvatarGroup.d.ts +27 -0
  25. package/dist/components/Avatar/AvatarGroup.js +28 -4
  26. package/dist/components/Badge/Badge.css +61 -3
  27. package/dist/components/Badge/Badge.d.ts +14 -4
  28. package/dist/components/Badge/Badge.js +1 -0
  29. package/dist/components/BottomSheet/BottomSheet.css +1 -0
  30. package/dist/components/BottomSheet/BottomSheet.d.ts +8 -0
  31. package/dist/components/BottomSheet/BottomSheet.js +14 -2
  32. package/dist/components/Box/Box.css +83 -0
  33. package/dist/components/Box/Box.d.ts +82 -2
  34. package/dist/components/Box/Box.js +42 -2
  35. package/dist/components/Button/Button.css +29 -0
  36. package/dist/components/Button/Button.d.ts +4 -4
  37. package/dist/components/Button/Button.js +4 -1
  38. package/dist/components/Calendar/Calendar.css +245 -0
  39. package/dist/components/Calendar/Calendar.d.ts +125 -0
  40. package/dist/components/Calendar/Calendar.js +320 -0
  41. package/dist/components/Chart/BarChart.d.ts +6 -0
  42. package/dist/components/Chart/BarChart.js +3 -1
  43. package/dist/components/Chart/LineChart.d.ts +6 -0
  44. package/dist/components/Chart/LineChart.js +3 -1
  45. package/dist/components/Checkbox/Checkbox.css +4 -1
  46. package/dist/components/Chips/Chips.css +39 -0
  47. package/dist/components/Chips/Chips.d.ts +7 -2
  48. package/dist/components/Chips/Chips.js +6 -2
  49. package/dist/components/Coachmark/Coachmark.css +118 -0
  50. package/dist/components/Coachmark/Coachmark.d.ts +75 -0
  51. package/dist/components/Coachmark/Coachmark.js +321 -0
  52. package/dist/components/CodeBlock/CodeBlock.css +96 -0
  53. package/dist/components/CodeBlock/CodeBlock.d.ts +47 -0
  54. package/dist/components/CodeBlock/CodeBlock.js +103 -0
  55. package/dist/components/ColorPicker/ColorPicker.css +133 -0
  56. package/dist/components/ColorPicker/ColorPicker.d.ts +73 -0
  57. package/dist/components/ColorPicker/ColorPicker.js +219 -0
  58. package/dist/components/Combobox/Combobox.css +11 -3
  59. package/dist/components/ConfirmAIAction/ConfirmAIAction.d.ts +11 -1
  60. package/dist/components/ConfirmAIAction/ConfirmAIAction.js +6 -1
  61. package/dist/components/ConfirmDialog/ConfirmDialog.css +3 -0
  62. package/dist/components/ConfirmDialog/ConfirmDialog.d.ts +14 -0
  63. package/dist/components/ConfirmDialog/ConfirmDialog.js +2 -2
  64. package/dist/components/DataTable/DataTable.css +80 -0
  65. package/dist/components/DataTable/DataTable.d.ts +23 -4
  66. package/dist/components/DataTable/DataTable.js +61 -15
  67. package/dist/components/DatePicker/DatePicker.css +8 -0
  68. package/dist/components/DatePicker/DatePicker.d.ts +4 -0
  69. package/dist/components/DatePicker/DatePicker.js +14 -1
  70. package/dist/components/DescriptionList/DescriptionList.css +113 -0
  71. package/dist/components/DescriptionList/DescriptionList.d.ts +59 -0
  72. package/dist/components/DescriptionList/DescriptionList.js +51 -0
  73. package/dist/components/Drawer/Drawer.css +1 -0
  74. package/dist/components/Dropdown/Dropdown.js +47 -29
  75. package/dist/components/FileInput/FileInput.css +24 -4
  76. package/dist/components/FileInput/FileInput.d.ts +22 -2
  77. package/dist/components/FileInput/FileInput.js +23 -2
  78. package/dist/components/Grid/Grid.js +5 -5
  79. package/dist/components/IconPicker/IconPicker.css +107 -0
  80. package/dist/components/IconPicker/IconPicker.d.ts +74 -0
  81. package/dist/components/IconPicker/IconPicker.js +194 -0
  82. package/dist/components/Input/Input.css +41 -3
  83. package/dist/components/Input/Input.d.ts +14 -1
  84. package/dist/components/Input/Input.js +72 -6
  85. package/dist/components/Kanban/Kanban.css +5 -0
  86. package/dist/components/Kanban/Kanban.d.ts +41 -0
  87. package/dist/components/Kanban/Kanban.js +59 -27
  88. package/dist/components/Kanban/KanbanCard.d.ts +2 -0
  89. package/dist/components/Kanban/KanbanCard.js +1 -1
  90. package/dist/components/Kanban/KanbanColumn.d.ts +2 -0
  91. package/dist/components/Kanban/KanbanColumn.js +3 -0
  92. package/dist/components/Kbd/Kbd.css +66 -0
  93. package/dist/components/Kbd/Kbd.d.ts +32 -0
  94. package/dist/components/Kbd/Kbd.js +40 -0
  95. package/dist/components/Link/Link.css +1 -1
  96. package/dist/components/List/List.css +136 -0
  97. package/dist/components/List/List.d.ts +82 -0
  98. package/dist/components/List/List.js +53 -0
  99. package/dist/components/List/ListItem.d.ts +85 -0
  100. package/dist/components/List/ListItem.js +81 -0
  101. package/dist/components/Modal/Modal.css +93 -8
  102. package/dist/components/Modal/Modal.d.ts +45 -7
  103. package/dist/components/Modal/Modal.js +106 -6
  104. package/dist/components/MultiSelect/MultiSelect.css +9 -1
  105. package/dist/components/MultiSelect/MultiSelect.js +45 -8
  106. package/dist/components/OrgChart/OrgChart.css +149 -0
  107. package/dist/components/OrgChart/OrgChart.d.ts +83 -0
  108. package/dist/components/OrgChart/OrgChart.js +297 -0
  109. package/dist/components/OtpInput/OtpInput.css +93 -0
  110. package/dist/components/OtpInput/OtpInput.d.ts +60 -0
  111. package/dist/components/OtpInput/OtpInput.js +215 -0
  112. package/dist/components/Pagination/Pagination.d.ts +6 -0
  113. package/dist/components/Pagination/Pagination.js +9 -1
  114. package/dist/components/PhoneInput/PhoneInput.css +9 -1
  115. package/dist/components/PhoneInput/PhoneInput.d.ts +10 -0
  116. package/dist/components/PhoneInput/PhoneInput.js +20 -3
  117. package/dist/components/Popover/Popover.d.ts +7 -0
  118. package/dist/components/Popover/Popover.js +11 -1
  119. package/dist/components/RichTextEditor/RichTextEditor.css +203 -0
  120. package/dist/components/RichTextEditor/RichTextEditor.d.ts +83 -0
  121. package/dist/components/RichTextEditor/RichTextEditor.js +494 -0
  122. package/dist/components/SegmentedControl/SegmentedControl.d.ts +2 -0
  123. package/dist/components/SegmentedControl/SegmentedControl.js +21 -8
  124. package/dist/components/Select/Select.css +71 -1
  125. package/dist/components/Select/Select.d.ts +12 -0
  126. package/dist/components/Select/Select.js +93 -10
  127. package/dist/components/SidePanel/SidePanel.css +4 -4
  128. package/dist/components/SidePanelItem/SidePanelItem.css +7 -5
  129. package/dist/components/SidePanelSearch/SidePanelSearch.css +2 -2
  130. package/dist/components/SidePanelSection/SidePanelSection.css +7 -5
  131. package/dist/components/Stack/Stack.css +49 -0
  132. package/dist/components/Stack/Stack.d.ts +65 -7
  133. package/dist/components/Stack/Stack.js +30 -2
  134. package/dist/components/StatCard/StatCard.css +73 -0
  135. package/dist/components/StatCard/StatCard.d.ts +17 -0
  136. package/dist/components/StatCard/StatCard.js +4 -1
  137. package/dist/components/Stepper/Stepper.css +4 -1
  138. package/dist/components/Stepper/Stepper.d.ts +8 -0
  139. package/dist/components/Stepper/Stepper.js +4 -4
  140. package/dist/components/Switch/Switch.css +1 -0
  141. package/dist/components/Tabs/Tab.d.ts +15 -0
  142. package/dist/components/Tabs/Tab.js +30 -1
  143. package/dist/components/Tabs/Tabs.css +132 -0
  144. package/dist/components/Tabs/Tabs.d.ts +7 -0
  145. package/dist/components/Tabs/Tabs.js +13 -2
  146. package/dist/components/Tag/Tag.css +85 -2
  147. package/dist/components/Tag/Tag.d.ts +13 -6
  148. package/dist/components/Tag/Tag.js +1 -0
  149. package/dist/components/Text/Text.d.ts +9 -1
  150. package/dist/components/Text/Text.js +2 -2
  151. package/dist/components/Textarea/Textarea.css +11 -3
  152. package/dist/components/TimePicker/TimePicker.css +8 -0
  153. package/dist/components/TimePicker/TimePicker.d.ts +6 -0
  154. package/dist/components/TimePicker/TimePicker.js +1 -1
  155. package/dist/components/Tooltip/Tooltip.css +40 -0
  156. package/dist/components/Tooltip/Tooltip.d.ts +11 -0
  157. package/dist/components/Tooltip/Tooltip.js +114 -11
  158. package/dist/index.d.ts +25 -0
  159. package/dist/index.js +14 -0
  160. package/dist/teste/AILabel.test.d.ts +1 -0
  161. package/dist/teste/AILabel.test.js +33 -0
  162. package/dist/teste/AccordionConteudoLivre.test.d.ts +1 -0
  163. package/dist/teste/AccordionConteudoLivre.test.js +29 -0
  164. package/dist/teste/Alert.test.d.ts +1 -0
  165. package/dist/teste/Alert.test.js +27 -0
  166. package/dist/teste/AtributosRepassados.test.d.ts +1 -0
  167. package/dist/teste/AtributosRepassados.test.js +52 -0
  168. package/dist/teste/AttachmentCardIA.test.d.ts +1 -0
  169. package/dist/teste/AttachmentCardIA.test.js +89 -0
  170. package/dist/teste/AvatarGroupOverlap.test.d.ts +1 -0
  171. package/dist/teste/AvatarGroupOverlap.test.js +56 -0
  172. package/dist/teste/BadgeTag.test.d.ts +1 -0
  173. package/dist/teste/BadgeTag.test.js +42 -0
  174. package/dist/teste/BottomSheet.test.d.ts +1 -0
  175. package/dist/teste/BottomSheet.test.js +23 -0
  176. package/dist/teste/BoxItemFlex.test.d.ts +1 -0
  177. package/dist/teste/BoxItemFlex.test.js +54 -0
  178. package/dist/teste/BoxLayout.test.d.ts +1 -0
  179. package/dist/teste/BoxLayout.test.js +35 -0
  180. package/dist/teste/Button.test.d.ts +1 -0
  181. package/dist/teste/Button.test.js +27 -0
  182. package/dist/teste/Calendar.test.d.ts +1 -0
  183. package/dist/teste/Calendar.test.js +221 -0
  184. package/dist/teste/ChipsXs.test.d.ts +1 -0
  185. package/dist/teste/ChipsXs.test.js +31 -0
  186. package/dist/teste/Coachmark.test.d.ts +1 -0
  187. package/dist/teste/Coachmark.test.js +149 -0
  188. package/dist/teste/ColorPicker.test.d.ts +1 -0
  189. package/dist/teste/ColorPicker.test.js +132 -0
  190. package/dist/teste/ConfirmAIAction.test.d.ts +1 -0
  191. package/dist/teste/ConfirmAIAction.test.js +33 -0
  192. package/dist/teste/DataTableCelulaLivre.test.d.ts +1 -0
  193. package/dist/teste/DataTableCelulaLivre.test.js +76 -0
  194. package/dist/teste/DataTableDocumento.test.d.ts +1 -0
  195. package/dist/teste/DataTableDocumento.test.js +92 -0
  196. package/dist/teste/DatePicker.test.js +23 -0
  197. package/dist/teste/Dropdown.test.js +111 -0
  198. package/dist/teste/FileInputTrigger.test.d.ts +1 -0
  199. package/dist/teste/FileInputTrigger.test.js +53 -0
  200. package/dist/teste/IconPicker.test.d.ts +1 -0
  201. package/dist/teste/IconPicker.test.js +130 -0
  202. package/dist/teste/InputMascaraEAfins.test.d.ts +1 -0
  203. package/dist/teste/InputMascaraEAfins.test.js +99 -0
  204. package/dist/teste/KbdCodeBlock.test.d.ts +1 -0
  205. package/dist/teste/KbdCodeBlock.test.js +95 -0
  206. package/dist/teste/List.test.d.ts +1 -0
  207. package/dist/teste/List.test.js +153 -0
  208. package/dist/teste/Modal.test.d.ts +1 -0
  209. package/dist/teste/Modal.test.js +26 -0
  210. package/dist/teste/ModalVariantes.test.d.ts +1 -0
  211. package/dist/teste/ModalVariantes.test.js +151 -0
  212. package/dist/teste/MultiSelectErro.test.d.ts +1 -0
  213. package/dist/teste/MultiSelectErro.test.js +62 -0
  214. package/dist/teste/NomeAcessivelSsr.test.d.ts +1 -0
  215. package/dist/teste/NomeAcessivelSsr.test.js +88 -0
  216. package/dist/teste/OrgChart.test.d.ts +1 -0
  217. package/dist/teste/OrgChart.test.js +162 -0
  218. package/dist/teste/OtpInput.test.d.ts +1 -0
  219. package/dist/teste/OtpInput.test.js +143 -0
  220. package/dist/teste/PopoverMaxHeight.test.d.ts +1 -0
  221. package/dist/teste/PopoverMaxHeight.test.js +38 -0
  222. package/dist/teste/RichTextEditor.test.d.ts +1 -0
  223. package/dist/teste/RichTextEditor.test.js +287 -0
  224. package/dist/teste/RotulosTraduziveis.test.d.ts +1 -0
  225. package/dist/teste/RotulosTraduziveis.test.js +405 -0
  226. package/dist/teste/SegmentedControl.test.js +33 -0
  227. package/dist/teste/Select.test.d.ts +1 -0
  228. package/dist/teste/Select.test.js +62 -0
  229. package/dist/teste/SelectPlacementFiltro.test.d.ts +1 -0
  230. package/dist/teste/SelectPlacementFiltro.test.js +88 -0
  231. package/dist/teste/Stack.test.d.ts +1 -0
  232. package/dist/teste/Stack.test.js +57 -0
  233. package/dist/teste/StatCardRotuloTopo.test.d.ts +1 -0
  234. package/dist/teste/StatCardRotuloTopo.test.js +34 -0
  235. package/dist/teste/TabsContadorFechavel.test.d.ts +1 -0
  236. package/dist/teste/TabsContadorFechavel.test.js +79 -0
  237. package/dist/teste/Tooltip.test.d.ts +1 -0
  238. package/dist/teste/Tooltip.test.js +109 -0
  239. package/dist/teste/TooltipDark.test.d.ts +1 -0
  240. package/dist/teste/TooltipDark.test.js +31 -0
  241. package/dist/utils/calendario.d.ts +28 -0
  242. package/dist/utils/calendario.js +73 -0
  243. package/dist/utils/chart.d.ts +4 -0
  244. package/dist/utils/chart.js +3 -2
  245. package/dist/utils/html-seguro.d.ts +27 -0
  246. package/dist/utils/html-seguro.js +97 -0
  247. package/dist/utils/id.d.ts +2 -0
  248. package/dist/utils/id.js +23 -0
  249. package/dist/utils/paleta-de-cores.d.ts +26 -0
  250. package/dist/utils/paleta-de-cores.js +10 -0
  251. package/dist/utils/texto.d.ts +5 -0
  252. package/dist/utils/texto.js +5 -0
  253. package/package.json +3 -3
  254. package/src/index.ts +26 -0
  255. package/src/teste/AILabel.test.tsx +41 -0
  256. package/src/teste/AccordionConteudoLivre.test.tsx +39 -0
  257. package/src/teste/Alert.test.tsx +32 -0
  258. package/src/teste/AtributosRepassados.test.tsx +73 -0
  259. package/src/teste/AttachmentCardIA.test.tsx +126 -0
  260. package/src/teste/AvatarGroupOverlap.test.tsx +74 -0
  261. package/src/teste/BadgeTag.test.tsx +64 -0
  262. package/src/teste/BottomSheet.test.tsx +25 -0
  263. package/src/teste/BoxItemFlex.test.tsx +81 -0
  264. package/src/teste/BoxLayout.test.tsx +50 -0
  265. package/src/teste/Button.test.tsx +39 -0
  266. package/src/teste/Calendar.test.tsx +282 -0
  267. package/src/teste/ChipsXs.test.tsx +41 -0
  268. package/src/teste/Coachmark.test.tsx +198 -0
  269. package/src/teste/ColorPicker.test.tsx +153 -0
  270. package/src/teste/ConfirmAIAction.test.tsx +41 -0
  271. package/src/teste/DataTableCelulaLivre.test.tsx +103 -0
  272. package/src/teste/DataTableDocumento.test.tsx +102 -0
  273. package/src/teste/DatePicker.test.tsx +38 -0
  274. package/src/teste/Dropdown.test.tsx +146 -0
  275. package/src/teste/FileInputTrigger.test.tsx +89 -0
  276. package/src/teste/IconPicker.test.tsx +145 -0
  277. package/src/teste/InputMascaraEAfins.test.tsx +124 -0
  278. package/src/teste/KbdCodeBlock.test.tsx +106 -0
  279. package/src/teste/List.test.tsx +269 -0
  280. package/src/teste/Modal.test.tsx +28 -0
  281. package/src/teste/ModalVariantes.test.tsx +173 -0
  282. package/src/teste/MultiSelectErro.test.tsx +97 -0
  283. package/src/teste/NomeAcessivelSsr.test.tsx +110 -0
  284. package/src/teste/OrgChart.test.tsx +183 -0
  285. package/src/teste/OtpInput.test.tsx +163 -0
  286. package/src/teste/PopoverMaxHeight.test.tsx +47 -0
  287. package/src/teste/RichTextEditor.test.tsx +329 -0
  288. package/src/teste/RotulosTraduziveis.test.tsx +545 -0
  289. package/src/teste/SegmentedControl.test.tsx +57 -0
  290. package/src/teste/Select.test.tsx +97 -0
  291. package/src/teste/SelectPlacementFiltro.test.tsx +110 -0
  292. package/src/teste/Stack.test.tsx +80 -0
  293. package/src/teste/StatCardRotuloTopo.test.tsx +44 -0
  294. package/src/teste/TabsContadorFechavel.test.tsx +144 -0
  295. package/src/teste/Tooltip.test.tsx +219 -0
  296. package/src/teste/TooltipDark.test.tsx +51 -0
  297. package/src/utils/calendario.ts +78 -0
  298. package/src/utils/chart.ts +7 -2
  299. package/src/utils/html-seguro.ts +94 -0
  300. package/src/utils/id.ts +24 -0
  301. package/src/utils/paleta-de-cores.ts +34 -0
  302. package/src/utils/texto.ts +5 -0
@@ -0,0 +1,85 @@
1
+ /** Elemento interativo (ou não) que ocupa a linha inteira. */
2
+ export type ListItemTag = "button" | "a" | "div";
3
+ /**
4
+ * ListItem — linha de lista inteira clicável, com conteúdo livre.
5
+ *
6
+ * Renderiza um `<li>` que contém UM elemento (`button`, `a` ou `div`) do tamanho
7
+ * da linha: o alvo de clique e de foco é a linha toda, não só o título. Por isso
8
+ * o ListItem vive dentro de um `List` (ou de um `ul`/`ol`, como `Stack as="ul"`).
9
+ *
10
+ * O conteúdo se encaixa por slots, todos opcionais: `start` (avatar, ícone,
11
+ * checkbox decorativo), `title`, `subtitle`, `meta` (data, contexto), `end`
12
+ * (badge, seta, valor) e o conteúdo padrão, que entra abaixo de `meta`. `title`,
13
+ * `subtitle` e `meta` também aceitam texto direto por prop.
14
+ *
15
+ * Elemento: sem `as`, vira `a` quando há `href` e `button` nos outros casos.
16
+ * `as="div"` é a linha que não navega nem age (só mostra), e vira acionável
17
+ * (role="button", Enter e Espaço) se receber `onClick`. Controles dentro de uma
18
+ * linha clicável (botão, checkbox) quebram o HTML: se a linha precisa deles,
19
+ * use `as="div"` sem `onClick` e ponha a ação num deles.
20
+ *
21
+ * `selected` marca o item atual (fundo azul-claro e `aria-current`). `disabled`
22
+ * tira a linha da ordem de tabulação e bloqueia o clique.
23
+ *
24
+ * Atributos HTML (`id`, `style`, `role`, `tabIndex`, `data-*`, `aria-*`) vão
25
+ * para o elemento interativo, que é quem recebe `aria-label` quando a linha não
26
+ * tem texto visível. `title` NÃO é o atributo HTML: é o título da linha.
27
+ * @property {string} as - Elemento da linha: 'button' | 'a' | 'div'. Padrão: 'a' com href, senão 'button'
28
+ * @property {string} href - Destino do link (vira as="a")
29
+ * @property {string} target - Destino do link: '_blank' ganha rel="noopener noreferrer"
30
+ * @property {string} rel - Relação do link (sobrescreve o padrão do target)
31
+ * @property {boolean} selected - Item atual: fundo de seleção e aria-current
32
+ * @property {boolean} disabled - Bloqueia clique e foco
33
+ * @property {any} title - Título da linha: texto, ou slot `title` (nó)
34
+ * @property {any} subtitle - Segunda linha: texto, ou slot `subtitle` (nó)
35
+ * @property {any} meta - Terceira linha, menor (data, contexto): texto, ou slot `meta` (nó)
36
+ * @property {any} start - Slot `start`: conteúdo antes do texto (avatar, ícone)
37
+ * @property {any} end - Slot `end`: conteúdo no fim da linha (badge, seta, valor)
38
+ * @property {function} onClick - Callback do clique (ou de Enter/Espaço no as="div")
39
+ * @property {string} className - Classes CSS adicionais, no elemento interativo
40
+ * @slot start - Conteúdo antes do texto.
41
+ * @slot title - Título (substitui a prop `title`).
42
+ * @slot subtitle - Segunda linha (substitui a prop `subtitle`).
43
+ * @slot meta - Terceira linha (substitui a prop `meta`).
44
+ * @slot end - Conteúdo no fim da linha.
45
+ * @quandoUsar Itens de uma lista em que a linha toda é a ação: documentos não lidos, notificações, resultados de busca, opções de menu de filtro, itens de navegação secundária. Hover, foco visível e seleção já vêm resolvidos.
46
+ * @quandoNaoUsar Para dados comparados coluna a coluna, use `DataTable`. Para um cartão com título, ações e elevação própria, use `Card`. Para um botão solto fora de lista, use `Button`. Para a navegação principal do produto, use `SidePanelItem` ou `AppNavItem`.
47
+ */
48
+ /** Elemento interativo (ou não) que ocupa a linha inteira. */
49
+ export interface ListItemProps {
50
+ /** Elemento da linha. Sem `as`: `a` quando há `href`, senão `button`. */
51
+ as?: ListItemTag;
52
+ /** Destino do link (liga `as="a"`). */
53
+ href?: string;
54
+ /** Destino do link. `_blank` ganha `rel="noopener noreferrer"`. */
55
+ target?: string;
56
+ /** Relação do link. Sobrescreve o padrão do `target`. */
57
+ rel?: string;
58
+ /** Item atual: fundo de seleção e `aria-current`. @default false */
59
+ selected?: boolean;
60
+ /** Bloqueia clique e foco. @default false */
61
+ disabled?: boolean;
62
+ /** Título da linha. Texto, ou slot `title` para um nó. */
63
+ title?: any;
64
+ /** Segunda linha. Texto, ou slot `subtitle` para um nó. */
65
+ subtitle?: any;
66
+ /** Terceira linha, menor (data, contexto). Texto, ou slot `meta` para um nó. */
67
+ meta?: any;
68
+ /** Conteúdo antes do texto (avatar, ícone). No Vue, slot `start`. */
69
+ start?: any;
70
+ /** Conteúdo no fim da linha (badge, seta, valor). No Vue, slot `end`. */
71
+ end?: any;
72
+ /** Chamado no clique da linha (ou em Enter/Espaço no `as="div"`). */
73
+ onClick?: (event: any) => void;
74
+ /** Classes CSS adicionais, no elemento interativo. */
75
+ className?: string;
76
+ /** ID HTML do elemento interativo. */
77
+ id?: string;
78
+ /** Atributos HTML repassados ao elemento interativo (style, data-*, aria-*…). */
79
+ style?: any;
80
+ [key: string]: any;
81
+ /** Conteúdo livre, abaixo de `meta`. */
82
+ children?: any;
83
+ }
84
+ declare function ListItem(props: ListItemProps): import("react/jsx-runtime").JSX.Element;
85
+ export default ListItem;
@@ -0,0 +1,81 @@
1
+ "use client";
2
+ import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import Text from "../Text/Text";
4
+ function ListItem(props) {
5
+ function elementTag() {
6
+ if (props.as)
7
+ return props.as;
8
+ return props.href ? "a" : "button";
9
+ }
10
+ function isInteractive() {
11
+ return elementTag() !== "div" || !!props.onClick;
12
+ }
13
+ function classes() {
14
+ return [
15
+ "umds-list-item",
16
+ isInteractive() ? "umds-list-item--interactive" : "",
17
+ props.selected ? "umds-list-item--selected" : "",
18
+ props.disabled ? "umds-list-item--disabled" : "",
19
+ props.className,
20
+ ]
21
+ .filter(Boolean)
22
+ .join(" ");
23
+ }
24
+ function ariaCurrent() {
25
+ return props.selected ? "true" : undefined;
26
+ }
27
+ function ariaDisabled() {
28
+ return props.disabled ? "true" : undefined;
29
+ }
30
+ function hrefValue() {
31
+ return props.disabled ? undefined : props.href;
32
+ }
33
+ function relValue() {
34
+ if (props.rel)
35
+ return props.rel;
36
+ return props.target === "_blank" ? "noopener noreferrer" : undefined;
37
+ }
38
+ function divRole() {
39
+ return props.onClick ? "button" : undefined;
40
+ }
41
+ function divTabIndex() {
42
+ if (!props.onClick)
43
+ return undefined;
44
+ return props.disabled ? -1 : 0;
45
+ }
46
+ function handleClick(event) {
47
+ if (props.disabled) {
48
+ if (event && event.preventDefault)
49
+ event.preventDefault();
50
+ return;
51
+ }
52
+ if (props.onClick)
53
+ props.onClick(event);
54
+ }
55
+ function handleKeyDown(event) {
56
+ if (!props.onClick || props.disabled || !event)
57
+ return;
58
+ // Só a própria linha aciona: Enter/Espaço dentro de um controle interno não.
59
+ if (event.target !== event.currentTarget)
60
+ return;
61
+ if (event.key !== "Enter" && event.key !== " ")
62
+ return;
63
+ event.preventDefault();
64
+ props.onClick(event);
65
+ }
66
+ function htmlAttrs() {
67
+ const out = {};
68
+ for (const chave in props) {
69
+ if (chave.indexOf("data-") === 0 ||
70
+ chave.indexOf("aria-") === 0 ||
71
+ chave === "style" ||
72
+ chave === "role" ||
73
+ chave === "tabIndex") {
74
+ out[chave] = props[chave];
75
+ }
76
+ }
77
+ return out;
78
+ }
79
+ return (_jsxs("li", { className: "umds-list__item", children: [elementTag() === "button" ? (_jsxs("button", { type: "button", id: props.id, disabled: props.disabled, "aria-current": ariaCurrent(), onClick: (event) => handleClick(event), ...htmlAttrs(), className: classes(), children: [props.start ? (_jsx("span", { className: "umds-list-item__start", children: _jsx(_Fragment, { children: props.start }) })) : null, _jsxs("span", { className: "umds-list-item__body", children: [props.title ? (_jsx("span", { className: "umds-list-item__title", children: _jsx(Text, { variant: "body2", as: "span", weight: "semibold", color: "inherit", children: _jsx(_Fragment, { children: props.title }) }) })) : null, props.subtitle ? (_jsx("span", { className: "umds-list-item__subtitle", children: _jsx(Text, { variant: "body2", as: "span", color: "inherit", children: _jsx(_Fragment, { children: props.subtitle }) }) })) : null, props.meta ? (_jsx("span", { className: "umds-list-item__meta", children: _jsx(Text, { variant: "caption", as: "span", color: "inherit", children: _jsx(_Fragment, { children: props.meta }) }) })) : null, _jsx(_Fragment, { children: props.children })] }), props.end ? (_jsx("span", { className: "umds-list-item__end", children: _jsx(_Fragment, { children: props.end }) })) : null] })) : null, elementTag() === "a" ? (_jsxs("a", { id: props.id, href: hrefValue(), target: props.target, rel: relValue(), "aria-current": ariaCurrent(), "aria-disabled": ariaDisabled(), onClick: (event) => handleClick(event), ...htmlAttrs(), className: classes(), children: [props.start ? (_jsx("span", { className: "umds-list-item__start", children: _jsx(_Fragment, { children: props.start }) })) : null, _jsxs("span", { className: "umds-list-item__body", children: [props.title ? (_jsx("span", { className: "umds-list-item__title", children: _jsx(Text, { variant: "body2", as: "span", weight: "semibold", color: "inherit", children: _jsx(_Fragment, { children: props.title }) }) })) : null, props.subtitle ? (_jsx("span", { className: "umds-list-item__subtitle", children: _jsx(Text, { variant: "body2", as: "span", color: "inherit", children: _jsx(_Fragment, { children: props.subtitle }) }) })) : null, props.meta ? (_jsx("span", { className: "umds-list-item__meta", children: _jsx(Text, { variant: "caption", as: "span", color: "inherit", children: _jsx(_Fragment, { children: props.meta }) }) })) : null, _jsx(_Fragment, { children: props.children })] }), props.end ? (_jsx("span", { className: "umds-list-item__end", children: _jsx(_Fragment, { children: props.end }) })) : null] })) : null, elementTag() === "div" ? (_jsxs("div", { id: props.id, role: divRole(), tabIndex: divTabIndex(), "aria-current": ariaCurrent(), "aria-disabled": ariaDisabled(), onClick: (event) => handleClick(event), onKeyDown: (event) => handleKeyDown(event), ...htmlAttrs(), className: classes(), children: [props.start ? (_jsx("span", { className: "umds-list-item__start", children: _jsx(_Fragment, { children: props.start }) })) : null, _jsxs("span", { className: "umds-list-item__body", children: [props.title ? (_jsx("span", { className: "umds-list-item__title", children: _jsx(Text, { variant: "body2", as: "span", weight: "semibold", color: "inherit", children: _jsx(_Fragment, { children: props.title }) }) })) : null, props.subtitle ? (_jsx("span", { className: "umds-list-item__subtitle", children: _jsx(Text, { variant: "body2", as: "span", color: "inherit", children: _jsx(_Fragment, { children: props.subtitle }) }) })) : null, props.meta ? (_jsx("span", { className: "umds-list-item__meta", children: _jsx(Text, { variant: "caption", as: "span", color: "inherit", children: _jsx(_Fragment, { children: props.meta }) }) })) : null, _jsx(_Fragment, { children: props.children })] }), props.end ? (_jsx("span", { className: "umds-list-item__end", children: _jsx(_Fragment, { children: props.end }) })) : null] })) : null] }));
80
+ }
81
+ export default ListItem;
@@ -29,6 +29,7 @@
29
29
  left: 0;
30
30
  right: 0;
31
31
  bottom: 0;
32
+ /* stylelint-disable-next-line 1ds/cor-por-token -- o DS não tem token de scrim/overlay (candidato a novo token) */
32
33
  background-color: rgba(0, 0, 0, 0.4); /* overlay escuro — sem token 1DS: candidato a novo token */
33
34
  backdrop-filter: blur(4px);
34
35
  animation: umds-fade-in 0.2s ease-out;
@@ -214,7 +215,8 @@
214
215
  Cor: sempre token; as que o DS não tem vão no vizinho já decidido:
215
216
  #222222 título → neutral-dark-pure #333333
216
217
  #e1e3e6 bordas → neutral-light-medium #EBEBEB
217
- #7d7d7d apoio → neutral-dark-medium #7D7D7D (bate exato)
218
+ #7d7d7d apoio → neutral-dark-down #565656 (o #7D7D7D do produto dá
219
+ 4,11:1 sobre branco e reprova o WCAG 1.4.3 — ver subtítulo)
218
220
  Raio: 8px do DS, não os 12px do produto — a rodada de agosto fez 8 universal.
219
221
  Os cantos de baixo ficam arredondados porque o diálogo recorta (overflow).
220
222
  ───────────────────────────────────────────────────────────────────────────── */
@@ -234,14 +236,14 @@
234
236
  align-items: flex-start;
235
237
  justify-content: space-between;
236
238
  gap: var(--umds-primitive-spacing-mini); /* 12px */
237
- padding: 18px 22px 14px; /* produto: 18px 22px 14px */
239
+ padding: var(--umds-primitive-spacing-xxxs) var(--umds-primitive-spacing-xxs); /* 16px 24px — mesma altura total do produto (18px 22px 14px) */
238
240
  border-bottom: 1px solid var(--umds-semantic-color-neutral-light-medium);
239
241
  flex-shrink: 0;
240
242
  box-sizing: border-box;
241
243
  }
242
244
 
243
245
  .umds-modal--base .umds-modal__text-group {
244
- gap: 3px; /* produto: 3px entre título e subtítulo */
246
+ gap: var(--umds-primitive-spacing-quarck); /* 4px entre título e subtítulo (produto: 3px) */
245
247
  min-width: 0;
246
248
  }
247
249
 
@@ -253,14 +255,17 @@
253
255
 
254
256
  .umds-modal__subtitle {
255
257
  font-size: var(--umds-primitive-font-size-xxxs); /* 12px */
256
- color: var(--umds-semantic-color-neutral-dark-medium);
258
+ /* neutral-dark-down, não neutral-dark-medium: o subtítulo é TEXTO (vira a
259
+ aria-describedby do diálogo) e o #7D7D7D dá 4,11:1 sobre branco — abaixo
260
+ dos 4,5:1 do WCAG 1.4.3. #565656 dá 7,34:1 e passa nos 13 temas. */
261
+ color: var(--umds-semantic-color-neutral-dark-down);
257
262
  }
258
263
 
259
264
  /* ── Controles de janela ──────────────────────────────────────────────────── */
260
265
  .umds-modal__header-actions {
261
266
  display: flex;
262
267
  align-items: center;
263
- gap: 2px; /* produto: 2px — os controles andam juntos */
268
+ gap: var(--umds-primitive-spacing-micro); /* 2px — os controles andam juntos */
264
269
  flex-shrink: 0;
265
270
  }
266
271
 
@@ -315,7 +320,7 @@
315
320
  flex: 1;
316
321
  min-height: 0;
317
322
  overflow-y: auto;
318
- padding: 20px 22px; /* produto: 20px 22px */
323
+ padding: var(--umds-primitive-spacing-xxxs) var(--umds-primitive-spacing-xxs); /* 16px 24px (produto: 20px 22px) */
319
324
  display: flex;
320
325
  flex-direction: column;
321
326
  gap: var(--umds-primitive-spacing-xxxs); /* 16px */
@@ -327,9 +332,9 @@
327
332
  display: flex;
328
333
  align-items: center;
329
334
  justify-content: space-between;
330
- gap: 10px; /* produto: 10px */
335
+ gap: var(--umds-primitive-spacing-nano); /* 8px (produto: 10px) */
331
336
  margin-top: 0;
332
- padding: 14px 22px; /* produto: 14px 22px */
337
+ padding: var(--umds-primitive-spacing-xxxs) var(--umds-primitive-spacing-xxs); /* 16px 24px (produto: 14px 22px) */
333
338
  border-top: 1px solid var(--umds-semantic-color-neutral-light-medium);
334
339
  background: var(--umds-semantic-color-neutral-light-pure);
335
340
  /* Levanta o rodapé do conteúdo que passa por baixo dele ao rolar.
@@ -370,6 +375,86 @@
370
375
  border-radius: 0;
371
376
  }
372
377
 
378
+ /* ── variant="primary": cabeçalho cheio na cor primária ──
379
+ Título, subtítulo e controles em branco (neutral-light-pure, o mesmo par que
380
+ o Button primary usa sobre primary-pure). */
381
+ .umds-modal--primary .umds-modal__header {
382
+ background-color: var(--umds-semantic-color-primary-pure);
383
+ border-bottom-color: var(--umds-semantic-color-primary-pure);
384
+ }
385
+
386
+ .umds-modal--primary .umds-modal__title,
387
+ .umds-modal--primary .umds-modal__subtitle {
388
+ color: var(--umds-semantic-color-neutral-light-pure);
389
+ }
390
+
391
+ .umds-modal--primary .umds-modal__ctrl {
392
+ color: var(--umds-semantic-color-neutral-light-pure);
393
+ }
394
+
395
+ .umds-modal--primary .umds-modal__ctrl:hover,
396
+ .umds-modal--primary .umds-modal__ctrl--ativo,
397
+ .umds-modal--primary .umds-modal__ctrl--close:hover {
398
+ background: var(--umds-semantic-color-primary-dark);
399
+ color: var(--umds-semantic-color-neutral-light-pure);
400
+ }
401
+
402
+ .umds-modal--primary .umds-modal__ctrl:focus-visible {
403
+ outline-color: var(--umds-semantic-color-neutral-light-pure);
404
+ }
405
+
406
+ .umds-modal--primary .umds-modal__ctrl-divider {
407
+ background: var(--umds-semantic-color-primary-medium);
408
+ }
409
+
410
+ /* ── responsive: abaixo do breakpoint vira painel que sobe pela borda de baixo ──
411
+ Mesma anatomia do BottomSheet (largura total, cantos de cima arredondados,
412
+ alça, entrada por baixo). Quem decide o breakpoint é o componente (media
413
+ query em JS, para a prop `responsiveBreakpoint` valer). */
414
+ .umds-modal-root--sheet {
415
+ align-items: flex-end;
416
+ padding: 0;
417
+ }
418
+
419
+ .umds-modal.umds-modal--sheet {
420
+ width: 100%;
421
+ max-width: none;
422
+ max-height: 90vh;
423
+ border-bottom-left-radius: 0;
424
+ border-bottom-right-radius: 0;
425
+ animation: umds-modal-sheet-in var(--umds-semantic-motion-duration-base)
426
+ var(--umds-semantic-motion-easing-standard);
427
+ }
428
+
429
+ @keyframes umds-modal-sheet-in {
430
+ from {
431
+ transform: translateY(100%);
432
+ }
433
+ to {
434
+ transform: translateY(0);
435
+ }
436
+ }
437
+
438
+ .umds-modal__grabber {
439
+ display: flex;
440
+ align-items: center;
441
+ justify-content: center;
442
+ padding: var(--umds-primitive-spacing-nano) 0 0;
443
+ flex-shrink: 0;
444
+ }
445
+
446
+ .umds-modal--primary .umds-modal__grabber {
447
+ background-color: var(--umds-semantic-color-primary-pure);
448
+ }
449
+
450
+ .umds-modal__grabber-bar {
451
+ display: block;
452
+ width: var(--umds-primitive-spacing-sm); /* 40px */
453
+ height: var(--umds-primitive-spacing-quarck); /* 4px */
454
+ border-radius: var(--umds-primitive-border-radius-pill);
455
+ background-color: var(--umds-semantic-color-neutral-light-down);
456
+ }
457
+
373
458
  /* ── Alto contraste ──
374
459
  No 1doc-high-contrast o painel e a página são pretos e a sombra (preta)
375
460
  não aparece: sem traço, o modal não tem borda visível. O traço é um
@@ -27,11 +27,43 @@ export interface ModalProps {
27
27
  * - "positive": sucesso (verde, ícone circle-check).
28
28
  * - "negative": erro/falha (vermelho, ícone circle-exclamation).
29
29
  * - "info": atenção (laranja, ícone triangle-exclamation).
30
+ * - "primary": modal base com o cabeçalho cheio na cor primária (título e
31
+ * controles em branco). Não é diálogo de feedback: mantém as três faixas.
30
32
  * @default 'default'
31
33
  */
32
- variant?: "default" | "positive" | "negative" | "info";
33
- /** Título em destaque */
34
+ variant?: "default" | "positive" | "negative" | "info" | "primary";
35
+ /**
36
+ * Largura do modal, qualquer valor CSS (`"600px"`, `"60vw"`). Sem
37
+ * `maxWidth`, o teto passa a ser a própria tela (o 498px do `md` não
38
+ * segura mais). Vence o `size`. Com `windowControls`, vale só no modo
39
+ * normal: expandido e tela cheia mandam no tamanho.
40
+ */
41
+ width?: string;
42
+ /** Largura máxima, qualquer valor CSS. Vence o teto do `size`. */
43
+ maxWidth?: string;
44
+ /**
45
+ * Abaixo do breakpoint (`responsiveBreakpoint`), o modal vira um painel que
46
+ * sobe pela borda de baixo, como o `BottomSheet`: largura total, cantos de
47
+ * cima arredondados, alça no topo. Acima dele, continua centralizado. É
48
+ * o mesmo componente reorganizado, então título, corpo e rodapé não mudam.
49
+ * @default false
50
+ */
51
+ responsive?: boolean;
52
+ /** Largura da tela, em px, abaixo da qual o `responsive` vira painel. Lida na montagem. @default 640 */
53
+ responsiveBreakpoint?: number;
54
+ /**
55
+ * Título em destaque. Com título, o diálogo é nomeado por ele
56
+ * (`aria-labelledby`) e `ariaLabel` é ignorado.
57
+ */
34
58
  title?: string;
59
+ /**
60
+ * Nome acessível do diálogo quando não há `title` (vira `aria-label`).
61
+ * Sem título e sem esta prop, o leitor de tela anuncia só "diálogo", sem
62
+ * dizer do quê — informe sempre que o modal não tiver título visível. Como
63
+ * último recurso o componente usa "Diálogo", para o `role="dialog"` nunca
64
+ * sair anônimo.
65
+ */
66
+ ariaLabel?: string;
35
67
  /** Texto de descrição/apoio */
36
68
  description?: string;
37
69
  /** Texto do botão de confirmação/ação primária */
@@ -68,12 +100,18 @@ export interface ModalProps {
68
100
  /** Se verdadeiro, renderiza o modal inline (sem fixed/overlay), útil para documentação */
69
101
  inline?: boolean;
70
102
  /**
71
- * Controles de janela no cabeçalho: restaurar, expandir, tela cheia e
72
- * minimizar, antes do ×. É tudo ou nada — ou o modal tem só o ×, ou tem o
73
- * conjunto inteiro. Ligado, o modal passa a mudar de tamanho sozinho.
103
+ * Controles de janela no cabeçalho, antes do ×. Duas formas:
104
+ * - `true`: o conjunto inteiro (restaurar, expandir, tela cheia e minimizar).
105
+ * O modal passa a mudar de tamanho sozinho (normal 780px, expandido, tela
106
+ * cheia).
107
+ * - uma lista com os que quiser, na ordem fixa do cabeçalho:
108
+ * `["expand", "fullscreen"]`, `["fullscreen"]`... Os nomes são `normal`,
109
+ * `expand`, `fullscreen` e `minimize`. Sem `normal` na lista, clicar de
110
+ * novo no modo ativo volta ao normal, e o modo normal usa o tamanho do
111
+ * próprio modal (`size`, `width`), não os 780px do conjunto inteiro.
74
112
  */
75
- windowControls?: boolean;
76
- /** Acionado no botão minimizar. Só existe com `windowControls`. */
113
+ windowControls?: boolean | Array<"normal" | "expand" | "fullscreen" | "minimize">;
114
+ /** Acionado no botão minimizar. Só existe quando `minimize` está entre os controles. */
77
115
  onMinimize?: (event?: any) => void;
78
116
  /**
79
117
  * Região esquerda do rodapé — conteúdo de apoio que não é botão: a caixa
@@ -12,6 +12,7 @@ function Modal(props) {
12
12
  const escCleanupRef = useRef(null);
13
13
  const closeFnRef = useRef(null);
14
14
  const previousFocusRef = useRef(null);
15
+ const mediaCleanupRef = useRef(null);
15
16
  const [lastOpen, setLastOpen] = useState(() => false);
16
17
  const [uid, setUid] = useState(() => "umds-modal-" + Math.random().toString(36).slice(2, 9));
17
18
  function titleId() {
@@ -23,22 +24,92 @@ function Modal(props) {
23
24
  function labelledBy() {
24
25
  return props.title ? uid + "-title" : undefined;
25
26
  }
27
+ function nomeAcessivel() {
28
+ if (props.title)
29
+ return undefined;
30
+ return props.ariaLabel || "Diálogo";
31
+ }
26
32
  function describedBy() {
27
33
  return props.description ? uid + "-description" : undefined;
28
34
  }
29
35
  function ehFeedback() {
30
- const temVariante = props.variant ? props.variant !== "default" : false;
36
+ // `primary` é só o cabeçalho cheio do modal base: não é feedback.
37
+ const temVariante = props.variant
38
+ ? props.variant !== "default" && props.variant !== "primary"
39
+ : false;
31
40
  return temVariante || props.layout === "dialog";
32
41
  }
33
42
  const [modoAtual, setModoAtual] = useState(() => "normal");
43
+ const [isCompact, setIsCompact] = useState(() => false);
44
+ function ehSheet() {
45
+ return !!props.responsive && isCompact;
46
+ }
47
+ function temNormal() {
48
+ if (props.responsive && isCompact)
49
+ return false;
50
+ if (props.windowControls === true)
51
+ return true;
52
+ return (Array.isArray(props.windowControls) &&
53
+ props.windowControls.includes("normal"));
54
+ }
55
+ function temExpandir() {
56
+ if (props.responsive && isCompact)
57
+ return false;
58
+ if (props.windowControls === true)
59
+ return true;
60
+ return (Array.isArray(props.windowControls) &&
61
+ props.windowControls.includes("expand"));
62
+ }
63
+ function temTelaCheia() {
64
+ if (props.responsive && isCompact)
65
+ return false;
66
+ if (props.windowControls === true)
67
+ return true;
68
+ return (Array.isArray(props.windowControls) &&
69
+ props.windowControls.includes("fullscreen"));
70
+ }
71
+ function temMinimizar() {
72
+ if (props.responsive && isCompact)
73
+ return false;
74
+ if (props.windowControls === true)
75
+ return true;
76
+ return (Array.isArray(props.windowControls) &&
77
+ props.windowControls.includes("minimize"));
78
+ }
79
+ function temControles() {
80
+ if (props.responsive && isCompact)
81
+ return false;
82
+ if (props.windowControls === true)
83
+ return true;
84
+ return (Array.isArray(props.windowControls) && props.windowControls.length > 0);
85
+ }
86
+ function janelaPorLista() {
87
+ return Array.isArray(props.windowControls);
88
+ }
89
+ function estiloDoDialogo() {
90
+ if (!props.width && !props.maxWidth)
91
+ return undefined;
92
+ if (props.responsive && isCompact)
93
+ return undefined;
94
+ if (props.windowControls && modoAtual !== "normal")
95
+ return undefined;
96
+ const estilo = {};
97
+ if (props.width)
98
+ estilo.width = props.width;
99
+ if (props.maxWidth)
100
+ estilo.maxWidth = props.maxWidth;
101
+ else
102
+ estilo.maxWidth = "100%";
103
+ return estilo;
104
+ }
34
105
  function irParaNormal() {
35
106
  setModoAtual("normal");
36
107
  }
37
108
  function irParaExpandido() {
38
- setModoAtual("expanded");
109
+ setModoAtual(modoAtual === "expanded" && !temNormal() ? "normal" : "expanded");
39
110
  }
40
111
  function irParaTelaCheia() {
41
- setModoAtual("fullscreen");
112
+ setModoAtual(modoAtual === "fullscreen" && !temNormal() ? "normal" : "fullscreen");
42
113
  }
43
114
  function classeDoControle(modo) {
44
115
  return modo === modoAtual
@@ -48,6 +119,12 @@ function Modal(props) {
48
119
  function classeDaJanela() {
49
120
  if (!props.windowControls)
50
121
  return "";
122
+ if (props.responsive && isCompact)
123
+ return "";
124
+ // Lista de controles: o normal é o tamanho do próprio modal.
125
+ if (Array.isArray(props.windowControls) && modoAtual === "normal") {
126
+ return "";
127
+ }
51
128
  return `umds-modal--janela-${modoAtual}`;
52
129
  }
53
130
  function temRodape() {
@@ -61,6 +138,7 @@ function Modal(props) {
61
138
  props.inline ? "umds-modal-root--inline" : "umds-modal-root",
62
139
  props.open ? "umds-modal-root--open" : "umds-modal-root--closed",
63
140
  props.size === "fullscreen" ? "umds-modal-root--fullscreen" : "",
141
+ props.responsive && isCompact ? "umds-modal-root--sheet" : "",
64
142
  ]
65
143
  .filter(Boolean)
66
144
  .join(" ");
@@ -72,6 +150,7 @@ function Modal(props) {
72
150
  props.size && props.size !== "md" ? `umds-modal--${props.size}` : "",
73
151
  ehFeedback() ? "umds-modal--feedback" : "umds-modal--base",
74
152
  classeDaJanela(),
153
+ props.responsive && isCompact ? "umds-modal--sheet" : "",
75
154
  props.className,
76
155
  ]
77
156
  .filter(Boolean)
@@ -103,6 +182,10 @@ function Modal(props) {
103
182
  function handleEscClose(event) {
104
183
  if (props.closeOnEsc === false)
105
184
  return;
185
+ // Quem já usou o Esc (Select, DatePicker, Popover aberto dentro do
186
+ // modal) chamou preventDefault: a tecla é dele, o modal não fecha.
187
+ if (event && event.defaultPrevented)
188
+ return;
106
189
  if (!isTopOverlay(uid))
107
190
  return;
108
191
  handleClose(event);
@@ -168,10 +251,23 @@ function Modal(props) {
168
251
  closeFnRef.current(event);
169
252
  }
170
253
  };
171
- document.addEventListener("keydown", watcher, true);
254
+ // No borbulho (false), não na captura: o ouvinte do document só vê a tecla
255
+ // depois que o componente aberto dentro do modal teve a vez de consumi-la.
256
+ document.addEventListener("keydown", watcher, false);
172
257
  escCleanupRef.current = () => {
173
- document.removeEventListener("keydown", watcher, true);
258
+ document.removeEventListener("keydown", watcher, false);
174
259
  };
260
+ if (typeof window !== "undefined" && window.matchMedia) {
261
+ const consulta = window.matchMedia("(max-width: " + (props.responsiveBreakpoint || 640) + "px)");
262
+ const aoMudar = (e) => {
263
+ setIsCompact(!!e.matches);
264
+ };
265
+ setIsCompact(!!consulta.matches);
266
+ consulta.addEventListener("change", aoMudar);
267
+ mediaCleanupRef.current = () => {
268
+ consulta.removeEventListener("change", aoMudar);
269
+ };
270
+ }
175
271
  syncOpenState();
176
272
  }, []);
177
273
  useEffect(() => {
@@ -185,9 +281,13 @@ function Modal(props) {
185
281
  escCleanupRef.current();
186
282
  escCleanupRef.current = null;
187
283
  }
284
+ if (mediaCleanupRef.current) {
285
+ mediaCleanupRef.current();
286
+ mediaCleanupRef.current = null;
287
+ }
188
288
  removeOverlay(uid);
189
289
  };
190
290
  }, []);
191
- return (_jsx(_Fragment, { children: props.open ? (_jsx(_Fragment, { children: _jsxs("div", { className: rootClasses(), children: [_jsx("div", { className: "umds-modal-overlay", onClick: (e) => handleOverlayClick(e) }), _jsxs("div", { role: "dialog", "aria-modal": "true", ref: dialogRef, "aria-labelledby": labelledBy(), "aria-describedby": describedBy(), tabIndex: -1, onKeyDown: (event) => handleTrapKeydown(event), className: modalClasses(), children: [!ehFeedback() ? (_jsxs(_Fragment, { children: [_jsxs("div", { className: "umds-modal__header", children: [_jsxs("div", { className: "umds-modal__text-group", children: [props.title ? (_jsx("span", { className: "umds-modal__title", id: titleId(), children: props.title })) : null, props.description ? (_jsx("span", { className: "umds-modal__subtitle", id: descriptionId(), children: props.description })) : null] }), _jsxs("div", { className: "umds-modal__header-actions", children: [props.windowControls ? (_jsxs(_Fragment, { children: [_jsx("button", { type: "button", title: props.normalModeLabel || "Modo normal", "aria-label": props.normalModeLabel || "Modo normal", "aria-pressed": modoAtual === "normal", onClick: (event) => irParaNormal(), className: classeDoControle("normal"), children: _jsx(Icon, { customSize: "14px", icon: faWindowRestore }) }), _jsx("button", { type: "button", title: props.expandLabel || "Expandir", "aria-label": props.expandLabel || "Expandir", "aria-pressed": modoAtual === "expanded", onClick: (event) => irParaExpandido(), className: classeDoControle("expanded"), children: _jsx(Icon, { customSize: "14px", icon: faUpRightAndDownLeftFromCenter }) }), _jsx("button", { type: "button", title: props.fullscreenLabel || "Tela cheia", "aria-label": props.fullscreenLabel || "Tela cheia", "aria-pressed": modoAtual === "fullscreen", onClick: (event) => irParaTelaCheia(), className: classeDoControle("fullscreen"), children: _jsx(Icon, { customSize: "14px", icon: faExpand }) }), _jsx("button", { type: "button", className: "umds-modal__ctrl", title: props.minimizeLabel || "Minimizar", "aria-label": props.minimizeLabel || "Minimizar", onClick: (e) => props.onMinimize?.(e), children: _jsx(Icon, { customSize: "14px", icon: faMinus }) }), _jsx("span", { className: "umds-modal__ctrl-divider" })] })) : null, !props.hideCloseButton ? (_jsx("button", { type: "button", className: "umds-modal__ctrl umds-modal__ctrl--close", onClick: (e) => handleClose(e), title: props.closeLabel || "Fechar", "aria-label": props.closeLabel || "Fechar", children: _jsx(Icon, { customSize: "16px", icon: faXmark }) })) : null] })] }), _jsx("div", { className: "umds-modal__body", children: _jsx(_Fragment, { children: props.children }) }), temRodape() ? (_jsxs("div", { className: "umds-modal__footer", children: [_jsx("div", { className: "umds-modal__footer-start", children: props.footerStart ? _jsx(_Fragment, { children: props.footerStart }) : null }), _jsxs("div", { className: "umds-modal__footer-end", children: [props.footerSlot ? _jsx(_Fragment, { children: props.footerSlot }) : null, !props.footerSlot ? (_jsxs(_Fragment, { children: [props.cancelLabel ? (_jsx(Button, { variant: "text", onClick: (e) => props.onCancel?.(e), children: props.cancelLabel })) : null, props.confirmLabel ? (_jsx(Button, { variant: "primary", onClick: (e) => props.onConfirm?.(e), children: props.confirmLabel })) : null] })) : null] })] })) : null] })) : null, ehFeedback() ? (_jsxs(_Fragment, { children: [!props.hideCloseButton ? (_jsx("div", { className: "umds-modal__close-wrapper", children: _jsx("button", { className: "umds-modal__close-button", onClick: (e) => handleClose(e), "aria-label": props.closeLabel || "Fechar", children: _jsx(Icon, { size: "sm", icon: faXmark }) }) })) : null, _jsxs("div", { className: "umds-modal__content", children: [_jsxs("div", { className: "umds-modal__header umds-modal__header--feedback", children: [props.variant && props.variant !== "default" ? (_jsx("div", { className: `umds-modal__icon ${iconVariantClass()}`, children: _jsx(Icon, { customSize: "40px", icon: iconName() }) })) : null, _jsxs("div", { className: "umds-modal__text-group", children: [props.title ? (_jsx(Text, { variant: "h5", weight: "bold", id: titleId(), children: props.title })) : null, props.description ? (_jsx(Text, { variant: "body2", color: "secondary", id: descriptionId(), children: props.description })) : null] })] }), _jsx(_Fragment, { children: props.children }), _jsxs("div", { className: "umds-modal__footer umds-modal__footer--feedback", children: [props.footerSlot ? _jsx(_Fragment, { children: props.footerSlot }) : null, !props.footerSlot ? (_jsxs(_Fragment, { children: [props.cancelLabel ? (_jsx(Button, { variant: "text", onClick: (e) => props.onCancel?.(e), children: props.cancelLabel })) : null, props.confirmLabel ? (_jsx(Button, { variant: "primary", onClick: (e) => props.onConfirm?.(e), children: props.confirmLabel })) : null] })) : null] })] })] })) : null] })] }) })) : null }));
291
+ return (_jsx(_Fragment, { children: props.open ? (_jsx(_Fragment, { children: _jsxs("div", { className: rootClasses(), children: [_jsx("div", { className: "umds-modal-overlay", onClick: (e) => handleOverlayClick(e) }), _jsxs("div", { role: "dialog", "aria-modal": "true", ref: dialogRef, "aria-label": nomeAcessivel(), "aria-labelledby": labelledBy(), "aria-describedby": describedBy(), tabIndex: -1, style: estiloDoDialogo(), onKeyDown: (event) => handleTrapKeydown(event), className: modalClasses(), children: [!ehFeedback() ? (_jsxs(_Fragment, { children: [ehSheet() ? (_jsx("div", { "aria-hidden": "true", className: "umds-modal__grabber", children: _jsx("span", { className: "umds-modal__grabber-bar" }) })) : null, _jsxs("div", { className: "umds-modal__header", children: [_jsxs("div", { className: "umds-modal__text-group", children: [props.title ? (_jsx("span", { className: "umds-modal__title", id: titleId(), children: props.title })) : null, props.description ? (_jsx("span", { className: "umds-modal__subtitle", id: descriptionId(), children: props.description })) : null] }), _jsxs("div", { className: "umds-modal__header-actions", children: [temNormal() ? (_jsx("button", { type: "button", title: props.normalModeLabel || "Modo normal", "aria-label": props.normalModeLabel || "Modo normal", "aria-pressed": modoAtual === "normal", onClick: (event) => irParaNormal(), className: classeDoControle("normal"), children: _jsx(Icon, { customSize: "14px", icon: faWindowRestore }) })) : null, temExpandir() ? (_jsx("button", { type: "button", title: props.expandLabel || "Expandir", "aria-label": props.expandLabel || "Expandir", "aria-pressed": modoAtual === "expanded", onClick: (event) => irParaExpandido(), className: classeDoControle("expanded"), children: _jsx(Icon, { customSize: "14px", icon: faUpRightAndDownLeftFromCenter }) })) : null, temTelaCheia() ? (_jsx("button", { type: "button", title: props.fullscreenLabel || "Tela cheia", "aria-label": props.fullscreenLabel || "Tela cheia", "aria-pressed": modoAtual === "fullscreen", onClick: (event) => irParaTelaCheia(), className: classeDoControle("fullscreen"), children: _jsx(Icon, { customSize: "14px", icon: faExpand }) })) : null, temMinimizar() ? (_jsx("button", { type: "button", className: "umds-modal__ctrl", title: props.minimizeLabel || "Minimizar", "aria-label": props.minimizeLabel || "Minimizar", onClick: (e) => props.onMinimize?.(e), children: _jsx(Icon, { customSize: "14px", icon: faMinus }) })) : null, temControles() && !props.hideCloseButton ? (_jsx("span", { className: "umds-modal__ctrl-divider" })) : null, !props.hideCloseButton ? (_jsx("button", { type: "button", className: "umds-modal__ctrl umds-modal__ctrl--close", onClick: (e) => handleClose(e), title: props.closeLabel || "Fechar", "aria-label": props.closeLabel || "Fechar", children: _jsx(Icon, { customSize: "16px", icon: faXmark }) })) : null] })] }), _jsx("div", { className: "umds-modal__body", children: _jsx(_Fragment, { children: props.children }) }), temRodape() ? (_jsxs("div", { className: "umds-modal__footer", children: [_jsx("div", { className: "umds-modal__footer-start", children: props.footerStart ? _jsx(_Fragment, { children: props.footerStart }) : null }), _jsxs("div", { className: "umds-modal__footer-end", children: [props.footerSlot ? _jsx(_Fragment, { children: props.footerSlot }) : null, !props.footerSlot ? (_jsxs(_Fragment, { children: [props.cancelLabel ? (_jsx(Button, { variant: "text", onClick: (e) => props.onCancel?.(e), children: props.cancelLabel })) : null, props.confirmLabel ? (_jsx(Button, { variant: "primary", onClick: (e) => props.onConfirm?.(e), children: props.confirmLabel })) : null] })) : null] })] })) : null] })) : null, ehFeedback() ? (_jsxs(_Fragment, { children: [!props.hideCloseButton ? (_jsx("div", { className: "umds-modal__close-wrapper", children: _jsx("button", { className: "umds-modal__close-button", onClick: (e) => handleClose(e), "aria-label": props.closeLabel || "Fechar", children: _jsx(Icon, { size: "sm", icon: faXmark }) }) })) : null, _jsxs("div", { className: "umds-modal__content", children: [_jsxs("div", { className: "umds-modal__header umds-modal__header--feedback", children: [props.variant && props.variant !== "default" ? (_jsx("div", { className: `umds-modal__icon ${iconVariantClass()}`, children: _jsx(Icon, { customSize: "40px", icon: iconName() }) })) : null, _jsxs("div", { className: "umds-modal__text-group", children: [props.title ? (_jsx(Text, { variant: "h5", weight: "bold", id: titleId(), children: props.title })) : null, props.description ? (_jsx(Text, { variant: "body2", color: "secondary", id: descriptionId(), children: props.description })) : null] })] }), _jsx(_Fragment, { children: props.children }), _jsxs("div", { className: "umds-modal__footer umds-modal__footer--feedback", children: [props.footerSlot ? _jsx(_Fragment, { children: props.footerSlot }) : null, !props.footerSlot ? (_jsxs(_Fragment, { children: [props.cancelLabel ? (_jsx(Button, { variant: "text", onClick: (e) => props.onCancel?.(e), children: props.cancelLabel })) : null, props.confirmLabel ? (_jsx(Button, { variant: "primary", onClick: (e) => props.onConfirm?.(e), children: props.confirmLabel })) : null] })) : null] })] })] })) : null] })] }) })) : null }));
192
292
  }
193
293
  export default Modal;
@@ -37,7 +37,7 @@
37
37
  display: flex;
38
38
  align-items: center;
39
39
  background-color: var(--umds-semantic-color-background-white);
40
- border: 1px solid var(--umds-semantic-color-neutral-light-down);
40
+ border: 1px solid var(--umds-semantic-field-border-default);
41
41
  border-radius: var(--umds-primitive-border-radius-sm);
42
42
  padding: var(--umds-primitive-spacing-nano) var(--umds-primitive-spacing-xxxs); /* era 8px 12px (protótipo --space-3) — snap 14/07 */
43
43
  min-height: var(--umds-semantic-field-height); /* 44px — Figma Size=Default (era 40px) */
@@ -378,6 +378,14 @@
378
378
  border-color: var(--umds-semantic-field-border-default);
379
379
  }
380
380
 
381
+ /* Somente leitura não é desabilitado: o texto segue lido e a WCAG 1.4.3 vale
382
+ sem isenção. O placeholder padrão foi calibrado para fundo branco e cai para
383
+ ~4,2:1 sobre o fundo de somente leitura; neutral-dark-down passa 4,5:1 em
384
+ todos os temas (1doc 6,78:1 · 1doc-dark 10,83:1 · alto contraste 16,48:1). */
385
+ .umds-multiselect--readonly .umds-multiselect__placeholder {
386
+ color: var(--umds-semantic-color-neutral-dark-down);
387
+ }
388
+
381
389
  /* O campo de busca precisa de indicador de foco — o painel foca ele ao abrir.
382
390
  Um outline no <input> desenhava um retângulo azul solto no meio do painel,
383
391
  porque o input não tem borda própria para o anel acompanhar.