Skip to content

Commit

Permalink
Fix Set wrapper type so you can have an array of wrappers
Browse files Browse the repository at this point in the history
  • Loading branch information
Tobbe committed Oct 18, 2023
1 parent fca02b6 commit 6057ed5
Show file tree
Hide file tree
Showing 2 changed files with 32 additions and 24 deletions.
43 changes: 24 additions & 19 deletions packages/router/src/Set.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,19 @@
import type { ReactElement, ReactNode } from 'react'
import * as React from 'react'
import React from 'react'

export type WrapperType<WTProps> = (
props: WTProps & { children: ReactNode }
props: Omit<WTProps, 'wrap' | 'children'> & {
children: ReactNode
}
) => ReactElement | null

type SetProps<P> = P & {
// P is the interface for the props that are forwarded to the wrapper
// components. TypeScript will most likely infer this for you, but if you
// need to you can specify it yourself in your JSX like so:
// <Set<{theme: string}> wrap={ThemeableLayout} theme="dark">
/**
* P is the interface for the props that are forwarded to the wrapper
* components. TypeScript will most likely infer this for you, but if you
* need to you can specify it yourself in your JSX like so:
* <Set<{theme: string}> wrap={ThemableLayout} theme="dark">
*/
wrap?: WrapperType<P> | WrapperType<P>[]
/**
*`Routes` nested in a `<Set>` with `private` specified require
Expand All @@ -19,19 +23,23 @@ type SetProps<P> = P & {
* @deprecated Please use `<PrivateSet>` instead
*/
private?: boolean
/** The page name where a user will be redirected when not authenticated */
/**
* The page name where a user will be redirected when not authenticated
*
* @deprecated Please use `<PrivateSet>` instead and specify this prop there
*/
unauthenticated?: string
/**
* Route is permitted when authenticated and use has any of the provided
* Route is permitted when authenticated and user has any of the provided
* roles such as "admin" or ["admin", "editor"]
*/
roles?: string | string[]
/** Prerender all pages in the set */
prerender?: boolean
children: ReactNode
/** Loading state for auth to distinguish with whileLoading */
whileLoadingAuth?: () => React.ReactElement | null
whileLoadingPage?: () => React.ReactElement | null
whileLoadingAuth?: () => ReactElement | null
whileLoadingPage?: () => ReactElement | null
}

/**
Expand All @@ -40,11 +48,10 @@ type SetProps<P> = P & {
* JSX like so:
* <Set<{theme: string}> wrap={ThemeableLayout} theme="dark">
*/
export function Set<WrapperProps>(_props: SetProps<WrapperProps>) {
export function Set<WrapperProps>(props: SetProps<WrapperProps>) {
// @MARK: Virtual Component, this is actually never rendered
// See analyzeRoutes in utils.tsx, inside the isSetNode block

return null
return <>{props.children}</>
}

type PrivateSetProps<P> = Omit<
Expand All @@ -57,18 +64,16 @@ type PrivateSetProps<P> = Omit<
}

/** @deprecated Please use `<PrivateSet>` instead */
export function Private<WrapperProps>(_props: PrivateSetProps<WrapperProps>) {
export function Private<WrapperProps>(props: PrivateSetProps<WrapperProps>) {
// @MARK Virtual Component, this is actually never rendered
// See analyzeRoutes in utils.tsx, inside the isSetNode block
return null
return <>{props.children}</>
}

export function PrivateSet<WrapperProps>(
_props: PrivateSetProps<WrapperProps>
) {
export function PrivateSet<WrapperProps>(props: PrivateSetProps<WrapperProps>) {
// @MARK Virtual Component, this is actually never rendered
// See analyzeRoutes in utils.tsx, inside the isSetNode block
return null
return <>{props.children}</>
}

export const isSetNode = (
Expand Down
13 changes: 8 additions & 5 deletions packages/router/src/__tests__/set.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,14 @@ import { Set } from '../Set'
const ChildA = () => <h1>ChildA</h1>
const ChildB = () => <h1>ChildB</h1>
const ChildC = () => <h1>ChildC</h1>
const GlobalLayout: React.FC<{ children?: ReactNode }> = ({ children }) => (
const GlobalLayout = ({ children }: { children: ReactNode }) => (
<div>
<h1>Global Layout</h1>
{children}
<footer>This is a footer</footer>
</div>
)
const CustomWrapper: React.FC<{ children?: ReactNode }> = ({ children }) => (
const CustomWrapper = ({ children }: { children: ReactNode }) => (
<div>
<h1>Custom Wrapper</h1>
{children}
Expand Down Expand Up @@ -89,20 +89,23 @@ test('passes props to wrappers', async () => {
interface Props {
propOne: string
propTwo: string
children?: ReactNode
children: ReactNode
}

const PropWrapper: React.FC<Props> = ({ children, propOne, propTwo }) => (
const PropWrapper = ({ children, propOne, propTwo }: Props) => (
<div>
<h1>Prop Wrapper</h1>
<p>1:{propOne}</p>
<p>2:{propTwo}</p>
{children}
</div>
)

const PropWrapperTwo = ({ children }: Props) => <div>{children}</div>

const TestSet = () => (
<Router>
<Set wrap={[PropWrapper, GlobalLayout]} propOne="une" propTwo="deux">
<Set wrap={[PropWrapper, PropWrapperTwo]} propOne="une" propTwo="deux">
<Route path="/" page={ChildA} name="childA" />
</Set>
</Router>
Expand Down

0 comments on commit 6057ed5

Please sign in to comment.