Skip to content

Commit

Permalink
allow to pass in custom ownerDocument into the internal <Portal>
Browse files Browse the repository at this point in the history
This allows us to use a custom `ownerDocument`. This is useful if a
`<Menu>` is rendered in an `<iframe>`, then we can use the
`ownerDocument` from the `<MenuButton>` to know where to render the
`<MenuItems>` (when portalling)
  • Loading branch information
RobinMalfait committed Dec 12, 2024
1 parent d71fb9c commit 6743015
Showing 1 changed file with 8 additions and 8 deletions.
16 changes: 8 additions & 8 deletions packages/@headlessui-react/src/components/portal/portal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,10 @@ import type { Props } from '../../types'
import { env } from '../../utils/env'
import { forwardRefWithAs, useRender, type HasDisplayName, type RefProp } from '../../utils/render'

function usePortalTarget(ref: MutableRefObject<HTMLElement | null>): HTMLElement | null {
function usePortalTarget(ownerDocument: Document | null): HTMLElement | null {
let forceInRoot = usePortalRoot()
let groupTarget = useContext(PortalGroupContext)

let ownerDocument = useOwnerDocument(ref)

let [target, setTarget] = useState(() => {
// Group context is used, but still null
if (!forceInRoot && groupTarget !== null) return groupTarget.current ?? null
Expand Down Expand Up @@ -77,22 +75,24 @@ export type PortalProps<TTag extends ElementType = typeof DEFAULT_PORTAL_TAG> =
PortalPropsWeControl,
{
enabled?: boolean
ownerDocument?: Document | null
}
>

let InternalPortalFn = forwardRefWithAs(function InternalPortalFn<
TTag extends ElementType = typeof DEFAULT_PORTAL_TAG,
>(props: PortalProps<TTag>, ref: Ref<HTMLElement>) {
let theirProps = props
let { ownerDocument: incomingOwnerDocument = null, ...theirProps } = props
let internalPortalRootRef = useRef<HTMLElement | null>(null)
let portalRef = useSyncRefs(
optionalRef<(typeof internalPortalRootRef)['current']>((ref) => {
internalPortalRootRef.current = ref
}),
ref
)
let ownerDocument = useOwnerDocument(internalPortalRootRef)
let target = usePortalTarget(internalPortalRootRef)
let defaultOwnerDocument = useOwnerDocument(internalPortalRootRef)
let ownerDocument = incomingOwnerDocument ?? defaultOwnerDocument
let target = usePortalTarget(ownerDocument)
let [element] = useState<HTMLDivElement | null>(() =>
env.isServer ? null : ownerDocument?.createElement('div') ?? null
)
Expand Down Expand Up @@ -154,12 +154,12 @@ function PortalFn<TTag extends ElementType = typeof DEFAULT_PORTAL_TAG>(
) {
let portalRef = useSyncRefs(ref)

let { enabled = true, ...theirProps } = props
let { enabled = true, ownerDocument, ...theirProps } = props

let render = useRender()

return enabled ? (
<InternalPortalFn {...theirProps} ref={portalRef} />
<InternalPortalFn {...theirProps} ownerDocument={ownerDocument} ref={portalRef} />
) : (
render({
ourProps: { ref: portalRef },
Expand Down

0 comments on commit 6743015

Please sign in to comment.