@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.
- package/CHANGELOG.md +434 -0
- package/dist/components/Accordion/Accordion.css +13 -0
- package/dist/components/Accordion/Accordion.d.ts +3 -0
- package/dist/components/Accordion/Accordion.js +1 -0
- package/dist/components/AppSubheader/AppSubheader.css +10 -1
- package/dist/components/AttachmentCard/AttachmentCard.css +10 -8
- package/dist/components/AttachmentCard/AttachmentCard.d.ts +3 -0
- package/dist/components/AttachmentCard/AttachmentCard.js +8 -1
- package/dist/components/Badge/Badge.css +14 -1
- package/dist/components/Badge/Badge.d.ts +11 -2
- package/dist/components/Badge/Badge.js +3 -0
- package/dist/components/Calendar/Calendar.d.ts +7 -6
- package/dist/components/Coachmark/Coachmark.css +10 -0
- package/dist/components/Coachmark/Coachmark.d.ts +12 -0
- package/dist/components/Coachmark/Coachmark.js +46 -5
- package/dist/components/ColorPicker/ColorPicker.css +8 -1
- package/dist/components/ColorPicker/ColorPicker.d.ts +2 -2
- package/dist/components/DataTable/DataTable.css +174 -0
- package/dist/components/DataTable/DataTable.d.ts +63 -2
- package/dist/components/DataTable/DataTable.js +278 -6
- package/dist/components/DescriptionList/DescriptionList.css +14 -0
- package/dist/components/DescriptionList/DescriptionList.d.ts +3 -0
- package/dist/components/DescriptionList/DescriptionList.js +1 -0
- package/dist/components/EmptyState/EmptyState.d.ts +4 -2
- package/dist/components/EmptyState/EmptyState.js +2 -2
- package/dist/components/Input/Input.css +21 -0
- package/dist/components/Input/Input.d.ts +7 -0
- package/dist/components/Input/Input.js +2 -1
- package/dist/components/List/ListItem.d.ts +14 -2
- package/dist/components/List/ListItem.js +3 -2
- package/dist/components/RichTextEditor/RichTextEditor.css +47 -0
- package/dist/components/RichTextEditor/RichTextEditor.d.ts +22 -8
- package/dist/components/RichTextEditor/RichTextEditor.js +460 -3
- package/dist/components/SegmentedControl/SegmentedControl.css +24 -0
- package/dist/components/SegmentedControl/SegmentedControl.d.ts +2 -0
- package/dist/components/SegmentedControl/SegmentedControl.js +4 -1
- package/dist/components/Select/Select.css +94 -0
- package/dist/components/Select/Select.d.ts +26 -4
- package/dist/components/Select/Select.js +210 -35
- package/dist/components/StatCard/StatCard.css +65 -0
- package/dist/components/StatCard/StatCard.d.ts +9 -0
- package/dist/components/StatCard/StatCard.js +10 -1
- package/dist/components/Toast/Toast.css +32 -0
- package/dist/components/Toast/Toast.d.ts +18 -0
- package/dist/components/Toast/Toast.js +14 -1
- package/dist/components/Toast/ToastStack.js +8 -1
- package/dist/teste/AccordionTituloNeutro.test.d.ts +1 -0
- package/dist/teste/AccordionTituloNeutro.test.js +23 -0
- package/dist/teste/AppSubheaderRegiao.test.d.ts +1 -0
- package/dist/teste/AppSubheaderRegiao.test.js +13 -0
- package/dist/teste/AttachmentCardLista.test.d.ts +1 -0
- package/dist/teste/AttachmentCardLista.test.js +49 -0
- package/dist/teste/AttachmentCardSm.test.d.ts +1 -0
- package/dist/teste/AttachmentCardSm.test.js +26 -0
- package/dist/teste/BadgeNeutroColado.test.d.ts +1 -0
- package/dist/teste/BadgeNeutroColado.test.js +11 -0
- package/dist/teste/BadgeTag.test.js +13 -0
- package/dist/teste/CalendarCabecalho.test.d.ts +1 -0
- package/dist/teste/CalendarCabecalho.test.js +11 -0
- package/dist/teste/CoachmarkSemVeu.test.d.ts +1 -0
- package/dist/teste/CoachmarkSemVeu.test.js +85 -0
- package/dist/teste/ColorPickerXs.test.d.ts +1 -0
- package/dist/teste/ColorPickerXs.test.js +21 -0
- package/dist/teste/DataTableArvoreEVariantes.test.d.ts +1 -0
- package/dist/teste/DataTableArvoreEVariantes.test.js +190 -0
- package/dist/teste/DescriptionListCompacta.test.d.ts +1 -0
- package/dist/teste/DescriptionListCompacta.test.js +22 -0
- package/dist/teste/EmptyStateTituloRico.test.d.ts +1 -0
- package/dist/teste/EmptyStateTituloRico.test.js +23 -0
- package/dist/teste/InputAgrupado.test.d.ts +1 -0
- package/dist/teste/InputAgrupado.test.js +24 -0
- package/dist/teste/ListItemTooltipStandalone.test.d.ts +1 -0
- package/dist/teste/ListItemTooltipStandalone.test.js +39 -0
- package/dist/teste/RichTextEditorAlinhaImagemTabela.test.d.ts +1 -0
- package/dist/teste/RichTextEditorAlinhaImagemTabela.test.js +212 -0
- package/dist/teste/RichTextEditorEstiloDeTexto.test.d.ts +1 -0
- package/dist/teste/RichTextEditorEstiloDeTexto.test.js +120 -0
- package/dist/teste/SegmentedControlContador.test.d.ts +1 -0
- package/dist/teste/SegmentedControlContador.test.js +39 -0
- package/dist/teste/SelectAbertoControladoEFlutuante.test.d.ts +1 -0
- package/dist/teste/SelectAbertoControladoEFlutuante.test.js +145 -0
- package/dist/teste/SelectFiltroCorETamanho.test.d.ts +1 -0
- package/dist/teste/SelectFiltroCorETamanho.test.js +77 -0
- package/dist/teste/StatCardSecundariaETom.test.d.ts +1 -0
- package/dist/teste/StatCardSecundariaETom.test.js +45 -0
- package/dist/teste/ToastAcaoEDetalhes.test.d.ts +1 -0
- package/dist/teste/ToastAcaoEDetalhes.test.js +94 -0
- package/dist/utils/html-seguro.d.ts +19 -1
- package/dist/utils/html-seguro.js +113 -2
- package/dist/utils/toast.d.ts +10 -1
- package/dist/utils/toast.js +2 -1
- package/package.json +2 -2
- package/src/teste/AccordionTituloNeutro.test.tsx +25 -0
- package/src/teste/AppSubheaderRegiao.test.tsx +17 -0
- package/src/teste/AttachmentCardLista.test.tsx +53 -0
- package/src/teste/AttachmentCardSm.test.tsx +29 -0
- package/src/teste/BadgeNeutroColado.test.tsx +15 -0
- package/src/teste/BadgeTag.test.tsx +21 -0
- package/src/teste/CalendarCabecalho.test.tsx +11 -0
- package/src/teste/CoachmarkSemVeu.test.tsx +101 -0
- package/src/teste/ColorPickerXs.test.tsx +22 -0
- package/src/teste/DataTableArvoreEVariantes.test.tsx +240 -0
- package/src/teste/DescriptionListCompacta.test.tsx +24 -0
- package/src/teste/EmptyStateTituloRico.test.tsx +34 -0
- package/src/teste/InputAgrupado.test.tsx +26 -0
- package/src/teste/ListItemTooltipStandalone.test.tsx +64 -0
- package/src/teste/RichTextEditorAlinhaImagemTabela.test.tsx +238 -0
- package/src/teste/RichTextEditorEstiloDeTexto.test.tsx +137 -0
- package/src/teste/SegmentedControlContador.test.tsx +43 -0
- package/src/teste/SelectAbertoControladoEFlutuante.test.tsx +180 -0
- package/src/teste/SelectFiltroCorETamanho.test.tsx +90 -0
- package/src/teste/StatCardSecundariaETom.test.tsx +51 -0
- package/src/teste/ToastAcaoEDetalhes.test.tsx +109 -0
- package/src/utils/html-seguro.ts +105 -2
- package/src/utils/toast.ts +12 -2
|
@@ -191,10 +191,16 @@
|
|
|
191
191
|
width: 100%;
|
|
192
192
|
}
|
|
193
193
|
|
|
194
|
+
/* Fundo branco: o azul-claro do gatilho só vem depois de escolhido um valor (`--has-value`,
|
|
195
|
+
abaixo), que é quando o filtro está recortando a lista. O tamanho padrão é o sm (32px). */
|
|
194
196
|
.umds-select--filter .umds-select__trigger {
|
|
195
197
|
width: auto;
|
|
196
198
|
gap: var(--umds-primitive-spacing-nano);
|
|
197
199
|
border-color: var(--umds-semantic-color-primary-pure);
|
|
200
|
+
background-color: var(--umds-semantic-color-background-white);
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
.umds-select--filter.umds-select--has-value .umds-select__trigger {
|
|
198
204
|
background-color: var(--umds-semantic-color-primary-light);
|
|
199
205
|
}
|
|
200
206
|
|
|
@@ -212,6 +218,11 @@
|
|
|
212
218
|
font-weight: var(--umds-primitive-font-weight-semibold);
|
|
213
219
|
}
|
|
214
220
|
|
|
221
|
+
/* Fonte de 12px no filtro pequeno (o tamanho do CrisDoc); no md segue 14px. */
|
|
222
|
+
.umds-select--filter.umds-select--sm .umds-select__trigger .umds-text {
|
|
223
|
+
font-size: var(--umds-primitive-font-size-xxxs); /* 12px */
|
|
224
|
+
}
|
|
225
|
+
|
|
215
226
|
.umds-select--filter .umds-select__dropdown {
|
|
216
227
|
/* 240px: três vezes o degrau xxl (80px). Sem token de largura de menu. */
|
|
217
228
|
width: max-content;
|
|
@@ -219,6 +230,89 @@
|
|
|
219
230
|
max-width: calc(100vw - var(--umds-primitive-spacing-xxxs) * 2);
|
|
220
231
|
}
|
|
221
232
|
|
|
233
|
+
/* ── Variante search: o filtro dentro de uma barra de busca ──
|
|
234
|
+
Altura de campo e contorno neutro, para ficar ao lado do campo de busca. */
|
|
235
|
+
.umds-select--filter-search .umds-select__trigger {
|
|
236
|
+
border-color: var(--umds-semantic-field-border-default);
|
|
237
|
+
background-color: var(--umds-semantic-color-background-white);
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
.umds-select--filter-search.umds-select--has-value .umds-select__trigger {
|
|
241
|
+
background-color: var(--umds-semantic-color-background-white);
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
.umds-select--filter-search .umds-select__trigger:hover:not(.umds-select--disabled .umds-select__trigger) {
|
|
245
|
+
border-color: var(--umds-semantic-field-border-hover);
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
.umds-select--filter-search .umds-select__trigger .umds-text,
|
|
249
|
+
.umds-select--filter-search .umds-select__actions {
|
|
250
|
+
color: var(--umds-semantic-color-neutral-dark-pure);
|
|
251
|
+
font-weight: var(--umds-primitive-font-weight-regular);
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
.umds-select--filter-search .umds-select__actions {
|
|
255
|
+
color: var(--umds-semantic-color-neutral-dark-medium);
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
/* ── Variante combo: o filtro colado a outro controle ──
|
|
259
|
+
Sem contorno nem raio próprios: quem desenha a borda é o contêiner do combo. */
|
|
260
|
+
.umds-select--filter-combo .umds-select__trigger {
|
|
261
|
+
border-color: transparent;
|
|
262
|
+
border-radius: var(--umds-primitive-border-radius-none);
|
|
263
|
+
background-color: transparent;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
.umds-select--filter-combo.umds-select--has-value .umds-select__trigger {
|
|
267
|
+
background-color: transparent;
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
.umds-select--filter-combo .umds-select__trigger:hover:not(.umds-select--disabled .umds-select__trigger) {
|
|
271
|
+
border-color: transparent;
|
|
272
|
+
background-color: var(--umds-semantic-color-background-light);
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
.umds-select--filter-combo .umds-select__trigger .umds-text,
|
|
276
|
+
.umds-select--filter-combo .umds-select__actions {
|
|
277
|
+
color: var(--umds-semantic-color-neutral-dark-down);
|
|
278
|
+
font-weight: var(--umds-primitive-font-weight-regular);
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
/* O foco do combo é o anel do próprio gatilho, por dentro (o contêiner pode cortar o de fora). */
|
|
282
|
+
.umds-select--filter-combo .umds-select__trigger:focus-visible,
|
|
283
|
+
.umds-select--filter-combo.umds-select--open .umds-select__trigger {
|
|
284
|
+
border-color: transparent;
|
|
285
|
+
box-shadow: inset 0 0 0 var(--umds-primitive-border-width-thin) var(--umds-semantic-color-primary-pure);
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
/* ── Ícone e amostra de cor no gatilho (triggerIcon, triggerSwatch) ── */
|
|
289
|
+
.umds-select__trigger-icon {
|
|
290
|
+
display: inline-flex;
|
|
291
|
+
align-items: center;
|
|
292
|
+
flex-shrink: 0;
|
|
293
|
+
color: var(--umds-semantic-color-neutral-dark-medium);
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
.umds-select--filter .umds-select__trigger-icon {
|
|
297
|
+
color: inherit;
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
.umds-select__swatch {
|
|
301
|
+
flex-shrink: 0;
|
|
302
|
+
box-sizing: border-box;
|
|
303
|
+
width: var(--umds-primitive-spacing-mini);
|
|
304
|
+
height: var(--umds-primitive-spacing-mini);
|
|
305
|
+
border-radius: var(--umds-primitive-border-radius-xs);
|
|
306
|
+
/* Anel de 1px: amostra clara não some no fundo branco, nem escura no escuro. */
|
|
307
|
+
border: var(--umds-primitive-border-width-hairline) solid var(--umds-semantic-color-neutral-light-down);
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
/* ── Lista flutuante (dentro de diálogo) ──
|
|
311
|
+
O estilo inline (fixed, translate, largura e altura medidas) vem do componente. */
|
|
312
|
+
.umds-select--floating .umds-select__dropdown {
|
|
313
|
+
box-sizing: border-box;
|
|
314
|
+
}
|
|
315
|
+
|
|
222
316
|
/* ── Busca no dropdown ── */
|
|
223
317
|
.umds-select__search-container {
|
|
224
318
|
display: flex;
|
|
@@ -3,10 +3,13 @@ import './Select.css';
|
|
|
3
3
|
* Opção exibida na lista do Select.
|
|
4
4
|
* @property {string} label - Texto visível da opção.
|
|
5
5
|
* @property {any} value - Valor associado à opção.
|
|
6
|
+
* @property {string} color - Cor da opção, um token (`var(--umds-semantic-color-...)` ou `var(--umds-primitive-...)`): uma amostra de 12px antes do texto na lista e, com a opção escolhida (seleção única), no gatilho. Decorativa: o texto diz a opção. Sem a prop, nada muda.
|
|
6
7
|
*/
|
|
7
8
|
export interface SelectOption {
|
|
8
9
|
label: string;
|
|
9
10
|
value: string | number;
|
|
11
|
+
/** Cor da opção (token): amostra antes do texto, e no gatilho quando escolhida. */
|
|
12
|
+
color?: string;
|
|
10
13
|
[key: string]: any;
|
|
11
14
|
}
|
|
12
15
|
/**
|
|
@@ -40,8 +43,14 @@ export interface SelectOption {
|
|
|
40
43
|
* @property {string} ariaLabel - Nome acessível quando não há label visível.
|
|
41
44
|
* @property {string} id - ID base dos elementos internos. Gerado automaticamente se omitido.
|
|
42
45
|
* @property {function} onChange - Callback com o(s) valor(es) selecionado(s).
|
|
43
|
-
* @property {string} placement - Onde a lista abre: 'bottom' (padrão) | 'top' | 'auto'. O `auto` abre para cima quando falta espaço embaixo
|
|
44
|
-
*
|
|
46
|
+
* @property {string} placement - Onde a lista abre: 'bottom' (padrão) | 'top' | 'auto'. O `auto` mede o espaço da janela E do ancestral que rola ou corta (um corpo de modal, um painel com overflow): abre para cima quando falta espaço embaixo e há mais em cima, e limita a altura da lista ao espaço que sobra.
|
|
47
|
+
*
|
|
48
|
+
* Dentro de um diálogo (`role="dialog"` ou `aria-modal`), a lista abre por cima dele: ela passa a `position: fixed`, ancorada no gatilho pelo `@floating-ui/dom`, e não é cortada pelo `overflow` do corpo do modal.
|
|
49
|
+
* @property {string} variant - 'default' | 'filter' | 'search' | 'combo'. O `filter` é o botão de filtro de barra de ferramentas: 32px (`size="sm"` é o padrão das variantes de filtro) e fonte de 12px, fundo branco com contorno azul (azul-claro só depois de escolhido um valor), largura do conteúdo, lista mais larga que o botão, busca focada ao abrir. `search` é o mesmo filtro dentro de uma barra de busca (altura de campo, contorno neutro). `combo` é o filtro colado a outro controle (sem contorno nem raio próprios: quem desenha a borda é o contêiner). Combine com `searchable`, `emptyOptionLabel` e o slot `footer`.
|
|
50
|
+
* @property {boolean} open - Abre/fecha a lista de fora (modo controlado). Sem ela, o Select controla o próprio estado. Use com `onOpenChange`: o filtro com ação no rodapé fecha a lista antes de abrir um modal.
|
|
51
|
+
* @property {function} onOpenChange - Chamado quando a lista pede para abrir ou fechar (clique, teclado, clique fora, Esc, escolha de opção). No modo controlado, é quem decide o novo `open`.
|
|
52
|
+
* @property {IconProp} triggerIcon - Ícone à esquerda do texto do gatilho (objeto Font Awesome importado). Decorativo.
|
|
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.
|
|
45
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).
|
|
46
55
|
* @property {any} footer - Rodapé fixo da lista, com ações ("Gerenciar marcadores"). Passe o elemento correspondente (React node ou Vue slot `footer`).
|
|
47
56
|
* @quandoUsar Escolher UM valor de uma lista fechada. O valor selecionado fica visível no campo.
|
|
@@ -83,8 +92,20 @@ export interface SelectProps {
|
|
|
83
92
|
size?: "sm" | "md" | "lg";
|
|
84
93
|
/** Onde a lista abre. @default 'bottom' */
|
|
85
94
|
placement?: "bottom" | "top" | "auto";
|
|
86
|
-
/** Variante visual. @default 'default' */
|
|
87
|
-
variant?: "default" | "filter";
|
|
95
|
+
/** Variante visual. `filter`, `search` e `combo` são o filtro de barra. @default 'default' */
|
|
96
|
+
variant?: "default" | "filter" | "search" | "combo";
|
|
97
|
+
/**
|
|
98
|
+
* Abre/fecha a lista de fora (modo controlado). `any` de propósito: no Vue uma
|
|
99
|
+
* prop `boolean` sem valor chega como `false`, e `props.open !== undefined`
|
|
100
|
+
* ficaria sempre verdadeiro (o Select se acharia controlado e nunca abriria).
|
|
101
|
+
*/
|
|
102
|
+
open?: any;
|
|
103
|
+
/** Pede para abrir ou fechar a lista. No modo controlado, o pai decide o novo `open`. */
|
|
104
|
+
onOpenChange?: (open: boolean) => void;
|
|
105
|
+
/** Ícone à esquerda do texto do gatilho. */
|
|
106
|
+
triggerIcon?: IconProp;
|
|
107
|
+
/** Amostra de cor à esquerda do texto do gatilho (token de cor). */
|
|
108
|
+
triggerSwatch?: string;
|
|
88
109
|
/** Opção "sem filtro" no topo da lista (seleção única). Escolhê-la chama `onChange("")`. */
|
|
89
110
|
emptyOptionLabel?: string;
|
|
90
111
|
/** Rodapé fixo da lista (ações). React node ou slot `footer` no Vue. */
|
|
@@ -105,5 +126,6 @@ export interface SelectProps {
|
|
|
105
126
|
ariaLabel?: string;
|
|
106
127
|
className?: string;
|
|
107
128
|
}
|
|
129
|
+
import { IconProp } from "../Icon/Icon";
|
|
108
130
|
declare function Select(props: SelectProps): import("react/jsx-runtime").JSX.Element;
|
|
109
131
|
export default Select;
|
|
@@ -3,6 +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
7
|
import Text from "../Text/Text";
|
|
7
8
|
import Icon from "../Icon/Icon";
|
|
8
9
|
import Spinner from "../Spinner/Spinner";
|
|
@@ -15,6 +16,10 @@ function Select(props) {
|
|
|
15
16
|
const searchInputRef = useRef(null);
|
|
16
17
|
const outsideWatcherRef = useRef(null);
|
|
17
18
|
const searchTimeoutRef = useRef(null);
|
|
19
|
+
const dropdownRef = useRef(null);
|
|
20
|
+
const floatCleanupRef = useRef(null);
|
|
21
|
+
const latestOpenRef = useRef(false);
|
|
22
|
+
const latestOpenChangeRef = useRef(null);
|
|
18
23
|
function textoDeApoio() {
|
|
19
24
|
return props.helperText || props.description || "";
|
|
20
25
|
}
|
|
@@ -25,6 +30,14 @@ function Select(props) {
|
|
|
25
30
|
return props.readOnly ? "true" : undefined;
|
|
26
31
|
}
|
|
27
32
|
const [isOpen, setIsOpen] = useState(() => false);
|
|
33
|
+
const [prepared, setPrepared] = useState(() => false);
|
|
34
|
+
const [floatMode, setFloatMode] = useState(() => false);
|
|
35
|
+
const [floatReady, setFloatReady] = useState(() => false);
|
|
36
|
+
const [floatX, setFloatX] = useState(() => 0);
|
|
37
|
+
const [floatY, setFloatY] = useState(() => 0);
|
|
38
|
+
const [floatW, setFloatW] = useState(() => 0);
|
|
39
|
+
const [floatMaxH, setFloatMaxH] = useState(() => 0);
|
|
40
|
+
const [listMaxH, setListMaxH] = useState(() => 0);
|
|
28
41
|
const [searchTerm, setSearchTerm] = useState(() => "");
|
|
29
42
|
const [internalSelected, setInternalSelected] = useState(() => Array.isArray(props.defaultValue)
|
|
30
43
|
? props.defaultValue
|
|
@@ -36,6 +49,24 @@ function Select(props) {
|
|
|
36
49
|
const [shouldFocusTrigger, setShouldFocusTrigger] = useState(() => false);
|
|
37
50
|
const [activeIndex, setActiveIndex] = useState(() => -1);
|
|
38
51
|
const [uid, setUid] = useState(() => "");
|
|
52
|
+
function opened() {
|
|
53
|
+
if (props.open !== undefined)
|
|
54
|
+
return props.open === "" ? true : !!props.open;
|
|
55
|
+
return isOpen;
|
|
56
|
+
}
|
|
57
|
+
function isFilter() {
|
|
58
|
+
return (props.variant === "filter" ||
|
|
59
|
+
props.variant === "search" ||
|
|
60
|
+
props.variant === "combo");
|
|
61
|
+
}
|
|
62
|
+
function setOpen(next) {
|
|
63
|
+
if (next === opened())
|
|
64
|
+
return;
|
|
65
|
+
if (props.open === undefined)
|
|
66
|
+
setIsOpen(next);
|
|
67
|
+
if (props.onOpenChange)
|
|
68
|
+
props.onOpenChange(next);
|
|
69
|
+
}
|
|
39
70
|
function baseId() {
|
|
40
71
|
return props.id || uid;
|
|
41
72
|
}
|
|
@@ -48,6 +79,9 @@ function Select(props) {
|
|
|
48
79
|
function isInvalid() {
|
|
49
80
|
return !!props.invalid || !!props.errorMessage;
|
|
50
81
|
}
|
|
82
|
+
function ariaRequiredText() {
|
|
83
|
+
return props.required ? "true" : undefined;
|
|
84
|
+
}
|
|
51
85
|
function ariaInvalidText() {
|
|
52
86
|
return isInvalid() ? "true" : undefined;
|
|
53
87
|
}
|
|
@@ -116,6 +150,14 @@ function Select(props) {
|
|
|
116
150
|
}
|
|
117
151
|
return String(currentVal[0]);
|
|
118
152
|
}
|
|
153
|
+
function triggerSwatchColor() {
|
|
154
|
+
if (props.triggerSwatch)
|
|
155
|
+
return props.triggerSwatch;
|
|
156
|
+
if (props.multiple || isPlaceholder())
|
|
157
|
+
return undefined;
|
|
158
|
+
const escolhida = selectedOptionsList()[0];
|
|
159
|
+
return escolhida ? escolhida.color : undefined;
|
|
160
|
+
}
|
|
119
161
|
function isPlaceholder() {
|
|
120
162
|
const currentVal = props.value !== undefined
|
|
121
163
|
? Array.isArray(props.value)
|
|
@@ -162,14 +204,19 @@ function Select(props) {
|
|
|
162
204
|
function wrapperClassesList() {
|
|
163
205
|
return [
|
|
164
206
|
"umds-select",
|
|
165
|
-
`umds-select--${props.size || "md"}`,
|
|
207
|
+
`umds-select--${props.size || (isFilter() ? "sm" : "md")}`,
|
|
208
|
+
isFilter() && !isPlaceholder() ? "umds-select--has-value" : "",
|
|
166
209
|
props.fullWidth ? "umds-select--full-width" : "",
|
|
167
210
|
props.disabled ? "umds-select--disabled" : "",
|
|
168
211
|
props.readOnly ? "umds-select--readonly" : "",
|
|
169
212
|
props.invalid ? "umds-select--invalid" : "",
|
|
170
|
-
|
|
213
|
+
opened() ? "umds-select--open" : "",
|
|
171
214
|
props.searchVariant === "inline" ? "umds-select--search-inline" : "",
|
|
172
|
-
|
|
215
|
+
isFilter() ? "umds-select--filter" : "",
|
|
216
|
+
props.variant === "search" ? "umds-select--filter-search" : "",
|
|
217
|
+
props.variant === "combo" ? "umds-select--filter-combo" : "",
|
|
218
|
+
opened() && floatMode ? "umds-select--floating" : "",
|
|
219
|
+
props.triggerIcon ? "umds-select--has-trigger-icon" : "",
|
|
173
220
|
opensUp && props.searchVariant !== "inline"
|
|
174
221
|
? "umds-select--placement-top"
|
|
175
222
|
: "",
|
|
@@ -198,7 +245,7 @@ function Select(props) {
|
|
|
198
245
|
return props.label && !baseId() ? props.label : undefined;
|
|
199
246
|
}
|
|
200
247
|
function activeDescendantText() {
|
|
201
|
-
if (!
|
|
248
|
+
if (!opened() || activeIndex < 0 || !baseId())
|
|
202
249
|
return undefined;
|
|
203
250
|
return baseId() + "-option-" + activeIndex;
|
|
204
251
|
}
|
|
@@ -208,8 +255,18 @@ function Select(props) {
|
|
|
208
255
|
function removeItemAriaLabelText(label) {
|
|
209
256
|
return (props.removeAriaLabel || "Remover") + " " + label;
|
|
210
257
|
}
|
|
211
|
-
function
|
|
258
|
+
function insideDialog() {
|
|
259
|
+
if (typeof document === "undefined" ||
|
|
260
|
+
!triggerRef.current ||
|
|
261
|
+
props.searchVariant === "inline")
|
|
262
|
+
return false;
|
|
263
|
+
if (typeof triggerRef.current.closest !== "function")
|
|
264
|
+
return false;
|
|
265
|
+
return !!triggerRef.current.closest('[role="dialog"], [aria-modal="true"]');
|
|
266
|
+
}
|
|
267
|
+
function shouldOpenUp(flutuante) {
|
|
212
268
|
const pedido = props.placement || "bottom";
|
|
269
|
+
setListMaxH(0);
|
|
213
270
|
if (pedido === "top")
|
|
214
271
|
return true;
|
|
215
272
|
if (pedido !== "auto")
|
|
@@ -217,32 +274,114 @@ function Select(props) {
|
|
|
217
274
|
if (typeof window === "undefined" || !triggerRef.current)
|
|
218
275
|
return false;
|
|
219
276
|
const caixa = triggerRef.current.getBoundingClientRect();
|
|
220
|
-
|
|
221
|
-
|
|
277
|
+
let topo = 0;
|
|
278
|
+
let base = window.innerHeight;
|
|
279
|
+
if (!flutuante) {
|
|
280
|
+
let pai = triggerRef.current.parentElement;
|
|
281
|
+
while (pai && pai !== document.body) {
|
|
282
|
+
const corte = window.getComputedStyle(pai).overflowY;
|
|
283
|
+
if (corte === "auto" ||
|
|
284
|
+
corte === "scroll" ||
|
|
285
|
+
corte === "hidden" ||
|
|
286
|
+
corte === "clip") {
|
|
287
|
+
const area = pai.getBoundingClientRect();
|
|
288
|
+
topo = Math.max(topo, area.top);
|
|
289
|
+
base = Math.min(base, area.bottom);
|
|
290
|
+
}
|
|
291
|
+
pai = pai.parentElement;
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
const abaixo = base - caixa.bottom;
|
|
295
|
+
const acima = caixa.top - topo;
|
|
222
296
|
const opcoes = filteredOptionsList().length;
|
|
223
297
|
const estimada = Math.min(300, opcoes * 36 + 8 + (props.searchable ? 44 : 0) + (props.footer ? 44 : 0));
|
|
224
|
-
|
|
298
|
+
const sobe = abaixo < estimada && acima > abaixo;
|
|
299
|
+
const espaco = (sobe ? acima : abaixo) - 8;
|
|
300
|
+
if (espaco < 300)
|
|
301
|
+
setListMaxH(Math.max(96, Math.floor(espaco)));
|
|
302
|
+
return sobe;
|
|
303
|
+
}
|
|
304
|
+
function prepareOpen() {
|
|
305
|
+
setPrepared(true);
|
|
306
|
+
// Local: no React gerado o setState é assíncrono e o estado leria STALE.
|
|
307
|
+
const flutuante = insideDialog();
|
|
308
|
+
setFloatMode(flutuante);
|
|
309
|
+
setFloatReady(false);
|
|
310
|
+
setOpensUp(shouldOpenUp(flutuante));
|
|
311
|
+
// Abre com a opção já selecionada ativa (padrão combobox).
|
|
312
|
+
setActiveIndex(filteredOptionsList().findIndex((opt) => isOptionSelected(opt.value)));
|
|
313
|
+
if (props.searchable &&
|
|
314
|
+
(props.autoFocusSearch || props.searchVariant === "inline" || isFilter())) {
|
|
315
|
+
setShouldFocusSearch(true);
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
function updateFloat() {
|
|
319
|
+
if (!triggerRef.current || !dropdownRef.current)
|
|
320
|
+
return;
|
|
321
|
+
computePosition(triggerRef.current, dropdownRef.current, {
|
|
322
|
+
strategy: "fixed",
|
|
323
|
+
placement: opensUp ? "top-start" : "bottom-start",
|
|
324
|
+
middleware: [
|
|
325
|
+
offset(4),
|
|
326
|
+
flip({
|
|
327
|
+
fallbackStrategy: "bestFit",
|
|
328
|
+
}),
|
|
329
|
+
size({
|
|
330
|
+
apply({ availableHeight, rects }) {
|
|
331
|
+
setFloatW(rects.reference.width);
|
|
332
|
+
setFloatMaxH(Math.max(96, Math.min(300, Math.floor(availableHeight - 8))));
|
|
333
|
+
},
|
|
334
|
+
}),
|
|
335
|
+
],
|
|
336
|
+
}).then((posicao) => {
|
|
337
|
+
setFloatX(Math.round(posicao.x));
|
|
338
|
+
setFloatY(Math.round(posicao.y));
|
|
339
|
+
setFloatReady(true);
|
|
340
|
+
});
|
|
341
|
+
}
|
|
342
|
+
function dropdownStyle() {
|
|
343
|
+
if (props.searchVariant === "inline")
|
|
344
|
+
return {
|
|
345
|
+
top: "0",
|
|
346
|
+
};
|
|
347
|
+
if (opened() && floatMode) {
|
|
348
|
+
const estilo = {
|
|
349
|
+
position: "fixed",
|
|
350
|
+
top: "0",
|
|
351
|
+
left: "0",
|
|
352
|
+
bottom: "auto",
|
|
353
|
+
transform: "translate(" + floatX + "px, " + floatY + "px)",
|
|
354
|
+
visibility: floatReady ? "visible" : "hidden",
|
|
355
|
+
};
|
|
356
|
+
if (isFilter()) {
|
|
357
|
+
estilo.minWidth =
|
|
358
|
+
"max(" + floatW + "px, calc(var(--umds-primitive-spacing-xxl) * 3))";
|
|
359
|
+
}
|
|
360
|
+
else {
|
|
361
|
+
estilo.width = floatW + "px";
|
|
362
|
+
}
|
|
363
|
+
if (floatMaxH)
|
|
364
|
+
estilo.maxHeight = floatMaxH + "px";
|
|
365
|
+
return estilo;
|
|
366
|
+
}
|
|
367
|
+
return listMaxH
|
|
368
|
+
? {
|
|
369
|
+
maxHeight: listMaxH + "px",
|
|
370
|
+
}
|
|
371
|
+
: {};
|
|
225
372
|
}
|
|
226
373
|
function toggle() {
|
|
227
374
|
if (props.disabled || props.readOnly)
|
|
228
375
|
return;
|
|
229
|
-
//
|
|
230
|
-
//
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
setIsOpen(next);
|
|
376
|
+
// Decide pela variável local: no React gerado o setState é assíncrono e
|
|
377
|
+
// ler o estado logo após atribuí-lo vem STALE.
|
|
378
|
+
const next = !opened();
|
|
379
|
+
setOpen(next);
|
|
234
380
|
if (next) {
|
|
235
|
-
|
|
236
|
-
// Abre com a opção já selecionada ativa (padrão combobox).
|
|
237
|
-
setActiveIndex(filteredOptionsList().findIndex((opt) => isOptionSelected(opt.value)));
|
|
238
|
-
if (props.searchable &&
|
|
239
|
-
(props.autoFocusSearch ||
|
|
240
|
-
props.searchVariant === "inline" ||
|
|
241
|
-
props.variant === "filter")) {
|
|
242
|
-
setShouldFocusSearch(true);
|
|
243
|
-
}
|
|
381
|
+
prepareOpen();
|
|
244
382
|
}
|
|
245
383
|
else {
|
|
384
|
+
setPrepared(false);
|
|
246
385
|
setActiveIndex(-1);
|
|
247
386
|
}
|
|
248
387
|
}
|
|
@@ -275,7 +414,8 @@ function Select(props) {
|
|
|
275
414
|
}
|
|
276
415
|
}
|
|
277
416
|
function closeSearch() {
|
|
278
|
-
|
|
417
|
+
setOpen(false);
|
|
418
|
+
setPrepared(false);
|
|
279
419
|
setSearchTerm("");
|
|
280
420
|
setActiveIndex(-1);
|
|
281
421
|
if (props.onSearchChange) {
|
|
@@ -298,7 +438,7 @@ function Select(props) {
|
|
|
298
438
|
return;
|
|
299
439
|
const key = event.key;
|
|
300
440
|
if (key === "Escape") {
|
|
301
|
-
if (
|
|
441
|
+
if (opened()) {
|
|
302
442
|
event.preventDefault();
|
|
303
443
|
closeSearch();
|
|
304
444
|
}
|
|
@@ -311,7 +451,7 @@ function Select(props) {
|
|
|
311
451
|
return;
|
|
312
452
|
}
|
|
313
453
|
event.preventDefault();
|
|
314
|
-
if (!
|
|
454
|
+
if (!opened()) {
|
|
315
455
|
toggle();
|
|
316
456
|
return;
|
|
317
457
|
}
|
|
@@ -377,7 +517,8 @@ function Select(props) {
|
|
|
377
517
|
else {
|
|
378
518
|
newValue = option.value;
|
|
379
519
|
setInternalSelected([newValue]);
|
|
380
|
-
|
|
520
|
+
setOpen(false);
|
|
521
|
+
setPrepared(false);
|
|
381
522
|
setActiveIndex(-1);
|
|
382
523
|
}
|
|
383
524
|
if (props.onChange) {
|
|
@@ -428,12 +569,22 @@ function Select(props) {
|
|
|
428
569
|
useEffect(() => {
|
|
429
570
|
if (!props.id)
|
|
430
571
|
setUid(gerarId("umds-select"));
|
|
572
|
+
// No Vue o onUpdate só roda depois de uma atualização: a lista que já nasce
|
|
573
|
+
// aberta (open controlado) é preparada aqui.
|
|
574
|
+
latestOpenRef.current = opened();
|
|
575
|
+
latestOpenChangeRef.current = props.onOpenChange;
|
|
576
|
+
if (opened() && !prepared)
|
|
577
|
+
prepareOpen();
|
|
431
578
|
if (typeof document === "undefined")
|
|
432
579
|
return;
|
|
433
580
|
const handleClickOutside = (event) => {
|
|
434
581
|
if (selectRef.current &&
|
|
435
582
|
!selectRef.current.contains(event.target)) {
|
|
583
|
+
// Só avisa quando a lista está aberta: o ouvinte vive no document inteiro.
|
|
584
|
+
if (latestOpenRef.current && latestOpenChangeRef.current)
|
|
585
|
+
latestOpenChangeRef.current(false);
|
|
436
586
|
setIsOpen(false);
|
|
587
|
+
setPrepared(false);
|
|
437
588
|
setActiveIndex(-1);
|
|
438
589
|
}
|
|
439
590
|
};
|
|
@@ -441,7 +592,27 @@ function Select(props) {
|
|
|
441
592
|
document.addEventListener("mousedown", handleClickOutside);
|
|
442
593
|
}, []);
|
|
443
594
|
useEffect(() => {
|
|
444
|
-
|
|
595
|
+
// Guarda o estado visto neste render para o ouvinte de clique fora.
|
|
596
|
+
latestOpenRef.current = opened();
|
|
597
|
+
latestOpenChangeRef.current = props.onOpenChange;
|
|
598
|
+
// Aberta de fora (open controlado): aplica os efeitos de abrir uma vez.
|
|
599
|
+
if (opened() && !prepared)
|
|
600
|
+
prepareOpen();
|
|
601
|
+
if (!opened() && prepared)
|
|
602
|
+
setPrepared(false);
|
|
603
|
+
// Lista flutuante: segue o gatilho (scroll, resize) enquanto aberta.
|
|
604
|
+
if (opened() &&
|
|
605
|
+
floatMode &&
|
|
606
|
+
triggerRef.current &&
|
|
607
|
+
dropdownRef.current &&
|
|
608
|
+
!floatCleanupRef.current) {
|
|
609
|
+
floatCleanupRef.current = autoUpdate(triggerRef.current, dropdownRef.current, () => updateFloat());
|
|
610
|
+
}
|
|
611
|
+
if ((!opened() || !floatMode) && floatCleanupRef.current) {
|
|
612
|
+
floatCleanupRef.current();
|
|
613
|
+
floatCleanupRef.current = null;
|
|
614
|
+
}
|
|
615
|
+
if (opened() && shouldFocusSearch) {
|
|
445
616
|
// Retry a few times if ref is not yet ready (though onUpdate usually implies rendered)
|
|
446
617
|
// We use a small timeout to ensure browser paints or simply check ref
|
|
447
618
|
if (searchInputRef.current) {
|
|
@@ -450,7 +621,7 @@ function Select(props) {
|
|
|
450
621
|
}
|
|
451
622
|
}
|
|
452
623
|
// Devolve o foco ao trigger após fechar por Esc/seleção via teclado.
|
|
453
|
-
if (!
|
|
624
|
+
if (!opened() && shouldFocusTrigger) {
|
|
454
625
|
if (triggerRef.current) {
|
|
455
626
|
triggerRef.current.focus();
|
|
456
627
|
setShouldFocusTrigger(false);
|
|
@@ -459,6 +630,10 @@ function Select(props) {
|
|
|
459
630
|
});
|
|
460
631
|
useEffect(() => {
|
|
461
632
|
return () => {
|
|
633
|
+
if (floatCleanupRef.current) {
|
|
634
|
+
floatCleanupRef.current();
|
|
635
|
+
floatCleanupRef.current = null;
|
|
636
|
+
}
|
|
462
637
|
// Cancela o debounce pendente da busca — evita callback após unmount.
|
|
463
638
|
if (searchTimeoutRef.current) {
|
|
464
639
|
clearTimeout(searchTimeoutRef.current);
|
|
@@ -472,13 +647,11 @@ function Select(props) {
|
|
|
472
647
|
}
|
|
473
648
|
};
|
|
474
649
|
}, []);
|
|
475
|
-
return (_jsxs("div", { ref: selectRef, className: wrapperClassesList(), children: [props.label ? (_jsxs(Text, { as: "label", variant: "label", className: "umds-select__label", id: labelIdText(), children: [props.label, props.required ? (_jsx("span", { className: "umds-select__required", children: " *" })) : null] })) : null, _jsxs("div", { className: "umds-select__container", children: [!(
|
|
650
|
+
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
|
+
background: triggerSwatchColor(),
|
|
652
|
+
} })) : null, displayLabelText() ? (_jsx(Text, { as: "span", variant: "body2", className: isPlaceholder() ? "umds-select__placeholder" : "", children: displayLabelText() })) : null, props.multiple &&
|
|
476
653
|
props.selectionDisplay === "tags" &&
|
|
477
|
-
selectedOptionsList().length > 0 ? (_jsx("div", { className: "umds-select__tags", children: selectedOptionsList()?.map((opt) => (_jsx(Tag, { size: "sm", label: opt.label, closable: true, disabled: props.disabled, onClose: (e) => removeValue(opt.value, e) }, opt.value))) })) : null] }), _jsxs("div", { className: "umds-select__actions", children: [props.loading ? _jsx(Spinner, { size: "sm", variant: "secondary" }) : null, _jsx("div", { className: "umds-select__arrow", children: _jsx(Icon, { size: "sm", icon:
|
|
478
|
-
? {
|
|
479
|
-
top: "0",
|
|
480
|
-
}
|
|
481
|
-
: {}, 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: [
|
|
654
|
+
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: [
|
|
482
655
|
"umds-select__option",
|
|
483
656
|
isOptionSelected(option.value)
|
|
484
657
|
? "umds-select__option--selected"
|
|
@@ -486,7 +659,9 @@ function Select(props) {
|
|
|
486
659
|
index === activeIndex ? "umds-select__option--active" : "",
|
|
487
660
|
]
|
|
488
661
|
.filter(Boolean)
|
|
489
|
-
.join(" "), children: [props.multiple ? (_jsx("div", { className: "umds-select__option-checkbox", children: _jsx(Checkbox, { checked: isOptionSelected(option.value), decorative: true }) })) : null,
|
|
662
|
+
.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
|
+
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 &&
|
|
490
665
|
props.selectionDisplay === "list" &&
|
|
491
666
|
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] }));
|
|
492
667
|
}
|
|
@@ -225,3 +225,68 @@
|
|
|
225
225
|
.umds-stat-card--rotulo-topo:not(:has(.umds-stat-card__icone)) .umds-stat-card__valor {
|
|
226
226
|
grid-column: 1 / -1;
|
|
227
227
|
}
|
|
228
|
+
|
|
229
|
+
/* ── valueTone: cor do número principal (variantes escuras: contraste AA no branco) ── */
|
|
230
|
+
.umds-stat-card--valor-primary .umds-stat-card__valor {
|
|
231
|
+
color: var(--umds-semantic-color-primary-pure);
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
.umds-stat-card--valor-positive .umds-stat-card__valor {
|
|
235
|
+
color: var(--umds-semantic-color-feedback-positive-dark);
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
.umds-stat-card--valor-negative .umds-stat-card__valor {
|
|
239
|
+
color: var(--umds-semantic-color-feedback-negative-dark);
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
.umds-stat-card--valor-info .umds-stat-card__valor {
|
|
243
|
+
color: var(--umds-semantic-color-feedback-info-dark);
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
/* ── Segunda medida (secondaryValue, secondaryLabel) ──
|
|
247
|
+
Menor, à direita da principal, separada por um filete. Vem depois do corpo no HTML. */
|
|
248
|
+
.umds-stat-card__secundaria {
|
|
249
|
+
display: flex;
|
|
250
|
+
flex-direction: column;
|
|
251
|
+
gap: var(--umds-primitive-spacing-micro);
|
|
252
|
+
margin-left: auto;
|
|
253
|
+
padding-left: var(--umds-primitive-spacing-xxxs);
|
|
254
|
+
border-left: var(--umds-primitive-border-width-hairline) solid var(--umds-semantic-color-neutral-light-medium);
|
|
255
|
+
text-align: right;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
.umds-stat-card--centro .umds-stat-card__secundaria {
|
|
259
|
+
margin-left: 0;
|
|
260
|
+
padding-left: 0;
|
|
261
|
+
border-left: none;
|
|
262
|
+
align-items: center;
|
|
263
|
+
text-align: center;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
.umds-stat-card__valor-secundario {
|
|
267
|
+
font-size: var(--umds-primitive-font-size-sm); /* 20px */
|
|
268
|
+
font-weight: var(--umds-primitive-font-weight-bold);
|
|
269
|
+
line-height: 1.15;
|
|
270
|
+
font-variant-numeric: tabular-nums;
|
|
271
|
+
color: var(--umds-semantic-color-neutral-dark-down);
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
.umds-stat-card__rotulo-secundario {
|
|
275
|
+
font-size: var(--umds-primitive-font-size-xxxs);
|
|
276
|
+
color: var(--umds-semantic-color-neutral-dark-down);
|
|
277
|
+
line-height: 1.4;
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
/* Com o rótulo no topo a grade ganha uma terceira coluna para a segunda medida. */
|
|
281
|
+
.umds-stat-card--rotulo-topo.umds-stat-card--com-secundaria {
|
|
282
|
+
grid-template-columns: auto 1fr auto;
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
.umds-stat-card--rotulo-topo .umds-stat-card__secundaria {
|
|
286
|
+
grid-column: 3;
|
|
287
|
+
grid-row: 2;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
.umds-stat-card--rotulo-topo.umds-stat-card--com-secundaria:not(:has(.umds-stat-card__icone)) .umds-stat-card__valor {
|
|
291
|
+
grid-column: 1 / 3;
|
|
292
|
+
}
|