@payfit/unity-themes 2.24.2 → 2.25.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 (57) hide show
  1. package/dist/css/unity.css +1653 -543
  2. package/dist/esm/components/unity-theme-provider.d.ts +25 -0
  3. package/dist/esm/components/unity-theme-provider.js +34 -0
  4. package/dist/esm/components/unity-theme-provider.test.d.ts +1 -0
  5. package/dist/esm/index.d.ts +1 -0
  6. package/dist/esm/index.js +8 -5
  7. package/dist/esm/scripts/actions/compose-multi-theme.d.ts +15 -0
  8. package/dist/esm/scripts/transforms/tailwind-color-token.d.ts +4 -3
  9. package/dist/esm/scripts/transforms/tailwind-grid-token.d.ts +2 -1
  10. package/dist/esm/scripts/transforms/tailwind-spacing-token.d.ts +1 -1
  11. package/dist/esm/scripts/transforms/tailwind-text-token.d.ts +1 -1
  12. package/dist/esm/scripts/transforms/tailwind-typography-token.d.ts +1 -4
  13. package/dist/esm/scripts/utils/prefix-transform.d.ts +4 -0
  14. package/dist/esm/utils/cn.d.ts +4 -3
  15. package/package.json +3 -2
  16. package/src/components/unity-theme-provider.stories.tsx +532 -0
  17. package/src/components/unity-theme-provider.test.tsx +150 -0
  18. package/src/components/unity-theme-provider.tsx +72 -0
  19. package/src/index.ts +8 -0
  20. package/src/scripts/actions/compose-multi-theme.ts +59 -0
  21. package/src/scripts/build.ts +261 -55
  22. package/src/scripts/formats/unity-theme.test.ts +180 -253
  23. package/src/scripts/formats/unity-theme.ts +27 -64
  24. package/src/scripts/transforms/tailwind-color-token.test.ts +18 -0
  25. package/src/scripts/transforms/tailwind-color-token.ts +7 -3
  26. package/src/scripts/transforms/tailwind-grid-token.test.ts +22 -0
  27. package/src/scripts/transforms/tailwind-grid-token.ts +7 -3
  28. package/src/scripts/transforms/tailwind-spacing-token.test.ts +9 -0
  29. package/src/scripts/transforms/tailwind-spacing-token.ts +15 -2
  30. package/src/scripts/transforms/tailwind-text-token.test.ts +18 -0
  31. package/src/scripts/transforms/tailwind-text-token.ts +15 -2
  32. package/src/scripts/transforms/tailwind-typography-token.test.ts +8 -2
  33. package/src/scripts/transforms/tailwind-typography-token.ts +5 -1
  34. package/src/scripts/utils/prefix-transform.test.ts +137 -0
  35. package/src/scripts/utils/prefix-transform.ts +16 -0
  36. package/src/utils/cn.ts +2 -2
  37. package/tokens/common/aspect-ratios.json +11 -0
  38. package/tokens/common/breakpoints.json +18 -0
  39. package/tokens/{text.json → common/font-sizes.json} +0 -28
  40. package/tokens/common/font-weights.json +18 -0
  41. package/tokens/{radii.json → common/radii.json} +0 -15
  42. package/tokens/{spacings.json → common/spacings.json} +0 -25
  43. package/tokens/legacy/radii.json +21 -0
  44. package/tokens/legacy/text.json +14 -0
  45. package/tokens/rebrand/colors.json +1400 -0
  46. package/tokens/rebrand/radii.json +21 -0
  47. package/tokens/rebrand/shadows.json +81 -0
  48. package/tokens/rebrand/text.json +14 -0
  49. package/tokens/rebrand/typography.json +329 -0
  50. package/dist/esm/scripts/formats/generators/header-generator.d.ts +0 -2
  51. package/src/scripts/formats/generators/header-generator.ts +0 -32
  52. /package/tokens/{animations.json → common/animations.json} +0 -0
  53. /package/tokens/{layout.json → common/layout.json} +0 -0
  54. /package/tokens/{sizes.json → common/sizes.json} +0 -0
  55. /package/tokens/{colors.json → legacy/colors.json} +0 -0
  56. /package/tokens/{shadows.json → legacy/shadows.json} +0 -0
  57. /package/tokens/{typography.json → legacy/typography.json} +0 -0
