@chrono-os/ui-shared
v0.12.0
Published
Componentes React + utilitários compartilhados (WhatsAppFab, Header, Footer, apiFetch, captureAttribution, tokens Tailwind) para projetos Chrono/Naírio
Readme
@chrono-os/ui-shared
Componentes React + utilitários compartilhados (WhatsAppFab, Header, Footer, apiFetch, captureAttribution, tokens Tailwind) para projetos Chrono/Naírio.
Status atual: Fase 2 ✅ ·
0.5.0publicado no npmjs.org/@chrono-os (registro público) · plano em Naírio/Plan/2026-05-24_modulo-ui-shared.md
Install
Registro público no npmjs.org — não precisa de auth nem .npmrc.
yarn add @chrono-os/ui-shared(Opcional) Se quiser pinar explicitamente o scope ao registry público, crie .npmrc na raiz do projeto:
@chrono-os:registry=https://registry.npmjs.org/Uso
import { formatWhatsAppLink } from "@chrono-os/ui-shared";
const url = formatWhatsAppLink("+55 51 99999-9999", "Olá Naírio");Client HTTP
// Server Component ou client: o entry /api não puxa React.
import { createApiFetch, ApiError } from "@chrono-os/ui-shared/api";
export const apiFetch = createApiFetch(() => process.env.NEXT_PUBLIC_API_URL ?? "", {
credentials: "include",
// Opcional: header calculado a cada request.
getHeaders: (path) => (path.startsWith("/admin") ? { "X-Property": lerProperty() } : undefined),
// Opcional: efeito colateral e/ou troca do erro lançado.
onError: (err, { response, data }) => {
if (err.status === 401) guardarRotaAtual();
// devolver um Error o lança no lugar; não devolver nada lança `err`.
},
});
try {
await apiFetch<Lead>("/leads", { method: "POST", body: JSON.stringify(lead) });
} catch (err) {
if (err instanceof ApiError) console.log(err.status, err.code, err.message, err.details);
}Em resposta !ok lança ApiError(status, code, message, details) com code/message/details vindos de { error, message, details } do backend (fallback UNKNOWN_ERROR / Erro desconhecido). Content-Type JSON só quando há body; cache: 'no-store' por default.
Atribuição de campanha
import { captureAttribution, getAttribution, ATTRIBUTION_FULL } from "@chrono-os/ui-shared";
// No pouso (layout/LP): first-touch da sessão.
captureAttribution("lp:doacao-imoveis", ATTRIBUTION_FULL);
// No envio do lead:
const payload = { email, ...getAttribution(ATTRIBUTION_FULL) };Sem o segundo argumento, o comportamento é o de sempre: origem + 5 utm_* em sessionStorage (attribution_v1), nada entre sessões. Cada extensão é uma flag de AttributionOptions (clickIds, utmId, sessionId, landing, persist, urlFallback, metaCookies); ATTRIBUTION_FULL liga todas. Passe o mesmo objeto nas duas chamadas.
Com persist, a regra é: first-touch dentro da sessão; entre sessões, o clique novo vence campo a campo e o salvo (localStorage, 30 dias em janela rolante) só preenche lacuna; landingPage acompanha o clique. persist e metaCookies gravam/leem dado de campanha entre sessões — o consentimento é decisão do consumidor. Detalhes no topo de src/tracking/attribution.ts.
Tailwind preset
Importe o preset no tailwind.config.ts do consumer:
import type { Config } from "tailwindcss";
import { tailwindPreset } from "@chrono-os/ui-shared/tailwind";
const config: Config = {
presets: [tailwindPreset],
content: ["./app/**/*.{ts,tsx}", "./components/**/*.{ts,tsx}"],
};
export default config;O preset registra cores via CSS vars (var(--brand-navy), etc. — consumer carrega brand-tokens.css) + 2 classes utilitárias prontas:
| Classe | Equivalente | O que faz |
|---|---|---|
| container-page | mx-auto max-w-[1240px] px-8 | Wrapper de página com 1240px máximo e padding lateral 32px. Sobrescreva o limite via --max-w-container no globals.css. |
| section-pad | py-24 md:py-32 | Spacing vertical canônico de seções marketing — 96px mobile / 128px md+. |
Use direto no JSX:
<section className="section-pad bg-surface-dark">
<div className="container-page">{children}</div>
</section>Roadmap
| Fase | Conteúdo | ETA | |---|---|---| | 0 | Estrutura + CI + 0.1.0 stub | 2026-05-31 ✅ | | 1 | Utilitários (apiFetch, captureAttribution, formatWhatsAppLink) | 2026-06-14 ✅ | | 2 | Componentes visuais (WhatsAppFab, Header, Footer) + tokens Tailwind | 2026-07-05 ✅ | | 3 | Release 1.0 estável + docs parceiros | 2026-08-22 |
Versionamento
SemVer. Releases via tag vX.Y.Z no main. Ver CHANGELOG.md.
Desenvolvimento
yarn install
yarn dev # tsup --watch
yarn test # vitest
yarn typecheck
yarn build