FN-7333: stabilize Planner Chat expanded spacing
Stabilize Planner Chat task detail spacing across expanded and mobile layouts. - Move Planner Chat body padding to the base selector so expand/collapse only changes height and flex behavior. - Apply the mobile Planner Chat padding override to the same base body selector. - Add CSS regression coverage and a patch changeset for the published CLI bundle. Files changed: .changeset/planner-chat-stable-spacing.md | 7 ++++ .../dashboard/app/components/TaskDetailModal.css | 11 +++++- ...etailModal.responsive-and-dependencies.test.tsx | 44 ++++++++++++++++++++++ 3 files changed, 60 insertions(+), 2 deletions(-) Fusion-Task-Id: FN-7333 Fusion-Task-Lineage: 84130908-fabb-433f-a48d-5d9c6649c234 Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
This commit is contained in:
7
.changeset/planner-chat-stable-spacing.md
Normal file
7
.changeset/planner-chat-stable-spacing.md
Normal file
@@ -0,0 +1,7 @@
|
||||
---
|
||||
"@runfusion/fusion": patch
|
||||
---
|
||||
|
||||
summary: Keep Planner Chat spacing stable when expanding task details.
|
||||
category: fix
|
||||
dev: Stabilizes task-detail Planner Chat CSS so expanded mode changes height allocation without padding jumps.
|
||||
@@ -140,6 +140,14 @@ Task detail workflow badges share the board badge's slight token-based icon-to-l
|
||||
padding-block: var(--space-md);
|
||||
}
|
||||
|
||||
/*
|
||||
FNXC:TaskDetailPlannerChat 2026-06-30-23:58:
|
||||
Planner Chat expand/collapse may reallocate height or hide mobile chrome, but it must not change the chat surface spacing. Keep body padding on the collapsed base selector and let expanded selectors own only flex/height behavior.
|
||||
*/
|
||||
.detail-body--planner-chat {
|
||||
padding: var(--space-md);
|
||||
}
|
||||
|
||||
.detail-title {
|
||||
font-size: 18px;
|
||||
font-weight: 600;
|
||||
@@ -884,7 +892,6 @@ Expanded Planner Chat must still expose task Priority, Execution Mode, and the t
|
||||
.task-detail-content--planner-chat-expanded .detail-body--planner-chat {
|
||||
flex: 1;
|
||||
min-height: 0;
|
||||
padding: var(--space-md);
|
||||
}
|
||||
|
||||
.task-detail-content--planner-chat-expanded .detail-section--planner-chat {
|
||||
@@ -1196,7 +1203,7 @@ FN-6500 fixes a tablet regression from FN-5599: the task-detail overlay offset a
|
||||
margin-bottom: var(--space-sm);
|
||||
}
|
||||
|
||||
.task-detail-content--planner-chat-expanded .detail-body--planner-chat {
|
||||
.detail-body--planner-chat {
|
||||
padding: var(--space-sm);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -63,6 +63,12 @@ function getExactCssRuleBlock(css: string, selector: string): string {
|
||||
return ruleMatch?.[1] ?? "";
|
||||
}
|
||||
|
||||
function getStandaloneCssRuleBlock(css: string, selector: string): string {
|
||||
const escapedSelector = selector.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
||||
const ruleMatch = css.match(new RegExp(`(?:^|})\\s*${escapedSelector}\\s*\\{([^}]*)\\}`));
|
||||
return ruleMatch?.[1] ?? "";
|
||||
}
|
||||
|
||||
function getCssAtRuleBlockContainingExactRule(css: string, atRule: string, selector: string): string {
|
||||
let startAt = 0;
|
||||
while (startAt < css.length) {
|
||||
@@ -88,6 +94,12 @@ function expectTabTouchAction(ruleBlock: string, surface: string): void {
|
||||
expect(ruleBlock, `${surface} touch-action`).toContain("touch-action: pan-x pan-y;");
|
||||
}
|
||||
|
||||
function expectNoSpacingOverrides(ruleBlock: string, surface: string): void {
|
||||
expect(ruleBlock, `${surface} padding`).not.toMatch(/\bpadding(?:-[\w-]+)?:/);
|
||||
expect(ruleBlock, `${surface} margin`).not.toMatch(/\bmargin(?:-[\w-]+)?:/);
|
||||
expect(ruleBlock, `${surface} gap`).not.toMatch(/(?:^|\s)gap:/);
|
||||
}
|
||||
|
||||
describe("TaskDetailModal", () => {
|
||||
describe("mobile responsive structure", () => {
|
||||
it("keeps planner chat composer usable on narrow task-detail layouts", () => {
|
||||
@@ -149,6 +161,38 @@ describe("TaskDetailModal", () => {
|
||||
expect(plannerExpandedTabsBlock).toContain("flex: 0 0 auto;");
|
||||
});
|
||||
|
||||
it("keeps Planner Chat expand spacing identical across desktop and mobile", () => {
|
||||
const css = readDashboardStylesSource();
|
||||
const plannerBodySpacingStart = css.indexOf("Planner Chat expand/collapse may reallocate height");
|
||||
expect(plannerBodySpacingStart).toBeGreaterThanOrEqual(0);
|
||||
const plannerBodySpacingCss = css.slice(plannerBodySpacingStart, css.indexOf(".detail-title", plannerBodySpacingStart));
|
||||
const plannerBodyBlock = getExactCssRuleBlock(plannerBodySpacingCss, ".detail-body--planner-chat");
|
||||
const plannerPanelBlock = getExactCssRuleBlock(css, ".task-planner-chat");
|
||||
const plannerTranscriptBlock = getExactCssRuleBlock(css, ".task-planner-chat-transcript");
|
||||
const plannerComposerBlock = getExactCssRuleBlock(css, ".task-planner-chat-composer");
|
||||
const expandedPlannerBodyBlock = getExactCssRuleBlock(css, ".task-detail-content--planner-chat-expanded .detail-body--planner-chat");
|
||||
const expandedPlannerSectionBlock = getExactCssRuleBlock(css, ".task-detail-content--planner-chat-expanded .detail-section--planner-chat");
|
||||
const mobilePlannerBlock = getCssAtRuleBlockContaining(css, "@media (max-width: 768px)", ".task-detail-content--planner-chat-expanded .detail-meta");
|
||||
const mobilePlannerBodyBlock = getStandaloneCssRuleBlock(mobilePlannerBlock, ".detail-body--planner-chat");
|
||||
const mobileExpandedPlannerBodyBlock = getExactCssRuleBlock(mobilePlannerBlock, ".task-detail-content--planner-chat-expanded .detail-body--planner-chat");
|
||||
|
||||
expect(plannerBodyBlock).toContain("padding: var(--space-md);");
|
||||
expect(expandedPlannerBodyBlock).toContain("flex: 1;");
|
||||
expect(expandedPlannerBodyBlock).toContain("min-height: 0;");
|
||||
expectNoSpacingOverrides(expandedPlannerBodyBlock, "desktop expanded planner body");
|
||||
expect(expandedPlannerSectionBlock).toContain("flex: 1;");
|
||||
expect(expandedPlannerSectionBlock).toContain("min-height: 0;");
|
||||
expectNoSpacingOverrides(expandedPlannerSectionBlock, "desktop expanded planner section");
|
||||
expect(mobilePlannerBodyBlock).toContain("padding: var(--space-sm);");
|
||||
expect(mobileExpandedPlannerBodyBlock).toBe("");
|
||||
expect(plannerPanelBlock).toContain("gap: var(--space-md);");
|
||||
expect(plannerTranscriptBlock).toContain("padding: var(--space-md);");
|
||||
expect(plannerTranscriptBlock).toContain("gap: var(--space-md);");
|
||||
expect(plannerComposerBlock).toContain("gap: var(--space-sm);");
|
||||
expect(css).not.toMatch(/task-detail-content--planner-chat-expanded[^{]+\.(?:task-planner-chat|task-planner-chat-transcript|task-planner-chat-composer)\s*\{[^}]*(?:padding|margin|gap)\s*:/);
|
||||
expect(css).not.toMatch(/task-detail-content--planner-chat-expanded[^{]+\.detail-body--planner-chat\s*\{[^}]*(?:padding|margin|gap)\s*:/);
|
||||
});
|
||||
|
||||
it("keeps detail metadata as a single wrapping flex row without mobile column fallbacks", () => {
|
||||
const css = readDashboardStylesSource();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user