@payfit/unity-themes 2.55.22 → 2.56.0

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 (52) hide show
  1. package/dist/esm/scripts/style-dictionary-config.d.ts +14 -0
  2. package/package.json +14 -5
  3. package/skills/unity-themes/SKILL.md +45 -0
  4. package/src/agent-references/manifest.json +16 -0
  5. package/src/agent-references/tokens-catalog.json +13891 -0
  6. package/dist/esm/scripts/agent-references/color-reference.d.ts +0 -37
  7. package/src/agent-references/README.mdx +0 -25
  8. package/src/agent-references/primitive-colors.mdx +0 -18
  9. package/src/agent-references/semantic-border-colors.mdx +0 -16
  10. package/src/agent-references/semantic-content-colors.mdx +0 -16
  11. package/src/agent-references/semantic-surface-colors.mdx +0 -16
  12. package/src/agent-references/semantic-utility-colors.mdx +0 -16
  13. package/src/components/unity-theme-provider.stories.tsx +0 -532
  14. package/src/components/unity-theme-provider.test.tsx +0 -150
  15. package/src/components/unity-theme-provider.tsx +0 -72
  16. package/src/index.ts +0 -15
  17. package/src/scripts/actions/append-animations.ts +0 -73
  18. package/src/scripts/actions/compose-multi-theme.ts +0 -59
  19. package/src/scripts/agent-references/color-reference.test.ts +0 -140
  20. package/src/scripts/agent-references/color-reference.ts +0 -348
  21. package/src/scripts/build.ts +0 -420
  22. package/src/scripts/file-headers/unity.ts +0 -31
  23. package/src/scripts/formats/processors/grid-processor.test.ts +0 -378
  24. package/src/scripts/formats/processors/grid-processor.ts +0 -64
  25. package/src/scripts/formats/processors/typography-processor.test.ts +0 -111
  26. package/src/scripts/formats/processors/typography-processor.ts +0 -48
  27. package/src/scripts/formats/unity-theme.test.ts +0 -329
  28. package/src/scripts/formats/unity-theme.ts +0 -54
  29. package/src/scripts/formats/utils.test.ts +0 -264
  30. package/src/scripts/formats/utils.ts +0 -15
  31. package/src/scripts/transforms/oklch.test.ts +0 -166
  32. package/src/scripts/transforms/oklch.ts +0 -19
  33. package/src/scripts/transforms/tailwind-animation-token.test.ts +0 -108
  34. package/src/scripts/transforms/tailwind-animation-token.ts +0 -51
  35. package/src/scripts/transforms/tailwind-color-token.test.ts +0 -304
  36. package/src/scripts/transforms/tailwind-color-token.ts +0 -17
  37. package/src/scripts/transforms/tailwind-grid-token.test.ts +0 -114
  38. package/src/scripts/transforms/tailwind-grid-token.ts +0 -27
  39. package/src/scripts/transforms/tailwind-spacing-token.test.ts +0 -315
  40. package/src/scripts/transforms/tailwind-spacing-token.ts +0 -24
  41. package/src/scripts/transforms/tailwind-text-token.test.ts +0 -328
  42. package/src/scripts/transforms/tailwind-text-token.ts +0 -30
  43. package/src/scripts/transforms/tailwind-typography-token.test.ts +0 -55
  44. package/src/scripts/transforms/tailwind-typography-token.ts +0 -20
  45. package/src/scripts/types.ts +0 -30
  46. package/src/scripts/utils/prefix-transform.test.ts +0 -137
  47. package/src/scripts/utils/prefix-transform.ts +0 -16
  48. package/src/utils/cn.ts +0 -109
  49. package/src/utils/merge-config.ts +0 -194
  50. package/src/utils/tailwind-merge.test.ts +0 -462
  51. package/src/utils/tailwind-merge.ts +0 -77
  52. package/src/utils/tailwind-variants.ts +0 -53
