@react-md/portal
Advanced tools
Comparing version 2.0.0-alpha.0 to 2.0.0-alpha.1
@@ -8,7 +8,7 @@ import React from "react"; | ||
var ConditionalPortal = function (_a) { | ||
var portal = _a.portal, portalInto = _a.portalInto, portalIntoId = _a.portalIntoId, visible = _a.visible, children = _a.children; | ||
var portal = _a.portal, portalInto = _a.portalInto, portalIntoId = _a.portalIntoId, children = _a.children; | ||
if (!portal && !portalInto && !portalIntoId) { | ||
return children; | ||
} | ||
return (React.createElement(Portal, { into: portalInto, intoId: portalIntoId, visible: visible }, children)); | ||
return (React.createElement(Portal, { into: portalInto, intoId: portalIntoId }, children)); | ||
}; | ||
@@ -30,3 +30,2 @@ if (process.env.NODE_ENV !== "production") { | ||
portalIntoId: PropTypes.string, | ||
visible: PropTypes.bool.isRequired, | ||
children: PropTypes.node, | ||
@@ -33,0 +32,0 @@ }; |
@@ -1,2 +0,2 @@ | ||
import { useState, useEffect } from "react"; | ||
import { useState, useEffect, useRef, useCallback } from "react"; | ||
function getContainer(_a) { | ||
@@ -45,28 +45,48 @@ var into = _a.into, intoId = _a.intoId; | ||
} | ||
/** | ||
* This is an internal hook that will set the portal's container and validate that the portal | ||
* target is valid in dev mode. | ||
* @private | ||
*/ | ||
export function usePortalState(props) { | ||
var visible = props.visible; | ||
var visible = props.visible, into = props.into, intoId = props.intoId; | ||
var _a = useState(null), container = _a[0], setContainer = _a[1]; | ||
useEffect(function () { | ||
setContainer(visible ? getContainer(props) : null); | ||
}, [visible]); | ||
}, [visible, into, intoId]); | ||
return container; | ||
} | ||
/** | ||
* This hook allows you to stagger the visibility of a portal so that it will stay visible | ||
* until an exit animation has finished. This relies on the react-transition-group onExited | ||
* hook to work. | ||
* | ||
* @param visible - Boolean if the main component should be visible. This will trigger the staggered | ||
* animation in or out | ||
* @param onExited - An optional onExited callback | ||
* @return an object containing a boolean if the portal is visible as well as a merged `onExited` callback | ||
* to apply to the react-transition-group child that is animating. | ||
*/ | ||
export function useStaggeredVisibility(_a) { | ||
var visible = _a.visible, onExited = _a.onExited; | ||
var _b = useState(function () { return visible; }), portalVisible = _b[0], setPortalVisible = _b[1]; | ||
var _b = useState(visible), portalVisible = _b[0], setPortalVisible = _b[1]; | ||
if (visible && !portalVisible) { | ||
setPortalVisible(true); | ||
} | ||
var ref = useRef(onExited); | ||
useEffect(function () { | ||
if (visible) { | ||
setPortalVisible(true); | ||
ref.current = onExited; | ||
}); | ||
var handleExited = useCallback(function (node) { | ||
var onExited = ref.current; | ||
if (onExited) { | ||
onExited(node); | ||
} | ||
}, [visible]); | ||
setPortalVisible(false); | ||
}, []); | ||
return { | ||
portalVisible: portalVisible, | ||
onExited: function (node) { | ||
if (onExited) { | ||
onExited(node); | ||
} | ||
setPortalVisible(false); | ||
}, | ||
onExited: handleExited, | ||
}; | ||
} | ||
//# sourceMappingURL=hooks.js.map |
@@ -5,3 +5,2 @@ export { default as Portal } from "./Portal"; | ||
export * from "./ConditionalPortal"; | ||
export { useStaggeredVisibility } from "./hooks"; | ||
//# sourceMappingURL=index.js.map |
@@ -0,7 +1,22 @@ | ||
import { useEffect, useState } from "react"; | ||
import { createPortal } from "react-dom"; | ||
import { usePortalState } from "./hooks"; | ||
var Portal = function (props) { | ||
var visible = props.visible, children = props.children; | ||
var container = usePortalState(props); | ||
if (!visible || !container) { | ||
import getContainer from "./getContainer"; | ||
/** | ||
* This component is a simple wrapper for the `createPortal` API from ReactDOM that will just ensure | ||
* that `null` is always returned for server side rendering as well as a "nice" way to choose specific | ||
* portal targets or just falling back to the `document.body`. | ||
*/ | ||
var Portal = function (_a) { | ||
var into = _a.into, intoId = _a.intoId, children = _a.children; | ||
var _b = useState(null), container = _b[0], setContainer = _b[1]; | ||
// setting the container via useEffect instead of immediately in the render | ||
// just so that it doesn't throw an error immediately if the dom hasn't fully | ||
// painted after a SSR | ||
useEffect(function () { | ||
var nextContainer = getContainer(into, intoId); | ||
if (container !== nextContainer) { | ||
setContainer(nextContainer); | ||
} | ||
}); | ||
if (!container) { | ||
return null; | ||
@@ -25,3 +40,2 @@ } | ||
intoId: PropTypes.string, | ||
visible: PropTypes.bool.isRequired, | ||
children: PropTypes.node, | ||
@@ -28,0 +42,0 @@ }; |
@@ -13,7 +13,7 @@ "use strict"; | ||
var ConditionalPortal = function (_a) { | ||
var portal = _a.portal, portalInto = _a.portalInto, portalIntoId = _a.portalIntoId, visible = _a.visible, children = _a.children; | ||
var portal = _a.portal, portalInto = _a.portalInto, portalIntoId = _a.portalIntoId, children = _a.children; | ||
if (!portal && !portalInto && !portalIntoId) { | ||
return children; | ||
} | ||
return (react_1.default.createElement(Portal_1.default, { into: portalInto, intoId: portalIntoId, visible: visible }, children)); | ||
return (react_1.default.createElement(Portal_1.default, { into: portalInto, intoId: portalIntoId }, children)); | ||
}; | ||
@@ -35,3 +35,2 @@ if (process.env.NODE_ENV !== "production") { | ||
portalIntoId: PropTypes.string, | ||
visible: PropTypes.bool.isRequired, | ||
children: PropTypes.node, | ||
@@ -38,0 +37,0 @@ }; |
@@ -47,27 +47,47 @@ "use strict"; | ||
} | ||
/** | ||
* This is an internal hook that will set the portal's container and validate that the portal | ||
* target is valid in dev mode. | ||
* @private | ||
*/ | ||
function usePortalState(props) { | ||
var visible = props.visible; | ||
var visible = props.visible, into = props.into, intoId = props.intoId; | ||
var _a = react_1.useState(null), container = _a[0], setContainer = _a[1]; | ||
react_1.useEffect(function () { | ||
setContainer(visible ? getContainer(props) : null); | ||
}, [visible]); | ||
}, [visible, into, intoId]); | ||
return container; | ||
} | ||
exports.usePortalState = usePortalState; | ||
/** | ||
* This hook allows you to stagger the visibility of a portal so that it will stay visible | ||
* until an exit animation has finished. This relies on the react-transition-group onExited | ||
* hook to work. | ||
* | ||
* @param visible - Boolean if the main component should be visible. This will trigger the staggered | ||
* animation in or out | ||
* @param onExited - An optional onExited callback | ||
* @return an object containing a boolean if the portal is visible as well as a merged `onExited` callback | ||
* to apply to the react-transition-group child that is animating. | ||
*/ | ||
function useStaggeredVisibility(_a) { | ||
var visible = _a.visible, onExited = _a.onExited; | ||
var _b = react_1.useState(function () { return visible; }), portalVisible = _b[0], setPortalVisible = _b[1]; | ||
var _b = react_1.useState(visible), portalVisible = _b[0], setPortalVisible = _b[1]; | ||
if (visible && !portalVisible) { | ||
setPortalVisible(true); | ||
} | ||
var ref = react_1.useRef(onExited); | ||
react_1.useEffect(function () { | ||
if (visible) { | ||
setPortalVisible(true); | ||
ref.current = onExited; | ||
}); | ||
var handleExited = react_1.useCallback(function (node) { | ||
var onExited = ref.current; | ||
if (onExited) { | ||
onExited(node); | ||
} | ||
}, [visible]); | ||
setPortalVisible(false); | ||
}, []); | ||
return { | ||
portalVisible: portalVisible, | ||
onExited: function (node) { | ||
if (onExited) { | ||
onExited(node); | ||
} | ||
setPortalVisible(false); | ||
}, | ||
onExited: handleExited, | ||
}; | ||
@@ -74,0 +94,0 @@ } |
@@ -12,4 +12,2 @@ "use strict"; | ||
__export(require("./ConditionalPortal")); | ||
var hooks_1 = require("./hooks"); | ||
exports.useStaggeredVisibility = hooks_1.useStaggeredVisibility; | ||
//# sourceMappingURL=index.js.map |
"use strict"; | ||
var __importDefault = (this && this.__importDefault) || function (mod) { | ||
return (mod && mod.__esModule) ? mod : { "default": mod }; | ||
}; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
var react_1 = require("react"); | ||
var react_dom_1 = require("react-dom"); | ||
var hooks_1 = require("./hooks"); | ||
var Portal = function (props) { | ||
var visible = props.visible, children = props.children; | ||
var container = hooks_1.usePortalState(props); | ||
if (!visible || !container) { | ||
var getContainer_1 = __importDefault(require("./getContainer")); | ||
/** | ||
* This component is a simple wrapper for the `createPortal` API from ReactDOM that will just ensure | ||
* that `null` is always returned for server side rendering as well as a "nice" way to choose specific | ||
* portal targets or just falling back to the `document.body`. | ||
*/ | ||
var Portal = function (_a) { | ||
var into = _a.into, intoId = _a.intoId, children = _a.children; | ||
var _b = react_1.useState(null), container = _b[0], setContainer = _b[1]; | ||
// setting the container via useEffect instead of immediately in the render | ||
// just so that it doesn't throw an error immediately if the dom hasn't fully | ||
// painted after a SSR | ||
react_1.useEffect(function () { | ||
var nextContainer = getContainer_1.default(into, intoId); | ||
if (container !== nextContainer) { | ||
setContainer(nextContainer); | ||
} | ||
}); | ||
if (!container) { | ||
return null; | ||
@@ -27,3 +45,2 @@ } | ||
intoId: PropTypes.string, | ||
visible: PropTypes.bool.isRequired, | ||
children: PropTypes.node, | ||
@@ -30,0 +47,0 @@ }; |
{ | ||
"name": "@react-md/portal", | ||
"version": "2.0.0-alpha.0", | ||
"version": "2.0.0-alpha.1", | ||
"description": "This package is for including icons within react-md. There is included support for both font icons and SVG icons. There is also a helper component for applying spacing between icons and text.", | ||
@@ -41,3 +41,3 @@ "scripts": { | ||
"dependencies": { | ||
"@react-md/transition": "^2.0.0-alpha.0" | ||
"@react-md/transition": "^2.0.0-alpha.1" | ||
}, | ||
@@ -47,3 +47,3 @@ "publishConfig": { | ||
}, | ||
"gitHead": "cc5de21740e62c1fd5da8f832f562c48eb028717" | ||
"gitHead": "9197bcdf38df3cff304499431696dc8e950b4b17" | ||
} |
# @react-md/portal | ||
The Portal component is a simple wrapper with React's `createPortal` API that | ||
will automatically generate portal nodes behind the scenes as needed. | ||
will automatically generate portal nodes behind the scenes as needed. Unlike the | ||
majority of `react-md` packages, this package does not export any styles. | ||
@@ -11,1 +12,57 @@ ## Installation | ||
``` | ||
<!-- DOCS_REMOVE --> | ||
## Documentation | ||
You should check out the | ||
[full documentation](https://react-md.dev/packages/portal) for live examples and | ||
more customization information, but an example usage is shown below. | ||
<!-- DOCS_REMOVE_END --> | ||
<!-- INCLUDING_STYLES --> | ||
## Usage | ||
The main purpose of the `Portal` is to be able to fix overflow issues for fixed | ||
elements within the page. If you have `overflow` set to anything other than the | ||
default value, fixed elements might not appear correctly. To work around this, | ||
you can portal that fixed element to a different part of the page and it'll fix | ||
the problem. If none of this makes sense to you at a first glance, you probably | ||
don't need this package. | ||
The example below will just show the API for the portal and not a real world | ||
example. | ||
```tsx | ||
import React, { useState } from "react"; | ||
import { render } from "react-dom"; | ||
import { Portal } from "@react-md/portal"; | ||
const App = () => { | ||
const [visible, setVisible] = useState(false); | ||
return ( | ||
<Fragment> | ||
<button | ||
id="example-button" | ||
type="button" | ||
onClick={() => setVisible(prevVisible => !prevVisible)} | ||
> | ||
Show Portal | ||
</button> | ||
<Portal> | ||
{visible && ( | ||
<h3> | ||
This is some portalled text that will only appear when{" "} | ||
<code>visible</code> | ||
</h3> | ||
)} | ||
</Portal> | ||
</Fragment> | ||
); | ||
}; | ||
render(<App />, document.getElementById("root")); | ||
``` |
@@ -0,1 +1,3 @@ | ||
export { PortalInto } from "./getContainer"; | ||
export { default as Portal } from "./Portal"; | ||
@@ -6,4 +8,1 @@ export * from "./Portal"; | ||
export * from "./ConditionalPortal"; | ||
export { useStaggeredVisibility } from "./hooks"; | ||
export * from "./types.d"; |
import { FunctionComponent, ReactElement } from "react"; | ||
import { PortalInto } from "./types.d"; | ||
import { PortalInto } from "./getContainer"; | ||
/** | ||
@@ -23,6 +23,2 @@ * If any of these props are defined on a component, the component will | ||
/** | ||
* Boolean if the portal would be visible if one of the other portal props are defined or enabled. | ||
*/ | ||
visible: boolean; | ||
/** | ||
* This children to render. | ||
@@ -29,0 +25,0 @@ */ |
import { PortalProps, StaggerablePortalProps } from "./types.d"; | ||
/** | ||
* This is an internal hook that will set the portal's container and validate that the portal | ||
* target is valid in dev mode. | ||
* @private | ||
*/ | ||
export declare function usePortalState(props: PortalProps): HTMLElement | null; | ||
/** | ||
* This hook allows you to stagger the visibility of a portal so that it will stay visible | ||
* until an exit animation has finished. This relies on the react-transition-group onExited | ||
* hook to work. | ||
* | ||
* @param visible - Boolean if the main component should be visible. This will trigger the staggered | ||
* animation in or out | ||
* @param onExited - An optional onExited callback | ||
* @return an object containing a boolean if the portal is visible as well as a merged `onExited` callback | ||
* to apply to the react-transition-group child that is animating. | ||
*/ | ||
export declare function useStaggeredVisibility({ visible, onExited, }: StaggerablePortalProps): { | ||
@@ -4,0 +20,0 @@ portalVisible: boolean; |
@@ -0,1 +1,2 @@ | ||
export { PortalInto } from "./getContainer"; | ||
export { default as Portal } from "./Portal"; | ||
@@ -5,3 +6,1 @@ export * from "./Portal"; | ||
export * from "./ConditionalPortal"; | ||
export { useStaggeredVisibility } from "./hooks"; | ||
export * from "./types.d"; |
@@ -1,4 +0,28 @@ | ||
import { FunctionComponent } from "react"; | ||
import { PortalProps } from "./types.d"; | ||
import { FunctionComponent, ReactNode } from "react"; | ||
import { PortalInto } from "./getContainer"; | ||
export interface PortalProps { | ||
/** | ||
* Either a function that returns an HTMLElement, an HTMLElement, or a `document.querySelector` | ||
* string that will return the HTMLElement to render the children into. If both the `into` and | ||
* `intoId` props are `undefined`, the `document.body` will be chosen instead. | ||
* | ||
* If the `querySelector` string does not return a valid HTMLElement, an error will be thrown. | ||
*/ | ||
into?: PortalInto; | ||
/** | ||
* The id of an element that the portal should be rendered into. If an element with the provided | ||
* id can not be found on the page at the time of mounting, an error will be thrown. | ||
*/ | ||
intoId?: string; | ||
/** | ||
* The children to render within the portal. | ||
*/ | ||
children?: ReactNode; | ||
} | ||
/** | ||
* This component is a simple wrapper for the `createPortal` API from ReactDOM that will just ensure | ||
* that `null` is always returned for server side rendering as well as a "nice" way to choose specific | ||
* portal targets or just falling back to the `document.body`. | ||
*/ | ||
declare const Portal: FunctionComponent<PortalProps>; | ||
export default Portal; |
@@ -13,7 +13,2 @@ import { ReactNode } from "react"; | ||
/** | ||
* Boolean if the portal is currently visible. | ||
*/ | ||
visible: boolean; | ||
/** | ||
* Either a function that returns an HTMLElement, an HTMLElement, or a `document.querySelector` | ||
@@ -37,4 +32,1 @@ * string that will return the HTMLElement to render the children into. If both the `into` and | ||
} | ||
export type StaggerablePortalProps = Pick<PortalProps, "visible"> & | ||
Pick<TransitionProps, "onExited">; |
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
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
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
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
Minified code
QualityThis package contains minified code. This may be harmless in some cases where minified code is included in packaged libraries, however packages on npm should not minify code.
Found 1 instance in 1 package
53075
36
847
2
68