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

Cancel drag when the the draggable item loses focus #857

Open
marcospassos opened this issue Aug 4, 2022 · 2 comments · May be fixed by #1087
Open

Cancel drag when the the draggable item loses focus #857

marcospassos opened this issue Aug 4, 2022 · 2 comments · May be fixed by #1087

Comments

@marcospassos
Copy link

Currently, when dragging using the keyboard, the item remains active even when focusing out of it. It leads to several issues that can't be solved at the userland.

I tried implementing a custom sensor, but the current design doesn't allow for extension (note the ts-ignore):

/**
 * A custom keyboard sensor cancels the drag when moving the focus out of the draggable element.
 */
class CustomKeyboardSensor extends KeyboardSensor {
    private readonly sensorProps: SensorProps<SensorOptions>;

    constructor(props: KeyboardSensorProps) {
        super(props);

        this.sensorProps = props;

        this.handleDragCancel = this.handleDragCancel.bind(this);

        this.attachSensor();
    }

    private attachSensor(): void {
        this.sensorProps.event.target?.addEventListener('blur', this.handleDragCancel);
    }

    private detachSensor(): void {
        this.sensorProps.event.target?.removeEventListener('blur', this.handleDragCancel);
    }

    private handleDragCancel(): void {
        // There's no other way to notify the parent class to clean up the state.
        // @ts-ignore
        this.detach();
        this.detachSensor();
        this.sensorProps.onCancel();
    }
}

Even ignoring the error, other issues arise. For example, using the CustomKeyboardSensor, when pressing enter to finish dragging, DND kit announces the event as a cancel operation. Even worse, after calling the onCancel callback, in response to a click outside, the item steals the focus back, so you need to click twice to move the focus away from the item.

@marcospassos marcospassos changed the title Cancel drag when losing focus on the draggable item Cancel drag when the the draggable item loses focus Aug 4, 2022
@codewitch
Copy link

Would love assistance on this as well. If a non keyboard user accidentally gets into a keyboard drag state, the app will feel like it is broken since they cant cancel the drag by clicking elsewhere.

One thought would be to build a combination sensor that taps into both keyboard and click events?

@jperals jperals linked a pull request Mar 28, 2023 that will close this issue
@pwang347
Copy link

For what it's worth, here's something hacky I did that seems to be working fine and not running into the issues mentioned above. Note also that in my application I am using handleEnd instead of handleCancel.

export class CustomKeyboardSensor extends KeyboardSensor {
    constructor(props: KeyboardSensorProps) {
        super(props);

        const handleEnd = (this as any).handleEnd.bind(this);
        const detach = (this as any).detach.bind(this);

        props.activeNode.activatorNode.current?.addEventListener("blur", handleEnd);

        // hack: override the detach method to also remove the blur event
        (this as any).detach = () => {
            detach();
            props.activeNode.activatorNode.current?.removeEventListener("blur", handleEnd);
        };
    }
}

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.

3 participants