@1doc/1ds-react 2.8.0 → 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 (213) hide show
  1. package/CHANGELOG.md +1106 -0
  2. package/dist/components/AILabel/AILabel.js +1 -1
  3. package/dist/components/Accordion/Accordion.d.ts +6 -2
  4. package/dist/components/AttachmentCard/AttachmentCard.css +16 -0
  5. package/dist/components/AttachmentCard/AttachmentCard.d.ts +19 -2
  6. package/dist/components/AttachmentCard/AttachmentCard.js +40 -3
  7. package/dist/components/Avatar/Avatar.css +7 -2
  8. package/dist/components/Avatar/AvatarGroup.d.ts +17 -0
  9. package/dist/components/Avatar/AvatarGroup.js +22 -8
  10. package/dist/components/Badge/Badge.css +54 -2
  11. package/dist/components/Badge/Badge.d.ts +14 -4
  12. package/dist/components/Badge/Badge.js +1 -0
  13. package/dist/components/Box/Box.css +83 -0
  14. package/dist/components/Box/Box.d.ts +82 -2
  15. package/dist/components/Box/Box.js +42 -2
  16. package/dist/components/Button/Button.css +29 -0
  17. package/dist/components/Button/Button.d.ts +4 -4
  18. package/dist/components/Button/Button.js +4 -1
  19. package/dist/components/Calendar/Calendar.css +245 -0
  20. package/dist/components/Calendar/Calendar.d.ts +125 -0
  21. package/dist/components/Calendar/Calendar.js +320 -0
  22. package/dist/components/Chips/Chips.css +38 -0
  23. package/dist/components/Chips/Chips.d.ts +5 -2
  24. package/dist/components/Chips/Chips.js +2 -1
  25. package/dist/components/Coachmark/Coachmark.css +118 -0
  26. package/dist/components/Coachmark/Coachmark.d.ts +75 -0
  27. package/dist/components/Coachmark/Coachmark.js +321 -0
  28. package/dist/components/CodeBlock/CodeBlock.css +96 -0
  29. package/dist/components/CodeBlock/CodeBlock.d.ts +47 -0
  30. package/dist/components/CodeBlock/CodeBlock.js +103 -0
  31. package/dist/components/ColorPicker/ColorPicker.css +133 -0
  32. package/dist/components/ColorPicker/ColorPicker.d.ts +73 -0
  33. package/dist/components/ColorPicker/ColorPicker.js +219 -0
  34. package/dist/components/Combobox/Combobox.css +8 -0
  35. package/dist/components/DataTable/DataTable.css +80 -0
  36. package/dist/components/DataTable/DataTable.d.ts +19 -4
  37. package/dist/components/DataTable/DataTable.js +59 -15
  38. package/dist/components/DatePicker/DatePicker.css +8 -0
  39. package/dist/components/DatePicker/DatePicker.js +10 -1
  40. package/dist/components/DescriptionList/DescriptionList.css +113 -0
  41. package/dist/components/DescriptionList/DescriptionList.d.ts +59 -0
  42. package/dist/components/DescriptionList/DescriptionList.js +51 -0
  43. package/dist/components/FileInput/FileInput.css +16 -0
  44. package/dist/components/FileInput/FileInput.d.ts +4 -2
  45. package/dist/components/FileInput/FileInput.js +8 -2
  46. package/dist/components/Grid/Grid.js +5 -5
  47. package/dist/components/IconPicker/IconPicker.css +107 -0
  48. package/dist/components/IconPicker/IconPicker.d.ts +74 -0
  49. package/dist/components/IconPicker/IconPicker.js +194 -0
  50. package/dist/components/Input/Input.css +38 -0
  51. package/dist/components/Input/Input.d.ts +10 -1
  52. package/dist/components/Input/Input.js +66 -5
  53. package/dist/components/Kanban/Kanban.css +4 -0
  54. package/dist/components/Kbd/Kbd.css +66 -0
  55. package/dist/components/Kbd/Kbd.d.ts +32 -0
  56. package/dist/components/Kbd/Kbd.js +40 -0
  57. package/dist/components/List/List.css +136 -0
  58. package/dist/components/List/List.d.ts +82 -0
  59. package/dist/components/List/List.js +53 -0
  60. package/dist/components/List/ListItem.d.ts +85 -0
  61. package/dist/components/List/ListItem.js +81 -0
  62. package/dist/components/Modal/Modal.css +80 -0
  63. package/dist/components/Modal/Modal.d.ts +33 -6
  64. package/dist/components/Modal/Modal.js +101 -6
  65. package/dist/components/MultiSelect/MultiSelect.css +8 -0
  66. package/dist/components/MultiSelect/MultiSelect.js +10 -1
  67. package/dist/components/OrgChart/OrgChart.css +149 -0
  68. package/dist/components/OrgChart/OrgChart.d.ts +83 -0
  69. package/dist/components/OrgChart/OrgChart.js +297 -0
  70. package/dist/components/OtpInput/OtpInput.css +93 -0
  71. package/dist/components/OtpInput/OtpInput.d.ts +60 -0
  72. package/dist/components/OtpInput/OtpInput.js +215 -0
  73. package/dist/components/PhoneInput/PhoneInput.css +8 -0
  74. package/dist/components/Popover/Popover.d.ts +7 -0
  75. package/dist/components/Popover/Popover.js +11 -1
  76. package/dist/components/RichTextEditor/RichTextEditor.css +203 -0
  77. package/dist/components/RichTextEditor/RichTextEditor.d.ts +83 -0
  78. package/dist/components/RichTextEditor/RichTextEditor.js +494 -0
  79. package/dist/components/SegmentedControl/SegmentedControl.js +7 -2
  80. package/dist/components/Select/Select.css +70 -0
  81. package/dist/components/Select/Select.d.ts +12 -0
  82. package/dist/components/Select/Select.js +59 -4
  83. package/dist/components/Stack/Stack.css +49 -0
  84. package/dist/components/Stack/Stack.d.ts +65 -7
  85. package/dist/components/Stack/Stack.js +30 -2
  86. package/dist/components/StatCard/StatCard.css +73 -0
  87. package/dist/components/StatCard/StatCard.d.ts +17 -0
  88. package/dist/components/StatCard/StatCard.js +4 -1
  89. package/dist/components/Tabs/Tab.d.ts +15 -0
  90. package/dist/components/Tabs/Tab.js +30 -1
  91. package/dist/components/Tabs/Tabs.css +132 -0
  92. package/dist/components/Tabs/Tabs.d.ts +7 -0
  93. package/dist/components/Tabs/Tabs.js +13 -2
  94. package/dist/components/Tag/Tag.css +85 -2
  95. package/dist/components/Tag/Tag.d.ts +13 -6
  96. package/dist/components/Tag/Tag.js +1 -0
  97. package/dist/components/Text/Text.js +2 -2
  98. package/dist/components/Textarea/Textarea.css +8 -0
  99. package/dist/components/TimePicker/TimePicker.css +8 -0
  100. package/dist/components/Tooltip/Tooltip.css +25 -0
  101. package/dist/components/Tooltip/Tooltip.d.ts +11 -0
  102. package/dist/components/Tooltip/Tooltip.js +18 -3
  103. package/dist/index.d.ts +25 -0
  104. package/dist/index.js +14 -0
  105. package/dist/teste/AILabel.test.d.ts +1 -0
  106. package/dist/teste/AILabel.test.js +33 -0
  107. package/dist/teste/AccordionConteudoLivre.test.d.ts +1 -0
  108. package/dist/teste/AccordionConteudoLivre.test.js +29 -0
  109. package/dist/teste/AtributosRepassados.test.d.ts +1 -0
  110. package/dist/teste/AtributosRepassados.test.js +52 -0
  111. package/dist/teste/AttachmentCardIA.test.d.ts +1 -0
  112. package/dist/teste/AttachmentCardIA.test.js +89 -0
  113. package/dist/teste/AvatarGroupOverlap.test.d.ts +1 -0
  114. package/dist/teste/AvatarGroupOverlap.test.js +56 -0
  115. package/dist/teste/BadgeTag.test.d.ts +1 -0
  116. package/dist/teste/BadgeTag.test.js +42 -0
  117. package/dist/teste/BoxItemFlex.test.d.ts +1 -0
  118. package/dist/teste/BoxItemFlex.test.js +54 -0
  119. package/dist/teste/BoxLayout.test.d.ts +1 -0
  120. package/dist/teste/BoxLayout.test.js +35 -0
  121. package/dist/teste/Button.test.d.ts +1 -0
  122. package/dist/teste/Button.test.js +27 -0
  123. package/dist/teste/Calendar.test.d.ts +1 -0
  124. package/dist/teste/Calendar.test.js +221 -0
  125. package/dist/teste/ChipsXs.test.d.ts +1 -0
  126. package/dist/teste/ChipsXs.test.js +31 -0
  127. package/dist/teste/Coachmark.test.d.ts +1 -0
  128. package/dist/teste/Coachmark.test.js +149 -0
  129. package/dist/teste/ColorPicker.test.d.ts +1 -0
  130. package/dist/teste/ColorPicker.test.js +132 -0
  131. package/dist/teste/DataTableCelulaLivre.test.d.ts +1 -0
  132. package/dist/teste/DataTableCelulaLivre.test.js +76 -0
  133. package/dist/teste/DataTableDocumento.test.d.ts +1 -0
  134. package/dist/teste/DataTableDocumento.test.js +92 -0
  135. package/dist/teste/DatePicker.test.js +23 -0
  136. package/dist/teste/FileInputTrigger.test.d.ts +1 -0
  137. package/dist/teste/FileInputTrigger.test.js +53 -0
  138. package/dist/teste/IconPicker.test.d.ts +1 -0
  139. package/dist/teste/IconPicker.test.js +130 -0
  140. package/dist/teste/InputMascaraEAfins.test.d.ts +1 -0
  141. package/dist/teste/InputMascaraEAfins.test.js +99 -0
  142. package/dist/teste/KbdCodeBlock.test.d.ts +1 -0
  143. package/dist/teste/KbdCodeBlock.test.js +95 -0
  144. package/dist/teste/List.test.d.ts +1 -0
  145. package/dist/teste/List.test.js +153 -0
  146. package/dist/teste/ModalVariantes.test.d.ts +1 -0
  147. package/dist/teste/ModalVariantes.test.js +151 -0
  148. package/dist/teste/NomeAcessivelSsr.test.d.ts +1 -0
  149. package/dist/teste/NomeAcessivelSsr.test.js +88 -0
  150. package/dist/teste/OrgChart.test.d.ts +1 -0
  151. package/dist/teste/OrgChart.test.js +162 -0
  152. package/dist/teste/OtpInput.test.d.ts +1 -0
  153. package/dist/teste/OtpInput.test.js +143 -0
  154. package/dist/teste/PopoverMaxHeight.test.d.ts +1 -0
  155. package/dist/teste/PopoverMaxHeight.test.js +38 -0
  156. package/dist/teste/RichTextEditor.test.d.ts +1 -0
  157. package/dist/teste/RichTextEditor.test.js +287 -0
  158. package/dist/teste/SelectPlacementFiltro.test.d.ts +1 -0
  159. package/dist/teste/SelectPlacementFiltro.test.js +88 -0
  160. package/dist/teste/Stack.test.d.ts +1 -0
  161. package/dist/teste/Stack.test.js +57 -0
  162. package/dist/teste/StatCardRotuloTopo.test.d.ts +1 -0
  163. package/dist/teste/StatCardRotuloTopo.test.js +34 -0
  164. package/dist/teste/TabsContadorFechavel.test.d.ts +1 -0
  165. package/dist/teste/TabsContadorFechavel.test.js +79 -0
  166. package/dist/teste/TooltipDark.test.d.ts +1 -0
  167. package/dist/teste/TooltipDark.test.js +31 -0
  168. package/dist/utils/calendario.d.ts +28 -0
  169. package/dist/utils/calendario.js +73 -0
  170. package/dist/utils/html-seguro.d.ts +27 -0
  171. package/dist/utils/html-seguro.js +97 -0
  172. package/dist/utils/paleta-de-cores.d.ts +26 -0
  173. package/dist/utils/paleta-de-cores.js +10 -0
  174. package/dist/utils/texto.d.ts +5 -0
  175. package/dist/utils/texto.js +5 -0
  176. package/package.json +3 -3
  177. package/src/index.ts +26 -0
  178. package/src/teste/AILabel.test.tsx +41 -0
  179. package/src/teste/AccordionConteudoLivre.test.tsx +39 -0
  180. package/src/teste/AtributosRepassados.test.tsx +73 -0
  181. package/src/teste/AttachmentCardIA.test.tsx +126 -0
  182. package/src/teste/AvatarGroupOverlap.test.tsx +74 -0
  183. package/src/teste/BadgeTag.test.tsx +64 -0
  184. package/src/teste/BoxItemFlex.test.tsx +81 -0
  185. package/src/teste/BoxLayout.test.tsx +50 -0
  186. package/src/teste/Button.test.tsx +39 -0
  187. package/src/teste/Calendar.test.tsx +282 -0
  188. package/src/teste/ChipsXs.test.tsx +41 -0
  189. package/src/teste/Coachmark.test.tsx +198 -0
  190. package/src/teste/ColorPicker.test.tsx +153 -0
  191. package/src/teste/DataTableCelulaLivre.test.tsx +103 -0
  192. package/src/teste/DataTableDocumento.test.tsx +102 -0
  193. package/src/teste/DatePicker.test.tsx +38 -0
  194. package/src/teste/FileInputTrigger.test.tsx +89 -0
  195. package/src/teste/IconPicker.test.tsx +145 -0
  196. package/src/teste/InputMascaraEAfins.test.tsx +124 -0
  197. package/src/teste/KbdCodeBlock.test.tsx +106 -0
  198. package/src/teste/List.test.tsx +269 -0
  199. package/src/teste/ModalVariantes.test.tsx +173 -0
  200. package/src/teste/NomeAcessivelSsr.test.tsx +110 -0
  201. package/src/teste/OrgChart.test.tsx +183 -0
  202. package/src/teste/OtpInput.test.tsx +163 -0
  203. package/src/teste/PopoverMaxHeight.test.tsx +47 -0
  204. package/src/teste/RichTextEditor.test.tsx +329 -0
  205. package/src/teste/SelectPlacementFiltro.test.tsx +110 -0
  206. package/src/teste/Stack.test.tsx +80 -0
  207. package/src/teste/StatCardRotuloTopo.test.tsx +44 -0
  208. package/src/teste/TabsContadorFechavel.test.tsx +144 -0
  209. package/src/teste/TooltipDark.test.tsx +51 -0
  210. package/src/utils/calendario.ts +78 -0
  211. package/src/utils/html-seguro.ts +94 -0
  212. package/src/utils/paleta-de-cores.ts +34 -0
  213. package/src/utils/texto.ts +5 -0
