fix focus scroll layering
This commit is contained in:
8 files changed
+44
-26
No files matched your search
@@ -35,7 +35,7 @@
|
||||
.surfaceHostAdvanced {
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
z-index: calc(var(--mantine-z-index-popover) - 1);
|
||||
z-index: calc(var(--mantine-z-index-modal) - 1);
|
||||
width: auto;
|
||||
height: auto;
|
||||
pointer-events: none;
|
||||
|
||||
@@ -201,7 +201,7 @@ export const BoardAdvancedFocusProvider = ({ children }: PropsWithChildren) => {
|
||||
data-advanced-focus-overlay
|
||||
backgroundOpacity={0.38}
|
||||
blur={0}
|
||||
zIndex="calc(var(--mantine-z-index-popover) - 2)"
|
||||
zIndex="calc(var(--mantine-z-index-modal) - 2)"
|
||||
className={`${classes.backdrop} ${active.phase === "closing" ? classes.backdropClosing : ""}`}
|
||||
aria-hidden
|
||||
/>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { CSSProperties, KeyboardEvent, MutableRefObject, WheelEvent } from "react";
|
||||
import type { CSSProperties, KeyboardEvent, MutableRefObject } from "react";
|
||||
import { useEffect, useRef } from "react";
|
||||
import { ActionIcon, Badge, Box, Card } from "@mantine/core";
|
||||
import { useElementSize, useViewportSize } from "@mantine/hooks";
|
||||
@@ -54,6 +54,7 @@ export const BoardItemContent = ({ item }: BoardItemContentProps) => {
|
||||
const [isEditMode] = useEditMode();
|
||||
const widgetStateRef = useRef<Record<string, unknown> | null>(null);
|
||||
const closeButtonRef = useRef<HTMLButtonElement>(null);
|
||||
const surfaceRef = useRef<HTMLDivElement>(null);
|
||||
const { active, open, close, dismiss, hover, leave } = useAdvancedFocus();
|
||||
const supportsAdvancedFocus = definitionSupportsAdvancedFocus(
|
||||
widgetImports[item.kind].definition as WidgetDefinition,
|
||||
@@ -90,12 +91,22 @@ export const BoardItemContent = ({ item }: BoardItemContentProps) => {
|
||||
event.preventDefault();
|
||||
openAdvanced(true);
|
||||
};
|
||||
const handleWheel = (event: WheelEvent<HTMLDivElement>) => {
|
||||
if (!isAdvanced || !event.shiftKey) return;
|
||||
const delta = event.deltaY || event.deltaX;
|
||||
if (!redirectShiftWheel(event.currentTarget, event.target, delta)) return;
|
||||
event.preventDefault();
|
||||
};
|
||||
useEffect(() => {
|
||||
const surface = surfaceRef.current;
|
||||
if (!isAdvanced || !surface) return;
|
||||
|
||||
const handleWheel = (event: WheelEvent) => {
|
||||
if (!event.shiftKey) return;
|
||||
const multiplier = event.deltaMode === 1 ? 16 : event.deltaMode === 2 ? surface.clientHeight : 1;
|
||||
const delta = (event.deltaY || event.deltaX) * multiplier;
|
||||
if (!redirectShiftWheel(surface, event.target, delta)) return;
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
};
|
||||
|
||||
surface.addEventListener("wheel", handleWheel, { capture: true, passive: false });
|
||||
return () => surface.removeEventListener("wheel", handleWheel, { capture: true });
|
||||
}, [isAdvanced]);
|
||||
|
||||
return (
|
||||
<>
|
||||
@@ -140,11 +151,11 @@ export const BoardItemContent = ({ item }: BoardItemContentProps) => {
|
||||
</ActionIcon>
|
||||
)}
|
||||
<Card
|
||||
ref={surfaceRef}
|
||||
id={isAdvanced ? advancedViewId : undefined}
|
||||
role={isAdvanced ? "region" : undefined}
|
||||
aria-label={isAdvanced ? advancedViewLabel : undefined}
|
||||
data-advanced-focus-surface={isAdvanced || undefined}
|
||||
onWheel={handleWheel}
|
||||
radius={board.itemRadius}
|
||||
p={isAdvanced ? undefined : 0}
|
||||
h={isAdvanced ? undefined : "100%"}
|
||||
|
||||
@@ -120,13 +120,30 @@ describe("Board advanced interactions", () => {
|
||||
probe.dataset.shiftScrollProbe = "true";
|
||||
probe.style.cssText = "height:80px;overflow-y:auto";
|
||||
probe.innerHTML = '<div style="height:600px"></div>';
|
||||
probe.addEventListener("wheel", (event) => event.stopPropagation());
|
||||
element.append(probe);
|
||||
});
|
||||
const scrollProbe = advancedSurface.locator("[data-shift-scroll-probe]");
|
||||
await page.keyboard.down("Shift");
|
||||
await scrollProbe.dispatchEvent("wheel", { shiftKey: true, deltaX: 120, deltaY: 0 });
|
||||
const pixelEventCancelled = await scrollProbe.evaluate(
|
||||
(element) =>
|
||||
!element.dispatchEvent(
|
||||
new WheelEvent("wheel", { bubbles: true, cancelable: true, shiftKey: true, deltaX: 120 }),
|
||||
),
|
||||
);
|
||||
expect(pixelEventCancelled).toBe(true);
|
||||
await scrollProbe.evaluate((element) => {
|
||||
element.scrollTop = 0;
|
||||
});
|
||||
const lineEventCancelled = await scrollProbe.evaluate(
|
||||
(element) =>
|
||||
!element.dispatchEvent(
|
||||
new WheelEvent("wheel", { bubbles: true, cancelable: true, shiftKey: true, deltaX: 3, deltaMode: 1 }),
|
||||
),
|
||||
);
|
||||
await page.keyboard.up("Shift");
|
||||
expect(await scrollProbe.evaluate((element) => element.scrollTop)).toBeGreaterThan(0);
|
||||
expect(lineEventCancelled).toBe(true);
|
||||
expect(await scrollProbe.evaluate((element) => element.scrollTop)).toBeGreaterThanOrEqual(48);
|
||||
await page.keyboard.press("Escape");
|
||||
await expect(advancedSurface).toBeHidden();
|
||||
await expect(widget).toBeFocused();
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
export interface StreamSession {
|
||||
sessionId: string;
|
||||
sessionName: string;
|
||||
user?: {
|
||||
user: {
|
||||
userId: string;
|
||||
username: string;
|
||||
profilePictureUrl: string | null;
|
||||
|
||||
@@ -28,7 +28,7 @@ export const DiskUsage = ({ system, fontSize, progressSize, valueMiw, valueGap =
|
||||
{formatPercent(system.disk)}
|
||||
</Text>
|
||||
<HoverCard
|
||||
zIndex={getDefaultZIndex("popover") - 3}
|
||||
zIndex={getDefaultZIndex("modal") - 3}
|
||||
position="right"
|
||||
withArrow
|
||||
shadow="md"
|
||||
|
||||
@@ -57,7 +57,7 @@ interface PortalTooltipProps {
|
||||
}
|
||||
|
||||
const MARGIN = 14;
|
||||
const TOOLTIP_Z_INDEX = getDefaultZIndex("modal");
|
||||
const BACKGROUND_TOOLTIP_Z_INDEX = getDefaultZIndex("modal") - 3;
|
||||
|
||||
const PortalTooltipContent = ({ active, label, payload, formatter, showTotal }: PortalTooltipProps) => {
|
||||
const mouseRef = useRef({ x: 0, y: 0 });
|
||||
@@ -123,7 +123,7 @@ const PortalTooltipContent = ({ active, label, payload, formatter, showTotal }:
|
||||
position: "fixed",
|
||||
left: pos.x,
|
||||
top: pos.y,
|
||||
zIndex: pos.isAdvanced ? getDefaultZIndex("popover") : TOOLTIP_Z_INDEX,
|
||||
zIndex: pos.isAdvanced ? getDefaultZIndex("modal") : BACKGROUND_TOOLTIP_Z_INDEX,
|
||||
pointerEvents: "none",
|
||||
};
|
||||
|
||||
|
||||
@@ -46,16 +46,6 @@ describe("getWidgetQueryKeys", () => {
|
||||
});
|
||||
|
||||
describe("supportsAdvancedFocus", () => {
|
||||
const definition = { supportsAdvancedFocus: undefined } as Parameters<typeof supportsAdvancedFocus>[0];
|
||||
|
||||
test("defaults to enabled", () => {
|
||||
expect(supportsAdvancedFocus(definition)).toBe(true);
|
||||
});
|
||||
|
||||
test("allows widgets to opt out", () => {
|
||||
expect(supportsAdvancedFocus({ ...definition, supportsAdvancedFocus: false })).toBe(false);
|
||||
});
|
||||
|
||||
test.each([appDefinition, beszelSystemGridDefinition, beszelSystemTableDefinition])(
|
||||
"keeps non-enhanced widgets compact",
|
||||
(widgetDefinition) => {
|
||||
|
||||
Reference in new issue
Block a user