mirror of
https://github.com/getpaseo/paseo.git
synced 2026-11-04 07:33:18 +00:00
fix(app): preserve compact pane actions and window clearance
Carry the owning pane into compact launch actions, keep split and restore controls in its menu, and distribute window corners through visible split children. Keep tab rails below header-owned window controls. Co-authored-by: Elsa Granger <zeyugao@outlook.com>
This commit is contained in:
co-authored by
Elsa Granger
parent
951caba89a
commit
d1fd3e328f
@@ -1,3 +1,4 @@
|
||||
import type { Locator, Page } from "@playwright/test";
|
||||
import { expect, test } from "../support/fixtures";
|
||||
import { runWorkspaceActionFromCommandCenter } from "../support/helpers/command-center-workspace-actions";
|
||||
import {
|
||||
@@ -9,6 +10,7 @@ import { seedWorkspace } from "../support/helpers/seed-client";
|
||||
import { waitForWorkspaceTabsVisible } from "../support/helpers/workspace-tabs";
|
||||
|
||||
test.describe("Direct terminal shortcut pane placement", () => {
|
||||
test.use({ viewport: { width: 1600, height: 900 } });
|
||||
test("opens a terminal in the focused pane", async ({ page }) => {
|
||||
const workspace = await seedWorkspace({ repoPrefix: "direct-terminal-shortcut-pane-" });
|
||||
|
||||
@@ -47,3 +49,58 @@ test.describe("Direct terminal shortcut pane placement", () => {
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
async function prepareUnfocusedCompactPane(page: Page, workspaceId: string) {
|
||||
await page.setViewportSize({ width: 1600, height: 900 });
|
||||
await gotoWorkspace(page, workspaceId);
|
||||
await waitForWorkspaceTabsVisible(page);
|
||||
await clickNewChat(page);
|
||||
await runWorkspaceActionFromCommandCenter(page, "Split pane right");
|
||||
const draftPane = page
|
||||
.locator('[data-testid^="workspace-pane-"]')
|
||||
.filter({ has: page.getByTestId("message-input-root") });
|
||||
const emptyPane = page
|
||||
.locator('[data-testid^="workspace-pane-"]')
|
||||
.filter({ has: page.getByTestId("workspace-new-tab-panel") });
|
||||
const draftPaneId = await draftPane.getAttribute("data-testid");
|
||||
const emptyPaneId = await emptyPane.getAttribute("data-testid");
|
||||
expect(draftPaneId).not.toBeNull();
|
||||
expect(emptyPaneId).not.toBeNull();
|
||||
await page.setViewportSize({ width: 760, height: 900 });
|
||||
return {
|
||||
originalPane: page.getByTestId(draftPaneId!),
|
||||
otherPane: page.getByTestId(emptyPaneId!),
|
||||
};
|
||||
}
|
||||
|
||||
async function launchTerminalFromCompactPane(page: Page, pane: Locator) {
|
||||
await pane.getByTestId("workspace-tab-switcher-trigger").click();
|
||||
await page.getByTestId("workspace-tab-switcher-new-terminal").click();
|
||||
await expect(pane.getByTestId("terminal-surface")).toBeVisible({ timeout: 30_000 });
|
||||
}
|
||||
|
||||
async function maximizeAndRestoreCompactPane(page: Page, pane: Locator) {
|
||||
await pane.getByTestId("workspace-header-menu-trigger").click();
|
||||
await expect(page.getByRole("menuitem", { name: "Split pane right", exact: true })).toBeVisible();
|
||||
await page.getByRole("menuitem", { name: "Maximize pane", exact: true }).click();
|
||||
await pane.getByTestId("workspace-header-menu-trigger").click();
|
||||
await page.getByRole("menuitem", { name: "Restore pane", exact: true }).click();
|
||||
}
|
||||
|
||||
test("compact pane launch stays in its owning pane and pane controls remain reachable", async ({
|
||||
page,
|
||||
}) => {
|
||||
const workspace = await seedWorkspace({ repoPrefix: "compact-pane-launch-" });
|
||||
try {
|
||||
const { originalPane, otherPane } = await prepareUnfocusedCompactPane(
|
||||
page,
|
||||
workspace.workspaceId,
|
||||
);
|
||||
await launchTerminalFromCompactPane(page, originalPane);
|
||||
await expect(otherPane.getByTestId("workspace-new-tab-panel")).toBeVisible();
|
||||
await maximizeAndRestoreCompactPane(page, originalPane);
|
||||
await expect(otherPane).toBeVisible();
|
||||
} finally {
|
||||
await workspace.cleanup();
|
||||
}
|
||||
});
|
||||
|
||||
@@ -36,6 +36,7 @@ import {
|
||||
WindowChromeSafeArea,
|
||||
useWindowChromeCorners,
|
||||
removeWindowChromeCorner,
|
||||
resolveChildWindowChromeCorners,
|
||||
type WindowChromeCorners,
|
||||
} from "@/utils/desktop-window";
|
||||
import { TitlebarDragRegion } from "@/components/desktop/titlebar-drag-region";
|
||||
@@ -187,7 +188,7 @@ export function SplitContainer({
|
||||
renderCompactHeader,
|
||||
}: SplitContainerProps) {
|
||||
const inheritedWindowChromeCorners = useWindowChromeCorners();
|
||||
const windowChromeCorners = focusModeEnabled ? inheritedWindowChromeCorners : "none";
|
||||
const windowChromeCorners = inheritedWindowChromeCorners;
|
||||
const { activeDragTabId, dropPreview, tabDropPreview } = useWorkspaceTabDrag();
|
||||
const [maximizedPane, setMaximizedPane] = useState<{
|
||||
workspaceKey: string;
|
||||
@@ -560,7 +561,18 @@ function SplitNodeView({
|
||||
showDropZones={showDropZones}
|
||||
dropPreview={dropPreview}
|
||||
tabDropPreview={tabDropPreview}
|
||||
windowChromeCorners={windowChromeCorners}
|
||||
windowChromeCorners={resolveChildWindowChromeCorners({
|
||||
corners: windowChromeCorners,
|
||||
direction: node.group.direction,
|
||||
isFirst:
|
||||
node.group.children.findIndex(
|
||||
(candidate) => !isSplitNodeHiddenForPresentation(candidate, maximizedPaneId),
|
||||
) === index,
|
||||
isLast:
|
||||
node.group.children.findLastIndex(
|
||||
(candidate) => !isSplitNodeHiddenForPresentation(candidate, maximizedPaneId),
|
||||
) === index,
|
||||
})}
|
||||
maximizedPaneId={maximizedPaneId}
|
||||
workspaceHasMultiplePanes={workspaceHasMultiplePanes}
|
||||
onTogglePaneMaximized={onTogglePaneMaximized}
|
||||
@@ -723,11 +735,30 @@ const SplitPaneView = memo(function SplitPaneView({
|
||||
);
|
||||
const compactHeaderActions = useMemo(
|
||||
() => ({
|
||||
pane: {
|
||||
id: paneId,
|
||||
splitRight: focusModeEnabled ? undefined : handleSplitRight,
|
||||
splitDown: focusModeEnabled ? undefined : handleSplitDown,
|
||||
toggleMaximized:
|
||||
workspaceHasMultiplePanes && !focusModeEnabled ? handleTogglePaneMaximized : undefined,
|
||||
maximized: paneId === maximizedPaneId,
|
||||
},
|
||||
closeAbove: handleCloseTabsToLeft,
|
||||
closeBelow: handleCloseTabsToRight,
|
||||
closeOthers: handleCloseOtherTabs,
|
||||
}),
|
||||
[handleCloseTabsToLeft, handleCloseTabsToRight, handleCloseOtherTabs],
|
||||
[
|
||||
paneId,
|
||||
focusModeEnabled,
|
||||
handleSplitRight,
|
||||
handleSplitDown,
|
||||
workspaceHasMultiplePanes,
|
||||
handleTogglePaneMaximized,
|
||||
maximizedPaneId,
|
||||
handleCloseTabsToLeft,
|
||||
handleCloseTabsToRight,
|
||||
handleCloseOtherTabs,
|
||||
],
|
||||
);
|
||||
const createNewTab = useCallback(() => onCreateNewTab({ paneId }), [onCreateNewTab, paneId]);
|
||||
useWorkspaceNewTabKeyboardAction({
|
||||
@@ -738,6 +769,14 @@ const SplitPaneView = memo(function SplitPaneView({
|
||||
paneId,
|
||||
createNewTab,
|
||||
});
|
||||
const compactHeader = useMemo(
|
||||
() => (
|
||||
<WindowChromeSafeArea placement="inline">
|
||||
{renderCompactHeader(paneTabs, activeTabDescriptor?.key ?? "", compactHeaderActions)}
|
||||
</WindowChromeSafeArea>
|
||||
),
|
||||
[renderCompactHeader, paneTabs, activeTabDescriptor?.key, compactHeaderActions],
|
||||
);
|
||||
return (
|
||||
<RenderProfile id={`SplitPaneView:${pane.id}`}>
|
||||
<View
|
||||
@@ -746,52 +785,48 @@ const SplitPaneView = memo(function SplitPaneView({
|
||||
style={styles.pane}
|
||||
testID={`workspace-pane-${pane.id}`}
|
||||
>
|
||||
<AdaptiveWorkspaceChrome
|
||||
compactHeader={renderCompactHeader(
|
||||
paneTabs,
|
||||
activeTabDescriptor?.key ?? "",
|
||||
compactHeaderActions,
|
||||
)}
|
||||
>
|
||||
<AdaptiveWorkspaceChrome compactHeader={compactHeader}>
|
||||
{renderMainHeader?.()}
|
||||
<WindowChromeSafeArea placement="inline" style={styles.paneTabs}>
|
||||
<TitlebarDragRegion />
|
||||
<WorkspaceDesktopTabsRow
|
||||
paneId={pane.id}
|
||||
isFocused={isFocused && isWorkspaceFocused}
|
||||
tabs={desktopTabRowItems}
|
||||
normalizedServerId={normalizedServerId}
|
||||
normalizedWorkspaceId={normalizedWorkspaceId}
|
||||
setHoveredCloseTabKey={setHoveredCloseTabKey}
|
||||
onNavigateTab={onNavigateTab}
|
||||
onCloseTab={onCloseTab}
|
||||
onCopyResumeCommand={onCopyResumeCommand}
|
||||
onCopyAgentId={onCopyAgentId}
|
||||
onCopyTerminalId={onCopyTerminalId}
|
||||
onCopyFilePath={onCopyFilePath}
|
||||
onReloadAgent={onReloadAgent}
|
||||
onRenameTab={onRenameTab}
|
||||
onCloseTabsToLeft={handleCloseTabsToLeft}
|
||||
onCloseTabsToRight={handleCloseTabsToRight}
|
||||
onCloseOtherTabs={handleCloseOtherTabs}
|
||||
onCreateNewTab={onCreateNewTab}
|
||||
onReorderTabs={handleReorderTabs}
|
||||
ownsKeyboardShortcuts={false}
|
||||
externalDndContext
|
||||
activeDragTabId={activeDragTabId}
|
||||
tabDropPreviewIndex={
|
||||
tabDropPreview?.paneId === pane.id ? tabDropPreview.indicatorIndex : null
|
||||
}
|
||||
showPaneSplitActions={!focusModeEnabled}
|
||||
showPaneMaximizeAction={workspaceHasMultiplePanes && !focusModeEnabled}
|
||||
paneMaximized={paneId === maximizedPaneId}
|
||||
onTogglePaneMaximized={handleTogglePaneMaximized}
|
||||
onSplitRight={handleSplitRight}
|
||||
onSplitDown={handleSplitDown}
|
||||
focusModeEnabled={Boolean(focusModeEnabled)}
|
||||
onExitFocusMode={onExitFocusMode}
|
||||
/>
|
||||
</WindowChromeSafeArea>
|
||||
<WindowChromeRegion corners={focusModeEnabled ? "both" : "none"}>
|
||||
<WindowChromeSafeArea placement="inline" style={styles.paneTabs}>
|
||||
<TitlebarDragRegion />
|
||||
<WorkspaceDesktopTabsRow
|
||||
paneId={pane.id}
|
||||
isFocused={isFocused && isWorkspaceFocused}
|
||||
tabs={desktopTabRowItems}
|
||||
normalizedServerId={normalizedServerId}
|
||||
normalizedWorkspaceId={normalizedWorkspaceId}
|
||||
setHoveredCloseTabKey={setHoveredCloseTabKey}
|
||||
onNavigateTab={onNavigateTab}
|
||||
onCloseTab={onCloseTab}
|
||||
onCopyResumeCommand={onCopyResumeCommand}
|
||||
onCopyAgentId={onCopyAgentId}
|
||||
onCopyTerminalId={onCopyTerminalId}
|
||||
onCopyFilePath={onCopyFilePath}
|
||||
onReloadAgent={onReloadAgent}
|
||||
onRenameTab={onRenameTab}
|
||||
onCloseTabsToLeft={handleCloseTabsToLeft}
|
||||
onCloseTabsToRight={handleCloseTabsToRight}
|
||||
onCloseOtherTabs={handleCloseOtherTabs}
|
||||
onCreateNewTab={onCreateNewTab}
|
||||
onReorderTabs={handleReorderTabs}
|
||||
ownsKeyboardShortcuts={false}
|
||||
externalDndContext
|
||||
activeDragTabId={activeDragTabId}
|
||||
tabDropPreviewIndex={
|
||||
tabDropPreview?.paneId === pane.id ? tabDropPreview.indicatorIndex : null
|
||||
}
|
||||
showPaneSplitActions={!focusModeEnabled}
|
||||
showPaneMaximizeAction={workspaceHasMultiplePanes && !focusModeEnabled}
|
||||
paneMaximized={paneId === maximizedPaneId}
|
||||
onTogglePaneMaximized={handleTogglePaneMaximized}
|
||||
onSplitRight={handleSplitRight}
|
||||
onSplitDown={handleSplitDown}
|
||||
focusModeEnabled={Boolean(focusModeEnabled)}
|
||||
onExitFocusMode={onExitFocusMode}
|
||||
/>
|
||||
</WindowChromeSafeArea>
|
||||
</WindowChromeRegion>
|
||||
</AdaptiveWorkspaceChrome>
|
||||
|
||||
<View style={styles.paneContent}>
|
||||
|
||||
@@ -25,6 +25,13 @@ export function AdaptiveWorkspaceChrome({
|
||||
}
|
||||
|
||||
export interface WorkspaceCompactHeaderActions {
|
||||
pane?: {
|
||||
id: string;
|
||||
splitRight?: () => void;
|
||||
splitDown?: () => void;
|
||||
toggleMaximized?: () => void;
|
||||
maximized: boolean;
|
||||
};
|
||||
closeAbove: (key: string) => Promise<void> | void;
|
||||
closeBelow: (key: string) => Promise<void> | void;
|
||||
closeOthers: (key: string) => Promise<void> | void;
|
||||
|
||||
@@ -124,14 +124,15 @@ function getFallbackTabOptionDescription(
|
||||
}
|
||||
|
||||
interface MobileWorkspaceTabSwitcherProps {
|
||||
paneId?: string;
|
||||
tabs: WorkspaceTabDescriptor[];
|
||||
activeTabKey: string;
|
||||
normalizedServerId: string;
|
||||
normalizedWorkspaceId: string;
|
||||
onSelectSwitcherTab: (key: string) => void;
|
||||
createTerminalDisabled: boolean;
|
||||
onCreateDraftTab: () => void;
|
||||
onCreateTerminal: () => void;
|
||||
onCreateDraftTab: (input?: { paneId?: string }) => void;
|
||||
onCreateTerminal: (input?: { paneId?: string }) => void;
|
||||
onCopyResumeCommand: (agentId: string) => Promise<void> | void;
|
||||
onCopyAgentId: (agentId: string) => Promise<void> | void;
|
||||
onCopyTerminalId: (terminalId: string) => Promise<void> | void;
|
||||
@@ -286,6 +287,7 @@ export const MobileWorkspaceTabSwitcher = memo(function MobileWorkspaceTabSwitch
|
||||
createTerminalDisabled,
|
||||
onCreateDraftTab,
|
||||
onCreateTerminal,
|
||||
paneId,
|
||||
onCopyResumeCommand,
|
||||
onCopyAgentId,
|
||||
onCopyTerminalId,
|
||||
@@ -343,13 +345,13 @@ export const MobileWorkspaceTabSwitcher = memo(function MobileWorkspaceTabSwitch
|
||||
|
||||
const handleNewAgent = useCallback(() => {
|
||||
setIsOpen(false);
|
||||
onCreateDraftTab();
|
||||
}, [onCreateDraftTab]);
|
||||
onCreateDraftTab({ paneId });
|
||||
}, [onCreateDraftTab, paneId]);
|
||||
|
||||
const handleNewTerminal = useCallback(() => {
|
||||
setIsOpen(false);
|
||||
onCreateTerminal();
|
||||
}, [onCreateTerminal]);
|
||||
onCreateTerminal({ paneId });
|
||||
}, [onCreateTerminal, paneId]);
|
||||
|
||||
const footer = useMemo(
|
||||
() => (
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import type { WorkspaceCompactHeaderActions } from "./adaptive-workspace-chrome";
|
||||
import React, { useCallback, useMemo } from "react";
|
||||
import { View } from "react-native";
|
||||
import { useRouter, type Href } from "expo-router";
|
||||
@@ -206,13 +207,14 @@ function HeaderMenuProfileItem({
|
||||
}
|
||||
|
||||
export interface WorkspaceHeaderMenuMobileProps extends WorkspaceHeaderWorkspaceActions {
|
||||
pane?: WorkspaceCompactHeaderActions["pane"];
|
||||
normalizedServerId: string;
|
||||
normalizedWorkspaceId: string;
|
||||
scripts: UseWorkspaceScriptsMenuPagesInput;
|
||||
showCreateBrowserTab: boolean;
|
||||
createTerminalDisabled: boolean;
|
||||
onCreateTerminalWithProfile: (profile: TerminalProfile) => void;
|
||||
onCreateBrowser: () => void;
|
||||
onCreateTerminalWithProfile: (profile: TerminalProfile, paneId?: string) => void;
|
||||
onCreateBrowser: (input?: { paneId?: string }) => void;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -231,8 +233,18 @@ export function WorkspaceHeaderMenuMobile({
|
||||
createTerminalDisabled,
|
||||
onCreateTerminalWithProfile,
|
||||
onCreateBrowser,
|
||||
pane,
|
||||
...workspaceActions
|
||||
}: WorkspaceHeaderMenuMobileProps) {
|
||||
const paneId = pane?.id;
|
||||
const handleCreateBrowser = useCallback(
|
||||
() => onCreateBrowser({ paneId }),
|
||||
[onCreateBrowser, paneId],
|
||||
);
|
||||
const handleCreateTerminalWithProfile = useCallback(
|
||||
(profile: TerminalProfile) => onCreateTerminalWithProfile(profile, paneId),
|
||||
[onCreateTerminalWithProfile, paneId],
|
||||
);
|
||||
const { t } = useTranslation();
|
||||
const router = useRouter();
|
||||
const triggerStyle = useIconButtonChromeStyle({ size: "large" });
|
||||
@@ -278,6 +290,25 @@ export function WorkspaceHeaderMenuMobile({
|
||||
pages={pages}
|
||||
sheetTitle={t("workspace.header.actions.workspaceActions")}
|
||||
>
|
||||
{pane?.splitRight ? (
|
||||
<DropdownMenuItem onSelect={pane.splitRight}>
|
||||
{t("workspace.tabs.actions.splitRight")}
|
||||
</DropdownMenuItem>
|
||||
) : null}
|
||||
{pane?.splitDown ? (
|
||||
<DropdownMenuItem onSelect={pane.splitDown}>
|
||||
{t("workspace.tabs.actions.splitDown")}
|
||||
</DropdownMenuItem>
|
||||
) : null}
|
||||
{pane?.toggleMaximized ? (
|
||||
<DropdownMenuItem onSelect={pane.toggleMaximized}>
|
||||
{t(
|
||||
pane.maximized
|
||||
? "workspace.tabs.actions.restorePane"
|
||||
: "workspace.tabs.actions.maximizePane",
|
||||
)}
|
||||
</DropdownMenuItem>
|
||||
) : null}
|
||||
{scriptsMenu.trigger}
|
||||
{pluginMenu.rows}
|
||||
{pluginMenu.rows.length > 0 ? <DropdownMenuSeparator /> : null}
|
||||
@@ -285,7 +316,7 @@ export function WorkspaceHeaderMenuMobile({
|
||||
<DropdownMenuItem
|
||||
testID="workspace-header-new-browser"
|
||||
leading={MENU_NEW_BROWSER_ICON}
|
||||
onSelect={onCreateBrowser}
|
||||
onSelect={handleCreateBrowser}
|
||||
>
|
||||
{t("workspace.header.actions.newBrowser")}
|
||||
</DropdownMenuItem>
|
||||
@@ -298,7 +329,7 @@ export function WorkspaceHeaderMenuMobile({
|
||||
key={profile.id}
|
||||
profile={profile}
|
||||
disabled={createTerminalDisabled}
|
||||
onCreateTerminalWithProfile={onCreateTerminalWithProfile}
|
||||
onCreateTerminalWithProfile={handleCreateTerminalWithProfile}
|
||||
/>
|
||||
))}
|
||||
<DropdownMenuSeparator />
|
||||
|
||||
@@ -1799,8 +1799,8 @@ function WorkspaceScreenContent({
|
||||
});
|
||||
|
||||
const handleCreateTerminalWithProfile = useCallback(
|
||||
(profile: TerminalProfile) => {
|
||||
createTerminal({ profile, destination: { kind: "open" } });
|
||||
(profile: TerminalProfile, paneId?: string) => {
|
||||
createTerminal({ profile, destination: { kind: "open", paneId } });
|
||||
},
|
||||
[createTerminal],
|
||||
);
|
||||
@@ -3384,6 +3384,7 @@ function WorkspaceScreenContent({
|
||||
explorerToggleAccessibilityState={explorerSidebarToggleAccessibilityState}
|
||||
>
|
||||
<MobileWorkspaceTabSwitcher
|
||||
paneId={actions.pane?.id}
|
||||
tabs={headerTabs}
|
||||
activeTabKey={headerActiveTabKey}
|
||||
normalizedServerId={normalizedServerId}
|
||||
@@ -3404,6 +3405,7 @@ function WorkspaceScreenContent({
|
||||
onCloseOtherTabs={actions.closeOthers}
|
||||
/>
|
||||
<WorkspaceHeaderMenuMobile
|
||||
pane={actions.pane}
|
||||
normalizedServerId={normalizedServerId}
|
||||
normalizedWorkspaceId={normalizedWorkspaceId}
|
||||
scripts={compactHeaderScripts}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import {
|
||||
intersectWindowChromeCorners,
|
||||
resolveChildWindowChromeCorners,
|
||||
resolveHasOwnedWindowChromeObstruction,
|
||||
resolveWindowChromeObstruction,
|
||||
resolveWindowChromeSafeArea,
|
||||
@@ -87,3 +88,54 @@ describe("window chrome", () => {
|
||||
).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
it("assigns window buttons only to exposed split edges", () => {
|
||||
expect(
|
||||
resolveChildWindowChromeCorners({
|
||||
corners: "both",
|
||||
direction: "horizontal",
|
||||
isFirst: true,
|
||||
isLast: false,
|
||||
}),
|
||||
).toBe("top-left");
|
||||
expect(
|
||||
resolveChildWindowChromeCorners({
|
||||
corners: "both",
|
||||
direction: "horizontal",
|
||||
isFirst: false,
|
||||
isLast: true,
|
||||
}),
|
||||
).toBe("top-right");
|
||||
expect(
|
||||
resolveChildWindowChromeCorners({
|
||||
corners: "both",
|
||||
direction: "horizontal",
|
||||
isFirst: false,
|
||||
isLast: false,
|
||||
}),
|
||||
).toBe("none");
|
||||
expect(
|
||||
resolveChildWindowChromeCorners({
|
||||
corners: "both",
|
||||
direction: "vertical",
|
||||
isFirst: true,
|
||||
isLast: false,
|
||||
}),
|
||||
).toBe("both");
|
||||
expect(
|
||||
resolveChildWindowChromeCorners({
|
||||
corners: "both",
|
||||
direction: "vertical",
|
||||
isFirst: false,
|
||||
isLast: true,
|
||||
}),
|
||||
).toBe("none");
|
||||
expect(
|
||||
resolveChildWindowChromeCorners({
|
||||
corners: "top-right",
|
||||
direction: "horizontal",
|
||||
isFirst: true,
|
||||
isLast: true,
|
||||
}),
|
||||
).toBe("top-right");
|
||||
});
|
||||
|
||||
@@ -83,6 +83,19 @@ export function intersectWindowChromeCorners(
|
||||
);
|
||||
}
|
||||
|
||||
export function resolveChildWindowChromeCorners(input: {
|
||||
corners: WindowChromeCorners;
|
||||
direction: "horizontal" | "vertical";
|
||||
isFirst: boolean;
|
||||
isLast: boolean;
|
||||
}): WindowChromeCorners {
|
||||
if (input.direction === "vertical") return input.isFirst ? input.corners : "none";
|
||||
return intersectWindowChromeCorners(
|
||||
input.corners,
|
||||
windowChromeCornersFromFlags(input.isFirst, input.isLast),
|
||||
);
|
||||
}
|
||||
|
||||
export function removeWindowChromeCorner(
|
||||
corners: WindowChromeCorners,
|
||||
corner: WindowChromeCorner,
|
||||
|
||||
Reference in New Issue
Block a user