From b096832bf5554f8be4cd64386bb04b37c61c9cc4 Mon Sep 17 00:00:00 2001 From: Alejandro Alonso Date: Wed, 24 Jun 2026 18:20:21 +0200 Subject: [PATCH] :bug: Fix v2 text editor detaching typography tokens (#10402) --- common/src/app/common/types/text.cljc | 16 ++++++++-- common/test/common_tests/types/text_test.cljc | 30 +++++++++++++++++++ .../src/app/util/text/content/from_dom.cljs | 12 ++++++-- .../src/app/util/text/content/to_dom.cljs | 5 ++-- 4 files changed, 55 insertions(+), 8 deletions(-) diff --git a/common/src/app/common/types/text.cljc b/common/src/app/common/types/text.cljc index e0330b3264..6068cfc829 100644 --- a/common/src/app/common/types/text.cljc +++ b/common/src/app/common/types/text.cljc @@ -78,6 +78,11 @@ text-transform-attrs text-fills)) +(def text-span-attrs + "Inline text span attrs. Line-height is paragraph-level in the DOM editor; + it may still be stored redundantly on span nodes." + (vec (remove #{:line-height} text-node-attrs))) + (defn text-node-attr? [attr] (d/index-of text-node-attrs attr)) @@ -317,9 +322,16 @@ "Given two content text structures, conformed by maps and vectors, compare them, and returns a set with the attributes that have changed. This is independent of the text structure, so if the structure changes - but the attributes are the same, it will return an empty set." + but the attributes are the same, it will return an empty set. + + Line-height on text nodes is ignored: it is a paragraph-level attribute + and may be stored redundantly on spans (e.g. after token apply)." [a b] - (let [diff-attrs (compare-text-content a b + (let [strip-span-line-height + #(transform-nodes is-text-node? (fn [node] (dissoc node :line-height)) %) + a (strip-span-line-height a) + b (strip-span-line-height b) + diff-attrs (compare-text-content a b {:text-cb identity :attribute-cb (fn [acc attr] (conj acc attr))})] (if-not (contains? diff-attrs :text-content-structure) diff --git a/common/test/common_tests/types/text_test.cljc b/common/test/common_tests/types/text_test.cljc index f6dea90560..b63a6db6e1 100644 --- a/common/test/common_tests/types/text_test.cljc +++ b/common/test/common_tests/types/text_test.cljc @@ -76,8 +76,31 @@ (assoc-in content-base [:children 0 :children 0 :children 0 :font-family] "Arial")) (def content-changed-line-height + (assoc-in content-base [:children 0 :children 0 :line-height] "1.5")) + +(def content-redundant-span-line-height (assoc-in content-base [:children 0 :children 0 :children 0 :line-height] "1.5")) +;; Token apply may store line-height on paragraph and spans; after a DOM +;; round-trip spans no longer carry it (paragraph-level in the editor). +(def content-token-like-line-height + (-> content-base + (assoc-in [:children 0 :children 0 :line-height] 1.4) + (assoc-in [:children 0 :children 0 :children 0 :line-height] 1.4))) + +(def content-after-editor-roundtrip + (update-in content-token-like-line-height + [:children 0 :children 0 :children 0] + dissoc :line-height)) + +;; from_dom used to merge default nil typography refs on import. +(def content-explicit-nil-typography-refs + (-> content-base + (assoc-in [:children 0 :children 0 :typography-ref-id] nil) + (assoc-in [:children 0 :children 0 :typography-ref-file] nil) + (assoc-in [:children 0 :children 0 :children 0 :typography-ref-id] nil) + (assoc-in [:children 0 :children 0 :children 0 :typography-ref-file] nil))) + (def content-changed-letter-spacing (assoc-in content-base [:children 0 :children 0 :children 0 :letter-spacing] "2")) @@ -185,6 +208,10 @@ ;; Other text-node-attr categories attrs-font-family (cttx/get-diff-attrs content-base content-changed-font-family) attrs-line-height (cttx/get-diff-attrs content-base content-changed-line-height) + attrs-span-line-height (cttx/get-diff-attrs content-base content-redundant-span-line-height) + attrs-roundtrip-line-height (cttx/get-diff-attrs content-token-like-line-height + content-after-editor-roundtrip) + attrs-nil-typography-refs (cttx/get-diff-attrs content-base content-explicit-nil-typography-refs) attrs-letter-spacing (cttx/get-diff-attrs content-base content-changed-letter-spacing) attrs-text-decoration (cttx/get-diff-attrs content-base content-changed-text-decoration) attrs-text-transform (cttx/get-diff-attrs content-base content-changed-text-transform) @@ -215,6 +242,9 @@ ;; Each text-node-attr category reports correct attr key (t/is (= #{:font-family} attrs-font-family)) (t/is (= #{:line-height} attrs-line-height)) + (t/is (= #{} attrs-span-line-height)) + (t/is (= #{} attrs-roundtrip-line-height)) + (t/is (= #{} attrs-nil-typography-refs)) (t/is (= #{:letter-spacing} attrs-letter-spacing)) (t/is (= #{:text-decoration} attrs-text-decoration)) (t/is (= #{:text-transform} attrs-text-transform)) diff --git a/frontend/src/app/util/text/content/from_dom.cljs b/frontend/src/app/util/text/content/from_dom.cljs index 4d016313b5..7b56b014c1 100644 --- a/frontend/src/app/util/text/content/from_dom.cljs +++ b/frontend/src/app/util/text/content/from_dom.cljs @@ -51,13 +51,19 @@ [_ style-decode] (get styles/mapping key)] (style-decode (.getPropertyValue style style-name))) (let [style-name (styles/get-style-name key)] - (styles/normalize-attr-value key (.getPropertyValue style style-name))))] - (assoc acc key (if (value-empty? value) (get defaults key) value)))) + (styles/normalize-attr-value key (.getPropertyValue style style-name)))) + default (get defaults key) + final-value (if (value-empty? value) default value)] + ;; Omit attrs with no CSS value when the default is nil (e.g. + ;; typography-ref-id). Avoids polluting round-tripped content. + (if (and (value-empty? value) (nil? default)) + acc + (assoc acc key final-value)))) {} attrs))) (defn get-text-span-styles [element] - (get-attrs-from-styles element txt/text-node-attrs (txt/get-default-text-attrs))) + (get-attrs-from-styles element txt/text-span-attrs (txt/get-default-text-attrs))) (defn get-paragraph-styles [element] diff --git a/frontend/src/app/util/text/content/to_dom.cljs b/frontend/src/app/util/text/content/to_dom.cljs index 373b49bdc9..cd7ab9d5aa 100644 --- a/frontend/src/app/util/text/content/to_dom.cljs +++ b/frontend/src/app/util/text/content/to_dom.cljs @@ -94,9 +94,8 @@ (defn get-text-span-styles [inline paragraph] - (let [node (if (= "" (:text inline)) paragraph inline) - styles (get-styles-from-attrs node txt/text-node-attrs txt/default-text-attrs)] - (dissoc styles :line-height))) + (let [node (if (= "" (:text inline)) paragraph inline)] + (get-styles-from-attrs node txt/text-span-attrs txt/default-text-attrs))) (defn normalize-spaces "Add zero-width spaces after forward slashes to enable word breaking"