import * as React from 'react'; import { Component, ValidationMap, ComponentClass } from 'react'; import * as PropTypes from 'prop-types'; import { Store, RouterStoreState } from './Store'; import { Match, hoistNonReactStatics } from './utils'; import { History, Location } from 'history'; export type MagicRouterProviderContext = { routerStore: Store; router: { history: History }; }; export type Decorator

= (Target: any) => ComponentClass

; export type InjectedMatch = { match: Match, }; export type InjectedLocation = { location: Location, }; export type InjectedHistory = { history: History, }; export type InjectedAll = InjectedMatch & InjectedLocation & InjectedHistory; export type WhatToInject = { match?: boolean; location?: boolean; history?: boolean; }; /** * Render the first Route that match */ export function InjectMagicRouter

(options: WhatToInject = {}): Decorator

{ return (Target: any) => { const { 'match': injectMatch = true, 'location': injectLocation = true, 'history': injectHistory = true } = options; if (!injectMatch && !injectLocation && !injectHistory) { console.warn(`All inject are off, just returning the component`); return Target; } // if we inject only history, no need to subscribe const needSubscribe: boolean = !injectMatch && !injectLocation && injectHistory; class MagicRouterProvider extends Component<{}, {}> { static displayName: string = 'MagicRouterProvider'; static contextTypes: ValidationMap = { routerStore: PropTypes.instanceOf(Store), router: PropTypes.any, }; context: MagicRouterProviderContext; unsubscribe: () => void; private isUnmounted: boolean = false; constructor(props: any, context: MagicRouterProviderContext) { super(props, context); if (!context.routerStore || !context.routerStore.getState() || !context.router || !context.router.history) { throw new Error('InjectMatch need a RouterProvider as ancestor'); } if (needSubscribe) { this.unsubscribe = context.routerStore.subscribe(() => { if (this.isUnmounted === false) { this.forceUpdate(); } }); } } componentWillUnmount(): void { this.isUnmounted = true; if (this.unsubscribe) { this.unsubscribe(); } } render(): JSX.Element { const injectedProps: Partial = {}; if (injectMatch) { injectedProps.match = this.context.routerStore.getState().match; } if (injectHistory) { injectedProps.history = this.context.router.history; } if (injectLocation) { injectedProps.location = this.context.routerStore.getState().location; } return ; } } return hoistNonReactStatics(MagicRouterProvider, Target); }; }