diff --git a/docs/plans/municipios-mobile-sem-moldura-impl.md b/docs/plans/municipios-mobile-sem-moldura-impl.md new file mode 100644 index 00000000..e50f047d --- /dev/null +++ b/docs/plans/municipios-mobile-sem-moldura-impl.md @@ -0,0 +1,92 @@ +# Impl: B184 — Omnibox mobile sem moldura (padrão de todas as listas) + cards edge-to-edge e salvar no header (municípios) + +Status: entregue em código (2026-08-09) +Atualizado em: 2026-08-10 +Issue: #514 +Intenção: docs/plans/municipios-mobile-sem-moldura.md +Appetite restante: ~0,5–1 dia eng (herdado; abordagem dentro do envelope) + +## Leitura da intenção + +- **Outcome:** no celular, o chrome do filtro de listas some: label oculta, omnibox sem moldura e sticky sob a barra superior com linha separadora, limpar vira X circular dentro do input (com chips **ou** busca digitada). **Escopo ampliado por decisão do humano (2026-08-09):** o look bare/sticky é o **padrão mobile do chassis `CampaignListOmnibox` — todas as listas `/campanha`**, não só municípios. Em municípios, adicionalmente: "Salvar filtro" vira icon button no header (mobile) e os cards ficam sem borda, edge-to-edge, separados por linha. +- **O que NÃO negociar:** desktop de todas as listas inalterado (label visível, box com borda, botão texto "Limpar", sem X); comportamento de filtragem (URL/navegação) intacto em todas as listas; chips continuam dentro da omnibox; fluxo do popover de salvar (nomear/renomear) intacto; cards edge-to-edge e salvar no header são municípios-only (outras listas não têm essa superfície/saved filters); sem dados/KPI novos. +- **O que reavaliar:** a hipótese da intenção escopava a municípios; a decisão do humano tornou o chassis o dono do padrão — prop opt-in morre, o look bare vira o default < `md` do chassis, e os 11 call sites mudam juntos. Cards e header continuam nos arquivos de municípios. + +## Abordagem recomendada + +```mermaid +flowchart LR + subgraph Chassis["CampaignListOmnibox (padrão < md, todos os 11 call sites)"] + L[Label: hidden md:block
input ganha aria-label={label} sempre] + B[Box: border-0 shadow-none md:border md:border-input md:shadow-xs] + S[Coluna do input: sticky top-0 z-20 -mx-4 border-b bg-background px-4 py-2
md:static md:mx-0 md:border-b-0 md:bg-transparent] + X["X circular no input: onClearAll && (chips || query)
aria-label='Limpar', md:hidden"] + C["'Limpar' texto: hidden md:inline-flex"] + end + subgraph Municipio["Municípios (adicional)"] + M2[SaveMunicipalityFilterControl no trailing: hidden md:inline-flex] + H1["page.tsx → SetCampaignHeaderAction → SaveMunicipalityFilterControl presentation='icon' + md:hidden"] + K1["Cards: gap-0 -mx-4 md:gap-4 md:mx-0; article border-b last:border-b-0 md:border md:rounded-xl"] + end + Chassis --> Municipio +``` + +**Opções consideradas:** + +- **A — Look bare como padrão do chassis (`CampaignListOmnibox`), sem prop.** Todos os 11 call sites herdam; desktop via variantes `md:`; nada muda nos adapters/URLs. +- **B — Prop opt-in `mobileBare` (plano anterior), só municípios.** +- **C — Cópia local do chassis para municípios.** + +**Recomendação:** A — a decisão do humano fez do look o padrão; prop opt-in viraria fricção para toda lista futura. O chassis é o dono do concern (B127) e não há divergência entre listas: todas passam `onClearAll`, todas limpam busca + filtros no `kind: 'clear'` (verificado em todos os 11 runActions), nenhuma tem trailing que precise ficar na região sticky (picker e ações ficam abaixo, fora da sticky, e as ações desktop-only já são `hidden md:flex`). Desktop continua 100% no comportamento atual via variantes `md:`. + +**Rejeitadas:** B porque o pedido agora é o padrão — cada lista futura teria que lembrar da prop; C porque duplica o contrato ARIA/combobox do chassis (o próprio plano da intenção proíbe "twin" do dono existente). + +### Componentes / mudanças + +- **`CampaignListOmnibox`** (`src/components/campaign/shared/CampaignListOmnibox.tsx`) — sem prop nova; abaixo de `md`: + - `label` → `hidden md:block` (o `