@1doc/1ds-react 2.10.0 → 2.11.1

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 (92) hide show
  1. package/CHANGELOG.md +235 -0
  2. package/dist/components/Accordion/Accordion.d.ts +6 -0
  3. package/dist/components/Accordion/Accordion.js +17 -5
  4. package/dist/components/Badge/Badge.css +13 -4
  5. package/dist/components/Badge/Badge.d.ts +9 -2
  6. package/dist/components/Badge/Badge.js +3 -0
  7. package/dist/components/Button/Button.css +5 -0
  8. package/dist/components/Button/Button.d.ts +3 -0
  9. package/dist/components/Button/Button.js +1 -0
  10. package/dist/components/Calendar/Calendar.css +10 -0
  11. package/dist/components/Calendar/Calendar.d.ts +3 -0
  12. package/dist/components/Calendar/Calendar.js +6 -1
  13. package/dist/components/Coachmark/Coachmark.d.ts +2 -1
  14. package/dist/components/Coachmark/Coachmark.js +6 -1
  15. package/dist/components/CodeBlock/CodeBlock.css +3 -3
  16. package/dist/components/CodeBlock/CodeBlock.d.ts +2 -2
  17. package/dist/components/DataTable/DataTable.css +42 -0
  18. package/dist/components/DataTable/DataTable.d.ts +9 -2
  19. package/dist/components/DataTable/DataTable.js +15 -0
  20. package/dist/components/Input/Input.css +9 -0
  21. package/dist/components/Input/Input.d.ts +3 -0
  22. package/dist/components/Input/Input.js +1 -0
  23. package/dist/components/Kbd/Kbd.css +3 -3
  24. package/dist/components/Kbd/Kbd.d.ts +1 -1
  25. package/dist/components/Modal/Modal.css +19 -0
  26. package/dist/components/Modal/Modal.d.ts +7 -0
  27. package/dist/components/Modal/Modal.js +1 -0
  28. package/dist/components/RichTextEditor/RichTextEditor.d.ts +2 -2
  29. package/dist/components/RichTextEditor/RichTextEditor.js +0 -5
  30. package/dist/components/SegmentedControl/SegmentedControl.css +46 -0
  31. package/dist/components/SegmentedControl/SegmentedControl.d.ts +3 -0
  32. package/dist/components/SegmentedControl/SegmentedControl.js +1 -0
  33. package/dist/components/Select/Select.css +28 -2
  34. package/dist/components/Select/Select.d.ts +7 -0
  35. package/dist/components/Select/Select.js +55 -9
  36. package/dist/components/StatCard/StatCard.css +8 -0
  37. package/dist/components/StatCard/StatCard.d.ts +3 -0
  38. package/dist/components/StatCard/StatCard.js +1 -0
  39. package/dist/components/Tabs/Tabs.css +11 -0
  40. package/dist/components/Tabs/Tabs.d.ts +7 -0
  41. package/dist/components/Tabs/Tabs.js +7 -1
  42. package/dist/components/Tag/Tag.css +3 -1
  43. package/dist/teste/AccordionControlado.test.d.ts +1 -0
  44. package/dist/teste/AccordionControlado.test.js +73 -0
  45. package/dist/teste/BadgeAttachedTomEPadding.test.d.ts +1 -0
  46. package/dist/teste/BadgeAttachedTomEPadding.test.js +43 -0
  47. package/dist/teste/ButtonDensidade.test.d.ts +1 -0
  48. package/dist/teste/ButtonDensidade.test.js +28 -0
  49. package/dist/teste/CalendarCompacto.test.d.ts +1 -0
  50. package/dist/teste/CalendarCompacto.test.js +29 -0
  51. package/dist/teste/CoachmarkUmPasso.test.d.ts +1 -0
  52. package/dist/teste/CoachmarkUmPasso.test.js +34 -0
  53. package/dist/teste/DataTableCompactaETom.test.d.ts +1 -0
  54. package/dist/teste/DataTableCompactaETom.test.js +69 -0
  55. package/dist/teste/InputGhost.test.d.ts +1 -0
  56. package/dist/teste/InputGhost.test.js +32 -0
  57. package/dist/teste/ModalProporcoes1Doc.test.d.ts +1 -0
  58. package/dist/teste/ModalProporcoes1Doc.test.js +32 -0
  59. package/dist/teste/RichTextEditorEstiloDeTexto.test.js +7 -7
  60. package/dist/teste/SegmentedControlSuperficie.test.d.ts +1 -0
  61. package/dist/teste/SegmentedControlSuperficie.test.js +39 -0
  62. package/dist/teste/SelectItemComEscopo.test.d.ts +1 -0
  63. package/dist/teste/SelectItemComEscopo.test.js +54 -0
  64. package/dist/teste/SelectListaFiltro.test.d.ts +1 -0
  65. package/dist/teste/SelectListaFiltro.test.js +102 -0
  66. package/dist/teste/StatCardTamanhoSm.test.d.ts +1 -0
  67. package/dist/teste/StatCardTamanhoSm.test.js +32 -0
  68. package/dist/teste/TabsCompacta.test.d.ts +1 -0
  69. package/dist/teste/TabsCompacta.test.js +35 -0
  70. package/dist/teste/TagPositivoTingido.test.d.ts +1 -0
  71. package/dist/teste/TagPositivoTingido.test.js +54 -0
  72. package/dist/teste/lerArquivo.d.ts +1 -0
  73. package/dist/teste/lerArquivo.js +12 -0
  74. package/dist/utils/html-seguro.js +1 -1
  75. package/package.json +3 -3
  76. package/src/teste/AccordionControlado.test.tsx +87 -0
  77. package/src/teste/BadgeAttachedTomEPadding.test.tsx +60 -0
  78. package/src/teste/ButtonDensidade.test.tsx +40 -0
  79. package/src/teste/CalendarCompacto.test.tsx +37 -0
  80. package/src/teste/CoachmarkUmPasso.test.tsx +45 -0
  81. package/src/teste/DataTableCompactaETom.test.tsx +85 -0
  82. package/src/teste/InputGhost.test.tsx +42 -0
  83. package/src/teste/ModalProporcoes1Doc.test.tsx +36 -0
  84. package/src/teste/RichTextEditorEstiloDeTexto.test.tsx +8 -8
  85. package/src/teste/SegmentedControlSuperficie.test.tsx +52 -0
  86. package/src/teste/SelectItemComEscopo.test.tsx +69 -0
  87. package/src/teste/SelectListaFiltro.test.tsx +120 -0
  88. package/src/teste/StatCardTamanhoSm.test.tsx +42 -0
  89. package/src/teste/TabsCompacta.test.tsx +45 -0
  90. package/src/teste/TagPositivoTingido.test.tsx +60 -0
  91. package/src/teste/lerArquivo.ts +13 -0
  92. package/src/utils/html-seguro.ts +1 -1
