UNPKG

@tldraw/editor

Version:

tldraw infinite canvas SDK (editor).

142 lines (141 loc) 5.04 kB
import { Fragment, jsx, jsxs } from "react/jsx-runtime"; import { track } from "@tldraw/state-react"; import { useEffect, useRef, useState } from "react"; import { useEditor } from "../hooks/useEditor.mjs"; import { useEditorComponents } from "../hooks/useEditorComponents.mjs"; import { usePeerIds } from "../hooks/usePeerIds.mjs"; import { usePresence } from "../hooks/usePresence.mjs"; const LiveCollaborators = track(function Collaborators() { const peerIds = usePeerIds(); return peerIds.map((id) => /* @__PURE__ */ jsx(CollaboratorGuard, { collaboratorId: id }, id)); }); const CollaboratorGuard = track(function CollaboratorGuard2({ collaboratorId }) { const editor = useEditor(); const presence = usePresence(collaboratorId); const collaboratorState = useCollaboratorState(editor, presence); if (!(presence && presence.currentPageId === editor.getCurrentPageId())) { return null; } switch (collaboratorState) { case "inactive": { const { followingUserId, highlightedUserIds } = editor.getInstanceState(); if (!(followingUserId === presence.userId || highlightedUserIds.includes(presence.userId))) { return null; } break; } case "idle": { const { highlightedUserIds } = editor.getInstanceState(); if (presence.followingUserId === editor.user.getId() && !(presence.chatMessage || highlightedUserIds.includes(presence.userId))) { return null; } break; } case "active": { break; } } return /* @__PURE__ */ jsx(Collaborator, { latestPresence: presence }); }); const Collaborator = track(function Collaborator2({ latestPresence }) { const editor = useEditor(); const { CollaboratorBrush, CollaboratorScribble, CollaboratorCursor, CollaboratorHint, CollaboratorShapeIndicator } = useEditorComponents(); const zoomLevel = editor.getZoomLevel(); const viewportPageBounds = editor.getViewportPageBounds(); const { userId, chatMessage, brush, scribbles, selectedShapeIds, userName, cursor, color } = latestPresence; if (!cursor) return null; const isCursorInViewport = !(cursor.x < viewportPageBounds.minX - 12 / zoomLevel || cursor.y < viewportPageBounds.minY - 16 / zoomLevel || cursor.x > viewportPageBounds.maxX - 12 / zoomLevel || cursor.y > viewportPageBounds.maxY - 16 / zoomLevel); return /* @__PURE__ */ jsxs(Fragment, { children: [ brush && CollaboratorBrush ? /* @__PURE__ */ jsx( CollaboratorBrush, { className: "tl-collaborator__brush", userId, brush, color, opacity: 0.1 }, userId + "_brush" ) : null, isCursorInViewport && CollaboratorCursor ? /* @__PURE__ */ jsx( CollaboratorCursor, { className: "tl-collaborator__cursor", userId, point: cursor, color, zoom: zoomLevel, name: userName !== "New User" ? userName : null, chatMessage: chatMessage ?? "" }, userId + "_cursor" ) : CollaboratorHint ? /* @__PURE__ */ jsx( CollaboratorHint, { className: "tl-collaborator__cursor-hint", userId, point: cursor, color, zoom: zoomLevel, viewport: viewportPageBounds }, userId + "_cursor_hint" ) : null, CollaboratorScribble && scribbles.length ? /* @__PURE__ */ jsx(Fragment, { children: scribbles.map((scribble) => /* @__PURE__ */ jsx( CollaboratorScribble, { className: "tl-collaborator__scribble", userId, scribble, color, zoom: zoomLevel, opacity: scribble.color === "laser" ? 0.5 : 0.1 }, userId + "_scribble_" + scribble.id )) }) : null, CollaboratorShapeIndicator && selectedShapeIds.filter((id) => !editor.isShapeHidden(id)).map((shapeId) => /* @__PURE__ */ jsx( CollaboratorShapeIndicator, { className: "tl-collaborator__shape-indicator", userId, shapeId, color, opacity: 0.5 }, userId + "_" + shapeId )) ] }); }); function getStateFromElapsedTime(editor, elapsed) { return elapsed > editor.options.collaboratorInactiveTimeoutMs ? "inactive" : elapsed > editor.options.collaboratorIdleTimeoutMs ? "idle" : "active"; } function useCollaboratorState(editor, latestPresence) { const rLastActivityTimestamp = useRef(latestPresence?.lastActivityTimestamp ?? -1); const [state, setState] = useState( () => getStateFromElapsedTime(editor, Date.now() - rLastActivityTimestamp.current) ); useEffect(() => { const interval = editor.timers.setInterval(() => { setState(getStateFromElapsedTime(editor, Date.now() - rLastActivityTimestamp.current)); }, editor.options.collaboratorCheckIntervalMs); return () => clearInterval(interval); }, [editor]); if (latestPresence) { rLastActivityTimestamp.current = latestPresence.lastActivityTimestamp ?? Infinity; } return state; } export { LiveCollaborators }; //# sourceMappingURL=LiveCollaborators.mjs.map