♻️ Refactor shape attrs extraction helpers

This commit is contained in:
Andrey Antukh 2023-09-12 16:01:10 +02:00
parent e6f8022de0
commit 385fd9c4e6
15 changed files with 231 additions and 211 deletions

View file

@ -12,11 +12,9 @@
[app.common.geom.shapes :as gsh] [app.common.geom.shapes :as gsh]
[app.common.types.shape :refer [stroke-caps-line stroke-caps-marker]] [app.common.types.shape :refer [stroke-caps-line stroke-caps-marker]]
[app.common.types.shape.radius :as ctsr] [app.common.types.shape.radius :as ctsr]
[app.main.ui.context :as muc]
[app.util.object :as obj] [app.util.object :as obj]
[app.util.svg :as usvg] [app.util.svg :as usvg]
[cuerdas.core :as str] [cuerdas.core :as str]))
[rumext.v2 :as mf]))
(defn- stroke-type->dasharray (defn- stroke-type->dasharray
[width style] [width style]
@ -29,7 +27,8 @@
(->> values (map #(+ % width)) (str/join ",")))) (->> values (map #(+ % width)) (str/join ","))))
(defn extract-border-radius [{:keys [x y width height] :as shape}] (defn get-border-radius
[shape]
(case (ctsr/radius-mode shape) (case (ctsr/radius-mode shape)
:radius-1 :radius-1
(let [radius (gsh/shape-corners-1 shape)] (let [radius (gsh/shape-corners-1 shape)]
@ -37,6 +36,10 @@
:radius-4 :radius-4
(let [[r1 r2 r3 r4] (gsh/shape-corners-4 shape) (let [[r1 r2 r3 r4] (gsh/shape-corners-4 shape)
x (dm/get-prop shape :x)
y (dm/get-prop shape :y)
width (dm/get-prop shape :width)
height (dm/get-prop shape :height)
top (- width r1 r2) top (- width r1 r2)
right (- height r2 r3) right (- height r2 r3)
bottom (- width r3 r4) bottom (- width r3 r4)
@ -53,208 +56,198 @@
"a" r1 "," r1 " 0 0 1 " r1 "," (- r1) " " "a" r1 "," r1 " 0 0 1 " r1 "," (- r1) " "
"z")}))) "z")})))
(defn add-border-props!
[props shape]
(obj/merge! props (get-border-radius shape)))
(defn add-border-radius [attrs shape] (defn add-fill!
(obj/merge! attrs (extract-border-radius shape))) [attrs fill-data render-id index type]
(let [index (if (some? index) (dm/str "_" index) "")]
(defn add-fill
([attrs fill-data render-id type]
(add-fill attrs fill-data render-id nil type))
([attrs fill-data render-id index type]
(let [fill-attrs
(cond (cond
(contains? fill-data :fill-image) (contains? fill-data :fill-image)
(let [fill-image-id (str "fill-image-" render-id)] (let [id (dm/str "fill-image-" render-id)]
{:fill (str "url(#" fill-image-id ")")}) (obj/set! attrs "fill" (dm/str "url(#" id ")")))
(and (contains? fill-data :fill-color-gradient) (some? (:fill-color-gradient fill-data))) (some? (:fill-color-gradient fill-data))
(let [fill-color-gradient-id (str "fill-color-gradient_" render-id (if index (str "_" index) ""))] (let [id (dm/str "fill-color-gradient_" render-id index)]
{:fill (str "url(#" fill-color-gradient-id ")")}) (obj/set! attrs "fill" (dm/str "url(#" id ")")))
(contains? fill-data :fill-color) (contains? fill-data :fill-color)
{:fill (:fill-color fill-data)} (obj/set! attrs "fill" (:fill-color fill-data))
:else :else
{:fill "none"}) (obj/set! attrs "fill" "none"))
fill-attrs (cond-> fill-attrs (when (contains? fill-data :fill-opacity)
(contains? fill-data :fill-opacity) (obj/set! attrs "fillOpacity" (:fill-opacity fill-data)))
(assoc :fillOpacity (:fill-opacity fill-data))
;; Old texts with only an opacity set are black by default (when (and (= :text type)
(and (= type :text) (nil? (:fill-color-gradient fill-data)) (nil? (:fill-color fill-data))) (nil? (:fill-color-gradient fill-data))
(assoc :fill "black"))] (nil? (:fill-color fill-data)))
(obj/set! attrs "fill" "black"))
(obj/merge! attrs (clj->js fill-attrs))))) attrs))
(defn add-stroke [attrs stroke-data render-id index] (defn add-stroke!
(let [stroke-style (:stroke-style stroke-data :solid) [attrs data render-id index]
stroke-color-gradient-id (str "stroke-color-gradient_" render-id "_" index) (let [style (:stroke-style data :solid)]
stroke-width (:stroke-width stroke-data 1)] (when-not (= style :none)
(if (not= stroke-style :none) (let [width (:stroke-width data 1)
(let [stroke-attrs gradient (:stroke-color-gradient data)
(cond-> {:strokeWidth stroke-width} color (:stroke-color data)
(:stroke-color-gradient stroke-data) opacity (:stroke-opacity data)]
(assoc :stroke (str/format "url(#%s)" stroke-color-gradient-id))
(and (not (:stroke-color-gradient stroke-data)) (obj/set! attrs "strokeWidth" width)
(:stroke-color stroke-data nil))
(assoc :stroke (:stroke-color stroke-data nil))
(and (not (:stroke-color-gradient stroke-data)) (when (some? gradient)
(:stroke-opacity stroke-data nil)) (let [gradient-id (dm/str "stroke-color-gradient_" render-id "_" index)]
(assoc :strokeOpacity (:stroke-opacity stroke-data nil)) (obj/set! attrs "stroke" (str/ffmt "url(#%)" gradient-id))))
(not= stroke-style :svg) (when-not (some? gradient)
(assoc :strokeDasharray (stroke-type->dasharray stroke-width stroke-style)) (when (some? color)
(obj/set! attrs "stroke" color))
(when (some? opacity)
(obj/set! attrs "strokeOpacity" opacity)))
(when (not= style :svg)
(obj/set! attrs "strokeDasharray" (stroke-type->dasharray width style)))
;; For simple line caps we use svg stroke-line-cap attribute. This ;; For simple line caps we use svg stroke-line-cap attribute. This
;; only works if all caps are the same and we are not using the tricks ;; only works if all caps are the same and we are not using the tricks
;; for inner or outer strokes. ;; for inner or outer strokes.
(and (stroke-caps-line (:stroke-cap-start stroke-data)) (let [caps-start (:stroke-cap-start data)
(= (:stroke-cap-start stroke-data) (:stroke-cap-end stroke-data)) caps-end (:stroke-cap-end data)
(not (#{:inner :outer} (:stroke-alignment stroke-data))) alignment (:stroke-alignment data)]
(not= :dotted stroke-style)) (cond
(assoc :strokeLinecap (:stroke-cap-start stroke-data)) (and (contains? stroke-caps-line caps-start)
(= caps-start caps-end)
(not= :inner alignment)
(not= :outer alignment)
(not= :dotted style))
(obj/set! attrs "strokeLinecap" caps-start)
(= :dotted stroke-style) (= :dotted style)
(assoc :strokeLinecap "round") (obj/set! attrs "strokeLinecap" "round"))
(when (and (not= :inner alignment)
(not= :outer alignment))
;; For other cap types we use markers. ;; For other cap types we use markers.
(and (or (stroke-caps-marker (:stroke-cap-start stroke-data)) (when (or (contains? stroke-caps-marker caps-start)
(and (stroke-caps-line (:stroke-cap-start stroke-data)) (and (contains? stroke-caps-line caps-start)
(not= (:stroke-cap-start stroke-data) (:stroke-cap-end stroke-data)))) (not= caps-start caps-end)))
(not (#{:inner :outer} (:stroke-alignment stroke-data)))) (obj/set! attrs "markerStart" (str/ffmt "url(#marker-%-%)" render-id (name caps-start))))
(assoc :markerStart
(str/format "url(#marker-%s-%s)" render-id (name (:stroke-cap-start stroke-data))))
(and (or (stroke-caps-marker (:stroke-cap-end stroke-data)) (when (or (contains? stroke-caps-marker caps-end)
(and (stroke-caps-line (:stroke-cap-end stroke-data)) (and (contains? stroke-caps-line caps-end)
(not= (:stroke-cap-start stroke-data) (:stroke-cap-end stroke-data)))) (not= caps-start caps-end)))
(not (#{:inner :outer} (:stroke-alignment stroke-data)))) (obj/set! attrs "markerEnd" (str/ffmt "url(#marker-%-%)" render-id (name caps-end))))))))
(assoc :markerEnd
(str/format "url(#marker-%s-%s)" render-id (name (:stroke-cap-end stroke-data)))))]
(obj/merge! attrs (clj->js stroke-attrs))) attrs))
attrs)))
(defn add-layer-props [attrs shape] (defn add-layer-props!
(cond-> attrs [props shape]
(:opacity shape) (let [opacity (:opacity shape)]
(obj/set! "opacity" (:opacity shape)))) (if (some? opacity)
(obj/set! props "opacity" opacity)
props)))
;; FIXME: DEPRECATED (defn get-svg-props
(defn extract-svg-attrs
[render-id svg-defs svg-attrs]
(if (and (empty? svg-defs) (empty? svg-attrs))
[#js {} #js {}]
(let [replace-id (fn [id]
(if (contains? svg-defs id)
(str render-id "-" id)
id))
svg-attrs (-> svg-attrs
(usvg/clean-attrs)
(usvg/update-attr-ids replace-id)
(dissoc :id))
attrs (-> svg-attrs (dissoc :style) (clj->js))
styles (-> svg-attrs (get :style {}) (clj->js))]
[attrs styles])))
(defn get-svg-attrs
[shape render-id] [shape render-id]
(let [svg-attrs (get shape :svg-attrs {}) (let [attrs (get shape :svg-attrs {})
svg-defs (get shape :svg-defs {})] defs (get shape :svg-defs {})]
(if (and (empty? svg-defs) (if (and (empty? defs)
(empty? svg-attrs)) (empty? attrs))
{} #js {}
(let [replace-id (fn [id] (-> attrs
(if (contains? svg-defs id) ;; TODO: revisit, why we need to execute it each render? Can
(str render-id "-" id) ;; we do this operation on importation and avoid unnecesary
id))] ;; work on render?
(-> svg-attrs
(usvg/clean-attrs) (usvg/clean-attrs)
(usvg/update-attr-ids replace-id) (usvg/update-attr-ids
(dissoc :id)))))) (fn [id]
(if (contains? defs id)
(str render-id "-" id)
id)))
(dissoc :id)
(obj/map->obj)))))
(defn add-style-attrs (defn add-fill-props!
([props shape] [props shape render-id]
(let [render-id (mf/use-ctx muc/render-id)] (let [svg-attrs (get-svg-props shape render-id)
(add-style-attrs props shape render-id))) svg-style (obj/get svg-attrs "style")
([props shape render-id] shape-type (dm/get-prop shape :type)
(let [svg-defs (:svg-defs shape {})
svg-attrs (:svg-attrs shape {})
[svg-attrs svg-styles] shape-fills (get shape :fills [])
(extract-svg-attrs render-id svg-defs svg-attrs) fill-image (get shape :fill-image)
styles (-> (obj/get props "style" (obj/create)) style (-> (obj/get props "style" #js {})
(obj/merge! svg-styles) (obj/merge! svg-style)
(add-layer-props shape)) (add-layer-props! shape))]
styles (cond (or (some? (:fill-image shape)) (cond
(= :image (:type shape)) (or (some? fill-image)
(> (count (:fills shape)) 1) (= :image shape-type)
(some #(some? (:fill-color-gradient %)) (:fills shape))) (> (count shape-fills) 1)
(obj/set! styles "fill" (str "url(#fill-0-" render-id ")")) (some #(some? (:fill-color-gradient %)) shape-fills))
(obj/set! style "fill" (dm/str "url(#fill-0-" render-id ")"))
;; imported svgs can have fill and fill-opacity attributes ;; imported svgs can have fill and fill-opacity attributes
(and (some? svg-styles) (obj/contains? svg-styles "fill")) (contains? svg-style "fill")
(-> styles (-> style
(obj/set! "fill" (obj/get svg-styles "fill")) (obj/set! "fill" (obj/get svg-style "fill"))
(obj/set! "fillOpacity" (obj/get svg-styles "fillOpacity"))) (obj/set! "fillOpacity" (obj/get svg-style "fillOpacity")))
(and (some? svg-attrs) (obj/contains? svg-attrs "fill")) (obj/contains? svg-attrs "fill")
(-> styles (-> style
(obj/set! "fill" (obj/get svg-attrs "fill")) (obj/set! "fill" (obj/get svg-attrs "fill"))
(obj/set! "fillOpacity" (obj/get svg-attrs "fillOpacity"))) (obj/set! "fillOpacity" (obj/get svg-attrs "fillOpacity")))
;; If the shape comes from an imported SVG (we know because it has ;; If the shape comes from an imported SVG (we know because
;; the :svg-attrs atribute), and it does not have an own fill, we ;; it has the :svg-attrs atribute), and it does not have an
;; set a default black fill. This will be inherited by child nodes, ;; own fill, we set a default black fill. This will be
;; and is for emulating the behavior of standard SVG, in that a node ;; inherited by child nodes, and is for emulating the
;; that has no explicit fill has a default fill of black. ;; behavior of standard SVG, in that a node that has no
;; This may be reset to normal if a Penpot frame shape appears below ;; explicit fill has a default fill of black. This may be
;; reset to normal if a Penpot frame shape appears below
;; (see main.ui.shapes.frame/frame-container). ;; (see main.ui.shapes.frame/frame-container).
(and (contains? shape :svg-attrs) (and (contains? shape :svg-attrs)
(#{:svg-raw :group} (:type shape)) (or (= :svg-raw shape-type)
(empty? (:fills shape))) (= :group shape-type))
(-> styles (empty? shape-fills))
(obj/set! "fill" (or (obj/get (:wrapper-styles shape) "fill") clr/black))) (let [wstyle (get shape :wrapper-styles)
fill (obj/get wstyle "fill")
fill (d/nilv fill clr/black)]
(obj/set! style "fill" fill))
(d/not-empty? (:fills shape)) (d/not-empty? shape-fills)
(add-fill styles (d/without-nils (get-in shape [:fills 0])) render-id 0 (:type shape)) (let [fill (d/without-nils (nth shape-fills 0))]
(add-fill! style fill render-id 0 shape-type)))
:else
styles)]
(-> props (-> props
(obj/merge! svg-attrs) (obj/merge! svg-attrs)
(add-border-radius shape) (obj/set! "style" style))))
(obj/set! "style" styles)))))
(defn extract-style-attrs (defn get-style-props
([shape] [shape render-id]
(-> (obj/create) (-> #js {}
(add-style-attrs shape))) (add-fill-props! shape render-id)
([shape render-id] (add-border-props! shape)))
(-> (obj/create)
(add-style-attrs shape render-id))))
(defn get-stroke-style (defn get-stroke-style
[stroke-data index render-id] [stroke-data index render-id]
;; FIXME: optimize (add-stroke! #js {} stroke-data render-id index))
(add-stroke #js {} stroke-data render-id index))
(defn get-fill-style (defn get-fill-style
[fill-data index render-id type] [fill-data index render-id type]
;; FIXME: optimize (add-fill! #js {} fill-data render-id index type))
(add-fill #js {} fill-data render-id index type))
(defn extract-border-radius-attrs (defn extract-border-radius-attrs
[shape] [shape]
(-> (obj/create) (-> (obj/create)
(add-border-radius shape))) (add-border-props! shape)))
(defn get-border-radius-props
[shape]
(add-border-props! #js {} shape))

View file

@ -34,7 +34,7 @@
rid (mf/use-ctx muc/render-id) rid (mf/use-ctx muc/render-id)
props (mf/with-memo [shape] props (mf/with-memo [shape]
(-> (attrs/extract-style-attrs shape rid) (-> (attrs/get-style-props shape rid)
(obj/merge! #js {:cx cx :cy cy :rx rx :ry ry :transform t})))] (obj/merge! #js {:cx cx :cy cy :rx rx :ry ry :transform t})))]
[:& shape-custom-strokes {:shape shape} [:& shape-custom-strokes {:shape shape}

View file

@ -394,8 +394,8 @@
(obj/set! props "filter" (dm/fmt "url(#filter_%)" render-id)) (obj/set! props "filter" (dm/fmt "url(#filter_%)" render-id))
props)) props))
svg-attrs (attrs/get-svg-attrs shape render-id) svg-attrs (attrs/get-svg-props shape render-id)
svg-styles (get svg-attrs :style {})] svg-styles (obj/get svg-attrs "style")]
(cond (cond
^boolean url-fill? ^boolean url-fill?
@ -404,22 +404,22 @@
(obj/unset! style "fillOpacity") (obj/unset! style "fillOpacity")
(obj/set! props "fill" (dm/fmt "url(#fill-%-%)" position render-id))) (obj/set! props "fill" (dm/fmt "url(#fill-%-%)" position render-id)))
(and ^boolean (or (contains? svg-styles :fill) (and ^boolean (or (obj/contains? svg-styles "fill")
(contains? svg-styles :fillOpacity)) (obj/contains? svg-styles "fillOpacity"))
^boolean (obj/contains? svg-styles "fill")) ^boolean (obj/contains? svg-styles "fill"))
(let [fill (get svg-styles :fill) (let [fill (obj/get svg-styles "fill")
opacity (get svg-styles :fillOpacity)] opacity (obj/get svg-styles "fillOpacity")]
(when (some? fill) (when (some? fill)
(obj/set! style "fill" fill)) (obj/set! style "fill" fill))
(when (some? opacity) (when (some? opacity)
(obj/set! style "fillOpacity" opacity))) (obj/set! style "fillOpacity" opacity)))
(and ^boolean (or (contains? svg-attrs :fill) (and ^boolean (or (obj/contains? svg-attrs "fill")
(contains? svg-attrs :fillOpacity)) (obj/contains? svg-attrs "fillOpacity"))
^boolean (empty? shape-fills)) ^boolean (empty? shape-fills))
(let [fill (get svg-attrs :fill) (let [fill (obj/get svg-attrs "fill")
opacity (get svg-attrs :fillOpacity)] opacity (obj/get svg-attrs "fillOpacity")]
(when (some? fill) (when (some? fill)
(obj/set! style "fill" fill)) (obj/set! style "fill" fill))
(when (some? opacity) (when (some? opacity)

View file

@ -18,6 +18,8 @@
(def no-repeat-padding 1.05) (def no-repeat-padding 1.05)
;; FIXME: this component breaks hooks rules
(mf/defc fills (mf/defc fills
{::mf/wrap-props false} {::mf/wrap-props false}
[props] [props]

View file

@ -43,7 +43,7 @@
t (gsh/transform-str shape) t (gsh/transform-str shape)
props (mf/with-memo [shape render-id] props (mf/with-memo [shape render-id]
(-> (attrs/extract-style-attrs shape render-id) (-> (attrs/get-style-props shape render-id)
(obj/merge! #js {:x x :y y :width w :height h :transform t}))) (obj/merge! #js {:x x :y y :width w :height h :transform t})))
path? (some? (.-d props))] path? (some? (.-d props))]
@ -74,7 +74,7 @@
show-content? (get shape :show-content) show-content? (get shape :show-content)
props (mf/with-memo [shape render-id] props (mf/with-memo [shape render-id]
(-> (attrs/extract-style-attrs shape render-id) (-> (attrs/get-style-props shape render-id)
(obj/merge! (obj/merge!
#js {:x x #js {:x x
:y y :y y

View file

@ -6,6 +6,7 @@
(ns app.main.ui.shapes.image (ns app.main.ui.shapes.image
(:require (:require
[app.common.data.macros :as dm]
[app.common.geom.shapes :as gsh] [app.common.geom.shapes :as gsh]
[app.main.ui.context :as muc] [app.main.ui.context :as muc]
[app.main.ui.shapes.attrs :as attrs] [app.main.ui.shapes.attrs :as attrs]
@ -18,21 +19,24 @@
[props] [props]
(let [shape (unchecked-get props "shape") (let [shape (unchecked-get props "shape")
{:keys [x y width height]} shape
x (dm/get-prop shape :x)
y (dm/get-prop shape :y)
w (dm/get-prop shape :width)
h (dm/get-prop shape :height)
render-id (mf/use-ctx muc/render-id) render-id (mf/use-ctx muc/render-id)
transform (gsh/transform-str shape) transform (gsh/transform-str shape)
props (-> (attrs/extract-style-attrs shape render-id)
(obj/merge! (attrs/extract-border-radius-attrs shape)) props (mf/with-memo [shape render-id]
(obj/merge! (-> #js {}
#js {:x x (attrs/add-fill-props! shape render-id)
:y y (attrs/add-border-props! shape)
:transform transform (obj/merge! #js {:x x :y y :width w :height h :transform transform})))
:width width
:height height}))
path? (some? (.-d props))] path? (some? (.-d props))]
[:& shape-custom-strokes {:shape shape} [:& shape-custom-strokes {:shape shape}
(if path? (if ^boolean path?
[:> :path props] [:> :path props]
[:> :rect props])])) [:> :rect props])]))

View file

@ -30,7 +30,7 @@
""))) "")))
render-id (mf/use-ctx muc/render-id) render-id (mf/use-ctx muc/render-id)
props (-> (attrs/extract-style-attrs shape render-id) props (-> (attrs/get-style-props shape render-id)
(obj/set! "d" pdata))] (obj/set! "d" pdata))]
[:& shape-custom-strokes {:shape shape} [:& shape-custom-strokes {:shape shape}

View file

@ -28,7 +28,7 @@
rid (mf/use-ctx muc/render-id) rid (mf/use-ctx muc/render-id)
props (mf/with-memo [shape rid] props (mf/with-memo [shape rid]
(-> (attrs/extract-style-attrs shape rid) (-> (attrs/get-style-props shape rid)
(obj/merge! #js {:x x :y y :transform t :width w :height h}))) (obj/merge! #js {:x x :y y :transform t :width w :height h})))
path? (some? (.-d props))] path? (some? (.-d props))]

View file

@ -21,6 +21,8 @@
[app.util.object :as obj] [app.util.object :as obj]
[rumext.v2 :as mf])) [rumext.v2 :as mf]))
;; FIXME: revisit this: breaks all memoization because of this new
;; property added to shapes
(defn propagate-wrapper-styles-child (defn propagate-wrapper-styles-child
[child wrapper-props] [child wrapper-props]
(let [child-props-childs (let [child-props-childs
@ -93,7 +95,8 @@
wrapper-props wrapper-props
(cond-> wrapper-props (cond-> wrapper-props
(= :group type) (= :group type)
(attrs/add-style-attrs shape render-id) (-> (attrs/add-fill-props! shape render-id)
(attrs/add-border-props! shape))
(some? filter-str) (some? filter-str)
(obj/set! "filter" filter-str)) (obj/set! "filter" filter-str))

View file

@ -22,8 +22,8 @@
(def svg-ids-ctx (mf/create-context nil)) (def svg-ids-ctx (mf/create-context nil))
(defn set-styles [attrs shape render-id] (defn set-styles [attrs shape render-id]
(let [custom-attrs (-> (usa/extract-style-attrs shape render-id) (let [custom-attrs (-> (usa/get-style-props shape render-id)
(obj/without ["transform"])) (obj/unset! "transform"))
attrs (or attrs {}) attrs (or attrs {})
attrs (cond-> attrs attrs (cond-> attrs

View file

@ -192,7 +192,7 @@
:transform transform :transform transform
:width (if (#{:auto-width} grow-type) 100000 width) :width (if (#{:auto-width} grow-type) 100000 width)
:height (if (#{:auto-height :auto-width} grow-type) 100000 height) :height (if (#{:auto-height :auto-width} grow-type) 100000 height)
:style (-> (obj/create) (attrs/add-layer-props shape)) :style (attrs/add-layer-props! #js {} shape)
:ref ref} :ref ref}
;; We use a class here because react has a bug that won't use the appropriate selector for ;; We use a class here because react has a bug that won't use the appropriate selector for
;; `background-clip` ;; `background-clip`

View file

@ -50,7 +50,8 @@
:y y :y y
:width width :width width
:height height} :height height}
(attrs/add-style-attrs shape render-id)) (attrs/add-fill-props! shape render-id)
(attrs/add-border-props! shape))
get-gradient-id get-gradient-id
(fn [index] (fn [index]
(str render-id "_" (:id shape) "_" index))] (str render-id "_" (:id shape) "_" index))]

View file

@ -99,8 +99,8 @@
rawsvg? (= :svg-raw shape-type) rawsvg? (= :svg-raw shape-type)
wrapper-elem (if ^boolean rawsvg? mf/Fragment "g") wrapper-elem (if ^boolean rawsvg? mf/Fragment "g")
wrapper-props (if ^boolean rawsvg? wrapper-props (if ^boolean rawsvg?
#js {:className "workspace-shape-wrapper"} #js {}
#js {})] #js {:className "workspace-shape-wrapper"})]
(when (and (some? shape) (when (and (some? shape)
(not ^boolean (:hidden shape))) (not ^boolean (:hidden shape)))

View file

@ -51,7 +51,7 @@
(d/nilv (ex/ignoring (upf/format-path content)) ""))) (d/nilv (ex/ignoring (upf/format-path content)) "")))
border-attrs border-attrs
(attrs/extract-border-radius shape) (attrs/get-border-radius shape)
outline-type outline-type
(case type (case type

View file

@ -19,7 +19,7 @@
(defn get (defn get
([obj k] ([obj k]
(when-not (nil? obj) (when (some? obj)
(unchecked-get obj k))) (unchecked-get obj k)))
([obj k default] ([obj k default]
(let [result (get obj k)] (let [result (get obj k)]
@ -27,7 +27,8 @@
(defn contains? (defn contains?
[obj k] [obj k]
(some? (unchecked-get obj k))) (when (some? obj)
(js/Object.hasOwn obj k)))
(defn get-keys (defn get-keys
[obj] [obj]
@ -105,11 +106,27 @@
(js* "~{} in ~{}" prop obj)) (js* "~{} in ~{}" prop obj))
(defn map->obj (defn map->obj
[o] [x]
(reduce-kv (fn [result k v] (cond
(let [k (if (keyword? k) (name k) k) (nil? x)
v (if (keyword? v) (name v) v)] nil
(unchecked-set result k v)
result)) (keyword? x)
(name x)
(map? x)
(reduce-kv (fn [m k v]
(let [k (if (keyword? k) (name k) k)]
(unchecked-set m k (^function map->obj v))
m))
#js {} #js {}
o)) x)
(coll? x)
(reduce (fn [arr v]
(.push arr v)
arr)
(array)
x)
:else x))