diff --git a/common/src/app/common/types/token.cljc b/common/src/app/common/types/token.cljc index 651cb58ef6..20be853b8f 100644 --- a/common/src/app/common/types/token.cljc +++ b/common/src/app/common/types/token.cljc @@ -74,7 +74,8 @@ (sm/register! ::color [:map - [:color {:optional true} token-name-ref]]) + [:fill {:optional true} token-name-ref] + [:stroke-color {:optional true} token-name-ref]]) (def color-keys (schema-keys ::color)) diff --git a/common/src/app/common/types/tokens_lib.cljc b/common/src/app/common/types/tokens_lib.cljc index 397072f552..c79bf422eb 100644 --- a/common/src/app/common/types/tokens_lib.cljc +++ b/common/src/app/common/types/tokens_lib.cljc @@ -147,9 +147,11 @@ Token references are strings delimited by curly braces. E.g.: {foo.bar.baz} -> foo.bar.baz" [token-value] - (some->> (re-seq #"\{([^}]*)\}" token-value) - (map second) - (into #{}))) + (if (string? token-value) + (some->> (re-seq #"\{([^}]*)\}" token-value) + (map second) + (into #{})) + #{})) (defn token-value-self-reference? "Check if the token is self referencing with its `token-name` in `token-value`. diff --git a/common/test/common_tests/types/tokens_lib_test.cljc b/common/test/common_tests/types/tokens_lib_test.cljc index 2c47b3b96e..e4e04dae25 100644 --- a/common/test/common_tests/types/tokens_lib_test.cljc +++ b/common/test/common_tests/types/tokens_lib_test.cljc @@ -398,7 +398,6 @@ :type :boolean :value true))) - expected-order (ctob/get-ordered-set-names tokens-lib) expected-tokens (ctob/get-active-themes-set-tokens tokens-lib) expected-token-names (mapv key expected-tokens)] @@ -1140,3 +1139,4 @@ (t/is (= @with-prev-tokens-lib @tokens-lib))) (t/testing "fresh tokens library is also equal" (= @with-empty-tokens-lib @tokens-lib))))))) + diff --git a/frontend/package.json b/frontend/package.json index 66be04638f..5813d4c8c7 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -54,7 +54,6 @@ "@storybook/react-vite": "^8.3.6", "@types/node": "^22.7.7", "autoprefixer": "^10.4.20", - "bun": "^1.1.25", "concurrently": "^9.0.1", "esbuild": "^0.24.0", "express": "^4.21.1", @@ -120,7 +119,7 @@ "rxjs": "8.0.0-alpha.14", "sax": "^1.4.1", "source-map-support": "^0.5.21", - "style-dictionary": "^4.1.4", + "style-dictionary": "4.0.0-prerelease.34", "tdigest": "^0.1.2", "tinycolor2": "npm:^1.6.0", "ua-parser-js": "2.0.0-rc.1", diff --git a/frontend/shadow-cljs.edn b/frontend/shadow-cljs.edn index 56e1678e4d..a0673a0e9c 100644 --- a/frontend/shadow-cljs.edn +++ b/frontend/shadow-cljs.edn @@ -183,4 +183,3 @@ {:fn-invoke-direct true :elide-asserts true :anon-fn-naming-policy :off}}}}} - diff --git a/frontend/src/app/main/ui/workspace/tokens/changes.cljs b/frontend/src/app/main/ui/workspace/tokens/changes.cljs index 320dca9488..8c31b729b8 100644 --- a/frontend/src/app/main/ui/workspace/tokens/changes.cljs +++ b/frontend/src/app/main/ui/workspace/tokens/changes.cljs @@ -128,13 +128,20 @@ {:reg-objects? true :attrs [:strokes]})) -(defn update-color - [value shape-ids] +(defn update-color [f value shape-ids] (let [color (some->> value (tinycolor/valid-color) (tinycolor/->hex) (str "#"))] - (wdc/change-fill shape-ids {:color color} 0))) + (f shape-ids {:color color} 0))) + +(defn update-fill + [value shape-ids] + (update-color wdc/change-fill value shape-ids)) + +(defn update-stroke-color + [value shape-ids] + (update-color wdc/change-stroke value shape-ids)) (defn update-shape-dimensions [value shape-ids attributes] (ptk/reify ::update-shape-dimensions 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 274ad90a5d..b8ec3af160 100644 --- a/frontend/src/app/main/ui/workspace/tokens/context_menu.cljs +++ b/frontend/src/app/main/ui/workspace/tokens/context_menu.cljs @@ -184,6 +184,9 @@ :r3 "Bottom Right"} :on-update-shape-all wtch/update-shape-radius-all :on-update-shape wtch/update-shape-radius-single-corner}) + :color (fn [context-data] + [(generic-attribute-actions #{:fill} "Fill" (assoc context-data :on-update-shape wtch/update-fill)) + (generic-attribute-actions #{:stroke-color} "Stroke" (assoc context-data :on-update-shape wtch/update-stroke-color))]) :spacing spacing-attribute-actions :sizing sizing-attribute-actions :rotation (partial generic-attribute-actions #{:rotation} "Rotation") diff --git a/frontend/src/app/main/ui/workspace/tokens/form.cljs b/frontend/src/app/main/ui/workspace/tokens/form.cljs index 04810d8799..6c9ea8fd50 100644 --- a/frontend/src/app/main/ui/workspace/tokens/form.cljs +++ b/frontend/src/app/main/ui/workspace/tokens/form.cljs @@ -7,7 +7,6 @@ (ns app.main.ui.workspace.tokens.form (:require-macros [app.main.style :as stl]) (:require - ;; ["lodash.debounce" :as debounce] [app.common.colors :as c] [app.common.data :as d] [app.common.data.macros :as dm] @@ -113,16 +112,20 @@ Token names should only contain letters and digits separated by . characters.")} (p/rejected {:errors [(wte/get-error-code :error.token/direct-self-reference)]}) :else - (-> (update tokens token-name merge {:value value - :name token-name - :type (:type token)}) - (sd/resolve-tokens+) - (p/then - (fn [resolved-tokens] - (let [{:keys [errors resolved-value] :as resolved-token} (get resolved-tokens token-name)] - (cond - resolved-value (p/resolved resolved-token) - :else (p/rejected {:errors (or errors (wte/get-error-code :error/unknown-error))}))))))))) + (let [tokens' (cond-> tokens + ;; Remove previous token when renaming a token + (not= name-value (:name token)) (dissoc (:name token)) + :always (update token-name #(ctob/make-token (merge % {:value value + :name token-name + :type (:type token)}))))] + (-> tokens' + (sd/resolve-tokens-interactive+) + (p/then + (fn [resolved-tokens] + (let [{:keys [errors resolved-value] :as resolved-token} (get resolved-tokens token-name)] + (cond + resolved-value (p/resolved resolved-token) + :else (p/rejected {:errors (or errors (wte/get-error-code :error/unknown-error))})))))))))) (defn use-debonced-resolve-callback "Resolves a token values using `StyleDictionary`. @@ -201,8 +204,7 @@ Token names should only contain letters and digits separated by . characters.")} (mf/defc form {::mf/wrap-props false} [{:keys [token token-type action selected-token-set-id]}] - (let [validate-name? (mf/use-state (not (:id token))) - token (or token {:type token-type}) + (let [token (or token {:type token-type}) 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) @@ -219,6 +221,7 @@ Token names should only contain letters and digits separated by . characters.")} (d/dissoc-in token-path)))) ;; Name + touched-name? (mf/use-state false) name-ref (mf/use-var (:name token)) name-errors (mf/use-state nil) validate-name @@ -234,15 +237,14 @@ Token names should only contain letters and digits separated by . characters.")} (uf/debounce (fn [e] (let [value (dom/get-target-val e) errors (validate-name value)] - ;; Prevent showing error when just going to another field on a new token - (when-not (and validate-name? (str/empty? value)) - (reset! validate-name? false) + (when touched-name? (reset! name-errors errors)))))) on-update-name (mf/use-fn (mf/deps on-update-name-debounced) (fn [e] + (reset! touched-name? true) (reset! name-ref (dom/get-target-val e)) (on-update-name-debounced e))) @@ -311,10 +313,10 @@ Token names should only contain letters and digits separated by . characters.")} (mf/deps validate-name validate-descripion token resolved-tokens) (fn [e] (dom/prevent-default e) - ;; We have to re-validate the current form values before submitting - ;; because the validation is asynchronous/debounced - ;; and the user might have edited a valid form to make it invalid, - ;; and press enter before the next validations could return. + ;; We have to re-validate the current form values before submitting + ;; because the validation is asynchronous/debounced + ;; and the user might have edited a valid form to make it invalid, + ;; and press enter before the next validations could return. (let [final-name (finalize-name @name-ref) valid-name?+ (-> (validate-name final-name) schema-validation->promise) final-value (finalize-value @value-ref) @@ -327,8 +329,8 @@ Token names should only contain letters and digits separated by . characters.")} :token token :tokens resolved-tokens})]) (p/finally (fn [result err] - ;; The result should be a vector of all resolved validations - ;; We do not handle the error case as it will be handled by the components validations + ;; The result should be a vector of all resolved validations + ;; We do not handle the error case as it will be handled by the components validations (when (and (seq result) (not err)) (st/emit! (dt/update-create-token {:token (ctob/make-token :name final-name :type (or (:type token) token-type) @@ -386,7 +388,7 @@ Token names should only contain letters and digits separated by . characters.")} :on-change on-update-value :ref value-input-ref} :render-right (when color? - (mf/fnc color-bullet [] + (mf/fnc drop-down-button [] [:div {:class (stl/css :color-bullet) :on-click #(swap! color-ramp-open? not)} (if-let [hex (some-> @color tinycolor/valid-color tinycolor/->hex)] diff --git a/frontend/src/app/main/ui/workspace/tokens/modals/themes.cljs b/frontend/src/app/main/ui/workspace/tokens/modals/themes.cljs index b8399ae9a4..0f29642585 100644 --- a/frontend/src/app/main/ui/workspace/tokens/modals/themes.cljs +++ b/frontend/src/app/main/ui/workspace/tokens/modals/themes.cljs @@ -366,4 +366,4 @@ :aria-label (tr "labels.close") :variant "action" :icon "close"}] - [:& themes-modal-body]]])) \ No newline at end of file + [:& themes-modal-body]]])) diff --git a/frontend/src/app/main/ui/workspace/tokens/tinycolor.cljs b/frontend/src/app/main/ui/workspace/tokens/tinycolor.cljs index 9a8d74f101..1770fb5861 100644 --- a/frontend/src/app/main/ui/workspace/tokens/tinycolor.cljs +++ b/frontend/src/app/main/ui/workspace/tokens/tinycolor.cljs @@ -4,7 +4,7 @@ This library was chosen as it is already used by StyleDictionary, so there is no extra dependency cost and there was no clojure alternatives with all the necessary features." (:require - ["tinycolor2" :as tinycolor])) + ["tinycolor2$default" :as tinycolor])) (defn tinycolor? [^js x] (and (instance? tinycolor x) (.isValid x))) diff --git a/frontend/src/app/main/ui/workspace/tokens/token_types.cljs b/frontend/src/app/main/ui/workspace/tokens/token_types.cljs index ce4c5cbf31..b8247a288d 100644 --- a/frontend/src/app/main/ui/workspace/tokens/token_types.cljs +++ b/frontend/src/app/main/ui/workspace/tokens/token_types.cljs @@ -24,7 +24,7 @@ :color {:title "Color" :attributes ctt/color-keys - :on-update-shape wtch/update-color + :on-update-shape wtch/update-fill :modal {:key :tokens/color :fields [{:label "Color" :key :color}]}} diff --git a/frontend/src/app/main/ui/workspace/tokens/update.cljs b/frontend/src/app/main/ui/workspace/tokens/update.cljs index d0c6dbec68..bc85bea839 100644 --- a/frontend/src/app/main/ui/workspace/tokens/update.cljs +++ b/frontend/src/app/main/ui/workspace/tokens/update.cljs @@ -19,7 +19,8 @@ (def attributes->shape-update {#{:rx :ry} (fn [v ids _] (wtch/update-shape-radius-all v ids)) #{:r1 :r2 :r3 :r4} wtch/update-shape-radius-single-corner - ctt/color-keys wtch/update-color + #{:fill} wtch/update-fill + #{:stroke-color} wtch/update-stroke-color ctt/stroke-width-keys wtch/update-stroke-width ctt/sizing-keys wtch/update-shape-dimensions ctt/opacity-keys wtch/update-opacity diff --git a/frontend/yarn.lock b/frontend/yarn.lock index a4afad7155..e602e47918 100644 --- a/frontend/yarn.lock +++ b/frontend/yarn.lock @@ -218,7 +218,7 @@ __metadata: languageName: node linkType: hard -"@bundled-es-modules/glob@npm:^10.4.2": +"@bundled-es-modules/glob@npm:^10.3.13": version: 10.4.2 resolution: "@bundled-es-modules/glob@npm:10.4.2" dependencies: @@ -234,7 +234,7 @@ __metadata: languageName: node linkType: hard -"@bundled-es-modules/memfs@npm:^4.9.4": +"@bundled-es-modules/memfs@npm:^4.8.1": version: 4.9.4 resolution: "@bundled-es-modules/memfs@npm:4.9.4" dependencies: @@ -766,62 +766,6 @@ __metadata: languageName: node linkType: hard -"@oven/bun-darwin-aarch64@npm:1.1.34": - version: 1.1.34 - resolution: "@oven/bun-darwin-aarch64@npm:1.1.34" - conditions: os=darwin & cpu=arm64 - languageName: node - linkType: hard - -"@oven/bun-darwin-x64-baseline@npm:1.1.34": - version: 1.1.34 - resolution: "@oven/bun-darwin-x64-baseline@npm:1.1.34" - conditions: os=darwin & cpu=x64 - languageName: node - linkType: hard - -"@oven/bun-darwin-x64@npm:1.1.34": - version: 1.1.34 - resolution: "@oven/bun-darwin-x64@npm:1.1.34" - conditions: os=darwin & cpu=x64 - languageName: node - linkType: hard - -"@oven/bun-linux-aarch64@npm:1.1.34": - version: 1.1.34 - resolution: "@oven/bun-linux-aarch64@npm:1.1.34" - conditions: os=linux & cpu=arm64 - languageName: node - linkType: hard - -"@oven/bun-linux-x64-baseline@npm:1.1.34": - version: 1.1.34 - resolution: "@oven/bun-linux-x64-baseline@npm:1.1.34" - conditions: os=linux & cpu=x64 - languageName: node - linkType: hard - -"@oven/bun-linux-x64@npm:1.1.34": - version: 1.1.34 - resolution: "@oven/bun-linux-x64@npm:1.1.34" - conditions: os=linux & cpu=x64 - languageName: node - linkType: hard - -"@oven/bun-windows-x64-baseline@npm:1.1.34": - version: 1.1.34 - resolution: "@oven/bun-windows-x64-baseline@npm:1.1.34" - conditions: os=win32 & cpu=x64 - languageName: node - linkType: hard - -"@oven/bun-windows-x64@npm:1.1.34": - version: 1.1.34 - resolution: "@oven/bun-windows-x64@npm:1.1.34" - conditions: os=win32 & cpu=x64 - languageName: node - linkType: hard - "@parcel/watcher-android-arm64@npm:2.5.0": version: 2.5.0 resolution: "@parcel/watcher-android-arm64@npm:2.5.0" @@ -2472,43 +2416,6 @@ __metadata: languageName: node linkType: hard -"bun@npm:^1.1.25": - version: 1.1.34 - resolution: "bun@npm:1.1.34" - dependencies: - "@oven/bun-darwin-aarch64": "npm:1.1.34" - "@oven/bun-darwin-x64": "npm:1.1.34" - "@oven/bun-darwin-x64-baseline": "npm:1.1.34" - "@oven/bun-linux-aarch64": "npm:1.1.34" - "@oven/bun-linux-x64": "npm:1.1.34" - "@oven/bun-linux-x64-baseline": "npm:1.1.34" - "@oven/bun-windows-x64": "npm:1.1.34" - "@oven/bun-windows-x64-baseline": "npm:1.1.34" - dependenciesMeta: - "@oven/bun-darwin-aarch64": - optional: true - "@oven/bun-darwin-x64": - optional: true - "@oven/bun-darwin-x64-baseline": - optional: true - "@oven/bun-linux-aarch64": - optional: true - "@oven/bun-linux-x64": - optional: true - "@oven/bun-linux-x64-baseline": - optional: true - "@oven/bun-windows-x64": - optional: true - "@oven/bun-windows-x64-baseline": - optional: true - bin: - bun: bin/bun.exe - bunx: bin/bun.exe - checksum: 10c0/d7a69a3e6a7545d7c76edaf86633f23f791641732fb0f5a6378f1503d267d03a3353afcc01e735acb6981b12acc83827d73bca701f8e3f62183bb00ad7e22e9d - conditions: (os=darwin | os=linux | os=win32) & (cpu=arm64 | cpu=x64) - languageName: node - linkType: hard - "bytes@npm:3.1.2, bytes@npm:^3.0.0": version: 3.1.2 resolution: "bytes@npm:3.1.2" @@ -4403,7 +4310,6 @@ __metadata: "@tokens-studio/sd-transforms": "npm:^0.16.1" "@types/node": "npm:^22.7.7" autoprefixer: "npm:^10.4.20" - bun: "npm:^1.1.25" compression: "npm:^1.7.4" concurrently: "npm:^9.0.1" date-fns: "npm:^4.1.0" @@ -4454,7 +4360,7 @@ __metadata: shadow-cljs: "npm:2.28.18" source-map-support: "npm:^0.5.21" storybook: "npm:^8.3.6" - style-dictionary: "npm:^4.1.4" + style-dictionary: "npm:4.0.0-prerelease.34" svg-sprite: "npm:^2.0.4" tdigest: "npm:^0.1.2" tinycolor2: "npm:^1.6.0" @@ -8590,13 +8496,13 @@ __metadata: languageName: node linkType: hard -"style-dictionary@npm:^4.1.4": - version: 4.1.4 - resolution: "style-dictionary@npm:4.1.4" +"style-dictionary@npm:4.0.0-prerelease.34": + version: 4.0.0-prerelease.34 + resolution: "style-dictionary@npm:4.0.0-prerelease.34" dependencies: "@bundled-es-modules/deepmerge": "npm:^4.3.1" - "@bundled-es-modules/glob": "npm:^10.4.2" - "@bundled-es-modules/memfs": "npm:^4.9.4" + "@bundled-es-modules/glob": "npm:^10.3.13" + "@bundled-es-modules/memfs": "npm:^4.8.1" "@zip.js/zip.js": "npm:^2.7.44" chalk: "npm:^5.3.0" change-case: "npm:^5.3.0" @@ -8608,7 +8514,7 @@ __metadata: tinycolor2: "npm:^1.6.0" bin: style-dictionary: bin/style-dictionary.js - checksum: 10c0/b88e2f94615bc851e2e797e685863911dbb875d312bf1571a3be6b6a9dde7e0b324d83495f153446eceefe93ec119c80e2ca032a600818dcecc72174d285e429 + checksum: 10c0/775d00c0e6aec7749dd5554c448550bc0793aaff9ab028d61ba219476ffa827d3e11866d326c34a27d3e848156b885e476beaade0909fe6b174a50e857dd5009 languageName: node linkType: hard