@gravity-ui/graph
Version:
Modern graph editor component
197 lines (196 loc) • 6.6 kB
JavaScript
/* eslint-disable complexity */
import { Scheduler } from "./Scheduler";
import { Tree } from "./Tree";
function createDefaultPrivateContext() {
return {
scheduler: new Scheduler(),
globalIterateId: 0,
};
}
export class CoreComponent {
get zIndex() {
return this.__comp.treeNode.zIndex;
}
set zIndex(index) {
this.__comp.treeNode.updateZIndex(index);
this.performRender();
}
get renderOrder() {
return this.__comp.treeNode.renderOrder;
}
constructor(props, parent) {
this.$ = {};
this.context = {};
this.props = {};
this.performRender = () => {
this.__comp.context.scheduler.scheduleUpdate();
};
this.context = parent?.context || {};
this.__comp = {
parent,
context: parent ? parent.__comp.context : createDefaultPrivateContext(),
treeNode: new Tree(this),
children: {},
childrenKeys: [],
prevChildrenArr: [],
updated: false,
iterateId: 0,
};
this.props = props;
}
isIterated() {
return this.__comp.iterateId === this.__comp.context.globalIterateId;
}
getParent() {
return this.__comp.parent;
}
setContext(context) {
Object.assign(this.context, context);
this.performRender();
}
unmount() {
// noop
}
render() {
// noop
}
updateChildren() {
// noop
}
setProps(_) {
// noop
}
__unmount() {
this.__unmountChildren();
this.unmount();
this.performRender();
}
iterate() {
if (!this.__comp.parent) {
this.__comp.context.globalIterateId = Math.random();
}
this.__comp.iterateId = this.__comp.context.globalIterateId;
return true;
}
__updateChildren() {
const nextChildrenArr = this.updateChildren();
if (typeof nextChildrenArr === "undefined")
return;
const __comp = this.__comp;
const children = __comp.children;
const childrenKeys = __comp.childrenKeys;
const nextChildrenKeys = (__comp.childrenKeys = []);
if (nextChildrenArr === __comp.prevChildrenArr)
return;
let key;
let ref;
let child;
let currentChild;
const treeNode = __comp.treeNode;
__comp.prevChildrenArr = nextChildrenArr;
treeNode.clearChildren();
if (nextChildrenArr.length === 0) {
if (childrenKeys.length > 0) {
for (let i = 0; i < childrenKeys.length; i += 1) {
key = childrenKeys[i];
child = children[key];
child.__unmount();
children[key] = undefined;
}
}
return;
}
if (childrenKeys.length === 0) {
if (nextChildrenArr.length > 0) {
for (let i = 0; i < nextChildrenArr.length; i += 1) {
child = nextChildrenArr[i];
// eslint-disable-next-line no-prototype-builtins
key = child.options.hasOwnProperty("key") ? child.options.key : `${child.klass.name}|${i}|defaultKey`;
ref = child.options.ref;
// eslint-disable-next-line new-cap
children[key] = new child.klass(child.props, this);
if (typeof ref === "function") {
ref(children[key]);
}
else if (typeof ref === "string") {
this.$[ref] = children[key];
}
nextChildrenKeys.push(key);
treeNode.append(children[key].__comp.treeNode);
}
}
return;
}
const childForMount = [];
const keyForMount = [];
for (let i = 0; i < nextChildrenArr.length; i += 1) {
child = nextChildrenArr[i];
// eslint-disable-next-line no-prototype-builtins
key = child.options.hasOwnProperty("key") ? child.options.key : `${child.klass.name}|${i}|defaultKey`;
currentChild = children[key];
nextChildrenKeys.push(key);
if (currentChild !== undefined &&
currentChild instanceof child.klass &&
currentChild.constructor === child.klass) {
currentChild.setProps(child.props);
currentChild.__comp.updated = true;
}
else {
childForMount.push(child);
keyForMount.push(key);
}
}
for (let i = 0; i < childrenKeys.length; i += 1) {
key = childrenKeys[i];
child = children[key];
if (child === undefined)
continue;
if (child.__comp.updated === true) {
child.__comp.updated = false;
}
else {
child.__unmount();
children[key] = undefined;
}
}
for (let i = 0; i < childForMount.length; i += 1) {
child = childForMount[i];
key = keyForMount[i];
ref = child.options.ref;
// eslint-disable-next-line new-cap
child = children[key] = new child.klass(child.props, this);
if (typeof ref === "function") {
ref(children[key]);
}
else if (typeof ref === "string") {
this.$[ref] = children[key];
}
}
for (let i = 0; i < nextChildrenKeys.length; i += 1) {
if ((child = children[nextChildrenKeys[i]]) !== undefined) {
treeNode.append(child.__comp.treeNode);
}
}
}
__unmountChildren() {
this.__comp.treeNode.clearChildren();
const children = this.__comp.children;
const childrenKeys = this.__comp.childrenKeys;
for (let i = 0; i < childrenKeys.length; i += 1) {
children[childrenKeys[i]].__unmount();
}
}
static create(props = {}, options = {}) {
return { props, options, klass: this };
}
static mount(Component, props) {
const root = new Component(props);
const scheduler = root.__comp.context.scheduler;
scheduler.setRoot(root.__comp.treeNode);
scheduler.scheduleUpdate();
return root;
}
static unmount(instance) {
instance.__unmount();
}
}