@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,494 @@
1
+ "use client";
2
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
+ import './RichTextEditor.css';
4
+ import * as React from "react";
5
+ import { useState, useRef, useEffect } from "react";
6
+ import { faBold, faItalic, faUnderline, faStrikethrough, faListUl, faListOl, faLink, faRotateLeft, faRotateRight, faEraser, } from "@fortawesome/free-solid-svg-icons";
7
+ import Button from "../Button/Button";
8
+ import Icon from "../Icon/Icon";
9
+ import Input from "../Input/Input";
10
+ import Text from "../Text/Text";
11
+ import { gerarId } from "../../utils/id";
12
+ import { htmlDoLink, htmlVazio, normalizarEndereco, sanitizarHtml, } from "../../utils/html-seguro";
13
+ function RichTextEditor(props) {
14
+ const editorRef = useRef(null);
15
+ const toolbarRef = useRef(null);
16
+ const linkInputWrapRef = useRef(null);
17
+ const ultimoEmitidoRef = useRef("");
18
+ const selecaoRef = useRef(null);
19
+ const focoPendenteRef = useRef("");
20
+ const observadorRef = useRef(null);
21
+ const [uid, setUid] = useState(() => "");
22
+ const [linkOpen, setLinkOpen] = useState(() => false);
23
+ const [linkUrl, setLinkUrl] = useState(() => "");
24
+ const [linkError, setLinkError] = useState(() => false);
25
+ const [toolFocus, setToolFocus] = useState(() => 0);
26
+ const [active, setActive] = useState(() => "");
27
+ function baseId() {
28
+ return props.id || uid;
29
+ }
30
+ function labelId() {
31
+ return baseId() && props.label ? baseId() + "-label" : undefined;
32
+ }
33
+ function editorId() {
34
+ return baseId() ? baseId() + "-editor" : undefined;
35
+ }
36
+ function errorId() {
37
+ return baseId() && props.errorMessage ? baseId() + "-error" : undefined;
38
+ }
39
+ function helperId() {
40
+ return baseId() && props.helperText ? baseId() + "-helper" : undefined;
41
+ }
42
+ function describedBy() {
43
+ const ids = [errorId(), helperId()].filter(Boolean).join(" ");
44
+ return ids || undefined;
45
+ }
46
+ function editorAriaLabel() {
47
+ if (props.ariaLabel)
48
+ return props.ariaLabel;
49
+ return props.label && !labelId() ? props.label : undefined;
50
+ }
51
+ function isInvalid() {
52
+ return !!props.invalid || !!props.errorMessage;
53
+ }
54
+ function isEditable() {
55
+ return !props.disabled && !props.readOnly;
56
+ }
57
+ function editableText() {
58
+ return isEditable() ? "true" : "false";
59
+ }
60
+ function showToolbar() {
61
+ return !props.readOnly;
62
+ }
63
+ function classes() {
64
+ return [
65
+ "umds-rte",
66
+ isInvalid() ? "umds-rte--invalid" : "",
67
+ props.disabled ? "umds-rte--disabled" : "",
68
+ props.readOnly ? "umds-rte--readonly" : "",
69
+ props.resizable ? "umds-rte--resizable" : "",
70
+ props.className,
71
+ ]
72
+ .filter(Boolean)
73
+ .join(" ");
74
+ }
75
+ function editorStyle() {
76
+ const altura = props.minHeight !== undefined && props.minHeight !== null
77
+ ? props.minHeight
78
+ : 0;
79
+ return altura
80
+ ? {
81
+ minHeight: altura + "px",
82
+ }
83
+ : undefined;
84
+ }
85
+ function rotulo(chave) {
86
+ const padrao = {
87
+ bold: "Negrito",
88
+ italic: "Itálico",
89
+ underline: "Sublinhado",
90
+ strike: "Tachado",
91
+ ul: "Lista com marcadores",
92
+ ol: "Lista numerada",
93
+ link: "Link",
94
+ undo: "Desfazer",
95
+ redo: "Refazer",
96
+ clear: "Limpar formatação",
97
+ linkAddress: "Endereço do link",
98
+ linkApply: "Aplicar",
99
+ linkRemove: "Remover link",
100
+ linkCancel: "Cancelar",
101
+ linkInvalid: "Use um endereço http, https, mailto ou tel.",
102
+ };
103
+ const dado = props.labels || {};
104
+ return dado[chave] || padrao[chave];
105
+ }
106
+ function toolbarName() {
107
+ return props.toolbarLabel || "Formatação";
108
+ }
109
+ function tools() {
110
+ const padrao = [
111
+ "bold",
112
+ "italic",
113
+ "underline",
114
+ "|",
115
+ "ul",
116
+ "ol",
117
+ "|",
118
+ "link",
119
+ "|",
120
+ "undo",
121
+ "redo",
122
+ ];
123
+ const lista = props.toolbar && props.toolbar.length ? props.toolbar : padrao;
124
+ const catalogo = {
125
+ bold: {
126
+ command: "bold",
127
+ icon: faBold,
128
+ toggle: true,
129
+ },
130
+ italic: {
131
+ command: "italic",
132
+ icon: faItalic,
133
+ toggle: true,
134
+ },
135
+ underline: {
136
+ command: "underline",
137
+ icon: faUnderline,
138
+ toggle: true,
139
+ },
140
+ strike: {
141
+ command: "strikeThrough",
142
+ icon: faStrikethrough,
143
+ toggle: true,
144
+ },
145
+ ul: {
146
+ command: "insertUnorderedList",
147
+ icon: faListUl,
148
+ toggle: true,
149
+ },
150
+ ol: {
151
+ command: "insertOrderedList",
152
+ icon: faListOl,
153
+ toggle: true,
154
+ },
155
+ link: {
156
+ command: "link",
157
+ icon: faLink,
158
+ toggle: false,
159
+ },
160
+ undo: {
161
+ command: "undo",
162
+ icon: faRotateLeft,
163
+ toggle: false,
164
+ },
165
+ redo: {
166
+ command: "redo",
167
+ icon: faRotateRight,
168
+ toggle: false,
169
+ },
170
+ clear: {
171
+ command: "removeFormat",
172
+ icon: faEraser,
173
+ toggle: false,
174
+ },
175
+ };
176
+ const saida = [];
177
+ let posicao = 0;
178
+ for (let i = 0; i < lista.length; i++) {
179
+ const chave = lista[i];
180
+ if (chave === "|") {
181
+ saida.push({
182
+ key: "sep-" + i,
183
+ separator: true,
184
+ });
185
+ continue;
186
+ }
187
+ const def = catalogo[chave];
188
+ if (!def)
189
+ continue;
190
+ saida.push({
191
+ key: chave,
192
+ separator: false,
193
+ command: def.command,
194
+ icon: def.icon,
195
+ toggle: def.toggle,
196
+ position: posicao,
197
+ label: rotulo(chave),
198
+ });
199
+ posicao = posicao + 1;
200
+ }
201
+ return saida;
202
+ }
203
+ function estaAtiva(ferramenta) {
204
+ return (!!ferramenta.toggle &&
205
+ active.split(",").indexOf(ferramenta.command) !== -1);
206
+ }
207
+ function pressedText(ferramenta) {
208
+ return ferramenta.toggle
209
+ ? estaAtiva(ferramenta)
210
+ ? "true"
211
+ : "false"
212
+ : undefined;
213
+ }
214
+ function toolClasses(ferramenta) {
215
+ return [
216
+ "umds-rte__tool",
217
+ estaAtiva(ferramenta) ? "umds-rte__tool--active" : "",
218
+ ]
219
+ .filter(Boolean)
220
+ .join(" ");
221
+ }
222
+ function toolTabIndex(ferramenta) {
223
+ return ferramenta.position === toolFocus ? 0 : -1;
224
+ }
225
+ function escreverHtml(html) {
226
+ if (!editorRef.current)
227
+ return;
228
+ const limpo = sanitizarHtml(html || "");
229
+ if (editorRef.current.innerHTML !== limpo)
230
+ editorRef.current.innerHTML = limpo;
231
+ }
232
+ function selecaoNaArea() {
233
+ if (typeof window === "undefined" ||
234
+ !window.getSelection ||
235
+ !editorRef.current)
236
+ return false;
237
+ const selecao = window.getSelection();
238
+ return (!!selecao &&
239
+ selecao.rangeCount > 0 &&
240
+ editorRef.current.contains(selecao.anchorNode));
241
+ }
242
+ function lerEstados() {
243
+ if (typeof document === "undefined" ||
244
+ typeof document.queryCommandState !== "function")
245
+ return;
246
+ if (!selecaoNaArea())
247
+ return;
248
+ const comandos = [
249
+ "bold",
250
+ "italic",
251
+ "underline",
252
+ "strikeThrough",
253
+ "insertUnorderedList",
254
+ "insertOrderedList",
255
+ ];
256
+ const ligados = [];
257
+ for (let i = 0; i < comandos.length; i++) {
258
+ try {
259
+ if (document.queryCommandState(comandos[i]))
260
+ ligados.push(comandos[i]);
261
+ }
262
+ catch (erro) {
263
+ // O navegador não conhece o comando: fica desligado.
264
+ }
265
+ }
266
+ const texto = ligados.join(",");
267
+ if (texto !== active)
268
+ setActive(texto);
269
+ }
270
+ function emitir() {
271
+ if (!editorRef.current)
272
+ return;
273
+ let html = editorRef.current.innerHTML;
274
+ // Apagou tudo: o navegador deixa um <br> e o placeholder (que é :empty) não volta.
275
+ if (htmlVazio(html)) {
276
+ html = "";
277
+ if (editorRef.current.innerHTML !== "" &&
278
+ editorRef.current.querySelector("li") === null)
279
+ editorRef.current.innerHTML = "";
280
+ }
281
+ ultimoEmitidoRef.current = html;
282
+ if (props.onChange)
283
+ props.onChange(html);
284
+ }
285
+ function handleInput() {
286
+ emitir();
287
+ lerEstados();
288
+ }
289
+ function handlePaste(event) {
290
+ if (!event || !event.clipboardData)
291
+ return;
292
+ // Colar entra como texto puro: sem formatação de outro site e sem HTML estranho.
293
+ event.preventDefault();
294
+ const texto = event.clipboardData.getData("text/plain");
295
+ if (texto && typeof document !== "undefined")
296
+ document.execCommand("insertText", false, texto);
297
+ }
298
+ function handleEditorKeyDown(event) {
299
+ if (!event)
300
+ return;
301
+ if ((event.ctrlKey || event.metaKey) &&
302
+ !event.altKey &&
303
+ (event.key === "k" || event.key === "K")) {
304
+ event.preventDefault();
305
+ abrirLink();
306
+ }
307
+ }
308
+ function handleBlur(event) {
309
+ if (props.onBlur)
310
+ props.onBlur(event);
311
+ }
312
+ function handleToolMouseDown(event) {
313
+ if (event && event.preventDefault)
314
+ event.preventDefault();
315
+ }
316
+ function handleToolClick(ferramenta) {
317
+ if (!isEditable() || typeof document === "undefined")
318
+ return;
319
+ if (ferramenta.command === "link") {
320
+ abrirLink();
321
+ return;
322
+ }
323
+ if (editorRef.current && !selecaoNaArea())
324
+ editorRef.current.focus();
325
+ document.execCommand(ferramenta.command, false, undefined);
326
+ handleInput();
327
+ }
328
+ function handleToolFocus(ferramenta) {
329
+ if (toolFocus !== ferramenta.position)
330
+ setToolFocus(ferramenta.position);
331
+ }
332
+ function handleToolbarKeyDown(event) {
333
+ if (!event || !toolbarRef.current)
334
+ return;
335
+ const tecla = event.key;
336
+ if (tecla !== "ArrowRight" &&
337
+ tecla !== "ArrowLeft" &&
338
+ tecla !== "Home" &&
339
+ tecla !== "End")
340
+ return;
341
+ const botoes = toolbarRef.current.querySelectorAll("button");
342
+ const total = botoes.length;
343
+ if (!total)
344
+ return;
345
+ let atual = toolFocus;
346
+ if (tecla === "ArrowRight")
347
+ atual = (atual + 1) % total;
348
+ else if (tecla === "ArrowLeft")
349
+ atual = (atual - 1 + total) % total;
350
+ else if (tecla === "Home")
351
+ atual = 0;
352
+ else
353
+ atual = total - 1;
354
+ event.preventDefault();
355
+ setToolFocus(atual);
356
+ botoes[atual].focus();
357
+ }
358
+ function abrirLink() {
359
+ if (!isEditable() || typeof window === "undefined" || linkOpen)
360
+ return;
361
+ let enderecoAtual = "";
362
+ selecaoRef.current = null;
363
+ if (selecaoNaArea()) {
364
+ const selecao = window.getSelection();
365
+ selecaoRef.current = selecao.getRangeAt(0).cloneRange();
366
+ const no = selecao.anchorNode;
367
+ const elemento = no && no.nodeType === 3 ? no.parentNode : no;
368
+ const ancora = elemento && elemento.closest ? elemento.closest("a") : null;
369
+ if (ancora)
370
+ enderecoAtual = ancora.getAttribute("href") || "";
371
+ }
372
+ setLinkUrl(enderecoAtual);
373
+ setLinkError(false);
374
+ setLinkOpen(true);
375
+ focoPendenteRef.current = "link";
376
+ }
377
+ function fecharLink() {
378
+ setLinkOpen(false);
379
+ setLinkError(false);
380
+ focoPendenteRef.current = "editor";
381
+ }
382
+ function restaurarSelecao() {
383
+ if (typeof window === "undefined" || !window.getSelection)
384
+ return;
385
+ if (editorRef.current)
386
+ editorRef.current.focus();
387
+ if (selecaoRef.current) {
388
+ const selecao = window.getSelection();
389
+ selecao.removeAllRanges();
390
+ selecao.addRange(selecaoRef.current);
391
+ }
392
+ }
393
+ function handleLinkInput(texto) {
394
+ setLinkUrl(texto);
395
+ if (linkError)
396
+ setLinkError(false);
397
+ }
398
+ function aplicarLink() {
399
+ if (typeof document === "undefined")
400
+ return;
401
+ const endereco = normalizarEndereco(linkUrl);
402
+ if (!endereco) {
403
+ setLinkError(true);
404
+ return;
405
+ }
406
+ restaurarSelecao();
407
+ const selecao = window.getSelection();
408
+ const semTexto = !!selecao && selecao.isCollapsed;
409
+ // Sem texto escolhido, o próprio endereço vira o texto do link.
410
+ const comando = semTexto ? "insertHTML" : "createLink";
411
+ const argumento = semTexto ? htmlDoLink(endereco) : endereco;
412
+ document.execCommand(comando, false, argumento);
413
+ setLinkOpen(false);
414
+ focoPendenteRef.current = "editor";
415
+ handleInput();
416
+ }
417
+ function removerLink() {
418
+ if (typeof document === "undefined")
419
+ return;
420
+ restaurarSelecao();
421
+ document.execCommand("unlink", false, undefined);
422
+ setLinkOpen(false);
423
+ focoPendenteRef.current = "editor";
424
+ handleInput();
425
+ }
426
+ function handleLinkSubmit(event) {
427
+ if (event && event.preventDefault)
428
+ event.preventDefault();
429
+ aplicarLink();
430
+ }
431
+ function handleLinkKeyDown(event) {
432
+ if (event && event.key === "Escape") {
433
+ event.preventDefault();
434
+ event.stopPropagation();
435
+ fecharLink();
436
+ }
437
+ }
438
+ function linkErrorText() {
439
+ return linkError ? rotulo("linkInvalid") : undefined;
440
+ }
441
+ function linkRemoveVisible() {
442
+ return linkUrl !== "";
443
+ }
444
+ useEffect(() => {
445
+ setUid(gerarId("umds-rte"));
446
+ const inicial = props.value !== undefined ? props.value : props.defaultValue || "";
447
+ escreverHtml(inicial);
448
+ ultimoEmitidoRef.current = htmlVazio(inicial)
449
+ ? ""
450
+ : editorRef.current
451
+ ? editorRef.current.innerHTML
452
+ : "";
453
+ if (typeof document !== "undefined") {
454
+ const aoMudarSelecao = () => lerEstados();
455
+ document.addEventListener("selectionchange", aoMudarSelecao);
456
+ observadorRef.current = () => document.removeEventListener("selectionchange", aoMudarSelecao);
457
+ }
458
+ }, []);
459
+ useEffect(() => {
460
+ // `value` de fora diferente do que a área tem: reescreve (reset do formulário, valor vindo do servidor).
461
+ if (props.value !== undefined &&
462
+ editorRef.current &&
463
+ props.value !== ultimoEmitidoRef.current) {
464
+ const limpo = sanitizarHtml(props.value);
465
+ if (editorRef.current.innerHTML !== limpo &&
466
+ !(htmlVazio(limpo) && htmlVazio(editorRef.current.innerHTML))) {
467
+ editorRef.current.innerHTML = limpo;
468
+ }
469
+ ultimoEmitidoRef.current = props.value;
470
+ }
471
+ if (focoPendenteRef.current) {
472
+ const alvo = focoPendenteRef.current;
473
+ focoPendenteRef.current = "";
474
+ if (alvo === "editor" && editorRef.current) {
475
+ restaurarSelecao();
476
+ }
477
+ else if (alvo === "link" && linkInputWrapRef.current) {
478
+ const campo = linkInputWrapRef.current.querySelector("input");
479
+ if (campo)
480
+ campo.focus();
481
+ }
482
+ }
483
+ });
484
+ useEffect(() => {
485
+ return () => {
486
+ if (observadorRef.current) {
487
+ observadorRef.current();
488
+ observadorRef.current = null;
489
+ }
490
+ };
491
+ }, []);
492
+ return (_jsxs("div", { className: classes(), children: [props.label ? (_jsx("span", { className: "umds-rte__label", id: labelId(), children: props.label })) : null, _jsxs("div", { className: "umds-rte__frame", children: [showToolbar() ? (_jsx("div", { role: "toolbar", className: "umds-rte__toolbar", ref: toolbarRef, "aria-label": toolbarName(), "aria-controls": editorId(), onKeyDown: (event) => handleToolbarKeyDown(event), children: tools()?.map((ferramenta) => (_jsxs(React.Fragment, { children: [ferramenta.separator ? (_jsx("span", { role: "separator", "aria-orientation": "vertical", className: "umds-rte__separator" })) : null, !ferramenta.separator ? (_jsx("button", { type: "button", "aria-label": ferramenta.label, title: ferramenta.label, "aria-pressed": pressedText(ferramenta), tabIndex: toolTabIndex(ferramenta), disabled: !isEditable(), onMouseDown: (event) => handleToolMouseDown(event), onClick: (event) => handleToolClick(ferramenta), onFocus: (event) => handleToolFocus(ferramenta), className: toolClasses(ferramenta), children: _jsx(Icon, { size: "sm", variant: "inherit", icon: ferramenta.icon }) })) : null] }, ferramenta.key))) })) : null, linkOpen ? (_jsxs("form", { className: "umds-rte__link", noValidate: true, onSubmit: (event) => handleLinkSubmit(event), onKeyDown: (event) => handleLinkKeyDown(event), children: [_jsx("div", { className: "umds-rte__link-field", ref: linkInputWrapRef, children: _jsx(Input, { size: "sm", type: "url", placeholder: "https://", label: rotulo("linkAddress"), value: linkUrl, errorMessage: linkErrorText(), onChange: (texto) => handleLinkInput(texto) }) }), _jsxs("div", { className: "umds-rte__link-actions", children: [_jsx(Button, { variant: "primary", size: "sm", type: "submit", children: rotulo("linkApply") }), linkRemoveVisible() ? (_jsx(Button, { variant: "secondary", size: "sm", onClick: (event) => removerLink(), children: rotulo("linkRemove") })) : null, _jsx(Button, { variant: "text", size: "sm", onClick: (event) => fecharLink(), children: rotulo("linkCancel") })] })] })) : null, _jsx("div", { role: "textbox", "aria-multiline": "true", className: "umds-rte__editor", ref: editorRef, id: editorId(), "aria-label": editorAriaLabel(), "aria-labelledby": labelId(), "aria-describedby": describedBy(), "aria-invalid": isInvalid() ? "true" : undefined, "aria-readonly": props.readOnly ? "true" : undefined, "aria-disabled": props.disabled ? "true" : undefined, "aria-placeholder": props.placeholder, "data-placeholder": props.placeholder, contentEditable: editableText(), tabIndex: props.disabled ? -1 : 0, style: editorStyle(), onInput: (event) => handleInput(), onPaste: (event) => handlePaste(event), onKeyDown: (event) => handleEditorKeyDown(event), onBlur: (event) => handleBlur(event) }), props.footer ? (_jsx("div", { className: "umds-rte__footer", children: _jsx(_Fragment, { children: props.footer }) })) : null] }), props.errorMessage ? (_jsx(Text, { as: "span", variant: "caption", color: "negative", id: errorId(), children: props.errorMessage })) : null, props.helperText ? (_jsx(Text, { as: "span", variant: "caption", color: "secondary", id: helperId(), children: props.helperText })) : null] }));
493
+ }
494
+ export default RichTextEditor;
@@ -32,6 +32,7 @@ export interface SegmentedControlOption {
32
32
  * @property {string} value - Valor escolhido (controlado).
33
33
  * @property {string} defaultValue - Valor inicial (não-controlado). Ignorado quando `value` é fornecido.
34
34
  * @property {string} name - Nome compartilhado dos radios (submit nativo + setas do navegador). Gerado se omitido.
35
+ * @property {string} id - Base dos ids internos (rótulo, radios, erro) e do `name`, quando ele não é informado. Passe em SSR para os ids já saírem no HTML do servidor; sem ela, o id automático nasce no navegador.
35
36
  * @property {boolean} disabled - Desabilita o grupo inteiro.
36
37
  * @property {boolean} required - Marca o grupo como obrigatório.
37
38
  * @property {boolean} invalid - Estado de erro.
@@ -49,6 +50,7 @@ export interface SegmentedControlProps {
49
50
  value?: string;
50
51
  defaultValue?: string;
51
52
  name?: string;
53
+ id?: string;
52
54
  disabled?: boolean;
53
55
  required?: boolean;
54
56
  invalid?: boolean;
@@ -2,23 +2,27 @@
2
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  import './SegmentedControl.css';
4
4
  import * as React from "react";
5
- import { useState } from "react";
5
+ import { useState, useEffect } from "react";
6
6
  import Icon from "../Icon/Icon";
7
7
  import Text from "../Text/Text";
8
+ import { gerarId } from "../../utils/id";
8
9
  function SegmentedControl(props) {
9
10
  const [internalValue, setInternalValue] = useState(() => props.defaultValue !== undefined ? props.defaultValue : "");
10
- const [uid, setUid] = useState(() => "umds-segmented-" + Math.random().toString(36).slice(2, 9));
11
+ const [uid, setUid] = useState(() => "");
12
+ function baseId() {
13
+ return props.id || uid;
14
+ }
11
15
  function optionList() {
12
16
  return props.options || [];
13
17
  }
14
18
  function groupName() {
15
- return props.name || uid;
19
+ return props.name || baseId() || undefined;
16
20
  }
17
21
  function labelId() {
18
- return uid + "-label";
22
+ return baseId() ? baseId() + "-label" : undefined;
19
23
  }
20
24
  function errorId() {
21
- return uid + "-error";
25
+ return baseId() ? baseId() + "-error" : undefined;
22
26
  }
23
27
  function currentValue() {
24
28
  return props.value !== undefined ? props.value : internalValue;
@@ -29,6 +33,9 @@ function SegmentedControl(props) {
29
33
  function labelledByText() {
30
34
  return props.label ? labelId() : undefined;
31
35
  }
36
+ function groupAriaLabel() {
37
+ return props.label && !baseId() ? props.label : undefined;
38
+ }
32
39
  function describedByText() {
33
40
  return props.errorMessage ? errorId() : undefined;
34
41
  }
@@ -51,7 +58,7 @@ function SegmentedControl(props) {
51
58
  .join(" ");
52
59
  }
53
60
  function inputId(index) {
54
- return uid + "-" + index;
61
+ return baseId() ? baseId() + "-" + index : undefined;
55
62
  }
56
63
  function estaEscolhido(option) {
57
64
  return option.value === currentValue();
@@ -62,8 +69,10 @@ function SegmentedControl(props) {
62
69
  function rotuloDoSegmento(option) {
63
70
  // Com `label` visivel, o `ariaLabel` e IGNORADO de proposito: nome
64
71
  // acessivel diferente do texto visivel quebra o WCAG 2.5.3.
72
+ // Sem id (antes do onMount) o label-for nao liga a nada: o nome e o
73
+ // proprio texto visivel, o que tambem respeita o 2.5.3.
65
74
  if (option.label)
66
- return undefined;
75
+ return baseId() ? undefined : option.label;
67
76
  // Ultimo recurso. `value` e nome ruim, mas radio anonimo e pior — e o
68
77
  // TypeScript nao pega, porque `label` e `ariaLabel` sao os dois opcionais.
69
78
  return option.ariaLabel || option.value;
@@ -75,6 +84,10 @@ function SegmentedControl(props) {
75
84
  if (props.onChange)
76
85
  props.onChange(option.value);
77
86
  }
78
- return (_jsxs("div", { className: groupClasses(), children: [props.label ? (_jsxs("span", { className: "umds-segmented__group-label", id: labelId(), children: [props.label, props.required ? (_jsx("span", { className: "umds-segmented__required", children: " *" })) : null] })) : null, _jsx("div", { role: "radiogroup", className: "umds-segmented__track", "aria-labelledby": labelledByText(), "aria-describedby": describedByText(), "aria-invalid": ariaInvalidText(), "aria-required": ariaRequiredText(), children: optionList()?.map((option, index) => (_jsxs(React.Fragment, { children: [_jsx("input", { type: "radio", className: "umds-segmented__input", id: inputId(index), name: groupName(), value: option.value, checked: estaEscolhido(option), disabled: estaDesabilitado(option), "aria-label": rotuloDoSegmento(option), onChange: (event) => handleChange(option) }), _jsx("label", { className: "umds-segmented__item", htmlFor: inputId(index), children: _jsxs("span", { className: "umds-segmented__conteudo", children: [option.icon ? (_jsx(Icon, { size: "sm", variant: "inherit", icon: option.icon })) : null, option.label ? (_jsx("span", { className: "umds-segmented__texto", children: option.label })) : null] }) })] }, option.value))) }), props.errorMessage ? (_jsx(Text, { as: "span", variant: "caption", color: "negative", className: "umds-segmented__error-message", id: errorId(), children: props.errorMessage })) : null] }));
87
+ useEffect(() => {
88
+ if (!props.id)
89
+ setUid(gerarId("umds-segmented"));
90
+ }, []);
91
+ return (_jsxs("div", { className: groupClasses(), children: [props.label ? (_jsxs("span", { className: "umds-segmented__group-label", id: labelId(), children: [props.label, props.required ? (_jsx("span", { className: "umds-segmented__required", children: " *" })) : null] })) : null, _jsx("div", { role: "radiogroup", className: "umds-segmented__track", "aria-labelledby": labelledByText(), "aria-label": groupAriaLabel(), "aria-describedby": describedByText(), "aria-invalid": ariaInvalidText(), "aria-required": ariaRequiredText(), children: optionList()?.map((option, index) => (_jsxs(React.Fragment, { children: [_jsx("input", { type: "radio", className: "umds-segmented__input", id: inputId(index), name: groupName(), value: option.value, checked: estaEscolhido(option), disabled: estaDesabilitado(option), "aria-label": rotuloDoSegmento(option), onChange: (event) => handleChange(option) }), _jsx("label", { className: "umds-segmented__item", htmlFor: inputId(index), children: _jsxs("span", { className: "umds-segmented__conteudo", children: [option.icon ? (_jsx(Icon, { size: "sm", variant: "inherit", icon: option.icon })) : null, option.label ? (_jsx("span", { className: "umds-segmented__texto", children: option.label })) : null] }) })] }, option.value))) }), props.errorMessage ? (_jsx(Text, { as: "span", variant: "caption", color: "negative", className: "umds-segmented__error-message", id: errorId(), children: props.errorMessage })) : null] }));
79
92
  }
80
93
  export default SegmentedControl;
@@ -39,7 +39,7 @@
39
39
  align-items: center;
40
40
  justify-content: space-between;
41
41
  background-color: var(--umds-semantic-color-background-white);
42
- border: 1px solid var(--umds-semantic-color-neutral-light-down);
42
+ border: 1px solid var(--umds-semantic-field-border-default);
43
43
  border-radius: var(--umds-primitive-border-radius-sm);
44
44
  padding: 0 var(--umds-primitive-spacing-xxxs); /* era 0 12px (protótipo --space-3) — snap 14/07 */
45
45
  height: var(--umds-semantic-field-height); /* 44px — Figma Size=Default (era 40px) */
@@ -157,6 +157,68 @@
157
157
  overflow: hidden;
158
158
  }
159
159
 
160
+ /* ── Lista que abre para cima (placement top, ou auto sem espaço embaixo) ── */
161
+ .umds-select--placement-top .umds-select__dropdown {
162
+ top: auto;
163
+ bottom: calc(100% + 4px);
164
+ }
165
+
166
+ /* ── Rodapé da lista (slot footer): ações fixas abaixo das opções ── */
167
+ .umds-select__footer {
168
+ flex-shrink: 0;
169
+ display: flex;
170
+ align-items: center;
171
+ padding: var(--umds-primitive-spacing-nano) var(--umds-primitive-spacing-xxxs);
172
+ border-top: 1px solid var(--umds-semantic-color-neutral-light-medium);
173
+ background-color: var(--umds-semantic-color-background-elevated);
174
+ }
175
+
176
+ /* ── Variante filter: botão de filtro de barra de ferramentas ──
177
+ Contornado em azul, largura do conteúdo, lista mais larga que o botão. */
178
+ .umds-select--filter {
179
+ width: auto;
180
+ }
181
+
182
+ .umds-select--filter.umds-select--full-width {
183
+ width: 100%;
184
+ }
185
+
186
+ .umds-select--filter .umds-select__container {
187
+ width: auto;
188
+ }
189
+
190
+ .umds-select--filter.umds-select--full-width .umds-select__container {
191
+ width: 100%;
192
+ }
193
+
194
+ .umds-select--filter .umds-select__trigger {
195
+ width: auto;
196
+ gap: var(--umds-primitive-spacing-nano);
197
+ border-color: var(--umds-semantic-color-primary-pure);
198
+ background-color: var(--umds-semantic-color-primary-light);
199
+ }
200
+
201
+ .umds-select--filter.umds-select--full-width .umds-select__trigger {
202
+ width: 100%;
203
+ }
204
+
205
+ .umds-select--filter .umds-select__trigger:hover:not(.umds-select--disabled .umds-select__trigger) {
206
+ border-color: var(--umds-semantic-color-primary-dark);
207
+ }
208
+
209
+ .umds-select--filter .umds-select__trigger .umds-text,
210
+ .umds-select--filter .umds-select__actions {
211
+ color: var(--umds-semantic-color-primary-pure);
212
+ font-weight: var(--umds-primitive-font-weight-semibold);
213
+ }
214
+
215
+ .umds-select--filter .umds-select__dropdown {
216
+ /* 240px: três vezes o degrau xxl (80px). Sem token de largura de menu. */
217
+ width: max-content;
218
+ min-width: max(100%, calc(var(--umds-primitive-spacing-xxl) * 3));
219
+ max-width: calc(100vw - var(--umds-primitive-spacing-xxxs) * 2);
220
+ }
221
+
160
222
  /* ── Busca no dropdown ── */
161
223
  .umds-select__search-container {
162
224
  display: flex;
@@ -382,6 +444,14 @@
382
444
  border-color: var(--umds-semantic-field-border-default);
383
445
  }
384
446
 
447
+ /* Somente leitura não é desabilitado: o texto segue lido e a WCAG 1.4.3 vale
448
+ sem isenção. O placeholder padrão foi calibrado para fundo branco e cai para
449
+ ~4,2:1 sobre o fundo de somente leitura; neutral-dark-down passa 4,5:1 em
450
+ todos os temas (1doc 6,78:1 · 1doc-dark 10,83:1 · alto contraste 16,48:1). */
451
+ .umds-select--readonly .umds-select__placeholder {
452
+ color: var(--umds-semantic-color-neutral-dark-down);
453
+ }
454
+
385
455
  /* O campo de busca precisa de indicador de foco — o painel foca ele ao abrir.
386
456
  Um outline no <input> desenhava um retângulo azul solto no meio do painel,
387
457
  porque o input não tem borda própria para o anel acompanhar. O indicador vai