@vnmfify/core
Version:
```shell npm i @vnmfify/core -S ```
234 lines (202 loc) • 10.2 kB
JavaScript
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