react-dnd#useDrag JavaScript Examples

The following examples show how to use react-dnd#useDrag. You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: 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 #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.jsx    From taro-form with MIT License 6 votes vote down vote up
Module = ({ item, editForm }) => {

  const [, drag] = useDrag({
    item: { type: EditTypes.FORM_ADD, tpl: item.tpl },
    begin() {
      editForm(-1)
    }
  })

  return <View ref={drag} className='item'>
    <Text className='text'>{item.text}</Text>
  </View>
}
Example #5
Source File: Fields.jsx    From signdocs with MIT License 6 votes vote down vote up
FieldItem = (props) => {
  const { children, disabled, type } = props;
  const [, drag] = useDrag({
    canDrag: !disabled,
    item: {
      ...props,
      hideSourceOnDrag: true,
    },
    collect: (monitor) => ({
      isDragging: monitor.isDragging(),
    }),
  });
  let classNames = 'draggable';
  if (disabled) classNames += ' disabled-drag';
  return (
    <li ref={drag} className={classNames} id={`FIELD-${type}`}>
      {children}
    </li>
  );
}
Example #6
Source File: sort.js    From actual with MIT License 6 votes vote down vote up
export function useDraggable({
  item,
  type,
  makePreview,
  children,
  canDrag,
  onDragChange
}) {
  let _onDragChange = useRef(onDragChange);

  //eslint-disable-next-line
  const [{ isDragging }, dragRef] = useDrag({
    item: { type, item },
    collect: monitor => ({ isDragging: monitor.isDragging() }),

    begin(monitor) {
      _onDragChange.current({ state: 'start-preview', type, item });

      setTimeout(() => {
        _onDragChange.current({ state: 'start' });
      }, 0);
    },

    end(item, monitor) {
      _onDragChange.current({ state: 'end', type, item });
    },

    canDrag() {
      return canDrag;
    }
  });

  useLayoutEffect(() => {
    _onDragChange.current = onDragChange;
  });

  return { dragRef };
}
Example #7
Source File: useRowDrag.js    From os-league-tools with MIT License 6 votes vote down vote up
export default function useRowDrag(type, index) {
    return useDrag({
        type,
        item: { index },
        collect: monitor => ({
            isDragging: monitor.isDragging(),
        }),
    });
}
Example #8
Source File: dragTarget.js    From ant-simple-pro with MIT License 6 votes vote down vote up
DragTarget = memo(function DragTarget({itemValue}) {

  const [, drager] = useDrag({
      type:"Box",
      item:itemValue
  });

  return (
      <div ref={ drager } className={style.drapTarget}>
        <SvgIcon iconClass={itemValue.type} className='svg-style' />
        <p>{itemValue.title}</p>
      </div>
  )
})
Example #9
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 #10
Source File: DraggableBox.jsx    From signdocs with MIT License 5 votes vote down vote up
DraggableBox = ({ cfData, thisPage }) => {
  const dispatch = useDispatch();
  const {
    type,
    bbox,
    hideSourceOnDrag = false,
    signatoryId,
    placeholder,
  } = cfData;
  const onRemove = () => dispatch(deleteContentField(cfData.id));
  const signatory = useSelector(getUserDetails(signatoryId));

  const [{ isDragging, opacity }, drag, preview] = useDrag({
    item: { ...cfData, type },
    collect: (monitor) => ({
      isDragging: monitor.isDragging(),
      opacity: monitor.isDragging() ? 0.4 : 1,
    }),
  });
  if (isDragging && hideSourceOnDrag) {
    return <div ref={drag} />;
  }

  const style = convertBBOXtoPixels(bbox, thisPage);

  if (type === ItemTypes.UNFILLED_SIGNATURE)
    return (
      <div
        ref={preview}
        className="content-field draggable-item"
        style={{ ...style, opacity }}
      >
        <UnfilledSignature
          onRemove={onRemove}
          signatoryName={signatory.fullName}
          width={style.width}
          height={style.height}
          ref={drag}
        />
      </div>
    );

  if (type === ItemTypes.UNFILLED_TEXT)
    return (
      <div
        ref={preview}
        className="content-field draggable-item fillable"
        style={{ ...style, opacity }}
      >
        <UnfilledTextBox
          placeholder={placeholder}
          onRemove={onRemove}
          width={style.width}
          height={style.height}
          ref={drag}
        />
      </div>
    );
}
Example #11
Source File: Thumbnail.js    From vindr-lab-viewer with MIT License 5 votes vote down vote up
function Thumbnail(props) {
  const {
    active,
    altImageText,
    error,
    displaySetInstanceUID,
    imageId,
    imageSrc,
    SeriesDescription,
    stackPercentComplete,
    StudyInstanceUID,
    onClick,
    onDoubleClick,
    onMouseDown,
    supportsDrag,
  } = props;

  const [collectedProps, drag, dragPreview] = useDrag({
    // `droppedItem` in `dropTarget`
    // The only data it will have access to
    item: {
      StudyInstanceUID,
      displaySetInstanceUID,
      type: 'thumbnail', // Has to match `dropTarget`'s type
    },
    canDrag: function(monitor) {
      return supportsDrag;
    },
  });

  const hasImage = imageSrc || imageId;
  const hasAltText = altImageText !== undefined;

  return (
    <div
      ref={drag}
      className={classNames('thumbnail', {
        active_item: active,
      })}
      onClick={onClick}
      onDoubleClick={onDoubleClick}
      onMouseDown={onMouseDown}
    >
      {SeriesDescription && (
        <div className="series-description">{SeriesDescription || ''}</div>
      )}
      {/* SHOW IMAGE */}
      {hasImage && (
        <ImageThumbnail
          imageSrc={imageSrc}
          imageId={imageId}
          error={error}
          stackPercentComplete={stackPercentComplete}
          width={97}
        />
      )}
      {/* SHOW TEXT ALTERNATIVE */}
      {!hasImage && hasAltText && (
        <div className={'alt-image-text p-x-1'}>
          <h1>{altImageText}</h1>
        </div>
      )}
      {ThumbnailFooter(props)}
    </div>
  );
}
Example #12
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 #13
Source File: DraggableCard.js    From cards-of-personality-frontend with GNU Affero General Public License v3.0 4 votes vote down vote up
DraggableCard = ({
  bgColor,
  isBroadcastingDrag = true,
  isFlipBroadcasted,
  color,
  socket,
  text,
  type,
  setUserIsDragging,
  flippedByDefault = false,
  isFlippable = true,
  screen = '',
  isMyCardsOpen,
  isSubmittedTableOpen,
}) => {
  const [ghostCard, setGhostCard] = useState({});
  const [isFlipped, setFlipped] = useState(flippedByDefault);
  const [{isDragging, getDifferenceFromInitialOffset}, drag] = useDrag({
    item: {
      type,
      id: 0,
      text,
      bgColor,
      color,
      isFlipped,
    },
    collect: (monitor) => ({
      isDragging: !!monitor.isDragging() && !Object.keys(ghostCard).length,
      getDifferenceFromInitialOffset:
        !!monitor.isDragging() && monitor.getDifferenceFromInitialOffset(),
    }),
  });

  if (isDragging && getDifferenceFromInitialOffset) {
    const {x, y} = getDifferenceFromInitialOffset;

    if (isBroadcastingDrag) {
      // send dragged card to server
      socket.emit('dragged card', {type, text, x, y});
    }
  }

  useEffect(() => {
    setUserIsDragging(type);

    if (isBroadcastingDrag) {
      if (!isDragging) {
        // send card that was let go to server
        socket.emit('let go card', {ghostDragging: false, type, text});
      }
    }

    if (!isDragging) {
      setUserIsDragging(null);
    }

    return () => {
      setUserIsDragging(null);
    };
  }, [isBroadcastingDrag, setUserIsDragging, socket, text, type, isDragging]);

  useEffect(() => {
    let isMounted = true;
    if (isBroadcastingDrag) {
      // on everyones client but the sender, show the card being returned to deck if let go prematurely
      socket.on('let go card', ({text: otherText}) => {
        if (isMounted && text === otherText) {
          setGhostCard({});
        }
      });

      // on everyones client but the sender, show the card being dragged
      socket.on('dragged card', ({text: otherText, x, y, type}) => {
        if (isMounted && text === otherText) {
          // if i'm looking at my cards, never drag cards on other screens
          if (isMyCardsOpen && !isSubmittedTableOpen) {
            return;
          }
          // if the card that is being dragged is on the submitted cards screen
          // and the submitted cards screen isn't open, then don't set state
          if (screen === 'submittedCards' && !isSubmittedTableOpen) {
            return;
          }
          // if the card that is being dragged is on the main screen
          // and the submitted cards screen is open, then don't set state
          if (screen === 'main' && isSubmittedTableOpen) {
            return;
          }

          setGhostCard({x, y, text});
        }
      });
    }

    if (isFlipBroadcasted) {
      socket.on('card is flipped', function ({isFlipped, text: otherText}) {
        if (isMounted && text === otherText) {
          setFlipped(isFlipped);
        }
      });
    }

    return () => {
      // socket.off('let go card');
      // socket.off('dragged cards');
      isMounted = false;
    };
  }, [
    isBroadcastingDrag,
    setUserIsDragging,
    socket,
    text,
    type,
    isFlipBroadcasted,
    isMyCardsOpen,
    isSubmittedTableOpen,
    screen
  ]);

  const getTransform = () => {
    if (isBroadcastingDrag) {
      // any cards being dragged by someone else
      if (Object.keys(ghostCard).length) {
        if (ghostCard.text === text) {
          return {
            pointerEvents: 'none',
            opacity: '1',
            transform: `translate3d(${ghostCard.x}px, ${ghostCard.y}px, 0)`,
            zIndex: '999',
          };
        } else {
          return {pointerEvents: 'none', transform: 'translate3d(0, 0, 0)'};
        }
      }
    }

    // on the client that's actually dragging the card
    if (isDragging && getDifferenceFromInitialOffset) {
      return {
        pointerEvents: 'none',
        transform: `translate3d(${getDifferenceFromInitialOffset.x}px, ${getDifferenceFromInitialOffset.y}px, 0)`,
      };
    }

    return {transform: 'translate3d(0, 0, 0)'};
  };

  const getClassName = () => {
    if (isBroadcastingDrag) {
      // any cards being dragged by someone else
      if (Object.keys(ghostCard).length) {
        if (ghostCard.text === text) {
          return 'is-dragging';
        } else {
          return null;
        }
      }
    }

    // on the client that's actually dragging the card
    if (isDragging && getDifferenceFromInitialOffset) {
      return 'is-dragging';
    }

    return null;
  };

  return (
    <CardElement
      className={getClassName()}
      onClick={() => {
        if (isFlippable) {
          setFlipped((isFlipped) => {
            socket.emit('card is flipped', {isFlipped: !isFlipped, text});
            return !isFlipped;
          });
        }
      }}
      ref={drag}
      style={{
        zIndex: isDragging ? 999 : '0',
        ...getTransform(),
        backgroundColor: bgColor,
        color,
        justifyContent: isFlipped ? '' : 'flex-start',
      }}
    >
      {isFlipped ? (
        text
      ) : (
        <>
          <div
            className={`LogoInCard ${
              type === 'whiteCard' ? 'LogoInCard--whiteCard' : ''
            }`}
          />
          {type.includes('black') && (
            <TouchIconWrap>
              <TouchIcon />
            </TouchIconWrap>
          )}
        </>
      )}
    </CardElement>
  );
}
Example #14
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 #15
Source File: User.js    From virtualdojo-rooms with GNU General Public License v3.0 4 votes vote down vote up
function User({
  user,
  currentUser,
  avatarSize,
  inRoom,
  avatarColor,
  changeRoom,
  dragDisabled,
}) {
  const { setIsDragging } = useContext(store);
  const classes = useStyles();
  const [anchorEl, setAnchorEl] = useState(null);

  const handlePopoverOpen = (event) => {
    setAnchorEl(event.currentTarget);
  };

  const handlePopoverClose = () => {
    setAnchorEl(null);
  };

  const canDrag = currentUser.isMentor && !dragDisabled;

  const [{ isDragging }, drag] = useDrag({
    item: { name: user.userName, type: ItemTypes.USER },
    begin: () => setIsDragging(true),
    canDrag,
    end: (item, monitor) => {
      const dropResult = monitor.getDropResult();
      setIsDragging(false);
      if (item && dropResult) {
        changeRoom(user.userId, dropResult.room.roomId);
      }
    },
    collect: (monitor) => ({
      isDragging: monitor.isDragging(),
    }),
  });

  const avatarWidthHeight = avatarSize === "sm" ? 24 : 36;

  const popoverOpen = !isDragging && Boolean(anchorEl);
  const initials = user.userName
    .trim()
    .split(" ")
    .slice(0, 2)
    .map((s) => (s && [...s].length > 0 ? [...s][0].toUpperCase() : ""));
  console.log(initials);
  return (
    <Grid
      item
      style={{
        opacity: isDragging ? "0.4" : "1",
      }}
      onMouseEnter={handlePopoverOpen}
      onMouseLeave={handlePopoverClose}
    >
      <Avatar
        style={{
          ...avatarColor,
          width: avatarWidthHeight,
          height: avatarWidthHeight,
          cursor: canDrag ? "grab" : "default",
          borderRadius: user.isMentor ? 0 : "50%",
        }}
        ref={drag}
      >
        {initials}
      </Avatar>

      <Popover
        id="mouse-over-popover"
        className={classes.popover}
        classes={{
          paper: classes.paper,
        }}
        open={popoverOpen}
        anchorEl={anchorEl}
        anchorOrigin={{
          vertical: "bottom",
          horizontal: "left",
        }}
        transformOrigin={{
          vertical: "top",
          horizontal: "left",
        }}
        onClose={handlePopoverClose}
        disableRestoreFocus
      >
        <Typography>
          {user.userName}
          {user.isMentor && <b> (Mentor)</b>}
        </Typography>
      </Popover>
    </Grid>
  );
}
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: Card.jsx    From ashteki with GNU Affero General Public License v3.0 4 votes vote down vote up
Card = ({
    canDrag,
    card,
    cardBackUrl,
    className,
    disableMouseOver,
    onClick,
    onAltClick,
    onDieClick,
    onMenuItemClick,
    onMouseOut,
    onMouseOver,
    orientation = 'vertical',
    showAltIcon,
    side,
    size,
    source,
    style,
    wrapped = true
}) => {
    const cardBack = cardBackUrl || (card.isConjuration ? conjback : spellback);
    const sizeClass = {
        [size]: size !== 'normal'
    };
    const [showMenu, setShowMenu] = useState(false);

    const [{ dragOffset, isDragging }, drag, preview] = useDrag({
        item: { card: card, source: source, type: ItemTypes.CARD },
        canDrag: () => canDrag || (!card.unselectable && card.canPlay),
        collect: (monitor) => ({
            isDragging: monitor.isDragging(),
            dragOffset: monitor.getSourceClientOffset()
        })
    });

    const isAllowedMenuSource = () => {
        return source === 'play area' || source === 'spellboard';
    };

    const onCardClicked = (event, card) => {
        event.preventDefault();
        event.stopPropagation();
        if (isAllowedMenuSource() && card.menu && card.menu.length !== 0) {
            setShowMenu(!showMenu);
            return;
        }

        onClick && onClick(card);
    };

    const getCountersForCard = (card) => {
        let counters = [];
        let needsFade = UpgradeCardTypes.includes(card.type) && !['full deck'].includes(source);
        if (card.acquiredEffects?.length) {
            card.acquiredEffects.forEach((e) => {
                counters.push({
                    icon: e.effect,
                    name: e.source,
                    count: 1,
                    fade: needsFade,
                    showValue: false
                });
            });
        }
        if (card.armor > 0) {
            counters.push({
                name: 'armor',
                count: card.armor,
                fade: needsFade,
                showValue: true
            });
        }

        if (card.guarded || card.cannotBlock) {
            counters.push({
                name: 'guarded',
                count: 1,
                fade: needsFade,
                showValue: false
            });
        }

        for (const [key, token] of Object.entries(card.tokens || {})) {
            counters.push({
                name: key,
                count: token,
                fade: needsFade,
                showValue: true
            });
        }

        for (const upgrade of card.upgrades || []) {
            counters = counters.concat(getCountersForCard(upgrade));
        }

        return counters.filter((counter) => counter.count >= 0);
    };

    const getCardSizeMultiplier = () => {
        switch (size) {
            case 'small':
                return 0.6;
            case 'large':
                return 1.4;
            case 'x-large':
                return 2;
        }

        return 1;
    };

    const getupgrades = () => {
        if (!['full deck', 'play area', 'spellboard'].includes(source)) {
            return null;
        }

        if (['full deck', 'play area'].includes(source) && !card.upgrades) {
            return null;
        }
        if ('spellboard' === source && !card.childCards) {
            return null;
        }

        let index = 1;
        const cardsToRender = 'spellboard' === source
            ? card.childCards
            : card.upgrades;
        let upgrades = cardsToRender.map((upgrade) => {
            let returnedupgrade = (
                <Card
                    key={upgrade.uuid}
                    source={source}
                    card={upgrade}
                    className={classNames('upgrade', `upgrade-${index}`)}
                    wrapped={false}
                    onMouseOver={
                        !disableMouseOver && onMouseOver
                            ? (upgrade) => onMouseOver(upgrade)
                            : undefined
                    }
                    onMouseOut={!disableMouseOver && onMouseOut}
                    onClick={onClick}
                    onMenuItemClick={onMenuItemClick}
                    size={size}
                />
            );

            index += 1;
            return returnedupgrade;
        });

        return upgrades;
    };

    const renderUnderneathCards = () => {
        // TODO: Right now it is assumed that all cards in the childCards array
        // are being placed underneath the current card. In the future there may
        // be other types of cards in this array and it should be filtered.
        let underneathCards = card.childCards;
        if (!underneathCards || underneathCards.length === 0 || card.location === 'spellboard') {
            return;
        }

        let maxCards = 1 + (underneathCards.length - 1) / 6;
        return (
            <SquishableCardPanel
                cardSize={size}
                cards={underneathCards}
                className='underneath'
                maxCards={maxCards}
                onCardClick={onClick}
                onMouseOut={onMouseOut}
                onMouseOver={onMouseOver}
                source='underneath'
            />
        );
    };

    const getCardOrdering = () => {
        if (!card.order) {
            return null;
        }

        return <div className='card-ordering'>{card.order}</div>;
    };

    const shouldShowMenu = () => {
        if (!isAllowedMenuSource()) {
            return false;
        }

        if (!card.menu || !showMenu) {
            return false;
        }

        return true;
    };

    const showCounters = () => {
        if (['full deck'].includes(source)) {
            return true;
        }

        if (card.facedown || UpgradeCardTypes.includes(card.type)) {
            return false;
        }

        return true;
    };

    const isFacedown = () => {
        return card.facedown || !card.name;
    };

    const getDragFrame = (image) => {
        if (!isDragging) {
            return null;
        }

        let style = {};
        if (dragOffset && isDragging) {
            let x = dragOffset.x;
            let y = dragOffset.y;
            style = {
                left: x,
                top: y
            };
        }

        return (
            <div className='drag-preview' style={style} ref={preview}>
                {image}
            </div>
        );
    };

    const getBoostedFlags = (card) => {
        if (card.flags) {
            let flagItems = Object.keys(card.flags)
                .sort((a, b) => (a < b ? -1 : 1))
                .map((key, index) => {
                    return (
                        <div key={key + index} className={`darkbg flag ${key}`}>
                            <span className='sr-only'>{key[0]}</span>
                            {card.flags[key]}
                        </div>
                    );
                });

            return <div className='flags'>{flagItems}</div>;
        }

        return '';
    };

    const getChainIcon = (card) => {
        if (card.isChained) {
            return (
                <div className='card-chain-icon'>
                    <FontAwesomeIcon icon={faLink} />
                </div>
            );
        }
        return '';
    };

    const getAltIcon = (card) => {
        if (showAltIcon && card.altArts) {
            return (
                <div className='card-alt-icon'>
                    <button className=''
                        onClick={() => onAltClick(card)}
                    >Alt</button>
                </div>
            );
        }
        return '';
    };

    const getCard = () => {
        if (!card) {
            return <div />;
        }

        let statusClass = getStatusClass();
        const combatClass = card.isAttacker || card.isDefender ? 'combat-' + side : null;

        let cardClass = classNames(
            'game-card',
            `card-type-${card.type}`,
            className,
            sizeClass,
            statusClass,
            combatClass,
            {
                'custom-card': card.code && card.code.startsWith('custom'),
                horizontal: orientation !== 'vertical',
                vertical: orientation === 'vertical',
                'can-play':
                    statusClass !== 'selected' &&
                    statusClass !== 'selectable' &&
                    !card.unselectable &&
                    !card.isAttacker &&
                    !card.isDefender &&
                    card.canPlay,
                unselectable: !card.selected && card.unselectable,
                dragging: isDragging,
                controlled: card.controlled,
                attacker: card.isAttacker,
                defender: card.isDefender
            }
        );
        let imageClass = classNames('card-image vertical', sizeClass, {
            exhausted: orientation === 'exhausted' || orientation === 'horizontal'
        });
        let image = card ? (
            <div className={imageClass}>
                <CardImage card={card} cardBack={cardBack} />
                {getChainIcon(card)}
                {getBoostedFlags(card)}
            </div>
        ) : null;
        let dice =
            card.dieUpgrades && card.dieUpgrades.length > 0
                ? card.dieUpgrades.map((d) => (
                    <Die key={'dup-' + d.uuid} die={d} onClick={onDieClick} />
                ))
                : null;

        return (
            <div className='card-frame' ref={drag}>
                {getDragFrame(image)}
                {getCardOrdering()}
                <div
                    tabIndex={0}
                    className={cardClass}
                    onMouseOver={
                        !disableMouseOver && (!isFacedown() || !card.parent) && onMouseOver
                            ? () => onMouseOver(card)
                            : undefined
                    }
                    onMouseOut={!disableMouseOver && !isFacedown() ? onMouseOut : undefined}
                    onClick={(event) => onCardClicked(event, card)}
                >
                    <div>
                        <span className='card-name'>{card.name}</span>
                        {image}
                    </div>
                    {showCounters() && <CardCounters counters={getCountersForCard(card)} />}
                    <div className='die-upgrades'>{dice}</div>
                </div>
                {shouldShowMenu() && (
                    <CardMenu
                        menu={card.menu}
                        side={side}
                        onMenuItemClick={(menuItem) => {
                            onMenuItemClick && onMenuItemClick(card, menuItem);
                            setShowMenu(!showMenu);
                        }}
                    />
                )}
            </div>
        );
    };

    const getStatusClass = () => {
        if (!card) {
            return undefined;
        }

        // location prevents highlighting cards we're about to meditate
        if (card.selected && card.location !== 'deck') {
            return 'selected';
        } else if (card.selectable) {
            // if (card.isAttacker) return 'attacker-' + side + ' selectable ';
            return 'selectable';
            // } else if (card.isAttacker) {
            //     return 'attacker-' + side;
            // } else if (card.isDefender) {
            //     return 'defender-' + side;
        } else if (card.new) {
            return 'new';
        }

        return undefined;
    };

    let styleCopy = Object.assign({}, style);
    if (card.upgrades) {
        styleCopy.top = card.upgrades.length * (15 * getCardSizeMultiplier());
    }
    if (wrapped) {
        return (
            <div className={'card-wrapper'} style={style}>
                {getAltIcon(card)}

                {getCard()}
                {getupgrades()}
                {renderUnderneathCards()}
            </div>
        );
    }

    return getCard();
}
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: 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 #20
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 #21
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 #22
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 #23
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 #24
Source File: InventoryItem.js    From CyberStateRP with MIT License 4 votes vote down vote up
InventoryItem = props => {
    const [itemImage, setItemImage] = useState(null)
    const ref = useRef(null)
    const { inv } = useContext(InventoryContext)
    const images = require.context('../../../assets/images/', true)

    const [{ isDragging }, drag] = useDrag({
        item: {
            sqlId: props.sqlId,// eslint-disable-line
            type: props.type,// eslint-disable-line
            itemId: props.itemId,// eslint-disable-line
            width: props.width,// eslint-disable-line
            height: props.height,// eslint-disable-line
            inVehicle: props.inVehicle,// eslint-disable-line
        },
        begin: monitor => {
            inv.updateDraggedItem(
                {
                    sqlId: props.sqlId,
                    itemId: props.itemId,
                    x: props.gridX,
                    y: props.gridY,
                    initGroup: props.parentId,
                }
            )
        },
        end: (item, monitor) => {
            if (!monitor.didDrop()) {
                inv.updateHoverIndexes({})
            }
        },
        collect: monitor => ({
            isDragging: monitor.isDragging(),
        }),
    })
    const loadSVG = imageName => {
        setItemImage(images(`./${imageName}.svg`))
    }

    const loadImage = imageName => {
        switch (imageName) {
        case 1:
            loadSVG('glasses')
            break
        case 2:
            loadSVG('tie')
            break
        case 3:
            loadSVG('vest')
            break
        case 4:
            loadSVG('tshirt')
            break
        case 5:
            loadSVG('visa-card')
            break
        case 6:
            loadSVG('cap')
            break
        case 7:
            loadSVG('jacket')
            break
        case 8:
            loadSVG('pants')
            break
        case 9:
            loadSVG('shoes')
            break
        case 10:
            loadSVG('chain')
            break
        case 11:
            loadSVG('apple-watch')
            break
        case 12:
            loadSVG('arm')
            break
        case 13:
            loadSVG('backpack')
            break
        case 14:
            loadSVG('mask')
            break
        case 15:
            loadSVG('phone')
            break
        case 16:
            loadSVG('passport')
            break
        case 54:
            loadSVG('keycar')
            break
        case 59:
            loadSVG('keyhome')
            break
        default:
            setItemImage(images(`./items/${imageName}.png`))
        }
    }

    const showModal = active => {
        inv.showModal(active, props, ref.current.getBoundingClientRect())
    }
    const showMenu = active => {
        inv.showItemMenu(active, props, ref.current.getBoundingClientRect())
    }

    const { gridX, gridY, width, height, layout, itemId, parentId, sqlId, inVehicle } = props
    useEffect(() => {
        loadImage(itemId)
    }, [])
    const { margin, itemSize } = layout
    const realM = (itemId >= 1 && (itemId <= 16 || itemId === 54 || itemId === 59) && parentId === -1) ? 0 : margin
    const { x, y } = calGridItemPosition((gridX < 0) ? 0 : gridX, (gridY < 0) ? 0 : gridY, realM, itemSize)
    const { wPx, hPx } = calWHtoPx(width, height, realM, itemSize)
    const realW = (itemId >= 1 && (itemId <= 16 || itemId === 54 || itemId === 59) && parentId === -1 && (inVehicle === false || !inVehicle)) ? '100%' : wPx
    const realH = (itemId >= 1 && (itemId <= 16 || itemId === 54 || itemId === 59) && parentId === -1 && (inVehicle === false || !inVehicle)) ? '100%' : hPx
    drag(ref)
    // loadImage(itemId)
    return (
        <React.Fragment>
            <div
                ref={ref}
                onMouseEnter={() => showModal(true)}
                onMouseLeave={() => showModal(false)}
                onContextMenu={() => showMenu(true)}
                role="presentation"
                key={sqlId}
                className="card"
                style={{
                    width: realW,
                    height: realH,
                    opacity: isDragging ? 0.4 : 1,
                    transform: `translate(${x}px, ${y}px)`,
                }}
            >
                <div
                    className={`${itemId <= 16 || itemId === 54 || itemId === 59 ? 'svgImage' : 'pngImage'}`}
                    style={{
                        [(itemId > 16 && itemId !== 54 && itemId !== 59 ? 'backgroundImage' : 'WebkitMaskImage')]:
                        itemImage ? `url(${itemImage})` : '',
                        backgroundSize: 'contain',
                        backgroundRepeat: 'no-repeat',
                        backgroundPosition: 'center',
                    }}
                />
                <InventoryMergeLayer
                    key={sqlId}
                    id={sqlId}
                    type="mergeLayer"
                    index={sqlId}
                    inVehicle={!!inVehicle}
                />
            </div>
        </React.Fragment>

    )
}
Example #25
Source File: MovablePanel.jsx    From ashteki with GNU Affero General Public License v3.0 4 votes vote down vote up
MovablePanel = ({ children, name, onCloseClick, side, title }) => {
    const key = `${name}-${side}`;
    const savedStyle = localStorage.getItem(key);
    const style = (savedStyle && JSON.parse(savedStyle)) || PopupDefaults[key];

    if (style) {
        if (style.left >= window.innerWidth) {
            style.left = window.innerWidth - 50;
        }

        if (style.top >= window.innerHeight) {
            style.top = window.innerHeight - 50;
        }
    }

    const [position, setPosition] = useState(Object.assign({}, style));
    const popupRef = useRef(null);

    const getStyle = (offset) => {
        const style = {
            left: Math.max(offset.x, 10),
            top: Math.max(offset.y, 50),
            position: 'fixed'
        };

        const popup = $(popupRef.current);

        style.top -= popup.height();
        if (style.top < 50) {
            style.top = 50;
        }

        if (style.left + popup.width() > window.innerWidth) {
            style.left = window.innerWidth - popup.width();
        }

        if (style.top + 50 > window.innerHeight) {
            style.top = window.innerHeight - 50;
        }

        return style;
    };

    const [{ isDragging, dragOffset }, drag] = useDrag({
        item: { name: key, type: ItemTypes.PANEL },
        collect: (monitor) => {
            return {
                isDragging: monitor.isDragging(),
                dragOffset: monitor.getSourceClientOffset()
            };
        },
        end: (_, monitor) => {
            const offset = monitor.getSourceClientOffset();
            const style = getStyle(offset);

            localStorage.setItem(`${key}`, JSON.stringify(style));
        }
    });

    useEffect(() => {
        if (isDragging) {
            let style = getStyle(dragOffset);

            setPosition(style);
        }
    }, [dragOffset, isDragging]);

    let content = (
        <div ref={popupRef}>
            <div ref={drag} className='panel panel-primary' style={position}>
                <div className='panel-heading' onClick={(event) => event.stopPropagation()}>
                    <span className='text-center'>{title}</span>
                    <span className='float-right'>
                        <a className='close-button' onClick={onCloseClick}>
                            <FontAwesomeIcon icon={faTimes} />
                        </a>
                    </span>
                </div>
                {children}
            </div>
        </div>
    );

    return content;
}