@1doc/1ds-react 2.8.0 → 2.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +1540 -0
- package/dist/components/AILabel/AILabel.js +1 -1
- package/dist/components/Accordion/Accordion.css +13 -0
- package/dist/components/Accordion/Accordion.d.ts +9 -2
- package/dist/components/Accordion/Accordion.js +1 -0
- package/dist/components/AppSubheader/AppSubheader.css +10 -1
- package/dist/components/AttachmentCard/AttachmentCard.css +26 -8
- package/dist/components/AttachmentCard/AttachmentCard.d.ts +22 -2
- package/dist/components/AttachmentCard/AttachmentCard.js +47 -3
- package/dist/components/Avatar/Avatar.css +7 -2
- package/dist/components/Avatar/AvatarGroup.d.ts +17 -0
- package/dist/components/Avatar/AvatarGroup.js +22 -8
- package/dist/components/Badge/Badge.css +67 -2
- package/dist/components/Badge/Badge.d.ts +23 -4
- package/dist/components/Badge/Badge.js +4 -0
- package/dist/components/Box/Box.css +83 -0
- package/dist/components/Box/Box.d.ts +82 -2
- package/dist/components/Box/Box.js +42 -2
- package/dist/components/Button/Button.css +29 -0
- package/dist/components/Button/Button.d.ts +4 -4
- package/dist/components/Button/Button.js +4 -1
- package/dist/components/Calendar/Calendar.css +245 -0
- package/dist/components/Calendar/Calendar.d.ts +126 -0
- package/dist/components/Calendar/Calendar.js +320 -0
- package/dist/components/Chips/Chips.css +38 -0
- package/dist/components/Chips/Chips.d.ts +5 -2
- package/dist/components/Chips/Chips.js +2 -1
- package/dist/components/Coachmark/Coachmark.css +128 -0
- package/dist/components/Coachmark/Coachmark.d.ts +87 -0
- package/dist/components/Coachmark/Coachmark.js +362 -0
- package/dist/components/CodeBlock/CodeBlock.css +96 -0
- package/dist/components/CodeBlock/CodeBlock.d.ts +47 -0
- package/dist/components/CodeBlock/CodeBlock.js +103 -0
- package/dist/components/ColorPicker/ColorPicker.css +140 -0
- package/dist/components/ColorPicker/ColorPicker.d.ts +73 -0
- package/dist/components/ColorPicker/ColorPicker.js +219 -0
- package/dist/components/Combobox/Combobox.css +8 -0
- package/dist/components/DataTable/DataTable.css +254 -0
- package/dist/components/DataTable/DataTable.d.ts +81 -5
- package/dist/components/DataTable/DataTable.js +335 -19
- package/dist/components/DatePicker/DatePicker.css +8 -0
- package/dist/components/DatePicker/DatePicker.js +10 -1
- package/dist/components/DescriptionList/DescriptionList.css +127 -0
- package/dist/components/DescriptionList/DescriptionList.d.ts +62 -0
- package/dist/components/DescriptionList/DescriptionList.js +52 -0
- package/dist/components/EmptyState/EmptyState.d.ts +4 -2
- package/dist/components/EmptyState/EmptyState.js +2 -2
- package/dist/components/FileInput/FileInput.css +16 -0
- package/dist/components/FileInput/FileInput.d.ts +4 -2
- package/dist/components/FileInput/FileInput.js +8 -2
- package/dist/components/Grid/Grid.js +5 -5
- package/dist/components/IconPicker/IconPicker.css +107 -0
- package/dist/components/IconPicker/IconPicker.d.ts +74 -0
- package/dist/components/IconPicker/IconPicker.js +194 -0
- package/dist/components/Input/Input.css +59 -0
- package/dist/components/Input/Input.d.ts +17 -1
- package/dist/components/Input/Input.js +67 -5
- package/dist/components/Kanban/Kanban.css +4 -0
- package/dist/components/Kbd/Kbd.css +66 -0
- package/dist/components/Kbd/Kbd.d.ts +32 -0
- package/dist/components/Kbd/Kbd.js +40 -0
- package/dist/components/List/List.css +136 -0
- package/dist/components/List/List.d.ts +82 -0
- package/dist/components/List/List.js +53 -0
- package/dist/components/List/ListItem.d.ts +97 -0
- package/dist/components/List/ListItem.js +82 -0
- package/dist/components/Modal/Modal.css +80 -0
- package/dist/components/Modal/Modal.d.ts +33 -6
- package/dist/components/Modal/Modal.js +101 -6
- package/dist/components/MultiSelect/MultiSelect.css +8 -0
- package/dist/components/MultiSelect/MultiSelect.js +10 -1
- package/dist/components/OrgChart/OrgChart.css +149 -0
- package/dist/components/OrgChart/OrgChart.d.ts +83 -0
- package/dist/components/OrgChart/OrgChart.js +297 -0
- package/dist/components/OtpInput/OtpInput.css +93 -0
- package/dist/components/OtpInput/OtpInput.d.ts +60 -0
- package/dist/components/OtpInput/OtpInput.js +215 -0
- package/dist/components/PhoneInput/PhoneInput.css +8 -0
- package/dist/components/Popover/Popover.d.ts +7 -0
- package/dist/components/Popover/Popover.js +11 -1
- package/dist/components/RichTextEditor/RichTextEditor.css +250 -0
- package/dist/components/RichTextEditor/RichTextEditor.d.ts +97 -0
- package/dist/components/RichTextEditor/RichTextEditor.js +951 -0
- package/dist/components/SegmentedControl/SegmentedControl.css +24 -0
- package/dist/components/SegmentedControl/SegmentedControl.d.ts +2 -0
- package/dist/components/SegmentedControl/SegmentedControl.js +10 -2
- package/dist/components/Select/Select.css +164 -0
- package/dist/components/Select/Select.d.ts +34 -0
- package/dist/components/Select/Select.js +258 -28
- package/dist/components/Stack/Stack.css +49 -0
- package/dist/components/Stack/Stack.d.ts +65 -7
- package/dist/components/Stack/Stack.js +30 -2
- package/dist/components/StatCard/StatCard.css +138 -0
- package/dist/components/StatCard/StatCard.d.ts +26 -0
- package/dist/components/StatCard/StatCard.js +13 -1
- package/dist/components/Tabs/Tab.d.ts +15 -0
- package/dist/components/Tabs/Tab.js +30 -1
- package/dist/components/Tabs/Tabs.css +132 -0
- package/dist/components/Tabs/Tabs.d.ts +7 -0
- package/dist/components/Tabs/Tabs.js +13 -2
- package/dist/components/Tag/Tag.css +85 -2
- package/dist/components/Tag/Tag.d.ts +13 -6
- package/dist/components/Tag/Tag.js +1 -0
- package/dist/components/Text/Text.js +2 -2
- package/dist/components/Textarea/Textarea.css +8 -0
- package/dist/components/TimePicker/TimePicker.css +8 -0
- package/dist/components/Toast/Toast.css +32 -0
- package/dist/components/Toast/Toast.d.ts +18 -0
- package/dist/components/Toast/Toast.js +14 -1
- package/dist/components/Toast/ToastStack.js +8 -1
- package/dist/components/Tooltip/Tooltip.css +25 -0
- package/dist/components/Tooltip/Tooltip.d.ts +11 -0
- package/dist/components/Tooltip/Tooltip.js +18 -3
- package/dist/index.d.ts +25 -0
- package/dist/index.js +14 -0
- package/dist/teste/AILabel.test.d.ts +1 -0
- package/dist/teste/AILabel.test.js +33 -0
- package/dist/teste/AccordionConteudoLivre.test.d.ts +1 -0
- package/dist/teste/AccordionConteudoLivre.test.js +29 -0
- package/dist/teste/AccordionTituloNeutro.test.d.ts +1 -0
- package/dist/teste/AccordionTituloNeutro.test.js +23 -0
- package/dist/teste/AppSubheaderRegiao.test.d.ts +1 -0
- package/dist/teste/AppSubheaderRegiao.test.js +13 -0
- package/dist/teste/AtributosRepassados.test.d.ts +1 -0
- package/dist/teste/AtributosRepassados.test.js +52 -0
- package/dist/teste/AttachmentCardIA.test.d.ts +1 -0
- package/dist/teste/AttachmentCardIA.test.js +89 -0
- package/dist/teste/AttachmentCardLista.test.d.ts +1 -0
- package/dist/teste/AttachmentCardLista.test.js +49 -0
- package/dist/teste/AttachmentCardSm.test.d.ts +1 -0
- package/dist/teste/AttachmentCardSm.test.js +26 -0
- package/dist/teste/AvatarGroupOverlap.test.d.ts +1 -0
- package/dist/teste/AvatarGroupOverlap.test.js +56 -0
- package/dist/teste/BadgeNeutroColado.test.d.ts +1 -0
- package/dist/teste/BadgeNeutroColado.test.js +11 -0
- package/dist/teste/BadgeTag.test.d.ts +1 -0
- package/dist/teste/BadgeTag.test.js +55 -0
- package/dist/teste/BoxItemFlex.test.d.ts +1 -0
- package/dist/teste/BoxItemFlex.test.js +54 -0
- package/dist/teste/BoxLayout.test.d.ts +1 -0
- package/dist/teste/BoxLayout.test.js +35 -0
- package/dist/teste/Button.test.d.ts +1 -0
- package/dist/teste/Button.test.js +27 -0
- package/dist/teste/Calendar.test.d.ts +1 -0
- package/dist/teste/Calendar.test.js +221 -0
- package/dist/teste/CalendarCabecalho.test.d.ts +1 -0
- package/dist/teste/CalendarCabecalho.test.js +11 -0
- package/dist/teste/ChipsXs.test.d.ts +1 -0
- package/dist/teste/ChipsXs.test.js +31 -0
- package/dist/teste/Coachmark.test.d.ts +1 -0
- package/dist/teste/Coachmark.test.js +149 -0
- package/dist/teste/CoachmarkSemVeu.test.d.ts +1 -0
- package/dist/teste/CoachmarkSemVeu.test.js +85 -0
- package/dist/teste/ColorPicker.test.d.ts +1 -0
- package/dist/teste/ColorPicker.test.js +132 -0
- package/dist/teste/ColorPickerXs.test.d.ts +1 -0
- package/dist/teste/ColorPickerXs.test.js +21 -0
- package/dist/teste/DataTableArvoreEVariantes.test.d.ts +1 -0
- package/dist/teste/DataTableArvoreEVariantes.test.js +190 -0
- package/dist/teste/DataTableCelulaLivre.test.d.ts +1 -0
- package/dist/teste/DataTableCelulaLivre.test.js +76 -0
- package/dist/teste/DataTableDocumento.test.d.ts +1 -0
- package/dist/teste/DataTableDocumento.test.js +92 -0
- package/dist/teste/DatePicker.test.js +23 -0
- package/dist/teste/DescriptionListCompacta.test.d.ts +1 -0
- package/dist/teste/DescriptionListCompacta.test.js +22 -0
- package/dist/teste/EmptyStateTituloRico.test.d.ts +1 -0
- package/dist/teste/EmptyStateTituloRico.test.js +23 -0
- package/dist/teste/FileInputTrigger.test.d.ts +1 -0
- package/dist/teste/FileInputTrigger.test.js +53 -0
- package/dist/teste/IconPicker.test.d.ts +1 -0
- package/dist/teste/IconPicker.test.js +130 -0
- package/dist/teste/InputAgrupado.test.d.ts +1 -0
- package/dist/teste/InputAgrupado.test.js +24 -0
- package/dist/teste/InputMascaraEAfins.test.d.ts +1 -0
- package/dist/teste/InputMascaraEAfins.test.js +99 -0
- package/dist/teste/KbdCodeBlock.test.d.ts +1 -0
- package/dist/teste/KbdCodeBlock.test.js +95 -0
- package/dist/teste/List.test.d.ts +1 -0
- package/dist/teste/List.test.js +153 -0
- package/dist/teste/ListItemTooltipStandalone.test.d.ts +1 -0
- package/dist/teste/ListItemTooltipStandalone.test.js +39 -0
- package/dist/teste/ModalVariantes.test.d.ts +1 -0
- package/dist/teste/ModalVariantes.test.js +151 -0
- package/dist/teste/NomeAcessivelSsr.test.d.ts +1 -0
- package/dist/teste/NomeAcessivelSsr.test.js +88 -0
- package/dist/teste/OrgChart.test.d.ts +1 -0
- package/dist/teste/OrgChart.test.js +162 -0
- package/dist/teste/OtpInput.test.d.ts +1 -0
- package/dist/teste/OtpInput.test.js +143 -0
- package/dist/teste/PopoverMaxHeight.test.d.ts +1 -0
- package/dist/teste/PopoverMaxHeight.test.js +38 -0
- package/dist/teste/RichTextEditor.test.d.ts +1 -0
- package/dist/teste/RichTextEditor.test.js +287 -0
- package/dist/teste/RichTextEditorAlinhaImagemTabela.test.d.ts +1 -0
- package/dist/teste/RichTextEditorAlinhaImagemTabela.test.js +212 -0
- package/dist/teste/RichTextEditorEstiloDeTexto.test.d.ts +1 -0
- package/dist/teste/RichTextEditorEstiloDeTexto.test.js +120 -0
- package/dist/teste/SegmentedControlContador.test.d.ts +1 -0
- package/dist/teste/SegmentedControlContador.test.js +39 -0
- package/dist/teste/SelectAbertoControladoEFlutuante.test.d.ts +1 -0
- package/dist/teste/SelectAbertoControladoEFlutuante.test.js +145 -0
- package/dist/teste/SelectFiltroCorETamanho.test.d.ts +1 -0
- package/dist/teste/SelectFiltroCorETamanho.test.js +77 -0
- package/dist/teste/SelectPlacementFiltro.test.d.ts +1 -0
- package/dist/teste/SelectPlacementFiltro.test.js +88 -0
- package/dist/teste/Stack.test.d.ts +1 -0
- package/dist/teste/Stack.test.js +57 -0
- package/dist/teste/StatCardRotuloTopo.test.d.ts +1 -0
- package/dist/teste/StatCardRotuloTopo.test.js +34 -0
- package/dist/teste/StatCardSecundariaETom.test.d.ts +1 -0
- package/dist/teste/StatCardSecundariaETom.test.js +45 -0
- package/dist/teste/TabsContadorFechavel.test.d.ts +1 -0
- package/dist/teste/TabsContadorFechavel.test.js +79 -0
- package/dist/teste/ToastAcaoEDetalhes.test.d.ts +1 -0
- package/dist/teste/ToastAcaoEDetalhes.test.js +94 -0
- package/dist/teste/TooltipDark.test.d.ts +1 -0
- package/dist/teste/TooltipDark.test.js +31 -0
- package/dist/utils/calendario.d.ts +28 -0
- package/dist/utils/calendario.js +73 -0
- package/dist/utils/html-seguro.d.ts +45 -0
- package/dist/utils/html-seguro.js +208 -0
- package/dist/utils/paleta-de-cores.d.ts +26 -0
- package/dist/utils/paleta-de-cores.js +10 -0
- package/dist/utils/texto.d.ts +5 -0
- package/dist/utils/texto.js +5 -0
- package/dist/utils/toast.d.ts +10 -1
- package/dist/utils/toast.js +2 -1
- package/package.json +3 -3
- package/src/index.ts +26 -0
- package/src/teste/AILabel.test.tsx +41 -0
- package/src/teste/AccordionConteudoLivre.test.tsx +39 -0
- package/src/teste/AccordionTituloNeutro.test.tsx +25 -0
- package/src/teste/AppSubheaderRegiao.test.tsx +17 -0
- package/src/teste/AtributosRepassados.test.tsx +73 -0
- package/src/teste/AttachmentCardIA.test.tsx +126 -0
- package/src/teste/AttachmentCardLista.test.tsx +53 -0
- package/src/teste/AttachmentCardSm.test.tsx +29 -0
- package/src/teste/AvatarGroupOverlap.test.tsx +74 -0
- package/src/teste/BadgeNeutroColado.test.tsx +15 -0
- package/src/teste/BadgeTag.test.tsx +85 -0
- package/src/teste/BoxItemFlex.test.tsx +81 -0
- package/src/teste/BoxLayout.test.tsx +50 -0
- package/src/teste/Button.test.tsx +39 -0
- package/src/teste/Calendar.test.tsx +282 -0
- package/src/teste/CalendarCabecalho.test.tsx +11 -0
- package/src/teste/ChipsXs.test.tsx +41 -0
- package/src/teste/Coachmark.test.tsx +198 -0
- package/src/teste/CoachmarkSemVeu.test.tsx +101 -0
- package/src/teste/ColorPicker.test.tsx +153 -0
- package/src/teste/ColorPickerXs.test.tsx +22 -0
- package/src/teste/DataTableArvoreEVariantes.test.tsx +240 -0
- package/src/teste/DataTableCelulaLivre.test.tsx +103 -0
- package/src/teste/DataTableDocumento.test.tsx +102 -0
- package/src/teste/DatePicker.test.tsx +38 -0
- package/src/teste/DescriptionListCompacta.test.tsx +24 -0
- package/src/teste/EmptyStateTituloRico.test.tsx +34 -0
- package/src/teste/FileInputTrigger.test.tsx +89 -0
- package/src/teste/IconPicker.test.tsx +145 -0
- package/src/teste/InputAgrupado.test.tsx +26 -0
- package/src/teste/InputMascaraEAfins.test.tsx +124 -0
- package/src/teste/KbdCodeBlock.test.tsx +106 -0
- package/src/teste/List.test.tsx +269 -0
- package/src/teste/ListItemTooltipStandalone.test.tsx +64 -0
- package/src/teste/ModalVariantes.test.tsx +173 -0
- package/src/teste/NomeAcessivelSsr.test.tsx +110 -0
- package/src/teste/OrgChart.test.tsx +183 -0
- package/src/teste/OtpInput.test.tsx +163 -0
- package/src/teste/PopoverMaxHeight.test.tsx +47 -0
- package/src/teste/RichTextEditor.test.tsx +329 -0
- package/src/teste/RichTextEditorAlinhaImagemTabela.test.tsx +238 -0
- package/src/teste/RichTextEditorEstiloDeTexto.test.tsx +137 -0
- package/src/teste/SegmentedControlContador.test.tsx +43 -0
- package/src/teste/SelectAbertoControladoEFlutuante.test.tsx +180 -0
- package/src/teste/SelectFiltroCorETamanho.test.tsx +90 -0
- package/src/teste/SelectPlacementFiltro.test.tsx +110 -0
- package/src/teste/Stack.test.tsx +80 -0
- package/src/teste/StatCardRotuloTopo.test.tsx +44 -0
- package/src/teste/StatCardSecundariaETom.test.tsx +51 -0
- package/src/teste/TabsContadorFechavel.test.tsx +144 -0
- package/src/teste/ToastAcaoEDetalhes.test.tsx +109 -0
- package/src/teste/TooltipDark.test.tsx +51 -0
- package/src/utils/calendario.ts +78 -0
- package/src/utils/html-seguro.ts +197 -0
- package/src/utils/paleta-de-cores.ts +34 -0
- package/src/utils/texto.ts +5 -0
- package/src/utils/toast.ts +12 -2
|
@@ -186,6 +186,14 @@
|
|
|
186
186
|
cursor: default;
|
|
187
187
|
}
|
|
188
188
|
|
|
189
|
+
/* Somente leitura não é desabilitado: o texto segue lido e a WCAG 1.4.3 vale
|
|
190
|
+
sem isenção. O placeholder padrão foi calibrado para fundo branco e cai para
|
|
191
|
+
~4,2:1 sobre o fundo de somente leitura; neutral-dark-down passa 4,5:1 em
|
|
192
|
+
todos os temas (1doc 6,78:1 · 1doc-dark 10,83:1 · alto contraste 16,48:1). */
|
|
193
|
+
.umds-input--readonly .umds-input__control::placeholder {
|
|
194
|
+
color: var(--umds-semantic-color-neutral-dark-down);
|
|
195
|
+
}
|
|
196
|
+
|
|
189
197
|
/* ── Ícone esquerdo ── */
|
|
190
198
|
.umds-input__icon-left {
|
|
191
199
|
display: flex;
|
|
@@ -196,6 +204,20 @@
|
|
|
196
204
|
flex-shrink: 0;
|
|
197
205
|
}
|
|
198
206
|
|
|
207
|
+
/* ── Ícone decorativo à direita (iconRight) ── */
|
|
208
|
+
.umds-input__icon-right {
|
|
209
|
+
display: flex;
|
|
210
|
+
align-items: center;
|
|
211
|
+
justify-content: center;
|
|
212
|
+
margin-left: var(--umds-primitive-spacing-nano);
|
|
213
|
+
color: var(--umds-semantic-color-neutral-dark-medium);
|
|
214
|
+
flex-shrink: 0;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
.umds-input--disabled .umds-input__icon-right {
|
|
218
|
+
color: var(--umds-semantic-color-neutral-dark-up);
|
|
219
|
+
}
|
|
220
|
+
|
|
199
221
|
/* ── Ações à direita (botões de ícone) ── */
|
|
200
222
|
.umds-input__actions-right {
|
|
201
223
|
display: flex;
|
|
@@ -235,6 +257,43 @@
|
|
|
235
257
|
outline-offset: 0; /* exceção ao offset 2px: o botão vive DENTRO do campo, e o afastamento invadiria a borda */
|
|
236
258
|
}
|
|
237
259
|
|
|
260
|
+
/* ── borderless: o campo dentro de um grupo que já tem a moldura ──
|
|
261
|
+
Sem borda, fundo e raio. O foco NÃO some: o anel do campo vira um contorno
|
|
262
|
+
para dentro (WCAG 2.4.7), e o erro mantém a borda vermelha (a cor do erro não
|
|
263
|
+
pode depender só da moldura do grupo). Sem erro, hover e foco não pintam borda. */
|
|
264
|
+
.umds-input--borderless:not(.umds-input--error) .umds-input__container {
|
|
265
|
+
border-color: transparent;
|
|
266
|
+
border-radius: 0;
|
|
267
|
+
background-color: transparent;
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
.umds-input--borderless .umds-input__container:focus-within:not(.umds-input__container--disabled):not(.umds-input__container--readonly) {
|
|
271
|
+
box-shadow: none;
|
|
272
|
+
outline: 2px solid var(--umds-semantic-color-primary-pure);
|
|
273
|
+
outline-offset: -2px;
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
/* ── grouped: o campo dentro de um contêiner que já tem moldura e foco ──
|
|
277
|
+
O campo de chips: as tags e o input moram na mesma caixa, e quem desenha a moldura
|
|
278
|
+
e o foco (`:focus-within`) é o contêiner. Aqui o campo não impõe altura de campo
|
|
279
|
+
(a linha cresce com as tags), nem padding, nem anel próprio. */
|
|
280
|
+
.umds-input--grouped:not(.umds-input--full-width) {
|
|
281
|
+
width: auto;
|
|
282
|
+
flex: 1 1 var(--umds-primitive-spacing-xxl); /* 80px: o input nunca encolhe a ponto de sumir */
|
|
283
|
+
min-width: 0;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
.umds-input--grouped .umds-input__container {
|
|
287
|
+
height: auto;
|
|
288
|
+
min-height: 0;
|
|
289
|
+
padding: 0;
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
.umds-input--grouped .umds-input__container:focus-within:not(.umds-input__container--disabled):not(.umds-input__container--readonly) {
|
|
293
|
+
outline: none;
|
|
294
|
+
box-shadow: none;
|
|
295
|
+
}
|
|
296
|
+
|
|
238
297
|
/* ── Mobile: fonte ≥16px no controle (decisão 25/07) ──
|
|
239
298
|
Fonte <16px num campo focado dispara zoom automático no Safari iOS.
|
|
240
299
|
Só abaixo do breakpoint-sm (640px) — desktop permanece idêntico. */
|
|
@@ -34,7 +34,11 @@ export interface InputAction {
|
|
|
34
34
|
* @property {string} ariaLabel - Nome acessível quando não há label visível
|
|
35
35
|
* @property {IconProp} iconLeft - Ícone Font Awesome à esquerda
|
|
36
36
|
* @property {InputAction[]} iconsRight - Botões de ação com ícone à direita
|
|
37
|
-
* @property {
|
|
37
|
+
* @property {IconProp} iconRight - Ícone decorativo à direita (não é botão, some para o leitor de tela). Para ação clicável, use `iconsRight`.
|
|
38
|
+
* @property {boolean} grouped - O campo vive dentro de um contêiner que já desenha a moldura E o foco (o campo de chips: as tags e o input na mesma caixa). Implica `borderless`, e tira a altura de campo, o padding e o anel de foco próprio: o contêiner mostra o foco com `:focus-within`. Sem esse foco no contêiner, quem usa teclado perde o indicador (WCAG 2.4.7).
|
|
39
|
+
* @property {boolean} borderless - Sem borda, fundo e raio: o campo dentro de um grupo que já tem a moldura (um Select e um Input lado a lado numa mesma caixa). O foco continua visível, em contorno, e o erro mantém a borda vermelha.
|
|
40
|
+
* @property {string} mask - Máscara simples: 'cpf' | 'cnpj' | 'cep' | 'phone'. O valor exibido e o que chega em `onChange` já vêm formatados (para só os dígitos, `valor.replace(/\D/g, "")`). Aceita só dígitos, limita o tamanho e abre o teclado numérico no celular.
|
|
41
|
+
* @property {function} onChange - Callback acionado A CADA TECLA (recebe o novo valor string), nos dois frameworks. O blur sai em `onBlur`.
|
|
38
42
|
* @property {function} onFocus - Callback de foco (recebe o evento nativo)
|
|
39
43
|
* @property {function} onBlur - Callback de blur (recebe o evento nativo)
|
|
40
44
|
* @quandoUsar Entrada de texto de UMA linha: nome, e-mail, número, busca. É o campo padrão quando o dado é curto e livre.
|
|
@@ -87,6 +91,18 @@ export interface InputProps {
|
|
|
87
91
|
hidePasswordLabel?: string;
|
|
88
92
|
iconLeft?: IconProp;
|
|
89
93
|
iconsRight?: InputAction[];
|
|
94
|
+
/** Ícone decorativo à direita (não clicável, `aria-hidden`). Para ação, use `iconsRight`. */
|
|
95
|
+
iconRight?: IconProp;
|
|
96
|
+
/** Sem borda, fundo e raio, para o campo dentro de um grupo que já tem a moldura. O foco e o erro continuam visíveis. @default false */
|
|
97
|
+
borderless?: boolean;
|
|
98
|
+
/**
|
|
99
|
+
* O campo dentro de um contêiner que já tem a moldura e o foco (o campo de chips).
|
|
100
|
+
* Implica `borderless` e tira a altura de campo, o padding e o anel de foco
|
|
101
|
+
* próprio: o foco vem do contêiner (`:focus-within`). @default false
|
|
102
|
+
*/
|
|
103
|
+
grouped?: boolean;
|
|
104
|
+
/** Máscara simples. O valor exibido e o de `onChange` já saem formatados. */
|
|
105
|
+
mask?: "cpf" | "cnpj" | "cep" | "phone";
|
|
90
106
|
onChange?: (value: string) => void;
|
|
91
107
|
onFocus?: (event?: any) => void;
|
|
92
108
|
onBlur?: (event?: any) => void;
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
3
|
import './Input.css';
|
|
4
|
-
import { useState } from "react";
|
|
4
|
+
import { useState, useRef } from "react";
|
|
5
5
|
import { faEye, faEyeSlash } from "@fortawesome/free-solid-svg-icons";
|
|
6
6
|
import Icon from "../Icon/Icon";
|
|
7
7
|
import Text from "../Text/Text";
|
|
8
8
|
function Input(props) {
|
|
9
|
+
const ultimoEventoRef = useRef(null);
|
|
10
|
+
const ultimoValorRef = useRef(null);
|
|
9
11
|
const [isPasswordVisible, setIsPasswordVisible] = useState(() => false);
|
|
10
12
|
const [internalValue, setInternalValue] = useState(() => props.defaultValue || "");
|
|
11
13
|
const [uid, setUid] = useState(() => "umds-input-" + Math.random().toString(36).slice(2, 9));
|
|
@@ -48,6 +50,8 @@ function Input(props) {
|
|
|
48
50
|
props.disabled ? "umds-input--disabled" : "",
|
|
49
51
|
props.readOnly ? "umds-input--readonly" : "",
|
|
50
52
|
props.numberSpinner ? "umds-input--number-spinner" : "",
|
|
53
|
+
props.borderless || props.grouped ? "umds-input--borderless" : "",
|
|
54
|
+
props.grouped ? "umds-input--grouped" : "",
|
|
51
55
|
`umds-input--${props.size || "md"}`,
|
|
52
56
|
props.className,
|
|
53
57
|
]
|
|
@@ -69,16 +73,74 @@ function Input(props) {
|
|
|
69
73
|
function iconSize() {
|
|
70
74
|
return props.size === "sm" || props.size === "xs" ? "sm" : "md";
|
|
71
75
|
}
|
|
76
|
+
function aplicarMascara(valor) {
|
|
77
|
+
const texto = valor === undefined || valor === null ? "" : String(valor);
|
|
78
|
+
if (!props.mask)
|
|
79
|
+
return texto;
|
|
80
|
+
let digitos = texto.replace(/\D/g, "");
|
|
81
|
+
let padrao = "";
|
|
82
|
+
if (props.mask === "cpf")
|
|
83
|
+
padrao = "###.###.###-##";
|
|
84
|
+
else if (props.mask === "cnpj")
|
|
85
|
+
padrao = "##.###.###/####-##";
|
|
86
|
+
else if (props.mask === "cep")
|
|
87
|
+
padrao = "#####-###";
|
|
88
|
+
else if (props.mask === "phone")
|
|
89
|
+
padrao = digitos.length > 10 ? "(##) #####-####" : "(##) ####-####";
|
|
90
|
+
let saida = "";
|
|
91
|
+
let posicao = 0;
|
|
92
|
+
for (let i = 0; i < padrao.length && posicao < digitos.length; i++) {
|
|
93
|
+
if (padrao.charAt(i) === "#") {
|
|
94
|
+
saida += digitos.charAt(posicao);
|
|
95
|
+
posicao++;
|
|
96
|
+
}
|
|
97
|
+
else {
|
|
98
|
+
saida += padrao.charAt(i);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
return saida;
|
|
102
|
+
}
|
|
103
|
+
function tamanhoMaximo() {
|
|
104
|
+
if (props.mask === "cpf")
|
|
105
|
+
return 14;
|
|
106
|
+
if (props.mask === "cnpj")
|
|
107
|
+
return 18;
|
|
108
|
+
if (props.mask === "cep")
|
|
109
|
+
return 9;
|
|
110
|
+
if (props.mask === "phone")
|
|
111
|
+
return 15;
|
|
112
|
+
return undefined;
|
|
113
|
+
}
|
|
114
|
+
function modoDoTeclado() {
|
|
115
|
+
return props.mask ? "numeric" : undefined;
|
|
116
|
+
}
|
|
117
|
+
function valorExibido() {
|
|
118
|
+
const bruto = props.value !== undefined ? props.value : internalValue;
|
|
119
|
+
return aplicarMascara(bruto);
|
|
120
|
+
}
|
|
72
121
|
function handleChange(event) {
|
|
73
|
-
|
|
122
|
+
const nativo = event.nativeEvent || event;
|
|
123
|
+
if (nativo === ultimoEventoRef.current)
|
|
124
|
+
return;
|
|
125
|
+
ultimoEventoRef.current = nativo;
|
|
126
|
+
const valor = aplicarMascara(event.target.value);
|
|
127
|
+
// O `change` do blur (Vue) repete o que o `input` da última tecla
|
|
128
|
+
// entregou; só passa se o valor mudou de fato (ex.: change disparado à mão).
|
|
129
|
+
if (nativo.type === "change" && valor === ultimoValorRef.current)
|
|
130
|
+
return;
|
|
131
|
+
ultimoValorRef.current = valor;
|
|
132
|
+
if (props.mask && event.target.value !== valor) {
|
|
133
|
+
event.target.value = valor;
|
|
134
|
+
}
|
|
135
|
+
setInternalValue(valor);
|
|
74
136
|
if (props.onChange) {
|
|
75
|
-
props.onChange(
|
|
137
|
+
props.onChange(valor);
|
|
76
138
|
}
|
|
77
139
|
}
|
|
78
|
-
return (_jsxs("div", { className: wrapperClasses(), children: [props.label ? (_jsxs(Text, { as: "label", variant: "label", className: "umds-input__label", forId: inputId(), children: [_jsx(_Fragment, { children: props.label }), props.required ? (_jsx("span", { className: "umds-input__required", children: "*" })) : null] })) : null, _jsxs("div", { className: inputContainerClasses(), children: [props.iconLeft ? (_jsx("div", { className: "umds-input__icon-left", children: _jsx(Icon, { icon: props.iconLeft, size: iconSize() }) })) : null, _jsx("input", { className: "umds-input__control", id: inputId(), type: inputType(), name: props.name, min: props.min, max: props.max, step: props.step, disabled: props.disabled, readOnly: props.readOnly, placeholder: props.placeholder, value:
|
|
140
|
+
return (_jsxs("div", { className: wrapperClasses(), children: [props.label ? (_jsxs(Text, { as: "label", variant: "label", className: "umds-input__label", forId: inputId(), children: [_jsx(_Fragment, { children: props.label }), props.required ? (_jsx("span", { className: "umds-input__required", children: "*" })) : null] })) : null, _jsxs("div", { className: inputContainerClasses(), children: [props.iconLeft ? (_jsx("div", { className: "umds-input__icon-left", children: _jsx(Icon, { icon: props.iconLeft, size: iconSize() }) })) : null, _jsx("input", { className: "umds-input__control", id: inputId(), type: inputType(), name: props.name, min: props.min, max: props.max, step: props.step, disabled: props.disabled, readOnly: props.readOnly, placeholder: props.placeholder, value: valorExibido(), maxLength: tamanhoMaximo(), inputMode: modoDoTeclado(), onInput: (event) => handleChange(event), onChange: (event) => handleChange(event), onFocus: (event) => props.onFocus?.(event), onBlur: (event) => props.onBlur?.(event), "aria-label": props.ariaLabel, "aria-invalid": !!props.invalid ||
|
|
79
141
|
!!(props.errorMessage && props.errorMessage.length > 0), "aria-describedby": describedBy() || undefined, required: props.required }), _jsxs("div", { className: "umds-input__actions-right", children: [props.type === "password" ? (_jsx("button", { type: "button", className: "umds-input__action-btn", disabled: props.disabled, onClick: (event) => togglePassword(), "aria-label": passwordToggleLabel(), children: _jsx(Icon, { icon: isPasswordVisible ? faEyeSlash : faEye, size: iconSize() }) })) : null, props.iconsRight?.length ? (_jsx(_Fragment, { children: props.iconsRight?.map((action, index) => (_jsx("button", { type: "button", className: "umds-input__action-btn", disabled: props.disabled, onClick: (e) => {
|
|
80
142
|
e.stopPropagation();
|
|
81
143
|
action.onClick?.(e);
|
|
82
|
-
}, title: action.tooltip, "aria-label": action.label || action.tooltip, children: _jsx(Icon, { icon: action.icon, size: iconSize() }) }, index))) })) : null] })] }), props.errorMessage ? (_jsx(Text, { as: "span", variant: "caption", color: "negative", id: errorId(), children: _jsx(_Fragment, { children: props.errorMessage }) })) : null, props.helperText ? (_jsx(Text, { as: "span", variant: "caption", color: "secondary", id: helperId(), children: _jsx(_Fragment, { children: props.helperText }) })) : null] }));
|
|
144
|
+
}, title: action.tooltip, "aria-label": action.label || action.tooltip, children: _jsx(Icon, { icon: action.icon, size: iconSize() }) }, index))) })) : null] }), props.iconRight ? (_jsx("div", { "aria-hidden": "true", className: "umds-input__icon-right", children: _jsx(Icon, { icon: props.iconRight, size: iconSize() }) })) : null] }), props.errorMessage ? (_jsx(Text, { as: "span", variant: "caption", color: "negative", id: errorId(), children: _jsx(_Fragment, { children: props.errorMessage }) })) : null, props.helperText ? (_jsx(Text, { as: "span", variant: "caption", color: "secondary", id: helperId(), children: _jsx(_Fragment, { children: props.helperText }) })) : null] }));
|
|
83
145
|
}
|
|
84
146
|
export default Input;
|
|
@@ -7,7 +7,11 @@
|
|
|
7
7
|
cartão.
|
|
8
8
|
============================================ */
|
|
9
9
|
|
|
10
|
+
/* `position: relative` ancora os textos só para leitor de tela (absolutos) das
|
|
11
|
+
colunas dentro da área que rola; sem ele, o de uma coluna fora da tela sobe
|
|
12
|
+
até a página e cria rolagem horizontal nela. */
|
|
10
13
|
.umds-kanban {
|
|
14
|
+
position: relative;
|
|
11
15
|
display: flex;
|
|
12
16
|
align-items: stretch;
|
|
13
17
|
gap: var(--umds-primitive-spacing-xxxs);
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/* ─────────────────────────────────────────────
|
|
2
|
+
KBD
|
|
3
|
+
Uma tecla, ou uma combinação, em fonte monoespaçada.
|
|
4
|
+
|
|
5
|
+
A caixa é cinza com borda e uma sombra de base de 1px (a "espessura" da
|
|
6
|
+
tecla). Texto escuro sobre cinza claro: contraste de texto, não só de cor.
|
|
7
|
+
|
|
8
|
+
Cores: semânticos · Medidas: primitivos
|
|
9
|
+
───────────────────────────────────────────── */
|
|
10
|
+
|
|
11
|
+
.umds-kbd {
|
|
12
|
+
display: inline-block;
|
|
13
|
+
box-sizing: border-box;
|
|
14
|
+
min-width: var(--umds-primitive-spacing-xxs); /* 24px */
|
|
15
|
+
padding: var(--umds-primitive-spacing-micro) var(--umds-primitive-spacing-nano); /* 2px 8px */
|
|
16
|
+
font-family: var(--umds-semantic-font-family-mono);
|
|
17
|
+
font-weight: var(--umds-primitive-font-weight-semibold);
|
|
18
|
+
line-height: var(--umds-primitive-font-line-height-lg);
|
|
19
|
+
text-align: center;
|
|
20
|
+
white-space: nowrap;
|
|
21
|
+
color: var(--umds-semantic-color-neutral-dark-pure);
|
|
22
|
+
background: var(--umds-semantic-color-background-light);
|
|
23
|
+
border: var(--umds-primitive-border-width-hairline) solid var(--umds-semantic-color-neutral-light-down);
|
|
24
|
+
border-bottom-width: var(--umds-primitive-border-width-thin);
|
|
25
|
+
border-radius: var(--umds-primitive-border-radius-xs);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
.umds-kbd.umds-kbd--md {
|
|
29
|
+
font-size: var(--umds-primitive-font-size-xxs); /* 14px */
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
.umds-kbd.umds-kbd--sm {
|
|
33
|
+
min-width: 0;
|
|
34
|
+
padding: 0 var(--umds-primitive-spacing-quarck); /* 0 4px */
|
|
35
|
+
font-size: var(--umds-primitive-font-size-xxxs); /* 12px */
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/* ── Combinação ── */
|
|
39
|
+
.umds-kbd-combo {
|
|
40
|
+
display: inline-flex;
|
|
41
|
+
align-items: center;
|
|
42
|
+
gap: var(--umds-primitive-spacing-quarck); /* 4px */
|
|
43
|
+
font-family: var(--umds-semantic-font-family-mono);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
.umds-kbd-combo__item {
|
|
47
|
+
display: inline-flex;
|
|
48
|
+
align-items: center;
|
|
49
|
+
gap: var(--umds-primitive-spacing-quarck); /* 4px */
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
.umds-kbd-combo__separator {
|
|
53
|
+
font-size: var(--umds-primitive-font-size-xxxs); /* 12px */
|
|
54
|
+
color: var(--umds-semantic-color-neutral-dark-down);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/* O tamanho do conjunto vale para cada tecla dentro dele. */
|
|
58
|
+
.umds-kbd-combo.umds-kbd--md .umds-kbd--inner {
|
|
59
|
+
font-size: var(--umds-primitive-font-size-xxs); /* 14px */
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
.umds-kbd-combo.umds-kbd--sm .umds-kbd--inner {
|
|
63
|
+
min-width: 0;
|
|
64
|
+
padding: 0 var(--umds-primitive-spacing-quarck); /* 0 4px */
|
|
65
|
+
font-size: var(--umds-primitive-font-size-xxxs); /* 12px */
|
|
66
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import './Kbd.css';
|
|
2
|
+
/**
|
|
3
|
+
* Kbd — uma tecla, ou uma combinação de teclas, num `<kbd>`.
|
|
4
|
+
*
|
|
5
|
+
* Uma tecla: `<Kbd>Esc</Kbd>`. Uma combinação: `keys` (`["Ctrl", "Shift", "P"]`),
|
|
6
|
+
* que desenha uma caixa por tecla com o `separator` entre elas (`+` por padrão).
|
|
7
|
+
* A fonte é a monoespaçada do DS (`--umds-semantic-font-family-mono`), a caixa é
|
|
8
|
+
* cinza com borda e uma sombra de base, como uma tecla de verdade.
|
|
9
|
+
*
|
|
10
|
+
* Semântica: `<kbd>` é o elemento HTML de "entrada de teclado", e um `<kbd>`
|
|
11
|
+
* dentro de outro é a forma de dizer "combinação de teclas". O leitor de tela lê
|
|
12
|
+
* "Ctrl + Shift + P" (o separador é texto, não desenho).
|
|
13
|
+
* @property {string[]} keys - Teclas de uma combinação, em ordem. Sem `keys`, vale o conteúdo (uma tecla)
|
|
14
|
+
* @property {string} separator - Texto entre as teclas de uma combinação (padrão "+")
|
|
15
|
+
* @property {string} size - 'sm' | 'md' (padrão)
|
|
16
|
+
* @property {string} className - Classes CSS adicionais
|
|
17
|
+
* @quandoUsar Mostrar um atalho de teclado ou a tecla que a pessoa deve apertar: painel de atalhos, dica de campo, instrução.
|
|
18
|
+
* @quandoNaoUsar Para botão, use `Button`. Para trecho de código, use `CodeBlock`.
|
|
19
|
+
*/
|
|
20
|
+
export interface KbdProps {
|
|
21
|
+
keys?: string[];
|
|
22
|
+
separator?: string;
|
|
23
|
+
size?: "sm" | "md";
|
|
24
|
+
className?: string;
|
|
25
|
+
id?: string;
|
|
26
|
+
style?: any;
|
|
27
|
+
[key: string]: any;
|
|
28
|
+
/** Uma tecla (quando não há `keys`). */
|
|
29
|
+
children?: any;
|
|
30
|
+
}
|
|
31
|
+
declare function Kbd(props: KbdProps): import("react/jsx-runtime").JSX.Element;
|
|
32
|
+
export default Kbd;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import './Kbd.css';
|
|
3
|
+
function Kbd(props) {
|
|
4
|
+
function isSingle() {
|
|
5
|
+
return !(props.keys && props.keys.length > 0);
|
|
6
|
+
}
|
|
7
|
+
function keyList() {
|
|
8
|
+
return props.keys || [];
|
|
9
|
+
}
|
|
10
|
+
function classes() {
|
|
11
|
+
const combinacao = !!props.keys && props.keys.length > 0;
|
|
12
|
+
return [
|
|
13
|
+
combinacao ? "umds-kbd-combo" : "umds-kbd",
|
|
14
|
+
`umds-kbd--${props.size || "md"}`,
|
|
15
|
+
props.className,
|
|
16
|
+
]
|
|
17
|
+
.filter(Boolean)
|
|
18
|
+
.join(" ");
|
|
19
|
+
}
|
|
20
|
+
function separatorText() {
|
|
21
|
+
return props.separator || "+";
|
|
22
|
+
}
|
|
23
|
+
function isLast(index) {
|
|
24
|
+
return index === keyList().length - 1;
|
|
25
|
+
}
|
|
26
|
+
function htmlAttrs() {
|
|
27
|
+
const out = {};
|
|
28
|
+
for (const chave in props) {
|
|
29
|
+
if (chave.indexOf("data-") === 0 ||
|
|
30
|
+
chave.indexOf("aria-") === 0 ||
|
|
31
|
+
chave === "style" ||
|
|
32
|
+
chave === "title") {
|
|
33
|
+
out[chave] = props[chave];
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
return out;
|
|
37
|
+
}
|
|
38
|
+
return (_jsxs("kbd", { id: props.id, ...htmlAttrs(), className: classes(), children: [isSingle() ? _jsx(_Fragment, { children: props.children }) : null, keyList()?.map((tecla, posicao) => (_jsxs("span", { className: "umds-kbd-combo__item", children: [_jsx("kbd", { className: "umds-kbd umds-kbd--inner", children: tecla }), !isLast(posicao) ? (_jsx("span", { className: "umds-kbd-combo__separator", children: separatorText() })) : null] }, posicao)))] }));
|
|
39
|
+
}
|
|
40
|
+
export default Kbd;
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
/* ─────────────────────────────────────────────
|
|
2
|
+
LIST / LIST ITEM
|
|
3
|
+
Lista semântica (ul/ol > li) de linhas clicáveis com conteúdo livre.
|
|
4
|
+
Só tokens do DS. Sem equivalente (mantido como literal):
|
|
5
|
+
padding vertical de 10px do CrisDoc → usa spacing-nano (8px).
|
|
6
|
+
───────────────────────────────────────────── */
|
|
7
|
+
|
|
8
|
+
/* ── List ── */
|
|
9
|
+
.umds-list {
|
|
10
|
+
display: flex;
|
|
11
|
+
flex-direction: column;
|
|
12
|
+
min-width: 0;
|
|
13
|
+
box-sizing: border-box;
|
|
14
|
+
font-family: var(--umds-semantic-font-family-base);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
ul.umds-list,
|
|
18
|
+
ol.umds-list {
|
|
19
|
+
list-style: none;
|
|
20
|
+
margin: 0;
|
|
21
|
+
padding: 0;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
.umds-list--gap-none { gap: 0; }
|
|
25
|
+
.umds-list--gap-micro { gap: var(--umds-primitive-spacing-micro); }
|
|
26
|
+
.umds-list--gap-quarck { gap: var(--umds-primitive-spacing-quarck); }
|
|
27
|
+
.umds-list--gap-nano { gap: var(--umds-primitive-spacing-nano); }
|
|
28
|
+
.umds-list--gap-mini { gap: var(--umds-primitive-spacing-mini); }
|
|
29
|
+
.umds-list--gap-xxxs { gap: var(--umds-primitive-spacing-xxxs); }
|
|
30
|
+
|
|
31
|
+
/* Estado vazio: o miolo da lista troca de conteúdo; quem rodeia não muda. */
|
|
32
|
+
.umds-list--empty {
|
|
33
|
+
align-items: center;
|
|
34
|
+
justify-content: center;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/* ── <li> que envolve a linha ── */
|
|
38
|
+
.umds-list__item {
|
|
39
|
+
display: block;
|
|
40
|
+
list-style: none;
|
|
41
|
+
margin: 0;
|
|
42
|
+
padding: 0;
|
|
43
|
+
min-width: 0;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/* ── Linha ── */
|
|
47
|
+
.umds-list-item {
|
|
48
|
+
display: flex;
|
|
49
|
+
align-items: flex-start;
|
|
50
|
+
gap: var(--umds-primitive-spacing-nano); /* 8px */
|
|
51
|
+
width: 100%;
|
|
52
|
+
box-sizing: border-box;
|
|
53
|
+
min-width: 0;
|
|
54
|
+
margin: 0;
|
|
55
|
+
padding: var(--umds-primitive-spacing-nano) var(--umds-primitive-spacing-mini); /* 8px 12px */
|
|
56
|
+
border: 0;
|
|
57
|
+
border-radius: var(--umds-primitive-border-radius-sm); /* 8px */
|
|
58
|
+
background: transparent;
|
|
59
|
+
color: var(--umds-semantic-color-neutral-dark-pure);
|
|
60
|
+
font: inherit;
|
|
61
|
+
text-align: left;
|
|
62
|
+
text-decoration: none;
|
|
63
|
+
transition: background-color var(--umds-semantic-motion-duration-fast) var(--umds-semantic-motion-easing-standard);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
.umds-list-item--interactive {
|
|
67
|
+
cursor: pointer;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
.umds-list-item--interactive:hover {
|
|
71
|
+
background: var(--umds-semantic-color-background-light);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
.umds-list-item--interactive:focus-visible {
|
|
75
|
+
outline: 2px solid var(--umds-semantic-color-primary-pure);
|
|
76
|
+
outline-offset: -2px; /* dentro da linha: o anel não é cortado por overflow do pai */
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/* ── Selecionado ── */
|
|
80
|
+
.umds-list-item--selected {
|
|
81
|
+
background: var(--umds-semantic-color-primary-light);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
.umds-list-item--selected.umds-list-item--interactive:hover {
|
|
85
|
+
background: color-mix(
|
|
86
|
+
in srgb,
|
|
87
|
+
var(--umds-semantic-color-primary-light) 85%,
|
|
88
|
+
var(--umds-semantic-color-background-white)
|
|
89
|
+
);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/* ── Desabilitado ── */
|
|
93
|
+
.umds-list-item--disabled,
|
|
94
|
+
.umds-list-item--disabled .umds-list-item__subtitle,
|
|
95
|
+
.umds-list-item--disabled .umds-list-item__meta {
|
|
96
|
+
color: var(--umds-semantic-color-neutral-dark-up);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
.umds-list-item--disabled,
|
|
100
|
+
.umds-list-item--disabled.umds-list-item--interactive:hover {
|
|
101
|
+
cursor: not-allowed;
|
|
102
|
+
background: transparent;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/* ── Anatomia ── */
|
|
106
|
+
.umds-list-item__start,
|
|
107
|
+
.umds-list-item__end {
|
|
108
|
+
display: inline-flex;
|
|
109
|
+
flex-shrink: 0;
|
|
110
|
+
align-items: center;
|
|
111
|
+
align-self: center;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
.umds-list-item__end {
|
|
115
|
+
margin-left: auto;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
.umds-list-item__body {
|
|
119
|
+
display: flex;
|
|
120
|
+
flex: 1 1 auto;
|
|
121
|
+
flex-direction: column;
|
|
122
|
+
gap: var(--umds-primitive-spacing-micro); /* 2px */
|
|
123
|
+
min-width: 0;
|
|
124
|
+
overflow-wrap: anywhere;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
.umds-list-item__title {
|
|
128
|
+
display: block;
|
|
129
|
+
color: inherit;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
.umds-list-item__subtitle,
|
|
133
|
+
.umds-list-item__meta {
|
|
134
|
+
display: block;
|
|
135
|
+
color: var(--umds-semantic-color-neutral-dark-down);
|
|
136
|
+
}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import './List.css';
|
|
2
|
+
/** Espaço entre as linhas, na escala oficial do DS. `none` cola as linhas. */
|
|
3
|
+
export type ListGap = "none" | "micro" | "quarck" | "nano" | "mini" | "xxxs";
|
|
4
|
+
/** Elemento da lista: `ul` (padrão) ou `ol` quando a ordem importa. */
|
|
5
|
+
/** Espaço entre as linhas, na escala oficial do DS. `none` cola as linhas. */
|
|
6
|
+
/** Elemento da lista: `ul` (padrão) ou `ol` quando a ordem importa. */
|
|
7
|
+
export type ListTag = "ul" | "ol";
|
|
8
|
+
/**
|
|
9
|
+
* List — agrupa `ListItem` numa lista semântica (`ul`/`ol` com `li`) e traz o
|
|
10
|
+
* estado vazio dentro dela.
|
|
11
|
+
*
|
|
12
|
+
* Quando não há itens, passe `isEmpty`: a lista troca os itens por um
|
|
13
|
+
* `EmptyState` (`emptyTitle`, `emptyDescription`, `emptyIcon`, `emptyActionLabel`
|
|
14
|
+
* com `onEmptyAction`) ou, para um conteúdo próprio, pelo slot `empty`. Só o
|
|
15
|
+
* miolo troca: o título do cartão, a busca, os filtros e a paginação ao redor
|
|
16
|
+
* continuam montados, e o estado vazio é anunciado ao leitor de tela
|
|
17
|
+
* (`role="status"`). `isEmpty` é uma decisão sua, porque a lista não conta
|
|
18
|
+
* filhos: `:is-empty="!itens.length"`.
|
|
19
|
+
*
|
|
20
|
+
* A lista precisa de nome: passe `ariaLabel` (ou `ariaLabelledby`, apontando
|
|
21
|
+
* para o título visível). Sem isso o leitor de tela anuncia "lista, 5 itens"
|
|
22
|
+
* sem dizer de quê.
|
|
23
|
+
*
|
|
24
|
+
* `ul` e `ol` saem sem marcador, margem e recuo, com `role="list"` (o Safari
|
|
25
|
+
* tira a semântica de lista de `list-style: none`).
|
|
26
|
+
* @property {string} as - Elemento: 'ul' (padrão) | 'ol'
|
|
27
|
+
* @property {string} gap - Espaço entre as linhas, na escala do DS ('none' cola)
|
|
28
|
+
* @property {string} ariaLabel - Nome acessível da lista
|
|
29
|
+
* @property {string} ariaLabelledby - Id do título visível que nomeia a lista
|
|
30
|
+
* @property {boolean} isEmpty - Sem itens: mostra o estado vazio no lugar das linhas
|
|
31
|
+
* @property {string} emptyTitle - Título do estado vazio (padrão: "Nenhum item encontrado")
|
|
32
|
+
* @property {string} emptyDescription - Texto de apoio do estado vazio
|
|
33
|
+
* @property {IconProp} emptyIcon - Ícone do estado vazio (objeto do Font Awesome)
|
|
34
|
+
* @property {string} emptySize - Tamanho do estado vazio: 'sm' (padrão, compacto) | 'md' | 'lg'
|
|
35
|
+
* @property {string} emptyActionLabel - Rótulo do botão do estado vazio (junto de onEmptyAction)
|
|
36
|
+
* @property {function} onEmptyAction - Callback do botão do estado vazio
|
|
37
|
+
* @property {any} empty - Slot `empty`: conteúdo próprio no lugar do EmptyState
|
|
38
|
+
* @property {string} className - Classes CSS adicionais
|
|
39
|
+
* @slot empty - Conteúdo do estado vazio (substitui o EmptyState padrão).
|
|
40
|
+
* @quandoUsar Qualquer lista de linhas clicáveis (`ListItem`) ou de itens simples que pode ficar sem resultado: documentos não lidos, notificações, resultados de busca. Resolve a semântica de lista e o "nada por aqui" num lugar só.
|
|
41
|
+
* @quandoNaoUsar Para dados tabulares comparados coluna a coluna, use `DataTable` (que já tem o próprio estado vazio). Para só empilhar blocos com espaçamento, sem semântica de lista, use `Stack`. Para um estado vazio que ocupa a tela inteira (sem lista), use `EmptyState` direto.
|
|
42
|
+
*/
|
|
43
|
+
/** Espaço entre as linhas, na escala oficial do DS. `none` cola as linhas. */
|
|
44
|
+
/** Elemento da lista: `ul` (padrão) ou `ol` quando a ordem importa. */
|
|
45
|
+
export interface ListProps {
|
|
46
|
+
/** Elemento da lista. @default 'ul' */
|
|
47
|
+
as?: ListTag;
|
|
48
|
+
/** Espaço entre as linhas, na escala oficial (`none` cola). @default 'quarck' */
|
|
49
|
+
gap?: ListGap;
|
|
50
|
+
/** Nome acessível da lista. */
|
|
51
|
+
ariaLabel?: string;
|
|
52
|
+
/** Id do título visível que nomeia a lista. */
|
|
53
|
+
ariaLabelledby?: string;
|
|
54
|
+
/** Sem itens: mostra o estado vazio no lugar das linhas. @default false */
|
|
55
|
+
isEmpty?: boolean;
|
|
56
|
+
/** Título do estado vazio. @default 'Nenhum item encontrado' */
|
|
57
|
+
emptyTitle?: string;
|
|
58
|
+
/** Texto de apoio do estado vazio. */
|
|
59
|
+
emptyDescription?: string;
|
|
60
|
+
/** Ícone do estado vazio: o objeto importado do Font Awesome. */
|
|
61
|
+
emptyIcon?: IconProp;
|
|
62
|
+
/** Tamanho do estado vazio. @default 'sm' */
|
|
63
|
+
emptySize?: "sm" | "md" | "lg";
|
|
64
|
+
/** Rótulo do botão do estado vazio (exibido junto de `onEmptyAction`). */
|
|
65
|
+
emptyActionLabel?: string;
|
|
66
|
+
/** Chamado no botão do estado vazio. */
|
|
67
|
+
onEmptyAction?: () => void;
|
|
68
|
+
/** Conteúdo próprio do estado vazio. No Vue, slot `empty`. */
|
|
69
|
+
empty?: any;
|
|
70
|
+
/** Classes CSS adicionais. */
|
|
71
|
+
className?: string;
|
|
72
|
+
/** ID HTML do elemento raiz. */
|
|
73
|
+
id?: string;
|
|
74
|
+
/** Atributos HTML repassados ao elemento raiz (style, data-*…). */
|
|
75
|
+
style?: any;
|
|
76
|
+
[key: string]: any;
|
|
77
|
+
/** As linhas: `ListItem` (ou `li`). */
|
|
78
|
+
children?: any;
|
|
79
|
+
}
|
|
80
|
+
import type { IconProp } from "../Icon/Icon";
|
|
81
|
+
declare function List(props: ListProps): import("react/jsx-runtime").JSX.Element;
|
|
82
|
+
export default List;
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import './List.css';
|
|
3
|
+
import EmptyState from "../EmptyState/EmptyState";
|
|
4
|
+
function List(props) {
|
|
5
|
+
function elementTag() {
|
|
6
|
+
return props.as || "ul";
|
|
7
|
+
}
|
|
8
|
+
function showEmpty() {
|
|
9
|
+
return !!props.isEmpty;
|
|
10
|
+
}
|
|
11
|
+
function showItems() {
|
|
12
|
+
return !props.isEmpty;
|
|
13
|
+
}
|
|
14
|
+
function classes() {
|
|
15
|
+
return [
|
|
16
|
+
"umds-list",
|
|
17
|
+
`umds-list--gap-${props.gap || "quarck"}`,
|
|
18
|
+
props.className,
|
|
19
|
+
]
|
|
20
|
+
.filter(Boolean)
|
|
21
|
+
.join(" ");
|
|
22
|
+
}
|
|
23
|
+
function emptyClasses() {
|
|
24
|
+
return ["umds-list umds-list--empty", props.className]
|
|
25
|
+
.filter(Boolean)
|
|
26
|
+
.join(" ");
|
|
27
|
+
}
|
|
28
|
+
function emptyTitleText() {
|
|
29
|
+
return props.emptyTitle || "Nenhum item encontrado";
|
|
30
|
+
}
|
|
31
|
+
function emptyActionProps() {
|
|
32
|
+
if (!props.onEmptyAction)
|
|
33
|
+
return {};
|
|
34
|
+
return {
|
|
35
|
+
actionLabel: props.emptyActionLabel,
|
|
36
|
+
onAction: props.onEmptyAction,
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
function emptySizeValue() {
|
|
40
|
+
return props.emptySize || "sm";
|
|
41
|
+
}
|
|
42
|
+
function htmlAttrs() {
|
|
43
|
+
const out = {};
|
|
44
|
+
for (const chave in props) {
|
|
45
|
+
if (chave.indexOf("data-") === 0 || chave === "style") {
|
|
46
|
+
out[chave] = props[chave];
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
return out;
|
|
50
|
+
}
|
|
51
|
+
return (_jsxs(_Fragment, { children: [showEmpty() ? (_jsx("div", { role: "status", id: props.id, ...htmlAttrs(), className: emptyClasses(), children: _jsx(_Fragment, { children: props.empty || (_jsx(EmptyState, { icon: props.emptyIcon, title: emptyTitleText(), description: props.emptyDescription, size: emptySizeValue(), ...emptyActionProps() })) }) })) : null, showItems() && elementTag() === "ul" ? (_jsx("ul", { role: "list", id: props.id, "aria-label": props.ariaLabel, "aria-labelledby": props.ariaLabelledby, ...htmlAttrs(), className: classes(), children: _jsx(_Fragment, { children: props.children }) })) : null, showItems() && elementTag() === "ol" ? (_jsx("ol", { role: "list", id: props.id, "aria-label": props.ariaLabel, "aria-labelledby": props.ariaLabelledby, ...htmlAttrs(), className: classes(), children: _jsx(_Fragment, { children: props.children }) })) : null] }));
|
|
52
|
+
}
|
|
53
|
+
export default List;
|