feat: allow host to pass color for collaborators (#2943)
* feat: allow host to pass color for collaborators * remove user prop as its not used anywhere * update changelog and readme * add pr link
This commit is contained in:
parent
86222662f2
commit
e63a0ec5be
@ -42,7 +42,7 @@ export const actionGoToCollaborator = register({
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const { background, stroke } = getClientColors(clientId);
|
const { background, stroke } = getClientColors(clientId, appState);
|
||||||
const shortName = getClientInitials(collaborator.username);
|
const shortName = getClientInitials(collaborator.username);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -1,6 +1,13 @@
|
|||||||
import colors from "./colors";
|
import colors from "./colors";
|
||||||
|
import { AppState } from "./types";
|
||||||
|
|
||||||
export const getClientColors = (clientId: string) => {
|
export const getClientColors = (clientId: string, appState: AppState) => {
|
||||||
|
if (appState?.collaborators) {
|
||||||
|
const currentUser = appState.collaborators.get(clientId);
|
||||||
|
if (currentUser?.color) {
|
||||||
|
return currentUser.color;
|
||||||
|
}
|
||||||
|
}
|
||||||
// Naive way of getting an integer out of the clientId
|
// Naive way of getting an integer out of the clientId
|
||||||
const sum = clientId.split("").reduce((a, str) => a + str.charCodeAt(0), 0);
|
const sum = clientId.split("").reduce((a, str) => a + str.charCodeAt(0), 0);
|
||||||
|
|
||||||
|
@ -281,7 +281,6 @@ function ExcalidrawWrapper() {
|
|||||||
width={dimensions.width}
|
width={dimensions.width}
|
||||||
height={dimensions.height}
|
height={dimensions.height}
|
||||||
initialData={initialStatePromiseRef.current.promise}
|
initialData={initialStatePromiseRef.current.promise}
|
||||||
user={{ name: collabAPI?.username }}
|
|
||||||
onCollabButtonClick={collabAPI?.onCollabButtonClick}
|
onCollabButtonClick={collabAPI?.onCollabButtonClick}
|
||||||
isCollaborating={collabAPI?.isCollaborating()}
|
isCollaborating={collabAPI?.isCollaborating()}
|
||||||
onPointerUpdate={collabAPI?.onPointerUpdate}
|
onPointerUpdate={collabAPI?.onPointerUpdate}
|
||||||
|
@ -18,6 +18,7 @@ Please add the latest change on the top under the correct section.
|
|||||||
|
|
||||||
### Features
|
### Features
|
||||||
|
|
||||||
|
- Allow host to pass [color](https://github.com/excalidraw/excalidraw/blob/master/src/types.ts#L36) for [collaborator](https://github.com/excalidraw/excalidraw/blob/master/src/types.ts#L27) [#2943](https://github.com/excalidraw/excalidraw/pull/2943). The unused prop `user` is now removed.
|
||||||
- Add `zenModeEnabled` and `gridModeEnabled` prop which enables zen mode and grid mode respectively [#2901](https://github.com/excalidraw/excalidraw/pull/2901). When this prop is used, the zen mode / grid mode will be fully controlled by the host app.
|
- Add `zenModeEnabled` and `gridModeEnabled` prop which enables zen mode and grid mode respectively [#2901](https://github.com/excalidraw/excalidraw/pull/2901). When this prop is used, the zen mode / grid mode will be fully controlled by the host app.
|
||||||
- Add `viewModeEnabled` prop which enabled the view mode [#2840](https://github.com/excalidraw/excalidraw/pull/2840). When this prop is used, the view mode will not show up in context menu is so it is fully controlled by host.
|
- Add `viewModeEnabled` prop which enabled the view mode [#2840](https://github.com/excalidraw/excalidraw/pull/2840). When this prop is used, the view mode will not show up in context menu is so it is fully controlled by host.
|
||||||
- Expose `getAppState` on `excalidrawRef` [#2834](https://github.com/excalidraw/excalidraw/pull/2834).
|
- Expose `getAppState` on `excalidrawRef` [#2834](https://github.com/excalidraw/excalidraw/pull/2834).
|
||||||
|
@ -106,7 +106,6 @@ export default function App() {
|
|||||||
onChange={(elements, state) => {
|
onChange={(elements, state) => {
|
||||||
console.log("Latest elements:", elements, "Latest state:", state);
|
console.log("Latest elements:", elements, "Latest state:", state);
|
||||||
}}
|
}}
|
||||||
user={{ name: "Excalidraw User" }}
|
|
||||||
onPointerUpdate={(pointerData) => console.log(pointerData)}
|
onPointerUpdate={(pointerData) => console.log(pointerData)}
|
||||||
onCollabButtonClick={() => {
|
onCollabButtonClick={() => {
|
||||||
window.alert("You clicked on collab button");
|
window.alert("You clicked on collab button");
|
||||||
@ -130,7 +129,6 @@ export default function App() {
|
|||||||
| [`offsetTop`](#offsetTop) | Number | `0` | top position relative to which Excalidraw should render |
|
| [`offsetTop`](#offsetTop) | Number | `0` | top position relative to which Excalidraw should render |
|
||||||
| [`onChange`](#onChange) | Function | | This callback is triggered whenever the component updates due to any change. This callback will receive the excalidraw elements and the current app state. |
|
| [`onChange`](#onChange) | Function | | This callback is triggered whenever the component updates due to any change. This callback will receive the excalidraw elements and the current app state. |
|
||||||
| [`initialData`](#initialData) | <pre>{elements?: <a href="https://github.com/excalidraw/excalidraw/blob/master/src/element/types.ts#L78">ExcalidrawElement[]</a>, appState?: <a href="https://github.com/excalidraw/excalidraw/blob/master/src/types.ts#L37">AppState<a> } </pre> | null | The initial data with which app loads. |
|
| [`initialData`](#initialData) | <pre>{elements?: <a href="https://github.com/excalidraw/excalidraw/blob/master/src/element/types.ts#L78">ExcalidrawElement[]</a>, appState?: <a href="https://github.com/excalidraw/excalidraw/blob/master/src/types.ts#L37">AppState<a> } </pre> | null | The initial data with which app loads. |
|
||||||
| [`user`](#user) | `{ name?: string }` | | User details. The name refers to the name of the user to be shown |
|
|
||||||
| [`excalidrawRef`](#excalidrawRef) | [`createRef`](https://reactjs.org/docs/refs-and-the-dom.html#creating-refs) or [`callbackRef`](https://reactjs.org/docs/refs-and-the-dom.html#callback-refs) or <pre>{ current: { readyPromise: <a href="https://github.com/excalidraw/excalidraw/blob/master/src/utils.ts#L317">resolvablePromise</a> } }</pre> | | Ref to be passed to Excalidraw |
|
| [`excalidrawRef`](#excalidrawRef) | [`createRef`](https://reactjs.org/docs/refs-and-the-dom.html#creating-refs) or [`callbackRef`](https://reactjs.org/docs/refs-and-the-dom.html#callback-refs) or <pre>{ current: { readyPromise: <a href="https://github.com/excalidraw/excalidraw/blob/master/src/utils.ts#L317">resolvablePromise</a> } }</pre> | | Ref to be passed to Excalidraw |
|
||||||
| [`onCollabButtonClick`](#onCollabButtonClick) | Function | | Callback to be triggered when the collab button is clicked |
|
| [`onCollabButtonClick`](#onCollabButtonClick) | Function | | Callback to be triggered when the collab button is clicked |
|
||||||
| [`isCollaborating`](#isCollaborating) | `boolean` | | This implies if the app is in collaboration mode |
|
| [`isCollaborating`](#isCollaborating) | `boolean` | | This implies if the app is in collaboration mode |
|
||||||
@ -257,10 +255,6 @@ This helps to load Excalidraw with `initialData`. It must be an object or a [pro
|
|||||||
|
|
||||||
You might want to use this when you want to load excalidraw with some initial elements and app state.
|
You might want to use this when you want to load excalidraw with some initial elements and app state.
|
||||||
|
|
||||||
#### `user`
|
|
||||||
|
|
||||||
This is the user name which shows during collaboration. Defaults to `{name: ''}`.
|
|
||||||
|
|
||||||
#### `excalidrawRef`
|
#### `excalidrawRef`
|
||||||
|
|
||||||
You can pass a `ref` when you want to access some excalidraw APIs. We expose the below APIs:
|
You can pass a `ref` when you want to access some excalidraw APIs. We expose the below APIs:
|
||||||
@ -269,7 +263,7 @@ You can pass a `ref` when you want to access some excalidraw APIs. We expose the
|
|||||||
| --- | --- | --- |
|
| --- | --- | --- |
|
||||||
| ready | `boolean` | This is set to true once Excalidraw is rendered |
|
| ready | `boolean` | This is set to true once Excalidraw is rendered |
|
||||||
| readyPromise | [resolvablePromise](https://github.com/excalidraw/excalidraw/blob/master/src/utils.ts#L317) | This promise will be resolved with the api once excalidraw has rendered. This will be helpful when you want do some action on the host app once this promise resolves. For this to work you will have to pass ref as shown [here](#readyPromise) |
|
| readyPromise | [resolvablePromise](https://github.com/excalidraw/excalidraw/blob/master/src/utils.ts#L317) | This promise will be resolved with the api once excalidraw has rendered. This will be helpful when you want do some action on the host app once this promise resolves. For this to work you will have to pass ref as shown [here](#readyPromise) |
|
||||||
| updateScene | <pre>(<a href="https://github.com/excalidraw/excalidraw/blob/master/src/types.ts#L189">sceneData</a>)) => void </pre> | updates the scene with the sceneData |
|
| updateScene | <pre>(<a href="https://github.com/excalidraw/excalidraw/blob/master/src/types.ts#L192">sceneData</a>)) => void </pre> | updates the scene with the sceneData |
|
||||||
| resetScene | `({ resetLoadingState: boolean }) => void` | Resets the scene. If `resetLoadingState` is passed as true then it will also force set the loading state to false. |
|
| resetScene | `({ resetLoadingState: boolean }) => void` | Resets the scene. If `resetLoadingState` is passed as true then it will also force set the loading state to false. |
|
||||||
| getSceneElementsIncludingDeleted | <pre> () => <a href="https://github.com/excalidraw/excalidraw/blob/master/src/element/types.ts#L78">ExcalidrawElement[]</a></pre> | Returns all the elements including the deleted in the scene |
|
| getSceneElementsIncludingDeleted | <pre> () => <a href="https://github.com/excalidraw/excalidraw/blob/master/src/element/types.ts#L78">ExcalidrawElement[]</a></pre> | Returns all the elements including the deleted in the scene |
|
||||||
| getSceneElements | <pre> () => <a href="https://github.com/excalidraw/excalidraw/blob/master/src/element/types.ts#L78">ExcalidrawElement[]</a></pre> | Returns all the elements excluding the deleted in the scene |
|
| getSceneElements | <pre> () => <a href="https://github.com/excalidraw/excalidraw/blob/master/src/element/types.ts#L78">ExcalidrawElement[]</a></pre> | Returns all the elements excluding the deleted in the scene |
|
||||||
|
@ -18,7 +18,6 @@ const Excalidraw = (props: ExcalidrawProps) => {
|
|||||||
offsetTop,
|
offsetTop,
|
||||||
onChange,
|
onChange,
|
||||||
initialData,
|
initialData,
|
||||||
user,
|
|
||||||
excalidrawRef,
|
excalidrawRef,
|
||||||
onCollabButtonClick,
|
onCollabButtonClick,
|
||||||
isCollaborating,
|
isCollaborating,
|
||||||
@ -59,7 +58,6 @@ const Excalidraw = (props: ExcalidrawProps) => {
|
|||||||
offsetTop={offsetTop}
|
offsetTop={offsetTop}
|
||||||
onChange={onChange}
|
onChange={onChange}
|
||||||
initialData={initialData}
|
initialData={initialData}
|
||||||
user={user}
|
|
||||||
excalidrawRef={excalidrawRef}
|
excalidrawRef={excalidrawRef}
|
||||||
onCollabButtonClick={onCollabButtonClick}
|
onCollabButtonClick={onCollabButtonClick}
|
||||||
isCollaborating={isCollaborating}
|
isCollaborating={isCollaborating}
|
||||||
@ -82,13 +80,12 @@ const areEqual = (
|
|||||||
prevProps: PublicExcalidrawProps,
|
prevProps: PublicExcalidrawProps,
|
||||||
nextProps: PublicExcalidrawProps,
|
nextProps: PublicExcalidrawProps,
|
||||||
) => {
|
) => {
|
||||||
const { initialData: prevInitialData, user: prevUser, ...prev } = prevProps;
|
const { initialData: prevInitialData, ...prev } = prevProps;
|
||||||
const { initialData: nextInitialData, user: nextUser, ...next } = nextProps;
|
const { initialData: nextInitialData, ...next } = nextProps;
|
||||||
|
|
||||||
const prevKeys = Object.keys(prevProps) as (keyof typeof prev)[];
|
const prevKeys = Object.keys(prevProps) as (keyof typeof prev)[];
|
||||||
const nextKeys = Object.keys(nextProps) as (keyof typeof next)[];
|
const nextKeys = Object.keys(nextProps) as (keyof typeof next)[];
|
||||||
return (
|
return (
|
||||||
prevUser?.name === nextUser?.name &&
|
|
||||||
prevKeys.length === nextKeys.length &&
|
prevKeys.length === nextKeys.length &&
|
||||||
prevKeys.every((key) => prev[key] === next[key])
|
prevKeys.every((key) => prev[key] === next[key])
|
||||||
);
|
);
|
||||||
|
@ -313,7 +313,7 @@ export const renderScene = (
|
|||||||
if (sceneState.remoteSelectedElementIds[element.id]) {
|
if (sceneState.remoteSelectedElementIds[element.id]) {
|
||||||
selectionColors.push(
|
selectionColors.push(
|
||||||
...sceneState.remoteSelectedElementIds[element.id].map((socketId) => {
|
...sceneState.remoteSelectedElementIds[element.id].map((socketId) => {
|
||||||
const { background } = getClientColors(socketId);
|
const { background } = getClientColors(socketId, appState);
|
||||||
return background;
|
return background;
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
@ -441,7 +441,7 @@ export const renderScene = (
|
|||||||
y = Math.max(y, 0);
|
y = Math.max(y, 0);
|
||||||
y = Math.min(y, normalizedCanvasHeight - height);
|
y = Math.min(y, normalizedCanvasHeight - height);
|
||||||
|
|
||||||
const { background, stroke } = getClientColors(clientId);
|
const { background, stroke } = getClientColors(clientId, appState);
|
||||||
|
|
||||||
const strokeStyle = context.strokeStyle;
|
const strokeStyle = context.strokeStyle;
|
||||||
const fillStyle = context.fillStyle;
|
const fillStyle = context.fillStyle;
|
||||||
|
@ -33,6 +33,10 @@ export type Collaborator = {
|
|||||||
selectedElementIds?: AppState["selectedElementIds"];
|
selectedElementIds?: AppState["selectedElementIds"];
|
||||||
username?: string | null;
|
username?: string | null;
|
||||||
userState?: UserIdleState;
|
userState?: UserIdleState;
|
||||||
|
color?: {
|
||||||
|
background: string;
|
||||||
|
stroke: string;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export type AppState = {
|
export type AppState = {
|
||||||
@ -166,9 +170,6 @@ export interface ExcalidrawProps {
|
|||||||
appState: AppState,
|
appState: AppState,
|
||||||
) => void;
|
) => void;
|
||||||
initialData?: ImportedDataState | null | Promise<ImportedDataState | null>;
|
initialData?: ImportedDataState | null | Promise<ImportedDataState | null>;
|
||||||
user?: {
|
|
||||||
name?: string | null;
|
|
||||||
};
|
|
||||||
excalidrawRef?: ForwardRef<ExcalidrawAPIRefValue>;
|
excalidrawRef?: ForwardRef<ExcalidrawAPIRefValue>;
|
||||||
onCollabButtonClick?: () => void;
|
onCollabButtonClick?: () => void;
|
||||||
isCollaborating?: boolean;
|
isCollaborating?: boolean;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user