UNPKG

@dark-engine/core

Version:

The lightweight and powerful UI rendering engine without dependencies and written in TypeScript (Browser, Node.js, Android, iOS, Windows, Linux, macOS)

321 lines (320 loc) 7.21 kB
import { platform, detectIsServer } from '../platform'; import { Reconciler } from '../reconciler'; import { EventEmitter } from '../emitter'; import { Awaiter } from '../awaiter'; class Scope { root = null; wip = null; cursor = null; unit = null; mDeep = true; mLevel = 0; mNav = new Map(); events = new Map(); offs = new Set(); reconciler = new Reconciler(); candidates = new Set(); deletions = new Set(); cancels = []; asyncEffects = new Set(); layoutEffects = new Set(); insertionEffects = new Set(); resId = 0; resources = new Map(); awaiter = new Awaiter(); onTransitionEnd = null; isLayoutEffect = false; isInsertionEffect = false; isUpdate = false; isBatch = false; isForce = false; isHydration = false; isStream = false; isTransition = false; isEvent = false; isHot = false; isDynamic = platform.detectIsDynamic(); isServer = detectIsServer(); emitter = new EventEmitter(); fork() { const scope = new Scope(); scope.root = null; scope.wip = null; scope.cursor = null; scope.unit = this.unit; scope.mDeep = this.mDeep; scope.mLevel = this.mLevel; scope.mNav = new Map(this.mNav); scope.events = this.events; scope.offs = this.offs; scope.reconciler = this.reconciler.fork(); scope.candidates = new Set([...this.candidates]); scope.deletions = new Set([...this.deletions]); scope.asyncEffects = new Set([...this.asyncEffects]); scope.layoutEffects = new Set([...this.layoutEffects]); scope.isUpdate = this.isUpdate; scope.emitter = this.emitter; scope.awaiter = this.awaiter; return scope; } getRoot() { return this.root; } setRoot(fiber) { this.root = fiber; } keepRoot() { !this.isUpdate && this.setRoot(this.wip); } getWorkInProgress() { return this.wip; } setWorkInProgress(fiber) { this.wip = fiber; } getNextUnitOfWork() { return this.unit; } setUnitOfWork(fiber) { this.unit = fiber; } getCursor() { return this.cursor; } setCursor(fiber) { this.cursor = fiber; } navToChild() { this.mLevel = this.mLevel + 1; this.mNav.set(this.mLevel, 0); } navToSibling() { this.mNav.set(this.mLevel, this.mNav.get(this.mLevel) + 1); } navToParent() { this.mLevel = this.mLevel - 1; } navToPrev() { const idx = this.getMountIndex(); if (idx === 0) { this.navToParent(); this.setMountDeep(true); } else { this.mNav.set(this.mLevel, this.mNav.get(this.mLevel) - 1); this.setMountDeep(false); } } getMountIndex() { return this.mNav.get(this.mLevel); } getMountDeep() { return this.mDeep; } setMountDeep(value) { this.mDeep = value; } resetMount() { this.mLevel = 0; this.mNav = new Map(); this.mDeep = true; } getEvents() { return this.events; } addOff(fn) { this.offs.add(fn); } off() { this.offs.forEach(x => x()); this.offs = new Set(); } getCandidates() { return this.candidates; } addCandidate(fiber) { this.candidates.add(fiber); } resetCandidates() { this.candidates = new Set(); } getDeletions() { return this.deletions; } hasDeletion(fiber) { let nextFiber = fiber; while (nextFiber) { if (this.deletions.has(nextFiber)) return true; nextFiber = nextFiber.parent; } return false; } addDeletion(fiber) { !this.hasDeletion(fiber) && this.deletions.add(fiber); } resetDeletions() { this.deletions = new Set(); } addAsyncEffect(fn) { this.asyncEffects.add(fn); } resetAsyncEffects() { this.asyncEffects = new Set(); } runAsyncEffects() { if (!this.isDynamic) return; const effects = this.asyncEffects; effects.size > 0 && setTimeout(() => effects.forEach(fn => fn())); } addLayoutEffect(fn) { this.layoutEffects.add(fn); } resetLayoutEffects() { this.layoutEffects = new Set(); } runLayoutEffects() { if (!this.isDynamic) return; this.setIsLayoutEffect(true); this.layoutEffects.forEach(fn => fn()); this.setIsLayoutEffect(false); } addInsertionEffect(fn) { this.insertionEffects.add(fn); } resetInsertionEffects() { this.insertionEffects = new Set(); } runInsertionEffects() { if (!this.isDynamic) return; this.setIsInsertionEffect(true); this.insertionEffects.forEach(fn => fn()); this.setIsInsertionEffect(false); } addCancel(fn) { this.cancels.push(fn); } applyCancels() { for (let i = this.cancels.length - 1; i >= 0; i--) { this.cancels[i](); } } resetCancels() { this.cancels = []; } getIsLayoutEffect() { return this.isLayoutEffect; } setIsLayoutEffect(value) { this.isLayoutEffect = value; } getIsInsertionEffect() { return this.isInsertionEffect; } setIsInsertionEffect(value) { this.isInsertionEffect = value; } getIsUpdate() { return this.isUpdate; } setIsUpdate(value) { this.isUpdate = value; } getIsBatch() { return this.isBatch; } setIsBatch(value) { this.isBatch = value; } getIsHydration() { return this.isHydration; } setIsHydration(value) { this.isHydration = value; } getIsStream() { return this.isStream; } setIsStream(value) { this.isStream = value; } getIsTransition() { return this.isTransition; } setIsTransition(value) { this.isTransition = value; } getIsEvent() { return this.isEvent; } setIsEvent(value, isForce = false) { this.isEvent = value; this.isForce = isForce; } getIsForce() { return this.isForce; } getIsHot() { return this.isHot; } setIsHot(value) { this.isHot = value; } getOnTransitionEnd() { return this.onTransitionEnd; } setOnTransitionEnd(fn) { this.onTransitionEnd = fn; } getReconciler() { return this.reconciler; } cleanup() { this.keepRoot(); this.setWorkInProgress(null); this.setUnitOfWork(null); this.setCursor(null); this.resetMount(); this.resetCandidates(); this.resetDeletions(); this.resetCancels(); this.resetInsertionEffects(); this.resetLayoutEffects(); this.resetAsyncEffects(); this.setIsHydration(false); this.setIsUpdate(false); this.reconciler.reset(); } getEmitter() { return this.emitter; } getResource(id) { return this.resources.get(id); } setResource(id, res) { this.resources.set(id, res); } getResources() { return this.resources; } getNextResourceId() { return ++this.resId; } getAwaiter() { return this.awaiter; } runAfterCommit() { this.resources = new Map(); this.isServer && (this.resId = 0); } } let rootId = null; const scopes = new Map(); const getRootId = () => rootId; const setRootId = id => { rootId = id; !scopes.has(rootId) && scopes.set(rootId, new Scope()); }; const removeScope = id => scopes.delete(id); const replaceScope = (scope, id = rootId) => Object.assign(scopes.get(id), scope); const $$scope = (id = rootId) => scopes.get(id); export { getRootId, setRootId, removeScope, replaceScope, $$scope }; //# sourceMappingURL=scope.js.map