@pmndrs/uikit
Version:
Build performant 3D user interfaces with Three.js and yoga.
77 lines (76 loc) • 3.24 kB
JavaScript
import { computed, effect, signal, untracked } from '@preact/signals-core';
import { createRootState, setupRoot, DEFAULT_PIXEL_SIZE } from '../components/root.js';
import { Parent, bindHandlers } from './utils.js';
import { readReactive } from '../utils.js';
export class Root extends Parent {
styleSignal = signal(undefined);
propertiesSignal;
defaultPropertiesSignal;
unsubscribe;
onFrameSet = new Set();
fontFamiliesSignal;
pixelSizeSignal;
internals;
constructor(camera, renderer, properties, defaultProperties, fontFamilies, requestRender, requestFrame) {
super();
this.pixelSizeSignal = signal(properties?.pixelSize ?? DEFAULT_PIXEL_SIZE);
this.matrixAutoUpdate = false;
this.fontFamiliesSignal = signal(fontFamilies);
this.propertiesSignal = signal(properties);
this.defaultPropertiesSignal = signal(defaultProperties);
this.unsubscribe = effect(() => {
let getCamera;
if (typeof camera === 'function') {
getCamera = camera;
}
else {
const cam = readReactive(camera);
if (cam == null) {
this.contextSignal.value = undefined;
return;
}
getCamera = () => cam;
}
const abortController = new AbortController();
const objectRef = { current: this };
this.internals = createRootState(objectRef, computed(() => readReactive(this.pixelSizeSignal.value) ?? DEFAULT_PIXEL_SIZE), this.styleSignal, this.propertiesSignal, this.defaultPropertiesSignal, getCamera, renderer, this.onFrameSet, requestRender ?? (() => { }), requestFrame ?? (() => { }));
this.contextSignal.value = Object.assign(this.internals, { fontFamiliesSignal: this.fontFamiliesSignal });
super.add(this.internals.interactionPanel);
setupRoot(this.internals, this.styleSignal, this.propertiesSignal, this, this.childrenContainer, abortController.signal);
bindHandlers(this.internals.handlers, this, abortController.signal);
return () => {
this.onFrameSet.clear();
this.remove(this.internals.interactionPanel);
abortController.abort();
};
});
}
update(delta) {
for (const onFrame of this.onFrameSet) {
onFrame(delta);
}
}
setFontFamilies(fontFamilies) {
this.fontFamiliesSignal.value = fontFamilies;
}
getComputedProperty(key) {
return untracked(() => this.internals.mergedProperties?.value.read(key, undefined));
}
getStyle() {
return this.styleSignal.peek();
}
setStyle(style, replace) {
this.styleSignal.value = replace ? style : { ...this.styleSignal.peek(), ...style };
}
setProperties(properties) {
this.pixelSizeSignal.value = properties?.pixelSize ?? DEFAULT_PIXEL_SIZE;
this.propertiesSignal.value = properties;
}
setDefaultProperties(properties) {
this.defaultPropertiesSignal.value = properties;
}
destroy() {
this.parent?.remove(this);
this.unsubscribe();
}
}