From f07b954b7e01b8a1af6ed4bbc9cf15f48c507d11 Mon Sep 17 00:00:00 2001 From: Andrey Antukh Date: Tue, 14 Apr 2026 19:48:59 +0200 Subject: [PATCH] :zap: Add efficiency improvements to workspace components (refactor part 1) (#8887) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * :recycle: Convert snap-points components to modern rumext format Migrate snap-point, snap-line, snap-feedback, and snap-points from legacy mf/defc format to modern * suffix format. This enables optimized props handling by the rumext macro, eliminating implicit JS object wrapping overhead on each render. All internal and external call sites updated to use [:> component* props] syntax. * :recycle: Convert frame-title to modern rumext format Migrate frame-title from legacy mf/defc format to modern * suffix format. The component was using legacy implicit props wrapping without ::mf/wrap-props false or ::mf/props :obj, causing unnecessary JS object conversion overhead on each render. The parent frame-titles* call site updated to use [:> frame-title* props] syntax. * :recycle: Convert interactions components to modern rumext format Migrate interaction-marker, interaction-path, interaction-handle, overlay-marker, and interactions from legacy mf/defc format to modern * suffix format. These five components had zero props optimization applied, causing implicit JS object wrapping on every render. All internal and external call sites updated to use [:> component* props] syntax. * :recycle: Convert rulers components to modern rumext format Migrate rulers-text, viewport-frame, and selection-area from legacy mf/defc format to modern * suffix format. These three components in the always-visible rulers layer had zero props optimization applied. Internal call sites in the parent rulers component updated to use [:> component* props] syntax. * :recycle: Convert frame-grid components to modern rumext format Migrate square-grid, layout-grid, grid-display-frame, and frame-grid from legacy mf/defc format to modern * suffix format. These four components render grid patterns per-frame with zero props optimization. All internal and external call sites updated to use [:> component* props] syntax. * :recycle: Convert gradient handler components to modern rumext format Migrate shadow, gradient-color-handler, and gradient-handler-transformed from legacy mf/defc format to modern * suffix format. These components are rendered during gradient editing with zero props optimization applied. Internal call sites in gradient-handler-transformed and gradient-handlers-impl updated to use [:> component* props] syntax. * :recycle: Rename ?-ending props in modernized workspace viewport components Apply prop naming rules to all * components migrated in the previous batch: - remove-snap? -> remove-snap in snap-feedback* (and get-snap helper) - selected? -> is-selected in interaction-path* - hover-disabled? -> is-hover-disabled in overlay-marker* and interactions* - show-rulers? -> show-rulers in viewport-frame* Update all internal and external call sites consistently. * :bug: Fix get-snap call in snap-feedback* using JS props object Modern rumext *-suffix components receive props as JS objects, not Clojure maps. snap-feedback* was pushing the raw props object into the rx/subject and get-snap was destructuring it as a Clojure map, causing all keys to resolve to nil. Fix by: - Changing get-snap to take positional arguments (coord, shapes, page-id, remove-snap, zoom) instead of a map-destructured opts arg - Building an explicit Clojure map from the bound locals before pushing to the subject - Destructuring that map inside the rx/switch-map callback and calling get-snap with positional args Also mark get-snap and add-point-to-snaps as private (defn-), consistent with the other helpers in the namespace — none are referenced externally. --- .../src/app/main/ui/workspace/viewport.cljs | 8 +- .../ui/workspace/viewport/frame_grid.cljs | 22 +-- .../main/ui/workspace/viewport/gradients.cljs | 12 +- .../ui/workspace/viewport/interactions.cljs | 164 +++++++++--------- .../main/ui/workspace/viewport/rulers.cljs | 22 +-- .../ui/workspace/viewport/snap_points.cljs | 65 +++---- .../main/ui/workspace/viewport/widgets.cljs | 22 +-- .../app/main/ui/workspace/viewport_wasm.cljs | 8 +- 8 files changed, 163 insertions(+), 160 deletions(-) diff --git a/frontend/src/app/main/ui/workspace/viewport.cljs b/frontend/src/app/main/ui/workspace/viewport.cljs index b0e540ac71..40f4344d29 100644 --- a/frontend/src/app/main/ui/workspace/viewport.cljs +++ b/frontend/src/app/main/ui/workspace/viewport.cljs @@ -577,7 +577,7 @@ :tool drawing-tool}]) (when show-grids? - [:& frame-grid/frame-grid + [:> frame-grid/frame-grid* {:zoom zoom :selected selected :transform transform @@ -588,7 +588,7 @@ :zoom zoom}]) (when show-snap-points? - [:& snap-points/snap-points + [:> snap-points/snap-points* {:layout layout :transform transform :drawing drawing-obj @@ -689,13 +689,13 @@ :disabled (or drawing-tool @space?)}]))) (when show-prototypes? - [:& interactions/interactions + [:> interactions/interactions* {:selected selected :page-id page-id :zoom zoom :objects objects-modified :current-transform transform - :hover-disabled? hover-disabled?}])]) + :is-hover-disabled hover-disabled?}])]) (when show-gradient-handlers? [:> gradients/gradient-handlers* diff --git a/frontend/src/app/main/ui/workspace/viewport/frame_grid.cljs b/frontend/src/app/main/ui/workspace/viewport/frame_grid.cljs index 61246ea705..5fafd22a6e 100644 --- a/frontend/src/app/main/ui/workspace/viewport/frame_grid.cljs +++ b/frontend/src/app/main/ui/workspace/viewport/frame_grid.cljs @@ -17,7 +17,7 @@ [app.main.refs :as refs] [rumext.v2 :as mf])) -(mf/defc square-grid [{:keys [frame zoom grid] :as props}] +(mf/defc square-grid* [{:keys [frame zoom grid]}] (let [grid-id (mf/use-memo #(uuid/next)) {:keys [size] :as params} (-> grid :params) {color-value :color color-opacity :opacity} (-> grid :params :color) @@ -45,7 +45,7 @@ :height (:height frame) :fill (str "url(#" grid-id ")")}]])) -(mf/defc layout-grid +(mf/defc layout-grid* [{:keys [key frame grid zoom]}] (let [{color-value :color color-opacity :opacity} (-> grid :params :color) ;; Support for old color format @@ -124,7 +124,7 @@ selrect parents)) -(mf/defc grid-display-frame +(mf/defc grid-display-frame* {::mf/wrap [mf/memo]} [{:keys [frame zoom transforming]}] (let [frame-id (:id frame) @@ -154,16 +154,16 @@ :zoom zoom :grid grid}] (case (:type grid) - :square [:> square-grid props] - :column [:> layout-grid props] - :row [:> layout-grid props])))]))) + :square [:> square-grid* props] + :column [:> layout-grid* props] + :row [:> layout-grid* props])))]))) (defn has-grid? [{:keys [grids]}] (and (some? grids) (d/not-empty? (->> grids (filter :display))))) -(mf/defc frame-grid +(mf/defc frame-grid* {::mf/wrap [mf/memo]} [{:keys [zoom transform selected focus]}] (let [frames (->> (mf/deref refs/workspace-frames) @@ -175,7 +175,7 @@ (when (and #_(not (is-transform? frame)) (not (ctst/rotated-frame? frame)) (or (empty? focus) (contains? focus (:id frame)))) - [:& grid-display-frame {:key (str "grid-" (:id frame)) - :zoom zoom - :frame frame - :transforming transforming}]))])) + [:> grid-display-frame* {:key (str "grid-" (:id frame)) + :zoom zoom + :frame frame + :transforming transforming}]))])) diff --git a/frontend/src/app/main/ui/workspace/viewport/gradients.cljs b/frontend/src/app/main/ui/workspace/viewport/gradients.cljs index 9573efab01..cd2623fd47 100644 --- a/frontend/src/app/main/ui/workspace/viewport/gradients.cljs +++ b/frontend/src/app/main/ui/workspace/viewport/gradients.cljs @@ -43,7 +43,7 @@ (def gradient-endpoint-radius-selected 6) (def gradient-endpoint-radius-handler 20) -(mf/defc shadow [{:keys [id offset]}] +(mf/defc shadow* [{:keys [id offset]}] [:filter {:id id :x "-10%" :y "-10%" @@ -61,7 +61,7 @@ (def checkerboard "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA8AAAAPCAIAAAC0tAIdAAACvUlEQVQoFQGyAk39AeLi4gAAAAAAAB0dHQAAAAAAAOPj4wAAAAAAAB0dHQAAAAAAAOPj4wAAAAAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB////AAAAAAAA4+PjAAAAAAAAHR0dAAAAAAAA4+PjAAAAAAAAHR0dAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAATj4+MAAAAAAAAdHR0AAAAAAADj4+MAAAAAAAAdHR0AAAAAAADj4+MAAAAAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAjScaa0cU7nIAAAAASUVORK5CYII=") -(mf/defc gradient-color-handler +(mf/defc gradient-color-handler* [{:keys [zoom point color angle selected index on-click on-pointer-down on-pointer-up on-pointer-move on-lost-pointer-capture]}] [:g {:filter "url(#gradient-drop-shadow)" @@ -118,7 +118,7 @@ :r (/ 2 zoom) :fill "var(--app-white)"}]]) -(mf/defc gradient-handler-transformed +(mf/defc gradient-handler-transformed* [{:keys [from-p to-p width-p @@ -270,7 +270,7 @@ [:g.gradient-handlers {:pointer-events "none"} [:defs - [:& shadow {:id "gradient-drop-shadow" :offset (/ 2 zoom)}]] + [:> shadow* {:id "gradient-drop-shadow" :offset (/ 2 zoom)}]] (let [lv (-> (gpt/to-vec from-p to-p) (gpt/unit)) @@ -425,7 +425,7 @@ (-> (gpt/to-vec from-p to-p) (gpt/scale (:offset stop))))] - [:& gradient-color-handler + [:> gradient-color-handler* {:key index :selected (= editing index) :zoom zoom @@ -505,7 +505,7 @@ (when (and norm-dist (d/num? norm-dist)) (change! {:width norm-dist})))))] - [:& gradient-handler-transformed + [:> gradient-handler-transformed* {:editing editing :from-p from-p :to-p to-p diff --git a/frontend/src/app/main/ui/workspace/viewport/interactions.cljs b/frontend/src/app/main/ui/workspace/viewport/interactions.cljs index daac5372e8..8617405003 100644 --- a/frontend/src/app/main/ui/workspace/viewport/interactions.cljs +++ b/frontend/src/app/main/ui/workspace/viewport/interactions.cljs @@ -96,8 +96,8 @@ [orig-pos orig-x orig-y dest-pos dest-x dest-y])) -(mf/defc interaction-marker - [{:keys [x y stroke action-type arrow-dir zoom] :as props}] +(mf/defc interaction-marker* + [{:keys [x y stroke action-type arrow-dir zoom]}] (let [icon-pdata (case action-type :navigate (case arrow-dir :right "M -6.5 0 L 5.5 0 M 6.715 0.715 L -0.5 -6.5 M 6.715 -0.715 L -0.365 6.635" @@ -138,8 +138,8 @@ "translate(" (* zoom x) ", " (* zoom y) ")")}])])) -(mf/defc interaction-path - [{:keys [index level orig-shape dest-shape dest-point selected? action-type zoom] :as props}] +(mf/defc interaction-path* + [{:keys [index level orig-shape dest-shape dest-point is-selected action-type zoom]}] (let [[orig-pos orig-x orig-y dest-pos dest-x dest-y] (cond dest-shape @@ -162,7 +162,7 @@ arrow-dir (if (= dest-pos :left) :right :left)] - (if-not selected? + (if-not is-selected [:g {:on-pointer-down #(on-pointer-down % index orig-shape)} [:path {:stroke "var(--df-secondary)" :fill "none" @@ -170,13 +170,13 @@ :stroke-width (/ 2 zoom) :d pdata}] (when (not dest-shape) - [:& interaction-marker {:index index - :x dest-x - :y dest-y - :stroke "var(--df-secondary)" - :action-type action-type - :arrow-dir arrow-dir - :zoom zoom}])] + [:> interaction-marker* {:index index + :x dest-x + :y dest-y + :stroke "var(--df-secondary)" + :action-type action-type + :arrow-dir arrow-dir + :zoom zoom}])] [:g {:on-pointer-down #(on-pointer-down % index orig-shape)} [:path {:stroke "var(--color-accent-tertiary)" @@ -190,36 +190,36 @@ :shape dest-shape :color "var(--color-accent-tertiary)"}]) - [:& interaction-marker {:index index - :x orig-x - :y orig-y - :stroke "var(--color-accent-tertiary)" - :zoom zoom}] - [:& interaction-marker {:index index - :x dest-x - :y dest-y - :stroke "var(--color-accent-tertiary)" - :action-type action-type - :arrow-dir arrow-dir - :zoom zoom}]]))) + [:> interaction-marker* {:index index + :x orig-x + :y orig-y + :stroke "var(--color-accent-tertiary)" + :zoom zoom}] + [:> interaction-marker* {:index index + :x dest-x + :y dest-y + :stroke "var(--color-accent-tertiary)" + :action-type action-type + :arrow-dir arrow-dir + :zoom zoom}]]))) -(mf/defc interaction-handle - [{:keys [index shape zoom] :as props}] +(mf/defc interaction-handle* + [{:keys [index shape zoom]}] (let [shape-rect (:selrect shape) handle-x (+ (:x shape-rect) (:width shape-rect)) handle-y (+ (:y shape-rect) (/ (:height shape-rect) 2))] [:g {:on-pointer-down #(on-pointer-down % index shape)} - [:& interaction-marker {:x handle-x - :y handle-y - :stroke "var(--color-accent-tertiary)" - :action-type :navigate - :arrow-dir :right - :zoom zoom}]])) + [:> interaction-marker* {:x handle-x + :y handle-y + :stroke "var(--color-accent-tertiary)" + :action-type :navigate + :arrow-dir :right + :zoom zoom}]])) -(mf/defc overlay-marker - [{:keys [page-id index orig-shape dest-shape position objects hover-disabled?] :as props}] +(mf/defc overlay-marker* + [{:keys [page-id index orig-shape dest-shape position objects is-hover-disabled]}] (let [start-move-position (fn [_] (st/emit! (dw/start-move-overlay-pos index)))] @@ -250,8 +250,8 @@ (some? thumbnail-data) (assoc :thumbnail thumbnail-data))] [:g {:on-pointer-down start-move-position - :on-pointer-enter #(reset! hover-disabled? true) - :on-pointer-leave #(reset! hover-disabled? false)} + :on-pointer-enter #(reset! is-hover-disabled true) + :on-pointer-leave #(reset! is-hover-disabled false)} [:g {:transform (gmt/translate-matrix (gpt/point (- marker-x dest-x) (- marker-y dest-y)))} [:& (mf/provider muc/render-thumbnails) {:value true} [:& (mf/provider embed/context) {:value false} @@ -273,8 +273,8 @@ :r 8 :fill "var(--color-accent-tertiary)"}]])))) -(mf/defc interactions - [{:keys [current-transform objects zoom selected hover-disabled? page-id] :as props}] +(mf/defc interactions* + [{:keys [current-transform objects zoom selected is-hover-disabled page-id]}] (let [active-shapes (into [] (comp (filter #(seq (:interactions %)))) (vals objects)) @@ -305,26 +305,26 @@ selected? (contains? selected (:id shape)) level (calc-level index (:interactions shape))] (when-not selected? - [:& interaction-path {:key (dm/str "non-selected-" (:id shape) "-" index) - :index index - :level level - :orig-shape shape - :dest-shape dest-shape - :selected selected - :selected? false - :action-type (:action-type interaction) - :zoom zoom}]))))] + [:> interaction-path* {:key (dm/str "non-selected-" (:id shape) "-" index) + :index index + :level level + :orig-shape shape + :dest-shape dest-shape + :selected selected + :is-selected false + :action-type (:action-type interaction) + :zoom zoom}]))))] [:g.selected (when (and draw-interaction-to first-selected) - [:& interaction-path {:key "interactive" - :index nil - :orig-shape first-selected - :dest-point draw-interaction-to - :dest-shape draw-interaction-to-frame - :selected? true - :action-type :navigate - :zoom zoom}]) + [:> interaction-path* {:key "interactive" + :index nil + :orig-shape first-selected + :dest-point draw-interaction-to + :dest-shape draw-interaction-to-frame + :is-selected true + :action-type :navigate + :zoom zoom}]) (for [shape selected-shapes] (if (seq (:interactions shape)) (for [[index interaction] (d/enumerate (:interactions shape))] @@ -333,38 +333,38 @@ (get objects (:destination interaction))) level (calc-level index (:interactions shape))] [:g {:key (dm/str "interaction-path-" (:id shape) "-" index)} - [:& interaction-path {:index index - :level level - :orig-shape shape - :dest-shape dest-shape - :selected selected - :selected? true - :action-type (:action-type interaction) - :zoom zoom}] + [:> interaction-path* {:index index + :level level + :orig-shape shape + :dest-shape dest-shape + :selected selected + :is-selected true + :action-type (:action-type interaction) + :zoom zoom}] (when (and (or (= (:action-type interaction) :open-overlay) (= (:action-type interaction) :toggle-overlay)) (= (:overlay-pos-type interaction) :manual)) (if (and (some? move-overlay-to) (= move-overlay-index index)) - [:& overlay-marker {:page-id page-id - :index index - :orig-shape shape - :dest-shape dest-shape - :position move-overlay-to - :objects objects - :hover-disabled? hover-disabled?}] - [:& overlay-marker {:page-id page-id - :index index - :orig-shape shape - :dest-shape dest-shape - :position (:overlay-position interaction) - :objects objects - :hover-disabled? hover-disabled?}]))]))) + [:> overlay-marker* {:page-id page-id + :index index + :orig-shape shape + :dest-shape dest-shape + :position move-overlay-to + :objects objects + :is-hover-disabled is-hover-disabled}] + [:> overlay-marker* {:page-id page-id + :index index + :orig-shape shape + :dest-shape dest-shape + :position (:overlay-position interaction) + :objects objects + :is-hover-disabled is-hover-disabled}]))]))) (when (and shape (not (cfh/unframed-shape? shape)) (not (#{:move :rotate} current-transform))) - [:& interaction-handle {:key (:id shape) - :index nil - :shape shape - :selected selected - :zoom zoom}])))]])) + [:> interaction-handle* {:key (:id shape) + :index nil + :shape shape + :selected selected + :zoom zoom}])))]])) diff --git a/frontend/src/app/main/ui/workspace/viewport/rulers.cljs b/frontend/src/app/main/ui/workspace/viewport/rulers.cljs index bec8eaf330..6b23bb277e 100644 --- a/frontend/src/app/main/ui/workspace/viewport/rulers.cljs +++ b/frontend/src/app/main/ui/workspace/viewport/rulers.cljs @@ -142,7 +142,7 @@ "Z")) -(mf/defc rulers-text +(mf/defc rulers-text* "Draws the text for the rulers in a specific axis" [{:keys [vbox step offset axis zoom-inverse]}] (let [clip-id (str "clip-ruler-" (d/name axis)) @@ -186,13 +186,13 @@ :style {:stroke font-color :stroke-width rulers-width}}]]))])) -(mf/defc viewport-frame - [{:keys [show-rulers? zoom zoom-inverse vbox offset-x offset-y]}] +(mf/defc viewport-frame* + [{:keys [show-rulers zoom zoom-inverse vbox offset-x offset-y]}] (let [{:keys [width height] x1 :x y1 :y} vbox x2 (+ x1 width) y2 (+ y1 height) - bw (if show-rulers? (* ruler-area-size zoom-inverse) 0) + bw (if show-rulers (* ruler-area-size zoom-inverse) 0) br (/ canvas-border-radius zoom) bs (* 4 zoom-inverse)] [:* @@ -214,13 +214,13 @@ :fill-rule "evenodd" :fill rulers-background}]] - (when show-rulers? + (when show-rulers (let [step (calculate-step-size zoom)] [:g.viewport-frame-rulers - [:& rulers-text {:vbox vbox :offset offset-x :step step :zoom-inverse zoom-inverse :axis :x}] - [:& rulers-text {:vbox vbox :offset offset-y :step step :zoom-inverse zoom-inverse :axis :y}]]))])) + [:> rulers-text* {:vbox vbox :offset offset-x :step step :zoom-inverse zoom-inverse :axis :x}] + [:> rulers-text* {:vbox vbox :offset offset-y :step step :zoom-inverse zoom-inverse :axis :y}]]))])) -(mf/defc selection-area +(mf/defc selection-area* [{:keys [vbox zoom-inverse selection-rect offset-x offset-y]}] ;; When using the format-number callls we consider if the guide is associated to a frame and we show the position relative to it with the offset [:g.selection-area @@ -332,8 +332,8 @@ (when (some? vbox) [:g.viewport-frame {:pointer-events "none"} - [:& viewport-frame - {:show-rulers? show-rulers? + [:> viewport-frame* + {:show-rulers show-rulers? :zoom zoom :zoom-inverse zoom-inverse :vbox vbox @@ -341,7 +341,7 @@ :offset-y offset-y}] (when (and show-rulers? (some? selection-rect)) - [:& selection-area + [:> selection-area* {:zoom zoom :zoom-inverse zoom-inverse :vbox vbox diff --git a/frontend/src/app/main/ui/workspace/viewport/snap_points.cljs b/frontend/src/app/main/ui/workspace/viewport/snap_points.cljs index d65ae80f06..64ce4ab55e 100644 --- a/frontend/src/app/main/ui/workspace/viewport/snap_points.cljs +++ b/frontend/src/app/main/ui/workspace/viewport/snap_points.cljs @@ -25,7 +25,7 @@ ;; (def ^:private line-opacity 1 ) ;; (def ^:private line-width 2) -(mf/defc snap-point +(mf/defc snap-point* [{:keys [point zoom]}] (let [{:keys [x y]} point cross-width (/ 3 zoom)] @@ -41,7 +41,7 @@ :y2 (- y cross-width) :style {:stroke line-color :stroke-width (str (/ line-width zoom))}}]])) -(mf/defc snap-line +(mf/defc snap-line* [{:keys [snap point zoom]}] [:line {:x1 (:x snap) :y1 (:y snap) @@ -50,8 +50,8 @@ :style {:stroke line-color :stroke-width (str (/ line-width zoom))} :opacity line-opacity}]) -(defn get-snap - [coord {:keys [shapes page-id remove-snap? zoom]}] +(defn- get-snap + [coord shapes page-id remove-snap zoom] (let [bounds (gsh/shapes->rect shapes) frame-id (snap/snap-frame-id shapes)] @@ -63,7 +63,7 @@ (rx/merge-map (fn [[frame-id point]] - (->> (snap/get-snap-points page-id frame-id remove-snap? zoom point coord) + (->> (snap/get-snap-points page-id frame-id remove-snap zoom point coord) (rx/map #(mapcat second %)) (rx/map #(map :pt %)) (rx/map #(vector point % coord))))) @@ -74,7 +74,7 @@ [coord] (if (= coord :x) :y :x)) -(defn add-point-to-snaps +(defn- add-point-to-snaps [[point snaps coord]] (let [normalize-coord #(assoc % coord (get point coord))] (cons point (map normalize-coord snaps)))) @@ -100,8 +100,8 @@ (map (fn [[fixedv [minv maxv]]] [(hash-map coord fixedv (flip coord) minv) (hash-map coord fixedv (flip coord) maxv)])))) -(mf/defc snap-feedback - [{:keys [shapes remove-snap? zoom modifiers] :as props}] +(mf/defc snap-feedback* + [{:keys [shapes remove-snap zoom modifiers page-id]}] (let [state (mf/use-state []) subject (mf/use-memo #(rx/subject)) @@ -116,9 +116,9 @@ (fn [] (let [sub (->> subject (rx/switch-map - (fn [props] - (->> (get-snap :y props) - (rx/combine-latest (get-snap :x props))))) + (fn [{:keys [shapes page-id remove-snap zoom]}] + (->> (get-snap :y shapes page-id remove-snap zoom) + (rx/combine-latest (get-snap :x shapes page-id remove-snap zoom))))) (rx/map (fn [result] @@ -133,28 +133,31 @@ #(rx/dispose! sub)))) (mf/use-effect - (mf/deps shapes remove-snap? modifiers) + (mf/deps shapes remove-snap modifiers) (fn [] - (rx/push! subject props))) + (rx/push! subject {:shapes shapes + :page-id page-id + :remove-snap remove-snap + :zoom zoom}))) [:g.snap-feedback (for [[from-point to-point] snap-lines] - [:& snap-line {:key (str "line-" (:x from-point) - "-" (:y from-point) - "-" (:x to-point) - "-" (:y to-point) "-") - :snap from-point - :point to-point - :zoom zoom}]) + [:> snap-line* {:key (str "line-" (:x from-point) + "-" (:y from-point) + "-" (:x to-point) + "-" (:y to-point) "-") + :snap from-point + :point to-point + :zoom zoom}]) (for [point snap-points] - [:& snap-point {:key (str "point-" (:x point) - "-" (:y point)) - :point point - :zoom zoom}])])) + [:> snap-point* {:key (str "point-" (:x point) + "-" (:y point)) + :point point + :zoom zoom}])])) -(mf/defc snap-points +(mf/defc snap-points* {::mf/wrap [mf/memo]} - [{:keys [layout zoom objects selected page-id drawing focus] :as props}] + [{:keys [layout zoom objects selected page-id drawing focus]}] (dm/assert! (set? selected)) (let [shapes (into [] (keep (d/getf objects)) selected) @@ -165,7 +168,7 @@ (mf/with-memo [layout filter-shapes objects focus] (snap/make-remove-snap layout filter-shapes objects focus)) - remove-snap? + remove-snap (mf/use-callback (mf/deps remove-snap-base?) (fn [{:keys [type grid] :as snap}] @@ -176,8 +179,8 @@ shapes (if drawing [drawing] shapes) frame-id (snap/snap-frame-id shapes)] (when-not (ctl/any-layout? objects frame-id) - [:& snap-feedback {:shapes shapes - :page-id page-id - :remove-snap? remove-snap? - :zoom zoom}]))) + [:> snap-feedback* {:shapes shapes + :page-id page-id + :remove-snap remove-snap + :zoom zoom}]))) diff --git a/frontend/src/app/main/ui/workspace/viewport/widgets.cljs b/frontend/src/app/main/ui/workspace/viewport/widgets.cljs index 7a25682209..a47897d2d6 100644 --- a/frontend/src/app/main/ui/workspace/viewport/widgets.cljs +++ b/frontend/src/app/main/ui/workspace/viewport/widgets.cljs @@ -78,7 +78,7 @@ :stroke-width (/ 1 zoom)}}])) -(mf/defc frame-title +(mf/defc frame-title* {::mf/wrap [mf/memo #(mf/deferred % ts/raf)] ::mf/forward-ref true} @@ -261,16 +261,16 @@ (not= id uuid/zero) (or (dbg/enabled? :shape-titles) (= parent-id uuid/zero)) (or (empty? focus) (contains? focus id))) - [:& frame-title {:key (dm/str "frame-title-" id) - :frame shape - :zoom zoom - :is-selected (contains? selected id) - :is-show-artboard-names is-show-artboard-names - :is-show-id (dbg/enabled? :shape-titles) - :is-grid-edition (and (= id edition) grid-edition?) - :on-frame-enter on-frame-enter - :on-frame-leave on-frame-leave - :on-frame-select on-frame-select}]))])) + [:> frame-title* {:key (dm/str "frame-title-" id) + :frame shape + :zoom zoom + :is-selected (contains? selected id) + :is-show-artboard-names is-show-artboard-names + :is-show-id (dbg/enabled? :shape-titles) + :is-grid-edition (and (= id edition) grid-edition?) + :on-frame-enter on-frame-enter + :on-frame-leave on-frame-leave + :on-frame-select on-frame-select}]))])) (mf/defc frame-flow* [{:keys [flow frame is-selected zoom on-frame-enter on-frame-leave on-frame-select]}] diff --git a/frontend/src/app/main/ui/workspace/viewport_wasm.cljs b/frontend/src/app/main/ui/workspace/viewport_wasm.cljs index 091a00a3e7..09b7fa6282 100644 --- a/frontend/src/app/main/ui/workspace/viewport_wasm.cljs +++ b/frontend/src/app/main/ui/workspace/viewport_wasm.cljs @@ -636,7 +636,7 @@ :tool drawing-tool}]) (when show-grids? - [:& frame-grid/frame-grid + [:> frame-grid/frame-grid* {:zoom zoom :selected selected :transform transform @@ -647,7 +647,7 @@ :zoom zoom}]) (when show-snap-points? - [:& snap-points/snap-points + [:> snap-points/snap-points* {:layout layout :transform transform :drawing drawing-obj @@ -749,13 +749,13 @@ :disabled (or drawing-tool @space?)}]))) (when show-prototypes? - [:& interactions/interactions + [:> interactions/interactions* {:selected selected :page-id page-id :zoom zoom :objects objects-modified :current-transform transform - :hover-disabled? hover-disabled?}])]) + :is-hover-disabled hover-disabled?}])]) (when show-gradient-handlers? [:> gradients/gradient-handlers*