UNPKG

react-view-router

Version:
254 lines (251 loc) 11.4 kB
const _excluded = ["name", "transition", "transitionPrefix", "transitionZIndex", "transitionFallback", "routerView", "router", "container", "containerStyle", "onScrollToPosition", "onSavePosition"]; function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; } function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; } function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; } function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : i + ""; } function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); } import "core-js/modules/web.dom.iterable.js"; function _objectWithoutProperties(e, t) { if (null == e) return {}; var o, r, i = _objectWithoutPropertiesLoose(e, t); if (Object.getOwnPropertySymbols) { var n = Object.getOwnPropertySymbols(e); for (r = 0; r < n.length; r++) o = n[r], -1 === t.indexOf(o) && {}.propertyIsEnumerable.call(e, o) && (i[o] = e[o]); } return i; } function _objectWithoutPropertiesLoose(r, e) { if (null == r) return {}; var t = {}; for (var n in r) if ({}.hasOwnProperty.call(r, n)) { if (-1 !== e.indexOf(n)) continue; t[n] = r[n]; } return t; } import React, { useMemo, useState } from 'react'; import { RouterView as RouterViewOrigin, useRouter, useMatchedRouteIndex, isPlainObject, isFunction, getSessionStorage, setSessionStorage, nextTick } from 'react-view-router'; import SwitchTransition from './SwitchTransition'; import CSSTransition from './CSSTransition'; import './router-view.css'; const SAVED_POSITION_KEY = '_REACT_VIEW_ROUTER_TRANSITION_POSITIONS_'; /** * @param {import('react-view-router').Route} to */ function isPush(to) { return to && (to.action === 'PUSH' || to.params.isPush || to.query.isPush); } /** * @param {import('react-view-router').Route} to * @param {import('react-view-router').Route} [prevRoute] */ function isPop(to, prevRoute) { return !to && prevRoute || to.action === 'POP' || to.params.isBack || to.params.isPop || to.query.back; } /** * @param {import('react-view-router').Route} to * @param {import('react-view-router').Route} [prevRoute] */ function isReplace(to, prevRoute) { return to && to.action === 'REPLACE' && !isPush(to) && !isPop(to, prevRoute); } /** * @typedef {import('react-view-router').RouterView} RouterView * @typedef {import('../types/router-view').TransitionRouterViewProps} TransitionRouterViewProps */ /** * @type {React.ForwardRefExoticComponent<TransitionRouterViewProps & React.RefAttributes<RouterView>>} */ const RouterViewTransition = /*#__PURE__*/React.forwardRef((props, ref) => { let { name, transition = 'slide', transitionPrefix = 'react-view-router-', transitionZIndex = 1000, transitionFallback = '', routerView, router: defaultRouter, container, containerStyle = {}, onScrollToPosition, onSavePosition } = props, restProps = _objectWithoutProperties(props, _excluded); const router = useRouter(defaultRouter); const matchedRouteIndex = useMatchedRouteIndex(); const savedPositionsKey = useMemo(() => `${name || 'default'}_${matchedRouteIndex}`, [name, matchedRouteIndex]); const [$refs] = useState(() => { const positions = getSessionStorage(SAVED_POSITION_KEY, true) || {}; if (!positions[savedPositionsKey]) positions[savedPositionsKey] = {}; return { positions, onScrollToPosition, onSavePosition }; }); $refs.onScrollToPosition = onScrollToPosition; $refs.onSavePosition = onSavePosition; if (routerView === RouterViewTransition) routerView = null; const backgroundColor = useMemo(() => containerStyle && containerStyle.backgroundColor || document.defaultView.getComputedStyle(document.body, null).getPropertyValue('background-color'), // eslint-disable-next-line react-hooks/exhaustive-deps [containerStyle && containerStyle.backgroundColor]); containerStyle = _objectSpread({ height: '100%' }, containerStyle); let containerTag = 'div'; if (isPlainObject(transition)) { transitionZIndex = transition.zIndex || transitionZIndex; containerStyle = Object.assign(containerStyle, transition.containerStyle); containerTag = transition.containerTag || containerTag; transition = transition.name || 'slide'; } const transitionMap = useMemo(() => { const isSlideNode = node => node && node.className.includes(transitionPrefix + 'slide'); const isFadeNode = node => node && node.className.includes(transitionPrefix + 'fade'); const _savePosition = maybeNode => { const node = maybeNode && maybeNode.children[0]; const to = router.currentRoute; if (node && isPush(to)) { const from = router.prevRoute; const key = from ? from.path : '-'; // const matchedRoute = to && to.matched[matchedRouteIndex + 1]; const position = from?.metaComputed.savePosition ? { x: node.scrollLeft, y: node.scrollTop } : $refs.onSavePosition ? $refs.onSavePosition(node, { to, from }) : null; if (position && (position.x || position.y)) { $refs.positions[savedPositionsKey][key] = position; setSessionStorage(SAVED_POSITION_KEY, $refs.positions); } } }; const _scrollToPosition = maybeNode => { const node = maybeNode && maybeNode.children[0]; const to = router.currentRoute; if (node && isPop(to, router.prevRoute)) { const key = to ? to.path : '-'; const savedPosition = $refs.positions[savedPositionsKey][key]; if (savedPosition) { if ($refs.onScrollToPosition) $refs.onScrollToPosition(node, savedPosition);else node.scrollTo(savedPosition.x, savedPosition.y); delete $refs.positions[savedPositionsKey][key]; setSessionStorage(SAVED_POSITION_KEY, $refs.positions); } } }; const transitionProps = { addEndListener: (node, done) => { const to = router.currentRoute; if (!isFadeNode(node) && isReplace(to, router.prevRoute) || node.className.includes('slide-right-enter') || node.className.includes('slide-left-exit')) { return done(); } node.addEventListener('transitionend', done, false); }, onEnter: maybeNode => { // if (maybeNode && $refs.route) { // maybeNode.childNodes.forEach(node => { // if (!node[KEEP_ALIVE_REPLACOR] // || node.$refs.mountRoot === maybeNode) return; // node.mountView(maybeNode, node); // }) // } if (isSlideNode(maybeNode)) { if (transitionZIndex) maybeNode.style.zIndex = transitionZIndex; if (backgroundColor) maybeNode.style.backgroundColor = backgroundColor; } }, onEntering: maybeNode => { nextTick(() => _scrollToPosition(maybeNode)); }, onEntered: maybeNode => { if (isSlideNode(maybeNode)) { if (transitionZIndex) maybeNode.style.zIndex = ''; if (backgroundColor) maybeNode.style.backgroundColor = ''; } }, onExit: maybeNode => { _savePosition(maybeNode); if (isSlideNode(maybeNode)) { if (transitionZIndex) maybeNode.style.zIndex = transitionZIndex; if (backgroundColor) maybeNode.style.backgroundColor = backgroundColor; } }, onExited: maybeNode => { // if (maybeNode) { // maybeNode.childNodes.forEach(node => { // if (!node[KEEP_ALIVE_REPLACOR] // || node.$refs.mountRoot !== maybeNode) return; // node.unmountView(); // }) // } if (isSlideNode(maybeNode)) { if (transitionZIndex) maybeNode.style.zIndex = ''; if (backgroundColor) maybeNode.style.backgroundColor = ''; } } }; /** * @type {{ * [key: string]: { * mode: string, * props: Partial<any> * }} * */ const map = { fade: { mode: 'out-in', props: { classNames: transitionPrefix + 'fade' } }, slide: { mode: 'in-out', props: { classNames: () => { let ret = ''; const to = router.currentRoute; if (isPush(to)) { ret = 'slide-left'; } else if (isPop(to, router.prevRoute)) { ret = 'slide-right'; } else { ret = isFunction(transitionFallback) ? transitionFallback(to) : transitionFallback; } return ret ? `${transitionPrefix}${ret}` : ret; } } }, carousel: { mode: 'together', props: { classNames: () => { let ret = ''; const to = router.currentRoute; if (isPush(to)) { ret = 'carousel-left'; } else if (isPop(to, router.prevRoute)) { ret = 'carousel-right'; } else { ret = isFunction(transitionFallback) ? transitionFallback(to) : transitionFallback; } return ret ? `${transitionPrefix}${ret}` : ret; } } } }; const transitionItem = map[transition]; if (transitionItem) Object.assign(transitionItem.props, transitionProps); return transitionItem || { mode: '', props: {} }; }, [$refs, matchedRouteIndex, savedPositionsKey, router, transitionFallback, transition, transitionPrefix, transitionZIndex, backgroundColor]); return /*#__PURE__*/React.createElement(routerView || RouterViewOrigin, _objectSpread({ ref: ref ? { ref } : undefined, name, router: defaultRouter, container: transition ? (result, route, props, view) => { if (container) result = container(result, route, props, view); // if (view.state.enableKeepAlive) return result; // console.log('router-view container', route, route.path, this.transitionName, router.stacks.length); return /*#__PURE__*/React.createElement(SwitchTransition, { mode: transitionMap.mode }, /*#__PURE__*/React.createElement(CSSTransition, _objectSpread({ key: route.path }, transitionMap.props), /*#__PURE__*/React.createElement(containerTag, { style: containerStyle // [`data-${KEEP_ALIVE_KEEP_COPIES}`]: true, }, result))); } : container }, restProps)); }); export { SAVED_POSITION_KEY }; export default RouterViewTransition;