🐛 Compare text numeric attrs with float tolerance (#11366)

Editor/WASM round-trips can truncate line-height strings
(e.g. 1.3333333333333333 → 1.33333). Exact string compare
treated that as a style change and detached typography tokens.
This commit is contained in:
Alejandro Alonso 2026-08-27 09:41:50 +02:00 committed by GitHub
parent 88a52d1098
commit f7bdc9786c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 26 additions and 2 deletions

View File

@ -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,

View File

@ -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))