({
registry={registry}
paneActions={paneActions}
contextMenuActions={contextMenuActions}
+ onSplitResizeDragging={onSplitResizeDragging}
/>
) : (
diff --git a/packages/panes/src/react/components/Workspace/components/Tab/Tab.tsx b/packages/panes/src/react/components/Workspace/components/Tab/Tab.tsx
index d4e52a2eeaf..7a8065bd18e 100644
--- a/packages/panes/src/react/components/Workspace/components/Tab/Tab.tsx
+++ b/packages/panes/src/react/components/Workspace/components/Tab/Tab.tsx
@@ -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 {
@@ -30,6 +30,7 @@ interface TabProps {
contextMenuActions?:
| ContextMenuActionConfig[]
| ((context: RendererContext) => ContextMenuActionConfig[]);
+ onSplitResizeDragging?: (sourceId: string, isDragging: boolean) => void;
}
function SplitView({
@@ -40,6 +41,7 @@ function SplitView({
registry,
paneActions,
contextMenuActions,
+ onSplitResizeDragging,
}: {
store: StoreApi>;
tab: TabType;
@@ -48,10 +50,18 @@ function SplitView({
registry: PaneRegistry;
paneActions?: TabProps["paneActions"];
contextMenuActions?: TabProps["contextMenuActions"];
+ onSplitResizeDragging?: TabProps["onSplitResizeDragging"];
}) {
const groupRef = useRef>(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 (
({
registry={registry}
paneActions={paneActions}
contextMenuActions={contextMenuActions}
+ onSplitResizeDragging={onSplitResizeDragging}
parentDirection={node.direction}
/>
-
+
+ onSplitResizeDragging?.(resizeSourceId, isDragging)
+ }
+ />
({
registry={registry}
paneActions={paneActions}
contextMenuActions={contextMenuActions}
+ onSplitResizeDragging={onSplitResizeDragging}
parentDirection={node.direction}
/>
@@ -115,6 +131,7 @@ function LayoutNodeView({
registry,
paneActions,
contextMenuActions,
+ onSplitResizeDragging,
parentDirection = null,
}: {
store: StoreApi>;
@@ -124,6 +141,7 @@ function LayoutNodeView({
registry: PaneRegistry;
paneActions?: TabProps["paneActions"];
contextMenuActions?: TabProps["contextMenuActions"];
+ onSplitResizeDragging?: TabProps["onSplitResizeDragging"];
parentDirection?: "horizontal" | "vertical" | null;
}) {
if (node.type === "pane") {
@@ -153,6 +171,7 @@ function LayoutNodeView({
registry={registry}
paneActions={paneActions}
contextMenuActions={contextMenuActions}
+ onSplitResizeDragging={onSplitResizeDragging}
/>
);
}
@@ -163,6 +182,7 @@ export function Tab({
registry,
paneActions,
contextMenuActions,
+ onSplitResizeDragging,
}: TabProps) {
if (!tab.layout) {
return (
@@ -182,6 +202,7 @@ export function Tab({
registry={registry}
paneActions={paneActions}
contextMenuActions={contextMenuActions}
+ onSplitResizeDragging={onSplitResizeDragging}
/>
);
diff --git a/packages/panes/src/react/components/Workspace/hooks/useWorkspaceInteractionState/index.ts b/packages/panes/src/react/components/Workspace/hooks/useWorkspaceInteractionState/index.ts
new file mode 100644
index 00000000000..0fb538d4c1f
--- /dev/null
+++ b/packages/panes/src/react/components/Workspace/hooks/useWorkspaceInteractionState/index.ts
@@ -0,0 +1 @@
+export { useWorkspaceInteractionState } from "./useWorkspaceInteractionState";
diff --git a/packages/panes/src/react/components/Workspace/hooks/useWorkspaceInteractionState/useWorkspaceInteractionState.ts b/packages/panes/src/react/components/Workspace/hooks/useWorkspaceInteractionState/useWorkspaceInteractionState.ts
new file mode 100644
index 00000000000..2693732f6f6
--- /dev/null
+++ b/packages/panes/src/react/components/Workspace/hooks/useWorkspaceInteractionState/useWorkspaceInteractionState.ts
@@ -0,0 +1,48 @@
+import { useCallback, useEffect, useRef } from "react";
+import type { WorkspaceInteractionState } from "../../../../types";
+
+interface UseWorkspaceInteractionStateOptions {
+ onInteractionStateChange?: (state: WorkspaceInteractionState) => void;
+}
+
+export function useWorkspaceInteractionState({
+ onInteractionStateChange,
+}: UseWorkspaceInteractionStateOptions) {
+ const splitResizeSourcesRef = useRef>(new Set());
+ const resizeActiveRef = useRef(false);
+ const onInteractionStateChangeRef = useRef(onInteractionStateChange);
+ onInteractionStateChangeRef.current = onInteractionStateChange;
+
+ const emitResizeActive = useCallback((resizeActive: boolean) => {
+ if (resizeActiveRef.current === resizeActive) return;
+ resizeActiveRef.current = resizeActive;
+ onInteractionStateChangeRef.current?.({ resizeActive });
+ }, []);
+
+ const clearResizeSources = useCallback(() => {
+ splitResizeSourcesRef.current.clear();
+ emitResizeActive(false);
+ }, [emitResizeActive]);
+
+ const onSplitResizeDragging = useCallback(
+ (sourceId: string, isDragging: boolean) => {
+ if (isDragging) {
+ splitResizeSourcesRef.current.add(sourceId);
+ } else {
+ splitResizeSourcesRef.current.delete(sourceId);
+ }
+ emitResizeActive(splitResizeSourcesRef.current.size > 0);
+ },
+ [emitResizeActive],
+ );
+
+ useEffect(() => {
+ window.addEventListener("blur", clearResizeSources);
+ return () => {
+ window.removeEventListener("blur", clearResizeSources);
+ clearResizeSources();
+ };
+ }, [clearResizeSources]);
+
+ return { onSplitResizeDragging };
+}
diff --git a/packages/panes/src/react/index.ts b/packages/panes/src/react/index.ts
index 4d825812559..a6fdb1547b4 100644
--- a/packages/panes/src/react/index.ts
+++ b/packages/panes/src/react/index.ts
@@ -7,5 +7,6 @@ export type {
PaneRegistry,
RendererContext,
TabContext,
+ WorkspaceInteractionState,
WorkspaceProps,
} from "./types";
diff --git a/packages/panes/src/react/types.ts b/packages/panes/src/react/types.ts
index ab4b3058de0..f91ccd0fc0c 100644
--- a/packages/panes/src/react/types.ts
+++ b/packages/panes/src/react/types.ts
@@ -82,6 +82,10 @@ export interface PaneDefinition {
export type PaneRegistry = Record>;
+export interface WorkspaceInteractionState {
+ resizeActive: boolean;
+}
+
export interface WorkspaceProps {
store: StoreApi>;
registry: PaneRegistry;
@@ -96,6 +100,7 @@ export interface WorkspaceProps {
tab: Tab,
) => boolean | Promise;
onBeforeCloseTab?: (tab: Tab) => boolean | Promise;
+ onInteractionStateChange?: (state: WorkspaceInteractionState) => void;
paneActions?:
| PaneActionConfig[]
| ((context: RendererContext) => PaneActionConfig[]);