|
@@ -8,15 +8,8 @@ import { NonDeletedExcalidrawElement } from "../element/types";
|
|
|
import { Language, t } from "../i18n";
|
|
|
import { calculateScrollCenter } from "../scene";
|
|
|
import { ExportType } from "../scene/types";
|
|
|
-import {
|
|
|
- AppProps,
|
|
|
- AppState,
|
|
|
- ExcalidrawProps,
|
|
|
- BinaryFiles,
|
|
|
- UIChildrenComponents,
|
|
|
- UIWelcomeScreenComponents,
|
|
|
-} from "../types";
|
|
|
-import { isShallowEqual, muteFSAbortError, getReactChildren } from "../utils";
|
|
|
+import { AppProps, AppState, ExcalidrawProps, BinaryFiles } from "../types";
|
|
|
+import { isShallowEqual, muteFSAbortError } from "../utils";
|
|
|
import { SelectedShapeActions, ShapesSwitcher } from "./Actions";
|
|
|
import { ErrorDialog } from "./ErrorDialog";
|
|
|
import { ExportCB, ImageExportDialog } from "./ImageExportDialog";
|
|
@@ -45,7 +38,6 @@ import { useDevice } from "../components/App";
|
|
|
import { Stats } from "./Stats";
|
|
|
import { actionToggleStats } from "../actions/actionToggleStats";
|
|
|
import Footer from "./footer/Footer";
|
|
|
-import WelcomeScreen from "./welcome-screen/WelcomeScreen";
|
|
|
import { hostSidebarCountersAtom } from "./Sidebar/Sidebar";
|
|
|
import { jotaiScope } from "../jotai";
|
|
|
import { useAtom } from "jotai";
|
|
@@ -53,6 +45,12 @@ import MainMenu from "./main-menu/MainMenu";
|
|
|
import { ActiveConfirmDialog } from "./ActiveConfirmDialog";
|
|
|
import { HandButton } from "./HandButton";
|
|
|
import { isHandToolActive } from "../appState";
|
|
|
+import {
|
|
|
+ mainMenuTunnel,
|
|
|
+ welcomeScreenMenuHintTunnel,
|
|
|
+ welcomeScreenToolbarHintTunnel,
|
|
|
+ welcomeScreenCenterTunnel,
|
|
|
+} from "./tunnels";
|
|
|
|
|
|
interface LayerUIProps {
|
|
|
actionManager: ActionManager;
|
|
@@ -67,7 +65,6 @@ interface LayerUIProps {
|
|
|
onInsertElements: (elements: readonly NonDeletedExcalidrawElement[]) => void;
|
|
|
showExitZenModeBtn: boolean;
|
|
|
langCode: Language["code"];
|
|
|
- isCollaborating: boolean;
|
|
|
renderTopRightUI?: ExcalidrawProps["renderTopRightUI"];
|
|
|
renderCustomStats?: ExcalidrawProps["renderCustomStats"];
|
|
|
renderCustomSidebar?: ExcalidrawProps["renderSidebar"];
|
|
@@ -81,6 +78,32 @@ interface LayerUIProps {
|
|
|
children?: React.ReactNode;
|
|
|
}
|
|
|
|
|
|
+const DefaultMainMenu: React.FC<{
|
|
|
+ UIOptions: AppProps["UIOptions"];
|
|
|
+}> = ({ UIOptions }) => {
|
|
|
+ return (
|
|
|
+ <MainMenu __fallback>
|
|
|
+ <MainMenu.DefaultItems.LoadScene />
|
|
|
+ <MainMenu.DefaultItems.SaveToActiveFile />
|
|
|
+ {/* FIXME we should to test for this inside the item itself */}
|
|
|
+ {UIOptions.canvasActions.export && <MainMenu.DefaultItems.Export />}
|
|
|
+ {/* FIXME we should to test for this inside the item itself */}
|
|
|
+ {UIOptions.canvasActions.saveAsImage && (
|
|
|
+ <MainMenu.DefaultItems.SaveAsImage />
|
|
|
+ )}
|
|
|
+ <MainMenu.DefaultItems.Help />
|
|
|
+ <MainMenu.DefaultItems.ClearCanvas />
|
|
|
+ <MainMenu.Separator />
|
|
|
+ <MainMenu.Group title="Excalidraw links">
|
|
|
+ <MainMenu.DefaultItems.Socials />
|
|
|
+ </MainMenu.Group>
|
|
|
+ <MainMenu.Separator />
|
|
|
+ <MainMenu.DefaultItems.ToggleTheme />
|
|
|
+ <MainMenu.DefaultItems.ChangeCanvasBackground />
|
|
|
+ </MainMenu>
|
|
|
+ );
|
|
|
+};
|
|
|
+
|
|
|
const LayerUI = ({
|
|
|
actionManager,
|
|
|
appState,
|
|
@@ -93,7 +116,6 @@ const LayerUI = ({
|
|
|
onPenModeToggle,
|
|
|
onInsertElements,
|
|
|
showExitZenModeBtn,
|
|
|
- isCollaborating,
|
|
|
renderTopRightUI,
|
|
|
renderCustomStats,
|
|
|
renderCustomSidebar,
|
|
@@ -108,28 +130,6 @@ const LayerUI = ({
|
|
|
}: LayerUIProps) => {
|
|
|
const device = useDevice();
|
|
|
|
|
|
- const [childrenComponents, restChildren] =
|
|
|
- getReactChildren<UIChildrenComponents>(children, {
|
|
|
- Menu: true,
|
|
|
- FooterCenter: true,
|
|
|
- WelcomeScreen: true,
|
|
|
- });
|
|
|
-
|
|
|
- const [WelcomeScreenComponents] = getReactChildren<UIWelcomeScreenComponents>(
|
|
|
- renderWelcomeScreen
|
|
|
- ? (
|
|
|
- childrenComponents?.WelcomeScreen ?? (
|
|
|
- <WelcomeScreen>
|
|
|
- <WelcomeScreen.Center />
|
|
|
- <WelcomeScreen.Hints.MenuHint />
|
|
|
- <WelcomeScreen.Hints.ToolbarHint />
|
|
|
- <WelcomeScreen.Hints.HelpHint />
|
|
|
- </WelcomeScreen>
|
|
|
- )
|
|
|
- )?.props?.children
|
|
|
- : null,
|
|
|
- );
|
|
|
-
|
|
|
const renderJSONExportDialog = () => {
|
|
|
if (!UIOptions.canvasActions.export) {
|
|
|
return null;
|
|
@@ -197,37 +197,12 @@ const LayerUI = ({
|
|
|
);
|
|
|
};
|
|
|
|
|
|
- const renderMenu = () => {
|
|
|
- return (
|
|
|
- childrenComponents.Menu || (
|
|
|
- <MainMenu>
|
|
|
- <MainMenu.DefaultItems.LoadScene />
|
|
|
- <MainMenu.DefaultItems.SaveToActiveFile />
|
|
|
- {/* FIXME we should to test for this inside the item itself */}
|
|
|
- {UIOptions.canvasActions.export && <MainMenu.DefaultItems.Export />}
|
|
|
- {/* FIXME we should to test for this inside the item itself */}
|
|
|
- {UIOptions.canvasActions.saveAsImage && (
|
|
|
- <MainMenu.DefaultItems.SaveAsImage />
|
|
|
- )}
|
|
|
- <MainMenu.DefaultItems.Help />
|
|
|
- <MainMenu.DefaultItems.ClearCanvas />
|
|
|
- <MainMenu.Separator />
|
|
|
- <MainMenu.Group title="Excalidraw links">
|
|
|
- <MainMenu.DefaultItems.Socials />
|
|
|
- </MainMenu.Group>
|
|
|
- <MainMenu.Separator />
|
|
|
- <MainMenu.DefaultItems.ToggleTheme />
|
|
|
- <MainMenu.DefaultItems.ChangeCanvasBackground />
|
|
|
- </MainMenu>
|
|
|
- )
|
|
|
- );
|
|
|
- };
|
|
|
const renderCanvasActions = () => (
|
|
|
<div style={{ position: "relative" }}>
|
|
|
- {WelcomeScreenComponents.MenuHint}
|
|
|
{/* wrapping to Fragment stops React from occasionally complaining
|
|
|
about identical Keys */}
|
|
|
- <>{renderMenu()}</>
|
|
|
+ <mainMenuTunnel.Out />
|
|
|
+ {renderWelcomeScreen && <welcomeScreenMenuHintTunnel.Out />}
|
|
|
</div>
|
|
|
);
|
|
|
|
|
@@ -264,7 +239,6 @@ const LayerUI = ({
|
|
|
|
|
|
return (
|
|
|
<FixedSideContainer side="top">
|
|
|
- {WelcomeScreenComponents.Center}
|
|
|
<div className="App-menu App-menu_top">
|
|
|
<Stack.Col
|
|
|
gap={6}
|
|
@@ -279,7 +253,9 @@ const LayerUI = ({
|
|
|
<Section heading="shapes" className="shapes-section">
|
|
|
{(heading: React.ReactNode) => (
|
|
|
<div style={{ position: "relative" }}>
|
|
|
- {WelcomeScreenComponents.ToolbarHint}
|
|
|
+ {renderWelcomeScreen && (
|
|
|
+ <welcomeScreenToolbarHintTunnel.Out />
|
|
|
+ )}
|
|
|
<Stack.Col gap={4} align="start">
|
|
|
<Stack.Row
|
|
|
gap={1}
|
|
@@ -380,7 +356,16 @@ const LayerUI = ({
|
|
|
|
|
|
return (
|
|
|
<>
|
|
|
- {restChildren}
|
|
|
+ {/* ------------------------- tunneled UI ---------------------------- */}
|
|
|
+ {/* make sure we render host app components first so that we can detect
|
|
|
+ them first on initial render to optimize layout shift */}
|
|
|
+ {children}
|
|
|
+ {/* render component fallbacks. Can be rendered anywhere as they'll be
|
|
|
+ tunneled away. We only render tunneled components that actually
|
|
|
+ have defaults when host do not render anything. */}
|
|
|
+ <DefaultMainMenu UIOptions={UIOptions} />
|
|
|
+ {/* ------------------------------------------------------------------ */}
|
|
|
+
|
|
|
{appState.isLoading && <LoadingMessage delay={250} />}
|
|
|
{appState.errorMessage && (
|
|
|
<ErrorDialog
|
|
@@ -427,8 +412,6 @@ const LayerUI = ({
|
|
|
renderCustomStats={renderCustomStats}
|
|
|
renderSidebars={renderSidebars}
|
|
|
device={device}
|
|
|
- renderMenu={renderMenu}
|
|
|
- welcomeScreenCenter={WelcomeScreenComponents.Center}
|
|
|
/>
|
|
|
)}
|
|
|
|
|
@@ -451,13 +434,13 @@ const LayerUI = ({
|
|
|
: {}
|
|
|
}
|
|
|
>
|
|
|
+ {renderWelcomeScreen && <welcomeScreenCenterTunnel.Out />}
|
|
|
{renderFixedSideContainer()}
|
|
|
<Footer
|
|
|
appState={appState}
|
|
|
actionManager={actionManager}
|
|
|
showExitZenModeBtn={showExitZenModeBtn}
|
|
|
- footerCenter={childrenComponents.FooterCenter}
|
|
|
- welcomeScreenHelp={WelcomeScreenComponents.HelpHint}
|
|
|
+ renderWelcomeScreen={renderWelcomeScreen}
|
|
|
/>
|
|
|
{appState.showStats && (
|
|
|
<Stats
|