@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
@@ -40,6 +40,10 @@ export interface SelectOption {
40
40
  * @property {string} ariaLabel - Nome acessível quando não há label visível.
41
41
  * @property {string} id - ID base dos elementos internos. Gerado automaticamente se omitido.
42
42
  * @property {function} onChange - Callback com o(s) valor(es) selecionado(s).
43
+ * @property {string} placement - Onde a lista abre: 'bottom' (padrão) | 'top' | 'auto'. O `auto` abre para cima quando falta espaço embaixo da tela e há mais em cima (lista dentro do rodapé de um modal).
44
+ * @property {string} variant - 'default' | 'filter'. O `filter` é o botão de filtro de barra de ferramentas: contornado em azul, largura do conteúdo, lista mais larga que o botão, busca focada ao abrir. Combine com `searchable`, `emptyOptionLabel` e o slot `footer`.
45
+ * @property {string} emptyOptionLabel - Opção "sem filtro" no topo da lista (seleção única): marcada quando nada está escolhido; ao escolher, `onChange` recebe `""` e o campo volta a mostrar o `placeholder` (o nome do filtro).
46
+ * @property {any} footer - Rodapé fixo da lista, com ações ("Gerenciar marcadores"). Passe o elemento correspondente (React node ou Vue slot `footer`).
43
47
  * @quandoUsar Escolher UM valor de uma lista fechada. O valor selecionado fica visível no campo.
44
48
  * @quandoNaoUsar Para escolher VÁRIOS valores — use `MultiSelect`. Para um menu de AÇÕES (editar, excluir, duplicar) em vez de valores, use `Dropdown`. Para 2 a 4 opções mutuamente exclusivas sempre visíveis, use `Radio`.
45
49
  */
@@ -77,6 +81,14 @@ export interface SelectProps {
77
81
  errorMessage?: string;
78
82
  fullWidth?: boolean;
79
83
  size?: "sm" | "md" | "lg";
84
+ /** Onde a lista abre. @default 'bottom' */
85
+ placement?: "bottom" | "top" | "auto";
86
+ /** Variante visual. @default 'default' */
87
+ variant?: "default" | "filter";
88
+ /** Opção "sem filtro" no topo da lista (seleção única). Escolhê-la chama `onChange("")`. */
89
+ emptyOptionLabel?: string;
90
+ /** Rodapé fixo da lista (ações). React node ou slot `footer` no Vue. */
91
+ footer?: any;
80
92
  pagination?: boolean;
81
93
  hasMore?: boolean;
82
94
  onLoadMore?: () => void;
@@ -8,6 +8,7 @@ import Icon from "../Icon/Icon";
8
8
  import Spinner from "../Spinner/Spinner";
9
9
  import Checkbox from "../Checkbox/Checkbox";
10
10
  import Tag from "../Tag/Tag";
11
+ import { gerarId } from "../../utils/id";
11
12
  function Select(props) {
12
13
  const selectRef = useRef(null);
13
14
  const triggerRef = useRef(null);
@@ -30,10 +31,36 @@ function Select(props) {
30
31
  : props.defaultValue !== undefined && props.defaultValue !== null
31
32
  ? [props.defaultValue]
32
33
  : Array());
34
+ const [opensUp, setOpensUp] = useState(() => false);
33
35
  const [shouldFocusSearch, setShouldFocusSearch] = useState(() => false);
34
36
  const [shouldFocusTrigger, setShouldFocusTrigger] = useState(() => false);
35
37
  const [activeIndex, setActiveIndex] = useState(() => -1);
36
- const [uid, setUid] = useState(() => "umds-select-" + Math.random().toString(36).slice(2, 9));
38
+ const [uid, setUid] = useState(() => "");
39
+ function baseId() {
40
+ return props.id || uid;
41
+ }
42
+ function errorIdText() {
43
+ return baseId() ? baseId() + "-error" : undefined;
44
+ }
45
+ function helperIdText() {
46
+ return baseId() ? baseId() + "-helper" : undefined;
47
+ }
48
+ function isInvalid() {
49
+ return !!props.invalid || !!props.errorMessage;
50
+ }
51
+ function ariaInvalidText() {
52
+ return isInvalid() ? "true" : undefined;
53
+ }
54
+ function describedByText() {
55
+ if (!baseId())
56
+ return undefined;
57
+ const partes = Array();
58
+ if (props.errorMessage)
59
+ partes.push(baseId() + "-error");
60
+ if (mostraApoio())
61
+ partes.push(baseId() + "-helper");
62
+ return partes.length > 0 ? partes.join(" ") : undefined;
63
+ }
37
64
  function selectedOptionsList() {
38
65
  const currentVal = props.value !== undefined
39
66
  ? Array.isArray(props.value)
@@ -66,6 +93,12 @@ function Select(props) {
66
93
  : internalSelected || [];
67
94
  if (currentVal.length === 0)
68
95
  return props.placeholder || "Selecione...";
96
+ // Opção "sem filtro" escolhida: volta a mostrar o nome do filtro.
97
+ if (props.emptyOptionLabel &&
98
+ !props.multiple &&
99
+ currentVal.length === 1 &&
100
+ currentVal[0] === "")
101
+ return props.placeholder || "Selecione...";
69
102
  if (props.multiple) {
70
103
  if (props.selectionDisplay === "tags")
71
104
  return "";
@@ -91,6 +124,11 @@ function Select(props) {
91
124
  ? []
92
125
  : [props.value]
93
126
  : internalSelected || [];
127
+ if (props.emptyOptionLabel &&
128
+ !props.multiple &&
129
+ currentVal.length === 1 &&
130
+ currentVal[0] === "")
131
+ return true;
94
132
  return currentVal.length === 0;
95
133
  }
96
134
  function formValue() {
@@ -106,9 +144,18 @@ function Select(props) {
106
144
  function filteredOptionsList() {
107
145
  if (!props.options)
108
146
  return [];
147
+ // Opção "sem filtro" no topo (seleção única), sempre visível sem busca.
148
+ const vazia = props.emptyOptionLabel && !props.multiple && !searchTerm
149
+ ? [
150
+ {
151
+ label: props.emptyOptionLabel,
152
+ value: "",
153
+ },
154
+ ]
155
+ : [];
109
156
  // If it's remote search (onSearchChange provided), we don't filter locally
110
157
  if (!props.searchable || !searchTerm || props.onSearchChange)
111
- return props.options;
158
+ return vazia.concat(props.options);
112
159
  const term = searchTerm.toLowerCase();
113
160
  return props.options.filter((opt) => opt.label.toLowerCase().includes(term));
114
161
  }
@@ -122,6 +169,10 @@ function Select(props) {
122
169
  props.invalid ? "umds-select--invalid" : "",
123
170
  isOpen ? "umds-select--open" : "",
124
171
  props.searchVariant === "inline" ? "umds-select--search-inline" : "",
172
+ props.variant === "filter" ? "umds-select--filter" : "",
173
+ opensUp && props.searchVariant !== "inline"
174
+ ? "umds-select--placement-top"
175
+ : "",
125
176
  props.multiple &&
126
177
  props.selectionDisplay === "tags" &&
127
178
  selectedOptionsList().length > 0
@@ -133,22 +184,45 @@ function Select(props) {
133
184
  .join(" ");
134
185
  }
135
186
  function listboxIdText() {
136
- return (props.id || uid) + "-listbox";
187
+ return baseId() ? baseId() + "-listbox" : undefined;
137
188
  }
138
189
  function labelIdText() {
139
- return (props.id || uid) + "-label";
190
+ return baseId() ? baseId() + "-label" : undefined;
191
+ }
192
+ function comboboxLabelledBy() {
193
+ return props.label && baseId() ? labelIdText() : undefined;
194
+ }
195
+ function comboboxAriaLabel() {
196
+ if (props.ariaLabel)
197
+ return props.ariaLabel;
198
+ return props.label && !baseId() ? props.label : undefined;
140
199
  }
141
200
  function activeDescendantText() {
142
- if (!isOpen || activeIndex < 0)
201
+ if (!isOpen || activeIndex < 0 || !baseId())
143
202
  return undefined;
144
- return (props.id || uid) + "-option-" + activeIndex;
203
+ return baseId() + "-option-" + activeIndex;
145
204
  }
146
205
  function optionIdText(index) {
147
- return (props.id || uid) + "-option-" + index;
206
+ return baseId() ? baseId() + "-option-" + index : undefined;
148
207
  }
149
208
  function removeItemAriaLabelText(label) {
150
209
  return (props.removeAriaLabel || "Remover") + " " + label;
151
210
  }
211
+ function shouldOpenUp() {
212
+ const pedido = props.placement || "bottom";
213
+ if (pedido === "top")
214
+ return true;
215
+ if (pedido !== "auto")
216
+ return false;
217
+ if (typeof window === "undefined" || !triggerRef.current)
218
+ return false;
219
+ const caixa = triggerRef.current.getBoundingClientRect();
220
+ const abaixo = window.innerHeight - caixa.bottom;
221
+ const acima = caixa.top;
222
+ const opcoes = filteredOptionsList().length;
223
+ const estimada = Math.min(300, opcoes * 36 + 8 + (props.searchable ? 44 : 0) + (props.footer ? 44 : 0));
224
+ return abaixo < estimada && acima > abaixo;
225
+ }
152
226
  function toggle() {
153
227
  if (props.disabled || props.readOnly)
154
228
  return;
@@ -158,10 +232,13 @@ function Select(props) {
158
232
  const next = !isOpen;
159
233
  setIsOpen(next);
160
234
  if (next) {
235
+ setOpensUp(shouldOpenUp());
161
236
  // Abre com a opção já selecionada ativa (padrão combobox).
162
237
  setActiveIndex(filteredOptionsList().findIndex((opt) => isOptionSelected(opt.value)));
163
238
  if (props.searchable &&
164
- (props.autoFocusSearch || props.searchVariant === "inline")) {
239
+ (props.autoFocusSearch ||
240
+ props.searchVariant === "inline" ||
241
+ props.variant === "filter")) {
165
242
  setShouldFocusSearch(true);
166
243
  }
167
244
  }
@@ -342,9 +419,15 @@ function Select(props) {
342
419
  ? []
343
420
  : [props.value]
344
421
  : internalSelected || [];
422
+ // "Sem filtro" aparece marcada enquanto nada está escolhido.
423
+ if (props.emptyOptionLabel && !props.multiple && val === "") {
424
+ return currentVal.length === 0 || currentVal.includes("");
425
+ }
345
426
  return currentVal.includes(val);
346
427
  }
347
428
  useEffect(() => {
429
+ if (!props.id)
430
+ setUid(gerarId("umds-select"));
348
431
  if (typeof document === "undefined")
349
432
  return;
350
433
  const handleClickOutside = (event) => {
@@ -389,7 +472,7 @@ function Select(props) {
389
472
  }
390
473
  };
391
474
  }, []);
392
- return (_jsxs("div", { ref: selectRef, className: wrapperClassesList(), children: [props.label ? (_jsxs(Text, { as: "label", variant: "label", className: "umds-select__label", id: labelIdText(), children: [props.label, props.required ? (_jsx("span", { className: "umds-select__required", children: " *" })) : null] })) : null, _jsxs("div", { className: "umds-select__container", children: [!(isOpen && props.searchVariant === "inline") ? (_jsxs("div", { role: "combobox", "aria-haspopup": "listbox", className: "umds-select__trigger", ref: triggerRef, onClick: (event) => toggle(), onKeyDown: (event) => handleTriggerKeyDown(event), "aria-readonly": ariaReadonly(), "aria-expanded": isOpen, "aria-controls": listboxIdText(), "aria-activedescendant": activeDescendantText(), "aria-labelledby": props.label ? labelIdText() : undefined, "aria-label": props.ariaLabel, "aria-invalid": props.invalid ? "true" : undefined, tabIndex: props.disabled ? -1 : 0, children: [_jsxs("div", { className: "umds-select__values", children: [displayLabelText() ? (_jsx(Text, { as: "span", variant: "body2", className: isPlaceholder() ? "umds-select__placeholder" : "", children: displayLabelText() })) : null, props.multiple &&
475
+ return (_jsxs("div", { ref: selectRef, className: wrapperClassesList(), children: [props.label ? (_jsxs(Text, { as: "label", variant: "label", className: "umds-select__label", id: labelIdText(), children: [props.label, props.required ? (_jsx("span", { className: "umds-select__required", children: " *" })) : null] })) : null, _jsxs("div", { className: "umds-select__container", children: [!(isOpen && props.searchVariant === "inline") ? (_jsxs("div", { role: "combobox", "aria-haspopup": "listbox", className: "umds-select__trigger", ref: triggerRef, onClick: (event) => toggle(), onKeyDown: (event) => handleTriggerKeyDown(event), "aria-readonly": ariaReadonly(), "aria-expanded": isOpen, "aria-controls": listboxIdText(), "aria-activedescendant": activeDescendantText(), "aria-labelledby": comboboxLabelledBy(), "aria-label": comboboxAriaLabel(), "aria-invalid": ariaInvalidText(), "aria-describedby": describedByText(), "aria-disabled": props.disabled ? "true" : undefined, tabIndex: props.disabled ? -1 : 0, children: [_jsxs("div", { className: "umds-select__values", children: [displayLabelText() ? (_jsx(Text, { as: "span", variant: "body2", className: isPlaceholder() ? "umds-select__placeholder" : "", children: displayLabelText() })) : null, props.multiple &&
393
476
  props.selectionDisplay === "tags" &&
394
477
  selectedOptionsList().length > 0 ? (_jsx("div", { className: "umds-select__tags", children: selectedOptionsList()?.map((opt) => (_jsx(Tag, { size: "sm", label: opt.label, closable: true, disabled: props.disabled, onClose: (e) => removeValue(opt.value, e) }, opt.value))) })) : null] }), _jsxs("div", { className: "umds-select__actions", children: [props.loading ? _jsx(Spinner, { size: "sm", variant: "secondary" }) : null, _jsx("div", { className: "umds-select__arrow", children: _jsx(Icon, { size: "sm", icon: isOpen ? faChevronUp : faChevronDown }) })] })] })) : null, isOpen ? (_jsxs("div", { className: "umds-select__dropdown", style: props.searchVariant === "inline"
395
478
  ? {
@@ -403,7 +486,7 @@ function Select(props) {
403
486
  index === activeIndex ? "umds-select__option--active" : "",
404
487
  ]
405
488
  .filter(Boolean)
406
- .join(" "), children: [props.multiple ? (_jsx("div", { className: "umds-select__option-checkbox", children: _jsx(Checkbox, { checked: isOptionSelected(option.value), decorative: true }) })) : null, _jsx("div", { className: "umds-select__option-content", children: _jsx(_Fragment, { children: props.item || (_jsx(Text, { variant: "body2", children: option.label })) }) }), !props.multiple && isOptionSelected(option.value) ? (_jsx("div", { className: "umds-select__option-check", children: _jsx(Icon, { size: "sm", icon: faCheck }) })) : null] }, option.value))), props.loading && props.pagination ? (_jsxs("div", { className: "umds-select__loading-more", children: [_jsx(Spinner, { size: "sm" }), _jsx(Text, { variant: "caption", children: props.loadingLabel || "Carregando mais..." })] })) : null] })] })) : null] }), props.name ? (_jsx("input", { type: "hidden", name: props.name, value: formValue() || "" })) : null, props.errorMessage ? (_jsx(Text, { variant: "caption", color: "negative", className: "umds-select__error-message", children: props.errorMessage })) : null, mostraApoio() ? (_jsx(Text, { variant: "caption", color: "secondary", className: "umds-select__description", children: textoDeApoio() })) : null, props.multiple &&
489
+ .join(" "), children: [props.multiple ? (_jsx("div", { className: "umds-select__option-checkbox", children: _jsx(Checkbox, { checked: isOptionSelected(option.value), decorative: true }) })) : null, _jsx("div", { className: "umds-select__option-content", children: _jsx(_Fragment, { children: props.item || (_jsx(Text, { variant: "body2", children: option.label })) }) }), !props.multiple && isOptionSelected(option.value) ? (_jsx("div", { className: "umds-select__option-check", children: _jsx(Icon, { size: "sm", icon: faCheck }) })) : null] }, option.value))), props.loading && props.pagination ? (_jsxs("div", { className: "umds-select__loading-more", children: [_jsx(Spinner, { size: "sm" }), _jsx(Text, { variant: "caption", children: props.loadingLabel || "Carregando mais..." })] })) : null] }), props.footer ? (_jsx("div", { className: "umds-select__footer", children: _jsx(_Fragment, { children: props.footer }) })) : null] })) : null] }), props.name ? (_jsx("input", { type: "hidden", name: props.name, value: formValue() || "" })) : null, props.errorMessage ? (_jsx(Text, { variant: "caption", color: "negative", className: "umds-select__error-message", id: errorIdText(), children: props.errorMessage })) : null, mostraApoio() ? (_jsx(Text, { variant: "caption", color: "secondary", className: "umds-select__description", id: helperIdText(), children: textoDeApoio() })) : null, props.multiple &&
407
490
  props.selectionDisplay === "list" &&
408
491
  selectedOptionsList().length > 0 ? (_jsx("div", { className: "umds-select__selected-list", children: selectedOptionsList()?.map((opt) => (_jsxs("div", { className: "umds-select__selected-list-item", children: [_jsx(Text, { variant: "body2", children: opt.label }), _jsx("button", { type: "button", className: "umds-select__list-remove", "aria-label": removeItemAriaLabelText(opt.label), onClick: (e) => removeValue(opt.value, e), children: _jsx(Icon, { size: "sm", icon: faTrash }) })] }, opt.value))) })) : null] }));
409
492
  }
@@ -102,7 +102,7 @@
102
102
  }
103
103
 
104
104
  .umds-side-panel__topo {
105
- padding: var(--umds-primitive-spacing-xxxs) 10px 10px; /* produto: 16px 10px 10px */
105
+ padding: var(--umds-primitive-spacing-xxxs) var(--umds-primitive-spacing-nano) var(--umds-primitive-spacing-nano); /* 16px 8px 8px (produto: 16px 10px 10px) */
106
106
  flex-shrink: 0;
107
107
  box-sizing: border-box;
108
108
  }
@@ -111,7 +111,7 @@
111
111
  display: flex;
112
112
  align-items: center;
113
113
  justify-content: space-between;
114
- margin-bottom: 10px; /* produto: 10px */
114
+ margin-bottom: var(--umds-primitive-spacing-nano); /* 8px (produto: 10px) */
115
115
  min-height: var(--umds-primitive-spacing-xxs); /* 24px */
116
116
  }
117
117
 
@@ -131,7 +131,7 @@
131
131
  padding: 0;
132
132
  margin: 0;
133
133
  border: none;
134
- border-radius: 6px; /* produto: 6px — a escala do DS só tem 8 */
134
+ border-radius: var(--umds-primitive-border-radius-sm); /* 8px — raio canônico (produto: 6px) */
135
135
  background: none;
136
136
  color: var(--umds-semantic-color-neutral-dark-medium);
137
137
  cursor: pointer;
@@ -151,7 +151,7 @@
151
151
  }
