Commit c896bbd
Ronald A Richardson
fix: stable element object identity prevents interact.js destruction on addElement; add canvas boundary clamping
Root cause of persistent drag/resize breakage
----------------------------------------------
The previous implementation stored the entire template (including content
array) in a single @Tracked _template object. Every mutation went through
_updateTemplate(), which did:
JSON.parse(JSON.stringify(merged))
This deep-clone creates brand-new JS object references for EVERY element in
the content array, even elements that were not changed. Glimmer's {{#each}}
loop compares item references to decide whether to reuse or recreate a
component. Because every object was a new reference after every operation
(addElement, updateElement, deleteElement, reorderElement), Glimmer destroyed
and recreated EVERY ElementRenderer component on every single mutation. This
fired will-destroy (teardownElement -> interactable.unset()) followed by
did-insert (setupElement -> new interactable) for all elements — not just the
one that changed.
Fix: split state into @Tracked _meta (non-content template fields) and
@Tracked _content (element array). The invariant is that existing element
objects keep their JS identity across renders:
addElement -> push new object onto _content; existing objects unchanged;
Glimmer creates exactly one new ElementRenderer
updateElement -> Object.assign onto the existing object (preserves identity);
replace _content with [..._content] (same refs) to notify
Glimmer; {{#each}} reuses all existing components
moveElement -> Object.assign only; no _content replacement; zero re-renders
deleteElement -> filter to new array without target; only that component is
destroyed
reorderElement-> mutate z_index in-place; replace array ref for reactivity
undo/redo -> restore from deep-cloned snapshot; full re-render acceptable
since it is an explicit user action
Canvas boundary clamping
------------------------
Added position and size clamping in both the drag.move and resize.move
handlers in canvas.js. Elements are now constrained to [0, canvasWidth - elW]
on the x axis and [0, canvasHeight - elH] on the y axis. Canvas dimensions
are read at event time (getCanvasDims()) so paper-size changes are reflected
without recreating interactables.1 parent 548d603 commit c896bbd
File tree
2 files changed
+188
-148
lines changed- addon/components
- template-builder
2 files changed
+188
-148
lines changed
0 commit comments