@@ -511,9 +511,24 @@ function DataTable(props) {
511
511
  .filter(Boolean)
512
512
  .join(" ");
513
513
  }
514
+ function toneOf(row, index) {
515
+ if (!props.rowTone)
516
+ return "";
517
+ const bruto = typeof props.rowTone === "function"
518
+ ? props.rowTone(row, index)
519
+ : row[props.rowTone];
520
+ const tom = bruto === undefined || bruto === null ? "" : String(bruto);
521
+ return tom === "negative" ||
522
+ tom === "positive" ||
523
+ tom === "info" ||
524
+ tom === "muted"
525
+ ? tom
526
+ : "";
527
+ }
514
528
  function rowClasses(row, rowIdx) {
515
529
  return [
516
530
  "umds-datatable__row",
531
+ toneOf(row, rowIdx) ? "umds-datatable__row--" + toneOf(row, rowIdx) : "",
517
532
  isSelected(row, rowIdx) || isHighlighted(row, rowIdx)
518
533
  ? "umds-datatable__row--selected"
519
534
  : "",
@@ -257,6 +257,15 @@
257
257
  outline-offset: 0; /* exceção ao offset 2px: o botão vive DENTRO do campo, e o afastamento invadiria a borda */
258
258
  }
259
259
 
260
+ /* ── variant="ghost": a busca dentro de um painel, sem a borda escura ──
261
+ Só o repouso muda (fundo claro e borda clara). Hover, foco, erro, desabilitado e somente leitura vêm das
262
+ regras do campo padrão, que têm mais especificidade (o :where zera a das cadeias de :not aqui), então o
263
+ hover escurece a borda e o foco segue com borda azul e anel. A moldura clara não é o único sinal do campo: o ícone, o placeholder e o cursor o dizem. */
264
+ .umds-input--ghost:where(:not(.umds-input--error):not(.umds-input--disabled):not(.umds-input--readonly)) .umds-input__container {
265
+ background-color: var(--umds-semantic-color-background-light);
266
+ border-color: var(--umds-semantic-color-neutral-light-medium);
267
+ }
268
+
260
269
  /* ── borderless: o campo dentro de um grupo que já tem a moldura ──
261
270
  Sem borda, fundo e raio. O foco NÃO some: o anel do campo vira um contorno
262
271
  para dentro (WCAG 2.4.7), e o erro mantém a borda vermelha (a cor do erro não
@@ -36,6 +36,7 @@ export interface InputAction {
36
36
  * @property {InputAction[]} iconsRight - Botões de ação com ícone à direita
37
37
  * @property {IconProp} iconRight - Ícone decorativo à direita (não é botão, some para o leitor de tela). Para ação clicável, use `iconsRight`.
38
38
  * @property {boolean} grouped - O campo vive dentro de um contêiner que já desenha a moldura E o foco (o campo de chips: as tags e o input na mesma caixa). Implica `borderless`, e tira a altura de campo, o padding e o anel de foco próprio: o contêiner mostra o foco com `:focus-within`. Sem esse foco no contêiner, quem usa teclado perde o indicador (WCAG 2.4.7).
39
+ * @property {string} variant - 'default' | 'ghost'. O `ghost` é o campo de busca dentro de um painel: fundo cinza claro e borda clara (a escura do padrão some em repouso). O hover escurece a borda, e o foco, o erro, o desabilitado e o somente leitura são os do campo padrão (o anel de foco continua inteiro). Sem a prop, nada muda.
39
40
  * @property {boolean} borderless - Sem borda, fundo e raio: o campo dentro de um grupo que já tem a moldura (um Select e um Input lado a lado numa mesma caixa). O foco continua visível, em contorno, e o erro mantém a borda vermelha.
40
41
  * @property {string} mask - Máscara simples: 'cpf' | 'cnpj' | 'cep' | 'phone'. O valor exibido e o que chega em `onChange` já vêm formatados (para só os dígitos, `valor.replace(/\D/g, "")`). Aceita só dígitos, limita o tamanho e abre o teclado numérico no celular.
41
42
  * @property {function} onChange - Callback acionado A CADA TECLA (recebe o novo valor string), nos dois frameworks. O blur sai em `onBlur`.
@@ -93,6 +94,8 @@ export interface InputProps {
93
94
  iconsRight?: InputAction[];
94
95
  /** Ícone decorativo à direita (não clicável, `aria-hidden`). Para ação, use `iconsRight`. */
95
96
  iconRight?: IconProp;
97
+ /** `ghost`: o campo de busca dentro de um painel, sem a borda escura em repouso. @default 'default' */
98
+ variant?: "default" | "ghost";
96
99
  /** Sem borda, fundo e raio, para o campo dentro de um grupo que já tem a moldura. O foco e o erro continuam visíveis. @default false */
97
100
  borderless?: boolean;
98
101
  /**
@@ -52,6 +52,7 @@ function Input(props) {
52
52
  props.numberSpinner ? "umds-input--number-spinner" : "",
53
53
  props.borderless || props.grouped ? "umds-input--borderless" : "",
54
54
  props.grouped ? "umds-input--grouped" : "",
55
+ props.variant === "ghost" ? "umds-input--ghost" : "",
55
56
  `umds-input--${props.size || "md"}`,
56
57
  props.className,
57
58
  ]
@@ -1,6 +1,6 @@
1
1
  /* ─────────────────────────────────────────────
2
2
  KBD
3
- Uma tecla, ou uma combinação, em fonte monoespaçada.
3
+ Uma tecla, ou uma combinação, na fonte do DS (a base).
4
4
 
5
5
  A caixa é cinza com borda e uma sombra de base de 1px (a "espessura" da
6
6
  tecla). Texto escuro sobre cinza claro: contraste de texto, não só de cor.
@@ -13,7 +13,7 @@
13
13
  box-sizing: border-box;
14
14
  min-width: var(--umds-primitive-spacing-xxs); /* 24px */
15
15
  padding: var(--umds-primitive-spacing-micro) var(--umds-primitive-spacing-nano); /* 2px 8px */
16
- font-family: var(--umds-semantic-font-family-mono);
16
+ font-family: var(--umds-semantic-font-family-base);
17
17
  font-weight: var(--umds-primitive-font-weight-semibold);
18
18
  line-height: var(--umds-primitive-font-line-height-lg);
19
19
  text-align: center;
@@ -40,7 +40,7 @@
40
40
  display: inline-flex;
41
41
  align-items: center;
42
42
  gap: var(--umds-primitive-spacing-quarck); /* 4px */
43
- font-family: var(--umds-semantic-font-family-mono);
43
+ font-family: var(--umds-semantic-font-family-base);
44
44
  }
