Skip to content

Commit 46e7d1d

Browse files
Fix: panda-preset-color-radix semantic token generation (#17)
* Fix semantic token generation. - Fix semantic token generation in panda-preset-color-radix and add test for coverage. - Fix test scripts in package.json to stop double test output. * Update README.md examples to remove empty semanticTokens.
1 parent 3033156 commit 46e7d1d

File tree

17 files changed

+84
-69
lines changed

17 files changed

+84
-69
lines changed

.changeset/polite-cups-love.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
---
2-
"@amandaguthrie/panda-preset-color-radix": patch
2+
"@amandaguthrie/panda-preset-color-radix": minor
33
---
44
<br />
55

6+
- Refactor logic for semantic token map generation to exclude the `semanticTokens` key if no map is provided or if all mapped color names are invalid. Fixes #16
67
- Move shared `entries` and `fromEntries` utilities from `@puffin-ui/shared`
78
to `@amandaguthrie/panda-preset-shared-utils`
89
- Move test library from `@puffin-ui/shared` to `@amandaguthrie/panda-preset-dev-utils`

packages/panda-plugin-type-extend/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@
3737
"build": "tsup --entry src/index.ts --entry src/index.ts --format=esm,cjs --dts",
3838
"build-fast": "tsup --entry src/index.ts --entry src/index.ts --format=esm,cjs --no-dts",
3939
"dev": "pnpm build-fast --watch",
40-
"test": "node --import tsx --test test/test.mts"
40+
"test": "node --import tsx test/test.mts"
4141
},
4242
"devDependencies": {
4343
"@amandaguthrie/panda-preset-dev-utils": "workspace:*",

packages/panda-preset-breakpoints/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@
3737
"build": "tsup --entry src/index.ts --entry src/index.ts --format=esm,cjs --dts",
3838
"build-fast": "tsup --entry src/index.ts --entry src/index.ts --format=esm,cjs --no-dts",
3939
"dev": "pnpm build-fast --watch",
40-
"test": "node --import tsx --test test/test.mts"
40+
"test": "node --import tsx test/test.mts"
4141
},
4242
"dependencies": {
4343
"@amandaguthrie/panda-preset-shared-utils": "workspace:*"

packages/panda-preset-color-radix/README.md

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -187,7 +187,7 @@ const coreTokenStructure = {
187187
}
188188
}
189189
}
190-
}, semanticTokens: {}
190+
}
191191
}
192192
}
193193
}
@@ -353,8 +353,7 @@ const allColors = {
353353
}
354354
}
355355
}
356-
},
357-
semanticTokens: {}
356+
}
358357
}
359358
}
360359
}
@@ -414,8 +413,7 @@ const someColors = {
414413
}
415414
}
416415
}
417-
},
418-
semanticTokens: {}
416+
}
419417
}
420418
}
421419
}

