refactor(editor-app): 改进架构和类型安全 (#226)
* refactor(editor-app): 改进架构和类型安全 * refactor(editor-app): 开始拆分 Inspector.tsx - 创建基础架构 * refactor(editor-app): 完成 Inspector.tsx 拆分 * refactor(editor-app): 优化 Inspector 类型定义,消除所有 any 使用 * refactor(editor): 实现可扩展的属性渲染器系统 * Potential fix for code scanning alert no. 231: Unused variable, import, function or class Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com> * fix(ci): 防止 Codecov 服务故障阻塞 CI 流程 --------- Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
This commit is contained in:
30
packages/editor-core/src/Services/IPropertyRenderer.ts
Normal file
30
packages/editor-core/src/Services/IPropertyRenderer.ts
Normal file
@@ -0,0 +1,30 @@
|
||||
import { ReactElement } from 'react';
|
||||
|
||||
export interface PropertyContext {
|
||||
readonly name: string;
|
||||
readonly path?: string[];
|
||||
readonly depth?: number;
|
||||
readonly readonly?: boolean;
|
||||
readonly decimalPlaces?: number;
|
||||
readonly expandByDefault?: boolean;
|
||||
readonly parentObject?: any;
|
||||
readonly metadata?: Record<string, any>;
|
||||
}
|
||||
|
||||
export interface IPropertyRenderer<T = any> {
|
||||
readonly id: string;
|
||||
readonly name: string;
|
||||
readonly priority?: number;
|
||||
|
||||
canHandle(value: any, context: PropertyContext): value is T;
|
||||
render(value: T, context: PropertyContext): ReactElement;
|
||||
}
|
||||
|
||||
export interface IPropertyRendererRegistry {
|
||||
register(renderer: IPropertyRenderer): void;
|
||||
unregister(rendererId: string): void;
|
||||
findRenderer(value: any, context: PropertyContext): IPropertyRenderer | undefined;
|
||||
render(value: any, context: PropertyContext): ReactElement | null;
|
||||
getAllRenderers(): IPropertyRenderer[];
|
||||
hasRenderer(value: any, context: PropertyContext): boolean;
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
import React from 'react';
|
||||
import { IService, createLogger } from '@esengine/ecs-framework';
|
||||
import { IPropertyRenderer, IPropertyRendererRegistry, PropertyContext } from './IPropertyRenderer';
|
||||
|
||||
const logger = createLogger('PropertyRendererRegistry');
|
||||
|
||||
export class PropertyRendererRegistry implements IPropertyRendererRegistry, IService {
|
||||
private renderers: Map<string, IPropertyRenderer> = new Map();
|
||||
|
||||
register(renderer: IPropertyRenderer): void {
|
||||
if (this.renderers.has(renderer.id)) {
|
||||
logger.warn(`Overwriting existing property renderer: ${renderer.id}`);
|
||||
}
|
||||
|
||||
this.renderers.set(renderer.id, renderer);
|
||||
logger.debug(`Registered property renderer: ${renderer.name} (${renderer.id})`);
|
||||
}
|
||||
|
||||
unregister(rendererId: string): void {
|
||||
if (this.renderers.delete(rendererId)) {
|
||||
logger.debug(`Unregistered property renderer: ${rendererId}`);
|
||||
}
|
||||
}
|
||||
|
||||
findRenderer(value: any, context: PropertyContext): IPropertyRenderer | undefined {
|
||||
const renderers = Array.from(this.renderers.values())
|
||||
.sort((a, b) => (b.priority || 0) - (a.priority || 0));
|
||||
|
||||
for (const renderer of renderers) {
|
||||
try {
|
||||
if (renderer.canHandle(value, context)) {
|
||||
return renderer;
|
||||
}
|
||||
} catch (error) {
|
||||
logger.error(`Error in canHandle for renderer ${renderer.id}:`, error);
|
||||
}
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
render(value: any, context: PropertyContext): React.ReactElement | null {
|
||||
const renderer = this.findRenderer(value, context);
|
||||
|
||||
if (!renderer) {
|
||||
logger.debug(`No renderer found for value type: ${typeof value}`);
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
return renderer.render(value, context);
|
||||
} catch (error) {
|
||||
logger.error(`Error rendering with ${renderer.id}:`, error);
|
||||
return React.createElement(
|
||||
'span',
|
||||
{ style: { color: '#f87171', fontStyle: 'italic' } },
|
||||
'[Render Error]'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
getAllRenderers(): IPropertyRenderer[] {
|
||||
return Array.from(this.renderers.values());
|
||||
}
|
||||
|
||||
hasRenderer(value: any, context: PropertyContext): boolean {
|
||||
return this.findRenderer(value, context) !== undefined;
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
this.renderers.clear();
|
||||
logger.debug('PropertyRendererRegistry disposed');
|
||||
}
|
||||
}
|
||||
@@ -31,6 +31,8 @@ export * from './Services/IDialog';
|
||||
export * from './Services/INotification';
|
||||
export * from './Services/IInspectorProvider';
|
||||
export * from './Services/InspectorRegistry';
|
||||
export * from './Services/IPropertyRenderer';
|
||||
export * from './Services/PropertyRendererRegistry';
|
||||
|
||||
export * from './Module/IEventBus';
|
||||
export * from './Module/ICommandRegistry';
|
||||
|
||||
Reference in New Issue
Block a user