import type { PluginMessageEvent, PluginUIEvent } from './model.js'; import { TokenType, TokenProperty, TokenValueString, } from '@penpot/plugin-types'; penpot.ui.open('Design Tokens test', `?theme=${penpot.theme}`, { width: 1000, height: 800, }); penpot.on('themechange', (theme) => { sendMessage({ type: 'theme', content: theme }); }); penpot.ui.onMessage(async (message) => { if (message.type === 'load-library') { loadLibrary(); } else if (message.type === 'load-tokens') { loadTokens(message.setId); } else if (message.type === 'add-theme') { addTheme(message.themeGroup, message.themeName); } else if (message.type === 'add-set') { addSet(message.setName); } else if (message.type === 'add-token') { addToken( message.setId, message.tokenType, message.tokenName, message.tokenValue, ); } else if (message.type === 'rename-theme') { renameTheme(message.themeId, message.newName); } else if (message.type === 'rename-set') { renameSet(message.setId, message.newName); } else if (message.type === 'rename-token') { renameToken(message.setId, message.tokenId, message.newName); } else if (message.type === 'delete-theme') { deleteTheme(message.themeId); } else if (message.type === 'delete-set') { deleteSet(message.setId); } else if (message.type === 'delete-token') { deleteToken(message.setId, message.tokenId); } else if (message.type === 'toggle-theme') { toggleTheme(message.themeId); } else if (message.type === 'toggle-set') { toggleSet(message.setId); } else if (message.type === 'apply-token') { applyToken(message.setId, message.tokenId, message.properties); } }); function sendMessage(message: PluginMessageEvent) { penpot.ui.sendMessage(message); } function loadLibrary() { const tokensCatalog = penpot.library.local.tokens; const themes = tokensCatalog.themes; const themesData = themes.map((theme) => { const activeSets = theme.activeSets.map((set) => set.name).join(', '); return { id: theme.id, group: theme.group, name: theme.name, active: theme.active, activeSets: activeSets, }; }); penpot.ui.sendMessage({ source: 'penpot', type: 'set-themes', themesData, }); const sets = tokensCatalog.sets; const setsData = sets.map((set) => { return { id: set.id, name: set.name, active: set.active, }; }); penpot.ui.sendMessage({ source: 'penpot', type: 'set-sets', setsData, }); } function loadTokens(setId: string) { const tokensCatalog = penpot.library.local.tokens; const set = tokensCatalog?.getSetById(setId); const tokensByType = set?.tokensByType; const tokenGroupsData = []; if (tokensByType) { for (const group of tokensByType) { const type = group[0]; const tokens = group[1]; tokenGroupsData.push([ type, tokens.map((token) => { return { id: token.id, name: token.name, description: token.description, valueString: JSON.stringify(token.value), resolvedValueString: token.resolvedValueString, }; }), ]); } penpot.ui.sendMessage({ source: 'penpot', type: 'set-tokens', tokenGroupsData, }); } } function addTheme(themeGroup: string, themeName: string) { const tokensCatalog = penpot.library.local.tokens; const theme = tokensCatalog?.addTheme({ group: themeGroup, name: themeName }); if (theme) { loadLibrary(); } } function addSet(setName: string) { const tokensCatalog = penpot.library.local.tokens; const set = tokensCatalog?.addSet({ name: setName }); if (set) { loadLibrary(); } } function addToken( setId: string, tokenType: string, tokenName: string, tokenValue: unknown, ) { const tokensCatalog = penpot.library.local.tokens; const set = tokensCatalog?.getSetById(setId); const token = set?.addToken({ type: tokenType as TokenType, name: tokenName, value: tokenValue as TokenValueString, }); if (token) { // TODO: remove this timeout when styleDictionary is replaced // with tokenScript and the token validation is syncrhronous. setTimeout(() => { loadTokens(setId); }, 0); } } function renameTheme(themeId: string, newName: string) { const tokensCatalog = penpot.library.local.tokens; const theme = tokensCatalog?.getThemeById(themeId); if (theme) { theme.name = newName; loadLibrary(); } } function renameSet(setId: string, newName: string) { const tokensCatalog = penpot.library.local.tokens; const set = tokensCatalog?.getSetById(setId); if (set) { set.name = newName; loadLibrary(); } } function renameToken(setId: string, tokenId: string, newName: string) { const tokensCatalog = penpot.library.local.tokens; const set = tokensCatalog?.getSetById(setId); const token = set?.getTokenById(tokenId); if (token) { token.name = newName; // TODO: remove this timeout when styleDictionary is replaced // with tokenScript and the token validation is syncrhronous. setTimeout(() => { loadTokens(setId); }, 0); } } function deleteTheme(themeId: string) { const tokensCatalog = penpot.library.local.tokens; const theme = tokensCatalog?.getThemeById(themeId); if (theme) { theme.remove(); loadLibrary(); } } function deleteSet(setId: string) { const tokensCatalog = penpot.library.local.tokens; const set = tokensCatalog?.getSetById(setId); if (set) { set.remove(); loadLibrary(); } } function deleteToken(setId: string, tokenId: string) { const tokensCatalog = penpot.library.local.tokens; const set = tokensCatalog?.getSetById(setId); const token = set?.getTokenById(tokenId); if (token) { token.remove(); loadTokens(setId); } } function toggleTheme(themeId: string) { const tokensCatalog = penpot.library.local.tokens; const theme = tokensCatalog?.getThemeById(themeId); if (theme) { theme.toggleActive(); loadLibrary(); } } function toggleSet(setId: string) { const tokensCatalog = penpot.library.local.tokens; const set = tokensCatalog?.getSetById(setId); if (set) { set.toggleActive(); loadLibrary(); } } function applyToken( setId: string, tokenId: string, properties: TokenProperty[] | undefined, ) { const tokensCatalog = penpot.library.local.tokens; const set = tokensCatalog?.getSetById(setId); const token = set?.getTokenById(tokenId); if (token) { token.applyToSelected(properties); } // Alternative way // // const selection = penpot.selection; // if (token && selection) { // token.applyToShapes(selection, properties); // } // Other alternative way // // const selection = penpot.selection; // if (token && selection) { // for (const shape of selection) { // shape.applyToken(token, properties); // } // } }