@payfit/unity-themes 2.55.5 → 2.55.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,37 @@
1
+ type ColorToken = {
2
+ name: string;
3
+ value?: string;
4
+ $value?: string;
5
+ path: string[];
6
+ };
7
+ type ReferenceToken = {
8
+ name: string;
9
+ group: string;
10
+ variable: string;
11
+ };
12
+ type ReferenceFile = {
13
+ filename: string;
14
+ content: string;
15
+ };
16
+ type UtilitySection = {
17
+ title: string;
18
+ patterns: string[];
19
+ };
20
+ export declare const generateColorGroupReference: ({ title, storybookTitle, description, tokens, utilitySections, }: {
21
+ title: string;
22
+ storybookTitle: string;
23
+ description: string;
24
+ tokens: ReferenceToken[];
25
+ utilitySections?: UtilitySection[];
26
+ }) => string;
27
+ export declare const generatePrimitiveColorReferenceFiles: (legacyTokens: ColorToken[]) => ReferenceFile[];
28
+ export declare const generateSemanticColorReferenceFiles: (legacyTokens: ColorToken[]) => ReferenceFile[];
29
+ export declare const generateThemesAgentReferencesReadme: ({ primitiveFiles, semanticFiles, }: {
30
+ primitiveFiles: ReferenceFile[];
31
+ semanticFiles: ReferenceFile[];
32
+ }) => string;
33
+ export declare const writeColorAgentReferences: ({ legacyTokens, outputDir, }: {
34
+ legacyTokens: ColorToken[];
35
+ outputDir: string;
36
+ }) => void;
37
+ export {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@payfit/unity-themes",
3
- "version": "2.55.5",
3
+ "version": "2.55.6",
4
4
  "main": "./dist/esm/index.js",
5
5
  "types": "./dist/esm/index.d.ts",
6
6
  "style": "./dist/css/unity.css",
@@ -8,8 +8,7 @@
8
8
  "files": [
9
9
  "dist",
10
10
  "tokens",
11
- "src",
12
- "skills"
11
+ "src"
13
12
  ],
14
13
  "storybook": {
15
14
  "url": "https://unity-theme.payfit.io/"
@@ -45,7 +44,6 @@
45
44
  "@storybook/addon-vitest": "10.4.6",
46
45
  "@storybook/react-vite": "10.4.6",
47
46
  "@tailwindcss/vite": "4.3.2",
48
- "@tanstack/intent": "0.3.0",
49
47
  "@types/lodash": "4.14.202",
50
48
  "@types/node": "^24.12.0",
51
49
  "@types/react": "18.3.18",
@@ -64,10 +62,10 @@
64
62
  "typescript": "6.0.3",
65
63
  "vite": "8.0.16",
66
64
  "vitest": "4.1.9",
67
- "@payfit/hr-app-eslint": "0.0.0-use.local",
68
65
  "@payfit/hr-apps-tsconfigs": "0.0.0-use.local",
69
66
  "@payfit/storybook-config": "0.0.0-use.local",
70
- "@payfit/vite-configs": "0.0.0-use.local"
67
+ "@payfit/vite-configs": "0.0.0-use.local",
68
+ "@payfit/hr-app-eslint": "0.0.0-use.local"
71
69
  },
72
70
  "peerDependencies": {
73
71
  "@fontsource/inter": "5.0.19",
@@ -84,8 +82,5 @@
84
82
  "tailwind-merge": "3.6.0",
85
83
  "tailwind-variants": "3.2.2",
86
84
  "tailwindcss": "4.3.2"
87
- },
88
- "keywords": [
89
- "tanstack-intent"
90
- ]
85
+ }
91
86
  }
