Files
paint-ui/store/text-store.ts

214 lines
6.2 KiB
TypeScript
Raw Normal View History

feat: implement comprehensive text tool (Phase 11) Add complete text rendering system with the following features: **Text Tool Core:** - TextTool class with click-to-place text functionality - Text cursor and pointer event handling - Integration with DrawCommand for undo/redo support **Text Rendering:** - Multi-line text support with line height control - Custom letter spacing - Text alignment (left/center/right) - Font families: 13 web-safe fonts + 14 popular Google Fonts - Dynamic Google Font loading via Web Font Loader API - Font styles (normal/italic) and weights (100-900) **Text Dialog UI:** - Full-featured text editor dialog - Live preview of text with all formatting - Font family selection (web-safe + Google Fonts) - Font size (8-500px), style, and weight controls - Color picker with hex input - Text alignment options - Line height slider (0.5-3x) - Letter spacing slider (-10 to 50px) - Multi-line text input with textarea **State Management:** - text-store with Zustand + persist middleware - All text settings preserved across sessions - Dialog state management (open/close) - Click position tracking **Integration:** - Added text tool to tool palette with Type icon - Registered TextTool in canvas tool system - Added TextDialog to editor layout - Full type safety with TypeScript interfaces **Undoable:** - Text rendering fully integrated with command pattern - Each text insertion creates single undo point - Proper before/after state capture This completes Phase 11 of the implementation plan, marking the transition from MVP to a fully-featured image editor. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-21 09:45:05 +01:00
import { create } from 'zustand';
import { persist } from 'zustand/middleware';
import type { TextSettings, TextStore as ITextStore } from '@/types/text';
const DEFAULT_SETTINGS: TextSettings = {
text: '',
fontFamily: 'Arial',
fontSize: 48,
fontStyle: 'normal',
fontWeight: 'normal',
color: '#000000',
align: 'left',
baseline: 'alphabetic',
lineHeight: 1.2,
letterSpacing: 0,
};
export const useTextStore = create<ITextStore>()(
persist(
(set, get) => ({
feat: implement comprehensive text tool (Phase 11) Add complete text rendering system with the following features: **Text Tool Core:** - TextTool class with click-to-place text functionality - Text cursor and pointer event handling - Integration with DrawCommand for undo/redo support **Text Rendering:** - Multi-line text support with line height control - Custom letter spacing - Text alignment (left/center/right) - Font families: 13 web-safe fonts + 14 popular Google Fonts - Dynamic Google Font loading via Web Font Loader API - Font styles (normal/italic) and weights (100-900) **Text Dialog UI:** - Full-featured text editor dialog - Live preview of text with all formatting - Font family selection (web-safe + Google Fonts) - Font size (8-500px), style, and weight controls - Color picker with hex input - Text alignment options - Line height slider (0.5-3x) - Letter spacing slider (-10 to 50px) - Multi-line text input with textarea **State Management:** - text-store with Zustand + persist middleware - All text settings preserved across sessions - Dialog state management (open/close) - Click position tracking **Integration:** - Added text tool to tool palette with Type icon - Registered TextTool in canvas tool system - Added TextDialog to editor layout - Full type safety with TypeScript interfaces **Undoable:** - Text rendering fully integrated with command pattern - Each text insertion creates single undo point - Proper before/after state capture This completes Phase 11 of the implementation plan, marking the transition from MVP to a fully-featured image editor. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-21 09:45:05 +01:00
settings: { ...DEFAULT_SETTINGS },
textObjects: [],
isOnCanvasEditorActive: false,
editorPosition: null,
editorText: '',
editingTextId: null,
feat: implement comprehensive text tool (Phase 11) Add complete text rendering system with the following features: **Text Tool Core:** - TextTool class with click-to-place text functionality - Text cursor and pointer event handling - Integration with DrawCommand for undo/redo support **Text Rendering:** - Multi-line text support with line height control - Custom letter spacing - Text alignment (left/center/right) - Font families: 13 web-safe fonts + 14 popular Google Fonts - Dynamic Google Font loading via Web Font Loader API - Font styles (normal/italic) and weights (100-900) **Text Dialog UI:** - Full-featured text editor dialog - Live preview of text with all formatting - Font family selection (web-safe + Google Fonts) - Font size (8-500px), style, and weight controls - Color picker with hex input - Text alignment options - Line height slider (0.5-3x) - Letter spacing slider (-10 to 50px) - Multi-line text input with textarea **State Management:** - text-store with Zustand + persist middleware - All text settings preserved across sessions - Dialog state management (open/close) - Click position tracking **Integration:** - Added text tool to tool palette with Type icon - Registered TextTool in canvas tool system - Added TextDialog to editor layout - Full type safety with TypeScript interfaces **Undoable:** - Text rendering fully integrated with command pattern - Each text insertion creates single undo point - Proper before/after state capture This completes Phase 11 of the implementation plan, marking the transition from MVP to a fully-featured image editor. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-21 09:45:05 +01:00
setText: (text) =>
set((state) => ({
settings: { ...state.settings, text },
})),
setFontFamily: (fontFamily) =>
set((state) => ({
settings: { ...state.settings, fontFamily },
})),
setFontSize: (fontSize) =>
set((state) => ({
settings: { ...state.settings, fontSize: Math.max(8, Math.min(500, fontSize)) },
})),
setFontStyle: (fontStyle) =>
set((state) => ({
settings: { ...state.settings, fontStyle },
})),
setFontWeight: (fontWeight) =>
set((state) => ({
settings: { ...state.settings, fontWeight },
})),
setColor: (color) =>
set((state) => ({
settings: { ...state.settings, color },
})),
setAlign: (align) =>
set((state) => ({
settings: { ...state.settings, align },
})),
setBaseline: (baseline) =>
set((state) => ({
settings: { ...state.settings, baseline },
})),
setLineHeight: (lineHeight) =>
set((state) => ({
settings: { ...state.settings, lineHeight: Math.max(0.5, Math.min(3, lineHeight)) },
})),
setLetterSpacing: (letterSpacing) =>
set((state) => ({
settings: { ...state.settings, letterSpacing: Math.max(-10, Math.min(50, letterSpacing)) },
})),
updateSettings: (settings) =>
set((state) => ({
settings: { ...state.settings, ...settings },
})),
// Text object management
addTextObject: (textObject) =>
set((state) => ({
textObjects: [
...state.textObjects,
{
...textObject,
id: `text-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`,
},
],
})),
updateTextObject: (id, updates) =>
set((state) => ({
textObjects: state.textObjects.map((obj) =>
obj.id === id ? { ...obj, ...updates } : obj
),
})),
deleteTextObject: (id) =>
set((state) => ({
textObjects: state.textObjects.filter((obj) => obj.id !== id),
})),
getTextObjectAt: (x, y, layerId) => {
const state = get();
// Create temporary canvas for text measurement
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
if (!ctx) return null;
// Find text objects at position (reverse order to get topmost)
for (let i = state.textObjects.length - 1; i >= 0; i--) {
const obj = state.textObjects[i];
if (obj.layerId !== layerId) continue;
// Measure text properly
ctx.font = `${obj.fontStyle} ${obj.fontWeight} ${obj.fontSize}px ${obj.fontFamily}`;
const lines = obj.text.split('\n');
let maxWidth = 0;
lines.forEach((line) => {
const metrics = ctx.measureText(line || ' ');
if (metrics.width > maxWidth) maxWidth = metrics.width;
});
// Account for the padding we add in the editor (40px horizontal, 10px vertical)
const width = maxWidth + 40;
const height = lines.length * obj.fontSize * obj.lineHeight + 10;
// The text is stored at obj.x, obj.y (which already includes the +10 offset from editor)
// But we need to check against the editor bounds which start 10px before
const boundX = obj.x - 10;
const boundY = obj.y;
if (
x >= boundX &&
x <= boundX + width &&
y >= boundY &&
y <= boundY + height
) {
return obj;
}
}
return null;
},
activateOnCanvasEditor: (canvasX, canvasY, textId) => {
const state = get();
if (textId) {
// Editing existing text
const textObj = state.textObjects.find((obj) => obj.id === textId);
if (textObj) {
set({
isOnCanvasEditorActive: true,
// Subtract the 10px padding offset to position editor correctly
editorPosition: { x: textObj.x - 10, y: textObj.y },
editorText: textObj.text,
editingTextId: textId,
settings: {
...state.settings,
fontFamily: textObj.fontFamily,
fontSize: textObj.fontSize,
fontStyle: textObj.fontStyle,
fontWeight: textObj.fontWeight,
color: textObj.color,
align: textObj.align,
baseline: textObj.baseline,
lineHeight: textObj.lineHeight,
letterSpacing: textObj.letterSpacing,
},
});
}
} else {
// Creating new text
set({
isOnCanvasEditorActive: true,
editorPosition: { x: canvasX, y: canvasY },
editorText: '',
editingTextId: null,
});
}
},
deactivateOnCanvasEditor: () =>
set({
isOnCanvasEditorActive: false,
editorPosition: null,
editorText: '',
editingTextId: null,
}),
updateEditorPosition: (canvasX, canvasY) =>
feat: implement comprehensive text tool (Phase 11) Add complete text rendering system with the following features: **Text Tool Core:** - TextTool class with click-to-place text functionality - Text cursor and pointer event handling - Integration with DrawCommand for undo/redo support **Text Rendering:** - Multi-line text support with line height control - Custom letter spacing - Text alignment (left/center/right) - Font families: 13 web-safe fonts + 14 popular Google Fonts - Dynamic Google Font loading via Web Font Loader API - Font styles (normal/italic) and weights (100-900) **Text Dialog UI:** - Full-featured text editor dialog - Live preview of text with all formatting - Font family selection (web-safe + Google Fonts) - Font size (8-500px), style, and weight controls - Color picker with hex input - Text alignment options - Line height slider (0.5-3x) - Letter spacing slider (-10 to 50px) - Multi-line text input with textarea **State Management:** - text-store with Zustand + persist middleware - All text settings preserved across sessions - Dialog state management (open/close) - Click position tracking **Integration:** - Added text tool to tool palette with Type icon - Registered TextTool in canvas tool system - Added TextDialog to editor layout - Full type safety with TypeScript interfaces **Undoable:** - Text rendering fully integrated with command pattern - Each text insertion creates single undo point - Proper before/after state capture This completes Phase 11 of the implementation plan, marking the transition from MVP to a fully-featured image editor. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-21 09:45:05 +01:00
set({
editorPosition: { x: canvasX, y: canvasY },
feat: implement comprehensive text tool (Phase 11) Add complete text rendering system with the following features: **Text Tool Core:** - TextTool class with click-to-place text functionality - Text cursor and pointer event handling - Integration with DrawCommand for undo/redo support **Text Rendering:** - Multi-line text support with line height control - Custom letter spacing - Text alignment (left/center/right) - Font families: 13 web-safe fonts + 14 popular Google Fonts - Dynamic Google Font loading via Web Font Loader API - Font styles (normal/italic) and weights (100-900) **Text Dialog UI:** - Full-featured text editor dialog - Live preview of text with all formatting - Font family selection (web-safe + Google Fonts) - Font size (8-500px), style, and weight controls - Color picker with hex input - Text alignment options - Line height slider (0.5-3x) - Letter spacing slider (-10 to 50px) - Multi-line text input with textarea **State Management:** - text-store with Zustand + persist middleware - All text settings preserved across sessions - Dialog state management (open/close) - Click position tracking **Integration:** - Added text tool to tool palette with Type icon - Registered TextTool in canvas tool system - Added TextDialog to editor layout - Full type safety with TypeScript interfaces **Undoable:** - Text rendering fully integrated with command pattern - Each text insertion creates single undo point - Proper before/after state capture This completes Phase 11 of the implementation plan, marking the transition from MVP to a fully-featured image editor. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-21 09:45:05 +01:00
}),
updateEditorText: (text) =>
feat: implement comprehensive text tool (Phase 11) Add complete text rendering system with the following features: **Text Tool Core:** - TextTool class with click-to-place text functionality - Text cursor and pointer event handling - Integration with DrawCommand for undo/redo support **Text Rendering:** - Multi-line text support with line height control - Custom letter spacing - Text alignment (left/center/right) - Font families: 13 web-safe fonts + 14 popular Google Fonts - Dynamic Google Font loading via Web Font Loader API - Font styles (normal/italic) and weights (100-900) **Text Dialog UI:** - Full-featured text editor dialog - Live preview of text with all formatting - Font family selection (web-safe + Google Fonts) - Font size (8-500px), style, and weight controls - Color picker with hex input - Text alignment options - Line height slider (0.5-3x) - Letter spacing slider (-10 to 50px) - Multi-line text input with textarea **State Management:** - text-store with Zustand + persist middleware - All text settings preserved across sessions - Dialog state management (open/close) - Click position tracking **Integration:** - Added text tool to tool palette with Type icon - Registered TextTool in canvas tool system - Added TextDialog to editor layout - Full type safety with TypeScript interfaces **Undoable:** - Text rendering fully integrated with command pattern - Each text insertion creates single undo point - Proper before/after state capture This completes Phase 11 of the implementation plan, marking the transition from MVP to a fully-featured image editor. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-21 09:45:05 +01:00
set({
editorText: text,
feat: implement comprehensive text tool (Phase 11) Add complete text rendering system with the following features: **Text Tool Core:** - TextTool class with click-to-place text functionality - Text cursor and pointer event handling - Integration with DrawCommand for undo/redo support **Text Rendering:** - Multi-line text support with line height control - Custom letter spacing - Text alignment (left/center/right) - Font families: 13 web-safe fonts + 14 popular Google Fonts - Dynamic Google Font loading via Web Font Loader API - Font styles (normal/italic) and weights (100-900) **Text Dialog UI:** - Full-featured text editor dialog - Live preview of text with all formatting - Font family selection (web-safe + Google Fonts) - Font size (8-500px), style, and weight controls - Color picker with hex input - Text alignment options - Line height slider (0.5-3x) - Letter spacing slider (-10 to 50px) - Multi-line text input with textarea **State Management:** - text-store with Zustand + persist middleware - All text settings preserved across sessions - Dialog state management (open/close) - Click position tracking **Integration:** - Added text tool to tool palette with Type icon - Registered TextTool in canvas tool system - Added TextDialog to editor layout - Full type safety with TypeScript interfaces **Undoable:** - Text rendering fully integrated with command pattern - Each text insertion creates single undo point - Proper before/after state capture This completes Phase 11 of the implementation plan, marking the transition from MVP to a fully-featured image editor. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-21 09:45:05 +01:00
}),
}),
{
name: 'text-storage',
partialize: (state) => ({
settings: state.settings,
}), // Only persist settings, not text objects (they're saved with project)
feat: implement comprehensive text tool (Phase 11) Add complete text rendering system with the following features: **Text Tool Core:** - TextTool class with click-to-place text functionality - Text cursor and pointer event handling - Integration with DrawCommand for undo/redo support **Text Rendering:** - Multi-line text support with line height control - Custom letter spacing - Text alignment (left/center/right) - Font families: 13 web-safe fonts + 14 popular Google Fonts - Dynamic Google Font loading via Web Font Loader API - Font styles (normal/italic) and weights (100-900) **Text Dialog UI:** - Full-featured text editor dialog - Live preview of text with all formatting - Font family selection (web-safe + Google Fonts) - Font size (8-500px), style, and weight controls - Color picker with hex input - Text alignment options - Line height slider (0.5-3x) - Letter spacing slider (-10 to 50px) - Multi-line text input with textarea **State Management:** - text-store with Zustand + persist middleware - All text settings preserved across sessions - Dialog state management (open/close) - Click position tracking **Integration:** - Added text tool to tool palette with Type icon - Registered TextTool in canvas tool system - Added TextDialog to editor layout - Full type safety with TypeScript interfaces **Undoable:** - Text rendering fully integrated with command pattern - Each text insertion creates single undo point - Proper before/after state capture This completes Phase 11 of the implementation plan, marking the transition from MVP to a fully-featured image editor. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-21 09:45:05 +01:00
}
)
);