Skip to content

fix(electron): stabilize canvas-first shell#13

Open
crs48 wants to merge 2 commits intomainfrom
codex/fix-canvas-shell-regressions
Open

fix(electron): stabilize canvas-first shell#13
crs48 wants to merge 2 commits intomainfrom
codex/fix-canvas-shell-regressions

Conversation

@crs48
Copy link
Copy Markdown
Owner

@crs48 crs48 commented Mar 11, 2026

Summary

  • restore the canvas workspace host to a real full-height container
  • avoid Base UI menu crashes by rendering simple menu labels without group-only primitives
  • add a renderer regression test that locks the canvas host height behavior

Validation

  • pnpm exec tsc --noEmit -p apps/electron/tsconfig.json
  • pnpm exec eslint apps/electron/src/renderer/components/CanvasView.tsx apps/electron/src/renderer/components/CanvasView.test.tsx packages/ui/src/primitives/Menu.tsx
  • pnpm --dir apps/electron exec vitest run src/renderer/components/CanvasView.test.tsx
  • git push -u origin codex/fix-canvas-shell-regressions (pre-push hooks ran pnpm typecheck and pnpm test successfully)
  • live Electron verification via CDP: canvas renders, system menu opens, no renderer console errors

Summary by CodeRabbit

Release Notes

  • Tests

    • Added unit tests for the CanvasView component to validate rendering behavior and styling.
  • Bug Fixes

    • Fixed full-height rendering in the canvas display area.
  • Refactor

    • Updated Menu component label structure for improved implementation consistency.

crs48 added 2 commits March 10, 2026 17:19
- render simple menu labels as static text instead of Base UI group labels
- prevent SystemMenu from crashing the Electron shell on open
- keep advanced dropdown group label exports unchanged for grouped menus
- replace the canvas shell wrapper with full-height sizing so it cannot collapse
  inside the absolute workspace shell
- add a renderer regression test that guards the canvas host height contract
@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Mar 11, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 80cb6bc1-4c91-4aa3-a2c9-5b1b17f6a80b

📥 Commits

Reviewing files that changed from the base of the PR and between c14e6e1 and 49c8459.

📒 Files selected for processing (3)
  • apps/electron/src/renderer/components/CanvasView.test.tsx
  • apps/electron/src/renderer/components/CanvasView.tsx
  • packages/ui/src/primitives/Menu.tsx

📝 Walkthrough

Walkthrough

This PR adds a comprehensive unit test for CanvasView, updates the component's wrapper className for full-height rendering, and simplifies MenuLabel rendering by replacing a styled group label component with a plain div.

Changes

Cohort / File(s) Summary
CanvasView Component & Test
apps/electron/src/renderer/components/CanvasView.test.tsx, apps/electron/src/renderer/components/CanvasView.tsx
Introduces unit tests for CanvasView component with mocked dependencies and validates rendering of Canvas placeholder. Updates wrapper className from flex-1 to h-full for full-height layout.
Menu Primitives
packages/ui/src/primitives/Menu.tsx
Replaces BaseMenu.GroupLabel with a plain div in MenuLabel component, changing semantic role while preserving visual styling.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

Possibly related PRs

Poem

🐰 wiggles nose
The canvas now stands tall and free,
With tests to guard its legacy,
MenuLabels shed their fancy dress,
Simpler rendering—much less mess! ✨

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'fix(electron): stabilize canvas-first shell' directly addresses the main objectives: restoring the canvas workspace host to full-height and preventing shell collapse, which are the primary concerns in the changeset.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch codex/fix-canvas-shell-regressions

Comment @coderabbitai help to get the list of available commands and usage tips.

@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps bot commented Mar 11, 2026

Greptile Summary

This PR makes three targeted stability fixes to the canvas-first Electron shell: it corrects the canvas container's height class (flex-1h-full), replaces a crashy Base UI GroupLabel primitive with a plain <div> in MenuLabel, and adds a renderer regression test that locks the height behaviour.

Key changes:

  • CanvasView.tsx: flex-1 only works when the parent is a flex container; h-full is the correct class here and ensures the canvas occupies full viewport height in all parent layout contexts.
  • Menu.tsx (MenuLabel): BaseMenu.GroupLabel requires a BaseMenu.Group ancestor for its internal context — using it standalone caused crashes. Swapping to a plain <div> fixes the crash but removes ARIA group-label semantics (see inline comment).
  • CanvasView.test.tsx: Good addition of a regression test, but the DOM traversal (parentElement?.parentElement) is fragile and will break or silently mis-assert if the component's internal nesting changes (see inline comment).

