Skip to content

Commit

Permalink
Add default portal containerRef context
Browse files Browse the repository at this point in the history
  • Loading branch information
mkljczk committed Jun 6, 2023
1 parent 43f450d commit b66f042
Showing 1 changed file with 24 additions and 2 deletions.
26 changes: 24 additions & 2 deletions packages/portal/src/reach-portal.tsx
Expand Up @@ -20,6 +20,9 @@ import { createPortal } from "react-dom";

declare const __DEV__: boolean;

const PortalContainerContext = React.createContext<React.RefObject<Node> | null>(null);
const { Provider: PortalContainerContextProvider } = PortalContainerContext;

/**
* Portal
*
Expand All @@ -34,6 +37,8 @@ const PortalImpl: React.FC<PortalProps> = ({
let portalNode = React.useRef<HTMLElement | null>(null);
let forceUpdate = useForceUpdate();

const contextContainerRef = React.useContext(PortalContainerContext);

if (__DEV__) {
// eslint-disable-next-line react-hooks/rules-of-hooks
React.useEffect(() => {
Expand All @@ -54,6 +59,23 @@ const PortalImpl: React.FC<PortalProps> = ({
"See https://reactjs.org/docs/forwarding-refs.html."
);
}
} else if (contextContainerRef != null) {
if (typeof contextContainerRef !== "object" || !("current" in contextContainerRef)) {
console.warn(
"@reach/portal: Invalid value passed to the `PortalContainerContext`" +
"provider. The portal will be appended to the document body, but if " +
"you want to attach it to another DOM node you must pass a valid " +
"React ref object to `containerRef`."
);
} else if (contextContainerRef.current == null) {
console.warn(
"@reach/portal: A ref was passed to the `PortalContainerContext`" +
"provider, but no DOM node was attached to it. Be sure to pass the " +
"ref to a DOM component.\n\nIf you are forwarding the ref from " +
"another component, be sure to use the React.forwardRef API. " +
"See https://reactjs.org/docs/forwarding-refs.html."
);
}
}
}, [containerRef]);
}
Expand All @@ -64,7 +86,7 @@ const PortalImpl: React.FC<PortalProps> = ({
// It's possible that the content of the portal has, itself, been portaled.
// In that case, it's important to append to the correct document element.
let ownerDocument = mountNode.current!.ownerDocument;
let body = containerRef?.current || ownerDocument.body;
let body = containerRef?.current || contextContainerRef?.current || ownerDocument.body;
portalNode.current = ownerDocument?.createElement(type)!;
body.appendChild(portalNode.current);
forceUpdate();
Expand Down Expand Up @@ -131,4 +153,4 @@ Portal.displayName = "Portal";
// Exports

export type { PortalProps };
export { Portal };
export { Portal, PortalContainerContextProvider };

0 comments on commit b66f042

Please sign in to comment.