Repository navigation
fix: WebKit scrolling on block drop (BLO-1353) #3122
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
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,3 +1,7 @@ | ||
| import { BlockNoteEditor } from "@blocknote/core"; | ||
| import { BlockNoteView } from "@blocknote/mantine"; | ||
| import "@blocknote/mantine/style.css"; | ||
| import { createRef } from "react"; | ||
| import TestingApp from "@examples/01-basic/testing/src/App"; | ||
| import PdfFileApp from "@examples/06-custom-schema/04-pdf-file-block/src/App"; | ||
| import { describe, expect, test } from "vite-plus/test"; | ||
|
|
@@ -148,4 +152,65 @@ describe("Check Block Dragging Functionality", () => { | |
| await compareDocToSnapshot("dragPdf"); | ||
| }, | ||
| ); | ||
|
|
||
| test.skipIf(browserName === "firefox")( | ||
| "keeps the dropped block visible when the previous selection is offscreen", | ||
| async () => { | ||
| const editor = BlockNoteEditor.create({ | ||
| initialContent: Array.from({ length: 70 }, (_, index) => ({ | ||
| id: `paragraph-${index}`, | ||
| type: "paragraph", | ||
| content: `Paragraph ${index}`, | ||
| })), | ||
| }); | ||
| const scrollRef = createRef<HTMLDivElement>(); | ||
| await render( | ||
| <div | ||
| ref={scrollRef} | ||
| style={{ height: 300, width: 600, overflowY: "auto" }} | ||
| > | ||
| <BlockNoteView editor={editor} /> | ||
| </div>, | ||
| ); | ||
| const scroller = scrollRef.current!; | ||
| const selectedBlock = await waitForSelector('[data-id="paragraph-0"]'); | ||
| const source = await waitForSelector('[data-id="paragraph-60"]'); | ||
| const destination = await waitForSelector('[data-id="paragraph-62"]'); | ||
| editor.setTextCursorPosition("paragraph-0", "start"); | ||
| editor.focus(); | ||
|
|
||
| // Keep the native selection near the start while scrolling to later blocks. | ||
| // Refocusing on drop must not scroll back to that old selection. | ||
| scroller.scrollTop += | ||
| source.getBoundingClientRect().top - | ||
| scroller.getBoundingClientRect().top - | ||
| 80; | ||
| expect(selectedBlock.getBoundingClientRect().bottom).toBeLessThan( | ||
| scroller.getBoundingClientRect().top, | ||
| ); | ||
| expect(editor.getTextCursorPosition().block.id).toBe("paragraph-0"); | ||
|
|
||
| await dragAndDropBlock(source, destination, false); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win 🔎 Supported by static analysis🏁 Script executed: #!/bin/bash
# Inspect the drag-start selection change on this branch.
fd -i 'dragging.ts' packages/core/src/extensions/SideMenu \
-x rg -n -C 8 'function dragStart|setSelection|NodeSelection'Repository: TypeCellOS/BlockNote Length of output: 2642 🏁 Script executed: #!/bin/bash
set -e
printf '%s\n' '--- test context ---'
sed -n '150,225p' tests/src/end-to-end/dragdrop/dragdrop.test.tsx
printf '%s\n' '--- helper definition and uses ---'
rg -n -C 20 'dragAndDropBlock' tests/src packagesRepository: TypeCellOS/BlockNote Length of output: 37449 🏁 Script executed: #!/bin/bash
set -e
sed -n '80,115p' tests/src/utils/mouse.ts
sed -n '146,202p' packages/core/src/extensions/SideMenu/dragging.tsRepository: TypeCellOS/BlockNote Length of output: 2384 🏁 Script executed: #!/bin/bash
set -e
rg -n -C 12 'dragStart\(' packages/core/src packages/react/src packages/mantine/src tests/srcRepository: TypeCellOS/BlockNote Length of output: 2034 Make the visibility assertion distinguish the drop target from the dragged block.
🤖 Prompt for AI Agents |
||
|
|
||
| await expect | ||
| .poll(() => { | ||
| const ids = editor.document.map((block) => block.id); | ||
| return ids[ids.indexOf("paragraph-62") + 1]; | ||
| }) | ||
| .toBe("paragraph-60"); | ||
| await expect | ||
| .poll(() => { | ||
| const moved = scroller.querySelector('[data-id="paragraph-60"]'); | ||
| if (!moved) { | ||
| return false; | ||
| } | ||
| const blockRect = moved.getBoundingClientRect(); | ||
| const viewport = scroller.getBoundingClientRect(); | ||
| return ( | ||
| blockRect.top >= viewport.top && blockRect.bottom <= viewport.bottom | ||
| ); | ||
| }) | ||
| .toBe(true); | ||
| }, | ||
| ); | ||
| }); | ||
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.
Hm, if true, this may be a prosemirror-view bug maybe we should submit it there? https://code.haverbeke.berlin/prosemirror/prosemirror-view/src/commit/c6320e2374d8de7b6243d89a4500320480f7c17c/src/input.ts#L832
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.
Looked deep into this and it's not related to ProseMirror, any
content-editablewill have the same behaviour. You can reproduce the issue in this minimal example.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 appreciate the deep dive, & this sandbox is really great at showing the issue!
I wonder whether @marijnh would be willing to take this upstream into prosemirror-view though. There are a bunch of kludges for other browser & behaviors that it might still be relevant for him to take up.
If you like, I can submit something to his repo (it's moved off of GH now): https://code.haverbeke.berlin/prosemirror/prosemirror-view
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.
Sounds good, though in that case idk if this is the right fix. Probably better to have smth more targeted at WebKit if it's going into
prosemirror-viewrather than a catch-allappendTransactionon drops.