realtimecursor
Version:
Real-time collaboration system with cursor tracking and approval workflow
347 lines (284 loc) • 9.38 kB
Markdown
# RealtimeCursor Enhanced SDK
A user-friendly SDK for real-time cursor tracking and collaboration features.
## Features
- 🖱️ Real-time cursor tracking
- 👥 Collaborator presence
- 📝 Content synchronization
- ⌨️ Typing indicators
- 🔄 Automatic reconnection
- 🎨 Customizable cursors and colors
- ⚛️ Ready-to-use React components
- 🌐 Vanilla JavaScript support
## Installation
```bash
npm install realtimecursor-enhanced
# or
yarn add realtimecursor-enhanced
```
## Quick Start
### Option 1: Ready-to-use Collaborative Editor
The fastest way to add real-time collaboration to your app:
```jsx
import React from 'react';
import { CollaborativeEditor } from 'realtimecursor-enhanced';
import 'realtimecursor-enhanced/dist/cursor.css';
function MyEditor() {
return (
<CollaborativeEditor
apiUrl="http://localhost:3001"
projectId="my-project"
userId="user-123"
userName="John Doe"
initialContent="Start collaborating!"
onContentChange={(content) => console.log('Content changed:', content)}
height="400px"
/>
);
}
```
### Option 2: Using the React Hook
For more control over the UI:
```jsx
import React, { useState, useRef, useEffect } from 'react';
import { useRealtimeCursor, CursorOverlay, CollaboratorsList } from 'realtimecursor-enhanced';
import 'realtimecursor-enhanced/dist/cursor.css';
function CustomEditor() {
const [content, setContent] = useState('');
const editorRef = useRef(null);
const {
cursors,
collaborators,
connected,
typingStatus,
connect,
disconnect,
updateCursor,
updateContent,
updateTypingStatus
} = useRealtimeCursor({
apiUrl: 'http://localhost:3001',
projectId: 'my-project',
user: {
id: 'user-123',
name: 'John Doe',
color: '#3b82f6'
}
});
// Connect on mount
useEffect(() => {
connect();
return () => disconnect();
}, [connect, disconnect]);
// Update cursor position on mouse move
const handleMouseMove = (e) => {
if (!editorRef.current) return;
const rect = editorRef.current.getBoundingClientRect();
updateCursor({
x: e.clientX,
y: e.clientY,
relativeX: e.clientX - rect.left,
relativeY: e.clientY - rect.top
});
};
// Update content and typing status
const handleContentChange = (e) => {
const newContent = e.target.value;
setContent(newContent);
updateContent(newContent);
updateTypingStatus(true);
// Reset typing status after 2 seconds
setTimeout(() => updateTypingStatus(false), 2000);
};
return (
<div>
<div className="connection-status">
{connected ? 'Connected' : 'Disconnected'}
</div>
<div className="editor-container" ref={editorRef} onMouseMove={handleMouseMove}>
<textarea
value={content}
onChange={handleContentChange}
placeholder="Start typing..."
/>
<CursorOverlay cursors={cursors} />
</div>
<div className="collaborators-panel">
<h3>Active Collaborators ({collaborators.length})</h3>
<CollaboratorsList collaborators={collaborators} typingStatus={typingStatus} />
</div>
</div>
);
}
```
### Option 3: Vanilla JavaScript
```javascript
import { RealtimeCursor } from 'realtimecursor-enhanced';
import 'realtimecursor-enhanced/dist/cursor.css';
// Initialize the cursor client
const cursorClient = new RealtimeCursor({
apiUrl: 'http://localhost:3001',
projectId: 'my-project',
user: {
id: 'user-123',
name: 'John Doe',
color: '#3b82f6'
},
debug: true // Enable debug logging
});
// Connect to the real-time service
cursorClient.connect();
// Set up event handlers
cursorClient.on('connected', () => {
console.log('Connected to real-time service');
document.getElementById('status').textContent = 'Connected';
});
cursorClient.on('disconnected', () => {
console.log('Disconnected from real-time service');
document.getElementById('status').textContent = 'Disconnected';
});
cursorClient.on('cursors-changed', (cursors) => {
console.log('Cursors updated:', cursors);
renderCursors(cursors);
});
cursorClient.on('collaborators-changed', (collaborators) => {
console.log('Collaborators updated:', collaborators);
renderCollaborators(collaborators);
});
cursorClient.on('typing-status-changed', (typingStatus) => {
console.log('Typing status updated:', typingStatus);
updateTypingIndicators(typingStatus);
});
cursorClient.on('content-updated', (data) => {
console.log('Content updated:', data);
document.getElementById('editor').value = data.content;
});
// Update cursor position on mouse move
document.getElementById('editor-container').addEventListener('mousemove', (e) => {
const rect = e.currentTarget.getBoundingClientRect();
cursorClient.updateCursor({
x: e.clientX,
y: e.clientY,
relativeX: e.clientX - rect.left,
relativeY: e.clientY - rect.top
});
});
// Update content and typing status when changed
let typingTimeout;
document.getElementById('editor').addEventListener('input', (e) => {
cursorClient.updateContent(e.target.value);
cursorClient.updateTypingStatus(true);
// Reset typing status after 2 seconds
clearTimeout(typingTimeout);
typingTimeout = setTimeout(() => {
cursorClient.updateTypingStatus(false);
}, 2000);
});
// Disconnect when the page is closed
window.addEventListener('beforeunload', () => {
cursorClient.disconnect();
});
// Helper functions for rendering (implement these based on your UI)
function renderCursors(cursors) { /* ... */ }
function renderCollaborators(collaborators) { /* ... */ }
function updateTypingIndicators(typingStatus) { /* ... */ }
```
## API Reference
### RealtimeCursor Class
```javascript
const cursorClient = new RealtimeCursor(options);
```
#### Options
- `apiUrl` (string): URL of the RealtimeCursor API server
- `projectId` (string): Unique identifier for the project
- `user` (object): User information
- `id` (string): Unique identifier for the user
- `name` (string): Display name for the user
- `color` (string, optional): Color for the user's cursor (hex code)
- `debug` (boolean, optional): Enable debug logging
- `autoConnect` (boolean, optional): Automatically connect on initialization
#### Methods
- `connect()`: Connect to the real-time service
- `disconnect()`: Disconnect from the real-time service
- `updateCursor(position)`: Update cursor position
- `position` (object): Cursor position
- `x` (number, optional): Absolute X position
- `y` (number, optional): Absolute Y position
- `relativeX` (number, optional): Relative X position within container
- `relativeY` (number, optional): Relative Y position within container
- `textPosition` (number, optional): Position in text (for text editors)
- `updateContent(content)`: Update content
- `content` (string): New content
- `updateTypingStatus(isTyping)`: Update typing status
- `isTyping` (boolean): Whether the user is typing
- `getCollaborators()`: Get all collaborators
- `getCursors()`: Get all cursors
- `getTypingStatus()`: Get typing status
- `isConnected()`: Get connection status
#### Events
- `connected`: Emitted when connected to the service
- `disconnected`: Emitted when disconnected from the service
- `connection-error`: Emitted when a connection error occurs
- `reconnect-attempt`: Emitted when attempting to reconnect
- `reconnect-failed`: Emitted when reconnection fails
- `cursors-changed`: Emitted when cursors are updated
- `collaborators-changed`: Emitted when collaborators list changes
- `typing-status-changed`: Emitted when typing status changes
- `content-updated`: Emitted when content is updated by another user
- `user-joined`: Emitted when a user joins
- `user-left`: Emitted when a user leaves
- `error`: Emitted when an error occurs
### useRealtimeCursor Hook
```javascript
const {
cursors,
collaborators,
connected,
typingStatus,
connect,
disconnect,
updateCursor,
updateContent,
updateTypingStatus
} = useRealtimeCursor(options);
```
#### Returns
- `cursors` (object): Map of cursor objects by user ID
- `collaborators` (array): List of active collaborators
- `connected` (boolean): Connection status
- `typingStatus` (object): Map of typing status by user ID
- `connect()`: Function to connect to the service
- `disconnect()`: Function to disconnect from the service
- `updateCursor(position)`: Function to update cursor position
- `updateContent(content)`: Function to update content
- `updateTypingStatus(isTyping)`: Function to update typing status
### React Components
#### CursorOverlay
```jsx
<CursorOverlay cursors={cursors} />
```
#### CollaboratorsList
```jsx
<CollaboratorsList collaborators={collaborators} typingStatus={typingStatus} />
```
#### CollaborativeEditor
```jsx
<CollaborativeEditor
apiUrl="http://localhost:3001"
projectId="my-project"
userId="user-123"
userName="John Doe"
userColor="#3b82f6"
initialContent="Start collaborating!"
onContentChange={(content) => console.log('Content changed:', content)}
height="400px"
/>
```
## Backend Server
This SDK requires a backend server for real-time communication. The server is included in the package and can be started with:
```bash
cd api
npm install
npm start
```
## License
MIT