Browse Source

Custom render refactor (#6510)

clean-up-readme
Artur Arseniev 9 months ago
committed by GitHub
parent
commit
b923584075
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 10
      packages/core/src/canvas/config/config.ts
  2. 28
      packages/core/src/canvas/view/FrameView.ts
  3. 2
      packages/core/src/dom_components/model/Component.ts
  4. 26
      packages/core/src/utils/Droppable.ts
  5. 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 FrameView from '../view/FrameView';
export interface CustomRendererProps {
editor: Editor;
frame: Frame;
window: Window;
frameView: FrameView;
onMount: (view: ComponentView) => void;
}
export interface CanvasConfig {
stylePrefix?: string;
@ -118,7 +126,7 @@ export interface CanvasConfig {
* 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 = () => ({

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

2
packages/core/src/dom_components/model/Component.ts

@ -323,7 +323,7 @@ export default class Component extends StyleableModel<ComponentProperties> {
// Register global updates for collection properties
['classes', 'traits', 'components'].forEach((name) => {
const events = `add remove ${name !== 'components' ? 'change' : ''}`;
const events = `add remove reset ${name !== 'components' ? 'change' : ''}`;
this.listenTo(this.get(name), events.trim(), (...args) => this.emitUpdate(name, ...args));
});

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

@ -187,9 +187,10 @@ export default class Droppable {
sorter.eventHandlers.legacyOnEnd = sorterOptions.legacyOnEnd;
sorter.containerContext.customTarget = sorterOptions.customTarget;
}
let dropModel = this.getTempDropModel(content);
const el = dropModel.view?.el;
const sources = el ? [{ element: el, dragSource: dragSourceOrigin }] : [];
const shallowCmp = em.Components.getShallowWrapper();
const model = shallowCmp?.append(content, { temporary: true })[0];
const element = model?.getEl();
const sources = [{ element, dragSource: { model, ...dragSourceOrigin } }];
sorter.startSort(sources);
this.sorter = sorter;
this.draggedNode = sorter.sourceNodes?.[0];
@ -206,25 +207,6 @@ export default class Droppable {
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) {
const { em } = this;
this.over = false;

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

@ -17,6 +17,11 @@ import {
import Dimension from './Dimension';
import { SorterOptions } from './types';
interface SorterSource<T> {
element?: HTMLElement;
dragSource?: DragSource<T>;
}
export default class Sorter<T, NodeType extends SortableTreeNode<T>> {
em: EditorModel;
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
* @param {HTMLElement[]} sources[]
* */
startSort(sources: { element?: HTMLElement; dragSource?: DragSource<T> }[]) {
startSort(sources: SorterSource<T>[]) {
const { sourceNodes, sourcesWithModel } = this.getSourceNodes(sources);
this.sourceNodes = 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]);
}
validTarget(
targetEl: HTMLElement | undefined,
sources: { element?: HTMLElement; dragSource?: DragSource<T> }[],
index: number,
): boolean {
validTarget(targetEl: HTMLElement | undefined, sources: SorterSource<T>[], index: number): boolean {
if (!targetEl) return false;
const targetModel = $(targetEl).data('model');
if (!targetModel) return false;
@ -108,12 +109,12 @@ export default class Sorter<T, NodeType extends SortableTreeNode<T>> {
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 sourcesWithModel: { model: T; content?: any }[] = validSources.map((source) => {
return {
model: $(source.element)?.data('model'),
model: source.dragSource?.model || $(source.element)?.data('model'),
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.
* @param sourceElement - The initial source element to check.
* @returns The closest valid source element, or null if none is found.
*/

Loading…
Cancel
Save