Pular para o conteúdo
// visualizar em
salvo em todas as páginas

Estilos e troca

Treze linguagens visuais completas sobre os mesmos componentes. Carregue o CSS, envolva o app num StyleProvider e troque uma palavra para mudar tudo.

// você vai aprender

  • Quais arquivos CSS e fontes cada um dos 13 estilos precisa
  • O que styleName, mode e brand fazem, e quais deles são herdados
  • Como aninhar estilos e trocá-los em tempo de execução sem perder estado

Experimente

Escreva na nota, curta algumas vezes e escolha outro estilo. Os componentes renderizam de novo com outro CSS; nada é montado outra vez, então o texto e a contagem continuam.

minimal · light · #3fa34d

Resumo semanal

Curtidas: 3

Importe o CSS

O base.css traz os tokens, as regras dos componentes e a ordem das camadas. Importe uma vez e depois um arquivo para cada estilo que você usa. O minimal é o padrão e não precisa de arquivo próprio.

app/layout.tsx
import "@camaleo/styles/base.css";
import "@camaleo/styles/neubrutalism.css";
import "@camaleo/styles/editorial.css";
DICA

Se as pessoas podem escolher o estilo, importe de antemão todos os estilos que você oferece. Um estilo sem o arquivo cai nos padrões do minimal, sem nenhum erro.

Carregue as fontes

As fontes não vêm junto. Cada estilo nomeia as famílias dele nos tokens --cml-font-*, com fallbacks do sistema, então funciona mesmo sem elas, só que menos parecido consigo mesmo. Carregue só as dos estilos que você publica:

EstiloFontes
minimalInter
swissArchivo
editorialNewsreader (texto), Fraunces (títulos), Inter (controles e rótulos)
progressiveFigtree
materialRoboto Flex
cupertinoInter
glassPlus Jakarta Sans
neumorphismManrope
clayNunito, Fredoka (títulos)
neubrutalismSpace Grotesk
retroIBM Plex Sans
retro-pixelPixelify Sans, Press Start 2P (títulos grandes, só latim básico)
y2kExo 2, Audiowide (títulos grandes)

O CSS pede as famílias pelo nome, então uma tag <link> de folha de estilos ou um @font-face hospedado por você funciona do jeito que está. Com next/font, aponte o token para a variável da fonte:

app/fonts.css
/* app/layout.tsx: const grotesk = Space_Grotesk({ subsets: ["latin"], variable: "--font-grotesk" }) */
[data-style="neubrutalism"] {
  --cml-font-body: var(--font-grotesk), system-ui, sans-serif;
}

Envolva o app

O StyleProvider renderiza uma <div> com data-style, data-mode e os tokens da marca inline. Tudo dentro dele, inclusive diálogos e menus renderizados num portal, recebe o estilo.

app/providers.tsx
import { StyleProvider } from "@camaleo/react";

export function Providers({ children }: { children: React.ReactNode }) {
  return (
    <StyleProvider styleName="neubrutalism" mode="system" brand="#3fa34d">
      {children}
    </StyleProvider>
  );
}
PropValoresHerda de um provider pai?
styleNameUm dos 13 nomes; minimal por padrãoNão: um provider aninhado sem ela é minimal
modelight, dark ou systemSim, quando omitida (a raiz segue o sistema)
brandQualquer cor CSSSim, quando omitida

Os 13 estilos

Todo estilo renderiza o mesmo DOM: o teste de matriz compara o markup dos 13 e falha se um for diferente. Só o CSS muda, e é por isso que a troca sai barata.

EstiloEm uma linha
minimalNeutro e discreto, os padrões de onde todo outro estilo parte
swissUma grotesca, linhas de 1px em tinta, cantos retos, sem sombras
editorialPapel, tinta e filetes finos, com serifas de revista
progressiveCara de app instalável: fundo cinza quente, áreas de toque de 44px
materialSuperfícies tonais, botões em pílula, campos preenchidos e contornados
cupertinoFundo cinza agrupado, células brancas, cantos contínuos
glassCamadas translúcidas foscas sobre um fundo suave e desfocado
neumorphismUma só superfície moldada pela luz: ações em relevo, campos afundados
clayFormas fofas em tons pastel que parecem modeladas em argila
neubrutalismContornos de 2px em tinta e sombras duras, sem desfoque
retroVisual clássico de desktop com chanfros em quatro cores
retro-pixel8 bits: bordas grossas em tinta, cantos em degrau, fontes pixeladas
y2kBotões brilhantes de gelatina, cromado escovado e risca de giz

O material se inspira no Material Design e o cupertino nas Human Interface Guidelines. O Camaleo não tem ligação com o Google nem com a Apple e não usa nenhuma fonte, ícone ou marca registrada deles.

Aninhamento

Um StyleProvider aninhado é uma ilha: todo token é declarado de novo no elemento dele, então ele parte de padrões limpos em vez de se misturar com o pai. O mode e o brand do pai ainda chegam até ele, a não ser que você os defina.

minimal · light · #3fa34d

Seu app, na skin da barra de preview

Uma ilha retro: ela começa dos tokens limpos

Troca em tempo de execução

Guarde o estilo no estado e passe para baixo. Mudar o styleName muda um atributo no mesmo elemento, então o React mantém cada componente e o estado dele. Não coloque o estilo numa key: isso remonta a árvore e zera os formulários.

skin-switcher.tsx
"use client";
import { useState } from "react";
import { STYLE_NAMES, type StyleName, StyleProvider } from "@camaleo/react";

export function App({ children }: { children: React.ReactNode }) {
  const [skin, setSkin] = useState<StyleName>("minimal");
  return (
    <StyleProvider styleName={skin}>
      <select aria-label="Skin" value={skin} onChange={(e) => setSkin(e.target.value as StyleName)}>
        {STYLE_NAMES.map((name) => <option key={name}>{name}</option>)}
      </select>
      {children}
    </StyleProvider>
  );
}

A página inteira, a partir do servidor

Para aplicar o estilo no próprio <html> (fundo da página, barras de rolagem), espalhe styleScopeProps nele. É seguro no servidor, então um layout raiz pode chamá-lo sem um componente de cliente.

app/layout.tsx
import { styleScopeProps } from "@camaleo/react/style-scope";

export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html lang="pt-BR" {...styleScopeProps({ styleName: "editorial", mode: "system" })}>
      <body>{children}</body>
    </html>
  );
}
CUIDADO

Popups renderizam num portal fora da sua árvore. Eles mantêm o estilo pelo contexto do React, então renderize-os dentro de um StyleProvider (ou sob um <html> com styleScopeProps), nunca numa raiz React separada.

Antes de publicar

  • O base.css é importado uma vez, antes dos arquivos dos estilos
  • Há um arquivo CSS para cada estilo que as pessoas podem escolher
  • As fontes desses estilos estão carregadas
  • O estilo fica no estado, nunca numa key
Esta página foi útil? · Editar esta página no GitHub