45
45
 
46
46
  .umds-kbd-combo__item {
@@ -4,7 +4,7 @@ import './Kbd.css';
4
4
  *
5
5
  * Uma tecla: `<Kbd>Esc</Kbd>`. Uma combinação: `keys` (`["Ctrl", "Shift", "P"]`),
6
6
  * que desenha uma caixa por tecla com o `separator` entre elas (`+` por padrão).
7
- * A fonte é a monoespaçada do DS (`--umds-semantic-font-family-mono`), a caixa é
7
+ * A fonte é a do DS (`--umds-semantic-font-family-base`), a caixa é
8
8
  * cinza com borda e uma sombra de base, como uma tecla de verdade.
9
9
  *
10
10
  * Semântica: `<kbd>` é o elemento HTML de "entrada de teclado", e um `<kbd>`
@@ -407,6 +407,25 @@
407
407
  background: var(--umds-semantic-color-primary-medium);
408
408
  }
409
409
 
410
+ /* ── density="1doc": as proporções do modal do CrisDoc ──
411
+ Cabeçalho de 67px (o padrão dá 61), rodapé de 65px (o padrão dá 73) e raio de 12px (o DS usa 8). Sem token
412
+ para essas medidas: literais comentados, como o resto do modal base. As alturas são mínimas, então título
413
+ com subtítulo ou botão mais alto continua crescendo. Fora a tela cheia e o painel, que têm cantos próprios. */
414
+ .umds-modal--1doc:not(.umds-modal--fullscreen):not(.umds-modal--janela-fullscreen):not(.umds-modal--sheet) {
415
+ /* stylelint-disable-next-line 1ds/raio-canonico -- o 12px é a opção density="1doc" (o modal do CrisDoc); o padrão segue em 8px */
416
+ border-radius: 12px;
417
+ }
418
+
419
+ .umds-modal--1doc.umds-modal--base .umds-modal__header {
420
+ align-items: center;
421
+ min-height: 67px;
422
+ }
423
+
424
+ .umds-modal--1doc.umds-modal--base .umds-modal__footer {
425
+ min-height: 65px;
426
+ padding: var(--umds-primitive-spacing-mini) var(--umds-primitive-spacing-xxs); /* 12px 24px */
427
+ }
428
+
410
429
  /* ── responsive: abaixo do breakpoint vira painel que sobe pela borda de baixo ──
411
430
  Mesma anatomia do BottomSheet (largura total, cantos de cima arredondados,
412
431
  alça, entrada por baixo). Quem decide o breakpoint é o componente (media
@@ -95,6 +95,13 @@ export interface ModalProps {
95
95
  * @default 'dialog'
96
96
  */
97
97
  layout?: "dialog" | "content";
98
+ /**
99
+ * Proporções do modal. `1doc` leva o cabeçalho a 67px, o rodapé a 65px e o raio a 12px, as medidas do
100
+ * modal do CrisDoc; o padrão (`default`) segue com 61px, 73px e 8px. Só o modal base (com título), e
101
+ * combina com `variant="primary"`. Tela cheia e painel (`responsive`) mantêm os cantos deles.
102
+ * @default 'default'
103
+ */
104
+ density?: "default" | "1doc";
98
105
  /** Classes CSS adicionais para o container do modal */
99
106
  className?: string;
100
107
  /** Se verdadeiro, renderiza o modal inline (sem fixed/overlay), útil para documentação */
