♻️ Rename :content to :path-data for path and bool shapes

Rename the :content attribute to :path-data on path and bool shapes to
eliminate ambiguity with the text shape :content attribute. This allows
the sync-attrs system in component.cljc to map :path-data directly to
:geometry-group without type-dependent dispatch, and removes the special
case in container.cljc that checked shape type when resolving the
content sync group.

Affected namespaces:
- app.common.types.{path,shape,component,container}
- app.common.types.path.{shape-to-path,segment}
- app.common.geom.shapes.{transforms,intersect}
- app.common.files.{builder,shapes-builder}

Signed-off-by: Andrey Antukh <niwi@niwi.nz>
This commit is contained in:
Andrey Antukh 2026-03-30 10:52:30 +00:00
parent 0ad5baa5d9
commit 93f87cb1a2
10 changed files with 37 additions and 47 deletions

View File

@ -388,7 +388,7 @@
(get bool :selrect)
operations
[{:type :set :attr :content :val (:content bool) :ignore-touched true}
[{:type :set :attr :path-data :val (:path-data bool) :ignore-touched true}
{:type :set :attr :type :val :bool :ignore-touched true}
{:type :set :attr :bool-type :val type :ignore-touched true}
{:type :set :attr :selrect :val selrect :ignore-touched true}

View File

@ -356,7 +356,7 @@
{:type :path
:name name
:frame-id frame-id
:content content
:path-data content
:selrect selrect
:points points
:svg-viewbox selrect

View File

@ -175,19 +175,19 @@
"Checks if the given rect overlaps with the path in any point"
[shape rect include-content?]
(when (d/not-empty? (:content shape))
(when (d/not-empty? (:path-data shape))
(let [;; If paths are too complex the intersection is too expensive
;; we fallback to check its bounding box otherwise the performance penalty
;; is too big
;; TODO: Look for ways to optimize this operation
simple? (> (count (:content shape)) 100)
simple? (> (count (:path-data shape)) 100)
rect-points (grc/rect->points rect)
rect-lines (points->lines rect-points)
path-lines (if simple?
(points->lines (:points shape))
(path.segm/path->lines shape))
start-point (-> shape :content (first) :params (gpt/point))]
start-point (-> shape :path-data (first) :params (gpt/point))]
(or (intersects-lines? rect-lines path-lines)
(if include-content?

View File

@ -99,7 +99,7 @@
(d/update-when :y d/safe+ dy)
(d/update-when :position-data move-position-data mvec)
(cond-> (or (= :bool type) (= :path type))
(update :content path/move-content mvec)))))
(update :path-data path/move-content mvec)))))
;; --- Absolute Movement
@ -324,7 +324,7 @@
(update shape :position-data transform-position-data transform-mtx)
shape)
shape (if (or (= type :path) (= type :bool))
(update shape :content path/transform-content transform-mtx)
(update shape :path-data path/transform-content transform-mtx)
(assoc shape
:x (dm/get-prop selrect :x)
:y (dm/get-prop selrect :y)
@ -360,7 +360,7 @@
360)
shape (if (or (= type :path) (= type :bool))
(update shape :content path/transform-content transform-mtx)
(update shape :path-data path/transform-content transform-mtx)
(assoc shape
:x (dm/get-prop selrect :x)
:y (dm/get-prop selrect :y)

View File

@ -49,8 +49,8 @@
{:name :name-group
:fills :fill-group
:hide-fill-on-export :fill-group
:content {:path :geometry-group
:text :content-group}
:content :content-group
:path-data :geometry-group
:position-data :content-group
:hidden :visibility-group
:blocked :modifiable-group
@ -147,16 +147,9 @@
:interactions})
(defn resolve-sync-group
"Makes a by type resolution of the sync group. This is necessary
because we have several properties that has different group
depending on the shape type. Per example the attr `:content` is used
by path and text shapes and the sync groups are different for each
shape type."
[type attr]
(when-let [group (get sync-attrs attr)]
(if (map? group)
(get group type)
group)))
"Resolve the sync group for a given attribute."
[_type attr]
(get sync-attrs attr))
(defn component-attr?
"Check if some attribute is one that is involved in component syncrhonization.

View File

@ -587,10 +587,7 @@
(= attr :position-data))
is-geometry?
(and (or (= group :geometry-group) ;; never triggers touched by itself
(and (= group :content-group)
(= (:type shape) :path)))
;; :content in paths are also considered geometric
(and (= group :geometry-group)
(not (#{:width :height} attr)))
;; TODO: the check of :width and :height probably may be

View File

@ -132,7 +132,7 @@
(defn update-geometry
"Update shape with new geometry calculated from provided content"
([shape content]
(update-geometry (assoc shape :content content)))
(update-geometry (assoc shape :path-data content)))
([shape]
(let [flip-x
(get shape :flip-x)
@ -143,7 +143,7 @@
;; NOTE: we ensure that content is PathData instance
content
(impl/path-data
(get shape :content))
(get shape :path-data))
;; Ensure plain format once
transform
@ -181,7 +181,7 @@
(grc/points->rect))]
(-> shape
(assoc :content content)
(assoc :path-data content)
(assoc :points points)
(assoc :selrect selrect)))))
@ -214,7 +214,7 @@
(remove :hidden)
(remove cpf/svg-raw-shape?)
(map #(stp/convert-to-path % objects))
(map :content))
(map :path-data))
contents
(sequence extract-content-xf (:shapes shape))]
@ -229,7 +229,7 @@
:hint (str "unable to calculate bool content for shape " (:id shape))
:shapes (:shapes shape)
:type (:bool-type shape)
:content (vec contents)
:path-data (vec contents)
:cause cause)))))
(def wasm:calc-bool-content
@ -249,7 +249,7 @@
(let [content (if (fn? wasm:calc-bool-content)
(wasm:calc-bool-content shape objects)
(calc-bool-content shape objects))
shape (assoc shape :content content)]
shape (assoc shape :path-data content)]
(update-geometry shape)))
(defn shape-with-open-path?
@ -259,7 +259,7 @@
maybe-close (if svg? identity subpath/close-subpaths)]
(and (= :path (:type shape))
(not (->> shape
:content
:path-data
(maybe-close)
(subpath/get-subpaths)
(every? subpath/is-closed?))))))
@ -270,6 +270,6 @@
(convert-to-path shape {}))
([shape objects]
(-> (stp/convert-to-path shape objects)
(update :content impl/path-data))))
(update :path-data impl/path-data))))
(dm/export impl/decode-segments)

