From eb31e19807bf8a3a07f474ce7817dc54a1697068 Mon Sep 17 00:00:00 2001 From: LekoArts Date: Thu, 6 Jun 2024 14:37:26 +0200 Subject: [PATCH 1/7] non-working with pages AND app router --- packages/elements/src/react/sign-in/root.tsx | 24 ++++--- packages/elements/src/react/sign-up/root.tsx | 25 ++++++-- .../path-inference/__tests__/next.test.ts | 62 +++++++++++++++++++ .../path-inference/__tests__/utils.test.ts | 14 +++++ .../src/react/utils/path-inference/next.tsx | 62 +++++++++++++++++++ .../src/react/utils/path-inference/utils.ts | 3 + 6 files changed, 178 insertions(+), 12 deletions(-) create mode 100644 packages/elements/src/react/utils/path-inference/__tests__/next.test.ts create mode 100644 packages/elements/src/react/utils/path-inference/__tests__/utils.test.ts create mode 100644 packages/elements/src/react/utils/path-inference/next.tsx create mode 100644 packages/elements/src/react/utils/path-inference/utils.ts diff --git a/packages/elements/src/react/sign-in/root.tsx b/packages/elements/src/react/sign-in/root.tsx index 09cce2c8726..7018a4e703d 100644 --- a/packages/elements/src/react/sign-in/root.tsx +++ b/packages/elements/src/react/sign-in/root.tsx @@ -12,6 +12,7 @@ import { Router, useClerkRouter, useNextRouter, useVirtualRouter } from '~/react import { SignInRouterCtx } from '~/react/sign-in/context'; import { Form } from '../common/form'; +import { usePathnameWithoutCatchAll } from '../utils/path-inference/next'; type SignInFlowProviderProps = { children: React.ReactNode; @@ -60,13 +61,19 @@ function SignInFlowProvider({ children, exampleMode }: SignInFlowProviderProps) } export type SignInRootProps = SignInFlowProviderProps & { + /** + * Fallback markup to render while Clerk is loading + */ fallback?: React.ReactNode; /** - * The base path for your sign-in route. Defaults to `/sign-in`. - * - * TODO: re-use usePathnameWithoutCatchAll from the next SDK + * The base path for your sign-in route. + * Will be automatically inferred in Next.js. + * @example `/sign-in` */ path?: string; + /** + * If you want to render Clerk Elements in e.g. a modal, use the `virtual` routing mode. + */ routing?: ROUTING; }; @@ -87,18 +94,21 @@ export type SignInRootProps = SignInFlowProviderProps & { */ export function SignInRoot({ children, - exampleMode, + exampleMode = false, fallback = null, - path = SIGN_IN_DEFAULT_BASE_PATH, - routing, + path: pathProp, + routing = ROUTING.path, }: SignInRootProps): JSX.Element | null { const clerk = useClerk(); + const inferredPath = usePathnameWithoutCatchAll(); + const path = pathProp || inferredPath || SIGN_IN_DEFAULT_BASE_PATH; clerk.telemetry?.record( eventComponentMounted('Elements_SignInRoot', { - exampleMode: Boolean(exampleMode), + exampleMode, fallback: Boolean(fallback), path, + routing, }), ); diff --git a/packages/elements/src/react/sign-up/root.tsx b/packages/elements/src/react/sign-up/root.tsx index 4a0cc57ad7b..cd4b129fc2e 100644 --- a/packages/elements/src/react/sign-up/root.tsx +++ b/packages/elements/src/react/sign-up/root.tsx @@ -13,6 +13,7 @@ import { Router, useClerkRouter, useNextRouter, useVirtualRouter } from '~/react import { SignUpRouterCtx } from '~/react/sign-up/context'; import { Form } from '../common/form'; +import { usePathnameWithoutCatchAll } from '../utils/path-inference/next'; type SignUpFlowProviderProps = { children: React.ReactNode; @@ -61,8 +62,19 @@ function SignUpFlowProvider({ children, exampleMode }: SignUpFlowProviderProps) } export type SignUpRootProps = SignUpFlowProviderProps & { + /** + * Fallback markup to render while Clerk is loading + */ fallback?: React.ReactNode; + /** + * The base path for your sign-up route. + * Will be automatically inferred in Next.js. + * @example `/sign-up` + */ path?: string; + /** + * If you want to render Clerk Elements in e.g. a modal, use the `virtual` routing mode. + */ routing?: ROUTING; }; @@ -83,18 +95,21 @@ export type SignUpRootProps = SignUpFlowProviderProps & { */ export function SignUpRoot({ children, - exampleMode, + exampleMode = false, fallback = null, - path = SIGN_UP_DEFAULT_BASE_PATH, - routing, + path: pathProp, + routing = ROUTING.path, }: SignUpRootProps): JSX.Element | null { const clerk = useClerk(); + const inferredPath = usePathnameWithoutCatchAll(); + const path = pathProp || inferredPath || SIGN_UP_DEFAULT_BASE_PATH; clerk.telemetry?.record( eventComponentMounted('Elements_SignUpRoot', { - path, + exampleMode, fallback: Boolean(fallback), - exampleMode: Boolean(exampleMode), + path, + routing, }), ); diff --git a/packages/elements/src/react/utils/path-inference/__tests__/next.test.ts b/packages/elements/src/react/utils/path-inference/__tests__/next.test.ts new file mode 100644 index 00000000000..75451f5d8d3 --- /dev/null +++ b/packages/elements/src/react/utils/path-inference/__tests__/next.test.ts @@ -0,0 +1,62 @@ +import { renderHook } from '@testing-library/react'; +import { useRouter } from 'next/compat/router'; +import { useParams, usePathname } from 'next/navigation'; + +import { usePathnameWithoutCatchAll } from '../next'; + +jest.mock('next/compat/router', () => ({ + useRouter: jest.fn(), +})); +jest.mock('next/navigation', () => ({ + usePathname: jest.fn(), + useParams: jest.fn(), +})); + +describe('usePathnameWithoutCatchAll', () => { + afterEach(() => { + jest.clearAllMocks(); + }); + + it('should work with pages router', () => { + const pathname = '/user/123/profile/[[...rest]]/page'; + const expectedPath = '/user/123/profile'; + + (useRouter as jest.Mock).mockImplementation(() => ({ + push: jest.fn(), + pathname: pathname, + route: '/', + asPath: '/', + query: '', + })); + + const { result } = renderHook(() => usePathnameWithoutCatchAll()); + + expect(result.current).toBe(expectedPath); + }); + + it('should work with app router', () => { + const pathname = '/user/123/profile/security'; + const expectedPath = '/user/123/profile'; + + (useRouter as jest.Mock).mockImplementation(() => null); + (usePathname as jest.Mock).mockReturnValue(pathname); + (useParams as jest.Mock).mockReturnValue({ id: '123', rest: ['security'] }); + + const { result } = renderHook(() => usePathnameWithoutCatchAll()); + + expect(result.current).toBe(expectedPath); + }); + + it('should work with multiple catch all params (app router)', () => { + const pathname = '/user/123/profile/security/otp'; + const expectedPath = '/user/123/profile'; + + (useRouter as jest.Mock).mockImplementation(() => null); + (usePathname as jest.Mock).mockReturnValue(pathname); + (useParams as jest.Mock).mockReturnValue({ id: '123', rest: ['security', 'otp'] }); + + const { result } = renderHook(() => usePathnameWithoutCatchAll()); + + expect(result.current).toBe(expectedPath); + }); +}); diff --git a/packages/elements/src/react/utils/path-inference/__tests__/utils.test.ts b/packages/elements/src/react/utils/path-inference/__tests__/utils.test.ts new file mode 100644 index 00000000000..9cc92f0a537 --- /dev/null +++ b/packages/elements/src/react/utils/path-inference/__tests__/utils.test.ts @@ -0,0 +1,14 @@ +import { removeOptionalCatchAllSegment } from '../utils'; + +describe('removeOptionalCatchAllSegment', () => { + it('should remove optional catch-all segment from the pathname', () => { + const pathname = '/users/[[...slug]].js'; + const expected = '/users'; + expect(removeOptionalCatchAllSegment(pathname)).toEqual(expected); + }); + + it('should not remove anything if there is no optional catch-all segment', () => { + const pathname = '/users/john/profile'; + expect(removeOptionalCatchAllSegment(pathname)).toEqual(pathname); + }); +}); diff --git a/packages/elements/src/react/utils/path-inference/next.tsx b/packages/elements/src/react/utils/path-inference/next.tsx new file mode 100644 index 00000000000..facafe25ec7 --- /dev/null +++ b/packages/elements/src/react/utils/path-inference/next.tsx @@ -0,0 +1,62 @@ +import { useRouter } from 'next/compat/router'; +import React from 'react'; + +import { removeOptionalCatchAllSegment } from './utils'; + +// Adapted from packages/nextjs/src/client-boundary/hooks/usePathnameWithoutCatchAll.tsx + +export const usePathnameWithoutCatchAll = () => { + const pathRef = React.useRef(); + + /** + * The compat version of useRouter returns null instead of throwing an error when used inside App router. + * Use it to detect if the component is used inside pages or app router + * TODO: Should we skip this compat layer since in the router we do not use compat? + */ + const pagesRouter = useRouter(); + + if (pagesRouter) { + if (pathRef.current) { + return pathRef.current; + } else { + // The optional catch all route is included in the pathname in pages router. It starts with [[... and we can just remove it + pathRef.current = removeOptionalCatchAllSegment(pagesRouter.pathname); + return pathRef.current; + } + } + + /** + * Require is used to avoid importing next/navigation when the pages router is used, as it will throw an error. + * Can't use dynamic import as the hook needs to be sync + */ + // eslint-disable-next-line @typescript-eslint/no-var-requires + const usePathname = require('next/navigation').usePathname; + // eslint-disable-next-line @typescript-eslint/no-var-requires + const useParams = require('next/navigation').useParams; + + /** + * Get the pathname that includes any named or catch all params. + * @example + * /user/[id]/profile/[[...rest]]/page.tsx + * + * This filesystem route could give us the following pathname: + * /user/123/profile/security + * if the user navigates to the security section of the user profile + */ + const pathname = usePathname() || ''; + const pathParts = pathname.split('/').filter(Boolean); + /** + * For /user/[id]/profile/[[...rest]]/page.tsx useParams will return { id: '123', rest: ['security'] }. + * So catch all params are always arrays + */ + const catchAllParams = Object.values(useParams() || {}) + .filter(v => Array.isArray(v)) + .flat(Infinity); + if (pathRef.current) { + return pathRef.current; + } else { + // /user/123/profile/security should be transformed to /user/123/profile + pathRef.current = `/${pathParts.slice(0, pathParts.length - catchAllParams.length).join('/')}`; + return pathRef.current; + } +}; diff --git a/packages/elements/src/react/utils/path-inference/utils.ts b/packages/elements/src/react/utils/path-inference/utils.ts new file mode 100644 index 00000000000..d616c67d28d --- /dev/null +++ b/packages/elements/src/react/utils/path-inference/utils.ts @@ -0,0 +1,3 @@ +export function removeOptionalCatchAllSegment(pathname: string) { + return pathname.replace(/\/\[\[\.\.\..*/, ''); +} From 0455851c168100d1b19dcf7e585836ab87c167f3 Mon Sep 17 00:00:00 2001 From: LekoArts Date: Thu, 6 Jun 2024 14:52:51 +0200 Subject: [PATCH 2/7] app router only --- .../path-inference/__tests__/utils.test.ts | 14 --------- .../src/react/utils/path-inference/next.tsx | 31 +------------------ .../src/react/utils/path-inference/utils.ts | 3 -- 3 files changed, 1 insertion(+), 47 deletions(-) delete mode 100644 packages/elements/src/react/utils/path-inference/__tests__/utils.test.ts delete mode 100644 packages/elements/src/react/utils/path-inference/utils.ts diff --git a/packages/elements/src/react/utils/path-inference/__tests__/utils.test.ts b/packages/elements/src/react/utils/path-inference/__tests__/utils.test.ts deleted file mode 100644 index 9cc92f0a537..00000000000 --- a/packages/elements/src/react/utils/path-inference/__tests__/utils.test.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { removeOptionalCatchAllSegment } from '../utils'; - -describe('removeOptionalCatchAllSegment', () => { - it('should remove optional catch-all segment from the pathname', () => { - const pathname = '/users/[[...slug]].js'; - const expected = '/users'; - expect(removeOptionalCatchAllSegment(pathname)).toEqual(expected); - }); - - it('should not remove anything if there is no optional catch-all segment', () => { - const pathname = '/users/john/profile'; - expect(removeOptionalCatchAllSegment(pathname)).toEqual(pathname); - }); -}); diff --git a/packages/elements/src/react/utils/path-inference/next.tsx b/packages/elements/src/react/utils/path-inference/next.tsx index facafe25ec7..7d2f736b8e2 100644 --- a/packages/elements/src/react/utils/path-inference/next.tsx +++ b/packages/elements/src/react/utils/path-inference/next.tsx @@ -1,39 +1,10 @@ -import { useRouter } from 'next/compat/router'; +import { useParams, usePathname } from 'next/navigation'; import React from 'react'; -import { removeOptionalCatchAllSegment } from './utils'; - // Adapted from packages/nextjs/src/client-boundary/hooks/usePathnameWithoutCatchAll.tsx export const usePathnameWithoutCatchAll = () => { const pathRef = React.useRef(); - - /** - * The compat version of useRouter returns null instead of throwing an error when used inside App router. - * Use it to detect if the component is used inside pages or app router - * TODO: Should we skip this compat layer since in the router we do not use compat? - */ - const pagesRouter = useRouter(); - - if (pagesRouter) { - if (pathRef.current) { - return pathRef.current; - } else { - // The optional catch all route is included in the pathname in pages router. It starts with [[... and we can just remove it - pathRef.current = removeOptionalCatchAllSegment(pagesRouter.pathname); - return pathRef.current; - } - } - - /** - * Require is used to avoid importing next/navigation when the pages router is used, as it will throw an error. - * Can't use dynamic import as the hook needs to be sync - */ - // eslint-disable-next-line @typescript-eslint/no-var-requires - const usePathname = require('next/navigation').usePathname; - // eslint-disable-next-line @typescript-eslint/no-var-requires - const useParams = require('next/navigation').useParams; - /** * Get the pathname that includes any named or catch all params. * @example diff --git a/packages/elements/src/react/utils/path-inference/utils.ts b/packages/elements/src/react/utils/path-inference/utils.ts deleted file mode 100644 index d616c67d28d..00000000000 --- a/packages/elements/src/react/utils/path-inference/utils.ts +++ /dev/null @@ -1,3 +0,0 @@ -export function removeOptionalCatchAllSegment(pathname: string) { - return pathname.replace(/\/\[\[\.\.\..*/, ''); -} From b746b9a7d02e2d0300d5d7a2f283ff2cb5d8c256 Mon Sep 17 00:00:00 2001 From: LekoArts Date: Thu, 6 Jun 2024 15:28:59 +0200 Subject: [PATCH 3/7] add changeset --- .changeset/six-lobsters-happen.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 .changeset/six-lobsters-happen.md diff --git a/.changeset/six-lobsters-happen.md b/.changeset/six-lobsters-happen.md new file mode 100644 index 00000000000..5751b72fbd5 --- /dev/null +++ b/.changeset/six-lobsters-happen.md @@ -0,0 +1,12 @@ +--- +'@clerk/elements': minor +--- + +The `path` prop on the `` and `` component is now automatically inferred. Previously, the default values were `/sign-in` and `/sign-up`, on other routes you had to explicitly define your route. + +The new heuristic for determining the path where `` and `` are mounted is: + +1. `path` prop +2. Automatically inferred +3. If it can't be inferred, fallback to `CLERK_SIGN_IN_URL` and `CLERK_SIGN_UP_URL` env var +4. Fallback to `/sign-in` and `/sign-up` From 866dbe577bba077df0f9268b20a49a911eb729e0 Mon Sep 17 00:00:00 2001 From: LekoArts Date: Wed, 12 Jun 2024 12:54:50 +0200 Subject: [PATCH 4/7] Revert "app router only" This reverts commit 0455851c168100d1b19dcf7e585836ab87c167f3. --- .../path-inference/__tests__/utils.test.ts | 14 +++++++++ .../src/react/utils/path-inference/next.tsx | 31 ++++++++++++++++++- .../src/react/utils/path-inference/utils.ts | 3 ++ 3 files changed, 47 insertions(+), 1 deletion(-) create mode 100644 packages/elements/src/react/utils/path-inference/__tests__/utils.test.ts create mode 100644 packages/elements/src/react/utils/path-inference/utils.ts diff --git a/packages/elements/src/react/utils/path-inference/__tests__/utils.test.ts b/packages/elements/src/react/utils/path-inference/__tests__/utils.test.ts new file mode 100644 index 00000000000..9cc92f0a537 --- /dev/null +++ b/packages/elements/src/react/utils/path-inference/__tests__/utils.test.ts @@ -0,0 +1,14 @@ +import { removeOptionalCatchAllSegment } from '../utils'; + +describe('removeOptionalCatchAllSegment', () => { + it('should remove optional catch-all segment from the pathname', () => { + const pathname = '/users/[[...slug]].js'; + const expected = '/users'; + expect(removeOptionalCatchAllSegment(pathname)).toEqual(expected); + }); + + it('should not remove anything if there is no optional catch-all segment', () => { + const pathname = '/users/john/profile'; + expect(removeOptionalCatchAllSegment(pathname)).toEqual(pathname); + }); +}); diff --git a/packages/elements/src/react/utils/path-inference/next.tsx b/packages/elements/src/react/utils/path-inference/next.tsx index 7d2f736b8e2..facafe25ec7 100644 --- a/packages/elements/src/react/utils/path-inference/next.tsx +++ b/packages/elements/src/react/utils/path-inference/next.tsx @@ -1,10 +1,39 @@ -import { useParams, usePathname } from 'next/navigation'; +import { useRouter } from 'next/compat/router'; import React from 'react'; +import { removeOptionalCatchAllSegment } from './utils'; + // Adapted from packages/nextjs/src/client-boundary/hooks/usePathnameWithoutCatchAll.tsx export const usePathnameWithoutCatchAll = () => { const pathRef = React.useRef(); + + /** + * The compat version of useRouter returns null instead of throwing an error when used inside App router. + * Use it to detect if the component is used inside pages or app router + * TODO: Should we skip this compat layer since in the router we do not use compat? + */ + const pagesRouter = useRouter(); + + if (pagesRouter) { + if (pathRef.current) { + return pathRef.current; + } else { + // The optional catch all route is included in the pathname in pages router. It starts with [[... and we can just remove it + pathRef.current = removeOptionalCatchAllSegment(pagesRouter.pathname); + return pathRef.current; + } + } + + /** + * Require is used to avoid importing next/navigation when the pages router is used, as it will throw an error. + * Can't use dynamic import as the hook needs to be sync + */ + // eslint-disable-next-line @typescript-eslint/no-var-requires + const usePathname = require('next/navigation').usePathname; + // eslint-disable-next-line @typescript-eslint/no-var-requires + const useParams = require('next/navigation').useParams; + /** * Get the pathname that includes any named or catch all params. * @example diff --git a/packages/elements/src/react/utils/path-inference/utils.ts b/packages/elements/src/react/utils/path-inference/utils.ts new file mode 100644 index 00000000000..d616c67d28d --- /dev/null +++ b/packages/elements/src/react/utils/path-inference/utils.ts @@ -0,0 +1,3 @@ +export function removeOptionalCatchAllSegment(pathname: string) { + return pathname.replace(/\/\[\[\.\.\..*/, ''); +} From 717bac8644871ffe4ed65aecaf8a6c7d48420bdc Mon Sep 17 00:00:00 2001 From: LekoArts Date: Wed, 12 Jun 2024 14:15:50 +0200 Subject: [PATCH 5/7] get it working --- .../elements/src/react/utils/path-inference/next.tsx | 11 +---------- packages/elements/tsup.config.ts | 2 +- 2 files changed, 2 insertions(+), 11 deletions(-) diff --git a/packages/elements/src/react/utils/path-inference/next.tsx b/packages/elements/src/react/utils/path-inference/next.tsx index facafe25ec7..3920f58f80d 100644 --- a/packages/elements/src/react/utils/path-inference/next.tsx +++ b/packages/elements/src/react/utils/path-inference/next.tsx @@ -1,4 +1,5 @@ import { useRouter } from 'next/compat/router'; +import { useParams, usePathname } from 'next/navigation'; import React from 'react'; import { removeOptionalCatchAllSegment } from './utils'; @@ -11,7 +12,6 @@ export const usePathnameWithoutCatchAll = () => { /** * The compat version of useRouter returns null instead of throwing an error when used inside App router. * Use it to detect if the component is used inside pages or app router - * TODO: Should we skip this compat layer since in the router we do not use compat? */ const pagesRouter = useRouter(); @@ -25,15 +25,6 @@ export const usePathnameWithoutCatchAll = () => { } } - /** - * Require is used to avoid importing next/navigation when the pages router is used, as it will throw an error. - * Can't use dynamic import as the hook needs to be sync - */ - // eslint-disable-next-line @typescript-eslint/no-var-requires - const usePathname = require('next/navigation').usePathname; - // eslint-disable-next-line @typescript-eslint/no-var-requires - const useParams = require('next/navigation').useParams; - /** * Get the pathname that includes any named or catch all params. * @example diff --git a/packages/elements/tsup.config.ts b/packages/elements/tsup.config.ts index c8cb1e480ad..8a60447c3af 100644 --- a/packages/elements/tsup.config.ts +++ b/packages/elements/tsup.config.ts @@ -21,7 +21,7 @@ export default defineConfig(overrideOptions => { 'react/sign-in/index': 'src/react/sign-in/index.ts', 'react/sign-up/index': 'src/react/sign-up/index.ts', }, - external: ['react', 'react-dom', '@statelyai/inspect'], + external: ['react', 'react-dom', 'next', '@statelyai/inspect'], format: ['cjs', 'esm'], minify: false, sourcemap: true, From d3014e544a831aeebc1c75f1ed62584a339557b1 Mon Sep 17 00:00:00 2001 From: LekoArts Date: Wed, 12 Jun 2024 14:42:50 +0200 Subject: [PATCH 6/7] update comments --- packages/elements/src/react/sign-in/root.tsx | 3 ++- packages/elements/src/react/sign-up/root.tsx | 3 ++- packages/elements/src/react/utils/path-inference/next.tsx | 8 ++++++++ 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/packages/elements/src/react/sign-in/root.tsx b/packages/elements/src/react/sign-in/root.tsx index 7018a4e703d..0139b6d5e69 100644 --- a/packages/elements/src/react/sign-in/root.tsx +++ b/packages/elements/src/react/sign-in/root.tsx @@ -81,8 +81,9 @@ export type SignInRootProps = SignInFlowProviderProps & { * Root component for the sign-in flow. It sets up providers and state management for its children. * Must wrap all sign-in related components. * - * @param {string} path - The root path the sign-in flow is mounted at. Default: `/sign-in` + * @param {string} path - The root path the sign-in flow is mounted at. Will be automatically inferred in Next.js. You can set it to `/sign-in` for example. * @param {React.ReactNode} fallback - Fallback markup to render while Clerk is loading. Default: `null` + * @param {boolean} routing - If you want to render Clerk Elements in e.g. a modal, use the `virtual` routing mode. * * @example * import * as SignIn from "@clerk/elements/sign-in" diff --git a/packages/elements/src/react/sign-up/root.tsx b/packages/elements/src/react/sign-up/root.tsx index cd4b129fc2e..e6080b20b06 100644 --- a/packages/elements/src/react/sign-up/root.tsx +++ b/packages/elements/src/react/sign-up/root.tsx @@ -82,8 +82,9 @@ export type SignUpRootProps = SignUpFlowProviderProps & { * Root component for the sign-up flow. It sets up providers and state management for its children. * Must wrap all sign-up related components. * - * @param {string} path - The root path the sign-up flow is mounted at. Default: `/sign-up` + * @param {string} path - The root path the sign-up flow is mounted at. Will be automatically inferred in Next.js. You can set it to `/sign-up` for example. * @param {React.ReactNode} fallback - Fallback markup to render while Clerk is loading. Default: `null` + * @param {boolean} routing - If you want to render Clerk Elements in e.g. a modal, use the `virtual` routing mode. * * @example * import * as SignUp from "@clerk/elements/sign-up" diff --git a/packages/elements/src/react/utils/path-inference/next.tsx b/packages/elements/src/react/utils/path-inference/next.tsx index 3920f58f80d..43083fabbb4 100644 --- a/packages/elements/src/react/utils/path-inference/next.tsx +++ b/packages/elements/src/react/utils/path-inference/next.tsx @@ -6,6 +6,14 @@ import { removeOptionalCatchAllSegment } from './utils'; // Adapted from packages/nextjs/src/client-boundary/hooks/usePathnameWithoutCatchAll.tsx +/** + * This hook grabs the current pathname (both in pages and app router) and removes any (optional) catch all segments. + * @example + * 1. /user/[id]/profile/[[...rest]]/page.tsx + * 2. /user/123/profile/security + * 3. /user/123/profile + * @returns The pathname without any catch all segments + */ export const usePathnameWithoutCatchAll = () => { const pathRef = React.useRef(); From eb033eab02288478a08de9927fe3fb46ef56026d Mon Sep 17 00:00:00 2001 From: LekoArts Date: Thu, 13 Jun 2024 10:59:40 +0200 Subject: [PATCH 7/7] fix typo --- packages/elements/src/react/sign-in/root.tsx | 2 +- packages/elements/src/react/sign-up/root.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/elements/src/react/sign-in/root.tsx b/packages/elements/src/react/sign-in/root.tsx index f2f04b094fd..82d860ab2e7 100644 --- a/packages/elements/src/react/sign-in/root.tsx +++ b/packages/elements/src/react/sign-in/root.tsx @@ -85,7 +85,7 @@ export type SignInRootProps = SignInFlowProviderProps & { * * @param {string} path - The root path the sign-in flow is mounted at. Will be automatically inferred in Next.js. You can set it to `/sign-in` for example. * @param {React.ReactNode} fallback - Fallback markup to render while Clerk is loading. Default: `null` - * @param {boolean} routing - If you want to render Clerk Elements in e.g. a modal, use the `virtual` routing mode. + * @param {string} routing - If you want to render Clerk Elements in e.g. a modal, use the `'virtual'` routing mode. Default: `'path'` * * @example * import * as SignIn from "@clerk/elements/sign-in" diff --git a/packages/elements/src/react/sign-up/root.tsx b/packages/elements/src/react/sign-up/root.tsx index 18818ede610..4ce7f86526a 100644 --- a/packages/elements/src/react/sign-up/root.tsx +++ b/packages/elements/src/react/sign-up/root.tsx @@ -86,7 +86,7 @@ export type SignUpRootProps = SignUpFlowProviderProps & { * * @param {string} path - The root path the sign-up flow is mounted at. Will be automatically inferred in Next.js. You can set it to `/sign-up` for example. * @param {React.ReactNode} fallback - Fallback markup to render while Clerk is loading. Default: `null` - * @param {boolean} routing - If you want to render Clerk Elements in e.g. a modal, use the `virtual` routing mode. + * @param {string} routing - If you want to render Clerk Elements in e.g. a modal, use the `'virtual'` routing mode. Default: `'path'` * * @example * import * as SignUp from "@clerk/elements/sign-up"