UNPKG

@devextreme/runtime

Version:

DevExtreme virtual DOM common components

122 lines (121 loc) 4.47 kB
import { Component, findDOMfromVNode } from 'inferno'; import { InfernoEffectHost } from './effect_host'; const areObjectsEqual = (firstObject, secondObject) => { const bothAreObjects = firstObject instanceof Object && secondObject instanceof Object; if (!bothAreObjects) { return firstObject === secondObject; } const firstObjectKeys = Object.keys(firstObject); const secondObjectKeys = Object.keys(secondObject); if (firstObjectKeys.length !== secondObjectKeys.length) { return false; } const hasDifferentElement = firstObjectKeys.some((key) => firstObject[key] !== secondObject[key]); return !hasDifferentElement; }; export class BaseInfernoComponent extends Component { constructor() { super(...arguments); this._pendingContext = this.context; } componentWillReceiveProps(_, context) { this._pendingContext = context !== null && context !== void 0 ? context : {}; } shouldComponentUpdate(nextProps, nextState) { return (!areObjectsEqual(this.props, nextProps) || !areObjectsEqual(this.state, nextState) || !areObjectsEqual(this.context, this._pendingContext)); } } export class InfernoComponent extends BaseInfernoComponent { constructor() { super(...arguments); this._effects = []; } createEffects() { return []; } updateEffects() { } componentWillMount() { InfernoEffectHost.lock(); } // eslint-disable-next-line @typescript-eslint/no-unused-vars componentWillUpdate(_nextProps, _nextState, _context) { InfernoEffectHost.lock(); } componentDidMount() { InfernoEffectHost.callbacks.push(() => { this._effects = this.createEffects(); }); InfernoEffectHost.callEffects(); } componentDidUpdate() { InfernoEffectHost.callbacks.push(() => this.updateEffects()); InfernoEffectHost.callEffects(); } destroyEffects() { this._effects.forEach((e) => e.dispose()); } componentWillUnmount() { this.destroyEffects(); } } export class InfernoWrapperComponent extends InfernoComponent { constructor() { super(...arguments); this.vDomElement = null; } vDomUpdateClasses() { const el = this.vDomElement; const currentClasses = el.className.length ? el.className.split(' ') : []; const addedClasses = currentClasses.filter((className) => el.dxClasses.previous.indexOf(className) < 0); const removedClasses = el.dxClasses.previous.filter((className) => currentClasses.indexOf(className) < 0); addedClasses.forEach((value) => { const indexInRemoved = el.dxClasses.removed.indexOf(value); if (indexInRemoved > -1) { el.dxClasses.removed.splice(indexInRemoved, 1); } else if (!el.dxClasses.added.includes(value)) { el.dxClasses.added.push(value); } }); removedClasses.forEach((value) => { const indexInAdded = el.dxClasses.added.indexOf(value); if (indexInAdded > -1) { el.dxClasses.added.splice(indexInAdded, 1); } else if (!el.dxClasses.removed.includes(value)) { el.dxClasses.removed.push(value); } }); } componentDidMount() { const el = findDOMfromVNode(this.$LI, true); this.vDomElement = el; super.componentDidMount(); el.dxClasses = el.dxClasses || { removed: [], added: [], previous: [], }; el.dxClasses.previous = (el === null || el === void 0 ? void 0 : el.className.length) ? el.className.split(' ') : []; } componentDidUpdate() { super.componentDidUpdate(); const el = this.vDomElement; if (el !== null) { el.dxClasses.added.forEach((className) => el.classList.add(className)); el.dxClasses.removed.forEach((className) => el.classList.remove(className)); el.dxClasses.previous = el.className.length ? el.className.split(' ') : []; } } shouldComponentUpdate(nextProps, nextState) { const shouldUpdate = super.shouldComponentUpdate(nextProps, nextState); if (shouldUpdate) { this.vDomUpdateClasses(); } return shouldUpdate; } }