From d270c9670e83caabda7a9e34b75a4502b30abacf Mon Sep 17 00:00:00 2001
From: Andrew Zhurov <zhurov.andrew@gmail.com>
Date: Sat, 30 Jul 2022 12:15:01 +0300
Subject: [PATCH 1/2] :bug: Fix layers get out of their group when moved

Signed-off-by: Andrei Zhurau <zhurov.andrew@gmail.com>
---
 CHANGES.md                                           |  1 +
 frontend/src/app/main/data/workspace/transforms.cljs | 10 +---------
 2 files changed, 2 insertions(+), 9 deletions(-)

diff --git a/CHANGES.md b/CHANGES.md
index 9b626a3ae..c2447d24d 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -13,6 +13,7 @@
 
 - Fix unexpected removal of guides on copy&paste frames [Taiga #3887](https://tree.taiga.io/project/penpot/issue/3887) by @andrewzhurov
 - Fix props preserving on copy&paste texts [Taiga #3629](https://tree.taiga.io/project/penpot/issue/3629) by @andrewzhurov
+- Fix unexpected layers ungrouping on moving it [Taiga #3932](https://tree.taiga.io/project/penpot/issue/3932) by @andrewzhurov
 
 ### :arrow_up: Deps updates
 ### :heart: Community contributions by (Thank you!)
diff --git a/frontend/src/app/main/data/workspace/transforms.cljs b/frontend/src/app/main/data/workspace/transforms.cljs
index dde91cdc2..30ee41945 100644
--- a/frontend/src/app/main/data/workspace/transforms.cljs
+++ b/frontend/src/app/main/data/workspace/transforms.cljs
@@ -739,14 +739,6 @@
         (rx/of (set-modifiers [id] {:displacement displ} false true)
                (apply-modifiers))))))
 
-(defn check-frame-move?
-  [target-frame-id objects position shape]
-
-  (let [current-frame (get objects (:frame-id shape))]
-    ;; If the current frame contains the point and it's a child of the target
-    (and (gsh/has-point? current-frame position)
-         (cph/is-child? objects target-frame-id (:id current-frame)))))
-
 (defn- calculate-frame-for-move
   [ids]
   (ptk/reify ::calculate-frame-for-move
@@ -761,7 +753,7 @@
             (->> ids
                  (cph/clean-loops objects)
                  (keep #(get objects %))
-                 (remove (partial check-frame-move? frame-id objects position)))
+                 (remove #(= (:frame-id %) frame-id)))
 
             moving-frames
             (->> ids

From 74c6556ad65c2df6c10838c3396e864b428776f1 Mon Sep 17 00:00:00 2001
From: Andrey Antukh <niwi@niwi.nz>
Date: Mon, 1 Aug 2022 16:29:21 +0200
Subject: [PATCH 2/2] :recycle: Refactor some page helpers usage

---
 common/src/app/common/pages/helpers.cljc      | 16 +++++-----------
 common/src/app/common/types/shape_tree.cljc   | 10 ++++++----
 .../app/main/data/workspace/transforms.cljs   | 19 ++++++++++---------
 .../src/app/main/ui/workspace/viewport.cljs   |  4 ++--
 .../app/main/ui/workspace/viewport/hooks.cljs |  5 +++--
 5 files changed, 26 insertions(+), 28 deletions(-)

diff --git a/common/src/app/common/pages/helpers.cljc b/common/src/app/common/pages/helpers.cljc
index 23424981c..c3bf84e70 100644
--- a/common/src/app/common/pages/helpers.cljc
+++ b/common/src/app/common/pages/helpers.cljc
@@ -23,19 +23,13 @@
   (and (= type :frame) (= id uuid/zero)))
 
 (defn root-frame?
-  ([objects id]
-   (root-frame? (get objects id)))
-
-  ([{:keys [frame-id type]}]
-   (and (= type :frame)
-        (= frame-id uuid/zero))))
+  [{:keys [frame-id type]}]
+  (and (= type :frame)
+       (= frame-id uuid/zero)))
 
 (defn frame-shape?
-  ([objects id]
-   (frame-shape? (get objects id)))
-
-  ([{:keys [type]}]
-   (= type :frame)))
+  [{:keys [type]}]
+  (= type :frame))
 
 (defn group-shape?
   [{:keys [type]}]
diff --git a/common/src/app/common/types/shape_tree.cljc b/common/src/app/common/types/shape_tree.cljc
index b03054e24..67fac58df 100644
--- a/common/src/app/common/types/shape_tree.cljc
+++ b/common/src/app/common/types/shape_tree.cljc
@@ -161,13 +161,15 @@
     (cond
       (= base base-shape-id)
       (and (not top-frames?)
-           (cph/frame-shape? objects base-shape-id)
-           (cph/root-frame? objects base-shape-id))
+           (let [object (get objects base-shape-id)]
+             (or (cph/frame-shape? object)
+                 (cph/root-frame? object))))
 
       (= base over-shape-id)
       (or top-frames?
-          (not (cph/frame-shape? objects over-shape-id))
-          (not (cph/root-frame? objects over-shape-id)))
+          (let [object (get objects over-shape-id)]
+            (or (not (cph/frame-shape? object))
+                (not (cph/root-frame? object)))))
 
       :else
       (< index-a index-b))))
