Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/funny-insects-clean.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@uppy/dashboard": patch
---

Fix form appending for shadow dom
30 changes: 27 additions & 3 deletions packages/@uppy/dashboard/src/components/FileCard/index.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import classNames from 'classnames'
import { nanoid } from 'nanoid/non-secure'
import { useCallback, useEffect, useState } from 'preact/hooks'
import { useCallback, useEffect, useRef, useState } from 'preact/hooks'
import getFileTypeIcon from '../../utils/getFileTypeIcon.js'
import ignoreEvent from '../../utils/ignoreEvent.js'
import FilePreview from '../FilePreview.js'
Expand Down Expand Up @@ -66,14 +66,37 @@ export default function FileCard(props: $TSFixMe) {
return formEl
})

// We need to know where Uppy is being rendered
const domRef = useRef<HTMLDivElement>(null)

useEffect(() => {
document.body.appendChild(form)
/**
* Use the "rootNode" of whereever Uppy is rendered, falling back
* to `window.document` if domRef isn't initialized for some reason
*/
const rootNode = domRef.current?.getRootNode() ?? (document as Node)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: Guarding getRootNode: handle absent method gracefully

domRef.current?.getRootNode() only guards domRef.current being nullish, not the presence of getRootNode. In environments where Node.getRootNode is undefined (older/legacy browsers or certain polyfilled contexts), this will throw TypeError: getRootNode is not a function. Use domRef.current?.getRootNode?.() (or a safe fallback like ownerDocument) to avoid a runtime crash.

Fix in Cursor Fix in Web

/**
* This is the case for the Light DOM and <iframes>.
* In these scenarios, we don't want to append a child to an
* <html> element, but to the <body>
*/
if (rootNode instanceof Document) {
rootNode.body.appendChild(form)
}
// This is the case for the Shadow DOM
else if (rootNode instanceof ShadowRoot) {
rootNode.appendChild(form)
}
// Everything else (realistically there isn't)
else {
rootNode.appendChild(form)
}
form.addEventListener('submit', handleSave)
return () => {
form.removeEventListener('submit', handleSave)
// check if form is still in the DOM before removing
if (form.parentNode) {
document.body.removeChild(form)
form.parentNode.removeChild(form)
}
}
}, [form, handleSave])
Expand All @@ -87,6 +110,7 @@ export default function FileCard(props: $TSFixMe) {
onDragLeave={ignoreEvent}
onDrop={ignoreEvent}
onPaste={ignoreEvent}
ref={domRef}
>
<div className="uppy-DashboardContent-bar">
<div
Expand Down
Loading