Files
paint-ui/lib/tool-loader.ts
Sebastian Krüger 2e18f43453 feat(ui/perf): implement loading states, keyboard navigation, and lazy-loaded tools
Add comprehensive UX and performance improvements:

**Loading States & Feedback:**
- Add loading overlay with spinner and custom messages
- Integrate loading states into all file operations (open, save, export)
- Create loading-store.ts for centralized loading state management

**Keyboard Navigation:**
- Expand keyboard shortcuts to include tool selection (1-7)
- Add layer navigation with Arrow Up/Down
- Add layer operations (Ctrl+D duplicate, Delete/Backspace remove)
- Display keyboard shortcuts in tool tooltips
- Enhanced keyboard shortcut system with proper key conflict handling

**Performance - Code Splitting:**
- Implement dynamic tool loader with lazy loading
- Tools load on-demand when first selected
- Preload common tools (pencil, brush, eraser) for instant access
- Add tool caching to prevent redundant loads
- Reduces initial bundle size and improves startup time

**Integration:**
- Add LoadingOverlay to app layout
- Update canvas-with-tools to use lazy-loaded tool instances
- Add keyboard shortcut hints to tool palette UI

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-21 16:08:24 +01:00

153 lines
3.9 KiB
TypeScript

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
*/
async function loadTool(toolType: ToolType): Promise<BaseTool> {
// Check cache first
if (toolCache.has(toolType)) {
return toolCache.get(toolType)!;
}
// Check if already loading
if (toolLoadingPromises.has(toolType)) {
return toolLoadingPromises.get(toolType)!;
}
// Start loading
const loadPromise = (async () => {
let tool: BaseTool;
switch (toolType) {
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;
}
default: {
// Fallback to pencil tool
const { PencilTool } = await import('@/tools/pencil-tool');
tool = new PencilTool();
}
}
// Cache the tool
toolCache.set(toolType, tool);
toolLoadingPromises.delete(toolType);
return tool;
})();
toolLoadingPromises.set(toolType, loadPromise);
return loadPromise;
}
/**
* Get a tool instance (loads it if not cached)
*/
export async function getTool(toolType: ToolType): Promise<BaseTool> {
return loadTool(toolType);
}
/**
* Preload a tool (for performance optimization)
*/
export function preloadTool(toolType: ToolType): void {
loadTool(toolType).catch((error) => {
console.error(`Failed to preload tool ${toolType}:`, error);
});
}
/**
* 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
*/
export function isToolLoaded(toolType: ToolType): boolean {
return toolCache.has(toolType);
}
/**
* Clear tool cache (for testing)
*/
export function clearToolCache(): void {
toolCache.clear();
toolLoadingPromises.clear();
}