terraphim / terraphim/terraphim-ai
[Research] TipTap/ProseMirror Integration with Web Components
Nobody has claimed this yet.
- Dominant language
- Rust
- Stars
- 62
- Forks
- 5
- Avg merge
- 2h 27m
- Merged PRs (30d)
- 1
Description
Research Objective
Investigate strategies for integrating TipTap/ProseMirror rich text editor into Web Components for NovelWrapper migration.
Current State (NovelWrapper.svelte)
- Using
@paralect/novel-sveltewrapper - TipTap core with Markdown extension
- Custom Terraphim autocomplete suggestion plugin
- Configurable output format (HTML/Markdown)
- Role-based autocomplete from knowledge graph
- Connection testing and index building
Reference: desktop/src/lib/Editor/NovelWrapper.svelte
Research Questions
- How to wrap TipTap editor in Web Component?
- Shadow DOM vs Light DOM for editor content?
- How to maintain custom suggestion plugin?
- Event handling across component boundary?
- Performance implications of Web Component wrapper?
Integration Approaches
Approach 1: Light DOM Editor
Mount TipTap editor in Light DOM slot within Web Component.
Pros:
- Full TipTap functionality
- Standard CSS styling
- Plugin compatibility guaranteed
- Event handling straightforward
Cons:
- Less encapsulation
- Style leakage possible
- Not truly isolated
Implementation:
class TerraphimEditor extends HTMLElement {
connectedCallback() {
const slot = this.querySelector('slot[name="editor"]');
this.editor = new Editor({
element: slot,
extensions: [...]
});
}
}
Approach 2: Shadow DOM with adoptedStyleSheets
Mount editor in Shadow DOM, inject styles via Constructable Stylesheets.
Pros:
- True encapsulation
- Style isolation
- Component distribution
Cons:
- Need to manage all TipTap CSS
- Plugin styles may break
- contenteditable complexity
Implementation:
class TerraphimEditor extends HTMLElement {
connectedCallback() {
const shadow = this.attachShadow({ mode: 'open' });
const sheet = new CSSStyleSheet();
sheet.replaceSync(tiptapStyles);
shadow.adoptedStyleSheets = [sheet];
this.editor = new Editor({
element: shadow.querySelector('.editor'),
extensions: [...]
});
}
}
Approach 3: Iframe Isolation (Nuclear Option)
Run editor in iframe for complete isolation.
Pros:
- Maximum isolation
- No Shadow DOM issues
- Full control
Cons:
- Performance overhead
- Communication complexity
- Loading time
- Not practical for our use case
Custom Extension Migration
TerraphimSuggestion Plugin
Current: Svelte component aware, uses stores
Challenge: How to pass reactive role/suggestions to Web Component?
Solutions:
-
Properties + Events:
- Pass role as property
- Emit custom events for suggestions
- Plugin queries parent Web Component
-
Service Layer:
- Keep
novelAutocompleteServiceas singleton - Plugin calls service directly
- Web Component configures service
- Keep
-
Suggestion Provider Pattern:
- Define interface for suggestion provider
- Inject provider into plugin
- Web Component implements provider
Key Features to Maintain
From Current Implementation:
- TipTap editor with Markdown support
- Custom autocomplete with
/trigger - Knowledge graph suggestions
- HTML vs Markdown output toggle
- Read-only mode
- Connection testing
- Index building
- Role-based suggestions
- Tauri vs Web backend switching
New Requirements:
- Web Component API
- Shadow DOM compatible (if chosen)
- Accessible
- Theme-aware
- No Svelte dependencies
Technical Challenges
Challenge 1: ProseMirror DOM Manipulation
Problem: ProseMirror directly manipulates DOM, needs real DOM nodes
Solution: Use Light DOM or careful Shadow DOM setup
Challenge 2: Plugin Context
Problem: Plugins need access to app context (role, backend)
Solution: Dependency injection or context provider pattern
Challenge 3: Style Injection
Problem: TipTap styles must be available
Solution: Bundle styles with component or use adoptedStyleSheets
Challenge 4: Markdown Extension
Problem: tiptap-markdown extension compatibility
Solution: Test in Web Component context, may need wrapper
Libraries to Evaluate
1. @tiptap/core (Current)
- Status: Framework-agnostic
- Web Component support: Should work
- Action: Test compatibility
2. Alternative Editors (If TipTap Fails)
a) Quill.js
- Pros: Simpler, well-documented
- Cons: Less extensible, no Markdown native
b) ProseMirror (Direct)
- Pros: Maximum control
- Cons: Low-level, complex
c) EditorJS
- Pros: Block-based, modern
- Cons: Different paradigm, JSON output
d) CodeMirror 6
- Pros: Excellent for code/markdown
- Cons: Not WYSIWYG
Acceptance Criteria
- TipTap integration approach selected
- Shadow DOM decision documented
- Custom plugin migration path defined
- Prototype Web Component editor
- Performance comparison (render time, typing latency)
- Markdown extension compatibility verified
- Autocomplete integration working
- Accessibility verified
References
- Current editor:
desktop/src/lib/Editor/NovelWrapper.svelte - Custom plugin:
desktop/src/lib/Editor/TerraphimSuggestion.ts - Autocomplete service:
desktop/src/lib/services/novelAutocompleteService.ts
Documentation
Findings will be documented in: .docs/research-tiptap-integration.md
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Read desktop/src/lib/Editor/NovelWrapper.svelte, desktop/src/lib/Editor/TerraphimSuggestion.ts, and desktop/src/lib/services/novelAutocompleteService.ts to understand the current editor, plugin, and service boundaries. Evaluate the listed Web Component approaches and document the selected integration, Shadow DOM decision, migration path, prototype findings, compatibility, performance, accessibility, and autocomplete results in .docs/research-tiptap-integration.md.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- javascript, typescript
- Domain
- frontend, web-dev
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 30/100