fix(copilot): keep sidebar mode beside host content instead of overlapping it - #3029
fix(copilot): keep sidebar mode beside host content instead of overlapping it#3029RoyBA wants to merge 10 commits into
Conversation
…pping it In sidebar display mode, reserve space for the panel with body margin-right and suspend the containing-block properties the host may set on <body> (transform, perspective, will-change) while the sidebar is open — all restored on close. Those properties make <body> the containing block for the fixed sidebar, re-anchoring it to the margin-shrunk body: the sidebar gets pushed (white gap) and, on tall pages, stretches to the document height and scrolls with the page. Suspending them keeps the sidebar a true viewport-fixed panel and leaves the host's own layout untouched. Co-Authored-By: GitHub Copilot <noreply@github.com>
…pps in sidebar mode Viewport-filling hosts (100vw / position: absolute inset shells like maps and dashboards) ignore the body margin, so the sidebar overlapped them. Add an optional hostRoot widget config: when set, sidebar mode constrains that element's width to calc(100vw - sidebarWidth) instead of nudging the body margin, restored on close. No behavior change when it is unset. Co-Authored-By: GitHub Copilot <noreply@github.com>
There was a problem hiding this comment.
All reported issues were addressed across 4 files
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
Share a single getHostRoot helper and re-query the host on cleanup instead of reusing a cached node; use overflow-x: clip (not hidden) so the host does not become a scroll container; toggle the drag transition on whichever element is reserved so host-width drags animate too. Co-Authored-By: GitHub Copilot <noreply@github.com>
There was a problem hiding this comment.
All reported issues were addressed across 1 file (changes from recent commits).
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
…idth before transition Cleanup now restores the exact node it styled using that node's captured styles, and undoes the body-margin reservation whenever the body fallback was used, so a hostRoot that is swapped or removed while open no longer leaves the wrong node or the body in a stale state. Also flush the host width before enabling its transition: Chromium cannot interpolate width from auto to calc(), so it stuck the host at its pre-open width and never shrank. The body margin animates from 0 and is unaffected. Co-Authored-By: GitHub Copilot <noreply@github.com>
There was a problem hiding this comment.
All reported issues were addressed across 1 file (changes from recent commits).
Tip: Review your code locally with the cubic CLI to iterate faster.
Re-trigger cubic
…malization The browser rewrites inline style values: translateZ(0) becomes translateZ(0px) and calc(100vw - 400px) becomes calc(-400px + 100vw). Assert the restored transform against the normalized value and check the hostRoot width via its bounding rect instead of the raw calc string. Co-Authored-By: GitHub Copilot <noreply@github.com>
…ssion reserveSpace resolves the host fresh each call to handle SPA node swaps, but cleanup only restored the node captured at open, leaving a swapped-in host stuck at width: calc(100vw - Xpx). Track each styled host node in a ref map and restore them all on close. Co-Authored-By: GitHub Copilot <noreply@github.com>
There was a problem hiding this comment.
All reported issues were addressed across 1 file (changes from recent commits).
Tip: Review your code locally with the cubic CLI to iterate faster.
Re-trigger cubic
… fallback The host path never touches body margin-right or transition, so restoring them unconditionally on close clobbered any host-app updates made while the sidebar was open. Restore them only when no host node was constrained. Co-Authored-By: GitHub Copilot <noreply@github.com>
There was a problem hiding this comment.
All reported issues were addressed across 1 file (changes from recent commits).
Tip: Review your code locally with the cubic CLI to iterate faster.
Re-trigger cubic
hosts.size doubled as the body-fallback signal, so a hostRoot that disappeared mid-session (map non-empty, body margin written) skipped the margin restore and left the page shifted. Add a usedBodyFallback ref set on each body-branch write and reset per session; cleanup restores all host nodes always and body margin/transition only when the fallback was used. Co-Authored-By: GitHub Copilot <noreply@github.com>
Summary
In the Copilot widget's sidebar display mode, the fixed panel could overlap host content or leave a white gap on some host pages. This PR fixes that: the sidebar now stays pinned as a true viewport-height panel beside the host content, and it also handles viewport-filling host apps (maps/dashboards) through an opt-in config.
Root cause
The widget reserves space with
body { margin-right }, which only works while the fixed sidebar is anchored to the viewport and the host content flows inside the body's content box. Two host situations break that:<body>— if the host setstransform(commonlytranslateZ(0)),perspective, orwill-changeon<body>, that element becomes the containing block for the fixed sidebar, which re-anchors to the margin-shrunk body: the sidebar gets pushed (leaving a white gap) and, on tall pages, stretches to the full document height and scrolls with the page.100vw/position: absolute; inset: 0, e.g. a full-screen map) don't live in the body's content box, so a body margin can't shrink them and the sidebar overlaps.How to reproduce
The bug only appears when the host page makes
<body>a containing block for fixed elements (via atransform/perspective/will-change— commonly atranslateZ(0)GPU hint) or when the host fills the viewport. A plain host page won't show it.1. Start a Chainlit server (any app), e.g.
chainlit run app.pyonhttp://localhost:8000.2. Serve this host page from a static server (not
file://) and open it:3. Observe the sidebar.
Viewport-filling variant (
hostRoot)Give the host a full-screen shell instead of normal-flow content:
hostRoot, the sidebar overlaps it — a body margin can't shrink a100vw/ absolute-inset layout.hostRoot: "#root"tomountChainlitWidget, and the app reflows into the reduced width beside the sidebar.Fix
While the sidebar is open, on
<body>we suspend the containing-block properties (transform,perspective,will-change) so the fixed sidebar stays anchored to the viewport, and reserve space withmargin-right.For viewport-filling apps, a new opt-in
hostRootconfig lets integrators name their app root; when set, that element's width is constrained tocalc(100vw - sidebarWidth)instead of the body margin. Everything is saved and restored on close / mode-switch / unmount.There is no DOM reparenting and no style copying, so the host's own layout and native scrollbar are preserved.
Summary by cubic
Fixes the Copilot widget sidebar so it stays beside host content instead of overlapping it or leaving a white gap.
Bug Fixes
transform,perspective, andwill-changeon<body>while the sidebar is open, keeping the fixed panel viewport-anchored.hostRootnode is swapped or removed while open, and undoes the body margin only when the fallback was used.New Features
hostRootconfig for viewport-filling shells (e.g. maps) that ignore body margins.calc(100vw - sidebarWidth)instead of the body margin.Written for commit 4537875. Summary will update on new commits.