# Plano de Implementação — V0.2 (DX Baseline + Events Foundation)

**Spec de referência:** `2026-05-17-post-v1-roadmap-design.md`  
**Pré-requisito:** V0.1 completo (`cargo test` 98 testes, `cargo run --example counter`)  
**Critério de conclusão:** `cargo test --workspace` + `cargo clippy --workspace --all-targets -- -D warnings` passam. CI verde no primeiro push.

---

## Ordem de execução

As etapas devem ser executadas nesta ordem — cada uma é pré-requisito da próxima onde indicado.

---

## Etapa 1 — Extração do crate `lemon::widget` *(fundação de todo o resto)*

### 1.1 Workspace

- Adicionar `src/widget` em `[workspace] members` no `Cargo.toml` raiz
- Criar `src/widget/Cargo.toml` com `lemon = { workspace = true }` e `publish = true`

### 1.2 Refatorar `Element` enum no core

Arquivo: `src/src/element/mod.rs`

- Renomear/reorganizar variantes para primitivas puras:
  - `Box` → `Prim { style: StyleProps, paint: PaintProps, children: Vec<Element>, handlers: EventHandlers }`
  - `Text` → `TextNode { content: TextContent, style: TextStyle }`
  - `Component`, `Fragment`, `None` permanecem iguais
  - Remover variantes `Row`, `Column`, `Button`, `Image` do enum core
- Atualizar diff (`src/src/diff/`) para usar as novas variantes
- Atualizar retained tree (`src/src/retained/`) para usar as novas variantes
- Atualizar layout pass (`src/src/layout/`) — Row/Column eram Prim com flex; agora `Prim` sempre usa `StyleProps.display: flex` quando configurado
- Atualizar paint pass (`src/src/paint/`) — `Button` era Prim com paint + label; agora é composição em lemon::widget

### 1.3 Criar builders em `lemon::widget`

Arquivos novos em `src/widget/src/`:

- `lib.rs` — re-exporta tudo
- `row.rs` — `Row` builder: retorna `Element::Prim` com `display: flex, flex_direction: row`
- `column.rs` — `Column` builder: retorna `Element::Prim` com `display: flex, flex_direction: column`
- `box_.rs` — `Box_` builder: retorna `Element::Prim` genérico
- `text.rs` — `Text` builder: retorna `Element::TextNode`
- `button.rs` — `Button` builder: retorna `Element::Prim` com paint de background, padding e `on_click`
- `image.rs` — `Image` builder: retorna `Element::Prim` (placeholder até V0.4)

### 1.4 Atualizar exemplos

- `examples/counter/src/main.rs`: trocar `use lemon::widgets::*` por `use lemon::widget::*`
- Verificar que `cargo run --example counter` continua funcionando

---

## Etapa 2 — Licença

- Adicionar `license = "MIT"` em `src/Cargo.toml` e `src/widget/Cargo.toml`
- Criar `LICENSE` no root (texto MIT padrão com `Copyright (c) 2026 Lucas Larangeira`)

---

## Etapa 3 — CI

Arquivo novo: `.github/workflows/ci.yml`

```yaml
name: CI
on: [push, pull_request]
jobs:
  check:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: dtolnay/rust-toolchain@stable
        with:
          components: rustfmt, clippy
      - run: cargo fmt --all -- --check
      - run: cargo clippy --workspace --all-targets -- -D warnings
      - run: cargo test --workspace
```

- Resolver qualquer warning de clippy existente antes de ativar `-D warnings`

---

## Etapa 4 — Novos exemplos

### 4.1 `examples/card`

Demonstra layout composto: card com título, subtítulo, dois botões lado a lado.  
Arquivo: `examples/card/src/main.rs` + `examples/card/Cargo.toml`

### 4.2 `examples/list_keyed`

Demonstra lista dinâmica com keys: botão adiciona item, botão por item remove-o.  
Exercita `MoveChild` e `key()` no diff.  
Arquivo: `examples/list_keyed/src/main.rs` + `examples/list_keyed/Cargo.toml`

- Adicionar ambos em `[workspace] members`

---

## Etapa 5 — Keyboard

**Depende de:** Etapa 1 concluída.

### 5.1 Tipos de evento

Arquivo: `src/src/element/events.rs` (ou `event.rs`)

```rust
pub struct KeyEvent {
    pub key: Key,          // winit::keyboard::Key re-exportado ou wrapper
    pub modifiers: Modifiers,
    pub repeat: bool,
}

pub enum KeyboardHandler {
    KeyDown(Rc<dyn Fn(KeyEvent)>),
    KeyUp(Rc<dyn Fn(KeyEvent)>),
}
```

- Adicionar `on_key_down` e `on_key_up` em `EventHandlers` do retained tree
- Adicionar `.on_key_down(f)` e `.on_key_up(f)` em `Prim` builder

### 5.2 Sistema de foco

Arquivo: `src/src/retained/focus.rs`

- `FocusManager`: mantém `Option<NodePath>` do nó com foco atual
- Prop `focusable: bool` em `StyleProps` (padrão `false`)
- `FocusManager::next()` / `prev()` para Tab / Shift+Tab — percorre retained tree em ordem de documento, filtrando `focusable: true`
- `FocusManager` vive no `AppState` (platform layer)

### 5.3 Platform — despacho de eventos de teclado

Arquivo: `src/src/platform/window.rs`

- Processar `WindowEvent::KeyboardInput` do winit
- Se `Tab` → `FocusManager::next()` (ou `prev()` com Shift)
- Senão → despachar `KeyEvent` para `on_key_down` / `on_key_up` do nó focado

---

## Etapa 6 — Hover

**Depende de:** Etapa 1 concluída.

### 6.1 Estado de hover no retained tree

Arquivo: `src/src/retained/mod.rs`

- Campo `hovered: bool` em `RetainedNode`
- `hoverable: bool` em `StyleProps` (padrão `false`; `true` quando `on_hover_enter` ou `on_hover_leave` definido)

### 6.2 Handlers

- Adicionar `on_hover_enter: Option<Rc<dyn Fn()>>` e `on_hover_leave: Option<Rc<dyn Fn()>>` em `EventHandlers`
- Adicionar `.on_hover_enter(f)` e `.on_hover_leave(f)` em `Prim` builder

### 6.3 Platform — hit-test de hover

Arquivo: `src/src/platform/hit_test.rs`

- Manter `Option<NodePath>` do nó atualmente hovered em `AppState`
- A cada `CursorMoved`: hit-test pós-ordem sobre nós `hoverable`
- Se mudou: disparar `on_hover_leave` no nó anterior, `on_hover_enter` no novo

### 6.4 Cursor do sistema

- Prop `cursor: CursorIcon` em `StyleProps` (padrão `Default`)
- A cada `CursorMoved`: aplicar `cursor` do nó hovered via `winit::window::Window::set_cursor`

---

## Critério de done

- [ ] `cargo test --workspace` — sem falhas
- [ ] `cargo clippy --workspace --all-targets -- -D warnings` — sem warnings
- [ ] `cargo run --example counter` — funciona como antes
- [ ] `cargo run -p card` — card renderiza corretamente
- [ ] `cargo run -p list_keyed` — lista dinâmica funciona com add/remove
- [ ] Keyboard: digitar com um `Text` focado dispara `on_key_down`
- [ ] Hover: `on_hover_enter` / `on_hover_leave` disparam ao mover o mouse
- [ ] CI verde no GitHub Actions
