From de346c96eb71b402dd44fe36826a7ae3a2e9b2dd Mon Sep 17 00:00:00 2001 From: Alessandro Pagiaro Date: Sun, 13 Mar 2022 16:30:58 +0100 Subject: [PATCH 1/2] Bubble all events from InPortal to OutPortal --- src/index.tsx | 20 ++++++++++++++++++- stories/html.stories.js | 44 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 63 insertions(+), 1 deletion(-) diff --git a/src/index.tsx b/src/index.tsx index 4035f69..c55b786 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -31,6 +31,7 @@ interface PortalNodeBase> { // If an expected placeholder is provided, only unmount if that's still that was the // latest placeholder we replaced. This avoids some race conditions. unmount(expectedPlaceholder?: Node): void; + } export interface HtmlPortalNode = Component> extends PortalNodeBase { element: HTMLElement; @@ -159,8 +160,25 @@ class InPortal extends React.PureComponent { this.addPropsChannel(); } - componentDidUpdate() { + componentDidUpdate(previousProps: InPortalProps) { this.addPropsChannel(); + if(previousProps.node.element !== this.props.node.element){ + Object.keys(window).forEach(key => { + if (/^on/.test(key)) { + const eventType = key.slice(2); + this.props.node.element.addEventListener(eventType, this.onEventHandler); + if(previousProps.node.element){ + previousProps.node.element.removeEventListener(eventType, this.onEventHandler); + } + } + }); + + } + } + + onEventHandler(e:any){ + e.stopPropagation(); + this.props.node.element.dispatchEvent(e); } render() { diff --git a/stories/html.stories.js b/stories/html.stories.js index 1bf2986..64948c2 100644 --- a/stories/html.stories.js +++ b/stories/html.stories.js @@ -349,5 +349,49 @@ storiesOf('Portals', module) ; } + return + }).add('Events bubbling from PortalOut', () => { + const MyExpensiveComponent = () =>
console.log('expensive')}>expensive!
; + + const MyComponent = () => { + const portalNode = React.useMemo(() => createHtmlPortalNode(), []); + + return
+ {/* + Create the content that you want to move around. + InPortals render as normal, but to detached DOM. + Until this is used MyExpensiveComponent will not + appear anywhere in the page. + */} + + + + + {/* ... The rest of your UI ... */} + + {/* Pass the node to whoever might want to show it: */} + +
; + } + + const ComponentA = (props) => { + return
alert('Div clicked')} + onMouseDown={() => console.log('Mouse Down')} + onMouseEnter={() => console.log('Mouse enter')} + > + {/* ... Some more UI ... */} + + A: + + +
; + } + return }); From 7e487466c212493336a4ddc069c217142308e16b Mon Sep 17 00:00:00 2001 From: Tim Perry Date: Mon, 21 Mar 2022 15:06:19 +0100 Subject: [PATCH 2/2] WIP: Make it clearer where events are firing --- stories/html.stories.js | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/stories/html.stories.js b/stories/html.stories.js index 64948c2..27ed6ea 100644 --- a/stories/html.stories.js +++ b/stories/html.stories.js @@ -363,12 +363,14 @@ storiesOf('Portals', module) Until this is used MyExpensiveComponent will not appear anywhere in the page. */} - - - +
alert('InPortal wrapper click event')}> + + + +
{/* ... The rest of your UI ... */} @@ -378,8 +380,8 @@ storiesOf('Portals', module) } const ComponentA = (props) => { - return
alert('Div clicked')} + return
alert('OutPortal wrapper click event')} onMouseDown={() => console.log('Mouse Down')} onMouseEnter={() => console.log('Mouse enter')} >