@1doc/1ds-react 2.8.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 +1540 -0
- package/dist/components/AILabel/AILabel.js +1 -1
- package/dist/components/Accordion/Accordion.css +13 -0
- package/dist/components/Accordion/Accordion.d.ts +9 -2
- package/dist/components/Accordion/Accordion.js +1 -0
- package/dist/components/AppSubheader/AppSubheader.css +10 -1
- package/dist/components/AttachmentCard/AttachmentCard.css +26 -8
- package/dist/components/AttachmentCard/AttachmentCard.d.ts +22 -2
- package/dist/components/AttachmentCard/AttachmentCard.js +47 -3
- package/dist/components/Avatar/Avatar.css +7 -2
- package/dist/components/Avatar/AvatarGroup.d.ts +17 -0
- package/dist/components/Avatar/AvatarGroup.js +22 -8
- package/dist/components/Badge/Badge.css +67 -2
- package/dist/components/Badge/Badge.d.ts +23 -4
- package/dist/components/Badge/Badge.js +4 -0
- package/dist/components/Box/Box.css +83 -0
- package/dist/components/Box/Box.d.ts +82 -2
- package/dist/components/Box/Box.js +42 -2
- package/dist/components/Button/Button.css +29 -0
- package/dist/components/Button/Button.d.ts +4 -4
- package/dist/components/Button/Button.js +4 -1
- package/dist/components/Calendar/Calendar.css +245 -0
- package/dist/components/Calendar/Calendar.d.ts +126 -0
- package/dist/components/Calendar/Calendar.js +320 -0
- package/dist/components/Chips/Chips.css +38 -0
- package/dist/components/Chips/Chips.d.ts +5 -2
- package/dist/components/Chips/Chips.js +2 -1
- package/dist/components/Coachmark/Coachmark.css +128 -0
- package/dist/components/Coachmark/Coachmark.d.ts +87 -0
- package/dist/components/Coachmark/Coachmark.js +362 -0
- package/dist/components/CodeBlock/CodeBlock.css +96 -0
- package/dist/components/CodeBlock/CodeBlock.d.ts +47 -0
- package/dist/components/CodeBlock/CodeBlock.js +103 -0
- package/dist/components/ColorPicker/ColorPicker.css +140 -0
- package/dist/components/ColorPicker/ColorPicker.d.ts +73 -0
- package/dist/components/ColorPicker/ColorPicker.js +219 -0
- package/dist/components/Combobox/Combobox.css +8 -0
- package/dist/components/DataTable/DataTable.css +254 -0
- package/dist/components/DataTable/DataTable.d.ts +81 -5
- package/dist/components/DataTable/DataTable.js +335 -19
- package/dist/components/DatePicker/DatePicker.css +8 -0
- package/dist/components/DatePicker/DatePicker.js +10 -1
- package/dist/components/DescriptionList/DescriptionList.css +127 -0
- package/dist/components/DescriptionList/DescriptionList.d.ts +62 -0
- package/dist/components/DescriptionList/DescriptionList.js +52 -0
- package/dist/components/EmptyState/EmptyState.d.ts +4 -2
- package/dist/components/EmptyState/EmptyState.js +2 -2
- package/dist/components/FileInput/FileInput.css +16 -0
- package/dist/components/FileInput/FileInput.d.ts +4 -2
- package/dist/components/FileInput/FileInput.js +8 -2
- package/dist/components/Grid/Grid.js +5 -5
- package/dist/components/IconPicker/IconPicker.css +107 -0
- package/dist/components/IconPicker/IconPicker.d.ts +74 -0
- package/dist/components/IconPicker/IconPicker.js +194 -0
- package/dist/components/Input/Input.css +59 -0
- package/dist/components/Input/Input.d.ts +17 -1
- package/dist/components/Input/Input.js +67 -5
- package/dist/components/Kanban/Kanban.css +4 -0
- package/dist/components/Kbd/Kbd.css +66 -0
- package/dist/components/Kbd/Kbd.d.ts +32 -0
- package/dist/components/Kbd/Kbd.js +40 -0
- package/dist/components/List/List.css +136 -0
- package/dist/components/List/List.d.ts +82 -0
- package/dist/components/List/List.js +53 -0
- package/dist/components/List/ListItem.d.ts +97 -0
- package/dist/components/List/ListItem.js +82 -0
- package/dist/components/Modal/Modal.css +80 -0
- package/dist/components/Modal/Modal.d.ts +33 -6
- package/dist/components/Modal/Modal.js +101 -6
- package/dist/components/MultiSelect/MultiSelect.css +8 -0
- package/dist/components/MultiSelect/MultiSelect.js +10 -1
- package/dist/components/OrgChart/OrgChart.css +149 -0
- package/dist/components/OrgChart/OrgChart.d.ts +83 -0
- package/dist/components/OrgChart/OrgChart.js +297 -0
- package/dist/components/OtpInput/OtpInput.css +93 -0
- package/dist/components/OtpInput/OtpInput.d.ts +60 -0
- package/dist/components/OtpInput/OtpInput.js +215 -0
- package/dist/components/PhoneInput/PhoneInput.css +8 -0
- package/dist/components/Popover/Popover.d.ts +7 -0
- package/dist/components/Popover/Popover.js +11 -1
- package/dist/components/RichTextEditor/RichTextEditor.css +250 -0
- package/dist/components/RichTextEditor/RichTextEditor.d.ts +97 -0
- package/dist/components/RichTextEditor/RichTextEditor.js +951 -0
- package/dist/components/SegmentedControl/SegmentedControl.css +24 -0
- package/dist/components/SegmentedControl/SegmentedControl.d.ts +2 -0
- package/dist/components/SegmentedControl/SegmentedControl.js +10 -2
- package/dist/components/Select/Select.css +164 -0
- package/dist/components/Select/Select.d.ts +34 -0
- package/dist/components/Select/Select.js +258 -28
- package/dist/components/Stack/Stack.css +49 -0
- package/dist/components/Stack/Stack.d.ts +65 -7
- package/dist/components/Stack/Stack.js +30 -2
- package/dist/components/StatCard/StatCard.css +138 -0
- package/dist/components/StatCard/StatCard.d.ts +26 -0
- package/dist/components/StatCard/StatCard.js +13 -1
- package/dist/components/Tabs/Tab.d.ts +15 -0
- package/dist/components/Tabs/Tab.js +30 -1
- package/dist/components/Tabs/Tabs.css +132 -0
- package/dist/components/Tabs/Tabs.d.ts +7 -0
- package/dist/components/Tabs/Tabs.js +13 -2
- package/dist/components/Tag/Tag.css +85 -2
- package/dist/components/Tag/Tag.d.ts +13 -6
- package/dist/components/Tag/Tag.js +1 -0
- package/dist/components/Text/Text.js +2 -2
- package/dist/components/Textarea/Textarea.css +8 -0
- package/dist/components/TimePicker/TimePicker.css +8 -0
- 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/components/Tooltip/Tooltip.css +25 -0
- package/dist/components/Tooltip/Tooltip.d.ts +11 -0
- package/dist/components/Tooltip/Tooltip.js +18 -3
- package/dist/index.d.ts +25 -0
- package/dist/index.js +14 -0
- package/dist/teste/AILabel.test.d.ts +1 -0
- package/dist/teste/AILabel.test.js +33 -0
- package/dist/teste/AccordionConteudoLivre.test.d.ts +1 -0
- package/dist/teste/AccordionConteudoLivre.test.js +29 -0
- 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/AtributosRepassados.test.d.ts +1 -0
- package/dist/teste/AtributosRepassados.test.js +52 -0
- package/dist/teste/AttachmentCardIA.test.d.ts +1 -0
- package/dist/teste/AttachmentCardIA.test.js +89 -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/AvatarGroupOverlap.test.d.ts +1 -0
- package/dist/teste/AvatarGroupOverlap.test.js +56 -0
- package/dist/teste/BadgeNeutroColado.test.d.ts +1 -0
- package/dist/teste/BadgeNeutroColado.test.js +11 -0
- package/dist/teste/BadgeTag.test.d.ts +1 -0
- package/dist/teste/BadgeTag.test.js +55 -0
- package/dist/teste/BoxItemFlex.test.d.ts +1 -0
- package/dist/teste/BoxItemFlex.test.js +54 -0
- package/dist/teste/BoxLayout.test.d.ts +1 -0
- package/dist/teste/BoxLayout.test.js +35 -0
- package/dist/teste/Button.test.d.ts +1 -0
- package/dist/teste/Button.test.js +27 -0
- package/dist/teste/Calendar.test.d.ts +1 -0
- package/dist/teste/Calendar.test.js +221 -0
- package/dist/teste/CalendarCabecalho.test.d.ts +1 -0
- package/dist/teste/CalendarCabecalho.test.js +11 -0
- package/dist/teste/ChipsXs.test.d.ts +1 -0
- package/dist/teste/ChipsXs.test.js +31 -0
- package/dist/teste/Coachmark.test.d.ts +1 -0
- package/dist/teste/Coachmark.test.js +149 -0
- package/dist/teste/CoachmarkSemVeu.test.d.ts +1 -0
- package/dist/teste/CoachmarkSemVeu.test.js +85 -0
- package/dist/teste/ColorPicker.test.d.ts +1 -0
- package/dist/teste/ColorPicker.test.js +132 -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/DataTableCelulaLivre.test.d.ts +1 -0
- package/dist/teste/DataTableCelulaLivre.test.js +76 -0
- package/dist/teste/DataTableDocumento.test.d.ts +1 -0
- package/dist/teste/DataTableDocumento.test.js +92 -0
- package/dist/teste/DatePicker.test.js +23 -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/FileInputTrigger.test.d.ts +1 -0
- package/dist/teste/FileInputTrigger.test.js +53 -0
- package/dist/teste/IconPicker.test.d.ts +1 -0
- package/dist/teste/IconPicker.test.js +130 -0
- package/dist/teste/InputAgrupado.test.d.ts +1 -0
- package/dist/teste/InputAgrupado.test.js +24 -0
- package/dist/teste/InputMascaraEAfins.test.d.ts +1 -0
- package/dist/teste/InputMascaraEAfins.test.js +99 -0
- package/dist/teste/KbdCodeBlock.test.d.ts +1 -0
- package/dist/teste/KbdCodeBlock.test.js +95 -0
- package/dist/teste/List.test.d.ts +1 -0
- package/dist/teste/List.test.js +153 -0
- package/dist/teste/ListItemTooltipStandalone.test.d.ts +1 -0
- package/dist/teste/ListItemTooltipStandalone.test.js +39 -0
- package/dist/teste/ModalVariantes.test.d.ts +1 -0
- package/dist/teste/ModalVariantes.test.js +151 -0
- package/dist/teste/NomeAcessivelSsr.test.d.ts +1 -0
- package/dist/teste/NomeAcessivelSsr.test.js +88 -0
- package/dist/teste/OrgChart.test.d.ts +1 -0
- package/dist/teste/OrgChart.test.js +162 -0
- package/dist/teste/OtpInput.test.d.ts +1 -0
- package/dist/teste/OtpInput.test.js +143 -0
- package/dist/teste/PopoverMaxHeight.test.d.ts +1 -0
- package/dist/teste/PopoverMaxHeight.test.js +38 -0
- package/dist/teste/RichTextEditor.test.d.ts +1 -0
- package/dist/teste/RichTextEditor.test.js +287 -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/SelectPlacementFiltro.test.d.ts +1 -0
- package/dist/teste/SelectPlacementFiltro.test.js +88 -0
- package/dist/teste/Stack.test.d.ts +1 -0
- package/dist/teste/Stack.test.js +57 -0
- package/dist/teste/StatCardRotuloTopo.test.d.ts +1 -0
- package/dist/teste/StatCardRotuloTopo.test.js +34 -0
- package/dist/teste/StatCardSecundariaETom.test.d.ts +1 -0
- package/dist/teste/StatCardSecundariaETom.test.js +45 -0
- package/dist/teste/TabsContadorFechavel.test.d.ts +1 -0
- package/dist/teste/TabsContadorFechavel.test.js +79 -0
- package/dist/teste/ToastAcaoEDetalhes.test.d.ts +1 -0
- package/dist/teste/ToastAcaoEDetalhes.test.js +94 -0
- package/dist/teste/TooltipDark.test.d.ts +1 -0
- package/dist/teste/TooltipDark.test.js +31 -0
- package/dist/utils/calendario.d.ts +28 -0
- package/dist/utils/calendario.js +73 -0
- package/dist/utils/html-seguro.d.ts +45 -0
- package/dist/utils/html-seguro.js +208 -0
- package/dist/utils/paleta-de-cores.d.ts +26 -0
- package/dist/utils/paleta-de-cores.js +10 -0
- package/dist/utils/texto.d.ts +5 -0
- package/dist/utils/texto.js +5 -0
- package/dist/utils/toast.d.ts +10 -1
- package/dist/utils/toast.js +2 -1
- package/package.json +3 -3
- package/src/index.ts +26 -0
- package/src/teste/AILabel.test.tsx +41 -0
- package/src/teste/AccordionConteudoLivre.test.tsx +39 -0
- package/src/teste/AccordionTituloNeutro.test.tsx +25 -0
- package/src/teste/AppSubheaderRegiao.test.tsx +17 -0
- package/src/teste/AtributosRepassados.test.tsx +73 -0
- package/src/teste/AttachmentCardIA.test.tsx +126 -0
- package/src/teste/AttachmentCardLista.test.tsx +53 -0
- package/src/teste/AttachmentCardSm.test.tsx +29 -0
- package/src/teste/AvatarGroupOverlap.test.tsx +74 -0
- package/src/teste/BadgeNeutroColado.test.tsx +15 -0
- package/src/teste/BadgeTag.test.tsx +85 -0
- package/src/teste/BoxItemFlex.test.tsx +81 -0
- package/src/teste/BoxLayout.test.tsx +50 -0
- package/src/teste/Button.test.tsx +39 -0
- package/src/teste/Calendar.test.tsx +282 -0
- package/src/teste/CalendarCabecalho.test.tsx +11 -0
- package/src/teste/ChipsXs.test.tsx +41 -0
- package/src/teste/Coachmark.test.tsx +198 -0
- package/src/teste/CoachmarkSemVeu.test.tsx +101 -0
- package/src/teste/ColorPicker.test.tsx +153 -0
- package/src/teste/ColorPickerXs.test.tsx +22 -0
- package/src/teste/DataTableArvoreEVariantes.test.tsx +240 -0
- package/src/teste/DataTableCelulaLivre.test.tsx +103 -0
- package/src/teste/DataTableDocumento.test.tsx +102 -0
- package/src/teste/DatePicker.test.tsx +38 -0
- package/src/teste/DescriptionListCompacta.test.tsx +24 -0
- package/src/teste/EmptyStateTituloRico.test.tsx +34 -0
- package/src/teste/FileInputTrigger.test.tsx +89 -0
- package/src/teste/IconPicker.test.tsx +145 -0
- package/src/teste/InputAgrupado.test.tsx +26 -0
- package/src/teste/InputMascaraEAfins.test.tsx +124 -0
- package/src/teste/KbdCodeBlock.test.tsx +106 -0
- package/src/teste/List.test.tsx +269 -0
- package/src/teste/ListItemTooltipStandalone.test.tsx +64 -0
- package/src/teste/ModalVariantes.test.tsx +173 -0
- package/src/teste/NomeAcessivelSsr.test.tsx +110 -0
- package/src/teste/OrgChart.test.tsx +183 -0
- package/src/teste/OtpInput.test.tsx +163 -0
- package/src/teste/PopoverMaxHeight.test.tsx +47 -0
- package/src/teste/RichTextEditor.test.tsx +329 -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/SelectPlacementFiltro.test.tsx +110 -0
- package/src/teste/Stack.test.tsx +80 -0
- package/src/teste/StatCardRotuloTopo.test.tsx +44 -0
- package/src/teste/StatCardSecundariaETom.test.tsx +51 -0
- package/src/teste/TabsContadorFechavel.test.tsx +144 -0
- package/src/teste/ToastAcaoEDetalhes.test.tsx +109 -0
- package/src/teste/TooltipDark.test.tsx +51 -0
- package/src/utils/calendario.ts +78 -0
- package/src/utils/html-seguro.ts +197 -0
- package/src/utils/paleta-de-cores.ts +34 -0
- package/src/utils/texto.ts +5 -0
- package/src/utils/toast.ts +12 -2
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
/** Elemento interativo (ou não) que ocupa a linha inteira. */
|
|
2
|
+
export type ListItemTag = "button" | "a" | "div";
|
|
3
|
+
/**
|
|
4
|
+
* ListItem — linha de lista inteira clicável, com conteúdo livre.
|
|
5
|
+
*
|
|
6
|
+
* Renderiza um `<li>` que contém UM elemento (`button`, `a` ou `div`) do tamanho
|
|
7
|
+
* da linha: o alvo de clique e de foco é a linha toda, não só o título. Por isso
|
|
8
|
+
* o ListItem vive dentro de um `List` (ou de um `ul`/`ol`, como `Stack as="ul"`).
|
|
9
|
+
*
|
|
10
|
+
* O conteúdo se encaixa por slots, todos opcionais: `start` (avatar, ícone,
|
|
11
|
+
* checkbox decorativo), `title`, `subtitle`, `meta` (data, contexto), `end`
|
|
12
|
+
* (badge, seta, valor) e o conteúdo padrão, que entra abaixo de `meta`. `title`,
|
|
13
|
+
* `subtitle` e `meta` também aceitam texto direto por prop.
|
|
14
|
+
*
|
|
15
|
+
* Elemento: sem `as`, vira `a` quando há `href` e `button` nos outros casos.
|
|
16
|
+
* `as="div"` é a linha que não navega nem age (só mostra), e vira acionável
|
|
17
|
+
* (role="button", Enter e Espaço) se receber `onClick`. Controles dentro de uma
|
|
18
|
+
* linha clicável (botão, checkbox) quebram o HTML: se a linha precisa deles,
|
|
19
|
+
* use `as="div"` sem `onClick` e ponha a ação num deles.
|
|
20
|
+
*
|
|
21
|
+
* `selected` marca o item atual (fundo azul-claro e `aria-current`). `disabled`
|
|
22
|
+
* tira a linha da ordem de tabulação e bloqueia o clique.
|
|
23
|
+
*
|
|
24
|
+
* Atributos HTML (`id`, `style`, `role`, `tabIndex`, `data-*`, `aria-*`) vão
|
|
25
|
+
* SÓ para o elemento interativo (nunca para o `li`), que é quem recebe
|
|
26
|
+
* `aria-label` quando a linha não tem texto visível. `title` NÃO é o atributo
|
|
27
|
+
* HTML: é o título da linha. O atributo `title` (a dica nativa do navegador) é a
|
|
28
|
+
* prop `tooltip`.
|
|
29
|
+
*
|
|
30
|
+
* `standalone` tira o `li`: o ListItem vira só o elemento interativo, para uso
|
|
31
|
+
* fora de um `List` (botão de número de página, item de carrossel, linha dentro
|
|
32
|
+
* de um `div`). Fora de `ul`/`ol`, o `li` é HTML inválido.
|
|
33
|
+
* @property {string} as - Elemento da linha: 'button' | 'a' | 'div'. Padrão: 'a' com href, senão 'button'
|
|
34
|
+
* @property {string} href - Destino do link (vira as="a")
|
|
35
|
+
* @property {string} target - Destino do link: '_blank' ganha rel="noopener noreferrer"
|
|
36
|
+
* @property {string} rel - Relação do link (sobrescreve o padrão do target)
|
|
37
|
+
* @property {boolean} selected - Item atual: fundo de seleção e aria-current
|
|
38
|
+
* @property {boolean} disabled - Bloqueia clique e foco
|
|
39
|
+
* @property {string} tooltip - Dica nativa do navegador: vira o atributo HTML `title` do elemento interativo
|
|
40
|
+
* @property {boolean} standalone - Renderiza sem o `li`, só o elemento interativo (uso fora de `List`)
|
|
41
|
+
* @property {any} title - Título da linha: texto, ou slot `title` (nó)
|
|
42
|
+
* @property {any} subtitle - Segunda linha: texto, ou slot `subtitle` (nó)
|
|
43
|
+
* @property {any} meta - Terceira linha, menor (data, contexto): texto, ou slot `meta` (nó)
|
|
44
|
+
* @property {any} start - Slot `start`: conteúdo antes do texto (avatar, ícone)
|
|
45
|
+
* @property {any} end - Slot `end`: conteúdo no fim da linha (badge, seta, valor)
|
|
46
|
+
* @property {function} onClick - Callback do clique (ou de Enter/Espaço no as="div")
|
|
47
|
+
* @property {string} className - Classes CSS adicionais, no elemento interativo
|
|
48
|
+
* @slot start - Conteúdo antes do texto.
|
|
49
|
+
* @slot title - Título (substitui a prop `title`).
|
|
50
|
+
* @slot subtitle - Segunda linha (substitui a prop `subtitle`).
|
|
51
|
+
* @slot meta - Terceira linha (substitui a prop `meta`).
|
|
52
|
+
* @slot end - Conteúdo no fim da linha.
|
|
53
|
+
* @quandoUsar Itens de uma lista em que a linha toda é a ação: documentos não lidos, notificações, resultados de busca, opções de menu de filtro, itens de navegação secundária. Hover, foco visível e seleção já vêm resolvidos.
|
|
54
|
+
* @quandoNaoUsar Para dados comparados coluna a coluna, use `DataTable`. Para um cartão com título, ações e elevação própria, use `Card`. Para um botão solto fora de lista, use `Button`. Para a navegação principal do produto, use `SidePanelItem` ou `AppNavItem`.
|
|
55
|
+
*/
|
|
56
|
+
/** Elemento interativo (ou não) que ocupa a linha inteira. */
|
|
57
|
+
export interface ListItemProps {
|
|
58
|
+
/** Elemento da linha. Sem `as`: `a` quando há `href`, senão `button`. */
|
|
59
|
+
as?: ListItemTag;
|
|
60
|
+
/** Destino do link (liga `as="a"`). */
|
|
61
|
+
href?: string;
|
|
62
|
+
/** Destino do link. `_blank` ganha `rel="noopener noreferrer"`. */
|
|
63
|
+
target?: string;
|
|
64
|
+
/** Relação do link. Sobrescreve o padrão do `target`. */
|
|
65
|
+
rel?: string;
|
|
66
|
+
/** Item atual: fundo de seleção e `aria-current`. @default false */
|
|
67
|
+
selected?: boolean;
|
|
68
|
+
/** Bloqueia clique e foco. @default false */
|
|
69
|
+
disabled?: boolean;
|
|
70
|
+
/** Dica nativa do navegador: vira o atributo HTML `title` do elemento interativo. */
|
|
71
|
+
tooltip?: string;
|
|
72
|
+
/** Sem o `li`: só o elemento interativo, para usar fora de um `List`. @default false */
|
|
73
|
+
standalone?: boolean;
|
|
74
|
+
/** Título da linha. Texto, ou slot `title` para um nó. */
|
|
75
|
+
title?: any;
|
|
76
|
+
/** Segunda linha. Texto, ou slot `subtitle` para um nó. */
|
|
77
|
+
subtitle?: any;
|
|
78
|
+
/** Terceira linha, menor (data, contexto). Texto, ou slot `meta` para um nó. */
|
|
79
|
+
meta?: any;
|
|
80
|
+
/** Conteúdo antes do texto (avatar, ícone). No Vue, slot `start`. */
|
|
81
|
+
start?: any;
|
|
82
|
+
/** Conteúdo no fim da linha (badge, seta, valor). No Vue, slot `end`. */
|
|
83
|
+
end?: any;
|
|
84
|
+
/** Chamado no clique da linha (ou em Enter/Espaço no `as="div"`). */
|
|
85
|
+
onClick?: (event: any) => void;
|
|
86
|
+
/** Classes CSS adicionais, no elemento interativo. */
|
|
87
|
+
className?: string;
|
|
88
|
+
/** ID HTML do elemento interativo. */
|
|
89
|
+
id?: string;
|
|
90
|
+
/** Atributos HTML repassados ao elemento interativo (style, data-*, aria-*…). */
|
|
91
|
+
style?: any;
|
|
92
|
+
[key: string]: any;
|
|
93
|
+
/** Conteúdo livre, abaixo de `meta`. */
|
|
94
|
+
children?: any;
|
|
95
|
+
}
|
|
96
|
+
declare function ListItem(props: ListItemProps): import("react/jsx-runtime").JSX.Element;
|
|
97
|
+
export default ListItem;
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import Text from "../Text/Text";
|
|
4
|
+
function ListItem(props) {
|
|
5
|
+
function elementTag() {
|
|
6
|
+
if (props.as)
|
|
7
|
+
return props.as;
|
|
8
|
+
return props.href ? "a" : "button";
|
|
9
|
+
}
|
|
10
|
+
function isInteractive() {
|
|
11
|
+
return elementTag() !== "div" || !!props.onClick;
|
|
12
|
+
}
|
|
13
|
+
function classes() {
|
|
14
|
+
return [
|
|
15
|
+
"umds-list-item",
|
|
16
|
+
isInteractive() ? "umds-list-item--interactive" : "",
|
|
17
|
+
props.selected ? "umds-list-item--selected" : "",
|
|
18
|
+
props.disabled ? "umds-list-item--disabled" : "",
|
|
19
|
+
props.className,
|
|
20
|
+
]
|
|
21
|
+
.filter(Boolean)
|
|
22
|
+
.join(" ");
|
|
23
|
+
}
|
|
24
|
+
function ariaCurrent() {
|
|
25
|
+
return props.selected ? "true" : undefined;
|
|
26
|
+
}
|
|
27
|
+
function ariaDisabled() {
|
|
28
|
+
return props.disabled ? "true" : undefined;
|
|
29
|
+
}
|
|
30
|
+
function hrefValue() {
|
|
31
|
+
return props.disabled ? undefined : props.href;
|
|
32
|
+
}
|
|
33
|
+
function relValue() {
|
|
34
|
+
if (props.rel)
|
|
35
|
+
return props.rel;
|
|
36
|
+
return props.target === "_blank" ? "noopener noreferrer" : undefined;
|
|
37
|
+
}
|
|
38
|
+
function divRole() {
|
|
39
|
+
return props.onClick ? "button" : undefined;
|
|
40
|
+
}
|
|
41
|
+
function divTabIndex() {
|
|
42
|
+
if (!props.onClick)
|
|
43
|
+
return undefined;
|
|
44
|
+
return props.disabled ? -1 : 0;
|
|
45
|
+
}
|
|
46
|
+
function handleClick(event) {
|
|
47
|
+
if (props.disabled) {
|
|
48
|
+
if (event && event.preventDefault)
|
|
49
|
+
event.preventDefault();
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
if (props.onClick)
|
|
53
|
+
props.onClick(event);
|
|
54
|
+
}
|
|
55
|
+
function handleKeyDown(event) {
|
|
56
|
+
if (!props.onClick || props.disabled || !event)
|
|
57
|
+
return;
|
|
58
|
+
// Só a própria linha aciona: Enter/Espaço dentro de um controle interno não.
|
|
59
|
+
if (event.target !== event.currentTarget)
|
|
60
|
+
return;
|
|
61
|
+
if (event.key !== "Enter" && event.key !== " ")
|
|
62
|
+
return;
|
|
63
|
+
event.preventDefault();
|
|
64
|
+
props.onClick(event);
|
|
65
|
+
}
|
|
66
|
+
function htmlAttrs() {
|
|
67
|
+
const out = {};
|
|
68
|
+
for (const chave in props) {
|
|
69
|
+
if (chave.indexOf("data-") === 0 ||
|
|
70
|
+
chave.indexOf("aria-") === 0 ||
|
|
71
|
+
chave === "style" ||
|
|
72
|
+
chave === "role" ||
|
|
73
|
+
chave === "tabIndex" ||
|
|
74
|
+
(chave === "class" && props.standalone)) {
|
|
75
|
+
out[chave] = props[chave];
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
return out;
|
|
79
|
+
}
|
|
80
|
+
return (_jsxs(_Fragment, { children: [!props.standalone ? (_jsxs("li", { className: "umds-list__item", children: [elementTag() === "button" ? (_jsxs("button", { type: "button", id: props.id, title: props.tooltip, disabled: props.disabled, "aria-current": ariaCurrent(), onClick: (event) => handleClick(event), ...htmlAttrs(), className: classes(), children: [props.start ? (_jsx("span", { className: "umds-list-item__start", children: _jsx(_Fragment, { children: props.start }) })) : null, _jsxs("span", { className: "umds-list-item__body", children: [props.title ? (_jsx("span", { className: "umds-list-item__title", children: _jsx(Text, { variant: "body2", as: "span", weight: "semibold", color: "inherit", children: _jsx(_Fragment, { children: props.title }) }) })) : null, props.subtitle ? (_jsx("span", { className: "umds-list-item__subtitle", children: _jsx(Text, { variant: "body2", as: "span", color: "inherit", children: _jsx(_Fragment, { children: props.subtitle }) }) })) : null, props.meta ? (_jsx("span", { className: "umds-list-item__meta", children: _jsx(Text, { variant: "caption", as: "span", color: "inherit", children: _jsx(_Fragment, { children: props.meta }) }) })) : null, _jsx(_Fragment, { children: props.children })] }), props.end ? (_jsx("span", { className: "umds-list-item__end", children: _jsx(_Fragment, { children: props.end }) })) : null] })) : null, elementTag() === "a" ? (_jsxs("a", { id: props.id, title: props.tooltip, href: hrefValue(), target: props.target, rel: relValue(), "aria-current": ariaCurrent(), "aria-disabled": ariaDisabled(), onClick: (event) => handleClick(event), ...htmlAttrs(), className: classes(), children: [props.start ? (_jsx("span", { className: "umds-list-item__start", children: _jsx(_Fragment, { children: props.start }) })) : null, _jsxs("span", { className: "umds-list-item__body", children: [props.title ? (_jsx("span", { className: "umds-list-item__title", children: _jsx(Text, { variant: "body2", as: "span", weight: "semibold", color: "inherit", children: _jsx(_Fragment, { children: props.title }) }) })) : null, props.subtitle ? (_jsx("span", { className: "umds-list-item__subtitle", children: _jsx(Text, { variant: "body2", as: "span", color: "inherit", children: _jsx(_Fragment, { children: props.subtitle }) }) })) : null, props.meta ? (_jsx("span", { className: "umds-list-item__meta", children: _jsx(Text, { variant: "caption", as: "span", color: "inherit", children: _jsx(_Fragment, { children: props.meta }) }) })) : null, _jsx(_Fragment, { children: props.children })] }), props.end ? (_jsx("span", { className: "umds-list-item__end", children: _jsx(_Fragment, { children: props.end }) })) : null] })) : null, elementTag() === "div" ? (_jsxs("div", { id: props.id, title: props.tooltip, role: divRole(), tabIndex: divTabIndex(), "aria-current": ariaCurrent(), "aria-disabled": ariaDisabled(), onClick: (event) => handleClick(event), onKeyDown: (event) => handleKeyDown(event), ...htmlAttrs(), className: classes(), children: [props.start ? (_jsx("span", { className: "umds-list-item__start", children: _jsx(_Fragment, { children: props.start }) })) : null, _jsxs("span", { className: "umds-list-item__body", children: [props.title ? (_jsx("span", { className: "umds-list-item__title", children: _jsx(Text, { variant: "body2", as: "span", weight: "semibold", color: "inherit", children: _jsx(_Fragment, { children: props.title }) }) })) : null, props.subtitle ? (_jsx("span", { className: "umds-list-item__subtitle", children: _jsx(Text, { variant: "body2", as: "span", color: "inherit", children: _jsx(_Fragment, { children: props.subtitle }) }) })) : null, props.meta ? (_jsx("span", { className: "umds-list-item__meta", children: _jsx(Text, { variant: "caption", as: "span", color: "inherit", children: _jsx(_Fragment, { children: props.meta }) }) })) : null, _jsx(_Fragment, { children: props.children })] }), props.end ? (_jsx("span", { className: "umds-list-item__end", children: _jsx(_Fragment, { children: props.end }) })) : null] })) : null] })) : null, !!props.standalone ? (_jsxs(_Fragment, { children: [elementTag() === "button" ? (_jsxs("button", { type: "button", id: props.id, title: props.tooltip, disabled: props.disabled, "aria-current": ariaCurrent(), onClick: (event) => handleClick(event), ...htmlAttrs(), className: classes(), children: [props.start ? (_jsx("span", { className: "umds-list-item__start", children: _jsx(_Fragment, { children: props.start }) })) : null, _jsxs("span", { className: "umds-list-item__body", children: [props.title ? (_jsx("span", { className: "umds-list-item__title", children: _jsx(Text, { variant: "body2", as: "span", weight: "semibold", color: "inherit", children: _jsx(_Fragment, { children: props.title }) }) })) : null, props.subtitle ? (_jsx("span", { className: "umds-list-item__subtitle", children: _jsx(Text, { variant: "body2", as: "span", color: "inherit", children: _jsx(_Fragment, { children: props.subtitle }) }) })) : null, props.meta ? (_jsx("span", { className: "umds-list-item__meta", children: _jsx(Text, { variant: "caption", as: "span", color: "inherit", children: _jsx(_Fragment, { children: props.meta }) }) })) : null, _jsx(_Fragment, { children: props.children })] }), props.end ? (_jsx("span", { className: "umds-list-item__end", children: _jsx(_Fragment, { children: props.end }) })) : null] })) : null, elementTag() === "a" ? (_jsxs("a", { id: props.id, title: props.tooltip, href: hrefValue(), target: props.target, rel: relValue(), "aria-current": ariaCurrent(), "aria-disabled": ariaDisabled(), onClick: (event) => handleClick(event), ...htmlAttrs(), className: classes(), children: [props.start ? (_jsx("span", { className: "umds-list-item__start", children: _jsx(_Fragment, { children: props.start }) })) : null, _jsxs("span", { className: "umds-list-item__body", children: [props.title ? (_jsx("span", { className: "umds-list-item__title", children: _jsx(Text, { variant: "body2", as: "span", weight: "semibold", color: "inherit", children: _jsx(_Fragment, { children: props.title }) }) })) : null, props.subtitle ? (_jsx("span", { className: "umds-list-item__subtitle", children: _jsx(Text, { variant: "body2", as: "span", color: "inherit", children: _jsx(_Fragment, { children: props.subtitle }) }) })) : null, props.meta ? (_jsx("span", { className: "umds-list-item__meta", children: _jsx(Text, { variant: "caption", as: "span", color: "inherit", children: _jsx(_Fragment, { children: props.meta }) }) })) : null, _jsx(_Fragment, { children: props.children })] }), props.end ? (_jsx("span", { className: "umds-list-item__end", children: _jsx(_Fragment, { children: props.end }) })) : null] })) : null, elementTag() === "div" ? (_jsxs("div", { id: props.id, title: props.tooltip, role: divRole(), tabIndex: divTabIndex(), "aria-current": ariaCurrent(), "aria-disabled": ariaDisabled(), onClick: (event) => handleClick(event), onKeyDown: (event) => handleKeyDown(event), ...htmlAttrs(), className: classes(), children: [props.start ? (_jsx("span", { className: "umds-list-item__start", children: _jsx(_Fragment, { children: props.start }) })) : null, _jsxs("span", { className: "umds-list-item__body", children: [props.title ? (_jsx("span", { className: "umds-list-item__title", children: _jsx(Text, { variant: "body2", as: "span", weight: "semibold", color: "inherit", children: _jsx(_Fragment, { children: props.title }) }) })) : null, props.subtitle ? (_jsx("span", { className: "umds-list-item__subtitle", children: _jsx(Text, { variant: "body2", as: "span", color: "inherit", children: _jsx(_Fragment, { children: props.subtitle }) }) })) : null, props.meta ? (_jsx("span", { className: "umds-list-item__meta", children: _jsx(Text, { variant: "caption", as: "span", color: "inherit", children: _jsx(_Fragment, { children: props.meta }) }) })) : null, _jsx(_Fragment, { children: props.children })] }), props.end ? (_jsx("span", { className: "umds-list-item__end", children: _jsx(_Fragment, { children: props.end }) })) : null] })) : null] })) : null] }));
|
|
81
|
+
}
|
|
82
|
+
export default ListItem;
|
|
@@ -375,6 +375,86 @@
|
|
|
375
375
|
border-radius: 0;
|
|
376
376
|
}
|
|
377
377
|
|
|
378
|
+
/* ── variant="primary": cabeçalho cheio na cor primária ──
|
|
379
|
+
Título, subtítulo e controles em branco (neutral-light-pure, o mesmo par que
|
|
380
|
+
o Button primary usa sobre primary-pure). */
|
|
381
|
+
.umds-modal--primary .umds-modal__header {
|
|
382
|
+
background-color: var(--umds-semantic-color-primary-pure);
|
|
383
|
+
border-bottom-color: var(--umds-semantic-color-primary-pure);
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
.umds-modal--primary .umds-modal__title,
|
|
387
|
+
.umds-modal--primary .umds-modal__subtitle {
|
|
388
|
+
color: var(--umds-semantic-color-neutral-light-pure);
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
.umds-modal--primary .umds-modal__ctrl {
|
|
392
|
+
color: var(--umds-semantic-color-neutral-light-pure);
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
.umds-modal--primary .umds-modal__ctrl:hover,
|
|
396
|
+
.umds-modal--primary .umds-modal__ctrl--ativo,
|
|
397
|
+
.umds-modal--primary .umds-modal__ctrl--close:hover {
|
|
398
|
+
background: var(--umds-semantic-color-primary-dark);
|
|
399
|
+
color: var(--umds-semantic-color-neutral-light-pure);
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
.umds-modal--primary .umds-modal__ctrl:focus-visible {
|
|
403
|
+
outline-color: var(--umds-semantic-color-neutral-light-pure);
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
.umds-modal--primary .umds-modal__ctrl-divider {
|
|
407
|
+
background: var(--umds-semantic-color-primary-medium);
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
/* ── responsive: abaixo do breakpoint vira painel que sobe pela borda de baixo ──
|
|
411
|
+
Mesma anatomia do BottomSheet (largura total, cantos de cima arredondados,
|
|
412
|
+
alça, entrada por baixo). Quem decide o breakpoint é o componente (media
|
|
413
|
+
query em JS, para a prop `responsiveBreakpoint` valer). */
|
|
414
|
+
.umds-modal-root--sheet {
|
|
415
|
+
align-items: flex-end;
|
|
416
|
+
padding: 0;
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
.umds-modal.umds-modal--sheet {
|
|
420
|
+
width: 100%;
|
|
421
|
+
max-width: none;
|
|
422
|
+
max-height: 90vh;
|
|
423
|
+
border-bottom-left-radius: 0;
|
|
424
|
+
border-bottom-right-radius: 0;
|
|
425
|
+
animation: umds-modal-sheet-in var(--umds-semantic-motion-duration-base)
|
|
426
|
+
var(--umds-semantic-motion-easing-standard);
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
@keyframes umds-modal-sheet-in {
|
|
430
|
+
from {
|
|
431
|
+
transform: translateY(100%);
|
|
432
|
+
}
|
|
433
|
+
to {
|
|
434
|
+
transform: translateY(0);
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
.umds-modal__grabber {
|
|
439
|
+
display: flex;
|
|
440
|
+
align-items: center;
|
|
441
|
+
justify-content: center;
|
|
442
|
+
padding: var(--umds-primitive-spacing-nano) 0 0;
|
|
443
|
+
flex-shrink: 0;
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
.umds-modal--primary .umds-modal__grabber {
|
|
447
|
+
background-color: var(--umds-semantic-color-primary-pure);
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
.umds-modal__grabber-bar {
|
|
451
|
+
display: block;
|
|
452
|
+
width: var(--umds-primitive-spacing-sm); /* 40px */
|
|
453
|
+
height: var(--umds-primitive-spacing-quarck); /* 4px */
|
|
454
|
+
border-radius: var(--umds-primitive-border-radius-pill);
|
|
455
|
+
background-color: var(--umds-semantic-color-neutral-light-down);
|
|
456
|
+
}
|
|
457
|
+
|
|
378
458
|
/* ── Alto contraste ──
|
|
379
459
|
No 1doc-high-contrast o painel e a página são pretos e a sombra (preta)
|
|
380
460
|
não aparece: sem traço, o modal não tem borda visível. O traço é um
|
|
@@ -27,9 +27,30 @@ export interface ModalProps {
|
|
|
27
27
|
* - "positive": sucesso (verde, ícone circle-check).
|
|
28
28
|
* - "negative": erro/falha (vermelho, ícone circle-exclamation).
|
|
29
29
|
* - "info": atenção (laranja, ícone triangle-exclamation).
|
|
30
|
+
* - "primary": modal base com o cabeçalho cheio na cor primária (título e
|
|
31
|
+
* controles em branco). Não é diálogo de feedback: mantém as três faixas.
|
|
30
32
|
* @default 'default'
|
|
31
33
|
*/
|
|
32
|
-
variant?: "default" | "positive" | "negative" | "info";
|
|
34
|
+
variant?: "default" | "positive" | "negative" | "info" | "primary";
|
|
35
|
+
/**
|
|
36
|
+
* Largura do modal, qualquer valor CSS (`"600px"`, `"60vw"`). Sem
|
|
37
|
+
* `maxWidth`, o teto passa a ser a própria tela (o 498px do `md` não
|
|
38
|
+
* segura mais). Vence o `size`. Com `windowControls`, vale só no modo
|
|
39
|
+
* normal: expandido e tela cheia mandam no tamanho.
|
|
40
|
+
*/
|
|
41
|
+
width?: string;
|
|
42
|
+
/** Largura máxima, qualquer valor CSS. Vence o teto do `size`. */
|
|
43
|
+
maxWidth?: string;
|
|
44
|
+
/**
|
|
45
|
+
* Abaixo do breakpoint (`responsiveBreakpoint`), o modal vira um painel que
|
|
46
|
+
* sobe pela borda de baixo, como o `BottomSheet`: largura total, cantos de
|
|
47
|
+
* cima arredondados, alça no topo. Acima dele, continua centralizado. É
|
|
48
|
+
* o mesmo componente reorganizado, então título, corpo e rodapé não mudam.
|
|
49
|
+
* @default false
|
|
50
|
+
*/
|
|
51
|
+
responsive?: boolean;
|
|
52
|
+
/** Largura da tela, em px, abaixo da qual o `responsive` vira painel. Lida na montagem. @default 640 */
|
|
53
|
+
responsiveBreakpoint?: number;
|
|
33
54
|
/**
|
|
34
55
|
* Título em destaque. Com título, o diálogo é nomeado por ele
|
|
35
56
|
* (`aria-labelledby`) e `ariaLabel` é ignorado.
|
|
@@ -79,12 +100,18 @@ export interface ModalProps {
|
|
|
79
100
|
/** Se verdadeiro, renderiza o modal inline (sem fixed/overlay), útil para documentação */
|
|
80
101
|
inline?: boolean;
|
|
81
102
|
/**
|
|
82
|
-
* Controles de janela no cabeçalho
|
|
83
|
-
*
|
|
84
|
-
*
|
|
103
|
+
* Controles de janela no cabeçalho, antes do ×. Duas formas:
|
|
104
|
+
* - `true`: o conjunto inteiro (restaurar, expandir, tela cheia e minimizar).
|
|
105
|
+
* O modal passa a mudar de tamanho sozinho (normal 780px, expandido, tela
|
|
106
|
+
* cheia).
|
|
107
|
+
* - uma lista com os que quiser, na ordem fixa do cabeçalho:
|
|
108
|
+
* `["expand", "fullscreen"]`, `["fullscreen"]`... Os nomes são `normal`,
|
|
109
|
+
* `expand`, `fullscreen` e `minimize`. Sem `normal` na lista, clicar de
|
|
110
|
+
* novo no modo ativo volta ao normal, e o modo normal usa o tamanho do
|
|
111
|
+
* próprio modal (`size`, `width`), não os 780px do conjunto inteiro.
|
|
85
112
|
*/
|
|
86
|
-
windowControls?: boolean
|
|
87
|
-
/** Acionado no botão minimizar. Só existe
|
|
113
|
+
windowControls?: boolean | Array<"normal" | "expand" | "fullscreen" | "minimize">;
|
|
114
|
+
/** Acionado no botão minimizar. Só existe quando `minimize` está entre os controles. */
|
|
88
115
|
onMinimize?: (event?: any) => void;
|
|
89
116
|
/**
|
|
90
117
|
* Região esquerda do rodapé — conteúdo de apoio que não é botão: a caixa
|
|
@@ -12,6 +12,7 @@ function Modal(props) {
|
|
|
12
12
|
const escCleanupRef = useRef(null);
|
|
13
13
|
const closeFnRef = useRef(null);
|
|
14
14
|
const previousFocusRef = useRef(null);
|
|
15
|
+
const mediaCleanupRef = useRef(null);
|
|
15
16
|
const [lastOpen, setLastOpen] = useState(() => false);
|
|
16
17
|
const [uid, setUid] = useState(() => "umds-modal-" + Math.random().toString(36).slice(2, 9));
|
|
17
18
|
function titleId() {
|
|
@@ -32,18 +33,83 @@ function Modal(props) {
|
|
|
32
33
|
return props.description ? uid + "-description" : undefined;
|
|
33
34
|
}
|
|
34
35
|
function ehFeedback() {
|
|
35
|
-
|
|
36
|
+
// `primary` é só o cabeçalho cheio do modal base: não é feedback.
|
|
37
|
+
const temVariante = props.variant
|
|
38
|
+
? props.variant !== "default" && props.variant !== "primary"
|
|
39
|
+
: false;
|
|
36
40
|
return temVariante || props.layout === "dialog";
|
|
37
41
|
}
|
|
38
42
|
const [modoAtual, setModoAtual] = useState(() => "normal");
|
|
43
|
+
const [isCompact, setIsCompact] = useState(() => false);
|
|
44
|
+
function ehSheet() {
|
|
45
|
+
return !!props.responsive && isCompact;
|
|
46
|
+
}
|
|
47
|
+
function temNormal() {
|
|
48
|
+
if (props.responsive && isCompact)
|
|
49
|
+
return false;
|
|
50
|
+
if (props.windowControls === true)
|
|
51
|
+
return true;
|
|
52
|
+
return (Array.isArray(props.windowControls) &&
|
|
53
|
+
props.windowControls.includes("normal"));
|
|
54
|
+
}
|
|
55
|
+
function temExpandir() {
|
|
56
|
+
if (props.responsive && isCompact)
|
|
57
|
+
return false;
|
|
58
|
+
if (props.windowControls === true)
|
|
59
|
+
return true;
|
|
60
|
+
return (Array.isArray(props.windowControls) &&
|
|
61
|
+
props.windowControls.includes("expand"));
|
|
62
|
+
}
|
|
63
|
+
function temTelaCheia() {
|
|
64
|
+
if (props.responsive && isCompact)
|
|
65
|
+
return false;
|
|
66
|
+
if (props.windowControls === true)
|
|
67
|
+
return true;
|
|
68
|
+
return (Array.isArray(props.windowControls) &&
|
|
69
|
+
props.windowControls.includes("fullscreen"));
|
|
70
|
+
}
|
|
71
|
+
function temMinimizar() {
|
|
72
|
+
if (props.responsive && isCompact)
|
|
73
|
+
return false;
|
|
74
|
+
if (props.windowControls === true)
|
|
75
|
+
return true;
|
|
76
|
+
return (Array.isArray(props.windowControls) &&
|
|
77
|
+
props.windowControls.includes("minimize"));
|
|
78
|
+
}
|
|
79
|
+
function temControles() {
|
|
80
|
+
if (props.responsive && isCompact)
|
|
81
|
+
return false;
|
|
82
|
+
if (props.windowControls === true)
|
|
83
|
+
return true;
|
|
84
|
+
return (Array.isArray(props.windowControls) && props.windowControls.length > 0);
|
|
85
|
+
}
|
|
86
|
+
function janelaPorLista() {
|
|
87
|
+
return Array.isArray(props.windowControls);
|
|
88
|
+
}
|
|
89
|
+
function estiloDoDialogo() {
|
|
90
|
+
if (!props.width && !props.maxWidth)
|
|
91
|
+
return undefined;
|
|
92
|
+
if (props.responsive && isCompact)
|
|
93
|
+
return undefined;
|
|
94
|
+
if (props.windowControls && modoAtual !== "normal")
|
|
95
|
+
return undefined;
|
|
96
|
+
const estilo = {};
|
|
97
|
+
if (props.width)
|
|
98
|
+
estilo.width = props.width;
|
|
99
|
+
if (props.maxWidth)
|
|
100
|
+
estilo.maxWidth = props.maxWidth;
|
|
101
|
+
else
|
|
102
|
+
estilo.maxWidth = "100%";
|
|
103
|
+
return estilo;
|
|
104
|
+
}
|
|
39
105
|
function irParaNormal() {
|
|
40
106
|
setModoAtual("normal");
|
|
41
107
|
}
|
|
42
108
|
function irParaExpandido() {
|
|
43
|
-
setModoAtual("expanded");
|
|
109
|
+
setModoAtual(modoAtual === "expanded" && !temNormal() ? "normal" : "expanded");
|
|
44
110
|
}
|
|
45
111
|
function irParaTelaCheia() {
|
|
46
|
-
setModoAtual("fullscreen");
|
|
112
|
+
setModoAtual(modoAtual === "fullscreen" && !temNormal() ? "normal" : "fullscreen");
|
|
47
113
|
}
|
|
48
114
|
function classeDoControle(modo) {
|
|
49
115
|
return modo === modoAtual
|
|
@@ -53,6 +119,12 @@ function Modal(props) {
|
|
|
53
119
|
function classeDaJanela() {
|
|
54
120
|
if (!props.windowControls)
|
|
55
121
|
return "";
|
|
122
|
+
if (props.responsive && isCompact)
|
|
123
|
+
return "";
|
|
124
|
+
// Lista de controles: o normal é o tamanho do próprio modal.
|
|
125
|
+
if (Array.isArray(props.windowControls) && modoAtual === "normal") {
|
|
126
|
+
return "";
|
|
127
|
+
}
|
|
56
128
|
return `umds-modal--janela-${modoAtual}`;
|
|
57
129
|
}
|
|
58
130
|
function temRodape() {
|
|
@@ -66,6 +138,7 @@ function Modal(props) {
|
|
|
66
138
|
props.inline ? "umds-modal-root--inline" : "umds-modal-root",
|
|
67
139
|
props.open ? "umds-modal-root--open" : "umds-modal-root--closed",
|
|
68
140
|
props.size === "fullscreen" ? "umds-modal-root--fullscreen" : "",
|
|
141
|
+
props.responsive && isCompact ? "umds-modal-root--sheet" : "",
|
|
69
142
|
]
|
|
70
143
|
.filter(Boolean)
|
|
71
144
|
.join(" ");
|
|
@@ -77,6 +150,7 @@ function Modal(props) {
|
|
|
77
150
|
props.size && props.size !== "md" ? `umds-modal--${props.size}` : "",
|
|
78
151
|
ehFeedback() ? "umds-modal--feedback" : "umds-modal--base",
|
|
79
152
|
classeDaJanela(),
|
|
153
|
+
props.responsive && isCompact ? "umds-modal--sheet" : "",
|
|
80
154
|
props.className,
|
|
81
155
|
]
|
|
82
156
|
.filter(Boolean)
|
|
@@ -108,6 +182,10 @@ function Modal(props) {
|
|
|
108
182
|
function handleEscClose(event) {
|
|
109
183
|
if (props.closeOnEsc === false)
|
|
110
184
|
return;
|
|
185
|
+
// Quem já usou o Esc (Select, DatePicker, Popover aberto dentro do
|
|
186
|
+
// modal) chamou preventDefault: a tecla é dele, o modal não fecha.
|
|
187
|
+
if (event && event.defaultPrevented)
|
|
188
|
+
return;
|
|
111
189
|
if (!isTopOverlay(uid))
|
|
112
190
|
return;
|
|
113
191
|
handleClose(event);
|
|
@@ -173,10 +251,23 @@ function Modal(props) {
|
|
|
173
251
|
closeFnRef.current(event);
|
|
174
252
|
}
|
|
175
253
|
};
|
|
176
|
-
|
|
254
|
+
// No borbulho (false), não na captura: o ouvinte do document só vê a tecla
|
|
255
|
+
// depois que o componente aberto dentro do modal teve a vez de consumi-la.
|
|
256
|
+
document.addEventListener("keydown", watcher, false);
|
|
177
257
|
escCleanupRef.current = () => {
|
|
178
|
-
document.removeEventListener("keydown", watcher,
|
|
258
|
+
document.removeEventListener("keydown", watcher, false);
|
|
179
259
|
};
|
|
260
|
+
if (typeof window !== "undefined" && window.matchMedia) {
|
|
261
|
+
const consulta = window.matchMedia("(max-width: " + (props.responsiveBreakpoint || 640) + "px)");
|
|
262
|
+
const aoMudar = (e) => {
|
|
263
|
+
setIsCompact(!!e.matches);
|
|
264
|
+
};
|
|
265
|
+
setIsCompact(!!consulta.matches);
|
|
266
|
+
consulta.addEventListener("change", aoMudar);
|
|
267
|
+
mediaCleanupRef.current = () => {
|
|
268
|
+
consulta.removeEventListener("change", aoMudar);
|
|
269
|
+
};
|
|
270
|
+
}
|
|
180
271
|
syncOpenState();
|
|
181
272
|
}, []);
|
|
182
273
|
useEffect(() => {
|
|
@@ -190,9 +281,13 @@ function Modal(props) {
|
|
|
190
281
|
escCleanupRef.current();
|
|
191
282
|
escCleanupRef.current = null;
|
|
192
283
|
}
|
|
284
|
+
if (mediaCleanupRef.current) {
|
|
285
|
+
mediaCleanupRef.current();
|
|
286
|
+
mediaCleanupRef.current = null;
|
|
287
|
+
}
|
|
193
288
|
removeOverlay(uid);
|
|
194
289
|
};
|
|
195
290
|
}, []);
|
|
196
|
-
return (_jsx(_Fragment, { children: props.open ? (_jsx(_Fragment, { children: _jsxs("div", { className: rootClasses(), children: [_jsx("div", { className: "umds-modal-overlay", onClick: (e) => handleOverlayClick(e) }), _jsxs("div", { role: "dialog", "aria-modal": "true", ref: dialogRef, "aria-label": nomeAcessivel(), "aria-labelledby": labelledBy(), "aria-describedby": describedBy(), tabIndex: -1, onKeyDown: (event) => handleTrapKeydown(event), className: modalClasses(), children: [!ehFeedback() ? (_jsxs(_Fragment, { children: [_jsxs("div", { className: "umds-modal__header", children: [_jsxs("div", { className: "umds-modal__text-group", children: [props.title ? (_jsx("span", { className: "umds-modal__title", id: titleId(), children: props.title })) : null, props.description ? (_jsx("span", { className: "umds-modal__subtitle", id: descriptionId(), children: props.description })) : null] }), _jsxs("div", { className: "umds-modal__header-actions", children: [
|
|
291
|
+
return (_jsx(_Fragment, { children: props.open ? (_jsx(_Fragment, { children: _jsxs("div", { className: rootClasses(), children: [_jsx("div", { className: "umds-modal-overlay", onClick: (e) => handleOverlayClick(e) }), _jsxs("div", { role: "dialog", "aria-modal": "true", ref: dialogRef, "aria-label": nomeAcessivel(), "aria-labelledby": labelledBy(), "aria-describedby": describedBy(), tabIndex: -1, style: estiloDoDialogo(), onKeyDown: (event) => handleTrapKeydown(event), className: modalClasses(), children: [!ehFeedback() ? (_jsxs(_Fragment, { children: [ehSheet() ? (_jsx("div", { "aria-hidden": "true", className: "umds-modal__grabber", children: _jsx("span", { className: "umds-modal__grabber-bar" }) })) : null, _jsxs("div", { className: "umds-modal__header", children: [_jsxs("div", { className: "umds-modal__text-group", children: [props.title ? (_jsx("span", { className: "umds-modal__title", id: titleId(), children: props.title })) : null, props.description ? (_jsx("span", { className: "umds-modal__subtitle", id: descriptionId(), children: props.description })) : null] }), _jsxs("div", { className: "umds-modal__header-actions", children: [temNormal() ? (_jsx("button", { type: "button", title: props.normalModeLabel || "Modo normal", "aria-label": props.normalModeLabel || "Modo normal", "aria-pressed": modoAtual === "normal", onClick: (event) => irParaNormal(), className: classeDoControle("normal"), children: _jsx(Icon, { customSize: "14px", icon: faWindowRestore }) })) : null, temExpandir() ? (_jsx("button", { type: "button", title: props.expandLabel || "Expandir", "aria-label": props.expandLabel || "Expandir", "aria-pressed": modoAtual === "expanded", onClick: (event) => irParaExpandido(), className: classeDoControle("expanded"), children: _jsx(Icon, { customSize: "14px", icon: faUpRightAndDownLeftFromCenter }) })) : null, temTelaCheia() ? (_jsx("button", { type: "button", title: props.fullscreenLabel || "Tela cheia", "aria-label": props.fullscreenLabel || "Tela cheia", "aria-pressed": modoAtual === "fullscreen", onClick: (event) => irParaTelaCheia(), className: classeDoControle("fullscreen"), children: _jsx(Icon, { customSize: "14px", icon: faExpand }) })) : null, temMinimizar() ? (_jsx("button", { type: "button", className: "umds-modal__ctrl", title: props.minimizeLabel || "Minimizar", "aria-label": props.minimizeLabel || "Minimizar", onClick: (e) => props.onMinimize?.(e), children: _jsx(Icon, { customSize: "14px", icon: faMinus }) })) : null, temControles() && !props.hideCloseButton ? (_jsx("span", { className: "umds-modal__ctrl-divider" })) : null, !props.hideCloseButton ? (_jsx("button", { type: "button", className: "umds-modal__ctrl umds-modal__ctrl--close", onClick: (e) => handleClose(e), title: props.closeLabel || "Fechar", "aria-label": props.closeLabel || "Fechar", children: _jsx(Icon, { customSize: "16px", icon: faXmark }) })) : null] })] }), _jsx("div", { className: "umds-modal__body", children: _jsx(_Fragment, { children: props.children }) }), temRodape() ? (_jsxs("div", { className: "umds-modal__footer", children: [_jsx("div", { className: "umds-modal__footer-start", children: props.footerStart ? _jsx(_Fragment, { children: props.footerStart }) : null }), _jsxs("div", { className: "umds-modal__footer-end", children: [props.footerSlot ? _jsx(_Fragment, { children: props.footerSlot }) : null, !props.footerSlot ? (_jsxs(_Fragment, { children: [props.cancelLabel ? (_jsx(Button, { variant: "text", onClick: (e) => props.onCancel?.(e), children: props.cancelLabel })) : null, props.confirmLabel ? (_jsx(Button, { variant: "primary", onClick: (e) => props.onConfirm?.(e), children: props.confirmLabel })) : null] })) : null] })] })) : null] })) : null, ehFeedback() ? (_jsxs(_Fragment, { children: [!props.hideCloseButton ? (_jsx("div", { className: "umds-modal__close-wrapper", children: _jsx("button", { className: "umds-modal__close-button", onClick: (e) => handleClose(e), "aria-label": props.closeLabel || "Fechar", children: _jsx(Icon, { size: "sm", icon: faXmark }) }) })) : null, _jsxs("div", { className: "umds-modal__content", children: [_jsxs("div", { className: "umds-modal__header umds-modal__header--feedback", children: [props.variant && props.variant !== "default" ? (_jsx("div", { className: `umds-modal__icon ${iconVariantClass()}`, children: _jsx(Icon, { customSize: "40px", icon: iconName() }) })) : null, _jsxs("div", { className: "umds-modal__text-group", children: [props.title ? (_jsx(Text, { variant: "h5", weight: "bold", id: titleId(), children: props.title })) : null, props.description ? (_jsx(Text, { variant: "body2", color: "secondary", id: descriptionId(), children: props.description })) : null] })] }), _jsx(_Fragment, { children: props.children }), _jsxs("div", { className: "umds-modal__footer umds-modal__footer--feedback", children: [props.footerSlot ? _jsx(_Fragment, { children: props.footerSlot }) : null, !props.footerSlot ? (_jsxs(_Fragment, { children: [props.cancelLabel ? (_jsx(Button, { variant: "text", onClick: (e) => props.onCancel?.(e), children: props.cancelLabel })) : null, props.confirmLabel ? (_jsx(Button, { variant: "primary", onClick: (e) => props.onConfirm?.(e), children: props.confirmLabel })) : null] })) : null] })] })] })) : null] })] }) })) : null }));
|
|
197
292
|
}
|
|
198
293
|
export default Modal;
|
|
@@ -378,6 +378,14 @@
|
|
|
378
378
|
border-color: var(--umds-semantic-field-border-default);
|
|
379
379
|
}
|
|
380
380
|
|
|
381
|
+
/* Somente leitura não é desabilitado: o texto segue lido e a WCAG 1.4.3 vale
|
|
382
|
+
sem isenção. O placeholder padrão foi calibrado para fundo branco e cai para
|
|
383
|
+
~4,2:1 sobre o fundo de somente leitura; neutral-dark-down passa 4,5:1 em
|
|
384
|
+
todos os temas (1doc 6,78:1 · 1doc-dark 10,83:1 · alto contraste 16,48:1). */
|
|
385
|
+
.umds-multiselect--readonly .umds-multiselect__placeholder {
|
|
386
|
+
color: var(--umds-semantic-color-neutral-dark-down);
|
|
387
|
+
}
|
|
388
|
+
|
|
381
389
|
/* O campo de busca precisa de indicador de foco — o painel foca ele ao abrir.
|
|
382
390
|
Um outline no <input> desenhava um retângulo azul solto no meio do painel,
|
|
383
391
|
porque o input não tem borda própria para o anel acompanhar.
|
|
@@ -56,6 +56,12 @@ function MultiSelect(props) {
|
|
|
56
56
|
function labelIdText() {
|
|
57
57
|
return baseId() ? baseId() + "-label" : undefined;
|
|
58
58
|
}
|
|
59
|
+
function comboboxLabelledBy() {
|
|
60
|
+
return props.label && baseId() ? labelIdText() : undefined;
|
|
61
|
+
}
|
|
62
|
+
function comboboxAriaLabel() {
|
|
63
|
+
return props.label && !baseId() ? props.label : undefined;
|
|
64
|
+
}
|
|
59
65
|
function errorIdText() {
|
|
60
66
|
return baseId() ? baseId() + "-error" : undefined;
|
|
61
67
|
}
|
|
@@ -162,6 +168,8 @@ function MultiSelect(props) {
|
|
|
162
168
|
toggle();
|
|
163
169
|
}
|
|
164
170
|
else if (event.key === "Escape" && isOpen) {
|
|
171
|
+
// O Esc é da lista (fecha só ela): o Modal em volta não reage.
|
|
172
|
+
event.preventDefault();
|
|
165
173
|
setIsOpen(false);
|
|
166
174
|
setSearchTerm("");
|
|
167
175
|
}
|
|
@@ -177,6 +185,7 @@ function MultiSelect(props) {
|
|
|
177
185
|
}
|
|
178
186
|
function handleSearchKeyDown(event) {
|
|
179
187
|
if (event.key === "Escape") {
|
|
188
|
+
event.preventDefault();
|
|
180
189
|
setIsOpen(false);
|
|
181
190
|
setSearchTerm("");
|
|
182
191
|
setActiveIndex(-1);
|
|
@@ -285,6 +294,6 @@ function MultiSelect(props) {
|
|
|
285
294
|
}
|
|
286
295
|
};
|
|
287
296
|
}, []);
|
|
288
|
-
return (_jsxs("div", { ref: containerRef, className: wrapperClasses(), children: [props.label ? (_jsxs(Text, { as: "label", variant: "label", className: "umds-multiselect__label", id: labelIdText(), children: [props.label, props.required ? (_jsx("span", { className: "umds-multiselect__required", children: " *" })) : null] })) : null, _jsxs("div", { className: "umds-multiselect__container", children: [_jsxs("div", { role: "combobox", "aria-haspopup": "listbox", className: "umds-multiselect__trigger", id: comboboxIdText(), onClick: (event) => toggle(), onKeyDown: (event) => handleTriggerKeyDown(event), "aria-readonly": ariaReadonly(), "aria-expanded": isOpen, "aria-controls": listboxIdText(), "aria-labelledby":
|
|
297
|
+
return (_jsxs("div", { ref: containerRef, className: wrapperClasses(), children: [props.label ? (_jsxs(Text, { as: "label", variant: "label", className: "umds-multiselect__label", id: labelIdText(), children: [props.label, props.required ? (_jsx("span", { className: "umds-multiselect__required", children: " *" })) : null] })) : null, _jsxs("div", { className: "umds-multiselect__container", children: [_jsxs("div", { role: "combobox", "aria-haspopup": "listbox", className: "umds-multiselect__trigger", id: comboboxIdText(), onClick: (event) => toggle(), onKeyDown: (event) => handleTriggerKeyDown(event), "aria-readonly": ariaReadonly(), "aria-expanded": isOpen, "aria-controls": listboxIdText(), "aria-labelledby": comboboxLabelledBy(), "aria-label": comboboxAriaLabel(), "aria-disabled": props.disabled, "aria-invalid": ariaInvalidText(), "aria-describedby": describedByText(), tabIndex: props.disabled ? -1 : 0, children: [_jsxs("div", { className: "umds-multiselect__tags-area", children: [selectedOptions().length === 0 ? (_jsx("span", { className: "umds-multiselect__placeholder", children: props.placeholder || "Selecione..." })) : null, selectedOptions().length > 0 ? (_jsx(_Fragment, { children: selectedOptions()?.map((opt) => (_jsx(Tag, { size: "sm", label: opt.label, closable: true, closeAriaLabel: removeTagAriaLabelText(opt.label), onClose: (event) => removeTag(opt.value, event) }, opt.value))) })) : null] }), _jsxs("div", { className: "umds-multiselect__actions", children: [selectedOptions().length > 0 && !props.disabled ? (_jsx("span", { role: "button", className: "umds-multiselect__clear", onClick: (event) => clearAll(event), onKeyDown: (event) => aoTeclarLimparTudo(event), tabIndex: 0, "aria-label": clearSelectionText(), title: clearSelectionText(), children: _jsx(Icon, { variant: "inherit", customSize: "10px", icon: faXmark }) })) : null, _jsx("div", { className: "umds-multiselect__arrow", children: _jsx(Icon, { variant: "inherit", customSize: "12px", icon: faChevronDown }) })] })] }), isOpen ? (_jsxs("div", { className: "umds-multiselect__dropdown", children: [_jsxs("div", { className: "umds-multiselect__search", children: [_jsx("div", { className: "umds-multiselect__search-icon", children: _jsx(Icon, { variant: "inherit", customSize: "14px", icon: faMagnifyingGlass }) }), _jsx("input", { type: "text", role: "combobox", className: "umds-multiselect__search-input", ref: searchInputRef, "aria-label": props.searchAriaLabel || "Buscar", placeholder: props.searchPlaceholder || "Buscar...", value: searchTerm, onInput: (event) => handleSearch(event), onChange: (event) => handleSearch(event), onKeyDown: (event) => handleSearchKeyDown(event), onClick: (event) => event.stopPropagation(), "aria-expanded": isOpen, "aria-controls": listboxIdText(), "aria-activedescendant": activeOptionId() }), !!searchTerm ? (_jsx("span", { role: "button", className: "umds-multiselect__search-clear", onClick: (event) => clearSearchTerm(), onKeyDown: (event) => aoTeclarLimparBusca(event), tabIndex: 0, "aria-label": props.clearSearchAriaLabel || "Limpar busca", children: _jsx(Icon, { variant: "inherit", customSize: "10px", icon: faXmark }) })) : null] }), _jsxs("div", { role: "listbox", "aria-multiselectable": "true", className: "umds-multiselect__options", id: listboxIdText(), children: [filteredOptions().length === 0 ? (_jsx("div", { className: "umds-multiselect__empty", children: _jsx(Text, { variant: "body2", color: "secondary", children: props.emptyLabel || "Nenhum item encontrado" }) })) : null, filteredOptions()?.map((option, indice) => (_jsxs("div", { role: "option", id: optionIdText(indice), onClick: (event) => selectOption(option.value), "aria-selected": isSelected(option.value), className: optionClasses(option.value, indice), children: [_jsx("div", { "aria-hidden": "true", className: "umds-multiselect__option-checkbox", children: _jsx(Checkbox, { size: "sm", checked: isSelected(option.value), decorative: true }) }), _jsx("span", { className: "umds-multiselect__option-label", children: option.label })] }, option.value)))] }), selectedOptions().length > 0 ? (_jsxs("div", { className: "umds-multiselect__footer", children: [_jsx(Text, { variant: "caption", color: "secondary", children: selectedCountText() }), _jsx("span", { role: "button", className: "umds-multiselect__footer-clear", onClick: (event) => clearAll(event), onKeyDown: (event) => aoTeclarLimparTudo(event), tabIndex: 0, children: props.clearAllLabel || "Limpar tudo" })] })) : null] })) : null] }), props.name ? (_jsx(_Fragment, { children: currentValue()?.map((val) => (_jsx("input", { type: "hidden", name: props.name, value: String(val) }, String(val)))) })) : null, props.errorMessage ? (_jsx(Text, { variant: "caption", color: "negative", className: "umds-multiselect__error-message", id: errorIdText(), children: props.errorMessage })) : null, mostraApoio() ? (_jsx(Text, { variant: "caption", color: "secondary", className: "umds-multiselect__description", id: helperIdText(), children: textoDeApoio() })) : null] }));
|
|
289
298
|
}
|
|
290
299
|
export default MultiSelect;
|