@@ -1,72 +0,0 @@
1
- import { createContext, useContext, useEffect, useState } from 'react'
2
-
3
- import type { PropsWithChildren, RefObject } from 'react'
4
-
5
- export type UnityTheme = 'legacy' | 'rebrand'
6
-
7
- interface UnityThemeContextValue {
8
- theme: UnityTheme
9
- setTheme: (theme: UnityTheme) => void
10
- }
11
-
12
- const UnityThemeContext = createContext<UnityThemeContextValue>({
13
- // Render legacy by default for backwards compatibility
14
- theme: 'legacy',
15
- // Intentional noop. Will be replaced by a set dispatcher from React
16
- // eslint-disable-next-line @typescript-eslint/no-empty-function
17
- setTheme: () => {},
18
- })
19
-
20
- export interface UnityThemeProviderProps {
21
- /** Initial theme. Can be changed at runtime via `useUnityTheme().setTheme`. */
22
- theme?: UnityTheme
23
- /**
24
- * Element on which `data-uy-theme` is set.
25
- * - `undefined` (default): uses `document.documentElement` (`<html>`)
26
- * - A React ref: uses the referenced element
27
- * - A CSS selector string: uses `document.querySelector(selector)`
28
- * @default document.documentElement
29
- */
30
- target?: RefObject<HTMLElement | null> | string
31
- }
32
-
33
- function resolveTarget(
34
- target: UnityThemeProviderProps['target'],
35
- ): HTMLElement | null {
36
- if (target === undefined) return document.documentElement
37
- if (typeof target === 'string') return document.querySelector(target)
38
- return target.current
39
- }
40
-
41
- export function UnityThemeProvider({
42
- theme: initialTheme = 'legacy',
43
- target,
44
- children,
45
- }: PropsWithChildren<UnityThemeProviderProps>) {
46
- const [theme, setTheme] = useState<UnityTheme>(initialTheme)
47
-
48
- useEffect(() => {
49
- const el = resolveTarget(target)
50
- if (!el) return
51
-
52
- el.dataset.uyTheme = theme
53
-
54
- return () => {
55
- delete el.dataset.uyTheme
56
- }
57
- }, [theme, target])
58
-
59
- return (
60
- <UnityThemeContext.Provider value={{ theme, setTheme }}>
61
- {children}
62
- </UnityThemeContext.Provider>
63
- )
64
- }
65
-
66
- /**
67
- * Returns the current theme and a setter to change it at runtime.
68
- * Returns `"legacy"` with a no-op setter when used outside a provider.
69
- */
70
- export function useUnityTheme(): UnityThemeContextValue {
71
- return useContext(UnityThemeContext)
72
- }
package/src/index.ts DELETED
@@ -1,15 +0,0 @@
1
- // Core utilities
2
- export * from './utils/cn'
3
- export * from './utils/tailwind-merge'
4
- export * from './utils/tailwind-variants'
5
-
6
- // Configuration (for advanced users)
7
- export { twMergeConfig } from './utils/merge-config'
8
-
9
- // Theme provider
10
- export {
11
- UnityThemeProvider,
12
- useUnityTheme,
13
- type UnityTheme,
14
- type UnityThemeProviderProps,
15
- } from './components/unity-theme-provider'
@@ -1,73 +0,0 @@
1
- import fs from 'fs'
2
- import path from 'path'
3
-
4
- import type { Config, Dictionary, PlatformConfig } from 'style-dictionary/types'
5
-
6
- export function appendAnimations(
7
- dictionary: Dictionary,
8
- config: PlatformConfig,
9
- options: Config,
10
- ) {
11
- if (!config.animationsPath) {
12
- console.warn('No animationsPath specified in config')
13
- return
14
- }
15
- if (!config.files || config.files.length === 0) {
16
- console.warn('No output files specified in config')
17
- return
18
- }
19
- if (!config.buildPath) {
20
- console.warn('No buildPath specified in config')
21
- return
22
- }
23
-
24
- const animationsDir = config.animationsPath as string
25
- const outputFile = config.files[0]?.destination ?? ''
26
- const cssPath = path.join(config.buildPath, outputFile)
27
-
28
- if (!fs.existsSync(animationsDir)) {
29
- console.warn(`Animations directory not found: ${animationsDir}`)
30
- return
31
- }
32
-
33
- const animationFiles = fs
34
- .readdirSync(animationsDir)
35
- .filter(file => file.endsWith('.css'))
36
-
37
- const animations = animationFiles
38
- .map(file => fs.readFileSync(path.join(animationsDir, file), 'utf8'))
39
- .join('\n\n')
40
-
41
- const css = fs.readFileSync(cssPath, 'utf8')
42
- const finalCSS = `${css}\n\n${animations}`
43
-
44
- fs.writeFileSync(cssPath, finalCSS)
45
- }
46
-
47
- export function removeAnimations(
48
- dictionary: Dictionary,
49
- config: PlatformConfig,
50
- options: Config,
51
- ) {
52
- if (!config.animationsPath) {
53
- console.warn('No animationsPath specified in config')
54
- return
55
- }
56
- if (!config.files || config.files.length === 0) {
57
- console.warn('No output files specified in config')
58
- return
59
- }
60
- if (!config.buildPath) {
61
- console.warn('No buildPath specified in config')
62
- return
63
- }
64
-
65
- const outputFile = config.files[0]?.destination ?? ''
66
- const cssPath = path.join(config.buildPath, outputFile)
67
-
68
- // erase animations from the file
69
- const css = fs.readFileSync(cssPath, 'utf8')
70
- const finalCSS = css.replace(/@keyframes\s+\w+\s*\{[\s\S]*?\}/g, '')
71
-
72
- fs.writeFileSync(cssPath, finalCSS)
73
- }
@@ -1,59 +0,0 @@
1
- /**
2
- * Composes the final multi-theme `unity.css` by concatenating the formatted
3
- * outputs from three SD instances into a single file.
4
- */
5
- import fs from 'fs'
6
- import path from 'path'
7
-
8
- import prettier from 'prettier'
9
-
10
- export interface ComposeInput {
11
- /** css/variables output for legacy (:root selector) */
12
- legacyCss: string
13
- /** css/variables output for rebrand ([data-uy-theme="rebrand"] selector) */
14
- rebrandCss: string
15
- /** css/unity-theme output (@theme block + grid/typography utilities) */
16
- themeCss: string
17
- /** File header + imports */
18
- header: string
19
- /** Custom variant declarations */
20
- customVariants: string
21
- /** Output path for the composed CSS */
22
- outputPath: string
23
- }
24
-
25
- export async function composeMultiThemeCss(input: ComposeInput): Promise<void> {
26
- const {
27
- legacyCss,
28
- rebrandCss,
29
- themeCss,
30
- header,
31
- customVariants,
32
- outputPath,
33
- } = input
34
-
35
- const css = `${header}
36
-
37
- @layer base {
38
- ${legacyCss}
39
-
40
- ${rebrandCss}
41
- }
42
-
43
- ${themeCss}
44
-
45
- ${customVariants}
46
- `
47
-
48
- console.log(' \x1b[2m→\x1b[0m Formatting with Prettier...')
49
- const formatted = await prettier.format(css, {
50
- parser: 'css',
51
- printWidth: 120,
52
- tabWidth: 2,
53
- useTabs: false,
54
- })
55
-
56
- fs.mkdirSync(path.dirname(outputPath), { recursive: true })
57
- fs.writeFileSync(outputPath, formatted)
58
- console.log(` \x1b[2m→\x1b[0m Written to \x1b[33m${outputPath}\x1b[0m`)
59
- }
@@ -1,140 +0,0 @@
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
- })
@@ -1,348 +0,0 @@
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
- }