Files
ttstd-infinite-canvas/web/src/lib/canvas/node-registry/node-registry.ts

113 lines
3.9 KiB
TypeScript

import type { CanvasNodeData, CanvasNodeTypeId } from "@/types/canvas";
import type { PluginCanvasNodeContribution } from "@/lib/plugins/plugin-types";
import { canvasNodeDefinitionFromPlugin, type CanvasNodeDefinition } from "./node-definition";
/** 模块级注册表 */
const definitions = new Map<CanvasNodeTypeId, CanvasNodeDefinition>();
/** 节点类型 → 归属方。内置节点归属 "builtin",为后续扩展留出隔离位。 */
const ownerByType = new Map<CanvasNodeTypeId, string>();
/** 未注册类型的兜底最小尺寸——与非媒体节点的历史下限一致 */
const FALLBACK_MIN_SIZE = { width: 220, height: 160 } as const;
/** 批量注册节点定义 */
export function registerNodeDefinitions(defs: CanvasNodeDefinition[], ownerId = "builtin") {
for (const def of defs) {
definitions.set(def.type, def);
ownerByType.set(def.type, ownerId);
}
}
/** Registers schema-driven canvas nodes from the unified plugin manifest. */
export function registerPluginCanvasNodes(pluginId: string, nodes: PluginCanvasNodeContribution[]) {
registerNodeDefinitions(nodes.map((node) => canvasNodeDefinitionFromPlugin(pluginId, node)), pluginId);
}
/**
* 注销某归属方的全部节点定义。
* 只删归属该 ownerId 的条目——内置节点不会被其他归属方的增删波及。
*/
export function unregisterNodeDefinitions(ownerId: string) {
for (const [type, owner] of ownerByType) {
if (owner !== ownerId) continue;
definitions.delete(type);
ownerByType.delete(type);
}
}
export function getNodeDefinition(type: CanvasNodeTypeId) {
return definitions.get(type);
}
export function getNodeOwnerId(type: CanvasNodeTypeId) {
return ownerByType.get(type) || "builtin";
}
export function listNodeDefinitions() {
return [...definitions.values()];
}
/** 添加节点菜单可见的节点定义 */
export function listCreatableNodeDefinitions() {
return listNodeDefinitions().filter((def) => def.showInCreateMenu);
}
/** UI 短标签 */
export function getNodeLabel(type: CanvasNodeTypeId) {
return definitions.get(type)?.label || "未知节点";
}
/** 列表/搜索标签,缺省派生自 label */
export function getNodeListLabel(type: CanvasNodeTypeId) {
const def = definitions.get(type);
if (!def) return "未知节点";
return def.listLabel || `${def.label}节点`;
}
export function getNodeIcon(type: CanvasNodeTypeId) {
return definitions.get(type)?.icon ?? null;
}
/** 手动拉伸的最小尺寸 */
export function getNodeMinSize(type: CanvasNodeTypeId) {
return definitions.get(type)?.minSize ?? FALLBACK_MIN_SIZE;
}
/** 拉伸时是否锁定宽高比 */
export function shouldKeepAspectRatio(node: CanvasNodeData) {
return definitions.get(node.type)?.keepAspectRatio?.(node) ?? false;
}
/**
* 该节点作为 @ 引用素材时的类型,非素材返回 null。
* 只按类型判定——角色卡那类跨类型覆盖由调用方在此之前处理。
*/
export function getNodeResourceKind(node: CanvasNodeData) {
return definitions.get(node.type)?.resourceKind?.(node) ?? null;
}
/** 该节点作为生成节点时的生成模式,不产生生成行为返回 null */
export function getNodeGenerationMode(node: CanvasNodeData) {
return definitions.get(node.type)?.generationMode?.(node) ?? null;
}
/** 该节点作为上游输入被计数时的类别,不参与计数返回 undefined */
export function getNodeInputKind(type: CanvasNodeTypeId) {
return definitions.get(type)?.inputKind;
}
export function getNodeAcceptedInputKind(type: CanvasNodeTypeId) {
return definitions.get(type)?.acceptsInputKind;
}
export function getNodeAcceptedInputKinds(type: CanvasNodeTypeId) {
const accepted = definitions.get(type)?.acceptsInputKind;
if (!accepted) return [];
return Array.isArray(accepted) ? accepted : [accepted];
}
export function getNodeMaxInputCount(type: CanvasNodeTypeId) {
return definitions.get(type)?.maxInputCount;
}