[](https://workerb.linearb.io/v2/badge/collaboration-page?magicLinkId=DEipBn-) ## Description In this PR, we are adding an enhancement to DnD of modal widgets. DnD was implemented only for layouts so in the case of modal, the header and footer are not layouts and DnD is not triggered when a widget is being dragged on top of these components of a modal. However for the user to be able to efficiently use the DnD of modal, mouse events of the modal are also needed to be processed. To enable this we have a new hook that wraps all detached widgets in editor mode only, `useAnvilDetachedWidgetsDnD` It makes sure mouse move events on the widget are dispatched to the dnd listeners via custom event `DETACHED_WIDGET_MOUSE_MOVE_EVENT` we aslo had to special handle mouse leave and enter utilities to activate a canvas for DnD, - for all widgets except modals these are handled on the `useAnvilDnDEventCallbacks` - for modal widgets these events are handled on the `useAnvilDetachedWidgetsDnD` Fixes #33318 _or_ Fixes `Issue URL` > [!WARNING] > _If no issue exists, please create an issue first, and check with the maintainers if the issue is valid._ ## Automation /ok-to-test tags="@tag.Anvil" ### 🔍 Cypress test results <!-- This is an auto-generated comment: Cypress test results --> > [!TIP] > 🟢 🟢 🟢 All cypress tests have passed! 🎉 🎉 🎉 > Workflow run: <https://github.com/appsmithorg/appsmith/actions/runs/9171877023> > Commit: 53925782d15c9998d993f39a0239bee64a7805fc > Cypress dashboard url: <a href="https://internal.appsmith.com/app/cypress-dashboard/rundetails-65890b3c81d7400d08fa9ee5?branch=master&workflowId=9171877023&attempt=1" target="_blank">Click here!</a> <!-- end of auto-generated comment: Cypress test results --> ## Communication Should the DevRel and Marketing teams inform users about this change? - [ ] Yes - [ ] No
267 lines
12 KiB
TypeScript
267 lines
12 KiB
TypeScript
import { RenderModes } from "constants/WidgetConstants";
|
|
import React from "react";
|
|
import * as editorSelectors from "selectors/editorSelectors";
|
|
import { WidgetTypeFactories } from "test/factories/Widgets/WidgetTypeFactories";
|
|
import { render } from "test/testUtils";
|
|
import InputWidget from "widgets/InputWidgetV2/widget";
|
|
import { ModalWidget } from "widgets/ModalWidget/widget";
|
|
import { WDSModalWidget } from "widgets/wds/WDSModalWidget/widget";
|
|
import { withLayoutSystemWidgetHOC } from "./withLayoutSystemWidgetHOC";
|
|
import { LayoutSystemTypes } from "./types";
|
|
import * as layoutSystemSelectors from "selectors/layoutSystemSelectors";
|
|
|
|
describe("Layout System HOC's Tests", () => {
|
|
describe("Fixed Layout Layers", () => {
|
|
it("Layout system hoc should return Fixed Editor for FIXED positioning and CANVAS render mode", () => {
|
|
const widget = InputWidget;
|
|
const HOC = withLayoutSystemWidgetHOC(widget);
|
|
const widgetProps = WidgetTypeFactories[InputWidget.type].build();
|
|
jest
|
|
.spyOn(editorSelectors, "getRenderMode")
|
|
.mockImplementation(() => RenderModes.CANVAS);
|
|
jest
|
|
.spyOn(layoutSystemSelectors, "getLayoutSystemType")
|
|
.mockImplementation(() => LayoutSystemTypes.FIXED);
|
|
const component = render(<HOC {...widgetProps} />);
|
|
const positionedLayer =
|
|
component.container.getElementsByClassName("positioned-widget")[0];
|
|
const resizerLayer =
|
|
component.container.getElementsByClassName("resize-wrapper")[0];
|
|
expect(positionedLayer).toBeTruthy();
|
|
expect(resizerLayer).toBeTruthy();
|
|
});
|
|
it("Layout system hoc should return Fixed Modal Editor for FIXED positioning and CANVAS render mode", () => {
|
|
const widget = ModalWidget;
|
|
const HOC = withLayoutSystemWidgetHOC(widget);
|
|
const widgetProps = WidgetTypeFactories[ModalWidget.type].build({
|
|
isVisible: true,
|
|
});
|
|
jest
|
|
.spyOn(editorSelectors, "getRenderMode")
|
|
.mockImplementation(() => RenderModes.CANVAS);
|
|
jest
|
|
.spyOn(layoutSystemSelectors, "getLayoutSystemType")
|
|
.mockImplementation(() => LayoutSystemTypes.FIXED);
|
|
const component = render(<HOC {...widgetProps} />);
|
|
const positionedLayer =
|
|
component.container.getElementsByClassName("positioned-widget")[0];
|
|
const resizerLayer =
|
|
component.container.getElementsByClassName("resize-wrapper")[0];
|
|
const overlayLayer =
|
|
component.container.getElementsByClassName("bp3-overlay")[0];
|
|
expect(positionedLayer).toBeFalsy();
|
|
expect(overlayLayer).toBeTruthy();
|
|
expect(resizerLayer).toBeTruthy();
|
|
});
|
|
it("Layout system hoc should return Fixed Modal Viewer for FIXED positioning and PAGE render mode", () => {
|
|
const widget = ModalWidget;
|
|
const HOC = withLayoutSystemWidgetHOC(widget);
|
|
const widgetProps = WidgetTypeFactories[ModalWidget.type].build({
|
|
isVisible: true,
|
|
});
|
|
jest
|
|
.spyOn(editorSelectors, "getRenderMode")
|
|
.mockImplementation(() => RenderModes.PAGE);
|
|
jest
|
|
.spyOn(layoutSystemSelectors, "getLayoutSystemType")
|
|
.mockImplementation(() => LayoutSystemTypes.FIXED);
|
|
const component = render(<HOC {...widgetProps} />);
|
|
const positionedLayer =
|
|
component.container.getElementsByClassName("positioned-widget")[0];
|
|
const resizerLayer =
|
|
component.container.getElementsByClassName("resize-wrapper")[0];
|
|
const overlayLayer =
|
|
component.container.getElementsByClassName("bp3-overlay")[0];
|
|
expect(positionedLayer).toBeFalsy();
|
|
expect(overlayLayer).toBeTruthy();
|
|
expect(resizerLayer).toBeFalsy();
|
|
});
|
|
it("Layout system hoc should return Fixed Viewer for FIXED positioning and PAGE render mode", () => {
|
|
const widget = InputWidget;
|
|
const HOC = withLayoutSystemWidgetHOC(widget);
|
|
const widgetProps = WidgetTypeFactories[InputWidget.type].build();
|
|
jest
|
|
.spyOn(editorSelectors, "getRenderMode")
|
|
.mockImplementation(() => RenderModes.PAGE);
|
|
jest
|
|
.spyOn(layoutSystemSelectors, "getLayoutSystemType")
|
|
.mockImplementation(() => LayoutSystemTypes.FIXED);
|
|
const component = render(<HOC {...widgetProps} />);
|
|
const positionedLayer =
|
|
component.container.getElementsByClassName("positioned-widget")[0];
|
|
const resizerLayer =
|
|
component.container.getElementsByClassName("resize-wrapper")[0];
|
|
expect(positionedLayer).toBeTruthy();
|
|
expect(resizerLayer).toBeFalsy();
|
|
});
|
|
});
|
|
describe("Auto Layout Layers", () => {
|
|
it("Layout system hoc should return Auto Layout Editor for AUTO positioning and CANVAS render mode", () => {
|
|
const widget = InputWidget;
|
|
const HOC = withLayoutSystemWidgetHOC(widget);
|
|
const widgetProps = WidgetTypeFactories[InputWidget.type].build();
|
|
jest
|
|
.spyOn(editorSelectors, "getRenderMode")
|
|
.mockImplementation(() => RenderModes.CANVAS);
|
|
jest
|
|
.spyOn(layoutSystemSelectors, "getLayoutSystemType")
|
|
.mockImplementation(() => LayoutSystemTypes.AUTO);
|
|
const component = render(<HOC {...widgetProps} />);
|
|
const flexPositionedLayer = component.container.getElementsByClassName(
|
|
"auto-layout-child-" + widgetProps.widgetId,
|
|
)[0];
|
|
const resizerLayer =
|
|
component.container.getElementsByClassName("resize-wrapper")[0];
|
|
expect(flexPositionedLayer).toBeTruthy();
|
|
expect(resizerLayer).toBeTruthy();
|
|
});
|
|
it("Layout system hoc should return Auto Modal Editor for AUTO positioning and CANVAS render mode", () => {
|
|
const widget = ModalWidget;
|
|
const HOC = withLayoutSystemWidgetHOC(widget);
|
|
const widgetProps = WidgetTypeFactories[ModalWidget.type].build({
|
|
isVisible: true,
|
|
});
|
|
jest
|
|
.spyOn(editorSelectors, "getRenderMode")
|
|
.mockImplementation(() => RenderModes.CANVAS);
|
|
jest
|
|
.spyOn(layoutSystemSelectors, "getLayoutSystemType")
|
|
.mockImplementation(() => LayoutSystemTypes.AUTO);
|
|
const component = render(<HOC {...widgetProps} />);
|
|
const flexPositionedLayer = component.container.getElementsByClassName(
|
|
"auto-layout-child-" + widgetProps.widgetId,
|
|
)[0];
|
|
const resizerLayer =
|
|
component.container.getElementsByClassName("resize-wrapper")[0];
|
|
const overlayLayer =
|
|
component.container.getElementsByClassName("bp3-overlay")[0];
|
|
expect(flexPositionedLayer).toBeFalsy();
|
|
expect(overlayLayer).toBeTruthy();
|
|
expect(resizerLayer).toBeTruthy();
|
|
});
|
|
it("Layout system hoc should return Auto Modal Viewer for AUTO positioning and PAGE render mode", () => {
|
|
const widget = ModalWidget;
|
|
const HOC = withLayoutSystemWidgetHOC(widget);
|
|
const widgetProps = WidgetTypeFactories[ModalWidget.type].build({
|
|
isVisible: true,
|
|
});
|
|
jest
|
|
.spyOn(editorSelectors, "getRenderMode")
|
|
.mockImplementation(() => RenderModes.PAGE);
|
|
jest
|
|
.spyOn(layoutSystemSelectors, "getLayoutSystemType")
|
|
.mockImplementation(() => LayoutSystemTypes.AUTO);
|
|
const component = render(<HOC {...widgetProps} />);
|
|
const flexPositionedLayer = component.container.getElementsByClassName(
|
|
"auto-layout-child-" + widgetProps.widgetId,
|
|
)[0];
|
|
const resizerLayer =
|
|
component.container.getElementsByClassName("resize-wrapper")[0];
|
|
const overlayLayer =
|
|
component.container.getElementsByClassName("bp3-overlay")[0];
|
|
expect(flexPositionedLayer).toBeFalsy();
|
|
expect(overlayLayer).toBeTruthy();
|
|
expect(resizerLayer).toBeFalsy();
|
|
});
|
|
it("Layout system hoc should return Auto Viewer for Auto positioning and PAGE render mode", () => {
|
|
const widget = InputWidget;
|
|
const HOC = withLayoutSystemWidgetHOC(widget);
|
|
const widgetProps = WidgetTypeFactories[InputWidget.type].build();
|
|
jest
|
|
.spyOn(editorSelectors, "getRenderMode")
|
|
.mockImplementation(() => RenderModes.PAGE);
|
|
jest
|
|
.spyOn(layoutSystemSelectors, "getLayoutSystemType")
|
|
.mockImplementation(() => LayoutSystemTypes.AUTO);
|
|
const component = render(<HOC {...widgetProps} />);
|
|
const flexPositionedLayer = component.container.getElementsByClassName(
|
|
"auto-layout-child-" + widgetProps.widgetId,
|
|
)[0];
|
|
const resizerLayer =
|
|
component.container.getElementsByClassName("resize-wrapper")[0];
|
|
expect(flexPositionedLayer).toBeTruthy();
|
|
expect(resizerLayer).toBeFalsy();
|
|
});
|
|
});
|
|
describe("Anvil Layout Layers", () => {
|
|
it("Layout system hoc should return Anvil Editor for ANVIL positioning and CANVAS render mode", () => {
|
|
const widget = InputWidget;
|
|
const HOC = withLayoutSystemWidgetHOC(widget);
|
|
const widgetProps = WidgetTypeFactories[InputWidget.type].build();
|
|
jest
|
|
.spyOn(editorSelectors, "getRenderMode")
|
|
.mockImplementation(() => RenderModes.CANVAS);
|
|
jest
|
|
.spyOn(layoutSystemSelectors, "getLayoutSystemType")
|
|
.mockImplementation(() => LayoutSystemTypes.ANVIL);
|
|
const component = render(<HOC {...widgetProps} />);
|
|
const flexPositionedLayer = component.container.getElementsByClassName(
|
|
"anvil-layout-child-" + widgetProps.widgetId,
|
|
)[0];
|
|
expect(flexPositionedLayer).toBeTruthy();
|
|
});
|
|
it("should return Auto Modal Editor for ANVIL positioning and CANVAS render mode", () => {
|
|
const widget = WDSModalWidget;
|
|
const HOC = withLayoutSystemWidgetHOC(widget);
|
|
const widgetProps = WidgetTypeFactories[ModalWidget.type].build({
|
|
isVisible: true,
|
|
detachFromLayout: true,
|
|
renderMode: RenderModes.CANVAS,
|
|
layout: [
|
|
{
|
|
layoutId: "modalLayoutId",
|
|
},
|
|
],
|
|
});
|
|
jest
|
|
.spyOn(editorSelectors, "getRenderMode")
|
|
.mockImplementation(() => RenderModes.CANVAS);
|
|
jest
|
|
.spyOn(layoutSystemSelectors, "getLayoutSystemType")
|
|
.mockImplementation(() => LayoutSystemTypes.ANVIL);
|
|
const component = render(<HOC {...widgetProps} />);
|
|
const flexPositionedLayer = component.container.getElementsByClassName(
|
|
"anvil-layout-child-" + widgetProps.widgetId,
|
|
)[0];
|
|
expect(flexPositionedLayer).toBeFalsy();
|
|
});
|
|
it("should return Auto Modal Viewer for ANVIL positioning and PAGE render mode", () => {
|
|
const widget = WDSModalWidget;
|
|
const HOC = withLayoutSystemWidgetHOC(widget);
|
|
const widgetProps = WidgetTypeFactories[ModalWidget.type].build({
|
|
isVisible: true,
|
|
detachFromLayout: true,
|
|
renderMode: RenderModes.PAGE,
|
|
});
|
|
jest
|
|
.spyOn(editorSelectors, "getRenderMode")
|
|
.mockImplementation(() => RenderModes.PAGE);
|
|
jest
|
|
.spyOn(layoutSystemSelectors, "getLayoutSystemType")
|
|
.mockImplementation(() => LayoutSystemTypes.ANVIL);
|
|
const component = render(<HOC {...widgetProps} />);
|
|
const flexPositionedLayer = component.container.getElementsByClassName(
|
|
"anvil-layout-child-" + widgetProps.widgetId,
|
|
)[0];
|
|
expect(flexPositionedLayer).toBeFalsy();
|
|
});
|
|
it("should return Anvil Viewer for ANVIL positioning and PAGE render mode", () => {
|
|
const widget = InputWidget;
|
|
const HOC = withLayoutSystemWidgetHOC(widget);
|
|
const widgetProps = WidgetTypeFactories[InputWidget.type].build();
|
|
jest
|
|
.spyOn(editorSelectors, "getRenderMode")
|
|
.mockImplementation(() => RenderModes.PAGE);
|
|
jest
|
|
.spyOn(layoutSystemSelectors, "getLayoutSystemType")
|
|
.mockImplementation(() => LayoutSystemTypes.ANVIL);
|
|
const component = render(<HOC {...widgetProps} />);
|
|
const flexPositionedLayer =
|
|
component.container.ownerDocument.getElementById(
|
|
"anvil_widget_" + widgetProps.widgetId,
|
|
);
|
|
expect(flexPositionedLayer).toBeTruthy();
|
|
});
|
|
});
|
|
});
|