@chayns-components/core
Version:
A set of beautiful React components for developing your own applications with chayns.
163 lines (158 loc) • 7.55 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var _react = _interopRequireWildcard(require("react"));
var _DropdownBodyWrapper = require("./DropdownBodyWrapper.styles");
var _reactDom = require("react-dom");
var _dropdown = require("../../types/dropdown");
var _DelayedDropdownContent = _interopRequireDefault(require("./delayed-dropdown-content/DelayedDropdownContent"));
var _dropdown2 = require("../../hooks/dropdown");
var _container = require("../../hooks/container");
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
const DropdownBodyWrapper = /*#__PURE__*/(0, _react.forwardRef)(({
anchorElement,
bodyWidth,
children,
container: containerProp,
contentHeight = 0,
direction = _dropdown.DropdownDirection.BOTTOM_RIGHT,
maxHeight,
minBodyWidth = 0,
onAvailableMaxHeightChange,
onClose,
onOutsideClick,
onMeasure,
shouldCaptureEvents = true,
shouldShowDropdown
}, ref) => {
const isInChaynsWalletRef = (0, _react.useRef)(false);
const [measuredContentHeight, setMeasuredContentHeight] = (0, _react.useState)(0);
const [measuredContentWidth, setMeasuredContentWidth] = (0, _react.useState)(0);
const [portal, setPortal] = (0, _react.useState)();
const contentRef = (0, _react.useRef)(null);
const shouldPreventClickRef = (0, _react.useRef)(false);
const touchTimeoutRef = (0, _react.useRef)(undefined);
const container = (0, _container.useContainer)({
anchorElement,
container: containerProp
});
const {
transform,
width,
coordinates,
availableMaxHeight
} = (0, _dropdown2.useDropdown)({
anchorElement,
container,
contentHeight,
contentWidth: bodyWidth ?? measuredContentWidth,
direction,
shouldShowDropdown
});
(0, _react.useEffect)(() => {
if (typeof onAvailableMaxHeightChange === 'function') {
onAvailableMaxHeightChange(availableMaxHeight);
}
}, [availableMaxHeight, onAvailableMaxHeightChange]);
const handleClose = (0, _react.useCallback)(() => {
if (typeof onClose === 'function') {
onClose();
}
}, [onClose]);
/**
* This function closes the body
*/
const handleClick = (0, _react.useCallback)(event => {
if (contentRef.current && shouldShowDropdown && !anchorElement.contains(event.target) && !contentRef.current.contains(event.target)) {
event.preventDefault();
event.stopPropagation();
const shouldPreventCloseOnClick = (onOutsideClick === null || onOutsideClick === void 0 ? void 0 : onOutsideClick()) ?? false;
if (!shouldPreventClickRef.current && !shouldPreventCloseOnClick) {
handleClose();
}
}
shouldPreventClickRef.current = false;
}, [anchorElement, handleClose, onOutsideClick, shouldShowDropdown]);
const handleContentMeasure = (0, _react.useCallback)(measurements => {
// Measurements are only needed if the content is shown in the chayns wallet. To prevent
// unnecessary renders, we only set the height if the content is shown in the wallet.
if (isInChaynsWalletRef.current) {
setMeasuredContentHeight(measurements.height);
}
setMeasuredContentWidth(measurements.width);
if (typeof onMeasure === 'function') {
onMeasure(measurements);
}
}, [onMeasure]);
const handleTouchEnd = (0, _react.useCallback)(() => {
clearTimeout(touchTimeoutRef.current);
}, []);
const handleTouchStart = (0, _react.useCallback)(() => {
touchTimeoutRef.current = window.setTimeout(() => {
shouldPreventClickRef.current = true;
}, 500);
}, []);
/**
* This hook listens for clicks
*/
(0, _dropdown2.useDropdownListener)({
onClick: handleClick,
onClose: handleClose,
onTouchEnd: handleTouchEnd,
onTouchStart: handleTouchStart,
shouldCaptureEvents
});
(0, _react.useEffect)(() => {
const isBottomDirection = [_dropdown.DropdownDirection.BOTTOM, _dropdown.DropdownDirection.BOTTOM_LEFT, _dropdown.DropdownDirection.BOTTOM_RIGHT].includes(direction);
const reservationWrapperElement = anchorElement.closest(_container.ContainerAnchor.RESERVATION_WRAPPER);
isInChaynsWalletRef.current = !!(reservationWrapperElement && reservationWrapperElement.contains(anchorElement)) || true;
// This effect checks if additional space is needed to show dropdown content in chayns cards.
if (isBottomDirection && isInChaynsWalletRef.current && measuredContentHeight > 0 && reservationWrapperElement && shouldShowDropdown) {
const availableHeight = window.innerHeight - anchorElement.getBoundingClientRect().bottom;
// If the content height is greater than the available height, we need to add additional space.
// This is to ensure that the dropdown content is fully visible. The 16 pixels are a buffer for shadows.
const additionalNeededSpace = measuredContentHeight + 16 - availableHeight;
if (additionalNeededSpace > 0) {
// Add margin bottom to the reservation wrapper to ensure the dropdown content is fully visible.
reservationWrapperElement.style.marginBottom = `${additionalNeededSpace}px`;
} else {
// Reset the margin bottom if no additional space is needed.
reservationWrapperElement.style.marginBottom = '0px';
}
}
if (isInChaynsWalletRef.current && reservationWrapperElement && !shouldShowDropdown) {
// Reset the margin bottom when the dropdown is closed.
reservationWrapperElement.style.marginBottom = '0px';
}
return () => {
if (reservationWrapperElement) {
reservationWrapperElement.style.marginBottom = '0px';
}
};
}, [anchorElement, direction, measuredContentHeight, shouldShowDropdown]);
(0, _react.useEffect)(() => {
if (!container) return;
setPortal(() => /*#__PURE__*/(0, _reactDom.createPortal)(/*#__PURE__*/_react.default.createElement(_DelayedDropdownContent.default, {
coordinates: coordinates,
onMeasure: handleContentMeasure,
shouldShowContent: shouldShowDropdown,
transform: transform
}, /*#__PURE__*/_react.default.createElement(_DropdownBodyWrapper.StyledDropdownBodyWrapperContent, {
$width: width,
$minWidth: minBodyWidth,
$maxHeight: maxHeight,
$direction: direction,
ref: contentRef,
className: typeof maxHeight === 'number' ? 'chayns-scrollbar' : undefined,
tabIndex: 0
}, children)), container));
}, [children, container, coordinates, direction, handleContentMeasure, maxHeight, minBodyWidth, shouldShowDropdown, transform, width]);
(0, _react.useImperativeHandle)(ref, () => contentRef.current, []);
return /*#__PURE__*/_react.default.createElement(_DropdownBodyWrapper.StyledDropdownBodyWrapper, null, portal);
});
DropdownBodyWrapper.displayName = 'DropdownBodyWrapper';
var _default = exports.default = DropdownBodyWrapper;
//# sourceMappingURL=DropdownBodyWrapper.js.map