@1doc/1ds-react 2.10.0 → 2.11.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 +219 -0
- package/dist/components/Accordion/Accordion.d.ts +6 -0
- package/dist/components/Accordion/Accordion.js +17 -5
- package/dist/components/Badge/Badge.css +13 -4
- package/dist/components/Badge/Badge.d.ts +9 -2
- package/dist/components/Badge/Badge.js +3 -0
- package/dist/components/Button/Button.css +5 -0
- package/dist/components/Button/Button.d.ts +3 -0
- package/dist/components/Button/Button.js +1 -0
- package/dist/components/Calendar/Calendar.css +10 -0
- package/dist/components/Calendar/Calendar.d.ts +3 -0
- package/dist/components/Calendar/Calendar.js +6 -1
- package/dist/components/Coachmark/Coachmark.d.ts +2 -1
- package/dist/components/Coachmark/Coachmark.js +6 -1
- package/dist/components/DataTable/DataTable.css +42 -0
- package/dist/components/DataTable/DataTable.d.ts +9 -2
- package/dist/components/DataTable/DataTable.js +15 -0
- package/dist/components/Input/Input.css +9 -0
- package/dist/components/Input/Input.d.ts +3 -0
- package/dist/components/Input/Input.js +1 -0
- package/dist/components/Modal/Modal.css +19 -0
- package/dist/components/Modal/Modal.d.ts +7 -0
- package/dist/components/Modal/Modal.js +1 -0
- package/dist/components/SegmentedControl/SegmentedControl.css +46 -0
- package/dist/components/SegmentedControl/SegmentedControl.d.ts +3 -0
- package/dist/components/SegmentedControl/SegmentedControl.js +1 -0
- package/dist/components/Select/Select.css +28 -2
- package/dist/components/Select/Select.d.ts +7 -0
- package/dist/components/Select/Select.js +55 -9
- package/dist/components/StatCard/StatCard.css +8 -0
- package/dist/components/StatCard/StatCard.d.ts +3 -0
- package/dist/components/StatCard/StatCard.js +1 -0
- package/dist/components/Tabs/Tabs.css +11 -0
- package/dist/components/Tabs/Tabs.d.ts +7 -0
- package/dist/components/Tabs/Tabs.js +7 -1
- package/dist/components/Tag/Tag.css +3 -1
- package/dist/teste/AccordionControlado.test.d.ts +1 -0
- package/dist/teste/AccordionControlado.test.js +73 -0
- package/dist/teste/BadgeAttachedTomEPadding.test.d.ts +1 -0
- package/dist/teste/BadgeAttachedTomEPadding.test.js +43 -0
- package/dist/teste/ButtonDensidade.test.d.ts +1 -0
- package/dist/teste/ButtonDensidade.test.js +28 -0
- package/dist/teste/CalendarCompacto.test.d.ts +1 -0
- package/dist/teste/CalendarCompacto.test.js +29 -0
- package/dist/teste/CoachmarkUmPasso.test.d.ts +1 -0
- package/dist/teste/CoachmarkUmPasso.test.js +34 -0
- package/dist/teste/DataTableCompactaETom.test.d.ts +1 -0
- package/dist/teste/DataTableCompactaETom.test.js +69 -0
- package/dist/teste/InputGhost.test.d.ts +1 -0
- package/dist/teste/InputGhost.test.js +32 -0
- package/dist/teste/ModalProporcoes1Doc.test.d.ts +1 -0
- package/dist/teste/ModalProporcoes1Doc.test.js +32 -0
- package/dist/teste/SegmentedControlSuperficie.test.d.ts +1 -0
- package/dist/teste/SegmentedControlSuperficie.test.js +39 -0
- package/dist/teste/SelectItemComEscopo.test.d.ts +1 -0
- package/dist/teste/SelectItemComEscopo.test.js +54 -0
- package/dist/teste/SelectListaFiltro.test.d.ts +1 -0
- package/dist/teste/SelectListaFiltro.test.js +102 -0
- package/dist/teste/StatCardTamanhoSm.test.d.ts +1 -0
- package/dist/teste/StatCardTamanhoSm.test.js +32 -0
- package/dist/teste/TabsCompacta.test.d.ts +1 -0
- package/dist/teste/TabsCompacta.test.js +35 -0
- package/dist/teste/TagPositivoTingido.test.d.ts +1 -0
- package/dist/teste/TagPositivoTingido.test.js +54 -0
- package/dist/teste/lerArquivo.d.ts +1 -0
- package/dist/teste/lerArquivo.js +12 -0
- package/package.json +3 -3
- package/src/teste/AccordionControlado.test.tsx +87 -0
- package/src/teste/BadgeAttachedTomEPadding.test.tsx +60 -0
- package/src/teste/ButtonDensidade.test.tsx +40 -0
- package/src/teste/CalendarCompacto.test.tsx +37 -0
- package/src/teste/CoachmarkUmPasso.test.tsx +45 -0
- package/src/teste/DataTableCompactaETom.test.tsx +85 -0
- package/src/teste/InputGhost.test.tsx +42 -0
- package/src/teste/ModalProporcoes1Doc.test.tsx +36 -0
- package/src/teste/SegmentedControlSuperficie.test.tsx +52 -0
- package/src/teste/SelectItemComEscopo.test.tsx +69 -0
- package/src/teste/SelectListaFiltro.test.tsx +120 -0
- package/src/teste/StatCardTamanhoSm.test.tsx +42 -0
- package/src/teste/TabsCompacta.test.tsx +45 -0
- package/src/teste/TagPositivoTingido.test.tsx +60 -0
- package/src/teste/lerArquivo.ts +13 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,224 @@
|
|
|
1
1
|
# @1doc/1ds-react
|
|
2
2
|
|
|
3
|
+
## 2.11.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- bf2cfdc: feat(accordion): `open` e `onOpenChange`, abertura controlada
|
|
8
|
+
|
|
9
|
+
`open` (lista de ids dos itens abertos) e `onOpenChange` (recebe a nova lista a cada abrir ou fechar). Com `open`, quem manda é o
|
|
10
|
+
app: o clique só pede e o painel muda quando `open` muda, para lembrar a escolha entre visitas (as seções do CrisDoc). Sem `open`, o
|
|
11
|
+
Accordion guarda o próprio estado, como antes (começando pelos `defaultOpen`), e `onOpenChange` também avisa. `open=[]` é controlado
|
|
12
|
+
(tudo fechado), não ausência. Item desabilitado não pede nada.
|
|
13
|
+
|
|
14
|
+
```vue
|
|
15
|
+
<Accordion
|
|
16
|
+
:items="secoes"
|
|
17
|
+
multiple
|
|
18
|
+
:open="abertos"
|
|
19
|
+
:onOpenChange="(ids) => (abertos = ids)"
|
|
20
|
+
/>
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
- 9c8baa3: feat(badge): `2xs` com 8px de padding lateral; `attached` com 22px e o tom escuro como opção (`attachedTone`)
|
|
24
|
+
|
|
25
|
+
- `size="2xs"`: o padding lateral passa de 4px a 8px, como o selo do CrisDoc. A altura segue em 16px e a fonte em 10px.
|
|
26
|
+
- `attached`: o rótulo colado tem altura mínima de 22px (24 - 2) de qualquer tamanho; o `md` (padrão) já media 22 e
|
|
27
|
+
o `xs` e o `2xs` colados sobem a ele.
|
|
28
|
+
- `attachedTone="dark"` (novo; padrão `light`): o neutro sólido colado em cinza escuro (`neutral-dark-down`) com texto
|
|
29
|
+
branco, o rótulo escuro do CrisDoc. O ardósia do CrisDoc dá 2,9:1 com texto branco, então o DS usa o token que passa
|
|
30
|
+
(7,3:1 e inverte sozinho nos temas escuros). Só vale com `attached`, `variant="neutral"` e `appearance="solid"`.
|
|
31
|
+
|
|
32
|
+
```vue
|
|
33
|
+
<Badge
|
|
34
|
+
attached
|
|
35
|
+
size="xs"
|
|
36
|
+
variant="neutral"
|
|
37
|
+
appearance="solid"
|
|
38
|
+
attachedTone="dark"
|
|
39
|
+
>Tarefa manual</Badge>
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
- 7883c6b: feat(button): `density="comfortable"`, o `sm` com 12px de padding lateral
|
|
43
|
+
|
|
44
|
+
O botão pequeno do CrisDoc tem 12px de padding lateral e o `sm` do DS tem 8px. Mudar o `sm` alargaria todo botão que já o
|
|
45
|
+
usa, então a diferença virou uma densidade: `density="comfortable"` leva o `sm` a 12px (a altura de 32px, a fonte e o raio
|
|
46
|
+
não mudam). Sem a prop, nenhum botão muda. Nos outros tamanhos a prop não faz diferença (`xs` já usa 12px, `md` 16px e
|
|
47
|
+
`lg` 24px), e o botão só de ícone, de largura fixa, fica de fora.
|
|
48
|
+
|
|
49
|
+
```vue
|
|
50
|
+
<Button
|
|
51
|
+
variant="secondary"
|
|
52
|
+
size="sm"
|
|
53
|
+
density="comfortable"
|
|
54
|
+
>Personalizar</Button>
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
- c101901: feat(calendar): `density="compact"`, evento de 20px
|
|
58
|
+
|
|
59
|
+
`density` (`default` | `compact`). O `compact` leva o evento a 20px de altura (16 + 4, o degrau do DS mais perto dos 20,5 do CrisDoc;
|
|
60
|
+
o padrão dá 25) com 4px de padding lateral (o padrão tem 8) e linha de 16px. Com menos padding o título cabe inteiro onde antes
|
|
61
|
+
cortava; ele só é cortado, com reticências, quando passa da largura da célula. O padrão não muda.
|
|
62
|
+
|
|
63
|
+
```vue
|
|
64
|
+
<Calendar :events="eventos" density="compact" />
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
- c9c05cc: feat(coachmark): com um passo só, sem o contador "1 de 1"
|
|
68
|
+
|
|
69
|
+
O contador ("2 de 8") só aparece com mais de um passo, no cartão e na região `aria-live`: com um passo o leitor de
|
|
70
|
+
tela ouve só o título. É o caso da dica pontual (`modal={false}`) e de qualquer tour de um passo. `counterLabel`
|
|
71
|
+
continua valendo para os tours com mais passos. O botão do último passo segue sendo "Concluir" (`finishLabel`).
|
|
72
|
+
|
|
73
|
+
- ad47648: feat(datatable): `density="compact"` com cabeçalho e linha de 44px, e tom por linha (`rowTone`)
|
|
74
|
+
|
|
75
|
+
- `density="compact"`: `th` e `td` ganham `height` igual à altura de campo do DS (44px), no lugar dos 38 e 49 de
|
|
76
|
+
antes. É mínimo: conteúdo mais alto (avatar, botão) estica a linha. A tabela de documento (`variant="document"`)
|
|
77
|
+
continua justa.
|
|
78
|
+
- `rowTone`: o nome do campo da linha com o tom, ou uma função `(row, rowIndex) => tom`. Tons: `negative`,
|
|
79
|
+
`positive`, `info` (fundo claro da cor semântica) e `muted` (texto esmaecido). A linha selecionada ou destacada
|
|
80
|
+
vence o tom e o tom vence a zebra. Tom desconhecido é ignorado. O tom é decoração: o estado também vai em texto.
|
|
81
|
+
|
|
82
|
+
```vue
|
|
83
|
+
<DataTable
|
|
84
|
+
density="compact"
|
|
85
|
+
:columns="colunas"
|
|
86
|
+
:data="usuarios"
|
|
87
|
+
:rowTone="
|
|
88
|
+
(u) => (u.bloqueado ? 'negative' : u.desligado ? 'muted' : undefined)
|
|
89
|
+
"
|
|
90
|
+
/>
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
- a1de816: feat(input): `variant="ghost"`, a busca dentro de um painel
|
|
94
|
+
|
|
95
|
+
`variant` (`default` | `ghost`). O `ghost` tira a borda escura do repouso: fundo cinza claro (`background-light`) e borda clara
|
|
96
|
+
(`neutral-light-medium`). Só o repouso muda: hover (borda mais escura), foco (borda azul e anel), erro, desabilitado e somente leitura
|
|
97
|
+
são os do campo padrão, e o ícone, o placeholder e o cursor seguem dizendo que é um campo. Sem a prop, nada muda.
|
|
98
|
+
|
|
99
|
+
```vue
|
|
100
|
+
<Input
|
|
101
|
+
variant="ghost"
|
|
102
|
+
size="sm"
|
|
103
|
+
fullWidth
|
|
104
|
+
ariaLabel="Buscar filtros"
|
|
105
|
+
placeholder="Buscar filtros"
|
|
106
|
+
/>
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
- 9e41dc1: feat(modal): `density="1doc"`, as proporções do modal do CrisDoc
|
|
110
|
+
|
|
111
|
+
`density` (`default` | `1doc`) leva o cabeçalho a 67px (o padrão dá 61), o rodapé a 65px (o padrão dá 73, com o padding de 12px 24px)
|
|
112
|
+
e o raio a 12px (o padrão é 8px). As alturas são mínimas: título com subtítulo ou botão mais alto continua crescendo. Combina com
|
|
113
|
+
`variant="primary"`. A tela cheia e o painel (`responsive`) mantêm os cantos deles. Sem a prop, o modal não muda. Sem token para
|
|
114
|
+
essas medidas: literais comentados no CSS.
|
|
115
|
+
|
|
116
|
+
```vue
|
|
117
|
+
<Modal
|
|
118
|
+
:open="aberto"
|
|
119
|
+
density="1doc"
|
|
120
|
+
variant="primary"
|
|
121
|
+
title="Resolver tarefa"
|
|
122
|
+
width="600px"
|
|
123
|
+
/>
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
- 7d9e687: feat(segmentedcontrol): `variant="surface"`, o escolhido em superfície branca
|
|
127
|
+
|
|
128
|
+
`variant` (`default` | `surface`). No `surface` o trilho é cinza claro, sem divisores, e o segmento escolhido é uma peça branca com
|
|
129
|
+
sombra, texto escuro e negrito (o seletor do CrisDoc). A seleção não depende só do tom: o peso e a sombra a dizem. O contador do
|
|
130
|
+
escolhido fica cinza sobre o branco e o dos outros, branco sobre o trilho. O padrão (azul cheio) não muda.
|
|
131
|
+
|
|
132
|
+
```vue
|
|
133
|
+
<SegmentedControl
|
|
134
|
+
label="Modo"
|
|
135
|
+
variant="surface"
|
|
136
|
+
:options="opcoes"
|
|
137
|
+
:value="modo"
|
|
138
|
+
:onChange="trocar"
|
|
139
|
+
/>
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
- bf81dfa: feat(select): a lista do filtro tem a largura do gatilho, com `listMinWidth` e sem passar da janela
|
|
143
|
+
|
|
144
|
+
Regressão do 2.10 no `Select variant="filter"` (a lista do Marcadores da inbox media 556px e passava 17px da borda):
|
|
145
|
+
|
|
146
|
+
- Causa: o wrapper do filtro tinha `width: auto` e é `display: flex` (bloco), então se esticava até a largura do pai;
|
|
147
|
+
o `100%` da lista passava a ser a do pai e não a do gatilho. Agora é `fit-content`.
|
|
148
|
+
- A lista tem a largura do gatilho (nunca menor), cresce até o conteúdo e fica dentro da janela: o campo de busca
|
|
149
|
+
não entra mais na conta da largura (`contain: inline-size`) e acompanha a lista.
|
|
150
|
+
- Perto da borda direita a lista se alinha ao fim do gatilho (medido ao abrir). Na lista flutuante dentro de
|
|
151
|
+
diálogo, o floating-ui ganhou `shift` com 8px de respiro.
|
|
152
|
+
- `listMinWidth` (número em px ou medida CSS) troca o mínimo de 240px: o CrisDoc usa 220.
|
|
153
|
+
|
|
154
|
+
```vue
|
|
155
|
+
<Select
|
|
156
|
+
variant="filter"
|
|
157
|
+
ariaLabel="Marcadores"
|
|
158
|
+
placeholder="Marcadores"
|
|
159
|
+
searchable
|
|
160
|
+
:listMinWidth="220"
|
|
161
|
+
:options="marcadores"
|
|
162
|
+
/>
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
- cfe3687: feat(select): `item` com o escopo da opção, na lista e no gatilho
|
|
166
|
+
|
|
167
|
+
O conteúdo de cada opção agora recebe a opção nos dois frameworks:
|
|
168
|
+
|
|
169
|
+
- Vue: o slot `#item="{ optionData }"` (o Mitosis gerava `<slot name="item">` sem escopo e o `optionData` chegava `undefined`; o
|
|
170
|
+
`postbuild.js` passa `optionData` e o apelido `option`).
|
|
171
|
+
- React: `item` pode ser uma função `({ optionData }) => nó` (antes, a função virava filho inválido). O nó solto, sem escopo,
|
|
172
|
+
continua valendo na lista.
|
|
173
|
+
- Com a opção escolhida (seleção única), o gatilho mostra o conteúdo do `item` no lugar do texto: o "SeletorComEtiqueta" do
|
|
174
|
+
CrisDoc, com nome e etiqueta, aparece igual na lista e no campo. Sem valor (placeholder), na seleção múltipla e com o nó solto do
|
|
175
|
+
React, o gatilho segue com o texto.
|
|
176
|
+
|
|
177
|
+
```vue
|
|
178
|
+
<Select label="Prioridade" :options="opcoes" :value="valor" :onChange="mudar">
|
|
179
|
+
<template #item="{ optionData }"><strong>{{ optionData.label }}</strong> {{ optionData.etiqueta }}</template>
|
|
180
|
+
</Select>
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
- 53dfebe: feat(statcard): `size="sm"`, o KPI com o número a 18px/800
|
|
184
|
+
|
|
185
|
+
Os KPIs da home do CrisDoc têm o número a 18px/800. `size="sm"` leva o número a esse tamanho (o `md`, padrão, segue
|
|
186
|
+
em 24/700). Vale também com `labelPosition="top"`, que tem o número em 32/800: o `sm` vence. O 18px não está na escala
|
|
187
|
+
de fonte do DS (que vai de 16 a 20) e fica como literal comentado, como o 10px do `Badge` 2xs. O número continua antes
|
|
188
|
+
do rótulo no HTML.
|
|
189
|
+
|
|
190
|
+
```vue
|
|
191
|
+
<StatCard
|
|
192
|
+
size="sm"
|
|
193
|
+
label="Minhas tarefas"
|
|
194
|
+
:value="12"
|
|
195
|
+
:icon="faClock"
|
|
196
|
+
variant="primary"
|
|
197
|
+
/>
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
- 4471b90: feat(tabs): `density="compact"`, abas de 40px
|
|
201
|
+
|
|
202
|
+
O `Tabs` ganha `density` (`default` | `compact`). O `compact` leva a altura mínima das abas de 48px a 40px (o degrau `sm` do DS) com
|
|
203
|
+
padding vertical de 8px, para barras de abas dentro de uma tela (o CrisDoc usa 40). A pílula do contador (`count`) não muda e já
|
|
204
|
+
era o que o CrisDoc pede: cinza (`neutral-light-medium`) na aba inativa e azul só na ativa, nas duas densidades. Sem a prop, nenhuma
|
|
205
|
+
aba muda.
|
|
206
|
+
|
|
207
|
+
```vue
|
|
208
|
+
<Tabs :value="aba" :onChange="trocar" density="compact" ariaLabel="Processos">
|
|
209
|
+
<Tab label="Fluxos" index="1" :count="56" />
|
|
210
|
+
</Tabs>
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
### Patch Changes
|
|
214
|
+
|
|
215
|
+
- 7ccb05c: fix(tag): `variant="positive"` outlined com o texto em `positive-dark`
|
|
216
|
+
|
|
217
|
+
O contorno da tag outlined é transparente, então o texto cai sobre o fundo de quem está atrás, que muitas vezes é
|
|
218
|
+
tingido (o azul-claro de um card). `positive-pure` sobre `primary-light` dá 3,6:1 e reprova o WCAG 1.4.3;
|
|
219
|
+
`positive-dark` dá 7,9:1 e é o mesmo par de texto da tag `soft`. Nos temas escuro e de alto contraste o `dark` também
|
|
220
|
+
passa de 4,5:1. O contorno continua em `positive-pure`. As outras variantes não mudam.
|
|
221
|
+
|
|
3
222
|
## 2.10.0
|
|
4
223
|
|
|
5
224
|
### Minor Changes
|
|
@@ -14,6 +14,8 @@ export interface AccordionItemData {
|
|
|
14
14
|
/**
|
|
15
15
|
* Accordion component — lista de painéis expansíveis (sanfona).
|
|
16
16
|
* @property {AccordionItemData[]} items - Itens do accordion (id, title, content, disabled?, defaultOpen?). Conteúdo livre por item: no React, `content` aceita nó; no Vue, o slot `#content-<id>` (recebe `{ item }`).
|
|
17
|
+
* @property {string[]} open - Ids dos itens abertos (modo controlado). Sem a prop, o Accordion guarda o próprio estado (começando pelos `defaultOpen`). Com ela, quem manda é o app: abrir ou fechar chama `onOpenChange` e o painel só muda quando `open` muda. Serve para lembrar a escolha entre visitas.
|
|
18
|
+
* @property {function} onOpenChange - Chamado ao abrir ou fechar um item, com a nova lista de ids abertos (`(openIds: string[]) => void`). Funciona também sem `open`.
|
|
17
19
|
* @property {boolean} multiple - Permite manter vários painéis abertos ao mesmo tempo
|
|
18
20
|
* @property {string} variant - Estilo visual: 'default' | 'bordered' | 'separated'
|
|
19
21
|
* @property {string} titleVariant - Título dos itens: 'default' | 'neutral'. O `neutral` é o título de texto, 14px na cor do texto, sem cor de ação (como um `Button text` neutro), para o accordion do CrisDoc.
|
|
@@ -24,6 +26,10 @@ export interface AccordionItemData {
|
|
|
24
26
|
export interface AccordionProps {
|
|
25
27
|
items: AccordionItemData[];
|
|
26
28
|
multiple?: boolean;
|
|
29
|
+
/** Ids dos itens abertos (controlado). Sem a prop, o estado é interno. */
|
|
30
|
+
open?: string[];
|
|
31
|
+
/** Abriu ou fechou um item: recebe a nova lista de ids abertos. */
|
|
32
|
+
onOpenChange?: (openIds: string[]) => void;
|
|
27
33
|
variant?: "default" | "bordered" | "separated";
|
|
28
34
|
/** Título dos itens. `neutral`: 14px na cor do texto, peso médio. @default 'default' */
|
|
29
35
|
titleVariant?: "default" | "neutral";
|
|
@@ -9,8 +9,13 @@ function Accordion(props) {
|
|
|
9
9
|
function itemList() {
|
|
10
10
|
return props.items || [];
|
|
11
11
|
}
|
|
12
|
+
function currentOpen() {
|
|
13
|
+
return props.open !== undefined && props.open !== null
|
|
14
|
+
? props.open
|
|
15
|
+
: openIds;
|
|
16
|
+
}
|
|
12
17
|
function isOpen(id) {
|
|
13
|
-
return
|
|
18
|
+
return currentOpen().includes(id);
|
|
14
19
|
}
|
|
15
20
|
function triggerId(id) {
|
|
16
21
|
return `umds-accordion-trigger-${id}`;
|
|
@@ -21,15 +26,22 @@ function Accordion(props) {
|
|
|
21
26
|
function toggle(id, disabled) {
|
|
22
27
|
if (disabled)
|
|
23
28
|
return;
|
|
24
|
-
|
|
25
|
-
|
|
29
|
+
const atuais = currentOpen();
|
|
30
|
+
let proximos;
|
|
31
|
+
if (atuais.includes(id)) {
|
|
32
|
+
proximos = atuais.filter((x) => x !== id);
|
|
26
33
|
}
|
|
27
34
|
else if (props.multiple) {
|
|
28
|
-
|
|
35
|
+
proximos = [...atuais, id];
|
|
29
36
|
}
|
|
30
37
|
else {
|
|
31
|
-
|
|
38
|
+
proximos = [id];
|
|
32
39
|
}
|
|
40
|
+
// Controlado: quem muda é o app (o `open` novo). Sem `open`, o estado interno.
|
|
41
|
+
if (props.open === undefined || props.open === null)
|
|
42
|
+
setOpenIds(proximos);
|
|
43
|
+
if (props.onOpenChange)
|
|
44
|
+
props.onOpenChange(proximos);
|
|
33
45
|
}
|
|
34
46
|
function wrapperClasses() {
|
|
35
47
|
return [
|
|
@@ -60,12 +60,12 @@
|
|
|
60
60
|
|
|
61
61
|
/* ── Tamanhos — padding + gap por tamanho (sem height fixa) ── */
|
|
62
62
|
|
|
63
|
-
/* 2xs: 16px de altura (10 de fonte + 2 + 2 de padding + 2 de borda)
|
|
64
|
-
10px não está na escala do DS (menor
|
|
65
|
-
|
|
63
|
+
/* 2xs: 16px de altura (10 de fonte + 2 + 2 de padding + 2 de borda) e 8px de padding
|
|
64
|
+
lateral, como o selo do CrisDoc. A fonte de 10px não está na escala do DS (menor
|
|
65
|
+
degrau: 12px), sem token equivalente. */
|
|
66
66
|
.umds-badge--2xs {
|
|
67
67
|
font-size: 0.625rem; /* 10px: fora da escala, selo compacto */
|
|
68
|
-
padding: var(--umds-primitive-spacing-micro) var(--umds-primitive-spacing-
|
|
68
|
+
padding: var(--umds-primitive-spacing-micro) var(--umds-primitive-spacing-nano);
|
|
69
69
|
gap: var(--umds-primitive-spacing-micro);
|
|
70
70
|
border-radius: var(--umds-primitive-border-radius-xs); /* 4px */
|
|
71
71
|
}
|
|
@@ -252,6 +252,8 @@
|
|
|
252
252
|
position: absolute;
|
|
253
253
|
top: 0;
|
|
254
254
|
left: 0;
|
|
255
|
+
/* 22px: o rótulo do CrisDoc (24 - 2). Os tamanhos menores (xs, 2xs) sobem a ele; o md já mede 22. */
|
|
256
|
+
min-height: calc(var(--umds-primitive-spacing-xxs) - var(--umds-primitive-spacing-micro));
|
|
255
257
|
border-radius: 0 0 var(--umds-primitive-border-radius-sm) var(--umds-primitive-border-radius-sm);
|
|
256
258
|
}
|
|
257
259
|
|
|
@@ -267,3 +269,10 @@
|
|
|
267
269
|
background-color: var(--umds-semantic-color-neutral-light-medium);
|
|
268
270
|
color: var(--umds-semantic-color-neutral-dark-pure);
|
|
269
271
|
}
|
|
272
|
+
|
|
273
|
+
/* attachedTone="dark": o neutro escuro do CrisDoc. O ardósia do CrisDoc dá 2,9:1 com texto branco; o par
|
|
274
|
+
neutral-dark-down + branco dá 7,3:1 e inverte sozinho nos temas escuros. */
|
|
275
|
+
.umds-badge--attached.umds-badge--neutral.umds-badge--solid.umds-badge--attached-dark {
|
|
276
|
+
background-color: var(--umds-semantic-color-neutral-dark-down);
|
|
277
|
+
color: var(--umds-semantic-color-neutral-light-pure);
|
|
278
|
+
}
|
|
@@ -13,8 +13,8 @@ export interface BadgeProps {
|
|
|
13
13
|
*/
|
|
14
14
|
variant?: "neutral" | "positive" | "negative" | "info" | "primary" | "new";
|
|
15
15
|
/**
|
|
16
|
-
* Tamanho do badge. `2xs` é o compacto (16px, fonte de 10px
|
|
17
|
-
* setor e de contagem dentro de linha de lista e card.
|
|
16
|
+
* Tamanho do badge. `2xs` é o compacto (16px, fonte de 10px, 8px de padding
|
|
17
|
+
* lateral) para selo de setor e de contagem dentro de linha de lista e card.
|
|
18
18
|
* @default 'md'
|
|
19
19
|
*/
|
|
20
20
|
size?: "2xs" | "xs" | "sm" | "md" | "lg" | "pill";
|
|
@@ -35,6 +35,13 @@ export interface BadgeProps {
|
|
|
35
35
|
* @default 'left'
|
|
36
36
|
*/
|
|
37
37
|
attachedSide?: "left" | "right";
|
|
38
|
+
/**
|
|
39
|
+
* Tom do rótulo colado neutro e sólido: `light` (padrão, cinza claro com texto escuro) ou `dark` (cinza
|
|
40
|
+
* escuro com texto branco, o rótulo escuro do CrisDoc). Só vale com `attached`, `variant="neutral"` e
|
|
41
|
+
* `appearance="solid"`; as outras variantes ignoram. O rótulo colado mede 22px de altura.
|
|
42
|
+
* @default 'light'
|
|
43
|
+
*/
|
|
44
|
+
attachedTone?: "light" | "dark";
|
|
38
45
|
/**
|
|
39
46
|
* Estilo visual do badge.
|
|
40
47
|
* @default 'soft'
|
|
@@ -56,6 +56,11 @@
|
|
|
56
56
|
font-size: var(--umds-primitive-font-size-xxxs); /* 12px */
|
|
57
57
|
}
|
|
58
58
|
|
|
59
|
+
/* density="comfortable": o sm com o padding de 12px do CrisDoc. O botão só de ícone tem largura fixa e fica de fora. */
|
|
60
|
+
.umds-button--sm.umds-button--comfortable:not(.umds-button--icon) {
|
|
61
|
+
padding: 0 var(--umds-primitive-spacing-mini); /* 12px */
|
|
62
|
+
}
|
|
63
|
+
|
|
59
64
|
.umds-button--md {
|
|
60
65
|
height: var(--umds-primitive-spacing-sm); /* 40px */
|
|
61
66
|
padding: 0 var(--umds-primitive-spacing-xxxs); /* 16px */
|
|
@@ -3,6 +3,7 @@ import './Button.css';
|
|
|
3
3
|
* Button — botão de ação com variantes, tamanhos, ícones e estado de carregamento.
|
|
4
4
|
* @property {string} variant - Variante visual: 'primary' | 'secondary' | 'neutral' | 'neutral-text' | 'text' | 'negative' | 'negative-outlined' | 'icon'. `neutral` é o contornado cinza; `neutral-text` é o texto sem borda e sem azul, para barras de ações onde nenhum botão é a ação principal.
|
|
5
5
|
* @property {string} size - Tamanho do botão: 'xs' (26px, para dentro de card e linha de lista) | 'sm' (32px) | 'md' (40px) | 'lg' (48px)
|
|
6
|
+
* @property {string} density - 'default' (padrão) | 'comfortable'. O `comfortable` leva o padding lateral do `sm` de 8px a 12px (o botão pequeno do CrisDoc); a altura (32px) não muda. Nos outros tamanhos não faz diferença: `xs` já usa 12px, `md` 16px e `lg` 24px. Sem a prop, nenhum botão existente muda.
|
|
6
7
|
* @property {boolean} disabled - Desabilita o botão
|
|
7
8
|
* @property {string} type - Tipo nativo do botão: 'button' | 'submit' | 'reset'
|
|
8
9
|
* @property {Function} onClick - Callback disparado no clique
|
|
@@ -27,6 +28,8 @@ import './Button.css';
|
|
|
27
28
|
export interface ButtonProps {
|
|
28
29
|
variant?: "primary" | "secondary" | "neutral" | "neutral-text" | "text" | "negative" | "negative-outlined" | "icon";
|
|
29
30
|
size?: "xs" | "sm" | "md" | "lg";
|
|
31
|
+
/** `comfortable`: o `sm` com 12px de padding lateral (o padrão é 8px). @default 'default' */
|
|
32
|
+
density?: "default" | "comfortable";
|
|
30
33
|
disabled?: boolean;
|
|
31
34
|
type?: "button" | "submit" | "reset";
|
|
32
35
|
children?: any;
|
|
@@ -9,6 +9,7 @@ function Button(props) {
|
|
|
9
9
|
"umds-button",
|
|
10
10
|
`umds-button--${props.variant || "primary"}`,
|
|
11
11
|
`umds-button--${props.size || "md"}`,
|
|
12
|
+
props.density === "comfortable" ? "umds-button--comfortable" : "",
|
|
12
13
|
props.fullWidth ? "umds-button--full-width" : "",
|
|
13
14
|
props.className,
|
|
14
15
|
]
|
|
@@ -171,6 +171,16 @@
|
|
|
171
171
|
cursor: pointer;
|
|
172
172
|
}
|
|
173
173
|
|
|
174
|
+
/* density="compact": evento de 20px (16 + 4: o degrau do DS mais perto dos 20,5 do CrisDoc) e 4px de padding
|
|
175
|
+
lateral. A linha tem 16px de altura e 2px de padding em cima e embaixo. O título continua cortado com
|
|
176
|
+
reticências só quando passa da largura (a regra do título, abaixo). */
|
|
177
|
+
.umds-calendar--compact .umds-calendar__event {
|
|
178
|
+
min-height: calc(var(--umds-primitive-spacing-xxxs) + var(--umds-primitive-spacing-quarck)); /* 20px */
|
|
179
|
+
padding: var(--umds-primitive-spacing-micro) var(--umds-primitive-spacing-quarck); /* 2px 4px */
|
|
180
|
+
line-height: var(--umds-primitive-spacing-xxxs); /* 16px */
|
|
181
|
+
align-items: center;
|
|
182
|
+
}
|
|
183
|
+
|
|
174
184
|
.umds-calendar__event:hover {
|
|
175
185
|
filter: brightness(0.96);
|
|
176
186
|
}
|
|
@@ -65,6 +65,7 @@ export interface CalendarDayCell {
|
|
|
65
65
|
* @property {string} today - O "hoje" do calendário (`YYYY-MM-DD`; padrão a data do sistema). Útil em testes e em demonstração.
|
|
66
66
|
* @property {number} weekStartsOn - Primeiro dia da semana: 0 domingo (padrão) | 1 segunda
|
|
67
67
|
* @property {number} maxVisible - Eventos por dia na visão de mês antes do "+N" (padrão 3)
|
|
68
|
+
* @property {string} density - 'default' | 'compact'. O `compact` aperta o evento: altura de 20px (o degrau do DS mais perto dos 20,5 do CrisDoc; o padrão dá 25) e 4px de padding lateral (o padrão tem 8), para o título caber inteiro onde antes cortava com reticências. O título só é cortado (com reticências) quando de fato passa da largura da célula.
|
|
68
69
|
* @property {string} locale - Idioma dos nomes de mês e de dia (padrão 'pt-BR')
|
|
69
70
|
* @property {string} ariaLabel - Nome acessível da grade (padrão: o título, ex.: "Maio 2026")
|
|
70
71
|
* @property {string} previousLabel - Nome do botão de voltar (padrão "Anterior")
|
|
@@ -99,6 +100,8 @@ export interface CalendarProps {
|
|
|
99
100
|
today?: string;
|
|
100
101
|
weekStartsOn?: 0 | 1;
|
|
101
102
|
maxVisible?: number;
|
|
103
|
+
/** `compact`: evento de 20px com 4px de padding lateral. @default 'default' */
|
|
104
|
+
density?: "default" | "compact";
|
|
102
105
|
locale?: string;
|
|
103
106
|
ariaLabel?: string;
|
|
104
107
|
previousLabel?: string;
|
|
@@ -100,7 +100,12 @@ function Calendar(props) {
|
|
|
100
100
|
];
|
|
101
101
|
}
|
|
102
102
|
function rootClasses() {
|
|
103
|
-
return [
|
|
103
|
+
return [
|
|
104
|
+
"umds-calendar",
|
|
105
|
+
"umds-calendar--" + viewValue(),
|
|
106
|
+
props.density === "compact" ? "umds-calendar--compact" : "",
|
|
107
|
+
props.className,
|
|
108
|
+
]
|
|
104
109
|
.filter(Boolean)
|
|
105
110
|
.join(" ");
|
|
106
111
|
}
|
|
@@ -23,7 +23,8 @@ export interface CoachmarkStep {
|
|
|
23
23
|
* O cartão é um diálogo modal (`role="dialog"`, `aria-modal`): o foco entra nele
|
|
24
24
|
* ao abrir, o Tab fica preso nele, Esc sai do tour, as setas esquerda e direita
|
|
25
25
|
* voltam e avançam, e o foco volta ao elemento de antes ao fechar. A cada passo o
|
|
26
|
-
* leitor de tela ouve "2 de 8: título" (região `aria-live`).
|
|
26
|
+
* leitor de tela ouve "2 de 8: título" (região `aria-live`). Com um passo só não há contador ("1 de 1" não
|
|
27
|
+
* diz nada): o cartão mostra o título e o leitor de tela ouve só ele.
|
|
27
28
|
*
|
|
28
29
|
* O componente é CONTROLADO por `open`: o tour só existe com `open` verdadeiro, e
|
|
29
30
|
* `onClose(motivo)` avisa quando ele quer fechar (`"finish"` no último
|
|
@@ -62,7 +62,12 @@ function Coachmark(props) {
|
|
|
62
62
|
.replace("{current}", String(index() + 1))
|
|
63
63
|
.replace("{total}", String(stepCount()));
|
|
64
64
|
}
|
|
65
|
+
function hasCounter() {
|
|
66
|
+
return stepCount() > 1;
|
|
67
|
+
}
|
|
65
68
|
function announceText() {
|
|
69
|
+
if (!hasCounter())
|
|
70
|
+
return currentStep().title;
|
|
66
71
|
return counterText() + ": " + currentStep().title;
|
|
67
72
|
}
|
|
68
73
|
function nextText() {
|
|
@@ -357,6 +362,6 @@ function Coachmark(props) {
|
|
|
357
362
|
desligarEsc();
|
|
358
363
|
};
|
|
359
364
|
}, []);
|
|
360
|
-
return (_jsx(_Fragment, { children: show() ? (_jsx(_Fragment, { children: _jsx(Portal, { children: _jsxs("div", { className: rootClasses(), children: [isModal() ? (_jsx("div", { "aria-hidden": "true", className: "umds-coachmark__veil", onMouseDown: (event) => handleVeilMouseDown(event) })) : null, hasTarget && isModal() ? (_jsx("div", { "aria-hidden": "true", className: "umds-coachmark__cutout", style: cutoutStyle() })) : null, _jsxs("div", { role: "dialog", ref: cardRef, style: cardStyle(), "aria-modal": ariaModalText(), "aria-labelledby": titleId(), "aria-describedby": contentId(), tabIndex: -1, onKeyDown: (event) => handleKeyDown(event), className: cardClasses(), children: [_jsx("span", { "aria-live": "polite", className: "umds-coachmark__sr", children: announceText() }), _jsx(Text, { as: "span", variant: "body2", weight: "bold", color: "primary", "aria-hidden": "true", children: counterText() }), _jsx(Text, { as: "h2", variant: "subtitle1", weight: "bold", id: titleId(), children: currentStep().title }), currentStep().content ? (_jsx(Text, { as: "p", variant: "body2", color: "secondary", id: contentId(), children: currentStep().content })) : null, _jsxs("div", { className: "umds-coachmark__footer", children: [showSkip() ? (_jsx(Button, { variant: "text", size: "sm", onClick: (event) => fechar("skip"), children: skipText() })) : null, _jsxs("span", { className: "umds-coachmark__actions", children: [!isFirst() ? (_jsx(Button, { variant: "secondary", size: "md", onClick: (event) => handlePrevious(), children: previousText() })) : null, _jsx(Button, { variant: "primary", size: "md", onClick: (event) => handleNext(), children: nextText() })] })] })] })] }) }) })) : null }));
|
|
365
|
+
return (_jsx(_Fragment, { children: show() ? (_jsx(_Fragment, { children: _jsx(Portal, { children: _jsxs("div", { className: rootClasses(), children: [isModal() ? (_jsx("div", { "aria-hidden": "true", className: "umds-coachmark__veil", onMouseDown: (event) => handleVeilMouseDown(event) })) : null, hasTarget && isModal() ? (_jsx("div", { "aria-hidden": "true", className: "umds-coachmark__cutout", style: cutoutStyle() })) : null, _jsxs("div", { role: "dialog", ref: cardRef, style: cardStyle(), "aria-modal": ariaModalText(), "aria-labelledby": titleId(), "aria-describedby": contentId(), tabIndex: -1, onKeyDown: (event) => handleKeyDown(event), className: cardClasses(), children: [_jsx("span", { "aria-live": "polite", className: "umds-coachmark__sr", children: announceText() }), hasCounter() ? (_jsx(Text, { as: "span", variant: "body2", weight: "bold", color: "primary", "aria-hidden": "true", children: counterText() })) : null, _jsx(Text, { as: "h2", variant: "subtitle1", weight: "bold", id: titleId(), children: currentStep().title }), currentStep().content ? (_jsx(Text, { as: "p", variant: "body2", color: "secondary", id: contentId(), children: currentStep().content })) : null, _jsxs("div", { className: "umds-coachmark__footer", children: [showSkip() ? (_jsx(Button, { variant: "text", size: "sm", onClick: (event) => fechar("skip"), children: skipText() })) : null, _jsxs("span", { className: "umds-coachmark__actions", children: [!isFirst() ? (_jsx(Button, { variant: "secondary", size: "md", onClick: (event) => handlePrevious(), children: previousText() })) : null, _jsx(Button, { variant: "primary", size: "md", onClick: (event) => handleNext(), children: nextText() })] })] })] })] }) }) })) : null }));
|
|
361
366
|
}
|
|
362
367
|
export default Coachmark;
|
|
@@ -207,6 +207,14 @@
|
|
|
207
207
|
padding: var(--umds-primitive-spacing-nano) var(--umds-primitive-spacing-nano); /* 6px: candidato a novo token; 8px */
|
|
208
208
|
}
|
|
209
209
|
|
|
210
|
+
/* Cabeçalho e linha de 44px (a altura de campo do DS). `height` na célula vale como mínimo: conteúdo mais
|
|
211
|
+
alto (avatar, botão) estica a linha. O documento imprime justo e fica fora. */
|
|
212
|
+
.umds-datatable--compact:not(.umds-datatable--document) .umds-datatable__th,
|
|
213
|
+
.umds-datatable--compact:not(.umds-datatable--document) .umds-datatable__td {
|
|
214
|
+
box-sizing: border-box;
|
|
215
|
+
height: var(--umds-semantic-field-height);
|
|
216
|
+
}
|
|
217
|
+
|
|
210
218
|
.umds-datatable--compact .umds-datatable__th--checkbox,
|
|
211
219
|
.umds-datatable--compact .umds-datatable__td--checkbox {
|
|
212
220
|
padding: var(--umds-primitive-spacing-nano) var(--umds-primitive-spacing-quarck) var(--umds-primitive-spacing-nano) var(--umds-primitive-spacing-nano); /* 6px: candidato a novo token; 4px; 8px */
|
|
@@ -273,6 +281,40 @@
|
|
|
273
281
|
background: var(--umds-semantic-color-primary-light);
|
|
274
282
|
}
|
|
275
283
|
|
|
284
|
+
/* ── Tom por linha (rowTone) ──
|
|
285
|
+
Fundo claro da cor semântica; a linha selecionada ou destacada vence o tom (por isso o :not). Fica depois da
|
|
286
|
+
zebra para vencê-la. `muted` só esmaece o texto. */
|
|
287
|
+
.umds-datatable__row--negative:not(.umds-datatable__row--selected),
|
|
288
|
+
.umds-datatable__row--negative:not(.umds-datatable__row--selected).umds-datatable__row--striped {
|
|
289
|
+
background: var(--umds-semantic-color-feedback-negative-light);
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
.umds-datatable__row--positive:not(.umds-datatable__row--selected),
|
|
293
|
+
.umds-datatable__row--positive:not(.umds-datatable__row--selected).umds-datatable__row--striped {
|
|
294
|
+
background: var(--umds-semantic-color-feedback-positive-light);
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
.umds-datatable__row--info:not(.umds-datatable__row--selected),
|
|
298
|
+
.umds-datatable__row--info:not(.umds-datatable__row--selected).umds-datatable__row--striped {
|
|
299
|
+
background: var(--umds-semantic-color-feedback-info-light);
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
.umds-datatable__row--negative:not(.umds-datatable__row--selected):hover {
|
|
303
|
+
background: color-mix(in srgb, var(--umds-semantic-color-feedback-negative-light) 85%, var(--umds-semantic-color-background-white));
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
.umds-datatable__row--positive:not(.umds-datatable__row--selected):hover {
|
|
307
|
+
background: color-mix(in srgb, var(--umds-semantic-color-feedback-positive-light) 85%, var(--umds-semantic-color-background-white));
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
.umds-datatable__row--info:not(.umds-datatable__row--selected):hover {
|
|
311
|
+
background: color-mix(in srgb, var(--umds-semantic-color-feedback-info-light) 85%, var(--umds-semantic-color-background-white));
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
.umds-datatable__row--muted .umds-datatable__td {
|
|
315
|
+
color: var(--umds-semantic-color-neutral-dark-down); /* #565656: 7,3:1 sobre branco */
|
|
316
|
+
}
|
|
317
|
+
|
|
276
318
|
/* ── Linha destacada (selectedRowKeys / isRowSelected) ──
|
|
277
319
|
Além do fundo, uma barra de 4px à esquerda: o destaque não depende só da cor. */
|
|
278
320
|
.umds-datatable__row--highlighted > :first-child {
|
|
@@ -35,8 +35,13 @@ export interface DataTableColumn {
|
|
|
35
35
|
* @property {Array<string|number>} selectedKeys - Chaves das linhas selecionadas (controlado;
|
|
36
36
|
* requer rowKey)
|
|
37
37
|
* @property {string} variant - 'default' (tabela de interface) | 'document' (tabela de CONTEÚDO de documento: sem ordenação, seleção nem clique de linha, bordas finas, cabeçalho repetido e linha inteira por página na impressão)
|
|
38
|
-
* @property {string} density - Densidade das células: 'default' | 'compact'.
|
|
39
|
-
*
|
|
38
|
+
* @property {string} density - Densidade das células: 'default' | 'compact'. O compacto aperta o padding e
|
|
39
|
+
* fixa a altura do cabeçalho e da linha em 44px (a altura de campo do DS; o conteúdo maior que isso cresce a
|
|
40
|
+
* linha). Com `variant="document"`, o compacto também leva a fonte a 12px (a escala do DS não tem 13px).
|
|
41
|
+
* @property {string|function} rowTone - Tom por linha: nome do campo da linha que traz o tom, ou função
|
|
42
|
+
* `(row, rowIndex) => tom`. Tons: 'negative' (vermelho claro), 'positive' (verde claro), 'info' (laranja claro)
|
|
43
|
+
* e 'muted' (texto esmaecido). Sem tom, a linha segue o padrão; a linha selecionada ou destacada vence o tom.
|
|
44
|
+
* O tom é decoração: diga o estado também em texto ou ícone (a cor sozinha não basta).
|
|
40
45
|
* @property {string} headerVariant - Cabeçalho: 'default' (claro) | 'dark' (navy, texto claro; o cabeçalho
|
|
41
46
|
* escuro do CrisDoc). Cores pelos tokens `background-dark` e `neutral-light-pure`, então o tema acompanha.
|
|
42
47
|
* @property {boolean} headerUppercase - Rótulos do cabeçalho em caixa alta. Opt-in; vale para qualquer
|
|
@@ -98,6 +103,8 @@ export interface DataTableProps {
|
|
|
98
103
|
/** `document`: tabela de conteúdo de documento, imprimível e sem interação. @default 'default' */
|
|
99
104
|
variant?: "default" | "document";
|
|
100
105
|
density?: "default" | "compact";
|
|
106
|
+
/** Tom por linha: nome do campo ou função `(row, rowIndex) => 'negative' | 'positive' | 'info' | 'muted'`. */
|
|
107
|
+
rowTone?: string | ((row: Record<string, any>, rowIndex: number) => string | undefined);
|
|
101
108
|
/** `dark`: cabeçalho navy com texto claro (o do CrisDoc). @default 'default' */
|
|
102
109
|
headerVariant?: "default" | "dark";
|
|
103
110
|
/** Rótulos do cabeçalho em caixa alta. @default false */
|
|
@@ -511,9 +511,24 @@ function DataTable(props) {
|
|
|
511
511
|
.filter(Boolean)
|
|
512
512
|
.join(" ");
|
|
513
513
|
}
|
|
514
|
+
function toneOf(row, index) {
|
|
515
|
+
if (!props.rowTone)
|
|
516
|
+
return "";
|
|
517
|
+
const bruto = typeof props.rowTone === "function"
|
|
518
|
+
? props.rowTone(row, index)
|
|
519
|
+
: row[props.rowTone];
|
|
520
|
+
const tom = bruto === undefined || bruto === null ? "" : String(bruto);
|
|
521
|
+
return tom === "negative" ||
|
|
522
|
+
tom === "positive" ||
|
|
523
|
+
tom === "info" ||
|
|
524
|
+
tom === "muted"
|
|
525
|
+
? tom
|
|
526
|
+
: "";
|
|
527
|
+
}
|
|
514
528
|
function rowClasses(row, rowIdx) {
|
|
515
529
|
return [
|
|
516
530
|
"umds-datatable__row",
|
|
531
|
+
toneOf(row, rowIdx) ? "umds-datatable__row--" + toneOf(row, rowIdx) : "",
|
|
517
532
|
isSelected(row, rowIdx) || isHighlighted(row, rowIdx)
|
|
518
533
|
? "umds-datatable__row--selected"
|
|
519
534
|
: "",
|
|
@@ -257,6 +257,15 @@
|
|
|
257
257
|
outline-offset: 0; /* exceção ao offset 2px: o botão vive DENTRO do campo, e o afastamento invadiria a borda */
|
|
258
258
|
}
|
|
259
259
|
|
|
260
|
+
/* ── variant="ghost": a busca dentro de um painel, sem a borda escura ──
|
|
261
|
+
Só o repouso muda (fundo claro e borda clara). Hover, foco, erro, desabilitado e somente leitura vêm das
|
|
262
|
+
regras do campo padrão, que têm mais especificidade (o :where zera a das cadeias de :not aqui), então o
|
|
263
|
+
hover escurece a borda e o foco segue com borda azul e anel. A moldura clara não é o único sinal do campo: o ícone, o placeholder e o cursor o dizem. */
|
|
264
|
+
.umds-input--ghost:where(:not(.umds-input--error):not(.umds-input--disabled):not(.umds-input--readonly)) .umds-input__container {
|
|
265
|
+
background-color: var(--umds-semantic-color-background-light);
|
|
266
|
+
border-color: var(--umds-semantic-color-neutral-light-medium);
|
|
267
|
+
}
|
|
268
|
+
|
|
260
269
|
/* ── borderless: o campo dentro de um grupo que já tem a moldura ──
|
|
261
270
|
Sem borda, fundo e raio. O foco NÃO some: o anel do campo vira um contorno
|
|
262
271
|
para dentro (WCAG 2.4.7), e o erro mantém a borda vermelha (a cor do erro não
|
|
@@ -36,6 +36,7 @@ export interface InputAction {
|
|
|
36
36
|
* @property {InputAction[]} iconsRight - Botões de ação com ícone à direita
|
|
37
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
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 {string} variant - 'default' | 'ghost'. O `ghost` é o campo de busca dentro de um painel: fundo cinza claro e borda clara (a escura do padrão some em repouso). O hover escurece a borda, e o foco, o erro, o desabilitado e o somente leitura são os do campo padrão (o anel de foco continua inteiro). Sem a prop, nada muda.
|
|
39
40
|
* @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
41
|
* @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
42
|
* @property {function} onChange - Callback acionado A CADA TECLA (recebe o novo valor string), nos dois frameworks. O blur sai em `onBlur`.
|
|
@@ -93,6 +94,8 @@ export interface InputProps {
|
|
|
93
94
|
iconsRight?: InputAction[];
|
|
94
95
|
/** Ícone decorativo à direita (não clicável, `aria-hidden`). Para ação, use `iconsRight`. */
|
|
95
96
|
iconRight?: IconProp;
|
|
97
|
+
/** `ghost`: o campo de busca dentro de um painel, sem a borda escura em repouso. @default 'default' */
|
|
98
|
+
variant?: "default" | "ghost";
|
|
96
99
|
/** 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
100
|
borderless?: boolean;
|
|
98
101
|
/**
|
|
@@ -52,6 +52,7 @@ function Input(props) {
|
|
|
52
52
|
props.numberSpinner ? "umds-input--number-spinner" : "",
|
|
53
53
|
props.borderless || props.grouped ? "umds-input--borderless" : "",
|
|
54
54
|
props.grouped ? "umds-input--grouped" : "",
|
|
55
|
+
props.variant === "ghost" ? "umds-input--ghost" : "",
|
|
55
56
|
`umds-input--${props.size || "md"}`,
|
|
56
57
|
props.className,
|
|
57
58
|
]
|