From 9e6b769fb770c1f2fb01910d72c65431c3197b62 Mon Sep 17 00:00:00 2001 From: Tobbe Lundberg Date: Fri, 13 Dec 2024 21:37:45 +0100 Subject: [PATCH] feat(router): Better autocomplete for ``s (#11769) --- .changesets/11769.md | 3 ++ packages/router/src/Set.tsx | 75 ++++++++++++++++++++++++------------- 2 files changed, 53 insertions(+), 25 deletions(-) create mode 100644 .changesets/11769.md diff --git a/.changesets/11769.md b/.changesets/11769.md new file mode 100644 index 000000000000..13720912a477 --- /dev/null +++ b/.changesets/11769.md @@ -0,0 +1,3 @@ +- feat(router): Better autocomplete for ``s (#11769) by @Tobbe + +There's a limit to 10 wrapper components. After that additional props will not be included. To work around this you can either make sure to put wrapper components that doesn't require any props last, or just split your wrappers between multiple ``s diff --git a/packages/router/src/Set.tsx b/packages/router/src/Set.tsx index 98403546a7f7..80b66c284d4e 100644 --- a/packages/router/src/Set.tsx +++ b/packages/router/src/Set.tsx @@ -3,12 +3,7 @@ import React from 'react' import type { AvailableRoutes } from '@redwoodjs/router' -type SetProps

= (P extends React.FC ? React.ComponentProps

: unknown) & { - /** - * A react component that the children of the Set will be wrapped - * in (typically a Layout component) - */ - wrap?: P +type RegularSetProps = { /** *`Routes` nested in a `` with `private` specified require * authentication. When a user is not authenticated and attempts to visit @@ -23,6 +18,38 @@ type SetProps

= (P extends React.FC ? React.ComponentProps

: unknown) & { * @deprecated Please use `` instead and specify this prop there */ unauthenticated?: keyof AvailableRoutes +} + +/** + * A set containing public ``s + */ +export function Set( + props: CommonSetProps & RegularSetProps, +) { + // @MARK: Virtual Component, this is actually never rendered + // See analyzeRoutes in utils.tsx, inside the isSetNode block + return <>{props.children} +} + +type CommonSetProps

= (P extends React.FC + ? React.ComponentProps

+ : P extends React.FC[] + ? React.ComponentProps & + React.ComponentProps & + React.ComponentProps & + React.ComponentProps & + React.ComponentProps & + React.ComponentProps & + React.ComponentProps & + React.ComponentProps & + React.ComponentProps & + React.ComponentProps + : unknown) & { + /** + * A React component, or an array of React components, that the children of + * the Set will be wrapped in (typically a Layout component and/or a context) + */ + wrap?: P /** * Route is permitted when authenticated and user has any of the provided * roles such as "admin" or ["admin", "editor"] @@ -36,22 +63,13 @@ type SetProps

= (P extends React.FC ? React.ComponentProps

: unknown) & { whileLoadingPage?: () => ReactElement | null } -/** - * A set containing public ``s - */ -export function Set(props: SetProps) { - // @MARK: Virtual Component, this is actually never rendered - // See analyzeRoutes in utils.tsx, inside the isSetNode block - return <>{props.children} -} - -type PrivateSetProps

= Omit, 'private' | 'unauthenticated'> & { - /** The page name where a user will be redirected when not authenticated */ - unauthenticated: keyof AvailableRoutes -} - /** @deprecated Please use `` instead */ -export function Private(props: PrivateSetProps) { +export function Private( + props: CommonSetProps & { + /** The page name where a user will be redirected when not authenticated */ + unauthenticated: keyof AvailableRoutes + }, +) { // @MARK Virtual Component, this is actually never rendered // See analyzeRoutes in utils.tsx, inside the isSetNode block return <>{props.children} @@ -60,7 +78,12 @@ export function Private(props: PrivateSetProps) { /** * A set containing private ``s that require authentication to access */ -export function PrivateSet(props: PrivateSetProps) { +export function PrivateSet( + props: CommonSetProps & { + /** The page name where a user will be redirected when not authenticated */ + unauthenticated: keyof AvailableRoutes + }, +) { // @MARK Virtual Component, this is actually never rendered // See analyzeRoutes in utils.tsx, inside the isSetNode block return <>{props.children} @@ -68,7 +91,7 @@ export function PrivateSet(props: PrivateSetProps) { export const isSetNode = ( node: ReactNode, -): node is ReactElement> => { +): node is ReactElement & RegularSetProps> => { return ( React.isValidElement(node) && (node.type === Set || node.type === PrivateSet || node.type === Private) && @@ -79,13 +102,15 @@ export const isSetNode = ( export const isPrivateSetNode = ( node: ReactNode, -): node is ReactElement> => { +): node is ReactElement< + CommonSetProps & { unauthenticated: keyof AvailableRoutes } +> => { return React.isValidElement(node) && node.type === PrivateSet } // Only identifies nodes, not nodes export const isPrivateNode = ( node: ReactNode, -): node is ReactElement> => { +): node is ReactElement & RegularSetProps> => { return React.isValidElement(node) && node.type === Private }