react-useportal
Advanced tools
Comparing version 1.0.5 to 1.0.6
@@ -7,3 +7,3 @@ import { DOMAttributes, SyntheticEvent, MutableRefObject } from 'react'; | ||
targetEl: HTMLElRef; | ||
} | SyntheticEvent<any, Event>; | ||
} & SyntheticEvent<any, Event>; | ||
declare type CustomEventHandler = (customEvent: CustomEvent) => void; | ||
@@ -10,0 +10,0 @@ declare type CustomEventHandlers = { |
"use strict"; | ||
var __assign = (this && this.__assign) || function () { | ||
__assign = Object.assign || function(t) { | ||
for (var s, i = 1, n = arguments.length; i < n; i++) { | ||
s = arguments[i]; | ||
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) | ||
t[p] = s[p]; | ||
} | ||
return t; | ||
}; | ||
return __assign.apply(this, arguments); | ||
}; | ||
var __rest = (this && this.__rest) || function (s, e) { | ||
@@ -17,18 +28,24 @@ var t = {}; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
const react_1 = require("react"); | ||
const react_dom_1 = require("react-dom"); | ||
const use_ssr_1 = __importDefault(require("use-ssr")); | ||
const errorMessage1 = 'You must either bind to an element or pass an event to openPortal(e).'; | ||
const stopPropagation = (e) => { | ||
e.stopPropagation(); | ||
e.preventDefault(); | ||
var react_1 = require("react"); | ||
var react_dom_1 = require("react-dom"); | ||
var use_ssr_1 = __importDefault(require("use-ssr")); | ||
var errorMessage1 = 'You must either bind to an element or pass an event to openPortal(e).'; | ||
var stopPropagation = function (e) { | ||
if (e && e.nativeEvent) | ||
e.nativeEvent.stopImmediatePropagation(); | ||
if (e) | ||
e.stopPropagation(); | ||
if (e) | ||
e.preventDefault(); | ||
}; | ||
function usePortal(_a = {}) { | ||
var { closeOnOutsideClick = true, closeOnEsc = true, bindTo, // attach the portal to this node in the DOM | ||
isOpen: defaultIsOpen = false, onOpen, onClose, onPortalClick } = _a, eventHandlers = __rest(_a, ["closeOnOutsideClick", "closeOnEsc", "bindTo", "isOpen", "onOpen", "onClose", "onPortalClick"]); | ||
const { isServer, isBrowser } = use_ssr_1.default(); | ||
const [isOpen, makeOpen] = react_1.useState(defaultIsOpen); | ||
function usePortal(_a) { | ||
if (_a === void 0) { _a = {}; } | ||
var _b = _a.closeOnOutsideClick, closeOnOutsideClick = _b === void 0 ? true : _b, _c = _a.closeOnEsc, closeOnEsc = _c === void 0 ? true : _c, bindTo = _a.bindTo, // attach the portal to this node in the DOM | ||
_d = _a.isOpen, // attach the portal to this node in the DOM | ||
defaultIsOpen = _d === void 0 ? false : _d, onOpen = _a.onOpen, onClose = _a.onClose, onPortalClick = _a.onPortalClick, eventHandlers = __rest(_a, ["closeOnOutsideClick", "closeOnEsc", "bindTo", "isOpen", "onOpen", "onClose", "onPortalClick"]); | ||
var _e = use_ssr_1.default(), isServer = _e.isServer, isBrowser = _e.isBrowser; | ||
var _f = react_1.useState(defaultIsOpen), isOpen = _f[0], makeOpen = _f[1]; | ||
// we use this ref because `isOpen` is stale for handleOutsideMouseClick | ||
const open = react_1.useRef(isOpen); | ||
const setOpen = react_1.useCallback((v) => { | ||
var open = react_1.useRef(isOpen); | ||
var setOpen = react_1.useCallback(function (v) { | ||
// workaround to not have stale `isOpen` in the handleOutsideMouseClick | ||
@@ -38,9 +55,9 @@ open.current = v; | ||
}, []); | ||
const targetEl = react_1.useRef(); // this is the element you are clicking/hovering/whatever, to trigger opening the portal | ||
const portal = react_1.useRef(isBrowser ? document.createElement('div') : null); | ||
react_1.useEffect(() => { | ||
var targetEl = react_1.useRef(); // this is the element you are clicking/hovering/whatever, to trigger opening the portal | ||
var portal = react_1.useRef(isBrowser ? document.createElement('div') : null); | ||
react_1.useEffect(function () { | ||
if (isBrowser && !portal.current) | ||
portal.current = document.createElement('div'); | ||
}, [isBrowser, portal]); | ||
const elToMountTo = react_1.useMemo(() => { | ||
var elToMountTo = react_1.useMemo(function () { | ||
if (isServer) | ||
@@ -50,3 +67,10 @@ return; | ||
}, [isServer, bindTo]); | ||
const handleEvent = react_1.useCallback((func, event) => { | ||
var customEvent = react_1.useCallback(function (e) { | ||
var event = e || {}; | ||
event.portal = portal; | ||
event.targetEl = targetEl; | ||
event.event = e; | ||
return event; | ||
}, []); | ||
var handleEvent = react_1.useCallback(function (func, event) { | ||
if (!func || isServer) | ||
@@ -59,12 +83,13 @@ return; | ||
// i.e. onClick, etc. inside usePortal({ onClick({ portal, targetEl }) {} }) | ||
func(Object.assign({ portal, targetEl, event }, (event || {}))); | ||
func(customEvent(event)); | ||
}, [portal, targetEl]); | ||
// this should handle all eventHandlers like onClick, onMouseOver, etc. passed into the config | ||
const customEventHandlers = Object | ||
var customEventHandlers = Object | ||
.entries(eventHandlers) | ||
.reduce((acc, [handlerName, eventHandler]) => { | ||
acc[handlerName] = (event) => handleEvent(eventHandler, event); | ||
.reduce(function (acc, _a) { | ||
var handlerName = _a[0], eventHandler = _a[1]; | ||
acc[handlerName] = function (event) { return handleEvent(eventHandler, event); }; | ||
return acc; | ||
}, {}); | ||
const openPortal = react_1.useCallback((event) => { | ||
var openPortal = react_1.useCallback(function (event) { | ||
if (isServer) | ||
@@ -75,11 +100,9 @@ return; | ||
// setTimeout, but for now this works | ||
if (event) | ||
stopPropagation(event); | ||
if (event == null && targetEl.current == null) { | ||
setTimeout(() => setOpen(true), 0); | ||
setTimeout(function () { return setOpen(true); }, 0); | ||
throw Error(errorMessage1); | ||
} | ||
if (event && event.nativeEvent) | ||
event.nativeEvent.stopImmediatePropagation(); | ||
if (event) | ||
stopPropagation(event); | ||
if (event) | ||
targetEl.current = event.currentTarget; | ||
@@ -92,3 +115,3 @@ if (!targetEl.current) | ||
}, [isServer, portal, setOpen, handleEvent, targetEl, onOpen]); | ||
const closePortal = react_1.useCallback((event) => { | ||
var closePortal = react_1.useCallback(function (event) { | ||
if (isServer) | ||
@@ -98,3 +121,3 @@ return; | ||
stopPropagation(event); | ||
if (onClose) | ||
if (onClose && open.current) | ||
handleEvent(onClose, event); | ||
@@ -104,4 +127,6 @@ if (open.current) | ||
}, [isServer, handleEvent, onClose, setOpen]); | ||
const togglePortal = react_1.useCallback((e) => open.current ? closePortal(e) : openPortal(e), [closePortal, openPortal]); | ||
const handleKeydown = react_1.useCallback(e => { | ||
var togglePortal = react_1.useCallback(function (e) { | ||
return open.current ? closePortal(e) : openPortal(e); | ||
}, [closePortal, openPortal]); | ||
var handleKeydown = react_1.useCallback(function (e) { | ||
stopPropagation(e); | ||
@@ -112,5 +137,3 @@ var ESC = 27; | ||
}, [closeOnEsc, closePortal]); | ||
const handleOutsideMouseClick = react_1.useCallback(e => { | ||
if (!(portal.current instanceof HTMLElement)) | ||
return; | ||
var handleOutsideMouseClick = react_1.useCallback(function (e) { | ||
if (portal.current.contains(e.target) || e.button !== 0 || !open.current || targetEl.current.contains(e.target)) | ||
@@ -122,7 +145,9 @@ return; | ||
}, [isServer, closePortal, closeOnOutsideClick, portal]); | ||
const handleMouseDown = react_1.useCallback(e => { | ||
var handleMouseDown = react_1.useCallback(function (e) { | ||
if (isServer) | ||
return; | ||
stopPropagation(e); | ||
if (onPortalClick) | ||
if (!(portal.current instanceof HTMLElement)) | ||
return; | ||
if (portal.current.contains(e.target) && onPortalClick) | ||
handleEvent(onPortalClick, e); | ||
@@ -132,4 +157,4 @@ handleOutsideMouseClick(e); | ||
// used to remove the event listeners on unmount | ||
const eventListeners = react_1.useRef({}); | ||
react_1.useEffect(() => { | ||
var eventListeners = react_1.useRef({}); | ||
react_1.useEffect(function () { | ||
if (isServer) | ||
@@ -142,13 +167,14 @@ return; | ||
// but for all other event handlers. For now this works. | ||
const eventHandlerMap = { | ||
var eventHandlerMap = { | ||
onScroll: 'scroll', | ||
onWheel: 'wheel', | ||
}; | ||
const node = portal.current; | ||
var node = portal.current; | ||
elToMountTo.appendChild(portal.current); | ||
// handles all special case handlers. Currently only onScroll and onWheel | ||
Object.entries(eventHandlerMap).forEach(([handlerName /* onScroll */, eventListenerName /* scroll */]) => { | ||
Object.entries(eventHandlerMap).forEach(function (_a) { | ||
var handlerName = _a[0] /* onScroll */, eventListenerName = _a[1] /* scroll */; | ||
if (!eventHandlers[handlerName]) | ||
return; | ||
eventListeners.current[handlerName] = (e) => handleEvent(eventHandlers[handlerName], e); | ||
eventListeners.current[handlerName] = function (e) { return handleEvent(eventHandlers[handlerName], e); }; | ||
document.addEventListener(eventListenerName, eventListeners.current[handlerName]); | ||
@@ -158,5 +184,6 @@ }); | ||
document.addEventListener('mousedown', handleMouseDown); | ||
return () => { | ||
return function () { | ||
// handles all special case handlers. Currently only onScroll and onWheel | ||
Object.entries(eventHandlerMap).forEach(([handlerName, eventListenerName]) => { | ||
Object.entries(eventHandlerMap).forEach(function (_a) { | ||
var handlerName = _a[0], eventListenerName = _a[1]; | ||
if (!eventHandlers[handlerName]) | ||
@@ -172,3 +199,4 @@ return; | ||
}, [isServer, handleOutsideMouseClick, handleKeydown, elToMountTo, portal]); | ||
const Portal = react_1.useCallback(({ children }) => { | ||
var Portal = react_1.useCallback(function (_a) { | ||
var children = _a.children; | ||
if (portal.current != null) | ||
@@ -178,7 +206,7 @@ return react_dom_1.createPortal(children, portal.current); | ||
}, [portal]); | ||
return Object.assign([openPortal, closePortal, open.current, Portal, togglePortal], Object.assign(Object.assign({ isOpen: open.current, openPortal, ref: targetEl, closePortal, | ||
togglePortal, | ||
Portal }, customEventHandlers), { bind: Object.assign({ ref: targetEl }, customEventHandlers) })); | ||
return Object.assign([openPortal, closePortal, open.current, Portal, togglePortal], __assign(__assign({ isOpen: open.current, openPortal: openPortal, ref: targetEl, closePortal: closePortal, | ||
togglePortal: togglePortal, | ||
Portal: Portal }, customEventHandlers), { bind: __assign({ ref: targetEl }, customEventHandlers) })); | ||
} | ||
exports.default = usePortal; | ||
//# sourceMappingURL=usePortal.js.map |
{ | ||
"name": "react-useportal", | ||
"version": "1.0.5", | ||
"version": "1.0.6", | ||
"homepage": "https://codesandbox.io/s/w6jp7z4pkk", | ||
@@ -5,0 +5,0 @@ "main": "dist/usePortal.js", |
@@ -234,2 +234,3 @@ <p style="text-align: center;" align="center"> | ||
### Option Usage | ||
```js | ||
@@ -248,10 +249,14 @@ const { | ||
isOpen: false, | ||
// targetEl is the element that you either are attaching a `ref` to | ||
// or that you are putting `openPortal` or `togglePortal` on | ||
onOpen: ({ portal, targetEl, ...event }) => {}, | ||
// `event` has all the fields that a normal `event` would have such as `event.target.value`, etc. | ||
onClose({ portal, targetEl, ...event }) {}, | ||
onPortalClick({ portal, targetEl, ...event }) {}, | ||
// in addition, any event handler such as onClick, onMouseOver, etc will be handled like | ||
onClick({ event, portal, targetEl }) {} | ||
// with the additional `portal` and `targetEl` added to it as seen in the examples below | ||
onOpen: (event) => { | ||
// can access: event.portal, event.targetEl, event.event, event.target, etc. | ||
}, | ||
// `onClose` will not have an `event` unless you pass an `event` to `closePortal` | ||
onClose({ portal, targetEl, event }) {}, | ||
// `targetEl` is the element that you either are attaching a `ref` to | ||
// or that you are putting `openPortal` or `togglePortal` or `closePortal` on | ||
onPortalClick({ portal, targetEl, event }) {}, | ||
// in addition, any event handler such as onClick, onMouseOver, etc will be handled the same | ||
onClick({ portal, targetEl, event }) {} | ||
}) | ||
@@ -258,0 +263,0 @@ ``` |
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
31283
219
287