mirror of
https://github.com/penpot/penpot.git
synced 2025-05-05 15:05:54 +02:00
92 lines
3.1 KiB
Clojure
92 lines
3.1 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) UXBOX Labs SL
|
|
|
|
(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]))
|
|
|
|
(defn mask-id [render-id mask]
|
|
(str render-id "-" (:id mask) "-mask"))
|
|
|
|
(defn mask-url [render-id mask]
|
|
(str "url(#" (mask-id render-id mask) ")"))
|
|
|
|
(defn clip-id [render-id mask]
|
|
(str render-id "-" (:id mask) "-clip"))
|
|
|
|
(defn clip-url [render-id mask]
|
|
(str "url(#" (clip-id render-id mask) ")"))
|
|
|
|
(defn filter-id [render-id mask]
|
|
(str render-id "-" (:id mask) "-filter"))
|
|
|
|
(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 :fills [{: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
|
|
{::mf/wrap-props false}
|
|
[props]
|
|
(let [mask (unchecked-get props "mask")
|
|
render-id (mf/use-ctx muc/render-ctx)
|
|
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))}]]]]])))
|
|
|