mirror of
https://github.com/penpot/penpot.git
synced 2025-04-15 16:31:25 -05:00
🐛 Fix position problems cutting-pasting a component
This commit is contained in:
parent
e28f8cae74
commit
1b8714fe7f
5 changed files with 54 additions and 46 deletions
CHANGES.md
common/src/app/common
|
@ -14,6 +14,7 @@
|
|||
|
||||
- Fix path having a wrong selrect [Taiga #10257](https://tree.taiga.io/project/penpot/issue/10257)
|
||||
- Fix SVG `stroke-linecap` property when importing SVGs [Taiga #9489](https://tree.taiga.io/project/penpot/issue/9489)
|
||||
- Fix position problems cutting-pasting a component [Taiga #10677](https://tree.taiga.io/project/penpot/issue/10677)
|
||||
|
||||
## 2.6.0 (Unreleased)
|
||||
|
||||
|
|
|
@ -345,7 +345,9 @@
|
|||
[:map {:title "DelComponentChange"}
|
||||
[:type [:= :del-component]]
|
||||
[:id ::sm/uuid]
|
||||
[:main-instance {:optional true} :any]
|
||||
;; when it is an undo of a cut-paste, we need to undo the movement
|
||||
;; of the shapes so we need to move them delta
|
||||
[:delta {:optional true} ::gpt/point]
|
||||
[:skip-undelete? {:optional true} :boolean]]]
|
||||
|
||||
[:restore-component
|
||||
|
@ -960,8 +962,8 @@
|
|||
(ctkl/mod-component data params))
|
||||
|
||||
(defmethod process-change :del-component
|
||||
[data {:keys [id skip-undelete? main-instance]}]
|
||||
(ctf/delete-component data id skip-undelete? main-instance))
|
||||
[data {:keys [id skip-undelete? delta]}]
|
||||
(ctf/delete-component data id skip-undelete? delta))
|
||||
|
||||
(defmethod process-change :restore-component
|
||||
[data {:keys [id page-id parent-id]}]
|
||||
|
|
|
@ -1041,7 +1041,7 @@
|
|||
:page-id page-id})))
|
||||
|
||||
(defn restore-component
|
||||
[changes id page-id main-instance parent-id]
|
||||
[changes id page-id delta parent-id]
|
||||
(assert-library! changes)
|
||||
(-> changes
|
||||
(update :redo-changes conj {:type :restore-component
|
||||
|
@ -1050,7 +1050,7 @@
|
|||
:parent-id parent-id})
|
||||
(update :undo-changes conj {:type :del-component
|
||||
:id id
|
||||
:main-instance main-instance})))
|
||||
:delta delta})))
|
||||
|
||||
(defn reorder-grid-children
|
||||
[changes ids]
|
||||
|
|
|
@ -359,18 +359,26 @@
|
|||
(when (some #(= (:id current-page) %) (:pages library-data)) ;; If the page doesn't belong to the library, it's not valid
|
||||
current-page)
|
||||
(ctpl/get-last-page library-data))]
|
||||
(prepare-restore-component changes library-data component-id page (gpt/point 0 0) nil nil nil)))
|
||||
(prepare-restore-component changes library-data component-id page nil nil nil nil)))
|
||||
|
||||
([changes library-data component-id page delta old-id parent-id frame-id]
|
||||
([changes library-data component-id page position old-id parent-id frame-id]
|
||||
(let [component (ctkl/get-deleted-component library-data component-id)
|
||||
parent (get-in page [:objects parent-id])
|
||||
main-inst (get-in component [:objects (:main-instance-id component)])
|
||||
inside-component? (some? (ctn/get-instance-root (:objects page) parent))
|
||||
shapes (cfh/get-children-with-self (:objects component) (:main-instance-id component))
|
||||
shapes (map #(gsh/move % delta) shapes)
|
||||
|
||||
is-variant? (ctk/is-variant? component)
|
||||
|
||||
first-shape (cond-> (first shapes)
|
||||
orig-pos (gpt/point (:x main-inst) (:y main-inst))
|
||||
delta (if position
|
||||
(gpt/subtract position orig-pos)
|
||||
(gpt/point 0 0))
|
||||
minusdelta (gpt/point (- (:x delta)) (- (:y delta)))
|
||||
|
||||
moved-shapes (map #(gsh/move % delta) shapes)
|
||||
|
||||
first-shape (cond-> (first moved-shapes)
|
||||
(not (nil? parent-id))
|
||||
(assoc :parent-id parent-id)
|
||||
(not (nil? frame-id))
|
||||
|
@ -394,9 +402,9 @@
|
|||
(some? old-id) (pcb/amend-last-change #(assoc % :old-id old-id))) ; on copy/paste old id is used later to reorder the paster layers
|
||||
changes (reduce #(pcb/add-object %1 %2 {:ignore-touched true})
|
||||
changes
|
||||
(rest shapes))]
|
||||
{:changes (pcb/restore-component changes component-id (:id page) main-inst parent-id)
|
||||
:shape (first shapes)})))
|
||||
(rest moved-shapes))]
|
||||
{:changes (pcb/restore-component changes component-id (:id page) minusdelta parent-id)
|
||||
:shape (first moved-shapes)})))
|
||||
|
||||
;; ---- General library synchronization functions ----
|
||||
|
||||
|
@ -2188,20 +2196,16 @@
|
|||
;; When we duplicate a variant along with its variant-container, we will duplicate it
|
||||
in-variant-container? (contains? ids-map (:variant-id main))
|
||||
|
||||
|
||||
restore-component
|
||||
#(let [origin-frame (get-in page [:objects frame-id])
|
||||
delta (cond-> delta
|
||||
(some? origin-frame)
|
||||
(gpt/subtract (-> origin-frame :selrect gpt/point)))
|
||||
{:keys [shape changes]} (prepare-restore-component changes
|
||||
library-data
|
||||
component-id
|
||||
page
|
||||
delta
|
||||
main-id
|
||||
parent-id
|
||||
frame-id)]
|
||||
#(let [{:keys [shape changes]}
|
||||
(prepare-restore-component changes
|
||||
library-data
|
||||
component-id
|
||||
page
|
||||
pos
|
||||
main-id
|
||||
parent-id
|
||||
frame-id)]
|
||||
[shape changes])
|
||||
|
||||
[_shape changes]
|
||||
|
|
|
@ -403,33 +403,34 @@
|
|||
|
||||
(defn load-component-objects
|
||||
"Add an :objects property to the component, with only the shapes that belong to it"
|
||||
[file-data component]
|
||||
(let [components-v2 (dm/get-in file-data [:options :components-v2])]
|
||||
(if (and components-v2 component (empty? (:objects component))) ;; This operation may be called twice, e.g. in an idempotent change
|
||||
(let [component-page (get-component-page file-data component)
|
||||
page-objects (:objects component-page)
|
||||
objects (->> (cons (:main-instance-id component)
|
||||
(cfh/get-children-ids page-objects (:main-instance-id component)))
|
||||
(map #(get page-objects %))
|
||||
(d/index-by :id))]
|
||||
(assoc component :objects objects))
|
||||
component)))
|
||||
([file-data component]
|
||||
(load-component-objects file-data component (gpt/point 0 0)))
|
||||
([file-data component delta]
|
||||
(let [components-v2 (dm/get-in file-data [:options :components-v2])]
|
||||
(if (and components-v2 component (empty? (:objects component))) ;; This operation may be called twice, e.g. in an idempotent change
|
||||
(let [component-page (get-component-page file-data component)
|
||||
page-objects (:objects component-page)
|
||||
objects (->> (cons (:main-instance-id component)
|
||||
(cfh/get-children-ids page-objects (:main-instance-id component)))
|
||||
(map #(get page-objects %))
|
||||
;; when it is an undo of a cut-paste, we need to undo the movement
|
||||
;; of the shapes so we need to move them delta
|
||||
(map #(gsh/move % delta))
|
||||
(d/index-by :id))]
|
||||
(assoc component :objects objects))
|
||||
component))))
|
||||
|
||||
(defn delete-component
|
||||
"Mark a component as deleted and store the main instance shapes iside it, to
|
||||
be able to be recovered later."
|
||||
[file-data component-id skip-undelete? main-instance]
|
||||
(let [components-v2 (dm/get-in file-data [:options :components-v2])]
|
||||
[file-data component-id skip-undelete? delta]
|
||||
(let [components-v2 (dm/get-in file-data [:options :components-v2])
|
||||
delta (or delta (gpt/point 0 0))]
|
||||
(if (or (not components-v2) skip-undelete?)
|
||||
(ctkl/delete-component file-data component-id)
|
||||
(let [set-main-instance ;; If there is a saved main-instance, restore it. This happens on the restore-component action
|
||||
#(if main-instance
|
||||
(assoc-in % [:objects (:main-instance-id %)] main-instance)
|
||||
%)]
|
||||
(-> file-data
|
||||
(ctkl/update-component component-id (partial load-component-objects file-data))
|
||||
(ctkl/update-component component-id set-main-instance)
|
||||
(ctkl/mark-component-deleted component-id))))))
|
||||
(-> file-data
|
||||
(ctkl/update-component component-id #(load-component-objects file-data % delta))
|
||||
(ctkl/mark-component-deleted component-id)))))
|
||||
|
||||
(defn restore-component
|
||||
"Recover a deleted component and all its shapes and put all this again in place."
|
||||
|
|
Loading…
Add table
Reference in a new issue