Browse Source

Make custom renderer async

pull/6510/head
Artur Arseniev 1 year ago
parent
commit
9041dc0003
  1. 10
      packages/core/src/canvas/config/config.ts
  2. 28
      packages/core/src/canvas/view/FrameView.ts
  3. 26
      packages/core/src/utils/Droppable.ts
  4. 19
      packages/core/src/utils/sorter/Sorter.ts

10
packages/core/src/canvas/config/config.ts

@ -5,6 +5,14 @@ import { CanvasSpotBuiltInTypes } from '../model/CanvasSpot';
import Frame from '../model/Frame'; import Frame from '../model/Frame';
import FrameView from '../view/FrameView'; import FrameView from '../view/FrameView';
export interface CustomRendererProps {
editor: Editor;
frame: Frame;
window: Window;
frameView: FrameView;
onMount: (view: ComponentView) => void;
}
export interface CanvasConfig { export interface CanvasConfig {
stylePrefix?: string; stylePrefix?: string;
@ -118,7 +126,7 @@ export interface CanvasConfig {
* reactRoot.render(<React.StrictMode><RenderChildren components={[root]}/></React.StrictMode>); * reactRoot.render(<React.StrictMode><RenderChildren components={[root]}/></React.StrictMode>);
* } * }
*/ */
customRenderer?: (options: { editor: Editor; frame: Frame; window: Window; frameView: FrameView }) => ComponentView; customRenderer?: (props: CustomRendererProps) => void;
} }
const config: () => CanvasConfig = () => ({ const config: () => CanvasConfig = () => ({

28
packages/core/src/canvas/view/FrameView.ts

@ -1,18 +1,18 @@
import { bindAll, debounce, isString, isUndefined } from 'underscore'; import { bindAll, debounce, isFunction, isString } from 'underscore';
import { ModuleView } from '../../abstract'; import { ModuleView } from '../../abstract';
import { BoxRect, ObjectAny } from '../../common'; import { BoxRect, ObjectAny } from '../../common';
import CssRulesView from '../../css_composer/view/CssRulesView'; import CssRulesView from '../../css_composer/view/CssRulesView';
import ComponentWrapperView from '../../dom_components/view/ComponentWrapperView';
import ComponentView from '../../dom_components/view/ComponentView';
import { type as typeHead } from '../../dom_components/model/ComponentHead'; import { type as typeHead } from '../../dom_components/model/ComponentHead';
import ComponentView from '../../dom_components/view/ComponentView';
import ComponentWrapperView from '../../dom_components/view/ComponentWrapperView';
import AutoScroller from '../../utils/AutoScroller';
import Droppable from '../../utils/Droppable'; import Droppable from '../../utils/Droppable';
import { append, appendVNodes, createCustomEvent, createEl, motionsEv, off, on } from '../../utils/dom'; import { append, appendVNodes, createCustomEvent, createEl, motionsEv, off, on } from '../../utils/dom';
import { hasDnd, setViewEl } from '../../utils/mixins'; import { hasDnd, setViewEl } from '../../utils/mixins';
import Canvas from '../model/Canvas'; import Canvas from '../model/Canvas';
import Frame from '../model/Frame'; import Frame from '../model/Frame';
import FrameWrapView from './FrameWrapView';
import CanvasEvents from '../types'; import CanvasEvents from '../types';
import AutoScroller from '../../utils/AutoScroller'; import FrameWrapView from './FrameWrapView';
export default class FrameView extends ModuleView<Frame, HTMLIFrameElement> { export default class FrameView extends ModuleView<Frame, HTMLIFrameElement> {
/** @ts-ignore */ /** @ts-ignore */
@ -339,7 +339,6 @@ export default class FrameView extends ModuleView<Frame, HTMLIFrameElement> {
renderBody() { renderBody() {
const { config, em, model, ppfx } = this; const { config, em, model, ppfx } = this;
const doc = this.getDoc();
const body = this.getBody(); const body = this.getBody();
const win = this.getWindow(); const win = this.getWindow();
const hasAutoHeight = model.hasAutoHeight(); const hasAutoHeight = model.hasAutoHeight();
@ -429,12 +428,16 @@ export default class FrameView extends ModuleView<Frame, HTMLIFrameElement> {
const { view } = em?.Components?.getType('wrapper') || {}; const { view } = em?.Components?.getType('wrapper') || {};
if (!view) return; if (!view) return;
if (typeof config.customRenderer === 'function') { if (isFunction(config.customRenderer)) {
this.wrapper = config.customRenderer({ config.customRenderer({
editor: em.Editor, editor: em.Editor,
frame: model, frame: model,
window: win, window: win,
frameView: this, frameView: this,
onMount: (rootView) => {
this.wrapper = rootView;
this._onRootMount(rootView);
},
}); });
} else { } else {
this.wrapper = new view({ this.wrapper = new view({
@ -445,8 +448,15 @@ export default class FrameView extends ModuleView<Frame, HTMLIFrameElement> {
frameView: this, frameView: this,
}, },
}).render(); }).render();
this._onRootMount(this.wrapper!);
} }
append(body, this.wrapper?.el!); }
_onRootMount(rootView: ComponentView) {
const { config, em, model } = this;
const doc = this.getDoc();
const body = doc.body;
append(body, rootView.el);
append( append(
body, body,
new CssRulesView({ new CssRulesView({

26
packages/core/src/utils/Droppable.ts

@ -187,9 +187,10 @@ export default class Droppable {
sorter.eventHandlers.legacyOnEnd = sorterOptions.legacyOnEnd; sorter.eventHandlers.legacyOnEnd = sorterOptions.legacyOnEnd;
sorter.containerContext.customTarget = sorterOptions.customTarget; sorter.containerContext.customTarget = sorterOptions.customTarget;
} }
let dropModel = this.getTempDropModel(content); const shallowCmp = em.Components.getShallowWrapper();
const el = dropModel.view?.el; const model = shallowCmp?.append(content, { temporary: true })[0];
const sources = el ? [{ element: el, dragSource: dragSourceOrigin }] : []; const element = model?.getEl();
const sources = [{ element, dragSource: { model, ...dragSourceOrigin } }];
sorter.startSort(sources); sorter.startSort(sources);
this.sorter = sorter; this.sorter = sorter;
this.draggedNode = sorter.sourceNodes?.[0]; this.draggedNode = sorter.sourceNodes?.[0];
@ -206,25 +207,6 @@ export default class Droppable {
em.trigger('canvas:dragenter', dt, content); em.trigger('canvas:dragenter', dt, content);
} }
/**
* Generates a temporary model of the content being dragged for use with the sorter.
* @returns The temporary model representing the dragged content.
*/
private getTempDropModel(content?: any) {
const comps = this.em.Components.getComponents();
const opts = {
avoidChildren: 1,
avoidStore: 1,
avoidUpdateStyle: 1,
};
const tempModel = comps.add(content, { ...opts, temporary: true });
let dropModel = comps.remove(tempModel, { ...opts, temporary: true } as any);
// @ts-ignore
dropModel = dropModel instanceof Array ? dropModel[0] : dropModel;
dropModel.view?.$el.data('model', dropModel);
return dropModel;
}
handleDragEnd(model: any, dt: any) { handleDragEnd(model: any, dt: any) {
const { em } = this; const { em } = this;
this.over = false; this.over = false;

19
packages/core/src/utils/sorter/Sorter.ts

@ -17,6 +17,11 @@ import {
import Dimension from './Dimension'; import Dimension from './Dimension';
import { SorterOptions } from './types'; import { SorterOptions } from './types';
interface SorterSource<T> {
element?: HTMLElement;
dragSource?: DragSource<T>;
}
export default class Sorter<T, NodeType extends SortableTreeNode<T>> { export default class Sorter<T, NodeType extends SortableTreeNode<T>> {
em: EditorModel; em: EditorModel;
treeClass: new (model: T, dragSource?: DragSource<T>) => NodeType; treeClass: new (model: T, dragSource?: DragSource<T>) => NodeType;
@ -70,7 +75,7 @@ export default class Sorter<T, NodeType extends SortableTreeNode<T>> {
* Picking components to move * Picking components to move
* @param {HTMLElement[]} sources[] * @param {HTMLElement[]} sources[]
* */ * */
startSort(sources: { element?: HTMLElement; dragSource?: DragSource<T> }[]) { startSort(sources: SorterSource<T>[]) {
const { sourceNodes, sourcesWithModel } = this.getSourceNodes(sources); const { sourceNodes, sourcesWithModel } = this.getSourceNodes(sources);
this.sourceNodes = sourceNodes; this.sourceNodes = sourceNodes;
this.dropLocationDeterminer.startSort(sourceNodes); this.dropLocationDeterminer.startSort(sourceNodes);
@ -93,11 +98,7 @@ export default class Sorter<T, NodeType extends SortableTreeNode<T>> {
this.em.trigger('sorter:drag:start', sources[0], sourcesWithModel[0]); this.em.trigger('sorter:drag:start', sources[0], sourcesWithModel[0]);
} }
validTarget( validTarget(targetEl: HTMLElement | undefined, sources: SorterSource<T>[], index: number): boolean {
targetEl: HTMLElement | undefined,
sources: { element?: HTMLElement; dragSource?: DragSource<T> }[],
index: number,
): boolean {
if (!targetEl) return false; if (!targetEl) return false;
const targetModel = $(targetEl).data('model'); const targetModel = $(targetEl).data('model');
if (!targetModel) return false; if (!targetModel) return false;
@ -108,12 +109,12 @@ export default class Sorter<T, NodeType extends SortableTreeNode<T>> {
return canMove; return canMove;
} }
private getSourceNodes(sources: { element?: HTMLElement; dragSource?: DragSource<T> }[]) { private getSourceNodes(sources: SorterSource<T>[]) {
const validSources = sources.filter((source) => !!source.dragSource || this.findValidSourceElement(source.element)); const validSources = sources.filter((source) => !!source.dragSource || this.findValidSourceElement(source.element));
const sourcesWithModel: { model: T; content?: any }[] = validSources.map((source) => { const sourcesWithModel: { model: T; content?: any }[] = validSources.map((source) => {
return { return {
model: $(source.element)?.data('model'), model: source.dragSource?.model || $(source.element)?.data('model'),
content: source.dragSource, content: source.dragSource,
}; };
}); });
@ -188,7 +189,7 @@ export default class Sorter<T, NodeType extends SortableTreeNode<T>> {
/** /**
* Finds the closest valid source element within the container context. * Finds the closest valid source element within the container context.
* @param sourceElement - The initial source element to check. * @param sourceElement - The initial source element to check.
* @returns The closest valid source element, or null if none is found. * @returns The closest valid source element, or null if none is found.
*/ */

Loading…
Cancel
Save