@payfit/unity-components 2.55.13 → 2.55.15

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.
Files changed (60) hide show
  1. package/dist/esm/components/autocomplete/parts/AutocompletePanel.js +1 -1
  2. package/dist/esm/components/avatar/Avatar.context.js +1 -1
  3. package/dist/esm/components/bottom-sheet/parts/BottomSheetDragIndicator.js +1 -1
  4. package/dist/esm/components/breadcrumbs/Breadcrumbs.context.js +1 -1
  5. package/dist/esm/components/breadcrumbs/Breadcrumbs.js +1 -1
  6. package/dist/esm/components/carousel/Carousel.options.js +1 -1
  7. package/dist/esm/components/carousel/hooks/useCarouselState.js +8 -4
  8. package/dist/esm/components/client-side-pagination/ClientSidePagination.js +1 -1
  9. package/dist/esm/components/client-side-pagination/parts/RawPaginationLink.js +1 -1
  10. package/dist/esm/components/client-side-pagination/utils/pagination-window.js +18 -19
  11. package/dist/esm/components/code/Code.js +1 -1
  12. package/dist/esm/components/collapsible/Collapsible.js +1 -1
  13. package/dist/esm/components/dialog/test-utils.js +4 -2
  14. package/dist/esm/components/error-state/initConfig.js +1 -1
  15. package/dist/esm/components/filter/parts/FilterButton.js +1 -1
  16. package/dist/esm/components/filter/parts/FilterLabel.js +1 -1
  17. package/dist/esm/components/filter/utils/value-formatters.js +1 -1
  18. package/dist/esm/components/filter-toolbar/FilterToolbar.js +27 -27
  19. package/dist/esm/components/filter-toolbar/parts/AddFilterItem.js +1 -1
  20. package/dist/esm/components/form/Form.context.js +1 -1
  21. package/dist/esm/components/form-field/FormField.context.js +1 -1
  22. package/dist/esm/components/inline-field/parts/InlineFieldEditView.js +7 -4
  23. package/dist/esm/components/inline-field-group/InlineFieldGroup.js +14 -8
  24. package/dist/esm/components/multi-select/MultiSelect.js +2 -2
  25. package/dist/esm/components/pagination/utils/pagination-window.js +25 -26
  26. package/dist/esm/components/phone-number/parts/PhoneNumberItem.js +1 -1
  27. package/dist/esm/components/popover/Popover.js +1 -1
  28. package/dist/esm/components/radio-button-group/parts/RadioButton.js +1 -1
  29. package/dist/esm/components/select/parts/SelectOption.context.js +1 -1
  30. package/dist/esm/components/select-list/helpers.js +2 -2
  31. package/dist/esm/components/select-list/parts/SelectListOptGroup.js +1 -1
  32. package/dist/esm/components/selectable-card/internals/Content.js +1 -1
  33. package/dist/esm/components/selectable-card/internals/Description.js +1 -1
  34. package/dist/esm/components/selectable-card/internals/Illustration.js +1 -1
  35. package/dist/esm/components/selectable-card/internals/SelectedIndicator.js +1 -1
  36. package/dist/esm/components/side-panel/parts/SidePanelDragIndicator.js +1 -1
  37. package/dist/esm/components/stepper/Stepper.context.js +1 -1
  38. package/dist/esm/components/table/Table.context.js +1 -1
  39. package/dist/esm/components/table/hooks/useTableKeyboardNavigation.js +10 -8
  40. package/dist/esm/components/tabs/Tabs.context.js +1 -1
  41. package/dist/esm/components/task-menu/TaskMenu.context.js +1 -1
  42. package/dist/esm/components/timeline/Timeline.context.js +1 -1
  43. package/dist/esm/components/timeline/parts/TimelineStepContent.context.js +1 -1
  44. package/dist/esm/hooks/use-has-scroll.js +3 -1
  45. package/dist/esm/index.js +2 -2
  46. package/package.json +14 -14
  47. package/skills/unity-data-table/SKILL.md +24 -240
  48. package/skills/unity-data-table/references/patterns.md +237 -0
  49. package/skills/unity-find-component/SKILL.md +20 -105
  50. package/skills/unity-find-component/references/component-catalog.md +94 -0
  51. package/skills/unity-layout-and-styling/SKILL.md +14 -141
  52. package/skills/unity-layout-and-styling/references/patterns.md +139 -0
  53. package/skills/unity-migrate-from-midnight/SKILL.md +9 -9
  54. package/skills/unity-navigation/SKILL.md +12 -116
  55. package/skills/unity-navigation/references/patterns.md +115 -0
  56. package/skills/unity-overlays/SKILL.md +11 -132
  57. package/skills/unity-overlays/references/patterns.md +131 -0
  58. package/skills/unity-setup-feature-plugin/SKILL.md +4 -3
  59. package/skills/unity-tanstack-form/SKILL.md +15 -102
  60. package/skills/unity-tanstack-form/references/patterns.md +102 -0
