FE-1590: Keep the bottom toolbar clear of the panels around it - #9533
FE-1590: Keep the bottom toolbar clear of the panels around it#9533kube wants to merge 7 commits into
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
1 Skipped Deployment
|
dcef401 to
68924cd
Compare
The bar stays centered on the canvas until a panel would cover it, then shifts to the free side with a margin. Where the space between the panels is too narrow for the full set of controls it collapses to the cursor, the diagnostics status and Play, expanding again while the pointer or the keyboard is on it.
Each group measures from an effect keyed on the callback, so a fresh one per render would disconnect the observers and report a width in a loop.
The segment's transition was `all 0.3s`, so a collapsing group animated the glass panel's width over twice the group's own 150ms, and the offset, which transitioned on a curve of its own, pulled the bar past its place and back. The transition now names the two properties the hover effect changes, and the bar only animates its offset while a panel opens or closes: a collapse keeps it glued to the width it is measured at, and a resize drag to the panel edge. Hover expansion settles in 174ms rather than 315ms, a collapse in 86ms rather than 201ms.
The bar rode above the bottom panel on its `bottom`, which the main thread animates, while the panel slides on a transform the compositor animates. The frames dropped while the panel's content mounts leave a layout-driven animation behind, so the bar arrived after the panel it is meant to sit on. Lane now holds a fixed inset and both axes ride one transform. Collapse decelerates over 120ms instead of easing in and out over 150ms: hovering moved 0.3% of the way in the first frame and now moves 22%, and the bar settles in 133ms rather than 174ms.
Keeps the toolbar clear of the assistant panel, which paints over it: the panel's width moves from its own state into the editor's, and one derivation of the panel insets now serves both the toolbar and the viewport controls, which were hidden behind the assistant for the same reason. Reveals the hidden controls from CSS rather than mirrored state. A control that unmounts while focused fires no blur, so the focus flag could stay set and leave the toolbar stranded open; `:focus-within` cannot go stale. Only the click-hold stays in JavaScript, for the menus that render outside the bar. Takes the measurement and the fold policy out of the component into `useBottomBarLayout`, drops the forked width hook for the package's own `useElementSize`, and splits the toolbar's two dropdowns into their own files around the trigger they share. While a panel animates, the offset now follows the width the bar is heading for, so its transition is not restarted every frame. Folding eases in over 160ms and revealing decelerates over 120ms, since only one of the two answers a pointer.
68924cd to
09661be
Compare
PR SummaryLow Risk Overview When space is still too tight, non-essential controls collapse into Reviewed by Cursor Bugbot for commit 3159005. Bugbot is set up for automated code reviews on this repo. Configure here. |
There was a problem hiding this comment.
🟡 Changes recommended
Keyboard-opened portalled menus do not hold the toolbar expanded while active.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Pull request overview
Keeps Petrinaut’s bottom toolbar clear of surrounding panels and viewport controls.
Changes:
- Adds measured toolbar placement and collapsible control groups.
- Centralizes canvas insets and AI assistant width in editor state.
- Adds geometry tests, documentation, and a patch changeset.
File summaries
| File | Description |
|---|---|
.changeset/bottom-bar-panel-clearance.md |
Adds the package changeset. |
libs/@hashintel/petrinaut/docs/drawing-a-net.md |
Documents toolbar placement and folding. |
libs/@hashintel/petrinaut/docs/simulation.md |
Documents collapsed playback controls. |
libs/@hashintel/petrinaut/src/react/hooks/use-petrinaut-commands.test.tsx |
Updates the editor context fixture. |
libs/@hashintel/petrinaut/src/react/hooks/use-petrinaut-mutations.test.tsx |
Updates the editor context fixture. |
libs/@hashintel/petrinaut/src/react/state/editor-context.ts |
Adds assistant-width state and action. |
libs/@hashintel/petrinaut/src/react/state/editor-provider.tsx |
Implements assistant-width updates. |
libs/@hashintel/petrinaut/src/react/state/panel-defaults.ts |
Defines the default assistant width. |
libs/@hashintel/petrinaut/src/ui/constants/ui.ts |
Exposes viewport-control geometry. |
libs/@hashintel/petrinaut/src/ui/hooks/use-canvas-insets.test.ts |
Tests shared panel insets. |
libs/@hashintel/petrinaut/src/ui/hooks/use-canvas-insets.ts |
Derives canvas insets from editor state. |
libs/@hashintel/petrinaut/src/ui/views/Editor/components/BottomBar/bottom-bar-placement.test.ts |
Tests toolbar placement geometry. |
libs/@hashintel/petrinaut/src/ui/views/Editor/components/BottomBar/bottom-bar-placement.ts |
Calculates fit and horizontal offset. |
libs/@hashintel/petrinaut/src/ui/views/Editor/components/BottomBar/bottom-bar.tsx |
Integrates placement and folding behavior. |
libs/@hashintel/petrinaut/src/ui/views/Editor/components/BottomBar/collapse-context.ts |
Defines collapsible-group context. |
libs/@hashintel/petrinaut/src/ui/views/Editor/components/BottomBar/collapsible-group.tsx |
Animates and measures folded controls. |
libs/@hashintel/petrinaut/src/ui/views/Editor/components/BottomBar/cursor-mode-dropdown.tsx |
Extracts the persistent cursor selector. |
libs/@hashintel/petrinaut/src/ui/views/Editor/components/BottomBar/edition-tools.tsx |
Extracts collapsible editing tools. |
libs/@hashintel/petrinaut/src/ui/views/Editor/components/BottomBar/simulation-controls.tsx |
Groups collapsible playback controls. |
libs/@hashintel/petrinaut/src/ui/views/Editor/components/BottomBar/toolbar-menu-trigger.tsx |
Adds a shared dropdown trigger. |
libs/@hashintel/petrinaut/src/ui/views/Editor/components/BottomBar/toolbar-modes.tsx |
Removes the superseded combined component. |
libs/@hashintel/petrinaut/src/ui/views/Editor/components/BottomBar/use-bottom-bar-layout.ts |
Owns measurement, folding, and placement state. |
libs/@hashintel/petrinaut/src/ui/views/Editor/panels/ai-assistant-panel.test.tsx |
Updates the editor context fixture. |
libs/@hashintel/petrinaut/src/ui/views/Editor/panels/ai-assistant-panel/ai-assistant-contents.tsx |
Moves assistant width into editor state. |
libs/@hashintel/petrinaut/src/ui/views/Editor/panels/SimulateView/experiments/experiments-story-fixtures.tsx |
Updates the story fixture. |
libs/@hashintel/petrinaut/src/ui/views/SDCPN/components/viewport-controls.tsx |
Uses shared insets for positioning. |
Review details
- Files reviewed: 26/26 changed files
- Comments generated: 1
- Review effort level: Balanced
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
`Menu` mounts its trigger through Ark's `asChild`, which clones the element to attach the click handling, the trigger ref and its ARIA. Wrapping the button in a component that consumed only its own props dropped all of that, so neither the cursor-mode nor the add-component dropdown opened.
fc6a3e2 to
c117f5e
Compare
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 2 potential issues.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit c117f5e. Configure here.
The click-hold was released by the very menus it protected. A menu opened from the toolbar renders in a portal outside it, so a click on a row that leaves the menu open failed the containment check, cleared the hold, and folded the bar under its own open menu — with the menu still anchored to a control that had just been clipped away. Opening a menu from the keyboard never took the hold at all. The reveal now keys on the menu's own open state, the way the sidebar's row actions already do, so hover, focus and an open menu are the three CSS selectors that reveal the controls and the JavaScript hold is gone. Ark marks its own menu triggers; the playback popover renders its trigger externally, so that one marks itself, which `ToolbarButton` can now carry.

