import * as React from "react"; import * as cx from "classnames"; import { TreeMoveOffset, containsNestedTreeNodeById, getNestedTreeNodeById, getParentTreeNode } from "tandem-common"; import { DropTarget } from "react-dnd"; import { InspectorNode, InspectorTreeNodeName, inspectorNodeInShadow, getPCNodeContentNode } from "paperclip"; import { getPCNode, PCSourceTagNames, PCNode, extendsComponent, DependencyGraph, getPCNodeModule } from "paperclip"; import { compose, Dispatch } from "redux"; import { sourceInspectorLayerDropped } from "../../../../../actions"; import { withLayersPaneContext, LayersPaneContextProps } from "./contexts"; import { shouldUpdate } from "recompose"; import { getSyntheticNodeInspectorNode, getInspectorContentNodeContainingChild } from "paperclip"; export type WithNodeDropTargetProps = { inspectorNode: InspectorNode; }; type WithNodeDropTargetInnerProps = { draggedSourceNode: PCNode; dispatch: Dispatch; graph: DependencyGraph; contentNode: InspectorNode; } & WithNodeDropTargetProps; export const withDndContext = withLayersPaneContext( ( { inspectorNode }: WithNodeDropTargetProps, { dispatch, graph, rootInspectorNode }: LayersPaneContextProps ) => { getInspectorContentNodeContainingChild; getSyntheticNodeInspectorNode; return { dispatch, graph, contentNode: getInspectorContentNodeContainingChild( inspectorNode, rootInspectorNode ) }; } ); export const withNodeDropTarget = (offset: TreeMoveOffset) => compose( DropTarget( "INSPECTOR_NODE", { canDrop: ( { inspectorNode, contentNode, graph }: WithNodeDropTargetInnerProps, monitor ) => { const contentSourceNode = contentNode && getPCNode(contentNode.sourceNodeId, graph); const draggingInspectorNode = monitor.getItem() as InspectorNode; if (inspectorNode.id === draggingInspectorNode.id) { return false; } const draggedSourceNode = getPCNode( draggingInspectorNode.sourceNodeId, graph ); const assocSourceNodeId = inspectorNode.name === InspectorTreeNodeName.CONTENT ? inspectorNode.sourceSlotNodeId : inspectorNode.sourceNodeId; const sourceNode = getPCNode(assocSourceNodeId, graph); const parentSourceNode: PCNode = getParentTreeNode( sourceNode.id, getPCNodeModule(assocSourceNodeId, graph) ); // if the dragged node is a component, then ensure that it can only be dragged around // the root level of the module. if (draggedSourceNode.name === PCSourceTagNames.COMPONENT) { if ( offset === TreeMoveOffset.APPEND || offset === TreeMoveOffset.PREPEND ) { return sourceNode.name === PCSourceTagNames.MODULE; } else { return ( parentSourceNode && parentSourceNode.name === PCSourceTagNames.MODULE ); } } if ( offset === TreeMoveOffset.BEFORE || offset === TreeMoveOffset.AFTER ) { return ( parentSourceNode && (parentSourceNode.name !== PCSourceTagNames.COMPONENT_INSTANCE && !extendsComponent(parentSourceNode)) ); } if ( offset === TreeMoveOffset.APPEND || offset === TreeMoveOffset.PREPEND ) { // do not allow style mixins to have children for now. This may change // later on if ::part functionality is added. if (sourceNode.name === PCSourceTagNames.STYLE_MIXIN) { return false; } if ( sourceNode.name === PCSourceTagNames.TEXT || sourceNode.name === PCSourceTagNames.COMPONENT_INSTANCE || extendsComponent(sourceNode) ) { return false; } return ( !contentSourceNode || containsNestedTreeNodeById(sourceNode.id, contentSourceNode) || (inspectorNode.name === InspectorTreeNodeName.CONTENT && !inspectorNodeInShadow(inspectorNode, contentNode)) ); } else { return true; } }, drop: ({ dispatch, inspectorNode }, monitor) => { dispatch( sourceInspectorLayerDropped( monitor.getItem() as InspectorNode, inspectorNode, offset ) ); } }, (connect, monitor) => { return { connectDropTarget: connect.dropTarget(), isOver: !!monitor.isOver(), canDrop: !!monitor.canDrop() }; } ) ); export const withHoverVariant = compose( shouldUpdate((props: any, next: any) => { return ( props.isOver !== next.isOver || props.connectDropTarget !== next.connectDropTarget ); }), (Base: React.ComponentClass) => ({ isOver, canDrop, contentNode, connectDropTarget, ...rest }) => { return connectDropTarget(
); } );