Skip to content

feat: Let hosts dock the action menu to the top - #995

Open
ivnnv wants to merge 8 commits into
pascalorg:mainfrom
ivnnv:action-menu-placement
Open

ivnnv wants to merge 8 commits into
pascalorg:mainfrom
ivnnv:action-menu-placement

Conversation

@ivnnv

@ivnnv ivnnv commented Oct 4, 2026 •

Copy link
Copy Markdown

Right now the viewer loses two strips of space, the top one for the toolbar row and the bottom one for the action menu, and hosts cant change that since the menu position is hardcoded in the editor (just floating it at the top doesnt work either, as its centered on the whole viewer so it lands on top of the toolbar groups and covers the camera controls hint, 2nd screenshot). Docking the menu into the toolbar row gives the whole bottom strip back to the canvas.

This adds an opt-in actionMenuPlacement prop to Editor ('bottom' by default so nothing changes for anyone, or 'top'). With 'top' the v2 layout renders the menu in a new center slot of the viewer toolbar row, in between the side groups and at the same height (tooltips and popovers inside it open downwards). When the three dont fit in one row the menu goes under the left group if theres room beside a taller right group, otherwise on its own centered row, and the level selector and camera hint now sit under wherever the toolbar actually ends instead of a fixed offset, so nothing gets covered (with the default bottom menu they stay exactly where they were). On the older v1 layout it just floats at the top edge, and mobile keeps the bottom rail as it is.

  1. Default, nothing changes: menu at the bottom

default

  1. Just floating the menu at the top: it overlaps the right toolbar group (needs the extra fix)

floating

  1. actionMenuPlacement="top": docked in the toolbar row, bottom strip free

top

  1. Narrow viewer: the menu gets its own row below the side groups

narrow


Note

Low Risk
UI layout and overlay positioning only; default bottom preserves existing behavior, with resize-driven CSS vars as the main integration surface for hosts.

Overview
Adds an opt-in actionMenuPlacement prop on Editor ('bottom' default, 'top' to dock the action menu at the top). On layout v2 desktop, 'top' renders the menu inline in a new center viewer-toolbar slot between left/right groups instead of as a bottom floater, freeing the bottom canvas strip.

EditorLayoutV2 gains viewerToolbarCenter and responsive toolbar layout: a ResizeObserver chooses inline vs wrapped placement and sets CSS variables (--viewer-toolbar-bottom, --viewer-toolbar-right-bottom, --viewer-toolbar-full-bottom) so overlays track the real toolbar height.

ActionMenu supports placement and inline; a placement context drives tooltip/popover direction (open away from the dock edge). Floating level selector, camera controls hint, and RightStack use those variables (and reserveBottomMenu) to avoid overlapping the toolbar or bottom menu. v1 can float the menu at the top; mobile stays bottom-docked. ActionMenuPlacement is exported for hosts.

Reviewed by Cursor Bugbot for commit 5dd2291. Bugbot is set up for automated code reviews on this repo. Configure here.

ivnnv added 5 commits October 3, 2026 23:43
Add an actionMenuPlacement editor prop ('bottom' | 'top', default 'bottom').
Tooltips and popovers inside the menu open away from the docked edge.
Mobile keeps the bottom rail.
A floating top menu is centered on the whole viewer, so it overlaps the host's
toolbar groups and covers the camera controls hint. In layout v2 the menu now
sits in a new center slot of the toolbar row, between the side groups and level
with them; the camera hint moves below it. Layout v1 keeps a floating menu at
the top edge.
The side groups are normally the same height, so nothing moves by default; a
host that stacks a group vertically on narrow windows no longer pushes the
other group down.
When the side groups and the docked menu don't fit in one row, the menu moves
to its own centered row below the side groups instead of pushing the right
group out of view. The layout publishes where the toolbar ends, and the level
selector and camera hint sit below that, so nothing they cover changes with
the row height. With the default bottom menu nothing moves. The camera hint
also only makes room for a top menu that is really docked (not on mobile).
@pascal

pascal Bot commented Oct 4, 2026

Copy link
Copy Markdown

What this does

