mirror of
https://github.com/penpot/penpot.git
synced 2025-02-15 19:48:22 -05:00
✨ Add nesting constraints for components
This commit is contained in:
parent
3c07416c48
commit
a78eb226e2
9 changed files with 277 additions and 131 deletions
|
@ -326,7 +326,8 @@
|
||||||
(log/dbg :hint "repairing shape :nested-main-not-allowed" :id (:id shape) :name (:name shape) :page-id page-id)
|
(log/dbg :hint "repairing shape :nested-main-not-allowed" :id (:id shape) :name (:name shape) :page-id page-id)
|
||||||
(-> (pcb/empty-changes nil page-id)
|
(-> (pcb/empty-changes nil page-id)
|
||||||
(pcb/with-file-data file-data)
|
(pcb/with-file-data file-data)
|
||||||
(pcb/update-shapes [(:id shape)] repair-shape))))
|
(pcb/update-shapes [(:id shape)] repair-shape)
|
||||||
|
(pcb/change-parent uuid/zero [shape] nil {:component-swap true}))))
|
||||||
|
|
||||||
(defmethod repair-error :root-copy-not-allowed
|
(defmethod repair-error :root-copy-not-allowed
|
||||||
[_ {:keys [shape page-id] :as error} file-data _]
|
[_ {:keys [shape page-id] :as error} file-data _]
|
||||||
|
|
|
@ -393,7 +393,8 @@
|
||||||
(check-shape-copy-root-top shape file page libraries)))
|
(check-shape-copy-root-top shape file page libraries)))
|
||||||
|
|
||||||
(if (ctk/main-instance? shape)
|
(if (ctk/main-instance? shape)
|
||||||
(if (= context :not-component)
|
;; mains can't be nested into mains
|
||||||
|
(if (or (= context :not-component) (= context :main-top))
|
||||||
(report-error :nested-main-not-allowed
|
(report-error :nested-main-not-allowed
|
||||||
"Nested main component only allowed inside other component"
|
"Nested main component only allowed inside other component"
|
||||||
shape file page)
|
shape file page)
|
||||||
|
|
|
@ -387,3 +387,49 @@
|
||||||
(if (ctk/in-component-copy? parent)
|
(if (ctk/in-component-copy? parent)
|
||||||
true
|
true
|
||||||
(has-any-copy-parent? objects (:parent-id shape))))))
|
(has-any-copy-parent? objects (:parent-id shape))))))
|
||||||
|
|
||||||
|
(defn has-any-main?
|
||||||
|
"Check if the shape has any children or parent that is a main component."
|
||||||
|
[objects shape]
|
||||||
|
(let [children (cfh/get-children-with-self objects (:id shape))
|
||||||
|
parents (cfh/get-parents objects (:id shape))]
|
||||||
|
(or
|
||||||
|
(some ctk/main-instance? children)
|
||||||
|
(some ctk/main-instance? parents))))
|
||||||
|
|
||||||
|
(defn valid-shape-for-component?
|
||||||
|
"Check if a main component can be generated from this shape in terms of nested components:
|
||||||
|
- A main can't be the ancestor of another main
|
||||||
|
- A main can't be nested in copies"
|
||||||
|
[objects shape]
|
||||||
|
(and
|
||||||
|
(not (has-any-main? objects shape))
|
||||||
|
(not (has-any-copy-parent? objects shape))))
|
||||||
|
|
||||||
|
(defn- invalid-structure-for-component?
|
||||||
|
"Check if the structure generated nesting children in parent is invalid in terms of nested components"
|
||||||
|
[objects parent children]
|
||||||
|
(let [selected-main-instance? (some true? (map #(has-any-main? objects %) children))
|
||||||
|
parent-in-component? (in-any-component? objects parent)
|
||||||
|
comps-nesting-loop? (not (->> children
|
||||||
|
(map #(cfh/components-nesting-loop? objects (:id %) (:id parent)))
|
||||||
|
(every? nil?)))]
|
||||||
|
(or
|
||||||
|
;;We don't want to change the structure of component copies
|
||||||
|
(ctk/in-component-copy? parent)
|
||||||
|
;; If we are moving something containing a main instance the container can't be part of a component (neither main nor copy)
|
||||||
|
(and selected-main-instance? parent-in-component?)
|
||||||
|
;; Avoid placing a shape as a direct or indirect child of itself,
|
||||||
|
;; or inside its main component if it's in a copy.
|
||||||
|
comps-nesting-loop?)))
|
||||||
|
|
||||||
|
(defn find-valid-parent-and-frame-ids
|
||||||
|
"Navigate trough the ancestors until find one that is valid"
|
||||||
|
[parent-id objects children]
|
||||||
|
(let [parent (get objects parent-id)]
|
||||||
|
(if (invalid-structure-for-component? objects parent children)
|
||||||
|
(find-valid-parent-and-frame-ids (:parent-id parent) objects children)
|
||||||
|
[parent-id
|
||||||
|
(if (= :frame (:type parent))
|
||||||
|
parent-id
|
||||||
|
(:frame-id parent))])))
|
||||||
|
|
|
@ -1845,18 +1845,9 @@
|
||||||
tree-root (get-tree-root-shapes pobjects)
|
tree-root (get-tree-root-shapes pobjects)
|
||||||
only-one-root-shape? (and
|
only-one-root-shape? (and
|
||||||
(< 1 (count pobjects))
|
(< 1 (count pobjects))
|
||||||
(= 1 (count tree-root)))
|
(= 1 (count tree-root)))]
|
||||||
all-objects (merge page-objects pobjects)
|
|
||||||
comps-nesting-loop? (not (->> (keys pobjects)
|
|
||||||
(map #(cfh/components-nesting-loop? all-objects % (:id base)))
|
|
||||||
(every? nil?)))]
|
|
||||||
|
|
||||||
(cond
|
(cond
|
||||||
comps-nesting-loop?
|
|
||||||
;; Avoid placing a shape as a direct or indirect child of itself,
|
|
||||||
;; or inside its main component if it's in a copy.
|
|
||||||
[uuid/zero uuid/zero (gpt/subtract position orig-pos)]
|
|
||||||
|
|
||||||
(selected-frame? state)
|
(selected-frame? state)
|
||||||
|
|
||||||
(if (or (any-same-frame-from-selected? state (keys pobjects))
|
(if (or (any-same-frame-from-selected? state (keys pobjects))
|
||||||
|
@ -1869,7 +1860,7 @@
|
||||||
paste-y (:y selected-frame-obj)
|
paste-y (:y selected-frame-obj)
|
||||||
delta (gpt/subtract (gpt/point paste-x paste-y) orig-pos)]
|
delta (gpt/subtract (gpt/point paste-x paste-y) orig-pos)]
|
||||||
|
|
||||||
[(:frame-id base) parent-id delta index])
|
[parent-id delta index])
|
||||||
|
|
||||||
;; Paste inside selected frame otherwise
|
;; Paste inside selected frame otherwise
|
||||||
(let [selected-frame-obj (get page-objects (first page-selected))
|
(let [selected-frame-obj (get page-objects (first page-selected))
|
||||||
|
@ -1902,20 +1893,19 @@
|
||||||
;; - Align it to the limits on the x and y axis
|
;; - Align it to the limits on the x and y axis
|
||||||
;; - Respect the distance of the object to the right and bottom in the original frame
|
;; - Respect the distance of the object to the right and bottom in the original frame
|
||||||
(gpt/point paste-x paste-y))]
|
(gpt/point paste-x paste-y))]
|
||||||
[frame-id frame-id delta (dec (count (:shapes selected-frame-obj)))]))
|
[frame-id delta (dec (count (:shapes selected-frame-obj)))]))
|
||||||
|
|
||||||
(empty? page-selected)
|
(empty? page-selected)
|
||||||
(let [frame-id (ctst/top-nested-frame page-objects position)
|
(let [frame-id (ctst/top-nested-frame page-objects position)
|
||||||
delta (gpt/subtract position orig-pos)]
|
delta (gpt/subtract position orig-pos)]
|
||||||
[frame-id frame-id delta])
|
[frame-id delta])
|
||||||
|
|
||||||
:else
|
:else
|
||||||
(let [frame-id (:frame-id base)
|
(let [parent-id (:parent-id base)
|
||||||
parent-id (:parent-id base)
|
|
||||||
delta (if in-viewport?
|
delta (if in-viewport?
|
||||||
(gpt/subtract position orig-pos)
|
(gpt/subtract position orig-pos)
|
||||||
(gpt/subtract (gpt/point (:selrect base)) orig-pos))]
|
(gpt/subtract (gpt/point (:selrect base)) orig-pos))]
|
||||||
[frame-id parent-id delta index]))))
|
[parent-id delta index]))))
|
||||||
|
|
||||||
;; Change the indexes of the pasted shapes
|
;; Change the indexes of the pasted shapes
|
||||||
(change-add-obj-index [objects selected index change]
|
(change-add-obj-index [objects selected index change]
|
||||||
|
@ -1953,64 +1943,65 @@
|
||||||
(ptk/reify ::paste-shapes
|
(ptk/reify ::paste-shapes
|
||||||
ptk/WatchEvent
|
ptk/WatchEvent
|
||||||
(watch [it state _]
|
(watch [it state _]
|
||||||
(let [file-id (:current-file-id state)
|
(let [file-id (:current-file-id state)
|
||||||
page (wsh/lookup-page state)
|
page (wsh/lookup-page state)
|
||||||
|
|
||||||
media-idx (->> (:media pdata)
|
media-idx (->> (:media pdata)
|
||||||
(d/index-by :prev-id))
|
(d/index-by :prev-id))
|
||||||
|
|
||||||
selected (:selected pdata)
|
selected (:selected pdata)
|
||||||
objects (:objects pdata)
|
objects (:objects pdata)
|
||||||
|
|
||||||
position (deref ms/mouse-position)
|
position (deref ms/mouse-position)
|
||||||
|
|
||||||
;; Calculate position for the pasted elements
|
;; Calculate position for the pasted elements
|
||||||
[frame-id
|
[candidate-parent-id
|
||||||
parent-id
|
|
||||||
delta
|
delta
|
||||||
index] (calculate-paste-position state objects selected position)
|
index] (calculate-paste-position state objects selected position)
|
||||||
|
|
||||||
;; We don't want to change the structure of component
|
page-objects (:objects page)
|
||||||
;; copies If the parent-id or the frame-id are
|
|
||||||
;; component-copies, we need to get the first not copy
|
|
||||||
;; parent
|
|
||||||
parent-id (:id (ctn/get-first-not-copy-parent (:objects page) parent-id))
|
|
||||||
frame-id (:id (ctn/get-first-not-copy-parent (:objects page) frame-id))
|
|
||||||
|
|
||||||
objects (update-vals objects (partial process-shape file-id frame-id parent-id))
|
[parent-id
|
||||||
all-objects (merge (:objects page) objects)
|
frame-id] (ctn/find-valid-parent-and-frame-ids candidate-parent-id page-objects (vals objects))
|
||||||
|
|
||||||
libraries (wsh/get-libraries state)
|
index (if (= candidate-parent-id parent-id)
|
||||||
ldata (wsh/get-file state file-id)
|
index
|
||||||
|
0)
|
||||||
|
|
||||||
drop-cell (when (ctl/grid-layout? all-objects parent-id)
|
objects (update-vals objects (partial process-shape file-id frame-id parent-id))
|
||||||
(gslg/get-drop-cell frame-id all-objects position))
|
|
||||||
|
|
||||||
changes (-> (dws/prepare-duplicate-changes all-objects page selected delta it libraries ldata file-id)
|
all-objects (merge page-objects objects)
|
||||||
(pcb/amend-changes (partial process-rchange media-idx))
|
|
||||||
(pcb/amend-changes (partial change-add-obj-index objects selected index)))
|
libraries (wsh/get-libraries state)
|
||||||
|
ldata (wsh/get-file state file-id)
|
||||||
|
|
||||||
|
drop-cell (when (ctl/grid-layout? all-objects parent-id)
|
||||||
|
(gslg/get-drop-cell frame-id all-objects position))
|
||||||
|
|
||||||
|
changes (-> (dws/prepare-duplicate-changes all-objects page selected delta it libraries ldata file-id)
|
||||||
|
(pcb/amend-changes (partial process-rchange media-idx))
|
||||||
|
(pcb/amend-changes (partial change-add-obj-index objects selected index)))
|
||||||
|
|
||||||
;; Adds a resize-parents operation so the groups are
|
;; Adds a resize-parents operation so the groups are
|
||||||
;; updated. We add all the new objects
|
;; updated. We add all the new objects
|
||||||
changes (->> (:redo-changes changes)
|
changes (->> (:redo-changes changes)
|
||||||
(filter add-obj?)
|
(filter add-obj?)
|
||||||
(map :id)
|
(map :id)
|
||||||
(pcb/resize-parents changes))
|
(pcb/resize-parents changes))
|
||||||
|
|
||||||
selected (into (d/ordered-set)
|
selected (into (d/ordered-set)
|
||||||
(comp
|
(comp
|
||||||
(filter add-obj?)
|
(filter add-obj?)
|
||||||
(filter #(contains? selected (:old-id %)))
|
(filter #(contains? selected (:old-id %)))
|
||||||
(map :obj)
|
(map :obj)
|
||||||
(map :id))
|
(map :id))
|
||||||
(:redo-changes changes))
|
(:redo-changes changes))
|
||||||
|
|
||||||
changes (cond-> changes
|
changes (cond-> changes
|
||||||
(some? drop-cell)
|
(some? drop-cell)
|
||||||
(pcb/update-shapes [parent-id]
|
(pcb/update-shapes [parent-id]
|
||||||
#(ctl/add-children-to-cell % selected all-objects drop-cell)))
|
#(ctl/add-children-to-cell % selected all-objects drop-cell)))
|
||||||
|
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)
|
||||||
|
|
|
@ -340,12 +340,16 @@
|
||||||
(ptk/reify ::add-component
|
(ptk/reify ::add-component
|
||||||
ptk/WatchEvent
|
ptk/WatchEvent
|
||||||
(watch [_ state _]
|
(watch [_ state _]
|
||||||
(let [objects (wsh/lookup-page-objects state)
|
(let [objects (wsh/lookup-page-objects state)
|
||||||
selected (->> (wsh/lookup-selected state)
|
selected (->> (wsh/lookup-selected state)
|
||||||
(cfh/clean-loops objects)
|
(cfh/clean-loops objects))
|
||||||
(remove #(ctn/has-any-copy-parent? objects (get objects %)))) ;; We don't want to change the structure of component copies
|
selected-objects (map #(get objects %) selected)
|
||||||
components-v2 (features/active-feature? state "components/v2")]
|
components-v2 (features/active-feature? state "components/v2")
|
||||||
(rx/of (add-component2 selected components-v2))))))
|
;; We don't want to change the structure of component copies
|
||||||
|
can-make-component (every? true? (map #(ctn/valid-shape-for-component? objects %) selected-objects))]
|
||||||
|
|
||||||
|
(when can-make-component
|
||||||
|
(rx/of (add-component2 selected components-v2)))))))
|
||||||
|
|
||||||
(defn add-multiple-components
|
(defn add-multiple-components
|
||||||
"Add several new components to current file library, from the currently selected shapes."
|
"Add several new components to current file library, from the currently selected shapes."
|
||||||
|
@ -353,19 +357,22 @@
|
||||||
(ptk/reify ::add-multiple-components
|
(ptk/reify ::add-multiple-components
|
||||||
ptk/WatchEvent
|
ptk/WatchEvent
|
||||||
(watch [_ state _]
|
(watch [_ state _]
|
||||||
(let [components-v2 (features/active-feature? state "components/v2")
|
(let [components-v2 (features/active-feature? state "components/v2")
|
||||||
objects (wsh/lookup-page-objects state)
|
objects (wsh/lookup-page-objects state)
|
||||||
selected (->> (wsh/lookup-selected state)
|
selected (->> (wsh/lookup-selected state)
|
||||||
(cfh/clean-loops objects)
|
(cfh/clean-loops objects))
|
||||||
(remove #(ctn/has-any-copy-parent? objects (get objects %)))) ;; We don't want to change the structure of component copies
|
selected-objects (map #(get objects %) selected)
|
||||||
added-components (map
|
;; We don't want to change the structure of component copies
|
||||||
#(add-component2 [%] components-v2)
|
can-make-component (every? true? (map #(ctn/valid-shape-for-component? objects %) selected-objects))
|
||||||
selected)
|
added-components (map
|
||||||
|
#(add-component2 [%] components-v2)
|
||||||
|
selected)
|
||||||
undo-id (js/Symbol)]
|
undo-id (js/Symbol)]
|
||||||
(rx/concat
|
(when can-make-component
|
||||||
(rx/of (dwu/start-undo-transaction undo-id))
|
(rx/concat
|
||||||
(rx/from added-components)
|
(rx/of (dwu/start-undo-transaction undo-id))
|
||||||
(rx/of (dwu/commit-undo-transaction undo-id)))))))
|
(rx/from added-components)
|
||||||
|
(rx/of (dwu/commit-undo-transaction undo-id))))))))
|
||||||
|
|
||||||
(defn rename-component
|
(defn rename-component
|
||||||
"Rename the component with the given id, in the current file library."
|
"Rename the component with the given id, in the current file library."
|
||||||
|
|
|
@ -560,13 +560,14 @@
|
||||||
|
|
||||||
(rx/map
|
(rx/map
|
||||||
(fn [[move-vector mod?]]
|
(fn [[move-vector mod?]]
|
||||||
(let [position (gpt/add from-position move-vector)
|
(let [position (gpt/add from-position move-vector)
|
||||||
exclude-frames (if mod? exclude-frames exclude-frames-siblings)
|
exclude-frames (if mod? exclude-frames exclude-frames-siblings)
|
||||||
target-frame (ctst/top-nested-frame objects position exclude-frames)
|
target-frame (ctst/top-nested-frame objects position exclude-frames)
|
||||||
flex-layout? (ctl/flex-layout? objects target-frame)
|
[target-frame _] (ctn/find-valid-parent-and-frame-ids target-frame objects shapes)
|
||||||
grid-layout? (ctl/grid-layout? objects target-frame)
|
flex-layout? (ctl/flex-layout? objects target-frame)
|
||||||
drop-index (when flex-layout? (gslf/get-drop-index target-frame objects position))
|
grid-layout? (ctl/grid-layout? objects target-frame)
|
||||||
cell-data (when (and grid-layout? (not mod?)) (gslg/get-drop-cell target-frame objects position))]
|
drop-index (when flex-layout? (gslf/get-drop-index target-frame objects position))
|
||||||
|
cell-data (when (and grid-layout? (not mod?)) (gslg/get-drop-cell target-frame objects position))]
|
||||||
(array move-vector target-frame drop-index cell-data))))
|
(array move-vector target-frame drop-index cell-data))))
|
||||||
|
|
||||||
(rx/take-until stopper))]
|
(rx/take-until stopper))]
|
||||||
|
@ -587,16 +588,12 @@
|
||||||
[(assoc move-vector :x 0) :x]
|
[(assoc move-vector :x 0) :x]
|
||||||
|
|
||||||
:else
|
:else
|
||||||
[move-vector nil])
|
[move-vector nil])]
|
||||||
|
|
||||||
nesting-loop? (some #(cfh/components-nesting-loop? objects (:id %) target-frame) shapes)
|
|
||||||
is-component-copy? (ctk/in-component-copy? (get objects target-frame))]
|
|
||||||
|
|
||||||
(cond-> (dwm/create-modif-tree ids (ctm/move-modifiers move-vector))
|
(-> (dwm/create-modif-tree ids (ctm/move-modifiers move-vector))
|
||||||
(and (not nesting-loop?) (not is-component-copy?))
|
(dwm/build-change-frame-modifiers objects selected target-frame drop-index cell-data)
|
||||||
(dwm/build-change-frame-modifiers objects selected target-frame drop-index cell-data)
|
(dwm/set-modifiers false false {:snap-ignore-axis snap-ignore-axis}))))))
|
||||||
:always
|
|
||||||
(dwm/set-modifiers false false {:snap-ignore-axis snap-ignore-axis}))))))
|
|
||||||
|
|
||||||
(->> move-stream
|
(->> move-stream
|
||||||
(rx/with-latest-from ms/mouse-position-alt)
|
(rx/with-latest-from ms/mouse-position-alt)
|
||||||
|
|
|
@ -422,13 +422,13 @@
|
||||||
(let [components-v2 (features/use-feature "components/v2")
|
(let [components-v2 (features/use-feature "components/v2")
|
||||||
single? (= (count shapes) 1)
|
single? (= (count shapes) 1)
|
||||||
objects (deref refs/workspace-page-objects)
|
objects (deref refs/workspace-page-objects)
|
||||||
any-in-copy? (some true? (map #(ctn/has-any-copy-parent? objects %) shapes))
|
can-make-component (every? true? (map #(ctn/valid-shape-for-component? objects %) shapes))
|
||||||
heads (filter ctk/instance-head? shapes)
|
heads (filter ctk/instance-head? shapes)
|
||||||
components-menu-entries (cmm/generate-components-menu-entries heads components-v2)
|
components-menu-entries (cmm/generate-components-menu-entries heads components-v2)
|
||||||
do-add-component #(st/emit! (dwl/add-component))
|
do-add-component #(st/emit! (dwl/add-component))
|
||||||
do-add-multiple-components #(st/emit! (dwl/add-multiple-components))]
|
do-add-multiple-components #(st/emit! (dwl/add-multiple-components))]
|
||||||
[:*
|
[:*
|
||||||
(when-not any-in-copy? ;; We don't want to change the structure of component copies
|
(when can-make-component ;; We don't want to change the structure of component copies
|
||||||
[:*
|
[:*
|
||||||
[:& menu-separator]
|
[:& menu-separator]
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,6 @@
|
||||||
[app.common.data :as d]
|
[app.common.data :as d]
|
||||||
[app.common.data.macros :as dm]
|
[app.common.data.macros :as dm]
|
||||||
[app.common.files.helpers :as cfh]
|
[app.common.files.helpers :as cfh]
|
||||||
[app.common.types.component :as ctk]
|
|
||||||
[app.common.types.container :as ctn]
|
[app.common.types.container :as ctn]
|
||||||
[app.common.types.shape.layout :as ctl]
|
[app.common.types.shape.layout :as ctl]
|
||||||
[app.common.uuid :as uuid]
|
[app.common.uuid :as uuid]
|
||||||
|
@ -261,7 +260,7 @@
|
||||||
|
|
||||||
on-drop
|
on-drop
|
||||||
(mf/use-fn
|
(mf/use-fn
|
||||||
(mf/deps id index objects expanded?)
|
(mf/deps id index objects expanded? selected)
|
||||||
(fn [side _data]
|
(fn [side _data]
|
||||||
(let [shape (get objects id)
|
(let [shape (get objects id)
|
||||||
|
|
||||||
|
@ -276,6 +275,8 @@
|
||||||
:else
|
:else
|
||||||
(cfh/get-parent-id objects id))
|
(cfh/get-parent-id objects id))
|
||||||
|
|
||||||
|
[parent-id _] (ctn/find-valid-parent-and-frame-ids parent-id objects (map #(get objects %) selected))
|
||||||
|
|
||||||
parent (get objects parent-id)
|
parent (get objects parent-id)
|
||||||
|
|
||||||
to-index (cond
|
to-index (cond
|
||||||
|
@ -283,9 +284,7 @@
|
||||||
(and expanded? (= side :bot) (d/not-empty? (:shapes shape))) (count (:shapes parent))
|
(and expanded? (= side :bot) (d/not-empty? (:shapes shape))) (count (:shapes parent))
|
||||||
(= side :top) (inc index)
|
(= side :top) (inc index)
|
||||||
:else index)]
|
:else index)]
|
||||||
|
(st/emit! (dw/relocate-selected-shapes parent-id to-index)))))
|
||||||
(when-not (ctk/in-component-copy? parent) ;; We don't want to change the structure of component copies
|
|
||||||
(st/emit! (dw/relocate-selected-shapes parent-id to-index))))))
|
|
||||||
|
|
||||||
on-hold
|
on-hold
|
||||||
(mf/use-fn
|
(mf/use-fn
|
||||||
|
|
|
@ -170,7 +170,7 @@
|
||||||
(dwl/add-component)
|
(dwl/add-component)
|
||||||
:the/end))))
|
:the/end))))
|
||||||
|
|
||||||
(t/deftest test-add-component-from-component
|
(t/deftest test-add-component-from-component-instance
|
||||||
(t/async
|
(t/async
|
||||||
done
|
done
|
||||||
(let [state (-> thp/initial-state
|
(let [state (-> thp/initial-state
|
||||||
|
@ -178,30 +178,27 @@
|
||||||
(thp/sample-shape :shape1 :rect
|
(thp/sample-shape :shape1 :rect
|
||||||
{:name "Rect 1"})
|
{:name "Rect 1"})
|
||||||
(thp/make-component :main1 :component1
|
(thp/make-component :main1 :component1
|
||||||
[(thp/id :shape1)]))
|
[(thp/id :shape1)])
|
||||||
|
(thp/instantiate-component :instance1 (thp/id :component1)))
|
||||||
|
|
||||||
store (the/prepare-store state done
|
store (the/prepare-store state done
|
||||||
(fn [new-state]
|
(fn [new-state]
|
||||||
;; Expected shape tree:
|
;; Expected shape tree:
|
||||||
;;
|
;;
|
||||||
;; [Page]
|
;; [Page: Page]
|
||||||
;; Root Frame
|
;; Root Frame
|
||||||
;; Rect 1
|
;; Rect 1 #
|
||||||
;; Rect 1
|
;; Rect 1
|
||||||
;; Rect 1
|
;; Rect 1 #
|
||||||
;;
|
;; Rect 1* @--> Rect 1
|
||||||
;; [Rect 1]
|
;; Rect 1 ---> Rect 1
|
||||||
;; page1 / Rect 1
|
;;
|
||||||
;;
|
|
||||||
;; [Rect 1]
|
|
||||||
;; page1 / Rect 1
|
|
||||||
;;
|
|
||||||
(let [[[instance1 shape1]
|
(let [[[instance1 shape1]
|
||||||
[c-instance1 c-shape1]
|
[c-instance1 c-shape1]
|
||||||
component1]
|
component1]
|
||||||
(thl/resolve-instance-and-main
|
(thl/resolve-instance-and-main
|
||||||
new-state
|
new-state
|
||||||
(thp/id :main1)
|
(thp/id :instance1)
|
||||||
true)
|
true)
|
||||||
|
|
||||||
[[instance2 instance1' shape1']
|
[[instance2 instance1' shape1']
|
||||||
|
@ -225,6 +222,56 @@
|
||||||
(t/is (= (:name c-instance1') "Rect 1"))
|
(t/is (= (:name c-instance1') "Rect 1"))
|
||||||
(t/is (= (:name c-instance2) "Rect 1")))))]
|
(t/is (= (:name c-instance2) "Rect 1")))))]
|
||||||
|
|
||||||
|
(ptk/emit!
|
||||||
|
store
|
||||||
|
(dw/select-shape (thp/id :instance1))
|
||||||
|
(dwl/add-component)
|
||||||
|
:the/end))))
|
||||||
|
|
||||||
|
|
||||||
|
(t/deftest test-add-component-from-component-main
|
||||||
|
(t/async
|
||||||
|
done
|
||||||
|
(let [state (-> thp/initial-state
|
||||||
|
(thp/sample-page)
|
||||||
|
(thp/sample-shape :shape1 :rect
|
||||||
|
{:name "Rect 1"})
|
||||||
|
(thp/make-component :main1 :component1
|
||||||
|
[(thp/id :shape1)]))
|
||||||
|
|
||||||
|
store (the/prepare-store state done
|
||||||
|
(fn [new-state]
|
||||||
|
;; Expected shape tree:
|
||||||
|
;;
|
||||||
|
;; [Page]
|
||||||
|
;; Root Frame
|
||||||
|
;; Rect 1
|
||||||
|
;; Rect 1
|
||||||
|
;;
|
||||||
|
;; [Rect 1]
|
||||||
|
;; page1 / Rect 1
|
||||||
|
;;
|
||||||
|
(let [file (wsh/get-local-file new-state)
|
||||||
|
components (ctkl/components file)
|
||||||
|
page (thp/current-page new-state)
|
||||||
|
shape1 (thp/get-shape new-state :shape1)
|
||||||
|
parent1 (ctn/get-shape page (:parent-id shape1))
|
||||||
|
main1 (thp/get-shape state :main1)
|
||||||
|
[[instance1 shape1]
|
||||||
|
[c-instance1 c-shape1]
|
||||||
|
component1]
|
||||||
|
(thl/resolve-instance-and-main
|
||||||
|
new-state
|
||||||
|
(:id main1))]
|
||||||
|
;; Creating a component from a main doesn't generate a new component
|
||||||
|
(t/is (= (count components) 1))
|
||||||
|
|
||||||
|
(t/is (= (:name shape1) "Rect 1"))
|
||||||
|
(t/is (= (:name instance1) "Rect 1"))
|
||||||
|
(t/is (= (:name component1) "Rect 1"))
|
||||||
|
(t/is (= (:name c-shape1) "Rect 1"))
|
||||||
|
(t/is (= (:name c-instance1) "Rect 1")))))]
|
||||||
|
|
||||||
(ptk/emit!
|
(ptk/emit!
|
||||||
store
|
store
|
||||||
(dw/select-shape (thp/id :main1))
|
(dw/select-shape (thp/id :main1))
|
||||||
|
@ -580,7 +627,62 @@
|
||||||
(dwl/detach-component (:id instance1))
|
(dwl/detach-component (:id instance1))
|
||||||
:the/end))))
|
:the/end))))
|
||||||
|
|
||||||
(t/deftest test-add-nested-component
|
|
||||||
|
|
||||||
|
(t/deftest test-add-nested-component-instance
|
||||||
|
(t/async
|
||||||
|
done
|
||||||
|
(let [state (-> thp/initial-state
|
||||||
|
(thp/sample-page)
|
||||||
|
(thp/sample-shape :shape1 :rect
|
||||||
|
{:name "Rect 1"})
|
||||||
|
(thp/make-component :main1 :component1
|
||||||
|
[(thp/id :shape1)])
|
||||||
|
(thp/instantiate-component :instance1 (thp/id :component1)))
|
||||||
|
|
||||||
|
store (the/prepare-store state done
|
||||||
|
(fn [new-state]
|
||||||
|
;; Expected shape tree:
|
||||||
|
;;
|
||||||
|
;; [Page]
|
||||||
|
;; Root Frame
|
||||||
|
;; Rect 1
|
||||||
|
;; Rect 1
|
||||||
|
;; Board
|
||||||
|
;; Rect 1
|
||||||
|
;; Rect 1
|
||||||
|
;;
|
||||||
|
;; [Rect 1]
|
||||||
|
;; page1 / Rect 1
|
||||||
|
;;
|
||||||
|
;; [Board]
|
||||||
|
;; page1 / Board
|
||||||
|
;;
|
||||||
|
(let [instance1 (thp/get-shape new-state :instance1)
|
||||||
|
|
||||||
|
[[group shape1 shape2]
|
||||||
|
[c-group c-shape1 c-shape2]
|
||||||
|
component]
|
||||||
|
(thl/resolve-instance-and-main
|
||||||
|
new-state
|
||||||
|
(:parent-id instance1))]
|
||||||
|
|
||||||
|
(t/is (= (:name group) "Board"))
|
||||||
|
(t/is (= (:name shape1) "Rect 1"))
|
||||||
|
(t/is (= (:name shape2) "Rect 1"))
|
||||||
|
(t/is (= (:name component) "Board"))
|
||||||
|
(t/is (= (:name c-group) "Board"))
|
||||||
|
(t/is (= (:name c-shape1) "Rect 1"))
|
||||||
|
(t/is (= (:name c-shape2) "Rect 1")))))]
|
||||||
|
|
||||||
|
(ptk/emit!
|
||||||
|
store
|
||||||
|
(dw/select-shape (thp/id :instance1))
|
||||||
|
(dwsh/create-artboard-from-selection)
|
||||||
|
(dwl/add-component)
|
||||||
|
:the/end))))
|
||||||
|
|
||||||
|
(t/deftest test-add-nested-component-main
|
||||||
(t/async
|
(t/async
|
||||||
done
|
done
|
||||||
(let [state (-> thp/initial-state
|
(let [state (-> thp/initial-state
|
||||||
|
@ -594,34 +696,36 @@
|
||||||
;;
|
;;
|
||||||
;; [Page]
|
;; [Page]
|
||||||
;; Root Frame
|
;; Root Frame
|
||||||
;; Group
|
;; Board
|
||||||
;; Rect 1
|
;; Rect 1
|
||||||
;; Rect 1
|
;; Rect 1
|
||||||
;;
|
;;
|
||||||
;; [Rect 1]
|
;; [Rect 1]
|
||||||
;; page1 / Rect 1
|
;; page1 / Rect 1
|
||||||
;;
|
;;
|
||||||
;; [Group]
|
|
||||||
;; page1 / Group
|
|
||||||
;;
|
;;
|
||||||
(let [page (thp/current-page new-state)
|
(let [file (wsh/get-local-file new-state)
|
||||||
|
components (ctkl/components file)
|
||||||
|
page (thp/current-page new-state)
|
||||||
|
|
||||||
shape1 (thp/get-shape new-state :shape1)
|
shape1 (thp/get-shape new-state :shape1)
|
||||||
parent1 (ctn/get-shape page (:parent-id shape1))
|
parent1 (ctn/get-shape page (:parent-id shape1))
|
||||||
|
|
||||||
[[group shape1 shape2]
|
[[group shape1]
|
||||||
[c-group c-shape1 c-shape2]
|
[c-group c-shape1]
|
||||||
component]
|
component]
|
||||||
(thl/resolve-instance-and-main
|
(thl/resolve-instance-and-main
|
||||||
new-state
|
new-state
|
||||||
(:parent-id parent1))]
|
(:parent-id shape1))]
|
||||||
|
|
||||||
(t/is (= (:name group) "Board"))
|
;; Creating a component from something containing a main doesn't generate a new component
|
||||||
|
(t/is (= (count components) 1))
|
||||||
|
|
||||||
|
(t/is (= (:name group) "Rect 1"))
|
||||||
(t/is (= (:name shape1) "Rect 1"))
|
(t/is (= (:name shape1) "Rect 1"))
|
||||||
(t/is (= (:name shape2) "Rect 1"))
|
(t/is (= (:name component) "Rect 1"))
|
||||||
(t/is (= (:name component) "Board"))
|
(t/is (= (:name c-group) "Rect 1"))
|
||||||
(t/is (= (:name c-group) "Board"))
|
(t/is (= (:name c-shape1) "Rect 1")))))]
|
||||||
(t/is (= (:name c-shape1) "Rect 1"))
|
|
||||||
(t/is (= (:name c-shape2) "Rect 1")))))]
|
|
||||||
|
|
||||||
(ptk/emit!
|
(ptk/emit!
|
||||||
store
|
store
|
||||||
|
|
Loading…
Add table
Reference in a new issue