@payfit/unity-components 2.55.14 → 2.55.16

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.
@@ -4,9 +4,10 @@ description: >
4
4
  Load when building Unity links, tabs, breadcrumbs, nav, or pagination. Use it
5
5
  to choose router-aware Tanstack Router components versus Raw* href
6
6
  primitives.
7
- type: core
8
- library: '@payfit/unity-components'
9
- library_version: '2.x'
7
+ metadata:
8
+ type: core
9
+ library: '@payfit/unity-components'
10
+ library_version: '2.x'
10
11
  sources:
11
12
  - 'PayFit/hr-apps:libs/shared/unity/components/src/components/link/RawLink.tsx'
12
13
  - 'PayFit/hr-apps:libs/shared/unity/components/src/components/breadcrumbs/Breadcrumbs.tsx'
@@ -73,119 +74,14 @@ export function EmployeesShell() {
73
74
 
74
75
  ## Core Patterns
75
76
 
76
- ### Raw and integration map
77
+ - Use router-aware integration exports in TanStack Router features and `Raw*`
78
+ primitives for explicit `href` navigation.
79
+ - Preserve the required Breadcrumbs, Pagination, and Tabs composition.
80
+ - In non-TanStack applications, provide the appropriate router adapter before
81
+ using `Raw*` navigation components.
77
82
 
78
- | Base entry (`@payfit/unity-components`) | Integration (`@payfit/unity-components/integrations/tanstack-router`) | Prop |
79
- | --------------------------------------- | --------------------------------------------------------------------- | --------------------------------------- |
80
- | `RawLink` | `Link` | `href` (raw) / `to` (integration) |
81
- | `RawNavItem` | `NavItem` | same |
82
- | `RawBreadcrumbLink` | `BreadcrumbLink` | same |
83
- | `RawPaginationLink` | `PaginationLink` | same |
84
- | `RawTab` (+ `Tabs`) | `Tab` (+ `Tabs`) | route-aware `to` selects the active tab |
85
- | `RawLinkButton` | `LinkButton` | same |
86
-
87
- The integration components are produced via `createLink(RawLink)`. They render
88
- exactly the same DOM as the raw versions but accept Tanstack's typed `to`,
89
- `params`, `search`, and `preload` props.
90
-
91
- ### Compose Breadcrumbs / Pagination / Tabs
92
-
93
- Each navigation composite has a strict child contract. Direct children of the
94
- container must be the wrapper part — loose children are silently filtered.
95
-
96
- ```tsx
97
- import {
98
- Breadcrumb,
99
- BreadcrumbLink,
100
- Breadcrumbs,
101
- Pagination,
102
- PaginationContent,
103
- PaginationItem,
104
- RawPaginationLink,
105
- RawTab,
106
- TabList,
107
- TabPanel,
108
- Tabs,
109
- } from '@payfit/unity-components'
110
-
111
- export function CompositionExamples({
112
- page,
113
- pageCount,
114
- onPageChange,
115
- }: {
116
- page: number
117
- pageCount: number
118
- onPageChange: (next: number, prev: number, dir: -1 | 1) => void
119
- }) {
120
- return (
121
- <>
122
- <Breadcrumbs>
123
- <Breadcrumb>
124
- <BreadcrumbLink href="/">Home</BreadcrumbLink>
125
- </Breadcrumb>
126
- <Breadcrumb>
127
- <BreadcrumbLink href="/employees">Employees</BreadcrumbLink>
128
- </Breadcrumb>
129
- </Breadcrumbs>
130
-
131
- <Pagination
132
- currentPage={page}
133
- pageCount={pageCount}
134
- onPageChange={onPageChange}
135
- >
136
- <PaginationContent>
137
- {Array.from({ length: pageCount }, (_, i) => i + 1).map(n => (
138
- <PaginationItem key={n}>
139
- <RawPaginationLink value={n} isActive={n === page}>
140
- {n}
141
- </RawPaginationLink>
142
- </PaginationItem>
143
- ))}
144
- </PaginationContent>
145
- </Pagination>
146
-
147
- <Tabs>
148
- <TabList>
149
- <RawTab id="active">Active</RawTab>
150
- <RawTab id="archived">Archived</RawTab>
151
- </TabList>
152
- <TabPanel id="active">Active rows</TabPanel>
153
- <TabPanel id="archived">Archived rows</TabPanel>
154
- </Tabs>
155
- </>
156
- )
157
- }
158
- ```
159
-
160
- ### RouterProvider for Raw\* in non-Tanstack apps
161
-
162
- When you use `Raw*` components in an app that uses a different router (e.g.
163
- React Router), wrap the app once in `RouterProvider` so `isActive` and
164
- client-side navigation work. The Tanstack integration entry does NOT need
165
- this — it reads from Tanstack hooks directly.
166
-
167
- ```tsx
168
- import { RouterProvider } from '@payfit/unity-components'
169
- import { matchPath, useLocation, useNavigate } from 'react-router-dom'
170
-
171
- export function UnityRouterBridge({ children }: { children: React.ReactNode }) {
172
- const navigate = useNavigate()
173
- const location = useLocation()
174
-
175
- return (
176
- <RouterProvider
177
- navigate={to => navigate(to)}
178
- isActive={(to, isExact) =>
179
- Boolean(
180
- matchPath({ path: to, end: Boolean(isExact) }, location.pathname),
181
- )
182
- }
183
- >
184
- {children}
185
- </RouterProvider>
186
- )
187
- }
188
- ```
83
+ Read [references/patterns.md](references/patterns.md) for complete compositions
84
+ and provider examples.
189
85
 
190
86
  ## Common Mistakes
191
87
 
@@ -260,7 +156,7 @@ import { Pagination, PaginationContent, PaginationItem, RawPaginationLink }
260
156
 
261
157
  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.
262
158
 
263
- Source: components/pagination/Pagination.tsx; index.ts; maintainer interview (ClientSidePagination is internal to DataTable)
159
+ Source: components/pagination/Pagination.tsx; index.ts
264
160
 
265
161
  ### MEDIUM Forget to wrap BreadcrumbLink in Breadcrumb
266
162
 
@@ -0,0 +1,115 @@
1
+ # Unity navigation patterns
2
+
3
+ ### Raw and integration map
4
+
5
+ | Base entry (`@payfit/unity-components`) | Integration (`@payfit/unity-components/integrations/tanstack-router`) | Prop |
6
+ | --------------------------------------- | --------------------------------------------------------------------- | --------------------------------------- |
7
+ | `RawLink` | `Link` | `href` (raw) / `to` (integration) |
8
+ | `RawNavItem` | `NavItem` | same |
9
+ | `RawBreadcrumbLink` | `BreadcrumbLink` | same |
10
+ | `RawPaginationLink` | `PaginationLink` | same |
11
+ | `RawTab` (+ `Tabs`) | `Tab` (+ `Tabs`) | route-aware `to` selects the active tab |
12
+ | `RawLinkButton` | `LinkButton` | same |
13
+
14
+ The integration components are produced via `createLink(RawLink)`. They render
15
+ exactly the same DOM as the raw versions but accept Tanstack's typed `to`,
16
+ `params`, `search`, and `preload` props.
17
+
18
+ ### Compose Breadcrumbs / Pagination / Tabs
19
+
20
+ Each navigation composite has a strict child contract. Direct children of the
21
+ container must be the wrapper part — loose children are silently filtered.
22
+
23
+ ```tsx
24
+ import {
25
+ Breadcrumb,
26
+ BreadcrumbLink,
27
+ Breadcrumbs,
28
+ Pagination,
29
+ PaginationContent,
30
+ PaginationItem,
31
+ RawPaginationLink,
32
+ RawTab,
33
+ TabList,
34
+ TabPanel,
35
+ Tabs,
36
+ } from '@payfit/unity-components'
37
+
38
+ export function CompositionExamples({
39
+ page,
40
+ pageCount,
41
+ onPageChange,
42
+ }: {
43
+ page: number
44
+ pageCount: number
45
+ onPageChange: (next: number, prev: number, dir: -1 | 1) => void
46
+ }) {
47
+ return (
48
+ <>
49
+ <Breadcrumbs>
50
+ <Breadcrumb>
51
+ <BreadcrumbLink href="/">Home</BreadcrumbLink>
52
+ </Breadcrumb>
53
+ <Breadcrumb>
54
+ <BreadcrumbLink href="/employees">Employees</BreadcrumbLink>
55
+ </Breadcrumb>
56
+ </Breadcrumbs>
57
+
58
+ <Pagination
59
+ currentPage={page}
60
+ pageCount={pageCount}
61
+ onPageChange={onPageChange}
62
+ >
63
+ <PaginationContent>
64
+ {Array.from({ length: pageCount }, (_, i) => i + 1).map(n => (
65
+ <PaginationItem key={n}>
66
+ <RawPaginationLink value={n} isActive={n === page}>
67
+ {n}
68
+ </RawPaginationLink>
69
+ </PaginationItem>
70
+ ))}
71
+ </PaginationContent>
72
+ </Pagination>
73
+
74
+ <Tabs>
75
+ <TabList>
76
+ <RawTab id="active">Active</RawTab>
77
+ <RawTab id="archived">Archived</RawTab>
78
+ </TabList>
79
+ <TabPanel id="active">Active rows</TabPanel>
80
+ <TabPanel id="archived">Archived rows</TabPanel>
81
+ </Tabs>
82
+ </>
83
+ )
84
+ }
85
+ ```
86
+
87
+ ### RouterProvider for Raw\* in non-Tanstack apps
88
+
89
+ When you use `Raw*` components in an app that uses a different router (e.g.
90
+ React Router), wrap the app once in `RouterProvider` so `isActive` and
91
+ client-side navigation work. The Tanstack integration entry does NOT need
92
+ this — it reads from Tanstack hooks directly.
93
+
94
+ ```tsx
95
+ import { RouterProvider } from '@payfit/unity-components'
96
+ import { matchPath, useLocation, useNavigate } from 'react-router-dom'
97
+
98
+ export function UnityRouterBridge({ children }: { children: React.ReactNode }) {
99
+ const navigate = useNavigate()
100
+ const location = useLocation()
101
+
102
+ return (
103
+ <RouterProvider
104
+ navigate={to => navigate(to)}
105
+ isActive={(to, isExact) =>
106
+ Boolean(
107
+ matchPath({ path: to, end: Boolean(isExact) }, location.pathname),
108
+ )
109
+ }
110
+ >
111
+ {children}
112
+ </RouterProvider>
113
+ )
114
+ }
115
+ ```
@@ -4,9 +4,10 @@ description: >
4
4
  Load when adding Unity dialogs, side panels, bottom sheets, tooltips,
5
5
  popovers, or menus. Use it to choose modal versus non-modal overlays and keep
6
6
  disabled-control tooltip behavior accessible.
7
- type: core
8
- library: '@payfit/unity-components'
9
- library_version: '2.x'
7
+ metadata:
8
+ type: core
9
+ library: '@payfit/unity-components'
10
+ library_version: '2.x'
10
11
  sources:
11
12
  - 'PayFit/hr-apps:libs/shared/unity/components/src/components/dialog/Dialog.tsx'
12
13
  - 'PayFit/hr-apps:libs/shared/unity/components/src/components/side-panel/SidePanel.tsx'
@@ -73,135 +74,13 @@ manage focus, restoration, scroll lock, and Escape automatically.
73
74
 
74
75
  ## Core Patterns
75
76
 
76
- ### Dialog with DialogTrigger + DialogActions
77
+ - Compose blocking decisions with `DialogTrigger`, `Dialog`, and
78
+ `DialogActions`.
79
+ - Use `SidePanel` for side-anchored detail or editing flows.
80
+ - Use `Popover` for focusable informational content and `Menu` for action
81
+ lists.
77
82
 
78
- ```tsx
79
- import {
80
- Button,
81
- Dialog,
82
- DialogActions,
83
- DialogButton,
84
- DialogContent,
85
- DialogTitle,
86
- DialogTrigger,
87
- } from '@payfit/unity-components'
88
-
89
- export function ArchiveDialog({ onArchive }: { onArchive: () => void }) {
90
- return (
91
- <DialogTrigger>
92
- <Button>Archive</Button>
93
- <Dialog size="md">
94
- <DialogTitle>Archive this employee?</DialogTitle>
95
- <DialogContent>
96
- They will no longer appear in active lists. You can restore them
97
- later.
98
- </DialogContent>
99
- <DialogActions>
100
- <DialogButton variant="close">Cancel</DialogButton>
101
- <DialogButton variant="confirm" onPress={onArchive}>
102
- Archive
103
- </DialogButton>
104
- </DialogActions>
105
- </Dialog>
106
- </DialogTrigger>
107
- )
108
- }
109
- ```
110
-
111
- ### SidePanel for detail views
112
-
113
- ```tsx
114
- import { useState } from 'react'
115
-
116
- import {
117
- Button,
118
- SidePanel,
119
- SidePanelContent,
120
- SidePanelFooter,
121
- SidePanelHeader,
122
- } from '@payfit/unity-components'
123
-
124
- export function EmployeeDetailPanel({ employee }: { employee: Employee }) {
125
- const [isOpen, setIsOpen] = useState(false)
126
-
127
- return (
128
- <>
129
- <Button onPress={() => setIsOpen(true)}>View details</Button>
130
- <SidePanel isOpen={isOpen} onOpenChange={setIsOpen}>
131
- <SidePanelHeader>{employee.name}</SidePanelHeader>
132
- <SidePanelContent>
133
- <p>{employee.position}</p>
134
- <p>{employee.team}</p>
135
- </SidePanelContent>
136
- <SidePanelFooter>
137
- <Button variant="secondary" onPress={() => setIsOpen(false)}>
138
- Close
139
- </Button>
140
- </SidePanelFooter>
141
- </SidePanel>
142
- </>
143
- )
144
- }
145
- ```
146
-
147
- ### Popover for interactive informational content
148
-
149
- `title` is required (use `isTitleSrOnly` if you don't want it visible).
150
- Children may be focusable; the Popover is non-modal so the page stays
151
- interactive behind it.
152
-
153
- ```tsx
154
- import { Button, Popover, PopoverTrigger } from '@payfit/unity-components'
155
-
156
- export function HelpPopover() {
157
- return (
158
- <PopoverTrigger>
159
- <Button variant="tertiary">What is a working agreement?</Button>
160
- <Popover title="Working agreement">
161
- <p>
162
- A working agreement defines when, where and how an employee works. See
163
- the <a href="/handbook/working-agreement">handbook</a> for details.
164
- </p>
165
- </Popover>
166
- </PopoverTrigger>
167
- )
168
- }
169
- ```
170
-
171
- ### Menu for action lists
172
-
173
- `Menu` expects exactly two children: a trigger and a content block. Use
174
- `MenuTrigger` / `MenuContent` / `RawMenuItem` for the standard composition.
175
-
176
- ```tsx
177
- import {
178
- IconButton,
179
- Menu,
180
- MenuContent,
181
- MenuTrigger,
182
- RawMenuItem,
183
- } from '@payfit/unity-components'
184
-
185
- export function RowActions({
186
- onEdit,
187
- onArchive,
188
- }: {
189
- onEdit: () => void
190
- onArchive: () => void
191
- }) {
192
- return (
193
- <Menu>
194
- <MenuTrigger>
195
- <IconButton icon="MoreFilled" title="Actions" />
196
- </MenuTrigger>
197
- <MenuContent>
198
- <RawMenuItem onAction={onEdit}>Edit</RawMenuItem>
199
- <RawMenuItem onAction={onArchive}>Archive</RawMenuItem>
200
- </MenuContent>
201
- </Menu>
202
- )
203
- }
204
- ```
83
+ Read [references/patterns.md](references/patterns.md) for complete examples.
205
84
 
206
85
  ## Common Mistakes
207
86
 
@@ -224,7 +103,7 @@ Correct:
224
103
 
225
104
  Unity enforces the WCAG rule that disabled controls must not carry tooltips (the disabled element is not keyboard-focusable, so the tooltip is unreachable). This is enforced at the library level, not just policy.
226
105
 
227
- Source: components/tooltip/Tooltip.tsx; maintainer interview (enforced by Unity)
106
+ Source: components/tooltip/Tooltip.tsx
228
107
 
229
108
  ### MEDIUM Use Dialog for a non-blocking hint
230
109
 
@@ -0,0 +1,131 @@
1
+ # Unity overlay patterns
2
+
3
+ ### Dialog with DialogTrigger + DialogActions
4
+
5
+ ```tsx
6
+ import {
7
+ Button,
8
+ Dialog,
9
+ DialogActions,
10
+ DialogButton,
11
+ DialogContent,
12
+ DialogTitle,
13
+ DialogTrigger,
14
+ } from '@payfit/unity-components'
15
+
16
+ export function ArchiveDialog({ onArchive }: { onArchive: () => void }) {
17
+ return (
18
+ <DialogTrigger>
19
+ <Button>Archive</Button>
20
+ <Dialog size="md">
21
+ <DialogTitle>Archive this employee?</DialogTitle>
22
+ <DialogContent>
23
+ They will no longer appear in active lists. You can restore them
24
+ later.
25
+ </DialogContent>
26
+ <DialogActions>
27
+ <DialogButton variant="close">Cancel</DialogButton>
28
+ <DialogButton variant="confirm" onPress={onArchive}>
29
+ Archive
30
+ </DialogButton>
31
+ </DialogActions>
32
+ </Dialog>
33
+ </DialogTrigger>
34
+ )
35
+ }
36
+ ```
37
+
38
+ ### SidePanel for detail views
39
+
40
+ ```tsx
41
+ import { useState } from 'react'
42
+
43
+ import {
44
+ Button,
45
+ SidePanel,
46
+ SidePanelContent,
47
+ SidePanelFooter,
48
+ SidePanelHeader,
49
+ } from '@payfit/unity-components'
50
+
51
+ export function EmployeeDetailPanel({ employee }: { employee: Employee }) {
52
+ const [isOpen, setIsOpen] = useState(false)
53
+
54
+ return (
55
+ <>
56
+ <Button onPress={() => setIsOpen(true)}>View details</Button>
57
+ <SidePanel isOpen={isOpen} onOpenChange={setIsOpen}>
58
+ <SidePanelHeader>{employee.name}</SidePanelHeader>
59
+ <SidePanelContent>
60
+ <p>{employee.position}</p>
61
+ <p>{employee.team}</p>
62
+ </SidePanelContent>
63
+ <SidePanelFooter>
64
+ <Button variant="secondary" onPress={() => setIsOpen(false)}>
65
+ Close
66
+ </Button>
67
+ </SidePanelFooter>
68
+ </SidePanel>
69
+ </>
70
+ )
71
+ }
72
+ ```
73
+
74
+ ### Popover for interactive informational content
75
+
76
+ `title` is required (use `isTitleSrOnly` if you don't want it visible).
77
+ Children may be focusable; the Popover is non-modal so the page stays
78
+ interactive behind it.
79
+
80
+ ```tsx
81
+ import { Button, Popover, PopoverTrigger } from '@payfit/unity-components'
82
+
83
+ export function HelpPopover() {
84
+ return (
85
+ <PopoverTrigger>
86
+ <Button variant="tertiary">What is a working agreement?</Button>
87
+ <Popover title="Working agreement">
88
+ <p>
89
+ A working agreement defines when, where and how an employee works. See
90
+ the <a href="/handbook/working-agreement">handbook</a> for details.
91
+ </p>
92
+ </Popover>
93
+ </PopoverTrigger>
94
+ )
95
+ }
96
+ ```
97
+
98
+ ### Menu for action lists
99
+
100
+ `Menu` expects exactly two children: a trigger and a content block. Use
101
+ `MenuTrigger` / `MenuContent` / `RawMenuItem` for the standard composition.
102
+
103
+ ```tsx
104
+ import {
105
+ IconButton,
106
+ Menu,
107
+ MenuContent,
108
+ MenuTrigger,
109
+ RawMenuItem,
110
+ } from '@payfit/unity-components'
111
+
112
+ export function RowActions({
113
+ onEdit,
114
+ onArchive,
115
+ }: {
116
+ onEdit: () => void
117
+ onArchive: () => void
118
+ }) {
119
+ return (
120
+ <Menu>
121
+ <MenuTrigger>
122
+ <IconButton icon="MoreFilled" title="Actions" />
123
+ </MenuTrigger>
124
+ <MenuContent>
125
+ <RawMenuItem onAction={onEdit}>Edit</RawMenuItem>
126
+ <RawMenuItem onAction={onArchive}>Archive</RawMenuItem>
127
+ </MenuContent>
128
+ </Menu>
129
+ )
130
+ }
131
+ ```
@@ -7,9 +7,10 @@ description: >
7
7
  → I18nProvider (react-aria-components) → UnityIconsProvider. Import
8
8
  @payfit/unity-themes/css/unity.css once. Merge @payfit/unity-components/i18n
9
9
  JSON into the IntlProvider messages, keyed by locale.
10
- type: lifecycle
11
- library: '@payfit/unity-components'
12
- library_version: '2.x'
10
+ metadata:
11
+ type: lifecycle
12
+ library: '@payfit/unity-components'
13
+ library_version: '2.x'
13
14
  sources:
14
15
  - 'PayFit/hr-apps:libs/shared/unity/components/src/docs/tutorials/Getting Started.mdx'
15
16
  - 'PayFit/hr-apps:libs/shared/unity/icons/src/components/icons-provider/UnityIconsProvider.tsx'