@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.
- package/CHANGELOG.md +235 -0
- package/dist/components/Accordion/Accordion.d.ts +6 -0
- package/dist/components/Accordion/Accordion.js +17 -5
- package/dist/components/Badge/Badge.css +13 -4
- package/dist/components/Badge/Badge.d.ts +9 -2
- package/dist/components/Badge/Badge.js +3 -0
- package/dist/components/Button/Button.css +5 -0
- package/dist/components/Button/Button.d.ts +3 -0
- package/dist/components/Button/Button.js +1 -0
- package/dist/components/Calendar/Calendar.css +10 -0
- package/dist/components/Calendar/Calendar.d.ts +3 -0
- package/dist/components/Calendar/Calendar.js +6 -1
- package/dist/components/Coachmark/Coachmark.d.ts +2 -1
- package/dist/components/Coachmark/Coachmark.js +6 -1
- package/dist/components/CodeBlock/CodeBlock.css +3 -3
- package/dist/components/CodeBlock/CodeBlock.d.ts +2 -2
- package/dist/components/DataTable/DataTable.css +42 -0
- package/dist/components/DataTable/DataTable.d.ts +9 -2
- package/dist/components/DataTable/DataTable.js +15 -0
- package/dist/components/Input/Input.css +9 -0
- package/dist/components/Input/Input.d.ts +3 -0
- package/dist/components/Input/Input.js +1 -0
- package/dist/components/Kbd/Kbd.css +3 -3
- package/dist/components/Kbd/Kbd.d.ts +1 -1
- package/dist/components/Modal/Modal.css +19 -0
- package/dist/components/Modal/Modal.d.ts +7 -0
- package/dist/components/Modal/Modal.js +1 -0
- package/dist/components/RichTextEditor/RichTextEditor.d.ts +2 -2
- package/dist/components/RichTextEditor/RichTextEditor.js +0 -5
- package/dist/components/SegmentedControl/SegmentedControl.css +46 -0
- package/dist/components/SegmentedControl/SegmentedControl.d.ts +3 -0
- package/dist/components/SegmentedControl/SegmentedControl.js +1 -0
- package/dist/components/Select/Select.css +28 -2
- package/dist/components/Select/Select.d.ts +7 -0
- package/dist/components/Select/Select.js +55 -9
- package/dist/components/StatCard/StatCard.css +8 -0
- package/dist/components/StatCard/StatCard.d.ts +3 -0
- package/dist/components/StatCard/StatCard.js +1 -0
- package/dist/components/Tabs/Tabs.css +11 -0
- package/dist/components/Tabs/Tabs.d.ts +7 -0
- package/dist/components/Tabs/Tabs.js +7 -1
- package/dist/components/Tag/Tag.css +3 -1
- package/dist/teste/AccordionControlado.test.d.ts +1 -0
- package/dist/teste/AccordionControlado.test.js +73 -0
- package/dist/teste/BadgeAttachedTomEPadding.test.d.ts +1 -0
- package/dist/teste/BadgeAttachedTomEPadding.test.js +43 -0
- package/dist/teste/ButtonDensidade.test.d.ts +1 -0
- package/dist/teste/ButtonDensidade.test.js +28 -0
- package/dist/teste/CalendarCompacto.test.d.ts +1 -0
- package/dist/teste/CalendarCompacto.test.js +29 -0
- package/dist/teste/CoachmarkUmPasso.test.d.ts +1 -0
- package/dist/teste/CoachmarkUmPasso.test.js +34 -0
- package/dist/teste/DataTableCompactaETom.test.d.ts +1 -0
- package/dist/teste/DataTableCompactaETom.test.js +69 -0
- package/dist/teste/InputGhost.test.d.ts +1 -0
- package/dist/teste/InputGhost.test.js +32 -0
- package/dist/teste/ModalProporcoes1Doc.test.d.ts +1 -0
- package/dist/teste/ModalProporcoes1Doc.test.js +32 -0
- package/dist/teste/RichTextEditorEstiloDeTexto.test.js +7 -7
- package/dist/teste/SegmentedControlSuperficie.test.d.ts +1 -0
- package/dist/teste/SegmentedControlSuperficie.test.js +39 -0
- package/dist/teste/SelectItemComEscopo.test.d.ts +1 -0
- package/dist/teste/SelectItemComEscopo.test.js +54 -0
- package/dist/teste/SelectListaFiltro.test.d.ts +1 -0
- package/dist/teste/SelectListaFiltro.test.js +102 -0
- package/dist/teste/StatCardTamanhoSm.test.d.ts +1 -0
- package/dist/teste/StatCardTamanhoSm.test.js +32 -0
- package/dist/teste/TabsCompacta.test.d.ts +1 -0
- package/dist/teste/TabsCompacta.test.js +35 -0
- package/dist/teste/TagPositivoTingido.test.d.ts +1 -0
- package/dist/teste/TagPositivoTingido.test.js +54 -0
- package/dist/teste/lerArquivo.d.ts +1 -0
- package/dist/teste/lerArquivo.js +12 -0
- package/dist/utils/html-seguro.js +1 -1
- package/package.json +3 -3
- package/src/teste/AccordionControlado.test.tsx +87 -0
- package/src/teste/BadgeAttachedTomEPadding.test.tsx +60 -0
- package/src/teste/ButtonDensidade.test.tsx +40 -0
- package/src/teste/CalendarCompacto.test.tsx +37 -0
- package/src/teste/CoachmarkUmPasso.test.tsx +45 -0
- package/src/teste/DataTableCompactaETom.test.tsx +85 -0
- package/src/teste/InputGhost.test.tsx +42 -0
- package/src/teste/ModalProporcoes1Doc.test.tsx +36 -0
- package/src/teste/RichTextEditorEstiloDeTexto.test.tsx +8 -8
- package/src/teste/SegmentedControlSuperficie.test.tsx +52 -0
- package/src/teste/SelectItemComEscopo.test.tsx +69 -0
- package/src/teste/SelectListaFiltro.test.tsx +120 -0
- package/src/teste/StatCardTamanhoSm.test.tsx +42 -0
- package/src/teste/TabsCompacta.test.tsx +45 -0
- package/src/teste/TagPositivoTingido.test.tsx +60 -0
- package/src/teste/lerArquivo.ts +13 -0
- 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,
|
|
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-
|
|
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-
|
|
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
|
|
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
|
-
* (
|
|
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,
|
|
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:
|
|
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(" +
|
|
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
|
-
|
|
368
|
-
|
|
369
|
-
|
|
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 [
|
|
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
|
-
|
|
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 {};
|