@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.
@@ -1 +1 @@
1
- {"version":3,"file":"semantic-tokens.d.ts","sourceRoot":"","sources":["../../src/preset/semantic-tokens.ts"],"names":[],"mappings":"AAMA;;;;;GAKG;AACH,eAAO,MAAM,gBAAgB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAkE3B,CAAC"}
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@discourser/design-system",
3
- "version": "0.20.1",
3
+ "version": "0.22.0",
4
4
  "description": "Aesthetic-agnostic design system with Panda CSS and Ark UI",
5
5
  "type": "module",
6
6
  "publishConfig": {
@@ -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 { DesignLanguageContract, TonalPalette, SemanticColors } from '../contracts/design-language.contract'
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(language.colors as unknown as Record<string, TonalPalette>),
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(language.typography.scale as unknown as Record<string, { fontSize: string }>),
22
- lineHeights: extractLineHeights(language.typography.scale as unknown as Record<string, { lineHeight: string }>),
23
- fontWeights: extractFontWeights(language.typography.scale as unknown as Record<string, { fontWeight: string }>),
24
- letterSpacings: extractLetterSpacings(language.typography.scale as unknown as Record<string, { letterSpacing: string }>),
25
- spacing: objectToTokens(language.spacing as unknown as Record<string, string>),
26
- radii: objectToTokens(language.shape.radii as unknown as Record<string, string>),
27
- shadows: objectToTokens(language.elevation.levels as unknown as Record<string, string>),
28
- durations: objectToTokens(language.motion.durations as unknown as Record<string, string>),
29
- easings: objectToTokens(language.motion.easings as unknown as Record<string, string>),
30
- borderWidths: objectToTokens(language.border.widths as unknown as Record<string, string>)
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(language: DesignLanguageContract) {
35
- const light = language.semantic;
36
- const dark = language.semanticDark || light; // Fallback to light if no dark
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: Object.fromEntries(
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
- tone,
79
- { value }
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(scale: Record<string, { letterSpacing: string }>) {
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
  }
@@ -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 { m3SemanticTokens } from './semantic-tokens';
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
- // M3-to-Radix color bridges
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
- const semantic = material3Language.semantic;
5
- const semanticDark = material3Language.semanticDark!;
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
- * M3 Semantic Tokens - layered on top of Park UI
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 m3SemanticTokens = defineSemanticTokens.colors({
14
- // M3 Surface System
15
- surface: {
16
- DEFAULT: { value: { base: semantic.surface, _dark: semanticDark.surface } },
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
- DEFAULT: { value: { base: semantic.surfaceContainer, _dark: semanticDark.surfaceContainer } },
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
- onSurface: {
28
- DEFAULT: { value: { base: semantic.onSurface, _dark: semanticDark.onSurface } },
29
- variant: { value: { base: semantic.onSurfaceVariant, _dark: semanticDark.onSurfaceVariant } },
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
- // M3 Primary tokens (for explicit M3 usage)
33
- m3Primary: {
34
- DEFAULT: { value: { base: semantic.primary, _dark: semanticDark.primary } },
35
- container: { value: { base: semantic.primaryContainer, _dark: semanticDark.primaryContainer } },
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
- onM3Primary: {
38
- DEFAULT: { value: { base: semantic.onPrimary, _dark: semanticDark.onPrimary } },
39
- container: { value: { base: semantic.onPrimaryContainer, _dark: semanticDark.onPrimaryContainer } },
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
- // M3 Secondary (prefixed to avoid conflict with Park UI Radix-scale bridge)
43
- m3Secondary: {
44
- DEFAULT: { value: { base: semantic.secondary, _dark: semanticDark.secondary } },
45
- container: { value: { base: semantic.secondaryContainer, _dark: semanticDark.secondaryContainer } },
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
- onM3Secondary: {
48
- DEFAULT: { value: { base: semantic.onSecondary, _dark: semanticDark.onSecondary } },
49
- container: { value: { base: semantic.onSecondaryContainer, _dark: semanticDark.onSecondaryContainer } },
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
- // M3 Tertiary (prefixed to avoid conflict with Park UI Radix-scale bridge)
53
- m3Tertiary: {
54
- DEFAULT: { value: { base: semantic.tertiary, _dark: semanticDark.tertiary } },
55
- container: { value: { base: semantic.tertiaryContainer, _dark: semanticDark.tertiaryContainer } },
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
- onM3Tertiary: {
58
- DEFAULT: { value: { base: semantic.onTertiary, _dark: semanticDark.onTertiary } },
59
- container: { value: { base: semantic.onTertiaryContainer, _dark: semanticDark.onTertiaryContainer } },
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
- // M3 Outline
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: semantic.outline, _dark: semanticDark.outline } },
65
- variant: { value: { base: semantic.outlineVariant, _dark: semanticDark.outlineVariant } },
124
+ DEFAULT: { value: { base: s.outline, _dark: d.outline } },
125
+ variant: { value: { base: s.outlineVariant, _dark: d.outlineVariant } },
66
126
  },
67
127
 
68
- // M3 Inverse
69
- inverseSurface: { value: { base: semantic.inverseSurface, _dark: semanticDark.inverseSurface } },
70
- inverseOnSurface: { value: { base: semantic.inverseOnSurface, _dark: semanticDark.inverseOnSurface } },
71
- inversePrimary: { value: { base: semantic.inversePrimary, _dark: semanticDark.inversePrimary } },
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: semanticDark.secondary, _dark: semantic.secondary } },
75
- inverseTertiary: { value: { base: semanticDark.tertiary, _dark: semantic.tertiary } },
140
+ inverseSecondary: { value: { base: d.secondary, _dark: s.secondary } },
141
+ inverseTertiary: { value: { base: d.tertiary, _dark: s.tertiary } },
76
142
 
77
- // Scrim/Shadow
78
- scrim: { value: { base: semantic.scrim, _dark: semanticDark.scrim } },
79
- });
143
+ // Utility
144
+ scrim: { value: { base: s.scrim, _dark: d.scrim } },
145
+ shadow: { value: { base: s.shadow, _dark: d.shadow } },
146
+ });