mirror of
https://github.com/penpot/penpot.git
synced 2025-02-23 23:35:58 -05:00
commit
caa81b4fe2
22 changed files with 239 additions and 133 deletions
10
CHANGES.md
10
CHANGES.md
|
@ -1,5 +1,15 @@
|
|||
# CHANGELOG
|
||||
|
||||
## 1.12.4-beta
|
||||
|
||||
### :bug: Bugs fixed
|
||||
|
||||
- Fix crash on iOS when displaying viewer [#1522](https://github.com/penpot/penpot/issues/1522)
|
||||
- Fix problems with trackpad zoom and scroll in MacOS [#1161](https://github.com/penpot/penpot/issues/1161)
|
||||
- Fix problem with copy/paste in Safari [#1209](https://github.com/penpot/penpot/issues/1209)
|
||||
- Improved command support for MacOS [Taiga #2789](https://tree.taiga.io/project/penpot/issue/2789)
|
||||
- Fix shift+2 shortcut in MacOS with non-english keyboards [Taiga #3038](https://tree.taiga.io/project/penpot/issue/3038)
|
||||
|
||||
## 1.12.3-beta
|
||||
|
||||
### :bug: Bugs fixed
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
"Main api for send emails."
|
||||
(:require
|
||||
[app.common.logging :as l]
|
||||
[app.common.pprint :as pp]
|
||||
[app.common.spec :as us]
|
||||
[app.config :as cf]
|
||||
[app.db :as db]
|
||||
|
@ -165,19 +166,25 @@
|
|||
(let [enabled? (or (contains? cf/flags :smtp)
|
||||
(cf/get :smtp-enabled)
|
||||
(:enabled task))]
|
||||
(if enabled?
|
||||
(emails/send! cfg props)
|
||||
(when enabled?
|
||||
(emails/send! cfg props))
|
||||
|
||||
(when (contains? cf/flags :log-emails)
|
||||
(send-console! cfg props)))))
|
||||
|
||||
(defn- send-console!
|
||||
[cfg email]
|
||||
(let [baos (java.io.ByteArrayOutputStream.)
|
||||
mesg (emails/smtp-message cfg email)]
|
||||
(.writeTo mesg baos)
|
||||
(let [out (with-out-str
|
||||
(println "email console dump:")
|
||||
(println "******** start email" (:id email) "**********")
|
||||
(println (.toString baos))
|
||||
(println "******** end email "(:id email) "**********"))]
|
||||
(l/info :email out))))
|
||||
(let [body (:body email)
|
||||
out (with-out-str
|
||||
(println "email console dump:")
|
||||
(println "******** start email" (:id email) "**********")
|
||||
(pp/pprint (dissoc email :body))
|
||||
(if (string? body)
|
||||
(println body)
|
||||
(println (->> body
|
||||
(filter #(= "text/plain" (:type %)))
|
||||
(map :content)
|
||||
first)))
|
||||
(println "******** end email" (:id email) "**********"))]
|
||||
(l/info ::l/raw out)))
|
||||
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
(:require
|
||||
[app.common.data :as d]
|
||||
[app.common.exceptions :as ex]
|
||||
[app.common.logging :as l]
|
||||
[app.common.spec :as us]
|
||||
[app.common.uuid :as uuid]
|
||||
[app.config :as cf]
|
||||
|
@ -374,6 +375,9 @@
|
|||
{:iss :profile-identity
|
||||
:profile-id (:id profile)})]
|
||||
|
||||
(when (contains? cf/flags :log-invitation-tokens)
|
||||
(l/trace :hint "invitation token" :token itoken))
|
||||
|
||||
(when (and member (not (eml/allow-send-emails? conn member)))
|
||||
(ex/raise :type :validation
|
||||
:code :member-is-muted
|
||||
|
|
|
@ -1548,13 +1548,10 @@
|
|||
[]
|
||||
(letfn [;; Sort objects so they have the same relative ordering
|
||||
;; when pasted later.
|
||||
(sort-selected [state data]
|
||||
(let [selected (:selected data)
|
||||
page-id (:current-page-id state)
|
||||
objects (get-in state [:workspace-data
|
||||
:pages-index
|
||||
page-id
|
||||
:objects])]
|
||||
(sort-selected-async [state data]
|
||||
(let [selected (wsh/lookup-selected state)
|
||||
objects (wsh/lookup-page-objects state)
|
||||
page-id (:current-page-id state)]
|
||||
(->> (uw/ask! {:cmd :selection/query-z-index
|
||||
:page-id page-id
|
||||
:objects objects
|
||||
|
@ -1566,6 +1563,24 @@
|
|||
(map first)
|
||||
(into (d/ordered-set)))))))))
|
||||
|
||||
;; We cannot call to a remote procedure in Safari (for the copy) so we need
|
||||
;; to calculate it here instead of on the worker
|
||||
(sort-selected-sync [state data]
|
||||
(let [selected (wsh/lookup-selected state)
|
||||
objects (wsh/lookup-page-objects state)
|
||||
z-index (cp/calculate-z-index objects)
|
||||
z-values (->> selected
|
||||
(map #(vector %
|
||||
(+ (get z-index %)
|
||||
(get z-index (get-in objects [% :frame-id]))))))
|
||||
selected
|
||||
(->> z-values
|
||||
(sort-by second)
|
||||
(map first)
|
||||
(into (d/ordered-set)))]
|
||||
|
||||
(assoc data :selected selected)))
|
||||
|
||||
;; Retrieve all ids of selected shapes with corresponding
|
||||
;; children; this is needed because each shape should be
|
||||
;; processed one by one because of async events (data url
|
||||
|
@ -1627,11 +1642,18 @@
|
|||
:file-id (:current-file-id state)
|
||||
:selected selected
|
||||
:objects {}
|
||||
:images #{}}]
|
||||
:images #{}}
|
||||
|
||||
sort-results
|
||||
(fn [obs]
|
||||
;; Safari doesn't allow asynchronous sorting on the copy
|
||||
(if (cfg/check-browser? :safari)
|
||||
(rx/map (partial sort-selected-sync state) obs)
|
||||
(rx/mapcat (partial sort-selected-async state) obs)))]
|
||||
(->> (rx/from (seq (vals pdata)))
|
||||
(rx/merge-map (partial prepare-object objects selected))
|
||||
(rx/reduce collect-data initial)
|
||||
(rx/mapcat (partial sort-selected state))
|
||||
(sort-results)
|
||||
(rx/map t/encode-str)
|
||||
(rx/map wapi/write-to-clipboard)
|
||||
(rx/catch on-copy-error)
|
||||
|
@ -2102,4 +2124,3 @@
|
|||
(d/export dwgu/update-guides)
|
||||
(d/export dwgu/remove-guide)
|
||||
(d/export dwgu/set-hover-guide)
|
||||
|
||||
|
|
|
@ -134,7 +134,7 @@
|
|||
:fn #(st/emit! dw/zoom-to-fit-all)}
|
||||
|
||||
:zoom-selected {:tooltip (ds/shift "2")
|
||||
:command "shift+2"
|
||||
:command ["shift+2" "@" "\""]
|
||||
:fn #(st/emit! dw/zoom-to-selected-shape)}
|
||||
|
||||
:duplicate {:tooltip (ds/meta "D")
|
||||
|
|
|
@ -434,13 +434,13 @@
|
|||
group (gsh/selection-rect shapes)
|
||||
group-center (gsh/center-selrect group)
|
||||
initial-angle (gpt/angle @ms/mouse-position group-center)
|
||||
calculate-angle (fn [pos ctrl? shift?]
|
||||
calculate-angle (fn [pos mod? shift?]
|
||||
(let [angle (- (gpt/angle pos group-center) initial-angle)
|
||||
angle (if (neg? angle) (+ 360 angle) angle)
|
||||
angle (if (= angle 360)
|
||||
0
|
||||
angle)
|
||||
angle (if ctrl?
|
||||
angle (if mod?
|
||||
(* (mth/floor (/ angle 45)) 45)
|
||||
angle)
|
||||
angle (if shift?
|
||||
|
@ -449,10 +449,10 @@
|
|||
angle))]
|
||||
(rx/concat
|
||||
(->> ms/mouse-position
|
||||
(rx/with-latest vector ms/mouse-position-ctrl)
|
||||
(rx/with-latest vector ms/mouse-position-mod)
|
||||
(rx/with-latest vector ms/mouse-position-shift)
|
||||
(rx/map (fn [[[pos ctrl?] shift?]]
|
||||
(let [delta-angle (calculate-angle pos ctrl? shift?)]
|
||||
(rx/map (fn [[[pos mod?] shift?]]
|
||||
(let [delta-angle (calculate-angle pos mod? shift?)]
|
||||
(set-rotation-modifiers delta-angle shapes group-center))))
|
||||
(rx/take-until stoper))
|
||||
(rx/of (apply-modifiers (map :id shapes))
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
(ns app.main.streams
|
||||
"User interaction events and streams."
|
||||
(:require
|
||||
[app.config :as cfg]
|
||||
[app.main.store :as st]
|
||||
[app.util.globals :as globals]
|
||||
[app.util.keyboard :as kbd]
|
||||
|
@ -20,7 +21,7 @@
|
|||
[v]
|
||||
(instance? KeyboardEvent v))
|
||||
|
||||
(defrecord MouseEvent [type ctrl shift alt])
|
||||
(defrecord MouseEvent [type ctrl shift alt meta])
|
||||
|
||||
(defn mouse-event?
|
||||
[v]
|
||||
|
@ -46,7 +47,7 @@
|
|||
(and (mouse-event? v)
|
||||
(= :double-click (:type v))))
|
||||
|
||||
(defrecord PointerEvent [source pt ctrl shift alt])
|
||||
(defrecord PointerEvent [source pt ctrl shift alt meta])
|
||||
|
||||
(defn pointer-event?
|
||||
[v]
|
||||
|
@ -83,6 +84,20 @@
|
|||
(rx/subscribe-with ob sub)
|
||||
sub))
|
||||
|
||||
(defonce mouse-position-meta
|
||||
(let [sub (rx/behavior-subject nil)
|
||||
ob (->> st/stream
|
||||
(rx/filter pointer-event?)
|
||||
(rx/map :meta)
|
||||
(rx/dedupe))]
|
||||
(rx/subscribe-with ob sub)
|
||||
sub))
|
||||
|
||||
(defonce mouse-position-mod
|
||||
(if (cfg/check-platform? :macos)
|
||||
mouse-position-meta
|
||||
mouse-position-ctrl))
|
||||
|
||||
(defonce mouse-position-shift
|
||||
(let [sub (rx/behavior-subject nil)
|
||||
ob (->> st/stream
|
||||
|
@ -111,7 +126,7 @@
|
|||
ob (->> (rx/merge
|
||||
(->> st/stream
|
||||
(rx/filter keyboard-event?)
|
||||
(rx/filter kbd/altKey?)
|
||||
(rx/filter kbd/alt-key?)
|
||||
(rx/map #(= :down (:type %))))
|
||||
;; Fix a situation caused by using `ctrl+alt` kind of shortcuts,
|
||||
;; that makes keyboard-alt stream registering the key pressed but
|
||||
|
@ -119,15 +134,15 @@
|
|||
(->> window-blur
|
||||
(rx/map (constantly false))))
|
||||
(rx/dedupe))]
|
||||
(rx/subscribe-with ob sub)
|
||||
sub))
|
||||
(rx/subscribe-with ob sub)
|
||||
sub))
|
||||
|
||||
(defonce keyboard-ctrl
|
||||
(let [sub (rx/behavior-subject nil)
|
||||
ob (->> (rx/merge
|
||||
(->> st/stream
|
||||
(rx/filter keyboard-event?)
|
||||
(rx/filter kbd/ctrlKey?)
|
||||
(rx/filter kbd/ctrl-key?)
|
||||
(rx/map #(= :down (:type %))))
|
||||
;; Fix a situation caused by using `ctrl+alt` kind of shortcuts,
|
||||
;; that makes keyboard-alt stream registering the key pressed but
|
||||
|
@ -135,9 +150,30 @@
|
|||
(->> window-blur
|
||||
(rx/map (constantly false))))
|
||||
(rx/dedupe))]
|
||||
(rx/subscribe-with ob sub)
|
||||
(rx/subscribe-with ob sub)
|
||||
sub))
|
||||
|
||||
(defonce keyboard-meta
|
||||
(let [sub (rx/behavior-subject nil)
|
||||
ob (->> (rx/merge
|
||||
(->> st/stream
|
||||
(rx/filter keyboard-event?)
|
||||
(rx/filter kbd/meta-key?)
|
||||
(rx/map #(= :down (:type %))))
|
||||
;; Fix a situation caused by using `ctrl+alt` kind of shortcuts,
|
||||
;; that makes keyboard-alt stream registering the key pressed but
|
||||
;; on blurring the window (unfocus) the key down is never arrived.
|
||||
(->> window-blur
|
||||
(rx/map (constantly false))))
|
||||
(rx/dedupe))]
|
||||
(rx/subscribe-with ob sub)
|
||||
sub))
|
||||
|
||||
(defonce keyboard-mod
|
||||
(if (cfg/check-platform? :macos)
|
||||
keyboard-meta
|
||||
keyboard-ctrl))
|
||||
|
||||
(defonce keyboard-space
|
||||
(let [sub (rx/behavior-subject nil)
|
||||
ob (->> st/stream
|
||||
|
|
|
@ -6,7 +6,9 @@
|
|||
|
||||
(ns app.main.ui.components.dropdown
|
||||
(:require
|
||||
[app.config :as cfg]
|
||||
[app.util.dom :as dom]
|
||||
[app.util.globals :as globals]
|
||||
[app.util.keyboard :as kbd]
|
||||
[goog.events :as events]
|
||||
[goog.object :as gobj]
|
||||
|
@ -22,8 +24,13 @@
|
|||
|
||||
on-click
|
||||
(fn [event]
|
||||
(let [target (dom/get-target event)]
|
||||
(when-not (.-data-no-close ^js target)
|
||||
(let [target (dom/get-target event)
|
||||
|
||||
;; MacOS ctrl+click sends two events: context-menu and click.
|
||||
;; In order to not have two handlings we ignore ctrl+click for this platform
|
||||
mac-ctrl-click? (and (cfg/check-platform? :macos) (kbd/ctrl? event))]
|
||||
(when (and (not mac-ctrl-click?)
|
||||
(not (.-data-no-close ^js target)))
|
||||
(if ref
|
||||
(let [parent (mf/ref-val ref)]
|
||||
(when-not (or (not parent) (.contains parent target))
|
||||
|
@ -37,9 +44,9 @@
|
|||
|
||||
on-mount
|
||||
(fn []
|
||||
(let [keys [(events/listen js/document EventType.CLICK on-click)
|
||||
(events/listen js/document EventType.CONTEXTMENU on-click)
|
||||
(events/listen js/document EventType.KEYUP on-keyup)]]
|
||||
(let [keys [(events/listen globals/document EventType.CLICK on-click)
|
||||
(events/listen globals/document EventType.CONTEXTMENU on-click)
|
||||
(events/listen globals/document EventType.KEYUP on-keyup)]]
|
||||
#(doseq [key keys]
|
||||
(events/unlistenByKey key))))]
|
||||
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
[app.main.ui.dashboard.sidebar :refer [profile-section]]
|
||||
[app.main.ui.icons :as i]
|
||||
[app.util.i18n :as i18n :refer [tr]]
|
||||
[app.util.keyboard :as kbd]
|
||||
[app.util.router :as rt]
|
||||
[potok.core :as ptk]
|
||||
[rumext.alpha :as mf]))
|
||||
|
@ -55,8 +56,7 @@
|
|||
(fn [event]
|
||||
(let [version (:main @cf/version)]
|
||||
(st/emit! (ptk/event ::ev/event {::ev/name "show-release-notes" :version version}))
|
||||
(if (and (.-ctrlKey ^js event)
|
||||
(.-altKey ^js event))
|
||||
(if (and (kbd/alt? event) (kbd/mod? event))
|
||||
(st/emit! (modal/show {:type :onboarding}))
|
||||
(st/emit! (modal/show {:type :release-notes :version version}))))))]
|
||||
|
||||
|
|
|
@ -152,7 +152,7 @@
|
|||
(mf/deps fullscreen?)
|
||||
(fn []
|
||||
;; Trigger dom fullscreen depending on our state
|
||||
(let [wrapper (dom/get-element "viewer-layout")
|
||||
(let [wrapper (dom/get-element "viewer-layout")
|
||||
fullscreen-dom? (dom/fullscreen?)]
|
||||
(when (not= fullscreen? fullscreen-dom?)
|
||||
(if fullscreen?
|
||||
|
|
|
@ -28,7 +28,7 @@
|
|||
[{:keys [local file page frame]}]
|
||||
(let [on-mouse-wheel
|
||||
(fn [event]
|
||||
(when (or (kbd/ctrl? event) (kbd/meta? event))
|
||||
(when (kbd/mod? event)
|
||||
(dom/prevent-default event)
|
||||
(let [event (.getBrowserEvent ^js event)
|
||||
delta (+ (.-deltaY ^js event)
|
||||
|
|
|
@ -45,7 +45,7 @@
|
|||
(dom/prevent-default event)
|
||||
(let [id (:id item)]
|
||||
(cond
|
||||
(or (kbd/ctrl? event) (kbd/meta? event))
|
||||
(kbd/mod? event)
|
||||
(st/emit! (dv/toggle-selection id))
|
||||
|
||||
(kbd/shift? event)
|
||||
|
|
|
@ -61,7 +61,7 @@
|
|||
|
||||
on-mouse-wheel
|
||||
(fn [event]
|
||||
(when (or (kbd/ctrl? event) (kbd/meta? event))
|
||||
(when (kbd/mod? event)
|
||||
(dom/prevent-default event)
|
||||
(let [event (.getBrowserEvent ^js event)
|
||||
delta (+ (.-deltaY ^js event) (.-deltaX ^js event))]
|
||||
|
|
|
@ -47,15 +47,15 @@
|
|||
(st/emit! (drp/create-node-at-position (meta position))))
|
||||
|
||||
(let [shift? (kbd/shift? event)
|
||||
ctrl? (kbd/ctrl? event)]
|
||||
mod? (kbd/mod? event)]
|
||||
(cond
|
||||
last-p?
|
||||
(st/emit! (drp/reset-last-handler))
|
||||
|
||||
(and (= edit-mode :move) ctrl? (not curve?))
|
||||
(and (= edit-mode :move) mod? (not curve?))
|
||||
(st/emit! (drp/make-curve position))
|
||||
|
||||
(and (= edit-mode :move) ctrl? curve?)
|
||||
(and (= edit-mode :move) mod? curve?)
|
||||
(st/emit! (drp/make-corner position))
|
||||
|
||||
(= edit-mode :move)
|
||||
|
|
|
@ -1485,7 +1485,7 @@
|
|||
(mf/deps extend-selected-assets selected-assets)
|
||||
(fn [asset-type asset-groups event asset-id default-click]
|
||||
(cond
|
||||
(kbd/ctrl? event)
|
||||
(kbd/mod? event)
|
||||
(do
|
||||
(dom/stop-propagation event)
|
||||
(st/emit! (dw/toggle-selected-assets asset-id asset-type)))
|
||||
|
|
|
@ -133,7 +133,7 @@
|
|||
(kbd/shift? event)
|
||||
(st/emit! (dw/shift-select-shapes id))
|
||||
|
||||
(or (kbd/ctrl? event) (kbd/meta? event))
|
||||
(kbd/mod? event)
|
||||
(st/emit! (dw/select-shape id true))
|
||||
|
||||
(> (count selected) 1)
|
||||
|
|
|
@ -73,7 +73,7 @@
|
|||
|
||||
;; STATE
|
||||
alt? (mf/use-state false)
|
||||
ctrl? (mf/use-state false)
|
||||
mod? (mf/use-state false)
|
||||
space? (mf/use-state false)
|
||||
cursor (mf/use-state (utils/get-cursor :pointer-inner))
|
||||
hover-ids (mf/use-state nil)
|
||||
|
@ -163,9 +163,9 @@
|
|||
|
||||
(hooks/setup-dom-events viewport-ref zoom disable-paste in-viewport?)
|
||||
(hooks/setup-viewport-size viewport-ref)
|
||||
(hooks/setup-cursor cursor alt? ctrl? space? panning drawing-tool drawing-path? node-editing?)
|
||||
(hooks/setup-keyboard alt? ctrl? space?)
|
||||
(hooks/setup-hover-shapes page-id move-stream raw-position-ref base-objects transform selected ctrl? hover hover-ids @hover-disabled? zoom)
|
||||
(hooks/setup-cursor cursor alt? mod? space? panning drawing-tool drawing-path? node-editing?)
|
||||
(hooks/setup-keyboard alt? mod? space?)
|
||||
(hooks/setup-hover-shapes page-id move-stream raw-position-ref base-objects transform selected mod? hover hover-ids @hover-disabled? zoom)
|
||||
(hooks/setup-viewport-modifiers modifiers base-objects)
|
||||
(hooks/setup-shortcuts node-editing? drawing-path?)
|
||||
(hooks/setup-active-frames base-objects vbox hover active-frames)
|
||||
|
@ -244,7 +244,7 @@
|
|||
[:& outline/shape-outlines
|
||||
{:objects base-objects
|
||||
:selected selected
|
||||
:hover (when (or @ctrl? (not= :frame (:type @hover)))
|
||||
:hover (when (or @mod? (not= :frame (:type @hover)))
|
||||
#{(or @frame-hover (:id @hover))})
|
||||
:edition edition
|
||||
:zoom zoom}])
|
||||
|
@ -254,7 +254,7 @@
|
|||
{:shapes selected-shapes
|
||||
:zoom zoom
|
||||
:edition edition
|
||||
:disable-handlers (or drawing-tool edition @space? @ctrl?)
|
||||
:disable-handlers (or drawing-tool edition @space? @mod?)
|
||||
:on-move-selected on-move-selected
|
||||
:on-context-menu on-menu-selected}])
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
(ns app.main.ui.workspace.viewport.actions
|
||||
(:require
|
||||
[app.common.geom.point :as gpt]
|
||||
[app.common.math :as mth]
|
||||
[app.common.uuid :as uuid]
|
||||
[app.config :as cfg]
|
||||
[app.main.data.workspace :as dw]
|
||||
|
@ -40,8 +41,10 @@
|
|||
|
||||
(let [event (.-nativeEvent bevent)
|
||||
ctrl? (kbd/ctrl? event)
|
||||
meta? (kbd/meta? event)
|
||||
shift? (kbd/shift? event)
|
||||
alt? (kbd/alt? event)
|
||||
mod? (kbd/mod? event)
|
||||
|
||||
left-click? (and (not panning) (= 1 (.-which event)))
|
||||
middle-click? (and (not panning) (= 2 (.-which event)))
|
||||
|
@ -53,7 +56,7 @@
|
|||
middle-click?
|
||||
(do
|
||||
(dom/prevent-default bevent)
|
||||
(if ctrl?
|
||||
(if mod?
|
||||
(let [raw-pt (dom/get-client-position event)
|
||||
viewport (mf/ref-val viewport-ref)
|
||||
pt (utils/translate-point-to-viewport viewport zoom raw-pt)]
|
||||
|
@ -63,7 +66,7 @@
|
|||
|
||||
left-click?
|
||||
(do
|
||||
(st/emit! (ms/->MouseEvent :down ctrl? shift? alt?))
|
||||
(st/emit! (ms/->MouseEvent :down ctrl? shift? alt? meta?))
|
||||
|
||||
(when (and (not= edition id) text-editing?)
|
||||
(st/emit! dw/clear-edition-mode))
|
||||
|
@ -78,7 +81,7 @@
|
|||
;; Handle path node area selection
|
||||
(st/emit! (dwdp/handle-area-selection shift?))
|
||||
|
||||
(and @space? ctrl?)
|
||||
(and @space? mod?)
|
||||
(let [raw-pt (dom/get-client-position event)
|
||||
viewport (mf/ref-val viewport-ref)
|
||||
pt (utils/translate-point-to-viewport viewport zoom raw-pt)]
|
||||
|
@ -90,8 +93,8 @@
|
|||
drawing-tool
|
||||
(st/emit! (dd/start-drawing drawing-tool))
|
||||
|
||||
(or (not id) (and frame? (not selected?)) ctrl?)
|
||||
(st/emit! (dw/handle-area-selection shift? ctrl?))
|
||||
(or (not id) (and frame? (not selected?)) mod?)
|
||||
(st/emit! (dw/handle-area-selection shift? mod?))
|
||||
|
||||
(not drawing-tool)
|
||||
(st/emit! (dw/start-move-selected id shift?)))))))))))
|
||||
|
@ -103,11 +106,11 @@
|
|||
(fn [bevent]
|
||||
(let [event (.-nativeEvent bevent)
|
||||
shift? (kbd/shift? event)
|
||||
ctrl? (kbd/ctrl? event)
|
||||
mod? (kbd/mod? event)
|
||||
left-click? (= 1 (.-which event))]
|
||||
|
||||
(when (and left-click?
|
||||
(not ctrl?)
|
||||
(not mod?)
|
||||
(not shift?)
|
||||
(not @space?)
|
||||
(or (not @hover)
|
||||
|
@ -152,12 +155,15 @@
|
|||
(let [ctrl? (kbd/ctrl? event)
|
||||
shift? (kbd/shift? event)
|
||||
alt? (kbd/alt? event)
|
||||
meta? (kbd/meta? event)
|
||||
mod? (kbd/mod? event)
|
||||
|
||||
hovering? (some? @hover)
|
||||
frame? (= :frame (:type @hover))]
|
||||
(st/emit! (ms/->MouseEvent :click ctrl? shift? alt?))
|
||||
(st/emit! (ms/->MouseEvent :click ctrl? shift? alt? meta?))
|
||||
|
||||
(when (and hovering?
|
||||
(or (not frame?) ctrl?)
|
||||
(or (not frame?) mod?)
|
||||
(not @space?)
|
||||
(not edition)
|
||||
(not drawing-path?)
|
||||
|
@ -173,13 +179,14 @@
|
|||
(let [ctrl? (kbd/ctrl? event)
|
||||
shift? (kbd/shift? event)
|
||||
alt? (kbd/alt? event)
|
||||
meta? (kbd/meta? event)
|
||||
|
||||
{:keys [id type] :as shape} @hover
|
||||
|
||||
frame? (= :frame type)
|
||||
group? (= :group type)]
|
||||
|
||||
(st/emit! (ms/->MouseEvent :double-click ctrl? shift? alt?))
|
||||
(st/emit! (ms/->MouseEvent :double-click ctrl? shift? alt? meta?))
|
||||
|
||||
;; Emit asynchronously so the double click to exit shapes won't break
|
||||
(timers/schedule
|
||||
|
@ -238,12 +245,13 @@
|
|||
ctrl? (kbd/ctrl? event)
|
||||
shift? (kbd/shift? event)
|
||||
alt? (kbd/alt? event)
|
||||
meta? (kbd/meta? event)
|
||||
|
||||
left-click? (= 1 (.-which event))
|
||||
middle-click? (= 2 (.-which event))]
|
||||
|
||||
(when left-click?
|
||||
(st/emit! (ms/->MouseEvent :up ctrl? shift? alt?)))
|
||||
(st/emit! (ms/->MouseEvent :up ctrl? shift? alt? meta?)))
|
||||
|
||||
(when middle-click?
|
||||
(dom/prevent-default event)
|
||||
|
@ -339,11 +347,13 @@
|
|||
(st/emit! (ms/->PointerEvent :delta delta
|
||||
(kbd/ctrl? event)
|
||||
(kbd/shift? event)
|
||||
(kbd/alt? event)))
|
||||
(kbd/alt? event)
|
||||
(kbd/meta? event)))
|
||||
(st/emit! (ms/->PointerEvent :viewport pt
|
||||
(kbd/ctrl? event)
|
||||
(kbd/shift? event)
|
||||
(kbd/alt? event))))))))
|
||||
(kbd/alt? event)
|
||||
(kbd/meta? event))))))))
|
||||
|
||||
(defn on-pointer-move [viewport-ref raw-position-ref zoom move-stream]
|
||||
(mf/use-callback
|
||||
|
@ -359,27 +369,18 @@
|
|||
(mf/use-callback
|
||||
(mf/deps zoom)
|
||||
(fn [event]
|
||||
(let [event (.getBrowserEvent ^js event)
|
||||
raw-pt (dom/get-client-position event)
|
||||
viewport (mf/ref-val viewport-ref)
|
||||
pt (utils/translate-point-to-viewport viewport zoom raw-pt)
|
||||
|
||||
ctrl? (kbd/ctrl? event)
|
||||
meta? (kbd/meta? event)
|
||||
(let [viewport (mf/ref-val viewport-ref)
|
||||
event (.getBrowserEvent ^js event)
|
||||
target (dom/get-target event)]
|
||||
(cond
|
||||
(or ctrl? meta?)
|
||||
(do
|
||||
(dom/prevent-default event)
|
||||
(dom/stop-propagation event)
|
||||
(let [delta (+ (.-deltaY ^js event)
|
||||
(.-deltaX ^js event))]
|
||||
(if (pos? delta)
|
||||
(st/emit! (dw/decrease-zoom pt))
|
||||
(st/emit! (dw/increase-zoom pt)))))
|
||||
(when (.contains ^js viewport target)
|
||||
(dom/prevent-default event)
|
||||
(dom/stop-propagation event)
|
||||
(let [pt (->> (dom/get-client-position event)
|
||||
(utils/translate-point-to-viewport viewport zoom))
|
||||
|
||||
(.contains ^js viewport target)
|
||||
(let [delta-mode (.-deltaMode ^js event)
|
||||
mod? (kbd/mod? event)
|
||||
|
||||
delta-mode (.-deltaMode ^js event)
|
||||
|
||||
unit (cond
|
||||
(= delta-mode WheelEvent.DeltaMode.PIXEL) 1
|
||||
|
@ -393,13 +394,16 @@
|
|||
delta-x (-> (.-deltaX ^js event)
|
||||
(* unit)
|
||||
(/ zoom))]
|
||||
(dom/prevent-default event)
|
||||
(dom/stop-propagation event)
|
||||
(if (and (not (cfg/check-platform? :macos)) ;; macos sends delta-x automatically, don't need to do it
|
||||
(kbd/shift? event))
|
||||
(st/emit! (dw/update-viewport-position {:x #(+ % delta-y)}))
|
||||
(st/emit! (dw/update-viewport-position {:x #(+ % delta-x)
|
||||
:y #(+ % delta-y)})))))))))
|
||||
(if mod?
|
||||
(let [delta (* -1 (+ (.-deltaY ^js event) (.-deltaX ^js event)))
|
||||
scale (-> (+ 1 (/ delta 100)) (mth/clamp 0.77 1.3))]
|
||||
(st/emit! (dw/set-zoom pt scale)))
|
||||
(if (and (not (cfg/check-platform? :macos))
|
||||
;; macos sends delta-x automatically, don't need to do it
|
||||
(kbd/shift? event))
|
||||
(st/emit! (dw/update-viewport-position {:x #(+ % delta-y)}))
|
||||
(st/emit! (dw/update-viewport-position {:x #(+ % delta-x)
|
||||
:y #(+ % delta-y)}))))))))))
|
||||
|
||||
(defn on-drag-enter []
|
||||
(mf/use-callback
|
||||
|
|
|
@ -58,13 +58,13 @@
|
|||
;; We schedule the event so it fires after `initialize-page` event
|
||||
(timers/schedule #(st/emit! (dw/initialize-viewport size)))))))
|
||||
|
||||
(defn setup-cursor [cursor alt? ctrl? space? panning drawing-tool drawing-path? path-editing?]
|
||||
(defn setup-cursor [cursor alt? mod? space? panning drawing-tool drawing-path? path-editing?]
|
||||
(mf/use-effect
|
||||
(mf/deps @cursor @alt? @ctrl? @space? panning drawing-tool drawing-path? path-editing?)
|
||||
(mf/deps @cursor @alt? @mod? @space? panning drawing-tool drawing-path? path-editing?)
|
||||
(fn []
|
||||
(let [new-cursor
|
||||
(cond
|
||||
(and @ctrl? @space?) (utils/get-cursor :zoom)
|
||||
(and @mod? @space?) (utils/get-cursor :zoom)
|
||||
(or panning @space?) (utils/get-cursor :hand)
|
||||
(= drawing-tool :comments) (utils/get-cursor :comments)
|
||||
(= drawing-tool :frame) (utils/get-cursor :create-artboard)
|
||||
|
@ -80,9 +80,9 @@
|
|||
(when (not= @cursor new-cursor)
|
||||
(reset! cursor new-cursor))))))
|
||||
|
||||
(defn setup-keyboard [alt? ctrl? space?]
|
||||
(defn setup-keyboard [alt? mod? space?]
|
||||
(hooks/use-stream ms/keyboard-alt #(reset! alt? %))
|
||||
(hooks/use-stream ms/keyboard-ctrl #(reset! ctrl? %))
|
||||
(hooks/use-stream ms/keyboard-mod #(reset! mod? %))
|
||||
(hooks/use-stream ms/keyboard-space #(reset! space? %)))
|
||||
|
||||
(defn group-empty-space?
|
||||
|
@ -108,10 +108,10 @@
|
|||
(map dom/bounding-rect->rect))]
|
||||
(not (some #(gshr/contains-point? % pos) collisions)))))
|
||||
|
||||
(defn setup-hover-shapes [page-id move-stream raw-position-ref objects transform selected ctrl? hover hover-ids hover-disabled? zoom]
|
||||
(defn setup-hover-shapes [page-id move-stream raw-position-ref objects transform selected mod? hover hover-ids hover-disabled? zoom]
|
||||
(let [;; We use ref so we don't recreate the stream on a change
|
||||
zoom-ref (mf/use-ref zoom)
|
||||
ctrl-ref (mf/use-ref @ctrl?)
|
||||
mod-ref (mf/use-ref @mod?)
|
||||
transform-ref (mf/use-ref nil)
|
||||
selected-ref (mf/use-ref selected)
|
||||
hover-disabled-ref (mf/use-ref hover-disabled?)
|
||||
|
@ -121,7 +121,7 @@
|
|||
(mf/deps page-id)
|
||||
(fn [point]
|
||||
(let [zoom (mf/ref-val zoom-ref)
|
||||
ctrl? (mf/ref-val ctrl-ref)
|
||||
mod? (mf/ref-val mod-ref)
|
||||
rect (gsh/center->rect point (/ 5 zoom) (/ 5 zoom))]
|
||||
(if (mf/ref-val hover-disabled-ref)
|
||||
(rx/of nil)
|
||||
|
@ -130,7 +130,7 @@
|
|||
:page-id page-id
|
||||
:rect rect
|
||||
:include-frames? true
|
||||
:clip-children? (not ctrl?)
|
||||
:clip-children? (not mod?)
|
||||
:reverse? true}))))) ;; we want the topmost shape to be selected first
|
||||
|
||||
over-shapes-stream
|
||||
|
@ -157,8 +157,8 @@
|
|||
#(mf/set-ref-val! zoom-ref zoom))
|
||||
|
||||
(mf/use-effect
|
||||
(mf/deps @ctrl?)
|
||||
#(mf/set-ref-val! ctrl-ref @ctrl?))
|
||||
(mf/deps @mod?)
|
||||
#(mf/set-ref-val! mod-ref @mod?))
|
||||
|
||||
(mf/use-effect
|
||||
(mf/deps selected)
|
||||
|
@ -178,17 +178,17 @@
|
|||
|
||||
selected (mf/ref-val selected-ref)
|
||||
|
||||
ctrl? (mf/ref-val ctrl-ref)
|
||||
mod? (mf/ref-val mod-ref)
|
||||
|
||||
remove-xfm (mapcat #(cph/get-parent-ids objects %))
|
||||
remove-id? (cond-> (into #{} remove-xfm selected)
|
||||
:always
|
||||
(into (filter #(check-text-collision? objects (mf/ref-val raw-position-ref) %)) ids)
|
||||
|
||||
(not ctrl?)
|
||||
(not mod?)
|
||||
(into (filter #(group-empty-space? % objects ids)) ids)
|
||||
|
||||
ctrl?
|
||||
mod?
|
||||
(into (filter is-group?) ids))
|
||||
|
||||
hover-shape (->> ids
|
||||
|
|
|
@ -6,13 +6,15 @@
|
|||
|
||||
(ns app.util.dom
|
||||
(:require
|
||||
[app.common.exceptions :as ex]
|
||||
[app.common.geom.point :as gpt]
|
||||
[app.util.globals :as globals]
|
||||
[app.util.object :as obj]
|
||||
[cuerdas.core :as str]
|
||||
[goog.dom :as dom]
|
||||
[promesa.core :as p]))
|
||||
[app.common.geom.point :as gpt]
|
||||
[app.common.logging :as log]
|
||||
[app.util.globals :as globals]
|
||||
[app.util.object :as obj]
|
||||
[cuerdas.core :as str]
|
||||
[goog.dom :as dom]
|
||||
[promesa.core :as p]))
|
||||
|
||||
(log/set-level! :warn)
|
||||
|
||||
;; --- Deprecated methods
|
||||
|
||||
|
@ -289,8 +291,9 @@
|
|||
(boolean (.-fullscreenElement globals/document))
|
||||
|
||||
:else
|
||||
(ex/raise :type :not-supported
|
||||
:hint "seems like the current browser does not support fullscreen api.")))
|
||||
(do
|
||||
(log/error :msg "Seems like the current browser does not support fullscreen api.")
|
||||
false)))
|
||||
|
||||
(defn ^boolean blob?
|
||||
[^js v]
|
||||
|
|
|
@ -4,37 +4,47 @@
|
|||
;;
|
||||
;; Copyright (c) UXBOX Labs SL
|
||||
|
||||
(ns app.util.keyboard)
|
||||
(ns app.util.keyboard
|
||||
(:require
|
||||
[app.config :as cfg]))
|
||||
|
||||
(defn is-key?
|
||||
[key]
|
||||
(fn [e]
|
||||
[^string key]
|
||||
(fn [^js e]
|
||||
(= (.-key e) key)))
|
||||
|
||||
(defn ^boolean alt?
|
||||
[event]
|
||||
[^js event]
|
||||
(.-altKey event))
|
||||
|
||||
(defn ^boolean ctrl?
|
||||
[event]
|
||||
[^js event]
|
||||
(.-ctrlKey event))
|
||||
|
||||
(defn ^boolean meta?
|
||||
[event]
|
||||
[^js event]
|
||||
(.-metaKey event))
|
||||
|
||||
(defn ^boolean shift?
|
||||
[event]
|
||||
[^js event]
|
||||
(.-shiftKey event))
|
||||
|
||||
(defn ^boolean mod?
|
||||
[^js event]
|
||||
(if (cfg/check-platform? :macos)
|
||||
(meta? event)
|
||||
(ctrl? event)))
|
||||
|
||||
(def esc? (is-key? "Escape"))
|
||||
(def enter? (is-key? "Enter"))
|
||||
(def space? (is-key? " "))
|
||||
(def up-arrow? (is-key? "ArrowUp"))
|
||||
(def down-arrow? (is-key? "ArrowDown"))
|
||||
(def altKey? (is-key? "Alt"))
|
||||
(def ctrlKey? (or (is-key? "Control")
|
||||
(is-key? "Meta")))
|
||||
(def alt-key? (is-key? "Alt"))
|
||||
(def ctrl-key? (is-key? "Control"))
|
||||
(def meta-key? (is-key? "Meta"))
|
||||
(def comma? (is-key? ","))
|
||||
(def backspace? (is-key? "Backspace"))
|
||||
|
||||
(defn editing? [e]
|
||||
(.-editing ^js e))
|
||||
|
|
|
@ -8,11 +8,13 @@
|
|||
"HTML5 web api helpers."
|
||||
(:require
|
||||
[app.common.data :as d]
|
||||
[app.common.exceptions :as ex]
|
||||
[app.common.logging :as log]
|
||||
[app.util.object :as obj]
|
||||
[beicon.core :as rx]
|
||||
[cuerdas.core :as str]))
|
||||
|
||||
(log/set-level! :warn)
|
||||
|
||||
(defn- file-reader
|
||||
[f]
|
||||
(rx/create
|
||||
|
@ -114,8 +116,9 @@
|
|||
(.webkitRequestFullscreen el)
|
||||
|
||||
:else
|
||||
(ex/raise :type :not-supported
|
||||
:hint "seems like the current browser does not support fullscreen api.")))
|
||||
(do
|
||||
(log/error :msg "Seems like the current browser does not support fullscreen api.")
|
||||
false)))
|
||||
|
||||
(defn exit-fullscreen
|
||||
[]
|
||||
|
@ -127,8 +130,9 @@
|
|||
(.webkitExitFullscreen js/document)
|
||||
|
||||
:else
|
||||
(ex/raise :type :not-supported
|
||||
:hint "seems like the current browser does not support fullscreen api.")))
|
||||
(do
|
||||
(log/error :msg "Seems like the current browser does not support fullscreen api.")
|
||||
false)))
|
||||
|
||||
(defn observe-resize
|
||||
[node]
|
||||
|
|
Loading…
Add table
Reference in a new issue