diff --git a/CHANGES.md b/CHANGES.md index 61e7fde3c..5e13c092b 100644 --- a/CHANGES.md +++ b/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 diff --git a/backend/src/app/emails.clj b/backend/src/app/emails.clj index 6721c299c..1a5aebb63 100644 --- a/backend/src/app/emails.clj +++ b/backend/src/app/emails.clj @@ -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))) diff --git a/backend/src/app/rpc/mutations/teams.clj b/backend/src/app/rpc/mutations/teams.clj index a104f3604..a06815b6a 100644 --- a/backend/src/app/rpc/mutations/teams.clj +++ b/backend/src/app/rpc/mutations/teams.clj @@ -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 diff --git a/frontend/src/app/main/data/workspace.cljs b/frontend/src/app/main/data/workspace.cljs index 59bc76e2e..bedd0dd4c 100644 --- a/frontend/src/app/main/data/workspace.cljs +++ b/frontend/src/app/main/data/workspace.cljs @@ -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) - diff --git a/frontend/src/app/main/data/workspace/shortcuts.cljs b/frontend/src/app/main/data/workspace/shortcuts.cljs index bb5a2539b..4814692f1 100644 --- a/frontend/src/app/main/data/workspace/shortcuts.cljs +++ b/frontend/src/app/main/data/workspace/shortcuts.cljs @@ -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") diff --git a/frontend/src/app/main/data/workspace/transforms.cljs b/frontend/src/app/main/data/workspace/transforms.cljs index 8f5d3cc85..9a8bc6bbe 100644 --- a/frontend/src/app/main/data/workspace/transforms.cljs +++ b/frontend/src/app/main/data/workspace/transforms.cljs @@ -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)) diff --git a/frontend/src/app/main/streams.cljs b/frontend/src/app/main/streams.cljs index 7b5201ffa..759fddd23 100644 --- a/frontend/src/app/main/streams.cljs +++ b/frontend/src/app/main/streams.cljs @@ -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 diff --git a/frontend/src/app/main/ui/components/dropdown.cljs b/frontend/src/app/main/ui/components/dropdown.cljs index 114617fa5..507af1f4d 100644 --- a/frontend/src/app/main/ui/components/dropdown.cljs +++ b/frontend/src/app/main/ui/components/dropdown.cljs @@ -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))))] diff --git a/frontend/src/app/main/ui/settings/sidebar.cljs b/frontend/src/app/main/ui/settings/sidebar.cljs index 0b9cce30d..3a5504fe9 100644 --- a/frontend/src/app/main/ui/settings/sidebar.cljs +++ b/frontend/src/app/main/ui/settings/sidebar.cljs @@ -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}))))))] diff --git a/frontend/src/app/main/ui/viewer.cljs b/frontend/src/app/main/ui/viewer.cljs index 144c472d9..917a0c9d7 100644 --- a/frontend/src/app/main/ui/viewer.cljs +++ b/frontend/src/app/main/ui/viewer.cljs @@ -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? diff --git a/frontend/src/app/main/ui/viewer/handoff.cljs b/frontend/src/app/main/ui/viewer/handoff.cljs index f3cbeaa7b..4a00631ea 100644 --- a/frontend/src/app/main/ui/viewer/handoff.cljs +++ b/frontend/src/app/main/ui/viewer/handoff.cljs @@ -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) diff --git a/frontend/src/app/main/ui/viewer/handoff/left_sidebar.cljs b/frontend/src/app/main/ui/viewer/handoff/left_sidebar.cljs index 4319c262d..4e05ac409 100644 --- a/frontend/src/app/main/ui/viewer/handoff/left_sidebar.cljs +++ b/frontend/src/app/main/ui/viewer/handoff/left_sidebar.cljs @@ -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) diff --git a/frontend/src/app/main/ui/viewer/interactions.cljs b/frontend/src/app/main/ui/viewer/interactions.cljs index e3e0b55b4..587b41ac9 100644 --- a/frontend/src/app/main/ui/viewer/interactions.cljs +++ b/frontend/src/app/main/ui/viewer/interactions.cljs @@ -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))] diff --git a/frontend/src/app/main/ui/workspace/shapes/path/editor.cljs b/frontend/src/app/main/ui/workspace/shapes/path/editor.cljs index 2ccc1583d..36d0fcf41 100644 --- a/frontend/src/app/main/ui/workspace/shapes/path/editor.cljs +++ b/frontend/src/app/main/ui/workspace/shapes/path/editor.cljs @@ -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) diff --git a/frontend/src/app/main/ui/workspace/sidebar/assets.cljs b/frontend/src/app/main/ui/workspace/sidebar/assets.cljs index 8ed877406..903e3c7d5 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/assets.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/assets.cljs @@ -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))) diff --git a/frontend/src/app/main/ui/workspace/sidebar/layers.cljs b/frontend/src/app/main/ui/workspace/sidebar/layers.cljs index 9e65bbf54..b077c1ee3 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/layers.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/layers.cljs @@ -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) diff --git a/frontend/src/app/main/ui/workspace/viewport.cljs b/frontend/src/app/main/ui/workspace/viewport.cljs index a0d0c740f..13321c3fd 100644 --- a/frontend/src/app/main/ui/workspace/viewport.cljs +++ b/frontend/src/app/main/ui/workspace/viewport.cljs @@ -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}]) diff --git a/frontend/src/app/main/ui/workspace/viewport/actions.cljs b/frontend/src/app/main/ui/workspace/viewport/actions.cljs index 6ac904151..2be7787c1 100644 --- a/frontend/src/app/main/ui/workspace/viewport/actions.cljs +++ b/frontend/src/app/main/ui/workspace/viewport/actions.cljs @@ -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 diff --git a/frontend/src/app/main/ui/workspace/viewport/hooks.cljs b/frontend/src/app/main/ui/workspace/viewport/hooks.cljs index f9b7ca0c2..00361b7d1 100644 --- a/frontend/src/app/main/ui/workspace/viewport/hooks.cljs +++ b/frontend/src/app/main/ui/workspace/viewport/hooks.cljs @@ -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 diff --git a/frontend/src/app/util/dom.cljs b/frontend/src/app/util/dom.cljs index 15cbf004e..4398e9da8 100644 --- a/frontend/src/app/util/dom.cljs +++ b/frontend/src/app/util/dom.cljs @@ -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] diff --git a/frontend/src/app/util/keyboard.cljs b/frontend/src/app/util/keyboard.cljs index 0fb84f09d..52077fb30 100644 --- a/frontend/src/app/util/keyboard.cljs +++ b/frontend/src/app/util/keyboard.cljs @@ -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)) diff --git a/frontend/src/app/util/webapi.cljs b/frontend/src/app/util/webapi.cljs index 643d6d618..b56ac91a7 100644 --- a/frontend/src/app/util/webapi.cljs +++ b/frontend/src/app/util/webapi.cljs @@ -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]