import { AnimationClassNames, concatStyleSets, IStackProps, Stack } from '@fluentui/react';
import React, { useMemo, useRef } from 'react';
import { match, matchPath, RedirectProps, RouteProps, useLocation, useRouteMatch } from 'react-router-dom';
import { withDisplayName } from './utils';
export const DefaultStackProps: IStackProps = {
tokens: { childrenGap: 8, padding: 20 },
verticalFill: true,
};
export const RouteStackProps: IStackProps = {
...DefaultStackProps,
className: AnimationClassNames.slideUpIn10,
styles: { root: { overflow: 'auto' } },
};
export interface CacheRouteProps extends RouteProps {
noCache?: boolean;
}
export const CacheRoute = withDisplayName('CacheRoute')((props: CacheRouteProps) => {
const match = useRouteMatch(props);
const everMatched = useRef(!!match);
if (!everMatched.current && match) {
everMatched.current = true;
}
const stackProps = useMemo((): IStackProps => ({
...RouteStackProps,
styles: concatStyleSets(
RouteStackProps.styles,
{ root: { display: match ? 'flex' : 'none' } }
),
}), [!!match]);
if (props.noCache && !match) {
return null;
}
if (!everMatched.current) {
return null;
}
return (
{props.children}
);
});
export interface CacheSwitchProps {
children: React.ReactNodeArray;
}
export const CacheSwitch = withDisplayName('CacheSwitch')((props: CacheSwitchProps) => {
const location = useLocation();
let contextMatch = useRouteMatch();
let element: React.ReactElement | undefined;
let computedMatch: match | null | undefined;
let cached: React.ReactElement[] = [];
React.Children.forEach(props.children, child => {
if (React.isValidElement(child)) {
// Always render all cached routes
const isCacheRoute = child.type === CacheRoute;
if (isCacheRoute) {
cached.push(child);
}
// If we already found the matched route,
// Don't care about others
if (computedMatch) {
return;
}
const path = child.props.path ?? child.props.from;
const match = path
? matchPath(location.pathname, { ...child.props, path })
: contextMatch;
if (match) {
computedMatch = match;
if (isCacheRoute) {
// Don't render a CacheRoute twice
element = undefined;
} else {
element = child;
}
}
}
});
return (
<>
{cached}
{element ? React.cloneElement(element, { location, computedMatch }) : null}
>
);
});