@@ -149,6 +149,7 @@ function Modal(props) {
149
149
  `umds-modal--${props.variant || "default"}`,
150
150
  props.size && props.size !== "md" ? `umds-modal--${props.size}` : "",
151
151
  ehFeedback() ? "umds-modal--feedback" : "umds-modal--base",
152
+ props.density === "1doc" ? "umds-modal--1doc" : "",
152
153
  classeDaJanela(),
153
154
  props.responsive && isCompact ? "umds-modal--sheet" : "",
154
155
  props.className,
@@ -35,7 +35,7 @@ export type RichTextTool = "bold" | "italic" | "underline" | "strike" | "ul" | "
35
35
  * higienização: só PNG, JPEG, GIF e WebP em `data:`, ou `http(s)`; sem SVG.
36
36
  *
37
37
  * Estilo de texto por TOKEN do DS, também opcional na `toolbar`: `fontFamily`
38
- * (padrão ou monoespaçada), `fontSize` (12, 14, 16, 20 e 24px, da escala do DS) e
38
+ * (a fonte do DS), `fontSize` (12, 14, 16, 20 e 24px, da escala do DS) e
39
39
  * `textColor` (a paleta do DS). Cada um abre um painel abaixo da barra e aplica ao
40
40
  * texto selecionado (sem seleção, o painel pede que se selecione). O valor guarda
41
41
  * `<span style="color: var(--umds-primitive-red-pure)">`: só token do DS passa na
@@ -53,7 +53,7 @@ export type RichTextTool = "bold" | "italic" | "underline" | "strike" | "ul" | "
53
53
  * @property {string} placeholder - Texto de apoio com o editor vazio
54
54
  * @property {string[]} toolbar - Ferramentas da barra, em ordem: 'bold' | 'italic' | 'underline' | 'strike' | 'ul' | 'ol' | 'link' | 'undo' | 'redo' | 'clear' | 'alignLeft' | 'alignCenter' | 'alignRight' | 'alignJustify' | 'image' | 'table' | 'fontFamily' | 'fontSize' | 'textColor' | '|' (separador)
55
55
  * @property {string} toolbarLabel - Nome da barra (padrão "Formatação")
56
- * @property {object} labels - Nomes das ferramentas e dos campos, parcial: `{ bold, italic, underline, strike, ul, ol, link, undo, redo, clear, alignLeft, alignCenter, alignRight, alignJustify, image, table, linkAddress, linkApply, linkRemove, linkCancel, linkInvalid, imageUrl, imageAlt, imageFile, imageApply, imageCancel, imageInvalid, imageType, imageTooLarge, tableRows, tableCols, tableApply, tableCancel, tableInvalid, tableActions, tableAddRow, tableRemoveRow, tableAddCol, tableRemoveCol, tableRemove, fontFamily, fontSize, textColor, fontFamilyBase, fontFamilyMono, styleClose, styleNeedsSelection }`
56
+ * @property {object} labels - Nomes das ferramentas e dos campos, parcial: `{ bold, italic, underline, strike, ul, ol, link, undo, redo, clear, alignLeft, alignCenter, alignRight, alignJustify, image, table, linkAddress, linkApply, linkRemove, linkCancel, linkInvalid, imageUrl, imageAlt, imageFile, imageApply, imageCancel, imageInvalid, imageType, imageTooLarge, tableRows, tableCols, tableApply, tableCancel, tableInvalid, tableActions, tableAddRow, tableRemoveRow, tableAddCol, tableRemoveCol, tableRemove, fontFamily, fontSize, textColor, fontFamilyBase, styleClose, styleNeedsSelection }`
57
57
  * @property {number} minHeight - Altura mínima da área de escrita, em px (padrão 120)
58
58
  * @property {boolean} resizable - Deixa redimensionar a altura pelo canto
59
59
  * @property {boolean} disabled - Desabilita barra e área
@@ -148,7 +148,6 @@ function RichTextEditor(props) {
148
148
  fontSize: "Tamanho da fonte",
149
149
  textColor: "Cor do texto",
150
150
  fontFamilyBase: "Padrão",
151
- fontFamilyMono: "Monoespaçada",
152
151
  styleClose: "Fechar",
153
152
  styleNeedsSelection: "Selecione o texto antes de aplicar.",
154
153
  };
@@ -790,10 +789,6 @@ function RichTextEditor(props) {
790
789
  label: rotulo("fontFamilyBase"),
791
790
  value: "var(--umds-semantic-font-family-base)",
792
791
  },
793
- {
794
- label: rotulo("fontFamilyMono"),
795
- value: "var(--umds-semantic-font-family-mono)",
796
- },
797
792
  ];
798
793
  }
799
794
  function fontSizeOptions() {
@@ -208,3 +208,49 @@
208
208
  background-color: var(--umds-semantic-color-neutral-light-pure);
209
209
  color: var(--umds-semantic-color-primary-pure);
210
210
  }