View File

@ -148,8 +148,8 @@
(defn path->lines
"Given a path returns a list of lines that approximate the path"
[shape]
(loop [command (first (:content shape))
pending (rest (:content shape))
(loop [command (first (:path-data shape))
pending (rest (:path-data shape))
result []
last-start nil
prev-point nil]

View File

@ -162,13 +162,13 @@
head-data (select-keys head bool/style-properties)
content (into []
(comp (filter cfh/path-shape?)
(map :content)
(map :path-data)
(map vec)
(mapcat fix-first-relative))
child-as-paths)]
(-> group
(assoc :type :path)
(assoc :content (path.impl/path-data content))
(assoc :path-data (path.impl/path-data content))
(merge head-data)
(d/without-keys dissoc-attrs))))
@ -184,12 +184,12 @@
(:bool-type shape)
content
(-> (bool/calculate-content bool-type (map :content children))
(-> (bool/calculate-content bool-type (map :path-data children))
(path.impl/path-data))]
(-> shape
(assoc :type :path)
(assoc :content content)
(assoc :path-data content)
(dissoc :bool-type)
(d/without-keys dissoc-attrs))))
@ -231,7 +231,7 @@
(-> shape
(assoc :type :path)
(assoc :content content)
(assoc :path-data content)
(cond-> (= :image type)
(assoc :fill-image (get shape :metadata)))
(d/without-keys dissoc-attrs)))

View File

@ -238,7 +238,7 @@
[:map {:title "BoolAttrs"}
[:shapes [:vector {:gen/max 10 :gen/min 1} ::sm/uuid]]
[:bool-type [::sm/one-of bool-types]]
[:content path/schema:content]])
[:path-data path/schema:content]])
(def ^:private schema:rect-attrs
[:map {:title "RectAttrs"}])
@ -263,7 +263,7 @@
(def ^:private schema:path-attrs
[:map {:title "PathAttrs"}
[:content path/schema:content]])
[:path-data path/schema:content]])
(def ^:private schema:text-attrs
[:map {:title "TextAttrs"}
@ -417,7 +417,7 @@
(def ^:private allowed-shape-geom-attrs #{:x :y :width :height})
(def ^:private allowed-shape-base-attrs #{:id :name :type :selrect :points :transform
:transform-inverse :parent-id :frame-id})
(def ^:private allowed-bool-attrs #{:shapes :bool-type :content})
(def ^:private allowed-bool-attrs #{:shapes :bool-type :path-data})
(def ^:private allowed-group-attrs #{:shapes})
(def ^:private allowed-frame-attrs #{:shapes :hide-fill-on-export :show-content :hide-in-viewer
:layout :layout-flex-dir :layout-gap-type :layout-gap
@ -427,7 +427,7 @@
:layout-grid-rows})
(def ^:private allowed-image-attrs #{:metadata})
(def ^:private allowed-svg-attrs #{:content})
(def ^:private allowed-path-attrs #{:content})
(def ^:private allowed-path-attrs #{:path-data})
(def ^:private allowed-text-attrs #{:content})
(def ^:private allowed-generic-attrs (set/union allowed-shape-attrs allowed-shape-geom-attrs allowed-shape-base-attrs))
@ -583,18 +583,18 @@
(assoc :points points))))
(defn setup-path
[{:keys [content selrect points] :as shape}]
[{:keys [path-data selrect points] :as shape}]
(let [selrect (or selrect
(path/calc-selrect content)
(path/calc-selrect path-data)
(grc/make-rect))
points (or points
(grc/rect->points selrect))
;; Ensure we hace correct type here for Path Data
content (path/content content)]
path-data (path/content path-data)]
(-> shape
(assoc :selrect selrect)
(assoc :points points)
(assoc :content content))))
(assoc :path-data path-data))))
(defn- setup-image
[{:keys [metadata] :as shape}]