Add efficiency improvements to workspace components (refactor part 1) (#8887)

* ♻️ 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.

* ♻️ 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.

* ♻️ 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.

* ♻️ 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.

* ♻️ 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.

* ♻️ 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.

* ♻️ 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.

* 🐛 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.
This commit is contained in:
Andrey Antukh 2026-04-14 19:48:59 +02:00 committed by GitHub
parent 3264bc746f
commit f07b954b7e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 163 additions and 160 deletions

View File

@ -577,7 +577,7 @@
:tool drawing-tool}]) :tool drawing-tool}])
(when show-grids? (when show-grids?
[:& frame-grid/frame-grid [:> frame-grid/frame-grid*
{:zoom zoom {:zoom zoom
:selected selected :selected selected
:transform transform :transform transform
@ -588,7 +588,7 @@
:zoom zoom}]) :zoom zoom}])
(when show-snap-points? (when show-snap-points?
[:& snap-points/snap-points [:> snap-points/snap-points*
{:layout layout {:layout layout
:transform transform :transform transform
:drawing drawing-obj :drawing drawing-obj
@ -689,13 +689,13 @@
:disabled (or drawing-tool @space?)}]))) :disabled (or drawing-tool @space?)}])))
(when show-prototypes? (when show-prototypes?
[:& interactions/interactions [:> interactions/interactions*
{:selected selected {:selected selected
:page-id page-id :page-id page-id
:zoom zoom :zoom zoom
:objects objects-modified :objects objects-modified
:current-transform transform :current-transform transform
:hover-disabled? hover-disabled?}])]) :is-hover-disabled hover-disabled?}])])
(when show-gradient-handlers? (when show-gradient-handlers?
[:> gradients/gradient-handlers* [:> gradients/gradient-handlers*

View File

@ -17,7 +17,7 @@
[app.main.refs :as refs] [app.main.refs :as refs]
[rumext.v2 :as mf])) [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)) (let [grid-id (mf/use-memo #(uuid/next))
{:keys [size] :as params} (-> grid :params) {:keys [size] :as params} (-> grid :params)
{color-value :color color-opacity :opacity} (-> grid :params :color) {color-value :color color-opacity :opacity} (-> grid :params :color)
@ -45,7 +45,7 @@
:height (:height frame) :height (:height frame)
:fill (str "url(#" grid-id ")")}]])) :fill (str "url(#" grid-id ")")}]]))
(mf/defc layout-grid (mf/defc layout-grid*
[{:keys [key frame grid zoom]}] [{:keys [key frame grid zoom]}]
(let [{color-value :color color-opacity :opacity} (-> grid :params :color) (let [{color-value :color color-opacity :opacity} (-> grid :params :color)
;; Support for old color format ;; Support for old color format
@ -124,7 +124,7 @@
selrect selrect
parents)) parents))
(mf/defc grid-display-frame (mf/defc grid-display-frame*
{::mf/wrap [mf/memo]} {::mf/wrap [mf/memo]}
[{:keys [frame zoom transforming]}] [{:keys [frame zoom transforming]}]
(let [frame-id (:id frame) (let [frame-id (:id frame)
@ -154,16 +154,16 @@
:zoom zoom :zoom zoom
:grid grid}] :grid grid}]
(case (:type grid) (case (:type grid)
:square [:> square-grid props] :square [:> square-grid* props]
:column [:> layout-grid props] :column [:> layout-grid* props]
:row [:> layout-grid props])))]))) :row [:> layout-grid* props])))])))
(defn has-grid? (defn has-grid?
[{:keys [grids]}] [{:keys [grids]}]
(and (some? grids) (and (some? grids)
(d/not-empty? (->> grids (filter :display))))) (d/not-empty? (->> grids (filter :display)))))
(mf/defc frame-grid (mf/defc frame-grid*
{::mf/wrap [mf/memo]} {::mf/wrap [mf/memo]}
[{:keys [zoom transform selected focus]}] [{:keys [zoom transform selected focus]}]
(let [frames (->> (mf/deref refs/workspace-frames) (let [frames (->> (mf/deref refs/workspace-frames)
@ -175,7 +175,7 @@
(when (and #_(not (is-transform? frame)) (when (and #_(not (is-transform? frame))
(not (ctst/rotated-frame? frame)) (not (ctst/rotated-frame? frame))
(or (empty? focus) (contains? focus (:id frame)))) (or (empty? focus) (contains? focus (:id frame))))
[:& grid-display-frame {:key (str "grid-" (:id frame)) [:> grid-display-frame* {:key (str "grid-" (:id frame))
:zoom zoom :zoom zoom
:frame frame :frame frame
:transforming transforming}]))])) :transforming transforming}]))]))

View File

@ -43,7 +43,7 @@
(def gradient-endpoint-radius-selected 6) (def gradient-endpoint-radius-selected 6)
(def gradient-endpoint-radius-handler 20) (def gradient-endpoint-radius-handler 20)
(mf/defc shadow [{:keys [id offset]}] (mf/defc shadow* [{:keys [id offset]}]
[:filter {:id id [:filter {:id id
:x "-10%" :x "-10%"
:y "-10%" :y "-10%"
@ -61,7 +61,7 @@
(def checkerboard "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA8AAAAPCAIAAAC0tAIdAAACvUlEQVQoFQGyAk39AeLi4gAAAAAAAB0dHQAAAAAAAOPj4wAAAAAAAB0dHQAAAAAAAOPj4wAAAAAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB////AAAAAAAA4+PjAAAAAAAAHR0dAAAAAAAA4+PjAAAAAAAAHR0dAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAATj4+MAAAAAAAAdHR0AAAAAAADj4+MAAAAAAAAdHR0AAAAAAADj4+MAAAAAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAjScaa0cU7nIAAAAASUVORK5CYII=") (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 [{:keys [zoom point color angle selected index
on-click on-pointer-down on-pointer-up on-pointer-move on-lost-pointer-capture]}] on-click on-pointer-down on-pointer-up on-pointer-move on-lost-pointer-capture]}]
[:g {:filter "url(#gradient-drop-shadow)" [:g {:filter "url(#gradient-drop-shadow)"
@ -118,7 +118,7 @@
:r (/ 2 zoom) :r (/ 2 zoom)
:fill "var(--app-white)"}]]) :fill "var(--app-white)"}]])
(mf/defc gradient-handler-transformed (mf/defc gradient-handler-transformed*
[{:keys [from-p [{:keys [from-p
to-p to-p
width-p width-p
@ -270,7 +270,7 @@
[:g.gradient-handlers {:pointer-events "none"} [:g.gradient-handlers {:pointer-events "none"}
[:defs [: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) (let [lv (-> (gpt/to-vec from-p to-p)
(gpt/unit)) (gpt/unit))
@ -425,7 +425,7 @@
(-> (gpt/to-vec from-p to-p) (-> (gpt/to-vec from-p to-p)
(gpt/scale (:offset stop))))] (gpt/scale (:offset stop))))]
[:& gradient-color-handler [:> gradient-color-handler*
{:key index {:key index
:selected (= editing index) :selected (= editing index)
:zoom zoom :zoom zoom
@ -505,7 +505,7 @@
(when (and norm-dist (d/num? norm-dist)) (when (and norm-dist (d/num? norm-dist))
(change! {:width norm-dist})))))] (change! {:width norm-dist})))))]
[:& gradient-handler-transformed [:> gradient-handler-transformed*
{:editing editing {:editing editing
:from-p from-p :from-p from-p
:to-p to-p :to-p to-p

View File

@ -96,8 +96,8 @@
[orig-pos orig-x orig-y dest-pos dest-x dest-y])) [orig-pos orig-x orig-y dest-pos dest-x dest-y]))
(mf/defc interaction-marker (mf/defc interaction-marker*
[{:keys [x y stroke action-type arrow-dir zoom] :as props}] [{:keys [x y stroke action-type arrow-dir zoom]}]
(let [icon-pdata (case action-type (let [icon-pdata (case action-type
:navigate (case arrow-dir :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" :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) ")")}])])) "translate(" (* zoom x) ", " (* zoom y) ")")}])]))
(mf/defc interaction-path (mf/defc interaction-path*
[{:keys [index level orig-shape dest-shape dest-point selected? action-type zoom] :as props}] [{: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] (let [[orig-pos orig-x orig-y dest-pos dest-x dest-y]
(cond (cond
dest-shape dest-shape
@ -162,7 +162,7 @@
arrow-dir (if (= dest-pos :left) :right :left)] 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)} [:g {:on-pointer-down #(on-pointer-down % index orig-shape)}
[:path {:stroke "var(--df-secondary)" [:path {:stroke "var(--df-secondary)"
:fill "none" :fill "none"
@ -170,13 +170,13 @@
:stroke-width (/ 2 zoom) :stroke-width (/ 2 zoom)
:d pdata}] :d pdata}]
(when (not dest-shape) (when (not dest-shape)
[:& interaction-marker {:index index [:> interaction-marker* {:index index
:x dest-x :x dest-x
:y dest-y :y dest-y
:stroke "var(--df-secondary)" :stroke "var(--df-secondary)"
:action-type action-type :action-type action-type
:arrow-dir arrow-dir :arrow-dir arrow-dir
:zoom zoom}])] :zoom zoom}])]
[:g {:on-pointer-down #(on-pointer-down % index orig-shape)} [:g {:on-pointer-down #(on-pointer-down % index orig-shape)}
[:path {:stroke "var(--color-accent-tertiary)" [:path {:stroke "var(--color-accent-tertiary)"
@ -190,36 +190,36 @@
:shape dest-shape :shape dest-shape
:color "var(--color-accent-tertiary)"}]) :color "var(--color-accent-tertiary)"}])
[:& interaction-marker {:index index [:> interaction-marker* {:index index
:x orig-x :x orig-x
:y orig-y :y orig-y
:stroke "var(--color-accent-tertiary)" :stroke "var(--color-accent-tertiary)"
:zoom zoom}] :zoom zoom}]
[:& interaction-marker {:index index [:> interaction-marker* {:index index
:x dest-x :x dest-x
:y dest-y :y dest-y
:stroke "var(--color-accent-tertiary)" :stroke "var(--color-accent-tertiary)"
:action-type action-type :action-type action-type
:arrow-dir arrow-dir :arrow-dir arrow-dir
:zoom zoom}]]))) :zoom zoom}]])))
(mf/defc interaction-handle (mf/defc interaction-handle*
[{:keys [index shape zoom] :as props}] [{:keys [index shape zoom]}]
(let [shape-rect (:selrect shape) (let [shape-rect (:selrect shape)
handle-x (+ (:x shape-rect) (:width shape-rect)) handle-x (+ (:x shape-rect) (:width shape-rect))
handle-y (+ (:y shape-rect) (/ (:height shape-rect) 2))] handle-y (+ (:y shape-rect) (/ (:height shape-rect) 2))]
[:g {:on-pointer-down #(on-pointer-down % index shape)} [:g {:on-pointer-down #(on-pointer-down % index shape)}
[:& interaction-marker {:x handle-x [:> interaction-marker* {:x handle-x
:y handle-y :y handle-y
:stroke "var(--color-accent-tertiary)" :stroke "var(--color-accent-tertiary)"
:action-type :navigate :action-type :navigate
:arrow-dir :right :arrow-dir :right
:zoom zoom}]])) :zoom zoom}]]))
(mf/defc overlay-marker (mf/defc overlay-marker*
[{:keys [page-id index orig-shape dest-shape position objects hover-disabled?] :as props}] [{:keys [page-id index orig-shape dest-shape position objects is-hover-disabled]}]
(let [start-move-position (let [start-move-position
(fn [_] (fn [_]
(st/emit! (dw/start-move-overlay-pos index)))] (st/emit! (dw/start-move-overlay-pos index)))]
@ -250,8 +250,8 @@
(some? thumbnail-data) (some? thumbnail-data)
(assoc :thumbnail thumbnail-data))] (assoc :thumbnail thumbnail-data))]
[:g {:on-pointer-down start-move-position [:g {:on-pointer-down start-move-position
:on-pointer-enter #(reset! hover-disabled? true) :on-pointer-enter #(reset! is-hover-disabled true)
:on-pointer-leave #(reset! hover-disabled? false)} :on-pointer-leave #(reset! is-hover-disabled false)}
[:g {:transform (gmt/translate-matrix (gpt/point (- marker-x dest-x) (- marker-y dest-y)))} [:g {:transform (gmt/translate-matrix (gpt/point (- marker-x dest-x) (- marker-y dest-y)))}
[:& (mf/provider muc/render-thumbnails) {:value true} [:& (mf/provider muc/render-thumbnails) {:value true}
[:& (mf/provider embed/context) {:value false} [:& (mf/provider embed/context) {:value false}
@ -273,8 +273,8 @@
:r 8 :r 8
:fill "var(--color-accent-tertiary)"}]])))) :fill "var(--color-accent-tertiary)"}]]))))
(mf/defc interactions (mf/defc interactions*
[{:keys [current-transform objects zoom selected hover-disabled? page-id] :as props}] [{:keys [current-transform objects zoom selected is-hover-disabled page-id]}]
(let [active-shapes (into [] (let [active-shapes (into []
(comp (filter #(seq (:interactions %)))) (comp (filter #(seq (:interactions %))))
(vals objects)) (vals objects))
@ -305,26 +305,26 @@
selected? (contains? selected (:id shape)) selected? (contains? selected (:id shape))
level (calc-level index (:interactions shape))] level (calc-level index (:interactions shape))]
(when-not selected? (when-not selected?
[:& interaction-path {:key (dm/str "non-selected-" (:id shape) "-" index) [:> interaction-path* {:key (dm/str "non-selected-" (:id shape) "-" index)
:index index :index index
:level level :level level
:orig-shape shape :orig-shape shape
:dest-shape dest-shape :dest-shape dest-shape
:selected selected :selected selected
:selected? false :is-selected false
:action-type (:action-type interaction) :action-type (:action-type interaction)
:zoom zoom}]))))] :zoom zoom}]))))]
[:g.selected [:g.selected
(when (and draw-interaction-to first-selected) (when (and draw-interaction-to first-selected)
[:& interaction-path {:key "interactive" [:> interaction-path* {:key "interactive"
:index nil :index nil
:orig-shape first-selected :orig-shape first-selected
:dest-point draw-interaction-to :dest-point draw-interaction-to
:dest-shape draw-interaction-to-frame :dest-shape draw-interaction-to-frame
:selected? true :is-selected true
:action-type :navigate :action-type :navigate
:zoom zoom}]) :zoom zoom}])
(for [shape selected-shapes] (for [shape selected-shapes]
(if (seq (:interactions shape)) (if (seq (:interactions shape))
(for [[index interaction] (d/enumerate (:interactions shape))] (for [[index interaction] (d/enumerate (:interactions shape))]
@ -333,38 +333,38 @@
(get objects (:destination interaction))) (get objects (:destination interaction)))
level (calc-level index (:interactions shape))] level (calc-level index (:interactions shape))]
[:g {:key (dm/str "interaction-path-" (:id shape) "-" index)} [:g {:key (dm/str "interaction-path-" (:id shape) "-" index)}
[:& interaction-path {:index index [:> interaction-path* {:index index
:level level :level level
:orig-shape shape :orig-shape shape
:dest-shape dest-shape :dest-shape dest-shape
:selected selected :selected selected
:selected? true :is-selected true
:action-type (:action-type interaction) :action-type (:action-type interaction)
:zoom zoom}] :zoom zoom}]
(when (and (or (= (:action-type interaction) :open-overlay) (when (and (or (= (:action-type interaction) :open-overlay)
(= (:action-type interaction) :toggle-overlay)) (= (:action-type interaction) :toggle-overlay))
(= (:overlay-pos-type interaction) :manual)) (= (:overlay-pos-type interaction) :manual))
(if (and (some? move-overlay-to) (if (and (some? move-overlay-to)
(= move-overlay-index index)) (= move-overlay-index index))
[:& overlay-marker {:page-id page-id [:> overlay-marker* {:page-id page-id
:index index :index index
:orig-shape shape :orig-shape shape
:dest-shape dest-shape :dest-shape dest-shape
:position move-overlay-to :position move-overlay-to
:objects objects :objects objects
:hover-disabled? hover-disabled?}] :is-hover-disabled is-hover-disabled}]
[:& overlay-marker {:page-id page-id [:> overlay-marker* {:page-id page-id
:index index :index index
:orig-shape shape :orig-shape shape
:dest-shape dest-shape :dest-shape dest-shape
:position (:overlay-position interaction) :position (:overlay-position interaction)
:objects objects :objects objects
:hover-disabled? hover-disabled?}]))]))) :is-hover-disabled is-hover-disabled}]))])))
(when (and shape (when (and shape
(not (cfh/unframed-shape? shape)) (not (cfh/unframed-shape? shape))
(not (#{:move :rotate} current-transform))) (not (#{:move :rotate} current-transform)))
[:& interaction-handle {:key (:id shape) [:> interaction-handle* {:key (:id shape)
:index nil :index nil
:shape shape :shape shape
:selected selected :selected selected
:zoom zoom}])))]])) :zoom zoom}])))]]))

