diff --git a/common/app/common/pages.cljc b/common/app/common/pages.cljc index b0f311af3..4ef70baba 100644 --- a/common/app/common/pages.cljc +++ b/common/app/common/pages.cljc @@ -64,6 +64,7 @@ (d/export helpers/merge-path-item) (d/export helpers/compact-path) (d/export helpers/compact-name) +(d/export helpers/merge-modifiers) ;; Indices (d/export indices/calculate-z-index) diff --git a/common/app/common/pages/helpers.cljc b/common/app/common/pages/helpers.cljc index 6bc748419..1fce3111b 100644 --- a/common/app/common/pages/helpers.cljc +++ b/common/app/common/pages/helpers.cljc @@ -457,3 +457,12 @@ [path name] (let [path-split (split-path path)] (merge-path-item (first path-split) name))) + +(defn merge-modifiers + [objects modifiers] + + (let [set-modifier (fn [objects [id modifiers]] + (-> objects + (d/update-when id assoc :modifiers modifiers)))] + (->> modifiers + (reduce set-modifier objects)))) diff --git a/frontend/src/app/main/refs.cljs b/frontend/src/app/main/refs.cljs index 3a50f2a46..db33ad5aa 100644 --- a/frontend/src/app/main/refs.cljs +++ b/frontend/src/app/main/refs.cljs @@ -242,7 +242,7 @@ modifiers (:workspace-modifiers state) objects (cond-> objects with-modifiers? - (d/deep-merge modifiers)) + (cp/merge-modifiers modifiers)) xform (comp (map #(get objects %)) (remove nil?))] (into [] xform ids))) diff --git a/frontend/src/app/main/ui/shapes/image.cljs b/frontend/src/app/main/ui/shapes/image.cljs index 4ad49835b..4dd1e3e41 100644 --- a/frontend/src/app/main/ui/shapes/image.cljs +++ b/frontend/src/app/main/ui/shapes/image.cljs @@ -51,12 +51,7 @@ ;; Prevent browser dragging of the image (dom/prevent-default event))] - (if (nil? @data-uri) - [:> "rect" (obj/merge! - props - #js {:fill "#E8E9EA" - :stroke "#000000"})] - [:> "image" (obj/merge! - props - #js {:xlinkHref @data-uri - :onDragStart on-drag-start})])))) + [:> "image" (obj/merge! + props + #js {:xlinkHref (or @data-uri uri) + :onDragStart on-drag-start})]))) diff --git a/frontend/src/app/main/ui/shapes/shape.cljs b/frontend/src/app/main/ui/shapes/shape.cljs index 88df3cff8..793c168fb 100644 --- a/frontend/src/app/main/ui/shapes/shape.cljs +++ b/frontend/src/app/main/ui/shapes/shape.cljs @@ -16,8 +16,9 @@ [rumext.alpha :as mf])) (mf/defc shape-container - {::mf/wrap-props false} - [props] + {::mf/forward-ref true + ::mf/wrap-props false} + [props ref] (let [shape (obj/get props "shape") children (obj/get props "children") pointer-events (obj/get props "pointer-events") @@ -33,6 +34,7 @@ frame? (= :frame type) group-props (-> (obj/clone props) (obj/without ["shape" "children"]) + (obj/set! "ref" ref) (obj/set! "id" (str "shape-" (:id shape))) (obj/set! "filter" (filters/filter-str filter-id shape)) (obj/set! "style" styles) diff --git a/frontend/src/app/main/ui/shapes/text.cljs b/frontend/src/app/main/ui/shapes/text.cljs index f26386dae..48a516240 100644 --- a/frontend/src/app/main/ui/shapes/text.cljs +++ b/frontend/src/app/main/ui/shapes/text.cljs @@ -22,7 +22,7 @@ (let [node (obj/get props "node") text (:text node) style (sts/generate-text-styles node)] - [:span {:style style} + [:span.text-node {:style style} (if (= text "") "\u00A0" text)])) (mf/defc render-root @@ -102,6 +102,10 @@ :height (if (#{:auto-height :auto-width} grow-type) 100000 height) :style (-> (obj/new) (attrs/add-layer-props shape)) :ref ref} + ;; We use a class here because react has a bug that won't use the appropiate selector for + ;; `background-clip` + [:style ".text-node { background-clip: text; + -webkit-background-clip: text;" ] [:& render-node {:index 0 :shape shape :node content}]])) diff --git a/frontend/src/app/main/ui/shapes/text/styles.cljs b/frontend/src/app/main/ui/shapes/text/styles.cljs index 21825299e..83404cc7c 100644 --- a/frontend/src/app/main/ui/shapes/text/styles.cljs +++ b/frontend/src/app/main/ui/shapes/text/styles.cljs @@ -89,10 +89,10 @@ (let [text-color (-> (update gradient :type keyword) (uc/gradient->css))] (-> base - (obj/set! "background" "var(--text-color)") + (obj/set! "--text-color" text-color) + (obj/set! "backgroundImage" "var(--text-color)") (obj/set! "WebkitTextFillColor" "transparent") - (obj/set! "WebkitBackgroundClip" "text") - (obj/set! "--text-color" text-color)))) + (obj/set! "WebkitBackgroundClip" "text")))) (when (and (string? letter-spacing) (pos? (alength letter-spacing))) diff --git a/frontend/src/app/main/ui/workspace/shapes/frame.cljs b/frontend/src/app/main/ui/workspace/shapes/frame.cljs index 8e8dd3186..8875ba6e5 100644 --- a/frontend/src/app/main/ui/workspace/shapes/frame.cljs +++ b/frontend/src/app/main/ui/workspace/shapes/frame.cljs @@ -68,14 +68,16 @@ [props] (let [shape (obj/get props "shape")] (when (:thumbnail shape) - [:image {:xlinkHref (:thumbnail shape) - :x (:x shape) - :y (:y shape) - :width (:width shape) - :height (:height shape) - ;; DEBUG - ;; :style {:filter "sepia(1)"} - }]))) + [:image.frame-thumbnail + {:id (str "thumbnail-" (:id shape)) + :xlinkHref (:thumbnail shape) + :x (:x shape) + :y (:y shape) + :width (:width shape) + :height (:height shape) + ;; DEBUG + ;; :style {:filter "sepia(1)"} + }]))) ;; This custom deffered don't deffer rendering when ghost rendering is ;; used. @@ -114,19 +116,30 @@ (filterv #(and (= :text (:type %)) (= (:id shape) (:frame-id %))))) - ds-modifier (get-in shape [:modifiers :displacement])] + ds-modifier (get-in shape [:modifiers :displacement]) + + rendered? (mf/use-state false) + + show-thumbnail? (and thumbnail? (some? (:thumbnail shape))) + + on-dom + (mf/use-callback + (fn [node] + (ts/schedule-on-idle #(reset! rendered? (some? node)))))] (when (and shape (not (:hidden shape))) [:g.frame-wrapper {:display (when (:hidden shape) "none")} - (if (and thumbnail? (some? (:thumbnail shape))) - [:& thumbnail {:shape shape}] - - [:> shape-container {:shape shape } + (when-not show-thumbnail? + [:> shape-container {:shape shape + :ref on-dom} (when embed-fonts? [:& ste/embed-fontfaces-style {:shapes text-childs}]) [:& frame-shape {:shape shape - :childs children}]])]))))) + :childs children}]]) + + (when (or (not @rendered?) show-thumbnail?) + [:& thumbnail {:shape shape}])]))))) diff --git a/frontend/src/app/main/ui/workspace/viewport/utils.cljs b/frontend/src/app/main/ui/workspace/viewport/utils.cljs index e3df76657..a1e6f6a83 100644 --- a/frontend/src/app/main/ui/workspace/viewport/utils.cljs +++ b/frontend/src/app/main/ui/workspace/viewport/utils.cljs @@ -15,8 +15,19 @@ (defn update-transform [node shapes modifiers] (doseq [{:keys [id type]} shapes] - (when-let [node (dom/get-element (str "shape-" id))] - (let [node (if (= :frame type) (.-parentNode node) node)] + (let [shape-node (dom/get-element (str "shape-" id)) + + ;; When the shape is a frame we maybe need to move its thumbnail + thumb-node (dom/get-element (str "thumbnail-" id))] + (when-let [node (cond + (and (some? shape-node) (= :frame type)) + (.-parentNode shape-node) + + (and (some? thumb-node) (= :frame type)) + thumb-node + + :else + shape-node)] (dom/set-attribute node "transform" (str (:displacement modifiers))))))) (defn remove-transform [node shapes] diff --git a/frontend/src/app/util/range_tree.js b/frontend/src/app/util/range_tree.js index 3f823a9f2..0b7532b8a 100644 --- a/frontend/src/app/util/range_tree.js +++ b/frontend/src/app/util/range_tree.js @@ -287,7 +287,7 @@ goog.scope(function() { function moveRedLeft(branch) { flipColors(branch); - if (isRed(branch.right.left)) { + if (branch.right && isRed(branch.right.left)) { branch.right = rotateRight(branch.right); branch = rotateLeft(branch); flipColors(branch);