diff --git a/.changeset/keyboard-zoom.md b/.changeset/keyboard-zoom.md new file mode 100644 index 000000000..3444eab61 --- /dev/null +++ b/.changeset/keyboard-zoom.md @@ -0,0 +1,5 @@ +--- +'@workflowbuilder/sdk': minor +--- + +The editor now supports keyboard zoom: `Ctrl/Cmd` with `+`/`=` zooms in and `Ctrl/Cmd` with `-` zooms out while the canvas is focused. diff --git a/apps/demo/src/app/plugins/help/components/watermark/watermark.module.css b/apps/demo/src/app/plugins/help/components/watermark/watermark.module.css index 88aa096be..62c283185 100644 --- a/apps/demo/src/app/plugins/help/components/watermark/watermark.module.css +++ b/apps/demo/src/app/plugins/help/components/watermark/watermark.module.css @@ -13,7 +13,7 @@ opacity: 1; } - z-index: 5; + z-index: 0; :global(html[data-theme='dark']) & { path { diff --git a/apps/demo/src/app/plugins/help/plugin-exports.ts b/apps/demo/src/app/plugins/help/plugin-exports.ts index 0026430e5..3228fbeb0 100644 --- a/apps/demo/src/app/plugins/help/plugin-exports.ts +++ b/apps/demo/src/app/plugins/help/plugin-exports.ts @@ -6,5 +6,8 @@ import { Watermark } from './components/watermark/watermark'; export function plugin(): void { registerComponentDecorator('DiagramContainer', { content: Watermark, + // Render after the canvas so the watermark paints above nodes/edges, + // while `z-index: 0` keeps it below the side panels (z-index: 1). + place: 'after', }); } diff --git a/apps/docs/src/content/docs/overview/features/diagram-state-management.md b/apps/docs/src/content/docs/overview/features/diagram-state-management.md index 9c4907b73..8d8471cf3 100644 --- a/apps/docs/src/content/docs/overview/features/diagram-state-management.md +++ b/apps/docs/src/content/docs/overview/features/diagram-state-management.md @@ -58,6 +58,8 @@ Workflow Builder automatically persists workflow changes in the background witho | Paste | `Ctrl+V` | `Cmd+V` | | Cut | `Ctrl+X` | `Cmd+X` | | Select all | `Ctrl+A` | `Cmd+A` | +| Zoom in | `Ctrl++` | `Cmd++` | +| Zoom out | `Ctrl+-` | `Cmd+-` | | Undo | `Ctrl+Z` | `Cmd+Z` | | Redo | `Ctrl+Shift+Z` | `Cmd+Shift+Z` | diff --git a/packages/sdk/src/hooks/use-command-handler-keyboard.ts b/packages/sdk/src/hooks/use-command-handler-keyboard.ts index 44c3c0284..13f50ced7 100644 --- a/packages/sdk/src/hooks/use-command-handler-keyboard.ts +++ b/packages/sdk/src/hooks/use-command-handler-keyboard.ts @@ -6,10 +6,25 @@ import { useKeyPress } from './use-key-press'; export function useCommandHandlerKeyboard(commandHandler: CommandHandler) { const a = useKeyPress('a', { withControlOrMeta: true }); + const plus = useKeyPress('+', { withControlOrMeta: true }); + const equal = useKeyPress('=', { withControlOrMeta: true }); + const minus = useKeyPress('-', { withControlOrMeta: true }); useEffect(() => { if (a) { commandHandler.selectAll(); } }, [a]); + + useEffect(() => { + if (plus || equal) { + commandHandler.zoomIn(); + } + }, [plus, equal]); + + useEffect(() => { + if (minus) { + commandHandler.zoomOut(); + } + }, [minus]); } diff --git a/packages/sdk/src/hooks/use-command-handler.ts b/packages/sdk/src/hooks/use-command-handler.ts index 4e3dea6da..d2fc7b0e3 100644 --- a/packages/sdk/src/hooks/use-command-handler.ts +++ b/packages/sdk/src/hooks/use-command-handler.ts @@ -1,15 +1,18 @@ -import { useOnSelectionChange, useStoreApi } from '@xyflow/react'; +import { useOnSelectionChange, useReactFlow, useStoreApi } from '@xyflow/react'; import { useCallback, useState } from 'react'; import type { WorkflowBuilderOnSelectionChangeParams } from '../node/common'; export type CommandHandler = { selectAll: () => void; + zoomIn: () => void; + zoomOut: () => void; }; export function useCommandHandler(): CommandHandler { const [_, setSelection] = useState(); const reactFlowStore = useStoreApi(); + const { zoomIn, zoomOut } = useReactFlow(); useOnSelectionChange({ onChange: (change) => setSelection(change as WorkflowBuilderOnSelectionChangeParams), @@ -21,7 +24,17 @@ export function useCommandHandler(): CommandHandler { state.addSelectedEdges(state.edges.map((edge) => edge.id)); }, [reactFlowStore]); + const zoomInCommand = useCallback(() => { + zoomIn(); + }, [zoomIn]); + + const zoomOutCommand = useCallback(() => { + zoomOut(); + }, [zoomOut]); + return { selectAll, + zoomIn: zoomInCommand, + zoomOut: zoomOutCommand, }; }