View File

@ -142,7 +142,7 @@
"Z")) "Z"))
(mf/defc rulers-text (mf/defc rulers-text*
"Draws the text for the rulers in a specific axis" "Draws the text for the rulers in a specific axis"
[{:keys [vbox step offset axis zoom-inverse]}] [{:keys [vbox step offset axis zoom-inverse]}]
(let [clip-id (str "clip-ruler-" (d/name axis)) (let [clip-id (str "clip-ruler-" (d/name axis))
@ -186,13 +186,13 @@
:style {:stroke font-color :style {:stroke font-color
:stroke-width rulers-width}}]]))])) :stroke-width rulers-width}}]]))]))
(mf/defc viewport-frame (mf/defc viewport-frame*
[{:keys [show-rulers? zoom zoom-inverse vbox offset-x offset-y]}] [{:keys [show-rulers zoom zoom-inverse vbox offset-x offset-y]}]
(let [{:keys [width height] x1 :x y1 :y} vbox (let [{:keys [width height] x1 :x y1 :y} vbox
x2 (+ x1 width) x2 (+ x1 width)
y2 (+ y1 height) 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) br (/ canvas-border-radius zoom)
bs (* 4 zoom-inverse)] bs (* 4 zoom-inverse)]
[:* [:*
@ -214,13 +214,13 @@
:fill-rule "evenodd" :fill-rule "evenodd"
:fill rulers-background}]] :fill rulers-background}]]
(when show-rulers? (when show-rulers
(let [step (calculate-step-size zoom)] (let [step (calculate-step-size zoom)]
[:g.viewport-frame-rulers [: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-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-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]}] [{: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 ;; 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 [:g.selection-area
@ -332,8 +332,8 @@
(when (some? vbox) (when (some? vbox)
[:g.viewport-frame {:pointer-events "none"} [:g.viewport-frame {:pointer-events "none"}
[:& viewport-frame [:> viewport-frame*
{:show-rulers? show-rulers? {:show-rulers show-rulers?
:zoom zoom :zoom zoom
:zoom-inverse zoom-inverse :zoom-inverse zoom-inverse
:vbox vbox :vbox vbox
@ -341,7 +341,7 @@
:offset-y offset-y}] :offset-y offset-y}]
(when (and show-rulers? (some? selection-rect)) (when (and show-rulers? (some? selection-rect))
[:& selection-area [:> selection-area*
{:zoom zoom {:zoom zoom
:zoom-inverse zoom-inverse :zoom-inverse zoom-inverse
:vbox vbox :vbox vbox

View File

@ -25,7 +25,7 @@
;; (def ^:private line-opacity 1 ) ;; (def ^:private line-opacity 1 )
;; (def ^:private line-width 2) ;; (def ^:private line-width 2)
(mf/defc snap-point (mf/defc snap-point*
[{:keys [point zoom]}] [{:keys [point zoom]}]
(let [{:keys [x y]} point (let [{:keys [x y]} point
cross-width (/ 3 zoom)] cross-width (/ 3 zoom)]
@ -41,7 +41,7 @@
:y2 (- y cross-width) :y2 (- y cross-width)
:style {:stroke line-color :stroke-width (str (/ line-width zoom))}}]])) :style {:stroke line-color :stroke-width (str (/ line-width zoom))}}]]))
(mf/defc snap-line (mf/defc snap-line*
[{:keys [snap point zoom]}] [{:keys [snap point zoom]}]
[:line {:x1 (:x snap) [:line {:x1 (:x snap)
:y1 (:y snap) :y1 (:y snap)
@ -50,8 +50,8 @@
:style {:stroke line-color :stroke-width (str (/ line-width zoom))} :style {:stroke line-color :stroke-width (str (/ line-width zoom))}
:opacity line-opacity}]) :opacity line-opacity}])
(defn get-snap (defn- get-snap
[coord {:keys [shapes page-id remove-snap? zoom]}] [coord shapes page-id remove-snap zoom]
(let [bounds (gsh/shapes->rect shapes) (let [bounds (gsh/shapes->rect shapes)
frame-id (snap/snap-frame-id shapes)] frame-id (snap/snap-frame-id shapes)]
@ -63,7 +63,7 @@
(rx/merge-map (rx/merge-map
(fn [[frame-id point]] (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 #(mapcat second %))
(rx/map #(map :pt %)) (rx/map #(map :pt %))
(rx/map #(vector point % coord))))) (rx/map #(vector point % coord)))))
@ -74,7 +74,7 @@
[coord] [coord]
(if (= coord :x) :y :x)) (if (= coord :x) :y :x))
(defn add-point-to-snaps (defn- add-point-to-snaps
[[point snaps coord]] [[point snaps coord]]
(let [normalize-coord #(assoc % coord (get point coord))] (let [normalize-coord #(assoc % coord (get point coord))]
(cons point (map normalize-coord snaps)))) (cons point (map normalize-coord snaps))))
@ -100,8 +100,8 @@
(map (fn [[fixedv [minv maxv]]] [(hash-map coord fixedv (flip coord) minv) (map (fn [[fixedv [minv maxv]]] [(hash-map coord fixedv (flip coord) minv)
(hash-map coord fixedv (flip coord) maxv)])))) (hash-map coord fixedv (flip coord) maxv)]))))
(mf/defc snap-feedback (mf/defc snap-feedback*
[{:keys [shapes remove-snap? zoom modifiers] :as props}] [{:keys [shapes remove-snap zoom modifiers page-id]}]
(let [state (mf/use-state []) (let [state (mf/use-state [])
subject (mf/use-memo #(rx/subject)) subject (mf/use-memo #(rx/subject))
@ -116,9 +116,9 @@
(fn [] (fn []
(let [sub (->> subject (let [sub (->> subject
(rx/switch-map (rx/switch-map
(fn [props] (fn [{:keys [shapes page-id remove-snap zoom]}]
(->> (get-snap :y props) (->> (get-snap :y shapes page-id remove-snap zoom)
(rx/combine-latest (get-snap :x props))))) (rx/combine-latest (get-snap :x shapes page-id remove-snap zoom)))))
(rx/map (rx/map
(fn [result] (fn [result]
@ -133,28 +133,31 @@
#(rx/dispose! sub)))) #(rx/dispose! sub))))
(mf/use-effect (mf/use-effect
(mf/deps shapes remove-snap? modifiers) (mf/deps shapes remove-snap modifiers)
(fn [] (fn []
(rx/push! subject props))) (rx/push! subject {:shapes shapes
:page-id page-id
:remove-snap remove-snap
:zoom zoom})))
[:g.snap-feedback [:g.snap-feedback
(for [[from-point to-point] snap-lines] (for [[from-point to-point] snap-lines]
[:& snap-line {:key (str "line-" (:x from-point) [:> snap-line* {:key (str "line-" (:x from-point)
"-" (:y from-point) "-" (:y from-point)
"-" (:x to-point) "-" (:x to-point)
"-" (:y to-point) "-") "-" (:y to-point) "-")
:snap from-point :snap from-point
:point to-point :point to-point
:zoom zoom}]) :zoom zoom}])
(for [point snap-points] (for [point snap-points]
[:& snap-point {:key (str "point-" (:x point) [:> snap-point* {:key (str "point-" (:x point)
"-" (:y point)) "-" (:y point))
:point point :point point
:zoom zoom}])])) :zoom zoom}])]))
(mf/defc snap-points (mf/defc snap-points*
{::mf/wrap [mf/memo]} {::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)) (dm/assert! (set? selected))
(let [shapes (into [] (keep (d/getf objects)) selected) (let [shapes (into [] (keep (d/getf objects)) selected)
@ -165,7 +168,7 @@
(mf/with-memo [layout filter-shapes objects focus] (mf/with-memo [layout filter-shapes objects focus]
(snap/make-remove-snap layout filter-shapes objects focus)) (snap/make-remove-snap layout filter-shapes objects focus))
remove-snap? remove-snap
(mf/use-callback (mf/use-callback
(mf/deps remove-snap-base?) (mf/deps remove-snap-base?)
(fn [{:keys [type grid] :as snap}] (fn [{:keys [type grid] :as snap}]
@ -176,8 +179,8 @@
shapes (if drawing [drawing] shapes) shapes (if drawing [drawing] shapes)
frame-id (snap/snap-frame-id shapes)] frame-id (snap/snap-frame-id shapes)]
(when-not (ctl/any-layout? objects frame-id) (when-not (ctl/any-layout? objects frame-id)
[:& snap-feedback {:shapes shapes [:> snap-feedback* {:shapes shapes
:page-id page-id :page-id page-id
:remove-snap? remove-snap? :remove-snap remove-snap
:zoom zoom}]))) :zoom zoom}])))

View File

@ -78,7 +78,7 @@
:stroke-width (/ 1 zoom)}}])) :stroke-width (/ 1 zoom)}}]))
(mf/defc frame-title (mf/defc frame-title*
{::mf/wrap [mf/memo {::mf/wrap [mf/memo
#(mf/deferred % ts/raf)] #(mf/deferred % ts/raf)]
::mf/forward-ref true} ::mf/forward-ref true}
@ -261,16 +261,16 @@
(not= id uuid/zero) (not= id uuid/zero)
(or (dbg/enabled? :shape-titles) (= parent-id uuid/zero)) (or (dbg/enabled? :shape-titles) (= parent-id uuid/zero))
(or (empty? focus) (contains? focus id))) (or (empty? focus) (contains? focus id)))
[:& frame-title {:key (dm/str "frame-title-" id) [:> frame-title* {:key (dm/str "frame-title-" id)
:frame shape :frame shape
:zoom zoom :zoom zoom
:is-selected (contains? selected id) :is-selected (contains? selected id)
:is-show-artboard-names is-show-artboard-names :is-show-artboard-names is-show-artboard-names
:is-show-id (dbg/enabled? :shape-titles) :is-show-id (dbg/enabled? :shape-titles)
:is-grid-edition (and (= id edition) grid-edition?) :is-grid-edition (and (= id edition) grid-edition?)
:on-frame-enter on-frame-enter :on-frame-enter on-frame-enter
:on-frame-leave on-frame-leave :on-frame-leave on-frame-leave
:on-frame-select on-frame-select}]))])) :on-frame-select on-frame-select}]))]))
(mf/defc frame-flow* (mf/defc frame-flow*
[{:keys [flow frame is-selected zoom on-frame-enter on-frame-leave on-frame-select]}] [{:keys [flow frame is-selected zoom on-frame-enter on-frame-leave on-frame-select]}]

View File

@ -636,7 +636,7 @@
:tool drawing-tool}]) :tool drawing-tool}])
(when show-grids? (when show-grids?
[:& frame-grid/frame-grid [:> frame-grid/frame-grid*
{:zoom zoom {:zoom zoom
:selected selected :selected selected
:transform transform :transform transform
@ -647,7 +647,7 @@
:zoom zoom}]) :zoom zoom}])
(when show-snap-points? (when show-snap-points?
[:& snap-points/snap-points [:> snap-points/snap-points*
{:layout layout {:layout layout
:transform transform :transform transform
:drawing drawing-obj :drawing drawing-obj
@ -749,13 +749,13 @@
:disabled (or drawing-tool @space?)}]))) :disabled (or drawing-tool @space?)}])))
(when show-prototypes? (when show-prototypes?
[:& interactions/interactions [:> interactions/interactions*
{:selected selected {:selected selected
:page-id page-id :page-id page-id
:zoom zoom :zoom zoom
:objects objects-modified :objects objects-modified
:current-transform transform :current-transform transform
:hover-disabled? hover-disabled?}])]) :is-hover-disabled hover-disabled?}])])
(when show-gradient-handlers? (when show-gradient-handlers?
[:> gradients/gradient-handlers* [:> gradients/gradient-handlers*