@ffid-br/tailor-ui 0.1.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/README.md ADDED
@@ -0,0 +1,144 @@
1
+ # @ffid-br/tailor-ui
2
+
3
+ Primitivos de marca da Tailor.ia em React: a fita métrica de carregamento, a abertura cinematográfica, o ponto com a malha Fibonacci, a transição login → app e o lockup do produto. Antes, cada app mantinha uma cópia desses componentes. Agora todos vêm deste pacote.
4
+
5
+ ## Instalação
6
+
7
+ ```bash
8
+ npm install @ffid-br/tailor-ui
9
+ ```
10
+
11
+ Dependências de pares (peer): `react`, `react-dom` e `framer-motion` (10, 11 ou 12). Na prática o framer-motion 10+ exige React 18.
12
+
13
+ ## Configuração no app (Tailwind v4)
14
+
15
+ No CSS de entrada do app, logo depois de `@import "tailwindcss";`:
16
+
17
+ ```css
18
+ @import "tailwindcss";
19
+ @import "@ffid-br/tailor-ui/theme.css"; /* tokens: tailor-green, tailor-ink, font-tailor... */
20
+ @import "@ffid-br/tailor-ui/style.css"; /* animações: fita, ponto, entrada */
21
+ @source "../node_modules/@ffid-br/tailor-ui/dist";
22
+ ```
23
+
24
+ - `theme.css` é um bloco `@theme` que cria as classes nomeadas (`bg-tailor-green`, `text-tailor-ink`, `fill-tailor-green`, `font-tailor`, `font-tailor-num`). Se o app já define esses tokens, pode pular esta linha.
25
+ - `style.css` traz só os tokens como variáveis CSS (`--tailor-green`...) e os keyframes dos componentes, todos respeitando `prefers-reduced-motion`.
26
+ - `@source` faz o Tailwind do app ler as classes usadas nos componentes. O caminho é relativo ao arquivo CSS: ajuste se ele não estiver em `src/`.
27
+
28
+ A fonte Raleway (e a Roboto, para números) é carregada pelo app.
29
+
30
+ ## Componentes
31
+
32
+ ### `TailorLoader`
33
+
34
+ ```tsx
35
+ <TailorLoader /> {/* inline: "Tirando as medidas..." */}
36
+ <TailorLoader variant="overlay" label="Entrando" /> {/* tela inteira, bloqueia a interação */}
37
+ <TailorLoader variant="compact" label="Salvando" /> {/* uma linha, para botão ou célula */}
38
+ <TailorLoader detail="3 de 5 contas" />
39
+ ```
40
+
41
+ Sempre expõe `role="status"` com o rótulo.
42
+
43
+ ### `CinematicIntro`
44
+
45
+ ```tsx
46
+ <AnimatePresence>
47
+ {mostrarIntro && (
48
+ <CinematicIntro
49
+ onComplete={() => setMostrarIntro(false)}
50
+ produto="Pilot" // opcional, aparece abaixo da marca
51
+ overline="Alfaiataria digital"
52
+ slogan="Tecnologia sob medida para a sua operação"
53
+ skipLabel="Pular"
54
+ />
55
+ )}
56
+ </AnimatePresence>
57
+ ```
58
+
59
+ Se o usuário pediu menos movimento, chama `onComplete` na hora e não renderiza nada. `logo` troca o wordmark (whitelabel).
60
+
61
+ ### `PontoMalha`
62
+
63
+ O ponto verde piscando com a malha Fibonacci. Ocupa o contêiner posicionado mais próximo e o fundo preto fica por conta de quem usa. `malha={false}` mostra só o ponto.
64
+
65
+ ```tsx
66
+ <div className="relative h-[377px] bg-black"><PontoMalha /></div>
67
+ ```
68
+
69
+ ### `TailorBrandMark`
70
+
71
+ Lockup: wordmark com 21px de arte e o nome do produto em 18px semibold (tailor-ink no claro, branco no escuro). As logos padrão já vêm embutidas no pacote, então nada precisa ser copiado para o `public/`.
72
+
73
+ ```tsx
74
+ <TailorBrandMark produto="Conta" />
75
+ <TailorBrandMark produto="Conta" compact /> {/* barra recolhida: só a palavra */}
76
+ <TailorBrandMark produto="Conta" onDark /> {/* menu sempre preto, independe do tema */}
77
+ <TailorBrandMark produto="Pilot" logoClaro={cliente.logo} logoEscuro={cliente.logoBranca} />
78
+ ```
79
+
80
+ `logoTailor` e `logoTailorBranco` também são exportados (data URI) para outros usos.
81
+
82
+ ## Receita: transição login → app
83
+
84
+ 1. **No login**: marque a entrada ao enviar, desmarque se der erro e mostre o preto crescendo do botão.
85
+
86
+ ```tsx
87
+ import { EntrarOverlay, marcarEntradaPendente, limparEntradaPendente } from '@ffid-br/tailor-ui';
88
+
89
+ const botaoRef = useRef<HTMLButtonElement>(null);
90
+
91
+ async function entrar(e: React.FormEvent) {
92
+ e.preventDefault();
93
+ setEntrando(true);
94
+ marcarEntradaPendente();
95
+ try {
96
+ await login(email, senha);
97
+ navigate('/'); // o preto continua na EntradaApp
98
+ } catch {
99
+ limparEntradaPendente();
100
+ setEntrando(false); // o círculo recolhe
101
+ }
102
+ }
103
+
104
+ return (
105
+ <>
106
+ <EntrarOverlay ativo={entrando} origemRef={botaoRef} />
107
+ <form onSubmit={entrar}>
108
+ ...
109
+ <button ref={botaoRef} type="submit">Entrar</button>
110
+ </form>
111
+ </>
112
+ );
113
+ ```
114
+
115
+ 2. **No layout logado**: monte a `EntradaApp` uma vez e marque o contêiner cujos filhos devem entrar em sequência.
116
+
117
+ ```tsx
118
+ import { EntradaApp } from '@ffid-br/tailor-ui';
119
+
120
+ <>
121
+ <EntradaApp />
122
+ <main>
123
+ <div data-tailor-entrada-alvo className="grid ...">
124
+ <Card /> <Card /> <Card />
125
+ </div>
126
+ </main>
127
+ </>
128
+ ```
129
+
130
+ A `EntradaApp` aparece quando há entrada pendente (`sessionStorage['tailor_entrada_pendente']`) ou na primeira visita da aba. São 1,618s de preto com o ponto piscando e 0,618s recolhendo de baixo para cima. Durante esse tempo, `<html data-entrada>` faz os filhos de `[data-tailor-entrada-alvo]` subirem 21px, um depois do outro. Com menos movimento, o app aparece direto.
131
+
132
+ ## Por que não embutimos Tailwind
133
+
134
+ O `style.css` deste pacote não traz preflight nem utilitários do Tailwind, e isso é proposital. No `account-selector-component` o CSS publicado levava um build inteiro do Tailwind. Esse CSS carregava depois do CSS do app, então os utilitários do pacote venciam os responsivos do host (`.hidden` derrubava `lg:flex`), redefiniam tokens e o preflight resetava a página (ver [ffid-br/account-selector-component#2](https://github.com/ffid-br/account-selector-component/issues/2)). Aqui os componentes só usam classes, e quem gera o CSS delas é o Tailwind do próprio app, via `@source`. Assim existe uma única versão do Tailwind na página.
135
+
136
+ Cores só por tokens nomeados (`tailor-green`, `tailor-ink`, `black`, `white`, `neutral-*`). Nada de `[#hex]`.
137
+
138
+ ## Desenvolvimento
139
+
140
+ ```bash
141
+ npm install
142
+ npm test # vitest + testing-library
143
+ npm run build # dist/: index.es.js, index.umd.js, types/, style.css, theme.css, logos
144
+ ```