diff --git a/frontend/src/app/main/ui/workspace/tokens/changes.cljs b/frontend/src/app/main/ui/workspace/tokens/changes.cljs index b2238b034..e9328fed1 100644 --- a/frontend/src/app/main/ui/workspace/tokens/changes.cljs +++ b/frontend/src/app/main/ui/workspace/tokens/changes.cljs @@ -139,11 +139,10 @@ :attrs [:strokes]})) (defn update-color [f value shape-ids] - (when-let [color (some->> value - (tinycolor/valid-color) - (tinycolor/->hex) - (str "#"))] - (f shape-ids {:color color} 0 {:ignore-touched true}))) + (when-let [tc (tinycolor/valid-color value)] + (let [hex (tinycolor/->hex-string tc) + opacity (tinycolor/alpha tc)] + (f shape-ids {:color hex :opacity opacity} 0 {:ignore-touched true})))) (defn update-fill [value shape-ids] diff --git a/frontend/src/app/main/ui/workspace/tokens/components/controls/input_token_color_bullet.cljs b/frontend/src/app/main/ui/workspace/tokens/components/controls/input_token_color_bullet.cljs index c6aaa1ee1..4ff70d333 100644 --- a/frontend/src/app/main/ui/workspace/tokens/components/controls/input_token_color_bullet.cljs +++ b/frontend/src/app/main/ui/workspace/tokens/components/controls/input_token_color_bullet.cljs @@ -8,7 +8,7 @@ (:require-macros [app.main.style :as stl]) (:require [app.main.ui.components.color-bullet :refer [color-bullet]] - [app.main.ui.workspace.tokens.tinycolor :as tinycolor] + [app.main.ui.workspace.tokens.token :as wtt] [rumext.v2 :as mf])) (def ^:private schema::input-token-color-bullet @@ -22,6 +22,6 @@ [{:keys [color on-click]}] [:div {:class (stl/css :input-token-color-bullet) :on-click on-click} - (if-let [hex (some-> color tinycolor/valid-color tinycolor/->hex)] - [:> color-bullet {:color hex :mini true}] + (if-let [color' (wtt/color-bullet-color color)] + [:> color-bullet {:color color' :mini true}] [:div {:class (stl/css :input-token-color-bullet-placeholder)}])]) diff --git a/frontend/src/app/main/ui/workspace/tokens/form.cljs b/frontend/src/app/main/ui/workspace/tokens/form.cljs index 16bb899f8..4e308efc3 100644 --- a/frontend/src/app/main/ui/workspace/tokens/form.cljs +++ b/frontend/src/app/main/ui/workspace/tokens/form.cljs @@ -160,13 +160,14 @@ (defn hex->value [hex] (when-let [tc (tinycolor/valid-color hex)] - (let [hex (str "#" (tinycolor/->hex tc)) + (let [hex (tinycolor/->hex-string tc) + alpha (tinycolor/alpha tc) [r g b] (c/hex->rgb hex) [h s v] (c/hex->hsv hex)] {:hex hex :r r :g g :b b :h h :s s :v v - :alpha 1}))) + :alpha alpha}))) (mf/defc ramp* [{:keys [color on-change]}] @@ -182,16 +183,15 @@ on-change' (mf/use-fn (mf/deps on-change) - (fn [{:keys [hex]}] + (fn [{:keys [hex alpha]}] (let [dragging? (mf/ref-val dragging-ref)] (when-not (and dragging? hex) - (on-change hex)))))] + (on-change hex alpha)))))] (colorpicker/use-color-picker-css-variables! wrapper-node-ref (hex->value color)) [:div {:ref wrapper-node-ref} [:> ramp-selector* {:color (hex->value color) - :disable-opacity true :on-start-drag on-start-drag :on-finish-drag on-finish-drag :on-change on-change'}]])) @@ -313,10 +313,15 @@ (on-update-value-debounced value)))) on-update-color (mf/use-fn (mf/deps on-update-value-debounced) - (fn [hex-value] - (reset! value-ref hex-value) - (set! (.-value (mf/ref-val value-input-ref)) hex-value) - (on-update-value-debounced hex-value))) + (fn [hex-value alpha] + (let [color-value (if (= 1 alpha) + hex-value + (-> (tinycolor/valid-color hex-value) + (tinycolor/set-alpha alpha) + (tinycolor/->rgba-string)))] + (reset! value-ref color-value) + (dom/set-value! (mf/ref-val value-input-ref) color-value) + (on-update-value-debounced color-value)))) on-display-colorpicker (mf/use-fn (mf/deps color-ramp-open?) diff --git a/frontend/src/app/main/ui/workspace/tokens/tinycolor.cljs b/frontend/src/app/main/ui/workspace/tokens/tinycolor.cljs index 1770fb586..0fb77eff4 100644 --- a/frontend/src/app/main/ui/workspace/tokens/tinycolor.cljs +++ b/frontend/src/app/main/ui/workspace/tokens/tinycolor.cljs @@ -13,15 +13,22 @@ (let [tc (tinycolor color-str)] (when (.isValid tc) tc))) -(defn ->hex [^js tc] +(defn ->hex-string [^js tc] (assert (tinycolor? tc)) - (.toHex tc)) + (.toHexString tc)) + +(defn ->rgba-string [^js tc] + (assert (tinycolor? tc)) + (.toRgbString tc)) (defn color-format [^js tc] (assert (tinycolor? tc)) (.getFormat tc)) -(comment - (some-> (valid-color "red") ->hex) - (some-> (valid-color "red") color-format) - nil) +(defn alpha [^js tc] + (assert (tinycolor? tc)) + (.getAlpha tc)) + +(defn set-alpha [^js tc alpha] + (assert (tinycolor? tc)) + (.setAlpha tc alpha)) diff --git a/frontend/src/app/main/ui/workspace/tokens/token.cljs b/frontend/src/app/main/ui/workspace/tokens/token.cljs index 3fd66ed7a..97f9c7701 100644 --- a/frontend/src/app/main/ui/workspace/tokens/token.cljs +++ b/frontend/src/app/main/ui/workspace/tokens/token.cljs @@ -88,19 +88,6 @@ {:path (seq path) :selector selector})) -(defn token-names-tree-id-map [tokens] - (reduce - (fn [acc [_ {:keys [name] :as token}]] - (when (string? name) - (let [temp-id (random-uuid) - token (assoc token :temp/id temp-id)] - (-> acc - (assoc-in (concat [:tree] (token-name->path name)) token) - (assoc-in [:ids-map temp-id] token))))) - {:tree {} - :ids-map {}} - tokens)) - (defn token-name-path-exists? "Traverses the path from `token-name` down a `token-tree` and checks if a token at that path exists. @@ -135,8 +122,13 @@ (defn color-token? [token] (= (:type token) :color)) -(defn resolved-value-hex [{:keys [resolved-value] :as token}] +(defn color-bullet-color [token-color-value] + (when-let [tc (tinycolor/valid-color token-color-value)] + (if (tinycolor/alpha tc) + {:color (tinycolor/->hex-string tc) + :opacity (tinycolor/alpha tc)} + (tinycolor/->hex-string tc)))) + +(defn resolved-token-bullet-color [{:keys [resolved-value] :as token}] (when (and resolved-value (color-token? token)) - (some->> (tinycolor/valid-color resolved-value) - (tinycolor/->hex) - (str "#")))) + (color-bullet-color resolved-value))) 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 c585eedc0..209aaed62 100644 --- a/frontend/src/app/main/ui/workspace/tokens/token_pill.cljs +++ b/frontend/src/app/main/ui/workspace/tokens/token_pill.cljs @@ -154,10 +154,10 @@ errors? (or ref-not-in-active-set no-valid-value) color (when (seq (ctob/find-token-value-references value)) - (wtt/resolved-value-hex theme-token)) + (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-value-hex token)) + color (or color (wtt/resolved-token-bullet-color token)) on-click (mf/use-callback diff --git a/frontend/test/frontend_tests/tokens/logic/token_actions_test.cljs b/frontend/test/frontend_tests/tokens/logic/token_actions_test.cljs index eb86d0252..e3200c7c8 100644 --- a/frontend/test/frontend_tests/tokens/logic/token_actions_test.cljs +++ b/frontend/test/frontend_tests/tokens/logic/token_actions_test.cljs @@ -131,11 +131,17 @@ (let [color-token {:name "color.primary" :value "red" :type :color} + color-alpha-token {:name "color.secondary" + :value "rgba(255,0,0,0.5)" + :type :color} file (-> (setup-file-with-tokens) (update-in [:data :tokens-lib] - #(ctob/add-token-in-set % "Set A" (ctob/make-token color-token)))) + #(-> % + (ctob/add-token-in-set "Set A" (ctob/make-token color-token)) + (ctob/add-token-in-set "Set A" (ctob/make-token color-alpha-token))))) store (ths/setup-store file) rect-1 (cths/get-shape file :rect-1) + rect-2 (cths/get-shape file :rect-2) events [(wtch/apply-token {:shape-ids [(:id rect-1)] :attributes #{:color} :token (toht/get-token file "color.primary") @@ -143,18 +149,40 @@ (wtch/apply-token {:shape-ids [(:id rect-1)] :attributes #{:stroke-color} :token (toht/get-token file "color.primary") + :on-update-shape wtch/update-stroke-color}) + (wtch/apply-token {:shape-ids [(:id rect-2)] + :attributes #{:color} + :token (toht/get-token file "color.secondary") + :on-update-shape wtch/update-fill}) + (wtch/apply-token {:shape-ids [(:id rect-2)] + :attributes #{:stroke-color} + :token (toht/get-token file "color.secondary") :on-update-shape wtch/update-stroke-color})]] (tohs/run-store-async store done events (fn [new-state] (let [file' (ths/get-file-from-state new-state) token-target' (toht/get-token file' "rotation.medium") - rect-1' (cths/get-shape file' :rect-1)] - (t/is (some? (:applied-tokens rect-1'))) - (t/is (= (:fill (:applied-tokens rect-1')) (:name token-target'))) - (t/is (= (get-in rect-1' [:fills 0 :fill-color]) "#ff0000")) - (t/is (= (:stroke (:applied-tokens rect-1')) (:name token-target'))) - (t/is (= (get-in rect-1' [:strokes 0 :stroke-color]) "#ff0000"))))))))) + rect-1' (cths/get-shape file' :rect-1) + rect-2' (cths/get-shape file' :rect-2)] + (t/testing "regular color" + (t/is (some? (:applied-tokens rect-1'))) + + (t/is (= (:fill (:applied-tokens rect-1')) (:name token-target'))) + (t/is (= (get-in rect-1' [:fills 0 :fill-color]) "#ff0000")) + + (t/is (= (:stroke (:applied-tokens rect-1')) (:name token-target'))) + (t/is (= (get-in rect-1' [:strokes 0 :stroke-color]) "#ff0000"))) + (t/testing "color with alpha channel" + (t/is (some? (:applied-tokens rect-2'))) + + (t/is (= (:fill (:applied-tokens rect-2')) (:name token-target'))) + (t/is (= (get-in rect-2' [:fills 0 :fill-color]) "#ff0000")) + (t/is (= (get-in rect-2' [:fills 0 :fill-opacity]) 0.5)) + + (t/is (= (:stroke (:applied-tokens rect-2')) (:name token-target'))) + (t/is (= (get-in rect-2' [:strokes 0 :stroke-color]) "#ff0000")) + (t/is (= (get-in rect-2' [:strokes 0 :stroke-opacity]) 0.5)))))))))) (t/deftest test-apply-dimensions (t/testing "applies dimensions token and updates the shapes width and height"