@brainfish-ai/components 0.18.4 → 0.18.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. package/dist/alert-dialog.d.ts +2 -2
  2. package/dist/article-suggestions-banner.d.ts +16 -0
  3. package/dist/button-group.d.ts +3 -2
  4. package/dist/button.d.ts +1 -1
  5. package/dist/combobox.d.ts +24 -3
  6. package/dist/confirm-dialog.d.ts +1 -1
  7. package/dist/div-button.d.ts +1 -1
  8. package/dist/esm/chunks/{ChatSearch.BJtS7ZMs.js → ChatSearch.DSB-T76c.js} +2 -2
  9. package/dist/esm/chunks/{ChatSearch.BJtS7ZMs.js.map → ChatSearch.DSB-T76c.js.map} +1 -1
  10. package/dist/esm/chunks/{combobox.CkN-wAHB.js → combobox.DNYCWyub.js} +40 -21
  11. package/dist/esm/chunks/combobox.DNYCWyub.js.map +1 -0
  12. package/dist/esm/components/article-suggestions-banner.js +55 -0
  13. package/dist/esm/components/article-suggestions-banner.js.map +1 -0
  14. package/dist/esm/components/chat-search.js +1 -1
  15. package/dist/esm/components/combobox.js +1 -1
  16. package/dist/esm/components/header-nav.js +55 -0
  17. package/dist/esm/components/header-nav.js.map +1 -0
  18. package/dist/esm/components/ui/button-group.js +23 -8
  19. package/dist/esm/components/ui/button-group.js.map +1 -1
  20. package/dist/esm/components/ui/button.js +2 -8
  21. package/dist/esm/components/ui/button.js.map +1 -1
  22. package/dist/esm/components/ui/command.js +1 -1
  23. package/dist/esm/components/ui/command.js.map +1 -1
  24. package/dist/esm/components/ui/div-button.js +1 -0
  25. package/dist/esm/components/ui/div-button.js.map +1 -1
  26. package/dist/esm/global.css +1 -1
  27. package/dist/esm/index.js +179 -5
  28. package/dist/esm/index.js.map +1 -1
  29. package/dist/header-nav.d.ts +28 -0
  30. package/dist/index.d.ts +134 -9
  31. package/dist/stats.html +1 -1
  32. package/dist/two-level-combobox.d.ts +2 -0
  33. package/package.json +6 -1
  34. package/components.json +0 -16
  35. package/dist/esm/chunks/combobox.CkN-wAHB.js.map +0 -1
  36. package/markdown-editor.plan.md +0 -2101
  37. package/markdown-editor.spec.md +0 -915
