react-dnd#DropTargetMonitor TypeScript Examples
The following examples show how to use
react-dnd#DropTargetMonitor.
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.tsx From hive with MIT License | 6 votes |
widgetTarget = {
canDrop() {
return false;
},
hover(props: Props, monitor: DropTargetMonitor) {
const { id: draggedId } = monitor.getItem();
const overId = props.model.uuid;
if (draggedId !== overId) {
const overIndex = props.dashboardView.currentPage.findWidgetIndex(overId);
props.dashboardView.currentPage.moveWidget(draggedId, overIndex);
}
},
}
Example #2
Source File: navigator-item-dnd-container.tsx From utopia with MIT License | 6 votes |
function onDrop(
propsOfDraggedItem: NavigatorItemDragAndDropWrapperProps,
propsOfDropTargetItem: NavigatorItemDragAndDropWrapperProps,
monitor: DropTargetMonitor,
component: HTMLDivElement | null,
) {
if (monitor != null && component != null) {
const dragSelections = propsOfDraggedItem.getDragSelections()
const filteredSelections = dragSelections.filter((selection) =>
canDrop(propsOfDraggedItem, selection.elementPath),
)
const draggedElements = filteredSelections.map((selection) => selection.elementPath)
const clearHintAction = showNavigatorDropTargetHint(null, null)
const target = propsOfDropTargetItem.elementPath
switch (propsOfDropTargetItem.appropriateDropTargetHint?.type) {
case 'before':
return propsOfDraggedItem.editorDispatch(
[placeComponentsBefore(draggedElements, target), clearHintAction],
'everyone',
)
case 'after':
return propsOfDraggedItem.editorDispatch(
[placeComponentsAfter(draggedElements, target), clearHintAction],
'everyone',
)
case 'reparent':
return propsOfDraggedItem.editorDispatch(
[reparentComponents(draggedElements, target), clearHintAction],
'everyone',
)
default:
return propsOfDraggedItem.editorDispatch([clearHintAction], 'everyone')
}
}
}
Example #3
Source File: DragItem.tsx From gio-design with Apache License 2.0 | 6 votes |
DragItem: React.FC<DragItemProps> = (props) => {
const { label, value, onMoved, index, disabled, ...rest } = props;
const prefixCls = `${usePrefixCls(PREFIX)}`;
const ref = useRef<HTMLDivElement>(null);
const [{ handlerId }, drop] = useDrop({
accept: 'drag-item',
collect(monitor) {
return {
handlerId: monitor.getHandlerId(),
};
},
hover(item: { index: number; type: string; id: string }, monitor: DropTargetMonitor) {
const dragIndex = item.index;
const hoverIndex = index;
if (dragIndex === hoverIndex) {
return;
}
const hoverBoundingRect = ref.current?.getBoundingClientRect() || { bottom: 0, top: 0 };
const hoverMiddleY = (hoverBoundingRect.bottom - hoverBoundingRect.top) / 2;
const clientOffset = monitor.getClientOffset();
const hoverClientY = (clientOffset as XYCoord).y - hoverBoundingRect.top;
// Dragging upwards or downwards
if ((dragIndex < hoverIndex && hoverClientY < hoverMiddleY) || (dragIndex > hoverIndex && hoverClientY > hoverMiddleY)) {
return
};
onMoved?.(dragIndex as number, hoverIndex);
// eslint-disable-next-line no-param-reassign
item.index = hoverIndex;
},
});
const [, drag] = useDrag({
item: { type: 'drag-item', id: value, index },
collect: (monitor: DragSourceMonitor) => ({
isDragging: monitor.isDragging(),
}),
canDrag: !disabled,
});
drag(drop(ref));
return (
<div
className={classNames(`${prefixCls}--item`, `${prefixCls}--item--drag`, {
[`${prefixCls}--item--disabled`]: disabled,
})}
ref={ref}
data-handler-id={handlerId}
>
<DragOutlined
className={classNames(`${prefixCls}--item--drag--icon`, {
[`${prefixCls}--item--drag--icon--disabled`]: disabled,
})}
color="#ADB2C2"
size="14px"
/>
<Item label={label} value={value} disabled={disabled} {...rest} />
</div>
);
}
Example #4
Source File: useDropComponent.ts From openchakra with MIT License | 6 votes |
useDropComponent = (
componentId: string,
accept: (ComponentType | MetaComponentType)[] = rootComponents,
canDrop: boolean = true,
) => {
const dispatch = useDispatch()
const [{ isOver }, drop] = useDrop({
accept,
collect: monitor => ({
isOver: monitor.isOver({ shallow: true }) && monitor.canDrop(),
}),
drop: (item: ComponentItemProps, monitor: DropTargetMonitor) => {
if (!monitor.isOver()) {
return
}
if (item.isMoved) {
dispatch.components.moveComponent({
parentId: componentId,
componentId: item.id,
})
} else if (item.isMeta) {
dispatch.components.addMetaComponent(builder[item.type](componentId))
} else {
dispatch.components.addComponent({
parentName: componentId,
type: item.type,
rootParentType: item.rootParentType,
})
}
},
canDrop: () => canDrop,
})
return { drop, isOver }
}
Example #5
Source File: DropHolder.tsx From datart with Apache License 2.0 | 6 votes |
DropHolder: React.FC<DropHolderProps> = memo(
({ tabItem, parentId }) => {
const [{ isOver, canDrop }, refDrop] = useDrop(
() => ({
accept: CONTAINER_TAB,
item: { tabItem, parentId },
drop: () => ({ tabItem, parentId }),
canDrop: (item: any) => {
if (CanDropToWidgetTypes.includes(item.type)) {
return true;
}
return false;
},
collect: (monitor: DropTargetMonitor) => ({
isOver: monitor.isOver(),
canDrop: monitor.canDrop(),
}),
}),
[],
);
const bgColor = useMemo(() => {
let color = 'transparent';
if (canDrop) {
color = '#f1e648c7';
if (isOver) {
color = '#1bcf81d3';
}
}
return color;
}, [isOver, canDrop]);
return (
<DropWrap ref={refDrop} bgColor={bgColor}>
<div className="center">将组件拖入该区域</div>
</DropWrap>
);
},
)
Example #6
Source File: use-hooks.tsx From erda-ui with GNU Affero General Public License v3.0 | 5 votes |
useListDnD = ({ type, index, onMove, collect }: IDragProps) => {
const dragRef = useRef<HTMLDivElement>(null);
const [, drop] = useDrop({
accept: type,
hover(item: DragItem, monitor: DropTargetMonitor) {
if (!dragRef.current) {
return;
}
const dragIndex = item.index;
const hoverIndex = index;
// Don't replace items with themselves
if (dragIndex === hoverIndex) {
return;
}
// Determine rectangle on screen
const hoverBoundingRect = dragRef.current!.getBoundingClientRect();
// Get vertical middle
const hoverMiddleY = (hoverBoundingRect.bottom - hoverBoundingRect.top) / 2;
// Determine mouse position
const clientOffset = monitor.getClientOffset();
// Get pixels to the top
const hoverClientY = (clientOffset as XYCoord).y - hoverBoundingRect.top;
// Only perform the move when the mouse has crossed half of the items height
// When dragging downwards, only move when the cursor is below 50%
// When dragging upwards, only move when the cursor is above 50%
// Dragging downwards
if (dragIndex < hoverIndex && hoverClientY < hoverMiddleY) {
return;
}
// Dragging upwards
if (dragIndex > hoverIndex && hoverClientY > hoverMiddleY) {
return;
}
// Time to actually perform the action
onMove(dragIndex, hoverIndex);
// Note: we're mutating the monitor item here!
// Generally it's better to avoid mutations,
// but it's good here for the sake of performance
// to avoid expensive index searches.
item.index = hoverIndex;
},
});
const [collectedProps, drag, previewRef] = useDrag({
item: { index, type },
collect,
});
drag(drop(dragRef));
return [dragRef, previewRef, collectedProps];
}
Example #7
Source File: DragAndDropTreeComponent.tsx From frontend-sample-showcase with MIT License | 5 votes |
DragAndDropNode: React.FC<TreeNodeRendererProps> = (props) => {
const { treeModelSource, treeNodeLoader, isDragging, setDragging } = React.useContext(dragDropContext)!;
// Make node draggable
const [, dragSourceRef] = useDrag({
item: { type: "tree-node", id: props.node.id },
begin: () => setDragging(true),
end: () => setDragging(false),
});
// Make node accept drop events
const [{ isHovered }, dropTargetRef] = useDrop({
accept: "tree-node",
hover: handleHover,
canDrop: handleCanDrop,
drop: handleDrop,
collect: (monitor) => ({ isHovered: monitor.isOver() }),
});
const [canDrop, setCanDrop] = React.useState(false);
function handleCanDrop(item: NodeDragObject): boolean {
// Do not allow dropping a node in such a way that would create a parent-child relationship cycle
const isDroppingOnSelf = props.node.id === item.id && dropArea === DropArea.Inside;
const newCanDrop = !isDroppingOnSelf && !areNodesRelated(treeModelSource.getModel(), item.id, props.node.id);
setCanDrop(newCanDrop);
return newCanDrop;
}
const elementRef = React.useRef<HTMLDivElement>(null);
const [dropArea, setDropArea] = React.useState<DropArea>(DropArea.Inside);
function handleHover(item: NodeDragObject, monitor: DropTargetMonitor): void {
// Determine which drop area is hovered and whether we can drop the node there
const cursorY = monitor.getClientOffset()?.y;
const dropTargetY = elementRef.current?.getBoundingClientRect().y;
if (cursorY !== undefined && dropTargetY !== undefined) {
setDropArea(determineDropArea(25, 7, cursorY - dropTargetY));
handleCanDrop(item);
}
}
function handleDrop(item: NodeDragObject): void {
// The main entry point for drop event handling
const { parentId, index } = getDropLocation(treeModelSource.getModel(), props.node, dropArea);
moveNode(treeModelSource, treeNodeLoader, item.id, parentId, index)
.catch((error) => {
// eslint-disable-next-line no-console
console.error(error);
});
}
const isDropAreaDisplayed = isHovered && canDrop;
const nodeStyle: React.CSSProperties = {
height: 25,
...(isDropAreaDisplayed && dropArea === DropArea.Inside && { background: "var(--buic-row-hover)" }),
};
return (
<div ref={mergeRefs([dragSourceRef, dropTargetRef, elementRef])}>
<div style={{ height: 0 }}>
{isDropAreaDisplayed && dropArea === DropArea.Above && <NodeInsertMarker topOffset={0} />}
{isDropAreaDisplayed && dropArea === DropArea.Below && <NodeInsertMarker topOffset={25} />}
</div>
<BasicTreeNode style={nodeStyle} isHoverDisabled={isDragging} {...props} />
</div>
);
}
Example #8
Source File: navigator-item-dnd-container.tsx From utopia with MIT License | 4 votes |
function onHover(
propsOfDraggedItem: NavigatorItemDragAndDropWrapperProps,
propsOfDropTargetItem: NavigatorItemDragAndDropWrapperProps,
monitor: DropTargetMonitor | null,
component: HTMLDivElement | null,
): void {
if (
monitor != null &&
component != null &&
propsOfDraggedItem
.getDragSelections()
.some((selection) => canDrop(propsOfDraggedItem, selection.elementPath))
) {
// React DnD necessitates the two divs around the actual navigator item,
// so we need to drill down to the navigator elements themselves which have real dimensions.
const dropDomNode = ReactDOM.findDOMNode(component)
const dragDomNode = dropDomNode?.firstChild
const domNode = dragDomNode?.firstChild
if (domNode == null || typeof domNode === 'string') {
return
}
const dropTargetRectangle = (domNode as HTMLElement).getBoundingClientRect()
const cursor = monitor.getClientOffset()
const targetAction = propsOfDraggedItem.highlighted
? []
: [EditorActions.setHighlightedView(propsOfDraggedItem.elementPath)]
const canReparent = propsOfDraggedItem
.getDragSelections()
.every(
(dragSelectedItem: DragSelection) =>
!EP.pathsEqual(propsOfDraggedItem.elementPath, dragSelectedItem.elementPath) &&
propsOfDraggedItem.supportsChildren,
)
const numberOfAreasToCut = canReparent ? 3 : 2
if (cursor == null) {
return
}
if (isCursorInTopArea(dropTargetRectangle, cursor.y, numberOfAreasToCut)) {
if (propsOfDraggedItem.appropriateDropTargetHint?.type !== 'before') {
propsOfDraggedItem.editorDispatch(
[
...targetAction,
showNavigatorDropTargetHint('before', propsOfDropTargetItem.elementPath),
],
'leftpane',
)
}
} else if (
isCursorInBottomArea(dropTargetRectangle, cursor.y, numberOfAreasToCut) &&
(propsOfDraggedItem.noOfChildren === 0 || propsOfDraggedItem.collapsed)
) {
if (
isCursorInLeftAreaOfItem(cursor.x, propsOfDraggedItem.elementPath) &&
EP.parentPath(propsOfDraggedItem.elementPath) != null
) {
const maximumTargetDepth = propsOfDraggedItem.getMaximumDistance(
EP.toComponentId(propsOfDraggedItem.elementPath),
0,
)
const cursorTargetDepth = getTargetDepthFromMousePosition(
cursor.x,
propsOfDraggedItem.elementPath,
)
const targetDistance = Math.min(cursorTargetDepth, maximumTargetDepth)
const targetTP = EP.getNthParent(propsOfDraggedItem.elementPath, targetDistance)
if (
propsOfDraggedItem.appropriateDropTargetHint?.type !== 'after' ||
!EP.pathsEqual(propsOfDraggedItem.appropriateDropTargetHint?.target, targetTP)
) {
propsOfDraggedItem.editorDispatch(
[...targetAction, showNavigatorDropTargetHint('after', targetTP)],
'leftpane',
)
}
} else if (
propsOfDraggedItem.appropriateDropTargetHint?.type !== 'after' ||
!EP.pathsEqual(
propsOfDraggedItem.appropriateDropTargetHint?.target,
propsOfDropTargetItem.elementPath,
)
) {
propsOfDraggedItem.editorDispatch(
[
...targetAction,
showNavigatorDropTargetHint('after', propsOfDropTargetItem.elementPath),
],
'leftpane',
)
}
} else if (canReparent) {
if (propsOfDraggedItem.appropriateDropTargetHint?.type !== 'reparent') {
propsOfDraggedItem.editorDispatch(
[
...targetAction,
showNavigatorDropTargetHint('reparent', propsOfDropTargetItem.elementPath),
],
'leftpane',
)
}
} else if (propsOfDraggedItem.appropriateDropTargetHint?.type !== null) {
propsOfDraggedItem.editorDispatch([showNavigatorDropTargetHint(null, null)], 'leftpane')
}
}
}
Example #9
Source File: DropTarget.tsx From gear-js with GNU General Public License v3.0 | 4 votes |
DropTarget = ({ type, setDroppedFile }: Props) => {
const alert = useAlert();
const [wrongFormat, setWrongFormat] = useState(false);
const inputRef = useRef<HTMLInputElement>(null);
if (wrongFormat) {
setTimeout(() => setWrongFormat(false), 3000);
}
const checkFileFormat = useCallback((files: any) => {
if (typeof files[0]?.name === 'string') {
const fileExt: string = files[0].name.split('.').pop().toLowerCase();
return fileExt !== 'wasm';
}
return true;
}, []);
const handleFilesUpload = useCallback(
(file: File) => {
setDroppedFile({ file, type });
},
[setDroppedFile, type]
);
const emulateInputClick = () => {
inputRef.current?.click();
};
const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {
const {
target: { files },
} = event;
if (files?.length) {
const isCorrectFormat = checkFileFormat(files);
setWrongFormat(isCorrectFormat);
if (!isCorrectFormat) {
handleFilesUpload(files[0]);
// since type='file' input can't be controlled,
// reset it's value to trigger onChange again in case the same file selected twice
event.target.value = '';
} else {
alert.error('Wrong file format');
setWrongFormat(false);
}
}
};
const handleFileDrop = useCallback(
(item) => {
if (item) {
const { files } = item;
const isCorrectFormat = checkFileFormat(files);
setWrongFormat(isCorrectFormat);
if (!isCorrectFormat) {
handleFilesUpload(files[0]);
} else {
alert.error('Wrong file format');
setWrongFormat(false);
}
}
},
// eslint-disable-next-line react-hooks/exhaustive-deps
[checkFileFormat, handleFilesUpload]
);
const [{ canDrop, isOver }, drop] = useDrop(
() => ({
accept: [NativeTypes.FILE],
drop(item: { files: any[] }) {
if (handleFileDrop) {
handleFileDrop(item);
}
},
collect: (monitor: DropTargetMonitor) => ({
isOver: monitor.isOver(),
canDrop: monitor.canDrop(),
}),
}),
[handleFileDrop]
);
const isActive = canDrop && isOver;
const className = clsx(styles.drop, isActive && styles.active);
const isProgramUpload = type === UploadTypes.PROGRAM;
const buttonText = `Upload ${type}`;
return (
<div className={className} ref={drop}>
{isActive ? (
<div className={styles.file}>
<span className={styles.text}>Drop your .wasm files here to upload</span>
</div>
) : (
<div className={styles.noFile}>
<input className={styles.input} ref={inputRef} type="file" onChange={handleChange} />
<Button
text={buttonText}
icon={isProgramUpload ? upload : editor}
color={isProgramUpload ? 'primary' : 'secondary'}
onClick={emulateInputClick}
/>
<div className={styles.text}>{`Click “${buttonText}” to browse or drag and drop your .wasm files here`}</div>
</div>
)}
</div>
);
}
Example #10
Source File: DraggableItem.tsx From querybook with Apache License 2.0 | 4 votes |
export function DraggableItem<T extends { id: any }>({
children,
className,
index,
originalIndex,
onHoverMove,
onMove,
draggableItemType,
resetHoverItems,
itemInfo,
canDrop,
}: IDraggableItemProps<T> & { children: React.ReactNode }) {
const ref = useRef<HTMLLIElement>(null);
const [{ isDragging }, drag] = useDrag({
type: draggableItemType,
item: { type: draggableItemType, index, originalIndex, itemInfo },
collect: (monitor) => ({
isDragging: !!monitor.isDragging(),
}),
end: (_, monitor) => {
resetHoverItems();
},
});
const [, drop] = useDrop({
accept: draggableItemType,
canDrop,
drop: (item: IDragItem) => {
onMove(item.originalIndex, item.index);
},
hover: (item: IDragItem, monitor: DropTargetMonitor) => {
if (!ref.current) {
return;
}
if (!monitor.canDrop()) {
return;
}
const dragIndex = item.index;
const hoverIndex = index;
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 as XYCoord).y - hoverBoundingRect.top;
// Only perform the move when the mouse has crossed half of the items height
// When dragging downwards, only move when the cursor is below 50%
// When dragging upwards, only move when the cursor is above 50%
// Dragging downwards
if (dragIndex < hoverIndex && hoverClientY < hoverMiddleY) {
return;
}
// Dragging upwards
if (dragIndex > hoverIndex && hoverClientY > hoverMiddleY) {
return;
}
// Time to actually perform the action
onHoverMove(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;
},
});
drag(drop(ref));
// To hide the item that is being dragged
const opacity = isDragging ? 0 : 1;
return (
<li
className={'DraggableItem ' + (className ?? '')}
style={{ opacity }}
ref={ref}
>
{children}
</li>
);
}
Example #11
Source File: ChartDraggableTargetContainer.tsx From datart with Apache License 2.0 | 4 votes |
ChartDraggableTargetContainer: FC<ChartDataConfigSectionProps> = memo(function ChartDraggableTargetContainer({ ancestors, modalSize, config, translate: t = (...args) => args?.[0], onConfigChanged, }) { const { dataset } = useContext(ChartDatasetContext); const { drillOption } = useContext(ChartDrillContext); const { dataView, availableSourceFunctions } = useContext(VizDataViewContext); const [currentConfig, setCurrentConfig] = useState(config); const [showModal, contextHolder] = useFieldActionModal({ i18nPrefix: 'viz.palette.data.enum.actionType', }); const { aggregation } = useContext(ChartAggregationContext); useEffect(() => { setCurrentConfig(config); }, [config]); const [{ isOver, canDrop }, drop] = useDrop( () => ({ accept: [ CHART_DRAG_ELEMENT_TYPE.DATASET_COLUMN, CHART_DRAG_ELEMENT_TYPE.DATASET_COLUMN_GROUP, CHART_DRAG_ELEMENT_TYPE.DATA_CONFIG_COLUMN, ], drop(item: ChartDataSectionField & DragItem, monitor) { let items = Array.isArray(item) ? item : [item]; let needDelete = true; if ( monitor.getItemType() === CHART_DRAG_ELEMENT_TYPE.DATASET_COLUMN ) { const currentColumns: ChartDataSectionField[] = ( currentConfig.rows || [] ).concat( items.map(val => { let config: ChartDataSectionField = { uid: uuidv4(), ...val, aggregate: getDefaultAggregate(val), }; if ( val.category === ChartDataViewFieldCategory.DateLevelComputedField ) { config.colName = `${val.colName}(${t(val.expression)})`; config.expression = `${val.expression}(${val.colName})`; config.field = val.colName; } return config; }), ); updateCurrentConfigColumns(currentConfig, currentColumns, true); } else if ( monitor.getItemType() === CHART_DRAG_ELEMENT_TYPE.DATASET_COLUMN_GROUP ) { const hierarchyChildFields = items?.[0]?.children || []; const currentColumns: ChartDataSectionField[] = ( currentConfig.rows || [] ).concat( hierarchyChildFields.map(val => ({ uid: uuidv4(), ...val, aggregate: getDefaultAggregate(val), })), ); updateCurrentConfigColumns(currentConfig, currentColumns, true); } else if ( monitor.getItemType() === CHART_DRAG_ELEMENT_TYPE.DATA_CONFIG_COLUMN ) { const originItemIndex = (currentConfig.rows || []).findIndex( r => r.uid === item.uid, ); if (originItemIndex > -1) { const needRefreshData = currentConfig?.type === ChartDataSectionType.GROUP; needDelete = false; const currentColumns = updateBy( currentConfig?.rows || [], draft => { draft.splice(originItemIndex, 1); item.aggregate = getDefaultAggregate(item); return draft.splice(item?.index!, 0, item); }, ); updateCurrentConfigColumns( currentConfig, currentColumns, needRefreshData, ); } else { const currentColumns = updateBy( currentConfig?.rows || [], draft => { item.aggregate = getDefaultAggregate(item); return draft.splice(item?.index!, 0, item); }, ); updateCurrentConfigColumns(currentConfig, currentColumns); } } return { delete: needDelete }; }, canDrop: (item: ChartDataSectionField, monitor) => { let items = Array.isArray(item) ? item : [item]; if ( [CHART_DRAG_ELEMENT_TYPE.DATASET_COLUMN_GROUP].includes( monitor.getItemType() as any, ) && ![ ChartDataSectionType.GROUP, ChartDataSectionType.COLOR, ChartDataSectionType.MIXED, ].includes(currentConfig.type as ChartDataSectionType) ) { return false; } if ( typeof currentConfig.actions === 'object' && !items.every(val => val.type in (currentConfig.actions || {})) ) { //zh: 判断现在拖动的数据项是否可以拖动到当前容器中 en: Determine whether the currently dragged data item can be dragged into the current container return false; } // if ( // typeof currentConfig.actions === 'object' && // !(item.type in currentConfig.actions) // ) { // return false; // } if (currentConfig.allowSameField) { return true; } if ( monitor.getItemType() === CHART_DRAG_ELEMENT_TYPE.DATA_CONFIG_COLUMN ) { return true; } if ( items[0].category === ChartDataViewFieldCategory.DateLevelComputedField ) { const colNames = currentConfig.rows?.map(col => col.colName); return colNames ? colNames.every(v => !v?.includes(items[0].colName)) : true; } const exists = currentConfig.rows?.map(col => col.colName); return items.every(i => !exists?.includes(i.colName)); }, collect: (monitor: DropTargetMonitor) => ({ isOver: monitor.isOver(), canDrop: monitor.canDrop(), }), }), [onConfigChanged, currentConfig, dataView, dataset], ); const updateCurrentConfigColumns = ( currentConfig, newColumns, refreshDataset = false, ) => { const newCurrentConfig = updateByKey(currentConfig, 'rows', newColumns); setCurrentConfig(newCurrentConfig); onConfigChanged?.(ancestors, newCurrentConfig, refreshDataset); }; const getDefaultAggregate = (item: ChartDataSectionField) => { if ( currentConfig?.type === ChartDataSectionType.AGGREGATE || currentConfig?.type === ChartDataSectionType.SIZE || currentConfig?.type === ChartDataSectionType.INFO || currentConfig?.type === ChartDataSectionType.MIXED ) { if ( currentConfig.disableAggregate || item.category === ChartDataViewFieldCategory.AggregateComputedField ) { return; } if (item.aggregate) { return item.aggregate; } let aggType: string = ''; if (currentConfig?.actions instanceof Array) { currentConfig?.actions?.find( type => type === ChartDataSectionFieldActionType.Aggregate || type === ChartDataSectionFieldActionType.AggregateLimit, ); } else if (currentConfig?.actions instanceof Object) { aggType = currentConfig?.actions?.[item?.type]?.find( type => type === ChartDataSectionFieldActionType.Aggregate || type === ChartDataSectionFieldActionType.AggregateLimit, ); } if (aggType) { return AggregateFieldSubAggregateType?.[aggType]?.[0]; } } }; const onDraggableItemMove = (dragIndex: number, hoverIndex: number) => { const draggedItem = currentConfig.rows?.[dragIndex]; if (draggedItem) { const newCurrentConfig = updateBy(currentConfig, draft => { const columns = draft.rows || []; columns.splice(dragIndex, 1); columns.splice(hoverIndex, 0, draggedItem); }); setCurrentConfig(newCurrentConfig); } else { // const placeholder = { // uid: CHARTCONFIG_FIELD_PLACEHOLDER_UID, // colName: 'Placeholder', // category: 'field', // type: 'STRING', // } as any; // const newCurrentConfig = updateBy(currentConfig, draft => { // const columns = draft.rows || []; // if (dragIndex) { // columns.splice(dragIndex, 1); // } // columns.splice(hoverIndex, 0, placeholder); // }); // setCurrentConfig(newCurrentConfig); } }; const handleOnDeleteItem = config => () => { if (config.uid) { let newCurrentConfig = updateBy(currentConfig, draft => { draft.rows = draft.rows?.filter(c => c.uid !== config.uid); if ( config.category === ChartDataViewFieldCategory.DateLevelComputedField ) { draft.replacedColName = config.colName; } }); setCurrentConfig(newCurrentConfig); onConfigChanged?.(ancestors, newCurrentConfig, true); } }; const renderDropItems = () => { if ( !currentConfig.rows || !currentConfig?.rows?.filter(Boolean)?.length ) { const fieldCount = reachLowerBoundCount(currentConfig?.limit, 0); if (fieldCount > 0) { return ( <DropPlaceholder> {t('dropCount', undefined, { count: fieldCount })} </DropPlaceholder> ); } return <DropPlaceholder>{t('drop')}</DropPlaceholder>; } return currentConfig.rows?.map((columnConfig, index) => { return ( <ChartDraggableElement key={columnConfig.uid} id={columnConfig.uid} index={index} config={columnConfig} content={() => { const contentProps = { modalSize: modalSize, config: currentConfig, columnConfig: columnConfig, ancestors: ancestors, aggregation: aggregation, availableSourceFunctions, onConfigChanged: onConfigChanged, handleOpenActionModal: handleOpenActionModal, }; return columnConfig.category === ChartDataViewFieldCategory.Hierarchy ? ( <ChartDraggableElementHierarchy {...contentProps} /> ) : ( <ChartDraggableElementField {...contentProps} /> ); }} moveCard={onDraggableItemMove} onDelete={handleOnDeleteItem(columnConfig)} ></ChartDraggableElement> ); }); }; const renderDrillFilters = () => { if (currentConfig?.type !== ChartDataSectionType.FILTER) { return; } return getDillConditions()?.map(drill => { const field = drill.field; return ( <StyledDillFilter type={field.type}> {getColumnRenderName(field)} </StyledDillFilter> ); }); }; const getDillConditions = () => { return drillOption ?.getAllDrillDownFields() ?.filter(drill => Boolean(drill?.condition)); }; const handleFieldConfigChanged = ( columnUid: string, fieldConfig: ChartDataSectionField, needRefresh?: boolean, ) => { if (!fieldConfig) { return; } const newConfig = updateDataConfigByField( columnUid, currentConfig, fieldConfig, ); onConfigChanged?.(ancestors, newConfig, needRefresh); }; const handleOpenActionModal = (uid: string) => (actionType: ValueOf<typeof ChartDataSectionFieldActionType>) => { (showModal as Function)( uid, actionType, currentConfig, handleFieldConfigChanged, dataset, dataView, modalSize, aggregation, ); }; return ( <StyledContainer ref={drop} isOver={isOver} canDrop={canDrop}> {renderDropItems()} {renderDrillFilters()} {contextHolder} </StyledContainer> ); })
Example #12
Source File: DraggableItem.tsx From datart with Apache License 2.0 | 4 votes |
DraggableItem: FC<DraggableItemProps> = ({
id,
text,
index,
moveCard,
onDrop,
}) => {
const ref = useRef<HTMLDivElement>(null);
const [{ handlerId }, drop] = useDrop({
accept: 'ItemTypes.Item',
collect(monitor) {
return {
handlerId: monitor.getHandlerId(),
};
},
hover(item: Item, monitor: DropTargetMonitor) {
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 as XYCoord).y - hoverBoundingRect.top;
// Only perform the move when the mouse has crossed half of the items height
// When dragging downwards, only move when the cursor is below 50%
// When dragging upwards, only move when the cursor is above 50%
// Dragging downwards
if (dragIndex < hoverIndex && hoverClientY < hoverMiddleY) {
return;
}
// Dragging upwards
if (dragIndex > hoverIndex && hoverClientY > hoverMiddleY) {
return;
}
// Time to actually perform the action
moveCard && 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;
},
drop(item: Item, monitor: DropTargetMonitor) {
onDrop && onDrop(item.id, item.index);
},
});
const [{ isDragging }, drag] = useDrag({
type: 'ItemTypes.Item',
item: () => {
return { id, index };
},
collect: (monitor: any) => ({
isDragging: monitor.isDragging(),
}),
});
const opacity = isDragging ? 0 : 1;
drag(drop(ref));
return (
<div ref={ref} style={{ ...style, opacity }} data-handler-id={handlerId}>
{text}
</div>
);
}
Example #13
Source File: NameItem.tsx From datart with Apache License 2.0 | 4 votes |
NameItem: React.FC<NameItemProps> = ({
index,
card,
zIndex,
moveCard,
moveEnd,
widgetType,
}) => {
const widget = useContext(WidgetContext);
const ItemRef = useRef<HTMLDivElement>(null);
const [{ handlerId }, drop] = useDrop({
accept: 'WidgetNameListDnd',
collect(monitor) {
return {
handlerId: monitor.getHandlerId(),
};
},
hover(item: DragItem, monitor: DropTargetMonitor) {
if (!ItemRef.current) {
return;
}
const dragIndex = item.index;
const hoverIndex = index;
const dragZIndex = item.zIndex;
const hoverZIndex = card.index;
const hoverSelected = card.selected;
// Don't replace items with themselves
if (dragIndex === hoverIndex) {
return;
}
// Determine rectangle on screen
const hoverBoundingRect = ItemRef.current?.getBoundingClientRect();
// Get vertical middle
const hoverMiddleY =
(hoverBoundingRect.bottom - hoverBoundingRect.top) / 2;
// Determine mouse position
const clientOffset = monitor.getClientOffset();
// Get pixels to the top
const hoverClientY = (clientOffset as XYCoord).y - hoverBoundingRect.top;
// Only perform the move when the mouse has crossed half of the items height
// When dragging downwards, only move when the cursor is below 50%
// When dragging upwards, only move when the cursor is above 50%
// Dragging downwards
if (dragIndex < hoverIndex && hoverClientY < hoverMiddleY) {
return;
}
// Dragging upwards
if (dragIndex > hoverIndex && hoverClientY > hoverMiddleY) {
return;
}
// Time to actually perform the action
moveCard(dragIndex, hoverIndex, dragZIndex, hoverZIndex);
// Note: we're mutating the monitor item here!
// Generally it's better to avoid mutations,
// but it's good here for the sake of performance
// to avoid expensive index searches.
item.index = hoverIndex;
item.zIndex = hoverZIndex;
item.selected = hoverSelected;
},
});
const [{ isDragging }, drag] = useDrag({
type: 'WidgetNameListDnd',
item: () => {
return { id: card.id, index, zIndex, selected: card.selected };
},
collect: (monitor: any) => ({
isDragging: monitor.isDragging(),
}),
end() {
moveEnd();
},
});
const opacity = isDragging ? 0.1 : 1;
// 使用 drag 和 drop 包装 ref
drag(drop(ItemRef));
const dispatch = useDispatch();
const selectWidget = useCallback(
(e: React.MouseEvent<HTMLDivElement>) => {
e.stopPropagation();
let newSelected = !card.selected;
if (card.selected) {
newSelected = card.selected;
}
dispatch(
editWidgetInfoActions.selectWidget({
multipleKey: e.shiftKey,
id: card.id,
selected: newSelected,
}),
);
},
[card, dispatch],
);
return (
<ItemWrap
selected={card.selected}
onMouseDown={selectWidget}
onClick={e => e.stopPropagation()}
>
<div
className={classNames('name-item', {
'selected-Item': card.selected,
})}
ref={ItemRef}
data-handler-id={handlerId}
style={{ opacity }}
>
<span className="name" title={card.name || 'untitled-widget'}>
{card.name || 'untitled-widget'}
</span>
<WidgetActionDropdown widget={widget} />
</div>
</ItemWrap>
);
}
Example #14
Source File: ThumbnailItem.tsx From datart with Apache License 2.0 | 4 votes |
ThumbnailItem: React.FC<IProps> = ({
page,
index,
selected,
moveCard,
moveEnd,
}) => {
const dispatch = useDispatch();
const ItemRef = useRef<HTMLDivElement>(null);
const dashboard = useSelector((state: { board: BoardState }) =>
makeSelectBoardConfigById()(state, page.relId),
);
useEffect(() => {
try {
const { thumbnail, name } = dashboard as Dashboard;
dispatch(
storyActions.updateStoryPageNameAndThumbnail({
storyId: page.storyId,
pageId: page.id,
name,
thumbnail,
}),
);
} catch (error) {}
// storyActions.updateStoryPageNameAndThumbnail
}, [dashboard, dispatch, page.id, page.storyId]);
const [{ handlerId }, drop] = useDrop({
accept: 'storyBoardListDnd',
collect(monitor) {
return {
handlerId: monitor.getHandlerId(),
};
},
hover(item: DragItem, monitor: DropTargetMonitor) {
if (!ItemRef.current) {
return;
}
const dragIndex = item.index;
const hoverIndex = page.index;
const hoverSelected = item.selected;
// const dragId = item.id;
// Don't replace items with themselves
if (dragIndex === hoverIndex) {
return;
}
// Determine rectangle on screen
const hoverBoundingRect = ItemRef.current?.getBoundingClientRect();
// Get vertical middle
const hoverMiddleY =
(hoverBoundingRect.bottom - hoverBoundingRect.top) / 2;
// Determine mouse position
const clientOffset = monitor.getClientOffset();
// Get pixels to the top
const hoverClientY = (clientOffset as XYCoord).y - hoverBoundingRect.top;
// Only perform the move when the mouse has crossed half of the items height
// When dragging downwards, only move when the cursor is below 50%
// When dragging upwards, only move when the cursor is above 50%
// Dragging downwards
if (dragIndex < hoverIndex && hoverClientY < hoverMiddleY) {
return;
}
// Dragging upwards
if (dragIndex > hoverIndex && hoverClientY > hoverMiddleY) {
return;
}
// Time to actually perform the action
moveCard(item.id, page.id);
// Note: we're mutating the monitor item here!
// Generally it's better to avoid mutations,
// but it's good here for the sake of performance
// to avoid expensive index searches.
item.index = hoverIndex;
item.selected = hoverSelected;
},
});
const [{ isDragging }, drag] = useDrag({
type: 'storyBoardListDnd',
item: () => {
return {
id: page.id,
index: page.index,
selected: selected,
};
},
collect: (monitor: any) => ({
isDragging: monitor.isDragging(),
}),
end() {
moveEnd();
},
});
const opacity = isDragging ? 0.1 : 1;
// 使用 drag 和 drop 包装 ref
drag(drop(ItemRef));
return (
<ItemWrap selected={selected}>
<div
className="item"
ref={ItemRef}
data-handler-id={handlerId}
style={{ opacity }}
>
<p>{index}</p>
<h4>{page.name}</h4>
</div>
</ItemWrap>
);
}
Example #15
Source File: useDraggable.ts From ui-schema with MIT License | 4 votes |
useDraggable = <C extends HTMLElement = HTMLElement, S extends ItemSpec = ItemSpec>(
{
item,
allowedTypes,
scope: localScope,
refRoot,
}: {
item: S
allowedTypes: string[] | List<string> | undefined
scope?: string
refRoot: React.MutableRefObject<C | null>
}
): {
isOver: boolean
canDrop: boolean
drop: ConnectDropTarget
isDragging: boolean
drag: ConnectDragSource
preview: ConnectDragPreview
setDisableDrag: React.Dispatch<React.SetStateAction<boolean>>
canDrag: boolean
} => {
const [disableDrag, setDisableDrag] = React.useState<boolean>(false)
const {onMove, scope} = useKitDnd<C>()
const [{isOver, canDrop}, drop] = useDrop<S, S, { handlerId: (Identifier | null), isOver: boolean, canDrop: boolean }>(() => ({
accept: localScope ? localScope : (scope ? '_' + scope : '_') as string,
options: {},
collect: (monitor: DropTargetMonitor<C>) => ({
isOver: monitor.isOver({shallow: true}),
canDrop: monitor.canDrop(),
handlerId: monitor.getHandlerId(),
}),
canDrop: (fromItem: S, monitor: DropTargetMonitor<C>) => {
if (!monitor.isOver({shallow: true})) {
return false
}
return (
!fromItem.dataKeys.push(fromItem.index).equals(item.dataKeys.push(item.index)) &&
fromItem.id !== item.id
) && (
!allowedTypes ||
allowedTypes.indexOf(fromItem.type) !== -1
)
},
hover(fromItem: S, monitor: DropTargetMonitor<C>) {
if (monitor.canDrop()) {
onMove({
targetElement: refRoot.current as C,
toItem: item as unknown as S,
fromItem: fromItem as unknown as S,
monitor,
})
}
},
}), [item, localScope, scope, allowedTypes, refRoot])
const [{canDrag, isDragging}, drag, preview] = useDrag<S, S, { isDragging: boolean, canDrag: boolean }>(() => ({
type: localScope ? localScope : (scope ? '_' + scope : '_') as string,
item: {...item},
collect: (monitor: DragSourceMonitor<S>) => ({
isDragging: monitor.isDragging(),
canDrag: monitor.canDrag(),
}),
canDrag: () => {
return !disableDrag
},
isDragging: (monitor: DragSourceMonitor<S>) => {
const {index, dataKeys} = item
const tmpItem = monitor.getItem() as S
if (!tmpItem) return false
let itemDataKeys = tmpItem.dataKeys as List<number>
if (!List.isList(itemDataKeys)) {
itemDataKeys = List(itemDataKeys) as List<number>
}
return tmpItem.dataKeys.push(tmpItem.index).equals(dataKeys.push(index)) &&
itemDataKeys.equals(!List.isList(dataKeys) ? List(dataKeys) : dataKeys)
},
}), [
item, localScope, scope, disableDrag,
])
return {
isOver, canDrop, drop,
isDragging, drag, preview,
setDisableDrag,
// todo: somehow `canDrag` isn't `false` when it is internally `false`
canDrag: canDrag && !disableDrag,
}
}