react-useportal
Advanced tools
Comparing version 0.1.43 to 0.1.44
"use strict"; | ||
var __importDefault = (this && this.__importDefault) || function (mod) { | ||
return (mod && mod.__esModule) ? mod : { "default": mod }; | ||
}; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
const react_1 = require("react"); | ||
const react_dom_1 = require("react-dom"); | ||
const emptyFunction = () => { }; | ||
const use_ssr_1 = __importDefault(require("use-ssr")); | ||
function usePortal({ closeOnOutsideClick = true, closeOnEsc = true, renderOnClickedElement, renderBelowClickedElement, // appear directly under the clicked element/node in the DOM | ||
bindTo, // attach the portal to this node in the DOM | ||
isOpen: defaultIsOpen = false, stateful = true, } = {}) { | ||
const isBrowser = react_1.useRef(false); | ||
react_1.useEffect(() => { | ||
isBrowser.current = true; | ||
return () => { | ||
isBrowser.current = false; | ||
}; | ||
}, []); | ||
// if we're not on the browser, don't continue | ||
if (!isBrowser.current) | ||
return Object.assign([emptyFunction, emptyFunction, false, emptyFunction], { | ||
isOpen: false, | ||
openPortal: emptyFunction, | ||
onMouseDown: emptyFunction, | ||
ref: null, | ||
closePortal: emptyFunction, | ||
togglePortal: emptyFunction, | ||
Portal: emptyFunction, | ||
bind: { | ||
onMouseDown: emptyFunction, | ||
ref: null | ||
} | ||
}); | ||
const { isServer, isBrowser } = use_ssr_1.default(); | ||
const [isOpen, makeOpen] = react_1.useState(defaultIsOpen); | ||
// we use this ref because `isOpen` is stale for handleOutsideMouseClick | ||
const open = react_1.useRef(isOpen); | ||
@@ -39,4 +22,12 @@ const setOpen = react_1.useCallback(v => { | ||
const renderByRef = react_1.useRef(); | ||
const portal = react_1.useRef(document && document.createElement('div')); | ||
const elToMountTo = react_1.useMemo(() => (bindTo && react_dom_1.findDOMNode(bindTo)) || (document && document.body), []); | ||
const portal = react_1.useRef(isBrowser && document.createElement('div')); | ||
react_1.useEffect(() => { | ||
if (isBrowser && !portal.current) | ||
portal.current = document.createElement('div'); | ||
}, [isBrowser]); | ||
const elToMountTo = react_1.useMemo(() => { | ||
if (isServer) | ||
return; | ||
return ((bindTo && react_dom_1.findDOMNode(bindTo)) || document.body); | ||
}, [isServer, bindTo]); | ||
const handleKeydown = react_1.useCallback(e => { | ||
@@ -46,4 +37,6 @@ var ESC = 27; | ||
setOpen(false); | ||
}, []); | ||
}, [closeOnEsc, stateful, setOpen]); | ||
const openPortal = react_1.useCallback(e => { | ||
if (isServer) | ||
return; | ||
// for some reason, when we don't have the event argument there | ||
@@ -57,3 +50,3 @@ // is a weird race condition, would like to see if we can remove | ||
const { left, top, height } = e.target.getBoundingClientRect(); | ||
if (renderOnClickedElement) { | ||
if (renderOnClickedElement && portal.current instanceof HTMLElement) { | ||
portal.current.style.height = '0px'; | ||
@@ -64,3 +57,3 @@ portal.current.style.position = 'absolute'; | ||
} | ||
else if (renderBelowClickedElement) { | ||
else if (renderBelowClickedElement && portal.current instanceof HTMLElement) { | ||
portal.current.style.position = 'absolute'; | ||
@@ -71,14 +64,22 @@ portal.current.style.left = left + 'px'; | ||
stateful && setOpen(true); | ||
}, [stateful, portal]); | ||
}, [isServer, stateful, portal, setOpen, renderBelowClickedElement, renderOnClickedElement]); | ||
const closePortal = react_1.useCallback(() => { | ||
if (isServer) | ||
return; | ||
if (open.current) | ||
setOpen(false); | ||
}, [isOpen, open.current]); | ||
}, [isServer, isOpen, open.current, setOpen]); | ||
const togglePortal = react_1.useCallback(e => (isOpen ? setOpen(false) : openPortal(e)), [isOpen, open.current, setOpen, openPortal]); | ||
const handleOutsideMouseClick = react_1.useCallback(({ target, button }) => { | ||
if (portal.current.contains(target) || button !== 0 || !portal.current || !open.current) | ||
if (isServer || !(portal.current instanceof HTMLElement)) | ||
return; | ||
if (portal.current.contains(target) || button !== 0 || !open.current) | ||
return; | ||
if (stateful && closeOnOutsideClick) | ||
closePortal(); | ||
}, [isOpen]); | ||
}, [isServer, isOpen, stateful, closePortal, closeOnOutsideClick]); | ||
react_1.useEffect(() => { | ||
if (isServer || !(elToMountTo instanceof HTMLElement) || !(portal.current instanceof HTMLElement)) | ||
return; | ||
const node = portal.current; | ||
elToMountTo.appendChild(portal.current); | ||
@@ -90,7 +91,10 @@ document && document.addEventListener('keydown', handleKeydown); | ||
document && document.removeEventListener('click', handleOutsideMouseClick); | ||
elToMountTo.removeChild(portal.current); | ||
elToMountTo.removeChild(node); | ||
}; | ||
}, [handleOutsideMouseClick, handleKeydown]); | ||
const togglePortal = react_1.useCallback(e => isOpen ? setOpen(false) : openPortal(e), [isOpen, open.current]); | ||
const Portal = ({ children }) => react_dom_1.createPortal(children, portal.current); | ||
}, [isServer, handleOutsideMouseClick, handleKeydown, elToMountTo]); | ||
const Portal = ({ children }) => { | ||
if (portal.current instanceof HTMLElement) | ||
return react_dom_1.createPortal(children, portal.current); | ||
return null; | ||
}; | ||
return Object.assign([ | ||
@@ -116,4 +120,3 @@ openPortal, | ||
} | ||
exports.usePortal = usePortal; | ||
exports.default = usePortal; | ||
//# sourceMappingURL=usePortal.js.map |
{ | ||
"name": "react-useportal", | ||
"version": "0.1.43", | ||
"version": "0.1.44", | ||
"homepage": "https://codesandbox.io/s/w6jp7z4pkk", | ||
@@ -24,3 +24,4 @@ "main": "dist/usePortal.js", | ||
"parcel-bundler": "^1.12.3", | ||
"typescript": "^3.4.5" | ||
"typescript": "^3.4.5", | ||
"use-ssr": "^1.0.13" | ||
}, | ||
@@ -30,4 +31,8 @@ "scripts": { | ||
"build": "rm -rf dist && ./node_modules/.bin/tsc --module CommonJS", | ||
"publish": "yarn build && yarn publish" | ||
"prepublish": "yarn build", | ||
"test": "echo \"Error: no test specified\" && exit 1" | ||
}, | ||
"files": [ | ||
"dist" | ||
], | ||
"keywords": [ | ||
@@ -34,0 +39,0 @@ "react", |
@@ -152,5 +152,6 @@ <p style="text-align: center;" align="center"> | ||
``` | ||
- [X] make isomorphic | ||
- [ ] tests (priority) | ||
- [ ] see if it's reliable to rely on react's internals for determining whether we're on the server or not. [Here](https://github.com/JedWatson/exenv) it says not to, but that was also 3 years ago. | ||
- [ ] make work without requiring the html synthetic event & document when you are required to have it and when you are not | ||
- [ ] clean up code | ||
- [X] make isomorphic |
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
No tests
QualityPackage does not have any tests. This is a strong signal of a poorly maintained or low quality package.
Found 1 instance in 1 package
157
18460
7
6
144
2
1