From 762465b0de9fae1a070dc8f82d0230853f544f4c Mon Sep 17 00:00:00 2001 From: Jan Amann Date: Tue, 27 Aug 2024 16:02:14 +0200 Subject: [PATCH] Refactor navigation APIs --- .../createLocalizedPathnamesNavigation.tsx | 12 ++-- .../createSharedPathnamesNavigation.tsx | 28 ++++---- .../createLocalizedPathnamesNavigation.tsx | 12 ++-- .../createSharedPathnamesNavigation.tsx | 26 +++----- .../src/navigation/shared/config.tsx | 64 ------------------- packages/next-intl/src/routing/config.tsx | 41 ++++++++---- 6 files changed, 61 insertions(+), 122 deletions(-) delete mode 100644 packages/next-intl/src/navigation/shared/config.tsx diff --git a/packages/next-intl/src/navigation/react-client/createLocalizedPathnamesNavigation.tsx b/packages/next-intl/src/navigation/react-client/createLocalizedPathnamesNavigation.tsx index 1bd975e69..fb7ec7284 100644 --- a/packages/next-intl/src/navigation/react-client/createLocalizedPathnamesNavigation.tsx +++ b/packages/next-intl/src/navigation/react-client/createLocalizedPathnamesNavigation.tsx @@ -1,11 +1,11 @@ import React, {ComponentProps, ReactElement, forwardRef, useMemo} from 'react'; import useLocale from '../../react-client/useLocale'; +import { + receiveRoutingConfig, + RoutingConfigLocalizedNavigation +} from '../../routing/config'; import {Locales, Pathnames} from '../../routing/types'; import {ParametersExceptFirst} from '../../shared/types'; -import { - LocalizedNavigationRoutingConfigInput, - receiveLocalizedNavigationRoutingConfig -} from '../shared/config'; import { compileLocalizedPathname, getRoute, @@ -21,8 +21,8 @@ import useBaseRouter from './useBaseRouter'; export default function createLocalizedPathnamesNavigation< AppLocales extends Locales, AppPathnames extends Pathnames ->(input: LocalizedNavigationRoutingConfigInput) { - const config = receiveLocalizedNavigationRoutingConfig(input); +>(routing: RoutingConfigLocalizedNavigation) { + const config = receiveRoutingConfig(routing); function useTypedLocale(): AppLocales[number] { const locale = useLocale(); diff --git a/packages/next-intl/src/navigation/react-client/createSharedPathnamesNavigation.tsx b/packages/next-intl/src/navigation/react-client/createSharedPathnamesNavigation.tsx index c55f689eb..4050010f9 100644 --- a/packages/next-intl/src/navigation/react-client/createSharedPathnamesNavigation.tsx +++ b/packages/next-intl/src/navigation/react-client/createSharedPathnamesNavigation.tsx @@ -1,10 +1,10 @@ import React, {ComponentProps, ReactElement, forwardRef} from 'react'; +import { + receiveLocalePrefixConfig, + RoutingConfigSharedNavigation +} from '../../routing/config'; import {Locales} from '../../routing/types'; import {ParametersExceptFirst} from '../../shared/types'; -import { - SharedNavigationRoutingConfigInput, - receiveSharedNavigationRoutingConfig -} from '../shared/config'; import ClientLink from './ClientLink'; import {clientRedirect, clientPermanentRedirect} from './redirects'; import useBasePathname from './useBasePathname'; @@ -12,8 +12,8 @@ import useBaseRouter from './useBaseRouter'; export default function createSharedPathnamesNavigation< const AppLocales extends Locales ->(input?: SharedNavigationRoutingConfigInput) { - const config = receiveSharedNavigationRoutingConfig(input); +>(routing?: RoutingConfigSharedNavigation) { + const localePrefix = receiveLocalePrefixConfig(routing?.localePrefix); type LinkProps = Omit< ComponentProps>, @@ -23,7 +23,7 @@ export default function createSharedPathnamesNavigation< return ( ref={ref} - localePrefix={config.localePrefix} + localePrefix={localePrefix} {...props} /> ); @@ -37,30 +37,24 @@ export default function createSharedPathnamesNavigation< pathname: string, ...args: ParametersExceptFirst ) { - return clientRedirect( - {pathname, localePrefix: config.localePrefix}, - ...args - ); + return clientRedirect({pathname, localePrefix}, ...args); } function permanentRedirect( pathname: string, ...args: ParametersExceptFirst ) { - return clientPermanentRedirect( - {pathname, localePrefix: config.localePrefix}, - ...args - ); + return clientPermanentRedirect({pathname, localePrefix}, ...args); } function usePathname(): string { - const result = useBasePathname(config.localePrefix); + const result = useBasePathname(localePrefix); // @ts-expect-error -- Mirror the behavior from Next.js, where `null` is returned when `usePathname` is used outside of Next, but the types indicate that a string is always returned. return result; } function useRouter() { - return useBaseRouter(config.localePrefix); + return useBaseRouter(localePrefix); } return { diff --git a/packages/next-intl/src/navigation/react-server/createLocalizedPathnamesNavigation.tsx b/packages/next-intl/src/navigation/react-server/createLocalizedPathnamesNavigation.tsx index b34c72a34..ba63dea8c 100644 --- a/packages/next-intl/src/navigation/react-server/createLocalizedPathnamesNavigation.tsx +++ b/packages/next-intl/src/navigation/react-server/createLocalizedPathnamesNavigation.tsx @@ -1,11 +1,11 @@ import React, {ComponentProps} from 'react'; +import { + receiveRoutingConfig, + RoutingConfigLocalizedNavigation +} from '../../routing/config'; import {Locales, Pathnames} from '../../routing/types'; import {getRequestLocale} from '../../server/react-server/RequestLocale'; import {ParametersExceptFirst} from '../../shared/types'; -import { - LocalizedNavigationRoutingConfigInput, - receiveLocalizedNavigationRoutingConfig -} from '../shared/config'; import { HrefOrHrefWithParams, HrefOrUrlObjectWithParams, @@ -18,8 +18,8 @@ import {serverPermanentRedirect, serverRedirect} from './redirects'; export default function createLocalizedPathnamesNavigation< AppLocales extends Locales, AppPathnames extends Pathnames ->(input: LocalizedNavigationRoutingConfigInput) { - const config = receiveLocalizedNavigationRoutingConfig(input); +>(routing: RoutingConfigLocalizedNavigation) { + const config = receiveRoutingConfig(routing); type LinkProps = Omit< ComponentProps, diff --git a/packages/next-intl/src/navigation/react-server/createSharedPathnamesNavigation.tsx b/packages/next-intl/src/navigation/react-server/createSharedPathnamesNavigation.tsx index 83084ecf1..deaf31468 100644 --- a/packages/next-intl/src/navigation/react-server/createSharedPathnamesNavigation.tsx +++ b/packages/next-intl/src/navigation/react-server/createSharedPathnamesNavigation.tsx @@ -1,17 +1,17 @@ import React, {ComponentProps} from 'react'; +import { + receiveLocalePrefixConfig, + RoutingConfigSharedNavigation +} from '../../routing/config'; import {Locales} from '../../routing/types'; import {ParametersExceptFirst} from '../../shared/types'; -import { - SharedNavigationRoutingConfigInput, - receiveSharedNavigationRoutingConfig -} from '../shared/config'; import ServerLink from './ServerLink'; import {serverPermanentRedirect, serverRedirect} from './redirects'; export default function createSharedPathnamesNavigation< AppLocales extends Locales ->(input?: SharedNavigationRoutingConfigInput) { - const config = receiveSharedNavigationRoutingConfig(input); +>(routing?: RoutingConfigSharedNavigation) { + const localePrefix = receiveLocalePrefixConfig(routing?.localePrefix); function notSupported(hookName: string) { return () => { @@ -27,29 +27,21 @@ export default function createSharedPathnamesNavigation< 'localePrefix' | 'locales' > ) { - return ( - localePrefix={config.localePrefix} {...props} /> - ); + return localePrefix={localePrefix} {...props} />; } function redirect( pathname: string, ...args: ParametersExceptFirst ) { - return serverRedirect( - {pathname, localePrefix: config.localePrefix}, - ...args - ); + return serverRedirect({pathname, localePrefix}, ...args); } function permanentRedirect( pathname: string, ...args: ParametersExceptFirst ) { - return serverPermanentRedirect( - {pathname, localePrefix: config.localePrefix}, - ...args - ); + return serverPermanentRedirect({pathname, localePrefix}, ...args); } return { diff --git a/packages/next-intl/src/navigation/shared/config.tsx b/packages/next-intl/src/navigation/shared/config.tsx deleted file mode 100644 index 6fc928e9a..000000000 --- a/packages/next-intl/src/navigation/shared/config.tsx +++ /dev/null @@ -1,64 +0,0 @@ -import {RoutingConfig, receiveLocalePrefixConfig} from '../../routing/config'; -import { - Locales, - LocalePrefixConfigVerbose, - Pathnames -} from '../../routing/types'; - -/** - * Shared pathnames - */ - -export type SharedNavigationRoutingConfigInput = - RoutingConfig & { - locales?: AppLocales; - }; - -export type SharedNavigationRoutingConfig = - SharedNavigationRoutingConfigInput & { - localePrefix: LocalePrefixConfigVerbose; - }; - -export function receiveSharedNavigationRoutingConfig< - AppLocales extends Locales ->( - input?: SharedNavigationRoutingConfigInput -): SharedNavigationRoutingConfig { - return { - ...input, - localePrefix: receiveLocalePrefixConfig(input?.localePrefix) - }; -} - -/** - * Localized pathnames - */ - -export type LocalizedNavigationRoutingConfigInput< - AppLocales extends Locales, - AppPathnames extends Pathnames -> = RoutingConfig & { - locales: AppLocales; - - /** Maps internal pathnames to external ones which can be localized per locale. */ - pathnames: AppPathnames; -}; - -export type LocalizedNavigationRoutingConfig< - AppLocales extends Locales, - AppPathnames extends Pathnames -> = LocalizedNavigationRoutingConfigInput & { - localePrefix: LocalePrefixConfigVerbose; -}; - -export function receiveLocalizedNavigationRoutingConfig< - AppLocales extends Locales, - AppPathnames extends Pathnames ->( - input: LocalizedNavigationRoutingConfigInput -): LocalizedNavigationRoutingConfig { - return { - ...input, - localePrefix: receiveLocalePrefixConfig(input?.localePrefix) - }; -} diff --git a/packages/next-intl/src/routing/config.tsx b/packages/next-intl/src/routing/config.tsx index 832ce8578..74ee9545d 100644 --- a/packages/next-intl/src/routing/config.tsx +++ b/packages/next-intl/src/routing/config.tsx @@ -6,12 +6,6 @@ import { Pathnames } from './types'; -/** - * Maintainer note: The config that is accepted by the middleware, the shared - * and the localized pathnames navigation factory function is slightly - * different. This type declares the shared base config that is accepted by all - * of them. Properties that are different are declared in consuming types. - */ export type RoutingConfig< AppLocales extends Locales, AppPathnames extends Pathnames @@ -34,13 +28,37 @@ export type RoutingConfig< **/ localePrefix?: LocalePrefix; - /** Can be used to change the locale handling per domain. */ + /** + * Can be used to change the locale handling per domain. + * @see https://next-intl-docs.vercel.app/docs/routing#domains + **/ domains?: DomainsConfig; - /** A map of localized pathnames per locale. */ + /** + * A map of localized pathnames per locale. + * @see https://next-intl-docs.vercel.app/docs/routing#pathnames + **/ pathnames?: AppPathnames; }; +export type RoutingConfigSharedNavigation< + AppLocales extends Locales, + AppPathnames extends Pathnames +> = Omit, 'defaultLocale' | 'locales'> & + Partial< + Pick, 'defaultLocale' | 'locales'> + >; + +export type RoutingConfigLocalizedNavigation< + AppLocales extends Locales, + AppPathnames extends Pathnames +> = Omit< + RoutingConfig, + 'defaultLocale' | 'pathnames' +> & + Partial, 'defaultLocale'>> & + Required, 'pathnames'>>; + export type ResolvedRoutingConfig< AppLocales extends Locales, AppPathnames extends Pathnames @@ -50,10 +68,9 @@ export type ResolvedRoutingConfig< export function receiveRoutingConfig< AppLocales extends Locales, - AppPathnames extends Pathnames ->( - input: RoutingConfig -): ResolvedRoutingConfig { + AppPathnames extends Pathnames, + Config extends Partial> +>(input: Config) { return { ...input, localePrefix: receiveLocalePrefixConfig(input.localePrefix)