UNPKG

zent

Version:

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

101 lines (100 loc) 4.6 kB
import { __assign } from "tslib"; import { jsx as _jsx } from "react/jsx-runtime"; import { useCallback, useEffect, useMemo, useRef, useState } from 'react'; import isNil from '../utils/isNil'; import { smoothScroll } from '../utils/scroll'; import { ElevatorContext } from './context'; import { ElevatorAnchor } from './ElevatorAnchor'; import { ElevatorLinks } from './ElevatorLinks'; var SCROLL_DURATION = 200; var getDefaultContainer = function () { return window; }; export var Elevator = function (_a) { var children = _a.children, onChange = _a.onChange, targetOffset = _a.targetOffset, getContainer = _a.getContainer, defaultActiveLink = _a.defaultActiveLink, propOffsetTop = _a.offsetTop, propActiveLink = _a.activeLink; var getContainerResult = getContainer === null || getContainer === void 0 ? void 0 : getContainer(); var _b = useState(new Map()), anchorElementsMap = _b[0], setAnchorElementsMap = _b[1]; var _c = useState(''), internalActiveLink = _c[0], setInternalActiveLink = _c[1]; var activeLink = useMemo(function () { return (!isNil(propActiveLink) ? propActiveLink : internalActiveLink); }, [propActiveLink, internalActiveLink]); var isScrolling = useRef(false); var handleAnchorEnter = function (link) { setInternalActiveLink(link); if (isScrolling.current || link === activeLink) return; onChange === null || onChange === void 0 ? void 0 : onChange(link, activeLink); }; var offsetTop = useMemo(function () { var containerHeight = getDefaultContainer().innerHeight; if (getContainerResult) { containerHeight = getContainerResult.getBoundingClientRect().height; } var defaultOffsetTop = containerHeight / 2; return !isNil(propOffsetTop) ? containerHeight - (propOffsetTop || 1) : defaultOffsetTop; }, [propOffsetTop, getContainerResult]); var handleRegisterAnchor = useCallback(function (link, el) { setAnchorElementsMap(function (prev) { var map = new Map(prev); map.set(link, el); return map; }); }, []); var handleUnRegister = useCallback(function (link) { setAnchorElementsMap(function (prev) { var map = new Map(prev); map.delete(link); return map; }); }, []); var handleScrollToLink = function (link, controlled) { if (controlled === void 0) { controlled = false; } var el = anchorElementsMap.get(link); if (!el) return; var bounds = el.getBoundingClientRect(); var container = getDefaultContainer(); var containerTop = 0; var scrollTop = container.scrollY; var scrollLeft = container.scrollX; if (getContainerResult) { container = getContainerResult; var containerBounds = container.getBoundingClientRect(); containerTop = containerBounds.top; scrollTop = container.scrollTop; scrollLeft = container.scrollLeft; } var scrollTopTarget = bounds.top - containerTop + scrollTop - (targetOffset || 0); isScrolling.current = true; smoothScroll(container, scrollLeft, scrollTopTarget, SCROLL_DURATION).then(function () { isScrolling.current = false; !controlled && (onChange === null || onChange === void 0 ? void 0 : onChange(link, activeLink)); }); }; var handleLinkClick = function (link) { if (isNil(propActiveLink)) { handleScrollToLink(link); } else if (link !== activeLink) { onChange === null || onChange === void 0 ? void 0 : onChange(link, activeLink); } }; useEffect(function () { if (!isNil(propActiveLink) && propActiveLink !== internalActiveLink) { handleScrollToLink(propActiveLink, true); } if (isNil(propActiveLink) && defaultActiveLink) { handleScrollToLink(defaultActiveLink); } }, [propActiveLink, anchorElementsMap, defaultActiveLink]); return (_jsx(ElevatorContext.Provider, __assign({ value: { activeLink: activeLink, offsetTop: offsetTop, getContainer: getContainer, onLinkClick: handleLinkClick, onAnchorEnter: handleAnchorEnter, registerAnchor: handleRegisterAnchor, unRegisterAnchor: handleUnRegister, } }, { children: children }), void 0)); }; Elevator.Links = ElevatorLinks; Elevator.Anchor = ElevatorAnchor; export default Elevator;