From 6d1ff0cb497325b2c890e0322f46f5cf64cc2651 Mon Sep 17 00:00:00 2001 From: Andrey Antukh Date: Tue, 4 Feb 2025 12:40:28 +0100 Subject: [PATCH 01/25] :fire: Remove unused and incorrect ref passed to dropdown component --- frontend/src/app/main/ui/workspace/tokens/theme_select.cljs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/frontend/src/app/main/ui/workspace/tokens/theme_select.cljs b/frontend/src/app/main/ui/workspace/tokens/theme_select.cljs index 397bbb70b..f62ebadfa 100644 --- a/frontend/src/app/main/ui/workspace/tokens/theme_select.cljs +++ b/frontend/src/app/main/ui/workspace/tokens/theme_select.cljs @@ -95,7 +95,6 @@ is-open? (:is-open? state) ;; Dropdown - dropdown-element* (mf/use-ref nil) on-close-dropdown (mf/use-fn #(swap! state* assoc :is-open? false)) on-open-dropdown @@ -118,8 +117,7 @@ current-label] [:> icon* {:icon-id i/arrow-down :class (stl/css :dropdown-button) :aria-hidden true}] [:& dropdown {:show is-open? - :on-close on-close-dropdown - :ref dropdown-element*} + :on-close on-close-dropdown} [:& theme-options {:active-theme-paths active-theme-paths :themes themes :on-close on-close-dropdown}]]])) From f4dee75a173152f766e1f894aa15f5090b531221 Mon Sep 17 00:00:00 2001 From: Andrey Antukh Date: Tue, 4 Feb 2025 14:29:26 +0100 Subject: [PATCH 02/25] :fire: Remove unused workspace tokens common ns file --- frontend/src/app/main/data/workspace/tokens/common.cljs | 8 -------- .../src/app/main/data/workspace/tokens/selected_set.cljs | 8 +++++--- 2 files changed, 5 insertions(+), 11 deletions(-) delete mode 100644 frontend/src/app/main/data/workspace/tokens/common.cljs diff --git a/frontend/src/app/main/data/workspace/tokens/common.cljs b/frontend/src/app/main/data/workspace/tokens/common.cljs deleted file mode 100644 index 7cb07aeae..000000000 --- a/frontend/src/app/main/data/workspace/tokens/common.cljs +++ /dev/null @@ -1,8 +0,0 @@ -(ns app.main.data.workspace.tokens.common - (:require - [app.main.data.helpers :as dsh])) - -(defn get-workspace-tokens-lib - [state] - (-> (dsh/lookup-file-data state) - (get :tokens-lib))) diff --git a/frontend/src/app/main/data/workspace/tokens/selected_set.cljs b/frontend/src/app/main/data/workspace/tokens/selected_set.cljs index ece47fca0..4ecd79eca 100644 --- a/frontend/src/app/main/data/workspace/tokens/selected_set.cljs +++ b/frontend/src/app/main/data/workspace/tokens/selected_set.cljs @@ -3,7 +3,7 @@ Will default to the first set." (:require [app.common.types.tokens-lib :as ctob] - [app.main.data.workspace.tokens.common :as dwtc] + [app.main.data.helpers :as dsh] [potok.v2.core :as ptk])) (defn assoc-selected-token-set-name [state set-name] @@ -11,14 +11,16 @@ (defn get-selected-token-set-name [state] (or (get-in state [:workspace-local :selected-token-set-name]) - (some-> (dwtc/get-workspace-tokens-lib state) + (some-> (dsh/lookup-file-data state) + (get :tokens-lib) (ctob/get-sets) (first) :name))) (defn get-selected-token-set [state] (when-let [set-name (get-selected-token-set-name state)] - (some-> (dwtc/get-workspace-tokens-lib state) + (some-> (dsh/lookup-file-data state) + (get :tokens-lib) (ctob/get-set set-name)))) (defn get-selected-token-set-token [state token-name] From e46fb9dba736cbe382eb3801cfaef1398f18d81d Mon Sep 17 00:00:00 2001 From: Andrey Antukh Date: Tue, 4 Feb 2025 14:30:00 +0100 Subject: [PATCH 03/25] :paperclip: Add missing copyright header --- .../src/app/main/data/workspace/tokens/selected_set.cljs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/frontend/src/app/main/data/workspace/tokens/selected_set.cljs b/frontend/src/app/main/data/workspace/tokens/selected_set.cljs index 4ecd79eca..676bd0453 100644 --- a/frontend/src/app/main/data/workspace/tokens/selected_set.cljs +++ b/frontend/src/app/main/data/workspace/tokens/selected_set.cljs @@ -1,3 +1,9 @@ +;; This Source Code Form is subject to the terms of the Mozilla Public +;; License, v. 2.0. If a copy of the MPL was not distributed with this +;; file, You can obtain one at http://mozilla.org/MPL/2.0/. +;; +;; Copyright (c) KALEIDOS INC + (ns app.main.data.workspace.tokens.selected-set "The user selected token set in the ui, stored by the `:name` of the set. Will default to the first set." From 7e0b2702deb425371986d18089518acedad064b9 Mon Sep 17 00:00:00 2001 From: Andrey Antukh Date: Tue, 4 Feb 2025 14:31:55 +0100 Subject: [PATCH 04/25] :lipstick: Add minor cosmetic changes --- .../src/app/main/data/workspace/tokens/selected_set.cljs | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/frontend/src/app/main/data/workspace/tokens/selected_set.cljs b/frontend/src/app/main/data/workspace/tokens/selected_set.cljs index 676bd0453..748a8acee 100644 --- a/frontend/src/app/main/data/workspace/tokens/selected_set.cljs +++ b/frontend/src/app/main/data/workspace/tokens/selected_set.cljs @@ -12,9 +12,6 @@ [app.main.data.helpers :as dsh] [potok.v2.core :as ptk])) -(defn assoc-selected-token-set-name [state set-name] - (assoc-in state [:workspace-local :selected-token-set-name] set-name)) - (defn get-selected-token-set-name [state] (or (get-in state [:workspace-local :selected-token-set-name]) (some-> (dsh/lookup-file-data state) @@ -38,8 +35,8 @@ :tokens)) (defn set-selected-token-set-name - [set-name] + [name] (ptk/reify ::set-selected-token-set-path-from-name ptk/UpdateEvent (update [_ state] - (assoc-selected-token-set-name state set-name)))) + (update state :workspace-local assoc :selected-token-set-name name)))) From b6e26d15e1da6a1f717ce5e6fe85107d29a80ea9 Mon Sep 17 00:00:00 2001 From: Andrey Antukh Date: Tue, 4 Feb 2025 18:03:37 +0100 Subject: [PATCH 05/25] :lipstick: Add cosmetic changes to tokens sidebar component --- .../src/app/main/ui/workspace/sidebar.cljs | 4 +- .../app/main/ui/workspace/tokens/sidebar.cljs | 40 +++++++++++-------- .../ui/workspace/tokens/style_dictionary.cljs | 4 +- 3 files changed, 28 insertions(+), 20 deletions(-) diff --git a/frontend/src/app/main/ui/workspace/sidebar.cljs b/frontend/src/app/main/ui/workspace/sidebar.cljs index f28f04ac2..5b2222f44 100644 --- a/frontend/src/app/main/ui/workspace/sidebar.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar.cljs @@ -31,7 +31,7 @@ [app.main.ui.workspace.sidebar.shortcuts :refer [shortcuts-container]] [app.main.ui.workspace.sidebar.sitemap :refer [sitemap]] [app.main.ui.workspace.sidebar.versions :refer [versions-toolbox*]] - [app.main.ui.workspace.tokens.sidebar :refer [tokens-sidebar-tab]] + [app.main.ui.workspace.tokens.sidebar :refer [tokens-sidebar-tab*]] [app.util.debug :as dbg] [app.util.i18n :refer [tr]] [potok.v2.core :as ptk] @@ -120,7 +120,7 @@ tokens-tab (when design-tokens? - (mf/html [:& tokens-sidebar-tab])) + (mf/html [:> tokens-sidebar-tab*])) tabs (if ^boolean mode-inspect? diff --git a/frontend/src/app/main/ui/workspace/tokens/sidebar.cljs b/frontend/src/app/main/ui/workspace/tokens/sidebar.cljs index 86e6157b9..4f8fd62a4 100644 --- a/frontend/src/app/main/ui/workspace/tokens/sidebar.cljs +++ b/frontend/src/app/main/ui/workspace/tokens/sidebar.cljs @@ -254,24 +254,31 @@ :style "header"}])]] [:& theme-sets-list {:on-open on-open}]]]])) -(mf/defc tokens-tab - [_props] - (let [objects (mf/deref refs/workspace-page-objects) +(mf/defc tokens-tab* + [] + (let [objects (mf/deref refs/workspace-page-objects) + selected (mf/deref refs/selected-shapes) - selected (mf/deref refs/selected-shapes) - selected-shapes (into [] (keep (d/getf objects)) selected) + selected-shapes + (mf/with-memo [selected objects] + (into [] (keep (d/getf objects)) selected)) - active-theme-tokens (sd/use-active-theme-sets-tokens) + active-theme-tokens + (sd/use-active-theme-tokens) - tokens (sd/use-resolved-workspace-tokens) + tokens + (sd/use-resolved-workspace-tokens) - selected-token-set-tokens (mf/deref refs/workspace-selected-token-set-tokens) + selected-token-set-tokens + (mf/deref refs/workspace-selected-token-set-tokens) - selected-token-set-name (mf/deref refs/workspace-selected-token-set-name) + selected-token-set-name + (mf/deref refs/workspace-selected-token-set-name) - token-groups (mf/with-memo [tokens selected-token-set-tokens] - (-> (select-keys tokens (keys selected-token-set-tokens)) - (sorted-token-groups)))] + token-groups + (mf/with-memo [tokens selected-token-set-tokens] + (-> (select-keys tokens (keys selected-token-set-tokens)) + (sorted-token-groups)))] [:* [:& token-context-menu] [:& title-bar {:all-clickable true @@ -357,10 +364,9 @@ :on-click on-export} (tr "labels.export")]]])) -(mf/defc tokens-sidebar-tab - {::mf/wrap [mf/memo] - ::mf/wrap-props false} - [_props] +(mf/defc tokens-sidebar-tab* + {::mf/wrap [mf/memo]} + [] (let [{on-pointer-down-pages :on-pointer-down on-lost-pointer-capture-pages :on-lost-pointer-capture on-pointer-move-pages :on-pointer-move @@ -374,5 +380,5 @@ :on-pointer-down on-pointer-down-pages :on-lost-pointer-capture on-lost-pointer-capture-pages :on-pointer-move on-pointer-move-pages}] - [:& tokens-tab]] + [:> tokens-tab*]] [:& import-export-button]])) diff --git a/frontend/src/app/main/ui/workspace/tokens/style_dictionary.cljs b/frontend/src/app/main/ui/workspace/tokens/style_dictionary.cljs index 2a1618e19..28d72e34e 100644 --- a/frontend/src/app/main/ui/workspace/tokens/style_dictionary.cljs +++ b/frontend/src/app/main/ui/workspace/tokens/style_dictionary.cljs @@ -295,6 +295,8 @@ prefer-selected-token-set-tokens (merge active-theme-tokens selected-token-set-tokens)] (use-resolved-tokens prefer-selected-token-set-tokens))) -(defn use-active-theme-sets-tokens [] +(defn use-active-theme-tokens + "A hook that returns active tokens for the current active theme" + [] (-> (mf/deref refs/workspace-active-theme-sets-tokens) (use-resolved-tokens {:cache-atom !theme-tokens-cache}))) From 0fee8143dd918e869fcb7a293b46b04b270c8d3d Mon Sep 17 00:00:00 2001 From: Andrey Antukh Date: Tue, 4 Feb 2025 16:46:09 +0100 Subject: [PATCH 06/25] :zap: Don't use seq operations for string includes operation --- frontend/src/app/main/ui/workspace/tokens/token_pill.cljs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/frontend/src/app/main/ui/workspace/tokens/token_pill.cljs b/frontend/src/app/main/ui/workspace/tokens/token_pill.cljs index 209aaed62..fb356f58a 100644 --- a/frontend/src/app/main/ui/workspace/tokens/token_pill.cljs +++ b/frontend/src/app/main/ui/workspace/tokens/token_pill.cljs @@ -144,11 +144,13 @@ {::mf/wrap-props false} [{:keys [on-click token theme-token full-applied on-context-menu half-applied selected-shapes token-type-props active-theme-tokens]}] (let [{:keys [name value errors]} token - is-reference (some #(= % "{") value) + + is-reference? (str/includes? value "{") + can-edit? (:can-edit (deref refs/permissions)) is-viewer (not can-edit?) - ref-not-in-active-set (and is-reference + ref-not-in-active-set (and is-reference? (not (contains-reference-value? value (keys active-theme-tokens)))) no-valid-value (seq errors) errors? (or ref-not-in-active-set From 5575a66b8dcd8c929b2606574c29218a284d3407 Mon Sep 17 00:00:00 2001 From: Andrey Antukh Date: Tue, 4 Feb 2025 16:54:04 +0100 Subject: [PATCH 07/25] :paperclip: Add many FIXME comments on token-pill component --- frontend/src/app/main/refs.cljs | 1 + .../app/main/ui/workspace/tokens/sidebar.cljs | 1 + .../main/ui/workspace/tokens/token_pill.cljs | 22 ++++++++++++++----- 3 files changed, 19 insertions(+), 5 deletions(-) diff --git a/frontend/src/app/main/refs.cljs b/frontend/src/app/main/refs.cljs index b0e5c1642..1dc8cf419 100644 --- a/frontend/src/app/main/refs.cljs +++ b/frontend/src/app/main/refs.cljs @@ -479,6 +479,7 @@ (def workspace-active-set-names (l/derived (d/nilf ctob/get-active-themes-set-names) tokens-lib)) +;; FIXME: deprecated, it should not be implemented with ref (def workspace-active-theme-sets-tokens (l/derived #(or (some-> % ctob/get-active-themes-set-tokens) {}) tokens-lib)) diff --git a/frontend/src/app/main/ui/workspace/tokens/sidebar.cljs b/frontend/src/app/main/ui/workspace/tokens/sidebar.cljs index 4f8fd62a4..9c18e15cd 100644 --- a/frontend/src/app/main/ui/workspace/tokens/sidebar.cljs +++ b/frontend/src/app/main/ui/workspace/tokens/sidebar.cljs @@ -116,6 +116,7 @@ :token-type-props token-type-props}))))) tokens-count (count tokens) can-edit? (:can-edit (deref refs/permissions))] + [:div {:on-click on-toggle-open-click} [:& cmm/asset-section {:icon (token-section-icon type) :title title diff --git a/frontend/src/app/main/ui/workspace/tokens/token_pill.cljs b/frontend/src/app/main/ui/workspace/tokens/token_pill.cljs index fb356f58a..2d0dc0927 100644 --- a/frontend/src/app/main/ui/workspace/tokens/token_pill.cljs +++ b/frontend/src/app/main/ui/workspace/tokens/token_pill.cljs @@ -134,6 +134,8 @@ ;; Otherwise only show the base title :else base-title))) +;; FIXME: the token thould already have precalculated references, so +;; we don't need to perform this regex operation on each rerender (defn contains-reference-value? "Extracts the value between `{}` in a string and checks if it's in the provided vector." [text values] @@ -145,24 +147,32 @@ [{:keys [on-click token theme-token full-applied on-context-menu half-applied selected-shapes token-type-props active-theme-tokens]}] (let [{:keys [name value errors]} token - is-reference? (str/includes? value "{") + is-reference? (str/includes? value "{") + contains-path? (str/includes? name ".") + + ;; FIXME: move to context or props can-edit? (:can-edit (deref refs/permissions)) is-viewer (not can-edit?) ref-not-in-active-set (and is-reference? (not (contains-reference-value? value (keys active-theme-tokens)))) + no-valid-value (seq errors) errors? (or ref-not-in-active-set no-valid-value) + + ;; FIXME: :zap: this performs a duplicate operation for + ;; nothing, this generates a lot of garbage objects for + ;; finally not using them color (when (seq (ctob/find-token-value-references value)) (wtt/resolved-token-bullet-color theme-token)) - contains-path? (str/includes? name ".") + splitted-name (cfh/split-by-last-period name) color (or color (wtt/resolved-token-bullet-color token)) on-click - (mf/use-callback + (mf/use-fn (mf/deps errors? on-click) (fn [event] (dom/stop-propagation event) @@ -198,7 +208,9 @@ (mf/deps selected-shapes is-viewer) (fn [event] (let [node (dom/get-current-target event) - title (token-pill-tooltip is-viewer (first selected-shapes) token-type-props token half-applied no-valid-value ref-not-in-active-set)] + title (token-pill-tooltip is-viewer (first selected-shapes) + token-type-props token + half-applied no-valid-value ref-not-in-active-set)] (dom/set-attribute! node "title" title))))] [:button {:class (stl/css-case :token-pill true @@ -238,4 +250,4 @@ (last splitted-name)]] [:span {:class (stl/css :name-wrapper) :aria-label name} - name])])) \ No newline at end of file + name])])) From bccc90f5a23b8edf8d5c54bb7cd30d0cb6bdd5a3 Mon Sep 17 00:00:00 2001 From: Andrey Antukh Date: Tue, 4 Feb 2025 16:57:11 +0100 Subject: [PATCH 08/25] :zap: Don't create keys seq on each rerender on token-pill component --- frontend/src/app/main/ui/workspace/tokens/token_pill.cljs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/frontend/src/app/main/ui/workspace/tokens/token_pill.cljs b/frontend/src/app/main/ui/workspace/tokens/token_pill.cljs index 2d0dc0927..395291c85 100644 --- a/frontend/src/app/main/ui/workspace/tokens/token_pill.cljs +++ b/frontend/src/app/main/ui/workspace/tokens/token_pill.cljs @@ -138,9 +138,9 @@ ;; we don't need to perform this regex operation on each rerender (defn contains-reference-value? "Extracts the value between `{}` in a string and checks if it's in the provided vector." - [text values] + [text active-tokens] (let [match (second (re-find #"\{([^}]+)\}" text))] - (boolean (some #(= % match) values)))) + (contains? active-tokens match))) (mf/defc token-pill {::mf/wrap-props false} @@ -156,7 +156,7 @@ is-viewer (not can-edit?) ref-not-in-active-set (and is-reference? - (not (contains-reference-value? value (keys active-theme-tokens)))) + (not (contains-reference-value? value active-theme-tokens))) no-valid-value (seq errors) errors? (or ref-not-in-active-set From 333cc5996c6badfa29dc30759b5775503803926a Mon Sep 17 00:00:00 2001 From: Andrey Antukh Date: Tue, 4 Feb 2025 18:47:26 +0100 Subject: [PATCH 09/25] :lipstick: Add mainly cosmetic changes to tokens pill Simplify the component logic removing duplicate token prop handling --- .../app/main/ui/workspace/tokens/sidebar.cljs | 7 +- .../app/main/ui/workspace/tokens/token.cljs | 5 ++ .../main/ui/workspace/tokens/token_pill.cljs | 90 +++++++++---------- 3 files changed, 52 insertions(+), 50 deletions(-) diff --git a/frontend/src/app/main/ui/workspace/tokens/sidebar.cljs b/frontend/src/app/main/ui/workspace/tokens/sidebar.cljs index 9c18e15cd..3f9b5a207 100644 --- a/frontend/src/app/main/ui/workspace/tokens/sidebar.cljs +++ b/frontend/src/app/main/ui/workspace/tokens/sidebar.cljs @@ -33,7 +33,7 @@ [app.main.ui.workspace.tokens.style-dictionary :as sd] [app.main.ui.workspace.tokens.theme-select :refer [theme-select]] [app.main.ui.workspace.tokens.token :as wtt] - [app.main.ui.workspace.tokens.token-pill :refer [token-pill]] + [app.main.ui.workspace.tokens.token-pill :refer [token-pill*]] [app.main.ui.workspace.tokens.token-types :as wtty] [app.util.dom :as dom] [app.util.i18n :refer [tr]] @@ -140,13 +140,12 @@ on-token-click (fn [e] (on-token-pill-click e token)) on-context-menu (fn [e] (on-context-menu e token))] - [:& token-pill + [:> token-pill* {:key (:name token) :token-type-props token-type-props - :token token + :token (d/nilv theme-token token) :selected-shapes selected-shapes :active-theme-tokens active-theme-tokens - :theme-token theme-token :half-applied (or (and applied multiple-selection) (and applied (not full-applied))) :full-applied (if multiple-selection diff --git a/frontend/src/app/main/ui/workspace/tokens/token.cljs b/frontend/src/app/main/ui/workspace/tokens/token.cljs index 97f9c7701..dff5ebb10 100644 --- a/frontend/src/app/main/ui/workspace/tokens/token.cljs +++ b/frontend/src/app/main/ui/workspace/tokens/token.cljs @@ -122,6 +122,11 @@ (defn color-token? [token] (= (:type token) :color)) + +;; FIXME: this should be precalculated ? +(defn is-reference? [token] + (str/includes? (:value token) "{")) + (defn color-bullet-color [token-color-value] (when-let [tc (tinycolor/valid-color token-color-value)] (if (tinycolor/alpha tc) diff --git a/frontend/src/app/main/ui/workspace/tokens/token_pill.cljs b/frontend/src/app/main/ui/workspace/tokens/token_pill.cljs index 395291c85..d84baba50 100644 --- a/frontend/src/app/main/ui/workspace/tokens/token_pill.cljs +++ b/frontend/src/app/main/ui/workspace/tokens/token_pill.cljs @@ -4,7 +4,6 @@ [app.main.style :as stl]) (:require [app.common.files.helpers :as cfh] - [app.common.types.tokens-lib :as ctob] [app.main.refs :as refs] [app.main.ui.components.color-bullet :refer [color-bullet]] [app.main.ui.ds.foundations.assets.icon :refer [icon*]] @@ -94,8 +93,8 @@ (str/join ", " (map attribute-dictionary values)) "."))) grouped-values))) -(defn token-pill-tooltip - "Generates a tooltip for a given token." +(defn- generate-tooltip + "Generates a tooltip for a given token" [is-viewer shape token-type-props token half-applied no-valid-value ref-not-in-active-set] (let [{:keys [name value resolved-value type]} token {:keys [title]} token-type-props @@ -142,34 +141,29 @@ (let [match (second (re-find #"\{([^}]+)\}" text))] (contains? active-tokens match))) -(mf/defc token-pill +(mf/defc token-pill* {::mf/wrap-props false} - [{:keys [on-click token theme-token full-applied on-context-menu half-applied selected-shapes token-type-props active-theme-tokens]}] + [{:keys [on-click token full-applied on-context-menu half-applied selected-shapes token-type-props active-theme-tokens]}] (let [{:keys [name value errors]} token - is-reference? (str/includes? value "{") + is-reference? (wtt/is-reference? token) contains-path? (str/includes? name ".") - ;; FIXME: move to context or props can-edit? (:can-edit (deref refs/permissions)) is-viewer (not can-edit?) - ref-not-in-active-set (and is-reference? - (not (contains-reference-value? value active-theme-tokens))) + + ref-not-in-active-set + (and is-reference? + (not (contains-reference-value? value active-theme-tokens))) no-valid-value (seq errors) errors? (or ref-not-in-active-set no-valid-value) - ;; FIXME: :zap: this performs a duplicate operation for - ;; nothing, this generates a lot of garbage objects for - ;; finally not using them - color (when (seq (ctob/find-token-value-references value)) - (wtt/resolved-token-bullet-color theme-token)) - - splitted-name (cfh/split-by-last-period name) - color (or color (wtt/resolved-token-bullet-color token)) + color (when (wtt/color-token? token) + (wtt/resolved-token-bullet-color token)) on-click (mf/use-fn @@ -179,13 +173,14 @@ (when (and (not (seq errors)) on-click) (on-click event)))) - token-status-id (cond - half-applied - "token-status-partial" - full-applied - "token-status-full" - :else - "token-status-non-applied") + token-status-id + (cond + half-applied + "token-status-partial" + full-applied + "token-status-full" + :else + "token-status-non-applied") on-context-menu (mf/use-fn @@ -203,28 +198,30 @@ (when (and can-edit? (not (seq errors)) on-click) (on-click event)))) + ;; FIXME: missing deps on-hover (mf/use-fn (mf/deps selected-shapes is-viewer) (fn [event] - (let [node (dom/get-current-target event) - title (token-pill-tooltip is-viewer (first selected-shapes) - token-type-props token - half-applied no-valid-value ref-not-in-active-set)] + (let [node (dom/get-current-target event) + title (generate-tooltip is-viewer (first selected-shapes) + token-type-props token + half-applied no-valid-value ref-not-in-active-set)] (dom/set-attribute! node "title" title))))] - [:button {:class (stl/css-case :token-pill true - :token-pill-default can-edit? - :token-pill-applied (and can-edit? (or half-applied full-applied)) - :token-pill-invalid (and can-edit? errors?) - :token-pill-invalid-applied (and full-applied errors? can-edit?) - :token-pill-viewer is-viewer - :token-pill-applied-viewer (and is-viewer - (or half-applied full-applied)) - :token-pill-invalid-viewer (and is-viewer - errors?) - :token-pill-invalid-applied-viewer (and is-viewer - (and full-applied errors?))) + [:button {:class (stl/css-case + :token-pill true + :token-pill-default can-edit? + :token-pill-applied (and can-edit? (or half-applied full-applied)) + :token-pill-invalid (and can-edit? errors?) + :token-pill-invalid-applied (and full-applied errors? can-edit?) + :token-pill-viewer is-viewer + :token-pill-applied-viewer (and is-viewer + (or half-applied full-applied)) + :token-pill-invalid-viewer (and is-viewer + errors?) + :token-pill-invalid-applied-viewer (and is-viewer + (and full-applied errors?))) :type "button" :on-click on-click :on-mouse-enter on-hover @@ -234,6 +231,7 @@ [:> icon* {:icon-id "broken-link" :class (stl/css :token-pill-icon)}] + color [:& color-bullet {:color color :mini true}] @@ -241,13 +239,13 @@ [:> token-status-icon* {:icon-id token-status-id :class (stl/css :token-pill-icon)}]) + (if contains-path? - [:span {:class (stl/css :divided-name-wrapper) - :aria-label name} - [:span {:class (stl/css :first-name-wrapper)} - (first splitted-name)] - [:span {:class (stl/css :last-name-wrapper)} - (last splitted-name)]] + (let [[first-part last-part] (cfh/split-by-last-period name)] + [:span {:class (stl/css :divided-name-wrapper) + :aria-label name} + [:span {:class (stl/css :first-name-wrapper)} first-part] + [:span {:class (stl/css :last-name-wrapper)} last-part]]) [:span {:class (stl/css :name-wrapper) :aria-label name} name])])) From a53c37bc3c884397e4d04f67bc1be2714c2aa2d4 Mon Sep 17 00:00:00 2001 From: Andrey Antukh Date: Tue, 4 Feb 2025 18:13:07 +0100 Subject: [PATCH 10/25] :zap: Don't create function references for token-pill callbacks --- frontend/src/app/main/ui/workspace/tokens/sidebar.cljs | 10 ++++------ frontend/src/app/main/ui/workspace/tokens/token.cljs | 4 +++- .../src/app/main/ui/workspace/tokens/token_pill.cljs | 9 ++++----- 3 files changed, 11 insertions(+), 12 deletions(-) diff --git a/frontend/src/app/main/ui/workspace/tokens/sidebar.cljs b/frontend/src/app/main/ui/workspace/tokens/sidebar.cljs index 3f9b5a207..f884bbe96 100644 --- a/frontend/src/app/main/ui/workspace/tokens/sidebar.cljs +++ b/frontend/src/app/main/ui/workspace/tokens/sidebar.cljs @@ -133,13 +133,11 @@ [:& cmm/asset-section-block {:role :content} [:div {:class (stl/css :token-pills-wrapper)} (for [token (sort-by :name tokens)] - (let [theme-token (get active-theme-tokens (wtt/token-identifier token)) + (let [theme-token (get active-theme-tokens (:name token)) multiple-selection (< 1 (count selected-shapes)) full-applied (:all-selected? (attribute-actions token selected-shapes (or all-attributes attributes))) - applied (wtt/shapes-token-applied? token selected-shapes (or all-attributes attributes)) - on-token-click (fn [e] - (on-token-pill-click e token)) - on-context-menu (fn [e] (on-context-menu e token))] + applied (wtt/shapes-token-applied? token selected-shapes (or all-attributes attributes))] + [:> token-pill* {:key (:name token) :token-type-props token-type-props @@ -151,7 +149,7 @@ :full-applied (if multiple-selection false applied) - :on-click on-token-click + :on-click on-token-pill-click :on-context-menu on-context-menu}]))]])]])) (defn sorted-token-groups diff --git a/frontend/src/app/main/ui/workspace/tokens/token.cljs b/frontend/src/app/main/ui/workspace/tokens/token.cljs index dff5ebb10..441310006 100644 --- a/frontend/src/app/main/ui/workspace/tokens/token.cljs +++ b/frontend/src/app/main/ui/workspace/tokens/token.cljs @@ -21,7 +21,9 @@ {:value parsed-value :unit unit})))) -(defn token-identifier [{:keys [name] :as _token}] +;; FIXME: looks very redundant function +(defn token-identifier + [{:keys [name] :as _token}] name) (defn attributes-map diff --git a/frontend/src/app/main/ui/workspace/tokens/token_pill.cljs b/frontend/src/app/main/ui/workspace/tokens/token_pill.cljs index d84baba50..24553bdfe 100644 --- a/frontend/src/app/main/ui/workspace/tokens/token_pill.cljs +++ b/frontend/src/app/main/ui/workspace/tokens/token_pill.cljs @@ -142,7 +142,6 @@ (contains? active-tokens match))) (mf/defc token-pill* - {::mf/wrap-props false} [{:keys [on-click token full-applied on-context-menu half-applied selected-shapes token-type-props active-theme-tokens]}] (let [{:keys [name value errors]} token @@ -167,11 +166,11 @@ on-click (mf/use-fn - (mf/deps errors? on-click) + (mf/deps errors? on-click token) (fn [event] (dom/stop-propagation event) (when (and (not (seq errors)) on-click) - (on-click event)))) + (on-click event token)))) token-status-id (cond @@ -184,11 +183,11 @@ on-context-menu (mf/use-fn - (mf/deps can-edit? on-context-menu) + (mf/deps can-edit? on-context-menu token) (fn [e] (dom/stop-propagation e) (when can-edit? - (on-context-menu e)))) + (on-context-menu e token)))) on-click (mf/use-fn From 769000da2d2e194a0b1f468455bb123ea3b529a5 Mon Sep 17 00:00:00 2001 From: Andrey Antukh Date: Tue, 4 Feb 2025 18:14:29 +0100 Subject: [PATCH 11/25] :lipstick: Add cosmetic changes to token-component component --- .../app/main/ui/workspace/tokens/sidebar.cljs | 73 ++++++++++--------- 1 file changed, 39 insertions(+), 34 deletions(-) diff --git a/frontend/src/app/main/ui/workspace/tokens/sidebar.cljs b/frontend/src/app/main/ui/workspace/tokens/sidebar.cljs index f884bbe96..6566f8859 100644 --- a/frontend/src/app/main/ui/workspace/tokens/sidebar.cljs +++ b/frontend/src/app/main/ui/workspace/tokens/sidebar.cljs @@ -78,42 +78,47 @@ (l/derived lens:token-type-open-status))) {:keys [modal attributes all-attributes title]} token-type-props - on-context-menu (mf/use-fn - (fn [event token] - (dom/prevent-default event) - (dom/stop-propagation event) - (st/emit! (dt/show-token-context-menu - {:type :token - :position (dom/get-client-position event) - :errors (:errors token) - :token-name (:name token)})))) + on-context-menu + (mf/use-fn + (fn [event token] + (dom/prevent-default event) + (dom/stop-propagation event) + (st/emit! (dt/show-token-context-menu + {:type :token + :position (dom/get-client-position event) + :errors (:errors token) + :token-name (:name token)})))) - on-toggle-open-click (mf/use-fn - (mf/deps open? tokens) - #(st/emit! (dt/set-token-type-section-open type (not open?)))) - on-popover-open-click (mf/use-fn - (fn [event] - (mf/deps type title) - (let [{:keys [key fields]} modal] - (dom/stop-propagation event) - (st/emit! (dt/set-token-type-section-open type true)) - (modal/show! key {:x (.-clientX ^js event) - :y (.-clientY ^js event) - :position :right - :fields fields - :title title - :action "create" - :token-type type})))) + on-toggle-open-click + (mf/use-fn + (mf/deps open? tokens) + #(st/emit! (dt/set-token-type-section-open type (not open?)))) - on-token-pill-click (mf/use-fn - (mf/deps selected-shapes token-type-props) - (fn [event token] - (dom/stop-propagation event) - (when (seq selected-shapes) - (st/emit! - (wtch/toggle-token {:token token - :shapes selected-shapes - :token-type-props token-type-props}))))) + on-popover-open-click + (mf/use-fn + (fn [event] + (mf/deps type title) + (let [{:keys [key fields]} modal] + (dom/stop-propagation event) + (st/emit! (dt/set-token-type-section-open type true)) + (modal/show! key {:x (.-clientX ^js event) + :y (.-clientY ^js event) + :position :right + :fields fields + :title title + :action "create" + :token-type type})))) + + on-token-pill-click + (mf/use-fn + (mf/deps selected-shapes token-type-props) + (fn [event token] + (dom/stop-propagation event) + (when (seq selected-shapes) + (st/emit! + (wtch/toggle-token {:token token + :shapes selected-shapes + :token-type-props token-type-props}))))) tokens-count (count tokens) can-edit? (:can-edit (deref refs/permissions))] From 1f450c83ecc030d958f95368057e0383f0fd6af7 Mon Sep 17 00:00:00 2001 From: Andrey Antukh Date: Tue, 4 Feb 2025 18:15:23 +0100 Subject: [PATCH 12/25] :zap: Use new component definition convention for token-component --- .../src/app/main/ui/workspace/tokens/sidebar.cljs | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/frontend/src/app/main/ui/workspace/tokens/sidebar.cljs b/frontend/src/app/main/ui/workspace/tokens/sidebar.cljs index 6566f8859..31af0915d 100644 --- a/frontend/src/app/main/ui/workspace/tokens/sidebar.cljs +++ b/frontend/src/app/main/ui/workspace/tokens/sidebar.cljs @@ -72,7 +72,8 @@ :shape-ids shape-ids :selected-pred #(seq (% ids-by-attributes))})) -(mf/defc token-component +(mf/defc token-component* + {::mf/private true} [{:keys [type tokens selected-shapes token-type-props active-theme-tokens]}] (let [open? (mf/deref (-> (l/key type) (l/derived lens:token-type-open-status))) @@ -289,12 +290,12 @@ (for [{:keys [token-key token-type-props tokens]} (concat (:filled token-groups) (:empty token-groups))] - [:& token-component {:key token-key - :type token-key - :selected-shapes selected-shapes - :active-theme-tokens active-theme-tokens - :tokens tokens - :token-type-props token-type-props}])])) + [:> token-component* {:key token-key + :type token-key + :selected-shapes selected-shapes + :active-theme-tokens active-theme-tokens + :tokens tokens + :token-type-props token-type-props}])])) (mf/defc import-export-button {::mf/wrap-props false} From c1ce24e5f0b1cde35a0b8226d8e1385e64f36ae1 Mon Sep 17 00:00:00 2001 From: Andrey Antukh Date: Tue, 4 Feb 2025 18:17:16 +0100 Subject: [PATCH 13/25] :zap: Don't sort tokens on each rerender --- frontend/src/app/main/ui/workspace/tokens/sidebar.cljs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/frontend/src/app/main/ui/workspace/tokens/sidebar.cljs b/frontend/src/app/main/ui/workspace/tokens/sidebar.cljs index 31af0915d..0571a2c0a 100644 --- a/frontend/src/app/main/ui/workspace/tokens/sidebar.cljs +++ b/frontend/src/app/main/ui/workspace/tokens/sidebar.cljs @@ -79,6 +79,10 @@ (l/derived lens:token-type-open-status))) {:keys [modal attributes all-attributes title]} token-type-props + tokens + (mf/with-memo [tokens] + (vec (sort-by :name tokens))) + on-context-menu (mf/use-fn (fn [event token] @@ -138,7 +142,7 @@ (when open? [:& cmm/asset-section-block {:role :content} [:div {:class (stl/css :token-pills-wrapper)} - (for [token (sort-by :name tokens)] + (for [token tokens] (let [theme-token (get active-theme-tokens (:name token)) multiple-selection (< 1 (count selected-shapes)) full-applied (:all-selected? (attribute-actions token selected-shapes (or all-attributes attributes))) From ff34d1d5f9f1d26100f11b860793c04d016bd876 Mon Sep 17 00:00:00 2001 From: Andrey Antukh Date: Tue, 4 Feb 2025 18:19:44 +0100 Subject: [PATCH 14/25] :zap: Don't create an additional sequence on iterating for tokens --- .../src/app/main/ui/workspace/tokens/sidebar.cljs | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/frontend/src/app/main/ui/workspace/tokens/sidebar.cljs b/frontend/src/app/main/ui/workspace/tokens/sidebar.cljs index 0571a2c0a..216ade0e9 100644 --- a/frontend/src/app/main/ui/workspace/tokens/sidebar.cljs +++ b/frontend/src/app/main/ui/workspace/tokens/sidebar.cljs @@ -292,8 +292,15 @@ [:& title-bar {:all-clickable true :title (tr "workspace.token.tokens-section-title" selected-token-set-name)}] - (for [{:keys [token-key token-type-props tokens]} (concat (:filled token-groups) - (:empty token-groups))] + (for [{:keys [token-key token-type-props tokens]} (:filled token-groups)] + [:> token-component* {:key token-key + :type token-key + :selected-shapes selected-shapes + :active-theme-tokens active-theme-tokens + :tokens tokens + :token-type-props token-type-props}]) + + (for [{:keys [token-key token-type-props tokens]} (:empty token-groups)] [:> token-component* {:key token-key :type token-key :selected-shapes selected-shapes From 7a4d8b824eb20373df2ff9409eae3adbdf473407 Mon Sep 17 00:00:00 2001 From: Andrey Antukh Date: Tue, 4 Feb 2025 18:28:26 +0100 Subject: [PATCH 15/25] :lipstick: Rename token-component* to token-group* --- .../app/main/ui/workspace/tokens/sidebar.cljs | 27 ++++++++++--------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/frontend/src/app/main/ui/workspace/tokens/sidebar.cljs b/frontend/src/app/main/ui/workspace/tokens/sidebar.cljs index 216ade0e9..a2a5d50f0 100644 --- a/frontend/src/app/main/ui/workspace/tokens/sidebar.cljs +++ b/frontend/src/app/main/ui/workspace/tokens/sidebar.cljs @@ -72,7 +72,7 @@ :shape-ids shape-ids :selected-pred #(seq (% ids-by-attributes))})) -(mf/defc token-component* +(mf/defc token-group* {::mf/private true} [{:keys [type tokens selected-shapes token-type-props active-theme-tokens]}] (let [open? (mf/deref (-> (l/key type) @@ -287,26 +287,27 @@ (mf/with-memo [tokens selected-token-set-tokens] (-> (select-keys tokens (keys selected-token-set-tokens)) (sorted-token-groups)))] + [:* [:& token-context-menu] [:& title-bar {:all-clickable true :title (tr "workspace.token.tokens-section-title" selected-token-set-name)}] (for [{:keys [token-key token-type-props tokens]} (:filled token-groups)] - [:> token-component* {:key token-key - :type token-key - :selected-shapes selected-shapes - :active-theme-tokens active-theme-tokens - :tokens tokens - :token-type-props token-type-props}]) + [:> token-group* {:key token-key + :type token-key + :selected-shapes selected-shapes + :active-theme-tokens active-theme-tokens + :tokens tokens + :token-type-props token-type-props}]) (for [{:keys [token-key token-type-props tokens]} (:empty token-groups)] - [:> token-component* {:key token-key - :type token-key - :selected-shapes selected-shapes - :active-theme-tokens active-theme-tokens - :tokens tokens - :token-type-props token-type-props}])])) + [:> token-group* {:key token-key + :type token-key + :selected-shapes selected-shapes + :active-theme-tokens active-theme-tokens + :tokens tokens + :token-type-props token-type-props}])])) (mf/defc import-export-button {::mf/wrap-props false} From e4bf2bd9ad680d5c72e0b4e7b47fb6b86e57c6d6 Mon Sep 17 00:00:00 2001 From: Andrey Antukh Date: Tue, 4 Feb 2025 18:37:20 +0100 Subject: [PATCH 16/25] :lipstick: Internal function rename on tokens sidebar --- frontend/src/app/main/ui/workspace/tokens/sidebar.cljs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frontend/src/app/main/ui/workspace/tokens/sidebar.cljs b/frontend/src/app/main/ui/workspace/tokens/sidebar.cljs index a2a5d50f0..1067f78fb 100644 --- a/frontend/src/app/main/ui/workspace/tokens/sidebar.cljs +++ b/frontend/src/app/main/ui/workspace/tokens/sidebar.cljs @@ -162,7 +162,7 @@ :on-click on-token-pill-click :on-context-menu on-context-menu}]))]])]])) -(defn sorted-token-groups +(defn- get-sorted-token-groups "Separate token-types into groups of `:empty` or `:filled` depending if tokens exist for that type. Sort each group alphabetically (by their `:token-key`)." [tokens] @@ -286,7 +286,7 @@ token-groups (mf/with-memo [tokens selected-token-set-tokens] (-> (select-keys tokens (keys selected-token-set-tokens)) - (sorted-token-groups)))] + (get-sorted-token-groups)))] [:* [:& token-context-menu] From 831b0baddd7812f5cc20b61bcd7dfab85887ab80 Mon Sep 17 00:00:00 2001 From: Andrey Antukh Date: Tue, 4 Feb 2025 20:29:39 +0100 Subject: [PATCH 17/25] :zap: Improve efficiency of grouping and sorting token types --- .../app/main/ui/workspace/tokens/sidebar.cljs | 76 +++++++++++-------- .../main/ui/workspace/tokens/token_pill.cljs | 10 +-- frontend/src/app/util/array.cljs | 11 ++- 3 files changed, 59 insertions(+), 38 deletions(-) diff --git a/frontend/src/app/main/ui/workspace/tokens/sidebar.cljs b/frontend/src/app/main/ui/workspace/tokens/sidebar.cljs index 1067f78fb..98e614382 100644 --- a/frontend/src/app/main/ui/workspace/tokens/sidebar.cljs +++ b/frontend/src/app/main/ui/workspace/tokens/sidebar.cljs @@ -35,6 +35,7 @@ [app.main.ui.workspace.tokens.token :as wtt] [app.main.ui.workspace.tokens.token-pill :refer [token-pill*]] [app.main.ui.workspace.tokens.token-types :as wtty] + [app.util.array :as array] [app.util.dom :as dom] [app.util.i18n :refer [tr]] [app.util.webapi :as wapi] @@ -74,10 +75,12 @@ (mf/defc token-group* {::mf/private true} - [{:keys [type tokens selected-shapes token-type-props active-theme-tokens]}] + [{:keys [type tokens selected-shapes active-theme-tokens]}] (let [open? (mf/deref (-> (l/key type) (l/derived lens:token-type-open-status))) - {:keys [modal attributes all-attributes title]} token-type-props + + {:keys [modal attributes all-attributes title] :as token-type-props} + (get wtty/token-types type) tokens (mf/with-memo [tokens] @@ -150,7 +153,6 @@ [:> token-pill* {:key (:name token) - :token-type-props token-type-props :token (d/nilv theme-token token) :selected-shapes selected-shapes :active-theme-tokens active-theme-tokens @@ -163,19 +165,23 @@ :on-context-menu on-context-menu}]))]])]])) (defn- get-sorted-token-groups - "Separate token-types into groups of `:empty` or `:filled` depending if tokens exist for that type. - Sort each group alphabetically (by their `:token-key`)." - [tokens] - (let [tokens-by-type (ctob/group-by-type tokens) - {:keys [empty filled]} (->> wtty/token-types - (map (fn [[token-key token-type-props]] - {:token-key token-key - :token-type-props token-type-props - :tokens (get tokens-by-type token-key [])})) - (group-by (fn [{:keys [tokens]}] - (if (empty? tokens) :empty :filled))))] - {:empty (sort-by :token-key empty) - :filled (sort-by :token-key filled)})) + "Separate token-types into groups of `empty` or `filled` depending if + tokens exist for that type. Sort each group alphabetically (by + their type)." + [tokens-by-type] + (loop [empty #js [] + filled #js [] + types (-> wtty/token-types keys seq)] + (if-let [type (first types)] + (if (not-empty (get tokens-by-type type)) + (recur empty + (array/conj! filled type) + (rest types)) + (recur (array/conj! empty type) + filled + (rest types))) + [(seq (array/sort! empty)) + (seq (array/sort! filled))]))) (mf/defc themes-header [_props] @@ -283,31 +289,39 @@ selected-token-set-name (mf/deref refs/workspace-selected-token-set-name) - token-groups + tokens-by-type (mf/with-memo [tokens selected-token-set-tokens] - (-> (select-keys tokens (keys selected-token-set-tokens)) - (get-sorted-token-groups)))] + (let [tokens (reduce-kv (fn [tokens k _] + (if (contains? selected-token-set-tokens k) + tokens + (dissoc tokens k))) + tokens + tokens)] + (ctob/group-by-type tokens))) + + [empty-group filled-group] + (mf/with-memo [tokens-by-type] + (get-sorted-token-groups tokens-by-type))] [:* [:& token-context-menu] [:& title-bar {:all-clickable true :title (tr "workspace.token.tokens-section-title" selected-token-set-name)}] - (for [{:keys [token-key token-type-props tokens]} (:filled token-groups)] - [:> token-group* {:key token-key - :type token-key - :selected-shapes selected-shapes - :active-theme-tokens active-theme-tokens - :tokens tokens - :token-type-props token-type-props}]) + (for [type filled-group] + (let [tokens (get tokens-by-type type)] + [:> token-group* {:key (name type) + :type type + :selected-shapes selected-shapes + :active-theme-tokens active-theme-tokens + :tokens tokens}])) - (for [{:keys [token-key token-type-props tokens]} (:empty token-groups)] - [:> token-group* {:key token-key - :type token-key + (for [type empty-group] + [:> token-group* {:key (name type) + :type type :selected-shapes selected-shapes :active-theme-tokens active-theme-tokens - :tokens tokens - :token-type-props token-type-props}])])) + :tokens []}])])) (mf/defc import-export-button {::mf/wrap-props false} diff --git a/frontend/src/app/main/ui/workspace/tokens/token_pill.cljs b/frontend/src/app/main/ui/workspace/tokens/token_pill.cljs index 24553bdfe..3cc333d46 100644 --- a/frontend/src/app/main/ui/workspace/tokens/token_pill.cljs +++ b/frontend/src/app/main/ui/workspace/tokens/token_pill.cljs @@ -9,6 +9,7 @@ [app.main.ui.ds.foundations.assets.icon :refer [icon*]] [app.main.ui.ds.foundations.utilities.token.token-status :refer [token-status-icon*]] [app.main.ui.workspace.tokens.token :as wtt] + [app.main.ui.workspace.tokens.token-types :as wtty] [app.util.dom :as dom] [app.util.i18n :refer [tr]] [cuerdas.core :as str] @@ -95,9 +96,9 @@ (defn- generate-tooltip "Generates a tooltip for a given token" - [is-viewer shape token-type-props token half-applied no-valid-value ref-not-in-active-set] + [is-viewer shape token half-applied no-valid-value ref-not-in-active-set] (let [{:keys [name value resolved-value type]} token - {:keys [title]} token-type-props + {:keys [title] :as token-type-props} (get wtty/token-types (:type token)) applied-tokens (:applied-tokens shape) app-token-vals (set (vals applied-tokens)) app-token-keys (keys applied-tokens) @@ -142,7 +143,7 @@ (contains? active-tokens match))) (mf/defc token-pill* - [{:keys [on-click token full-applied on-context-menu half-applied selected-shapes token-type-props active-theme-tokens]}] + [{:keys [on-click token full-applied on-context-menu half-applied selected-shapes active-theme-tokens]}] (let [{:keys [name value errors]} token is-reference? (wtt/is-reference? token) @@ -203,8 +204,7 @@ (mf/deps selected-shapes is-viewer) (fn [event] (let [node (dom/get-current-target event) - title (generate-tooltip is-viewer (first selected-shapes) - token-type-props token + title (generate-tooltip is-viewer (first selected-shapes) token half-applied no-valid-value ref-not-in-active-set)] (dom/set-attribute! node "title" title))))] diff --git a/frontend/src/app/util/array.cljs b/frontend/src/app/util/array.cljs index 1e56d99b3..18ef45aef 100644 --- a/frontend/src/app/util/array.cljs +++ b/frontend/src/app/util/array.cljs @@ -6,9 +6,10 @@ (ns app.util.array "A collection of helpers for work with javascript arrays." - (:refer-clojure :exclude [conj! conj filter map reduce find]) + (:refer-clojure :exclude [conj! conj filter map reduce find sort]) (:require - [cljs.core :as c])) + [cljs.core :as c] + [goog.array :as garray])) (defn conj "A conj like function for js arrays." @@ -67,3 +68,9 @@ (defn find [f v] (.find ^js/Array v f)) + +(defn sort! + [a] + (garray/sort a compare) + a) + From d6e7a331d57f3d6435d3f3de793c76ce1be18577 Mon Sep 17 00:00:00 2001 From: Andrey Antukh Date: Tue, 4 Feb 2025 20:54:07 +0100 Subject: [PATCH 18/25] :recycle: Move token-types to changes ns And rename it to token-properties --- .../app/main/ui/workspace/tokens/changes.cljs | 99 ++++++++++++++++++- .../ui/workspace/tokens/context_menu.cljs | 5 +- .../app/main/ui/workspace/tokens/form.cljs | 4 +- .../app/main/ui/workspace/tokens/sidebar.cljs | 13 +-- .../main/ui/workspace/tokens/token_pill.cljs | 11 +-- .../main/ui/workspace/tokens/token_types.cljs | 89 ----------------- 6 files changed, 110 insertions(+), 111 deletions(-) delete mode 100644 frontend/src/app/main/ui/workspace/tokens/token_types.cljs diff --git a/frontend/src/app/main/ui/workspace/tokens/changes.cljs b/frontend/src/app/main/ui/workspace/tokens/changes.cljs index ceba897e4..cab2069fe 100644 --- a/frontend/src/app/main/ui/workspace/tokens/changes.cljs +++ b/frontend/src/app/main/ui/workspace/tokens/changes.cljs @@ -6,6 +6,8 @@ (ns app.main.ui.workspace.tokens.changes (:require + [app.common.data :as d] + [app.common.data.macros :as dm] [app.common.types.shape.layout :as ctsl] [app.common.types.shape.radius :as ctsr] [app.common.types.token :as ctt] @@ -26,6 +28,8 @@ [clojure.set :as set] [potok.v2.core :as ptk])) +(declare token-properties) + ;; Token Updates --------------------------------------------------------------- (defn apply-token @@ -76,12 +80,16 @@ (update shape :applied-tokens remove-token)))))))) (defn toggle-token - [{:keys [token-type-props token shapes] :as _props}] + [{:keys [token shapes]}] (ptk/reify ::on-toggle-token ptk/WatchEvent (watch [_ _ _] - (let [{:keys [attributes all-attributes on-update-shape]} token-type-props - unapply-tokens? (wtt/shapes-token-applied? token shapes (or all-attributes attributes)) + (let [{:keys [attributes all-attributes on-update-shape]} + (get token-properties (:type token)) + + unapply-tokens? + (wtt/shapes-token-applied? token shapes (or all-attributes attributes)) + shape-ids (map :id shapes)] (if unapply-tokens? (rx/of @@ -252,3 +260,88 @@ (select-keys attributes))] (dwsl/update-layout-child shape-ids props {:ignore-touched true :page-id page-id})))))) + +;; Token Types ----------------------------------------------------------------- + +;; FIXME: the values should be lazy evaluated, probably a function, +;; becasue on future we will need to translate that labels and that +;; can not be done statically + +(def token-properties + "A map of default properties by token type" + (d/ordered-map + :border-radius + {:title "Border Radius" + :attributes ctt/border-radius-keys + :on-update-shape update-shape-radius-all + :modal {:key :tokens/border-radius + :fields [{:label "Border Radius" + :key :border-radius}]}} + + :color + {:title "Color" + :attributes #{:fill} + :all-attributes ctt/color-keys + :on-update-shape update-fill-stroke + :modal {:key :tokens/color + :fields [{:label "Color" :key :color}]}} + + :stroke-width + {:title "Stroke Width" + :attributes ctt/stroke-width-keys + :on-update-shape update-stroke-width + :modal {:key :tokens/stroke-width + :fields [{:label "Stroke Width" + :key :stroke-width}]}} + + :sizing + {:title "Sizing" + :attributes #{:width :height} + :all-attributes ctt/sizing-keys + :on-update-shape update-shape-dimensions + :modal {:key :tokens/sizing + :fields [{:label "Sizing" + :key :sizing}]}} + :dimensions + {:title "Dimensions" + :attributes #{:width :height} + :all-attributes (set/union + ctt/spacing-keys + ctt/sizing-keys + ctt/border-radius-keys + ctt/stroke-width-keys) + :on-update-shape update-shape-dimensions + :modal {:key :tokens/dimensions + :fields [{:label "Dimensions" + :key :dimensions}]}} + + :opacity + {:title "Opacity" + :attributes ctt/opacity-keys + :on-update-shape update-opacity + :modal {:key :tokens/opacity + :fields [{:label "Opacity" + :key :opacity}]}} + + :rotation + {:title "Rotation" + :attributes ctt/rotation-keys + :on-update-shape update-rotation + :modal {:key :tokens/rotation + :fields [{:label "Rotation" + :key :rotation}]}} + :spacing + {:title "Spacing" + :attributes #{:column-gap :row-gap} + :all-attributes ctt/spacing-keys + :on-update-shape update-layout-spacing + :modal {:key :tokens/spacing + :fields [{:label "Spacing" + :key :spacing}]}})) + +(defn get-token-properties [token] + (get token-properties (:type token))) + +(defn token-attributes [token-type] + (dm/get-in token-properties [token-type :attributes])) + diff --git a/frontend/src/app/main/ui/workspace/tokens/context_menu.cljs b/frontend/src/app/main/ui/workspace/tokens/context_menu.cljs index 9961ea407..77b2e16d2 100644 --- a/frontend/src/app/main/ui/workspace/tokens/context_menu.cljs +++ b/frontend/src/app/main/ui/workspace/tokens/context_menu.cljs @@ -18,7 +18,6 @@ [app.main.ui.ds.foundations.assets.icon :refer [icon*]] [app.main.ui.workspace.tokens.changes :as wtch] [app.main.ui.workspace.tokens.token :as wtt] - [app.main.ui.workspace.tokens.token-types :as wtty] [app.util.dom :as dom] [app.util.i18n :refer [tr]] [app.util.timers :as timers] @@ -37,7 +36,7 @@ (defn generic-attribute-actions [attributes title {:keys [token selected-shapes on-update-shape]}] (let [on-update-shape-fn (or on-update-shape - (-> (wtty/get-token-properties token) + (-> (wtch/get-token-properties token) (:on-update-shape))) {:keys [selected-pred shape-ids]} (attribute-actions token selected-shapes attributes)] (map (fn [attribute] @@ -214,7 +213,7 @@ (generic-attribute-actions #{:y} "Y" (assoc context-data :on-update-shape wtch/update-shape-position))))})) (defn default-actions [{:keys [token selected-token-set-name]}] - (let [{:keys [modal]} (wtty/get-token-properties token)] + (let [{:keys [modal]} (wtch/get-token-properties token)] [{:title (tr "workspace.token.edit") :no-selectable true :action (fn [event] diff --git a/frontend/src/app/main/ui/workspace/tokens/form.cljs b/frontend/src/app/main/ui/workspace/tokens/form.cljs index 46406903a..85c8530c3 100644 --- a/frontend/src/app/main/ui/workspace/tokens/form.cljs +++ b/frontend/src/app/main/ui/workspace/tokens/form.cljs @@ -21,13 +21,13 @@ [app.main.ui.notifications.context-notification :refer [context-notification]] [app.main.ui.workspace.colorpicker :as colorpicker] [app.main.ui.workspace.colorpicker.ramp :refer [ramp-selector*]] + [app.main.ui.workspace.tokens.changes :as wtch] [app.main.ui.workspace.tokens.components.controls.input-token-color-bullet :refer [input-token-color-bullet*]] [app.main.ui.workspace.tokens.components.controls.input-tokens :refer [input-tokens*]] [app.main.ui.workspace.tokens.errors :as wte] [app.main.ui.workspace.tokens.style-dictionary :as sd] [app.main.ui.workspace.tokens.tinycolor :as tinycolor] [app.main.ui.workspace.tokens.token :as wtt] - [app.main.ui.workspace.tokens.token-types :as wtty] [app.main.ui.workspace.tokens.update :as wtu] [app.main.ui.workspace.tokens.warnings :as wtw] [app.util.dom :as dom] @@ -223,7 +223,7 @@ [{:keys [token token-type action selected-token-set-name on-display-colorpicker]}] (let [create? (not (instance? ctob/Token token)) token (or token {:type token-type}) - token-properties (wtty/get-token-properties token) + token-properties (wtch/get-token-properties token) color? (wtt/color-token? token) selected-set-tokens (mf/deref refs/workspace-selected-token-set-tokens) active-theme-tokens (mf/deref refs/workspace-active-theme-sets-tokens) diff --git a/frontend/src/app/main/ui/workspace/tokens/sidebar.cljs b/frontend/src/app/main/ui/workspace/tokens/sidebar.cljs index 98e614382..acf919a06 100644 --- a/frontend/src/app/main/ui/workspace/tokens/sidebar.cljs +++ b/frontend/src/app/main/ui/workspace/tokens/sidebar.cljs @@ -34,7 +34,6 @@ [app.main.ui.workspace.tokens.theme-select :refer [theme-select]] [app.main.ui.workspace.tokens.token :as wtt] [app.main.ui.workspace.tokens.token-pill :refer [token-pill*]] - [app.main.ui.workspace.tokens.token-types :as wtty] [app.util.array :as array] [app.util.dom :as dom] [app.util.i18n :refer [tr]] @@ -80,7 +79,7 @@ (l/derived lens:token-type-open-status))) {:keys [modal attributes all-attributes title] :as token-type-props} - (get wtty/token-types type) + (get wtch/token-properties type) tokens (mf/with-memo [tokens] @@ -119,14 +118,12 @@ on-token-pill-click (mf/use-fn - (mf/deps selected-shapes token-type-props) + (mf/deps selected-shapes) (fn [event token] (dom/stop-propagation event) (when (seq selected-shapes) - (st/emit! - (wtch/toggle-token {:token token - :shapes selected-shapes - :token-type-props token-type-props}))))) + (st/emit! (wtch/toggle-token {:token token + :shapes selected-shapes}))))) tokens-count (count tokens) can-edit? (:can-edit (deref refs/permissions))] @@ -171,7 +168,7 @@ [tokens-by-type] (loop [empty #js [] filled #js [] - types (-> wtty/token-types keys seq)] + types (-> wtch/token-properties keys seq)] (if-let [type (first types)] (if (not-empty (get tokens-by-type type)) (recur empty diff --git a/frontend/src/app/main/ui/workspace/tokens/token_pill.cljs b/frontend/src/app/main/ui/workspace/tokens/token_pill.cljs index 3cc333d46..c635fd444 100644 --- a/frontend/src/app/main/ui/workspace/tokens/token_pill.cljs +++ b/frontend/src/app/main/ui/workspace/tokens/token_pill.cljs @@ -8,8 +8,8 @@ [app.main.ui.components.color-bullet :refer [color-bullet]] [app.main.ui.ds.foundations.assets.icon :refer [icon*]] [app.main.ui.ds.foundations.utilities.token.token-status :refer [token-status-icon*]] + [app.main.ui.workspace.tokens.changes :as wtch] [app.main.ui.workspace.tokens.token :as wtt] - [app.main.ui.workspace.tokens.token-types :as wtty] [app.util.dom :as dom] [app.util.i18n :refer [tr]] [cuerdas.core :as str] @@ -75,9 +75,8 @@ ;; Helper functions (defn partially-applied-attr "Translates partially applied attributes based on the dictionary." - [app-token-keys is-applied token-type-props] - (let [{:keys [attributes all-attributes]} token-type-props - filtered-keys (if all-attributes + [app-token-keys is-applied {:keys [attributes all-attributes]}] + (let [filtered-keys (if all-attributes (filter #(contains? all-attributes %) app-token-keys) (filter #(contains? attributes %) app-token-keys))] (when is-applied @@ -98,7 +97,7 @@ "Generates a tooltip for a given token" [is-viewer shape token half-applied no-valid-value ref-not-in-active-set] (let [{:keys [name value resolved-value type]} token - {:keys [title] :as token-type-props} (get wtty/token-types (:type token)) + {:keys [title] :as token-props} (wtch/get-token-properties token) applied-tokens (:applied-tokens shape) app-token-vals (set (vals applied-tokens)) app-token-keys (keys applied-tokens) @@ -106,7 +105,7 @@ applied-to (if half-applied - (partially-applied-attr app-token-keys is-applied? token-type-props) + (partially-applied-attr app-token-keys is-applied? token-props) (tr "labels.all")) grouped-values (group-by dimensions-dictionary app-token-keys) diff --git a/frontend/src/app/main/ui/workspace/tokens/token_types.cljs b/frontend/src/app/main/ui/workspace/tokens/token_types.cljs deleted file mode 100644 index f5979add4..000000000 --- a/frontend/src/app/main/ui/workspace/tokens/token_types.cljs +++ /dev/null @@ -1,89 +0,0 @@ -;; This Source Code Form is subject to the terms of the Mozilla Public -;; License, v. 2.0. If a copy of the MPL was not distributed with this -;; file, You can obtain one at http://mozilla.org/MPL/2.0/. -;; -;; Copyright (c) KALEIDOS INC - -(ns app.main.ui.workspace.tokens.token-types - (:require - [app.common.data :as d :refer [ordered-map]] - [app.common.types.token :as ctt] - [app.main.ui.workspace.tokens.changes :as wtch] - [clojure.set :as set])) - -(def token-types - (ordered-map - :border-radius - {:title "Border Radius" - :attributes ctt/border-radius-keys - :on-update-shape wtch/update-shape-radius-all - :modal {:key :tokens/border-radius - :fields [{:label "Border Radius" - :key :border-radius}]}} - - :color - {:title "Color" - :attributes #{:fill} - :all-attributes ctt/color-keys - :on-update-shape wtch/update-fill-stroke - :modal {:key :tokens/color - :fields [{:label "Color" :key :color}]}} - - :stroke-width - {:title "Stroke Width" - :attributes ctt/stroke-width-keys - :on-update-shape wtch/update-stroke-width - :modal {:key :tokens/stroke-width - :fields [{:label "Stroke Width" - :key :stroke-width}]}} - - :sizing - {:title "Sizing" - :attributes #{:width :height} - :all-attributes ctt/sizing-keys - :on-update-shape wtch/update-shape-dimensions - :modal {:key :tokens/sizing - :fields [{:label "Sizing" - :key :sizing}]}} - :dimensions - {:title "Dimensions" - :attributes #{:width :height} - :all-attributes (set/union - ctt/spacing-keys - ctt/sizing-keys - ctt/border-radius-keys - ctt/stroke-width-keys) - :on-update-shape wtch/update-shape-dimensions - :modal {:key :tokens/dimensions - :fields [{:label "Dimensions" - :key :dimensions}]}} - - :opacity - {:title "Opacity" - :attributes ctt/opacity-keys - :on-update-shape wtch/update-opacity - :modal {:key :tokens/opacity - :fields [{:label "Opacity" - :key :opacity}]}} - - :rotation - {:title "Rotation" - :attributes ctt/rotation-keys - :on-update-shape wtch/update-rotation - :modal {:key :tokens/rotation - :fields [{:label "Rotation" - :key :rotation}]}} - :spacing - {:title "Spacing" - :attributes #{:column-gap :row-gap} - :all-attributes ctt/spacing-keys - :on-update-shape wtch/update-layout-spacing - :modal {:key :tokens/spacing - :fields [{:label "Spacing" - :key :spacing}]}})) - -(defn get-token-properties [token] - (get token-types (:type token))) - -(defn token-attributes [token-type] - (get-in token-types [token-type :attributes])) From c91b7606a0a9f8b9d7561b76b3c51f5567adc271 Mon Sep 17 00:00:00 2001 From: Andrey Antukh Date: Tue, 4 Feb 2025 20:57:36 +0100 Subject: [PATCH 19/25] :zap: Add minor efficiency improvements using new call convention --- frontend/src/app/main/ui/workspace/tokens/sidebar.cljs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/frontend/src/app/main/ui/workspace/tokens/sidebar.cljs b/frontend/src/app/main/ui/workspace/tokens/sidebar.cljs index acf919a06..8de07ca5f 100644 --- a/frontend/src/app/main/ui/workspace/tokens/sidebar.cljs +++ b/frontend/src/app/main/ui/workspace/tokens/sidebar.cljs @@ -246,7 +246,8 @@ [:& h/sortable-container {} [:& sets-list]]))) -(mf/defc themes-sets-tab +(mf/defc themes-sets-tab* + {::mf/private true} [{:keys [resize-height]}] (let [open? (mf/use-state true) on-open (mf/use-fn #(reset! open? true)) @@ -400,7 +401,7 @@ size-pages-opened :size} (use-resize-hook :tokens 200 38 "0.6" :y false nil)] [:div {:class (stl/css :sidebar-wrapper)} - [:& themes-sets-tab {:resize-height size-pages-opened}] + [:> themes-sets-tab* {:resize-height size-pages-opened}] [:article {:class (stl/css :tokens-section-wrapper) :data-testid "tokens-sidebar"} [:div {:class (stl/css :resize-area-horiz) From 81036b9330599e3611cd98275371bc3bba04ad67 Mon Sep 17 00:00:00 2001 From: Andrey Antukh Date: Wed, 5 Feb 2025 11:46:07 +0100 Subject: [PATCH 20/25] :zap: Improve handling open-status and tokens selection --- frontend/src/app/main/data/tokens.cljs | 2 +- .../app/main/ui/workspace/tokens/sidebar.cljs | 59 ++++++++++--------- .../app/main/ui/workspace/tokens/token.cljs | 24 ++++---- 3 files changed, 46 insertions(+), 39 deletions(-) diff --git a/frontend/src/app/main/data/tokens.cljs b/frontend/src/app/main/data/tokens.cljs index af5b103ae..de295d071 100644 --- a/frontend/src/app/main/data/tokens.cljs +++ b/frontend/src/app/main/data/tokens.cljs @@ -312,7 +312,7 @@ (ptk/reify ::set-token-type-section-open ptk/UpdateEvent (update [_ state] - (assoc-in state [:workspace-tokens :open-status token-type] open?)))) + (assoc-in state [:workspace-local :token-type-open-status token-type] open?)))) ;; === Token Context Menu diff --git a/frontend/src/app/main/ui/workspace/tokens/sidebar.cljs b/frontend/src/app/main/ui/workspace/tokens/sidebar.cljs index 8de07ca5f..97f2233f5 100644 --- a/frontend/src/app/main/ui/workspace/tokens/sidebar.cljs +++ b/frontend/src/app/main/ui/workspace/tokens/sidebar.cljs @@ -8,6 +8,7 @@ (:require-macros [app.main.style :as stl]) (:require [app.common.data :as d] + [app.common.data.macros :as dm] [app.common.types.tokens-lib :as ctob] [app.main.data.event :as ev] [app.main.data.modal :as modal] @@ -44,8 +45,8 @@ [rumext.v2 :as mf] [shadow.resource])) -(def lens:token-type-open-status - (l/derived (l/in [:workspace-tokens :open-status]) st/state)) +(def ref:token-type-open-status + (l/derived #(dm/get-in % [:workspace-local :token-type-open-status]) st/state)) ;; Components ------------------------------------------------------------------ @@ -65,20 +66,19 @@ :sizing "expand" "add")) -(defn attribute-actions [token selected-shapes attributes] +(def ^:private + xf:map-id + (map :id)) + +(defn- all-selected? [token selected-shapes attributes] (let [ids-by-attributes (wtt/shapes-ids-by-applied-attributes token selected-shapes attributes) - shape-ids (into #{} (map :id selected-shapes))] - {:all-selected? (wtt/shapes-applied-all? ids-by-attributes shape-ids attributes) - :shape-ids shape-ids - :selected-pred #(seq (% ids-by-attributes))})) + shape-ids (into #{} xf:map-id selected-shapes)] + (wtt/shapes-applied-all? ids-by-attributes shape-ids attributes))) (mf/defc token-group* {::mf/private true} - [{:keys [type tokens selected-shapes active-theme-tokens]}] - (let [open? (mf/deref (-> (l/key type) - (l/derived lens:token-type-open-status))) - - {:keys [modal attributes all-attributes title] :as token-type-props} + [{:keys [type tokens selected-shapes active-theme-tokens is-open]}] + (let [{:keys [modal attributes all-attributes title] :as token-type-props} (get wtch/token-properties type) tokens @@ -98,23 +98,24 @@ on-toggle-open-click (mf/use-fn - (mf/deps open? tokens) - #(st/emit! (dt/set-token-type-section-open type (not open?)))) + (mf/deps is-open type) + #(st/emit! (dt/set-token-type-section-open type (not is-open)))) on-popover-open-click (mf/use-fn + (mf/deps type title modal) (fn [event] - (mf/deps type title) - (let [{:keys [key fields]} modal] - (dom/stop-propagation event) - (st/emit! (dt/set-token-type-section-open type true)) - (modal/show! key {:x (.-clientX ^js event) - :y (.-clientY ^js event) - :position :right - :fields fields - :title title - :action "create" - :token-type type})))) + (dom/stop-propagation event) + (st/emit! (dt/set-token-type-section-open type true) + ;; FIXME: use dom/get-client-position + (modal/show (:key modal) + {:x (.-clientX ^js event) + :y (.-clientY ^js event) + :position :right + :fields (:fields modal) + :title title + :action "create" + :token-type type})))) on-token-pill-click (mf/use-fn @@ -131,7 +132,7 @@ [:& cmm/asset-section {:icon (token-section-icon type) :title title :assets-count tokens-count - :open? open?} + :open? is-open} [:& cmm/asset-section-block {:role :title-button} (when can-edit? [:> icon-button* {:on-click on-popover-open-click @@ -139,13 +140,13 @@ :icon "add" ;; TODO: This needs translation :aria-label (str "Add token: " title)}])] - (when open? + (when is-open [:& cmm/asset-section-block {:role :content} [:div {:class (stl/css :token-pills-wrapper)} (for [token tokens] (let [theme-token (get active-theme-tokens (:name token)) multiple-selection (< 1 (count selected-shapes)) - full-applied (:all-selected? (attribute-actions token selected-shapes (or all-attributes attributes))) + full-applied (all-selected? token selected-shapes (or all-attributes attributes)) applied (wtt/shapes-token-applied? token selected-shapes (or all-attributes attributes))] [:> token-pill* @@ -270,6 +271,7 @@ [] (let [objects (mf/deref refs/workspace-page-objects) selected (mf/deref refs/selected-shapes) + open-status (mf/deref ref:token-type-open-status) selected-shapes (mf/with-memo [selected objects] @@ -309,6 +311,7 @@ (for [type filled-group] (let [tokens (get tokens-by-type type)] [:> token-group* {:key (name type) + :is-open (get open-status type false) :type type :selected-shapes selected-shapes :active-theme-tokens active-theme-tokens diff --git a/frontend/src/app/main/ui/workspace/tokens/token.cljs b/frontend/src/app/main/ui/workspace/tokens/token.cljs index 441310006..6056d0966 100644 --- a/frontend/src/app/main/ui/workspace/tokens/token.cljs +++ b/frontend/src/app/main/ui/workspace/tokens/token.cljs @@ -1,6 +1,7 @@ (ns app.main.ui.workspace.tokens.token (:require [app.common.data :as d] + [app.common.data.macros :as dm] [app.main.ui.workspace.tokens.tinycolor :as tinycolor] [clojure.set :as set] [cuerdas.core :as str])) @@ -45,7 +46,7 @@ (defn token-attribute-applied? "Test if `token` is applied to a `shape` on single `token-attribute`." [token shape token-attribute] - (when-let [id (get-in shape [:applied-tokens token-attribute])] + (when-let [id (dm/get-in shape [:applied-tokens token-attribute])] (= (token-identifier token) id))) (defn token-applied? @@ -58,15 +59,18 @@ [token shapes token-attributes] (some #(token-applied? token % token-attributes) shapes)) -(defn shapes-ids-by-applied-attributes [token shapes token-attributes] - (reduce (fn [acc shape] - (let [applied-ids-by-attribute (->> (map #(when (token-attribute-applied? token shape %) - [% #{(:id shape)}]) - token-attributes) - (filter some?) - (into {}))] - (merge-with into acc applied-ids-by-attribute))) - {} shapes)) +(defn shapes-ids-by-applied-attributes + [token shapes token-attributes] + (let [conj* (fnil conj #{})] + (reduce (fn [result shape] + (let [shape-id (dm/get-prop shape :id)] + (->> token-attributes + (filter #(token-attribute-applied? token shape %)) + (reduce (fn [result attr] + (update result attr conj* shape-id)) + result)))) + {} + shapes))) (defn shapes-applied-all? [ids-by-attributes shape-ids attributes] (every? #(set/superset? (get ids-by-attributes %) shape-ids) attributes)) From 8e85d5a02a57be2c503c6efc5bc9d3273bc47e53 Mon Sep 17 00:00:00 2001 From: Andrey Antukh Date: Wed, 5 Feb 2025 15:52:28 +0100 Subject: [PATCH 21/25] :zap: Add performance oriented refactor to token sidebar and token-pill --- .../app/main/ui/workspace/tokens/sidebar.cljs | 36 +++-------- .../main/ui/workspace/tokens/token_pill.cljs | 62 ++++++++++++++----- 2 files changed, 55 insertions(+), 43 deletions(-) diff --git a/frontend/src/app/main/ui/workspace/tokens/sidebar.cljs b/frontend/src/app/main/ui/workspace/tokens/sidebar.cljs index 97f2233f5..656693e95 100644 --- a/frontend/src/app/main/ui/workspace/tokens/sidebar.cljs +++ b/frontend/src/app/main/ui/workspace/tokens/sidebar.cljs @@ -33,7 +33,6 @@ [app.main.ui.workspace.tokens.sets-context-menu :refer [sets-context-menu]] [app.main.ui.workspace.tokens.style-dictionary :as sd] [app.main.ui.workspace.tokens.theme-select :refer [theme-select]] - [app.main.ui.workspace.tokens.token :as wtt] [app.main.ui.workspace.tokens.token-pill :refer [token-pill*]] [app.util.array :as array] [app.util.dom :as dom] @@ -66,19 +65,10 @@ :sizing "expand" "add")) -(def ^:private - xf:map-id - (map :id)) - -(defn- all-selected? [token selected-shapes attributes] - (let [ids-by-attributes (wtt/shapes-ids-by-applied-attributes token selected-shapes attributes) - shape-ids (into #{} xf:map-id selected-shapes)] - (wtt/shapes-applied-all? ids-by-attributes shape-ids attributes))) - (mf/defc token-group* {::mf/private true} [{:keys [type tokens selected-shapes active-theme-tokens is-open]}] - (let [{:keys [modal attributes all-attributes title] :as token-type-props} + (let [{:keys [modal title]} (get wtch/token-properties type) tokens @@ -144,23 +134,13 @@ [:& cmm/asset-section-block {:role :content} [:div {:class (stl/css :token-pills-wrapper)} (for [token tokens] - (let [theme-token (get active-theme-tokens (:name token)) - multiple-selection (< 1 (count selected-shapes)) - full-applied (all-selected? token selected-shapes (or all-attributes attributes)) - applied (wtt/shapes-token-applied? token selected-shapes (or all-attributes attributes))] - - [:> token-pill* - {:key (:name token) - :token (d/nilv theme-token token) - :selected-shapes selected-shapes - :active-theme-tokens active-theme-tokens - :half-applied (or (and applied multiple-selection) - (and applied (not full-applied))) - :full-applied (if multiple-selection - false - applied) - :on-click on-token-pill-click - :on-context-menu on-context-menu}]))]])]])) + [:> token-pill* + {:key (:name token) + :token token + :selected-shapes selected-shapes + :active-theme-tokens active-theme-tokens + :on-click on-token-pill-click + :on-context-menu on-context-menu}])]])]])) (defn- get-sorted-token-groups "Separate token-types into groups of `empty` or `filled` depending if diff --git a/frontend/src/app/main/ui/workspace/tokens/token_pill.cljs b/frontend/src/app/main/ui/workspace/tokens/token_pill.cljs index c635fd444..b7316f814 100644 --- a/frontend/src/app/main/ui/workspace/tokens/token_pill.cljs +++ b/frontend/src/app/main/ui/workspace/tokens/token_pill.cljs @@ -141,17 +141,49 @@ (let [match (second (re-find #"\{([^}]+)\}" text))] (contains? active-tokens match))) +(def ^:private + xf:map-id + (map :id)) + +(defn- applied-all-attributes? + [token selected-shapes attributes] + (let [ids-by-attributes (wtt/shapes-ids-by-applied-attributes token selected-shapes attributes) + shape-ids (into #{} xf:map-id selected-shapes)] + (wtt/shapes-applied-all? ids-by-attributes shape-ids attributes))) + + (mf/defc token-pill* - [{:keys [on-click token full-applied on-context-menu half-applied selected-shapes active-theme-tokens]}] + {::mf/wrap [mf/memo]} + [{:keys [on-click token on-context-menu selected-shapes active-theme-tokens]}] (let [{:keys [name value errors]} token + token + (or (get active-theme-tokens (:name token)) token) + + has-selected? (pos? (count selected-shapes)) is-reference? (wtt/is-reference? token) contains-path? (str/includes? name ".") + {:keys [attributes all-attributes]} + (get wtch/token-properties (:type token)) + + full-applied? + (if has-selected? + (applied-all-attributes? token selected-shapes (or all-attributes attributes)) + true) + + applied? + (if has-selected? + (wtt/shapes-token-applied? token selected-shapes (or all-attributes attributes)) + false) + + half-applied? + (and applied? (not full-applied?)) + ;; FIXME: move to context or props can-edit? (:can-edit (deref refs/permissions)) - is-viewer (not can-edit?) + is-viewer? (not can-edit?) ref-not-in-active-set (and is-reference? @@ -174,9 +206,9 @@ token-status-id (cond - half-applied + half-applied? "token-status-partial" - full-applied + full-applied? "token-status-full" :else "token-status-non-applied") @@ -200,26 +232,26 @@ ;; FIXME: missing deps on-hover (mf/use-fn - (mf/deps selected-shapes is-viewer) + (mf/deps selected-shapes is-viewer?) (fn [event] (let [node (dom/get-current-target event) - title (generate-tooltip is-viewer (first selected-shapes) token - half-applied no-valid-value ref-not-in-active-set)] + title (generate-tooltip is-viewer? (first selected-shapes) token + half-applied? no-valid-value ref-not-in-active-set)] (dom/set-attribute! node "title" title))))] [:button {:class (stl/css-case :token-pill true :token-pill-default can-edit? - :token-pill-applied (and can-edit? (or half-applied full-applied)) + :token-pill-applied (and can-edit? has-selected? (or half-applied? full-applied?)) :token-pill-invalid (and can-edit? errors?) - :token-pill-invalid-applied (and full-applied errors? can-edit?) - :token-pill-viewer is-viewer - :token-pill-applied-viewer (and is-viewer - (or half-applied full-applied)) - :token-pill-invalid-viewer (and is-viewer + :token-pill-invalid-applied (and full-applied? errors? can-edit?) + :token-pill-viewer is-viewer? + :token-pill-applied-viewer (and is-viewer? has-selected? + (or half-applied? full-applied?)) + :token-pill-invalid-viewer (and is-viewer? errors?) - :token-pill-invalid-applied-viewer (and is-viewer - (and full-applied errors?))) + :token-pill-invalid-applied-viewer (and is-viewer? + (and full-applied? errors?))) :type "button" :on-click on-click :on-mouse-enter on-hover From 05a459ea19cfc447a2faad9dd87525f828b8dcf9 Mon Sep 17 00:00:00 2001 From: Andrey Antukh Date: Wed, 5 Feb 2025 15:59:38 +0100 Subject: [PATCH 22/25] :paperclip: Add missing license header --- frontend/src/app/main/ui/workspace/tokens/token_pill.cljs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/frontend/src/app/main/ui/workspace/tokens/token_pill.cljs b/frontend/src/app/main/ui/workspace/tokens/token_pill.cljs index b7316f814..f6ea9a07c 100644 --- a/frontend/src/app/main/ui/workspace/tokens/token_pill.cljs +++ b/frontend/src/app/main/ui/workspace/tokens/token_pill.cljs @@ -1,3 +1,9 @@ +;; This Source Code Form is subject to the terms of the Mozilla Public +;; License, v. 2.0. If a copy of the MPL was not distributed with this +;; file, You can obtain one at http://mozilla.org/MPL/2.0/. +;; +;; Copyright (c) KALEIDOS INC + (ns app.main.ui.workspace.tokens.token-pill (:require-macros [app.common.data.macros :as dm] From f0e5196659e94c6ff8bf6da7ab340c97836badd8 Mon Sep 17 00:00:00 2001 From: Andrey Antukh Date: Wed, 5 Feb 2025 18:12:14 +0100 Subject: [PATCH 23/25] :zap: Add minor optimization to token-pill component --- .../main/ui/workspace/tokens/token_pill.cljs | 22 ++++++++++--------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/frontend/src/app/main/ui/workspace/tokens/token_pill.cljs b/frontend/src/app/main/ui/workspace/tokens/token_pill.cljs index f6ea9a07c..2b7730a56 100644 --- a/frontend/src/app/main/ui/workspace/tokens/token_pill.cljs +++ b/frontend/src/app/main/ui/workspace/tokens/token_pill.cljs @@ -9,6 +9,7 @@ [app.common.data.macros :as dm] [app.main.style :as stl]) (:require + [app.common.data :as d] [app.common.files.helpers :as cfh] [app.main.refs :as refs] [app.main.ui.components.color-bullet :refer [color-bullet]] @@ -157,15 +158,11 @@ shape-ids (into #{} xf:map-id selected-shapes)] (wtt/shapes-applied-all? ids-by-attributes shape-ids attributes))) - (mf/defc token-pill* {::mf/wrap [mf/memo]} [{:keys [on-click token on-context-menu selected-shapes active-theme-tokens]}] (let [{:keys [name value errors]} token - token - (or (get active-theme-tokens (:name token)) token) - has-selected? (pos? (count selected-shapes)) is-reference? (wtt/is-reference? token) contains-path? (str/includes? name ".") @@ -175,12 +172,12 @@ full-applied? (if has-selected? - (applied-all-attributes? token selected-shapes (or all-attributes attributes)) + (applied-all-attributes? token selected-shapes (d/nilv all-attributes attributes)) true) applied? (if has-selected? - (wtt/shapes-token-applied? token selected-shapes (or all-attributes attributes)) + (wtt/shapes-token-applied? token selected-shapes (d/nilv all-attributes attributes)) false) half-applied? @@ -196,11 +193,16 @@ (not (contains-reference-value? value active-theme-tokens))) no-valid-value (seq errors) - errors? (or ref-not-in-active-set - no-valid-value) - color (when (wtt/color-token? token) - (wtt/resolved-token-bullet-color token)) + errors? + (or ref-not-in-active-set + no-valid-value) + + color + (when (wtt/color-token? token) + (let [theme-token (get active-theme-tokens (:name token))] + (or (wtt/resolved-token-bullet-color theme-token) + (wtt/resolved-token-bullet-color token)))) on-click (mf/use-fn From d46d80bd5c5c63768702d752776d6d8a3a58f235 Mon Sep 17 00:00:00 2001 From: Andrey Antukh Date: Wed, 5 Feb 2025 18:04:26 +0100 Subject: [PATCH 24/25] :zap: Use value equals on selected shapes set --- frontend/src/app/main/refs.cljs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/app/main/refs.cljs b/frontend/src/app/main/refs.cljs index 1dc8cf419..c5de2cd79 100644 --- a/frontend/src/app/main/refs.cljs +++ b/frontend/src/app/main/refs.cljs @@ -144,7 +144,7 @@ (l/derived (fn [{:keys [objects selected]}] (dsh/process-selected-shapes objects selected)) - selected-shapes-data)) + selected-shapes-data =)) (defn make-selected-ref [id] From 2bac94ad5c67f4f0d5379185fcad8c0cac71e049 Mon Sep 17 00:00:00 2001 From: Andrey Antukh Date: Wed, 5 Feb 2025 18:04:46 +0100 Subject: [PATCH 25/25] :zap: Use new call convention on all components of tokens sidebar --- .../app/main/ui/workspace/tokens/sidebar.cljs | 68 +++++++++++++------ 1 file changed, 46 insertions(+), 22 deletions(-) diff --git a/frontend/src/app/main/ui/workspace/tokens/sidebar.cljs b/frontend/src/app/main/ui/workspace/tokens/sidebar.cljs index 656693e95..54397f0d9 100644 --- a/frontend/src/app/main/ui/workspace/tokens/sidebar.cljs +++ b/frontend/src/app/main/ui/workspace/tokens/sidebar.cljs @@ -19,6 +19,7 @@ [app.main.ui.components.dropdown-menu :refer [dropdown-menu dropdown-menu-item*]] [app.main.ui.components.title-bar :refer [title-bar]] + [app.main.ui.context :as ctx] [app.main.ui.ds.buttons.button :refer [button*]] [app.main.ui.ds.buttons.icon-button :refer [icon-button*]] [app.main.ui.ds.foundations.typography.text :refer [text*]] @@ -161,15 +162,24 @@ [(seq (array/sort! empty)) (seq (array/sort! filled))]))) -(mf/defc themes-header - [_props] - (let [ordered-themes (mf/deref refs/workspace-token-themes-no-hidden) - can-edit? (:can-edit (deref refs/permissions)) +(mf/defc themes-header* + {::mf/private true} + [] + (let [ordered-themes + (mf/deref refs/workspace-token-themes-no-hidden) + + permissions + (mf/use-ctx ctx/permissions) + + can-edit? + (get permissions :can-edit) + open-modal (mf/use-fn (fn [e] (dom/stop-propagation e) (modal/show! :tokens/themes {})))] + [:div {:class (stl/css :themes-wrapper)} [:span {:class (stl/css :themes-header)} (tr "labels.themes")] (if (empty? ordered-themes) @@ -191,13 +201,24 @@ (tr "workspace.token.no-permission-themes"))} [:& theme-select]]))])) -(mf/defc add-set-button - [{:keys [on-open style]}] - (let [{:keys [on-create new-path]} (sets-context/use-context) - on-click #(do - (on-open) - (on-create [])) - can-edit? (:can-edit (deref refs/permissions))] +(mf/defc add-set-button* + {::mf/private true} + [{:keys [style]}] + (let [{:keys [on-create new-path]} + (sets-context/use-context) + + permissions + (mf/use-ctx ctx/permissions) + + can-edit? + (get permissions :can-edit) + + on-click + (mf/use-fn + (mf/deps on-create) + (fn [] + (on-create [])))] + (if (= style "inline") (when-not new-path (if can-edit? @@ -216,36 +237,39 @@ :on-click on-click :aria-label (tr "workspace.token.add set")}])))) -(mf/defc theme-sets-list - [{:keys [on-open]}] +(mf/defc theme-sets-list* + {::mf/private true} + [] (let [token-sets (mf/deref refs/workspace-ordered-token-sets) {:keys [new-path] :as ctx} (sets-context/use-context)] (if (and (empty? token-sets) (not new-path)) - [:& add-set-button {:on-open on-open - :style "inline"}] + [:> add-set-button* {:style "inline"}] [:& h/sortable-container {} [:& sets-list]]))) (mf/defc themes-sets-tab* {::mf/private true} [{:keys [resize-height]}] - (let [open? (mf/use-state true) - on-open (mf/use-fn #(reset! open? true)) - can-edit? (:can-edit (deref refs/permissions))] + (let [permissions + (mf/use-ctx ctx/permissions) + + can-edit? + (get permissions :can-edit)] + [:& sets-context/provider {} [:& sets-context-menu] [:article {:data-testid "token-themes-sets-sidebar" :class (stl/css :sets-section-wrapper) :style {"--resize-height" (str resize-height "px")}} [:div {:class (stl/css :sets-sidebar)} - [:& themes-header] + [:> themes-header*] [:div {:class (stl/css :sidebar-header)} [:& title-bar {:title (tr "labels.sets")} (when can-edit? - [:& add-set-button {:on-open on-open - :style "header"}])]] - [:& theme-sets-list {:on-open on-open}]]]])) + [:> add-set-button* {:style "header"}])]] + + [:> theme-sets-list* {}]]]])) (mf/defc tokens-tab* []