fix: contain board canvas overflow
This commit is contained in:
5 files changed
+14
-9
No files matched your search
@@ -9,7 +9,7 @@
|
||||
}
|
||||
|
||||
.gutter {
|
||||
position: sticky;
|
||||
position: relative;
|
||||
top: 0;
|
||||
align-self: start;
|
||||
padding-top: 24px;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
"use client";
|
||||
|
||||
import { useEffect, useRef } from "react";
|
||||
import { useEffect, useState } from "react";
|
||||
import { Box } from "@mantine/core";
|
||||
|
||||
import { useCurrentLayout, useInitialViewportWidth, useRequiredBoard } from "@homarr/boards/context";
|
||||
@@ -24,17 +24,16 @@ import classes from "./_client.module.css";
|
||||
const APP_SHELL_INLINE_PADDING = 32;
|
||||
|
||||
const useFixedBoardGutters = () => {
|
||||
const columnsRef = useRef<HTMLDivElement>(null);
|
||||
const [columns, setColumns] = useState<HTMLDivElement | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
const columns = columnsRef.current;
|
||||
if (!columns) return;
|
||||
|
||||
let frame = 0;
|
||||
const update = () => {
|
||||
frame = 0;
|
||||
const columnsRect = columns.getBoundingClientRect();
|
||||
const headerBottom = document.querySelector("header")?.getBoundingClientRect().bottom ?? 0;
|
||||
const headerBottom = document.querySelector("[data-app-shell-header]")?.getBoundingClientRect().bottom ?? 0;
|
||||
const stickyTop = Math.max(0, headerBottom + 16);
|
||||
|
||||
for (const gutter of columns.querySelectorAll<HTMLElement>("[data-board-gutter]")) {
|
||||
@@ -62,6 +61,7 @@ const useFixedBoardGutters = () => {
|
||||
const resizeObserver = new ResizeObserver(scheduleUpdate);
|
||||
resizeObserver.observe(columns);
|
||||
document.addEventListener("scroll", scheduleUpdate, { capture: true, passive: true });
|
||||
window.addEventListener("scroll", scheduleUpdate, { passive: true });
|
||||
window.addEventListener("resize", scheduleUpdate, { passive: true });
|
||||
scheduleUpdate();
|
||||
|
||||
@@ -69,11 +69,12 @@ const useFixedBoardGutters = () => {
|
||||
window.cancelAnimationFrame(frame);
|
||||
resizeObserver.disconnect();
|
||||
document.removeEventListener("scroll", scheduleUpdate, { capture: true });
|
||||
window.removeEventListener("scroll", scheduleUpdate);
|
||||
window.removeEventListener("resize", scheduleUpdate);
|
||||
};
|
||||
}, []);
|
||||
}, [columns]);
|
||||
|
||||
return columnsRef;
|
||||
return setColumns;
|
||||
};
|
||||
|
||||
export const ClientBoard = () => {
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
max-width: 100%;
|
||||
min-width: 0;
|
||||
overflow: visible;
|
||||
overflow-x: auto;
|
||||
overscroll-behavior-inline: contain;
|
||||
}
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ interface Props {
|
||||
|
||||
export const MainHeader = ({ logo, actions, hasNavigation = true }: Props) => {
|
||||
return (
|
||||
<AppShellHeader maw="100vw" zIndex={201} style={{ overflowX: "hidden" }}>
|
||||
<AppShellHeader maw="100vw" zIndex={201} style={{ overflowX: "hidden" }} data-app-shell-header>
|
||||
<Group h="100%" gap="xl" px="md" justify="apart" wrap="nowrap">
|
||||
<Group h="100%" align="center" style={{ flex: 1 }} wrap="nowrap">
|
||||
{hasNavigation && <ClientBurger />}
|
||||
|
||||
@@ -177,6 +177,7 @@ describe("Board grid", () => {
|
||||
const zoomedTileBox = await expectBoundingBoxAsync(logicalTile);
|
||||
expect(zoomedTileBox.width).toBeGreaterThan(normalZoomTileBox.width * 1.25);
|
||||
await expectHorizontalOverflowAsync(canvas);
|
||||
await expectDocumentNotHorizontallyScrollableAsync(page);
|
||||
const overflowRailY = (await expectBoundingBoxAsync(rail)).y;
|
||||
await page.evaluate(() => window.scrollTo({ top: 300, behavior: "auto" }));
|
||||
await expect.poll(async () => (await expectBoundingBoxAsync(rail)).y).toBeGreaterThanOrEqual(0);
|
||||
@@ -348,6 +349,8 @@ describe("Board grid", () => {
|
||||
|
||||
await page.setViewportSize({ width: 600, height: 1200 });
|
||||
await expect(canvas).toHaveAttribute("data-canvas-scale", String(minimumCanvasScale));
|
||||
await expectHorizontalOverflowAsync(canvas);
|
||||
await expectDocumentNotHorizontallyScrollableAsync(page);
|
||||
for (const direction of ["n", "ne", "e", "se", "s", "sw", "w", "nw"] as const) {
|
||||
await expectTargetSizeAsync(firstItem.locator(`:scope > [data-grid-resize-handle="${direction}"]`));
|
||||
}
|
||||
@@ -823,8 +826,8 @@ describe("Board grid", () => {
|
||||
|
||||
const stickyRailY = (await expectBoundingBoxAsync(rail)).y;
|
||||
await page.evaluate(() => window.scrollTo({ top: 500, behavior: "auto" }));
|
||||
await expect.poll(async () => (await expectBoundingBoxAsync(rail)).y).toBeGreaterThanOrEqual(0);
|
||||
const scrolledRailY = (await expectBoundingBoxAsync(rail)).y;
|
||||
expect(scrolledRailY).toBeGreaterThanOrEqual(0);
|
||||
expect(scrolledRailY).toBeLessThanOrEqual(stickyRailY + 0.5);
|
||||
await page.evaluate(() => window.scrollTo({ top: 0, behavior: "auto" }));
|
||||
|
||||
|
||||
Reference in new issue
Block a user