Keep desktop sidebar controls stable across panel changes (#2078)
* fix(app): stabilize desktop sidebar controls Keep the left-window-controls toggle mounted across sidebar state changes so its position and tooltip state remain stable. Preserve browser placement and show an explicit Explorer close control only where native right-side controls do not provide one. * fix(app): suppress inactive sidebar chrome
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import {
|
||||
intersectWindowChromeCorners,
|
||||
resolveHasOwnedWindowChromeObstruction,
|
||||
resolveWindowChromeObstruction,
|
||||
resolveWindowChromeSafeArea,
|
||||
} from "@/utils/desktop-window";
|
||||
@@ -49,4 +50,33 @@ describe("window chrome", () => {
|
||||
expect(intersectWindowChromeCorners("top-right", "both")).toBe("top-right");
|
||||
expect(intersectWindowChromeCorners("top-left", "top-right")).toBe("none");
|
||||
});
|
||||
|
||||
it("reports an obstruction only when the surface owns its corner", () => {
|
||||
const obstruction = {
|
||||
topLeft: { width: 78, height: 45 },
|
||||
topRight: { width: 140, height: 48 },
|
||||
};
|
||||
|
||||
expect(
|
||||
resolveHasOwnedWindowChromeObstruction({
|
||||
obstruction,
|
||||
corners: "top-left",
|
||||
corner: "top-left",
|
||||
}),
|
||||
).toBe(true);
|
||||
expect(
|
||||
resolveHasOwnedWindowChromeObstruction({
|
||||
obstruction,
|
||||
corners: "top-left",
|
||||
corner: "top-right",
|
||||
}),
|
||||
).toBe(false);
|
||||
expect(
|
||||
resolveHasOwnedWindowChromeObstruction({
|
||||
obstruction: { topLeft: null, topRight: null },
|
||||
corners: "both",
|
||||
corner: "top-right",
|
||||
}),
|
||||
).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -24,6 +24,8 @@ interface WindowChromeObstruction {
|
||||
topRight: WindowChromeCornerObstruction | null;
|
||||
}
|
||||
|
||||
export type WindowChromeCorner = "top-left" | "top-right";
|
||||
|
||||
type WindowChromeSafeAreaStyle = { height: number } | { paddingLeft: number; paddingRight: number };
|
||||
|
||||
const EMPTY_OBSTRUCTION: WindowChromeObstruction = { topLeft: null, topRight: null };
|
||||
@@ -37,6 +39,29 @@ function windowChromeCornersFromFlags(topLeft: boolean, topRight: boolean): Wind
|
||||
return "none";
|
||||
}
|
||||
|
||||
export function windowChromeCornersInclude(
|
||||
corners: WindowChromeCorners,
|
||||
corner: WindowChromeCorner,
|
||||
): boolean {
|
||||
return corners === "both" || corners === corner;
|
||||
}
|
||||
|
||||
export function resolveHasOwnedWindowChromeObstruction(input: {
|
||||
obstruction: WindowChromeObstruction;
|
||||
corners: WindowChromeCorners;
|
||||
corner: WindowChromeCorner;
|
||||
}): boolean {
|
||||
if (!windowChromeCornersInclude(input.corners, input.corner)) return false;
|
||||
return input.corner === "top-left"
|
||||
? input.obstruction.topLeft !== null
|
||||
: input.obstruction.topRight !== null;
|
||||
}
|
||||
|
||||
export function useHasWindowChromeObstruction(corner: WindowChromeCorner): boolean {
|
||||
const obstruction = useContext(WindowChromeContext);
|
||||
return corner === "top-left" ? obstruction.topLeft !== null : obstruction.topRight !== null;
|
||||
}
|
||||
|
||||
export function intersectWindowChromeCorners(
|
||||
inherited: WindowChromeCorners,
|
||||
declared: WindowChromeCorners,
|
||||
@@ -210,6 +235,17 @@ export function useWindowChromeCorners(): WindowChromeCorners {
|
||||
return useContext(WindowChromeCornersContext);
|
||||
}
|
||||
|
||||
export function useOwnsWindowChromeCorner(corner: WindowChromeCorner): boolean {
|
||||
const corners = useContext(WindowChromeCornersContext);
|
||||
return windowChromeCornersInclude(corners, corner);
|
||||
}
|
||||
|
||||
export function useHasOwnedWindowChromeObstruction(corner: WindowChromeCorner): boolean {
|
||||
const obstruction = useContext(WindowChromeContext);
|
||||
const corners = useContext(WindowChromeCornersContext);
|
||||
return resolveHasOwnedWindowChromeObstruction({ obstruction, corners, corner });
|
||||
}
|
||||
|
||||
type WindowChromeSafeAreaProps = ViewProps & {
|
||||
placement: WindowChromeSafeAreaPlacement;
|
||||
horizontalPadding?: number;
|
||||
|
||||
Reference in New Issue
Block a user