Sobre

migração v2 para v3

Passo a passo para atualizar sua aplicação da v2 para a v3 do Design System.

A v3 remove as dependências de styled-components e @radix-ui. Os estilos passam a ser distribuídos como arquivos CSS estáticos e o theming acontece via CSS custom properties, aplicadas pelo atributo data-ds-theme.

Esta página cobre todos os breaking changes e o passo a passo da atualização. Para projetos novos, consulte direto a documentação dos componentes e dos tokens.

Migração assistida por agente

O repositório do Design System publica um plugin do Claude Code com uma skill que executa essa migração no seu projeto. Instale o marketplace do repositório e peça ao agente para migrar o projeto para a v3.

# via SSH
/plugin marketplace add [email protected]:frontend-platform/olist-design-system.git

# via HTTPS
/plugin marketplace add https://gitlab.olist.io/frontend-platform/olist-design-system.git

/plugin install migrate-olist-ds-v3

A skill aplica as mudanças mecânicas (versões, imports de CSS, subpaths, deep imports, ajustes de teste), roda typecheck e build, e reporta separadamente o que exige decisão humana, como seletores afetados pelo wrapper do ThemeProviderV2 e layouts responsivos em SSR.

Depois de instalado, peça a migração num prompt:

Migre este projeto do @olist/design-system da v2 para a v3.

Ou apenas cite a skill:

/migrate-olist-ds-v3

Resumo dos breaking changes

MudançaImpacto
styled-components e @radix-ui removidosMenos dependências transitivas; sem ThemeProvider do styled-components
Imports de CSS agora obrigatóriosAdicionar imports na entrada da aplicação
Theming via data-ds-themeTemas não-padrão exigem import de CSS adicional
Brands alpha, beta, rebrand, fbo e vnda removidosMigre para o brand base olist
Brand tiny renomeado para erpTrocar themes.tiny por themes.erp e o CSS do tema
ThemeProviderV2 opcional no tema padrãoCom olist/base, os imports de CSS são suficientes
ThemeProviderV2 renderiza um wrapperPode afetar seletores CSS e testes que dependem da árvore DOM
Chart movido para @olist/design-system/chartAjustar import e instalar peers opcionais
Snapshots de testes mudamCSS do styled-components não é mais serializado

1. Imports de CSS obrigatórios

Os estilos não são mais injetados em runtime. É obrigatório importar os arquivos CSS uma única vez na entrada da aplicação (_app.tsx, main.tsx, index.tsx):

// tokens (variáveis CSS) — sempre obrigatório
import '@olist/design-system-tokens/css/index.css';

// estilos dos componentes — obrigatório se usa @olist/design-system
import '@olist/design-system/styles.css';

// estilos dos templates — obrigatório se usa @olist/templates
import '@olist/templates/dist/styles.css';

O index.css inclui apenas os tokens primitivos e o tema olist/base. Se a aplicação usa outro tema, importe também o CSS dele:

import '@olist/design-system-tokens/css/themes/erp/base.css';

Sem esses imports os componentes renderizam sem estilo nenhum.

2. Configure o bundler para importar CSS

Importar CSS de node_modules não funciona por padrão em todo bundler, e até a v2 o Design System nunca exigiu isso. Ajuste conforme a stack:

webpack (Module Federation, SPAs custom): sem loader de CSS o build quebra com Module parse failed: Unexpected character no primeiro .css.

npm i -D style-loader css-loader
// webpack.config.js — dentro de module.rules
{ test: /\.css$/, use: ['style-loader', 'css-loader'] }

Next.js: import de CSS global só é permitido em pages/_app.tsx ou no root layout do App Router. Vite e CRA: já suportam import de CSS sem configuração extra.

Para verificar, procure as variáveis --ds-* no bundle final (grep -rl "ds-color" dist/). Se não aparecem, o CSS não está sendo incluído.

3. Theming via data-ds-theme

O tema padrão olist/base é declarado em :root, então com os imports de CSS ele não exige provider. Para selecionar outro tema, o ThemeProviderV2 aplica o atributo data-ds-theme="<brand>-<variation>":

import { ThemeProviderV2 } from '@olist/design-system';
import { themes } from '@olist/design-system-tokens';

const App = () => (
  <ThemeProviderV2 theme={themes.erp.base} themeName="erp" variation="base">
    ...
  </ThemeProviderV2>
);

Brands disponíveis: olist, erp e erp-dark. Para qualquer brand diferente de olist, importe o CSS do tema correspondente, como descrito na seção anterior.

Os brands alpha, beta, rebrand, fbo e vnda foram descontinuados nesta major e não existem mais nos pacotes de tokens: quem usava algum deles deve migrar para o brand base olist. O brand tiny foi renomeado para erp (e tiny-dark para erp-dark), então themes.tiny passa a ser themes.erp, themes.tinyDark passa a ser themes.erpDark e o CSS sai de css/themes/tiny/base.css para css/themes/erp/base.css.

O ThemeProviderV2 agora renderiza um elemento div ao redor dos filhos para carregar o atributo. Ele usa display: contents e não afeta o layout, mas existe na árvore DOM: seletores CSS, queries de teste e snapshots que dependiam da estrutura exata podem precisar de ajuste.

4. Aplicações com styled-components próprio

Este é o breaking change mais fácil de passar despercebido. Na v2 o ThemeProviderV2 era, por baixo, o ThemeProvider do styled-components, e isso tinha dois efeitos dos quais muitas aplicações dependiam sem saber: qualquer styled.div da própria aplicação conseguia ler props.theme.olist.*, e o tipo DefaultTheme era estendido para tipar theme.olist.

