mirror of
https://github.com/penpot/penpot.git
synced 2026-10-29 05:50:35 +00:00
🐛 Predict typography ownership across variant switches
Correct the independent switch model when only some typography styles carry into the new variant. Mixed ownership drops the reference, while fully carried styles retain it. Predict this from the two mains and prior authored groups, including when the result is corrupt. F221's regression and ownership controls failed before the correction; they pass 2 tests / 6 assertions afterward. The original program and shrink pass. Async frontend replay passes 19 assertions with undo/redo. Common/frontend lint passes; changed files were formatted. No production behavior, golden data or benchmark baseline changes. Fresh 5,000-program gates remain required. AI-assisted-by: gpt-6
This commit is contained in:
parent
b4271059df
commit
7e2f8b8781
@ -397,12 +397,24 @@
|
||||
(if-let [[main _] (source after new-paths new-main-id shape)]
|
||||
(let [path (get new-paths (:id main))
|
||||
[old old-main groups] (get old-copies path)
|
||||
old-main (or old-main (get old-by-path path))]
|
||||
old-main (or old-main (get old-by-path path))
|
||||
text-differences (when (= :text (:type main))
|
||||
(thtx/override-units (:content old-main) (:content main)))
|
||||
carried-text-units (into #{}
|
||||
(keep (fn [[group unit]]
|
||||
(when (and (contains? groups group)
|
||||
(not (contains? text-differences unit)))
|
||||
unit)))
|
||||
text-groups)
|
||||
mixed-typography? (some #(not= (contains? carried-text-units :typography)
|
||||
(contains? carried-text-units %))
|
||||
[:family :weight :size :line-height :spacing :case])]
|
||||
(reduce-kv
|
||||
(fn [result group _]
|
||||
(if-let [unit (get text-groups group)]
|
||||
(cond-> result
|
||||
(and (not (contains? (thtx/override-units (:content old-main) (:content main)) unit))
|
||||
(and (not (and (= unit :typography) mixed-typography?))
|
||||
(not (contains? text-differences unit))
|
||||
(not (same-value? main group {:content (:content old)})))
|
||||
(-> (assoc-in [(:id shape) group] {:content (:content old)})
|
||||
(assoc-in [(:id shape) :content-group] {})))
|
||||
|
||||
@ -388,6 +388,45 @@
|
||||
(t/is (= {} (get-in result [:result-text :content-group])))
|
||||
(t/is (false? (shadow/same-value? (:result-text after) :text-content-size expected)))))))
|
||||
|
||||
(t/deftest switch-shadow-keeps-a-typography-only-with-its-style-ownership
|
||||
(doseq [[new-size keep-reference?] [[14 true] [22 false]]]
|
||||
(let [content #(thtx/content [[["Same text" {:size %}]]])
|
||||
applied (thtx/content
|
||||
(thtx/apply-typography [[["Same text"]]] :heading
|
||||
{:family "Roboto" :weight 700 :italic true :size 22
|
||||
:line-height 1.6 :spacing 2 :case "uppercase"}))
|
||||
root {:type :frame :name "Board" :width 100 :height 100 :rotation 0}
|
||||
text {:type :text :name "Caption" :width 70 :height 25 :rotation 0}
|
||||
before {:old (assoc root :id :old :shapes [:old-text])
|
||||
:old-text (assoc text :id :old-text :parent-id :old :content (content 14))
|
||||
:copy (assoc root :id :copy :shape-ref :old :shapes [:copy-text])
|
||||
:copy-text (assoc text :id :copy-text :shape-ref :old-text :parent-id :copy :content applied)}
|
||||
after {:new (assoc root :id :new :shapes [:new-text])
|
||||
:new-text (assoc text :id :new-text :parent-id :new :content (content new-size))
|
||||
:copy (assoc root :id :copy :shape-ref :new :shapes [:result-text])
|
||||
;; A corrupt result must not supply the model's expected values.
|
||||
:result-text (assoc text :id :result-text :shape-ref :new-text :parent-id :copy
|
||||
:content (content 99))}
|
||||
groups #{:content-group :text-content-typography :text-content-family
|
||||
:text-content-weight :text-content-size :text-content-line-height
|
||||
:text-content-spacing :text-content-case}
|
||||
model {:copy-text (zipmap groups (repeat {:content applied}))}
|
||||
predicted (get (shadow/swap model before after :copy :old :new true) :result-text)
|
||||
expected-groups (cond-> groups
|
||||
(not keep-reference?) (disj :text-content-size :text-content-typography))]
|
||||
(t/is (= expected-groups (set (keys predicted))))
|
||||
(t/is (false? (shadow/same-value? (:result-text after) :text-content-family
|
||||
(:text-content-family predicted))))
|
||||
(when keep-reference?
|
||||
(t/is (false? (shadow/same-value? (:result-text after) :text-content-typography
|
||||
(:text-content-typography predicted))))))))
|
||||
|
||||
(t/deftest typography-ownership-stays-consistent-when-a-variant-changes-size
|
||||
(t/is (map? (cg/run {:world [2 0 {:library true :variants true :rich-variants true
|
||||
:text true :text-styles true :layout nil :layout-copies true}]
|
||||
:ops [[:text-style 4 8 1] [:switch 1 0 0 0]
|
||||
[:undo] [:undo] [:redo] [:redo]]}))))
|
||||
|
||||
(t/deftest source-library-edits-wait-for-explicit-consumer-acceptance
|
||||
(let [initial (cg/initial-state [2 1 {:library true :stale-libraries true}])
|
||||
situation (:situation initial)
|
||||
|
||||
@ -337,6 +337,12 @@
|
||||
:ops [[:swap 0 0 0 0] [:text 23 3 1 0] [:text-style 22 8 1]
|
||||
[:undo] [:undo] [:undo] [:redo] [:redo] [:redo]]})))
|
||||
|
||||
(t/deftest ^:async typography-ownership-stays-consistent-when-a-variant-changes-size
|
||||
(await (replay {:world [2 0 {:library true :variants true :rich-variants true
|
||||
:text true :text-styles true :layout nil :layout-copies true}]
|
||||
:ops [[:text-style 4 8 1] [:switch 1 0 0 0]
|
||||
[:undo] [:undo] [:redo] [:redo]]})))
|
||||
|
||||
(t/deftest ^:async detaching-after-a-nested-switch-keeps-placement-stable-through-sync
|
||||
(await (replay {:world [2 2 {:library true :variants true :rich-variants true
|
||||
:text true :text-styles true :layout :flex :layout-copies true}]
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user