react-sortable-hoc icon indicating copy to clipboard operation
react-sortable-hoc copied to clipboard

Attempting to drag in Safari and IE selects text on page

Open mccambridge opened this issue 7 years ago • 10 comments

When I drag an item in Safari or IE 11, the text on other areas of the page that my mouse travels by gets selected. It's as if the browser doesn't know I'm dragging but thinks my mouse went down for the purpose of highlighting text on the page.

Great hoc! I definitely appreciate your work! :D

mccambridge avatar Jul 27 '17 17:07 mccambridge

Firefox and IE both have the same problem of a drag causing selection. The solution I found is just two steps:-

  1. Define the following css class :-
 .noselect {
 -webkit-touch-callout: none; /* iOS Safari */
   -webkit-user-select: none; /* Safari */
    -khtml-user-select: none; /* Konqueror HTML */
      -moz-user-select: none; /* Firefox */
       -ms-user-select: none; /* Internet Explorer/Edge */
           user-select: none; /* Non-prefixed version, currently
                                 supported by Chrome and Opera */
}
  1. Apply the css class on your SortableItem component (div or li which you will drag) like so :-
const SortableItem = SortableElement(({value,SortableItemClassName}) =>
  <li className="noselect">{value}</li>
);

Check both the reproduced problem and its solution by opening the sandbox in Firefox :- https://codesandbox.io/s/G6jPqD9oy

The source of solution is from Overflowstack

wahabshah avatar Aug 08 '17 11:08 wahabshah

@wahabshah It doesn't work in Safari for me.

Here is my solution. Add the special sort start event handler to your sortable container:

const SortableList = SortableContainer(/* your container */);

ReactDOM.render(
    <SortableList
        items={[]} // your list items
        onSortStart={(_, event) => event.preventDefault()} // it does the trick
        onSortEnd={() => {}} // your sort end handler
    />,
    document.getElementById('app')
);

Unfortunately it doesn't work when the pressDelay or the distance option is set.

I insist that this handler must be in react-sortable-hoc by default.

Finesse avatar Dec 08 '17 10:12 Finesse

technically these aren't really solutions but more work-arounds. I think the real problem is because the framework decides to copy the element to the bottom of the body and hides the original one instead of actually changing the element. I used react-beautiful-dnd and they don't have these problems (though I have NO IDEA how in hell they get the grabbing cursor (i don't see it anywhere in the dom lol) but it works!

dagadbm avatar Jun 05 '18 13:06 dagadbm

By the way this behavior is completely different on safari. (Just try to do a select all on safari). Safari for some reason selects the background as well as the text this is why there is some weird behavior when using this in safari (even when you use user-select: none)

dagadbm avatar Jun 05 '18 16:06 dagadbm

Adding the user-select:none style to the SortableItem stops the user from being able to interact with the item. For example, they may wish to copy the contents. So instead I use the SortableContainers onSortStart and onSortEnd to set some state which is then passed into the SortableItem to set when the class is added.

handleOnSortEnd () {
        this.setState({ isSorting: false });
}

handleOnSortStart () {
        this.setState({ isSorting: true });
}
const SortableItem = SortableElement(({value}) =>
  <li className={ classnames({ "user-select-none": this.state.isSorting }) }>{value}</li>
);

juliankigwana avatar Sep 13 '18 10:09 juliankigwana

I didn't have any luck with any of the above solutions so I came up with this. @wahabshah was where i started, but I then reversed the thinking. Apply user-select:none to everything but the items that can select. by using the asterisk * and :not() pseudo

*NOTE this will remove text selection form the entire page, for my application this is perfect.

*:not(.noselect){
 -webkit-touch-callout: none; /* iOS Safari */
   -webkit-user-select: none; /* Safari */
    -khtml-user-select: none; /* Konqueror HTML */
      -moz-user-select: none; /* Firefox */
       -ms-user-select: none; /* Internet Explorer/Edge */
           user-select: none; /* Non-prefixed version, currently
                                 supported by Chrome and Opera */
}

campmedia avatar Jan 06 '19 21:01 campmedia

Almost two years passed, and the issue is still there.

oziniak avatar Mar 19 '19 15:03 oziniak

I also have this problem. Would be nice with a proper fix for this.

B3Kay avatar Apr 09 '19 09:04 B3Kay

If you want to use pressDelay or distance, you could try something like this:

updateBeforeSortStart={() => {
    function disableselect() {return false}
    document.onselectstart = disableselect;
    document.onmousedown = disableselect;
}}
onSortEnd={() => {
    document.onselectstart = null;
    document.onmousedown = null;
}}

denis-lukin avatar May 19 '20 09:05 denis-lukin

If you want to use pressDelay and distance and solution by @denis-lukin did not work for you. You can try something like this:

updateBeforeSortStart={() => {
    document.body.classList.add('not-selectable');
}}
onSortEnd={() => {
    document.body.classList.remove('not-selectable')
}}

abime avatar Dec 15 '20 10:12 abime