diff --git a/frontend/src/app/main/data/workspace/transforms.cljs b/frontend/src/app/main/data/workspace/transforms.cljs
index 30ee41945..51118544e 100644
--- a/frontend/src/app/main/data/workspace/transforms.cljs
+++ b/frontend/src/app/main/data/workspace/transforms.cljs
@@ -745,24 +745,25 @@
     ptk/WatchEvent
     (watch [it state _]
       (let [position @ms/mouse-position
-            page-id (:current-page-id state)
-            objects (wsh/lookup-page-objects state page-id)
+            page-id  (:current-page-id state)
+            objects  (wsh/lookup-page-objects state page-id)
             frame-id (ctt/frame-id-by-position objects position)
+            lookup   (d/getf objects)
 
             moving-shapes
             (->> ids
                  (cph/clean-loops objects)
-                 (keep #(get objects %))
+                 (keep (d/getf objects))
                  (remove #(= (:frame-id %) frame-id)))
 
             moving-frames
-            (->> ids
-                 (filter #(cph/frame-shape? objects %)))
+            (filter #(cph/frame-shape? (lookup %)) ids)
 
-            changes (-> (pcb/empty-changes it page-id)
-                        (pcb/with-objects objects)
-                        (pcb/update-shapes moving-frames (fn [shape] (assoc shape :hide-in-viewer true)))
-                        (pcb/change-parent frame-id moving-shapes))]
+            changes
+            (-> (pcb/empty-changes it page-id)
+                (pcb/with-objects objects)
+                (pcb/update-shapes moving-frames (fn [shape] (assoc shape :hide-in-viewer true)))
+                (pcb/change-parent frame-id moving-shapes))]
 
         (when-not (empty? changes)
           (rx/of (dch/commit-changes changes)
diff --git a/frontend/src/app/main/ui/workspace/viewport.cljs b/frontend/src/app/main/ui/workspace/viewport.cljs
index 659271878..4b0565674 100644
--- a/frontend/src/app/main/ui/workspace/viewport.cljs
+++ b/frontend/src/app/main/ui/workspace/viewport.cljs
@@ -145,7 +145,7 @@
         on-pointer-move   (actions/on-pointer-move viewport-ref zoom move-stream)
         on-pointer-up     (actions/on-pointer-up)
         on-move-selected  (actions/on-move-selected hover hover-ids selected space?)
-        on-menu-selected  (actions/on-menu-selected hover hover-ids selected) 
+        on-menu-selected  (actions/on-menu-selected hover hover-ids selected)
 
         on-frame-enter    (actions/on-frame-enter frame-hover)
         on-frame-leave    (actions/on-frame-leave frame-hover)
@@ -277,7 +277,7 @@
          [:& outline/shape-outlines
           {:objects base-objects
            :hover #{(->> @hover-ids
-                         (filter #(cph/frame-shape? base-objects %))
+                         (filter #(cph/frame-shape? (get base-objects %)))
                          (remove selected)
                          (first))}
            :zoom zoom}])
diff --git a/frontend/src/app/main/ui/workspace/viewport/hooks.cljs b/frontend/src/app/main/ui/workspace/viewport/hooks.cljs
index 2909ab0b4..ef965496a 100644
--- a/frontend/src/app/main/ui/workspace/viewport/hooks.cljs
+++ b/frontend/src/app/main/ui/workspace/viewport/hooks.cljs
@@ -188,11 +188,12 @@
 
              grouped? (fn [id] (contains? #{:group :bool} (get-in objects [id :type])))
 
-
              selected-with-parents
              (into #{} (mapcat #(cph/get-parent-ids objects %)) selected)
 
-             root-frame-with-data? #(and (cph/root-frame? objects %) (d/not-empty? (get-in objects [% :shapes])))
+             root-frame-with-data?
+             #(as-> (get objects %) obj
+                (and (cph/root-frame? obj) (d/not-empty? (:shapes obj))))
 
              ;; Set with the elements to remove from the hover list
              remove-id?