Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

react-custom-portal

Package Overview
Dependencies
Maintainers
2
Versions
6
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

react-custom-portal - npm Package Compare versions

Comparing version 1.0.3 to 1.0.4

176

dist/createPortal.js

@@ -1,6 +0,11 @@

import React, { createContext, useContext, useState, useLayoutEffect, useEffect } from 'react';
export const createPortal = (name = undefined) => {
import React, { createContext, useContext, useState, useLayoutEffect, useEffect } from "react"; //
//
export const createPortal = options => {
const {
displayName
} = getOptions(options);
const PortalContext = createContext();
const Root = ({
const PortalRoot = ({
children

@@ -14,20 +19,11 @@ }) => {

const Content = props => {
const [id] = useState(createID);
PortalRoot.displayName = `${displayName}.Root`;
const PortalContent = props => {
const portal = useContext(PortalContext);
const data = React.createElement(ContentRenderer, Object.assign({}, props, {
key: id
}));
portal.data.set(id, data);
useLayoutEffect(() => {
portal.data.set(id, data);
portal.dataChanged();
});
useEffect(() => () => {
portal.data.delete(id);
portal.dataChanged();
}, []);
return null;
return renderContentProxy(portal, ContentRenderer, props);
};
PortalContent.displayName = `${displayName}.Content`;
const ContentRenderer = ({

@@ -37,32 +33,128 @@ children

const Render = ({
render = defaultRender
ContentRenderer.displayName = PortalContent.displayName;
const PortalRender = ({
children
}) => {
const [id] = useState(createID);
const portal = useContext(PortalContext);
const [, subscription] = useState();
portal.subscriptions.set(id, subscription);
useLayoutEffect(() => {
portal.subscriptions.set(id, subscription);
});
useEffect(() => () => {
portal.subscriptions.delete(id);
}, []);
return render([...portal.data.values()]);
return usePortalRender(portal, children);
};
if (name) {
Root.displayName = `${name}.Root`;
Content.displayName = `${name}.Content`;
Render.displayName = `${name}.Render`;
}
PortalRender.displayName = `${displayName}.Render`;
return {
Root: PortalRoot,
Content: PortalContent,
Render: PortalRender
};
}; //
//
ContentRenderer.displayName = Content.displayName || Content.name;
export const createGlobalPortal = options => {
const {
displayName
} = getOptions(options);
const portal = createCustomPortal();
const PortalContent = props => renderContentProxy(portal, ContentRenderer, props);
PortalContent.displayName = `${displayName}.Content`;
const ContentRenderer = ({
children
}) => children;
ContentRenderer.displayName = PortalContent.displayName;
const PortalRender = ({
children
}) => usePortalRender(portal, children);
PortalRender.displayName = `${displayName}.Render`;
return {
Root,
Content,
Render
Content: PortalContent,
Render: PortalRender
};
};
}; //
//
const getOptions = (options, component) => {
let actualOptions = typeof options === "string" ? {
displayName: options
} : { ...options
};
if (!actualOptions.displayName) {
actualOptions.displayName = `${component}${++DefaultPortalName}`;
}
return actualOptions;
}; //
//
let DefaultPortalName = 0; //
//
const renderContentProxy = (portal, ContentRenderer, {
children,
preserveContexts,
...proxyProps
}) => function render(index, content) {
if (preserveContexts && index < preserveContexts.length) {
const Context = preserveContexts[index];
return React.createElement(Context.Consumer, null, value => render(index + 1, React.createElement(Context.Provider, {
value: value
}, content)));
} else {
return React.createElement(ContentProxy, {
content,
proxyProps,
portal,
ContentRenderer
});
}
}(0, children); //
//
const ContentProxy = ({
content,
proxyProps,
portal,
ContentRenderer
}) => {
const [id] = useState(createID);
const markup = React.createElement(ContentRenderer, Object.assign({}, proxyProps, {
key: id
}), content);
portal.data.set(id, markup);
useLayoutEffect(() => {
portal.data.set(id, markup);
portal.dataChanged();
});
useEffect(() => () => {
portal.data.delete(id);
portal.dataChanged(); // eslint-disable-next-line
}, []);
return null;
}; //
//
const usePortalRender = (portal, children = defaultRender) => {
const [id] = useState(createID);
const [, subscription] = useState();
portal.subscriptions.set(id, subscription); // eslint-disable-next-line
useLayoutEffect(() => {
portal.subscriptions.set(id, subscription);
});
useEffect(() => () => {
portal.subscriptions.delete(id); // eslint-disable-next-line
}, []);
return children([...portal.data.values()]);
}; //
//
const createCustomPortal = () => new CustomPortal();

@@ -77,3 +169,5 @@

dataChanged() {
[...this.subscriptions.values()].forEach(subscription => subscription({}));
for (const subscription of this.subscriptions.values()) {
subscription({});
}
}

@@ -80,0 +174,0 @@

@@ -1,1 +0,1 @@

export { createPortal } from './createPortal';
export { createPortal, createGlobalPortal } from './createPortal';
{
"name": "react-custom-portal",
"version": "1.0.3",
"version": "1.0.4",
"main": "dist/index.js",

@@ -11,8 +11,8 @@ "dependencies": {},

"@babel/cli": "^7.8.4",
"@testing-library/jest-dom": "^4.2.4",
"@testing-library/react": "^9.3.2",
"@testing-library/user-event": "^7.1.2",
"@testing-library/jest-dom": "^5.1.1",
"@testing-library/react": "^9.4.0",
"@testing-library/user-event": "^10.0.0",
"react": "^16.12.0",
"react-dom": "^16.12.0",
"react-scripts": "3.4.0"
"react-scripts": "^3.4.0"
},

@@ -72,4 +72,3 @@ "scripts": {

"url": "https://github.com/react-custom-portal/react-custom-portal/issues"
},
"homepage": "https://github.com/react-custom-portal/react-custom-portal#readme"
}
}

@@ -15,3 +15,3 @@ ## react-custom-portal

<ExternalMarkup.Content>
This will not be rendered here,
This text will not be rendered here,
but instead it will be rendered within ExternalMarkup.Render

@@ -26,4 +26,3 @@ </ExternalMarkup.Content>

...
{/* The content of <ExternalMarkup.Content ... /> will be rendered here
instead of <ExternalMarkup.Render /> */}
{/* The content of <ExternalMarkup.Content ... /> will be rendered here */}
<ExternalMarkup.Render />

@@ -46,4 +45,21 @@ ...

By default &lt;Portal.Render /> will render the content of all the &lt;Portal.Content /> been rendered within the &lt;Portal.Root />. If you want to tweak some things you can set the `render` property of &lt;Portal.Render /> to a function and it will be passed an array of &lt;Portal.Content />s. Then filter them by their props and return some markup to render.
By default &lt;Portal.Render /> will render the content of all the &lt;Portal.Content />s been rendered within the &lt;Portal.Root />. If you want to tweak some things you can pass a function as the only child of &lt;Portal.Render /> and it will be passed an array of &lt;Portal.Content />s.
`createPortal` can be passed a string `name` to tune the names of created components for debug purpose.
```js
...
<ExternalMarkup.Content shape="circle" ... />
...
<ExternalMarkup.Content shape="rectangle" ... />
...
<ExternalMarkup.Render>
{children => children.filter(child => child.props.shape === "rectangle")}
</ExternalMarkup.Render>
...
```
`createPortal` can be passed an options object with `displayName` prop to tune the names of created components for debug purpose.
```js
const Objects3DSettings = createPortal({ displayName: "Objects3DSettings" })
// now react tools displays "Objects3DSettings.Content" for <Objects3DSettings.Content ... /> instead of "Portal.Content"
```

@@ -1,7 +0,11 @@

import React, { createContext, useContext, useState, useLayoutEffect, useEffect } from 'react'
import React, { createContext, useContext, useState, useLayoutEffect, useEffect } from "react"
export const createPortal = (name = undefined) => {
//
//
export const createPortal = (options) => {
const { displayName } = getOptions(options)
const PortalContext = createContext()
const Root = ({ children }) => {
const PortalRoot = ({ children }) => {
const [portal] = useState(createCustomPortal)

@@ -14,53 +18,122 @@ return (

}
PortalRoot.displayName = `${displayName}.Root`
const Content = (props) => {
const [id] = useState(createID)
const PortalContent = (props) => {
const portal = useContext(PortalContext)
const data = <ContentRenderer {...props} key={id} />
portal.data.set(id, data)
useLayoutEffect(() => {
portal.data.set(id, data)
portal.dataChanged()
})
useEffect(() => () => {
portal.data.delete(id)
portal.dataChanged()
}, [])
return null
return renderContentProxy(portal, ContentRenderer, props)
}
PortalContent.displayName = `${displayName}.Content`
const ContentRenderer = ({ children }) => children
ContentRenderer.displayName = PortalContent.displayName
const Render = ({ render = defaultRender }) => {
const [id] = useState(createID)
const PortalRender = ({ children }) => {
const portal = useContext(PortalContext)
const [, subscription] = useState()
portal.subscriptions.set(id, subscription)
useLayoutEffect(() => {
portal.subscriptions.set(id, subscription)
})
useEffect(() => () => {
portal.subscriptions.delete(id)
}, [])
return render([...portal.data.values()])
return usePortalRender(portal, children)
}
PortalRender.displayName = `${displayName}.Render`
if (name) {
Root.displayName = `${name}.Root`
Content.displayName = `${name}.Content`
Render.displayName = `${name}.Render`
return {
Root: PortalRoot,
Content: PortalContent,
Render: PortalRender,
}
ContentRenderer.displayName = Content.displayName || Content.name
}
//
//
export const createGlobalPortal = (options) => {
const { displayName } = getOptions(options)
const portal = createCustomPortal()
const PortalContent = props => renderContentProxy(portal, ContentRenderer, props)
PortalContent.displayName = `${displayName}.Content`
const ContentRenderer = ({ children }) => children
ContentRenderer.displayName = PortalContent.displayName
const PortalRender = ({ children }) => usePortalRender(portal, children)
PortalRender.displayName = `${displayName}.Render`
return {
Root,
Content,
Render,
Content: PortalContent,
Render: PortalRender,
}
}
//
//
const getOptions = (options, component) => {
let actualOptions = typeof options === "string" ? { displayName: options } : { ...options }
if (!actualOptions.displayName) {
actualOptions.displayName = `${component}${++DefaultPortalName}`
}
return actualOptions
}
//
//
let DefaultPortalName = 0
//
//
const renderContentProxy = (portal, ContentRenderer, { children, preserveContexts, ...proxyProps }) =>
(function render(index, content) {
if (preserveContexts && index < preserveContexts.length) {
const Context = preserveContexts[index]
return (
<Context.Consumer>
{value => render(index + 1, <Context.Provider value={value}>{content}</Context.Provider>)}
</Context.Consumer>
)
} else {
return (
<ContentProxy {...{ content, proxyProps, portal, ContentRenderer }} />
)
}
})(0, children)
//
//
const ContentProxy = ({ content, proxyProps, portal, ContentRenderer }) => {
const [id] = useState(createID)
const markup = <ContentRenderer {...proxyProps} key={id}>{content}</ContentRenderer>
portal.data.set(id, markup)
useLayoutEffect(() => {
portal.data.set(id, markup)
portal.dataChanged()
})
useEffect(() => () => {
portal.data.delete(id)
portal.dataChanged()
// eslint-disable-next-line
}, [])
return null
}
//
//
const usePortalRender = (portal, children = defaultRender) => {
const [id] = useState(createID)
const [, subscription] = useState()
portal.subscriptions.set(id, subscription)
// eslint-disable-next-line
useLayoutEffect(() => {
portal.subscriptions.set(id, subscription)
})
useEffect(() => () => {
portal.subscriptions.delete(id)
// eslint-disable-next-line
}, [])
return children([...portal.data.values()])
}
//
//
const createCustomPortal = () => new CustomPortal()

@@ -73,3 +146,5 @@

dataChanged() {
[...this.subscriptions.values()].forEach(subscription => subscription({}))
for (const subscription of this.subscriptions.values()) {
subscription({})
}
}

@@ -76,0 +151,0 @@ }

@@ -1,1 +0,1 @@

export { createPortal } from './createPortal'
export { createPortal, createGlobalPortal } from './createPortal'

@@ -1,24 +0,48 @@

import React, { useState } from 'react'
import { createPortal } from './components'
import React, { useState, createContext, useContext } from "react"
import { createPortal, createGlobalPortal } from "./components"
export const Portal = createPortal('OnOff')
const Portal = createPortal({ displayName: "OnOff" })
const GlobalPortal = createGlobalPortal({ displayName: "OnOff" })
const ExampleContext = createContext()
export const Switch = () => {
const [state, setState] = useState(false)
return <>
<input id="switch" type="checkbox" value={state} onClick={() => setState(!state)} />
<label htmlFor="switch">switch</label>
<Portal.Content>{state ? "on" : "off"}</Portal.Content>
</>
const Label = ({ text }) => {
const context = useContext(ExampleContext)
return <>{text}<br/>({context})</>
}
const Switch = () => {
const [state, setState] = useState(false)
return <>
<input id="switch" type="checkbox" value={state} onClick={() => setState(!state)} />
<label htmlFor="switch">switch</label>
<Portal.Content preserveContexts={[ExampleContext]}>
<Label text={state ? "on" : "off"} />
</Portal.Content>
</>
}
const SwitchGlobal = () => {
const [state, setState] = useState(false)
return <>
<input id="global-switch" type="checkbox" value={state} onClick={() => setState(!state)} />
<label htmlFor="global-switch">global switch</label>
<GlobalPortal.Content>{state ? "global-on" : "global-off"}</GlobalPortal.Content>
</>
}
const ExampleApp = () => {
return (
<Portal.Root>
<div style={{padding: 20}} ><Switch /></div>
<div style={{padding: 20, backgroundColor: "tomato"}} ><Portal.Render /></div>
</Portal.Root>
)
return <>
<Portal.Root>
<ExampleContext.Provider value="context value is right">
<div style={{padding: 20}} ><Switch /></div>
</ExampleContext.Provider>
<ExampleContext.Provider value="context value is wrong">
<div style={{padding: 20, backgroundColor: "tomato"}} ><Portal.Render /></div>
</ExampleContext.Provider>
</Portal.Root>
<div style={{padding: 20}} ><SwitchGlobal /></div>
<div style={{padding: 20, backgroundColor: "tomato"}} ><GlobalPortal.Render /></div>
</>
}
export default ExampleApp

@@ -1,6 +0,6 @@

import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import ExampleApp from './ExampleApp';
import React from "react"
import ReactDOM from "react-dom"
import "./index.css"
import ExampleApp from "./ExampleApp"
ReactDOM.render(<ExampleApp />, document.getElementById('root'));
ReactDOM.render(<ExampleApp />, document.getElementById("root"))
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc