diff --git a/common/deps.edn b/common/deps.edn index b267ccefcf..370e6d2d9c 100644 --- a/common/deps.edn +++ b/common/deps.edn @@ -22,7 +22,7 @@ java-http-clj/java-http-clj {:mvn/version "0.4.3"} funcool/promesa {:mvn/version "8.0.450"} - funcool/cuerdas {:mvn/version "2022.06.13-401"} + funcool/cuerdas {:mvn/version "2022.06.16-403"} lambdaisland/uri {:mvn/version "1.13.95" :exclusions [org.clojure/data.json]} diff --git a/common/src/app/common/file_builder.cljc b/common/src/app/common/file_builder.cljc index 06dd1975cd..787e17c74d 100644 --- a/common/src/app/common/file_builder.cljc +++ b/common/src/app/common/file_builder.cljc @@ -223,7 +223,7 @@ (defn close-artboard [file] (assert (nil? (:current-component-id file))) - (let [parent-id (peek (get file :parent-stack)) + (let [parent-id (-> file :parent-id peek) parent (lookup-shape file parent-id) current-frame-id (or (:frame-id parent) root-frame)] (-> file diff --git a/common/src/app/common/pages/helpers.cljc b/common/src/app/common/pages/helpers.cljc index fcbd882bbb..a3f48bf16a 100644 --- a/common/src/app/common/pages/helpers.cljc +++ b/common/src/app/common/pages/helpers.cljc @@ -223,8 +223,14 @@ (loop [parents-a (rest parents-a) parents-b (rest parents-b) base uuid/zero] - (if (not= (first parents-a) (first parents-b)) + (cond + (not= (first parents-a) (first parents-b)) [base (first parents-a) (first parents-b)] + + (or (empty? parents-a) (empty? parents-b)) + [uuid/zero (first parents-a) (first parents-b)] + + :else (recur (rest parents-a) (rest parents-b) (first parents-a)))) index-base-a (when base-child-a (get-position-on-parent objects base-child-a)) diff --git a/frontend/src/app/main/data/workspace.cljs b/frontend/src/app/main/data/workspace.cljs index 5bbd56046e..c8ac153de1 100644 --- a/frontend/src/app/main/data/workspace.cljs +++ b/frontend/src/app/main/data/workspace.cljs @@ -1214,12 +1214,6 @@ ;; selected and its parents objects (cph/selected-subtree objects selected) - ;;z-index (cp/calculate-z-index objects) - ;;z-values (->> selected - ;; (map #(vector % - ;; (+ (get z-index %) - ;; (get z-index (get-in objects [% :frame-id])))))) - selected (->> (cph/sort-z-index objects selected) (into (d/ordered-set)))] diff --git a/frontend/src/app/main/ui/shapes/frame.cljs b/frontend/src/app/main/ui/shapes/frame.cljs index 8fb3772df5..1aa7a7b5b7 100644 --- a/frontend/src/app/main/ui/shapes/frame.cljs +++ b/frontend/src/app/main/ui/shapes/frame.cljs @@ -42,86 +42,81 @@ [:> :path props] [:> :rect props])]))) +;; Wrapper around the frame that will handle things such as strokes and other properties +;; we wrap the proper frames and also the thumbnails +(mf/defc frame-container + {::mf/wrap-props false} + [props] + + (let [shape (obj/get props "shape") + children (obj/get props "children") + + {:keys [x y width height show-content]} shape + transform (gsh/transform-str shape) + props (-> (attrs/extract-style-attrs shape) + (obj/merge! + #js {:x x + :y y + :transform transform + :width width + :height height + :className "frame-background"})) + path? (some? (.-d props)) + render-id (mf/use-ctx muc/render-ctx)] + + [:* + [:g {:clip-path (when (not show-content) (frame-clip-url shape render-id))} + (when (not show-content) + [:& frame-clip-def {:shape shape :render-id render-id}]) + + [:& shape-fills {:shape shape} + (if path? + [:> :path props] + [:> :rect props])] + + children] + + [:& shape-strokes {:shape shape} + (if path? + [:> :path props] + [:> :rect props])]])) + + +(mf/defc frame-thumbnail-image + {::mf/wrap-props false} + [props] + + (let [shape (obj/get props "shape") + bounds (or (obj/get props "bounds") (gsh/points->selrect (:points shape)))] + + (when (:thumbnail shape) + [:image.frame-thumbnail + {:id (dm/str "thumbnail-" (:id shape)) + :href (:thumbnail shape) + :x (:x bounds) + :y (:y bounds) + :width (:width bounds) + :height (:height bounds) + ;; DEBUG + :style {:filter (when (debug? :thumbnails) "sepia(1)")}}]))) + (mf/defc frame-thumbnail {::mf/wrap-props false} [props] - (let [shape (obj/get props "shape") - bounds (or (obj/get props "bounds") (:selrect shape))] + (let [shape (obj/get props "shape")] (when (:thumbnail shape) - (let [{:keys [x y width height show-content]} shape - transform (gsh/transform-str shape) - props (-> (attrs/extract-style-attrs shape) - (obj/merge! - #js {:x x - :y y - :transform transform - :width width - :height height - :className "frame-background"})) - path? (some? (.-d props)) - render-id (mf/use-ctx muc/render-ctx)] - - [:* - [:g {:clip-path (when (not show-content) (frame-clip-url shape render-id))} - (when (not show-content) - [:& frame-clip-def {:shape shape :render-id render-id}]) - [:& shape-fills {:shape shape} - (if path? - [:> :path props] - [:> :rect props])] - - [:image.frame-thumbnail - {:id (dm/str "thumbnail-" (:id shape)) - :href (:thumbnail shape) - :x (:x bounds) - :y (:y bounds) - :width (:width bounds) - :height (:height bounds) - ;; DEBUG - :style {:filter (when (debug? :thumbnails) "sepia(1)")}}]] - - [:& shape-strokes {:shape shape} - (if path? - [:> :path props] - [:> :rect props])]])))) + [:> frame-container props + [:> frame-thumbnail-image props]]))) (defn frame-shape [shape-wrapper] (mf/fnc frame-shape {::mf/wrap-props false} [props] - (let [childs (unchecked-get props "childs") - shape (unchecked-get props "shape") - {:keys [x y width height show-content]} shape - transform (gsh/transform-str shape) - - props (-> (attrs/extract-style-attrs shape) - (obj/merge! - #js {:x x - :y y - :transform transform - :width width - :height height - :className "frame-background"})) - path? (some? (.-d props)) - render-id (mf/use-ctx muc/render-ctx)] - - [:* - [:g {:clip-path (when (not show-content) - (frame-clip-url shape render-id))} - [:& shape-fills {:shape shape} - (if path? - [:> :path props] - [:> :rect props])] - - [:g.frame-children - (for [item childs] - [:& shape-wrapper {:shape item - :key (dm/str (:id item))}])]] - - [:& shape-strokes {:shape shape} - (if path? - [:> :path props] - [:> :rect props])]]))) + (let [childs (unchecked-get props "childs")] + [:> frame-container props + [:g.frame-children + (for [item childs] + [:& shape-wrapper {:key (dm/str (:id item)) :shape item}])]]))) diff --git a/frontend/src/app/main/ui/workspace/shapes.cljs b/frontend/src/app/main/ui/workspace/shapes.cljs index 166aba242a..293492c83e 100644 --- a/frontend/src/app/main/ui/workspace/shapes.cljs +++ b/frontend/src/app/main/ui/workspace/shapes.cljs @@ -87,21 +87,20 @@ opts #js {:shape shape :thumbnail? thumbnail?}] (when (and (some? shape) (not (:hidden shape))) - [:* - (case (:type shape) - :path [:> path/path-wrapper opts] - :text [:> text/text-wrapper opts] - :group [:> group-wrapper opts] - :rect [:> rect-wrapper opts] - :image [:> image-wrapper opts] - :circle [:> circle-wrapper opts] - :svg-raw [:> svg-raw-wrapper opts] - :bool [:> bool-wrapper opts] + (case (:type shape) + :path [:> path/path-wrapper opts] + :text [:> text/text-wrapper opts] + :group [:> group-wrapper opts] + :rect [:> rect-wrapper opts] + :image [:> image-wrapper opts] + :circle [:> circle-wrapper opts] + :svg-raw [:> svg-raw-wrapper opts] + :bool [:> bool-wrapper opts] - ;; Only used when drawing a new frame. - :frame [:> frame-wrapper opts] + ;; Only used when drawing a new frame. + :frame [:> frame-wrapper opts] - nil)]))) + nil)))) (def group-wrapper (group/group-wrapper-factory shape-wrapper)) (def svg-raw-wrapper (svg-raw/svg-raw-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 deb213d491..3e33494ac7 100644 --- a/frontend/src/app/main/ui/workspace/shapes/frame.cljs +++ b/frontend/src/app/main/ui/workspace/shapes/frame.cljs @@ -9,7 +9,6 @@ [app.common.data :as d] [app.common.data.macros :as dm] [app.common.pages.helpers :as cph] - [app.common.uuid :as uuid] [app.main.data.workspace.state-helpers :as wsh] [app.main.data.workspace.thumbnails :as dwt] [app.main.fonts :as fonts] @@ -78,8 +77,6 @@ ;; If the current shape is root we handle its thumbnail and the dynamic modifiers (let [thumbnail? (unchecked-get props "thumbnail?") - - render-id (mf/use-memo #(str (uuid/next))) fonts (mf/use-memo (mf/deps shape objects) #(ff/shape->fonts shape objects)) fonts (-> fonts (hooks/use-equal-memo)) @@ -96,7 +93,7 @@ [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 in-memory?] + on-frame-load (fns/use-node-store thumbnail? node-ref rendered? render-frame?)] (mf/use-effect @@ -128,7 +125,7 @@ @node-ref) (when (not @rendered?) (reset! rendered? true))))) - [:& (mf/provider ctx/render-ctx) {:value render-id} + [:* [:g.frame-container {:id (dm/str "frame-container-" (:id shape)) :key "frame-container" :ref on-frame-load @@ -137,5 +134,6 @@ [: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?) (not in-memory?)) 0)} - thumbnail-renderer]]])))))) + :opacity (when (and @rendered? (not thumbnail?) (not render-frame?)) 0)} + [:& shape-container {:shape shape} + thumbnail-renderer]]]])))))) diff --git a/frontend/src/app/main/ui/workspace/shapes/frame/dynamic_modifiers.cljs b/frontend/src/app/main/ui/workspace/shapes/frame/dynamic_modifiers.cljs index 0ce9b0a6a2..dc46bf2412 100644 --- a/frontend/src/app/main/ui/workspace/shapes/frame/dynamic_modifiers.cljs +++ b/frontend/src/app/main/ui/workspace/shapes/frame/dynamic_modifiers.cljs @@ -78,40 +78,41 @@ (defn get-nodes "Retrieve the DOM nodes to apply the matrix transformation" [base-node {:keys [id type masked-group?] :as shape}] - (let [shape-node (if (= (.-id base-node) (dm/str "shape-" id)) - base-node - (dom/query base-node (dm/str "#shape-" id))) + (when (some? base-node) + (let [shape-node (if (= (.-id base-node) (dm/str "shape-" id)) + base-node + (dom/query base-node (dm/str "#shape-" id))) - frame? (= :frame type) - group? (= :group type) - text? (= :text type) - mask? (and group? masked-group?)] - (cond - frame? - [shape-node - (dom/query shape-node ".frame-children") - (dom/query (dm/str "#thumbnail-container-" id)) - (dom/query (dm/str "#thumbnail-" id)) - (dom/query (dm/str "#frame-title-" id))] + frame? (= :frame type) + group? (= :group type) + text? (= :text type) + mask? (and group? masked-group?)] + (cond + frame? + [shape-node + (dom/query shape-node ".frame-children") + (dom/query (dm/str "#thumbnail-container-" id)) + (dom/query (dm/str "#thumbnail-" id)) + (dom/query (dm/str "#frame-title-" id))] - ;; For groups we don't want to transform the whole group but only - ;; its filters/masks - mask? - [(dom/query shape-node ".mask-clip-path") - (dom/query shape-node ".mask-shape")] + ;; For groups we don't want to transform the whole group but only + ;; its filters/masks + mask? + [(dom/query shape-node ".mask-clip-path") + (dom/query shape-node ".mask-shape")] - group? - (let [shape-defs (dom/query shape-node "defs")] - (d/concat-vec - (dom/query-all shape-defs ".svg-def") - (dom/query-all shape-defs ".svg-mask-wrapper"))) + group? + (let [shape-defs (dom/query shape-node "defs")] + (d/concat-vec + (dom/query-all shape-defs ".svg-def") + (dom/query-all shape-defs ".svg-mask-wrapper"))) - text? - [shape-node - (dom/query shape-node ".text-container")] + text? + [shape-node + (dom/query shape-node ".text-container")] - :else - [shape-node]))) + :else + [shape-node])))) (defn transform-region! [node modifiers] diff --git a/frontend/src/app/main/ui/workspace/shapes/frame/node_store.cljs b/frontend/src/app/main/ui/workspace/shapes/frame/node_store.cljs index 832795711d..8eef40f24a 100644 --- a/frontend/src/app/main/ui/workspace/shapes/frame/node_store.cljs +++ b/frontend/src/app/main/ui/workspace/shapes/frame/node_store.cljs @@ -15,7 +15,7 @@ [thumbnail? node-ref rendered? render-frame?] (let [;; when `true` the node is in memory - in-memory? (mf/use-var true) + in-memory? (mf/use-state true) ;; State just for re-rendering re-render (mf/use-state 0) @@ -32,7 +32,7 @@ (reset! parent-ref node) (swap! re-render inc)))))] - (mf/use-effect + (mf/use-layout-effect (mf/deps thumbnail? render-frame?) (fn [] (when (and (some? @parent-ref) (some? @node-ref) @rendered? (and thumbnail? (not render-frame?))) @@ -43,4 +43,4 @@ (.appendChild @parent-ref @node-ref) (reset! in-memory? false)))) - [on-frame-load @in-memory?])) + on-frame-load)) diff --git a/frontend/src/app/main/ui/workspace/shapes/frame/thumbnail_render.cljs b/frontend/src/app/main/ui/workspace/shapes/frame/thumbnail_render.cljs index 44b5c27366..0358603438 100644 --- a/frontend/src/app/main/ui/workspace/shapes/frame/thumbnail_render.cljs +++ b/frontend/src/app/main/ui/workspace/shapes/frame/thumbnail_render.cljs @@ -214,13 +214,19 @@ [on-load-frame-dom @render-frame? (mf/html - [:* + [:& frame/frame-container {:bounds shape-bb + :shape (cond-> shape + (some? thumbnail-data) + (assoc :thumbnail thumbnail-data))} + (when @show-frame-thumbnail - [:> frame/frame-thumbnail {:key (dm/str (:id shape)) - :bounds shape-bb - :shape (cond-> shape - (some? thumbnail-data) - (assoc :thumbnail thumbnail-data))}]) + [:> frame/frame-thumbnail-image + {:key (dm/str (:id shape)) + :bounds shape-bb + :shape (cond-> shape + (some? thumbnail-data) + (assoc :thumbnail thumbnail-data))}]) + [:foreignObject {:x x :y y :width width :height height} [:canvas.thumbnail-canvas