diff --git a/common/src/app/common/types/text.cljc b/common/src/app/common/types/text.cljc index 6068cfc829..3b830eb9d3 100644 --- a/common/src/app/common/types/text.cljc +++ b/common/src/app/common/types/text.cljc @@ -9,6 +9,7 @@ [app.common.data :as d] [app.common.data.macros :as dm] [app.common.flags :as flags] + [app.common.math :as mth] [app.common.types.color :as clr] [app.common.types.fills :as types.fills] [clojure.set :as set] @@ -217,7 +218,10 @@ attributes or other things that may be attached). - Consider nil values, empty strings or empty lists all equal. - Normalize numeric values (legacy) into strings. - - No value is equal than the default value." + - No value is equal than the default value. + - Numeric attrs (e.g. line-height) compare with float tolerance so + editor/WASM round-trips like \"1.3333333333333333\" vs \"1.33333\" + do not count as a real style change (avoids detaching tokens)." [key value1 value2] (when (text-node-attr? key) (let [default-value (get default-text-attrs key) @@ -229,7 +233,16 @@ $))) value1' (normalize-value value1) value2' (normalize-value value2)] - (not= value1' value2')))) + (cond + (= value1' value2') + false + + :else + (let [n1 (when (string? value1') (d/parse-double value1')) + n2 (when (string? value2') (d/parse-double value2'))] + (if (and (some? n1) (some? n2)) + (not (mth/close? n1 n2)) + true)))))) (defn- compare-text-content "Given two content text structures, conformed by maps and vectors, diff --git a/common/test/common_tests/types/text_test.cljc b/common/test/common_tests/types/text_test.cljc index b63a6db6e1..98032b8bc4 100644 --- a/common/test/common_tests/types/text_test.cljc +++ b/common/test/common_tests/types/text_test.cljc @@ -78,6 +78,14 @@ (def content-changed-line-height (assoc-in content-base [:children 0 :children 0 :line-height] "1.5")) +;; Token/WASM may store full float precision; editor round-trips often +;; truncate (e.g. CSS / f32). These must compare as equal. +(def content-line-height-full-precision + (assoc-in content-base [:children 0 :children 0 :line-height] "1.3333333333333333")) + +(def content-line-height-truncated + (assoc-in content-base [:children 0 :children 0 :line-height] "1.33333")) + (def content-redundant-span-line-height (assoc-in content-base [:children 0 :children 0 :children 0 :line-height] "1.5")) @@ -208,6 +216,8 @@ ;; 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-line-height-precision (cttx/get-diff-attrs content-line-height-full-precision + content-line-height-truncated) 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) @@ -242,6 +252,7 @@ ;; 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-line-height-precision)) (t/is (= #{} attrs-span-line-height)) (t/is (= #{} attrs-roundtrip-line-height)) (t/is (= #{} attrs-nil-typography-refs))