react-dnd#useDrop TypeScript Examples

The following examples show how to use react-dnd#useDrop. You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: DragItem.tsx    From gio-design with Apache License 2.0 6 votes vote down vote up
DragItem: React.FC<DragItemProps> = (props) => {
  const { label, value, onMoved, index, disabled, ...rest } = props;
  const prefixCls = `${usePrefixCls(PREFIX)}`;
  const ref = useRef<HTMLDivElement>(null);
  const [{ handlerId }, drop] = useDrop({
    accept: 'drag-item',
    collect(monitor) {
      return {
        handlerId: monitor.getHandlerId(),
      };
    },
    hover(item: { index: number; type: string; id: string }, monitor: DropTargetMonitor) {

      const dragIndex = item.index;
      const hoverIndex = index;

      if (dragIndex === hoverIndex) {
        return;
      }
      const hoverBoundingRect = ref.current?.getBoundingClientRect() || { bottom: 0, top: 0 };
      const hoverMiddleY = (hoverBoundingRect.bottom - hoverBoundingRect.top) / 2;
      const clientOffset = monitor.getClientOffset();

      const hoverClientY = (clientOffset as XYCoord).y - hoverBoundingRect.top;

      // Dragging upwards or downwards
      if ((dragIndex < hoverIndex && hoverClientY < hoverMiddleY) || (dragIndex > hoverIndex && hoverClientY > hoverMiddleY)) {
        return
      };

      onMoved?.(dragIndex as number, hoverIndex);
      // eslint-disable-next-line no-param-reassign
      item.index = hoverIndex;
    },
  });
  const [, drag] = useDrag({
    item: { type: 'drag-item', id: value, index },
    collect: (monitor: DragSourceMonitor) => ({
      isDragging: monitor.isDragging(),
    }),
    canDrag: !disabled,
  });

  drag(drop(ref));
  return (
    <div
      className={classNames(`${prefixCls}--item`, `${prefixCls}--item--drag`, {
        [`${prefixCls}--item--disabled`]: disabled,
      })}
      ref={ref}
      data-handler-id={handlerId}
    >
      <DragOutlined
        className={classNames(`${prefixCls}--item--drag--icon`, {
          [`${prefixCls}--item--drag--icon--disabled`]: disabled,
        })}
        color="#ADB2C2"
        size="14px"
      />
      <Item label={label} value={value} disabled={disabled} {...rest} />
    </div>
  );
}
Example #2
Source File: useDropComponent.ts    From openchakra with MIT License 6 votes vote down vote up
useDropComponent = (
  componentId: string,
  accept: (ComponentType | MetaComponentType)[] = rootComponents,
  canDrop: boolean = true,
) => {
  const dispatch = useDispatch()

  const [{ isOver }, drop] = useDrop({
    accept,
    collect: monitor => ({
      isOver: monitor.isOver({ shallow: true }) && monitor.canDrop(),
    }),
    drop: (item: ComponentItemProps, monitor: DropTargetMonitor) => {
      if (!monitor.isOver()) {
        return
      }

      if (item.isMoved) {
        dispatch.components.moveComponent({
          parentId: componentId,
          componentId: item.id,
        })
      } else if (item.isMeta) {
        dispatch.components.addMetaComponent(builder[item.type](componentId))
      } else {
        dispatch.components.addComponent({
          parentName: componentId,
          type: item.type,
          rootParentType: item.rootParentType,
        })
      }
    },
    canDrop: () => canDrop,
  })

  return { drop, isOver }
}
Example #3
Source File: DayCell.tsx    From calendar-hack with MIT License 6 votes vote down vote up
DayCell: React.FC<Props> = ({ dayDetails, date, units, swap, selected, hovering, }) => {

    function canSwap(d1: Date) {
        return dayDetails !== undefined;
    }

    const [{ isOver, canDrop, droppedItem }, drop] = useDrop({
        accept: ItemTypes.DAY,
        canDrop: () => canSwap(date),
        drop: () => { swap(date, droppedItem.date); return; },
        collect: (monitor) => ({
            isOver: monitor.isOver(),
            canDrop: monitor.canDrop(),
            droppedItem: monitor.getItem()
        }),
    })

    return (
        <div style={{
            position: 'relative',
            width: '100%',
            height: '100%',
        }}>
            <DropTarget isOver={isOver} canDrop={canDrop} ref={drop}>
                {dayDetails && <WorkoutCard dayDetails={dayDetails} date={date} units={units} swap={swap} />}
                {!dayDetails && <BlankCard date={date} />}
                {isOver && !canDrop && <Overlay color="pink" />}
                {isOver && canDrop && <Overlay color="lightgreen" />}

                {dayDetails && selected && <Overlay color="pink" />}
                {dayDetails && !selected && hovering && <Overlay color="lightgreen" />}
            </DropTarget>
        </div>
    );
}
Example #4
Source File: Dustbin.tsx    From jetlinks-ui-antd with MIT License 6 votes vote down vote up
Dustbin: React.FC<DustbinProps> = ({
    accept,
    lastDroppedItem,
    dropResult,
    onDrop,
}) => {
    const [{ isOver, canDrop }, drop] = useDrop({
        accept,
        drop: onDrop,
        collect: monitor => ({
            isOver: monitor.isOver(),
            canDrop: monitor.canDrop(),
        }),
    })

    const isActive = isOver && canDrop
    let backgroundColor = '#222'
    if (isActive) {
        backgroundColor = 'darkgreen'
    } else if (canDrop) {
        backgroundColor = 'darkkhaki'
    }

    return (
        <div ref={drop} style={{ ...style, backgroundColor }}>
            {/* {isActive
                ? 'Release to drop'
                : `This dustbin accepts: ${accept.join(', ')}`} */}

            {/* {lastDroppedItem && ( */}
            <p>Last dropped: {JSON.stringify(dropResult)}</p>
            {/* )} */}
        </div>
    )
}
Example #5
Source File: DropHolder.tsx    From datart with Apache License 2.0 6 votes vote down vote up
DropHolder: React.FC<DropHolderProps> = memo(
  ({ tabItem, parentId }) => {
    const [{ isOver, canDrop }, refDrop] = useDrop(
      () => ({
        accept: CONTAINER_TAB,
        item: { tabItem, parentId },
        drop: () => ({ tabItem, parentId }),
        canDrop: (item: any) => {
          if (CanDropToWidgetTypes.includes(item.type)) {
            return true;
          }
          return false;
        },
        collect: (monitor: DropTargetMonitor) => ({
          isOver: monitor.isOver(),
          canDrop: monitor.canDrop(),
        }),
      }),
      [],
    );
    const bgColor = useMemo(() => {
      let color = 'transparent';
      if (canDrop) {
        color = '#f1e648c7';
        if (isOver) {
          color = '#1bcf81d3';
        }
      }

      return color;
    }, [isOver, canDrop]);
    return (
      <DropWrap ref={refDrop} bgColor={bgColor}>
        <div className="center">将组件拖入该区域</div>
      </DropWrap>
    );
  },
)
Example #6
Source File: index.tsx    From redux-with-domain with MIT License 6 votes vote down vote up
AttriItem: FC<Props> = ({ attr: { group, fields }, index }) => {
  const dispatch = useDispatch()
  const chartId = useSelector(module.selectors.getChartId)
  const fieldItems = fields.map(field => {
    return (
      <div key={field.id} className="attr-field">
        {field.name}
      </div>
    )
  })

  const [_, drop] = useDrop({
    accept: 'FIELD',
    drop: (item: any, monitor) => {
      dispatch(
        module.actions.addField({ group, fieldId: item.id, index, chartId })
      )
    }
  })

  return (
    <div key={group} className="attr">
      <div className="attr-group">{group}</div>
      <div className="attr-field-list" ref={drop}>
        {fieldItems}
      </div>
    </div>
  )
}
Example #7
Source File: ClassEditor.tsx    From legend-studio with Apache License 2.0 5 votes vote down vote up
DerviedPropertiesEditor = observer(
  (props: { _class: Class; editorState: ClassEditorState }) => {
    const { _class, editorState } = props;
    const isReadOnly = editorState.isReadOnly;
    const classState = editorState.classState;

    const indirectDerivedProperties = getAllClassDerivedProperties(_class)
      .filter((property) => !_class.derivedProperties.includes(property))
      .sort((p1, p2) => p1.name.localeCompare(p2.name))
      .sort(
        (p1, p2) =>
          (p1._OWNER === _class ? 1 : 0) - (p2._OWNER === _class ? 1 : 0),
      );
    const deleteDerivedProperty =
      (dp: DerivedProperty): (() => void) =>
      (): void => {
        class_deleteDerivedProperty(_class, dp);
        classState.deleteDerivedPropertyState(dp);
        if (dp === editorState.selectedProperty) {
          editorState.setSelectedProperty(undefined);
        }
      };

    const handleDropDerivedProperty = useCallback(
      (item: UMLEditorElementDropTarget): void => {
        if (!isReadOnly && item.data.packageableElement instanceof Type) {
          const dp = stub_DerivedProperty(item.data.packageableElement, _class);
          class_addDerivedProperty(_class, dp);
          classState.addDerivedPropertyState(dp);
        }
      },
      [_class, classState, isReadOnly],
    );
    const [{ isDerivedPropertyDragOver }, dropDerivedPropertyRef] = useDrop(
      () => ({
        accept: [
          CORE_DND_TYPE.PROJECT_EXPLORER_CLASS,
          CORE_DND_TYPE.PROJECT_EXPLORER_ENUMERATION,
        ],
        drop: (item: ElementDragSource): void =>
          handleDropDerivedProperty(item),
        collect: (monitor): { isDerivedPropertyDragOver: boolean } => ({
          isDerivedPropertyDragOver: monitor.isOver({ shallow: true }),
        }),
      }),
      [handleDropDerivedProperty],
    );

    useApplicationNavigationContext(
      LEGEND_STUDIO_APPLICATION_NAVIGATION_CONTEXT.CLASS_EDITOR_DERIVED_PROPERTIES,
    );

    return (
      <div
        ref={dropDerivedPropertyRef}
        className={clsx('panel__content__lists', {
          'panel__content__lists--dnd-over':
            isDerivedPropertyDragOver && !isReadOnly,
        })}
      >
        {_class.derivedProperties
          .concat(indirectDerivedProperties)
          .filter((dp): dp is DerivedProperty =>
            Boolean(classState.getNullableDerivedPropertyState(dp)),
          )
          .map((dp) => (
            <DerivedPropertyBasicEditor
              key={dp._UUID}
              derivedProperty={dp}
              _class={_class}
              editorState={editorState}
              deleteDerivedProperty={deleteDerivedProperty(dp)}
              isReadOnly={isReadOnly}
            />
          ))}
      </div>
    );
  },
)
Example #8
Source File: DayOfWeekHeader.tsx    From calendar-hack with MIT License 5 votes vote down vote up
DayOfWeekHeader: React.FC<Props> = ({ dow, swapDow, selectDow, hoverDow }) => {

    const [{ isOver, canDrop, droppedItem }, drop] = useDrop({
        accept: ItemTypes.DOW,
        canDrop: () => true,
        drop: () => { swapDow(dow, droppedItem.dow); return; },
        collect: (monitor) => {
            if (monitor.isOver()) {
                hoverDow(dow);
            }
            return {
                isOver: monitor.isOver(),
                canDrop: monitor.canDrop(),
                droppedItem: monitor.getItem()
            }
        },
    })

    const [{ isDragging }, drag, preview] = useDrag({
        item: { type: ItemTypes.DOW, dow: dow },
        collect: (monitor) => {
            if (monitor.isDragging()) {
                selectDow(dow);
            }
            return {
                isDragging: monitor.isDragging(),
            };
        },
        begin: (monitor: DragSourceMonitor) => {
            selectDow(dow);
        },
        end: (item: { dow: dayOfWeek } | undefined, monitor: DragSourceMonitor) => {
            const dropResult = monitor.getDropResult()
            if (item && dropResult) {
                selectDow(undefined);
                hoverDow(undefined);
            }
        },
    })

    return (
        <div style={{
            position: 'relative',
            width: '100%',
            height: '100%',
        }}>
            <DragSource isDragging={isDragging} dow={dow}>
                <DropTarget isOver={isOver} canDrop={canDrop} ref={drop}>
                    <Preview generator={generateDowPreview} />
                    <div ref={preview}>
                        <Root ref={drag}>
                            <DragHandle viewBox="0 0 32 36" />
                            <div>{dow}</div>
                        </Root>
                    </div>
                </DropTarget>
            </DragSource>
        </div>
    )
}
Example #9
Source File: ClassEditor.tsx    From legend-studio with Apache License 2.0 5 votes vote down vote up
PropertiesEditor = observer(
  (props: { _class: Class; editorState: ClassEditorState }) => {
    const { _class, editorState } = props;
    const isReadOnly = editorState.isReadOnly;

    const deleteProperty =
      (property: Property): (() => void) =>
      (): void => {
        class_deleteProperty(_class, property);
        if (property === editorState.selectedProperty) {
          editorState.setSelectedProperty(undefined);
        }
      };
    const indirectProperties = getAllClassProperties(_class)
      .filter((property) => !_class.properties.includes(property))
      .sort((p1, p2) => p1.name.localeCompare(p2.name))
      .sort(
        (p1, p2) =>
          (p1._OWNER === _class ? 1 : 0) - (p2._OWNER === _class ? 1 : 0),
      );

    const handleDropProperty = useCallback(
      (item: UMLEditorElementDropTarget): void => {
        if (!isReadOnly && item.data.packageableElement instanceof Type) {
          class_addProperty(
            _class,
            stub_Property(item.data.packageableElement, _class),
          );
        }
      },
      [_class, isReadOnly],
    );
    const [{ isPropertyDragOver }, dropPropertyRef] = useDrop(
      () => ({
        accept: [
          CORE_DND_TYPE.PROJECT_EXPLORER_CLASS,
          CORE_DND_TYPE.PROJECT_EXPLORER_ENUMERATION,
        ],
        drop: (item: ElementDragSource): void => handleDropProperty(item),
        collect: (monitor): { isPropertyDragOver: boolean } => ({
          isPropertyDragOver: monitor.isOver({ shallow: true }),
        }),
      }),
      [handleDropProperty],
    );

    useApplicationNavigationContext(
      LEGEND_STUDIO_APPLICATION_NAVIGATION_CONTEXT.CLASS_EDITOR_PROPERTIES,
    );

    return (
      <div
        ref={dropPropertyRef}
        className={clsx('panel__content__lists', {
          'panel__content__lists--dnd-over': isPropertyDragOver && !isReadOnly,
        })}
      >
        {_class.properties.concat(indirectProperties).map((property) => (
          <PropertyBasicEditor
            key={property._UUID}
            property={property}
            _class={_class}
            editorState={editorState}
            deleteProperty={deleteProperty(property)}
            isReadOnly={isReadOnly}
          />
        ))}
      </div>
    );
  },
)
Example #10
Source File: DragAndDropTreeComponent.tsx    From frontend-sample-showcase with MIT License 5 votes vote down vote up
DragAndDropNode: React.FC<TreeNodeRendererProps> = (props) => {
  const { treeModelSource, treeNodeLoader, isDragging, setDragging } = React.useContext(dragDropContext)!;

  // Make node draggable
  const [, dragSourceRef] = useDrag({
    item: { type: "tree-node", id: props.node.id },
    begin: () => setDragging(true),
    end: () => setDragging(false),
  });

  // Make node accept drop events
  const [{ isHovered }, dropTargetRef] = useDrop({
    accept: "tree-node",
    hover: handleHover,
    canDrop: handleCanDrop,
    drop: handleDrop,
    collect: (monitor) => ({ isHovered: monitor.isOver() }),
  });

  const [canDrop, setCanDrop] = React.useState(false);
  function handleCanDrop(item: NodeDragObject): boolean {
    // Do not allow dropping a node in such a way that would create a parent-child relationship cycle
    const isDroppingOnSelf = props.node.id === item.id && dropArea === DropArea.Inside;
    const newCanDrop = !isDroppingOnSelf && !areNodesRelated(treeModelSource.getModel(), item.id, props.node.id);
    setCanDrop(newCanDrop);
    return newCanDrop;
  }

  const elementRef = React.useRef<HTMLDivElement>(null);
  const [dropArea, setDropArea] = React.useState<DropArea>(DropArea.Inside);
  function handleHover(item: NodeDragObject, monitor: DropTargetMonitor): void {
    // Determine which drop area is hovered and whether we can drop the node there
    const cursorY = monitor.getClientOffset()?.y;
    const dropTargetY = elementRef.current?.getBoundingClientRect().y;
    if (cursorY !== undefined && dropTargetY !== undefined) {
      setDropArea(determineDropArea(25, 7, cursorY - dropTargetY));
      handleCanDrop(item);
    }
  }

  function handleDrop(item: NodeDragObject): void {
    // The main entry point for drop event handling
    const { parentId, index } = getDropLocation(treeModelSource.getModel(), props.node, dropArea);
    moveNode(treeModelSource, treeNodeLoader, item.id, parentId, index)
      .catch((error) => {
        // eslint-disable-next-line no-console
        console.error(error);
      });
  }

  const isDropAreaDisplayed = isHovered && canDrop;
  const nodeStyle: React.CSSProperties = {
    height: 25,
    ...(isDropAreaDisplayed && dropArea === DropArea.Inside && { background: "var(--buic-row-hover)" }),
  };
  return (
    <div ref={mergeRefs([dragSourceRef, dropTargetRef, elementRef])}>
      <div style={{ height: 0 }}>
        {isDropAreaDisplayed && dropArea === DropArea.Above && <NodeInsertMarker topOffset={0} />}
        {isDropAreaDisplayed && dropArea === DropArea.Below && <NodeInsertMarker topOffset={25} />}
      </div>
      <BasicTreeNode style={nodeStyle} isHoverDisabled={isDragging} {...props} />
    </div>
  );
}
Example #11
Source File: BindingElementEditor.tsx    From legend-studio with Apache License 2.0 5 votes vote down vote up
BindingScopeEditor = observer(
  (props: {
    elements: PackageableElementReference<PackageableElement>[];
    addElement: () => void;
    removeElement: (
      val: PackageableElementReference<PackageableElement>,
    ) => void;
    allowAddingElement: boolean;
    handleDropElement: (item: UMLEditorElementDropTarget) => void;
    isReadOnly: boolean;
  }) => {
    const {
      elements,
      addElement,
      removeElement,
      allowAddingElement,
      handleDropElement,
      isReadOnly,
    } = props;
    const [{ isElementDragOver }, dropElementRef] = useDrop(
      () => ({
        accept: [
          CORE_DND_TYPE.PROJECT_EXPLORER_ENUMERATION,
          CORE_DND_TYPE.PROJECT_EXPLORER_PACKAGE,
          CORE_DND_TYPE.PROJECT_EXPLORER_CLASS,
          CORE_DND_TYPE.PROJECT_EXPLORER_PROFILE,
          CORE_DND_TYPE.PROJECT_EXPLORER_ASSOCIATION,
          CORE_DND_TYPE.PROJECT_EXPLORER_FUNCTION,
        ],
        drop: (item: ElementDragSource): void => handleDropElement(item),
        collect: (monitor): { isElementDragOver: boolean } => ({
          isElementDragOver: monitor.isOver({ shallow: true }),
        }),
      }),
      [handleDropElement],
    );

    return (
      <div className="binding-scope-editor">
        <div
          ref={dropElementRef}
          className="binding-scope-editor__panel__content dnd__overlay__container"
        >
          <div
            className={clsx({ dnd__overlay: isElementDragOver && !isReadOnly })}
          />
          <div className="binding-scope-editor__panel__content__form">
            <div className="binding-scope-editor__panel__content__form__section">
              <div className="binding-scope-editor__panel__content__form__section__list">
                {elements.map((elementRef) => (
                  <BindingScopeEntryEditor
                    key={elementRef.value._UUID}
                    elementRef={elementRef}
                    removeElement={removeElement}
                    isReadOnly={isReadOnly}
                  />
                ))}
                <div className="binding-scope-editor__panel__content__form__section__list__new-item__add">
                  <button
                    className="binding-scope-editor__panel__content__form__section__list__new-item__add-btn btn btn--dark"
                    disabled={!allowAddingElement}
                    tabIndex={-1}
                    onClick={addElement}
                    title="Add Element"
                  >
                    Add Value
                  </button>
                </div>
              </div>
            </div>
          </div>
        </div>
      </div>
    );
  },
)
Example #12
Source File: DataDocNavigator.tsx    From querybook with Apache License 2.0 5 votes vote down vote up
FavoriteDataDocsSection: React.FC<ICommonSectionProps> = (props) => {
    const { selectedDocId, loadedFilterModes, filterString } = props;
    const section = 'favorite';
    const { collapsed, setCollapsed, load } = useCommonNavigatorState(
        section,
        props
    );
    const dataDocs = useSelector(favoriteDataDocsSelector);
    const dispatch = useDispatch();

    const [{ isOver }, dropRef] = useDrop({
        accept: [BoardDraggableType, DataDocDraggableType],
        drop: (item: IDragItem<IDataDoc | IProcessedBoardItem>, monitor) => {
            if (monitor.didDrop()) {
                return;
            }
            let docId: number = null;
            if (item.type === BoardDraggableType) {
                const itemInfo = item.itemInfo as IProcessedBoardItem;
                if (itemInfo.itemType === 'data_doc') {
                    docId = itemInfo.itemId;
                }
            } else {
                docId = (item.itemInfo as IDataDoc).id;
            }

            if (docId != null) {
                dispatch(dataDocActions.favoriteDataDoc(docId));
            }
        },

        collect: (monitor) => {
            const item: IDragItem = monitor.getItem();
            return {
                isOver:
                    item?.type === BoardDraggableType &&
                    ((item?.itemInfo as unknown) as IProcessedBoardItem)
                        .itemType === 'table'
                        ? false
                        : monitor.isOver(),
            };
        },
    });
    const handleUnfavoriteDataDoc = useCallback(
        (dataDoc: IDataDoc) =>
            dispatch(dataDocActions.unfavoriteDataDoc(dataDoc.id)),
        []
    );

    return (
        <div
            className={isOver ? 'nav-favorite-dragged-over' : ''}
            ref={dropRef}
        >
            <DataDocNavigatorSection
                sectionHeader={'Favorites'}
                sectionHeaderIcon="Star"
                dataDocs={dataDocs}
                selectedDocId={selectedDocId}
                filterString={filterString}
                loaded={!!loadedFilterModes[section]}
                loadDataDocs={load}
                collapsed={collapsed}
                setCollapsed={setCollapsed}
                onRemove={handleUnfavoriteDataDoc}
                allowReorder
            />
        </div>
    );
}
Example #13
Source File: QueryBuilderGraphFetchTreePanel.tsx    From legend-studio with Apache License 2.0 5 votes vote down vote up
QueryBuilderGraphFetchTreePanel = observer(
  (props: { queryBuilderState: QueryBuilderState }) => {
    const { queryBuilderState } = props;
    const fetchStructureState = queryBuilderState.fetchStructureState;
    const graphFetchState = fetchStructureState.graphFetchTreeState;
    const treeData = graphFetchState.treeData;

    // Deep/Graph Fetch Tree
    const updateTreeData = (data: QueryBuilderGraphFetchTreeData): void => {
      graphFetchState.setGraphFetchTree(data);
    };

    // Drag and Drop
    const handleDrop = useCallback(
      (item: QueryBuilderExplorerTreeDragSource): void => {
        graphFetchState.addProperty(item.node);
      },
      [graphFetchState],
    );
    const [{ isPropertyDragOver }, dropConnector] = useDrop(
      () => ({
        accept: [
          QUERY_BUILDER_EXPLORER_TREE_DND_TYPE.ENUM_PROPERTY,
          QUERY_BUILDER_EXPLORER_TREE_DND_TYPE.PRIMITIVE_PROPERTY,
        ],
        drop: (
          item: QueryBuilderExplorerTreeDragSource,
          monitor: DropTargetMonitor,
        ): void => {
          if (!monitor.didDrop()) {
            handleDrop(item);
          } // prevent drop event propagation to accomondate for nested DnD
        },
        collect: (monitor): { isPropertyDragOver: boolean } => ({
          isPropertyDragOver: monitor.isOver({ shallow: true }),
        }),
      }),
      [handleDrop],
    );

    return (
      <div
        data-testid={QUERY_BUILDER_TEST_ID.QUERY_BUILDER_GRAPH_FETCH}
        className="panel__content dnd__overlay__container"
        ref={dropConnector}
      >
        <div className={clsx({ dnd__overlay: isPropertyDragOver })} />
        {(!treeData || isGraphFetchTreeDataEmpty(treeData)) && (
          <BlankPanelPlaceholder
            placeholderText="Add a graph fetch property"
            tooltipText="Drag and drop properties here"
          />
        )}
        {treeData && !isGraphFetchTreeDataEmpty(treeData) && (
          <QueryBuilderGraphFetchTreeExplorer
            graphFetchState={graphFetchState}
            treeData={treeData}
            isReadOnly={false}
            updateTreeData={updateTreeData}
          />
        )}
      </div>
    );
  },
)
Example #14
Source File: useReorderTodo.tsx    From remix-hexagonal-architecture with MIT License 5 votes vote down vote up
useReorderTodo = (
  todoListId: string,
  todo: TodoDto,
  currentIndex: number,
  onPreviewMove: (todoId: string, newIndex: number) => void
) => {
  const todosOrder = useFetcher();

  const moveTodo = (newIndex: number) => {
    const formData = new FormData();
    formData.append("todoId", todo.id);
    formData.append("newIndex", newIndex.toString());

    todosOrder.submit(formData, {
      method: "put",
      action: `/l/${todoListId}/order`,
    });
  };

  const [{ isDragging }, drag, preview] = useDrag<
    DragItem,
    DropResult,
    CollectedProps
  >({
    type: DragTypeTodo,
    item: { todoId: todo.id },
    collect: (monitor) => ({
      isDragging: monitor.isDragging(),
    }),
    end: (item, monitor) => {
      const dropResult = monitor.getDropResult();
      if (dropResult?.newIndex != null) moveTodo(dropResult.newIndex);
    },
  });

  const [, drop] = useDrop<DragItem, DropResult>({
    accept: DragTypeTodo,
    hover: (item) => {
      onPreviewMove(item.todoId, currentIndex);
    },
    drop: () => ({
      newIndex: currentIndex,
    }),
  });

  return {
    isDragging,
    ref: (node: HTMLDivElement | null) => drag(drop(node)),
    preview,
  };
}
Example #15
Source File: navigator-item-dnd-container.tsx    From utopia with MIT License 5 votes vote down vote up
NavigatorItemContainer = React.memo((props: NavigatorItemDragAndDropWrapperProps) => {
  const [{ isDragging }, drag] = useDrag(
    () => ({
      type: 'NAVIGATOR_ITEM',
      collect: (monitor) => ({
        isDragging: monitor.isDragging(),
      }),
      item: props,
      beginDrag: beginDrag,
    }),
    [props],
  )

  const dropRef = React.useRef<HTMLDivElement | null>(null)

  const [{ isOver }, drop] = useDrop<
    NavigatorItemDragAndDropWrapperProps,
    unknown,
    DropCollectedProps
  >(
    () => ({
      accept: 'NAVIGATOR_ITEM',
      collect: (monitor) => ({
        isOver: monitor.isOver(),
        canDrop: monitor.canDrop(),
      }),
      hover: (item: NavigatorItemDragAndDropWrapperProps, monitor) => {
        onHover(item, props, monitor, dropRef.current)
      },
      drop: (item: NavigatorItemDragAndDropWrapperProps, monitor) => {
        onDrop(item, props, monitor, dropRef.current)
      },
    }),
    [props],
  )

  const attachDrop = React.useCallback(
    (domElement: HTMLDivElement) => {
      drop(domElement)
      dropRef.current = domElement
    },
    [drop, dropRef],
  )

  return (
    <div ref={attachDrop}>
      <div ref={drag}>
        <NavigatorItemDndWrapper {...props} isOver={isOver} isDragging={isDragging} />
      </div>
    </div>
  )
})
Example #16
Source File: index.tsx    From ql with MIT License 5 votes vote down vote up
DragableBodyRow = ({
  index,
  moveRow,
  className,
  style,
  ...restProps
}: any) => {
  const ref = useRef();
  const [{ isOver, dropClassName }, drop] = useDrop(
    () => ({
      accept: type,
      collect: (monitor) => {
        const { index: dragIndex } = monitor.getItem() || ({} as any);
        if (dragIndex === index) {
          return {};
        }
        return {
          isOver: monitor.isOver(),
          dropClassName:
            dragIndex < index ? ' drop-over-downward' : ' drop-over-upward',
        };
      },
      drop: (item: any) => {
        moveRow(item.index, index);
      },
    }),
    [index],
  );
  const [, drag, preview] = useDrag(
    () => ({
      type,
      item: { index },
      collect: (monitor) => ({
        isDragging: monitor.isDragging(),
      }),
    }),
    [index],
  );
  drop(drag(ref));

  return (
    <tr
      ref={ref}
      className={`${className}${isOver ? dropClassName : ''}`}
      style={{ cursor: 'move', ...style }}
      {...restProps}
    >
      {restProps.children}
    </tr>
  );
}
Example #17
Source File: ContextItem.tsx    From next-basics with GNU General Public License v3.0 5 votes vote down vote up
export function ContextItem({
  index,
  data,
  canDrag,
  highlighted,
  handleDropItem,
  handleItemClick,
  handleItemDelete,
  handleItemHover,
}: ContextItemProps): React.ReactElement {
  const ref = useRef();
  const [{ isOver, dropClassName }, drop] = useDrop({
    accept: type,
    collect: (monitor) => {
      const { index: dragIndex } = monitor.getItem() || {};
      if (dragIndex === index) {
        return {};
      }
      return {
        isOver: monitor.isOver(),
        dropClassName:
          dragIndex < index
            ? `${styles.dropOverDownward}`
            : `${styles.dropOverUpward}`,
      };
    },
    drop: (item: any) => {
      handleDropItem(item.index, index);
    },
  });
  const [{ isDragging }, drag] = useDrag({
    item: { type, index },
    canDrag,
    collect: (monitor) => ({
      isDragging: monitor.isDragging(),
    }),
  });
  drop(drag(ref));

  const handleMouseEnter = (): void => {
    handleItemHover(data.name);
  };

  const handleMouseLeave = (): void => {
    handleItemHover();
  };

  return (
    <div
      ref={ref}
      className={classNames(styles.varItem, {
        [dropClassName]: isOver,
        [styles.highlighted]: highlighted,
      })}
      onClick={handleItemClick}
      key={data.name}
      onMouseEnter={handleMouseEnter}
      onMouseLeave={handleMouseLeave}
    >
      {data.resolve ? (
        <LinkOutlined style={{ color: "var(--theme-orange-color)" }} />
      ) : (
        <CodeOutlined style={{ color: "var(--theme-green-color)" }} />
      )}
      <span className={styles.varName}>{data.name}</span>
      <Button
        type="link"
        danger
        icon={<DeleteOutlined />}
        className={styles.deleteIcon}
        onClick={handleItemDelete}
      />
    </div>
  );
}
Example #18
Source File: fileitem.tsx    From utopia with MIT License 5 votes vote down vote up
export function FileBrowserItem(props: FileBrowserItemProps) {
  const [{ isDragging }, drag, dragPreview] = useDrag(
    () => ({
      type: 'files',
      canDrag: () => canDragnDrop(props),
      collect: (monitor) => ({
        isDragging: monitor.isDragging(),
      }),
      item: () => {
        props.dispatch([
          EditorActions.switchEditorMode(
            EditorModes.insertMode(false, dragAndDropInsertionSubject([props.path])),
          ),
        ])
        return props
      },
    }),
    [props],
  )
  const [{ isOver }, drop] = useDrop(
    {
      accept: 'files',
      canDrop: () => true,
      drop: (item, monitor) => {
        onDrop(props, item)
      },
      hover: (item: FileBrowserItemProps) => {
        const targetDirectory =
          props.fileType === 'DIRECTORY' ? props.path : getParentDirectory(props.path)
        // do not trigger highlight when it tries to move to it's descendant directories
        if (targetDirectory.includes(item.path)) {
          if (props.dropTarget != null) {
            props.dispatch([EditorActions.setFilebrowserDropTarget(null)], 'leftpane')
          }
        } else {
          if (props.dropTarget !== targetDirectory) {
            props.dispatch([EditorActions.setFilebrowserDropTarget(targetDirectory)], 'leftpane')
          }
        }
      },
      collect: (monitor) => ({
        isOver: monitor.isOver(),
      }),
    },
    [props],
  )

  const forwardedRef = (node: ConnectableElement) => drag(drop(node))

  return (
    <FileBrowserItemInner
      {...props}
      isDragging={isDragging}
      isOver={isOver}
      connectDragPreview={dragPreview}
      // eslint-disable-next-line react/jsx-no-bind
      forwardedRef={forwardedRef}
    />
  )
}
Example #19
Source File: ElementListItemDraggable.tsx    From openchakra with MIT License 5 votes vote down vote up
ElementListItemDraggable: React.FC<Props> = ({
  type,
  id,
  onSelect,
  moveItem,
  index,
  onHover,
  onUnhover,
  name,
}) => {
  const ref = useRef<HTMLDivElement>(null)
  const [, drop] = useDrop({
    accept: ITEM_TYPE,
    hover(item: DragObjectWithType, monitor) {
      if (!ref.current) {
        return
      }
      // @ts-ignore
      const dragIndex = item.index
      const hoverIndex = index
      if (dragIndex === hoverIndex) {
        return
      }
      const hoverBoundingRect = ref.current.getBoundingClientRect()
      const hoverMiddleY =
        (hoverBoundingRect.bottom - hoverBoundingRect.top) / 2
      const clientOffset = monitor.getClientOffset()
      const hoverClientY = (clientOffset as XYCoord).y - hoverBoundingRect.top
      if (dragIndex < hoverIndex && hoverClientY < hoverMiddleY) {
        return
      }
      if (dragIndex > hoverIndex && hoverClientY > hoverMiddleY) {
        return
      }
      if (moveItem) {
        moveItem(dragIndex, hoverIndex)
      }
      // @ts-ignore
      item.index = hoverIndex
    },
  })
  const [{ isDragging }, drag] = useDrag({
    item: { type: ITEM_TYPE, id, index },
    collect: monitor => ({
      isDragging: monitor.isDragging(),
    }),
  })

  const opacity = isDragging ? 0 : 1

  drag(drop(ref))

  const onSelectElement = () => {
    onSelect(id)
  }

  const onMouseOver = () => {
    onHover(id)
  }

  return (
    <ElementListItem
      ref={ref}
      onSelect={onSelectElement}
      opacity={opacity}
      onMouseOver={onMouseOver}
      onMouseOut={onUnhover}
      type={type}
      draggable
      name={name}
    />
  )
}
Example #20
Source File: BrickTable.tsx    From next-basics with GNU General Public License v3.0 5 votes vote down vote up
DraggableBodyRow = ({
  index,
  moveRow,
  className,
  style,
  ...restProps
}) => {
  const ref = React.useRef();
  const [{ isOver, dropClassName }, drop] = useDrop({
    accept: type,
    collect: (monitor) => {
      const { index: dragIndex } = monitor.getItem() || {};
      if (dragIndex === index) {
        return {};
      }
      return {
        isOver: monitor.isOver(),
        dropClassName:
          dragIndex < index
            ? `${styles.dropOverDownward}`
            : `${styles.dropOverUpward}`,
      };
    },
    drop: (item: any) => {
      moveRow(item.index, index);
    },
  });
  const [, drag] = useDrag({
    item: { type, index },
    collect: (monitor) => ({
      isDragging: monitor.isDragging(),
    }),
  });
  drop(drag(ref));
  return (
    <tr
      ref={ref}
      className={classNames(className, styles.draggableRow, {
        [dropClassName]: isOver,
      })}
      style={{ cursor: "move", ...style }}
      {...restProps}
    />
  );
}
Example #21
Source File: use-hooks.tsx    From erda-ui with GNU Affero General Public License v3.0 5 votes vote down vote up
useListDnD = ({ type, index, onMove, collect }: IDragProps) => {
  const dragRef = useRef<HTMLDivElement>(null);

  const [, drop] = useDrop({
    accept: type,
    hover(item: DragItem, monitor: DropTargetMonitor) {
      if (!dragRef.current) {
        return;
      }
      const dragIndex = item.index;
      const hoverIndex = index;

      // Don't replace items with themselves
      if (dragIndex === hoverIndex) {
        return;
      }

      // Determine rectangle on screen
      const hoverBoundingRect = dragRef.current!.getBoundingClientRect();

      // Get vertical middle
      const hoverMiddleY = (hoverBoundingRect.bottom - hoverBoundingRect.top) / 2;

      // Determine mouse position
      const clientOffset = monitor.getClientOffset();

      // Get pixels to the top
      const hoverClientY = (clientOffset as XYCoord).y - hoverBoundingRect.top;

      // Only perform the move when the mouse has crossed half of the items height
      // When dragging downwards, only move when the cursor is below 50%
      // When dragging upwards, only move when the cursor is above 50%

      // Dragging downwards
      if (dragIndex < hoverIndex && hoverClientY < hoverMiddleY) {
        return;
      }

      // Dragging upwards
      if (dragIndex > hoverIndex && hoverClientY > hoverMiddleY) {
        return;
      }

      // Time to actually perform the action
      onMove(dragIndex, hoverIndex);

      // Note: we're mutating the monitor item here!
      // Generally it's better to avoid mutations,
      // but it's good here for the sake of performance
      // to avoid expensive index searches.
      item.index = hoverIndex;
    },
  });

  const [collectedProps, drag, previewRef] = useDrag({
    item: { index, type },
    collect,
  });

  drag(drop(dragRef));

  return [dragRef, previewRef, collectedProps];
}
Example #22
Source File: DragSortEditTable.tsx    From datart with Apache License 2.0 5 votes vote down vote up
DraggableAndEditableBodyRow = ({
  index,
  moveRow,
  className,
  style,
  ...restProps
}) => {
  const [form] = Form.useForm();
  const ref = useRef(null);
  const [{ isOver, dropClassName }, drop] = useDrop({
    accept: type,
    collect: monitor => {
      const { index: dragIndex } = monitor.getItem<{ index: number }>() || {};
      if (dragIndex === index) {
        return {};
      }
      return {
        isOver: monitor.isOver(),
        dropClassName:
          dragIndex < index ? ' drop-over-downward' : ' drop-over-upward',
      };
    },
    drop: (item: { index: number }) => {
      moveRow(item.index, index);
    },
  });
  const [, drag] = useDrag({
    type,
    item: { index },
    collect: monitor => ({
      isDragging: monitor.isDragging(),
    }),
  });
  drop(drag(ref));

  return (
    <Form form={form} component={false}>
      <EditableContext.Provider value={form}>
        <tr
          ref={ref}
          className={`${className}${isOver ? dropClassName : ''}`}
          style={{ cursor: 'move', ...style }}
          {...restProps}
        />
      </EditableContext.Provider>
    </Form>
  );
}
Example #23
Source File: OperationSetImplementationEditor.tsx    From legend-studio with Apache License 2.0 4 votes vote down vote up
OperationSetImplementationEditor = observer(
  (props: {
    setImplementation: OperationSetImplementation;
    isReadOnly: boolean;
  }) => {
    const { setImplementation, isReadOnly } = props;
    const editorStore = useEditorStore();
    const mappingEditorState =
      editorStore.getCurrentEditorState(MappingEditorState);
    const mapping = mappingEditorState.mapping;
    // Parameters
    const setImplementationOptions = getClassMappingsByClass(
      mapping,
      setImplementation.class.value,
    )
      .filter(
        (si) =>
          // filter out the current set impl
          si.id.value !== setImplementation.id.value &&
          // filter out set impls already included through a container or the actual container itself
          !getAllChildSetImplementations(setImplementation).includes(si),
      )
      .map((si) => ({ value: si, label: si.id.value }));
    const filterOption = createFilter({
      stringify: (option: SetImplementationOption): string => option.label,
    });
    const addParameter = (): void =>
      operationMapping_addParameter(
        setImplementation,
        new SetImplementationContainer(
          SetImplementationExplicitReference.create(
            new OperationSetImplementation(
              InferableMappingElementIdExplicitValue.create('', ''),
              new Mapping(''),
              PackageableElementExplicitReference.create(new Class('')),
              InferableMappingElementRootExplicitValue.create(false),
              OperationType.STORE_UNION,
            ),
          ),
        ),
      );
    const deleteParameter =
      (val: SetImplementationContainer): (() => void) =>
      (): void =>
        operationMapping_deleteParameter(setImplementation, val);
    const changeParamater =
      (
        val: SetImplementationContainer,
      ): ((option: SetImplementationOption | null) => void) =>
      (option: SetImplementationOption | null): void => {
        const setImpl = option?.value;
        if (setImpl) {
          operationMapping_changeParameter(
            setImplementation,
            val,
            new SetImplementationContainer(
              SetImplementationExplicitReference.create(setImpl),
            ),
          );
        }
      };
    // Drag and Drop
    const handleDrop = useCallback(
      (item: OperationSetImplementationDropTarget): void => {
        const mappingElement = item.data;
        if (
          mappingElement instanceof SetImplementation &&
          setImplementation.operation !== OperationType.INHERITANCE &&
          mappingElement.class.value === setImplementation.class.value &&
          !setImplementation.parameters.find(
            (param) => param.setImplementation.value === mappingElement,
          ) &&
          mappingElement !== setImplementation
        ) {
          operationMapping_addParameter(
            setImplementation,
            new SetImplementationContainer(
              SetImplementationExplicitReference.create(mappingElement),
            ),
          );
        }
      },
      [setImplementation],
    );
    const [{ isDragOver }, dropRef] = useDrop(
      () => ({
        accept: CORE_DND_TYPE.MAPPING_EXPLORER_CLASS_MAPPING,
        drop: (item: MappingElementDragSource): void => handleDrop(item),
        collect: (monitor): { isDragOver: boolean } => ({
          isDragOver: monitor.isOver({ shallow: true }),
        }),
      }),
      [handleDrop],
    );
    // actions
    const visit =
      (param: SetImplementationContainer): (() => void) =>
      (): void => {
        const parent = param.setImplementation.value._PARENT;
        // TODO: think more about this flow. Right now we open the mapping element in the parent mapping
        if (parent !== mappingEditorState.element) {
          editorStore.openElement(parent);
          editorStore
            .getCurrentEditorState(MappingEditorState)
            .openMappingElement(param.setImplementation.value, false);
        } else {
          mappingEditorState.openMappingElement(
            param.setImplementation.value,
            true,
          );
        }
      };

    useEffect(() => {
      if (!isReadOnly) {
        setImplementation.accept_SetImplementationVisitor(
          new MappingElementDecorator(editorStore),
        );
      }
      return isReadOnly
        ? noop()
        : (): void =>
            setImplementation.accept_SetImplementationVisitor(
              new MappingElementDecorationCleaner(editorStore),
            );
    }, [setImplementation, isReadOnly, editorStore]);

    return (
      <div className="mapping-element-editor__content">
        <div className="panel">
          <div className="panel__header">
            <div className="panel__header__title">
              <div className="panel__header__title__content">PARAMETERS</div>
            </div>
            <div className="panel__header__actions">
              <button
                className="panel__header__action"
                disabled={
                  isReadOnly ||
                  setImplementation.operation === OperationType.INHERITANCE
                }
                onClick={addParameter}
                tabIndex={-1}
                title={'Add parameter'}
              >
                <PlusIcon />
              </button>
            </div>
          </div>
          <div
            ref={dropRef}
            className={clsx('panel__content', {
              'operation-mapping-editor__parameters--dnd-over':
                isDragOver && !isReadOnly,
            })}
          >
            {setImplementation.parameters.map((param) => (
              <div
                key={param._UUID}
                className="operation-mapping-editor__parameter"
              >
                <div className="operation-mapping-editor__parameter__selector">
                  <CustomSelectorInput
                    options={setImplementationOptions}
                    disabled={isReadOnly}
                    onChange={changeParamater(param)}
                    filterOption={filterOption}
                    value={{
                      value: param,
                      label: param.setImplementation.value.id.value,
                    }}
                    placeholder={`Select parameter ID`}
                  />
                </div>
                <button
                  className="operation-mapping-editor__parameter__visit-btn"
                  onClick={visit(param)}
                  tabIndex={-1}
                  title={'Visit mapping element'}
                >
                  <ArrowCircleRightIcon />
                </button>
                {!isReadOnly && (
                  <button
                    className="operation-mapping-editor__parameter__remove-btn"
                    disabled={isReadOnly}
                    onClick={deleteParameter(param)}
                    tabIndex={-1}
                    title={'Remove'}
                  >
                    <TimesIcon />
                  </button>
                )}
              </div>
            ))}
          </div>
        </div>
      </div>
    );
  },
)
Example #24
Source File: ThumbnailItem.tsx    From datart with Apache License 2.0 4 votes vote down vote up
ThumbnailItem: React.FC<IProps> = ({
  page,
  index,
  selected,
  moveCard,
  moveEnd,
}) => {
  const dispatch = useDispatch();
  const ItemRef = useRef<HTMLDivElement>(null);
  const dashboard = useSelector((state: { board: BoardState }) =>
    makeSelectBoardConfigById()(state, page.relId),
  );
  useEffect(() => {
    try {
      const { thumbnail, name } = dashboard as Dashboard;
      dispatch(
        storyActions.updateStoryPageNameAndThumbnail({
          storyId: page.storyId,
          pageId: page.id,
          name,
          thumbnail,
        }),
      );
    } catch (error) {}
    // storyActions.updateStoryPageNameAndThumbnail
  }, [dashboard, dispatch, page.id, page.storyId]);
  const [{ handlerId }, drop] = useDrop({
    accept: 'storyBoardListDnd',
    collect(monitor) {
      return {
        handlerId: monitor.getHandlerId(),
      };
    },
    hover(item: DragItem, monitor: DropTargetMonitor) {
      if (!ItemRef.current) {
        return;
      }
      const dragIndex = item.index;
      const hoverIndex = page.index;
      const hoverSelected = item.selected;
      // const dragId = item.id;
      // Don't replace items with themselves
      if (dragIndex === hoverIndex) {
        return;
      }

      // Determine rectangle on screen
      const hoverBoundingRect = ItemRef.current?.getBoundingClientRect();

      // Get vertical middle
      const hoverMiddleY =
        (hoverBoundingRect.bottom - hoverBoundingRect.top) / 2;

      // Determine mouse position
      const clientOffset = monitor.getClientOffset();

      // Get pixels to the top
      const hoverClientY = (clientOffset as XYCoord).y - hoverBoundingRect.top;

      // Only perform the move when the mouse has crossed half of the items height
      // When dragging downwards, only move when the cursor is below 50%
      // When dragging upwards, only move when the cursor is above 50%

      // Dragging downwards
      if (dragIndex < hoverIndex && hoverClientY < hoverMiddleY) {
        return;
      }

      // Dragging upwards
      if (dragIndex > hoverIndex && hoverClientY > hoverMiddleY) {
        return;
      }

      // Time to actually perform the action
      moveCard(item.id, page.id);

      // Note: we're mutating the monitor item here!
      // Generally it's better to avoid mutations,
      // but it's good here for the sake of performance
      // to avoid expensive index searches.
      item.index = hoverIndex;
      item.selected = hoverSelected;
    },
  });

  const [{ isDragging }, drag] = useDrag({
    type: 'storyBoardListDnd',
    item: () => {
      return {
        id: page.id,
        index: page.index,
        selected: selected,
      };
    },
    collect: (monitor: any) => ({
      isDragging: monitor.isDragging(),
    }),
    end() {
      moveEnd();
    },
  });
  const opacity = isDragging ? 0.1 : 1;
  // 使用 drag 和 drop 包装 ref
  drag(drop(ItemRef));

  return (
    <ItemWrap selected={selected}>
      <div
        className="item"
        ref={ItemRef}
        data-handler-id={handlerId}
        style={{ opacity }}
      >
        <p>{index}</p>
        <h4>{page.name}</h4>
      </div>
    </ItemWrap>
  );
}
Example #25
Source File: MappingTestEditor.tsx    From legend-studio with Apache License 2.0 4 votes vote down vote up
MappingTestQueryEditor = observer(
  (props: { testState: MappingTestState; isReadOnly: boolean }) => {
    const { testState, isReadOnly } = props;
    const queryState = testState.queryState;
    const editorStore = useEditorStore();
    const applicationStore = useApplicationStore();

    const extraQueryEditorActions = editorStore.pluginManager
      .getStudioPlugins()
      .flatMap(
        (plugin) =>
          (
            plugin as DSLMapping_LegendStudioPlugin_Extension
          ).getExtraMappingTestQueryEditorActionConfigurations?.() ?? [],
      )
      .map((config) => (
        <Fragment key={config.key}>
          {config.renderer(testState, isReadOnly)}
        </Fragment>
      ));

    // Class mapping selector
    const [openClassMappingSelectorModal, setOpenClassMappingSelectorModal] =
      useState(false);
    const showClassMappingSelectorModal = (): void =>
      setOpenClassMappingSelectorModal(true);
    const hideClassMappingSelectorModal = (): void =>
      setOpenClassMappingSelectorModal(false);
    const changeClassMapping = useCallback(
      (setImplementation: SetImplementation | undefined): void => {
        // do all the necessary updates
        flowResult(
          queryState.updateLamba(
            setImplementation
              ? editorStore.graphManagerState.graphManager.HACKY__createGetAllLambda(
                  guaranteeType(
                    getMappingElementTarget(setImplementation),
                    Class,
                  ),
                )
              : stub_RawLambda(),
          ),
        ).catch(applicationStore.alertUnhandledError);
        hideClassMappingSelectorModal();

        // Attempt to generate data for input data panel as we pick the class mapping
        if (setImplementation) {
          editorStore.setActionAlertInfo({
            message: 'Mapping test input data is already set',
            prompt: 'Do you want to regenerate the input data?',
            type: ActionAlertType.CAUTION,
            onEnter: (): void => editorStore.setBlockGlobalHotkeys(true),
            onClose: (): void => editorStore.setBlockGlobalHotkeys(false),
            actions: [
              {
                label: 'Regenerate',
                type: ActionAlertActionType.PROCEED_WITH_CAUTION,
                handler: (): void =>
                  testState.setInputDataStateBasedOnSource(
                    getMappingElementSource(
                      setImplementation,
                      editorStore.pluginManager.getStudioPlugins(),
                    ),
                    true,
                  ),
              },
              {
                label: 'Keep my input data',
                type: ActionAlertActionType.PROCEED,
                default: true,
              },
            ],
          });
        }
      },
      [applicationStore, editorStore, testState, queryState],
    );

    // Drag and Drop
    const handleDrop = useCallback(
      (item: MappingElementDragSource): void => {
        changeClassMapping(guaranteeType(item.data, SetImplementation));
      },
      [changeClassMapping],
    );
    const [{ isDragOver, canDrop }, dropRef] = useDrop(
      () => ({
        accept: CORE_DND_TYPE.MAPPING_EXPLORER_CLASS_MAPPING,
        drop: (item: MappingElementDragSource): void => handleDrop(item),
        collect: (monitor): { isDragOver: boolean; canDrop: boolean } => ({
          isDragOver: monitor.isOver({ shallow: true }),
          canDrop: monitor.canDrop(),
        }),
      }),
      [handleDrop],
    );

    const clearQuery = applicationStore.guardUnhandledError(() =>
      flowResult(testState.queryState.updateLamba(stub_RawLambda())),
    );

    return (
      <div className="panel mapping-test-editor__query-panel">
        <div className="panel__header">
          <div className="panel__header__title">
            <div className="panel__header__title__label">query</div>
          </div>
          <div className="panel__header__actions">
            {extraQueryEditorActions}
            <button
              className="panel__header__action"
              tabIndex={-1}
              disabled={isReadOnly}
              onClick={clearQuery}
              title={'Clear query'}
            >
              <TimesIcon />
            </button>
          </div>
        </div>
        {!isStubbed_RawLambda(queryState.query) && (
          <div className="panel__content">
            <div className="mapping-test-editor__query-panel__query">
              <StudioTextInputEditor
                inputValue={queryState.lambdaString}
                isReadOnly={true}
                language={EDITOR_LANGUAGE.PURE}
                showMiniMap={false}
              />
            </div>
          </div>
        )}
        {isStubbed_RawLambda(queryState.query) && (
          <div ref={dropRef} className="panel__content">
            <BlankPanelPlaceholder
              placeholderText="Choose a class mapping"
              onClick={showClassMappingSelectorModal}
              clickActionType="add"
              tooltipText="Drop a class mapping, or click to choose one to start building the query"
              dndProps={{
                isDragOver: isDragOver,
                canDrop: canDrop,
              }}
            />
          </div>
        )}
        {openClassMappingSelectorModal && (
          <ClassMappingSelectorModal
            mappingEditorState={testState.mappingEditorState}
            hideClassMappingSelectorModal={hideClassMappingSelectorModal}
            changeClassMapping={changeClassMapping}
          />
        )}
      </div>
    );
  },
)
Example #26
Source File: ColumnHeader.tsx    From firetable with Apache License 2.0 4 votes vote down vote up
export default function DraggableHeaderRenderer<R>({
  column,
}: HeaderRendererProps<R> & {
  onColumnsReorder: (sourceKey: string, targetKey: string) => void;
}) {
  const classes = useStyles();

  const {
    tableState,
    tableActions,
    userClaims,
    columnMenuRef,
  } = useFiretableContext();
  const [{ isDragging }, drag] = useDrag({
    item: { key: column.key, type: "COLUMN_DRAG" },
    collect: (monitor) => ({
      isDragging: !!monitor.isDragging(),
    }),
  });

  const [{ isOver }, drop] = useDrop({
    accept: "COLUMN_DRAG",
    drop({ key, type }: ColumnDragObject) {
      if (type === "COLUMN_DRAG") {
        // onColumnsReorder(key, props.column.key);
        tableActions?.column.reorder(key, column.key);
      }
    },
    collect: (monitor) => ({
      isOver: !!monitor.isOver(),
      canDrop: !!monitor.canDrop(),
    }),
  });

  const headerRef = useCombinedRefs(drag, drop);
  if (!columnMenuRef || !tableState || !tableActions) return null;
  const { orderBy } = tableState;

  const handleClick = (
    event: React.MouseEvent<HTMLButtonElement, MouseEvent>
  ) =>
    columnMenuRef?.current?.setSelectedColumnHeader({
      column,
      anchorEl: event.currentTarget,
    });

  const isSorted = orderBy?.[0]?.key === (column.key as string);
  const isAsc = isSorted && orderBy?.[0]?.direction === "asc";

  const handleSortClick = () => {
    if (isAsc) {
      const ordering: FiretableOrderBy = [
        { key: column.key as string, direction: "desc" },
      ];

      tableActions.table.orderBy(ordering);
    } else {
      const ordering: FiretableOrderBy = [
        { key: column.key as string, direction: "asc" },
      ];
      tableActions.table.orderBy(ordering);
    }
  };

  return (
    <Grid
      ref={headerRef}
      container
      className={clsx(
        classes.root,
        isDragging && classes.isDragging,
        isOver && !isDragging && classes.isOver
      )}
      alignItems="center"
      wrap="nowrap"
    >
      <Tooltip
        title={
          <>
            <Typography variant="subtitle2" component="p">
              {column.key as string}
            </Typography>
            <Typography variant="body2" component="p">
              <small>(Click to copy)</small>
            </Typography>
          </>
        }
        enterDelay={1000}
        placement="bottom-start"
      >
        <Grid
          item
          onClick={() => {
            navigator.clipboard.writeText(column.key as string);
          }}
        >
          {getFieldProp("icon", (column as any).type)}
        </Grid>
      </Tooltip>

      <Grid item xs className={classes.columnNameContainer}>
        <Tooltip
          title={<Typography variant="subtitle2">{column.name}</Typography>}
          enterDelay={1000}
          placement="bottom-start"
          PopperProps={{
            modifiers: {
              flip: { enabled: false },
              preventOverflow: {
                enabled: false,
                boundariesElement: "scrollParent",
              },
              hide: { enabled: false },
            },
          }}
          TransitionComponent={Fade}
          classes={{ tooltip: classes.columnNameTooltip }}
        >
          <Typography
            variant="subtitle2"
            noWrap
            className={classes.columnName}
            component="div"
            color="inherit"
          >
            {column.name}
          </Typography>
        </Tooltip>
      </Grid>

      {(column as any).type !== FieldType.id && (
        <Grid
          item
          className={clsx(
            classes.sortIconContainer,
            isSorted && classes.sortIconContainerSorted
          )}
        >
          <IconButton
            disableFocusRipple={true}
            size="small"
            onClick={handleSortClick}
            color="inherit"
            aria-label={`Sort by ${isAsc ? "descending" : "ascending"}`}
            className={clsx(classes.sortIcon, isAsc && classes.sortIconAsc)}
          >
            <SortDescIcon />
          </IconButton>
        </Grid>
      )}

      {(userClaims?.roles?.includes("ADMIN") ||
        (userClaims?.roles?.includes("OPS") &&
          [FieldType.multiSelect, FieldType.singleSelect].includes(
            (column as any).type
          ))) && (
        <Grid item>
          <IconButton
            size="small"
            className={classes.dropdownButton}
            aria-label={`Show ${column.name} column dropdown`}
            color="inherit"
            onClick={handleClick}
          >
            <DropdownIcon />
          </IconButton>
        </Grid>
      )}
    </Grid>
  );
  //   return (
  //     <div
  //       ref={useCombinedRefs(drag, drop)}
  //       style={{
  //         opacity: isDragging ? 0.5 : 1,
  //         backgroundColor: isOver ? '#ececec' : 'inherit',
  //         cursor: 'move'
  //       }}
  //     >
  //       {props.column.name}
  //     </div>
  //   );
}
Example #27
Source File: EnumerationEditor.tsx    From legend-studio with Apache License 2.0 4 votes vote down vote up
EnumEditor = observer(
  (props: { _enum: Enum; deselectValue: () => void; isReadOnly: boolean }) => {
    const { _enum, deselectValue, isReadOnly } = props;
    // Tab
    const [selectedTab, setSelectedTab] = useState<UML_EDITOR_TAB>(
      UML_EDITOR_TAB.TAGGED_VALUES,
    );
    const tabs = [UML_EDITOR_TAB.TAGGED_VALUES, UML_EDITOR_TAB.STEREOTYPES];
    const changeTab =
      (tab: UML_EDITOR_TAB): (() => void) =>
      (): void =>
        setSelectedTab(tab);
    // Tagged value and Stereotype
    let addButtonTitle = '';
    switch (selectedTab) {
      case UML_EDITOR_TAB.TAGGED_VALUES:
        addButtonTitle = 'Add tagged value';
        break;
      case UML_EDITOR_TAB.STEREOTYPES:
        addButtonTitle = 'Add stereotype';
        break;
      default:
        break;
    }
    const addValue = (): void => {
      if (!isReadOnly) {
        if (selectedTab === UML_EDITOR_TAB.TAGGED_VALUES) {
          annotatedElement_addTaggedValue(
            _enum,
            stub_TaggedValue(stub_Tag(stub_Profile())),
          );
        } else if (selectedTab === UML_EDITOR_TAB.STEREOTYPES) {
          annotatedElement_addStereotype(
            _enum,
            StereotypeExplicitReference.create(stub_Stereotype(stub_Profile())),
          );
        }
      }
    };
    const _deleteStereotype =
      (val: StereotypeReference): (() => void) =>
      (): void =>
        annotatedElement_deleteStereotype(_enum, val);
    const _deleteTaggedValue =
      (val: TaggedValue): (() => void) =>
      (): void =>
        annotatedElement_deleteTaggedValue(_enum, val);
    // Drag and Drop
    const handleDropTaggedValue = useCallback(
      (item: UMLEditorElementDropTarget): void => {
        if (!isReadOnly && item.data.packageableElement instanceof Profile) {
          annotatedElement_addTaggedValue(
            _enum,
            stub_TaggedValue(stub_Tag(item.data.packageableElement)),
          );
        }
      },
      [_enum, isReadOnly],
    );
    const [{ isTaggedValueDragOver }, dropTaggedValueRef] = useDrop(
      () => ({
        accept: [CORE_DND_TYPE.PROJECT_EXPLORER_PROFILE],
        drop: (item: ElementDragSource): void => handleDropTaggedValue(item),
        collect: (monitor): { isTaggedValueDragOver: boolean } => ({
          isTaggedValueDragOver: monitor.isOver({ shallow: true }),
        }),
      }),
      [handleDropTaggedValue],
    );
    const handleDropStereotype = useCallback(
      (item: UMLEditorElementDropTarget): void => {
        if (!isReadOnly && item.data.packageableElement instanceof Profile) {
          annotatedElement_addStereotype(
            _enum,
            StereotypeExplicitReference.create(
              stub_Stereotype(item.data.packageableElement),
            ),
          );
        }
      },
      [_enum, isReadOnly],
    );
    const [{ isStereotypeDragOver }, dropStereotypeRef] = useDrop(
      () => ({
        accept: [CORE_DND_TYPE.PROJECT_EXPLORER_PROFILE],
        drop: (item: ElementDragSource): void => handleDropStereotype(item),
        collect: (monitor): { isStereotypeDragOver: boolean } => ({
          isStereotypeDragOver: monitor.isOver({ shallow: true }),
        }),
      }),
      [handleDropStereotype],
    );

    return (
      <div className="uml-element-editor enum-editor">
        <div data-testid={LEGEND_STUDIO_TEST_ID.PANEL} className="panel">
          <div className="panel__header">
            <div className="panel__header__title">
              {isReadOnly && (
                <div className="uml-element-editor__header__lock">
                  <LockIcon />
                </div>
              )}
              <div className="panel__header__title__label">enum</div>
              <div className="panel__header__title__content">{_enum.name}</div>
            </div>
            <div className="panel__header__actions">
              <button
                className="panel__header__action"
                onClick={deselectValue}
                tabIndex={-1}
                title={'Close'}
              >
                <TimesIcon />
              </button>
            </div>
          </div>
          <div
            data-testid={LEGEND_STUDIO_TEST_ID.UML_ELEMENT_EDITOR__TABS_HEADER}
            className="panel__header uml-element-editor__tabs__header"
          >
            <div className="uml-element-editor__tabs">
              {tabs.map((tab) => (
                <div
                  key={tab}
                  onClick={changeTab(tab)}
                  className={clsx('uml-element-editor__tab', {
                    'uml-element-editor__tab--active': tab === selectedTab,
                  })}
                >
                  {prettyCONSTName(tab)}
                </div>
              ))}
            </div>
            <div className="panel__header__actions">
              <button
                className="panel__header__action"
                disabled={isReadOnly}
                onClick={addValue}
                tabIndex={-1}
                title={addButtonTitle}
              >
                <PlusIcon />
              </button>
            </div>
          </div>
          <div className="panel__content">
            {selectedTab === UML_EDITOR_TAB.TAGGED_VALUES && (
              <div
                ref={dropTaggedValueRef}
                className={clsx('panel__content__lists', {
                  'panel__content__lists--dnd-over':
                    isTaggedValueDragOver && !isReadOnly,
                })}
              >
                {_enum.taggedValues.map((taggedValue) => (
                  <TaggedValueEditor
                    key={taggedValue._UUID}
                    taggedValue={taggedValue}
                    deleteValue={_deleteTaggedValue(taggedValue)}
                    isReadOnly={isReadOnly}
                  />
                ))}
              </div>
            )}
            {selectedTab === UML_EDITOR_TAB.STEREOTYPES && (
              <div
                ref={dropStereotypeRef}
                className={clsx('panel__content__lists', {
                  'panel__content__lists--dnd-over':
                    isStereotypeDragOver && !isReadOnly,
                })}
              >
                {_enum.stereotypes.map((stereotype) => (
                  <StereotypeSelector
                    key={stereotype.value._UUID}
                    stereotype={stereotype}
                    deleteStereotype={_deleteStereotype(stereotype)}
                    isReadOnly={isReadOnly}
                  />
                ))}
              </div>
            )}
          </div>
        </div>
      </div>
    );
  },
)
Example #28
Source File: DropTarget.tsx    From gear-js with GNU General Public License v3.0 4 votes vote down vote up
DropTarget = ({ type, setDroppedFile }: Props) => {
  const alert = useAlert();

  const [wrongFormat, setWrongFormat] = useState(false);
  const inputRef = useRef<HTMLInputElement>(null);

  if (wrongFormat) {
    setTimeout(() => setWrongFormat(false), 3000);
  }

  const checkFileFormat = useCallback((files: any) => {
    if (typeof files[0]?.name === 'string') {
      const fileExt: string = files[0].name.split('.').pop().toLowerCase();
      return fileExt !== 'wasm';
    }
    return true;
  }, []);

  const handleFilesUpload = useCallback(
    (file: File) => {
      setDroppedFile({ file, type });
    },
    [setDroppedFile, type]
  );

  const emulateInputClick = () => {
    inputRef.current?.click();
  };

  const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {
    const {
      target: { files },
    } = event;
    if (files?.length) {
      const isCorrectFormat = checkFileFormat(files);
      setWrongFormat(isCorrectFormat);
      if (!isCorrectFormat) {
        handleFilesUpload(files[0]);
        // since type='file' input can't be controlled,
        // reset it's value to trigger onChange again in case the same file selected twice
        event.target.value = '';
      } else {
        alert.error('Wrong file format');
        setWrongFormat(false);
      }
    }
  };

  const handleFileDrop = useCallback(
    (item) => {
      if (item) {
        const { files } = item;
        const isCorrectFormat = checkFileFormat(files);
        setWrongFormat(isCorrectFormat);
        if (!isCorrectFormat) {
          handleFilesUpload(files[0]);
        } else {
          alert.error('Wrong file format');
          setWrongFormat(false);
        }
      }
    },
    // eslint-disable-next-line react-hooks/exhaustive-deps
    [checkFileFormat, handleFilesUpload]
  );

  const [{ canDrop, isOver }, drop] = useDrop(
    () => ({
      accept: [NativeTypes.FILE],
      drop(item: { files: any[] }) {
        if (handleFileDrop) {
          handleFileDrop(item);
        }
      },
      collect: (monitor: DropTargetMonitor) => ({
        isOver: monitor.isOver(),
        canDrop: monitor.canDrop(),
      }),
    }),
    [handleFileDrop]
  );

  const isActive = canDrop && isOver;
  const className = clsx(styles.drop, isActive && styles.active);
  const isProgramUpload = type === UploadTypes.PROGRAM;
  const buttonText = `Upload ${type}`;

  return (
    <div className={className} ref={drop}>
      {isActive ? (
        <div className={styles.file}>
          <span className={styles.text}>Drop your .wasm files here to upload</span>
        </div>
      ) : (
        <div className={styles.noFile}>
          <input className={styles.input} ref={inputRef} type="file" onChange={handleChange} />
          <Button
            text={buttonText}
            icon={isProgramUpload ? upload : editor}
            color={isProgramUpload ? 'primary' : 'secondary'}
            onClick={emulateInputClick}
          />
          <div className={styles.text}>{`Click “${buttonText}” to browse or drag and drop your .wasm files here`}</div>
        </div>
      )}
    </div>
  );
}
Example #29
Source File: NameItem.tsx    From datart with Apache License 2.0 4 votes vote down vote up
NameItem: React.FC<NameItemProps> = ({
  index,
  card,
  zIndex,
  moveCard,
  moveEnd,
  widgetType,
}) => {
  const widget = useContext(WidgetContext);
  const ItemRef = useRef<HTMLDivElement>(null);
  const [{ handlerId }, drop] = useDrop({
    accept: 'WidgetNameListDnd',
    collect(monitor) {
      return {
        handlerId: monitor.getHandlerId(),
      };
    },
    hover(item: DragItem, monitor: DropTargetMonitor) {
      if (!ItemRef.current) {
        return;
      }
      const dragIndex = item.index;
      const hoverIndex = index;

      const dragZIndex = item.zIndex;
      const hoverZIndex = card.index;
      const hoverSelected = card.selected;
      // Don't replace items with themselves
      if (dragIndex === hoverIndex) {
        return;
      }

      // Determine rectangle on screen
      const hoverBoundingRect = ItemRef.current?.getBoundingClientRect();

      // Get vertical middle
      const hoverMiddleY =
        (hoverBoundingRect.bottom - hoverBoundingRect.top) / 2;

      // Determine mouse position
      const clientOffset = monitor.getClientOffset();

      // Get pixels to the top
      const hoverClientY = (clientOffset as XYCoord).y - hoverBoundingRect.top;

      // Only perform the move when the mouse has crossed half of the items height
      // When dragging downwards, only move when the cursor is below 50%
      // When dragging upwards, only move when the cursor is above 50%

      // Dragging downwards
      if (dragIndex < hoverIndex && hoverClientY < hoverMiddleY) {
        return;
      }

      // Dragging upwards
      if (dragIndex > hoverIndex && hoverClientY > hoverMiddleY) {
        return;
      }

      // Time to actually perform the action
      moveCard(dragIndex, hoverIndex, dragZIndex, hoverZIndex);

      // Note: we're mutating the monitor item here!
      // Generally it's better to avoid mutations,
      // but it's good here for the sake of performance
      // to avoid expensive index searches.
      item.index = hoverIndex;
      item.zIndex = hoverZIndex;
      item.selected = hoverSelected;
    },
  });

  const [{ isDragging }, drag] = useDrag({
    type: 'WidgetNameListDnd',
    item: () => {
      return { id: card.id, index, zIndex, selected: card.selected };
    },
    collect: (monitor: any) => ({
      isDragging: monitor.isDragging(),
    }),
    end() {
      moveEnd();
    },
  });
  const opacity = isDragging ? 0.1 : 1;
  // 使用 drag 和 drop 包装 ref
  drag(drop(ItemRef));
  const dispatch = useDispatch();
  const selectWidget = useCallback(
    (e: React.MouseEvent<HTMLDivElement>) => {
      e.stopPropagation();
      let newSelected = !card.selected;
      if (card.selected) {
        newSelected = card.selected;
      }

      dispatch(
        editWidgetInfoActions.selectWidget({
          multipleKey: e.shiftKey,
          id: card.id,
          selected: newSelected,
        }),
      );
    },
    [card, dispatch],
  );

  return (
    <ItemWrap
      selected={card.selected}
      onMouseDown={selectWidget}
      onClick={e => e.stopPropagation()}
    >
      <div
        className={classNames('name-item', {
          'selected-Item': card.selected,
        })}
        ref={ItemRef}
        data-handler-id={handlerId}
        style={{ opacity }}
      >
        <span className="name" title={card.name || 'untitled-widget'}>
          {card.name || 'untitled-widget'}
        </span>

        <WidgetActionDropdown widget={widget} />
      </div>
    </ItemWrap>
  );
}