diff --git a/common/src/app/common/logic/libraries.cljc b/common/src/app/common/logic/libraries.cljc index fee7e718c2..acfbe6c2d1 100644 --- a/common/src/app/common/logic/libraries.cljc +++ b/common/src/app/common/logic/libraries.cljc @@ -3165,6 +3165,7 @@ is-component-main? (ctk/main-instance? obj) subinstance-head? (ctk/subinstance-head? obj) instance-root? (ctk/instance-root? obj) + parent-not-in-copy (not (ctk/in-component-copy? parent)) into-component? (and duplicating-component? (ctn/in-any-component? objects parent)) @@ -3174,6 +3175,8 @@ (ctn/get-nesting-level-delta objects obj parent)) new-shape-ref (ctf/advance-shape-ref nil page libraries obj level-delta {:include-deleted? true}) + + regenerate-component (fn [changes shape] (let [[_ changes] (generate-add-component-changes changes shape objects file-id (:id page) variant-props)] @@ -3188,7 +3191,8 @@ (cond-> (and (not instance-root?) subinstance-head? - remove-swap-slot?) + remove-swap-slot? + parent-not-in-copy) (ctk/remove-swap-slot)) (dissoc :shapes diff --git a/common/src/app/common/types/container.cljc b/common/src/app/common/types/container.cljc index 849467d7f4..7c61356cbc 100644 --- a/common/src/app/common/types/container.cljc +++ b/common/src/app/common/types/container.cljc @@ -196,7 +196,7 @@ ;; Calculate how many parent heads share in common the original ;; shape and the new parent. pairs (map vector orig-heads dest-heads) - common-count (count (take-while (fn [a b] (= a b)) pairs))] + common-count (count (take-while (fn [[a b]] (= a b)) pairs))] (- (count orig-heads) common-count))) diff --git a/common/test/common_tests/logic/comp_remove_swap_slots_test.cljc b/common/test/common_tests/logic/comp_remove_swap_slots_test.cljc index da766cd71d..bf62f42c72 100644 --- a/common/test/common_tests/logic/comp_remove_swap_slots_test.cljc +++ b/common/test/common_tests/logic/comp_remove_swap_slots_test.cljc @@ -567,3 +567,62 @@ ;; blue2' has not swap-id after move (t/is (some? blue2')) (t/is (nil? (ctk/get-swap-slot blue2'))))) + +(defn- setup-nested-swap-file + [] + ;; {:frame-icon-a} [:name Frame1] # [Component :icon-a] + ;; {:frame-icon-b} [:name Frame1] # [Component :icon-b] + ;; {:frame-card} [:name Frame1] # [Component :card] + ;; :frame-inner [:name Frame1] + ;; :icon-copy [:name Frame1] @--> :frame-icon-a + ;; :card-copy [:name Frame1] @--> :frame-card + ;; :inner-copy [:name Frame1] @--> :frame-inner + ;; :icon-in-card-copy [:name Frame1] @--> :frame-icon-a + ;; swapped to :icon-b, it becomes + ;; :icon-b-copy [:name Frame1, swap-slot] @--> :frame-icon-b + (-> (thf/sample-file :file1) + (tho/add-frame :frame-icon-a) + (thc/make-component :icon-a :frame-icon-a) + (tho/add-frame :frame-icon-b) + (thc/make-component :icon-b :frame-icon-b) + (tho/add-frame :frame-card) + (thc/make-component :card :frame-card) + (tho/add-frame :frame-inner :parent-label :frame-card) + (thc/instantiate-component :icon-a :icon-copy :parent-label :frame-inner) + (thc/instantiate-component :card :card-copy + :children-labels [:inner-copy :icon-in-card-copy]) + (thc/component-swap :icon-in-card-copy :icon-b :icon-b-copy))) + +(t/deftest test-keep-swap-slot-duplicating-swapped-nested-copy-inside-copy + (let [;; ==== Setup + file (setup-nested-swap-file) + + page (thf/current-page file) + icon-b-copy (ths/get-shape file :icon-b-copy) + + ;; ==== Action + changes (-> (pcb/empty-changes nil) + (cll/generate-duplicate-changes (:objects page) ;; objects + page ;; page + #{(:id icon-b-copy)} ;; ids + (gpt/point 0 0) ;; delta + {(:id file) file} ;; libraries + (:data file) ;; library-data + (:id file)) ;; file-id + (cll/generate-duplicate-changes-update-indices (:objects page) ;; objects + #{(:id icon-b-copy)})) ;; ids + + file' (thf/apply-changes file changes) + + ;; ==== Get + page' (thf/current-page file') + duplicated-icon-b' (find-duplicated-shape icon-b-copy page')] + + ;; ==== Check + + ;; icon-b-copy has swap-slot + (t/is (some? (ctk/get-swap-slot icon-b-copy))) + + ;; duplicated icon-b copy keeps its swap-slot + (t/is (some? duplicated-icon-b')) + (t/is (some? (ctk/get-swap-slot duplicated-icon-b'))))) diff --git a/common/test/common_tests/types/container_test.cljc b/common/test/common_tests/types/container_test.cljc index 9f7a308c8a..f545705d42 100644 --- a/common/test/common_tests/types/container_test.cljc +++ b/common/test/common_tests/types/container_test.cljc @@ -291,3 +291,42 @@ (t/testing "two ordinary outside shapes are both kept" (t/is (= [outside-id outside-2-id] (vec (ctc/ids-for-structure-op objects [outside-id outside-2-id]))))))) + +(t/deftest get-nesting-level-delta + (let [page-id uuid/zero + head-id (uuid/next) + frame-id (uuid/next) + sub-id (uuid/next) + head-2-id (uuid/next) + plain-id (uuid/next) + ;; copy head with a plain frame and a nested copy head inside + head (make-shape head-id + :parent-id page-id + :type :frame + :component-id (uuid/next) + :component-root true + :shape-ref (uuid/next)) + frame (make-shape frame-id :parent-id head-id :type :frame :shape-ref (uuid/next)) + sub (make-shape sub-id + :parent-id frame-id + :type :frame + :component-id (uuid/next) + :shape-ref (uuid/next)) + head-2 (make-shape head-2-id + :parent-id page-id + :type :frame + :component-id (uuid/next) + :component-root true + :shape-ref (uuid/next)) + plain (make-shape plain-id :parent-id page-id) + root (root-shape) + objects (objects-map root head frame sub head-2 plain)] + (t/testing "shape stays under the same copy head" + (t/is (= 0 (ctc/get-nesting-level-delta objects sub frame)))) + (t/testing "shape leaves its copy head to the page" + (t/is (= 1 (ctc/get-nesting-level-delta objects sub root)))) + (t/testing "shape moves to a different copy head" + (t/is (= 1 (ctc/get-nesting-level-delta objects sub head-2)))) + (t/testing "shape outside any copy head goes inside one" + (t/is (= 0 (ctc/get-nesting-level-delta objects plain frame)))))) +