diff --git a/common/app/common/pages/changes.cljc b/common/app/common/pages/changes.cljc index c327e0286..1b963a69e 100644 --- a/common/app/common/pages/changes.cljc +++ b/common/app/common/pages/changes.cljc @@ -106,7 +106,7 @@ objects (dissoc objects id)] (cond-> objects (and (not= parent-id frame-id) - (= :group (:type parent))) + (#{:group :svg-raw} (:type parent))) (update-in [parent-id :shapes] (fn [s] (filterv #(not= % id) s))) (and (:shape-ref parent) (not ignore-touched)) diff --git a/frontend/src/app/main/data/workspace.cljs b/frontend/src/app/main/data/workspace.cljs index 39ad120c7..313bffaa7 100644 --- a/frontend/src/app/main/data/workspace.cljs +++ b/frontend/src/app/main/data/workspace.cljs @@ -401,16 +401,19 @@ (update [_ state] (update state :workspace-local (fn [{:keys [vbox vport left-sidebar? zoom] :as local}] - (let [wprop (/ (:width vport) width) - hprop (/ (:height vport) height) - left-offset (if left-sidebar? 0 (/ (* -1 15 16) zoom))] - (-> local ;; This matches $width-settings-bar - (assoc :vport size) ;; in frontend/resources/styles/main/partials/sidebar.scss - (update :vbox (fn [vbox] - (-> vbox - (update :width #(/ % wprop)) - (update :height #(/ % hprop)) - (assoc :left-offset left-offset))))))))))) + (if (or (mth/almost-zero? width) (mth/almost-zero? height)) + ;; If we have a resize to zero just keep the old value + local + (let [wprop (/ (:width vport) width) + hprop (/ (:height vport) height) + left-offset (if left-sidebar? 0 (/ (* -1 15 16) zoom))] + (-> local ;; This matches $width-settings-bar + (assoc :vport size) ;; in frontend/resources/styles/main/partials/sidebar.scss + (update :vbox (fn [vbox] + (-> vbox + (update :width #(/ % wprop)) + (update :height #(/ % hprop)) + (assoc :left-offset left-offset)))))))))))) (defn start-pan [state] diff --git a/frontend/src/app/main/ui/shapes/svg_raw.cljs b/frontend/src/app/main/ui/shapes/svg_raw.cljs index c79d848ed..ff1552861 100644 --- a/frontend/src/app/main/ui/shapes/svg_raw.cljs +++ b/frontend/src/app/main/ui/shapes/svg_raw.cljs @@ -13,11 +13,16 @@ [app.common.geom.point :as gpt] [app.common.geom.shapes :as gsh] [app.main.ui.shapes.attrs :as usa] - [app.util.data :as d] + [app.util.data :as ud] + [app.common.data :as cd] + [app.common.uuid :as uuid] [app.util.object :as obj] [cuerdas.core :as str] [rumext.alpha :as mf])) +;; Context to store a re-mapping of the ids +(def svg-ids-ctx (mf/create-context nil)) + (defn clean-attrs "Transforms attributes to their react equivalent" [attrs] @@ -51,7 +56,7 @@ "Converts the viewBox into a rectangle" [vbox] (when vbox - (let [[x y width height] (map d/parse-float (str/split vbox " "))] + (let [[x y width height] (map ud/parse-float (str/split vbox " "))] {:x x :y y :width width :height height}))) (defn vbox-center [shape] @@ -74,50 +79,81 @@ {:keys [x y width height]} (gsh/center->rect center (:width bounds) (:height bounds))] (str x " " y " " width " " height))) +(defn generate-id-mapping [content] + (letfn [(visit-node [result node] + (let [element-id (get-in node [:attrs :id]) + result (cond-> result + element-id (assoc element-id (str (uuid/next))))] + (reduce visit-node result (:content node))))] + (visit-node {} content))) + (defn svg-raw-shape [shape-wrapper] (mf/fnc svg-raw-shape - {::mf/wrap-props false} - [props] - (let [frame (unchecked-get props "frame") - shape (unchecked-get props "shape") - childs (unchecked-get props "childs") + {::mf/wrap-props false} + [props] + (let [frame (unchecked-get props "frame") + shape (unchecked-get props "shape") + childs (unchecked-get props "childs") - {:keys [tag attrs] :as content} (:content shape) + {:keys [tag attrs] :as content} (:content shape) - attrs (obj/merge! (clj->js (clean-attrs attrs)) - (usa/extract-style-attrs shape))] + new-mapping (mf/use-memo #(when (= tag :svg) (generate-id-mapping content))) + ids-mapping (if (= tag :svg) + new-mapping + (mf/use-ctx svg-ids-ctx)) - (cond - ;; Root SVG TAG - (and (map? content) (= tag :svg)) - (let [;; {:keys [x y width height]} (-> (:points shape) gsh/points->selrect) - {:keys [x y width height]} shape - attrs (-> attrs - (obj/set! "x" x) - (obj/set! "y" y) - (obj/set! "width" width) - (obj/set! "height" height) - (obj/set! "preserveAspectRatio" "none") - #_(obj/set! "viewBox" (transform-viewbox shape)))] + rex #"[^#]*#([^)\s]+).*" - [:g.svg-raw {:transform (gsh/transform-matrix shape)} - [:> "svg" attrs - (for [item childs] - [:& shape-wrapper {:frame frame - :shape item - :key (:id item)}])]]) + ;; Replaces the attributes ID's so there are no collisions between shapes + replace-ids + (fn [key val] + (let [[_ from-id] (re-matches rex val)] + (if (and from-id (contains? ids-mapping from-id)) + (str/replace val from-id (get ids-mapping from-id)) + val))) - ;; Other tags different than root - (map? content) - [:> (name tag) attrs - (for [item childs] - [:& shape-wrapper {:frame frame - :shape item - :key (:id item)}])] + attrs (->> attrs + (cd/mapm replace-ids) + (clean-attrs)) - ;; String content - (string? content) content + attrs (obj/merge! (clj->js attrs) + (usa/extract-style-attrs shape)) - :else nil)))) + element-id (get-in content [:attrs :id])] + + (cond + ;; Root SVG TAG + (and (map? content) (= tag :svg)) + (let [{:keys [x y width height]} shape + attrs (-> attrs + (obj/set! "x" x) + (obj/set! "y" y) + (obj/set! "width" width) + (obj/set! "height" height) + (obj/set! "preserveAspectRatio" "none") + #_(obj/set! "viewBox" (transform-viewbox shape)))] + + [:& (mf/provider svg-ids-ctx) {:value ids-mapping} + [:g.svg-raw {:transform (gsh/transform-matrix shape)} + [:> "svg" attrs + (for [item childs] + [:& shape-wrapper {:frame frame + :shape item + :key (:id item)}])]]]) + + ;; Other tags different than root + (map? content) + (let [attrs (cond-> attrs + element-id (obj/set! "id" (get ids-mapping element-id)))] + [:> (name tag) attrs + (for [item childs] + [:& shape-wrapper {:frame frame + :shape item + :key (:id item)}])]) + + ;; String content + (string? content) content + + :else nil)))) diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/svg_raw.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/svg_raw.cljs index b570a3707..3522b4f71 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/svg_raw.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/svg_raw.cljs @@ -41,6 +41,10 @@ ;; TODO CHECK IF IT'S A GRADIENT + (str/starts-with? color "url") + {:color :multiple + :opacity :multiple} + :else nil))