From 0eb4fe2223f42b5eee995751e839dba10f4ed1e7 Mon Sep 17 00:00:00 2001 From: Szymon Wiszczuk Date: Wed, 8 Feb 2023 18:41:35 +0100 Subject: [PATCH 1/3] feat; clean up types --- src/ElementsRenderer.ts | 20 ++++++- src/createBaseRouter.tsx | 18 +++---- src/createBrowserRouter.tsx | 23 +++++--- src/createConnectedRouter.tsx | 19 ++++--- src/createFarceRouter.tsx | 17 +++++- src/createInitialBrowserRouter.ts | 11 +++- src/createInitialFarceRouter.ts | 13 ++++- src/createRender.tsx | 14 ++++- src/getStoreRenderArgs.ts | 12 ++++- src/resolveRenderArgs.ts | 6 ++- src/server.tsx | 4 +- src/typeUtils.ts | 88 ------------------------------- 12 files changed, 122 insertions(+), 123 deletions(-) diff --git a/src/ElementsRenderer.ts b/src/ElementsRenderer.ts index 25bb5166..b3e55c92 100644 --- a/src/ElementsRenderer.ts +++ b/src/ElementsRenderer.ts @@ -1,6 +1,24 @@ import React from 'react'; -import { ElementsRendererProps, ResolvedElement } from './typeUtils'; +import HttpError from './HttpError'; +import { RenderArgsElements } from './resolveRenderArgs'; +import { Match, ResolvedElement } from './typeUtils'; + +export type RenderPendingArgs = Match; + +export interface RenderReadyArgs extends Match { + elements: RenderArgsElements; +} + +export interface RenderErrorArgs extends Match { + error: HttpError; +} + +export type RenderArgs = RenderPendingArgs | RenderReadyArgs | RenderErrorArgs; + +export interface ElementsRendererProps { + elements: RenderArgsElements; +} function accumulateElement( children: ResolvedElement, diff --git a/src/createBaseRouter.tsx b/src/createBaseRouter.tsx index f554f27e..a5f3f497 100644 --- a/src/createBaseRouter.tsx +++ b/src/createBaseRouter.tsx @@ -4,19 +4,19 @@ import { Store } from 'redux'; import warning from 'tiny-warning'; import ActionTypes from './ActionTypes'; +import { RenderArgs } from './ElementsRenderer'; import RouterContext, { RouterContextState } from './RouterContext'; import StaticContainer from './StaticContainer'; -import createRender from './createRender'; +import createRender, { CreateRenderOptions } from './createRender'; import createStoreRouterObject from './createStoreRouterObject'; import resolveRenderArgs from './resolveRenderArgs'; -import { - ConnectedRouterProps, - CreateRenderOptions, - MatchBase, - RenderArgs, - Resolver, - Router, -} from './typeUtils'; +import { MatchBase, Resolver } from './typeUtils'; + +export interface ConnectedRouterProps { + matchContext?: any; + resolver: Resolver; + initialRenderArgs?: RenderArgs; +} interface CreateProps extends CreateRenderOptions { render?: (args: RenderArgs) => React.ReactElement; diff --git a/src/createBrowserRouter.tsx b/src/createBrowserRouter.tsx index b78dda8a..8c9aef51 100644 --- a/src/createBrowserRouter.tsx +++ b/src/createBrowserRouter.tsx @@ -1,13 +1,24 @@ import BrowserProtocol from 'farce/BrowserProtocol'; import React from 'react'; -import createFarceRouter from './createFarceRouter'; -import resolver from './resolver'; -import { - BrowserRouter, - BrowserRouterOptions, +import { RenderArgs } from './ElementsRenderer'; +import createFarceRouter, { + FarceRouterOptions, FarceRouterProps, -} from './typeUtils'; +} from './createFarceRouter'; +import resolver from './resolver'; +import { Resolver } from './typeUtils'; + +export interface BrowserRouterProps + extends Omit { + resolver?: Resolver; +} + +export type BrowserRouter = React.ComponentType; +export interface BrowserRouterOptions + extends Omit { + render?: (args: RenderArgs) => React.ReactElement; +} export default function createBrowserRouter( options: BrowserRouterOptions, diff --git a/src/createConnectedRouter.tsx b/src/createConnectedRouter.tsx index 81134fed..0827eb17 100644 --- a/src/createConnectedRouter.tsx +++ b/src/createConnectedRouter.tsx @@ -2,18 +2,21 @@ import React from 'react'; import { shallowEqual, useSelector, useStore } from 'react-redux'; import { Store } from 'redux'; -import createBaseRouter from './createBaseRouter'; -import { - ConnectedRouterOptions, - ConnectedRouterProps, - ConnectedRouter as ConnectedRouterType, - FoundState, -} from './typeUtils'; +import { RenderArgs } from './ElementsRenderer'; +import createBaseRouter, { ConnectedRouterProps } from './createBaseRouter'; +import { CreateRenderOptions } from './createRender'; +import { FoundState } from './typeUtils'; + +export type ConnectedRouter = React.ComponentType; +export interface ConnectedRouterOptions extends CreateRenderOptions { + render?: (args: RenderArgs) => React.ReactElement; + getFound?: (store: Store) => FoundState; +} export default function createConnectedRouter({ getFound = ({ found }: any) => found as FoundState, ...options -}: ConnectedRouterOptions): ConnectedRouterType { +}: ConnectedRouterOptions): ConnectedRouter { const Router = createBaseRouter(options); const getFoundState = (state: Store) => { diff --git a/src/createFarceRouter.tsx b/src/createFarceRouter.tsx index ed3e68f0..be1668b5 100644 --- a/src/createFarceRouter.tsx +++ b/src/createFarceRouter.tsx @@ -1,10 +1,23 @@ import useIsomorphicEffect from '@restart/hooks/useIsomorphicEffect'; +import { HistoryEnhancerOptions, Protocol } from 'farce'; import React, { forwardRef, useImperativeHandle, useState } from 'react'; +import { Middleware, Store } from 'redux'; -import createBaseRouter from './createBaseRouter'; +import createBaseRouter, { ConnectedRouterProps } from './createBaseRouter'; +import { ConnectedRouterOptions } from './createConnectedRouter'; import createFarceStore from './createFarceStore'; -import { FarceRouter, FarceRouterOptions, FoundState } from './typeUtils'; +import { FoundState, RouteConfig } from './typeUtils'; +export interface FarceRouterOptions extends ConnectedRouterOptions { + store?: Store; + historyProtocol: Protocol; + historyMiddlewares?: Middleware[]; + historyOptions?: Omit; + routeConfig: RouteConfig; +} + +export type FarceRouter = React.ComponentType; +export type FarceRouterProps = ConnectedRouterProps; export default function createFarceRouter({ store: userStore, historyProtocol, diff --git a/src/createInitialBrowserRouter.ts b/src/createInitialBrowserRouter.ts index bae3bc2f..daec15b4 100644 --- a/src/createInitialBrowserRouter.ts +++ b/src/createInitialBrowserRouter.ts @@ -1,8 +1,15 @@ import BrowserProtocol from 'farce/BrowserProtocol'; -import createInitialFarceRouter from './createInitialFarceRouter'; +import { BrowserRouter } from './createBrowserRouter'; +import createInitialFarceRouter, { + InitialFarceRouterOptions, +} from './createInitialFarceRouter'; import resolver from './resolver'; -import { BrowserRouter, InitialBrowserRouterOptions } from './typeUtils'; + +export type InitialBrowserRouterOptions = Omit< + InitialFarceRouterOptions, + 'resolver' | 'historyProtocol' +>; export default function createInitialBrowserRouter( options: InitialBrowserRouterOptions, diff --git a/src/createInitialFarceRouter.ts b/src/createInitialFarceRouter.ts index c3878acb..ad00551a 100644 --- a/src/createInitialFarceRouter.ts +++ b/src/createInitialFarceRouter.ts @@ -1,7 +1,16 @@ -import createFarceRouter from './createFarceRouter'; +import createFarceRouter, { + FarceRouter, + FarceRouterOptions, +} from './createFarceRouter'; import createFarceStore from './createFarceStore'; import getStoreRenderArgs from './getStoreRenderArgs'; -import { FarceRouter, InitialFarceRouterOptions } from './typeUtils'; +import { Resolver } from './typeUtils'; + +export interface InitialFarceRouterOptions + extends Omit { + matchContext?: any; + resolver: Resolver; +} export default async function createInitialFarceRouter({ historyProtocol, diff --git a/src/createRender.tsx b/src/createRender.tsx index 19cfe786..866b96f5 100644 --- a/src/createRender.tsx +++ b/src/createRender.tsx @@ -1,8 +1,18 @@ import React from 'react'; -import ElementsRenderer from './ElementsRenderer'; +import ElementsRenderer, { + RenderArgs, + RenderErrorArgs, + RenderPendingArgs, + RenderReadyArgs, +} from './ElementsRenderer'; import StaticContainer from './StaticContainer'; -import { CreateRenderOptions, RenderArgs } from './typeUtils'; + +export interface CreateRenderOptions { + renderPending?: (args: RenderPendingArgs) => React.ReactElement; + renderReady?: (args: RenderReadyArgs) => React.ReactElement; + renderError?: (args: RenderErrorArgs) => React.ReactNode; +} /** * A convenience method for handling the 3 main states a route match might produce. diff --git a/src/getStoreRenderArgs.ts b/src/getStoreRenderArgs.ts index bf1d6a7d..5bed6554 100644 --- a/src/getStoreRenderArgs.ts +++ b/src/getStoreRenderArgs.ts @@ -1,6 +1,16 @@ +import { Store } from 'redux'; + +import { RenderArgs } from './ElementsRenderer'; import createStoreRouterObject from './createStoreRouterObject'; import getRenderArgs from './getRenderArgs'; -import { GetStoreRenderArgsOptions, RenderArgs } from './typeUtils'; +import { FoundState, Resolver } from './typeUtils'; + +export interface GetStoreRenderArgsOptions { + store: Store; + getFound?: (store: Store) => FoundState; + matchContext: any; + resolver: Resolver; +} // This function returns a promise. It doesn't need to be an async function // because it doesn't use the promise's value. diff --git a/src/resolveRenderArgs.ts b/src/resolveRenderArgs.ts index bfe55361..a7ed4d64 100644 --- a/src/resolveRenderArgs.ts +++ b/src/resolveRenderArgs.ts @@ -1,7 +1,6 @@ import HttpError from './HttpError'; import { Match, - RenderArgsElements, ResolvedElement, Resolver, RouteIndices, @@ -9,6 +8,11 @@ import { Router, } from './typeUtils'; +// This is the folded resolver output from resolveRenderArgs. +export type RenderArgsElements = Array< + ResolvedElement | Record +>; + function foldElements( elementsRaw: Array, routeIndices: RouteIndices, diff --git a/src/server.tsx b/src/server.tsx index 22bf04cb..1d191039 100644 --- a/src/server.tsx +++ b/src/server.tsx @@ -2,13 +2,15 @@ import FarceActions from 'farce/Actions'; import ServerProtocol from 'farce/ServerProtocol'; import React, { useMemo } from 'react'; +import { RenderArgs } from './ElementsRenderer'; import RedirectException from './RedirectException'; import RouterContext from './RouterContext'; +import { FarceRouterOptions } from './createFarceRouter'; import createFarceStore from './createFarceStore'; import createRender from './createRender'; import getStoreRenderArgs from './getStoreRenderArgs'; import defaultResolver from './resolver'; -import { FarceRouterOptions, RenderArgs, Resolver } from './typeUtils'; +import { Resolver } from './typeUtils'; interface RouterProviderProps { renderArgs: RenderArgs; diff --git a/src/typeUtils.ts b/src/typeUtils.ts index b0da5dd7..2ab62786 100644 --- a/src/typeUtils.ts +++ b/src/typeUtils.ts @@ -3,14 +3,12 @@ import { FarceStoreExtension, - HistoryEnhancerOptions, Location, LocationDescriptor, LocationDescriptorObject, NavigationListener, NavigationListenerOptions, NavigationListenerResult, - Protocol, Query, QueryDescriptor, } from 'farce'; @@ -18,7 +16,6 @@ import * as React from 'react'; // eslint-disable-next-line @typescript-eslint/no-unused-vars import { Middleware, Reducer, Store, StoreEnhancer } from 'redux'; -import HttpError from './HttpError'; import Matcher from './Matcher'; export { @@ -462,113 +459,28 @@ export interface FoundStoreExtension { // matcher: Matcher, // ): StoreEnhancer<{ found: FoundStoreExtension }>; -export type RenderPendingArgs = Match; - -// This is the folded resolver output from resolveRenderArgs. -export type RenderArgsElements = Array< - ResolvedElement | Record ->; - -export interface RenderReadyArgs extends Match { - elements: RenderArgsElements; -} - -export interface RenderErrorArgs extends Match { - error: HttpError; -} - -export type RenderArgs = RenderPendingArgs | RenderReadyArgs | RenderErrorArgs; - -export interface CreateRenderOptions { - renderPending?: (args: RenderPendingArgs) => React.ReactElement; - renderReady?: (args: RenderReadyArgs) => React.ReactElement; - renderError?: (args: RenderErrorArgs) => React.ReactNode; -} - // export function createRender( // options: CreateRenderOptions, // ): (renderArgs: RenderArgs) => React.ReactElement; -export interface ConnectedRouterOptions extends CreateRenderOptions { - render?: (args: RenderArgs) => React.ReactElement; - getFound?: (store: Store) => FoundState; -} - -export interface ConnectedRouterProps { - matchContext?: any; - resolver: Resolver; - initialRenderArgs?: RenderArgs; -} - -export type ConnectedRouter = React.ComponentType; - // export function createConnectedRouter( // options: ConnectedRouterOptions, // ): ConnectedRouter; -export interface FarceRouterOptions extends ConnectedRouterOptions { - store?: Store; - historyProtocol: Protocol; - historyMiddlewares?: Middleware[]; - historyOptions?: Omit; - routeConfig: RouteConfig; -} - -export type FarceRouterProps = ConnectedRouterProps; - -export type FarceRouter = React.ComponentType; - // export function createFarceRouter(options: FarceRouterOptions): FarceRouter; -export interface BrowserRouterOptions - extends Omit { - render?: (args: RenderArgs) => React.ReactElement; -} - -export interface BrowserRouterProps - extends Omit { - resolver?: Resolver; -} - -export type BrowserRouter = React.ComponentType; - // export function createBrowserRouter( // options: BrowserRouterOptions, // ): BrowserRouter; -export interface InitialFarceRouterOptions - extends Omit { - matchContext?: any; - resolver: Resolver; -} - // export function createInitialFarceRouter( // options: InitialFarceRouterOptions, // ): Promise; -export type InitialBrowserRouterOptions = Omit< - InitialFarceRouterOptions, - 'resolver' | 'historyProtocol' ->; - // export function createInitialBrowserRouter( // options: InitialBrowserRouterOptions, // ): Promise; -export interface ElementsRendererProps { - elements: RenderArgsElements; -} - -export type ElementsRenderer = - React.ComponentType | null; - -export interface GetStoreRenderArgsOptions { - store: Store; - getFound?: (store: Store) => FoundState; - matchContext: any; - resolver: Resolver; -} - // export function getStoreRenderArgs( // options: GetStoreRenderArgsOptions, // ): Promise; From 915443dd3cd57f83008254b4edd76c267d0bfdf0 Mon Sep 17 00:00:00 2001 From: Szymon Wiszczuk Date: Wed, 8 Feb 2023 18:55:27 +0100 Subject: [PATCH 2/3] further decoupling + naming change --- .eslintrc.js | 1 + src/ElementsRenderer.ts | 2 +- src/Link.tsx | 73 ++++++++++++++++++++++- src/Matcher.ts | 2 +- src/Redirect.tsx | 13 ++++- src/ResolverUtils.ts | 7 ++- src/Route.ts | 2 +- src/RouterContext.ts | 2 +- src/createBaseRouter.tsx | 2 +- src/createBrowserRouter.tsx | 2 +- src/createConnectedRouter.tsx | 2 +- src/createElements.tsx | 2 +- src/createFarceRouter.tsx | 2 +- src/createFarceStore.ts | 2 +- src/createInitialFarceRouter.ts | 2 +- src/createMatchEnhancer.ts | 2 +- src/createStoreRouterObject.ts | 2 +- src/foundReducer.ts | 2 +- src/getRenderArgs.ts | 2 +- src/getStoreRenderArgs.ts | 2 +- src/hotRouteConfig.ts | 2 +- src/makeRouteConfig.ts | 2 +- src/resolveRenderArgs.ts | 2 +- src/resolver.ts | 2 +- src/server.tsx | 2 +- src/useMatch.ts | 2 +- src/useParams.ts | 2 +- src/{typeUtils.ts => utilityTypes.ts} | 83 --------------------------- test/Matcher.test.ts | 2 +- test/render.test.tsx | 2 +- test/resolver.test.ts | 2 +- 31 files changed, 116 insertions(+), 113 deletions(-) rename src/{typeUtils.ts => utilityTypes.ts} (82%) diff --git a/.eslintrc.js b/.eslintrc.js index 5843f5b2..493a8216 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -9,5 +9,6 @@ module.exports = { rules: { 'prettier/prettier': 'error', 'no-use-before-define': 'off', + 'react/no-unused-prop-types': 'off', }, }; diff --git a/src/ElementsRenderer.ts b/src/ElementsRenderer.ts index b3e55c92..c7a2cd3e 100644 --- a/src/ElementsRenderer.ts +++ b/src/ElementsRenderer.ts @@ -2,7 +2,7 @@ import React from 'react'; import HttpError from './HttpError'; import { RenderArgsElements } from './resolveRenderArgs'; -import { Match, ResolvedElement } from './typeUtils'; +import { Match, ResolvedElement } from './utilityTypes'; export type RenderPendingArgs = Match; diff --git a/src/Link.tsx b/src/Link.tsx index 0e0a438f..d4a5b3dd 100644 --- a/src/Link.tsx +++ b/src/Link.tsx @@ -2,8 +2,79 @@ import useEventCallback from '@restart/hooks/useEventCallback'; import React from 'react'; import warning from 'tiny-warning'; -import { LinkInjectedProps, LinkProps } from './typeUtils'; import useRouter from './useRouter'; +import { LocationDescriptor } from './utilityTypes'; + +export type LinkPropsWithActivePropName< + TInner extends React.ComponentType< + LinkInjectedProps & { [activePropName in TActivePropName]: boolean } + >, + TActivePropName extends string, +> = ReplaceLinkProps< + TInner, + LinkPropsNodeChild & { + as: TInner; + activePropName: TActivePropName; + } & { + [activePropName in TActivePropName]?: null; + } +>; +export interface LinkPropsCommon { + to: LocationDescriptor; + // match: Match, provided by withRouter + // router: Router, provided by withRouter + exact?: boolean; + target?: string; + onClick?: (event: React.SyntheticEvent) => void; +} + +export interface LinkInjectedProps { + href: string; + onClick: (event: React.SyntheticEvent) => void; +} + +export interface LinkPropsNodeChild extends LinkPropsCommon { + activeClassName?: string; + activeStyle?: Record; + children?: React.ReactNode; +} + +type ReplaceLinkProps = Omit< + React.ComponentProps, + keyof TProps | keyof LinkInjectedProps +> & + TProps; + +export type LinkPropsSimple = ReplaceLinkProps<'a', LinkPropsNodeChild>; + +export type LinkPropsWithAs< + TInner extends React.ElementType, +> = ReplaceLinkProps< + TInner, + LinkPropsNodeChild & { + as: TInner; + activePropName?: null; + } +>; +export interface LinkPropsWithFunctionChild extends LinkPropsCommon { + children: (linkRenderArgs: { + href: string; + active: boolean; + onClick: (event: React.SyntheticEvent) => void; + }) => React.ReactNode; +} + +export type LinkProps< + TInner extends React.ElementType = never, + TInnerWithActivePropName extends React.ComponentType< + LinkInjectedProps & { [activePropName in TActivePropName]: boolean } + > = never, + TActivePropName extends string = never, +> = + | LinkPropsSimple + | LinkPropsWithAs + | LinkPropsWithActivePropName + | LinkPropsWithFunctionChild; // TODO: Try to type this & simplify those types in next breaking change. function Link({ diff --git a/src/Matcher.ts b/src/Matcher.ts index e4a6e586..26ae89a6 100644 --- a/src/Matcher.ts +++ b/src/Matcher.ts @@ -15,7 +15,7 @@ import type { RouteConfig, RouteIndices, RouteObject, -} from './typeUtils'; +} from './utilityTypes'; export type RouteConfigGroups = Record; diff --git a/src/Redirect.tsx b/src/Redirect.tsx index 6f0b1ef2..a4c0e18c 100644 --- a/src/Redirect.tsx +++ b/src/Redirect.tsx @@ -2,7 +2,13 @@ import React from 'react'; import RedirectException from './RedirectException'; -import { LocationDescriptor, Match, RedirectOptions } from './typeUtils'; +import { LocationDescriptor, Match } from './utilityTypes'; + +export interface RedirectOptions { + from?: string; + to: string | ((match: Match) => LocationDescriptor); + status?: number; +} class Redirect implements RedirectOptions { path?: string; @@ -38,8 +44,11 @@ if (__DEV__) { (Redirect.prototype as any).isReactComponent = {}; } +// It's more "natural" to call this "props" when used in the context of a +// React component. +export type RedirectProps = RedirectOptions; // This actually doesn't extend a React.Component, but we need consumer to think that it does -declare class RedirectType extends React.Component { +declare class RedirectType extends React.Component { constructor(config: RedirectOptions); } diff --git a/src/ResolverUtils.ts b/src/ResolverUtils.ts index 2711e899..45d4e2eb 100644 --- a/src/ResolverUtils.ts +++ b/src/ResolverUtils.ts @@ -2,7 +2,12 @@ import isPromise from 'is-promise'; import { setImmediate } from 'tiny-set-immediate'; import warning from 'tiny-warning'; -import { Match, RouteIndices, RouteMatch, RouteObjectBase } from './typeUtils'; +import { + Match, + RouteIndices, + RouteMatch, + RouteObjectBase, +} from './utilityTypes'; const UNRESOLVED = {}; diff --git a/src/Route.ts b/src/Route.ts index 45edb4df..b9097624 100644 --- a/src/Route.ts +++ b/src/Route.ts @@ -1,7 +1,7 @@ // eslint-disable-next-line max-classes-per-file import React from 'react'; -import type { RouteObject, RouteProps } from './typeUtils'; +import type { RouteObject, RouteProps } from './utilityTypes'; /** * Convenience class for creating normal routes with JSX. When not using JSX, diff --git a/src/RouterContext.ts b/src/RouterContext.ts index 1a21955a..75f8a93f 100644 --- a/src/RouterContext.ts +++ b/src/RouterContext.ts @@ -1,6 +1,6 @@ import React from 'react'; -import { Match, Router } from './typeUtils'; +import { Match, Router } from './utilityTypes'; export interface RouterContextState { match: Match | null; diff --git a/src/createBaseRouter.tsx b/src/createBaseRouter.tsx index a5f3f497..de0490ed 100644 --- a/src/createBaseRouter.tsx +++ b/src/createBaseRouter.tsx @@ -10,7 +10,7 @@ import StaticContainer from './StaticContainer'; import createRender, { CreateRenderOptions } from './createRender'; import createStoreRouterObject from './createStoreRouterObject'; import resolveRenderArgs from './resolveRenderArgs'; -import { MatchBase, Resolver } from './typeUtils'; +import { MatchBase, Resolver, Router } from './utilityTypes'; export interface ConnectedRouterProps { matchContext?: any; diff --git a/src/createBrowserRouter.tsx b/src/createBrowserRouter.tsx index 8c9aef51..d612a707 100644 --- a/src/createBrowserRouter.tsx +++ b/src/createBrowserRouter.tsx @@ -7,7 +7,7 @@ import createFarceRouter, { FarceRouterProps, } from './createFarceRouter'; import resolver from './resolver'; -import { Resolver } from './typeUtils'; +import { Resolver } from './utilityTypes'; export interface BrowserRouterProps extends Omit { diff --git a/src/createConnectedRouter.tsx b/src/createConnectedRouter.tsx index 0827eb17..651c65b1 100644 --- a/src/createConnectedRouter.tsx +++ b/src/createConnectedRouter.tsx @@ -5,7 +5,7 @@ import { Store } from 'redux'; import { RenderArgs } from './ElementsRenderer'; import createBaseRouter, { ConnectedRouterProps } from './createBaseRouter'; import { CreateRenderOptions } from './createRender'; -import { FoundState } from './typeUtils'; +import { FoundState } from './utilityTypes'; export type ConnectedRouter = React.ComponentType; export interface ConnectedRouterOptions extends CreateRenderOptions { diff --git a/src/createElements.tsx b/src/createElements.tsx index 6b4e84c5..0d509ed2 100644 --- a/src/createElements.tsx +++ b/src/createElements.tsx @@ -2,7 +2,7 @@ import React from 'react'; import warning from 'tiny-warning'; import { isResolved } from './ResolverUtils'; -import { Match, ResolvedElement, RouteMatch } from './typeUtils'; +import { Match, ResolvedElement, RouteMatch } from './utilityTypes'; /** * maps an array of `Route`s to React elements. The returned array diff --git a/src/createFarceRouter.tsx b/src/createFarceRouter.tsx index be1668b5..71be5449 100644 --- a/src/createFarceRouter.tsx +++ b/src/createFarceRouter.tsx @@ -6,7 +6,7 @@ import { Middleware, Store } from 'redux'; import createBaseRouter, { ConnectedRouterProps } from './createBaseRouter'; import { ConnectedRouterOptions } from './createConnectedRouter'; import createFarceStore from './createFarceStore'; -import { FoundState, RouteConfig } from './typeUtils'; +import { FoundState, RouteConfig } from './utilityTypes'; export interface FarceRouterOptions extends ConnectedRouterOptions { store?: Store; diff --git a/src/createFarceStore.ts b/src/createFarceStore.ts index 5c848a06..05a96002 100644 --- a/src/createFarceStore.ts +++ b/src/createFarceStore.ts @@ -15,7 +15,7 @@ import { import Matcher from './Matcher'; import createMatchEnhancer from './createMatchEnhancer'; import foundReducer from './foundReducer'; -import { RouteConfig } from './typeUtils'; +import { RouteConfig } from './utilityTypes'; interface Props { matcherOptions?: any; diff --git a/src/createInitialFarceRouter.ts b/src/createInitialFarceRouter.ts index ad00551a..e6b9447d 100644 --- a/src/createInitialFarceRouter.ts +++ b/src/createInitialFarceRouter.ts @@ -4,7 +4,7 @@ import createFarceRouter, { } from './createFarceRouter'; import createFarceStore from './createFarceStore'; import getStoreRenderArgs from './getStoreRenderArgs'; -import { Resolver } from './typeUtils'; +import { Resolver } from './utilityTypes'; export interface InitialFarceRouterOptions extends Omit { diff --git a/src/createMatchEnhancer.ts b/src/createMatchEnhancer.ts index 406a31bd..b0d5cb20 100644 --- a/src/createMatchEnhancer.ts +++ b/src/createMatchEnhancer.ts @@ -3,7 +3,7 @@ import { Middleware, Store, StoreEnhancer, applyMiddleware } from 'redux'; import ActionTypes from './ActionTypes'; import Matcher from './Matcher'; -import { FoundState, FoundStoreExtension, RouteConfig } from './typeUtils'; +import { FoundState, FoundStoreExtension, RouteConfig } from './utilityTypes'; function createMatchMiddleware( matcher: Matcher, diff --git a/src/createStoreRouterObject.ts b/src/createStoreRouterObject.ts index ed961f4c..64c87291 100644 --- a/src/createStoreRouterObject.ts +++ b/src/createStoreRouterObject.ts @@ -1,7 +1,7 @@ import FarceActions from 'farce/Actions'; import { Store, bindActionCreators } from 'redux'; -import { Router } from './typeUtils'; +import { Router } from './utilityTypes'; const NAVIGATION_ACTION_CREATORS = { push: FarceActions.push, diff --git a/src/foundReducer.ts b/src/foundReducer.ts index 5bc1d72f..cd956a75 100644 --- a/src/foundReducer.ts +++ b/src/foundReducer.ts @@ -1,7 +1,7 @@ import { Reducer } from 'redux'; import ActionTypes from './ActionTypes'; -import { FoundState } from './typeUtils'; +import { FoundState } from './utilityTypes'; // TODO: Re-check types here. const foundReducer = ( diff --git a/src/getRenderArgs.ts b/src/getRenderArgs.ts index ed6efc88..f07d15dd 100644 --- a/src/getRenderArgs.ts +++ b/src/getRenderArgs.ts @@ -1,5 +1,5 @@ import resolveRenderArgs, { ResolveRender } from './resolveRenderArgs'; -import { Router } from './typeUtils'; +import { Router } from './utilityTypes'; export default async function getRenderArgs( router: Router, diff --git a/src/getStoreRenderArgs.ts b/src/getStoreRenderArgs.ts index 5bed6554..c820d1c9 100644 --- a/src/getStoreRenderArgs.ts +++ b/src/getStoreRenderArgs.ts @@ -3,7 +3,7 @@ import { Store } from 'redux'; import { RenderArgs } from './ElementsRenderer'; import createStoreRouterObject from './createStoreRouterObject'; import getRenderArgs from './getRenderArgs'; -import { FoundState, Resolver } from './typeUtils'; +import { FoundState, Resolver } from './utilityTypes'; export interface GetStoreRenderArgsOptions { store: Store; diff --git a/src/hotRouteConfig.ts b/src/hotRouteConfig.ts index ea9a854a..2c4a8464 100644 --- a/src/hotRouteConfig.ts +++ b/src/hotRouteConfig.ts @@ -1,4 +1,4 @@ -import { RouteConfig } from './typeUtils'; +import { RouteConfig } from './utilityTypes'; export default function hotRouteConfig(routeConfig: RouteConfig): RouteConfig { if (__DEV__ && typeof window !== 'undefined') { diff --git a/src/makeRouteConfig.ts b/src/makeRouteConfig.ts index a7b31590..183b429c 100644 --- a/src/makeRouteConfig.ts +++ b/src/makeRouteConfig.ts @@ -1,6 +1,6 @@ import React from 'react'; -import { RouteConfig } from './typeUtils'; +import { RouteConfig } from './utilityTypes'; // TODO: what is even happening in this file? Try to fix as any's(+ maybe simplify) function buildRouteConfig( diff --git a/src/resolveRenderArgs.ts b/src/resolveRenderArgs.ts index a7ed4d64..ec8f7298 100644 --- a/src/resolveRenderArgs.ts +++ b/src/resolveRenderArgs.ts @@ -6,7 +6,7 @@ import { RouteIndices, RouteObject, Router, -} from './typeUtils'; +} from './utilityTypes'; // This is the folded resolver output from resolveRenderArgs. export type RenderArgsElements = Array< diff --git a/src/resolver.ts b/src/resolver.ts index 56dc7bab..59c2bcdf 100644 --- a/src/resolver.ts +++ b/src/resolver.ts @@ -14,7 +14,7 @@ import { ResolvedElement, RouteMatch, RouteObjectBase, -} from './typeUtils'; +} from './utilityTypes'; function getRouteGetData(route: RouteObjectBase) { return route.getData; diff --git a/src/server.tsx b/src/server.tsx index 1d191039..b0a01a92 100644 --- a/src/server.tsx +++ b/src/server.tsx @@ -10,7 +10,7 @@ import createFarceStore from './createFarceStore'; import createRender from './createRender'; import getStoreRenderArgs from './getStoreRenderArgs'; import defaultResolver from './resolver'; -import { Resolver } from './typeUtils'; +import { Resolver } from './utilityTypes'; interface RouterProviderProps { renderArgs: RenderArgs; diff --git a/src/useMatch.ts b/src/useMatch.ts index 94a4e6b0..c6da60c1 100644 --- a/src/useMatch.ts +++ b/src/useMatch.ts @@ -1,5 +1,5 @@ -import { Match } from './typeUtils'; import useRouter from './useRouter'; +import { Match } from './utilityTypes'; /** Returns the current route Match */ export default function useMatch(): Match | null { diff --git a/src/useParams.ts b/src/useParams.ts index bcfe7b4d..06ee08fd 100644 --- a/src/useParams.ts +++ b/src/useParams.ts @@ -1,5 +1,5 @@ -import { Params } from './typeUtils'; import useMatch from './useMatch'; +import { Params } from './utilityTypes'; /** Returns the current route params */ export default function useParams(): Params | undefined { diff --git a/src/typeUtils.ts b/src/utilityTypes.ts similarity index 82% rename from src/typeUtils.ts rename to src/utilityTypes.ts index 2ab62786..e54e1918 100644 --- a/src/typeUtils.ts +++ b/src/utilityTypes.ts @@ -303,93 +303,10 @@ export interface RouteProps extends RouteObjectBase { // constructor(status: number, data?: any); // } -export interface RedirectOptions { - from?: string; - to: string | ((match: Match) => LocationDescriptor); - status?: number; -} - -// It's more "natural" to call this "props" when used in the context of a -// React component. -export type RedirectProps = RedirectOptions; - // export class Redirect extends React.Component { // constructor(config: RedirectOptions); // } -export interface LinkPropsCommon { - to: LocationDescriptor; - // match: Match, provided by withRouter - // router: Router, provided by withRouter - exact?: boolean; - target?: string; - onClick?: (event: React.SyntheticEvent) => void; -} - -export interface LinkInjectedProps { - href: string; - onClick: (event: React.SyntheticEvent) => void; -} - -export interface LinkPropsNodeChild extends LinkPropsCommon { - activeClassName?: string; - activeStyle?: Record; - children?: React.ReactNode; -} - -type ReplaceLinkProps = Omit< - React.ComponentProps, - keyof TProps | keyof LinkInjectedProps -> & - TProps; - -export type LinkPropsSimple = ReplaceLinkProps<'a', LinkPropsNodeChild>; - -export type LinkPropsWithAs< - TInner extends React.ElementType, -> = ReplaceLinkProps< - TInner, - LinkPropsNodeChild & { - as: TInner; - activePropName?: null; - } ->; - -export type LinkPropsWithActivePropName< - TInner extends React.ComponentType< - LinkInjectedProps & { [activePropName in TActivePropName]: boolean } - >, - TActivePropName extends string, -> = ReplaceLinkProps< - TInner, - LinkPropsNodeChild & { - as: TInner; - activePropName: TActivePropName; - } & { - [activePropName in TActivePropName]?: null; - } ->; - -export interface LinkPropsWithFunctionChild extends LinkPropsCommon { - children: (linkRenderArgs: { - href: string; - active: boolean; - onClick: (event: React.SyntheticEvent) => void; - }) => React.ReactNode; -} - -export type LinkProps< - TInner extends React.ElementType = never, - TInnerWithActivePropName extends React.ComponentType< - LinkInjectedProps & { [activePropName in TActivePropName]: boolean } - > = never, - TActivePropName extends string = never, -> = - | LinkPropsSimple - | LinkPropsWithAs - | LinkPropsWithActivePropName - | LinkPropsWithFunctionChild; - // export class Link< // TInner extends React.ElementType = never, // TInnerWithActivePropName extends React.ComponentType< diff --git a/test/Matcher.test.ts b/test/Matcher.test.ts index cc7b84fa..2b8ac471 100644 --- a/test/Matcher.test.ts +++ b/test/Matcher.test.ts @@ -1,5 +1,5 @@ import Matcher from '../src/Matcher'; -import { Match } from '../src/typeUtils'; +import { Match } from '../src/utilityTypes'; const createLocationMatch = (locationMatch) => ({ diff --git a/test/render.test.tsx b/test/render.test.tsx index d40854da..71d8988a 100644 --- a/test/render.test.tsx +++ b/test/render.test.tsx @@ -5,7 +5,7 @@ import React from 'react'; import TestRenderer from 'react-test-renderer'; import createFarceRouter from '../src/createFarceRouter'; -import { RouteRenderMethod } from '../src/typeUtils'; +import { RouteRenderMethod } from '../src/utilityTypes'; import { InstrumentedResolver } from './helpers'; describe('render', () => { diff --git a/test/resolver.test.ts b/test/resolver.test.ts index d0cd30fc..67ded7b2 100644 --- a/test/resolver.test.ts +++ b/test/resolver.test.ts @@ -3,7 +3,7 @@ import pDefer from 'p-defer'; import { getRouteMatches } from '../src/ResolverUtils'; import resolver from '../src/resolver'; -import { Match } from '../src/typeUtils'; +import { Match } from '../src/utilityTypes'; describe('resolver', () => { describe('getData', () => { From e229ec047d1871a5d3f1924a444150db564ae0c2 Mon Sep 17 00:00:00 2001 From: Szymon Wiszczuk Date: Wed, 8 Feb 2023 19:01:31 +0100 Subject: [PATCH 3/3] minor updates --- src/Matcher.ts | 15 +++++ src/Route.ts | 10 +++- src/utilityTypes.ts | 133 -------------------------------------------- 3 files changed, 24 insertions(+), 134 deletions(-) diff --git a/src/Matcher.ts b/src/Matcher.ts index 26ae89a6..201ea6d4 100644 --- a/src/Matcher.ts +++ b/src/Matcher.ts @@ -31,6 +31,12 @@ export interface MatcherOptions { warnOnPartiallyMatchedNamedRoutes?: boolean; } +/** + * An object implementing the matching algorithm. + * + * User code generally shouldn't need this, but it doesn't hurt to here, + * since we use it for routerShape below. + */ export default class Matcher { private routeConfig: RouteConfig; @@ -76,6 +82,11 @@ export default class Matcher { return `${basePath}${this.getCanonicalPattern(path)}`; } + /** + * for match as above, returns whether match corresponds to location or a + * subpath of location; if exact is set, returns whether match corresponds + * exactly to location + */ isActive( { location: matchLocation }: Match, location: LocationDescriptorObject, @@ -90,6 +101,10 @@ export default class Matcher { ); } + /** + * Returns the path string for a pattern of the same format as a route path + * and a object of the corresponding path parameters + */ format(pattern: string, params: ParamsDescriptor): string { return compile(pattern)(params); } diff --git a/src/Route.ts b/src/Route.ts index b9097624..0714b83e 100644 --- a/src/Route.ts +++ b/src/Route.ts @@ -1,7 +1,15 @@ // eslint-disable-next-line max-classes-per-file import React from 'react'; -import type { RouteObject, RouteProps } from './utilityTypes'; +import type { RouteObject, RouteObjectBase } from './utilityTypes'; + +export interface RouteProps extends RouteObjectBase { + children?: React.ReactNode | Record; +} + +export interface RouteProps extends RouteObjectBase { + children?: React.ReactNode | Record; +} /** * Convenience class for creating normal routes with JSX. When not using JSX, diff --git a/src/utilityTypes.ts b/src/utilityTypes.ts index e54e1918..5fb1a023 100644 --- a/src/utilityTypes.ts +++ b/src/utilityTypes.ts @@ -93,50 +93,15 @@ export interface Resolver { ): AsyncGenerator | undefined>; } -// export const resolver: Resolver; - export interface FoundState { match: MatchBase; resolvedMatch: MatchBase; } -// export const foundReducer: Reducer; - export interface IsActiveOptions { exact?: boolean; } -/** - * An object implementing the matching algorithm. - * - * User code generally shouldn't need this, but it doesn't hurt to here, - * since we use it for routerShape below. - */ -// export class Matcher { -// constructor(routeConfig: RouteConfig); - -// match(location: Location): MatcherResult | null; - -// getRoutes: (match: MatchBase) => RouteObject[]; - -// /** -// * for match as above, returns whether match corresponds to location or a -// * subpath of location; if exact is set, returns whether match corresponds -// * exactly to location -// */ -// isActive: ( -// match: Match, -// location: LocationDescriptorObject, -// options?: IsActiveOptions, -// ) => boolean; - -// /** -// * Returns the path string for a pattern of the same format as a route path -// * and a object of the corresponding path parameters -// */ -// format: (pattern: string, params: ParamsDescriptor) => string; -// } - export interface Router extends FarceStoreExtension, FoundStoreExtension { /** * Navigates to a new location @@ -282,43 +247,6 @@ export interface RouteObject extends RouteObjectBase { export type RouteConfig = RouteObject[]; -export interface RouteProps extends RouteObjectBase { - children?: React.ReactNode | Record; -} - -/** - * JSX Route - */ -// export class Route extends React.Component { -// constructor(options: RouteObject | RouteProps); -// } - -// export function hotRouteConfig(routeConfig: RouteConfig): RouteConfig; - -// export class HttpError { -// status: number; - -// data: any; - -// constructor(status: number, data?: any); -// } - -// export class Redirect extends React.Component { -// constructor(config: RedirectOptions); -// } - -// export class Link< -// TInner extends React.ElementType = never, -// TInnerWithActivePropName extends React.ComponentType< -// LinkInjectedProps & { [activePropName in TActivePropName]: boolean } -// > = never, -// TActivePropName extends string = never, -// > extends React.Component< -// LinkProps -// > { -// props: LinkProps; -// } - export interface RouterState { match: Match; router: Router; @@ -336,68 +264,7 @@ export interface RouteComponentDataProps data: T; } -/** - * Returns the Router and current route match from context - */ -// export function useRouter(): RouterState; - -/** Returns the current route Match */ -// export function useMatch(): Match; - -/** Returns the current route params */ -// export function useParams(): Params; - -/** Returns the current location object */ -// export function useLocation(): Location; - -// export function withRouter( -// Component: React.ComponentType, -// ): React.ComponentType>; - -// export class RedirectException { -// constructor(location: LocationDescriptor, status?: number); - -// location: LocationDescriptor; - -// status: number; -// } - -/** - * Create a route configuration from JSX configuration elements. - */ -// export function makeRouteConfig(node: React.ReactNode): RouteConfig; - export interface FoundStoreExtension { matcher: Matcher; replaceRouteConfig: (routeConfig: RouteConfig) => void; } - -// export function createMatchEnhancer( -// matcher: Matcher, -// ): StoreEnhancer<{ found: FoundStoreExtension }>; - -// export function createRender( -// options: CreateRenderOptions, -// ): (renderArgs: RenderArgs) => React.ReactElement; - -// export function createConnectedRouter( -// options: ConnectedRouterOptions, -// ): ConnectedRouter; - -// export function createFarceRouter(options: FarceRouterOptions): FarceRouter; - -// export function createBrowserRouter( -// options: BrowserRouterOptions, -// ): BrowserRouter; - -// export function createInitialFarceRouter( -// options: InitialFarceRouterOptions, -// ): Promise; - -// export function createInitialBrowserRouter( -// options: InitialBrowserRouterOptions, -// ): Promise; - -// export function getStoreRenderArgs( -// options: GetStoreRenderArgsOptions, -// ): Promise;