Skip to content
Draft
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
16 changes: 16 additions & 0 deletions .changeset/add-figma-commit-undo-points.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
---
"@tokens-studio/figma-plugin": patch
---

Add figma.commitUndo() calls at key points where tokens are applied or removed from Figma layers

This adds undo points before major operations that change what's applied to Figma layers:
- When applying token values to nodes (setValuesOnNode)
- When removing token values from nodes (removeValuesFromNode)
- When updating/setting node data with tokens
- When removing tokens by value
- When remapping or bulk remapping tokens
- When swapping styles between themes
- When applying tokens to living documentation

This allows users to use Figma's native undo (Cmd/Ctrl+Z) to revert token application operations in logical chunks.
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,11 @@ import { defaultWorker } from '../Worker';
export const bulkRemapTokens: AsyncMessageChannelHandlers[AsyncMessageTypes.BULK_REMAP_TOKENS] = async (msg) => {
// Big O(n * m) + Big O(updatePluginData) + Big O(sendSelectionChange): (n = amount of nodes, m = amount of tokens in the node)
try {
// Commit undo point before bulk remapping tokens
if (typeof figma !== 'undefined' && figma.commitUndo) {
figma.commitUndo();
}

const { oldName, newName, useRegex } = msg;
const allWithData = await defaultNodeManager.findBaseNodesWithData({ updateMode: msg.updateMode });
const namespace = SharedPluginDataNamespaces.TOKENS;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,11 @@ import { ProgressTracker } from '../ProgressTracker';

export const remapTokens: AsyncMessageChannelHandlers[AsyncMessageTypes.REMAP_TOKENS] = async (msg) => {
try {
// Commit undo point before remapping tokens
if (typeof figma !== 'undefined' && figma.commitUndo) {
figma.commitUndo();
}

const {
oldName, newName, updateMode, category,
} = msg;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,13 @@ export const removeTokensByValue: AsyncMessageChannelHandlers[AsyncMessageTypes.
}));
});

if (nodesToRemove.length) await removePluginDataByMap({ nodeKeyMap: nodesToRemove });
if (nodesToRemove.length) {
// Commit undo point before removing tokens by value
if (typeof figma !== 'undefined' && figma.commitUndo) {
figma.commitUndo();
}
await removePluginDataByMap({ nodeKeyMap: nodesToRemove });
}

sendSelectionChange();
};
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,11 @@ import { defaultTokenValueRetriever } from '../TokenValueRetriever';
export const setNodeData: AsyncMessageChannelHandlers[AsyncMessageTypes.SET_NODE_DATA] = async (msg) => {
try {
if (figma.currentPage.selection.length) {
// Commit undo point before setting node data
if (typeof figma !== 'undefined' && figma.commitUndo) {
figma.commitUndo();
}

const tokensMap = tokenArrayGroupToMap(msg.tokens);
const nodes = figma.currentPage.selection;
const {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,11 @@ import { defaultWorker } from '../Worker';
import { ProgressTracker } from '../ProgressTracker';

export const setNoneValuesOnNode: AsyncMessageChannelHandlers[AsyncMessageTypes.SET_NONE_VALUES_ON_NODE] = async (msg) => {
// Commit undo point before setting none values on nodes
if (typeof figma !== 'undefined' && figma.commitUndo) {
figma.commitUndo();
}

const nodesToRemove: { [key: string]: Properties[] } = {};

msg.tokensToSet.forEach((token) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,11 @@ function getRootNode(updateMode: UpdateMode) {

// Go through layers to swap styles
export async function swapStyles(activeTheme: Record<string, string>, themes: ThemeObjectsList, updateMode: UpdateMode) {
// Commit undo point before swapping styles
if (typeof figma !== 'undefined' && figma.commitUndo) {
figma.commitUndo();
}

const activeThemes = themes.filter((theme) => Object.values(activeTheme).some((v) => v === theme.id)).map((t) => t.name);
// Creates an object that groups sibling styles by token name and theme name, e.g. { 'color.background': { 'dark': 'S:1234,4:16', 'light': 'S:1235,4:16' } }
const mappedStyleReferences = themes.reduce((acc, theme) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,10 @@ export const update: AsyncMessageChannelHandlers[AsyncMessageTypes.UPDATE] = asy
});
}
if (msg.tokens) {
// Commit undo point before updating nodes with tokens
if (typeof figma !== 'undefined' && figma.commitUndo) {
figma.commitUndo();
}
const {
figmaVariableReferences, figmaStyleReferences, stylePathPrefix,
} = await getThemeReferences(msg.settings.prefixStylesWithThemeName);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,11 @@ export async function applyTokensToDocumentation(
resolvedTokens: AnyTokenList,
): Promise<void> {
try {
// Commit undo point before applying tokens to documentation
if (typeof figma !== 'undefined' && figma.commitUndo) {
figma.commitUndo();
}

// Get current UI settings for token application
const uiSettings = await UiSettingsProperty.read(figma.root);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,10 @@ export default async function setValuesOnNode({
baseFontSize?: string; // The base font size to use, note that we should find a better way to pass this through
}) {
try {
// Commit undo point before applying token values to nodes
if (typeof figma !== 'undefined' && figma.commitUndo) {
figma.commitUndo();
}
if (
node.type !== 'CONNECTOR'
&& node.type !== 'SHAPE_WITH_TEXT'
Expand Down