Merge remote-tracking branch 'origin/staging' into develop

This commit is contained in:
alonso.torres 2021-05-25 14:01:42 +02:00
commit a9e8115088
24 changed files with 274 additions and 148 deletions

View file

@ -991,19 +991,22 @@
[[] [] []]
ids)
[rchanges uchanges] (relocate-shapes-changes objects
parents
parent-id
page-id
to-index
ids
groups-to-delete
groups-to-unmask
shapes-to-detach
shapes-to-reroot
shapes-to-deroot)]
[rchanges uchanges]
(relocate-shapes-changes objects
parents
parent-id
page-id
to-index
ids
groups-to-delete
groups-to-unmask
shapes-to-detach
shapes-to-reroot
shapes-to-deroot)
]
(rx/of (dch/commit-changes {:redo-changes rchanges
:undo-chanes uchanges
:undo-changes uchanges
:origin it})
(dwc/expand-collapse parent-id))))))
@ -1058,7 +1061,7 @@
:id id
:index cidx}]
(rx/of (dch/commit-changes {:redo-changes [rchg]
:undo-chanes [uchg]
:undo-changes [uchg]
:origin it}))))))
;; --- Shape / Selection Alignment and Distribution

View file

@ -32,31 +32,97 @@
(gsh/setup selrect)
(assoc :shapes (mapv :id shapes)))))
(defn get-empty-groups
"Retrieve emtpy groups after group creation"
[objects parent-id shapes]
(let [ids (cp/clean-loops objects (into #{} (map :id) shapes))
parents (->> ids
(reduce #(conj %1 (cp/get-parent %2 objects))
#{}))]
(loop [current-id (first parents)
to-check (rest parents)
removed-id? ids
result #{}]
(if-not current-id
;; Base case, no next element
result
(let [group (get objects current-id)]
(if (and (not= :frame (:type group))
(not= current-id parent-id)
(empty? (remove removed-id? (:shapes group))))
;; Adds group to the remove and check its parent
(let [to-check (d/concat [] to-check [(cp/get-parent current-id objects)]) ]
(recur (first to-check)
(rest to-check)
(conj removed-id? current-id)
(conj result current-id)))
;; otherwise recur
(recur (first to-check)
(rest to-check)
removed-id?
result)))))))
(defn prepare-create-group
[page-id shapes prefix keep-name]
[objects page-id shapes prefix keep-name]
(let [group (make-group shapes prefix keep-name)
frame-id (:frame-id (first shapes))
parent-id (:parent-id (first shapes))
rchanges [{:type :add-obj
:id (:id group)
:page-id page-id
:frame-id (:frame-id (first shapes))
:parent-id (:parent-id (first shapes))
:frame-id frame-id
:parent-id parent-id
:obj group
:index (::index (first shapes))}
{:type :mov-objects
:page-id page-id
:parent-id (:id group)
:shapes (mapv :id shapes)}]
uchanges (conj
(mapv (fn [obj] {:type :mov-objects
:page-id page-id
:parent-id (:parent-id obj)
:index (::index obj)
:shapes [(:id obj)]})
shapes)
{:type :del-obj
:id (:id group)
:page-id page-id})]
uchanges (-> (mapv
(fn [obj]
{:type :mov-objects
:page-id page-id
:parent-id (:parent-id obj)
:index (::index obj)
:shapes [(:id obj)]}) shapes)
(conj
{:type :del-obj
:id (:id group)
:page-id page-id}))
ids-to-delete (get-empty-groups objects parent-id shapes)
delete-group
(fn [changes id]
(-> changes
(conj {:type :del-obj
:id id
:page-id page-id})))
add-deleted-group
(fn [changes id]
(let [obj (-> (get objects id)
(d/without-keys [:shapes]))]
(d/concat [{:type :add-obj
:id id
:page-id page-id
:frame-id (:frame-id obj)
:parent-id (:parent-id obj)
:obj obj
:index (::index obj)}] changes)))
rchanges (->> ids-to-delete
(reduce delete-group rchanges))
uchanges (->> ids-to-delete
(reduce add-deleted-group uchanges))]
[group rchanges uchanges]))
(defn prepare-remove-group
@ -107,7 +173,8 @@
selected (cp/clean-loops objects selected)
shapes (shapes-for-grouping objects selected)]
(when-not (empty? shapes)
(let [[group rchanges uchanges] (prepare-create-group page-id shapes "Group-" false)]
(let [[group rchanges uchanges]
(prepare-create-group objects page-id shapes "Group-" false)]
(rx/of (dch/commit-changes {:redo-changes rchanges
:undo-changes uchanges
:origin it})
@ -146,7 +213,7 @@
(if (and (= (count shapes) 1)
(= (:type (first shapes)) :group))
[(first shapes) [] []]
(prepare-create-group page-id shapes "Group-" true))
(prepare-create-group objects page-id shapes "Group-" true))
rchanges (d/concat rchanges
[{:type :mod-obj

View file

@ -131,7 +131,7 @@
(if (and (= (count shapes) 1)
(= (:type (first shapes)) :group))
[(first shapes) [] []]
(dwg/prepare-create-group page-id shapes "Component-" true))
(dwg/prepare-create-group objects page-id shapes "Component-" true))
[new-shape new-shapes updated-shapes]
(make-component-shape group objects file-id)

View file

@ -562,7 +562,7 @@
(defn- extract-frame-changes
"Process a changes set in a commit to extract the frames that are channging"
[[event objects]]
[[event [old-objects new-objects]]]
(let [changes (-> event deref :changes)
extract-ids
@ -577,8 +577,11 @@
get-frame-id
(fn [id]
(or (and (= :frame (get-in objects [id :type])) id)
(get-in objects [id :frame-id])))
(let [shape (or (get new-objects id)
(get old-objects id))]
(or (and (= :frame (:type shape)) id)
(:frame-id shape))))
;; Extracts the frames and then removes nils and the root frame
xform (comp (mapcat extract-ids)
@ -613,7 +616,12 @@
(rx/filter #(or (= :app.main.data.workspace/finalize-page (ptk/type %))
(= ::watch-state-changes (ptk/type %)))))
objects-stream (rx/from-atom refs/workspace-page-objects {:emit-current-value? true})
objects-stream (->> (rx/concat
(rx/of nil)
(rx/from-atom refs/workspace-page-objects {:emit-current-value? true}))
;; We need to keep the old-objects so we can check the frame for the
;; deleted objects
(rx/buffer 2 1))
frame-changes (->> stream
(rx/filter dch/commit-changes?)

View file

@ -26,11 +26,18 @@
(get-in state [:workspace-data :components component-id :objects])))
(defn lookup-selected
[state]
(let [objects (lookup-page-objects state)
selected (->> (get-in state [:workspace-local :selected])
(cp/clean-loops objects))
is-present? (fn [id] (contains? objects id))]
(into (d/ordered-set)
(filter is-present?)
selected)))
([state]
(lookup-selected state nil))
([state {:keys [omit-blocked?]
:or {omit-blocked? false}}]
(let [objects (lookup-page-objects state)
selected (->> (get-in state [:workspace-local :selected])
(cp/clean-loops objects))
selectable? (fn [id]
(and (contains? objects id)
(or (not omit-blocked?)
(not (get-in objects [id :blocked] false)))))]
(into (d/ordered-set)
(filter selectable?)
selected))))

View file

@ -242,23 +242,24 @@
ptk/WatchEvent
(watch [it state stream]
(let [initial (deref ms/mouse-position)
selected (wsh/lookup-selected state)
selected (wsh/lookup-selected state {:omit-blocked? true})
stopper (rx/filter ms/mouse-up? stream)]
(->> ms/mouse-position
(rx/take-until stopper)
(rx/map #(gpt/to-vec initial %))
(rx/map #(gpt/length %))
(rx/filter #(> % 1))
(rx/take 1)
(rx/with-latest vector ms/mouse-position-alt)
(rx/mapcat
(fn [[_ alt?]]
(if alt?
;; When alt is down we start a duplicate+move
(rx/of (start-move-duplicate initial)
dws/duplicate-selected)
;; Otherwise just plain old move
(rx/of (start-move initial selected))))))))))
(when-not (empty? selected)
(->> ms/mouse-position
(rx/take-until stopper)
(rx/map #(gpt/to-vec initial %))
(rx/map #(gpt/length %))
(rx/filter #(> % 1))
(rx/take 1)
(rx/with-latest vector ms/mouse-position-alt)
(rx/mapcat
(fn [[_ alt?]]
(if alt?
;; When alt is down we start a duplicate+move
(rx/of (start-move-duplicate initial)
dws/duplicate-selected)
;; Otherwise just plain old move
(rx/of (start-move initial selected)))))))))))
(defn start-move-duplicate [from-position]
(ptk/reify ::start-move-selected
@ -319,7 +320,8 @@
(watch [it state stream]
(let [page-id (:current-page-id state)
objects (wsh/lookup-page-objects state page-id)
ids (if (nil? ids) (wsh/lookup-selected state) ids)
selected (wsh/lookup-selected state {:omit-blocked? true})
ids (if (nil? ids) selected ids)
shapes (mapv #(get objects %) ids)
stopper (rx/filter ms/mouse-up? stream)
layout (get state :workspace-layout)
@ -398,7 +400,7 @@
ptk/WatchEvent
(watch [it state stream]
(if (= same-event (get-in state [:workspace-local :current-move-selected]))
(let [selected (wsh/lookup-selected state)
(let [selected (wsh/lookup-selected state {:omit-blocked? true})
move-events (->> stream
(rx/filter (ptk/type? ::move-selected))
(rx/filter #(= direction (deref %))))
@ -435,6 +437,8 @@
page-id (:current-page-id state)
objects (wsh/lookup-page-objects state page-id)
ids (->> ids (into #{} (remove #(get-in objects [% :blocked] false))))
not-frame-id?
(fn [shape-id]
(let [shape (get objects shape-id)]
@ -457,27 +461,28 @@
;; shape adjusting their position.
(defn set-rotation
([delta-rotation shapes]
(set-rotation delta-rotation shapes (-> shapes gsh/selection-rect gsh/center-selrect)))
([angle shapes]
(set-rotation angle shapes (-> shapes gsh/selection-rect gsh/center-selrect)))
([delta-rotation shapes center]
(letfn [(rotate-shape [objects angle shape center]
(update-in objects [(:id shape) :modifiers] merge (gsh/rotation-modifiers center shape angle)))
([angle shapes center]
(ptk/reify ::set-rotation
ptk/UpdateEvent
(update [_ state]
(let [objects (wsh/lookup-page-objects state)
id->obj #(get objects %)
get-children (fn [shape] (map id->obj (cp/get-children (:id shape) objects)))
(rotate-around-center [objects angle center shapes]
(reduce #(rotate-shape %1 angle %2 center) objects shapes))
shapes (->> shapes (into [] (remove #(get % :blocked false))))
(set-rotation [objects]
(let [id->obj #(get objects %)
get-children (fn [shape] (map id->obj (cp/get-children (:id shape) objects)))
shapes (concat shapes (mapcat get-children shapes))]
(rotate-around-center objects delta-rotation center shapes)))]
shapes (->> shapes (mapcat get-children) (concat shapes))
(ptk/reify ::set-rotation
ptk/UpdateEvent
(update [_ state]
(let [page-id (:current-page-id state)]
(d/update-in-when state [:workspace-data :pages-index page-id :objects] set-rotation)))))))
update-shape
(fn [modifiers shape]
(let [rotate-modifiers (gsh/rotation-modifiers shape center angle)]
(assoc-in modifiers [(:id shape) :modifiers] rotate-modifiers)))]
(-> state
(update :workspace-modifiers
#(reduce update-shape % shapes))))))))
(defn increase-rotation [ids rotation]
(ptk/reify ::increase-rotation
@ -583,7 +588,7 @@
ptk/WatchEvent
(watch [it state stream]
(let [objects (wsh/lookup-page-objects state)
selected (wsh/lookup-selected state)
selected (wsh/lookup-selected state {:omit-blocked? true})
shapes (map #(get objects %) selected)
selrect (gsh/selection-rect (->> shapes (map gsh/transform-shape)))
origin (gpt/point (:x selrect) (+ (:y selrect) (/ (:height selrect) 2)))]
@ -600,7 +605,7 @@
ptk/WatchEvent
(watch [it state stream]
(let [objects (wsh/lookup-page-objects state)
selected (wsh/lookup-selected state)
selected (wsh/lookup-selected state {:omit-blocked? true})
shapes (map #(get objects %) selected)
selrect (gsh/selection-rect (->> shapes (map gsh/transform-shape)))
origin (gpt/point (+ (:x selrect) (/ (:width selrect) 2)) (:y selrect))]
@ -633,5 +638,5 @@
(ptk/reify ::selected-to-path
ptk/WatchEvent
(watch [_ state stream]
(let [ids (wsh/lookup-selected state)]
(let [ids (wsh/lookup-selected state {:omit-blocked? true})]
(rx/of (dch/update-shapes ids ups/convert-to-path))))))

View file

@ -22,18 +22,22 @@
(hooks/use-effect-ssr
(mf/deps embed? urls)
(fn []
(let [sub (when embed?
(->> (rx/from urls)
(rx/merge-map http/fetch-data-uri)
(rx/reduce conj {})
(rx/subs (fn [data]
(when-not (= data (mf/ref-val uri-data))
(mf/set-ref-val! uri-data data)
(reset! state inc))))))]
(let [;; When not active the embedding we return the URI
url-mapping (fn [obs]
(if embed?
(rx/merge-map http/fetch-data-uri obs)
(rx/map identity obs)))
sub (->> (rx/from urls)
(url-mapping)
(rx/reduce conj {})
(rx/subs (fn [data]
(when-not (= data (mf/ref-val uri-data))
(mf/set-ref-val! uri-data data)
(reset! state inc)))))]
#(when sub
(rx/dispose! sub)))))
;; Use ref so if the urls are cached will return inmediately instead of the
;; next render
(when embed?
(mf/ref-val uri-data))))
(mf/ref-val uri-data)))

View file

@ -31,7 +31,8 @@
:y y
:height height
:width width
:patternTransform transform}
:patternTransform transform
:data-loading (str (not (contains? embed uri)))}
[:image {:xlinkHref (get embed uri uri)
:width width
:height height}]]))))

View file

@ -32,7 +32,9 @@
:transform transform
:width width
:height height
:preserveAspectRatio "none"}))
:preserveAspectRatio "none"
:data-loading (str (not (contains? embed uri)))}))
on-drag-start (fn [event]
;; Prevent browser dragging of the image
(dom/prevent-default event))]

View file

@ -75,7 +75,8 @@
;; (uc/hex->rgba fill-color fill-opacity))
[r g b a] (uc/hex->rgba fill-color fill-opacity)
text-color (str/format "rgba(%s, %s, %s, %s)" r g b a)
text-color (when (and (some? fill-color) (some? fill-opacity))
(str/format "rgba(%s, %s, %s, %s)" r g b a))
fontsdb (deref fonts/fontsdb)
base #js {:textDecoration text-decoration

View file

@ -209,7 +209,7 @@
(into []
(cond
(= selected :recent) (reverse recent-colors)
(= selected :file) (vals file-colors)
(= selected :file) (->> (vals file-colors) (sort-by :name))
:else (library->colors shared-libs selected))))))
(mf/use-effect
@ -222,7 +222,8 @@
(mf/deps file-colors)
(fn []
(when (= selected :file)
(reset! current-library-colors (into [] (vals file-colors))))))
(reset! current-library-colors (into [] (->> (vals file-colors)
(sort-by :name)))))))
[:& palette {:left-sidebar? left-sidebar?
:current-colors @current-library-colors

View file

@ -150,10 +150,6 @@
(dom/prevent-default event)
(let [id (:id item)]
(cond
(or (:blocked item)
(:hidden item))
nil
(kbd/shift? event)
(st/emit! (dw/shift-select-shapes id))

View file

@ -288,6 +288,8 @@
(fn [changes]
(st/emit! (dwl/update-typography (merge typography changes) file-id))))
multiple? (->> values vals (d/seek #(= % :multiple)))
opts #js {:ids ids
:values values
:on-change on-change}]
@ -295,7 +297,7 @@
[:div.element-set
[:div.element-set-title
[:span label]
(when (not typography)
(when (and (not typography) (not multiple?))
[:div.add-page {:on-click on-convert-to-typography} i/close])]
(cond

View file

@ -27,7 +27,19 @@
(defn color-picker-callback
[color disable-gradient disable-opacity handle-change-color handle-open handle-close]
(fn [event]
(let [x (.-clientX event)
(let [color
(cond
(uc/multiple? color)
{:color cp/default-color
:opacity 1}
(= :multiple (:opacity color))
(assoc color :opacity 1)
:else
color)
x (.-clientX event)
y (.-clientY event)
props {:x x
:y y
@ -98,16 +110,12 @@
handle-click-color (mf/use-callback
(mf/deps color)
(let [;; If multiple, we change to default color
color (if (uc/multiple? color)
{:color cp/default-color :opacity 1}
color)]
(color-picker-callback color
disable-gradient
disable-opacity
handle-pick-color
handle-open
handle-close)))
(color-picker-callback color
disable-gradient
disable-opacity
handle-pick-color
handle-open
handle-close))
prev-color (h/use-previous color)]

View file

@ -148,22 +148,23 @@
extract-attrs
(fn [[ids values] {:keys [id type shapes content] :as shape}]
(let [props (get-in type->props [type attr-type])
result (case props
:ignore [ids values]
:shape [(conj ids id)
(merge-attrs values (merge
(empty-map attrs)
(select-keys shape attrs)))]
:text [(conj ids id)
(-> values
(merge-attrs (select-keys shape attrs))
(merge-attrs (attrs/get-attrs-multi (txt/node-seq content) attrs)))]
:children (let [children (->> (:shapes shape []) (map #(get objects %)))
[new-ids new-values] (get-attrs children objects attr-type)]
[(d/concat ids new-ids) (merge-attrs values new-values)])
[])]
result))]
(let [props (get-in type->props [type attr-type])]
(case props
:ignore [ids values]
:shape [(conj ids id)
(merge-attrs values (merge
(empty-map attrs)
(select-keys shape attrs)))]
:text [(conj ids id)
(-> values
(merge-attrs (select-keys shape attrs))
(merge-attrs (merge
(select-keys txt/default-text-attrs attrs)
(attrs/get-attrs-multi (txt/node-seq content) attrs))))]
:children (let [children (->> (:shapes shape []) (map #(get objects %)))
[new-ids new-values] (get-attrs children objects attr-type)]
[(d/concat ids new-ids) (merge-attrs values new-values)])
[])))]
(reduce extract-attrs [[] []] shapes)))
(mf/defc options

View file

@ -131,7 +131,7 @@
#(rx/dispose! sub))))
(mf/use-effect
(mf/deps shapes modifiers)
(mf/deps shapes filter-shapes modifiers)
(fn []
(rx/push! subject props)))
@ -161,7 +161,8 @@
(map #(get objects %))
(filterv (comp not nil?)))
filter-shapes (into #{}
(mapcat #(cp/get-object-with-children % objects))
(comp (mapcat #(cp/get-object-with-children % objects))
(map :id))
selected)
filter-shapes (fn [id]

View file

@ -29,16 +29,19 @@
(when node
(let [img-node (mf/ref-val thumbnail-img)]
(timers/schedule-on-idle
#(if-let [frame-node (dom/get-element (str "shape-" (:id shape)))]
(let [xml (-> (js/XMLSerializer.)
(.serializeToString frame-node)
js/encodeURIComponent
js/unescape
js/btoa)
img-src (str "data:image/svg+xml;base64," xml)]
(obj/set! img-node "src" img-src))
#(let [frame-node (dom/get-element (str "shape-" (:id shape)))
loading-node (when frame-node
(dom/query frame-node "[data-loading=\"true\"]"))]
(if (and (some? frame-node) (not (some? loading-node)))
(let [xml (-> (js/XMLSerializer.)
(.serializeToString frame-node)
js/encodeURIComponent
js/unescape
js/btoa)
img-src (str "data:image/svg+xml;base64," xml)]
(obj/set! img-node "src" img-src))
(on-frame-not-found (:id shape))))))))
(on-frame-not-found (:id shape)))))))))
on-image-load
(mf/use-callback
@ -108,8 +111,9 @@
(fn [frame-id]
;; If we couldn't find the frame maybe is still rendering. We push the event again
;; after a time
(timers/schedule-on-idle #(dwp/update-frame-thumbnail frame-id))
(rx/push! next :next)))]
(reset! shape-id nil)
(rx/push! next :next)
(timers/schedule-on-idle (st/emitf (dwp/update-frame-thumbnail frame-id)))))]
(mf/use-effect
(mf/deps render-frame)

View file

@ -135,7 +135,7 @@
:else "transparent")))
(defn multiple? [{:keys [id file-id value color gradient]}]
(defn multiple? [{:keys [id file-id value color gradient opacity]}]
(or (= value :multiple)
(= color :multiple)
(= gradient :multiple)

View file

@ -22,7 +22,10 @@
(defn add-subpath-command
"Adds a command to the subpath"
[subpath command]
(let [p (upc/command->point command)]
(let [command (if (= :close-path (:command command))
(upc/make-line-to (:from subpath))
command)
p (upc/command->point command)]
(-> subpath
(assoc :to p)
(update :data conj command))))

View file

@ -34,12 +34,13 @@
(-dispose [_]
(js/clearInterval sem)))))
(if (and (exists? js/window) (.-requestIdleCallback js/window))
(if (and (exists? js/window)
(.-requestIdleCallback js/window))
(do
(def ^:private request-idle-callback #(js/requestIdleCallback %))
(def ^:private cancel-idle-callback #(js/cancelIdleCallback %)))
(do
(def ^:private request-idle-callback #(js/setTimeout % 100))
(def ^:private request-idle-callback #(js/setTimeout % 250))
(def ^:private cancel-idle-callback #(js/clearTimeout %))))
(defn schedule-on-idle