# Unity navigation patterns

### Raw and integration map

| Base entry (`@payfit/unity-components`) | Integration (`@payfit/unity-components/integrations/tanstack-router`) | Prop                                    |
| --------------------------------------- | --------------------------------------------------------------------- | --------------------------------------- |
| `RawLink`                               | `Link`                                                                | `href` (raw) / `to` (integration)       |
| `RawNavItem`                            | `NavItem`                                                             | same                                    |
| `RawBreadcrumbLink`                     | `BreadcrumbLink`                                                      | same                                    |
| `RawPaginationLink`                     | `PaginationLink`                                                      | same                                    |
| `RawTab` (+ `Tabs`)                     | `Tab` (+ `Tabs`)                                                      | route-aware `to` selects the active tab |
| `RawLinkButton`                         | `LinkButton`                                                          | same                                    |

The integration components are produced via `createLink(RawLink)`. They render
exactly the same DOM as the raw versions but accept Tanstack's typed `to`,
`params`, `search`, and `preload` props.

### Compose Breadcrumbs / Pagination / Tabs

Each navigation composite has a strict child contract. Direct children of the
container must be the wrapper part — loose children are silently filtered.

```tsx
import {
  Breadcrumb,
  BreadcrumbLink,
  Breadcrumbs,
  Pagination,
  PaginationContent,
  PaginationItem,
  RawPaginationLink,
  RawTab,
  TabList,
  TabPanel,
  Tabs,
} from '@payfit/unity-components'

export function CompositionExamples({
  page,
  pageCount,
  onPageChange,
}: {
  page: number
  pageCount: number
  onPageChange: (next: number, prev: number, dir: -1 | 1) => void
}) {
  return (
    <>
      <Breadcrumbs>
        <Breadcrumb>
          <BreadcrumbLink href="/">Home</BreadcrumbLink>
        </Breadcrumb>
        <Breadcrumb>
          <BreadcrumbLink href="/employees">Employees</BreadcrumbLink>
        </Breadcrumb>
      </Breadcrumbs>

      <Pagination
        currentPage={page}
        pageCount={pageCount}
        onPageChange={onPageChange}
      >
        <PaginationContent>
          {Array.from({ length: pageCount }, (_, i) => i + 1).map(n => (
            <PaginationItem key={n}>
              <RawPaginationLink value={n} isActive={n === page}>
                {n}
              </RawPaginationLink>
            </PaginationItem>
          ))}
        </PaginationContent>
      </Pagination>

      <Tabs>
        <TabList>
          <RawTab id="active">Active</RawTab>
          <RawTab id="archived">Archived</RawTab>
        </TabList>
        <TabPanel id="active">Active rows</TabPanel>
        <TabPanel id="archived">Archived rows</TabPanel>
      </Tabs>
    </>
  )
}
```

### RouterProvider for Raw\* in non-Tanstack apps

When you use `Raw*` components in an app that uses a different router (e.g.
React Router), wrap the app once in `RouterProvider` so `isActive` and
client-side navigation work. The Tanstack integration entry does NOT need
this — it reads from Tanstack hooks directly.

```tsx
import { RouterProvider } from '@payfit/unity-components'
import { matchPath, useLocation, useNavigate } from 'react-router-dom'

export function UnityRouterBridge({ children }: { children: React.ReactNode }) {
  const navigate = useNavigate()
  const location = useLocation()

  return (
    <RouterProvider
      navigate={to => navigate(to)}
      isActive={(to, isExact) =>
        Boolean(
          matchPath({ path: to, end: Boolean(isExact) }, location.pathname),
        )
      }
    >
      {children}
    </RouterProvider>
  )
}
```
