-
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
fix: autoscroll when block is bigger than viewport #3746
fix: autoscroll when block is bigger than viewport #3746
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@ianstormtaylor can you please take a look at adding in this fix? getting this improvement out would be a big win for a lot of projects facing this bug :)
@gztomas can you please tag @ianstormtaylor as a reviewer? maybe that will help to get this reviewed and merged sooner |
@@ -186,10 +186,14 @@ export const Editable = (props: EditableProps) => { | |||
if (newDomRange) { | |||
domSelection.addRange(newDomRange!) | |||
const leafEl = newDomRange.startContainer.parentElement! | |||
leafEl.getBoundingClientRect = newDomRange.getBoundingClientRect.bind( | |||
newDomRange | |||
) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
when testing this fix, did you scroll around a lot? Worried about performance issues when building and destroying this every time you scroll
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I haven't found any performance issues so far. If that was the case however I think we would see the issue on typing rather than on scrolling given this piece of code is only called when the selection changes, not the scroll. I believe this should be a cheap operation either way. Or at least probably cheaper than the DOM access operations that happen on toDOMRange
sequential to this.
Hi @gztomas , thank you so much for the contribution. I went to go test this out on the deployed preview examples and it didn't seem to have any effect. What I tried was going to the rich text example, adding enough text for there to be a scollbar, and then I typed while the cursor was in and out of the view port. In both cases, the behavior was identical to what is now on latest. I also tried this by ensuring the text was in a single block and still no improvement. Is there something I'm missing in the steps to reproduce? |
@CameronAckermanSEL have you had a chance to re-review this? Is there anything else you need to repro? |
@gztomas can we push this change out? its been a few months and there's been no comments around this change causing issues. cc: @CameronAckermanSEL @ianstormtaylor |
@rglusk I don't think there is anything to be done on our side. There are a lot of PRs unattended fixing really important stuff. |
@timbuckley, i see you recently merged new code. Can you please either merge this for us, or give @gztomas and I write access to this repo? Thank you!! |
This is a problem for me as well, would like to see it gets fixed soon 👍 @timbuckley |
In case it was useful for you, this is the hack I'm using to fix this on my side // HACK for fixing Slate auto-scroll issue
// Overriding the rect for the Slate block with the selection block so Slate
// auto-scrolls to where the cursor is rather than auto-scrolling the whole
// block. If the block is big enough then the auto-scroll can make the cursor be
// outside of the viewport.
const { toDOMRange } = ReactEditor;
ReactEditor.toDOMRange = (editor, selection) => {
const range = toDOMRange(editor, selection);
range.startContainer.parentElement?.getBoundingClientRect = range.getBoundingClientRect.bind(
range
);
return range;
}; |
thanks @gztomas, that works :) hopefully this change will get merged at some point so other people can use your fix too! |
🦋 Changeset detectedLatest commit: 95a235d The changes in this PR will be included in the next version bump. This PR includes changesets to release 1 package
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
Thanks @gztomas! |
scrollIntoView(leafEl, { | ||
scrollMode: 'if-needed', | ||
boundary: el, | ||
}) | ||
delete leafEl.getBoundingClientRect |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🤔 this throws a typescript error could you elaborate why this is needed @gztomas?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@juliankrispel this restores the override happening at line 208
, so any future call to leafEl.getBoundingClientRect
will get the native getBoundingClientRect
implementation from leafEl
prototype chain. This is for cleanup purposes, as this code doesn't know who else might need to call getBoundingClientRect
for this element. I guess TS can't know that even deleting this, getBoundingClientRect
will still be available, from the prototype.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
thanks for explaining @gztomas
Is this adding or improving a feature or fixing a bug?
This is fixing an issue #3146
What's the new behavior?
Before:
![before mov](https://user-images.githubusercontent.com/1714020/85192368-a9b1db00-b298-11ea-82a1-f3af7c2b6303.gif)
![after mov](https://user-images.githubusercontent.com/1714020/85192371-ad456200-b298-11ea-92ab-188213d8d166.gif)
After:
How does this change work?
scroll-into-view-if-needed
can only scroll elements into view. In this case, the element is bigger than the viewport, and we actually want to scroll the range of the selection into the viewport.Range
already implementsgetBoundingClientRect
. That should be all whatscroll-into-view-if-needed
needs to do its thing. Butscroll-into-view-if-needed
won't just work if we pass a range instead of an element. While being a bit hacky, overridinggetBoundingClientRect
of the block with thegetBoundingClientRect
from the range works wonderfully.Have you checked that...?
yarn test
.yarn lint
. (Fix errors withyarn fix
.)yarn start
.)Does this fix any issues or need any specific reviewers?
Fixes: #3146
Reviewers: @CameronAckermanSEL @ianstormtaylor