@poly-ds/theme-manager
v0.2.3
Published
Runtime de temas: os 3 eixos, persistencia, matchMedia e o snippet anti-FOUC. TS puro, zero dependencia.
Maintainers
Readme
@poly-ds/theme-manager
Runtime de temas: os tres eixos, persistencia, matchMedia, escritores externos e o
snippet anti-FOUC. TypeScript puro, zero dependencia, sem tocar o DOM no import.
O guia de integracao — o que instalar e em que ordem — esta em
docs/TROCANDO-DE-TEMA.md. Este arquivo e a
referencia da API.
API
const manager = createThemeManager({
themes, // obrigatorio: lista de marcas (use THEMES de @poly-ds/tokens)
defaultTheme, // default: themes[0]
defaultScheme, // default: 'system'
defaultDensity, // default: 'comfortable'
storageKey, // default: 'poly-ds-theme'
root, // default: document.documentElement — `null` para headless/SSR
disableTransitions, // default: true
persist, // default: true
});| Metodo | |
| --- | --- |
| getState() | Estado atual. Referencia estavel entre mudancas — useSyncExternalStore exige. |
| setTheme / setScheme / setDensity | Muda um eixo e persiste. |
| toggleScheme() | Alterna a partir do que esta na tela (system resolvido como escuro vai para light). |
| cycleTheme() | Proxima marca de themes, circular. |
| subscribe(fn) | Notifica a cada mudanca. Devolve o cancelador. |
| applyTo(el) | Espelha os eixos num elemento alem do root, agora e depois. Devolve o disposer. |
| destroy() | Solta listeners, observer e espelhos. |
inlineScript(options): string // o snippet, ~506 B
inlineScriptTag(options): string // ja embrulhado em <script>
dsThemeScript(options) // plugin de bundler, em '@poly-ds/theme-manager/bundler'Passe o mesmo objeto de opcoes para createThemeManager e para o snippet. Os
defaults sao resolvidos pela mesma funcao (resolveDefaults), e um teste roda os
dois contra o mesmo localStorage e falha se os atributos divergirem.
Como isto e testado
tests/ roda em happy-dom, e nao num DOM de mentira escrito a mao. Tres APIs
aqui tem semantica sutil — MutationObserver (callback em microtask), matchMedia
(MediaQueryList com evento) e localStorage (que pode lancar so de ser acessado) —
e um duble caseiro de MutationObserver seria sincrono. O teste passaria por um
comportamento que o browser nao tem, que e o pior resultado possivel.
O que happy-dom nao cobre — ordem de flush de estilo, primeiro paint, o SO mudando de
verdade — esta em e2e/specs/theme-runtime.spec.ts, em Chromium, nos tres
frameworks.
Os dois testes que justificam o pacote:
- equivalencia snippet ↔ manager (
tests/inline-script.test.ts): as duas implementacoes recebem o mesmolocalStoragee tem que aplicar os mesmos atributos. Sem ele, um rename de campo viraria um flash no carregamento em vez de um erro. - sem flash no primeiro paint (e2e): cada escrita nos eixos e gravada com o
document.readyStatedo momento. A primeira tem que acontecer emloading— ou seja, durante o parse do<head>, antes do primeiro paint.
Os dois foram verificados por quebra deliberada: sem o snippet o segundo falha com
readyState: "interactive"; com um campo renomeado, o primeiro falha em 6 casos.
