Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { useBrowserShellInteractionPassthrough } from "./useBrowserShellInteractionPassthrough";
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import type { WorkspaceInteractionState } from "@superset/panes";
import { useCallback, useEffect, useRef } from "react";
import { browserRuntimeRegistry } from "../usePaneRegistry/components/BrowserPane";

interface UseBrowserShellInteractionPassthroughArgs {
sidebarOpen: boolean;
}

export function useBrowserShellInteractionPassthrough({
sidebarOpen,
}: UseBrowserShellInteractionPassthroughArgs) {
const workspaceResizeActiveRef = useRef(false);
const sidebarResizeActiveRef = useRef(false);

const syncBrowserShellInteractionPassthrough = useCallback(() => {
browserRuntimeRegistry.setShellInteractionPassthrough(
workspaceResizeActiveRef.current || sidebarResizeActiveRef.current,
);
}, []);

const onWorkspaceInteractionStateChange = useCallback(
(state: WorkspaceInteractionState) => {
workspaceResizeActiveRef.current = state.resizeActive;
syncBrowserShellInteractionPassthrough();
},
[syncBrowserShellInteractionPassthrough],
);

const onSidebarResizeDragging = useCallback(
(isDragging: boolean) => {
sidebarResizeActiveRef.current = isDragging;
syncBrowserShellInteractionPassthrough();
},
[syncBrowserShellInteractionPassthrough],
);

const clearBrowserShellInteractionPassthrough = useCallback(() => {
workspaceResizeActiveRef.current = false;
sidebarResizeActiveRef.current = false;
browserRuntimeRegistry.setShellInteractionPassthrough(false);
}, []);

useEffect(() => {
window.addEventListener("blur", clearBrowserShellInteractionPassthrough);
return () => {
window.removeEventListener(
"blur",
clearBrowserShellInteractionPassthrough,
);
clearBrowserShellInteractionPassthrough();
};
}, [clearBrowserShellInteractionPassthrough]);

useEffect(() => {
if (sidebarOpen || !sidebarResizeActiveRef.current) return;
sidebarResizeActiveRef.current = false;
syncBrowserShellInteractionPassthrough();
}, [sidebarOpen, syncBrowserShellInteractionPassthrough]);

return {
onSidebarResizeDragging,
onWorkspaceInteractionStateChange,
};
}
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@ class BrowserRuntimeRegistryImpl {
private listenersByPaneId = new Map<string, Set<() => void>>();
private rootContainer: HTMLDivElement | null = null;
private globalListenersInstalled = false;
private windowDragPassthrough = false;
private shellInteractionPassthrough = false;

private getListeners(paneId: string): Set<() => void> {
let set = this.listenersByPaneId.get(paneId);
Expand All @@ -57,12 +59,16 @@ class BrowserRuntimeRegistryImpl {
}

private ensureRootContainer(): HTMLDivElement {
if (this.rootContainer?.isConnected) return this.rootContainer;
if (this.rootContainer?.isConnected) {
this.installGlobalListeners();
return this.rootContainer;
}
const existing = document.getElementById(
ROOT_CONTAINER_ID,
) as HTMLDivElement | null;
if (existing) {
this.rootContainer = existing;
this.installGlobalListeners();
return existing;
}
const root = document.createElement("div");
Expand All @@ -84,15 +90,22 @@ class BrowserRuntimeRegistryImpl {
if (this.globalListenersInstalled) return;
this.globalListenersInstalled = true;

const setPassthrough = (passthrough: boolean) => {
for (const entry of this.entries.values()) {
if (!entry.visible) continue;
entry.webview.style.pointerEvents = passthrough ? "none" : "auto";
}
};
window.addEventListener("dragstart", () => setPassthrough(true), true);
window.addEventListener("dragend", () => setPassthrough(false), true);
window.addEventListener("drop", () => setPassthrough(false), true);
window.addEventListener(
"dragstart",
() => this.setWindowDragPassthrough(true),
true,
Comment thread
cubic-dev-ai[bot] marked this conversation as resolved.
);
window.addEventListener(
"dragend",
() => this.setWindowDragPassthrough(false),
true,
);
window.addEventListener(
"drop",
() => this.setWindowDragPassthrough(false),
true,
);
window.addEventListener("blur", () => this.setWindowDragPassthrough(false));

window.addEventListener("resize", () => {
for (const entry of this.entries.values()) {
Expand All @@ -101,6 +114,35 @@ class BrowserRuntimeRegistryImpl {
});
}

private setWindowDragPassthrough(passthrough: boolean) {
const wasActive = this.isPointerPassthroughActive();
this.windowDragPassthrough = passthrough;
this.applyPointerPassthroughIfChanged(wasActive);
}

setShellInteractionPassthrough(passthrough: boolean): void {
const wasActive = this.isPointerPassthroughActive();
this.shellInteractionPassthrough = passthrough;
this.applyPointerPassthroughIfChanged(wasActive);
}

private isPointerPassthroughActive() {
return this.windowDragPassthrough || this.shellInteractionPassthrough;
}

private applyPointerPassthroughIfChanged(wasActive: boolean) {
const isActive = this.isPointerPassthroughActive();
if (wasActive !== isActive) this.applyPointerPassthrough();
}

private applyPointerPassthrough() {
const passthrough = this.isPointerPassthroughActive();
for (const entry of this.entries.values()) {
if (!entry.visible) continue;
entry.webview.style.pointerEvents = passthrough ? "none" : "auto";
}
}

private updateLayout(entry: RegistryEntry) {
if (!entry.placeholder) return;
const rect = entry.placeholder.getBoundingClientRect();
Expand Down Expand Up @@ -349,6 +391,7 @@ class BrowserRuntimeRegistryImpl {

this.updateLayout(entry);
entry.webview.style.visibility = "visible";
this.applyPointerPassthrough();
}

detach(paneId: string): void {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ import { V2NotificationStatusIndicator } from "./components/V2NotificationStatus
import { V2PresetsBar } from "./components/V2PresetsBar";
import { WorkspaceEmptyState } from "./components/WorkspaceEmptyState";
import { WorkspaceSidebar } from "./components/WorkspaceSidebar";
import { useBrowserShellInteractionPassthrough } from "./hooks/useBrowserShellInteractionPassthrough";
import { useConsumeAutomationRunLink } from "./hooks/useConsumeAutomationRunLink";
import { useConsumeOpenUrlRequest } from "./hooks/useConsumeOpenUrlRequest";
import { useConsumePendingLaunch } from "./hooks/useConsumePendingLaunch";
Expand Down Expand Up @@ -482,6 +483,8 @@ function WorkspaceContent({
);

const sidebarOpen = v2UserPreferences.rightSidebarOpen;
const { onSidebarResizeDragging, onWorkspaceInteractionStateChange } =
useBrowserShellInteractionPassthrough({ sidebarOpen });

useWorkspaceHotkeys({
store,
Expand Down Expand Up @@ -593,13 +596,14 @@ function WorkspaceContent({
});
});
}}
onInteractionStateChange={onWorkspaceInteractionStateChange}
store={store}
/>
</div>
</ResizablePanel>
{sidebarOpen && (
<>
<ResizableHandle />
<ResizableHandle onDragging={onSidebarResizeDragging} />
<ResizablePanel
className="min-w-[220px]"
defaultSize={20}
Expand Down
1 change: 1 addition & 0 deletions packages/panes/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ export type {
PaneRegistry,
RendererContext,
TabContext,
WorkspaceInteractionState,
WorkspaceProps,
} from "./react";
export { resolveTabTitle, Workspace } from "./react";
Expand Down
6 changes: 6 additions & 0 deletions packages/panes/src/react/components/Workspace/Workspace.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import type { Pane } from "../../../types";
import type { WorkspaceProps } from "../../types";
import { Tab } from "./components/Tab";
import { TabBar } from "./components/TabBar";
import { useWorkspaceInteractionState } from "./hooks/useWorkspaceInteractionState";
import { resolveTabTitle } from "./utils/resolveTabTitle";

export function Workspace<TData>({
Expand All @@ -17,12 +18,16 @@ export function Workspace<TData>({
renderAddTabMenu,
renderBelowTabBar,
onBeforeCloseTab,
onInteractionStateChange,
paneActions,
contextMenuActions,
}: WorkspaceProps<TData>) {
const tabs = useStore(store, (s) => s.tabs);
const activeTabId = useStore(store, (s) => s.activeTabId);
const activeTab = tabs.find((t) => t.id === activeTabId) ?? null;
const { onSplitResizeDragging } = useWorkspaceInteractionState({
onInteractionStateChange,
});

const previousPanesRef = useRef<Map<string, Pane<TData>>>(new Map());
useEffect(() => {
Expand Down Expand Up @@ -91,6 +96,7 @@ export function Workspace<TData>({
registry={registry}
paneActions={paneActions}
contextMenuActions={contextMenuActions}
onSplitResizeDragging={onSplitResizeDragging}
/>
) : (
<div className="flex min-h-0 min-w-0 flex-1 items-center justify-center text-sm text-muted-foreground">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import {
ResizablePanel,
ResizablePanelGroup,
} from "@superset/ui/resizable";
import { useRef } from "react";
import { useEffect, useRef } from "react";
import type { StoreApi } from "zustand/vanilla";
import type { WorkspaceStore } from "../../../../../core/store";
import type {
Expand All @@ -30,6 +30,7 @@ interface TabProps<TData> {
contextMenuActions?:
| ContextMenuActionConfig<TData>[]
| ((context: RendererContext<TData>) => ContextMenuActionConfig<TData>[]);
onSplitResizeDragging?: (sourceId: string, isDragging: boolean) => void;
}

function SplitView<TData>({
Expand All @@ -40,6 +41,7 @@ function SplitView<TData>({
registry,
paneActions,
contextMenuActions,
onSplitResizeDragging,
}: {
store: StoreApi<WorkspaceStore<TData>>;
tab: TabType<TData>;
Expand All @@ -48,10 +50,18 @@ function SplitView<TData>({
registry: PaneRegistry<TData>;
paneActions?: TabProps<TData>["paneActions"];
contextMenuActions?: TabProps<TData>["contextMenuActions"];
onSplitResizeDragging?: TabProps<TData>["onSplitResizeDragging"];
}) {
const groupRef = useRef<React.ComponentRef<typeof ResizablePanelGroup>>(null);
const firstSize = node.splitPercentage ?? 50;
const secondSize = 100 - firstSize;
const resizeSourceId = `${tab.id}:${path.join(".") || "root"}`;

useEffect(() => {
return () => {
onSplitResizeDragging?.(resizeSourceId, false);
};
}, [onSplitResizeDragging, resizeSourceId]);

return (
<ResizablePanelGroup
Expand Down Expand Up @@ -84,10 +94,15 @@ function SplitView<TData>({
registry={registry}
paneActions={paneActions}
contextMenuActions={contextMenuActions}
onSplitResizeDragging={onSplitResizeDragging}
parentDirection={node.direction}
/>
</ResizablePanel>
<ResizableHandle />
<ResizableHandle
onDragging={(isDragging) =>
onSplitResizeDragging?.(resizeSourceId, isDragging)
}
/>
<ResizablePanel
className={PANE_MIN_SIZE_CLASS_NAME}
defaultSize={secondSize}
Expand All @@ -100,6 +115,7 @@ function SplitView<TData>({
registry={registry}
paneActions={paneActions}
contextMenuActions={contextMenuActions}
onSplitResizeDragging={onSplitResizeDragging}
parentDirection={node.direction}
/>
</ResizablePanel>
Expand All @@ -115,6 +131,7 @@ function LayoutNodeView<TData>({
registry,
paneActions,
contextMenuActions,
onSplitResizeDragging,
parentDirection = null,
}: {
store: StoreApi<WorkspaceStore<TData>>;
Expand All @@ -124,6 +141,7 @@ function LayoutNodeView<TData>({
registry: PaneRegistry<TData>;
paneActions?: TabProps<TData>["paneActions"];
contextMenuActions?: TabProps<TData>["contextMenuActions"];
onSplitResizeDragging?: TabProps<TData>["onSplitResizeDragging"];
parentDirection?: "horizontal" | "vertical" | null;
}) {
if (node.type === "pane") {
Expand Down Expand Up @@ -153,6 +171,7 @@ function LayoutNodeView<TData>({
registry={registry}
paneActions={paneActions}
contextMenuActions={contextMenuActions}
onSplitResizeDragging={onSplitResizeDragging}
/>
);
}
Expand All @@ -163,6 +182,7 @@ export function Tab<TData>({
registry,
paneActions,
contextMenuActions,
onSplitResizeDragging,
}: TabProps<TData>) {
if (!tab.layout) {
return (
Expand All @@ -182,6 +202,7 @@ export function Tab<TData>({
registry={registry}
paneActions={paneActions}
contextMenuActions={contextMenuActions}
onSplitResizeDragging={onSplitResizeDragging}
/>
</div>
);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { useWorkspaceInteractionState } from "./useWorkspaceInteractionState";
Loading
Loading