Compare commits

...

2 Commits

Author SHA1 Message Date
Eva Marco
2523096fdd 🐛 Fix css rule (#8206) 2026-01-27 12:30:14 +01:00
Xaviju
8e63c4e3e8 ♻️ Review remap interface and interaction (#8168)
* ♻️ Review remap interface and interaction
* ♻️ Fix remapping feature tests
2026-01-27 11:18:34 +01:00
7 changed files with 363 additions and 415 deletions

View File

@@ -12,88 +12,118 @@ test.beforeEach(async ({ page }) => {
await BaseWebSocketPage.mockRPC(page, "get-teams", "get-teams-tokens.json"); await BaseWebSocketPage.mockRPC(page, "get-teams", "get-teams-tokens.json");
}); });
test.describe("Tokens: Remapping Feature", () => { const createToken = async (page, type, name, textFieldName, value) => {
const tokensTabPanel = page.getByRole("tabpanel", { name: "tokens" });
const { tokensUpdateCreateModal } = await setupTokensFile(page, {
flags: ["enable-token-shadow"],
});
// Create base token
await tokensTabPanel
.getByRole("button", { name: `Add Token: ${type}` })
.click();
await expect(tokensUpdateCreateModal).toBeVisible();
const nameField = tokensUpdateCreateModal.getByLabel("Name");
await nameField.fill(name);
const colorField = tokensUpdateCreateModal.getByRole("textbox", {
name: textFieldName,
});
await colorField.fill(value);
const submitButton = tokensUpdateCreateModal.getByRole("button", {
name: "Save",
});
await submitButton.click();
await expect(tokensUpdateCreateModal).not.toBeVisible();
};
const renameToken = async (page, oldName, newName) => {
const { tokensUpdateCreateModal, tokensSidebar, tokenContextMenuForToken } =
await setupTokensFile(page, { flags: ["enable-token-shadow"] });
const baseToken = tokensSidebar.getByRole("button", {
name: oldName,
});
await baseToken.click({ button: "right" });
await tokenContextMenuForToken.getByText("Edit token").click();
await expect(tokensUpdateCreateModal).toBeVisible();
const nameField = tokensUpdateCreateModal.getByLabel("Name");
await nameField.fill(newName);
const submitButton = tokensUpdateCreateModal.getByRole("button", {
name: "Save",
});
await submitButton.click();
};
const createCompositeDerivedToken = async (page, type, name, reference) => {
const tokensTabPanel = page.getByRole("tabpanel", { name: "tokens" });
const { tokensUpdateCreateModal } = await setupTokensFile(page, {
flags: ["enable-token-shadow"],
});
await tokensTabPanel
.getByRole("button", { name: `Add Token: ${type}` })
.click();
await expect(tokensUpdateCreateModal).toBeVisible();
const nameField = tokensUpdateCreateModal.getByRole("textbox", {
name: "Name",
});
await nameField.fill(name);
const referenceToggle = tokensUpdateCreateModal.getByTestId("reference-opt");
await referenceToggle.click();
const referenceField = tokensUpdateCreateModal.getByRole("textbox", {
name: "Reference",
});
await referenceField.fill(reference);
const submitButton = tokensUpdateCreateModal.getByRole("button", {
name: "Save",
});
await submitButton.click();
await expect(tokensUpdateCreateModal).not.toBeVisible();
};
test.describe("Remapping Tokens", () => {
test.describe("Box Shadow Token Remapping", () => { test.describe("Box Shadow Token Remapping", () => {
test("User renames box shadow token with alias references", async ({ test("User renames box shadow token with alias references", async ({
page, page,
}) => { }) => {
const { const { tokensSidebar } = await setupTokensFile(page, {
tokensUpdateCreateModal, flags: ["enable-token-shadow"],
tokensSidebar, });
tokenContextMenuForToken,
} = await setupTokensFile(page, { flags: ["enable-token-shadow"] });
const tokensTabPanel = page.getByRole("tabpanel", { name: "tokens" });
// Create base shadow token // Create base shadow token
await tokensTabPanel await createToken(page, "Shadow", "base-shadow", "Color", "#000000");
.getByRole("button", { name: "Add Token: Shadow" })
.click();
await expect(tokensUpdateCreateModal).toBeVisible();
let nameField = tokensUpdateCreateModal.getByLabel("Name");
await nameField.fill("base-shadow");
const colorField = tokensUpdateCreateModal.getByRole("textbox", {
name: "Color",
});
await colorField.fill("#000000");
let submitButton = tokensUpdateCreateModal.getByRole("button", {
name: "Save",
});
await submitButton.click();
await expect(tokensUpdateCreateModal).not.toBeVisible();
// Create derived shadow token that references base-shadow // Create derived shadow token that references base-shadow
await tokensTabPanel await createCompositeDerivedToken(
.getByRole("button", { name: "Add Token: Shadow" }) page,
.click(); "Shadow",
await expect(tokensUpdateCreateModal).toBeVisible(); "derived-shadow",
"{base-shadow}",
nameField = tokensUpdateCreateModal.getByRole("textbox", { );
name: "Name",
});
await nameField.fill("derived-shadow");
const referenceToggle =
tokensUpdateCreateModal.getByTestId("reference-opt");
await referenceToggle.click();
const referenceField = tokensUpdateCreateModal.getByRole("textbox", {
name: "Reference",
});
await referenceField.fill("{base-shadow}");
submitButton = tokensUpdateCreateModal.getByRole("button", {
name: "Save",
});
await submitButton.click();
await expect(tokensUpdateCreateModal).not.toBeVisible();
// Rename base-shadow token // Rename base-shadow token
const baseToken = tokensSidebar.getByRole("button", { await renameToken(page, "base-shadow", "foundation-shadow");
name: "base-shadow",
});
await baseToken.click({ button: "right" });
await tokenContextMenuForToken.getByText("Edit token").click();
await expect(tokensUpdateCreateModal).toBeVisible();
nameField = tokensUpdateCreateModal.getByLabel("Name");
await nameField.fill("foundation-shadow");
submitButton = tokensUpdateCreateModal.getByRole("button", {
name: "Save",
});
await submitButton.click();
// Check for remapping modal // Check for remapping modal
const remappingModal = page.getByTestId("token-remapping-modal"); const remappingModal = page.getByTestId("token-remapping-modal");
await expect(remappingModal).toBeVisible({ timeout: 5000 }); await expect(remappingModal).toBeVisible({ timeout: 5000 });
await expect(remappingModal).toContainText("1"); await expect(remappingModal).toContainText("base-shadow");
await expect(remappingModal).toContainText("foundation-shadow");
const confirmButton = remappingModal.getByRole("button", { const confirmButton = remappingModal.getByRole("button", {
name: /remap/i, name: "remap tokens",
}); });
await confirmButton.click(); await confirmButton.click();
@@ -116,51 +146,16 @@ test.describe("Tokens: Remapping Feature", () => {
workspacePage, workspacePage,
} = await setupTokensFile(page, { flags: ["enable-token-shadow"] }); } = await setupTokensFile(page, { flags: ["enable-token-shadow"] });
const tokensTabPanel = page.getByRole("tabpanel", { name: "tokens" });
// Create base shadow token // Create base shadow token
await tokensTabPanel await createToken(page, "Shadow", "primary-shadow", "Color", "#000000");
.getByRole("button", { name: "Add Token: Shadow" })
.click();
await expect(tokensUpdateCreateModal).toBeVisible();
let nameField = tokensUpdateCreateModal.getByLabel("Name");
await nameField.fill("primary-shadow");
let colorField = tokensUpdateCreateModal.getByRole("textbox", {
name: "Color",
});
await colorField.fill("#000000");
let submitButton = tokensUpdateCreateModal.getByRole("button", {
name: "Save",
});
await submitButton.click();
await expect(tokensUpdateCreateModal).not.toBeVisible();
// Create derived shadow token that references base // Create derived shadow token that references base
await tokensTabPanel await createCompositeDerivedToken(
.getByRole("button", { name: "Add Token: Shadow" }) page,
.click(); "Shadow",
await expect(tokensUpdateCreateModal).toBeVisible(); "card-shadow",
"{primary-shadow}",
nameField = tokensUpdateCreateModal.getByLabel("Name"); );
await nameField.fill("card-shadow");
const referenceToggle =
tokensUpdateCreateModal.getByTestId("reference-opt");
await referenceToggle.click();
const referenceField = tokensUpdateCreateModal.getByRole("textbox", {
name: "Reference",
});
await referenceField.fill("{primary-shadow}");
submitButton = tokensUpdateCreateModal.getByRole("button", {
name: "Save",
});
await submitButton.click();
await expect(tokensUpdateCreateModal).not.toBeVisible();
// Apply the referenced token to a shape // Apply the referenced token to a shape
await page.getByRole("tab", { name: "Layers" }).click(); await page.getByRole("tab", { name: "Layers" }).click();
@@ -183,16 +178,16 @@ test.describe("Tokens: Remapping Feature", () => {
await tokenContextMenuForToken.getByText("Edit token").click(); await tokenContextMenuForToken.getByText("Edit token").click();
await expect(tokensUpdateCreateModal).toBeVisible(); await expect(tokensUpdateCreateModal).toBeVisible();
nameField = tokensUpdateCreateModal.getByLabel("Name"); const nameField = tokensUpdateCreateModal.getByLabel("Name");
await nameField.fill("main-shadow"); await nameField.fill("main-shadow");
// Update the color value // Update the color value
colorField = tokensUpdateCreateModal.getByRole("textbox", { const colorField = tokensUpdateCreateModal.getByRole("textbox", {
name: "Color", name: "Color",
}); });
await colorField.fill("#FF0000"); await colorField.fill("#FF0000");
submitButton = tokensUpdateCreateModal.getByRole("button", { const submitButton = tokensUpdateCreateModal.getByRole("button", {
name: "Save", name: "Save",
}); });
await submitButton.click(); await submitButton.click();
@@ -202,7 +197,7 @@ test.describe("Tokens: Remapping Feature", () => {
await expect(remappingModal).toBeVisible({ timeout: 5000 }); await expect(remappingModal).toBeVisible({ timeout: 5000 });
const confirmButton = remappingModal.getByRole("button", { const confirmButton = remappingModal.getByRole("button", {
name: /remap/i, name: "remap tokens",
}); });
await confirmButton.click(); await confirmButton.click();
@@ -259,73 +254,25 @@ test.describe("Tokens: Remapping Feature", () => {
const tokensTabPanel = page.getByRole("tabpanel", { name: "tokens" }); const tokensTabPanel = page.getByRole("tabpanel", { name: "tokens" });
// Create base typography token // Create base typography token
await tokensTabPanel await createToken(page, "Typography", "base-text", "Font size", "16");
.getByRole("button", { name: "Add Token: Typography" })
.click();
await expect(tokensUpdateCreateModal).toBeVisible();
let nameField = tokensUpdateCreateModal.getByLabel("Name");
await nameField.fill("base-text");
const fontSizeField = tokensUpdateCreateModal.getByRole("textbox", {
name: "Font size",
});
await fontSizeField.fill("16");
let submitButton = tokensUpdateCreateModal.getByRole("button", {
name: "Save",
});
await submitButton.click();
await expect(tokensUpdateCreateModal).not.toBeVisible();
// Create derived typography token // Create derived typography token
await tokensTabPanel await createCompositeDerivedToken(
.getByRole("button", { name: "Add Token: Typography" }) page,
.click(); "Typography",
await expect(tokensUpdateCreateModal).toBeVisible(); "body-text",
"{base-text}",
nameField = tokensUpdateCreateModal.getByRole("textbox", { );
name: "Name",
});
await nameField.fill("body-text");
const referenceToggle =
tokensUpdateCreateModal.getByTestId("reference-opt");
await referenceToggle.click();
const referenceField = tokensUpdateCreateModal.getByRole("textbox", {
name: "Reference",
});
await referenceField.fill("{base-text}");
submitButton = tokensUpdateCreateModal.getByRole("button", {
name: "Save",
});
await submitButton.click();
await expect(tokensUpdateCreateModal).not.toBeVisible();
// Rename base token // Rename base token
const baseToken = tokensSidebar.getByRole("button", { await renameToken(page, "base-text", "default-text");
name: "base-text",
});
await baseToken.click({ button: "right" });
await tokenContextMenuForToken.getByText("Edit token").click();
await expect(tokensUpdateCreateModal).toBeVisible();
nameField = tokensUpdateCreateModal.getByLabel("Name");
await nameField.fill("default-text");
submitButton = tokensUpdateCreateModal.getByRole("button", {
name: "Save",
});
await submitButton.click();
// Check for remapping modal // Check for remapping modal
const remappingModal = page.getByTestId("token-remapping-modal"); const remappingModal = page.getByTestId("token-remapping-modal");
await expect(remappingModal).toBeVisible({ timeout: 5000 }); await expect(remappingModal).toBeVisible({ timeout: 5000 });
const confirmButton = remappingModal.getByRole("button", { const confirmButton = remappingModal.getByRole("button", {
name: /remap/i, name: "remap tokens",
}); });
await confirmButton.click(); await confirmButton.click();
@@ -351,24 +298,7 @@ test.describe("Tokens: Remapping Feature", () => {
const tokensTabPanel = page.getByRole("tabpanel", { name: "tokens" }); const tokensTabPanel = page.getByRole("tabpanel", { name: "tokens" });
// Create base typography token // Create base typography token
await tokensTabPanel await createToken(page, "Typography", "body-style", "Font size", "16");
.getByRole("button", { name: "Add Token: Typography" })
.click();
await expect(tokensUpdateCreateModal).toBeVisible();
let nameField = tokensUpdateCreateModal.getByLabel("Name");
await nameField.fill("body-style");
let fontSizeField = tokensUpdateCreateModal.getByRole("textbox", {
name: "Font size",
});
await fontSizeField.fill("16");
let submitButton = tokensUpdateCreateModal.getByRole("button", {
name: "Save",
});
await submitButton.click();
await expect(tokensUpdateCreateModal).not.toBeVisible();
// Create derived typography token // Create derived typography token
await tokensTabPanel await tokensTabPanel
@@ -376,7 +306,7 @@ test.describe("Tokens: Remapping Feature", () => {
.click(); .click();
await expect(tokensUpdateCreateModal).toBeVisible(); await expect(tokensUpdateCreateModal).toBeVisible();
nameField = tokensUpdateCreateModal.getByRole("textbox", { let nameField = tokensUpdateCreateModal.getByRole("textbox", {
name: "Name", name: "Name",
}); });
await nameField.fill("paragraph-style"); await nameField.fill("paragraph-style");
@@ -390,7 +320,7 @@ test.describe("Tokens: Remapping Feature", () => {
}); });
await referenceField.fill("{body-style}"); await referenceField.fill("{body-style}");
submitButton = tokensUpdateCreateModal.getByRole("button", { let submitButton = tokensUpdateCreateModal.getByRole("button", {
name: "Save", name: "Save",
}); });
await submitButton.click(); await submitButton.click();
@@ -421,7 +351,7 @@ test.describe("Tokens: Remapping Feature", () => {
await nameField.fill("text-base"); await nameField.fill("text-base");
// Update the font size value // Update the font size value
fontSizeField = tokensUpdateCreateModal.getByRole("textbox", { const fontSizeField = tokensUpdateCreateModal.getByRole("textbox", {
name: "Font size", name: "Font size",
}); });
await fontSizeField.fill("18"); await fontSizeField.fill("18");
@@ -436,7 +366,7 @@ test.describe("Tokens: Remapping Feature", () => {
await expect(remappingModal).toBeVisible({ timeout: 5000 }); await expect(remappingModal).toBeVisible({ timeout: 5000 });
const confirmButton = remappingModal.getByRole("button", { const confirmButton = remappingModal.getByRole("button", {
name: /remap/i, name: "remap tokens",
}); });
await confirmButton.click(); await confirmButton.click();
@@ -471,72 +401,29 @@ test.describe("Tokens: Remapping Feature", () => {
test("User renames border radius token with alias references", async ({ test("User renames border radius token with alias references", async ({
page, page,
}) => { }) => {
const { const { tokensSidebar } = await setupTokensFile(page);
tokensUpdateCreateModal,
tokensSidebar,
tokenContextMenuForToken,
} = await setupTokensFile(page);
const tokensTabPanel = page.getByRole("tabpanel", { name: "tokens" });
// Create base border radius token // Create base border radius token
await tokensTabPanel await createToken(page, "Border Radius", "base-radius", "Value", "4");
.getByRole("button", { name: "Add Token: Border Radius" })
.click();
await expect(tokensUpdateCreateModal).toBeVisible();
let nameField = tokensUpdateCreateModal.getByLabel("Name");
await nameField.fill("base-radius");
const valueField = tokensUpdateCreateModal.getByLabel("Value");
await valueField.fill("4");
let submitButton = tokensUpdateCreateModal.getByRole("button", {
name: "Save",
});
await submitButton.click();
await expect(tokensUpdateCreateModal).not.toBeVisible();
// Create derived border radius token // Create derived border radius token
await tokensTabPanel await createToken(
.getByRole("button", { name: "Add Token: Border Radius" }) page,
.click(); "Border Radius",
await expect(tokensUpdateCreateModal).toBeVisible(); "card-radius",
"Value",
nameField = tokensUpdateCreateModal.getByLabel("Name"); "{base-radius}",
await nameField.fill("card-radius"); );
const valueField2 = tokensUpdateCreateModal.getByLabel("Value");
await valueField2.fill("{base-radius}");
submitButton = tokensUpdateCreateModal.getByRole("button", {
name: "Save",
});
await submitButton.click();
await expect(tokensUpdateCreateModal).not.toBeVisible();
// Rename base token // Rename base token
const baseToken = tokensSidebar.getByRole("button", { await renameToken(page, "base-radius", "primary-radius");
name: "base-radius",
});
await baseToken.click({ button: "right" });
await tokenContextMenuForToken.getByText("Edit token").click();
await expect(tokensUpdateCreateModal).toBeVisible();
nameField = tokensUpdateCreateModal.getByLabel("Name");
await nameField.fill("primary-radius");
submitButton = tokensUpdateCreateModal.getByRole("button", {
name: "Save",
});
await submitButton.click();
// Check for remapping modal // Check for remapping modal
const remappingModal = page.getByTestId("token-remapping-modal"); const remappingModal = page.getByTestId("token-remapping-modal");
await expect(remappingModal).toBeVisible({ timeout: 5000 }); await expect(remappingModal).toBeVisible({ timeout: 5000 });
const confirmButton = remappingModal.getByRole("button", { const confirmButton = remappingModal.getByRole("button", {
name: /remap/i, name: "remap tokens",
}); });
await confirmButton.click(); await confirmButton.click();
@@ -558,43 +445,17 @@ test.describe("Tokens: Remapping Feature", () => {
tokenContextMenuForToken, tokenContextMenuForToken,
} = await setupTokensFile(page); } = await setupTokensFile(page);
const tokensTabPanel = page.getByRole("tabpanel", { name: "tokens" });
// Create base border radius token // Create base border radius token
await tokensTabPanel await createToken(page, "Border Radius", "radius-sm", "Value", "4");
.getByRole("button", { name: "Add Token: Border Radius" })
.click();
await expect(tokensUpdateCreateModal).toBeVisible();
let nameField = tokensUpdateCreateModal.getByLabel("Name");
await nameField.fill("radius-sm");
let valueField = tokensUpdateCreateModal.getByLabel("Value");
await valueField.fill("4");
let submitButton = tokensUpdateCreateModal.getByRole("button", {
name: "Save",
});
await submitButton.click();
await expect(tokensUpdateCreateModal).not.toBeVisible();
// Create derived border radius token // Create derived border radius token
await tokensTabPanel await createToken(
.getByRole("button", { name: "Add Token: Border Radius" }) page,
.click(); "Border Radius",
await expect(tokensUpdateCreateModal).toBeVisible(); "button-radius",
"Value",
nameField = tokensUpdateCreateModal.getByLabel("Name"); "{radius-sm}",
await nameField.fill("button-radius"); );
const valueField2 = tokensUpdateCreateModal.getByLabel("Value");
await valueField2.fill("{radius-sm}");
submitButton = tokensUpdateCreateModal.getByRole("button", {
name: "Save",
});
await submitButton.click();
await expect(tokensUpdateCreateModal).not.toBeVisible();
// Rename and update value of base token // Rename and update value of base token
const radiusToken = tokensSidebar.getByRole("button", { const radiusToken = tokensSidebar.getByRole("button", {
@@ -604,14 +465,14 @@ test.describe("Tokens: Remapping Feature", () => {
await tokenContextMenuForToken.getByText("Edit token").click(); await tokenContextMenuForToken.getByText("Edit token").click();
await expect(tokensUpdateCreateModal).toBeVisible(); await expect(tokensUpdateCreateModal).toBeVisible();
nameField = tokensUpdateCreateModal.getByLabel("Name"); const nameField = tokensUpdateCreateModal.getByLabel("Name");
await nameField.fill("radius-base"); await nameField.fill("radius-base");
// Update the value // Update the value
valueField = tokensUpdateCreateModal.getByLabel("Value"); const valueField = tokensUpdateCreateModal.getByLabel("Value");
await valueField.fill("8"); await valueField.fill("8");
submitButton = tokensUpdateCreateModal.getByRole("button", { const submitButton = tokensUpdateCreateModal.getByRole("button", {
name: "Save", name: "Save",
}); });
await submitButton.click(); await submitButton.click();
@@ -621,7 +482,7 @@ test.describe("Tokens: Remapping Feature", () => {
await expect(remappingModal).toBeVisible({ timeout: 5000 }); await expect(remappingModal).toBeVisible({ timeout: 5000 });
const confirmButton = remappingModal.getByRole("button", { const confirmButton = remappingModal.getByRole("button", {
name: /remap/i, name: "remap tokens",
}); });
await confirmButton.click(); await confirmButton.click();
@@ -648,4 +509,82 @@ test.describe("Tokens: Remapping Feature", () => {
await expect(currentValue).toHaveValue("{radius-base}"); await expect(currentValue).toHaveValue("{radius-base}");
}); });
}); });
test.describe("Cancel remap", () => {
test("Only rename - breaks reference", async ({ page }) => {
const { tokensSidebar } = await setupTokensFile(page, {
flags: ["enable-token-shadow"],
});
// Create base shadow token
await createToken(page, "Shadow", "base-shadow", "Color", "#000000");
// Create derived shadow token that references base-shadow
await createCompositeDerivedToken(
page,
"Shadow",
"derived-shadow",
"{base-shadow}",
);
// Rename base-shadow token
await renameToken(page, "base-shadow", "foundation-shadow");
// Check for remapping modal
const remappingModal = page.getByTestId("token-remapping-modal");
await expect(remappingModal).toBeVisible({ timeout: 5000 });
const cancelButton = remappingModal.getByRole("button", {
name: "don't remap",
});
await cancelButton.click();
// Verify token was renamed
await expect(
tokensSidebar.getByRole("button", {
name: "foundation-shadow",
}),
).toBeVisible();
await expect(
tokensSidebar.locator('[aria-label="Missing reference"]'),
).toBeVisible();
});
test("Cancel process - no changes applied", async ({ page }) => {
const { tokensSidebar } = await setupTokensFile(page, {
flags: ["enable-token-shadow"],
});
// Create base shadow token
await createToken(page, "Shadow", "base-shadow", "Color", "#000000");
// Create derived shadow token that references base-shadow
await createCompositeDerivedToken(
page,
"Shadow",
"derived-shadow",
"{base-shadow}",
);
// Rename base-shadow token
await renameToken(page, "base-shadow", "foundation-shadow");
// Check for remapping modal
const remappingModal = page.getByTestId("token-remapping-modal");
await expect(remappingModal).toBeVisible({ timeout: 5000 });
const closeButton = remappingModal.getByRole("button", {
name: "close",
});
await closeButton.click();
// Verify original token name still exists
await expect(
tokensSidebar.getByRole("button", { name: "base-shadow" }),
).toBeVisible();
await expect(
tokensSidebar.getByRole("button", { name: "derived-shadow" }),
).toBeVisible();
});
});
}); });

View File

@@ -28,7 +28,6 @@
[app.main.ui.forms :as fc] [app.main.ui.forms :as fc]
[app.main.ui.workspace.tokens.management.forms.controls :as token.controls] [app.main.ui.workspace.tokens.management.forms.controls :as token.controls]
[app.main.ui.workspace.tokens.management.forms.validators :refer [default-validate-token]] [app.main.ui.workspace.tokens.management.forms.validators :refer [default-validate-token]]
[app.main.ui.workspace.tokens.remapping-modal :as remapping-modal]
[app.util.dom :as dom] [app.util.dom :as dom]
[app.util.forms :as fm] [app.util.forms :as fm]
[app.util.i18n :refer [tr]] [app.util.i18n :refer [tr]]
@@ -182,9 +181,33 @@
(when (or (k/enter? e) (k/space? e)) (when (or (k/enter? e) (k/space? e))
(on-cancel e)))) (on-cancel e))))
on-remap-token
(mf/use-fn
(mf/deps token)
(fn [valid-token name old-name description]
(st/emit!
(dwtl/update-token (:id token)
{:name name
:value (:value valid-token)
:description description})
(remap/remap-tokens old-name name)
(dwtp/propagate-workspace-tokens)
(modal/hide!))))
on-rename-token
(mf/use-fn
(mf/deps token)
(fn [valid-token name description]
(st/emit!
(dwtl/update-token (:id token)
{:name name
:value (:value valid-token)
:description description})
(modal/hide!))))
on-submit on-submit
(mf/use-fn (mf/use-fn
(mf/deps validate-token token tokens token-type value-subfield type active-tab) (mf/deps validate-token token tokens token-type value-subfield type active-tab on-remap-token on-rename-token is-create)
(fn [form _event] (fn [form _event]
(let [name (get-in @form [:clean-data :name]) (let [name (get-in @form [:clean-data :name])
path (str (d/name token-type) "." name) path (str (d/name token-type) "." name)
@@ -202,22 +225,15 @@
file-data (dh/lookup-file-data state) file-data (dh/lookup-file-data state)
old-name (:name token) old-name (:name token)
is-rename (and (= action "edit") (not= name old-name)) is-rename (and (= action "edit") (not= name old-name))
references-count (remap/count-token-references file-data old-name)] references-count (remap/count-token-references file-data old-name)
on-remap #(on-remap-token valid-token name old-name description)
on-rename #(on-rename-token valid-token name description)]
(if (and is-rename (> references-count 0)) (if (and is-rename (> references-count 0))
(remapping-modal/show-remapping-modal (st/emit! (modal/show :tokens/remapping-confirmation {:old-token-name old-name
{:old-token-name old-name :new-token-name name
:new-token-name name :references-count references-count
:references-count references-count :on-remap on-remap
:on-confirm (fn [] :on-rename on-rename}))
(st/emit!
(dwtl/update-token (:id token)
{:name name
:value (:value valid-token)
:description description})
(remap/remap-tokens old-name name)
(dwtp/propagate-workspace-tokens)
(modal/hide!)))
:on-cancel #(modal/hide!)})
(st/emit! (st/emit!
(if is-create (if is-create
(dwtl/create-token (ctob/make-token {:name name (dwtl/create-token (ctob/make-token {:name name

View File

@@ -295,7 +295,8 @@
errors? errors?
[:> icon* [:> icon*
{:icon-id i/broken-link {:icon-id i/broken-link
:class (stl/css :token-pill-icon)}] :class (stl/css :token-pill-icon)
:aria-label (tr "workspace.tokens.missing-reference")}]
color color
[:> swatch* {:background color [:> swatch* {:background color

View File

@@ -11,22 +11,15 @@
[app.main.data.modal :as modal] [app.main.data.modal :as modal]
[app.main.store :as st] [app.main.store :as st]
[app.main.ui.ds.buttons.button :refer [button*]] [app.main.ui.ds.buttons.button :refer [button*]]
[app.main.ui.ds.buttons.icon-button :refer [icon-button*]]
[app.main.ui.ds.foundations.assets.icon :as i]
[app.main.ui.ds.foundations.typography :as t]
[app.main.ui.ds.foundations.typography.heading :refer [heading*]] [app.main.ui.ds.foundations.typography.heading :refer [heading*]]
[app.main.ui.ds.notifications.context-notification :refer [context-notification*]] [app.main.ui.ds.foundations.typography.text :refer [text*]]
[app.util.dom :as dom]
[app.util.i18n :refer [tr]] [app.util.i18n :refer [tr]]
[app.util.keyboard :as kbd]
[rumext.v2 :as mf])) [rumext.v2 :as mf]))
(defn show-remapping-modal
"Show the token remapping confirmation modal"
[{:keys [old-token-name new-token-name references-count on-confirm on-cancel]}]
(let [props {:old-token-name old-token-name
:new-token-name new-token-name
:references-count references-count
:on-confirm on-confirm
:on-cancel on-cancel}]
(st/emit! (modal/show :tokens/remapping-confirmation props))))
(defn hide-remapping-modal (defn hide-remapping-modal
"Hide the token remapping confirmation modal" "Hide the token remapping confirmation modal"
[] []
@@ -34,73 +27,73 @@
;; Remapping Modal Component ;; Remapping Modal Component
(mf/defc token-remapping-modal (mf/defc token-remapping-modal
{::mf/wrap-props false {::mf/register modal/components
::mf/register modal/components
::mf/register-as :tokens/remapping-confirmation} ::mf/register-as :tokens/remapping-confirmation}
[{:keys [old-token-name new-token-name references-count on-confirm on-cancel]}] [{:keys [old-token-name new-token-name on-remap on-rename]}]
(let [remapping-in-progress* (mf/use-state false) (let [remap-modal (get @st/state :remap-modal)
remapping-in-progress? (deref remapping-in-progress*)
;; Remap logic on confirm ;; Remap logic on confirm
on-confirm-remap confirm-remap
(mf/use-fn (mf/use-fn
(mf/deps on-confirm remapping-in-progress*) (mf/deps on-remap remap-modal)
(fn [e] (fn []
(dom/prevent-default e)
(dom/stop-propagation e)
(reset! remapping-in-progress* true)
;; Call shared remapping logic ;; Call shared remapping logic
(let [state @st/state (let [old-token-name (:old-token-name remap-modal)
remap-modal (:remap-modal state)
old-token-name (:old-token-name remap-modal)
new-token-name (:new-token-name remap-modal)] new-token-name (:new-token-name remap-modal)]
(st/emit! [:tokens/remap-tokens old-token-name new-token-name])) (st/emit! [:tokens/remap-tokens old-token-name new-token-name]))
(when (fn? on-confirm) (when (fn? on-remap)
(on-confirm)))) (on-remap))))
on-cancel-remap rename-token
(mf/use-fn (mf/use-fn
(mf/deps on-cancel) (mf/deps on-rename)
(fn [e] (fn []
(dom/prevent-default e) (when (fn? on-rename)
(dom/stop-propagation e) (on-rename))))
(modal/hide!)
(when (fn? on-cancel) cancel-action
(on-cancel))))] (mf/use-fn
(fn []
(hide-remapping-modal)))
;; Close modal on Escape key if not in progress
on-key-down
(mf/use-fn
(mf/deps cancel-action)
(fn [event]
(when (kbd/enter? event)
(cancel-action))))]
[:div {:class (stl/css :modal-overlay)
:on-key-down on-key-down
:role "alertdialog"
:aria-modal "true"
:aria-labelledby "modal-title"}
[:div {:class (stl/css :modal-overlay)}
[:div {:class (stl/css :modal-dialog) [:div {:class (stl/css :modal-dialog)
:data-testid "token-remapping-modal"} :data-testid "token-remapping-modal"}
[:> icon-button* {:on-click cancel-action
:class (stl/css :close-btn)
:icon i/close
:variant "action"
:aria-label (tr "labels.close")}]
[:div {:class (stl/css :modal-header)} [:div {:class (stl/css :modal-header)}
[:> heading* {:level 2 [:> heading* {:level 2
:typography "headline-medium" :id "modal-title"
:typography "headline-large"
:class (stl/css :modal-title)} :class (stl/css :modal-title)}
(tr "workspace.tokens.remap-token-references")]] (tr "workspace.tokens.remap-token-references-title" old-token-name new-token-name)]]
[:div {:class (stl/css :modal-content)} [:div {:class (stl/css :modal-content)}
[:> heading* {:level 3 [:> text* {:as "p" :typography t/body-medium} (tr "workspace.tokens.remap-warning-effects")]
:typography "title-medium" [:> text* {:as "p" :typography t/body-medium} (tr "workspace.tokens.remap-warning-time")]]
:class (stl/css :modal-msg)}
(tr "workspace.tokens.renaming-token-from-to" old-token-name new-token-name)]
[:div {:class (stl/css :modal-scd-msg)}
(if (> references-count 0)
(tr "workspace.tokens.references-found" references-count)
(tr "workspace.tokens.no-references-found"))]
(when remapping-in-progress?
[:> context-notification*
{:level :info
:appearance :ghost}
(tr "workspace.tokens.remapping-in-progress")])]
[:div {:class (stl/css :modal-footer)} [:div {:class (stl/css :modal-footer)}
[:div {:class (stl/css :action-buttons)} [:div {:class (stl/css :action-buttons)}
[:> button* {:on-click on-cancel-remap [:> button* {:on-click rename-token
:type "button" :type "button"
:variant "secondary" :variant "secondary"}
:disabled remapping-in-progress?} (tr "workspace.tokens.not-remap")]
(tr "labels.cancel")] [:> button* {:on-click confirm-remap
[:> button* {:on-click on-confirm-remap
:type "button" :type "button"
:variant "primary" :variant "primary"}
:disabled remapping-in-progress?} (tr "workspace.tokens.remap")]]]]]))
(if (> references-count 0)
(tr "workspace.tokens.remap-and-rename")
(tr "workspace.tokens.rename-only"))]]]]]))

View File

@@ -10,6 +10,9 @@
@use "refactor/common-refactor.scss" as deprecated; @use "refactor/common-refactor.scss" as deprecated;
.modal-overlay { .modal-overlay {
--modal-title-foreground-color: var(--color-foreground-primary);
--modal-text-foreground-color: var(--color-foreground-secondary);
@extend .modal-overlay-base; @extend .modal-overlay-base;
display: flex; display: flex;
justify-content: center; justify-content: center;
@@ -17,16 +20,22 @@
position: fixed; position: fixed;
inset-inline-start: 0; inset-inline-start: 0;
inset-block-start: 0; inset-block-start: 0;
height: 100%; block-size: 100%;
width: 100%; inline-size: 100%;
background-color: var(--overlay-color); background-color: var(--overlay-color);
} }
.close-btn {
position: absolute;
inset-block-start: $sz-6;
inset-inline-end: $sz-6;
}
.modal-dialog { .modal-dialog {
@extend .modal-container-base; @extend .modal-container-base;
width: 100%; inline-size: 100%;
max-width: 32rem; max-inline-size: 32rem;
max-height: unset; max-block-size: unset;
user-select: none; user-select: none;
position: relative; position: relative;
} }
@@ -45,11 +54,7 @@
.modal-content { .modal-content {
@include t.use-typography("body-large"); @include t.use-typography("body-large");
margin-block-end: var(--sp-xxl); color: var(--modal-text-foreground-color);
padding: var(--sp-xxl) 0;
display: flex;
flex-direction: column;
gap: var(--sp-l);
} }
.modal-footer { .modal-footer {

View File

@@ -8072,6 +8072,10 @@ msgid "workspace.tokens.missing-references"
msgstr "Missing token references: " msgstr "Missing token references: "
#: src/app/main/ui/workspace/tokens/management/token_pill.cljs:123 #: src/app/main/ui/workspace/tokens/management/token_pill.cljs:123
msgid "workspace.tokens.missing-reference"
msgstr "Missing reference"
#: src/app/main/ui/workspace/tokens/management/token_pill.cljs:299
msgid "workspace.tokens.more-options" msgid "workspace.tokens.more-options"
msgstr "Right click to see options" msgstr "Right click to see options"
@@ -8162,36 +8166,29 @@ msgstr "Enter a token shadow alias"
msgid "workspace.tokens.reference-error" msgid "workspace.tokens.reference-error"
msgstr "Reference Errors: " msgstr "Reference Errors: "
#: src/app/main/ui/workspace/tokens/remapping_modal.cljs:86 #: src/app/main/ui/workspace/tokens/remapping_modal.cljs:78
msgid "workspace.tokens.references-found" msgid "workspace.tokens.remap-token-references-title"
msgstr "%s references found in your design" msgstr "Remap all tokens that use `%s` to `%s`?"
#: src/app/main/ui/workspace/tokens/remapping_modal.cljs:105
msgid "workspace.tokens.remap-and-rename"
msgstr "Remap & Rename"
#: src/app/main/ui/workspace/tokens/remapping_modal.cljs
#, unused
msgid "workspace.tokens.remap-explanation"
msgstr ""
"All references to this token will be automatically updated to use the new "
"name."
#: src/app/main/ui/workspace/tokens/remapping_modal.cljs:78 #: src/app/main/ui/workspace/tokens/remapping_modal.cljs:78
msgid "workspace.tokens.remap-token-references" msgid "workspace.tokens.remap-warning-effects"
msgstr "Remap Token References" msgstr "This will change all layers and references that use the old token name."
#: src/app/main/ui/workspace/tokens/remapping_modal.cljs:78
msgid "workspace.tokens.remap-warning-time"
msgstr "This action could take a while."
#: src/app/main/ui/workspace/tokens/remapping_modal.cljs:92 #: src/app/main/ui/workspace/tokens/remapping_modal.cljs:92
msgid "workspace.tokens.remapping-in-progress" msgid "workspace.tokens.remapping-in-progress"
msgstr "Remapping token references..." msgstr "Remapping token references..."
#: src/app/main/ui/workspace/tokens/remapping_modal.cljs:106 #: src/app/main/ui/workspace/tokens/remapping_modal.cljs:106
msgid "workspace.tokens.rename-only" msgid "workspace.tokens.not-remap"
msgstr "Rename" msgstr "Don't remap"
#: src/app/main/ui/workspace/tokens/remapping_modal.cljs:83 #: src/app/main/ui/workspace/tokens/remapping_modal.cljs:105
msgid "workspace.tokens.renaming-token-from-to" msgid "workspace.tokens.remap"
msgstr "Renaming token from '%s' to '%s'" msgstr "Remap tokens"
#: src/app/main/data/workspace/tokens/warnings.cljs:15, src/app/main/data/workspace/tokens/warnings.cljs:19, src/app/main/ui/workspace/colorpicker/color_tokens.cljs:56, src/app/main/ui/workspace/colorpicker/color_tokens.cljs:84, src/app/main/ui/workspace/sidebar/options/rows/color_row.cljs:103, src/app/main/ui/workspace/tokens/management/forms/controls/color_input.cljs:271, src/app/main/ui/workspace/tokens/management/forms/controls/color_input.cljs:445, src/app/main/ui/workspace/tokens/management/forms/controls/fonts_combobox.cljs:169, src/app/main/ui/workspace/tokens/management/forms/controls/fonts_combobox.cljs:304, src/app/main/ui/workspace/tokens/management/forms/controls/input.cljs:225, src/app/main/ui/workspace/tokens/management/forms/controls/input.cljs:332, src/app/main/ui/workspace/tokens/management/forms/controls/input.cljs:432, src/app/main/ui/workspace/tokens/management/token_pill.cljs:121 #: src/app/main/data/workspace/tokens/warnings.cljs:15, src/app/main/data/workspace/tokens/warnings.cljs:19, src/app/main/ui/workspace/colorpicker/color_tokens.cljs:56, src/app/main/ui/workspace/colorpicker/color_tokens.cljs:84, src/app/main/ui/workspace/sidebar/options/rows/color_row.cljs:103, src/app/main/ui/workspace/tokens/management/forms/controls/color_input.cljs:271, src/app/main/ui/workspace/tokens/management/forms/controls/color_input.cljs:445, src/app/main/ui/workspace/tokens/management/forms/controls/fonts_combobox.cljs:169, src/app/main/ui/workspace/tokens/management/forms/controls/fonts_combobox.cljs:304, src/app/main/ui/workspace/tokens/management/forms/controls/input.cljs:225, src/app/main/ui/workspace/tokens/management/forms/controls/input.cljs:332, src/app/main/ui/workspace/tokens/management/forms/controls/input.cljs:432, src/app/main/ui/workspace/tokens/management/token_pill.cljs:121
#, fuzzy #, fuzzy

View File

@@ -7994,6 +7994,10 @@ msgstr "Line height (multiplicador, px o %) o {alias}"
msgid "workspace.tokens.missing-references" msgid "workspace.tokens.missing-references"
msgstr "Referencias de tokens no encontradas: " msgstr "Referencias de tokens no encontradas: "
#: src/app/main/ui/workspace/tokens/management/token_pill.cljs:123
msgid "workspace.tokens.missing-reference"
msgstr "Referencia no encontrada"
#: src/app/main/ui/workspace/tokens/management/token_pill.cljs:123 #: src/app/main/ui/workspace/tokens/management/token_pill.cljs:123
msgid "workspace.tokens.more-options" msgid "workspace.tokens.more-options"
msgstr "Click derecho para ver opciones" msgstr "Click derecho para ver opciones"
@@ -8063,36 +8067,29 @@ msgstr "La referencia no es válida o no se encuentra en ningún set activo."
msgid "workspace.tokens.reference-error" msgid "workspace.tokens.reference-error"
msgstr "Errores en referencias: " msgstr "Errores en referencias: "
#: src/app/main/ui/workspace/tokens/remapping_modal.cljs:86 #: src/app/main/ui/workspace/tokens/remapping_modal.cljs:78
msgid "workspace.tokens.references-found" msgid "workspace.tokens.remap-token-references-title"
msgstr "%s referencias encontradas en tu diseño" msgstr "¿Actualizar todas las referencias de `%s` a `%s`?"
#: src/app/main/ui/workspace/tokens/remapping_modal.cljs:105
msgid "workspace.tokens.remap-and-rename"
msgstr "Actualizar referencias y renombrar"
#: src/app/main/ui/workspace/tokens/remapping_modal.cljs
#, unused
msgid "workspace.tokens.remap-explanation"
msgstr ""
"Todas las referencias a este token se actualizarán automáticamente para "
"usar el nuevo nombre."
#: src/app/main/ui/workspace/tokens/remapping_modal.cljs:78 #: src/app/main/ui/workspace/tokens/remapping_modal.cljs:78
msgid "workspace.tokens.remap-token-references" msgid "workspace.tokens.remap-warning-effects"
msgstr "Actualizar referencias de token" msgstr "Esta acción actualizará todas las capas y referencias que usen el token antiguo"
#: src/app/main/ui/workspace/tokens/remapping_modal.cljs:78
msgid "workspace.tokens.remap-warning-time"
msgstr "Este proceso puede durar un poco"
#: src/app/main/ui/workspace/tokens/remapping_modal.cljs:92 #: src/app/main/ui/workspace/tokens/remapping_modal.cljs:92
msgid "workspace.tokens.remapping-in-progress" msgid "workspace.tokens.remapping-in-progress"
msgstr "Actualizando referencias de token..." msgstr "Actualizando referencias de token..."
#: src/app/main/ui/workspace/tokens/remapping_modal.cljs:106 #: src/app/main/ui/workspace/tokens/remapping_modal.cljs:106
msgid "workspace.tokens.rename-only" msgid "workspace.tokens.not-remap"
msgstr "Renombrar" msgstr "No actualizar"
#: src/app/main/ui/workspace/tokens/remapping_modal.cljs:83 #: src/app/main/ui/workspace/tokens/remapping_modal.cljs:105
msgid "workspace.tokens.renaming-token-from-to" msgid "workspace.tokens.remap"
msgstr "Renombrando el token de '%s' a '%s'" msgstr "Actualizar tokens"
#: src/app/main/data/workspace/tokens/warnings.cljs:15, src/app/main/data/workspace/tokens/warnings.cljs:19, src/app/main/ui/workspace/colorpicker/color_tokens.cljs:56, src/app/main/ui/workspace/colorpicker/color_tokens.cljs:84, src/app/main/ui/workspace/sidebar/options/rows/color_row.cljs:103, src/app/main/ui/workspace/tokens/management/forms/controls/color_input.cljs:271, src/app/main/ui/workspace/tokens/management/forms/controls/color_input.cljs:445, src/app/main/ui/workspace/tokens/management/forms/controls/fonts_combobox.cljs:169, src/app/main/ui/workspace/tokens/management/forms/controls/fonts_combobox.cljs:304, src/app/main/ui/workspace/tokens/management/forms/controls/input.cljs:225, src/app/main/ui/workspace/tokens/management/forms/controls/input.cljs:332, src/app/main/ui/workspace/tokens/management/forms/controls/input.cljs:432, src/app/main/ui/workspace/tokens/management/token_pill.cljs:121 #: src/app/main/data/workspace/tokens/warnings.cljs:15, src/app/main/data/workspace/tokens/warnings.cljs:19, src/app/main/ui/workspace/colorpicker/color_tokens.cljs:56, src/app/main/ui/workspace/colorpicker/color_tokens.cljs:84, src/app/main/ui/workspace/sidebar/options/rows/color_row.cljs:103, src/app/main/ui/workspace/tokens/management/forms/controls/color_input.cljs:271, src/app/main/ui/workspace/tokens/management/forms/controls/color_input.cljs:445, src/app/main/ui/workspace/tokens/management/forms/controls/fonts_combobox.cljs:169, src/app/main/ui/workspace/tokens/management/forms/controls/fonts_combobox.cljs:304, src/app/main/ui/workspace/tokens/management/forms/controls/input.cljs:225, src/app/main/ui/workspace/tokens/management/forms/controls/input.cljs:332, src/app/main/ui/workspace/tokens/management/forms/controls/input.cljs:432, src/app/main/ui/workspace/tokens/management/token_pill.cljs:121
#, fuzzy #, fuzzy