FN-7155: keep goal mission picker natural-height
Keep the goal-to-mission link picker from stretching vertically in stacked layouts. - Reset the linked mission picker flex sizing at tablet and mobile breakpoints while preserving full-width stacking. - Add CSS regression coverage for the base flex value and breakpoint overrides. Files changed: packages/dashboard/app/components/GoalsView.css | 20 ++++++++- .../app/components/__tests__/GoalsView.css.test.ts | 48 ++++++++++++++++++++++ 2 files changed, 66 insertions(+), 2 deletions(-) Fusion-Task-Id: FN-7155 Fusion-Task-Lineage: cad957bb-3efd-4435-9386-fcf84cb0d209 Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
This commit is contained in:
@@ -295,8 +295,16 @@ The goal card is a 3-column flex row: .goals-card-main | .goals-card-actions | .
|
||||
align-items: stretch;
|
||||
}
|
||||
|
||||
.goals-linked-missions-link-button,
|
||||
/*
|
||||
FNXC:Goals 2026-06-27-00:00:
|
||||
FN-7155: In this tablet column layout, the picker flex-basis maps to height instead of width. Reset flex so the mission picker stays at native select height while preserving full-width stacking.
|
||||
*/
|
||||
.goals-linked-missions-picker {
|
||||
flex: 0 0 auto;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.goals-linked-missions-link-button {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
@@ -321,8 +329,16 @@ The goal card is a 3-column flex row: .goals-card-main | .goals-card-actions | .
|
||||
border-top: calc(var(--space-xs) / 4) solid var(--border);
|
||||
}
|
||||
|
||||
.goals-linked-missions-link-button,
|
||||
/*
|
||||
FNXC:Goals 2026-06-27-00:00:
|
||||
FN-7155: In this mobile column layout, the picker flex-basis maps to height instead of width. Reset flex so the mission picker stays at native select height while preserving full-width stacking.
|
||||
*/
|
||||
.goals-linked-missions-picker {
|
||||
flex: 0 0 auto;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.goals-linked-missions-link-button {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
|
||||
@@ -6,6 +6,41 @@ function goalsBlocks(css: string): string {
|
||||
return blocks.join("\n");
|
||||
}
|
||||
|
||||
function extractRuleBlock(css: string, selector: string): string {
|
||||
const escapedSelector = selector.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
||||
const match = css.match(new RegExp(`${escapedSelector}\\s*\\{([\\s\\S]*?)\\}`));
|
||||
return match?.[1] ?? "";
|
||||
}
|
||||
|
||||
function extractAtRuleBlocks(css: string, atRule: string): string[] {
|
||||
const blocks: string[] = [];
|
||||
let start = css.indexOf(atRule);
|
||||
|
||||
while (start !== -1) {
|
||||
const open = css.indexOf("{", start);
|
||||
if (open === -1) break;
|
||||
|
||||
let depth = 1;
|
||||
let cursor = open + 1;
|
||||
while (cursor < css.length && depth > 0) {
|
||||
if (css[cursor] === "{") depth++;
|
||||
if (css[cursor] === "}") depth--;
|
||||
cursor++;
|
||||
}
|
||||
|
||||
blocks.push(css.slice(open + 1, cursor - 1));
|
||||
start = css.indexOf(atRule, cursor);
|
||||
}
|
||||
|
||||
return blocks;
|
||||
}
|
||||
|
||||
function extractRuleBlockFromAtRule(css: string, atRule: string, selector: string): string {
|
||||
return extractAtRuleBlocks(css, atRule)
|
||||
.map((block) => extractRuleBlock(block, selector))
|
||||
.find((block) => block !== "") ?? "";
|
||||
}
|
||||
|
||||
describe("GoalsView CSS token guardrails", () => {
|
||||
it("uses tokens and contains mobile/focus rules", async () => {
|
||||
const css = await loadAllAppCss();
|
||||
@@ -20,4 +55,17 @@ describe("GoalsView CSS token guardrails", () => {
|
||||
expect(css).toMatch(/\.goals-[^\n{]*:focus-visible/g);
|
||||
expect(css).toMatch(/@media \(max-width: 768px\)[\s\S]*\.goals-/);
|
||||
});
|
||||
|
||||
it("keeps the linked mission picker natural-height in column breakpoints", async () => {
|
||||
const css = await loadAllAppCss();
|
||||
const basePickerBlock = extractRuleBlock(css, ".goals-linked-missions-picker");
|
||||
const mobilePickerBlock = extractRuleBlockFromAtRule(css, "@media (max-width: 768px)", ".goals-linked-missions-picker");
|
||||
const tabletPickerBlock = extractRuleBlockFromAtRule(css, "@media (min-width: 769px) and (max-width: 1024px)", ".goals-linked-missions-picker");
|
||||
|
||||
expect(basePickerBlock).toMatch(/flex\s*:\s*1\s+1\s+calc\(var\(--space-xl\)\s*\*\s*10\)/);
|
||||
expect(mobilePickerBlock).toMatch(/flex\s*:\s*0\s+0\s+auto/);
|
||||
expect(mobilePickerBlock).toMatch(/width\s*:\s*100%/);
|
||||
expect(tabletPickerBlock).toMatch(/flex\s*:\s*0\s+0\s+auto/);
|
||||
expect(tabletPickerBlock).toMatch(/width\s*:\s*100%/);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user