import clsx from "clsx"; import { useState } from "react"; import { KEYS } from "@excalidraw/common"; import { useTunnels } from "../context/tunnels"; import { t } from "../i18n"; import { useEditorInterface, useStylesPanelMode } from "./App"; import { HintViewer } from "./HintViewer"; import { Island } from "./Island"; import { LockButton } from "./LockButton"; import { PenModeButton } from "./PenModeButton"; import Stack from "./Stack"; import DropdownMenu from "./dropdownMenu/DropdownMenu"; import { drawShapeToolIcon, EmbedIcon, frameToolIcon, ImageIcon, LassoIcon, laserPointerToolIcon, bucketFillIcon, MagicIcon, mermaidLogoIcon, DotsIcon, } from "./icons"; import { ArrowToolButton, DiamondToolButton, EllipseToolButton, EraserToolButton, FreedrawToolPopover, FreedrawToolButton, getToolShortcut, HandToolButton, isToolButtonDisabled, LassoToolButton, LineToolButton, RectangleToolButton, SelectionToolButton, SelectionToolPopover, StickyNoteToolButton, TextToolButton, } from "./Tools"; import type { AppClassProperties, AppProps, AppState, UIAppState, } from "../types"; const ExtraToolsDropdown = ({ app, activeTool, setAppState, UIOptions, }: { app: AppClassProperties; activeTool: UIAppState["activeTool"]; setAppState: React.Component["setState"]; UIOptions: AppProps["UIOptions"]; }) => { const [isExtraToolsMenuOpen, setIsExtraToolsMenuOpen] = useState(false); const isFullStylesPanel = useStylesPanelMode() === "full"; const { TTDDialogTriggerTunnel } = useTunnels(); const imageToolSelected = activeTool.type === "image"; const frameToolSelected = activeTool.type === "frame"; const drawShapeToolSelected = activeTool.type === "autoshape"; const laserToolSelected = activeTool.type === "laser"; const bucketFillToolSelected = activeTool.type === "bucketfill"; const lassoToolSelected = isFullStylesPanel && activeTool.type === "lasso" && app.state.preferredSelectionTool.type !== "lasso"; const embeddableToolSelected = activeTool.type === "embeddable"; return ( { setIsExtraToolsMenuOpen(!isExtraToolsMenuOpen); setAppState({ openMenu: null, openPopup: null }); }} title={t("toolBar.extraTools")} > {imageToolSelected ? ImageIcon : frameToolSelected ? frameToolIcon : embeddableToolSelected ? EmbedIcon : isFullStylesPanel && drawShapeToolSelected ? drawShapeToolIcon : laserToolSelected && !app.props.isCollaborating ? laserPointerToolIcon : lassoToolSelected ? LassoIcon : bucketFillToolSelected ? bucketFillIcon : DotsIcon} setIsExtraToolsMenuOpen(false)} onSelect={() => setIsExtraToolsMenuOpen(false)} className="App-toolbar__extra-tools-dropdown" > {UIOptions.tools?.image !== false && ( app.setActiveTool({ type: "image" })} icon={ImageIcon} shortcut={KEYS["9"]} data-testid="toolbar-image" selected={imageToolSelected} disabled={isToolButtonDisabled(app, "image")} > {t("toolBar.image")} )} app.setActiveTool({ type: "frame" })} icon={frameToolIcon} shortcut={KEYS.F.toLocaleUpperCase()} data-testid="toolbar-frame" selected={frameToolSelected} disabled={isToolButtonDisabled(app, "frame")} > {t("toolBar.frame")} app.setActiveTool({ type: "embeddable" })} icon={EmbedIcon} data-testid="toolbar-embeddable" selected={embeddableToolSelected} disabled={isToolButtonDisabled(app, "embeddable")} > {t("toolBar.embeddable")} app.setActiveTool({ type: "autoshape" })} icon={drawShapeToolIcon} shortcut={getToolShortcut("autoshape")} data-testid="toolbar-autoshape" selected={drawShapeToolSelected} disabled={isToolButtonDisabled(app, "autoshape")} > {t("toolBar.autoshape")} app.setActiveTool({ type: "laser" })} icon={laserPointerToolIcon} data-testid="toolbar-laser" selected={laserToolSelected} shortcut={KEYS.K.toLocaleUpperCase()} disabled={isToolButtonDisabled(app, "laser")} > {t("toolBar.laser")} app.setActiveTool({ type: "bucketfill" })} icon={bucketFillIcon} data-testid="toolbar-bucketfill" selected={bucketFillToolSelected} shortcut={KEYS.B.toLocaleUpperCase()} disabled={isToolButtonDisabled(app, "bucketfill")} > {t("toolBar.bucketfill")} {isFullStylesPanel && ( app.setActiveTool({ type: "lasso" })} icon={LassoIcon} data-testid="toolbar-lasso" selected={lassoToolSelected} disabled={isToolButtonDisabled(app, "lasso")} > {t("toolBar.lasso")} )}
Generate
{app.props.aiEnabled !== false && } app.setOpenDialog({ name: "ttd", tab: "mermaid" })} icon={mermaidLogoIcon} data-testid="toolbar-embeddable" > {t("toolBar.mermaidToExcalidraw")} {app.props.aiEnabled !== false && app.plugins.diagramToCode && ( app.onMagicframeToolSelect()} icon={MagicIcon} data-testid="toolbar-magicframe" badge={AI} disabled={isToolButtonDisabled(app, "magicframe")} > {t("toolBar.magicframe")} )}
); }; /** the main (desktop/tablet) toolbar island */ export const Toolbar = ({ app, appState, setAppState, UIOptions, onPenModeToggle, onLockToggle, heading, }: { app: AppClassProperties; appState: UIAppState; setAppState: React.Component["setState"]; UIOptions: AppProps["UIOptions"]; onPenModeToggle: AppClassProperties["togglePenMode"]; onLockToggle: () => void; heading: React.ReactNode; }) => { const editorInterface = useEditorInterface(); const isCompactStylesPanel = useStylesPanelMode() === "compact"; const activeTool = appState.activeTool; const toolProps = { app, activeTool }; return ( {heading} {/* in compact UI the pen mode button is rendered as a separate floating button below the compact actions menu */} {!isCompactStylesPanel && ( onPenModeToggle(null)} title={t("toolBar.penMode")} penDetected={appState.penDetected} /> )} {app.props.activeTool == null && ( <>
)} {isCompactStylesPanel ? ( ) : appState.preferredSelectionTool.type === "lasso" ? ( ) : ( )} {isCompactStylesPanel ? ( ) : ( )}
); };