UNPKG

@vnmfify/core

Version:

```shell npm i @vnmfify/core -S ```

234 lines (202 loc) 10.2 kB
import _map from "lodash/map"; import _size from "lodash/size"; var _excluded = ["className", "sticky", "stickyOffsetTop", "children"]; function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { Promise.resolve(value).then(_next, _throw); } } function _asyncToGenerator(fn) { return function () { var self = this, args = arguments; return new Promise(function (resolve, reject) { var gen = fn.apply(self, args); function _next(value) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value); } function _throw(err) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err); } _next(undefined); }); }; } function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) { symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); } keys.push.apply(keys, symbols); } return keys; } function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; } function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } function _objectWithoutProperties(source, excluded) { if (source == null) return {}; var target = _objectWithoutPropertiesLoose(source, excluded); var key, i; if (Object.getOwnPropertySymbols) { var sourceSymbolKeys = Object.getOwnPropertySymbols(source); for (i = 0; i < sourceSymbolKeys.length; i++) { key = sourceSymbolKeys[i]; if (excluded.indexOf(key) >= 0) continue; if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue; target[key] = source[key]; } } return target; } function _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; } import { View } from "@vnxjs/components"; import { usePageScroll } from "@vnxjs/vnmf"; import classNames from "classnames"; import * as React from "react"; import { Children, cloneElement, createRef, isValidElement, useCallback, useMemo, useRef, useState } from "react"; import { isFragment } from "react-is"; import { prefixClassname } from "../styles"; import { getClientCoordinates, preventDefault } from "../utils/dom/event"; import { getRect, getRects, makeRect } from "../utils/dom/rect"; import IndexListAnchor from "./index-list-anchor"; import IndexListIndex from "./index-list-index"; import IndexListSidebar from "./index-list-sidebar"; import IndexListContext from "./index-list.context"; function childrenIndexBar(children, __children__, parentIndex) { Children.forEach(children, (child, index) => { if (! /*#__PURE__*/isValidElement(child)) { return; } var element = child; var elementType = element.type; var { key, props } = element; var { children: childrenProp } = props; if (isFragment(element)) { childrenIndexBar(childrenProp, __children__, key !== null && key !== void 0 ? key : index); return; } if (elementType === IndexListAnchor) { var _children__$children; var { index: indexProp } = props; var anchorRef = /*#__PURE__*/createRef(); var { length: arrayedIndex } = __children__.anchorRefs; __children__.anchorRefs.push(anchorRef); __children__.anchorProps.push(props); (_children__$children = __children__.children) === null || _children__$children === void 0 ? void 0 : _children__$children.push( /*#__PURE__*/cloneElement(element, { arrayedIndex, key: indexProp, ref: anchorRef })); } else { var _children__$children2; (_children__$children2 = __children__.children) === null || _children__$children2 === void 0 ? void 0 : _children__$children2.push( /*#__PURE__*/cloneElement(element, { key: key !== null && key !== void 0 ? key : "".concat(parentIndex, "-").concat(index) })); } }); } function useIndexBarChildren(children) { return useMemo(() => { var __children__ = { children: [], anchorRefs: [], anchorProps: [] }; childrenIndexBar(children, __children__); return __children__; }, [children]); } function IndexList(props) { var _activeAnchor$index, _activeAnchor$arrayed; var { className, sticky = true, stickyOffsetTop = 0, children: childrenProp } = props, restProps = _objectWithoutProperties(props, _excluded); var { anchorProps, anchorRefs, children } = useIndexBarChildren(childrenProp); var scrollTopRef = useRef(0); var listRef = useRef(); var sidebarRef = useRef(); var listRectRef = useRef(makeRect(0, 0)); var sidebarRectRef = useRef(makeRect(0, 0)); var anchorRectsRef = useRef([]); var [activeAnchor, setActiveAnchor] = useState({}); var getListRect = useCallback(() => getRect(listRef).then(rect => _objectSpread(_objectSpread({}, rect), {}, { top: rect.top + scrollTopRef.current })), []); var getSidebarRect = useCallback(() => getRect(sidebarRef), []); var getAnchorRects = useCallback(() => getRects(listRef, " .".concat(prefixClassname("index-list__anchor-wrapper"))), []); var scrollToAnchorIndexRef = useRef(); var getActiveAnchor = useCallback(() => { var { current: anchorRects } = anchorRectsRef; for (var i = anchorRefs.length - 1; i >= 0; i--) { var prevHeight = i > 0 ? anchorRects[i - 1].height : 0; var reachTop = sticky ? prevHeight : 0; if (reachTop >= anchorRects[i].top) { return i; } } return -1; }, [anchorRefs.length, sticky]); var onScroll = useCallback( /*#__PURE__*/_asyncToGenerator(function* () { var arrayedIndex = getActiveAnchor(); if (arrayedIndex >= 0) { setActiveAnchor({ arrayedIndex, index: anchorProps[arrayedIndex].index }); } else { setActiveAnchor({}); } }), [anchorProps, getActiveAnchor]); var scrollToAnchor = useCallback(anchorArrayedIndex => { if (anchorArrayedIndex < 0 || scrollToAnchorIndexRef.current === anchorArrayedIndex) { return; } scrollToAnchorIndexRef.current = anchorArrayedIndex; var { current: matchInstance } = anchorRefs[anchorArrayedIndex]; matchInstance === null || matchInstance === void 0 ? void 0 : matchInstance.scrollIntoView(scrollTopRef.current); }, [anchorRefs]); var getAnchorArrayedIndex = useCallback(event => { var { current: sidebarRect } = sidebarRectRef; var touch = getClientCoordinates(event); var sidebarLength = _size(anchorRefs); var itemHeight = sidebarRect.height / sidebarLength; var index = Math.floor((touch.clientY - sidebarRect.top) / itemHeight); if (index < 0) { index = 0; } else if (index > sidebarLength - 1) { index = sidebarLength - 1; } return index; }, [anchorRefs]); var scrollToEvent = useCallback(event => { var arrayedIndex = getAnchorArrayedIndex(event); scrollToAnchor(arrayedIndex); }, [getAnchorArrayedIndex, scrollToAnchor]); var onSidebarClick = useCallback(event => scrollToEvent(event), [scrollToEvent]); var onTouchMove = useCallback(event => { preventDefault(event); scrollToEvent(event); }, [scrollToEvent]); var onTouchStop = useCallback(() => scrollToAnchorIndexRef.current = undefined, []); usePageScroll(_ref2 => { var { scrollTop } = _ref2; scrollTopRef.current = scrollTop; setTimeout(() => { Promise.all([getListRect(), getSidebarRect(), getAnchorRects()]).then(rects => { var [listRect, sidebarRect, anchorRects] = rects; listRectRef.current = listRect; sidebarRectRef.current = sidebarRect; anchorRectsRef.current = anchorRects; }).then(onScroll); }, 0); }); var sidebarIndexes = useMemo(() => _map(anchorProps, anchorProp => /*#__PURE__*/React.createElement(IndexListIndex, { key: anchorProp.index, index: anchorProp.index })), [anchorProps]); return /*#__PURE__*/React.createElement(IndexListContext.Provider, { value: { sticky, stickyOffsetTop, activeIndex: (_activeAnchor$index = activeAnchor === null || activeAnchor === void 0 ? void 0 : activeAnchor.index) !== null && _activeAnchor$index !== void 0 ? _activeAnchor$index : -1, activeArrayedIndex: (_activeAnchor$arrayed = activeAnchor === null || activeAnchor === void 0 ? void 0 : activeAnchor.arrayedIndex) !== null && _activeAnchor$arrayed !== void 0 ? _activeAnchor$arrayed : -1, getListRect: () => listRectRef.current, getAnchorRects: () => anchorRectsRef.current } }, /*#__PURE__*/React.createElement(View, _objectSpread({ ref: listRef, className: classNames(prefixClassname("index-list"), className) }, restProps), /*#__PURE__*/React.createElement(IndexListSidebar, { ref: sidebarRef, onClick: onSidebarClick, onTouchMove: onTouchMove, onTouchCancel: onTouchStop, onTouchEnd: onTouchStop }, sidebarIndexes), children)); } export default IndexList; //# sourceMappingURL=index-list.js.map