feat: follow mode (#6848)

Co-authored-by: dwelle <5153846+dwelle@users.noreply.github.com>
This commit is contained in:
Barnabás Molnár 2023-12-15 00:07:11 +01:00 committed by GitHub
parent 88a2b286c7
commit aad8ab0123
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
28 changed files with 1039 additions and 138 deletions

View file

@ -41,7 +41,9 @@ import { Merge, ValueOf } from "./utility-types";
export type Point = Readonly<RoughPoint>;
export type Collaborator = {
export type SocketId = string;
export type Collaborator = Readonly<{
pointer?: CollaboratorPointer;
button?: "up" | "down";
selectedElementIds?: AppState["selectedElementIds"];
@ -56,7 +58,8 @@ export type Collaborator = {
avatarUrl?: string;
// user id. If supplied, we'll filter out duplicates when rendering user avatars.
id?: string;
};
socketId?: SocketId;
}>;
export type CollaboratorPointer = {
x: number;
@ -123,6 +126,11 @@ export type ActiveTool =
export type SidebarName = string;
export type SidebarTabName = string;
export type UserToFollow = {
socketId: string;
username: string;
};
type _CommonCanvasAppState = {
zoom: AppState["zoom"];
scrollX: AppState["scrollX"];
@ -303,13 +311,16 @@ export interface AppState {
pendingImageElementId: ExcalidrawImageElement["id"] | null;
showHyperlinkPopup: false | "info" | "editor";
selectedLinearElement: LinearElementEditor | null;
snapLines: readonly SnapLine[];
originSnapOffset: {
x: number;
y: number;
} | null;
objectsSnapModeEnabled: boolean;
/** the user's clientId & username who is being followed on the canvas */
userToFollow: UserToFollow | null;
/** the clientIds of the users following the current user */
followedBy: Set<string>;
}
export type UIAppState = Omit<
@ -385,6 +396,11 @@ export type ExcalidrawInitialDataState = Merge<
}
>;
export type OnUserFollowedPayload = {
userToFollow: UserToFollow;
action: "FOLLOW" | "UNFOLLOW";
};
export interface ExcalidrawProps {
onChange?: (
elements: readonly ExcalidrawElement[],
@ -438,7 +454,8 @@ export interface ExcalidrawProps {
activeTool: AppState["activeTool"],
pointerDownState: PointerDownState,
) => void;
onScrollChange?: (scrollX: number, scrollY: number) => void;
onScrollChange?: (scrollX: number, scrollY: number, zoom: Zoom) => void;
onUserFollow?: (payload: OnUserFollowedPayload) => void;
children?: React.ReactNode;
validateEmbeddable?:
| boolean
@ -675,6 +692,12 @@ export type ExcalidrawImperativeAPI = {
event: PointerEvent,
) => void,
) => UnsubscribeCallback;
onScrollChange: (
callback: (scrollX: number, scrollY: number, zoom: Zoom) => void,
) => UnsubscribeCallback;
onUserFollow: (
callback: (payload: OnUserFollowedPayload) => void,
) => UnsubscribeCallback;
};
export type Device = Readonly<{