react-dnd#useDrop JavaScript 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: useRowDrop.js    From os-league-tools with MIT License 6 votes vote down vote up
export default function useRowDrop(type, index, dropRef, moveRow) {
    return useDrop({
        accept: 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;
            }
            const hoverBoundingRect = dropRef.current.getBoundingClientRect();
            const hoverMiddleY = (hoverBoundingRect.bottom - hoverBoundingRect.top) / 2;
            const clientOffset = monitor.getClientOffset();
            const hoverClientY = clientOffset.y - hoverBoundingRect.top;

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

            moveRow(dragIndex, hoverIndex);
            // Mutating the state is actually a perf improvement here to avoid regenerating indexes
            // eslint-disable-next-line no-param-reassign
            item.index = hoverIndex;
        },
    });
}
Example #2
Source File: drag-sorting.jsx    From virtuoso-design-system with MIT License 6 votes vote down vote up
DragableUploadListItem = ({ originNode, moveRow, file, fileList }) => {
  const ref = React.useRef();
  const index = fileList.indexOf(file);
  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 ? ' drop-over-downward' : ' drop-over-upward',
      };
    },
    drop: item => {
      moveRow(item.index, index);
    },
  });
  const [, drag] = useDrag({
    type,
    item: { index },
    collect: monitor => ({
      isDragging: monitor.isDragging(),
    }),
  });
  drop(drag(ref));
  const errorNode = <Tooltip title="Upload Error">{originNode.props.children}</Tooltip>;
  return (
    <div
      ref={ref}
      className={`ant-upload-draggable-list-item ${isOver ? dropClassName : ''}`}
      style={{ cursor: 'move' }}
    >
      {file.status === 'error' ? errorNode : originNode}
    </div>
  );
}
Example #3
Source File: drag-sorting.jsx    From virtuoso-design-system with MIT License 6 votes vote down vote up
DragableBodyRow = ({ index, moveRow, className, style, ...restProps }) => {
  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 ? ' drop-over-downward' : ' drop-over-upward',
      };
    },
    drop: item => {
      moveRow(item.index, index);
    },
  });
  const [, drag] = useDrag({
    type,
    item: { index },
    collect: monitor => ({
      isDragging: monitor.isDragging(),
    }),
  });
  drop(drag(ref));

  return (
    <tr
      ref={ref}
      className={`${className}${isOver ? dropClassName : ''}`}
      style={{ cursor: 'move', ...style }}
      {...restProps}
    />
  );
}
Example #4
Source File: index.js    From dstack-server with Apache License 2.0 6 votes vote down vote up
DnDItem = memo(({id, onMoveItem, children}) => {
    const ref = useRef(null);

    const [, connectDrag] = useDrag({
        item: {id, type: 'IMG'},
        collect: monitor => {
            return {isDragging: monitor.isDragging()};
        },
    });

    const [, connectDrop] = useDrop({
        accept: 'IMG',
        drop: hoveredOverItem => {
            if (hoveredOverItem.id !== id) {
                onMoveItem(hoveredOverItem.id, id);
            }
        },
    });

    connectDrag(ref);
    connectDrop(ref);

    return React.Children.map(children, child =>
        React.cloneElement(child, {forwardedRef: ref})
    );
})
Example #5
Source File: ViewportPane.js    From vindr-lab-viewer with MIT License 6 votes vote down vote up
ViewportPane = function (props) {
  const { children, onDrop, viewportIndex, className: propClassName } = props;
  const [{ hovered, highlighted }, drop] = useDrop({
    accept: 'thumbnail',
    drop: (droppedItem, monitor) => {
      const canDrop = monitor.canDrop();
      const isOver = monitor.isOver();

      if (canDrop && isOver && onDrop) {
        const { StudyInstanceUID, displaySetInstanceUID } = droppedItem;

        onDrop({ viewportIndex, StudyInstanceUID, displaySetInstanceUID });
      }
    },
    // Monitor, and collect props.
    // Returned as values by `useDrop`
    collect: monitor => ({
      highlighted: monitor.canDrop(),
      hovered: monitor.isOver(),
    }),
  });

  return (
    <div
      className={classNames(
        'viewport-drop-target',
        { hovered: hovered },
        { highlighted: highlighted },
        propClassName
      )}
      ref={drop}
      data-cy={`viewport-container-${viewportIndex}`}
    >
      {children}
    </div>
  );
}
Example #6
Source File: BlackCardDrop.js    From cards-of-personality-frontend with GNU Affero General Public License v3.0 6 votes vote down vote up
BlackCardDrop = ({addBlackCardBackToPile, children}) => {
  const [, drop] = useDrop({
    accept: 'blackCardFromPlayer',
    drop: (item) => {
      addBlackCardBackToPile(item);
    },
  });

  return (
    <BlackCardDropElem ref={drop}>
      {children}
    </BlackCardDropElem>
  )
}
Example #7
Source File: sort.js    From actual with MIT License 6 votes vote down vote up
export function useDroppable({ types, id, onDrop, onLongHover }) {
  let ref = useRef(null);
  let [dropPos, setDropPos] = useState(null);

  // eslint-disable-next-line
  let [{ isOver }, dropRef] = useDrop({
    accept: types,
    drop({ item }, monitor) {
      onDrop(item.id, dropPos, id);
    },
    hover({ item, type }, monitor) {
      let hoverBoundingRect = ref.current.getBoundingClientRect();
      let hoverMiddleY = (hoverBoundingRect.bottom - hoverBoundingRect.top) / 2;
      let clientOffset = monitor.getClientOffset();
      let hoverClientY = clientOffset.y - hoverBoundingRect.top;
      let pos = hoverClientY < hoverMiddleY ? 'top' : 'bottom';

      setDropPos(pos);
    },
    collect(monitor) {
      return { isOver: monitor.isOver() };
    }
  });

  useEffect(() => {
    let timeout;
    if (onLongHover && isOver) {
      timeout = setTimeout(onLongHover, 700);
    }

    return () => timeout && clearTimeout(timeout);
  }, [isOver]);

  return {
    dropRef: useMergedRefs(dropRef, ref),
    dropPos: isOver ? dropPos : null
  };
}
Example #8
Source File: DroppableContainer.jsx    From signdocs with MIT License 5 votes vote down vote up
DroppableContainer = ({ children, className, thisPage }) => {
  const acceptableTypes = [
    ItemTypes.UNFILLED_SIGNATURE,
    ItemTypes.UNFILLED_TEXT,
  ];
  const { docId } = useParams();
  const dispatch = useDispatch();
  const createCF = (cfData) => dispatch(createContentField(cfData));
  const updateCF = (cfData) => dispatch(updateContentField(cfData));

  const allCFs = useSelector((state) => state.entities.contentFields);
  const contentFields = Object.values(allCFs).filter(
    (ele) => ele.docId === docId && ele.bbox?.page === thisPage,
  );

  const [_collectedProps, drop] = useDrop({
    accept: acceptableTypes,
    drop(item, monitor) {
      const diff = monitor.getDifferenceFromInitialOffset();
      let delta = diff;
      if (item.bbox.initial) {
        delta = getDelta(item.type, diff, thisPage);
      }

      const pageWidth = getWidthOfCurrentPage(thisPage);
      const pageHeight = getHeightOfCurrentPage(thisPage);
      let newBBOX = convertBBOXtoPixels(
        item.bbox,
        thisPage,
        pageWidth,
        pageHeight,
      );

      let left = newBBOX.left + delta.x + 8;
      let top = newBBOX.top + delta.y + 8;

      left = Math.min(left, pageWidth - newBBOX.width / 2);
      left = Math.max(newBBOX.width / 2, left);

      top = Math.min(top, pageHeight - newBBOX.height / 2);
      top = Math.max(newBBOX.height / 2, top);

      newBBOX = { ...newBBOX, left, top };
      if (allCFs[item.id]) {
        updateCF({ ...item, bbox: newBBOX });
      } else {
        createCF({ ...item, bbox: newBBOX });
      }
      return undefined;
    },
  });

  const unsignedCfs = contentFields.filter(isUnfilled);

  return (
    <div ref={drop} className={className}>
      {unsignedCfs.map((cf) => {
        return <DraggableBox key={cf.id} cfData={cf} thisPage={thisPage} />;
      })}
      {children}
    </div>
  );
}
Example #9
Source File: Droppable.jsx    From ashteki with GNU Affero General Public License v3.0 5 votes vote down vote up
Droppable = ({ children, manualMode, onDragDrop, source }) => {
    const [{ canDrop, isOver, itemSource }, drop] = useDrop({
        accept: ItemTypes.CARD,
        canDrop: (_, monitor) => {
            let item = monitor.getItem();

            if (manualMode) {
                return (
                    validTargets[item.source] &&
                    validTargets[item.source].some((target) => target === source)
                );
            }

            if (
                (item.source === 'hand' && source === 'spellboard') ||
                (item.source === 'hand' && source === 'play area') ||
                (item.source === 'hand' && source === 'discard')
            ) {
                return item.card.canPlay;
            }

            return false;
        },
        collect: (monitor) => {
            let item = monitor.getItem();

            return {
                isOver: monitor.isOver(),
                canDrop: monitor.canDrop(),
                itemSource: item && item.source
            };
        },
        drop: (_, monitor) => {
            let item = monitor.getItem();

            if (onDragDrop) {
                onDragDrop(item.card, item.source, source);
            }
        }
    });
    let className = classNames('overlay', {
        'drop-ok': isOver && canDrop,
        'no-drop': isOver && !canDrop && source !== itemSource,
        'can-drop': !isOver && canDrop
    });

    return (
        <div className='drop-target' ref={drop}>
            <div className={className} />
            {children}
        </div>
    );
}
Example #10
Source File: sortable-item.js    From Quest with MIT License 5 votes vote down vote up
// https://react-dnd.github.io/react-dnd/examples/sortable/simple
function SortableItem({ id, text, index, moveCard }) {
  const ref = useRef(null);
  const [, drop] = useDrop({
    accept: "item",
    hover(item, monitor) {
      if (!ref.current) {
        return;
      }
      const dragIndex = item.index;
      const hoverIndex = index;
      // Don't replace items with themselves
      if (dragIndex === hoverIndex) {
        return;
      }

      const hoverBoundingRect = ref.current.getBoundingClientRect();
      const hoverMiddleY = (hoverBoundingRect.bottom - hoverBoundingRect.top) / 2;
      const clientOffset = monitor.getClientOffset();
      const hoverClientY = clientOffset.y - hoverBoundingRect.top;

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

      // Dragging upwards
      if (dragIndex > hoverIndex && hoverClientY > hoverMiddleY) {
        return;
      }
      moveCard(dragIndex, hoverIndex);
      item.index = hoverIndex;
    },
  });

  const [{ isDragging }, drag] = useDrag({
    item: { type: "item", id, index },
    collect: (monitor) => ({ isDragging: monitor.isDragging() }),
  });

  const opacity = isDragging ? 0.2 : 1;

  drag(drop(ref));
  return (
    <div
      className={`${CARD} ${ELEVATION_2}`}
      ref={ref}
      style={{ opacity, margin: "8px 0px", cursor: "move" }}
    >
      <Icon icon="drag-handle-vertical" />
      <H5 style={{ display: "inline" }}>{text}</H5>
    </div>
  );
}
Example #11
Source File: PlayerDrop.js    From cards-of-personality-frontend with GNU Affero General Public License v3.0 5 votes vote down vote up
PlayerDrop = ({
  index,
  winningPlayerIndex,
  myName,
  players,
  socket,
  addCardToPlayer,
  userIsDragging,
  setUserIsDragging,
  className,
  isMyCardsOpen,
  isSubmittedTableOpen,
}) => {
  const [{isOver}, drop] = useDrop({
    accept: ['blackCard', 'blackCardFromPlayer'],
    drop: (item) => {
      addCardToPlayer(item, players[index]);
    },
    collect: (monitor) => ({
      isOver: !!monitor.isOver(),
    }),
  });

  return (
    <PlayerDropWrap className={className}>
      <Wrap ref={drop}>
        <CardElement
          style={{
            background:
              userIsDragging === 'blackCard' ||
              userIsDragging === 'blackCardFromPlayer'
                ? '#2cce9f'
                : null,
            transform: isOver ? 'scale(1.05)' : null,
          }}
        >
          <PlayerName style={{margin: 0}}>{`${getBlackCardLength({
            players,
            index,
          })} ${getPlayerName({myName, players, index, socket})}`}</PlayerName>
        </CardElement>
        {index === winningPlayerIndex && <Confetti />}
      </Wrap>
      {players &&
        players[index] &&
        players[index].blackCards &&
        players[index].blackCards.map((blackCard) => (
          <div
            key={blackCard.text}
            style={{
              pointerEvents:
                userIsDragging === 'blackCard' ||
                userIsDragging === 'blackCardFromPlayer'
                  ? 'none'
                  : null,
            }}
          >
            <DraggableCard
              screen="main"
              flippedByDefault
              isFlippable={false}
              socket={socket}
              setUserIsDragging={setUserIsDragging}
              type="blackCardFromPlayer"
              isMyCardsOpen={isMyCardsOpen}
              isSubmittedTableOpen={isSubmittedTableOpen}
              {...blackCard}
            />
          </div>
        ))}
    </PlayerDropWrap>
  );
}
Example #12
Source File: create_dnd.jsx    From taro-form with MIT License 5 votes vote down vote up
CreateDrop = ({ compName, form, indexs, moveForm, editForm, editInfo }) => {
  const [{ over }, drop] = useDrop({
    accept: [EditTypes.FORM_ADD, EditTypes.FORM_MOVE],
    hover(item, monitor) {
      if (item.type === EditTypes.FORM_ADD) {
        return
      }
      if (comp.isChildDisable(compName, item.tpl)) {
        return
      }
      // 判断是不是在当前组件内不移动的在内部移动index-1 从其他地方移动来的index保持不变
      let index = form.length
      if (item.indexs.length - 1 === indexs.length && item.indexs.slice(0, item.indexs.length - 1).join() === indexs.join()) {
        index--
      }
      const newIndexs = [...indexs, index]
      if (item.indexs.join() === newIndexs.join()) {
        return
      }
      // 禁止将父组件拖动到自己的子组件
      if (item.indexs.length < newIndexs.length && item.indexs.join() === newIndexs.slice(0, item.indexs.length).join()) {
        return
      }
      if (!monitor.isOver({ shallow: true })) {
        return
      }
      // 执行更新
      moveForm(item.indexs, newIndexs)
      // 更改索引
      item.indexs = newIndexs
    },
    drop(item) {
      if (item.type === EditTypes.FORM_MOVE) {
        return
      }
      // 禁止放进子组件
      if (comp.isChildDisable(compName, item.tpl)) {
        return
      }
      // 子组件数量判断
      if (!comp.isChildAdd(compName, form.length)) {
        return
      }
      moveForm(item.tpl, [...indexs, form.length])
    },
    collect(monitor) {
      const item = monitor.getItem()
      return {
        over: item
          && item.type === EditTypes.FORM_ADD
          && monitor.isOver()
          && !comp.isChildDisable(compName, item.tpl)
          && comp.isChildAdd(compName, form.length)
      }
    }
  })

  return <View
    ref={drop}
    className={`create-dnd__edit${over ? ' create-dnd__edit--drop' : ''}`}
    onClick={() => {
      compName === 'page' && editForm([])
    }}
  >
    <Text className='create-dnd__edit__title'>{editInfo.title}</Text>
    {!!editInfo.desc && <Text className='create-dnd__edit__desc'>{over ? '放开添加' : editInfo.desc}</Text>}
  </View>
}
Example #13
Source File: DndItem.js    From the-eye-knows-the-garbage with MIT License 4 votes vote down vote up
Card = function Card(_ref) {
  var id = _ref.id,
      _end = _ref.end,
      move = _ref.move,
      children = _ref.children,
      index = _ref.index;
  var ref = useRef(null);

  var _useDrop = useDrop({
    accept: ItemTypes.CARD,
    hover: function hover(item, monitor) {
      if (!ref.current) {
        return;
      }

      var dragIndex = item.index;
      var hoverIndex = index; // Don't replace items with themselves

      if (dragIndex === hoverIndex) {
        return;
      } // Determine rectangle on screen


      var hoverBoundingRect = ref.current.getBoundingClientRect(); // Get vertical middle

      var hoverMiddleY = (hoverBoundingRect.bottom - hoverBoundingRect.top) / 2; // Determine mouse position

      var clientOffset = monitor.getClientOffset(); // Get pixels to the top

      var 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


      if (move) {
        move(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.
      // eslint-disable-next-line no-param-reassign


      item.index = hoverIndex;
    }
  }),
      _useDrop2 = _slicedToArray(_useDrop, 2),
      drop = _useDrop2[1];

  var _useDrag = useDrag({
    item: {
      type: ItemTypes.CARD,
      id: id,
      index: index
    },
    collect: function collect(monitor) {
      return {
        isDragging: monitor.isDragging()
      };
    },
    end: function end(item) {
      if (!item) {
        return;
      }

      _end(item.id, item.index);
    }
  }),
      _useDrag2 = _slicedToArray(_useDrag, 2),
      isDragging = _useDrag2[0].isDragging,
      drag = _useDrag2[1];

  var opacity = isDragging ? 0 : 1;
  drag(drop(ref));
  return React.createElement("div", {
    ref: ref,
    style: {
      opacity: opacity
    }
  }, children);
}
Example #14
Source File: MyCardsDropZone.js    From cards-of-personality-frontend with GNU Affero General Public License v3.0 4 votes vote down vote up
MyCardsDropZone = ({
  addCardToMyCards,
  submittedCards,
  discardACard,
  myCards,
  myName,
  socket,
  setUserIsDragging,
  userIsDragging,
  submitACard,
  blackCards,
  setChatOpen,
  unreadCount,
  isMyCardsOpen,
  setMyCardsOpen,
  isSubmittedTableOpen,
  setSubmittedTableOpen,
}) => {
  const [{isOver}, drop] = useDrop({
    accept: 'whiteCard',
    drop: (item) => {
      addCardToMyCards(item);
    },
    collect: (monitor) => ({
      isOver: !!monitor.isOver(),
    }),
  });
  const [{isOverSubmit}, submitDropRef] = useDrop({
    accept: 'whiteCard',
    drop: (item) => {
      submitACard(item);
    },
    collect: (monitor) => ({
      isOverSubmit: !!monitor.isOver(),
    }),
  });
  const [{isOverDiscard}, discardDropRef] = useDrop({
    accept: 'whiteCard',
    drop: (item) => {
      discardACard(item);
    },
    collect: (monitor) => ({
      isOverDiscard: !!monitor.isOver(),
    }),
  });

  return (
    <>
      <DropZoneWrap>
        <MyCards
          onClick={() => setMyCardsOpen(true)}
          ref={drop}
          style={getMyNameCardsStyle({myCards, userIsDragging, isOver})}
          className="MyCardsDropBar"
        >
          {getMyNameCards({myCards, userIsDragging, myName, isOver})}
        </MyCards>
        <ChatButton
          socket={socket}
          myName={myName}
          setChatOpen={setChatOpen}
          unreadCount={unreadCount}
        />
      </DropZoneWrap>
      <div className={cx('MyCardsContainer', {'is-open': isMyCardsOpen})}>
        <Wrapper>
          <MenuTitle>{`${myName}'s Cards`}</MenuTitle>
          <ScrollingWrap className="MyCardsContainer-scrollingWrap">
            <Scrolling>
              <Card
                text={
                  blackCards && blackCards.length
                    ? blackCards[blackCards.length - 1]
                    : ''
                }
                bgColor="#000"
                color="#fff"
              />
              {myCards.map((card) => (
                <CardWrap key={card.text}>
                  <DraggableCard
                    isBroadcastingDrag={false}
                    flippedByDefault
                    key={card.text}
                    setUserIsDragging={setUserIsDragging}
                    socket={socket}
                    screen="myCards"
                    isMyCardsOpen={isMyCardsOpen}
                    isSubmittedTableOpen={isSubmittedTableOpen}
                    {...card}
                  />
                </CardWrap>
              ))}
              {getBlankCards(myCards).map((num) => (
                <BlankCard key={num}>Draw a card</BlankCard>
              ))}
            </Scrolling>
          </ScrollingWrap>
        </Wrapper>
        <ButtonWrapper>
          <BackToTableButton onClick={() => setMyCardsOpen(false)}>
            <BackIcon />
          </BackToTableButton>
          <SubmittedCardsButton
            ref={submitDropRef}
            onClick={() => setSubmittedTableOpen(true)}
            style={getBottomBarStyles({
              submittedCards,
              userIsDragging,
              isOverSubmit,
            })}
            className="SubmittedCardsBar"
          >
            {getBottomBarText({submittedCards, userIsDragging, isOverSubmit})}
          </SubmittedCardsButton>
        </ButtonWrapper>
      </div>
      <div
        className={cx('SubmittedCardsTable', {
          'is-open': isSubmittedTableOpen,
        })}
      >
        <WrapperCentered>
          <MenuTitle>SUBMITTED CARDS</MenuTitle>
          <ScrollingWrap className="SubmittedCardsTable-scrollingWrap">
            <Scrolling>
              <Card
                text={
                  blackCards && blackCards.length
                    ? blackCards[blackCards.length - 1]
                    : ''
                }
                bgColor="#000"
                color="#fff"
              />
              {submittedCards.map((card) => (
                <CardWrap key={card.text}>
                  <DraggableCard
                    isFlipBroadcasted
                    key={card.text}
                    setUserIsDragging={setUserIsDragging}
                    socket={socket}
                    screen="submittedCards"
                    isMyCardsOpen={isMyCardsOpen}
                    isSubmittedTableOpen={isSubmittedTableOpen}
                    {...card}
                  />
                </CardWrap>
              ))}
              {getBlankSubmittedCards(submittedCards).map((num) => (
                <BlankCard key={num}></BlankCard>
              ))}
            </Scrolling>
          </ScrollingWrap>
        </WrapperCentered>
        <ButtonWrapper>
          <BackToTableButton onClick={() => setSubmittedTableOpen(false)}>
            <BackIcon />
          </BackToTableButton>

          <DiscardButton
            ref={discardDropRef}
            style={getDiscardStyles({userIsDragging, isOverDiscard})}
            className="DiscardButton"
          >
            {isOverDiscard ? 'DROP IT!' : 'DROP TO DISCARD HERE'}
          </DiscardButton>
        </ButtonWrapper>
      </div>
    </>
  );
}
Example #15
Source File: QueueCard.js    From qasong with ISC License 4 votes vote down vote up
export default function ImgMediaCard({
  id,
  index,
  nowPlaying,
  onClickImage,
  moveCard,
  qid,
  queue,
  setQueue,
  thumbnail,
  title,
}) {
  const classes = useStyles();

  const ref = useRef(null);

  const removeQueueItem = () => {
    setQueue(
      queue.filter((item) => {
        return item.qid !== qid;
      })
    );
  };

  const [, drop] = useDrop({
    accept: "card",
    hover(item, monitor) {
      if (!ref.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 = ref.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
      moveCard(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] = useDrag({
    item: { type: "card", id, index },
    collect: (monitor) => ({
      isDragging: monitor.isDragging(),
    }),
  });
  const opacity = isDragging ? 0 : 1;
  drag(drop(ref));

  return (
    <Card
      ref={ref}
      className={classes.card}
      style={{
        backgroundColor: (nowPlaying && nowPlaying.qid) === qid && qasongOrange,
        opacity,
      }}
    >
      <CardActionArea style={{ height: "100px" }} onClick={() => onClickImage(qid)}>
        <CardMedia
          className={classes.media}
          component="img"
          alt={title}
          image={thumbnail}
          title={title}
        />
        <Box p={1}>
          <Grid container direction="column">
            <Grid item>
              <Typography style={{ fontSize: "8px" }} gutterBottom>
                {formatVideoTitle(title)}
              </Typography>
            </Grid>
          </Grid>
        </Box>
      </CardActionArea>
      {/* Remove from queue overlay */}
      <Box className={classes.overlay}>
        <Tooltip title="remove from queue">
          <IconButton
            edge="end"
            color="secondary"
            onClick={removeQueueItem}
            size="small"
            style={{ color: "red", background: "#00000080" }}
          >
            <ClearIcon />
          </IconButton>
        </Tooltip>
      </Box>
    </Card>
  );
}
Example #16
Source File: QueueRow.js    From qasong with ISC License 4 votes vote down vote up
export default function ImgMediaCard({
  id,
  index,
  nowPlaying,
  onClickMusicRow,
  moveCard,
  qid,
  queue,
  setQueue,
  title,
  timestamp,
}) {
  const classes = useStyles();

  const ref = useRef(null);

  const removeQueueItem = (e) => {
    e.stopPropagation();
    setQueue(
      queue.filter((item) => {
        return item.qid !== qid;
      })
    );
  };

  const [, drop] = useDrop({
    accept: "card",
    hover(item, monitor) {
      if (!ref.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 = ref.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
      moveCard(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({
    item: { type: "card", id, index },
    collect: (monitor) => ({
      isDragging: monitor.isDragging(),
    }),
  });

  const opacity = isDragging ? 0 : 1;
  drag(drop(ref));

  return (
    <Grid
      item
      container
      className={classes.row + " qasong-queueitem"}
      onClick={() => onClickMusicRow(qid)}
      direction="row"
      alignItems="center"
      ref={preview}
      style={{
        backgroundColor: (nowPlaying && nowPlaying.qid) === qid && qasongOrange,
        opacity,
      }}
    >
      <Grid item xs={1}>
        <IconButton>
          <PlayArrowIcon />
        </IconButton>
      </Grid>
      <Grid item xs={9}>
        <Typography>{title}</Typography>
      </Grid>
      <Grid item xs={1}>
        <IconButton className={classes.dragHandle} ref={ref}>
          <DragHandleIcon />
        </IconButton>
      </Grid>
      <Grid item xs={1}>
        <Typography>{timestamp}</Typography>
      </Grid>

      {/* Remove from queue overlay */}
      <Box className={classes.overlay}>
        <Tooltip title="remove from queue">
          <IconButton
            edge="end"
            onClick={removeQueueItem}
            size="small"
            style={{ color: "red", background: "#00000080" }}
          >
            <ClearIcon />
          </IconButton>
        </Tooltip>
      </Box>
    </Grid>
  );
}
Example #17
Source File: Room.js    From virtualdojo-rooms with GNU General Public License v3.0 4 votes vote down vote up
function Room({ room }) {
  const { currentUser, changeRoom, event, setRoomInfo } = useContext(store);
  const [isMovingUser, setIsMovingUser] = useState(false);
  const [isEditDialogOpen, setIsEditDialogOpen] = useState(false);
  const { t } = useTranslation("translation");
  const [{ canDrop, isOver }, drop] = useDrop({
    accept: ItemTypes.USER,
    drop: () => {
      return { room };
    },
    collect: (monitor) => ({
      isOver: monitor.isOver(),
      canDrop: monitor.canDrop(),
    }),
  });
  const { palette } = useTheme();
  const theme = {
    background: {
      default: palette.primary.main,
      active: palette.secondary.main,
      hover: palette.primary.main,
    },
    text: {
      default: palette.secondary.main,
      active: palette.primary.main,
      hover: palette.secondary.main,
    },
  };

  const changeRoomWithState = useCallback(
    async (userId, roomId) => {
      if (!isMovingUser) {
        setIsMovingUser(true);
        await changeRoom(userId, roomId);
        setIsMovingUser(false);
      }
    },
    [changeRoom, isMovingUser]
  );

  const isActive = canDrop && isOver;
  const isUserInThisRoom = currentUser.room.roomId === room.roomId;
  let activeClass = "default";
  if ((isUserInThisRoom && !canDrop) || isActive) {
    activeClass = "active";
  } else if (canDrop) {
    activeClass = "hover";
  }
  const orderedUsers = room.users.sort((a, b) =>
    a.userName > b.userName ? 1 : -1
  );
  return (
    <Paper
      ref={drop}
      style={{
        backgroundColor: theme.background[activeClass],
        padding: "15px",
        flexGrow: 1,
      }}
    >
      <EditRoomDialog
        isOpen={isEditDialogOpen}
        room={room}
        onClose={() => setIsEditDialogOpen(false)}
        onConfirm={async (roomName, imageUrl) => {
          if (roomName !== room.roomName || imageUrl !== room.imageUrl) {
            await setRoomInfo({ roomId: room.roomId, roomName, imageUrl });
          }
          setIsEditDialogOpen(false);
        }}
      ></EditRoomDialog>
      <Grid item xs container direction="row" spacing={2}>
        <Grid container spacing={2}>
          <Grid item>
            <ButtonBase
              disabled={!currentUser.isMentor}
              style={{
                width: 64,
                height: 64,
              }}
              onClick={() => setIsEditDialogOpen(true)}
            >
              <img
                style={{
                  margin: "auto",
                  display: "block",
                  maxWidth: "100%",
                  maxHeight: "100%",
                }}
                alt={`${room.roomName}`}
                src={room.imageUrl || defaultRoomImage}
              />
            </ButtonBase>
          </Grid>
          <Grid item xs>
            <Typography
              gutterBottom
              variant="subtitle1"
              style={{ color: theme.text[activeClass] }}
              noWrap={false}
            >
              {room.roomName}
            </Typography>
            <Grid item container xs={12} spacing={1}>
              <Grid item>
                <IconButton
                  aria-label="promote"
                  color={
                    currentUser.room.roomId === room.roomId
                      ? "primary"
                      : "secondary"
                  }
                  disabled={isMovingUser}
                  onClick={() => {
                    const el = document.createElement("textarea");
                    el.value = `${event.jitsiServer}/${room.roomId}`;
                    document.body.appendChild(el);
                    el.select();
                    document.execCommand("copy");
                    document.body.removeChild(el);
                  }}
                  style={{ padding: 0 }}
                >
                  <Tooltip title={"Copy Jitsi link"}>
                    <FileCopyIcon />
                  </Tooltip>
                </IconButton>
              </Grid>
              <Grid item>
                <IconButton
                  aria-label="promote"
                  color="secondary"
                  onClick={() =>
                    changeRoomWithState(currentUser.userId, room.roomId)
                  }
                  disabled={
                    isMovingUser ||
                    !event.hasFreeMovement ||
                    currentUser.room.roomId === room.roomId
                  }
                  style={{ padding: 0 }}
                >
                  <Tooltip
                    title={
                      currentUser.room.roomId === room.roomId
                        ? t("You are in this room")
                        : t("Explore Room")
                    }
                    placement="bottom"
                    key={currentUser.room.roomId === room.roomId}
                  >
                    {currentUser.room.roomId === room.roomId ? (
                      <ExploreOffIcon />
                    ) : (
                      <ExploreIcon />
                    )}
                  </Tooltip>
                </IconButton>
              </Grid>
              <Grid item>
                {isMovingUser && (
                  <CircularProgress
                    size={20}
                    color={
                      currentUser.room.roomId === room.roomId
                        ? "primary"
                        : "secondary"
                    }
                  />
                )}
              </Grid>
            </Grid>
          </Grid>
        </Grid>
        <Grid item container xs={12} spacing={1} alignItems={"flex-start"}>
          {orderedUsers.map((u) => (
            <User
              inRoom
              key={`${u.userId}${u.isMentor}`}
              avatarSize={orderedUsers.length > 20 ? "sm" : "md"}
              user={u}
              changeRoom={changeRoomWithState}
              dragDisabled={isMovingUser}
              currentUser={currentUser}
              avatarColor={{
                background: theme.text[activeClass],
                color: theme.background[activeClass],
              }}
            />
          ))}
        </Grid>
      </Grid>
    </Paper>
  );
}
Example #18
Source File: LicenseFieldItem.js    From react-invenio-deposit with MIT License 4 votes vote down vote up
LicenseFieldItem = ({
  license,
  moveLicense,
  replaceLicense,
  removeLicense,
  searchConfig,
  serializeLicenses,
}) => {
  const dropRef = React.useRef(null);
  const [_, drag, preview] = useDrag({
    item: { index: license.index, type: 'license' },
  });
  const [{ hidden }, drop] = useDrop({
    accept: 'license',
    hover(item, monitor) {
      if (!dropRef.current) {
        return;
      }
      const dragIndex = item.index;
      const hoverIndex = license.index;

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

      if (monitor.isOver({ shallow: true })) {
        moveLicense(dragIndex, hoverIndex);
        item.index = hoverIndex;
      }
    },
    collect: (monitor) => ({
      hidden: monitor.isOver({ shallow: true }),
    }),
  });

  // Initialize the ref explicitely
  drop(dropRef);
  return (
    <Ref innerRef={dropRef} key={license.key}>
      <List.Item
        key={license.key}
        className={
          hidden ? 'deposit-drag-listitem hidden' : 'deposit-drag-listitem'
        }
      >
        <List.Content floated="right">
          <LicenseModal
            searchConfig={searchConfig}
            onLicenseChange={(selectedLicense) => {
              replaceLicense(license.index, selectedLicense);
            }}
            mode={license.type}
            initialLicense={license.initial}
            action="edit"
            trigger={
              <Button size="mini" primary type="button">
                {i18next.t('Edit')}
              </Button>
            }
            serializeLicenses={serializeLicenses}
          />
          <Button
            size="mini"
            type="button"
            onClick={() => {
              removeLicense(license.index);
            }}
          >
            {i18next.t('Remove')}
          </Button>
        </List.Content>
        <Ref innerRef={drag}>
          <List.Icon name="bars" className="drag-anchor" />
        </Ref>
        <Ref innerRef={preview}>
          <List.Content>
            <List.Header>{license.title}</List.Header>
            {license.description && (
              <List.Description>
                {_truncate(license.description, { length: 300 })}
              </List.Description>
            )}
            {license.link && (
              <span>
                <a href={license.link} target="_blank" rel="noopener noreferrer">
                  {license.description && <span>&nbsp;</span>}
                  {i18next.t('Read more')}
                </a>
              </span>
            )}
          </List.Content>
        </Ref>
      </List.Item>
    </Ref>
  );
}
Example #19
Source File: dropTarget.js    From ant-simple-pro with MIT License 4 votes vote down vote up
DropTarget = memo(function DropTarget(props) {

  const [reviceData, setReviceData] = useState([]);

  const [currentMoveData, setCurrentMoveData] = useState({});

  const [popModelVal, setPopModelVal] = useSetState({ visible: false, dropTarget: {} });

  const [collectProps, droper] = useDrop({
    accept: "Box",
    collect: (minoter) => ({
      isOver: minoter.isOver(),
      canDrop: minoter.canDrop(),
      item: minoter.getItem(),
    }),
    drop: (item, monitor) => {
      const parentDiv = document.getElementById("dropers");
      const pointRect = parentDiv.getBoundingClientRect();
      const dropX = (monitor.getSourceClientOffset().x - pointRect.x) / spacing;
      const dropY = (monitor.getSourceClientOffset().y - pointRect.y) / spacing;
      setReviceData((pre) => [
        ...pre,
        Object.assign({}, item, {
          x: dropX,
          y: dropY,
          id: getRandomStr(),
          w: item.w / spacing,
          h: item.h / spacing,
        }),
      ]);
    },
  });

  const { show } = useContextMenu({ id: "dropFloor" });

  const showMenu = (e) => {
    show(e);
  };

  const menuOption = (status) => {
    if (!isJsonVal(currentMoveData)) {
      toast(requestCode.failedCode, "请先点击或者选择画布中要拖拽的组件");
      return false;
    }
    if (status === 1) {
      const copyVal = reviceData.filter((item) => item.id === currentMoveData.i);
      setReviceData((pre) => [...pre, Object.assign({}, copyVal[0], { id: getRandomStr() })]);
    } else if (status === 2) {
      setReviceData((pre) => pre.filter((item) => item.id !== currentMoveData.i));
    } else {
      setReviceData([]);
      setCurrentMoveData({});
    }
  };

  const MyAwesomeMenu = useCallback(
    () => (
      <Menu id="dropFloor">
        <Item onClick={() => menuOption(1)}>复制</Item>
        <Item onClick={() => menuOption(2)}>删除</Item>
        <Item onClick={() => menuOption(3)}>清屏画布</Item>
      </Menu>
    ),
    [menuOption]
  );

  const handleDrag = useCallback((layout, oldItem, newItem) => {
    const currentVal = reviceData.filter((item) => item.id === newItem.i);
    setCurrentMoveData(newItem);
    setPopModelVal({ visible: true, dropTarget: Object.assign({}, currentVal[0] || {}, newItem) });
  });

  return (
    <div style={{ width: "100%", height: "100%" }} onContextMenu={showMenu}>
      <div ref={droper} className={style.dropTarget} id="dropers">
        {reviceData.length ? (
          <>
            <GridLayout
              onDragStop={handleDrag}
              onDragStart={handleDrag}
              onResizeStop={handleDrag}
              rowHeight={spacing}
              cols={24}
              width={clintWidth}
              margin={[0, 0]}
            >
              {reviceData.map((item, index) => (
                <div
                  key={item.id}
                  data-grid={{
                    i: item.id,
                    x: item.x,
                    y: item.y,
                    w: item.w,
                    h: item.h,
                    resizeHandles: ["se", "s", "e"],
                  }}
                  style={{ background: "#fff" }}
                  className={style.dropGridItem}
                >
                  <RenderTemplate type={item.type} />
                </div>
              ))}
            </GridLayout>
            <MyAwesomeMenu />
          </>
        ) : (
          <Empty
            style={{ height: "100%", paddingTop: "200px" }}
            image="https://gw.alipayobjects.com/zos/antfincdn/ZHrcdLPrvN/empty.svg"
            imageStyle={{
              height: 60,
            }}
            description="暂无数据,请添加组件到画布来吧"
          ></Empty>
        )}
      </div>
      <PopModel {...popModelVal} onClose={setPopModelVal} />
    </div>
  );
})
Example #20
Source File: FundingFieldItem.js    From react-invenio-deposit with MIT License 4 votes vote down vote up
FundingFieldItem = ({
  compKey,
  index,
  fundingItem,
  awardType,
  moveFunding,
  replaceFunding,
  removeFunding,
  searchConfig,
  deserializeAward,
  deserializeFunder,
  computeFundingContents
}) => {
  const dropRef = React.useRef(null);
  const [_, drag, preview] = useDrag({
    item: { index, type: 'award' },
  });
  const [{ hidden }, drop] = useDrop({
    accept: 'award',
    hover(item, monitor) {
      if (!dropRef.current) {
        return;
      }
      const dragIndex = item.index;
      const hoverIndex = index;

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

      if (monitor.isOver({ shallow: true })) {
        moveFunding(dragIndex, hoverIndex);
        item.index = hoverIndex;
      }
    },
    collect: (monitor) => ({
      hidden: monitor.isOver({ shallow: true }),
    }),
  });

  let { headerContent, descriptionContent, awardOrFunder } = computeFundingContents(fundingItem);

  // Initialize the ref explicitely
  drop(dropRef);
  return (
    <Ref innerRef={dropRef} key={compKey}>
      <List.Item
        key={compKey}
        className={
          hidden ? 'deposit-drag-listitem hidden' : 'deposit-drag-listitem'
        }
      >
        <List.Content floated="right">
          <FundingModal
            searchConfig={searchConfig}
            onAwardChange={(selectedFunding) => {
              replaceFunding(index, selectedFunding);
            }}
            mode={awardType}
            action="edit"
            trigger={
              <Button size="mini" primary type="button">
                {i18next.t('Edit')}
              </Button>
            }
            deserializeAward={deserializeAward}
            deserializeFunder={deserializeFunder}
            computeFundingContents={computeFundingContents}
            initialFunding={fundingItem}
          />
          <Button size="mini" type="button" onClick={() => removeFunding(index)}>
            {i18next.t('Remove')}
          </Button>
        </List.Content>

        <Ref innerRef={drag}>
          <List.Icon name="bars" className="drag-anchor" />
        </Ref>
        <Ref innerRef={preview}>
          <List.Content>
            <List.Header>
              {(
                <>
                  <span className="mr-5">
                    {headerContent}
                  </span>

                  {awardOrFunder === 'award'
                    ? (fundingItem?.award?.number && (
                      <Label basic size="mini" className="mr-5">
                        {fundingItem.award.number}
                      </Label>)
                    )
                    : ''}
                  {
                    awardOrFunder === 'award'
                    ? (fundingItem?.award?.url && (
                      <a
                      href={`${fundingItem.award.url}`}
                      target="_blank"
                      rel="noopener noreferrer"
                      aria-label={i18next.t('Open external link')}
                    >
                      <Icon link name="external alternate" />
                    </a>
                    ))
                    : ''
                  }
                </>
              )}
            </List.Header>
            <List.Description>
              {descriptionContent ? descriptionContent : <br/>}
            </List.Description>
          </List.Content>
        </Ref>
      </List.Item>
    </Ref>
  );
}
Example #21
Source File: CreatibutorsFieldItem.js    From react-invenio-deposit with MIT License 4 votes vote down vote up
CreatibutorsFieldItem = ({
  compKey,
  identifiersError,
  index,
  replaceCreatibutor,
  removeCreatibutor,
  moveCreatibutor,
  addLabel,
  editLabel,
  initialCreatibutor,
  displayName,
  roleOptions,
  schema,
  autocompleteNames,
}) => {
  const dropRef = React.useRef(null);
  const [_, drag, preview] = useDrag({
    item: { index, type: 'creatibutor' },
  });
  const [{ hidden }, drop] = useDrop({
    accept: 'creatibutor',
    hover(item, monitor) {
      if (!dropRef.current) {
        return;
      }
      const dragIndex = item.index;
      const hoverIndex = index;

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

      if (monitor.isOver({ shallow: true })) {
        moveCreatibutor(dragIndex, hoverIndex);
        item.index = hoverIndex;
      }
    },
    collect: (monitor) => ({
      hidden: monitor.isOver({ shallow: true }),
    }),
  });

  const renderRole = (role, roleOptions) => {
    if (role) {
      const friendlyRole =
        roleOptions.find(({ value }) => value === role)?.text ?? role;

      return <Label size="tiny">{friendlyRole}</Label>;
    }
  };
  const firstError =
    identifiersError &&
    identifiersError.find((elem) => ![undefined, null].includes(elem));

  // Initialize the ref explicitely
  drop(dropRef);
  return (
    <Ref innerRef={dropRef} key={compKey}>
      <List.Item
        key={compKey}
        className={
          hidden ? 'deposit-drag-listitem hidden' : 'deposit-drag-listitem'
        }
      >
        <List.Content floated="right">
          <CreatibutorsModal
            addLabel={addLabel}
            editLabel={editLabel}
            onCreatibutorChange={(selectedCreatibutor) => {
              replaceCreatibutor(index, selectedCreatibutor);
            }}
            initialCreatibutor={initialCreatibutor}
            roleOptions={roleOptions}
            schema={schema}
            autocompleteNames={autocompleteNames}
            action="edit"
            trigger={
              <Button size="mini" primary type="button">
                {i18next.t('Edit')}
              </Button>
            }
          />
          <Button
            size="mini"
            type="button"
            onClick={() => removeCreatibutor(index)}
          >
            {i18next.t('Remove')}
          </Button>
        </List.Content>
        <Ref innerRef={drag}>
          <List.Icon name="bars" className="drag-anchor" />
        </Ref>
        <Ref innerRef={preview}>
          <List.Content>
            <List.Description>
              <span className="creatibutor">
                {_get(initialCreatibutor, 'person_or_org.identifiers', []).some(
                  (identifier) => identifier.scheme === 'orcid'
                ) && (
                  <img
                    alt="ORCID logo"
                    className="inline-id-icon mr-5"
                    src="/static/images/orcid.svg"
                    width="16"
                    height="16"
                  />
                )}
                {_get(initialCreatibutor, 'person_or_org.identifiers', []).some(
                  (identifier) => identifier.scheme === 'ror'
                ) && (
                  <img
                    alt="ROR logo"
                    className="inline-id-icon mr-5"
                    src="/static/images/ror-icon.svg"
                    width="16"
                    height="16"
                  />
                )}
                {_get(initialCreatibutor, 'person_or_org.identifiers', []).some(
                  (identifier) => identifier.scheme === 'gnd'
                ) && (
                  <img
                    alt="GND logo"
                    className="inline-id-icon mr-5"
                    src="/static/images/gnd-icon.svg"
                    width="16"
                    height="16"
                  />
                )}
                {displayName}{' '}
                {renderRole(initialCreatibutor?.role, roleOptions)}
              </span>
            </List.Description>
            {firstError && (
              <Label pointing="left" prompt>
                {firstError.scheme ? firstError.scheme : 'Invalid identifiers'}
              </Label>
            )}
          </List.Content>
        </Ref>
      </List.Item>
    </Ref>
  );
}
Example #22
Source File: InventoryMergeLayer.js    From CyberState with GNU General Public License v3.0 4 votes vote down vote up
InventoryMergeLayer = props => {
    const ref = useRef(null)
    const { inv } = useContext(InventoryContext)
    const canMergeItems = (itemSqlId, targetItemSqlId) => {
        const item = inv.findItemBySqlId(itemSqlId)
        const targetItem = inv.findItemBySqlId(targetItemSqlId)
        if (!item || !targetItem) {
            // REMOVE
            alt.emit('nError', 'Client: Один из предметов для слияния не найден!')
            return false
        }
        //console.log(JSON.stringify(item))
        //console.log(JSON.stringify(targetItem))
        const can = ( // патроны
            item.params.ammo
            && !item.params.weaponHash
            && targetItem.params.ammo
            && !targetItem.params.weaponHash
            && item.itemId === targetItem.itemId
        ) || ( // патроны на пушку
            item.params.ammo != null
                && !item.params.weaponHash
                && targetItem.params.weaponHash
                && item.itemId === inv.weaponAmmo[targetItem.itemId]
        ) || ( // нарко на нарко
            item.itemId === targetItem.itemId
            && inv.drugsIds.indexOf(item.itemId) !== -1
        ) || ( // сигарета на пачку
            item.itemId === 62
            && targetItem.itemId === 34
            && targetItem.params.count < 20
        )
        return can
    }

    const doItemsMerge = (itemSqlId, targetItemSqlId) => {
        const item = inv.findItemBySqlId(itemSqlId)
        const targetItem = inv.findItemBySqlId(itemSqlId)
        //console.log(`DRAG ITEM: ${JSON.stringify(item)}`)
        //console.log(`MERGE ITEM: ${JSON.stringify(props)}`)
        if (!item || !targetItem) {
            // REMOVE
            alt.emit('nError', 'Client: Один из предметов для слияния не найден!')
            return false
        }
        // патроны
        if (
            item.params.ammo
            && targetItem.params.ammo
            && item.itemId === targetItem.itemId
        ) {
            window.inventoryAPI.delete(itemSqlId)
            return true
        }
        // патроны на пушку
        if (
            item.params.ammo !== null
            && !item.params.weaponHash
            && targetItem.params.weaponHash
            && item.itemId === inv.weaponAmmo[targetItem.itemId]
        ) {
            window.inventoryAPI.delete(itemSqlId)
            return true
        }
        // наркота
        if (
            item.itemId === targetItem.itemId
            && inv.drugsIds.indexOf(item.itemId) !== -1
        ) {
            window.inventoryAPI.delete(itemSqlId)
            return true
        }
        // сигареты
        if (
            item.itemId === 62
            && targetItem.itemId === 34
        ) {
            if (targetItem.params.count >= 20) {
                // REMOVE
                alt.emit('nError', 'Client: Один из предметов для слияния не найден!')
                return false
            }
            window.inventoryAPI.delete(itemSqlId)
            return true
        }

        return false
    }

    const [, drop] = useDrop({
        accept: 'card',
        canDrop: (item, monitor) => {
            //console.log(`MergeLayer: ${JSON.stringify(item)}`)
            if (monitor.id === item.sqlId) return false
            return true
        },
        hover: (item, monitor) => {
            //console.log(`${JSON.stringify(item)}, ${JSON.stringify(monitor)}`)
            if (item.type === 'card') {
                const { x, y } = monitor.getClientOffset()
                //console.log(`${x}, ${y}`)
            }
        },
        drop: (item, monitor) => {
            //console.log(`DRAG ITEM: ${JSON.stringify(item)}`)
            //console.log(`MERGE ITEM: ${JSON.stringify(props)}`)
            if (!item.inVehicle && !props.inVehicle) {
                if (item.sqlId === props.id) {
                    return {}
                }
                //console.log(canMergeItems(item.sqlId, props.id))
                if (canMergeItems(item.sqlId, props.id)) {
                    inv.mergeItems(item.sqlId, props.id)
                    doItemsMerge(item.sqlId, props.id)
                }
            }
        },
        collect: monitor => ({
            isOver: !!monitor.isOver(),
        }),
    })

    drop(ref)
    return (
        <div
            ref={ref}
            className="mergeLayer"
        />
    )
}
Example #23
Source File: FieldDefCard.js    From acsys with MIT License 4 votes vote down vote up
Card = memo(({ id, details, moveCard }) => {
  const ref = useRef(null);
  const [{ isDragging }, connectDrag] = useDrag({
    item: { id, type: ItemTypes.CARD },
    collect: (monitor) => {
      const result = {
        isDragging: monitor.isDragging(),
      };
      return result;
    },
  });
  const [, connectDrop] = useDrop({
    accept: ItemTypes.CARD,
    hover({ id: draggedId }) {
      if (draggedId !== id) {
        moveCard(draggedId, id);
      }
    },
  });
  connectDrag(ref);
  connectDrop(ref);
  const opacity = isDragging ? 0 : 1;
  const containerStyle = useMemo(() => ({ ...style, opacity }), [opacity]);
  const data = [];

  data.push(<option value="none">none</option>);

  if (details.type === 'string') {
    data.push(<option value="autoGen">autoGen</option>);
    data.push(<option value="textEditor">textEditor</option>);
    data.push(<option value="richTextEditor">richTextEditor</option>);
    data.push(<option value="dateTimePicker">dateTimePicker</option>);
    data.push(<option value="imageReference">imageReference</option>);
    data.push(<option value="imageURL">imageURL</option>);
    data.push(<option value="videoReference">videoReference</option>);
    data.push(<option value="videoURL">videoURL</option>);
  }

  if (details.type === 'boolean') {
    data.push(<option value="booleanSelect">boolean</option>);
  }

  if (details.type === 'number') {
    data.push(<option value="numberEditor">numberEditor</option>);
    data.push(<option value="booleanSelect">boolean</option>);
  }

  const width = [];

  for (let i = 0; i < 12; i++) {
    width.push(<option value={i + 1}>{i + 1}</option>);
  }

  const setControl = (event) => {
    details.control = event;
  };
  const setKey = (event) => {
    details.is_key = event;
  };
  const showOnTable = (event) => {
    details.is_visible_on_table = event;
  };
  const showOnPage = (event) => {
    details.is_visible_on_page = event;
  };
  const setWidth = (event) => {
    details.width = parseInt(event);
  };

  return (
    <Paper style={{ maxHeight: 160, marginBottom: 30 }}>
      <AppBar
        style={{ height: 30, borderBottom: '1px solid rgba(0, 0, 0, 0.12)' }}
        position="static"
        color="default"
        elevation={0}
      >
        <Typography variant="subtitle1" align="center">
          {details.field_name}
        </Typography>
      </AppBar>
      <div ref={ref} style={containerStyle}>
        <Grid container spacing={2}>
          <Grid item xs={3}>
            <div>
              <Typography>Control</Typography>
            </div>
          </Grid>
          <Grid item xs={2}>
            <div>
              <Typography>Key</Typography>
            </div>
          </Grid>
          <Grid item xs={2}>
            <div>
              <Typography>Show on table</Typography>
            </div>
          </Grid>
          <Grid item xs={2}>
            <div>
              <Typography>Show on page</Typography>
            </div>
          </Grid>
          <Grid item xs={2}>
            <div>
              <Typography>Width on page</Typography>
            </div>
          </Grid>
          <Grid item xs={3}>
            <div>
              <NativeSelect
                defaultValue={details.control}
                onChange={(e) => setControl(e.target.value)}
              >
                {data}
              </NativeSelect>
            </div>
          </Grid>
          <Grid item xs={2}>
            <div>
              <NativeSelect
                defaultValue={Boolean(details.is_key)}
                onChange={(e) => setKey(e.target.value == 'true')}
              >
                <option value={true}>True</option>
                <option value={false}>False</option>
              </NativeSelect>
            </div>
          </Grid>
          <Grid item xs={2}>
            <div>
              <NativeSelect
                defaultValue={Boolean(details.is_visible_on_table)}
                onChange={(e) => showOnTable(e.target.value == 'true')}
              >
                <option value={true}>Show</option>
                <option value={false}>Hide</option>
              </NativeSelect>
            </div>
          </Grid>
          <Grid item xs={2}>
            <div>
              <NativeSelect
                defaultValue={Boolean(details.is_visible_on_page)}
                onChange={(e) => showOnPage(e.target.value == 'true')}
              >
                <option value={true}>Show</option>
                <option value={false}>Hide</option>
              </NativeSelect>
            </div>
          </Grid>
          <Grid item xs={2}>
            <div>
              <NativeSelect
                defaultValue={details.width}
                onChange={(e) => setWidth(e.target.value)}
              >
                {width}
              </NativeSelect>
            </div>
          </Grid>
        </Grid>
      </div>

      {moveCard}
    </Paper>
  );
})
Example #24
Source File: index.js    From strapi-molecules with MIT License 4 votes vote down vote up
RepeatableComponent = ({
  addRepeatableComponentToField,
  formErrors,
  componentUid,
  componentValue,
  componentValueLength,
  fields,
  isNested,
  isReadOnly,
  max,
  min,
  name,
  schema,
  dataForCurrentVersion,
  isVersionCurrent,
}) => {
  const [, drop] = useDrop({ accept: ItemTypes.COMPONENT });

  const componentErrorKeys = Object.keys(formErrors)
    .filter((errorKey) => {
      return take(errorKey.split("."), isNested ? 3 : 1).join(".") === name;
    })
    .map((errorKey) => {
      return errorKey
        .split(".")
        .slice(0, name.split(".").length + 1)
        .join(".");
    });

  // We need to synchronize the collapses array with the data
  // The key needed for react in the list will be the one from the collapses data
  // This way we don't have to mutate the data when it is received and we can use a unique key
  const [state, dispatch] = useReducer(reducer, initialState, () =>
    init(initialState, componentValue),
  );
  const { collapses } = state.toJS();
  const toggleCollapses = (index) => {
    dispatch({
      type: "TOGGLE_COLLAPSE",
      index,
    });
  };
  const missingComponentsValue = min - componentValueLength;
  const errorsArray = componentErrorKeys.map((key) =>
    get(formErrors, [key, "id"], ""),
  );

  const hasMinError =
    get(errorsArray, [0], "").includes("min") &&
    !collapses.some((obj) => obj.isOpen === true);

  return (
    <div>
      {componentValueLength === 0 && (
        <EmptyComponent hasMinError={hasMinError}>
          <FormattedMessage id={`${pluginId}.components.empty-repeatable`}>
            {(msg) => <p>{msg}</p>}
          </FormattedMessage>
        </EmptyComponent>
      )}
      <div ref={drop}>
        {componentValueLength > 0 &&
          componentValue.map((data, index) => {
            const componentFieldName = `${name}.${index}`;
            const doesPreviousFieldContainErrorsAndIsOpen =
              componentErrorKeys.includes(`${name}.${index - 1}`) &&
              index !== 0 &&
              get(collapses, [index - 1, "isOpen"], false) === false;
            const hasErrors = componentErrorKeys.includes(componentFieldName);

            return (
              <DraggedItem
                fields={fields}
                componentFieldName={componentFieldName}
                componentUid={componentUid}
                doesPreviousFieldContainErrorsAndIsOpen={
                  doesPreviousFieldContainErrorsAndIsOpen
                }
                hasErrors={hasErrors}
                hasMinError={hasMinError}
                isFirst={index === 0}
                isReadOnly={isReadOnly}
                isOpen={get(collapses, [index, "isOpen"], false)}
                key={get(collapses, [index, "_temp__id"], null)}
                onClickToggle={() => {
                  // Close all other collapses and open the selected one
                  toggleCollapses(index);
                }}
                removeCollapse={() => {
                  dispatch({
                    type: "REMOVE_COLLAPSE",
                    index,
                  });
                }}
                moveCollapse={(dragIndex, hoverIndex) => {
                  dispatch({
                    type: "MOVE_COLLAPSE",
                    dragIndex,
                    hoverIndex,
                  });
                }}
                parentName={name}
                schema={schema}
                toggleCollapses={toggleCollapses}
                dataForCurrentVersion={dataForCurrentVersion}
                isVersionCurrent={isVersionCurrent}
              />
            );
          })}
      </div>
      <Button
        hasMinError={hasMinError}
        disabled={isReadOnly}
        withBorderRadius={false}
        doesPreviousFieldContainErrorsAndIsClosed={
          componentValueLength > 0 &&
          componentErrorKeys.includes(`${name}.${componentValueLength - 1}`) &&
          collapses[componentValueLength - 1].isOpen === false
        }
        type="button"
        onClick={() => {
          if (!isReadOnly) {
            if (componentValueLength < max) {
              const shouldCheckErrors = hasMinError;

              addRepeatableComponentToField(
                name,
                componentUid,
                shouldCheckErrors,
              );
              dispatch({
                type: "ADD_NEW_FIELD",
              });
            } else if (componentValueLength >= max) {
              strapi.notification.info(
                `${pluginId}.components.notification.info.maximum-requirement`,
              );
            }
          }
        }}
      >
        <i className="fa fa-plus" />
        <FormattedMessage id={`${pluginId}.containers.EditView.add.new`} />
      </Button>
      {hasMinError && (
        <ErrorMessage>
          <FormattedMessage
            id={`${pluginId}.components.DynamicZone.missing${
              missingComponentsValue > 1 ? ".plural" : ".singular"
            }`}
            values={{ count: missingComponentsValue }}
          />
        </ErrorMessage>
      )}
    </div>
  );
}
Example #25
Source File: index.js    From strapi-molecules with MIT License 4 votes vote down vote up
DraggedItem = ({
  componentFieldName,
  componentUid,
  doesPreviousFieldContainErrorsAndIsOpen,
  fields,
  hasErrors,
  hasMinError,
  isFirst,
  isReadOnly,
  isOpen,
  moveCollapse,
  onClickToggle,
  removeCollapse,
  schema,
  toggleCollapses,
  dataForCurrentVersion,
  isVersionCurrent,

  // Retrieved from the select function
  moveComponentField,
  removeRepeatableField,
  triggerFormValidation,
  checkFormErrors,
  displayedValue,
}) => {
  const { setIsDraggingComponent, unsetIsDraggingComponent } = useEditView();
  const dragRef = useRef(null);
  const dropRef = useRef(null);
  const [showForm, setShowForm] = useState(false);

  useEffect(() => {
    if (isOpen || !isVersionCurrent) {
      setShowForm(true);
    }
  }, [isOpen]);

  useEffect(() => {
    if (!isVersionCurrent) {
      setShowForm(true);
    }
  }, [isVersionCurrent]);

  const [, drop] = useDrop({
    accept: ItemTypes.COMPONENT,
    canDrop() {
      return false;
    },
    hover(item, monitor) {
      if (!dropRef.current) {
        return;
      }

      const dragPath = item.originalPath;
      const hoverPath = componentFieldName;
      const fullPathToComponentArray = dragPath.split(".");
      const dragIndexString = fullPathToComponentArray
        .slice()
        .splice(-1)
        .join("");
      const hoverIndexString = hoverPath.split(".").splice(-1).join("");
      const pathToComponentArray = fullPathToComponentArray.slice(
        0,
        fullPathToComponentArray.length - 1,
      );
      const dragIndex = parseInt(dragIndexString, 10);
      const hoverIndex = parseInt(hoverIndexString, 10);

      // Don't replace items with themselves
      if (dragIndex === 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 in the data
      moveComponentField(pathToComponentArray, dragIndex, hoverIndex);
      // Time to actually perform the action in the synchronized collapses
      moveCollapse(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.originalPath = hoverPath;
    },
  });
  const [{ isDragging }, drag, preview] = useDrag({
    item: {
      type: ItemTypes.COMPONENT,
      displayedValue,
      originalPath: componentFieldName,
    },
    begin: () => {
      // Close all collapses
      toggleCollapses(-1);
      // Prevent the relations select from firing requests
      setIsDraggingComponent();
    },
    end: () => {
      // Enable the relations select to fire requests
      unsetIsDraggingComponent();
      // Update the errors
      triggerFormValidation();
    },
    collect: (monitor) => ({
      isDragging: monitor.isDragging(),
    }),
  });

  useEffect(() => {
    preview(getEmptyImage(), { captureDraggingState: false });
  }, [preview]);

  const getField = (fieldName) =>
    get(schema, ["schema", "attributes", fieldName], {});
  const getMeta = (fieldName) =>
    get(schema, ["metadatas", fieldName, "edit"], {});

  // Create the refs
  // We need 1 for the drop target
  // 1 for the drag target
  const refs = {
    dragRef: drag(dragRef),
    dropRef: drop(dropRef),
  };

  return (
    <>
      <Banner
        componentFieldName={componentFieldName}
        hasErrors={hasErrors}
        hasMinError={hasMinError}
        isFirst={isFirst}
        displayedValue={displayedValue}
        doesPreviousFieldContainErrorsAndIsOpen={
          doesPreviousFieldContainErrorsAndIsOpen
        }
        isDragging={isDragging}
        isOpen={isVersionCurrent ? isOpen : true}
        isReadOnly={isReadOnly}
        onClickToggle={onClickToggle}
        onClickRemove={() => {
          removeRepeatableField(componentFieldName);
          removeCollapse();
        }}
        ref={refs}
      />
      <Collapse
        isOpen={isVersionCurrent ? isOpen : true}
        style={{ backgroundColor: "#FAFAFB" }}
        onExited={() => setShowForm(false)}
      >
        {!isDragging && (
          <FormWrapper
            hasErrors={hasErrors}
            isOpen={isVersionCurrent ? isOpen : true}
            isReadOnly={isReadOnly}
          >
            {showForm &&
              fields.map((fieldRow, key) => {
                return (
                  <div className="row" key={key}>
                    {fieldRow.map((field) => {
                      const currentField = getField(field.name);
                      const isComponent =
                        get(currentField, "type", "") === "component";
                      const keys = `${componentFieldName}.${field.name}`;

                      if (isComponent) {
                        const componentUid = currentField.component;
                        const metas = getMeta(field.name);

                        return (
                          <FieldComponent
                            componentUid={componentUid}
                            isRepeatable={currentField.repeatable}
                            key={field.name}
                            label={metas.label}
                            isNested
                            name={keys}
                            max={currentField.max}
                            min={currentField.min}
                          />
                        );
                      }

                      return (
                        <div key={field.name} className={`col-${field.size}`}>
                          <Inputs
                            autoFocus={false}
                            componentUid={componentUid}
                            keys={keys}
                            layout={schema}
                            name={field.name}
                            onBlur={hasErrors ? checkFormErrors : null}
                            dataForCurrentVersion={dataForCurrentVersion}
                            isVersionCurrent={isVersionCurrent}
                          />
                        </div>
                      );
                    })}
                  </div>
                );
              })}
          </FormWrapper>
        )}
      </Collapse>
    </>
  );
}
Example #26
Source File: index.jsx    From taro-form with MIT License 4 votes vote down vote up
Edit = () => {

  const [cates] = useState(comp.getCates())
  const [cateHover, selectCate] = useState(0)

  const [module] = useState(comp.getComps())

  const [list, setList] = useState([])
  // 将编辑列表存储为全局变量用于节点选择
  window.editFormList = list
  // 选中的表单
  const [hover, setHover] = useState(-1)
  // 选中的表单
  const [hoverName, setHoverName] = useState(-1)
  const [config] = useState({ ...comp.getCompAttr('form'), edit: true })
  const [values] = useState(testData.values)
  const [form, setForm] = useState([])
  const [formValue, setFormValue] = useState({})

  const [preview, setPreview] = useState(false)
  const [previewPhone] = useState([
    { name: '手机', icon: 'shiwu-shouji', width: 480 },
    { name: '平板', icon: 'shouji', width: 750 },
    { name: '电脑', icon: 'dianshi', width: 1280 }
  ])
  const [previewPhoneHover, setPreviewPhoneHover] = useState(0)
  const [showJson, setShowJson] = useState('')
  const [jsonType, setJsonType] = useState('Object')

  const pullView = useRef(null)

  useEffect(() => {
    listUpdate = false
  }, [list])

  /**
   * 放开到删除
   */
  const [{ deleteShow, deleteOver }, dropDelete] = useDrop({
    accept: EditTypes.FORM_MOVE,
    drop(item) {
      recursionGetValue(item.indexs, list, 'child', true)
      setList([...list])
    },
    collect: monitor => ({
      deleteShow: monitor.canDrop(),
      deleteOver: monitor.isOver()
    })
  })

  /**
   * 组件排序
   */
  const moveList = useCallback((dragIndex, hoverIndex) => {
    let parent = {}
    // 移动组件之后重新确定他的父组件 并把嵌套在父组件的子组件该有的属性赋值改子组件
    if (hoverIndex.length > 1) {
      // 存在父组件
      parent = recursionGetValue(hoverIndex.slice(0, hoverIndex.length - 1), list, 'child')
    }

    if (typeof dragIndex === 'string') {
      // 新增组件 dragIndex表示组件名称
      recursionSetValue(hoverIndex, list, comp.getCompAttr(dragIndex, parent.tpl), 'child', true)
      setList([...list])
    } else {
      // 移动组件
      if (listUpdate || dragIndex.join() === hoverIndex.join()) {
        return
      }
      // 标记正在更新 防止重复更新导致数据出错
      listUpdate = true
      // 标记要移动的index位置 防止位置出错
      const dragLen = dragIndex.length
      if (dragLen < hoverIndex.length && hoverIndex[dragLen - 1] > dragIndex[dragLen - 1]) {
        hoverIndex[dragLen - 1]--
      }
      const item = recursionGetValue(dragIndex, list, 'child', true)
      recursionSetValue(hoverIndex, list, { ...item, ...comp.getCompAttr('', parent.tpl) }, 'child', true)
      setList([...list])
    }

  }, [list])


  const formRef = useRef(null)
  /**
   * 开始编辑表单 当indexs为-1时表示退出表单编辑
   */
  const editForm = useCallback(indexs => {
    if (indexs !== -1) {
      const item = indexs.length === 0 ? config : recursionGetValue(indexs, list, 'child')
      // 获取上级
      let parentTpl = ''
      if (indexs.length > 1) {
        parentTpl = recursionGetValue(indexs.slice(0, indexs.length - 1), list, 'child').tpl
      }
      const data = comp.getEditForm(item.tpl, parentTpl)
      setForm(data.form)
      setHoverName(data.text)
      setFormValue(item)
    }
    setHover(indexs)
  }, [list, config])

  /**
   * 等界面更新完成后取重新生成表单
   */
  useEffect(() => {
    if (!formRef.current) {
      return
    }
    formRef.current.getForm()
  }, [form, formValue])

  /**
   * 表单输入事件
   */
  const formInput = useCallback(data => {
    switch (data.event) {
      case 'input':
        const item = hover.length === 0 ? config : recursionGetValue(hover, list, 'child')
        // 表单输入事件
        recursionSetValue(data.names, item, data.value)
        setList([...list])
        break
    }
  }, [list, hover, config])

  const stopPropagation = e => e.stopPropagation()
  return <View className='page-root edit' onClick={() => editForm(-1)}>
    <View className='menu'>
      {
        cates.map((cate, index) => <View
          className={`cate${cateHover === index ? ' hover' : ''}`}
          key={cate.name}
          onClick={() => selectCate(cateHover === index ? -1 : index)}
        >
          <Text className='cate-name'>{cate.text}</Text>
          {cateHover === index && <View className='cate-child'>
            {
              module.filter(child => child.cate === cate.name).map(child => <Module key={child.tpl} item={child} editForm={editForm} />)
            }
          </View>}
        </View>)
      }
      <View className='line' />
      <View
        className={`cate${hover.length === 0 ? ' hover' : ''}`}
        onClick={e => {
          e.stopPropagation()
          editForm([])
        }}
      >
        <Text className='cate-name'>设置</Text>
      </View>
      <View className='line' />
      <View
        className='cate'
        onClick={() => setPreview(true)}
      >
        <Text className='cate-name'>预览</Text>
      </View>
      <View
        className='cate'
        onClick={() => setShowJson('form')}
      >
        <Text className='cate-name'>JSON</Text>
      </View>
    </View>
    <View
      className='phone'
      onClick={stopPropagation}
      style={comp.attrTransform({ style: { ...config.style, width: config.width } }).style}
    >
      <ScrollView className='scroll' scrollY>
        <Create
          form={list}
          config={config}
          values={values}
          moveForm={moveList}
          editForm={editForm}
          editInfo={{
            title: '表单构建',
            desc: '请将组件拖到这里'
          }}
        />
      </ScrollView>
    </View>
    <View className={`form${hover !== -1 ? ' form-show' : ''}`} onClick={stopPropagation}>
      <View className='head'>
        <Text className='title'>{hoverName}</Text>
        <Icon name='guanbi2' size={36} color='#202020' onClick={() => editForm(-1)} />
      </View>
      <View className='content'>
        <Form
          ref={formRef}
          form={form}
          values={formValue}
          config={{
            compStyle: { flexDirection: 'row', alignItems: 'center', padding: 10 },
            compTextStyle: { fontSize: 24, textAlign: 'right', width: 120 }
          }}
          onEvent={formInput}
        />
      </View>
    </View>
    {preview && <PullView side='top' ref={pullView} onClose={() => setPreview(false)}>
      <View className='preview'>
        <View className='head'>
          {
            previewPhone.map((item, index) => <View
              key={item.name}
              className={`item${index === previewPhoneHover ? ' hover' : ''}`}
              onClick={() => setPreviewPhoneHover(index)}
            >
              <Icon name={item.icon} size={36} color='#333' />
            </View>)
          }
        </View>
        <View
          className='mobile'
          style={comp.attrTransform({
            style: {
              ...config.style,
              width: previewPhone[previewPhoneHover].width
            }
          }).style}
        >
          <ScrollView className='scroll' scrollY>
            <Form form={list} values={{}} config={{ ...config, edit: false }} />
          </ScrollView>
        </View>
      </View>
    </PullView>}
    {!!showJson && <PullView side='top' onClose={() => setShowJson('')}>
      <View className='json'>
        <View className='head'>
          <Text className={`item${showJson === 'form' ? ' select' : ''}`} onClick={() => setShowJson('form')}>Form</Text>
          <Text className={`item${showJson === 'config' ? ' select' : ''}`} onClick={() => setShowJson('config')}>Config</Text>
        </View>
        <View className='main'>
          <ScrollView scrollY scrollX className='scroll'>
            <Code>
              {objectToString(showJson === 'form' ? list : config, null, 2, jsonType === 'Object')}
            </Code>
          </ScrollView>
          <View className='type'>
            <Text className={`item${jsonType === 'Object' ? ' select' : ''}`} onClick={() => setJsonType('Object')}>Object</Text>
            <Text className={`item${jsonType === 'JSON' ? ' select' : ''}`} onClick={() => setJsonType('JSON')}>JSON</Text>
          </View>
          <View
            className='copy'
            onClick={async () => {
              try {
                await Taro.setClipboardData({ data: objectToString(showJson === 'form' ? list : config, null, 2, jsonType === 'Object') })
                Taro.showToast({ title: '复制成功' })
              } catch (error) {
                toast('复制失败')
              }
            }}
          >
            <Icon name='wenjian' color='#666' size={24} />
            <Text className='text'>复制</Text>
          </View>
        </View>
      </View>
    </PullView>}
    <View className={`delete${deleteShow ? ' delete-show' : ''}${deleteOver ? ' delete-over' : ''}`} ref={dropDelete}>
      <View className='info'>
        <Icon name='shanchu3' size={52} color={deleteOver ? '#e2e2e2' : '#202020'} style={{ transition: 'color 0.1s' }} />
        <Text className='text'>{deleteOver ? '放开删除' : '拖到这里删除'}</Text>
      </View>
    </View>
  </View>
}
Example #27
Source File: create_dnd.jsx    From taro-form with MIT License 4 votes vote down vote up
DragDrog = ({ children, moveForm, editForm, indexs, tpl, compName, form }) => {
  const ref = useRef(null)
  // 是否横向布局
  const isRow = (() => {
    if (!ref.current) {
      return 'row'
    }
    const style = document.defaultView.getComputedStyle(ref.current.parentNode, null)
    const direction = style.flexDirection
    const display = style.display
    if (display === 'block') {
      return false
    } else {
      return direction === 'row'
    }
  })()
  const [{ isDragging }, drag] = useDrag({
    item: { type: EditTypes.FORM_MOVE, indexs, ref, tpl },
    collect: monitor => ({
      isDragging: monitor.isDragging()
    }),
    begin() {
      editForm(-1)
    }
  })
  const [{ over }, drop] = useDrop({
    accept: [EditTypes.FORM_MOVE, EditTypes.FORM_ADD],
    hover(item, monitor) {
      if (item.type === EditTypes.FORM_ADD) {
        return
      }
      if (!ref.current || !item.ref || !item.ref.current) {
        return
      }
      if (!monitor.isOver({ shallow: true })) {
        return
      }
      if (comp.isChildDisable(compName, item.tpl)) {
        return
      }
      // 跳过相同的位置
      if (item.indexs.join() === indexs.join()) {
        return
      }
      // 禁止将父组件拖动到自己的子组件
      if (item.indexs.length < indexs.length && item.indexs.join() === indexs.slice(0, item.indexs.length).join()) {
        return
      }
      const dragRect = item.ref.current?.getBoundingClientRect()
      const drarPos = monitor.getSourceClientOffset()
      const dropRect = ref.current?.getBoundingClientRect()
      const long = {
        drag: dragRect[isRow ? 'width' : 'height'],
        drop: dropRect[isRow ? 'width' : 'height']
      }
      // 拖动的块比 放开的块小 需要判断是否可以替换
      if (long.drag < long.drop) {
        const start = {
          drag: drarPos[isRow ? 'x' : 'y'],
          drop: dropRect[isRow ? 'left' : 'top']
        }
        const end = {
          drag: start.drag + long.drag,
          drop: start.drop + long.drop
        }
        const width = long.drop - long.drag
        const startWidth = start.drag - start.drop
        const endWidth = end.drop - end.drag
        // 超过三倍 在中间区域
        if (startWidth > width && endWidth > width) {
          return
        }
        // 更接近开始位置 并且当前的块在开始位置 则跳过
        if (startWidth < endWidth && item.indexs.length === indexs.length && item.indexs[item.indexs.length - 1] < indexs[indexs.length - 1]) {
          return
        }
        // 更接近结束位置 并且当前的块在结束位置 则跳过
        if (startWidth >= endWidth && item.indexs.length === indexs.length && item.indexs[item.indexs.length - 1] > indexs[indexs.length - 1]) {
          return
        }
      }
      moveForm(item.indexs, indexs, 'move')
      // 更改索引
      item.indexs = indexs
    },
    drop(item, monitor) {
      if (item.type === EditTypes.FORM_MOVE) {
        return
      }
      if (!monitor.isOver({ shallow: true })) {
        return
      }
      // 禁止放进子组件
      if (comp.isChildDisable(compName, item.tpl)) {
        return
      }
      // 子组件数量判断
      if (!comp.isChildAdd(compName, form.length)) {
        return
      }
      moveForm(item.tpl, indexs)
    },
    collect(monitor) {
      const item = monitor.getItem()
      return {
        over: item
          && item.type === EditTypes.FORM_ADD
          && monitor.isOver({ shallow: true })
          && !comp.isChildDisable(compName, item.tpl)
          && comp.isChildAdd(compName, form.length)
      }
    }
  })

  drag(drop(ref))
  return <View
    ref={ref}
    className={`form-drag-drop${isDragging ? ' form-drag-drop--hover' : ''}${isRow ? ' form-drag-drop--row' : ''}`}
    onClick={e => {
      e.stopPropagation()
      editForm()
    }}
  >
    {over && <View className='form-drag-drop__add'>
      <Text className='form-drag-drop__add__text'>放开添加</Text>
    </View>}
    {children}
  </View>
}
Example #28
Source File: InventoryMergeLayer.js    From CyberStateRP with MIT License 4 votes vote down vote up
InventoryMergeLayer = props => {
    const ref = useRef(null)
    const { inv } = useContext(InventoryContext)
    const canMergeItems = (itemSqlId, targetItemSqlId) => {
        const item = inv.findItemBySqlId(itemSqlId)
        const targetItem = inv.findItemBySqlId(targetItemSqlId)
        if (!item || !targetItem) {
            // REMOVE
            alt.emit('nError', 'Client: One of the merge items not found!')
            return false
        }
        //console.log(JSON.stringify(item))
        //console.log(JSON.stringify(targetItem))
        const can = ( // патроны
            item.params.ammo
            && !item.params.weaponHash
            && targetItem.params.ammo
            && !targetItem.params.weaponHash
            && item.itemId === targetItem.itemId
        ) || ( // патроны на пушку
            item.params.ammo != null
                && !item.params.weaponHash
                && targetItem.params.weaponHash
                && item.itemId === inv.weaponAmmo[targetItem.itemId]
        ) || ( // нарко на нарко
            item.itemId === targetItem.itemId
            && inv.drugsIds.indexOf(item.itemId) !== -1
        ) || ( // сигарета на пачку
            item.itemId === 62
            && targetItem.itemId === 34
            && targetItem.params.count < 20
        )
        return can
    }

    const doItemsMerge = (itemSqlId, targetItemSqlId) => {
        const item = inv.findItemBySqlId(itemSqlId)
        const targetItem = inv.findItemBySqlId(itemSqlId)
        //console.log(`DRAG ITEM: ${JSON.stringify(item)}`)
        //console.log(`MERGE ITEM: ${JSON.stringify(props)}`)
        if (!item || !targetItem) {
            // REMOVE
            alt.emit('nError', 'Client: One of the merge items not found!')
            return false
        }
        // патроны
        if (
            item.params.ammo
            && targetItem.params.ammo
            && item.itemId === targetItem.itemId
        ) {
            window.inventoryAPI.delete(itemSqlId)
            return true
        }
        // патроны на пушку
        if (
            item.params.ammo !== null
            && !item.params.weaponHash
            && targetItem.params.weaponHash
            && item.itemId === inv.weaponAmmo[targetItem.itemId]
        ) {
            window.inventoryAPI.delete(itemSqlId)
            return true
        }
        // наркота
        if (
            item.itemId === targetItem.itemId
            && inv.drugsIds.indexOf(item.itemId) !== -1
        ) {
            window.inventoryAPI.delete(itemSqlId)
            return true
        }
        // сигареты
        if (
            item.itemId === 62
            && targetItem.itemId === 34
        ) {
            if (targetItem.params.count >= 20) {
                // REMOVE
                alt.emit('nError', 'Client: One of the merge items not found!')
                return false
            }
            window.inventoryAPI.delete(itemSqlId)
            return true
        }

        return false
    }

    const [, drop] = useDrop({
        accept: 'card',
        canDrop: (item, monitor) => {
            //console.log(`MergeLayer: ${JSON.stringify(item)}`)
            if (monitor.id === item.sqlId) return false
            return true
        },
        hover: (item, monitor) => {
            //console.log(`${JSON.stringify(item)}, ${JSON.stringify(monitor)}`)
            if (item.type === 'card') {
                const { x, y } = monitor.getClientOffset()
                //console.log(`${x}, ${y}`)
            }
        },
        drop: (item, monitor) => {
            //console.log(`DRAG ITEM: ${JSON.stringify(item)}`)
            //console.log(`MERGE ITEM: ${JSON.stringify(props)}`)
            if (!item.inVehicle && !props.inVehicle) {
                if (item.sqlId === props.id) {
                    return {}
                }
                //console.log(canMergeItems(item.sqlId, props.id))
                if (canMergeItems(item.sqlId, props.id)) {
                    inv.mergeItems(item.sqlId, props.id)
                    doItemsMerge(item.sqlId, props.id)
                }
            }
        },
        collect: monitor => ({
            isOver: !!monitor.isOver(),
        }),
    })

    drop(ref)
    return (
        <div
            ref={ref}
            className="mergeLayer"
        />
    )
}
Example #29
Source File: InventoryItemsLayer.js    From CyberStateRP with MIT License 4 votes vote down vote up
InventoryItemsLayer = props => {
    const ref = useRef(null)
    const { inv } = useContext(InventoryContext)

    const [, drop] = useDrop({
        accept: 'card',
        canDrop(item, monitor) {
            //console.log(`ItemsLayer: ${JSON.stringify(item)}`)
            let hasError = false
            // проверка для сумок, что можно в них класть
            if (Object.prototype.hasOwnProperty.call(props, 'itemId')) {
                if (Object.prototype.hasOwnProperty.call(inv.forbiddenItems, props.itemId)) {
                    if (_.includes(inv.forbiddenItems[props.itemId], item.itemId)) {
                        hasError = true
                    }
                }
            }
            if (item.width > props.width || item.height > props.height) {
                hasError = true
            }
            // проверка повтора
            if (!Object.prototype.hasOwnProperty.call(props, 'itemId')) {
                const itemExists = _.find(
                    inv.personInventory,
                    singleItem => (singleItem.parentId === -1 && singleItem.itemId === item.itemId))
                if (itemExists) hasError = true
                if (item.itemId > 16 && item.itemId !== 54 && item.itemId !== 59) hasError = true
            }
            if (Object.prototype.hasOwnProperty.call(props, 'itemId')) {
                if (props.itemId === item.itemId) hasError = true
            }
            if (props.type === 'vehicle') {
                hasError = false
                // проверка есть ли вещи внутри
                if (Object.prototype.hasOwnProperty.call(inv.forbiddenItems, item.itemId)) {
                    let curItem = inv.findItemBySqlId(item.sqlId)
                    if (!curItem) curItem = inv.findVehItemBySqlId(inv.vehicleInventory, item.sqlId)
                    if (!curItem) return
                    if (Object.prototype.hasOwnProperty.call(curItem, 'items')) {
                        if (curItem.items.length > 0) {
                            hasError = true
                        }
                    }
                }
            }
            //console.log(`hasError: ${hasError}`)
            if (hasError) {
                return false
            }
            return true
        },
        hover(item, monitor) {
            if (item.type === 'card') {
                const hoverItem = props
                const { x, y } = monitor.getClientOffset()
                const groupItemBoundingRect = ref.current.getBoundingClientRect()
                const groupItemX = groupItemBoundingRect.left
                const groupItemY = groupItemBoundingRect.top
                props.onCardHoverInGroupItem(item, hoverItem, x - groupItemX, y - groupItemY)
            }
        },
        drop: (item, monitor) => {
            if (item.type === 'card') {
                const hoverItem = props
                const offset = monitor.getClientOffset()
                if (!offset) return {}
                const { x, y } = offset
                const groupItemBoundingRect = ref.current.getBoundingClientRect()
                const groupItemX = groupItemBoundingRect.left
                const groupItemY = groupItemBoundingRect.top
                props.onCardDropInGroupItem(item, hoverItem, x - groupItemX, y - groupItemY)
            }
        },
        collect: monitor => ({
            isOver: !!monitor.isOver(),
        }),
    })
    const createCards = (cards, groupID, index) => {
        const { layout } = props
        const itemDoms = []
        _.forEach(cards, (c, i) => {
            itemDoms.push(
                <InventoryItem
                    dragCardID={-1}
                    type="card"
                    card={c}
                    sqlId={c.sqlId}
                    inVehicle={c.inVehicle}
                    itemId={c.itemId}
                    index={i}
                    gridX={c.gridX}
                    gridY={c.gridY}
                    width={c.width}
                    height={c.height}
                    parentId={c.parentId}
                    key={`${groupID}_${c.sqlId}`}
                    layout={layout}
                />
            )
        })
        return itemDoms
    }
    const {
        id,
        index,
        cards,
    } = props

    drop(ref)
    return (
        <div
            ref={ref}
            className="itemsGrid"
        >
            {createCards(cards, id, index)}
        </div>
    )
}