--- name: composable-svelte-code description: Code editing, syntax highlighting, and visual programming for Composable Svelte. Use when implementing code editors, syntax highlighting, or node-based visual programming. Covers CodeEditor (CodeMirror), CodeHighlight (Prism), and NodeCanvas (SvelteFlow) from @composable-svelte/code package. --- # Composable Svelte Code Package Code editing, syntax highlighting, and visual programming components. --- ## PACKAGE OVERVIEW **Package**: `@composable-svelte/code` **Purpose**: Rich interactive components for code editing and visual programming. **Technology Stack**: - **CodeMirror 6**: Modern code editor with extensible architecture - **Prism.js**: Lightweight syntax highlighter - **SvelteFlow**: Node-based visual programming canvas **Core Components**: - `CodeEditor` - Full-featured code editor (CodeMirror) - `CodeHighlight` - Read-only syntax highlighting (Prism) - `NodeCanvas` - Visual node editor (SvelteFlow) **State Management**: All components follow Composable Architecture patterns with dedicated reducers and type-safe actions. --- ## CODE EDITOR (CodeMirror) **Purpose**: Full-featured code editor with syntax highlighting, autocomplete, and language support. ### Quick Start ```typescript import { createStore } from '@composable-svelte/core'; import { CodeEditor, codeEditorReducer, createInitialState } from '@composable-svelte/code'; // Create editor store const store = createStore({ initialState: createInitialState({ value: '// Write code here', language: 'typescript', theme: 'dark', showLineNumbers: true }), reducer: codeEditorReducer, dependencies: { onSave: async (value) => { await fetch('/api/save', { method: 'POST', body: value }); }, formatter: async (code, language) => { // Use prettier or similar return formatCode(code, language); } } }); // Render editor ``` ### Props - `store: Store` - Editor store (required) - `showToolbar: boolean` - Show toolbar with controls (default: true) ### State Interface ```typescript interface CodeEditorState { // Content value: string; // Current code language: SupportedLanguage; // Active language // Cursor & Selection cursorPosition: { line: number; column: number } | null; selection: EditorSelection | null; // UI State theme: 'light' | 'dark' | 'auto'; showLineNumbers: boolean; readOnly: boolean; // Features enableAutocomplete: boolean; enableLinting: boolean; tabSize: number; // Editor Status hasUnsavedChanges: boolean; lastSavedValue: string | null; isFocused: boolean; // History canUndo: boolean; canRedo: boolean; // Errors error: string | null; saveError: string | null; formatError: string | null; } ``` ### Supported Languages TypeScript, JavaScript, Svelte, HTML, CSS, JSON, Markdown, Bash, SQL, Python, Rust ### Actions ```typescript type CodeEditorAction = // Content | { type: 'valueChanged'; value: string; cursorPosition?: {...} } | { type: 'languageChanged'; language: SupportedLanguage } // Editing | { type: 'undo' } | { type: 'redo' } | { type: 'insertText'; text: string; position?: {...} } | { type: 'selectAll' } // Configuration | { type: 'themeChanged'; theme: 'light' | 'dark' | 'auto' } | { type: 'toggleLineNumbers' } | { type: 'setReadOnly'; readOnly: boolean } // Save/Format | { type: 'save' } | { type: 'format' }; ``` ### Dependencies ```typescript interface CodeEditorDependencies { // Save handler onSave?: (value: string) => Promise; // Format handler formatter?: (code: string, language: SupportedLanguage) => Promise; } ``` ### Complete Example ```typescript
{#if $editorStore.hasUnsavedChanges} Unsaved changes {/if} {#if $editorStore.cursorPosition} Ln {$editorStore.cursorPosition.line}, Col {$editorStore.cursorPosition.column} {/if} {$editorStore.language}
``` ### Toolbar Features When `showToolbar={true}`: - Language selector dropdown - Line numbers toggle - Theme toggle (light/dark) - Format button - Save button (shows "Save *" when unsaved changes) ### Keyboard Shortcuts CodeMirror provides standard keyboard shortcuts: - `Ctrl/Cmd + S`: Save - `Ctrl/Cmd + Z`: Undo - `Ctrl/Cmd + Shift + Z`: Redo - `Ctrl/Cmd + /`: Toggle comment - `Ctrl/Cmd + D`: Delete line - `Ctrl/Cmd + A`: Select all --- ## CODE HIGHLIGHT (Prism.js) **Purpose**: Read-only syntax highlighting for displaying code snippets. ### Quick Start ```typescript import { CodeHighlight } from '@composable-svelte/code'; ``` ### Props - `code: string` - Code to highlight (required) - `language: string` - Language (e.g., 'javascript', 'typescript', 'python') - `theme: 'light' | 'dark'` - Color theme (default: 'dark') - `showLineNumbers: boolean` - Show line numbers (default: false) - `highlightLines: number[]` - Lines to highlight (optional) - `class: string` - Custom CSS class (optional) ### Supported Languages JavaScript, TypeScript, Python, Rust, Go, Java, C, C++, C#, PHP, Ruby, SQL, HTML, CSS, JSON, YAML, Markdown, Bash, Svelte, and more. ### Examples ```typescript ``` ### When to Use CodeEditor vs CodeHighlight **Use CodeEditor**: - User needs to edit code - Autocomplete required - Linting/error checking needed - Save functionality required **Use CodeHighlight**: - Display-only code snippets - Documentation/tutorials - Code examples in blog posts - Faster rendering for many snippets --- ## NODE CANVAS (SvelteFlow) **Purpose**: Visual node-based programming canvas (node editor, flow diagrams). ### Quick Start ```typescript import { createStore } from '@composable-svelte/core'; import { NodeCanvas, nodeCanvasReducer, createInitialNodeCanvasState } from '@composable-svelte/code'; // Create node canvas store const canvasStore = createStore({ initialState: createInitialNodeCanvasState({ nodes: [ { id: '1', type: 'input', position: { x: 100, y: 100 }, data: { label: 'Input Node' } }, { id: '2', type: 'default', position: { x: 300, y: 100 }, data: { label: 'Process Node' } } ], edges: [ { id: 'e1-2', source: '1', target: '2' } ] }), reducer: nodeCanvasReducer, dependencies: {} }); console.log('Clicked:', node)} /> ``` ### Props - `store: Store` - Canvas store (required) - `nodeTypes: Record` - Custom node components (optional) - `edgeTypes: Record` - Custom edge components (optional) - `onNodeClick: (node: Node) => void` - Node click handler (optional) - `onEdgeClick: (edge: Edge) => void` - Edge click handler (optional) - `class: string` - Custom CSS class (optional) ### State Interface ```typescript interface NodeCanvasState { // Nodes nodes: Node[]; selectedNodes: string[]; // Node IDs // Edges edges: Edge[]; selectedEdges: string[]; // Edge IDs // Viewport viewport: { x: number; y: number; zoom: number; }; // Interaction isDragging: boolean; isPanning: boolean; // Error handling error: string | null; } interface Node { id: string; type: string; position: { x: number; y: number }; data: any; } interface Edge { id: string; source: string; // Node ID target: string; // Node ID type?: string; data?: any; } ``` ### Actions ```typescript type NodeCanvasAction = // Nodes | { type: 'addNode'; node: Node } | { type: 'removeNode'; nodeId: string } | { type: 'updateNode'; nodeId: string; data: Partial } | { type: 'moveNode'; nodeId: string; position: { x: number; y: number } } | { type: 'selectNode'; nodeId: string } | { type: 'deselectNode'; nodeId: string } | { type: 'clearNodeSelection' } // Edges | { type: 'addEdge'; edge: Edge } | { type: 'removeEdge'; edgeId: string } | { type: 'updateEdge'; edgeId: string; data: Partial } // Viewport | { type: 'setViewport'; viewport: Partial } | { type: 'zoomIn' } | { type: 'zoomOut' } | { type: 'fitView' } // Error | { type: 'errorOccurred'; error: string } | { type: 'errorCleared' }; ``` ### Use Cases - Visual programming tools - Flow diagrams - Workflow builders - Data pipelines - State machines - Architecture diagrams ### Complete Example ```typescript
``` --- ## COMPONENT SELECTION GUIDE **When to use each component**: **CodeEditor**: - User edits code - Autocomplete needed - Syntax checking required - Save functionality required **CodeHighlight**: - Display-only code - Documentation examples - Fast rendering for many snippets **NodeCanvas**: - Visual programming - Workflow editors - Diagram builders - Data pipeline visualization --- ## CROSS-REFERENCES **Related Skills**: - **composable-svelte-core**: Store, reducer, Effect system, TestStore - **composable-svelte-media**: Audio/video playback (AudioPlayer, VideoEmbed, VoiceInput) - **composable-svelte-chat**: Real-time communication (StreamingChat) - **composable-svelte-components**: UI components (Button, Input, etc.) - **composable-svelte-testing**: TestStore for testing reducers **When to Use Each Package**: - **code**: Code editors, syntax highlighting, visual programming - **media**: Audio players, video embeds, voice input - **chat**: Real-time chat, streaming responses - **graphics**: 3D scenes, WebGPU/WebGL rendering - **charts**: 2D data visualization - **maps**: Geospatial data --- ## PERFORMANCE CONSIDERATIONS **CodeEditor**: - Heavy component (CodeMirror bundle ~300KB) - Use CodeHighlight for display-only snippets - Lazy load for better initial page load **NodeCanvas**: - Heavy component (SvelteFlow bundle ~200KB) - Limit number of nodes for performance (< 1000 recommended) - Use virtualization for large graphs - Disable animations for large graphs --- ## TESTING PATTERNS ### CodeEditor Testing ```typescript import { TestStore } from '@composable-svelte/core'; import { codeEditorReducer, createInitialState } from '@composable-svelte/code'; const store = new TestStore({ initialState: createInitialState({ value: '' }), reducer: codeEditorReducer, dependencies: { onSave: vi.fn(), formatter: vi.fn((code) => Promise.resolve(code)) } }); // Test value change await store.send({ type: 'valueChanged', value: 'console.log("test");' }, (state) => { expect(state.value).toBe('console.log("test");'); expect(state.hasUnsavedChanges).toBe(true); }); // Test save await store.send({ type: 'save' }); await store.receive({ type: 'saved', value: 'console.log("test");' }, (state) => { expect(state.hasUnsavedChanges).toBe(false); expect(state.lastSavedValue).toBe('console.log("test");'); }); ``` ### NodeCanvas Testing ```typescript import { TestStore } from '@composable-svelte/core'; import { nodeCanvasReducer, createInitialNodeCanvasState } from '@composable-svelte/code'; const store = new TestStore({ initialState: createInitialNodeCanvasState({ nodes: [], edges: [] }), reducer: nodeCanvasReducer, dependencies: {} }); // Test add node await store.send({ type: 'addNode', node: { id: '1', type: 'input', position: { x: 100, y: 100 }, data: { label: 'Test' } } }, (state) => { expect(state.nodes.length).toBe(1); expect(state.nodes[0].id).toBe('1'); }); // Test add edge await store.send({ type: 'addEdge', edge: { id: 'e1-2', source: '1', target: '2' } }, (state) => { expect(state.edges.length).toBe(1); }); ``` --- ## TROUBLESHOOTING **CodeEditor not rendering**: - Check CodeMirror peer dependency installed - Verify store created with `codeEditorReducer` - Ensure container has height set **NodeCanvas performance issues**: - Limit number of nodes (< 1000 recommended) - Use simpler custom node components - Disable animations for large graphs **CodeHighlight language not recognized**: - Check language name matches Prism.js language keys - Ensure Prism.js language pack is loaded - Verify syntax highlighting CSS is included