UNPKG

@cainiaofe/cn-ui-m

Version:
121 lines (120 loc) 6.52 kB
import { __awaiter, __generator } from "tslib"; import React, { forwardRef, useCallback, useEffect, useImperativeHandle, useRef, useState, } from 'react'; import classNames from 'classnames'; import { Arrow } from './arrow'; import { arrow, autoUpdate, computePosition, platform, flip, hide, limitShift, offset, shift, } from '@floating-ui/dom'; import { useLockScroll } from "../../utils/use-lock-scroll"; import { Portal } from '../cn-modal/portal'; import { withNativeProps } from '@cainiaofe/cn-ui-common'; import { useClickAway } from 'ahooks'; import { isRTL } from '@cainiaofe/cn-i18n'; var rtl = isRTL(); var classNamePrefix = 'cn-ui-m-popover'; export var CnPopoverModal = forwardRef(function (props, ref) { var _a = props.visible, visibleProps = _a === void 0 ? false : _a, container = props.container, placement = props.placement, _b = props.floatingMode, floatingMode = _b === void 0 ? 'light' : _b, _c = props.floatingContent, floatingContent = _c === void 0 ? '' : _c, className = props.className, clickAwayCallback = props.clickAwayCallback; var _d = useState(props.visible), visible = _d[0], setVisible = _d[1]; useEffect(function () { if (visible && !visibleProps) { var t1_1 = setTimeout(function () { return setVisible(false); }, 300); return function () { return clearTimeout(t1_1); }; } setVisible(visibleProps); return function () { }; }, [visible, visibleProps]); var containerRef = useRef(null); useLockScroll(containerRef, !!visible); var floatingRef = useRef(null); var arrowRef = useRef(null); var floatingElement = withNativeProps(props, React.createElement("div", { className: classNames(CN_UI_HASH_CLASS_NAME, classNamePrefix, "".concat(classNamePrefix, "-").concat(floatingMode), !visibleProps && "".concat(classNamePrefix, "-hidden"), className), ref: floatingRef, dir: rtl ? 'rtl' : undefined, "data-testid": "cn-popover-modal" }, React.createElement("div", { className: "".concat(classNamePrefix, "-arrow"), ref: arrowRef }, React.createElement(Arrow, { className: "".concat(classNamePrefix, "-arrow-icon") })), React.createElement("div", { className: "".concat(classNamePrefix, "-inner") }, React.createElement("div", { className: "".concat(classNamePrefix, "-inner-content") }, floatingContent)))); var _e = useState(null), targetElement = _e[0], setTargetElement = _e[1]; var floatingUpdate = useCallback(function (targetRef) { return __awaiter(void 0, void 0, void 0, function () { var target, floating, arrowElement, _a, x, y, realPlacement, middlewareData, side, arrowSide, _b, arrowX, arrowY, arrowRotate; var _c; var _d, _e, _f; return __generator(this, function (_g) { switch (_g.label) { case 0: target = targetRef ? ((_e = (_d = targetRef.current) === null || _d === void 0 ? void 0 : _d.element) !== null && _e !== void 0 ? _e : null) : targetElement; floating = floatingRef.current; arrowElement = arrowRef.current; setTargetElement(target); if (!target || !floating || !arrowElement) return [2 /*return*/]; return [4 /*yield*/, computePosition(target, floating, { placement: placement, platform: platform, middleware: [ offset(12), shift({ padding: 4, crossAxis: false, limiter: limitShift(), }), flip(), hide(), arrow({ element: arrowElement, padding: 12, }), ], })]; case 1: _a = _g.sent(), x = _a.x, y = _a.y, realPlacement = _a.placement, middlewareData = _a.middlewareData; Object.assign(floating.style, { left: "".concat(x, "px"), top: "".concat(y, "px"), }); side = realPlacement.split('-')[0]; arrowSide = { top: 'bottom', right: 'left', bottom: 'top', left: 'right', }[side]; _b = (_f = middlewareData.arrow) !== null && _f !== void 0 ? _f : {}, arrowX = _b.x, arrowY = _b.y; Object.assign(arrowElement.style, (_c = { left: arrowX != null ? "".concat(arrowX, "px") : '', top: arrowY != null ? "".concat(arrowY, "px") : '', right: '', bottom: '' }, _c[arrowSide] = '-8px', _c)); arrowRotate = { top: '0deg', bottom: '180deg', left: '270deg', right: '90deg', }[side]; arrowElement.style.setProperty('--arrow-icon-rotate', arrowRotate); return [2 /*return*/]; } }); }); }, [placement, targetElement]); useEffect(function () { var floatingEle = floatingRef.current; if (!targetElement || !floatingEle) return; return autoUpdate(targetElement, floatingEle, function () { setTargetElement(targetElement); floatingUpdate(); }, { elementResize: typeof ResizeObserver !== 'undefined', }); }, [floatingUpdate, targetElement]); useImperativeHandle(ref, function () { var retRef = { floatingUpdate: floatingUpdate, floatingRef: floatingRef, }; return retRef; }, [floatingUpdate]); useClickAway(clickAwayCallback, [function () { return targetElement; }, floatingRef], ['click', 'touchmove']); return React.createElement(Portal, { container: container }, floatingElement); });