mirror of
https://github.com/penpot/penpot.git
synced 2025-01-08 07:50:43 -05:00
♻️ Components refactor: generator for generate component for swap
This commit is contained in:
parent
c001710676
commit
05f4459fb7
3 changed files with 153 additions and 121 deletions
|
@ -1820,10 +1820,53 @@
|
|||
(pcb/with-objects (:objects container))
|
||||
(generate-detach-instance container libraries id))))
|
||||
|
||||
(defn generate-update-shape-flags
|
||||
[changes ids objects {:keys [blocked hidden] :as flags}]
|
||||
(let [update-fn
|
||||
(fn [obj]
|
||||
(cond-> obj
|
||||
(boolean? blocked) (assoc :blocked blocked)
|
||||
(boolean? hidden) (assoc :hidden hidden)))
|
||||
|
||||
ids (if (boolean? blocked)
|
||||
(into ids (->> ids (mapcat #(cfh/get-children-ids objects %))))
|
||||
ids)]
|
||||
(-> changes
|
||||
(pcb/update-shapes ids update-fn {:attrs #{:blocked :hidden}}))))
|
||||
|
||||
(defn generate-delete-shapes
|
||||
[changes file page objects ids {:keys [components-v2 ignore-touched undo-group]}]
|
||||
(let [changes (-> changes
|
||||
(pcb/set-undo-group undo-group)
|
||||
[changes file page objects ids {:keys [components-v2 ignore-touched component-swap]}]
|
||||
(let [ids (cfh/clean-loops objects ids)
|
||||
|
||||
in-component-copy?
|
||||
(fn [shape-id]
|
||||
;; Look for shapes that are inside a component copy, but are
|
||||
;; not the root. In this case, they must not be deleted,
|
||||
;; but hidden (to be able to recover them more easily).
|
||||
;; Unless we are doing a component swap, in which case we want
|
||||
;; to delete the old shape
|
||||
(let [shape (get objects shape-id)]
|
||||
(and (ctn/has-any-copy-parent? objects shape)
|
||||
(not component-swap))))
|
||||
|
||||
[ids-to-delete ids-to-hide]
|
||||
(if components-v2
|
||||
(loop [ids-seq (seq ids)
|
||||
ids-to-delete []
|
||||
ids-to-hide []]
|
||||
(let [id (first ids-seq)]
|
||||
(if (nil? id)
|
||||
[ids-to-delete ids-to-hide]
|
||||
(if (in-component-copy? id)
|
||||
(recur (rest ids-seq)
|
||||
ids-to-delete
|
||||
(conj ids-to-hide id))
|
||||
(recur (rest ids-seq)
|
||||
(conj ids-to-delete id)
|
||||
ids-to-hide)))))
|
||||
[ids []])
|
||||
|
||||
changes (-> changes
|
||||
(pcb/with-page page)
|
||||
(pcb/with-objects objects)
|
||||
(pcb/with-library-data file))
|
||||
|
@ -1840,7 +1883,7 @@
|
|||
(conj group-ids (:id parent))
|
||||
group-ids)))
|
||||
#{}
|
||||
ids)
|
||||
ids-to-delete)
|
||||
|
||||
interacting-shapes
|
||||
(filter (fn [shape]
|
||||
|
@ -1848,11 +1891,11 @@
|
|||
;; some interaction, this must be deleted, too.
|
||||
(let [interactions (:interactions shape)]
|
||||
(some #(and (ctsi/has-destination %)
|
||||
(contains? ids (:destination %)))
|
||||
(contains? ids-to-delete (:destination %)))
|
||||
interactions)))
|
||||
(vals objects))
|
||||
|
||||
ids-set (set ids)
|
||||
ids-set (set ids-to-delete)
|
||||
guides-to-remove
|
||||
(->> (dm/get-in page [:options :guides])
|
||||
(vals)
|
||||
|
@ -1867,7 +1910,7 @@
|
|||
(filter (fn [flow]
|
||||
;; If any of the deleted is a frame that starts a flow,
|
||||
;; this must be deleted, too.
|
||||
(contains? ids (:starting-frame flow)))
|
||||
(contains? ids-to-delete (:starting-frame flow)))
|
||||
(-> page :options :flows))
|
||||
|
||||
all-parents
|
||||
|
@ -1875,10 +1918,10 @@
|
|||
;; All parents of any deleted shape must be resized.
|
||||
(into res (cfh/get-parent-ids objects id)))
|
||||
(d/ordered-set)
|
||||
ids)
|
||||
ids-to-delete)
|
||||
|
||||
all-children
|
||||
(->> ids ;; Children of deleted shapes must be also deleted.
|
||||
(->> ids-to-delete ;; Children of deleted shapes must be also deleted.
|
||||
(reduce (fn [res id]
|
||||
(into res (cfh/get-children-ids objects id)))
|
||||
[])
|
||||
|
@ -1887,7 +1930,7 @@
|
|||
|
||||
find-all-empty-parents
|
||||
(fn recursive-find-empty-parents [empty-parents]
|
||||
(let [all-ids (into empty-parents ids)
|
||||
(let [all-ids (into empty-parents ids-to-delete)
|
||||
contains? (partial contains? all-ids)
|
||||
xform (comp (map lookup)
|
||||
(filter #(or (cfh/group-shape? %) (cfh/bool-shape? %)))
|
||||
|
@ -1911,7 +1954,7 @@
|
|||
(conj components (:component-id shape))
|
||||
components)))
|
||||
[]
|
||||
(into ids all-children))
|
||||
(into ids-to-delete all-children))
|
||||
[])
|
||||
|
||||
changes (-> changes
|
||||
|
@ -1923,10 +1966,10 @@
|
|||
(pcb/delete-component changes component-id (:id page)))
|
||||
changes
|
||||
components-to-delete)
|
||||
|
||||
changes (-> changes
|
||||
(generate-update-shape-flags ids-to-hide objects {:hidden true})
|
||||
(pcb/remove-objects all-children {:ignore-touched true})
|
||||
(pcb/remove-objects ids {:ignore-touched ignore-touched})
|
||||
(pcb/remove-objects ids-to-delete {:ignore-touched ignore-touched})
|
||||
(pcb/remove-objects empty-parents)
|
||||
(pcb/resize-parents all-parents)
|
||||
(pcb/update-shapes groups-to-unmask
|
||||
|
@ -1938,10 +1981,67 @@
|
|||
(fn [interactions]
|
||||
(into []
|
||||
(remove #(and (ctsi/has-destination %)
|
||||
(contains? ids (:destination %))))
|
||||
(contains? ids-to-delete (:destination %))))
|
||||
interactions)))))
|
||||
(cond-> (seq starting-flows)
|
||||
(pcb/update-page-option :flows (fn [flows]
|
||||
(->> (map :id starting-flows)
|
||||
(reduce ctp/remove-flow flows))))))]
|
||||
[changes all-parents]))
|
||||
[all-parents changes]))
|
||||
|
||||
(defn generate-new-shape-for-swap
|
||||
[changes shape file page libraries id-new-component index target-cell keep-props-values]
|
||||
(let [objects (:objects page)
|
||||
position (gpt/point (:x shape) (:y shape))
|
||||
changes (-> changes
|
||||
(pcb/with-objects objects))
|
||||
position (-> position (with-meta {:cell target-cell}))
|
||||
parent (get objects (:parent-id shape))
|
||||
inside-comp? (ctn/in-any-component? objects parent)
|
||||
|
||||
[new-shape changes]
|
||||
(generate-instantiate-component changes
|
||||
objects
|
||||
(:id file)
|
||||
id-new-component
|
||||
position
|
||||
page
|
||||
libraries
|
||||
nil
|
||||
(:parent-id shape)
|
||||
(:frame-id shape)
|
||||
{:force-frame? true})
|
||||
|
||||
new-shape (cond-> new-shape
|
||||
;; if the shape isn't inside a main component, it shouldn't have a swap slot
|
||||
(and (nil? (ctk/get-swap-slot new-shape))
|
||||
inside-comp?)
|
||||
(update :touched cfh/set-touched-group (-> (ctf/find-swap-slot shape
|
||||
page
|
||||
{:id (:id file)
|
||||
:data file}
|
||||
libraries)
|
||||
(ctk/build-swap-slot-group))))]
|
||||
|
||||
[new-shape (-> changes
|
||||
;; Restore the properties
|
||||
(pcb/update-shapes [(:id new-shape)] #(d/patch-object % keep-props-values))
|
||||
|
||||
;; We need to set the same index as the original shape
|
||||
(pcb/change-parent (:parent-id shape) [new-shape] index {:component-swap true
|
||||
:ignore-touched true})
|
||||
(change-touched new-shape
|
||||
shape
|
||||
(ctn/make-container page :page)
|
||||
{}))]))
|
||||
|
||||
(defn generate-component-swap
|
||||
[changes objects shape file page libraries id-new-component index target-cell keep-props-values]
|
||||
(let [[all-parents changes]
|
||||
(-> changes
|
||||
(generate-delete-shapes file page objects (d/ordered-set (:id shape)) {:components-v2 true
|
||||
:component-swap true}))
|
||||
[new-shape changes]
|
||||
(-> changes
|
||||
(generate-new-shape-for-swap shape file page libraries id-new-component index target-cell keep-props-values))]
|
||||
[new-shape all-parents changes]))
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
[app.common.types.shape.layout :as ctl]
|
||||
[app.common.types.typography :as ctt]
|
||||
[app.common.uuid :as uuid]
|
||||
[app.main.data.comments :as dc]
|
||||
[app.main.data.events :as ev]
|
||||
[app.main.data.messages :as msg]
|
||||
[app.main.data.modal :as modal]
|
||||
|
@ -31,7 +32,6 @@
|
|||
[app.main.data.workspace.groups :as dwg]
|
||||
[app.main.data.workspace.notifications :as-alias dwn]
|
||||
[app.main.data.workspace.selection :as dws]
|
||||
[app.main.data.workspace.shapes :as dwsh]
|
||||
[app.main.data.workspace.specialized-panel :as dwsp]
|
||||
[app.main.data.workspace.state-helpers :as wsh]
|
||||
[app.main.data.workspace.thumbnails :as dwt]
|
||||
|
@ -465,12 +465,29 @@
|
|||
(watch [it state _]
|
||||
(let [data (get state :workspace-data)]
|
||||
(if (features/active-feature? state "components/v2")
|
||||
(let [component (ctkl/get-component data id)
|
||||
page-id (:main-instance-page component)
|
||||
root-id (:main-instance-id component)]
|
||||
(let [component (ctkl/get-component data id)
|
||||
page-id (:main-instance-page component)
|
||||
root-id (:main-instance-id component)
|
||||
file-id (:current-file-id state)
|
||||
file (wsh/get-file state file-id)
|
||||
page (wsh/lookup-page state page-id)
|
||||
objects (wsh/lookup-page-objects state page-id)
|
||||
components-v2 (features/active-feature? state "components/v2")
|
||||
undo-group (uuid/next)
|
||||
undo-id (js/Symbol)
|
||||
[all-parents changes]
|
||||
(-> (pcb/empty-changes it page-id)
|
||||
;; Deleting main root triggers component delete
|
||||
(cflh/generate-delete-shapes file page objects #{root-id} {:components-v2 components-v2
|
||||
:undo-group undo-group
|
||||
:undo-id undo-id}))]
|
||||
(rx/of
|
||||
(dwu/start-undo-transaction undo-id)
|
||||
(dwt/clear-thumbnail (:current-file-id state) page-id root-id "component")
|
||||
(dwsh/delete-shapes page-id #{root-id}))) ;; Deleting main root triggers component delete
|
||||
(dc/detach-comment-thread #{root-id})
|
||||
(dch/commit-changes changes)
|
||||
(ptk/data-event :layout/update {:ids all-parents :undo-group undo-group})
|
||||
(dwu/commit-undo-transaction undo-id)))
|
||||
(let [page-id (:current-page-id state)
|
||||
changes (-> (pcb/empty-changes it)
|
||||
(pcb/with-library-data data)
|
||||
|
@ -880,62 +897,6 @@
|
|||
second)
|
||||
0)))))
|
||||
|
||||
(defn- add-component-for-swap
|
||||
[shape file page libraries id-new-component index target-cell keep-props-values {:keys [undo-group]}]
|
||||
(dm/assert! (uuid? id-new-component))
|
||||
(ptk/reify ::add-component-for-swap
|
||||
ptk/WatchEvent
|
||||
(watch [it _ _]
|
||||
(let [objects (:objects page)
|
||||
position (gpt/point (:x shape) (:y shape))
|
||||
changes (-> (pcb/empty-changes it (:id page))
|
||||
(pcb/set-undo-group undo-group)
|
||||
(pcb/with-objects objects))
|
||||
position (-> position (with-meta {:cell target-cell}))
|
||||
parent (get objects (:parent-id shape))
|
||||
inside-comp? (ctn/in-any-component? objects parent)
|
||||
|
||||
[new-shape changes]
|
||||
(cflh/generate-instantiate-component changes
|
||||
objects
|
||||
(:id file)
|
||||
id-new-component
|
||||
position
|
||||
page
|
||||
libraries
|
||||
nil
|
||||
(:parent-id shape)
|
||||
(:frame-id shape)
|
||||
{:force-frame? true})
|
||||
|
||||
new-shape (cond-> new-shape
|
||||
; if the shape isn't inside a main component, it shouldn't have a swap slot
|
||||
(and (nil? (ctk/get-swap-slot new-shape))
|
||||
inside-comp?)
|
||||
(update :touched cfh/set-touched-group (-> (ctf/find-swap-slot shape
|
||||
page
|
||||
{:id (:id file)
|
||||
:data file}
|
||||
libraries)
|
||||
(ctk/build-swap-slot-group))))
|
||||
|
||||
changes
|
||||
(-> changes
|
||||
;; Restore the properties
|
||||
(pcb/update-shapes [(:id new-shape)] #(d/patch-object % keep-props-values))
|
||||
|
||||
;; We need to set the same index as the original shape
|
||||
(pcb/change-parent (:parent-id shape) [new-shape] index {:component-swap true
|
||||
:ignore-touched true})
|
||||
(cflh/change-touched new-shape
|
||||
shape
|
||||
(ctn/make-container page :page)
|
||||
{}))]
|
||||
|
||||
;; First delete so we don't break the grid layout cells
|
||||
(rx/of (dch/commit-changes changes)
|
||||
(dws/select-shape (:id new-shape) true))))))
|
||||
|
||||
(defn- component-swap
|
||||
"Swaps a component with another one"
|
||||
[shape file-id id-new-component]
|
||||
|
@ -943,7 +904,7 @@
|
|||
(dm/assert! (uuid? file-id))
|
||||
(ptk/reify ::component-swap
|
||||
ptk/WatchEvent
|
||||
(watch [_ state _]
|
||||
(watch [it state _]
|
||||
;; First delete shapes so we have space in the layout otherwise we can have problems
|
||||
;; in the grid creating new rows/columns to make space
|
||||
(let [file (wsh/get-file state file-id)
|
||||
|
@ -962,15 +923,18 @@
|
|||
keep-props-values (select-keys shape ctk/swap-keep-attrs)
|
||||
|
||||
undo-id (js/Symbol)
|
||||
undo-group (uuid/next)]
|
||||
undo-group (uuid/next)
|
||||
|
||||
[new-shape all-parents changes]
|
||||
(-> (pcb/empty-changes it (:id page))
|
||||
(pcb/set-undo-group undo-group)
|
||||
(cflh/generate-component-swap objects shape file page libraries id-new-component index target-cell keep-props-values))]
|
||||
|
||||
(rx/of
|
||||
(dwu/start-undo-transaction undo-id)
|
||||
(dwsh/delete-shapes nil (d/ordered-set (:id shape)) {:component-swap true
|
||||
:undo-id undo-id
|
||||
:undo-group undo-group})
|
||||
(add-component-for-swap shape file page libraries id-new-component index target-cell keep-props-values
|
||||
{:undo-group undo-group})
|
||||
(ptk/data-event :layout/update {:ids [(:parent-id shape)] :undo-group undo-group})
|
||||
(dch/commit-changes changes)
|
||||
(dws/select-shape (:id new-shape) true)
|
||||
(ptk/data-event :layout/update {:ids all-parents :undo-group undo-group})
|
||||
(dwu/commit-undo-transaction undo-id))))))
|
||||
|
||||
(defn component-multi-swap
|
||||
|
|
|
@ -102,47 +102,15 @@
|
|||
file (wsh/get-file state file-id)
|
||||
page (wsh/lookup-page state page-id)
|
||||
objects (wsh/lookup-page-objects state page-id)
|
||||
|
||||
components-v2 (features/active-feature? state "components/v2")
|
||||
|
||||
ids (cfh/clean-loops objects ids)
|
||||
|
||||
in-component-copy?
|
||||
(fn [shape-id]
|
||||
;; Look for shapes that are inside a component copy, but are
|
||||
;; not the root. In this case, they must not be deleted,
|
||||
;; but hidden (to be able to recover them more easily).
|
||||
;; Unless we are doing a component swap, in which case we want
|
||||
;; to delete the old shape
|
||||
(let [shape (get objects shape-id)]
|
||||
(and (ctn/has-any-copy-parent? objects shape)
|
||||
(not (:component-swap options)))))
|
||||
|
||||
[ids-to-delete ids-to-hide]
|
||||
(if components-v2
|
||||
(loop [ids-seq (seq ids)
|
||||
ids-to-delete []
|
||||
ids-to-hide []]
|
||||
(let [id (first ids-seq)]
|
||||
(if (nil? id)
|
||||
[ids-to-delete ids-to-hide]
|
||||
(if (in-component-copy? id)
|
||||
(recur (rest ids-seq)
|
||||
ids-to-delete
|
||||
(conj ids-to-hide id))
|
||||
(recur (rest ids-seq)
|
||||
(conj ids-to-delete id)
|
||||
ids-to-hide)))))
|
||||
[ids []])
|
||||
undo-id (or (:undo-id options) (js/Symbol))
|
||||
[changes all-parents] (-> (pcb/empty-changes it (:id page))
|
||||
(cflh/generate-delete-shapes file page objects ids-to-delete {:components-v2 components-v2
|
||||
:ignore-touched (:component-swap options)
|
||||
:undo-group (:undo-group options)
|
||||
:undo-id undo-id}))]
|
||||
[all-parents changes] (-> (pcb/empty-changes it (:id page))
|
||||
(cflh/generate-delete-shapes file page objects ids {:components-v2 components-v2
|
||||
:ignore-touched (:component-swap options)
|
||||
:undo-group (:undo-group options)
|
||||
:undo-id undo-id}))]
|
||||
|
||||
(rx/of (dwu/start-undo-transaction undo-id)
|
||||
(update-shape-flags ids-to-hide {:hidden true :undo-group (:undo-group options)})
|
||||
(dc/detach-comment-thread ids)
|
||||
(dch/commit-changes changes)
|
||||
(ptk/data-event :layout/update {:ids all-parents :undo-group (:undo-group options)})
|
||||
|
|
Loading…
Reference in a new issue