TkAstral3D/packages/sdk/lib/core/objects/UIPanelInline.ts
2026-04-08 15:34:43 +08:00

108 lines
3.5 KiB
TypeScript

import * as THREE from "three";
import { Inline } from "@/core/libs/three-mesh-ui/src/three-mesh-ui.js";
import App from "@/core/app/App";
import { findUIPanelRoot } from "@/utils/scene/uipanel";
import {
UIPanelElementController,
UIPanelElementInit,
UIPanelNode,
extractUIPanelProps,
normalizeUIPanelElementOptions,
} from "./UIPanelElementBase";
const InlineBase = Inline as unknown as new (options?: Record<string, any>) => THREE.Object3D;
export default class UIPanelInline extends InlineBase {
type = "UIPanelInline";
isUIPanelElement = true;
options: UIPanelNode;
declare set: (options: Record<string, any>) => void;
private controller: UIPanelElementController;
private handleAdded = () => {
const parent = this.parent as any;
if (!parent || !this.isValidParent(parent)) {
parent?.remove?.(this);
return;
}
const panel = findUIPanelRoot(this) as any;
if (!panel) return;
this.controller.updateRootId(panel.uuid);
panel.registerElement?.(this);
panel.requestUpdate?.();
};
private handleRemoved = () => {
const rootId = (this as any).metadata?.__uiPanelRootId;
const panel = rootId ? App.getObjectByUuid(rootId) : null;
panel?.unregisterElement?.(this);
};
constructor(options: Partial<UIPanelNode> = {}, init: UIPanelElementInit = {}) {
const normalized = normalizeUIPanelElementOptions(options, "inline", "Inline");
const { props } = extractUIPanelProps(normalized);
super(props);
this.options = normalized;
this.name = normalized.name || "Inline";
this.controller = new UIPanelElementController(this, this.options, this.type, init);
this.addEventListener("added", this.handleAdded);
this.addEventListener("removed", this.handleRemoved);
}
updateRootId(rootId: string) {
this.controller.updateRootId(rootId);
}
updateOptions(options: Partial<UIPanelNode>) {
if (options.name !== undefined) {
this.options.name = options.name;
this.name = options.name || this.name;
}
if (options.props) this.setProps(options.props);
if (options.states !== undefined) this.setStates(options.states);
}
setProps(patch: Record<string, any>) {
this.controller.setProps(patch);
}
setStates(states?: Record<string, Record<string, any>>) {
this.controller.setStates(states);
const rootId = (this as any).metadata?.__uiPanelRootId;
const panel = rootId ? App.getObjectByUuid(rootId) : null;
panel?.refreshInteraction?.();
}
applyState(state: string | null) {
this.controller.applyState(state);
}
hasInteractiveState() {
return this.controller.hasInteractiveState();
}
dispose() {
this.controller.dispose();
}
toJSON(meta?: THREE.JSONMeta) {
const snapshot = this.controller.detachInternalMeshes();
const data = super.toJSON(meta) as any;
this.controller.restoreInternalMeshes(snapshot);
data.object.type = this.type;
const options = JSON.parse(JSON.stringify(this.options)) as UIPanelNode;
options.name = this.name;
data.object.options = options;
return data;
}
static fromJSON(json: { options: UIPanelNode }, init: UIPanelElementInit = {}) {
return new UIPanelInline(json.options, init);
}
private isValidParent(parent: any) {
return parent?.type === "UIPanel" || parent?.type === "UIPanelBlock";
}
}