diff --git a/backend/src/app/features/components_v2.clj b/backend/src/app/features/components_v2.clj index c6389cd8d..ba1949550 100644 --- a/backend/src/app/features/components_v2.clj +++ b/backend/src/app/features/components_v2.clj @@ -211,22 +211,22 @@ transform-to-frames (fn [file-data] - ; Transform components and copies to frames, and set the - ; frame-id of its childrens + ; Transform component and copy heads to frames, and set the + ; frame-id of its childrens (letfn [(fix-container - [container] - (update container :objects update-vals fix-shape)) + [container] + (update container :objects update-vals fix-shape)) (fix-shape - [shape] - (if (ctk/instance-head? shape) - (assoc shape - :type :frame ; Old groups must be converted - :fills [] ; to frames and conform to spec - :hide-in-viewer true - :rx 0 - :ry 0) - shape))] + [shape] + (if (ctk/instance-head? shape) + (assoc shape + :type :frame ; Old groups must be converted + :fills [] ; to frames and conform to spec + :hide-in-viewer true + :rx 0 + :ry 0) + shape))] (-> file-data (update :pages-index update-vals fix-container) (update :components update-vals fix-container)))) @@ -236,15 +236,39 @@ ; Remap the frame-ids of the primary childs of the head instances ; to point to the head instance. (letfn [(fix-container - [container] - (update container :objects update-vals (partial fix-shape container))) + [container] + (update container :objects update-vals (partial fix-shape container))) (fix-shape - [container shape] - (let [parent (ctst/get-shape container (:parent-id shape))] - (if (ctk/instance-head? parent) - (assoc shape :frame-id (:id parent)) - shape)))] + [container shape] + (let [parent (ctst/get-shape container (:parent-id shape))] + (if (ctk/instance-head? parent) + (assoc shape :frame-id (:id parent)) + shape)))] + (-> file-data + (update :pages-index update-vals fix-container) + (update :components update-vals fix-container)))) + + fix-frame-ids + (fn [file-data] + ;; Ensure that frame-id of all shapes point to the parent or to the frame-id + ;; of the parent, and that the destination is indeed a frame. + (letfn [(fix-container [container] + (update container :objects #(cph/reduce-objects % fix-shape %))) + + (fix-shape [objects shape] + (let [parent (when (:parent-id shape) + (get objects (:parent-id shape))) + error? (when (some? parent) + (if (= (:type parent) :frame) + (not= (:frame-id shape) (:id parent)) + (not= (:frame-id shape) (:frame-id parent))))] + (if error? + (let [nearest-frame (cph/get-frame objects (:parent-id shape)) + frame-id (or (:id nearest-frame) uuid/zero)] + (update objects (:id shape) assoc :frame-id frame-id)) + objects)))] + (-> file-data (update :pages-index update-vals fix-container) (update :components update-vals fix-container))))] @@ -257,7 +281,8 @@ (remap-refs) (fix-copies-of-detached) (transform-to-frames) - (remap-frame-ids)))) + (remap-frame-ids) + (fix-frame-ids)))) (defn- migrate-components "If there is any component in the file library, add a new 'Library @@ -312,8 +337,8 @@ (fn [page shape] (let [parent (ctst/get-shape page (:parent-id shape))] (if (= :frame (:type parent)) - (:parent-id shape) - (:frame-id shape)))) + (:id parent) + (:frame-id parent)))) add-shapes (fn [page] @@ -369,7 +394,7 @@ "Convert a media object that contains a bitmap image into shapes, one shape of type :image and one group that contains it." [{:keys [name width height id mtype]} position] - (let [group-shape (cts/setup-shape + (let [frame-shape (cts/setup-shape {:type :frame :x (:x position) :y (:y position) @@ -390,9 +415,9 @@ :height height :mtype mtype} :name name - :frame-id uuid/zero - :parent-id (:id group-shape)})] - [group-shape [img-shape]])) + :frame-id (:id frame-shape) + :parent-id (:id frame-shape)})] + [frame-shape [img-shape]])) (defn- parse-datauri [data] @@ -549,7 +574,8 @@ cfsh/prepare-create-artboard-from-selection) changes (pcb/concat-changes changes changes2)] - (cp/process-changes fdata (:redo-changes changes) false))) + (cp/process-changes (assoc-in fdata [:options :components-v2] true) ; Process component creation in v2 way + (:redo-changes changes) false))) (defn- migrate-graphics [fdata] diff --git a/common/src/app/common/files/libraries_helpers.cljc b/common/src/app/common/files/libraries_helpers.cljc index bdac7d903..8aabda87a 100644 --- a/common/src/app/common/files/libraries_helpers.cljc +++ b/common/src/app/common/files/libraries_helpers.cljc @@ -20,14 +20,7 @@ [root-shape new-shapes updated-shapes] (if-not components-v2 (ctn/make-component-shape root objects file-id components-v2) - (let [new-id (uuid/next)] - [(assoc root :id new-id) - nil - [(assoc root - :component-id new-id - :component-file file-id - :component-root true - :main-instance true)]])) + (ctn/convert-shape-in-component root objects file-id)) changes (-> changes (pcb/add-component (:id root-shape) @@ -39,12 +32,10 @@ page-id))] [root-shape changes])) - (defn generate-add-component - "If there is exactly one id, and it's a frame (or a group in v1), and not already a - component, use it as root. Otherwise, create a frame (v2) or group (v1) that contains - all ids. Then, make a component with it, and link all shapes to their corresponding one - in the component." + "If there is exactly one id, and it's a frame (or a group in v1), and not already a component, + use it as root. Otherwise, create a frame (v2) or group (v1) that contains all ids. Then, make a + component with it, and link all shapes to their corresponding one in the component." [it shapes objects page-id file-id components-v2 prepare-create-group prepare-create-board] (let [changes (pcb/empty-changes it page-id) @@ -81,7 +72,9 @@ [root changes (map :id shapes)])) - [root-shape changes] (generate-add-component-changes changes root objects file-id page-id components-v2) + objects' (assoc objects (:id root) root) + + [root-shape changes] (generate-add-component-changes changes root objects' file-id page-id components-v2) changes (pcb/update-shapes changes old-root-ids diff --git a/common/src/app/common/files/shapes_helpers.cljc b/common/src/app/common/files/shapes_helpers.cljc index 6b4bf2e5e..2b6de6b25 100644 --- a/common/src/app/common/files/shapes_helpers.cljc +++ b/common/src/app/common/files/shapes_helpers.cljc @@ -86,7 +86,8 @@ :always (assoc :frame-id frame-id - :parent-id parent-id) + :parent-id parent-id + :shapes (into [] selected)) :always (with-meta {:index new-index}) diff --git a/frontend/src/app/main/data/workspace.cljs b/frontend/src/app/main/data/workspace.cljs index da98bad08..cf26ed78e 100644 --- a/frontend/src/app/main/data/workspace.cljs +++ b/frontend/src/app/main/data/workspace.cljs @@ -1604,6 +1604,7 @@ (watch [_ _ _] (try (let [clipboard-str (wapi/read-from-clipboard) + paste-transit-str (->> clipboard-str (rx/filter t/transit?) diff --git a/frontend/src/app/main/data/workspace/libraries.cljs b/frontend/src/app/main/data/workspace/libraries.cljs index a7c56a38b..05f4d3698 100644 --- a/frontend/src/app/main/data/workspace/libraries.cljs +++ b/frontend/src/app/main/data/workspace/libraries.cljs @@ -405,28 +405,29 @@ (ptk/reify ::duplicate-component ptk/WatchEvent (watch [it state _] - (let [libraries (wsh/get-libraries state) - library (get libraries library-id) - component (ctkl/get-component (:data library) component-id) - new-name (:name component) + (let [libraries (wsh/get-libraries state) + library (get libraries library-id) + component (ctkl/get-component (:data library) component-id) + new-name (:name component) - components-v2 (features/active-feature? state "components/v2") + components-v2 (features/active-feature? state "components/v2") - main-instance-page (when components-v2 - (ctf/get-component-page (:data library) component)) + main-instance-page (when components-v2 + (ctf/get-component-page (:data library) component)) - new-component (assoc component :id (uuid/next)) + new-component-id (when components-v2 + (uuid/next)) [new-component-shape new-component-shapes ; <- null in components-v2 new-main-instance-shape new-main-instance-shapes] - (dwlh/duplicate-component new-component (:data library)) + (dwlh/duplicate-component component new-component-id (:data library)) changes (-> (pcb/empty-changes it nil) (pcb/with-page main-instance-page) (pcb/with-objects (:objects main-instance-page)) (pcb/add-objects new-main-instance-shapes {:ignore-touched true}) (pcb/add-component (if components-v2 - (:id new-component) + new-component-id (:id new-component-shape)) (:path component) new-name diff --git a/frontend/src/app/main/data/workspace/libraries_helpers.cljs b/frontend/src/app/main/data/workspace/libraries_helpers.cljs index ffa0a1240..e7fe477ce 100644 --- a/frontend/src/app/main/data/workspace/libraries_helpers.cljs +++ b/frontend/src/app/main/data/workspace/libraries_helpers.cljs @@ -65,26 +65,43 @@ (defn duplicate-component "Clone the root shape of the component and all children. Generate new ids from all of them." - [component library-data] + [component new-component-id library-data] (let [components-v2 (dm/get-in library-data [:options :components-v2])] (if components-v2 (let [main-instance-page (ctf/get-component-page library-data component) main-instance-shape (ctf/get-component-root library-data component) - position (gpt/point (+ (:x main-instance-shape) - (:width main-instance-shape) - 50) - (:y main-instance-shape)) - options (if components-v2 {:main-instance? true} {}) + delta (gpt/point (+ (:width main-instance-shape) 50) 0) - [new-instance-shape new-instance-shapes] - (when (and (some? main-instance-page) (some? main-instance-shape)) - (ctn/make-component-instance main-instance-page - component - library-data - position - true - options))] + ids-map (volatile! {}) + + update-original-shape + (fn [original-shape new-shape] + (vswap! ids-map assoc (:id original-shape) (:id new-shape)) + original-shape) + + update-new-shape + (fn [shape] + (cond-> shape + (= (:component-id shape) (:id component)) + (assoc :component-id new-component-id) + + :always + (gsh/move delta))) + + [new-instance-shape new-instance-shapes _] + (ctst/clone-object main-instance-shape + (:parent-id main-instance-shape) + (:objects main-instance-page) + update-new-shape + update-original-shape) + + remap-frame + (fn [shape] + (update shape :frame-id + #(get @ids-map % (:frame-id shape)))) + + new-instance-shapes (map remap-frame new-instance-shapes)] [nil nil new-instance-shape new-instance-shapes])