2025-11-21 16:08:24 +01:00
|
|
|
import type { BaseTool } from '@/tools';
|
|
|
|
|
import type { ToolType } from '@/types';
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Tool loader cache
|
|
|
|
|
*/
|
|
|
|
|
const toolCache = new Map<string, BaseTool>();
|
|
|
|
|
const toolLoadingPromises = new Map<string, Promise<BaseTool>>();
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Dynamically import and instantiate a tool
|
2025-11-21 16:11:08 +01:00
|
|
|
* Supports both ToolType and internal tool keys (like 'rectangular-select')
|
2025-11-21 16:08:24 +01:00
|
|
|
*/
|
2025-11-21 16:11:08 +01:00
|
|
|
async function loadTool(toolKey: string): Promise<BaseTool> {
|
2025-11-21 16:08:24 +01:00
|
|
|
// Check cache first
|
2025-11-21 16:11:08 +01:00
|
|
|
if (toolCache.has(toolKey)) {
|
|
|
|
|
return toolCache.get(toolKey)!;
|
2025-11-21 16:08:24 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Check if already loading
|
2025-11-21 16:11:08 +01:00
|
|
|
if (toolLoadingPromises.has(toolKey)) {
|
|
|
|
|
return toolLoadingPromises.get(toolKey)!;
|
2025-11-21 16:08:24 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Start loading
|
|
|
|
|
const loadPromise = (async () => {
|
|
|
|
|
let tool: BaseTool;
|
|
|
|
|
|
2025-11-21 16:11:08 +01:00
|
|
|
switch (toolKey) {
|
2025-11-21 16:08:24 +01:00
|
|
|
case 'pencil': {
|
|
|
|
|
const { PencilTool } = await import('@/tools/pencil-tool');
|
|
|
|
|
tool = new PencilTool();
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case 'brush': {
|
|
|
|
|
const { BrushTool } = await import('@/tools/brush-tool');
|
|
|
|
|
tool = new BrushTool();
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case 'eraser': {
|
|
|
|
|
const { EraserTool } = await import('@/tools/eraser-tool');
|
|
|
|
|
tool = new EraserTool();
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case 'fill': {
|
|
|
|
|
const { FillTool } = await import('@/tools/fill-tool');
|
|
|
|
|
tool = new FillTool();
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case 'eyedropper': {
|
|
|
|
|
const { EyedropperTool } = await import('@/tools/eyedropper-tool');
|
|
|
|
|
tool = new EyedropperTool();
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case 'select':
|
|
|
|
|
case 'rectangular-select': {
|
|
|
|
|
const { RectangularSelectionTool } = await import('@/tools/rectangular-selection-tool');
|
|
|
|
|
tool = new RectangularSelectionTool();
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case 'elliptical-select': {
|
|
|
|
|
const { EllipticalSelectionTool } = await import('@/tools/elliptical-selection-tool');
|
|
|
|
|
tool = new EllipticalSelectionTool();
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case 'lasso-select': {
|
|
|
|
|
const { LassoSelectionTool } = await import('@/tools/lasso-selection-tool');
|
|
|
|
|
tool = new LassoSelectionTool();
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case 'magic-wand': {
|
|
|
|
|
const { MagicWandTool } = await import('@/tools/magic-wand-tool');
|
|
|
|
|
tool = new MagicWandTool();
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case 'move': {
|
|
|
|
|
const { MoveTool } = await import('@/tools/move-tool');
|
|
|
|
|
tool = new MoveTool();
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case 'transform': {
|
|
|
|
|
const { FreeTransformTool } = await import('@/tools/free-transform-tool');
|
|
|
|
|
tool = new FreeTransformTool();
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case 'shape': {
|
|
|
|
|
const { ShapeTool } = await import('@/tools/shape-tool');
|
|
|
|
|
tool = new ShapeTool();
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case 'text': {
|
|
|
|
|
const { TextTool } = await import('@/tools/text-tool');
|
|
|
|
|
tool = new TextTool();
|
|
|
|
|
break;
|
|
|
|
|
}
|
2025-11-21 16:27:02 +01:00
|
|
|
case 'clone': {
|
|
|
|
|
const { CloneStampTool } = await import('@/tools/clone-stamp-tool');
|
|
|
|
|
tool = new CloneStampTool();
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case 'smudge': {
|
|
|
|
|
const { SmudgeTool } = await import('@/tools/smudge-tool');
|
|
|
|
|
tool = new SmudgeTool();
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case 'dodge': {
|
|
|
|
|
const { DodgeBurnTool } = await import('@/tools/dodge-burn-tool');
|
|
|
|
|
tool = new DodgeBurnTool();
|
|
|
|
|
break;
|
|
|
|
|
}
|
2025-11-21 16:08:24 +01:00
|
|
|
default: {
|
|
|
|
|
// Fallback to pencil tool
|
|
|
|
|
const { PencilTool } = await import('@/tools/pencil-tool');
|
|
|
|
|
tool = new PencilTool();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Cache the tool
|
2025-11-21 16:11:08 +01:00
|
|
|
toolCache.set(toolKey, tool);
|
|
|
|
|
toolLoadingPromises.delete(toolKey);
|
2025-11-21 16:08:24 +01:00
|
|
|
|
|
|
|
|
return tool;
|
|
|
|
|
})();
|
|
|
|
|
|
2025-11-21 16:11:08 +01:00
|
|
|
toolLoadingPromises.set(toolKey, loadPromise);
|
2025-11-21 16:08:24 +01:00
|
|
|
return loadPromise;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Get a tool instance (loads it if not cached)
|
2025-11-21 16:11:08 +01:00
|
|
|
* Accepts both ToolType and internal tool keys (e.g., 'rectangular-select')
|
2025-11-21 16:08:24 +01:00
|
|
|
*/
|
2025-11-21 16:11:08 +01:00
|
|
|
export async function getTool(toolKey: ToolType | string): Promise<BaseTool> {
|
|
|
|
|
return loadTool(toolKey);
|
2025-11-21 16:08:24 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Preload a tool (for performance optimization)
|
|
|
|
|
*/
|
2025-11-21 16:11:08 +01:00
|
|
|
export function preloadTool(toolKey: ToolType | string): void {
|
|
|
|
|
loadTool(toolKey).catch((error) => {
|
|
|
|
|
console.error(`Failed to preload tool ${toolKey}:`, error);
|
2025-11-21 16:08:24 +01:00
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Preload commonly used tools
|
|
|
|
|
*/
|
|
|
|
|
export function preloadCommonTools(): void {
|
|
|
|
|
// Preload the most commonly used tools
|
|
|
|
|
preloadTool('pencil');
|
|
|
|
|
preloadTool('brush');
|
|
|
|
|
preloadTool('eraser');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Check if a tool is loaded
|
|
|
|
|
*/
|
2025-11-21 16:11:08 +01:00
|
|
|
export function isToolLoaded(toolKey: ToolType | string): boolean {
|
|
|
|
|
return toolCache.has(toolKey);
|
2025-11-21 16:08:24 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Clear tool cache (for testing)
|
|
|
|
|
*/
|
|
|
|
|
export function clearToolCache(): void {
|
|
|
|
|
toolCache.clear();
|
|
|
|
|
toolLoadingPromises.clear();
|
|
|
|
|
}
|