mirror of
https://github.com/penpot/penpot.git
synced 2025-02-03 21:09:00 -05:00
Merge pull request #354 from uxbox/task/732/update-subcomponent
Task/732/update subcomponent
This commit is contained in:
commit
3e14393c97
8 changed files with 504 additions and 324 deletions
|
@ -46,6 +46,7 @@
|
|||
(<= % max-safe-int)))
|
||||
(s/def ::component-id uuid?)
|
||||
(s/def ::component-file uuid?)
|
||||
(s/def ::component-root? boolean?)
|
||||
(s/def ::shape-ref uuid?)
|
||||
|
||||
(s/def ::safe-number
|
||||
|
@ -122,7 +123,6 @@
|
|||
(s/def :internal.shape/line-height ::safe-number)
|
||||
(s/def :internal.shape/locked boolean?)
|
||||
(s/def :internal.shape/page-id uuid?)
|
||||
(s/def :internal.shape/component-id uuid?)
|
||||
(s/def :internal.shape/proportion ::safe-number)
|
||||
(s/def :internal.shape/proportion-lock boolean?)
|
||||
(s/def :internal.shape/rx ::safe-number)
|
||||
|
@ -236,12 +236,8 @@
|
|||
:width :size-group
|
||||
:height :size-group
|
||||
:proportion :size-group
|
||||
:x :position-group
|
||||
:y :position-group
|
||||
:rx :radius-group
|
||||
:ry :radius-group
|
||||
:points :points-group
|
||||
:transform :transform-group})
|
||||
:ry :radius-group})
|
||||
|
||||
(def color-sync-attrs [:fill-color
|
||||
:stroke-color])
|
||||
|
@ -255,6 +251,7 @@
|
|||
(s/keys :opt-un [::id
|
||||
::component-id
|
||||
::component-file
|
||||
::component-root?
|
||||
::shape-ref])))
|
||||
|
||||
(s/def :internal.page/objects (s/map-of uuid? ::shape))
|
||||
|
@ -891,21 +888,21 @@
|
|||
|
||||
(defmethod process-operation :set
|
||||
[shape op]
|
||||
(let [attr (:attr op)
|
||||
val (:val op)
|
||||
ignore (:ignore-touched op)
|
||||
(let [attr (:attr op)
|
||||
val (:val op)
|
||||
ignore (:ignore-touched op)
|
||||
shape-ref (:shape-ref shape)
|
||||
group (get component-sync-attrs attr)]
|
||||
group (get component-sync-attrs attr)]
|
||||
|
||||
(cond-> shape
|
||||
(and shape-ref group (not ignore) (not= val (get shape attr)))
|
||||
(update :touched #(conj (or % #{}) group))
|
||||
|
||||
(nil? val)
|
||||
(dissoc attr)
|
||||
|
||||
(some? val)
|
||||
(assoc attr val)
|
||||
|
||||
(and shape-ref group (not ignore))
|
||||
(update :touched #(conj (or % #{}) group)))))
|
||||
(assoc attr val))))
|
||||
|
||||
(defmethod process-operation :set-touched
|
||||
[shape op]
|
||||
|
|
|
@ -31,15 +31,15 @@
|
|||
(update page :objects
|
||||
#(into % (d/index-by :id objects-list))))
|
||||
|
||||
(defn get-root-component
|
||||
"Get the root shape linked to the component for this shape, if any"
|
||||
[id objects]
|
||||
(let [obj (get objects id)]
|
||||
(if-let [component-id (:component-id obj)]
|
||||
id
|
||||
(if-let [parent-id (:parent-id obj)]
|
||||
(get-root-component parent-id objects)
|
||||
nil))))
|
||||
(defn get-root-shape
|
||||
"Get the root shape linked to a component for this shape, if any"
|
||||
[shape objects]
|
||||
(if (:component-root? shape)
|
||||
shape
|
||||
(if-let [parent-id (:parent-id shape)]
|
||||
(get-root-shape (get objects (:parent-id shape))
|
||||
objects)
|
||||
nil)))
|
||||
|
||||
(defn get-children
|
||||
"Retrieve all children ids recursively for a given object"
|
||||
|
@ -58,7 +58,7 @@
|
|||
(defn get-object-with-children
|
||||
"Retrieve a list with an object and all of its children"
|
||||
[id objects]
|
||||
(map #(get objects %) (concat [id] (get-children id objects))))
|
||||
(map #(get objects %) (cons id (get-children id objects))))
|
||||
|
||||
(defn is-shape-grouped
|
||||
"Checks if a shape is inside a group"
|
||||
|
|
|
@ -1148,12 +1148,9 @@
|
|||
(update [_ state]
|
||||
(let [page-id (:current-page-id state)
|
||||
objects (dwc/lookup-page-objects state page-id)
|
||||
root-id (cph/get-root-component (:id shape) objects)
|
||||
root-shape (get objects root-id)
|
||||
|
||||
mdata {:position position
|
||||
:shape shape
|
||||
:root-shape root-shape
|
||||
:selected (get-in state [:workspace-local :selected])}]
|
||||
(-> state
|
||||
(assoc-in [:workspace-local :context-menu] mdata))))
|
||||
|
|
|
@ -155,9 +155,15 @@
|
|||
{:type :set
|
||||
:attr :component-file
|
||||
:val nil}
|
||||
{:type :set
|
||||
:attr :component-root?
|
||||
:val (:component-root? updated-shape)}
|
||||
{:type :set
|
||||
:attr :shape-ref
|
||||
:val (:shape-ref updated-shape)}]})
|
||||
:val (:shape-ref updated-shape)}
|
||||
{:type :set
|
||||
:attr :touched
|
||||
:val (:touched updated-shape)}]})
|
||||
updated-shapes))
|
||||
|
||||
uchanges (conj uchanges
|
||||
|
@ -176,11 +182,18 @@
|
|||
{:type :set
|
||||
:attr :component-file
|
||||
:val (:component-file original-shape)}
|
||||
{:type :set
|
||||
:attr :component-root?
|
||||
:val (:component-root? original-shape)}
|
||||
{:type :set
|
||||
:attr :shape-ref
|
||||
:val (:shape-ref original-shape)}]}))
|
||||
:val (:shape-ref original-shape)}
|
||||
{:type :set
|
||||
:attr :touched
|
||||
:val (:touched original-shape)}]}))
|
||||
updated-shapes))]
|
||||
|
||||
|
||||
(rx/of (dwc/commit-changes rchanges uchanges {:commit-local? true})
|
||||
(dws/select-shapes (d/ordered-set (:id group))))))))))
|
||||
|
||||
|
@ -239,10 +252,12 @@
|
|||
(dwc/calculate-frame-overlap all-frames $))
|
||||
(assoc $ :parent-id
|
||||
(or (:parent-id $) (:frame-id $)))
|
||||
(assoc $ :shape-ref (:id original-shape)))
|
||||
(assoc $ :shape-ref (:id original-shape))
|
||||
(dissoc $ :touched))
|
||||
|
||||
(nil? (:parent-id original-shape))
|
||||
(assoc :component-id (:id original-shape))
|
||||
(assoc :component-id (:id original-shape)
|
||||
:component-root? true)
|
||||
|
||||
(and (nil? (:parent-id original-shape)) (some? file-id))
|
||||
(assoc :component-file file-id)
|
||||
|
@ -251,7 +266,7 @@
|
|||
(dissoc :component-file)
|
||||
|
||||
(some? (:parent-id original-shape))
|
||||
(dissoc :component-id :component-file))))
|
||||
(dissoc :component-root?))))
|
||||
|
||||
[new-shape new-shapes _]
|
||||
(cph/clone-object component-shape
|
||||
|
@ -285,9 +300,7 @@
|
|||
(watch [_ state stream]
|
||||
(let [page-id (:current-page-id state)
|
||||
objects (dwc/lookup-page-objects state page-id)
|
||||
root-id (cph/get-root-component id objects)
|
||||
|
||||
shapes (cph/get-object-with-children root-id objects)
|
||||
shapes (cph/get-object-with-children id objects)
|
||||
|
||||
rchanges (map (fn [obj]
|
||||
{:type :mod-obj
|
||||
|
@ -351,26 +364,38 @@
|
|||
(ptk/reify ::reset-component
|
||||
ptk/WatchEvent
|
||||
(watch [_ state stream]
|
||||
(let [page-id (:current-page-id state)
|
||||
page (get-in state [:workspace-data :pages-index page-id])
|
||||
objects (dwc/lookup-page-objects state page-id)
|
||||
root-id (cph/get-root-component id objects)
|
||||
root-shape (get objects id)
|
||||
file-id (get root-shape :component-file)
|
||||
;; ===== Uncomment this to debug =====
|
||||
;; (js/console.info "##### RESET-COMPONENT of shape" (str id))
|
||||
(let [page-id (:current-page-id state)
|
||||
page (get-in state [:workspace-data :pages-index page-id])
|
||||
objects (dwc/lookup-page-objects state page-id)
|
||||
shape (get objects id)
|
||||
file-id (get shape :component-file)
|
||||
|
||||
components
|
||||
(if (nil? file-id)
|
||||
(get-in state [:workspace-data :components])
|
||||
(get-in state [:workspace-libraries file-id :data :components]))
|
||||
[all-shapes component root-component]
|
||||
(dwlh/resolve-shapes-and-components shape
|
||||
objects
|
||||
state
|
||||
true)
|
||||
|
||||
;; ===== Uncomment this to debug =====
|
||||
;; _ (js/console.info "shape" (:name shape) "<- component" (:name component))
|
||||
;; _ (js/console.debug "all-shapes" (clj->js all-shapes))
|
||||
;; _ (js/console.debug "component" (clj->js component))
|
||||
;; _ (js/console.debug "root-component" (clj->js root-component))
|
||||
|
||||
[rchanges uchanges]
|
||||
(dwlh/generate-sync-shape-and-children-components root-shape
|
||||
objects
|
||||
components
|
||||
(dwlh/generate-sync-shape-and-children-components shape
|
||||
all-shapes
|
||||
component
|
||||
root-component
|
||||
(:id page)
|
||||
nil
|
||||
true)]
|
||||
|
||||
;; ===== Uncomment this to debug =====
|
||||
;; (js/console.debug "rchanges" (clj->js rchanges))
|
||||
|
||||
(rx/of (dwc/commit-changes rchanges uchanges {:commit-local? true}))))))
|
||||
|
||||
(defn update-component
|
||||
|
@ -379,60 +404,34 @@
|
|||
(ptk/reify ::update-component
|
||||
ptk/WatchEvent
|
||||
(watch [_ state stream]
|
||||
(let [page-id (:current-page-id state)
|
||||
objects (dwc/lookup-page-objects state page-id)
|
||||
root-id (cph/get-root-component id objects)
|
||||
root-shape (get objects id)
|
||||
;; ===== Uncomment this to debug =====
|
||||
;; (js/console.info "##### UPDATE-COMPONENT of shape" (str id))
|
||||
(let [page-id (:current-page-id state)
|
||||
objects (dwc/lookup-page-objects state page-id)
|
||||
shape (get objects id)
|
||||
file-id (get shape :component-file)
|
||||
|
||||
component-id (get root-shape :component-id)
|
||||
component-objs (dwc/lookup-component-objects state component-id)
|
||||
component-obj (get component-objs component-id)
|
||||
[all-shapes component root-component]
|
||||
(dwlh/resolve-shapes-and-components shape
|
||||
objects
|
||||
state
|
||||
true)
|
||||
|
||||
;; Clone again the original shape and its children, maintaing
|
||||
;; the ids of the cloned shapes. If the original shape has some
|
||||
;; new child shapes, the cloned ones will have new generated ids.
|
||||
update-new-shape (fn [new-shape original-shape]
|
||||
(cond-> new-shape
|
||||
true
|
||||
(assoc :frame-id nil)
|
||||
;; ===== Uncomment this to debug =====
|
||||
;; _ (js/console.info "shape" (:name shape) "-> component" (:name component))
|
||||
;; _ (js/console.debug "all-shapes" (clj->js all-shapes))
|
||||
;; _ (js/console.debug "component" (clj->js component))
|
||||
;; _ (js/console.debug "root-component" (clj->js root-component))
|
||||
|
||||
(= (:component-id original-shape) component-id)
|
||||
(dissoc :component-id)
|
||||
[rchanges uchanges]
|
||||
(dwlh/generate-sync-shape-inverse shape
|
||||
all-shapes
|
||||
component
|
||||
root-component
|
||||
page-id)]
|
||||
|
||||
(some? (:shape-ref original-shape))
|
||||
(assoc :id (:shape-ref original-shape))))
|
||||
|
||||
touch-shape (fn [original-shape _]
|
||||
(into {} original-shape))
|
||||
|
||||
[new-shape new-shapes original-shapes]
|
||||
(cph/clone-object root-shape nil objects update-new-shape touch-shape)
|
||||
|
||||
rchanges (d/concat
|
||||
[{:type :mod-component
|
||||
:id component-id
|
||||
:name (:name new-shape)
|
||||
:shapes new-shapes}]
|
||||
(map (fn [shape]
|
||||
{:type :mod-obj
|
||||
:page-id page-id
|
||||
:id (:id shape)
|
||||
:operations [{:type :set-touched
|
||||
:touched nil}]})
|
||||
original-shapes))
|
||||
|
||||
uchanges (d/concat
|
||||
[{:type :mod-component
|
||||
:id component-id
|
||||
:name (:name component-obj)
|
||||
:shapes (vals component-objs)}]
|
||||
(map (fn [shape]
|
||||
{:type :mod-obj
|
||||
:page-id page-id
|
||||
:id (:id shape)
|
||||
:operations [{:type :set-touched
|
||||
:touched (:touched shape)}]})
|
||||
original-shapes))]
|
||||
;; ===== Uncomment this to debug =====
|
||||
;; (js/console.debug "rchanges" (clj->js rchanges))
|
||||
|
||||
(rx/of (dwc/commit-changes rchanges uchanges {:commit-local? true}))))))
|
||||
|
||||
|
@ -450,6 +449,8 @@
|
|||
|
||||
ptk/WatchEvent
|
||||
(watch [_ state stream]
|
||||
;; ===== Uncomment this to debug =====
|
||||
;; (js/console.info "##### SYNC-FILE" (str (or file-id "local")))
|
||||
(let [[rchanges1 uchanges1] (dwlh/generate-sync-file :components file-id state)
|
||||
[rchanges2 uchanges2] (dwlh/generate-sync-library :components file-id state)
|
||||
[rchanges3 uchanges3] (dwlh/generate-sync-file :colors file-id state)
|
||||
|
@ -458,6 +459,8 @@
|
|||
[rchanges6 uchanges6] (dwlh/generate-sync-library :typographies file-id state)
|
||||
rchanges (d/concat rchanges1 rchanges2 rchanges3 rchanges4 rchanges5 rchanges6)
|
||||
uchanges (d/concat uchanges1 uchanges2 uchanges3 uchanges4 uchanges5 uchanges6)]
|
||||
;; ===== Uncomment this to debug =====
|
||||
;; (js/console.debug "rchanges" (clj->js rchanges))
|
||||
(rx/concat
|
||||
(rx/of (dm/hide-tag :sync-dialog))
|
||||
(when rchanges
|
||||
|
@ -483,8 +486,15 @@
|
|||
(ptk/reify ::sync-file-2nd-stage
|
||||
ptk/WatchEvent
|
||||
(watch [_ state stream]
|
||||
(let [[rchanges uchanges] (dwlh/generate-sync-file :components nil state)]
|
||||
;; ===== Uncomment this to debug =====
|
||||
;; (js/console.info "##### SYNC-FILE" (str (or file-id "local")) "(2nd stage)")
|
||||
(let [[rchanges1 uchanges1] (dwlh/generate-sync-file :components nil state)
|
||||
[rchanges2 uchanges2] (dwlh/generate-sync-library :components file-id state)
|
||||
rchanges (d/concat rchanges1 rchanges2)
|
||||
uchanges (d/concat uchanges1 uchanges2)]
|
||||
(when rchanges
|
||||
;; ===== Uncomment this to debug =====
|
||||
;; (js/console.debug "rchanges" (clj->js rchanges))
|
||||
(rx/of (dwc/commit-changes rchanges uchanges {:commit-local? true})))))))
|
||||
|
||||
(def ignore-sync
|
||||
|
|
|
@ -21,15 +21,62 @@
|
|||
|
||||
(declare generate-sync-container)
|
||||
(declare generate-sync-shape)
|
||||
(declare has-asset-reference-fn)
|
||||
|
||||
(declare generate-sync-component-components)
|
||||
(declare get-assets)
|
||||
(declare resolve-shapes-and-components)
|
||||
(declare generate-sync-shape-and-children-components)
|
||||
(declare generate-sync-shape-components)
|
||||
(declare generate-sync-shape-inverse)
|
||||
(declare generate-sync-shape<-component)
|
||||
(declare generate-sync-shape->component)
|
||||
(declare remove-component-and-ref)
|
||||
(declare remove-ref)
|
||||
(declare reset-touched)
|
||||
(declare update-attrs)
|
||||
(declare calc-new-pos)
|
||||
|
||||
|
||||
;; ---- Create a new component ----
|
||||
|
||||
(defn make-component-shape
|
||||
"Clone the shape and all children. Generate new ids and detach
|
||||
from parent and frame. Update the original shapes to have links
|
||||
to the new ones."
|
||||
[shape objects]
|
||||
(assert (nil? (:component-id shape)))
|
||||
(assert (nil? (:component-file shape)))
|
||||
(assert (nil? (:shape-ref shape)))
|
||||
(let [update-new-shape (fn [new-shape original-shape]
|
||||
(cond-> new-shape
|
||||
true
|
||||
(assoc :frame-id nil)
|
||||
|
||||
(nil? (:parent-id new-shape))
|
||||
(dissoc :component-id
|
||||
:component-file
|
||||
:component-root?
|
||||
:shape-ref)))
|
||||
|
||||
;; Make the original shape an instance of the new component.
|
||||
;; If one of the original shape children already was a component
|
||||
;; instance, the 'instanceness' is copied into the new component.
|
||||
update-original-shape (fn [original-shape new-shape]
|
||||
(cond-> original-shape
|
||||
true
|
||||
(-> (assoc :shape-ref (:id new-shape))
|
||||
(dissoc :touched))
|
||||
|
||||
(nil? (:parent-id new-shape))
|
||||
(assoc :component-id (:id new-shape)
|
||||
:component-file nil
|
||||
:component-root? true)
|
||||
|
||||
(some? (:parent-id new-shape))
|
||||
(dissoc :component-root?)))]
|
||||
|
||||
(cph/clone-object shape nil objects update-new-shape update-original-shape)))
|
||||
|
||||
|
||||
;; ---- General library synchronization functions ----
|
||||
|
||||
(defn generate-sync-file
|
||||
|
@ -55,7 +102,7 @@
|
|||
(let [[page-rchanges page-uchanges]
|
||||
(generate-sync-container asset-type
|
||||
library-id
|
||||
library-items
|
||||
state
|
||||
page
|
||||
(:id page)
|
||||
nil)]
|
||||
|
@ -82,7 +129,7 @@
|
|||
(let [[comp-rchanges comp-uchanges]
|
||||
(generate-sync-container asset-type
|
||||
library-id
|
||||
library-items
|
||||
state
|
||||
local-component
|
||||
nil
|
||||
(:id local-component))]
|
||||
|
@ -91,13 +138,36 @@
|
|||
(d/concat uchanges comp-uchanges)))
|
||||
[rchanges uchanges])))))
|
||||
|
||||
(defn has-asset-reference-fn
|
||||
(defn- generate-sync-container
|
||||
"Generate changes to synchronize all shapes in a particular container
|
||||
(a page or a component) that are linked to the given library."
|
||||
[asset-type library-id state container page-id component-id]
|
||||
(let [has-asset-reference? (has-asset-reference-fn asset-type library-id)
|
||||
linked-shapes (cph/select-objects has-asset-reference? container)]
|
||||
(loop [shapes (seq linked-shapes)
|
||||
rchanges []
|
||||
uchanges []]
|
||||
(if-let [shape (first shapes)]
|
||||
(let [[shape-rchanges shape-uchanges]
|
||||
(generate-sync-shape asset-type
|
||||
library-id
|
||||
state
|
||||
(get container :objects)
|
||||
page-id
|
||||
component-id
|
||||
shape)]
|
||||
(recur (next shapes)
|
||||
(d/concat rchanges shape-rchanges)
|
||||
(d/concat uchanges shape-uchanges)))
|
||||
[rchanges uchanges]))))
|
||||
|
||||
(defn- has-asset-reference-fn
|
||||
"Gets a function that checks if a shape uses some asset of the given type
|
||||
in the given library."
|
||||
[asset-type library-id]
|
||||
(case asset-type
|
||||
:components
|
||||
(fn [shape] (and (some? (:component-id shape))
|
||||
(fn [shape] (and (:component-root? shape)
|
||||
(= (:component-file shape) library-id)))
|
||||
|
||||
:colors
|
||||
|
@ -126,50 +196,28 @@
|
|||
#(and (some? (:typography-ref-id %))
|
||||
(= library-id (:typography-ref-file %)))))))))
|
||||
|
||||
(defn generate-sync-container
|
||||
"Generate changes to synchronize all shapes in a particular container
|
||||
(a page or a component)."
|
||||
[asset-type library-id library-items container page-id component-id]
|
||||
(let [has-asset-reference? (has-asset-reference-fn asset-type library-id)
|
||||
linked-shapes (cph/select-objects has-asset-reference? container)]
|
||||
(loop [shapes (seq linked-shapes)
|
||||
rchanges []
|
||||
uchanges []]
|
||||
(if-let [shape (first shapes)]
|
||||
(let [[shape-rchanges shape-uchanges]
|
||||
(generate-sync-shape asset-type
|
||||
library-id
|
||||
library-items
|
||||
(get container :objects)
|
||||
page-id
|
||||
component-id
|
||||
shape)]
|
||||
(recur (next shapes)
|
||||
(d/concat rchanges shape-rchanges)
|
||||
(d/concat uchanges shape-uchanges)))
|
||||
[rchanges uchanges]))))
|
||||
|
||||
(defmulti generate-sync-shape (fn [type _ _ _ _ _ _ _] type))
|
||||
(defmulti generate-sync-shape
|
||||
"Generate changes to synchronize one shape, that use the given type
|
||||
of asset of the given library."
|
||||
(fn [type _ _ _ _ _ _ _] type))
|
||||
|
||||
(defmethod generate-sync-shape :components
|
||||
[_ library-id library-items objects page-id component-id shape]
|
||||
[_ library-id state objects page-id component-id shape]
|
||||
(let [[all-shapes component root-component]
|
||||
(resolve-shapes-and-components shape
|
||||
objects
|
||||
state
|
||||
false)]
|
||||
|
||||
;; Synchronize a shape that is the root instance of a component, and all of its
|
||||
;; children. All attributes of the component shape that have changed, and whose
|
||||
;; group have not been touched in the linked shape, will be copied to the shape.
|
||||
;; Any shape that is linked to a no-longer existent component shape will be
|
||||
;; detached.
|
||||
(let [root-shape shape
|
||||
components library-items
|
||||
reset-touched? false]
|
||||
(generate-sync-shape-and-children-components root-shape
|
||||
objects
|
||||
components
|
||||
(generate-sync-shape-and-children-components shape
|
||||
all-shapes
|
||||
component
|
||||
root-component
|
||||
page-id
|
||||
component-id
|
||||
reset-touched?)))
|
||||
false)))
|
||||
|
||||
(defn generate-sync-text-shape [shape page-id component-id update-node]
|
||||
(defn- generate-sync-text-shape [shape page-id component-id update-node]
|
||||
(let [old-content (:content shape)
|
||||
new-content (ut/map-node update-node old-content)
|
||||
rchanges [(d/without-nils {:type :mod-obj
|
||||
|
@ -191,128 +239,170 @@
|
|||
[rchanges lchanges])))
|
||||
|
||||
(defmethod generate-sync-shape :colors
|
||||
[_ library-id library-items _ page-id component-id shape]
|
||||
[_ library-id state _ page-id component-id shape]
|
||||
|
||||
;; Synchronize a shape that uses some colors of the library. The value of the
|
||||
;; color in the library is copied to the shape.
|
||||
(if (= :text (:type shape))
|
||||
(let [update-node (fn [node]
|
||||
(if-let [color (get library-items (:fill-color-ref-id node))]
|
||||
(assoc node :fill-color (:value color))
|
||||
node))]
|
||||
(generate-sync-text-shape shape page-id component-id update-node))
|
||||
(loop [attrs (seq cp/color-sync-attrs)
|
||||
roperations []
|
||||
uoperations []]
|
||||
(let [attr (first attrs)]
|
||||
(if (nil? attr)
|
||||
(if (empty? roperations)
|
||||
empty-changes
|
||||
(let [rchanges [(d/without-nils {:type :mod-obj
|
||||
:page-id page-id
|
||||
:component-id component-id
|
||||
:id (:id shape)
|
||||
:operations roperations})]
|
||||
uchanges [(d/without-nils {:type :mod-obj
|
||||
:page-id page-id
|
||||
:component-id component-id
|
||||
:id (:id shape)
|
||||
:operations uoperations})]]
|
||||
[rchanges uchanges]))
|
||||
(let [attr-ref-id (keyword (str (name attr) "-ref-id"))]
|
||||
(if-not (contains? shape attr-ref-id)
|
||||
(recur (next attrs)
|
||||
roperations
|
||||
uoperations)
|
||||
(let [color (get library-items (get shape attr-ref-id))
|
||||
roperation {:type :set
|
||||
:attr attr
|
||||
:val (:value color)
|
||||
:ignore-touched true}
|
||||
uoperation {:type :set
|
||||
:attr attr
|
||||
:val (get shape attr)
|
||||
:ignore-touched true}]
|
||||
(let [colors (get-assets library-id :colors state)]
|
||||
(if (= :text (:type shape))
|
||||
(let [update-node (fn [node]
|
||||
(if-let [color (get colors (:fill-color-ref-id node))]
|
||||
(assoc node :fill-color (:value color))
|
||||
node))]
|
||||
(generate-sync-text-shape shape page-id component-id update-node))
|
||||
(loop [attrs (seq cp/color-sync-attrs)
|
||||
roperations []
|
||||
uoperations []]
|
||||
(let [attr (first attrs)]
|
||||
(if (nil? attr)
|
||||
(if (empty? roperations)
|
||||
empty-changes
|
||||
(let [rchanges [(d/without-nils {:type :mod-obj
|
||||
:page-id page-id
|
||||
:component-id component-id
|
||||
:id (:id shape)
|
||||
:operations roperations})]
|
||||
uchanges [(d/without-nils {:type :mod-obj
|
||||
:page-id page-id
|
||||
:component-id component-id
|
||||
:id (:id shape)
|
||||
:operations uoperations})]]
|
||||
[rchanges uchanges]))
|
||||
(let [attr-ref-id (keyword (str (name attr) "-ref-id"))]
|
||||
(if-not (contains? shape attr-ref-id)
|
||||
(recur (next attrs)
|
||||
(conj roperations roperation)
|
||||
(conj uoperations uoperation))))))))))
|
||||
roperations
|
||||
uoperations)
|
||||
(let [color (get colors (get shape attr-ref-id))
|
||||
roperation {:type :set
|
||||
:attr attr
|
||||
:val (:value color)
|
||||
:ignore-touched true}
|
||||
uoperation {:type :set
|
||||
:attr attr
|
||||
:val (get shape attr)
|
||||
:ignore-touched true}]
|
||||
(recur (next attrs)
|
||||
(conj roperations roperation)
|
||||
(conj uoperations uoperation)))))))))))
|
||||
|
||||
(defmethod generate-sync-shape :typographies
|
||||
[_ library-id library-items _ page-id component-id shape]
|
||||
[_ library-id state _ page-id component-id shape]
|
||||
|
||||
;; Synchronize a shape that uses some typographies of the library. The attributes
|
||||
;; of the typography are copied to the shape."
|
||||
(let [update-node (fn [node]
|
||||
(if-let [typography (get library-items (:typography-ref-id node))]
|
||||
(let [typographies (get-assets library-id :typographies state)
|
||||
update-node (fn [node]
|
||||
(if-let [typography (get typographies (:typography-ref-id node))]
|
||||
(merge node (d/without-keys typography [:name :id]))
|
||||
node))]
|
||||
(generate-sync-text-shape shape page-id component-id update-node)))
|
||||
|
||||
|
||||
;; ---- Create a new component ----
|
||||
|
||||
(defn make-component-shape
|
||||
"Clone the shape and all children. Generate new ids and detach
|
||||
from parent and frame. Update the original shapes to have links
|
||||
to the new ones."
|
||||
[shape objects]
|
||||
(let [update-new-shape (fn [new-shape original-shape]
|
||||
(assoc new-shape :frame-id nil))
|
||||
|
||||
;; If one of the original shape children already was a component
|
||||
;; instance, the 'instanceness' is copied into the new component,
|
||||
;; and the original shape now points to the new component.
|
||||
update-original-shape (fn [original-shape new-shape]
|
||||
(cond-> original-shape
|
||||
true
|
||||
(assoc :shape-ref (:id new-shape))
|
||||
|
||||
(nil? (:parent-id new-shape))
|
||||
(assoc :component-id (:id new-shape)
|
||||
:component-file nil)
|
||||
|
||||
(some? (:parent-id new-shape))
|
||||
(assoc :component-id nil
|
||||
:component-file nil)))]
|
||||
|
||||
(cph/clone-object shape nil objects update-new-shape update-original-shape)))
|
||||
|
||||
|
||||
;; ---- Component synchronization helpers ----
|
||||
|
||||
(defn generate-sync-shape-and-children-components
|
||||
"Generate changes to synchronize one shape that is linked to a component,
|
||||
and all its children. If reset-touched? is false, same considerations as
|
||||
in generate-sync-shape :components. If it's true, all attributes of the
|
||||
component that have changed will be copied, and the 'touched' flags in
|
||||
the shapes will be cleared."
|
||||
[root-shape objects components page-id component-id reset-touched?]
|
||||
(let [all-shapes (cph/get-object-with-children (:id root-shape) objects)
|
||||
component (get components (:component-id root-shape))
|
||||
root-component (get-in component [:objects (:shape-ref root-shape)])]
|
||||
(loop [shapes (seq all-shapes)
|
||||
rchanges []
|
||||
uchanges []]
|
||||
(let [shape (first shapes)]
|
||||
(if (nil? shape)
|
||||
[rchanges uchanges]
|
||||
(let [[shape-rchanges shape-uchanges]
|
||||
(generate-sync-shape-components
|
||||
shape
|
||||
root-shape
|
||||
root-component
|
||||
component
|
||||
page-id
|
||||
component-id
|
||||
reset-touched?)]
|
||||
(recur (next shapes)
|
||||
(d/concat rchanges shape-rchanges)
|
||||
(d/concat uchanges shape-uchanges))))))))
|
||||
(defn- get-assets
|
||||
[library-id asset-type state]
|
||||
(if (nil? library-id)
|
||||
(get-in state [:workspace-data asset-type])
|
||||
(get-in state [:workspace-libraries library-id :data asset-type])))
|
||||
|
||||
(defn generate-sync-shape-components
|
||||
(defn- get-component
|
||||
[state file-id component-id]
|
||||
(let [components (if (nil? file-id)
|
||||
(get-in state [:workspace-data :components])
|
||||
(get-in state [:workspace-libraries file-id :data :components]))]
|
||||
(get components component-id)))
|
||||
|
||||
(defn resolve-shapes-and-components
|
||||
"Get all shapes inside a component instance, and the component they are
|
||||
linked with. If follow-indirection? is true, and the shape corresponding
|
||||
to the root shape is also a component instance, follow the link and get
|
||||
the final component."
|
||||
[shape objects state follow-indirection?]
|
||||
(loop [all-shapes (cph/get-object-with-children (:id shape) objects)
|
||||
local-objects objects
|
||||
local-shape shape]
|
||||
|
||||
(let [root-shape (cph/get-root-shape local-shape local-objects)
|
||||
component (get-component state
|
||||
(get root-shape :component-file)
|
||||
(get root-shape :component-id))
|
||||
component-shape (get-in component [:objects (:shape-ref local-shape)])]
|
||||
|
||||
(if (or (nil? (:component-id component-shape))
|
||||
(not follow-indirection?))
|
||||
[all-shapes component component-shape]
|
||||
(let [resolve-indirection
|
||||
(fn [shape]
|
||||
(let [component-shape (get-in component [:objects (:shape-ref shape)])]
|
||||
(-> shape
|
||||
(assoc :shape-ref (:shape-ref component-shape))
|
||||
(d/assoc-when :component-id (:component-id component-shape))
|
||||
(d/assoc-when :component-file (:component-file component-shape)))))
|
||||
new-shapes (map resolve-indirection all-shapes)]
|
||||
(recur new-shapes
|
||||
(:objects component)
|
||||
component-shape))))))
|
||||
|
||||
(defn generate-sync-shape-and-children-components
|
||||
"Generate changes to synchronize one shape that the root of a component
|
||||
instance, and all its children, from the given component.
|
||||
If reset? is false, all atributes of each component shape that have
|
||||
changed, and whose group has not been touched in the instance shape will
|
||||
be copied to this one.
|
||||
If reset? is true, all changed attributes will be copied and the 'touched'
|
||||
flags in the instance shape will be cleared."
|
||||
[root-shape all-shapes component root-component page-id component-id reset?]
|
||||
(loop [shapes (seq all-shapes)
|
||||
rchanges []
|
||||
uchanges []]
|
||||
(let [shape (first shapes)]
|
||||
(if (nil? shape)
|
||||
[rchanges uchanges]
|
||||
(let [[shape-rchanges shape-uchanges]
|
||||
(generate-sync-shape<-component
|
||||
shape
|
||||
root-shape
|
||||
root-component
|
||||
component
|
||||
page-id
|
||||
component-id
|
||||
reset?)]
|
||||
(recur (next shapes)
|
||||
(d/concat rchanges shape-rchanges)
|
||||
(d/concat uchanges shape-uchanges)))))))
|
||||
|
||||
(defn- generate-sync-shape-inverse
|
||||
"Generate changes to update the component a shape is linked to, from
|
||||
the values in the shape and all its children.
|
||||
All atributes of each instance shape that have changed, will be copied
|
||||
to the component shape. Also clears the 'touched' flags in the source
|
||||
shapes.
|
||||
And if the component shapes are, in turn, instances of a second component,
|
||||
their 'touched' flags will be set accordingly."
|
||||
[root-shape all-shapes component root-component page-id]
|
||||
(loop [shapes (seq all-shapes)
|
||||
rchanges []
|
||||
uchanges []]
|
||||
(let [shape (first shapes)]
|
||||
(if (nil? shape)
|
||||
[rchanges uchanges]
|
||||
(let [[shape-rchanges shape-uchanges]
|
||||
(generate-sync-shape->component
|
||||
shape
|
||||
root-shape
|
||||
root-component
|
||||
component
|
||||
page-id)]
|
||||
(recur (next shapes)
|
||||
(d/concat rchanges shape-rchanges)
|
||||
(d/concat uchanges shape-uchanges)))))))
|
||||
|
||||
(defn- generate-sync-shape<-component
|
||||
"Generate changes to synchronize one shape that is linked to other shape
|
||||
inside a component. Same considerations as above about reset-touched?"
|
||||
[shape root-shape root-component component page-id component-id reset-touched?]
|
||||
[shape root-shape root-component component page-id component-id reset?]
|
||||
(if (nil? component)
|
||||
(remove-component-and-ref shape page-id component-id)
|
||||
(let [component-shape (get (:objects component) (:shape-ref shape))]
|
||||
|
@ -324,15 +414,55 @@
|
|||
root-component
|
||||
page-id
|
||||
component-id
|
||||
reset-touched?)))))
|
||||
{:omit-touched? (not reset?)
|
||||
:reset-touched? reset?
|
||||
:set-touched? false})))))
|
||||
|
||||
(defn remove-component-and-ref
|
||||
(defn- generate-sync-shape->component
|
||||
"Generate changes to synchronize one shape inside a component, with other
|
||||
shape that is linked to it."
|
||||
[shape root-shape root-component component page-id]
|
||||
;; ===== Uncomment this to debug =====
|
||||
;; (js/console.log "component" (clj->js component))
|
||||
(if (nil? component)
|
||||
empty-changes
|
||||
(let [component-shape (get (:objects component) (:shape-ref shape))]
|
||||
;; ===== Uncomment this to debug =====
|
||||
;; (js/console.log "component-shape" (clj->js component-shape))
|
||||
(if (nil? component-shape)
|
||||
empty-changes
|
||||
(let [;; ===== Uncomment this to debug =====
|
||||
;; _(js/console.info "update" (:name shape) "->" (:name component-shape))
|
||||
[rchanges1 uchanges1]
|
||||
(update-attrs component-shape
|
||||
shape
|
||||
root-component
|
||||
root-shape
|
||||
nil
|
||||
(:id root-component)
|
||||
{:omit-touched? false
|
||||
:reset-touched? false
|
||||
:set-touched? true})
|
||||
[rchanges2 uchanges2]
|
||||
(reset-touched shape
|
||||
page-id
|
||||
nil)]
|
||||
[(d/concat rchanges1 rchanges2)
|
||||
(d/concat uchanges2 uchanges2)])))))
|
||||
|
||||
|
||||
; ---- Operation generation helpers ----
|
||||
|
||||
(defn- remove-component-and-ref
|
||||
[shape page-id component-id]
|
||||
[[(d/without-nils {:type :mod-obj
|
||||
:id (:id shape)
|
||||
:page-id page-id
|
||||
:component-id component-id
|
||||
:operations [{:type :set
|
||||
:attr :component-root?
|
||||
:val nil}
|
||||
{:type :set
|
||||
:attr :component-id
|
||||
:val nil}
|
||||
{:type :set
|
||||
|
@ -348,6 +478,9 @@
|
|||
:page-id page-id
|
||||
:component-id component-id
|
||||
:operations [{:type :set
|
||||
:attr :component-root?
|
||||
:val (:component-root? shape)}
|
||||
{:type :set
|
||||
:attr :component-id
|
||||
:val (:component-id shape)}
|
||||
{:type :set
|
||||
|
@ -359,7 +492,7 @@
|
|||
{:type :set-touched
|
||||
:touched (:touched shape)}]})]])
|
||||
|
||||
(defn remove-ref
|
||||
(defn- -remove-ref
|
||||
[shape page-id component-id]
|
||||
[[(d/without-nils {:type :mod-obj
|
||||
:id (:id shape)
|
||||
|
@ -380,32 +513,57 @@
|
|||
{:type :set-touched
|
||||
:touched (:touched shape)}]})]])
|
||||
|
||||
(defn update-attrs
|
||||
"The main function that implements the sync algorithm."
|
||||
[shape component-shape root-shape root-component page-id component-id reset-touched?]
|
||||
(defn- reset-touched
|
||||
[shape page-id component-id]
|
||||
[[(d/without-nils {:type :mod-obj
|
||||
:id (:id shape)
|
||||
:page-id page-id
|
||||
:component-id component-id
|
||||
:operations [{:type :set-touched
|
||||
:touched nil}]})]
|
||||
[(d/without-nils {:type :mod-obj
|
||||
:id (:id shape)
|
||||
:page-id page-id
|
||||
:component-id component-id
|
||||
:operations [{:type :set-touched
|
||||
:touched (:touched shape)}]})]])
|
||||
|
||||
(defn- update-attrs
|
||||
"The main function that implements the sync algorithm. Copy
|
||||
attributes that have changed in the origin shape to the dest shape.
|
||||
If omit-touched? is true, attributes whose group has been touched
|
||||
in the destination shape will be ignored.
|
||||
If reset-touched? is true, the 'touched' flags will be cleared in
|
||||
the dest shape.
|
||||
If set-touched? is true, the corresponding 'touched' flags will be
|
||||
set in dest shape if they are different than their current values."
|
||||
[dest-shape origin-shape dest-root origin-root page-id component-id
|
||||
{:keys [omit-touched? reset-touched? set-touched?] :as options}]
|
||||
|
||||
;; === Uncomment this to debug synchronization ===
|
||||
;; (println "SYNC"
|
||||
;; "[C]" (:name component-shape)
|
||||
;; "[C]" (:name origin-shape)
|
||||
;; "->"
|
||||
;; (if page-id "[W]" ["C"])
|
||||
;; (:name shape))
|
||||
;; (:name dest-shape)
|
||||
;; (str options))
|
||||
|
||||
(let [; The position attributes need a special sync algorith, because we do
|
||||
; not synchronize the absolute position, but the position relative of
|
||||
; the container shape of the component.
|
||||
new-pos (calc-new-pos shape component-shape root-shape root-component)
|
||||
pos-group (get cp/component-sync-attrs :x)
|
||||
touched (get shape :touched #{})]
|
||||
new-pos (calc-new-pos dest-shape origin-shape dest-root origin-root)
|
||||
touched (get dest-shape :touched #{})]
|
||||
|
||||
(loop [attrs (seq (keys (dissoc cp/component-sync-attrs :x :y)))
|
||||
roperations (if (or (not (touched pos-group)) reset-touched? true)
|
||||
[{:type :set :attr :x :val (:x new-pos)} ; ^ TODO: the position-group is being set
|
||||
{:type :set :attr :y :val (:y new-pos)}] ; | as touched somewhere. Investigate why.
|
||||
roperations (if (or (not= (:x new-pos) (:x dest-shape))
|
||||
(not= (:y new-pos) (:y dest-shape)))
|
||||
[{:type :set :attr :x :val (:x new-pos)}
|
||||
{:type :set :attr :y :val (:y new-pos)}]
|
||||
[])
|
||||
uoperations (if (or (not (touched pos-group)) reset-touched? true)
|
||||
[{:type :set :attr :x :val (:x shape)}
|
||||
{:type :set :attr :y :val (:y shape)}]
|
||||
uoperations (if (or (not= (:x new-pos) (:x dest-shape))
|
||||
(not= (:y new-pos) (:y dest-shape)))
|
||||
[{:type :set :attr :x :val (:x dest-shape)}
|
||||
{:type :set :attr :y :val (:y dest-shape)}]
|
||||
[])]
|
||||
|
||||
(let [attr (first attrs)]
|
||||
|
@ -419,51 +577,50 @@
|
|||
uoperations (if reset-touched?
|
||||
(conj uoperations
|
||||
{:type :set-touched
|
||||
:touched (:touched shape)})
|
||||
:touched (:touched dest-shape)})
|
||||
uoperations)
|
||||
|
||||
rchanges [(d/without-nils {:type :mod-obj
|
||||
:id (:id shape)
|
||||
:id (:id dest-shape)
|
||||
:page-id page-id
|
||||
:component-id component-id
|
||||
:operations roperations})]
|
||||
uchanges [(d/without-nils {:type :mod-obj
|
||||
:id (:id shape)
|
||||
:id (:id dest-shape)
|
||||
:page-id page-id
|
||||
:component-id component-id
|
||||
:operations uoperations})]]
|
||||
[rchanges uchanges])
|
||||
|
||||
(if-not (contains? shape attr)
|
||||
(if-not (contains? dest-shape attr)
|
||||
(recur (next attrs)
|
||||
roperations
|
||||
uoperations)
|
||||
(let [roperation {:type :set
|
||||
:attr attr
|
||||
:val (get component-shape attr)
|
||||
:ignore-touched true}
|
||||
:val (get origin-shape attr)
|
||||
:ignore-touched (not set-touched?)}
|
||||
uoperation {:type :set
|
||||
:attr attr
|
||||
:val (get shape attr)
|
||||
:ignore-touched true}
|
||||
:val (get dest-shape attr)
|
||||
:ignore-touched (not set-touched?)}
|
||||
|
||||
attr-group (get cp/component-sync-attrs attr)]
|
||||
(if (or (not (touched attr-group)) reset-touched?)
|
||||
(recur (next attrs)
|
||||
(conj roperations roperation)
|
||||
(conj uoperations uoperation))
|
||||
(if (and (touched attr-group) omit-touched?)
|
||||
(recur (next attrs)
|
||||
roperations
|
||||
uoperations)))))))))
|
||||
uoperations)
|
||||
(recur (next attrs)
|
||||
(conj roperations roperation)
|
||||
(conj uoperations uoperation))))))))))
|
||||
|
||||
(defn calc-new-pos
|
||||
[shape component-shape root-shape root-component]
|
||||
(let [root-pos (gpt/point (:x root-shape) (:y root-shape))
|
||||
root-component-pos (gpt/point (:x root-component) (:y root-component))
|
||||
component-pos (gpt/point (:x component-shape) (:y component-shape))
|
||||
delta (gpt/subtract component-pos root-component-pos)
|
||||
shape-pos (gpt/point (:x shape) (:y shape))
|
||||
new-pos (gpt/add root-pos delta)]
|
||||
(defn- calc-new-pos
|
||||
[dest-shape origin-shape dest-root origin-root]
|
||||
(let [root-pos (gpt/point (:x dest-root) (:y dest-root))
|
||||
origin-root-pos (gpt/point (:x origin-root) (:y origin-root))
|
||||
origin-pos (gpt/point (:x origin-shape) (:y origin-shape))
|
||||
delta (gpt/subtract origin-pos origin-root-pos)
|
||||
shape-pos (gpt/point (:x dest-shape) (:y dest-shape))
|
||||
new-pos (gpt/add root-pos delta)]
|
||||
new-pos))
|
||||
|
||||
|
||||
|
|
|
@ -89,7 +89,8 @@
|
|||
(letfn [(show-shape [shape-id level objects]
|
||||
(let [shape (get objects shape-id)]
|
||||
(println (str/pad (str (str/repeat " " level)
|
||||
(:name shape))
|
||||
(:name shape)
|
||||
(when (seq (:touched shape)) "*")
|
||||
{:length 20
|
||||
:type :right})
|
||||
(show-component shape objects))
|
||||
|
@ -102,24 +103,36 @@
|
|||
(show-shape shape-id (inc level) objects))))))
|
||||
|
||||
(show-component [shape objects]
|
||||
(let [root-id (cph/get-root-component (:id shape) objects)
|
||||
root-shape (when root-id (get objects root-id))
|
||||
component-id (when root-shape (:component-id root-shape))
|
||||
component-file-id (when root-shape (:component-file root-shape))
|
||||
component-file (when component-file-id (get libraries component-file-id))
|
||||
shape-ref (:shape-ref shape)
|
||||
component (when component-id
|
||||
(if component-file
|
||||
(get-in component-file [:data :components component-id])
|
||||
(get components component-id)))
|
||||
component-shape (when (and component shape-ref)
|
||||
(get-in component [:objects shape-ref]))]
|
||||
(if component-shape
|
||||
(str/format " %s--> %s%s"
|
||||
(if (:component-id shape) "#" "-")
|
||||
(if (nil? (:shape-ref shape))
|
||||
""
|
||||
(let [root-shape (cph/get-root-shape shape objects)
|
||||
component-id (when root-shape (:component-id root-shape))
|
||||
component-file-id (when root-shape (:component-file root-shape))
|
||||
component-file (when component-file-id (get libraries component-file-id))
|
||||
component (when component-id
|
||||
(if component-file
|
||||
(get-in component-file [:data :components component-id])
|
||||
(get components component-id)))
|
||||
component-shape (when (and component (:shape-ref shape))
|
||||
(get-in component [:objects (:shape-ref shape)]))]
|
||||
(str/format " %s--> %s%s%s"
|
||||
(cond (:component-root? shape) "#"
|
||||
(:component-id shape) "@"
|
||||
:else "-")
|
||||
(when component-file (str/format "<%s> " (:name component-file)))
|
||||
(:name component-shape))
|
||||
"")))]
|
||||
(:name component-shape)
|
||||
(if (or (:component-root? shape)
|
||||
(nil? (:component-id shape)))
|
||||
""
|
||||
(let [component-id (:component-id shape)
|
||||
component-file-id (:component-file shape)
|
||||
component-file (when component-file-id (get libraries component-file-id))
|
||||
component (if component-file
|
||||
(get-in component-file [:data :components component-id])
|
||||
(get components component-id))]
|
||||
(str/format " (%s%s)"
|
||||
(when component-file (str/format "<%s> " (:name component-file)))
|
||||
(:name component))))))))]
|
||||
|
||||
(println "[Workspace]")
|
||||
(show-shape (:id root) 0 objects)
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
[app.main.ui.icons :as i]
|
||||
[app.util.dom :as dom]
|
||||
[app.main.data.workspace :as dw]
|
||||
[app.main.data.workspace.common :as dwc]
|
||||
[app.main.data.workspace.libraries :as dwl]
|
||||
[app.main.ui.hooks :refer [use-rxsub]]
|
||||
[app.main.ui.components.dropdown :refer [dropdown]]))
|
||||
|
@ -46,7 +47,6 @@
|
|||
[{:keys [mdata] :as props}]
|
||||
(let [{:keys [id] :as shape} (:shape mdata)
|
||||
selected (:selected mdata)
|
||||
root-shape (:root-shape mdata)
|
||||
|
||||
do-duplicate #(st/emit! dw/duplicate-selected)
|
||||
do-delete #(st/emit! dw/delete-selected)
|
||||
|
@ -66,10 +66,12 @@
|
|||
do-detach-component #(st/emit! (dwl/detach-component id))
|
||||
do-reset-component #(st/emit! (dwl/reset-component id))
|
||||
do-update-component #(do
|
||||
(st/emit! dwc/start-undo-transaction)
|
||||
(st/emit! (dwl/update-component id))
|
||||
(st/emit! (dwl/sync-file nil)))
|
||||
(st/emit! (dwl/sync-file nil))
|
||||
(st/emit! dwc/commit-undo-transaction))
|
||||
do-navigate-component-file #(st/emit! (dwl/nav-to-component-file
|
||||
(:component-file root-shape)))]
|
||||
(:component-file shape)))]
|
||||
[:*
|
||||
[:& menu-entry {:title "Copy"
|
||||
:shortcut "Ctrl + c"
|
||||
|
@ -117,28 +119,30 @@
|
|||
[:& menu-entry {:title "Lock"
|
||||
:on-click do-lock-shape}])
|
||||
|
||||
[:& menu-separator]
|
||||
|
||||
(if (nil? (:shape-ref shape))
|
||||
[:& menu-entry {:title "Create component"
|
||||
:shortcut "Ctrl + K"
|
||||
:on-click do-add-component}]
|
||||
(when (nil? (:shape-ref shape))
|
||||
[:*
|
||||
[:& menu-entry {:title "Detach instance"
|
||||
:on-click do-detach-component}]
|
||||
[:& menu-entry {:title "Reset overrides"
|
||||
:on-click do-reset-component}]
|
||||
(if (nil? (:component-file root-shape))
|
||||
[:& menu-entry {:title "Update master component"
|
||||
:on-click do-update-component}]
|
||||
[:& menu-entry {:title "Go to master component file"
|
||||
:on-click do-navigate-component-file}])])
|
||||
[:& menu-separator]
|
||||
[:& menu-entry {:title "Create component"
|
||||
:shortcut "Ctrl + K"
|
||||
:on-click do-add-component}]])
|
||||
|
||||
(when (:component-id shape)
|
||||
[:*
|
||||
[:& menu-separator]
|
||||
[:& menu-entry {:title "Detach instance"
|
||||
:on-click do-detach-component}]
|
||||
[:& menu-entry {:title "Reset overrides"
|
||||
:on-click do-reset-component}]
|
||||
(if (nil? (:component-file shape))
|
||||
[:& menu-entry {:title "Update master component"
|
||||
:on-click do-update-component}]
|
||||
[:& menu-entry {:title "Go to master component file"
|
||||
:on-click do-navigate-component-file}])])
|
||||
|
||||
[:& menu-separator]
|
||||
[:& menu-entry {:title "Delete"
|
||||
:shortcut "Supr"
|
||||
:on-click do-delete}]
|
||||
]))
|
||||
:on-click do-delete}]]))
|
||||
|
||||
(mf/defc viewport-context-menu
|
||||
[{:keys [mdata] :as props}]
|
||||
|
|
|
@ -89,7 +89,8 @@
|
|||
:default-value (:name shape "")}]
|
||||
[:span.element-name
|
||||
{:on-double-click on-click}
|
||||
(:name shape "")])))
|
||||
(:name shape "")
|
||||
(when (seq (:touched shape)) " *")])))
|
||||
|
||||
(defn- make-collapsed-iref
|
||||
[id]
|
||||
|
@ -305,6 +306,7 @@
|
|||
:component-id
|
||||
:component-file
|
||||
:shape-ref
|
||||
:touched
|
||||
:metadata])]
|
||||
(persistent!
|
||||
(reduce-kv (fn [res id obj]
|
||||
|
|
Loading…
Add table
Reference in a new issue