@@ -0,0 +1,237 @@
1
+ # Unity DataTable patterns
2
+
3
+ ### Define columns with the column helper and ColumnMeta
4
+
5
+ ColumnMeta drives accessibility (`isRowHeader`), keyboard navigation
6
+ (`isFocusable: false` for cells whose children are themselves focusable like
7
+ checkboxes), `helperText` (renders a tooltip next to the header), and
8
+ `headerClassName` (required when `layout="fixed"`).
9
+
10
+ ```tsx
11
+ import { Badge } from '@payfit/unity-components'
12
+ import { createColumnHelper } from '@tanstack/react-table'
13
+
14
+ const columnHelper = createColumnHelper<Employee>()
15
+
16
+ export const employeeColumns = [
17
+ columnHelper.accessor('name', {
18
+ id: 'employee',
19
+ header: 'Employee',
20
+ enableSorting: true,
21
+ meta: { isRowHeader: true, headerClassName: 'uy:w-[260px]' },
22
+ }),
23
+ columnHelper.accessor('status', {
24
+ header: 'Status',
25
+ enableColumnFilter: true,
26
+ filterFn: 'arrIncludesSome',
27
+ cell: info => {
28
+ const status = info.getValue()
29
+ return (
30
+ <Badge variant={status === 'active' ? 'success' : 'neutral'}>
31
+ {status}
32
+ </Badge>
33
+ )
34
+ },
35
+ meta: { helperText: 'Active employees can sign in.' },
36
+ }),
37
+ columnHelper.display({
38
+ id: 'actions',
39
+ header: '',
40
+ cell: ({ row }) => <RowMenu row={row.original} />,
41
+ meta: { isFocusable: false },
42
+ }),
43
+ ]
44
+ ```
45
+
46
+ ### Server-side pagination
47
+
48
+ `manualPagination: true` disables Tanstack's internal slicing. Pass only the
49
+ current page's slice as `data` and supply `pageCount`.
50
+
51
+ ```tsx
52
+ import { useMemo, useState } from 'react'
53
+
54
+ import { getCoreRowModel, useReactTable } from '@tanstack/react-table'
55
+
56
+ export function ServerTable({ totalCount, fetchPage }: Props) {
57
+ const [pagination, setPagination] = useState({ pageIndex: 0, pageSize: 20 })
58
+ const { data: pageRows = [] } = useQuery({
59
+ queryKey: ['employees', pagination],
60
+ queryFn: () => fetchPage(pagination.pageIndex, pagination.pageSize),
61
+ })
62
+
63
+ const columns = useMemo(() => employeeColumns, [])
64
+ const data = useMemo(() => pageRows, [pageRows])
65
+
66
+ const table = useReactTable({
67
+ data,
68
+ columns,
69
+ manualPagination: true,
70
+ pageCount: Math.ceil(totalCount / pagination.pageSize),
71
+ state: { pagination },
72
+ onPaginationChange: setPagination,
73
+ getCoreRowModel: getCoreRowModel(),
74
+ })
75
+
76
+ return (
77
+ <DataTableRoot>
78
+ <DataTable table={table}>
79
+ {row => (
80
+ <TableRow key={row.id}>
81
+ {row.getVisibleCells().map(cell => (
82
+ <TableCell key={cell.id}>
83
+ {flexRender(cell.column.columnDef.cell, cell.getContext())}
84
+ </TableCell>
85
+ ))}
86
+ </TableRow>
87
+ )}
88
+ </DataTable>
89
+ </DataTableRoot>
90
+ )
91
+ }
92
+ ```
93
+
94
+ ### Filtering with FilterToolbar
95
+
96
+ `FilterToolbar.onChange` emits `SerializableAppliedFilter[]`. Map that onto
97
+ `table.setColumnFilters` / `table.setGlobalFilter`. `renderControl` takes any
98
+ control — it is a render function on purpose so you can drop in date pickers,
99
+ multi-selects, text fields, etc.
100
+
101
+ ```tsx
102
+ import type { FilterDef } from '@payfit/unity-components'
103
+
104
+ import { FilterToolbar, Select, SelectItem } from '@payfit/unity-components'
105
+ import { getFilteredRowModel } from '@tanstack/react-table'
106
+
107
+ const filterDefs: FilterDef[] = [
108
+ {
109
+ id: 'status',
110
+ label: 'Status',
111
+ renderControl: (value, onChange) => (
112
+ <Select selectedKey={value as string} onSelectionChange={onChange}>
113
+ <SelectItem id="active">Active</SelectItem>
114
+ <SelectItem id="inactive">Inactive</SelectItem>
115
+ </Select>
116
+ ),
117
+ renderLabel: value => String(value),
118
+ },
119
+ ]
120
+
121
+ export function FilteredTable() {
122
+ const [columnFilters, setColumnFilters] = useState<ColumnFiltersState>([])
123
+
124
+ const table = useReactTable({
125
+ data,
126
+ columns,
127
+ state: { columnFilters, pagination },
128
+ onColumnFiltersChange: setColumnFilters,
129
+ onPaginationChange: setPagination,
130
+ getCoreRowModel: getCoreRowModel(),
131
+ getFilteredRowModel: getFilteredRowModel(),
132
+ getPaginationRowModel: getPaginationRowModel(),
133
+ })
134
+
135
+ return (
136
+ <>
137
+ <FilterToolbar
138
+ filterDefs={filterDefs}
139
+ onChange={applied =>
140
+ setColumnFilters(applied.map(f => ({ id: f.id, value: f.value })))
141
+ }
142
+ />
143
+ <DataTableRoot>
144
+ <DataTable table={table}>
145
+ {row => (
146
+ <TableRow key={row.id}>
147
+ {row.getVisibleCells().map(cell => (
148
+ <TableCell key={cell.id}>
149
+ {flexRender(cell.column.columnDef.cell, cell.getContext())}
150
+ </TableCell>
151
+ ))}
152
+ </TableRow>
153
+ )}
154
+ </DataTable>
155
+ </DataTableRoot>
156
+ </>
157
+ )
158
+ }
159
+ ```
160
+
161
+ ### Bulk actions with row selection
162
+
163
+ `DataTableBulkActions` lives next to `DataTable` inside `DataTableRoot`.
164
+ It auto-shows when rows are selected and provides the F6 focus trap. Use a
165
+ display column with `meta.isFocusable: false` for the checkbox.
166
+
167
+ ```tsx
168
+ import {
169
+ CheckboxStandalone,
170
+ DataTable,
171
+ DataTableBulkActions,
172
+ DataTableRoot,
173
+ } from '@payfit/unity-components'
174
+
175
+ const checkboxColumn = columnHelper.display({
176
+ id: 'select',
177
+ header: ({ table }) => (
178
+ <CheckboxStandalone
179
+ isSelected={table.getIsAllPageRowsSelected()}
180
+ isIndeterminate={table.getIsSomePageRowsSelected()}
181
+ onChange={value => table.toggleAllPageRowsSelected(value)}
182
+ slot="selection"
183
+ >
184
+ Select all
185
+ </CheckboxStandalone>
186
+ ),
187
+ cell: ({ row }) => (
188
+ <CheckboxStandalone
189
+ isSelected={row.getIsSelected()}
190
+ onChange={value => row.toggleSelected(value)}
191
+ slot="selection"
192
+ >
193
+ Select row
194
+ </CheckboxStandalone>
195
+ ),
196
+ enableSorting: false,
197
+ meta: { isFocusable: false },
198
+ })
199
+
200
+ export function BulkTable() {
201
+ const [rowSelection, setRowSelection] = useState({})
202
+ const columns = useMemo(() => [checkboxColumn, ...employeeColumns], [])
203
+ const table = useReactTable({
204
+ data,
205
+ columns,
206
+ state: { rowSelection, pagination },
207
+ onRowSelectionChange: setRowSelection,
208
+ onPaginationChange: setPagination,
209
+ enableRowSelection: true,
210
+ getCoreRowModel: getCoreRowModel(),
211
+ getPaginationRowModel: getPaginationRowModel(),
212
+ })
213
+
214
+ return (
215
+ <DataTableRoot>
216
+ <DataTable table={table}>
217
+ {row => (
218
+ <TableRow key={row.id} isSelected={row.getIsSelected()}>
219
+ {row.getVisibleCells().map(cell => (
220
+ <TableCell key={cell.id}>
221
+ {flexRender(cell.column.columnDef.cell, cell.getContext())}
222
+ </TableCell>
223
+ ))}
224
+ </TableRow>
225
+ )}
226
+ </DataTable>
227
+ <DataTableBulkActions
228
+ table={table}
229
+ actions={[
230
+ { id: 'archive', label: 'Archive', onAction: rows => archive(rows) },
231
+ { id: 'delete', label: 'Delete', onAction: rows => remove(rows) },
232
+ ]}
233
+ />
234
+ </DataTableRoot>
235
+ )
236
+ }
237
+ ```
@@ -1,12 +1,14 @@
1
1
  ---
2
2
  name: unity-find-component
3
3
  description: >
4
- Load before choosing or creating Unity UI. Use it to map a UI need to an
5
- existing @payfit/unity-components export, then fall back to React Aria plus
6
- uy: classes only when Unity has no fit.
7
- type: core
8
- library: '@payfit/unity-components'
9
- library_version: '2.x'
4
+ Load when selecting a Unity component is unclear or before creating a custom
5
+ UI primitive that may already exist in @payfit/unity-components. Use it to
6
+ find the existing component, then fall back to React Aria plus uy: classes
7
+ only when Unity has no fit.
8
+ metadata:
9
+ type: core
10
+ library: '@payfit/unity-components'
11
+ library_version: '2.x'
10
12
  sources:
11
13
  - 'PayFit/hr-apps:libs/shared/unity/components/src/index.ts'
12
14
  - 'PayFit/hr-apps:libs/shared/unity/icons/src/components/icon/parts/IconSprite.tsx'
@@ -18,100 +20,12 @@ sources:
18
20
  Routing skill for selecting a Unity component before writing UI code. Walk
19
21
  the catalog, then the decision tree, then the commonly-confused pairs.
20
22
 
21
- ## Quick Reference
22
-
23
- All exports come from a single entry: `@payfit/unity-components`. There are
24
- no sub-paths for runtime components; the only sub-paths are
25
- `@payfit/unity-components/integrations/tanstack-router` (router-aware
26
- navigation) and `@payfit/unity-components/i18n/<locale>.json` (message
27
- bundles). Names below are grouped by purpose.
28
-
29
- ### Layout
30
-
31
- `Flex`, `FlexItem`, `Grid`, `GridItem`, `Card`, `CardTitle`,
32
- `CardContent`, `SelectableCard...`, `NavigationCard`, `NavigationCardGroup`,
33
- `Page`, `PageHeader`, `PageHeading`, `AppLayout`, `AppMenu`,
34
- `FunnelLayout`, `FunnelPage`, `FunnelBody`, `FunnelSidebar`, `FunnelTopBar`,
35
- `FunnelPageHeader`, `FunnelPageContent`, `FunnelPageFooter`,
36
- `FunnelPageActions`, `FunnelBackButton`.
37
-
38
- ### Navigation
39
-
40
- Router-agnostic (base entry): `RawLink`, `RawNavItem`, `RawBreadcrumbLink`,
41
- `RawPaginationLink`, `RawPaginationPrevious`, `RawPaginationNext`, `RawTab`,
42
- `Nav`, `NavGroup`, `Breadcrumbs`, `Breadcrumb`, `Pagination`,
43
- `PaginationContent`, `PaginationItem`, `PaginationEllipsis`, `Tabs`,
44
- `TabList`, `TabPanel`, `SkipLinks`, `TaskMenu`, `RawTask`, `RawSubTask`,
45
- `TaskGroup`, `ListView`, `RawListViewItem`, `ListViewSection`,
46
- `ListViewItemLabel`, `ListViewItemText`.
47
-
48
- Router-aware (from
49
- `@payfit/unity-components/integrations/tanstack-router`): `Link`,
50
- `NavItem`, `BreadcrumbLink`, `PaginationLink`, `Tab`.
51
-
52
- ### Form fields (Tanstack Form — current)
53
-
54
- Bound via `form.AppField` then `field.<Name>`: `TextField`, `SelectField`,
55
- `NumberField`, `CheckboxField`, `CheckboxGroupField`, `DatePickerField`,
56
- `DateRangePickerField`, `MultiSelectField`, `RadioButtonGroupField`,
57
- `SelectableButtonGroupField`, `SelectableCardCheckboxGroupField`,
58
- `SelectableCardRadioGroupField`, `ToggleSwitchField`,
59
- `ToggleSwitchGroupField`, `PasswordField`.
60
-
61
- ### Form primitives (no form state)
62
-
63
- `Input`, `NumberInput`, `Select`, `SelectButton`, `SelectOption`,
64
- `SelectOptionGroup`, `SelectOptionHelper`, `MultiSelect`,
65
- `MultiSelectOption`, `MultiSelectOptGroup`, `Checkbox`, `CheckboxStandalone`,
66
- `CheckboxGroup`, `RadioButtonGroup`, `RadioButton`, `RadioButtonHelper`,
67
- `TextArea`, `ToggleSwitch`, `ToggleSwitchGroup`, `SegmentedButtonGroup`,
68
- `ToggleButton`, `SelectableButtonGroup`, `SelectableButton`, `Search`,
69
- `PhoneNumberInput`, `DatePicker`, `DateCalendar`, `DateRangePicker`,
70
- `DateRangeCalendar`, `Autocomplete`, `AutocompleteItem`,
71
- `AutocompleteItemGroup`, `Fieldset`, `FieldGroup`, `Label`, `FormField`,
72
- `FormControl`, `FormLabel`, `FormHelperText`, `FormFeedbackText`.
73
-
74
- ### Buttons and actions
75
-
76
- `Button`, `IconButton`, `CircularIconButton`, `RawLinkButton`, `Actionable`,
77
- `ActionBar`, `ActionBarRoot`, `ActionBarButton`, `ActionBarIconButton`,
78
- `FloatingActionBar`, `Anchor`.
79
-
80
- ### Overlays
81
-
82
- Modal: `Dialog`, `DialogContent`, `DialogTitle`, `DialogActions`,
83
- `DialogButton`, `PromoDialog`, `PromoDialogHero`, `PromoDialogTitle`,
84
- `PromoDialogSubtitle`, `PromoDialogContent`, `PromoDialogActions`,
85
- `SidePanel`, `SidePanelHeader`, `SidePanelContent`, `SidePanelFooter`,
86
- `BottomSheet`, `BottomSheetHeader`, `BottomSheetContent`,
87
- `BottomSheetFooter`.
88
-
89
- Non-modal: `Tooltip`, `DefinitionTooltip`, `Popover`, `Menu`, `MenuTrigger`,
90
- `MenuContent`, `MenuHeader`, `RawMenuItem`, `MenuSeparator`.
91
-
92
- ### Content and data
93
-
94
- `Text`, `Icon`, `Pill`, `Badge`, `Alert`, `AlertTitle`, `AlertContent`,
95
- `AlertActions`, `Avatar`, `AvatarFallback`, `AvatarIcon`, `AvatarImage`,
96
- `AvatarPair`, `DataTable`, `DataTableRoot`, `DataTableBulkActions`,
97
- `Table`, `TableBody`, `TableHeader`, `TableColumnHeader`, `TableRow`,
98
- `TableCell`, `TableEmptyState`, `TablePagination`, `Filter`,
99
- `FilterToolbar`, `Carousel`, `CarouselHeader`, `CarouselContent`,
100
- `CarouselSlide`, `CarouselNav`, `Collapsible`, `CollapsibleTitle`,
101
- `CollapsibleContent`, `Timeline`, `TimelineStep`, `TimelineStepHeader`,
102
- `TimelineStepDescription`.
103
-
104
- ### Status and loading
105
-
106
- `Spinner`, `ProgressBar`, `FullPageLoader`, `EmptyState`, `EmptyStateIcon`,
107
- `EmptyStateContent`, `EmptyStateActions`, `EmptyStateGetStarted`,
108
- `EmptyStateWaitingForData`, `EmptyStateGoodJob`,
109
- `EmptyStateUpgradeRequired`, `EmptyStateNoSearchResults`,
110
- `EmptyStateUseDesktop`, `ErrorState`, `ToastManager`, `toast`.
111
-
112
- ### Semantic and brand
113
-
114
- `PayFitBrand`, `PayFitPreprod`.
23
+ ## Component Catalog
24
+
25
+ Inspect the current exports in `src/index.ts`, then use the decision tree below.
26
+ For a categorized catalog of commonly used exports, read
27
+ [references/component-catalog.md](references/component-catalog.md) only when
28
+ component discovery requires it.
115
29
 
