react-dnd#useDrag TypeScript Examples

The following examples show how to use react-dnd#useDrag. 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: Box.tsx    From jetlinks-ui-antd with MIT License 6 votes vote down vote up
Box: React.FC<BoxProps> = ({ name, type, isDropped }) => {
    const [{ opacity }, drag] = useDrag({
        item: { name, type },
        collect: monitor => ({
            opacity: monitor.isDragging() ? 0.4 : 1,
        }),
    })

    return (
        <div ref={drag} style={{ ...style, opacity }}>
            {isDropped ? <s>{name}</s> : name}
        </div>
    )
}
Example #2
Source File: index.tsx    From redux-with-domain with MIT License 6 votes vote down vote up
FieldItem: FC<Props> = props => {
  const { field } = props

  const [_, dragRef] = useDrag({
    item: { type: 'FIELD', id: field.id }
  })

  return (
    <div className="item" ref={dragRef}>
      <FieldIcon />
      <span>{field.name}</span>
    </div>
  )
}
Example #3
Source File: WorkoutCard.tsx    From calendar-hack with MIT License 6 votes vote down vote up
WorkoutCard: React.FC<WorkoutCardProps> = ({ dayDetails, date, units, swap }) => {

    const [{ isDragging }, drag, preview] = useDrag({
        item: { date: date, type: ItemTypes.DAY, dayDetails: dayDetails, units: units },
        collect: (monitor) => ({
            isDragging: monitor.isDragging(),
            canDrag: dayDetails !== undefined,
        }),
        end: (item: { date: Date } | undefined, monitor: DragSourceMonitor) => {
            const dropResult = monitor.getDropResult()
            if (item && dropResult) {
            }
        },
    })

    return (
        <Card>
            <Dateline dayDetails={dayDetails} units={units} date={date} />
            <DragSource isDragging={isDragging} dayDetails={dayDetails} ref={preview}>
                <Preview generator={generateDayPreview} />
                <Content>
                    <div ref={drag}>
                        <DragHandle viewBox="0 0 32 36" />
                    </div>
                    <p>{renderDesc(dayDetails, dayDetails.sourceUnits, units)}</p>
                </Content>
            </DragSource>
        </Card >
    );
}
Example #4
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 #5
Source File: DateLevelFieldContainer.tsx    From datart with Apache License 2.0 5 votes vote down vote up
function DateLevelFieldContainer({
  onClearCheckedList,
  item,
  colName,
}: {
  onClearCheckedList?: () => any;
  item: {
    category: string;
    expression: string;
    id: string;
    type: string;
  };
  colName: string;
}) {
  const t = useI18NPrefix(`viz.workbench.dataview`);
  const [, drag] = useDrag(
    () => ({
      type: CHART_DRAG_ELEMENT_TYPE.DATASET_COLUMN,
      canDrag: true,
      item: {
        colName: `${colName}`,
        type: item.type,
        category: item.category,
        expression: `${item.expression}`,
      },
      collect: monitor => ({
        isDragging: monitor.isDragging(),
      }),
      end: onClearCheckedList,
    }),
    [],
  );
  return (
    <ItemWrapper ref={drag}>
      <CalendarOutlined style={{ color: INFO }} />
      &nbsp;
      <span>
        {colName}({t(item.expression)})
      </span>
    </ItemWrapper>
  );
}
Example #6
Source File: TableOrViewSourceTree.tsx    From legend-studio with Apache License 2.0 5 votes vote down vote up
RelationalOperationElementTreeNodeContainer: React.FC<
  TreeNodeContainerProps<
    TableOrViewTreeNodeData,
    { selectedType?: Type | undefined }
  >
