@1doc/1ds-react 2.8.0 → 2.9.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 +1106 -0
- package/dist/components/AILabel/AILabel.js +1 -1
- package/dist/components/Accordion/Accordion.d.ts +6 -2
- package/dist/components/AttachmentCard/AttachmentCard.css +16 -0
- package/dist/components/AttachmentCard/AttachmentCard.d.ts +19 -2
- package/dist/components/AttachmentCard/AttachmentCard.js +40 -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 +54 -2
- package/dist/components/Badge/Badge.d.ts +14 -4
- package/dist/components/Badge/Badge.js +1 -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 +125 -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 +118 -0
- package/dist/components/Coachmark/Coachmark.d.ts +75 -0
- package/dist/components/Coachmark/Coachmark.js +321 -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 +133 -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 +80 -0
- package/dist/components/DataTable/DataTable.d.ts +19 -4
- package/dist/components/DataTable/DataTable.js +59 -15
- package/dist/components/DatePicker/DatePicker.css +8 -0
- package/dist/components/DatePicker/DatePicker.js +10 -1
- package/dist/components/DescriptionList/DescriptionList.css +113 -0
- package/dist/components/DescriptionList/DescriptionList.d.ts +59 -0
- package/dist/components/DescriptionList/DescriptionList.js +51 -0
- 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 +38 -0
- package/dist/components/Input/Input.d.ts +10 -1
- package/dist/components/Input/Input.js +66 -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 +85 -0
- package/dist/components/List/ListItem.js +81 -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 +203 -0
- package/dist/components/RichTextEditor/RichTextEditor.d.ts +83 -0
- package/dist/components/RichTextEditor/RichTextEditor.js +494 -0
- package/dist/components/SegmentedControl/SegmentedControl.js +7 -2
- package/dist/components/Select/Select.css +70 -0
- package/dist/components/Select/Select.d.ts +12 -0
- package/dist/components/Select/Select.js +59 -4
- 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 +73 -0
- package/dist/components/StatCard/StatCard.d.ts +17 -0
- package/dist/components/StatCard/StatCard.js +4 -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/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/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/AvatarGroupOverlap.test.d.ts +1 -0
- package/dist/teste/AvatarGroupOverlap.test.js +56 -0
- package/dist/teste/BadgeTag.test.d.ts +1 -0
- package/dist/teste/BadgeTag.test.js +42 -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/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/ColorPicker.test.d.ts +1 -0
- package/dist/teste/ColorPicker.test.js +132 -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/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/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/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/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/TabsContadorFechavel.test.d.ts +1 -0
- package/dist/teste/TabsContadorFechavel.test.js +79 -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 +27 -0
- package/dist/utils/html-seguro.js +97 -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/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/AtributosRepassados.test.tsx +73 -0
- package/src/teste/AttachmentCardIA.test.tsx +126 -0
- package/src/teste/AvatarGroupOverlap.test.tsx +74 -0
- package/src/teste/BadgeTag.test.tsx +64 -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/ChipsXs.test.tsx +41 -0
- package/src/teste/Coachmark.test.tsx +198 -0
- package/src/teste/ColorPicker.test.tsx +153 -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/FileInputTrigger.test.tsx +89 -0
- package/src/teste/IconPicker.test.tsx +145 -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/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/SelectPlacementFiltro.test.tsx +110 -0
- package/src/teste/Stack.test.tsx +80 -0
- package/src/teste/StatCardRotuloTopo.test.tsx +44 -0
- package/src/teste/TabsContadorFechavel.test.tsx +144 -0
- package/src/teste/TooltipDark.test.tsx +51 -0
- package/src/utils/calendario.ts +78 -0
- package/src/utils/html-seguro.ts +94 -0
- package/src/utils/paleta-de-cores.ts +34 -0
- package/src/utils/texto.ts +5 -0
|
@@ -0,0 +1,297 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import './OrgChart.css';
|
|
4
|
+
import { useState, useRef, useEffect } from "react";
|
|
5
|
+
function OrgChart(props) {
|
|
6
|
+
const rootRef = useRef(null);
|
|
7
|
+
const focoPendenteRef = useRef("");
|
|
8
|
+
const [internalCollapsed, setInternalCollapsed] = useState(() => props.defaultCollapsedIds || []);
|
|
9
|
+
const [focusId, setFocusId] = useState(() => "");
|
|
10
|
+
function widthPx() {
|
|
11
|
+
return props.nodeWidth && props.nodeWidth > 0 ? props.nodeWidth : 176;
|
|
12
|
+
}
|
|
13
|
+
function heightPx() {
|
|
14
|
+
return props.nodeHeight && props.nodeHeight > 0 ? props.nodeHeight : 64;
|
|
15
|
+
}
|
|
16
|
+
function gapXPx() {
|
|
17
|
+
return props.gapX !== undefined && props.gapX >= 0 ? props.gapX : 16;
|
|
18
|
+
}
|
|
19
|
+
function gapYPx() {
|
|
20
|
+
return props.gapY !== undefined && props.gapY >= 0 ? props.gapY : 40;
|
|
21
|
+
}
|
|
22
|
+
function collapsed() {
|
|
23
|
+
return props.collapsedIds !== undefined
|
|
24
|
+
? props.collapsedIds
|
|
25
|
+
: internalCollapsed;
|
|
26
|
+
}
|
|
27
|
+
function treeName() {
|
|
28
|
+
return props.ariaLabel || "Organograma";
|
|
29
|
+
}
|
|
30
|
+
function classes() {
|
|
31
|
+
return ["umds-org-chart", props.className].filter(Boolean).join(" ");
|
|
32
|
+
}
|
|
33
|
+
function layout() {
|
|
34
|
+
const raizes = props.nodes || [];
|
|
35
|
+
const larg = widthPx();
|
|
36
|
+
const alt = heightPx();
|
|
37
|
+
const passoX = larg + gapXPx();
|
|
38
|
+
const passoY = alt + gapYPx();
|
|
39
|
+
const fechados = collapsed();
|
|
40
|
+
const lista = [];
|
|
41
|
+
const caminhos = [];
|
|
42
|
+
let folha = 0;
|
|
43
|
+
let maxNivel = 0;
|
|
44
|
+
const visitar = (no, nivel, paiId, pos, total) => {
|
|
45
|
+
const filhos = no.children || [];
|
|
46
|
+
const temFilhos = filhos.length > 0;
|
|
47
|
+
const aberto = temFilhos && fechados.indexOf(no.id) === -1;
|
|
48
|
+
const item = {
|
|
49
|
+
id: no.id,
|
|
50
|
+
node: no,
|
|
51
|
+
level: nivel,
|
|
52
|
+
parentId: paiId,
|
|
53
|
+
position: pos,
|
|
54
|
+
setSize: total,
|
|
55
|
+
hasChildren: temFilhos,
|
|
56
|
+
expanded: aberto,
|
|
57
|
+
childIds: [],
|
|
58
|
+
x: 0,
|
|
59
|
+
y: nivel * passoY,
|
|
60
|
+
};
|
|
61
|
+
if (nivel > maxNivel)
|
|
62
|
+
maxNivel = nivel;
|
|
63
|
+
lista.push(item);
|
|
64
|
+
if (aberto) {
|
|
65
|
+
const acima = [];
|
|
66
|
+
for (let i = 0; i < filhos.length; i++) {
|
|
67
|
+
const filho = visitar(filhos[i], nivel + 1, no.id, i + 1, filhos.length);
|
|
68
|
+
acima.push(filho);
|
|
69
|
+
item.childIds.push(filho.id);
|
|
70
|
+
}
|
|
71
|
+
item.x = (acima[0].x + acima[acima.length - 1].x) / 2;
|
|
72
|
+
// Conector: desce do pai até o meio do espaço, corre na horizontal e desce a cada filho.
|
|
73
|
+
const paiCentro = item.x + larg / 2;
|
|
74
|
+
const baseDoPai = item.y + alt;
|
|
75
|
+
const meio = baseDoPai + gapYPx() / 2;
|
|
76
|
+
let d = "M" + paiCentro + " " + baseDoPai + " V" + meio;
|
|
77
|
+
const primeiro = acima[0].x + larg / 2;
|
|
78
|
+
const ultimo = acima[acima.length - 1].x + larg / 2;
|
|
79
|
+
if (acima.length > 1)
|
|
80
|
+
d += " M" + primeiro + " " + meio + " H" + ultimo;
|
|
81
|
+
for (let j = 0; j < acima.length; j++) {
|
|
82
|
+
const cx = acima[j].x + larg / 2;
|
|
83
|
+
d += " M" + cx + " " + meio + " V" + acima[j].y;
|
|
84
|
+
}
|
|
85
|
+
caminhos.push(d);
|
|
86
|
+
}
|
|
87
|
+
else {
|
|
88
|
+
item.x = folha * passoX;
|
|
89
|
+
folha = folha + 1;
|
|
90
|
+
}
|
|
91
|
+
return item;
|
|
92
|
+
};
|
|
93
|
+
for (let r = 0; r < raizes.length; r++) {
|
|
94
|
+
visitar(raizes[r], 0, "", r + 1, raizes.length);
|
|
95
|
+
}
|
|
96
|
+
return {
|
|
97
|
+
items: lista,
|
|
98
|
+
paths: caminhos,
|
|
99
|
+
width: Math.max(folha * passoX - gapXPx(), larg),
|
|
100
|
+
height: (maxNivel + 1) * passoY - gapYPx(),
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
function itemList() {
|
|
104
|
+
return layout().items;
|
|
105
|
+
}
|
|
106
|
+
function toggleList() {
|
|
107
|
+
return itemList().filter((item) => item.hasChildren);
|
|
108
|
+
}
|
|
109
|
+
function pathList() {
|
|
110
|
+
return layout().paths;
|
|
111
|
+
}
|
|
112
|
+
function surfaceStyle() {
|
|
113
|
+
return {
|
|
114
|
+
width: layout().width + "px",
|
|
115
|
+
height: layout().height + "px",
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
function hasNodes() {
|
|
119
|
+
return itemList().length > 0;
|
|
120
|
+
}
|
|
121
|
+
function tabId() {
|
|
122
|
+
const lista = itemList();
|
|
123
|
+
for (let i = 0; i < lista.length; i++) {
|
|
124
|
+
if (lista[i].id === focusId)
|
|
125
|
+
return focusId;
|
|
126
|
+
}
|
|
127
|
+
return lista.length ? lista[0].id : "";
|
|
128
|
+
}
|
|
129
|
+
function nodeClasses(item) {
|
|
130
|
+
return [
|
|
131
|
+
"umds-org-chart__node",
|
|
132
|
+
item.level === 0 ? "umds-org-chart__node--root" : "",
|
|
133
|
+
item.id === props.selectedId ? "umds-org-chart__node--selected" : "",
|
|
134
|
+
]
|
|
135
|
+
.filter(Boolean)
|
|
136
|
+
.join(" ");
|
|
137
|
+
}
|
|
138
|
+
function nodeStyle(item) {
|
|
139
|
+
return {
|
|
140
|
+
left: item.x + "px",
|
|
141
|
+
top: item.y + "px",
|
|
142
|
+
width: widthPx() + "px",
|
|
143
|
+
height: heightPx() + "px",
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
function toggleStyle(item) {
|
|
147
|
+
return {
|
|
148
|
+
left: item.x + widthPx() / 2 + "px",
|
|
149
|
+
top: item.y + heightPx() + "px",
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
function expandedText(item) {
|
|
153
|
+
return item.hasChildren ? (item.expanded ? "true" : "false") : undefined;
|
|
154
|
+
}
|
|
155
|
+
function selectedText(item) {
|
|
156
|
+
return item.id === props.selectedId ? "true" : undefined;
|
|
157
|
+
}
|
|
158
|
+
function toggleGlyph(item) {
|
|
159
|
+
return item.expanded ? "−" : "+";
|
|
160
|
+
}
|
|
161
|
+
function toggleName(item) {
|
|
162
|
+
return item.expanded
|
|
163
|
+
? props.collapseLabel || "Recolher"
|
|
164
|
+
: props.expandLabel || "Expandir";
|
|
165
|
+
}
|
|
166
|
+
function subtitleOf(item) {
|
|
167
|
+
return item.node.subtitle || "";
|
|
168
|
+
}
|
|
169
|
+
function customContent(item) {
|
|
170
|
+
if (props.renderNode)
|
|
171
|
+
return props.renderNode(item.node, {
|
|
172
|
+
level: item.level,
|
|
173
|
+
expanded: item.expanded,
|
|
174
|
+
});
|
|
175
|
+
return "";
|
|
176
|
+
}
|
|
177
|
+
function hasCustomContent() {
|
|
178
|
+
return !!props.renderNode;
|
|
179
|
+
}
|
|
180
|
+
function plainContent() {
|
|
181
|
+
return !props.renderNode;
|
|
182
|
+
}
|
|
183
|
+
function mudarRecolhidos(proximos) {
|
|
184
|
+
setInternalCollapsed(proximos);
|
|
185
|
+
if (props.onCollapsedChange)
|
|
186
|
+
props.onCollapsedChange(proximos);
|
|
187
|
+
}
|
|
188
|
+
function alternar(item) {
|
|
189
|
+
if (!item.hasChildren)
|
|
190
|
+
return;
|
|
191
|
+
const atuais = collapsed();
|
|
192
|
+
mudarRecolhidos(item.expanded
|
|
193
|
+
? atuais.concat([item.id])
|
|
194
|
+
: atuais.filter((id) => id !== item.id));
|
|
195
|
+
}
|
|
196
|
+
function acharItem(id) {
|
|
197
|
+
const lista = itemList();
|
|
198
|
+
for (let i = 0; i < lista.length; i++) {
|
|
199
|
+
if (lista[i].id === id)
|
|
200
|
+
return lista[i];
|
|
201
|
+
}
|
|
202
|
+
return null;
|
|
203
|
+
}
|
|
204
|
+
function irPara(id) {
|
|
205
|
+
if (!id)
|
|
206
|
+
return;
|
|
207
|
+
setFocusId(id);
|
|
208
|
+
focoPendenteRef.current = id;
|
|
209
|
+
}
|
|
210
|
+
function focarNo(id) {
|
|
211
|
+
if (!rootRef.current)
|
|
212
|
+
return;
|
|
213
|
+
const alvo = rootRef.current.querySelector('[data-node-id="' + id + '"]');
|
|
214
|
+
if (alvo)
|
|
215
|
+
alvo.focus();
|
|
216
|
+
}
|
|
217
|
+
function handleNodeClick(item) {
|
|
218
|
+
setFocusId(item.id);
|
|
219
|
+
if (props.onNodeClick)
|
|
220
|
+
props.onNodeClick(item.node);
|
|
221
|
+
}
|
|
222
|
+
function handleToggleClick(event, item) {
|
|
223
|
+
if (event && event.stopPropagation)
|
|
224
|
+
event.stopPropagation();
|
|
225
|
+
alternar(item);
|
|
226
|
+
}
|
|
227
|
+
function irmaosDe(item) {
|
|
228
|
+
return itemList().filter((outro) => outro.parentId === item.parentId);
|
|
229
|
+
}
|
|
230
|
+
function handleKeyDown(event, item) {
|
|
231
|
+
if (!event || event.altKey || event.ctrlKey || event.metaKey)
|
|
232
|
+
return;
|
|
233
|
+
if (event.target !== event.currentTarget)
|
|
234
|
+
return;
|
|
235
|
+
const tecla = event.key;
|
|
236
|
+
const irmaos = irmaosDe(item);
|
|
237
|
+
// Por id: o desenho é recalculado a cada leitura, então os objetos mudam e a identidade não vale.
|
|
238
|
+
let indice = -1;
|
|
239
|
+
for (let i = 0; i < irmaos.length; i++) {
|
|
240
|
+
if (irmaos[i].id === item.id)
|
|
241
|
+
indice = i;
|
|
242
|
+
}
|
|
243
|
+
if (tecla === "ArrowLeft" || tecla === "ArrowRight") {
|
|
244
|
+
event.preventDefault();
|
|
245
|
+
const alvo = irmaos[indice + (tecla === "ArrowRight" ? 1 : -1)];
|
|
246
|
+
if (alvo)
|
|
247
|
+
irPara(alvo.id);
|
|
248
|
+
}
|
|
249
|
+
else if (tecla === "Home") {
|
|
250
|
+
event.preventDefault();
|
|
251
|
+
irPara(irmaos[0].id);
|
|
252
|
+
}
|
|
253
|
+
else if (tecla === "End") {
|
|
254
|
+
event.preventDefault();
|
|
255
|
+
irPara(irmaos[irmaos.length - 1].id);
|
|
256
|
+
}
|
|
257
|
+
else if (tecla === "ArrowUp") {
|
|
258
|
+
event.preventDefault();
|
|
259
|
+
if (item.parentId)
|
|
260
|
+
irPara(item.parentId);
|
|
261
|
+
}
|
|
262
|
+
else if (tecla === "ArrowDown") {
|
|
263
|
+
event.preventDefault();
|
|
264
|
+
if (!item.hasChildren)
|
|
265
|
+
return;
|
|
266
|
+
if (!item.expanded) {
|
|
267
|
+
// Recolhido: o primeiro Baixo abre; o foco desce no seguinte.
|
|
268
|
+
alternar(item);
|
|
269
|
+
return;
|
|
270
|
+
}
|
|
271
|
+
irPara(item.childIds[0]);
|
|
272
|
+
}
|
|
273
|
+
else if (tecla === " ") {
|
|
274
|
+
event.preventDefault();
|
|
275
|
+
alternar(item);
|
|
276
|
+
}
|
|
277
|
+
else if (tecla === "Enter") {
|
|
278
|
+
event.preventDefault();
|
|
279
|
+
handleNodeClick(item);
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
function handleFocus(event, item) {
|
|
283
|
+
if (event && event.target !== event.currentTarget)
|
|
284
|
+
return;
|
|
285
|
+
if (focusId !== item.id)
|
|
286
|
+
setFocusId(item.id);
|
|
287
|
+
}
|
|
288
|
+
useEffect(() => {
|
|
289
|
+
if (focoPendenteRef.current) {
|
|
290
|
+
const alvo = focoPendenteRef.current;
|
|
291
|
+
focoPendenteRef.current = "";
|
|
292
|
+
focarNo(alvo);
|
|
293
|
+
}
|
|
294
|
+
});
|
|
295
|
+
return (_jsx("div", { ref: rootRef, className: classes(), children: hasNodes() ? (_jsx("div", { role: "tree", className: "umds-org-chart__scroller", "aria-label": treeName(), children: _jsxs("div", { className: "umds-org-chart__surface", style: surfaceStyle(), children: [_jsx("svg", { "aria-hidden": "true", focusable: "false", className: "umds-org-chart__lines", width: layout().width, height: layout().height, children: pathList()?.map((caminho, posicao) => (_jsx("path", { className: "umds-org-chart__line", d: caminho }, posicao))) }), itemList()?.map((item) => (_jsxs("div", { role: "treeitem", style: nodeStyle(item), "data-node-id": item.id, "aria-level": item.level + 1, "aria-posinset": item.position, "aria-setsize": item.setSize, "aria-expanded": expandedText(item), "aria-selected": selectedText(item), tabIndex: item.id === tabId() ? 0 : -1, onClick: (event) => handleNodeClick(item), onKeyDown: (event) => handleKeyDown(event, item), onFocus: (event) => handleFocus(event, item), className: nodeClasses(item), children: [hasCustomContent() ? (_jsx("div", { className: "umds-org-chart__custom", children: customContent(item) })) : null, plainContent() ? (_jsxs(_Fragment, { children: [_jsx("span", { className: "umds-org-chart__title", title: item.node.title, children: item.node.title }), item.node.subtitle ? (_jsx("span", { className: "umds-org-chart__subtitle", title: subtitleOf(item), children: item.node.subtitle })) : null] })) : null] }, item.id))), toggleList()?.map((item) => (_jsx("button", { type: "button", "aria-hidden": "true", className: "umds-org-chart__toggle", style: toggleStyle(item), tabIndex: -1, title: toggleName(item), onClick: (event) => handleToggleClick(event, item), children: toggleGlyph(item) }, item.id)))] }) })) : null }));
|
|
296
|
+
}
|
|
297
|
+
export default OrgChart;
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
/* ─────────────────────────────────────────────
|
|
2
|
+
OTP INPUT
|
|
3
|
+
Código de verificação em caixas de um caractere.
|
|
4
|
+
|
|
5
|
+
A caixa segue a família de campos: borda de repouso, hover, foco (borda +
|
|
6
|
+
anel) e erro vêm dos tokens `--umds-semantic-field-*`. O que muda é a
|
|
7
|
+
geometria: caixa alta, número grande e centralizado.
|
|
8
|
+
|
|
9
|
+
Cores: semânticos · Medidas: primitivos
|
|
10
|
+
───────────────────────────────────────────── */
|
|
11
|
+
|
|
12
|
+
.umds-otp {
|
|
13
|
+
display: inline-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-otp__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-otp__digits {
|
|
26
|
+
display: flex;
|
|
27
|
+
gap: var(--umds-primitive-spacing-nano); /* 8px */
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
.umds-otp__digit {
|
|
31
|
+
box-sizing: border-box;
|
|
32
|
+
margin: 0;
|
|
33
|
+
padding: 0;
|
|
34
|
+
text-align: center;
|
|
35
|
+
font-family: inherit;
|
|
36
|
+
font-weight: var(--umds-primitive-font-weight-bold);
|
|
37
|
+
color: var(--umds-semantic-field-text-color);
|
|
38
|
+
background: var(--umds-semantic-color-background-white);
|
|
39
|
+
border: var(--umds-primitive-border-width-hairline) solid var(--umds-semantic-field-border-default);
|
|
40
|
+
border-radius: var(--umds-primitive-border-radius-sm);
|
|
41
|
+
caret-color: var(--umds-semantic-color-primary-pure);
|
|
42
|
+
transition:
|
|
43
|
+
border-color var(--umds-semantic-motion-duration-fast) var(--umds-semantic-motion-easing-standard),
|
|
44
|
+
box-shadow var(--umds-semantic-motion-duration-fast) var(--umds-semantic-motion-easing-standard);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
.umds-otp--md .umds-otp__digit {
|
|
48
|
+
width: var(--umds-primitive-spacing-md); /* 48px */
|
|
49
|
+
height: var(--umds-primitive-spacing-lg); /* 56px */
|
|
50
|
+
font-size: var(--umds-primitive-font-size-md); /* 24px */
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
.umds-otp--sm .umds-otp__digit {
|
|
54
|
+
width: var(--umds-primitive-spacing-sm); /* 40px */
|
|
55
|
+
height: var(--umds-primitive-spacing-md); /* 48px */
|
|
56
|
+
font-size: var(--umds-primitive-font-size-sm); /* 20px */
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
.umds-otp__digit:hover:not(:disabled) {
|
|
60
|
+
border-color: var(--umds-semantic-field-border-hover);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
.umds-otp__digit:focus,
|
|
64
|
+
.umds-otp__digit:focus-visible {
|
|
65
|
+
outline: none;
|
|
66
|
+
border-color: var(--umds-semantic-field-border-focus);
|
|
67
|
+
box-shadow: var(--umds-semantic-field-ring-focus);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
.umds-otp--invalid .umds-otp__digit,
|
|
71
|
+
.umds-otp--invalid .umds-otp__digit:hover:not(:disabled) {
|
|
72
|
+
border-color: var(--umds-semantic-field-border-error);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
.umds-otp--invalid .umds-otp__digit:focus,
|
|
76
|
+
.umds-otp--invalid .umds-otp__digit:focus-visible {
|
|
77
|
+
box-shadow: var(--umds-semantic-field-ring-error);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
.umds-otp__digit:disabled {
|
|
81
|
+
cursor: not-allowed;
|
|
82
|
+
background: var(--umds-semantic-field-disabled-background);
|
|
83
|
+
opacity: var(--umds-semantic-field-disabled-opacity);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/* Alto contraste: o anel de foco de sombra some, o contorno do sistema fica. */
|
|
87
|
+
@media (forced-colors: active) {
|
|
88
|
+
.umds-otp__digit:focus,
|
|
89
|
+
.umds-otp__digit:focus-visible {
|
|
90
|
+
outline: var(--umds-primitive-border-width-thin) solid Highlight;
|
|
91
|
+
outline-offset: var(--umds-primitive-border-width-thin);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import './OtpInput.css';
|
|
2
|
+
/**
|
|
3
|
+
* OtpInput — código de verificação em caixas de um caractere (SMS, e-mail,
|
|
4
|
+
* app autenticador).
|
|
5
|
+
*
|
|
6
|
+
* `length` caixas (6 por padrão). O foco anda sozinho: digitar avança, Backspace
|
|
7
|
+
* apaga e volta, as setas, Home e End movem. Colar o código inteiro em qualquer
|
|
8
|
+
* caixa distribui os caracteres; o preenchimento automático do navegador (SMS)
|
|
9
|
+
* também, porque a primeira caixa leva `autocomplete="one-time-code"`.
|
|
10
|
+
* Clicar numa caixa à frente da primeira vazia manda o foco de volta a ela: o
|
|
11
|
+
* código nunca fica com buraco no meio.
|
|
12
|
+
*
|
|
13
|
+
* O valor é uma string. `onChange` recebe o código a cada mudança e `onComplete`
|
|
14
|
+
* recebe quando as `length` caixas ficam cheias (uma vez por código completo).
|
|
15
|
+
* Aceita só dígitos (`type="numeric"`, padrão, com teclado numérico no celular)
|
|
16
|
+
* ou letras e dígitos (`type="alphanumeric"`, que sai em maiúsculas).
|
|
17
|
+
*
|
|
18
|
+
* Acessibilidade: o conjunto é um `role="group"` nomeado por `label` ou
|
|
19
|
+
* `ariaLabel`, e cada caixa tem nome próprio ("Dígito 3 de 6"). Troque
|
|
20
|
+
* `digitLabel` para traduzir; `{n}` e `{total}` viram a posição e o tamanho.
|
|
21
|
+
* Erro por `invalid` e `errorMessage` (ligado às caixas por `aria-describedby`).
|
|
22
|
+
* @property {number} length - Quantidade de caixas (padrão 6)
|
|
23
|
+
* @property {string} value - Código (controlado)
|
|
24
|
+
* @property {string} defaultValue - Código inicial (não controlado)
|
|
25
|
+
* @property {string} type - 'numeric' (padrão) | 'alphanumeric'
|
|
26
|
+
* @property {string} label - Rótulo visível do conjunto
|
|
27
|
+
* @property {string} ariaLabel - Nome acessível quando não há `label` visível
|
|
28
|
+
* @property {string} digitLabel - Nome de cada caixa; `{n}` e `{total}` são trocados (padrão: "Dígito {n} de {total}")
|
|
29
|
+
* @property {boolean} invalid - Estado de erro
|
|
30
|
+
* @property {string} errorMessage - Mensagem de erro (liga o estado de erro)
|
|
31
|
+
* @property {boolean} disabled - Desabilita todas as caixas
|
|
32
|
+
* @property {boolean} autoFocus - Foca a primeira caixa vazia ao montar
|
|
33
|
+
* @property {string} size - 'sm' | 'md' (padrão)
|
|
34
|
+
* @property {string} id - Base dos ids internos; passe em SSR para os ids já saírem no HTML do servidor
|
|
35
|
+
* @property {string} className - Classes CSS adicionais
|
|
36
|
+
* @property {function} onChange - Chamado com o código a cada mudança
|
|
37
|
+
* @property {function} onComplete - Chamado com o código quando todas as caixas ficam cheias
|
|
38
|
+
* @quandoUsar Confirmar um código curto que a pessoa recebeu por outro canal: autenticação em duas etapas, confirmação de e-mail ou de telefone.
|
|
39
|
+
* @quandoNaoUsar Para texto livre ou código de tamanho variável, use `Input`. Para senha, use `Input type="password"`. Para número com máscara (CPF, CEP), use `Input mask`.
|
|
40
|
+
*/
|
|
41
|
+
export interface OtpInputProps {
|
|
42
|
+
length?: number;
|
|
43
|
+
value?: string;
|
|
44
|
+
defaultValue?: string;
|
|
45
|
+
type?: "numeric" | "alphanumeric";
|
|
46
|
+
label?: string;
|
|
47
|
+
ariaLabel?: string;
|
|
48
|
+
digitLabel?: string;
|
|
49
|
+
invalid?: boolean;
|
|
50
|
+
errorMessage?: string;
|
|
51
|
+
disabled?: boolean;
|
|
52
|
+
autoFocus?: boolean;
|
|
53
|
+
size?: "sm" | "md";
|
|
54
|
+
id?: string;
|
|
55
|
+
className?: string;
|
|
56
|
+
onChange?: (value: string) => void;
|
|
57
|
+
onComplete?: (value: string) => void;
|
|
58
|
+
}
|
|
59
|
+
declare function OtpInput(props: OtpInputProps): import("react/jsx-runtime").JSX.Element;
|
|
60
|
+
export default OtpInput;
|
|
@@ -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;
|