@payfit/unity-components 2.56.0 → 2.56.2

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@payfit/unity-components",
3
- "version": "2.56.0",
3
+ "version": "2.56.2",
4
4
  "module": "./dist/esm/index.js",
5
5
  "type": "module",
6
6
  "sideEffects": false,
@@ -96,7 +96,7 @@
96
96
  "tailwind-variants": "3.2.2",
97
97
  "usehooks-ts": "3.1.1",
98
98
  "zod": "4.4.3",
99
- "@payfit/unity-illustrations": "2.56.0"
99
+ "@payfit/unity-illustrations": "2.56.2"
100
100
  },
101
101
  "peerDependencies": {
102
102
  "@hookform/devtools": "^4",
@@ -108,8 +108,8 @@
108
108
  "react-hook-form": "^7",
109
109
  "react-router-dom": "^5",
110
110
  "zod": "^3 || ^4",
111
- "@payfit/unity-icons": "2.56.0",
112
- "@payfit/unity-themes": "2.56.0"
111
+ "@payfit/unity-themes": "2.56.2",
112
+ "@payfit/unity-icons": "2.56.2"
113
113
  },
114
114
  "devDependencies": {
115
115
  "@figma/code-connect": "1.4.9",
@@ -159,10 +159,10 @@
159
159
  "@payfit/hr-apps-tsconfigs": "0.0.0-use.local",
160
160
  "@payfit/storybook-addon-console-errors": "0.0.0-use.local",
161
161
  "@payfit/storybook-config": "0.0.0-use.local",
162
- "@payfit/unity-icons": "2.56.0",
163
- "@payfit/unity-illustrations": "2.56.0",
164
- "@payfit/unity-themes": "2.56.0",
165
- "@payfit/vite-configs": "0.0.0-use.local"
162
+ "@payfit/unity-icons": "2.56.2",
163
+ "@payfit/vite-configs": "0.0.0-use.local",
164
+ "@payfit/unity-themes": "2.56.2",
165
+ "@payfit/unity-illustrations": "2.56.2"
166
166
  },
