From fa563f6cee423ef98f187d8df386ca0b616095d5 Mon Sep 17 00:00:00 2001 From: James Cheese Date: Thu, 2 Oct 2025 16:28:55 +0100 Subject: [PATCH 1/4] Allow a fallback mount option, to allow keeping a video/etc alive even when no OutputPortal is mounted --- src/index.tsx | 12 +++++ stories/html.stories.tsx | 105 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 117 insertions(+) diff --git a/src/index.tsx b/src/index.tsx index 531a573..aa8b490 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -7,6 +7,7 @@ const ELEMENT_TYPE_SVG = 'svg'; type BaseOptions = { attributes?: { [key: string]: string }; + fallbackMountNode?: React.MutableRefObject; }; type HtmlOptions = BaseOptions & { @@ -144,6 +145,16 @@ const createPortalNode = >( parent = undefined; lastPlaceholder = undefined; } + + if (parent === undefined && options?.fallbackMountNode?.current) { + const newParent = options?.fallbackMountNode.current; + + newParent.appendChild( + portalNode.element + ); + + parent = newParent; + } } } as AnyPortalNode; @@ -153,6 +164,7 @@ const createPortalNode = >( interface InPortalProps { node: AnyPortalNode; children: React.ReactNode; + keepMounted: boolean; } class InPortal extends React.PureComponent { diff --git a/stories/html.stories.tsx b/stories/html.stories.tsx index 54e1b57..5ba4929 100644 --- a/stories/html.stories.tsx +++ b/stories/html.stories.tsx @@ -426,3 +426,108 @@ export const ExampleFromREADME = () => { return }; + +export const DefaultToFallbackElementWhenNotInUse = () => { + const fallbackRef = React.useRef(undefined); + const portalNode = React.useMemo(() => createHtmlPortalNode({ fallbackMountNode: fallbackRef }), []); + const [showPortal, setShowPortal] = React.useState(true); + + return
+
+ + + +

+ The video below should continue playing in the background toggled. +

+ + + +
+ +

Regular OutPortal

+ + { showPortal === true && } + + +

Fallback:

+ +
+
+
+
; +}; + +export const PersistPlaybackWhilstDispalyedInAHiddenElement = () => { + const fallbackRef = React.useRef(undefined); + const portalNode = React.useMemo(() => createHtmlPortalNode({ fallbackMountNode: fallbackRef }), []); + const [showPortal, setShowPortal] = React.useState(true); + + return
+
+
+ + + +

+ The video below should continue playing in the background toggled. +

+ + + +
+ +
+ { showPortal === true && } +
+
+
; +}; + +export const CombineFallbackContainerAndSwitchingBetweenTwoPlaces = () => { + const fallbackRef = React.useRef(undefined); + const portalNode = React.useMemo(() => createHtmlPortalNode({ fallbackMountNode: fallbackRef }), []); + const [showPortal, setShowPortal] = React.useState(true); + const [secondPortalSelected, setSecondPortalSelected] = React.useState(true); + + return
+
+
+ + + +

+ The video below should continue playing in the background toggled. +

+ + + + + +
+ + { showPortal === true &&
+ +

Portal 1:

+ { !secondPortalSelected && } +
+ +

Portal 2:

+ { secondPortalSelected && } +
+
} +
+
; +}; + From 94aed1cee0a0407140a3a0e89ff808fbd86f23fa Mon Sep 17 00:00:00 2001 From: James Cheese Date: Thu, 2 Oct 2025 16:35:39 +0100 Subject: [PATCH 2/4] Remove unwanted prop from initial implementation attempt --- src/index.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/src/index.tsx b/src/index.tsx index aa8b490..0b63806 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -164,7 +164,6 @@ const createPortalNode = >( interface InPortalProps { node: AnyPortalNode; children: React.ReactNode; - keepMounted: boolean; } class InPortal extends React.PureComponent { From dbac6acf47ed81d4abe9bc269af205744df99a98 Mon Sep 17 00:00:00 2001 From: James Cheese Date: Mon, 6 Oct 2025 08:56:51 +0100 Subject: [PATCH 3/4] Update stories/html.stories.js Fixing typo Co-authored-by: Tim Perry <1526883+pimterry@users.noreply.github.com> --- stories/html.stories.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stories/html.stories.tsx b/stories/html.stories.tsx index 5ba4929..201f558 100644 --- a/stories/html.stories.tsx +++ b/stories/html.stories.tsx @@ -461,7 +461,7 @@ export const DefaultToFallbackElementWhenNotInUse = () => { ; }; -export const PersistPlaybackWhilstDispalyedInAHiddenElement = () => { +export const PersistPlaybackWhilstDisplayedInAHiddenElement = () => { const fallbackRef = React.useRef(undefined); const portalNode = React.useMemo(() => createHtmlPortalNode({ fallbackMountNode: fallbackRef }), []); const [showPortal, setShowPortal] = React.useState(true); From 9b9efce2188162cbfd6b2eef93b770d69d7dd6b1 Mon Sep 17 00:00:00 2001 From: James Cheese Date: Mon, 6 Oct 2025 09:57:29 +0100 Subject: [PATCH 4/4] PR fixes: Post-rebase fixes for issues raised by typescript story migration, removing outdated props from initial implementation attempts --- src/index.tsx | 2 +- stories/html.stories.tsx | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/index.tsx b/src/index.tsx index 0b63806..85f470c 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -7,7 +7,7 @@ const ELEMENT_TYPE_SVG = 'svg'; type BaseOptions = { attributes?: { [key: string]: string }; - fallbackMountNode?: React.MutableRefObject; + fallbackMountNode?: React.MutableRefObject; }; type HtmlOptions = BaseOptions & { diff --git a/stories/html.stories.tsx b/stories/html.stories.tsx index 201f558..d4cabb2 100644 --- a/stories/html.stories.tsx +++ b/stories/html.stories.tsx @@ -428,13 +428,13 @@ export const ExampleFromREADME = () => { }; export const DefaultToFallbackElementWhenNotInUse = () => { - const fallbackRef = React.useRef(undefined); + const fallbackRef = React.useRef(null); const portalNode = React.useMemo(() => createHtmlPortalNode({ fallbackMountNode: fallbackRef }), []); const [showPortal, setShowPortal] = React.useState(true); return
- + @@ -462,14 +462,14 @@ export const DefaultToFallbackElementWhenNotInUse = () => { }; export const PersistPlaybackWhilstDisplayedInAHiddenElement = () => { - const fallbackRef = React.useRef(undefined); + const fallbackRef = React.useRef(null); const portalNode = React.useMemo(() => createHtmlPortalNode({ fallbackMountNode: fallbackRef }), []); const [showPortal, setShowPortal] = React.useState(true); return
- + @@ -491,7 +491,7 @@ export const PersistPlaybackWhilstDisplayedInAHiddenElement = () => { }; export const CombineFallbackContainerAndSwitchingBetweenTwoPlaces = () => { - const fallbackRef = React.useRef(undefined); + const fallbackRef = React.useRef(null); const portalNode = React.useMemo(() => createHtmlPortalNode({ fallbackMountNode: fallbackRef }), []); const [showPortal, setShowPortal] = React.useState(true); const [secondPortalSelected, setSecondPortalSelected] = React.useState(true); @@ -499,7 +499,7 @@ export const CombineFallbackContainerAndSwitchingBetweenTwoPlaces = () => { return
- +