@ffid-br/tailor-ui 0.4.0 → 0.6.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/style.css CHANGED
@@ -18,6 +18,78 @@
18
18
  --tailor-ease-in-out: cubic-bezier(0.65, 0, 0.35, 1);
19
19
  }
20
20
 
21
+ /*
22
+ * Marca do cliente: componentes que leem estas variáveis vestem a marca de quem
23
+ * usa. Padrão Tailor aqui, em :where() para qualquer CSS do app sobrescrever
24
+ * (ou o componente TailorMarca). Tema escuro: `.dark` ou `[data-theme="dark"]`.
25
+ */
26
+ :where(:root) {
27
+ /* Seguem os tokens do Tailwind do app: quem já troca --color-tailor-green pela
28
+ cor do cliente (accounts, brandTheme) leva o cabeçalho junto. */
29
+ --tailor-marca-primaria: var(--color-tailor-green, var(--tailor-green));
30
+ --tailor-marca-primaria-texto: var(--color-tailor-ink, var(--tailor-ink));
31
+ --tailor-marca-texto: var(--tailor-black);
32
+ --tailor-marca-texto-suave: #666666;
33
+ --tailor-marca-borda: #E5E5E5;
34
+ --tailor-marca-fundo: transparent;
35
+ --tailor-marca-fonte-titulo: var(--tailor-font);
36
+ --tailor-marca-fonte-texto: var(--tailor-font);
37
+ --tailor-marca-peso-titulo: 500;
38
+ --tailor-marca-caixa-titulo: none;
39
+ --tailor-marca-raio: 0;
40
+ }
41
+ :where(.dark, [data-theme="dark"]) {
42
+ --tailor-marca-primaria-texto: var(--color-tailor-green, var(--tailor-green));
43
+ --tailor-marca-texto: var(--tailor-white);
44
+ --tailor-marca-texto-suave: #A3A3A3;
45
+ --tailor-marca-borda: rgba(255, 255, 255, 0.1);
46
+ }
47
+ .tailor-marca { display: contents; }
48
+
49
+ /* TailorPageHeader — cada medida tem a sua variável --tailor-cabecalho-*. */
50
+ .tailor-ph {
51
+ display: flex; flex-direction: column; gap: 21px;
52
+ padding: var(--tailor-cabecalho-padding, 0 0 21px);
53
+ background: var(--tailor-cabecalho-fundo, var(--tailor-marca-fundo));
54
+ border-bottom: var(--tailor-cabecalho-regua, 1px solid var(--tailor-marca-borda));
55
+ color: var(--tailor-marca-texto);
56
+ font-family: var(--tailor-marca-fonte-texto);
57
+ }
58
+ .tailor-ph__linha { display: flex; flex-direction: column; gap: 21px; }
59
+ @media (min-width: 640px) {
60
+ .tailor-ph__linha { flex-direction: row; align-items: flex-end; justify-content: space-between; }
61
+ }
62
+ .tailor-ph__principal { min-width: 0; display: flex; flex-direction: column; align-items: flex-start; gap: 8px; }
63
+ .tailor-ph__voltar {
64
+ display: inline-flex; align-items: center; gap: 6px; padding: 0; border: 0; background: none; cursor: pointer;
65
+ font: inherit; font-size: 13px; color: var(--tailor-marca-texto-suave); text-decoration: none; border-radius: var(--tailor-marca-raio);
66
+ }
67
+ .tailor-ph__voltar:hover, .tailor-ph__trilha-link:hover { color: var(--tailor-marca-texto); }
68
+ .tailor-ph__trilha ol { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; margin: 0; padding: 0; list-style: none; font-size: 13px; color: var(--tailor-marca-texto-suave); }
69
+ .tailor-ph__trilha li { display: flex; align-items: center; gap: 6px; }
70
+ .tailor-ph__trilha-link { color: inherit; text-decoration: none; }
71
+ .tailor-ph__trilha [aria-current="page"] { color: var(--tailor-marca-texto); }
72
+ .tailor-ph__voltar:focus-visible, .tailor-ph__trilha-link:focus-visible { outline: 3px solid var(--tailor-marca-primaria); outline-offset: 2px; }
73
+ .tailor-ph__sobretitulo {
74
+ display: flex; align-items: center; gap: 8px; margin: 5px 0 0;
75
+ font-size: 11px; font-weight: 500; letter-spacing: 0.14em; text-transform: uppercase;
76
+ color: var(--tailor-marca-primaria-texto);
77
+ }
78
+ .tailor-ph__ponto { width: 8px; height: 8px; background: var(--tailor-marca-primaria); border-radius: var(--tailor-marca-raio); }
79
+ .tailor-ph__titulo-linha { display: flex; flex-wrap: wrap; align-items: center; gap: 13px; }
80
+ .tailor-ph__titulo {
81
+ margin: 0; line-height: 1.1;
82
+ font-family: var(--tailor-marca-fonte-titulo); font-weight: var(--tailor-marca-peso-titulo);
83
+ text-transform: var(--tailor-marca-caixa-titulo);
84
+ font-size: var(--tailor-cabecalho-tamanho-titulo, clamp(26px, 4vw, 42px));
85
+ }
86
+ .tailor-ph__descricao { margin: 0; max-width: 610px; font-size: 16px; line-height: 1.618; color: var(--tailor-marca-texto-suave); }
87
+ .tailor-ph__lateral { display: flex; flex-shrink: 0; flex-wrap: wrap; align-items: center; gap: 13px; }
88
+ .tailor-ph__indicador { text-align: right; }
89
+ .tailor-ph__indicador-valor { display: block; font-size: 26px; font-weight: 500; line-height: 1; font-variant-numeric: tabular-nums; font-family: var(--tailor-marca-fonte-titulo); }
90
+ .tailor-ph__indicador-rotulo { display: block; margin-top: 8px; font-size: 13px; color: var(--tailor-marca-texto-suave); }
91
+ .tailor-ph__extra { min-width: 0; }
92
+
21
93
  /* TailorLoader — a malha pequena se desenha a partir do ponto e some, em 2φ (3,236s). */
