Better overlays interactions on boards inside boards

This commit is contained in:
Pablo Alba 2022-11-03 13:11:17 +01:00 committed by Andrés Moya
parent 58dbe21544
commit 1affb53a26
9 changed files with 595 additions and 314 deletions

View file

@ -4,6 +4,7 @@
### :boom: Breaking changes & Deprecations ### :boom: Breaking changes & Deprecations
### :sparkles: New features ### :sparkles: New features
- Better overlays interactions on boards inside boards [Taiga #4386](https://tree.taiga.io/project/penpot/us/4386)
### :bug: Bugs fixed ### :bug: Bugs fixed
- Add title to color bullets [Taiga #4218](https://tree.taiga.io/project/penpot/task/4218) - Add title to color bullets [Taiga #4218](https://tree.taiga.io/project/penpot/task/4218)

View file

@ -87,7 +87,7 @@
:close-overlay :close-overlay
:prev-screen :prev-screen
:open-url}) :open-url})
(s/def ::position-relative-to (s/nilable ::us/uuid))
(s/def ::overlay-pos-type (s/def ::overlay-pos-type
#{:manual #{:manual
:center :center
@ -118,7 +118,8 @@
:opt-un [::destination :opt-un [::destination
::close-click-outside ::close-click-outside
::background-overlay ::background-overlay
::animation])) ::animation
::position-relative-to]))
(defmethod action-opts-spec :toggle-overlay [_] (defmethod action-opts-spec :toggle-overlay [_]
(s/keys :req-un [::overlay-position (s/keys :req-un [::overlay-position
@ -126,11 +127,13 @@
:opt-un [::destination :opt-un [::destination
::close-click-outside ::close-click-outside
::background-overlay ::background-overlay
::animation])) ::animation
::position-relative-to]))
(defmethod action-opts-spec :close-overlay [_] (defmethod action-opts-spec :close-overlay [_]
(s/keys :opt-un [::destination (s/keys :opt-un [::destination
::animation])) ::animation
::position-relative-to]))
(defmethod action-opts-spec :prev-screen [_] (defmethod action-opts-spec :prev-screen [_]
(s/keys :req-un [])) (s/keys :req-un []))
@ -159,6 +162,7 @@
{:event-type :click {:event-type :click
:action-type :navigate :action-type :navigate
:destination nil :destination nil
:position-relative-to nil
:preserve-scroll false}) :preserve-scroll false})
(def default-delay 600) (def default-delay 600)
@ -336,6 +340,13 @@
(assert (has-overlay-opts interaction)) (assert (has-overlay-opts interaction))
(assoc interaction :background-overlay background-overlay)) (assoc interaction :background-overlay background-overlay))
(defn set-position-relative-to
[interaction position-relative-to]
(us/verify ::interaction interaction)
(us/verify ::position-relative-to position-relative-to)
(assert (has-overlay-opts interaction))
(assoc interaction :position-relative-to position-relative-to))
(defn- calc-overlay-pos-initial (defn- calc-overlay-pos-initial
[destination shape objects overlay-pos-type] [destination shape objects overlay-pos-type]
(if (and (= overlay-pos-type :manual) (some? destination)) (if (and (= overlay-pos-type :manual) (some? destination))
@ -350,43 +361,58 @@
(gpt/point 0 0))) (gpt/point 0 0)))
(defn calc-overlay-position (defn calc-overlay-position
[interaction base-frame dest-frame frame-offset] [interaction ;; interaction data
relative-to-shape ;; the interaction position is realtive to this sape
base-frame ;; the base frame of the current interaction
dest-frame ;; the frame to display with this interaction
frame-offset] ;; if this interaction starts in a frame opened on another interaction, this is the position of that frame
(us/verify ::interaction interaction) (us/verify ::interaction interaction)
(assert (has-overlay-opts interaction)) (assert (has-overlay-opts interaction))
(if (nil? dest-frame) (if (nil? dest-frame)
(gpt/point 0 0) (gpt/point 0 0)
(let [overlay-size (:selrect dest-frame) (let [overlay-position (:overlay-position interaction)
base-frame-size (:selrect base-frame)] overlay-size (:selrect dest-frame)
relative-to-shape-size (:selrect relative-to-shape)
base-frame-size (:selrect base-frame)
relative-to-is-auto? (and (nil? (:position-relative-to interaction)) (not= :manual (:overlay-pos-type interaction)))
base-position (if relative-to-is-auto?
{:x 0 :y 0}
{:x (+ (:x frame-offset)
(- (:x relative-to-shape-size) (:x base-frame-size)))
:y (+ (:y frame-offset)
(- (:y relative-to-shape-size) (:y base-frame-size)))})]
(case (:overlay-pos-type interaction) (case (:overlay-pos-type interaction)
:center :center
(gpt/point (/ (- (:width base-frame-size) (:width overlay-size)) 2) (gpt/point (+ (:x base-position) (/ (- (:width relative-to-shape-size) (:width overlay-size)) 2))
(/ (- (:height base-frame-size) (:height overlay-size)) 2)) (+ (:y base-position) (/ (- (:height relative-to-shape-size) (:height overlay-size)) 2)))
:top-left :top-left
(gpt/point 0 0) (gpt/point (:x base-position) (:y base-position))
:top-right :top-right
(gpt/point (- (:width base-frame-size) (:width overlay-size)) (gpt/point (+ (:x base-position) (- (:width relative-to-shape-size) (:width overlay-size)))
0) (:y base-position))
:top-center :top-center
(gpt/point (/ (- (:width base-frame-size) (:width overlay-size)) 2) (gpt/point (+ (:x base-position) (/ (- (:width relative-to-shape-size) (:width overlay-size)) 2))
0) (:y base-position))
:bottom-left :bottom-left
(gpt/point 0 (gpt/point (:x base-position)
(- (:height base-frame-size) (:height overlay-size))) (+ (:y base-position) (- (:height relative-to-shape-size) (:height overlay-size))))
:bottom-right :bottom-right
(gpt/point (- (:width base-frame-size) (:width overlay-size)) (gpt/point (+ (:x base-position) (- (:width relative-to-shape-size) (:width overlay-size)))
(- (:height base-frame-size) (:height overlay-size))) (+ (:y base-position) (- (:height relative-to-shape-size) (:height overlay-size))))
:bottom-center :bottom-center
(gpt/point (/ (- (:width base-frame-size) (:width overlay-size)) 2) (gpt/point (+ (:x base-position) (/ (- (:width relative-to-shape-size) (:width overlay-size)) 2))
(- (:height base-frame-size) (:height overlay-size))) (+ (:y base-position) (- (:height relative-to-shape-size) (:height overlay-size))))
:manual :manual
(gpt/add (:overlay-position interaction) frame-offset))))) (gpt/point (+ (:x base-position) (:x overlay-position))
(+ (:y base-position) (:y overlay-position)))))))
(defn has-animation? (defn has-animation?
[interaction] [interaction]

View file

@ -146,7 +146,6 @@
(t/is (= :open-url (:action-type new-interaction))) (t/is (= :open-url (:action-type new-interaction)))
(t/is (= "https://example.com" (:url new-interaction))))))) (t/is (= "https://example.com" (:url new-interaction)))))))
(t/deftest option-delay (t/deftest option-delay
(let [frame (cts/make-minimal-shape :frame) (let [frame (cts/make-minimal-shape :frame)
i1 ctsi/default-interaction i1 ctsi/default-interaction
@ -269,7 +268,194 @@
(t/testing "Set background-overlay" (t/testing "Set background-overlay"
(let [new-interaction (ctsi/set-background-overlay i3 true)] (let [new-interaction (ctsi/set-background-overlay i3 true)]
(t/is (not (:background-overlay i3))) (t/is (not (:background-overlay i3)))
(t/is (:background-overlay new-interaction)))))) (t/is (:background-overlay new-interaction))))
(t/testing "Set relative-to"
(let [relative-to-id (uuid/random)
new-interaction (ctsi/set-position-relative-to i3 relative-to-id)]
(t/is (= relative-to-id (:position-relative-to new-interaction)))))))
(t/deftest calc-overlay-position
(let [base-frame (-> (cts/make-minimal-shape :frame)
(assoc-in [:selrect :width] 100)
(assoc-in [:selrect :height] 100))
popup (-> (cts/make-minimal-shape :frame)
(assoc-in [:selrect :width] 50)
(assoc-in [:selrect :height] 50)
(assoc-in [:selrect :x] 10)
(assoc-in [:selrect :y] 10))
overlay-frame (-> (cts/make-minimal-shape :frame)
(assoc-in [:selrect :width] 30)
(assoc-in [:selrect :height] 20))
objects {(:id base-frame) base-frame
(:id popup) popup
(:id overlay-frame) overlay-frame}
frame-offset (gpt/point 5 5)
interaction (-> ctsi/default-interaction
(ctsi/set-action-type :open-overlay)
(ctsi/set-destination (:id overlay-frame)))
interaction-auto (ctsi/set-position-relative-to interaction nil)
interaction-base-frame (ctsi/set-position-relative-to interaction (:id base-frame))
interaction-popup (ctsi/set-position-relative-to interaction (:id popup))]
(t/testing "Overlay top-left relative to auto"
(let [i2 (ctsi/set-overlay-pos-type interaction-auto :top-left base-frame objects)
overlay-pos (ctsi/calc-overlay-position i2 base-frame base-frame overlay-frame frame-offset)]
(t/is (= (:x overlay-pos) 0))
(t/is (= (:y overlay-pos) 0))))
(t/testing "Overlay top-center relative to auto"
(let [i2 (ctsi/set-overlay-pos-type interaction-auto :top-center base-frame objects)
overlay-pos (ctsi/calc-overlay-position i2 base-frame base-frame overlay-frame frame-offset)]
(t/is (= (:x overlay-pos) 35))
(t/is (= (:y overlay-pos) 0))))
(t/testing "Overlay top-right relative to auto"
(let [i2 (ctsi/set-overlay-pos-type interaction-auto :top-right base-frame objects)
overlay-pos (ctsi/calc-overlay-position i2 base-frame base-frame overlay-frame frame-offset)]
(t/is (= (:x overlay-pos) 70))
(t/is (= (:y overlay-pos) 0))))
(t/testing "Overlay bottom-left relative to auto"
(let [i2 (ctsi/set-overlay-pos-type interaction-auto :bottom-left base-frame objects)
overlay-pos (ctsi/calc-overlay-position i2 base-frame base-frame overlay-frame frame-offset)]
(t/is (= (:x overlay-pos) 0))
(t/is (= (:y overlay-pos) 80))))
(t/testing "Overlay bottom-center relative to auto"
(let [i2 (ctsi/set-overlay-pos-type interaction-auto :bottom-center base-frame objects)
overlay-pos (ctsi/calc-overlay-position i2 base-frame base-frame overlay-frame frame-offset)]
(t/is (= (:x overlay-pos) 35))
(t/is (= (:y overlay-pos) 80))))
(t/testing "Overlay bottom-right relative to auto"
(let [i2 (ctsi/set-overlay-pos-type interaction-auto :bottom-right base-frame objects)
overlay-pos (ctsi/calc-overlay-position i2 base-frame base-frame overlay-frame frame-offset)]
(t/is (= (:x overlay-pos) 70))
(t/is (= (:y overlay-pos) 80))))
(t/testing "Overlay center relative to auto"
(let [i2 (ctsi/set-overlay-pos-type interaction-auto :center base-frame objects)
overlay-pos (ctsi/calc-overlay-position i2 base-frame base-frame overlay-frame frame-offset)]
(t/is (= (:x overlay-pos) 35))
(t/is (= (:y overlay-pos) 40))))
(t/testing "Overlay manual relative to auto"
(let [i2 (ctsi/set-overlay-pos-type interaction-auto :center base-frame objects)
overlay-pos (ctsi/calc-overlay-position i2 base-frame base-frame overlay-frame frame-offset)]
(t/is (= (:x overlay-pos) 35))
(t/is (= (:y overlay-pos) 40))))
(t/testing "Overlay manual relative to auto"
(let [i2 (-> interaction-auto
(ctsi/set-overlay-pos-type :manual base-frame objects)
(ctsi/set-overlay-position (gpt/point 12 62)))
overlay-pos (ctsi/calc-overlay-position i2 base-frame base-frame overlay-frame frame-offset)]
(t/is (= (:x overlay-pos) 17))
(t/is (= (:y overlay-pos) 67))))
(t/testing "Overlay top-left relative to base-frame"
(let [i2 (ctsi/set-overlay-pos-type interaction-base-frame :top-left base-frame objects)
overlay-pos (ctsi/calc-overlay-position i2 base-frame base-frame overlay-frame frame-offset)]
(t/is (= (:x overlay-pos) 5))
(t/is (= (:y overlay-pos) 5))))
(t/testing "Overlay top-center relative to base-frame"
(let [i2 (ctsi/set-overlay-pos-type interaction-base-frame :top-center base-frame objects)
overlay-pos (ctsi/calc-overlay-position i2 base-frame base-frame overlay-frame frame-offset)]
(t/is (= (:x overlay-pos) 40))
(t/is (= (:y overlay-pos) 5))))
(t/testing "Overlay top-right relative to base-frame"
(let [i2 (ctsi/set-overlay-pos-type interaction-base-frame :top-right base-frame objects)
overlay-pos (ctsi/calc-overlay-position i2 base-frame base-frame overlay-frame frame-offset)]
(t/is (= (:x overlay-pos) 75))
(t/is (= (:y overlay-pos) 5))))
(t/testing "Overlay bottom-left relative to base-frame"
(let [i2 (ctsi/set-overlay-pos-type interaction-base-frame :bottom-left base-frame objects)
overlay-pos (ctsi/calc-overlay-position i2 base-frame base-frame overlay-frame frame-offset)]
(t/is (= (:x overlay-pos) 5))
(t/is (= (:y overlay-pos) 85))))
(t/testing "Overlay bottom-center relative to base-frame"
(let [i2 (ctsi/set-overlay-pos-type interaction-base-frame :bottom-center base-frame objects)
overlay-pos (ctsi/calc-overlay-position i2 base-frame base-frame overlay-frame frame-offset)]
(t/is (= (:x overlay-pos) 40))
(t/is (= (:y overlay-pos) 85))))
(t/testing "Overlay bottom-right relative to base-frame"
(let [i2 (ctsi/set-overlay-pos-type interaction-base-frame :bottom-right base-frame objects)
overlay-pos (ctsi/calc-overlay-position i2 base-frame base-frame overlay-frame frame-offset)]
(t/is (= (:x overlay-pos) 75))
(t/is (= (:y overlay-pos) 85))))
(t/testing "Overlay center relative to base-frame"
(let [i2 (ctsi/set-overlay-pos-type interaction-base-frame :center base-frame objects)
overlay-pos (ctsi/calc-overlay-position i2 base-frame base-frame overlay-frame frame-offset)]
(t/is (= (:x overlay-pos) 40))
(t/is (= (:y overlay-pos) 45))))
(t/testing "Overlay manual relative to base-frame"
(let [i2 (-> interaction-base-frame
(ctsi/set-overlay-pos-type :manual base-frame objects)
(ctsi/set-overlay-position (gpt/point 12 62)))
overlay-pos (ctsi/calc-overlay-position i2 base-frame base-frame overlay-frame frame-offset)]
(t/is (= (:x overlay-pos) 17))
(t/is (= (:y overlay-pos) 67))))
(t/testing "Overlay top-left relative to popup"
(let [i2 (ctsi/set-overlay-pos-type interaction-popup :top-left base-frame objects)
overlay-pos (ctsi/calc-overlay-position i2 popup base-frame overlay-frame frame-offset)]
(t/is (= (:x overlay-pos) 15))
(t/is (= (:y overlay-pos) 15))))
(t/testing "Overlay top-center relative to popup"
(let [i2 (ctsi/set-overlay-pos-type interaction-popup :top-center base-frame objects)
overlay-pos (ctsi/calc-overlay-position i2 popup base-frame overlay-frame frame-offset)]
(t/is (= (:x overlay-pos) 25))
(t/is (= (:y overlay-pos) 15))))
(t/testing "Overlay top-right relative to popup"
(let [i2 (ctsi/set-overlay-pos-type interaction-popup :top-right base-frame objects)
overlay-pos (ctsi/calc-overlay-position i2 popup base-frame overlay-frame frame-offset)]
(t/is (= (:x overlay-pos) 35))
(t/is (= (:y overlay-pos) 15))))
(t/testing "Overlay bottom-left relative to popup"
(let [i2 (ctsi/set-overlay-pos-type interaction-popup :bottom-left base-frame objects)
overlay-pos (ctsi/calc-overlay-position i2 popup base-frame overlay-frame frame-offset)]
(t/is (= (:x overlay-pos) 15))
(t/is (= (:y overlay-pos) 45))))
(t/testing "Overlay bottom-center relative to popup"
(let [i2 (ctsi/set-overlay-pos-type interaction-popup :bottom-center base-frame objects)
overlay-pos (ctsi/calc-overlay-position i2 popup base-frame overlay-frame frame-offset)]
(t/is (= (:x overlay-pos) 25))
(t/is (= (:y overlay-pos) 45))))
(t/testing "Overlay bottom-right relative to popup"
(let [i2 (ctsi/set-overlay-pos-type interaction-popup :bottom-right base-frame objects)
overlay-pos (ctsi/calc-overlay-position i2 popup base-frame overlay-frame frame-offset)]
(t/is (= (:x overlay-pos) 35))
(t/is (= (:y overlay-pos) 45))))
(t/testing "Overlay center relative to popup"
(let [i2 (ctsi/set-overlay-pos-type interaction-popup :center base-frame objects)
overlay-pos (ctsi/calc-overlay-position i2 popup base-frame overlay-frame frame-offset)]
(t/is (= (:x overlay-pos) 25))
(t/is (= (:y overlay-pos) 30))))
(t/testing "Overlay manual relative to popup"
(let [i2 (-> interaction-popup
(ctsi/set-overlay-pos-type :manual base-frame objects)
(ctsi/set-overlay-position (gpt/point 12 62)))
overlay-pos (ctsi/calc-overlay-position i2 popup base-frame overlay-frame frame-offset)]
(t/is (= (:x overlay-pos) 27))
(t/is (= (:y overlay-pos) 77))))))
(t/deftest animation-checks (t/deftest animation-checks

View file

@ -121,9 +121,9 @@
(rx/concat (rx/concat
(rx/of (dch/update-shapes [(:id shape)] (rx/of (dch/update-shapes [(:id shape)]
(fn [shape] (fn [shape]
(let [new-interaction (ctsi/set-destination (let [new-interaction (-> ctsi/default-interaction
ctsi/default-interaction (ctsi/set-destination destination)
destination)] (assoc :position-relative-to (:id shape)))]
(update shape :interactions (update shape :interactions
ctsi/add-interaction new-interaction))))) ctsi/add-interaction new-interaction)))))
(when (and (not (connected-frame? objects (:id frame))) (when (and (not (connected-frame? objects (:id frame)))

View file

@ -388,6 +388,9 @@
(def viewer-local (def viewer-local
(l/derived :viewer-local st/state)) (l/derived :viewer-local st/state))
(def viewer-overlays
(l/derived :viewer-overlays st/state))
(def comment-threads (def comment-threads
(l/derived :comment-threads st/state)) (l/derived :comment-threads st/state))

View file

@ -36,8 +36,16 @@
(def viewer-interactions-show? (def viewer-interactions-show?
(l/derived :interactions-show? refs/viewer-local)) (l/derived :interactions-show? refs/viewer-local))
(defn- find-relative-to-base-frame
[shape objects overlays-ids base-frame]
(if (or (empty? overlays-ids) (nil? shape) (cph/root? shape))
base-frame
(if (contains? overlays-ids (:id shape))
shape
(find-relative-to-base-frame (cph/get-parent objects (:id shape)) objects overlays-ids base-frame))))
(defn- activate-interaction (defn- activate-interaction
[interaction shape base-frame frame-offset objects] [interaction shape base-frame frame-offset objects overlays]
(case (:action-type interaction) (case (:action-type interaction)
:navigate :navigate
(when-let [frame-id (:destination interaction)] (when-let [frame-id (:destination interaction)]
@ -50,12 +58,18 @@
:open-overlay :open-overlay
(let [dest-frame-id (:destination interaction) (let [dest-frame-id (:destination interaction)
dest-frame (get objects dest-frame-id)
relative-to-id (if (= :manual (:overlay-pos-type interaction))
(:id shape) ;; manual interactions are allways from "self"
(:position-relative-to interaction))
relative-to-shape (or (get objects relative-to-id) base-frame)
close-click-outside (:close-click-outside interaction) close-click-outside (:close-click-outside interaction)
background-overlay (:background-overlay interaction) background-overlay (:background-overlay interaction)
overlays-ids (set (map :id overlays))
dest-frame (get objects dest-frame-id) relative-to-base-frame (find-relative-to-base-frame relative-to-shape objects overlays-ids base-frame)
position (ctsi/calc-overlay-position interaction position (ctsi/calc-overlay-position interaction
base-frame relative-to-shape
relative-to-base-frame
dest-frame dest-frame
frame-offset)] frame-offset)]
(when dest-frame-id (when dest-frame-id
@ -68,10 +82,18 @@
:toggle-overlay :toggle-overlay
(let [frame-id (:destination interaction) (let [frame-id (:destination interaction)
dest-frame (get objects frame-id) dest-frame (get objects frame-id)
relative-to-id (if (= :manual (:overlay-pos-type interaction))
(:id shape) ;; manual interactions are allways from "self"
(:position-relative-to interaction))
relative-to-shape (or (get objects relative-to-id) base-frame)
overlays-ids (set (map :id overlays))
relative-to-base-frame (find-relative-to-base-frame relative-to-shape objects overlays-ids base-frame)
position (ctsi/calc-overlay-position interaction position (ctsi/calc-overlay-position interaction
base-frame relative-to-shape
relative-to-base-frame
dest-frame dest-frame
frame-offset) frame-offset)
close-click-outside (:close-click-outside interaction) close-click-outside (:close-click-outside interaction)
background-overlay (:background-overlay interaction)] background-overlay (:background-overlay interaction)]
(when frame-id (when frame-id
@ -98,7 +120,7 @@
;; Perform the opposite action of an interaction, if possible ;; Perform the opposite action of an interaction, if possible
(defn- deactivate-interaction (defn- deactivate-interaction
[interaction shape base-frame frame-offset objects] [interaction shape base-frame frame-offset objects overlays]
(case (:action-type interaction) (case (:action-type interaction)
:open-overlay :open-overlay
(let [frame-id (or (:destination interaction) (let [frame-id (or (:destination interaction)
@ -121,12 +143,18 @@
:close-overlay :close-overlay
(let [dest-frame-id (:destination interaction) (let [dest-frame-id (:destination interaction)
dest-frame (get objects dest-frame-id)
relative-to-id (if (= :manual (:overlay-pos-type interaction))
(:id shape) ;; manual interactions are allways from "self"
(:position-relative-to interaction))
relative-to-shape (or (get objects relative-to-id) base-frame)
close-click-outside (:close-click-outside interaction) close-click-outside (:close-click-outside interaction)
background-overlay (:background-overlay interaction) background-overlay (:background-overlay interaction)
overlays-ids (set (map :id overlays))
dest-frame (get objects dest-frame-id) relative-to-base-frame (find-relative-to-base-frame relative-to-shape objects overlays-ids base-frame)
position (ctsi/calc-overlay-position interaction position (ctsi/calc-overlay-position interaction
base-frame relative-to-shape
relative-to-base-frame
dest-frame dest-frame
frame-offset)] frame-offset)]
(when dest-frame-id (when dest-frame-id
@ -138,36 +166,36 @@
nil)) nil))
(defn- on-mouse-down (defn- on-mouse-down
[event shape base-frame frame-offset objects] [event shape base-frame frame-offset objects overlays]
(let [interactions (->> (:interactions shape) (let [interactions (->> (:interactions shape)
(filter #(or (= (:event-type %) :click) (filter #(or (= (:event-type %) :click)
(= (:event-type %) :mouse-press))))] (= (:event-type %) :mouse-press))))]
(when (seq interactions) (when (seq interactions)
(dom/stop-propagation event) (dom/stop-propagation event)
(doseq [interaction interactions] (doseq [interaction interactions]
(activate-interaction interaction shape base-frame frame-offset objects))))) (activate-interaction interaction shape base-frame frame-offset objects overlays)))))
(defn- on-mouse-up (defn- on-mouse-up
[event shape base-frame frame-offset objects] [event shape base-frame frame-offset objects overlays]
(let [interactions (->> (:interactions shape) (let [interactions (->> (:interactions shape)
(filter #(= (:event-type %) :mouse-press)))] (filter #(= (:event-type %) :mouse-press)))]
(when (seq interactions) (when (seq interactions)
(dom/stop-propagation event) (dom/stop-propagation event)
(doseq [interaction interactions] (doseq [interaction interactions]
(deactivate-interaction interaction shape base-frame frame-offset objects))))) (deactivate-interaction interaction shape base-frame frame-offset objects overlays)))))
(defn- on-mouse-enter (defn- on-mouse-enter
[event shape base-frame frame-offset objects] [event shape base-frame frame-offset objects overlays]
(let [interactions (->> (:interactions shape) (let [interactions (->> (:interactions shape)
(filter #(or (= (:event-type %) :mouse-enter) (filter #(or (= (:event-type %) :mouse-enter)
(= (:event-type %) :mouse-over))))] (= (:event-type %) :mouse-over))))]
(when (seq interactions) (when (seq interactions)
(dom/stop-propagation event) (dom/stop-propagation event)
(doseq [interaction interactions] (doseq [interaction interactions]
(activate-interaction interaction shape base-frame frame-offset objects))))) (activate-interaction interaction shape base-frame frame-offset objects overlays)))))
(defn- on-mouse-leave (defn- on-mouse-leave
[event shape base-frame frame-offset objects] [event shape base-frame frame-offset objects overlays]
(let [interactions (->> (:interactions shape) (let [interactions (->> (:interactions shape)
(filter #(= (:event-type %) :mouse-leave))) (filter #(= (:event-type %) :mouse-leave)))
interactions-inv (->> (:interactions shape) interactions-inv (->> (:interactions shape)
@ -175,19 +203,19 @@
(when (or (seq interactions) (seq interactions-inv)) (when (or (seq interactions) (seq interactions-inv))
(dom/stop-propagation event) (dom/stop-propagation event)
(doseq [interaction interactions] (doseq [interaction interactions]
(activate-interaction interaction shape base-frame frame-offset objects)) (activate-interaction interaction shape base-frame frame-offset objects overlays))
(doseq [interaction interactions-inv] (doseq [interaction interactions-inv]
(deactivate-interaction interaction shape base-frame frame-offset objects))))) (deactivate-interaction interaction shape base-frame frame-offset objects overlays)))))
(defn- on-load (defn- on-load
[shape base-frame frame-offset objects] [shape base-frame frame-offset objects overlays]
(let [interactions (->> (:interactions shape) (let [interactions (->> (:interactions shape)
(filter #(= (:event-type %) :after-delay)))] (filter #(= (:event-type %) :after-delay)))]
(loop [interactions (seq interactions) (loop [interactions (seq interactions)
sems []] sems []]
(if-let [interaction (first interactions)] (if-let [interaction (first interactions)]
(let [sem (tm/schedule (:delay interaction) (let [sem (tm/schedule (:delay interaction)
#(activate-interaction interaction shape base-frame frame-offset objects))] #(activate-interaction interaction shape base-frame frame-offset objects overlays))]
(recur (next interactions) (recur (next interactions)
(conj sems sem))) (conj sems sem)))
sems)))) sems))))
@ -209,6 +237,7 @@
:transform (gsh/transform-str shape)}]))) :transform (gsh/transform-str shape)}])))
;; TODO: use-memo use-fn ;; TODO: use-memo use-fn
(defn generic-wrapper-factory (defn generic-wrapper-factory
@ -223,34 +252,31 @@
objects (unchecked-get props "objects") objects (unchecked-get props "objects")
base-frame (mf/use-ctx base-frame-ctx) base-frame (mf/use-ctx base-frame-ctx)
frame-offset (mf/use-ctx frame-offset-ctx) frame-offset (mf/use-ctx frame-offset-ctx)
interactions-show? (mf/deref viewer-interactions-show?) interactions-show? (mf/deref viewer-interactions-show?)
overlays (mf/deref refs/viewer-overlays)
interactions (:interactions shape) interactions (:interactions shape)
svg-element? (and (= :svg-raw (:type shape)) svg-element? (and (= :svg-raw (:type shape))
(not= :svg (get-in shape [:content :tag]))) (not= :svg (get-in shape [:content :tag])))
on-mouse-down on-mouse-down
(mf/use-fn (mf/deps shape base-frame frame-offset objects) (mf/use-fn (mf/deps shape base-frame frame-offset objects)
#(on-mouse-down % shape base-frame frame-offset objects)) #(on-mouse-down % shape base-frame frame-offset objects overlays))
on-mouse-up on-mouse-up
(mf/use-fn (mf/deps shape base-frame frame-offset objects) (mf/use-fn (mf/deps shape base-frame frame-offset objects)
#(on-mouse-up % shape base-frame frame-offset objects)) #(on-mouse-up % shape base-frame frame-offset objects overlays))
on-mouse-enter on-mouse-enter
(mf/use-fn (mf/deps shape base-frame frame-offset objects) (mf/use-fn (mf/deps shape base-frame frame-offset objects)
#(on-mouse-enter % shape base-frame frame-offset objects)) #(on-mouse-enter % shape base-frame frame-offset objects overlays))
on-mouse-leave on-mouse-leave
(mf/use-fn (mf/deps shape base-frame frame-offset objects) (mf/use-fn (mf/deps shape base-frame frame-offset objects)
#(on-mouse-leave % shape base-frame frame-offset objects))] #(on-mouse-leave % shape base-frame frame-offset objects overlays))]
(mf/with-effect [] (mf/with-effect []
(let [sems (on-load shape base-frame frame-offset objects)] (let [sems (on-load shape base-frame frame-offset objects overlays)]
(partial run! tm/dispose! sems))) (partial run! tm/dispose! sems)))
(if-not svg-element? (if-not svg-element?
@ -401,9 +427,7 @@
svg-raw-container svg-raw-container
(mf/with-memo [objects] (mf/with-memo [objects]
(svg-raw-container-factory objects)) (svg-raw-container-factory objects))]
]
(when (and shape (not (:hidden shape))) (when (and shape (not (:hidden shape)))
(let [shape (-> (gsh/transform-shape shape) (let [shape (-> (gsh/transform-shape shape)
(gsh/translate-to-frame frame)) (gsh/translate-to-frame frame))

View file

@ -184,6 +184,8 @@
destination (get objects (:destination interaction)) destination (get objects (:destination interaction))
frames (mf/with-memo [objects] (ctt/get-viewer-frames objects {:all-frames? true})) frames (mf/with-memo [objects] (ctt/get-viewer-frames objects {:all-frames? true}))
shape-parent-ids (mf/with-memo [objects] (cph/get-parent-ids objects (:id shape)))
shape-parents (mf/with-memo [frames shape] (filter (comp (set shape-parent-ids) :id) frames))
overlay-pos-type (:overlay-pos-type interaction) overlay-pos-type (:overlay-pos-type interaction)
close-click-outside? (:close-click-outside interaction false) close-click-outside? (:close-click-outside interaction false)
@ -220,6 +222,14 @@
value (when (not= value "") (uuid/uuid value))] value (when (not= value "") (uuid/uuid value))]
(update-interaction index #(ctsi/set-destination % value)))) (update-interaction index #(ctsi/set-destination % value))))
change-position-relative-to
(fn [event]
(let [value (-> event
dom/get-target
dom/get-value
uuid/uuid)]
(update-interaction index #(ctsi/set-position-relative-to % value))))
change-preserve-scroll change-preserve-scroll
(fn [event] (fn [event]
(let [value (-> event dom/get-target dom/checked?)] (let [value (-> event dom/get-target dom/checked?)]
@ -243,9 +253,12 @@
(dom/add-class! target "error")))) (dom/add-class! target "error"))))
change-overlay-pos-type change-overlay-pos-type
(fn [event] (fn [shape-id event]
(let [value (-> event dom/get-target dom/get-value d/read-string)] (let [value (-> event dom/get-target dom/get-value d/read-string)]
(update-interaction index #(ctsi/set-overlay-pos-type % value shape objects)))) (update-interaction index #(ctsi/set-overlay-pos-type % value shape objects))
(when (= value :manual)
(update-interaction index #(ctsi/set-position-relative-to % shape-id)))))
toggle-overlay-pos-type toggle-overlay-pos-type
(fn [pos-type] (fn [pos-type]
@ -287,8 +300,7 @@
change-offset-effect change-offset-effect
(fn [event] (fn [event]
(let [value (-> event dom/get-target dom/checked?)] (let [value (-> event dom/get-target dom/checked?)]
(update-interaction index #(ctsi/set-offset-effect % value)))) (update-interaction index #(ctsi/set-offset-effect % value))))]
]
[:* [:*
[:div.element-set-options-group {:class (dom/classnames [:div.element-set-options-group {:class (dom/classnames
@ -378,12 +390,27 @@
(when (ctsi/has-overlay-opts interaction) (when (ctsi/has-overlay-opts interaction)
[:* [:*
; Overlay position relative-to (select)
[:div.interactions-element
[:span.element-set-subtitle.wide (tr "workspace.options.interaction-relative-to")]
[:select.input-select
{:value (str (:position-relative-to interaction))
:on-change change-position-relative-to}
(when (not= (:overlay-pos-type interaction) :manual)
[:*
[:option {:value ""} (tr "workspace.options.interaction-auto")]
(for [frame shape-parents]
[:option {:key (dm/str "position-relative-to-" (:id frame))
:value (str (:id frame))} (:name frame)])])
[:option {:key (dm/str "position-relative-to-" (:id shape))
:value (str (:id shape))} (:name shape) " (" (tr "workspace.options.interaction-self") ")"]]]
; Overlay position (select) ; Overlay position (select)
[:div.interactions-element [:div.interactions-element
[:span.element-set-subtitle.wide (tr "workspace.options.interaction-position")] [:span.element-set-subtitle.wide (tr "workspace.options.interaction-position")]
[:select.input-select [:select.input-select
{:value (str (:overlay-pos-type interaction)) {:value (str (:overlay-pos-type interaction))
:on-change change-overlay-pos-type} :on-change (partial change-overlay-pos-type (:id shape))}
(for [[value name] (overlay-pos-type-names)] (for [[value name] (overlay-pos-type-names)]
[:option {:value (str value)} name])]] [:option {:value (str value)} name])]]

View file

@ -3222,6 +3222,9 @@ msgstr "Push"
msgid "workspace.options.interaction-animation-slide" msgid "workspace.options.interaction-animation-slide"
msgstr "Slide" msgstr "Slide"
msgid "workspace.options.interaction-auto"
msgstr "auto"
#: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs #: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs
msgid "workspace.options.interaction-background" msgid "workspace.options.interaction-background"
msgstr "Add background overlay" msgstr "Add background overlay"
@ -3362,6 +3365,10 @@ msgstr "Top right"
msgid "workspace.options.interaction-position" msgid "workspace.options.interaction-position"
msgstr "Position" msgstr "Position"
#: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs
msgid "workspace.options.interaction-relative-to"
msgstr "Relative to"
#: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs #: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs
msgid "workspace.options.interaction-preserve-scroll" msgid "workspace.options.interaction-preserve-scroll"
msgstr "Preserve scroll position" msgstr "Preserve scroll position"

View file

@ -3621,6 +3621,9 @@ msgstr "Empujar"
msgid "workspace.options.interaction-animation-slide" msgid "workspace.options.interaction-animation-slide"
msgstr "Deslizar" msgstr "Deslizar"
msgid "workspace.options.interaction-auto"
msgstr "automático"
#: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs #: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs
msgid "workspace.options.interaction-background" msgid "workspace.options.interaction-background"
msgstr "Añadir sombreado de fondo" msgstr "Añadir sombreado de fondo"
@ -3761,6 +3764,10 @@ msgstr "Arriba derecha"
msgid "workspace.options.interaction-position" msgid "workspace.options.interaction-position"
msgstr "Posición" msgstr "Posición"
#: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs
msgid "workspace.options.interaction-relative-to"
msgstr "Relativo a"
#: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs #: src/app/main/ui/workspace/sidebar/options/menus/interactions.cljs
msgid "workspace.options.interaction-preserve-scroll" msgid "workspace.options.interaction-preserve-scroll"
msgstr "Conservar posición de desplazamiento" msgstr "Conservar posición de desplazamiento"