Skip to content
This repository was archived by the owner on Dec 23, 2025. It is now read-only.
Closed
Show file tree
Hide file tree
Changes from 5 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
8 changes: 4 additions & 4 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

74 changes: 55 additions & 19 deletions plugin-src/code.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ figma.showUI(__html__, { themeColors: true, height: 300 });
// alias variables correctly.
const allImportedVariables: Record<string, Variable> = {};

const DEFAULT_COLOR_MODE = "light";
const LEGACY_DEFAULT_MODE = "light";
const DEFAULT_MODE = "default";

function isAliasValue(
value: ParsedTokenValue[keyof ParsedTokenValue]
Expand All @@ -22,6 +23,26 @@ function isValidColorValue(value: any): value is ParsedTokenValue {
);
}

function getResolvedType(value: any): VariableResolvedDataType | undefined {
if (isValidColorValue(value)) {
return "COLOR";
} else if (typeof value === "number") {
return "FLOAT";
}
}

function groupByCollection(tokens: ParsedTokens): Record<string, ParsedTokens> {
return Object.entries(tokens).reduce<Record<string, ParsedTokens>>(
(result, [tokenName, tokenData]) => {
const collection = tokenName.split("/")[0];
result[collection] = result[collection] || {};
result[collection][tokenName] = tokenData;
return result;
},
{}
);
}

async function updateCollection(args: {
tokens: ParsedTokens;
collectionName: string;
Expand All @@ -48,6 +69,10 @@ async function updateCollection(args: {

// Get existing modes in the collection
for (const mode of collection.modes) {
if (mode.name === LEGACY_DEFAULT_MODE) {
collection.renameMode(mode.modeId, DEFAULT_MODE);
}

modesInCollectionBeforeImporting[mode.name] = mode.modeId;
}

Expand All @@ -64,9 +89,19 @@ async function updateCollection(args: {

let variable = variablesInCollectionBeforeImporting[tokenName];

// Don't save variables where we can't determine the resolved type
const resolvedType = getResolvedType(value["."]);
if (!resolvedType) {
continue;
}

if (!variable) {
// Create new variable
variable = figma.variables.createVariable(tokenName, collection, "COLOR");
variable = figma.variables.createVariable(
tokenName,
collection,
resolvedType
);
}

if (description) {
Expand All @@ -77,18 +112,22 @@ async function updateCollection(args: {
variable.hiddenFromPublishing = /primitive/.test(tokenName);

// Update scopes
if (/color\/semantic\/foreground/gi.test(tokenName)) {
if (/color\/foreground/gi.test(tokenName)) {
variable.scopes = ["TEXT_FILL", "SHAPE_FILL", "STROKE_COLOR"];
} else if (/color\/semantic\/stroke/gi.test(tokenName)) {
} else if (/color\/stroke/gi.test(tokenName)) {
variable.scopes = ["STROKE_COLOR", "EFFECT_COLOR"];
} else if (/color\/semantic\/background/gi.test(tokenName)) {
} else if (/color\/background/gi.test(tokenName)) {
variable.scopes = ["FRAME_FILL", "SHAPE_FILL"];
} else if (/dimension\/(padding|gap)/gi.test(tokenName)) {
variable.scopes = ["GAP"];
} else if (/dimension/gi.test(tokenName)) {
variable.scopes = ["WIDTH_HEIGHT"];
} else {
variable.scopes = [];
}

for (const [modeName, modeValue] of Object.entries(value)) {
const computedModeName = modeName === "." ? DEFAULT_COLOR_MODE : modeName;
const computedModeName = modeName === "." ? DEFAULT_MODE : modeName;

if (!(computedModeName in modesInCollectionBeforeImporting)) {
modesInCollectionBeforeImporting[computedModeName] =
Expand All @@ -101,10 +140,6 @@ async function updateCollection(args: {
continue;
}

if (!isValidColorValue(modeValue)) {
continue;
}

variable.setValueForMode(
modesInCollectionBeforeImporting[computedModeName],
modeValue
Expand All @@ -128,7 +163,7 @@ async function updateCollection(args: {
}

for (const [modeName, modeValue] of Object.entries(value)) {
const computedModeName = modeName === "." ? DEFAULT_COLOR_MODE : modeName;
const computedModeName = modeName === "." ? DEFAULT_MODE : modeName;

if (!(computedModeName in modesInCollectionBeforeImporting)) {
console.log(
Expand Down Expand Up @@ -174,7 +209,7 @@ async function updateCollection(args: {
const modesMissingValues = new Set(collection.modes.map((m) => m.modeId));

for (const [modeName] of Object.entries(value)) {
const computedModeName = modeName === "." ? DEFAULT_COLOR_MODE : modeName;
const computedModeName = modeName === "." ? DEFAULT_MODE : modeName;

if (!(computedModeName in modesInCollectionBeforeImporting)) {
console.log(
Expand All @@ -191,9 +226,7 @@ async function updateCollection(args: {
for (const modeId of modesMissingValues) {
variable.setValueForMode(
modeId,
variable.valuesByMode[
modesInCollectionBeforeImporting[DEFAULT_COLOR_MODE]
]
variable.valuesByMode[modesInCollectionBeforeImporting[DEFAULT_MODE]]
);
}
}
Expand All @@ -220,11 +253,14 @@ async function updateCollection(args: {
figma.ui.onmessage = async (msg) => {
if (msg.type === "import-tokens") {
const parsedTokens: ParsedTokens = msg.parsedTokens;
const groupedTokens = groupByCollection(parsedTokens);

await updateCollection({
tokens: parsedTokens,
collectionName: "WPDS Tokens",
});
for (const [collectionName, tokens] of Object.entries(groupedTokens)) {
await updateCollection({
tokens: tokens,
collectionName: `WPDS ${collectionName}`,
});
}
}

figma.closePlugin();
Expand Down
6 changes: 3 additions & 3 deletions types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,10 @@ export interface RGBA {
readonly a: number;
}

type ColorModes = "light" | "dark" | ".";
type TokenMode = ".";

export type ImportedTokenValue = {
[key in ColorModes]?: string;
[key in TokenMode]?: string;
};

export interface ImportedTokens {
Expand All @@ -25,7 +25,7 @@ export interface ImportedTokens {
}

export type ParsedTokenValue = {
[key in ColorModes]?: RGB | RGBA | string;
[key in TokenMode]?: RGB | RGBA | string | number;
};
export interface ParsedTokens {
[key: string]: {
Expand Down
11 changes: 9 additions & 2 deletions ui-src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ function App() {
const parsedTokens: ParsedTokens = {};

for (const [tokenName, tokenObject] of Object.entries(tokens)) {
// For now, only import colors.
if (!/color/gi.test(tokenName)) {
// Limit to supported token types
if (!/^(color|dimension)/gi.test(tokenName)) {
continue;
}

Expand Down Expand Up @@ -54,6 +54,13 @@ function App() {
b: Math.max(Math.min(converted.b, 1), 0),
a: converted.alpha ?? 1,
};
} else if (/dimension/gi.test(tokenName)) {
if (!/px$/.test(modeValue)) {
console.warn(`Invalid dimension value: ${modeValue}`);
continue;
}

computedModeValue = Number(modeValue.replace("px", ""));
}

if (!computedModeValue) {
Expand Down