diff --git a/frontend/playwright/ui/specs/tokens/sets.spec.js b/frontend/playwright/ui/specs/tokens/sets.spec.js index 9f1f3ed3f4..7aba083163 100644 --- a/frontend/playwright/ui/specs/tokens/sets.spec.js +++ b/frontend/playwright/ui/specs/tokens/sets.spec.js @@ -186,6 +186,61 @@ test.describe("Tokens: Sets Tab", () => { await expect(darkSet).toHaveCount(0); }); + test("Folding a group after reordering collapses only that group", async ({ + page, + }) => { + const { tokenThemesSetsSidebar, tokenSetGroupItems } = + await setupTokensFileRender(page); + + // The reorder swaps two groups, so every tree index changes while the DOM + // nodes keep their positions. + await createSet(tokenThemesSetsSidebar, "Colors/primary"); + + const lightDarkGroup = tokenSetGroupItems.filter({ hasText: "LightDark" }); + const colorsGroup = tokenSetGroupItems.filter({ hasText: "Colors" }); + + await expect(tokenSetGroupItems).toHaveCount(2); + await expect(tokenSetGroupItems.first()).toContainText("LightDark"); + + // Drag the Colors group above the LightDark group. The sets list is a small + // scroll container, so both groups cannot be under the pointer at once and + // the HTML5 drag events are dispatched directly. + const target = await lightDarkGroup.boundingBox(); + const dataTransfer = await page.evaluateHandle(() => new DataTransfer()); + + await colorsGroup.dispatchEvent("dragstart", { dataTransfer }); + await lightDarkGroup.dispatchEvent("dragenter", { dataTransfer }); + await lightDarkGroup.dispatchEvent("dragover", { + dataTransfer, + clientX: target.x + 100, + clientY: target.y + 2, + }); + await lightDarkGroup.dispatchEvent("drop", { + dataTransfer, + clientX: target.x + 100, + clientY: target.y + 2, + }); + await colorsGroup.dispatchEvent("dragend", { dataTransfer }); + + await expect(tokenSetGroupItems.first()).toContainText("Colors"); + + // Folding the first group hides only its own children. + await tokenSetGroupItems + .first() + .getByTestId("tokens-set-group-collapse") + .click(); + + await expect( + tokenThemesSetsSidebar.getByRole("button", { + name: "primary", + exact: true, + }), + ).toHaveCount(0); + await expect( + tokenThemesSetsSidebar.getByRole("button", { name: "dark", exact: true }), + ).toBeVisible(); + }); + test("Change current theme", async ({ page }) => { const { tokenThemesSetsSidebar, tokenSetItems } = await setupTokensFileRender(page); diff --git a/frontend/src/app/main/ui/workspace/tokens/sets/lists.cljs b/frontend/src/app/main/ui/workspace/tokens/sets/lists.cljs index 358d611703..0ee9c45400 100644 --- a/frontend/src/app/main/ui/workspace/tokens/sets/lists.cljs +++ b/frontend/src/app/main/ui/workspace/tokens/sets/lists.cljs @@ -10,6 +10,7 @@ (:require [app.common.data.macros :as dm] [app.common.types.tokens-lib :as ctob] + [app.common.uuid :as uuid] [app.main.data.workspace.tokens.library-edit :as dwtl] [app.main.store :as st] [app.main.ui.context :as ctx] @@ -134,13 +135,16 @@ on-collapse-click (mf/use-fn + (mf/deps path on-toggle-collapse) (fn [event] (dom/prevent-default event) (dom/stop-propagation event) (on-toggle-collapse path))) on-double-click - (mf/use-fn (mf/deps id) #(on-start-edition id)) + (mf/use-fn + (mf/deps id on-start-edition) + #(on-start-edition id)) on-checkbox-click (mf/use-fn @@ -240,7 +244,7 @@ on-double-click (mf/use-fn - (mf/deps id is-new) + (mf/deps id is-new on-start-edition) (fn [] (when-not is-new (on-start-edition id)))) @@ -358,7 +362,13 @@ (fn [path] (swap! collapsed-paths* #(if (contains? % path) (disj % path) - (conj % path)))))] + (conj % path))))) + + ;; The set being created is not persisted yet, so its id is generated + ;; on every walk of the tree. Keep one for the lifetime of this + ;; creation so the node can be keyed by identity like the rest. + new-node-id + (mf/use-memo (mf/deps new-path) #(dm/str (uuid/next)))] (mf/with-effect [] (let [sub (rx/subs! (fn [paths'] @@ -378,7 +388,7 @@ (cond ^boolean is-group [:> sets-tree-set-group* - {:key index + {:key id :id id :label (peek path) :is-editing (= edition-id id) @@ -400,7 +410,7 @@ ^boolean is-new [:> sets-tree-set* - {:key index + {:key new-node-id :id id :set token-set :label "" @@ -420,7 +430,7 @@ :else [:> sets-tree-set* - {:key index + {:key id :id id :set token-set :label (peek path)