@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,215 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import './OtpInput.css';
|
|
4
|
+
import { useState, useRef, useEffect } from "react";
|
|
5
|
+
import Text from "../Text/Text";
|
|
6
|
+
import { gerarId } from "../../utils/id";
|
|
7
|
+
function OtpInput(props) {
|
|
8
|
+
const groupRef = useRef(null);
|
|
9
|
+
const ultimoEventoRef = useRef(null);
|
|
10
|
+
const focoPendenteRef = useRef(-1);
|
|
11
|
+
const [internalValue, setInternalValue] = useState(() => props.defaultValue || "");
|
|
12
|
+
const [uid, setUid] = useState(() => "");
|
|
13
|
+
function baseId() {
|
|
14
|
+
return props.id || uid;
|
|
15
|
+
}
|
|
16
|
+
function codeLength() {
|
|
17
|
+
const n = props.length || 6;
|
|
18
|
+
return n < 1 ? 1 : n;
|
|
19
|
+
}
|
|
20
|
+
function positions() {
|
|
21
|
+
return Array.from({
|
|
22
|
+
length: codeLength(),
|
|
23
|
+
}, (_, i) => i);
|
|
24
|
+
}
|
|
25
|
+
function isAlpha() {
|
|
26
|
+
return props.type === "alphanumeric";
|
|
27
|
+
}
|
|
28
|
+
function limpar(texto) {
|
|
29
|
+
const bruto = texto || "";
|
|
30
|
+
const aceito = isAlpha()
|
|
31
|
+
? bruto.replace(/[^0-9a-zA-Z]/g, "").toUpperCase()
|
|
32
|
+
: bruto.replace(/[^0-9]/g, "");
|
|
33
|
+
return aceito;
|
|
34
|
+
}
|
|
35
|
+
function currentValue() {
|
|
36
|
+
const bruto = props.value !== undefined ? props.value : internalValue;
|
|
37
|
+
return limpar(bruto).slice(0, codeLength());
|
|
38
|
+
}
|
|
39
|
+
function charAt(index) {
|
|
40
|
+
return currentValue().charAt(index);
|
|
41
|
+
}
|
|
42
|
+
function isInvalid() {
|
|
43
|
+
return !!props.invalid || !!props.errorMessage;
|
|
44
|
+
}
|
|
45
|
+
function labelId() {
|
|
46
|
+
return baseId() && props.label ? baseId() + "-label" : undefined;
|
|
47
|
+
}
|
|
48
|
+
function errorId() {
|
|
49
|
+
return baseId() && props.errorMessage ? baseId() + "-error" : undefined;
|
|
50
|
+
}
|
|
51
|
+
function groupAriaLabel() {
|
|
52
|
+
if (props.ariaLabel)
|
|
53
|
+
return props.ariaLabel;
|
|
54
|
+
return props.label && !labelId() ? props.label : undefined;
|
|
55
|
+
}
|
|
56
|
+
function ariaInvalidText() {
|
|
57
|
+
return isInvalid() ? "true" : undefined;
|
|
58
|
+
}
|
|
59
|
+
function classes() {
|
|
60
|
+
return [
|
|
61
|
+
"umds-otp",
|
|
62
|
+
`umds-otp--${props.size || "md"}`,
|
|
63
|
+
isInvalid() ? "umds-otp--invalid" : "",
|
|
64
|
+
props.disabled ? "umds-otp--disabled" : "",
|
|
65
|
+
props.className,
|
|
66
|
+
]
|
|
67
|
+
.filter(Boolean)
|
|
68
|
+
.join(" ");
|
|
69
|
+
}
|
|
70
|
+
function digitName(index) {
|
|
71
|
+
const modelo = props.digitLabel || "Dígito {n} de {total}";
|
|
72
|
+
return modelo
|
|
73
|
+
.replace("{n}", String(index + 1))
|
|
74
|
+
.replace("{total}", String(codeLength()));
|
|
75
|
+
}
|
|
76
|
+
function inputMode() {
|
|
77
|
+
return isAlpha() ? "text" : "numeric";
|
|
78
|
+
}
|
|
79
|
+
function autoComplete(index) {
|
|
80
|
+
return index === 0 ? "one-time-code" : "off";
|
|
81
|
+
}
|
|
82
|
+
function digitId(index) {
|
|
83
|
+
return baseId() ? baseId() + "-" + index : undefined;
|
|
84
|
+
}
|
|
85
|
+
function definir(proximo) {
|
|
86
|
+
const novo = limpar(proximo).slice(0, codeLength());
|
|
87
|
+
const antigo = currentValue();
|
|
88
|
+
if (novo === antigo)
|
|
89
|
+
return false;
|
|
90
|
+
setInternalValue(novo);
|
|
91
|
+
if (props.onChange)
|
|
92
|
+
props.onChange(novo);
|
|
93
|
+
if (novo.length === codeLength() && props.onComplete)
|
|
94
|
+
props.onComplete(novo);
|
|
95
|
+
return true;
|
|
96
|
+
}
|
|
97
|
+
function focarDepois(index, mudou) {
|
|
98
|
+
if (mudou)
|
|
99
|
+
focoPendenteRef.current = index;
|
|
100
|
+
else
|
|
101
|
+
focarEm(index);
|
|
102
|
+
}
|
|
103
|
+
function focarEm(index) {
|
|
104
|
+
if (!groupRef.current)
|
|
105
|
+
return;
|
|
106
|
+
const caixas = groupRef.current.querySelectorAll("input");
|
|
107
|
+
const alvo = caixas[Math.max(0, Math.min(index, codeLength() - 1))];
|
|
108
|
+
if (alvo)
|
|
109
|
+
alvo.focus();
|
|
110
|
+
}
|
|
111
|
+
function limiteDoFoco() {
|
|
112
|
+
return Math.min(currentValue().length, codeLength() - 1);
|
|
113
|
+
}
|
|
114
|
+
function handleInput(event, index) {
|
|
115
|
+
const nativo = event.nativeEvent || event;
|
|
116
|
+
if (nativo === ultimoEventoRef.current)
|
|
117
|
+
return;
|
|
118
|
+
ultimoEventoRef.current = nativo;
|
|
119
|
+
const alvo = event.target;
|
|
120
|
+
const bruto = alvo.value || "";
|
|
121
|
+
const atual = charAt(index);
|
|
122
|
+
const valor = currentValue();
|
|
123
|
+
// Apagou: o código fecha o buraco (os de trás andam um para a frente).
|
|
124
|
+
if (bruto === "") {
|
|
125
|
+
const sem = atual
|
|
126
|
+
? valor.slice(0, index) + valor.slice(index + 1)
|
|
127
|
+
: valor;
|
|
128
|
+
if (atual)
|
|
129
|
+
definir(sem);
|
|
130
|
+
alvo.value = sem.charAt(index);
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
let texto = bruto;
|
|
134
|
+
// Digitou numa caixa que já tinha caractere: vale o que é novo.
|
|
135
|
+
if (atual && bruto.length === 2) {
|
|
136
|
+
texto = bruto.charAt(0) === atual ? bruto.charAt(1) : bruto.charAt(0);
|
|
137
|
+
}
|
|
138
|
+
const limpo = limpar(texto);
|
|
139
|
+
if (!limpo) {
|
|
140
|
+
alvo.value = atual;
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
// O que sobra de um código colado ou autopreenchido segue para as próximas caixas.
|
|
144
|
+
const proximo = valor.slice(0, index) + limpo + valor.slice(index + limpo.length);
|
|
145
|
+
const mudou = definir(proximo);
|
|
146
|
+
// A caixa mostra já o que o código passa a ter (o React só relê a prop no próximo render).
|
|
147
|
+
alvo.value = limpar(proximo).slice(0, codeLength()).charAt(index);
|
|
148
|
+
focarDepois(Math.min(index + limpo.length, codeLength() - 1), mudou);
|
|
149
|
+
}
|
|
150
|
+
function handlePaste(event, index) {
|
|
151
|
+
if (!event || !event.clipboardData)
|
|
152
|
+
return;
|
|
153
|
+
const texto = limpar(event.clipboardData.getData("text"));
|
|
154
|
+
event.preventDefault();
|
|
155
|
+
if (!texto)
|
|
156
|
+
return;
|
|
157
|
+
// Código inteiro: substitui tudo. Pedaço: entra a partir da caixa em que se colou.
|
|
158
|
+
const inicio = texto.length >= codeLength() ? 0 : index;
|
|
159
|
+
const valor = currentValue();
|
|
160
|
+
const mudou = definir(valor.slice(0, inicio) + texto + valor.slice(inicio + texto.length));
|
|
161
|
+
focarDepois(Math.min(inicio + texto.length, codeLength() - 1), mudou);
|
|
162
|
+
}
|
|
163
|
+
function handleKeyDown(event, index) {
|
|
164
|
+
if (!event || event.altKey || event.ctrlKey || event.metaKey)
|
|
165
|
+
return;
|
|
166
|
+
const tecla = event.key;
|
|
167
|
+
if (tecla === "Backspace" && !charAt(index) && index > 0) {
|
|
168
|
+
event.preventDefault();
|
|
169
|
+
const valor = currentValue();
|
|
170
|
+
const mudou = definir(valor.slice(0, index - 1) + valor.slice(index));
|
|
171
|
+
focarDepois(index - 1, mudou);
|
|
172
|
+
}
|
|
173
|
+
else if (tecla === "ArrowLeft") {
|
|
174
|
+
event.preventDefault();
|
|
175
|
+
focarEm(index - 1);
|
|
176
|
+
}
|
|
177
|
+
else if (tecla === "ArrowRight") {
|
|
178
|
+
event.preventDefault();
|
|
179
|
+
focarEm(Math.min(index + 1, limiteDoFoco()));
|
|
180
|
+
}
|
|
181
|
+
else if (tecla === "Home") {
|
|
182
|
+
event.preventDefault();
|
|
183
|
+
focarEm(0);
|
|
184
|
+
}
|
|
185
|
+
else if (tecla === "End") {
|
|
186
|
+
event.preventDefault();
|
|
187
|
+
focarEm(limiteDoFoco());
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
function handleFocus(event, index) {
|
|
191
|
+
// Sem buraco: foco à frente da primeira vazia volta para ela.
|
|
192
|
+
const limite = limiteDoFoco();
|
|
193
|
+
if (index > limite) {
|
|
194
|
+
focarEm(limite);
|
|
195
|
+
return;
|
|
196
|
+
}
|
|
197
|
+
if (event && event.target && event.target.select)
|
|
198
|
+
event.target.select();
|
|
199
|
+
}
|
|
200
|
+
useEffect(() => {
|
|
201
|
+
if (!props.id)
|
|
202
|
+
setUid(gerarId("umds-otp"));
|
|
203
|
+
if (props.autoFocus)
|
|
204
|
+
focarEm(limiteDoFoco());
|
|
205
|
+
}, []);
|
|
206
|
+
useEffect(() => {
|
|
207
|
+
if (focoPendenteRef.current >= 0) {
|
|
208
|
+
const alvo = focoPendenteRef.current;
|
|
209
|
+
focoPendenteRef.current = -1;
|
|
210
|
+
focarEm(alvo);
|
|
211
|
+
}
|
|
212
|
+
});
|
|
213
|
+
return (_jsxs("div", { className: classes(), children: [props.label ? (_jsx("span", { className: "umds-otp__label", id: labelId(), children: props.label })) : null, _jsx("div", { role: "group", className: "umds-otp__digits", ref: groupRef, "aria-label": groupAriaLabel(), "aria-labelledby": labelId(), children: positions()?.map((caixa) => (_jsx("input", { type: "text", autoCapitalize: "off", className: "umds-otp__digit", id: digitId(caixa), inputMode: inputMode(), autoComplete: autoComplete(caixa), spellCheck: false, value: charAt(caixa), disabled: props.disabled, "aria-label": digitName(caixa), "aria-invalid": ariaInvalidText(), "aria-describedby": errorId(), onInput: (event) => handleInput(event, caixa), onChange: (event) => handleInput(event, caixa), onKeyDown: (event) => handleKeyDown(event, caixa), onPaste: (event) => handlePaste(event, caixa), onFocus: (event) => handleFocus(event, caixa) }, caixa))) }), props.errorMessage ? (_jsx(Text, { as: "span", variant: "caption", color: "negative", id: errorId(), children: props.errorMessage })) : null] }));
|
|
214
|
+
}
|
|
215
|
+
export default OtpInput;
|
|
@@ -99,6 +99,14 @@
|
|
|
99
99
|
border-color: var(--umds-semantic-field-border-default);
|
|
100
100
|
}
|
|
101
101
|
|
|
102
|
+
/* Somente leitura não é desabilitado: o texto segue lido e a WCAG 1.4.3 vale
|
|
103
|
+
sem isenção. O placeholder padrão foi calibrado para fundo branco e cai para
|
|
104
|
+
~4,2:1 sobre o fundo de somente leitura; neutral-dark-down passa 4,5:1 em
|
|
105
|
+
todos os temas (1doc 6,78:1 · 1doc-dark 10,83:1 · alto contraste 16,48:1). */
|
|
106
|
+
.umds-phone-input--readonly .umds-phone-input__field::placeholder {
|
|
107
|
+
color: var(--umds-semantic-color-neutral-dark-down);
|
|
108
|
+
}
|
|
109
|
+
|
|
102
110
|
/* ── Flag selector pill ── */
|
|
103
111
|
.umds-phone-input__flag-btn {
|
|
104
112
|
display: inline-flex;
|
|
@@ -22,6 +22,7 @@ import './Popover.css';
|
|
|
22
22
|
* @property {boolean} closable - Exibe o botão de fechar no topo.
|
|
23
23
|
* @property {string} closeLabel - Nome acessível do botão de fechar. Padrão: "Fechar".
|
|
24
24
|
* @property {number} width - Largura do painel, em px. Padrão: 240.
|
|
25
|
+
* @property {number | string} maxHeight - Altura máxima do corpo, que rola quando o conteúdo passa dela. Número vira px; texto vai como CSS (`"60vh"`). `"none"` deixa o corpo crescer com o conteúdo (painel "Colunas do card"). Sem a prop, o teto histórico de 300px continua.
|
|
25
26
|
* @property {string} ariaLabel - Nome acessível quando não há `title`.
|
|
26
27
|
* @property {string} className - Classes CSS adicionais.
|
|
27
28
|
* @property {function} onOpenChange - Avisa quando abre e quando fecha.
|
|
@@ -45,6 +46,12 @@ export interface PopoverProps {
|
|
|
45
46
|
closable?: boolean;
|
|
46
47
|
closeLabel?: string;
|
|
47
48
|
width?: number;
|
|
49
|
+
/**
|
|
50
|
+
* Altura máxima do corpo. Número vira px; texto vai como CSS (`"60vh"`).
|
|
51
|
+
* `"none"` deixa o corpo crescer com o conteúdo. Sem a prop, vale o teto de
|
|
52
|
+
* 300px de sempre (o cabeçalho e o × não rolam junto).
|
|
53
|
+
*/
|
|
54
|
+
maxHeight?: number | string;
|
|
48
55
|
ariaLabel?: string;
|
|
49
56
|
className?: string;
|
|
50
57
|
children?: any;
|
|
@@ -305,6 +305,16 @@ function Popover(props) {
|
|
|
305
305
|
visibility: positioned ? "visible" : "hidden",
|
|
306
306
|
};
|
|
307
307
|
}
|
|
308
|
+
function corpoStyle() {
|
|
309
|
+
if (props.maxHeight === undefined || props.maxHeight === null) {
|
|
310
|
+
return undefined;
|
|
311
|
+
}
|
|
312
|
+
return {
|
|
313
|
+
maxHeight: typeof props.maxHeight === "number"
|
|
314
|
+
? props.maxHeight + "px"
|
|
315
|
+
: props.maxHeight,
|
|
316
|
+
};
|
|
317
|
+
}
|
|
308
318
|
function panelStyle() {
|
|
309
319
|
return {
|
|
310
320
|
opacity: positioned ? 1 : 0,
|
|
@@ -339,6 +349,6 @@ function Popover(props) {
|
|
|
339
349
|
}, []);
|
|
340
350
|
return (_jsxs("span", { ref: anchorRef, className: anchorClasses(), style: {
|
|
341
351
|
display: "inline-flex",
|
|
342
|
-
}, children: [_jsx("span", { className: "umds-popover__trigger", ref: triggerButtonRef, id: triggerIdText(), role: triggerIsInteractive ? undefined : "button", tabIndex: triggerIsInteractive ? undefined : 0, "aria-haspopup": triggerIsInteractive ? undefined : "dialog", "aria-expanded": triggerIsInteractive ? undefined : ariaExpandedText(), onClick: (event) => toggle(), onKeyDown: (event) => handleTriggerKeydown(event), children: _jsx(_Fragment, { children: props.children }) }), _jsx(Portal, { children: mounted ? (_jsx("span", { className: "umds-popover__floating", ref: floatingRef, style: floatingStyle(), children: _jsxs("div", { className: "umds-popover__panel", role: "dialog", "aria-modal": "false", ref: panelRef, "aria-labelledby": labelledByText(), "aria-label": props.title ? undefined : props.ariaLabel, tabIndex: -1, style: panelStyle(), onKeyDown: (event) => handlePanelKeydown(event), children: [props.title || props.closable ? (_jsxs("div", { className: "umds-popover__header", children: [props.title ? (_jsx(Text, { as: "span", variant: "body2", weight: "semibold", id: titleIdText(), children: props.title })) : null, props.closable ? (_jsx("button", { type: "button", className: "umds-popover__close", "aria-label": props.closeLabel || "Fechar", onClick: (event) => close(), children: _jsx(Icon, { size: "sm", variant: "inherit", icon: faXmark }) })) : null] })) : null, _jsx("div", { className: "umds-popover__body", children: _jsx(_Fragment, { children: props.content }) })] }) })) : null })] }));
|
|
352
|
+
}, children: [_jsx("span", { className: "umds-popover__trigger", ref: triggerButtonRef, id: triggerIdText(), role: triggerIsInteractive ? undefined : "button", tabIndex: triggerIsInteractive ? undefined : 0, "aria-haspopup": triggerIsInteractive ? undefined : "dialog", "aria-expanded": triggerIsInteractive ? undefined : ariaExpandedText(), onClick: (event) => toggle(), onKeyDown: (event) => handleTriggerKeydown(event), children: _jsx(_Fragment, { children: props.children }) }), _jsx(Portal, { children: mounted ? (_jsx("span", { className: "umds-popover__floating", ref: floatingRef, style: floatingStyle(), children: _jsxs("div", { className: "umds-popover__panel", role: "dialog", "aria-modal": "false", ref: panelRef, "aria-labelledby": labelledByText(), "aria-label": props.title ? undefined : props.ariaLabel, tabIndex: -1, style: panelStyle(), onKeyDown: (event) => handlePanelKeydown(event), children: [props.title || props.closable ? (_jsxs("div", { className: "umds-popover__header", children: [props.title ? (_jsx(Text, { as: "span", variant: "body2", weight: "semibold", id: titleIdText(), children: props.title })) : null, props.closable ? (_jsx("button", { type: "button", className: "umds-popover__close", "aria-label": props.closeLabel || "Fechar", onClick: (event) => close(), children: _jsx(Icon, { size: "sm", variant: "inherit", icon: faXmark }) })) : null] })) : null, _jsx("div", { className: "umds-popover__body", style: corpoStyle(), children: _jsx(_Fragment, { children: props.content }) })] }) })) : null })] }));
|
|
343
353
|
}
|
|
344
354
|
export default Popover;
|
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
/* ─────────────────────────────────────────────
|
|
2
|
+
RICH TEXT EDITOR
|
|
3
|
+
Editor de texto rico leve sobre contenteditable.
|
|
4
|
+
|
|
5
|
+
A moldura (borda, raio, foco, erro) segue a família de campos. A barra é uma
|
|
6
|
+
faixa de fundo claro com botões de 32px: o botão LIGADO (negrito, lista...)
|
|
7
|
+
ganha o fundo e a cor do primário, e a mesma informação sai em `aria-pressed`.
|
|
8
|
+
|
|
9
|
+
Cores: semânticos · Medidas: primitivos
|
|
10
|
+
───────────────────────────────────────────── */
|
|
11
|
+
|
|
12
|
+
.umds-rte {
|
|
13
|
+
display: flex;
|
|
14
|
+
flex-direction: column;
|
|
15
|
+
gap: var(--umds-primitive-spacing-quarck); /* 4px */
|
|
16
|
+
font-family: var(--umds-semantic-font-family-base);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
.umds-rte__label {
|
|
20
|
+
font-size: var(--umds-semantic-field-label-size);
|
|
21
|
+
font-weight: var(--umds-semantic-field-label-weight);
|
|
22
|
+
color: var(--umds-semantic-field-label-color);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
.umds-rte__frame {
|
|
26
|
+
display: flex;
|
|
27
|
+
flex-direction: column;
|
|
28
|
+
border: var(--umds-primitive-border-width-hairline) solid var(--umds-semantic-field-border-default);
|
|
29
|
+
border-radius: var(--umds-primitive-border-radius-sm);
|
|
30
|
+
background: var(--umds-semantic-color-background-white);
|
|
31
|
+
overflow: hidden;
|
|
32
|
+
transition:
|
|
33
|
+
border-color var(--umds-semantic-motion-duration-fast) var(--umds-semantic-motion-easing-standard),
|
|
34
|
+
box-shadow var(--umds-semantic-motion-duration-fast) var(--umds-semantic-motion-easing-standard);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
.umds-rte__frame:hover {
|
|
38
|
+
border-color: var(--umds-semantic-field-border-hover);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
.umds-rte__frame:focus-within {
|
|
42
|
+
border-color: var(--umds-semantic-field-border-focus);
|
|
43
|
+
box-shadow: var(--umds-semantic-field-ring-focus);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
.umds-rte--invalid .umds-rte__frame,
|
|
47
|
+
.umds-rte--invalid .umds-rte__frame:hover {
|
|
48
|
+
border-color: var(--umds-semantic-field-border-error);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
.umds-rte--invalid .umds-rte__frame:focus-within {
|
|
52
|
+
box-shadow: var(--umds-semantic-field-ring-error);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
.umds-rte--disabled .umds-rte__frame {
|
|
56
|
+
background: var(--umds-semantic-field-disabled-background);
|
|
57
|
+
opacity: var(--umds-semantic-field-disabled-opacity);
|
|
58
|
+
cursor: not-allowed;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
.umds-rte--readonly .umds-rte__frame {
|
|
62
|
+
background: var(--umds-semantic-field-readonly-background);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/* ── Barra ── */
|
|
66
|
+
.umds-rte__toolbar {
|
|
67
|
+
display: flex;
|
|
68
|
+
flex-wrap: wrap;
|
|
69
|
+
align-items: center;
|
|
70
|
+
gap: var(--umds-primitive-spacing-quarck); /* 4px */
|
|
71
|
+
padding: var(--umds-primitive-spacing-quarck) var(--umds-primitive-spacing-nano); /* 4px 8px */
|
|
72
|
+
background: var(--umds-semantic-color-background-light);
|
|
73
|
+
border-bottom: var(--umds-primitive-border-width-hairline) solid var(--umds-semantic-color-neutral-light-medium);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
.umds-rte__tool {
|
|
77
|
+
display: inline-flex;
|
|
78
|
+
align-items: center;
|
|
79
|
+
justify-content: center;
|
|
80
|
+
box-sizing: border-box;
|
|
81
|
+
width: var(--umds-primitive-spacing-xs); /* 32px */
|
|
82
|
+
height: var(--umds-primitive-spacing-xs);
|
|
83
|
+
margin: 0;
|
|
84
|
+
padding: 0;
|
|
85
|
+
border: none;
|
|
86
|
+
border-radius: var(--umds-primitive-border-radius-sm);
|
|
87
|
+
background: transparent;
|
|
88
|
+
color: var(--umds-semantic-color-neutral-dark-down);
|
|
89
|
+
cursor: pointer;
|
|
90
|
+
transition:
|
|
91
|
+
background-color var(--umds-semantic-motion-duration-fast) var(--umds-semantic-motion-easing-standard),
|
|
92
|
+
color var(--umds-semantic-motion-duration-fast) var(--umds-semantic-motion-easing-standard);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
.umds-rte__tool:hover:not(:disabled) {
|
|
96
|
+
background: var(--umds-semantic-color-neutral-light-medium);
|
|
97
|
+
color: var(--umds-semantic-color-neutral-dark-pure);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
.umds-rte__tool--active,
|
|
101
|
+
.umds-rte__tool--active:hover:not(:disabled) {
|
|
102
|
+
background: var(--umds-semantic-color-primary-light);
|
|
103
|
+
color: var(--umds-semantic-color-primary-dark);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
.umds-rte__tool:focus-visible {
|
|
107
|
+
outline: var(--umds-primitive-border-width-thin) solid var(--umds-semantic-color-primary-pure);
|
|
108
|
+
outline-offset: calc(var(--umds-primitive-border-width-thin) * -1);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
.umds-rte__tool:disabled {
|
|
112
|
+
cursor: not-allowed;
|
|
113
|
+
opacity: var(--umds-semantic-field-disabled-opacity);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
.umds-rte__separator {
|
|
117
|
+
align-self: stretch;
|
|
118
|
+
width: var(--umds-primitive-border-width-hairline);
|
|
119
|
+
margin: var(--umds-primitive-spacing-quarck) var(--umds-primitive-spacing-micro);
|
|
120
|
+
background: var(--umds-semantic-color-neutral-light-down);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/* ── Campo de link, logo abaixo da barra ── */
|
|
124
|
+
.umds-rte__link {
|
|
125
|
+
display: flex;
|
|
126
|
+
flex-wrap: wrap;
|
|
127
|
+
align-items: flex-end;
|
|
128
|
+
gap: var(--umds-primitive-spacing-nano); /* 8px */
|
|
129
|
+
padding: var(--umds-primitive-spacing-nano) var(--umds-primitive-spacing-mini); /* 8px 12px */
|
|
130
|
+
background: var(--umds-semantic-color-background-light);
|
|
131
|
+
border-bottom: var(--umds-primitive-border-width-hairline) solid var(--umds-semantic-color-neutral-light-medium);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
.umds-rte__link-field {
|
|
135
|
+
flex: 1 1 var(--umds-primitive-spacing-giant);
|
|
136
|
+
min-width: 0;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
.umds-rte__link-actions {
|
|
140
|
+
display: flex;
|
|
141
|
+
align-items: center;
|
|
142
|
+
gap: var(--umds-primitive-spacing-nano); /* 8px */
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
.umds-rte__table-field {
|
|
146
|
+
flex: 0 1 var(--umds-primitive-spacing-xxxl); /* 120px */
|
|
147
|
+
min-width: 0;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
.umds-rte__style-field {
|
|
151
|
+
flex: 0 1 auto;
|
|
152
|
+
min-width: 0;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/* Barra de linha e coluna: aparece com o cursor numa célula. */
|
|
156
|
+
.umds-rte__table-bar {
|
|
157
|
+
display: flex;
|
|
158
|
+
flex-wrap: wrap;
|
|
159
|
+
align-items: center;
|
|
160
|
+
gap: var(--umds-primitive-spacing-quarck); /* 4px */
|
|
161
|
+
padding: var(--umds-primitive-spacing-quarck) var(--umds-primitive-spacing-nano); /* 4px 8px */
|
|
162
|
+
background: var(--umds-semantic-color-background-light);
|
|
163
|
+
border-bottom: var(--umds-primitive-border-width-hairline) solid var(--umds-semantic-color-neutral-light-medium);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/* ── Área de escrita ── */
|
|
167
|
+
.umds-rte__editor {
|
|
168
|
+
box-sizing: border-box;
|
|
169
|
+
min-height: var(--umds-primitive-spacing-xxxl); /* 120px */
|
|
170
|
+
padding: var(--umds-primitive-spacing-mini) var(--umds-primitive-spacing-xxxs); /* 12px 16px */
|
|
171
|
+
font-size: var(--umds-semantic-field-text-size); /* 14px */
|
|
172
|
+
line-height: var(--umds-primitive-font-line-height-lg);
|
|
173
|
+
color: var(--umds-semantic-field-text-color);
|
|
174
|
+
outline: none;
|
|
175
|
+
overflow-wrap: anywhere;
|
|
176
|
+
overflow-y: auto;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
.umds-rte--resizable .umds-rte__editor {
|
|
180
|
+
resize: vertical;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/* Placeholder: o :empty some assim que há conteúdo (o JS limpa o <br> que sobra). */
|
|
184
|
+
.umds-rte__editor:empty::before {
|
|
185
|
+
content: attr(data-placeholder);
|
|
186
|
+
color: var(--umds-semantic-field-placeholder-color);
|
|
187
|
+
pointer-events: none;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
.umds-rte__editor ul,
|
|
191
|
+
.umds-rte__editor ol {
|
|
192
|
+
margin: var(--umds-primitive-spacing-quarck) 0;
|
|
193
|
+
padding-left: var(--umds-primitive-spacing-xxs); /* 24px */
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
.umds-rte__editor p,
|
|
197
|
+
.umds-rte__editor blockquote {
|
|
198
|
+
margin: 0 0 var(--umds-primitive-spacing-nano);
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
.umds-rte__editor blockquote {
|
|
202
|
+
padding-left: var(--umds-primitive-spacing-mini);
|
|
203
|
+
border-left: var(--umds-primitive-border-width-thin) solid var(--umds-semantic-color-neutral-light-down);
|
|
204
|
+
color: var(--umds-semantic-color-neutral-dark-down);
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
.umds-rte__editor img {
|
|
208
|
+
max-width: 100%;
|
|
209
|
+
height: auto;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
.umds-rte__editor table {
|
|
213
|
+
width: 100%;
|
|
214
|
+
margin: var(--umds-primitive-spacing-nano) 0;
|
|
215
|
+
border-collapse: collapse;
|
|
216
|
+
table-layout: fixed;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
.umds-rte__editor th,
|
|
220
|
+
.umds-rte__editor td {
|
|
221
|
+
min-width: var(--umds-primitive-spacing-sm); /* 40px: a célula vazia continua alcançável */
|
|
222
|
+
padding: var(--umds-primitive-spacing-quarck) var(--umds-primitive-spacing-nano); /* 4px 8px */
|
|
223
|
+
border: var(--umds-primitive-border-width-hairline) solid var(--umds-semantic-color-neutral-light-down);
|
|
224
|
+
vertical-align: top;
|
|
225
|
+
text-align: left;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
.umds-rte__editor th {
|
|
229
|
+
background: var(--umds-semantic-color-background-light);
|
|
230
|
+
font-weight: var(--umds-primitive-font-weight-semibold);
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
.umds-rte__editor a {
|
|
234
|
+
color: var(--umds-semantic-color-primary-pure);
|
|
235
|
+
text-decoration: underline;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
.umds-rte__footer {
|
|
239
|
+
padding: var(--umds-primitive-spacing-nano) var(--umds-primitive-spacing-xxxs); /* 8px 16px */
|
|
240
|
+
border-top: var(--umds-primitive-border-width-hairline) solid var(--umds-semantic-color-neutral-light-medium);
|
|
241
|
+
background: var(--umds-semantic-color-background-light);
|
|
242
|
+
font-size: var(--umds-primitive-font-size-xxs); /* 14px */
|
|
243
|
+
color: var(--umds-semantic-color-neutral-dark-down);
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
@media (forced-colors: active) {
|
|
247
|
+
.umds-rte__tool--active {
|
|
248
|
+
outline: var(--umds-primitive-border-width-thin) solid Highlight;
|
|
249
|
+
}
|
|
250
|
+
}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import './RichTextEditor.css';
|
|
2
|
+
/** Ferramentas da barra, na ordem em que aparecem em `toolbar`. `"|"` é um separador. */
|
|
3
|
+
export type RichTextTool = "bold" | "italic" | "underline" | "strike" | "ul" | "ol" | "link" | "undo" | "redo" | "clear" | "alignLeft" | "alignCenter" | "alignRight" | "alignJustify" | "image" | "table" | "fontFamily" | "fontSize" | "textColor" | "|";
|
|
4
|
+
/**
|
|
5
|
+
* RichTextEditor — editor de texto rico leve, sobre `contenteditable`, sem
|
|
6
|
+
* biblioteca: negrito, itálico, sublinhado, tachado, listas, link, desfazer e
|
|
7
|
+
* refazer, e limpar formatação.
|
|
8
|
+
*
|
|
9
|
+
* O valor é HTML (`value`/`defaultValue`/`onChange`) e SEMPRE passa por uma
|
|
10
|
+
* higienização: só ficam negrito, itálico, sublinhado, tachado, listas,
|
|
11
|
+
* parágrafos, quebras, títulos, citação e link; o resto (`script`, `style`,
|
|
12
|
+
* `onerror`, `class`, `javascript:`) sai, tanto do `value` que entra quanto do
|
|
13
|
+
* que se cola (colar entra como texto puro). Link só aceita `http(s)`, `mailto`,
|
|
14
|
+
* `tel`, caminho e âncora.
|
|
15
|
+
*
|
|
16
|
+
* A barra é um `role="toolbar"` com Tab numa parada só e setas entre as
|
|
17
|
+
* ferramentas; negrito, itálico, sublinhado, tachado e as listas são botões de
|
|
18
|
+
* liga/desliga (`aria-pressed`) que seguem a posição do cursor. Os atalhos do
|
|
19
|
+
* navegador (Ctrl+B, Ctrl+I, Ctrl+U, Ctrl+Z) valem, e Ctrl+K abre o link. O
|
|
20
|
+
* botão de link abre um campo logo abaixo da barra (endereço, aplicar, remover,
|
|
21
|
+
* cancelar), sem modal.
|
|
22
|
+
*
|
|
23
|
+
* A barra se escolhe por `toolbar`: a completa é o padrão; `["bold", "italic",
|
|
24
|
+
* "underline", "ul", "ol", "link"]` é a compacta; `["bold", "italic"]`, a mínima.
|
|
25
|
+
* O rodapé aceita o slot `footer` (a assinatura do autor, por exemplo) e a área
|
|
26
|
+
* pode ser redimensionável (`resizable`).
|
|
27
|
+
*
|
|
28
|
+
* Todos os textos são props (`labels`, `toolbarLabel`, `placeholder`).
|
|
29
|
+
*
|
|
30
|
+
* Opcionais na `toolbar` (fora da barra padrão): alinhamento (`alignLeft`,
|
|
31
|
+
* `alignCenter`, `alignRight`, `alignJustify`), imagem (`image`: por endereço ou por
|
|
32
|
+
* arquivo, que entra como `data:` URL, com texto alternativo) e tabela simples
|
|
33
|
+
* (`table`: insere linhas × colunas; com o cursor numa célula aparece a barra de
|
|
34
|
+
* adicionar e remover linha e coluna). Imagem e tabela passam pela mesma
|
|
35
|
+
* higienização: só PNG, JPEG, GIF e WebP em `data:`, ou `http(s)`; sem SVG.
|
|
36
|
+
*
|
|
37
|
+
* Estilo de texto por TOKEN do DS, também opcional na `toolbar`: `fontFamily`
|
|
38
|
+
* (padrão ou monoespaçada), `fontSize` (12, 14, 16, 20 e 24px, da escala do DS) e
|
|
39
|
+
* `textColor` (a paleta do DS). Cada um abre um painel abaixo da barra e aplica ao
|
|
40
|
+
* texto selecionado (sem seleção, o painel pede que se selecione). O valor guarda
|
|
41
|
+
* `<span style="color: var(--umds-primitive-red-pure)">`: só token do DS passa na
|
|
42
|
+
* higienização, cor em hex, rgb ou nome sai. Para voltar ao padrão, use `clear`.
|
|
43
|
+
*
|
|
44
|
+
* Limites: usa `document.execCommand`, que o
|
|
45
|
+
* navegador mantém mas está marcado como obsoleto (o comportamento do desfazer
|
|
46
|
+
* varia um pouco entre navegadores; adicionar e remover linha ou coluna mexe no
|
|
47
|
+
* DOM e não entra no desfazer). Imagem de arquivo passa de 2 MB? Recusada: o HTML
|
|
48
|
+
* do valor guarda a imagem inteira.
|
|
49
|
+
* @property {string} value - HTML (controlado)
|
|
50
|
+
* @property {string} defaultValue - HTML inicial (não controlado)
|
|
51
|
+
* @property {string} label - Rótulo visível do campo
|
|
52
|
+
* @property {string} ariaLabel - Nome acessível quando não há `label` visível
|
|
53
|
+
* @property {string} placeholder - Texto de apoio com o editor vazio
|
|
54
|
+
* @property {string[]} toolbar - Ferramentas da barra, em ordem: 'bold' | 'italic' | 'underline' | 'strike' | 'ul' | 'ol' | 'link' | 'undo' | 'redo' | 'clear' | 'alignLeft' | 'alignCenter' | 'alignRight' | 'alignJustify' | 'image' | 'table' | 'fontFamily' | 'fontSize' | 'textColor' | '|' (separador)
|
|
55
|
+
* @property {string} toolbarLabel - Nome da barra (padrão "Formatação")
|
|
56
|
+
* @property {object} labels - Nomes das ferramentas e dos campos, parcial: `{ bold, italic, underline, strike, ul, ol, link, undo, redo, clear, alignLeft, alignCenter, alignRight, alignJustify, image, table, linkAddress, linkApply, linkRemove, linkCancel, linkInvalid, imageUrl, imageAlt, imageFile, imageApply, imageCancel, imageInvalid, imageType, imageTooLarge, tableRows, tableCols, tableApply, tableCancel, tableInvalid, tableActions, tableAddRow, tableRemoveRow, tableAddCol, tableRemoveCol, tableRemove, fontFamily, fontSize, textColor, fontFamilyBase, fontFamilyMono, styleClose, styleNeedsSelection }`
|
|
57
|
+
* @property {number} minHeight - Altura mínima da área de escrita, em px (padrão 120)
|
|
58
|
+
* @property {boolean} resizable - Deixa redimensionar a altura pelo canto
|
|
59
|
+
* @property {boolean} disabled - Desabilita barra e área
|
|
60
|
+
* @property {boolean} readOnly - Só leitura: a área não edita e a barra some
|
|
61
|
+
* @property {boolean} invalid - Estado de erro
|
|
62
|
+
* @property {string} errorMessage - Mensagem de erro (liga o estado de erro)
|
|
63
|
+
* @property {string} helperText - Texto de ajuda abaixo do campo
|
|
64
|
+
* @property {string} id - Base dos ids internos; passe em SSR para os ids já saírem no HTML do servidor
|
|
65
|
+
* @property {string} className - Classes CSS adicionais
|
|
66
|
+
* @property {function} onChange - Chamado com o HTML a cada edição
|
|
67
|
+
* @property {function} onBlur - Chamado quando o foco sai da área de escrita
|
|
68
|
+
* @slot footer - Rodapé dentro da moldura, abaixo da área de escrita (assinatura).
|
|
69
|
+
* @quandoUsar Texto formatado que vira conteúdo de documento: despacho, resposta, descrição de serviço, modelo de texto.
|
|
70
|
+
* @quandoNaoUsar Para texto simples de várias linhas, use `Textarea`. Para texto de uma linha, `Input`. Quando for preciso tabela, imagem, cor ou fonte, este corte não serve: peça ao DS ou use um editor especializado.
|
|
71
|
+
*/
|
|
72
|
+
/** Ferramentas da barra, na ordem em que aparecem em `toolbar`. `"|"` é um separador. */
|
|
73
|
+
export interface RichTextEditorProps {
|
|
74
|
+
value?: string;
|
|
75
|
+
defaultValue?: string;
|
|
76
|
+
label?: string;
|
|
77
|
+
ariaLabel?: string;
|
|
78
|
+
placeholder?: string;
|
|
79
|
+
toolbar?: RichTextTool[];
|
|
80
|
+
toolbarLabel?: string;
|
|
81
|
+
labels?: Record<string, string>;
|
|
82
|
+
minHeight?: number;
|
|
83
|
+
resizable?: boolean;
|
|
84
|
+
disabled?: boolean;
|
|
85
|
+
readOnly?: boolean;
|
|
86
|
+
invalid?: boolean;
|
|
87
|
+
errorMessage?: string;
|
|
88
|
+
helperText?: string;
|
|
89
|
+
id?: string;
|
|
90
|
+
className?: string;
|
|
91
|
+
/** Slot `footer`: abaixo da área de escrita. */
|
|
92
|
+
footer?: any;
|
|
93
|
+
onChange?: (html: string) => void;
|
|
94
|
+
onBlur?: (event?: any) => void;
|
|
95
|
+
}
|
|
96
|
+
declare function RichTextEditor(props: RichTextEditorProps): import("react/jsx-runtime").JSX.Element;
|
|
97
|
+
export default RichTextEditor;
|