diff --git a/packages/cli/src/templates/Canvas/index.tsx b/packages/cli/src/templates/Canvas/index.tsx
index 2e3454d2ac..cead118f15 100644
--- a/packages/cli/src/templates/Canvas/index.tsx
+++ b/packages/cli/src/templates/Canvas/index.tsx
@@ -1,5 +1,4 @@
import { useMemo, useState } from "react";
-import { cx } from "@emotion/css";
import { ReactFlowInstance } from "reactflow";
import {
HvButton,
@@ -28,6 +27,7 @@ import {
import {
HvCanvasBottomPanel,
HvCanvasBottomPanelProps,
+ HvCanvasProvider,
HvCanvasToolbar,
} from "@hitachivantara/uikit-react-pentaho";
@@ -201,97 +201,93 @@ const Page = () => {
return (
- setSidePanelOpen(value)}
- onTabChange={(event, value) => setSidePanelTab(value as number)}
- >
- {sidePanelContent[sidePanelTab]}
-
- }
- >
-
- Drag and Drop your Nodes
-
- }
- message={
-
+ setSidePanelOpen(value)}
+ onTabChange={(event, value) => setSidePanelTab(value as number)}
>
- Then you can start configuring your flow.
-
+ {sidePanelContent[sidePanelTab]}
+
}
- icon={null}
- />
-
-
-
- }
- >
-
- Execute
-
-
- {bottomTabs.length > 0 && bottomPanelOpen && (
-
-
-
- )}
- {bottomPanelOpen && (
- setFullscreen((prev) => !prev)}
+
+ Drag and Drop your Nodes
+
+ }
+ message={
+
+ Then you can start configuring your flow.
+
+ }
+ icon={null}
+ />
+
+
+
+ }
>
-
- {(
- bottomTabs?.find((x) => x.id === selectedTable)?.title as Function
- )(false)}
-
-
+
+ Execute
+
+
+ {bottomTabs.length > 0 && bottomPanelOpen && (
+
-
-
- )}
+
+ )}
+ {bottomPanelOpen && (
+ setFullscreen((prev) => !prev)}
+ >
+
+ {(
+ bottomTabs?.find((x) => x.id === selectedTable)
+ ?.title as Function
+ )(false)}
+
+
+
+
+
+ )}
+
);
};
diff --git a/packages/cli/src/templates/Canvas/styles.tsx b/packages/cli/src/templates/Canvas/styles.tsx
index bce6781890..3e31aa5ad4 100644
--- a/packages/cli/src/templates/Canvas/styles.tsx
+++ b/packages/cli/src/templates/Canvas/styles.tsx
@@ -22,16 +22,6 @@ export const classes = {
toolbar: css({
top: `calc(${theme.header.height} + ${theme.header.secondLevelHeight} + ${theme.space.md})`,
}),
- fullWidth: css({
- right: theme.space.lg,
- marginLeft: "auto",
- marginRight: "auto",
- width: `calc(100% - 2 * ${theme.space.lg})`,
- }),
- minWidth: css({
- right: theme.space.lg,
- width: `calc(100% - 320px - 3 * ${theme.space.lg})`,
- }),
panel: css({
top: `calc(${theme.header.height} + ${theme.header.secondLevelHeight})`,
height: `calc(100% - ${theme.header.height} - ${theme.header.secondLevelHeight})`,
diff --git a/packages/pentaho/src/Canvas/BottomPanel/BottomPanel.tsx b/packages/pentaho/src/Canvas/BottomPanel/BottomPanel.tsx
index 89d5649501..4df01a206d 100644
--- a/packages/pentaho/src/Canvas/BottomPanel/BottomPanel.tsx
+++ b/packages/pentaho/src/Canvas/BottomPanel/BottomPanel.tsx
@@ -13,6 +13,7 @@ import {
useUniqueId,
} from "@hitachivantara/uikit-react-core";
+import { useCanvasContext } from "../CanvasContext";
import { HvCanvasPanelTab } from "../PanelTab";
import { HvCanvasPanelTabs, HvCanvasPanelTabsProps } from "../PanelTabs";
import { staticClasses, useClasses } from "./BottomPanel.styles";
@@ -91,6 +92,9 @@ export const HvCanvasBottomPanel = forwardRef<
const { classes, cx } = useClasses(classesProp);
+ const canvasContext = useCanvasContext();
+ const sidePanelWidth = canvasContext?.sidePanelWidth ?? 0;
+
const id = useUniqueId(idProp);
// Tab resize detector: to position tab actions and set the panel top right border radius
@@ -158,6 +162,10 @@ export const HvCanvasBottomPanel = forwardRef<
},
className,
)}
+ style={{
+ width: `calc(100% - ${sidePanelWidth}px - 2 * ${theme.space.sm})`,
+ right: theme.space.sm,
+ }}
{...others}
>
diff --git a/packages/pentaho/src/Canvas/CanvasContext.tsx b/packages/pentaho/src/Canvas/CanvasContext.tsx
new file mode 100644
index 0000000000..a9522bf251
--- /dev/null
+++ b/packages/pentaho/src/Canvas/CanvasContext.tsx
@@ -0,0 +1,54 @@
+import {
+ createContext,
+ useCallback,
+ useContext,
+ useMemo,
+ useState,
+} from "react";
+
+type HvCanvasContextValue = {
+ sidePanelOpen: boolean;
+ handleSidePanelOpen: (open: boolean) => void;
+ sidePanelWidth: number;
+ handleSidePanelWidth: (width: number) => void;
+};
+
+export const HvCanvasContext = createContext
(null);
+
+export const HvCanvasProvider = ({
+ children,
+}: {
+ children: React.ReactNode;
+ onSidePanelResize?: (width: number) => void;
+}) => {
+ const [sidePanelOpen, setSidePanelOpen] = useState(false);
+ const [width, setWidth] = useState(0);
+
+ const handleSidePanelWidth = useCallback((newWidth: number) => {
+ setWidth(newWidth);
+ }, []);
+
+ const handleSidePanelOpen = useCallback((open: boolean) => {
+ setSidePanelOpen(open);
+ }, []);
+
+ const value = useMemo(
+ () => ({
+ sidePanelOpen,
+ handleSidePanelOpen,
+ sidePanelWidth: sidePanelOpen ? width : 0,
+ handleSidePanelWidth,
+ }),
+ [sidePanelOpen, handleSidePanelOpen, width, handleSidePanelWidth],
+ );
+
+ return (
+
+ {children}
+
+ );
+};
+
+export const useCanvasContext = () => {
+ return useContext(HvCanvasContext);
+};
diff --git a/packages/pentaho/src/Canvas/SidePanel/SidePanel.test.tsx b/packages/pentaho/src/Canvas/SidePanel/SidePanel.test.tsx
index 2dd86afc9f..b12fa08332 100644
--- a/packages/pentaho/src/Canvas/SidePanel/SidePanel.test.tsx
+++ b/packages/pentaho/src/Canvas/SidePanel/SidePanel.test.tsx
@@ -4,6 +4,7 @@ import userEvent from "@testing-library/user-event";
import { describe, expect, it, vi } from "vitest";
import { HvButton } from "@hitachivantara/uikit-react-core";
+import { HvCanvasProvider } from "../CanvasContext";
import { HvCanvasSidePanel, HvCanvasSidePanelProps } from "./SidePanel";
const label = "Test";
@@ -21,9 +22,11 @@ const tabs = [
const renderSimplePanel = (props?: HvCanvasSidePanelProps) =>
render(
-
- {label}
- ,
+
+
+ {label}
+
+ ,
);
const ControlledPanel = ({
diff --git a/packages/pentaho/src/Canvas/SidePanel/SidePanel.tsx b/packages/pentaho/src/Canvas/SidePanel/SidePanel.tsx
index f933063f34..8cf1746004 100644
--- a/packages/pentaho/src/Canvas/SidePanel/SidePanel.tsx
+++ b/packages/pentaho/src/Canvas/SidePanel/SidePanel.tsx
@@ -1,4 +1,4 @@
-import { forwardRef } from "react";
+import { forwardRef, useEffect } from "react";
import {
ExtractNames,
HvBaseProps,
@@ -11,6 +11,7 @@ import {
} from "@hitachivantara/uikit-react-core";
import { End } from "@hitachivantara/uikit-react-icons";
+import { useCanvasContext } from "../CanvasContext";
import { HvCanvasPanelTab } from "../PanelTab";
import { HvCanvasPanelTabs, HvCanvasPanelTabsProps } from "../PanelTabs";
import { staticClasses, useClasses } from "./SidePanel.styles";
@@ -26,7 +27,7 @@ const DEFAULT_LABELS = {
};
export interface HvCanvasSidePanelProps
- extends HvBaseProps {
+ extends HvBaseProps {
/** When controlled, defines id the panel is open or not. */
open?: boolean;
/** When uncontrolled, defines the initial state of the panel. */
@@ -50,6 +51,14 @@ export interface HvCanvasSidePanelProps
) => void;
/** An object containing all the labels. */
labels?: Partial;
+ /** The minimum width of the side panel. */
+ minWidth?: number;
+ /** The maximum width of the side panel. */
+ maxWidth?: number;
+ /** The initial width of the side panel. */
+ initialWidth?: number;
+ /** Callback triggered when the panel width changes. */
+ onResize?: (width: number) => void;
/** The content that will be rendered within the canvas panel. */
children?: React.ReactNode;
/** A Jss Object used to override or extend the styles applied. */
@@ -72,6 +81,10 @@ export const HvCanvasSidePanel = forwardRef<
onToggle,
onTabChange,
labels: labelsProp,
+ minWidth = 100,
+ maxWidth = 500,
+ initialWidth = 320,
+ onResize,
className,
children,
classes: classesProp,
@@ -80,6 +93,11 @@ export const HvCanvasSidePanel = forwardRef<
const id = useUniqueId(idProp);
+ const canvasContext = useCanvasContext();
+ const handleSidePanelWidth = canvasContext?.handleSidePanelWidth;
+ const sidePanelOpen = canvasContext?.sidePanelOpen;
+ const handleSidePanelOpen = canvasContext?.handleSidePanelOpen;
+
const { classes, cx } = useClasses(classesProp);
const labels = useLabels(DEFAULT_LABELS, labelsProp);
@@ -90,16 +108,28 @@ export const HvCanvasSidePanel = forwardRef<
tabs?.[0]?.id ?? "none",
);
+ useEffect(() => {
+ handleSidePanelWidth?.(initialWidth);
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ }, [initialWidth]);
+
+ const updateWidth = (width: number) => {
+ handleSidePanelWidth?.(width);
+ onResize?.(width);
+ };
+
const { width, isDragging, getContainerProps, getSeparatorProps } =
useResizable({
ref,
- initialWidth: 320,
- minWidth: 100,
- maxWidth: 500,
+ initialWidth,
+ minWidth,
+ maxWidth,
+ onResize: updateWidth,
});
const handleTogglePanel = (event: React.MouseEvent | React.KeyboardEvent) => {
setOpen((prev) => !prev);
+ handleSidePanelOpen?.(!sidePanelOpen);
onToggle?.(event, !open);
};
diff --git a/packages/pentaho/src/Canvas/SidePanel/useResizable.tsx b/packages/pentaho/src/Canvas/SidePanel/useResizable.tsx
index 82d56b8b89..64743ef3b3 100644
--- a/packages/pentaho/src/Canvas/SidePanel/useResizable.tsx
+++ b/packages/pentaho/src/Canvas/SidePanel/useResizable.tsx
@@ -16,9 +16,10 @@ interface SeparatorProps {
interface ResizableProps {
ref: any;
- initialWidth?: number;
- minWidth?: number;
- maxWidth?: number;
+ initialWidth: number;
+ minWidth: number;
+ maxWidth: number;
+ onResize?: (width: number) => void;
}
export const useResizable = (
@@ -29,12 +30,7 @@ export const useResizable = (
getContainerProps: (overrides: any) => ContainerProps;
getSeparatorProps: () => SeparatorProps;
} => {
- const {
- ref,
- initialWidth = 320,
- minWidth = 100,
- maxWidth = 600,
- } = resizableOptions;
+ const { ref, initialWidth, minWidth, maxWidth, onResize } = resizableOptions;
const [width, setWidth] = useState(initialWidth);
const [isHover, setIsHover] = useState(false);
@@ -50,6 +46,7 @@ export const useResizable = (
const newWidth = event.clientX - rect.left;
if (newWidth >= minWidth && newWidth <= maxWidth) {
setWidth(newWidth);
+ onResize?.(newWidth);
}
}
};
diff --git a/packages/pentaho/src/Canvas/Toolbar/Toolbar.styles.tsx b/packages/pentaho/src/Canvas/Toolbar/Toolbar.styles.tsx
index b8d35d06ae..9ebbcfba6e 100644
--- a/packages/pentaho/src/Canvas/Toolbar/Toolbar.styles.tsx
+++ b/packages/pentaho/src/Canvas/Toolbar/Toolbar.styles.tsx
@@ -2,14 +2,14 @@ import { createClasses, theme } from "@hitachivantara/uikit-react-core";
export const { staticClasses, useClasses } = createClasses("HvCanvasToolbar", {
root: {
- width: "100%",
+ width: `calc(100% - var(--sidepanel-width) - 2 * ${theme.space.sm})`,
height: 54,
display: "flex",
alignItems: "center",
borderRadius: theme.radii.full,
backgroundColor: theme.colors.atmo1,
position: "absolute",
- right: 0,
+ right: theme.space.sm,
top: 0,
transition: "width 0.3s ease",
},
diff --git a/packages/pentaho/src/Canvas/Toolbar/Toolbar.tsx b/packages/pentaho/src/Canvas/Toolbar/Toolbar.tsx
index 2ecb5d0afb..e74748ca37 100644
--- a/packages/pentaho/src/Canvas/Toolbar/Toolbar.tsx
+++ b/packages/pentaho/src/Canvas/Toolbar/Toolbar.tsx
@@ -1,4 +1,5 @@
import { forwardRef } from "react";
+import { mergeStyles } from "packages/utils/src";
import {
ExtractNames,
HvBaseProps,
@@ -10,6 +11,7 @@ import {
} from "@hitachivantara/uikit-react-core";
import { Previous } from "@hitachivantara/uikit-react-icons";
+import { useCanvasContext } from "../CanvasContext";
import { staticClasses, useClasses } from "./Toolbar.styles";
export { staticClasses as canvasToolbarClasses };
@@ -46,6 +48,7 @@ export const HvCanvasToolbar = forwardRef(
backButton,
labels: labelsProp,
className,
+ style,
children,
backButtonProps,
classes: classesProp,
@@ -55,6 +58,9 @@ export const HvCanvasToolbar = forwardRef(
const { classes, cx } = useClasses(classesProp);
const labels = useLabels(DEFAULT_LABELS, labelsProp);
+ const canvasContext = useCanvasContext();
+ const sidePanelWidth = canvasContext?.sidePanelWidth ?? 0;
+
const title =
typeof titleProp === "string" ? (
{titleProp}
@@ -63,7 +69,14 @@ export const HvCanvasToolbar = forwardRef(
);
return (
-