> = (props) => {
  const { node, level, stepPaddingInRem, onNodeSelect } = props;
  const [, dragRef] = useDrag(
    () => ({
      type: TABLE_ELEMENT_DND_TYPE,
      item: new TableOrViewTreeNodeDragSource(node),
    }),
    [node],
  );
  const isExpandable = Boolean(node.childrenIds?.length);
  const nodeTypeIcon =
    node instanceof ColumnNodeData ? (
      renderColumnTypeIcon(node.column.type)
    ) : (
      <PURE_DatabaseTableJoinIcon />
    );
  const selectNode = (): void => onNodeSelect?.(node);
  const nodeExpandIcon = isExpandable ? (
    node.isOpen ? (
      <ChevronDownIcon />
    ) : (
      <ChevronRightIcon />
    )
  ) : (
    <div />
  );

  return (
    <div
      className="tree-view__node__container"
      onClick={selectNode}
      ref={dragRef}
      style={{
        paddingLeft: `${(level - 1) * (stepPaddingInRem ?? 1)}rem`,
        display: 'flex',
      }}
    >
      <div className="tree-view__node__icon">
        <div className="type-tree__expand-icon">{nodeExpandIcon}</div>
        <div className="type-tree__type-icon">{nodeTypeIcon}</div>
      </div>
      <div className="tree-view__node__label type-tree__node__label">
        <button tabIndex={-1} title={`${node.id}`}>
          {node.label}
        </button>
        {node instanceof ColumnNodeData && (
          <div className="type-tree__node__type">
            <button
              className="type-tree__node__type__label"
              // TODO: match type
              // className={clsx('type-tree__node__type__label', {
              //   'type-tree__node__type__label--highlighted':
              //     primitiveType && primitiveType === selectedType,
              // })}
              tabIndex={-1}
              title={'Column Type'}
            >
              {generateColumnTypeLabel(guaranteeType(node.column, Column).type)}
            </button>
          </div>
        )}
      </div>
    </div>
  );
}
Example #7
Source File: index.tsx    From erda-ui with GNU Affero General Public License v3.0 5 votes vote down vote up
useDragAndDrop = ({ item, index, onBeginDrag, onEndDrag, onMove }: any) => {
  const { type, data } = item;
  const [position, setPosition] = React.useState('');

  const dragRef = React.useRef<HTMLDivElement>(null);
  const [{ isDragging }, drag, preview] = useDrag({
    item: { type, data, index },
    collect: (monitor) => ({
      isDragging: monitor.isDragging(),
    }),
    begin: () => {
      onBeginDrag && onBeginDrag({ item, index });
    },
    end: (_, monitor) => {
      const posMap = {
        top: -1,
        center: 0,
        bottom: 1,
      };
      const result = monitor.getDropResult();
      if (onEndDrag) {
        onEndDrag({
          sourceItem: data,
          targetItem: result?.data,
          position: result?.position && posMap[result.position],
          didDrop: monitor.didDrop(),
        });
      }
    },
  });

  const [{ isOver, area }, drop] = useDrop({
    accept: type,
    collect: (monitor) => {
      if (monitor.isOver({ shallow: true })) {
        // hover 的节点
        const hoverBoundingRect = dragRef.current!.getBoundingClientRect();
        // hover节点高度
        const { height } = hoverBoundingRect;
        // 获取 hover 到的区域分界线:上(25%) 中(50%) 下(25%)
        const Y_top = hoverBoundingRect.top;
        const Y_split1 = hoverBoundingRect.top + height * 0.25;
        const Y_split2 = hoverBoundingRect.top + height * 0.75;
        const Y_bottom = hoverBoundingRect.bottom;

        return {
          isOver: monitor.isOver({ shallow: true }),
          area: [Y_top, Y_split1, Y_split2, Y_bottom],
        };
      }
      return {
        isOver: false,
        area: [],
      };
    },
    hover(dragItem: SortItemData, monitor) {
      const coordinate = monitor.getClientOffset();
      if (coordinate) {
        const mouseY = coordinate.y;
        const pos = mouseY < area[1] ? 'top' : mouseY < area[2] ? 'center' : 'bottom';
        setPosition(pos);
      }
      // Don't replace items with themselves
      if (dragItem.data.id !== data.id) {
        onMove &&
          onMove({
            sourceItem: dragItem,
            targetItem: item,
            position: dragItem.index < index ? 1 : -1,
          });
      }
    },
    drop: () => {
      return { data: item.data, position };
    },
  });

  return { drag: drag(dragRef), preview, drop, position, isDragging, isOver };
}
Example #8
Source File: TypeTree.tsx    From legend-studio with Apache License 2.0 5 votes vote down vote up
TypeTreeNodeContainer: React.FC<
  TreeNodeContainerProps<TypeTreeNodeData, { selectedType?: Type | undefined }>