Adds an opt-in actionMenuPlacement prop to Editor so a host can dock the action menu into the viewer's top toolbar row instead of floating it at the bottom. Default stays 'bottom', so existing hosts see no change. With 'top' on desktop and layout v2, the menu renders in a new center slot of the toolbar row, and the bottom strip of the viewer goes back to the canvas. The layout now measures the three toolbar groups: when they don't fit on one line the center group drops to its own centered row, and the row's bottom edge is published as a --viewer-toolbar-bottom CSS variable so the level selector and the camera controls hint sit below the toolbar wherever it actually ends. Tooltips and popovers inside the menu flip to open downwards when it is docked at the top. Mobile keeps the bottom rail, and v1 just floats the menu at the top edge.

File Change What it does
packages/editor/src/components/editor/editor-layout-v2.tsx modified RightColumn gains a toolbarCenter slot, a ResizeObserver that moves the center group to its own row when the three groups don't fit, and publishes --viewer-toolbar-bottom
packages/editor/src/components/editor/index.tsx modified New actionMenuPlacement prop; on desktop v2 it renders <ActionMenu inline placement="top" /> in the toolbar center slot instead of the overlay, and passes the hint offset down to ViewerCanvas
packages/editor/src/components/ui/action-menu/index.tsx modified inline and placement props, wraps the menu in the placement provider, forces 'bottom' on mobile
packages/editor/src/components/ui/action-menu/placement.ts added ActionMenuPlacement type, its context, and useActionMenuPopupSide
packages/editor/src/components/ui/action-menu/action-button.tsx modified Tooltip side falls back to the placement-aware side instead of a fixed one
packages/editor/src/components/ui/action-menu/measurement-control.tsx modified Popover opens away from the docked edge
packages/editor/src/components/ui/action-menu/view-toggles.tsx modified Same popover side handling for the toggles' popovers
packages/editor/src/components/ui/floating-level-selector.tsx modified Top offset reads --viewer-toolbar-bottom with the old value as fallback
packages/editor/src/index.tsx modified Exports the ActionMenuPlacement type

Best place to start: the RightColumn effect in editor-layout-v2.tsx, since the wrap decision and the CSS variable drive everything the overlays do, then the wiring in components/editor/index.tsx.

@ivnnv ivnnv changed the title Let hosts dock the action menu to the top feat: Let hosts dock the action menu to the top Oct 4, 2026

@cursor cursor Bot left a comment •

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Stale Bugbot comment from a previous run.

Comment thread packages/editor/src/components/editor/editor-layout-v2.tsx Outdated
Comment thread packages/editor/src/components/editor/editor-layout-v2.tsx
When the menu does not fit inline it goes under the left group if the right
group is tall enough to leave room there, else on its own full-width row. Only
the menu takes clicks on that row, so the empty space beside it still reaches
the canvas. Each side of the toolbar publishes its own bottom edge and the
inspector column sits below the right side instead of a fixed top-20.

@cursor cursor Bot left a comment •

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Stale Bugbot comment from a previous run.

const centerBox = centerRef.current
column.style.setProperty(
'--viewer-toolbar-bottom',
`${Math.max(bottomOf(leftRef.current), bottomOf(centerBox))}px`,

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Overlay offset double-counts toolbar top

Medium Severity

--viewer-toolbar-bottom is written as a column-relative Y, including the toolbar's top-3 offset, but consumers still add 0.75rem on a fallback that is only content height. On v2 the level selector, camera hint, and RightStack therefore sit about 12px lower than before, including with the default bottom menu.

Additional Locations (2)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit d6676e2. Configure here.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

i dont think so, the measured bottom and the 2.75rem fallback are both top-3 + the 32px row (44px), so +0.75rem lands on the same 56px as the old top-14. checked default before/after, level selector and hint at 56, inspector at 80

Comment thread packages/editor/src/components/editor/editor-layout-v2.tsx

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes using high effort and found 2 potential issues.

There are 3 total unresolved issues (including 1 from previous review).

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 25612a8. Configure here.

Comment thread packages/editor/src/components/ui/right-stack.tsx
Comment thread packages/editor/src/components/editor/editor-layout-v2.tsx
…top menu

The camera hint now sits below the full toolbar height, so a taller right
group or a missing left group can't put it inside the toolbar row. With the
menu docked at the top, the inspector column no longer keeps the bottom
clearance meant for a bottom menu.

This branch has not been deployed

No deployments
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