UNPKG

zent

Version:

一套前端设计语言和基于React的实现

147 lines (146 loc) 7.14 kB
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;