@1doc/1ds-react 2.9.0 → 2.10.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 (115) hide show
  1. package/CHANGELOG.md +434 -0
  2. package/dist/components/Accordion/Accordion.css +13 -0
  3. package/dist/components/Accordion/Accordion.d.ts +3 -0
  4. package/dist/components/Accordion/Accordion.js +1 -0
  5. package/dist/components/AppSubheader/AppSubheader.css +10 -1
  6. package/dist/components/AttachmentCard/AttachmentCard.css +10 -8
  7. package/dist/components/AttachmentCard/AttachmentCard.d.ts +3 -0
  8. package/dist/components/AttachmentCard/AttachmentCard.js +8 -1
  9. package/dist/components/Badge/Badge.css +14 -1
  10. package/dist/components/Badge/Badge.d.ts +11 -2
  11. package/dist/components/Badge/Badge.js +3 -0
  12. package/dist/components/Calendar/Calendar.d.ts +7 -6
  13. package/dist/components/Coachmark/Coachmark.css +10 -0
  14. package/dist/components/Coachmark/Coachmark.d.ts +12 -0
  15. package/dist/components/Coachmark/Coachmark.js +46 -5
  16. package/dist/components/ColorPicker/ColorPicker.css +8 -1
  17. package/dist/components/ColorPicker/ColorPicker.d.ts +2 -2
  18. package/dist/components/DataTable/DataTable.css +174 -0
  19. package/dist/components/DataTable/DataTable.d.ts +63 -2
  20. package/dist/components/DataTable/DataTable.js +278 -6
  21. package/dist/components/DescriptionList/DescriptionList.css +14 -0
  22. package/dist/components/DescriptionList/DescriptionList.d.ts +3 -0
  23. package/dist/components/DescriptionList/DescriptionList.js +1 -0
  24. package/dist/components/EmptyState/EmptyState.d.ts +4 -2
  25. package/dist/components/EmptyState/EmptyState.js +2 -2
  26. package/dist/components/Input/Input.css +21 -0
  27. package/dist/components/Input/Input.d.ts +7 -0
  28. package/dist/components/Input/Input.js +2 -1
  29. package/dist/components/List/ListItem.d.ts +14 -2
  30. package/dist/components/List/ListItem.js +3 -2
  31. package/dist/components/RichTextEditor/RichTextEditor.css +47 -0
  32. package/dist/components/RichTextEditor/RichTextEditor.d.ts +22 -8
  33. package/dist/components/RichTextEditor/RichTextEditor.js +460 -3
  34. package/dist/components/SegmentedControl/SegmentedControl.css +24 -0
  35. package/dist/components/SegmentedControl/SegmentedControl.d.ts +2 -0
  36. package/dist/components/SegmentedControl/SegmentedControl.js +4 -1
  37. package/dist/components/Select/Select.css +94 -0
  38. package/dist/components/Select/Select.d.ts +26 -4
  39. package/dist/components/Select/Select.js +210 -35
  40. package/dist/components/StatCard/StatCard.css +65 -0
  41. package/dist/components/StatCard/StatCard.d.ts +9 -0
  42. package/dist/components/StatCard/StatCard.js +10 -1
  43. package/dist/components/Toast/Toast.css +32 -0
  44. package/dist/components/Toast/Toast.d.ts +18 -0
  45. package/dist/components/Toast/Toast.js +14 -1
  46. package/dist/components/Toast/ToastStack.js +8 -1
  47. package/dist/teste/AccordionTituloNeutro.test.d.ts +1 -0
  48. package/dist/teste/AccordionTituloNeutro.test.js +23 -0
  49. package/dist/teste/AppSubheaderRegiao.test.d.ts +1 -0
  50. package/dist/teste/AppSubheaderRegiao.test.js +13 -0
  51. package/dist/teste/AttachmentCardLista.test.d.ts +1 -0
  52. package/dist/teste/AttachmentCardLista.test.js +49 -0
  53. package/dist/teste/AttachmentCardSm.test.d.ts +1 -0
  54. package/dist/teste/AttachmentCardSm.test.js +26 -0
  55. package/dist/teste/BadgeNeutroColado.test.d.ts +1 -0
  56. package/dist/teste/BadgeNeutroColado.test.js +11 -0
  57. package/dist/teste/BadgeTag.test.js +13 -0
  58. package/dist/teste/CalendarCabecalho.test.d.ts +1 -0
  59. package/dist/teste/CalendarCabecalho.test.js +11 -0
  60. package/dist/teste/CoachmarkSemVeu.test.d.ts +1 -0
  61. package/dist/teste/CoachmarkSemVeu.test.js +85 -0
  62. package/dist/teste/ColorPickerXs.test.d.ts +1 -0
  63. package/dist/teste/ColorPickerXs.test.js +21 -0
  64. package/dist/teste/DataTableArvoreEVariantes.test.d.ts +1 -0
  65. package/dist/teste/DataTableArvoreEVariantes.test.js +190 -0
  66. package/dist/teste/DescriptionListCompacta.test.d.ts +1 -0
  67. package/dist/teste/DescriptionListCompacta.test.js +22 -0
  68. package/dist/teste/EmptyStateTituloRico.test.d.ts +1 -0
  69. package/dist/teste/EmptyStateTituloRico.test.js +23 -0
  70. package/dist/teste/InputAgrupado.test.d.ts +1 -0
  71. package/dist/teste/InputAgrupado.test.js +24 -0
  72. package/dist/teste/ListItemTooltipStandalone.test.d.ts +1 -0
  73. package/dist/teste/ListItemTooltipStandalone.test.js +39 -0
  74. package/dist/teste/RichTextEditorAlinhaImagemTabela.test.d.ts +1 -0
  75. package/dist/teste/RichTextEditorAlinhaImagemTabela.test.js +212 -0
  76. package/dist/teste/RichTextEditorEstiloDeTexto.test.d.ts +1 -0
  77. package/dist/teste/RichTextEditorEstiloDeTexto.test.js +120 -0
  78. package/dist/teste/SegmentedControlContador.test.d.ts +1 -0
  79. package/dist/teste/SegmentedControlContador.test.js +39 -0
  80. package/dist/teste/SelectAbertoControladoEFlutuante.test.d.ts +1 -0
  81. package/dist/teste/SelectAbertoControladoEFlutuante.test.js +145 -0
  82. package/dist/teste/SelectFiltroCorETamanho.test.d.ts +1 -0
  83. package/dist/teste/SelectFiltroCorETamanho.test.js +77 -0
  84. package/dist/teste/StatCardSecundariaETom.test.d.ts +1 -0
  85. package/dist/teste/StatCardSecundariaETom.test.js +45 -0
  86. package/dist/teste/ToastAcaoEDetalhes.test.d.ts +1 -0
  87. package/dist/teste/ToastAcaoEDetalhes.test.js +94 -0
  88. package/dist/utils/html-seguro.d.ts +19 -1
  89. package/dist/utils/html-seguro.js +113 -2
  90. package/dist/utils/toast.d.ts +10 -1
  91. package/dist/utils/toast.js +2 -1
  92. package/package.json +2 -2
  93. package/src/teste/AccordionTituloNeutro.test.tsx +25 -0
  94. package/src/teste/AppSubheaderRegiao.test.tsx +17 -0
  95. package/src/teste/AttachmentCardLista.test.tsx +53 -0
  96. package/src/teste/AttachmentCardSm.test.tsx +29 -0
  97. package/src/teste/BadgeNeutroColado.test.tsx +15 -0
  98. package/src/teste/BadgeTag.test.tsx +21 -0
  99. package/src/teste/CalendarCabecalho.test.tsx +11 -0
  100. package/src/teste/CoachmarkSemVeu.test.tsx +101 -0
  101. package/src/teste/ColorPickerXs.test.tsx +22 -0
  102. package/src/teste/DataTableArvoreEVariantes.test.tsx +240 -0
  103. package/src/teste/DescriptionListCompacta.test.tsx +24 -0
  104. package/src/teste/EmptyStateTituloRico.test.tsx +34 -0
  105. package/src/teste/InputAgrupado.test.tsx +26 -0
  106. package/src/teste/ListItemTooltipStandalone.test.tsx +64 -0
  107. package/src/teste/RichTextEditorAlinhaImagemTabela.test.tsx +238 -0
  108. package/src/teste/RichTextEditorEstiloDeTexto.test.tsx +137 -0
  109. package/src/teste/SegmentedControlContador.test.tsx +43 -0
  110. package/src/teste/SelectAbertoControladoEFlutuante.test.tsx +180 -0
  111. package/src/teste/SelectFiltroCorETamanho.test.tsx +90 -0
  112. package/src/teste/StatCardSecundariaETom.test.tsx +51 -0
  113. package/src/teste/ToastAcaoEDetalhes.test.tsx +109 -0
  114. package/src/utils/html-seguro.ts +105 -2
  115. package/src/utils/toast.ts +12 -2