@@ -31,6 +31,7 @@ function Select(props) {
31
31
  : props.defaultValue !== undefined && props.defaultValue !== null
32
32
  ? [props.defaultValue]
33
33
  : Array());
34
+ const [opensUp, setOpensUp] = useState(() => false);
34
35
  const [shouldFocusSearch, setShouldFocusSearch] = useState(() => false);
35
36
  const [shouldFocusTrigger, setShouldFocusTrigger] = useState(() => false);
36
37
  const [activeIndex, setActiveIndex] = useState(() => -1);
@@ -92,6 +93,12 @@ function Select(props) {
92
93
  : internalSelected || [];
93
94
  if (currentVal.length === 0)
94
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...";
95
102
  if (props.multiple) {
96
103
  if (props.selectionDisplay === "tags")
97
104
  return "";
@@ -117,6 +124,11 @@ function Select(props) {
117
124
  ? []
118
125
  : [props.value]
119
126
  : internalSelected || [];
127
+ if (props.emptyOptionLabel &&
128
+ !props.multiple &&
129
+ currentVal.length === 1 &&
130
+ currentVal[0] === "")
131
+ return true;
120
132
  return currentVal.length === 0;
121
133
  }
122
134
  function formValue() {
@@ -132,9 +144,18 @@ function Select(props) {
132
144
  function filteredOptionsList() {
133
145
  if (!props.options)
134
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
+ : [];
135
156
  // If it's remote search (onSearchChange provided), we don't filter locally
136
157
  if (!props.searchable || !searchTerm || props.onSearchChange)
137
- return props.options;
158
+ return vazia.concat(props.options);
138
159
  const term = searchTerm.toLowerCase();
139
160
  return props.options.filter((opt) => opt.label.toLowerCase().includes(term));
140
161
  }
@@ -148,6 +169,10 @@ function Select(props) {
148
169
  props.invalid ? "umds-select--invalid" : "",
149
170
  isOpen ? "umds-select--open" : "",
150
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
+ : "",
151
176
  props.multiple &&
152
177
  props.selectionDisplay === "tags" &&
153
178
  selectedOptionsList().length > 0
@@ -164,6 +189,14 @@ function Select(props) {
164
189
  function labelIdText() {
165
190
  return baseId() ? baseId() + "-label" : undefined;
166
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;
199
+ }
167
200
  function activeDescendantText() {
168
201
  if (!isOpen || activeIndex < 0 || !baseId())
169
202
  return undefined;
@@ -175,6 +208,21 @@ function Select(props) {
175
208
  function removeItemAriaLabelText(label) {
176
209
  return (props.removeAriaLabel || "Remover") + " " + label;
177
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
+ }
178
226
  function toggle() {
179
227
  if (props.disabled || props.readOnly)
180
228
  return;
@@ -184,10 +232,13 @@ function Select(props) {
184
232
  const next = !isOpen;
185
233
  setIsOpen(next);
186
234
  if (next) {
235
+ setOpensUp(shouldOpenUp());
187
236
  // Abre com a opção já selecionada ativa (padrão combobox).
188
237
  setActiveIndex(filteredOptionsList().findIndex((opt) => isOptionSelected(opt.value)));
189
238
  if (props.searchable &&
190
- (props.autoFocusSearch || props.searchVariant === "inline")) {
239
+ (props.autoFocusSearch ||
240
+ props.searchVariant === "inline" ||
241
+ props.variant === "filter")) {
191
242
  setShouldFocusSearch(true);
192
243
  }
193
244
  }
@@ -368,6 +419,10 @@ function Select(props) {
368
419
  ? []
369
420
  : [props.value]
370
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
+ }
371
426
  return currentVal.includes(val);
372
427
  }
373
428
  useEffect(() => {
@@ -417,7 +472,7 @@ function Select(props) {
417
472
  }
418
473
  };
419
474
  }, []);
420
- 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": 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 &&
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 &&
421
476
  props.selectionDisplay === "tags" &&
422
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"
423
478
  ? {
@@ -431,7 +486,7 @@ function Select(props) {
431
486
  index === activeIndex ? "umds-select__option--active" : "",
432
487
  ]
433
488
  .filter(Boolean)
434
- .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", id: errorIdText(), children: props.errorMessage })) : null, mostraApoio() ? (_jsx(Text, { variant: "caption", color: "secondary", className: "umds-select__description", id: helperIdText(), 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 &&
435
490
  props.selectionDisplay === "list" &&
436
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] }));
437
492
  }
@@ -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
+ }
@@ -22,6 +22,9 @@ import './StatCard.css';
22
22
  * @property {string} trendIntent - Se a variação é boa ou ruim (cor), independente da direção: 'positive' | 'negative' | 'neutral'
23
23
  * @property {string} trendLabel - Texto da variação (ex.: '12% em relação ao mês anterior')
24
24
  * @property {string} description - Texto auxiliar abaixo do rótulo
25
+ * @property {string} labelPosition - Onde o rótulo aparece: 'bottom' (padrão, embaixo do número) | 'top' (no topo do cartão, acima do ícone e do número, com o número em 32/800). No HTML o número continua vindo antes do rótulo, então o leitor de tela anuncia igual.
26
+ * @property {string} infoTooltip - Texto de ajuda: mostra um ⓘ ao lado do rótulo com um Tooltip escuro. É um botão dentro do cartão; com `onClick` no cartão, evite (botão dentro de botão).
27
+ * @property {string} infoLabel - Nome acessível do ⓘ. Troque para traduzir. Padrão: "Mais informações".
25
28
  * @property {string} align - Alinhamento do conteúdo
26
29
  * @property {string} className - Classes CSS adicionais
27
30
  * @property {function} onClick - Torna o cartão acionável (vira botão)
@@ -56,6 +59,20 @@ export interface StatCardProps {
56
59
  description?: string;
57
60
  /** Alinhamento do conteúdo. @default 'start' */
58
61
  align?: "start" | "center";
62
+ /**
63
+ * Onde o rótulo aparece. `top` põe o rótulo no topo do cartão, acima do
64
+ * ícone e do número (que passa a 32/800), como no painel da 1Doc. No HTML o
65
+ * número segue antes do rótulo: só a posição visual muda.
66
+ * @default 'bottom'
67
+ */
68
+ labelPosition?: "bottom" | "top";
69
+ /**
70
+ * Texto de ajuda: mostra o ⓘ ao lado do rótulo, com um Tooltip escuro. É um
71
+ * botão focável dentro do cartão; com `onClick` no cartão, evite.
72
+ */
73
+ infoTooltip?: string;
74
+ /** Nome acessível do ⓘ. @default 'Mais informações' */
75
+ infoLabel?: string;
59
76
  /** Classes CSS adicionais. */
60
77
  className?: string;
61
78
  /** Torna o cartão acionável. */
@@ -1,13 +1,16 @@
1
1
  "use client";
2
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  import './StatCard.css';
4
+ import { faCircleInfo } from "@fortawesome/free-solid-svg-icons";
4
5
  import Icon from "../Icon/Icon";
6
+ import Tooltip from "../Tooltip/Tooltip";
5
7
  function StatCard(props) {
6
8
  function classes() {
7
9
  return [
8
10
  "umds-stat-card",
9
11
  `umds-stat-card--${props.variant || "neutral"}`,
10
12
  props.align === "center" ? "umds-stat-card--centro" : "",
13
+ props.labelPosition === "top" ? "umds-stat-card--rotulo-topo" : "",
11
14
  props.onClick ? "umds-stat-card--acionavel" : "",
12
15
  props.className,
13
16
  ]
@@ -45,6 +48,6 @@ function StatCard(props) {
45
48
  if (props.onClick)
46
49
  props.onClick();
47
50
  }
48
- return (_jsxs("div", { className: classes(), onClick: (event) => aoClicar(), role: ehAcionavel() ? "button" : undefined, tabIndex: ehAcionavel() ? 0 : undefined, children: [props.icon ? (_jsx("span", { className: "umds-stat-card__icone", "aria-hidden": "true", children: _jsx(Icon, { size: "md", variant: "inherit", icon: props.icon }) })) : null, _jsxs("div", { className: "umds-stat-card__corpo", children: [_jsx("span", { className: "umds-stat-card__valor", children: props.value }), _jsx("span", { className: "umds-stat-card__rotulo", children: props.label }), props.description ? (_jsx("span", { className: "umds-stat-card__descricao", children: props.description })) : null, props.trendLabel ? (_jsxs("span", { className: classesDaVariacao(), children: [_jsx("span", { "aria-hidden": "true", children: simboloDaVariacao() }), props.trendLabel] })) : null] })] }));
51
+ return (_jsxs("div", { className: classes(), onClick: (event) => aoClicar(), role: ehAcionavel() ? "button" : undefined, tabIndex: ehAcionavel() ? 0 : undefined, children: [props.icon ? (_jsx("span", { className: "umds-stat-card__icone", "aria-hidden": "true", children: _jsx(Icon, { size: "md", variant: "inherit", icon: props.icon }) })) : null, _jsxs("div", { className: "umds-stat-card__corpo", children: [_jsx("span", { className: "umds-stat-card__valor", children: props.value }), _jsxs("span", { className: "umds-stat-card__rotulo", children: [props.label, props.infoTooltip ? (_jsx(Tooltip, { variant: "dark", side: "top", content: props.infoTooltip, children: _jsx("button", { type: "button", className: "umds-stat-card__info", "aria-label": props.infoLabel || "Mais informações", children: _jsx(Icon, { variant: "inherit", customSize: "14px", icon: faCircleInfo }) }) })) : null] }), props.description ? (_jsx("span", { className: "umds-stat-card__descricao", children: props.description })) : null, props.trendLabel ? (_jsxs("span", { className: classesDaVariacao(), children: [_jsx("span", { "aria-hidden": "true", children: simboloDaVariacao() }), props.trendLabel] })) : null] })] }));
49
52
  }
50
53
  export default StatCard;
@@ -16,6 +16,21 @@ export interface TabProps {
16
16
  icon?: IconProp;
17
17
  /** Se a tab está desabilitada */
18
18
  disabled?: boolean;
19
+ /**
20
+ * Contador em pílula ao lado do texto: azul na aba ativa, cinza nas outras.
21
+ * Aceita número ou texto; o `0` aparece. Sem a prop, não há pílula.
22
+ */
23
+ count?: number | string;
24
+ /**
25
+ * Mostra o × para fechar a aba (abas de navegador, documentos abertos). O
26
+ * × é um botão próprio, irmão da aba (não dentro dela), e a tecla Delete
27
+ * na aba focada faz o mesmo. Quem remove a aba é o app, em `onClose`.
28
+ */
29
+ closable?: boolean;
30
+ /** Chamado ao fechar a aba, com o `index` dela e o evento. */
31
+ onClose?: (index: string, event?: any) => void;
32
+ /** Prefixo do nome acessível do ×; o texto da aba vem depois ("Fechar Documento 1"). Troque para traduzir. @default 'Fechar' */
33
+ closeLabel?: string;
19
34
  /** Classes CSS adicionais */
20
35
  className?: string;
21
36
  }
@@ -1,6 +1,7 @@
1
1
  "use client";
2
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  import { useContext } from "react";
4
+ import { faXmark } from "@fortawesome/free-solid-svg-icons";
4
5
  import TabsContext from "./tabs.context";
5
6
  import Icon from "../Icon/Icon";
6
7
  function Tab(props) {
@@ -17,11 +18,26 @@ function Tab(props) {
17
18
  ? tabsContext.tabsId + "-panel-" + props.index
18
19
  : undefined;
19
20
  }
21
+ function temContador() {
22
+ return (props.count !== undefined && props.count !== null && props.count !== "");
23
+ }
24
+ function itemClasses() {
25
+ return [
26
+ "umds-tabs__item",
27
+ props.closable ? "umds-tabs__item--closable" : "",
28
+ ]
29
+ .filter(Boolean)
30
+ .join(" ");
31
+ }
32
+ function closeAriaText() {
33
+ return (props.closeLabel || "Fechar") + " " + props.label;
34
+ }
20
35
  function classes() {
21
36
  return [
22
37
  "umds-tabs__tab",
23
38
  isSelected() ? "umds-tabs__tab--selected" : "",
24
39
  props.disabled ? "umds-tabs__tab--disabled" : "",
40
+ props.closable ? "umds-tabs__tab--closable" : "",
25
41
  props.className,
26
42
  ]
27
43
  .filter(Boolean)
@@ -42,9 +58,22 @@ function Tab(props) {
42
58
  tabsContext.onChange(props.index);
43
59
  }
44
60
  }
61
+ function handleClose(event) {
62
+ event.stopPropagation();
63
+ if (props.disabled)
64
+ return;
65
+ if (typeof props.onClose === "function") {
66
+ props.onClose(props.index, event);
67
+ }
68
+ }
45
69
  function handleKeyDown(event) {
46
70
  if (props.disabled)
47
71
  return;
72
+ if (props.closable && event.key === "Delete") {
73
+ event.preventDefault();
74
+ handleClose(event);
75
+ return;
76
+ }
48
77
  if (event.key === "Enter" || event.key === " ") {
49
78
  event.preventDefault();
50
79
  handleClick();
@@ -81,6 +110,6 @@ function Tab(props) {
81
110
  }
82
111
  }
83
112
  const tabsContext = useContext(TabsContext);
84
- return (_jsxs("button", { role: "tab", id: tabId(), "aria-controls": panelId(), "data-tab-index": props.index, "aria-selected": isSelected(), "aria-disabled": props.disabled, tabIndex: isSelected() ? 0 : -1, disabled: props.disabled, onClick: (event) => handleClick(), onKeyDown: (event) => handleKeyDown(event), className: classes(), children: [props.icon ? (_jsx(Icon, { size: "md", variant: "inherit", icon: props.icon })) : null, _jsx("span", { className: labelClasses(), children: props.label })] }));
113
+ return (_jsxs("span", { role: "presentation", className: itemClasses(), children: [_jsxs("button", { role: "tab", id: tabId(), "aria-controls": panelId(), "data-tab-index": props.index, "aria-selected": isSelected(), "aria-disabled": props.disabled, tabIndex: isSelected() ? 0 : -1, disabled: props.disabled, onClick: (event) => handleClick(), onKeyDown: (event) => handleKeyDown(event), className: classes(), children: [props.icon ? (_jsx(Icon, { size: "md", variant: "inherit", icon: props.icon })) : null, _jsx("span", { className: labelClasses(), children: props.label }), temContador() ? (_jsx("span", { className: "umds-tabs__count", children: props.count })) : null] }), props.closable ? (_jsx("button", { type: "button", className: "umds-tabs__close", "aria-label": closeAriaText(), disabled: props.disabled, tabIndex: -1, onClick: (event) => handleClose(event), children: _jsx(Icon, { variant: "inherit", customSize: "10px", icon: faXmark }) })) : null] }));
85
114
  }
86
115
  export default Tab;