diff --git a/frontend/src/app/main/ui/shapes/attrs.cljs b/frontend/src/app/main/ui/shapes/attrs.cljs index 83f1debbe..a70dd66b9 100644 --- a/frontend/src/app/main/ui/shapes/attrs.cljs +++ b/frontend/src/app/main/ui/shapes/attrs.cljs @@ -141,23 +141,28 @@ styles (-> svg-attrs (:style {}) (clj->js))] [attrs styles])) +(defn add-style-attrs + [props shape] + (let [render-id (mf/use-ctx muc/render-ctx) + svg-defs (:svg-defs shape {}) + svg-attrs (:svg-attrs shape {}) + + [svg-attrs svg-styles] (mf/use-memo + (mf/deps render-id svg-defs svg-attrs) + #(extract-svg-attrs render-id svg-defs svg-attrs)) + + styles (-> (obj/get props "style" (obj/new)) + (obj/merge! svg-styles) + (add-fill shape render-id) + (add-stroke shape render-id) + (add-layer-props shape))] + + (-> props + (obj/merge! svg-attrs) + (add-border-radius shape) + (obj/set! "style" styles)))) + (defn extract-style-attrs - ([shape] - (let [render-id (mf/use-ctx muc/render-ctx) - svg-defs (:svg-defs shape {}) - svg-attrs (:svg-attrs shape {}) - - [svg-attrs svg-styles] (mf/use-memo - (mf/deps render-id svg-defs svg-attrs) - #(extract-svg-attrs render-id svg-defs svg-attrs)) - - styles (-> (obj/new) - (obj/merge! svg-styles) - (add-fill shape render-id) - (add-stroke shape render-id) - (add-layer-props shape))] - - (-> (obj/new) - (obj/merge! svg-attrs) - (add-border-radius shape) - (obj/set! "style" styles))))) + [shape] + (-> (obj/new) + (add-style-attrs shape))) diff --git a/frontend/src/app/main/ui/shapes/group.cljs b/frontend/src/app/main/ui/shapes/group.cljs index fd7d8552f..9dc4ea0e9 100644 --- a/frontend/src/app/main/ui/shapes/group.cljs +++ b/frontend/src/app/main/ui/shapes/group.cljs @@ -20,33 +20,29 @@ (let [frame (unchecked-get props "frame") shape (unchecked-get props "shape") childs (unchecked-get props "childs") - expand-mask (unchecked-get props "expand-mask") pointer-events (unchecked-get props "pointer-events") - {:keys [id x y width height]} shape + {:keys [id x y width height masked-group?]} shape - show-mask? (and (:masked-group? shape) (not expand-mask)) - mask (when show-mask? (first childs)) - childs (if show-mask? (rest childs) childs) + [mask childs] (if masked-group? + [(first childs) (rest childs)] + [nil childs]) - mask-props (when (and mask (not expand-mask)) - #js {:clipPath (clip-str mask) - :mask (mask-str mask)}) - mask-wrapper (if (and mask (not expand-mask)) - "g" - mf/Fragment) + [mask-wrapper mask-props] + (if masked-group? + ["g" (-> (obj/new) + (obj/set! "clipPath" (clip-str mask)) + (obj/set! "mask" (mask-str mask)))] + [mf/Fragment nil])] - props (-> (attrs/extract-style-attrs shape))] + [:> mask-wrapper mask-props + (when masked-group? + [:> render-mask #js {:frame frame :mask mask}]) - [:> :g (attrs/extract-style-attrs shape) - [:> mask-wrapper mask-props - (when mask - [:> render-mask #js {:frame frame :mask mask}]) - - (for [item childs] - [:& shape-wrapper {:frame frame - :shape item - :key (:id item)}])]])))) + (for [item childs] + [:& shape-wrapper {:frame frame + :shape item + :key (:id item)}])])))) diff --git a/frontend/src/app/main/ui/shapes/shape.cljs b/frontend/src/app/main/ui/shapes/shape.cljs index 4d3f4fc68..0b8d29477 100644 --- a/frontend/src/app/main/ui/shapes/shape.cljs +++ b/frontend/src/app/main/ui/shapes/shape.cljs @@ -9,11 +9,12 @@ [app.common.data :as d] [app.common.uuid :as uuid] [app.main.ui.context :as muc] + [app.main.ui.shapes.attrs :as attrs] [app.main.ui.shapes.custom-stroke :as cs] + [app.main.ui.shapes.export :as ed] [app.main.ui.shapes.fill-image :as fim] [app.main.ui.shapes.filters :as filters] [app.main.ui.shapes.gradients :as grad] - [app.main.ui.shapes.export :as ed] [app.main.ui.shapes.svg-defs :as defs] [app.util.object :as obj] [rumext.alpha :as mf])) @@ -35,6 +36,7 @@ {:keys [x y width height type]} shape frame? (= :frame type) + group? (= :group type) wrapper-props (-> (obj/clone props) @@ -42,16 +44,23 @@ (obj/set! "ref" ref) (obj/set! "id" (str "shape-" (:id shape))) (obj/set! "filter" (filters/filter-str filter-id shape)) - (obj/set! "style" styles) + (obj/set! "style" styles)) - (cond-> frame? - (-> (obj/set! "x" x) - (obj/set! "y" y) - (obj/set! "width" width) - (obj/set! "height" height) - (obj/set! "xmlnsXlink" "http://www.w3.org/1999/xlink") - (obj/set! "xmlns" "http://www.w3.org/2000/svg") - (obj/set! "xmlns:penpot" "https://penpot.app/xmlns")))) + wrapper-props + (cond-> wrapper-props + frame? + (-> (obj/set! "x" x) + (obj/set! "y" y) + (obj/set! "width" width) + (obj/set! "height" height) + (obj/set! "xmlnsXlink" "http://www.w3.org/1999/xlink") + (obj/set! "xmlns" "http://www.w3.org/2000/svg") + (obj/set! "xmlns:penpot" "https://penpot.app/xmlns"))) + + wrapper-props + (cond-> wrapper-props + group? + (attrs/add-style-attrs shape)) wrapper-tag (if frame? "svg" "g")] diff --git a/frontend/src/app/main/ui/workspace/shapes.cljs b/frontend/src/app/main/ui/workspace/shapes.cljs index 48b6f00e8..b62038189 100644 --- a/frontend/src/app/main/ui/workspace/shapes.cljs +++ b/frontend/src/app/main/ui/workspace/shapes.cljs @@ -83,20 +83,19 @@ (when (and shape (not (:hidden shape))) [:* (if-not svg-element? - [:g.shape-wrapper - (case (:type shape) - :path [:> path/path-wrapper opts] - :text [:> text/text-wrapper opts] - :group [:> group-wrapper opts] - :rect [:> rect-wrapper opts] - :image [:> image-wrapper opts] - :circle [:> circle-wrapper opts] - :svg-raw [:> svg-raw-wrapper opts] + (case (:type shape) + :path [:> path/path-wrapper opts] + :text [:> text/text-wrapper opts] + :group [:> group-wrapper opts] + :rect [:> rect-wrapper opts] + :image [:> image-wrapper opts] + :circle [:> circle-wrapper opts] + :svg-raw [:> svg-raw-wrapper opts] - ;; Only used when drawing a new frame. - :frame [:> frame-wrapper {:shape shape}] + ;; Only used when drawing a new frame. + :frame [:> frame-wrapper {:shape shape}] - nil)] + nil) ;; Don't wrap svg elements inside a otherwise some can break [:> svg-raw-wrapper opts]) diff --git a/frontend/src/app/main/ui/workspace/shapes/group.cljs b/frontend/src/app/main/ui/workspace/shapes/group.cljs index db7ece44a..8e7f22fb4 100644 --- a/frontend/src/app/main/ui/workspace/shapes/group.cljs +++ b/frontend/src/app/main/ui/workspace/shapes/group.cljs @@ -42,9 +42,8 @@ childs (mf/deref childs-ref)] [:> shape-container {:shape shape} - [:g.group-shape - [:& group-shape - {:frame frame - :shape shape - :childs childs}]]])))) + [:& group-shape + {:frame frame + :shape shape + :childs childs}]])))) diff --git a/frontend/src/app/util/import/parser.cljc b/frontend/src/app/util/import/parser.cljc index 8fd551a6d..fed82c64b 100644 --- a/frontend/src/app/util/import/parser.cljc +++ b/frontend/src/app/util/import/parser.cljc @@ -96,14 +96,15 @@ (defn get-svg-data [type node] - (if (search-data-node? type) - (let [data-tags #{:ellipse :rect :path :text :foreignObject :image}] - (->> node - (node-seq) - (filter #(contains? data-tags (:tag %))) - (map #(:attrs %)) - (reduce add-attrs {}))) - (:attrs node))) + (let [node-attrs (add-attrs {} (:attrs node))] + (if (search-data-node? type) + (let [data-tags #{:ellipse :rect :path :text :foreignObject :image}] + (->> node + (node-seq) + (filter #(contains? data-tags (:tag %))) + (map #(:attrs %)) + (reduce add-attrs node-attrs))) + node-attrs))) (def has-position? #{:frame :rect :image :text}) @@ -188,7 +189,7 @@ (parse-path svg-data))) (defn add-fill - [props type node svg-data] + [props node svg-data] (let [fill (:fill svg-data)] (cond-> props @@ -206,7 +207,7 @@ :fill-opacity (-> svg-data (:fill-opacity "1") d/parse-double))))) (defn add-stroke - [props type node svg-data] + [props node svg-data] (let [stroke-style (get-meta node :stroke-style keyword) stroke-alignment (get-meta node :stroke-alignment keyword) @@ -303,6 +304,18 @@ (not (empty? exports)) (assoc :exports exports)))) +(defn add-layer-options + [props svg-data] + (let [blend-mode (get svg-data :mix-blend-mode) + opacity (-> (get svg-data :opacity) d/parse-double)] + + (cond-> props + (some? blend-mode) + (assoc :blend-mode (keyword blend-mode)) + + (some? opacity) + (assoc :opacity opacity)))) + (defn get-image-name [node] (get-in node [:attrs :penpot:name])) @@ -325,8 +338,9 @@ (-> {} (add-position type node svg-data) - (add-fill type node svg-data) - (add-stroke type node svg-data) + (add-fill node svg-data) + (add-stroke node svg-data) + (add-layer-options svg-data) (add-shadows node) (add-blur node) (add-exports node)