Conversation
`useScrollDrag` only checked `e.target.draggable`, but the mousedown target is the deepest node in the event path while `draggable` is set on the ancestor being dragged (e.g. `<li draggable><span>...</span></li>` in Tree). The drag-scroll lock was wrongly set in that case and the list kept scrolling. Walk up the ancestors and read the IDL attribute, so implicitly draggable elements (`a[href]`, `img`) are covered as well.
|
Someone is attempting to deploy a commit to the afc163's projects Team on Vercel. A member of the Team first needs to authorize it. |
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Advanced Run ID: 📒 Files selected for processing (2)
Included review availability: Your plan provides up to 4 included reviews per hour; 3 remain after this review. Walkthrough本次变更检查事件目标及其祖先的可拖动状态。显式可拖动元素和默认可拖动链接的子节点事件不再触发列表滚动,并新增回归测试。 Changes滚动拖动处理
Priority: ⬇️ Low Estimated code review effort: 2 (Simple) | ~10 minutes Change: Bug fix Suggested reviewers: Merge Risk: ⚪ Minimal · up to The drag filtering change includes regression coverage for draggable descendants, with no identified issue blocking merge. 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches 💡 1🛠️ Fix failing CI checks 💡
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. 小兔挥爪查祖先, Comment |
A virtual Tree never scrolls when a node is dragged near the top/bottom edge. The virtual list container is `overflow: hidden`, so the browser's native drag-to-edge autoscroll never kicks in. The JS fallback in rc-virtual-list (`useScrollDrag`) cannot cover it either: it runs on `mousemove`, which is not fired during a native HTML5 drag, and it now returns early whenever the target or one of its ancestors is `draggable` (react-component/virtual-list#386) so that it does not fight the native drag. Add `useDragEdgeScroll` to drive the scrolling from the drag events instead: `dragover` recomputes the offset from the pointer's distance to the edge, `dragleave` / `drop` / `dragend` cancel it. `drop` and `dragend` are listened on the document in the capture phase because `TreeNode` stops their propagation in the bubble phase. Gated on `virtual !== false` to match the virtual list's own `useVirtual = !!(virtual !== false && height && itemHeight)`, so an explicit `virtual={false}` is still left to the browser.
A virtual Tree never scrolls when a node is dragged near the top/bottom edge. The virtual list container is `overflow: hidden`, so the browser's native drag-to-edge autoscroll never kicks in. The JS fallback in rc-virtual-list (`useScrollDrag`) cannot cover it either: it runs on `mousemove`, which is not fired during a native HTML5 drag, and it now returns early whenever the target or one of its ancestors is `draggable` (react-component/virtual-list#386) so that it does not fight the native drag. Add `useDragEdgeScroll` to drive the scrolling from the drag events instead: `dragover` recomputes the offset from the pointer's distance to the edge, `dragleave` / `drop` / `dragend` cancel it. `drop` and `dragend` are listened on the document in the capture phase because `TreeNode` stops their propagation in the bubble phase. Gated on `virtual !== false` to match the virtual list's own `useVirtual = !!(virtual !== false && height && itemHeight)`, so an explicit `virtual={false}` is still left to the browser. Behaviour is covered by `NodeListEdgeScroll.spec.tsx`, which drives the real Tree: both scroll directions, returning to the idle zone, `drop`, `dragend` outside the container, `dragleave` (leaving stops, moving between inner nodes does not), the band boundary where the offset is 0, and re-entering the band while the loop already runs. `useDragEdgeScroll.spec.tsx` covers the two defensive branches that cannot be reached through the Tree — an unmounted list and a list torn down mid-scroll. 100% statement / branch / function / line coverage on the hook.
A virtual Tree never scrolls when a node is dragged near the top/bottom edge. The virtual list container is `overflow: hidden`, so the browser's native drag-to-edge autoscroll never kicks in. The JS fallback in rc-virtual-list (`useScrollDrag`) cannot cover it either: it runs on `mousemove`, which is not fired during a native HTML5 drag, and it now returns early whenever the target or one of its ancestors is `draggable` (react-component/virtual-list#386) so that it does not fight the native drag. Add `useDragEdgeScroll` to drive the scrolling from the drag events instead: `dragover` recomputes the offset from the pointer's distance to the edge, `dragleave` / `drop` / `dragend` cancel it. `drop` and `dragend` are listened on the document in the capture phase because `TreeNode` stops their propagation in the bubble phase. Gated on `virtual !== false` to match the virtual list's own `useVirtual = !!(virtual !== false && height && itemHeight)`, so an explicit `virtual={false}` is still left to the browser. Behaviour is covered by `NodeListEdgeScroll.spec.tsx`, which drives the real Tree: both scroll directions, returning to the idle zone, `drop`, `dragend` outside the container, `dragleave` (leaving stops, moving between inner nodes does not), the band boundary where the offset is 0, and re-entering the band while the loop already runs. `useDragEdgeScroll.spec.tsx` covers the two defensive branches that cannot be reached through the Tree — an unmounted list and a list torn down mid-scroll. 100% statement / branch / function / line coverage on the hook.
🤔 This is a ...
🔗 Related Issues
Follow-up of #304 (which fixed ant-design#52774)
Part of ant-design/ant-design#58508 (Tree virtual scroll + drag)
💡 Background and Solution
useScrollDragskips the drag-scroll when the mousedown target is draggable, so that a native HTML5 drag does not leave the list auto-scrolling after mouseup.The current check only reads
e.target.draggable. In the DOM event pathe.targetis the deepest node, whiledraggableis normally set on the ancestor being dragged. So for any draggable element that has children — e.g.<li draggable><span class="rc-tree-title">…</span></li>in rc-tree, or a<tr draggable>in Table — the check never matches,mouseDownLockis set anyway, and the list keeps scrolling after the drag ends.Fix: walk up from
e.targetthroughparentElementand read thedraggableIDL attribute, so implicitly draggable ancestors (a[href],img) are covered too — they are draggable without carrying adraggableattribute, so an attribute-based selector would miss them.The existing test added in #304 fires
mousedowndirectly on the<li draggable>(which has no child element), soe.target === liand the check passes — that is not how the browser dispatches the event, which is why the gap stayed unnoticed.✅ Verification
Red / green double run on the new cases:
<li draggable><a href="#">e.target.draggable)closest('[draggable="true"]'))Full suite: 9 suites / 284 tests passed.
tsc --noEmitclean, eslint 0 errors, prettier clean.📝 Change Log
draggableis set on an ancestor of the mousedown targetdraggable设置在 mousedown 目标祖先节点上时未跳过拖拽滚动的问题Summary by CodeRabbit
Bug 修复
测试