Merge pull request #6720 from penpot/niwinz-staging-path-editor-fixes

 Fix path edition/drawing state on workspace
This commit is contained in:
Alejandro Alonso 2025-06-20 10:34:19 +02:00 committed by GitHub
commit 3a0ac577f8
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
13 changed files with 256 additions and 254 deletions

View file

@ -96,7 +96,7 @@
(watch [_ _ _] (watch [_ _ _]
(rx/of (rx/of
(case type (case type
:path (path/handle-new-shape) :path (path/handle-drawing)
:curve (curve/handle-drawing) :curve (curve/handle-drawing)
(box/handle-drawing type)))))) (box/handle-drawing type))))))

View file

@ -14,7 +14,7 @@
[app.main.data.workspace.path.undo :as undo])) [app.main.data.workspace.path.undo :as undo]))
;; Drawing ;; Drawing
(dm/export drawing/handle-new-shape) (dm/export drawing/handle-drawing)
(dm/export drawing/start-path-from-point) (dm/export drawing/start-path-from-point)
(dm/export drawing/close-path-drag-start) (dm/export drawing/close-path-drag-start)
(dm/export drawing/change-edit-mode) (dm/export drawing/change-edit-mode)

View file

@ -11,7 +11,7 @@
[potok.v2.core :as ptk])) [potok.v2.core :as ptk]))
(defn init-path [] (defn init-path []
(ptk/reify ::init-path)) (ptk/data-event ::init-path {}))
(defn clean-edit-state (defn clean-edit-state
[state] [state]

View file

@ -6,6 +6,7 @@
(ns app.main.data.workspace.path.drawing (ns app.main.data.workspace.path.drawing
(:require (:require
[app.common.data :as d]
[app.common.data.macros :as dm] [app.common.data.macros :as dm]
[app.common.geom.point :as gpt] [app.common.geom.point :as gpt]
[app.common.geom.shapes.flex-layout :as gsl] [app.common.geom.shapes.flex-layout :as gsl]
@ -32,7 +33,8 @@
(declare change-edit-mode) (declare change-edit-mode)
(defn preview-next-point [{:keys [x y shift?]}] (defn preview-next-point
[{:keys [x y shift?]}]
(ptk/reify ::preview-next-point (ptk/reify ::preview-next-point
ptk/UpdateEvent ptk/UpdateEvent
(update [_ state] (update [_ state]
@ -42,9 +44,12 @@
position (cond-> (gpt/point x y) position (cond-> (gpt/point x y)
fix-angle? (path.helpers/position-fixed-angle last-point)) fix-angle? (path.helpers/position-fixed-angle last-point))
shape (st/get-path state) shape (st/get-path state)
{:keys [last-point prev-handler]} (get-in state [:workspace-local :edit-path id])
command (path.segment/next-node shape position last-point prev-handler)] {:keys [last-point prev-handler]}
(assoc-in state [:workspace-local :edit-path id :preview] command))))) (get-in state [:workspace-local :edit-path id])
segment (path.segment/next-node shape position last-point prev-handler)]
(assoc-in state [:workspace-local :edit-path id :preview] segment)))))
(defn add-node (defn add-node
[{:keys [x y shift?]}] [{:keys [x y shift?]}]
@ -189,16 +194,16 @@
(defn make-drag-stream (defn make-drag-stream
[state stream down-event] [state stream down-event]
(dm/assert! (assert (gpt/point? down-event)
"should be a pointer" "should be a point instance")
(gpt/point? down-event))
(let [stopper (rx/merge (let [stopper (rx/merge
(mse/drag-stopper stream) (mse/drag-stopper stream)
(->> stream (->> stream
(rx/filter helpers/end-path-event?))) (rx/filter helpers/end-path-event?)))
drag-events (->> (streams/position-stream state) drag-events
(->> (streams/position-stream state)
(rx/map #(drag-handler %)) (rx/map #(drag-handler %))
(rx/take-until stopper))] (rx/take-until stopper))]
(rx/concat (rx/concat
@ -208,9 +213,9 @@
drag-events drag-events
(rx/of (finish-drag))))))) (rx/of (finish-drag)))))))
(defn handle-drawing (defn- start-edition
[_id] [_id]
(ptk/reify ::handle-drawing (ptk/reify ::start-edition
ptk/UpdateEvent ptk/UpdateEvent
(update [_ state] (update [_ state]
(let [id (st/get-path-id state)] (let [id (st/get-path-id state)]
@ -218,36 +223,49 @@
ptk/WatchEvent ptk/WatchEvent
(watch [_ state stream] (watch [_ state stream]
(let [mouse-down (->> stream (let [mouse-down
(->> stream
(rx/filter mse/mouse-event?) (rx/filter mse/mouse-event?)
(rx/filter mse/mouse-down-event?)) (rx/filter mse/mouse-down-event?))
end-path-events (->> stream
(rx/filter helpers/end-path-event?)) end-stream
(->> stream
(rx/filter helpers/end-path-event?)
(rx/share))
stoper-stream
(->> stream
(rx/filter (ptk/type? ::start-edition))
(rx/merge end-stream))
;; Mouse move preview ;; Mouse move preview
mousemove-events mousemove-events
(->> (streams/position-stream state) (->> (streams/position-stream state)
(rx/take-until end-path-events) (rx/map #(preview-next-point %))
(rx/map #(preview-next-point %))) (rx/take-until end-stream))
;; From mouse down we can have: click, drag and double click ;; From mouse down we can have: click, drag and double click
mousedown-events mousedown-events
(->> mouse-down (->> mouse-down
(rx/take-until end-path-events)
;; We just ignore the mouse event and stream down the ;; We just ignore the mouse event and stream down the
;; last position event ;; last position event
(rx/with-latest-from #(-> %2) (streams/position-stream state)) (rx/with-latest-from #(-> %2) (streams/position-stream state))
;; We change to the stream that emits the first event ;; We change to the stream that emits the first event
(rx/switch-map (rx/switch-map
#(rx/race (make-node-events-stream stream) #(rx/race (make-node-events-stream stream)
(make-drag-stream state stream %))))] (make-drag-stream state stream %)))
(rx/take-until end-stream))]
(rx/concat (rx/concat
(rx/of (undo/start-path-undo)) (rx/of (undo/start-path-undo))
(rx/of (common/init-path)) (rx/of (common/init-path))
(rx/merge mousemove-events (->> (rx/merge mousemove-events
mousedown-events) mousedown-events)
(rx/of (common/finish-path))))))) (rx/take-until stoper-stream))
;; This step implicitly finish path
(rx/of (common/finish-path)
(change-edit-mode :draw)))))))
(defn setup-frame [] (defn setup-frame []
(ptk/reify ::setup-frame (ptk/reify ::setup-frame
@ -275,9 +293,9 @@
(cond-> (some? drop-index) (cond-> (some? drop-index)
(with-meta {:index drop-index}))))))))) (with-meta {:index drop-index})))))))))
(defn handle-new-shape-result (defn- handle-drawing-end
[shape-id] [shape-id]
(ptk/reify ::handle-new-shape-result (ptk/reify ::handle-drawing-end
ptk/UpdateEvent ptk/UpdateEvent
(update [_ state] (update [_ state]
(let [content (dm/get-in state [:workspace-drawing :object :content])] (let [content (dm/get-in state [:workspace-drawing :object :content])]
@ -299,8 +317,8 @@
(change-edit-mode :draw)) (change-edit-mode :draw))
(rx/of (dwdc/handle-finish-drawing))))))) (rx/of (dwdc/handle-finish-drawing)))))))
(defn handle-new-shape (defn handle-drawing
"Creates a new path shape" "Hanndle the start of drawing new path shape"
[] []
(ptk/reify ::handle-new-shape (ptk/reify ::handle-new-shape
ptk/UpdateEvent ptk/UpdateEvent
@ -312,12 +330,12 @@
(watch [_ state stream] (watch [_ state stream]
(let [shape-id (dm/get-in state [:workspace-drawing :object :id])] (let [shape-id (dm/get-in state [:workspace-drawing :object :id])]
(rx/concat (rx/concat
(rx/of (handle-drawing shape-id)) (rx/of (start-edition shape-id))
(->> stream (->> stream
(rx/filter (ptk/type? ::common/finish-path)) (rx/filter (ptk/type? ::common/finish-path))
(rx/take 1) (rx/take 1)
(rx/observe-on :async) (rx/observe-on :async)
(rx/map #(handle-new-shape-result shape-id)))))))) (rx/map (partial handle-drawing-end shape-id))))))))
(declare check-changed-content) (declare check-changed-content)
@ -339,7 +357,7 @@
(if (= :draw edit-mode) (if (= :draw edit-mode)
(rx/concat (rx/concat
(rx/of (dwsh/update-shapes [id] path/convert-to-path)) (rx/of (dwsh/update-shapes [id] path/convert-to-path))
(rx/of (handle-drawing id)) (rx/of (start-edition id))
(->> stream (->> stream
(rx/filter (ptk/type? ::common/finish-path)) (rx/filter (ptk/type? ::common/finish-path))
(rx/take 1) (rx/take 1)
@ -367,17 +385,18 @@
(ptk/reify ::change-edit-mode (ptk/reify ::change-edit-mode
ptk/UpdateEvent ptk/UpdateEvent
(update [_ state] (update [_ state]
(let [id (get-in state [:workspace-local :edition])] (if-let [id (dm/get-in state [:workspace-local :edition])]
(cond-> state (d/update-in-when state [:workspace-local :edit-path id] assoc :edit-mode mode)
id (assoc-in [:workspace-local :edit-path id :edit-mode] mode)))) state))
ptk/WatchEvent ptk/WatchEvent
(watch [_ state _] (watch [_ state _]
(let [id (st/get-path-id state)] (when-let [id (dm/get-in state [:workspace-local :edition])]
(cond (let [mode (dm/get-in state [:workspace-local :edit-path id :edit-mode])]
(and id (= :move mode)) (rx/of (common/finish-path)) (case mode
(and id (= :draw mode)) (rx/of (start-draw-mode)) :move (rx/of (common/finish-path))
:else (rx/empty)))))) :draw (rx/of (start-draw-mode))
(rx/empty)))))))
(defn reset-last-handler (defn reset-last-handler
[] []
@ -385,6 +404,5 @@
ptk/UpdateEvent ptk/UpdateEvent
(update [_ state] (update [_ state]
(let [id (st/get-path-id state)] (let [id (st/get-path-id state)]
(-> state (assoc-in state [:workspace-local :edit-path id :prev-handler] nil)))))
(assoc-in [:workspace-local :edit-path id :prev-handler] nil))))))

View file

@ -7,42 +7,8 @@
(ns app.main.data.workspace.path.state (ns app.main.data.workspace.path.state
(:require (:require
[app.common.data.macros :as dm] [app.common.data.macros :as dm]
[app.common.files.helpers :as cph]
[app.common.types.path.shape-to-path :as stp])) [app.common.types.path.shape-to-path :as stp]))
(defn path-editing?
"Returns true if we're editing a path or creating a new one."
[{local :workspace-local
drawing :workspace-drawing}]
(let [selected (:selected local)
edition (:edition local)
drawing-obj (:object drawing)
drawing-tool (:tool drawing)
edit-path? (dm/get-in local [:edit-path edition])
shape (or drawing-obj (first selected))
shape-id (:id shape)
single? (= (count selected) 1)
editing? (and (some? shape-id)
(some? edition)
(= shape-id edition))
;; we need to check if we're drawing a new object but we're
;; not using the pencil tool.
draw-path? (and (some? drawing-obj)
(cph/path-shape? drawing-obj)
(not= :curve drawing-tool))]
(or (and ^boolean single?
^boolean editing?
(and (not (cph/text-shape? shape))
(not (cph/frame-shape? shape))))
draw-path?
edit-path?)))
(defn get-path-id (defn get-path-id
"Retrieves the currently editing path id" "Retrieves the currently editing path id"
[state] [state]

View file

@ -22,9 +22,8 @@
(defn initialize-viewport (defn initialize-viewport
[{:keys [width height] :as size}] [{:keys [width height] :as size}]
(dm/assert! (assert (gpr/rect? size)
"expected `size` to be a rect instance" "expected `size` to be a rect instance")
(gpr/rect? size))
(letfn [(update* [{:keys [vport] :as local}] (letfn [(update* [{:keys [vport] :as local}]
(let [wprop (/ (:width vport) width) (let [wprop (/ (:width vport) width)

View file

@ -8,13 +8,11 @@
(:require (:require
[app.common.data :as d] [app.common.data :as d]
[app.common.data.macros :as dm] [app.common.data.macros :as dm]
[app.common.files.helpers :as cfh]
[app.common.geom.point :as gpt] [app.common.geom.point :as gpt]
[app.common.types.path :as path] [app.common.types.path :as path]
[app.common.types.path.helpers :as path.helpers] [app.common.types.path.helpers :as path.helpers]
[app.common.types.path.segment :as path.segment] [app.common.types.path.segment :as path.segment]
[app.main.data.workspace.path :as drp] [app.main.data.workspace.path :as drp]
[app.main.refs :as refs]
[app.main.snap :as snap] [app.main.snap :as snap]
[app.main.store :as st] [app.main.store :as st]
[app.main.streams :as ms] [app.main.streams :as ms]
@ -24,7 +22,6 @@
[app.util.keyboard :as kbd] [app.util.keyboard :as kbd]
[clojure.set :refer [map-invert]] [clojure.set :refer [map-invert]]
[goog.events :as events] [goog.events :as events]
[okulary.core :as l]
[rumext.v2 :as mf])) [rumext.v2 :as mf]))
(def point-radius 5) (def point-radius 5)
@ -261,18 +258,9 @@
angle (gpt/angle-with-other v1 v2)] angle (gpt/angle-with-other v1 v2)]
(<= (- 180 angle) 0.1)))) (<= (- 180 angle) 0.1))))
(defn- make-edit-path-ref [id]
(let [get-fn #(dm/get-in % [:edit-path id])]
(l/derived get-fn refs/workspace-local)))
(mf/defc path-editor* (mf/defc path-editor*
[{:keys [shape zoom]}] [{:keys [shape zoom state]}]
(let [hover-point (mf/use-state nil)
(let [shape-id (dm/get-prop shape :id)
edit-path-ref (mf/with-memo [shape-id]
(make-edit-path-ref shape-id))
hover-point (mf/use-state nil)
editor-ref (mf/use-ref nil) editor-ref (mf/use-ref nil)
{:keys [edit-mode {:keys [edit-mode
@ -286,19 +274,12 @@
moving-handler moving-handler
hover-handlers hover-handlers
hover-points hover-points
snap-toggled] snap-toggled]}
:as edit-path} state
(mf/deref edit-path-ref)
selected-points selected-points
(or selected-points #{}) (or selected-points #{})
shape
(mf/with-memo [shape]
(cond-> shape
(not (cfh/path-shape? shape))
(path/convert-to-path)))
base-content base-content
(get shape :content) (get shape :content)

View file

@ -7,14 +7,12 @@
(ns app.main.ui.workspace.top-toolbar (ns app.main.ui.workspace.top-toolbar
(:require-macros [app.main.style :as stl]) (:require-macros [app.main.style :as stl])
(:require (:require
[app.common.data.macros :as dm]
[app.common.geom.point :as gpt] [app.common.geom.point :as gpt]
[app.main.data.event :as ev] [app.main.data.event :as ev]
[app.main.data.modal :as modal] [app.main.data.modal :as modal]
[app.main.data.workspace :as dw] [app.main.data.workspace :as dw]
[app.main.data.workspace.common :as dwc] [app.main.data.workspace.common :as dwc]
[app.main.data.workspace.media :as dwm] [app.main.data.workspace.media :as dwm]
[app.main.data.workspace.path.state :as pst]
[app.main.data.workspace.shortcuts :as sc] [app.main.data.workspace.shortcuts :as sc]
[app.main.features :as features] [app.main.features :as features]
[app.main.refs :as refs] [app.main.refs :as refs]
@ -68,26 +66,31 @@
:ref ref :ref ref
:on-selected on-selected}]]])) :on-selected on-selected}]]]))
(def toolbar-hidden (def ^:private toolbar-hidden-ref
(l/derived (l/derived (fn [state]
(fn [state] (let [visibility (get state :hide-toolbar)
(let [visibility (dm/get-in state [:workspace-local :hide-toolbar]) path-edit-state (get state :edit-path)
editing? (pst/path-editing? state)
hidden? (if editing? true visibility)]
hidden?))
st/state))
(mf/defc top-toolbar selected (get state :selected)
{::mf/wrap [mf/memo] edition (get state :edition)
::mf/wrap-props false} single? (= (count selected) 1)
path-editing? (and single? (some? (get path-edit-state edition)))]
(if path-editing? true visibility)))
refs/workspace-local))
(mf/defc top-toolbar*
{::mf/memo true}
[{:keys [layout]}] [{:keys [layout]}]
(let [selected-drawtool (mf/deref refs/selected-drawing-tool) (let [drawtool (mf/deref refs/selected-drawing-tool)
edition (mf/deref refs/selected-edition) edition (mf/deref refs/selected-edition)
read-only? (mf/use-ctx ctx/workspace-read-only?) profile (mf/deref refs/profile)
props (get profile :props)
read-only? (mf/use-ctx ctx/workspace-read-only?)
rulers? (mf/deref refs/rulers?) rulers? (mf/deref refs/rulers?)
hide-toolbar? (mf/deref toolbar-hidden) hide-toolbar? (mf/deref toolbar-hidden-ref)
interrupt interrupt
(mf/use-fn #(st/emit! :interrupt (dw/clear-edition-mode))) (mf/use-fn #(st/emit! :interrupt (dw/clear-edition-mode)))
@ -121,8 +124,6 @@
(dom/blur! (dom/get-target event)) (dom/blur! (dom/get-target event))
(st/emit! (dwc/toggle-toolbar-visibility)))) (st/emit! (dwc/toggle-toolbar-visibility))))
profile (mf/deref refs/profile)
props (get profile :props)
test-tooltip-board-text test-tooltip-board-text
(if (not (:workspace-visited props)) (if (not (:workspace-visited props))
(tr "workspace.toolbar.frame-first-time" (sc/get-tooltip :draw-frame)) (tr "workspace.toolbar.frame-first-time" (sc/get-tooltip :draw-frame))
@ -139,7 +140,7 @@
{:title (tr "workspace.toolbar.move" (sc/get-tooltip :move)) {:title (tr "workspace.toolbar.move" (sc/get-tooltip :move))
:aria-label (tr "workspace.toolbar.move" (sc/get-tooltip :move)) :aria-label (tr "workspace.toolbar.move" (sc/get-tooltip :move))
:class (stl/css-case :main-toolbar-options-button true :class (stl/css-case :main-toolbar-options-button true
:selected (and (nil? selected-drawtool) :selected (and (nil? drawtool)
(not edition))) (not edition)))
:on-click interrupt} :on-click interrupt}
i/move]] i/move]]
@ -148,7 +149,7 @@
[:button [:button
{:title test-tooltip-board-text {:title test-tooltip-board-text
:aria-label (tr "workspace.toolbar.frame" (sc/get-tooltip :draw-frame)) :aria-label (tr "workspace.toolbar.frame" (sc/get-tooltip :draw-frame))
:class (stl/css-case :main-toolbar-options-button true :selected (= selected-drawtool :frame)) :class (stl/css-case :main-toolbar-options-button true :selected (= drawtool :frame))
:on-click select-drawtool :on-click select-drawtool
:data-tool "frame" :data-tool "frame"
:data-testid "artboard-btn"} :data-testid "artboard-btn"}
@ -157,7 +158,7 @@
[:button [:button
{:title (tr "workspace.toolbar.rect" (sc/get-tooltip :draw-rect)) {:title (tr "workspace.toolbar.rect" (sc/get-tooltip :draw-rect))
:aria-label (tr "workspace.toolbar.rect" (sc/get-tooltip :draw-rect)) :aria-label (tr "workspace.toolbar.rect" (sc/get-tooltip :draw-rect))
:class (stl/css-case :main-toolbar-options-button true :selected (= selected-drawtool :rect)) :class (stl/css-case :main-toolbar-options-button true :selected (= drawtool :rect))
:on-click select-drawtool :on-click select-drawtool
:data-tool "rect" :data-tool "rect"
:data-testid "rect-btn"} :data-testid "rect-btn"}
@ -166,7 +167,7 @@
[:button [:button
{:title (tr "workspace.toolbar.ellipse" (sc/get-tooltip :draw-ellipse)) {:title (tr "workspace.toolbar.ellipse" (sc/get-tooltip :draw-ellipse))
:aria-label (tr "workspace.toolbar.ellipse" (sc/get-tooltip :draw-ellipse)) :aria-label (tr "workspace.toolbar.ellipse" (sc/get-tooltip :draw-ellipse))
:class (stl/css-case :main-toolbar-options-button true :selected (= selected-drawtool :circle)) :class (stl/css-case :main-toolbar-options-button true :selected (= drawtool :circle))
:on-click select-drawtool :on-click select-drawtool
:data-tool "circle" :data-tool "circle"
:data-testid "ellipse-btn"} :data-testid "ellipse-btn"}
@ -175,7 +176,7 @@
[:button [:button
{:title (tr "workspace.toolbar.text" (sc/get-tooltip :draw-text)) {:title (tr "workspace.toolbar.text" (sc/get-tooltip :draw-text))
:aria-label (tr "workspace.toolbar.text" (sc/get-tooltip :draw-text)) :aria-label (tr "workspace.toolbar.text" (sc/get-tooltip :draw-text))
:class (stl/css-case :main-toolbar-options-button true :selected (= selected-drawtool :text)) :class (stl/css-case :main-toolbar-options-button true :selected (= drawtool :text))
:on-click select-drawtool :on-click select-drawtool
:data-tool "text"} :data-tool "text"}
i/text]] i/text]]
@ -186,7 +187,7 @@
[:button [:button
{:title (tr "workspace.toolbar.curve" (sc/get-tooltip :draw-curve)) {:title (tr "workspace.toolbar.curve" (sc/get-tooltip :draw-curve))
:aria-label (tr "workspace.toolbar.curve" (sc/get-tooltip :draw-curve)) :aria-label (tr "workspace.toolbar.curve" (sc/get-tooltip :draw-curve))
:class (stl/css-case :main-toolbar-options-button true :selected (= selected-drawtool :curve)) :class (stl/css-case :main-toolbar-options-button true :selected (= drawtool :curve))
:on-click select-drawtool :on-click select-drawtool
:data-tool "curve" :data-tool "curve"
:data-testid "curve-btn"} :data-testid "curve-btn"}
@ -195,7 +196,7 @@
[:button [:button
{:title (tr "workspace.toolbar.path" (sc/get-tooltip :draw-path)) {:title (tr "workspace.toolbar.path" (sc/get-tooltip :draw-path))
:aria-label (tr "workspace.toolbar.path" (sc/get-tooltip :draw-path)) :aria-label (tr "workspace.toolbar.path" (sc/get-tooltip :draw-path))
:class (stl/css-case :main-toolbar-options-button true :selected (= selected-drawtool :path)) :class (stl/css-case :main-toolbar-options-button true :selected (= drawtool :path))
:on-click select-drawtool :on-click select-drawtool
:data-tool "path" :data-tool "path"
:data-testid "path-btn"} :data-testid "path-btn"}

View file

@ -12,6 +12,8 @@
[app.common.data.macros :as dm] [app.common.data.macros :as dm]
[app.common.files.helpers :as cfh] [app.common.files.helpers :as cfh]
[app.common.geom.shapes :as gsh] [app.common.geom.shapes :as gsh]
[app.common.types.path :as path]
[app.common.types.shape :as cts]
[app.common.types.shape-tree :as ctt] [app.common.types.shape-tree :as ctt]
[app.common.types.shape.layout :as ctl] [app.common.types.shape.layout :as ctl]
[app.main.data.workspace.modifiers :as dwm] [app.main.data.workspace.modifiers :as dwm]
@ -29,6 +31,7 @@
[app.main.ui.workspace.shapes.text.text-edition-outline :refer [text-edition-outline]] [app.main.ui.workspace.shapes.text.text-edition-outline :refer [text-edition-outline]]
[app.main.ui.workspace.shapes.text.v2-editor :as editor-v2] [app.main.ui.workspace.shapes.text.v2-editor :as editor-v2]
[app.main.ui.workspace.shapes.text.viewport-texts-html :as stvh] [app.main.ui.workspace.shapes.text.viewport-texts-html :as stvh]
[app.main.ui.workspace.top-toolbar :refer [top-toolbar*]]
[app.main.ui.workspace.viewport-wasm :as viewport.wasm] [app.main.ui.workspace.viewport-wasm :as viewport.wasm]
[app.main.ui.workspace.viewport.actions :as actions] [app.main.ui.workspace.viewport.actions :as actions]
[app.main.ui.workspace.viewport.comments :as comments] [app.main.ui.workspace.viewport.comments :as comments]
@ -48,7 +51,7 @@
[app.main.ui.workspace.viewport.selection :as selection] [app.main.ui.workspace.viewport.selection :as selection]
[app.main.ui.workspace.viewport.snap-distances :as snap-distances] [app.main.ui.workspace.viewport.snap-distances :as snap-distances]
[app.main.ui.workspace.viewport.snap-points :as snap-points] [app.main.ui.workspace.viewport.snap-points :as snap-points]
[app.main.ui.workspace.viewport.top-bar :as top-bar] [app.main.ui.workspace.viewport.top-bar :refer [edition-bar*]]
[app.main.ui.workspace.viewport.utils :as utils] [app.main.ui.workspace.viewport.utils :as utils]
[app.main.ui.workspace.viewport.viewport-ref :refer [create-viewport-ref]] [app.main.ui.workspace.viewport.viewport-ref :refer [create-viewport-ref]]
[app.main.ui.workspace.viewport.widgets :as widgets] [app.main.ui.workspace.viewport.widgets :as widgets]
@ -88,12 +91,14 @@
vport vport
zoom zoom
zoom-inverse zoom-inverse
edition]} wlocal edition]}
wlocal
{:keys [options-mode {:keys [options-mode
tooltip tooltip
show-distances? show-distances?
picking-color?]} wglobal picking-color?]}
wglobal
vbox' (mf/use-debounce 100 vbox) vbox' (mf/use-debounce 100 vbox)
@ -127,7 +132,7 @@
mod? (mf/use-state false) mod? (mf/use-state false)
space? (mf/use-state false) space? (mf/use-state false)
z? (mf/use-state false) z? (mf/use-state false)
cursor (mf/use-state (utils/get-cursor :pointer-inner)) cursor (mf/use-state #(utils/get-cursor :pointer-inner))
hover-ids (mf/use-state nil) hover-ids (mf/use-state nil)
hover (mf/use-state nil) hover (mf/use-state nil)
measure-hover (mf/use-state nil) measure-hover (mf/use-state nil)
@ -137,8 +142,8 @@
active-frames (mf/use-state #{}) active-frames (mf/use-state #{})
;; REFS ;; REFS
[viewport-ref [viewport-ref on-viewport-ref]
on-viewport-ref] (create-viewport-ref) (create-viewport-ref)
;; VARS ;; VARS
disable-paste (mf/use-var false) disable-paste (mf/use-var false)
@ -163,34 +168,43 @@
selected-frames (into #{} (map :frame-id) selected-shapes) selected-frames (into #{} (map :frame-id) selected-shapes)
;; Only when we have all the selected shapes in one frame ;; Only when we have all the selected shapes in one frame
selected-frame (when (= (count selected-frames) 1) (get base-objects (first selected-frames))) selected-frame (when (= (count selected-frames) 1)
(get base-objects (first selected-frames)))
editing-shape (when edition (get base-objects edition)) edit-path-state (get edit-path edition)
edit-path-mode (get edit-path-state :edit-mode)
edit-path (get edit-path edition) path-editing? (some? edit-path-state)
edit-path-mode (get edit-path :edit-mode) path-drawing? (or (= edit-path-mode :draw)
(and (= :path (get drawing-obj :type))
(not= :curve drawing-tool)))
editing-shape (when edition
(get base-objects edition))
editing-shape (mf/with-memo [editing-shape path-editing? base-objects]
(if path-editing?
(path/convert-to-path editing-shape base-objects)
editing-shape))
create-comment? (= :comments drawing-tool) create-comment? (= :comments drawing-tool)
drawing-path? (or (= edit-path-mode :draw)
(= :path (get drawing-obj :type)))
node-editing? (cfh/path-shape? editing-shape)
text-editing? (cfh/text-shape? editing-shape) text-editing? (cfh/text-shape? editing-shape)
grid-editing? (and edition (ctl/grid-layout? base-objects edition)) grid-editing? (and edition (ctl/grid-layout? base-objects edition))
mode-inspect? (= options-mode :inspect) mode-inspect? (= options-mode :inspect)
on-click (actions/on-click hover selected edition drawing-path? drawing-tool space? selrect z?) on-click (actions/on-click hover selected edition path-drawing? drawing-tool space? selrect z?)
on-context-menu (actions/on-context-menu hover hover-ids read-only?) on-context-menu (actions/on-context-menu hover hover-ids read-only?)
on-double-click (actions/on-double-click hover hover-ids hover-top-frame-id drawing-path? base-objects edition drawing-tool z? read-only?) on-double-click (actions/on-double-click hover hover-ids hover-top-frame-id path-drawing? base-objects edition drawing-tool z? read-only?)
comp-inst-ref (mf/use-ref false) comp-inst-ref (mf/use-ref false)
on-drag-enter (actions/on-drag-enter comp-inst-ref) on-drag-enter (actions/on-drag-enter comp-inst-ref)
on-drag-over (actions/on-drag-over move-stream) on-drag-over (actions/on-drag-over move-stream)
on-drag-end (actions/on-drag-over comp-inst-ref) on-drag-end (actions/on-drag-over comp-inst-ref)
on-drop (actions/on-drop file comp-inst-ref) on-drop (actions/on-drop file comp-inst-ref)
on-pointer-down (actions/on-pointer-down @hover selected edition drawing-tool text-editing? node-editing? grid-editing? on-pointer-down (actions/on-pointer-down @hover selected edition drawing-tool text-editing? path-editing? grid-editing?
drawing-path? create-comment? space? panning z? read-only?) path-drawing? create-comment? space? panning z? read-only?)
on-pointer-up (actions/on-pointer-up disable-paste) on-pointer-up (actions/on-pointer-up disable-paste)
@ -236,14 +250,14 @@
(or drawing-obj transform)) (or drawing-obj transform))
show-selrect? (and selrect (empty? drawing) (not text-editing?)) show-selrect? (and selrect (empty? drawing) (not text-editing?))
show-measures? (and (not transform) show-measures? (and (not transform)
(not node-editing?) (not path-editing?)
(or show-distances? mode-inspect? read-only?)) (or show-distances? mode-inspect? read-only?))
show-artboard-names? (contains? layout :display-artboard-names) show-artboard-names? (contains? layout :display-artboard-names)
hide-ui? (contains? layout :hide-ui) hide-ui? (contains? layout :hide-ui)
show-rulers? (and (contains? layout :rulers) (not hide-ui?)) show-rulers? (and (contains? layout :rulers) (not hide-ui?))
disabled-guides? (or drawing-tool transform drawing-path? node-editing?) disabled-guides? (or drawing-tool transform path-drawing? path-editing?)
single-select? (= (count selected-shapes) 1) single-select? (= (count selected-shapes) 1)
@ -276,24 +290,30 @@
rule-area-size (/ rulers/ruler-area-size zoom)] rule-area-size (/ rulers/ruler-area-size zoom)]
(hooks/setup-dom-events zoom disable-paste in-viewport? read-only? drawing-tool drawing-path?) (hooks/setup-dom-events zoom disable-paste in-viewport? read-only? drawing-tool path-drawing?)
(hooks/setup-viewport-size vport viewport-ref) (hooks/setup-viewport-size vport viewport-ref)
(hooks/setup-cursor cursor alt? mod? space? panning drawing-tool drawing-path? node-editing? z? read-only?) (hooks/setup-cursor cursor alt? mod? space? panning drawing-tool path-drawing? path-editing? z? read-only?)
(hooks/setup-keyboard alt? mod? space? z? shift?) (hooks/setup-keyboard alt? mod? space? z? shift?)
(hooks/setup-hover-shapes page-id move-stream base-objects transform selected mod? hover measure-hover (hooks/setup-hover-shapes page-id move-stream base-objects transform selected mod? hover measure-hover
hover-ids hover-top-frame-id @hover-disabled? focus zoom show-measures?) hover-ids hover-top-frame-id @hover-disabled? focus zoom show-measures?)
(hooks/setup-viewport-modifiers modifiers base-objects) (hooks/setup-viewport-modifiers modifiers base-objects)
(hooks/setup-shortcuts node-editing? drawing-path? text-editing? grid-editing?) (hooks/setup-shortcuts path-editing? path-drawing? text-editing? grid-editing?)
(hooks/setup-active-frames base-objects hover-ids selected active-frames zoom transform vbox) (hooks/setup-active-frames base-objects hover-ids selected active-frames zoom transform vbox)
[:div {:class (stl/css :viewport) :style #js {"--zoom" zoom} :data-testid "viewport"} [:div {:class (stl/css :viewport) :style #js {"--zoom" zoom} :data-testid "viewport"}
(when (:can-edit permissions) (when (:can-edit permissions)
[:> top-bar/top-bar* {:layout layout [:*
:selected selected-shapes (when-not hide-ui?
:edit-path edit-path [:> top-toolbar* {:layout layout}])
:drawing drawing
:edition edition (when single-select?
:is-read-only read-only?}]) [:> edition-bar* {:shape editing-shape
:is-path-edition path-editing?
:is-grid-edition grid-editing?
:is-read-only read-only?
:edit-path-state edit-path-state
:layout layout}])])
[:div {:class (stl/css :viewport-overlays)} [:div {:class (stl/css :viewport-overlays)}
;; The behaviour inside a foreign object is a bit different that in plain HTML so we wrap ;; The behaviour inside a foreign object is a bit different that in plain HTML so we wrap
;; inside a foreign object "dummy" so this awkward behaviour is take into account ;; inside a foreign object "dummy" so this awkward behaviour is take into account
@ -512,7 +532,8 @@
:on-frame-leave on-frame-leave :on-frame-leave on-frame-leave
:on-frame-select on-frame-select}]) :on-frame-select on-frame-select}])
(when show-draw-area? (when (and ^boolean show-draw-area?
^boolean (cts/shape? drawing-obj))
[:> drawarea/draw-area* [:> drawarea/draw-area*
{:shape drawing-obj {:shape drawing-obj
:zoom zoom :zoom zoom
@ -618,6 +639,7 @@
(when-not text-editing? (when-not text-editing?
(if editing-shape (if editing-shape
[:> path-editor* {:shape editing-shape [:> path-editor* {:shape editing-shape
:state edit-path-state
:zoom zoom}] :zoom zoom}]
(when selected-shapes (when selected-shapes
[:> selection/handlers* [:> selection/handlers*

View file

@ -7,13 +7,19 @@
(ns app.main.ui.workspace.viewport.drawarea (ns app.main.ui.workspace.viewport.drawarea
"Drawing components." "Drawing components."
(:require (:require
[app.common.data.macros :as dm]
[app.common.math :as mth] [app.common.math :as mth]
[app.common.types.shape :as cts] [app.main.refs :as refs]
[app.main.ui.shapes.path :refer [path-shape]] [app.main.ui.shapes.path :refer [path-shape]]
[app.main.ui.workspace.shapes :as shapes] [app.main.ui.workspace.shapes :as shapes]
[app.main.ui.workspace.shapes.path.editor :refer [path-editor*]] [app.main.ui.workspace.shapes.path.editor :refer [path-editor*]]
[okulary.core :as l]
[rumext.v2 :as mf])) [rumext.v2 :as mf]))
(defn- make-edit-path-ref [id]
(let [get-fn #(dm/get-in % [:edit-path id])]
(l/derived get-fn refs/workspace-local)))
(mf/defc generic-draw-area* (mf/defc generic-draw-area*
{::mf/private true} {::mf/private true}
[{:keys [shape zoom]}] [{:keys [shape zoom]}]
@ -29,17 +35,32 @@
:fill "none" :fill "none"
:stroke-width (/ 1 zoom)}}]))) :stroke-width (/ 1 zoom)}}])))
(mf/defc path-draw-area*
{::mf/private true}
[{:keys [shape] :as props}]
(let [shape-id
(dm/get-prop shape :id)
edit-path-ref
(mf/with-memo [shape-id]
(make-edit-path-ref shape-id))
edit-path-state
(mf/deref edit-path-ref)
props
(mf/spread-props props {:state edit-path-state})]
[:> path-editor* props]))
(mf/defc draw-area* (mf/defc draw-area*
[{:keys [shape zoom tool] :as props}] [{:keys [shape zoom tool] :as props}]
;; Prevent rendering something that it's not a shape.
(when (cts/shape? shape)
[:g.draw-area [:g.draw-area
[:g {:style {:pointer-events "none"}} [:g {:style {:pointer-events "none"}}
[:& shapes/shape-wrapper {:shape shape}]] [:& shapes/shape-wrapper {:shape shape}]]
(case tool (case tool
:path [:> path-editor* props] :path [:> path-draw-area* props]
:curve [:& path-shape {:shape shape :zoom zoom}] :curve [:& path-shape {:shape shape :zoom zoom}]
#_:default [:> generic-draw-area* props])])) #_:default [:> generic-draw-area* props])])

View file

@ -67,8 +67,8 @@
:separate-nodes segments-selected?}))) :separate-nodes segments-selected?})))
(mf/defc path-actions* (mf/defc path-actions*
[{:keys [shape edit-path]}] [{:keys [shape state]}]
(let [{:keys [edit-mode selected-points snap-toggled]} edit-path (let [{:keys [edit-mode selected-points snap-toggled]} state
content (:content shape) content (:content shape)

View file

@ -7,19 +7,20 @@
(ns app.main.ui.workspace.viewport.top-bar (ns app.main.ui.workspace.viewport.top-bar
(:require-macros [app.main.style :as stl]) (:require-macros [app.main.style :as stl])
(:require (:require
[app.common.data.macros :as dm]
[app.common.files.helpers :as cfh]
[app.common.types.shape.layout :as ctl]
[app.main.data.workspace :as dw] [app.main.data.workspace :as dw]
[app.main.data.workspace.common :as dwc] [app.main.data.workspace.common :as dwc]
[app.main.store :as st] [app.main.store :as st]
[app.main.ui.workspace.top-toolbar :refer [top-toolbar]]
[app.main.ui.workspace.viewport.grid-layout-editor :refer [grid-edition-actions]] [app.main.ui.workspace.viewport.grid-layout-editor :refer [grid-edition-actions]]
[app.main.ui.workspace.viewport.path-actions :refer [path-actions*]] [app.main.ui.workspace.viewport.path-actions :refer [path-actions*]]
[app.util.i18n :as i18n :refer [tr]] [app.util.i18n :as i18n :refer [tr]]
[rumext.v2 :as mf])) [rumext.v2 :as mf]))
;; FIXME: this namespace should be renamed and all translation files
;; should also be renamed. But this should be done on development
;; branch.
(mf/defc view-only-actions* (mf/defc view-only-actions*
{::mf/private true}
[] []
(let [handle-close-view-mode (let [handle-close-view-mode
(mf/use-fn (mf/use-fn
@ -37,35 +38,8 @@
:on-click handle-close-view-mode} :on-click handle-close-view-mode}
(tr "workspace.top-bar.read-only.done")]]])) (tr "workspace.top-bar.read-only.done")]]]))
(mf/defc top-bar* (mf/defc edition-bar*
[{:keys [layout drawing is-read-only edition selected edit-path]}] [{:keys [layout is-read-only edit-path-state is-grid-edition is-path-edition shape]}]
(let [rulers? (contains? layout :rulers)
hide-ui? (contains? layout :hide-ui)
drawing-obj (get drawing :object)
shape (or drawing-obj (-> selected first))
shape-id (dm/get-prop shape :id)
single? (= (count selected) 1)
editing? (= shape-id edition)
draw-path? (and (some? drawing-obj)
(cfh/path-shape? drawing-obj)
(not= :curve (:tool drawing)))
is-path-edition
(or (and single? editing?
(and (not (cfh/text-shape? shape))
(not (cfh/frame-shape? shape))))
draw-path?)
grid-edition?
(and single? editing? (ctl/grid-layout? shape))]
[:*
(when-not ^boolean hide-ui?
[:& top-toolbar {:layout layout}])
(cond (cond
^boolean ^boolean
is-read-only is-read-only
@ -73,8 +47,13 @@
^boolean ^boolean
is-path-edition is-path-edition
[:div {:class (stl/css-case :viewport-actions-path true :viewport-actions-no-rulers (not rulers?))}
[:> path-actions* {:shape shape :edit-path edit-path}]]
grid-edition? (let [rulers? (contains? layout :rulers)
[:& grid-edition-actions {:shape shape}])])) class (stl/css-case
:viewport-actions-path true
:viewport-actions-no-rulers (not rulers?))]
[:div {:class class}
[:> path-actions* {:shape shape :state edit-path-state}]])
is-grid-edition
[:& grid-edition-actions {:shape shape}]))

View file

@ -12,6 +12,7 @@
[app.common.data.macros :as dm] [app.common.data.macros :as dm]
[app.common.files.helpers :as cfh] [app.common.files.helpers :as cfh]
[app.common.geom.shapes :as gsh] [app.common.geom.shapes :as gsh]
[app.common.types.path :as path]
[app.common.types.shape :as cts] [app.common.types.shape :as cts]
[app.common.types.shape-tree :as ctt] [app.common.types.shape-tree :as ctt]
[app.common.types.shape.layout :as ctl] [app.common.types.shape.layout :as ctl]
@ -27,6 +28,7 @@
[app.main.ui.workspace.shapes.text.editor :as editor-v1] [app.main.ui.workspace.shapes.text.editor :as editor-v1]
[app.main.ui.workspace.shapes.text.text-edition-outline :refer [text-edition-outline]] [app.main.ui.workspace.shapes.text.text-edition-outline :refer [text-edition-outline]]
[app.main.ui.workspace.shapes.text.v2-editor :as editor-v2] [app.main.ui.workspace.shapes.text.v2-editor :as editor-v2]
[app.main.ui.workspace.top-toolbar :refer [top-toolbar*]]
[app.main.ui.workspace.viewport.actions :as actions] [app.main.ui.workspace.viewport.actions :as actions]
[app.main.ui.workspace.viewport.comments :as comments] [app.main.ui.workspace.viewport.comments :as comments]
[app.main.ui.workspace.viewport.debug :as wvd] [app.main.ui.workspace.viewport.debug :as wvd]
@ -45,7 +47,7 @@
[app.main.ui.workspace.viewport.selection :as selection] [app.main.ui.workspace.viewport.selection :as selection]
[app.main.ui.workspace.viewport.snap-distances :as snap-distances] [app.main.ui.workspace.viewport.snap-distances :as snap-distances]
[app.main.ui.workspace.viewport.snap-points :as snap-points] [app.main.ui.workspace.viewport.snap-points :as snap-points]
[app.main.ui.workspace.viewport.top-bar :as top-bar] [app.main.ui.workspace.viewport.top-bar :refer [edition-bar*]]
[app.main.ui.workspace.viewport.utils :as utils] [app.main.ui.workspace.viewport.utils :as utils]
[app.main.ui.workspace.viewport.viewport-ref :refer [create-viewport-ref]] [app.main.ui.workspace.viewport.viewport-ref :refer [create-viewport-ref]]
[app.main.ui.workspace.viewport.widgets :as widgets] [app.main.ui.workspace.viewport.widgets :as widgets]
@ -162,38 +164,45 @@
drawing-tool (:tool drawing) drawing-tool (:tool drawing)
drawing-obj (:object drawing) drawing-obj (:object drawing)
selected-frames (into #{} (map :frame-id) selected-shapes) selected-frames (into #{} (map :frame-id) selected-shapes)
;; Only when we have all the selected shapes in one frame ;; Only when we have all the selected shapes in one frame
selected-frame (when (= (count selected-frames) 1) (get base-objects (first selected-frames))) selected-frame (when (= (count selected-frames) 1) (get base-objects (first selected-frames)))
editing-shape (when edition (get base-objects edition)) edit-path-state (get edit-path edition)
edit-path-mode (get edit-path-state :edit-mode)
edit-path (get edit-path edition) path-editing? (some? edit-path-state)
edit-path-mode (get edit-path :edit-mode) path-drawing? (or (= edit-path-mode :draw)
(and (= :path (get drawing-obj :type))
(not= :curve drawing-tool)))
editing-shape (when edition
(get base-objects edition))
editing-shape (mf/with-memo [editing-shape path-editing? base-objects]
(if path-editing?
(path/convert-to-path editing-shape base-objects)
editing-shape))
create-comment? (= :comments drawing-tool) create-comment? (= :comments drawing-tool)
drawing-path? (or (= edit-path-mode :draw)
(= :path (get drawing-obj :type)))
node-editing? (cfh/path-shape? editing-shape)
text-editing? (cfh/text-shape? editing-shape) text-editing? (cfh/text-shape? editing-shape)
grid-editing? (and edition (ctl/grid-layout? base-objects edition)) grid-editing? (and edition (ctl/grid-layout? base-objects edition))
mode-inspect? (= options-mode :inspect) mode-inspect? (= options-mode :inspect)
on-click (actions/on-click hover selected edition drawing-path? drawing-tool space? selrect z?) on-click (actions/on-click hover selected edition path-drawing? drawing-tool space? selrect z?)
on-context-menu (actions/on-context-menu hover hover-ids read-only?) on-context-menu (actions/on-context-menu hover hover-ids read-only?)
on-double-click (actions/on-double-click hover hover-ids hover-top-frame-id drawing-path? base-objects edition drawing-tool z? read-only?) on-double-click (actions/on-double-click hover hover-ids hover-top-frame-id path-drawing? base-objects edition drawing-tool z? read-only?)
comp-inst-ref (mf/use-ref false) comp-inst-ref (mf/use-ref false)
on-drag-enter (actions/on-drag-enter comp-inst-ref) on-drag-enter (actions/on-drag-enter comp-inst-ref)
on-drag-over (actions/on-drag-over move-stream) on-drag-over (actions/on-drag-over move-stream)
on-drag-end (actions/on-drag-over comp-inst-ref) on-drag-end (actions/on-drag-over comp-inst-ref)
on-drop (actions/on-drop file comp-inst-ref) on-drop (actions/on-drop file comp-inst-ref)
on-pointer-down (actions/on-pointer-down @hover selected edition drawing-tool text-editing? node-editing? grid-editing? on-pointer-down (actions/on-pointer-down @hover selected edition drawing-tool text-editing? path-editing? grid-editing?
drawing-path? create-comment? space? panning z? read-only?) path-drawing? create-comment? space? panning z? read-only?)
on-pointer-up (actions/on-pointer-up disable-paste) on-pointer-up (actions/on-pointer-up disable-paste)
@ -239,14 +248,14 @@
(or drawing-obj transform)) (or drawing-obj transform))
show-selrect? (and selrect (empty? drawing) (not text-editing?)) show-selrect? (and selrect (empty? drawing) (not text-editing?))
show-measures? (and (not transform) show-measures? (and (not transform)
(not node-editing?) (not path-editing?)
(or show-distances? mode-inspect?)) (or show-distances? mode-inspect?))
show-artboard-names? (contains? layout :display-artboard-names) show-artboard-names? (contains? layout :display-artboard-names)
hide-ui? (contains? layout :hide-ui) hide-ui? (contains? layout :hide-ui)
show-rulers? (and (contains? layout :rulers) (not hide-ui?)) show-rulers? (and (contains? layout :rulers) (not hide-ui?))
disabled-guides? (or drawing-tool transform drawing-path? node-editing?) disabled-guides? (or drawing-tool transform path-drawing? path-editing?)
single-select? (= (count selected-shapes) 1) single-select? (= (count selected-shapes) 1)
@ -329,23 +338,27 @@
(when (and @canvas-init? initialized?) (when (and @canvas-init? initialized?)
(wasm.api/set-canvas-background background))) (wasm.api/set-canvas-background background)))
(hooks/setup-dom-events zoom disable-paste in-viewport? read-only? drawing-tool drawing-path?) (hooks/setup-dom-events zoom disable-paste in-viewport? read-only? drawing-tool path-drawing?)
(hooks/setup-viewport-size vport viewport-ref) (hooks/setup-viewport-size vport viewport-ref)
(hooks/setup-cursor cursor alt? mod? space? panning drawing-tool drawing-path? node-editing? z? read-only?) (hooks/setup-cursor cursor alt? mod? space? panning drawing-tool path-drawing? path-editing? z? read-only?)
(hooks/setup-keyboard alt? mod? space? z? shift?) (hooks/setup-keyboard alt? mod? space? z? shift?)
(hooks/setup-hover-shapes page-id move-stream base-objects transform selected mod? hover measure-hover (hooks/setup-hover-shapes page-id move-stream base-objects transform selected mod? hover measure-hover
hover-ids hover-top-frame-id @hover-disabled? focus zoom show-measures?) hover-ids hover-top-frame-id @hover-disabled? focus zoom show-measures?)
(hooks/setup-shortcuts node-editing? drawing-path? text-editing? grid-editing?) (hooks/setup-shortcuts path-editing? path-drawing? text-editing? grid-editing?)
(hooks/setup-active-frames base-objects hover-ids selected active-frames zoom transform vbox) (hooks/setup-active-frames base-objects hover-ids selected active-frames zoom transform vbox)
[:div {:class (stl/css :viewport) :style #js {"--zoom" zoom} :data-testid "viewport"} [:div {:class (stl/css :viewport) :style #js {"--zoom" zoom} :data-testid "viewport"}
(when (:can-edit permissions) (when (:can-edit permissions)
[:> top-bar/top-bar* {:layout layout [:*
(when-not hide-ui?
[:> top-toolbar* {:layout layout}])
[:> edition-bar* {:layout layout
:selected selected-shapes :selected selected-shapes
:edit-path edit-path :edit-path edit-path-state
:drawing drawing :drawing drawing
:edition edition :edition edition
:is-read-only read-only?}]) :is-read-only read-only?}]])
[:div {:class (stl/css :viewport-overlays)} [:div {:class (stl/css :viewport-overlays)}
(when show-comments? (when show-comments?
[:> comments/comments-layer* {:vbox vbox [:> comments/comments-layer* {:vbox vbox
@ -509,7 +522,8 @@
:on-frame-leave on-frame-leave :on-frame-leave on-frame-leave
:on-frame-select on-frame-select}]) :on-frame-select on-frame-select}])
(when show-draw-area? (when (and ^boolean show-draw-area?
^boolean (cts/shape? drawing-obj))
[:> drawarea/draw-area* [:> drawarea/draw-area*
{:shape drawing-obj {:shape drawing-obj
:zoom zoom :zoom zoom
@ -615,6 +629,7 @@
(when-not text-editing? (when-not text-editing?
(if editing-shape (if editing-shape
[:> path-editor* {:shape editing-shape [:> path-editor* {:shape editing-shape
:state edit-path-state
:zoom zoom}] :zoom zoom}]
(when selected-shapes (when selected-shapes
[:> selection/handlers* [:> selection/handlers*