@1doc/1ds-react 2.7.2 → 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 +1280 -0
- package/dist/components/AIContent/AIContent.d.ts +10 -0
- package/dist/components/AIContent/AIContent.js +1 -1
- package/dist/components/AILabel/AILabel.d.ts +4 -0
- package/dist/components/AILabel/AILabel.js +2 -2
- package/dist/components/Accordion/Accordion.d.ts +6 -2
- package/dist/components/Alert/Alert.css +2 -0
- package/dist/components/Alert/Alert.d.ts +3 -1
- package/dist/components/Alert/Alert.js +7 -1
- package/dist/components/AppHeader/AppHeader.css +82 -8
- package/dist/components/AppHeader/AppHeader.d.ts +12 -1
- package/dist/components/AppHeader/AppHeader.js +186 -1
- package/dist/components/AppNavItem/AppNavItem.css +11 -3
- package/dist/components/AppShell/AppShell.css +9 -0
- package/dist/components/AppShell/AppShell.d.ts +8 -0
- package/dist/components/AppShell/AppShell.js +4 -1
- package/dist/components/AppSidebar/AppSidebar.css +1 -1
- package/dist/components/AppSidebar/AppSidebar.d.ts +4 -0
- package/dist/components/AppSidebar/AppSidebar.js +3 -1
- package/dist/components/AttachmentCard/AttachmentCard.css +17 -1
- package/dist/components/AttachmentCard/AttachmentCard.d.ts +29 -2
- package/dist/components/AttachmentCard/AttachmentCard.js +88 -20
- package/dist/components/Avatar/Avatar.css +7 -2
- package/dist/components/Avatar/AvatarGroup.d.ts +27 -0
- package/dist/components/Avatar/AvatarGroup.js +28 -4
- package/dist/components/Badge/Badge.css +61 -3
- package/dist/components/Badge/Badge.d.ts +14 -4
- package/dist/components/Badge/Badge.js +1 -0
- package/dist/components/BottomSheet/BottomSheet.css +1 -0
- package/dist/components/BottomSheet/BottomSheet.d.ts +8 -0
- package/dist/components/BottomSheet/BottomSheet.js +14 -2
- 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/Chart/BarChart.d.ts +6 -0
- package/dist/components/Chart/BarChart.js +3 -1
- package/dist/components/Chart/LineChart.d.ts +6 -0
- package/dist/components/Chart/LineChart.js +3 -1
- package/dist/components/Checkbox/Checkbox.css +4 -1
- package/dist/components/Chips/Chips.css +39 -0
- package/dist/components/Chips/Chips.d.ts +7 -2
- package/dist/components/Chips/Chips.js +6 -2
- 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 +11 -3
- package/dist/components/ConfirmAIAction/ConfirmAIAction.d.ts +11 -1
- package/dist/components/ConfirmAIAction/ConfirmAIAction.js +6 -1
- package/dist/components/ConfirmDialog/ConfirmDialog.css +3 -0
- package/dist/components/ConfirmDialog/ConfirmDialog.d.ts +14 -0
- package/dist/components/ConfirmDialog/ConfirmDialog.js +2 -2
- package/dist/components/DataTable/DataTable.css +80 -0
- package/dist/components/DataTable/DataTable.d.ts +23 -4
- package/dist/components/DataTable/DataTable.js +61 -15
- package/dist/components/DatePicker/DatePicker.css +8 -0
- package/dist/components/DatePicker/DatePicker.d.ts +4 -0
- package/dist/components/DatePicker/DatePicker.js +14 -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/Drawer/Drawer.css +1 -0
- package/dist/components/Dropdown/Dropdown.js +47 -29
- package/dist/components/FileInput/FileInput.css +24 -4
- package/dist/components/FileInput/FileInput.d.ts +22 -2
- package/dist/components/FileInput/FileInput.js +23 -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 +41 -3
- package/dist/components/Input/Input.d.ts +14 -1
- package/dist/components/Input/Input.js +72 -6
- package/dist/components/Kanban/Kanban.css +5 -0
- package/dist/components/Kanban/Kanban.d.ts +41 -0
- package/dist/components/Kanban/Kanban.js +59 -27
- package/dist/components/Kanban/KanbanCard.d.ts +2 -0
- package/dist/components/Kanban/KanbanCard.js +1 -1
- package/dist/components/Kanban/KanbanColumn.d.ts +2 -0
- package/dist/components/Kanban/KanbanColumn.js +3 -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/Link/Link.css +1 -1
- 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 +93 -8
- package/dist/components/Modal/Modal.d.ts +45 -7
- package/dist/components/Modal/Modal.js +106 -6
- package/dist/components/MultiSelect/MultiSelect.css +9 -1
- package/dist/components/MultiSelect/MultiSelect.js +45 -8
- 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/Pagination/Pagination.d.ts +6 -0
- package/dist/components/Pagination/Pagination.js +9 -1
- package/dist/components/PhoneInput/PhoneInput.css +9 -1
- package/dist/components/PhoneInput/PhoneInput.d.ts +10 -0
- package/dist/components/PhoneInput/PhoneInput.js +20 -3
- 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.d.ts +2 -0
- package/dist/components/SegmentedControl/SegmentedControl.js +21 -8
- package/dist/components/Select/Select.css +71 -1
- package/dist/components/Select/Select.d.ts +12 -0
- package/dist/components/Select/Select.js +93 -10
- package/dist/components/SidePanel/SidePanel.css +4 -4
- package/dist/components/SidePanelItem/SidePanelItem.css +7 -5
- package/dist/components/SidePanelSearch/SidePanelSearch.css +2 -2
- package/dist/components/SidePanelSection/SidePanelSection.css +7 -5
- 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/Stepper/Stepper.css +4 -1
- package/dist/components/Stepper/Stepper.d.ts +8 -0
- package/dist/components/Stepper/Stepper.js +4 -4
- package/dist/components/Switch/Switch.css +1 -0
- 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.d.ts +9 -1
- package/dist/components/Text/Text.js +2 -2
- package/dist/components/Textarea/Textarea.css +11 -3
- package/dist/components/TimePicker/TimePicker.css +8 -0
- package/dist/components/TimePicker/TimePicker.d.ts +6 -0
- package/dist/components/TimePicker/TimePicker.js +1 -1
- package/dist/components/Tooltip/Tooltip.css +40 -0
- package/dist/components/Tooltip/Tooltip.d.ts +11 -0
- package/dist/components/Tooltip/Tooltip.js +114 -11
- 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/Alert.test.d.ts +1 -0
- package/dist/teste/Alert.test.js +27 -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/BottomSheet.test.d.ts +1 -0
- package/dist/teste/BottomSheet.test.js +23 -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/ConfirmAIAction.test.d.ts +1 -0
- package/dist/teste/ConfirmAIAction.test.js +33 -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/Dropdown.test.js +111 -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/Modal.test.d.ts +1 -0
- package/dist/teste/Modal.test.js +26 -0
- package/dist/teste/ModalVariantes.test.d.ts +1 -0
- package/dist/teste/ModalVariantes.test.js +151 -0
- package/dist/teste/MultiSelectErro.test.d.ts +1 -0
- package/dist/teste/MultiSelectErro.test.js +62 -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/RotulosTraduziveis.test.d.ts +1 -0
- package/dist/teste/RotulosTraduziveis.test.js +405 -0
- package/dist/teste/SegmentedControl.test.js +33 -0
- package/dist/teste/Select.test.d.ts +1 -0
- package/dist/teste/Select.test.js +62 -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/Tooltip.test.d.ts +1 -0
- package/dist/teste/Tooltip.test.js +109 -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/chart.d.ts +4 -0
- package/dist/utils/chart.js +3 -2
- package/dist/utils/html-seguro.d.ts +27 -0
- package/dist/utils/html-seguro.js +97 -0
- package/dist/utils/id.d.ts +2 -0
- package/dist/utils/id.js +23 -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/Alert.test.tsx +32 -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/BottomSheet.test.tsx +25 -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/ConfirmAIAction.test.tsx +41 -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/Dropdown.test.tsx +146 -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/Modal.test.tsx +28 -0
- package/src/teste/ModalVariantes.test.tsx +173 -0
- package/src/teste/MultiSelectErro.test.tsx +97 -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/RotulosTraduziveis.test.tsx +545 -0
- package/src/teste/SegmentedControl.test.tsx +57 -0
- package/src/teste/Select.test.tsx +97 -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/Tooltip.test.tsx +219 -0
- package/src/teste/TooltipDark.test.tsx +51 -0
- package/src/utils/calendario.ts +78 -0
- package/src/utils/chart.ts +7 -2
- package/src/utils/html-seguro.ts +94 -0
- package/src/utils/id.ts +24 -0
- package/src/utils/paleta-de-cores.ts +34 -0
- package/src/utils/texto.ts +5 -0
|
@@ -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;
|
|
@@ -31,6 +31,12 @@ export interface PaginationProps {
|
|
|
31
31
|
previousPageLabel?: string;
|
|
32
32
|
/** Rótulo acessível do botão de próxima página. @default 'Próxima página' */
|
|
33
33
|
nextPageLabel?: string;
|
|
34
|
+
/** Palavra entre o campo de página e o total (`default` e `alternative`). Troque para traduzir. @default 'de' */
|
|
35
|
+
ofLabel?: string;
|
|
36
|
+
/** Texto do intervalo na variante `resumed`. Recebe início, fim e total de itens. Troque para traduzir. @default (start, end, total) => start + '-' + end + ' de ' + total */
|
|
37
|
+
itemRangeLabel?: (start: number, end: number, total: number) => string;
|
|
38
|
+
/** Nome acessível de cada botão numerado (`full-width` e `bordered`). Recebe o número da página. Troque para traduzir. @default (page) => 'Página ' + page */
|
|
39
|
+
pageLabel?: (page: number) => string;
|
|
34
40
|
page?: number;
|
|
35
41
|
totalPages?: number;
|
|
36
42
|
variant?: "default" | "alternative" | "resumed" | "full-width" | "bordered";
|
|
@@ -161,8 +161,16 @@ function Pagination(props) {
|
|
|
161
161
|
const current = props.page || 1;
|
|
162
162
|
const start = (current - 1) * size + 1;
|
|
163
163
|
const end = Math.min(current * size, totalItems);
|
|
164
|
+
if (props.itemRangeLabel)
|
|
165
|
+
return props.itemRangeLabel(start, end, totalItems);
|
|
164
166
|
return start + "-" + end + " de " + totalItems;
|
|
165
167
|
}
|
|
168
|
+
function ofText() {
|
|
169
|
+
return props.ofLabel || "de";
|
|
170
|
+
}
|
|
171
|
+
function pageAriaLabel(page) {
|
|
172
|
+
return props.pageLabel ? props.pageLabel(page) : "Página " + page;
|
|
173
|
+
}
|
|
166
174
|
function prevText() {
|
|
167
175
|
return props.prevLabel || "Anterior";
|
|
168
176
|
}
|
|
@@ -240,6 +248,6 @@ function Pagination(props) {
|
|
|
240
248
|
useEffect(() => {
|
|
241
249
|
syncInputToPage();
|
|
242
250
|
});
|
|
243
|
-
return (_jsxs("nav", { "aria-label": props.ariaLabel || "Paginação", className: classes(), children: [resolvedVariant() === "default" ? (_jsxs(_Fragment, { children: [props.showPrevNext !== false ? (_jsxs("button", { type: "button", className: "umds-pagination__link-btn", onClick: (event) => goToPage((props.page || 1) - 1), disabled: isPrevDisabled(), children: [_jsx(Icon, { variant: "inherit", customSize: "14px", icon: faChevronLeft }), _jsx("span", { children: prevText() })] })) : null, _jsx("input", { type: "text", inputMode: "numeric", className: "umds-pagination__input", value: inputValue, disabled: props.disabled, "aria-label": props.currentPageLabel || "Página atual", onInput: (event) => handleInputChange(event), onKeyDown: (event) => handleInputKeydown(event), onBlur: (event) => commitInput() }), _jsx("span", { className: "umds-pagination__of", children:
|
|
251
|
+
return (_jsxs("nav", { "aria-label": props.ariaLabel || "Paginação", className: classes(), children: [resolvedVariant() === "default" ? (_jsxs(_Fragment, { children: [props.showPrevNext !== false ? (_jsxs("button", { type: "button", className: "umds-pagination__link-btn", onClick: (event) => goToPage((props.page || 1) - 1), disabled: isPrevDisabled(), children: [_jsx(Icon, { variant: "inherit", customSize: "14px", icon: faChevronLeft }), _jsx("span", { children: prevText() })] })) : null, _jsx("input", { type: "text", inputMode: "numeric", className: "umds-pagination__input", value: inputValue, disabled: props.disabled, "aria-label": props.currentPageLabel || "Página atual", onInput: (event) => handleInputChange(event), onKeyDown: (event) => handleInputKeydown(event), onBlur: (event) => commitInput() }), _jsx("span", { className: "umds-pagination__of", children: ofText() }), _jsx("span", { className: "umds-pagination__total", children: props.totalPages || 1 }), props.showPrevNext !== false ? (_jsxs("button", { type: "button", className: "umds-pagination__link-btn", onClick: (event) => goToPage((props.page || 1) + 1), disabled: isNextDisabled(), children: [_jsx("span", { children: nextText() }), _jsx(Icon, { variant: "inherit", customSize: "14px", icon: faChevronRight })] })) : null] })) : null, resolvedVariant() === "alternative" ? (_jsxs(_Fragment, { children: [props.showPrevNext !== false ? (_jsx("button", { type: "button", className: "umds-pagination__ghost-btn", onClick: (event) => goToPage((props.page || 1) - 1), disabled: isPrevDisabled(), "aria-label": props.previousPageLabel || "Página anterior", children: _jsx(Icon, { variant: "inherit", customSize: "16px", icon: faChevronLeft }) })) : null, _jsx("input", { type: "text", inputMode: "numeric", className: "umds-pagination__input", value: inputValue, disabled: props.disabled, "aria-label": props.currentPageLabel || "Página atual", onInput: (event) => handleInputChange(event), onKeyDown: (event) => handleInputKeydown(event), onBlur: (event) => commitInput() }), _jsx("span", { className: "umds-pagination__of", children: ofText() }), _jsx("span", { className: "umds-pagination__total", children: props.totalPages || 1 }), props.showPrevNext !== false ? (_jsx("button", { type: "button", className: "umds-pagination__ghost-btn", onClick: (event) => goToPage((props.page || 1) + 1), disabled: isNextDisabled(), "aria-label": props.nextPageLabel || "Próxima página", children: _jsx(Icon, { variant: "inherit", customSize: "16px", icon: faChevronRight }) })) : null] })) : null, resolvedVariant() === "resumed" ? (_jsxs(_Fragment, { children: [_jsx("span", { className: "umds-pagination__range", children: rangeLabel() }), props.showPrevNext !== false ? (_jsxs(_Fragment, { children: [_jsx("button", { type: "button", className: "umds-pagination__ghost-btn", onClick: (event) => goToPage((props.page || 1) - 1), disabled: isPrevDisabled(), "aria-label": props.previousPageLabel || "Página anterior", children: _jsx(Icon, { variant: "inherit", customSize: "16px", icon: faChevronLeft }) }), _jsx("button", { type: "button", className: "umds-pagination__ghost-btn", onClick: (event) => goToPage((props.page || 1) + 1), disabled: isNextDisabled(), "aria-label": props.nextPageLabel || "Próxima página", children: _jsx(Icon, { variant: "inherit", customSize: "16px", icon: faChevronRight }) })] })) : null] })) : null, resolvedVariant() === "full-width" ? (_jsxs(_Fragment, { children: [props.showPrevNext !== false ? (_jsxs("button", { type: "button", className: "umds-pagination__nav-btn", onClick: (event) => goToPage((props.page || 1) - 1), disabled: isPrevDisabled(), children: [_jsx(Icon, { variant: "inherit", customSize: "14px", icon: faChevronLeft }), _jsx("span", { children: prevText() })] })) : null, pages()?.map((item) => (_jsxs("span", { className: "umds-pagination__item", children: [item.type === "page" ? (_jsx("button", { type: "button", onClick: (event) => goToPage(item.value), disabled: props.disabled, "aria-label": pageAriaLabel(item.value), "aria-current": isActive(item.value) ? "page" : undefined, className: getBtnClass(item.value), children: item.label })) : null, item.type === "dots" ? (_jsx("span", { "aria-hidden": "true", className: "umds-pagination__dots", children: item.label })) : null] }, item.key))), props.showPrevNext !== false ? (_jsxs("button", { type: "button", className: "umds-pagination__nav-btn", onClick: (event) => goToPage((props.page || 1) + 1), disabled: isNextDisabled(), children: [_jsx("span", { children: nextText() }), _jsx(Icon, { variant: "inherit", customSize: "14px", icon: faChevronRight })] })) : null] })) : null, resolvedVariant() === "bordered" ? (_jsxs("span", { className: "umds-pagination__box", children: [props.showPrevNext !== false ? (_jsxs("button", { type: "button", className: "umds-pagination__cell-btn umds-pagination__cell-btn--prev", onClick: (event) => goToPage((props.page || 1) - 1), disabled: isPrevDisabled(), children: [_jsx(Icon, { variant: "inherit", customSize: "14px", icon: faChevronLeft }), _jsx("span", { children: prevText() })] })) : null, _jsx("span", { className: "umds-pagination__cell-pages", children: pages()?.map((item) => (_jsxs("span", { className: "umds-pagination__item", children: [item.type === "page" ? (_jsx("button", { type: "button", onClick: (event) => goToPage(item.value), disabled: props.disabled, "aria-label": pageAriaLabel(item.value), "aria-current": isActive(item.value) ? "page" : undefined, className: getBtnClass(item.value), children: item.label })) : null, item.type === "dots" ? (_jsx("span", { "aria-hidden": "true", className: "umds-pagination__dots", children: item.label })) : null] }, item.key))) }), props.showPrevNext !== false ? (_jsxs("button", { type: "button", className: "umds-pagination__cell-btn umds-pagination__cell-btn--next", onClick: (event) => goToPage((props.page || 1) + 1), disabled: isNextDisabled(), children: [_jsx("span", { children: nextText() }), _jsx(Icon, { variant: "inherit", customSize: "14px", icon: faChevronRight })] })) : null] })) : null] }));
|
|
244
252
|
}
|
|
245
253
|
export default Pagination;
|
|
@@ -96,7 +96,15 @@
|
|
|
96
96
|
}
|
|
97
97
|
|
|
98
98
|
.umds-phone-input--readonly .umds-phone-input__container:hover {
|
|
99
|
-
border-color: var(--umds-semantic-
|
|
99
|
+
border-color: var(--umds-semantic-field-border-default);
|
|
100
|
+
}
|
|
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);
|
|
100
108
|
}
|
|
101
109
|
|
|
102
110
|
/* ── Flag selector pill ── */
|
|
@@ -36,6 +36,16 @@ export interface PhoneInputCountry {
|
|
|
36
36
|
export interface PhoneInputProps {
|
|
37
37
|
/** Rótulo acessível do seletor de país. @default 'Selecionar país' */
|
|
38
38
|
countryLabel?: string;
|
|
39
|
+
/** Nomes dos países na lista e no alt da bandeira, por código ISO (ex.: `{ BR: "Brazil", ES: "Spain" }`). Código ausente mantém o nome padrão. Troque para traduzir. @default nomes em português */
|
|
40
|
+
countryNames?: {
|
|
41
|
+
[code: string]: string;
|
|
42
|
+
};
|
|
43
|
+
/** Nome acessível do botão de copiar o número. Troque para traduzir. @default 'Copiar número' */
|
|
44
|
+
copyLabel?: string;
|
|
45
|
+
/** Dica (title) do botão de copiar. Troque para traduzir. @default 'Copiar' */
|
|
46
|
+
copyTitle?: string;
|
|
47
|
+
/** Nome acessível e dica do botão de copiar logo depois da cópia. Troque para traduzir. @default 'Copiado!' */
|
|
48
|
+
copiedLabel?: string;
|
|
39
49
|
value?: string;
|
|
40
50
|
defaultValue?: string;
|
|
41
51
|
placeholder?: string;
|
|
@@ -97,14 +97,31 @@ function PhoneInput(props) {
|
|
|
97
97
|
const [internalValue, setInternalValue] = useState(() => props.defaultValue || "");
|
|
98
98
|
const [uid, setUid] = useState(() => "umds-phone-input-" + Math.random().toString(36).slice(2, 9));
|
|
99
99
|
function countryList() {
|
|
100
|
-
|
|
100
|
+
const nomes = props.countryNames;
|
|
101
|
+
if (!nomes)
|
|
102
|
+
return COUNTRIES;
|
|
103
|
+
return COUNTRIES.map((c) => ({
|
|
104
|
+
...c,
|
|
105
|
+
name: nomes[c.code] || c.name,
|
|
106
|
+
}));
|
|
101
107
|
}
|
|
102
108
|
function selectedCode() {
|
|
103
109
|
return props.country || internalCountry;
|
|
104
110
|
}
|
|
105
111
|
function currentCountry() {
|
|
106
112
|
const code = selectedCode();
|
|
107
|
-
|
|
113
|
+
const lista = countryList();
|
|
114
|
+
return lista.find((c) => c.code === code) || lista[1];
|
|
115
|
+
}
|
|
116
|
+
function copyAriaText() {
|
|
117
|
+
return copied
|
|
118
|
+
? props.copiedLabel || "Copiado!"
|
|
119
|
+
: props.copyLabel || "Copiar número";
|
|
120
|
+
}
|
|
121
|
+
function copyTitleText() {
|
|
122
|
+
return copied
|
|
123
|
+
? props.copiedLabel || "Copiado!"
|
|
124
|
+
: props.copyTitle || "Copiar";
|
|
108
125
|
}
|
|
109
126
|
function inputId() {
|
|
110
127
|
return props.id || uid;
|
|
@@ -298,7 +315,7 @@ function PhoneInput(props) {
|
|
|
298
315
|
stopAutoUpdate();
|
|
299
316
|
};
|
|
300
317
|
}, []);
|
|
301
|
-
return (_jsxs("div", { ref: rootRef, onKeyDown: (event) => handleWrapperKeydown(event), className: wrapperClasses(), children: [props.label ? (_jsx("label", { className: "umds-phone-input__label", htmlFor: inputId(), children: props.label })) : null, _jsxs("div", { className: containerClasses(), children: [_jsxs("button", { type: "button", "aria-haspopup": "listbox", className: "umds-phone-input__flag-btn", ref: flagBtnRef, onClick: (event) => toggleDropdown(), disabled: props.disabled || props.readOnly, "aria-expanded": open, "aria-label": props.countryLabel || "Selecionar país", children: [_jsx("img", { width: "16", height: "12", className: "umds-phone-input__flag-img", src: currentCountry().flagUrl, alt: currentCountry().name }), _jsx("span", { "aria-hidden": "true", className: "umds-phone-input__chevron", children: _jsx(Icon, { variant: "inherit", customSize: "10px", icon: faChevronDown }) })] }), _jsx("input", { type: "tel", inputMode: "tel", className: "umds-phone-input__field", id: inputId(), name: props.name, value: displayValue(), placeholder: props.placeholder || `${currentCountry().ddi} (000) 000-0000`, disabled: props.disabled, readOnly: props.readOnly, "aria-invalid": isInvalid(), "aria-describedby": describedBy() || undefined, onChange: (event) => handleChange(event) }), props.name ? (_jsx("input", { type: "hidden", name: props.name + "_ddi", value: currentCountry().ddi })) : null, showCopy() && !props.disabled && !props.readOnly ? (_jsxs("button", { type: "button", onClick: (event) => handleCopy(), "aria-label":
|
|
318
|
+
return (_jsxs("div", { ref: rootRef, onKeyDown: (event) => handleWrapperKeydown(event), className: wrapperClasses(), children: [props.label ? (_jsx("label", { className: "umds-phone-input__label", htmlFor: inputId(), children: props.label })) : null, _jsxs("div", { className: containerClasses(), children: [_jsxs("button", { type: "button", "aria-haspopup": "listbox", className: "umds-phone-input__flag-btn", ref: flagBtnRef, onClick: (event) => toggleDropdown(), disabled: props.disabled || props.readOnly, "aria-expanded": open, "aria-label": props.countryLabel || "Selecionar país", children: [_jsx("img", { width: "16", height: "12", className: "umds-phone-input__flag-img", src: currentCountry().flagUrl, alt: currentCountry().name }), _jsx("span", { "aria-hidden": "true", className: "umds-phone-input__chevron", children: _jsx(Icon, { variant: "inherit", customSize: "10px", icon: faChevronDown }) })] }), _jsx("input", { type: "tel", inputMode: "tel", className: "umds-phone-input__field", id: inputId(), name: props.name, value: displayValue(), placeholder: props.placeholder || `${currentCountry().ddi} (000) 000-0000`, disabled: props.disabled, readOnly: props.readOnly, "aria-invalid": isInvalid(), "aria-describedby": describedBy() || undefined, onChange: (event) => handleChange(event) }), props.name ? (_jsx("input", { type: "hidden", name: props.name + "_ddi", value: currentCountry().ddi })) : null, showCopy() && !props.disabled && !props.readOnly ? (_jsxs("button", { type: "button", onClick: (event) => handleCopy(), "aria-label": copyAriaText(), title: copyTitleText(), className: [
|
|
302
319
|
"umds-phone-input__copy-btn",
|
|
303
320
|
copied ? "umds-phone-input__copy-btn--copied" : "",
|
|
304
321
|
]
|
|
@@ -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;
|