feat: 修改rax-render

This commit is contained in:
rorya.lyj 2020-08-14 15:25:04 +08:00
parent ac55847b3f
commit 14ad77cd69
2 changed files with 440 additions and 240 deletions

View File

@ -2,7 +2,7 @@ import { Fragment, Component, createElement } from 'rax';
// import { observer } from './obx-rax/observer'; // import { observer } from './obx-rax/observer';
import RaxEngine from '@ali/lowcode-rax-renderer/lib/index'; import RaxEngine from '@ali/lowcode-rax-renderer/lib/index';
// import RaxEngine from '../../rax-render/lib/index'; // import RaxEngine from '../../rax-render/lib/index';
import { SimulatorRenderer } from './renderer'; import { SimulatorRendererContainer, DocumentInstance } from './renderer';
import { host } from './host'; import { host } from './host';
import './renderer.less'; import './renderer.less';
@ -37,17 +37,31 @@ const originCloneElement = (window as any).Rax.cloneElement;
return originCloneElement(child, props, ...rest); return originCloneElement(child, props, ...rest);
}; };
export default class SimulatorRendererView extends Component<{ renderer: SimulatorRenderer }> { export default class SimulatorRendererView extends Component<{ rendererContainer: SimulatorRendererContainer }> {
render() { render() {
const { renderer } = this.props; const { rendererContainer } = this.props;
return ( return (
<Layout renderer={renderer}> <Layout rendererContainer={rendererContainer}>
<Renderer renderer={renderer} /> <Routes rendererContainer={rendererContainer} />
</Layout> </Layout>
); );
} }
} }
export class Routes extends Component<{ rendererContainer: SimulatorRendererContainer }> {
render() {
const { rendererContainer } = this.props;
return (
<Fragment>
{rendererContainer.documentInstances.map((instance) => {
return (
<Renderer rendererContainer={rendererContainer} documentInstance={instance} />
);
})}
</Fragment>
);
}
}
function ucfirst(s: string) { function ucfirst(s: string) {
return s.charAt(0).toUpperCase() + s.substring(1); return s.charAt(0).toUpperCase() + s.substring(1);
} }
@ -68,14 +82,13 @@ function getDeviceView(view: any, device: string, mode: string) {
return view; return view;
} }
// @observer class Layout extends Component<{ rendererContainer: SimulatorRendererContainer }> {
class Layout extends Component<{ renderer: SimulatorRenderer }> {
shouldComponentUpdate() { shouldComponentUpdate() {
return false; return false;
} }
render() { render() {
const { renderer, children } = this.props; const { rendererContainer, children } = this.props;
const layout = renderer.layout; const layout = rendererContainer.layout;
if (layout) { if (layout) {
const { Component, props } = layout; const { Component, props } = layout;
@ -86,11 +99,10 @@ class Layout extends Component<{ renderer: SimulatorRenderer }> {
} }
} }
// @observer class Renderer extends Component<{ rendererContainer: SimulatorRendererContainer, documentInstance: DocumentInstance }> {
class Renderer extends Component<{ renderer: SimulatorRenderer }> {
constructor(props: any) { constructor(props: any) {
super(props); super(props);
this.props.renderer.onReRender(() => { this.props.rendererContainer.onReRender(() => {
this.forceUpdate(); this.forceUpdate();
}); });
} }
@ -98,24 +110,28 @@ class Renderer extends Component<{ renderer: SimulatorRenderer }> {
return false; return false;
} }
render() { render() {
const { renderer } = this.props; const { documentInstance } = this.props;
const { device, designMode } = renderer; const { container } = documentInstance;
const { designMode, device } = container;
const { rendererContainer: renderer } = this.props;
// const { device, designMode } = renderer;
return ( return (
<RaxEngine <RaxEngine
schema={renderer.schema} schema={documentInstance.schema}
components={renderer.components} components={renderer.components}
context={renderer.context} context={renderer.context}
designMode={renderer.designMode} designMode={renderer.designMode}
suspended={renderer.suspended} suspended={documentInstance.suspended}
self={renderer.scope} self={documentInstance.scope}
onCompGetRef={(schema: any, ref: any) => { onCompGetRef={(schema: any, ref: any) => {
renderer.mountInstance(schema.id, ref); documentInstance.mountInstance(schema.id, ref);
}} }}
customCreateElement={(Component: any, props: any, children: any) => { customCreateElement={(Component: any, props: any, children: any) => {
const { __id, __desingMode, ...viewProps } = props; const { __id, __desingMode, ...viewProps } = props;
viewProps.componentId = __id; viewProps.componentId = __id;
const leaf = host.document.getNode(__id); const leaf: any = null;
// const leaf = host.document.getNode(__id);
viewProps._leaf = leaf; viewProps._leaf = leaf;
viewProps._componentName = leaf?.componentName; viewProps._componentName = leaf?.componentName;

View File

@ -1,5 +1,6 @@
import { BuiltinSimulatorRenderer, NodeInstance, Component } from '@ali/lowcode-designer'; import { BuiltinSimulatorRenderer, NodeInstance, Component, DocumentModel } from '@ali/lowcode-designer';
import { shared, render as raxRender, createElement } from 'rax'; // @ts-ignore
import { shared, render as raxRender, createElement, ComponentType } from 'rax';
import DriverUniversal from 'driver-universal'; import DriverUniversal from 'driver-universal';
import { computed, obx } from '@recore/obx'; import { computed, obx } from '@recore/obx';
import { RootSchema, NpmInfo, ComponentSchema } from '@ali/lowcode-types'; import { RootSchema, NpmInfo, ComponentSchema } from '@ali/lowcode-types';
@ -23,6 +24,7 @@ export interface LibraryMap {
} }
const SYMBOL_VNID = Symbol('_LCNodeId'); const SYMBOL_VNID = Symbol('_LCNodeId');
const SYMBOL_VDID = Symbol('_LCDocId');
function accessLibrary(library: string | object) { function accessLibrary(library: string | object) {
if (typeof library !== 'string') { if (typeof library !== 'string') {
@ -32,45 +34,116 @@ function accessLibrary(library: string | object) {
return (window as any)[library]; return (window as any)[library];
} }
export class SimulatorRenderer implements BuiltinSimulatorRenderer { // Slot/Leaf and Fragment|FunctionComponent polyfill(ref)
readonly isSimulatorRenderer = true;
private dispose?: () => void;
const builtinComponents = {
Slot,
Leaf,
};
function buildComponents(libraryMap: LibraryMap,
componentsMap: { [componentName: string]: NpmInfo | ComponentType<any> | ComponentSchema },
createComponent: (schema: ComponentSchema) => Component | null) {
const components: any = {
...builtinComponents,
};
Object.keys(componentsMap).forEach((componentName) => {
let component = componentsMap[componentName];
if (component && (component as ComponentSchema).componentName === 'Component') {
components[componentName] = createComponent(component as ComponentSchema);
} else if (isReactComponent(component)) {
components[componentName] = component;
} else {
component = findComponent(libraryMap, componentName, component as NpmInfo);
if (component) {
components[componentName] = component;
}
}
});
return components;
}
let REACT_KEY = '';
function cacheReactKey(el: Element): Element {
if (REACT_KEY !== '') {
return el;
}
REACT_KEY = Object.keys(el).find((key) => key.startsWith('__reactInternalInstance$')) || '';
if (!REACT_KEY && (el as HTMLElement).parentElement) {
return cacheReactKey((el as HTMLElement).parentElement!);
}
return el;
}
function getClosestNodeInstance(from: any, specId?: string): NodeInstance<any> | null {
const el: any = from;
if (el) {
// if (isElement(el)) {
// el = cacheReactKey(el);
// } else {
// return getNodeInstance(el, specId);
// }
return getNodeInstance(el);
}
return null;
}
function getNodeInstance(dom: HTMLElement): NodeInstance<any> | null {
const INTERNAL = '_internal';
let instance = Instance.get(dom);
while (instance && instance[INTERNAL]) {
if (isValidDesignModeRaxComponentInstance(instance)) {
const docId = (instance as any)[SYMBOL_VDID];
return {
docId,
nodeId: instance.props._leaf.getId(),
instance: instance,
node: instance.props._leaf,
};
}
instance = instance[INTERNAL].__parentInstance;
}
return null;
}
function checkInstanceMounted(instance: any): boolean {
if (isElement(instance)) {
return instance.parentElement != null;
}
return true;
}
function isValidDesignModeRaxComponentInstance(
raxComponentInst: any,
): raxComponentInst is {
props: {
_leaf: Exclude<NodeInstance<any>['node'], null | undefined>;
};
} {
const leaf = raxComponentInst?.props?._leaf;
return leaf && typeof leaf === 'object' && leaf.isNode;
}
export class DocumentInstance {
private instancesMap = new Map<string, any[]>(); private instancesMap = new Map<string, any[]>();
@obx.ref private _schema?: RootSchema; @obx.ref private _schema?: RootSchema;
@computed get schema(): any { @computed get schema(): any {
return this._schema; return this._schema;
} }
private _libraryMap: { [key: string]: string } = {};
private buildComponents() {
this._components = buildComponents(this._libraryMap, this._componentsMap);
}
@obx.ref private _components: any = {};
@computed get components(): object {
// 根据 device 选择不同组件,进行响应式
// 更好的做法是,根据 device 选择加载不同的组件资源,甚至是 simulatorUrl
return this._components;
}
@obx.ref private _designMode = 'design'; private dispose?: () => void;
@computed get designMode(): any {
return this._designMode;
}
@obx.ref private _componentsMap = {}; constructor(readonly container: SimulatorRendererContainer, readonly document: DocumentModel) {
@computed get componentsMap(): any { this.dispose = host.autorun(() => {
return this._componentsMap; // sync schema
} this._schema = document.export(1);
});
@obx.ref private _device = 'default';
@computed get device() {
return this._device;
}
// context from: utils、constants、history、location、match
@obx.ref private _appContext = {};
@computed get context(): any {
return this._appContext;
} }
@computed get suspended(): any { @computed get suspended(): any {
@ -80,23 +153,110 @@ export class SimulatorRenderer implements BuiltinSimulatorRenderer {
return null; return null;
} }
@computed get layout(): any { get path(): string {
// TODO: parse layout Component return '/' + this.document.fileName;
return null;
} }
private emitter = new EventEmitter();
constructor() { get id() {
if (!host) { return this.document.id;
}
private unmountIntance(id: string, instance: any) {
const instances = this.instancesMap.get(id);
if (instances) {
const i = instances.indexOf(instance);
if (i > -1) {
instances.splice(i, 1);
host.setInstance(this.document.id, id, instances);
}
}
}
mountInstance(id: string, instance: any) {
const docId = this.document.id;
const instancesMap = this.instancesMap;
if (instance == null) {
let instances = this.instancesMap.get(id);
if (instances) {
instances = instances.filter(checkInstanceMounted);
if (instances.length > 0) {
instancesMap.set(id, instances);
host.setInstance(this.document.id, id, instances);
} else {
instancesMap.delete(id);
host.setInstance(this.document.id, id, null);
}
}
return; return;
} }
const unmountIntance = this.unmountIntance.bind(this);
const origId = (instance as any)[SYMBOL_VNID];
if (origId && origId !== id) {
// 另外一个节点的 instance 在此被复用了,需要从原来地方卸载
unmountIntance(origId, instance);
}
if (isElement(instance)) {
cacheReactKey(instance);
} else if (origId !== id) {
// 涵盖 origId == null || origId !== id 的情况
let origUnmount: any = instance.componentWillUnmount;
if (origUnmount && origUnmount.origUnmount) {
origUnmount = origUnmount.origUnmount;
}
// hack! delete instance from map
const newUnmount = function(this: any) {
unmountIntance(id, instance);
origUnmount && origUnmount.call(this);
};
(newUnmount as any).origUnmount = origUnmount;
instance.componentWillUnmount = newUnmount;
}
this.dispose = host.connect(this as any, () => { (instance as any)[SYMBOL_VNID] = id;
(instance as any)[SYMBOL_VDID] = docId;
let instances = this.instancesMap.get(id);
if (instances) {
const l = instances.length;
instances = instances.filter(checkInstanceMounted);
let updated = instances.length !== l;
if (!instances.includes(instance)) {
instances.push(instance);
updated = true;
}
if (!updated) {
return;
}
} else {
instances = [instance];
}
instancesMap.set(id, instances);
host.setInstance(this.document.id, id, instances);
}
mountContext(docId: string, id: string, ctx: object) {
// this.ctxMap.set(id, ctx);
}
getNode(id: string): Node | null {
return null;
// return this.document.getNode(id);
}
}
export class SimulatorRendererContainer implements BuiltinSimulatorRenderer {
readonly isSimulatorRenderer = true;
private dispose?: () => void;
// TODO: history
readonly history: any;
@obx.ref private _documentInstances: DocumentInstance[] = [];
get documentInstances() {
return this._documentInstances;
}
constructor() {
this.dispose = host.connect(this, () => {
// sync layout config // sync layout config
// sync schema
this._schema = host.document.export(1);
// todo: split with others, not all should recompute // todo: split with others, not all should recompute
if (this._libraryMap !== host.libraryMap || this._componentsMap !== host.designer.componentsMap) { if (this._libraryMap !== host.libraryMap || this._componentsMap !== host.designer.componentsMap) {
this._libraryMap = host.libraryMap || {}; this._libraryMap = host.libraryMap || {};
@ -107,14 +267,38 @@ export class SimulatorRenderer implements BuiltinSimulatorRenderer {
// sync designMode // sync designMode
this._designMode = host.designMode; this._designMode = host.designMode;
// sync suspended
// sync scope
// sync device // sync device
this._device = host.device; this._device = host.device;
});
this.emitter.emit('rerender'); const documentInstanceMap = new Map<string, DocumentInstance>();
let initialEntry = '/';
host.autorun(({ firstRun }) => {
this._documentInstances = host.project.documents.map((doc) => {
let inst = documentInstanceMap.get(doc.id);
if (!inst) {
inst = new DocumentInstance(this, doc);
documentInstanceMap.set(doc.id, inst);
}
return inst;
});
const path = host.project.currentDocument
? documentInstanceMap.get(host.project.currentDocument.id)!.path
: '/';
if (firstRun) {
initialEntry = path;
} else {
if (this.history.location.pathname !== path) {
this.history.replace(path);
}
}
});
/*
const history = createMemoryHistory({
initialEntries: [initialEntry],
});
this.history = history;
history.listen((location, action) => {
host.project.open(location.pathname.substr(1));
}); });
host.componentsConsumer.consume(async (componentsAsset) => { host.componentsConsumer.consume(async (componentsAsset) => {
if (componentsAsset) { if (componentsAsset) {
@ -122,31 +306,69 @@ export class SimulatorRenderer implements BuiltinSimulatorRenderer {
this.buildComponents(); this.buildComponents();
} }
}); });
this._appContext = {
utils: {
router: {
push(path: string, params?: object) {
history.push(withQueryParams(path, params));
},
replace(path: string, params?: object) {
history.replace(withQueryParams(path, params));
},
},
legaoBuiltins: {
getUrlParams() {
const search = history.location.search;
return parseQuery(search);
}
}
},
constants: {},
};
host.injectionConsumer.consume((data) => { host.injectionConsumer.consume((data) => {
// sync utils, i18n, contants,... config // sync utils, i18n, contants,... config
this._appContext = {
utils: {},
constants: {
name: 'demo',
},
};
}); });
*/
} }
getClosestNodeInstance(from: any, nodeId?: string): NodeInstance<any> | null { @computed get layout(): any {
const node = getClosestNodeInstance(from, nodeId); // TODO: parse layout Component
return node; return null;
} }
getComponentInstances(id: string): any[] | null { private _libraryMap: { [key: string]: string } = {};
return this.instancesMap.get(id) || null; private buildComponents() {
// TODO: remove this.createComponent
this._components = buildComponents(this._libraryMap, this._componentsMap, this.createComponent.bind(this));
} }
@obx.ref private _components: any = {};
onReRender(fn: () => void) { @computed get components(): object {
this.emitter.on('rerender', fn); // 根据 device 选择不同组件,进行响应式
return () => { // 更好的做法是,根据 device 选择加载不同的组件资源,甚至是 simulatorUrl
this.emitter.removeListener('renderer', fn); return this._components;
}; }
// context from: utils、constants、history、location、match
@obx.ref private _appContext = {};
@computed get context(): any {
return this._appContext;
}
@obx.ref private _designMode: string = 'design';
@computed get designMode(): any {
return this._designMode;
}
@obx.ref private _device: string = 'default';
@computed get device() {
return this._device;
}
@obx.ref private _componentsMap = {};
@computed get componentsMap(): any {
return this._componentsMap;
}
/**
*
*/
load(asset: Asset): Promise<any> {
return loader.load(asset);
} }
getComponent(componentName: string) { getComponent(componentName: string) {
@ -167,20 +389,47 @@ export class SimulatorRenderer implements BuiltinSimulatorRenderer {
componentName = paths.join('.'); componentName = paths.join('.');
} }
// return null; return null;
} }
createComponent(schema: ComponentSchema): Component | null { getClosestNodeInstance(from: any, nodeId?: string): NodeInstance<any> | null {
const el: any = from;
if (el) {
// if (isElement(el)) {
// el = cacheReactKey(el);
// } else {
// return getNodeInstance(el, specId);
// }
return getNodeInstance(el);
}
return null; return null;
} }
getComponentInstances(id: string): any[] | null {
return this.instancesMap.get(id) || null;
}
onReRender(fn: () => void) {
this.emitter.on('rerender', fn);
return () => {
this.emitter.removeListener('renderer', fn);
};
}
findDOMNodes(instance: any): Array<Element | Text> | null {
return raxFindDOMNodes(instance);
}
getClientRects(element: Element | Text) {
return getClientRects(element);
}
setNativeSelection(enableFlag: boolean) { setNativeSelection(enableFlag: boolean) {
setNativeSelection(enableFlag); setNativeSelection(enableFlag);
} }
setDraggingState(state: boolean) { setDraggingState(state: boolean) {
cursor.setDragging(state); cursor.setDragging(state);
} }
setCopyState(state: boolean) { setCopyState(state: boolean) {
cursor.setCopy(state); cursor.setCopy(state);
} }
@ -188,93 +437,100 @@ export class SimulatorRenderer implements BuiltinSimulatorRenderer {
cursor.release(); cursor.release();
} }
findDOMNodes(instance: any): Array<Element | Text> | null { createComponent(schema: ComponentSchema): Component | null {
return [raxFindDOMNodes(instance)]; return null;
} // TODO: use ComponentEngine refactor
/*
const _schema = {
...schema,
};
_schema.methods = {};
_schema.lifeCycles = {};
/** const node = host.document.createNode(_schema);
* _schema = node.export(TransformStage.Render);
*/
load(asset: Asset): Promise<any> {
return loader.load(asset);
}
// private instancesMap = new Map<string, any[]>(); const processPropsSchema = (propsSchema: any, propsMap: any): any => {
private unmountIntance(id: string, instance: any) { if (!propsSchema) {
const instances = this.instancesMap.get(id); return {};
if (instances) {
const i = instances.indexOf(instance);
if (i > -1) {
instances.splice(i, 1);
host.setInstance(id, instances);
} }
}
} const result = { ...propsSchema };
mountInstance(id: string, instance: any | null) { const reg = /^(?:this\.props|props)\.(\S+)$/;
const instancesMap = this.instancesMap; Object.keys(result).map((key: string) => {
if (instance == null) { if (result[key]?.type === 'JSExpression') {
let instances = this.instancesMap.get(id); const { value } = result[key];
if (instances) { const matched = reg.exec(value);
instances = instances.filter(checkInstanceMounted); if (matched) {
if (instances.length > 0) { const propName = matched[1];
instancesMap.set(id, instances); result[key] = propsMap[propName];
host.setInstance(id, instances); }
} else { } else if (result[key]?.type === 'JSSlot') {
instancesMap.delete(id); const schema = result[key].value;
host.setInstance(id, null); result[key] = createElement(Ele, {schema, propsMap: {}});
}
});
return result;
};
const renderer = this;
const componentsMap = renderer.componentsMap;
class Ele extends React.Component<{ schema: any, propsMap: any }> {
private isModal: boolean;
constructor(props: any){
super(props);
const componentMeta = host.document.getComponentMeta(props.schema.componentName);
if (componentMeta?.prototype?.isModal()) {
this.isModal = true;
return;
} }
} }
return;
} render() {
const unmountIntance = this.unmountIntance.bind(this); if (this.isModal) {
const origId = (instance as any)[SYMBOL_VNID]; return null;
if (origId && origId !== id) { }
// 另外一个节点的 instance 在此被复用了,需要从原来地方卸载 const { schema, propsMap } = this.props;
unmountIntance(origId, instance); const Com = componentsMap[schema.componentName];
} if (!Com) {
if (isElement(instance)) { return null;
// cacheReactKey(instance); }
} else if (origId !== id) { let children = null;
// 涵盖 origId == null || origId !== id 的情况 if (schema.children && schema.children.length > 0) {
let origUnmount: any = instance.componentWillUnmount; children = schema.children.map((item: any) => createElement(Ele, {schema: item, propsMap}));
if (origUnmount && origUnmount.origUnmount) { }
origUnmount = origUnmount.origUnmount; const props = processPropsSchema(schema.props, propsMap);
const _leaf = host.document.createNode(schema);
return createElement(Com, {...props, _leaf}, children);
}
const _leaf = this.document.designer.currentDocument?.createNode(schema);
const node = this.document.createNode(schema);
let props = processPropsSchema(schema.props, propsMap);
props = this.document.designer.transformProps(props, node, TransformStage.Init);
props = this.document.designer.transformProps(props, node, TransformStage.Render);
return createElement(Com, { ...props, _leaf }, children);
};
const container = this;
class Com extends React.Component {
render() {
const componentsMap = container.componentsMap;
let children = null;
if (_schema.children && Array.isArray(_schema.children)) {
children = _schema.children?.map((item: any) => getElement(componentsMap, item, this.props));
}
} }
// hack! delete instance from map
const newUnmount = function(this: any) {
unmountIntance(id, instance);
origUnmount && origUnmount.call(this);
};
(newUnmount as any).origUnmount = origUnmount;
instance.componentWillUnmount = newUnmount;
} }
(instance as any)[SYMBOL_VNID] = id; return Com;
let instances = this.instancesMap.get(id); */
if (instances) {
const l = instances.length;
instances = instances.filter(checkInstanceMounted);
let updated = instances.length !== l;
if (!instances.includes(instance)) {
instances.push(instance);
updated = true;
}
if (!updated) {
return;
}
} else {
instances = [instance];
}
instancesMap.set(id, instances);
host.setInstance(id, instances);
}
getClientRects(element: Element | Text) {
return getClientRects(element);
} }
private _running = false; private _running = false;
run() { run() {
if (this._running) { if (this._running) {
return; return;
@ -287,6 +543,7 @@ export class SimulatorRenderer implements BuiltinSimulatorRenderer {
document.body.appendChild(container); document.body.appendChild(container);
container.id = containerId; container.id = containerId;
} }
// ==== compatiable vision // ==== compatiable vision
document.documentElement.classList.add('engine-page'); document.documentElement.classList.add('engine-page');
document.body.classList.add('engine-document'); // important! Stylesheet.invoke depends document.body.classList.add('engine-document'); // important! Stylesheet.invoke depends
@ -294,7 +551,7 @@ export class SimulatorRenderer implements BuiltinSimulatorRenderer {
raxRender(createElement(SimulatorRendererView, { renderer: this }), container, { raxRender(createElement(SimulatorRendererView, { renderer: this }), container, {
driver: DriverUniversal, driver: DriverUniversal,
}); });
host.document.setRendererReady(this); host.project.setRendererReady(this);
} }
} }
@ -350,77 +607,4 @@ function findComponent(libraryMap: LibraryMap, componentName: string, npm?: NpmI
return getSubComponent(library, paths); return getSubComponent(library, paths);
} }
const builtinComponents = { export default new SimulatorRendererContainer();
Slot,
Leaf,
};
function buildComponents(libraryMap: LibraryMap, componentsMap: { [componentName: string]: NpmInfo }) {
const components: any = {
...builtinComponents,
};
Object.keys(componentsMap).forEach((componentName) => {
let component = componentsMap[componentName];
if (isReactComponent(component)) {
components[componentName] = component;
} else {
component = findComponent(libraryMap, componentName, component);
if (component) {
components[componentName] = component;
}
}
});
return components;
}
function getClosestNodeInstance(from: any, specId?: string): NodeInstance<any> | null {
const el: any = from;
if (el) {
// if (isElement(el)) {
// el = cacheReactKey(el);
// } else {
// return getNodeInstance(el, specId);
// }
return getNodeInstance(el);
}
return null;
}
function isValidDesignModeRaxComponentInstance(
raxComponentInst: any,
): raxComponentInst is {
props: {
_leaf: Exclude<NodeInstance<any>['node'], null | undefined>;
};
} {
const leaf = raxComponentInst?.props?._leaf;
return leaf && typeof leaf === 'object' && leaf.isNode;
}
function getNodeInstance(dom: HTMLElement): NodeInstance<any> | null {
const INTERNAL = '_internal';
let instance = Instance.get(dom);
while (instance && instance[INTERNAL]) {
if (isValidDesignModeRaxComponentInstance(instance)) {
return {
nodeId: instance.props._leaf.getId(),
instance: instance,
node: instance.props._leaf,
};
}
instance = instance[INTERNAL].__parentInstance;
}
return null;
}
function checkInstanceMounted(instance: any): boolean {
if (isElement(instance)) {
return instance.parentElement != null;
}
return true;
}
export default new SimulatorRenderer();