UNPKG

@chayns-components/core

Version:

A set of beautiful React components for developing your own applications with chayns.

163 lines (158 loc) • 7.55 kB
"use strict"; 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