fix preferred tool

This commit is contained in:
Ryan Di
2025-09-25 18:31:51 +10:00
parent f6c8880f2e
commit 9215b2043d
7 changed files with 36 additions and 38 deletions

View File

@@ -11,7 +11,6 @@ import {
THEME,
DEFAULT_GRID_STEP,
isTestEnv,
isMobileOrTablet,
} from "@excalidraw/common";
import type { AppState, NormalizedZoomValue } from "./types";
@@ -56,7 +55,7 @@ export const getDefaultAppState = (): Omit<
fromSelection: false,
lastActiveTool: null,
},
preferredSelectionTool: isMobileOrTablet() ? "lasso" : "selection",
preferredSelectionTool: "selection",
penMode: false,
penDetected: false,
errorMessage: null,

View File

@@ -1034,12 +1034,12 @@ export const MobileShapeActions = ({
export const ShapesSwitcher = ({
activeTool,
appState,
setAppState,
app,
UIOptions,
}: {
activeTool: UIAppState["activeTool"];
appState: UIAppState;
setAppState: React.Component<any, AppState>["setState"];
app: AppClassProperties;
UIOptions: AppProps["UIOptions"];
}) => {
@@ -1061,7 +1061,9 @@ export const ShapesSwitcher = ({
const frameToolSelected = activeTool.type === "frame";
const laserToolSelected = activeTool.type === "laser";
const lassoToolSelected =
activeTool.type === "lasso" && app.state.preferredSelectionTool !== "lasso";
app.state.stylesPanelMode === "full" &&
activeTool.type === "lasso" &&
app.state.preferredSelectionTool !== "lasso";
const embeddableToolSelected = activeTool.type === "embeddable";
@@ -1092,14 +1094,14 @@ export const ShapesSwitcher = ({
// use a ToolPopover for selection/lasso toggle as well
if (
(value === "selection" || value === "lasso") &&
appState.stylesPanelMode === "compact"
app.state.stylesPanelMode === "compact"
) {
return (
<ToolPopover
key={"selection-popover"}
app={app}
options={SELECTION_TOOLS}
activeTool={activeTool as any}
activeTool={activeTool}
defaultOption={app.state.preferredSelectionTool}
namePrefix="selectionType"
title={capitalizeString(t("toolBar.selection"))}
@@ -1107,7 +1109,9 @@ export const ShapesSwitcher = ({
onToolChange={(type: string) => {
if (type === "selection" || type === "lasso") {
app.setActiveTool({ type });
app.state.preferredSelectionTool = type as any;
setAppState({
preferredSelectionTool: type,
});
}
}}
displayedOption={
@@ -1115,9 +1119,7 @@ export const ShapesSwitcher = ({
(tool) => tool.type === app.state.preferredSelectionTool,
) || SELECTION_TOOLS[0]
}
isActive={
activeTool.type === "selection" || activeTool.type === "lasso"
}
fillable={activeTool.type === "selection"}
/>
);
}
@@ -1136,12 +1138,12 @@ export const ShapesSwitcher = ({
aria-keyshortcuts={shortcut}
data-testid={`toolbar-${value}`}
onPointerDown={({ pointerType }) => {
if (!appState.penDetected && pointerType === "pen") {
if (!app.state.penDetected && pointerType === "pen") {
app.togglePenMode(true);
}
if (value === "selection") {
if (appState.activeTool.type === "selection") {
if (app.state.activeTool.type === "selection") {
app.setActiveTool({ type: "lasso" });
} else {
app.setActiveTool({ type: "selection" });
@@ -1149,7 +1151,7 @@ export const ShapesSwitcher = ({
}
}}
onChange={({ pointerType }) => {
if (appState.activeTool.type !== value) {
if (app.state.activeTool.type !== value) {
trackEvent("toolbar", value, "ui");
}
if (value === "image") {
@@ -1222,7 +1224,7 @@ export const ShapesSwitcher = ({
>
{t("toolBar.laser")}
</DropdownMenu.Item>
{appState.stylesPanelMode === "full" && (
{app.state.stylesPanelMode === "full" && (
<DropdownMenu.Item
onSelect={() => app.setActiveTool({ type: "lasso" })}
icon={LassoIcon}

View File

@@ -2375,12 +2375,13 @@ class App extends React.Component<AppProps, AppState> {
activeTool.type === "selection"
? {
...activeTool,
type: this.state.preferredSelectionTool,
type: scene.appState.preferredSelectionTool,
}
: scene.appState.activeTool,
isLoading: false,
toast: this.state.toast,
};
if (initialData?.scrollToContent) {
scene.appState = {
...scene.appState,

View File

@@ -368,7 +368,7 @@ const LayerUI = ({
/>
<ShapesSwitcher
appState={appState}
setAppState={setAppState}
activeTool={appState.activeTool}
UIOptions={UIOptions}
app={app}

View File

@@ -97,9 +97,9 @@ export const MobileMenu = ({
const renderToolbar = () => {
return (
<MobileToolBar
appState={appState}
app={app}
onHandToolToggle={onHandToolToggle}
setAppState={setAppState}
/>
);
};

View File

@@ -82,17 +82,17 @@ const LINEAR_ELEMENT_TOOLS = [
] as const;
type MobileToolBarProps = {
appState: UIAppState;
app: AppClassProperties;
onHandToolToggle: () => void;
setAppState: React.Component<any, UIAppState>["setState"];
};
export const MobileToolBar = ({
appState,
app,
onHandToolToggle,
setAppState,
}: MobileToolBarProps) => {
const activeTool = appState.activeTool;
const activeTool = app.state.activeTool;
const [isOtherShapesMenuOpen, setIsOtherShapesMenuOpen] = useState(false);
const [lastActiveGenericShape, setLastActiveGenericShape] = useState<
"rectangle" | "diamond" | "ellipse"
@@ -128,12 +128,12 @@ export const MobileToolBar = ({
const { TTDDialogTriggerTunnel } = useTunnels();
const handleToolChange = (toolType: string, pointerType?: string) => {
if (appState.activeTool.type !== toolType) {
if (app.state.activeTool.type !== toolType) {
trackEvent("toolbar", toolType, "ui");
}
if (toolType === "selection") {
if (appState.activeTool.type === "selection") {
if (app.state.activeTool.type === "selection") {
// Toggle selection tool behavior if needed
} else {
app.setActiveTool({ type: "selection" });
@@ -172,17 +172,17 @@ export const MobileToolBar = ({
}
return true;
});
const extraToolSelected = extraTools.includes(appState.activeTool.type);
const extraToolSelected = extraTools.includes(activeTool.type);
const extraIcon = extraToolSelected
? appState.activeTool.type === "frame"
? activeTool.type === "frame"
? frameToolIcon
: appState.activeTool.type === "embeddable"
: activeTool.type === "embeddable"
? EmbedIcon
: appState.activeTool.type === "laser"
: activeTool.type === "laser"
? laserPointerToolIcon
: appState.activeTool.type === "text"
: activeTool.type === "text"
? TextIcon
: appState.activeTool.type === "magicframe"
: activeTool.type === "magicframe"
? MagicIcon
: extraToolsIcon
: extraToolsIcon;
@@ -191,7 +191,7 @@ export const MobileToolBar = ({
<div className="mobile-toolbar" ref={toolbarRef}>
{/* Hand Tool */}
<HandButton
checked={isHandToolActive(appState)}
checked={isHandToolActive(app.state)}
onChange={onHandToolToggle}
title={t("toolBar.hand")}
isMobile
@@ -209,7 +209,9 @@ export const MobileToolBar = ({
onToolChange={(type: string) => {
if (type === "selection" || type === "lasso") {
app.setActiveTool({ type });
app.state.preferredSelectionTool = type;
setAppState({
preferredSelectionTool: type,
});
}
}}
displayedOption={
@@ -217,9 +219,6 @@ export const MobileToolBar = ({
(tool) => tool.type === app.state.preferredSelectionTool,
) || SELECTION_TOOLS[0]
}
isActive={
activeTool.type === "selection" || activeTool.type === "lasso"
}
/>
{/* Free Draw */}
@@ -285,7 +284,6 @@ export const MobileToolBar = ({
SHAPE_TOOLS.find((tool) => tool.type === lastActiveGenericShape) ||
SHAPE_TOOLS[0]
}
isActive={["rectangle", "diamond", "ellipse"].includes(activeTool.type)}
/>
{/* Arrow/Line */}
@@ -315,7 +313,6 @@ export const MobileToolBar = ({
(tool) => tool.type === lastActiveLinearElement,
) || LINEAR_ELEMENT_TOOLS[0]
}
isActive={["arrow", "line"].includes(activeTool.type)}
/>
{/* Image */}

View File

@@ -30,7 +30,6 @@ type ToolPopoverProps = {
"data-testid": string;
onToolChange: (type: string) => void;
displayedOption: ToolOption;
isActive: boolean;
fillable?: boolean;
};
@@ -44,12 +43,12 @@ export const ToolPopover = ({
title,
"data-testid": dataTestId,
onToolChange,
isActive,
displayedOption,
fillable = false,
}: ToolPopoverProps) => {
const [isPopupOpen, setIsPopupOpen] = useState(false);
const currentType = activeTool.type;
const isActive = displayedOption.type === currentType;
const SIDE_OFFSET = 32 / 2 + 10;
// if currentType is not in options, close popup