diff --git a/src/actions/actionCanvas.tsx b/src/actions/actionCanvas.tsx index dacd0ca5..eb811b62 100644 --- a/src/actions/actionCanvas.tsx +++ b/src/actions/actionCanvas.tsx @@ -1,7 +1,7 @@ import React from "react"; import { getDefaultAppState } from "../appState"; import { ColorPicker } from "../components/ColorPicker"; -import { resetZoom, trash, zoomIn, zoomOut } from "../components/icons"; +import { trash, zoomIn, zoomOut } from "../components/icons"; import { ToolButton } from "../components/ToolButton"; import { DarkModeToggle } from "../components/DarkModeToggle"; import { ZOOM_STEP } from "../constants"; @@ -17,6 +17,7 @@ import { getNewZoom } from "../scene/zoom"; import { AppState, NormalizedZoomValue } from "../types"; import { getShortcutKey } from "../utils"; import { register } from "./register"; +import { Tooltip } from "../components/Tooltip"; export const actionChangeViewBackgroundColor = register({ name: "changeViewBackgroundColor", @@ -108,6 +109,7 @@ export const actionZoomIn = register({ onClick={() => { updateData(null); }} + size="small" /> ), keyTest: (event) => @@ -142,6 +144,7 @@ export const actionZoomOut = register({ onClick={() => { updateData(null); }} + size="small" /> ), keyTest: (event) => @@ -168,16 +171,21 @@ export const actionResetZoom = register({ commitToHistory: false, }; }, - PanelComponent: ({ updateData }) => ( - { - updateData(null); - }} - /> + PanelComponent: ({ updateData, appState }) => ( + + { + updateData(null); + }} + size="small" + > + {(appState.zoom.value * 100).toFixed(0)}% + + ), keyTest: (event) => (event.code === CODES.ZERO || event.code === CODES.NUM_ZERO) && diff --git a/src/actions/actionExport.tsx b/src/actions/actionExport.tsx index e3208615..3916b0eb 100644 --- a/src/actions/actionExport.tsx +++ b/src/actions/actionExport.tsx @@ -70,7 +70,7 @@ export const actionChangeExportScale = register({ return ( {t("labels.exportEmbedScene")} -
{questionCircle}
+
{questionCircle}
), diff --git a/src/actions/actionHistory.tsx b/src/actions/actionHistory.tsx index 6f7536df..2653eb70 100644 --- a/src/actions/actionHistory.tsx +++ b/src/actions/actionHistory.tsx @@ -69,12 +69,13 @@ export const createUndoAction: ActionCreator = (history) => ({ event[KEYS.CTRL_OR_CMD] && event.key.toLowerCase() === KEYS.Z && !event.shiftKey, - PanelComponent: ({ updateData }) => ( + PanelComponent: ({ updateData, data }) => ( ), commitToHistory: () => false, @@ -89,12 +90,13 @@ export const createRedoAction: ActionCreator = (history) => ({ event.shiftKey && event.key.toLowerCase() === KEYS.Z) || (isWindows && event.ctrlKey && !event.shiftKey && event.key === KEYS.Y), - PanelComponent: ({ updateData }) => ( + PanelComponent: ({ updateData, data }) => ( ), commitToHistory: () => false, diff --git a/src/actions/actionNavigate.tsx b/src/actions/actionNavigate.tsx index 2da47779..4d64879a 100644 --- a/src/actions/actionNavigate.tsx +++ b/src/actions/actionNavigate.tsx @@ -30,8 +30,8 @@ export const actionGoToCollaborator = register({ commitToHistory: false, }; }, - PanelComponent: ({ appState, updateData, id }) => { - const clientId = id; + PanelComponent: ({ appState, updateData, data }) => { + const clientId: string | undefined = data?.id; if (!clientId) { return null; } diff --git a/src/actions/manager.tsx b/src/actions/manager.tsx index 9e2ce75b..7b83ae59 100644 --- a/src/actions/manager.tsx +++ b/src/actions/manager.tsx @@ -5,6 +5,7 @@ import { UpdaterFn, ActionName, ActionResult, + PanelComponentProps, } from "./types"; import { ExcalidrawElement } from "../element/types"; import { AppProps, AppState } from "../types"; @@ -107,11 +108,10 @@ export class ActionManager implements ActionsManagerInterface { ); } - // Id is an attribute that we can use to pass in data like keys. - // This is needed for dynamically generated action components - // like the user list. We can use this key to extract more - // data from app state. This is an alternative to generic prop hell! - renderAction = (name: ActionName, id?: string) => { + /** + * @param data additional data sent to the PanelComponent + */ + renderAction = (name: ActionName, data?: PanelComponentProps["data"]) => { const canvasActions = this.app.props.UIOptions.canvasActions; if ( @@ -139,8 +139,8 @@ export class ActionManager implements ActionsManagerInterface { elements={this.getElementsIncludingDeleted()} appState={this.getAppState()} updateData={updateData} - id={id} appProps={this.app.props} + data={data} /> ); } diff --git a/src/actions/types.ts b/src/actions/types.ts index c9658148..674a9a3f 100644 --- a/src/actions/types.ts +++ b/src/actions/types.ts @@ -2,6 +2,7 @@ import React from "react"; import { ExcalidrawElement } from "../element/types"; import { AppState, ExcalidrawProps } from "../types"; import Library from "../data/library"; +import { ToolButtonSize } from "../components/ToolButton"; /** if false, the action should be prevented */ export type ActionResult = @@ -102,15 +103,17 @@ export type ActionName = | "exportWithDarkMode" | "toggleTheme"; +export type PanelComponentProps = { + elements: readonly ExcalidrawElement[]; + appState: AppState; + updateData: (formData?: any) => void; + appProps: ExcalidrawProps; + data?: Partial<{ id: string; size: ToolButtonSize }>; +}; + export interface Action { name: ActionName; - PanelComponent?: React.FC<{ - elements: readonly ExcalidrawElement[]; - appState: AppState; - updateData: (formData?: any) => void; - appProps: ExcalidrawProps; - id?: string; - }>; + PanelComponent?: React.FC; perform: ActionFn; keyPriority?: number; keyTest?: ( diff --git a/src/components/Actions.tsx b/src/components/Actions.tsx index 63d2ce03..a651c07a 100644 --- a/src/components/Actions.tsx +++ b/src/components/Actions.tsx @@ -207,9 +207,6 @@ export const ZoomActions = ({ {renderAction("zoomIn")} {renderAction("zoomOut")} {renderAction("resetZoom")} -
- {(zoom.value * 100).toFixed(0)}% -
); diff --git a/src/components/CheckboxItem.scss b/src/components/CheckboxItem.scss index ae051798..a0a25ca0 100644 --- a/src/components/CheckboxItem.scss +++ b/src/components/CheckboxItem.scss @@ -81,7 +81,7 @@ align-items: center; } - .Tooltip-icon { + .excalidraw-tooltip-icon { width: 1em; height: 1em; } diff --git a/src/components/LayerUI.scss b/src/components/LayerUI.scss index 1245aa58..e018ec82 100644 --- a/src/components/LayerUI.scss +++ b/src/components/LayerUI.scss @@ -73,10 +73,10 @@ } :root[dir="ltr"] &.layer-ui__wrapper__footer-left--transition-left { - transform: translate(-92px, 0); + transform: translate(-76px, 0); } :root[dir="rtl"] &.layer-ui__wrapper__footer-left--transition-left { - transform: translate(92px, 0); + transform: translate(76px, 0); } &.layer-ui__wrapper__footer-left--transition-bottom { @@ -120,5 +120,15 @@ .disable-zen-mode--visible { pointer-events: all; } + + .layer-ui__wrapper__footer-left { + margin-bottom: 0.2em; + } + + .layer-ui__wrapper__footer-right { + margin-top: auto; + margin-bottom: auto; + margin-inline-end: 1em; + } } } diff --git a/src/components/LayerUI.tsx b/src/components/LayerUI.tsx index f42c1bc1..eb3bcd51 100644 --- a/src/components/LayerUI.tsx +++ b/src/components/LayerUI.tsx @@ -632,7 +632,9 @@ const LayerUI = ({ label={client.username || "Unknown user"} key={clientId} > - {actionManager.renderAction("goToCollaborator", clientId)} + {actionManager.renderAction("goToCollaborator", { + id: clientId, + })} ))} @@ -665,6 +667,16 @@ const LayerUI = ({ zoom={appState.zoom} /> + {!viewModeEnabled && ( +
+ {actionManager.renderAction("undo", { size: "small" })} + {actionManager.renderAction("redo", { size: "small" })} +
+ )} diff --git a/src/components/LibraryButton.tsx b/src/components/LibraryButton.tsx index c5a55460..7fca4e92 100644 --- a/src/components/LibraryButton.tsx +++ b/src/components/LibraryButton.tsx @@ -21,7 +21,7 @@ export const LibraryButton: React.FC<{