22
94
  .tailor-malha__linha {
23
95
  stroke-dasharray: 1;
@@ -102,6 +174,44 @@
102
174
  .tailor-estado__ponto--feito { background: #008548; }
103
175
  .tailor-estado__ponto--subiu { background: #0040FF; }
104
176
  .tailor-estado__ponto--desligado { background: #999999; }
177
+ .tailor-estado__ponto--parado { background: #666666; }
178
+ .tailor-estado__ponto--cumprimentando { background: var(--tailor-green); }
179
+ .tailor-estado__ponto--falando { background: #008548; }
180
+ .tailor-estado__ponto--erro { background: #FF0040; }
181
+
182
+ /* AgenteMascote estilo vetor: o movimento diz o estado; o olhar segue o cursor. */
183
+ .tailor-mv { line-height: 0; }
184
+ .tailor-mv__corpo { transform-box: fill-box; transform-origin: 50% 100%; animation: tailor-mv-respira 3.2s ease-in-out infinite; }
185
+ .tailor-mv--esperando .tailor-mv__corpo { animation: tailor-mv-espera 1.8s ease-in-out infinite; }
186
+ .tailor-mv--pensando .tailor-mv__corpo { animation: tailor-mv-inclina 2.6s ease-in-out infinite; }
187
+ .tailor-mv--comemorando .tailor-mv__corpo { animation: tailor-mv-pulo 0.9s cubic-bezier(.16,1,.3,1) infinite; }
188
+ .tailor-mv--erro .tailor-mv__corpo { animation: tailor-mv-treme 1.6s ease-in-out infinite; }
189
+ .tailor-mv--dormindo .tailor-mv__corpo { animation-duration: 5s; opacity: 0.55; }
190
+ .tailor-mv__olhos { transform-box: fill-box; transform-origin: center; animation: tailor-mv-piscar 4.2s infinite; }
191
+ .tailor-mv__pupila { transform: translate(var(--tailor-mv-x, 0), var(--tailor-mv-y, 0)); transition: transform 0.12s ease-out; }
192
+ .tailor-mv--pensando .tailor-mv__pupila { transform: translate(-4px, -5px); }
193
+ .tailor-mv__verde { animation: tailor-mv-pulso 2.4s ease-in-out infinite; }
194
+ .tailor-mv__balao {
195
+ position: absolute; left: 58%; bottom: 88%; z-index: 1; width: max-content; max-width: 180px;
196
+ background: var(--tailor-black); color: var(--tailor-white); padding: 8px 10px;
197
+ font: 500 12px/1.35 var(--font-tailor, "Raleway", system-ui, sans-serif); text-align: left;
198
+ }
199
+ .tailor-mv__balao::after { content: ""; position: absolute; left: 10px; bottom: -5px; width: 10px; height: 10px; background: inherit; transform: rotate(45deg); }
200
+ .tailor-mv__pontos > span { display: inline-block; width: 6px; height: 6px; margin: 0 2px; background: var(--tailor-green); animation: tailor-mv-ponto 1.4s infinite; }
201
+ .tailor-mv__pontos > span:nth-child(2) { animation-delay: 0.2s; }
202
+ .tailor-mv__pontos > span:nth-child(3) { animation-delay: 0.4s; }
203
+ .tailor-mv__confete rect { animation: tailor-mv-cai 1.8s linear infinite; }
204
+ .tailor-mv__zzz text { animation: tailor-mv-sobe 3s linear infinite; font: 600 18px sans-serif; }
205
+ @keyframes tailor-mv-respira { 0%, 100% { transform: none; } 50% { transform: scale(1.015, 0.985); } }
206
+ @keyframes tailor-mv-espera { 0%, 100% { transform: none; } 50% { transform: translateY(-4px); } }
207
+ @keyframes tailor-mv-inclina { 0%, 100% { transform: rotate(-5deg); } 50% { transform: rotate(-2deg); } }
208
+ @keyframes tailor-mv-pulo { 0%, 100% { transform: scale(1.03, 0.97); } 40% { transform: translateY(-18px) scale(0.98, 1.02); } }
209
+ @keyframes tailor-mv-treme { 0%, 60%, 100% { transform: none; } 66% { transform: translateX(-5px); } 72% { transform: translateX(5px); } 78% { transform: translateX(-3px); } 84% { transform: translateX(3px); } }
210
+ @keyframes tailor-mv-piscar { 0%, 94%, 100% { transform: none; } 97% { transform: scaleY(0.1); } }
211
+ @keyframes tailor-mv-pulso { 0%, 100% { opacity: 1; } 50% { opacity: 0.55; } }
212
+ @keyframes tailor-mv-ponto { 0%, 80%, 100% { opacity: 0.25; } 40% { opacity: 1; } }
213
+ @keyframes tailor-mv-cai { 0% { transform: translateY(-20px); opacity: 0; } 15% { opacity: 1; } 100% { transform: translateY(70px); opacity: 0; } }
214
+ @keyframes tailor-mv-sobe { 0% { transform: none; opacity: 0; } 20% { opacity: 1; } 100% { transform: translate(14px, -40px); opacity: 0; } }
105
215
 
106
216
  /* Menos movimento: a informação continua, o movimento sai. */
107
217
  @media (prefers-reduced-motion: reduce) {
@@ -109,4 +219,5 @@
109
219
  .tailor-loader__reticencias::after { animation: none; content: '...'; }
110
220
  .tailor-ponto-pisca { animation: none; }
111
221
  .tailor-mascote__corpo, .tailor-mascote__olho, .tailor-mascote__verde { animation: none; }
222
+ .tailor-mv *, .tailor-mv *::after { animation: none !important; transition: none !important; }
112
223
  }
@@ -1,3 +1,4 @@
1
+ import { AcessorioDoMascote, ChaveDoAgenteVetor, ExpressaoDoMascote, ObjetoDoMascote, TemaDoMascote } from './MascoteVetor';
1
2
  /**
2
3
  * Mapas 8x8 dos agentes (QD-0426, estilo Dots). `k` tinta, `e` olho (pisca),
3
4
  * `g` o único verde do personagem (pulsa), `.` vazio. Desenho aprovado em
@@ -9,26 +10,49 @@ declare const MAPAS: {
9
10
  readonly pm: readonly ["..gggg..", "kkkkkkkk", "k......k", "k.e..e.k", "k......k", "k.kkkk.k", "k......k", "kkkkkkkk"];
10
11
  readonly diretor: readonly [".kkkkkk.", ".k....k.", "kkkkkkkk", ".kk..kk.", ".k....k.", ".k.kk.k.", ".kkkkkk.", "...gg..."];
11
12
  };
13
+ /** Agentes com desenho em pixel. Os demais só existem em vetor. */
12
14
  export type ChaveDoMascote = keyof typeof MAPAS;
13
- export type EstadoDoMascote = 'analisando' | 'esperando' | 'feito' | 'subiu' | 'desligado';
15
+ export type ChaveDoAgente = ChaveDoAgenteVetor;
16
+ export type EstadoDoMascote = 'analisando' | 'esperando' | 'feito' | 'subiu' | 'desligado' | 'parado' | 'cumprimentando' | 'falando' | 'erro';
14
17
  /** Texto do estado: a cor nunca fala sozinha. */
15
18
  export declare const ROTULO_DO_ESTADO: Record<EstadoDoMascote, string>;
19
+ /** O vetor pinta por variável; `auto` segue o `dark:` do app. */
20
+ declare const SUPERFICIE: {
21
+ auto: string;
22
+ clara: string;
23
+ escura: string;
24
+ };
16
25
  export type AgenteMascoteProps = {
17
- agente: ChaveDoMascote;
26
+ agente: ChaveDoAgente;
18
27
  /** Nome exibido (a conta pode renomear). Vai no rótulo acessível. */
19
28
  nome: string;
20
29
  estado?: EstadoDoMascote;
21
30
  /** Quantas coisas esperam a pessoa. Só aparece acima de zero. */
22
31
  selo?: number;
23
- /** Lado de cada quadradinho, em px. Padrão: 4 (32px no total). */
32
+ /** Lado de cada quadradinho, em px. Padrão: 4 (32px no total). No vetor, a largura padrão é `celula * 8`. */
24
33
  celula?: number;
25
34
  /** Mostra o ponto e o texto do estado ao lado. */
26
35
  mostrarEstado?: boolean;
36
+ /** `pixel` (padrão) é a grade 8x8; `vetor` é o companheiro animado. Agentes sem mapa 8x8 saem sempre em vetor. */
37
+ estilo?: 'pixel' | 'vetor';
38
+ /** Vetor: largura em px. */
39
+ tamanho?: number;
40
+ /** Vetor: olhar no lugar do padrão do estado. */
41
+ expressao?: ExpressaoDoMascote;
42
+ /** Vetor: acessório + objeto de uma data (`natal`, `pascoa`...). */
43
+ tema?: TemaDoMascote;
44
+ acessorio?: AcessorioDoMascote;
45
+ objeto?: ObjetoDoMascote;
46
+ /** Vetor: frase no balão. Também entra no rótulo acessível. */
47
+ fala?: string;
48
+ /** Vetor: `auto` segue o tema do app; `clara`/`escura` travam (ex.: painel sempre branco). */
49
+ superficie?: keyof typeof SUPERFICIE;
27
50
  className?: string;
28
51
  };
29
52
  /**
30
- * O personagem do agente na grade 8x8 da marca, com o estado em ponto + texto.
31
- * Animação em degraus (bob, piscar, pulso do verde); com menos movimento, para.
53
+ * O personagem do agente, com o estado em ponto + texto. Em pixel, anima em
54
+ * degraus; em vetor, olha o cursor e muda de olhar e movimento por estado.
55
+ * Com menos movimento, para.
32
56
  */
33
- export declare function AgenteMascote({ agente, nome, estado, selo, celula, mostrarEstado, className, }: AgenteMascoteProps): import("react").JSX.Element;
57
+ export declare function AgenteMascote({ agente, nome, estado, selo, celula, mostrarEstado, estilo, tamanho, expressao, tema, acessorio, objeto, fala, superficie, className, }: AgenteMascoteProps): import("react").JSX.Element;
34
58
  export {};
@@ -1,7 +1,7 @@
1
1
  import { default as React } from 'react';
2
- import { ChaveDoMascote, EstadoDoMascote } from './AgenteMascote';
2
+ import { ChaveDoAgente, EstadoDoMascote } from './AgenteMascote';
3
3
  export type AgenteDaEquipe = {
4
- chave: ChaveDoMascote;
4
+ chave: ChaveDoAgente;
5
5
  nome: string;
6
6
  estado?: EstadoDoMascote;
7
7
  selo?: number;
@@ -14,10 +14,12 @@ export type EquipeDockProps = {
14
14
  abertoInicial?: boolean;
15
15
  /** Título do painel. Padrão: "Equipe". */
16
16
  titulo?: string;
17
+ /** `pixel` (padrão) ou `vetor`, para todos os mascotes do dock. */
18
+ estilo?: 'pixel' | 'vetor';
17
19
  className?: string;
18
20
  };
19
21
  /**
20
22
  * A equipe de agentes num canto da tela: botão com o mascote principal e o selo
21
23
  * de pendências somado; abre um painel com uma aba por agente.
22
24
  */
23
- export declare function EquipeDock({ agentes, abertoInicial, titulo, className }: EquipeDockProps): React.JSX.Element | null;
25
+ export declare function EquipeDock({ agentes, abertoInicial, titulo, estilo, className }: EquipeDockProps): React.JSX.Element | null;
@@ -0,0 +1,188 @@
1
+ import { default as React } from 'react';
2
+ declare const AGENTES: {
3
+ desk: {
4
+ topo: number;
5
+ apoio: [number, number];
6
+ olhos: {
7
+ l: number;
8
+ r: number;
9
+ y: number;
10
+ };
11
+ corpo: React.JSX.Element;
12
+ verde: React.JSX.Element;
13
+ };
14
+ pergunte: {
15
+ topo: number;
16
+ apoio: [number, number];
17
+ olhos: {
18
+ l: number;
19
+ r: number;
20
+ y: number;
21
+ };
22
+ corpo: React.JSX.Element;
23
+ verde: React.JSX.Element;
24
+ };
25
+ pm: {
26
+ topo: number;
27
+ apoio: [number, number];
28
+ olhos: {
29
+ l: number;
30
+ r: number;
31
+ y: number;
32
+ };
33
+ corpo: React.JSX.Element;
34
+ verde: React.JSX.Element;
35
+ };
36
+ diretor: {
37
+ topo: number;
38
+ apoio: [number, number];
39
+ olhos: {
40
+ l: number;
41
+ r: number;
42
+ y: number;
43
+ };
44
+ lente: true;
45
+ corpo: React.JSX.Element;
46
+ verde: React.JSX.Element;
47
+ };
48
+ sdr: {
49
+ topo: number;
50
+ apoio: [number, number];
51
+ olhos: {
52
+ l: number;
53
+ r: number;
54
+ y: number;
55
+ };
56
+ corpo: React.JSX.Element;
57
+ verde: React.JSX.Element;
58
+ };
59
+ cred: {
60
+ topo: number;
61
+ apoio: [number, number];
62
+ olhos: {
63
+ l: number;
64
+ r: number;
65
+ y: number;
66
+ };
67
+ corpo: React.JSX.Element;
68
+ verde: React.JSX.Element;
69
+ };
70
+ score: {
71
+ topo: number;
72
+ apoio: [number, number];
73
+ olhos: {
74
+ l: number;
75
+ r: number;
76
+ y: number;
77
+ };
78
+ corpo: React.JSX.Element;
79
+ verde: React.JSX.Element;
80
+ };
81
+ pilot: {
82
+ topo: number;
83
+ apoio: [number, number];
84
+ olhos: {
85
+ l: number;
86
+ r: number;
87
+ y: number;
88
+ };
89
+ corpo: React.JSX.Element;
90
+ verde: React.JSX.Element;
91
+ };
92
+ flow: {
93
+ topo: number;
94
+ apoio: [number, number];
95
+ olhos: {
96
+ l: number;
97
+ r: number;
98
+ y: number;
99
+ };
100
+ corpo: React.JSX.Element;
101
+ verde: React.JSX.Element;
102
+ };
103
+ bi: {
104
+ topo: number;
105
+ apoio: [number, number];
106
+ olhos: {
107
+ l: number;
108
+ r: number;
109
+ y: number;
110
+ };
111
+ corpo: React.JSX.Element;
112
+ verde: React.JSX.Element;
113
+ };
114
+ rh: {
115
+ topo: number;
116
+ apoio: [number, number];
117
+ olhos: {
118
+ l: number;
119
+ r: number;
120
+ y: number;
121
+ };
122
+ corpo: React.JSX.Element;
123
+ verde: React.JSX.Element;
124
+ };
125
+ };
126
+ export type ChaveDoAgenteVetor = keyof typeof AGENTES;
127
+ /** Expressão só nos olhos: formato, pálpebra e pupila, por lado. */
128
+ declare const EXPRESSOES: {
129
+ neutro: ["aberto", "aberto"];
130
+ feliz: ["feliz", "feliz"];
131
+ piscando: ["aberto", "feliz"];
132
+ surpreso: ["grande", "grande"];
133
+ bravo: ["bravo", "bravo"];
134
+ triste: ["triste", "triste"];
135
+ desconfiado: ["meio", "meio"];
136
+ sonolento: ["fechado", "fechado"];
137
+ tonto: ["x", "x"];
138
+ };
139
+ export type ExpressaoDoMascote = keyof typeof EXPRESSOES;
140
+ /** Pose do vetor: o movimento, o olhar padrão e os enfeites de cada estado. */
141
+ export type PoseDoMascote = 'parado' | 'cumprimentando' | 'pensando' | 'falando' | 'esperando' | 'comemorando' | 'erro' | 'dormindo';
142
+ /** Desenhados com o topo da cabeça em (0, 0). Só em tinta (exceto o gorro): o verde é do agente. */
143
+ declare const ACESSORIOS: {
144
+ gorro: React.JSX.Element;
145
+ orelhas: React.JSX.Element;
146
+ festa: React.JSX.Element;
147
+ bruxa: React.JSX.Element;
148
+ bone: React.JSX.Element;
149
+ capacete: React.JSX.Element;
150
+ coroa: React.JSX.Element;
151
+ };
152
+ export type AcessorioDoMascote = keyof typeof ACESSORIOS;
153
+ /** Desenhados com o canto de apoio em (0, 0), encostados no lado direito do corpo. */
154
+ declare const OBJETOS: {
155
+ presente: React.JSX.Element;
156
+ ovo: React.JSX.Element;
157
+ bolo: React.JSX.Element;
158
+ abobora: React.JSX.Element;
159
+ bola: React.JSX.Element;
160
+ sabre: React.JSX.Element;
161
+ trofeu: React.JSX.Element;
162
+ };
163
+ export type ObjetoDoMascote = keyof typeof OBJETOS;
164
+ /** Tema = acessório + objeto num nome só. */
165
+ declare const TEMAS: {
166
+ natal: ["gorro", "presente"];
167
+ pascoa: ["orelhas", "ovo"];
168
+ aniversario: ["festa", "bolo"];
169
+ halloween: ["bruxa", "abobora"];
170
+ copa: ["bone", "bola"];
171
+ galaxia: ["capacete", "sabre"];
172
+ premiacao: ["coroa", "trofeu"];
173
+ };
174
+ export type TemaDoMascote = keyof typeof TEMAS;
175
+ export type MascoteVetorProps = {
176
+ agente: ChaveDoAgenteVetor;
177
+ pose: PoseDoMascote;
178
+ expressao?: ExpressaoDoMascote;
179
+ tema?: TemaDoMascote;
180
+ acessorio?: AcessorioDoMascote;
181
+ objeto?: ObjetoDoMascote;
182
+ fala?: string;
183
+ /** Abaixo de 48px o balão some (no dock, por exemplo); a fala segue no rótulo acessível. */
184
+ tamanho: number;
185
+ };
186
+ /** Só o desenho; rótulo acessível, selo e estado ficam no `AgenteMascote`. */
187
+ export declare function MascoteVetor({ agente, pose, expressao, tema, acessorio, objeto, fala, tamanho }: MascoteVetorProps): React.JSX.Element;
188
+ export {};
@@ -0,0 +1,86 @@
1
+ import { default as React } from 'react';
2
+ /**
3
+ * A marca do cliente em variáveis CSS. Os componentes que leem `--tailor-marca-*`
4
+ * (por enquanto o `TailorPageHeader`) trocam de cor, fonte e cantos sem mudar uma
5
+ * linha de componente. Sem tema, valem os padrões Tailor do `style.css`.
6
+ */
7
+ export type TailorTema = {
8
+ /** Cor de destaque: o ponto do sobretítulo, a barra de foco. */
9
+ primaria?: string;
10
+ /** Destaque como texto sobre o fundo (precisa de contraste; no Tailor é o verde-ink). */
11
+ primariaTexto?: string;
12
+ texto?: string;
13
+ textoSuave?: string;
14
+ borda?: string;
15
+ /** Fundo do cabeçalho. Padrão: transparente (o cabeçalho é o começo da página). */
16
+ fundo?: string;
17
+ fonteTitulo?: string;
18
+ fonteTexto?: string;
19
+ pesoTitulo?: string | number;
20
+ /** `uppercase` para marcas que pedem título em caixa alta. */
21
+ caixaTitulo?: 'none' | 'uppercase';
22
+ /** Cantos dos elementos com caixa (etiqueta, botão voltar). Tailor: 0. */
23
+ raio?: string;
24
+ };
25
+ /** O tema como objeto de variáveis, para `style` ou para montar um CSS do cliente. */
26
+ export declare function temaParaVariaveis(tema: TailorTema): Record<string, string>;
27
+ export type TailorMarcaProps = {
28
+ tema: TailorTema;
29
+ /** Ajustes do tema escuro (`.dark` ou `[data-theme="dark"]` num ancestral). */
30
+ escuro?: TailorTema;
31
+ children: React.ReactNode;
32
+ };
33
+ /**
34
+ * Aplica o tema a tudo que estiver dentro, sem mexer no layout (`display: contents`).
35
+ * As variáveis vão num `<style>` com seletor próprio, e não em `style`, para o
36
+ * tema escuro conseguir sobrescrever as do claro.
37
+ */
38
+ export declare function TailorMarca({ tema, escuro, children }: TailorMarcaProps): React.JSX.Element;
39
+ /**
40
+ * `account_info.whitelabel` do cliente (Mongo `clients`). Os campos além de
41
+ * `colors.primary/secondary/background/text` e `logos.*` são a proposta para
42
+ * completar a marca; enquanto não existirem, ficam os padrões Tailor.
43
+ */
44
+ export type WhitelabelDoCliente = {
45
+ colors?: {
46
+ primary?: string;
47
+ secondary?: string;
48
+ background?: string;
49
+ text?: string;
50
+ text_muted?: string;
51
+ border?: string;
52
+ dark?: {
53
+ primary?: string;
54
+ background?: string;
55
+ text?: string;
56
+ text_muted?: string;
57
+ border?: string;
58
+ };
59
+ };
60
+ fonts?: {
61
+ heading?: string;
62
+ body?: string;
63
+ heading_weight?: number | string;
64
+ heading_case?: 'none' | 'uppercase';
65
+ };
66
+ shape?: {
67
+ radius?: string;
68
+ };
69
+ logos?: {
70
+ rectangular_light?: string;
71
+ rectangular_dark?: string;
72
+ square_light?: string;
73
+ square_dark?: string;
74
+ };
75
+ };
76
+ /** Razão de contraste WCAG entre duas cores hex. */
77
+ export declare function contraste(a: string, b: string): number;
78
+ /**
79
+ * Traduz o whitelabel do Mongo para o tema. Ignora o azul padrão do cadastro e
80
+ * valores que não são hex. A primária só vira cor de texto se tiver contraste
81
+ * AA sobre o fundo; senão o texto de destaque usa a cor de texto da marca.
82
+ */
83
+ export declare function temaDoWhitelabel(wl?: WhitelabelDoCliente | null): {
84
+ tema: TailorTema;
85
+ escuro?: TailorTema;
86
+ };
@@ -0,0 +1,47 @@
1
+ import { default as React } from 'react';
2
+ export type TailorPageHeaderLink = {
3
+ href: string;
4
+ className: string;
5
+ children: React.ReactNode;
6
+ 'aria-current'?: 'page';
7
+ };
8
+ export type TailorPageHeaderProps = {
9
+ /** ReactNode para permitir um acento dentro do título. */
10
+ titulo: React.ReactNode;
11
+ /** Uma frase: o que se faz nesta tela. */
12
+ descricao?: React.ReactNode;
13
+ /** Seção ou contexto, com o ponto da marca. Sem ele, não aparece. */
14
+ sobretitulo?: string;
15
+ /** Trilha de navegação; o último item é a página atual. */
16
+ trilha?: Array<{
17
+ rotulo: string;
18
+ href?: string;
19
+ }>;
20
+ /** Link ou ação de voltar, acima de tudo. */
21
+ voltar?: {
22
+ rotulo: string;
23
+ href?: string;
24
+ onClick?: () => void;
25
+ };
26
+ /** Ao lado do título: status, plano, contagem. */
27
+ etiqueta?: React.ReactNode;
28
+ /** Números do topo, quando ajudam a decidir o que fazer aqui. */
29
+ indicadores?: Array<{
30
+ rotulo: string;
31
+ valor: React.ReactNode;
32
+ }>;
33
+ /** Botões e busca, à direita. */
34
+ acoes?: React.ReactNode;
35
+ /** Abaixo, na largura toda: abas, filtros, barra de busca. */
36
+ children?: React.ReactNode;
37
+ /** Link do roteador do app (ex.: `NavLink`). Repasse todas as props. Sem ele, sai um `<a href>`. */
38
+ renderLink?: (props: TailorPageHeaderLink) => React.ReactNode;
39
+ className?: string;
40
+ };
41
+ /**
42
+ * O cabeçalho de página. Visual só por variáveis `--tailor-marca-*` e
43
+ * `--tailor-cabecalho-*` (ver `TailorMarca`), para vestir a marca do cliente:
44
+ * cor de destaque, fontes, peso e caixa do título, cantos, fundo.
45
+ * Padrão Tailor: sem card nem sombra, régua de 1px embaixo, título 26 → 42.
46
+ */
47
+ export declare function TailorPageHeader({ titulo, descricao, sobretitulo, trilha, voltar, etiqueta, indicadores, acoes, children, renderLink, className, }: TailorPageHeaderProps): React.JSX.Element;
@@ -12,6 +12,11 @@ export { logoTailor, logoTailorBranco } from './logos';
12
12
  export { TailorSidebar, SidebarGroup, SidebarItem, TailorUserMenu, TailorMobileBar } from './components/TailorSidebar';
13
13
  export type { TailorSidebarProps, TailorSidebarItem, TailorSidebarGrupo, TailorSidebarLinkProps, TailorSidebarRenderLink, SuperficieSidebar, BreakpointSidebar, SidebarGroupProps, SidebarItemProps, TailorUserMenuProps, TailorUserMenuAcao, TailorMobileBarProps, } from './components/TailorSidebar';
14
14
  export { AgenteMascote, ROTULO_DO_ESTADO } from './components/AgenteMascote';
15
- export type { AgenteMascoteProps, ChaveDoMascote, EstadoDoMascote } from './components/AgenteMascote';
15
+ export type { AgenteMascoteProps, ChaveDoMascote, ChaveDoAgente, EstadoDoMascote } from './components/AgenteMascote';
16
+ export type { ExpressaoDoMascote, TemaDoMascote, AcessorioDoMascote, ObjetoDoMascote, } from './components/MascoteVetor';
16
17
  export { EquipeDock } from './components/EquipeDock';
17
18
  export type { EquipeDockProps, AgenteDaEquipe } from './components/EquipeDock';
19
+ export { TailorPageHeader } from './components/TailorPageHeader';
20
+ export type { TailorPageHeaderProps, TailorPageHeaderLink } from './components/TailorPageHeader';
21
+ export { TailorMarca, temaParaVariaveis, temaDoWhitelabel, contraste } from './components/TailorMarca';
22
+ export type { TailorMarcaProps, TailorTema, WhitelabelDoCliente } from './components/TailorMarca';
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@ffid-br/tailor-ui",
3
3
  "private": false,
4
- "version": "0.4.0",
4
+ "version": "0.6.0",
5
5
  "description": "Primitivos de marca Tailor.ia em React: loader, intro, transição de login, lockup e barra lateral.",
6
6
  "type": "module",
7
7
  "main": "dist/index.umd.js",
@@ -32,7 +32,8 @@
32
32
  "typecheck": "tsc --noEmit",
33
33
  "test": "vitest run",
34
34
  "test:watch": "vitest",
35
- "prepublishOnly": "npm run build"
35
+ "prepublishOnly": "npm run build",
36
+ "exemplos": "vite exemplos --config exemplos/vite.config.ts"
36
37
  },
37
38
  "peerDependencies": {
38
39
  "framer-motion": "^10.0.0 || ^11.0.0 || ^12.0.0",
@@ -40,6 +41,7 @@
40
41
  "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0"
41
42
  },
42
43
  "devDependencies": {
44
+ "@tailwindcss/vite": "^4.3.3",
43
45
  "@testing-library/jest-dom": "^6.9.1",
44
46
  "@testing-library/react": "^16.3.2",
45
47
  "@types/react": "^18.3.5",
@@ -49,6 +51,7 @@
49
51
  "jsdom": "^29.0.1",
50
52
  "react": "^18.3.1",
51
53
  "react-dom": "^18.3.1",
54
+ "tailwindcss": "^4.3.3",
52
55
  "typescript": "^5.5.3",
53
56
  "vite": "^5.4.2",
54
57
  "vite-plugin-dts": "^4.5.3",