FN-6826: elevate the theme dropdown when open
Ensure the Command Center theme selector renders above neighboring views while preserving mobile in-flow behavior. - Add an open state class to the theme dropdown root for local stacking control. - Raise the open dropdown and popover above Command Center sibling cards without exceeding app chrome layers. - Cover desktop elevation and mobile static popover behavior in ThemeDropdown tests. Files changed: .../dashboard/app/components/ThemeDropdown.css | 15 +++++++- .../dashboard/app/components/ThemeDropdown.tsx | 2 +- .../components/__tests__/ThemeDropdown.test.tsx | 40 ++++++++++++++++++++++ 3 files changed, 55 insertions(+), 2 deletions(-) Fusion-Task-Id: FN-6826 Fusion-Task-Lineage: ff43c06e-f3a7-4b4c-8e29-46deb66e9145
This commit is contained in:
@@ -6,6 +6,14 @@
|
||||
min-inline-size: 0;
|
||||
}
|
||||
|
||||
/*
|
||||
FNXC:Theme 2026-06-20-00:00:
|
||||
FN-6826 requires the Command Center theme dropdown to paint on top of all sibling Command Center cards/views only while open. Use a local dropdown-tier z-index above DateRangePicker's 20 and below app chrome/mobile nav tiers, then reset it in the mobile in-flow branch so closed or static content never floats above unrelated chrome.
|
||||
*/
|
||||
.theme-dropdown.open {
|
||||
z-index: 40;
|
||||
}
|
||||
|
||||
.theme-dropdown-trigger {
|
||||
justify-content: space-between;
|
||||
gap: var(--space-sm);
|
||||
@@ -43,7 +51,7 @@
|
||||
|
||||
.theme-dropdown-popover {
|
||||
position: absolute;
|
||||
z-index: 10;
|
||||
z-index: 40;
|
||||
inset-block-start: calc(100% + var(--space-xs));
|
||||
inset-inline: 0;
|
||||
padding: var(--space-sm);
|
||||
@@ -85,8 +93,13 @@
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.theme-dropdown.open {
|
||||
z-index: auto;
|
||||
}
|
||||
|
||||
.theme-dropdown-popover {
|
||||
position: static;
|
||||
z-index: auto;
|
||||
margin-block-start: var(--space-xs);
|
||||
}
|
||||
|
||||
|
||||
@@ -105,7 +105,7 @@ export function ThemeDropdown({ colorTheme, onColorThemeChange, themeMode, onThe
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="theme-dropdown" ref={rootRef}>
|
||||
<div className={`theme-dropdown${open ? " open" : ""}`} ref={rootRef}>
|
||||
<button
|
||||
type="button"
|
||||
className="theme-dropdown-trigger btn"
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { readFileSync } from "node:fs";
|
||||
import { describe, it, expect, vi, beforeEach } from "vitest";
|
||||
import { fireEvent, render, screen, within } from "@testing-library/react";
|
||||
import { COLOR_THEMES } from "../themeOptions";
|
||||
@@ -73,4 +74,43 @@ describe("ThemeDropdown", () => {
|
||||
fireEvent.click(screen.getByRole("button", { name: /light/i }));
|
||||
expect(onThemeModeChange).toHaveBeenCalledWith("light");
|
||||
});
|
||||
|
||||
it.each([
|
||||
["without mode controls", undefined, undefined],
|
||||
["with mode controls", "dark" as const, vi.fn()],
|
||||
])("elevates the open popover above Command Center sibling cards %s", (_label, themeMode, onThemeModeChange) => {
|
||||
render(
|
||||
<ThemeDropdown
|
||||
colorTheme="default"
|
||||
themeMode={themeMode}
|
||||
onColorThemeChange={vi.fn()}
|
||||
onThemeModeChange={onThemeModeChange}
|
||||
/>,
|
||||
);
|
||||
|
||||
const trigger = screen.getByRole("button", { name: /default/i });
|
||||
const root = trigger.closest(".theme-dropdown");
|
||||
expect(root).toBeTruthy();
|
||||
expect(root?.classList.contains("open")).toBe(false);
|
||||
expect(getComputedStyle(root!).zIndex).not.toBe("40");
|
||||
|
||||
fireEvent.click(trigger);
|
||||
|
||||
const popover = document.querySelector<HTMLElement>(".theme-dropdown-popover");
|
||||
expect(trigger.getAttribute("aria-expanded")).toBe("true");
|
||||
expect(root?.classList.contains("open")).toBe(true);
|
||||
expect(getComputedStyle(root!).position).toBe("relative");
|
||||
expect(getComputedStyle(root!).zIndex).toBe("40");
|
||||
expect(popover).toBeTruthy();
|
||||
expect(getComputedStyle(popover!).position).toBe("absolute");
|
||||
expect(getComputedStyle(popover!).zIndex).toBe("40");
|
||||
});
|
||||
|
||||
it("preserves the mobile static in-flow popover branch without dropdown elevation", () => {
|
||||
const css = readFileSync("app/components/ThemeDropdown.css", "utf8");
|
||||
|
||||
expect(css).toMatch(
|
||||
/@media \(max-width: 768px\) \{[\s\S]*?\.theme-dropdown\.open \{[\s\S]*?z-index: auto;[\s\S]*?\.theme-dropdown-popover \{[\s\S]*?position: static;[\s\S]*?z-index: auto;/,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user