mirror of
https://github.com/penpot/penpot.git
synced 2026-10-30 14:30:37 +00:00
When a copy head took the place of a main shape and its component was the one of that place, it stopped being a swap, but its children kept referring to the main of its own component instead of to the children of that place. Validation did not see it, and the next sync deleted those children and added them again, losing their overrides, or the head did not follow later changes to that place. It happened in: - a variant switch that carries a swapped child into a variant whose child there has the same component; - update main of a copy that swapped a nested copy back to the component a deeper main puts in that place, after the main in between swapped it for another one; the clone in the main also kept :swap-group; - the repair of :ref-not-in-near-main, which also never cleared :swap-group. The swap in a copy, the switch, update main and the repair now share ctf/take-position: the head refers to the main shape of its position, is swapped while its component differs from that shape's, and else its descendants refer to the descendants of that shape. The switch also read the swapped child from the objects of the swap, where it was already gone with its old parent. It now reads it once it is moved into the new copy, so its placement turns its children too, and the undo takes it back to the root as the move to the root left it. The swap finds the new shapes in its own objects, not in its changes. The component memory says how a head takes a position. Benchmark (lower quantile, ms; baseline / now / ratio): deepest-edit-through-three-levels 35.2 / 37.1 / 1.05 edit-through-a-chain-of-dependents 68.9 / 70.5 / 1.02 library-update-into-copies 83.1 / 77.3 / 0.93 main-edit-into-10-copies 1.8 / 1.7 / 0.94 main-edit-into-100-copies 15.4 / 16.0 / 1.04 main-edit-into-1000-copies 153.1 / 160.6 / 1.05 variant-switch-into-copies 32.1 / 28.7 / 0.89 AI-assisted-by: claude-opus-5-5 Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>