diff --git a/common/src/app/common/types/container.cljc b/common/src/app/common/types/container.cljc index 9b06dd45c..548a2edf1 100644 --- a/common/src/app/common/types/container.cljc +++ b/common/src/app/common/types/container.cljc @@ -172,7 +172,13 @@ (cond-> new-shape :always (-> (gsh/move delta) - (dissoc :touched :main-instance?)) + (dissoc :touched)) + + main-instance? + (assoc :main-instance? true) + + (not main-instance?) + (dissoc :main-instance?) (and (not main-instance?) (nil? (:shape-ref original-shape))) (assoc :shape-ref (:id original-shape)) diff --git a/common/src/app/common/types/file.cljc b/common/src/app/common/types/file.cljc index 3beb6ac49..8632b8563 100644 --- a/common/src/app/common/types/file.cljc +++ b/common/src/app/common/types/file.cljc @@ -346,7 +346,7 @@ (map (partial get-component-root file-data) components) start-pos grid-gap)] - (loop [file-data file-data + (loop [file-data file-data components-seq (seq components) position-seq position-seq] (let [component (first components-seq) @@ -355,10 +355,26 @@ file-data (recur (add-main-instance file-data component position) (rest components-seq) - (rest position-seq)))))))] + (rest position-seq))))))) + + root-to-board + (fn [shape] + (cond-> shape + (and (ctk/instance-root? shape) + (not= (:type shape) :frame)) + (assoc :type :frame + :fills [] + :hide-in-viewer true + :rx 0 + :ry 0))) + + roots-to-board + (fn [page] + (update page :objects update-vals root-to-board))] (-> file-data (add-instance-grid (sort-by :name components)) + (update :pages-index update-vals roots-to-board) (assoc-in [:options :components-v2] true)))))) (defn- absorb-components diff --git a/frontend/src/app/main/data/workspace/libraries.cljs b/frontend/src/app/main/data/workspace/libraries.cljs index 23e6f5d78..cc624dcda 100644 --- a/frontend/src/app/main/data/workspace/libraries.cljs +++ b/frontend/src/app/main/data/workspace/libraries.cljs @@ -315,11 +315,13 @@ objects (wsh/lookup-page-objects state page-id) shapes (dwg/shapes-for-grouping objects selected)] (when-not (empty? shapes) - (let [[group _ changes] - (dwlh/generate-add-component it shapes objects page-id file-id components-v2 dwg/prepare-create-group)] + (let [[root _ changes] + (dwlh/generate-add-component it shapes objects page-id file-id components-v2 + dwg/prepare-create-group + dwsh/prepare-create-artboard-from-selection)] (when-not (empty? (:redo-changes changes)) (rx/of (dch/commit-changes changes) - (dws/select-shapes (d/ordered-set (:id group))))))))))) + (dws/select-shapes (d/ordered-set (:id root))))))))))) (defn add-component "Add a new component to current file library, from the currently selected shapes. diff --git a/frontend/src/app/main/data/workspace/libraries_helpers.cljs b/frontend/src/app/main/data/workspace/libraries_helpers.cljs index e4362797c..2a2fb4562 100644 --- a/frontend/src/app/main/data/workspace/libraries_helpers.cljs +++ b/frontend/src/app/main/data/workspace/libraries_helpers.cljs @@ -62,37 +62,48 @@ ;; ---- Components and instances creation ---- (defn generate-add-component - "If there is exactly one id, and it's a group or a frame, and not already a component, - use it as root. Otherwise, create a group that contains all ids. Then, make a + "If there is exactly one id, and it's a frame (or a group in v1), and not already a component, + use it as root. Otherwise, create a frame (v2) or group (v1) that contains all ids. Then, make a component with it, and link all shapes to their corresponding one in the component." - [it shapes objects page-id file-id components-v2 prepare-create-group] - (let [[group changes] + [it shapes objects page-id file-id components-v2 prepare-create-group prepare-create-board] + (let [changes (pcb/empty-changes it page-id) + + [root changes] (if (and (= (count shapes) 1) - (or (= (:type (first shapes)) :group) + (or (and (= (:type (first shapes)) :group) (not components-v2)) (= (:type (first shapes)) :frame)) (not (ctk/instance-root? (first shapes)))) [(first shapes) (-> (pcb/empty-changes it page-id) (pcb/with-objects objects))] - (let [group-name (if (= 1 (count shapes)) + (let [root-name (if (= 1 (count shapes)) (:name (first shapes)) "Component 1")] - (prepare-create-group it ; This function needs to be passed as argument - objects ; to avoid a circular dependence - page-id - shapes - group-name - (not (ctk/instance-root? (first shapes)))))) + (if-not components-v2 + (prepare-create-group it ; These functions needs to be passed as argument + objects ; to avoid a circular dependence + page-id + shapes + root-name + (not (ctk/instance-root? (first shapes)))) + (prepare-create-board changes + (uuid/next) + (:parent-id (first shapes)) + objects + (map :id shapes) + nil + root-name + true)))) - name (:name group) + name (:name root) [path name] (cph/parse-path-name name) [root-shape new-shapes updated-shapes] (if-not components-v2 - (ctn/make-component-shape group objects file-id components-v2) + (ctn/make-component-shape root objects file-id components-v2) (let [new-id (uuid/next)] - [(assoc group :id new-id) + [(assoc root :id new-id) nil - [(assoc group + [(assoc root :component-id new-id :component-file file-id :component-root? true @@ -104,9 +115,9 @@ name new-shapes updated-shapes - (:id group) + (:id root) page-id))] - [group (:id root-shape) changes])) + [root (:id root-shape) changes])) (defn duplicate-component "Clone the root shape of the component and all children. Generate new diff --git a/frontend/src/app/main/data/workspace/shapes.cljs b/frontend/src/app/main/data/workspace/shapes.cljs index b6e59ec02..950987d80 100644 --- a/frontend/src/app/main/data/workspace/shapes.cljs +++ b/frontend/src/app/main/data/workspace/shapes.cljs @@ -74,6 +74,31 @@ :parent-id parent-id :index index)))) +(defn prepare-add-shape + [changes attrs objects selected] + (let [id (or (:id attrs) (uuid/next)) + name (:name attrs) + + shape (make-new-shape + (assoc attrs :id id :name name) + objects + selected) + + index (:index (meta attrs)) + + changes (-> changes + (pcb/with-objects objects) + (cond-> (some? index) + (pcb/add-object shape {:index index})) + (cond-> (nil? index) + (pcb/add-object shape)) + (cond-> (some? (:parent-id attrs)) + (pcb/change-parent (:parent-id attrs) [shape])) + (cond-> (ctl/grid-layout? objects (:parent-id shape)) + (pcb/update-shapes [(:parent-id shape)] ctl/assign-cells)))] + + [shape changes])) + (defn add-shape ([attrs] (add-shape attrs {})) @@ -87,27 +112,11 @@ objects (wsh/lookup-page-objects state page-id) selected (wsh/lookup-selected state) - id (or (:id attrs) (uuid/next)) - name (:name attrs) + changes (pcb/empty-changes it page-id) - shape (make-new-shape - (assoc attrs :id id :name name) - objects - selected) + [shape changes] + (prepare-add-shape changes attrs objects selected) - index (:index (meta attrs)) - - changes (-> (pcb/empty-changes it page-id) - (pcb/with-objects objects) - (cond-> (some? index) - (pcb/add-object shape {:index index})) - (cond-> (nil? index) - (pcb/add-object shape)) - (cond-> (some? (:parent-id attrs)) - (pcb/change-parent (:parent-id attrs) [shape])) - (cond-> (ctl/grid-layout? objects (:parent-id shape)) - (pcb/update-shapes [(:parent-id shape)] ctl/assign-cells)) - ) undo-id (js/Symbol)] (rx/concat @@ -116,36 +125,38 @@ (when-not no-update-layout? (ptk/data-event :layout/update [(:parent-id shape)])) (when-not no-select? - (dws/select-shapes (d/ordered-set id))) + (dws/select-shapes (d/ordered-set (:id shape)))) (dwu/commit-undo-transaction undo-id)) (when (= :text (:type attrs)) - (->> (rx/of (dwe/start-edition-mode id)) + (->> (rx/of (dwe/start-edition-mode (:id shape))) (rx/observe-on :async))))))))) +(defn prepare-move-shapes-into-frame + [changes frame-id shapes objects] + (let [ordered-indexes (cph/order-by-indexed-shapes objects shapes) + parent-id (get-in objects [frame-id :parent-id]) + ordered-indexes (->> ordered-indexes (remove #(= % parent-id))) + to-move-shapes (map (d/getf objects) ordered-indexes)] + (when (d/not-empty? to-move-shapes) + (-> changes + (cond-> (not (ctl/any-layout? objects frame-id)) + (pcb/update-shapes ordered-indexes ctl/remove-layout-item-data)) + (pcb/update-shapes ordered-indexes #(cond-> % (cph/frame-shape? %) (assoc :hide-in-viewer true))) + (pcb/change-parent frame-id to-move-shapes 0) + (cond-> (ctl/grid-layout? objects frame-id) + (pcb/update-shapes [frame-id] ctl/assign-cells)))))) + (defn move-shapes-into-frame [frame-id shapes] (ptk/reify ::move-shapes-into-frame ptk/WatchEvent (watch [it state _] - (let [page-id (:current-page-id state) + (let [page-id (:current-page-id state) objects (wsh/lookup-page-objects state page-id) - - ordered-indexes (cph/order-by-indexed-shapes objects shapes) - parent-id (get-in objects [frame-id :parent-id]) - - ordered-indexes (->> ordered-indexes (remove #(= % parent-id))) - to-move-shapes (map (d/getf objects) ordered-indexes) - - changes - (when (d/not-empty? to-move-shapes) - (-> (pcb/empty-changes it page-id) - (pcb/with-objects objects) - (cond-> (not (ctl/any-layout? objects frame-id)) - (pcb/update-shapes ordered-indexes ctl/remove-layout-item-data)) - (pcb/update-shapes ordered-indexes #(cond-> % (cph/frame-shape? %) (assoc :hide-in-viewer true))) - (pcb/change-parent frame-id to-move-shapes 0) - (cond-> (ctl/grid-layout? objects frame-id) - (pcb/update-shapes [frame-id] ctl/assign-cells))))] - + changes (pcb/empty-changes it page-id) + changes (prepare-move-shapes-into-frame changes + frame-id + shapes + objects)] (if (some? changes) (rx/of (dch/commit-changes changes)) (rx/empty)))))) @@ -362,6 +373,35 @@ ;; Artboard ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +(defn prepare-create-artboard-from-selection + [changes id parent-id objects selected index frame-name without-fill?] + (let [selected-objs (map #(get objects %) selected) + new-index (or index + (cph/get-index-replacement selected objects))] + (when (d/not-empty? selected) + (let [srect (gsh/selection-rect selected-objs) + frame-id (get-in objects [(first selected) :frame-id]) + parent-id (or parent-id (get-in objects [(first selected) :parent-id])) + shape (-> (cts/make-minimal-shape :frame) + (merge {:x (:x srect) :y (:y srect) :width (:width srect) :height (:height srect)}) + (cond-> id + (assoc :id id)) + (cond-> frame-name + (assoc :name frame-name)) + (assoc :frame-id frame-id :parent-id parent-id) + (with-meta {:index new-index}) + (cond-> (or (not= frame-id uuid/zero) without-fill?) + (assoc :fills [] :hide-in-viewer true)) + (cts/setup-rect-selrect)) + + [shape changes] + (prepare-add-shape changes shape objects selected) + + changes + (prepare-move-shapes-into-frame changes (:id shape) selected objects)] + + [shape changes])))) + (defn create-artboard-from-selection ([] (create-artboard-from-selection nil)) @@ -372,34 +412,33 @@ ([id parent-id index] (ptk/reify ::create-artboard-from-selection ptk/WatchEvent - (watch [_ state _] - (let [page-id (:current-page-id state) - objects (wsh/lookup-page-objects state page-id) - selected (wsh/lookup-selected state) - selected (cph/clean-loops objects selected) - selected-objs (map #(get objects %) selected) - new-index (or index - (cph/get-index-replacement selected objects))] - (when (d/not-empty? selected) - (let [srect (gsh/selection-rect selected-objs) - frame-id (get-in objects [(first selected) :frame-id]) - parent-id (or parent-id (get-in objects [(first selected) :parent-id])) - shape (-> (cts/make-minimal-shape :frame) - (merge {:x (:x srect) :y (:y srect) :width (:width srect) :height (:height srect)}) - (cond-> id - (assoc :id id)) - (assoc :frame-id frame-id :parent-id parent-id) - (with-meta {:index new-index}) - (cond-> (not= frame-id uuid/zero) - (assoc :fills [] :hide-in-viewer true)) - (cts/setup-rect-selrect)) - undo-id (js/Symbol)] - (rx/of - (dwu/start-undo-transaction undo-id) - (add-shape shape {:no-update-layout? true}) - (move-shapes-into-frame (:id shape) selected) - (ptk/data-event :layout/update [(:id shape)]) - (dwu/commit-undo-transaction undo-id))))))))) + (watch [it state _] + (let [page-id (:current-page-id state) + objects (wsh/lookup-page-objects state page-id) + selected (wsh/lookup-selected state) + selected (cph/clean-loops objects selected) + + changes (pcb/empty-changes it page-id) + + [frame-shape changes] + (prepare-create-artboard-from-selection changes + id + parent-id + objects + selected + index + nil + false) + + undo-id (js/Symbol)] + + (when changes + (rx/of + (dwu/start-undo-transaction undo-id) + (dch/commit-changes changes) + (dws/select-shapes (d/ordered-set (:id frame-shape))) + (ptk/data-event :layout/update [(:id frame-shape)]) + (dwu/commit-undo-transaction undo-id)))))))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Shape Flags