feat: 实现可扩展的字段编辑器系统与专业资产选择器 (#227)
This commit is contained in:
50
packages/editor-core/src/Services/FieldEditorRegistry.ts
Normal file
50
packages/editor-core/src/Services/FieldEditorRegistry.ts
Normal file
@@ -0,0 +1,50 @@
|
||||
import { IService, createLogger } from '@esengine/ecs-framework';
|
||||
import { IFieldEditor, IFieldEditorRegistry, FieldEditorContext } from './IFieldEditor';
|
||||
|
||||
const logger = createLogger('FieldEditorRegistry');
|
||||
|
||||
export class FieldEditorRegistry implements IFieldEditorRegistry, IService {
|
||||
private editors: Map<string, IFieldEditor> = new Map();
|
||||
|
||||
register(editor: IFieldEditor): void {
|
||||
if (this.editors.has(editor.type)) {
|
||||
logger.warn(`Overwriting existing field editor: ${editor.type}`);
|
||||
}
|
||||
|
||||
this.editors.set(editor.type, editor);
|
||||
logger.debug(`Registered field editor: ${editor.name} (${editor.type})`);
|
||||
}
|
||||
|
||||
unregister(type: string): void {
|
||||
if (this.editors.delete(type)) {
|
||||
logger.debug(`Unregistered field editor: ${type}`);
|
||||
}
|
||||
}
|
||||
|
||||
getEditor(type: string, context?: FieldEditorContext): IFieldEditor | undefined {
|
||||
const editor = this.editors.get(type);
|
||||
if (editor) {
|
||||
return editor;
|
||||
}
|
||||
|
||||
const editors = Array.from(this.editors.values())
|
||||
.sort((a, b) => (b.priority || 0) - (a.priority || 0));
|
||||
|
||||
for (const editor of editors) {
|
||||
if (editor.canHandle(type, context)) {
|
||||
return editor;
|
||||
}
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
getAllEditors(): IFieldEditor[] {
|
||||
return Array.from(this.editors.values());
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
this.editors.clear();
|
||||
logger.debug('FieldEditorRegistry disposed');
|
||||
}
|
||||
}
|
||||
45
packages/editor-core/src/Services/IFieldEditor.ts
Normal file
45
packages/editor-core/src/Services/IFieldEditor.ts
Normal file
@@ -0,0 +1,45 @@
|
||||
import { ReactElement } from 'react';
|
||||
|
||||
export interface FieldEditorContext {
|
||||
readonly?: boolean;
|
||||
projectPath?: string;
|
||||
decimalPlaces?: number;
|
||||
metadata?: Record<string, any>;
|
||||
}
|
||||
|
||||
export interface FieldEditorProps<T = any> {
|
||||
label: string;
|
||||
value: T;
|
||||
onChange: (value: T) => void;
|
||||
context: FieldEditorContext;
|
||||
}
|
||||
|
||||
export interface IFieldEditor<T = any> {
|
||||
readonly type: string;
|
||||
readonly name: string;
|
||||
readonly priority?: number;
|
||||
|
||||
canHandle(fieldType: string, context?: FieldEditorContext): boolean;
|
||||
render(props: FieldEditorProps<T>): ReactElement;
|
||||
}
|
||||
|
||||
export interface IFieldEditorRegistry {
|
||||
register(editor: IFieldEditor): void;
|
||||
unregister(type: string): void;
|
||||
getEditor(type: string, context?: FieldEditorContext): IFieldEditor | undefined;
|
||||
getAllEditors(): IFieldEditor[];
|
||||
}
|
||||
|
||||
export interface FieldMetadata {
|
||||
type: string;
|
||||
options?: {
|
||||
fileExtension?: string;
|
||||
enumValues?: Array<{ value: string; label: string }>;
|
||||
min?: number;
|
||||
max?: number;
|
||||
step?: number;
|
||||
language?: string;
|
||||
multiline?: boolean;
|
||||
placeholder?: string;
|
||||
};
|
||||
}
|
||||
@@ -33,6 +33,8 @@ export * from './Services/IInspectorProvider';
|
||||
export * from './Services/InspectorRegistry';
|
||||
export * from './Services/IPropertyRenderer';
|
||||
export * from './Services/PropertyRendererRegistry';
|
||||
export * from './Services/IFieldEditor';
|
||||
export * from './Services/FieldEditorRegistry';
|
||||
|
||||
export * from './Module/IEventBus';
|
||||
export * from './Module/ICommandRegistry';
|
||||
|
||||
Reference in New Issue
Block a user