# 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](https://docs.decentraland.org/contributor/contributor-pt/guias-para-contribuidores/web-ui-standards/custom-components) 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](https://docs.decentraland.org/contributor/contributor-pt/guias-para-contribuidores/web-ui-standards/custom-components) para criar componentes UI2
* Veja [Estilização & Theming](https://docs.decentraland.org/contributor/contributor-pt/guias-para-contribuidores/web-ui-standards/styling-and-theming) para padrões de estilização
* Verificar [Visão Geral do Processo](https://docs.decentraland.org/contributor/contributor-pt/guias-para-contribuidores/web-ui-standards/process-overview) para o fluxo de trabalho completo
