mirror of
https://github.com/block/buzz.git
synced 2026-11-09 02:41:57 +00:00
fix(projects): stabilize workspace sheet transitions
Collapse the context rail before a workspace drawer enters so the sheet keeps a fixed width, and hide the sidebar-style resize guide without removing resizing. Signed-off-by: Thomas Petersen <thomasp@squareup.com> Co-authored-by: Thomas Petersen <thomasp@squareup.com>
This commit is contained in:
@@ -828,8 +828,8 @@ export const ChannelPane = React.memo(function ChannelPane({
|
||||
</section>
|
||||
) : null}
|
||||
|
||||
{/* Keep focus drawers mounted until their exit animation finishes. */}
|
||||
<AnimatePresence onExitComplete={markExitComplete}>
|
||||
{/* Serialize replacements so focus drawers keep one travel direction. */}
|
||||
<AnimatePresence mode="wait" onExitComplete={markExitComplete}>
|
||||
{channelManagementOpen && activeChannel ? (
|
||||
<ChannelManagementAuxiliaryPanel
|
||||
activeChannel={activeChannel}
|
||||
|
||||
@@ -11,6 +11,7 @@ type RightAuxiliaryPaneProps = {
|
||||
detached?: boolean;
|
||||
onResetWidth: () => void;
|
||||
onResizeStart: (event: React.PointerEvent<HTMLButtonElement>) => void;
|
||||
showResizeIndicator?: boolean;
|
||||
testId?: string;
|
||||
widthPx: number;
|
||||
};
|
||||
@@ -23,6 +24,7 @@ export function RightAuxiliaryPane({
|
||||
detached = false,
|
||||
onResetWidth,
|
||||
onResizeStart,
|
||||
showResizeIndicator = true,
|
||||
testId,
|
||||
widthPx,
|
||||
}: RightAuxiliaryPaneProps) {
|
||||
@@ -56,7 +58,12 @@ export function RightAuxiliaryPane({
|
||||
}
|
||||
type="button"
|
||||
>
|
||||
<span className="absolute bottom-0 left-1/2 top-0 w-px -translate-x-1/2 bg-transparent group-hover/right-pane-resize:bg-border/80 group-focus-visible/right-pane-resize:bg-border/80" />
|
||||
{showResizeIndicator ? (
|
||||
<span
|
||||
className="absolute bottom-0 left-1/2 top-0 w-px -translate-x-1/2 bg-transparent group-hover/right-pane-resize:bg-border/80 group-focus-visible/right-pane-resize:bg-border/80"
|
||||
data-testid="right-auxiliary-pane-resize-indicator"
|
||||
/>
|
||||
) : null}
|
||||
</button>
|
||||
<div className="relative flex min-h-0 min-w-0 flex-1 flex-col">
|
||||
{children}
|
||||
|
||||
@@ -134,6 +134,12 @@ export function ProjectChannelHome({
|
||||
null;
|
||||
const workspaceSheetOpen =
|
||||
workspaceSheetTab != null && workspaceRepository != null;
|
||||
const previousWorkspaceSheetOpenRef = React.useRef(workspaceSheetOpen);
|
||||
const workspaceSheetVisibilityChanged =
|
||||
previousWorkspaceSheetOpenRef.current !== workspaceSheetOpen;
|
||||
React.useEffect(() => {
|
||||
previousWorkspaceSheetOpenRef.current = workspaceSheetOpen;
|
||||
}, [workspaceSheetOpen]);
|
||||
const summaryVisible = summaryOpen && !workspaceSheetOpen;
|
||||
|
||||
const openWorkspaceSheet = React.useCallback(
|
||||
@@ -390,6 +396,7 @@ export function ProjectChannelHome({
|
||||
projects={projects}
|
||||
/>
|
||||
<ProjectContextRail
|
||||
animateWidth={!workspaceSheetVisibilityChanged}
|
||||
open={summaryVisible}
|
||||
panelWidthPx={summaryWidth.widthPx}
|
||||
resizing={summaryWidth.isResizing}
|
||||
|
||||
@@ -5,6 +5,7 @@ import { cn } from "@/shared/lib/cn";
|
||||
const CONTEXT_RAIL_GUTTER_PX = 8;
|
||||
|
||||
export function ProjectContextRail({
|
||||
animateWidth = true,
|
||||
children,
|
||||
open,
|
||||
panelWidthPx,
|
||||
@@ -12,6 +13,7 @@ export function ProjectContextRail({
|
||||
rounded = true,
|
||||
testId = "project-context-rail",
|
||||
}: {
|
||||
animateWidth?: boolean;
|
||||
children: React.ReactNode;
|
||||
open: boolean;
|
||||
panelWidthPx: number;
|
||||
@@ -24,7 +26,7 @@ export function ProjectContextRail({
|
||||
aria-hidden={!open}
|
||||
className={cn(
|
||||
"relative z-30 h-full shrink-0 overflow-hidden motion-reduce:transition-none",
|
||||
resizing
|
||||
resizing || !animateWidth
|
||||
? "transition-none"
|
||||
: "transition-[width] duration-200 ease-linear",
|
||||
)}
|
||||
|
||||
@@ -29,6 +29,7 @@ export function ProjectHomeColumn({
|
||||
detached
|
||||
onResetWidth={onResetWidth}
|
||||
onResizeStart={onResizeStart}
|
||||
showResizeIndicator={false}
|
||||
testId={testId}
|
||||
widthPx={widthPx}
|
||||
>
|
||||
|
||||
@@ -774,6 +774,49 @@ test("latest files commit opens its detail without a divider", async ({
|
||||
await expect(page.getByTestId("project-commit-detail")).toBeVisible();
|
||||
});
|
||||
|
||||
test("project workspace sheet enters at its settled width", async ({
|
||||
page,
|
||||
}) => {
|
||||
await enableProjectsFeature(page);
|
||||
await installMockBridge(page);
|
||||
await page.goto("/", { waitUntil: "domcontentloaded" });
|
||||
await page.getByTestId("open-projects-view").click();
|
||||
await openCreateProjectDialog(page);
|
||||
await page.getByTestId("create-project-name").fill("sheet-motion-demo");
|
||||
await page.getByTestId("create-project-submit").click();
|
||||
await expect(page.getByTestId("project-channel-home")).toBeVisible();
|
||||
|
||||
const summaryColumn = page.getByTestId("project-home-summary-column");
|
||||
const resizeHandle = summaryColumn.getByTestId(
|
||||
"right-auxiliary-pane-resize-handle",
|
||||
);
|
||||
await expect(resizeHandle).toBeVisible();
|
||||
await resizeHandle.hover();
|
||||
await expect(
|
||||
resizeHandle.getByTestId("right-auxiliary-pane-resize-indicator"),
|
||||
).toHaveCount(0);
|
||||
const summaryRail = page.getByTestId("project-home-summary-rail");
|
||||
const openRailWidth = await summaryRail.evaluate(
|
||||
(element) => element.getBoundingClientRect().width,
|
||||
);
|
||||
expect(openRailWidth).toBeGreaterThan(0);
|
||||
await page.getByTestId("project-home-context-tasks").click();
|
||||
await expect(page.getByTestId("project-home-workspace-sheet")).toBeVisible();
|
||||
|
||||
const collapsedRailWidth = await summaryRail.evaluate(
|
||||
(element) => element.getBoundingClientRect().width,
|
||||
);
|
||||
expect(collapsedRailWidth).toBeLessThanOrEqual(1);
|
||||
const focusDrawer = page.getByTestId("focus-thread-drawer");
|
||||
const enteringDrawerWidth = (await focusDrawer.boundingBox())?.width ?? 0;
|
||||
expect(enteringDrawerWidth).toBeGreaterThan(0);
|
||||
await waitForAnimations(page);
|
||||
const settledDrawerWidth = (await focusDrawer.boundingBox())?.width ?? 0;
|
||||
expect(
|
||||
Math.abs(settledDrawerWidth - enteringDrawerWidth),
|
||||
).toBeLessThanOrEqual(1);
|
||||
});
|
||||
|
||||
test("commit detail opens from the commits feed with a diff", async ({
|
||||
page,
|
||||
}) => {
|
||||
@@ -806,10 +849,9 @@ test("commit detail opens from the commits feed with a diff", async ({
|
||||
await expect(page.getByTestId("focus-thread-drawer")).toBeVisible();
|
||||
await page.getByTestId("project-home-context-tasks").click();
|
||||
await expect(page.getByTestId("project-home-workspace-sheet")).toBeVisible();
|
||||
await expect(page.getByTestId("focus-thread-drawer")).toHaveCSS(
|
||||
"outline-style",
|
||||
"none",
|
||||
);
|
||||
const focusDrawer = page.getByTestId("focus-thread-drawer");
|
||||
await expect(focusDrawer).toHaveCount(1);
|
||||
await expect(focusDrawer).toHaveCSS("outline-style", "none");
|
||||
const workspaceSheet = page.getByTestId("project-home-workspace-sheet");
|
||||
await expect(workspaceSheet).toHaveAttribute("data-tab", "issues");
|
||||
await expect(
|
||||
|
||||
Reference in New Issue
Block a user