teqo/docs/plans/bottom-drawer-handle-scroll-peek.md

137 lines
8.3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Bottom drawer — handle, gesto, scroll, peek discreto, labels 2 linhas
Status: implementado (PR)
Atualizado em: 2026-08-01
Issue: #132
Priority: P1
Model: cursor-grok-4.5-medium
Impeccable: C — chrome `CampaignQuickActionsDrawer` (comportamento + geometria)
Appetite: ~1–1,5d eng; snap/gesto/scroll + peek busca + altura labels; sem migration
Responsável: —
## Design (Impeccable)
Âncoras: `PRODUCT.md` (thumb zone; Feel the action) / `DESIGN.md` · B79/B91/B100 · Base UI Drawer snap · tema `campaign`.
Na implementação (`work-issue`): craft compacto → critique → polish (viewport ~390; detalhe município; scroll real).
Brief compacto:
- **Persona / contexto:** CG/assessor no celular fora do Início; uma mão; alterna ler a página e disparar ação/busca.
- **Job principal:** (1) handle **no topo** do sheet; (2) puxar para baixo fecha/recolhe; (3) scroll página ↓ fecha, ↑ abre; (4) collapsed ainda mostra busca **sem placeholder**; (5) títulos das ações com **2 linhas** visíveis.
- **Estratégia de cor:** Restrained.
- **Edit where you see:** não — launchers.
- **Anti-goals:** scrim modal; FAB; bottom nav; redesenhar catálogos B80–B90; absorver crash da busca (→ **B102** primeiro ou em paralelo sem bloquear geometria).
### Wireframe (texto)
**Dock (aberto):**
```text
┌─ página ───────────────────────────────────────┐
│ conteúdo │
├─ drawer ───────────────────────────────────────┤
│ ═ handle (TOPO) │
│ [○][○][○]… labels em 2 linhas visíveis │
│ ┌ Buscar na campanha (placeholder ok) ───────┐ │
│ └────────────────────────────────────────────┘ │
└────────────────────────────────────────────────┘
```
**Collapsed (fechado / após scroll ↓):**
```text
┌─ página (mais conteúdo) ───────────────────────┐
│ … │
├────────────────────────────────────────────────┤
│ ═ handle │
│ ┌ (input sem placeholder — discreto) ────────┐ │
│ └────────────────────────────────────────────┘ │
└────────────────────────────────────────────────┘
```
**Gesto:** drag handle/sheet ↓ → collapsed; scroll content ↓ → collapsed; scroll content ↑ → dock.
## Dados → decisão → apresentação
Dados: N/A — chrome; hits = B48+ via provider existente.
## Contexto
**B100 ✓** (#114) definiu dock no load + collapse no scroll **para baixo** + reopen **só** tap/pull (explicitamente **sem** reopen no scroll-up). Follow-up `a056616d` reordenou o DOM para o handle ficar **em baixo** (“snap shows bottom band”) — produto agora rejeita: handle deve voltar ao **topo**; puxar ↓ deve recolher; scroll ↑ deve **abrir**. Collapsed deve manter a barra de busca visível **sem placeholder**. Labels `line-clamp-2` existem no botão, mas dock `12rem` + `overflow-hidden` + handle embaixo cortam a 2ª linha.
## Objetivos
- **Handle no topo** do `DrawerContent` (reverter ordem do `a056616d`); banda visível do snap mostra handle → ações → busca.
- **Swipe/drag para baixo** no drawer recolhe para collapsed (Base UI `swipeDirection="down"` + snap; validar que não fica “só tap”).
- **Scroll do `campaign-content-scroll`:** ↓ além do limiar → collapsed; ↑ (delta ou `scrollTop` caindo / direção) → dock. Não reabrir se busca `uiFocused` _(assumido)_.
- **Collapsed:** renderiza input de busca **visível**, `placeholder=""` (ou omitido); sem strip de ações (ou strip hidden). Tap no input / focus → dock + focus.
- **Altura do dock / overflow:** 2ª linha dos labels visível (subir `QUICK_ACTIONS_SNAP_DOCK` e/ou `overflow-y-auto` na região de ações; tirar clip que come `line-clamp-2`).
- Load / navegação: estado inicial = dock (B100).
- Pins: unit direção scroll; e2e mobile handle no topo + collapse swipe se estável.
- Sem migration / Consent.
- Tracer: load dock → scroll ↓ collapsed (busca sem placeholder) → scroll ↑ dock → labels 2 linhas no viewport.
## Decisões travadas
- **Supersede B100 no reopen por scroll-up e no collapsed “só handle”.** Fonte: produto 2026-08-01. **Rejeitado:** manter “reopen só tap” (B100); collapsed só handle sem busca.
- **Handle no topo — reverter o DOM order do `a056616d`.** Se a geometria do snap exigir `padding-bottom` Base UI, aplicar **sem** mover o handle para baixo. **Rejeitado:** handle embaixo como “fix” de banda visível.
- **Collapsed = handle + busca discreta (sem placeholder); ações hidden.** **Rejeitado:** collapsed = só handle (B100); esconder busca no collapsed.
- **Scroll-up reabre** com limiar de direção (delta ↑ ≥ N px) ou `scrollTop` caindo abaixo do limiar — craft escolhe o mais estável; pin no unit. **Rejeitado:** hysteresis multi-eixo complexa neste item.
- **i18n:** ids `dock`/`collapsed`; aria pt-BR; placeholder vazio no collapsed (label sr-only permanece).
## Questões em aberto
- **Limiar scroll-up para abrir?** **Opções:** A) espelhar 24 px de delta ↑ | B) `scrollTop < 24` (só perto do topo). **Recomendação:** **A** (simétrico ao collapse). ✅ travado em craft (`quickActionsScrollDirection`).
- **Focus no input collapsed:** expande para dock automaticamente? **Opções:** A) sim | B) só digitar. **Recomendação:** **A**. ✅ travado em craft (`uiFocused` → dock).
## Abordagem proposta
```mermaid
flowchart TB
Scroll["campaign-content-scroll"] -->|delta down| Collapsed
Scroll -->|delta up| Dock
Handle["handle TOP"] -->|swipe down| Collapsed
Collapsed --> SearchPeek["search no placeholder"]
Dock --> Strip["actions 2-line labels"]
Dock --> SearchFull["search + placeholder"]
```
Componentes:
- **`CampaignQuickActionsDrawer.tsx`**: ordem handle → context; collapsed mostra `CampaignHomeSearch` (ou slot) sem placeholder; dock mostra strip + search completa; overflow/altura.
- **`CampaignQuickActionsHost.tsx` / snap context:** listener de scroll com direção (↑/↓); respeitar `uiFocused`.
- **`campaignQuickActionSnap.ts`:** recalibrar `QUICK_ACTIONS_SNAP_COLLAPSED` / `DOCK` para caber handle+busca (collapsed) e strip 2 linhas+busca (dock).
- **`CampaignHomeSearch` / `CampaignSearchInput`:** prop opcional `placeholder` / `discreet` para collapsed.
- **E2e / unit** atualizar expectativas B100 (scroll-up agora reabre; collapsed tem busca).
- **Migration:** Sem migration.
## Dependências
- Soft: B100 ✓, B91 ✓. Soft: **B101** (bleed/gap da strip — pode pousar junto). Soft: **B102** (crash) — se o crash bloquear teste manual da busca no drawer, priorizar B102.
- Nenhuma dura de Issue aberta.
## Não escopo
- Crash focus/type → **B102**.
- Gap/padding dos botões → **B101**.
- Título “Sugestões” → **B103**.
- Catálogos de ações por rota.
## Rabbit holes
- **Terceiro snap “expanded” para resultados.** Mitigação: Adiado; resultados rolam no dock ou a página.
- **`position: fixed` caseiro no lugar do Base UI.** Mitigação: só se swipe+snap forem irrecuperáveis após handle no topo + padding-bottom correto.
- **Persistir snap em sessionStorage.** Mitigação: fora; reset no pathname (B100).
## Adiado com gatilho
- Animação spring custom além do Base UI. Revisitar se critique pedir motion.
- Peek de 1 ícone de ação no collapsed. Revisitar se a mesa achar busca-só pobre.
## Referências
- GitHub Issue #132 (B105)
- `CampaignQuickActionsDrawer.tsx` · `CampaignQuickActionsHost.tsx` · `campaignQuickActionSnap.ts` · `Drawer.tsx` · `docs/plans/bottom-drawer-peek-acoes-busca.md` (B100 — supersedido em parte)
- Commit `a056616d` (handle bottom — reverter ordem)
- `PRODUCT.md` / `DESIGN.md` — Field Desk chrome