Components
Cursor Overlay
Cursor Overlay
Overlay a cursor indicator for collaborative editing or real-time interaction.
Cursor Overlay
Try to drag over text: you will see a black cursor on the drop target: color and other styles are customizable!
Installation
npx @udecode/plate-ui@latest add cursor-overlay
Examples
'use client';
import React, { useRef } from 'react';
import { CommentsProvider } from '@udecode/plate-comments';
import { Plate, PlateProvider } from '@udecode/plate-common';
import { ELEMENT_PARAGRAPH } from '@udecode/plate-paragraph';
import { DndProvider } from 'react-dnd';
import { HTML5Backend } from 'react-dnd-html5-backend';
import { commentsUsers, myUserId } from '@/lib/plate/comments';
import { MENTIONABLES } from '@/lib/plate/mentionables';
import { plugins } from '@/lib/plate/plate-plugins';
import { cn } from '@/lib/utils';
import { CommentsPopover } from '@/components/plate-ui/comments-popover';
import { CursorOverlay } from '@/components/plate-ui/cursor-overlay';
import { FixedToolbar } from '@/components/plate-ui/fixed-toolbar';
import { FixedToolbarButtons } from '@/components/plate-ui/fixed-toolbar-buttons';
import { FloatingToolbar } from '@/components/plate-ui/floating-toolbar';
import { FloatingToolbarButtons } from '@/components/plate-ui/floating-toolbar-buttons';
import { MentionCombobox } from '@/components/plate-ui/mention-combobox';
export default function Editor() {
const containerRef = useRef(null);
const initialValue = [
{
type: ELEMENT_PARAGRAPH,
children: [{ text: 'Hello, World!' }],
},
];
return (
<DndProvider backend={HTML5Backend}>
<div className="relative">
<PlateProvider plugins={plugins} initialValue={initialValue}>
<FixedToolbar>
<FixedToolbarButtons />
</FixedToolbar>
<div className="flex">
<CommentsProvider users={commentsUsers} myUserId={myUserId}>
<div
ref={containerRef}
className={cn(
'relative flex max-w-[900px] overflow-x-auto',
'[&_.slate-start-area-top]:!h-4',
'[&_.slate-start-area-left]:!w-[64px] [&_.slate-start-area-right]:!w-[64px]'
)}
>
<Plate
editableProps={{
autoFocus: true,
className: cn(
'relative max-w-full leading-[1.4] outline-none [&_strong]:font-bold',
'!min-h-[600px] w-[900px] px-[96px] py-16'
),
}}
>
<FloatingToolbar>
<FloatingToolbarButtons />
</FloatingToolbar>
<MentionCombobox items={MENTIONABLES} />
<CursorOverlay containerRef={containerRef} />
</Plate>
</div>
<CommentsPopover />
</CommentsProvider>
</div>
</PlateProvider>
</div>
</DndProvider>
);
}
API
CursorOverlay
useCursorOverlayPositions
Types
export type SelectionRect = {
width: number;
height: number;
top: number;
left: number;
};
export type CaretPosition = {
height: number;
top: number;
left: number;
};
export type CursorState<TCursorData extends UnknownObject = UnknownObject> = {
key?: any;
selection: Range | null;
data?: TCursorData;
};
export interface CursorOverlayState<TCursorData extends Record<string, unknown>>
extends CursorState<TCursorData> {
caretPosition: CaretPosition | null;
selectionRects: SelectionRect[];
}
export type CursorData = {
style?: CSSProperties;
selectionStyle?: CSSProperties;
};