// @ts-nocheck import * as React from "react"; import { head, get } from "lodash"; import { useDimensions } from "@sc/plugins/utilities"; import { useDrop } from "react-dnd"; import { DragTypes, EditorActions } from "../../types"; import { AddTypes } from "../EditorObject/EditorObject"; import { EditorContext } from "../../Editor"; import { listAncestors } from "../../actions"; interface ComponentWrapperProps { /** * The unique id of the editor object */ id: string; /** * Whether or not the component is currently showing properties */ isShowingProperties?: Boolean; /** * TODO: Add a description */ children: React.ReactNode; } const xisHovering = (monitor, { content, dispatch, hoverBoundingRect, id }) => { // Triggered when an object is on top of me // (places a cursor in the location where the drop will occur) // Only Proceed If Hovering Directly On The Object (And Not Nested Inside) if (!monitor.isOver({ shallow: true })) return; // Get the coordinates of the middle of the object const hoverMiddleY = (hoverBoundingRect.bottom - hoverBoundingRect.top) / 2; // Get the current mouse position const clientOffset = monitor.getClientOffset(); // Get the coorinates with respect to the object being hovered on const hoverClientY = clientOffset.y - hoverBoundingRect.top; // Add a cursor only when the mouse changes directions if (hoverClientY === monitor.getItem().formerClientY) return; // ignore if mouse doesn't move const sourceItem = head( content.filter((itm) => itm.id === monitor.getItem().id) ); const targetItem = head(content.filter((itm) => itm.id === id)); // (handle containers) if (get(sourceItem, "canHaveChildren", false)) { const offLimitObjects = listAncestors(content, targetItem.id); // all the parents of the targetItem if (sourceItem.id === targetItem.id) return; const offLimitIds = offLimitObjects.map((itm) => itm.parent); // all the ids parents if (offLimitIds.findIndex((itm) => itm === sourceItem.id) > -1) return; // if we find the id of the sourceItem in my list, cancel // Place at the bottom if the sourceItem tries to drop into itself if (sourceItem.id === targetItem.id) { dispatch({ type: EditorActions.ADD_HOVER_CURSOR, payload: { id: targetItem.id, addType: AddTypes.AFTER, }, }); // addHoverCursor(targetItem.id, AddTypes.AFTER); } } // Add a cursor inside fo the container if it is blank if its empty if (get(targetItem, "canHaveChildren", false)) { // if the container is empty, add a cursor if (content.findIndex((itm) => itm.parent === targetItem.id) === -1) { // object is empty dispatch({ type: EditorActions.ADD_HOVER_CURSOR, payload: { id: targetItem.id, addType: AddTypes.INSIDE, }, }); // console.log("I'm inside an Empty container"); return; } if (!get(targetItem, "parent", false)) return; // console.log("I'm inside a FULL container"); const children = content.filter((itm) => itm.parent === targetItem.id); // If the container is full, add the cursor after the last inner object const twentyPercentFromTheBottom = Math.round( hoverBoundingRect.height - hoverBoundingRect.height * 0.2 ); if (hoverClientY > twentyPercentFromTheBottom) { // console.log("I'm 20% from the bottom of ", targetItem.type); dispatch({ type: EditorActions.ADD_HOVER_CURSOR, payload: { id: targetItem.id, addType: AddTypes.AFTER, }, }); return; } // If they're close to the top of the container, add the cursor before the first inner object const tenPercentFromTheTop = Math.round(hoverBoundingRect.height * 0.1); if (hoverClientY < tenPercentFromTheTop) { // console.log("I'm 10% from the top of ", targetItem.type); dispatch({ type: EditorActions.ADD_HOVER_CURSOR, payload: { id: targetItem.id, addType: AddTypes.BEFORE, }, }); return; } if (!children.hasOwnProperty(children.length - 1)) return; dispatch({ type: EditorActions.ADD_HOVER_CURSOR, payload: { id: children[children.length - 1].id, addType: AddTypes.AFTER, }, }); return; } // Don't work on a root object (ALWAYS HAVE A 'BODY' object as your root!) if (!targetItem.parent) return; // Determine if the mouse is moving upwards or downwards // (this will establish where to place the object when the mouse is released) const currentAddType = hoverClientY < (monitor.getItem().formerClientY || hoverMiddleY) ? AddTypes.BEFORE : AddTypes.AFTER; monitor.getItem().formerClientY = hoverClientY; // Ignore if the mouse is heading in the same direction if (currentAddType === monitor.getItem().addType) return; monitor.getItem().addType = currentAddType; /** * At this point, we're ready to drop above or below an object. However, * if the user is hover on top of an object that is the first or last object * of the parent element, we should check to see if it is at the top 20 or * bottom 20% of the parent element. if it is, place above or below that * parent element */ // Place above (or below) the PARENT element if the mouse is within 20% of the top (or the bottom) // Place the cursor dispatch({ type: EditorActions.ADD_HOVER_CURSOR, payload: { id: targetItem.id, addType: currentAddType, }, }); }; const addHoverCursor = (id, dispatch, addType = AddTypes.AFTER) => { dispatch({ type: EditorActions.ADD_HOVER_CURSOR, payload: { id, addType, }, }); }; const isHovering = (monitor, { content, dispatch, hoverBoundingRect, id }) => { // Triggered when an object is on top of me // (places a cursor in the location where the drop will occur) // Only Proceed If Hovering Directly On The Object (And Not Nested Inside) if (!monitor.isOver({ shallow: true })) return; // [!] can drag up/down and show cursor in right spot (no container) const targetItem = head(content.filter((itm) => itm.id === id)); addHoverCursor(targetItem.id, dispatch); console.log("isHovering", id); // [!] Can release and replacement happens // [!] Dragging a container // [!] Dragging into a container // [!] Dragging at the top/bottom of a container }; /** * The container that is wrapped around each component in the editor */ const ComponentWrapper: React.FC = ({ children, id, }) => { const [ref, hoverBoundingRect] = useDimensions(); const editor = React.useContext(EditorContext); // const { content, addHoverCursor, listAncestors } = editor; const { content, dispatch } = editor; const [{ canDrop, isOver }, dropRef] = useDrop({ accept: DragTypes.EDITOROBJECT, drop: () => ({ id }), hover: (props, monitor) => { isHovering(monitor, { content, dispatch, hoverBoundingRect, id, }); }, collect: (monitor) => ({ isOver: monitor.isOver(), canDrop: monitor.canDrop(), }), }); return (
{children}
); }; export default ComponentWrapper;