@@ -0,0 +1,25 @@
1
+ import { Meta } from '@storybook/addon-docs/blocks'
2
+
3
+ <Meta title="Agent References/Unity Themes" />
4
+
5
+ {/* AUTO-GENERATED FILE. DO NOT EDIT.
6
+ Generated by unity-themes:pre-build.
7
+ Source: Unity Style Dictionary color tokens.
8
+ */}
9
+
10
+ # Unity Themes Agent References
11
+
12
+ Static Unity theme references for Storybook MCP, search, and agents.
13
+
14
+ Storybook includes these MDX files through the shared `../src/**/*.mdx` stories glob, and `@storybook/addon-mcp` exposes docs content to MCP clients.
15
+
16
+ ## Semantic colors
17
+
18
+ - [semantic-surface-colors](./semantic-surface-colors.mdx)
19
+ - [semantic-content-colors](./semantic-content-colors.mdx)
20
+ - [semantic-border-colors](./semantic-border-colors.mdx)
21
+ - [semantic-utility-colors](./semantic-utility-colors.mdx)
22
+
23
+ ## Primitive colors
24
+
25
+ - [primitive-colors](./primitive-colors.mdx)
@@ -0,0 +1,18 @@
1
+ import { Meta } from '@storybook/addon-docs/blocks'
2
+
3
+ <Meta title="Agent References/Primitive Colors" />
4
+
5
+ {/* AUTO-GENERATED FILE. DO NOT EDIT.
6
+ Generated by unity-themes:pre-build.
7
+ Source: Unity Style Dictionary color tokens.
8
+ */}
9
+
10
+ # Primitive Colors
11
+
12
+ Prefer semantic color tokens for product UI. Use primitive colors only when no semantic token fits the use case.
13
+
14
+ Color names: grayscale, blue, red, green, orange, cyan, purple, plum, peach, sunglow, teal, yellow
15
+
16
+ Scale: l1, l2, l3, l4, l5, l6, l7, l8, l9, l10, l11, l12. Grayscale also has l0.
17
+
18
+ Tailwind usage: `uy:bg-<color>-<scale>`, for example `uy:bg-blue-l6` or `uy:bg-grayscale-l0`.
@@ -0,0 +1,16 @@
1
+ import { Meta } from '@storybook/addon-docs/blocks'
2
+
3
+ <Meta title="Agent References/Semantic Colors/Border" />
4
+
5
+ {/* AUTO-GENERATED FILE. DO NOT EDIT.
6
+ Generated by unity-themes:pre-build.
7
+ Source: Unity Style Dictionary color tokens.
8
+ */}
9
+
10
+ # Semantic Border Colors
11
+
12
+ Use semantic color tokens for product UI. These names encode intent and stay stable across Unity themes. Use border tokens for borders and outlines. Other Tailwind color utilities may exist for these tokens, but using border tokens for backgrounds, text, gradients, or rings is discouraged.
13
+
14
+ Names: danger, danger-lowest, form-active, form-disabled, form-enabled, form-error, form-focus, form-hover, form-pressed, form-read-only, form-selected, info, info-lowest, inverted, inverted-active, inverted-disabled, inverted-enabled, inverted-focus, inverted-high, inverted-hover, inverted-pressed, neutral, neutral-active, neutral-disabled, neutral-enabled, neutral-high, neutral-high-active, neutral-high-disabled, neutral-high-enabled, neutral-high-focus, neutral-high-hover, neutral-high-pressed, neutral-hover, neutral-low, neutral-pressed, neutral-selected, primary, primary-active, primary-disabled, primary-enabled, primary-focus, primary-hover, primary-lowest, primary-pressed, promo, promo-lowest, success, success-low, success-lowest, warning, warning-lowest
15
+
16
+ Recommended: `uy:border-border-{name}`, `uy:outline-border-{name}`
@@ -0,0 +1,16 @@
1
+ import { Meta } from '@storybook/addon-docs/blocks'
2
+
3
+ <Meta title="Agent References/Semantic Colors/Content" />
4
+
5
+ {/* AUTO-GENERATED FILE. DO NOT EDIT.
6
+ Generated by unity-themes:pre-build.
7
+ Source: Unity Style Dictionary color tokens.
8
+ */}
9
+
10
+ # Semantic Content Colors
11
+
12
+ Use semantic color tokens for product UI. These names encode intent and stay stable across Unity themes. Use content tokens for text, icon color, and text decoration. Other Tailwind color utilities may exist for these tokens, but using content tokens for backgrounds, borders, rings, or outlines is discouraged.
13
+
14
+ Names: danger, danger-active, danger-disabled, danger-enabled, danger-focus, danger-high, danger-hover, danger-pressed, decorative-orange, decorative-orange-high, decorative-plum, decorative-plum-high, decorative-purple, decorative-purple-high, decorative-teal, decorative-teal-high, form-active, form-disabled, form-enabled, form-focus, form-hover, form-invalid, form-pressed, form-read-only, form-selected, info, info-active, info-disabled, info-enabled, info-focus, info-high, info-hover, info-pressed, inverted, inverted-active, inverted-disabled, inverted-enabled, inverted-focus, inverted-hover, inverted-pressed, neutral, neutral-active, neutral-disabled, neutral-enabled, neutral-focus, neutral-hover, neutral-low, neutral-lowest, neutral-lowest-active, neutral-lowest-disabled, neutral-lowest-enabled, neutral-lowest-focus, neutral-lowest-hover, neutral-lowest-pressed, neutral-pressed, primary, primary-active, primary-disabled, primary-enabled, primary-focus, primary-high, primary-hover, primary-pressed, promo, promo-high, success, success-active, success-disabled, success-enabled, success-focus, success-high, success-hover, success-pressed, warning, warning-active, warning-disabled, warning-enabled, warning-focus, warning-high, warning-hover, warning-pressed
15
+
16
+ Recommended: `uy:text-content-{name}`, `uy:decoration-content-{name}`
@@ -0,0 +1,16 @@
1
+ import { Meta } from '@storybook/addon-docs/blocks'
2
+
3
+ <Meta title="Agent References/Semantic Colors/Surface" />
4
+
5
+ {/* AUTO-GENERATED FILE. DO NOT EDIT.
6
+ Generated by unity-themes:pre-build.
7
+ Source: Unity Style Dictionary color tokens.
8
+ */}
9
+
10
+ # Semantic Surface Colors
11
+
12
+ Use semantic color tokens for product UI. These names encode intent and stay stable across Unity themes. Use surface tokens for backgrounds and filled UI surfaces. Other Tailwind color utilities may exist for these tokens, but using surface tokens for text, borders, rings, or outlines is discouraged.
13
+
14
+ Names: ai-low, danger, danger-active, danger-disabled, danger-enabled, danger-focus, danger-hover, danger-low, danger-lowest, danger-lowest-active, danger-lowest-disabled, danger-lowest-enabled, danger-lowest-focus, danger-lowest-hover, danger-lowest-pressed, danger-pressed, decorative-orange, decorative-orange-high, decorative-orange-low, decorative-orange-lowest, decorative-plum, decorative-plum-high, decorative-plum-low, decorative-plum-lowest, decorative-purple, decorative-purple-high, decorative-purple-low, decorative-purple-lowest, decorative-teal, decorative-teal-high, decorative-teal-low, decorative-teal-lowest, form-active, form-disabled, form-enabled, form-error, form-focus, form-high-active, form-high-disabled, form-high-enabled, form-high-error, form-high-focus, form-high-hover, form-high-pressed, form-high-read-only, form-high-selected, form-hover, form-pressed, form-read-only, form-selected, info, info-low, info-lowest, info-lowest-active, info-lowest-disabled, info-lowest-enabled, info-lowest-focus, info-lowest-hover, info-lowest-pressed, inverted, inverted-active, inverted-enabled, inverted-focus, inverted-hover, inverted-pressed, neutral, neutral-active, neutral-disabled, neutral-enabled, neutral-focus, neutral-hover, neutral-low, neutral-low-active, neutral-low-disabled, neutral-low-enabled, neutral-low-focus, neutral-low-hover, neutral-low-pressed, neutral-low-selected, neutral-lowest, neutral-lowest-active, neutral-lowest-disabled, neutral-lowest-enabled, neutral-lowest-focus, neutral-lowest-hover, neutral-lowest-pressed, neutral-lowest-selected, neutral-pressed, neutral-selected, primary, primary-active, primary-disabled, primary-enabled, primary-focus, primary-high, primary-highest, primary-hover, primary-low, primary-lowest, primary-lowest-active, primary-lowest-disabled, primary-lowest-enabled, primary-lowest-focus, primary-lowest-hover, primary-lowest-pressed, primary-pressed, promo, promo-low, promo-lowest, success, success-low, success-lowest, success-lowest-active, success-lowest-disabled, success-lowest-enabled, success-lowest-focus, success-lowest-hover, success-lowest-pressed, warning, warning-active, warning-disabled, warning-enabled, warning-focus, warning-hover, warning-low, warning-lowest, warning-lowest-active, warning-lowest-disabled, warning-lowest-enabled, warning-lowest-focus, warning-lowest-hover, warning-lowest-pressed, warning-pressed
15
+
16
+ Recommended: `uy:bg-surface-{name}`
@@ -0,0 +1,16 @@
1
+ import { Meta } from '@storybook/addon-docs/blocks'
2
+
3
+ <Meta title="Agent References/Semantic Colors/Utility & Canvas" />
4
+
5
+ {/* AUTO-GENERATED FILE. DO NOT EDIT.
6
+ Generated by unity-themes:pre-build.
7
+ Source: Unity Style Dictionary color tokens.
8
+ */}
9
+
10
+ # Semantic Utility & Canvas Colors
11
+
12
+ Use semantic color tokens for product UI. These names encode intent and stay stable across Unity themes. Use utility and canvas tokens only for their named UI purpose. These tokens are intentionally narrow and should not be treated as a general color palette.
13
+
14
+ Names: backdrop, focus-ring, inverted-focus-ring, shadow-100, shadow-200, shadow-300, shadow-400, shadow-500, shadow-600
15
+
16
+ Token-specific: `uy:bg-canvas-{name}`, `uy:ring-utility-focus-ring`, `uy:ring-utility-inverted-focus-ring`, `uy:bg-utility-backdrop`, shadow-\* tokens are not UI colors
@@ -0,0 +1,140 @@
1
+ import { describe, expect, it } from 'vitest'
2
+
3
+ import {
4
+ generatePrimitiveColorReferenceFiles,
5
+ generateSemanticColorReferenceFiles,
6
+ generateThemesAgentReferencesReadme,
7
+ } from './color-reference.js'
8
+
9
+ const createToken = (path: string[], value: string) => ({
10
+ name: `uy-${path.join('-').toLowerCase()}`,
11
+ path,
12
+ $value: value,
13
+ })
14
+
15
+ describe('color agent references', () => {
16
+ it('generates one compact primitive reference file for all palettes', () => {
17
+ const files = generatePrimitiveColorReferenceFiles([
18
+ createToken(['color', 'grayscale', 'L0'], '#000'),
19
+ createToken(['color', 'grayscale', 'L1'], '#005'),
20
+ createToken(['color', 'blue', 'L10'], '#001'),
21
+ createToken(['color', 'blue', 'L2'], '#002'),
22
+ createToken(['color', 'blue', 'L1'], '#003'),
23
+ createToken(['color', 'red', 'L1'], '#004'),
24
+ ])
25
+
26
+ expect(files.map(file => file.filename)).toEqual(['primitive-colors.mdx'])
27
+
28
+ const primitiveReference = files[0]?.content
29
+
30
+ expect(
31
+ primitiveReference!.startsWith(
32
+ `import { Meta } from '@storybook/addon-docs/blocks'\n\n<Meta title="Agent References/Primitive Colors" />`,
33
+ ),
34
+ ).toBe(true)
35
+ expect(primitiveReference).toContain(
36
+ `{/* AUTO-GENERATED FILE. DO NOT EDIT.
37
+ Generated by unity-themes:pre-build.
38
+ Source: Unity Style Dictionary color tokens.
39
+ */}`,
40
+ )
41
+ expect(primitiveReference).toContain('Color names: grayscale, blue, red')
42
+ expect(primitiveReference).toContain('Scale: l1, l2, l10')
43
+ expect(primitiveReference).toContain('Grayscale also has l0')
44
+ expect(primitiveReference!.indexOf('l1')).toBeLessThan(
45
+ primitiveReference!.indexOf('l2'),
46
+ )
47
+ expect(primitiveReference!.indexOf('l2')).toBeLessThan(
48
+ primitiveReference!.indexOf('l10'),
49
+ )
50
+ expect(primitiveReference).not.toContain('`--uy-color-blue-l1`')
51
+ expect(primitiveReference).not.toContain('Names: l1')
52
+ expect(primitiveReference).not.toContain('## Names')
53
+ expect(primitiveReference).not.toContain('- l1')
54
+ expect(primitiveReference).toContain('`uy:bg-<color>-<scale>`')
55
+ expect(primitiveReference).toContain('`uy:bg-blue-l')
56
+ expect(primitiveReference).not.toContain('Legacy value')
57
+ expect(primitiveReference).not.toContain('Rebrand value')
58
+ expect(primitiveReference).not.toContain('#001')
59
+ })
60
+
61
+ it('generates one compact semantic reference file per semantic group', () => {
62
+ const files = generateSemanticColorReferenceFiles([
63
+ createToken(['color', 'surface', 'primary'], '#fff'),
64
+ createToken(['color', 'content', 'neutral'], '#111'),
65
+ createToken(['color', 'border', 'primary'], '#222'),
66
+ createToken(['color', 'canvas', 'default'], '#333'),
67
+ ])
68
+
69
+ expect(files.map(file => file.filename)).toEqual([
70
+ 'semantic-surface-colors.mdx',
71
+ 'semantic-content-colors.mdx',
72
+ 'semantic-border-colors.mdx',
73
+ 'semantic-utility-colors.mdx',
74
+ ])
75
+
76
+ const surfaceReference = files[0]!.content
77
+
78
+ expect(surfaceReference).toContain(
79
+ '<Meta title="Agent References/Semantic Colors/Surface" />',
80
+ )
81
+ expect(surfaceReference).toContain('Names: primary')
82
+ expect(surfaceReference).not.toContain('## Names')
83
+ expect(surfaceReference).not.toContain('- primary')
84
+ expect(surfaceReference).not.toContain('`--uy-color-surface-primary`')
85
+ expect(surfaceReference).toContain('`uy:bg-surface-{name}`')
86
+ expect(surfaceReference).toContain('using surface tokens for text')
87
+ expect(surfaceReference).not.toContain('`uy:text-surface-{name}`')
88
+ expect(surfaceReference).not.toContain('CSS properties')
89
+ expect(surfaceReference).not.toContain(
90
+ 'background-color: var(--uy-color-surface-primary);',
91
+ )
92
+ expect(surfaceReference).not.toContain('#fff')
93
+
94
+ const contentReference = files[1]!.content
95
+ expect(contentReference).toContain('`uy:text-content-{name}`')
96
+ expect(contentReference).toContain('`uy:decoration-content-{name}`')
97
+ expect(contentReference).not.toContain('`uy:bg-content-{name}`')
98
+
99
+ const borderReference = files[2]!.content
100
+ expect(borderReference).toContain('`uy:border-border-{name}`')
101
+ expect(borderReference).toContain('`uy:outline-border-{name}`')
102
+ expect(borderReference).not.toContain('`uy:bg-border-{name}`')
103
+
104
+ const utilityReference = files[3]!.content
105
+ expect(utilityReference).toContain('Use utility and canvas tokens only')
106
+ expect(utilityReference).toContain('`uy:ring-utility-focus-ring`')
107
+ expect(utilityReference).not.toContain('`uy:bg-utility-{name}`')
108
+ })
109
+
110
+ it('links generated files from the README', () => {
111
+ const primitiveFiles = generatePrimitiveColorReferenceFiles([
112
+ createToken(['color', 'blue', 'L1'], '#001'),
113
+ ])
114
+ const semanticFiles = generateSemanticColorReferenceFiles([
115
+ createToken(['color', 'surface', 'primary'], '#fff'),
116
+ ])
117
+
118
+ const readme = generateThemesAgentReferencesReadme({
119
+ primitiveFiles,
120
+ semanticFiles,
121
+ })
122
+
123
+ expect(
124
+ readme.startsWith(
125
+ `import { Meta } from '@storybook/addon-docs/blocks'\n\n<Meta title="Agent References/Unity Themes" />`,
126
+ ),
127
+ ).toBe(true)
128
+ expect(readme).toContain(
129
+ `{/* AUTO-GENERATED FILE. DO NOT EDIT.
130
+ Generated by unity-themes:pre-build.
131
+ Source: Unity Style Dictionary color tokens.
132
+ */}`,
133
+ )
134
+ expect(readme).toContain(
135
+ '[semantic-surface-colors](./semantic-surface-colors.mdx)',
136
+ )
137
+ expect(readme).toContain('[primitive-colors](./primitive-colors.mdx)')
138
+ expect(readme).not.toContain('primitive-blue-colors')
139
+ })
140
+ })
@@ -0,0 +1,348 @@
1
+ import fs from 'fs'
2
+ import path from 'path'
3
+
4
+ type ColorToken = {
5
+ name: string
6
+ value?: string
7
+ $value?: string
8
+ path: string[]
9
+ }
10
+
11
+ type ReferenceToken = {
12
+ name: string
13
+ group: string
14
+ variable: string
15
+ }
16
+
17
+ type ReferenceFile = {
18
+ filename: string
19
+ content: string
20
+ }
21
+
22
+ type UtilitySection = {
23
+ title: string
24
+ patterns: string[]
25
+ }
26
+
27
+ const PRIMITIVE_GROUPS = [
28
+ 'grayscale',
29
+ 'blue',
30
+ 'red',
31
+ 'green',
32
+ 'orange',
33
+ 'cyan',
34
+ 'purple',
35
+ 'plum',
36
+ 'peach',
37
+ 'sunglow',
38
+ 'teal',
39
+ 'yellow',
40
+ ]
41
+
42
+ const SEMANTIC_GROUPS = [
43
+ {
44
+ title: 'Surface',
45
+ slug: 'surface',
46
+ groups: ['surface'],
47
+ usageGuidance:
48
+ 'Use surface tokens for backgrounds and filled UI surfaces. Other Tailwind color utilities may exist for these tokens, but using surface tokens for text, borders, rings, or outlines is discouraged.',
49
+ utilitySections: [
50
+ {
51
+ title: 'Recommended',
52
+ patterns: ['uy:bg-surface-{name}'],
53
+ },
54
+ ],
55
+ },
56
+ {
57
+ title: 'Content',
58
+ slug: 'content',
59
+ groups: ['content'],
60
+ usageGuidance:
61
+ 'Use content tokens for text, icon color, and text decoration. Other Tailwind color utilities may exist for these tokens, but using content tokens for backgrounds, borders, rings, or outlines is discouraged.',
62
+ utilitySections: [
63
+ {
64
+ title: 'Recommended',
65
+ patterns: ['uy:text-content-{name}', 'uy:decoration-content-{name}'],
66
+ },
67
+ ],
68
+ },
69
+ {
70
+ title: 'Border',
71
+ slug: 'border',
72
+ groups: ['border'],
73
+ usageGuidance:
74
+ 'Use border tokens for borders and outlines. Other Tailwind color utilities may exist for these tokens, but using border tokens for backgrounds, text, gradients, or rings is discouraged.',
75
+ utilitySections: [
76
+ {
77
+ title: 'Recommended',
78
+ patterns: ['uy:border-border-{name}', 'uy:outline-border-{name}'],
79
+ },
80
+ ],
81
+ },
82
+ {
83
+ title: 'Utility & Canvas',
84
+ slug: 'utility',
85
+ groups: ['utility', 'canvas'],
86
+ usageGuidance:
87
+ 'Use utility and canvas tokens only for their named UI purpose. These tokens are intentionally narrow and should not be treated as a general color palette.',
88
+ utilitySections: [
89
+ {
90
+ title: 'Token-specific',
91
+ patterns: [
92
+ 'uy:bg-canvas-{name}',
93
+ 'uy:ring-utility-focus-ring',
94
+ 'uy:ring-utility-inverted-focus-ring',
95
+ 'uy:bg-utility-backdrop',
96
+ 'shadow-\\* tokens are not UI colors',
97
+ ],
98
+ },
99
+ ],
100
+ },
101
+ ]
102
+
103
+ const SEMANTIC_GROUP_NAMES = SEMANTIC_GROUPS.flatMap(group => group.groups)
104
+
105
+ const generatedNotice = (source: string) =>
106
+ `{/* AUTO-GENERATED FILE. DO NOT EDIT.
107
+ Generated by unity-themes:pre-build.
108
+ Source: ${source}.
109
+ */}`
110
+
111
+ const storybookMeta = (title: string) =>
112
+ `import { Meta } from '@storybook/addon-docs/blocks'\n\n<Meta title="Agent References/${title}" />`
113
+
114
+ const parseReferenceToken = (token: ColorToken): ReferenceToken | null => {
115
+ const normalizedVariableName = token.name
116
+ .replace(/^uy-color-/, '')
117
+ .toLowerCase()
118
+ const [group, ...nameParts] = normalizedVariableName.split('-')
119
+ const name = nameParts.join('-')
120
+
121
+ if (!group || !name) {
122
+ return null
123
+ }
124
+
125
+ return {
126
+ name,
127
+ group,
128
+ variable: `--uy-color-${normalizedVariableName}`,
129
+ }
130
+ }
131
+
132
+ const getReferenceTokens = (tokens: ColorToken[]) =>
133
+ tokens
134
+ .filter(token => token.path[0] === 'color')
135
+ .map(parseReferenceToken)
136
+ .filter((token): token is ReferenceToken => token !== null)
137
+
138
+ const naturalLevelOrder = (name: string) => {
139
+ const levelMatch = /^l(\d+)$/i.exec(name)
140
+ return levelMatch ? Number(levelMatch[1]) : Number.POSITIVE_INFINITY
141
+ }
142
+
143
+ const sortByPrimitiveLevel = (a: ReferenceToken, b: ReferenceToken) => {
144
+ const aLevel = naturalLevelOrder(a.name)
145
+ const bLevel = naturalLevelOrder(b.name)
146
+
147
+ if (aLevel !== bLevel) {
148
+ return aLevel - bLevel
149
+ }
150
+
151
+ return a.name.localeCompare(b.name)
152
+ }
153
+
154
+ const sortByName = (a: ReferenceToken, b: ReferenceToken) =>
155
+ a.name.localeCompare(b.name)
156
+
157
+ const renderNames = (tokens: ReferenceToken[]) =>
158
+ `Names: ${tokens.map(token => token.name).join(', ')}`
159
+
160
+ const renderRecommendedUsageSections = (sections: UtilitySection[]) =>
161
+ sections.flatMap(section => [
162
+ `${section.title}: ${section.patterns
163
+ .map(pattern => (pattern.startsWith('uy:') ? `\`${pattern}\`` : pattern))
164
+ .join(', ')}`,
165
+ ])
166
+
167
+ export const generateColorGroupReference = ({
168
+ title,
169
+ storybookTitle,
170
+ description,
171
+ tokens,
172
+ utilitySections,
173
+ }: {
174
+ title: string
175
+ storybookTitle: string
176
+ description: string
177
+ tokens: ReferenceToken[]
178
+ utilitySections?: UtilitySection[]
179
+ }) => {
180
+ const lines = [
181
+ storybookMeta(storybookTitle),
182
+ generatedNotice('Unity Style Dictionary color tokens'),
183
+ `# ${title}`,
184
+ description,
185
+ renderNames(tokens),
186
+ ...(utilitySections ? renderRecommendedUsageSections(utilitySections) : []),
187
+ ]
188
+
189
+ return `${lines.join('\n\n').trimEnd()}\n`
190
+ }
191
+
192
+ const sortPrimitiveGroups = (groups: string[]) =>
193
+ groups.slice().sort((a, b) => {
194
+ const aIndex = PRIMITIVE_GROUPS.indexOf(a)
195
+ const bIndex = PRIMITIVE_GROUPS.indexOf(b)
196
+
197
+ return aIndex - bIndex
198
+ })
199
+
200
+ const uniqueSortedPrimitiveLevels = (tokens: ReferenceToken[]) =>
201
+ [...new Set(tokens.map(token => token.name))].sort((a, b) =>
202
+ sortByPrimitiveLevel(
203
+ { name: a, group: '', variable: '' },
204
+ { name: b, group: '', variable: '' },
205
+ ),
206
+ )
207
+
208
+ const generatePrimitiveColorsReference = (tokens: ReferenceToken[]) => {
209
+ const colors = sortPrimitiveGroups([
210
+ ...new Set(tokens.map(token => token.group)),
211
+ ])
212
+ const nonGrayscaleLevels = uniqueSortedPrimitiveLevels(
213
+ tokens.filter(token => token.group !== 'grayscale'),
214
+ )
215
+ const grayscaleLevels = uniqueSortedPrimitiveLevels(
216
+ tokens.filter(token => token.group === 'grayscale'),
217
+ )
218
+ const grayscaleExtraLevels = grayscaleLevels.filter(
219
+ level => !nonGrayscaleLevels.includes(level),
220
+ )
221
+ const exampleScale = nonGrayscaleLevels.includes('l6')
222
+ ? 'l6'
223
+ : nonGrayscaleLevels[0]
224
+ const grayscaleExampleScale = grayscaleExtraLevels[0] ?? grayscaleLevels[0]
225
+
226
+ const lines = [
227
+ storybookMeta('Primitive Colors'),
228
+ generatedNotice('Unity Style Dictionary color tokens'),
229
+ '# Primitive Colors',
230
+ 'Prefer semantic color tokens for product UI. Use primitive colors only when no semantic token fits the use case.',
231
+ `Color names: ${colors.join(', ')}`,
232
+ `Scale: ${nonGrayscaleLevels.join(', ')}${
233
+ grayscaleExtraLevels.length > 0
234
+ ? `. Grayscale also has ${grayscaleExtraLevels.join(', ')}`
235
+ : ''
236
+ }.`,
237
+ `Tailwind usage: \`uy:bg-<color>-<scale>\`, for example \`uy:bg-blue-${exampleScale}\`${
238
+ grayscaleExampleScale
239
+ ? ` or \`uy:bg-grayscale-${grayscaleExampleScale}\``
240
+ : ''
241
+ }.`,
242
+ ]
243
+
244
+ return `${lines.join('\n\n').trimEnd()}\n`
245
+ }
246
+
247
+ export const generatePrimitiveColorReferenceFiles = (
248
+ legacyTokens: ColorToken[],
249
+ ): ReferenceFile[] => {
250
+ const tokens = getReferenceTokens(legacyTokens).filter(token =>
251
+ PRIMITIVE_GROUPS.includes(token.group),
252
+ )
253
+
254
+ if (tokens.length === 0) {
255
+ return []
256
+ }
257
+
258
+ return [
259
+ {
260
+ filename: 'primitive-colors.mdx',
261
+ content: generatePrimitiveColorsReference(tokens),
262
+ },
263
+ ]
264
+ }
265
+
266
+ export const generateSemanticColorReferenceFiles = (
267
+ legacyTokens: ColorToken[],
268
+ ): ReferenceFile[] => {
269
+ const tokens = getReferenceTokens(legacyTokens).filter(token =>
270
+ SEMANTIC_GROUP_NAMES.includes(token.group),
271
+ )
272
+
273
+ return SEMANTIC_GROUPS.flatMap(group => {
274
+ const groupTokens = tokens
275
+ .filter(token => group.groups.includes(token.group))
276
+ .sort(sortByName)
277
+
278
+ if (groupTokens.length === 0) {
279
+ return []
280
+ }
281
+
282
+ return [
283
+ {
284
+ filename: `semantic-${group.slug}-colors.mdx`,
285
+ content: generateColorGroupReference({
286
+ title: `Semantic ${group.title} Colors`,
287
+ storybookTitle: `Semantic Colors/${group.title}`,
288
+ description: `Use semantic color tokens for product UI. These names encode intent and stay stable across Unity themes. ${group.usageGuidance}`,
289
+ tokens: groupTokens,
290
+ utilitySections: group.utilitySections,
291
+ }),
292
+ },
293
+ ]
294
+ })
295
+ }
296
+
297
+ const linkList = (files: ReferenceFile[]) =>
298
+ files.map(
299
+ file => `- [${file.filename.replace(/\.mdx$/, '')}](./${file.filename})`,
300
+ )
301
+
302
+ export const generateThemesAgentReferencesReadme = ({
303
+ primitiveFiles,
304
+ semanticFiles,
305
+ }: {
306
+ primitiveFiles: ReferenceFile[]
307
+ semanticFiles: ReferenceFile[]
308
+ }) => `${storybookMeta('Unity Themes')}
309
+
310
+ ${generatedNotice('Unity Style Dictionary color tokens')}
311
+
312
+ # Unity Themes Agent References
313
+
314
+ Static Unity theme references for Storybook MCP, search, and agents.
315
+
316
+ Storybook includes these MDX files through the shared \`../src/**/*.mdx\` stories glob, and \`@storybook/addon-mcp\` exposes docs content to MCP clients.
317
+
318
+ ## Semantic colors
319
+
320
+ ${linkList(semanticFiles).join('\n')}
321
+
322
+ ## Primitive colors
323
+
324
+ ${linkList(primitiveFiles).join('\n')}
325
+ `
326
+
327
+ export const writeColorAgentReferences = ({
328
+ legacyTokens,
329
+ outputDir,
330
+ }: {
331
+ legacyTokens: ColorToken[]
332
+ outputDir: string
333
+ }) => {
334
+ const primitiveFiles = generatePrimitiveColorReferenceFiles(legacyTokens)
335
+ const semanticFiles = generateSemanticColorReferenceFiles(legacyTokens)
336
+
337
+ fs.rmSync(outputDir, { recursive: true, force: true })
338
+ fs.mkdirSync(outputDir, { recursive: true })
339
+ fs.writeFileSync(
340
+ path.join(outputDir, 'README.mdx'),
341
+ generateThemesAgentReferencesReadme({ primitiveFiles, semanticFiles }),
342
+ 'utf8',
343
+ )
344
+
345
+ for (const file of [...semanticFiles, ...primitiveFiles]) {
346
+ fs.writeFileSync(path.join(outputDir, file.filename), file.content, 'utf8')
347
+ }
348
+ }
@@ -25,6 +25,7 @@ import * as tailwindGridTokenTransformer from './transforms/tailwind-grid-token.
25
25
  import * as tailwindSpacingTokenTransformer from './transforms/tailwind-spacing-token.js'
26
26
  import * as tailwindTextTokenTransformer from './transforms/tailwind-text-token.js'
27
27
  import * as tailwindTypographyTokenTransformer from './transforms/tailwind-typography-token.js'
28
+ import { writeColorAgentReferences } from './agent-references/color-reference.js'
28
29
 
29
30
  // ---------------------------------------------------------------------------
30
31
  // Register extensions (shared by all SD instances)
@@ -130,6 +131,7 @@ const ANIMATIONS_PATH = './assets/animations/'
130
131
  const DIST_FONTS_PATH = './dist/css/fonts/'
131
132
  const DIST_ASSETS_FONTS_PATH = './dist/css/assets/fonts/'
132
133
  const GENERATED_FONTS_CSS_PATH = './dist/css/generated/proprietary-fonts.css'
134
+ const AGENT_REFERENCES_PATH = './src/agent-references'
133
135
  const PREFIX = 'uy'
134
136
 
135
137
  // ---------------------------------------------------------------------------
@@ -372,11 +374,16 @@ async function build() {
372
374
  outputPath,
373
375
  })
374
376
 
375
- // 6. Append animation keyframes + reset CSS
376
- logStep(6, TOTAL_STEPS, 'Appending animation keyframes')
377
- logDetail(`Source: ${color.yellow(ANIMATIONS_PATH)}`)
377
+ // 6. Generate static references + append animation keyframes
378
+ logStep(6, TOTAL_STEPS, 'Generating agent references and animations')
379
+ logDetail(`Agent references: ${color.yellow(AGENT_REFERENCES_PATH)}`)
380
+ logDetail(`Animations source: ${color.yellow(ANIMATIONS_PATH)}`)
378
381
 
379
382
  const legacyDict = await legacySD.getPlatformTokens('css')
383
+ writeColorAgentReferences({
384
+ legacyTokens: legacyDict.allTokens,
385
+ outputDir: AGENT_REFERENCES_PATH,
386
+ })
380
387
  appendAnimations(
381
388
  legacyDict,
382
389
  {