diff --git a/common/src/app/common/types/component.cljc b/common/src/app/common/types/component.cljc index 8491462b3..7c48e7f30 100644 --- a/common/src/app/common/types/component.cljc +++ b/common/src/app/common/types/component.cljc @@ -197,6 +197,12 @@ (or (= slot-main slot-inst) (= (:id shape-main) slot-inst))))) +(defn remove-swap-slot + [shape] + (update shape :touched + (fn [touched] + (into #{} (remove #(str/starts-with? (name %) "swap-slot-") touched))))) + (defn get-component-root [component] (if (true? (:main-instance-id component)) diff --git a/common/src/app/common/types/container.cljc b/common/src/app/common/types/container.cljc index 2034ab58c..d71390508 100644 --- a/common/src/app/common/types/container.cljc +++ b/common/src/app/common/types/container.cljc @@ -211,20 +211,33 @@ :else (get-instance-root objects (get objects (:parent-id shape))))) +(defn find-component-main + "If the shape is a component main instance or is inside one, return that instance" + ([objects shape] + (find-component-main objects shape true)) + ([objects shape only-direct-child?] + (cond + (or (nil? shape) (cfh/root? shape)) + nil + (nil? (:parent-id shape)) ; This occurs in the root of components v1 + shape + (ctk/main-instance? shape) + shape + (and only-direct-child? ;; If we are asking only for direct childs of a component-main, + (ctk/instance-head? shape)) ;; stop when we found a instance-head that isn't main-instance + nil + (and (not only-direct-child?) + (ctk/instance-root? shape)) + nil + :else + (find-component-main objects (get objects (:parent-id shape)))))) + (defn inside-component-main? "Check if the shape is a component main instance or is inside one." - [objects shape] - (cond - (or (nil? shape) (cfh/root? shape)) - false - (nil? (:parent-id shape)) ; This occurs in the root of components v1 - true - (ctk/main-instance? shape) - true - (ctk/instance-head? shape) - false - :else - (inside-component-main? objects (get objects (:parent-id shape))))) + ([objects shape] + (inside-component-main? objects shape true)) + ([objects shape only-direct-child?] + (some? (find-component-main objects shape only-direct-child?)))) (defn in-any-component? "Check if the shape is part of any component (main or copy), wether it's diff --git a/frontend/src/app/main/data/workspace.cljs b/frontend/src/app/main/data/workspace.cljs index 044d133f9..1dddf3f99 100644 --- a/frontend/src/app/main/data/workspace.cljs +++ b/frontend/src/app/main/data/workspace.cljs @@ -789,9 +789,14 @@ (defn relocate-shapes-changes [it objects parents parent-id page-id to-index ids groups-to-delete groups-to-unmask shapes-to-detach shapes-to-reroot shapes-to-deroot shapes-to-unconstraint] - (let [ordered-indexes (cfh/order-by-indexed-shapes objects ids) - shapes (map (d/getf objects) ordered-indexes) - parent (get objects parent-id)] + (let [ordered-indexes (cfh/order-by-indexed-shapes objects ids) + shapes (map (d/getf objects) ordered-indexes) + parent (get objects parent-id) + component-main-parent (ctn/find-component-main objects parent false) + child-heads + (->> ordered-indexes + (mapcat #(ctn/get-child-heads objects %)) + (map :id))] (-> (pcb/empty-changes it page-id) (pcb/with-objects objects) @@ -804,6 +809,17 @@ (cond-> (and (not= uuid/zero parent-id) (cfh/frame-shape? parent)) (pcb/update-shapes ordered-indexes #(cond-> % (cfh/frame-shape? %) (assoc :hide-in-viewer true)))) + ;; Remove the swap slots if it is moving to a different component + (pcb/update-shapes child-heads + (fn [shape] + (cond-> shape + (not= component-main-parent (ctn/find-component-main objects shape false)) + (ctk/remove-swap-slot)))) + + ;; Add component-root property when moving a component outside a component + (cond-> (not (ctn/get-instance-root objects parent)) + (pcb/update-shapes child-heads #(assoc % :component-root true))) + ;; Move the shapes (pcb/change-parent parent-id shapes diff --git a/frontend/src/app/main/data/workspace/libraries.cljs b/frontend/src/app/main/data/workspace/libraries.cljs index 6f08743c9..e055ea16e 100644 --- a/frontend/src/app/main/data/workspace/libraries.cljs +++ b/frontend/src/app/main/data/workspace/libraries.cljs @@ -937,12 +937,14 @@ (ptk/reify ::add-component-for-swap ptk/WatchEvent (watch [it _ _] - (let [objects (:objects page) - position (gpt/point (:x shape) (:y shape)) - changes (-> (pcb/empty-changes it (:id page)) - (pcb/set-undo-group undo-group) - (pcb/with-objects objects)) - position (-> position (with-meta {:cell target-cell})) + (let [objects (:objects page) + position (gpt/point (:x shape) (:y shape)) + changes (-> (pcb/empty-changes it (:id page)) + (pcb/set-undo-group undo-group) + (pcb/with-objects objects)) + position (-> position (with-meta {:cell target-cell})) + parent (get objects (:parent-id shape)) + inside-comp? (ctn/in-any-component? objects parent) [new-shape changes] (dwlh/generate-instantiate-component changes @@ -958,7 +960,9 @@ {:force-frame? true}) new-shape (cond-> new-shape - (nil? (ctk/get-swap-slot new-shape)) + ; if the shape isn't inside a main component, it shouldn't have a swap slot + (and (nil? (ctk/get-swap-slot new-shape)) + inside-comp?) (update :touched cfh/set-touched-group (-> (ctf/find-swap-slot shape page {:id (:id file) diff --git a/frontend/src/app/main/data/workspace/selection.cljs b/frontend/src/app/main/data/workspace/selection.cljs index d260c5e0b..acb0d2175 100644 --- a/frontend/src/app/main/data/workspace/selection.cljs +++ b/frontend/src/app/main/data/workspace/selection.cljs @@ -460,9 +460,9 @@ ;; TODO: move to common.files.shape-helpers (defn- prepare-duplicate-shape-change ([changes objects page unames update-unames! ids-map obj delta level-delta libraries library-data it file-id] - (prepare-duplicate-shape-change changes objects page unames update-unames! ids-map obj delta level-delta libraries library-data it file-id (:frame-id obj) (:parent-id obj) false false)) + (prepare-duplicate-shape-change changes objects page unames update-unames! ids-map obj delta level-delta libraries library-data it file-id (:frame-id obj) (:parent-id obj) false false true)) - ([changes objects page unames update-unames! ids-map obj delta level-delta libraries library-data it file-id frame-id parent-id duplicating-component? child?] + ([changes objects page unames update-unames! ids-map obj delta level-delta libraries library-data it file-id frame-id parent-id duplicating-component? child? remove-swap-slot?] (cond (nil? obj) changes @@ -485,6 +485,7 @@ (ctk/instance-root? obj)) duplicating-component? (or duplicating-component? (ctk/instance-head? obj)) is-component-main? (ctk/main-instance? obj) + subinstance-head? (ctk/subinstance-head? obj) into-component? (and duplicating-component? (ctn/in-any-component? objects parent)) @@ -507,6 +508,9 @@ :parent-id parent-id :frame-id frame-id) + (cond-> (and subinstance-head? remove-swap-slot?) + (ctk/remove-swap-slot)) + (dissoc :shapes :main-instance :use-for-thumbnail) @@ -572,7 +576,11 @@ (if frame? new-id frame-id) new-id duplicating-component? - true)) + true + (and remove-swap-slot? + ;; only remove swap slot of children when the current shape + ;; is not a subinstance head + (not subinstance-head?)))) changes (map (d/getf objects) (:shapes obj))))))) diff --git a/frontend/src/app/main/data/workspace/transforms.cljs b/frontend/src/app/main/data/workspace/transforms.cljs index a69805cdc..e96f8ba72 100644 --- a/frontend/src/app/main/data/workspace/transforms.cljs +++ b/frontend/src/app/main/data/workspace/transforms.cljs @@ -842,6 +842,8 @@ frame (get objects frame-id) layout? (:layout frame) + component-main-frame (ctn/find-component-main objects frame false) + shapes (->> ids (cfh/clean-loops objects) (keep lookup)) moving-shapes @@ -906,9 +908,8 @@ (map :id moving-shapes) moving-shapes-children-ids - (->> moving-shapes - (mapcat #(cfh/get-children-with-self objects (:id %))) - (map :id)) + (->> moving-shapes-ids + (mapcat #(cfh/get-children-ids-with-self objects %))) child-heads (->> moving-shapes-ids @@ -921,6 +922,12 @@ ;; Remove layout-item properties when moving a shape outside a layout (cond-> (not (ctl/any-layout? objects frame-id)) (pcb/update-shapes moving-shapes-ids ctl/remove-layout-item-data)) + ;; Remove the swap slots if it is moving to a different component + (pcb/update-shapes child-heads + (fn [shape] + (cond-> shape + (not= component-main-frame (ctn/find-component-main objects shape false)) + (ctk/remove-swap-slot)))) ;; Remove component-root property when moving a shape inside a component (cond-> (ctn/get-instance-root objects frame) (pcb/update-shapes moving-shapes-children-ids #(dissoc % :component-root)))