diff --git a/packages/core/src/dom_components/model/Components.ts b/packages/core/src/dom_components/model/Components.ts index ce45676f5..d41ab740e 100644 --- a/packages/core/src/dom_components/model/Components.ts +++ b/packages/core/src/dom_components/model/Components.ts @@ -5,12 +5,14 @@ import { DomComponentsConfig } from '../config/config'; import EditorModel from '../../editor/model/Editor'; import ComponentManager from '..'; import CssRule from '../../css_composer/model/CssRule'; +import type Frame from '../../canvas/model/Frame'; import { ComponentAdd, ComponentAddType, ComponentDefinition, ComponentDefinitionDefined, + ComponentOptions, ComponentProperties, } from './types'; import ComponentText from './ComponentText'; @@ -113,10 +115,9 @@ const getComponentsFromDefs = ( }); }; -export interface ComponentsOptions { - em: EditorModel; - config?: DomComponentsConfig; +export interface ComponentsOptions extends Omit { domc?: ComponentManager; + config?: DomComponentsConfig; } interface AddComponentOptions extends AddOptions { @@ -402,10 +403,19 @@ Component> { return model; } + updateFrameRefs(model: Component, frame?: Frame) { + if (!frame || model.frame === frame) return; + model.opt.frame = frame; + model.components().forEach((child) => this.updateFrameRefs(child, frame)); + } + onAdd(model: Component, c?: any, opts: { temporary?: boolean } = {}) { const { domc, em } = this; const avoidInline = em.config.avoidInlineStyle; const allById = domc?.allById(); + const frame = this.parent?.frame || this.opt.frame; + + this.updateFrameRefs(model, frame); allById?.[model.getId()] !== model && domc?.Component.ensureInList(model); if (!avoidInline && em.config.forceClass && !opts.temporary) { diff --git a/packages/core/test/specs/dom_components/model/Component.ts b/packages/core/test/specs/dom_components/model/Component.ts index 5f984efac..c09f2a62f 100644 --- a/packages/core/test/specs/dom_components/model/Component.ts +++ b/packages/core/test/specs/dom_components/model/Component.ts @@ -471,6 +471,19 @@ describe('Component', () => { expect(result[0].em).toEqual(em); }); + test('append() assigns the destination frame to added component trees', () => { + const wrapper = em.getWrapper()!; + const frame = em.Pages.getMain().getMainFrame(); + const added = wrapper.append({ + tagName: 'section', + components: [{ tagName: 'span', content: 'Child' }], + })[0]; + const child = added.components().at(0); + + expect(added.frame).toBe(frame); + expect(child?.frame).toBe(frame); + }); + test('components() set new collection', () => { obj.append([{}, {}]); obj.components('test'); diff --git a/packages/core/test/specs/pages/index.ts b/packages/core/test/specs/pages/index.ts index f002eb156..d8ec48eb8 100644 --- a/packages/core/test/specs/pages/index.ts +++ b/packages/core/test/specs/pages/index.ts @@ -518,6 +518,31 @@ describe('Pages in canvas', () => { expect(target.parent()).toBe(mainWrapper); }); + test('Moving a component tree across page frames updates its frame reference', () => { + const mainFrame = pm.getMain().getMainFrame(); + const mainWrapper = mainFrame.getComponent(); + const page = pm.add({ + id: 'frame-target-page', + component: [], + })!; + const targetFrame = page.getMainFrame(); + const targetWrapper = targetFrame.getComponent(); + const target = mainWrapper.append({ + tagName: 'section', + components: [{ tagName: 'span', content: 'Inner child' }], + })[0]; + const child = target.components().at(0); + + expect(target.frame).toBe(mainFrame); + expect(child?.frame).toBe(mainFrame); + + targetWrapper.append(target); + + expect(target.frame).toBe(targetFrame); + expect(child?.frame).toBe(targetFrame); + expect(target.parent()).toBe(targetWrapper); + }); + test('Page supports a custom wrapper type for frames', async () => { editor.Components.addType('wrapper-component', { extend: 'wrapper',