@discourser/design-system 0.20.1 → 0.22.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.
- package/dist/{chunk-L5FO6K6L.cjs → chunk-IGCGVSG4.cjs} +156 -87
- package/dist/chunk-IGCGVSG4.cjs.map +1 -0
- package/dist/{chunk-WFKEAD5P.js → chunk-VJN7TIGL.js} +156 -87
- package/dist/chunk-VJN7TIGL.js.map +1 -0
- package/dist/components/Checkbox.d.ts +3 -3
- package/dist/components/Icons/TrashIcon.d.ts +6 -0
- package/dist/components/Icons/TrashIcon.d.ts.map +1 -0
- package/dist/components/Icons/index.d.ts +1 -0
- package/dist/components/Icons/index.d.ts.map +1 -1
- package/dist/figma-codex.json +2 -2
- package/dist/index.cjs +4 -4
- package/dist/index.js +1 -1
- package/dist/languages/transform.d.ts +1 -8
- package/dist/languages/transform.d.ts.map +1 -1
- package/dist/preset/index.cjs +2 -2
- package/dist/preset/index.d.ts.map +1 -1
- package/dist/preset/index.js +1 -1
- package/dist/preset/semantic-tokens.d.ts +95 -45
- package/dist/preset/semantic-tokens.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/__tests__/token-contract.test.ts +168 -0
- package/src/components/Icons/TrashIcon.tsx +34 -0
- package/src/components/Icons/index.ts +1 -0
- package/src/languages/transform.ts +74 -52
- package/src/preset/index.ts +14 -5
- package/src/preset/semantic-tokens.ts +120 -53
- package/dist/chunk-L5FO6K6L.cjs.map +0 -1
- package/dist/chunk-WFKEAD5P.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"semantic-tokens.d.ts","sourceRoot":"","sources":["../../src/preset/semantic-tokens.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"semantic-tokens.d.ts","sourceRoot":"","sources":["../../src/preset/semantic-tokens.ts"],"names":[],"mappings":"AAiBA;;;GAGG;AACH,eAAO,MAAM,mBAAmB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA4H9B,CAAC"}
|
package/package.json
CHANGED
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Token Contract Tests
|
|
3
|
+
*
|
|
4
|
+
* Permanent regression guard. Prevents semantic-tokens.ts from drifting out of sync
|
|
5
|
+
* with material3.language.ts. Run in CI on every PR.
|
|
6
|
+
*
|
|
7
|
+
* If any test here fails, a semantic role is missing or broken. Fix the gap in
|
|
8
|
+
* semantic-tokens.ts — do not adjust these tests.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import { describe, test, expect } from 'vitest';
|
|
12
|
+
import { material3Language } from '../languages/material3.language';
|
|
13
|
+
import { semanticColorTokens } from '../preset/semantic-tokens';
|
|
14
|
+
import { discourserPandaPreset } from '../preset/index';
|
|
15
|
+
|
|
16
|
+
// ---------------------------------------------------------------------------
|
|
17
|
+
// Check 1: Coverage — every language semantic role is represented in the preset
|
|
18
|
+
// ---------------------------------------------------------------------------
|
|
19
|
+
|
|
20
|
+
describe('Semantic token coverage', () => {
|
|
21
|
+
const languageRoles = Object.keys(material3Language.semantic);
|
|
22
|
+
const presetKeys = flattenTokenKeys(semanticColorTokens);
|
|
23
|
+
|
|
24
|
+
test.each(languageRoles)(
|
|
25
|
+
'"%s" from language contract is represented in semanticColorTokens',
|
|
26
|
+
(role) => {
|
|
27
|
+
// Normalize: strip `.DEFAULT` suffix, remove all dots, lowercase.
|
|
28
|
+
// This lets `primaryContainer` match `primary.container`, etc.
|
|
29
|
+
const normalize = (k: string) =>
|
|
30
|
+
k
|
|
31
|
+
.toLowerCase()
|
|
32
|
+
.replace(/\.default$/i, '')
|
|
33
|
+
.replace(/\./g, '');
|
|
34
|
+
const normalizedRole = normalize(role);
|
|
35
|
+
const found = presetKeys.some((k) => normalize(k) === normalizedRole);
|
|
36
|
+
expect(found).toBe(true);
|
|
37
|
+
},
|
|
38
|
+
);
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
// ---------------------------------------------------------------------------
|
|
42
|
+
// Check 2: No undefined or empty values in any token definition
|
|
43
|
+
// ---------------------------------------------------------------------------
|
|
44
|
+
|
|
45
|
+
describe('Semantic token values', () => {
|
|
46
|
+
test('no token has an undefined or empty light value', () => {
|
|
47
|
+
walkTokens(semanticColorTokens, (_path, token) => {
|
|
48
|
+
if (
|
|
49
|
+
token.value &&
|
|
50
|
+
typeof token.value === 'object' &&
|
|
51
|
+
'base' in token.value
|
|
52
|
+
) {
|
|
53
|
+
expect(token.value.base).toBeDefined();
|
|
54
|
+
expect(token.value.base).not.toBe('');
|
|
55
|
+
expect(token.value.base).toMatch(/^#[0-9A-Fa-f]{6}$/);
|
|
56
|
+
}
|
|
57
|
+
});
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
test('no token has an undefined or empty dark value', () => {
|
|
61
|
+
walkTokens(semanticColorTokens, (_path, token) => {
|
|
62
|
+
if (
|
|
63
|
+
token.value &&
|
|
64
|
+
typeof token.value === 'object' &&
|
|
65
|
+
'_dark' in token.value
|
|
66
|
+
) {
|
|
67
|
+
expect(token.value._dark).toBeDefined();
|
|
68
|
+
expect(token.value._dark).not.toBe('');
|
|
69
|
+
expect(token.value._dark).toMatch(/^#[0-9A-Fa-f]{6}$/);
|
|
70
|
+
}
|
|
71
|
+
});
|
|
72
|
+
});
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
// ---------------------------------------------------------------------------
|
|
76
|
+
// Check 3: Language contract symmetry — semantic and semanticDark have identical keys
|
|
77
|
+
// ---------------------------------------------------------------------------
|
|
78
|
+
|
|
79
|
+
describe('Language contract symmetry', () => {
|
|
80
|
+
test('semanticDark has the same keys as semantic', () => {
|
|
81
|
+
const lightKeys = Object.keys(material3Language.semantic).sort();
|
|
82
|
+
const darkKeys = Object.keys(material3Language.semanticDark!).sort();
|
|
83
|
+
expect(darkKeys).toEqual(lightKeys);
|
|
84
|
+
});
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
// ---------------------------------------------------------------------------
|
|
88
|
+
// Check 4: Preset assembly — Radix bridge keys AND semantic keys coexist after deep-merge
|
|
89
|
+
// ---------------------------------------------------------------------------
|
|
90
|
+
|
|
91
|
+
describe('Preset color assembly', () => {
|
|
92
|
+
const colors = discourserPandaPreset.theme?.extend?.semanticTokens
|
|
93
|
+
?.colors as Record<string, Record<string, unknown>>;
|
|
94
|
+
|
|
95
|
+
test.each(['primary', 'secondary', 'tertiary', 'error'])(
|
|
96
|
+
'%s has both Radix bridge keys (1, 12) and semantic keys (DEFAULT, container)',
|
|
97
|
+
(palette) => {
|
|
98
|
+
expect(colors[palette]['1']).toBeDefined();
|
|
99
|
+
expect(colors[palette]['12']).toBeDefined();
|
|
100
|
+
expect(colors[palette]['DEFAULT']).toBeDefined();
|
|
101
|
+
expect(colors[palette]['container']).toBeDefined();
|
|
102
|
+
},
|
|
103
|
+
);
|
|
104
|
+
|
|
105
|
+
test('surface has full nested container structure', () => {
|
|
106
|
+
const surface = colors['surface'] as Record<string, unknown>;
|
|
107
|
+
expect(surface['DEFAULT']).toBeDefined();
|
|
108
|
+
expect(
|
|
109
|
+
(surface['container'] as Record<string, unknown>)?.['DEFAULT'],
|
|
110
|
+
).toBeDefined();
|
|
111
|
+
expect(
|
|
112
|
+
(surface['container'] as Record<string, unknown>)?.['low'],
|
|
113
|
+
).toBeDefined();
|
|
114
|
+
expect(
|
|
115
|
+
(surface['container'] as Record<string, unknown>)?.['highest'],
|
|
116
|
+
).toBeDefined();
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
test('onSurface has variant subkey', () => {
|
|
120
|
+
const onSurface = colors['onSurface'] as Record<string, unknown>;
|
|
121
|
+
expect(onSurface['DEFAULT']).toBeDefined();
|
|
122
|
+
expect(onSurface['variant']).toBeDefined();
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
test('previously missing tokens are now present', () => {
|
|
126
|
+
expect(colors['background']).toBeDefined();
|
|
127
|
+
expect(colors['onBackground']).toBeDefined();
|
|
128
|
+
expect(colors['shadow']).toBeDefined();
|
|
129
|
+
expect(colors['surfaceVariant']).toBeDefined();
|
|
130
|
+
expect(
|
|
131
|
+
(colors['onError'] as Record<string, unknown>)?.['DEFAULT'],
|
|
132
|
+
).toBeDefined();
|
|
133
|
+
expect(
|
|
134
|
+
(colors['error'] as Record<string, unknown>)?.['container'],
|
|
135
|
+
).toBeDefined();
|
|
136
|
+
});
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
// ---------------------------------------------------------------------------
|
|
140
|
+
// Helpers
|
|
141
|
+
// ---------------------------------------------------------------------------
|
|
142
|
+
|
|
143
|
+
/** Flatten nested token object to dot-notation key array */
|
|
144
|
+
function flattenTokenKeys(obj: Record<string, unknown>, prefix = ''): string[] {
|
|
145
|
+
return Object.entries(obj).flatMap(([key, val]) => {
|
|
146
|
+
const fullKey = prefix ? `${prefix}.${key}` : key;
|
|
147
|
+
if (val && typeof val === 'object' && !('value' in (val as object))) {
|
|
148
|
+
return flattenTokenKeys(val as Record<string, unknown>, fullKey);
|
|
149
|
+
}
|
|
150
|
+
return [fullKey];
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/** Walk all leaf token nodes and call callback */
|
|
155
|
+
function walkTokens(
|
|
156
|
+
obj: Record<string, unknown>,
|
|
157
|
+
callback: (path: string, token: { value: unknown }) => void,
|
|
158
|
+
prefix = '',
|
|
159
|
+
) {
|
|
160
|
+
for (const [key, val] of Object.entries(obj)) {
|
|
161
|
+
const path = prefix ? `${prefix}.${key}` : key;
|
|
162
|
+
if (val && typeof val === 'object' && 'value' in (val as object)) {
|
|
163
|
+
callback(path, val as { value: unknown });
|
|
164
|
+
} else if (val && typeof val === 'object') {
|
|
165
|
+
walkTokens(val as Record<string, unknown>, callback, path);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { ark } from '@ark-ui/react/factory';
|
|
2
|
+
import type { ComponentProps } from 'react';
|
|
3
|
+
import { styled } from 'styled-system/jsx';
|
|
4
|
+
|
|
5
|
+
const StyledSvg = styled(ark.svg);
|
|
6
|
+
|
|
7
|
+
export type TrashIconProps = ComponentProps<typeof StyledSvg>;
|
|
8
|
+
|
|
9
|
+
export const TrashIcon = (props: TrashIconProps) => (
|
|
10
|
+
<StyledSvg
|
|
11
|
+
viewBox="0 0 44 51"
|
|
12
|
+
fill="none"
|
|
13
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
14
|
+
width="1em"
|
|
15
|
+
height="1em"
|
|
16
|
+
{...props}
|
|
17
|
+
>
|
|
18
|
+
<path d="M15.24 17.7998H17.8V38.2798H15.24V17.7998Z" fill="currentColor" />
|
|
19
|
+
<path
|
|
20
|
+
d="M20.3601 17.7998H22.9201V38.2798H20.3601V17.7998Z"
|
|
21
|
+
fill="currentColor"
|
|
22
|
+
/>
|
|
23
|
+
<path d="M25.48 17.7998H28.04V38.2798H25.48V17.7998Z" fill="currentColor" />
|
|
24
|
+
<path d="M5 10.1201H38.28V12.6801H5V10.1201Z" fill="currentColor" />
|
|
25
|
+
<path
|
|
26
|
+
d="M28.04 10.12H25.48V8.84C25.48 8.072 24.968 7.56 24.2 7.56H19.08C18.312 7.56 17.8 8.072 17.8 8.84V10.12H15.24V8.84C15.24 6.664 16.904 5 19.08 5H24.2C26.376 5 28.04 6.664 28.04 8.84V10.12Z"
|
|
27
|
+
fill="currentColor"
|
|
28
|
+
/>
|
|
29
|
+
<path
|
|
30
|
+
d="M29.3201 45.96H13.9601C11.9121 45.96 10.1201 44.296 9.86406 42.248L7.56006 11.528L10.1201 11.272L12.4241 41.992C12.4241 42.76 13.1921 43.4 13.9601 43.4H29.3201C30.0881 43.4 30.7281 42.76 30.8561 41.992L33.1601 11.272L35.7201 11.528L33.4161 42.248C33.1601 44.296 31.3681 45.96 29.3201 45.96Z"
|
|
31
|
+
fill="currentColor"
|
|
32
|
+
/>
|
|
33
|
+
</StyledSvg>
|
|
34
|
+
);
|
|
@@ -37,3 +37,4 @@ export {
|
|
|
37
37
|
export { UserProfileIcon, type UserProfileIconProps } from './UserProfileIcon';
|
|
38
38
|
export { PlayIcon, type PlayIconProps } from './PlayIcon';
|
|
39
39
|
export { SpeechIcon, type SpeechIconProps } from './SpeechIcon';
|
|
40
|
+
export { TrashIcon, type TrashIconProps } from './TrashIcon';
|
|
@@ -1,4 +1,7 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type {
|
|
2
|
+
DesignLanguageContract,
|
|
3
|
+
TonalPalette,
|
|
4
|
+
} from '../contracts/design-language.contract';
|
|
2
5
|
/**
|
|
3
6
|
* Transforms a DesignLanguageContract into Panda CSS theme configuration
|
|
4
7
|
*/
|
|
@@ -6,47 +9,70 @@ export function transformToPandaTheme(language: DesignLanguageContract) {
|
|
|
6
9
|
return {
|
|
7
10
|
tokens: transformTokens(language),
|
|
8
11
|
semanticTokens: transformSemanticTokens(language),
|
|
9
|
-
textStyles: transformTextStyles(language)
|
|
12
|
+
textStyles: transformTextStyles(language),
|
|
10
13
|
};
|
|
11
14
|
}
|
|
12
15
|
|
|
13
16
|
function transformTokens(language: DesignLanguageContract) {
|
|
14
17
|
return {
|
|
15
|
-
colors: transformColorPalettes(
|
|
18
|
+
colors: transformColorPalettes(
|
|
19
|
+
language.colors as unknown as Record<string, TonalPalette>,
|
|
20
|
+
),
|
|
16
21
|
fonts: {
|
|
17
22
|
display: { value: language.typography.fonts.display },
|
|
18
23
|
body: { value: language.typography.fonts.body },
|
|
19
|
-
mono: { value: language.typography.fonts.mono }
|
|
24
|
+
mono: { value: language.typography.fonts.mono },
|
|
20
25
|
},
|
|
21
|
-
fontSizes: extractFontSizes(
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
26
|
+
fontSizes: extractFontSizes(
|
|
27
|
+
language.typography.scale as unknown as Record<
|
|
28
|
+
string,
|
|
29
|
+
{ fontSize: string }
|
|
30
|
+
>,
|
|
31
|
+
),
|
|
32
|
+
lineHeights: extractLineHeights(
|
|
33
|
+
language.typography.scale as unknown as Record<
|
|
34
|
+
string,
|
|
35
|
+
{ lineHeight: string }
|
|
36
|
+
>,
|
|
37
|
+
),
|
|
38
|
+
fontWeights: extractFontWeights(
|
|
39
|
+
language.typography.scale as unknown as Record<
|
|
40
|
+
string,
|
|
41
|
+
{ fontWeight: string }
|
|
42
|
+
>,
|
|
43
|
+
),
|
|
44
|
+
letterSpacings: extractLetterSpacings(
|
|
45
|
+
language.typography.scale as unknown as Record<
|
|
46
|
+
string,
|
|
47
|
+
{ letterSpacing: string }
|
|
48
|
+
>,
|
|
49
|
+
),
|
|
50
|
+
spacing: objectToTokens(
|
|
51
|
+
language.spacing as unknown as Record<string, string>,
|
|
52
|
+
),
|
|
53
|
+
radii: objectToTokens(
|
|
54
|
+
language.shape.radii as unknown as Record<string, string>,
|
|
55
|
+
),
|
|
56
|
+
shadows: objectToTokens(
|
|
57
|
+
language.elevation.levels as unknown as Record<string, string>,
|
|
58
|
+
),
|
|
59
|
+
durations: objectToTokens(
|
|
60
|
+
language.motion.durations as unknown as Record<string, string>,
|
|
61
|
+
),
|
|
62
|
+
easings: objectToTokens(
|
|
63
|
+
language.motion.easings as unknown as Record<string, string>,
|
|
64
|
+
),
|
|
65
|
+
borderWidths: objectToTokens(
|
|
66
|
+
language.border.widths as unknown as Record<string, string>,
|
|
67
|
+
),
|
|
31
68
|
};
|
|
32
69
|
}
|
|
33
70
|
|
|
34
|
-
function transformSemanticTokens(
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
71
|
+
function transformSemanticTokens(_language: DesignLanguageContract) {
|
|
72
|
+
// Semantic colors are now managed entirely by semantic-tokens.ts
|
|
73
|
+
// This prevents flat hex tokens from overwriting the nested semantic token structure
|
|
38
74
|
return {
|
|
39
|
-
colors:
|
|
40
|
-
Object.entries(light).map(([key, lightValue]) => [
|
|
41
|
-
key,
|
|
42
|
-
{
|
|
43
|
-
value: {
|
|
44
|
-
base: lightValue,
|
|
45
|
-
_dark: dark[key as keyof SemanticColors] || lightValue
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
])
|
|
49
|
-
)
|
|
75
|
+
colors: {},
|
|
50
76
|
};
|
|
51
77
|
}
|
|
52
78
|
|
|
@@ -62,10 +88,10 @@ function transformTextStyles(language: DesignLanguageContract) {
|
|
|
62
88
|
fontSize: style.fontSize,
|
|
63
89
|
lineHeight: style.lineHeight,
|
|
64
90
|
fontWeight: style.fontWeight,
|
|
65
|
-
letterSpacing: style.letterSpacing
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
])
|
|
91
|
+
letterSpacing: style.letterSpacing,
|
|
92
|
+
},
|
|
93
|
+
},
|
|
94
|
+
]),
|
|
69
95
|
);
|
|
70
96
|
}
|
|
71
97
|
|
|
@@ -74,18 +100,15 @@ function transformColorPalettes(palettes: Record<string, TonalPalette>) {
|
|
|
74
100
|
Object.entries(palettes).map(([name, palette]) => [
|
|
75
101
|
name,
|
|
76
102
|
Object.fromEntries(
|
|
77
|
-
Object.entries(palette).map(([tone, value]) => [
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
])
|
|
81
|
-
)
|
|
82
|
-
])
|
|
103
|
+
Object.entries(palette).map(([tone, value]) => [tone, { value }]),
|
|
104
|
+
),
|
|
105
|
+
]),
|
|
83
106
|
);
|
|
84
107
|
}
|
|
85
108
|
|
|
86
109
|
function objectToTokens<T extends Record<string, string>>(obj: T) {
|
|
87
110
|
return Object.fromEntries(
|
|
88
|
-
Object.entries(obj).map(([key, value]) => [key, { value }])
|
|
111
|
+
Object.entries(obj).map(([key, value]) => [key, { value }]),
|
|
89
112
|
);
|
|
90
113
|
}
|
|
91
114
|
|
|
@@ -93,8 +116,8 @@ function extractFontSizes(scale: Record<string, { fontSize: string }>) {
|
|
|
93
116
|
return Object.fromEntries(
|
|
94
117
|
Object.entries(scale).map(([name, style]) => [
|
|
95
118
|
name,
|
|
96
|
-
{ value: style.fontSize }
|
|
97
|
-
])
|
|
119
|
+
{ value: style.fontSize },
|
|
120
|
+
]),
|
|
98
121
|
);
|
|
99
122
|
}
|
|
100
123
|
|
|
@@ -102,29 +125,28 @@ function extractLineHeights(scale: Record<string, { lineHeight: string }>) {
|
|
|
102
125
|
return Object.fromEntries(
|
|
103
126
|
Object.entries(scale).map(([name, style]) => [
|
|
104
127
|
name,
|
|
105
|
-
{ value: style.lineHeight }
|
|
106
|
-
])
|
|
128
|
+
{ value: style.lineHeight },
|
|
129
|
+
]),
|
|
107
130
|
);
|
|
108
131
|
}
|
|
109
132
|
|
|
110
133
|
function extractFontWeights(scale: Record<string, { fontWeight: string }>) {
|
|
111
134
|
const weights = new Map<string, string>();
|
|
112
|
-
Object.values(scale).forEach(style => {
|
|
135
|
+
Object.values(scale).forEach((style) => {
|
|
113
136
|
weights.set(style.fontWeight, style.fontWeight);
|
|
114
137
|
});
|
|
115
138
|
return Object.fromEntries(
|
|
116
|
-
Array.from(weights.entries()).map(([key, value]) => [
|
|
117
|
-
key,
|
|
118
|
-
{ value }
|
|
119
|
-
])
|
|
139
|
+
Array.from(weights.entries()).map(([key, value]) => [key, { value }]),
|
|
120
140
|
);
|
|
121
141
|
}
|
|
122
142
|
|
|
123
|
-
function extractLetterSpacings(
|
|
143
|
+
function extractLetterSpacings(
|
|
144
|
+
scale: Record<string, { letterSpacing: string }>,
|
|
145
|
+
) {
|
|
124
146
|
return Object.fromEntries(
|
|
125
147
|
Object.entries(scale).map(([name, style]) => [
|
|
126
148
|
name,
|
|
127
|
-
{ value: style.letterSpacing }
|
|
128
|
-
])
|
|
149
|
+
{ value: style.letterSpacing },
|
|
150
|
+
]),
|
|
129
151
|
);
|
|
130
152
|
}
|
package/src/preset/index.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { definePreset } from '@pandacss/dev';
|
|
2
2
|
import { activeLanguage, transformToPandaTheme } from '../languages';
|
|
3
3
|
import { colors as m3Colors } from './colors';
|
|
4
|
-
import {
|
|
4
|
+
import { semanticColorTokens } from './semantic-tokens';
|
|
5
5
|
|
|
6
6
|
// Park UI recipes - Core
|
|
7
7
|
import { button as parkButton } from './recipes/button';
|
|
@@ -97,8 +97,20 @@ export const discourserPandaPreset = definePreset({
|
|
|
97
97
|
// Semantic tokens: M3 colors + Park UI aliases + shadows + radii
|
|
98
98
|
semanticTokens: {
|
|
99
99
|
colors: {
|
|
100
|
-
//
|
|
100
|
+
// Non-conflicting M3 semantic tokens land here first
|
|
101
|
+
// (onPrimary, onSecondary, surface, outline, etc.)
|
|
102
|
+
...semanticColorTokens,
|
|
103
|
+
|
|
104
|
+
// M3-to-Radix color bridges — overwrite conflicting top-level keys,
|
|
105
|
+
// then re-merge the M3 semantic DEFAULT+container back in
|
|
101
106
|
...m3Colors,
|
|
107
|
+
primary: { ...m3Colors.primary, ...semanticColorTokens.primary },
|
|
108
|
+
secondary: {
|
|
109
|
+
...m3Colors.secondary,
|
|
110
|
+
...semanticColorTokens.secondary,
|
|
111
|
+
},
|
|
112
|
+
tertiary: { ...m3Colors.tertiary, ...semanticColorTokens.tertiary },
|
|
113
|
+
error: { ...m3Colors.error, ...semanticColorTokens.error },
|
|
102
114
|
|
|
103
115
|
// Park UI-style aliases for component compatibility
|
|
104
116
|
fg: {
|
|
@@ -119,9 +131,6 @@ export const discourserPandaPreset = definePreset({
|
|
|
119
131
|
value: { base: '{colors.gray.6}', _dark: '{colors.gray.6}' },
|
|
120
132
|
},
|
|
121
133
|
|
|
122
|
-
// M3 semantic tokens (surface, onSurface, etc.)
|
|
123
|
-
...m3SemanticTokens,
|
|
124
|
-
|
|
125
134
|
// Base colors
|
|
126
135
|
white: { value: '#FFFFFF' },
|
|
127
136
|
black: { value: '#000000' },
|
|
@@ -1,79 +1,146 @@
|
|
|
1
1
|
import { defineSemanticTokens } from '@pandacss/dev';
|
|
2
2
|
import { material3Language } from '../languages/material3.language';
|
|
3
3
|
|
|
4
|
-
|
|
5
|
-
|
|
4
|
+
/**
|
|
5
|
+
* MAINTENANCE CONTRACT:
|
|
6
|
+
* Every key in material3Language.semantic MUST have a corresponding entry here.
|
|
7
|
+
* src/__tests__/token-contract.test.ts enforces this automatically.
|
|
8
|
+
* When adding a new semantic role to material3.language.ts:
|
|
9
|
+
* 1. Add the token here in semanticColorTokens
|
|
10
|
+
* 2. Run pnpm test to confirm the contract test passes
|
|
11
|
+
* 3. Update Colors.mdx to add the swatch
|
|
12
|
+
* 4. Bump the minor version
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
const s = material3Language.semantic;
|
|
16
|
+
const d = material3Language.semanticDark!;
|
|
6
17
|
|
|
7
18
|
/**
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
* These provide M3-style naming (surface, onSurface, etc.)
|
|
11
|
-
* while Park UI components use their own naming (fg, canvas, etc.)
|
|
19
|
+
* Clean semantic color tokens — no m3 prefix.
|
|
20
|
+
* These are the authoritative names going forward.
|
|
12
21
|
*/
|
|
13
|
-
export const
|
|
14
|
-
//
|
|
15
|
-
|
|
16
|
-
DEFAULT: { value: { base:
|
|
17
|
-
dim: { value: { base: semantic.surfaceContainerLow, _dark: semanticDark.surfaceContainerLow } },
|
|
18
|
-
bright: { value: { base: semantic.surfaceContainerHigh, _dark: semanticDark.surfaceContainerHigh } },
|
|
22
|
+
export const semanticColorTokens = defineSemanticTokens.colors({
|
|
23
|
+
// Primary
|
|
24
|
+
primary: {
|
|
25
|
+
DEFAULT: { value: { base: s.primary, _dark: d.primary } },
|
|
19
26
|
container: {
|
|
20
|
-
|
|
21
|
-
low: { value: { base: semantic.surfaceContainerLow, _dark: semanticDark.surfaceContainerLow } },
|
|
22
|
-
lowest: { value: { base: semantic.surfaceContainerLowest, _dark: semanticDark.surfaceContainerLowest } },
|
|
23
|
-
high: { value: { base: semantic.surfaceContainerHigh, _dark: semanticDark.surfaceContainerHigh } },
|
|
24
|
-
highest: { value: { base: semantic.surfaceContainerHighest, _dark: semanticDark.surfaceContainerHighest } },
|
|
27
|
+
value: { base: s.primaryContainer, _dark: d.primaryContainer },
|
|
25
28
|
},
|
|
26
29
|
},
|
|
27
|
-
|
|
28
|
-
DEFAULT: { value: { base:
|
|
29
|
-
|
|
30
|
+
onPrimary: {
|
|
31
|
+
DEFAULT: { value: { base: s.onPrimary, _dark: d.onPrimary } },
|
|
32
|
+
container: {
|
|
33
|
+
value: { base: s.onPrimaryContainer, _dark: d.onPrimaryContainer },
|
|
34
|
+
},
|
|
30
35
|
},
|
|
31
36
|
|
|
32
|
-
//
|
|
33
|
-
|
|
34
|
-
DEFAULT: { value: { base:
|
|
35
|
-
container: {
|
|
37
|
+
// Secondary
|
|
38
|
+
secondary: {
|
|
39
|
+
DEFAULT: { value: { base: s.secondary, _dark: d.secondary } },
|
|
40
|
+
container: {
|
|
41
|
+
value: { base: s.secondaryContainer, _dark: d.secondaryContainer },
|
|
42
|
+
},
|
|
36
43
|
},
|
|
37
|
-
|
|
38
|
-
DEFAULT: { value: { base:
|
|
39
|
-
container: {
|
|
44
|
+
onSecondary: {
|
|
45
|
+
DEFAULT: { value: { base: s.onSecondary, _dark: d.onSecondary } },
|
|
46
|
+
container: {
|
|
47
|
+
value: { base: s.onSecondaryContainer, _dark: d.onSecondaryContainer },
|
|
48
|
+
},
|
|
40
49
|
},
|
|
41
50
|
|
|
42
|
-
//
|
|
43
|
-
|
|
44
|
-
DEFAULT: { value: { base:
|
|
45
|
-
container: {
|
|
51
|
+
// Tertiary
|
|
52
|
+
tertiary: {
|
|
53
|
+
DEFAULT: { value: { base: s.tertiary, _dark: d.tertiary } },
|
|
54
|
+
container: {
|
|
55
|
+
value: { base: s.tertiaryContainer, _dark: d.tertiaryContainer },
|
|
56
|
+
},
|
|
46
57
|
},
|
|
47
|
-
|
|
48
|
-
DEFAULT: { value: { base:
|
|
49
|
-
container: {
|
|
58
|
+
onTertiary: {
|
|
59
|
+
DEFAULT: { value: { base: s.onTertiary, _dark: d.onTertiary } },
|
|
60
|
+
container: {
|
|
61
|
+
value: { base: s.onTertiaryContainer, _dark: d.onTertiaryContainer },
|
|
62
|
+
},
|
|
50
63
|
},
|
|
51
64
|
|
|
52
|
-
//
|
|
53
|
-
|
|
54
|
-
DEFAULT: { value: { base:
|
|
55
|
-
container: { value: { base:
|
|
65
|
+
// Error
|
|
66
|
+
error: {
|
|
67
|
+
DEFAULT: { value: { base: s.error, _dark: d.error } },
|
|
68
|
+
container: { value: { base: s.errorContainer, _dark: d.errorContainer } },
|
|
56
69
|
},
|
|
57
|
-
|
|
58
|
-
DEFAULT: { value: { base:
|
|
59
|
-
container: {
|
|
70
|
+
onError: {
|
|
71
|
+
DEFAULT: { value: { base: s.onError, _dark: d.onError } },
|
|
72
|
+
container: {
|
|
73
|
+
value: { base: s.onErrorContainer, _dark: d.onErrorContainer },
|
|
74
|
+
},
|
|
60
75
|
},
|
|
61
76
|
|
|
62
|
-
//
|
|
77
|
+
// Surface system
|
|
78
|
+
surface: {
|
|
79
|
+
DEFAULT: { value: { base: s.surface, _dark: d.surface } },
|
|
80
|
+
dim: {
|
|
81
|
+
value: { base: s.surfaceContainerLow, _dark: d.surfaceContainerLow },
|
|
82
|
+
},
|
|
83
|
+
bright: {
|
|
84
|
+
value: { base: s.surfaceContainerHigh, _dark: d.surfaceContainerHigh },
|
|
85
|
+
},
|
|
86
|
+
container: {
|
|
87
|
+
DEFAULT: {
|
|
88
|
+
value: { base: s.surfaceContainer, _dark: d.surfaceContainer },
|
|
89
|
+
},
|
|
90
|
+
low: {
|
|
91
|
+
value: { base: s.surfaceContainerLow, _dark: d.surfaceContainerLow },
|
|
92
|
+
},
|
|
93
|
+
lowest: {
|
|
94
|
+
value: {
|
|
95
|
+
base: s.surfaceContainerLowest,
|
|
96
|
+
_dark: d.surfaceContainerLowest,
|
|
97
|
+
},
|
|
98
|
+
},
|
|
99
|
+
high: {
|
|
100
|
+
value: { base: s.surfaceContainerHigh, _dark: d.surfaceContainerHigh },
|
|
101
|
+
},
|
|
102
|
+
highest: {
|
|
103
|
+
value: {
|
|
104
|
+
base: s.surfaceContainerHighest,
|
|
105
|
+
_dark: d.surfaceContainerHighest,
|
|
106
|
+
},
|
|
107
|
+
},
|
|
108
|
+
},
|
|
109
|
+
},
|
|
110
|
+
onSurface: {
|
|
111
|
+
DEFAULT: { value: { base: s.onSurface, _dark: d.onSurface } },
|
|
112
|
+
variant: { value: { base: s.onSurfaceVariant, _dark: d.onSurfaceVariant } },
|
|
113
|
+
},
|
|
114
|
+
surfaceVariant: {
|
|
115
|
+
value: { base: s.surfaceVariant, _dark: d.surfaceVariant },
|
|
116
|
+
},
|
|
117
|
+
|
|
118
|
+
// Background
|
|
119
|
+
background: { value: { base: s.background, _dark: d.background } },
|
|
120
|
+
onBackground: { value: { base: s.onBackground, _dark: d.onBackground } },
|
|
121
|
+
|
|
122
|
+
// Outline
|
|
63
123
|
outline: {
|
|
64
|
-
DEFAULT: { value: { base:
|
|
65
|
-
variant: { value: { base:
|
|
124
|
+
DEFAULT: { value: { base: s.outline, _dark: d.outline } },
|
|
125
|
+
variant: { value: { base: s.outlineVariant, _dark: d.outlineVariant } },
|
|
66
126
|
},
|
|
67
127
|
|
|
68
|
-
//
|
|
69
|
-
inverseSurface: {
|
|
70
|
-
|
|
71
|
-
|
|
128
|
+
// Inverse
|
|
129
|
+
inverseSurface: {
|
|
130
|
+
value: { base: s.inverseSurface, _dark: d.inverseSurface },
|
|
131
|
+
},
|
|
132
|
+
inverseOnSurface: {
|
|
133
|
+
value: { base: s.inverseOnSurface, _dark: d.inverseOnSurface },
|
|
134
|
+
},
|
|
135
|
+
inversePrimary: {
|
|
136
|
+
value: { base: s.inversePrimary, _dark: d.inversePrimary },
|
|
137
|
+
},
|
|
72
138
|
// Not standard M3 tokens, but follow inversePrimary's pattern:
|
|
73
139
|
// light mode = dark-palette value, dark mode = light-palette value.
|
|
74
|
-
inverseSecondary: { value: { base:
|
|
75
|
-
inverseTertiary: { value: { base:
|
|
140
|
+
inverseSecondary: { value: { base: d.secondary, _dark: s.secondary } },
|
|
141
|
+
inverseTertiary: { value: { base: d.tertiary, _dark: s.tertiary } },
|
|
76
142
|
|
|
77
|
-
//
|
|
78
|
-
scrim: { value: { base:
|
|
79
|
-
}
|
|
143
|
+
// Utility
|
|
144
|
+
scrim: { value: { base: s.scrim, _dark: d.scrim } },
|
|
145
|
+
shadow: { value: { base: s.shadow, _dark: d.shadow } },
|
|
146
|
+
});
|