@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.
- package/dist/alert-dialog.d.ts +2 -2
- package/dist/article-suggestions-banner.d.ts +16 -0
- package/dist/button-group.d.ts +3 -2
- package/dist/button.d.ts +1 -1
- package/dist/combobox.d.ts +24 -3
- package/dist/confirm-dialog.d.ts +1 -1
- package/dist/div-button.d.ts +1 -1
- package/dist/esm/chunks/{ChatSearch.BJtS7ZMs.js → ChatSearch.DSB-T76c.js} +2 -2
- package/dist/esm/chunks/{ChatSearch.BJtS7ZMs.js.map → ChatSearch.DSB-T76c.js.map} +1 -1
- package/dist/esm/chunks/{combobox.CkN-wAHB.js → combobox.DNYCWyub.js} +40 -21
- package/dist/esm/chunks/combobox.DNYCWyub.js.map +1 -0
- package/dist/esm/components/article-suggestions-banner.js +55 -0
- package/dist/esm/components/article-suggestions-banner.js.map +1 -0
- package/dist/esm/components/chat-search.js +1 -1
- package/dist/esm/components/combobox.js +1 -1
- package/dist/esm/components/header-nav.js +55 -0
- package/dist/esm/components/header-nav.js.map +1 -0
- package/dist/esm/components/ui/button-group.js +23 -8
- package/dist/esm/components/ui/button-group.js.map +1 -1
- package/dist/esm/components/ui/button.js +2 -8
- package/dist/esm/components/ui/button.js.map +1 -1
- package/dist/esm/components/ui/command.js +1 -1
- package/dist/esm/components/ui/command.js.map +1 -1
- package/dist/esm/components/ui/div-button.js +1 -0
- package/dist/esm/components/ui/div-button.js.map +1 -1
- package/dist/esm/global.css +1 -1
- package/dist/esm/index.js +179 -5
- package/dist/esm/index.js.map +1 -1
- package/dist/header-nav.d.ts +28 -0
- package/dist/index.d.ts +134 -9
- package/dist/stats.html +1 -1
- package/dist/two-level-combobox.d.ts +2 -0
- package/package.json +6 -1
- package/components.json +0 -16
- package/dist/esm/chunks/combobox.CkN-wAHB.js.map +0 -1
- package/markdown-editor.plan.md +0 -2101
- package/markdown-editor.spec.md +0 -915
package/markdown-editor.spec.md
DELETED
|
@@ -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.
|