mirror of
https://github.com/penpot/penpot.git
synced 2025-01-22 14:39:45 -05:00
🐛 Advance nested copies when duplicated
This commit is contained in:
parent
1d25115218
commit
9a7a99e67a
4 changed files with 75 additions and 15 deletions
|
@ -154,6 +154,17 @@
|
|||
:else
|
||||
(get-head-shape objects (get objects (:parent-id shape)) options))))
|
||||
|
||||
(defn get-child-heads
|
||||
"Get all recursive childs that are heads (when a head is found, do not
|
||||
continue down looking for subsequent nested heads)."
|
||||
[objects shape-id]
|
||||
(let [shape (get objects shape-id)]
|
||||
(if (nil? shape)
|
||||
[]
|
||||
(if (ctk/instance-head? shape)
|
||||
[shape]
|
||||
(mapcat #(get-child-heads objects %) (:shapes shape))))))
|
||||
|
||||
(defn get-parent-heads
|
||||
"Get all component heads that are ancestors of the shape, in top-down order
|
||||
(include self if it's also a head)."
|
||||
|
@ -170,6 +181,20 @@
|
|||
(filter #(and (ctk/instance-head? %) (ctk/in-component-copy? %)))
|
||||
(reverse)))
|
||||
|
||||
(defn get-nesting-level-delta
|
||||
"Get how many levels a shape will 'go up' if moved under the new parent."
|
||||
[objects shape new-parent]
|
||||
(let [orig-heads (->> (get-parent-copy-heads objects shape)
|
||||
(remove #(= (:id %) (:id shape))))
|
||||
dest-heads (get-parent-copy-heads objects new-parent)
|
||||
|
||||
;; 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))]
|
||||
|
||||
(- (count orig-heads) common-count)))
|
||||
|
||||
(defn get-instance-root
|
||||
"Get the parent shape at the top of the component instance (main or copy)."
|
||||
[objects shape]
|
||||
|
|
|
@ -216,14 +216,14 @@
|
|||
|
||||
(some find-ref-shape-in-head (ctn/get-parent-heads (:objects container) shape))))
|
||||
|
||||
(defn find-original-ref-shape
|
||||
"Recursively call to find-ref-shape until find the original shape of the original component"
|
||||
[file container libraries shape & options]
|
||||
(defn advance-shape-ref
|
||||
"Get the shape-ref of the near main of the shape, recursively repeated as many times
|
||||
as the given levels."
|
||||
[file container libraries shape levels & options]
|
||||
(let [ref-shape (find-ref-shape file container libraries shape options)]
|
||||
(if (nil? (:shape-ref ref-shape))
|
||||
ref-shape
|
||||
(find-original-ref-shape file container libraries ref-shape options))))
|
||||
|
||||
(if (or (nil? (:shape-ref ref-shape)) (not (pos? levels)))
|
||||
(:id ref-shape)
|
||||
(advance-shape-ref file container libraries ref-shape (dec levels) options))))
|
||||
|
||||
(defn find-ref-component
|
||||
"Locate the nearest component in the local file or libraries that is referenced by the
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
[app.common.types.component :as ctk]
|
||||
[app.common.types.components-list :as ctkl]
|
||||
[app.common.types.container :as ctn]
|
||||
[app.common.types.file :as ctf]
|
||||
[app.common.types.shape :as cts]
|
||||
[app.common.types.shape-tree :as ctst]
|
||||
[app.common.types.shape.layout :as ctl]
|
||||
|
@ -1598,6 +1599,34 @@
|
|||
(let [frame (get objects parent-frame-id)]
|
||||
(gsh/translate-to-frame shape frame))))
|
||||
|
||||
;; When copying an instance that is nested inside another one, we need to
|
||||
;; advance the shape refs to one or more levels of remote mains.
|
||||
(advance-copies [state selected data]
|
||||
(let [file (wsh/get-local-file-full state)
|
||||
libraries (wsh/get-libraries state)
|
||||
page (wsh/lookup-page state)
|
||||
heads (mapcat #(ctn/get-child-heads (:objects data) %) selected)]
|
||||
(update data :objects
|
||||
#(reduce (partial advance-copy file libraries page)
|
||||
%
|
||||
heads))))
|
||||
|
||||
(advance-copy [file libraries page objects shape]
|
||||
(if (and (ctk/instance-head? shape) (not (ctk/main-instance? shape)))
|
||||
(let [level-delta (ctn/get-nesting-level-delta (:objects page) shape uuid/zero)]
|
||||
(if (pos? level-delta)
|
||||
(reduce (partial advance-shape file libraries page level-delta)
|
||||
objects
|
||||
(cfh/get-children-with-self objects (:id shape)))
|
||||
objects))
|
||||
objects))
|
||||
|
||||
(advance-shape [file libraries page level-delta objects shape]
|
||||
(let [new-shape-ref (ctf/advance-shape-ref file page libraries shape level-delta {:include-deleted? true})]
|
||||
(cond-> objects
|
||||
(and (some? new-shape-ref) (not= new-shape-ref (:shape-ref shape)))
|
||||
(assoc-in [(:id shape) :shape-ref] new-shape-ref))))
|
||||
|
||||
(on-copy-error [error]
|
||||
(js/console.error "clipboard blocked:" error)
|
||||
(rx/empty))]
|
||||
|
@ -1636,6 +1665,7 @@
|
|||
(rx/merge-map (partial prepare-object objects frame-id))
|
||||
(rx/reduce collect-data initial)
|
||||
(rx/map (partial sort-selected state))
|
||||
(rx/map (partial advance-copies state selected))
|
||||
(rx/map #(t/encode-str % {:type :json-verbose}))
|
||||
(rx/map wapi/write-to-clipboard)
|
||||
(rx/catch on-copy-error)
|
||||
|
|
|
@ -404,6 +404,7 @@
|
|||
ids-map
|
||||
%2
|
||||
delta
|
||||
nil
|
||||
libraries
|
||||
library-data
|
||||
it
|
||||
|
@ -459,10 +460,10 @@
|
|||
|
||||
;; TODO: move to common.files.shape-helpers
|
||||
(defn- prepare-duplicate-shape-change
|
||||
([changes objects page unames update-unames! ids-map obj delta libraries library-data it file-id]
|
||||
(prepare-duplicate-shape-change changes objects page unames update-unames! ids-map obj delta libraries library-data it file-id (:frame-id obj) (:parent-id obj) false false))
|
||||
([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))
|
||||
|
||||
([changes objects page unames update-unames! ids-map obj 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?]
|
||||
(cond
|
||||
(nil? obj)
|
||||
changes
|
||||
|
@ -486,11 +487,14 @@
|
|||
duplicating-component? (or duplicating-component? (ctk/instance-head? obj))
|
||||
is-component-main? (ctk/main-instance? obj)
|
||||
|
||||
original-ref-shape (-> (ctf/find-original-ref-shape nil page libraries obj {:include-deleted? true})
|
||||
:id)
|
||||
into-component? (and duplicating-component?
|
||||
(ctn/in-any-component? objects parent))
|
||||
|
||||
level-delta (if (some? level-delta)
|
||||
level-delta
|
||||
(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 [components-v2 (dm/get-in library-data [:options :components-v2])
|
||||
|
@ -518,9 +522,9 @@
|
|||
(cond-> (or frame? group? bool?)
|
||||
(assoc :shapes []))
|
||||
|
||||
(cond-> (and (some? original-ref-shape)
|
||||
(not= original-ref-shape (:shape-ref obj)))
|
||||
(assoc :shape-ref original-ref-shape))
|
||||
(cond-> (and (some? new-shape-ref)
|
||||
(not= new-shape-ref (:shape-ref obj)))
|
||||
(assoc :shape-ref new-shape-ref))
|
||||
|
||||
(gsh/move delta)
|
||||
(d/update-when :interactions #(ctsi/remap-interactions % ids-map objects))
|
||||
|
@ -561,6 +565,7 @@
|
|||
ids-map
|
||||
child
|
||||
delta
|
||||
level-delta
|
||||
libraries
|
||||
library-data
|
||||
it
|
||||
|
|
Loading…
Add table
Reference in a new issue