167
167
  "peerDependenciesMeta": {
168
168
  "@hookform/devtools": {
@@ -30,13 +30,21 @@ rg -i -C 2 'dialog|confirmation|modal' \
30
30
 
31
31
  ## Standard operating procedure
32
32
 
33
- 1. Extract the user's intent and expand it into synonyms, interaction patterns, and adjacent component terms.
34
- 2. Search the complete catalog; do not stop at the first slice or plausible hit.
35
- 3. Rank candidates by intent fit, description, keywords, tags, section, and related entries.
36
- 4. Return the best match first. Mention an alternative only when the evidence is genuinely ambiguous.
37
- 5. Search `libs/shared/unity/components/src` to confirm implementation details or locate nearby source.
38
- 6. Inspect Storybook stories only for props, API details, or usage examples after a likely component has been identified. When the Storybook MCP is available, use its curated component manifest or matching Storybook entry as a complementary source for rendered examples; the canonical JSON catalog remains the source of truth for discovery.
39
- 7. Walk the decision tree below before creating a custom primitive.
33
+ 1. Build an inventory of distinct interface needs from all task inputs,
34
+ including the primary workflow, surrounding controls, navigation, status
35
+ information, and secondary actions. Do not silently omit peripheral UI.
36
+ 2. Expand every identified need into synonyms, interaction patterns, and
37
+ adjacent component terms.
38
+ 3. Search the complete catalog for every inventory item; do not stop after
39
+ finding components for the primary workflow or at the first plausible hit.
40
+ 4. Rank candidates by intent fit, description, keywords, tags, section, and related entries.
41
+ 5. Return the best match first. Mention an alternative only when the evidence is genuinely ambiguous.
42
+ 6. Search `libs/shared/unity/components/src` to confirm implementation details or locate nearby source.
43
+ 7. Inspect Storybook stories only for props, API details, or usage examples after a likely component has been identified. When the Storybook MCP is available, use its curated component manifest or matching Storybook entry as a complementary source for rendered examples; the canonical JSON catalog remains the source of truth for discovery.
44
+ 8. Walk the decision tree below for every identified need before creating a custom primitive.
45
+ 9. Before implementation, perform a coverage check: every inventoried
46
+ interface need must map to a Unity component, an explicit React Aria
47
+ fallback, or a deliberate omission requested by the user.
40
48
 
41
49
  ## Decision Tree
42
50
 
@@ -131,6 +139,9 @@ import it into a new module.
131
139
  text. `IconButton` / `CircularIconButton` for icon-only actions
132
140
  (requires `aria-label`). `RawLinkButton` renders as an anchor but styled
133
141
  like a button — use when the action navigates.
142
+ - `Search` vs `TextField`: use `Search` for query, lookup, and filtering
143
+ controls with search affordances and clearing behavior. Use `TextField` for
144
+ general textual data entry.
134
145
  - `Menu` vs `Popover`: `Menu` is a list of actionable items keyed by
135
146
  keyboard (Enter/Arrow). `Popover` is a free-form floating panel and
136
147
  requires a `title`.
@@ -144,22 +155,12 @@ import it into a new module.
144
155
  for "this section failed to load." `Alert` is an inline banner that
145
156
  coexists with surrounding content.
146
157
 
147
- ## Icon Source Convention
158
+ ## Icon selection
148
159
 
149
- `Icon` takes a typed `src` prop of type `UnityIcon` a literal union of
150
- PascalCase names with a `Filled` or `Outlined` suffix (~310 values, from
151
- `@payfit/unity-icons`). Strings outside that union are a type error. Do
152
- not cast to `UnityIcon`; the cast bypasses the sprite-id guard and the
153
- icon silently renders empty.
154
-
155
- ```tsx
156
- import type { UnityIcon } from '@payfit/unity-icons'
157
-
158
- import { Icon } from '@payfit/unity-components'
159
-
160
- const icon: UnityIcon = 'MagnifyingGlassOutlined'
161
- ;<Icon src={icon} size={20} />
162
- ```
160
+ Choose the component here (`Icon`, `IconButton`, a prefix/suffix icon, and so
161
+ on), then use `unity-icons` to select an exact sprite name, type shared icon
162
+ props, or migrate a Midnight icon. Do not duplicate or guess the icon catalog
163
+ from the Components package.
163
164
 
164
165
  ## Forms Notice
165
166
 
@@ -259,37 +260,11 @@ that the `*Field` components handle.
259
260
 
260
261
  Source: libs/shared/unity/components/src/components/form-field/FormField.tsx; index.ts:205-223
261
262
 
262
- ### HIGH Pass an untyped string to Icon src and guess the name
263
-
264
- Wrong:
265
-
266
- ```tsx
267
- <Icon src="search" size={20} />
268
- <Icon src="trash-filled" />
269
- const name: string = 'trash'
270
- <Icon src={name as UnityIcon} />
271
- ```
272
-
273
- Correct:
274
-
275
- ```tsx
276
- import { Icon } from '@payfit/unity-components'
277
- import type { UnityIcon } from '@payfit/unity-icons'
278
- <Icon src="MagnifyingGlassOutlined" size={20} />
279
- <Icon src="TrashFilled" />
280
- type Props = { icon: UnityIcon }
281
- ```
282
-
283
- The `UnityIcon` literal union encodes the exact sprite ids; lowercase or
284
- kebab-case strings have no matching `<symbol id>` in the injected sprite,
285
- so `<use href="#search">` resolves to nothing and the SVG renders empty.
286
-
287
- Source: libs/shared/unity/icons/src/components/icon/parts/IconSprite.tsx; generated/index.ts (UnityIcon type)
288
-
289
263
  ## See also
290
264
 
291
265
  - For projects not yet configured for Unity, use the repository's
292
266
  `@payfit/nx-tools:setup-unity` generator
293
267
  - `unity-migrate-from-midnight` — when Level 3 fallback hits a Midnight
294
268
  screen, follow this skill to replace it
269
+ - `unity-icons` — select and type the exact icon after choosing the component
295
270
  - `unity-tanstack-form` — the only supported form authoring path
@@ -0,0 +1,130 @@
1
+ ---
2
+ name: unity-layout
3
+ description: >
4
+ Load when composing page or component layouts with Unity Page, PageHeader,
5
+ PageHeading, Flex, FlexItem, Grid, GridItem, or Text. Use it to choose the
6
+ right layout primitive, preserve semantic typography, and replace removed
7
+ responsive prop objects.
8
+ metadata:
9
+ type: core
10
+ library: '@payfit/unity-components'
11
+ library_version: '2.x'
12
+ sources:
13
+ - 'PayFit/hr-apps:libs/shared/unity/components/src/components/page/Page.tsx'
14
+ - 'PayFit/hr-apps:libs/shared/unity/components/src/components/page/parts/PageHeader.tsx'
15
+ - 'PayFit/hr-apps:libs/shared/unity/components/src/components/page/parts/PageHeading.tsx'
16
+ - 'PayFit/hr-apps:libs/shared/unity/components/src/components/flex/Flex.tsx'
17
+ - 'PayFit/hr-apps:libs/shared/unity/components/src/components/grid/Grid.tsx'
18
+ - 'PayFit/hr-apps:libs/shared/unity/components/src/components/text/Text.tsx'
19
+ ---
20
+
21
+ Compose structure with the layout and typography primitives exported by
22
+ `@payfit/unity-components`.
23
+
24
+ ## Choose the primitive
25
+
26
+ - Use `Page`, `PageHeader`, and `PageHeading` for the main Unity page shell
27
+ when an installed `Page` variant fits the application layout.
28
+ - Use `Flex` and `FlexItem` for one-dimensional rows or columns.
29
+ - Use `Grid` and `GridItem` when positioning content across rows and columns.
30
+ - Use `Text` for semantic Unity typography instead of styling a generic
31
+ element with typography classes.
32
+ - Use component props for the base layout. Use `uy:` responsive utilities in
33
+ `className` for breakpoint-specific changes; responsive prop objects were
34
+ removed in Unity v1.
35
+
36
+ ```tsx
37
+ import { Card, Flex, Grid, GridItem, Text } from '@payfit/unity-components'
38
+
39
+ export function PayslipSummary() {
40
+ return (
41
+ <Card>
42
+ <Flex direction="col" gap="200">
43
+ <Text variant="h3" asElement="h2">
44
+ Payslip
45
+ </Text>
46
+ <Grid cols={12} className="uy:gap-200 uy:md:gap-300">
47
+ <GridItem colSpan={6}>Gross</GridItem>
48
+ <GridItem colSpan={6}>Net</GridItem>
49
+ </Grid>
50
+ </Flex>
51
+ </Card>
52
+ )
53
+ }
54
+ ```
55
+
56
+ ## Page containers
57
+
58
+ Use `Page` as the main Unity page shell when one of its installed variants
59
+ matches the application layout.
60
+
61
+ Before composing the surrounding layout, inspect the installed `Page`
62
+ implementation and its variants to understand the spacing, sizing, background,
63
+ border, and responsive behavior it already provides. These details belong to
64
+ the installed component version; do not infer them from memory or duplicate
65
+ them in an outer wrapper.
66
+
67
+ The parent of `Page` should normally define only the space available within the
68
+ application shell. Do not add redundant padding, margins, backgrounds,
69
+ borders, or arbitrary maximum widths around `Page`.
70
+
71
+ When only part of the page needs a width constraint, apply it to the relevant
72
+ content section, form, card, or grid instead of constraining the entire `Page`.
73
+
74
+ If the available `Page` variants do not fit the intended shell, confirm the
75
+ component API and inspect nearby usage before introducing a wrapper or custom
76
+ layout.
77
+
78
+ Read [references/patterns.md](references/patterns.md) for the supported layout
79
+ props and responsive composition examples.
80
+
81
+ ## Common mistakes
82
+
83
+ ### Use Flex for a two-dimensional layout
84
+
85
+ Use `Grid` when items need explicit row and column placement. Nested `Flex`
86
+ containers obscure the intended structure and make responsive changes harder.
87
+
88
+ ### Pass responsive prop objects
89
+
90
+ Wrong:
91
+
92
+ ```tsx
93
+ <Flex gap={{ initial: '100', md: '200' }} />
94
+ ```
95
+
96
+ Correct:
97
+
98
+ ```tsx
99
+ <Flex gap="100" className="uy:md:gap-200" />
100
+ ```
101
+
102
+ ### Use a generic element for semantic typography
103
+
104
+ Wrong:
105
+
106
+ ```tsx
107
+ <div className="uy:typography-h1">Title</div>
108
+ ```
109
+
110
+ Correct:
111
+
112
+ ```tsx
113
+ <Text variant="h1">Title</Text>
114
+ ```
115
+
116
+ Override `asElement` only when the document hierarchy requires a different
117
+ semantic element from the visual variant.
118
+
119
+ ### Duplicate Page layout constraints
120
+
121
+ Do not treat `Page` as an unstyled `main` element. Inspect the installed
122
+ variant before adding an outer wrapper: duplicating its spacing, background,
123
+ border, or width constraints can compress the whole page unexpectedly.
124
+
125
+ ## See also
126
+
127
+ - `unity-themes` — token lookup, `uy:` utilities, responsive and state
128
+ modifiers, class merging, and typed variants.
129
+ - `unity-find-component` — choose a higher-level Unity component before
130
+ composing a custom primitive.
@@ -0,0 +1,59 @@
1
+ # Unity layout patterns
2
+
3
+ ## Flex for one dimension
4
+
5
+ Use `Flex` for a row or column and `FlexItem` for item-level growth or
6
+ alignment.
7
+
8
+ ```tsx
9
+ import { Flex, FlexItem } from '@payfit/unity-components'
10
+ ;<Flex direction="row" gap="200" justify="between" align="center">
11
+ <FlexItem grow="1">Left</FlexItem>
12
+ <FlexItem>Right</FlexItem>
13
+ </Flex>
14
+ ```
15
+
16
+ `Flex` exposes `asElement`, `inline`, `direction`, `isReversed`, `wrap`,
17
+ `gap`, `gapX`, `gapY`, `justify`, `align`, `alignContent`, and `className`.
18
+
19
+ ## Grid for two dimensions
20
+
21
+ Use `Grid` when content needs row and column placement. Position a `GridItem`
22
+ with either `area` or the column props; do not combine the two strategies.
23
+
24
+ ```tsx
25
+ import { Grid, GridItem } from '@payfit/unity-components'
26
+ ;<Grid cols={12} className="uy:gap-200">
27
+ <GridItem colSpan={8}>Main</GridItem>
28
+ <GridItem colSpan={4}>Aside</GridItem>
29
+ </Grid>
30
+ ```
31
+
32
+ `Grid` exposes `asElement`, `inline`, `cols`, `rows`, `areas`, `flow`,
33
+ `justifyItems`, `alignItems`, and `className`.
34
+
35
+ ## Responsive layout
36
+
37
+ Set the default through props, then apply breakpoint changes with `uy:`
38
+ utilities. Read `unity-themes` before choosing utility or token names.
39
+
40
+ ```tsx
41
+ <Flex gap="100" className="uy:md:gap-200 uy:lg:gap-300">
42
+ <span>Item</span>
43
+ </Flex>
44
+
45
+ <Grid cols={12} className="uy:grid-cols-1 uy:md:grid-cols-2 uy:lg:grid-cols-3" />
46
+ ```
47
+
48
+ ## Semantic typography
49
+
50
+ `Text` selects a semantic element from its variant and supports an explicit
51
+ `asElement` override.
52
+
53
+ ```tsx
54
+ import { Text } from '@payfit/unity-components'
55
+
56
+ <Text variant="h1" color="content.primary">Title</Text>
57
+ <Text variant="body" color="content.neutral">Description</Text>
58
+ <Text variant="h1" asElement="h2">Visual h1, semantic h2</Text>
59
+ ```
@@ -184,3 +184,5 @@ Source: no Unity equivalent for Midnight transition helpers
184
184
  `Popover`, `Menu`
185
185
  - `unity-tanstack-form` — replacement path for RHF forms in the migrated
186
186
  screen
187
+ - `unity-icons` — select and type replacements for Midnight icons
188
+ - `unity-illustrations` — select, load, and describe replacement artwork
@@ -143,14 +143,14 @@ look like a link.
143
143
 
144
144
  ## Media
145
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 |
146
+ | Midnight | Unity | Note |
147
+ | -------------- | ------------------------------------------------------------------- | ----------------------------------------------------------- |
148
+ | `Avatar` | `Avatar` | `type` → `variant` (circle/square) |
149
+ | `AvatarGroup` | — | No equivalent (planned) |
150
+ | `Icon` | `Icon` (`@payfit/unity-icons`) | Select and type the target with `unity-icons` |
151
+ | `Illustration` | `Illustration` / `LazyIllustration` (`@payfit/unity-illustrations`) | Select loading and accessibility with `unity-illustrations` |
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
154
 
155
155
  ## Misc
156
156
 
@@ -173,8 +173,8 @@ Unity primitive.
173
173
  | `v2/Box` | `Flex` / `Grid` | Same guidance as v1 `Box` |
174
174
  | `v2/Flex` | `Flex` | Drop the `v2/` namespace; same props |
175
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` |
176
+ | `v2/Icon` | `Icon` (`@payfit/unity-icons`) | Select and type the target with `unity-icons` |
177
+ | `v2/Illustration` | `Illustration` / `LazyIllustration` (`@payfit/unity-illustrations`) | Select loading and accessibility with `unity-illustrations` |
178
178
  | `v2/Image` | native `<img>` | — |
179
179
  | `v2/PageLayout` | `AppLayout` / `Page` | `AppLayout` for the app shell; `Page` for the content surface |
180
180
  | `v2/Stack` | `Flex` (with `direction` + `gap`) | — |
@@ -223,5 +223,7 @@ Source: components/promo-dialog/PromoDialog.tsx:230-236 (console.error guard)
223
223
  - `unity-migrate-from-midnight` — the disabled+tooltip trap is the most
224
224
  common Midnight-era pattern that Unity blocks; the migration skill covers
225
225
  the rewrite.
226
- - `unity-layout-and-styling` — overlay content uses the same `uy:` utility
227
- classes (Flex/Grid, spacing, `uy:data-[hovered=true]:…`).
226
+ - `unity-layout` — compose overlay content with Flex and Grid.
227
+ - `unity-themes` — apply spacing and component-owned `data-*` state styles.
228
+ - `unity-illustrations` — select and load the artwork required by
229
+ `PromoDialogHero`.
@@ -252,5 +252,6 @@ Source: TanstackTextField.tsx; TanstackFormField.tsx and its parts
252
252
  ## See also
253
253
 
254
254
  - `unity-migrate-from-midnight` — forms migrated off Midnight typically came with React Hook Form; that skill explains the Tanstack-only replacement path.
255
- - `unity-layout-and-styling` — form layouts use Flex/Grid and `uy:*` utilities for spacing and responsive behavior.
255
+ - `unity-layout` — compose form layouts with Flex and Grid.
256
+ - `unity-themes` — use `uy:*` spacing and responsive utilities.
256
257
  - `unity-navigation` — when a form posts via a route action or links to a sibling step, use the router-aware `Link` from `@payfit/unity-components/integrations/tanstack-router`.
@@ -1,278 +0,0 @@
1
- ---
2
- name: unity-layout-and-styling
3
- description: >
4
- Load when composing Unity layouts or styling with uy: Tailwind utilities.
5
- Use it for Flex/Grid/Text choices, class merging/variants, and validating
6
- Unity token names before adding styles.
7
- metadata:
8
- type: core
9
- library: '@payfit/unity-components, @payfit/unity-themes'
10
- library_version: '2.x'
11
- sources:
12
- - 'PayFit/hr-apps:libs/shared/unity/components/src/components/flex/Flex.tsx'
13
- - 'PayFit/hr-apps:libs/shared/unity/components/src/components/grid/Grid.tsx'
14
- - 'PayFit/hr-apps:libs/shared/unity/components/src/components/text/Text.tsx'
15
- - 'PayFit/hr-apps:libs/shared/unity/themes/src/utils/tailwind-merge.ts'
16
- - 'PayFit/hr-apps:libs/shared/unity/themes/src/utils/tailwind-variants.ts'
17
- - 'PayFit/hr-apps:libs/shared/unity/themes/src/utils/cn.ts'
18
- - 'PayFit/hr-apps:libs/shared/unity/themes/src/scripts/build.ts'
19
- ---
20
-
21
- Layout primitives, the `uy:` utility-class system, and the variant/merge tools
22
- used inside `@payfit/unity-components`.
23
-
24
- ## Token lookup SOP
25
-
26
- Before implementation, perform a targeted search of
27
- `tokens-catalog.json` using `rg`, `jq`, or another file-reading command.
28
- Loading this skill alone does not count as consulting the catalog.
29
-
30
- Before adding a token-based utility, search the canonical [Unity token catalog](../../../themes/src/agent-references/tokens-catalog.json).
31
- Use its exact `name` and `cssVariable`, then consult the generated theme
32
- blueprints under `../../../themes/src/storybook-mcp/` for common class
33
- patterns. Do not infer token names from raw DTCG paths or standard Tailwind
34
- conventions when the catalog can provide the transformed name.
35
-
36
- ## Setup
37
-
38
- ```tsx
39
- import { Card, Flex, Grid, Text } from '@payfit/unity-components'
40
-
41
- export function PayslipSummary() {
42
- return (
43
- <Card>
44
- <Flex direction="col" gap="200" className="uy:p-300">
45
- <Text variant="h3" asElement="h2">
46
- Payslip
47
- </Text>
48
- <Grid cols={12} className="uy:gap-200 uy:md:gap-300">
49
- <Flex direction="col" className="uy:col-span-12 uy:md:col-span-6">
50
- <Text variant="overline">Gross</Text>
51
- <Text variant="bodyLargeStrong">€ 4,200.00</Text>
52
- </Flex>
53
- <Flex direction="col" className="uy:col-span-12 uy:md:col-span-6">
54
- <Text variant="overline">Net</Text>
55
- <Text variant="bodyLargeStrong">€ 3,150.00</Text>
56
- </Flex>
57
- </Grid>
58
- </Flex>
59
- </Card>
60
- )
61
- }
62
- ```
63
-
64
- ## Core Patterns
65
-
66
- - Use `Flex` for one-dimensional layout and `Grid` for two-dimensional layout.
67
- - Express responsiveness and interaction states with `uy:` variants.
68
- - Use `uyTv` for typed component variants, `uyMerge` when merging external
69
- classes, and `cn` for simple conditional strings.
70
- - Use `Text` variants for typography and prefer exposed `data-*` states over
71
- raw hover selectors when components provide them.
72
-
73
- Read [references/patterns.md](references/patterns.md) for implementation
74
- examples.
75
-
76
- ## Common Mistakes
77
-
78
- ### CRITICAL Use bare Tailwind classes without uy: prefix
79
-
80
- Wrong:
81
-
82
- ```tsx
83
- <Flex className="flex gap-4 p-3"> … </Flex>
84
- ```
85
-
86
- Correct:
87
-
88
- ```tsx
89
- <Flex gap="100" className="uy:p-300">
90
- {' '}
91
- …{' '}
92
- </Flex>
93
- ```
94
-
95
- Unity CSS is built with `prefix(uy)`; bare classes are not in the compiled stylesheet and produce no styling.
96
-
97
- Source: themes/src/scripts/build.ts:298 (prefix(uy) import)
98
-
99
- ### HIGH Pass responsive prop objects (v0.x style)
100
-
101
- Wrong:
102
-
103
- ```tsx
104
- <Flex gap={{ initial: '100', md: '200' }} />
105
- ```
106
-
107
- Correct:
108
-
109
- ```tsx
110
- <Flex gap="100" className="uy:md:gap-200" />
111
- ```
112
-
113
- v1.x removed the responsive prop-object API. Use className with uy:md: et al.
114
-
115
- Source: components/flex/Flex.tsx:33; themes/docs/files/MIGRATION-v1.md
116
-
117
- ### HIGH Import twMerge from tailwind-merge directly
118
-
119
- Wrong:
120
-
121
- ```tsx
122
- import { twMerge } from 'tailwind-merge'
123
-
124
- twMerge('uy:p-100', 'uy:p-200')
125
- ```
126
-
127
- Correct:
128
-
129
- ```tsx
130
- import { uyMerge } from '@payfit/unity-themes'
131
-
132
- uyMerge('uy:p-100', 'uy:p-200') // → 'uy:p-200'
133
- ```
134
-
135
- The unconfigured twMerge has no knowledge of Unity tokens; class conflicts on uy:bg-surface-primary-default vs uy:bg-surface-danger-default are not resolved.
136
-
137
- Source: themes/src/utils/tailwind-merge.ts:1-7,75-77
138
-
139
- ### HIGH Import tv from tailwind-variants directly
140
-
141
- Wrong:
142
-
143
- ```tsx
144
- import { tv } from 'tailwind-variants'
145
- export const button = tv({ base: 'uy:px-200', variants: {...} })
146
- ```
147
-
148
- Correct:
149
-
150
- ```tsx
151
- import { uyTv } from '@payfit/unity-themes'
152
- export const button = uyTv({ base: 'uy:px-200', variants: {...} })
153
- ```
154
-
155
- tv() is unconfigured; uyTv pre-applies the Unity twMergeConfig so variant conflict resolution understands Unity tokens.
156
-
157
- Source: themes/src/utils/tailwind-variants.ts:48-51
158
-
159
- ### MEDIUM Use <div> + typography class instead of <Text>
160
-
161
- Wrong:
162
-
163
- ```tsx
164
- <div className="uy:typography-h1 uy:text-content-primary">Title</div>
165
- ```
166
-
167
- Correct:
168
-
169
- ```tsx
170
- <Text variant="h1" color="content.primary">
171
- Title
172
- </Text>
173
- ```
174
-
175
- `<Text variant="h1">` auto-selects the correct semantic element (h1) and applies the Unity typography variant; `<div>` loses the semantics and the variant API.
176
-
177
- Source: components/text/Text.tsx:60-104,137-139
178
-
179
- ### MEDIUM Use uy:hover: when component exposes data-\* state
180
-
181
- Wrong:
182
-
183
- ```tsx
184
- <ListViewItem className="uy:hover:bg-surface-primary-hover" />
185
- ```
186
-
187
- Correct:
188
-
189
- ```tsx
190
- <ListViewItem className="uy:data-[hovered=true]:bg-surface-primary-hover" />
191
- ```
192
-
193
- Some Unity components manage state via data-hovered, data-selected, etc. `uy:data-[hovered=true]:` targets the component-managed state and avoids drift.
194
-
195
- Source: themes/src/scripts/build.ts:303-307 (custom-variant for data attrs)
196
-
197
- ### HIGH Hallucinate token names that look plausible but do not exist
198
-
199
- Wrong:
200
-
201
- ```tsx
202
- <div className="uy:bg-primary-500 uy:text-gray-900 uy:border-blue-600" />
203
- ```
204
-
205
- Correct:
206
-
207
- ```tsx
208
- // Use Unity's semantic token names (verify against the live class index
209
- // in themes docs or the @theme block in dist/css/unity.css):
210
- <div className="uy:bg-surface-primary-default uy:text-content-primary uy:border-surface-primary-active" />
211
- ```
212
-
213
- 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.
214
-
215
- Source: themes/dist/css/unity.css (@theme block enumerates valid tokens)
216
-
217
- ### MEDIUM Reach for cn() to compose variant classes when uyTv fits
218
-
219
- Wrong:
220
-
221
- ```tsx
222
- import { cn } from '@payfit/unity-themes'
223
-
224
- function Pill({
225
- size,
226
- color,
227
- }: {
228
- size: 'sm' | 'lg'
229
- color: 'primary' | 'danger'
230
- }) {
231
- return (
232
- <span
233
- className={cn(
234
- 'uy:inline-flex uy:items-center',
235
- size === 'sm' && 'uy:px-100 uy:text-xs',
236
- size === 'lg' && 'uy:px-200 uy:text-sm',
237
- color === 'primary' && 'uy:bg-surface-primary-default',
238
- color === 'danger' && 'uy:bg-surface-danger-default',
239
- )}
240
- />
241
- )
242
- }
243
- ```
244
-
245
- Correct:
246
-
247
- ```tsx
248
- import type { VariantProps } from '@payfit/unity-themes'
249
-
250
- import { uyTv } from '@payfit/unity-themes'
251
-
252
- const pill = uyTv({
253
- base: 'uy:inline-flex uy:items-center',
254
- variants: {
255
- size: { sm: 'uy:px-100 uy:text-xs', lg: 'uy:px-200 uy:text-sm' },
256
- color: {
257
- primary: 'uy:bg-surface-primary-default',
258
- danger: 'uy:bg-surface-danger-default',
259
- },
260
- },
261
- })
262
- type PillProps = VariantProps<typeof pill>
263
- function Pill(props: PillProps) {
264
- return <span className={pill(props)} />
265
- }
266
- ```
267
-
268
- 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.
269
-
270
- Source: themes/src/utils/tailwind-variants.ts
271
-
272
- ## See also
273
-
274
- - `unity-find-component` — the decision tree's "React Aria + uy: classes" branch
275
- when no Unity component fits.
276
- - `unity-contribute-component` — `uyTv` is the contributor's variant tool.
277
- - `unity-themes-tokens-and-docs` — token discipline if you need a new token
278
- rather than reusing an existing one.
@@ -1,139 +0,0 @@
1
- # Unity layout and styling patterns
2
-
3
- ### Flex for 1D, Grid for 2D
4
-
5
- `Flex` is for one-dimensional rows/columns; `Grid` is for the 12-column (or 6-column)
6
- two-dimensional layout. Each exposes layout props; everything else goes via
7
- `className` with `uy:` utilities.
8
-
9
- ```tsx
10
- import { Flex, FlexItem, Grid, GridItem } from '@payfit/unity-components'
11
-
12
- // Flex props: asElement, inline, direction, isReversed, wrap,
13
- // gap, gapX, gapY, justify, align, alignContent, className
14
- <Flex direction="row" gap="200" justify="between" align="center">
15
- <FlexItem grow="1">Left</FlexItem>
16
- <FlexItem>Right</FlexItem>
17
- </Flex>
18
-
19
- // Grid props: asElement, inline, cols (6 | 12), rows, areas, flow,
20
- // justifyItems, alignItems, className
21
- // GridItem positions via colSpan/colStart/colEnd OR area (mutually exclusive)
22
- <Grid cols={12} className="uy:gap-200">
23
- <GridItem colSpan={8}>Main</GridItem>
24
- <GridItem colSpan={4}>Aside</GridItem>
25
- </Grid>
26
- ```
27
-
28
- ### Responsive classes via uy:md:
29
-
30
- There is no responsive prop-object API. Responsive behavior is driven by
31
- TailwindCSS v4 modifiers on `className`.
32
-
33
- ```tsx
34
- <Flex gap="100" className="uy:md:gap-200 uy:lg:gap-300">
35
- <span>Item</span>
36
- </Flex>
37
-
38
- <Grid cols={12} className="uy:grid-cols-1 uy:md:grid-cols-2 uy:lg:grid-cols-3" />
39
- ```
40
-
41
- ### Variants with uyTv
42
-
43
- `uyTv` from `@payfit/unity-themes` is the pre-configured tailwind-variants
44
- factory. It applies the Unity `twMergeConfig` so variant collisions resolve
45
- against Unity tokens. Export the variant function and derive its typed props
46
- with `VariantProps`.
47
-
48
- ```tsx
49
- import type { VariantProps } from '@payfit/unity-themes'
50
-
51
- import { uyTv } from '@payfit/unity-themes'
52
-
53
- export const callout = uyTv({
54
- base: 'uy:inline-flex uy:items-center uy:gap-100 uy:rounded-100 uy:px-200 uy:py-100',
55
- variants: {
56
- intent: {
57
- info: 'uy:bg-surface-primary-default uy:text-content-inverted-default',
58
- danger: 'uy:bg-surface-danger-default uy:text-content-inverted-default',
59
- neutral: 'uy:bg-surface-neutral-default uy:text-content-neutral-default',
60
- },
61
- size: {
62
- sm: 'uy:typography-body-small',
63
- md: 'uy:typography-body',
64
- },
65
- },
66
- defaultVariants: { intent: 'info', size: 'md' },
67
- })
68
-
69
- export type CalloutVariantProps = VariantProps<typeof callout>
70
- ```
71
-
72
- ### Class merging with uyMerge
73
-
74
- `uyMerge` is `tailwind-merge` configured with Unity's class groups. Use it
75
- whenever an external `className` may collide with internal classes.
76
-
77
- ```tsx
78
- import { uyMerge } from '@payfit/unity-themes'
79
-
80
- uyMerge('uy:p-100', 'uy:p-200') // → 'uy:p-200'
81
- uyMerge('uy:bg-surface-primary-default', 'uy:bg-surface-danger-default')
82
- // → 'uy:bg-surface-danger-default'
83
- uyMerge('uy:p-100', 'uy:px-200', 'uy:py-300') // p, px, py don't collide
84
- ```
85
-
86
- ### Conditional classes with cn / classNames / clsx
87
-
88
- `cn`, `classNames`, and `clsx` are aliases for the same Unity-configured helper
89
- in `@payfit/unity-themes`. Use them for ad-hoc conditional strings — not for
90
- component-scoped variant APIs.
91
-
92
- ```tsx
93
- import { cn } from '@payfit/unity-themes'
94
-
95
- function Row({
96
- isActive,
97
- className,
98
- }: {
99
- isActive: boolean
100
- className?: string
101
- }) {
102
- return (
103
- <div
104
- className={cn(
105
- 'uy:flex uy:items-center uy:px-200 uy:py-100',
106
- isActive && 'uy:bg-surface-primary-default',
107
- className,
108
- )}
109
- />
110
- )
111
- }
112
- ```
113
-
114
- ### Typography with `<Text>`
115
-
116
- Use `<Text variant=...>` instead of a `<div>` + typography class. `Text`
117
- picks a semantic element from the variant (e.g. `variant="h1"` → `<h1>`),
118
- applies the typography variant, and exposes `color`, `isTruncated`,
119
- `lineClamp`, and `maxWidthCh`.
120
-
121
- ```tsx
122
- import { Text } from '@payfit/unity-components'
123
-
124
- <Text variant="h1" color="content.primary">Title</Text>
125
- <Text variant="body" color="content.neutral">Description</Text>
126
- // Override the semantic element when needed:
127
- <Text variant="h1" asElement="h2">Visual h1, semantic h2</Text>
128
- ```
129
-
130
- ### Data-attribute pseudo-states
131
-
132
- Several Unity components expose internal state via `data-hovered`,
133
- `data-pressed`, `data-focus-visible`, etc. Target the component-owned state
134
- attribute rather than the native CSS pseudo-state.
135
-
136
- ```tsx
137
- import { ListViewItem } from '@payfit/unity-components'
138
- ;<ListViewItem className="uy:data-[hovered=true]:bg-surface-primary-hover" />
139
- ```