From ce351d34362c848159a94aabb5174fd357ab5b99 Mon Sep 17 00:00:00 2001 From: Jan Six Date: Thu, 5 Sep 2024 09:30:16 +0200 Subject: [PATCH 1/5] update logic to when removing styles look at overall themes created --- .../src/app/store/useTokens.tsx | 25 +++++++++++++++++++ .../asyncMessageHandlers/getLocalStyles.ts | 15 +++++++++++ .../src/plugin/asyncMessageHandlers/index.ts | 1 + .../src/plugin/controller.ts | 1 + .../src/plugin/updateStyles.ts | 16 ------------ .../src/types/AsyncMessages.ts | 11 ++++++-- 6 files changed, 51 insertions(+), 18 deletions(-) create mode 100644 packages/tokens-studio-for-figma/src/plugin/asyncMessageHandlers/getLocalStyles.ts diff --git a/packages/tokens-studio-for-figma/src/app/store/useTokens.tsx b/packages/tokens-studio-for-figma/src/app/store/useTokens.tsx index 82d08a3e2..ce85a2010 100644 --- a/packages/tokens-studio-for-figma/src/app/store/useTokens.tsx +++ b/packages/tokens-studio-for-figma/src/app/store/useTokens.tsx @@ -438,6 +438,8 @@ export default function useTokens() { isInfinite: true, }); + const allStyleIds = {}; + for (const themeId of selectedThemes) { const selectedTheme = themes.find((theme) => theme.id === themeId); @@ -477,12 +479,35 @@ export default function useTokens() { selectedTheme, })); + Object.assign(allStyleIds, createStylesResult.styleIds); + dispatch.tokenState.assignStyleIdsToCurrentTheme({ styleIds: createStylesResult.styleIds, tokens: tokensToCreate, selectedThemes }); } else { notifyToUI(`No styles created for theme: ${selectedTheme.name}. Make sure some sets are enabled.`, { error: true }); } } } + + // Remove styles that aren't in the theme or in the exposed token object + if (settings.removeStylesAndVariablesWithoutConnection) { + const { styles } = await AsyncMessageChannel.ReactInstance.message({ + type: AsyncMessageTypes.GET_LOCAL_STYLES, + }); + + const styleIdIncludedinTouchedStyles = (id) => Object.values(allStyleIds).includes(id); + + styles.forEach((style) => { + const shouldRemove = !styleIdIncludedinTouchedStyles(style.id) && ( + (settings.stylesTypography && style.type === 'TEXT') + || (settings.stylesColor && style.type === 'PAINT') + || (settings.stylesEffect && style.type === 'EFFECT') + ); + if (shouldRemove) { + style.remove(); + } + }); + } + dispatch.uiState.completeJob(BackgroundJobs.UI_CREATE_STYLES); }, [dispatch.tokenState, tokens, settings, themes, dispatch.uiState], diff --git a/packages/tokens-studio-for-figma/src/plugin/asyncMessageHandlers/getLocalStyles.ts b/packages/tokens-studio-for-figma/src/plugin/asyncMessageHandlers/getLocalStyles.ts new file mode 100644 index 000000000..5f66d9337 --- /dev/null +++ b/packages/tokens-studio-for-figma/src/plugin/asyncMessageHandlers/getLocalStyles.ts @@ -0,0 +1,15 @@ +import { AsyncMessageChannelHandlers } from '@/AsyncMessageChannel'; +import { AsyncMessageTypes } from '@/types/AsyncMessages'; + +export const getLocalStyles: AsyncMessageChannelHandlers[AsyncMessageTypes.GET_LOCAL_STYLES] = async () => { + try { + const localStyles = await Promise.all([ + figma.getLocalPaintStylesAsync(), + figma.getLocalTextStylesAsync(), + figma.getLocalEffectStylesAsync(), + ]).then((results) => results.flat()); + return { styles: localStyles }; + } catch (e) { + return { styles: [] }; + } +}; diff --git a/packages/tokens-studio-for-figma/src/plugin/asyncMessageHandlers/index.ts b/packages/tokens-studio-for-figma/src/plugin/asyncMessageHandlers/index.ts index c1a738bd3..8376de2c7 100644 --- a/packages/tokens-studio-for-figma/src/plugin/asyncMessageHandlers/index.ts +++ b/packages/tokens-studio-for-figma/src/plugin/asyncMessageHandlers/index.ts @@ -38,3 +38,4 @@ export * from './attachLocalVariablesToTheme'; export * from './renameVariables'; export * from './updateVariables'; export * from './setInitialLoad'; +export * from './getLocalStyles'; diff --git a/packages/tokens-studio-for-figma/src/plugin/controller.ts b/packages/tokens-studio-for-figma/src/plugin/controller.ts index 0c5b5a18b..2cc4090b0 100644 --- a/packages/tokens-studio-for-figma/src/plugin/controller.ts +++ b/packages/tokens-studio-for-figma/src/plugin/controller.ts @@ -60,6 +60,7 @@ AsyncMessageChannel.PluginInstance.handle( AsyncMessageChannel.PluginInstance.handle(AsyncMessageTypes.RESOLVE_STYLE_INFO, asyncHandlers.resolveStyleInfo); AsyncMessageChannel.PluginInstance.handle(AsyncMessageTypes.SET_NONE_VALUES_ON_NODE, asyncHandlers.setNoneValuesOnNode); AsyncMessageChannel.PluginInstance.handle(AsyncMessageTypes.GET_FIGMA_FONTS, asyncHandlers.getFigmaFonts); +AsyncMessageChannel.PluginInstance.handle(AsyncMessageTypes.GET_LOCAL_STYLES, asyncHandlers.getLocalStyles); AsyncMessageChannel.PluginInstance.handle(AsyncMessageTypes.SET_AUTH_DATA, asyncHandlers.setAuthData); AsyncMessageChannel.PluginInstance.handle(AsyncMessageTypes.CREATE_LOCAL_VARIABLES, asyncHandlers.createLocalVariables); AsyncMessageChannel.PluginInstance.handle(AsyncMessageTypes.CREATE_LOCAL_VARIABLES_WITHOUT_MODES, asyncHandlers.createLocalVariablesWithoutModes); diff --git a/packages/tokens-studio-for-figma/src/plugin/updateStyles.ts b/packages/tokens-studio-for-figma/src/plugin/updateStyles.ts index d8a0514e1..04c9a0518 100644 --- a/packages/tokens-studio-for-figma/src/plugin/updateStyles.ts +++ b/packages/tokens-studio-for-figma/src/plugin/updateStyles.ts @@ -66,21 +66,5 @@ export default async function updateStyles( notifyUI('Some styles were ignored due to "Ignore first part of token name" export setting', { error: true }); } - // Remove styles that aren't in the theme or in the exposed token object - if (settings.removeStylesAndVariablesWithoutConnection) { - const [allLocalPaintStyles, allLocalTextStyles, allLocalEffectStyles] = await Promise.all([ - figma.getLocalPaintStylesAsync(), - figma.getLocalTextStylesAsync(), - figma.getLocalEffectStylesAsync(), - ]); - const allLocalStyles = [...allLocalPaintStyles, ...allLocalTextStyles, ...allLocalEffectStyles]; - - allLocalStyles - .filter((style) => !Object.values(allStyleIds).includes(style.id)) - .forEach((style) => { - style.remove(); - }); - } - return allStyleIds; } diff --git a/packages/tokens-studio-for-figma/src/types/AsyncMessages.ts b/packages/tokens-studio-for-figma/src/types/AsyncMessages.ts index bcb02d918..6fbe80004 100644 --- a/packages/tokens-studio-for-figma/src/types/AsyncMessages.ts +++ b/packages/tokens-studio-for-figma/src/types/AsyncMessages.ts @@ -63,6 +63,7 @@ export enum AsyncMessageTypes { STARTUP = 'async/startup', GET_THEME_INFO = 'async/get-theme-info', GET_FIGMA_FONTS = 'async/get-figma-fonts', + GET_LOCAL_STYLES = 'async/get-local-styles', CREATE_LOCAL_VARIABLES = 'async/create-local-variables', CREATE_LOCAL_VARIABLES_WITHOUT_MODES = 'async/create-local-variables-without-modes', RESOLVE_VARIABLE_INFO = 'async/resolve-variable-info', @@ -261,6 +262,10 @@ export type GetFigmaFontsMessage = AsyncMessage }>; +export type GetLocalStylesMessage = AsyncMessage; +export type GetLocalStylesMessageResult = AsyncMessage +}>; export type SetAuthDataMessage = AsyncMessage; @@ -379,7 +384,8 @@ export type AsyncMessages = | AttachLocalVariablesToTheme | RenameVariablesAsyncMessage | UpdateVariablesAsyncMessage - | RemoveRelaunchDataMessage; + | RemoveRelaunchDataMessage + | GetLocalStylesMessage; export type AsyncMessageResults = CreateStylesAsyncMessageResult @@ -424,7 +430,8 @@ export type AsyncMessageResults = | AttachLocalVariablesToThemeResult | RenameVariablesAsyncMessageResult | UpdateVariablesAsyncMessageResult - | RemoveRelaunchDataMessageResult; + | RemoveRelaunchDataMessageResult + | GetLocalStylesMessageResult; export type AsyncMessagesMap = { [K in AsyncMessageTypes]: Extract From dc937cec0e4410fbc0a0365bde8f3b1049b6f91f Mon Sep 17 00:00:00 2001 From: Jan Six Date: Thu, 5 Sep 2024 09:31:43 +0200 Subject: [PATCH 2/5] add changeset --- .changeset/cold-humans-float.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/cold-humans-float.md diff --git a/.changeset/cold-humans-float.md b/.changeset/cold-humans-float.md new file mode 100644 index 000000000..6474d3e4e --- /dev/null +++ b/.changeset/cold-humans-float.md @@ -0,0 +1,5 @@ +--- +"@tokens-studio/figma-plugin": patch +--- + +Changed logic when "Remove styles and variables without connection to a token" is enabled where we now look at all created tokens in this session and remove them, instead of looking at each theme individually From b86c3985bfb0f22e19e5278ece9c9e121a75276c Mon Sep 17 00:00:00 2001 From: Jan Six Date: Thu, 5 Sep 2024 09:56:37 +0200 Subject: [PATCH 3/5] remove test from updateStyles --- .../src/plugin/updateStyles.test.ts | 38 ------------------- 1 file changed, 38 deletions(-) diff --git a/packages/tokens-studio-for-figma/src/plugin/updateStyles.test.ts b/packages/tokens-studio-for-figma/src/plugin/updateStyles.test.ts index 28e6f2a2e..c527812d7 100644 --- a/packages/tokens-studio-for-figma/src/plugin/updateStyles.test.ts +++ b/packages/tokens-studio-for-figma/src/plugin/updateStyles.test.ts @@ -340,42 +340,4 @@ describe('updateStyles', () => { expect(colorSpy).not.toHaveBeenCalled(); expect(textSpy).not.toHaveBeenCalled(); }); - - it('removes styles that arent connected if setting is on', async () => { - const tokens = [ - { - name: 'primary.500', - path: 'light/primary/500', - value: '#ff0000', - type: 'color', - styleId: '1234', - internal__Parent: 'global', - }, - ] as ExtendedSingleToken[]; - - mockGetThemeInfo.mockImplementationOnce(() => ( - Promise.resolve({ - type: AsyncMessageTypes.GET_THEME_INFO, - activeTheme: { - [INTERNAL_THEMES_NO_GROUP]: 'light', - }, - themes: [{ - id: 'light', - name: 'light', - selectedTokenSets: { - global: TokenSetStatus.ENABLED, - }, - $figmaStyleReferences: { - 'primary.500': '1234', - }, - }], - }) - )); - - await updateStyles(tokens, { - removeStylesAndVariablesWithoutConnection: true, - stylesColor: true, - } as SettingsState, false); - expect(mockRemove).toHaveBeenCalledTimes(1); - }); }); From 9642af0fd275cdc3c111c647566720f63db451d4 Mon Sep 17 00:00:00 2001 From: Jan Six Date: Fri, 6 Sep 2024 10:03:39 +0200 Subject: [PATCH 4/5] removes unused styles properly --- .../src/app/store/useTokens.tsx | 39 +++++++++++-------- .../asyncMessageHandlers/getLocalStyles.ts | 15 ------- .../src/plugin/asyncMessageHandlers/index.ts | 2 +- .../removeStylesWithoutConnection.ts | 22 +++++++++++ .../src/plugin/controller.ts | 2 +- .../src/types/AsyncMessages.ts | 14 ++++--- 6 files changed, 55 insertions(+), 39 deletions(-) delete mode 100644 packages/tokens-studio-for-figma/src/plugin/asyncMessageHandlers/getLocalStyles.ts create mode 100644 packages/tokens-studio-for-figma/src/plugin/asyncMessageHandlers/removeStylesWithoutConnection.ts diff --git a/packages/tokens-studio-for-figma/src/app/store/useTokens.tsx b/packages/tokens-studio-for-figma/src/app/store/useTokens.tsx index ce85a2010..c3c844717 100644 --- a/packages/tokens-studio-for-figma/src/app/store/useTokens.tsx +++ b/packages/tokens-studio-for-figma/src/app/store/useTokens.tsx @@ -438,7 +438,18 @@ export default function useTokens() { isInfinite: true, }); - const allStyleIds = {}; + const allStyleIds: Record = {}; + + const allExistingStyleReferences: string[] = themes.reduce((acc, theme) => { + if (theme.$figmaStyleReferences) { + Object.keys(theme.$figmaStyleReferences).forEach((key) => { + if (theme.$figmaStyleReferences && theme.$figmaStyleReferences[key]) { + acc.push(theme.$figmaStyleReferences[key]); + } + }); + } + return acc; + }, [] as string[]); for (const themeId of selectedThemes) { const selectedTheme = themes.find((theme) => theme.id === themeId); @@ -490,22 +501,18 @@ export default function useTokens() { // Remove styles that aren't in the theme or in the exposed token object if (settings.removeStylesAndVariablesWithoutConnection) { - const { styles } = await AsyncMessageChannel.ReactInstance.message({ - type: AsyncMessageTypes.GET_LOCAL_STYLES, - }); - - const styleIdIncludedinTouchedStyles = (id) => Object.values(allStyleIds).includes(id); - - styles.forEach((style) => { - const shouldRemove = !styleIdIncludedinTouchedStyles(style.id) && ( - (settings.stylesTypography && style.type === 'TEXT') - || (settings.stylesColor && style.type === 'PAINT') - || (settings.stylesEffect && style.type === 'EFFECT') - ); - if (shouldRemove) { - style.remove(); - } + console.log('Should remove!', Object.values(allStyleIds)); + const uniqueMergedStyleIds: string[] = Array.from(new Set([ + ...Object.values(allExistingStyleReferences).flat(), + ...Object.values(allStyleIds).flat(), + ])); + const { countOfRemovedStyles } = await AsyncMessageChannel.ReactInstance.message({ + type: AsyncMessageTypes.REMOVE_STYLES_WITHOUT_CONNECTION, + usedStyleIds: uniqueMergedStyleIds, }); + if (countOfRemovedStyles > 0) { + notifyToUI(`${countOfRemovedStyles} styles removed`); + } } dispatch.uiState.completeJob(BackgroundJobs.UI_CREATE_STYLES); diff --git a/packages/tokens-studio-for-figma/src/plugin/asyncMessageHandlers/getLocalStyles.ts b/packages/tokens-studio-for-figma/src/plugin/asyncMessageHandlers/getLocalStyles.ts deleted file mode 100644 index 5f66d9337..000000000 --- a/packages/tokens-studio-for-figma/src/plugin/asyncMessageHandlers/getLocalStyles.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { AsyncMessageChannelHandlers } from '@/AsyncMessageChannel'; -import { AsyncMessageTypes } from '@/types/AsyncMessages'; - -export const getLocalStyles: AsyncMessageChannelHandlers[AsyncMessageTypes.GET_LOCAL_STYLES] = async () => { - try { - const localStyles = await Promise.all([ - figma.getLocalPaintStylesAsync(), - figma.getLocalTextStylesAsync(), - figma.getLocalEffectStylesAsync(), - ]).then((results) => results.flat()); - return { styles: localStyles }; - } catch (e) { - return { styles: [] }; - } -}; diff --git a/packages/tokens-studio-for-figma/src/plugin/asyncMessageHandlers/index.ts b/packages/tokens-studio-for-figma/src/plugin/asyncMessageHandlers/index.ts index 8376de2c7..6ebf75e93 100644 --- a/packages/tokens-studio-for-figma/src/plugin/asyncMessageHandlers/index.ts +++ b/packages/tokens-studio-for-figma/src/plugin/asyncMessageHandlers/index.ts @@ -38,4 +38,4 @@ export * from './attachLocalVariablesToTheme'; export * from './renameVariables'; export * from './updateVariables'; export * from './setInitialLoad'; -export * from './getLocalStyles'; +export * from './removeStylesWithoutConnection'; diff --git a/packages/tokens-studio-for-figma/src/plugin/asyncMessageHandlers/removeStylesWithoutConnection.ts b/packages/tokens-studio-for-figma/src/plugin/asyncMessageHandlers/removeStylesWithoutConnection.ts new file mode 100644 index 000000000..632ee78a3 --- /dev/null +++ b/packages/tokens-studio-for-figma/src/plugin/asyncMessageHandlers/removeStylesWithoutConnection.ts @@ -0,0 +1,22 @@ +import { AsyncMessageChannelHandlers } from '@/AsyncMessageChannel'; +import { AsyncMessageTypes } from '@/types/AsyncMessages'; + +export const removeStylesWithoutConnection: AsyncMessageChannelHandlers[AsyncMessageTypes.REMOVE_STYLES_WITHOUT_CONNECTION] = async (msg) => { + try { + let count = 0; + const localStyles = await Promise.all([ + figma.getLocalPaintStylesAsync(), + figma.getLocalTextStylesAsync(), + figma.getLocalEffectStylesAsync(), + ]).then((results) => results.flat()); + localStyles.forEach((style) => { + if (!msg.usedStyleIds.includes(style.id)) { + style.remove(); + count += 1; + } + }); + return { countOfRemovedStyles: count }; + } catch (e) { + return { countOfRemovedStyles: 0 }; + } +}; diff --git a/packages/tokens-studio-for-figma/src/plugin/controller.ts b/packages/tokens-studio-for-figma/src/plugin/controller.ts index 2cc4090b0..7ce326635 100644 --- a/packages/tokens-studio-for-figma/src/plugin/controller.ts +++ b/packages/tokens-studio-for-figma/src/plugin/controller.ts @@ -60,7 +60,7 @@ AsyncMessageChannel.PluginInstance.handle( AsyncMessageChannel.PluginInstance.handle(AsyncMessageTypes.RESOLVE_STYLE_INFO, asyncHandlers.resolveStyleInfo); AsyncMessageChannel.PluginInstance.handle(AsyncMessageTypes.SET_NONE_VALUES_ON_NODE, asyncHandlers.setNoneValuesOnNode); AsyncMessageChannel.PluginInstance.handle(AsyncMessageTypes.GET_FIGMA_FONTS, asyncHandlers.getFigmaFonts); -AsyncMessageChannel.PluginInstance.handle(AsyncMessageTypes.GET_LOCAL_STYLES, asyncHandlers.getLocalStyles); +AsyncMessageChannel.PluginInstance.handle(AsyncMessageTypes.REMOVE_STYLES_WITHOUT_CONNECTION, asyncHandlers.removeStylesWithoutConnection); AsyncMessageChannel.PluginInstance.handle(AsyncMessageTypes.SET_AUTH_DATA, asyncHandlers.setAuthData); AsyncMessageChannel.PluginInstance.handle(AsyncMessageTypes.CREATE_LOCAL_VARIABLES, asyncHandlers.createLocalVariables); AsyncMessageChannel.PluginInstance.handle(AsyncMessageTypes.CREATE_LOCAL_VARIABLES_WITHOUT_MODES, asyncHandlers.createLocalVariablesWithoutModes); diff --git a/packages/tokens-studio-for-figma/src/types/AsyncMessages.ts b/packages/tokens-studio-for-figma/src/types/AsyncMessages.ts index 6fbe80004..3ea03e5ec 100644 --- a/packages/tokens-studio-for-figma/src/types/AsyncMessages.ts +++ b/packages/tokens-studio-for-figma/src/types/AsyncMessages.ts @@ -63,7 +63,7 @@ export enum AsyncMessageTypes { STARTUP = 'async/startup', GET_THEME_INFO = 'async/get-theme-info', GET_FIGMA_FONTS = 'async/get-figma-fonts', - GET_LOCAL_STYLES = 'async/get-local-styles', + REMOVE_STYLES_WITHOUT_CONNECTION = 'async/remove-styles-without-connection', CREATE_LOCAL_VARIABLES = 'async/create-local-variables', CREATE_LOCAL_VARIABLES_WITHOUT_MODES = 'async/create-local-variables-without-modes', RESOLVE_VARIABLE_INFO = 'async/resolve-variable-info', @@ -262,9 +262,11 @@ export type GetFigmaFontsMessage = AsyncMessage }>; -export type GetLocalStylesMessage = AsyncMessage; -export type GetLocalStylesMessageResult = AsyncMessage +export type RemoveStylesWithoutConnectionMessage = AsyncMessage; +export type RemoveStylesWithoutConnectionResult = AsyncMessage; export type SetAuthDataMessage = AsyncMessage From 98b72fa31ba973e1177ec6537049f62b59fe1d53 Mon Sep 17 00:00:00 2001 From: Jan Six Date: Tue, 10 Sep 2024 12:17:35 +0200 Subject: [PATCH 5/5] Updates from editor --- packages/tokens-studio-for-figma/src/app/store/useTokens.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/tokens-studio-for-figma/src/app/store/useTokens.tsx b/packages/tokens-studio-for-figma/src/app/store/useTokens.tsx index c3c844717..7b86e42e2 100644 --- a/packages/tokens-studio-for-figma/src/app/store/useTokens.tsx +++ b/packages/tokens-studio-for-figma/src/app/store/useTokens.tsx @@ -501,7 +501,6 @@ export default function useTokens() { // Remove styles that aren't in the theme or in the exposed token object if (settings.removeStylesAndVariablesWithoutConnection) { - console.log('Should remove!', Object.values(allStyleIds)); const uniqueMergedStyleIds: string[] = Array.from(new Set([ ...Object.values(allExistingStyleReferences).flat(), ...Object.values(allStyleIds).flat(),