Skip to content
Closed
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
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ export const CheckpointMenu = ({
</Button>
</PopoverTrigger>
</StandardTooltip>
<PopoverContent align="end" container={portalContainer}>
<PopoverContent align="end" container={portalContainer || undefined}>
<div className="flex flex-col gap-2">
{!isCurrent && (
<div className="flex flex-col gap-1 group hover:text-foreground">
Expand Down
34 changes: 30 additions & 4 deletions webview-ui/src/components/ui/hooks/useRooPortal.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,36 @@
import { useState } from "react"
import { useMount } from "react-use"
import { useState, useEffect } from "react"

export const useRooPortal = (id: string) => {
const [container, setContainer] = useState<HTMLElement>()
const [container, setContainer] = useState<HTMLElement | null>(null)
Copy link
Author

Choose a reason for hiding this comment

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

[P2] Changing the hook to return null introduces a null/undefined mismatch for consumers. Prefer returning undefined to align with common DOM APIs and existing prop types, avoiding the need for portalContainer || undefined at call sites.

Suggested change
const [container, setContainer] = useState<HTMLElement | null>(null)
const [container, setContainer] = useState<HTMLElement | undefined>(undefined)


useMount(() => setContainer(document.getElementById(id) ?? undefined))
useEffect(() => {
// Try to find the element immediately
const element = document.getElementById(id)
if (element) {
setContainer(element)
return
}

// If not found, set up a MutationObserver to watch for it
const observer = new MutationObserver(() => {
const element = document.getElementById(id)
if (element) {
setContainer(element)
observer.disconnect()
Copy link
Author

Choose a reason for hiding this comment

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

[P3] After the first match, the observer disconnects. If the portal node is later removed and re-inserted, container may reference a detached node. Consider re-subscribing on removal or checking container?.isConnected when consuming.

}
})

// Start observing the document body for changes
observer.observe(document.body, {
childList: true,
subtree: true,
})

// Cleanup
return () => {
observer.disconnect()
}
}, [id])

return container
}
Loading