Summary
Before this PR, the bottom toolbar was centered on the canvas by a fixed transform that knew nothing about the panels around it. Left sidebar, properties panel and viewport controls all sit in its row, and playback adds a 300px scrubber to it, so a wide panel or a narrow window left the toolbar overlapping a panel or sliding under the zoom column.
Toolbar now measures the space docked around it. It stays centered on the canvas while it clears both sides, shifts to the free side with a 12px margin when it would not, and folds to the cursor, the panel toggle, the diagnostics status and Play when even that leaves too little room. Pointer or keyboard focus on the toolbar brings the hidden controls back for as long as it stays there. One derivation of the panel insets serves the toolbar and the viewport controls, so the assistant panel no longer covers either.
Both recordings run the same path: select a place, drag the properties panel wider, hover the toolbar, deselect, open the bottom panel.
Before
9533-before-1800.mp4
After
9533-after-1800.mp4
Links
Changes
Placement
Toolbar sits in a full-width lane and moves by transform
bottom-bar-placement.tsholds the geometry as pure functionsInsets come from panel state, not from measuring the panels
Viewport controls publish their offset and width as constants
Bar rides both axes on one composited transform
Segment transition names its properties instead of
allCollapse decelerates over 120ms rather than easing in and out over 150ms
Assistant panel width moves into editor state
useCanvasInsetsderives what the panels cover, onceFolding
useBottomBarLayoutowns the measurement and the fold policyCollapsibleGroupmarks the controls that give wayToolbarModessplits intoCursorModeDropdownandEditionToolsTest coverage
bottom-bar-placement.test.ts:use-canvas-insets.test.ts:Review fixes
Known issues
How to test