> = (props) => {
  const { node, level, stepPaddingInRem, onNodeSelect, innerProps } = props;
  const { selectedType } = innerProps;
  const [, dragRef] = useDrag(
    () => ({ type: node.dndType, item: new TypeDragSource(node) }),
    [node],
  );
  const isExpandable = Boolean(node.childrenIds?.length);
  const nodeTypeIcon = node.type ? (
    getClassPropertyIcon(node.type)
  ) : (
    <PURE_EnumValueIcon />
  );
  const nodeExpandIcon = isExpandable ? (
    node.isOpen ? (
      <ChevronDownIcon />
    ) : (
      <ChevronRightIcon />
    )
  ) : (
    <div />
  );
  const selectNode = (): void => onNodeSelect?.(node);

  return (
    <div
      className={clsx('tree-view__node__container', {
        'type-tree__node__container--highlighted': node.type === selectedType,
      })}
      onClick={selectNode}
      ref={dragRef}
      style={{
        paddingLeft: `${(level - 1) * (stepPaddingInRem ?? 1)}rem`,
        display: 'flex',
      }}
    >
      <div className="tree-view__node__icon type-tree__node__icon">
        <div className="type-tree__expand-icon">{nodeExpandIcon}</div>
        <div className="type-tree__type-icon">{nodeTypeIcon}</div>
      </div>
      <div className="tree-view__node__label type-tree__node__label">
        <button tabIndex={-1} title={`${node.id}`}>
          {node.label}
        </button>
        {Boolean(node.type) && (
          <div className="type-tree__node__type">
            <button
              className={clsx('type-tree__node__type__label', {
                'type-tree__node__type__label--highlighted':
                  node.type === selectedType,
              })}
              tabIndex={-1}
              title={node.type?.path ?? ''}
            >
              {node.type?.name ?? 'unknown'}
            </button>
          </div>
        )}
      </div>
    </div>
  );
}
Example #9
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 #10
Source File: useInteractive.ts    From openchakra with MIT License 5 votes vote down vote up
useInteractive = (
  component: IComponent,
  enableVisualHelper: boolean = false,
) => {
  const dispatch = useDispatch()
  const showLayout = useSelector(getShowLayout)
  const isComponentSelected = useSelector(getIsSelectedComponent(component.id))
  const isHovered = useSelector(getIsHovered(component.id))
  const focusInput = useSelector(getFocusedComponent(component.id))

  const [, drag] = useDrag({
    item: { id: component.id, type: component.type, isMoved: true },
  })

  const ref = useRef<HTMLDivElement>(null)
  let props = {
    ...component.props,
    onMouseOver: (event: MouseEvent) => {
      event.stopPropagation()
      dispatch.components.hover(component.id)
    },
    onMouseOut: () => {
      dispatch.components.unhover()
    },
    onClick: (event: MouseEvent) => {
      event.preventDefault()
      event.stopPropagation()
      dispatch.components.select(component.id)
    },
    onDoubleClick: (event: MouseEvent) => {
      event.preventDefault()
      event.stopPropagation()
      if (focusInput === false) {
        dispatch.app.toggleInputText()
      }
    },
  }

  if (showLayout && enableVisualHelper) {
    props = {
      ...props,
      border: `1px dashed #718096`,
      padding: props.p || props.padding ? props.p || props.padding : 4,
    }
  }

  if (isHovered || isComponentSelected) {
    props = {
      ...props,
      boxShadow: `${focusInput ? '#ffc4c7' : '#4FD1C5'} 0px 0px 0px 2px inset`,
    }
  }

  return { props, ref: drag(ref), drag }
}
Example #11
Source File: QueryBuilderFunctionsExplorerPanel.tsx    From legend-studio with Apache License 2.0 5 votes vote down vote up
QueryBuilderFunctionsExplorerListEntry = observer(
  (props: {
    queryBuilderState: QueryBuilderState;
    element: ConcreteFunctionDefinition;
    rootPackageName: ROOT_PACKAGE_NAME;
  }) => {
    const { queryBuilderState, element, rootPackageName } = props;
    const node = generateFunctionsExplorerTreeNodeData(
      queryBuilderState,
      element,
      rootPackageName,
    );
    const functionSignature = generateFunctionSignature(element, true);
    const [, dragConnector, dragPreviewConnector] = useDrag(
      () => ({
        type: QUERY_BUILDER_FUNCTIONS_EXPLORER_TREE_DND_TYPE.FUNCTION,
        item: { node: node },
      }),
      [node],
    );
    // hide default HTML5 preview image
    useEffect(() => {
      dragPreviewConnector(getEmptyImage(), { captureDraggingState: true });
    }, [dragPreviewConnector]);

    return (
      <div
        className="query-builder__functions-explorer__function"
        ref={dragConnector}
      >
        <div className="query-builder__functions-explorer__function__content">
          <div className="query-builder__functions-explorer__function__icon">
            <div className="query-builder__functions-explorer__function-icon">
              <PURE_FunctionIcon />
            </div>
          </div>
          <div
            className="query-builder__functions-explorer__function__label"
            title={functionSignature}
          >
            {functionSignature}
          </div>
        </div>
        <div className="query-builder__functions-explorer__function__actions">
          <QueryBuilderFunctionInfoTooltip
            element={node.packageableElement as ConcreteFunctionDefinition}
          >
            <div className="query-builder__functions-explorer__function__action query-builder__functions-explorer__function__node__info">
              <InfoCircleIcon />
            </div>
          </QueryBuilderFunctionInfoTooltip>
        </div>
      </div>
    );
  },
)
Example #12
Source File: DragItem.tsx    From openchakra with MIT License 5 votes vote down vote up
DragItem: React.FC<ComponentItemProps> = ({
  type,
  soon,
  label,
  isMeta,
  isChild,
  rootParentType,
}) => {
  const [, drag] = useDrag({
    item: { id: type, type, isMeta, rootParentType },
  })

  let boxProps: any = {
    cursor: 'no-drop',
    color: 'whiteAlpha.600',
  }

  if (!soon) {
    boxProps = {
      ref: drag,
      color: 'whiteAlpha.800',
      cursor: 'move',
      _hover: {
        ml: -1,
        mr: 1,
        bg: 'teal.100',
        boxShadow: 'sm',
        color: 'teal.800',
      },
    }
  }

  if (isChild) {
    boxProps = { ...boxProps, ml: 4 }
  }

  return (
    <Box
      boxSizing="border-box"
      transition="margin 200ms"
      my={1}
      borderRadius="md"
      p={1}
      display="flex"
      alignItems="center"
      {...boxProps}
    >
      <DragHandleIcon path="" fontSize="xs" mr={2} />
      <Text letterSpacing="wide" fontSize="sm" textTransform="capitalize">
        {label}
      </Text>
      {isMeta && (
        <Box
          ml={2}
          borderWidth="1px"
          color="teal.300"
          borderColor="teal.600"
          fontSize="xs"
          borderRadius={4}
          px={1}
        >
          preset
        </Box>
      )}
      {soon && (
        <Box
          ml={2}
          borderWidth="1px"
          color="whiteAlpha.500"
          borderColor="whiteAlpha.300"
          fontSize="xs"
          borderRadius={4}
          px={1}
        >
          soon
        </Box>
      )}
    </Box>
  )
}
Example #13
Source File: QueryBuilderParameterPanel.tsx    From legend-studio with Apache License 2.0 5 votes vote down vote up
VariableExpressionViewer = observer(
  (props: {
    queryBuilderState: QueryBuilderState;
    variableExpressionState: QueryParameterState;
  }) => {
    const { queryBuilderState, variableExpressionState } = props;
    const queryParameterState = queryBuilderState.queryParametersState;
    const variable = variableExpressionState.parameter;
    const name = variable.name;
    const variableType = variable.genericType?.value.rawType;
    const typeName = variableType?.name;
    const editVariable = (): void => {
      queryParameterState.setSelectedParameter(variableExpressionState);
    };
    const deleteVariable = (): void =>
      queryParameterState.removeParameter(variableExpressionState);
    const [, dragConnector, dragPreviewConnector] = useDrag(
      () => ({
        type: QUERY_BUILDER_PARAMETER_TREE_DND_TYPE.VARIABLE,
        item: { variable: variableExpressionState },
      }),
      [variableExpressionState],
    );
    // hide default HTML5 preview image
    useEffect(() => {
      dragPreviewConnector(getEmptyImage(), { captureDraggingState: true });
    }, [dragPreviewConnector]);
    return (
      <div className="query-builder__parameters__parameter" ref={dragConnector}>
        <QueryBuilderParameterDragLayer queryBuilderState={queryBuilderState} />
        <div className="query-builder__parameters__parameter__content">
          <div className="query-builder__parameters__parameter__icon">
            <div className="query-builder__parameters__parameter-icon">
              <DollarIcon />
            </div>
          </div>
          <div className="query-builder__parameters__parameter__label">
            {name}
            <div className="query-builder__parameters__parameter__type">
              <div className="query-builder__parameters__parameter__type__label">
                {typeName}
              </div>
            </div>
          </div>
        </div>
        <div className="query-builder__parameters__parameter__actions">
          <button
            className="query-builder__parameters__parameter__action"
            tabIndex={-1}
            onClick={editVariable}
            title="Edit Parameter"
          >
            <PencilIcon />
          </button>
          <button
            className="query-builder__parameters__parameter__action"
            onClick={deleteVariable}
            title="Remove"
          >
            <TimesIcon />
          </button>
        </div>
      </div>
    );
  },
)
Example #14
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 #15
Source File: DataDocGridItem.tsx    From querybook with Apache License 2.0 5 votes vote down vote up
DataDocGridItem: React.FunctionComponent<IDataDocGridItemProps> = React.memo(
    ({ dataDoc, className, url, onRemove }) => {
        const [, drag] = useDrag({
            type: DataDocDraggableType,
            item: {
                type: DataDocDraggableType,
                itemInfo: dataDoc,
            },
        });

        const handleClick = React.useCallback(() => {
            history.push(url);
        }, [url]);

        const handleRemoveDataDoc = React.useCallback(
            (event: React.MouseEvent) => {
                if (onRemove) {
                    event.stopPropagation();
                    event.preventDefault();
                    onRemove(dataDoc);
                }
            },
            [onRemove, dataDoc]
        );

        const { title = '', public: publicDataDoc } = dataDoc;
        const privateIcon = !publicDataDoc ? 'Lock' : null;

        return (
            <div ref={drag} className="DataDocGridItem">
                <PopoverHoverWrapper>
                    {(showPopover, anchorElement) => (
                        <>
                            <ListLink
                                className={className}
                                onClick={handleClick}
                                to={url}
                                icon={privateIcon}
                                title={title}
                                isRow
                            >
                                {onRemove && (
                                    <IconButton
                                        className="delete-grid-item-button ml8"
                                        noPadding
                                        size={16}
                                        icon="X"
                                        onClick={handleRemoveDataDoc}
                                    />
                                )}
                            </ListLink>
                            <UrlContextMenu
                                url={url}
                                anchorRef={{ current: anchorElement }}
                            />
                            {showPopover && anchorElement && (
                                <Popover
                                    onHide={NOOP}
                                    anchor={anchorElement}
                                    layout={['right', 'top']}
                                >
                                    <DataDocHoverContent
                                        docId={dataDoc.id}
                                        title={title}
                                    />
                                </Popover>
                            )}
                        </>
                    )}
                </PopoverHoverWrapper>
            </div>
        );
    }
)
Example #16
Source File: FlatDataRecordTypeTree.tsx    From legend-studio with Apache License 2.0 5 votes vote down vote up
RecordFieldTreeNodeContainer: React.FC<
  TreeNodeContainerProps<
    FlatDataRecordTypeTreeNodeData,
    { selectedType?: Type | undefined }
  >
