Add nesting constraints for components

This commit is contained in:
Alejandro Alonso
2023-12-13 16:59:01 +01:00
committed by Andrés Moya
parent 3c07416c48
commit a78eb226e2
9 changed files with 277 additions and 131 deletions

View File

@@ -326,7 +326,8 @@
(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/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
[_ {:keys [shape page-id] :as error} file-data _]

View File

@@ -393,7 +393,8 @@
(check-shape-copy-root-top shape file page libraries)))
(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
"Nested main component only allowed inside other component"
shape file page)

View File

@@ -387,3 +387,49 @@
(if (ctk/in-component-copy? parent)
true
(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))])))