@snksergio/design-system 0.52.0 → 0.54.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/dist-lib/chunks/{panel-Bly-rNP9.cjs → panel-CTbiCa0_.cjs} +105 -3
- package/dist-lib/chunks/panel-CTbiCa0_.cjs.map +1 -0
- package/dist-lib/chunks/{panel-DA6K3a3n.mjs → panel-DsOKm4Im.mjs} +155 -53
- package/dist-lib/chunks/panel-DsOKm4Im.mjs.map +1 -0
- package/dist-lib/chunks/{toggle-group-C9rrkkmh.cjs → toggle-group-BTnqY_nt.cjs} +23 -23
- package/dist-lib/chunks/toggle-group-BTnqY_nt.cjs.map +1 -0
- package/dist-lib/chunks/{toggle-group-mXbG8_Jm.mjs → toggle-group-BYmj8142.mjs} +22 -22
- package/dist-lib/chunks/toggle-group-BYmj8142.mjs.map +1 -0
- package/dist-lib/index.cjs +634 -2
- package/dist-lib/index.cjs.map +1 -1
- package/dist-lib/index.mjs +692 -60
- package/dist-lib/index.mjs.map +1 -1
- package/dist-lib/preview/clientes.cjs +1 -1
- package/dist-lib/preview/clientes.mjs +1 -1
- package/dist-lib/shadcn.cjs +1 -1
- package/dist-lib/shadcn.mjs +1 -1
- package/dist-lib/src/components/index.d.ts +1 -0
- package/dist-lib/src/components/index.d.ts.map +1 -1
- package/dist-lib/src/components/ui/TabsNavigation/index.d.ts +5 -0
- package/dist-lib/src/components/ui/TabsNavigation/index.d.ts.map +1 -0
- package/dist-lib/src/components/ui/TabsNavigation/tabs-navigation-context.d.ts +19 -0
- package/dist-lib/src/components/ui/TabsNavigation/tabs-navigation-context.d.ts.map +1 -0
- package/dist-lib/src/components/ui/TabsNavigation/tabs-navigation.d.ts +84 -0
- package/dist-lib/src/components/ui/TabsNavigation/tabs-navigation.d.ts.map +1 -0
- package/dist-lib/src/components/ui/TabsNavigation/tabs-navigation.styles.d.ts +393 -0
- package/dist-lib/src/components/ui/TabsNavigation/tabs-navigation.styles.d.ts.map +1 -0
- package/dist-lib/src/components/ui/TabsNavigation/tabs-navigation.types.d.ts +99 -0
- package/dist-lib/src/components/ui/TabsNavigation/tabs-navigation.types.d.ts.map +1 -0
- package/dist-lib/src/components/ui/TabsNavigation/use-arrastar-para-rolar.d.ts +26 -0
- package/dist-lib/src/components/ui/TabsNavigation/use-arrastar-para-rolar.d.ts.map +1 -0
- package/dist-lib/src/components/ui/avatar-ig/avatar-group-context.d.ts +24 -0
- package/dist-lib/src/components/ui/avatar-ig/avatar-group-context.d.ts.map +1 -0
- package/dist-lib/src/components/ui/avatar-ig/avatar-group.d.ts +52 -0
- package/dist-lib/src/components/ui/avatar-ig/avatar-group.d.ts.map +1 -0
- package/dist-lib/src/components/ui/avatar-ig/avatar.d.ts +9 -0
- package/dist-lib/src/components/ui/avatar-ig/avatar.d.ts.map +1 -1
- package/dist-lib/src/components/ui/avatar-ig/avatar.styles.d.ts +93 -0
- package/dist-lib/src/components/ui/avatar-ig/avatar.styles.d.ts.map +1 -1
- package/dist-lib/src/components/ui/avatar-ig/avatar.types.d.ts +37 -0
- package/dist-lib/src/components/ui/avatar-ig/avatar.types.d.ts.map +1 -1
- package/dist-lib/src/components/ui/avatar-ig/index.d.ts +3 -2
- package/dist-lib/src/components/ui/avatar-ig/index.d.ts.map +1 -1
- package/dist-lib/theme.css +15 -0
- package/package.json +1 -1
- package/dist-lib/chunks/panel-Bly-rNP9.cjs.map +0 -1
- package/dist-lib/chunks/panel-DA6K3a3n.mjs.map +0 -1
- package/dist-lib/chunks/toggle-group-C9rrkkmh.cjs.map +0 -1
- package/dist-lib/chunks/toggle-group-mXbG8_Jm.mjs.map +0 -1
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { ReactNode } from 'react';
|
|
2
|
+
/** Superfície do CONTEÚDO abaixo da tira — a aba ativa precisa ser a mesma cor pra unir. */
|
|
3
|
+
export type TabsNavigationSurface = "surface" | "canvas";
|
|
4
|
+
/** `comfortable` = título + subtítulo (48px) · `compact` = só título (40px). */
|
|
5
|
+
export type TabsNavigationDensity = "comfortable" | "compact";
|
|
6
|
+
/** Tom do ponto de status. Passe um `ReactNode` em `status` pra desenhar o seu. */
|
|
7
|
+
export type TabsNavigationStatus = "success" | "warning" | "danger" | "info" | "neutral";
|
|
8
|
+
export interface TabsNavigationProps extends Omit<React.HTMLAttributes<HTMLDivElement>, "onChange"> {
|
|
9
|
+
/** `value` da aba ativa. O componente é SEMPRE controlado — ver `TabsNavigationProps.onValueChange`. */
|
|
10
|
+
value: string;
|
|
11
|
+
/**
|
|
12
|
+
* Chamado quando o usuário escolhe outra aba (clique, teclado ou lista de overflow).
|
|
13
|
+
*
|
|
14
|
+
* O componente **não hospeda o conteúdo**: ele diz qual aba está ativa e o consumidor
|
|
15
|
+
* decide o que trocar. É o que permite o painel morar fora — outra coluna, outra rota,
|
|
16
|
+
* outro componente. Pra fechar a acessibilidade nesse caso, passe `panelId` na aba.
|
|
17
|
+
*/
|
|
18
|
+
onValueChange: (value: string) => void;
|
|
19
|
+
/**
|
|
20
|
+
* Superfície do conteúdo logo abaixo da tira. A aba ativa é pintada com ela — é o que a
|
|
21
|
+
* une ao conteúdo. Num card `surface`; se o conteúdo for a própria página, `canvas`.
|
|
22
|
+
* @default "surface"
|
|
23
|
+
*/
|
|
24
|
+
surface?: TabsNavigationSurface;
|
|
25
|
+
/**
|
|
26
|
+
* `compact` remove o subtítulo e baixa a aba pra 40px. É escolha de CONTEÚDO, não de
|
|
27
|
+
* densidade: sem subtítulo, duas conversas do mesmo cliente ficam idênticas.
|
|
28
|
+
* @default "comfortable"
|
|
29
|
+
*/
|
|
30
|
+
density?: TabsNavigationDensity;
|
|
31
|
+
/**
|
|
32
|
+
* `true` = a aba ocupa a faixa inteira (lê como segmento, não como aba de navegador) e a
|
|
33
|
+
* tira perde a régua — a união passa a ser por continuidade de cor.
|
|
34
|
+
* @default false
|
|
35
|
+
*/
|
|
36
|
+
fill?: boolean;
|
|
37
|
+
/**
|
|
38
|
+
* `persistent` mantém as ações da aba sempre visíveis. Use quando a ação exige decisão
|
|
39
|
+
* (aceitar/recusar um chamado): revelar no hover esconde justamente o que precisa ser visto.
|
|
40
|
+
* @default "hover"
|
|
41
|
+
*/
|
|
42
|
+
actionsMode?: "hover" | "persistent";
|
|
43
|
+
/**
|
|
44
|
+
* Pinta o fundo recuado da tira (`bg-subtle` no claro, `bg-canvas` no escuro — cada modo tem
|
|
45
|
+
* o seu token de recuo). Desligue quando o container já pinta o fundo.
|
|
46
|
+
* @default true
|
|
47
|
+
*/
|
|
48
|
+
chrome?: boolean;
|
|
49
|
+
/** Com isto, o `+` aparece — fora do trilho, pra não sair de alcance quando as abas rolam. */
|
|
50
|
+
onNewTab?: () => void;
|
|
51
|
+
/** Rótulo do conjunto pro leitor de tela, ex.: `"Conversas abertas"`. */
|
|
52
|
+
"aria-label"?: string;
|
|
53
|
+
/** `<TabsNavigation.Tab>`s e, opcionalmente, um `<TabsNavigation.Actions>`. */
|
|
54
|
+
children?: ReactNode;
|
|
55
|
+
}
|
|
56
|
+
export interface TabsNavigationTabProps extends Omit<React.HTMLAttributes<HTMLDivElement>, "onSelect"> {
|
|
57
|
+
/** Identidade da aba — é o que volta em `onValueChange`. */
|
|
58
|
+
value: string;
|
|
59
|
+
/** Qualquer nó à esquerda: `Avatar`, `Icon`, imagem, sigla. */
|
|
60
|
+
leading?: ReactNode;
|
|
61
|
+
/** Ponto de status pronto, ou o seu próprio nó. */
|
|
62
|
+
status?: TabsNavigationStatus | ReactNode;
|
|
63
|
+
/** Contador (número) ou qualquer nó. Some quando a aba está ativa — o usuário já está lendo. */
|
|
64
|
+
badge?: number | ReactNode;
|
|
65
|
+
/**
|
|
66
|
+
* SUBSTITUI as ações padrão. Passe quantas quiser (`<TabsNavigation.Action>` ou qualquer botão) —
|
|
67
|
+
* é aqui que entram ✓/✗ de aceitar/recusar, "fixar", "duplicar".
|
|
68
|
+
*/
|
|
69
|
+
actions?: ReactNode;
|
|
70
|
+
/** Sem `actions`, declarar `onClose` liga as ações padrão (`⋯` de opções + `×` de fechar). */
|
|
71
|
+
onClose?: () => void;
|
|
72
|
+
/** Itens extras do menu `⋯` das ações padrão. Ignorado quando `actions` é passado. */
|
|
73
|
+
menu?: ReactNode;
|
|
74
|
+
/**
|
|
75
|
+
* `id` do elemento que esta aba controla, quando o conteúdo mora FORA do componente.
|
|
76
|
+
* Emite `aria-controls`. Dentro, prefira `<TabsNavigation.Panel value="…">`.
|
|
77
|
+
*/
|
|
78
|
+
panelId?: string;
|
|
79
|
+
/** Mantém as ações visíveis só nesta aba (o `pendente` do caso de chamados). */
|
|
80
|
+
actionsAlwaysVisible?: boolean;
|
|
81
|
+
/**
|
|
82
|
+
* Resumo mostrado ao pousar o ponteiro (500ms) — foto maior, contato, últimas informações.
|
|
83
|
+
* Qualquer nó; o conteúdo é seu.
|
|
84
|
+
*
|
|
85
|
+
* Existe como prop, e não envolvendo a aba num `HoverCard` por fora, porque a raiz separa os
|
|
86
|
+
* filhos por tipo pra montar a lista de overflow e a navegação por seta: um wrapper no lugar
|
|
87
|
+
* do `Tab` a faria perder a aba. ⚠️ Não é o lugar de ação nem de informação essencial —
|
|
88
|
+
* hover não existe no toque.
|
|
89
|
+
*/
|
|
90
|
+
hoverCard?: ReactNode;
|
|
91
|
+
/** `<TabsNavigation.Title>` + `<TabsNavigation.Subtitle>`, ou a composição que você quiser. */
|
|
92
|
+
children?: ReactNode;
|
|
93
|
+
}
|
|
94
|
+
export interface TabsNavigationPanelProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
95
|
+
/** Casa com o `value` da aba. Renderiza apenas quando ela está ativa. */
|
|
96
|
+
value: string;
|
|
97
|
+
children?: ReactNode;
|
|
98
|
+
}
|
|
99
|
+
//# sourceMappingURL=tabs-navigation.types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tabs-navigation.types.d.ts","sourceRoot":"","sources":["../../../../../src/components/ui/TabsNavigation/tabs-navigation.types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAEvC,4FAA4F;AAC5F,MAAM,MAAM,qBAAqB,GAAG,SAAS,GAAG,QAAQ,CAAC;AAEzD,gFAAgF;AAChF,MAAM,MAAM,qBAAqB,GAAG,aAAa,GAAG,SAAS,CAAC;AAE9D,mFAAmF;AACnF,MAAM,MAAM,oBAAoB,GAAG,SAAS,GAAG,SAAS,GAAG,QAAQ,GAAG,MAAM,GAAG,SAAS,CAAC;AAEzF,MAAM,WAAW,mBAAoB,SAAQ,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,cAAc,CAAC,EAAE,UAAU,CAAC;IACjG,wGAAwG;IACxG,KAAK,EAAE,MAAM,CAAC;IAEd;;;;;;OAMG;IACH,aAAa,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAEvC;;;;OAIG;IACH,OAAO,CAAC,EAAE,qBAAqB,CAAC;IAEhC;;;;OAIG;IACH,OAAO,CAAC,EAAE,qBAAqB,CAAC;IAEhC;;;;OAIG;IACH,IAAI,CAAC,EAAE,OAAO,CAAC;IAEf;;;;OAIG;IACH,WAAW,CAAC,EAAE,OAAO,GAAG,YAAY,CAAC;IAErC;;;;OAIG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;IAEjB,8FAA8F;IAC9F,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAC;IAEtB,yEAAyE;IACzE,YAAY,CAAC,EAAE,MAAM,CAAC;IAEtB,+EAA+E;IAC/E,QAAQ,CAAC,EAAE,SAAS,CAAC;CACtB;AAED,MAAM,WAAW,sBAAuB,SAAQ,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,cAAc,CAAC,EAAE,UAAU,CAAC;IACpG,4DAA4D;IAC5D,KAAK,EAAE,MAAM,CAAC;IAEd,+DAA+D;IAC/D,OAAO,CAAC,EAAE,SAAS,CAAC;IAEpB,mDAAmD;IACnD,MAAM,CAAC,EAAE,oBAAoB,GAAG,SAAS,CAAC;IAE1C,gGAAgG;IAChG,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAE3B;;;OAGG;IACH,OAAO,CAAC,EAAE,SAAS,CAAC;IAEpB,8FAA8F;IAC9F,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IAErB,sFAAsF;IACtF,IAAI,CAAC,EAAE,SAAS,CAAC;IAEjB;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IAEjB,gFAAgF;IAChF,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAE/B;;;;;;;;OAQG;IACH,SAAS,CAAC,EAAE,SAAS,CAAC;IAEtB,+FAA+F;IAC/F,QAAQ,CAAC,EAAE,SAAS,CAAC;CACtB;AAED,MAAM,WAAW,wBAAyB,SAAQ,KAAK,CAAC,cAAc,CAAC,cAAc,CAAC;IACpF,yEAAyE;IACzE,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,SAAS,CAAC;CACtB"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { RefObject } from 'react';
|
|
2
|
+
/**
|
|
3
|
+
* `useArrastarParaRolar` — segurar e arrastar a tira pra rolar horizontalmente.
|
|
4
|
+
*
|
|
5
|
+
* ## Por que não importei o `useGrabToScroll` do DataTable
|
|
6
|
+
*
|
|
7
|
+
* Ele existe (`ui/DataTable/hooks/use-grab-to-scroll.ts`) e resolve o mesmo gesto, mas está
|
|
8
|
+
* dentro do item `data-table` do registry: importá-lo faria o `tabs-navigation` **depender da
|
|
9
|
+
* tabela inteira** no copy-in — o consumidor puxaria DataTable + TableToolbar + virtual pra
|
|
10
|
+
* ter aba. Metade daquele hook também é específica de tabela (pula célula editável,
|
|
11
|
+
* expansível, de seleção), coisas que não existem aqui. Esta versão é o mesmo comportamento
|
|
12
|
+
* sem a parte que não se aplica.
|
|
13
|
+
*
|
|
14
|
+
* ## O que ele faz, e o que deliberadamente NÃO faz
|
|
15
|
+
*
|
|
16
|
+
* - **Só mouse/pen.** Em `pointer: coarse` (celular, tablet) o navegador já rola a tira no
|
|
17
|
+
* swipe, nativamente e com inércia. Interceptar ali seria trocar um gesto bom por um pior.
|
|
18
|
+
* - **Limiar de 6px** antes de virar arrasto: abaixo disso o gesto continua sendo um clique, e
|
|
19
|
+
* selecionar aba arrastando 2px por acidente não acontece.
|
|
20
|
+
* - **Engole o clique seguinte** ao arrasto (fase de captura) — senão soltar o ponteiro em
|
|
21
|
+
* cima de uma aba a selecionaria no fim de todo arrasto.
|
|
22
|
+
* - **Não toca em alvo interativo** (botão, link, menu): ali o gesto é do controle, não da
|
|
23
|
+
* tira. Sem isso, arrastar 6px começando no `×` fecharia a aba errada ou nenhuma.
|
|
24
|
+
*/
|
|
25
|
+
export declare function useArrastarParaRolar(trilho: RefObject<HTMLElement | null>, ativo?: boolean, limiarPx?: number): void;
|
|
26
|
+
//# sourceMappingURL=use-arrastar-para-rolar.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-arrastar-para-rolar.d.ts","sourceRoot":"","sources":["../../../../../src/components/ui/TabsNavigation/use-arrastar-para-rolar.ts"],"names":[],"mappings":"AAAA,OAAO,EAAqB,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAE1D;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,oBAAoB,CAClC,MAAM,EAAE,SAAS,CAAC,WAAW,GAAG,IAAI,CAAC,EACrC,KAAK,UAAO,EACZ,QAAQ,SAAI,GACX,IAAI,CAyFN"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { AvatarSize, AvatarSurface } from './avatar.types';
|
|
2
|
+
/**
|
|
3
|
+
* Contexto do `AvatarGroup` — é assim que o `size` chega nos filhos.
|
|
4
|
+
*
|
|
5
|
+
* ## Por que num arquivo só dele
|
|
6
|
+
*
|
|
7
|
+
* Evita ciclo de import: o `AvatarGroup` precisa do `Avatar` (renderiza o `+N`) e o `Avatar`
|
|
8
|
+
* precisa do contexto (lê o `size`). Com o contexto dentro do `avatar-group.tsx`, os dois
|
|
9
|
+
* módulos se importariam mutuamente — funciona em ESM na maioria dos casos, mas depende da
|
|
10
|
+
* ordem de avaliação e alguns bundlers avisam. Arquivo próprio corta a dependência.
|
|
11
|
+
*
|
|
12
|
+
* ## Por que contexto e não `cloneElement`
|
|
13
|
+
*
|
|
14
|
+
* Mesmo mecanismo do `ChipGroup`, do `KpiGroup` e do `CardOptionGroup`. Clonar filhos quebra
|
|
15
|
+
* quando eles vêm de um `map`, de um fragmento ou de um wrapper — que é exatamente como uma
|
|
16
|
+
* lista de responsáveis costuma ser montada.
|
|
17
|
+
*
|
|
18
|
+
* `undefined` = sem grupo em volta, e aí o `Avatar` mantém o default dele (`md`).
|
|
19
|
+
*/
|
|
20
|
+
export declare const AvatarGroupContext: import('react').Context<{
|
|
21
|
+
size?: AvatarSize;
|
|
22
|
+
surface: AvatarSurface;
|
|
23
|
+
} | undefined>;
|
|
24
|
+
//# sourceMappingURL=avatar-group-context.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"avatar-group-context.d.ts","sourceRoot":"","sources":["../../../../../src/components/ui/avatar-ig/avatar-group-context.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAEhE;;;;;;;;;;;;;;;;;GAiBG;AACH,eAAO,MAAM,kBAAkB;WACpB,UAAU;aAAW,aAAa;cACjC,CAAC"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { AvatarGroupProps } from './avatar.types';
|
|
2
|
+
/**
|
|
3
|
+
* `AvatarGroup` — pilha de avatares sobrepostos, com `size` propagado e excedente resumido.
|
|
4
|
+
*
|
|
5
|
+
* ## Por que existe
|
|
6
|
+
*
|
|
7
|
+
* A pilha era feita na mão em cada tela (`-ml-…` + `ring` escolhidos no olho), e três coisas
|
|
8
|
+
* saíam diferentes toda vez: quanto sobrepor, qual cor de anel, e o que fazer quando são 12
|
|
9
|
+
* pessoas. As três viram decisão do componente aqui.
|
|
10
|
+
*
|
|
11
|
+
* ## As quatro decisões, e por quê
|
|
12
|
+
*
|
|
13
|
+
* **1. A sobreposição escala com o tamanho.** Não é constante: 6px num avatar de 20px é 30% de
|
|
14
|
+
* sobreposição, e no de 40px é 15% — visualmente são arranjos diferentes. O mapa em
|
|
15
|
+
* `avatar.styles.ts` mantém ~25% em toda a escala.
|
|
16
|
+
*
|
|
17
|
+
* **2. O anel é da cor da SUPERFÍCIE DE TRÁS**, e é aqui que se erra. O anel separa um avatar
|
|
18
|
+
* do outro pintando o que está atrás; com o token errado ele deixa de separar e vira um halo.
|
|
19
|
+
* Por isso `surface` é **prop**, não constante.
|
|
20
|
+
*
|
|
21
|
+
* ⚠️ `table` e `surface` resolvem pro MESMO valor hoje (medido: `oklch(1 0 0)` no claro,
|
|
22
|
+
* `oklch(0.225 0 0)` no escuro). Dentro de tabela a escolha é **semântica**, não visual —
|
|
23
|
+
* declare `table` assim mesmo, pra a pilha seguir certa se um dia divergirem. Onde a diferença
|
|
24
|
+
* é visível hoje é em `canvas`, `subtle` e `muted`.
|
|
25
|
+
*
|
|
26
|
+
* **3. O primeiro fica por cima.** O empilhamento natural do DOM põe o último por cima; aqui o
|
|
27
|
+
* z-index é decrescente, porque a leitura é da esquerda pra direita e o primeiro avatar é o
|
|
28
|
+
* principal. É a convenção de Material e Ant, e é o que faz a pilha parecer uma fila.
|
|
29
|
+
*
|
|
30
|
+
* **4. O grupo fala, os avatares calam.** Três avatares soltos fazem o leitor de tela ler três
|
|
31
|
+
* nomes sem dizer que são um conjunto. O container leva `role="group"` + `aria-label`, e o
|
|
32
|
+
* `+N` é `aria-hidden` — o número já está no rótulo do grupo.
|
|
33
|
+
*
|
|
34
|
+
* ## Gotchas
|
|
35
|
+
*
|
|
36
|
+
* - **`size` no filho vence o do grupo.** É escape hatch pro caso de um avatar destacado; sem
|
|
37
|
+
* ele, não haveria como quebrar a uniformidade quando o desenho pede.
|
|
38
|
+
* - **`total` existe pra contagem do SERVIDOR.** Sem ele o `+N` conta só o que foi renderizado
|
|
39
|
+
* — e uma lista paginada em 5 mostraria `+0` tendo 40 pessoas.
|
|
40
|
+
* - **Não use pra 2 avatares sem sobreposição.** Aí é um `flex gap-gp-sm` comum: a pilha
|
|
41
|
+
* comunica "muitos, e o conjunto importa mais que cada um".
|
|
42
|
+
*
|
|
43
|
+
* @example
|
|
44
|
+
* <AvatarGroup size="sm" max={3} total={12} aria-label="12 responsáveis">
|
|
45
|
+
* <Avatar colorHex="#2563EB">MD</Avatar>
|
|
46
|
+
* <Avatar colorHex="#CC092F">AC</Avatar>
|
|
47
|
+
* <Avatar colorHex="#7C3AED">JS</Avatar>
|
|
48
|
+
* <Avatar colorHex="#0891B2">TK</Avatar>
|
|
49
|
+
* </AvatarGroup>
|
|
50
|
+
*/
|
|
51
|
+
export declare const AvatarGroup: import('react').ForwardRefExoticComponent<AvatarGroupProps & import('react').RefAttributes<HTMLDivElement>>;
|
|
52
|
+
//# sourceMappingURL=avatar-group.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"avatar-group.d.ts","sourceRoot":"","sources":["../../../../../src/components/ui/avatar-ig/avatar-group.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAEvD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgDG;AACH,eAAO,MAAM,WAAW,6GAwDvB,CAAC"}
|
|
@@ -15,6 +15,15 @@ import { AvatarProps } from './avatar.types';
|
|
|
15
15
|
* `className` com classe Tailwind `text-X` — ela sobrescreve a auto-pickada
|
|
16
16
|
* pela ordem de cascade.
|
|
17
17
|
*
|
|
18
|
+
* Foto (v0.53.0): passe `src` e mantenha as iniciais em `children` — elas são o
|
|
19
|
+
* **fallback** quando a URL falha. A imagem interna é `alt=""`; o nome da pessoa mora no
|
|
20
|
+
* `aria-label` do avatar, pra não ser anunciado duas vezes.
|
|
21
|
+
*
|
|
22
|
+
* ⚠️ Quando usar o `Avatar` compound do shadcn (`avatar`, com `AvatarImage`/`AvatarFallback`)
|
|
23
|
+
* em vez deste: quando o fallback não é iniciais (ícone, skeleton) ou você precisa controlar
|
|
24
|
+
* o estado de carregamento. Pra foto de pessoa dentro do DS — e sempre dentro de
|
|
25
|
+
* `AvatarGroup`, que propaga `size` por contexto — o certo é este.
|
|
26
|
+
*
|
|
18
27
|
* Accessibility:
|
|
19
28
|
* - With `aria-label` → role="img" (semantic avatar)
|
|
20
29
|
* - Without `aria-label` → aria-hidden="true" (decorative, inside a card/cell)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"avatar.d.ts","sourceRoot":"","sources":["../../../../../src/components/ui/avatar-ig/avatar.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"avatar.d.ts","sourceRoot":"","sources":["../../../../../src/components/ui/avatar-ig/avatar.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAElD;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,eAAO,MAAM,MAAM,wGAqFlB,CAAC"}
|
|
@@ -71,4 +71,97 @@ export declare const avatarVariants: import('tailwind-variants').TVReturnType<{
|
|
|
71
71
|
};
|
|
72
72
|
}, undefined, string[], unknown, unknown, undefined>>;
|
|
73
73
|
export type AvatarVariantProps = VariantProps<typeof avatarVariants>;
|
|
74
|
+
/**
|
|
75
|
+
* Item da pilha do `AvatarGroup` — o wrapper que sobrepõe e desenha o anel de separação.
|
|
76
|
+
*
|
|
77
|
+
* ## Por que o anel mora AQUI e não no `Avatar`
|
|
78
|
+
*
|
|
79
|
+
* `ring` acompanha o `border-radius` do elemento em que está. Num wrapper quadrado ele
|
|
80
|
+
* traçaria um quadrado em volta do círculo — daí o `rounded-radius-full` no próprio wrapper.
|
|
81
|
+
* E ficar no wrapper (e não no `Avatar`) mantém o `Avatar` solto sem anel nenhum: o anel só
|
|
82
|
+
* existe porque há sobreposição.
|
|
83
|
+
*
|
|
84
|
+
* ## A sobreposição escala com o tamanho
|
|
85
|
+
*
|
|
86
|
+
* Não é constante: 6px num avatar de 20px é **30%** de sobreposição, e no de 40px é **15%** —
|
|
87
|
+
* visualmente são arranjos diferentes. O mapa abaixo mantém ~25% em toda a escala, e cada
|
|
88
|
+
* valor é token de spacing (`sp-*`), não px na unha.
|
|
89
|
+
*
|
|
90
|
+
* ## O `surface` existe porque o anel é da cor do que está ATRÁS
|
|
91
|
+
*
|
|
92
|
+
* `ring-bg-surface` num painel funciona; na linha de uma tabela (`bg-bg-table`) apareceria um
|
|
93
|
+
* halo claro em volta de cada avatar. Quem sabe o que está atrás é quem compõe — daí ser prop.
|
|
94
|
+
*/
|
|
95
|
+
/**
|
|
96
|
+
* Container da pilha. É um `tv()` de uma linha só de propósito: sem ele o `className` do
|
|
97
|
+
* consumidor entraria por concatenação crua, e `items-start` não venceria o `items-center`
|
|
98
|
+
* daqui (é o `twMerge` embutido no `tv` que resolve conflito de classe). Também mantém o
|
|
99
|
+
* `avatar-ig` dependendo só de `@igreen/tv` — usar o `cn` de `@/lib/utils` acrescentaria uma
|
|
100
|
+
* `registryDependency` ao item por causa de duas classes.
|
|
101
|
+
*/
|
|
102
|
+
export declare const avatarGroupRoot: import('tailwind-variants').TVReturnType<{} | {} | {}, undefined, "flex items-center", {} | {}, undefined, import('tailwind-variants').TVReturnType<unknown, undefined, "flex items-center", unknown, unknown, undefined>>;
|
|
103
|
+
export declare const avatarGroupItem: import('tailwind-variants').TVReturnType<{
|
|
104
|
+
/** Deslocamento negativo ≈ 25% do diâmetro, em token. Ver o bloco acima. */
|
|
105
|
+
size: {
|
|
106
|
+
xs: string;
|
|
107
|
+
sm: string;
|
|
108
|
+
md: string;
|
|
109
|
+
lg: string;
|
|
110
|
+
xl: string;
|
|
111
|
+
};
|
|
112
|
+
/** Cor do anel = superfície de trás. */
|
|
113
|
+
surface: {
|
|
114
|
+
surface: string;
|
|
115
|
+
canvas: string;
|
|
116
|
+
subtle: string;
|
|
117
|
+
muted: string;
|
|
118
|
+
table: string;
|
|
119
|
+
};
|
|
120
|
+
/** O primeiro não desloca — senão a pilha inteira sai da margem esquerda. */
|
|
121
|
+
primeiro: {
|
|
122
|
+
true: string;
|
|
123
|
+
};
|
|
124
|
+
}, undefined, string[], {
|
|
125
|
+
/** Deslocamento negativo ≈ 25% do diâmetro, em token. Ver o bloco acima. */
|
|
126
|
+
size: {
|
|
127
|
+
xs: string;
|
|
128
|
+
sm: string;
|
|
129
|
+
md: string;
|
|
130
|
+
lg: string;
|
|
131
|
+
xl: string;
|
|
132
|
+
};
|
|
133
|
+
/** Cor do anel = superfície de trás. */
|
|
134
|
+
surface: {
|
|
135
|
+
surface: string;
|
|
136
|
+
canvas: string;
|
|
137
|
+
subtle: string;
|
|
138
|
+
muted: string;
|
|
139
|
+
table: string;
|
|
140
|
+
};
|
|
141
|
+
/** O primeiro não desloca — senão a pilha inteira sai da margem esquerda. */
|
|
142
|
+
primeiro: {
|
|
143
|
+
true: string;
|
|
144
|
+
};
|
|
145
|
+
}, undefined, import('tailwind-variants').TVReturnType<{
|
|
146
|
+
/** Deslocamento negativo ≈ 25% do diâmetro, em token. Ver o bloco acima. */
|
|
147
|
+
size: {
|
|
148
|
+
xs: string;
|
|
149
|
+
sm: string;
|
|
150
|
+
md: string;
|
|
151
|
+
lg: string;
|
|
152
|
+
xl: string;
|
|
153
|
+
};
|
|
154
|
+
/** Cor do anel = superfície de trás. */
|
|
155
|
+
surface: {
|
|
156
|
+
surface: string;
|
|
157
|
+
canvas: string;
|
|
158
|
+
subtle: string;
|
|
159
|
+
muted: string;
|
|
160
|
+
table: string;
|
|
161
|
+
};
|
|
162
|
+
/** O primeiro não desloca — senão a pilha inteira sai da margem esquerda. */
|
|
163
|
+
primeiro: {
|
|
164
|
+
true: string;
|
|
165
|
+
};
|
|
166
|
+
}, undefined, string[], unknown, unknown, undefined>>;
|
|
74
167
|
//# sourceMappingURL=avatar.styles.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"avatar.styles.d.ts","sourceRoot":"","sources":["../../../../../src/components/ui/avatar-ig/avatar.styles.ts"],"names":[],"mappings":"AAAA,OAAO,EAAM,KAAK,YAAY,EAAE,MAAM,YAAY,CAAC;AAEnD;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,cAAc;;;;;;;;;;;;;;;QA2BrB,8DAA8D;;;;;;;;;;;;;;;;;;QAA9D,8DAA8D;;;;;;;;;;;;;;;;;;QAA9D,8DAA8D;;;qDASlE,CAAC;AAEH,MAAM,MAAM,kBAAkB,GAAG,YAAY,CAAC,OAAO,cAAc,CAAC,CAAC"}
|
|
1
|
+
{"version":3,"file":"avatar.styles.d.ts","sourceRoot":"","sources":["../../../../../src/components/ui/avatar-ig/avatar.styles.ts"],"names":[],"mappings":"AAAA,OAAO,EAAM,KAAK,YAAY,EAAE,MAAM,YAAY,CAAC;AAEnD;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,cAAc;;;;;;;;;;;;;;;QA2BrB,8DAA8D;;;;;;;;;;;;;;;;;;QAA9D,8DAA8D;;;;;;;;;;;;;;;;;;QAA9D,8DAA8D;;;qDASlE,CAAC;AAEH,MAAM,MAAM,kBAAkB,GAAG,YAAY,CAAC,OAAO,cAAc,CAAC,CAAC;AAErE;;;;;;;;;;;;;;;;;;;;GAoBG;AACH;;;;;;GAMG;AACH,eAAO,MAAM,eAAe,4NAAoC,CAAC;AAEjE,eAAO,MAAM,eAAe;IAIxB,4EAA4E;;;;;;;;IAS5E,wCAAwC;;;;;;;;IASxC,6EAA6E;;;;;IAlB7E,4EAA4E;;;;;;;;IAS5E,wCAAwC;;;;;;;;IASxC,6EAA6E;;;;;IAlB7E,4EAA4E;;;;;;;;IAS5E,wCAAwC;;;;;;;;IASxC,6EAA6E;;;;qDAQ/E,CAAC"}
|
|
@@ -12,5 +12,42 @@ export interface AvatarProps extends Omit<React.HTMLAttributes<HTMLDivElement>,
|
|
|
12
12
|
* Takes precedence over `color`.
|
|
13
13
|
*/
|
|
14
14
|
colorHex?: string;
|
|
15
|
+
/**
|
|
16
|
+
* Foto da pessoa. Quando carrega, cobre o círculo inteiro; quando **falha**, o avatar
|
|
17
|
+
* volta pras iniciais (`children`) com a cor de sempre — por isso continue passando as
|
|
18
|
+
* iniciais mesmo com `src`.
|
|
19
|
+
*
|
|
20
|
+
* Não há prop `alt`: o nome mora no `aria-label` do avatar (a imagem interna é
|
|
21
|
+
* `alt=""`). Dois rótulos no mesmo elemento fariam o leitor de tela anunciar a pessoa
|
|
22
|
+
* duas vezes.
|
|
23
|
+
*/
|
|
24
|
+
src?: string;
|
|
25
|
+
}
|
|
26
|
+
/** Tamanhos do avatar — reusado pelo grupo, que os propaga por contexto. */
|
|
27
|
+
export type AvatarSize = NonNullable<AvatarVariantProps["size"]>;
|
|
28
|
+
/**
|
|
29
|
+
* Superfície ATRÁS do grupo — define a cor do anel que separa um avatar do outro.
|
|
30
|
+
* Errar aqui é o defeito clássico da pilha: anel `surface` numa linha de tabela vira halo.
|
|
31
|
+
*/
|
|
32
|
+
export type AvatarSurface = "surface" | "canvas" | "subtle" | "muted" | "table";
|
|
33
|
+
export interface AvatarGroupProps extends Omit<React.HTMLAttributes<HTMLDivElement>, "color"> {
|
|
34
|
+
/**
|
|
35
|
+
* Tamanho de TODOS os avatares do grupo, propagado por contexto.
|
|
36
|
+
* `size` no filho vence — escape hatch pro caso de um destacado.
|
|
37
|
+
* @default "md"
|
|
38
|
+
*/
|
|
39
|
+
size?: AvatarSize;
|
|
40
|
+
/** Acima disso, corta e mostra `+N` no fim. Sem `max`, mostra todos. */
|
|
41
|
+
max?: number;
|
|
42
|
+
/**
|
|
43
|
+
* Contagem REAL, quando ela não é o número de filhos renderizados.
|
|
44
|
+
* Sem isso, uma lista paginada em 5 mostraria `+0` tendo 40 pessoas.
|
|
45
|
+
*/
|
|
46
|
+
total?: number;
|
|
47
|
+
/**
|
|
48
|
+
* Superfície atrás do grupo — cor do anel de separação.
|
|
49
|
+
* @default "surface"
|
|
50
|
+
*/
|
|
51
|
+
surface?: AvatarSurface;
|
|
15
52
|
}
|
|
16
53
|
//# sourceMappingURL=avatar.types.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"avatar.types.d.ts","sourceRoot":"","sources":["../../../../../src/components/ui/avatar-ig/avatar.types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AAE1D,MAAM,WAAW,WACf,SAAQ,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,cAAc,CAAC,EAAE,OAAO,CAAC,EACzD,IAAI,CAAC,kBAAkB,EAAE,OAAO,CAAC;IACnC;;;;OAIG;IACH,KAAK,CAAC,EAAE,OAAO,GAAG,SAAS,GAAG,SAAS,GAAG,UAAU,GAAG,MAAM,GAAG,OAAO,CAAC;IAExE;;;;OAIG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"avatar.types.d.ts","sourceRoot":"","sources":["../../../../../src/components/ui/avatar-ig/avatar.types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AAE1D,MAAM,WAAW,WACf,SAAQ,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,cAAc,CAAC,EAAE,OAAO,CAAC,EACzD,IAAI,CAAC,kBAAkB,EAAE,OAAO,CAAC;IACnC;;;;OAIG;IACH,KAAK,CAAC,EAAE,OAAO,GAAG,SAAS,GAAG,SAAS,GAAG,UAAU,GAAG,MAAM,GAAG,OAAO,CAAC;IAExE;;;;OAIG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAElB;;;;;;;;OAQG;IACH,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED,4EAA4E;AAC5E,MAAM,MAAM,UAAU,GAAG,WAAW,CAAC,kBAAkB,CAAC,MAAM,CAAC,CAAC,CAAC;AAEjE;;;GAGG;AACH,MAAM,MAAM,aAAa,GAAG,SAAS,GAAG,QAAQ,GAAG,QAAQ,GAAG,OAAO,GAAG,OAAO,CAAC;AAEhF,MAAM,WAAW,gBACf,SAAQ,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,cAAc,CAAC,EAAE,OAAO,CAAC;IAC3D;;;;OAIG;IACH,IAAI,CAAC,EAAE,UAAU,CAAC;IAElB,wEAAwE;IACxE,GAAG,CAAC,EAAE,MAAM,CAAC;IAEb;;;OAGG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf;;;OAGG;IACH,OAAO,CAAC,EAAE,aAAa,CAAC;CACzB"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export { Avatar } from './avatar';
|
|
2
|
-
export {
|
|
3
|
-
export type
|
|
2
|
+
export { AvatarGroup } from './avatar-group';
|
|
3
|
+
export { avatarVariants, avatarGroupRoot, avatarGroupItem, type AvatarVariantProps, } from './avatar.styles';
|
|
4
|
+
export type { AvatarProps, AvatarGroupProps, AvatarSize, AvatarSurface, } from './avatar.types';
|
|
4
5
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/components/ui/avatar-ig/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAClC,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/components/ui/avatar-ig/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAClC,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAC7C,OAAO,EACL,cAAc,EACd,eAAe,EACf,eAAe,EACf,KAAK,kBAAkB,GACxB,MAAM,iBAAiB,CAAC;AACzB,YAAY,EACV,WAAW,EACX,gBAAgB,EAChB,UAAU,EACV,aAAa,GACd,MAAM,gBAAgB,CAAC"}
|
package/dist-lib/theme.css
CHANGED
|
@@ -685,6 +685,21 @@ body {
|
|
|
685
685
|
}
|
|
686
686
|
}
|
|
687
687
|
|
|
688
|
+
/* Rola, mas sem barra visível. Existe pro caso em que a barra QUEBRA o layout, não por
|
|
689
|
+
estética: na tira do TabsNavigation ela ocupa 11px DENTRO do trilho e empurra as abas 11px pra
|
|
690
|
+
cima da régua — a união da aba ativa com o conteúdo, que é o componente inteiro, some.
|
|
691
|
+
Medido antes de existir esta utility; a alternativa era `[scrollbar-width:none]` +
|
|
692
|
+
`[&::-webkit-scrollbar]:hidden` na unha, em componente distribuído.
|
|
693
|
+
⚠️ Só use quando houver outra affordance de navegação (setas, arrastar, teclado): barra
|
|
694
|
+
escondida sem substituto é conteúdo inalcançável pra quem só tem mouse. */
|
|
695
|
+
@utility scrollbar-none {
|
|
696
|
+
scrollbar-width: none;
|
|
697
|
+
|
|
698
|
+
&::-webkit-scrollbar {
|
|
699
|
+
display: none;
|
|
700
|
+
}
|
|
701
|
+
}
|
|
702
|
+
|
|
688
703
|
/* ── Superfície flutuante (usadas por 14 componentes distribuídos) ────────── */
|
|
689
704
|
|
|
690
705
|
@utility outline-float {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@snksergio/design-system",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.54.0",
|
|
4
4
|
"//distribuicao": "Canal PRIMARIO = registry shadcn (copy-in) + CLI @snksergio/create-design-system; sobe sozinho no merge (Vercel). Canal SECUNDARIO = este pacote npm (@snksergio/design-system), publicado por passo MANUAL do mantenedor, entao costuma ficar atras do registry. SECUNDARIO descreve a ORDEM DE PUBLICACAO, nao o nivel de suporte: NAO e depreciado, e desde a 0.37.0 entrega 41 dos 42 componentes ui/ no barrel raiz + os 41 primitivos shadcn no subpath ./shadcn (so TabelaTeste, demo interno, fica de fora). Publish so pelo Passo 7 do .claude/skills/ds-dev/release.md (valida com `npm run lib:verify`, pede o token, publica, revoga). Ver DISTRIBUICAO.md.",
|
|
5
5
|
"description": "iGreen Design System — internal library for SaaS CRM, admin panels and dashboards. React 19 + Tailwind v4 + Shadcn + Radix.",
|
|
6
6
|
"license": "UNLICENSED",
|