@@ -19,13 +19,22 @@ export interface BadgeProps {
19
19
  */
20
20
  size?: "2xs" | "xs" | "sm" | "md" | "lg" | "pill";
21
21
  /**
22
- * Cola o badge no canto superior esquerdo do card (rótulo de card, como
22
+ * Cola o badge no canto superior do card (rótulo de card, como
23
23
  * "Tarefa pendente"): cantos de baixo arredondados, os de cima retos.
24
24
  * Posiciona em `absolute`, então o pai precisa de `position: relative`
25
- * (o `Card` e o `Box` com `position` já servem).
25
+ * (o `Card` e o `Box` com `position` já servem). O canto é o esquerdo, ou o
26
+ * direito com `attachedSide="right"`. Com `variant="neutral"` e `appearance="solid"` o
27
+ * rótulo colado é o cinza claro com texto escuro (o "Tarefa manual" do CrisDoc), e não o
28
+ * cinza escuro do `solid`, pesado demais para um rótulo de card.
26
29
  * @default false
27
30
  */
28
31
  attached?: boolean;
32
+ /**
33
+ * Em que canto do card o `attached` cola: `left` (padrão) ou `right`.
34
+ * Só vale com `attached`.
35
+ * @default 'left'
36
+ */
37
+ attachedSide?: "left" | "right";
29
38
  /**
30
39
  * Estilo visual do badge.
31
40
  * @default 'soft'
@@ -8,6 +8,9 @@ function Badge(props) {
8
8
  `umds-badge--${props.size || "md"}`,
9
9
  `umds-badge--${props.appearance || "soft"}`,
10
10
  props.attached ? "umds-badge--attached" : "",
11
+ props.attached && props.attachedSide === "right"
12
+ ? "umds-badge--attached-right"
13
+ : "",
11
14
  props.className,
12
15
  ]
13
16
  .filter(Boolean)
@@ -52,8 +52,9 @@ export interface CalendarDayCell {
52
52
  *
53
53
  * A data mostrada (`date`) e a visão (`view`) são controláveis (`onDateChange`,
54
54
  * `onViewChange`) ou internas (`defaultDate`, `defaultView`). O cabeçalho aceita
55
- * o slot `headerStart` (um filtro de escopo, à esquerda) e `headerEnd` (a
56
- * legenda, à direita). Nomes de mês e de dia saem do `Intl` no `locale` pedido;
55
+ * um filtro de escopo à esquerda e a legenda à direita: no React, as props `headerStart`
56
+ * e `headerEnd` (um nó); no Vue, os slots `#header-start` e `#header-end` (com hífen: o
57
+ * Vue lê o nome do slot como está, e `#headerStart` não chega). Nomes de mês e de dia saem do `Intl` no `locale` pedido;
57
58
  * os demais textos são props.
58
59
  * @property {CalendarEvent[]} events - Eventos (lista plana)
59
60
  * @property {string} view - Visão: 'month' | 'week' (controlada)
@@ -82,8 +83,8 @@ export interface CalendarDayCell {
82
83
  * @property {function} onDateChange - Mudou a data de referência (navegação): recebe `YYYY-MM-DD`
83
84
  * @property {function} onViewChange - Mudou a visão: recebe 'month' | 'week'
84
85
  * @property {string} className - Classes CSS adicionais
85
- * @slot headerStart - Cabeçalho, à esquerda: um filtro de escopo.
86
- * @slot headerEnd - Cabeçalho, antes do seletor de visão: a legenda.
86
+ * @slot header-start - Só no Vue (`#header-start`, com hífen). Cabeçalho, à esquerda: um filtro de escopo. No React, a prop `headerStart`.
87
+ * @slot header-end - Só no Vue (`#header-end`, com hífen). Cabeçalho, antes do seletor de visão: a legenda. No React, a prop `headerEnd`.
87
88
  * @quandoUsar Mostrar prazos, vencimentos e compromissos distribuídos no tempo: agenda de documentos, de tarefas, de assinaturas.
88
89
  * @quandoNaoUsar Para escolher UMA data num campo, use `DatePicker`. Para uma sequência de acontecimentos sem grade de dias, use `Timeline`. Para uma grade de horas (agenda com horário de início e fim), este componente não serve: não tem eixo de horas.
89
90
  */
@@ -111,9 +112,9 @@ export interface CalendarProps {
111
112
  moreAriaLabel?: string;
112
113
  dayLabel?: (iso: string, count: number) => string;
113
114
  className?: string;
114
- /** Slot `headerStart`: à esquerda do cabeçalho. */
115
+ /** Cabeçalho, à esquerda: um filtro de escopo. React: o nó nesta prop. Vue: o slot `#header-start` (com hífen). */
115
116
  headerStart?: any;
116
- /** Slot `headerEnd`: à direita, antes do seletor de visão. */
117
+ /** Cabeçalho, à direita, antes do seletor de visão: a legenda. React: o nó nesta prop. Vue: o slot `#header-end` (com hífen). */
117
118
  headerEnd?: any;
118
119
  onDayClick?: (iso: string) => void;
119
120
  onEventClick?: (event: CalendarEvent) => void;
@@ -107,6 +107,16 @@
107
107
  border: 0;
108
108
  }
109
109
 
110
+ /* ── modal={false}: sem véu nem recorte, a página segue clicável ──
111
+ A raiz cobre a tela só para posicionar o cartão; quem recebe o ponteiro é o cartão. */
112
+ .umds-coachmark--modeless {
113
+ pointer-events: none;
114
+ }
115
+
116
+ .umds-coachmark--modeless .umds-coachmark__card {
117
+ pointer-events: auto;
118
+ }
119
+
110
120
  @media (forced-colors: active) {
111
121
  .umds-coachmark__card {
112
122
  border: var(--umds-primitive-border-width-thin) solid CanvasText;
@@ -38,7 +38,13 @@ export interface CoachmarkStep {
38
38
  *
39
39
  * Limite: a página atrás fica inerte (o véu captura o clique), então o alvo
40
40
  * não é clicável durante o tour.
41
+ *
42
+ * `modal={false}` tira o véu, o recorte e o foco preso: o cartão vira um popover
43
+ * ancorado no alvo, para uma dica pontual (um passo, "Novo: agora dá para * arrastar"). A página segue clicável, o foco entra no cartão ao abrir mas o Tab
44
+ * pode sair dele, o Esc fecha de qualquer lugar da página e o cartão vira um
45
+ * `role="dialog"` com `aria-modal="false"`.
41
46
  * @property {boolean} open - Mostra o tour
47
+ * @property {boolean} modal - `true` (padrão): véu, recorte e foco preso. `false`: sem véu nem foco preso, como um popover ancorado, para dica pontual
42
48
  * @property {CoachmarkStep[]} steps - Os passos, em ordem
43
49
  * @property {number} step - Passo atual, a partir de 0 (controlado)
44
50
  * @property {number} defaultStep - Passo inicial (não controlado)
@@ -57,6 +63,12 @@ export interface CoachmarkStep {
57
63
  */
58
64
  export interface CoachmarkProps {
59
65
  open?: boolean;
66
+ /**
67
+ * `true` (padrão): véu, recorte e foco preso. `false`: o cartão é um popover
68
+ * ancorado, sem véu nem foco preso. `any` de propósito: no Vue uma prop `boolean`
69
+ * sem valor chega como `false`, e o tour modal viraria sem véu por engano.
70
+ */
71
+ modal?: any;
60
72
  steps?: CoachmarkStep[];
61
73
  step?: number;
62
74
  defaultStep?: number;
@@ -12,6 +12,7 @@ function Coachmark(props) {
12
12
  const cleanupRef = useRef(null);
13
13
  const previousFocusRef = useRef(null);
14
14
  const attachedRef = useRef(null);
15
+ const escDocRef = useRef(null);
15
16
  const [internalStep, setInternalStep] = useState(() => props.defaultStep || 0);
16
17
  const [uid, setUid] = useState(() => "");
17
18
  const [active, setActive] = useState(() => false);
@@ -75,6 +76,14 @@ function Coachmark(props) {
75
76
  function skipText() {
76
77
  return props.skipLabel || "Sair do tour";
77
78
  }
79
+ function isModal() {
80
+ if (props.modal === undefined || props.modal === null)
81
+ return true;
82
+ return props.modal !== false && props.modal !== "false";
83
+ }
84
+ function ariaModalText() {
85
+ return isModal() ? "true" : "false";
86
+ }
78
87
  function showSkip() {
79
88
  return !props.hideSkip;
80
89
  }
@@ -85,6 +94,7 @@ function Coachmark(props) {
85
94
  return [
86
95
  "umds-coachmark",
87
96
  hasTarget ? "" : "umds-coachmark--no-target",
97
+ isModal() ? "" : "umds-coachmark--modeless",
88
98
  positioned ? "umds-coachmark--ready" : "",
89
99
  ]
90
100
  .filter(Boolean)
@@ -196,6 +206,23 @@ function Coachmark(props) {
196
206
  cleanupRef.current = null;
197
207
  }
198
208
  }
209
+ function ligarEsc() {
210
+ if (typeof document === "undefined" || escDocRef.current)
211
+ return;
212
+ const ouvir = (event) => {
213
+ // O Esc dentro do cartão já fechou (e deu preventDefault): não fecha duas vezes.
214
+ if (event.key === "Escape" && !event.defaultPrevented)
215
+ fechar("escape");
216
+ };
217
+ escDocRef.current = ouvir;
218
+ document.addEventListener("keydown", ouvir);
219
+ }
220
+ function desligarEsc() {
221
+ if (typeof document === "undefined" || !escDocRef.current)
222
+ return;
223
+ document.removeEventListener("keydown", escDocRef.current);
224
+ escDocRef.current = null;
225
+ }
199
226
  function sincronizar() {
200
227
  if (typeof document === "undefined")
201
228
  return;
@@ -210,12 +237,18 @@ function Coachmark(props) {
210
237
  if (show() && !active) {
211
238
  setActive(true);
212
239
  setTentativas(0);
213
- previousFocusRef.current = document.activeElement;
240
+ // Guarda só na primeira vez: no React o `active` leva um render para
241
+ // valer, e um segundo `sincronizar` antes disso guardaria o próprio
242
+ // cartão (já focado) como "o elemento de antes".
243
+ if (!previousFocusRef.current)
244
+ previousFocusRef.current = document.activeElement;
214
245
  ligar();
215
246
  if (cardRef.current)
216
247
  cardRef.current.focus({
217
248
  preventScroll: true,
218
249
  });
250
+ if (!isModal())
251
+ ligarEsc();
219
252
  }
220
253
  else if (show() && active && attachedRef.current !== index()) {
221
254
  ligar();
@@ -223,15 +256,22 @@ function Coachmark(props) {
223
256
  else if (!show() && active) {
224
257
  setActive(false);
225
258
  desligar();
259
+ desligarEsc();
226
260
  attachedRef.current = null;
227
261
  setHasTarget(false);
228
262
  setPositioned(false);
229
263
  if (props.step === undefined)
230
264
  setInternalStep(props.defaultStep || 0);
231
- if (previousFocusRef.current && previousFocusRef.current.focus) {
265
+ // Sem véu a pessoa pode ter ido para outro lugar da página: o foco só volta se ela não foi.
266
+ const focoLivre = isModal() ||
267
+ document.activeElement === document.body ||
268
+ !document.activeElement;
269
+ if (previousFocusRef.current &&
270
+ previousFocusRef.current.focus &&
271
+ focoLivre) {
232
272
  previousFocusRef.current.focus();
233
- previousFocusRef.current = null;
234
273
  }
274
+ previousFocusRef.current = null;
235
275
  }
236
276
  }
237
277
  function irPara(proximo) {
@@ -274,7 +314,7 @@ function Coachmark(props) {
274
314
  handlePrevious();
275
315
  return;
276
316
  }
277
- if (event.key !== "Tab" || !cardRef.current)
317
+ if (event.key !== "Tab" || !cardRef.current || !isModal())
278
318
  return;
279
319
  // Foco preso: Tab e Shift+Tab giram dentro do cartão.
280
320
  const focaveis = cardRef.current.querySelectorAll("button:not([disabled])");
@@ -314,8 +354,9 @@ function Coachmark(props) {
314
354
  useEffect(() => {
315
355
  return () => {
316
356
  desligar();
357
+ desligarEsc();
317
358
  };
318
359
  }, []);
319
- return (_jsx(_Fragment, { children: show() ? (_jsx(_Fragment, { children: _jsx(Portal, { children: _jsxs("div", { className: rootClasses(), children: [_jsx("div", { "aria-hidden": "true", className: "umds-coachmark__veil", onMouseDown: (event) => handleVeilMouseDown(event) }), hasTarget ? (_jsx("div", { "aria-hidden": "true", className: "umds-coachmark__cutout", style: cutoutStyle() })) : null, _jsxs("div", { role: "dialog", "aria-modal": "true", ref: cardRef, style: cardStyle(), "aria-labelledby": titleId(), "aria-describedby": contentId(), tabIndex: -1, onKeyDown: (event) => handleKeyDown(event), className: cardClasses(), children: [_jsx("span", { "aria-live": "polite", className: "umds-coachmark__sr", children: announceText() }), _jsx(Text, { as: "span", variant: "body2", weight: "bold", color: "primary", "aria-hidden": "true", children: counterText() }), _jsx(Text, { as: "h2", variant: "subtitle1", weight: "bold", id: titleId(), children: currentStep().title }), currentStep().content ? (_jsx(Text, { as: "p", variant: "body2", color: "secondary", id: contentId(), children: currentStep().content })) : null, _jsxs("div", { className: "umds-coachmark__footer", children: [showSkip() ? (_jsx(Button, { variant: "text", size: "sm", onClick: (event) => fechar("skip"), children: skipText() })) : null, _jsxs("span", { className: "umds-coachmark__actions", children: [!isFirst() ? (_jsx(Button, { variant: "secondary", size: "md", onClick: (event) => handlePrevious(), children: previousText() })) : null, _jsx(Button, { variant: "primary", size: "md", onClick: (event) => handleNext(), children: nextText() })] })] })] })] }) }) })) : null }));
360
+ return (_jsx(_Fragment, { children: show() ? (_jsx(_Fragment, { children: _jsx(Portal, { children: _jsxs("div", { className: rootClasses(), children: [isModal() ? (_jsx("div", { "aria-hidden": "true", className: "umds-coachmark__veil", onMouseDown: (event) => handleVeilMouseDown(event) })) : null, hasTarget && isModal() ? (_jsx("div", { "aria-hidden": "true", className: "umds-coachmark__cutout", style: cutoutStyle() })) : null, _jsxs("div", { role: "dialog", ref: cardRef, style: cardStyle(), "aria-modal": ariaModalText(), "aria-labelledby": titleId(), "aria-describedby": contentId(), tabIndex: -1, onKeyDown: (event) => handleKeyDown(event), className: cardClasses(), children: [_jsx("span", { "aria-live": "polite", className: "umds-coachmark__sr", children: announceText() }), _jsx(Text, { as: "span", variant: "body2", weight: "bold", color: "primary", "aria-hidden": "true", children: counterText() }), _jsx(Text, { as: "h2", variant: "subtitle1", weight: "bold", id: titleId(), children: currentStep().title }), currentStep().content ? (_jsx(Text, { as: "p", variant: "body2", color: "secondary", id: contentId(), children: currentStep().content })) : null, _jsxs("div", { className: "umds-coachmark__footer", children: [showSkip() ? (_jsx(Button, { variant: "text", size: "sm", onClick: (event) => fechar("skip"), children: skipText() })) : null, _jsxs("span", { className: "umds-coachmark__actions", children: [!isFirst() ? (_jsx(Button, { variant: "secondary", size: "md", onClick: (event) => handlePrevious(), children: previousText() })) : null, _jsx(Button, { variant: "primary", size: "md", onClick: (event) => handleNext(), children: nextText() })] })] })] })] }) }) })) : null }));
320
361
  }
321
362
  export default Coachmark;
@@ -35,7 +35,8 @@
35
35
  padding: var(--umds-primitive-spacing-quarck);
36
36
  }
37
37
 
38
- .umds-color-picker--sm .umds-color-picker__swatches {
38
+ .umds-color-picker--sm .umds-color-picker__swatches,
39
+ .umds-color-picker--xs .umds-color-picker__swatches {
39
40
  gap: var(--umds-primitive-spacing-quarck); /* 4px */
40
41
  }
41
42
 
@@ -76,6 +77,12 @@
76
77
  height: var(--umds-primitive-spacing-xxs);
77
78
  }
78
79
 
80
+ /* xs: 20px, o tamanho do CrisDoc (16 + 4, dois degraus da escala somados; sem token próprio). */
81
+ .umds-color-picker--xs .umds-color-picker__swatch {
82
+ width: calc(var(--umds-primitive-spacing-xxxs) + var(--umds-primitive-spacing-quarck)); /* 20px */
83
+ height: calc(var(--umds-primitive-spacing-xxxs) + var(--umds-primitive-spacing-quarck));
84
+ }
85
+
79
86
  .umds-color-picker__swatch--on-light {
80
87
  /* stylelint-disable-next-line 1ds/cor-por-token -- par fixo da marcação sobre amostra clara (ver acima) */
81
88
  color: var(--umds-primitive-gray-darkest);
@@ -44,7 +44,7 @@ export interface ColorPickerSwatch {
44
44
  * @property {boolean} allowCustom - Liga o campo de cor livre (hexadecimal)
45
45
  * @property {string} customLabel - Rótulo do campo de cor livre (padrão: "Cor livre (hexadecimal)")
46
46
  * @property {string} customErrorMessage - Mensagem do hexadecimal inválido (padrão: "Use o formato #RRGGBB")
47
- * @property {string} size - Tamanho da amostra: 'sm' (24px) | 'md' (32px)
47
+ * @property {string} size - Tamanho da amostra: 'xs' (20px, o do CrisDoc) | 'sm' (24px) | 'md' (32px). A marcação de selecionada (o anel duplo) é a mesma nos três.
48
48
  * @property {boolean} disabled - Desabilita o grupo inteiro
49
49
  * @property {string} id - Base dos ids internos; passe em SSR para os ids já saírem no HTML do servidor
50
50
  * @property {string} className - Classes CSS adicionais
@@ -63,7 +63,7 @@ export interface ColorPickerProps {
63
63
  allowCustom?: boolean;
64
64
  customLabel?: string;
65
65
  customErrorMessage?: string;
66
- size?: "sm" | "md";
66
+ size?: "xs" | "sm" | "md";
67
67
  disabled?: boolean;
68
68
  id?: string;
69
69
  className?: string;
@@ -212,6 +212,73 @@
212
212
  padding: var(--umds-primitive-spacing-nano) var(--umds-primitive-spacing-quarck) var(--umds-primitive-spacing-nano) var(--umds-primitive-spacing-nano); /* 6px: candidato a novo token; 4px; 8px */
213
213
  }
214
214
 
215
+ /* ── Cabeçalho escuro (headerVariant="dark") ──
216
+ O navy do CrisDoc, com o texto claro do par `background-dark` / `neutral-light-pure`
217
+ (os dois viram juntos com o tema). Ordenação e foco no cabeçalho escuro usam o
218
+ texto claro, não o azul de ação, que não tem contraste sobre o navy. */
219
+ .umds-datatable--header-dark .umds-datatable__thead {
220
+ background: var(--umds-semantic-color-background-dark);
221
+ border-bottom-color: var(--umds-semantic-color-background-dark);
222
+ }
223
+
224
+ .umds-datatable--header-dark .umds-datatable__th,
225
+ .umds-datatable--header-dark .umds-datatable__th--sortable:hover,
226
+ .umds-datatable--header-dark .umds-datatable__th--sorted {
227
+ color: var(--umds-semantic-color-neutral-light-pure);
228
+ }
229
+
230
+ .umds-datatable--header-dark .umds-datatable__sort-icon {
231
+ color: var(--umds-semantic-color-neutral-light-down);
232
+ }
233
+
234
+ .umds-datatable--header-dark .umds-datatable__sort-icon--active {
235
+ color: inherit;
236
+ }
237
+
238
+ .umds-datatable--header-dark .umds-datatable__sort-button:focus-visible {
239
+ outline-color: var(--umds-semantic-color-neutral-light-pure);
240
+ }
241
+
242
+ /* ── Caixa alta no cabeçalho (headerUppercase) ── */
243
+ .umds-datatable--header-uppercase .umds-datatable__th {
244
+ text-transform: uppercase;
245
+ letter-spacing: var(--umds-primitive-font-letter-spacing-wide);
246
+ }
247
+
248
+ /* ── Cabeçalho só para o leitor de tela (hideHeader) ──
249
+ Visualmente oculto, não removido: as colunas continuam nomeadas. */
250
+ .umds-datatable--header-hidden .umds-datatable__thead {
251
+ position: absolute;
252
+ width: var(--umds-primitive-border-width-hairline);
253
+ height: var(--umds-primitive-border-width-hairline);
254
+ margin: calc(-1 * var(--umds-primitive-border-width-hairline));
255
+ padding: 0;
256
+ overflow: hidden;
257
+ clip-path: inset(50%);
258
+ white-space: nowrap;
259
+ border: 0;
260
+ }
261
+
262
+ /* ── Zebra (striped) ── */
263
+ .umds-datatable__row--striped,
264
+ .umds-datatable__row--striped.umds-datatable__row--group {
265
+ background: var(--umds-semantic-color-background-light);
266
+ }
267
+
268
+ .umds-datatable__row--striped:hover {
269
+ background: var(--umds-semantic-color-neutral-light-medium);
270
+ }
271
+
272
+ .umds-datatable__row--striped.umds-datatable__row--selected {
273
+ background: var(--umds-semantic-color-primary-light);
274
+ }
275
+
276
+ /* ── Linha destacada (selectedRowKeys / isRowSelected) ──
277
+ Além do fundo, uma barra de 4px à esquerda: o destaque não depende só da cor. */
278
+ .umds-datatable__row--highlighted > :first-child {
279
+ box-shadow: inset var(--umds-primitive-border-width-thick) 0 0 var(--umds-semantic-color-primary-pure);
280
+ }
281
+
215
282
  /* ── Estado vazio ── */
216
283
  .umds-datatable__td--empty {
217
284
  padding: var(--umds-primitive-spacing-md) var(--umds-primitive-spacing-xxxs); /* 48px 16px */
@@ -233,6 +300,106 @@
233
300
  color: var(--umds-semantic-color-neutral-light-down); /* #D5D5D5 */
234
301
  }
235
302
 
303
+ .umds-datatable__empty-desc {
304
+ font-size: var(--umds-primitive-font-size-xxxs); /* 12px */
305
+ color: var(--umds-semantic-color-neutral-dark-down);
306
+ }
307
+
308
+ /* ── Linhas hierárquicas (treeData) ──
309
+ `role="treegrid"`. A primeira coluna de dados leva o recuo por nível, os fios e o
310
+ botão de expandir/recolher. Os fios são colunas de 24px (o passo do recuo) desenhadas
311
+ por trás do conteúdo, de ponta a ponta da célula, então atravessam o padding e se
312
+ emendam de uma linha à outra. */
313
+ .umds-datatable__td--tree {
314
+ position: relative;
315
+ }
316
+
317
+ .umds-datatable__tree-guides {
318
+ position: absolute;
319
+ top: 0;
320
+ bottom: 0;
321
+ left: var(--umds-primitive-spacing-xxxs);
322
+ display: flex;
323
+ pointer-events: none;
324
+ }
325
+
326
+ .umds-datatable__guide {
327
+ position: relative;
328
+ flex: 0 0 var(--umds-primitive-spacing-xxs);
329
+ }
330
+
331
+ .umds-datatable__guide--line::before,
332
+ .umds-datatable__guide--tee::before,
333
+ .umds-datatable__guide--elbow::before {
334
+ content: "";
335
+ position: absolute;
336
+ top: 0;
337
+ bottom: 0;
338
+ left: 50%;
339
+ border-left: var(--umds-primitive-border-width-hairline) solid var(--umds-semantic-color-neutral-light-down);
340
+ }
341
+
342
+ .umds-datatable__guide--elbow::before {
343
+ bottom: 50%;
344
+ }
345
+
346
+ .umds-datatable__guide--tee::after,
347
+ .umds-datatable__guide--elbow::after {
348
+ content: "";
349
+ position: absolute;
350
+ top: 50%;
351
+ left: 50%;
352
+ right: 0;
353
+ border-top: var(--umds-primitive-border-width-hairline) solid var(--umds-semantic-color-neutral-light-down);
354
+ }
355
+
356
+ .umds-datatable__tree-content {
357
+ position: relative;
358
+ display: flex;
359
+ align-items: center;
360
+ gap: var(--umds-primitive-spacing-quarck);
361
+ min-width: 0;
362
+ }
363
+
364
+ .umds-datatable__tree-text {
365
+ min-width: 0;
366
+ }
367
+
368
+ .umds-datatable__tree-toggle,
369
+ .umds-datatable__tree-spacer {
370
+ flex: 0 0 var(--umds-primitive-spacing-xxs);
371
+ width: var(--umds-primitive-spacing-xxs);
372
+ height: var(--umds-primitive-spacing-xxs);
373
+ }
374
+
375
+ .umds-datatable__tree-toggle {
376
+ display: inline-flex;
377
+ align-items: center;
378
+ justify-content: center;
379
+ margin: 0;
380
+ padding: 0;
381
+ border: none;
382
+ border-radius: var(--umds-primitive-border-radius-sm);
383
+ background: none;
384
+ color: var(--umds-semantic-color-neutral-dark-down);
385
+ cursor: pointer;
386
+ }
387
+
388
+ .umds-datatable__tree-toggle:hover {
389
+ background: var(--umds-semantic-color-neutral-light-medium);
390
+ color: var(--umds-semantic-color-neutral-dark-pure);
391
+ }
392
+
393
+ .umds-datatable__tree-toggle:focus-visible {
394
+ outline: 2px solid var(--umds-semantic-color-primary-pure);
395
+ outline-offset: 2px;
396
+ }
397
+
398
+ .umds-datatable--tree .umds-datatable__row:focus-visible {
399
+ outline: 2px solid var(--umds-semantic-color-primary-pure);
400
+ outline-offset: -2px;
401
+ }
402
+
236
403
  /* ── Skeleton ── */
237
404
  .umds-datatable__skeleton {
238
405
  height: 16px;
@@ -301,6 +468,13 @@
301
468
  overflow-wrap: anywhere;
302
469
  }
303
470
 
471
+ /* Compacto na tabela de documento: fonte de 12px (a menor da escala) e célula de 4px × 8px. */
472
+ .umds-datatable--document.umds-datatable--compact .umds-datatable__th,
473
+ .umds-datatable--document.umds-datatable--compact .umds-datatable__td {
474
+ padding: var(--umds-primitive-spacing-quarck) var(--umds-primitive-spacing-nano);
475
+ font-size: var(--umds-primitive-font-size-xxxs);
476
+ }
477
+
304
478
  @media print {
305
479
  .umds-datatable--document {
306
480
  overflow-x: visible;
@@ -35,7 +35,35 @@ export interface DataTableColumn {
35
35
  * @property {Array<string|number>} selectedKeys - Chaves das linhas selecionadas (controlado;
36
36
  * requer rowKey)
37
37
  * @property {string} variant - 'default' (tabela de interface) | 'document' (tabela de CONTEÚDO de documento: sem ordenação, seleção nem clique de linha, bordas finas, cabeçalho repetido e linha inteira por página na impressão)
38
- * @property {string} density - Densidade das células: 'default' | 'compact'
38
+ * @property {string} density - Densidade das células: 'default' | 'compact'. Com `variant="document"`,
39
+ * o compacto também leva a fonte a 12px (a escala do DS não tem 13px).
40
+ * @property {string} headerVariant - Cabeçalho: 'default' (claro) | 'dark' (navy, texto claro; o cabeçalho
41
+ * escuro do CrisDoc). Cores pelos tokens `background-dark` e `neutral-light-pure`, então o tema acompanha.
42
+ * @property {boolean} headerUppercase - Rótulos do cabeçalho em caixa alta. Opt-in; vale para qualquer
43
+ * `headerVariant`.
44
+ * @property {boolean} striped - Zebra: as linhas ímpares (a segunda, a quarta…) ganham o fundo claro.
45
+ * @property {Array<string|number>} selectedRowKeys - Chaves das linhas DESTACADAS (requer rowKey). Só
46
+ * destaque visual (fundo, barra à esquerda e `aria-selected`), sem checkbox: serve à linha "aberta" de
47
+ * uma lista mestre-detalhe. Não confunda com `selectedKeys`, que é a seleção por checkbox.
48
+ * @property {function} isRowSelected - Destaque por função `(row, rowIndex) => boolean`, com o mesmo
49
+ * efeito de `selectedRowKeys`. Use quando a regra não cabe numa lista de chaves.
50
+ * @property {IconProp} emptyIcon - Ícone do estado vazio (objeto Font Awesome importado). Padrão: `faInbox`.
51
+ * @property {string} emptyDescription - Texto de apoio abaixo da `emptyMessage` do estado vazio
52
+ * @property {boolean} hideHeader - Esconde o cabeçalho SÓ NA TELA: as colunas continuam nomeadas para o
53
+ * leitor de tela (a linha de cabeçalho fica visualmente oculta, não removida)
54
+ * @property {boolean} treeData - Linhas hierárquicas: cada linha pode ter filhas em `row[childrenKey]`.
55
+ * A tabela vira `role="treegrid"` (`aria-level`, `aria-posinset`, `aria-setsize`, `aria-expanded` nas
56
+ * linhas), a primeira coluna ganha recuo por nível, fios e o botão de expandir/recolher. Teclado: ↓ ↑ andam
57
+ * entre as linhas visíveis, → expande (ou desce à primeira filha), ← recolhe (ou sobe ao pai), Home e End.
58
+ * Com `treeData`, `onRowClick`, `onSelect` e os índices dos callbacks contam as linhas VISÍVEIS.
59
+ * @property {string} childrenKey - Campo com as linhas filhas. Padrão: 'children'
60
+ * @property {Array<string|number>} expandedKeys - Chaves das linhas expandidas (controlado). A chave é o
61
+ * `rowKey` da linha; sem `rowKey`, o caminho de índices ("0", "0.1")
62
+ * @property {Array<string|number>} defaultExpandedKeys - Chaves expandidas na abertura (não controlado)
63
+ * @property {boolean} defaultExpandAll - Abre a árvore toda na primeira renderização (não controlado)
64
+ * @property {function} onExpand - Callback ao expandir ou recolher: `(chavesExpandidas, linha, expandida)`
65
+ * @property {string} expandLabel - Nome acessível do botão de expandir. Troque para traduzir.
66
+ * @property {string} collapseLabel - Nome acessível do botão de recolher. Troque para traduzir.
39
67
  * @property {string} sortKey - Chave da coluna atualmente ordenada
40
68
  * @property {string} sortDirection - Direção da ordenação: 'asc' | 'desc'
41
69
  * @property {number} skeletonRows - Número de linhas skeleton exibidas no loading
@@ -54,7 +82,7 @@ export interface DataTableColumn {
54
82
  * @slot cell-<key> - Só no Vue. Célula livre da coluna `<key>`: `<template #cell-nome="{ row, value, rowIndex }">`.
55
83
  * @slot row-group - Só no Vue. Conteúdo da linha de grupo: `{ label, row, rowIndex }`.
56
84
  * @quandoUsar Dados TABULARES que se comparam coluna a coluna, com ordenação, seleção e paginação. Semântica de tabela para leitor de tela. Com `variant="document"`, a tabela que faz parte do TEXTO de um documento que se imprime (itens de nota, cotações): sem interação, com bordas finas e quebra de página que não corta linha.
57
- * @quandoNaoUsar Para hierarquia pai-filho — use `Tree`. Para cards em grade sem comparação coluna a coluna, use `Grid` com `Card`. Para pares rótulo/valor de um documento (sem cabeçalho de coluna), use `DescriptionList`.
85
+ * @quandoNaoUsar Para hierarquia pai-filho SEM colunas (navegação, seleção de pastas) — use `Tree`; com colunas de dado por linha, use `treeData`. Para cards em grade sem comparação coluna a coluna, use `Grid` com `Card`. Para pares rótulo/valor de um documento (sem cabeçalho de coluna), use `DescriptionList`.
58
86
  */
59
87
  export interface DataTableProps {
60
88
  columns: DataTableColumn[];
@@ -70,6 +98,38 @@ export interface DataTableProps {
70
98
  /** `document`: tabela de conteúdo de documento, imprimível e sem interação. @default 'default' */
71
99
  variant?: "default" | "document";
72
100
  density?: "default" | "compact";
101
+ /** `dark`: cabeçalho navy com texto claro (o do CrisDoc). @default 'default' */
102
+ headerVariant?: "default" | "dark";
103
+ /** Rótulos do cabeçalho em caixa alta. @default false */
104
+ headerUppercase?: boolean;
105
+ /** Zebra nas linhas ímpares. @default false */
106
+ striped?: boolean;
107
+ /** Chaves das linhas destacadas (só visual, sem checkbox; requer `rowKey`). */
108
+ selectedRowKeys?: Array<string | number>;
109
+ /** Destaque de linha por função `(row, rowIndex) => boolean`. */
110
+ isRowSelected?: (row: Record<string, any>, rowIndex: number) => boolean;
111
+ /** Ícone do estado vazio (objeto Font Awesome importado). @default faInbox */
112
+ emptyIcon?: IconProp;
113
+ /** Texto de apoio abaixo de `emptyMessage`. */
114
+ emptyDescription?: string;
115
+ /** Esconde o cabeçalho só na tela; o leitor de tela continua lendo as colunas. @default false */
116
+ hideHeader?: boolean;
117
+ /** Linhas hierárquicas (`role="treegrid"`), com filhas em `row[childrenKey]`. @default false */
118
+ treeData?: boolean;
119
+ /** Campo das linhas filhas. @default 'children' */
120
+ childrenKey?: string;
121
+ /** Chaves das linhas expandidas (controlado). */
122
+ expandedKeys?: Array<string | number>;
123
+ /** Chaves expandidas na abertura (não controlado). */
124
+ defaultExpandedKeys?: Array<string | number>;
125
+ /** Abre a árvore toda na abertura (não controlado). @default false */
126
+ defaultExpandAll?: boolean;
127
+ /** Ao expandir ou recolher: `(chavesExpandidas, linha, expandida)`. */
128
+ onExpand?: (expandedKeys: Array<string | number>, row: Record<string, any>, expanded: boolean) => void;
129
+ /** Nome acessível do botão de expandir. Troque para traduzir. @default 'Expandir' */
130
+ expandLabel?: string;
131
+ /** Nome acessível do botão de recolher. Troque para traduzir. @default 'Recolher' */
132
+ collapseLabel?: string;
73
133
  sortKey?: string;
74
134
  sortDirection?: "asc" | "desc";
75
135
  skeletonRows?: number;
@@ -83,5 +143,6 @@ export interface DataTableProps {
83
143
  /** Nome acessível do checkbox de cada linha. Recebe o número da linha (a partir de 1). Troque para traduzir. @default (rowNumber) => 'Selecionar linha ' + rowNumber */
84
144
  selectRowLabel?: (rowNumber: number) => string;
85
145
  }
146
+ import { IconProp } from "../Icon/Icon";
86
147
  declare function DataTable(props: DataTableProps): import("react/jsx-runtime").JSX.Element;
87
148
  export default DataTable;