feat: text tool UX, image crop, text format toolbar, double-click focus

- Text tool: click-to-place immediately opens inline editor, auto-switches
  back to select tool. Empty text cleanup on save.
- Crop: select image + press C (or right-click > Crop) to enter crop mode.
  8 drag handles with rule-of-thirds grid, dimmed outside area.
  Enter confirms, Escape cancels. Non-destructive (stored as normalized rect).
- Text format toolbar: appears when text items selected, with font size +/-,
  font family dropdown, and color picker with presets.
- Double-click image: zoom-to-fit (PureRef-style focus)
- Entrance animation: replaced bounce with simple fade-in (no delay before
  items become interactive)
- TextEditor: allow empty text (caller handles cleanup)
This commit is contained in:
Hiren Kangad
2026-03-11 17:22:25 +05:30
parent 4ed475c62e
commit 58da934ec1
14 changed files with 785 additions and 50 deletions
+3
View File
@@ -31,6 +31,7 @@ interface ShortcutHandlerDeps {
setShowHelp: React.Dispatch<React.SetStateAction<boolean>>;
setFocusMode: React.Dispatch<React.SetStateAction<boolean>>;
setReviewMode: React.Dispatch<React.SetStateAction<boolean>>;
startCrop?: () => void;
}
/**
@@ -43,6 +44,7 @@ export function useShortcutHandler(deps: ShortcutHandlerDeps) {
handleGroup, handleUngroup,
setActiveTool, setCanUndo, setCanRedo, setZoom,
setShowGrid, setShowHelp, setFocusMode, setReviewMode,
startCrop,
} = deps;
useEffect(() => {
@@ -91,6 +93,7 @@ export function useShortcutHandler(deps: ShortcutHandlerDeps) {
toggleShowHelp: () => setShowHelp((v) => !v),
toggleFocusMode: () => setFocusMode((v) => !v),
toggleReviewMode: () => setReviewMode((v) => !v),
startCrop,
pasteFromSystemClipboard: async (): Promise<string> => {
if (!resolvedBoardId) return 'No board';
const msg = await pasteFromSystemClipboard(scene, viewport, resolvedBoardId, onCanvasChange);