realtimecursor
Version:
Real-time collaboration system with cursor tracking and approval workflow
253 lines (210 loc) • 6.16 kB
Markdown
A lightweight library for real-time cursor tracking and collaboration in web applications.
- 🖱️ Real-time cursor tracking
- 👥 Collaborator presence
- 📝 Content synchronization
- ⌨️ Typing indicators
- 🔄 Automatic reconnection
- 🎨 Customizable cursors and colors
```bash
npm install realtimecursor
yarn add realtimecursor
```
```javascript
import { RealtimeCursor } from 'realtimecursor';
// Initialize the cursor client
const cursor = new RealtimeCursor({
projectId: 'your-project-id',
user: {
id: 'user-123',
name: 'John Doe',
color: '#3b82f6'
}
});
// Connect to the real-time service
cursor.connect();
// Set up event handlers
cursor.on('connect', () => {
console.log('Connected to real-time service');
});
cursor.on('collaborators-changed', (collaborators) => {
console.log('Active collaborators:', collaborators);
});
cursor.on('cursors-changed', (cursors) => {
console.log('Cursor positions:', cursors);
});
// Update cursor position
document.addEventListener('mousemove', (e) => {
const editorElement = document.getElementById('editor');
const rect = editorElement.getBoundingClientRect();
cursor.updateCursor({
x: e.clientX,
y: e.clientY,
relativeX: e.clientX - rect.left,
relativeY: e.clientY - rect.top
});
});
// Update content
document.getElementById('editor').addEventListener('input', (e) => {
cursor.updateContent(e.target.value);
cursor.updateTypingStatus(true);
// Reset typing status after 2 seconds
setTimeout(() => {
cursor.updateTypingStatus(false);
}, 2000);
});
// Disconnect when done
window.addEventListener('beforeunload', () => {
cursor.disconnect();
});
```
```jsx
import React, { useState, useRef, useEffect } from 'react';
import { useRealtimeCursor } from 'realtimecursor';
function CollaborativeEditor() {
const [content, setContent] = useState('');
const editorRef = useRef(null);
const {
cursors,
collaborators,
connected,
typingStatus,
connect,
disconnect,
updateCursor,
updateContent,
updateTypingStatus
} = useRealtimeCursor({
projectId: 'your-project-id',
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 when changed
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>Connection status: {connected ? 'Connected' : 'Disconnected'}</div>
<div>Active collaborators: {collaborators.length}</div>
<div
ref={editorRef}
onMouseMove={handleMouseMove}
style={{ position: 'relative' }}
>
<textarea
value={content}
onChange={handleContentChange}
placeholder="Start typing..."
/>
{/* Render cursors */}
{Object.values(cursors).map(cursor => (
<div
key={cursor.id}
style={{
position: 'absolute',
left: cursor.position.x || cursor.position.relativeX || 0,
top: cursor.position.y || cursor.position.relativeY || 0,
pointerEvents: 'none'
}}
>
<div
style={{
backgroundColor: cursor.user.color || '#3b82f6',
padding: '2px 6px',
borderRadius: '4px',
color: 'white',
fontSize: '12px'
}}
>
{cursor.user.name}
{typingStatus[cursor.id]?.isTyping && ' (typing...)'}
</div>
</div>
))}
</div>
</div>
);
}
```
```typescript
const cursor = new RealtimeCursor(options);
```
- `apiUrl` (string): URL of the RealtimeCursor API server (defaults to hosted service)
- `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
#### Methods
- `connect()`: Connect to the real-time service
- `disconnect()`: Disconnect from the real-time service
- `updateCursor(position)`: Update cursor position
- `updateContent(content)`: Update content
- `updateTypingStatus(isTyping)`: Update typing status
- `on(event, callback)`: Add event listener
- `off(event, callback)`: Remove event listener
- `getCollaborators()`: Get all collaborators
- `getCursors()`: Get all cursors
- `getTypingStatus()`: Get typing status
- `isConnected()`: Get connection status
#### Events
- `connect`: Emitted when connected to the service
- `disconnect`: Emitted when disconnected from the service
- `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
```typescript
const {
cursors,
collaborators,
connected,
typingStatus,
connect,
disconnect,
updateCursor,
updateContent,
updateTypingStatus
} = useRealtimeCursor(options);
```
MIT