116
30
  ## Decision Tree
117
31
 
@@ -241,8 +155,8 @@ const icon: UnityIcon = 'MagnifyingGlassOutlined'
241
155
  Tanstack Form (`useTanstackUnityForm`) is the only supported form system.
242
156
  The React Hook Form path — `useUnityForm` plus the legacy `TextField` /
243
157
  `SelectField` / `NumberField` etc. RHF wrappers exported from the same
244
- index — is deprecated and scheduled for removal after the rebrand. Do not
245
- author new code with `useUnityForm`. See `unity-tanstack-form`.
158
+ index — is deprecated. Do not author new code with `useUnityForm`. See
159
+ `unity-tanstack-form`.
246
160
 
247
161
  ## Common Mistakes
248
162
 
@@ -308,7 +222,7 @@ import { Button, Dialog } from '@payfit/unity-components'
308
222
  Midnight is deprecated; new screens that import it cannot match the Unity
309
223
  theme tokens and will require a migration pass later anyway.
310
224
 
311
- Source: AGENTS.md "Do NOT use (deprecated)"; maintainer interview
225
+ Source: AGENTS.md "Do NOT use (deprecated)"
312
226
 
313
227
  ### MEDIUM Combine Input + FormField when \*Field exists
314
228
 
@@ -359,11 +273,12 @@ The `UnityIcon` literal union encodes the exact sprite ids; lowercase or
359
273
  kebab-case strings have no matching `<symbol id>` in the injected sprite,
