@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.
- package/README.md +10 -0
- package/package.json +15 -10
- package/skills/unity-data-table/SKILL.md +512 -0
- package/skills/unity-find-component/SKILL.md +377 -0
- package/skills/unity-layout-and-styling/SKILL.md +400 -0
- package/skills/unity-migrate-from-midnight/SKILL.md +190 -0
- package/skills/unity-migrate-from-midnight/references/midnight-component-map.md +180 -0
- package/skills/unity-navigation/SKILL.md +331 -0
- package/skills/unity-overlays/SKILL.md +352 -0
- package/skills/unity-setup-feature-plugin/SKILL.md +55 -0
- package/skills/unity-tanstack-form/SKILL.md +349 -0
- package/skills/unity-tanstack-form/references/bound-field-components.md +67 -0
- package/skills/unity-tanstack-form/references/schema-adapters.md +108 -0
|
@@ -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.
|