B66: retract home chrome on search focus with animated transition.
Emends B47 so focusing the input clears strip/summary before typing; hardens hit rows against blur-before-click.
This commit is contained in:
parent
16852980b2
commit
31bd488c1e
8 changed files with 104 additions and 62 deletions
|
|
@ -7,6 +7,7 @@ alwaysApply: false
|
|||
|
||||
## Status
|
||||
|
||||
- **B66 entregue em código (2026-07-30):** modo focado da busca no **focus** (emenda B47) — `homeSearchUiFocused` (`inputFocused || query.isActive`) já no contrato/hook; overlap B68 (sugestões no focus vazio). **Nesta entrega:** `CampaignHomeLayout` retrai summary+spacer (`data-slot="home-chrome"`) e actions com grid `0fr/1fr` + opacity 220ms (`motion-reduce:transition-none`) em vez de `hidden`; `md:flex-none` no chrome; `HomeSearchHitRow` `onMouseDown` preventDefault (blur→click); e2e focus sem digitar + regressão com digitação. Sem migration. Plano: [`modo-focado-busca-no-focus.md`](../../../docs/plans/modo-focado-busca-no-focus.md).
|
||||
- **B61 entregue em código (2026-07-29):** etapa de ajuste de votos no wizard A1 — `WizardExpectedVotesStep` substitui o stub B60 em `atualizar-votos` com `?municipio=`; três passos explícitos média→pessimista→otimista via `?cenario=`; atalhos `2×`/±50/±100; validação client com jump+warning (`getWizardVoteViolation`); **um POST batch** ao concluir otimista (`POST /campanha/municipios/expected-votes`). Helpers em `wizardVoteEstimate.ts` + `wizardActionHref` estendido. Sem migration/Consent. Unit `wizardVoteEstimate`; e2e avanço de cenário + violação. Plano: [`ajuste-votos-wizard.md`](../../../docs/plans/ajuste-votos-wizard.md). Desbloqueia wiring A1 / **B64** (prefill votos).
|
||||
- **B62 entregue em código (2026-07-29):** modelo de sinal simplificado — `municipalityUpdate` kind `sinal` agora é só `signalType` + `body`; migration `20260730_010601_simplify_municipality_signal_fields` dropa `signal_source`/`triangulated` (o gerador reemitiu `ADD VALUE 'adiada'` por drift de snapshot — removido à mão, e o snapshot novo sara a cadeia); labels/descriptions dos 5 tipos reescritas para a mesa (`Rede esfriou`, `Adversário apareceu`, `Alguém pediu algo` — sem "broker" no modelo de sinal; `activity.origin` `pedido_broker` e a copy do suggestionCatalog ficaram fora por decisão da sessão). Forms: `MunicipalitySignalFields` (lista B26) e o bloco inline de `MunicipalityUpdateForm` perderam Fonte/Triangulado; feed/dossiê (`MunicipalityUpdateFeed` + `municipalityUpdatePageData`) só exibem o badge do tipo. **E11: presença de sinal de adversário lê como confirmada — triage 1** (decisão do usuário: "eles não vão adicionar sinais improváveis"), `adversarySignal: { present: true } | null`, fator único "Sinal de adversário registrado", glossário E18 alinhado. Fixa B63. Bônus: teste e2e `campaignMunicipalities` "advisor scopes…" estava obsoleto desde B43 (home da liderança) — atualizado para `/campanha/contatos` + redirect pós-B43, e o pin de bypass do `municipalityElectoralBaseline` baixado 9→8 (drift pré-existente). Gate: tsc/lint/format/cycles/knip(P3 pré-existente)/876 unit/489 int/e2e alvo verde/build (`/campanha` 233 kB); Aikido 0 findings. Plano: [`simplificar-modelo-sinal.md`](../../../docs/plans/simplificar-modelo-sinal.md). Desbloqueia **B63** (wizard registrar sinal).
|
||||
- **E10+ entregue em código (2026-07-29):** Escala e DRY pós-E10 — F1: `loadMunicipalityScopeFromDocs` no `municipalityPageData.ts` evita a segunda query de `municipality` quando `isPagedByPayload === false`; F2: `computeAllMunicipalityPotentials` memoizado por processo (retorna cache `Map<string, MunicipalityPotential>`); F3: `TooltipProvider` movido para o layout de `(app)`, restaurando o agrupamento de delay do Radix para os tooltips das listas; F4: DRY nos filtros multi do mobile em `MunicipalityFilters` via `.map` sobre `municipalityFilterDefinitions` (que ganhou `emptyLabel`). Sem migration/UI nova. Plano: [`escala-dry-pos-e10.md`](../../../docs/plans/escala-dry-pos-e10.md).
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
# Modo focado da busca no focus (não na digitação)
|
||||
|
||||
Status: rascunho
|
||||
Atualizado em: 2026-07-29
|
||||
Status: entregue (2026-07-30)
|
||||
Atualizado em: 2026-07-30 — as-built: predicado `homeSearchUiFocused` (`inputFocused || query.isActive`) já no contrato/hook (overlap B68); `CampaignHomeLayout` retrai summary+spacer (`data-slot="home-chrome"`) e actions (grid `0fr/1fr` + opacity 220ms ease-out, `motion-reduce:transition-none`) em vez de `hidden`; `md:flex-none` no chrome para não crescer no desktop; `HomeSearchHitRow` `onMouseDown` preventDefault (blur→click); e2e focus sem digitar + regressão com digitação; unit layout/search atualizados. Sem migration.
|
||||
Item do roadmap: [docs/roadmap.md](../roadmap.md) (Trilha B, item B66 — UX-1 busca Início)
|
||||
Impeccable: B — encaixe de motion/estado no chrome do Início (`CampaignHomeLayout` / `CampaignHomeStaffChrome`) sob tema `campaign`
|
||||
Appetite: ~0,5–0,75 dia eng; estado `focused` ≠ `query.isActive` + transição CSS; sem migration
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
# Roadmap — Teqo
|
||||
|
||||
Atualizado em: 2026-07-29 — ~~**B51**~~ ✓; ~~**B52**~~ ✓; ~~**B72**~~ ✓ gap strip ações; **B71** polish busca (bullets/título/hover full-bleed); **B69**–**B70** A4 liderança; ~~**B62**~~ ✓ simplificar sinal (E11 triage 1 por presença); ~~**B56**~~ ✓; ~~**B67**~~ ✓; ~~**B68**~~ ✓; **B66**; ~~**B59**~~ ✓; ~~**B65**~~ ✓; ~~**B60**~~ ✓; ~~**B61**~~ ✓; ~~**B48**~~ ✓; ~~**B49**~~ ✓; ~~**B50**~~ ✓; B53–B55; wizards ~~B60~~ ✓/~~**B61**~~ ✓/B63–B64.
|
||||
Atualizado em: 2026-07-30 — ~~**B66**~~ ✓ busca no focus; ~~**B51**~~ ✓; ~~**B52**~~ ✓; ~~**B72**~~ ✓ gap strip ações; **B71** polish busca (bullets/título/hover full-bleed); **B69**–**B70** A4 liderança; ~~**B62**~~ ✓ simplificar sinal (E11 triage 1 por presença); ~~**B56**~~ ✓; ~~**B67**~~ ✓; ~~**B68**~~ ✓; ~~**B59**~~ ✓; ~~**B65**~~ ✓; ~~**B60**~~ ✓; ~~**B61**~~ ✓; ~~**B48**~~ ✓; ~~**B49**~~ ✓; ~~**B50**~~ ✓; B53–B55; wizards ~~B60~~ ✓/~~**B61**~~ ✓/B63–B64.
|
||||
Registro canônico dos **próximos** planos e débitos. Histórico de entregas: resumo abaixo + planos em [`docs/plans/`](plans/) + notebook [`.cursor/rules/projects/nucleos-eleitorais.mdc`](../.cursor/rules/projects/nucleos-eleitorais.mdc).
|
||||
|
||||
## Âncoras do calendário eleitoral 2026 (Res. TSE 23.760/2026)
|
||||
|
|
@ -83,7 +83,7 @@ O discovery literatura→persona→entrevista ([relatório aprovado](research/re
|
|||
|
||||
### Demais itens abertos
|
||||
|
||||
- **UX-1 fluxos ação-primeiro (prioridade pós-sessão 29/07)** — evidência: [snapshot](plans/sessao-observada-coordenador-2026-07-29-snapshot.md) · O9–O11 em CUSTOMER.md · **rascunho:** [fluxos-acao-primeiro-inicio.md](plans/fluxos-acao-primeiro-inicio.md). Soft deadline: **03/08**. **Chassis Início:** ~~**B43**~~ ✓ → ~~**B44**~~ ✓ → ~~**B45**~~ ✓ → ~~**B46**~~ ✓ → ~~**B47**~~ ✓ → ~~**B58**~~ ✓ → ~~**B67**~~ ✓ (pan strip) → ~~**B65**~~ ✓ (âncora inferior mobile) → **B66** (focus limpa tela + animação) → ~~**B48**~~ ✓ → ~~**B49**~~ ✓ → ~~**B68**~~ ✓ → **B71** (polish resultados busca) · ~~**B72**~~ ✓ (gap strip) → ~~**B50**~~ ✓ → ~~**B51**~~ ✓ → ~~**B52**~~ ✓ → **B53–B55** · ~~**B56**~~ ✓ · **B57** futuro. **Wizards:** ~~**B59**~~ ✓ → ~~**B60**~~ ✓/**B61**/**B64** · ~~**B62**~~ ✓ → **B63** · **B69** → **B70** (A4 liderança).
|
||||
- **UX-1 fluxos ação-primeiro (prioridade pós-sessão 29/07)** — evidência: [snapshot](plans/sessao-observada-coordenador-2026-07-29-snapshot.md) · O9–O11 em CUSTOMER.md · **rascunho:** [fluxos-acao-primeiro-inicio.md](plans/fluxos-acao-primeiro-inicio.md). Soft deadline: **03/08**. **Chassis Início:** ~~**B43**~~ ✓ → ~~**B44**~~ ✓ → ~~**B45**~~ ✓ → ~~**B46**~~ ✓ → ~~**B47**~~ ✓ → ~~**B58**~~ ✓ → ~~**B67**~~ ✓ (pan strip) → ~~**B65**~~ ✓ (âncora inferior mobile) → ~~**B66**~~ ✓ (focus limpa tela + animação) → ~~**B48**~~ ✓ → ~~**B49**~~ ✓ → ~~**B68**~~ ✓ → **B71** (polish resultados busca) · ~~**B72**~~ ✓ (gap strip) → ~~**B50**~~ ✓ → ~~**B51**~~ ✓ → ~~**B52**~~ ✓ → **B53–B55** · ~~**B56**~~ ✓ · **B57** futuro. **Wizards:** ~~**B59**~~ ✓ → ~~**B60**~~ ✓/**B61**/**B64** · ~~**B62**~~ ✓ → **B63** · **B69** → **B70** (A4 liderança).
|
||||
- ~~**B43** Início em branco + Quadro~~ — **entregue 2026-07-29** (`/campanha` blank; staff dashboard em `/campanha/quadro`; liderança em `/campanha/contatos`; nav Início+Quadro / Início+Meus contatos; `requireCampaignPageActor` manda leader bloqueado → `/campanha/contatos`; sem migration) · [plano](plans/inicio-em-branco-quadro.md)
|
||||
- ~~**B44** Botão de ação do Início + lista horizontal~~ — **entregue 2026-07-29** (`CampaignHomeActionButton` + `CampaignHomeActionStrip`; Tooltip fine / long-press Drawer coarse; montado no Início por B45 ✓) · ~1d · Janela 1 · Impeccable C · [plano](plans/botao-acao-inicio-strip.md)
|
||||
- ~~**B45** Catálogo de ações por persona~~ — **entregue 2026-07-29** (`src/lib/campaignHomeActions.ts` + `CampaignHomeActions`; staff 6 ações com `uncovered-municipalities` → `?coverage=sem_assessor&sort=votos`; leader 2 com `my-contacts` → `/campanha/contatos`; demais inertes; ilha client por limite RSC↔ícones Lucide) · [plano](plans/catalogo-acoes-inicio-por-persona.md)
|
||||
|
|
@ -99,7 +99,7 @@ O discovery literatura→persona→entrevista ([relatório aprovado](research/re
|
|||
- **B70** Wizard atualizar liderança (grid 2/3/4 + form curto + skip + Continuar dirty + focus) · Depende de B59 + B69 · soft B60 · ~1,25–1,5d · Janela 1 · Impeccable C · [plano](plans/wizard-atualizar-lideranca.md)
|
||||
- ~~**B46** Posição dos botões de ação (thumb zone)~~ — **entregue 2026-07-29** (`CampaignHomeLayout`: coluna `min-h-full` + spacer `flex-1` só em mobile; `data-slot="home-actions"` / `home-search`; ordem flex `order-*` — mobile ações→busca, `md+` busca→ações); `/campanha` usa `CampaignPageShell` `min-h-full` + layout; decisão sticky vs coluna = coluna (opção B). Unit `campaignHomeLayout.unit.spec.ts`; e2e B45 intacto. Sem migration. Âncora inferior no mobile corrigida por **B65** ✓ (2026-07-29). · [plano](plans/posicao-botoes-acao-inicio-thumb-zone.md)
|
||||
- ~~**B47** Busca global — input (debounce, sem botão; modo focado: sobe e esconde o resto)~~ — **entregue 2026-07-29** (`CampaignHomeStaffChrome` + `CampaignHomeSearch` + `useHomeSearchQuery`; debounce 250 ms; query ativa ≥2 chars; `HomeSearchContext` para B48+; staff-only via `isStaffCampaignRole`; Escape limpa; região `aria-live` sem hits ainda; sem migration) · [plano](plans/busca-global-inicio-input.md) · **emenda B66:** limpeza no **focus** (não só na digitação) + animação
|
||||
- **B66** Modo focado da busca no **focus** (não na digitação) + animação de retração do chrome (strip/spacer/resumo) como se a barra expandisse — emenda a decisão B47 “expand = query”; hits continuam gated por limiar ≥2 · Depende de B47 ✓ · soft ~~B65~~ ✓ · ~0,5–0,75d · Janela 1 · Paralelizável com B49–B53 / B59 / B62 · Impeccable B · [plano](plans/modo-focado-busca-no-focus.md) · empty útil → **B68**
|
||||
- **B66** ~~Modo focado da busca no **focus** (não na digitação) + animação de retração do chrome (strip/spacer/resumo) como se a barra expandisse — emenda a decisão B47 “expand = query”; hits continuam gated por limiar ≥2~~ — **entregue 2026-07-30** (`homeSearchUiFocused`; `CampaignHomeLayout` grid `0fr/1fr` + opacity 220ms + `motion-reduce`; `HomeSearchHitRow` blur→click; e2e focus sem digitar) · Depende de B47 ✓ · soft ~~B65~~ ✓ · ~0,5–0,75d · Janela 1 · Impeccable B · [plano](plans/modo-focado-busca-no-focus.md) · empty útil → **B68** ✓
|
||||
- ~~**B65** Ancorar busca + ações do Início no limite inferior (mobile)~~ — **entregue 2026-07-29** (`h-full min-h-0` em `CampaignPageShell` + `CampaignHomeStaffChrome` + `CampaignHomeLayout`; `data-slot="home-dock"` agrupa strip + busca; spacer `flex-1` empurra o dock acima da bottom nav; `md+` inalterado; modo focado B47/B66 intacto; sem `fixed`/`mt-auto`) · Depende de B46 ✓ / B47 ✓ · [plano](plans/ancorar-busca-acoes-inicio-mobile.md)
|
||||
- ~~**B48** Busca — resultados Municípios (+ TIs no mesmo grupo; flag de prioridade alinhada; “2022” / agregado à direita; sem card)~~ — **entregue 2026-07-29** (`POST /campanha/home-search`, `searchHomeMunicipalities`, `HomeSearchMunicipalityGroup`; word-start; assessor scoped; TIs via `loadTerritoryOverview`) · [plano](plans/busca-global-resultados-municipios.md)
|
||||
- ~~**B68** Sugestões na busca aberta (empty state por papel)~~ — **entregue 2026-07-29** (`POST /campanha/home-search` com `mode: 'suggest'`; `loadHomeSearchSuggestions` + `rankHomeSearchSuggestMunicipalities`; assessor = carteira fria; CG/candidato = `priority === 'alta'` por déficit central + frescor; `homeSearchUiFocused` + seção **Sugestões**; `resultKind`; sem migration) · [plano](plans/sugestoes-busca-vazia-inicio.md)
|
||||
|
|
|
|||
|
|
@ -2,6 +2,35 @@ import type { ReactNode } from 'react'
|
|||
|
||||
import { cn } from '@/lib/utils'
|
||||
|
||||
const homeChromeRetractionClass = (retracted: boolean) =>
|
||||
cn(
|
||||
'grid min-h-0 transition-[grid-template-rows,opacity] duration-[220ms] ease-out motion-reduce:transition-none',
|
||||
retracted
|
||||
? 'grid-rows-[0fr] opacity-0 pointer-events-none motion-reduce:opacity-0'
|
||||
: 'grid-rows-[1fr] opacity-100 motion-reduce:opacity-100',
|
||||
)
|
||||
|
||||
const HomeChromeRetractionShell = ({
|
||||
retracted,
|
||||
slot,
|
||||
className,
|
||||
children,
|
||||
}: {
|
||||
retracted: boolean
|
||||
slot?: string
|
||||
className?: string
|
||||
children: ReactNode
|
||||
}) => (
|
||||
<div
|
||||
data-slot={slot}
|
||||
data-retracted={retracted || undefined}
|
||||
className={cn(homeChromeRetractionClass(retracted), className)}
|
||||
aria-hidden={retracted || undefined}
|
||||
>
|
||||
<div className="min-h-0 overflow-hidden">{children}</div>
|
||||
</div>
|
||||
)
|
||||
|
||||
export const CampaignHomeLayout = ({
|
||||
actions,
|
||||
searchSlot,
|
||||
|
|
@ -11,27 +40,34 @@ export const CampaignHomeLayout = ({
|
|||
actions: ReactNode
|
||||
searchSlot?: ReactNode
|
||||
summarySlot?: ReactNode
|
||||
/** When true (input focused or query active), hide thumb-zone spacer and action strip. */
|
||||
/** When true (input focused or query active), retract thumb-zone spacer and action strip. */
|
||||
focused?: boolean
|
||||
}) => (
|
||||
<div className="flex h-full min-h-0 w-full flex-col">
|
||||
{summarySlot ? (
|
||||
<div className={cn('order-0 min-w-0', focused && 'hidden')} data-slot="home-summary">
|
||||
{summarySlot}
|
||||
<HomeChromeRetractionShell
|
||||
retracted={focused}
|
||||
slot="home-chrome"
|
||||
className={!focused ? 'min-h-0 flex-1 md:flex-none' : undefined}
|
||||
>
|
||||
<div className="flex h-full min-h-0 flex-col">
|
||||
{summarySlot ? (
|
||||
<div className="min-w-0" data-slot="home-summary">
|
||||
{summarySlot}
|
||||
</div>
|
||||
) : null}
|
||||
<div aria-hidden className="min-h-0 flex-1 md:hidden" data-slot="home-thumb-spacer" />
|
||||
</div>
|
||||
) : null}
|
||||
<div
|
||||
aria-hidden
|
||||
className={cn('min-h-0 flex-1 md:hidden', focused && 'hidden')}
|
||||
data-slot="home-thumb-spacer"
|
||||
/>
|
||||
</HomeChromeRetractionShell>
|
||||
<div data-slot="home-dock" className="flex min-w-0 flex-col">
|
||||
<div
|
||||
data-slot="home-actions"
|
||||
className={cn('order-1 min-w-0 md:order-2', focused && 'hidden')}
|
||||
<HomeChromeRetractionShell
|
||||
retracted={focused}
|
||||
slot="home-actions-chrome"
|
||||
className="order-1 md:order-2"
|
||||
>
|
||||
{actions}
|
||||
</div>
|
||||
<div data-slot="home-actions" className="min-w-0">
|
||||
{actions}
|
||||
</div>
|
||||
</HomeChromeRetractionShell>
|
||||
{searchSlot ? (
|
||||
<div
|
||||
data-slot="home-search"
|
||||
|
|
|
|||
|
|
@ -23,6 +23,10 @@ export const HomeSearchHitRow = ({
|
|||
}) => (
|
||||
<Link
|
||||
href={href}
|
||||
onMouseDown={(event) => {
|
||||
// Combobox/list precedent: RelationChipCell — keep input focused until navigation (B66).
|
||||
event.preventDefault()
|
||||
}}
|
||||
className={cn(
|
||||
'flex min-h-11 w-full items-center gap-3 py-2.5 text-left text-foreground',
|
||||
'rounded-md outline-none hover:bg-muted/60 focus-visible:ring-2 focus-visible:ring-ring',
|
||||
|
|
|
|||
|
|
@ -31,7 +31,10 @@ test.describe('Início — busca global (B47)', () => {
|
|||
await expect(page.getByLabel('Buscar na campanha')).toHaveCount(0)
|
||||
})
|
||||
|
||||
test('staff focused search hides action strip after debounce', async ({ campaign, page }) => {
|
||||
test('staff focused search hides action strip on input focus (B66)', async ({
|
||||
campaign,
|
||||
page,
|
||||
}) => {
|
||||
const { fixtures } = campaign
|
||||
const coordinator = await fixtures.createCampaignUser('coordinator', {
|
||||
name: fixtures.value('Coordenadora Geral'),
|
||||
|
|
@ -42,6 +45,26 @@ test.describe('Início — busca global (B47)', () => {
|
|||
await expect(actionsSlot).toBeVisible()
|
||||
await expect(page.getByLabel('Ações rápidas')).toBeVisible()
|
||||
|
||||
await page.getByLabel('Buscar na campanha').focus()
|
||||
await expect(actionsSlot).toBeHidden({ timeout: 5000 })
|
||||
|
||||
await page.getByLabel('Buscar na campanha').blur()
|
||||
await expect(actionsSlot).toBeVisible({ timeout: 5000 })
|
||||
})
|
||||
|
||||
test('staff typing in search keeps action strip hidden after debounce', async ({
|
||||
campaign,
|
||||
page,
|
||||
}) => {
|
||||
const { fixtures } = campaign
|
||||
const coordinator = await fixtures.createCampaignUser('coordinator', {
|
||||
name: fixtures.value('Coordenadora Geral'),
|
||||
})
|
||||
|
||||
await campaign.login(page, coordinator.email!, coordinator.password)
|
||||
const actionsSlot = page.locator('[data-slot="home-actions"]')
|
||||
await expect(actionsSlot).toBeVisible()
|
||||
|
||||
await page.getByLabel('Buscar na campanha').fill('ca')
|
||||
await expect(actionsSlot).toBeHidden({ timeout: 5000 })
|
||||
|
||||
|
|
|
|||
|
|
@ -40,18 +40,20 @@ describe('CampaignHomeLayout', () => {
|
|||
expect(container.querySelector('[data-slot="home-dock"]')).not.toBeNull()
|
||||
})
|
||||
|
||||
it('renders mobile thumb-zone spacer above home-dock', () => {
|
||||
it('renders mobile thumb-zone spacer inside home-chrome above home-dock', () => {
|
||||
const { container } = render(<CampaignHomeLayout actions={<p>Actions block</p>} />)
|
||||
|
||||
const dock = container.querySelector('[data-slot="home-dock"]')
|
||||
const spacer = dock?.previousElementSibling
|
||||
expect(spacer?.getAttribute('data-slot')).toBe('home-thumb-spacer')
|
||||
const chrome = container.querySelector('[data-slot="home-chrome"]')
|
||||
const spacer = chrome?.querySelector('[data-slot="home-thumb-spacer"]')
|
||||
expect(chrome).not.toBeNull()
|
||||
expect(spacer).not.toBeNull()
|
||||
expect(spacer?.getAttribute('aria-hidden')).toBe('true')
|
||||
expect(spacer?.className).toContain('flex-1')
|
||||
expect(spacer?.className).toContain('md:hidden')
|
||||
expect(chrome?.nextElementSibling?.getAttribute('data-slot')).toBe('home-dock')
|
||||
})
|
||||
|
||||
it('hides spacer, summary, and actions when focused but keeps search', () => {
|
||||
it('retracts spacer, summary, and actions when focused but keeps search', () => {
|
||||
const { container } = render(
|
||||
<CampaignHomeLayout
|
||||
actions={<p>Actions block</p>}
|
||||
|
|
@ -61,11 +63,18 @@ describe('CampaignHomeLayout', () => {
|
|||
/>,
|
||||
)
|
||||
|
||||
expect(container.querySelector('[data-slot="home-thumb-spacer"]')?.className).toContain(
|
||||
'hidden',
|
||||
)
|
||||
expect(container.querySelector('[data-slot="home-summary"]')?.className).toContain('hidden')
|
||||
expect(container.querySelector('[data-slot="home-actions"]')?.className).toContain('hidden')
|
||||
const homeChrome = container.querySelector('[data-slot="home-chrome"]')
|
||||
expect(homeChrome?.getAttribute('data-retracted')).toBe('true')
|
||||
expect(homeChrome?.className).toContain('grid-rows-[0fr]')
|
||||
expect(homeChrome?.className).toContain('opacity-0')
|
||||
|
||||
const actionsChrome = container.querySelector('[data-slot="home-actions-chrome"]')
|
||||
expect(actionsChrome?.getAttribute('data-retracted')).toBe('true')
|
||||
expect(actionsChrome?.className).toContain('grid-rows-[0fr]')
|
||||
|
||||
expect(container.querySelector('[data-slot="home-thumb-spacer"]')).not.toBeNull()
|
||||
expect(container.querySelector('[data-slot="home-summary"]')).not.toBeNull()
|
||||
expect(container.querySelector('[data-slot="home-actions"]')).not.toBeNull()
|
||||
expect(container.querySelector('[data-slot="home-search"]')).not.toBeNull()
|
||||
expect(container.querySelector('[data-slot="home-dock"]')).not.toBeNull()
|
||||
})
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
import { render, screen } from '@testing-library/react'
|
||||
import { describe, expect, it, vi } from 'vitest'
|
||||
|
||||
import { CampaignHomeLayout } from '@/components/campaign/dashboard/CampaignHomeLayout'
|
||||
import { CampaignHomeSearch } from '@/components/campaign/dashboard/CampaignHomeSearch'
|
||||
import { HomeSearchProvider } from '@/components/campaign/dashboard/HomeSearchContext'
|
||||
|
||||
|
|
@ -15,36 +14,6 @@ const providerValue = {
|
|||
uiFocused: true,
|
||||
}
|
||||
|
||||
describe('CampaignHomeLayout focused mode', () => {
|
||||
it('hides actions, thumb spacer, and summary when focused', () => {
|
||||
const { container } = render(
|
||||
<CampaignHomeLayout
|
||||
focused
|
||||
actions={<p>Actions block</p>}
|
||||
searchSlot={<p>Search</p>}
|
||||
summarySlot={<p>Summary block</p>}
|
||||
/>,
|
||||
)
|
||||
|
||||
expect(container.querySelector('[data-slot="home-thumb-spacer"]')).toBeNull()
|
||||
expect(container.querySelector('[data-slot="home-actions"]')?.className).toContain('hidden')
|
||||
expect(container.querySelector('[data-slot="home-summary"]')?.className).toContain('hidden')
|
||||
})
|
||||
|
||||
it('shows summary when not focused', () => {
|
||||
render(
|
||||
<CampaignHomeLayout
|
||||
actions={<p>Actions block</p>}
|
||||
summarySlot={<p data-testid="home-summary-stub">Summary stub</p>}
|
||||
/>,
|
||||
)
|
||||
|
||||
expect(
|
||||
screen.getByTestId('home-summary-stub').closest('[data-slot="home-summary"]'),
|
||||
).not.toBeNull()
|
||||
})
|
||||
})
|
||||
|
||||
describe('CampaignHomeSearch', () => {
|
||||
it('renders search input and results region', () => {
|
||||
render(
|
||||
|
|
|
|||
Loading…
Reference in a new issue