@@ -1,13 +1,15 @@
1
1
  import type { Token } from 'style-dictionary'
2
2
  import type { NameTransform } from 'style-dictionary/types'
3
3
 
4
+ import { prefixTransform } from '../utils/prefix-transform'
5
+
4
6
  type Transformer = NameTransform['transform']
5
7
 
6
8
  export function filter(token: Token): boolean {
7
9
  return token.attributes?.category === 'grid'
8
10
  }
9
11
 
10
- export const transform: Transformer = token => {
12
+ export const tailwindGridTokenNameTransform: Transformer = (token, config) => {
11
13
  if (!token.attributes) {
12
14
  return token.name
13
15
  }
@@ -17,7 +19,9 @@ export const transform: Transformer = token => {
17
19
  >
18
20
  let name = String(category)
19
21
  if (type) name += `-${type}`
20
- if (item) name += `-${subitem}`
21
- if (subitem) name += `--${item}`
22
+ if (subitem) name += `-${subitem}`
23
+ if (item) name += `--${item}`
22
24
  return name
23
25
  }
26
+
27
+ export const transform = prefixTransform(tailwindGridTokenNameTransform)
@@ -302,5 +302,14 @@ describe('tailwind spacing token transform', () => {
302
302
  expect(result).toBe(expected)
303
303
  })
304
304
  })
305
+
306
+ it('should prepend prefix when config.prefix is set', () => {
307
+ const token = createMockToken(['spacing', '1', 'base'])
308
+ const config = { ...createMockPlatformConfig(), prefix: 'uy' }
309
+
310
+ const result = transform(token, config)
311
+
312
+ expect(result).toBe('uy-spacing-1')
313
+ })
305
314
  })
306
315
  })
@@ -1,11 +1,24 @@
1
1
  import type { Token } from 'style-dictionary'
2
- import type { Config, PlatformConfig } from 'style-dictionary/types'
2
+ import type {
3
+ Config,
4
+ NameTransform,
5
+ PlatformConfig,
6
+ } from 'style-dictionary/types'
7
+
8
+ import { prefixTransform } from '../utils/prefix-transform'
9
+
10
+ type Transformer = NameTransform['transform']
3
11
 
4
12
  export function filter(token: Token, options: Config): boolean {
5
13
  return token.path[0] === 'spacing'
6
14
  }
7
15
 
8
- export function transform(token: Token, _config: PlatformConfig): string {
16
+ const tailwindSpacingTokenNameTransform: Transformer = (
17
+ token: Token,
18
+ config: PlatformConfig,
19
+ ) => {
9
20
  const ignoreDefault = (nameToken: string) => !nameToken.includes('base')
10
21
  return [...(token.path as string[]).filter(ignoreDefault)].join('-')
11
22
  }
23
+
24
+ export const transform = prefixTransform(tailwindSpacingTokenNameTransform)
@@ -306,5 +306,23 @@ describe('tailwind text token transform', () => {
306
306
  expect(result).toBe(expected)
307
307
  })
308
308
  })
309
+
310
+ it('should prepend prefix when config.prefix is set', () => {
311
+ const token = createMockToken(['text', 'heading'])
312
+ const config = { ...createMockPlatformConfig(), prefix: 'uy' }
313
+
314
+ const result = transform(token, config)
315
+
316
+ expect(result).toBe('uy-text-heading')
317
+ })
318
+
319
+ it('should prepend prefix with -- variant when config.prefix is set', () => {
320
+ const token = createMockToken(['text', 'heading--large'])
321
+ const config = { ...createMockPlatformConfig(), prefix: 'uy' }
322
+
323
+ const result = transform(token, config)
324
+
325
+ expect(result).toBe('uy-text-heading--large')
326
+ })
309
327
  })
310
328
  })
@@ -1,11 +1,22 @@
1
1
  import type { Token } from 'style-dictionary'
2
- import type { Config, PlatformConfig } from 'style-dictionary/types'
2
+ import type {
3
+ Config,
4
+ NameTransform,
5
+ PlatformConfig,
6
+ } from 'style-dictionary/types'
7
+
8
+ import { prefixTransform } from '../utils/prefix-transform'
9
+
10
+ type Transformer = NameTransform['transform']
3
11
 
4
12
  export function filter(token: Token, options: Config): boolean {
5
13
  return token.path[0] === 'text'
6
14
  }
