zent
Version:
一套前端设计语言和基于React的实现
147 lines (146 loc) • 7.14 kB
JavaScript
import { __assign } from "tslib";
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
import cx from 'classnames';
import { createRef, forwardRef, useCallback, useEffect, useImperativeHandle, useMemo, useRef, useState, } from 'react';
import { Waypoint } from '../waypoint';
import { useCallbackRef } from '../utils/hooks/useCallbackRef';
import isBrowser from '../utils/isBrowser';
import { useResizeObserver } from '../utils/hooks/useResizeObserver';
import { WindowResizeHandler } from '../utils/component/WindowResizeHandler';
import { getViewportHeight } from '../utils/dom/getViewportSize';
export var Affix = forwardRef(function (_a, affixRef) {
var className = _a.className, placeholderClassName = _a.placeholderClassName, children = _a.children, offsetTop = _a.offsetTop, offsetBottom = _a.offsetBottom, getAffixContainer = _a.getAffixContainer, _b = _a.zIndex, zIndex = _b === void 0 ? 10 : _b, onPin = _a.onPin, onUnpin = _a.onUnpin;
var _c = useState(1), position = _c[0], setPosition = _c[1];
var _d = useState(), width = _d[0], setWidth = _d[1];
var _e = useState(), height = _e[0], setHeight = _e[1];
var placeholderRef = useRef(createRef());
var onPinCallbackRef = useCallbackRef(onPin);
var onUnpinCallbackRef = useCallbackRef(onUnpin);
var useTop = typeof offsetTop === 'number';
var useBottom = typeof offsetBottom === 'number';
var _f = useState(null), container = _f[0], setContainer = _f[1];
var _g = useState(0), containerTop = _g[0], setContainerTop = _g[1];
var _h = useState(0), containerBottom = _h[0], setContainerBottom = _h[1];
var _j = useState(0), windowHeight = _j[0], setWindowHeight = _j[1];
var containerBoundingRectChange = useCallback(function (container) {
var rect = container.getBoundingClientRect();
useTop && setContainerTop(rect.top);
useBottom && setContainerBottom(rect.bottom);
}, [useTop, useBottom]);
var setSize = useCallback(function (entries) {
var _a = entries[0], borderBoxSize = _a.borderBoxSize, contentRect = _a.contentRect;
if (borderBoxSize && borderBoxSize.length > 0) {
var _b = borderBoxSize[0], width_1 = _b.inlineSize, height_1 = _b.blockSize;
setWidth(width_1);
setHeight(height_1);
}
else {
var width_2 = contentRect.width, height_2 = contentRect.height;
setWidth(width_2);
setHeight(height_2);
}
}, []);
var _k = useResizeObserver(setSize), observe = _k.observe, disconnect = _k.disconnect;
var pin = useCallback(function (expectedPosition) {
return function (_a) {
var _b, _c;
var currentPosition = _a.currentPosition;
if (currentPosition !== expectedPosition) {
return;
}
var node = (_b = placeholderRef.current) === null || _b === void 0 ? void 0 : _b.current;
if (node) {
setWidth(node.offsetWidth);
setHeight(node.offsetHeight);
}
observe(node);
setPosition(currentPosition);
(_c = onPinCallbackRef.current) === null || _c === void 0 ? void 0 : _c.call(onPinCallbackRef);
};
}, [onPinCallbackRef, observe]);
var unpin = useCallback(function (expectedPrevPosition) {
return function (_a) {
var _b;
var currentPosition = _a.currentPosition, previousPosition = _a.previousPosition;
if (previousPosition !== expectedPrevPosition) {
return;
}
setWidth(undefined);
setHeight(undefined);
disconnect();
setPosition(currentPosition);
(_b = onUnpinCallbackRef.current) === null || _b === void 0 ? void 0 : _b.call(onUnpinCallbackRef);
};
}, [onUnpinCallbackRef, disconnect]);
var _l = useMemo(function () { return [pin(0), unpin(0)]; }, [pin, unpin]), pinTop = _l[0], unpinTop = _l[1];
var _m = useMemo(function () { return [pin(2), unpin(2)]; }, [pin, unpin]), pinBottom = _m[0], unpinBottom = _m[1];
var placeholderStyle = useMemo(function () {
if (position === 1) {
return {};
}
return {
height: height,
};
}, [height, position]);
var containerStyle = useMemo(function () {
if (position === 0 ||
position === 2) {
var styles = {
position: 'fixed',
zIndex: zIndex,
width: width,
};
if (container) {
if (position === 0) {
styles.top = offsetTop + containerTop;
}
else {
styles.bottom = offsetBottom + (windowHeight - containerBottom);
}
}
else {
if (position === 0) {
styles.top = offsetTop;
}
else {
styles.bottom = offsetBottom;
}
}
return styles;
}
return { position: 'static' };
}, [
container,
offsetBottom,
offsetTop,
containerTop,
containerBottom,
windowHeight,
position,
width,
zIndex,
]);
var updatePosition = useCallback(function () {
container && containerBoundingRectChange(container);
}, [container, containerBoundingRectChange]);
useEffect(function () {
var containerNode = getAffixContainer === null || getAffixContainer === void 0 ? void 0 : getAffixContainer();
if (containerNode) {
setContainer(containerNode);
containerBoundingRectChange(containerNode);
setWindowHeight(getViewportHeight());
}
}, [getAffixContainer, containerBoundingRectChange]);
var onWindowResize = useCallback(function () {
setWindowHeight(getViewportHeight());
}, []);
useImperativeHandle(affixRef, function () { return ({
updatePosition: updatePosition,
}); });
var ancestor = useMemo(function () {
return container !== null && container !== void 0 ? container : (isBrowser ? window : undefined);
}, [container]);
return (_jsxs(_Fragment, { children: [useTop && (_jsx(Waypoint, { scrollableAncestor: ancestor, onEnter: unpinTop, onLeave: pinTop, topOffset: offsetTop }, void 0)), _jsx("div", __assign({ className: cx('zent-affix-placeholder', placeholderClassName), style: placeholderStyle, ref: placeholderRef.current, "data-zv": '10.0.17' }, { children: _jsx("div", __assign({ className: cx('zent-affix', className), style: containerStyle, "data-zv": '10.0.17' }, { children: children }), void 0) }), void 0), useBottom && (_jsx(Waypoint, { scrollableAncestor: ancestor, onEnter: unpinBottom, onLeave: pinBottom, bottomOffset: offsetBottom }, void 0)), container && (_jsx(WindowResizeHandler, { onResize: onWindowResize, disableThrottle: true }, void 0))] }, void 0));
});
Affix.displayName = 'ZentAffix';
export default Affix;