From d6317297d7493787a55cb85ce47971161161c98e Mon Sep 17 00:00:00 2001 From: "alonso.torres" Date: Wed, 31 Aug 2022 16:30:30 +0200 Subject: [PATCH] :bug: Fix error when moving nested frames outside --- CHANGES.md | 2 + .../src/app/main/ui/workspace/shapes.cljs | 34 +++-- .../app/main/ui/workspace/shapes/frame.cljs | 141 ++++++++++-------- .../ui/workspace/viewport/pixel_overlay.cljs | 26 +++- 4 files changed, 120 insertions(+), 83 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 630895b8d9..ea75c9dcad 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -4,7 +4,9 @@ ### :bug: Bugs fixed +- Fix error when moving nested frames outside [Taiga #4017] https://tree.taiga.io/project/penpot/issue/4017 - Fix problem when hovering over nested frames [Taiga #4018] https://tree.taiga.io/project/penpot/issue/4018 + ## 1.15.2-beta ### :bug: Bugs fixed diff --git a/frontend/src/app/main/ui/workspace/shapes.cljs b/frontend/src/app/main/ui/workspace/shapes.cljs index 0c93d33eda..298a8b24d0 100644 --- a/frontend/src/app/main/ui/workspace/shapes.cljs +++ b/frontend/src/app/main/ui/workspace/shapes.cljs @@ -32,7 +32,8 @@ (declare group-wrapper) (declare svg-raw-wrapper) (declare bool-wrapper) -(declare frame-wrapper) +(declare root-frame-wrapper) +(declare nested-frame-wrapper) (def circle-wrapper (common/generic-wrapper-factory circle/circle-shape)) (def image-wrapper (common/generic-wrapper-factory image/image-shape)) @@ -62,15 +63,25 @@ (mapcat #(cph/get-children-with-self objects (:id %))))] [:& ff/fontfaces-style {:shapes (into [] xform shapes)}]) - (for [item shapes] - (if (cph/frame-shape? item) - [:& frame-wrapper {:shape item - :key (:id item) - :objects (get frame-objects (:id item)) - :thumbnail? (not (contains? active-frames (:id item)))}] + (for [shape shapes] + (cond + (not (cph/frame-shape? shape)) + [:& shape-wrapper + {:shape shape + :key (:id shape)}] - [:& shape-wrapper {:shape item - :key (:id item)}]))])) + (cph/root-frame? shape) + [:& root-frame-wrapper + {:shape shape + :key (:id shape) + :objects (get frame-objects (:id shape)) + :thumbnail? (not (contains? active-frames (:id shape)))}] + + :else + [:& nested-frame-wrapper + {:shape shape + :key (:id shape) + :objects (get frame-objects (:id shape))}]))])) (mf/defc shape-wrapper {::mf/wrap [#(mf/memo' % (mf/check-props ["shape"]))] @@ -98,12 +109,13 @@ :bool [:> bool-wrapper opts] ;; Only used when drawing a new frame. - :frame [:> frame-wrapper opts] + :frame [:> nested-frame-wrapper opts] nil)))) (def group-wrapper (group/group-wrapper-factory shape-wrapper)) (def svg-raw-wrapper (svg-raw/svg-raw-wrapper-factory shape-wrapper)) (def bool-wrapper (bool/bool-wrapper-factory shape-wrapper)) -(def frame-wrapper (frame/frame-wrapper-factory shape-wrapper)) +(def root-frame-wrapper (frame/root-frame-wrapper-factory shape-wrapper)) +(def nested-frame-wrapper (frame/nested-frame-wrapper-factory shape-wrapper)) diff --git a/frontend/src/app/main/ui/workspace/shapes/frame.cljs b/frontend/src/app/main/ui/workspace/shapes/frame.cljs index 2cacfc13d9..ad769ade66 100644 --- a/frontend/src/app/main/ui/workspace/shapes/frame.cljs +++ b/frontend/src/app/main/ui/workspace/shapes/frame.cljs @@ -35,9 +35,9 @@ ::mf/forward-ref true} [props ref] - (let [shape (unchecked-get props "shape") - childs-ref (mf/use-memo (mf/deps (:id shape)) #(refs/children-objects (:id shape))) - childs (mf/deref childs-ref)] + (let [shape (unchecked-get props "shape") + childs-ref (mf/use-memo (mf/deps (:id shape)) #(refs/children-objects (:id shape))) + childs (mf/deref childs-ref)] [:& (mf/provider embed/context) {:value true} [:& shape-container {:shape shape :ref ref :disable-shadows? (cph/root-frame? shape)} @@ -49,7 +49,7 @@ (= (unchecked-get new-props "thumbnail?") (unchecked-get old-props "thumbnail?")) (= (unchecked-get new-props "shape") (unchecked-get old-props "shape")))) -(defn frame-wrapper-factory +(defn nested-frame-wrapper-factory [shape-wrapper] (let [frame-shape (frame-shape-factory shape-wrapper)] @@ -58,81 +58,92 @@ ::mf/wrap-props false} [props] - (let [shape (unchecked-get props "shape") - frame-id (:id shape) + (let [shape (unchecked-get props "shape") + frame-id (:id shape) + objects (wsh/lookup-page-objects @st/state) + node-ref (mf/use-var nil) + modifiers-ref (mf/use-memo (mf/deps frame-id) #(refs/workspace-modifiers-by-frame-id frame-id)) + modifiers (mf/deref modifiers-ref)] - ;; References to the current rendered node and the its parentn - node-ref (mf/use-var nil) + (fdm/use-dynamic-modifiers objects @node-ref modifiers) + (let [shape (unchecked-get props "shape")] + [:& frame-shape {:shape shape :ref node-ref}]))))) - objects (wsh/lookup-page-objects @st/state) +(defn root-frame-wrapper-factory + [shape-wrapper] - ;; Modifiers - modifiers-ref (mf/use-memo (mf/deps frame-id) #(refs/workspace-modifiers-by-frame-id frame-id)) - modifiers (mf/deref modifiers-ref)] + (let [frame-shape (frame-shape-factory shape-wrapper)] + (mf/fnc frame-wrapper + {::mf/wrap [#(mf/memo' % check-props)] + ::mf/wrap-props false} + [props] + + (let [shape (unchecked-get props "shape") + frame-id (:id shape) + objects (wsh/lookup-page-objects @st/state) + node-ref (mf/use-var nil) + modifiers-ref (mf/use-memo (mf/deps frame-id) #(refs/workspace-modifiers-by-frame-id frame-id)) + modifiers (mf/deref modifiers-ref)] (fdm/use-dynamic-modifiers objects @node-ref modifiers) - (if-not (cph/root-frame? shape) - [:& frame-shape {:shape shape :ref node-ref}] + (let [thumbnail? (unchecked-get props "thumbnail?") + fonts (mf/use-memo (mf/deps shape objects) #(ff/shape->fonts shape objects)) + fonts (-> fonts (hooks/use-equal-memo)) - ;; If the current shape is root we handle its thumbnail and the dynamic modifiers - (let [thumbnail? (unchecked-get props "thumbnail?") - fonts (mf/use-memo (mf/deps shape objects) #(ff/shape->fonts shape objects)) - fonts (-> fonts (hooks/use-equal-memo)) + force-render (mf/use-state false) - force-render (mf/use-state false) + ;; Thumbnail data + page-id (mf/use-ctx ctx/current-page-id) - ;; Thumbnail data - page-id (mf/use-ctx ctx/current-page-id) + ;; when `true` we've called the mount for the frame + rendered? (mf/use-var false) - ;; when `true` we've called the mount for the frame - rendered? (mf/use-var false) + disable-thumbnail? (d/not-empty? (dm/get-in modifiers [(:id shape) :modifiers])) - disable-thumbnail? (d/not-empty? (dm/get-in modifiers [(:id shape) :modifiers])) + [on-load-frame-dom render-frame? thumbnail-renderer] + (ftr/use-render-thumbnail page-id shape node-ref rendered? disable-thumbnail? @force-render) - [on-load-frame-dom render-frame? thumbnail-renderer] - (ftr/use-render-thumbnail page-id shape node-ref rendered? disable-thumbnail? @force-render) + on-frame-load + (fns/use-node-store thumbnail? node-ref rendered? render-frame?)] - on-frame-load - (fns/use-node-store thumbnail? node-ref rendered? render-frame?)] + (mf/use-effect + (mf/deps fonts) + (fn [] + (->> (rx/from fonts) + (rx/merge-map fonts/fetch-font-css) + (rx/ignore)))) - (mf/use-effect - (mf/deps fonts) - (fn [] - (->> (rx/from fonts) - (rx/merge-map fonts/fetch-font-css) - (rx/ignore)))) + (mf/use-effect + (fn [] + ;; When a change in the data is received a "force-render" event is emited + ;; that will force the component to be mounted in memory + (let [sub + (->> (dwt/force-render-stream (:id shape)) + (rx/take-while #(not @rendered?)) + (rx/subs #(reset! force-render true)))] + #(when sub + (rx/dispose! sub))))) - (mf/use-effect - (fn [] - ;; When a change in the data is received a "force-render" event is emited - ;; that will force the component to be mounted in memory - (let [sub - (->> (dwt/force-render-stream (:id shape)) - (rx/take-while #(not @rendered?)) - (rx/subs #(reset! force-render true)))] - #(when sub - (rx/dispose! sub))))) + (mf/use-effect + (mf/deps shape fonts thumbnail? on-load-frame-dom @force-render render-frame?) + (fn [] + (when (and (some? @node-ref) (or @rendered? (not thumbnail?) @force-render render-frame?)) + (mf/mount + (mf/element frame-shape + #js {:ref on-load-frame-dom :shape shape :fonts fonts}) - (mf/use-effect - (mf/deps shape fonts thumbnail? on-load-frame-dom @force-render render-frame?) - (fn [] - (when (and (some? @node-ref) (or @rendered? (not thumbnail?) @force-render render-frame?)) - (mf/mount - (mf/element frame-shape - #js {:ref on-load-frame-dom :shape shape :fonts fonts}) + @node-ref) + (when (not @rendered?) (reset! rendered? true))))) - @node-ref) - (when (not @rendered?) (reset! rendered? true))))) - - [:& shape-container {:shape shape} - [:g.frame-container {:id (dm/str "frame-container-" (:id shape)) - :key "frame-container" - :ref on-frame-load - :opacity (when (:hidden shape) 0)} - [:& ff/fontfaces-style {:fonts fonts}] - [:g.frame-thumbnail-wrapper - {:id (dm/str "thumbnail-container-" (:id shape)) - ;; Hide the thumbnail when not displaying - :opacity (when (and @rendered? (not thumbnail?) (not render-frame?)) 0)} - thumbnail-renderer]]])))))) + [:& shape-container {:shape shape} + [:g.frame-container {:id (dm/str "frame-container-" (:id shape)) + :key "frame-container" + :ref on-frame-load + :opacity (when (:hidden shape) 0)} + [:& ff/fontfaces-style {:fonts fonts}] + [:g.frame-thumbnail-wrapper + {:id (dm/str "thumbnail-container-" (:id shape)) + ;; Hide the thumbnail when not displaying + :opacity (when (and @rendered? (not thumbnail?) (not render-frame?)) 0)} + thumbnail-renderer]]]))))) diff --git a/frontend/src/app/main/ui/workspace/viewport/pixel_overlay.cljs b/frontend/src/app/main/ui/workspace/viewport/pixel_overlay.cljs index 9fda55c82b..902053304e 100644 --- a/frontend/src/app/main/ui/workspace/viewport/pixel_overlay.cljs +++ b/frontend/src/app/main/ui/workspace/viewport/pixel_overlay.cljs @@ -7,6 +7,7 @@ (ns app.main.ui.workspace.viewport.pixel-overlay (:require [app.common.data :as d] + [app.common.pages.helpers :as cph] [app.common.uuid :as uuid] [app.main.data.modal :as modal] [app.main.data.workspace.colors :as dwc] @@ -41,13 +42,24 @@ shapes (->> (:shapes root) (map (d/getf objects)))] [:g.shapes - (for [item shapes] - (if (= (:type item) :frame) - [:& shapes/frame-wrapper {:shape item - :key (:id item) - :objects objects}] - [:& shapes/shape-wrapper {:shape item - :key (:id item)}]))])) + (for [shape shapes] + (cond + (not (cph/frame-shape? shape)) + [:& shapes/shape-wrapper + {:shape shape + :key (:id shape)}] + + (cph/root-frame? shape) + [:& shapes/root-frame-wrapper + {:shape shape + :key (:id shape) + :objects objects}] + + :else + [:& shapes/nested-frame-wrapper + {:shape shape + :key (:id shape) + :objects objects}]))])) (mf/defc pixel-overlay {::mf/wrap-props false}