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
8 changed files with 367 additions and 432 deletions

View File

@@ -12,88 +12,118 @@ test.beforeEach(async ({ page }) => {
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("User renames box shadow token with alias references", async ({
page,
}) => {
const {
tokensUpdateCreateModal,
tokensSidebar,
tokenContextMenuForToken,
} = await setupTokensFile(page, { flags: ["enable-token-shadow"] });
const tokensTabPanel = page.getByRole("tabpanel", { name: "tokens" });
const { tokensSidebar } = await setupTokensFile(page, {
flags: ["enable-token-shadow"],
});
// Create base shadow token
await tokensTabPanel
.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();
await createToken(page, "Shadow", "base-shadow", "Color", "#000000");
// Create derived shadow token that references base-shadow
await tokensTabPanel
.getByRole("button", { name: "Add Token: Shadow" })
.click();
await expect(tokensUpdateCreateModal).toBeVisible();
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();
await createCompositeDerivedToken(
page,
"Shadow",
"derived-shadow",
"{base-shadow}",
);
// Rename base-shadow token
const baseToken = tokensSidebar.getByRole("button", {
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();
await renameToken(page, "base-shadow", "foundation-shadow");
// Check for remapping modal
const remappingModal = page.getByTestId("token-remapping-modal");
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", {
name: /remap/i,
name: "remap tokens",
});
await confirmButton.click();
@@ -116,51 +146,16 @@ test.describe("Tokens: Remapping Feature", () => {
workspacePage,
} = await setupTokensFile(page, { flags: ["enable-token-shadow"] });
const tokensTabPanel = page.getByRole("tabpanel", { name: "tokens" });
// Create base shadow token
await tokensTabPanel
.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();
await createToken(page, "Shadow", "primary-shadow", "Color", "#000000");
// Create derived shadow token that references base
await tokensTabPanel
.getByRole("button", { name: "Add Token: Shadow" })
.click();
await expect(tokensUpdateCreateModal).toBeVisible();
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();
await createCompositeDerivedToken(
page,
"Shadow",
"card-shadow",
"{primary-shadow}",
);
// Apply the referenced token to a shape
await page.getByRole("tab", { name: "Layers" }).click();
@@ -183,16 +178,16 @@ test.describe("Tokens: Remapping Feature", () => {
await tokenContextMenuForToken.getByText("Edit token").click();
await expect(tokensUpdateCreateModal).toBeVisible();
nameField = tokensUpdateCreateModal.getByLabel("Name");
const nameField = tokensUpdateCreateModal.getByLabel("Name");
await nameField.fill("main-shadow");
// Update the color value
colorField = tokensUpdateCreateModal.getByRole("textbox", {
const colorField = tokensUpdateCreateModal.getByRole("textbox", {
name: "Color",
});
await colorField.fill("#FF0000");
submitButton = tokensUpdateCreateModal.getByRole("button", {
const submitButton = tokensUpdateCreateModal.getByRole("button", {
name: "Save",
});
await submitButton.click();
@@ -202,7 +197,7 @@ test.describe("Tokens: Remapping Feature", () => {
await expect(remappingModal).toBeVisible({ timeout: 5000 });
const confirmButton = remappingModal.getByRole("button", {
name: /remap/i,
name: "remap tokens",
});
await confirmButton.click();
@@ -259,73 +254,25 @@ test.describe("Tokens: Remapping Feature", () => {
const tokensTabPanel = page.getByRole("tabpanel", { name: "tokens" });
// Create base typography token
await tokensTabPanel
.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();
await createToken(page, "Typography", "base-text", "Font size", "16");
// Create derived typography token
await tokensTabPanel
.getByRole("button", { name: "Add Token: Typography" })
.click();
await expect(tokensUpdateCreateModal).toBeVisible();
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();
await createCompositeDerivedToken(
page,
"Typography",
"body-text",
"{base-text}",
);
// Rename base token
const baseToken = tokensSidebar.getByRole("button", {
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();
await renameToken(page, "base-text", "default-text");
// Check for remapping modal
const remappingModal = page.getByTestId("token-remapping-modal");
await expect(remappingModal).toBeVisible({ timeout: 5000 });
const confirmButton = remappingModal.getByRole("button", {
name: /remap/i,
name: "remap tokens",
});
await confirmButton.click();
@@ -351,24 +298,7 @@ test.describe("Tokens: Remapping Feature", () => {
const tokensTabPanel = page.getByRole("tabpanel", { name: "tokens" });
// Create base typography token
await tokensTabPanel
.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();
await createToken(page, "Typography", "body-style", "Font size", "16");
// Create derived typography token
await tokensTabPanel
@@ -376,7 +306,7 @@ test.describe("Tokens: Remapping Feature", () => {
.click();
await expect(tokensUpdateCreateModal).toBeVisible();
nameField = tokensUpdateCreateModal.getByRole("textbox", {
let nameField = tokensUpdateCreateModal.getByRole("textbox", {
name: "Name",
});
await nameField.fill("paragraph-style");
@@ -390,7 +320,7 @@ test.describe("Tokens: Remapping Feature", () => {
});
await referenceField.fill("{body-style}");
submitButton = tokensUpdateCreateModal.getByRole("button", {
let submitButton = tokensUpdateCreateModal.getByRole("button", {
name: "Save",
});
await submitButton.click();
@@ -421,7 +351,7 @@ test.describe("Tokens: Remapping Feature", () => {
await nameField.fill("text-base");
// Update the font size value
fontSizeField = tokensUpdateCreateModal.getByRole("textbox", {
const fontSizeField = tokensUpdateCreateModal.getByRole("textbox", {
name: "Font size",
});
await fontSizeField.fill("18");
@@ -436,7 +366,7 @@ test.describe("Tokens: Remapping Feature", () => {
await expect(remappingModal).toBeVisible({ timeout: 5000 });
const confirmButton = remappingModal.getByRole("button", {
name: /remap/i,
name: "remap tokens",
});
await confirmButton.click();
@@ -471,72 +401,29 @@ test.describe("Tokens: Remapping Feature", () => {
test("User renames border radius token with alias references", async ({
page,
}) => {
const {
tokensUpdateCreateModal,
tokensSidebar,
tokenContextMenuForToken,
} = await setupTokensFile(page);
const tokensTabPanel = page.getByRole("tabpanel", { name: "tokens" });
const { tokensSidebar } = await setupTokensFile(page);
// Create base border radius token
await tokensTabPanel
.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();
await createToken(page, "Border Radius", "base-radius", "Value", "4");
// Create derived border radius token
await tokensTabPanel
.getByRole("button", { name: "Add Token: Border Radius" })
.click();
await expect(tokensUpdateCreateModal).toBeVisible();
nameField = tokensUpdateCreateModal.getByLabel("Name");
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();
await createToken(
page,
"Border Radius",
"card-radius",
"Value",
"{base-radius}",
);
// Rename base token
const baseToken = tokensSidebar.getByRole("button", {
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();
await renameToken(page, "base-radius", "primary-radius");
// Check for remapping modal
const remappingModal = page.getByTestId("token-remapping-modal");
await expect(remappingModal).toBeVisible({ timeout: 5000 });
const confirmButton = remappingModal.getByRole("button", {
name: /remap/i,
name: "remap tokens",
});
await confirmButton.click();
@@ -558,43 +445,17 @@ test.describe("Tokens: Remapping Feature", () => {
tokenContextMenuForToken,
} = await setupTokensFile(page);
const tokensTabPanel = page.getByRole("tabpanel", { name: "tokens" });
// Create base border radius token
await tokensTabPanel
.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();
await createToken(page, "Border Radius", "radius-sm", "Value", "4");
// Create derived border radius token
await tokensTabPanel
.getByRole("button", { name: "Add Token: Border Radius" })
.click();
await expect(tokensUpdateCreateModal).toBeVisible();
nameField = tokensUpdateCreateModal.getByLabel("Name");
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();
await createToken(
page,
"Border Radius",
"button-radius",
"Value",
"{radius-sm}",
);
// Rename and update value of base token
const radiusToken = tokensSidebar.getByRole("button", {
@@ -604,14 +465,14 @@ test.describe("Tokens: Remapping Feature", () => {
await tokenContextMenuForToken.getByText("Edit token").click();
await expect(tokensUpdateCreateModal).toBeVisible();
nameField = tokensUpdateCreateModal.getByLabel("Name");
const nameField = tokensUpdateCreateModal.getByLabel("Name");
await nameField.fill("radius-base");
// Update the value
valueField = tokensUpdateCreateModal.getByLabel("Value");
const valueField = tokensUpdateCreateModal.getByLabel("Value");
await valueField.fill("8");
submitButton = tokensUpdateCreateModal.getByRole("button", {
const submitButton = tokensUpdateCreateModal.getByRole("button", {
name: "Save",
});
await submitButton.click();
@@ -621,7 +482,7 @@ test.describe("Tokens: Remapping Feature", () => {
await expect(remappingModal).toBeVisible({ timeout: 5000 });
const confirmButton = remappingModal.getByRole("button", {
name: /remap/i,
name: "remap tokens",
});
await confirmButton.click();
@@ -648,4 +509,82 @@ test.describe("Tokens: Remapping Feature", () => {
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

@@ -433,18 +433,11 @@
ptk/WatchEvent
(watch [it state _]
(let [data (dsh/lookup-file-data state)
token-set (if set-id
(lookup-token-set state set-id)
(lookup-token-set state))
token (-> (get-tokens-lib state)
(ctob/get-token (ctob/get-id token-set) token-id))
token-type (:type token)
changes (-> (pcb/empty-changes it)
(pcb/with-library-data data)
(pcb/set-token set-id token-id nil))]
(rx/of (dch/commit-changes changes)
(ptk/data-event ::ev/event {::ev/name "delete-token" :type token-type}))))))
(rx/of (dch/commit-changes changes))))))
(defn bulk-delete-tokens
[set-id token-ids]
@@ -452,15 +445,9 @@
(dm/assert! (every? uuid? token-ids))
(ptk/reify ::bulk-delete-tokens
ptk/WatchEvent
(watch [it state _]
(let [data (dsh/lookup-file-data state)
changes (reduce (fn [changes token-id]
(pcb/set-token changes set-id token-id nil))
(-> (pcb/empty-changes it)
(pcb/with-library-data data))
token-ids)]
(rx/of (dch/commit-changes changes)
(ptk/data-event ::ev/event {::ev/name "delete-token-node"}))))))
(watch [_ _ _]
(apply rx/of
(map #(delete-token set-id %) token-ids)))))
(defn duplicate-token
[token-id]

View File

@@ -28,7 +28,6 @@
[app.main.ui.forms :as fc]
[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.remapping-modal :as remapping-modal]
[app.util.dom :as dom]
[app.util.forms :as fm]
[app.util.i18n :refer [tr]]
@@ -182,9 +181,33 @@
(when (or (k/enter? e) (k/space? 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
(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]
(let [name (get-in @form [:clean-data :name])
path (str (d/name token-type) "." name)
@@ -202,22 +225,15 @@
file-data (dh/lookup-file-data state)
old-name (:name token)
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))
(remapping-modal/show-remapping-modal
{:old-token-name old-name
:new-token-name name
:references-count references-count
:on-confirm (fn []
(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! (modal/show :tokens/remapping-confirmation {:old-token-name old-name
:new-token-name name
:references-count references-count
:on-remap on-remap
:on-rename on-rename}))
(st/emit!
(if is-create
(dwtl/create-token (ctob/make-token {:name name

View File

@@ -295,7 +295,8 @@
errors?
[:> icon*
{: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
[:> swatch* {:background color

View File

@@ -11,22 +11,15 @@
[app.main.data.modal :as modal]
[app.main.store :as st]
[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.notifications.context-notification :refer [context-notification*]]
[app.util.dom :as dom]
[app.main.ui.ds.foundations.typography.text :refer [text*]]
[app.util.i18n :refer [tr]]
[app.util.keyboard :as kbd]
[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
"Hide the token remapping confirmation modal"
[]
@@ -34,73 +27,73 @@
;; Remapping Modal Component
(mf/defc token-remapping-modal
{::mf/wrap-props false
::mf/register modal/components
{::mf/register modal/components
::mf/register-as :tokens/remapping-confirmation}
[{:keys [old-token-name new-token-name references-count on-confirm on-cancel]}]
(let [remapping-in-progress* (mf/use-state false)
remapping-in-progress? (deref remapping-in-progress*)
[{:keys [old-token-name new-token-name on-remap on-rename]}]
(let [remap-modal (get @st/state :remap-modal)
;; Remap logic on confirm
on-confirm-remap
confirm-remap
(mf/use-fn
(mf/deps on-confirm remapping-in-progress*)
(fn [e]
(dom/prevent-default e)
(dom/stop-propagation e)
(reset! remapping-in-progress* true)
(mf/deps on-remap remap-modal)
(fn []
;; Call shared remapping logic
(let [state @st/state
remap-modal (:remap-modal state)
old-token-name (:old-token-name remap-modal)
(let [old-token-name (:old-token-name remap-modal)
new-token-name (:new-token-name remap-modal)]
(st/emit! [:tokens/remap-tokens old-token-name new-token-name]))
(when (fn? on-confirm)
(on-confirm))))
(when (fn? on-remap)
(on-remap))))
on-cancel-remap
rename-token
(mf/use-fn
(mf/deps on-cancel)
(fn [e]
(dom/prevent-default e)
(dom/stop-propagation e)
(modal/hide!)
(when (fn? on-cancel)
(on-cancel))))]
(mf/deps on-rename)
(fn []
(when (fn? on-rename)
(on-rename))))
cancel-action
(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)
: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)}
[:> heading* {:level 2
:typography "headline-medium"
:id "modal-title"
:typography "headline-large"
: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)}
[:> heading* {:level 3
:typography "title-medium"
: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")])]
[:> text* {:as "p" :typography t/body-medium} (tr "workspace.tokens.remap-warning-effects")]
[:> text* {:as "p" :typography t/body-medium} (tr "workspace.tokens.remap-warning-time")]]
[:div {:class (stl/css :modal-footer)}
[:div {:class (stl/css :action-buttons)}
[:> button* {:on-click on-cancel-remap
[:> button* {:on-click rename-token
:type "button"
:variant "secondary"
:disabled remapping-in-progress?}
(tr "labels.cancel")]
[:> button* {:on-click on-confirm-remap
:variant "secondary"}
(tr "workspace.tokens.not-remap")]
[:> button* {:on-click confirm-remap
:type "button"
:variant "primary"
:disabled remapping-in-progress?}
(if (> references-count 0)
(tr "workspace.tokens.remap-and-rename")
(tr "workspace.tokens.rename-only"))]]]]]))
:variant "primary"}
(tr "workspace.tokens.remap")]]]]]))

View File

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

View File

@@ -8072,6 +8072,10 @@ msgid "workspace.tokens.missing-references"
msgstr "Missing token references: "
#: 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"
msgstr "Right click to see options"
@@ -8162,36 +8166,29 @@ msgstr "Enter a token shadow alias"
msgid "workspace.tokens.reference-error"
msgstr "Reference Errors: "
#: src/app/main/ui/workspace/tokens/remapping_modal.cljs:86
msgid "workspace.tokens.references-found"
msgstr "%s references found in your design"
#: 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
msgid "workspace.tokens.remap-token-references-title"
msgstr "Remap all tokens that use `%s` to `%s`?"
#: src/app/main/ui/workspace/tokens/remapping_modal.cljs:78
msgid "workspace.tokens.remap-token-references"
msgstr "Remap Token References"
msgid "workspace.tokens.remap-warning-effects"
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
msgid "workspace.tokens.remapping-in-progress"
msgstr "Remapping token references..."
#: src/app/main/ui/workspace/tokens/remapping_modal.cljs:106
msgid "workspace.tokens.rename-only"
msgstr "Rename"
msgid "workspace.tokens.not-remap"
msgstr "Don't remap"
#: src/app/main/ui/workspace/tokens/remapping_modal.cljs:83
msgid "workspace.tokens.renaming-token-from-to"
msgstr "Renaming token from '%s' to '%s'"
#: src/app/main/ui/workspace/tokens/remapping_modal.cljs:105
msgid "workspace.tokens.remap"
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
#, fuzzy

View File

@@ -7994,6 +7994,10 @@ msgstr "Line height (multiplicador, px o %) o {alias}"
msgid "workspace.tokens.missing-references"
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
msgid "workspace.tokens.more-options"
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"
msgstr "Errores en referencias: "
#: src/app/main/ui/workspace/tokens/remapping_modal.cljs:86
msgid "workspace.tokens.references-found"
msgstr "%s referencias encontradas en tu diseño"
#: 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
msgid "workspace.tokens.remap-token-references-title"
msgstr "¿Actualizar todas las referencias de `%s` a `%s`?"
#: src/app/main/ui/workspace/tokens/remapping_modal.cljs:78
msgid "workspace.tokens.remap-token-references"
msgstr "Actualizar referencias de token"
msgid "workspace.tokens.remap-warning-effects"
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
msgid "workspace.tokens.remapping-in-progress"
msgstr "Actualizando referencias de token..."
#: src/app/main/ui/workspace/tokens/remapping_modal.cljs:106
msgid "workspace.tokens.rename-only"
msgstr "Renombrar"
msgid "workspace.tokens.not-remap"
msgstr "No actualizar"
#: src/app/main/ui/workspace/tokens/remapping_modal.cljs:83
msgid "workspace.tokens.renaming-token-from-to"
msgstr "Renombrando el token de '%s' a '%s'"
#: src/app/main/ui/workspace/tokens/remapping_modal.cljs:105
msgid "workspace.tokens.remap"
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
#, fuzzy