152
152
 
153
153
  .umds-side-panel__corpo {
154
- padding: 0 10px var(--umds-primitive-spacing-xxxs); /* produto: 0 10px 16px */
154
+ padding: 0 var(--umds-primitive-spacing-nano) var(--umds-primitive-spacing-xxxs); /* 0 8px 16px (produto: 0 10px 16px) */
155
155
  overflow-y: auto;
156
156
  min-height: 0;
157
157
  flex: 1;
@@ -12,13 +12,13 @@
12
12
  .umds-side-panel-item {
13
13
  display: flex;
14
14
  align-items: center;
15
- gap: 9px; /* produto: 9px — entre os degraus 8 e 12 da escala */
15
+ gap: var(--umds-primitive-spacing-nano); /* 8px (produto: 9px) */
16
16
  width: 100%;
17
17
  height: 34px; /* produto: 34px */
18
18
  margin: 0;
19
- padding: 0 var(--umds-primitive-spacing-nano) 0 9px; /* produto: 0 8px 0 9px */
19
+ padding: 0 var(--umds-primitive-spacing-nano); /* 0 8px (produto: 0 8px 0 9px) */
20
20
  border: none;
21
- border-radius: 6px; /* produto: 6px — a escala do DS só tem 8 */
21
+ border-radius: var(--umds-primitive-border-radius-sm); /* 8px — raio canônico (produto: 6px) */
22
22
  background: none;
23
23
  color: var(--umds-semantic-color-neutral-dark-down);
24
24
  font-family: inherit;
@@ -71,12 +71,14 @@
71
71
  white-space: nowrap;
72
72
  }
73
73
 
74
- /* Fora do estado ativo o número é mais claro que o nome: é apoio, não rótulo. */
74
+ /* O contador é texto: `neutral-dark-down` (#565656, 7,34:1), a mesma cor do
75
+ nome. O produto o deixava mais claro (#7D7D7D), mas isso dá 4,11:1 sobre
76
+ branco e reprova o WCAG 1.4.3 — a hierarquia fica com o tamanho e o peso. */
75
77
  .umds-side-panel-item__num {
76
78
  flex-shrink: 0;
77
79
  font-size: 11px; /* produto: 11px */
78
80
  font-weight: var(--umds-primitive-font-weight-bold);
79
- color: var(--umds-semantic-color-neutral-dark-medium);
81
+ color: var(--umds-semantic-color-neutral-dark-down);
80
82
  }
81
83
 
82
84
  .umds-side-panel-item--ativo .umds-side-panel-item__num {
@@ -17,9 +17,9 @@
17
17
  .umds-side-panel-search__campo {
18
18
  width: 100%;
19
19
  height: 30px; /* produto: 30px — entre os degraus 24 e 32 */
20
- padding: 0 var(--umds-primitive-spacing-nano) 0 28px; /* produto: 0 8px 0 28px */
20
+ padding: 0 var(--umds-primitive-spacing-nano) 0 var(--umds-primitive-spacing-xs); /* 0 8px 0 32px — 24px encostaria o texto na lupa (produto: 28px) */
21
21
  border: 1px solid var(--umds-semantic-color-neutral-light-down);
22
- border-radius: 6px; /* produto: 6px — a escala do DS só tem 8 */
22
+ border-radius: var(--umds-primitive-border-radius-sm); /* 8px — raio canônico (produto: 6px) */
23
23
  background: var(--umds-semantic-color-neutral-light-up);
24
24
  color: var(--umds-semantic-color-neutral-dark-pure);
25
25
  font-family: inherit;
@@ -9,10 +9,11 @@
9
9
  align-items: center;
10
10
  justify-content: space-between;
11
11
  gap: var(--umds-primitive-spacing-nano); /* 8px */
12
- padding: var(--umds-primitive-spacing-nano) var(--umds-primitive-spacing-nano)
13
- 6px; /* produto: 8px 8px 6px */
14
- margin-top: 14px; /* produto: 14px — entre os degraus 12 e 16 */
15
- color: var(--umds-semantic-color-neutral-dark-medium);
12
+ padding: var(--umds-primitive-spacing-nano); /* 8px (produto: 8px 8px 6px) */
13
+ margin-top: var(--umds-primitive-spacing-mini); /* 12px (produto: 14px) */
14
+ /* neutral-dark-down: o rótulo é texto de 10px e o #7D7D7D do produto dá
15
+ 4,11:1 sobre branco (WCAG 1.4.3 pede 4,5:1). */
16
+ color: var(--umds-semantic-color-neutral-dark-down);
16
17
  font-size: 10px; /* produto: 10px — abaixo do menor degrau (12) */
17
18
  font-weight: var(--umds-primitive-font-weight-bold);
18
19
  line-height: 15px; /* produto: 15px */
@@ -27,9 +28,10 @@
27
28
  width: 23px; /* produto: 23px */
28
29
  height: 20px; /* produto: 20px */
29
30
  padding: 0 var(--umds-primitive-spacing-micro) 0 0; /* produto: 0 2px 0 0 */
31
+ /* stylelint-disable-next-line 1ds/espaco-da-escala -- ajuste óptico: alinha o glifo com a borda do grupo, não é degrau de espaço */
30
32
  margin-right: -3px; /* produto: -3px — alinha o glifo com a borda do grupo */
31
33
  border: 1px solid transparent;
32
- border-radius: 5px; /* produto: 5px */
34
+ border-radius: var(--umds-primitive-border-radius-sm); /* 8px — raio canônico (produto: 5px) */
33
35
  background: none;
34
36
  color: inherit;
35
37
  cursor: pointer;
@@ -55,3 +55,52 @@
55
55
  .umds-stack--justify-between { justify-content: space-between; }
56
56
  .umds-stack--justify-around { justify-content: space-around; }
57
57
  .umds-stack--justify-evenly { justify-content: space-evenly; }
58
+
59
+ /* ── Sem espaço ── */
60
+ .umds-stack--gap-none { gap: 0; }
61
+
62
+ /* ── Lista: ul/ol sem marcador, margem nem recuo do navegador ── */
63
+ ul.umds-stack,
64
+ ol.umds-stack {
65
+ list-style: none;
66
+ margin: 0;
67
+ padding: 0;
68
+ }
69
+
70
+ /* ── Como item de outro Stack/flex ── */
71
+ .umds-stack--grow { flex-grow: 1; }
72
+ .umds-stack--shrink-0 { flex-shrink: 0; }
73
+ .umds-stack--shrink-1 { flex-shrink: 1; }
74
+
75
+ .umds-stack--basis-auto { flex-basis: auto; }
76
+ .umds-stack--basis-0 { flex-basis: 0; }
77
+ .umds-stack--basis-25 { flex-basis: 25%; }
78
+ .umds-stack--basis-33 { flex-basis: 33.3333%; }
79
+ .umds-stack--basis-50 { flex-basis: 50%; }
80
+ .umds-stack--basis-66 { flex-basis: 66.6667%; }
81
+ .umds-stack--basis-75 { flex-basis: 75%; }
82
+ .umds-stack--basis-100 { flex-basis: 100%; }
83
+
84
+ /* O padrão do Stack já é min-width: 0; estas duas só tornam a escolha explícita. */
85
+ .umds-stack--min-w-0 { min-width: 0; }
86
+ .umds-stack--min-w-auto { min-width: auto; }
87
+
88
+ /* ── Overflow: o eixo vem depois do geral, então vence por ordem de cascata ── */
89
+ .umds-stack--overflow-visible { overflow: visible; }
90
+ .umds-stack--overflow-hidden { overflow: hidden; }
91
+ .umds-stack--overflow-auto { overflow: auto; }
92
+ .umds-stack--overflow-scroll { overflow: scroll; }
93
+
94
+ .umds-stack--overflow-x-visible { overflow-x: visible; }
95
+ .umds-stack--overflow-x-hidden { overflow-x: hidden; }
96
+ .umds-stack--overflow-x-auto { overflow-x: auto; }
97
+ .umds-stack--overflow-x-scroll { overflow-x: scroll; }
98
+
99
+ .umds-stack--overflow-y-visible { overflow-y: visible; }
100
+ .umds-stack--overflow-y-hidden { overflow-y: hidden; }
101
+ .umds-stack--overflow-y-auto { overflow-y: auto; }
102
+ .umds-stack--overflow-y-scroll { overflow-y: scroll; }
103
+
104
+ /* ── Dimensão ── */
105
+ .umds-stack--full-height { height: 100%; }
106
+ .umds-stack--full-width { width: 100%; }
@@ -1,27 +1,60 @@
1
1
  import './Stack.css';
2
- /** Degraus da escala oficial de espaçamento do 1DS. */
3
- export type StackSpacing = "quarck" | "nano" | "micro" | "mini" | "xxxs" | "xxs" | "xs" | "sm" | "md" | "lg" | "xl" | "xxl" | "xxxl";
2
+ /** Degraus da escala oficial de espaçamento do 1DS. `none` zera o espaço. */
3
+ export type StackSpacing = "none" | "quarck" | "nano" | "micro" | "mini" | "xxxs" | "xxs" | "xs" | "sm" | "md" | "lg" | "xl" | "xxl" | "xxxl";
4
+ /** Elemento HTML que o Stack renderiza. */
5
+ /** Degraus da escala oficial de espaçamento do 1DS. `none` zera o espaço. */
6
+ /** Elemento HTML que o Stack renderiza. */
7
+ export type StackTag = "div" | "span" | "ul" | "ol" | "li" | "section" | "nav" | "header" | "footer" | "form";
8
+ /** Valores de `overflow` aceitos (por eixo ou nos dois). */
9
+ /** Degraus da escala oficial de espaçamento do 1DS. `none` zera o espaço. */
10
+ /** Elemento HTML que o Stack renderiza. */
11
+ /** Valores de `overflow` aceitos (por eixo ou nos dois). */
12
+ export type StackOverflow = "visible" | "hidden" | "auto" | "scroll";
4
13
  /**
5
14
  * Stack — empilha os filhos com espaçamento da escala do DS.
6
15
  *
7
16
  * Existe para eliminar o `style={{ display: "flex", gap: 16 }}` escrito à mão,
8
17
  * que é por onde o design system vaza: o 16 sai da cabeça de quem escreve, não
9
18
  * do token. Aqui o `gap` só aceita degraus da escala oficial.
19
+ *
20
+ * Também é o item de outro Stack: quem precisa crescer, encolher ou ocupar a
21
+ * altura toda dentro de um Stack pai aninha um Stack com `grow`, `shrink`,
22
+ * `basis`, `fullHeight`... (não existe `Stack.Item`: subcomponente por ponto
23
+ * não sobrevive aos dois geradores, e o Stack aninhado já é um item flex).
24
+ *
25
+ * Atributos HTML (`id`, `style`, `title`, `role`, `tabIndex`, `data-*`,
26
+ * `aria-*`) vão para o elemento raiz. Com `as="nav"`, `section` ou `form`,
27
+ * passe `aria-label` ou `aria-labelledby`: a região só é anunciada se tiver nome.
28
+ * @property {string} as - Elemento HTML: 'div' (padrão) | 'span' | 'ul' | 'ol' | 'li' | 'section' | 'nav' | 'header' | 'footer' | 'form'
10
29
  * @property {string} direction - Eixo do empilhamento: 'vertical' (padrão) | 'horizontal'
11
- * @property {string} gap - Espaço entre os filhos, na escala do DS
30
+ * @property {string} gap - Espaço entre os filhos, na escala do DS ('none' zera)
12
31
  * @property {string} align - Alinhamento no eixo transversal
13
32
  * @property {string} justify - Distribuição no eixo principal
14
33
  * @property {boolean} wrap - Permite quebrar em várias linhas
15
34
  * @property {boolean} inline - Usa display inline-flex em vez de flex
35
+ * @property {boolean} grow - Como item de outro Stack/flex: cresce para ocupar o espaço livre
36
+ * @property {string} shrink - Como item flex: '0' não encolhe, '1' encolhe
37
+ * @property {string} basis - Como item flex: tamanho base ('auto', '0', '25', '33', '50', '66', '75', '100'; os números são %)
38
+ * @property {string} minWidth - '0' (padrão do Stack) deixa o conteúdo longo encolher; 'auto' devolve o mínimo do conteúdo
39
+ * @property {string} overflow - Overflow nos dois eixos
40
+ * @property {string} overflowX - Overflow horizontal
41
+ * @property {string} overflowY - Overflow vertical
42
+ * @property {boolean} fullHeight - Ocupa 100% da altura do pai
43
+ * @property {boolean} fullWidth - Ocupa 100% da largura do pai
16
44
  * @property {string} className - Classes CSS adicionais
17
- * @quandoUsar Empilhar elementos com espaçamento consistente: campos de um formulário, botões de uma barra de ações, itens de uma lista. É o jeito certo de dar respiro sem escrever CSS.
18
- * @quandoNaoUsar Para layout em COLUNAS que se alinham entre si — use `Grid`. Para uma caixa com padding e fundo, use `Box`. Stack só distribui no eixo, não desenha nada.
45
+ * @property {function} onSubmit - Só com as="form": callback do envio
46
+ * @quandoUsar Empilhar elementos com espaçamento consistente: campos de um formulário, botões de uma barra de ações, itens de uma lista (`as="ul"` com filhos `as="li"`). É o jeito certo de dar respiro sem escrever CSS, e de fazer uma região crescer ou rolar dentro de outra.
47
+ * @quandoNaoUsar Para layout em COLUNAS que se alinham entre si — use `Grid`. Para uma caixa com padding e fundo, use `Box` (que também aceita direction e gap quando a superfície é a própria linha ou região). Stack só distribui no eixo, não desenha nada.
19
48
  */
20
- /** Degraus da escala oficial de espaçamento do 1DS. */
49
+ /** Degraus da escala oficial de espaçamento do 1DS. `none` zera o espaço. */
50
+ /** Elemento HTML que o Stack renderiza. */
51
+ /** Valores de `overflow` aceitos (por eixo ou nos dois). */
21
52
  export interface StackProps {
53
+ /** Elemento HTML renderizado. @default 'div' */
54
+ as?: StackTag;
22
55
  /** Eixo do empilhamento. @default 'vertical' */
23
56
  direction?: "vertical" | "horizontal";
24
- /** Espaço entre os filhos, na escala oficial (xxxs = 16px). @default 'xxxs' */
57
+ /** Espaço entre os filhos, na escala oficial (xxxs = 16px; `none` = 0). @default 'xxxs' */
25
58
  gap?: StackSpacing;
26
59
  /** Alinhamento no eixo transversal. */
27
60
  align?: "start" | "center" | "end" | "stretch" | "baseline";
@@ -31,8 +64,33 @@ export interface StackProps {
31
64
  wrap?: boolean;
32
65
  /** Usa `inline-flex` em vez de `flex`. */
33
66
  inline?: boolean;
67
+ /** Como item de outro Stack/flex: cresce para ocupar o espaço livre. */
68
+ grow?: boolean;
69
+ /** Como item flex: `"0"` não encolhe; `"1"` encolhe. */
70
+ shrink?: "0" | "1";
71
+ /** Como item flex: tamanho base. Os números são porcentagem do pai. */
72
+ basis?: "auto" | "0" | "25" | "33" | "50" | "66" | "75" | "100";
73
+ /** `"0"` (já é o padrão do Stack) deixa o conteúdo encolher; `"auto"` volta ao mínimo do conteúdo. */
74
+ minWidth?: "0" | "auto";
75
+ /** Overflow nos dois eixos. */
76
+ overflow?: StackOverflow;
77
+ /** Overflow horizontal (vence `overflow` no eixo X). */
78
+ overflowX?: StackOverflow;
79
+ /** Overflow vertical (vence `overflow` no eixo Y). */
80
+ overflowY?: StackOverflow;
81
+ /** Ocupa 100% da altura do pai. */
82
+ fullHeight?: boolean;
83
+ /** Ocupa 100% da largura do pai. */
84
+ fullWidth?: boolean;
34
85
  /** Classes CSS adicionais. */
35
86
  className?: string;
87
+ /** Só com `as="form"`: chamado no envio do formulário. */
88
+ onSubmit?: (event: any) => void;
89
+ /** ID HTML do elemento raiz. */
90
+ id?: string;
91
+ /** Atributos HTML repassados ao elemento raiz (style, data-*, aria-*…). */
92
+ style?: any;
93
+ [key: string]: any;
36
94
  /** Conteúdo empilhado. */
37
95
  children?: any;
38
96
  }
@@ -1,6 +1,10 @@
1
- import { Fragment as _Fragment, jsx as _jsx } from "react/jsx-runtime";
1
+ "use client";
2
+ import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
3
  import './Stack.css';
3
4
  function Stack(props) {
5
+ function elementTag() {
6
+ return props.as || "div";
7
+ }
4
8
  function classes() {
5
9
  return [
6
10
  "umds-stack",
@@ -10,11 +14,35 @@ function Stack(props) {
10
14
  props.justify ? `umds-stack--justify-${props.justify}` : "",
11
15
  props.wrap ? "umds-stack--wrap" : "",
12
16
  props.inline ? "umds-stack--inline" : "",
17
+ props.grow ? "umds-stack--grow" : "",
18
+ props.shrink ? `umds-stack--shrink-${props.shrink}` : "",
19
+ props.basis ? `umds-stack--basis-${props.basis}` : "",
20
+ props.minWidth ? `umds-stack--min-w-${props.minWidth}` : "",
21
+ props.overflow ? `umds-stack--overflow-${props.overflow}` : "",
22
+ props.overflowX ? `umds-stack--overflow-x-${props.overflowX}` : "",
23
+ props.overflowY ? `umds-stack--overflow-y-${props.overflowY}` : "",
24
+ props.fullHeight ? "umds-stack--full-height" : "",
25
+ props.fullWidth ? "umds-stack--full-width" : "",
13
26
  props.className,
14
27
  ]
15
28
  .filter(Boolean)
16
29
  .join(" ");
17
30
  }
18
- return (_jsx("div", { className: classes(), children: _jsx(_Fragment, { children: props.children }) }));
31
+ function htmlAttrs() {
32
+ const out = {};
33
+ for (const chave in props) {
34
+ if (chave.indexOf("data-") === 0 ||
35
+ chave.indexOf("aria-") === 0 ||
36
+ chave === "style" ||
37
+ chave === "class" ||
38
+ chave === "title" ||
39
+ chave === "role" ||
40
+ chave === "tabIndex") {
41
+ out[chave] = props[chave];
42
+ }
43
+ }
44
+ return out;
45
+ }
46
+ return (_jsxs(_Fragment, { children: [elementTag() === "div" ? (_jsx("div", { id: props.id, ...htmlAttrs(), className: classes(), children: _jsx(_Fragment, { children: props.children }) })) : null, elementTag() === "span" ? (_jsx("span", { id: props.id, ...htmlAttrs(), className: classes(), children: _jsx(_Fragment, { children: props.children }) })) : null, elementTag() === "ul" ? (_jsx("ul", { role: "list", id: props.id, ...htmlAttrs(), className: classes(), children: _jsx(_Fragment, { children: props.children }) })) : null, elementTag() === "ol" ? (_jsx("ol", { role: "list", id: props.id, ...htmlAttrs(), className: classes(), children: _jsx(_Fragment, { children: props.children }) })) : null, elementTag() === "li" ? (_jsx("li", { id: props.id, ...htmlAttrs(), className: classes(), children: _jsx(_Fragment, { children: props.children }) })) : null, elementTag() === "section" ? (_jsx("section", { id: props.id, ...htmlAttrs(), className: classes(), children: _jsx(_Fragment, { children: props.children }) })) : null, elementTag() === "nav" ? (_jsx("nav", { id: props.id, ...htmlAttrs(), className: classes(), children: _jsx(_Fragment, { children: props.children }) })) : null, elementTag() === "header" ? (_jsx("header", { id: props.id, ...htmlAttrs(), className: classes(), children: _jsx(_Fragment, { children: props.children }) })) : null, elementTag() === "footer" ? (_jsx("footer", { id: props.id, ...htmlAttrs(), className: classes(), children: _jsx(_Fragment, { children: props.children }) })) : null, elementTag() === "form" ? (_jsx("form", { id: props.id, onSubmit: (event) => props.onSubmit && props.onSubmit(event), ...htmlAttrs(), className: classes(), children: _jsx(_Fragment, { children: props.children }) })) : null] }));
19
47
  }
20
48
  export default Stack;
@@ -152,3 +152,76 @@
152
152
  .umds-stat-card__variacao--neutral {
153
153
  color: var(--umds-semantic-color-neutral-dark-down);
154
154
  }
155
+
156
+ /* ── ⓘ de ajuda ao lado do rótulo (infoTooltip) ── */
157
+ .umds-stat-card__rotulo {
158
+ display: inline-flex;
159
+ align-items: center;
160
+ gap: var(--umds-primitive-spacing-nano);
161
+ }
162
+
163
+ .umds-stat-card__info {
164
+ display: inline-flex;
165
+ align-items: center;
166
+ justify-content: center;
167
+ padding: 0;
168
+ border: none;
169
+ background: transparent;
170
+ color: var(--umds-semantic-color-neutral-dark-medium);
171
+ cursor: help;
172
+ border-radius: var(--umds-primitive-border-radius-circular);
173
+ }
174
+
175
+ .umds-stat-card__info:hover {
176
+ color: var(--umds-semantic-color-neutral-dark-pure);
177
+ }
178
+
179
+ .umds-stat-card__info:focus-visible {
180
+ outline: 2px solid var(--umds-semantic-color-primary-pure);
181
+ outline-offset: 2px;
182
+ }
183
+
184
+ /* ── labelPosition="top": rótulo no topo, ícone e número embaixo ──
185
+ O HTML segue com o número antes do rótulo (a ordem do leitor de tela); só a
186
+ grade muda a ordem visual. O corpo vira `display: contents` para o rótulo,
187
+ o número e o resto virarem itens da própria grade do cartão. */
188
+ .umds-stat-card--rotulo-topo {
189
+ display: grid;
190
+ grid-template-columns: auto 1fr;
191
+ align-items: center;
192
+ column-gap: 0;
193
+ row-gap: var(--umds-primitive-spacing-nano);
194
+ }
195
+
196
+ .umds-stat-card--rotulo-topo .umds-stat-card__corpo {
197
+ display: contents;
198
+ }
199
+
200
+ .umds-stat-card--rotulo-topo .umds-stat-card__rotulo {
201
+ grid-column: 1 / -1;
202
+ grid-row: 1;
203
+ font-weight: var(--umds-primitive-font-weight-semibold);
204
+ }
205
+
206
+ .umds-stat-card--rotulo-topo .umds-stat-card__icone {
207
+ grid-column: 1;
208
+ grid-row: 2;
209
+ margin-right: var(--umds-primitive-spacing-mini);
210
+ }
211
+
212
+ .umds-stat-card--rotulo-topo .umds-stat-card__valor {
213
+ grid-column: 2;
214
+ grid-row: 2;
215
+ font-size: var(--umds-primitive-font-size-lg); /* 32px */
216
+ font-weight: var(--umds-primitive-font-weight-extrabold);
217
+ }
218
+
219
+ .umds-stat-card--rotulo-topo .umds-stat-card__descricao,
220
+ .umds-stat-card--rotulo-topo .umds-stat-card__variacao {
221
+ grid-column: 1 / -1;
222
+ }
223
+
224
+ /* Sem ícone, o número ocupa a linha toda. */
225
+ .umds-stat-card--rotulo-topo:not(:has(.umds-stat-card__icone)) .umds-stat-card__valor {
226
+ grid-column: 1 / -1;
227
+ }