Skip to content

Commit cf2f5cc

Browse files
committed
fix(template-builder): selection highlight, 0,0 repositioning on z-index change
Bug 1 — Selection not working Root cause: canvas.js was tracking _selectedUuid locally. When the layers panel selected an element, the parent's selectedElement updated but the canvas's _selectedUuid never changed, so @isSelected was always false. Additionally, the canvas's {{on "click" handleDeselectAll}} was firing even when a child element was tapped (interact.js tap does not stop the native click from bubbling), immediately clearing the selection. Fix: - canvas.js: removed local _selectedUuid state entirely. selectedUuid is now a getter derived from @selectedElement (the parent's source of truth). This means any selection source (canvas tap, layers panel, keyboard) is automatically reflected in the canvas highlight. - canvas.js: handleDeselectAll now guards with event.target !== event.currentTarget so it only fires when the canvas background itself is clicked, not when a child element is tapped. Bug 2 — z-index change repositions all elements to 0,0 Root cause: reorderElement replaces element objects with new spread copies. Glimmer re-renders the ElementRenderer's style attribute (wrapperStyle). wrapperStyle intentionally omits the CSS transform (which is managed imperatively by interact.js). When Glimmer writes the new style attribute, it clears the transform, snapping every element to 0,0. Fix: - element-renderer.hbs: added {{did-update this.handleUpdate @element}}. - element-renderer.js: handleUpdate re-applies _applyTransform(el) after Glimmer updates the style attribute, restoring the correct position. Bonus fix — reorderElement now syncs selectedElement to the new object so the properties panel reflects the updated z_index immediately.
1 parent 7389a43 commit cf2f5cc

File tree

4 files changed

+29
-11
lines changed

4 files changed

+29
-11
lines changed

addon/components/template-builder.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -338,6 +338,11 @@ export default class TemplateBuilderComponent extends Component {
338338
if (el.uuid === swapElement.uuid) return { ...el, z_index: currentZ };
339339
return el;
340340
});
341+
342+
// Sync selectedElement so the properties panel reflects the new z_index.
343+
if (this.selectedElement?.uuid === uuid) {
344+
this.selectedElement = this._content.find((el) => el.uuid === uuid) ?? null;
345+
}
341346
}
342347

343348
// -------------------------------------------------------------------------

addon/components/template-builder/canvas.js

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import Component from '@glimmer/component';
2-
import { tracked } from '@glimmer/tracking';
32
import { action } from '@ember/object';
43
import { guidFor } from '@ember/object/internals';
54

@@ -31,12 +30,10 @@ import { guidFor } from '@ember/object/internals';
3130
export default class TemplateBuilderCanvasComponent extends Component {
3231
canvasId = `tb-canvas-${guidFor(this)}`;
3332

34-
/**
35-
* Tracked UUID of the currently selected element. Using a primitive string
36-
* (not an object reference) ensures Glimmer detects the change and
37-
* re-renders only the affected ElementRenderer's selection ring.
38-
*/
39-
@tracked _selectedUuid = null;
33+
// No local selection state. The canvas derives selectedUuid from
34+
// @selectedElement (owned by TemplateBuilderComponent) so that selections
35+
// made from the layers panel, keyboard shortcuts, or any other source are
36+
// always reflected here without duplication.
4037

4138
// -------------------------------------------------------------------------
4239
// Canvas dimensions
@@ -70,7 +67,7 @@ export default class TemplateBuilderCanvasComponent extends Component {
7067
}
7168

7269
get selectedUuid() {
73-
return this._selectedUuid;
70+
return this.args.selectedElement?.uuid ?? null;
7471
}
7572

7673
// -------------------------------------------------------------------------
@@ -79,15 +76,20 @@ export default class TemplateBuilderCanvasComponent extends Component {
7976

8077
@action
8178
handleSelectElement(element) {
82-
this._selectedUuid = element.uuid;
79+
// Delegate entirely to the parent. The parent sets selectedElement,
80+
// which flows back down as @selectedElement, which drives selectedUuid.
8381
if (this.args.onSelectElement) {
8482
this.args.onSelectElement(element);
8583
}
8684
}
8785

8886
@action
89-
handleDeselectAll() {
90-
this._selectedUuid = null;
87+
handleDeselectAll(event) {
88+
// Only deselect when the user clicks the canvas background directly.
89+
// If the click originated from a child element (an ElementRenderer),
90+
// interact.js has already fired its tap event and called handleSelectElement.
91+
// We must not clear the selection here in that case.
92+
if (event.target !== event.currentTarget) return;
9193
if (this.args.onDeselectAll) {
9294
this.args.onDeselectAll();
9395
}

addon/components/template-builder/element-renderer.hbs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
data-element-type={{this.elementType}}
99
data-element-uuid={{@element.uuid}}
1010
{{did-insert this.handleInsert}}
11+
{{did-update this.handleUpdate @element}}
1112
{{will-destroy this.handleDestroy}}
1213
>
1314
{{! TEXT }}

addon/components/template-builder/element-renderer.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,16 @@ export default class TemplateBuilderElementRendererComponent extends Component {
6060
this._setupInteract(el);
6161
}
6262

63+
@action
64+
handleUpdate(el) {
65+
// Glimmer has just re-rendered the style attribute (e.g. after a z_index
66+
// change via reorderElement). The style attribute does not include the
67+
// CSS transform — that is managed imperatively by interact.js and
68+
// _applyTransform. Re-apply it now so the element stays at its current
69+
// position rather than snapping to 0,0.
70+
this._applyTransform(el);
71+
}
72+
6373
@action
6474
handleDestroy(el) {
6575
if (this._interactable) {

0 commit comments

Comments
 (0)