Overview
This issue proposes migrating the PulmNotes editor from our custom implementation to TipTap, a headless rich-text editor framework. This migration aims to resolve current editor issues (cursor positioning, mentions, slash commands) while reducing code complexity and improving long-term maintainability.
Motivation
Current Problems
Benefits of Migration
60% code reduction : ~2000 lines → ~800 lines
Automatic cursor management : Eliminates manual positioning bugs
Built-in features : Keyboard shortcuts, undo/redo, accessibility
Better mobile support : Touch events handled automatically
Future-ready : Collaborative editing capability
Active community : Stack Overflow support, regular updates
Proven stability : Battle-tested in production applications
Migration Scope
Files to Refactor (~40-50% code changes)
1. Editor UI Layer (Primary Changes)
Editor.tsx (646 lines → 150-200 lines) - 70% simplification
Block.tsx (394 lines → 50-100 lines) - 75% elimination
SlashMenu.tsx (196 lines → 20-50 lines) - 75% simplification
MentionMenu.tsx (180 lines → 30-60 lines) - 70% simplification
2. Files Unchanged (Keep As-Is)
Persistence layer (LocalStorageNoteStore.ts, CategoryStore.ts)
Data types (types.ts) - Add conversion utilities only
UI components (existing component library)
Technical Approach
Core Changes:
// Replace custom block management with TipTap's document model
const editor = useEditor ( {
extensions : [
Document ,
Paragraph ,
Text ,
Heading . configure ( { levels : [ 1 , 2 , 3 ] } ) ,
// Custom extensions for our features
CustomBlockExtension ,
MentionExtension ,
SlashCommandExtension ,
] ,
content : convertNoteToTipTapJSON ( note ) ,
onUpdate : ( { editor } ) => {
const blocks = convertTipTapJSONToBlocks ( editor . getJSON ( ) ) ;
onUpdateBlocks ( note . id , blocks ) ;
} ,
} ) ;
Data Model Compatibility:
Keep existing Block type interface
Create conversion functions:
convertBlocksToTipTapJSON(blocks: Block[]): JSONContent
convertTipTapJSONToBlocks(content: JSONContent): Block[]
Persistence layer remains completely unchanged
Implementation Tasks
Phase 1: Setup & Dependencies (1 hour)
Install TipTap packages:
Core: @tiptap/react, @tiptap/pm, @tiptap/core
Extensions: @tiptap/extension-document, @tiptap/extension-paragraph, @tiptap/extension-text, @tiptap/extension-heading, @tiptap/extension-bullet-list, @tiptap/extension-ordered-list, @tiptap/extension-list-item, @tiptap/extension-code-block, @tiptap/extension-blockquote, @tiptap/extension-horizontal-rule
Custom features: @tiptap/extension-mention, @tiptap/suggestion
Bundle size analysis (expected: 50-70KB gzipped)
Phase 2: Core Editor Migration (2 hours)
Phase 3: Custom Extensions (1.5 hours)
Phase 4: Slash Commands (0.5 hours)
Phase 5: Mention System (0.5 hours)
Phase 6: Integration & Testing (1 hour)
Phase 7: Cleanup (0.5 hours)
Migration Strategy
Recommended Approach: Complete Refactor
Timeline: 4-6 hours development
Risk: Medium (large changes, but well-tested library)
Benefit: Clean slate with full TipTap features
Steps:
Install TipTap dependencies
Rewrite Editor.tsx with useEditor hook
Create custom extensions for blocks, mentions, slash commands
Update persistence layer integration
Test thoroughly
Deploy
Alternative: Gradual Migration
Timeline: 2-3 days (part-time)
Risk: Low (easier to debug, can rollback)
Benefit: Incremental validation
Steps:
Add TipTap alongside custom editor
Migrate SlashMenu → SlashCommand extension
Migrate MentionMenu → Mention extension
Migrate Block rendering → NodeView
Remove old components
Expected Outcomes
Code Reduction
Editor UI: 646 lines → 150-200 lines (70% reduction)
Block Rendering: 394 lines → 50-100 lines (75% reduction)
Slash Menu: 196 lines → 20-50 lines (75% reduction)
Mention Menu: 180 lines → 30-60 lines (70% reduction)
Type System: 85 lines → 85 lines (unchanged)
Persistence: ~500 lines → ~500 lines (unchanged)
TOTAL: ~2000 lines → ~800 lines (60% reduction)
Solved Issues
✅ Cursor positioning works perfectly (automatic)
✅ @mentions fully functional with autocomplete
✅ Slash commands work reliably
✅ Keyboard shortcuts handled automatically
✅ Better accessibility support
✅ Mobile touch events work properly
Technical Constraints
No Breaking Changes : Data model remains compatible
Persistence Unchanged : LocalStorage layer untouched
Backward Compatibility : Existing notes load correctly
No Data Migration : Conversion happens at runtime
Related Issues
Estimated Effort
Development Time : 4-6 hours (complete refactor) or 2-3 days (gradual)
Complexity : Medium
Risk : Medium (large changes, well-tested library)
Testing Time : 1 hour
Acceptance Criteria
Success Metrics
Zero cursor positioning bugs
60% code reduction achieved
All features from custom editor maintained
Improved development velocity for future features
Better test coverage with TipTap's built-in testing utilities
Notes
TipTap handles most complex editor logic internally
Custom features (blocks, mentions, slash commands) implemented as extensions
Data model conversion happens at the editor boundary
Persistence layer completely isolated from changes
Can run in parallel during gradual migration
Consider breaking into smaller PRs for easier review
Overview
This issue proposes migrating the PulmNotes editor from our custom implementation to TipTap, a headless rich-text editor framework. This migration aims to resolve current editor issues (cursor positioning, mentions, slash commands) while reducing code complexity and improving long-term maintainability.
Motivation
Current Problems
Benefits of Migration
Migration Scope
Files to Refactor (~40-50% code changes)
1. Editor UI Layer (Primary Changes)
Editor.tsx(646 lines → 150-200 lines) - 70% simplificationBlock.tsx(394 lines → 50-100 lines) - 75% eliminationSlashMenu.tsx(196 lines → 20-50 lines) - 75% simplificationMentionMenu.tsx(180 lines → 30-60 lines) - 70% simplification2. Files Unchanged (Keep As-Is)
LocalStorageNoteStore.ts,CategoryStore.ts)types.ts) - Add conversion utilities onlyTechnical Approach
Core Changes:
Data Model Compatibility:
Blocktype interfaceconvertBlocksToTipTapJSON(blocks: Block[]): JSONContentconvertTipTapJSONToBlocks(content: JSONContent): Block[]Implementation Tasks
Phase 1: Setup & Dependencies (1 hour)
@tiptap/react,@tiptap/pm,@tiptap/core@tiptap/extension-document,@tiptap/extension-paragraph,@tiptap/extension-text,@tiptap/extension-heading,@tiptap/extension-bullet-list,@tiptap/extension-ordered-list,@tiptap/extension-list-item,@tiptap/extension-code-block,@tiptap/extension-blockquote,@tiptap/extension-horizontal-rule@tiptap/extension-mention,@tiptap/suggestionPhase 2: Core Editor Migration (2 hours)
Editor.tsxwithuseEditorhookconvertNoteToTipTapJSONfunctionconvertTipTapJSONToBlocksfunctionPhase 3: Custom Extensions (1.5 hours)
CustomBlockExtensionusingNodeViewComponentPhase 4: Slash Commands (0.5 hours)
suggestionpluginPhase 5: Mention System (0.5 hours)
MentionExtensionfor note referencesPhase 6: Integration & Testing (1 hour)
Phase 7: Cleanup (0.5 hours)
Migration Strategy
Recommended Approach: Complete Refactor
Timeline: 4-6 hours development
Risk: Medium (large changes, but well-tested library)
Benefit: Clean slate with full TipTap features
Steps:
Alternative: Gradual Migration
Timeline: 2-3 days (part-time)
Risk: Low (easier to debug, can rollback)
Benefit: Incremental validation
Steps:
Expected Outcomes
Code Reduction
Solved Issues
Technical Constraints
Related Issues
Estimated Effort
Acceptance Criteria
Success Metrics
Notes