Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to change drag dropEffect based on drop targets? #3529

Open
sdt-jchau opened this issue Dec 30, 2022 · 1 comment · May be fixed by #3531
Open

How to change drag dropEffect based on drop targets? #3529

sdt-jchau opened this issue Dec 30, 2022 · 1 comment · May be fixed by #3531

Comments

@sdt-jchau
Copy link

The current dropEffect example shows how to change dropEffect on the drag source based on the drag source itself (https://react-dnd.github.io/react-dnd/examples/customize/drop-effects). Is there a way to dynamically change the dropEffect based on the target? For example, I have 2 drop target boxes. If I drag an item to Box 1, it should show Add effect. If I drag an item to Box 2, it should show Copy effect.

@josephdangerstewart
Copy link

josephdangerstewart commented Jan 6, 2023

It doesn't look like this is supported out of the box, but I was able to get something working with this hack (loosely inspired by this hack)

export const Html5BackendWithDropEffectSupport = (manager, context) => {
	const result = HTML5Backend(manager, context);
	result.dropTargetOptions = {};

	result.handleTopDragOver_ = result.handleTopDragOver;
	result.handleTopDragOver = (e) => {
		const { dragOverTargetIds } = result;
		const bestDropTarget = (dragOverTargetIds ?? []).find(
			(x) => result.monitor.canDropOnTarget(x) && x
		);

		const dropTargetDropEffect =
			bestDropTarget &&
			result.dropTargetOptions[bestDropTarget]?.dropEffect;

		result.handleTopDragOver_(e);
		// Check e.altKey to preseve altKey to copy behavior
		result.altKeyPressed = e.altKey || Boolean(dropTargetDropEffect);
		e.dataTransfer.dropEffect =
			dropTargetDropEffect || e.dataTransfer.dropEffect;
	};

	result.connectDropTarget_ = result.connectDropTarget;
	result.connectDropTarget = (targetId, node, options) => {
		result.dropTargetOptions[targetId] = options;
		const unsubscribe = result.connectDropTarget_(targetId, node, options);

		return () => {
			delete result.dropTargetOptions[targetId];
			unsubscribe();
		};
	};

	return result;
};

Then you can specify the dropEffect in an options object in the useDrop hook like so

useDrop({
	...,
	options: {
		dropEffect: 'copy'
	},
})

Edit: It should be noted that if you also specify a dropEffect on the drag source then that will take precedence

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants