Skip to content

Commit

Permalink
Bubble all events from InPortal to OutPortal
Browse files Browse the repository at this point in the history
  • Loading branch information
alessandro308 committed Mar 13, 2022
1 parent 3426281 commit de346c9
Show file tree
Hide file tree
Showing 2 changed files with 63 additions and 1 deletion.
20 changes: 19 additions & 1 deletion src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ interface PortalNodeBase<C extends Component<any>> {
// 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<C extends Component<any> = Component<any>> extends PortalNodeBase<C> {
element: HTMLElement;
Expand Down Expand Up @@ -159,8 +160,25 @@ class InPortal extends React.PureComponent<InPortalProps, { nodeProps: {} }> {
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() {
Expand Down
44 changes: 44 additions & 0 deletions stories/html.stories.js
Original file line number Diff line number Diff line change
Expand Up @@ -349,5 +349,49 @@ storiesOf('Portals', module)
</div>;
}

return <MyComponent componentToShow='component-a' />
}).add('Events bubbling from PortalOut', () => {
const MyExpensiveComponent = () => <div onMouseDown={() => console.log('expensive')}>expensive!</div>;

const MyComponent = () => {
const portalNode = React.useMemo(() => createHtmlPortalNode(), []);

return <div>
{/*
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.
*/}
<InPortal node={portalNode}>
<MyExpensiveComponent
// Optionally provide props to use before this enters the DOM
myProp={"defaultValue"}
/>
</InPortal>

{/* ... The rest of your UI ... */}

{/* Pass the node to whoever might want to show it: */}
<ComponentA portalNode={portalNode} />
</div>;
}

const ComponentA = (props) => {
return <div
onClick={() => alert('Div clicked')}
onMouseDown={() => console.log('Mouse Down')}
onMouseEnter={() => console.log('Mouse enter')}
>
{/* ... Some more UI ... */}

A:

<OutPortal
node={props.portalNode} // Show the content from this node here
/>
</div>;
}

return <MyComponent componentToShow='component-a' />
});

0 comments on commit de346c9

Please sign in to comment.