Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion src/app.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,12 @@
]);
});

const rootNodes = $derived(treeState.getChildren(undefined));
const rootNodes = $derived(
treeState
.getChildren(undefined)
// @todo temporary render only token-set
.filter((item) => item.meta.nodeType === "token-set"),
);

// svelte-ignore state_referenced_locally
let selectedItems = new SvelteSet<string>(
Expand Down
157 changes: 157 additions & 0 deletions src/css-variables.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { test, expect, describe } from "vitest";
import { generateCssVariables, parseCssVariables } from "./css-variables";
import { parseDesignTokens } from "./tokens";
import { parseTokenResolver } from "./resolver";
import type { TreeNode } from "./store";
import type { TreeNodeMeta } from "./state.svelte";

Expand Down Expand Up @@ -1112,3 +1113,159 @@ describe("parseCssVariables", () => {
});
});
});

describe("generateCssVariables with modifiers and contexts", () => {
test("skips modifier nodes and their entire subtrees", () => {
const result = parseTokenResolver({
version: "2025.10",
resolutionOrder: [
{
type: "set",
name: "base",
sources: [
{
baseColor: {
$type: "color",
$value: { colorSpace: "srgb", components: [1, 0, 0] },
},
},
],
},
{
type: "modifier",
name: "theme",
description: "Color theme",
contexts: {
light: [
{
primary: {
$type: "color",
$value: { colorSpace: "srgb", components: [0, 0, 1] },
},
},
],
},
},
],
});

expect(result.errors).toHaveLength(0);
const css = generateCssVariables(nodesToMap(result.nodes));

// Should contain token from set
expect(css).toContain("--base-color: rgb(100% 0% 0%);");

// Should NOT contain token from modifier's context (entire subtree skipped)
expect(css).not.toContain("--primary:");
expect(css).not.toContain("theme");
expect(css).not.toContain("light");
});

test("skips tokens in all modifier contexts", () => {
const result = parseTokenResolver({
version: "2025.10",
resolutionOrder: [
{
type: "modifier",
name: "theme",
contexts: {
light: [
{
background: {
$type: "color",
$value: { colorSpace: "srgb", components: [1, 1, 1] },
},
},
],
dark: [
{
background: {
$type: "color",
$value: { colorSpace: "srgb", components: [0, 0, 0] },
},
},
],
},
},
],
});

expect(result.errors).toHaveLength(0);
const css = generateCssVariables(nodesToMap(result.nodes));

// Should NOT contain background token from any context
expect(css).toContain(":root {\n}");
});

test("skips nested groups and tokens under modifier contexts", () => {
const result = parseTokenResolver({
version: "2025.10",
resolutionOrder: [
{
type: "modifier",
name: "contrast",
contexts: {
high: [
{
colors: {
$type: "color",
text: {
$value: { colorSpace: "srgb", components: [0, 0, 0] },
},
},
},
],
},
},
],
});

expect(result.errors).toHaveLength(0);
const css = generateCssVariables(nodesToMap(result.nodes));

// Should NOT contain any token from modifier context (entire subtree skipped)
expect(css).toContain(":root {\n}");
});

test("skips tokens from multiple modifiers", () => {
const result = parseTokenResolver({
version: "2025.10",
resolutionOrder: [
{
type: "modifier",
name: "theme",
contexts: {
light: [
{
background: {
$type: "color",
$value: { colorSpace: "srgb", components: [1, 1, 1] },
},
},
],
},
},
{
type: "modifier",
name: "contrast",
contexts: {
high: [
{
text: {
$type: "color",
$value: { colorSpace: "srgb", components: [0, 0, 0] },
},
},
],
},
},
],
});

expect(result.errors).toHaveLength(0);
const css = generateCssVariables(nodesToMap(result.nodes));

// Should NOT contain tokens from any modifier
expect(css).toContain(":root {\n}");
});
});
10 changes: 9 additions & 1 deletion src/css-variables.ts
Original file line number Diff line number Diff line change
Expand Up @@ -184,8 +184,16 @@ const processNode = (
lines: string[],
nodes: Map<string, TreeNode<TreeNodeMeta>>,
) => {
// token-modifier and token-context nodes and their entire subtrees should be skipped
if (
node.meta.nodeType === "token-modifier" ||
node.meta.nodeType === "token-context"
) {
return;
}

// token-set is intended for grouping globals
// and should be omitted in generated variables
// and should be omitted in generated variables, but its children are processed
if (node.meta.nodeType === "token-set") {
const children = childrenByParent.get(node.nodeId) ?? [];
for (const child of children) {
Expand Down
6 changes: 6 additions & 0 deletions src/export-dialog.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,12 @@
// remove set node from data and serialize as DTCG format module
const setIds = new Set<undefined | string>();
for (const node of nodes.values()) {
if (
node.meta.nodeType === "token-modifier" ||
node.meta.nodeType === "token-context"
) {
Comment thread
coderabbitai[bot] marked this conversation as resolved.
continue;
}
if (node.meta.nodeType === "token-set") {
setIds.add(node.nodeId);
} else {
Expand Down
Loading