mirror of
https://github.com/penpot/penpot.git
synced 2025-05-19 09:26:12 +02:00
🎉 Copy paste components, even to another page
This commit is contained in:
parent
b73ce14560
commit
b33e469501
7 changed files with 143 additions and 85 deletions
|
@ -326,8 +326,8 @@
|
||||||
(ctf/delete-component data id skip-undelete?))
|
(ctf/delete-component data id skip-undelete?))
|
||||||
|
|
||||||
(defmethod process-change :restore-component
|
(defmethod process-change :restore-component
|
||||||
[data {:keys [id]}]
|
[data {:keys [id page-id]}]
|
||||||
(ctf/restore-component data id))
|
(ctf/restore-component data id page-id))
|
||||||
|
|
||||||
(defmethod process-change :purge-component
|
(defmethod process-change :purge-component
|
||||||
[data {:keys [id]}]
|
[data {:keys [id]}]
|
||||||
|
|
|
@ -656,13 +656,16 @@
|
||||||
:id id})))
|
:id id})))
|
||||||
|
|
||||||
(defn restore-component
|
(defn restore-component
|
||||||
[changes id]
|
([changes id]
|
||||||
(assert-library changes)
|
(restore-component changes id nil))
|
||||||
(-> changes
|
([changes id page-id]
|
||||||
(update :redo-changes conj {:type :restore-component
|
(assert-library changes)
|
||||||
:id id})
|
(-> changes
|
||||||
(update :undo-changes d/preconj {:type :del-component
|
(update :redo-changes conj {:type :restore-component
|
||||||
:id id})))
|
:id id
|
||||||
|
:page-id page-id})
|
||||||
|
(update :undo-changes d/preconj {:type :del-component
|
||||||
|
:id id}))))
|
||||||
|
|
||||||
(defn ignore-remote
|
(defn ignore-remote
|
||||||
[changes]
|
[changes]
|
||||||
|
|
|
@ -201,10 +201,14 @@
|
||||||
|
|
||||||
(defn restore-component
|
(defn restore-component
|
||||||
"Recover a deleted component and all its shapes and put all this again in place."
|
"Recover a deleted component and all its shapes and put all this again in place."
|
||||||
[file-data component-id]
|
[file-data component-id page-id]
|
||||||
(-> file-data
|
(let [components-v2 (dm/get-in file-data [:options :components-v2])
|
||||||
(ctkl/update-component component-id #(dissoc % :objects))
|
update-page? (and components-v2 (not (nil? page-id)))]
|
||||||
(ctkl/mark-component-undeleted component-id)))
|
(-> file-data
|
||||||
|
(ctkl/update-component component-id #(dissoc % :objects))
|
||||||
|
(ctkl/mark-component-undeleted component-id)
|
||||||
|
(cond-> update-page?
|
||||||
|
(ctkl/update-component component-id #(assoc % :main-instance-page page-id))))))
|
||||||
|
|
||||||
(defn purge-component
|
(defn purge-component
|
||||||
"Remove permanently a component."
|
"Remove permanently a component."
|
||||||
|
@ -383,7 +387,6 @@
|
||||||
(some? (:component-file %))
|
(some? (:component-file %))
|
||||||
(assoc :component-file (:id file-data)))
|
(assoc :component-file (:id file-data)))
|
||||||
main-instance-shapes)
|
main-instance-shapes)
|
||||||
|
|
||||||
; Add all shapes of the main instance to the library page
|
; Add all shapes of the main instance to the library page
|
||||||
add-main-instance-shapes
|
add-main-instance-shapes
|
||||||
(fn [page]
|
(fn [page]
|
||||||
|
|
|
@ -1600,9 +1600,10 @@
|
||||||
(gpt/subtract (gpt/point (:selrect base)) orig-pos))]
|
(gpt/subtract (gpt/point (:selrect base)) orig-pos))]
|
||||||
[frame-id parent-id delta index]))))
|
[frame-id parent-id delta index]))))
|
||||||
|
|
||||||
;; Change the indexes if the paste is done with an element selected
|
;; Change the indexes of the pasted shapes
|
||||||
(change-add-obj-index [paste-objects selected index change]
|
(change-add-obj-index [paste-objects selected index change]
|
||||||
(let [set-index (fn [[result index] id]
|
(let [index (or index -1) ;; if there is no current element selected, we want the first (inc index) to be 0
|
||||||
|
set-index (fn [[result index] id]
|
||||||
[(assoc result id index) (inc index)])
|
[(assoc result id index) (inc index)])
|
||||||
|
|
||||||
map-ids
|
map-ids
|
||||||
|
@ -1626,7 +1627,8 @@
|
||||||
|
|
||||||
;; Proceed with the standard shape paste process.
|
;; Proceed with the standard shape paste process.
|
||||||
(do-paste [it state mouse-pos media]
|
(do-paste [it state mouse-pos media]
|
||||||
(let [file-id (:current-file-id state)
|
(let [libraries (wsh/get-libraries state)
|
||||||
|
file-id (:current-file-id state)
|
||||||
page (wsh/lookup-page state)
|
page (wsh/lookup-page state)
|
||||||
media-idx (d/index-by :prev-id media)
|
media-idx (d/index-by :prev-id media)
|
||||||
|
|
||||||
|
@ -1651,7 +1653,9 @@
|
||||||
|
|
||||||
all-objects (merge (:objects page) paste-objects)
|
all-objects (merge (:objects page) paste-objects)
|
||||||
|
|
||||||
changes (-> (dws/prepare-duplicate-changes all-objects page selected delta it nil)
|
library-data (wsh/get-file state file-id)
|
||||||
|
|
||||||
|
changes (-> (dws/prepare-duplicate-changes all-objects page selected delta it libraries library-data)
|
||||||
(pcb/amend-changes (partial process-rchange media-idx))
|
(pcb/amend-changes (partial process-rchange media-idx))
|
||||||
(pcb/amend-changes (partial change-add-obj-index paste-objects selected index)))
|
(pcb/amend-changes (partial change-add-obj-index paste-objects selected index)))
|
||||||
|
|
||||||
|
|
|
@ -152,7 +152,6 @@
|
||||||
changes (-> (pcb/empty-changes it)
|
changes (-> (pcb/empty-changes it)
|
||||||
(pcb/with-library-data data)
|
(pcb/with-library-data data)
|
||||||
(pcb/update-color color))
|
(pcb/update-color color))
|
||||||
|
|
||||||
undo-id (js/Symbol)]
|
undo-id (js/Symbol)]
|
||||||
(rx/of (dwu/start-undo-transaction undo-id)
|
(rx/of (dwu/start-undo-transaction undo-id)
|
||||||
(dch/commit-changes changes)
|
(dch/commit-changes changes)
|
||||||
|
@ -436,18 +435,10 @@
|
||||||
(ptk/reify ::restore-component
|
(ptk/reify ::restore-component
|
||||||
ptk/WatchEvent
|
ptk/WatchEvent
|
||||||
(watch [it state _]
|
(watch [it state _]
|
||||||
(let [library-data (wsh/get-file state library-id)
|
(let [library-data (wsh/get-file state library-id)
|
||||||
component (ctkl/get-deleted-component library-data component-id)
|
changes (:changes (dwlh/prepare-restore-component library-data component-id it))]
|
||||||
page (ctf/get-component-page library-data component)
|
(rx/of (dch/commit-changes changes))))))
|
||||||
shapes (cph/get-children-with-self (:objects component) (:main-instance-id component))
|
|
||||||
changes (-> (pcb/empty-changes it)
|
|
||||||
(pcb/with-library-data library-data)
|
|
||||||
(pcb/with-page page))
|
|
||||||
changes (reduce #(pcb/add-object %1 %2 {:ignore-touched true})
|
|
||||||
changes
|
|
||||||
shapes)
|
|
||||||
changes (pcb/restore-component changes component-id)]
|
|
||||||
(rx/of (dch/commit-changes changes))))))
|
|
||||||
|
|
||||||
(defn instantiate-component
|
(defn instantiate-component
|
||||||
"Create a new shape in the current page, from the component with the given id
|
"Create a new shape in the current page, from the component with the given id
|
||||||
|
@ -476,7 +467,6 @@
|
||||||
(dch/commit-changes changes)
|
(dch/commit-changes changes)
|
||||||
(ptk/data-event :layout/update [(:id new-shape)])
|
(ptk/data-event :layout/update [(:id new-shape)])
|
||||||
(dws/select-shapes (d/ordered-set (:id new-shape)))
|
(dws/select-shapes (d/ordered-set (:id new-shape)))
|
||||||
|
|
||||||
(dwu/commit-undo-transaction undo-id))))))
|
(dwu/commit-undo-transaction undo-id))))))
|
||||||
|
|
||||||
(defn detach-component
|
(defn detach-component
|
||||||
|
|
|
@ -146,24 +146,30 @@
|
||||||
|
|
||||||
(defn generate-instantiate-component
|
(defn generate-instantiate-component
|
||||||
"Generate changes to create a new instance from a component."
|
"Generate changes to create a new instance from a component."
|
||||||
[changes file-id component-id position page libraries]
|
([changes file-id component-id position page libraries]
|
||||||
(let [component (ctf/get-component libraries file-id component-id)
|
(generate-instantiate-component changes file-id component-id position page libraries nil))
|
||||||
library (get libraries file-id)
|
|
||||||
|
|
||||||
components-v2 (dm/get-in library [:data :options :components-v2])
|
([changes file-id component-id position page libraries old-id]
|
||||||
|
(let [component (ctf/get-component libraries file-id component-id)
|
||||||
|
library (get libraries file-id)
|
||||||
|
|
||||||
[new-shape new-shapes]
|
components-v2 (dm/get-in library [:data :options :components-v2])
|
||||||
(ctn/make-component-instance page
|
|
||||||
component
|
|
||||||
(:data library)
|
|
||||||
position
|
|
||||||
components-v2)
|
|
||||||
|
|
||||||
changes (reduce #(pcb/add-object %1 %2 {:ignore-touched true})
|
[new-shape new-shapes]
|
||||||
changes
|
(ctn/make-component-instance page
|
||||||
new-shapes)]
|
component
|
||||||
|
(:data library)
|
||||||
|
position
|
||||||
|
components-v2)
|
||||||
|
|
||||||
[new-shape changes]))
|
changes (cond-> (pcb/add-object changes (first new-shapes) {:ignore-touched true})
|
||||||
|
(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 new-shapes))]
|
||||||
|
|
||||||
|
[new-shape changes])))
|
||||||
|
|
||||||
(defn generate-detach-instance
|
(defn generate-detach-instance
|
||||||
"Generate changes to remove the links between a shape and all its children
|
"Generate changes to remove the links between a shape and all its children
|
||||||
|
@ -185,6 +191,29 @@
|
||||||
|
|
||||||
(pcb/update-shapes changes shapes update-fn)))
|
(pcb/update-shapes changes shapes update-fn)))
|
||||||
|
|
||||||
|
|
||||||
|
(defn prepare-restore-component
|
||||||
|
([library-data component-id it]
|
||||||
|
(let [component (ctkl/get-deleted-component library-data component-id)
|
||||||
|
page (ctf/get-component-page library-data component)]
|
||||||
|
(prepare-restore-component library-data component-id it page (gpt/point 0 0) nil nil)))
|
||||||
|
|
||||||
|
([library-data component-id it page delta old-id changes]
|
||||||
|
(let [component (ctkl/get-deleted-component library-data component-id)
|
||||||
|
|
||||||
|
shapes (cph/get-children-with-self (:objects component) (:main-instance-id component))
|
||||||
|
shapes (map #(gsh/move % delta) shapes)
|
||||||
|
changes (-> (or changes (pcb/empty-changes it))
|
||||||
|
(pcb/with-page page)
|
||||||
|
(pcb/with-library-data library-data))
|
||||||
|
changes (cond-> (pcb/add-object changes (first shapes) {:ignore-touched true})
|
||||||
|
(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))
|
||||||
|
:shape (first shapes)})))
|
||||||
|
|
||||||
;; ---- General library synchronization functions ----
|
;; ---- General library synchronization functions ----
|
||||||
|
|
||||||
(defn generate-sync-file
|
(defn generate-sync-file
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
[app.common.pages.helpers :as cph]
|
[app.common.pages.helpers :as cph]
|
||||||
[app.common.spec :as us]
|
[app.common.spec :as us]
|
||||||
[app.common.types.component :as ctk]
|
[app.common.types.component :as ctk]
|
||||||
|
[app.common.types.file :as ctf]
|
||||||
[app.common.types.page :as ctp]
|
[app.common.types.page :as ctp]
|
||||||
[app.common.types.shape.interactions :as ctsi]
|
[app.common.types.shape.interactions :as ctsi]
|
||||||
[app.common.uuid :as uuid]
|
[app.common.uuid :as uuid]
|
||||||
|
@ -332,53 +333,77 @@
|
||||||
(defn prepare-duplicate-changes
|
(defn prepare-duplicate-changes
|
||||||
"Prepare objects to duplicate: generate new id, give them unique names,
|
"Prepare objects to duplicate: generate new id, give them unique names,
|
||||||
move to the desired position, and recalculate parents and frames as needed."
|
move to the desired position, and recalculate parents and frames as needed."
|
||||||
[all-objects page ids delta it libraries]
|
([all-objects page ids delta it libraries library-data]
|
||||||
(let [shapes (map (d/getf all-objects) ids)
|
(let [init-changes
|
||||||
unames (volatile! (cp/retrieve-used-names (:objects page)))
|
(-> (pcb/empty-changes it)
|
||||||
update-unames! (fn [new-name] (vswap! unames conj new-name))
|
(pcb/with-page page)
|
||||||
all-ids (reduce #(into %1 (cons %2 (cph/get-children-ids all-objects %2))) (d/ordered-set) ids)
|
(pcb/with-objects all-objects))]
|
||||||
ids-map (into {} (map #(vector % (uuid/next))) all-ids)
|
(prepare-duplicate-changes all-objects page ids delta it libraries library-data init-changes)))
|
||||||
|
|
||||||
init-changes
|
([all-objects page ids delta it libraries library-data init-changes]
|
||||||
(-> (pcb/empty-changes it)
|
(let [shapes (map (d/getf all-objects) ids)
|
||||||
(pcb/with-page page)
|
unames (volatile! (cp/retrieve-used-names (:objects page)))
|
||||||
(pcb/with-objects all-objects))
|
update-unames! (fn [new-name] (vswap! unames conj new-name))
|
||||||
|
all-ids (reduce #(into %1 (cons %2 (cph/get-children-ids all-objects %2))) (d/ordered-set) ids)
|
||||||
|
ids-map (into {} (map #(vector % (uuid/next))) all-ids)
|
||||||
|
|
||||||
changes
|
changes
|
||||||
(->> shapes
|
(->> shapes
|
||||||
(reduce #(prepare-duplicate-shape-change %1
|
(reduce #(prepare-duplicate-shape-change %1
|
||||||
all-objects
|
all-objects
|
||||||
page
|
page
|
||||||
unames
|
unames
|
||||||
update-unames!
|
update-unames!
|
||||||
ids-map
|
ids-map
|
||||||
%2
|
%2
|
||||||
delta
|
delta
|
||||||
libraries)
|
libraries
|
||||||
init-changes))]
|
library-data
|
||||||
|
it)
|
||||||
|
init-changes))]
|
||||||
|
|
||||||
(-> changes
|
(-> changes
|
||||||
(prepare-duplicate-flows shapes page ids-map)
|
(prepare-duplicate-flows shapes page ids-map)
|
||||||
(prepare-duplicate-guides shapes page ids-map delta))))
|
(prepare-duplicate-guides shapes page ids-map delta)))))
|
||||||
|
|
||||||
|
(defn- prepare-duplicate-component-change
|
||||||
|
([changes page component-root delta libraries library-data it]
|
||||||
|
(let [component-id (:component-id component-root)
|
||||||
|
file-id (:component-file component-root)
|
||||||
|
main-component (ctf/get-component libraries file-id component-id)
|
||||||
|
moved-component (gsh/move component-root delta)
|
||||||
|
pos (gpt/point (:x moved-component) (:y moved-component))
|
||||||
|
|
||||||
|
instantiate-component
|
||||||
|
#(dwlh/generate-instantiate-component changes
|
||||||
|
file-id
|
||||||
|
(:component-id component-root)
|
||||||
|
pos
|
||||||
|
page
|
||||||
|
libraries
|
||||||
|
(:id component-root))
|
||||||
|
|
||||||
|
restore-component
|
||||||
|
#(let [restore (dwlh/prepare-restore-component library-data (:component-id component-root) it page delta (:id component-root) changes)]
|
||||||
|
[(:shape restore) (:changes restore)])
|
||||||
|
|
||||||
|
[_shape changes]
|
||||||
|
(if (nil? main-component)
|
||||||
|
(restore-component)
|
||||||
|
(instantiate-component))]
|
||||||
|
changes)))
|
||||||
|
|
||||||
(defn- prepare-duplicate-shape-change
|
(defn- prepare-duplicate-shape-change
|
||||||
([changes objects page unames update-unames! ids-map obj delta libraries]
|
([changes objects page unames update-unames! ids-map obj delta libraries library-data it]
|
||||||
(prepare-duplicate-shape-change changes objects page unames update-unames! ids-map obj delta libraries (:frame-id obj) (:parent-id obj)))
|
(prepare-duplicate-shape-change changes objects page unames update-unames! ids-map obj delta libraries library-data it (:frame-id obj) (:parent-id obj)))
|
||||||
|
|
||||||
([changes objects page unames update-unames! ids-map obj delta libraries frame-id parent-id]
|
([changes objects page unames update-unames! ids-map obj delta libraries library-data it frame-id parent-id]
|
||||||
(cond
|
(cond
|
||||||
(nil? obj)
|
(nil? obj)
|
||||||
changes
|
changes
|
||||||
|
|
||||||
(ctk/main-instance? obj)
|
(ctk/main-instance? obj)
|
||||||
(let [[_new-shape changes]
|
(prepare-duplicate-component-change changes page obj delta libraries library-data it)
|
||||||
(dwlh/generate-instantiate-component changes
|
|
||||||
(:component-file obj)
|
|
||||||
(:component-id obj)
|
|
||||||
(gpt/point (:x obj) (:y obj))
|
|
||||||
page
|
|
||||||
libraries)]
|
|
||||||
changes)
|
|
||||||
|
|
||||||
:else
|
:else
|
||||||
(let [frame? (cph/frame-shape? obj)
|
(let [frame? (cph/frame-shape? obj)
|
||||||
|
@ -410,6 +435,8 @@
|
||||||
child
|
child
|
||||||
delta
|
delta
|
||||||
libraries
|
libraries
|
||||||
|
library-data
|
||||||
|
it
|
||||||
(if frame? new-id frame-id)
|
(if frame? new-id frame-id)
|
||||||
new-id))
|
new-id))
|
||||||
changes
|
changes
|
||||||
|
@ -562,9 +589,11 @@
|
||||||
(calc-duplicate-delta obj state objects)
|
(calc-duplicate-delta obj state objects)
|
||||||
(gpt/point 0 0))
|
(gpt/point 0 0))
|
||||||
|
|
||||||
|
file-id (:current-file-id state)
|
||||||
libraries (wsh/get-libraries state)
|
libraries (wsh/get-libraries state)
|
||||||
|
library-data (wsh/get-file state file-id)
|
||||||
|
|
||||||
changes (->> (prepare-duplicate-changes objects page selected delta it libraries)
|
changes (->> (prepare-duplicate-changes objects page selected delta it libraries library-data)
|
||||||
(duplicate-changes-update-indices objects selected))
|
(duplicate-changes-update-indices objects selected))
|
||||||
|
|
||||||
changes (cond-> changes add-undo-group? (assoc :undo-group (uuid/random)))
|
changes (cond-> changes add-undo-group? (assoc :undo-group (uuid/random)))
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue