diff --git a/CHANGES.md b/CHANGES.md index 268b5febb..23b3a3884 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -23,6 +23,7 @@ - Fix problem with system shortcuts and application [#737](https://github.com/penpot/penpot/issues/737) - Fix issue with typographies panel cannot be collapsed [#707](https://github.com/penpot/penpot/issues/707) - Fix problem with middle mouse button press moving the canvas when not moving mouse [#717](https://github.com/penpot/penpot/issues/717) +- Fix problem with masks interactions outside bounds [#718](https://github.com/penpot/penpot/issues/718) ### :heart: Community contributions by (Thank you!) diff --git a/frontend/src/app/main/ui/shapes/group.cljs b/frontend/src/app/main/ui/shapes/group.cljs index 991ee92ca..c355b30d5 100644 --- a/frontend/src/app/main/ui/shapes/group.cljs +++ b/frontend/src/app/main/ui/shapes/group.cljs @@ -12,7 +12,7 @@ [app.util.object :as obj] [rumext.alpha :as mf] [app.main.ui.shapes.attrs :as attrs] - [app.main.ui.shapes.mask :refer [mask-str mask-factory]])) + [app.main.ui.shapes.mask :refer [mask-str clip-str mask-factory]])) (defn group-shape [shape-wrapper] @@ -35,6 +35,7 @@ props (-> (attrs/extract-style-attrs shape) (obj/merge! #js {:pointerEvents pointer-events + :clipPath (when (and mask (not expand-mask)) (clip-str mask)) :mask (when (and mask (not expand-mask)) (mask-str mask))}))] [:> :g props diff --git a/frontend/src/app/main/ui/shapes/mask.cljs b/frontend/src/app/main/ui/shapes/mask.cljs index fab611fd3..07ccb7cf9 100644 --- a/frontend/src/app/main/ui/shapes/mask.cljs +++ b/frontend/src/app/main/ui/shapes/mask.cljs @@ -10,18 +10,25 @@ (ns app.main.ui.shapes.mask (:require [rumext.alpha :as mf] - [cuerdas.core :as str])) + [cuerdas.core :as str] + [app.common.geom.shapes :as gsh])) (defn mask-str [mask] (str/fmt "url(#%s)" (str (:id mask) "-mask"))) +(defn clip-str [mask] + (str/fmt "url(#%s)" (str (:id mask) "-clip"))) + (defn mask-factory [shape-wrapper] (mf/fnc mask-shape {::mf/wrap-props false} [props] (let [frame (unchecked-get props "frame") - mask (unchecked-get props "mask")] + mask (unchecked-get props "mask") + mask' (-> mask + (gsh/transform-shape) + (gsh/translate-to-frame frame))] [:defs [:filter {:id (str (:id mask) "-filter")} [:feFlood {:flood-color "white" @@ -30,8 +37,16 @@ :in2 "SourceGraphic" :operator "in" :result "comp"}]] + ;; Clip path is necesary so the elements inside the mask won't affect + ;; the events outside. Clip hides the elements but mask doesn't (like display vs visibility) + ;; we cannot use clips instead of mask because clips can only be simple shapes + [:clipPath {:id (str (:id mask) "-clip")} + [:polyline {:points (->> (:points mask') + (map #(str (:x %) "," (:y %))) + (str/join " "))}]] [:mask {:id (str (:id mask) "-mask")} [:g {:filter (str/fmt "url(#%s)" (str (:id mask) "-filter"))} - [:& shape-wrapper {:frame frame :shape (-> mask - (dissoc :shadow :blur))}]]]]))) + [:& shape-wrapper {:frame frame + :shape (-> mask + (dissoc :shadow :blur))}]]]])))