@chakra-ui/portal
Advanced tools
Comparing version 1.0.2 to 1.0.3
# Change Log | ||
## 1.0.3 | ||
### Patch Changes | ||
- [`a98817de`](https://github.com/chakra-ui/chakra-ui/commit/a98817de0849bf9eec89fae3faf4fbe085f21011) | ||
Thanks [@segunadebayo](https://github.com/segunadebayo)! - - Fix issue where | ||
`Portal` and `PortalManager` renders elements outside of view. | ||
- Fixed issue where elements within portal used in an `iframe` got rendered | ||
outside of the `iframe`. `Portal` now smartly detects it's document owner | ||
and attaches its node to the correct `document.body` | ||
- Removed extra DOM node `PortalManager` creates. Less is more! | ||
## 1.0.2 | ||
@@ -4,0 +18,0 @@ |
"use strict"; | ||
exports.__esModule = true; | ||
exports.PortalManager = exports.usePortalManager = void 0; | ||
exports.PortalManager = PortalManager; | ||
exports.usePortalManager = void 0; | ||
var React = _interopRequireWildcard(require("react")); | ||
var _utils = require("@chakra-ui/utils"); | ||
var _hooks = require("@chakra-ui/hooks"); | ||
var React = _interopRequireWildcard(require("react")); | ||
@@ -25,45 +24,12 @@ function _getRequireWildcardCache() { if (typeof WeakMap !== "function") return null; var cache = new WeakMap(); _getRequireWildcardCache = function _getRequireWildcardCache() { return cache; }; return cache; } | ||
/** | ||
* PortalManager | ||
* | ||
* Used to manage multiple portals within an application. | ||
* It must be render only once, at the root of your application. | ||
* | ||
* Inspired by BaseWeb's LayerManager component | ||
*/ | ||
var PortalManager = function PortalManager(props) { | ||
function PortalManager(props) { | ||
var children = props.children, | ||
zIndex = props.zIndex; | ||
/** | ||
* The element that wraps the stacked layers | ||
*/ | ||
var ref = React.useRef(null); | ||
var forceUpdate = (0, _hooks.useForceUpdate)(); | ||
/** | ||
* force an update on mount so the Provider works correctly | ||
*/ | ||
(0, _hooks.useSafeLayoutEffect)(function () { | ||
forceUpdate(); | ||
}, []); | ||
/** | ||
* let's detect if use has mutiple instances of this component | ||
*/ | ||
var parentManager = usePortalManager(); | ||
var context = { | ||
node: (parentManager == null ? void 0 : parentManager.node) || ref.current, | ||
zIndex: zIndex | ||
}; | ||
return /*#__PURE__*/React.createElement(PortalManagerContextProvider, { | ||
value: context | ||
}, children, /*#__PURE__*/React.createElement("div", { | ||
className: "chakra-portal-manager", | ||
ref: ref | ||
})); | ||
}; | ||
value: { | ||
zIndex: zIndex | ||
} | ||
}, children); | ||
} | ||
exports.PortalManager = PortalManager; | ||
if (_utils.__DEV__) { | ||
@@ -70,0 +36,0 @@ PortalManager.displayName = "PortalManager"; |
"use strict"; | ||
exports.__esModule = true; | ||
exports.Portal = void 0; | ||
exports.Portal = Portal; | ||
@@ -12,3 +12,3 @@ var _hooks = require("@chakra-ui/hooks"); | ||
var ReactDOM = _interopRequireWildcard(require("react-dom")); | ||
var _reactDom = require("react-dom"); | ||
@@ -28,2 +28,18 @@ var _portalManager = require("./portal-manager"); | ||
var Container = function Container(props) { | ||
var children = props.children, | ||
zIndex = props.zIndex; | ||
return /*#__PURE__*/React.createElement("div", { | ||
className: "chakra-portal-zIndex", | ||
style: { | ||
position: "absolute", | ||
zIndex: zIndex, | ||
top: 0, | ||
left: 0, | ||
right: 0, | ||
bottom: 0 | ||
} | ||
}, children); | ||
}; | ||
/** | ||
@@ -34,94 +50,45 @@ * Portal | ||
* that exists outside the DOM hierarchy of the parent component. | ||
* There is no document link yet | ||
* | ||
* @see Docs https://chakra-ui.com/docs/overlay/portal | ||
*/ | ||
var Portal = function Portal(props) { | ||
var onMount = props.onMount, | ||
onUnmount = props.onUnmount, | ||
children = props.children, | ||
getContainer = props.getContainer; | ||
/** | ||
* Generate the portal's dom node. We'll wrap the children | ||
* in this dom node before mounting it. | ||
*/ | ||
var _React$useState = React.useState(function () { | ||
if (_utils.isBrowser) { | ||
var div = document.createElement("div"); | ||
div.className = "chakra-portal"; | ||
return div; | ||
} // for ssr | ||
return null; | ||
}), | ||
portal = _React$useState[0]; | ||
/** | ||
* This portal might be nested in another portal. | ||
* Let's read from the portal context to check this. | ||
*/ | ||
function Portal(props) { | ||
var tempNode = React.useRef(null); | ||
var portal = React.useRef(null); | ||
var forceUpdate = (0, _hooks.useForceUpdate)(); | ||
var getContainer = (0, _hooks.useCallbackRef)(props.getContainer); | ||
var onMount = (0, _hooks.useCallbackRef)(props.onMount); | ||
var onUnmount = (0, _hooks.useCallbackRef)(props.onUnmount); | ||
var parentPortal = usePortalContext(); | ||
/** | ||
* If there's a PortalManager rendered, let's read from it. | ||
* We use the portal manager to manage multiple portals | ||
*/ | ||
var manager = (0, _portalManager.usePortalManager)(); | ||
var append = React.useCallback(function (container) { | ||
// if user specified a mount node, do nothing. | ||
if (!portal || !container) return; // else, simply append component to the portal node | ||
container.appendChild(portal); | ||
}, [portal]); | ||
(0, _hooks.useSafeLayoutEffect)(function () { | ||
var _ref, _ref2; | ||
var _ref, _getContainer; | ||
// get the custom container from the container prop | ||
var customContainer = getContainer == null ? void 0 : getContainer(); | ||
/** | ||
* We need to know where to mount this portal, we have 4 options: | ||
* - If a mountRef is specified, we'll use that as the container | ||
* - If portal is nested, use the parent portal node as container. | ||
* - If it is not nested, use the manager's node as container | ||
* - else use document.body as containers | ||
*/ | ||
var container = (_ref = (_ref2 = customContainer != null ? customContainer : parentPortal) != null ? _ref2 : manager == null ? void 0 : manager.node) != null ? _ref : document.body; | ||
/** | ||
* Append portal node to the computed container | ||
*/ | ||
append(container); | ||
onMount == null ? void 0 : onMount(); | ||
if (!tempNode.current) return; | ||
var doc = tempNode.current.ownerDocument; | ||
portal.current = doc.createElement("div"); | ||
portal.current.className = Portal.className; | ||
var host = (_ref = (_getContainer = getContainer()) != null ? _getContainer : parentPortal) != null ? _ref : doc.body; | ||
host.appendChild(portal.current); | ||
forceUpdate(); | ||
onMount(); | ||
var portalNode = portal.current; | ||
return function () { | ||
onUnmount == null ? void 0 : onUnmount(); | ||
if (!portal) return; | ||
onUnmount(); | ||
if (container != null && container.contains(portal)) { | ||
container == null ? void 0 : container.removeChild(portal); | ||
if (host.contains(portalNode)) { | ||
host.removeChild(portalNode); | ||
} | ||
}; | ||
}, [getContainer, portal, parentPortal, onMount, onUnmount, manager == null ? void 0 : manager.node, append]); | ||
var portalChildren = manager != null && manager.zIndex ? /*#__PURE__*/React.createElement("div", { | ||
className: "chakra-portal-zIndex", | ||
style: { | ||
position: "absolute", | ||
zIndex: manager.zIndex, | ||
width: "100%" | ||
} | ||
}, children) : children; | ||
}, []); | ||
var childrenToRender = manager != null && manager.zIndex ? /*#__PURE__*/React.createElement(Container, null, props.children) : props.children; | ||
return portal.current ? /*#__PURE__*/(0, _reactDom.createPortal)( /*#__PURE__*/React.createElement(PortalContextProvider, { | ||
value: portal.current | ||
}, childrenToRender), portal.current) : /*#__PURE__*/React.createElement("span", { | ||
ref: tempNode | ||
}); | ||
} | ||
if (!portal) { | ||
return /*#__PURE__*/React.createElement(React.Fragment, null, portalChildren); | ||
} | ||
Portal.className = "chakra-portal"; | ||
Portal.selector = "." + Portal.className; | ||
return /*#__PURE__*/ReactDOM.createPortal( /*#__PURE__*/React.createElement(PortalContextProvider, { | ||
value: portal | ||
}, portalChildren), portal); | ||
}; | ||
exports.Portal = Portal; | ||
if (_utils.__DEV__) { | ||
@@ -128,0 +95,0 @@ Portal.displayName = "Portal"; |
@@ -0,4 +1,3 @@ | ||
import { createContext, __DEV__ } from "@chakra-ui/utils"; | ||
import * as React from "react"; | ||
import { createContext, __DEV__ } from "@chakra-ui/utils"; | ||
import { useSafeLayoutEffect, useForceUpdate } from "@chakra-ui/hooks"; | ||
var [PortalManagerContextProvider, usePortalManager] = createContext({ | ||
@@ -9,12 +8,3 @@ strict: false, | ||
export { usePortalManager }; | ||
/** | ||
* PortalManager | ||
* | ||
* Used to manage multiple portals within an application. | ||
* It must be render only once, at the root of your application. | ||
* | ||
* Inspired by BaseWeb's LayerManager component | ||
*/ | ||
export var PortalManager = props => { | ||
export function PortalManager(props) { | ||
var { | ||
@@ -24,31 +14,8 @@ children, | ||
} = props; | ||
/** | ||
* The element that wraps the stacked layers | ||
*/ | ||
var ref = React.useRef(null); | ||
var forceUpdate = useForceUpdate(); | ||
/** | ||
* force an update on mount so the Provider works correctly | ||
*/ | ||
useSafeLayoutEffect(() => { | ||
forceUpdate(); | ||
}, []); | ||
/** | ||
* let's detect if use has mutiple instances of this component | ||
*/ | ||
var parentManager = usePortalManager(); | ||
var context = { | ||
node: (parentManager == null ? void 0 : parentManager.node) || ref.current, | ||
zIndex | ||
}; | ||
return /*#__PURE__*/React.createElement(PortalManagerContextProvider, { | ||
value: context | ||
}, children, /*#__PURE__*/React.createElement("div", { | ||
className: "chakra-portal-manager", | ||
ref: ref | ||
})); | ||
}; | ||
value: { | ||
zIndex | ||
} | ||
}, children); | ||
} | ||
@@ -55,0 +22,0 @@ if (__DEV__) { |
@@ -1,5 +0,5 @@ | ||
import { useSafeLayoutEffect } from "@chakra-ui/hooks"; | ||
import { createContext, isBrowser, __DEV__ } from "@chakra-ui/utils"; | ||
import { useCallbackRef, useForceUpdate, useSafeLayoutEffect } from "@chakra-ui/hooks"; | ||
import { createContext, __DEV__ } from "@chakra-ui/utils"; | ||
import * as React from "react"; | ||
import * as ReactDOM from "react-dom"; | ||
import { createPortal } from "react-dom"; | ||
import { usePortalManager } from "./portal-manager"; | ||
@@ -11,2 +11,20 @@ var [PortalContextProvider, usePortalContext] = createContext({ | ||
var Container = props => { | ||
var { | ||
children, | ||
zIndex | ||
} = props; | ||
return /*#__PURE__*/React.createElement("div", { | ||
className: "chakra-portal-zIndex", | ||
style: { | ||
position: "absolute", | ||
zIndex, | ||
top: 0, | ||
left: 0, | ||
right: 0, | ||
bottom: 0 | ||
} | ||
}, children); | ||
}; | ||
/** | ||
@@ -17,92 +35,44 @@ * Portal | ||
* that exists outside the DOM hierarchy of the parent component. | ||
* There is no document link yet | ||
* | ||
* @see Docs https://chakra-ui.com/docs/overlay/portal | ||
*/ | ||
export var Portal = props => { | ||
var { | ||
onMount, | ||
onUnmount, | ||
children, | ||
getContainer | ||
} = props; | ||
/** | ||
* Generate the portal's dom node. We'll wrap the children | ||
* in this dom node before mounting it. | ||
*/ | ||
var [portal] = React.useState(() => { | ||
if (isBrowser) { | ||
var div = document.createElement("div"); | ||
div.className = "chakra-portal"; | ||
return div; | ||
} // for ssr | ||
return null; | ||
}); | ||
/** | ||
* This portal might be nested in another portal. | ||
* Let's read from the portal context to check this. | ||
*/ | ||
export function Portal(props) { | ||
var tempNode = React.useRef(null); | ||
var portal = React.useRef(null); | ||
var forceUpdate = useForceUpdate(); | ||
var getContainer = useCallbackRef(props.getContainer); | ||
var onMount = useCallbackRef(props.onMount); | ||
var onUnmount = useCallbackRef(props.onUnmount); | ||
var parentPortal = usePortalContext(); | ||
/** | ||
* If there's a PortalManager rendered, let's read from it. | ||
* We use the portal manager to manage multiple portals | ||
*/ | ||
var manager = usePortalManager(); | ||
var append = React.useCallback(container => { | ||
// if user specified a mount node, do nothing. | ||
if (!portal || !container) return; // else, simply append component to the portal node | ||
container.appendChild(portal); | ||
}, [portal]); | ||
useSafeLayoutEffect(() => { | ||
var _ref, _ref2; | ||
var _ref, _getContainer; | ||
// get the custom container from the container prop | ||
var customContainer = getContainer == null ? void 0 : getContainer(); | ||
/** | ||
* We need to know where to mount this portal, we have 4 options: | ||
* - If a mountRef is specified, we'll use that as the container | ||
* - If portal is nested, use the parent portal node as container. | ||
* - If it is not nested, use the manager's node as container | ||
* - else use document.body as containers | ||
*/ | ||
var container = (_ref = (_ref2 = customContainer != null ? customContainer : parentPortal) != null ? _ref2 : manager == null ? void 0 : manager.node) != null ? _ref : document.body; | ||
/** | ||
* Append portal node to the computed container | ||
*/ | ||
append(container); | ||
onMount == null ? void 0 : onMount(); | ||
if (!tempNode.current) return; | ||
var doc = tempNode.current.ownerDocument; | ||
portal.current = doc.createElement("div"); | ||
portal.current.className = Portal.className; | ||
var host = (_ref = (_getContainer = getContainer()) != null ? _getContainer : parentPortal) != null ? _ref : doc.body; | ||
host.appendChild(portal.current); | ||
forceUpdate(); | ||
onMount(); | ||
var portalNode = portal.current; | ||
return () => { | ||
onUnmount == null ? void 0 : onUnmount(); | ||
if (!portal) return; | ||
onUnmount(); | ||
if (container != null && container.contains(portal)) { | ||
container == null ? void 0 : container.removeChild(portal); | ||
if (host.contains(portalNode)) { | ||
host.removeChild(portalNode); | ||
} | ||
}; | ||
}, [getContainer, portal, parentPortal, onMount, onUnmount, manager == null ? void 0 : manager.node, append]); | ||
var portalChildren = manager != null && manager.zIndex ? /*#__PURE__*/React.createElement("div", { | ||
className: "chakra-portal-zIndex", | ||
style: { | ||
position: "absolute", | ||
zIndex: manager.zIndex, | ||
width: "100%" | ||
} | ||
}, children) : children; | ||
}, []); | ||
var childrenToRender = manager != null && manager.zIndex ? /*#__PURE__*/React.createElement(Container, null, props.children) : props.children; | ||
return portal.current ? /*#__PURE__*/createPortal( /*#__PURE__*/React.createElement(PortalContextProvider, { | ||
value: portal.current | ||
}, childrenToRender), portal.current) : /*#__PURE__*/React.createElement("span", { | ||
ref: tempNode | ||
}); | ||
} | ||
Portal.className = "chakra-portal"; | ||
Portal.selector = "." + Portal.className; | ||
if (!portal) { | ||
return /*#__PURE__*/React.createElement(React.Fragment, null, portalChildren); | ||
} | ||
return /*#__PURE__*/ReactDOM.createPortal( /*#__PURE__*/React.createElement(PortalContextProvider, { | ||
value: portal | ||
}, portalChildren), portal); | ||
}; | ||
if (__DEV__) { | ||
@@ -109,0 +79,0 @@ Portal.displayName = "Portal"; |
import * as React from "react"; | ||
interface PortalManagerContext { | ||
node: HTMLElement; | ||
zIndex?: number; | ||
} | ||
declare const usePortalManager: () => PortalManagerContext; | ||
declare const usePortalManager: () => PortalManagerContext | null; | ||
export { usePortalManager }; | ||
export interface PortalManagerProps { | ||
/** | ||
* Child elements of the Portal manager | ||
* Ideally, it should be at the top-level | ||
* of your application | ||
*/ | ||
children?: React.ReactNode; | ||
/** | ||
* [Z-Index war] If your has multiple elements | ||
* with z-index clashing, you might need to | ||
* apply a z-index to the Portal manager | ||
* with z-index clashing, you might need to apply a z-index to the Portal manager | ||
*/ | ||
zIndex?: number; | ||
} | ||
/** | ||
* PortalManager | ||
* | ||
* Used to manage multiple portals within an application. | ||
* It must be render only once, at the root of your application. | ||
* | ||
* Inspired by BaseWeb's LayerManager component | ||
*/ | ||
export declare const PortalManager: React.FC<PortalManagerProps>; | ||
export declare function PortalManager(props: PortalManagerProps): JSX.Element; | ||
export declare namespace PortalManager { | ||
var displayName: string; | ||
} |
@@ -19,3 +19,3 @@ import * as React from "react"; | ||
*/ | ||
children?: React.ReactNode; | ||
children: React.ReactNode; | ||
} | ||
@@ -27,5 +27,10 @@ /** | ||
* that exists outside the DOM hierarchy of the parent component. | ||
* There is no document link yet | ||
* | ||
* @see Docs https://chakra-ui.com/docs/overlay/portal | ||
*/ | ||
export declare const Portal: React.FC<PortalProps>; | ||
export declare function Portal(props: PortalProps): JSX.Element; | ||
export declare namespace Portal { | ||
var className: string; | ||
var selector: string; | ||
var displayName: string; | ||
} |
{ | ||
"name": "@chakra-ui/portal", | ||
"version": "1.0.2", | ||
"version": "1.0.3", | ||
"description": "React component used to render children outside the DOM hierarchy of the parent component", | ||
@@ -59,9 +59,11 @@ "keywords": [ | ||
"peerDependencies": { | ||
"react": "16.x || 17.x", | ||
"react-dom": "16.x || 17.x" | ||
"react": ">=16.8.6", | ||
"react-dom": ">=16.8.6" | ||
}, | ||
"devDependencies": { | ||
"@types/react-frame-component": "^4.1.1", | ||
"react": "^17.0.1", | ||
"react-dom": "^17.0.1" | ||
"react-dom": "^17.0.1", | ||
"react-frame-component": "^4.1.3" | ||
} | ||
} |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
35444
4
18
273
1