packages/panda-preset-color-radix/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@
3737
"build": "tsup --entry src/index.ts --entry src/index.ts --format=esm,cjs --dts",
3838
"build-fast": "tsup --entry src/index.ts --entry src/index.ts --format=esm,cjs --no-dts",
3939
"dev": "pnpm build-fast --watch",
40-
"test": "node --import tsx --test test/test.mts"
40+
"test": "node --import tsx test/test.mts"
4141
},
4242
"dependencies": {
4343
"@amandaguthrie/panda-preset-shared-utils": "workspace:*",

packages/panda-preset-color-radix/src/preset.ts

Lines changed: 48 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { definePreset } from '@pandacss/dev';
1+
import { definePreset, type Preset } from '@pandacss/dev';
22
import type { Condition, RecursiveToken } from '@pandacss/types';
33
import {
44
type ColorKeyRadix,
@@ -20,7 +20,7 @@ const defaultOptions: ColorRadixPresetDefaults = {
2020
};
2121

2222
export function pandaPresetColorRadix(options?: ColorRadixPresetOptions) {
23-
const mergedOptions = Object.assign({}, defaultOptions, options);
23+
const mergedOptions = options != undefined ? Object.assign({}, defaultOptions, options) : defaultOptions;
2424
const { colors, colorModeConditions, coreColorPrefix, semanticColorMap, semanticColorPrefix } = mergedOptions;
2525

2626
// If an array of colors is passed, filter the array to valid Radix color names. If the array has no valid color names, return all Radix colors.
@@ -53,18 +53,20 @@ export function pandaPresetColorRadix(options?: ColorRadixPresetOptions) {
5353
defaultColorMode: colorModeConditions.default,
5454
}) as RecursiveToken<string, any>;
5555

56-
return definePreset({
56+
const preset: Preset = {
5757
theme: {
5858
extend: {
59-
tokens: {
60-
colors: coreTokens,
61-
},
62-
semanticTokens: {
63-
colors: semanticTokens,
64-
},
59+
tokens: { colors: coreTokens },
6560
},
6661
},
67-
});
62+
};
63+
64+
if (semanticTokens != undefined) {
65+
// @ts-ignore This is undefined but we can set it.
66+
preset.theme.extend.semanticTokens = { colors: semanticTokens };
67+
}
68+
69+
return definePreset(preset);
6870
}
6971

7072
/** @desc Generate Radix core color tokens from a list of Radix colors. */
@@ -137,35 +139,40 @@ function generateRadixSemanticTokens({
137139
return newValue;
138140
}
139141

140-
const semanticTokens = fromEntries(
141-
entries(semanticColorMap).map(([tokenName, mapDetail]) => {
142-
const colorName = mapDetail.color;
143-
144-
const colorValue: RecursiveToken<string, any> = { '1': {} };
145-
146-
const thisDefault = mapDetail.default ?? fallbackDefault;
147-
148-
for (let scale = 1; scale <= 12; scale++) {
149-
const scaleKey = scale.toString();
150-
const base = {
151-
base: `{colors.${corePrefixToken}${colorName}.${scaleKey}.${thisDefault}}`,
152-
};
153-
const lightConditions = forEachCondition(
154-
base,
155-
conditions.light,
156-
`{colors.${corePrefixToken}${colorName}.${scaleKey}.light}`,
157-
);
158-
const allConditions = forEachCondition(
159-
lightConditions,
160-
conditions.dark,
161-
`{colors.${corePrefixToken}${colorName}.${scaleKey}.dark}`,
162-
);
163-
colorValue[scaleKey] = { value: allConditions };
164-
}
165-
166-
return [tokenName, colorValue];
167-
}),
168-
);
169-
170-
return semanticPrefix ? { [semanticPrefix]: semanticTokens } : semanticTokens;
142+
// If the map has no keys, set to undefined. Otherwise, map to semantic token format.
143+
const semanticTokens =
144+
Object.keys(semanticColorMap).length > 0
145+
? fromEntries(
146+
entries(semanticColorMap).map(([tokenName, mapDetail]) => {
147+
const colorName = mapDetail.color;
148+
149+
const colorValue: RecursiveToken<string, any> = { '1': {} };
150+
151+
const thisDefault = mapDetail.default ?? fallbackDefault;
152+
153+
for (let scale = 1; scale <= 12; scale++) {
154+
const scaleKey = scale.toString();
155+
const base = {
156+
base: `{colors.${corePrefixToken}${colorName}.${scaleKey}.${thisDefault}}`,
157+
};
158+
const lightConditions = forEachCondition(
159+
base,
160+
conditions.light,
161+
`{colors.${corePrefixToken}${colorName}.${scaleKey}.light}`,
162+
);
163+
const allConditions = forEachCondition(
164+
lightConditions,
165+
conditions.dark,
166+
`{colors.${corePrefixToken}${colorName}.${scaleKey}.dark}`,
167+
);
168+
colorValue[scaleKey] = { value: allConditions };
169+
}
170+
171+
return [tokenName, colorValue];
172+
}),
173+
)
174+
: undefined;
175+
176+
// If there are semantic tokens, check if there's a prefix set and wrap them. If there's no prefix, return the semantic tokens. Otherwise, return undefined.
177+
return semanticTokens ? (semanticPrefix ? { [semanticPrefix]: semanticTokens } : semanticTokens) : undefined;
171178
}

packages/panda-preset-color-radix/test/semantic-tokens.test.ts

Lines changed: 18 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,18 @@ import type { ColorRadixPresetOptions } from '../src';
55
import pandaPresetColorRadix from '../src';
66
import { GENERATE_SNAPSHOTS } from './test-constants';
77

8-
describe('Semantic Token Configuration & Generation', async () => {
9-
await it('should not generate any semantic tokens with default configuration', async () => {
8+
describe('Semantic Token Configuration & Generation', () => {
9+
it('should not generate any semantic tokens with default configuration', async () => {
1010
assert.equal(toJson(pandaPresetColorRadix()), await readJsonSnapshot('default'));
1111
});
12-
await it('should generate semantic tokens when provided with a semantic color map', async () => {
12+
it('should not generate any semantic tokens when semanticColorMap is undefined', async () => {
13+
const config: ColorRadixPresetOptions = {};
14+
if (GENERATE_SNAPSHOTS) {
15+
await writeJsonSnapshot('semantic-map-undefined', toJson(pandaPresetColorRadix(config)));
16+
}
17+
assert.equal(toJson(pandaPresetColorRadix(config)), await readJsonSnapshot('semantic-map-undefined'));
18+
});
19+
it('should generate semantic tokens when provided with a semantic color map', async () => {
1320
const config: ColorRadixPresetOptions = {
1421
semanticColorMap: {
1522
primary: { color: 'grass' },
@@ -20,7 +27,7 @@ describe('Semantic Token Configuration & Generation', async () => {
2027
}
2128
assert.equal(toJson(pandaPresetColorRadix(config)), await readJsonSnapshot('default-color-map'));
2229
});
23-
await it('should use light conditions when provided', async () => {
30+
it('should use light conditions when provided', async () => {
2431
const config: ColorRadixPresetOptions = {
2532
colorModeConditions: {
2633
light: ['_osLight'],
@@ -39,7 +46,7 @@ describe('Semantic Token Configuration & Generation', async () => {
3946

4047
assert.equal(toJson(pandaPresetColorRadix(config)), await readJsonSnapshot('light-conditions-custom'));
4148
});
42-
await it('should use dark conditions when provided', async () => {
49+
it('should use dark conditions when provided', async () => {
4350
const config: ColorRadixPresetOptions = {
4451
colorModeConditions: {
4552
dark: ['_osDark'],
@@ -59,7 +66,7 @@ describe('Semantic Token Configuration & Generation', async () => {
5966
assert.equal(toJson(pandaPresetColorRadix(config)), await readJsonSnapshot('dark-conditions-custom'));
6067
});
6168

62-
await it('should add missing core tokens', async () => {
69+
it('should add missing core tokens', async () => {
6370
const config: ColorRadixPresetOptions = {
6471
colors: ['cyan'],
6572
semanticColorMap: {
@@ -75,7 +82,7 @@ describe('Semantic Token Configuration & Generation', async () => {
7582
assert.equal(toJson(pandaPresetColorRadix(config)), await readJsonSnapshot('colors-array-add-semantic'));
7683
});
7784

78-
await it('should ignore color tokens that are not Radix color names', async () => {
85+
it('should ignore color tokens that are not Radix color names', async () => {
7986
const config: ColorRadixPresetOptions = {
8087
semanticColorMap: {
8188
// @ts-expect-error testing invalid token
@@ -87,10 +94,10 @@ describe('Semantic Token Configuration & Generation', async () => {
8794
await writeJsonSnapshot('color-map-ignore-invalid', toJson(pandaPresetColorRadix(config)));
8895
}
8996

90-
assert.match(toJson(pandaPresetColorRadix(config)), /"semanticTokens":{}/g);
97+
assert.doesNotMatch(toJson(pandaPresetColorRadix(config)), /"semanticTokens":{}/g);
9198
assert.equal(toJson(pandaPresetColorRadix(config)), await readJsonSnapshot('color-map-ignore-invalid'));
9299
});
93-
await it('should use a semantic color prefix when provided', async () => {
100+
it('should use a semantic color prefix when provided', async () => {
94101
const config: ColorRadixPresetOptions = {
95102
colors: ['grass'],
96103
semanticColorPrefix: 'brand',
@@ -105,7 +112,7 @@ describe('Semantic Token Configuration & Generation', async () => {
105112
assert.match(toJson(pandaPresetColorRadix(config)), /"brand":/g);
106113
assert.equal(toJson(pandaPresetColorRadix(config)), await readJsonSnapshot('semantic-prefix-custom'));
107114
});
108-
await it('should allow "" as a semantic color prefix to remove the prefix', async () => {
115+
it('should allow "" as a semantic color prefix to remove the prefix', async () => {
109116
const config: ColorRadixPresetOptions = {
110117
colors: ['grass'],
111118
semanticColorPrefix: '',
@@ -123,7 +130,7 @@ describe('Semantic Token Configuration & Generation', async () => {
123130
);
124131
assert.equal(toJson(pandaPresetColorRadix(config)), await readJsonSnapshot('semantic-prefix-blank-custom'));
125132
});
126-
await it('should use core color prefix in semantic color values', async () => {
133+
it('should use core color prefix in semantic color values', async () => {
127134
const config: ColorRadixPresetOptions = {
128135
colors: ['grass'],
129136
coreColorPrefix: 'core',

packages/panda-preset-color-radix/test/snapshots/color-map-ignore-invalid.json

Lines changed: 1 addition & 1 deletion
Large diffs are not rendered by default.
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
{"theme":{"extend":{"tokens":{"colors":{"radix":{"cyan":{"1":{"DEFAULT":{"value":"#0b161a"},"light":{"value":"#fafdfe"},"dark":{"value":"#0b161a"}},"2":{"DEFAULT":{"value":"#101b20"},"light":{"value":"#f2fafb"},"dark":{"value":"#101b20"}},"3":{"DEFAULT":{"value":"#082c36"},"light":{"value":"#def7f9"},"dark":{"value":"#082c36"}},"4":{"DEFAULT":{"value":"#003848"},"light":{"value":"#caf1f6"},"dark":{"value":"#003848"}},"5":{"DEFAULT":{"value":"#004558"},"light":{"value":"#b5e9f0"},"dark":{"value":"#004558"}},"6":{"DEFAULT":{"value":"#045468"},"light":{"value":"#9ddde7"},"dark":{"value":"#045468"}},"7":{"DEFAULT":{"value":"#12677e"},"light":{"value":"#7dcedc"},"dark":{"value":"#12677e"}},"8":{"DEFAULT":{"value":"#11809c"},"light":{"value":"#3db9cf"},"dark":{"value":"#11809c"}},"9":{"DEFAULT":{"value":"#00a2c7"},"light":{"value":"#00a2c7"},"dark":{"value":"#00a2c7"}},"10":{"DEFAULT":{"value":"#23afd0"},"light":{"value":"#0797b9"},"dark":{"value":"#23afd0"}},"11":{"DEFAULT":{"value":"#4ccce6"},"light":{"value":"#107d98"},"dark":{"value":"#4ccce6"}},"12":{"DEFAULT":{"value":"#b6ecf7"},"light":{"value":"#0d3c48"},"dark":{"value":"#b6ecf7"}}}}}},"semanticTokens":{}}}}
1+
{"theme":{"extend":{"tokens":{"colors":{"radix":{"cyan":{"1":{"DEFAULT":{"value":"#0b161a"},"light":{"value":"#fafdfe"},"dark":{"value":"#0b161a"}},"2":{"DEFAULT":{"value":"#101b20"},"light":{"value":"#f2fafb"},"dark":{"value":"#101b20"}},"3":{"DEFAULT":{"value":"#082c36"},"light":{"value":"#def7f9"},"dark":{"value":"#082c36"}},"4":{"DEFAULT":{"value":"#003848"},"light":{"value":"#caf1f6"},"dark":{"value":"#003848"}},"5":{"DEFAULT":{"value":"#004558"},"light":{"value":"#b5e9f0"},"dark":{"value":"#004558"}},"6":{"DEFAULT":{"value":"#045468"},"light":{"value":"#9ddde7"},"dark":{"value":"#045468"}},"7":{"DEFAULT":{"value":"#12677e"},"light":{"value":"#7dcedc"},"dark":{"value":"#12677e"}},"8":{"DEFAULT":{"value":"#11809c"},"light":{"value":"#3db9cf"},"dark":{"value":"#11809c"}},"9":{"DEFAULT":{"value":"#00a2c7"},"light":{"value":"#00a2c7"},"dark":{"value":"#00a2c7"}},"10":{"DEFAULT":{"value":"#23afd0"},"light":{"value":"#0797b9"},"dark":{"value":"#23afd0"}},"11":{"DEFAULT":{"value":"#4ccce6"},"light":{"value":"#107d98"},"dark":{"value":"#4ccce6"}},"12":{"DEFAULT":{"value":"#b6ecf7"},"light":{"value":"#0d3c48"},"dark":{"value":"#b6ecf7"}}}}}}}}}
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
{"theme":{"extend":{"tokens":{"colors":{"grass":{"1":{"DEFAULT":{"value":"#0e1511"},"light":{"value":"#fbfefb"},"dark":{"value":"#0e1511"}},"2":{"DEFAULT":{"value":"#141a15"},"light":{"value":"#f5fbf5"},"dark":{"value":"#141a15"}},"3":{"DEFAULT":{"value":"#1b2a1e"},"light":{"value":"#e9f6e9"},"dark":{"value":"#1b2a1e"}},"4":{"DEFAULT":{"value":"#1d3a24"},"light":{"value":"#daf1db"},"dark":{"value":"#1d3a24"}},"5":{"DEFAULT":{"value":"#25482d"},"light":{"value":"#c9e8ca"},"dark":{"value":"#25482d"}},"6":{"DEFAULT":{"value":"#2d5736"},"light":{"value":"#b2ddb5"},"dark":{"value":"#2d5736"}},"7":{"DEFAULT":{"value":"#366740"},"light":{"value":"#94ce9a"},"dark":{"value":"#366740"}},"8":{"DEFAULT":{"value":"#3e7949"},"light":{"value":"#65ba74"},"dark":{"value":"#3e7949"}},"9":{"DEFAULT":{"value":"#46a758"},"light":{"value":"#46a758"},"dark":{"value":"#46a758"}},"10":{"DEFAULT":{"value":"#53b365"},"light":{"value":"#3e9b4f"},"dark":{"value":"#53b365"}},"11":{"DEFAULT":{"value":"#71d083"},"light":{"value":"#2a7e3b"},"dark":{"value":"#71d083"}},"12":{"DEFAULT":{"value":"#c2f0c2"},"light":{"value":"#203c25"},"dark":{"value":"#c2f0c2"}}}}},"semanticTokens":{}}}}
1+
{"theme":{"extend":{"tokens":{"colors":{"grass":{"1":{"DEFAULT":{"value":"#0e1511"},"light":{"value":"#fbfefb"},"dark":{"value":"#0e1511"}},"2":{"DEFAULT":{"value":"#141a15"},"light":{"value":"#f5fbf5"},"dark":{"value":"#141a15"}},"3":{"DEFAULT":{"value":"#1b2a1e"},"light":{"value":"#e9f6e9"},"dark":{"value":"#1b2a1e"}},"4":{"DEFAULT":{"value":"#1d3a24"},"light":{"value":"#daf1db"},"dark":{"value":"#1d3a24"}},"5":{"DEFAULT":{"value":"#25482d"},"light":{"value":"#c9e8ca"},"dark":{"value":"#25482d"}},"6":{"DEFAULT":{"value":"#2d5736"},"light":{"value":"#b2ddb5"},"dark":{"value":"#2d5736"}},"7":{"DEFAULT":{"value":"#366740"},"light":{"value":"#94ce9a"},"dark":{"value":"#366740"}},"8":{"DEFAULT":{"value":"#3e7949"},"light":{"value":"#65ba74"},"dark":{"value":"#3e7949"}},"9":{"DEFAULT":{"value":"#46a758"},"light":{"value":"#46a758"},"dark":{"value":"#46a758"}},"10":{"DEFAULT":{"value":"#53b365"},"light":{"value":"#3e9b4f"},"dark":{"value":"#53b365"}},"11":{"DEFAULT":{"value":"#71d083"},"light":{"value":"#2a7e3b"},"dark":{"value":"#71d083"}},"12":{"DEFAULT":{"value":"#c2f0c2"},"light":{"value":"#203c25"},"dark":{"value":"#c2f0c2"}}}}}}}}

0 commit comments

Comments
 (0)