mirror of
https://github.com/ionic-team/ionic-framework.git
synced 2025-08-20 12:29:55 +08:00
122 lines
3.3 KiB
TypeScript
122 lines
3.3 KiB
TypeScript
import React from 'react';
|
|
|
|
import { generateId, isDevMode } from '../utils';
|
|
|
|
import { RouteManagerContext, RouteManagerContextState } from './RouteManagerContext';
|
|
import { View } from './View';
|
|
import { ViewItem } from './ViewItem';
|
|
import { ViewTransitionManager } from './ViewTransitionManager';
|
|
|
|
interface StackManagerProps {
|
|
id?: string;
|
|
routeManager: RouteManagerContextState;
|
|
children?: React.ReactNode;
|
|
}
|
|
|
|
interface StackManagerState {
|
|
routerOutletReady: boolean;
|
|
}
|
|
|
|
class StackManagerInner extends React.Component<StackManagerProps, StackManagerState> {
|
|
routerOutletEl: React.RefObject<HTMLIonRouterOutletElement> = React.createRef();
|
|
|
|
id: string;
|
|
|
|
constructor(props: StackManagerProps) {
|
|
super(props);
|
|
this.id = this.props.id || generateId();
|
|
this.handleViewSync = this.handleViewSync.bind(this);
|
|
this.handleHideView = this.handleHideView.bind(this);
|
|
this.state = {
|
|
routerOutletReady: false
|
|
};
|
|
}
|
|
|
|
componentDidMount() {
|
|
this.props.routeManager.setupIonRouter(this.id, this.props.children, this.routerOutletEl.current!);
|
|
this.routerOutletEl.current!.addEventListener('routerOutletReady', () => {
|
|
this.setState({
|
|
routerOutletReady: true
|
|
});
|
|
});
|
|
}
|
|
|
|
static getDerivedStateFromProps(props: StackManagerProps, state: StackManagerState) {
|
|
props.routeManager.syncRoute('', props.children);
|
|
return state;
|
|
}
|
|
|
|
componentWillUnmount() {
|
|
this.props.routeManager.removeViewStack(this.id);
|
|
}
|
|
|
|
handleViewSync(page: HTMLElement, viewId: string) {
|
|
this.props.routeManager.syncView(page, viewId);
|
|
}
|
|
|
|
handleHideView(viewId: string) {
|
|
this.props.routeManager.hideView(viewId);
|
|
}
|
|
|
|
renderChild(item: ViewItem, route: any) {
|
|
const component = React.cloneElement(route, {
|
|
computedMatch: item.routeData.match
|
|
});
|
|
return component;
|
|
}
|
|
|
|
render() {
|
|
const routeManager = this.props.routeManager;
|
|
const viewStack = routeManager.viewStacks.get(this.id);
|
|
const views = (viewStack || { views: [] }).views.filter(x => x.show);
|
|
const ionRouterOutlet = React.Children.only(this.props.children) as React.ReactElement;
|
|
const { routerOutletReady } = this.state;
|
|
|
|
const childElements = routerOutletReady ? views.map(view => {
|
|
const route = routeManager.getRoute(view.routeId);
|
|
return (
|
|
<ViewTransitionManager
|
|
id={view.id}
|
|
key={view.key}
|
|
mount={view.mount}
|
|
>
|
|
<View
|
|
onViewSync={this.handleViewSync}
|
|
onHideView={this.handleHideView}
|
|
view={view}
|
|
route={route}
|
|
>
|
|
{this.renderChild(view, route)}
|
|
</View>
|
|
</ViewTransitionManager>
|
|
);
|
|
}) : <div></div>;
|
|
|
|
const elementProps: any = {
|
|
ref: this.routerOutletEl
|
|
};
|
|
|
|
if(ionRouterOutlet.props.forwardedRef) {
|
|
ionRouterOutlet.props.forwardedRef.current = this.routerOutletEl;
|
|
}
|
|
|
|
if (isDevMode()) {
|
|
elementProps['data-stack-id'] = this.id;
|
|
}
|
|
|
|
const routerOutletChild = React.cloneElement(ionRouterOutlet, elementProps, childElements);
|
|
|
|
return routerOutletChild;
|
|
}
|
|
}
|
|
|
|
const withContext = (Component: any) => {
|
|
return (props: any) => (
|
|
<RouteManagerContext.Consumer>
|
|
{context => <Component {...props} routeManager={context} />}
|
|
</RouteManagerContext.Consumer>
|
|
)
|
|
}
|
|
|
|
export const StackManager = withContext(StackManagerInner);
|