UNPKG

@dark-engine/platform-desktop

Version:

Dark renderer to desktop platforms like Windows, Linux, macOS via Nodegui and Qt

177 lines (176 loc) 5.82 kB
import { REF_ATTR, ATTR_BLACK_LIST, CREATE_EFFECT_TAG, UPDATE_EFFECT_TAG, DELETE_EFFECT_TAG, MOVE_MASK, detectIsUndefined, detectIsObject, NodeType, detectIsTagVirtualNode, detectIsPlainVirtualNode, getFiberWithElement, collectElements, walk, applyRef as $applyRef, } from '@dark-engine/core'; import { TagNativeElement, TextNativeElement, CommentNativeElement } from '../native-element'; import { detectIsEvent } from '../events'; import { HIDDEN_ATTR } from '../constants'; let moves = []; let callbacks = []; function createNativeElement(vNode) { switch (vNode.type) { case NodeType.TAG: return new TagNativeElement(vNode.name); case NodeType.TEXT: return new TextNativeElement(vNode.value); case NodeType.COMMENT: return new CommentNativeElement(vNode.value); } } function applyRef(ref, element) { $applyRef(ref, element.getNativeView()); } function addAttributes(element, vNode) { const tagElement = element; for (const attrName in vNode.attrs) { const attrValue = vNode.attrs[attrName]; if (attrName === REF_ATTR) { applyRef(attrValue, tagElement); continue; } if (detectIsEvent(attrName)) { attrValue && detectIsObject(attrValue) && addEvents(tagElement, attrValue); } else if (!detectIsUndefined(attrValue) && !ATTR_BLACK_LIST[attrName]) { tagElement.setAttribute(attrName, attrValue); } } } function updateAttributes(element, prevVNode, nextVNode) { const attrNames = getAttributeNames(prevVNode, nextVNode); const tagElement = element; for (const attrName of attrNames) { const prevAttrValue = prevVNode.attrs[attrName]; const nextAttrValue = nextVNode.attrs[attrName]; if (attrName === REF_ATTR) { applyRef(prevAttrValue, tagElement); continue; } if (!detectIsUndefined(nextAttrValue)) { if (detectIsEvent(attrName)) { nextAttrValue && detectIsObject(nextAttrValue) && prevAttrValue !== nextAttrValue && addEvents(tagElement, nextAttrValue); } else if (!ATTR_BLACK_LIST[attrName] && prevAttrValue !== nextAttrValue) { tagElement.setAttribute(attrName, nextAttrValue); } } else { if (detectIsEvent(attrName)) { prevAttrValue && detectIsObject(prevAttrValue) && removeEvents(tagElement, prevAttrValue); } else { tagElement.removeAttribute(attrName); } } } } function addEvents(tagElement, value) { for (const key in value) { tagElement.addEventListener(key, value[key]); } } function removeEvents(tagElement, value) { for (const key in value) { tagElement.removeEventListener(key); } } function commitCreation(fiber) { const parent = getFiberWithElement(fiber.parent); const parentElement = parent.el; const children = parentElement.children; if (children.length === 0 || fiber.eidx > children.length - 1) { appendNativeElement(fiber.el, parentElement); } else { insertNativeElement(fiber.el, parentElement.children[fiber.eidx], parentElement); } detectIsTagVirtualNode(fiber.inst) && addAttributes(fiber.el, fiber.inst); } function commitUpdate(fiber) { const element = fiber.el; const prevInst = fiber.alt.inst; const nextInst = fiber.inst; detectIsPlainVirtualNode(nextInst) ? prevInst.value !== nextInst.value && (element.value = nextInst.value) : updateAttributes(element, prevInst, nextInst); } function commitDeletion(fiber) { const parent = getFiberWithElement(fiber.parent); walk(fiber, onWalkInCommitDeletion(parent.el)); } const onWalkInCommitDeletion = parentElement => (fiber, skip) => { if (fiber.el) { removeNativeElement(fiber.el, parentElement); return skip(); } }; function move(fiber) { const sourceNodes = collectElements(fiber, x => x.el); const sourceNode = sourceNodes[0]; const parentElement = sourceNode.parentElement; const elementIdx = fiber.eidx; const move = () => { for (let i = 0; i < sourceNodes.length; i++) { insertNativeElement(sourceNodes[i], parentElement.children[elementIdx + i], parentElement); removeNativeElement(parentElement.children[elementIdx + i + 1], parentElement); } }; for (let i = 0; i < sourceNodes.length; i++) { const node = sourceNodes[i]; insertNativeElement(new CommentNativeElement(`${elementIdx}:${i}`), node, parentElement); removeNativeElement(node, parentElement); } moves.push(move); } function getAttributeNames(prevVNode, nextVNode) { const attrNames = new Set(); const prevAttrs = Object.keys(prevVNode.attrs); const nextAttrs = Object.keys(nextVNode.attrs); const size = Math.max(prevAttrs.length, nextAttrs.length); for (let i = 0; i < size; i++) { attrNames.add(prevAttrs[i] || nextAttrs[i]); } return attrNames; } function commit(fiber) { switch (fiber.tag) { case CREATE_EFFECT_TAG: fiber.el && commitCreation(fiber); break; case UPDATE_EFFECT_TAG: fiber.mask & MOVE_MASK && (move(fiber), (fiber.mask &= ~MOVE_MASK)); fiber.el && commitUpdate(fiber); break; case DELETE_EFFECT_TAG: commitDeletion(fiber); break; default: break; } } function finishCommit() { callbacks.forEach(x => x()); moves.forEach(x => x()); callbacks = []; moves = []; } function runAtTheEndOfCommit(cb) { callbacks.push(cb); } const appendNativeElement = (element, parent) => parent.appendChild(element); const insertNativeElement = (element, sibling, parent) => parent.insertBefore(element, sibling); const removeNativeElement = (element, parent) => parent.removeChild(element); const toggle = (element, isVisible) => element.setAttribute(HIDDEN_ATTR, isVisible); export { createNativeElement, commit, finishCommit, runAtTheEndOfCommit, toggle }; //# sourceMappingURL=dom.js.map