@payfit/unity-components 2.35.4 → 2.35.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,180 @@
1
+ # Midnight → Unity component map
2
+
3
+ Exhaustive map of every public `@payfit/midnight` export to its
4
+ `@payfit/unity-components`, `@payfit/unity-icons`, `@payfit/unity-themes`
5
+ or `@payfit/unity-illustrations` counterpart.
6
+
7
+ **How to use this map**
8
+
9
+ - Find the Midnight component you're porting in the left column.
10
+ - The middle column is the Unity replacement (or `—` if none exists).
11
+ - The right column is a one-line note: composition pattern, behavior
12
+ delta, or "no equivalent" reason. Prop renames, the disabled-tooltip
13
+ rule, and full a11y deltas live in `../SKILL.md` — don't repeat them
14
+ per row.
15
+
16
+ If a row says **no equivalent**, accept the gap. Do not invent a Unity
17
+ component, do not reach for an external library unless explicitly
18
+ allowed (see `VirtualizedList`), and do not style a non-link element to
19
+ look like a link.
20
+
21
+ > Cross-package targets: `Icon` lives in `@payfit/unity-icons`;
22
+ > `Illustration` and `LazyIllustration` live in
23
+ > `@payfit/unity-illustrations`; `UnityThemeProvider` lives in
24
+ > `@payfit/unity-themes`. Everything else is `@payfit/unity-components`.
25
+
26
+ ## Layout & containers
27
+
28
+ | Midnight | Unity | Note |
29
+ | --------------- | -------------------------- | --------------------------------------------------------------------- |
30
+ | `Box` | `Flex` (1D) / `Grid` (2D) | No 1:1; pick `Flex` with `direction`/`gap`/`align`, `Grid` for 2D |
31
+ | `CalloutCard` | `Card` | Deprecated in Midnight; compose with `Card` + `Text` + icon/action |
32
+ | `Card` | `Card` | Use `shadow` and `bgColor` props for the visual variants |
33
+ | `CardContainer` | `Card` | Card with `asChild` + `RawLink` (or `Link`) for interactive cards |
34
+ | `Column` | `Flex direction="column"` | — |
35
+ | `DataCard` | `Card` + `Text` (composed) | No direct equivalent; compose label/value/action from primitives |
36
+ | `Grid` | `Grid` | — |
37
+ | `Layout` | `Flex` | Internal Midnight primitive; pick `Flex` (or `Grid`) at the call site |
38
+ | `Row` | `Flex direction="row"` | — |
39
+ | `Scrollable` | `Flex` + overflow utility | Compose with `uy:overflow-auto`/`uy:overflow-y-auto` classes |
40
+ | `Section` | `Flex asElement="section"` | Add `Text variant="h*"` for the heading |
41
+
42
+ ## Typography
43
+
44
+ | Midnight | Unity | Note |
45
+ | ---------- | ------------------------- | ------------------------------------------------------------------------- |
46
+ | `Code` | native `<code>` | No Unity equivalent; use the native element |
47
+ | `Heading` | `Text variant="heading*"` | No dedicated `Heading`; typography is a `Text` variant |
48
+ | `LinkText` | `Link` | Use `Link` directly — links must look like links |
49
+ | `Markdown` | — | No equivalent; do not pull in an external library unless explicitly asked |
50
+ | `Text` | `Text` | Prop shape differs (`size`/`variation` → `variant`); see Unity docs |
51
+
52
+ ## Buttons & actions
53
+
54
+ | Midnight | Unity | Note |
55
+ | --------------- | ------------------------ | --------------------------------------------------------------- |
56
+ | `Actionable` | `Actionable` | `onAction` → `onPress` |
57
+ | `Button` | `Button` | |
58
+ | `IconButton` | `IconButton` | `CircularIconButton` for the round variant |
59
+ | `Link` | `RawLink` / `Link` | Router-agnostic `RawLink`; router-aware `Link` from integration |
60
+ | `Linkable` | `RawLink` | Internal Midnight; use `RawLink` directly |
61
+ | `MinimalButton` | `Button variant="ghost"` | — |
62
+ | `Navigable` | `RawLink` | Internal Midnight; use `RawLink` (or router-aware `Link`) |
63
+ | `SubmitButton` | `Button type="submit"` | No dedicated submit button |
64
+
65
+ ## Form structure
66
+
67
+ | Midnight | Unity | Note |
68
+ | ---------- | ----------- | ---------------------------------------------------------------- |
69
+ | `Field` | `FormField` | Wrapper with `FormLabel` / `FormHelperText` / `FormFeedbackText` |
70
+ | `FieldSet` | `Fieldset` | Casing change (`FieldSet` → `Fieldset`) |
71
+ | `Form` | `Form` | Pair with `useTanstackUnityForm` — see `unity-tanstack-form` |
72
+
73
+ ## Form inputs
74
+
75
+ > Form-bound usage is via Tanstack form (`useTanstackUnityForm`), where
76
+ > Unity components are exposed as `<field.*>` after wiring the form
77
+ > hook. Top-level `*Field` exports use the deprecated RHF binding and
78
+ > will be removed — see `unity-tanstack-form` for the supported path.
79
+ > The "Unity" column below names the component; how to bind it lives in
80
+ > that skill.
81
+
82
+ | Midnight | Unity | Note |
83
+ | ------------------ | ------------------------------------------------------------ | -------------------------------------------------------------------------------------- |
84
+ | `Checkbox` | `Checkbox` / `CheckboxField` | `CheckboxField` is the form organism |
85
+ | `CheckboxGroup` | `CheckboxGroup` / `CheckboxGroupField` | — |
86
+ | `DatePickerField` | `DatePicker` / `DatePickerField` | Range: `DateRangePicker` standalone or `<field.DateRangePickerField>` in Tanstack form |
87
+ | `Dropzone` | — | No equivalent |
88
+ | `MultiSelectField` | `MultiSelect` / `MultiSelectField` | — |
89
+ | `MultiUploadField` | — | No equivalent |
90
+ | `PasswordField` | `PasswordField` | Tanstack-form-bound only — accessed via `<field.PasswordField>` |
91
+ | `RadioGroup` | `RadioButtonGroup` + `RadioButton` / `RadioButtonGroupField` | Multi-card layout: `SelectableCardRadioGroupField` |
92
+ | `SearchField` | `Search` | `Input type="search"` as a non-styled fallback |
93
+ | `SelectField` | `Select` / `SelectField` | — |
94
+ | `Slider` | — | No equivalent |
95
+ | `Switch` | `ToggleSwitch` / `ToggleSwitchField` | — |
96
+ | `TextAreaField` | `TextArea` | No dedicated `TextAreaField` organism; compose with `FormField` |
97
+ | `TextField` | `Input` / `TextField` | `Input` standalone; `TextField` is the form organism |
98
+ | `UploadField` | — | No equivalent |
99
+
100
+ ## Overlays & dialogs
101
+
102
+ | Midnight | Unity | Note |
103
+ | -------------- | -------------------------------------------- | ------------------------------------------------------------------------------ |
104
+ | `Banner` | `Alert` | `variation` → `variant` (info/warning/success/danger/insight) |
105
+ | `ConfirmModal` | `Dialog` + `DialogContent` + `DialogActions` | Deprecated in Midnight; compose explicitly |
106
+ | `ContentModal` | `Dialog` | Deprecated in Midnight |
107
+ | `DropdownMenu` | `Menu` | Trigger + content composition |
108
+ | `FormModal` | `Dialog` | Deprecated in Midnight; submit via the inner `Form` |
109
+ | `Modal` | `Dialog` | Use `PromoDialog` for marketing dialogs |
110
+ | `Popover` | `Popover` | Unity exposes `title` / `displayCloseButton` |
111
+ | `Toast` | `ToastManager` + `toast()` | Mount `ToastManager` at root; call `toast(...)` from anywhere |
112
+ | `Tooltip` | `Tooltip` | Unity refuses to render on a disabled control — see SKILL.md "Common Mistakes" |
113
+
114
+ ## Navigation
115
+
116
+ | Midnight | Unity | Note |
117
+ | ------------------- | ----------------------- | -------------------------------------------------- |
118
+ | `Pagination` | `Pagination` | Pair with `DataTable` for table-bound paging |
119
+ | `PrimaryNavigation` | `AppMenu` + `AppLayout` | Compose `AppMenu` inside `AppLayout`'s `menu` slot |
120
+ | `Tabs` | `Tabs` | — |
121
+
122
+ ## Data display
123
+
124
+ | Midnight | Unity | Note |
125
+ | ----------------- | --------------------------- | ---------------------------------------------------------------------------------------------- |
126
+ | `Badge` | `Badge` | `color` → `variant` (success/warning/danger/neutral/promo/attention/contextual/numeric) |
127
+ | `ExpandableTable` | `DataTable` (row-expansion) | Add an expansion column via TanStack Table's row-expansion API |
128
+ | `Pill` | `Pill` | Unity `Pill` is numeric-only and has fewer colors; intent is the same (small inline indicator) |
129
+ | `SelectableTable` | `DataTable` (row-selection) | Add a selection column via TanStack Table's row-selection API |
130
+ | `Table` | `Table` / `DataTable` | `Table` for layout-only; `DataTable` for sorting/filter/pagination via TanStack Table |
131
+ | `Tag` | — | No equivalent (dismissible chip; Unity `Badge` is non-dismissible) |
132
+ | `VirtualizedList` | `ListView` | Fallback to `@tanstack/virtual` directly only if the design genuinely cannot fit `ListView` |
133
+
134
+ ## Feedback & status
135
+
136
+ | Midnight | Unity | Note |
137
+ | -------------------- | ---------------------------- | --------------------------------------------------------- |
138
+ | `EmptyState` | `EmptyState` | Unity ships `EmptyState*` presets (NoSearchResults, etc.) |
139
+ | `Loader` | `Spinner` / `FullPageLoader` | `Spinner` for inline; `FullPageLoader` for full-screen |
140
+ | `ObfuscatedContent` | — | No equivalent |
141
+ | `ObfuscatedDataCard` | — | No equivalent |
142
+ | `ObfuscatedText` | — | No equivalent |
143
+
144
+ ## Media
145
+
146
+ | Midnight | Unity | Note |
147
+ | -------------- | ------------------------------------------------------------------- | ----------------------------------------------------------------------- |
148
+ | `Avatar` | `Avatar` | `type` → `variant` (circle/square) |
149
+ | `AvatarGroup` | — | No equivalent (planned) |
150
+ | `Icon` | `Icon` (`@payfit/unity-icons`) | Pass typed `src: UnityIcon` string literal — do not cast `as UnityIcon` |
151
+ | `Illustration` | `Illustration` / `LazyIllustration` (`@payfit/unity-illustrations`) | `LazyIllustration` for animated assets |
152
+ | `Image` | native `<img>` | No Unity equivalent |
153
+ | `Svg` | native `<svg>` (or `Icon` if it's an icon) | No Unity equivalent for arbitrary SVGs |
154
+
155
+ ## Misc
156
+
157
+ | Midnight | Unity | Note |
158
+ | ------------------ | --------------------------------------------- | ------------------------------------------------------------------- |
159
+ | `Accordion` | `Collapsible` | Unity `Collapsible` is single-item; no multi-item accordion |
160
+ | `MidnightProvider` | `UnityThemeProvider` (`@payfit/unity-themes`) | Mount once at app root |
161
+ | `Overlay` | — | Internal Midnight primitive; use `Dialog`/`Popover`/`Menu` directly |
162
+ | `Transition` | `uy:transition-*` / `uy:duration-*` classes | No JS helper; use TailwindCSS utilities |
163
+
164
+ ## v2 components
165
+
166
+ Midnight v2 was a transitional API. Most v2 components map 1:1 to a
167
+ Unity primitive.
168
+
169
+ | Midnight v2 | Unity | Note |
170
+ | ----------------- | ------------------------------------------------------------------- | ------------------------------------------------------------- |
171
+ | `v2/AsyncImage` | native `<img>` | No Unity equivalent |
172
+ | `v2/Avatar` | `Avatar` | — |
173
+ | `v2/Box` | `Flex` / `Grid` | Same guidance as v1 `Box` |
174
+ | `v2/Flex` | `Flex` | Drop the `v2/` namespace; same props |
175
+ | `v2/Grid` | `Grid` | Drop the `v2/` namespace |
176
+ | `v2/Icon` | `Icon` (`@payfit/unity-icons`) | Same target as v1 `Icon` |
177
+ | `v2/Illustration` | `Illustration` / `LazyIllustration` (`@payfit/unity-illustrations`) | Same target as v1 `Illustration` |
178
+ | `v2/Image` | native `<img>` | — |
179
+ | `v2/PageLayout` | `AppLayout` / `Page` | `AppLayout` for the app shell; `Page` for the content surface |
180
+ | `v2/Stack` | `Flex` (with `direction` + `gap`) | — |
@@ -0,0 +1,331 @@
1
+ ---
2
+ name: unity-navigation
3
+ description: >
4
+ Pick between router-agnostic Raw* components (RawLink, RawNavItem,
5
+ RawBreadcrumbLink, RawPaginationLink, RawTab) in the @payfit/unity-components
6
+ base entry and router-aware components (Link, NavItem, BreadcrumbLink,
7
+ PaginationLink, Tabs) in @payfit/unity-components/integrations/tanstack-router.
8
+ Compositional patterns: Breadcrumbs > Breadcrumb > BreadcrumbLink;
9
+ Pagination > PaginationContent > PaginationItem > RawPaginationLink;
10
+ Tabs > TabList > RawTab + TabPanel. RouterProvider is needed for Raw*
11
+ components in non-Tanstack apps; the tanstack-router integration uses
12
+ Tanstack hooks directly. The v1 monolithic Pagination no longer exists
13
+ publicly — ClientSidePagination is now internal to DataTable only.
14
+ type: core
15
+ library: '@payfit/unity-components'
16
+ library_version: '2.x'
17
+ sources:
18
+ - 'PayFit/hr-apps:libs/shared/unity/components/src/components/link/RawLink.tsx'
19
+ - 'PayFit/hr-apps:libs/shared/unity/components/src/components/breadcrumbs/Breadcrumbs.tsx'
20
+ - 'PayFit/hr-apps:libs/shared/unity/components/src/components/pagination/Pagination.tsx'
21
+ - 'PayFit/hr-apps:libs/shared/unity/components/src/components/tabs/Tabs.tsx'
22
+ - 'PayFit/hr-apps:libs/shared/unity/components/src/integrations/tanstack-router/index.ts'
23
+ - 'PayFit/hr-apps:libs/shared/unity/components/src/providers/router/RouterProvider.tsx'
24
+ - 'PayFit/hr-apps:libs/shared/unity/components/src/docs/concepts/navigation/Navigation Patterns Explained.mdx'
25
+ ---
26
+
27
+ Two entry points expose the same components in two flavors. The base entry
28
+ (`@payfit/unity-components`) ships router-agnostic `Raw*` primitives that take
29
+ a plain `href`. The Tanstack integration entry
30
+ (`@payfit/unity-components/integrations/tanstack-router`) ships type-safe
31
+ counterparts that take `to` and are wired via `createLink` from
32
+ `@tanstack/react-router`.
33
+
34
+ ## Setup
35
+
36
+ In a Tanstack Router feature plugin, import every link/nav component from the
37
+ integration entry. No `RouterProvider` is required — the integration uses
38
+ Tanstack hooks directly.
39
+
40
+ ```tsx
41
+ import {
42
+ Breadcrumb,
43
+ BreadcrumbLink,
44
+ Breadcrumbs,
45
+ Link,
46
+ Tab,
47
+ TabList,
48
+ TabPanel,
49
+ Tabs,
50
+ } from '@payfit/unity-components/integrations/tanstack-router'
51
+ import { Outlet } from '@tanstack/react-router'
52
+
53
+ export function EmployeesShell() {
54
+ return (
55
+ <>
56
+ <Breadcrumbs>
57
+ <Breadcrumb>
58
+ <BreadcrumbLink to="/">Home</BreadcrumbLink>
59
+ </Breadcrumb>
60
+ <Breadcrumb>
61
+ <BreadcrumbLink to="/employees">Employees</BreadcrumbLink>
62
+ </Breadcrumb>
63
+ </Breadcrumbs>
64
+
65
+ <Tabs>
66
+ <TabList>
67
+ <Tab to="/employees/active">Active</Tab>
68
+ <Tab to="/employees/archived">Archived</Tab>
69
+ </TabList>
70
+ <TabPanel>
71
+ <Outlet />
72
+ </TabPanel>
73
+ </Tabs>
74
+
75
+ <Link to="/employees/new">New employee</Link>
76
+ </>
77
+ )
78
+ }
79
+ ```
80
+
81
+ ## Core Patterns
82
+
83
+ ### Raw and integration map
84
+
85
+ | Base entry (`@payfit/unity-components`) | Integration (`@payfit/unity-components/integrations/tanstack-router`) | Prop |
86
+ | --------------------------------------- | --------------------------------------------------------------------- | --------------------------------------- |
87
+ | `RawLink` | `Link` | `href` (raw) / `to` (integration) |
88
+ | `RawNavItem` | `NavItem` | same |
89
+ | `RawBreadcrumbLink` | `BreadcrumbLink` | same |
90
+ | `RawPaginationLink` | `PaginationLink` | same |
91
+ | `RawTab` (+ `Tabs`) | `Tab` (+ `Tabs`) | route-aware `to` selects the active tab |
92
+ | `RawLinkButton` | `LinkButton` | same |
93
+
94
+ The integration components are produced via `createLink(RawLink)`. They render
95
+ exactly the same DOM as the raw versions but accept Tanstack's typed `to`,
96
+ `params`, `search`, and `preload` props.
97
+
98
+ ### Compose Breadcrumbs / Pagination / Tabs
99
+
100
+ Each navigation composite has a strict child contract. Direct children of the
101
+ container must be the wrapper part — loose children are silently filtered.
102
+
103
+ ```tsx
104
+ import {
105
+ Breadcrumb,
106
+ BreadcrumbLink,
107
+ Breadcrumbs,
108
+ Pagination,
109
+ PaginationContent,
110
+ PaginationItem,
111
+ RawPaginationLink,
112
+ RawTab,
113
+ TabList,
114
+ TabPanel,
115
+ Tabs,
116
+ } from '@payfit/unity-components'
117
+
118
+ export function CompositionExamples({
119
+ page,
120
+ pageCount,
121
+ onPageChange,
122
+ }: {
123
+ page: number
124
+ pageCount: number
125
+ onPageChange: (next: number, prev: number, dir: -1 | 1) => void
126
+ }) {
127
+ return (
128
+ <>
129
+ <Breadcrumbs>
130
+ <Breadcrumb>
131
+ <BreadcrumbLink href="/">Home</BreadcrumbLink>
132
+ </Breadcrumb>
133
+ <Breadcrumb>
134
+ <BreadcrumbLink href="/employees">Employees</BreadcrumbLink>
135
+ </Breadcrumb>
136
+ </Breadcrumbs>
137
+
138
+ <Pagination
139
+ currentPage={page}
140
+ pageCount={pageCount}
141
+ onPageChange={onPageChange}
142
+ >
143
+ <PaginationContent>
144
+ {Array.from({ length: pageCount }, (_, i) => i + 1).map(n => (
145
+ <PaginationItem key={n}>
146
+ <RawPaginationLink value={n} isActive={n === page}>
147
+ {n}
148
+ </RawPaginationLink>
149
+ </PaginationItem>
150
+ ))}
151
+ </PaginationContent>
152
+ </Pagination>
153
+
154
+ <Tabs>
155
+ <TabList>
156
+ <RawTab id="active">Active</RawTab>
157
+ <RawTab id="archived">Archived</RawTab>
158
+ </TabList>
159
+ <TabPanel id="active">Active rows</TabPanel>
160
+ <TabPanel id="archived">Archived rows</TabPanel>
161
+ </Tabs>
162
+ </>
163
+ )
164
+ }
165
+ ```
166
+
167
+ ### RouterProvider for Raw\* in non-Tanstack apps
168
+
169
+ When you use `Raw*` components in an app that uses a different router (e.g.
170
+ React Router), wrap the app once in `RouterProvider` so `isActive` and
171
+ client-side navigation work. The Tanstack integration entry does NOT need
172
+ this — it reads from Tanstack hooks directly.
173
+
174
+ ```tsx
175
+ import { RouterProvider } from '@payfit/unity-components'
176
+ import { matchPath, useLocation, useNavigate } from 'react-router-dom'
177
+
178
+ export function UnityRouterBridge({ children }: { children: React.ReactNode }) {
179
+ const navigate = useNavigate()
180
+ const location = useLocation()
181
+
182
+ return (
183
+ <RouterProvider
184
+ navigate={to => navigate(to)}
185
+ isActive={(to, isExact) =>
186
+ Boolean(
187
+ matchPath({ path: to, end: Boolean(isExact) }, location.pathname),
188
+ )
189
+ }
190
+ >
191
+ {children}
192
+ </RouterProvider>
193
+ )
194
+ }
195
+ ```
196
+
197
+ ## Common Mistakes
198
+
199
+ ### HIGH Import Link from base entry in a Tanstack Router feature
200
+
201
+ Wrong:
202
+
203
+ ```tsx
204
+ import { Link } from '@payfit/unity-components'
205
+
206
+ ;<Link to="/dashboard">Go</Link>
207
+ ```
208
+
209
+ Correct:
210
+
211
+ ```tsx
212
+ import { Link } from '@payfit/unity-components/integrations/tanstack-router'
213
+
214
+ ;<Link to="/dashboard">Go</Link>
215
+ ```
216
+
217
+ The base export "Link" does not exist; agents alias RawLink and pass to=. The prop is silently ignored and the link does not navigate.
218
+
219
+ Source: integrations/tanstack-router/components/link/Link.tsx (createLink wraps RawLink)
220
+
221
+ ### HIGH Pass to= prop to RawLink
222
+
223
+ Wrong:
224
+
225
+ ```tsx
226
+ import { RawLink } from '@payfit/unity-components'
227
+
228
+ ;<RawLink to="/dashboard">Go</RawLink>
229
+ ```
230
+
231
+ Correct:
232
+
233
+ ```tsx
234
+ // Use the integration Link for type-safe routing:
235
+ import { Link } from '@payfit/unity-components/integrations/tanstack-router'
236
+ <Link to="/dashboard">Go</Link>
237
+ // OR keep RawLink with a plain href:
238
+ <RawLink href="/dashboard">Go</RawLink>
239
+ ```
240
+
241
+ RawLink only accepts href. The to prop is silently ignored.
242
+
243
+ Source: components/link/RawLink.tsx:113-163
244
+
245
+ ### HIGH Expect the v1 monolithic Pagination
246
+
247
+ Wrong:
248
+
249
+ ```tsx
250
+ import { Pagination, ClientSidePagination } from '@payfit/unity-components'
251
+ // ClientSidePagination is not exported; Pagination needs children.
252
+ <Pagination currentPage={1} pageCount={10} onPageChange={…} />
253
+ ```
254
+
255
+ Correct:
256
+
257
+ ```tsx
258
+ import { Pagination, PaginationContent, PaginationItem, RawPaginationLink }
259
+ from '@payfit/unity-components'
260
+ <Pagination currentPage={1} pageCount={10} onPageChange={…}>
261
+ <PaginationContent>
262
+ <PaginationItem>
263
+ <RawPaginationLink value={1}>1</RawPaginationLink>
264
+ </PaginationItem>
265
+ {/* … */}
266
+ </PaginationContent>
267
+ </Pagination>
268
+ // Or, for tables, let DataTable handle pagination internally.
269
+ ```
270
+
271
+ v2 Pagination is compositional; passing currentPage/pageCount with no children renders an empty container. The old monolithic component (ClientSidePagination) now lives only inside DataTable as an internal — there is no public monolithic export. For standalone pagination, compose it yourself; for paginated tables, use DataTable which has it built in.
272
+
273
+ Source: components/pagination/Pagination.tsx; index.ts; maintainer interview (ClientSidePagination is internal to DataTable)
274
+
275
+ ### MEDIUM Forget to wrap BreadcrumbLink in Breadcrumb
276
+
277
+ Wrong:
278
+
279
+ ```tsx
280
+ <Breadcrumbs>
281
+ <BreadcrumbLink href="/">Home</BreadcrumbLink>
282
+ </Breadcrumbs>
283
+ ```
284
+
285
+ Correct:
286
+
287
+ ```tsx
288
+ <Breadcrumbs>
289
+ <Breadcrumb>
290
+ <BreadcrumbLink href="/">Home</BreadcrumbLink>
291
+ </Breadcrumb>
292
+ </Breadcrumbs>
293
+ ```
294
+
295
+ Breadcrumbs filters children to Breadcrumb type; loose BreadcrumbLinks are dropped silently.
296
+
297
+ Source: components/breadcrumbs/Breadcrumbs.tsx:328-407
298
+
299
+ ### MEDIUM Use Raw\* components without RouterProvider in a non-Tanstack app
300
+
301
+ Wrong:
302
+
303
+ ```tsx
304
+ <App>
305
+ <RawLink href="/dashboard">Go</RawLink>
306
+ </App>
307
+ ```
308
+
309
+ Correct:
310
+
311
+ ```tsx
312
+ <RouterProvider
313
+ isActive={path => router.isActive(path)}
314
+ navigate={router.navigate}
315
+ >
316
+ <App>
317
+ <RawLink href="/dashboard">Go</RawLink>
318
+ </App>
319
+ </RouterProvider>
320
+ ```
321
+
322
+ Raw\* components consume useRouter() context. Without RouterProvider, isActive checks return undefined and active-link styling is lost.
323
+
324
+ Source: components/link/RawLink.tsx:186; providers/router/RouterProvider.tsx
325
+
326
+ ## See also
327
+
328
+ - `unity-setup-feature-plugin` — where and how to mount `RouterProvider`,
329
+ and when a feature plugin should switch from base to integration entry.
330
+ - `unity-data-table` — DataTable has pagination built in; do not compose
331
+ `Pagination` next to it.