-
Notifications
You must be signed in to change notification settings - Fork 3.3k
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
Triple-click selection and Selection API issue #4329
Comments
@julienmonnard Thanks for the great demo and explanation. Are you working on this issue? |
@bytrangle Unfortunately I currently don't have enough free time to work on it... If you or anybody want to take it you're very welcome to do so. |
More findings in case anyone wants to take on this issue:
The Quote Block button shouldn't be highlighted in this case. The method responsible for checking if a block is selected is
Inside, it calls
In case of the Rich Text example, Let's add a After building Slate locally, visit the rich text example. This is what happens when single clicking the second paragraph block: The element node we get is correct. When click and drag to select the second block: Please don't mind numerous element nodes output to the console. It's because I click and drag, the selection will change continuously and the And this is what happens when I triple click: We get exactly four element nodes. I've tried it many times, and it's always four. I think it happens like this:
Because on the third click, Do you have any idea what cause this @julienmonnard? I've read your hypothesis above, but it doesn't seem to explain the case of single click. In that case, the |
(I worked with @julienmonnard on the initial report, so it's possible that I'm somewhat biased :) ) EDIT: Funny thing, both me and Julien were replying to this. He has way more in-depth experience with Slate, and everyone should read his post first ✌️ @bytrangle I would suggest to try and fully understand the selection API. Just to clarify something on your post:
This is not entirely true. You're missing 1 more condition: So, for any such collapsed selections, things are pretty easy, because all browsers behave the same, and basically the above condition is always true. I think there are 2 composite "problems":
I hope this helps... it's a pretty complicated situation for anyone with fresh eyes. |
So first of all, to not mix everything below, there is different things at play here:
I will try to keep these names. If you do a single click on you paragraph, for example between the letters {
anchorNode: text, // "text" is a `DOM Node` representing the word "bold"
anchorOffset: 2,
focusNode: text, // "text" is a `DOM Node` representing the word "bold"
focusOffset: 2,
} Here, the two Now if you do the "click-and-drag", your // If you dragged from beginning to end
{
anchorNode: text, // "text" is a `DOM Node` representing the text until just before "bold"
anchorOffset: 0,
focusNode: text, // "text" is a `DOM Node` representing the text from the comma until the end
focusOffset: 82,
}
// If you dragged from end to beginning
{
anchorNode: text, // "text" is a `DOM Node` representing the text from the comma until the end
anchorOffset: 82,
focusNode: text, // "text" is a `DOM Node` representing the text until just before "bold"
focusOffset: 0,
} For Slate, it's the same as before, it will get the first valid And for the triple click: // in Chrome
{
anchorNode: text, // "text" is a `DOM Node` representing the text until just before "bold"
anchorOffset: 0,
focusNode: text, // Now "text" is a `DOM Node` representing the text of the quote
focusOffset: 0,
}
// in Firefox
{
anchorNode: text, // "text" is a `DOM Node` representing the text until just before "bold"
anchorOffset: 0,
focusNode: text, // "text" is a `DOM Node` representing the text from the comma until the end
focusOffset: 82,
} Since here the Selection API returns the text of the quote as a focusNode The problem here is that since the focusOffset is at 0, it means that no characters from the focusNode is actually selected, so Slate should not be giving that |
I've been investigating / trying to fix this (see comments on #4492) and wanted to record some findings: The basic issue as I understand it is that the DOM selection API supports two kinds of selection endpoint:
but Slate selections support only text endpoints. When a DOM selection has an element endpoint, Slate looks for a corresponding text endpoint ( Browsers vary on exactly what actions produce element endpoints, but they are generally actions that sensibly mean "select the whole element":
All of these generate element endpoints (in most cases) in the browsers I've tested (Chrome, Firefox, Safari, all on a Mac), and in most cases the element endpoints turn into a hanging selection in Slate. It's good to have hanging selections! There's no other way in Slate to represent the selection of a whole block, and there are lots of actions that sensibly work on a whole block: e.g. if you triple-click a paragraph or shift-arrow-down a paragraph and hit delete, it's sensible for the whole paragraph to be deleted, not just the text within it. (I haven't tested a lot of rich text editors on this but it seems pretty standard.) But hanging selections have some bugs: First, browsers differ in exactly how they generate selection endpoints for the actions above:
(I feel like these differences are not really a problem—applications should do something sensible with both hanging and non-hanging selections; so inconsistencies in when hanging / non-hanging selections are generated don't really matter. Just my opinion!) Second, applications don't always handle hanging selections correctly:
@bytrangle made an attempt at fixing these bugs with #4455 / #4512. I've been looking into alternative fixes because @bytrangle's fixes have caused other bugs (#4492), because they address Chrome only (the issue is more widespread), and because they fix the bugs by getting rid of hanging selections (which I think is a mistake; hanging ranges are useful). I've been working on a branch that addresses these bugs by always looking for the text endpoint inside the DOM selection, never outside. This works without browser-specific fixups, but it also gets rid of hanging selections (as above I think this is a mistake). I'd rather address the bugs by fixing the examples where needed, and by understanding / fixing the behavior of hanging selections inside void nodes. What do you think? @ianstormtaylor would love your input here. |
Description
Hello! We are currently facing a bug with triple-click selection. When we triple-click on a word, the expectation is that the whole text block gets selected, a paragraph for example. The problem here is that for 2 of the 3 browsers I tested (it happens on Chrome and Edge, not on Firefox), Slate will also select the following (or part of the following) sibling node.
You can see recordings for both behaviours, the first for Chrome (bug) and the second on Firefox (no bug).
Recording
Chrome.mov
Firefox.mov
Steps
To reproduce the behavior:
Expectation
The expectation would be to have the selection only on the text block that was actually targeted, and not the following one.
Environment
Context
From my understanding, there is two things that feel are part of the issue.
The first might be because of the way
offsets
are considered within a selection.At this line:
slate/packages/slate-react/src/utils/dom.ts
Line 110 in e042ebd
offset
is compared tochildNodes.length
But according to the Selection API the offset represents the number of characters selected, not the number of child nodes, so this is not comparing the same things at all.
The second thing is, if the value of
focusOffset
is 0, it means there is nothing selected in thefocusNode
and therefore, this node should be removed from the selection range. Currently, maybe because of the first point, Slate keeps digging into thisfocusNode
to find a selectable child and include it in the range. On top of it, iffocusNode
is avoid
element, it can create more problems, as Slate is not supposed to handle the content of avoid
element.The text was updated successfully, but these errors were encountered: