Conversation
|
clauderic
left a comment
There was a problem hiding this comment.
Summary
Adds support for drag-and-drop across window.open() popup documents by (1) having getDocuments() include any documents the host app has registered on a globalThis.__dndKitDocuments__ set, and (2) rerouting scheduler's requestAnimationFrame to a visible popup window when the main document is hidden.
Thanks for taking a run at #2100 — cross-window drag is a genuinely hard gap and it's great to see someone tackling it.
Feedback
Blocking issues
-
packages/dom/src/utilities/execution-context/getDocuments.ts:47andpackages/dom/src/utilities/scheduling/scheduler.ts:39— the integration point is an undocumented global.globalThis.__dndKitDocuments__is a mutable global that the host app is expected to populate, with no exported registration function, no type surface, and no lifecycle. This doesn't fit the library's architecture: cross-cutting behaviour like this belongs on the manager (aDragDropManagerInputoption) or in aPluginthat owns registration and tears down indestroy(). As written there's also no way to unregister a document, so a closed popup leaks into the set indefinitely. -
packages/dom/src/utilities/scheduling/scheduler.ts:39-56— this can permanently wedge the scheduler.Scheduler.schedule()setsthis.pending = trueand only clears it insideflush. If the popup window is closed (or its rAF is throttled) between thewin.requestAnimationFrame(callback)call and the frame firing,flushnever runs:pendingstaystrue, every subsequentschedule()call silently queues a task that never executes, and every returned promise never resolves. Sincescheduleris a module-level singleton used across@dnd-kit/dom, that would freeze the whole library for the page. There's no fallback timer and nowindow.closedcheck. -
packages/dom/src/utilities/scheduling/scheduler.ts:41— thedocument.hiddencondition is too broad.document.hiddenis true for any backgrounded tab, not only when a popup has focus. As soon as the user switches to another tab, scheduling is diverted into a popup window regardless of whether a cross-window drag is in progress. -
Missing changeset. This modifies files under
packages/dom/src/, so it needs a.changeset/*.mdwith'@dnd-kit/dom': patch(orminor, since this is really new functionality rather than a bug fix). -
anycasts. Both new blocks use(globalThis as any).__dndKitDocuments__. The repo's convention is full type safety withoutany; the accompanyingdndKitDocuments.d.tsdeclare globalshould make the cast unnecessary — but that file isn't imported anywhere, so it's unclear whether the ambient declaration is actually picked up by the build. Worth verifying.
Suggestions
packages/dom/src/utilities/execution-context/dndKitDocuments.d.ts:4— file is missing a trailing newline.packages/dom/src/utilities/execution-context/getDocuments.ts:47— indentation is off by one space (// Traverse...), and the comment says "registered by the host app" without explaining where that registration is supposed to happen.getDocuments()is recursive with a sharedseenset, so the popup-document block runs at every level of the recursion. It works because of the dedupe, but it means popups get appended from whichever frame reaches it first. Hoisting it to the top-level call would be clearer. Related: the popup documents are added directly rather than passed back throughgetDocuments(popupDoc, seen), so their own iframes are never discovered.- No tests. A regression test would be hard for real popups, but the
getDocumentsmerge behaviour is testable in isolation withbun:test. - No JSDoc on the new behaviour, and
getDocuments's existing doc comment still says it returns only the current document plus same-origin parents and children.
Changeset
- Status: missing. Needs
'@dnd-kit/dom'—minorif this is treated as a new capability,patchif scoped as a fix.
Overall
The underlying problem is real and worth solving, but the current shape — a magic global plus a global rAF override — has failure modes that reach well beyond the cross-window case. We'd suggest reworking this as an explicit, disposable registration API (manager option or plugin) and confining the scheduler change to an active cross-window drag, with a fallback so the scheduler can never deadlock. Thanks again for digging into this.
[claude-review]
Problem: getDocuments misses window.open popup documents; Scheduler freezes when the main tab is backgrounded during a popup drag
Approach: opt-in global registry globalThis.dndKitDocuments: Set — consumers register popup documents on open and deregister on close; zero impact when the registry is absent
Affected files: packages/dom/src/utilities/... (wherever getDocuments and Scheduler live in the source tree)
Include a minimal reproduction: open a window.open popup, mount a DragDropProvider in it, try to drag — events are lost