Skip to content

Editor Migration: Migrate from Custom Editor to TipTap Editor #13

Description

@akshad-exe

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)

  • Rewrite Editor.tsx with useEditor hook
  • Implement convertNoteToTipTapJSON function
  • Implement convertTipTapJSONToBlocks function
  • Remove manual cursor positioning logic
  • Remove manual block array management
  • Test basic text editing functionality

Phase 3: Custom Extensions (1.5 hours)

  • Create CustomBlockExtension using NodeViewComponent
  • Migrate block type support (text, h1, h2, h3, code, etc.)
  • Test block creation and deletion
  • Verify block styling applies correctly

Phase 4: Slash Commands (0.5 hours)

  • Implement slash command extension using TipTap's suggestion plugin
  • Configure command palette items
  • Test command triggering and selection
  • Verify keyboard navigation works

Phase 5: Mention System (0.5 hours)

  • Implement MentionExtension for note references
  • Configure mention suggestion popup
  • Style mentions in blue (matching Instagram-style)
  • Test mention insertion and autocomplete
  • Verify @ character detection

Phase 6: Integration & Testing (1 hour)

  • Connect TipTap editor to existing persistence layer
  • Test note saving and loading
  • Test category management integration
  • Verify all keyboard shortcuts work
  • Test on different browsers
  • Mobile responsiveness testing

Phase 7: Cleanup (0.5 hours)

  • Remove old editor components
  • Delete unused utility functions
  • Update documentation
  • Clean up imports

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:

  1. Install TipTap dependencies
  2. Rewrite Editor.tsx with useEditor hook
  3. Create custom extensions for blocks, mentions, slash commands
  4. Update persistence layer integration
  5. Test thoroughly
  6. Deploy

Alternative: Gradual Migration

Timeline: 2-3 days (part-time)
Risk: Low (easier to debug, can rollback)
Benefit: Incremental validation

Steps:

  1. Add TipTap alongside custom editor
  2. Migrate SlashMenu → SlashCommand extension
  3. Migrate MentionMenu → Mention extension
  4. Migrate Block rendering → NodeView
  5. 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

  • TipTap editor integrated and functional
  • All existing notes load correctly
  • Cursor positioning works without manual intervention
  • @mention system works with autocomplete
  • Slash commands display and function properly
  • Block types supported (text, h1-h3, code, lists, etc.)
  • Notes save and persist correctly
  • No console errors
  • Performance is equal or better than current implementation
  • Mobile responsiveness maintained
  • All keyboard shortcuts work
  • Undo/redo functionality works
  • Bundle size increase is acceptable (50-70KB gzipped)
  • No breaking changes to existing functionality
  • Documentation updated

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

Metadata

Metadata

Assignees

Labels

enhancementNew feature or request

Type

No type

Fields

No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions