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"],
|
moduleFileExtensions: ["ts", "tsx", "js", "jsx", "json", "node", "css"],
|
||||||
moduleDirectories: ["node_modules", "src", "test"],
|
moduleDirectories: ["node_modules", "src", "test"],
|
||||||
transformIgnorePatterns: [
|
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: {
|
moduleNameMapper: {
|
||||||
"\\.(css|less)$": "<rootDir>/test/__mocks__/styleMock.js",
|
"\\.(css|less)$": "<rootDir>/test/__mocks__/styleMock.js",
|
||||||
|
|
|
||||||
|
|
@ -288,6 +288,7 @@
|
||||||
"@typescript-eslint/parser": "^6.7.4",
|
"@typescript-eslint/parser": "^6.7.4",
|
||||||
"babel-plugin-lodash": "^3.3.4",
|
"babel-plugin-lodash": "^3.3.4",
|
||||||
"babel-plugin-module-resolver": "^4.1.0",
|
"babel-plugin-module-resolver": "^4.1.0",
|
||||||
|
"canvas": "^2.11.2",
|
||||||
"chalk": "^4.1.1",
|
"chalk": "^4.1.1",
|
||||||
"compression-webpack-plugin": "^10.0.0",
|
"compression-webpack-plugin": "^10.0.0",
|
||||||
"cra-bundle-analyzer": "^0.1.0",
|
"cra-bundle-analyzer": "^0.1.0",
|
||||||
|
|
|
||||||
|
|
@ -31,3 +31,23 @@ export interface CanvasPositions {
|
||||||
yDiff: number;
|
yDiff: number;
|
||||||
height: 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 React, { useEffect, useRef } from "react";
|
||||||
import { useSelector } from "react-redux";
|
import { useSelector } from "react-redux";
|
||||||
import { throttle } from "lodash";
|
|
||||||
import { Layer, Stage } from "react-konva/lib/ReactKonvaCore";
|
import { Layer, Stage } from "react-konva/lib/ReactKonvaCore";
|
||||||
import { useWidgetSelection } from "utils/hooks/useWidgetSelection";
|
import { useWidgetSelection } from "utils/hooks/useWidgetSelection";
|
||||||
import { SelectionRequestType } from "sagas/WidgetSelectUtils";
|
|
||||||
|
|
||||||
import {
|
import {
|
||||||
useShowTableFilterPane,
|
useShowTableFilterPane,
|
||||||
|
|
@ -13,12 +10,10 @@ import {
|
||||||
import type {
|
import type {
|
||||||
CanvasPositions,
|
CanvasPositions,
|
||||||
WidgetNameData,
|
WidgetNameData,
|
||||||
WidgetNamePositionData,
|
WidgetNamePositionType,
|
||||||
WIDGET_NAME_TYPE,
|
|
||||||
} from "./WidgetNameTypes";
|
} from "./WidgetNameTypes";
|
||||||
import {
|
import {
|
||||||
DEFAULT_WIDGET_NAME_CANVAS_HEIGHT,
|
DEFAULT_WIDGET_NAME_CANVAS_HEIGHT,
|
||||||
WIDGET_NAME_CANVAS_PADDING,
|
|
||||||
widgetNameWrapperStyle,
|
widgetNameWrapperStyle,
|
||||||
WIDGET_NAME_CANVAS,
|
WIDGET_NAME_CANVAS,
|
||||||
} from "./WidgetNameConstants";
|
} from "./WidgetNameConstants";
|
||||||
|
|
@ -26,11 +21,20 @@ import {
|
||||||
getFocusedWidgetNameData,
|
getFocusedWidgetNameData,
|
||||||
getSelectedWidgetNameData,
|
getSelectedWidgetNameData,
|
||||||
} from "../selectors";
|
} from "../selectors";
|
||||||
import type { LayoutElementPosition } from "layoutSystems/common/types";
|
|
||||||
import { getShouldAllowDrag } from "selectors/widgetDragSelectors";
|
import { getShouldAllowDrag } from "selectors/widgetDragSelectors";
|
||||||
import type { Stage as CanvasStageType } from "konva/lib/Stage";
|
import type { Stage as CanvasStageType } from "konva/lib/Stage";
|
||||||
import type { Layer as KonvaLayer } from "konva/lib/Layer";
|
import {
|
||||||
import { getWidgetNameComponent } from "./utils";
|
getMainContainerAnvilCanvasDOMElement,
|
||||||
|
resetCanvas,
|
||||||
|
updateSelectedWidgetPositions,
|
||||||
|
} from "./widgetNameRenderUtils";
|
||||||
|
import {
|
||||||
|
getDragStartHandler,
|
||||||
|
getMouseMoveHandler,
|
||||||
|
getScrollEndHandler,
|
||||||
|
getScrollHandler,
|
||||||
|
} from "./eventHandlers";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This Component contains logic to draw widget name on canvas
|
* This Component contains logic to draw widget name on canvas
|
||||||
|
|
@ -38,34 +42,31 @@ import { getWidgetNameComponent } from "./utils";
|
||||||
* @param props Object that contains
|
* @param props Object that contains
|
||||||
* @prop canvasWidth width of canvas in pixels
|
* @prop canvasWidth width of canvas in pixels
|
||||||
* @prop containerRef ref of PageViewWrapper component
|
* @prop containerRef ref of PageViewWrapper component
|
||||||
* @prop parentRef ref of the MainContainerWrapper component i.e, the parent of the canvas component
|
|
||||||
*/
|
*/
|
||||||
const OverlayCanvasContainer = (props: {
|
const OverlayCanvasContainer = (props: {
|
||||||
canvasWidth: number;
|
canvasWidth: number;
|
||||||
containerRef: React.RefObject<HTMLDivElement>;
|
containerRef: React.RefObject<HTMLDivElement | null>;
|
||||||
parentRef: React.RefObject<HTMLDivElement>;
|
|
||||||
}) => {
|
}) => {
|
||||||
//widget name data of widgets
|
//widget name data of widgets
|
||||||
const selectedWidgetNameData: WidgetNameData | undefined = useSelector(
|
const selectedWidgetNameData: WidgetNameData[] | undefined = useSelector(
|
||||||
getSelectedWidgetNameData,
|
getSelectedWidgetNameData,
|
||||||
);
|
);
|
||||||
const focusedWidgetNameData: WidgetNameData | undefined = useSelector(
|
const focusedWidgetNameData: WidgetNameData | undefined = useSelector(
|
||||||
getFocusedWidgetNameData,
|
getFocusedWidgetNameData,
|
||||||
);
|
);
|
||||||
|
// should we allow dragging of widgets
|
||||||
const shouldAllowDrag = useSelector(getShouldAllowDrag);
|
const shouldAllowDrag = useSelector(getShouldAllowDrag);
|
||||||
|
// When we begin dragging, the drag and resize hooks need a few details to take over
|
||||||
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 });
|
|
||||||
|
|
||||||
const { setDraggingState } = useWidgetDragResize();
|
const { setDraggingState } = useWidgetDragResize();
|
||||||
const showTableFilterPane = useShowTableFilterPane();
|
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
|
//Positions of canvas
|
||||||
const canvasPositions = useRef<CanvasPositions>({
|
const canvasPositions = useRef<CanvasPositions>({
|
||||||
top: 0,
|
top: 0,
|
||||||
|
|
@ -77,19 +78,28 @@ const OverlayCanvasContainer = (props: {
|
||||||
});
|
});
|
||||||
|
|
||||||
const scrollTop = useRef<number>(0);
|
const scrollTop = useRef<number>(0);
|
||||||
const isScrolling = useRef(0);
|
const isScrolling = useRef<number>(0);
|
||||||
const hasScroll = useRef<boolean>(false);
|
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(() => {
|
useEffect(() => {
|
||||||
if (!stageRef?.current?.content || !wrapperRef?.current) return;
|
if (!stageRef?.current?.content || !wrapperRef?.current) return;
|
||||||
|
|
||||||
const HTMLCanvas: HTMLDivElement = stageRef?.current?.content;
|
const HTMLCanvas: HTMLDivElement = stageRef?.current?.content;
|
||||||
const rect: DOMRect = HTMLCanvas.getBoundingClientRect();
|
const rect: DOMRect = HTMLCanvas.getBoundingClientRect();
|
||||||
|
|
||||||
const wrapper: HTMLDivElement = wrapperRef?.current as HTMLDivElement;
|
const wrapper: HTMLDivElement = wrapperRef?.current as HTMLDivElement;
|
||||||
const wrapperRect: DOMRect = wrapper.getBoundingClientRect();
|
const wrapperRect: DOMRect = wrapper.getBoundingClientRect();
|
||||||
|
|
||||||
|
|
@ -99,266 +109,86 @@ const OverlayCanvasContainer = (props: {
|
||||||
height: wrapperRect.height,
|
height: wrapperRect.height,
|
||||||
left: rect.left,
|
left: rect.left,
|
||||||
top: rect.top,
|
top: rect.top,
|
||||||
width: rect.width,
|
width: wrapperRect.width,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}, [wrapperRef?.current, props.canvasWidth]);
|
}, [wrapperRef?.current, props.canvasWidth]);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Method used to add widget name to the Konva canvas' layer
|
* Adds 3 event listeners.
|
||||||
* @param layer Konva layer onto which the widget name is to be added
|
* 1. Mouse Move: On the container, to check if the mouse is over a widget, so that we can focus it
|
||||||
* @param widgetNameData widget name data contains more information regarding the widget that is used in drawing the name
|
* 2. Scroll: On the MainContainer, to check if the user is scrolling. This is so that we can hide the widget names
|
||||||
* @param position position of widget in pixels
|
* Also, this tells us that we need to compute and store scroll offset values to correctly position the widget name components.
|
||||||
* @param type if it's either selected or focused widget name
|
* 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(() => {
|
useEffect(() => {
|
||||||
if (
|
const scrollParent: HTMLDivElement | null =
|
||||||
!props.containerRef?.current ||
|
getMainContainerAnvilCanvasDOMElement();
|
||||||
!props.parentRef?.current ||
|
|
||||||
!wrapperRef?.current
|
if (!props.containerRef?.current || !wrapperRef?.current || !scrollParent)
|
||||||
)
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
const container: HTMLDivElement = props.containerRef
|
const container: HTMLDivElement = props.containerRef
|
||||||
?.current as HTMLDivElement;
|
?.current as HTMLDivElement;
|
||||||
const parent: HTMLDivElement = props.parentRef?.current as HTMLDivElement;
|
|
||||||
|
|
||||||
container.addEventListener("mousemove", handleMouseMove);
|
const reset = resetCanvas.bind(this, widgetNamePositions, stageRef);
|
||||||
parent.addEventListener("scroll", handleScroll);
|
|
||||||
|
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 () => {
|
return () => {
|
||||||
container.removeEventListener("mousemove", handleMouseMove);
|
container.removeEventListener("mousemove", mouseMoveHandler);
|
||||||
parent.removeEventListener("scroll", handleScroll);
|
scrollParent.removeEventListener("scroll", scrollHandler);
|
||||||
|
scrollParent.removeEventListener("scrollend", scrollEndHandler);
|
||||||
};
|
};
|
||||||
}, [
|
}, [
|
||||||
props.containerRef?.current,
|
props.containerRef?.current,
|
||||||
props.parentRef?.current,
|
|
||||||
wrapperRef?.current,
|
wrapperRef?.current,
|
||||||
widgetNamePositions.current,
|
widgetNamePositions.current,
|
||||||
canvasPositions.current,
|
canvasPositions.current,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
/**
|
// Reset the canvas if no widgets are focused or selected
|
||||||
* This Method verifies if the mouse position coincides with any widget name drawn on canvas
|
// Update the widget name positions if there are widgets focused or selected
|
||||||
* and returns details regarding the widget
|
// and they've changed.
|
||||||
* @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);
|
|
||||||
|
|
||||||
//for selected and focused widget names check the widget name positions with respect to mouse positions
|
// Note: If the selector for `selectWidgetNameData` reference changes
|
||||||
for (const widgetNamePosition of widgetNamePositionsArray) {
|
// Then this will run on every render. We should be careful about this.
|
||||||
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
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!selectedWidgetNameData && !focusedWidgetNameData) {
|
if (!selectedWidgetNameData && !focusedWidgetNameData) {
|
||||||
resetCanvas();
|
resetCanvas(widgetNamePositions, stageRef);
|
||||||
} else {
|
} else {
|
||||||
updateSelectedWidgetPositions();
|
updateFn();
|
||||||
}
|
}
|
||||||
}, [selectedWidgetNameData, focusedWidgetNameData]);
|
}, [selectedWidgetNameData, focusedWidgetNameData]);
|
||||||
|
|
||||||
/**
|
const handleDragStart = getDragStartHandler(
|
||||||
* Resets canvas when there is nothing to be drawn on canvas
|
showTableFilterPane,
|
||||||
*/
|
setDraggingState,
|
||||||
const resetCanvas = () => {
|
shouldAllowDrag,
|
||||||
// Resets stored widget position names
|
canvasPositions,
|
||||||
widgetNamePositions.current = { selected: undefined, focused: undefined };
|
widgetNamePositions,
|
||||||
|
);
|
||||||
// clears all drawings on canvas
|
|
||||||
const stage = stageRef.current;
|
|
||||||
if (!stage) return;
|
|
||||||
const layer = stage.getLayers()[0];
|
|
||||||
if (!layer) return;
|
|
||||||
layer.destroyChildren();
|
|
||||||
layer.draw();
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
|
|
@ -373,7 +203,7 @@ const OverlayCanvasContainer = (props: {
|
||||||
canvasPositions?.current.height || DEFAULT_WIDGET_NAME_CANVAS_HEIGHT
|
canvasPositions?.current.height || DEFAULT_WIDGET_NAME_CANVAS_HEIGHT
|
||||||
}
|
}
|
||||||
ref={stageRef}
|
ref={stageRef}
|
||||||
width={props.canvasWidth + WIDGET_NAME_CANVAS_PADDING}
|
width={canvasPositions?.current.width || 0}
|
||||||
>
|
>
|
||||||
<Layer />
|
<Layer />
|
||||||
</Stage>
|
</Stage>
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,6 @@ import {
|
||||||
* widgetName Group on Konva, position of widgetName on canvas and canvas offsets
|
* widgetName Group on Konva, position of widgetName on canvas and canvas offsets
|
||||||
*/
|
*/
|
||||||
export const getWidgetNameComponent = (
|
export const getWidgetNameComponent = (
|
||||||
position: LayoutElementPosition,
|
|
||||||
widgetName: string,
|
widgetName: string,
|
||||||
widgetNameData: WidgetNameData,
|
widgetNameData: WidgetNameData,
|
||||||
parentDOM: HTMLDivElement | null,
|
parentDOM: HTMLDivElement | null,
|
||||||
|
|
@ -64,8 +63,14 @@ export const getWidgetNameComponent = (
|
||||||
canvasTopOffset,
|
canvasTopOffset,
|
||||||
left: widgetLeft,
|
left: widgetLeft,
|
||||||
top: widgetTop,
|
top: widgetTop,
|
||||||
} = getPositionsForBoundary(parentDOM, htmlCanvasDOM, position, scrollTop);
|
} = getPositionsForBoundary(
|
||||||
const left: number = widgetLeft + position.width - componentWidth;
|
parentDOM,
|
||||||
|
htmlCanvasDOM,
|
||||||
|
widgetNameData.position,
|
||||||
|
scrollTop,
|
||||||
|
);
|
||||||
|
const left: number =
|
||||||
|
widgetLeft + widgetNameData.position.width - componentWidth;
|
||||||
const top: number = widgetTop - WIDGET_NAME_HEIGHT;
|
const top: number = widgetTop - WIDGET_NAME_HEIGHT;
|
||||||
|
|
||||||
//Store the widget name positions for future use
|
//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,
|
widgets,
|
||||||
dataTree,
|
dataTree,
|
||||||
shouldShowWidgetName,
|
shouldShowWidgetName,
|
||||||
): WidgetNameData | undefined => {
|
): WidgetNameData[] | undefined => {
|
||||||
if (
|
if (
|
||||||
!selectedWidgets ||
|
!selectedWidgets ||
|
||||||
selectedWidgets.length !== 1 ||
|
selectedWidgets.length === 0 ||
|
||||||
!shouldShowWidgetName
|
!shouldShowWidgetName
|
||||||
)
|
)
|
||||||
return;
|
return;
|
||||||
|
const result: WidgetNameData[] = [];
|
||||||
const selectedWidgetId = selectedWidgets[0];
|
for (const selectedWidgetId of selectedWidgets) {
|
||||||
|
|
||||||
const selectedWidget = widgets[selectedWidgetId];
|
const selectedWidget = widgets[selectedWidgetId];
|
||||||
|
if (!selectedWidget) continue;
|
||||||
if (!selectedWidget) return;
|
result.push(getWidgetNameState(selectedWidget, dataTree, positions));
|
||||||
|
}
|
||||||
return 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";
|
import { getLayoutSystemType } from "selectors/layoutSystemSelectors";
|
||||||
|
|
||||||
export enum LayoutSystemFeatures {
|
export enum LayoutSystemFeatures {
|
||||||
ENABLE_MAIN_CONTAINER_RESIZER = "ENABLE_MAIN_CONTAINER_RESIZER", //enable main canvas resizer
|
ENABLE_MAIN_CONTAINER_RESIZER = "ENABLE_MAIN_CONTAINER_RESIZER",
|
||||||
ENABLE_FORKING_FROM_TEMPLATES = "ENABLE_FORKING_FROM_TEMPLATES", //enable forking pages from template directly inside apps
|
ENABLE_FORKING_FROM_TEMPLATES = "ENABLE_FORKING_FROM_TEMPLATES",
|
||||||
ENABLE_CANVAS_LAYOUT_CONTROL = "ENABLE_CANVAS_LAYOUT_CONTROL", //enables layout control option in property pane
|
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> = {
|
const FIXED_LAYOUT_FEATURES: Record<LayoutSystemFeatures, boolean> = {
|
||||||
[LayoutSystemFeatures.ENABLE_FORKING_FROM_TEMPLATES]: true,
|
[LayoutSystemFeatures.ENABLE_FORKING_FROM_TEMPLATES]: true,
|
||||||
[LayoutSystemFeatures.ENABLE_CANVAS_LAYOUT_CONTROL]: true,
|
[LayoutSystemFeatures.ENABLE_CANVAS_LAYOUT_CONTROL]: true,
|
||||||
[LayoutSystemFeatures.ENABLE_MAIN_CONTAINER_RESIZER]: false,
|
[LayoutSystemFeatures.ENABLE_MAIN_CONTAINER_RESIZER]: false,
|
||||||
|
[LayoutSystemFeatures.ENABLE_CANVAS_OVERLAY_FOR_EDITOR_UI]: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
const AUTO_LAYOUT_FEATURES: Record<LayoutSystemFeatures, boolean> = {
|
const AUTO_LAYOUT_FEATURES: Record<LayoutSystemFeatures, boolean> = {
|
||||||
[LayoutSystemFeatures.ENABLE_FORKING_FROM_TEMPLATES]: false,
|
[LayoutSystemFeatures.ENABLE_FORKING_FROM_TEMPLATES]: false,
|
||||||
[LayoutSystemFeatures.ENABLE_CANVAS_LAYOUT_CONTROL]: false,
|
[LayoutSystemFeatures.ENABLE_CANVAS_LAYOUT_CONTROL]: false,
|
||||||
[LayoutSystemFeatures.ENABLE_MAIN_CONTAINER_RESIZER]: true,
|
[LayoutSystemFeatures.ENABLE_MAIN_CONTAINER_RESIZER]: true,
|
||||||
|
[LayoutSystemFeatures.ENABLE_CANVAS_OVERLAY_FOR_EDITOR_UI]: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
const ANVIL_FEATURES: Record<LayoutSystemFeatures, boolean> = {
|
const ANVIL_FEATURES: Record<LayoutSystemFeatures, boolean> = {
|
||||||
[LayoutSystemFeatures.ENABLE_FORKING_FROM_TEMPLATES]: false,
|
[LayoutSystemFeatures.ENABLE_FORKING_FROM_TEMPLATES]: false,
|
||||||
[LayoutSystemFeatures.ENABLE_CANVAS_LAYOUT_CONTROL]: false,
|
[LayoutSystemFeatures.ENABLE_CANVAS_LAYOUT_CONTROL]: false,
|
||||||
[LayoutSystemFeatures.ENABLE_MAIN_CONTAINER_RESIZER]: true,
|
[LayoutSystemFeatures.ENABLE_MAIN_CONTAINER_RESIZER]: true,
|
||||||
|
[LayoutSystemFeatures.ENABLE_CANVAS_OVERLAY_FOR_EDITOR_UI]: true,
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -39,6 +39,7 @@ import {
|
||||||
} from "../../../layoutSystems/common/useLayoutSystemFeatures";
|
} from "../../../layoutSystems/common/useLayoutSystemFeatures";
|
||||||
import { CANVAS_VIEWPORT } from "constants/componentClassNameConstants";
|
import { CANVAS_VIEWPORT } from "constants/componentClassNameConstants";
|
||||||
import { MainContainerResizer } from "layoutSystems/common/mainContainerResizer/MainContainerResizer";
|
import { MainContainerResizer } from "layoutSystems/common/mainContainerResizer/MainContainerResizer";
|
||||||
|
import OverlayCanvasContainer from "layoutSystems/common/WidgetNamesCanvas";
|
||||||
|
|
||||||
interface MainCanvasWrapperProps {
|
interface MainCanvasWrapperProps {
|
||||||
isPreviewMode: boolean;
|
isPreviewMode: boolean;
|
||||||
|
|
@ -46,6 +47,7 @@ interface MainCanvasWrapperProps {
|
||||||
navigationHeight?: number;
|
navigationHeight?: number;
|
||||||
isAppSettingsPaneWithNavigationTabOpen?: boolean;
|
isAppSettingsPaneWithNavigationTabOpen?: boolean;
|
||||||
currentPageId: string;
|
currentPageId: string;
|
||||||
|
parentRef: React.RefObject<HTMLDivElement | null>;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Wrapper = styled.section<{
|
const Wrapper = styled.section<{
|
||||||
|
|
@ -141,8 +143,10 @@ function MainContainerWrapper(props: MainCanvasWrapperProps) {
|
||||||
const isWDSV2Enabled = useFeatureFlag("ab_wds_enabled");
|
const isWDSV2Enabled = useFeatureFlag("ab_wds_enabled");
|
||||||
|
|
||||||
const checkLayoutSystemFeatures = useLayoutSystemFeatures();
|
const checkLayoutSystemFeatures = useLayoutSystemFeatures();
|
||||||
const [enableMainContainerResizer] = checkLayoutSystemFeatures([
|
const [enableMainContainerResizer, enableOverlayCanvas] =
|
||||||
|
checkLayoutSystemFeatures([
|
||||||
LayoutSystemFeatures.ENABLE_MAIN_CONTAINER_RESIZER,
|
LayoutSystemFeatures.ENABLE_MAIN_CONTAINER_RESIZER,
|
||||||
|
LayoutSystemFeatures.ENABLE_CANVAS_OVERLAY_FOR_EDITOR_UI,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|
@ -250,6 +254,12 @@ function MainContainerWrapper(props: MainCanvasWrapperProps) {
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{node}
|
{node}
|
||||||
|
{enableOverlayCanvas && (
|
||||||
|
<OverlayCanvasContainer
|
||||||
|
canvasWidth={canvasWidth}
|
||||||
|
containerRef={props.parentRef}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
</Wrapper>
|
</Wrapper>
|
||||||
<MainContainerResizer
|
<MainContainerResizer
|
||||||
currentPageId={currentPageId}
|
currentPageId={currentPageId}
|
||||||
|
|
|
||||||
|
|
@ -83,6 +83,8 @@ function WidgetsEditor() {
|
||||||
const shouldShowSnapShotBanner =
|
const shouldShowSnapShotBanner =
|
||||||
!!readableSnapShotDetails && !isPreviewingNavigation;
|
!!readableSnapShotDetails && !isPreviewingNavigation;
|
||||||
|
|
||||||
|
const ref = useRef<HTMLDivElement>(null);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (navigationPreviewRef?.current) {
|
if (navigationPreviewRef?.current) {
|
||||||
const { offsetHeight } = navigationPreviewRef.current;
|
const { offsetHeight } = navigationPreviewRef.current;
|
||||||
|
|
@ -117,22 +119,34 @@ function WidgetsEditor() {
|
||||||
const allowDragToSelect = useAllowEditorDragToSelect();
|
const allowDragToSelect = useAllowEditorDragToSelect();
|
||||||
const { isAutoHeightWithLimitsChanging } = useAutoHeightUIState();
|
const { isAutoHeightWithLimitsChanging } = useAutoHeightUIState();
|
||||||
|
|
||||||
const handleWrapperClick = useCallback(() => {
|
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
|
// Making sure that we don't deselect the widget
|
||||||
// after we are done dragging the limits in auto height with limits
|
// after we are done dragging the limits in auto height with limits
|
||||||
if (allowDragToSelect && !isAutoHeightWithLimitsChanging) {
|
if (
|
||||||
|
allowDragToSelect &&
|
||||||
|
!isAutoHeightWithLimitsChanging &&
|
||||||
|
!isCanvasWrapperClicked
|
||||||
|
) {
|
||||||
focusWidget && focusWidget();
|
focusWidget && focusWidget();
|
||||||
deselectAll && deselectAll();
|
deselectAll && deselectAll();
|
||||||
dispatch(closePropertyPane());
|
dispatch(closePropertyPane());
|
||||||
dispatch(closeTableFilterPane());
|
dispatch(closeTableFilterPane());
|
||||||
dispatch(setCanvasSelectionFromEditor(false));
|
dispatch(setCanvasSelectionFromEditor(false));
|
||||||
}
|
}
|
||||||
}, [
|
},
|
||||||
|
[
|
||||||
allowDragToSelect,
|
allowDragToSelect,
|
||||||
focusWidget,
|
focusWidget,
|
||||||
deselectAll,
|
deselectAll,
|
||||||
isAutoHeightWithLimitsChanging,
|
isAutoHeightWithLimitsChanging,
|
||||||
]);
|
],
|
||||||
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* drag event handler for selection drawing
|
* drag event handler for selection drawing
|
||||||
|
|
@ -210,6 +224,7 @@ function WidgetsEditor() {
|
||||||
}
|
}
|
||||||
isPreviewMode={isPreviewMode}
|
isPreviewMode={isPreviewMode}
|
||||||
isPublished={isPublished}
|
isPublished={isPublished}
|
||||||
|
ref={ref}
|
||||||
sidebarWidth={isPreviewingNavigation ? sidebarWidth : 0}
|
sidebarWidth={isPreviewingNavigation ? sidebarWidth : 0}
|
||||||
>
|
>
|
||||||
{shouldShowSnapShotBanner && (
|
{shouldShowSnapShotBanner && (
|
||||||
|
|
@ -224,6 +239,7 @@ function WidgetsEditor() {
|
||||||
}
|
}
|
||||||
isPreviewMode={isPreviewMode}
|
isPreviewMode={isPreviewMode}
|
||||||
navigationHeight={navigationHeight}
|
navigationHeight={navigationHeight}
|
||||||
|
parentRef={ref}
|
||||||
shouldShowSnapShotBanner={shouldShowSnapShotBanner}
|
shouldShowSnapShotBanner={shouldShowSnapShotBanner}
|
||||||
/>
|
/>
|
||||||
</PageViewWrapper>
|
</PageViewWrapper>
|
||||||
|
|
|
||||||
|
|
@ -4033,6 +4033,25 @@ __metadata:
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
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":
|
"@mdx-js/react@npm:^2.1.5":
|
||||||
version: 2.3.0
|
version: 2.3.0
|
||||||
resolution: "@mdx-js/react@npm:2.3.0"
|
resolution: "@mdx-js/react@npm:2.3.0"
|
||||||
|
|
@ -10461,6 +10480,7 @@ __metadata:
|
||||||
axios: ^0.27.2
|
axios: ^0.27.2
|
||||||
babel-plugin-lodash: ^3.3.4
|
babel-plugin-lodash: ^3.3.4
|
||||||
babel-plugin-module-resolver: ^4.1.0
|
babel-plugin-module-resolver: ^4.1.0
|
||||||
|
canvas: ^2.11.2
|
||||||
chalk: ^4.1.1
|
chalk: ^4.1.1
|
||||||
classnames: ^2.3.1
|
classnames: ^2.3.1
|
||||||
clsx: ^1.2.1
|
clsx: ^1.2.1
|
||||||
|
|
@ -10684,6 +10704,16 @@ __metadata:
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
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":
|
"are-we-there-yet@npm:^3.0.0":
|
||||||
version: 3.0.1
|
version: 3.0.1
|
||||||
resolution: "are-we-there-yet@npm:3.0.1"
|
resolution: "are-we-there-yet@npm:3.0.1"
|
||||||
|
|
@ -12358,6 +12388,18 @@ __metadata:
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
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":
|
"capital-case@npm:^1.0.4":
|
||||||
version: 1.0.4
|
version: 1.0.4
|
||||||
resolution: "capital-case@npm:1.0.4"
|
resolution: "capital-case@npm:1.0.4"
|
||||||
|
|
@ -12916,7 +12958,7 @@ __metadata:
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"color-support@npm:^1.1.3":
|
"color-support@npm:^1.1.2, color-support@npm:^1.1.3":
|
||||||
version: 1.1.3
|
version: 1.1.3
|
||||||
resolution: "color-support@npm:1.1.3"
|
resolution: "color-support@npm:1.1.3"
|
||||||
bin:
|
bin:
|
||||||
|
|
@ -14287,6 +14329,15 @@ __metadata:
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
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":
|
"decompress-response@npm:^6.0.0":
|
||||||
version: 6.0.0
|
version: 6.0.0
|
||||||
resolution: "decompress-response@npm:6.0.0"
|
resolution: "decompress-response@npm:6.0.0"
|
||||||
|
|
@ -14636,6 +14687,13 @@ __metadata:
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
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":
|
"detect-newline@npm:^3.0.0":
|
||||||
version: 3.1.0
|
version: 3.1.0
|
||||||
resolution: "detect-newline@npm:3.1.0"
|
resolution: "detect-newline@npm:3.1.0"
|
||||||
|
|
@ -17410,6 +17468,23 @@ __metadata:
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
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":
|
"gauge@npm:^4.0.3":
|
||||||
version: 4.0.4
|
version: 4.0.4
|
||||||
resolution: "gauge@npm:4.0.4"
|
resolution: "gauge@npm:4.0.4"
|
||||||
|
|
@ -22104,6 +22179,13 @@ __metadata:
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
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":
|
"mimic-response@npm:^3.1.0":
|
||||||
version: 3.1.0
|
version: 3.1.0
|
||||||
resolution: "mimic-response@npm:3.1.0"
|
resolution: "mimic-response@npm:3.1.0"
|
||||||
|
|
@ -22516,6 +22598,15 @@ __metadata:
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
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":
|
"nanoid@npm:^2.0.4":
|
||||||
version: 2.1.11
|
version: 2.1.11
|
||||||
resolution: "nanoid@npm:2.1.11"
|
resolution: "nanoid@npm:2.1.11"
|
||||||
|
|
@ -22801,6 +22892,18 @@ __metadata:
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
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":
|
"npmlog@npm:^6.0.0":
|
||||||
version: 6.0.2
|
version: 6.0.2
|
||||||
resolution: "npmlog@npm:6.0.2"
|
resolution: "npmlog@npm:6.0.2"
|
||||||
|
|
@ -28463,6 +28566,17 @@ __metadata:
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
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":
|
"simple-update-notifier@npm:^2.0.0":
|
||||||
version: 2.0.0
|
version: 2.0.0
|
||||||
resolution: "simple-update-notifier@npm:2.0.0"
|
resolution: "simple-update-notifier@npm:2.0.0"
|
||||||
|
|
@ -31837,7 +31951,7 @@ __metadata:
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
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
|
version: 1.1.5
|
||||||
resolution: "wide-align@npm:1.1.5"
|
resolution: "wide-align@npm:1.1.5"
|
||||||
dependencies:
|
dependencies:
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user