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

 Add missing fixes to the path edition mode
This commit is contained in:
Alejandro Alonso 2025-06-20 11:31:17 +02:00 committed by GitHub
commit 3d0c3013e5
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 116 additions and 104 deletions

View file

@ -31,8 +31,23 @@
[beicon.v2.core :as rx]
[potok.v2.core :as ptk]))
(declare close-path-drag-end)
(declare check-changed-content)
(declare change-edit-mode)
(defn- end-path-event?
[event]
(let [type (ptk/type event)]
(or
(= type ::common/finish-path)
(= type :app.main.data.workspace.path.shortcuts/esc-pressed)
(= type :app.main.data.workspace.common/clear-edition-mode)
(= type :app.main.data.workspace.edition/clear-edition-mode)
(= type :app.main.data.workspace/finalize-page)
(= event :interrupt) ;; ESC
(and ^boolean (mse/mouse-event? event)
^boolean (mse/mouse-double-click-event? event)))))
(defn preview-next-point
[{:keys [x y shift?]}]
(ptk/reify ::preview-next-point
@ -126,8 +141,6 @@
(rx/of (preview-next-point handler)
(undo/merge-head))))))
(declare close-path-drag-end)
(defn close-path-drag-start
[position]
(ptk/reify ::close-path-drag-start
@ -146,8 +159,7 @@
(rx/take-until
(rx/merge
(mse/drag-stopper stream)
(->> stream
(rx/filter helpers/end-path-event?)))))]
(rx/filter end-path-event? stream))))]
(rx/concat
(rx/of (add-node position))
@ -171,8 +183,7 @@
(watch [_ state stream]
(let [stopper (rx/merge
(mse/drag-stopper stream)
(->> stream
(rx/filter helpers/end-path-event?)))
(rx/filter end-path-event? stream))
drag-events (->> (streams/position-stream state)
(rx/map #(drag-handler %))
@ -199,8 +210,7 @@
(let [stopper (rx/merge
(mse/drag-stopper stream)
(->> stream
(rx/filter helpers/end-path-event?)))
(rx/filter end-path-event? stream))
drag-events
(->> (streams/position-stream state)
@ -230,7 +240,7 @@
end-stream
(->> stream
(rx/filter helpers/end-path-event?)
(rx/filter end-path-event?)
(rx/share))
stoper-stream
@ -241,8 +251,7 @@
;; Mouse move preview
mousemove-events
(->> (streams/position-stream state)
(rx/map #(preview-next-point %))
(rx/take-until end-stream))
(rx/map #(preview-next-point %)))
;; From mouse down we can have: click, drag and double click
mousedown-events
@ -256,18 +265,15 @@
(make-drag-stream state stream %)))
(rx/take-until end-stream))]
(rx/concat
(rx/of (undo/start-path-undo))
(rx/of (common/init-path))
(->> (rx/merge mousemove-events
mousedown-events)
(rx/take-until stoper-stream))
(->> (rx/concat
(rx/of (undo/start-path-undo))
(->> (rx/merge mousemove-events
mousedown-events)
(rx/take-until stoper-stream))
(rx/of (ptk/data-event ::end-edition))))))))
;; 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/UpdateEvent
(update [_ state]
@ -332,14 +338,15 @@
(rx/concat
(rx/of (start-edition shape-id))
(->> stream
(rx/filter (ptk/type? ::common/finish-path))
(rx/filter (ptk/type? ::end-edition))
(rx/take 1)
(rx/observe-on :async)
(rx/map (partial handle-drawing-end shape-id))))))))
(declare check-changed-content)
(declare start-draw-mode*)
(defn start-draw-mode []
(defn start-draw-mode
[]
(ptk/reify ::start-draw-mode
ptk/UpdateEvent
(update [_ state]
@ -350,36 +357,31 @@
(update-in state [:workspace-local :edit-path id] assoc :old-content content)
state)))
ptk/WatchEvent
(watch [_ _ _]
(rx/of (start-draw-mode*)))))
(defn start-draw-mode*
[]
(ptk/reify ::start-draw-mode*
ptk/WatchEvent
(watch [_ state stream]
(let [id (get-in state [:workspace-local :edition])
edit-mode (get-in state [:workspace-local :edit-path id :edit-mode])]
(if (= :draw edit-mode)
(let [local (get state :workspace-local)
id (get local :edition)
mode (dm/get-in local [:edit-path id :edit-mode])]
(if (= :draw mode)
(rx/concat
(rx/of (dwsh/update-shapes [id] path/convert-to-path))
(rx/of (start-edition id))
(->> stream
(rx/filter (ptk/type? ::common/finish-path))
(rx/filter (ptk/type? ::end-edition))
(rx/take 1)
(rx/map check-changed-content)))
(rx/mapcat (fn [_]
(rx/of (check-changed-content)
(start-draw-mode*))))))
(rx/empty))))))
(defn check-changed-content []
(ptk/reify ::check-changed-content
ptk/WatchEvent
(watch [_ state _]
(let [id (st/get-path-id state)
content (st/get-path state :content)
old-content (get-in state [:workspace-local :edit-path id :old-content])
mode (get-in state [:workspace-local :edit-path id :edit-mode])
empty-content? (empty? content)]
(cond
(and (not= content old-content) (not empty-content?)) (rx/of (changes/save-path-content))
(= mode :draw) (rx/of :interrupt)
:else (rx/of
(common/finish-path)
(dwdc/clear-drawing)))))))
(defn change-edit-mode
[mode]
(ptk/reify ::change-edit-mode
@ -406,3 +408,25 @@
(let [id (st/get-path-id state)]
(assoc-in state [:workspace-local :edit-path id :prev-handler] nil)))))
(defn check-changed-content
[]
(ptk/reify ::check-changed-content
ptk/WatchEvent
(watch [_ state _]
(let [id (st/get-path-id state)
content (st/get-path state :content)
old-content (get-in state [:workspace-local :edit-path id :old-content])
mode (get-in state [:workspace-local :edit-path id :edit-mode])
empty-content? (empty? content)]
(cond
(and (not= content old-content) (not empty-content?))
(rx/of (changes/save-path-content))
(= mode :draw)
(rx/of :interrupt)
:else
(rx/of
(common/finish-path)
(dwdc/clear-drawing)))))))

