/* eslint-disable @typescript-eslint/no-empty-interface */ import { injectable, storeKey, inject } from 'reactant'; import { BaseReactantRouter, RouterOptions, RouterState, } from 'reactant-router'; import type { IRouterOptions as IBaseRouterOptions } from 'reactant-router'; import type { History } from 'history'; import { routerChangeName, SharedAppOptions, syncRouterName, } from './constants'; import { ISharedAppOptions } from './interfaces'; import { PortDetector } from './portDetector'; import { spawn } from './spawn'; export { createBrowserHistory, createHashHistory, createMemoryHistory, } from 'reactant-router'; export type RouterChangeNameOptions = | { method: 'push'; args: [string, Record<string, any>?]; } | { method: 'replace'; args: [string, Record<string, any>?]; } | { method: 'go'; args: [number]; } | { method: 'goBack'; args: []; } | { method: 'goForward'; args: []; }; export interface IRouterOptions extends IBaseRouterOptions { // } @injectable({ name: 'reactant:router', }) class ReactantRouter extends BaseReactantRouter { private _router?: RouterState; constructor( protected portDetector: PortDetector, @inject(SharedAppOptions) protected sharedAppOptions: ISharedAppOptions, @inject(RouterOptions) protected options: IRouterOptions ) { super({ ...options, autoCreateHistory: !( (sharedAppOptions.type === 'SharedWorker' || sharedAppOptions.type === 'ServiceWorker') && sharedAppOptions.port === 'server' ), }); this.portDetector.onServer((transport) => { return transport!.listen( syncRouterName, async () => this.router?.location ); }); this.portDetector.onClient((transport) => { transport!.emit(syncRouterName).then((location) => { if (!location) return; const action = this.onLocationChanged(location, 'REPLACE'); this[storeKey]?.dispatch(action!); }); }); if ( sharedAppOptions.type === 'SharedWorker' || sharedAppOptions.type === 'ServiceWorker' ) { this.portDetector.onServer((transport) => { const history: History = { push: async (path: string, state?: Record<string, any>) => { this._router = await transport.emit(routerChangeName, { method: 'push', args: [path, state], }); }, replace: async (path: string, state?: Record<string, any>) => { this._router = await transport.emit(routerChangeName, { method: 'replace', args: [path, state], }); }, go: async (n: number) => { this._router = await transport.emit(routerChangeName, { method: 'go', args: [n], }); }, goBack: async () => { this._router = await transport.emit(routerChangeName, { method: 'goBack', args: [], }); }, goForward: async () => { this._router = await transport.emit(routerChangeName, { method: 'goForward', args: [], }); }, } as any; this.history = history; }); this.portDetector.onClient((transport) => { return transport.listen(routerChangeName, ({ method, args = [] }) => { const fn: Function = this.history[method]; fn(...args); return this.router; }); }); } } get router() { return this._router ?? this[storeKey]?.getState()[this.stateKey]; } private async _push(path: string, state?: Record<string, any>) { await this.history.push(path, state); } private async _replace(path: string, state?: Record<string, any>) { await this.history.replace(path, state); } private async _go(n: number) { await this.history.go(n); } private async _goBack() { await this.history.goBack(); } private async _goForward() { await this.history.goForward(); } async push(path: string, state?: Record<string, any>) { await spawn(this as any, '_push', [path, state]); } async replace(path: string, state?: Record<string, any>) { await spawn(this as any, '_replace', [path, state]); } async go(n: number) { await spawn(this as any, '_go', [n]); } async goBack() { await spawn(this as any, '_goBack', []); } async goForward() { await spawn(this as any, '_goForward', []); } } export { ReactantRouter as Router, RouterOptions };