@dark-engine/platform-desktop
Version:
Dark renderer to desktop platforms like Windows, Linux, macOS via Nodegui and Qt
184 lines (183 loc) • 5.64 kB
JavaScript
import { QWidget } from '@nodegui/nodegui';
import { NodeType, ROOT, detectIsFunction } from '@dark-engine/core';
import { createSetterName, detectIsContainer } from '../utils';
import { createSyntheticEventHandler } from '../events';
import { getElementFactory } from '../registry';
import { TEXT_ATTR } from '../constants';
class NativeElement {
type;
parentElement = null;
constructor(type) {
this.type = type;
}
getText() {
return this.type;
}
}
class TagNativeElement extends NativeElement {
name = null;
attrs = {};
children = [];
nativeView;
eventListeners = new Map();
constructor(name) {
super(NodeType.TAG);
this.name = name;
this.nativeView = getElementFactory(name).create();
}
getNativeView() {
if (this.name === ROOT) {
const tag = this.children[0];
return tag.getNativeView();
}
return this.nativeView;
}
appendChild(element) {
element.parentElement = this;
this.children.push(element);
if (element.type === NodeType.TAG) {
const parent = this.nativeView;
const child = element.getNativeView();
detectIsContainer(parent) && parent.appendChild(child);
} else if (element.type === NodeType.TEXT) {
this.updateText();
}
}
insertBefore(element, siblingElement) {
if (!siblingElement) {
return this.appendChild(element);
}
const idx = this.children.findIndex(node => node === siblingElement);
if (idx === -1) {
return this.appendChild(element);
}
if (element.parentElement) {
element.parentElement.removeChild(element);
}
this.children.splice(idx, 0, element);
element.parentElement = this;
if (element.type === NodeType.TAG) {
const parent = this.nativeView;
const child = element.getNativeView();
const sibling = siblingElement.getNativeView();
const idx = this.children.filter(node => node.type === NodeType.TAG).findIndex(node => node === element);
detectIsContainer(parent) && parent.insertBefore(child, sibling, idx);
} else if (element.type === NodeType.TEXT) {
this.updateText();
}
}
removeChild(element) {
const idx = this.children.findIndex(node => node === element);
if (idx !== -1) {
this.children.splice(idx, 1);
element.parentElement = null;
if (element.type === NodeType.TAG) {
const parent = this.nativeView;
const child = element.getNativeView();
detectIsContainer(parent) && parent.removeChild(child);
} else if (element.type === NodeType.TEXT) {
this.updateText();
}
}
}
getAttribute(name) {
return this.attrs[name];
}
setAttribute(name, value) {
const setterName = createSetterName(name);
defaultAttrSetter(this, name, value);
if (!detectIsFunction(this.nativeView[setterName])) return;
if (!this.nativeView[INITIAL_ATTR_VALUE]) {
this.nativeView[INITIAL_ATTR_VALUE] = {};
}
this.nativeView[INITIAL_ATTR_VALUE][name] = this.nativeView[name];
this.nativeView[setterName](value);
this.attrs[name] = value;
}
removeAttribute(name) {
const setterName = createSetterName(name);
if (!detectIsFunction(this.nativeView[setterName])) return;
const initialValue = this.nativeView[INITIAL_ATTR_VALUE][name];
this.nativeView[setterName](initialValue);
delete this.nativeView[INITIAL_ATTR_VALUE][name];
delete this.attrs[name];
}
updateText() {
let text = '';
for (const child of this.children) {
if (child.type === NodeType.TEXT) {
text += child.value;
}
}
this.setAttribute(TEXT_ATTR, text);
}
getText() {
return this.getAttribute(TEXT_ATTR);
}
addEventListener(eventName, handler) {
const syntheticHandler = createSyntheticEventHandler(eventName, handler);
this.removeEventListener(eventName);
this.eventListeners.set(eventName, syntheticHandler);
this.nativeView.addEventListener(eventName, syntheticHandler);
}
removeEventListener(eventName) {
const handler = this.eventListeners.get(eventName);
this.eventListeners.delete(eventName);
this.nativeView.removeEventListener(eventName, handler);
}
}
class TextNativeElement extends NativeElement {
_value = '';
constructor(text) {
super(NodeType.TEXT);
this._value = text;
}
get value() {
return this._value;
}
set value(value) {
this._value = value;
if (this.parentElement?.type === NodeType.TAG) {
this.parentElement.updateText();
}
}
getText() {
return this._value;
}
}
class CommentNativeElement extends NativeElement {
_value = '';
constructor(text) {
super(NodeType.COMMENT);
this._value = `<!--${text}-->`;
}
get value() {
return this._value;
}
set value(value) {
this._value = value;
}
getText() {
return this._value;
}
}
function createAttrSetter(setter) {
const map = {
id: (w, n) => w.setObjectName(n),
posX: (w, n) => w.move(n, w.y()),
posY: (w, n) => w.move(w.x(), n),
width: (w, n) => w.resize(n, w.height()),
height: (w, n) => w.resize(w.width(), n),
style: (w, n) => w.setInlineStyle(n),
...setter,
};
return (element, name, value) => {
const widget = element.getNativeView();
if (!QWidget.isPrototypeOf(widget) && !(widget instanceof QWidget)) return;
map[name] && map[name](widget, value);
};
}
const defaultAttrSetter = createAttrSetter({});
export const INITIAL_ATTR_VALUE = '_INITIAL_ATTR_VALUE';
export { NativeElement, TagNativeElement, TextNativeElement, CommentNativeElement, createAttrSetter };
//# sourceMappingURL=native-element.js.map