@@ -1,915 +0,0 @@
1
- # Markdown Editor/Viewer Component Specification
2
-
3
- ## 1. Purpose and Overview
4
-
5
- The Markdown Editor/Viewer is a comprehensive reusable component that provides both editing and read-only viewing capabilities for markdown content. It leverages TipTap as the foundation editor and extends the existing multimedia rendering patterns from FormattedMessage.tsx to support embedded content, suggestions, multiplayer collaboration, and streaming content.
6
-
7
- ### 1.1 Core Objectives
8
- - Provide a Notion-like editing experience with rich markdown support
9
- - Seamlessly toggle between edit and read-only modes
10
- - Support multimedia embedding with consistent patterns from existing codebase
11
- - Enable collaborative editing with suggestion tracking
12
- - Handle streaming content for real-time applications
13
- - Maintain accessibility and performance standards
14
-
15
- ## 2. Functional Requirements
16
-
17
- ### 2.1 Mode Management
18
- - **Toggle Modes**: Switch between `edit` and `readonly` modes
19
- - **State Preservation**: Maintain content state when switching modes
20
- - **Mode-specific UI**: Different toolbar and interaction patterns per mode
21
- - **Keyboard Shortcuts**: Support common shortcuts (Ctrl+E to toggle, etc.)
22
-
23
- ### 2.2 Edit Mode Features
24
- - **Rich Text Editing**: Support for all standard markdown elements
25
- - **Suggestion System**: Display edit suggestions with visual indicators
26
- - **Multimedia Insertion**: Drag-and-drop and paste support for media
27
- - **Collaboration**: Real-time multiplayer editing capabilities
28
- - **Formatting Toolbar**: Context-aware formatting controls
29
- - **Auto-save**: Periodic content persistence
30
-
31
- ### 2.3 Read-Only Mode Features
32
- - **Multimedia Rendering**: Full support for all embed types from existing system
33
- - **Streaming Content**: Handle real-time content updates
34
- - **Interactive Elements**: Clickable links, zoomable images
35
- - **Export Options**: Copy, print, and share functionality
36
-
37
- ### 2.4 Suggestion System
38
- - **Visual Indicators**: Strikethrough for deletions, underline for additions
39
- - **Interactive Controls**: Accept/reject individual or batch suggestions
40
- - **Keyboard Navigation**: Arrow keys and tab navigation through suggestions
41
- - **Mouse Interaction**: Click to accept/reject suggestions
42
- - **Suggestion Metadata**: Track author, timestamp, and reason
43
-
44
- ### 2.5 Multimedia Support
45
- - **Image Handling**: Zoomable images using existing ZoomableImage component
46
- - **Video Support**: Native video player for mp4, mov files
47
- - **Diagram Rendering**: Mermaid diagrams using existing MermaidDiagram component
48
- - **Embeds**: YouTube, Vimeo, Wistia, Loom, Supademo, Typeform via existing embed system
49
- - **iFrame Support**: Generic iframe embedding with security controls
50
-
51
- ## 3. Technical Requirements
52
-
53
- ### 3.1 Technology Stack
54
- - **Core Editor**: TipTap v3+ with React integration and native document model
55
- - **Content Format**: TipTap JSON format for internal storage and editing
56
- - **Markdown Translation**: Utility layer using remark-gfm, rehype-raw for import/export + initial loading of existing documents
57
- - **State Management**: React state with optional external state management
58
- - **Styling**: Tailwind CSS classes consistent with existing components
59
- - **TypeScript**: Full type safety with proper interfaces
60
-
61
- ### 3.2 Performance Requirements
62
- - **Initial Load**: < 500ms time to interactive
63
- - **Mode Switching**: < 100ms transition time
64
- - **Large Documents**: Support documents up to 1MB in size
65
- - **Memory Usage**: < 50MB for typical documents
66
- - **Streaming**: Handle 1000+ characters/second streaming rate
67
-
68
- ### 3.3 Accessibility Requirements
69
- - **ARIA Labels**: Proper labeling for all interactive elements
70
- - **Keyboard Navigation**: Full keyboard accessibility
71
- - **Screen Reader**: Compatible with major screen readers
72
- - **Color Contrast**: WCAG 2.1 AA compliance
73
- - **Focus Management**: Proper focus handling in all modes
74
-
75
- ## 4. API Design
76
-
77
- ### 4.1 Component Props Interface
78
-
79
- ```typescript
80
- interface MarkdownEditorViewerProps {
81
- // Core content and mode
82
- content: string;
83
- mode: 'edit' | 'readonly';
84
- onContentChange?: (content: string) => void;
85
- onModeChange?: (mode: 'edit' | 'readonly') => void;
86
-
87
- // Streaming support
88
- isStreaming?: boolean;
89
-
90
- // Suggestion system
91
- suggestions?: EditorSuggestion[];
92
- onSuggestionAccept?: (suggestionId: string) => void;
93
- onSuggestionReject?: (suggestionId: string) => void;
94
- showSuggestions?: boolean;
95
-
96
- // Collaboration
97
- collaborators?: Collaborator[];
98
- currentUser?: User;
99
- onCollaboratorCursor?: (userId: string, position: number) => void;
100
-
101
- // Multimedia and embeds
102
- contentTypeEndpoint?: string;
103
- redirectRules?: RedirectRule[];
104
- allowedEmbeds?: EmbedType[];
105
- maxFileSize?: number;
106
-
107
- // Editor configuration
108
- placeholder?: string;
109
- autoFocus?: boolean;
110
- readOnly?: boolean;
111
- className?: string;
112
-
113
- // Callbacks
114
- onSave?: (content: string) => void;
115
- onError?: (error: EditorError) => void;
116
- onChange?: (content: string, delta?: any) => void;
117
- }
118
-
119
- interface EditorSuggestion {
120
- id: string;
121
- type: 'insert' | 'delete' | 'replace';
122
- position: { from: number; to: number };
123
- oldText?: string;
124
- newText?: string;
125
- author?: User;
126
- timestamp: Date;
127
- reason?: string;
128
- status: 'pending' | 'accepted' | 'rejected';
129
- }
130
-
131
- interface Collaborator {
132
- id: string;
133
- name: string;
134
- avatar?: string;
135
- color: string;
136
- cursor?: { position: number; selection?: { from: number; to: number } };
137
- isActive: boolean;
138
- }
139
-
140
- interface User {
141
- id: string;
142
- name: string;
143
- email?: string;
144
- avatar?: string;
145
- }
146
-
147
- type EmbedType = 'youtube' | 'vimeo' | 'wistia' | 'loom' | 'supademo' | 'typeform' | 'iframe' | 'mermaid' | 'image' | 'video';
148
-
149
- interface EditorError {
150
- type: 'validation' | 'network' | 'permission' | 'file' | 'embed';
151
- message: string;
152
- details?: any;
153
- }
154
- ```
155
-
156
- ### 4.2 TipTap Extensions Configuration
157
-
158
- ```typescript
159
- interface EditorExtensions {
160
- // Core extensions
161
- document: DocumentExtension;
162
- paragraph: ParagraphExtension;
163
- text: TextExtension;
164
-
165
- // Formatting extensions
166
- bold: BoldExtension;
167
- italic: ItalicExtension;
168
- code: CodeExtension;
169
- codeBlock: CodeBlockExtension;
170
- heading: HeadingExtension;
171
-
172
- // Structure extensions
173
- bulletList: BulletListExtension;
174
- orderedList: OrderedListExtension;
175
- listItem: ListItemExtension;
176
- blockquote: BlockquoteExtension;
177
- horizontalRule: HorizontalRuleExtension;
178
-
179
- // Custom extensions
180
- suggestions: SuggestionExtension;
181
- multimedia: MultimediaExtension;
182
- collaboration: CollaborationExtension;
183
- streaming: StreamingExtension;
184
-
185
- // Table support
186
- table: TableExtension;
187
- tableRow: TableRowExtension;
188
- tableCell: TableCellExtension;
189
- tableHeader: TableHeaderExtension;
190
- }
191
- ```
192
-
193
- ## 5. Architecture Design
194
-
195
- ### 5.1 Monorepo Architecture
196
-
197
- The component will be developed within the **`@brainfish-ai/tiptap`** package. This package will contain the editor component (evolving from `SimpleEditor`), its UI primitives, custom hooks, and the required Tiptap extensions. This co-location simplifies dependencies and aligns the editor's UI with its core logic.
198
-
199
- ### 5.2 Component Structure
200
-
201
- The following structure will be implemented within `packages/tiptap/src/`:
202
-
203
- ```
204
- components/
205
- ├── tiptap-templates/
206
- │ └── simple/
207
- │ ├── markdown-viewer-editor.tsx # Editor Viewer component that lazy loads content-viewer or simple-editor based on mode
208
- │ ├── content-viewer.tsx # Viewer component
209
- │ ├── simple-editor.tsx # Editor component
210
- │ └── ...
211
- ├── tiptap-ui/
212
- │ ├── ViewerContent.tsx # Read-only renderer
213
- │ └── ... # Other UI components (Suggestions, Collaboration, etc.)
214
- └── tiptap-node/
215
- └── ... # Custom node components
216
- lib/
217
- ├── markdownTranslator.ts # Markdown ↔ TipTap JSON conversion
218
- └── tiptap-utils.ts # Generic Tiptap utilities
219
- extensions/
220
- ├── SuggestionExtension.ts # TipTap suggestion extension
221
- ├── MultimediaExtension.ts # Media handling extension
222
- ├── CollaborationExtension.ts # Multiplayer extension
223
- └── StreamingExtension.ts # Streaming content extension
224
- hooks/
225
- └── ... # Custom hooks for editor functionality
226
- ```
227
-
228
- ### 5.2 State Management Architecture
229
-
230
- ```typescript
231
- interface EditorState {
232
- // Content state
233
- content: string;
234
- mode: 'edit' | 'readonly';
235
- isDirty: boolean;
236
- lastSaved: Date | null;
237
-
238
- // Suggestion state
239
- suggestions: EditorSuggestion[];
240
- activeSuggestion: string | null;
241
- suggestionMode: boolean;
242
-
243
- // Collaboration state
244
- collaborators: Collaborator[];
245
- currentUser: User | null;
246
- isConnected: boolean;
247
-
248
- // UI state
249
- isLoading: boolean;
250
- error: EditorError | null;
251
- showToolbar: boolean;
252
- fullscreen: boolean;
253
-
254
- // Streaming state
255
- isStreaming: boolean;
256
- streamBuffer: string;
257
- }
258
- ```
259
-
260
- ## 6. TipTap Integration Specifications
261
-
262
- ### 6.1 Core Editor Configuration
263
-
264
- ```typescript
265
- const createEditor = (props: MarkdownEditorViewerProps) => {
266
- return useEditor({
267
- extensions: [
268
- Document,
269
- Paragraph,
270
- Text,
271
- Heading.configure({ levels: [1, 2, 3, 4, 5, 6] }),
272
- Bold,
273
- Italic,
274
- Code,
275
- CodeBlock.configure({
276
- languageClassPrefix: 'language-',
277
- HTMLAttributes: { class: 'code-block' },
278
- }),
279
- BulletList,
280
- OrderedList,
281
- ListItem,
282
- Blockquote,
283
- HorizontalRule,
284
- Table.configure({ resizable: true }),
285
- TableRow,
286
- TableHeader,
287
- TableCell,
288
- // Custom extensions
289
- SuggestionExtension.configure({
290
- suggestion: {
291
- items: props.suggestions || [],
292
- render: renderSuggestion,
293
- },
294
- }),
295
- MultimediaExtension.configure({
296
- allowedTypes: props.allowedEmbeds || [],
297
- maxFileSize: props.maxFileSize || 10 * 1024 * 1024, // 10MB
298
- }),
299
- StreamingExtension.configure({
300
- onStream: handleStreamingContent,
301
- }),
302
- ],
303
- content: props.content,
304
- editable: props.mode === 'edit' && !props.readOnly,
305
- onUpdate: ({ editor }) => {
306
- const content = editor.getHTML();
307
- props.onContentChange?.(content);
308
- props.onChange?.(content);
309
- },
310
- parseOptions: {
311
- preserveWhitespace: 'full',
312
- },
313
- });
314
- };
315
- ```
316
-
317
- ### 6.2 Custom TipTap Extensions
318
-
319
- #### 6.2.1 Suggestion Extension
320
-
321
- ```typescript
322
- const SuggestionExtension = Extension.create({
323
- name: 'suggestions',
324
-
325
- addGlobalAttributes() {
326
- return [
327
- {
328
- types: ['paragraph', 'heading', 'codeBlock'],
329
- attributes: {
330
- suggestionId: { default: null },
331
- suggestionType: { default: null },
332
- suggestionAuthor: { default: null },
333
- },
334
- },
335
- ];
336
- },
337
-
338
- addCommands() {
339
- return {
340
- addSuggestion: (suggestion: EditorSuggestion) => ({ tr, state }) => {
341
- // Implementation for adding suggestion marks
342
- },
343
- acceptSuggestion: (suggestionId: string) => ({ tr, state }) => {
344
- // Implementation for accepting suggestions
345
- },
346
- rejectSuggestion: (suggestionId: string) => ({ tr, state }) => {
347
- // Implementation for rejecting suggestions
348
- },
349
- };
350
- },
351
-
352
- addKeyboardShortcuts() {
353
- return {
354
- 'Mod-Shift-a': () => this.editor.commands.acceptSuggestion(),
355
- 'Mod-Shift-r': () => this.editor.commands.rejectSuggestion(),
356
- };
357
- },
358
- });
359
- ```
360
-
361
- #### 6.2.2 Multimedia Extension
362
-
363
- ```typescript
364
- const MultimediaExtension = Extension.create({
365
- name: 'multimedia',
366
-
367
- addCommands() {
368
- return {
369
- insertMedia: (attrs: { src: string; type: string; alt?: string }) => ({ tr, state }) => {
370
- // Implementation for inserting multimedia content
371
- },
372
- insertEmbed: (url: string) => ({ tr, state }) => {
373
- // Implementation for inserting embeds
374
- },
375
- };
376
- },
377
-
378
- addProseMirrorPlugins() {
379
- return [
380
- new Plugin({
381
- key: new PluginKey('multimedia'),
382
- props: {
383
- handleDOMEvents: {
384
- paste: (view, event) => {
385
- // Handle paste events for media
386
- },
387
- drop: (view, event) => {
388
- // Handle drag and drop for media
389
- },
390
- },
391
- },
392
- }),
393
- ];
394
- },
395
- });
396
- ```
397
-
398
- #### 6.2.3 Streaming Extension
399
-
400
- ```typescript
401
- const StreamingExtension = Extension.create({
402
- name: 'streaming',
403
-
404
- addCommands() {
405
- return {
406
- appendStreamContent: (content: string) => ({ tr, state }) => {
407
- // Implementation for appending streaming content
408
- },
409
- finalizeStream: () => ({ tr, state }) => {
410
- // Implementation for finalizing streamed content
411
- },
412
- };
413
- },
414
-
415
- onCreate() {
416
- this.options.onStream?.(this.editor);
417
- },
418
- });
419
- ```
420
-
421
- ## 7. Markdown Translation Layer
422
-
423
- ### 7.1 Markdown ↔ TipTap Conversion Utility
424
-
425
- ```typescript
426
- interface MarkdownTranslator {
427
- // Convert markdown string to TipTap JSON format
428
- markdownToTipTap(markdown: string): TipTapDocument;
429
-
430
- // Convert TipTap JSON to markdown string
431
- tipTapToMarkdown(doc: TipTapDocument): string;
432
-
433
- // Handle existing FormattedMessage content
434
- parseExistingContent(content: string, redirectRules?: RedirectRule[]): TipTapDocument;
435
- }
436
-
437
- const markdownTranslator = {
438
- markdownToTipTap: (markdown: string) => {
439
- // Use remark-gfm and rehype-raw to parse markdown
440
- const processor = unified()
441
- .use(remarkParse)
442
- .use(remarkGfm)
443
- .use(remarkRehype, { allowDangerousHtml: true })
444
- .use(rehypeRaw);
445
-
446
- const mdast = processor.parse(markdown);
447
- const hast = processor.runSync(mdast);
448
-
449
- // Convert HAST to TipTap JSON format
450
- return convertHastToTipTap(hast);
451
- },
452
-
453
- tipTapToMarkdown: (doc: TipTapDocument) => {
454
- // Convert TipTap JSON back to markdown
455
- return convertTipTapToMarkdown(doc);
456
- },
457
-
458
- parseExistingContent: (content: string, redirectRules = []) => {
459
- // Handle FormattedMessage-specific patterns and embeds
460
- const processedContent = preprocessEmbeds(content, redirectRules);
461
- return markdownTranslator.markdownToTipTap(processedContent);
462
- }
463
- };
464
- ```
465
-
466
- ### 7.2 Content Flow Architecture
467
-
468
- ```
469
- Existing Markdown → markdownTranslator.parseExistingContent() → TipTap JSON
470
-
471
- TipTap Editor
472
-
473
- TipTap JSON → markdownTranslator.tipTapToMarkdown() → Markdown Export
474
- ```
475
-
476
- ## 8. Multimedia System Specifications
477
-
478
- ### 8.1 Integration with Existing Embed System
479
-
480
- The component will leverage the existing embed system from `src/components/markdown/embeds/` with the following integration pattern:
481
-
482
- ```typescript
483
- const MultimediaRenderer: React.FC<{ url: string; type: string }> = ({ url, type }) => {
484
- // Reuse existing EmbedComponent logic
485
- const embedComponent = EmbedComponent({
486
- attrs: { href: url },
487
- isAttachmentVideo: type === 'video',
488
- });
489
-
490
- if (React.isValidElement(embedComponent)) {
491
- return embedComponent;
492
- }
493
-
494
- // Fallback for unsupported types
495
- return <div>Unsupported media type: {type}</div>;
496
- };
497
- ```
498
-
499
- ### 7.2 Supported Multimedia Types
500
-
501
- | Type | Component | Description |
502
- |------|-----------|-------------|
503
- | Images | ZoomableImage | PNG, JPG, GIF, WebP with zoom functionality |
504
- | Videos | NativeVideo | MP4, MOV, WebM with native player |
505
- | Diagrams | MermaidDiagram | Mermaid syntax diagrams |
506
- | YouTube | Youtube | YouTube video embeds |
507
- | Vimeo | Vimeo | Vimeo video embeds |
508
- | Wistia | Wistia | Wistia video embeds |
509
- | Loom | Loom | Loom video embeds |
510
- | Supademo | Supademo | Supademo interactive demos |
511
- | Typeform | Typeform | Typeform embeds |
512
- | iFrames | Frame | Generic iframe support with security controls |
513
-
514
- ### 7.3 Media Upload Workflow
515
-
516
- ```typescript
517
- interface MediaUploadFlow {
518
- 1: 'User initiates upload (drag, paste, or button)';
519
- 2: 'Validate file type and size';
520
- 3: 'Show upload progress indicator';
521
- 4: 'Upload to server or process locally';
522
- 5: 'Insert media node into editor at cursor position';
523
- 6: 'Update content and trigger onChange';
524
- }
525
- ```
526
-
527
- ## 8. Suggestion System Implementation
528
-
529
- ### 8.1 Visual Representation
530
-
531
- ```css
532
- .suggestion-delete {
533
- text-decoration: line-through;
534
- background-color: rgba(239, 68, 68, 0.1);
535
- color: rgba(239, 68, 68, 0.7);
536
- }
537
-
538
- .suggestion-insert {
539
- text-decoration: underline;
540
- background-color: rgba(34, 197, 94, 0.1);
541
- color: rgba(34, 197, 94, 0.8);
542
- }
543
-
544
- .suggestion-replace .old-text {
545
- text-decoration: line-through;
546
- background-color: rgba(239, 68, 68, 0.1);
547
- }
548
-
549
- .suggestion-replace .new-text {
550
- text-decoration: underline;
551
- background-color: rgba(34, 197, 94, 0.1);
552
- }
553
-
554
- .suggestion-active {
555
- outline: 2px solid #3b82f6;
556
- outline-offset: 2px;
557
- }
558
- ```
559
-
560
- ### 8.2 Suggestion Interaction Handlers
561
-
562
- ```typescript
563
- const useSuggestionHandlers = (editor: Editor) => {
564
- const handleSuggestionAccept = useCallback((suggestionId: string) => {
565
- const suggestion = findSuggestion(suggestionId);
566
- if (!suggestion) return;
567
-
568
- switch (suggestion.type) {
569
- case 'insert':
570
- editor.commands.insertContentAt(suggestion.position.from, suggestion.newText);
571
- break;
572
- case 'delete':
573
- editor.commands.deleteRange(suggestion.position);
574
- break;
575
- case 'replace':
576
- editor.commands.deleteRange(suggestion.position);
577
- editor.commands.insertContentAt(suggestion.position.from, suggestion.newText);
578
- break;
579
- }
580
-
581
- // Update suggestion status
582
- onSuggestionAccept?.(suggestionId);
583
- }, [editor, onSuggestionAccept]);
584
-
585
- const handleSuggestionReject = useCallback((suggestionId: string) => {
586
- removeSuggestionMarks(editor, suggestionId);
587
- onSuggestionReject?.(suggestionId);
588
- }, [editor, onSuggestionReject]);
589
-
590
- return { handleSuggestionAccept, handleSuggestionReject };
591
- };
592
- ```
593
-
594
- ### 8.3 Keyboard Navigation
595
-
596
- ```typescript
597
- const suggestionKeyboardShortcuts = {
598
- 'Tab': () => navigateToNextSuggestion(),
599
- 'Shift-Tab': () => navigateToPreviousSuggestion(),
600
- 'Enter': () => acceptActiveSuggestion(),
601
- 'Escape': () => rejectActiveSuggestion(),
602
- 'Mod-Shift-a': () => acceptAllSuggestions(),
603
- 'Mod-Shift-r': () => rejectAllSuggestions(),
604
- };
605
- ```
606
-
607
- ## 9. Multiplayer Collaboration Approach
608
-
609
- ### 9.1 Collaboration Architecture
610
-
611
- ```typescript
612
- interface CollaborationProvider {
613
- // Connection management
614
- connect(roomId: string, user: User): Promise<void>;
615
- disconnect(): void;
616
-
617
- // Document synchronization
618
- sendUpdate(update: any): void;
619
- onReceiveUpdate(callback: (update: any) => void): void;
620
-
621
- // Cursor tracking
622
- sendCursor(position: number, selection?: { from: number; to: number }): void;
623
- onCursorUpdate(callback: (userId: string, cursor: CursorPosition) => void): void;
624
-
625
- // Presence
626
- sendPresence(data: any): void;
627
- onPresenceUpdate(callback: (users: Collaborator[]) => void): void;
628
- }
629
- ```
630
-
631
- ### 9.2 Conflict Resolution
632
-
633
- ```typescript
634
- interface ConflictResolution {
635
- strategy: 'operational-transform' | 'crdt' | 'last-writer-wins';
636
-
637
- resolveConflict(localUpdate: any, remoteUpdate: any): any;
638
-
639
- transformUpdate(update: any, against: any): any;
640
- }
641
- ```
642
-
643
- ### 9.3 Real-time Features
644
-
645
- - **Live Cursors**: Show real-time cursor positions of collaborators
646
- - **Selection Indicators**: Highlight text selections from other users
647
- - **Typing Indicators**: Show when collaborators are typing
648
- - **Presence Awareness**: Display active collaborators list
649
- - **Version History**: Track document versions and changes
650
- - **Conflict Resolution**: Handle simultaneous edits gracefully
651
-
652
- ## 10. Streaming Content Handling
653
-
654
- ### 10.1 Streaming Interface
655
-
656
- ```typescript
657
- interface StreamingHandler {
658
- // Stream management
659
- startStream(): void;
660
- appendContent(chunk: string): void;
661
- endStream(): void;
662
-
663
- // Stream state
664
- isStreaming: boolean;
665
- buffer: string;
666
-
667
- // Callbacks
668
- onStreamStart?: () => void;
669
- onStreamChunk?: (chunk: string) => void;
670
- onStreamEnd?: () => void;
671
- }
672
- ```
673
-
674
- ### 10.2 Streaming Implementation
675
-
676
- ```typescript
677
- const useStreaming = (editor: Editor) => {
678
- const [streamBuffer, setStreamBuffer] = useState('');
679
- const [isStreaming, setIsStreaming] = useState(false);
680
-
681
- const appendStreamContent = useCallback((chunk: string) => {
682
- setStreamBuffer(prev => prev + chunk);
683
-
684
- // Update editor content without losing focus
685
- editor.commands.insertContentAt(
686
- editor.state.doc.content.size,
687
- chunk,
688
- false // Don't update selection
689
- );
690
- }, [editor]);
691
-
692
- const finalizeStream = useCallback(() => {
693
- setIsStreaming(false);
694
- setStreamBuffer('');
695
- // Process any final formatting or cleanup
696
- }, []);
697
-
698
- return {
699
- isStreaming,
700
- streamBuffer,
701
- appendStreamContent,
702
- finalizeStream,
703
- };
704
- };
705
- ```
706
-
707
- ### 10.3 Streaming Optimizations
708
-
709
- - **Debounced Updates**: Batch rapid content updates
710
- - **Partial Rendering**: Only render visible content during streaming
711
- - **Memory Management**: Clean up old stream chunks
712
- - **Error Recovery**: Handle interrupted streams gracefully
713
-
714
- ## 11. Performance Considerations
715
-
716
- ### 11.1 Optimization Strategies
717
-
718
- - **Virtualization**: Use virtual scrolling for large documents
719
- - **Lazy Loading**: Load multimedia content on demand
720
- - **Code Splitting**: Split editor and viewer into separate bundles
721
- - **Memoization**: Cache expensive operations and renders
722
- - **Debouncing**: Debounce onChange events and auto-save
723
-
724
- ### 11.2 Bundle Size Management
725
-
726
- ```typescript
727
- // Dynamic imports for large dependencies
728
- const TipTapEditor = lazy(() => import('./components/Editor/EditorContent'));
729
- const MultimediaRenderer = lazy(() => import('./components/Multimedia/MediaRenderer'));
730
- const CollaborationFeatures = lazy(() => import('./components/Collaboration'));
731
- ```
732
-
733
- ### 11.3 Memory Management
734
-
735
- - **Content Cleanup**: Clear undo/redo history for large documents
736
- - **Event Listeners**: Properly clean up event listeners on unmount
737
- - **WebSocket Connections**: Close collaboration connections when not needed
738
- - **Media Caching**: Implement LRU cache for multimedia content
739
-
740
- ## 12. Testing Strategy
741
-
742
- ### 12.1 Unit Testing
743
-
744
- ```typescript
745
- describe('MarkdownEditorViewer', () => {
746
- describe('Mode Switching', () => {
747
- it('should switch from edit to readonly mode', () => {});
748
- it('should preserve content when switching modes', () => {});
749
- it('should disable editing in readonly mode', () => {});
750
- });
751
-
752
- describe('Suggestion System', () => {
753
- it('should display suggestions visually', () => {});
754
- it('should accept suggestions correctly', () => {});
755
- it('should reject suggestions correctly', () => {});
756
- it('should handle keyboard navigation', () => {});
757
- });
758
-
759
- describe('Multimedia Handling', () => {
760
- it('should render images correctly', () => {});
761
- it('should embed videos properly', () => {});
762
- it('should handle mermaid diagrams', () => {});
763
- it('should process file uploads', () => {});
764
- });
765
-
766
- describe('Streaming Content', () => {
767
- it('should append streaming content', () => {});
768
- it('should handle stream interruption', () => {});
769
- it('should finalize streams correctly', () => {});
770
- });
771
- });
772
- ```
773
-
774
- ### 12.2 Integration Testing
775
-
776
- - **TipTap Integration**: Test editor initialization and extension loading
777
- - **Embed System**: Test multimedia rendering with existing embed components
778
- - **Collaboration**: Test real-time features with mock WebSocket connections
779
- - **Performance**: Test with large documents and multiple media items
780
-
781
- ### 12.3 E2E Testing
782
-
783
- - **User Workflows**: Test complete editing and viewing workflows
784
- - **Cross-browser**: Test on major browsers and devices
785
- - **Accessibility**: Test with screen readers and keyboard navigation
786
- - **Error Scenarios**: Test error handling and recovery
787
-
788
- ## 13. Dependencies and Integration Points
789
-
790
- ### 13.1 Required Dependencies
791
-
792
- ```json
793
- {
794
- "dependencies": {
795
- "@tiptap/react": "^2.1.0",
796
- "@tiptap/starter-kit": "^2.1.0",
797
- "@tiptap/extension-table": "^2.1.0",
798
- "@tiptap/extension-collaboration": "^2.1.0",
799
- "@tiptap/extension-collaboration-cursor": "^2.1.0",
800
- "y-webrtc": "^10.2.5",
801
- "yjs": "^13.6.0"
802
- }
803
- }
804
- ```
805
-
806
- ### 13.2 Integration Points
807
-
808
- - **Existing Embed System**: `src/components/markdown/embeds/`
809
- - **Multimedia Components**: `ZoomableImage`, `MermaidDiagram`, `NativeVideo`
810
- - **UI Components**: Reuse existing Radix UI components for modals, dropdowns
811
- - **Styling System**: Leverage existing Tailwind CSS classes and design tokens
812
- - **Utils and Hooks**: Extend existing utility functions and custom hooks
813
-
814
- ### 13.3 Breaking Changes
815
-
816
- - **None Expected**: Component designed to extend existing patterns
817
- - **Optional Integration**: Can be used alongside or instead of FormattedMessage
818
- - **Backward Compatibility**: Maintains compatibility with existing embed system
819
-
820
- ## 14. Security Considerations
821
-
822
- ### 14.1 Content Security
823
-
824
- - **XSS Prevention**: Sanitize user input and embedded content
825
- - **CSP Headers**: Implement Content Security Policy for iframe embeds
826
- - **URL Validation**: Validate and sanitize embedded URLs
827
- - **File Upload Security**: Implement file type and size validation
828
-
829
- ### 14.2 Collaboration Security
830
-
831
- - **Authentication**: Verify user identity for collaboration features
832
- - **Authorization**: Control document access and editing permissions
833
- - **Data Encryption**: Encrypt collaboration data in transit
834
- - **Rate Limiting**: Prevent abuse of real-time features
835
-
836
- ## 15. Accessibility Requirements
837
-
838
- ### 15.1 ARIA Implementation
839
-
840
- ```typescript
841
- const editorARIA = {
842
- 'aria-label': 'Markdown editor',
843
- 'aria-multiline': 'true',
844
- 'role': 'textbox',
845
- 'aria-describedby': 'editor-help-text',
846
- };
847
-
848
- const toolbarARIA = {
849
- 'role': 'toolbar',
850
- 'aria-label': 'Formatting toolbar',
851
- 'aria-orientation': 'horizontal',
852
- };
853
- ```
854
-
855
- ### 15.2 Keyboard Navigation
856
-
857
- - **Tab Order**: Logical tab sequence through all interactive elements
858
- - **Arrow Keys**: Navigate through suggestions and toolbar items
859
- - **Shortcuts**: Standard keyboard shortcuts for common actions
860
- - **Focus Management**: Proper focus handling during mode switches
861
-
862
- ### 15.3 Screen Reader Support
863
-
864
- - **Live Regions**: Announce content changes and mode switches
865
- - **Descriptive Labels**: Clear labels for all interactive elements
866
- - **Status Updates**: Announce suggestion accept/reject actions
867
- - **Media Descriptions**: Provide alt text for multimedia content
868
-
869
- ## 16. Error Handling
870
-
871
- ### 16.1 Error Types and Handling
872
-
873
- ```typescript
874
- enum EditorErrorType {
875
- INITIALIZATION_ERROR = 'initialization',
876
- CONTENT_PARSE_ERROR = 'content_parse',
877
- COLLABORATION_ERROR = 'collaboration',
878
- MEDIA_UPLOAD_ERROR = 'media_upload',
879
- NETWORK_ERROR = 'network',
880
- PERMISSION_ERROR = 'permission',
881
- }
882
-
883
- interface ErrorHandler {
884
- type: EditorErrorType;
885
- message: string;
886
- retry?: () => void;
887
- fallback?: () => void;
888
- }
889
- ```
890
-
891
- ### 16.2 Error Recovery
892
-
893
- - **Graceful Degradation**: Fall back to basic markdown editing if advanced features fail
894
- - **Retry Mechanisms**: Automatic retry for network-related errors
895
- - **User Notification**: Clear error messages with actionable solutions
896
- - **Data Preservation**: Prevent data loss during error scenarios
897
-
898
- ## 17. Future Enhancements
899
-
900
- ### 17.1 Planned Features
901
-
902
- - **Plugin System**: Allow custom extensions and plugins
903
- - **Advanced Tables**: Enhanced table editing with spreadsheet-like features
904
- - **Math Support**: LaTeX math rendering and editing
905
- - **Comments**: Inline commenting system for collaboration
906
- - **Version Control**: Git-like version control for documents
907
-
908
- ### 17.2 Scalability Considerations
909
-
910
- - **Cloud Sync**: Integration with cloud storage providers
911
- - **Offline Support**: Offline editing with sync when reconnected
912
- - **Mobile Optimization**: Touch-friendly interface for mobile devices
913
- - **Performance Monitoring**: Built-in performance monitoring and optimization
914
-
915
- This specification provides a comprehensive foundation for implementing the Markdown Editor/Viewer component while maintaining consistency with existing codebase patterns and ensuring scalability for future enhancements.