360
274
  so `<use href="#search">` resolves to nothing and the SVG renders empty.
361
275
 
362
- Source: libs/shared/unity/icons/src/components/icon/parts/IconSprite.tsx; generated/index.ts (UnityIcon type); maintainer interview
276
+ Source: libs/shared/unity/icons/src/components/icon/parts/IconSprite.tsx; generated/index.ts (UnityIcon type)
363
277
 
364
278
  ## See also
365
279
 
366
- - `unity-setup-feature-plugin` required before any Unity import will work
280
+ - For projects not yet configured for Unity, use the repository's
281
+ `@payfit/nx-tools:setup-unity` generator
367
282
  - `unity-migrate-from-midnight` — when Level 3 fallback hits a Midnight
368
283
  screen, follow this skill to replace it
369
284
  - `unity-tanstack-form` — the only supported form authoring path
@@ -0,0 +1,94 @@
1
+ # Unity component catalog
2
+
3
+ All exports come from a single entry: `@payfit/unity-components`. There are
4
+ no sub-paths for runtime components; the only sub-paths are
5
+ `@payfit/unity-components/integrations/tanstack-router` (router-aware
6
+ navigation) and `@payfit/unity-components/i18n/<locale>.json` (message
7
+ bundles). Names below are grouped by purpose.
8
+
9
+ ### Layout
10
+
11
+ `Flex`, `FlexItem`, `Grid`, `GridItem`, `Card`, `CardTitle`,
12
+ `CardContent`, `SelectableCard...`, `NavigationCard`, `NavigationCardGroup`,
13
+ `Page`, `PageHeader`, `PageHeading`, `AppLayout`, `AppMenu`,
14
+ `FunnelLayout`, `FunnelPage`, `FunnelBody`, `FunnelSidebar`, `FunnelTopBar`,
15
+ `FunnelPageHeader`, `FunnelPageContent`, `FunnelPageFooter`,
16
+ `FunnelPageActions`, `FunnelBackButton`.
17
+
18
+ ### Navigation
19
+
20
+ Router-agnostic (base entry): `RawLink`, `RawNavItem`, `RawBreadcrumbLink`,
21
+ `RawPaginationLink`, `RawPaginationPrevious`, `RawPaginationNext`, `RawTab`,
22
+ `Nav`, `NavGroup`, `Breadcrumbs`, `Breadcrumb`, `Pagination`,
23
+ `PaginationContent`, `PaginationItem`, `PaginationEllipsis`, `Tabs`,
24
+ `TabList`, `TabPanel`, `SkipLinks`, `TaskMenu`, `RawTask`, `RawSubTask`,
25
+ `TaskGroup`, `ListView`, `RawListViewItem`, `ListViewSection`,
26
+ `ListViewItemLabel`, `ListViewItemText`.
27
+
28
+ Router-aware (from
29
+ `@payfit/unity-components/integrations/tanstack-router`): `Link`,
30
+ `NavItem`, `BreadcrumbLink`, `PaginationLink`, `Tab`.
31
+
32
+ ### Form fields (Tanstack Form — current)
33
+
34
+ Bound via `form.AppField` then `field.<Name>`: `TextField`, `SelectField`,
35
+ `NumberField`, `CheckboxField`, `CheckboxGroupField`, `DatePickerField`,
36
+ `DateRangePickerField`, `MultiSelectField`, `RadioButtonGroupField`,
37
+ `SelectableButtonGroupField`, `SelectableCardCheckboxGroupField`,
38
+ `SelectableCardRadioGroupField`, `ToggleSwitchField`,
39
+ `ToggleSwitchGroupField`, `PasswordField`.
40
+
41
+ ### Form primitives (no form state)
42
+
43
+ `Input`, `NumberInput`, `Select`, `SelectButton`, `SelectOption`,
44
+ `SelectOptionGroup`, `SelectOptionHelper`, `MultiSelect`,
45
+ `MultiSelectOption`, `MultiSelectOptGroup`, `Checkbox`, `CheckboxStandalone`,
46
+ `CheckboxGroup`, `RadioButtonGroup`, `RadioButton`, `RadioButtonHelper`,
47
+ `TextArea`, `ToggleSwitch`, `ToggleSwitchGroup`, `SegmentedButtonGroup`,
48
+ `ToggleButton`, `SelectableButtonGroup`, `SelectableButton`, `Search`,
49
+ `PhoneNumberInput`, `DatePicker`, `DateCalendar`, `DateRangePicker`,
50
+ `DateRangeCalendar`, `Autocomplete`, `AutocompleteItem`,
51
+ `AutocompleteItemGroup`, `Fieldset`, `FieldGroup`, `Label`, `FormField`,
52
+ `FormControl`, `FormLabel`, `FormHelperText`, `FormFeedbackText`.
53
+
54
+ ### Buttons and actions
55
+
56
+ `Button`, `IconButton`, `CircularIconButton`, `RawLinkButton`, `Actionable`,
57
+ `ActionBar`, `ActionBarRoot`, `ActionBarButton`, `ActionBarIconButton`,
58
+ `FloatingActionBar`, `Anchor`.
59
+
60
+ ### Overlays
61
+
62
+ Modal: `Dialog`, `DialogContent`, `DialogTitle`, `DialogActions`,
63
+ `DialogButton`, `PromoDialog`, `PromoDialogHero`, `PromoDialogTitle`,
64
+ `PromoDialogSubtitle`, `PromoDialogContent`, `PromoDialogActions`,
65
+ `SidePanel`, `SidePanelHeader`, `SidePanelContent`, `SidePanelFooter`,
66
+ `BottomSheet`, `BottomSheetHeader`, `BottomSheetContent`,
67
+ `BottomSheetFooter`.
68
+
69
+ Non-modal: `Tooltip`, `DefinitionTooltip`, `Popover`, `Menu`, `MenuTrigger`,
70
+ `MenuContent`, `MenuHeader`, `RawMenuItem`, `MenuSeparator`.
71
+
72
+ ### Content and data
73
+
74
+ `Text`, `Icon`, `Pill`, `Badge`, `Alert`, `AlertTitle`, `AlertContent`,
75
+ `AlertActions`, `Avatar`, `AvatarFallback`, `AvatarIcon`, `AvatarImage`,
76
+ `AvatarPair`, `DataTable`, `DataTableRoot`, `DataTableBulkActions`,
77
+ `Table`, `TableBody`, `TableHeader`, `TableColumnHeader`, `TableRow`,
78
+ `TableCell`, `TableEmptyState`, `TablePagination`, `Filter`,
79
+ `FilterToolbar`, `Carousel`, `CarouselHeader`, `CarouselContent`,
80
+ `CarouselSlide`, `CarouselNav`, `Collapsible`, `CollapsibleTitle`,
81
+ `CollapsibleContent`, `Timeline`, `TimelineStep`, `TimelineStepHeader`,
82
+ `TimelineStepDescription`.
83
+
84
+ ### Status and loading
85
+
86
+ `Spinner`, `ProgressBar`, `FullPageLoader`, `EmptyState`, `EmptyStateIcon`,
87
+ `EmptyStateContent`, `EmptyStateActions`, `EmptyStateGetStarted`,
88
+ `EmptyStateWaitingForData`, `EmptyStateGoodJob`,
89
+ `EmptyStateUpgradeRequired`, `EmptyStateNoSearchResults`,
90
+ `EmptyStateUseDesktop`, `ErrorState`, `ToastManager`, `toast`.
91
+
92
+ ### Semantic and brand
93
+
94
+ `PayFitBrand`, `PayFitPreprod`.
@@ -4,9 +4,10 @@ description: >
4
4
  Load when composing Unity layouts or styling with uy: Tailwind utilities.
