UNPKG

@gravity-ui/graph

Version:

Modern graph editor component

197 lines (196 loc) 6.6 kB
/* 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(); } }