Browse Source

Deselect components on removal (#6799)

Removing a component (directly or via replaceWith) left it in the
editor's Selected collection, since only the core:component-delete
command deselected explicitly. The stale entry breaks anything
iterating the selection and, with UndoManager's trackSelection,
lets undo restore a selection pointing at removed components.

Deselect in Components.removeChildren so every non-temporary removal
path is covered. Temporary and undo-driven removals are unaffected.
pull/6803/head
Garvish Panchal 2 months ago
committed by GitHub
parent
commit
129a34c518
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 1
      packages/core/src/dom_components/model/Components.ts
  2. 44
      packages/core/test/specs/editor/index.ts

1
packages/core/src/dom_components/model/Components.ts

@ -210,6 +210,7 @@ Component> {
sels.remove(rulesRemoved.map((rule) => rule.getSelectors().at(0)));
if (!removed.opt.temporary) {
em.removeSelected(removed);
em.Commands.run('core:component-style-clear', { target: removed });
removed.views.forEach((view) => {
view.scriptContainer &&

44
packages/core/test/specs/editor/index.ts

@ -165,6 +165,50 @@ describe('Editor', () => {
expect(editor.getSelectedAll().length).toBe(0);
});
test('Removing a selected component removes it from the selection', () => {
const wrapper = editor.getWrapper()!;
const added = wrapper.append('<div>Component 1</div>');
editor.select(added[0]);
expect(editor.getSelectedAll().length).toBe(1);
added[0].remove();
expect(editor.getSelectedAll().length).toBe(0);
});
test('Replacing a selected component removes it from the selection', () => {
const wrapper = editor.getWrapper()!;
const added = wrapper.append('<div>Component 1</div>');
editor.select(added[0]);
added[0].replaceWith('<span>Replacement</span>');
expect(editor.getSelectedAll().length).toBe(0);
});
test('Undo after replaceWith inside component:selected restores content without orphan selection', () => {
const um = editor.UndoManager;
const wrapper = editor.getWrapper()!;
wrapper.append('<div data-id="a">A</div><div data-id="b">B</div>');
um.clear();
let replaced = false;
editor.on('component:selected', (cmp) => {
if (replaced) return;
replaced = true;
cmp.replaceWith('<span data-id="c">C</span>');
});
editor.select(wrapper.components().at(0));
expect(replaced).toBe(true);
expect(wrapper.getInnerHTML()).toBe('<span data-id="c">C</span><div data-id="b">B</div>');
um.undo();
expect(wrapper.getInnerHTML()).toBe('<div data-id="a">A</div><div data-id="b">B</div>');
// Whatever selection the undo restored must reference components still in the tree
editor.getSelectedAll().forEach((cmp) => {
expect(cmp.parent()).toBeTruthy();
});
});
test.skip('Shift key selecting a component that is being edited should not clear any text selections', () => {
const all = editor.Components.allById();
const em = editor.em;

Loading…
Cancel
Save