5
5
  Use it for Flex/Grid/Text choices, class merging/variants, and validating
6
6
  Unity token names before adding styles.
7
- type: core
8
- library: '@payfit/unity-components, @payfit/unity-themes'
9
- library_version: '2.x'
7
+ metadata:
8
+ type: core
9
+ library: '@payfit/unity-components, @payfit/unity-themes'
10
+ library_version: '2.x'
10
11
  sources:
11
12
  - 'PayFit/hr-apps:libs/shared/unity/components/src/components/flex/Flex.tsx'
12
13
  - 'PayFit/hr-apps:libs/shared/unity/components/src/components/grid/Grid.tsx'
@@ -50,143 +51,15 @@ export function PayslipSummary() {
50
51
 
51
52
  ## Core Patterns
52
53
 
53
- ### Flex for 1D, Grid for 2D
54
+ - Use `Flex` for one-dimensional layout and `Grid` for two-dimensional layout.
55
+ - Express responsiveness and interaction states with `uy:` variants.
56
+ - Use `uyTv` for typed component variants, `uyMerge` when merging external
57
+ classes, and `cn` for simple conditional strings.
58
+ - Use `Text` variants for typography and prefer exposed `data-*` states over
59
+ raw hover selectors when components provide them.
54
60
 
55
- `Flex` is for one-dimensional rows/columns; `Grid` is for the 12-column (or 6-column)
56
- two-dimensional layout. Each exposes layout props; everything else goes via
57
- `className` with `uy:` utilities.
58
-
59
- ```tsx
60
- import { Flex, FlexItem, Grid, GridItem } from '@payfit/unity-components'
61
-
62
- // Flex props: asElement, inline, direction, isReversed, wrap,
63
- // gap, gapX, gapY, justify, align, alignContent, className
64
- <Flex direction="row" gap="200" justify="between" align="center">
65
- <FlexItem grow="1">Left</FlexItem>
66
- <FlexItem>Right</FlexItem>
67
- </Flex>
68
-
69
- // Grid props: asElement, inline, cols (6 | 12), rows, areas, flow,
70
- // justifyItems, alignItems, className
71
- // GridItem positions via colSpan/colStart/colEnd OR area (mutually exclusive)
72
- <Grid cols={12} className="uy:gap-200">
73
- <GridItem colSpan={8}>Main</GridItem>
74
- <GridItem colSpan={4}>Aside</GridItem>
75
- </Grid>
76
- ```
77
-
78
- ### Responsive classes via uy:md:
79
-
80
- There is no responsive prop-object API. Responsive behavior is driven by
81
- TailwindCSS v4 modifiers on `className`.
82
-
83
- ```tsx
84
- <Flex gap="100" className="uy:md:gap-200 uy:lg:gap-300">
85
- <span>Item</span>
86
- </Flex>
87
-
88
- <Grid cols={12} className="uy:grid-cols-1 uy:md:grid-cols-2 uy:lg:grid-cols-3" />
89
- ```
90
-
91
- ### Variants with uyTv
92
-
93
- `uyTv` from `@payfit/unity-themes` is the pre-configured tailwind-variants
94
- factory. It applies the Unity `twMergeConfig` so variant collisions resolve
95
- against Unity tokens. Export the variant function and derive its typed props
96
- with `VariantProps`.
97
-
98
- ```tsx
99
- import type { VariantProps } from '@payfit/unity-themes'
100
-
101
- import { uyTv } from '@payfit/unity-themes'
102
-
103
- export const callout = uyTv({
104
- base: 'uy:inline-flex uy:items-center uy:gap-100 uy:rounded-100 uy:px-200 uy:py-100',
105
- variants: {
106
- intent: {
107
- info: 'uy:bg-surface-primary-default uy:text-content-inverted-default',
108
- danger: 'uy:bg-surface-danger-default uy:text-content-inverted-default',
109
- neutral: 'uy:bg-surface-neutral-default uy:text-content-neutral-default',
110
- },
111
- size: {
112
- sm: 'uy:typography-body-small',
113
- md: 'uy:typography-body',
114
- },
115
- },
116
- defaultVariants: { intent: 'info', size: 'md' },
117
- })
118
-
119
- export type CalloutVariantProps = VariantProps<typeof callout>
120
- ```
121
-
122
- ### Class merging with uyMerge
123
-
124
- `uyMerge` is `tailwind-merge` configured with Unity's class groups. Use it
125
- whenever an external `className` may collide with internal classes.
126
-
127
- ```tsx
128
- import { uyMerge } from '@payfit/unity-themes'
129
-
130
- uyMerge('uy:p-100', 'uy:p-200') // → 'uy:p-200'
131
- uyMerge('uy:bg-surface-primary-default', 'uy:bg-surface-danger-default')
132
- // → 'uy:bg-surface-danger-default'
133
- uyMerge('uy:p-100', 'uy:px-200', 'uy:py-300') // p, px, py don't collide
134
- ```
135
-
136
- ### Conditional classes with cn / classNames / clsx
137
-
138
- `cn`, `classNames`, and `clsx` are aliases for the same Unity-configured helper
139
- in `@payfit/unity-themes`. Use them for ad-hoc conditional strings — not for
140
- component-scoped variant APIs.
141
-
142
- ```tsx
143
- import { cn } from '@payfit/unity-themes'
144
-
145
- function Row({
146
- isActive,
147
- className,
148
- }: {
149
- isActive: boolean
150
- className?: string
151
- }) {
152
- return (
153
- <div
154
- className={cn(
155
- 'uy:flex uy:items-center uy:px-200 uy:py-100',
156
- isActive && 'uy:bg-surface-primary-default',
157
- className,
158
- )}
159
- />
160
- )
161
- }
162
- ```
163
-
164
- ### Typography with `<Text>`
165
-
166
- Use `<Text variant=...>` instead of a `<div>` + typography class. `Text`
167
- picks a semantic element from the variant (e.g. `variant="h1"` → `<h1>`),
168
- applies the typography variant, and exposes `color`, `isTruncated`,
169
- `lineClamp`, and `maxWidthCh`.
170
-
171
- ```tsx
172
- import { Text } from '@payfit/unity-components'
173
-
174
- <Text variant="h1" color="content.primary">Title</Text>
175
- <Text variant="body" color="content.neutral">Description</Text>
176
- // Override the semantic element when needed:
177
- <Text variant="h1" asElement="h2">Visual h1, semantic h2</Text>
178
- ```
179
-
180
- ### Data-attribute pseudo-states
181
-
182
- Several Unity components expose internal state via `data-hovered`,
183
- `data-pressed`, `data-focus-visible`, etc. Target the component-owned state
184
- attribute rather than the native CSS pseudo-state.
185
-
186
- ```tsx
187
- import { ListViewItem } from '@payfit/unity-components'
188
- ;<ListViewItem className="uy:data-[hovered=true]:bg-surface-primary-hover" />
189
- ```
61
+ Read [references/patterns.md](references/patterns.md) for implementation
62
+ examples.
190
63
 
191
64
  ## Common Mistakes
192
65
 
@@ -327,7 +200,7 @@ Correct:
327
200
 
328
201
  Agents generate names that match standard Tailwind conventions but are not in the Unity token set; the class is absent from the compiled stylesheet, the element silently renders with no style.
329
202
 
330
- Source: maintainer interview; themes/dist/css/unity.css (@theme block enumerates valid tokens)
203
+ Source: themes/dist/css/unity.css (@theme block enumerates valid tokens)
331
204
 
332
205
  ### MEDIUM Reach for cn() to compose variant classes when uyTv fits
333
206
 
@@ -382,7 +255,7 @@ function Pill(props: PillProps) {
382
255
 
383
256
  cn() / classNames / clsx are for ad-hoc conditional class strings; component-scoped variant APIs with multiple axes (size × color × intent) belong in `uyTv`, which gives a typed `VariantProps` signature and pre-applied conflict resolution.
384
257
 
385
- Source: maintainer interview; themes/src/utils/tailwind-variants.ts
258
+ Source: themes/src/utils/tailwind-variants.ts
386
259
 
387
260
  ## See also
388
261