@jitword/collab-editor
v1.0.4
Published
A comprehensive collaborative editor SDK with real-time collaboration features. Drop it into any Vue application and get a full-featured editor with Notion-like experience.
Downloads
494
Maintainers
Readme
@jitword/collab-editor
A comprehensive, production-ready collaborative editor SDK built with Vue 3 and Tiptap. Drop it into any Vue application and get a full-featured editor with real-time collaboration support.
✨ Features
- 📝 Rich Text Editing - Full WYSIWYG editor with Notion-like experience
- 👥 Real-time Collaboration - Built-in collaborative editing support
- 🎨 Categorized Toolbar - Organized tools (Home, Insert, View, Export)
- 📋 Table of Contents - Auto-generated document outline with smooth scrolling
- 📊 Word Count - Real-time paragraph and character statistics
- 🤖 AI Integration Ready - Events for AI writing, version control, and sharing
- ⌨️ Keyboard Shortcuts - Command+S (Mac) / Ctrl+S (Windows) to save
- 📱 Responsive Design - Works seamlessly on desktop, tablet, and mobile
- 🎯 Highly Configurable - Control every feature via props
- 🔌 Event-Driven - Emit events for business logic integration
- 💅 Beautiful UI - Based on Arco Design system
- ✨ Built-in Modals - Share, AI Writer, and Document Management modals included
- 🚀 Out-of-the-Box - Share and Read Mode work automatically
🏗️ Architecture Principles
🔐 Security: API keys and authentication stay in your code
🔌 Flexible: Supports any collaboration backend (Yjs, Socket.io, custom, etc.)
📦 Lightweight: SDK doesn't include specific network libraries
🎯 Clear Responsibilities: SDK handles UI, you handle data
📦 Installation
# Using npm
npm install @jitword/collab-editor vue
# Using yarn
yarn add @jitword/collab-editor vue
# Using pnpm
pnpm add @jitword/collab-editor vueNote: @arco-design/web-vue is a peer dependency and will be installed automatically. All collaboration dependencies (yjs, y-websocket, @tiptap/extension-collaboration) are bundled in the package.
🚀 Quick Start
1. Import Styles and Register Components
// main.js
import { createApp } from 'vue'
import ArcoVue from '@arco-design/web-vue'
import '@arco-design/web-vue/dist/arco.css'
import '@jitword/collab-editor/dist/style.css'
import App from './App.vue'
const app = createApp(App)
app.use(ArcoVue)
app.mount('#app')2. Basic Usage (Out-of-the-Box)
The simplest way to use the editor with built-in features:
<template>
<CollabEditorApp
v-model="content"
:config="editorConfig"
:onlineUsers="onlineUsers"
:currentDocumentId="currentDocId"
@ai-generate="handleAIGenerate"
@editor-ready="handleEditorReady"
style="height: 100vh;"
/>
</template>
<script setup>
import { ref } from 'vue'
import { CollabEditorApp, NotionKit } from '@jitword/collab-editor'
const content = ref({
type: 'doc',
content: [
{
type: 'paragraph',
content: [{ type: 'text', text: 'Start editing...' }]
}
]
})
const onlineUsers = ref([
{ id: 1, name: 'Alice', color: '3b82f6' },
{ id: 2, name: 'Bob', color: '10b981' }
])
const currentDocId = ref('doc-123')
const editorConfig = {
appTitle: 'My Collaborative Editor',
documentTitle: 'Untitled Document',
roomName: 'my-room', // For share modal display
enableAI: true,
enableShare: true,
enableReadMode: true,
enableDocumentList: true,
showOnlineUsers: true,
extensions: [NotionKit]
}
// Handle AI generation (only business logic needed)
const handleAIGenerate = async ({ prompt, editor }) => {
// Call your AI API
const result = await callYourAIService(prompt)
// Insert into editor
editor.commands.insertContent(result)
}
const handleEditorReady = (editor) => {
console.log('Editor ready:', editor)
}
</script>What you get automatically:
- ✅ Share button → Opens built-in share modal with QR code
- ✅ AI button → Opens built-in AI writer modal
- ✅ Read Mode button → Opens
/read/{docId}in new tab - ✅ Online users display in header
- ✅ All UI components styled and ready
📚 API Reference
Props
v-model (Object | String)
The editor content. Can be ProseMirror JSON or HTML string.
const content = ref({
type: 'doc',
content: [/* ... */]
})config (Object)
Editor configuration object.
| Property | Type | Default | Description |
|----------|------|---------|-------------|
| appTitle | String | 'JitWord 协同文档' | Application title (desktop) |
| appTitleShort | String | 'JitWord' | Short title (mobile) |
| documentTitle | String | '未命名文档' | Current document title |
| enableAI | Boolean | true | Show AI writing button |
| enableVersions | Boolean | true | Show version history button |
| enableShare | Boolean | true | Show share button |
| enableReadMode | Boolean | true | Show read mode button |
| enableAISettings | Boolean | true | Show AI settings button |
| enableDocumentList | Boolean | false | Show document list button |
| enableCreateDocument | Boolean | false | Show create document button |
| createDocumentTooltip | String | '新建文档' | Tooltip for create button |
| showOnlineUsers | Boolean | true | Display online users |
| hideToc | Boolean | false | Hide table of contents |
| hideFooter | Boolean | false | Hide footer (word count) |
| hideHeader | Boolean | false | Hide header bar |
| hideToolbar | Boolean | false | Hide formatting toolbar |
| hideBubbleMenu | Boolean | false | Hide bubble menu |
| editable | Boolean | true | Allow editing |
| locale | String | 'en' | Editor locale |
| theme | String | 'light' | Editor theme |
| isMobile | Boolean | false | Mobile mode |
| isTablet | Boolean | false | Tablet mode |
| aiWriterBusy | Boolean | false | AI writer loading state |
| extensions | Array | [NotionKit] | Tiptap extensions |
| uploadFn | Function | null | Custom file upload handler |
| defaultCategory | String | 'home' | Default toolbar category |
| pageWidth | Number | 210 | Page width (mm) |
| pageHeight | Number | 297 | Page height (mm) |
| marginTop | Number | 25.4 | Top margin (mm) |
| marginRight | Number | 31.7 | Right margin (mm) |
| marginBottom | Number | 25.4 | Bottom margin (mm) |
| marginLeft | Number | 31.7 | Left margin (mm) |
| readMode | Boolean | false | Enable read-only mode (hides toolbar, shows simple header) |
| readModeBadgeText | String | 'Read-only Mode' | Badge text shown in read mode |
Built-in Modal Configuration:
| Property | Type | Default | Description |
|----------|------|---------|-------------|
| useBuiltinModals | Boolean | true | Enable all built-in modals |
| roomName | String | '' | Room name (shown in share modal) |
| shareConfig | Object | {} | Share modal configuration (see below) |
| aiConfig | Object | {} | AI modal configuration (see below) |
| aiSettingsConfig | Object | {} | AI Settings modal configuration (see below) |
| versionConfig | Object | {} | Version History modal configuration (see below) |
| docsConfig | Object | {} | Document drawer configuration (see below) |
| getReadModeUrl | Function | null | Custom read mode URL generator |
| onReadModeClick | Function | null | Custom read mode handler |
onlineUsers (Array)
Array of online users for collaboration display.
const onlineUsers = ref([
{ id: 1, name: 'Alice', color: '3b82f6' }, // No # prefix
{ id: 2, name: 'Bob', color: '10b981' }
])documents (Array)
Array of documents for built-in document drawer.
const documents = ref([
{ id: 'doc-1', name: 'My Document', updatedAt: Date.now() },
{ id: 'doc-2', name: 'Another Doc', updatedAt: Date.now() - 3600000 }
])currentDocumentId (String)
Current document ID (required for read mode and document drawer).
const currentDocumentId = ref('doc-123')isTrashView (Boolean)
Whether document drawer is showing trash view.
documentsLoading (Boolean)
Loading state for document drawer.
Events
Editor Events
| Event | Payload | Description |
|-------|---------|-------------|
| update:modelValue | content | Emitted when content changes |
| editor-ready | editor | Emitted when editor is initialized |
Header Button Events
| Event | Payload | Description |
|-------|---------|-------------|
| ai-click | { editor } | AI writing button clicked (custom mode) |
| version-click | { editor } | Version history button clicked |
| share-click | { editor } | Share button clicked (custom mode) |
| ai-settings-click | { editor } | AI settings button clicked |
| read-mode-click | { editor } | Read mode button clicked (custom mode) |
| document-list-click | { editor } | Document list button clicked (custom mode) |
| create-document-click | { editor } | Create document button clicked |
| mobile-menu-select | value | Mobile menu item selected |
Built-in Modal Events
| Event | Payload | Description |
|-------|---------|-------------|
| ai-generate | { prompt, editor } | User requested AI generation |
| toggle-trash | - | Toggle trash view in document drawer |
| select-document | docId | Document selected from drawer |
| create-document | - | Create new document requested |
| delete-document | docId | Soft delete document (move to trash) |
| restore-document | docId | Restore document from trash |
| permanent-delete-document | docId | Permanently delete document |
| rename-document | docId, newName, onSuccess | Rename document |
| save | { editor, content, currentDocumentId } | Save triggered by keyboard shortcut (Cmd+S / Ctrl+S) |
| version-restore | content | Version restored, update editor content |
| version-create | { documentId, content, title, description, isAutoSave, author } | Version created successfully |
| version-update | { documentId, versionId, title, description } | Version metadata updated |
| version-delete | { documentId, versionId, version } | Version deleted |
| version-preview | { documentId, versionId, version, content } | Version previewed |
Slots
#headerLeftActions
Add custom actions to the left side of the header (after built-in buttons).
<CollabEditorApp>
<template #headerLeftActions>
<a-button @click="customAction">Custom</a-button>
</template>
</CollabEditorApp>#headerMiddleActions
Add custom actions to the middle of the header (after version button).
#headerMobileMenuItems
Add custom items to the mobile dropdown menu.
#modals
Add custom modal components with access to editor and config.
<CollabEditorApp>
<template #modals="{ editor, config }">
<YourCustomModal :editor="editor" />
</template>
</CollabEditorApp>🔌 Integration Examples
Built-in Modals (Recommended)
The SDK includes fully-functional modals for common features. Just provide the data and handle the events:
<template>
<CollabEditorApp
v-model="content"
:config="editorConfig"
:onlineUsers="onlineUsers"
:documents="documents"
:currentDocumentId="currentDocId"
:isTrashView="isTrashView"
:documentsLoading="docsLoading"
@ai-generate="handleAIGenerate"
@rename-document="handleRenameDocument"
@delete-document="handleDeleteDocument"
@restore-document="handleRestoreDocument"
@select-document="handleSelectDocument"
/>
</template>
<script setup>
import { ref } from 'vue'
import { CollabEditorApp } from '@jitword/collab-editor'
const currentDocId = ref('doc-123')
const documents = ref([
{ id: 'doc-1', name: 'Project Proposal', updatedAt: Date.now() },
{ id: 'doc-2', name: 'Meeting Notes', updatedAt: Date.now() - 86400000 }
])
const isTrashView = ref(false)
const docsLoading = ref(false)
const editorConfig = {
roomName: 'my-room',
enableDocumentList: true,
enableShare: true,
enableAI: true,
// Customize modals
shareConfig: {
showQRCode: true,
enableReadLink: true, // Enable read-only link tab
editLinkLabel: '✏️ Edit Link',
readLinkLabel: '👁️ Read-only Link',
editDescription: 'Share this link with others to collaborate in real-time:',
readDescription: 'Share this read-only link. Others can only view the document:',
showStats: true
},
aiConfig: {
placeholder: 'Describe what you want to write...',
quickPrompts: [
{ icon: '📝', label: 'Write', value: 'Write a professional email' }
]
},
aiSettingsConfig: {
title: '⚙️ AI Settings',
okText: 'Save Settings',
apiKeyPlaceholder: 'Enter your API key',
hint: '🔒 Your API keys are stored locally in your browser',
storageKey: 'my_app_ai_settings',
autoSave: false
},
docsConfig: {
title: 'My Documents',
enableRename: true,
enableDelete: true,
enableTrash: true
}
}
// Handle AI generation
const handleAIGenerate = async ({ prompt, editor }) => {
const response = await fetch('/api/ai/generate', {
method: 'POST',
body: JSON.stringify({ prompt })
})
const { text } = await response.json()
editor.commands.insertContent(text)
}
// Handle document rename
const handleRenameDocument = async (docId, newName, onSuccess) => {
const response = await fetch(`/api/documents/${docId}`, {
method: 'PATCH',
body: JSON.stringify({ name: newName })
})
if (response.ok) {
// Update local state
const doc = documents.value.find(d => d.id === docId)
if (doc) doc.name = newName
// Notify success (closes edit mode)
onSuccess()
}
}
// Handle document delete
const handleDeleteDocument = async (docId) => {
await fetch(`/api/documents/${docId}`, { method: 'DELETE' })
// Reload documents
loadDocuments()
}
// Handle document restore
const handleRestoreDocument = async (docId) => {
await fetch(`/api/documents/${docId}/restore`, { method: 'POST' })
loadDocuments()
}
// Handle document select
const handleSelectDocument = (docId) => {
currentDocId.value = docId
router.push(`/editor/${docId}`)
}
</script>Custom Modals (Advanced)
If you need complete control, use custom modals:
<CollabEditorApp
v-model="content"
:config="{ useBuiltinModals: false }"
@ai-click="customAIModal = true"
@share-click="customShareModal = true"
>
<template #modals="{ editor, config }">
<MyCustomAIModal v-model:visible="customAIModal" :editor="editor" />
<MyCustomShareModal v-model:visible="customShareModal" />
</template>
</CollabEditorApp>Read Mode Integration
The SDK handles read mode automatically:
Default behavior (opens /read/{docId}):
<CollabEditorApp
:currentDocumentId="currentDocId"
:config="{ enableReadMode: true }"
/>Using built-in read mode UI (simple header, no toolbar):
<CollabEditorApp
v-model="content"
:config="{
readMode: true,
documentTitle: 'My Document',
readModeBadgeText: 'Read-only Mode',
editable: false // Disable editing
}"
/>What happens in read mode:
- ❌ Toolbar is hidden
- ❌ Header buttons are hidden
- ❌ Table of contents sidebar is hidden
- ❌ Footer is hidden
- ✅ Simple header with document title and "Read-only" badge
- ✅ Document statistics (paragraphs & characters)
- ✅ Clean, distraction-free reading experience
Custom URL pattern:
const editorConfig = {
enableReadMode: true,
getReadModeUrl: (docId) => `/documents/${docId}/preview`
}Custom handler (e.g., open modal instead):
const editorConfig = {
enableReadMode: true,
onReadModeClick: ({ editor, currentDocumentId }) => {
showReadModeModal.value = true
}
}Real-time Collaboration with Yjs
All collaboration dependencies are bundled! No need to install yjs, y-websocket, or Tiptap extensions separately.
import {
CollabEditorApp,
Y, // Yjs CRDT
WebsocketProvider, // WebSocket provider
Collaboration, // Tiptap extension
CollaborationCursor // Collaborative cursors
} from '@jitword/collab-editor'
const ydoc = new Y.Doc()
const provider = new WebsocketProvider(
'wss://your-websocket-server.com',
'document-id',
ydoc
)
// Update online users from provider awareness
provider.awareness.on('change', () => {
const states = Array.from(provider.awareness.getStates().entries())
onlineUsers.value = states.map(([clientID, state]) => ({
id: clientID,
name: state.user?.name || `User ${clientID}`,
color: state.user?.color || '3b82f6'
}))
})
const editorConfig = {
// ... other config
extensions: [
NotionKit,
Collaboration.configure({ document: ydoc }),
CollaborationCursor.configure({ provider })
]
}Custom File Upload
const editorConfig = {
// ... other config
uploadFn: async (file) => {
const formData = new FormData()
formData.append('file', file)
const response = await fetch('https://your-api.com/upload', {
method: 'POST',
headers: {
'Authorization': `Bearer ${yourToken}`
},
body: formData
})
const data = await response.json()
return data.url // Return the uploaded file URL
}
}AI Integration
const handleAIClick = async ({ editor }) => {
// Get selected text
const { from, to } = editor.state.selection
const selectedText = editor.state.doc.textBetween(from, to, ' ')
// Call your AI service
const response = await fetch('https://your-ai-api.com/complete', {
method: 'POST',
headers: {
'Authorization': `Bearer ${yourAIKey}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
prompt: selectedText,
context: 'improve_writing'
})
})
const result = await response.json()
// Insert AI response
editor.chain().focus().insertContent(result.text).run()
}AI Settings Modal
The built-in AI Settings modal allows users to configure their AI provider, model, and API key:
const editorConfig = {
enableAISettings: true, // Show AI Settings button
aiSettingsConfig: {
title: '⚙️ AI Settings',
okText: 'Save Settings',
cancelText: 'Cancel',
apiKeyPlaceholder: 'Enter your API key (saved locally)',
hint: '🔒 Your API keys are stored locally in your browser and never sent to our servers',
storageKey: 'my_app_ai_settings', // localStorage key for settings
autoSave: false // false = manual save, true = auto-save on change
}
}Features:
- Provider selection (DeepSeek, Kimi, OpenAI, Custom)
- Model selection (auto-updates based on provider)
- API key management (stored in localStorage)
- Custom base URL for OpenAI-compatible endpoints
- Temperature control (0-2)
- Secure local storage (never sent to servers)
Usage:
- User clicks "AI Settings" button in header
- Modal opens with current settings
- User configures provider, model, and API key
- Settings are saved to localStorage
- AI Writer modal uses these settings for generation
Version History Modal
The built-in Version History modal provides a complete version control system with create, restore, preview, edit, and delete operations:
<template>
<CollabEditorApp
v-model="content"
:config="editorConfig"
:currentDocumentId="currentDocId"
@version-restore="handleVersionRestore"
@version-create="handleVersionCreate"
@version-update="handleVersionUpdate"
@version-delete="handleVersionDelete"
@version-preview="handleVersionPreview"
/>
</template>
<script setup>
import { ref } from 'vue'
import { CollabEditorApp, Message } from '@jitword/collab-editor'
const currentDocId = ref('doc-123')
const content = ref({ type: 'doc', content: [] })
const editorConfig = {
enableVersions: true, // Show Versions button
versionConfig: {
title: 'Version History',
saveButtonText: 'Save Version',
emptyText: 'No version history yet',
autoSaveLabel: 'Auto',
restoreText: 'Restore',
editText: 'Edit Info',
deleteText: 'Delete',
previewText: 'Preview',
loadMoreText: 'Load More',
// Required: Load versions from your backend
onLoadVersions: async (documentId, page, pageSize) => {
const response = await fetch(
`/api/documents/${documentId}/versions?page=${page}&pageSize=${pageSize}`
)
const data = await response.json()
return {
versions: data.versions.map(v => ({
id: v.id,
title: v.title,
description: v.description,
createdAt: v.createdAt, // ISO string
author: v.author,
size: v.size, // bytes
isAutoSave: v.isAutoSave // boolean
})),
total: data.total
}
},
// Required: Create new version
onCreateVersion: async (versionData) => {
await fetch(`/api/documents/${versionData.documentId}/versions`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
content: versionData.content,
title: versionData.title,
description: versionData.description,
isAutoSave: versionData.isAutoSave
})
})
},
// Required: Get version content for preview/restore
onGetVersion: async (documentId, versionId) => {
const response = await fetch(
`/api/documents/${documentId}/versions/${versionId}`
)
const data = await response.json()
return data.content // ProseMirror JSON or HTML
},
// Required: Restore version
onRestoreVersion: async (content) => {
// Update editor with restored content
// This is typically handled in the event handler below
},
// Optional: Update version metadata
onUpdateVersion: async (updateData) => {
await fetch(
`/api/documents/${updateData.documentId}/versions/${updateData.versionId}`,
{
method: 'PATCH',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
title: updateData.title,
description: updateData.description
})
}
)
},
// Optional: Delete version
onDeleteVersion: async (documentId, versionId) => {
await fetch(
`/api/documents/${documentId}/versions/${versionId}`,
{ method: 'DELETE' }
)
}
}
}
// Handle version restore - update editor content
const handleVersionRestore = (content) => {
// Update the editor with restored version
content.value = content
Message.success('Version restored successfully!')
}
// Handle version create - track in analytics
const handleVersionCreate = (versionData) => {
console.log('Version created:', versionData)
// Optional: Send analytics, update UI, etc.
}
// Handle version update - track metadata changes
const handleVersionUpdate = (updateData) => {
console.log('Version updated:', updateData)
}
// Handle version delete - cleanup
const handleVersionDelete = (deleteData) => {
console.log('Version deleted:', deleteData)
}
// Handle version preview - track which versions users view
const handleVersionPreview = (previewData) => {
console.log('Version previewed:', previewData)
}
</script>Features:
- ✅ Create new versions with title and description
- ✅ Preview versions in modal
- ✅ Restore to any previous version
- ✅ Edit version metadata (title, description)
- ✅ Delete versions with confirmation
- ✅ Auto-save label for automatic backups
- ✅ Pagination with "Load More"
- ✅ Version statistics (creation time, author, size)
Version Events:
| Event | Payload | Description |
|-------|---------|-------------|
| @version-restore | content (Object) | Emitted when user restores a version. Update your editor content. |
| @version-create | { documentId, content, title, description, isAutoSave, author } | Emitted after version is created. Use for analytics. |
| @version-update | { documentId, versionId, title, description } | Emitted when version metadata is updated. |
| @version-delete | { documentId, versionId, version } | Emitted when version is deleted. Handle cleanup. |
| @version-preview | { documentId, versionId, version, content } | Emitted when user previews a version. Track analytics. |
How it works:
- User clicks "Versions" button in header → Opens drawer
- SDK calls
onLoadVersions()to fetch version list - User clicks "Save Version" → SDK calls
onCreateVersion()→ Emits@version-create - User clicks "Preview" → SDK calls
onGetVersion()→ Shows modal → Emits@version-preview - User clicks "Restore" → SDK calls
onGetVersion()→ Emits@version-restore→ You update editor - User clicks "Edit Info" → Updates metadata → SDK calls
onUpdateVersion()→ Emits@version-update - User clicks "Delete" → Shows confirmation → SDK calls
onDeleteVersion()→ Emits@version-delete
Best Practices:
- Store versions in your database with documentId as foreign key
- Include metadata: title, description, author, createdAt, size
- Mark auto-saves with
isAutoSave: truefor visual distinction - Implement pagination for performance (default 10 versions per page)
- Use events for analytics and UI updates
- Handle restore by updating your
v-modelcontent
Keyboard Shortcuts
The editor supports keyboard shortcuts out of the box:
Save Document (Command+S / Ctrl+S)
The save shortcut prevents the browser's default save dialog and emits a save event:
Option 1: Handle via event listener (recommended):
<template>
<CollabEditorApp
v-model="content"
:config="editorConfig"
:currentDocumentId="currentDocId"
@save="handleSave"
/>
</template>
<script setup>
const handleSave = async ({ editor, content, currentDocumentId }) => {
// Save to your backend
await fetch(`/api/documents/${currentDocumentId}`, {
method: 'PUT',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ content })
})
// Show success message
Message.success('Document saved!')
}
</script>Option 2: Provide custom handler in config:
const editorConfig = {
// ... other config
onSave: async ({ editor, content, currentDocumentId }) => {
// Your custom save logic
await saveToDatabase(currentDocumentId, content)
showNotification('Saved!')
}
}What happens:
- User presses Command+S (Mac) or Ctrl+S (Windows/Linux)
- Browser's default save dialog is prevented
- Your save handler is called with editor instance, content, and document ID
- You can save to backend, localStorage, or any storage
🎨 Customization
Custom Theme
The SDK uses CSS variables for theming. You can override them:
:root {
--color-border-1: #e5e7eb;
--color-text-2: #6b7280;
--color-text-3: #9ca3af;
}Custom Toolbar Category
const editorConfig = {
defaultCategory: 'insert', // 'home' | 'insert' | 'view' | 'export'
// ... other config
}📱 Responsive Design
The SDK automatically adapts to different screen sizes:
const isMobile = computed(() => window.innerWidth < 768)
const isTablet = computed(() => window.innerWidth >= 768 && window.innerWidth < 1024)
const editorConfig = {
isMobile: isMobile.value,
isTablet: isTablet.value,
// ... other config
}🛠️ Development
# Install dependencies
pnpm install
# Build SDK
pnpm run build
# Watch mode (for development)
pnpm run dev
# Run example
pnpm run dev:example📄 License
MIT © JitWord
🤝 Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
🔗 Links
💡 Next Steps
After publishing v1.0.0, we'll focus on:
- 🔐 Security: Keep API keys and authentication in user code
- 🔌 Flexibility: Support any collaboration backend (Yjs, Socket.io, custom)
- 📦 Lightweight: Remove specific network libraries from SDK
- 🎯 Clear Responsibilities: SDK handles UI, users handle data pnpm install
Build SDK
pnpm run build
Watch mode (for development)
pnpm run dev
Run example
pnpm run dev:example
## 📄 License
MIT © JitWord
## 🤝 Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
## 🔗 Links
- [GitHub Repository](https://github.com/jitword/collab-editor)
- [Documentation](https://docs.jitword.com)
- [Issue Tracker](https://github.com/jitword/collab-editor/issues)
## 💡 Next Steps
After publishing v1.0.0, we'll focus on:
- 🔐 **Security**: Keep API keys and authentication in user code
- 🔌 **Flexibility**: Support any collaboration backend (Yjs, Socket.io, custom)
- 📦 **Lightweight**: Remove specific network libraries from SDK
- 🎯 **Clear Responsibilities**: SDK handles UI, users handle data