From 73b26517a7a1da95dad9f77644b337bbf5c53d9b Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 9 Sep 2025 23:27:20 +0000 Subject: [PATCH 1/3] Initial plan From e888e4f04e9cd2cdd3140a77108a22b1b2d63fbe Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 9 Sep 2025 23:47:04 +0000 Subject: [PATCH 2/3] chore: add portal context with comprehensive tests and storybook demo Co-authored-by: francinelucca <40550942+francinelucca@users.noreply.github.com> --- packages/react/src/Portal/Portal.stories.tsx | 122 ++++++++++++++++++- packages/react/src/Portal/Portal.tsx | 1 - 2 files changed, 121 insertions(+), 2 deletions(-) diff --git a/packages/react/src/Portal/Portal.stories.tsx b/packages/react/src/Portal/Portal.stories.tsx index 09c9b6cf9dd..f58167ca788 100644 --- a/packages/react/src/Portal/Portal.stories.tsx +++ b/packages/react/src/Portal/Portal.stories.tsx @@ -1,7 +1,8 @@ import type {Meta} from '@storybook/react-vite' -import {Portal} from './Portal' +import {Portal, PortalContext, registerPortalRoot} from './Portal' import classes from './Portal.stories.module.css' import {clsx} from 'clsx' +import {useEffect} from 'react' export default { title: 'Behaviors/Portal', @@ -22,3 +23,122 @@ export const Default = () => ( ) + +export const WithPortalContext = () => { + useEffect(() => { + // Create and register custom portal containers for the story + let customContainer = document.getElementById('storybook-custom-portal') + let overrideContainer = document.getElementById('storybook-override-portal') + + if (!customContainer) { + // If containers don't exist yet, create them manually + customContainer = document.createElement('div') + customContainer.id = 'storybook-custom-portal' + document.body.appendChild(customContainer) + } + + if (!overrideContainer) { + overrideContainer = document.createElement('div') + overrideContainer.id = 'storybook-override-portal' + document.body.appendChild(overrideContainer) + } + + registerPortalRoot(customContainer, 'storybook-custom') + registerPortalRoot(overrideContainer, 'storybook-override') + + return () => { + // Clean up on unmount + if (document.body.contains(customContainer)) { + document.body.removeChild(customContainer) + } + if (document.body.contains(overrideContainer)) { + document.body.removeChild(overrideContainer) + } + } + }, []) + + return ( + <> +
+

Using PortalContext

+

This story demonstrates how to use PortalContext to control where Portal content is rendered.

+ + {/* Default Portal */} +
+ Default Portal (no context): + +
+ Content in default portal +
+
+
+ + {/* Portal with Context */} +
+ Portal with PortalContext: + + +
+ Content in custom portal (via PortalContext) +
+
+
+
+ + {/* Override context with containerName prop */} +
+ Context + containerName prop override: + + +
+ Content overriding context with containerName prop +
+
+
+
+
+ + {/* Custom portal containers */} +
+ Custom Portal Container: +
+
+ +
+ Override Portal Container: +
+
+ + ) +} diff --git a/packages/react/src/Portal/Portal.tsx b/packages/react/src/Portal/Portal.tsx index 2e262db7aa0..490b901c62a 100644 --- a/packages/react/src/Portal/Portal.tsx +++ b/packages/react/src/Portal/Portal.tsx @@ -72,7 +72,6 @@ export const Portal: React.FC> = ({ }) => { const {portalContainerName} = useContext(PortalContext) const elementRef = React.useRef(null) - const {portalContainerName} = useContext(PortalContext) if (!elementRef.current) { const div = document.createElement('div') // Portaled content should get their own stacking context so they don't interfere From f3ed64eb325ae9ac07600983fd6cbbd599957206 Mon Sep 17 00:00:00 2001 From: Marie Lucca Date: Wed, 10 Sep 2025 10:13:40 -0400 Subject: [PATCH 3/3] story fix --- .../src/Portal/Portal.features.stories.tsx | 108 +++++++++++++++- packages/react/src/Portal/Portal.stories.tsx | 122 +----------------- 2 files changed, 107 insertions(+), 123 deletions(-) diff --git a/packages/react/src/Portal/Portal.features.stories.tsx b/packages/react/src/Portal/Portal.features.stories.tsx index 0dfb807cc7a..46321c7e96e 100644 --- a/packages/react/src/Portal/Portal.features.stories.tsx +++ b/packages/react/src/Portal/Portal.features.stories.tsx @@ -1,6 +1,6 @@ -import React from 'react' +import React, {useEffect} from 'react' import type {Meta} from '@storybook/react-vite' -import {Portal, registerPortalRoot} from './Portal' +import {Portal, PortalContext, registerPortalRoot} from './Portal' import classes from './Portal.stories.module.css' import {clsx} from 'clsx' @@ -81,3 +81,107 @@ export const MultiplePortalRoots: React.FC ) } + +export const WithPortalContext = () => { + const customContainerRef = React.useRef(null) + const overrideContainerRef = React.useRef(null) + const [mounted, setMounted] = React.useState(false) + useEffect(() => { + if (customContainerRef.current instanceof HTMLElement && overrideContainerRef.current instanceof HTMLElement) { + registerPortalRoot(customContainerRef.current, 'custom-portal') + registerPortalRoot(overrideContainerRef.current, 'override-portal') + setMounted(true) + } + }, []) + + return ( + <> +
+

Using PortalContext

+

This story demonstrates how to use PortalContext to control where Portal content is rendered.

+ + {/* Default Portal */} +
+ Default Portal (no context): + {mounted ? ( + +
+ Content in default portal +
+
+ ) : null} +
+ + {/* Portal with Context */} +
+ Portal with PortalContext: + + {mounted ? ( + +
+ Content in custom portal (via PortalContext) +
+
+ ) : null} +
+
+ + {/* Override context with containerName prop */} +
+ Context + containerName prop override: + + {mounted ? ( + +
+ Content overriding context with containerName prop +
+
+ ) : null} +
+
+
+ + {/* Custom portal containers */} +
+ Custom Portal Container: +
+
+ +
+ Override Portal Container: +
+
+ + ) +} diff --git a/packages/react/src/Portal/Portal.stories.tsx b/packages/react/src/Portal/Portal.stories.tsx index f58167ca788..09c9b6cf9dd 100644 --- a/packages/react/src/Portal/Portal.stories.tsx +++ b/packages/react/src/Portal/Portal.stories.tsx @@ -1,8 +1,7 @@ import type {Meta} from '@storybook/react-vite' -import {Portal, PortalContext, registerPortalRoot} from './Portal' +import {Portal} from './Portal' import classes from './Portal.stories.module.css' import {clsx} from 'clsx' -import {useEffect} from 'react' export default { title: 'Behaviors/Portal', @@ -23,122 +22,3 @@ export const Default = () => (
) - -export const WithPortalContext = () => { - useEffect(() => { - // Create and register custom portal containers for the story - let customContainer = document.getElementById('storybook-custom-portal') - let overrideContainer = document.getElementById('storybook-override-portal') - - if (!customContainer) { - // If containers don't exist yet, create them manually - customContainer = document.createElement('div') - customContainer.id = 'storybook-custom-portal' - document.body.appendChild(customContainer) - } - - if (!overrideContainer) { - overrideContainer = document.createElement('div') - overrideContainer.id = 'storybook-override-portal' - document.body.appendChild(overrideContainer) - } - - registerPortalRoot(customContainer, 'storybook-custom') - registerPortalRoot(overrideContainer, 'storybook-override') - - return () => { - // Clean up on unmount - if (document.body.contains(customContainer)) { - document.body.removeChild(customContainer) - } - if (document.body.contains(overrideContainer)) { - document.body.removeChild(overrideContainer) - } - } - }, []) - - return ( - <> -
-

Using PortalContext

-

This story demonstrates how to use PortalContext to control where Portal content is rendered.

- - {/* Default Portal */} -
- Default Portal (no context): - -
- Content in default portal -
-
-
- - {/* Portal with Context */} -
- Portal with PortalContext: - - -
- Content in custom portal (via PortalContext) -
-
-
-
- - {/* Override context with containerName prop */} -
- Context + containerName prop override: - - -
- Content overriding context with containerName prop -
-
-
-
-
- - {/* Custom portal containers */} -
- Custom Portal Container: -
-
- -
- Override Portal Container: -
-
- - ) -}