mirror of
https://github.com/penpot/penpot.git
synced 2025-01-10 17:00:36 -05:00
✨ Fix masks for Firefox
This commit is contained in:
parent
96eacb6efe
commit
d0e008665f
3 changed files with 64 additions and 29 deletions
|
@ -17,11 +17,15 @@
|
|||
:width width
|
||||
:height height})
|
||||
|
||||
(defn position-data-bounding-box
|
||||
(defn position-data-points
|
||||
[{:keys [position-data] :as shape}]
|
||||
(let [points (->> position-data
|
||||
(mapcat (comp gpr/rect->points position-data->rect)))
|
||||
transform (gtr/transform-matrix shape)
|
||||
points (gco/transform-points points transform)]
|
||||
(gpr/points->selrect points)))
|
||||
transform (gtr/transform-matrix shape)]
|
||||
(gco/transform-points points transform)))
|
||||
|
||||
(defn position-data-bounding-box
|
||||
[shape]
|
||||
(gpr/points->selrect (position-data-points shape)))
|
||||
|
||||
|
||||
|
|
|
@ -6,7 +6,9 @@
|
|||
|
||||
(ns app.main.ui.shapes.mask
|
||||
(:require
|
||||
[app.common.data :as d]
|
||||
[app.common.geom.shapes :as gsh]
|
||||
[app.common.geom.shapes.text :as gst]
|
||||
[app.main.ui.context :as muc]
|
||||
[cuerdas.core :as str]
|
||||
[rumext.alpha :as mf]))
|
||||
|
@ -29,6 +31,17 @@
|
|||
(defn filter-url [render-id mask]
|
||||
(str "url(#" (filter-id render-id mask) ")"))
|
||||
|
||||
(defn set-white-fill
|
||||
[shape]
|
||||
(let [update-color
|
||||
(fn [data]
|
||||
(-> data
|
||||
(dissoc :fill-color :fill-opacity :fill-color-gradient)
|
||||
(assoc :fill-color "#FFFFFF" :fill-opacity 1)))]
|
||||
(-> shape
|
||||
(d/update-when :position-data #(mapv update-color %))
|
||||
(assoc :stroke-color "#FFFFFF" :stroke-opacity 1))))
|
||||
|
||||
(defn mask-factory
|
||||
[shape-wrapper]
|
||||
(mf/fnc mask-shape
|
||||
|
@ -36,25 +49,44 @@
|
|||
[props]
|
||||
(let [mask (unchecked-get props "mask")
|
||||
render-id (mf/use-ctx muc/render-ctx)
|
||||
mask' (gsh/transform-shape mask)]
|
||||
[:defs
|
||||
[:filter {:id (filter-id render-id mask)}
|
||||
[:feFlood {:flood-color "white"
|
||||
:result "FloodResult"}]
|
||||
[:feComposite {:in "FloodResult"
|
||||
:in2 "SourceGraphic"
|
||||
:operator "in"
|
||||
:result "comp"}]]
|
||||
;; Clip path is necessary 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 {:class "mask-clip-path"
|
||||
:id (clip-id render-id mask)}
|
||||
[:polyline {:points (->> (:points mask')
|
||||
(map #(str (:x %) "," (:y %)))
|
||||
(str/join " "))}]]
|
||||
[:mask {:class "mask-shape"
|
||||
:id (mask-id render-id mask)}
|
||||
[:g {:filter (filter-url render-id mask)}
|
||||
[:& shape-wrapper {:shape (dissoc mask :shadow :blur)}]]]])))
|
||||
svg-text? (and (= :text (:type mask)) (some? (:position-data mask)))
|
||||
|
||||
mask (cond-> mask svg-text? set-white-fill)
|
||||
|
||||
mask-bb
|
||||
(cond
|
||||
svg-text?
|
||||
(gst/position-data-points mask)
|
||||
|
||||
:else
|
||||
(-> (gsh/transform-shape mask)
|
||||
(:points)))]
|
||||
[:*
|
||||
[:g {:opacity 0}
|
||||
[:g {:id (str "shape-" (mask-id render-id mask))}
|
||||
[:& shape-wrapper {:shape (dissoc mask :shadow :blur)}]]]
|
||||
|
||||
[:defs
|
||||
[:filter {:id (filter-id render-id mask)}
|
||||
[:feFlood {:flood-color "white"
|
||||
:result "FloodResult"}]
|
||||
[:feComposite {:in "FloodResult"
|
||||
:in2 "SourceGraphic"
|
||||
:operator "in"
|
||||
:result "comp"}]]
|
||||
;; Clip path is necessary 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 {:class "mask-clip-path"
|
||||
:id (clip-id render-id mask)}
|
||||
[:polyline {:points (->> mask-bb
|
||||
(map #(str (:x %) "," (:y %)))
|
||||
(str/join " "))}]]
|
||||
|
||||
[:mask {:class "mask-shape"
|
||||
:id (mask-id render-id mask)}
|
||||
;; SVG texts are broken in Firefox with the filter. When the masking shapes is a text
|
||||
;; we use the `set-white-fill` instead of using the filter
|
||||
[:g {:filter (when-not svg-text? (filter-url render-id mask))}
|
||||
[:use {:href (str "#shape-" (mask-id render-id mask))}]]]]])))
|
||||
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
(ns app.main.ui.workspace.shapes.text
|
||||
(:require
|
||||
[app.common.attrs :as attrs]
|
||||
[app.common.data :as d]
|
||||
[app.common.geom.matrix :as gmt]
|
||||
[app.common.geom.shapes :as gsh]
|
||||
[app.common.logging :as log]
|
||||
|
@ -123,7 +122,7 @@
|
|||
(mf/defc text-wrapper
|
||||
{::mf/wrap-props false}
|
||||
[props]
|
||||
(let [{:keys [id content points] :as shape} (unchecked-get props "shape")
|
||||
(let [{:keys [id] :as shape} (unchecked-get props "shape")
|
||||
edition-ref (mf/use-memo (mf/deps id) #(l/derived (fn [o] (= id (:edition o))) refs/workspace-local))
|
||||
edition? (mf/deref edition-ref)
|
||||
|
||||
|
@ -150,7 +149,7 @@
|
|||
(gsh/transform-rect mtx)))))]
|
||||
(reset! local-position-data position-data))))
|
||||
|
||||
[shape-ref on-change-node] (use-mutable-observer handle-change-foreign-object)
|
||||
[_ on-change-node] (use-mutable-observer handle-change-foreign-object)
|
||||
|
||||
show-svg-text? (or (some? (:position-data shape)) (some? @local-position-data))
|
||||
|
||||
|
@ -170,7 +169,7 @@
|
|||
(fn []
|
||||
;; Timer to update the shape. We do this so a lot of changes won't produce
|
||||
;; a lot of updates (kind of a debounce)
|
||||
(let [sid (timers/schedule 250 update-position-data)]
|
||||
(let [sid (timers/schedule 100 update-position-data)]
|
||||
(fn []
|
||||
(rx/dispose! sid)))))
|
||||
|
||||
|
|
Loading…
Reference in a new issue