feat: new Live Collaboration Component API (#6104)

* feat: new Live Collaboration Component API

* namespace export icons into `icons` dictionary and lowercase

* update readme and changelog

* review fixes

* fix

* fix

* update docs

* remove

* allow button rest props

* update docs

* docs

* add `WelcomeScreen.Center.MenuItemLiveCollaborationTrigger`

* fix lint

* update changelog

Co-authored-by: dwelle <luzar.david@gmail.com>
This commit is contained in:
Aakansha Doshi
2023-01-12 23:28:57 +05:30
committed by GitHub
parent 9d04479f98
commit faad8a65f1
14 changed files with 150 additions and 105 deletions

View File

@ -25,8 +25,11 @@ Please add the latest change on the top under the correct section.
- Any top-level children passed to the `<Excalidraw/>` component that do not belong to one of the officially supported Excalidraw children components are now rendered directly inside the Excalidraw container (previously, they weren't rendered at all) [#6096](https://github.com/excalidraw/excalidraw/pull/6096).
#### BREAKING CHANGE
- Expose [LiveCollaborationTrigger](https://github.com/excalidraw/excalidraw/blob/master/src/packages/excalidraw/README.md#LiveCollaborationTrigger) component. Replaces `props.onCollabButtonClick` [#6104](https://github.com/excalidraw/excalidraw/pull/6104).
#### BREAKING CHANGES
- `props.onCollabButtonClick` is now removed. You need to render the main menu item yourself, and optionally also render the `<LiveCollaborationTrigger>` component using [renderTopRightUI](https://github.com/excalidraw/excalidraw/blob/master/src/packages/excalidraw/README.md#renderTopRightUI) prop if you want to retain the canvas button at top-right.
- The prop `renderFooter` is now removed in favor of rendering as a child component.
### Excalidraw schema

View File

@ -138,9 +138,6 @@ export default function App() {
console.log("Elements :", elements, "State : ", state)
}
onPointerUpdate={(payload) => console.log(payload)}
onCollabButtonClick={() =>
window.alert("You clicked on collab button")
}
viewModeEnabled={viewModeEnabled}
zenModeEnabled={zenModeEnabled}
gridModeEnabled={gridModeEnabled}
@ -331,7 +328,6 @@ const App = () => {
onChange: (elements, state) =>
console.log("Elements :", elements, "State : ", state),
onPointerUpdate: (payload) => console.log(payload),
onCollabButtonClick: () => window.alert("You clicked on collab button"),
viewModeEnabled: viewModeEnabled,
zenModeEnabled: zenModeEnabled,
gridModeEnabled: gridModeEnabled,
@ -655,6 +651,7 @@ The default menu items are:
- `<WelcomeScreen.Center.MenuItemHelp/>` - opens the help dialog.
- `<WelcomeScreen.Center.MenuItemLoadScene/>` - open the load file dialog.
- `<WelcomeScreen.Center.MenuItemLiveCollaborationTrigger/>` - intended to open the live collaboration dialog. Works similarly to [`<LiveCollaborationTrigger>`](#LiveCollaborationTrigger) and you must supply `onSelect()` handler to integrate with your collaboration implementation.
**Usage**
@ -719,6 +716,36 @@ Hint for the toolbar. Supply `children` to customize the hint text.
Hint for the help dialog. Supply `children` to customize the hint text.
### LiveCollaborationTrigger
If you implement live collaboration support and want to expose the same UI button as on excalidraw.com, you can render the `<LiveCollaborationTrigger>` component using the [renderTopRightUI](#rendertoprightui) prop. You'll need to supply `onSelect()` to handle opening of your collaboration dialog, but the button will display current `appState.collaborators` count for you.
| Prop | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `onSelect` | `() => any` | Yes | | Handler called when the user click on the button |
| `isCollaborating` | `boolean` | Yes | false | Whether live collaboration session is in effect. Modifies button style. |
**Usage**
```jsx
import { LiveCollaborationTrigger } from "@excalidraw/excalidraw";
const App = () => (
<Excalidraw
renderTopRightUI={(isMobile) => {
if (isMobile) {
return null;
}
return (
<LiveCollaborationTrigger
isCollaborating={isCollaborating}
onSelect={() => setCollabDialogShown(true)}
/>
);
}}
/>
);
```
### Props
| Name | Type | Default | Description |
@ -726,7 +753,6 @@ Hint for the help dialog. Supply `children` to customize the hint text.
| [`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) | <code>{elements?: <a href="https://github.com/excalidraw/excalidraw/blob/master/src/element/types.ts#L106">ExcalidrawElement[]</a>, appState?: <a href="https://github.com/excalidraw/excalidraw/blob/master/src/types.ts#L79">AppState<a> } </code> | null | The initial data with which app loads. |
| [`ref`](#ref) | [`createRef`](https://reactjs.org/docs/refs-and-the-dom.html#creating-refs) &#124; [`useRef`](https://reactjs.org/docs/hooks-reference.html#useref) &#124; [`callbackRef`](https://reactjs.org/docs/refs-and-the-dom.html#callback-refs) &#124; <code>{ current: { readyPromise: <a href="https://github.com/excalidraw/excalidraw/blob/master/src/utils.ts#L317">resolvablePromise</a> } }</code> | | Ref to be passed to Excalidraw |
| [`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 |
| [`onPointerUpdate`](#onPointerUpdate) | Function | | Callback triggered when mouse pointer is updated. |
| [`langCode`](#langCode) | string | `en` | Language code string |
@ -900,10 +926,6 @@ You can use this function to update the library. It accepts the below attributes
Adds supplied files data to the `appState.files` cache on top of existing files present in the cache.
#### `onCollabButtonClick`
This callback is triggered when clicked on the collab button in excalidraw. If not supplied, the collab dialog button is not rendered.
#### `isCollaborating`
This prop indicates if the app is in collaboration mode.

View File

@ -72,24 +72,13 @@ const {
Sidebar,
Footer,
MainMenu,
LiveCollaborationTrigger,
} = window.ExcalidrawLib;
const COMMENT_ICON_DIMENSION = 32;
const COMMENT_INPUT_HEIGHT = 50;
const COMMENT_INPUT_WIDTH = 150;
const renderTopRightUI = () => {
return (
<button
onClick={() => alert("This is dummy top right UI")}
style={{ height: "2.5rem" }}
>
{" "}
Click me{" "}
</button>
);
};
export default function App() {
const appRef = useRef<any>(null);
const [viewModeEnabled, setViewModeEnabled] = useState(false);
@ -148,6 +137,28 @@ export default function App() {
fetchData();
}, [excalidrawAPI]);
const renderTopRightUI = (isMobile: boolean) => {
return (
<>
{!isMobile && (
<LiveCollaborationTrigger
isCollaborating={isCollaborating}
onSelect={() => {
window.alert("Collab dialog clicked");
}}
/>
)}
<button
onClick={() => alert("This is dummy top right UI")}
style={{ height: "2.5rem" }}
>
{" "}
Click me{" "}
</button>
</>
);
};
const loadSceneOrLibrary = async () => {
const file = await fileOpen({ description: "Excalidraw or library file" });
const contents = await loadSceneOrLibraryFromBlob(file, null, null);
@ -489,12 +500,10 @@ export default function App() {
<MainMenu.DefaultItems.SaveAsImage />
<MainMenu.DefaultItems.Export />
<MainMenu.Separator />
{isCollaborating && (
<MainMenu.DefaultItems.LiveCollaboration
onSelect={() => window.alert("You clicked on collab button")}
isCollaborating={isCollaborating}
/>
)}
<MainMenu.DefaultItems.LiveCollaborationTrigger
isCollaborating={isCollaborating}
onSelect={() => window.alert("You clicked on collab button")}
/>
<MainMenu.Group title="Excalidraw links">
<MainMenu.DefaultItems.Socials />
</MainMenu.Group>
@ -508,6 +517,7 @@ export default function App() {
</button>
</MainMenu.ItemCustom>
<MainMenu.DefaultItems.Help />
{excalidrawAPI && <MobileFooter excalidrawAPI={excalidrawAPI} />}
</MainMenu>
);
@ -677,9 +687,6 @@ export default function App() {
button: "down" | "up";
pointersMap: Gesture["pointers"];
}) => setPointerData(payload)}
onCollabButtonClick={() =>
window.alert("You clicked on collab button")
}
viewModeEnabled={viewModeEnabled}
zenModeEnabled={zenModeEnabled}
gridModeEnabled={gridModeEnabled}

View File

@ -14,13 +14,13 @@ import { jotaiScope, jotaiStore } from "../../jotai";
import Footer from "../../components/footer/FooterCenter";
import MainMenu from "../../components/main-menu/MainMenu";
import WelcomeScreen from "../../components/welcome-screen/WelcomeScreen";
import LiveCollaborationTrigger from "../../components/live-collaboration/LiveCollaborationTrigger";
const ExcalidrawBase = (props: ExcalidrawProps) => {
const {
onChange,
initialData,
excalidrawRef,
onCollabButtonClick,
isCollaborating = false,
onPointerUpdate,
renderTopRightUI,
@ -94,7 +94,6 @@ const ExcalidrawBase = (props: ExcalidrawProps) => {
onChange={onChange}
initialData={initialData}
excalidrawRef={excalidrawRef}
onCollabButtonClick={onCollabButtonClick}
isCollaborating={isCollaborating}
onPointerUpdate={onPointerUpdate}
renderTopRightUI={renderTopRightUI}
@ -246,3 +245,4 @@ export { Footer };
export { MainMenu };
export { useDevice } from "../../components/App";
export { WelcomeScreen };
export { LiveCollaborationTrigger };