7
15
 
8
- export function transform(token: Token, _config: PlatformConfig): string {
16
+ const tailwindTextTokenNameTransform: Transformer = (
17
+ token: Token,
18
+ config: PlatformConfig,
19
+ ) => {
9
20
  const path = token.path as string[]
10
21
 
11
22
  if (path[1]?.includes('--')) {
@@ -15,3 +26,5 @@ export function transform(token: Token, _config: PlatformConfig): string {
15
26
 
16
27
  return `text-${path[1]}`
17
28
  }
29
+
30
+ export const transform = prefixTransform(tailwindTextTokenNameTransform)
@@ -36,14 +36,20 @@ describe('tailwind typography token transform', () => {
36
36
  describe('transform', () => {
37
37
  it('should reorder the path elements correctly', () => {
38
38
  const token = createMockToken(['typography', 'h1', 'sm'])
39
- const result = transform(token, {} as any, {})
39
+ const result = transform(token, {}, {})
40
40
  expect(result).toBe('typography-sm-h1')
41
41
  })
42
42
 
43
43
  it('should handle "default" breakpoint correctly', () => {
44
44
  const token = createMockToken(['typography', 'h1', 'default'])
45
- const result = transform(token, {} as any, {})
45
+ const result = transform(token, {}, {})
46
46
  expect(result).toBe('typography-default-h1')
47
47
  })
48
+
49
+ it('should prepend prefix when config.prefix is set', () => {
50
+ const token = createMockToken(['typography', 'h1', 'sm'])
51
+ const result = transform(token, { prefix: 'uy' }, {})
52
+ expect(result).toBe('uy-typography-sm-h1')
53
+ })
48
54
  })
49
55
  })
@@ -1,16 +1,20 @@
1
1
  import type { Token } from 'style-dictionary'
2
2
  import type { NameTransform } from 'style-dictionary/types'
3
3
 
4
+ import { prefixTransform } from '../utils/prefix-transform'
5
+
4
6
  type Transformer = NameTransform['transform']
5
7
 
6
8
  export function filter(token: Token): boolean {
7
9
  return token.$type === 'typography'
8
10
  }
9
11
 
10
- export const transform: Transformer = token => {
12
+ const tailwindTypographyTransform: Transformer = (token, config) => {
11
13
  const [_category, type, item] = token.path
12
14
  // Reorders the token path from [typography, h1, sm]
13
15
  // to the string "typography-sm-h1"
14
16
  const newPath = ['typography', item, type]
15
17
  return newPath.join('-')
16
18
  }
19
+
20
+ export const transform = prefixTransform(tailwindTypographyTransform)
@@ -0,0 +1,137 @@
1
+ import type {
2
+ Config,
3
+ PlatformConfig,
4
+ TransformedToken,
5
+ } from 'style-dictionary/types'
6
+
7
+ import { describe, expect, it, vi } from 'vitest'
8
+
9
+ import { prefixTransform } from './prefix-transform.js'
10
+
11
+ describe('prefixTransform', () => {
12
+ const createMockToken = (): TransformedToken =>
13
+ ({
14
+ name: 'test-token',
15
+ value: '#000000',
16
+ type: 'color',
17
+ path: ['color', 'primary'],
18
+ original: {},
19
+ filePath: '',
20
+ isSource: false,
21
+ }) as TransformedToken
22
+
23
+ const createMockConfig = (prefix?: string): PlatformConfig =>
24
+ ({
25
+ platforms: {},
26
+ source: [],
27
+ include: [],
28
+ prefix,
29
+ }) as unknown as PlatformConfig
30
+
31
+ const createMockOptions = (): Config =>
32
+ ({
33
+ platforms: {},
34
+ source: [],
35
+ include: [],
36
+ }) as Config
37
+
38
+ describe('without prefix', () => {
39
+ it('should return the original transformer value when no prefix is set', () => {
40
+ const transformer = vi.fn(() => 'color-primary')
41
+ const wrapped = prefixTransform(transformer)
42
+
43
+ const result = wrapped(
44
+ createMockToken(),
45
+ createMockConfig(),
46
+ createMockOptions(),
47
+ )
48
+
49
+ expect(result).toBe('color-primary')
50
+ })
51
+
52
+ it('should return the original transformer value when prefix is empty string', () => {
53
+ const transformer = vi.fn(() => 'color-primary')
54
+ const wrapped = prefixTransform(transformer)
55
+
56
+ const result = wrapped(
57
+ createMockToken(),
58
+ createMockConfig(''),
59
+ createMockOptions(),
60
+ )
61
+
62
+ expect(result).toBe('color-primary')
63
+ })
64
+ })
65
+
66
+ describe('with prefix', () => {
67
+ it('should prepend the prefix to the transformer value', () => {
68
+ const transformer = vi.fn(() => 'color-primary')
69
+ const wrapped = prefixTransform(transformer)
70
+
71
+ const result = wrapped(
72
+ createMockToken(),
73
+ createMockConfig('uy'),
74
+ createMockOptions(),
75
+ )
76
+
77
+ expect(result).toBe('uy-color-primary')
78
+ })
79
+
80
+ it('should work with different prefix values', () => {
81
+ const transformer = vi.fn(() => 'spacing-md')
82
+ const wrapped = prefixTransform(transformer)
83
+
84
+ const result = wrapped(
85
+ createMockToken(),
86
+ createMockConfig('my-prefix'),
87
+ createMockOptions(),
88
+ )
89
+
90
+ expect(result).toBe('my-prefix-spacing-md')
91
+ })
92
+ })
93
+
94
+ describe('async transformer', () => {
95
+ it('should handle a transformer that returns a Promise', async () => {
96
+ const transformer = vi.fn(() => Promise.resolve('color-primary'))
97
+ const wrapped = prefixTransform(transformer)
98
+
99
+ const result = wrapped(
100
+ createMockToken(),
101
+ createMockConfig('uy'),
102
+ createMockOptions(),
103
+ )
104
+
105
+ expect(result).toBeInstanceOf(Promise)
106
+ await expect(result).resolves.toBe('uy-color-primary')
107
+ })
108
+
109
+ it('should handle a Promise result without prefix', async () => {
110
+ const transformer = vi.fn(() => Promise.resolve('color-primary'))
111
+ const wrapped = prefixTransform(transformer)
112
+
113
+ const result = wrapped(
114
+ createMockToken(),
115
+ createMockConfig(),
116
+ createMockOptions(),
117
+ )
118
+
119
+ await expect(result).resolves.toBe('color-primary')
120
+ })
121
+ })
122
+
123
+ describe('argument passthrough', () => {
124
+ it('should forward all arguments to the wrapped transformer', () => {
125
+ const transformer = vi.fn(() => 'result')
126
+ const wrapped = prefixTransform(transformer)
127
+
128
+ const token = createMockToken()
129
+ const config = createMockConfig('uy')
130
+ const options = createMockOptions()
131
+
132
+ void wrapped(token, config, options)
133
+
134
+ expect(transformer).toHaveBeenCalledWith(token, config, options)
135
+ })
136
+ })
137
+ })
@@ -0,0 +1,16 @@
1
+ import type { NameTransform } from 'style-dictionary/types'
2
+
3
+ type Transformer = NameTransform['transform']
4
+
5
+ export const prefixTransform: (transformer: Transformer) => Transformer =
6
+ transformer =>
7
+ (...args) => {
8
+ const [, config] = args
9
+ const prefix = config.prefix ? `${config.prefix}-` : ''
10
+ const value = transformer(...args)
11
+
12
+ if (value instanceof Promise) {
13
+ return value.then(val => `${prefix}${val}`)
14
+ }
15
+ return `${prefix}${value}`
16
+ }
package/src/utils/cn.ts CHANGED
@@ -6,8 +6,8 @@ import { twMergeConfig } from './merge-config'
6
6
  * Internal Unity-configured class name utility function.
7
7
  * @internal
8
8
  */
9
- const uyCn = (...classes: string[]) =>
10
- cnMerge(...classes)({
9
+ const uyCn = (...params: Parameters<typeof cnMerge>) =>
10
+ cnMerge(...params)({
11
11
  twMerge: true,
12
12
  twMergeConfig,
13
13
  })
@@ -0,0 +1,11 @@
1
+ {
2
+ "aspect": {
3
+ "$type": "number",
4
+ "video": {
5
+ "$value": "16 / 9"
6
+ },
7
+ "square": {
8
+ "$value": "1 / 1"
9
+ }
10
+ }
11
+ }
@@ -0,0 +1,18 @@
1
+ {
2
+ "breakpoint": {
3
+ "$type": "dimension",
4
+ "$description": "Supported viewport breakpoints",
5
+ "sm": {
6
+ "$value": "490px"
7
+ },
8
+ "md": {
9
+ "$value": "768px"
10
+ },
11
+ "lg": {
12
+ "$value": "1280px"
13
+ },
14
+ "xl": {
15
+ "$value": "1440px"
16
+ }
17
+ }
18
+ }
@@ -1,32 +1,4 @@
1
1
  {
2
- "font": {
3
- "$type": "fontFamily",
4
- "serif": {
5
- "$value": ["Source Serif 4", "serif"]
6
- },
7
- "sans": {
8
- "$value": ["Inter", "sans-serif"]
9
- },
10
- "mono": {
11
- "$value": ["Roboto Mono", "monospace"]
12
- }
13
- },
14
- "font-weight": {
15
- "$type": "fontWeight",
16
- "$description": "Font weights for the design system",
17
- "regular": {
18
- "$value": 400
19
- },
20
- "medium": {
21
- "$value": 500
22
- },
23
- "semibold": {
24
- "$value": 600
25
- },
26
- "bold": {
27
- "$value": 700
28
- }
29
- },
30
2
  "text": {
31
3
  "$type": "dimension",
32
4
  "$description": "Font sizes for the design system",
@@ -0,0 +1,18 @@
1
+ {
2
+ "font-weight": {
3
+ "$type": "fontWeight",
4
+ "$description": "Font weights for the design system",
5
+ "regular": {
6
+ "$value": 400
7
+ },
8
+ "medium": {
9
+ "$value": 500
10
+ },
11
+ "semibold": {
12
+ "$value": 600
13
+ },
14
+ "bold": {
15
+ "$value": 700
16
+ }
17
+ }
18
+ }
@@ -32,21 +32,6 @@
32
32
  "400": {
33
33
  "$value": "32px"
34
34
  },
35
- "xs": {
36
- "$value": "{radius.50}"
37
- },
38
- "sm": {
39
- "$value": "{radius.75}"
40
- },
41
- "md": {
42
- "$value": "{radius.100}"
43
- },
44
- "lg": {
45
- "$value": "{radius.200}"
46
- },
47
- "xl": {
48
- "$value": "{radius.300}"
49
- },
50
35
  "circle": {
51
36
  "$value": "50%",
52
37
  "$extensions": {
@@ -51,30 +51,5 @@
51
51
  "1000": {
52
52
  "$value": "80px"
53
53
  }
54
- },
55
- "breakpoint": {
56
- "$type": "dimension",
57
- "$description": "Supported viewport breakpoints",
58
- "sm": {
59
- "$value": "490px"
60
- },
61
- "md": {
62
- "$value": "768px"
63
- },
64
- "lg": {
65
- "$value": "1280px"
66
- },
67
- "xl": {
68
- "$value": "1440px"
69
- }
70
- },
71
- "aspect": {
72
- "$type": "number",
73
- "video": {
74
- "$value": "16 / 9"
75
- },
76
- "square": {
77
- "$value": "1 / 1"
78
- }
79
54
  }
80
55
  }
@@ -0,0 +1,21 @@
1
+ {
2
+ "radius": {
3
+ "$type": "dimension",
4
+ "$description": "Semantic Corner radius scale for the design system",
5
+ "xs": {
6
+ "$value": "{radius.50}"
7
+ },
8
+ "sm": {
9
+ "$value": "{radius.75}"
10
+ },
11
+ "md": {
12
+ "$value": "{radius.100}"
13
+ },
14
+ "lg": {
15
+ "$value": "{radius.200}"
16
+ },
17
+ "xl": {
18
+ "$value": "{radius.300}"
19
+ }
20
+ }
21
+ }
@@ -0,0 +1,14 @@
1
+ {
2
+ "font": {
3
+ "$type": "fontFamily",
4
+ "serif": {
5
+ "$value": ["Source Serif 4", "serif"]
6
+ },
7
+ "sans": {
8
+ "$value": ["Inter", "sans-serif"]
9
+ },
10
+ "mono": {
11
+ "$value": ["Roboto Mono", "monospace"]
12
+ }
13
+ }
14
+ }