View file

@ -10,22 +10,7 @@
[app.common.math :as mth]
[app.common.types.path :as path]
[app.common.types.path.helpers :as path.helpers]
[app.common.types.path.segment :as path.segment]
[app.main.data.workspace.path.common :as common]
[app.util.mouse :as mse]
[potok.v2.core :as ptk]))
(defn end-path-event?
[event]
(let [type (ptk/type event)]
(or (= type ::common/finish-path)
(= type :app.main.data.workspace.path.shortcuts/esc-pressed)
(= type :app.main.data.workspace.common/clear-edition-mode)
(= type :app.main.data.workspace.edition/clear-edition-mode)
(= type :app.main.data.workspace/finalize-page)
(= event :interrupt) ;; ESC
(and ^boolean (mse/mouse-event? event)
^boolean (mse/mouse-double-click-event? event)))))
[app.common.types.path.segment :as path.segment]))
(defn append-node
"Creates a new node in the path. Usually used when drawing."

View file

@ -51,7 +51,7 @@
[app.main.ui.workspace.viewport.selection :as selection]
[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.top-bar :refer [edition-bar*]]
[app.main.ui.workspace.viewport.top-bar :refer [path-edition-bar* grid-edition-bar* view-only-bar*]]
[app.main.ui.workspace.viewport.utils :as utils]
[app.main.ui.workspace.viewport.viewport-ref :refer [create-viewport-ref]]
[app.main.ui.workspace.viewport.widgets :as widgets]
@ -302,17 +302,21 @@
[:div {:class (stl/css :viewport) :style #js {"--zoom" zoom} :data-testid "viewport"}
(when (:can-edit permissions)
[:*
(when-not hide-ui?
[:> top-toolbar* {:layout layout}])
(if read-only?
[:> view-only-bar* {}]
[:*
(when-not hide-ui?
[:> top-toolbar* {:layout layout}])
(when single-select?
[:> 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}])])
(when (and ^boolean path-editing?
^boolean single-select?)
[:> path-edition-bar* {:shape editing-shape
:edit-path-state edit-path-state
:layout layout}])
(when (and ^boolean grid-editing?
^boolean single-select?)
[:> grid-edition-bar* {:shape editing-shape}])]))
[:div {:class (stl/css :viewport-overlays)}
;; The behaviour inside a foreign object is a bit different that in plain HTML so we wrap
@ -637,7 +641,7 @@
(when show-selection-handlers?
[:g.selection-handlers {:clipPath "url(#clip-handlers)"}
(when-not text-editing?
(if editing-shape
(if (and editing-shape path-editing?)
[:> path-editor* {:shape editing-shape
:state edit-path-state
:zoom zoom}]

View file

@ -19,7 +19,7 @@
;; should also be renamed. But this should be done on development
;; branch.
(mf/defc view-only-actions*
(mf/defc view-only-bar*
{::mf/private true}
[]
(let [handle-close-view-mode
@ -38,22 +38,15 @@
:on-click handle-close-view-mode}
(tr "workspace.top-bar.read-only.done")]]]))
(mf/defc edition-bar*
[{:keys [layout is-read-only edit-path-state is-grid-edition is-path-edition shape]}]
(cond
^boolean
is-read-only
[:> view-only-actions*]
(mf/defc path-edition-bar*
[{:keys [layout edit-path-state shape]}]
(let [rulers? (contains? layout :rulers)
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}]]))
^boolean
is-path-edition
(let [rulers? (contains? layout :rulers)
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}]))
(mf/defc grid-edition-bar*
[{:keys [shape]}]
[:& grid-edition-actions {:shape shape}])

View file

@ -47,7 +47,7 @@
[app.main.ui.workspace.viewport.selection :as selection]
[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.top-bar :refer [edition-bar*]]
[app.main.ui.workspace.viewport.top-bar :refer [path-edition-bar* grid-edition-bar* view-only-bar*]]
[app.main.ui.workspace.viewport.utils :as utils]
[app.main.ui.workspace.viewport.viewport-ref :refer [create-viewport-ref]]
[app.main.ui.workspace.viewport.widgets :as widgets]
@ -349,16 +349,22 @@
[:div {:class (stl/css :viewport) :style #js {"--zoom" zoom} :data-testid "viewport"}
(when (:can-edit permissions)
[:*
(when-not hide-ui?
[:> top-toolbar* {:layout layout}])
(if read-only?
[:> view-only-bar* {}]
[:*
(when-not hide-ui?
[:> top-toolbar* {:layout layout}])
(when (and ^boolean path-editing?
^boolean single-select?)
[:> path-edition-bar* {:shape editing-shape
:edit-path-state edit-path-state
:layout layout}])
(when (and ^boolean grid-editing?
^boolean single-select?)
[:> grid-edition-bar* {:shape editing-shape}])]))
[:> edition-bar* {:layout layout
:selected selected-shapes
:edit-path edit-path-state
:drawing drawing
:edition edition
:is-read-only read-only?}]])
[:div {:class (stl/css :viewport-overlays)}
(when show-comments?
[:> comments/comments-layer* {:vbox vbox
@ -627,7 +633,7 @@
(when show-selection-handlers?
[:g.selection-handlers {:clipPath "url(#clip-handlers)"}
(when-not text-editing?
(if editing-shape
(if (and editing-shape path-editing?)
[:> path-editor* {:shape editing-shape
:state edit-path-state
:zoom zoom}]