0
Fork 0
mirror of https://github.com/penpot/penpot.git synced 2025-04-01 09:31:26 -05:00

🐛 Fixed issues with text selection and edition

This commit is contained in:
alonso.torres 2021-01-21 16:09:13 +01:00 committed by Andrey Antukh
parent 40e54dbbd4
commit 86936a66e0
9 changed files with 164 additions and 109 deletions

View file

@ -50,7 +50,7 @@
(when (and wrapper
(not allow-click-outside)
(not (.contains wrapper current))
(not (= type (keyword (.getAttribute current "data-allow-click-modal")))))
(not (= type (keyword (dom/get-data current "allow-click-modal")))))
(dom/stop-propagation event)
(dom/prevent-default event)
(st/emit! (dm/hide)))))

View file

@ -52,21 +52,24 @@
drawing? @refs/selected-drawing-tool
button (.-which (.-nativeEvent event))
shift? (kbd/shift? event)
ctrl? (kbd/ctrl? event)]
(dom/prevent-default event)
(when-not blocked
ctrl? (kbd/ctrl? event)
allow-click? (and (not blocked)
(not drawing?)
(not ctrl?)
(not edition))]
(when (and (= button 1) allow-click?)
(cond
(or (not= 1 button) drawing? ctrl? edition)
nil
(= type :frame)
(when selected?
(do
(dom/stop-propagation event)
(st/emit! (dw/start-move-selected))))
:else
(and (= type :frame) selected?)
(do
(dom/prevent-default event)
(dom/stop-propagation event)
(st/emit! (dw/start-move-selected)))
(not= type :frame)
(do
(dom/prevent-default event)
(dom/stop-propagation event)
(let [toggle-selected? (and selected? shift?)

View file

@ -34,7 +34,7 @@
[app.main.ui.measurements :as msr]
[app.main.ui.workspace.shapes.path.editor :refer [path-editor]]))
(def rotation-handler-size 25)
(def rotation-handler-size 20)
(def resize-point-radius 4)
(def resize-point-circle-radius 10)
(def resize-point-rect-size 8)
@ -43,6 +43,7 @@
(def selection-rect-color-component "#00E0FF")
(def selection-rect-width 1)
(def min-selrect-side 10)
(def small-selrect-side 30)
(mf/defc selection-rect [{:keys [transform rect zoom color]}]
(when rect
@ -57,66 +58,78 @@
:stroke-width (/ selection-rect-width zoom)
:fill "transparent"}}])))
(defn- handlers-for-selection [{:keys [x y width height]}]
(->>
[ ;; TOP-LEFT
{:type :rotation
:position :top-left
:props {:cx x :cy y}}
(defn- handlers-for-selection [{:keys [x y width height]} {:keys [type]} zoom]
(let [zoom-width (* width zoom)
zoom-height (* height zoom)
(when (and (> width min-selrect-side) (> height min-selrect-side))
{:type :resize-point
align (when (or (<= zoom-width small-selrect-side)
(<= zoom-height small-selrect-side))
:outside)
show-resize-point? (or (not= type :path)
(and
(> zoom-width min-selrect-side)
(> zoom-height min-selrect-side)))
min-side-top? (or (not= type :path) (> zoom-height min-selrect-side))
min-side-side? (or (not= type :path) (> zoom-width min-selrect-side))]
(->>
[ ;; TOP-LEFT
{:type :rotation
:position :top-left
:props {:cx x :cy y}})
:props {:cx x :cy y}}
{:type :rotation
:position :top-right
:props {:cx (+ x width) :cy y}}
(when show-resize-point?
{:type :resize-point
:position :top-left
:props {:cx x :cy y :align align}})
(when (and (> width min-selrect-side) (> height min-selrect-side))
{:type :resize-point
{:type :rotation
:position :top-right
:props {:cx (+ x width) :cy y}})
:props {:cx (+ x width) :cy y}}
{:type :rotation
:position :bottom-right
:props {:cx (+ x width) :cy (+ y height)}}
(when show-resize-point?
{:type :resize-point
:position :top-right
:props {:cx (+ x width) :cy y :align align}})
(when (and (> width min-selrect-side) (> height min-selrect-side))
{:type :resize-point
{:type :rotation
:position :bottom-right
:props {:cx (+ x width) :cy (+ y height)}})
:props {:cx (+ x width) :cy (+ y height)}}
{:type :rotation
:position :bottom-left
:props {:cx x :cy (+ y height)}}
(when show-resize-point?
{:type :resize-point
:position :bottom-right
:props {:cx (+ x width) :cy (+ y height) :align align}})
(when (and (> width min-selrect-side) (> height min-selrect-side))
{:type :resize-point
{:type :rotation
:position :bottom-left
:props {:cx x :cy (+ y height)}})
:props {:cx x :cy (+ y height)}}
(when (> height min-selrect-side)
{:type :resize-side
:position :top
:props {:x x :y y :length width :angle 0 }})
(when show-resize-point?
{:type :resize-point
:position :bottom-left
:props {:cx x :cy (+ y height) :align align}})
(when (> width min-selrect-side)
{:type :resize-side
:position :right
:props {:x (+ x width) :y y :length height :angle 90 }})
(when min-side-top?
{:type :resize-side
:position :top
:props {:x x :y y :length width :angle 0 :align align}})
(when (> height min-selrect-side)
{:type :resize-side
:position :bottom
:props {:x (+ x width) :y (+ y height) :length width :angle 180 }})
(when min-side-side?
{:type :resize-side
:position :right
:props {:x (+ x width) :y y :length height :angle 90 :align align}})
(when (> width min-selrect-side)
{:type :resize-side
:position :left
:props {:x x :y (+ y height) :length height :angle 270 }})]
(when min-side-top?
{:type :resize-side
:position :bottom
:props {:x (+ x width) :y (+ y height) :length width :angle 180 :align align}})
(filterv (comp not nil?))))
(when min-side-side?
{:type :resize-side
:position :left
:props {:x x :y (+ y height) :length height :angle 270 :align align}})]
(filterv (comp not nil?)))))
(mf/defc rotation-handler [{:keys [cx cy transform position rotation zoom on-rotate]}]
(let [size (/ rotation-handler-size zoom)
@ -137,13 +150,11 @@
:on-mouse-down on-rotate}]))
(mf/defc resize-point-handler
[{:keys [cx cy zoom position on-resize transform rotation color overflow-text]}]
(let [{cx' :x cy' :y} (gpt/transform (gpt/point cx cy) transform)
rot-square (case position
:top-left 0
:top-right 90
:bottom-right 180
:bottom-left 270)]
[{:keys [cx cy zoom position on-resize transform rotation color overflow-text align]}]
(let [cursor (if (#{:top-left :bottom-right} position)
(cur/resize-nesw rotation) (cur/resize-nwse rotation))
{cx' :x cy' :y} (gpt/transform (gpt/point cx cy) transform)]
[:g.resize-handler
[:circle {:r (/ resize-point-radius zoom)
:style {:fillOpacity "1"
@ -154,24 +165,53 @@
:cx cx'
:cy cy'}]
[:circle {:on-mouse-down #(on-resize {:x cx' :y cy'} %)
:r (/ resize-point-circle-radius zoom)
:fill (if (debug? :resize-handler) "red" "transparent")
:cx cx'
:cy cy'
:style {:cursor (if (#{:top-left :bottom-right} position)
(cur/resize-nesw rotation) (cur/resize-nwse rotation))}}]
]))
(if (= align :outside)
(let [resize-point-circle-radius (/ resize-point-circle-radius zoom)
offset-x (if (#{:top-right :bottom-right} position) 0 (- resize-point-circle-radius))
offset-y (if (#{:bottom-left :bottom-right} position) 0 (- resize-point-circle-radius))
cx (+ cx offset-x)
cy (+ cy offset-y)
{cx' :x cy' :y} (gpt/transform (gpt/point cx cy) transform)]
[:rect {:x cx'
:y cy'
:width resize-point-circle-radius
:height resize-point-circle-radius
:transform (str/fmt "rotate(%s, %s, %s)" rotation cx' cy')
:style {:fill (if (debug? :resize-handler) "red" "transparent")
:cursor cursor}
:on-mouse-down #(on-resize {:x cx' :y cy'} %)}])
(mf/defc resize-side-handler [{:keys [x y length angle zoom position rotation transform on-resize]}]
(let [rot-square (case position
:top-left 0
:top-right 90
:bottom-right 180
:bottom-left 270)]
[:circle {:on-mouse-down #(on-resize {:x cx' :y cy'} %)
:r (/ resize-point-circle-radius zoom)
:cx cx'
:cy cy'
:style {:fill (if (debug? :resize-handler) "red" "transparent")
:cursor cursor}}])
)]))
(mf/defc resize-side-handler
"The side handler is always rendered horizontaly and then rotated"
[{:keys [x y length align angle zoom position rotation transform on-resize]}]
(let [res-point (if (#{:top :bottom} position)
{:y y}
{:x x})
target-length (max 0 (- length (/ (* resize-point-rect-size 2) zoom)))
width (if (< target-length 6) length target-length)
height (/ resize-side-height zoom)]
[:rect {:x (+ x (/ (- length width) 2))
:y (- y (/ height 2))
height (/ resize-side-height zoom)
offset-x (/ (- length width) 2)
offset-y (if (= align :outside) (- height) (- (/ height 2)))
target-x (+ x offset-x)
target-y (+ y offset-y)]
[:rect {:x target-x
:y target-y
:width width
:height height
:transform (gmt/multiply transform
@ -217,7 +257,7 @@
[:& outline {:shape shape :color color}]
;; Handlers
(for [{:keys [type position props]} (handlers-for-selection selrect)]
(for [{:keys [type position props]} (handlers-for-selection selrect shape zoom)]
(let [common-props {:key (str (name type) "-" (name position))
:zoom zoom
:position position

View file

@ -43,20 +43,23 @@
(recur (first ids) (rest ids))
false))))))
(defn use-select-shape [{:keys [id]}]
(defn use-select-shape [{:keys [id]} edition]
(mf/use-callback
(mf/deps id)
(mf/deps id edition)
(fn [event]
(let [selected @refs/selected-shapes
selected? (contains? selected id)]
(dom/prevent-default event)
(if selected?
(when (kbd/shift? event)
(st/emit! (dw/select-shape id true)))
(do
(when-not (or (empty? selected) (kbd/shift? event))
(st/emit! (dw/deselect-all)))
(st/emit! (dw/select-shape id))))))))
(when (not edition)
(let [selected @refs/selected-shapes
selected? (contains? selected id)
shift? (kbd/shift? event)]
(cond
(and selected? shift?)
(st/emit! (dw/select-shape id true))
(and (not (empty? selected)) (not shift?))
(st/emit! (dw/deselect-all) (dw/select-shape id))
(not selected?)
(st/emit! (dw/select-shape id))))))))
;; Ensure that the label has always the same font
;; size, regardless of zoom
@ -72,8 +75,9 @@
[{:keys [frame]}]
(let [{:keys [width x y]} frame
zoom (mf/deref refs/selected-zoom)
edition (mf/deref refs/selected-edition)
label-pos (gpt/point x (- y (/ 10 zoom)))
handle-click (use-select-shape frame)
handle-click (use-select-shape frame edition)
handle-pointer-enter (we/use-pointer-enter frame)
handle-pointer-leave (we/use-pointer-leave frame)]
[:text {:x 0
@ -123,6 +127,7 @@
(let [shape (unchecked-get props "shape")
objects (unchecked-get props "objects")
ghost? (mf/use-ctx muc/ghost-ctx)
edition (mf/deref refs/selected-edition)
moving-iref (mf/use-memo (mf/deps (:id shape))
#(make-is-moving-ref (:id shape)))
@ -137,7 +142,7 @@
ds-modifier (get-in shape [:modifiers :displacement])
handle-context-menu (we/use-context-menu shape)
handle-double-click (use-select-shape shape)
handle-double-click (use-select-shape shape edition)
handle-mouse-down (we/use-mouse-down shape)
hide-moving? (and (not ghost?) moving?)]

View file

@ -45,6 +45,7 @@
(and (= edit-mode :move) selected?)
(st/emit! (drp/deselect-node position))))))
on-mouse-down
(fn [event]
(when-not last-p?
@ -60,6 +61,7 @@
(and (= edit-mode :draw) (not start-path?))
(st/emit! (drp/close-path-drag-start position))))))]
[:g.path-point
[:circle.path-point
{:cx x
@ -182,11 +184,18 @@
editor-dom (mf/ref-val editor-ref)]
(when-not (or (.contains editor-dom current)
(dom/class? current "viewport-actions-entry"))
(st/emit! (drp/deselect-all)))))]
(st/emit! (drp/deselect-all)))))
handle-double-click-outside
(fn [event]
(when (= edit-mode :move)
(st/emit! :interrupt)))]
(mf/use-layout-effect
(mf/deps edit-mode)
(fn []
(let [keys [(events/listen js/document EventType.CLICK handle-click-outside)]]
(let [keys [(events/listen (dom/get-root) EventType.CLICK handle-click-outside)
(events/listen (dom/get-root) EventType.DBLCLICK handle-double-click-outside)]]
#(doseq [key keys]
(events/unlistenByKey key)))))

View file

@ -59,7 +59,6 @@
render-editor (mf/use-state false)
edition? (= edition id)
embed-resources? (mf/use-ctx muc/embed-ctx)
handle-mouse-down (we/use-mouse-down shape)
@ -116,7 +115,7 @@
:shape shape
:selected? selected?
:grow-type (:grow-type shape)}]]
(when edition?
(when (and (not ghost?) edition?)
[:& editor/text-shape-edit {:key (str "editor" (:id shape))
:shape shape}])

View file

@ -167,19 +167,18 @@
on-click-outside
(fn [event]
(let [options (dom/get-element-by-class "element-options")
(let [target (dom/get-target event)
options (dom/get-element-by-class "element-options")
assets (dom/get-element-by-class "assets-bar")
cpicker (dom/get-element-by-class "colorpicker-tooltip")
self (mf/ref-val self-ref)
target (dom/get-target event)
selecting? (mf/ref-val selecting-ref)]
(when-not (or (and options (.contains options target))
(and assets (.contains assets target))
(and self (.contains self target))
(and cpicker (.contains cpicker target)))
(do
(dom/prevent-default event)
(dom/stop-propagation event)
(if selecting?
(mf/set-ref-val! selecting-ref false)
@ -203,16 +202,16 @@
on-mount
(fn []
(let [lkey1 (events/listen js/document EventType.CLICK on-click-outside)
lkey2 (events/listen js/document EventType.KEYUP on-key-up)]
(let [keys [(events/listen js/document EventType.CLICK on-click-outside)
(events/listen js/document EventType.KEYUP on-key-up)]]
(st/emit! (dwt/assign-editor id editor)
(dwc/start-undo-transaction))
#(do
(st/emit! (dwt/assign-editor id nil)
(dwc/commit-undo-transaction))
(events/unlistenByKey lkey1)
(events/unlistenByKey lkey2))))
(doseq [key keys]
(events/unlistenByKey key)))))
on-focus
(fn [event]

View file

@ -345,10 +345,7 @@
(let [ctrl? (kbd/ctrl? event)
shift? (kbd/shift? event)
alt? (kbd/alt? event)]
(st/emit! (ms/->MouseEvent :double-click ctrl? shift? alt?))
(if (not drawing-path?)
(st/emit! dw/clear-edition-mode)))))
(st/emit! (ms/->MouseEvent :double-click ctrl? shift? alt?)))))
on-key-down
(mf/use-callback

View file

@ -253,3 +253,6 @@
(defn active? [node]
(= (.-activeElement js/document) node))
(defn get-data [^js node ^string attr]
(.getAttribute node (str "data-" attr)))