diff --git a/common/src/app/common/colors.cljc b/common/src/app/common/colors.cljc index 932d79d635..64a940ad95 100644 --- a/common/src/app/common/colors.cljc +++ b/common/src/app/common/colors.cljc @@ -248,11 +248,12 @@ [[h s brightness]] (if (= s 0) [brightness brightness brightness] - (let [sextant (int (mth/floor (/ h 60))) - remainder (- (/ h 60) sextant) - val1 (int (* brightness (- 1 s))) - val2 (int (* brightness (- 1 (* s remainder)))) - val3 (int (* brightness (- 1 (* s (- 1 remainder)))))] + (let [sextant (int (mth/floor (/ h 60))) + remainder (- (/ h 60) sextant) + brightness (d/nilv brightness 0) + val1 (int (* brightness (- 1 s))) + val2 (int (* brightness (- 1 (* s remainder)))) + val3 (int (* brightness (- 1 (* s (- 1 remainder)))))] (case sextant 1 [val2 brightness val1] 2 [val1 brightness val3] diff --git a/frontend/src/app/main/ui/workspace/colorpicker.cljs b/frontend/src/app/main/ui/workspace/colorpicker.cljs index 28fd4a0f6b..c774a780f8 100644 --- a/frontend/src/app/main/ui/workspace/colorpicker.cljs +++ b/frontend/src/app/main/ui/workspace/colorpicker.cljs @@ -33,7 +33,7 @@ [app.main.ui.workspace.colorpicker.harmony :refer [harmony-selector]] [app.main.ui.workspace.colorpicker.hsva :refer [hsva-selector]] [app.main.ui.workspace.colorpicker.libraries :refer [libraries]] - [app.main.ui.workspace.colorpicker.ramp :refer [ramp-selector]] + [app.main.ui.workspace.colorpicker.ramp :refer [ramp-selector*]] [app.main.ui.workspace.colorpicker.shortcuts :as sc] [app.util.dom :as dom] [app.util.i18n :as i18n :refer [tr]] @@ -346,7 +346,7 @@ [:div {:class (stl/css :picker-detail-wrapper)} [:div {:class (stl/css :center-circle)}] [:canvas#picker-detail {:class (stl/css :picker-detail) :width 256 :height 140}]] - [:& ramp-selector + [:> ramp-selector* {:color current-color :disable-opacity disable-opacity :on-change handle-change-color diff --git a/frontend/src/app/main/ui/workspace/colorpicker/ramp.cljs b/frontend/src/app/main/ui/workspace/colorpicker/ramp.cljs index 970525d3c1..83a419dcac 100644 --- a/frontend/src/app/main/ui/workspace/colorpicker/ramp.cljs +++ b/frontend/src/app/main/ui/workspace/colorpicker/ramp.cljs @@ -8,6 +8,7 @@ (:require-macros [app.main.style :as stl]) (:require [app.common.colors :as cc] + [app.common.data :as d] [app.common.math :as mth] [app.main.ui.components.color-bullet :as cb] [app.main.ui.workspace.colorpicker.slider-selector :refer [slider-selector]] @@ -51,48 +52,82 @@ :top (str (* 100 (- 1 (/ value 255))) "%")}}]])) -(mf/defc ramp-selector [{:keys [color disable-opacity on-change on-start-drag on-finish-drag]}] - (let [{hex :hex - hue :h saturation :s value :v alpha :alpha} color +(defn- enrich-color-map + [{:keys [h s v] :as color}] + (let [h (d/nilv h 0) + s (d/nilv s 0) + v (d/nilv v 0) + hsv [h s v] + [r g b] (cc/hsv->rgb hsv)] + (assoc color + :hex (cc/hsv->hex hsv) + :h h :s s :v v + :r r :g g :b b))) + +(mf/defc ramp-selector* + [{:keys [color disable-opacity on-change on-start-drag on-finish-drag]}] + (let [internal-color* + (mf/use-state #(enrich-color-map color)) + + internal-color + (deref internal-color*) + + h (get internal-color :h) + s (get internal-color :s) + v (get internal-color :v) + hex (get internal-color :hex) + alpha (get internal-color :alpha) + + bullet-color + (mf/with-memo [hex alpha] + {:color hex :opacity alpha}) on-change-value-saturation - (fn [new-saturation new-value] - (let [hex (cc/hsv->hex [hue new-saturation new-value]) - [r g b] (cc/hex->rgb hex)] - (on-change {:hex hex - :r r :g g :b b - :s new-saturation - :v new-value}))) + (mf/use-fn + (mf/deps internal-color on-change) + (fn [saturation value] + (let [color (-> internal-color + (assoc :s saturation) + (assoc :v value) + (enrich-color-map))] + (reset! internal-color* color) + (on-change color)))) on-change-hue - (fn [new-hue] - (let [hex (cc/hsv->hex [new-hue saturation value]) - [r g b] (cc/hex->rgb hex)] - (on-change {:hex hex - :r r :g g :b b - :h new-hue}))) + (mf/use-fn + (mf/deps internal-color on-change) + (fn [hue] + (let [color (-> internal-color + (assoc :h hue) + enrich-color-map)] + (reset! internal-color* color) + (on-change color)))) on-change-opacity - (fn [new-opacity] - (on-change {:alpha new-opacity}))] + (mf/use-fn + (mf/deps internal-color on-change) + (fn [opacity] + (let [color (assoc internal-color :alpha opacity)] + (reset! internal-color* color) + (on-change color))))] + [:* [:& value-saturation-selector - {:hue hue - :saturation saturation - :value value + {:hue h + :saturation s + :value v :on-change on-change-value-saturation :on-start-drag on-start-drag :on-finish-drag on-finish-drag}] [:div {:class (stl/css :shade-selector) - :style #js {"--bullet-size" "52px"}} - [:& cb/color-bullet {:color {:color hex - :opacity alpha} + :style {:--bullet-size "52px"}} + [:& cb/color-bullet {:color bullet-color :area true}] [:div {:class (stl/css :sliders-wrapper)} [:& slider-selector {:type :hue :max-value 360 - :value hue + :value h :on-change on-change-hue :on-start-drag on-start-drag :on-finish-drag on-finish-drag}] diff --git a/frontend/src/app/main/ui/workspace/tokens/form.cljs b/frontend/src/app/main/ui/workspace/tokens/form.cljs index 8a18e78695..bf58d92acd 100644 --- a/frontend/src/app/main/ui/workspace/tokens/form.cljs +++ b/frontend/src/app/main/ui/workspace/tokens/form.cljs @@ -19,7 +19,7 @@ [app.main.ui.ds.foundations.typography.heading :refer [heading*]] [app.main.ui.ds.foundations.typography.text :refer [text*]] [app.main.ui.workspace.colorpicker :as colorpicker] - [app.main.ui.workspace.colorpicker.ramp :refer [ramp-selector]] + [app.main.ui.workspace.colorpicker.ramp :refer [ramp-selector*]] [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] @@ -156,31 +156,43 @@ (defonce form-token-cache-atom (atom nil)) -(mf/defc ramp +(defn hex->value + [hex] + (when-let [tc (tinycolor/valid-color hex)] + (let [hex (str "#" (tinycolor/->hex 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}))) + +(mf/defc ramp* [{:keys [color on-change]}] (let [wrapper-node-ref (mf/use-ref nil) - dragging? (mf/use-state) - hex->value (fn [hex] - (when-let [tc (tinycolor/valid-color hex)] - (let [hex (str "#" (tinycolor/->hex 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}))) - value (mf/use-state (hex->value color)) - on-change' (fn [{:keys [hex]}] - (reset! value (hex->value hex)) - (when-not (and @dragging? hex) - (on-change hex)))] - (colorpicker/use-color-picker-css-variables! wrapper-node-ref @value) + dragging-ref (mf/use-ref false) + + on-start-drag + (mf/use-fn #(mf/set-ref-val! dragging-ref true)) + + on-finish-drag + (mf/use-fn #(mf/set-ref-val! dragging-ref false)) + + on-change' + (mf/use-fn + (mf/deps on-change) + (fn [{:keys [hex]}] + (let [dragging? (mf/ref-val dragging-ref)] + (when-not (and dragging? hex) + (on-change hex)))))] + + (colorpicker/use-color-picker-css-variables! wrapper-node-ref (hex->value color)) [:div {:ref wrapper-node-ref} - [:& ramp-selector - {:color @value + [:> ramp-selector* + {:color (hex->value color) :disable-opacity true - :on-start-drag #(reset! dragging? true) - :on-finish-drag #(reset! dragging? false) + :on-start-drag on-start-drag + :on-finish-drag on-finish-drag :on-change on-change'}]])) (mf/defc token-value-or-errors @@ -419,9 +431,9 @@ [:> input-token-color-bullet* {:color @color :on-click on-display-colorpicker}])] (when @color-ramp-open? - [:& ramp {:color (some-> (or @token-resolve-result (:value token)) - (tinycolor/valid-color)) - :on-change on-update-color}]) + [:> ramp* {:color (some-> (or @token-resolve-result (:value token)) + (tinycolor/valid-color)) + :on-change on-update-color}]) [:& token-value-or-errors {:result-or-errors @token-resolve-result}]] [:div {:class (stl/css :input-row)}