fix: Restructure WidgetNameCanvas (#28202)
#### PR fixes following issue(s) Fixes #28201 #### Type of change - New feature (non-breaking change which adds functionality) - doesn't effect user perception #### How Has This Been Tested? - [ ] Manual - [ ] JUnit - [ ] Jest - [ ] Cypress #### Test Plan #### Issues raised during DP testing ## Checklist: #### Dev activity - [ ] My code follows the style guidelines of this project - [ ] I have performed a self-review of my own code - [ ] I have commented my code, particularly in hard-to-understand areas - [ ] I have made corresponding changes to the documentation - [ ] My changes generate no new warnings - [ ] I have added tests that prove my fix is effective or that my feature works - [ ] New and existing unit tests pass locally with my changes - [ ] PR is being merged under a feature flag #### QA activity: - [ ] [Speedbreak features](https://github.com/appsmithorg/TestSmith/wiki/Guidelines-for-test-plans#speedbreakers-) have been covered - [ ] Test plan covers all impacted features and [areas of interest](https://github.com/appsmithorg/TestSmith/wiki/Guidelines-for-test-plans#areas-of-interest-) - [ ] Test plan has been peer reviewed by project stakeholders and other QA members - [ ] Manually tested functionality on DP - [ ] We had an implementation alignment call with stakeholders post QA Round 2 - [ ] Cypress test cases have been added and approved by SDET/manual QA - [ ] Added `Test Plan Approved` label after Cypress tests were reviewed - [ ] Added `Test Plan Approved` label after JUnit tests were reviewed
This commit is contained in:
parent
af9e89d2a1
commit
49c222c4a5
|
|
@ -17,7 +17,7 @@ module.exports = {
|
|||
moduleFileExtensions: ["ts", "tsx", "js", "jsx", "json", "node", "css"],
|
||||
moduleDirectories: ["node_modules", "src", "test"],
|
||||
transformIgnorePatterns: [
|
||||
"<rootDir>/node_modules/(?!codemirror|design-system|design-system-old|react-dnd|dnd-core|@babel|(@blueprintjs)|@github|lodash-es|@draft-js-plugins|react-documents|linkedom|assert-never)",
|
||||
"<rootDir>/node_modules/(?!codemirror|konva|design-system|design-system-old|react-dnd|dnd-core|@babel|(@blueprintjs)|@github|lodash-es|@draft-js-plugins|react-documents|linkedom|assert-never)",
|
||||
],
|
||||
moduleNameMapper: {
|
||||
"\\.(css|less)$": "<rootDir>/test/__mocks__/styleMock.js",
|
||||
|
|
|
|||
|
|
@ -288,6 +288,7 @@
|
|||
"@typescript-eslint/parser": "^6.7.4",
|
||||
"babel-plugin-lodash": "^3.3.4",
|
||||
"babel-plugin-module-resolver": "^4.1.0",
|
||||
"canvas": "^2.11.2",
|
||||
"chalk": "^4.1.1",
|
||||
"compression-webpack-plugin": "^10.0.0",
|
||||
"cra-bundle-analyzer": "^0.1.0",
|
||||
|
|
|
|||
|
|
@ -31,3 +31,23 @@ export interface CanvasPositions {
|
|||
yDiff: number;
|
||||
height: number;
|
||||
}
|
||||
|
||||
export interface WidgetNamePositionType {
|
||||
selected: WidgetNamePositionData | undefined;
|
||||
focused: WidgetNamePositionData | undefined;
|
||||
}
|
||||
|
||||
// TODO(abhinav): Update this at the source of the setDraggingState function
|
||||
export type SetDragginStateFnType = ({
|
||||
draggedOn,
|
||||
draggingGroupCenter,
|
||||
dragGroupActualParent,
|
||||
isDragging,
|
||||
startPoints,
|
||||
}: {
|
||||
isDragging: boolean;
|
||||
dragGroupActualParent?: string | undefined;
|
||||
draggingGroupCenter?: Record<string, any> | undefined;
|
||||
startPoints?: any;
|
||||
draggedOn?: string | undefined;
|
||||
}) => void;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,179 @@
|
|||
import type { DragEventHandler, MutableRefObject, DragEvent } from "react";
|
||||
import type {
|
||||
CanvasPositions,
|
||||
SetDragginStateFnType,
|
||||
WidgetNamePositionType,
|
||||
} from "./WidgetNameTypes";
|
||||
import { throttle } from "lodash";
|
||||
import { getMainContainerAnvilCanvasDOMElement } from "./widgetNameRenderUtils";
|
||||
|
||||
/**
|
||||
* This returns a callback for scroll event on the MainContainer
|
||||
*
|
||||
* This callback does the following:
|
||||
* 1. Sets the scrolling state to 1 if it is not already set to 0.
|
||||
* A value of 0 signifies that we've only just started scrolling and this event has triggered
|
||||
* So, we set it to 1 after we've reset the canvas.
|
||||
* We reset the canvas as we donot want to show any widget names while scrolling.
|
||||
*
|
||||
* 2. We update the scrollTop in a ref. This is used to calculate the position of the widget name
|
||||
* We also wrap this in a requestAnimationFrame to ensure that we get the latest scrollTop value and it doesn't cause layout thrashing
|
||||
*
|
||||
* 3. If there is actually a scroll ofset, we set hasScroll to true
|
||||
*
|
||||
* @returns void
|
||||
*/
|
||||
export function getScrollHandler(
|
||||
isScrolling: MutableRefObject<number>,
|
||||
hasScroll: MutableRefObject<boolean>,
|
||||
resetCanvas: () => void,
|
||||
scrollTop: MutableRefObject<number>,
|
||||
) {
|
||||
return function handleScroll() {
|
||||
const scrollParent: HTMLDivElement | null =
|
||||
getMainContainerAnvilCanvasDOMElement();
|
||||
if (!scrollParent) return;
|
||||
|
||||
if (isScrolling.current === 0) {
|
||||
isScrolling.current = 1;
|
||||
resetCanvas();
|
||||
}
|
||||
|
||||
window.requestAnimationFrame(() => {
|
||||
scrollTop.current = scrollParent.scrollTop;
|
||||
if (scrollParent.scrollHeight > scrollParent.clientHeight) {
|
||||
hasScroll.current = true;
|
||||
}
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* This returns a callback for scroll end event on the MainContainer
|
||||
*
|
||||
* This callback does the following:
|
||||
* 1. Sets the scrolling state to 0 (see handleScroll)
|
||||
* 2. If there is a scroll offset, we update the positions of the selected and focused widget names
|
||||
*/
|
||||
export function getScrollEndHandler(
|
||||
isScrolling: MutableRefObject<number>,
|
||||
hasScroll: MutableRefObject<boolean>,
|
||||
updateSelectedWidgetPositions: () => void,
|
||||
) {
|
||||
return function handleScrollEnd() {
|
||||
isScrolling.current = 0;
|
||||
if (hasScroll.current) {
|
||||
updateSelectedWidgetPositions();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* This Method verifies if the mouse position coincides with any widget name drawn on canvas
|
||||
* and returns details regarding the widget
|
||||
* @param e Mouse event
|
||||
* @returns Mainly isMouseOver indicating if the mouse is on any one of the widget name
|
||||
* if true also returns data regarding the widget
|
||||
*/
|
||||
export function getMouseOverDetails(
|
||||
e: MouseEvent,
|
||||
canvasPositions: MutableRefObject<CanvasPositions>,
|
||||
widgetNamePositions: MutableRefObject<WidgetNamePositionType>,
|
||||
) {
|
||||
const x = e.clientX - canvasPositions.current.left;
|
||||
const y = e.clientY - canvasPositions.current.top;
|
||||
const widgetNamePositionsArray = Object.values(widgetNamePositions.current);
|
||||
|
||||
//for selected and focused widget names check the widget name positions with respect to mouse positions
|
||||
for (const widgetNamePosition of widgetNamePositionsArray) {
|
||||
if (widgetNamePosition) {
|
||||
const { height, left, top, widgetNameData, width } = widgetNamePosition;
|
||||
if (x > left && x < left + width && y > top && y < top + height) {
|
||||
return { isMouseOver: true, cursor: "pointer", widgetNameData };
|
||||
}
|
||||
}
|
||||
}
|
||||
return { isMouseOver: false };
|
||||
}
|
||||
|
||||
export function getMouseMoveHandler(
|
||||
wrapperRef: MutableRefObject<HTMLDivElement | null>,
|
||||
canvasPositions: MutableRefObject<CanvasPositions>,
|
||||
widgetNamePositions: MutableRefObject<WidgetNamePositionType>,
|
||||
) {
|
||||
/**
|
||||
* Mouse Move event function, this tracks every mouse move on canvas such that
|
||||
* if the mouse position coincides with the positions of widget name, it makes the canvas intractable
|
||||
* This is throttled since it tracks every single mouse move
|
||||
*/
|
||||
return throttle((e: MouseEvent) => {
|
||||
const wrapper = wrapperRef?.current as HTMLDivElement;
|
||||
if (!wrapper) return;
|
||||
|
||||
//check if the mouse is coinciding with the widget name drawing on canvas
|
||||
const { cursor, isMouseOver } = getMouseOverDetails(
|
||||
e,
|
||||
canvasPositions,
|
||||
widgetNamePositions,
|
||||
);
|
||||
|
||||
//if mouse over make the canvas intractable
|
||||
if (isMouseOver) {
|
||||
if (wrapper.style.pointerEvents === "none") {
|
||||
wrapper.style.pointerEvents = "auto";
|
||||
}
|
||||
} // if not mouse over then keep it default
|
||||
else if (wrapper.style.pointerEvents !== "none") {
|
||||
wrapper.style.pointerEvents = "none";
|
||||
wrapper.style.cursor = "default";
|
||||
}
|
||||
|
||||
//set cursor based on intractability
|
||||
if (!cursor) {
|
||||
wrapper.style.cursor = "default";
|
||||
} else if (wrapper.style.cursor !== cursor) {
|
||||
wrapper.style.cursor = cursor;
|
||||
}
|
||||
}, 20);
|
||||
}
|
||||
|
||||
/**
|
||||
* on Drag Start event handler to enable drag of widget from the widget name component drawing on canvas
|
||||
*/
|
||||
export function getDragStartHandler(
|
||||
showTableFilterPane: () => void,
|
||||
setDraggingState: SetDragginStateFnType,
|
||||
shouldAllowDrag: boolean,
|
||||
canvasPositions: MutableRefObject<CanvasPositions>,
|
||||
widgetNamePositions: MutableRefObject<WidgetNamePositionType>,
|
||||
): DragEventHandler {
|
||||
return (e: DragEvent<HTMLDivElement>) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
|
||||
//checks if the mouse is over the widget name, if so return it's details
|
||||
const { isMouseOver, widgetNameData } = getMouseOverDetails(
|
||||
e as unknown as MouseEvent,
|
||||
canvasPositions,
|
||||
widgetNamePositions,
|
||||
);
|
||||
|
||||
if (!isMouseOver || !shouldAllowDrag || widgetNameData?.dragDisabled)
|
||||
return;
|
||||
|
||||
//set dragging state
|
||||
const startPoints = {
|
||||
top: 0,
|
||||
left: 0,
|
||||
};
|
||||
showTableFilterPane();
|
||||
setDraggingState({
|
||||
isDragging: true,
|
||||
dragGroupActualParent: widgetNameData?.parentId,
|
||||
draggingGroupCenter: { widgetId: widgetNameData?.id },
|
||||
startPoints,
|
||||
draggedOn: widgetNameData?.parentId,
|
||||
});
|
||||
};
|
||||
}
|
||||
|
|
@ -1,10 +1,7 @@
|
|||
import type { DragEventHandler, DragEvent } from "react";
|
||||
import React, { useEffect, useRef } from "react";
|
||||
import { useSelector } from "react-redux";
|
||||
import { throttle } from "lodash";
|
||||
import { Layer, Stage } from "react-konva/lib/ReactKonvaCore";
|
||||
import { useWidgetSelection } from "utils/hooks/useWidgetSelection";
|
||||
import { SelectionRequestType } from "sagas/WidgetSelectUtils";
|
||||
|
||||
import {
|
||||
useShowTableFilterPane,
|
||||
|
|
@ -13,12 +10,10 @@ import {
|
|||
import type {
|
||||
CanvasPositions,
|
||||
WidgetNameData,
|
||||
WidgetNamePositionData,
|
||||
WIDGET_NAME_TYPE,
|
||||
WidgetNamePositionType,
|
||||
} from "./WidgetNameTypes";
|
||||
import {
|
||||
DEFAULT_WIDGET_NAME_CANVAS_HEIGHT,
|
||||
WIDGET_NAME_CANVAS_PADDING,
|
||||
widgetNameWrapperStyle,
|
||||
WIDGET_NAME_CANVAS,
|
||||
} from "./WidgetNameConstants";
|
||||
|
|
@ -26,11 +21,20 @@ import {
|
|||
getFocusedWidgetNameData,
|
||||
getSelectedWidgetNameData,
|
||||
} from "../selectors";
|
||||
import type { LayoutElementPosition } from "layoutSystems/common/types";
|
||||
|
||||
import { getShouldAllowDrag } from "selectors/widgetDragSelectors";
|
||||
import type { Stage as CanvasStageType } from "konva/lib/Stage";
|
||||
import type { Layer as KonvaLayer } from "konva/lib/Layer";
|
||||
import { getWidgetNameComponent } from "./utils";
|
||||
import {
|
||||
getMainContainerAnvilCanvasDOMElement,
|
||||
resetCanvas,
|
||||
updateSelectedWidgetPositions,
|
||||
} from "./widgetNameRenderUtils";
|
||||
import {
|
||||
getDragStartHandler,
|
||||
getMouseMoveHandler,
|
||||
getScrollEndHandler,
|
||||
getScrollHandler,
|
||||
} from "./eventHandlers";
|
||||
|
||||
/**
|
||||
* This Component contains logic to draw widget name on canvas
|
||||
|
|
@ -38,34 +42,31 @@ import { getWidgetNameComponent } from "./utils";
|
|||
* @param props Object that contains
|
||||
* @prop canvasWidth width of canvas in pixels
|
||||
* @prop containerRef ref of PageViewWrapper component
|
||||
* @prop parentRef ref of the MainContainerWrapper component i.e, the parent of the canvas component
|
||||
*/
|
||||
const OverlayCanvasContainer = (props: {
|
||||
canvasWidth: number;
|
||||
containerRef: React.RefObject<HTMLDivElement>;
|
||||
parentRef: React.RefObject<HTMLDivElement>;
|
||||
containerRef: React.RefObject<HTMLDivElement | null>;
|
||||
}) => {
|
||||
//widget name data of widgets
|
||||
const selectedWidgetNameData: WidgetNameData | undefined = useSelector(
|
||||
const selectedWidgetNameData: WidgetNameData[] | undefined = useSelector(
|
||||
getSelectedWidgetNameData,
|
||||
);
|
||||
const focusedWidgetNameData: WidgetNameData | undefined = useSelector(
|
||||
getFocusedWidgetNameData,
|
||||
);
|
||||
|
||||
// should we allow dragging of widgets
|
||||
const shouldAllowDrag = useSelector(getShouldAllowDrag);
|
||||
|
||||
const wrapperRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
// used to keep track of positions of widgetName drawn on canvas to make it intractable
|
||||
const widgetNamePositions = useRef<{
|
||||
selected: WidgetNamePositionData | undefined;
|
||||
focused: WidgetNamePositionData | undefined;
|
||||
}>({ selected: undefined, focused: undefined });
|
||||
|
||||
// When we begin dragging, the drag and resize hooks need a few details to take over
|
||||
const { setDraggingState } = useWidgetDragResize();
|
||||
const showTableFilterPane = useShowTableFilterPane();
|
||||
const { selectWidget } = useWidgetSelection();
|
||||
|
||||
const wrapperRef = useRef<HTMLDivElement>(null);
|
||||
// used to keep track of positions of widgetName drawn on canvas to make it intractable
|
||||
const widgetNamePositions = useRef<WidgetNamePositionType>({
|
||||
selected: undefined,
|
||||
focused: undefined,
|
||||
});
|
||||
//Positions of canvas
|
||||
const canvasPositions = useRef<CanvasPositions>({
|
||||
top: 0,
|
||||
|
|
@ -77,19 +78,28 @@ const OverlayCanvasContainer = (props: {
|
|||
});
|
||||
|
||||
const scrollTop = useRef<number>(0);
|
||||
const isScrolling = useRef(0);
|
||||
const isScrolling = useRef<number>(0);
|
||||
const hasScroll = useRef<boolean>(false);
|
||||
const stageRef = useRef<CanvasStageType>(null);
|
||||
const stageRef = useRef<CanvasStageType | null>(null);
|
||||
|
||||
const { selectWidget } = useWidgetSelection();
|
||||
// Pre bind arguments to the updateSelectedWidgetPositions function
|
||||
// This makes it easier to use the function later in the code
|
||||
const updateFn = updateSelectedWidgetPositions.bind(this, {
|
||||
stageRef,
|
||||
selectedWidgetNameData,
|
||||
focusedWidgetNameData,
|
||||
selectWidget,
|
||||
scrollTop,
|
||||
widgetNamePositions,
|
||||
canvasPositions,
|
||||
});
|
||||
|
||||
//used to set canvasPositions, which is used further to calculate the exact positions of widgets
|
||||
// Used to set canvasPositions, which is used further to calculate the exact positions of widgets
|
||||
useEffect(() => {
|
||||
if (!stageRef?.current?.content || !wrapperRef?.current) return;
|
||||
|
||||
const HTMLCanvas: HTMLDivElement = stageRef?.current?.content;
|
||||
const rect: DOMRect = HTMLCanvas.getBoundingClientRect();
|
||||
|
||||
const wrapper: HTMLDivElement = wrapperRef?.current as HTMLDivElement;
|
||||
const wrapperRect: DOMRect = wrapper.getBoundingClientRect();
|
||||
|
||||
|
|
@ -99,266 +109,86 @@ const OverlayCanvasContainer = (props: {
|
|||
height: wrapperRect.height,
|
||||
left: rect.left,
|
||||
top: rect.top,
|
||||
width: rect.width,
|
||||
width: wrapperRect.width,
|
||||
};
|
||||
}
|
||||
}, [wrapperRef?.current, props.canvasWidth]);
|
||||
|
||||
/**
|
||||
* Method used to add widget name to the Konva canvas' layer
|
||||
* @param layer Konva layer onto which the widget name is to be added
|
||||
* @param widgetNameData widget name data contains more information regarding the widget that is used in drawing the name
|
||||
* @param position position of widget in pixels
|
||||
* @param type if it's either selected or focused widget name
|
||||
* Adds 3 event listeners.
|
||||
* 1. Mouse Move: On the container, to check if the mouse is over a widget, so that we can focus it
|
||||
* 2. Scroll: On the MainContainer, to check if the user is scrolling. This is so that we can hide the widget names
|
||||
* Also, this tells us that we need to compute and store scroll offset values to correctly position the widget name components.
|
||||
* 3. Scroll End: On the MainContainer, to check if the user has stopped scrolling. This is so that we can show the widget names again
|
||||
*/
|
||||
const addWidgetNameToCanvas = (
|
||||
layer: KonvaLayer,
|
||||
widgetNameData: WidgetNameData,
|
||||
position: LayoutElementPosition,
|
||||
type: WIDGET_NAME_TYPE,
|
||||
) => {
|
||||
if (!position) return;
|
||||
|
||||
const { id: widgetId, widgetName } = widgetNameData;
|
||||
|
||||
//Get Widget Name
|
||||
if (widgetName) {
|
||||
const {
|
||||
canvasLeftOffset,
|
||||
canvasTopOffset,
|
||||
widgetNameComponent,
|
||||
widgetNamePosition,
|
||||
} = getWidgetNameComponent(
|
||||
position,
|
||||
widgetName,
|
||||
widgetNameData,
|
||||
props?.parentRef?.current,
|
||||
stageRef?.current?.content,
|
||||
scrollTop.current,
|
||||
);
|
||||
|
||||
widgetNamePositions.current[type] = { ...widgetNamePosition };
|
||||
|
||||
canvasPositions.current = {
|
||||
...canvasPositions.current,
|
||||
xDiff: canvasLeftOffset,
|
||||
yDiff: canvasTopOffset,
|
||||
};
|
||||
|
||||
//Make widget name clickable
|
||||
widgetNameComponent.on("click", () => {
|
||||
selectWidget(SelectionRequestType.One, [widgetId]);
|
||||
});
|
||||
|
||||
//Add widget name to canvas
|
||||
layer.add(widgetNameComponent);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* This method is called whenever there is a change in state of canvas,
|
||||
* i.e, widget position is changed, canvas resized, selected widget changes
|
||||
* @param widgetPosition
|
||||
*/
|
||||
const updateSelectedWidgetPositions = (
|
||||
widgetPosition?: LayoutElementPosition,
|
||||
) => {
|
||||
if (!stageRef?.current) return;
|
||||
|
||||
const stage = stageRef.current;
|
||||
const layer = stage.getLayers()[0];
|
||||
//destroy all drawings on canvas
|
||||
layer.destroyChildren();
|
||||
|
||||
//Check and draw selected Widget
|
||||
if (selectedWidgetNameData) {
|
||||
const { position: selectedWidgetPosition } = selectedWidgetNameData;
|
||||
|
||||
const position = widgetPosition || selectedWidgetPosition;
|
||||
|
||||
addWidgetNameToCanvas(
|
||||
layer,
|
||||
selectedWidgetNameData,
|
||||
position,
|
||||
"selected",
|
||||
);
|
||||
}
|
||||
|
||||
//Check and draw focused Widget
|
||||
if (focusedWidgetNameData) {
|
||||
const { position } = focusedWidgetNameData;
|
||||
|
||||
addWidgetNameToCanvas(layer, focusedWidgetNameData, position, "focused");
|
||||
}
|
||||
|
||||
layer.draw();
|
||||
};
|
||||
|
||||
/**
|
||||
* Mouse Move event function, this tracks every mouse move on canvas such that
|
||||
* if the mouse position coincides with the positions of widget name, it makes the canvas intractable
|
||||
* This is throttled since it tracks every single mouse move
|
||||
*/
|
||||
const handleMouseMove = throttle((e: MouseEvent) => {
|
||||
const wrapper = wrapperRef?.current as HTMLDivElement;
|
||||
if (!wrapper) return;
|
||||
|
||||
//check if the mouse is coinciding with the widget name drawing on canvas
|
||||
const { cursor, isMouseOver } = getMouseOverDetails(e);
|
||||
|
||||
//if mouse over make the canvas intractable
|
||||
if (isMouseOver) {
|
||||
if (wrapper.style.pointerEvents === "none") {
|
||||
wrapper.style.pointerEvents = "auto";
|
||||
}
|
||||
} // if not mouse over then keep it default
|
||||
else if (wrapper.style.pointerEvents !== "none") {
|
||||
wrapper.style.pointerEvents = "none";
|
||||
wrapper.style.cursor = "default";
|
||||
}
|
||||
|
||||
//set cursor based on intractability
|
||||
if (!cursor) {
|
||||
wrapper.style.cursor = "default";
|
||||
} else if (wrapper.style.cursor !== cursor) {
|
||||
wrapper.style.cursor = cursor;
|
||||
}
|
||||
}, 20);
|
||||
|
||||
/**
|
||||
* on Drag Start event handler to enable drag of widget from the widget name component drawing on canvas
|
||||
* @param e
|
||||
*/
|
||||
const handleDragStart: DragEventHandler = (e: DragEvent) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
|
||||
//checks if the mouse is over the widget name, if so return it's details
|
||||
const { isMouseOver, widgetNameData } = getMouseOverDetails(
|
||||
e as unknown as MouseEvent,
|
||||
);
|
||||
|
||||
if (!isMouseOver || !shouldAllowDrag || widgetNameData?.dragDisabled)
|
||||
return;
|
||||
|
||||
//set dragging state
|
||||
const startPoints = {
|
||||
top: 0,
|
||||
left: 0,
|
||||
};
|
||||
showTableFilterPane();
|
||||
setDraggingState({
|
||||
isDragging: true,
|
||||
dragGroupActualParent: widgetNameData?.parentId,
|
||||
draggingGroupCenter: { widgetId: widgetNameData?.id },
|
||||
startPoints,
|
||||
draggedOn: widgetNameData?.parentId,
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* handle Scroll of the canvas, this helps in keeping track og canvas scroll
|
||||
* so that the widget name remains accurately placed even when the canvas is scrolled
|
||||
*/
|
||||
const handleScroll = () => {
|
||||
if (!props.parentRef?.current) return;
|
||||
|
||||
const currentScrollTop: number = props.parentRef?.current?.scrollTop;
|
||||
|
||||
if (!isScrolling.current) {
|
||||
resetCanvas();
|
||||
}
|
||||
|
||||
clearTimeout(isScrolling.current);
|
||||
isScrolling.current = setTimeout(() => {
|
||||
scrollTop.current = currentScrollTop;
|
||||
//while scrolling update the widget name position
|
||||
updateSelectedWidgetPositions();
|
||||
isScrolling.current = 0;
|
||||
if (
|
||||
(props.parentRef?.current?.scrollHeight || 0) >
|
||||
(props.parentRef?.current?.clientHeight || 0)
|
||||
)
|
||||
hasScroll.current = true;
|
||||
}, 100);
|
||||
};
|
||||
|
||||
//Add event listeners
|
||||
useEffect(() => {
|
||||
if (
|
||||
!props.containerRef?.current ||
|
||||
!props.parentRef?.current ||
|
||||
!wrapperRef?.current
|
||||
)
|
||||
const scrollParent: HTMLDivElement | null =
|
||||
getMainContainerAnvilCanvasDOMElement();
|
||||
|
||||
if (!props.containerRef?.current || !wrapperRef?.current || !scrollParent)
|
||||
return;
|
||||
|
||||
const container: HTMLDivElement = props.containerRef
|
||||
?.current as HTMLDivElement;
|
||||
const parent: HTMLDivElement = props.parentRef?.current as HTMLDivElement;
|
||||
|
||||
container.addEventListener("mousemove", handleMouseMove);
|
||||
parent.addEventListener("scroll", handleScroll);
|
||||
const reset = resetCanvas.bind(this, widgetNamePositions, stageRef);
|
||||
|
||||
const scrollHandler = getScrollHandler(
|
||||
isScrolling,
|
||||
hasScroll,
|
||||
reset,
|
||||
scrollTop,
|
||||
);
|
||||
|
||||
const scrollEndHandler = getScrollEndHandler(
|
||||
isScrolling,
|
||||
hasScroll,
|
||||
updateFn,
|
||||
);
|
||||
|
||||
const mouseMoveHandler = getMouseMoveHandler(
|
||||
wrapperRef,
|
||||
canvasPositions,
|
||||
widgetNamePositions,
|
||||
);
|
||||
|
||||
container.addEventListener("mousemove", mouseMoveHandler);
|
||||
scrollParent.addEventListener("scroll", scrollHandler);
|
||||
scrollParent.addEventListener("scrollend", scrollEndHandler);
|
||||
|
||||
return () => {
|
||||
container.removeEventListener("mousemove", handleMouseMove);
|
||||
parent.removeEventListener("scroll", handleScroll);
|
||||
container.removeEventListener("mousemove", mouseMoveHandler);
|
||||
scrollParent.removeEventListener("scroll", scrollHandler);
|
||||
scrollParent.removeEventListener("scrollend", scrollEndHandler);
|
||||
};
|
||||
}, [
|
||||
props.containerRef?.current,
|
||||
props.parentRef?.current,
|
||||
wrapperRef?.current,
|
||||
widgetNamePositions.current,
|
||||
canvasPositions.current,
|
||||
]);
|
||||
|
||||
/**
|
||||
* This Method verifies if the mouse position coincides with any widget name drawn on canvas
|
||||
* and returns details regarding the widget
|
||||
* @param e Mouse event
|
||||
* @returns Mainly isMouseOver indicating if the mouse is on any one of the widget name
|
||||
* if true also returns data regarding the widget
|
||||
*/
|
||||
const getMouseOverDetails = (e: MouseEvent) => {
|
||||
const x = e.clientX - canvasPositions.current.left;
|
||||
const y = e.clientY - canvasPositions.current.top;
|
||||
const widgetNamePositionsArray = Object.values(widgetNamePositions.current);
|
||||
// Reset the canvas if no widgets are focused or selected
|
||||
// Update the widget name positions if there are widgets focused or selected
|
||||
// and they've changed.
|
||||
|
||||
//for selected and focused widget names check the widget name positions with respect to mouse positions
|
||||
for (const widgetNamePosition of widgetNamePositionsArray) {
|
||||
if (widgetNamePosition) {
|
||||
const { height, left, top, widgetNameData, width } = widgetNamePosition;
|
||||
if (x > left && x < left + width && y > top && y < top + height) {
|
||||
return { isMouseOver: true, cursor: "pointer", widgetNameData };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return { isMouseOver: false };
|
||||
};
|
||||
|
||||
//Used when the position of selected or focused widget changes
|
||||
// Note: If the selector for `selectWidgetNameData` reference changes
|
||||
// Then this will run on every render. We should be careful about this.
|
||||
useEffect(() => {
|
||||
if (!selectedWidgetNameData && !focusedWidgetNameData) {
|
||||
resetCanvas();
|
||||
resetCanvas(widgetNamePositions, stageRef);
|
||||
} else {
|
||||
updateSelectedWidgetPositions();
|
||||
updateFn();
|
||||
}
|
||||
}, [selectedWidgetNameData, focusedWidgetNameData]);
|
||||
|
||||
/**
|
||||
* Resets canvas when there is nothing to be drawn on canvas
|
||||
*/
|
||||
const resetCanvas = () => {
|
||||
// Resets stored widget position names
|
||||
widgetNamePositions.current = { selected: undefined, focused: undefined };
|
||||
|
||||
// clears all drawings on canvas
|
||||
const stage = stageRef.current;
|
||||
if (!stage) return;
|
||||
const layer = stage.getLayers()[0];
|
||||
if (!layer) return;
|
||||
layer.destroyChildren();
|
||||
layer.draw();
|
||||
};
|
||||
const handleDragStart = getDragStartHandler(
|
||||
showTableFilterPane,
|
||||
setDraggingState,
|
||||
shouldAllowDrag,
|
||||
canvasPositions,
|
||||
widgetNamePositions,
|
||||
);
|
||||
|
||||
return (
|
||||
<div
|
||||
|
|
@ -373,7 +203,7 @@ const OverlayCanvasContainer = (props: {
|
|||
canvasPositions?.current.height || DEFAULT_WIDGET_NAME_CANVAS_HEIGHT
|
||||
}
|
||||
ref={stageRef}
|
||||
width={props.canvasWidth + WIDGET_NAME_CANVAS_PADDING}
|
||||
width={canvasPositions?.current.width || 0}
|
||||
>
|
||||
<Layer />
|
||||
</Stage>
|
||||
|
|
|
|||
|
|
@ -26,7 +26,6 @@ import {
|
|||
* widgetName Group on Konva, position of widgetName on canvas and canvas offsets
|
||||
*/
|
||||
export const getWidgetNameComponent = (
|
||||
position: LayoutElementPosition,
|
||||
widgetName: string,
|
||||
widgetNameData: WidgetNameData,
|
||||
parentDOM: HTMLDivElement | null,
|
||||
|
|
@ -64,8 +63,14 @@ export const getWidgetNameComponent = (
|
|||
canvasTopOffset,
|
||||
left: widgetLeft,
|
||||
top: widgetTop,
|
||||
} = getPositionsForBoundary(parentDOM, htmlCanvasDOM, position, scrollTop);
|
||||
const left: number = widgetLeft + position.width - componentWidth;
|
||||
} = getPositionsForBoundary(
|
||||
parentDOM,
|
||||
htmlCanvasDOM,
|
||||
widgetNameData.position,
|
||||
scrollTop,
|
||||
);
|
||||
const left: number =
|
||||
widgetLeft + widgetNameData.position.width - componentWidth;
|
||||
const top: number = widgetTop - WIDGET_NAME_HEIGHT;
|
||||
|
||||
//Store the widget name positions for future use
|
||||
|
|
|
|||
|
|
@ -0,0 +1,198 @@
|
|||
import type { MutableRefObject } from "react";
|
||||
import type { Stage as CanvasStageType } from "konva/lib/Stage";
|
||||
import type { Layer as KonvaLayer } from "konva/lib/Layer";
|
||||
|
||||
import type {
|
||||
CanvasPositions,
|
||||
WIDGET_NAME_TYPE,
|
||||
WidgetNameData,
|
||||
WidgetNamePositionType,
|
||||
} from "./WidgetNameTypes";
|
||||
import { SelectionRequestType } from "sagas/WidgetSelectUtils";
|
||||
import { getWidgetNameComponent } from "./utils";
|
||||
import type { KonvaEventListener } from "konva/lib/Node";
|
||||
import type { Group } from "konva/lib/Group";
|
||||
import { MAIN_CONTAINER_WIDGET_ID } from "constants/WidgetConstants";
|
||||
import { getAnvilCanvasId } from "layoutSystems/anvil/canvas/utils";
|
||||
|
||||
export function getMainContainerAnvilCanvasDOMElement() {
|
||||
const mainContainerAnvilCanvasDOMId = getAnvilCanvasId(
|
||||
MAIN_CONTAINER_WIDGET_ID,
|
||||
);
|
||||
|
||||
return document.getElementById(
|
||||
mainContainerAnvilCanvasDOMId,
|
||||
) as HTMLDivElement | null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets canvas when there is nothing to be drawn on canvas
|
||||
*/
|
||||
export function resetCanvas(
|
||||
widgetNamePositions: MutableRefObject<WidgetNamePositionType>,
|
||||
stageRef: MutableRefObject<CanvasStageType | null>,
|
||||
) {
|
||||
// Resets stored widget position names
|
||||
widgetNamePositions.current = { selected: undefined, focused: undefined };
|
||||
|
||||
// clears all drawings on canvas
|
||||
const stage = stageRef.current;
|
||||
if (!stage) return;
|
||||
const layer = stage.getLayers()[0];
|
||||
if (!layer) return;
|
||||
layer.destroyChildren();
|
||||
layer.draw();
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is used to draw the widget name components on the canvas for the
|
||||
* selected and focused widgets.
|
||||
* 1. It loops through all the selected widgets and draws the names for all of them
|
||||
* 2. It draws the name for the focused widget
|
||||
*
|
||||
* ALL of the arguments are passed down to the `addWidgetNameToCanvas` method
|
||||
* except for `stageRef` which is used to get the Konva stage and layer and the
|
||||
* selectedWidgetNameData and focusedWidgetNameData which are used to call individual
|
||||
* `addWidgetNameToCanvas` methods.
|
||||
*
|
||||
* This method finally draws the layer to commit the changes computed by `addWidgetNameToCanvas` calls
|
||||
*
|
||||
*/
|
||||
export const updateSelectedWidgetPositions = (props: {
|
||||
stageRef: MutableRefObject<CanvasStageType | null>;
|
||||
selectedWidgetNameData: WidgetNameData[] | undefined;
|
||||
focusedWidgetNameData: WidgetNameData | undefined;
|
||||
selectWidget: (
|
||||
type: SelectionRequestType,
|
||||
payload?: string[] | undefined,
|
||||
) => void;
|
||||
scrollTop: MutableRefObject<number>;
|
||||
widgetNamePositions: MutableRefObject<WidgetNamePositionType>;
|
||||
canvasPositions: MutableRefObject<CanvasPositions>;
|
||||
}) => {
|
||||
const {
|
||||
canvasPositions,
|
||||
focusedWidgetNameData,
|
||||
scrollTop,
|
||||
selectedWidgetNameData,
|
||||
selectWidget,
|
||||
stageRef,
|
||||
widgetNamePositions,
|
||||
} = props;
|
||||
if (!stageRef?.current) return;
|
||||
|
||||
const stage = stageRef.current;
|
||||
const layer = stage.getLayers()[0];
|
||||
// Clean up the layer so that we can update all the widget names
|
||||
layer.destroyChildren();
|
||||
|
||||
// For each selected widget, draw the widget name
|
||||
if (selectedWidgetNameData && selectedWidgetNameData.length > 0) {
|
||||
for (const widgetNameData of selectedWidgetNameData) {
|
||||
addWidgetNameToCanvas(
|
||||
layer,
|
||||
widgetNameData,
|
||||
"selected",
|
||||
selectWidget,
|
||||
scrollTop,
|
||||
stageRef,
|
||||
widgetNamePositions,
|
||||
canvasPositions,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Draw the focused widget name
|
||||
if (focusedWidgetNameData) {
|
||||
addWidgetNameToCanvas(
|
||||
layer,
|
||||
focusedWidgetNameData,
|
||||
"focused",
|
||||
selectWidget,
|
||||
scrollTop,
|
||||
stageRef,
|
||||
widgetNamePositions,
|
||||
canvasPositions,
|
||||
);
|
||||
}
|
||||
|
||||
layer.draw();
|
||||
};
|
||||
|
||||
/**
|
||||
* This method adds the widget name on the canvas and adds the click event handler to the widget name component
|
||||
*
|
||||
* @param layer : The KonvaLayer on which to draw
|
||||
* @param widgetNameData : the WidgetName data for the widget
|
||||
* @param type: Whether we need to draw the selected or focused widget name
|
||||
* @param selectWidget: The selectWidget method to call when the widget name is clicked
|
||||
* @param scrollTop: The amount of pixels scrolled by the canvas
|
||||
* @param stageRef: The Konva stage reference
|
||||
* @param widgetNamePositions: The widget name positions (selected and focused)
|
||||
* @param canvasPositions: The canvas positions
|
||||
* @returns void
|
||||
*/
|
||||
export const addWidgetNameToCanvas = (
|
||||
layer: KonvaLayer,
|
||||
widgetNameData: WidgetNameData,
|
||||
type: WIDGET_NAME_TYPE,
|
||||
selectWidget: (
|
||||
type: SelectionRequestType,
|
||||
payload?: string[] | undefined,
|
||||
) => void,
|
||||
scrollTop: MutableRefObject<number>,
|
||||
stageRef: MutableRefObject<CanvasStageType | null>,
|
||||
widgetNamePositions: MutableRefObject<WidgetNamePositionType>,
|
||||
canvasPositions: MutableRefObject<CanvasPositions>,
|
||||
) => {
|
||||
// If we don't have the positions, return
|
||||
if (!widgetNameData.position) return;
|
||||
|
||||
const { id: widgetId, widgetName } = widgetNameData;
|
||||
|
||||
// Get the scroll parent to calculate the offsets
|
||||
const scrollParent = getMainContainerAnvilCanvasDOMElement();
|
||||
|
||||
// If we have a widget name
|
||||
// Use Konva APIs to draw the text (see `getWidgetNameComponent`)
|
||||
if (widgetName) {
|
||||
const {
|
||||
canvasLeftOffset,
|
||||
canvasTopOffset,
|
||||
widgetNameComponent,
|
||||
widgetNamePosition,
|
||||
} = getWidgetNameComponent(
|
||||
widgetName,
|
||||
widgetNameData,
|
||||
scrollParent,
|
||||
stageRef?.current?.content,
|
||||
scrollTop.current,
|
||||
);
|
||||
|
||||
// Store the drawn widget name position
|
||||
widgetNamePositions.current[type] = { ...widgetNamePosition };
|
||||
|
||||
// Update the Canvas positions' x and y diffs
|
||||
canvasPositions.current = {
|
||||
...canvasPositions.current,
|
||||
xDiff: canvasLeftOffset,
|
||||
yDiff: canvasTopOffset,
|
||||
};
|
||||
|
||||
// Create Konva event handler
|
||||
// Note: The stopPropagation() doesn't seem to be working, so another workaround has been added to the WidgetsEditor component
|
||||
const eventHandler: KonvaEventListener<Group, MouseEvent> = (
|
||||
konvaEvent,
|
||||
) => {
|
||||
selectWidget(SelectionRequestType.One, [widgetId]);
|
||||
konvaEvent.cancelBubble = true;
|
||||
konvaEvent.evt.stopPropagation();
|
||||
};
|
||||
|
||||
//Make widget name clickable
|
||||
widgetNameComponent.on("click", eventHandler);
|
||||
|
||||
//Add widget name to canvas
|
||||
layer.add(widgetNameComponent);
|
||||
}
|
||||
};
|
||||
|
|
@ -77,21 +77,21 @@ export const getSelectedWidgetNameData = createSelector(
|
|||
widgets,
|
||||
dataTree,
|
||||
shouldShowWidgetName,
|
||||
): WidgetNameData | undefined => {
|
||||
): WidgetNameData[] | undefined => {
|
||||
if (
|
||||
!selectedWidgets ||
|
||||
selectedWidgets.length !== 1 ||
|
||||
selectedWidgets.length === 0 ||
|
||||
!shouldShowWidgetName
|
||||
)
|
||||
return;
|
||||
|
||||
const selectedWidgetId = selectedWidgets[0];
|
||||
|
||||
const selectedWidget = widgets[selectedWidgetId];
|
||||
|
||||
if (!selectedWidget) return;
|
||||
|
||||
return getWidgetNameState(selectedWidget, dataTree, positions);
|
||||
const result: WidgetNameData[] = [];
|
||||
for (const selectedWidgetId of selectedWidgets) {
|
||||
const selectedWidget = widgets[selectedWidgetId];
|
||||
if (!selectedWidget) continue;
|
||||
result.push(getWidgetNameState(selectedWidget, dataTree, positions));
|
||||
}
|
||||
if (result.length > 0) return result;
|
||||
else return;
|
||||
},
|
||||
);
|
||||
|
||||
|
|
|
|||
|
|
@ -3,27 +3,31 @@ import { LayoutSystemTypes } from "layoutSystems/types";
|
|||
import { getLayoutSystemType } from "selectors/layoutSystemSelectors";
|
||||
|
||||
export enum LayoutSystemFeatures {
|
||||
ENABLE_MAIN_CONTAINER_RESIZER = "ENABLE_MAIN_CONTAINER_RESIZER", //enable main canvas resizer
|
||||
ENABLE_FORKING_FROM_TEMPLATES = "ENABLE_FORKING_FROM_TEMPLATES", //enable forking pages from template directly inside apps
|
||||
ENABLE_CANVAS_LAYOUT_CONTROL = "ENABLE_CANVAS_LAYOUT_CONTROL", //enables layout control option in property pane
|
||||
ENABLE_MAIN_CONTAINER_RESIZER = "ENABLE_MAIN_CONTAINER_RESIZER",
|
||||
ENABLE_FORKING_FROM_TEMPLATES = "ENABLE_FORKING_FROM_TEMPLATES",
|
||||
ENABLE_CANVAS_LAYOUT_CONTROL = "ENABLE_CANVAS_LAYOUT_CONTROL",
|
||||
ENABLE_CANVAS_OVERLAY_FOR_EDITOR_UI = "ENABLE_CANVAS_OVERLAY_FOR_EDITOR_UI",
|
||||
}
|
||||
|
||||
const FIXED_LAYOUT_FEATURES: Record<LayoutSystemFeatures, boolean> = {
|
||||
[LayoutSystemFeatures.ENABLE_FORKING_FROM_TEMPLATES]: true,
|
||||
[LayoutSystemFeatures.ENABLE_CANVAS_LAYOUT_CONTROL]: true,
|
||||
[LayoutSystemFeatures.ENABLE_MAIN_CONTAINER_RESIZER]: false,
|
||||
[LayoutSystemFeatures.ENABLE_CANVAS_OVERLAY_FOR_EDITOR_UI]: false,
|
||||
};
|
||||
|
||||
const AUTO_LAYOUT_FEATURES: Record<LayoutSystemFeatures, boolean> = {
|
||||
[LayoutSystemFeatures.ENABLE_FORKING_FROM_TEMPLATES]: false,
|
||||
[LayoutSystemFeatures.ENABLE_CANVAS_LAYOUT_CONTROL]: false,
|
||||
[LayoutSystemFeatures.ENABLE_MAIN_CONTAINER_RESIZER]: true,
|
||||
[LayoutSystemFeatures.ENABLE_CANVAS_OVERLAY_FOR_EDITOR_UI]: false,
|
||||
};
|
||||
|
||||
const ANVIL_FEATURES: Record<LayoutSystemFeatures, boolean> = {
|
||||
[LayoutSystemFeatures.ENABLE_FORKING_FROM_TEMPLATES]: false,
|
||||
[LayoutSystemFeatures.ENABLE_CANVAS_LAYOUT_CONTROL]: false,
|
||||
[LayoutSystemFeatures.ENABLE_MAIN_CONTAINER_RESIZER]: true,
|
||||
[LayoutSystemFeatures.ENABLE_CANVAS_OVERLAY_FOR_EDITOR_UI]: true,
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -39,6 +39,7 @@ import {
|
|||
} from "../../../layoutSystems/common/useLayoutSystemFeatures";
|
||||
import { CANVAS_VIEWPORT } from "constants/componentClassNameConstants";
|
||||
import { MainContainerResizer } from "layoutSystems/common/mainContainerResizer/MainContainerResizer";
|
||||
import OverlayCanvasContainer from "layoutSystems/common/WidgetNamesCanvas";
|
||||
|
||||
interface MainCanvasWrapperProps {
|
||||
isPreviewMode: boolean;
|
||||
|
|
@ -46,6 +47,7 @@ interface MainCanvasWrapperProps {
|
|||
navigationHeight?: number;
|
||||
isAppSettingsPaneWithNavigationTabOpen?: boolean;
|
||||
currentPageId: string;
|
||||
parentRef: React.RefObject<HTMLDivElement | null>;
|
||||
}
|
||||
|
||||
const Wrapper = styled.section<{
|
||||
|
|
@ -141,9 +143,11 @@ function MainContainerWrapper(props: MainCanvasWrapperProps) {
|
|||
const isWDSV2Enabled = useFeatureFlag("ab_wds_enabled");
|
||||
|
||||
const checkLayoutSystemFeatures = useLayoutSystemFeatures();
|
||||
const [enableMainContainerResizer] = checkLayoutSystemFeatures([
|
||||
LayoutSystemFeatures.ENABLE_MAIN_CONTAINER_RESIZER,
|
||||
]);
|
||||
const [enableMainContainerResizer, enableOverlayCanvas] =
|
||||
checkLayoutSystemFeatures([
|
||||
LayoutSystemFeatures.ENABLE_MAIN_CONTAINER_RESIZER,
|
||||
LayoutSystemFeatures.ENABLE_CANVAS_OVERLAY_FOR_EDITOR_UI,
|
||||
]);
|
||||
|
||||
useEffect(() => {
|
||||
return () => {
|
||||
|
|
@ -250,6 +254,12 @@ function MainContainerWrapper(props: MainCanvasWrapperProps) {
|
|||
</div>
|
||||
)}
|
||||
{node}
|
||||
{enableOverlayCanvas && (
|
||||
<OverlayCanvasContainer
|
||||
canvasWidth={canvasWidth}
|
||||
containerRef={props.parentRef}
|
||||
/>
|
||||
)}
|
||||
</Wrapper>
|
||||
<MainContainerResizer
|
||||
currentPageId={currentPageId}
|
||||
|
|
|
|||
|
|
@ -83,6 +83,8 @@ function WidgetsEditor() {
|
|||
const shouldShowSnapShotBanner =
|
||||
!!readableSnapShotDetails && !isPreviewingNavigation;
|
||||
|
||||
const ref = useRef<HTMLDivElement>(null);
|
||||
|
||||
useEffect(() => {
|
||||
if (navigationPreviewRef?.current) {
|
||||
const { offsetHeight } = navigationPreviewRef.current;
|
||||
|
|
@ -117,22 +119,34 @@ function WidgetsEditor() {
|
|||
const allowDragToSelect = useAllowEditorDragToSelect();
|
||||
const { isAutoHeightWithLimitsChanging } = useAutoHeightUIState();
|
||||
|
||||
const handleWrapperClick = useCallback(() => {
|
||||
// Making sure that we don't deselect the widget
|
||||
// after we are done dragging the limits in auto height with limits
|
||||
if (allowDragToSelect && !isAutoHeightWithLimitsChanging) {
|
||||
focusWidget && focusWidget();
|
||||
deselectAll && deselectAll();
|
||||
dispatch(closePropertyPane());
|
||||
dispatch(closeTableFilterPane());
|
||||
dispatch(setCanvasSelectionFromEditor(false));
|
||||
}
|
||||
}, [
|
||||
allowDragToSelect,
|
||||
focusWidget,
|
||||
deselectAll,
|
||||
isAutoHeightWithLimitsChanging,
|
||||
]);
|
||||
const handleWrapperClick = useCallback(
|
||||
(e: any) => {
|
||||
// This is a hack for widget name component clicks on Canvas.
|
||||
// For some reason the stopPropagation in the konva event listener isn't working
|
||||
// Also, the nodeName is available only for the konva event, so standard type definition
|
||||
// for onClick handlers don't work. Hence leaving the event type as any.
|
||||
const isCanvasWrapperClicked = e.target?.nodeName === "CANVAS";
|
||||
// Making sure that we don't deselect the widget
|
||||
// after we are done dragging the limits in auto height with limits
|
||||
if (
|
||||
allowDragToSelect &&
|
||||
!isAutoHeightWithLimitsChanging &&
|
||||
!isCanvasWrapperClicked
|
||||
) {
|
||||
focusWidget && focusWidget();
|
||||
deselectAll && deselectAll();
|
||||
dispatch(closePropertyPane());
|
||||
dispatch(closeTableFilterPane());
|
||||
dispatch(setCanvasSelectionFromEditor(false));
|
||||
}
|
||||
},
|
||||
[
|
||||
allowDragToSelect,
|
||||
focusWidget,
|
||||
deselectAll,
|
||||
isAutoHeightWithLimitsChanging,
|
||||
],
|
||||
);
|
||||
|
||||
/**
|
||||
* drag event handler for selection drawing
|
||||
|
|
@ -210,6 +224,7 @@ function WidgetsEditor() {
|
|||
}
|
||||
isPreviewMode={isPreviewMode}
|
||||
isPublished={isPublished}
|
||||
ref={ref}
|
||||
sidebarWidth={isPreviewingNavigation ? sidebarWidth : 0}
|
||||
>
|
||||
{shouldShowSnapShotBanner && (
|
||||
|
|
@ -224,6 +239,7 @@ function WidgetsEditor() {
|
|||
}
|
||||
isPreviewMode={isPreviewMode}
|
||||
navigationHeight={navigationHeight}
|
||||
parentRef={ref}
|
||||
shouldShowSnapShotBanner={shouldShowSnapShotBanner}
|
||||
/>
|
||||
</PageViewWrapper>
|
||||
|
|
|
|||
|
|
@ -4033,6 +4033,25 @@ __metadata:
|
|||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@mapbox/node-pre-gyp@npm:^1.0.0":
|
||||
version: 1.0.11
|
||||
resolution: "@mapbox/node-pre-gyp@npm:1.0.11"
|
||||
dependencies:
|
||||
detect-libc: ^2.0.0
|
||||
https-proxy-agent: ^5.0.0
|
||||
make-dir: ^3.1.0
|
||||
node-fetch: ^2.6.7
|
||||
nopt: ^5.0.0
|
||||
npmlog: ^5.0.1
|
||||
rimraf: ^3.0.2
|
||||
semver: ^7.3.5
|
||||
tar: ^6.1.11
|
||||
bin:
|
||||
node-pre-gyp: bin/node-pre-gyp
|
||||
checksum: b848f6abc531a11961d780db813cc510ca5a5b6bf3184d72134089c6875a91c44d571ba6c1879470020803f7803609e7b2e6e429651c026fe202facd11d444b8
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@mdx-js/react@npm:^2.1.5":
|
||||
version: 2.3.0
|
||||
resolution: "@mdx-js/react@npm:2.3.0"
|
||||
|
|
@ -10461,6 +10480,7 @@ __metadata:
|
|||
axios: ^0.27.2
|
||||
babel-plugin-lodash: ^3.3.4
|
||||
babel-plugin-module-resolver: ^4.1.0
|
||||
canvas: ^2.11.2
|
||||
chalk: ^4.1.1
|
||||
classnames: ^2.3.1
|
||||
clsx: ^1.2.1
|
||||
|
|
@ -10684,6 +10704,16 @@ __metadata:
|
|||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"are-we-there-yet@npm:^2.0.0":
|
||||
version: 2.0.0
|
||||
resolution: "are-we-there-yet@npm:2.0.0"
|
||||
dependencies:
|
||||
delegates: ^1.0.0
|
||||
readable-stream: ^3.6.0
|
||||
checksum: 6c80b4fd04ecee6ba6e737e0b72a4b41bdc64b7d279edfc998678567ff583c8df27e27523bc789f2c99be603ffa9eaa612803da1d886962d2086e7ff6fa90c7c
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"are-we-there-yet@npm:^3.0.0":
|
||||
version: 3.0.1
|
||||
resolution: "are-we-there-yet@npm:3.0.1"
|
||||
|
|
@ -12358,6 +12388,18 @@ __metadata:
|
|||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"canvas@npm:^2.11.2":
|
||||
version: 2.11.2
|
||||
resolution: "canvas@npm:2.11.2"
|
||||
dependencies:
|
||||
"@mapbox/node-pre-gyp": ^1.0.0
|
||||
nan: ^2.17.0
|
||||
node-gyp: latest
|
||||
simple-get: ^3.0.3
|
||||
checksum: 61e554aef80022841dc836964534082ec21435928498032562089dfb7736215f039c7d99ee546b0cf10780232d9bf310950f8b4d489dc394e0fb6f6adfc97994
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"capital-case@npm:^1.0.4":
|
||||
version: 1.0.4
|
||||
resolution: "capital-case@npm:1.0.4"
|
||||
|
|
@ -12916,7 +12958,7 @@ __metadata:
|
|||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"color-support@npm:^1.1.3":
|
||||
"color-support@npm:^1.1.2, color-support@npm:^1.1.3":
|
||||
version: 1.1.3
|
||||
resolution: "color-support@npm:1.1.3"
|
||||
bin:
|
||||
|
|
@ -14287,6 +14329,15 @@ __metadata:
|
|||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"decompress-response@npm:^4.2.0":
|
||||
version: 4.2.1
|
||||
resolution: "decompress-response@npm:4.2.1"
|
||||
dependencies:
|
||||
mimic-response: ^2.0.0
|
||||
checksum: 4e783ca4dfe9417354d61349750fe05236f565a4415a6ca20983a311be2371debaedd9104c0b0e7b36e5f167aeaae04f84f1a0b3f8be4162f1d7d15598b8fdba
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"decompress-response@npm:^6.0.0":
|
||||
version: 6.0.0
|
||||
resolution: "decompress-response@npm:6.0.0"
|
||||
|
|
@ -14636,6 +14687,13 @@ __metadata:
|
|||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"detect-libc@npm:^2.0.0":
|
||||
version: 2.0.2
|
||||
resolution: "detect-libc@npm:2.0.2"
|
||||
checksum: 2b2cd3649b83d576f4be7cc37eb3b1815c79969c8b1a03a40a4d55d83bc74d010753485753448eacb98784abf22f7dbd3911fd3b60e29fda28fed2d1a997944d
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"detect-newline@npm:^3.0.0":
|
||||
version: 3.1.0
|
||||
resolution: "detect-newline@npm:3.1.0"
|
||||
|
|
@ -17410,6 +17468,23 @@ __metadata:
|
|||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"gauge@npm:^3.0.0":
|
||||
version: 3.0.2
|
||||
resolution: "gauge@npm:3.0.2"
|
||||
dependencies:
|
||||
aproba: ^1.0.3 || ^2.0.0
|
||||
color-support: ^1.1.2
|
||||
console-control-strings: ^1.0.0
|
||||
has-unicode: ^2.0.1
|
||||
object-assign: ^4.1.1
|
||||
signal-exit: ^3.0.0
|
||||
string-width: ^4.2.3
|
||||
strip-ansi: ^6.0.1
|
||||
wide-align: ^1.1.2
|
||||
checksum: 81296c00c7410cdd48f997800155fbead4f32e4f82109be0719c63edc8560e6579946cc8abd04205297640691ec26d21b578837fd13a4e96288ab4b40b1dc3e9
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"gauge@npm:^4.0.3":
|
||||
version: 4.0.4
|
||||
resolution: "gauge@npm:4.0.4"
|
||||
|
|
@ -22104,6 +22179,13 @@ __metadata:
|
|||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"mimic-response@npm:^2.0.0":
|
||||
version: 2.1.0
|
||||
resolution: "mimic-response@npm:2.1.0"
|
||||
checksum: 014fad6ab936657e5f2f48bd87af62a8e928ebe84472aaf9e14fec4fcb31257a5edff77324d8ac13ddc6685ba5135cf16e381efac324e5f174fb4ddbf902bf07
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"mimic-response@npm:^3.1.0":
|
||||
version: 3.1.0
|
||||
resolution: "mimic-response@npm:3.1.0"
|
||||
|
|
@ -22516,6 +22598,15 @@ __metadata:
|
|||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"nan@npm:^2.17.0":
|
||||
version: 2.18.0
|
||||
resolution: "nan@npm:2.18.0"
|
||||
dependencies:
|
||||
node-gyp: latest
|
||||
checksum: 4fe42f58456504eab3105c04a5cffb72066b5f22bd45decf33523cb17e7d6abc33cca2a19829407b9000539c5cb25f410312d4dc5b30220167a3594896ea6a0a
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"nanoid@npm:^2.0.4":
|
||||
version: 2.1.11
|
||||
resolution: "nanoid@npm:2.1.11"
|
||||
|
|
@ -22801,6 +22892,18 @@ __metadata:
|
|||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"npmlog@npm:^5.0.1":
|
||||
version: 5.0.1
|
||||
resolution: "npmlog@npm:5.0.1"
|
||||
dependencies:
|
||||
are-we-there-yet: ^2.0.0
|
||||
console-control-strings: ^1.1.0
|
||||
gauge: ^3.0.0
|
||||
set-blocking: ^2.0.0
|
||||
checksum: 516b2663028761f062d13e8beb3f00069c5664925871a9b57989642ebe09f23ab02145bf3ab88da7866c4e112cafff72401f61a672c7c8a20edc585a7016ef5f
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"npmlog@npm:^6.0.0":
|
||||
version: 6.0.2
|
||||
resolution: "npmlog@npm:6.0.2"
|
||||
|
|
@ -28463,6 +28566,17 @@ __metadata:
|
|||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"simple-get@npm:^3.0.3":
|
||||
version: 3.1.1
|
||||
resolution: "simple-get@npm:3.1.1"
|
||||
dependencies:
|
||||
decompress-response: ^4.2.0
|
||||
once: ^1.3.1
|
||||
simple-concat: ^1.0.0
|
||||
checksum: 80195e70bf171486e75c31e28e5485468195cc42f85940f8b45c4a68472160144d223eb4d07bc82ef80cb974b7c401db021a540deb2d34ac4b3b8883da2d6401
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"simple-update-notifier@npm:^2.0.0":
|
||||
version: 2.0.0
|
||||
resolution: "simple-update-notifier@npm:2.0.0"
|
||||
|
|
@ -31837,7 +31951,7 @@ __metadata:
|
|||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"wide-align@npm:^1.1.0, wide-align@npm:^1.1.5":
|
||||
"wide-align@npm:^1.1.0, wide-align@npm:^1.1.2, wide-align@npm:^1.1.5":
|
||||
version: 1.1.5
|
||||
resolution: "wide-align@npm:1.1.5"
|
||||
dependencies:
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user