UNPKG

react-view-router

Version:
267 lines (266 loc) 10.9 kB
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