diff --git a/common/app/common/pages.cljc b/common/app/common/pages.cljc index 643720eab4..42acab8997 100644 --- a/common/app/common/pages.cljc +++ b/common/app/common/pages.cljc @@ -362,6 +362,9 @@ (defmethod change-spec :del-component [_] (s/keys :req-un [::id])) +(defmethod change-spec :sync-library [_] + (s/keys :req-un [::id])) + (s/def ::change (s/multi-spec change-spec :type)) (s/def ::changes (s/coll-of ::change)) @@ -774,6 +777,81 @@ [data {:keys [id]}] (d/dissoc-in data [:components id])) +(declare sync-page) +(declare sync-shape-and-children) +(declare sync-shape) + +(defmethod process-change :sync-library + [data id] + (cph/walk-pages (sync-page (:components data)) data)) + +(defn- sync-page + [components] + (fn [page-id page] + (let [linked-shapes + (cph/select-objects #(some? (:component-id %)) page) + + updated-shapes + (reduce + (fn [updated-shapes linked-shape] + (let [component-id (:component-id linked-shape) + component (get components component-id)] + (into updated-shapes + (sync-shape-and-children linked-shape + component + (:objects page))))) + [] + linked-shapes)] + + (cph/update-object-list page updated-shapes)))) + +(defn- sync-shape-and-children + [linked-shape component objects] + (let [children (cph/get-children-objects (:id linked-shape) objects) + all-shapes (conj children linked-shape)] + (if (nil? component) + (map #(dissoc % :component-id :shape-ref) all-shapes) + (map #(sync-shape % (:objects component)) all-shapes)))) + +(defn- sync-shape + [shape component-objs] + (let [component-shape (get component-objs (:shape-ref shape))] + (if (nil? component-shape) + (assoc shape :shape-ref nil) + (-> shape + (d/update-when :content :content component-shape) + (d/update-when :fill-color :fill-color component-shape) + (d/update-when :fill-color-ref-file :fill-color-ref-file component-shape) + (d/update-when :fill-color-ref-id :fill-color-ref-id component-shape) + (d/update-when :fill-opacity :fill-opacity component-shape) + (d/update-when :font-family :font-family component-shape) + (d/update-when :font-size :font-size component-shape) + (d/update-when :font-style :font-style component-shape) + (d/update-when :font-weight :font-weight component-shape) + (d/update-when :letter-spacing :letter-spacing component-shape) + (d/update-when :line-height :line-height component-shape) + (d/update-when :proportion :proportion component-shape) + (d/update-when :rx :rx component-shape) + (d/update-when :ry :ry component-shape) + (d/update-when :cx :cx component-shape) + (d/update-when :cy :cy component-shape) + (d/update-when :x :x component-shape) + (d/update-when :y :y component-shape) + (d/update-when :exports :exports component-shape) + (d/update-when :stroke-color :stroke-color component-shape) + (d/update-when :stroke-color-ref-file :stroke-color-ref-file component-shape) + (d/update-when :stroke-color-ref-id :stroke-color-ref-id component-shape) + (d/update-when :stroke-opacity :stroke-opacity component-shape) + (d/update-when :stroke-style :stroke-style component-shape) + (d/update-when :stroke-width :stroke-width component-shape) + (d/update-when :stroke-alignment :stroke-alignment component-shape) + (d/update-when :text-align :text-align component-shape) + (d/update-when :width :width component-shape) + (d/update-when :height :height component-shape) + (d/update-when :interactions :interactions component-shape) + (d/update-when :selrect :selrect component-shape) + (d/update-when :points :points component-shape))))) + (defmethod process-operation :set [shape op] (let [attr (:attr op) diff --git a/common/app/common/pages_helpers.cljc b/common/app/common/pages_helpers.cljc index fd33cbd43c..57fbd955a2 100644 --- a/common/app/common/pages_helpers.cljc +++ b/common/app/common/pages_helpers.cljc @@ -12,6 +12,24 @@ [app.common.data :as d] [app.common.uuid :as uuid])) +(defn walk-pages + "Go through all pages of a file and apply a function to each one" + ;; The function receives two parameters (page-id and page), and + ;; returns the updated page. + [f data] + (update data :pages-index #(d/mapm f %))) + +(defn select-objects + "Get a list of all objects in a page that satisfy a condition" + [f page] + (filter f (vals (get page :objects)))) + +(defn update-object-list + "Update multiple objects in a page at once" + [page objects-list] + (update page :objects + #(into % (d/index-by :id objects-list)))) + (defn get-children "Retrieve all children ids recursively for a given object" [id objects] @@ -20,6 +38,11 @@ (d/concat shapes (mapcat #(get-children % objects) shapes)) []))) +(defn get-children-objects + "Retrieve all children objects recursively for a given object" + [id objects] + (map #(get objects %) (get-children id objects))) + (defn is-shape-grouped "Checks if a shape is inside a group" [shape-id objects] diff --git a/frontend/src/app/main/data/workspace/libraries.cljs b/frontend/src/app/main/data/workspace/libraries.cljs index 1ef240fa58..16ecdf42a3 100644 --- a/frontend/src/app/main/data/workspace/libraries.cljs +++ b/frontend/src/app/main/data/workspace/libraries.cljs @@ -142,7 +142,10 @@ :id (:id updated-shape) :operations [{:type :set :attr :component-id - :val (:component-id updated-shape)}]}) + :val (:component-id updated-shape)} + {:type :set + :attr :shape-ref + :val (:shape-ref updated-shape)}]}) updated-shapes)) uchanges (conj uchanges @@ -156,6 +159,9 @@ :id (:id updated-shape) :operations [{:type :set :attr :component-id + :val nil} + {:type :set + :attr :shape-ref :val nil}]}) updated-shapes))] @@ -174,10 +180,15 @@ (let [new-shape (assoc shape :id new-id :parent-id parent-id - :frame-id nil)] - [new-shape - [new-shape] - [(assoc shape :component-id (:id new-shape))]]) + :frame-id nil) + + new-shapes [new-shape] + + updated-shapes [(cond-> shape + true (assoc :shape-ref (:id new-shape)) + (nil? parent-id) (assoc :component-id (:id new-shape)))]] + + [new-shape new-shapes updated-shapes]) (loop [child-ids (seq (:shapes shape)) new-children [] @@ -188,11 +199,17 @@ :id new-id :parent-id parent-id :frame-id nil - :shapes (map :id new-children))] - [new-shape - (conj new-children new-shape) - (conj updated-children - (assoc shape :component-id (:id new-shape)))]) + :shapes (map :id new-children)) + + new-shapes (conj new-children new-shape) + + updated-shapes + (conj updated-children + (cond-> shape + true (assoc :shape-ref (:id new-shape)) + (nil? parent-id) (assoc :component-id (:id new-shape))))] + + [new-shape new-shapes updated-shapes]) (let [child-id (first child-ids) child (get objects child-id) @@ -213,7 +230,9 @@ (let [component (get-in state [:workspace-data :components id]) rchanges [{:type :del-component - :id id}] + :id id} + {:type :sync-library + :id (get-in state [:workspace-file :id])}] uchanges [{:type :add-component :id id