feat(page): add composable page primitives
This commit is contained in:
@@ -0,0 +1,71 @@
|
||||
---
|
||||
title: Title portals
|
||||
description: Mount page titles into an application shell while retaining an SSR fallback.
|
||||
order: 20
|
||||
toc:
|
||||
- id: info-resolver
|
||||
title: Page information resolver
|
||||
- id: managed-target
|
||||
title: Managed title target
|
||||
- id: fallback
|
||||
title: Fallback
|
||||
- id: nested-managers
|
||||
title: Nested managers
|
||||
---
|
||||
|
||||
## Page information resolver {#info-resolver}
|
||||
|
||||
`PagesManager.getPageInfo` connects route or layout metadata to page components. It receives the optional `Partial<PageInfo>` from `PageContainer` and returns a normalized `PageInfo`, or `undefined` when no managed information is available:
|
||||
|
||||
```tsx
|
||||
<PagesManager
|
||||
getPageInfo={(info) => ({
|
||||
breadcrumb: info?.breadcrumb ?? routeMetadata.breadcrumb,
|
||||
description: info?.description ?? routeMetadata.description,
|
||||
subtitle: info?.subtitle ?? routeMetadata.subtitle,
|
||||
title: info?.title ?? routeMetadata.title,
|
||||
})}
|
||||
>
|
||||
<Outlet />
|
||||
</PagesManager>
|
||||
```
|
||||
|
||||
If the resolver returns `undefined`, `PageContainer` still merges its local partial information with inherited page information.
|
||||
|
||||
## Managed title target {#managed-target}
|
||||
|
||||
A layout can give `PagesManager` a DOM container while a page places its title in the external Header through `PageTitlePortal`:
|
||||
|
||||
```tsx
|
||||
function ApplicationLayout() {
|
||||
const [titleContainer, setTitleContainer] =
|
||||
React.useState<HTMLElement | null>(null)
|
||||
|
||||
return (
|
||||
<PagesManager titleContainer={titleContainer}>
|
||||
<header>
|
||||
<div ref={setTitleContainer} />
|
||||
</header>
|
||||
<Outlet />
|
||||
</PagesManager>
|
||||
)
|
||||
}
|
||||
|
||||
function ProductsPage() {
|
||||
return (
|
||||
<PageTitlePortal>
|
||||
<PageTitle>Products</PageTitle>
|
||||
</PageTitlePortal>
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
`titleContainer` accepts an `Element` or `DocumentFragment`. A `PageTitlePortal` may override the manager with its own `container` prop.
|
||||
|
||||
## Fallback {#fallback}
|
||||
|
||||
Without an available target, the Portal renders `children` in place by default, so server rendering and the first client render retain the page title. Supply `fallback` to replace the inline content, including `null` to hide it.
|
||||
|
||||
## Nested managers {#nested-managers}
|
||||
|
||||
A nested `PagesManager` inherits its parent's `getPageInfo` and title target when they are omitted. Pass `null` as `titleContainer` explicitly to stop title-target inheritance and keep titles in that subtree inline.
|
||||
Reference in New Issue
Block a user