diff --git a/CHANGELOG.md b/CHANGELOG.md index 537d733c01..bfac196ea5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ ## Unreleased +### Features + +- Undo/Redo buttons in the viewer toolbar (top-left, alongside the collapse and view-mode controls). The buttons subscribe to the history store via `subscribeHistoryCommandState`, dispatch through `runUndo`/`runRedo` (respecting the collaborative history delegate), and disable when nothing can be undone/redone. Keyboard shortcuts were already wired: Ctrl/Cmd+Z undo, Ctrl/Cmd+Shift+Z redo. + ### Fixes - Preserve custom scene materials across save, load, clone, fork, and live sync. Materials were dropped at every persistence boundary, so a scene reopened with default surfaces. Collections were dropped on MCP import for the same reason ([#597](https://github.com/pascalorg/editor/pull/597)) by [@ShiroKSH](https://github.com/ShiroKSH) diff --git a/apps/editor/components/viewer-toolbar.tsx b/apps/editor/components/viewer-toolbar.tsx index a707288ecf..d7822e6c98 100644 --- a/apps/editor/components/viewer-toolbar.tsx +++ b/apps/editor/components/viewer-toolbar.tsx @@ -10,6 +10,10 @@ import { DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger, + getHistoryCommandState, + runRedo, + runUndo, + subscribeHistoryCommandState, useEditor, useFloorplanAnnotationVisibility, useFloorplanMode, @@ -37,6 +41,7 @@ import { Layers3, Magnet, PenLine, + Redo2, Ruler, ScanLine, SlidersHorizontal, @@ -44,9 +49,10 @@ import { SquareUserRound, SwatchBook, Tag, + Undo2, } from 'lucide-react' import Image from 'next/image' -import { type ReactNode, useCallback } from 'react' +import { type ReactNode, useCallback, useEffect, useState } from 'react' import { flushSync } from 'react-dom' import { cn } from '@/lib/utils' import { Tooltip, TooltipContent, TooltipTrigger } from './toolbar-tooltip' @@ -686,10 +692,69 @@ function PreviewButton() { ) } +// Undo/Redo toolbar controls. They subscribe to the shared history state +// (`history.ts`) so buttons enable/disable as the scene history grows, and +// route through `runUndo`/`runRedo` so they honor a collaborative host +// delegate when one is installed. Keyboard shortcuts (Ctrl/Cmd+Z and +// Ctrl/Cmd+Shift+Z) are wired separately in `use-keyboard.ts` and land here +// via the same state subscription. +function HistoryControls() { + const [state, setState] = useState(() => getHistoryCommandState()) + + useEffect(() => { + return subscribeHistoryCommandState(() => setState(getHistoryCommandState())) + }, []) + + const undo = () => { + if (!getHistoryCommandState().canUndo) return + runUndo() + } + + const redo = () => { + if (!getHistoryCommandState().canRedo) return + runRedo() + } + + return ( +