zent
Version:
一套前端设计语言和基于React的实现
107 lines (106 loc) • 4.51 kB
JavaScript
import { __assign } from "tslib";
import { jsx as _jsx } from "react/jsx-runtime";
import cx from 'classnames';
import { Subject } from 'rxjs';
import { usePopoverContext } from './Context';
import Portal from '../portal';
import { useWindowEventHandler } from '../utils/component/WindowEventHandler';
import findPositionedParent from '../utils/dom/findPositionedParent';
import { INVISIBLE_POSITION } from './placement';
import { useLazy } from '../utils/hooks/useLazy';
import { useAnimationFramed } from '../utils/hooks/useAnimationFramed';
import { createContext, useContext, useEffect, useImperativeHandle, useMemo, useRef, useState, } from 'react';
import { useMounted } from '../utils/hooks/useMounted';
var ContentContext = createContext({
positionChanged$: new Subject(),
});
ContentContext.displayName = 'PopoverContentContext';
function translateToContainerCoordinates(containerRect, bb) {
var left = containerRect.left, top = containerRect.top;
return {
width: bb.width,
height: bb.height,
top: bb.top - top,
left: bb.left - left,
bottom: bb.bottom - top,
right: bb.right - left,
};
}
function getPosition(_a, getContainer, getPositionedParent, portalRef) {
var _b;
var visible = _a.visible, placement = _a.placement, popover = _a.popover, cushion = _a.cushion;
if (!visible) {
return INVISIBLE_POSITION;
}
var container = getContainer();
var parent = getPositionedParent();
var portal = portalRef.current;
var anchor = (_b = popover.getAnchor) === null || _b === void 0 ? void 0 : _b.call(popover);
if (!container ||
!parent ||
!portal ||
!anchor ||
!(anchor instanceof HTMLElement)) {
return INVISIBLE_POSITION;
}
var parentRect = parent.getBoundingClientRect();
var content = portal.container;
var contentRect = content.getBoundingClientRect();
var anchorRect = anchor.getBoundingClientRect();
var relativeRect = translateToContainerCoordinates(parentRect, anchorRect);
var position = placement({
relativeRect: relativeRect,
anchor: anchor,
anchorRect: anchorRect,
content: content,
contentRect: contentRect,
containerRect: parentRect,
container: parent,
cushion: cushion,
});
return position;
}
function PopoverContent(_a) {
var children = _a.children;
var ctx = usePopoverContext();
var parentPositionChanged$ = useContext(ContentContext).positionChanged$;
var contentCtx = useMemo(function () { return ({
positionChanged$: new Subject(),
}); }, []);
var _b = useState(INVISIBLE_POSITION), position = _b[0], setPosition = _b[1];
var contextRef = useRef(ctx);
contextRef.current = ctx;
var containerSelector = ctx.containerSelector, portalRef = ctx.portalRef;
var getContainer = useLazy(function () { return document.querySelector(containerSelector); }, [containerSelector]);
var getPositionedParent = useLazy(function () {
var container = getContainer();
return container && findPositionedParent(container);
}, [getContainer]);
var mounted = useMounted();
var adjustPosition = useAnimationFramed(function () {
if (!mounted.current) {
return;
}
var position = getPosition(contextRef.current, getContainer, getPositionedParent, portalRef);
setPosition(position);
});
useImperativeHandle(ctx.contentRef, function () { return ({
adjustPosition: adjustPosition,
}); }, [adjustPosition]);
useWindowEventHandler('resize', adjustPosition);
useWindowEventHandler('scroll', adjustPosition, {
capture: true,
});
useEffect(function () {
ctx.popover.positionUpdated();
contentCtx.positionChanged$.next();
}, [ctx.popover, position, contentCtx]);
useEffect(function () {
var $ = parentPositionChanged$.subscribe(function () {
adjustPosition();
});
return function () { return $.unsubscribe(); };
}, [parentPositionChanged$, adjustPosition]);
return (_jsx(Portal, __assign({ ref: portalRef, visible: ctx.visible, selector: containerSelector, className: cx('zent-popover-v2', position.className, ctx.className), style: __assign(__assign({}, position.style), ctx.style) }, { children: _jsx(ContentContext.Provider, __assign({ value: contentCtx }, { children: children }), void 0) }), void 0));
}
export default PopoverContent;