@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,62 @@
|
|
|
1
|
+
import './DescriptionList.css';
|
|
2
|
+
/**
|
|
3
|
+
* Par rótulo/valor da DescriptionList.
|
|
4
|
+
* @property {string} label - Rótulo (o termo).
|
|
5
|
+
* @property {any} value - Valor (a descrição). No Vue é tratado como texto.
|
|
6
|
+
* @property {string} id - Identidade estável do par (padrão: o próprio rótulo).
|
|
7
|
+
*/
|
|
8
|
+
export interface DescriptionListItem {
|
|
9
|
+
label: string;
|
|
10
|
+
value?: any;
|
|
11
|
+
id?: string;
|
|
12
|
+
[key: string]: any;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* DescriptionList — pares rótulo/valor de um documento, em `<dl>`.
|
|
16
|
+
*
|
|
17
|
+
* Dois desenhos para o mesmo dado:
|
|
18
|
+
* - `inline` (padrão): uma linha por par, rótulo pintado à esquerda e valor à
|
|
19
|
+
* direita, numa grade de bordas finas e SEM cabeçalho. Encolhe até o conteúdo
|
|
20
|
+
* (`fit`) ou ocupa a largura toda. É a tabela de "dotação orçamentária" de um
|
|
21
|
+
* despacho.
|
|
22
|
+
* - `stacked`: rótulo pequeno em cima e valor embaixo, em até 4 `columns`. É o
|
|
23
|
+
* bloco "Dados do processo". Com `bordered`, o valor ganha a caixa de um campo
|
|
24
|
+
* somente leitura.
|
|
25
|
+
*
|
|
26
|
+
* O que é do papel fica nela: sem hover, sem foco, sem clique, e na impressão o
|
|
27
|
+
* par nunca é cortado entre duas páginas. Para tabela com cabeçalho de coluna,
|
|
28
|
+
* use `DataTable variant="document"`.
|
|
29
|
+
*
|
|
30
|
+
* Semântica: `<dl>` com `<dt>` e `<dd>`, agrupados por `<div>` (HTML 5.2). O
|
|
31
|
+
* leitor de tela anuncia a lista de termos e a quantidade.
|
|
32
|
+
* @property {DescriptionListItem[]} items - Os pares, na ordem em que aparecem
|
|
33
|
+
* @property {string} layout - 'inline' (padrão) | 'stacked'
|
|
34
|
+
* @property {number} columns - Só no `stacked`: colunas de pares, de 1 a 4 (padrão 2)
|
|
35
|
+
* @property {string} density - 'default' | 'compact'. O compacto leva a fonte a 12px (o tamanho do CrisDoc) e aperta o espaço entre os pares do `stacked`.
|
|
36
|
+
* @property {boolean} bordered - Só no `stacked`: o valor numa caixa de campo somente leitura
|
|
37
|
+
* @property {boolean} fit - Só no `inline`: encolhe até o conteúdo em vez de ocupar a largura toda
|
|
38
|
+
* @property {string} emptyValue - Texto quando o valor vem vazio (padrão: "—")
|
|
39
|
+
* @property {string} ariaLabel - Nome acessível da lista
|
|
40
|
+
* @property {string} ariaLabelledby - Id do título visível que nomeia a lista
|
|
41
|
+
* @property {string} className - Classes CSS adicionais
|
|
42
|
+
* @quandoUsar Dados cadastrais e de empenho dentro do texto de um documento, ficha de processo, bloco de detalhes de uma tela de leitura: qualquer conjunto de "campo: valor".
|
|
43
|
+
* @quandoNaoUsar Para dados com várias linhas comparáveis coluna a coluna, use `DataTable`. Para campos que a pessoa edita, use `Input` e afins. Para valor com marcação (badge, link, botão), a DescriptionList no Vue só mostra texto: monte o bloco com `Stack` e `Text`.
|
|
44
|
+
*/
|
|
45
|
+
export interface DescriptionListProps {
|
|
46
|
+
items?: DescriptionListItem[];
|
|
47
|
+
layout?: "inline" | "stacked";
|
|
48
|
+
columns?: 1 | 2 | 3 | 4;
|
|
49
|
+
bordered?: boolean;
|
|
50
|
+
/** Densidade. `compact`: fonte de 12px e espaço menor entre os pares. @default 'default' */
|
|
51
|
+
density?: "default" | "compact";
|
|
52
|
+
fit?: boolean;
|
|
53
|
+
emptyValue?: string;
|
|
54
|
+
ariaLabel?: string;
|
|
55
|
+
ariaLabelledby?: string;
|
|
56
|
+
className?: string;
|
|
57
|
+
id?: string;
|
|
58
|
+
style?: any;
|
|
59
|
+
[key: string]: any;
|
|
60
|
+
}
|
|
61
|
+
declare function DescriptionList(props: DescriptionListProps): import("react/jsx-runtime").JSX.Element;
|
|
62
|
+
export default DescriptionList;
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import './DescriptionList.css';
|
|
3
|
+
function DescriptionList(props) {
|
|
4
|
+
function itemList() {
|
|
5
|
+
return props.items || [];
|
|
6
|
+
}
|
|
7
|
+
function isStacked() {
|
|
8
|
+
return props.layout === "stacked";
|
|
9
|
+
}
|
|
10
|
+
function classes() {
|
|
11
|
+
const colunas = props.columns || 2;
|
|
12
|
+
return [
|
|
13
|
+
"umds-description-list",
|
|
14
|
+
props.layout === "stacked"
|
|
15
|
+
? "umds-description-list--stacked"
|
|
16
|
+
: "umds-description-list--inline",
|
|
17
|
+
props.layout === "stacked"
|
|
18
|
+
? `umds-description-list--cols-${colunas}`
|
|
19
|
+
: "",
|
|
20
|
+
props.layout === "stacked" && props.bordered
|
|
21
|
+
? "umds-description-list--bordered"
|
|
22
|
+
: "",
|
|
23
|
+
props.layout !== "stacked" && props.fit
|
|
24
|
+
? "umds-description-list--fit"
|
|
25
|
+
: "",
|
|
26
|
+
props.density === "compact" ? "umds-description-list--compact" : "",
|
|
27
|
+
props.className,
|
|
28
|
+
]
|
|
29
|
+
.filter(Boolean)
|
|
30
|
+
.join(" ");
|
|
31
|
+
}
|
|
32
|
+
function valueText(item) {
|
|
33
|
+
const valor = item.value;
|
|
34
|
+
if (valor === undefined || valor === null || valor === "")
|
|
35
|
+
return props.emptyValue || "—";
|
|
36
|
+
return valor;
|
|
37
|
+
}
|
|
38
|
+
function itemKey(item) {
|
|
39
|
+
return item.id || item.label;
|
|
40
|
+
}
|
|
41
|
+
function htmlAttrs() {
|
|
42
|
+
const out = {};
|
|
43
|
+
for (const chave in props) {
|
|
44
|
+
if (chave.indexOf("data-") === 0 || chave === "style") {
|
|
45
|
+
out[chave] = props[chave];
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
return out;
|
|
49
|
+
}
|
|
50
|
+
return (_jsx("dl", { id: props.id, "aria-label": props.ariaLabel, "aria-labelledby": props.ariaLabelledby, ...htmlAttrs(), className: classes(), children: itemList()?.map((item) => (_jsxs("div", { className: "umds-description-list__item", children: [_jsx("dt", { className: "umds-description-list__term", children: item.label }), _jsx("dd", { className: "umds-description-list__description", children: valueText(item) })] }, itemKey(item)))) }));
|
|
51
|
+
}
|
|
52
|
+
export default DescriptionList;
|
|
@@ -4,7 +4,8 @@ import './EmptyState.css';
|
|
|
4
4
|
* @property {IconProp} icon - Ícone FontAwesome: objeto importado (recomendado —
|
|
5
5
|
* ex.: faInbox de free-solid-svg-icons), nome ('inbox') ou par ['far','inbox'].
|
|
6
6
|
* Nomes/pares exigem registro prévio na library. Decorativo (aria-hidden).
|
|
7
|
-
* @property {string} title - Título principal do estado vazio (
|
|
7
|
+
* @property {string} title - Título principal do estado vazio: texto, ou conteúdo rico (um nó no React; no Vue, o slot `title`, com a prop como texto de reserva). O título é um `div`, então aceita negrito, ícone, link.
|
|
8
|
+
* @slot title - Só no Vue. Título com conteúdo rico (no lugar do texto da prop `title`).
|
|
8
9
|
* @property {string} description - Texto de apoio exibido abaixo do título
|
|
9
10
|
* @property {string} actionLabel - Rótulo do botão de ação (exibido junto com onAction)
|
|
10
11
|
* @property {function} onAction - Callback acionado ao clicar no botão de ação
|
|
@@ -15,7 +16,8 @@ import './EmptyState.css';
|
|
|
15
16
|
*/
|
|
16
17
|
export interface EmptyStateProps {
|
|
17
18
|
icon?: IconProp;
|
|
18
|
-
|
|
19
|
+
/** Título: texto ou conteúdo rico. No Vue, texto, ou o slot `title`. */
|
|
20
|
+
title?: any;
|
|
19
21
|
description?: string;
|
|
20
22
|
actionLabel?: string;
|
|
21
23
|
onAction?: () => void;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
3
|
import './EmptyState.css';
|
|
4
4
|
import Icon from "../Icon/Icon";
|
|
5
5
|
function EmptyState(props) {
|
|
@@ -23,6 +23,6 @@ function EmptyState(props) {
|
|
|
23
23
|
return "40px";
|
|
24
24
|
return "32px";
|
|
25
25
|
}
|
|
26
|
-
return (_jsxs("div", { className: classes(), children: [!!props.icon ? (_jsx("div", { "aria-hidden": "true", className: "umds-empty-state__icon-wrap", children: _jsx(Icon, { variant: "inherit", icon: props.icon, customSize: iconSize() }) })) : null, _jsx("
|
|
26
|
+
return (_jsxs("div", { className: classes(), children: [!!props.icon ? (_jsx("div", { "aria-hidden": "true", className: "umds-empty-state__icon-wrap", children: _jsx(Icon, { variant: "inherit", icon: props.icon, customSize: iconSize() }) })) : null, _jsx("div", { className: "umds-empty-state__title", children: _jsx(_Fragment, { children: props.title }) }), !!props.description ? (_jsx("p", { className: "umds-empty-state__desc", children: props.description })) : null, hasAction() ? (_jsx("button", { type: "button", className: "umds-empty-state__action", onClick: (event) => props.onAction && props.onAction(), children: props.actionLabel })) : null] }));
|
|
27
27
|
}
|
|
28
28
|
export default EmptyState;
|
|
@@ -29,6 +29,22 @@
|
|
|
29
29
|
pointer-events: none;
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
+
/* ── Variante trigger: sem caixa; o conteúdo passado é o gatilho ── */
|
|
33
|
+
.umds-file-input--trigger {
|
|
34
|
+
display: inline-flex;
|
|
35
|
+
flex-direction: column;
|
|
36
|
+
align-items: flex-start;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
.umds-file-input__trigger-wrap {
|
|
40
|
+
display: inline-flex;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/* O input não entra no Tab: o gatilho (o botão) é quem recebe o foco. */
|
|
44
|
+
.umds-file-input--trigger .umds-file-input__native {
|
|
45
|
+
position: absolute;
|
|
46
|
+
}
|
|
47
|
+
|
|
32
48
|
/* ── Drop zone ── */
|
|
33
49
|
.umds-file-input__drop-zone {
|
|
34
50
|
cursor: pointer;
|
|
@@ -20,7 +20,7 @@ export interface FileInputFile {
|
|
|
20
20
|
* @property {boolean} multiple - Permite selecionar múltiplos arquivos
|
|
21
21
|
* @property {number} maxSize - Tamanho máximo em bytes (exibido como dica na variante base)
|
|
22
22
|
* @property {boolean} disabled - Desabilita a seleção de arquivos
|
|
23
|
-
* @property {string} variant - Variante visual: 'base' (linha) | 'card' (preview visual)
|
|
23
|
+
* @property {string} variant - Variante visual: 'base' (linha) | 'card' (preview visual) | 'trigger' (sem caixa: o seletor é aberto por outro controle, o conteúdo que você passa, como um `Button` "Anexar arquivo" ou um link "Alterar foto"; o clique nele abre o seletor e o resto (`accept`, `multiple`, `files`, `onChange`) funciona igual)
|
|
24
24
|
* @property {string} label - Rótulo exibido acima do campo
|
|
25
25
|
* @property {FileInputFile[]} files - Arquivos atualmente listados (controlado)
|
|
26
26
|
* @property {string} name - Nome do campo no submit de form nativo. Com name, os File
|
|
@@ -41,7 +41,7 @@ export interface FileInputProps {
|
|
|
41
41
|
multiple?: boolean;
|
|
42
42
|
maxSize?: number;
|
|
43
43
|
disabled?: boolean;
|
|
44
|
-
variant?: "base" | "card";
|
|
44
|
+
variant?: "base" | "card" | "trigger";
|
|
45
45
|
label?: string;
|
|
46
46
|
files?: FileInputFile[];
|
|
47
47
|
name?: string;
|
|
@@ -70,6 +70,8 @@ export interface FileInputProps {
|
|
|
70
70
|
removeAriaLabel?: string;
|
|
71
71
|
/** Prefixo do nome acessível da barra de progresso de um arquivo (recebe o nome do arquivo depois de um espaço). Troque para traduzir. @default 'Enviando' */
|
|
72
72
|
uploadingAriaLabel?: string;
|
|
73
|
+
/** Gatilho da variante `trigger` (o `Button` ou link que abre o seletor). React: filhos; Vue: slot padrão. */
|
|
74
|
+
children?: any;
|
|
73
75
|
onChange?: (files?: File[]) => void;
|
|
74
76
|
onRemove?: (index?: number) => void;
|
|
75
77
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
3
|
import './FileInput.css';
|
|
4
4
|
import { useState, useRef } from "react";
|
|
5
5
|
import { faArrowUpFromBracket, faCloudArrowUp, faFile, faXmark, } from "@fortawesome/free-solid-svg-icons";
|
|
@@ -69,6 +69,12 @@ function FileInput(props) {
|
|
|
69
69
|
setNativeFiles(props.multiple ? [...nativeFiles, ...files] : files);
|
|
70
70
|
applyNativeFiles();
|
|
71
71
|
}
|
|
72
|
+
function openDialog() {
|
|
73
|
+
if (props.disabled)
|
|
74
|
+
return;
|
|
75
|
+
if (inputRef.current)
|
|
76
|
+
inputRef.current.click();
|
|
77
|
+
}
|
|
72
78
|
function handleChange(event) {
|
|
73
79
|
if (props.disabled)
|
|
74
80
|
return;
|
|
@@ -115,7 +121,7 @@ function FileInput(props) {
|
|
|
115
121
|
applyNativeFiles();
|
|
116
122
|
}
|
|
117
123
|
}
|
|
118
|
-
return (_jsxs("div", { className: wrapperClasses(), children: [props.label ? (_jsx("label", { className: "umds-file-input__label", children: props.label })) : null, _jsxs("label", { className: "umds-file-input__drop-zone", onDragOver: (event) => handleDragOver(event), onDragLeave: (event) => handleDragLeave(), onDrop: (event) => handleDrop(event), children: [_jsx("input", { type: "file", className: "umds-file-input__native", ref: inputRef, name: props.name, accept: props.accept, multiple: props.multiple, disabled: props.disabled, onChange: (event) => handleChange(event), "aria-label": props.label || props.selectFileLabel || "Selecionar arquivo", "aria-invalid": props.invalid }), props.variant !== "card" ? (_jsxs("div", { className: "umds-file-input__trigger", children: [_jsx("span", { "aria-hidden": "true", className: "umds-file-input__upload-icon", children: _jsx(Icon, { variant: "inherit", customSize: "20px", icon: faArrowUpFromBracket }) }), _jsxs("span", { className: "umds-file-input__trigger-text", children: [_jsx("strong", { children: props.triggerLabel || "Clique para selecionar" }), triggerHintText()] }), props.accept ? (_jsx("span", { className: "umds-file-input__hint", children: props.accept })) : null, props.maxSize ? (_jsx("span", { className: "umds-file-input__hint", children: maxSizeText() })) : null] })) : null, props.variant === "card" ? (_jsxs("div", { className: "umds-file-input__card-zone", children: [_jsx("span", { "aria-hidden": "true", className: "umds-file-input__card-icon", children: _jsx(Icon, { variant: "inherit", customSize: "32px", icon: faCloudArrowUp }) }), _jsxs("span", { className: "umds-file-input__card-text", children: [_jsx("strong", { children: props.dropLabel || "Arraste e solte" }), orText(), _jsx("span", { className: "umds-file-input__card-link", children: props.browseLabel || "clique para escolher" })] })] })) : null] }), hasFiles() ? (_jsx("ul", { className: "umds-file-input__list", children: filesList()?.map((file, idx) => (_jsxs("li", { className: fileClasses(file), children: [_jsxs("div", { className: "umds-file-input__file-row", children: [_jsx("span", { "aria-hidden": "true", className: "umds-file-input__file-avatar", children: _jsx(Icon, { variant: "inherit", customSize: "16px", icon: faFile }) }), _jsxs("div", { className: "umds-file-input__file-info", children: [_jsx("span", { className: "umds-file-input__file-name", children: file.name }), file.status !== "uploading" ? (_jsx("span", { className: "umds-file-input__file-size", children: formatSize(file.size) })) : null, file.error ? (_jsx("span", { className: "umds-file-input__file-error", children: file.error })) : null] }), _jsx("button", { type: "button", className: "umds-file-input__file-remove", onClick: (event) => handleRemove(idx), "aria-label": removeFileLabel(file.name), children: _jsx(Icon, { variant: "inherit", customSize: "10px", icon: faXmark }) })] }), file.status === "uploading" && file.progress !== undefined ? (_jsx("div", { role: "progressbar", className: "umds-file-input__progress-bar", "aria-valuenow": file.progress, "aria-valuemin": 0, "aria-valuemax": 100, "aria-label": uploadingFileLabel(file.name), children: _jsx("div", { className: "umds-file-input__progress-fill", style: {
|
|
124
|
+
return (_jsxs("div", { className: wrapperClasses(), children: [props.label && props.variant !== "trigger" ? (_jsx("label", { className: "umds-file-input__label", children: props.label })) : null, props.variant === "trigger" ? (_jsxs(_Fragment, { children: [_jsx("span", { className: "umds-file-input__trigger-wrap", onClick: (event) => openDialog(), children: _jsx(_Fragment, { children: props.children }) }), _jsx("input", { type: "file", className: "umds-file-input__native", ref: inputRef, name: props.name, accept: props.accept, multiple: props.multiple, disabled: props.disabled, onChange: (event) => handleChange(event), "aria-label": props.label || props.selectFileLabel || "Selecionar arquivo", "aria-invalid": props.invalid, tabIndex: -1 })] })) : null, props.variant !== "trigger" ? (_jsxs("label", { className: "umds-file-input__drop-zone", onDragOver: (event) => handleDragOver(event), onDragLeave: (event) => handleDragLeave(), onDrop: (event) => handleDrop(event), children: [_jsx("input", { type: "file", className: "umds-file-input__native", ref: inputRef, name: props.name, accept: props.accept, multiple: props.multiple, disabled: props.disabled, onChange: (event) => handleChange(event), "aria-label": props.label || props.selectFileLabel || "Selecionar arquivo", "aria-invalid": props.invalid }), props.variant !== "card" ? (_jsxs("div", { className: "umds-file-input__trigger", children: [_jsx("span", { "aria-hidden": "true", className: "umds-file-input__upload-icon", children: _jsx(Icon, { variant: "inherit", customSize: "20px", icon: faArrowUpFromBracket }) }), _jsxs("span", { className: "umds-file-input__trigger-text", children: [_jsx("strong", { children: props.triggerLabel || "Clique para selecionar" }), triggerHintText()] }), props.accept ? (_jsx("span", { className: "umds-file-input__hint", children: props.accept })) : null, props.maxSize ? (_jsx("span", { className: "umds-file-input__hint", children: maxSizeText() })) : null] })) : null, props.variant === "card" ? (_jsxs("div", { className: "umds-file-input__card-zone", children: [_jsx("span", { "aria-hidden": "true", className: "umds-file-input__card-icon", children: _jsx(Icon, { variant: "inherit", customSize: "32px", icon: faCloudArrowUp }) }), _jsxs("span", { className: "umds-file-input__card-text", children: [_jsx("strong", { children: props.dropLabel || "Arraste e solte" }), orText(), _jsx("span", { className: "umds-file-input__card-link", children: props.browseLabel || "clique para escolher" })] })] })) : null] })) : null, hasFiles() ? (_jsx("ul", { className: "umds-file-input__list", children: filesList()?.map((file, idx) => (_jsxs("li", { className: fileClasses(file), children: [_jsxs("div", { className: "umds-file-input__file-row", children: [_jsx("span", { "aria-hidden": "true", className: "umds-file-input__file-avatar", children: _jsx(Icon, { variant: "inherit", customSize: "16px", icon: faFile }) }), _jsxs("div", { className: "umds-file-input__file-info", children: [_jsx("span", { className: "umds-file-input__file-name", children: file.name }), file.status !== "uploading" ? (_jsx("span", { className: "umds-file-input__file-size", children: formatSize(file.size) })) : null, file.error ? (_jsx("span", { className: "umds-file-input__file-error", children: file.error })) : null] }), _jsx("button", { type: "button", className: "umds-file-input__file-remove", onClick: (event) => handleRemove(idx), "aria-label": removeFileLabel(file.name), children: _jsx(Icon, { variant: "inherit", customSize: "10px", icon: faXmark }) })] }), file.status === "uploading" && file.progress !== undefined ? (_jsx("div", { role: "progressbar", className: "umds-file-input__progress-bar", "aria-valuenow": file.progress, "aria-valuemin": 0, "aria-valuemax": 100, "aria-label": uploadingFileLabel(file.name), children: _jsx("div", { className: "umds-file-input__progress-fill", style: {
|
|
119
125
|
width: `${file.progress}%`,
|
|
120
126
|
} }) })) : null] }, idx))) })) : null, props.invalid && props.errorMessage ? (_jsx("span", { role: "alert", className: "umds-file-input__error", children: props.errorMessage })) : null, !props.invalid && props.helperText ? (_jsx("span", { className: "umds-file-input__helper", children: props.helperText })) : null] }));
|
|
121
127
|
}
|
|
@@ -41,16 +41,16 @@ function Grid(props) {
|
|
|
41
41
|
}
|
|
42
42
|
return classList.filter(Boolean).join(" ");
|
|
43
43
|
}
|
|
44
|
-
function
|
|
44
|
+
function estiloInline() {
|
|
45
45
|
const styleObj = {};
|
|
46
46
|
if (props.container && props.spacing) {
|
|
47
47
|
const gapValue = `var(--umds-primitive-spacing-${props.spacing})`;
|
|
48
48
|
styleObj.gap = gapValue;
|
|
49
49
|
styleObj["--umds-grid-gap"] = gapValue;
|
|
50
50
|
}
|
|
51
|
-
// O gerador Vue do Mitosis
|
|
52
|
-
//
|
|
53
|
-
//
|
|
51
|
+
// O getter NÃO se chama `style`: o gerador Vue do Mitosis troca toda
|
|
52
|
+
// ocorrência da palavra (até a string "style" e comentário) por
|
|
53
|
+
// `style.value`, e o estilo do consumidor deixava de passar.
|
|
54
54
|
return styleObj;
|
|
55
55
|
}
|
|
56
56
|
function htmlAttrs() {
|
|
@@ -67,6 +67,6 @@ function Grid(props) {
|
|
|
67
67
|
}
|
|
68
68
|
return out;
|
|
69
69
|
}
|
|
70
|
-
return (_jsx("div", { id: props.id, style:
|
|
70
|
+
return (_jsx("div", { id: props.id, style: estiloInline(), ...htmlAttrs(), className: classes(), children: _jsx(_Fragment, { children: props.children }) }));
|
|
71
71
|
}
|
|
72
72
|
export default Grid;
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
/* ─────────────────────────────────────────────
|
|
2
|
+
ICON PICKER
|
|
3
|
+
Grade de ícones com busca. O escolhido ganha o fundo e a borda do primário.
|
|
4
|
+
|
|
5
|
+
Cores: semânticos · Medidas: primitivos
|
|
6
|
+
───────────────────────────────────────────── */
|
|
7
|
+
|
|
8
|
+
.umds-icon-picker {
|
|
9
|
+
display: flex;
|
|
10
|
+
flex-direction: column;
|
|
11
|
+
gap: var(--umds-primitive-spacing-nano); /* 8px */
|
|
12
|
+
font-family: var(--umds-semantic-font-family-base);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
.umds-icon-picker__label {
|
|
16
|
+
font-size: var(--umds-semantic-field-label-size);
|
|
17
|
+
font-weight: var(--umds-semantic-field-label-weight);
|
|
18
|
+
color: var(--umds-semantic-field-label-color);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/* Só para leitor de tela: "12 ícones", a cada busca. */
|
|
22
|
+
.umds-icon-picker__sr {
|
|
23
|
+
position: absolute;
|
|
24
|
+
width: 1px;
|
|
25
|
+
height: 1px;
|
|
26
|
+
padding: 0;
|
|
27
|
+
margin: -1px;
|
|
28
|
+
overflow: hidden;
|
|
29
|
+
clip: rect(0, 0, 0, 0);
|
|
30
|
+
clip-path: inset(50%);
|
|
31
|
+
white-space: nowrap;
|
|
32
|
+
border: 0;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/* ── Grade ── */
|
|
36
|
+
/* Tamanho do ladrilho: o ícone escolhe, a grade só repete (nada estica quando o container é largo). */
|
|
37
|
+
.umds-icon-picker--md {
|
|
38
|
+
--umds-icon-picker-tile: var(--umds-primitive-spacing-sm); /* 40px */
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
.umds-icon-picker--sm {
|
|
42
|
+
--umds-icon-picker-tile: var(--umds-primitive-spacing-xs); /* 32px */
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
.umds-icon-picker__grid {
|
|
46
|
+
display: grid;
|
|
47
|
+
justify-content: start;
|
|
48
|
+
gap: var(--umds-primitive-spacing-quarck); /* 4px */
|
|
49
|
+
/* Folga para o anel de foco não ser cortado pelo overflow da grade. */
|
|
50
|
+
padding: var(--umds-primitive-spacing-quarck);
|
|
51
|
+
overflow-y: auto;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
.umds-icon-picker__item {
|
|
55
|
+
display: inline-flex;
|
|
56
|
+
align-items: center;
|
|
57
|
+
justify-content: center;
|
|
58
|
+
box-sizing: border-box;
|
|
59
|
+
min-width: 0;
|
|
60
|
+
margin: 0;
|
|
61
|
+
padding: 0;
|
|
62
|
+
width: var(--umds-icon-picker-tile);
|
|
63
|
+
height: var(--umds-icon-picker-tile);
|
|
64
|
+
border: var(--umds-primitive-border-width-hairline) solid var(--umds-semantic-color-neutral-light-medium);
|
|
65
|
+
border-radius: var(--umds-primitive-border-radius-sm);
|
|
66
|
+
background: var(--umds-semantic-color-background-white);
|
|
67
|
+
color: var(--umds-semantic-color-neutral-dark-down);
|
|
68
|
+
cursor: pointer;
|
|
69
|
+
transition:
|
|
70
|
+
background-color var(--umds-semantic-motion-duration-fast) var(--umds-semantic-motion-easing-standard),
|
|
71
|
+
border-color var(--umds-semantic-motion-duration-fast) var(--umds-semantic-motion-easing-standard),
|
|
72
|
+
color var(--umds-semantic-motion-duration-fast) var(--umds-semantic-motion-easing-standard);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
.umds-icon-picker__item:hover:not(:disabled) {
|
|
76
|
+
background: var(--umds-semantic-color-background-light);
|
|
77
|
+
border-color: var(--umds-semantic-color-neutral-light-down);
|
|
78
|
+
color: var(--umds-semantic-color-neutral-dark-pure);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
.umds-icon-picker__item--selected,
|
|
82
|
+
.umds-icon-picker__item--selected:hover:not(:disabled) {
|
|
83
|
+
background: var(--umds-semantic-color-primary-light);
|
|
84
|
+
border-color: var(--umds-semantic-color-primary-pure);
|
|
85
|
+
color: var(--umds-semantic-color-primary-dark);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
.umds-icon-picker__item:focus-visible {
|
|
89
|
+
outline: var(--umds-primitive-border-width-thin) solid var(--umds-semantic-color-primary-pure);
|
|
90
|
+
outline-offset: var(--umds-primitive-border-width-thin);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
.umds-icon-picker__item:disabled {
|
|
94
|
+
cursor: not-allowed;
|
|
95
|
+
opacity: var(--umds-semantic-field-disabled-opacity);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
.umds-icon-picker__empty {
|
|
99
|
+
padding: var(--umds-primitive-spacing-xxxs) 0; /* 16px */
|
|
100
|
+
text-align: center;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
@media (forced-colors: active) {
|
|
104
|
+
.umds-icon-picker__item--selected {
|
|
105
|
+
outline: var(--umds-primitive-border-width-thin) solid Highlight;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import './IconPicker.css';
|
|
2
|
+
/**
|
|
3
|
+
* Ícone do IconPicker, quando precisa de nome ou palavras de busca próprios.
|
|
4
|
+
* @property {any} icon - O ícone: o objeto importado do Font Awesome (`faUser`).
|
|
5
|
+
* @property {string} label - Nome para leitor de tela, tooltip e busca (padrão: o nome do ícone, sem hífen).
|
|
6
|
+
* @property {string[]} keywords - Palavras que também acham o ícone na busca (ex.: ["pessoa", "usuário"]).
|
|
7
|
+
*/
|
|
8
|
+
export interface IconPickerItem {
|
|
9
|
+
icon: any;
|
|
10
|
+
label?: string;
|
|
11
|
+
keywords?: string[];
|
|
12
|
+
[key: string]: any;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* IconPicker — escolha de UM ícone numa grade, com busca.
|
|
16
|
+
*
|
|
17
|
+
* Os ícones vêm por prop (`icons`): objetos do Font Awesome importados
|
|
18
|
+
* (`faUser`, `faFolder`...), puros ou embrulhados em `{ icon, label, keywords }`
|
|
19
|
+
* quando o nome ou a busca precisam de ajuda. O valor é o NOME do ícone
|
|
20
|
+
* (`"user"`, `"file-lines"`), o `iconName` do Font Awesome: guarde o nome e
|
|
21
|
+
* resolva de volta para o objeto na hora de desenhar.
|
|
22
|
+
*
|
|
23
|
+
* É um `radiogroup`: um Tab entra na grade (no ícone escolhido, ou no primeiro)
|
|
24
|
+
* e as setas movem a escolha (esquerda e direita um ícone, cima e baixo uma
|
|
25
|
+
* linha), com Home e End nas pontas. A busca (campo acima da grade, ligada por
|
|
26
|
+
* padrão) filtra por nome e palavras-chave sem acento nem caixa; a seta para
|
|
27
|
+
* baixo no campo leva à grade, e o número de resultados é anunciado.
|
|
28
|
+
*
|
|
29
|
+
* O ícone escolhido ganha fundo e borda do primário, e o resultado vazio mostra
|
|
30
|
+
* `emptyText`. A altura da grade pode ser limitada (`maxHeight`) para listas com
|
|
31
|
+
* dezenas de ícones.
|
|
32
|
+
* @property {any[]} icons - Os ícones: objetos do Font Awesome, ou `{ icon, label?, keywords? }`
|
|
33
|
+
* @property {string} value - Nome do ícone escolhido (controlado)
|
|
34
|
+
* @property {string} defaultValue - Nome inicial (não controlado)
|
|
35
|
+
* @property {string} label - Rótulo visível do grupo
|
|
36
|
+
* @property {string} ariaLabel - Nome acessível quando não há `label` visível
|
|
37
|
+
* @property {number} columns - Colunas da grade (padrão 8)
|
|
38
|
+
* @property {string} size - Tamanho do ícone: 'sm' | 'md' (padrão)
|
|
39
|
+
* @property {number} maxHeight - Altura máxima da grade, em px (rola dentro dela)
|
|
40
|
+
* @property {boolean} hideSearch - Esconde o campo de busca
|
|
41
|
+
* @property {string} searchLabel - Nome do campo de busca (padrão "Buscar ícone")
|
|
42
|
+
* @property {string} searchPlaceholder - Placeholder da busca (padrão "Buscar ícone...")
|
|
43
|
+
* @property {string} emptyText - Texto sem resultados (padrão "Nenhum ícone encontrado")
|
|
44
|
+
* @property {string} resultsLabel - Anúncio da quantidade de resultados; `{count}` vira o número (padrão "{count} ícones")
|
|
45
|
+
* @property {function} iconLabel - Nome de um ícone sem `label`: `(nome) => texto` (padrão: o nome sem hífen)
|
|
46
|
+
* @property {boolean} disabled - Desabilita o grupo inteiro
|
|
47
|
+
* @property {string} id - Base dos ids internos; passe em SSR para os ids já saírem no HTML do servidor
|
|
48
|
+
* @property {string} className - Classes CSS adicionais
|
|
49
|
+
* @property {function} onChange - Chamado com o nome do ícone e o item escolhido
|
|
50
|
+
* @quandoUsar Escolher o ícone de uma categoria, de um tipo de documento, de um perfil, de um atalho.
|
|
51
|
+
* @quandoNaoUsar Para escolher entre poucas opções que o texto descreve melhor, use `SegmentedControl` ou `Select`. Para escolher uma cor, use `ColorPicker`.
|
|
52
|
+
*/
|
|
53
|
+
export interface IconPickerProps {
|
|
54
|
+
icons?: any[];
|
|
55
|
+
value?: string;
|
|
56
|
+
defaultValue?: string;
|
|
57
|
+
label?: string;
|
|
58
|
+
ariaLabel?: string;
|
|
59
|
+
columns?: number;
|
|
60
|
+
size?: "sm" | "md";
|
|
61
|
+
maxHeight?: number;
|
|
62
|
+
hideSearch?: boolean;
|
|
63
|
+
searchLabel?: string;
|
|
64
|
+
searchPlaceholder?: string;
|
|
65
|
+
emptyText?: string;
|
|
66
|
+
resultsLabel?: string;
|
|
67
|
+
iconLabel?: (name: string) => string;
|
|
68
|
+
disabled?: boolean;
|
|
69
|
+
id?: string;
|
|
70
|
+
className?: string;
|
|
71
|
+
onChange?: (name: string, item: any) => void;
|
|
72
|
+
}
|
|
73
|
+
declare function IconPicker(props: IconPickerProps): import("react/jsx-runtime").JSX.Element;
|
|
74
|
+
export default IconPicker;
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import './IconPicker.css';
|
|
4
|
+
import { useState, useRef, useEffect } from "react";
|
|
5
|
+
import Icon from "../Icon/Icon";
|
|
6
|
+
import Input from "../Input/Input";
|
|
7
|
+
import Text from "../Text/Text";
|
|
8
|
+
import { gerarId } from "../../utils/id";
|
|
9
|
+
import { semAcento } from "../../utils/texto";
|
|
10
|
+
import { faMagnifyingGlass } from "@fortawesome/free-solid-svg-icons";
|
|
11
|
+
function IconPicker(props) {
|
|
12
|
+
const groupRef = useRef(null);
|
|
13
|
+
const focoPendenteRef = useRef(-1);
|
|
14
|
+
const [internalValue, setInternalValue] = useState(() => props.defaultValue || "");
|
|
15
|
+
const [query, setQuery] = useState(() => "");
|
|
16
|
+
const [uid, setUid] = useState(() => "");
|
|
17
|
+
function baseId() {
|
|
18
|
+
return props.id || uid;
|
|
19
|
+
}
|
|
20
|
+
function labelId() {
|
|
21
|
+
return baseId() && props.label ? baseId() + "-label" : undefined;
|
|
22
|
+
}
|
|
23
|
+
function groupAriaLabel() {
|
|
24
|
+
if (props.ariaLabel)
|
|
25
|
+
return props.ariaLabel;
|
|
26
|
+
return props.label && !labelId() ? props.label : undefined;
|
|
27
|
+
}
|
|
28
|
+
function currentValue() {
|
|
29
|
+
return props.value !== undefined ? props.value : internalValue;
|
|
30
|
+
}
|
|
31
|
+
function columnCount() {
|
|
32
|
+
return props.columns && props.columns > 0 ? props.columns : 8;
|
|
33
|
+
}
|
|
34
|
+
function classes() {
|
|
35
|
+
return [
|
|
36
|
+
"umds-icon-picker",
|
|
37
|
+
`umds-icon-picker--${props.size || "md"}`,
|
|
38
|
+
props.disabled ? "umds-icon-picker--disabled" : "",
|
|
39
|
+
props.className,
|
|
40
|
+
]
|
|
41
|
+
.filter(Boolean)
|
|
42
|
+
.join(" ");
|
|
43
|
+
}
|
|
44
|
+
function gridStyle() {
|
|
45
|
+
const estilo = {
|
|
46
|
+
gridTemplateColumns: "repeat(" + columnCount() + ", var(--umds-icon-picker-tile))",
|
|
47
|
+
};
|
|
48
|
+
if (props.maxHeight)
|
|
49
|
+
estilo.maxHeight = props.maxHeight + "px";
|
|
50
|
+
return estilo;
|
|
51
|
+
}
|
|
52
|
+
function nomeDe(icone) {
|
|
53
|
+
if (!icone)
|
|
54
|
+
return "";
|
|
55
|
+
if (typeof icone === "string")
|
|
56
|
+
return icone;
|
|
57
|
+
return icone.iconName || "";
|
|
58
|
+
}
|
|
59
|
+
function rotuloDe(nome) {
|
|
60
|
+
if (props.iconLabel)
|
|
61
|
+
return props.iconLabel(nome);
|
|
62
|
+
return nome.replace(/-/g, " ");
|
|
63
|
+
}
|
|
64
|
+
function itemList() {
|
|
65
|
+
const lista = props.icons || [];
|
|
66
|
+
const saida = [];
|
|
67
|
+
for (let i = 0; i < lista.length; i++) {
|
|
68
|
+
const bruto = lista[i];
|
|
69
|
+
const embrulhado = !!bruto && bruto.icon !== undefined && bruto.iconName === undefined;
|
|
70
|
+
const icone = embrulhado ? bruto.icon : bruto;
|
|
71
|
+
const nome = nomeDe(icone);
|
|
72
|
+
if (!nome)
|
|
73
|
+
continue;
|
|
74
|
+
const rotulo = embrulhado && bruto.label ? bruto.label : rotuloDe(nome);
|
|
75
|
+
const palavras = embrulhado && bruto.keywords ? bruto.keywords.join(" ") : "";
|
|
76
|
+
saida.push({
|
|
77
|
+
name: nome,
|
|
78
|
+
label: rotulo,
|
|
79
|
+
icon: icone,
|
|
80
|
+
raw: bruto,
|
|
81
|
+
search: semAcento(nome + " " + rotulo + " " + palavras),
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
return saida;
|
|
85
|
+
}
|
|
86
|
+
function visibleItems() {
|
|
87
|
+
const busca = semAcento(query);
|
|
88
|
+
if (!busca)
|
|
89
|
+
return itemList();
|
|
90
|
+
return itemList().filter((item) => item.search.indexOf(busca) !== -1);
|
|
91
|
+
}
|
|
92
|
+
function hasResults() {
|
|
93
|
+
return visibleItems().length > 0;
|
|
94
|
+
}
|
|
95
|
+
function emptyMessage() {
|
|
96
|
+
return props.emptyText || "Nenhum ícone encontrado";
|
|
97
|
+
}
|
|
98
|
+
function resultsText() {
|
|
99
|
+
return (props.resultsLabel || "{count} ícones").replace("{count}", String(visibleItems().length));
|
|
100
|
+
}
|
|
101
|
+
function searchName() {
|
|
102
|
+
return props.searchLabel || "Buscar ícone";
|
|
103
|
+
}
|
|
104
|
+
function estaEscolhido(item) {
|
|
105
|
+
return !!currentValue() && item.name === currentValue();
|
|
106
|
+
}
|
|
107
|
+
function itemClasses(item) {
|
|
108
|
+
return [
|
|
109
|
+
"umds-icon-picker__item",
|
|
110
|
+
estaEscolhido(item) ? "umds-icon-picker__item--selected" : "",
|
|
111
|
+
]
|
|
112
|
+
.filter(Boolean)
|
|
113
|
+
.join(" ");
|
|
114
|
+
}
|
|
115
|
+
function indiceDoTab() {
|
|
116
|
+
const lista = visibleItems();
|
|
117
|
+
for (let i = 0; i < lista.length; i++) {
|
|
118
|
+
if (estaEscolhido(lista[i]))
|
|
119
|
+
return i;
|
|
120
|
+
}
|
|
121
|
+
return 0;
|
|
122
|
+
}
|
|
123
|
+
function tabIndexDe(index) {
|
|
124
|
+
return index === indiceDoTab() ? 0 : -1;
|
|
125
|
+
}
|
|
126
|
+
function escolher(item) {
|
|
127
|
+
if (props.disabled)
|
|
128
|
+
return;
|
|
129
|
+
setInternalValue(item.name);
|
|
130
|
+
if (props.onChange)
|
|
131
|
+
props.onChange(item.name, item.raw);
|
|
132
|
+
}
|
|
133
|
+
function focarEm(index) {
|
|
134
|
+
if (!groupRef.current)
|
|
135
|
+
return;
|
|
136
|
+
const botoes = groupRef.current.querySelectorAll('[role="radio"]');
|
|
137
|
+
const alvo = botoes[index];
|
|
138
|
+
if (alvo)
|
|
139
|
+
alvo.focus();
|
|
140
|
+
}
|
|
141
|
+
function handleKeyDown(event, index) {
|
|
142
|
+
if (!event || event.altKey || event.ctrlKey || event.metaKey)
|
|
143
|
+
return;
|
|
144
|
+
const lista = visibleItems();
|
|
145
|
+
const total = lista.length;
|
|
146
|
+
if (!total)
|
|
147
|
+
return;
|
|
148
|
+
const colunas = columnCount();
|
|
149
|
+
let alvo = index;
|
|
150
|
+
if (event.key === "ArrowRight")
|
|
151
|
+
alvo = (index + 1) % total;
|
|
152
|
+
else if (event.key === "ArrowLeft")
|
|
153
|
+
alvo = (index - 1 + total) % total;
|
|
154
|
+
else if (event.key === "ArrowDown")
|
|
155
|
+
alvo = index + colunas < total ? index + colunas : index;
|
|
156
|
+
else if (event.key === "ArrowUp")
|
|
157
|
+
alvo = index - colunas >= 0 ? index - colunas : index;
|
|
158
|
+
else if (event.key === "Home")
|
|
159
|
+
alvo = 0;
|
|
160
|
+
else if (event.key === "End")
|
|
161
|
+
alvo = total - 1;
|
|
162
|
+
else
|
|
163
|
+
return;
|
|
164
|
+
event.preventDefault();
|
|
165
|
+
if (alvo === index &&
|
|
166
|
+
event.key !== "ArrowRight" &&
|
|
167
|
+
event.key !== "ArrowLeft")
|
|
168
|
+
return;
|
|
169
|
+
escolher(lista[alvo]);
|
|
170
|
+
focoPendenteRef.current = alvo;
|
|
171
|
+
}
|
|
172
|
+
function handleSearch(texto) {
|
|
173
|
+
setQuery(texto);
|
|
174
|
+
}
|
|
175
|
+
function handleSearchKeyDown(event) {
|
|
176
|
+
if (!event || event.key !== "ArrowDown" || !hasResults())
|
|
177
|
+
return;
|
|
178
|
+
event.preventDefault();
|
|
179
|
+
focarEm(indiceDoTab());
|
|
180
|
+
}
|
|
181
|
+
useEffect(() => {
|
|
182
|
+
if (!props.id)
|
|
183
|
+
setUid(gerarId("umds-icon-picker"));
|
|
184
|
+
}, []);
|
|
185
|
+
useEffect(() => {
|
|
186
|
+
if (focoPendenteRef.current >= 0) {
|
|
187
|
+
const alvo = focoPendenteRef.current;
|
|
188
|
+
focoPendenteRef.current = -1;
|
|
189
|
+
focarEm(alvo);
|
|
190
|
+
}
|
|
191
|
+
});
|
|
192
|
+
return (_jsxs("div", { className: classes(), children: [props.label ? (_jsx("span", { className: "umds-icon-picker__label", id: labelId(), children: props.label })) : null, !props.hideSearch ? (_jsx("div", { className: "umds-icon-picker__search", onKeyDown: (event) => handleSearchKeyDown(event), children: _jsx(Input, { size: "sm", type: "search", ariaLabel: searchName(), placeholder: props.searchPlaceholder || "Buscar ícone...", iconLeft: faMagnifyingGlass, value: query, disabled: props.disabled, onChange: (texto) => handleSearch(texto) }) })) : null, _jsx("span", { role: "status", "aria-live": "polite", className: "umds-icon-picker__sr", children: resultsText() }), hasResults() ? (_jsx("div", { role: "radiogroup", className: "umds-icon-picker__grid", ref: groupRef, "aria-label": groupAriaLabel(), "aria-labelledby": labelId(), style: gridStyle(), children: visibleItems()?.map((item, posicao) => (_jsx("button", { type: "button", role: "radio", "aria-checked": estaEscolhido(item) ? "true" : "false", "aria-label": item.label, title: item.label, disabled: props.disabled, tabIndex: tabIndexDe(posicao), onClick: (event) => escolher(item), onKeyDown: (event) => handleKeyDown(event, posicao), className: itemClasses(item), children: _jsx(Icon, { variant: "inherit", icon: item.icon, size: props.size === "sm" ? "sm" : "md" }) }, item.name))) })) : null, !hasResults() ? (_jsx("div", { className: "umds-icon-picker__empty", children: _jsx(Text, { as: "p", variant: "body2", color: "secondary", children: emptyMessage() }) })) : null] }));
|
|
193
|
+
}
|
|
194
|
+
export default IconPicker;
|