penpot/frontend/src/app/util/mouse.cljs
Alejandro Alonso c794e0ed73
🎉 Events enhancements (#9310)
* 🎉 Coalesce viewport pointermove into one PointerEvent

* 🎉 Skip worker hover selection query during transform

* 🎉 Coalesce snap X/Y into one worker query-snap-xy
2026-05-04 17:57:00 +02:00

99 lines
2.2 KiB
Clojure

;; This Source Code Form is subject to the terms of the Mozilla Public
;; License, v. 2.0. If a copy of the MPL was not distributed with this
;; file, You can obtain one at http://mozilla.org/MPL/2.0/.
;;
;; Copyright (c) KALEIDOS INC
(ns app.util.mouse
(:require
[beicon.v2.core :as rx]))
(defrecord MouseEvent [type ctrl shift alt meta])
;; `movement` — optional delta (client/window space) for the same tick as `pt`.
;; Used so viewport `pointermove` can emit once (`source` :viewport) while pan/zoom
;; still observe displacement without a second Potok emit.
(defrecord PointerEvent [source pt ctrl shift alt meta movement])
(defrecord ScrollEvent [point])
(defrecord BlurEvent [])
(defn mouse-event?
[v]
(instance? MouseEvent v))
(defn pointer-event?
[v]
(instance? PointerEvent v))
(defn scroll-event?
[v]
(instance? ScrollEvent v))
(defn blur-event?
[v]
(instance? BlurEvent v))
(defn mouse-down-event?
[^MouseEvent v]
(= :down (.-type v)))
(defn mouse-up-event?
[^MouseEvent v]
(= :up (.-type v)))
(defn mouse-click-event?
[^MouseEvent v]
(= :click (.-type v)))
(defn mouse-double-click-event?
[^MouseEvent v]
(= :double-click (.-type v)))
(defn get-pointer-source
[^PointerEvent ev]
(.-source ev))
(defn get-pointer-position
[^PointerEvent ev]
(.-pt ev))
(defn get-pointer-movement
[^PointerEvent ev]
(.-movement ev))
(defn get-pointer-ctrl-mod
[^PointerEvent ev]
(.-ctrl ev))
(defn get-pointer-meta-mod
[^PointerEvent ev]
(.-meta ev))
(defn get-pointer-alt-mod
[^PointerEvent ev]
(.-alt ev))
(defn get-pointer-shift-mod
[^PointerEvent ev]
(.-shift ev))
(defn drag-stopper
"Creates a stream to stop drag events. Takes into account the mouse and also
if the window loses focus or the esc key is pressed."
([stream]
(drag-stopper stream nil))
([stream {:keys [blur? up-mouse? interrupt?] :or {blur? true up-mouse? true interrupt? true}}]
(rx/merge
(if blur?
(->> stream
(rx/filter blur-event?))
(rx/empty))
(if up-mouse?
(->> stream
(rx/filter mouse-event?)
(rx/filter mouse-up-event?))
(rx/empty))
(if interrupt?
(->> stream
(rx/filter #(= % :interrupt)))
(rx/empty)))))