Conversation
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
The command, favorite, and mode picker popovers rendered their content inline. In the widget's floating mode the chat panel is itself a transformed Radix popper, which becomes the containing block for the fixed-positioned popovers and breaks floating-ui's scale compensation under host zoom/font-size, throwing them off-screen. Portal each popover into cl_shadowRootElement (the convention the shared ui/* primitives already use) and set an explicit z-index on each picker's content so Radix copies it onto the popper wrapper, keeping them above the z-50 chat. This matches how ui/popover, dropdown, select set z-50 on their own content and avoids a global wrapper override. Co-Authored-By: GitHub Copilot <noreply@github.com>
d20929c to
3209114
Compare
|
@RoyBA Any chance for tests on this one? |
Add tests for the three composer pickers verifying each popover is portaled into cl_shadowRootElement and carries the z-[51] stacking class that keeps it above the chat surfaces. Co-Authored-By: GitHub Copilot <noreply@github.com>
There was a problem hiding this comment.
All reported issues were addressed across 3 files (changes from recent commits).
Tip: Review your code locally with the cubic CLI to iterate faster.
Re-trigger cubic
Address review: use attachShadow instead of a plain div and assert the popover lands in the encapsulated shadow tree (not the light DOM), add a standalone document.body fallback test, centralize the ResizeObserver/scrollIntoView shims in setup-tests, and move shadow-host cleanup into afterEach. Co-Authored-By: GitHub Copilot <noreply@github.com>
There was a problem hiding this comment.
All reported issues were addressed across 5 files (changes from recent commits).
Tip: Review your code locally with the cubic CLI to iterate faster.
Re-trigger cubic
Address review: move cleanupShadowHosts into setup-tests' global afterEach so mountShadowHost consumers can't leak the DOM host or the cl_shadowRootElement global, removing the per-spec afterEach boilerplate. Co-Authored-By: GitHub Copilot <noreply@github.com>
@dokterbob Added unit tests for all three composer pickers |
|
This PR is stale because it has been open for 14 days with no activity. |
Summary
In the Copilot widget, the message-composer popovers — tools picker (
CommandPopoverButton),ModePicker, andFavoriteButton— could render far off-target (and, once portaled, behind the chat) when the widget is embedded in a host page that scales it. This fixes both the positioning and the stacking, scoped to the widget's shadow DOM. The standalone Chainlit app is unaffected.How to reproduce
html { font-size: 10px }(common in some design systems). The widget's own text now renders tiny and hard to read.customCssUrl:A transformed host root reproduces the same thing without
zoom— e.g.body { transform: translateZ(0) }(orfilter/perspective/will-change: transform), which is common on real hosts.Root causes
Two compounding, shadow-DOM-specific issues:
zoom/transform/ rootfont-size. The popovers rendered theirPopoverContentinline (no Portal). In floating mode the whole chat panel is itself a Radix popper whose wrapper carries atransform, so it becomes the containing block for the popovers'position: fixedcontent. floating-ui can't compensate for the combined host scale + panel transform, so the computed offset drifts — and the drift grows with the zoom factor, pushing the popover off-screen.z-indexonto[data-radix-popper-content-wrapper]as an inline style. These pickers set noz-index, so the wrapper inlinesautoand loses to the widget'sz-50chat surfaces.Fix
<PopoverPortal container={window.cl_shadowRootElement}>— the convention the sharedfrontend/src/components/ui/*primitives already use. This moves the content out of the transformed/zoomed panel, so position is computed against the shadow root, not a scaled containing block. In the standalone app that global isundefined, so Radix falls back todocument.body(unchanged behavior).z-[51]on each picker's own content, so Radix copies it onto the popper wrapper (matching thez-50-on-content convention of the other poppers) and it stays above thez-50chat. Scoped per-component — no global rule, no!important, no effect on other poppers.Files changed
CommandPopoverButton.tsxModePicker.tsxFavoriteButton.tsxfrontend/tests/{CommandPopoverButton,ModePicker,FavoriteButton}.spec.tsx(tests)Testing
cl_shadowRootElementand carries thez-[51]stacking class.pnpm test→ 38/38.pnpm lint,pnpm format-check,pnpm type-checkpass.zoomand non-default rootfont-size, in light and dark themes.