fix: stale appState of MainMenu defaultItems rendered from Actions (#6074)

This commit is contained in:
David Luzar 2023-01-06 14:32:55 +01:00 committed by GitHub
parent 9803a85381
commit 40d53d9231
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
26 changed files with 463 additions and 431 deletions

View file

@ -1,23 +0,0 @@
// TODO barnabasmolnar/editor-redesign
// this icon is not great
import { getShortcutFromShortcutName } from "../actions/shortcuts";
import { save } from "../components/icons";
import { t } from "../i18n";
import "./ActiveFile.scss";
import DropdownMenuItem from "./dropdownMenu/DropdownMenuItem";
type ActiveFileProps = {
fileName?: string;
onSave: () => void;
};
export const ActiveFile = ({ fileName, onSave }: ActiveFileProps) => (
<DropdownMenuItem
shortcut={getShortcutFromShortcutName("saveScene")}
dataTestId="save-button"
onSelect={onSave}
icon={save}
ariaLabel={`${t("buttons.save")}`}
>{`${t("buttons.save")}`}</DropdownMenuItem>
);

View file

@ -312,9 +312,9 @@ const ExcalidrawSetAppStateContext = React.createContext<
>(() => {});
ExcalidrawSetAppStateContext.displayName = "ExcalidrawSetAppStateContext";
const ExcalidrawActionManagerContext = React.createContext<
ActionManager | { renderAction: ActionManager["renderAction"] }
>({ renderAction: () => null });
const ExcalidrawActionManagerContext = React.createContext<ActionManager>(
null!,
);
ExcalidrawActionManagerContext.displayName = "ExcalidrawActionManagerContext";
export const useExcalidrawElements = () =>

View file

@ -1,41 +0,0 @@
import { useState } from "react";
import { t } from "../i18n";
import { TrashIcon } from "./icons";
import ConfirmDialog from "./ConfirmDialog";
import DropdownMenuItem from "./dropdownMenu/DropdownMenuItem";
const ClearCanvas = ({ onConfirm }: { onConfirm: () => void }) => {
const [showDialog, setShowDialog] = useState(false);
const toggleDialog = () => {
setShowDialog(!showDialog);
};
return (
<>
<DropdownMenuItem
icon={TrashIcon}
onSelect={toggleDialog}
dataTestId="clear-canvas-button"
ariaLabel={t("buttons.clearReset")}
>
{t("buttons.clearReset")}
</DropdownMenuItem>
{showDialog && (
<ConfirmDialog
onConfirm={() => {
onConfirm();
toggleDialog();
}}
onCancel={toggleDialog}
title={t("clearCanvasDialog.title")}
>
<p className="clear-canvas__content"> {t("alerts.clearReset")}</p>
</ConfirmDialog>
)}
</>
);
};
export default ClearCanvas;

View file

@ -2,48 +2,30 @@ import { t } from "../i18n";
import { UsersIcon } from "./icons";
import "./CollabButton.scss";
import DropdownMenuItem from "./dropdownMenu/DropdownMenuItem";
import clsx from "clsx";
const CollabButton = ({
isCollaborating,
collaboratorCount,
onClick,
isInHamburgerMenu = true,
}: {
isCollaborating: boolean;
collaboratorCount: number;
onClick: () => void;
isInHamburgerMenu?: boolean;
}) => {
return (
<>
{isInHamburgerMenu ? (
<DropdownMenuItem
dataTestId="collab-button"
icon={UsersIcon}
onSelect={onClick}
ariaLabel={t("labels.liveCollaboration")}
>
{t("labels.liveCollaboration")}
</DropdownMenuItem>
) : (
<button
className={clsx("collab-button", { active: isCollaborating })}
type="button"
onClick={onClick}
style={{ position: "relative" }}
title={t("labels.liveCollaboration")}
>
{UsersIcon}
{collaboratorCount > 0 && (
<div className="CollabButton-collaborators">
{collaboratorCount}
</div>
)}
</button>
<button
className={clsx("collab-button", { active: isCollaborating })}
type="button"
onClick={onClick}
style={{ position: "relative" }}
title={t("labels.liveCollaboration")}
>
{UsersIcon}
{collaboratorCount > 0 && (
<div className="CollabButton-collaborators">{collaboratorCount}</div>
)}
</>
</button>
);
};

View file

@ -39,8 +39,8 @@ export const ContextMenu = React.memo(
if (
item &&
(item === CONTEXT_MENU_SEPARATOR ||
!item.contextItemPredicate ||
item.contextItemPredicate(
!item.predicate ||
item.predicate(
elements,
appState,
actionManager.app.props,

View file

@ -183,7 +183,9 @@ const LayerUI = ({
<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 />
)}
@ -350,7 +352,6 @@ const LayerUI = ({
<UserList collaborators={appState.collaborators} />
{onCollabButtonClick && (
<CollabButton
isInHamburgerMenu={false}
isCollaborating={isCollaborating}
collaboratorCount={appState.collaborators.size}
onClick={onCollabButtonClick}

View file

@ -1,4 +1,5 @@
import clsx from "clsx";
import { actionShortcuts } from "../../actions";
import { ActionManager } from "../../actions/manager";
import { t } from "../../i18n";
import { AppState, UIChildrenComponents } from "../../types";
@ -9,6 +10,7 @@ import {
ZoomActions,
} from "../Actions";
import { useDevice } from "../App";
import { HelpButton } from "../HelpButton";
import { WelcomeScreenHelpArrow } from "../icons";
import { Section } from "../Section";
import Stack from "../Stack";
@ -86,7 +88,10 @@ const Footer = ({
</div>
</WelcomeScreenDecor>
{actionManager.renderAction("toggleShortcuts")}
<HelpButton
title={t("helpDialog.title")}
onClick={() => actionManager.executeAction(actionShortcuts)}
/>
</div>
</div>
<ExitZenModeAction

View file

@ -6,34 +6,81 @@ import {
useExcalidrawSetAppState,
useExcalidrawActionManager,
} from "../App";
import { ExportIcon, ExportImageIcon, UsersIcon } from "../icons";
import {
ExportIcon,
ExportImageIcon,
HelpIcon,
LoadIcon,
MoonIcon,
save,
SunIcon,
TrashIcon,
UsersIcon,
} from "../icons";
import { GithubIcon, DiscordIcon, TwitterIcon } from "../icons";
import DropdownMenuItem from "../dropdownMenu/DropdownMenuItem";
import DropdownMenuItemLink from "../dropdownMenu/DropdownMenuItemLink";
import {
actionClearCanvas,
actionLoadScene,
actionSaveToActiveFile,
actionShortcuts,
actionToggleTheme,
} from "../../actions";
import "./DefaultItems.scss";
import { useState } from "react";
import ConfirmDialog from "../ConfirmDialog";
export const LoadScene = () => {
// FIXME Hack until we tie "t" to lang state
// eslint-disable-next-line
const appState = useExcalidrawAppState();
const actionManager = useExcalidrawActionManager();
if (appState.viewModeEnabled) {
if (!actionManager.isActionEnabled(actionLoadScene)) {
return null;
}
return actionManager.renderAction("loadScene");
return (
<DropdownMenuItem
icon={LoadIcon}
onSelect={() => actionManager.executeAction(actionLoadScene)}
dataTestId="load-button"
shortcut={getShortcutFromShortcutName("loadScene")}
ariaLabel={t("buttons.load")}
>
{t("buttons.load")}
</DropdownMenuItem>
);
};
LoadScene.displayName = "LoadScene";
export const SaveToActiveFile = () => {
// FIXME Hack until we tie "t" to lang state
// eslint-disable-next-line
const appState = useExcalidrawAppState();
const actionManager = useExcalidrawActionManager();
if (!appState.fileHandle) {
if (!actionManager.isActionEnabled(actionSaveToActiveFile)) {
return null;
}
return actionManager.renderAction("saveToActiveFile");
return (
<DropdownMenuItem
shortcut={getShortcutFromShortcutName("saveScene")}
dataTestId="save-button"
onSelect={() => actionManager.executeAction(actionSaveToActiveFile)}
icon={save}
ariaLabel={`${t("buttons.save")}`}
>{`${t("buttons.save")}`}</DropdownMenuItem>
);
};
SaveToActiveFile.displayName = "SaveToActiveFile";
export const SaveAsImage = () => {
const setAppState = useExcalidrawSetAppState();
// Hack until we tie "t" to lang state
// FIXME Hack until we tie "t" to lang state
// eslint-disable-next-line
const appState = useExcalidrawAppState();
return (
@ -51,32 +98,96 @@ export const SaveAsImage = () => {
SaveAsImage.displayName = "SaveAsImage";
export const Help = () => {
// Hack until we tie "t" to lang state
// FIXME Hack until we tie "t" to lang state
// eslint-disable-next-line
const appState = useExcalidrawAppState();
const actionManager = useExcalidrawActionManager();
return actionManager.renderAction("toggleShortcuts", undefined, true);
return (
<DropdownMenuItem
dataTestId="help-menu-item"
icon={HelpIcon}
onSelect={() => actionManager.executeAction(actionShortcuts)}
shortcut="?"
ariaLabel={t("helpDialog.title")}
>
{t("helpDialog.title")}
</DropdownMenuItem>
);
};
Help.displayName = "Help";
export const ClearCanvas = () => {
// FIXME Hack until we tie "t" to lang state
// eslint-disable-next-line
const appState = useExcalidrawAppState();
const actionManager = useExcalidrawActionManager();
if (appState.viewModeEnabled) {
const [showDialog, setShowDialog] = useState(false);
const toggleDialog = () => setShowDialog(!showDialog);
if (!actionManager.isActionEnabled(actionClearCanvas)) {
return null;
}
return actionManager.renderAction("clearCanvas");
return (
<>
<DropdownMenuItem
icon={TrashIcon}
onSelect={toggleDialog}
dataTestId="clear-canvas-button"
ariaLabel={t("buttons.clearReset")}
>
{t("buttons.clearReset")}
</DropdownMenuItem>
{/* FIXME this should live outside MainMenu so it stays open
if menu is closed */}
{showDialog && (
<ConfirmDialog
onConfirm={() => {
actionManager.executeAction(actionClearCanvas);
toggleDialog();
}}
onCancel={toggleDialog}
title={t("clearCanvasDialog.title")}
>
<p className="clear-canvas__content"> {t("alerts.clearReset")}</p>
</ConfirmDialog>
)}
</>
);
};
ClearCanvas.displayName = "ClearCanvas";
export const ToggleTheme = () => {
// Hack until we tie "t" to lang state
// eslint-disable-next-line
const appState = useExcalidrawAppState();
const actionManager = useExcalidrawActionManager();
return actionManager.renderAction("toggleTheme");
if (!actionManager.isActionEnabled(actionToggleTheme)) {
return null;
}
return (
<DropdownMenuItem
onSelect={() => {
return actionManager.executeAction(actionToggleTheme);
}}
icon={appState.theme === "dark" ? SunIcon : MoonIcon}
dataTestId="toggle-dark-mode"
shortcut={getShortcutFromShortcutName("toggleTheme")}
ariaLabel={
appState.theme === "dark"
? t("buttons.lightMode")
: t("buttons.darkMode")
}
>
{appState.theme === "dark"
? t("buttons.lightMode")
: t("buttons.darkMode")}
</DropdownMenuItem>
);
};
ToggleTheme.displayName = "ToggleTheme";
@ -101,7 +212,7 @@ export const ChangeCanvasBackground = () => {
ChangeCanvasBackground.displayName = "ChangeCanvasBackground";
export const Export = () => {
// Hack until we tie "t" to lang state
// FIXME Hack until we tie "t" to lang state
// eslint-disable-next-line
const appState = useExcalidrawAppState();
const setAppState = useExcalidrawSetAppState();
@ -154,7 +265,7 @@ export const LiveCollaboration = ({
onSelect: () => void;
isCollaborating: boolean;
}) => {
// Hack until we tie "t" to lang state
// FIXME Hack until we tie "t" to lang state
// eslint-disable-next-line
const appState = useExcalidrawAppState();
return (