Package Exports
- @jitword/collab-editor
- @jitword/collab-editor/dist/style.css
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