realtimecursor-sdk-fixed
v1.1.0
Published
Fixed version of RealtimeCursor SDK for real-time collaboration
Maintainers
Readme
RealtimeCursor SDK - Fixed Version (v1.1.0)
A lightweight SDK for adding real-time cursor tracking and collaboration features to your web applications.
Features
- Real-time cursor tracking
- Collaborator presence
- Content synchronization
- React hooks and components
- Vanilla JavaScript support
Installation
npm install realtimecursor-sdk-fixedUsage
React
import React, { useState, useRef, useEffect } from 'react';
import { useRealtimeCursor, CursorOverlay, CollaboratorsList } from 'realtimecursor-sdk-fixed';
import 'realtimecursor-sdk-fixed/dist/cursor.css';
function CollaborativeEditor() {
const [content, setContent] = useState('');
const editorRef = useRef(null);
const {
cursors,
collaborators,
updateCursor,
updateContent,
connect,
disconnect
} = useRealtimeCursor({
apiUrl: 'http://localhost:3001',
projectId: 'your-project-id',
user: {
id: 'user-123',
name: 'John Doe',
color: '#3b82f6' // Optional
}
});
// 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);
};
return (
<div className="collaborative-editor">
<h2>Collaborative Editor</h2>
<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} />
</div>
</div>
);
}Vanilla JavaScript
import { RealtimeCursor } from 'realtimecursor-sdk-fixed';
import 'realtimecursor-sdk-fixed/dist/cursor.css';
// Initialize the cursor client
const cursorClient = new RealtimeCursor({
apiUrl: 'http://localhost:3001',
projectId: 'your-project-id',
user: {
id: 'user-123',
name: 'John Doe',
color: '#3b82f6' // Optional
}
});
// Connect to the real-time service
cursorClient.connect();
// Set up event handlers
cursorClient.onConnect = () => {
console.log('Connected to real-time service');
};
cursorClient.onDisconnect = () => {
console.log('Disconnected from real-time service');
};
cursorClient.onCursorsChange = (cursors) => {
console.log('Cursors updated:', cursors);
renderCursors(cursors);
};
cursorClient.onCollaboratorsChange = (collaborators) => {
console.log('Collaborators updated:', collaborators);
renderCollaborators(collaborators);
};
cursorClient.onContentUpdate = (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 when changed
document.getElementById('editor').addEventListener('input', (e) => {
cursorClient.updateContent(e.target.value);
});
// Disconnect when done
window.addEventListener('beforeunload', () => {
cursorClient.disconnect();
});
// Helper functions to render cursors and collaborators
function renderCursors(cursors) {
const container = document.getElementById('cursors-container');
container.innerHTML = '';
Object.values(cursors).forEach(cursor => {
const cursorElement = document.createElement('div');
cursorElement.className = 'realtimecursor-cursor';
cursorElement.style.left = `${cursor.position.x || cursor.position.relativeX || 0}px`;
cursorElement.style.top = `${cursor.position.y || cursor.position.relativeY || 0}px`;
// Add cursor SVG and label
cursorElement.innerHTML = `
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" style="transform: rotate(-45deg)">
<path d="M1 1L11 11V19L7 21V13L1 1Z" fill="${cursor.user.color || '#3b82f6'}" stroke="white" stroke-width="1" />
</svg>
<div class="realtimecursor-label" style="background-color: ${cursor.user.color || '#3b82f6'}">
${cursor.user.name}
</div>
`;
container.appendChild(cursorElement);
});
}
function renderCollaborators(collaborators) {
const container = document.getElementById('collaborators-container');
container.innerHTML = '';
if (collaborators.length === 0) {
container.innerHTML = '<div class="realtimecursor-no-collaborators">No active collaborators</div>';
return;
}
collaborators.forEach(user => {
const userElement = document.createElement('div');
userElement.className = 'realtimecursor-collaborator';
userElement.innerHTML = `
<div class="realtimecursor-collaborator-avatar" style="background-color: ${user.color || '#3b82f6'}">
${user.name ? user.name.charAt(0).toUpperCase() : '?'}
</div>
<div class="realtimecursor-collaborator-name">
${user.name}
</div>
`;
container.appendChild(userElement);
});
}API Reference
RealtimeCursor Class
const cursorClient = new RealtimeCursor(options);Options
apiUrl(string): URL of the RealtimeCursor API serverprojectId(string): Unique identifier for the projectuser(object): User informationid(string): Unique identifier for the username(string): Display name for the usercolor(string, optional): Color for the user's cursor (hex code)
Methods
connect(): Connect to the real-time servicedisconnect(): Disconnect from the real-time serviceupdateCursor(position): Update cursor positionposition(object): Cursor positionx(number, optional): Absolute X positiony(number, optional): Absolute Y positionrelativeX(number, optional): Relative X position within containerrelativeY(number, optional): Relative Y position within containertextPosition(number, optional): Position in text (for text editors)
updateContent(content, version): Update contentcontent(string): New contentversion(number, optional): Content version
Event Handlers
onConnect: Called when connected to the serviceonDisconnect: Called when disconnected from the serviceonCursorsChange(cursors): Called when cursors are updatedonCollaboratorsChange(collaborators): Called when collaborators list changesonContentUpdate(data): Called when content is updated by another useronUserJoined(user): Called when a user joinsonUserLeft(user): Called when a user leavesonError(error): Called when an error occurs
useRealtimeCursor Hook
const {
cursors,
collaborators,
connected,
connect,
disconnect,
updateCursor,
updateContent
} = useRealtimeCursor(options);Returns
cursors(object): Map of cursor objects by user IDcollaborators(array): List of active collaboratorsconnected(boolean): Connection statusconnect(): Function to connect to the servicedisconnect(): Function to disconnect from the serviceupdateCursor(position): Function to update cursor positionupdateContent(content, version): Function to update content
CursorOverlay Component
<CursorOverlay cursors={cursors} containerRef={containerRef} />Props
cursors(object): Map of cursor objects by user IDcontainerRef(React.RefObject, optional): Reference to the container element
CollaboratorsList Component
<CollaboratorsList collaborators={collaborators} />Props
collaborators(array): List of active collaborators
Backend Server
This SDK requires a backend server for real-time communication. The server is included in the package and can be started with:
cd api
npm install
npm startLicense
MIT
