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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
// 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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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> </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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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>
)
}