fix: Engine Control popover collapsed to ~trigger width (FN-8802 .card clamp) (#3363)
## What & why RUFU-042. The open **Engine Controls** popover (footer status bar, bottom-right) carries the shared `.card` class. Since FN-8802, `.card` bases set `min-width: 0; max-width: 100%` (TaskCard.css). The popover's containing block (`.engine-control-menu`) sizes to the narrow trigger button, so `.card`'s `max-width: 100%` clamped the intended `24rem` grid down to ~the trigger's width — a **~5mm-wide invisible popover**. ## Fix (CSS only, `EngineControlMenu.css`) - Footer-scoped desktop rule (`0,3,0`) re-asserts `min-width`/`max-width` clamped to the **viewport** (not the trigger wrapper), deterministically beating the shared `.card` (`0,1,0`) by specificity — same pattern as `.selection-comment-panel.card`. - Mobile `@media (max-width:1024px)` resets `min-width:0; max-width:none` so the full-width gutter panel cannot overflow nor be re-clamped by `.card`. - No `className="card"` removal; shared `.card` base untouched. ## Regression tests Two new tests in `EngineControlMenu.test.tsx` assert the desktop min/max guard and the mobile reset, so the collapse cannot silently return. **17/17 tests pass.** No changeset (`@fusion/dashboard` is a private package). <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Bug Fixes** * Improved engine control popovers so they size correctly without collapsing or overflowing. * Enhanced mobile layouts to maintain full-width display with appropriate screen gutters. * **Tests** * Added regression coverage for desktop width limits and narrow-screen popover behavior. <!-- end of auto-generated comment: release notes by coderabbit.ai --> Co-authored-by: Fusion <noreply@runfusion.ai> Co-authored-by: gsxdsm <gsxdsm@users.noreply.github.com>
This commit is contained in:
@@ -2,8 +2,24 @@
|
||||
position: relative;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
width: max-content;
|
||||
}
|
||||
|
||||
/*
|
||||
FNXC:EngineControls 2026-08-08-15:40 (FN-8802 width-collapse regression, RUFU-042):
|
||||
The open popover carries the shared `.card` class, whose base now sets `min-width: 0` and
|
||||
`max-width: 100%` (FN-8802, TaskCard.css). Its containing block is this `.engine-control-menu`
|
||||
wrapper, which sizes to the narrow trigger button; `.card`'s `max-width: 100%` therefore
|
||||
clamped the intended grid width down to ~the trigger's width (~5mm), hiding all content.
|
||||
|
||||
The selected text (width/min-width/max-width) below must beat `.card` deterministically, so it
|
||||
targets the popover in its only real mount context (the ExecutorStatusBar footer segment) with
|
||||
higher specificity — the same pattern used by `.selection-comment-panel.card`. `max-width` is
|
||||
clamped to the VIEWPORT (not the trigger wrapper), `min-width` sets the floor so it can never
|
||||
collapse to a sliver, and the footer-scoped overrides re-assert the width so later `.card` rules
|
||||
cannot win by load order.
|
||||
*/
|
||||
|
||||
.engine-control-menu__trigger {
|
||||
color: var(--text-muted);
|
||||
}
|
||||
@@ -186,9 +202,15 @@ FN-8007 defines both desktop pseudo-thumbs locally with the marker's shared size
|
||||
}
|
||||
|
||||
.executor-status-bar__segment--engine-controls .engine-control-menu > .engine-control-menu__popover.card {
|
||||
/* RUFU-042 (FN-8802 regression): this footer-scoped rule (0,3,0) out-specifies the shared
|
||||
`.card` base (0,1,0), which sets `min-width: 0; max-width: 100%` (TaskCard.css). Without
|
||||
these re-assertions `.card` could clamp the popover to its narrow trigger wrapper (~5mm).
|
||||
`max-width` is clamped to the VIEWPORT, not the trigger, so the grid width survives. */
|
||||
position: absolute;
|
||||
right: 0;
|
||||
bottom: calc(100% + var(--space-xs));
|
||||
min-width: min(24rem, calc(100vw - (var(--space-lg) * 2)));
|
||||
max-width: calc(100vw - (var(--space-lg) * 2));
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
@@ -232,6 +254,9 @@ FN-8007 defines both desktop pseudo-thumbs locally with the marker's shared size
|
||||
right: var(--space-sm);
|
||||
bottom: var(--engine-control-mobile-bottom-stack);
|
||||
width: auto;
|
||||
/* RUFU-042 (FN-8802 regression): reset the desktop viewport min/max floor so the phone-width gutter panel never overflows; `.card`'s max-width:100% cannot clamp the left/right-stretched panel. */
|
||||
min-width: 0;
|
||||
max-width: none;
|
||||
max-height: min(28rem, calc(100dvh - var(--engine-control-mobile-bottom-stack) - (var(--space-md) * 2)));
|
||||
overflow: auto;
|
||||
}
|
||||
@@ -243,6 +268,8 @@ FN-8007 defines both desktop pseudo-thumbs locally with the marker's shared size
|
||||
right: var(--space-sm);
|
||||
bottom: var(--engine-control-mobile-bottom-stack);
|
||||
width: auto;
|
||||
min-width: 0;
|
||||
max-width: none;
|
||||
max-height: min(28rem, calc(100dvh - var(--engine-control-mobile-bottom-stack) - (var(--space-md) * 2)));
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
@@ -427,4 +427,32 @@ describe("EngineControlMenu", () => {
|
||||
|
||||
expect(await screen.findByRole("alert")).toHaveTextContent("settings unavailable");
|
||||
});
|
||||
|
||||
// FNXC:EngineControls 2026-08-08-15:40 (FN-8802 width-collapse regression, RUFU-042):
|
||||
// The open popover carries the shared `.card` class, whose base now sets `min-width: 0` and
|
||||
// `max-width: 100%` (TaskCard.css). Its containing block is `.engine-control-menu` which sizes
|
||||
// to the narrow trigger button, so `.card`'s `max-width: 100%` clamped the popover's intended
|
||||
// grid width down to ~the trigger's width (~5mm). The footer-scoped rule (0,3,0) must re-assert
|
||||
// a VIEWPORT-clamped min/max width that beats `.card` (0,1,0), so the menu can never collapse
|
||||
// to a sliver. Keep this guard asserted so the fix cannot silently regress.
|
||||
it("keeps the footer-scoped popover width immune to the shared `.card` clamp on desktop", () => {
|
||||
const footerPopover = cssRule(engineControlMenuCss, ".executor-status-bar__segment--engine-controls .engine-control-menu > .engine-control-menu__popover.card");
|
||||
expect(footerPopover).toContain("position: absolute;");
|
||||
expect(footerPopover).toContain("min-width: min(24rem, calc(100vw - (var(--space-lg) * 2)));");
|
||||
expect(footerPopover).toContain("max-width: calc(100vw - (var(--space-lg) * 2));");
|
||||
});
|
||||
|
||||
// FNXC:EngineControls 2026-08-08-15:40 (FN-8802 width-collapse regression, RUFU-042):
|
||||
// On narrow/tablet widths the popover becomes a full-width gutter panel (`left/right: var(--space-sm)`).
|
||||
// It must reset the desktop min/max floor and defeat `.card`'s `max-width: 100%` so the phone panel
|
||||
// stays full-width without overflowing. Assert the media-query rules only (cssRule grabs the first
|
||||
// selector match, which is the desktop base rule, so match the @media block explicitly).
|
||||
it("keeps the mobile popover full-width and never overflowed by the desktop min-width floor", () => {
|
||||
const mobileBlock = engineControlMenuCss.match(/@media \(max-width: 1024px\) \{([\s\S]*?)\}/)?.[1] ?? "";
|
||||
expect(mobileBlock).toContain("left: var(--space-sm);");
|
||||
expect(mobileBlock).toContain("right: var(--space-sm);");
|
||||
expect(mobileBlock).toContain("max-width: none;");
|
||||
expect(mobileBlock).toContain("min-width: 0;");
|
||||
expect(mobileBlock).toContain("width: auto;");
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user