react-view-router
Version:
react-view-router
267 lines (266 loc) • 10.9 kB
JavaScript
import _slicedToArray from "@babel/runtime/helpers/slicedToArray";
import "core-js/modules/es6.array.filter.js";
import "core-js/modules/es6.array.map.js";
import "core-js/modules/es6.regexp.replace.js";
import { useState, useCallback, useMemo, useEffect } from 'react';
import { isCommonPage, getRouteMatched, useRouter, useMatchedRouteAndIndex, useRouteChanged, useRouteMetaChanged } from './base';
import { isRouteChanged, hasOwnProp, getRouteChildren, readRouteMeta, isString } from '../util';
var DEFAULT_TITLE_NAME = 'title';
function readRouteTitle(route, options = {}) {
var ret = {
visible: false,
title: ''
};
var visible = readRouteMeta(route, 'visible', options);
if (visible === false) return ret;
var titleName = options.titleName || DEFAULT_TITLE_NAME;
ret.title = readRouteMeta(route, titleName, options) || '';
ret.visible = Boolean(ret.title);
return ret;
}
function readRouteTitles(router, routes, options = {}) {
var refresh = options.refresh,
filter = options.filter,
_options$titleName = options.titleName,
titleName = _options$titleName === void 0 ? DEFAULT_TITLE_NAME : _options$titleName,
_options$maxLevel = options.maxLevel,
maxLevel = _options$maxLevel === void 0 ? 99 : _options$maxLevel,
_options$level = options.level,
level = _options$level === void 0 ? 1 : _options$level;
routes = getRouteChildren(routes);
return routes.filter(r => r.meta[titleName]).map(r => {
var _readRouteTitle = readRouteTitle(r, {
router,
titleName,
level,
maxLevel,
refresh
}),
visible = _readRouteTitle.visible,
title = _readRouteTitle.title;
if (visible === false) return;
if (filter && filter(r, routes, {
title,
visible,
router,
meta: r.meta,
level,
maxLevel,
refresh
}) === false) return;
var ret = {
title,
path: r.path,
meta: r.meta,
route: r,
level
};
if (level < maxLevel && Array.isArray(r.children) && r.children.length) {
var children = readRouteTitles(router, r.children, {
refresh,
filter,
titleName,
maxLevel,
level: level + 1
});
if (children.length) ret.children = children;
}
return ret;
}).filter(Boolean);
}
function getMatchedDepth(matchedRoute) {
return matchedRoute ? matchedRoute.depth + 1 : 0;
}
function isTitleRoute(route, titleName = DEFAULT_TITLE_NAME) {
return route && hasOwnProp(route.meta, titleName);
}
function walkMatchedRouteList(callback, matched, depth, maxLevel, titleName = DEFAULT_TITLE_NAME) {
if (!callback) return;
// let baseLevel = depth;
while (depth < maxLevel && matched && matched[depth]) {
var matchedRouteIndex = depth++;
var matchedRoute = matched[matchedRouteIndex];
if (isTitleRoute(matchedRoute, titleName)) {
// const { visible } = readRouteTitle(matchedRoute.config, titleName, {
// maxLevel: maxLevel - baseLevel,
// level: depth - baseLevel
// });
// if (!visible) break;
callback(matchedRoute, matchedRouteIndex);
}
}
}
function getMatchedRouteList(matched, depth, maxLevel, titleName) {
var ret = [];
walkMatchedRouteList(matchedRoute => {
ret.push(matchedRoute);
}, matched, depth, maxLevel, titleName);
return ret;
}
function getMatchedRoutes(router, matchedRoute, maxLevel, commonPageName, titleName) {
var currentRoute = router.currentRoute || router.initialRoute;
var depth = getMatchedDepth(matchedRoute);
var matchedRoutes = getMatchedRouteList(getRouteMatched(router, currentRoute, commonPageName), depth, maxLevel + depth, titleName);
return matchedRoutes;
}
function findTitleByMatchedPath(matchedPath, titles, matchedTitles) {
if (!matchedPath) return undefined;
var matchedTitle;
titles.some(title => {
if (title.path === matchedPath) {
matchedTitle = title;
if (matchedTitles) matchedTitles.push(title);
return true;
}
if (title.children && title.children.length) {
matchedTitle = findTitleByMatchedPath(matchedPath, title.children, matchedTitles);
if (matchedTitle && matchedTitles) matchedTitles.unshift(title);
}
return matchedTitle;
});
return matchedTitle;
}
function useRouteTitle(props, defaultRouter, deps = []) {
if (!props) props = {};
var _props = props,
_props$maxLevel = _props.maxLevel,
maxLevel = _props$maxLevel === void 0 ? 99 : _props$maxLevel,
_props$filterMetas = _props.filterMetas,
filterMetas = _props$filterMetas === void 0 ? [] : _props$filterMetas,
manual = _props.manual,
_props$matchedOffset = _props.matchedOffset,
matchedOffset = _props$matchedOffset === void 0 ? 0 : _props$matchedOffset,
_props$titleName = _props.titleName,
titleName = _props$titleName === void 0 ? DEFAULT_TITLE_NAME : _props$titleName,
_props$commonPageName = _props.commonPageName,
commonPageName = _props$commonPageName === void 0 ? 'commonPage' : _props$commonPageName;
var _useState = useState({
parsed: false,
mounted: false,
timerIds: {}
}),
_useState2 = _slicedToArray(_useState, 1),
$refs = _useState2[0];
$refs.filter = props.filter;
$refs.onNoMatchedPath = props.onNoMatchedPath;
var router = useRouter(defaultRouter);
if (!router) throw new Error('[useRouteTitle] router can not be null!');
var _ref = defaultRouter ? [null, 0]
// eslint-disable-next-line react-hooks/rules-of-hooks
: useMatchedRouteAndIndex(undefined, {
matchedOffset,
commonPageName
}),
_ref2 = _slicedToArray(_ref, 2),
matchedRoute = _ref2[0],
routeIndex = _ref2[1];
var _useState3 = useState(false),
_useState4 = _slicedToArray(_useState3, 2),
dirty = _useState4[0],
setDirty = _useState4[1];
var refreshTitles = useCallback(() => setDirty(true), [setDirty]);
var refreshTabs = useCallback((routes = []) => {
$refs.parsed = true;
return readRouteTitles(router, routes, {
refresh: refreshTitles,
filter: $refs.filter,
titleName,
maxLevel
});
},
// eslint-disable-next-line react-hooks/exhaustive-deps
[router, $refs, maxLevel, refreshTitles, ...deps]);
var _useState5 = useState(() => manual ? [] : refreshTabs(defaultRouter ? router.routes : matchedRoute ? matchedRoute.config.children : [])),
_useState6 = _slicedToArray(_useState5, 2),
titles = _useState6[0],
setTitles = _useState6[1];
var _useState7 = useState(() => getMatchedRoutes(router, matchedRoute, maxLevel, commonPageName, titleName)),
_useState8 = _slicedToArray(_useState7, 2),
matchedRoutes = _useState8[0],
setMatchedRoutes = _useState8[1];
var matchedTitles = useMemo(() => {
var ret = [];
if (!matchedRoutes.length || !$refs.parsed) return ret;
var currentRoute = matchedRoutes[matchedRoutes.length - 1];
findTitleByMatchedPath(currentRoute.path, titles, ret);
return ret;
}, [$refs.parsed, matchedRoutes, titles]);
var currentPaths = useMemo(() => {
if (!matchedRoutes.length || !$refs.parsed) return [];
var currentRoute = matchedRoutes[matchedRoutes.length - 1];
var currentTitle = findTitleByMatchedPath(currentRoute.path, titles);
if (!currentTitle && $refs.mounted && $refs.onNoMatchedPath) {
if ($refs.timerIds.onNoMatchedPath) clearTimeout($refs.timerIds.onNoMatchedPath);
$refs.timerIds.onNoMatchedPath = setTimeout(() => {
$refs.timerIds.onNoMatchedPath = 0;
if (!$refs.mounted || !$refs.onNoMatchedPath) return;
var fallback = fallbackPath => {
var toPath = isString(fallbackPath) ? fallbackPath : fallbackPath.path;
var currentRoute = router.pendingRoute || router.currentRoute || router.initialRoute;
if (!toPath || currentRoute && currentRoute.path === toPath) return;
return router.replace(fallbackPath);
};
if (isString($refs.onNoMatchedPath)) {
if (!titles.length) return;
return fallback($refs.onNoMatchedPath === ':first' ? titles[0].path : $refs.onNoMatchedPath);
}
$refs.onNoMatchedPath(currentRoute.path, titles, fallback);
}, 0);
}
return currentTitle ? matchedRoutes.map(r => r.path) : [];
}, [matchedRoutes, titles, $refs, router]);
useRouteChanged(router, useCallback((currentRoute, prevRoute) => {
if (!$refs.mounted) return;
var routes = getMatchedRoutes(router, matchedRoute, maxLevel, commonPageName, titleName);
if (routes.length !== matchedRoutes.length || matchedRoutes.some((route, i) => route.path !== routes[i].path)) {
setMatchedRoutes(routes);
}
if (!defaultRouter) {
var matched = getRouteMatched(router, currentRoute, commonPageName);
if (matched) {
var depth = getMatchedDepth(matchedRoute);
var prevMatched = getRouteMatched(router, prevRoute, commonPageName);
var matchedRouteList = getMatchedRouteList(prevMatched, depth, maxLevel, titleName);
var newMatchedRouteList = getMatchedRouteList(matched, depth, maxLevel, titleName);
if (matchedRouteList.length !== newMatchedRouteList.length || newMatchedRouteList.some((newMatchedRoute, i) => isRouteChanged(matchedRouteList[i], newMatchedRoute))) {
var newMatchedRoute = newMatchedRouteList[0];
setTitles(refreshTabs(newMatchedRoute ? newMatchedRoute.config.parent ? newMatchedRoute.config.parent.children : router.routes : []));
}
}
}
}, [router, matchedRoute, maxLevel, commonPageName, titleName, matchedRoutes, defaultRouter, refreshTabs, $refs]));
$refs.routeMetaChangedCallback = useCallback(() => {
if (!$refs.mounted) return;
var matched = getRouteMatched(router, router.currentRoute, commonPageName);
var matchedRoute = matched[routeIndex];
setTitles(refreshTabs(defaultRouter ? router.routes : matchedRoute ? matchedRoute.config.children : []));
}, [router, commonPageName, routeIndex, refreshTabs, defaultRouter, $refs]);
useRouteMetaChanged(router, $refs.routeMetaChangedCallback, [...filterMetas, titleName, 'visible']);
useMemo(() => {
if (!dirty || !$refs.mounted) return;
setDirty(false);
if ($refs.timerIds.dirty) return;
$refs.timerIds.dirty = setTimeout(() => {
$refs.timerIds.dirty = 0;
router.isRunning && $refs.routeMetaChangedCallback && $refs.routeMetaChangedCallback();
}, 0);
}, [router, dirty, $refs]);
useEffect(() => {
$refs.mounted = true;
return () => {
$refs.mounted = false;
};
}, [$refs]);
return {
parsed: $refs.parsed,
titles,
setTitles,
refreshTitles,
matchedRoutes,
matchedTitles,
currentPaths
};
}
export { isTitleRoute, isCommonPage, readRouteTitle, readRouteTitles };
export default useRouteTitle;
//# sourceMappingURL=use-route-title.js.map