Confidence Score: 4/5

  • Safe to merge with two minor style/accessibility concerns that can be addressed as follow-ups.
  • All three changes are small and targeted. The h-full layout fix is straightforwardly correct. The MenuLabel crash fix is valid but introduces an accessibility regression worth tracking. The regression test provides value but uses a fragile traversal pattern. No logic errors or breaking changes were found.
  • packages/ui/src/primitives/Menu.tsx — the ARIA regression in MenuLabel should be addressed before it accumulates more usage.

Important Files Changed

Filename Overview
apps/electron/src/renderer/components/CanvasView.tsx Single-line layout fix: replaces flex-1 with h-full on the outer container so the canvas occupies full height regardless of whether the parent establishes a flex context. Change is correct and safe.
apps/electron/src/renderer/components/CanvasView.test.tsx New regression test that locks the h-full class on the canvas host. The assertion uses fragile parentElement?.parentElement DOM traversal that is tightly coupled to nesting depth, making it susceptible to false results if the component structure changes.
packages/ui/src/primitives/Menu.tsx Replaces BaseMenu.GroupLabel with a plain <div> in MenuLabel to avoid crashes when the primitive is used without a BaseMenu.Group parent. Fixes the runtime issue but removes ARIA group-label semantics, which is an accessibility regression.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A["Electron Renderer Shell"] -->|"renders"| B["CanvasView\n(h-full container)"]
    B --> C["Title overlay\n(absolute, z-20)"]
    B --> D["Empty-state hint\n(absolute, pointer-events-none)"]
    B --> E["Inner wrapper\n(h-full)"]
    E --> F["Canvas component\n(fills inner wrapper)"]

    G["Menu trigger"] --> H["BaseMenu.Root / Popup"]
    H --> I["MenuItem(s)"]
    H --> J["MenuLabel\n(plain div — no BaseMenu.GroupLabel)"]
    H --> K["MenuSeparator\n(BaseMenu.Separator)"]
Loading

Last reviewed commit: 49c8459

render(<CanvasView docId="canvas-1" />)

const canvas = screen.getByTestId('mock-canvas')
const canvasHost = canvas.parentElement?.parentElement
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Brittle DOM traversal for host element lookup

The test navigates up the DOM via canvas.parentElement?.parentElement to find the canvas host container. This couples the test to the exact depth of nesting between the mock-canvas element and the target div. If an additional wrapper element is ever introduced inside <div className="h-full"> (the inner wrapper at line 247 of CanvasView.tsx), this traversal silently resolves to the wrong element and the assertion either gives a false positive or a confusing failure.

A more resilient approach is to add a data-testid to the host div in CanvasView.tsx and query it directly:

// CanvasView.tsx line 230
<div data-testid="canvas-host" className="relative h-full overflow-hidden">
// CanvasView.test.tsx
const canvasHost = screen.getByTestId('canvas-host')
expect(canvasHost.className).toContain('h-full')

This makes the test resilient to structural changes while still locking the h-full behaviour.

Comment on lines 117 to 119
export function MenuLabel({ children }: { children: React.ReactNode }) {
return (
<BaseMenu.GroupLabel className="px-2 py-1.5 text-xs font-semibold text-foreground-muted">
{children}
</BaseMenu.GroupLabel>
)
return <div className="px-2 py-1.5 text-xs font-semibold text-foreground-muted">{children}</div>
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Accessibility regression: ARIA group label semantics removed

Replacing BaseMenu.GroupLabel with a plain <div> fixes the crash (the Base UI primitive requires a BaseMenu.Group ancestor to supply its context), but it drops the semantic ARIA association. BaseMenu.GroupLabel renders with role="group" labelling semantics so that screen readers can announce the label when entering the group. The plain <div> has no implicit ARIA role, so assistive technology users will no longer hear the label when navigating through the menu.

If the intention is to avoid the crash entirely, the minimal fix that preserves semantics is to wrap any MenuLabel usage in a BaseMenu.Group:

// at the call site
<BaseMenu.Group>
  <MenuLabel>Section heading</MenuLabel>
  <MenuItem ></MenuItem>
</BaseMenu.Group>

Alternatively, if the MenuLabel component must be usable without a group parent, emit a <div role="presentation"> or <div role="group" aria-label={…}> to maintain at least partial semantics. The current plain <div> is silent to screen readers.

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