rb-react-tiny-popover
Version:
A simple and highly customizable popover react higher order component with no other dependencies!
184 lines • 9.38 kB
JavaScript
;
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);
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.Popover = exports.usePopover = exports.ArrowContainer = exports.useArrowContainer = void 0;
var jsx_runtime_1 = require("react/jsx-runtime");
var react_1 = require("react");
var PopoverPortal_1 = require("./PopoverPortal");
var util_1 = require("./util");
var usePopover_1 = require("./usePopover");
Object.defineProperty(exports, "usePopover", { enumerable: true, get: function () { return usePopover_1.usePopover; } });
var useMemoizedArray_1 = require("./useMemoizedArray");
var useHandlePrevValues_1 = require("./useHandlePrevValues");
var useArrowContainer_1 = require("./useArrowContainer");
Object.defineProperty(exports, "useArrowContainer", { enumerable: true, get: function () { return useArrowContainer_1.useArrowContainer; } });
var ArrowContainer_1 = require("./ArrowContainer");
Object.defineProperty(exports, "ArrowContainer", { enumerable: true, get: function () { return ArrowContainer_1.ArrowContainer; } });
var DEFAULT_POSITIONS = ['top', 'left', 'right', 'bottom'];
var PopoverInternal = (0, react_1.forwardRef)(function (_a, externalRef) {
var isOpen = _a.isOpen, children = _a.children, content = _a.content, _b = _a.positions, externalPositions = _b === void 0 ? DEFAULT_POSITIONS : _b, _c = _a.align, align = _c === void 0 ? 'center' : _c, _d = _a.padding, padding = _d === void 0 ? 0 : _d, _e = _a.reposition, reposition = _e === void 0 ? true : _e, _f = _a.parentElement, parentElement = _f === void 0 ? window.document.body : _f, _g = _a.boundaryElement, boundaryElement = _g === void 0 ? parentElement : _g, containerClassName = _a.containerClassName, containerStyle = _a.containerStyle, transform = _a.transform, _h = _a.transformMode, transformMode = _h === void 0 ? 'absolute' : _h, _j = _a.boundaryInset, boundaryInset = _j === void 0 ? 0 : _j, onClickOutside = _a.onClickOutside, _k = _a.clickOutsideCapture, clickOutsideCapture = _k === void 0 ? false : _k;
var positions = (0, useMemoizedArray_1.useMemoizedArray)(Array.isArray(externalPositions) ? externalPositions : [externalPositions]);
var _l = (0, useHandlePrevValues_1.useHandlePrevValues)({
positions: positions,
reposition: reposition,
transformMode: transformMode,
transform: transform,
boundaryElement: boundaryElement,
boundaryInset: boundaryInset,
}), prev = _l.prev, updatePrevValues = _l.updatePrevValues;
var childRef = (0, react_1.useRef)();
var _m = (0, react_1.useState)({
align: align,
nudgedLeft: 0,
nudgedTop: 0,
position: positions[0],
padding: padding,
childRect: util_1.EMPTY_RECT,
popoverRect: util_1.EMPTY_RECT,
parentRect: util_1.EMPTY_RECT,
boundaryRect: util_1.EMPTY_RECT,
boundaryInset: boundaryInset,
violations: util_1.EMPTY_RECT,
hasViolations: false,
}), popoverState = _m[0], setPopoverState = _m[1];
var onPositionPopover = (0, react_1.useCallback)(function (popoverState) { return setPopoverState(popoverState); }, []);
var _o = (0, usePopover_1.usePopover)({
isOpen: isOpen,
childRef: childRef,
containerClassName: containerClassName,
parentElement: parentElement,
boundaryElement: boundaryElement,
transform: transform,
transformMode: transformMode,
positions: positions,
align: align,
padding: padding,
boundaryInset: boundaryInset,
reposition: reposition,
onPositionPopover: onPositionPopover,
}), positionPopover = _o.positionPopover, popoverRef = _o.popoverRef, scoutRef = _o.scoutRef;
(0, react_1.useLayoutEffect)(function () {
var shouldUpdate = true;
var updatePopover = function () {
var _a, _b;
if (isOpen && shouldUpdate) {
var childRect = (_a = childRef === null || childRef === void 0 ? void 0 : childRef.current) === null || _a === void 0 ? void 0 : _a.getBoundingClientRect();
var popoverRect = (_b = popoverRef === null || popoverRef === void 0 ? void 0 : popoverRef.current) === null || _b === void 0 ? void 0 : _b.getBoundingClientRect();
if (childRect != null &&
popoverRect != null &&
(!(0, util_1.rectsAreEqual)(childRect, popoverState.childRect) ||
popoverRect.width !== popoverState.popoverRect.width ||
popoverRect.height !== popoverState.popoverRect.height ||
popoverState.padding !== padding ||
popoverState.align !== align ||
positions !== prev.positions ||
reposition !== prev.reposition ||
transformMode !== prev.transformMode ||
transform !== prev.transform ||
boundaryElement !== prev.boundaryElement ||
boundaryInset !== prev.boundaryInset)) {
positionPopover();
}
updatePrevValues();
if (shouldUpdate) {
window.requestAnimationFrame(updatePopover);
}
}
};
updatePopover();
return function () {
shouldUpdate = false;
};
}, [
align,
boundaryElement,
boundaryInset,
isOpen,
padding,
popoverRef,
popoverState.align,
popoverState.childRect,
popoverState.padding,
popoverState.popoverRect.height,
popoverState.popoverRect.width,
positionPopover,
positions,
prev.boundaryElement,
prev.boundaryInset,
prev.positions,
prev.reposition,
prev.transform,
prev.transformMode,
reposition,
transform,
transformMode,
updatePrevValues,
]);
(0, react_1.useEffect)(function () {
var popoverElement = popoverRef.current;
Object.assign(popoverElement.style, containerStyle);
return function () {
Object.keys(containerStyle !== null && containerStyle !== void 0 ? containerStyle : {}).forEach(function (key) {
return delete popoverElement.style[key];
});
};
}, [containerStyle, isOpen, popoverRef]);
var handleOnClickOutside = (0, react_1.useCallback)(function (e) {
var _a, _b;
if (isOpen &&
!((_a = popoverRef.current) === null || _a === void 0 ? void 0 : _a.contains(e.target)) &&
!((_b = childRef.current) === null || _b === void 0 ? void 0 : _b.contains(e.target))) {
onClickOutside === null || onClickOutside === void 0 ? void 0 : onClickOutside(e);
}
}, [isOpen, onClickOutside, popoverRef]);
var handleWindowResize = (0, react_1.useCallback)(function () {
if (childRef.current && isOpen) {
window.requestAnimationFrame(function () { return positionPopover(); });
}
}, [positionPopover, isOpen]);
(0, react_1.useEffect)(function () {
var body = parentElement;
body.addEventListener('click', handleOnClickOutside, clickOutsideCapture);
body.addEventListener('contextmenu', handleOnClickOutside, clickOutsideCapture);
window.addEventListener('resize', handleWindowResize);
return function () {
body.removeEventListener('click', handleOnClickOutside, clickOutsideCapture);
body.removeEventListener('contextmenu', handleOnClickOutside, clickOutsideCapture);
window.removeEventListener('resize', handleWindowResize);
};
}, [clickOutsideCapture, handleOnClickOutside, handleWindowResize, parentElement]);
var handleRef = (0, react_1.useCallback)(function (node) {
childRef.current = node;
if (externalRef != null) {
if (typeof externalRef === 'object') {
externalRef.current = node;
}
else if (typeof externalRef === 'function') {
externalRef(node);
}
}
}, [externalRef]);
var renderChild = function () { return (0, react_1.cloneElement)(children, { ref: handleRef }); };
var renderPopover = function () {
if (!isOpen)
return null;
return ((0, jsx_runtime_1.jsx)(PopoverPortal_1.PopoverPortal, { element: popoverRef.current, scoutElement: scoutRef.current, container: parentElement, children: typeof content === 'function' ? content(popoverState) : content }));
};
return ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [renderChild(), renderPopover()] }));
});
exports.Popover = (0, react_1.forwardRef)(function (props, ref) {
if (typeof window === 'undefined')
return props.children;
return (0, jsx_runtime_1.jsx)(PopoverInternal, __assign({}, props, { ref: ref }));
});
//# sourceMappingURL=Popover.js.map