Na v3 nada disso acontece. Se a aplicação tem styled-components próprio lendo theme.olist.*, o theme chega vazio em runtime e o typecheck acusa Property 'olist' does not exist on type 'DefaultTheme'.

A correção é importar o ThemeProviderV2 do subpath de compatibilidade, que injeta o tema no contexto do styled-components e repõe o augment de tipo:

// antes (v2)
import { ThemeProviderV2 } from '@olist/design-system';
import theme from '@olist/design-system-tokens/themes/olist/base';

export function AppProviders({ children }) {
  return <ThemeProviderV2 theme={theme}>{children}</ThemeProviderV2>;
}

// depois (v3)
import { ThemeProviderV2 } from '@olist/design-system/styled-components';
import theme from '@olist/design-system-tokens/themes/olist/base';

export function AppProviders({ children }) {
  return <ThemeProviderV2 theme={theme}>{children}</ThemeProviderV2>;
}

Use o mesmo import no wrapper de testes para que os testes também recebam o tema. styled-components é uma peer dependency opcional: o subpath só o referencia quando importado, então quem não usa styled-components continua sem a dependência.

Se a aplicação tinha styled-components apenas por causa do Design System, ela pode ser removida:

yarn remove styled-components

5. Deep imports pararam de funcionar

O @olist/design-system passou a declarar o campo exports no package.json. Caminhos internos como @olist/design-system/dist/esm/components/.../Algo.js agora são bloqueados pelo bundler (Package path ./dist/esm/... is not exported), o layout interno do dist mudou por causa dos CSS Modules e alguns símbolos deixaram de existir, como o AccordionChevronIcon.

Migre para a API pública (import { X } from '@olist/design-system') ou, se dependia de primitivas internas não exportadas, internalize uma cópia própria.

6. Chart movido para subpath

// antes (v2)
import { Chart } from '@olist/design-system';

// depois (v3)
import { Chart } from '@olist/design-system/chart';

As dependências dele viraram peer dependencies opcionais, instaladas só por quem usa o componente:

yarn add @mui/x-charts @mui/material @emotion/react @emotion/styled

Quem não usa o Chart deixa de carregar MUI e Emotion no bundle.

7. Objeto de tema

O hook useTheme() continua retornando o shape { olist: tokens }, então o acesso a tokens em JavaScript segue funcionando. Os internals do objeto mudaram (ele não é mais o objeto de tema do styled-components), então código que dependia de propriedades internas ou da identidade do objeto pode precisar de ajuste. Para metadados do tema atual, use o novo hook useDesignSystemTheme(), que expõe { themeName, variation, tokens, theme }.

Os tokens de tema borderRadius.circle e borderRadius.pill deixaram de referenciar os tokens primitivos e passaram a ser os valores literais 50% e 9999px. Quem sobrescrevia esses primitivos esperando que o tema seguisse a referência precisa sobrescrever o token de tema.

8. Testes

Snapshots que serializavam o CSS do styled-components vão mudar, já que os componentes usam classes de CSS Modules e variáveis CSS. Atualize os snapshots e remova serializers como o jest-styled-components.

O Design System trata a ausência de matchMedia no jsdom com fallback para o valor base, então os testes não quebram por isso. Se os seus testes asserem comportamento por breakpoint, mocke window.matchMedia:

// jest.setup.ts
Object.defineProperty(window, 'matchMedia', {
  writable: true,
  value: jest.fn().mockImplementation((query) => ({
    matches: false,
    media: query,
    onchange: null,
    addEventListener: jest.fn(),
    removeEventListener: jest.fn(),
    addListener: jest.fn(),
    removeListener: jest.fn(),
    dispatchEvent: jest.fn(),
  })),
});

9. Alinhe as versões de todos os pacotes

Atualize todos os pacotes do Design System juntos para a v3 (@olist/design-system, -tokens, -icons, @olist/styled-system, @olist/templates). Eles se referenciam entre si e misturar v2 com v3 causa instâncias duplicadas no node_modules.

Atenção a pacotes olist de terceiros que dependem do Design System como peer dependency, como o @olist/react-commons. Se eles ainda apontam para a v2, o gerenciador pode instalar uma segunda cópia. O sintoma típico é um erro de tipos que parece não fazer sentido, porque existem duas definições do mesmo tipo:

Type 'ResponsiveValue<SpacingValues>' is not assignable to type 'SpacingValues'.

10. Module Federation

Se você compartilha os pacotes do Design System em shared, garanta que o requiredVersion seja um semver publicado (^3.0.0) e que a versão seja singleton entre host e remotes. Um requiredVersion inválido, como um caminho file: usado em testes locais, faz o webpack tratar o próprio pacote como módulo e o build quebra.

Checklist

  1. Atualize todos os pacotes @olist/* para a v3 de uma vez e verifique que não há instância v2 duplicada.
  2. Configure o bundler para importar CSS e adicione os imports na entrada da aplicação.
  3. Se a aplicação usa styled-components próprio, troque o import do ThemeProviderV2 pelo subpath de compatibilidade, inclusive nos testes.
  4. Substitua deep imports de internals por API pública ou cópia internalizada.
  5. Remova styled-components apenas se ele existia só por causa do Design System.
  6. Ajuste o import do Chart e instale os peers opcionais, se usar o componente.
  7. Rode typecheck e build: o build pega deep imports que o typecheck não pega.
  8. Atualize snapshots de testes.
  9. Valide visualmente a aplicação, principalmente temas não-padrão.