diff --git a/common/app/common/pages.cljc b/common/app/common/pages.cljc index 6a947ec779..93dc8ec048 100644 --- a/common/app/common/pages.cljc +++ b/common/app/common/pages.cljc @@ -297,10 +297,10 @@ (s/def :internal.color/name ::string) -(s/def :internal.color/value ::string) -(s/def :internal.color/color ::string) -(s/def :internal.color/opacity ::safe-number) -(s/def :internal.color/gradient ::gradient) +(s/def :internal.color/value (s/nilable ::string)) +(s/def :internal.color/color (s/nilable ::string)) +(s/def :internal.color/opacity (s/nilable ::safe-number)) +(s/def :internal.color/gradient (s/nilable ::gradient)) (s/def ::color (s/keys :req-un [::id diff --git a/frontend/resources/images/icons/picker.svg b/frontend/resources/images/icons/picker.svg index be86a18081..3fc711f38c 100644 --- a/frontend/resources/images/icons/picker.svg +++ b/frontend/resources/images/icons/picker.svg @@ -1,4 +1,3 @@ - diff --git a/frontend/resources/styles/main/partials/colorpicker.scss b/frontend/resources/styles/main/partials/colorpicker.scss index 05cf8370d6..70a43f3b34 100644 --- a/frontend/resources/styles/main/partials/colorpicker.scss +++ b/frontend/resources/styles/main/partials/colorpicker.scss @@ -29,7 +29,7 @@ border: none; cursor: pointer; - &.active, + &.active svg, &:hover svg { fill: $color-primary; } diff --git a/frontend/src/app/main/data/colors.cljs b/frontend/src/app/main/data/colors.cljs index 16d49b9b0c..7b7edc9877 100644 --- a/frontend/src/app/main/data/colors.cljs +++ b/frontend/src/app/main/data/colors.cljs @@ -133,36 +133,6 @@ (map #(dwt/update-text-attrs {:id % :editor (get editors %) :attrs attrs}) text-ids) (dwc/update-shapes shape-ids update-fn)))))))) -#_(defn change-fill - ([ids color id file-id] - (change-fill ids color 1 id file-id)) - ([ids color opacity id file-id] - (ptk/reify ::change-fill - ptk/WatchEvent - (watch [_ state s] - (let [pid (:current-page-id state) - objects (get-in state [:workspace-data :pages-index pid :objects]) - children (mapcat #(cph/get-children % objects) ids) - ids (into ids children) - - is-text? #(= :text (:type (get objects %))) - text-ids (filter is-text? ids) - shape-ids (filter (comp not is-text?) ids) - - attrs (cond-> {:fill-color color - :fill-color-ref-id id - :fill-color-ref-file file-id} - (and opacity (not= opacity :multiple)) (assoc :fill-opacity opacity)) - - update-fn (fn [shape] (merge shape attrs)) - editors (get-in state [:workspace-local :editors]) - reduce-fn (fn [state id] - (update-in state [:workspace-data :pages-index pid :objects id] update-fn))] - - (rx/from (conj - (map #(dwt/update-text-attrs {:id % :editor (get editors %) :attrs attrs}) text-ids) - (dwc/update-shapes shape-ids update-fn)))))))) - (defn change-stroke [ids color] (ptk/reify ::change-stroke ptk/WatchEvent @@ -185,49 +155,44 @@ :stroke-opacity 1)))] (rx/of (dwc/update-shapes ids update-fn)))))) -#_(defn change-stroke [ids color id file-id] - (ptk/reify ::change-stroke - ptk/WatchEvent - (watch [_ state s] - (let [objects (get-in state [:workspace-data :pages-index (:current-page-id state) :objects]) - children (mapcat #(cph/get-children % objects) ids) - ids (into ids children) - - update-fn (fn [s] - (cond-> s - true - (assoc :stroke-color color - :stroke-color-ref-id id - :stroke-color-ref-file file-id) - - (= (:stroke-style s) :none) - (assoc :stroke-style :solid - :stroke-width 1 - :stroke-opacity 1)))] - (rx/of (dwc/update-shapes ids update-fn)))))) - (defn picker-for-selected-shape [] - ;; TODO: replace st/emit! by a subject push and set that in the WatchEvent - (let [handle-change-color - (fn [color shift?] - (let [ids (get-in @st/state [:workspace-local :selected])] - (st/emit! - (if shift? - (change-stroke ids color) - (change-fill ids color)) - (md/hide))))] - (ptk/reify ::start-picker + (let [sub (rx/subject)] + (ptk/reify ::picker-for-selected-shape + ptk/WatchEvent + (watch [_ state stream] + (let [ids (get-in state [:workspace-local :selected]) + stop? (->> stream + (rx/filter (ptk/type? ::stop-picker))) + + update-events (fn [[color shift?]] + (rx/of (if shift? + (change-stroke ids color) + (change-fill ids color)) + (stop-picker)))] + (rx/merge + ;; Stream that updates the stroke/width and stops if `esc` pressed + (->> sub + (rx/take-until stop?) + (rx/flat-map update-events)) + + ;; Hide the modal if the stop event is emitted + (->> stop? + (rx/first) + (rx/map #(md/hide)))))) + ptk/UpdateEvent (update [_ state] - (-> state - (assoc-in [:workspace-local :picking-color?] true) - (assoc ::md/modal {:id (random-uuid) - :type :colorpicker - :props {:on-change handle-change-color} - :allow-click-outside true})))))) + (let [handle-change-color (fn [color shift?] (rx/push! sub [color shift?]))] + (-> state + (assoc-in [:workspace-local :picking-color?] true) + (assoc ::md/modal {:id (random-uuid) + :data {:color "#000000" :opacity 1} + :type :colorpicker + :props {:on-change handle-change-color} + :allow-click-outside true}))))))) (defn select-gradient-stop [spot] - (ptk/reify ::start-picker + (ptk/reify ::select-gradient-stop ptk/UpdateEvent (update [_ state] (-> state diff --git a/frontend/src/app/main/data/modal.cljs b/frontend/src/app/main/data/modal.cljs index 976ecff65d..cd0a7c2c54 100644 --- a/frontend/src/app/main/data/modal.cljs +++ b/frontend/src/app/main/data/modal.cljs @@ -50,7 +50,9 @@ (ptk/reify ::update-modal ptk/UpdateEvent (update [_ state] - (c/update state ::modal merge options)))) + (cond-> state + (::modal state) + (c/update ::modal merge options))))) (defn show! [type props] diff --git a/frontend/src/app/main/ui/modal.cljs b/frontend/src/app/main/ui/modal.cljs index ac6a3c9aa0..4b2d36256a 100644 --- a/frontend/src/app/main/ui/modal.cljs +++ b/frontend/src/app/main/ui/modal.cljs @@ -20,10 +20,10 @@ (:import goog.events.EventType)) (defn- on-esc-clicked - [event] - (when (k/esc? event) - (st/emit! (dm/hide)) - (dom/stop-propagation event))) + [event allow-click-outside] + (when (and (k/esc? event) (not allow-click-outside)) + (do (dom/stop-propagation event) + (st/emit! (dm/hide))))) (defn- on-pop-state [event] @@ -62,16 +62,23 @@ (let [data (unchecked-get props "data") wrapper-ref (mf/use-ref nil) + allow-click-outside (:allow-click-outside data) + handle-click-outside (fn [event] - (on-click-outside event wrapper-ref (:type data) (:allow-click-outside data)))] + (on-click-outside event wrapper-ref (:type data) allow-click-outside)) + + handle-keydown + (fn [event] + (on-esc-clicked event allow-click-outside))] (mf/use-layout-effect + (mf/deps allow-click-outside) (fn [] - (let [keys [(events/listen js/document EventType.KEYDOWN on-esc-clicked) + (let [keys [(events/listen js/document EventType.KEYDOWN handle-keydown) (events/listen js/window EventType.POPSTATE on-pop-state) (events/listen js/document EventType.CLICK handle-click-outside)]] - #(for [key keys] + #(doseq [key keys] (events/unlistenByKey key))))) [:div.modal-wrapper {:ref wrapper-ref} diff --git a/frontend/src/app/main/ui/workspace/colorpicker.cljs b/frontend/src/app/main/ui/workspace/colorpicker.cljs index 04be286240..b63d2e29d2 100644 --- a/frontend/src/app/main/ui/workspace/colorpicker.cljs +++ b/frontend/src/app/main/ui/workspace/colorpicker.cljs @@ -121,6 +121,9 @@ ref-picker (mf/use-ref) + dirty? (mf/use-var false) + last-color (mf/use-var data) + picking-color? (mf/deref picking-color?) picked-color (mf/deref picked-color) picked-color-select (mf/deref picked-color-select) @@ -128,8 +131,6 @@ editing-spot-state (mf/deref editing-spot-state-ref) - ;; data-ref (mf/use-var data) - current-color (:current-color @state) change-tab @@ -140,15 +141,9 @@ (fn [changes] (let [editing-stop (:editing-stop @state)] (swap! state #(cond-> % - true (update :current-color merge changes) - editing-stop (update-in [:stops editing-stop] merge changes))) - - #_(when (:hex changes) - (reset! value-ref (:hex changes))) - - ;; TODO: CHANGE TO SUPPORT GRADIENTS - #_(on-change (:hex changes (:hex current-color)) - (:alpha changes (:alpha current-color))))) + true (update :current-color merge changes) + editing-stop (update-in [:stops editing-stop] merge changes))) + (reset! dirty? true))) handle-change-stop (fn [offset] @@ -160,11 +155,15 @@ (st/emit! (dc/select-gradient-stop offset))))) on-select-library-color - (fn [color] (prn "color" color)) + (fn [color] (reset! state (data->state color))) + + on-add-library-color + (fn [color] (st/emit! (dwl/add-color (state->data @state)))) on-activate-gradient (fn [type] (fn [] + (reset! dirty? true) (if (= type (:type @state)) (do (swap! state assoc :type :color) @@ -179,13 +178,6 @@ 1 (-> (:current-color @state) (assoc :alpha 0))}))))))] - ;; Update state when there is a change in the props upstream - ;; TODO: Review for gradients - #_(mf/use-effect - (mf/deps value opacity) - (fn [] - (swap! state assoc current-color (as-color-components value opacity)))) - ;; Updates the CSS color variable when there is a change in the color (mf/use-effect (mf/deps current-color) @@ -208,48 +200,47 @@ ;; When closing the modal we update the recent-color list (mf/use-effect - (fn [] (fn [] - (st/emit! (dc/stop-picker)) - (st/emit! (dwl/add-recent-color (state->data @state)))))) + #(fn [] + (st/emit! (dc/stop-picker)) + (when @last-color + (st/emit! (dwl/add-recent-color @last-color))))) + ;; Updates color when used el pixel picker (mf/use-effect - (mf/deps picking-color? picked-color) + (mf/deps picking-color? picked-color-select) (fn [] - (when picking-color? - (let [[r g b] (or picked-color [0 0 0]) + (when (and picking-color? picked-color-select) + (let [[r g b alpha] picked-color hex (uc/rgb->hex [r g b]) [h s v] (uc/hex->hsv hex)] + (handle-change-color {:hex hex + :r r :g g :b b + :h h :s s :v v + :alpha alpha}))))) - (swap! state update :current-color assoc - :r r :g g :b b - :h h :s s :v v - :hex hex) - - ;; TODO: UPDATE TO USE GRADIENTS - #_(reset! value-ref hex) - #_(when picked-color-select - (on-change hex (:alpha current-color) nil nil picked-shift?)))))) - - ;; TODO: UPDATE TO USE GRADIENTS - #_(mf/use-effect - (mf/deps picking-color? picked-color-select) - (fn [] (when (and picking-color? picked-color-select) - (on-change (:hex current-color) (:alpha current-color) nil nil picked-shift?)))) - + ;; Changes when another gradient handler is selected (mf/use-effect (mf/deps editing-spot-state) #(when (not= editing-spot-state (:editing-stop @state)) (handle-change-stop (or editing-spot-state 0)))) + ;; Changes on the viewport when moving a gradient handler (mf/use-effect (mf/deps data) #(if-let [gradient-data (-> data data->state :gradient-data)] - (swap! state assoc :gradient-data gradient-data))) + (do + (reset! dirty? true) + (swap! state assoc :gradient-data gradient-data)))) + ;; Send the properties to the store (mf/use-effect (mf/deps @state) (fn [] - (on-change (state->data @state)))) + (if @dirty? + (let [color (state->data @state)] + (reset! dirty? false) + (reset! last-color color) + (on-change color))))) [:div.colorpicker {:ref ref-picker} [:div.colorpicker-content @@ -306,7 +297,8 @@ :on-change handle-change-color}] [:& libraries {:current-color current-color - :on-select-color on-select-library-color}] + :on-select-color on-select-library-color + :on-add-library-color on-add-library-color}] (when on-accept [:div.actions diff --git a/frontend/src/app/main/ui/workspace/colorpicker/libraries.cljs b/frontend/src/app/main/ui/workspace/colorpicker/libraries.cljs index 3c4a04c817..09d5b95187 100644 --- a/frontend/src/app/main/ui/workspace/colorpicker/libraries.cljs +++ b/frontend/src/app/main/ui/workspace/colorpicker/libraries.cljs @@ -32,7 +32,7 @@ [app.main.ui.workspace.colorpicker.ramp :refer [ramp-selector]] [app.main.ui.workspace.colorpicker.color-inputs :refer [color-inputs]])) -(mf/defc libraries [{:keys [current-color on-select-color]}] +(mf/defc libraries [{:keys [current-color on-select-color on-add-library-color]}] (let [selected-library (mf/use-state "recent") current-library-colors (mf/use-state []) @@ -69,7 +69,7 @@ (mf/use-effect (mf/deps file-colors) (fn [] (when (= @selected-library "file") - (let [colors (map #(select-keys % [:id :value]) (vals file-colors))] + (let [colors (vals file-colors)] (reset! current-library-colors (into [] colors)))))) @@ -88,7 +88,7 @@ [:div.selected-colors (when (= "file" @selected-library) [:div.color-bullet.button.plus-button {:style {:background-color "white"} - :on-click #(st/emit! (dwl/add-color current-color))} + :on-click on-add-library-color} i/plus]) [:div.color-bullet.button {:style {:background-color "white"} diff --git a/frontend/src/app/main/ui/workspace/colorpicker/pixel_overlay.cljs b/frontend/src/app/main/ui/workspace/colorpicker/pixel_overlay.cljs index faa61fbe58..9aea134b3b 100644 --- a/frontend/src/app/main/ui/workspace/colorpicker/pixel_overlay.cljs +++ b/frontend/src/app/main/ui/workspace/colorpicker/pixel_overlay.cljs @@ -10,20 +10,157 @@ (ns app.main.ui.workspace.colorpicker.pixel-overlay (:require [rumext.alpha :as mf] - [okulary.core :as l] [cuerdas.core :as str] - [app.common.geom.point :as gpt] - [app.common.math :as math] - [app.common.uuid :refer [uuid]] + [okulary.core :as l] + [promesa.core :as p] + [goog.events :as events] + [app.common.uuid :as uuid] + [app.util.timers :as timers] [app.util.dom :as dom] - [app.util.color :as uc] [app.util.object :as obj] - [app.main.store :as st] - [app.main.refs :as refs] - [app.main.data.workspace.libraries :as dwl] - [app.main.data.colors :as dc] + [app.main.data.colors :as dwc] + [app.main.data.fetch :as mdf] [app.main.data.modal :as modal] - [app.main.ui.icons :as i] - [app.util.i18n :as i18n :refer [t]])) + [app.main.refs :as refs] + [app.main.store :as st] + [app.main.ui.context :as muc] + [app.main.ui.cursors :as cur] + [app.main.ui.keyboard :as kbd] + [app.main.ui.workspace.shapes :refer [shape-wrapper frame-wrapper]]) + (:import goog.events.EventType)) +(defn format-viewbox [vbox] + (str/join " " [(+ (:x vbox 0) (:left-offset vbox 0)) + (:y vbox 0) + (:width vbox 0) + (:height vbox 0)])) +(mf/defc overlay-frames + {::mf/wrap [mf/memo] + ::mf/wrap-props false} + [] + (let [data (mf/deref refs/workspace-page) + objects (:objects data) + root (get objects uuid/zero) + shapes (->> (:shapes root) (map #(get objects %)))] + [:* + [:g.shapes + (for [item shapes] + (if (= (:type item) :frame) + [:& frame-wrapper {:shape item + :key (:id item) + :objects objects}] + [:& shape-wrapper {:shape item + :key (:id item)}]))]])) + +(mf/defc pixel-overlay + {::mf/wrap-props false} + [props] + (let [vport (unchecked-get props "vport") + vbox (unchecked-get props "vbox") + viewport-ref (unchecked-get props "viewport-ref") + options (unchecked-get props "options") + svg-ref (mf/use-ref nil) + canvas-ref (mf/use-ref nil) + fetch-pending (mf/deref (mdf/pending-ref)) + + handle-keydown + (fn [event] + (when (and (kbd/esc? event)) + (do (dom/stop-propagation event) + (dom/prevent-default event) + (st/emit! (dwc/stop-picker)) + (modal/disallow-click-outside!)))) + + on-mouse-move-picker + (fn [event] + (when-let [zoom-view-node (.getElementById js/document "picker-detail")] + (let [{brx :left bry :top} (dom/get-bounding-rect (mf/ref-val viewport-ref)) + x (- (.-clientX event) brx) + y (- (.-clientY event) bry) + + zoom-context (.getContext zoom-view-node "2d") + canvas-node (mf/ref-val canvas-ref) + canvas-context (.getContext canvas-node "2d") + pixel-data (.getImageData canvas-context x y 1 1) + rgba (.-data pixel-data) + r (obj/get rgba 0) + g (obj/get rgba 1) + b (obj/get rgba 2) + a (obj/get rgba 3) + + area-data (.getImageData canvas-context (- x 25) (- y 20) 50 40)] + + (-> (js/createImageBitmap area-data) + (p/then (fn [image] + ;; Draw area + (obj/set! zoom-context "imageSmoothingEnabled" false) + (.drawImage zoom-context image 0 0 200 160)))) + (st/emit! (dwc/pick-color [r g b a]))))) + + on-mouse-down-picker + (fn [event] + (dom/prevent-default event) + (dom/stop-propagation event) + (st/emit! (dwc/pick-color-select true (kbd/shift? event)))) + + on-mouse-up-picker + (fn [event] + (dom/prevent-default event) + (dom/stop-propagation event) + (st/emit! (dwc/stop-picker)) + (modal/disallow-click-outside!))] + + (mf/use-effect + (fn [] + (let [listener (events/listen js/document EventType.KEYDOWN handle-keydown)] + #(events/unlistenByKey listener)))) + + (mf/use-effect + ;; Everytime we finish retrieving a new URL we redraw the canvas + ;; so even if we're not finished the user can start to pick basic + ;; shapes + (mf/deps fetch-pending) + (fn [] + (try + (let [canvas-node (mf/ref-val canvas-ref) + canvas-context (.getContext canvas-node "2d") + svg-node (mf/ref-val svg-ref)] + (timers/schedule 100 + #(let [xml (.serializeToString (js/XMLSerializer.) svg-node) + img-src (str "data:image/svg+xml;base64," + (-> xml js/encodeURIComponent js/unescape js/btoa)) + img (js/Image.) + on-error (fn [err] (.error js/console "ERROR" err)) + on-load (fn [] (.drawImage canvas-context img 0 0))] + (.addEventListener img "error" on-error) + (.addEventListener img "load" on-load) + (obj/set! img "src" img-src)))) + (catch :default e (.error js/console e))))) + + [:* + [:div.overlay + {:tab-index 0 + :style {:position "absolute" + :top 0 + :left 0 + :width "100%" + :height "100%" + :cursor cur/picker} + :on-mouse-down on-mouse-down-picker + :on-mouse-up on-mouse-up-picker + :on-mouse-move on-mouse-move-picker}] + [:canvas {:ref canvas-ref + :width (:width vport 0) + :height (:height vport 0) + :style {:display "none"}}] + [:& (mf/provider muc/embed-ctx) {:value true} + [:svg.viewport + {:ref svg-ref + :preserveAspectRatio "xMidYMid meet" + :width (:width vport 0) + :height (:height vport 0) + :view-box (format-viewbox vbox) + :style {:display "none" + :background-color (get options :background "#E8E9EA")}} + [:& overlay-frames]]]])) diff --git a/frontend/src/app/main/ui/workspace/viewport.cljs b/frontend/src/app/main/ui/workspace/viewport.cljs index e69c427d36..256b577b57 100644 --- a/frontend/src/app/main/ui/workspace/viewport.cljs +++ b/frontend/src/app/main/ui/workspace/viewport.cljs @@ -41,6 +41,7 @@ [app.main.ui.workspace.frame-grid :refer [frame-grid]] [app.main.ui.workspace.shapes.outline :refer [outline]] [app.main.ui.workspace.gradients :refer [gradient-handlers]] + [app.main.ui.workspace.colorpicker.pixel-overlay :refer [pixel-overlay]] [app.common.math :as mth] [app.util.dom :as dom] [app.util.dom.dnd :as dnd] @@ -185,104 +186,6 @@ (:width vbox 0) (:height vbox 0)])) -(mf/defc pixel-picker-overlay - {::mf/wrap-props false} - [props] - (let [vport (unchecked-get props "vport") - vbox (unchecked-get props "vbox") - viewport-ref (unchecked-get props "viewport-ref") - options (unchecked-get props "options") - svg-ref (mf/use-ref nil) - canvas-ref (mf/use-ref nil) - fetch-pending (mf/deref (mdf/pending-ref)) - - on-mouse-move-picker - (fn [event] - (when-let [zoom-view-node (.getElementById js/document "picker-detail")] - (let [{brx :left bry :top} (dom/get-bounding-rect (mf/ref-val viewport-ref)) - x (- (.-clientX event) brx) - y (- (.-clientY event) bry) - - zoom-context (.getContext zoom-view-node "2d") - canvas-node (mf/ref-val canvas-ref) - canvas-context (.getContext canvas-node "2d") - pixel-data (.getImageData canvas-context x y 1 1) - rgba (.-data pixel-data) - r (obj/get rgba 0) - g (obj/get rgba 1) - b (obj/get rgba 2) - a (obj/get rgba 3) - - area-data (.getImageData canvas-context (- x 25) (- y 20) 50 40)] - - (-> (js/createImageBitmap area-data) - (p/then (fn [image] - ;; Draw area - (obj/set! zoom-context "imageSmoothingEnabled" false) - (.drawImage zoom-context image 0 0 200 160)))) - (st/emit! (dwc/pick-color [r g b a]))))) - - on-mouse-down-picker - (fn [event] - (dom/prevent-default event) - (dom/stop-propagation event) - (st/emit! (dwc/pick-color-select true (kbd/shift? event)))) - - on-mouse-up-picker - (fn [event] - (dom/prevent-default event) - (dom/stop-propagation event) - (st/emit! (dwc/stop-picker)) - (modal/disallow-click-outside!))] - - (mf/use-effect - ;; Everytime we finish retrieving a new URL we redraw the canvas - ;; so even if we're not finished the user can start to pick basic - ;; shapes - (mf/deps fetch-pending) - (fn [] - (try - (let [canvas-node (mf/ref-val canvas-ref) - canvas-context (.getContext canvas-node "2d") - svg-node (mf/ref-val svg-ref)] - (timers/schedule 100 - #(let [xml (.serializeToString (js/XMLSerializer.) svg-node) - img-src (str "data:image/svg+xml;base64," - (-> xml js/encodeURIComponent js/unescape js/btoa)) - img (js/Image.) - on-error (fn [err] (.error js/console "ERROR" err)) - on-load (fn [] (.drawImage canvas-context img 0 0))] - (.addEventListener img "error" on-error) - (.addEventListener img "load" on-load) - (obj/set! img "src" img-src)))) - (catch :default e (.error js/console e))))) - - [:* - [:div.overlay - {:style {:position "absolute" - :top 0 - :left 0 - :width "100%" - :height "100%" - :cursor cur/picker} - :on-mouse-down on-mouse-down-picker - :on-mouse-up on-mouse-up-picker - :on-mouse-move on-mouse-move-picker}] - [:canvas {:ref canvas-ref - :width (:width vport 0) - :height (:height vport 0) - :style {:display "none"}}] - [:& (mf/provider muc/embed-ctx) {:value true} - [:svg.viewport - {:ref svg-ref - :preserveAspectRatio "xMidYMid meet" - :width (:width vport 0) - :height (:height vport 0) - :view-box (format-viewbox vbox) - :style {:display "none" - :background-color (get options :background "#E8E9EA")}} - [:& frames]]]])) - (mf/defc viewport [{:keys [page-id page local layout] :as props}] (let [{:keys [options-mode @@ -310,8 +213,6 @@ drawing-tool (:tool drawing) drawing-obj (:object drawing) - pick-color (mf/use-state [255 255 255 255]) - zoom (or zoom 1) on-mouse-down @@ -587,11 +488,11 @@ [:* (when picking-color? - [:& pixel-picker-overlay {:vport vport - :vbox vbox - :viewport-ref viewport-ref - :options options - :layout layout}]) + [:& pixel-overlay {:vport vport + :vbox vbox + :viewport-ref viewport-ref + :options options + :layout layout}]) [:svg.viewport {:preserveAspectRatio "xMidYMid meet"