> = (props) => {
  const { node, level, stepPaddingInRem, onNodeSelect, innerProps } = props;
  const { selectedType } = innerProps;
  const [, dragRef] = useDrag(
    () => ({
      type: CORE_DND_TYPE.TYPE_TREE_PRIMITIVE,
      item: new FlatDataColumnDragSource(node),
    }),
    [node],
  );
  const nodeTypeIcon = <PURE_PrimitiveTypeIcon />;
  const selectNode = (): void => onNodeSelect?.(node);
  const primitiveType = node.field.flatDataDataType._correspondingPrimitiveType;

  return (
    <div
      className="tree-view__node__container"
      onClick={selectNode}
      ref={dragRef}
      style={{
        paddingLeft: `${(level - 1) * (stepPaddingInRem ?? 1)}rem`,
        display: 'flex',
      }}
    >
      <div className="tree-view__node__icon flat-data-column-tree__node__icon">
        <div className="type-tree__type-icon">{nodeTypeIcon}</div>
      </div>
      <div className="tree-view__node__label type-tree__node__label">
        <button tabIndex={-1} title={`${node.id}`}>
          {node.label}
        </button>
        {
          <div className="type-tree__node__type">
            <button
              className={clsx('type-tree__node__type__label', {
                'type-tree__node__type__label--highlighted':
                  primitiveType && primitiveType === selectedType,
              })}
              tabIndex={-1}
              title={'Column Type'}
            >
              {primitiveType?.path ?? 'RecordType'}
            </button>
          </div>
        }
      </div>
    </div>
  );
}
Example #17
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 #18
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 #19
Source File: EditorBrickAsComponent.spec.tsx    From next-core with GNU General Public License v3.0 5 votes vote down vote up
(useDrag as jest.MockedFunction<typeof useDrag>).mockReturnValue([
  { isDragging: false },
  jest.fn(),
  undefined,
]);
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: WidgetDndHandleMask.tsx    From datart with Apache License 2.0 5 votes vote down vote up
WidgetDndHandleMask: React.FC<WidgetDndHandleMaskProps> = memo(
  ({ widgetId, widgetType }) => {
    const dispatch = useDispatch();
    interface DropResult {
      tabItem: ContainerItem;
      parentId: string;
    }

    const [_, dragRef, dragPreview] = useDrag(() => ({
      type: CONTAINER_TAB,
      item: { type: widgetType },
      end: (item, monitor) => {
        const dropResult = monitor.getDropResult<DropResult>();
        if (item && dropResult) {
          const { tabItem, parentId } = dropResult;
          dispatch(
            editBoardStackActions.addWidgetToContainerWidget({
              parentId,
              tabItem: { ...tabItem, childWidgetId: widgetId },
              sourceId: widgetId,
            }),
          );
        }
      },
      collect: monitor => ({
        isDragging: monitor.isDragging(),
        handlerId: monitor.getHandlerId(),
      }),
    }));

    const ssp = e => {
      e.stopPropagation();
    };
    return (
      <>
        <div
          ref={dragPreview}
          className="dragRef2"
          onClick={ssp}
          onDragStart={ssp}
          style={{
            position: 'absolute',
            top: '0',
            cursor: 'grabbing',
            width: '100%',
            height: '100%',
          }}
        ></div>
        <div
          ref={dragRef}
          // onDragStart={ssp}
          onClick={ssp}
          className="dragRef1"
          style={{
            position: 'absolute',
            cursor: 'grabbing',
            top: '0',
            zIndex: LEVEL_10 + 1,
            width: '100%',
            height: '100%',
          }}
        ></div>
      </>
    );
  },
)
Example #22
Source File: index.tsx    From uno-game with MIT License 5 votes vote down vote up
DraggableCard: React.FC<CardProps> = (props) => {
	const {
		card,
		index,
		style,
		className,
		onClick,
		selected,
		isDraggingAnyCard,
		onDragEnd,
		canBePartOfCurrentCombo,
		isMoreThanOneCardBeingDragged,
	} = props

	const draggableCardRef = useRef(null)

	const canCardBeUsed = canBePartOfCurrentCombo || card.canBeUsed

	const [{ isDragging }, drag, preview] = useDrag({
		item: {
			type: CARD_TYPE,
			id: card.id,
			index,
			src: card.src,
			name: card.name,
			cardType: card.type,
			selected,
			className,
		} as DraggedCardItem,
		collect: monitor => ({
			isDragging: monitor.isDragging(),
		}),
		canDrag: canCardBeUsed,
		end: onDragEnd,
	})

	drag(draggableCardRef)

	useDidMount(() => {
		preview(getEmptyImage(), { captureDraggingState: true })
	})

	return (
		<img
			ref={draggableCardRef}
			key={card.name}
			className={className}
			alt={card.name}
			src={card.src}
			style={{
				...style,
				opacity: (isDragging || (isDraggingAnyCard && isMoreThanOneCardBeingDragged && selected)) ? 0 : 1,
				filter: !canCardBeUsed ? "brightness(0.5)" : "saturate(1.5)",
				pointerEvents: canCardBeUsed ? "all" : "none",
				...(selected ? {
					border: `${Device.isMobile ? "3px" : "5px"} solid #EC0000`,
					borderRadius: Device.isMobile ? "8px" : "16px",
				} : {}),
			}}
			onClick={onClick}
		/>
	)
}
Example #23
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 #24
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 #25
Source File: BrickItem.spec.tsx    From next-basics with GNU General Public License v3.0 5 votes vote down vote up
jest.mock("react-dnd", () => ({
  useDrag: jest.fn(),
}));
Example #26
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 #27
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 #28
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 #29
Source File: draggable-table.tsx    From admin with MIT License 4 votes vote down vote up
DraggableTable: React.FC<DraggableTableProps> = ({
  entities,
  setEntities,
  onDelete,
  columns,
}) => {
  const [records, setRecords] = useState(entities)
  useEffect(() => {
    setRecords(entities)
  }, [entities])

  useEffect(() => setEntities(records), [records])

  const DND_ITEM_TYPE = "row"

  const {
    getTableProps,
    getTableBodyProps,
    headerGroups,
    rows,
    prepareRow,
  } = useTable({
    columns,
    data: records,
  })

  const moveRow = (dragIndex, hoverIndex) => {
    const dragRecord = records[dragIndex]
    setRecords(
      update(records, {
        $splice: [
          [dragIndex, 1],
          [hoverIndex, 0, dragRecord],
        ],
      })
    )
    setEntities(
      update(records, {
        $splice: [
          [dragIndex, 1],
          [hoverIndex, 0, dragRecord],
        ],
      })
    )
  }

  const debouncedMoveRow = useMemo(() => debounce(moveRow, 100), [])

  useEffect(() => {
    return () => {
      debouncedMoveRow.cancel()
    }
  }, [])

  const Row = ({ row, index, moveRow }) => {
    const dropRef = useRef(null)
    const dragRef = useRef(null)

    const [_, drop] = useDrop(() => ({
      accept: DND_ITEM_TYPE,
      hover: (item, monitor) => {
        if (!dropRef.current) {
          return
        }

        const dragIndex = item.index
        const hoverIndex = index
        // Don't replace items with themselves
        if (dragIndex === hoverIndex) {
          return
        }

        // return // TODO: fix hover/drop action
        // if (latestMoved?.from === dragIndex && latestMoved?.to === hoverIndex) {
        //   return
        // }
        // Determine rectangle on screen
        const hoverBoundingRect = dropRef.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.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

        // setLatestMoved({ from: dragIndex, to: hoverIndex })
        moveRow(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 [{ isDragging }, drag, preview] = useDrag(() => ({
      type: "row",
      item: { index },
      collect: (monitor) => ({
        isDragging: !!monitor.isDragging(),
      }),
    }))

    const opacity = isDragging ? 0 : 1

    preview(drop(dropRef))
    drag(dragRef)

    return (
      <Table.Row ref={dropRef} style={{ opacity }}>
        <Table.Cell className="medium:w-[72px] small:w-auto">
          <Button
            ref={dragRef}
            variant="ghost"
            size="small"
            className="h-6 w-6 cursor-grab text-grey-40 mx-6"
          >
            <GripIcon size={20} />
          </Button>
        </Table.Cell>
        {row.cells.map((cell) => {
          return <td {...cell.getCellProps()}>{cell.render("Cell")}</td>
        })}
        {onDelete && (
          <Table.Cell>
            <Button
              onClick={() => onDelete(row.original)}
              variant="ghost"
              size="small"
              className="p-1 text-grey-40 cursor-pointer mx-6"
            >
              <TrashIcon size={20} />
            </Button>
          </Table.Cell>
        )}
      </Table.Row>
    )
  }

  return (
    <div className="w-full h-full">
      <DndProvider backend={HTML5Backend}>
        <Table {...getTableProps()}>
          <Table.Head>
            {headerGroups?.map((headerGroup) => (
              <Table.HeadRow {...headerGroup.getHeaderGroupProps()}>
                <Table.HeadCell> </Table.HeadCell>
                {headerGroup.headers.map((col) => (
                  <Table.HeadCell {...col.getHeaderProps()}>
                    {col.render("Header")}
                  </Table.HeadCell>
                ))}
              </Table.HeadRow>
            ))}
          </Table.Head>
          <Table.Body {...getTableBodyProps()}>
            {rows.map(
              (row, index) =>
                prepareRow(row) || (
                  <Row
                    index={index}
                    row={row}
                    moveRow={moveRow}
                    {...row.getRowProps()}
                  />
                )
            )}
          </Table.Body>
        </Table>
      </DndProvider>
    </div>
  )
}