mirror of
https://github.com/excalidraw/excalidraw.git
synced 2025-05-03 10:00:07 -04:00
feat: new Menu Component API (#6034)
* feat: new Menu Component API * allow valid children types * introduce menu group to group items * Add lang footer * use display name * displayName * define types inside * fix default menu * add json export to menu * fix * simplify expression * put open menu into own compo to optimize perf So that we don't rerun `useOutsideClickHook` (and rebind event listeners all the time) * naming tweaks * rename MenuComponents->MenuDefaultItems and export default items from Menu.Items * import Menu.scss in Menu.tsx * move menu scss to excal app * Don't filter children inside menu group * move E+ out of socials * support style prop for MenuItem and MenuGroup * Support header in menu group and add Excalidraw links header for default items in social section * rename header to title * fix padding for lang * render menu in mobile * review fixes * tweaks * Export collaborators and show in mobile menu * revert .env * lint :p * again lint * show correct actions in view mode for mobile * Whitelist Collaborators Comp * mobile styling * padding * don't show nerds when menu open in mobile * lint :( * hide shortcuts * refactor userlist to support mobile and keep a wrapper comp for excal app * use only UserList * render only on mobile for default items * remove unused hooks * Show collab button in menu when onCollabButtonClick present and hide export when UIOptions.canvasActions.export is false * fix tests * lint * inject userlist inside menu on mobile * revert userlist * move menu socials to default menu * fix collab * use meny in library * Make Menu generic and create hamburgemenu for public excal menu and use menu in library as well * use appState.openMenu for mobile * fix tests * styling fixes and support style and class name in menu content * fix test * rename MenuDefaultItems->DefaultItems * move footer css to its own comp * rename HamburgerMenu -> MainMenu * rename menu -> dropdownMenu and update classes, onClick->onToggle * close main menu when dialog closes * by bye filtering * update docs * fix lint * update example, docs for useDevice and footer in mobile, rename menu ->DropDownMenu everywhere * spec * remove isMenuOpenAtom and set openMenu as canvas for main menu, render decreases in specs :) * [temp] remove cyclic depenedency to fix build * hack- update appstate to sync lang change * Add more specs * wip: rewrite MainMenu footer * fix margin * fix snaps * not needed as lang list no more imported * simplify custom footer rendering * Add DropdownMenuItemLink and DropdownMenuItemCustom and update API, docs * fix `MainMenu.ItemCustom` * naming * use onSelect and base class for custom items * fix lint * fix snap * use custom item for lang * update docs * fix * properly use `MainMenu.ItemCustom` for `LanguageList` * add margin top to custom items * flex Co-authored-by: dwelle <luzar.david@gmail.com>
This commit is contained in:
parent
08afb857c3
commit
8420aecb34
54 changed files with 1876 additions and 1911 deletions
|
@ -15,6 +15,8 @@ Please add the latest change on the top under the correct section.
|
|||
|
||||
### Features
|
||||
|
||||
- Expose component API for the Excalidraw main menu [#6034](https://github.com/excalidraw/excalidraw/pull/6034), You can read more about its usage [here](https://github.com/excalidraw/excalidraw/blob/master/src/packages/excalidraw/README.md#MainMenu)
|
||||
|
||||
- Render Footer as a component instead of render prop [#5970](https://github.com/excalidraw/excalidraw/pull/5970). You can read more about its usage [here](https://github.com/excalidraw/excalidraw/blob/master/src/packages/excalidraw/README.md#Footer)
|
||||
|
||||
#### BREAKING CHANGE
|
||||
|
|
|
@ -405,6 +405,195 @@ const App = () => {
|
|||
};
|
||||
```
|
||||
|
||||
This will only for `Desktop` devices.
|
||||
|
||||
For `mobile` you will need to render it inside the [MainMenu](#mainmenu). You can use the [`useDevice`](#useDevice) hook to check the type of device, this will be available only inside the `children` of `Excalidraw` component.
|
||||
|
||||
```js
|
||||
import { useDevice, Footer } from "@excalidraw/excalidraw";
|
||||
|
||||
const MobileFooter = ({
|
||||
}) => {
|
||||
const device = useDevice();
|
||||
if (device.isMobile) {
|
||||
return (
|
||||
<Footer>
|
||||
<button
|
||||
className="custom-footer"
|
||||
onClick={() => alert("This is custom footer in mobile menu")}
|
||||
>
|
||||
{" "}
|
||||
custom footer{" "}
|
||||
</button>
|
||||
</Footer>
|
||||
);
|
||||
}
|
||||
return null;
|
||||
|
||||
};
|
||||
const App = () => {
|
||||
<Excalidraw>
|
||||
<MainMenu>
|
||||
<MainMenu.Item onSelect={() => window.alert("Item1")}> Item1 </MainMenu.Item>
|
||||
<MainMenu.Item onSelect={() => window.alert("Item2")}> Item 2 </>
|
||||
<MobileFooter/>
|
||||
</MainMenu>
|
||||
</Excalidraw>
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
You can visit the[ example](https://ehlz3.csb.app/) for working demo.
|
||||
|
||||
#### MainMenu
|
||||
|
||||
By default Excalidraw will render the `MainMenu` with default options. If you want to customise the `MainMenu`, you can pass the `MainMenu` component with the list options. You can visit [codesandbox example](https://ehlz3.csb.app/) for a working demo.
|
||||
|
||||
**Usage**
|
||||
|
||||
```js
|
||||
import { MainMenu } from "@excalidraw/excalidraw";
|
||||
const App = () => {
|
||||
<Excalidraw>
|
||||
<MainMenu>
|
||||
<MainMenu.Item onSelect={() => window.alert("Item1")}> Item1 </MainMenu.Item>
|
||||
<MainMenu.Item onSelect={() => window.alert("Item2")}> Item 2 </>
|
||||
</MainMenu>
|
||||
</Excalidraw>
|
||||
}
|
||||
```
|
||||
|
||||
**MainMenu**
|
||||
|
||||
This is the `MainMenu` component which you need to import to render the menu with custom options.
|
||||
|
||||
**MainMenu.Item**
|
||||
|
||||
To render an item, its recommended to use `MainMenu.Item`.
|
||||
|
||||
| Prop | Type | Required | Default | Description |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| `onSelect` | `Function` | Yes | `undefined` | The handler is triggered when the item is selected. |
|
||||
| `children` | `React.ReactNode` | Yes | `undefined` | The content of the menu item |
|
||||
| `icon` | `JSX.Element` | No | `undefined` | The icon used in the menu item |
|
||||
| `shortcut` | `string` | No | `undefined` | The shortcut to be shown for the menu item |
|
||||
| `className` | `string` | No | "" | The class names to be added to the menu item |
|
||||
| `style` | `React.CSSProperties` | No | `undefined` | The inline styles to be added to the menu item |
|
||||
| `ariaLabel` | `string` | `undefined` | No | The `aria-label` to be added to the item for accessibility |
|
||||
| `dataTestId` | `string` | `undefined` | No | The `data-testid` to be added to the item. |
|
||||
|
||||
**MainMenu.ItemLink**
|
||||
|
||||
To render an item as a link, its recommended to use `MainMenu.ItemLink`.
|
||||
|
||||
**Usage**
|
||||
|
||||
```js
|
||||
import { MainMenu } from "@excalidraw/excalidraw";
|
||||
const App = () => {
|
||||
<Excalidraw>
|
||||
<MainMenu>
|
||||
<MainMenu.ItemLink href="https://google.com">Google</MainMenu.ItemLink>
|
||||
<MainMenu.ItemLink href="https://excalidraw.com">
|
||||
Excalidraw
|
||||
</MainMenu.ItemLink>
|
||||
</MainMenu>
|
||||
</Excalidraw>;
|
||||
};
|
||||
```
|
||||
|
||||
| Prop | Type | Required | Default | Description |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| `href` | `string` | Yes | `undefined` | The `href` attribute to be added to the `anchor` element. |
|
||||
| `children` | `React.ReactNode` | Yes | `undefined` | The content of the menu item |
|
||||
| `icon` | `JSX.Element` | No | `undefined` | The icon used in the menu item |
|
||||
| `shortcut` | `string` | No | `undefined` | The shortcut to be shown for the menu item |
|
||||
| `className` | `string` | No | "" | The class names to be added to the menu item |
|
||||
| `style` | `React.CSSProperties` | No | `undefined` | The inline styles to be added to the menu item |
|
||||
| `ariaLabel` | `string` | No | `undefined` | The `aria-label` to be added to the item for accessibility |
|
||||
| `dataTestId` | `string` | No | `undefined` | The `data-testid` to be added to the item. |
|
||||
|
||||
**MainMenu.ItemCustom**
|
||||
|
||||
To render a custom item, you can use `MainMenu.ItemCustom`.
|
||||
|
||||
**Usage**
|
||||
|
||||
```js
|
||||
import { MainMenu } from "@excalidraw/excalidraw";
|
||||
const App = () => {
|
||||
<Excalidraw>
|
||||
<MainMenu>
|
||||
<MainMenu.ItemCustom>
|
||||
<button
|
||||
style={{ height: "2rem" }}
|
||||
onClick={() => window.alert("custom menu item")}
|
||||
>
|
||||
{" "}
|
||||
custom item
|
||||
</button>
|
||||
</MainMenu.ItemCustom>
|
||||
</MainMenu>
|
||||
</Excalidraw>;
|
||||
};
|
||||
```
|
||||
|
||||
| Prop | Type | Required | Default | Description |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| `children` | `React.ReactNode` | Yes | `undefined` | The content of the menu item |
|
||||
| `className` | `string` | No | "" | The class names to be added to the menu item |
|
||||
| `style` | `React.CSSProperties` | No | `undefined` | The inline styles to be added to the menu item |
|
||||
| `dataTestId` | `string` | No | `undefined` | The `data-testid` to be added to the item. |
|
||||
|
||||
**MainMenu.DefaultItems**
|
||||
|
||||
For the items which are shown in the menu in [excalidraw.com](https://excalidraw.com), you can use `MainMenu.DefaultItems`
|
||||
|
||||
```js
|
||||
import { MainMenu } from "@excalidraw/excalidraw";
|
||||
const App = () => {
|
||||
<Excalidraw>
|
||||
<MainMenu>
|
||||
<MainMenu.DefaultItems.Socials/>
|
||||
<MainMenu.DefaultItems.Export/>
|
||||
<MainMenu.Item onSelect={() => window.alert("Item1")}> Item1 </MainMenu.Item>
|
||||
<MainMenu.Item onSelect={() => window.alert("Item2")}> Item 2 </>
|
||||
</MainMenu>
|
||||
</Excalidraw>
|
||||
}
|
||||
```
|
||||
|
||||
Here is a [complete list](https://github.com/excalidraw/excalidraw/blob/master/src/components/mainMenu/DefaultItems.tsx) of the default items.
|
||||
|
||||
**MainMenu.Group**
|
||||
|
||||
To Group item in the main menu, you can use `MainMenu.Group`
|
||||
|
||||
```js
|
||||
import { MainMenu } from "@excalidraw/excalidraw";
|
||||
const App = () => {
|
||||
<Excalidraw>
|
||||
<MainMenu>
|
||||
<MainMenu.Group title="Excalidraw items">
|
||||
<MainMenu.DefaultItems.Socials/>
|
||||
<MainMenu.DefaultItems.Export/>
|
||||
</MainMenu.Group>
|
||||
<MainMenu.Group title="custom items">
|
||||
<MainMenu.Item onSelect={() => window.alert("Item1")}> Item1 </MainMenu.Item>
|
||||
<MainMenu.Item onSelect={() => window.alert("Item2")}> Item 2 </>
|
||||
</MainMenu.Group>
|
||||
</MainMenu>
|
||||
</Excalidraw>
|
||||
}
|
||||
```
|
||||
|
||||
| Prop | Type | Required | Default | Description |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| `children ` | `React.ReactNode` | Yes | `undefined` | The content of the `Menu Group` |
|
||||
| `title` | `string` | No | `undefined` | The `title` for the grouped items |
|
||||
| `className` | `string` | No | "" | The `classname` to be added to the group |
|
||||
| `style` | `React.CSsSProperties` | No | `undefined` | The inline `styles` to be added to the group |
|
||||
|
||||
### Props
|
||||
|
||||
| Name | Type | Default | Description |
|
||||
|
@ -1369,6 +1558,53 @@ viewportCoordsToSceneCoords({clientX: number, clientY: number}, appState: <a hre
|
|||
|
||||
This function returns equivalent scene coords for the provided viewport coords in params.
|
||||
|
||||
#### useDevice
|
||||
|
||||
This hook can be used to check the type of device which is being used. It can only be used inside the `children` of `Excalidraw` component
|
||||
|
||||
```js
|
||||
import { useDevice, Footer } from "@excalidraw/excalidraw";
|
||||
|
||||
const MobileFooter = ({
|
||||
}) => {
|
||||
const device = useDevice();
|
||||
if (device.isMobile) {
|
||||
return (
|
||||
<Footer>
|
||||
<button
|
||||
className="custom-footer"
|
||||
onClick={() => alert("This is custom footer in mobile menu")}
|
||||
>
|
||||
{" "}
|
||||
custom footer{" "}
|
||||
</button>
|
||||
</Footer>
|
||||
);
|
||||
}
|
||||
return null;
|
||||
|
||||
};
|
||||
const App = () => {
|
||||
<Excalidraw>
|
||||
<MainMenu>
|
||||
<MainMenu.Item> Item1 </MainMenu.Item>
|
||||
<MainMenu.Item> Item 2 </>
|
||||
<MobileFooter/>
|
||||
</MainMenu>
|
||||
</Excalidraw>
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
The `device` has the following `attributes`
|
||||
|
||||
| Name | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| `isSmScreen` | `boolean` | Set to `true` when the device small screen is small (Width < `640px` ) |
|
||||
| `isMobile` | `boolean` | Set to `true` when the device is `mobile` |
|
||||
| `isTouchScreen` | `boolean` | Set to `true` for `touch` devices |
|
||||
| `canDeviceFitSidebar` | `boolean` | Implies whether there is enough space to fit the `sidebar` |
|
||||
|
||||
### Exported constants
|
||||
|
||||
#### `FONT_FAMILY`
|
||||
|
|
|
@ -73,9 +73,4 @@
|
|||
.custom-element {
|
||||
padding: 0.1rem;
|
||||
}
|
||||
|
||||
&.excalidraw-container .layer-ui__wrapper .layer-ui__wrapper__footer-center {
|
||||
// Remove once we stop importing langauge list from excalidraw app
|
||||
justify-content: flex-start;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,6 +28,8 @@ import {
|
|||
} from "../../../types";
|
||||
import { NonDeletedExcalidrawElement } from "../../../element/types";
|
||||
import { ImportedLibraryData } from "../../../data/types";
|
||||
import CustomFooter from "./CustomFooter";
|
||||
import MobileFooter from "./MobileFooter";
|
||||
|
||||
declare global {
|
||||
interface Window {
|
||||
|
@ -69,24 +71,9 @@ const {
|
|||
restoreElements,
|
||||
Sidebar,
|
||||
Footer,
|
||||
MainMenu,
|
||||
} = window.ExcalidrawLib;
|
||||
|
||||
const COMMENT_SVG = (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="24"
|
||||
height="24"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
strokeWidth="2"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
className="feather feather-message-circle"
|
||||
>
|
||||
<path d="M21 11.5a8.38 8.38 0 0 1-.9 3.8 8.5 8.5 0 0 1-7.6 4.7 8.38 8.38 0 0 1-3.8-.9L3 21l1.9-5.7a8.38 8.38 0 0 1-.9-3.8 8.5 8.5 0 0 1 4.7-7.6 8.38 8.38 0 0 1 3.8-.9h.5a8.48 8.48 0 0 1 8 8v.5z"></path>
|
||||
</svg>
|
||||
);
|
||||
const COMMENT_ICON_DIMENSION = 32;
|
||||
const COMMENT_INPUT_HEIGHT = 50;
|
||||
const COMMENT_INPUT_WIDTH = 150;
|
||||
|
@ -343,6 +330,7 @@ export default function App() {
|
|||
}
|
||||
});
|
||||
};
|
||||
|
||||
const renderCommentIcons = () => {
|
||||
return Object.values(commentIcons).map((commentIcon) => {
|
||||
if (!excalidrawAPI) {
|
||||
|
@ -495,6 +483,35 @@ export default function App() {
|
|||
);
|
||||
};
|
||||
|
||||
const renderMenu = () => {
|
||||
return (
|
||||
<MainMenu>
|
||||
<MainMenu.DefaultItems.SaveAsImage />
|
||||
<MainMenu.DefaultItems.Export />
|
||||
<MainMenu.Separator />
|
||||
{isCollaborating && (
|
||||
<MainMenu.DefaultItems.LiveCollaboration
|
||||
onSelect={() => window.alert("You clicked on collab button")}
|
||||
isCollaborating={isCollaborating}
|
||||
/>
|
||||
)}
|
||||
<MainMenu.Group title="Excalidraw links">
|
||||
<MainMenu.DefaultItems.Socials />
|
||||
</MainMenu.Group>
|
||||
<MainMenu.Separator />
|
||||
<MainMenu.ItemCustom>
|
||||
<button
|
||||
style={{ height: "2rem" }}
|
||||
onClick={() => window.alert("custom menu item")}
|
||||
>
|
||||
custom item
|
||||
</button>
|
||||
</MainMenu.ItemCustom>
|
||||
<MainMenu.DefaultItems.Help />
|
||||
{excalidrawAPI && <MobileFooter excalidrawAPI={excalidrawAPI} />}
|
||||
</MainMenu>
|
||||
);
|
||||
};
|
||||
return (
|
||||
<div className="App" ref={appRef}>
|
||||
<h1> Excalidraw Example</h1>
|
||||
|
@ -675,43 +692,12 @@ export default function App() {
|
|||
onScrollChange={rerenderCommentIcons}
|
||||
renderSidebar={renderSidebar}
|
||||
>
|
||||
<Footer>
|
||||
<button
|
||||
className="custom-element"
|
||||
onClick={() => {
|
||||
excalidrawAPI?.setActiveTool({
|
||||
type: "custom",
|
||||
customType: "comment",
|
||||
});
|
||||
const url = `data:${MIME_TYPES.svg},${encodeURIComponent(
|
||||
`<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="24"
|
||||
height="24"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
class="feather feather-message-circle"
|
||||
>
|
||||
<path d="M21 11.5a8.38 8.38 0 0 1-.9 3.8 8.5 8.5 0 0 1-7.6 4.7 8.38 8.38 0 0 1-3.8-.9L3 21l1.9-5.7a8.38 8.38 0 0 1-.9-3.8 8.5 8.5 0 0 1 4.7-7.6 8.38 8.38 0 0 1 3.8-.9h.5a8.48 8.48 0 0 1 8 8v.5z"></path>
|
||||
</svg>`,
|
||||
)}`;
|
||||
excalidrawAPI?.setCursor(`url(${url}), auto`);
|
||||
}}
|
||||
>
|
||||
{COMMENT_SVG}
|
||||
</button>
|
||||
<button
|
||||
className="custom-footer"
|
||||
onClick={() => alert("This is dummy footer")}
|
||||
>
|
||||
{" "}
|
||||
custom footer{" "}
|
||||
</button>
|
||||
</Footer>
|
||||
{excalidrawAPI && (
|
||||
<Footer>
|
||||
<CustomFooter excalidrawAPI={excalidrawAPI} />
|
||||
</Footer>
|
||||
)}
|
||||
{renderMenu()}
|
||||
</Excalidraw>
|
||||
{Object.keys(commentIcons || []).length > 0 && renderCommentIcons()}
|
||||
{comment && renderComment()}
|
||||
|
|
65
src/packages/excalidraw/example/CustomFooter.tsx
Normal file
65
src/packages/excalidraw/example/CustomFooter.tsx
Normal file
|
@ -0,0 +1,65 @@
|
|||
import { ExcalidrawImperativeAPI } from "../../../types";
|
||||
import { MIME_TYPES } from "../entry";
|
||||
const COMMENT_SVG = (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="24"
|
||||
height="24"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
strokeWidth="2"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
className="feather feather-message-circle"
|
||||
>
|
||||
<path d="M21 11.5a8.38 8.38 0 0 1-.9 3.8 8.5 8.5 0 0 1-7.6 4.7 8.38 8.38 0 0 1-3.8-.9L3 21l1.9-5.7a8.38 8.38 0 0 1-.9-3.8 8.5 8.5 0 0 1 4.7-7.6 8.38 8.38 0 0 1 3.8-.9h.5a8.48 8.48 0 0 1 8 8v.5z"></path>
|
||||
</svg>
|
||||
);
|
||||
const CustomFooter = ({
|
||||
excalidrawAPI,
|
||||
}: {
|
||||
excalidrawAPI: ExcalidrawImperativeAPI;
|
||||
}) => {
|
||||
return (
|
||||
<>
|
||||
<button
|
||||
className="custom-element"
|
||||
onClick={() => {
|
||||
excalidrawAPI?.setActiveTool({
|
||||
type: "custom",
|
||||
customType: "comment",
|
||||
});
|
||||
const url = `data:${MIME_TYPES.svg},${encodeURIComponent(
|
||||
`<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="24"
|
||||
height="24"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
class="feather feather-message-circle"
|
||||
>
|
||||
<path d="M21 11.5a8.38 8.38 0 0 1-.9 3.8 8.5 8.5 0 0 1-7.6 4.7 8.38 8.38 0 0 1-3.8-.9L3 21l1.9-5.7a8.38 8.38 0 0 1-.9-3.8 8.5 8.5 0 0 1 4.7-7.6 8.38 8.38 0 0 1 3.8-.9h.5a8.48 8.48 0 0 1 8 8v.5z"></path>
|
||||
</svg>`,
|
||||
)}`;
|
||||
excalidrawAPI?.setCursor(`url(${url}), auto`);
|
||||
}}
|
||||
>
|
||||
{COMMENT_SVG}
|
||||
</button>
|
||||
<button
|
||||
className="custom-footer"
|
||||
onClick={() => alert("This is dummy footer")}
|
||||
>
|
||||
{" "}
|
||||
custom footer{" "}
|
||||
</button>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default CustomFooter;
|
20
src/packages/excalidraw/example/MobileFooter.tsx
Normal file
20
src/packages/excalidraw/example/MobileFooter.tsx
Normal file
|
@ -0,0 +1,20 @@
|
|||
import { ExcalidrawImperativeAPI } from "../../../types";
|
||||
import CustomFooter from "./CustomFooter";
|
||||
const { useDevice, Footer } = window.ExcalidrawLib;
|
||||
|
||||
const MobileFooter = ({
|
||||
excalidrawAPI,
|
||||
}: {
|
||||
excalidrawAPI: ExcalidrawImperativeAPI;
|
||||
}) => {
|
||||
const device = useDevice();
|
||||
if (device.isMobile) {
|
||||
return (
|
||||
<Footer>
|
||||
<CustomFooter excalidrawAPI={excalidrawAPI} />
|
||||
</Footer>
|
||||
);
|
||||
}
|
||||
return null;
|
||||
};
|
||||
export default MobileFooter;
|
|
@ -11,6 +11,7 @@ import { DEFAULT_UI_OPTIONS } from "../../constants";
|
|||
import { Provider } from "jotai";
|
||||
import { jotaiScope, jotaiStore } from "../../jotai";
|
||||
import Footer from "../../components/footer/FooterCenter";
|
||||
import MainMenu from "../../components/mainMenu/MainMenu";
|
||||
|
||||
const ExcalidrawBase = (props: ExcalidrawProps) => {
|
||||
const {
|
||||
|
@ -239,3 +240,5 @@ export {
|
|||
|
||||
export { Sidebar } from "../../components/Sidebar/Sidebar";
|
||||
export { Footer };
|
||||
export { MainMenu };
|
||||
export { useDevice } from "../../components/App";
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue