diff --git a/frontend/src/app/main/ui/workspace/viewport/selection.cljs b/frontend/src/app/main/ui/workspace/viewport/selection.cljs index 2db02dfc9..bd7a0c7df 100644 --- a/frontend/src/app/main/ui/workspace/viewport/selection.cljs +++ b/frontend/src/app/main/ui/workspace/viewport/selection.cljs @@ -8,6 +8,7 @@ "Selection handlers component." (:require [app.common.data.macros :as dm] + [app.common.files.helpers :as cfh] [app.common.geom.matrix :as gmt] [app.common.geom.point :as gpt] [app.common.geom.shapes :as gsh] @@ -19,11 +20,11 @@ [app.main.ui.context :as ctx] [app.main.ui.css-cursors :as cur] [app.main.ui.workspace.shapes.path.editor :refer [path-editor]] + [app.util.array :as array] [app.util.debug :as dbg] [app.util.dom :as dom] [app.util.object :as obj] - [rumext.v2 :as mf] - [rumext.v2.util :refer [map->obj]])) + [rumext.v2 :as mf])) (def rotation-handler-size 20) (def resize-point-radius 4) @@ -37,134 +38,150 @@ (def small-selrect-side 30) (mf/defc selection-rect + {::mf/wrap-props false} [{:keys [transform rect zoom color on-move-selected on-context-menu]}] - (when rect - (let [{:keys [x y width height]} rect] - [:rect.main.viewport-selrect - {:x x - :y y - :width width - :height height - :transform (str transform) - :on-pointer-down on-move-selected - :on-context-menu on-context-menu - :style {:stroke color - :stroke-width (/ selection-rect-width zoom) - :fill "none"}}]))) + (let [x (dm/get-prop rect :x) + y (dm/get-prop rect :y) + width (dm/get-prop rect :width) + height (dm/get-prop rect :height)] + [:rect.main.viewport-selrect + {:x x + :y y + :width width + :height height + :transform (str transform) + :on-pointer-down on-move-selected + :on-context-menu on-context-menu + :style {:stroke color + :stroke-width (/ selection-rect-width zoom) + :fill "none"}}])) -(defn- handlers-for-selection [{:keys [x y width height]} {:keys [type]} zoom] - (let [threshold-small (/ 25 zoom) - threshold-tiny (/ 10 zoom) +(defn- calculate-handlers + "Calculates selection handlers for the current selection." + [selection shape zoom] + (let [x (dm/get-prop selection :x) + y (dm/get-prop selection :y) + width (dm/get-prop selection :width) + height (dm/get-prop selection :height) - small-width? (<= width threshold-small) - tiny-width? (<= width threshold-tiny) + threshold-small (/ 25 zoom) + threshold-tiny (/ 10 zoom) - small-height? (<= height threshold-small) - tiny-height? (<= height threshold-tiny) + small-width? (<= width threshold-small) + tiny-width? (<= width threshold-tiny) - vertical-line? (and (= type :path) tiny-width?) - horizontal-line? (and (= type :path) tiny-height?) + small-height? (<= height threshold-small) + tiny-height? (<= height threshold-tiny) - align (if (or small-width? small-height?) - :outside - :inside)] - (->> - [;; TOP-LEFT - {:type :rotation - :position :top-left - :props {:cx x :cy y}} + path? (cfh/path-shape? shape) + vertical-line? (and ^boolean path? ^boolean tiny-width?) + horizontal-line? (and ^boolean path? ^boolean tiny-height?) - {:type :rotation - :position :top-right - :props {:cx (+ x width) :cy y}} + align (if (or ^boolean small-width? ^boolean small-height?) + :outside + :inside) - {:type :rotation - :position :bottom-right - :props {:cx (+ x width) :cy (+ y height)}} + result #js [#js {:type :rotation + :position :top-left + :props #js {:cx x :cy y}} - {:type :rotation - :position :bottom-left - :props {:cx x :cy (+ y height)}} + #js {:type :rotation + :position :top-right + :props #js {:cx (+ x width) :cy y}} - (when-not horizontal-line? - (let [x (if small-width? (+ x (/ (- width threshold-small) 2)) x) - length (if small-width? threshold-small width)] - {:type :resize-side - :position :top - :props {:x x - :y y - :length length - :angle 0 - :align align - :show-handler? tiny-width?}})) + #js {:type :rotation + :position :bottom-right + :props #js {:cx (+ x width) :cy (+ y height)}} - (when-not horizontal-line? - (let [x (if small-width? (+ x (/ (+ width threshold-small) 2)) (+ x width)) - length (if small-width? threshold-small width)] - {:type :resize-side - :position :bottom - :props {:x x - :y (+ y height) - :length length - :angle 180 - :align align - :show-handler? tiny-width?}})) + #js {:type :rotation + :position :bottom-left + :props #js {:cx x :cy (+ y height)}}]] - (when-not vertical-line? - (let [y (if small-height? (+ y (/ (- height threshold-small) 2)) y) - length (if small-height? threshold-small height)] - {:type :resize-side - :position :right - :props {:x (+ x width) - :y y - :length length - :angle 90 - :align align - :show-handler? tiny-height?}})) - (when-not vertical-line? - (let [y (if small-height? (+ y (/ (+ height threshold-small) 2)) (+ y height)) - length (if small-height? threshold-small height)] - {:type :resize-side - :position :left - :props {:x x - :y y - :length length - :angle 270 - :align align - :show-handler? tiny-height?}})) + (when-not ^boolean horizontal-line? + (array/conj! result + #js {:type :resize-side + :position :top + :props #js {:x (if ^boolean small-width? + (+ x (/ (- width threshold-small) 2)) + x) + :y y + :length (if ^boolean small-width? + threshold-small + width) + :angle 0 + :align align + :show-handler tiny-width?}} + #js {:type :resize-side + :position :bottom + :props #js {:x (if ^boolean small-width? + (+ x (/ (+ width threshold-small) 2)) + (+ x width)) + :y (+ y height) + :length (if small-width? threshold-small width) + :angle 180 + :align align + :show-handler tiny-width?}})) - (when (and (not tiny-width?) (not tiny-height?)) - {:type :resize-point - :position :top-left - :props {:cx x :cy y :align align}}) + (when-not vertical-line? + (array/conj! result + #js {:type :resize-side + :position :right + :props #js {:x (+ x width) + :y (if small-height? (+ y (/ (- height threshold-small) 2)) y) + :length (if small-height? threshold-small height) + :angle 90 + :align align + :show-handler tiny-height?}} - (when (and (not tiny-width?) (not tiny-height?)) - {:type :resize-point - :position :top-right - :props {:cx (+ x width) :cy y :align align}}) + #js {:type :resize-side + :position :left + :props #js {:x x + :y (if ^boolean small-height? + (+ y (/ (+ height threshold-small) 2)) + (+ y height)) + :length (if ^boolean small-height? + threshold-small + height) + :angle 270 + :align align + :show-handler tiny-height?}})) - (when (and (not tiny-width?) (not tiny-height?)) - {:type :resize-point - :position :bottom-right - :props {:cx (+ x width) :cy (+ y height) :align align}}) + (when (and (not tiny-width?) (not tiny-height?)) + (array/conj! result + #js {:type :resize-point + :position :top-left + :props #js {:cx x :cy y :align align}} + #js {:type :resize-point + :position :top-right + :props #js {:cx (+ x width) :cy y :align align}} + #js {:type :resize-point + :position :bottom-right + :props #js {:cx (+ x width) :cy (+ y height) :align align}} + #js {:type :resize-point + :position :bottom-left + :props #js {:cx x :cy (+ y height) :align align}})))) - (when (and (not tiny-width?) (not tiny-height?)) - {:type :resize-point - :position :bottom-left - :props {:cx x :cy (+ y height) :align align}})] +(mf/defc rotation-handler + {::mf/wrap-props false} + [{:keys [cx cy transform position rotation zoom on-rotate] :as props}] + (let [size (/ rotation-handler-size zoom) + delta-x (if (or (= position :top-left) + (= position :bottom-left)) + size + 0) + delta-y (if (or (= :top-left position) + (= :top-right position)) + size + 0) - (filterv (comp not nil?))))) - -(mf/defc rotation-handler [{:keys [cx cy transform position rotation zoom on-rotate]}] - (let [size (/ rotation-handler-size zoom) - x (- cx (if (#{:top-left :bottom-left} position) size 0)) - y (- cy (if (#{:top-left :top-right} position) size 0)) - angle (case position - :top-left 0 - :top-right 90 - :bottom-right 180 - :bottom-left 270)] + x (- cx delta-x) + y (- cy delta-y) + angle (case position + :top-left 0 + :top-right 90 + :bottom-right 180 + :bottom-left 270)] [:rect {:x x :y y :class (cur/get-dynamic "rotate" (+ rotation angle)) @@ -176,13 +193,20 @@ :on-pointer-down on-rotate}])) (mf/defc resize-point-handler - [{:keys [cx cy zoom position on-resize transform rotation color align]}] - (let [layout (mf/deref refs/workspace-layout) - scale-text (:scale-text layout) - cursor (if (#{:top-left :bottom-right} position) - (if scale-text (cur/get-dynamic "scale-nesw" rotation) (cur/get-dynamic "resize-nesw" rotation)) - (if scale-text (cur/get-dynamic "scale-nwse" rotation) (cur/get-dynamic "resize-nwse" rotation))) - {cx' :x cy' :y} (gpt/transform (gpt/point cx cy) transform)] + {::mf/wrap-props false} + [{:keys [cx cy zoom position on-resize transform rotation color align scale-text]}] + (let [cursor (if (or (= position :top-left) + (= position :bottom-right)) + (if ^boolean scale-text + (cur/get-dynamic "scale-nesw" rotation) + (cur/get-dynamic "resize-nesw" rotation)) + (if ^boolean scale-text + (cur/get-dynamic "scale-nwse" rotation) + (cur/get-dynamic "resize-nwse" rotation))) + + pt (gpt/transform (gpt/point cx cy) transform) + cx' (dm/get-prop pt :x) + cy' (dm/get-prop pt :y)] [:g.resize-handler [:circle {:r (/ resize-point-radius zoom) @@ -196,49 +220,68 @@ (if (= align :outside) (let [resize-point-circle-radius (/ resize-point-circle-radius zoom) - offset-x (if (#{:top-right :bottom-right} position) 0 (- resize-point-circle-radius)) - offset-y (if (#{:bottom-left :bottom-right} position) 0 (- resize-point-circle-radius)) - cx (+ cx offset-x) - cy (+ cy offset-y) - {cx' :x cy' :y} (gpt/transform (gpt/point cx cy) transform)] + offset-x (if (or (= position :top-right) + (= position :bottom-right)) + 0 + (- resize-point-circle-radius)) + offset-y (if (or (= position :bottom-left) + (= position :bottom-right)) + 0 + (- resize-point-circle-radius)) + cx (+ cx offset-x) + cy (+ cy offset-y) + pt (gpt/transform (gpt/point cx cy) transform) + cx' (dm/get-prop pt :x) + cy' (dm/get-prop pt :y)] [:rect {:x cx' :y cy' + :data-position (name position) :class cursor - :width resize-point-circle-radius - :height resize-point-circle-radius - :transform (when rotation (dm/fmt "rotate(%, %, %)" rotation cx' cy')) :style {:fill (if (dbg/enabled? :handlers) "red" "none") :stroke-width 0} - :on-pointer-down #(on-resize {:x cx' :y cy'} %)}]) + :width resize-point-circle-radius + :height resize-point-circle-radius + :transform (when (some? rotation) + (dm/fmt "rotate(%, %, %)" rotation cx' cy')) + :on-pointer-down on-resize}]) - [:circle {:on-pointer-down #(on-resize {:x cx' :y cy'} %) + [:circle {:on-pointer-down on-resize :r (/ resize-point-circle-radius zoom) + :data-position (name position) :cx cx' :cy cy' + :data-x cx' + :data-y cy' :class cursor :style {:fill (if (dbg/enabled? :handlers) "red" "none") :stroke-width 0}}])])) +;; The side handler is always rendered horizontally and then rotated (mf/defc resize-side-handler - "The side handler is always rendered horizontally and then rotated" - [{:keys [x y length align angle zoom position rotation transform on-resize color show-handler?]}] - (let [res-point (if (#{:top :bottom} position) - {:y y} - {:x x}) - layout (mf/deref refs/workspace-layout) - scale-text (:scale-text layout) - height (/ resize-side-height zoom) - offset-y (if (= align :outside) (- height) (- (/ height 2))) - target-y (+ y offset-y) - transform-str (dm/str (gmt/multiply transform (gmt/rotate-matrix angle (gpt/point x y))))] + {::mf/wrap-props false} + [{:keys [x y length align angle zoom position rotation transform on-resize color show-handler scale-text]}] + (let [height (/ resize-side-height zoom) + offset-y (if (= align :outside) (- height) (- (/ height 2))) + target-y (+ y offset-y) + transform-str (dm/str (gmt/multiply transform (gmt/rotate-matrix angle (gpt/point x y)))) + cursor (if (or (= position :left) + (= position :right)) + (if ^boolean scale-text + (cur/get-dynamic "scale-ew" rotation) + (cur/get-dynamic "resize-ew" rotation)) + (if ^boolean scale-text + (cur/get-dynamic "scale-ns" rotation) + (cur/get-dynamic "resize-ns" rotation)))] + [:g.resize-handler - (when show-handler? + (when ^boolean show-handler [:circle {:r (/ resize-point-radius zoom) :style {:fillOpacity 1 :stroke color :strokeWidth "1px" :fill "var(--color-white)" :vectorEffect "non-scaling-stroke"} + :data-position (name position) :cx (+ x (/ length 2)) :cy y :transform transform-str}]) @@ -246,42 +289,25 @@ :y target-y :width length :height height - :class (if (#{:left :right} position) - (if scale-text (cur/get-dynamic "scale-ew" rotation) (cur/get-dynamic "resize-ew" rotation)) - (if scale-text (cur/get-dynamic "scale-ns" rotation) (cur/get-dynamic "resize-ns" rotation))) + :class cursor + :data-position (name position) :transform transform-str - :on-pointer-down #(on-resize res-point %) + :on-pointer-down on-resize :style {:fill (if (dbg/enabled? :handlers) "yellow" "none") :stroke-width 0}}]])) -(defn minimum-selrect [{:keys [x y width height] :as selrect}] - (let [final-width (max width min-selrect-side) - final-height (max height min-selrect-side) - offset-x (/ (- final-width width) 2) - offset-y (/ (- final-height height) 2)] - {:x (- x offset-x) - :y (- y offset-y) - :width final-width - :height final-height})) - (mf/defc controls-selection {::mf/wrap-props false} - [props] - (let [shape (obj/get props "shape") - zoom (obj/get props "zoom") - color (obj/get props "color") - on-move-selected (obj/get props "on-move-selected") - on-context-menu (obj/get props "on-context-menu") - disable-handlers (obj/get props "disable-handlers") + [{:keys [shape zoom color on-move-selected on-context-menu disable-handlers]}] + (let [selrect (dm/get-prop shape :selrect) + transform-type (mf/deref refs/current-transform) + transform (gsh/transform-str shape)] - current-transform (mf/deref refs/current-transform) - - selrect (:selrect shape) - transform (gsh/transform-str shape)] - - (when (and (not (:transforming shape)) - (not (#{:move :rotate} current-transform))) - [:g.controls {:pointer-events (if disable-handlers "none" "visible")} + (when (and (some? selrect) + (not (:transforming shape)) + (not (or (= transform-type :move) + (= transform-type :rotate)))) + [:g.controls {:pointer-events (if ^boolean disable-handlers "none" "visible")} ;; Selection rect [:& selection-rect {:rect selrect :transform transform @@ -292,54 +318,61 @@ (mf/defc controls-handlers {::mf/wrap-props false} - [props] - (let [shape (obj/get props "shape") - zoom (obj/get props "zoom") - color (obj/get props "color") - on-resize (obj/get props "on-resize") - on-rotate (obj/get props "on-rotate") - disable-handlers (obj/get props "disable-handlers") - current-transform (mf/deref refs/current-transform) - workspace-read-only? (mf/use-ctx ctx/workspace-read-only?) + [{:keys [shape zoom color on-resize on-rotate disable-handlers]}] + (let [transform-type (mf/deref refs/current-transform) + read-only? (mf/use-ctx ctx/workspace-read-only?) - selrect (:selrect shape) - transform (gsh/transform-matrix shape) + layout (mf/deref refs/workspace-layout) + scale-text? (contains? layout :scale-text) - rotation (-> (gpt/point 1 0) - (gpt/transform (:transform shape)) - (gpt/angle) - (mod 360))] + selrect (dm/get-prop shape :selrect) + transform (gsh/transform-matrix shape) - (when (and (not (#{:move :rotate} current-transform)) - (not workspace-read-only?) - (not (:transforming shape))) - [:g.controls {:pointer-events (if disable-handlers "none" "visible")} - ;; Handlers - (for [{:keys [type position props]} (handlers-for-selection selrect shape zoom)] - (let [rotation - (cond - (and (#{:top-left :bottom-right} position) - (or (and (:flip-x shape) (not (:flip-y shape))) - (and (:flip-y shape) (not (:flip-x shape))))) - (- rotation 90) + rotation (-> (gpt/point 1 0) + (gpt/transform (:transform shape)) + (gpt/angle) + (mod 360)) - (and (#{:top-right :bottom-left} position) - (or (and (:flip-x shape) (not (:flip-y shape))) - (and (:flip-y shape) (not (:flip-x shape))))) - (+ rotation 90) + flip-x (get shape :flip-x) + flip-y (get shape :flip-y) + half-flip? (or (and (some? flip-x) (not (some? flip-y))) + (and (some? flip-y) (not (some? flip-x))))] - :else - rotation) + (when (and (not ^boolean read-only?) + (not (:transforming shape)) + (not (or (= transform-type :move) + (= transform-type :rotate)))) - common-props {:key (dm/str (name type) "-" (name position)) - :zoom zoom - :position position - :on-rotate on-rotate - :on-resize (partial on-resize position) - :transform transform - :rotation rotation - :color color} - props (map->obj (merge common-props props))] + [:g.controls {:pointer-events (if ^boolean disable-handlers "none" "visible")} + (for [handler (calculate-handlers selrect shape zoom)] + (let [type (obj/get handler "type") + position (obj/get handler "position") + props (obj/get handler "props") + rotation (cond + (and ^boolean half-flip? + (or (= position :top-left) + (= position :bottom-right))) + (- rotation 90) + + (and ^boolean half-flip? + (or (= position :top-right) + (= position :bottom-left))) + (- rotation 90) + + :else + rotation) + + props (obj/merge! + #js {:key (dm/str (name type) "-" (name position)) + :scale-text scale-text? + :zoom zoom + :position position + :on-rotate on-rotate + :on-resize on-resize + :transform transform + :rotation rotation + :color color} + props)] (case type :rotation [:> rotation-handler props] :resize-point [:> resize-point-handler props] @@ -348,8 +381,12 @@ ;; --- Selection Handlers (Component) (mf/defc text-edition-selection - [{:keys [shape color zoom] :as props}] - (let [{:keys [x y width height]} shape] + {::mf/wrap-props false} + [{:keys [shape color zoom]}] + (let [x (dm/get-prop shape :x) + y (dm/get-prop shape :y) + width (dm/get-prop shape :width) + height (dm/get-prop shape :height)] [:g.controls [:rect.main {:x x :y y :transform (gsh/transform-str shape) @@ -362,23 +399,31 @@ :fill "none"}}]])) (mf/defc multiple-handlers - [{:keys [shapes selected zoom color disable-handlers] :as props}] + {::mf/wrap-props false} + [{:keys [shapes selected zoom color disable-handlers]}] (let [shape (mf/with-memo [shapes] (-> shapes (gsh/shapes->rect) (assoc :type :multiple) (cts/setup-shape))) + on-resize - (fn [current-position _initial-position event] - (when (dom/left-mouse? event) - (dom/stop-propagation event) - (st/emit! (dw/start-resize current-position selected shape)))) + (mf/use-fn + (mf/deps selected shape) + (fn [event] + (when (dom/left-mouse? event) + (dom/stop-propagation event) + (let [target (dom/get-current-target event) + position (keyword (dom/get-data target "position"))] + (st/emit! (dw/start-resize position selected shape)))))) on-rotate - (fn [event] - (when (dom/left-mouse? event) - (dom/stop-propagation event) - (st/emit! (dw/start-rotate shapes))))] + (mf/use-fn + (mf/deps shapes) + (fn [event] + (when (dom/left-mouse? event) + (dom/stop-propagation event) + (st/emit! (dw/start-rotate shapes)))))] [:& controls-handlers {:shape shape @@ -389,7 +434,8 @@ :on-rotate on-rotate}])) (mf/defc multiple-selection - [{:keys [shapes zoom color disable-handlers on-move-selected on-context-menu] :as props}] + {::mf/wrap-props false} + [{:keys [shapes zoom color disable-handlers on-move-selected on-context-menu]}] (let [shape (mf/with-memo [shapes] (-> shapes (gsh/shapes->rect) @@ -405,20 +451,27 @@ :on-context-menu on-context-menu}])) (mf/defc single-handlers - [{:keys [shape zoom color disable-handlers] :as props}] - (let [shape-id (:id shape) + {::mf/wrap-props false} + [{:keys [shape zoom color disable-handlers]}] + (let [shape-id (dm/get-prop shape :id) on-resize - (fn [current-position _initial-position event] - (when (dom/left-mouse? event) - (dom/stop-propagation event) - (st/emit! (dw/start-resize current-position #{shape-id} shape)))) + (mf/use-fn + (mf/deps shape-id shape) + (fn [event] + (when (dom/left-mouse? event) + (dom/stop-propagation event) + (let [target (dom/get-current-target event) + position (keyword (dom/get-data target "position"))] + (st/emit! (dw/start-resize position #{shape-id} shape)))))) on-rotate - (fn [event] - (when (dom/left-mouse? event) - (dom/stop-propagation event) - (st/emit! (dw/start-rotate [shape]))))] + (mf/use-fn + (mf/deps shape) + (fn [event] + (when (dom/left-mouse? event) + (dom/stop-propagation event) + (st/emit! (dw/start-rotate [shape])))))] [:& controls-handlers {:shape shape @@ -429,7 +482,8 @@ :on-resize on-resize}])) (mf/defc single-selection - [{:keys [shape zoom color disable-handlers on-move-selected on-context-menu] :as props}] + {::mf/wrap-props false} + [{:keys [shape zoom color disable-handlers on-move-selected on-context-menu]}] [:& controls-selection {:shape shape :zoom zoom @@ -439,23 +493,25 @@ :on-context-menu on-context-menu}]) (mf/defc selection-area - {::mf/wrap [mf/memo]} - [{:keys [shapes edition zoom disable-handlers on-move-selected on-context-menu] :as props}] - (let [num (count shapes) - {:keys [type] :as shape} (first shapes) + {::mf/wrap-props false} + [{:keys [shapes edition zoom disable-handlers on-move-selected on-context-menu]}] + (let [total (count shapes) + + shape (first shapes) + shape-id (dm/get-prop shape :id) ;; Note that we don't use mf/deref to avoid a repaint dependency here objects (deref refs/workspace-page-objects) - color (if (and (= num 1) - (ctn/in-any-component? objects shape)) - selection-rect-color-component - selection-rect-color-normal)] + color (if (and (= total 1) ^boolean (ctn/in-any-component? objects shape)) + selection-rect-color-component + selection-rect-color-normal)] + (cond - (zero? num) + (zero? total) nil - (> num 1) + (> total 1) [:& multiple-selection {:shapes shapes :zoom zoom @@ -464,13 +520,14 @@ :on-move-selected on-move-selected :on-context-menu on-context-menu}] - (and (= type :text) (= edition (:id shape))) + (and (cfh/text-shape? shape) + (= edition shape-id)) [:& text-edition-selection {:shape shape :zoom zoom :color color}] - (= edition (:id shape)) + (= edition shape-id) nil :else @@ -483,23 +540,25 @@ :on-context-menu on-context-menu}]))) (mf/defc selection-handlers - {::mf/wrap [mf/memo]} - [{:keys [shapes selected edition zoom disable-handlers] :as props}] - (let [num (count shapes) - {:keys [type] :as shape} (first shapes) + {::mf/wrap-props false} + [{:keys [shapes selected edition zoom disable-handlers]}] + (let [total (count shapes) + + shape (first shapes) + shape-id (dm/get-prop shape :id) ;; Note that we don't use mf/deref to avoid a repaint dependency here objects (deref refs/workspace-page-objects) - color (if (and (= num 1) - (ctn/in-any-component? objects shape)) - selection-rect-color-component - selection-rect-color-normal)] + color (if (and (= total 1) ^boolean (ctn/in-any-component? objects shape)) + selection-rect-color-component + selection-rect-color-normal)] + (cond - (zero? num) + (zero? total) nil - (> num 1) + (> total 1) [:& multiple-handlers {:shapes shapes :selected selected @@ -507,10 +566,11 @@ :color color :disable-handlers disable-handlers}] - (and (= type :text) (= edition (:id shape))) + (and (cfh/text-shape? shape) + (= edition shape-id)) nil - (= edition (:id shape)) + (= edition shape-id) [:& path-editor {:zoom zoom :shape shape}] diff --git a/frontend/src/app/util/array.cljs b/frontend/src/app/util/array.cljs index 2c85375e9..875a4ba32 100644 --- a/frontend/src/app/util/array.cljs +++ b/frontend/src/app/util/array.cljs @@ -15,6 +15,22 @@ (defn conj! "A conj! like function for js arrays." - [a v] - (.push ^js a v) - a) + ([a v] + (.push ^js a v) + a) + ([a v1 v2] + (.push ^js a v1 v2) + a) + ([a v1 v2 v3] + (.push ^js a v1 v2 v3) + a) + ([a v1 v2 v3 v4] + (.push ^js a v1 v2 v3 v4) + a) + ([a v1 v2 v3 v4 v5] + (.push ^js a v1 v2 v3 v4 v5) + a) + ([a v1 v2 v3 v4 v5 v6] + (.push ^js a v1 v2 v3 v4 v5 v6) + a)) +