Skip to content

Fix clipped ActionMenu/HelpTooltip popovers; kick off UI/UX overhaul (Phase 0) - #14

Merged
brianramseyau merged 7 commits into
mainfrom
phase-00-plan-docs-actionmenu-hotfix
Sep 14, 2026
Merged

brianramseyau merged 7 commits into
mainfrom
phase-00-plan-docs-actionmenu-hotfix

Conversation

@brianramseyau

Copy link
Copy Markdown
Owner

What

Fixes the reported bug: the row-action menu (⋮) rendered inside each table's overflow-x-auto card and always opened downward, so a row near the bottom of the viewport (the last row on Expenses, always) had its menu clipped or entirely invisible. HelpTooltip had the same hand-rolled-positioning shape.

ActionMenu and HelpTooltip are rebuilt on bits-ui (DropdownMenu / Popover) — both are now portalled and collision-aware, so they flip upward near the viewport edge instead of clipping. Public props are unchanged except the custom trigger snippet, which now receives props to spread rather than an (open, toggle) pair — its one caller (Income's "Add" button) is updated.

Why this is also "Phase 0" of a bigger plan

This kicks off a broader UI/UX overhaul (the app's inconsistent CRUDL pages, duplicated markup, no shared component vocabulary). The full plan is in foundational/PLAN_01_OVERVIEW.md and the design direction ("Polymer") is in foundational/DESIGN.md. This PR itself only:

  • Installs the shadcn-svelte + bits-ui foundation (dropdown-menu, popover, button only for now). Their tokens are mapped to the app's existing slate/indigo palette, not "Polymer" yet — nothing else changes visually. Phase 1 does the real palette swap.
  • Updates AGENTS.md with the plan/design pointers, a mandatory /frontend-design step for UI work, a browser-screenshot recipe (with a note about the login rate limit), and a per-phase checks-and-reviews workflow matched to this repo's actual CI (lint/typecheck/test/e2e — no review bot configured here).
  • Adds e2e/action-menu.spec.ts, a real-browser regression test that opens the last row's menu at a short viewport and asserts it lands fully inside it.

Notes

  • jsdom can't lay out bits-ui's floating content (no real layout engine), which needed a few unit-test adjustments — see ActionMenu.spec.ts's top-of-file comment and DESIGN.md's decisions log for the full explanation. A global src/tests/setup.ts reset (body style + bits-ui's dismissable-layer registry) will matter again for every future bits-ui overlay (Dialog, Sheet, Drawer, Select, Tabs in later phases).
  • Manually confirmed against the dev server that the last row's menu on /expenses is now fully visible, in both light and dark mode.

Verification

  • pnpm verify (lint + typecheck + test, both apps) — green
  • pnpm test:e2e — green, 17/17 including the new regression test
  • API coverage unaffected (no API changes)

🤖 Generated with Claude Code

brianramseyau and others added 4 commits September 14, 2026 21:56
…plan (Phase 0)

The row-action menu (⋮) rendered inside each table's overflow-x-auto card
and always opened downward, so a row near the bottom of the viewport had
its menu clipped or entirely invisible - the last row on Expenses always
did this. HelpTooltip had the same hand-rolled-positioning shape.

Rebuild both on bits-ui: ActionMenu on DropdownMenu, HelpTooltip on
Popover. Both are now portalled and collision-aware, so they flip upward
near the viewport edge instead of clipping. Their public props are
unchanged except the custom `trigger` snippet, which now receives props to
spread rather than an (open, toggle) pair - updated its one caller
(Income's "Add" button).

This is Phase 0 of a broader UI/UX overhaul, planned out in
foundational/PLAN_01_OVERVIEW.md and DESIGN.md ("Polymer" - see that doc
for the concept, palette and signature element). Phase 0 also:
- installs the shadcn-svelte + bits-ui foundation (dropdown-menu, popover,
  button only for now), with the new components' tokens mapped to the
  app's *existing* slate/indigo palette so nothing else changes visually
  yet - Phase 1 does the real palette swap
- updates AGENTS.md with the plan/design pointers, a mandatory
  /frontend-design step for UI work, a browser-screenshot recipe, and a
  per-phase checks-and-reviews workflow matched to this repo's actual CI
  (lint/typecheck/test/e2e - no review bot)
- adds e2e/action-menu.spec.ts, a real-browser regression test asserting
  the last row's menu lands fully inside the viewport

jsdom can't lay out bits-ui's floating content (no real layout engine), so
unit tests needed a few adjustments - see ActionMenu.spec.ts's top-of-file
comment and DESIGN.md's decisions log for what and why. A global
src/tests/setup.ts reset (body style + bits-ui's dismissable-layer
registry) will matter again for every future bits-ui overlay.

Verified: pnpm verify and pnpm test:e2e both green; API coverage
unaffected (no API changes). Manually confirmed against the dev server
that the last row's menu on /expenses is now fully visible in both light
and dark mode.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Kilo is active on this repo (confirmed on PR #14) - it was just paused
when Dev was previously stopped. My earlier pass had concluded (from
checking PR #11's reviews/comments and repo files) that no review bot was
configured here and rewrote the workflow accordingly; that was wrong.
Restore the "green check isn't proof there's nothing to fix - read every
comment, reply and resolve each thread individually" steps in AGENTS.md
and PLAN_01_OVERVIEW.md.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
CI's test/e2e jobs were failing with "Invalid command exported from
demo_seed.js file. Invalid URL" - unrelated to this branch's own changes,
since it throws while apps/api's test bootstrap boots the ace Kernel
(testUtils.db().migrate()), which scans every command file in
commands/ regardless of what's being tested.

Root cause (already diagnosed and fixed the same way in EveryList,
commit 468045b): Node 24.20.0's loader changes broke @adonisjs/ace's
command-metadata validator (adonisjs/ace#169) - its jsonschema-based
validator resolves schema $refs against an implicit base URL that
24.20.0's stricter URL parsing rejects. Fixed upstream in ace 14.1.1
(adonisjs/ace#170, which gives the schema a real $id), but
@adonisjs/core@7.3.3 still depends on ^14.1.0, which resolves to the
broken 14.1.0 by default.

- pnpm-workspace.yaml: override @adonisjs/ace to 14.1.1 project-wide,
  same mechanism already used there for a couple of other transitive
  deps. Verified locally on Node 24.18.1: still 640/640 passing - the
  fix is backward compatible, not just forward-compatible with 24.20.0.
- Pin Node to 24.20.0 everywhere, matching EveryList: new .nvmrc, both
  package.json engines fields (>=24.20.0 <25), CI's node-version, and
  the Dockerfile's base image tag. The Docker image tag pin is cosmetic
  consistency rather than a required fix - the built image runs
  precompiled JS, not the .ts loader path this bug is actually in.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Approval is now needed once per phase (the commit+push that opens the
PR), not again for every fix-up commit responding to a broken CI check
or review/Kilo feedback within that same PR - the owner will say up
front if they want to hold off on a round instead. Merging, and
starting a new piece of work, still need explicit confirmation.

Also drops the "dev server must stay running" rule - the owner will ask
to hold off ahead of time instead of this needing a standing rule.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Comment thread apps/web/src/lib/components/ActionMenu.svelte
Comment thread apps/web/src/lib/components/HelpTooltip.svelte Outdated
Comment thread e2e/action-menu.spec.ts Outdated
Comment thread pnpm-workspace.yaml Outdated
@kilo-code-bot

kilo-code-bot Bot commented Sep 14, 2026 •

Copy link
Copy Markdown

Code Review Summary

Status: No Issues Found | Recommendation: Merge

Files Reviewed (1 file)
  • foundational/PLAN_01_PHASE_00_PLAN_DOCS_ACTIONMENU_HOTFIX.md

Incremental review of cd9208db3571e07cb6aac740bf614a469e77cbbb: the only change since the previous review fixed the previously-flagged wording - the doc now correctly separates the exact 24.20.0 pins (.nvmrc, CI node-version, Dockerfile base tags) from both package.json engines floors (>=24.20.0 <25). Verified against the actual files; the prior finding is resolved.

Previous Review Summaries (3 snapshots, latest commit 1e44cb9)

Current summary above is authoritative. Previous snapshots are kept for context only.

Previous review (commit 1e44cb9)

Status: 1 Issue Found | Recommendation: Address before merge

Overview

Severity Count
CRITICAL 0
WARNING 0
SUGGESTION 1
Issue Details (click to expand)

SUGGESTION

File Line Issue
foundational/PLAN_01_PHASE_00_PLAN_DOCS_ACTIONMENU_HOTFIX.md 45 Says Node was "pinned to 24.20.0 everywhere", but the two engines fields set a >=24.20.0 <25 range, not an exact pin.
Files Reviewed (2 files)
  • foundational/PLAN_01_PHASE_00_PLAN_DOCS_ACTIONMENU_HOTFIX.md - 1 issue
  • foundational/DESIGN.md - no issues (role="status" rationale verified against HelpTooltip.svelte)

Fix these issues in Kilo Cloud

Previous review (commit 2a5753f)

Status: No Issues Found | Recommendation: Merge

All four findings from the previous review at 7e50b2b are addressed in 2a5753f; no new issues found in the changed lines.

Files Reviewed (6 files)
  • apps/web/src/lib/components/ActionMenu.svelte
  • apps/web/src/lib/components/HelpTooltip.svelte
  • apps/web/src/lib/components/HelpTooltip.spec.ts
  • apps/web/src/routes/income/+page.svelte
  • e2e/action-menu.spec.ts
  • pnpm-workspace.yaml

Previous review (commit 7e50b2b)

Status: 4 Issues Found | Recommendation: Address before merge

Overview

Severity Count
CRITICAL 0
WARNING 1
SUGGESTION 3
Issue Details (click to expand)

WARNING

File Line Issue
apps/web/src/lib/components/ActionMenu.svelte 61 class prop is now silently dropped — the default button overwrites {...props}'s class after the spread, so the prop no longer reaches the DOM (it used to land on the wrapper <div>).

SUGGESTION

File Line Issue
apps/web/src/lib/components/HelpTooltip.svelte 29 role="tooltip" on portalled Popover content conflicts with the trigger's auto aria-haspopup="dialog" semantics.
e2e/action-menu.spec.ts 24 Bounds only the first menu item, so a menu whose lower items are clipped would still pass the regression test.
pnpm-workspace.yaml 8 Override rationale cites @adonisjs/core@7.3.3, but the lockfile resolves 7.3.5.
Files Reviewed (62 files)

Hand-written code:

  • apps/web/src/lib/components/ActionMenu.svelte — 1 issue
  • apps/web/src/lib/components/HelpTooltip.svelte — 1 issue
  • e2e/action-menu.spec.ts — 1 issue
  • pnpm-workspace.yaml — 1 issue
  • apps/web/src/lib/components/ActionMenu.spec.ts — no issues
  • apps/web/src/lib/components/HelpTooltip.spec.ts — no issues
  • apps/web/src/lib/utils.ts — no issues
  • apps/web/src/routes/income/+page.svelte — no issues
  • apps/web/src/routes/income/page.spec.ts — no issues
  • apps/web/src/routes/expenses/page.spec.ts — no issues
  • apps/web/src/routes/layout.css — no issues
  • apps/web/src/tests/setup.ts — no issues
  • apps/web/vitest.config.ts — no issues
  • apps/web/eslint.config.js — no issues
  • apps/web/components.json — no issues
  • apps/web/package.json, apps/api/package.json, package.json — no issues
  • .github/workflows/ci.yml, .nvmrc, Dockerfile — no issues
  • AGENTS.md, foundational/DESIGN.md, foundational/PLAN_01_*.md — docs, reviewed for consistency

Vendored/generated (shadcn-svelte CLI output, excluded from lint/coverage per eslint.config.js/vitest.config.ts — not reviewed for style): apps/web/src/lib/components/ui/**, pnpm-lock.yaml

Fix these issues in Kilo Cloud


Reviewed by deepseek-v4.1-flash · Input: 0 · Output: 0 · Cached: 0

brianramseyau and others added 2 commits September 14, 2026 22:26
- ActionMenu.svelte / income/+page.svelte: the default trigger's (and
  Income's custom trigger's) literal `class` attribute was overwriting
  `{...props}`'s class after the spread, silently dropping a caller's
  `class` prop even though it's still declared in Props. Merge with
  `cn()` instead of overwriting.
- HelpTooltip.svelte: `role="tooltip"` on the popover content
  contradicted PopoverTrigger's own `aria-haspopup="dialog"` semantics
  (a true ARIA tooltip is non-interactive, hover-triggered description
  text - this panel is a click-to-open, focus-managed popover). Use
  `role="status"` instead, so the explanation is announced the moment
  it appears rather than needing an ARIA role that doesn't match its
  actual behaviour. Updated the one spec that queried by the old role.
- e2e/action-menu.spec.ts: the regression test only checked the first
  menu item's (Edit) bounding box, which could pass in exactly the
  clipping failure mode it exists to catch if a menu opened with just
  enough room for its first item but not its later ones. Check the
  menu container's own bounding box instead - if the container fits,
  every item inside it does too.
- pnpm-workspace.yaml: fixed the override comment's cited
  @adonisjs/core version (7.3.3 -> the actually-resolved 7.3.5).

Verified: pnpm verify and pnpm test:e2e both still green.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Note the unrelated Node/ace CI fix and the Kilo Code Review round (4
found, 4 fixed, re-review confirmed clean) in the phase doc's Notes
and deviations. Log the role="tooltip" -> role="status" a11y decision
in DESIGN.md's decisions log for future click-to-reveal panels to
follow.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Comment thread foundational/PLAN_01_PHASE_00_PLAN_DOCS_ACTIONMENU_HOTFIX.md Outdated
Kilo caught it: the phase doc said Node was "pinned to 24.20.0
everywhere", but the two package.json engines fields set a
>=24.20.0 <25 range - only .nvmrc, CI and the Dockerfile are an exact
pin. Reworded to say that accurately.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@brianramseyau
brianramseyau merged commit 50504db into main Sep 14, 2026
5 checks passed
@brianramseyau
brianramseyau deleted the phase-00-plan-docs-actionmenu-hotfix branch September 14, 2026 21:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant