> For the complete documentation index, see [llms.txt](https://docs.decentraland.org/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.decentraland.org/contributor/contributor-pt/guias-do-contribuidor/padroes-de-web-ui/migration.md).

# Guia de Migração

Este guia cobre o processo de migração de componentes de UI1 (`decentraland-ui`) para UI2 (`decentraland-ui2`).

## Quando Migrar

As migrações podem começar por três razões válidas:

### 1. Melhoria Técnica

Você quer migrar um componente por:

* Melhor suporte a temas
* Melhorias nos tipos TypeScript
* Consistência com outros componentes UI2
* Otimização de desempenho
* Melhorias de acessibilidade

### 2. Atualizando um Componente

* Um componente UI1 precisa ser atualizado
* Ainda não existe um equivalente em UI2
* **Requisito**: Crie-o primeiro em UI2, depois use-o

### 3. Necessidades do Projeto

* O componente será usado em um projeto novo ou existente
* Há tempo disponível para migrá-lo corretamente
* Recursos do projeto permitem uma migração completa

{% hint style="warning" %}
**Não** migre componentes "apenas porque." Cada migração deve ter uma justificativa comercial ou técnica clara.
{% endhint %}

***

## Processo de Migração

### Passo 1: Planejamento

Antes de iniciar a migração:

1. **Identificar dependências**
   * Quais outros componentes ele usa?
   * Quais projetos atualmente o utilizam?
   * Há mudanças incompatíveis planejadas?
2. **Revisar uso atual**
   * Quantos projetos usam este componente?
   * Quais props são mais comumente usadas?
   * Existe algum problema conhecido?
3. **Definir escopo**
   * Esta será uma migração 1:1?
   * Há melhorias planejadas?
   * Qual é o cronograma?

### Passo 2: Criar Componente UI2

Siga o [Componentes Personalizados](/contributor/contributor-pt/guias-do-contribuidor/padroes-de-web-ui/custom-components.md) guia para componentes candidatos a UI2.

**Requisitos:**

* Use sintaxe de objeto para styled-components
* Use apenas valores do tema (sem valores arbitrários)
* Adicione histórias abrangentes no Storybook
* Escreva testes completos
* Documente todas as props e comportamentos

**Exemplo de estrutura:**

```
ui2/src/components/Button/
├── Button.tsx
├── Button.styles.ts
├── Button.stories.tsx
├── Button.test.tsx
├── types.ts
├── index.ts
└── README.md
```

### Passo 3: Manter Compatibilidade

O componente UI2 **DEVE** expor as mesmas props e comportamentos que a versão UI1.

#### Mesmas Props

```tsx
// UI1 Button
interface ButtonProps {
  primary?: boolean;
  size?: 'small' | 'medium' | 'large';
  onClick?: () => void;
  disabled?: boolean;
  children: React.ReactNode;
}

// UI2 Button - DEVE suportar as mesmas props
interface ButtonProps {
  primary?: boolean;
  size?: 'small' | 'medium' | 'large';
  onClick?: () => void;
  disabled?: boolean;
  children: React.ReactNode;
  // Pode adicionar novas props opcionais
  variant?: 'text' | 'outlined' | 'contained';
}
```

#### Alterações Compatíveis Retroativamente

Se você precisar alterar ou adicionar props:

1. **Primeiro**, adicione as novas props ao UI1 como opcionais
2. **Em seguida**, migre os consumidores do UI1 para usar as novas props
3. **Finalmente**, crie o componente UI2 com a nova API

```tsx
// Passo 1: Adicionar prop opcional ao UI1
interface ButtonProps {
  primary?: boolean;
  // Nova prop opcional
  variant?: 'primary' | 'secondary';
}

// Passo 2: Atualizar implementação do UI1
export function Button({ primary, variant = primary ? 'primary' : 'secondary' }: ButtonProps) {
  // Use variant em vez de primary internamente
}

// Passo 3: Criar UI2 com nova API
interface ButtonProps {
  // variant agora é a prop principal
  variant?: 'primary' | 'secondary';
  // Mantenha primary para compatibilidade, marque como deprecated
  /** @deprecated Use variant instead */
  primary?: boolean;
}
```

### Passo 4: Depreciar Componente UI1

Adicione um aviso de depreciação ao componente UI1:

````tsx
/**
 * @deprecated Este componente foi migrado para UI2.
 * Importe de 'decentraland-ui2' em vez disso:
 * 
 * ```tsx
 * import { Button } from 'decentraland-ui2';
 * ```
 * 
 * Veja o guia de migração: https://docs.decentraland.org/contributor-guides/web-ui-standards/migration
 */
export function Button(props: ButtonProps) {
  // ... implementação existente
}
````

### Passo 5: Adoção Gradual

Não force a migração imediata. Permita a adoção gradual:

1. **Publicar** componente UI2
2. **Documentar** caminho de migração
3. **Atualizar** novos projetos para usar UI2
4. **Migrar** projetos existentes de forma oportunista
5. **Planejar** eventual remoção do UI1 (com aviso)

***

## Exemplos de Migração

### Exemplo 1: Componente Simples

Migrando um básico `Card` componente:

#### Versão UI1

```tsx
// decentraland-ui/src/components/Card/Card.tsx
import React from 'react';
import './Card.css';

export interface CardProps {
  className?: string;
  children: React.ReactNode;
}

export function Card({ className, children }: CardProps) {
  return (
    <div className={`dcl-card ${className || ''}`}>
      {children}
    </div>
  );
}
```

#### Versão UI2

```tsx
// decentraland-ui2/src/components/Card/Card.tsx
import { styled } from '@mui/material/styles';

export interface CardProps {
  className?: string;
  children: React.ReactNode;
}

const StyledCard = styled('div')(({ theme }) => ({
  backgroundColor: theme.palette.background.paper,
  borderRadius: theme.shape.borderRadius,
  padding: theme.spacing(2),
  boxShadow: theme.shadows[1],
  
  [theme.breakpoints.down('sm')]: {
    padding: theme.spacing(1),
  },
}));

export function Card({ className, children }: CardProps) {
  return (
    <StyledCard className={className}>
      {children}
    </StyledCard>
  );
}
```

### Exemplo 2: Componente com Variantes

Migrando um `Button` com variantes:

#### Versão UI1

```tsx
// UI1
import './Button.css';

interface ButtonProps {
  primary?: boolean;
  secondary?: boolean;
  size?: 'small' | 'medium' | 'large';
}

export function Button({ primary, secondary, size = 'medium', ...props }: ButtonProps) {
  const classes = [
    'dcl-button',
    primary && 'primary',
    secondary && 'secondary',
    `size-${size}`,
  ].filter(Boolean).join(' ');
  
  return <button className={classes} {...props} />;
}
```

#### Versão UI2

```tsx
// UI2
import { styled } from '@mui/material/styles';

interface ButtonProps {
  /** @deprecated Use variant="contained" instead */
  primary?: boolean;
  /** @deprecated Use variant="outlined" instead */
  secondary?: boolean;
  variant?: 'text' | 'outlined' | 'contained';
  size?: 'small' | 'medium' | 'large';
}

const StyledButton = styled('button')<ButtonProps>(({ theme, variant = 'contained', size = 'medium' }) => {
  const sizes = {
    small: theme.spacing(0.5, 1),
    medium: theme.spacing(1, 2),
    large: theme.spacing(1.5, 3),
  };
  
  const variants = {
    text: {
      backgroundColor: 'transparent',
      color: theme.palette.primary.main,
    },
    outlined: {
      backgroundColor: 'transparent',
      color: theme.palette.primary.main,
      border: `1px solid ${theme.palette.primary.main}`,
    },
    contained: {
      backgroundColor: theme.palette.primary.main,
      color: theme.palette.primary.contrastText,
    },
  };
  
  return {
    padding: sizes[size],
    borderRadius: theme.shape.borderRadius,
    border: 'none',
    cursor: 'pointer',
    ...variants[variant],
    
    '&:hover': {
      opacity: 0.9,
    },
    
    '&:disabled': {
      opacity: 0.5,
      cursor: 'not-allowed',
    },
  };
});

export function Button({ 
  primary, 
  secondary, 
  variant, 
  ...props 
}: ButtonProps) {
  // Tratar props depreciadas
  const actualVariant = variant || 
    (primary ? 'contained' : secondary ? 'outlined' : 'text');
  
  return <StyledButton variant={actualVariant} {...props} />;
}
```

***

## Checklist de Migração

Use esta checklist para cada migração de componente:

### Fase de Planejamento

* [ ] Identificar todos os projetos que usam o componente
* [ ] Documentar props e comportamentos atuais
* [ ] Definir escopo e cronograma da migração
* [ ] Obter aprovação das partes interessadas

### Fase de Implementação

* [ ] Criar componente UI2 seguindo os padrões
* [ ] Manter compatibilidade de props
* [ ] Usar sintaxe de objeto para estilização
* [ ] Usar apenas valores do tema
* [ ] Implementar todos os estados (idle, hover, focus, disabled, error)
* [ ] Adicione histórias abrangentes no Storybook
* [ ] Escrever testes unitários
* [ ] Documentar recursos de acessibilidade

### Fase de Depreciação

* [ ] Adicionar aviso de depreciação ao componente UI1
* [ ] Atualizar documentação do UI1
* [ ] Criar guia de migração para consumidores
* [ ] Publicar componente UI2

### Fase de Adoção

* [ ] Atualizar novos projetos para usar UI2
* [ ] Criar PRs de migração para projetos existentes
* [ ] Monitorar por problemas
* [ ] Coletar feedback
* [ ] Planejar cronograma de remoção do UI1

***

## Padrões Comuns de Migração

### CSS para Styled Components

```tsx
// UI1: arquivo CSS
.dcl-card {
  background: #fff;
  padding: 16px;
  border-radius: 8px;
}

// UI2: componente styled
const Card = styled('div')(({ theme }) => ({
  backgroundColor: theme.palette.background.paper,
  padding: theme.spacing(2),
  borderRadius: theme.shape.borderRadius,
}));
```

### Nomes de Classe para Props

```tsx
// UI1: Variantes baseadas em classe
<Button className={primary ? 'primary' : 'secondary'} />

// UI2: Variantes baseadas em prop
<Button variant={primary ? 'contained' : 'outlined'} />
```

### Valores Fixos para Tema

```tsx
// UI1: Valores fixos
const styles = {
  color: '#333',
  fontSize: '14px',
  padding: '8px 16px',
};

// UI2: Valores do tema
const Component = styled('div')(({ theme }) => ({
  color: theme.palette.text.primary,
  fontSize: theme.typography.body2.fontSize,
  padding: theme.spacing(1, 2),
}));
```

***

## Alterações Incompatíveis

Às vezes mudanças incompatíveis são necessárias. Trate-as com cuidado:

### Quando Mudanças Incompatíveis São Aceitáveis

* Correções de segurança
* Bugs críticos
* Atualizações de versão major
* Remoção de recursos depreciados (com aviso)

### Como Lidar com Mudanças Incompatíveis

1. **Anunciar cedo** - Comunicar as mudanças com antecedência
2. **Fornecer caminho de migração** - Documentar como atualizar
3. **Aumentar versão** - Seguir versionamento semântico
4. **Período de depreciação** - Dar tempo para migrar
5. **Codemods** - Fornecer ferramentas de migração automatizadas se possível

### Exemplo: Removendo Props Depreciadas

```tsx
// Versão 1.0: Introduzir nova API, depreciar a antiga
interface ButtonProps {
  /** @deprecated Use variant="contained" instead */
  primary?: boolean;
  variant?: 'text' | 'outlined' | 'contained';
}

// Versão 1.5: Avisar sobre remoção
interface ButtonProps {
  /** @deprecated Will be removed in 2.0. Use variant instead */
  primary?: boolean;
  variant?: 'text' | 'outlined' | 'contained';
}

// Versão 2.0: Remover prop depreciada
interface ButtonProps {
  variant?: 'text' | 'outlined' | 'contained';
}
```

***

## Testando a Migração

Assegure que os componentes migrados funcionem corretamente:

### Testes de Regresso Visual

Compare visualmente componentes UI1 e UI2:

```tsx
// Storybook story para comparação
export const ComparisonStory: Story = {
  render: () => (
    <div style={{ display: 'flex', gap: '2rem' }}>
      <div>
        <h3>UI1</h3>
        <UI1Button primary>Click Me</UI1Button>
      </div>
      <div>
        <h3>UI2</h3>
        <UI2Button variant="contained">Click Me</UI2Button>
      </div>
    </div>
  ),
};
```

### Testes Comportamentais

Assegure que as props funcionem da mesma forma:

```tsx
describe('Button migration', () => {
  it('should handle primary prop (deprecated) the same as variant="contained"', () => {
    const { container: ui1 } = render(<UI1Button primary>Test</UI1Button>);
    const { container: ui2 } = render(<UI2Button primary>Test</UI2Button>);
    
    // Comparar saída renderizada
    expect(ui1.textContent).toBe(ui2.textContent);
  });
});
```

***

## Atualizações de Documentação

Após a migração, atualize a documentação:

### Atualizar Docs do Componente UI1

```markdown
# Button (UI1 - Depreciado)

> ⚠️ **Este componente foi migrado para UI2.**
> Veja a [documentação do UI2 Button](../ui2/button) para a nova versão.

Este componente está depreciado e será removido em uma versão futura.
Por favor, migre para UI2.

## Guia de Migração

Veja [Migration Guide](./migration) para detalhes.
```

### Criar Docs do Componente UI2

```markdown
# Button (UI2)

Componente de botão moderno com suporte completo ao tema.

## Migração a partir do UI1

Se você está migrando do UI1:

- prop `primary` → `variant="contained"`
- prop `secondary` → `variant="outlined"`
- classes CSS → styled-components

Veja o [Migration Guide](./migration) completo para detalhes.
```

***

## Próximos Passos

* Rever [Componentes Personalizados](/contributor/contributor-pt/guias-do-contribuidor/padroes-de-web-ui/custom-components.md) para criar componentes UI2
* Veja [Estilização & Theming](/contributor/contributor-pt/guias-do-contribuidor/padroes-de-web-ui/styling-and-theming.md) para padrões de estilização
* Verificar [Visão Geral do Processo](/contributor/contributor-pt/guias-do-contribuidor/padroes-de-web-ui/process-overview.md) para o fluxo de trabalho completo


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.decentraland.org/contributor/contributor-pt/guias-do-contribuidor/padroes-de-web-ui/migration.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