211
+
212
+ /* ── variant="surface": o escolhido em superfície branca (o seletor do CrisDoc) ──
213
+ Trilho cinza claro sem divisores; o segmento escolhido é uma peça branca com sombra e texto escuro em
214
+ negrito (a seleção não depende só do tom: o peso e a sombra a dizem). O trilho deixa de recortar, para a
215
+ sombra aparecer. O contador do escolhido fica cinza sobre o branco e o dos outros, branco sobre o trilho. */
216
+ .umds-segmented--surface .umds-segmented__track {
217
+ background-color: var(--umds-semantic-color-neutral-light-medium);
218
+ border-color: var(--umds-semantic-color-neutral-light-medium);
219
+ overflow: visible;
220
+ }
221
+
222
+ .umds-segmented--surface .umds-segmented__item {
223
+ background-color: transparent;
224
+ border-right-color: transparent;
225
+ border-radius: var(--umds-primitive-border-radius-sm);
226
+ }
227
+
228
+ .umds-segmented--surface .umds-segmented__item:hover {
229
+ background-color: var(--umds-semantic-color-neutral-light-down);
230
+ }
231
+
232
+ .umds-segmented--surface .umds-segmented__input:checked + .umds-segmented__item,
233
+ .umds-segmented--surface .umds-segmented__input:checked + .umds-segmented__item:hover {
234
+ background-color: var(--umds-semantic-color-background-white);
235
+ color: var(--umds-semantic-color-neutral-dark-pure);
236
+ font-weight: var(--umds-primitive-font-weight-bold);
237
+ box-shadow: var(--umds-semantic-shadow-md);
238
+ }
239
+
240
+ .umds-segmented--surface .umds-segmented__input:disabled + .umds-segmented__item:hover {
241
+ background-color: transparent;
242
+ }
243
+
244
+ .umds-segmented--surface .umds-segmented__input:disabled:checked + .umds-segmented__item:hover {
245
+ background-color: var(--umds-semantic-color-background-white);
246
+ color: var(--umds-semantic-color-neutral-dark-pure);
247
+ }
248
+
249
+ .umds-segmented--surface .umds-segmented__count {
250
+ background-color: var(--umds-semantic-color-background-white);
251
+ }
252
+
253
+ .umds-segmented--surface .umds-segmented__input:checked + .umds-segmented__item .umds-segmented__count {
254
+ background-color: var(--umds-semantic-color-neutral-light-medium);
255
+ color: var(--umds-semantic-color-neutral-dark-pure);
256
+ }
@@ -40,6 +40,7 @@ export interface SegmentedControlOption {
40
40
  * @property {boolean} invalid - Estado de erro.
41
41
  * @property {string} errorMessage - Mensagem de erro do grupo.
42
42
  * @property {string} size - Tamanho: 'sm' (32px) | 'md' (40px).
43
+ * @property {string} variant - 'default' (padrão): o segmento escolhido é azul cheio com texto branco. 'surface': trilho cinza claro e o segmento escolhido em superfície branca, com sombra e texto em negrito (o seletor do CrisDoc). O contador do escolhido fica cinza sobre o branco e o dos outros, branco sobre o trilho.
43
44
  * @property {boolean} fullWidth - Os segmentos dividem a largura do container.
44
45
  * @property {string} className - Classes CSS adicionais.
45
46
  * @property {function} onChange - Callback com o valor escolhido.
@@ -58,6 +59,8 @@ export interface SegmentedControlProps {
58
59
  invalid?: boolean;
59
60
  errorMessage?: string;
60
61
  size?: "sm" | "md";
62
+ /** `surface`: o escolhido em superfície branca sobre trilho cinza, no lugar do azul cheio. @default 'default' */
63
+ variant?: "default" | "surface";
61
64
  fullWidth?: boolean;
62
65
  className?: string;
63
66
  onChange?: (value: string) => void;
@@ -49,6 +49,7 @@ function SegmentedControl(props) {
49
49
  return [
50
50
  "umds-segmented",
51
51
  `umds-segmented--${props.size || "md"}`,
52
+ props.variant === "surface" ? "umds-segmented--surface" : "",
52
53
  props.fullWidth ? "umds-segmented--full-width" : "",
53
54
  props.disabled ? "umds-segmented--disabled" : "",
54
55
  isInvalid() ? "umds-segmented--invalid" : "",
@@ -175,8 +175,10 @@
175
175
 
176
176
  /* ── Variante filter: botão de filtro de barra de ferramentas ──
177
177
  Contornado em azul, largura do conteúdo, lista mais larga que o botão. */
178
+ /* fit-content e não auto: o wrapper é flex (bloco), e `auto` o estica até a largura do pai. Com ele esticado,
179
+ o `100%` da lista passava a ser o do pai (556px numa barra) e não o do gatilho. */
178
180
  .umds-select--filter {
179
- width: auto;
181
+ width: fit-content;
180
182
  }
181
183
 
182
184
  .umds-select--filter.umds-select--full-width {
@@ -224,12 +226,25 @@
224
226
  }
225
227
 
226
228
  .umds-select--filter .umds-select__dropdown {
227
- /* 240px: três vezes o degrau xxl (80px). Sem token de largura de menu. */
229
+ /* 240px: três vezes o degrau xxl (80px). Sem token de largura de menu. `listMinWidth` troca este mínimo
230
+ (estilo inline). A lista nunca é mais estreita que o gatilho (100%). */
228
231
  width: max-content;
229
232
  min-width: max(100%, calc(var(--umds-primitive-spacing-xxl) * 3));
230
233
  max-width: calc(100vw - var(--umds-primitive-spacing-xxxs) * 2);
231
234
  }
232
235
 
236
+ /* Perto da borda direita da janela: a lista se alinha ao fim do gatilho (`alignEnd`, medido ao abrir). */
237
+ .umds-select--filter.umds-select--list-end .umds-select__dropdown {
238
+ left: auto;
239
+ right: 0;
240
+ }
241
+
242
+ /* A busca da lista de filtro acompanha a largura da lista e não a dita: `contain: inline-size` tira a
243
+ largura natural do campo da conta do `max-content`. */
244
+ .umds-select--filter .umds-select__search-container {
245
+ contain: inline-size;
246
+ }
247
+
233
248
  /* ── Variante search: o filtro dentro de uma barra de busca ──
234
249
  Altura de campo e contorno neutro, para ficar ao lado do campo de busca. */
235
250
  .umds-select--filter-search .umds-select__trigger {
@@ -333,6 +348,7 @@
333
348
 
334
349
  .umds-select__search-input {
335
350
  flex: 1;
351
+ min-width: 0;
336
352
  border: none;
337
353
  outline: none;
338
354
  font-size: var(--umds-primitive-font-size-xxs);
@@ -557,3 +573,13 @@
557
573
  border-bottom-color: var(--umds-semantic-color-primary-pure);
558
574
  box-shadow: inset 0 -1px 0 var(--umds-semantic-color-primary-pure);
559
575
  }
576
+
577
+ /* ── item no gatilho: o conteúdo do slot/função `item` da opção escolhida ── */
578
+ .umds-select__trigger-item {
579
+ display: inline-flex;
580
+ align-items: center;
581
+ min-width: 0;
582
+ overflow: hidden;
583
+ font-size: var(--umds-semantic-field-text-size);
584
+ color: var(--umds-semantic-field-text-color);
585
+ }
@@ -53,6 +53,8 @@ export interface SelectOption {
53
53
  * @property {string} triggerSwatch - Amostra de cor à esquerda do texto do gatilho: um token (`var(--umds-semantic-color-...)`) ou `var(--umds-primitive-...)`. Decorativa; o texto diz a opção.
54
54
  * @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).
55
55
  * @property {any} footer - Rodapé fixo da lista, com ações ("Gerenciar marcadores"). Passe o elemento correspondente (React node ou Vue slot `footer`).
56
+ * @property {any} item - Conteúdo de cada opção na lista, e do gatilho com a opção escolhida (seleção única). No React, uma função `({ optionData }) => nó` (`optionData` é a opção: `label`, `value` e os campos seus). No Vue, o slot com escopo `#item="{ optionData }"` (o mesmo `optionData`; `option` é um apelido). Sem ela, a opção é o `label` em texto. Na lista de seleção múltipla e na do `emptyOptionLabel` o gatilho segue mostrando o texto.
57
+ * @property {string|number} listMinWidth - Largura mínima da lista das variantes de filtro: um número (px) ou uma medida CSS ("220px"). Padrão: 240px. A lista tem a largura do gatilho (nunca menor), cresce até o conteúdo e nunca passa da borda da janela: perto da borda direita ela se alinha ao fim do gatilho. A busca interna acompanha a largura da lista, sem alargá-la.
56
58
  * @quandoUsar Escolher UM valor de uma lista fechada. O valor selecionado fica visível no campo.
57
59
  * @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`.
58
60
  */
@@ -110,6 +112,11 @@ export interface SelectProps {
110
112
  emptyOptionLabel?: string;
111
113
  /** Rodapé fixo da lista (ações). React node ou slot `footer` no Vue. */
112
114
  footer?: any;
115
+ /**
116
+ * Largura mínima da lista das variantes de filtro: número (px) ou medida CSS ("220px"). A lista nunca
117
+ * fica mais estreita que o gatilho. @default 240 (o `filter` do DS)
118
+ */
119
+ listMinWidth?: string | number;
113
120
  pagination?: boolean;
114
121
  hasMore?: boolean;
115
122
  onLoadMore?: () => void;
@@ -3,7 +3,7 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
3
3
  import './Select.css';
4
4
  import { useState, useRef, useEffect } from "react";
5
5
  import { faChevronUp, faChevronDown, faMagnifyingGlass, faXmark, faCheck, faTrash, } from "@fortawesome/free-solid-svg-icons";
6
- import { computePosition, autoUpdate, offset, flip, size, } from "@floating-ui/dom";
6
+ import { computePosition, autoUpdate, offset, flip, shift, size, } from "@floating-ui/dom";
7
7
  import Text from "../Text/Text";
8
8
  import Icon from "../Icon/Icon";
9
9
  import Spinner from "../Spinner/Spinner";
@@ -38,6 +38,7 @@ function Select(props) {
38
38
  const [floatW, setFloatW] = useState(() => 0);
39
39
  const [floatMaxH, setFloatMaxH] = useState(() => 0);
40
40
  const [listMaxH, setListMaxH] = useState(() => 0);
41
+ const [alignEnd, setAlignEnd] = useState(() => false);
41
42
  const [searchTerm, setSearchTerm] = useState(() => "");
42
43
  const [internalSelected, setInternalSelected] = useState(() => Array.isArray(props.defaultValue)
43
44
  ? props.defaultValue
@@ -150,6 +151,20 @@ function Select(props) {
150
151
  }
151
152
  return String(currentVal[0]);
152
153
  }
154
+ function opcaoDoGatilho() {
155
+ if (props.multiple || isPlaceholder())
156
+ return undefined;
157
+ return selectedOptionsList()[0];
158
+ }
159
+ function itemNoGatilho() {
160
+ return typeof props.item === "function" && !!opcaoDoGatilho();
161
+ }
162
+ function conteudoDoItemNoGatilho() {
163
+ return props.item({
164
+ optionData: opcaoDoGatilho(),
165
+ option: opcaoDoGatilho(),
166
+ });
167
+ }
153
168
  function triggerSwatchColor() {
154
169
  if (props.triggerSwatch)
155
170
  return props.triggerSwatch;
@@ -216,6 +231,7 @@ function Select(props) {
216
231
  props.variant === "search" ? "umds-select--filter-search" : "",
217
232
  props.variant === "combo" ? "umds-select--filter-combo" : "",
218
233
  opened() && floatMode ? "umds-select--floating" : "",
234
+ opened() && alignEnd ? "umds-select--list-end" : "",
219
235
  props.triggerIcon ? "umds-select--has-trigger-icon" : "",
220
236
  opensUp && props.searchVariant !== "inline"
221
237
  ? "umds-select--placement-top"
@@ -307,6 +323,7 @@ function Select(props) {
307
323
  const flutuante = insideDialog();
308
324
  setFloatMode(flutuante);
309
325
  setFloatReady(false);
326
+ setAlignEnd(false);
310
327
  setOpensUp(shouldOpenUp(flutuante));
311
328
  // Abre com a opção já selecionada ativa (padrão combobox).
312
329
  setActiveIndex(filteredOptionsList().findIndex((opt) => isOptionSelected(opt.value)));
@@ -326,6 +343,10 @@ function Select(props) {
326
343
  flip({
327
344
  fallbackStrategy: "bestFit",
328
345
  }),
346
+ // Perto da borda da janela, a lista desliza para dentro (8px de respiro).
347
+ shift({
348
+ padding: 8,
349
+ }),
329
350
  size({
330
351
  apply({ availableHeight, rects }) {
331
352
  setFloatW(rects.reference.width);
@@ -339,6 +360,22 @@ function Select(props) {
339
360
  setFloatReady(true);
340
361
  });
341
362
  }
363
+ function listMinWidthCss() {
364
+ const pedida = props.listMinWidth;
365
+ if (!isFilter() || pedida === undefined || pedida === null || pedida === "")
366
+ return "";
367
+ return typeof pedida === "number" ? pedida + "px" : String(pedida);
368
+ }
369
+ function keepInWindow() {
370
+ if (typeof window === "undefined" || !dropdownRef.current)
371
+ return;
372
+ if (!opened() || !isFilter() || floatMode || alignEnd)
373
+ return;
374
+ const caixa = dropdownRef.current.getBoundingClientRect();
375
+ // 8px de respiro até a borda: o degrau nano do DS.
376
+ if (caixa.right > window.innerWidth - 8)
377
+ setAlignEnd(true);
378
+ }
342
379
  function dropdownStyle() {
343
380
  if (props.searchVariant === "inline")
344
381
  return {
@@ -355,7 +392,11 @@ function Select(props) {
355
392
  };
356
393
  if (isFilter()) {
357
394
  estilo.minWidth =
358
- "max(" + floatW + "px, calc(var(--umds-primitive-spacing-xxl) * 3))";
395
+ "max(" +
396
+ floatW +
397
+ "px, " +
398
+ (listMinWidthCss() || "calc(var(--umds-primitive-spacing-xxl) * 3)") +
399
+ ")";
359
400
  }
360
401
  else {
361
402
  estilo.width = floatW + "px";
@@ -364,11 +405,12 @@ function Select(props) {
364
405
  estilo.maxHeight = floatMaxH + "px";
365
406
  return estilo;
366
407
  }
367
- return listMaxH
368
- ? {
369
- maxHeight: listMaxH + "px",
370
- }
371
- : {};
408
+ const estilo = {};
409
+ if (listMaxH)
410
+ estilo.maxHeight = listMaxH + "px";
411
+ if (listMinWidthCss())
412
+ estilo.minWidth = "max(100%, " + listMinWidthCss() + ")";
413
+ return estilo;
372
414
  }
373
415
  function toggle() {
374
416
  if (props.disabled || props.readOnly)
@@ -575,6 +617,7 @@ function Select(props) {
575
617
  latestOpenChangeRef.current = props.onOpenChange;
576
618
  if (opened() && !prepared)
577
619
  prepareOpen();
620
+ keepInWindow();
578
621
  if (typeof document === "undefined")
579
622
  return;
580
623
  const handleClickOutside = (event) => {
@@ -600,6 +643,9 @@ function Select(props) {
600
643
  prepareOpen();
601
644
  if (!opened() && prepared)
602
645
  setPrepared(false);
646
+ if (!opened() && alignEnd)
647
+ setAlignEnd(false);
648
+ keepInWindow();
603
649
  // Lista flutuante: segue o gatilho (scroll, resize) enquanto aberta.
604
650
  if (opened() &&
605
651
  floatMode &&
@@ -649,7 +695,7 @@ function Select(props) {
649
695
  }, []);
650
696
  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: [!(opened() && 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": opened(), "aria-controls": listboxIdText(), "aria-activedescendant": activeDescendantText(), "aria-labelledby": comboboxLabelledBy(), "aria-label": comboboxAriaLabel(), "aria-invalid": ariaInvalidText(), "aria-required": ariaRequiredText(), "aria-describedby": describedByText(), "aria-disabled": props.disabled ? "true" : undefined, tabIndex: props.disabled ? -1 : 0, children: [_jsxs("div", { className: "umds-select__values", children: [props.triggerIcon ? (_jsx("span", { "aria-hidden": "true", className: "umds-select__trigger-icon", children: _jsx(Icon, { variant: "inherit", customSize: "12px", icon: props.triggerIcon }) })) : null, triggerSwatchColor() ? (_jsx("span", { "aria-hidden": "true", className: "umds-select__swatch", style: {
651
697
  background: triggerSwatchColor(),
652
- } })) : null, displayLabelText() ? (_jsx(Text, { as: "span", variant: "body2", className: isPlaceholder() ? "umds-select__placeholder" : "", children: displayLabelText() })) : null, props.multiple &&
698
+ } })) : null, itemNoGatilho() ? (_jsx("span", { className: "umds-select__trigger-item", children: conteudoDoItemNoGatilho() })) : null, displayLabelText() && !itemNoGatilho() ? (_jsx(Text, { as: "span", variant: "body2", className: isPlaceholder() ? "umds-select__placeholder" : "", children: displayLabelText() })) : null, props.multiple &&
653
699
  props.selectionDisplay === "tags" &&
654
700
  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: opened() ? faChevronUp : faChevronDown }) })] })] })) : null, opened() ? (_jsxs("div", { className: "umds-select__dropdown", ref: dropdownRef, style: dropdownStyle(), onKeyDown: (event) => handleDropdownKeyDown(event), children: [props.searchable ? (_jsxs("div", { className: "umds-select__search-container", children: [_jsx("div", { className: "umds-select__search-icon", children: _jsx(Icon, { size: "sm", icon: faMagnifyingGlass }) }), _jsx("input", { type: "text", className: "umds-select__search-input", ref: searchInputRef, placeholder: props.searchPlaceholder || "Buscar...", "aria-label": props.searchAriaLabel || "Buscar", value: searchTerm, onInput: (e) => handleSearch(e) }), props.searchVariant === "inline" ? (_jsx("button", { type: "button", className: "umds-select__search-close", "aria-label": props.closeSearchAriaLabel || "Fechar busca", onClick: (event) => closeSearch(), onKeyDown: (event) => handleSearchCloseKeyDown(event), children: _jsx(Icon, { size: "sm", icon: faXmark }) })) : null] })) : null, _jsxs("div", { role: "listbox", className: "umds-select__options", id: listboxIdText(), "aria-multiselectable": props.multiple ? "true" : undefined, onScroll: (e) => onScrollList(e), children: [filteredOptionsList().length === 0 && !props.loading ? (_jsx("div", { className: "umds-select__no-options", children: _jsx(Text, { variant: "body2", color: "secondary", children: props.emptyLabel || "Nenhum item encontrado" }) })) : null, filteredOptionsList()?.map((option, index) => (_jsxs("div", { role: "option", id: optionIdText(index), "aria-selected": isOptionSelected(option.value), onClick: (event) => selectOption(option), className: [
655
701
  "umds-select__option",
@@ -661,7 +707,7 @@ function Select(props) {
661
707
  .filter(Boolean)
662
708
  .join(" "), children: [props.multiple ? (_jsx("div", { className: "umds-select__option-checkbox", children: _jsx(Checkbox, { checked: isOptionSelected(option.value), decorative: true }) })) : null, option.color ? (_jsx("span", { "aria-hidden": "true", className: "umds-select__swatch", style: {
663
709
  background: option.color,
664
- } })) : 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 &&
710
+ } })) : null, _jsx("div", { className: "umds-select__option-content", children: _jsx(_Fragment, { children: typeof props.item === "function" ? props.item({ optionData: option, option }) : 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 &&
665
711
  props.selectionDisplay === "list" &&
666
712
  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] }));
667
713
  }
@@ -290,3 +290,11 @@
290
290
  .umds-stat-card--rotulo-topo.umds-stat-card--com-secundaria:not(:has(.umds-stat-card__icone)) .umds-stat-card__valor {
291
291
  grid-column: 1 / 3;
292
292
  }
293
+
294
+ /* ── size="sm": o KPI de 18px/800 ──
295
+ 18px não está na escala de fonte do DS (16 e 20): é a medida dos KPIs da home do CrisDoc, mantida como literal.
296
+ Dois seletores de classe para vencer o 32/800 do `labelPosition="top"` sem depender da ordem. */
297
+ .umds-stat-card.umds-stat-card--sm .umds-stat-card__valor {
298
+ font-size: 1.125rem; /* 18px */
299
+ font-weight: var(--umds-primitive-font-weight-extrabold);
300
+ }
@@ -22,6 +22,7 @@ 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} size - 'md' (padrão) | 'sm': o `sm` leva o número a 18px/800, o tamanho dos KPIs da home do CrisDoc (fora da escala de fonte do DS, que vai de 16 a 20). Vale também com `labelPosition="top"`.
25
26
  * @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
27
  * @property {string|number} secondaryValue - Segunda medida do cartão, menor, à direita da principal ("22,31%" do setor e "14,11%" do geral). Vem depois do resto no HTML. `0` aparece; vazio e ausente não.
27
28
  * @property {string} secondaryLabel - O que a segunda medida significa ("Geral")
@@ -73,6 +74,8 @@ export interface StatCardProps {
73
74
  secondaryValue?: string | number;
74
75
  /** O que a segunda medida significa. */
75
76
  secondaryLabel?: string;
77
+ /** Tamanho do número: `sm` é o KPI de 18px/800. @default 'md' */
78
+ size?: "md" | "sm";
76
79
  /** Cor do número principal. @default 'default' */
77
80
  valueTone?: "default" | "primary" | "positive" | "negative" | "info";
78
81
  /**
@@ -10,6 +10,7 @@ function StatCard(props) {
10
10
  "umds-stat-card",
11
11
  `umds-stat-card--${props.variant || "neutral"}`,
12
12
  props.align === "center" ? "umds-stat-card--centro" : "",
13
+ props.size === "sm" ? "umds-stat-card--sm" : "",
13
14
  props.labelPosition === "top" ? "umds-stat-card--rotulo-topo" : "",
14
15
  temSecundaria() ? "umds-stat-card--com-secundaria" : "",
15
16
  props.valueTone && props.valueTone !== "default"
@@ -93,6 +93,17 @@
93
93
  white-space: nowrap;
94
94
  }
95
95
 
96
+ /* ============================
97
+ Densidade compacta (density="compact" no Tabs)
98
+ Altura mínima de 40px (o degrau sm do DS) e padding vertical de 8px: com o texto de 14px e a barra de
99
+ 3px, a aba fica nos 40. Só o padding vertical (padding-block), para não desfazer o espaço do × da aba
100
+ fechável. O contador em pílula não muda: cinza na aba inativa e azul só na ativa.
101
+ ============================ */
102
+ .umds-tabs--compact .umds-tabs__tab {
103
+ min-height: var(--umds-primitive-spacing-sm); /* 40px */
104
+ padding-block: var(--umds-primitive-spacing-nano);
105
+ }
106
+
96
107
  /* ============================
97
108
  Label
98
109
  ============================ */
@@ -14,6 +14,13 @@ export interface TabsProps {
14
14
  onChange?: (index: string) => void;
15
15
  /** Label de acessibilidade para o tablist */
16
16
  ariaLabel?: string;
17
+ /**
18
+ * Densidade das abas: `compact` leva a altura mínima de 48px a 40px (padding vertical de 8px), para barras
19
+ * de abas dentro de uma tela (o CrisDoc usa 40). O contador em pílula não muda: cinza na aba inativa e azul
20
+ * só na ativa, nas duas densidades.
21
+ * @default 'default'
22
+ */
23
+ density?: "default" | "compact";
17
24
  /**
18
25
  * Identificador estável usado como base dos ids acessíveis
19
26
  * (`{id}-tab-{index}` / `{id}-panel-{index}`). Passe o MESMO id no
@@ -6,7 +6,13 @@ import Icon from "../Icon/Icon";
6
6
  import TabsContext from "./tabs.context";
7
7
  function Tabs(props) {
8
8
  function classes() {
9
- return ["umds-tabs", props.className].filter(Boolean).join(" ");
9
+ return [
10
+ "umds-tabs",
11
+ props.density === "compact" ? "umds-tabs--compact" : "",
12
+ props.className,
13
+ ]
14
+ .filter(Boolean)
15
+ .join(" ");
10
16
  }
11
17
  function barClasses() {
12
18
  return ["umds-tabs__bar", props.onAdd ? "umds-tabs__bar--com-add" : ""]
@@ -194,7 +194,9 @@
194
194
 
195
195
  .umds-tag--outlined.umds-tag--positive {
196
196
  border-color: var(--umds-semantic-color-feedback-positive-pure);
197
- color: var(--umds-semantic-color-feedback-positive-pure);
197
+ /* O contorno transparente deixa o texto sobre o fundo de quem está atrás (um card tingido de azul-claro).
198
+ positive-pure sobre primary-light dá 3,6:1; positive-dark dá 7,9:1 e é o par de texto do `soft`. */
199
+ color: var(--umds-semantic-color-feedback-positive-dark);
198
200
  }
199
201
 
200
202
  .umds-tag--outlined.umds-tag--negative {
@@ -0,0 +1 @@
1
+ export {};