接入 UI 编辑器撤销重做入口
在编辑器头部增加撤销与重做按钮及禁用态 增加桌面 Cmd/Ctrl 快捷键并保留文本控件原生行为
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import { ChevronLeft } from 'lucide-react';
|
||||
import { ChevronLeft, Redo2, Undo2 } from 'lucide-react';
|
||||
import { type ReactNode, useEffect, useMemo, useState } from 'react';
|
||||
|
||||
import { ThemedModal } from '../../components/modal/ThemedModal';
|
||||
@@ -82,6 +82,37 @@ export default function UiEditorPage({
|
||||
if (session.save.isDirty) setGenerateSuccess(null);
|
||||
}, [session.save.isDirty]);
|
||||
|
||||
useEffect(() => {
|
||||
const isEditableTarget = (target: EventTarget | null) => {
|
||||
const element = target instanceof HTMLElement ? target : null;
|
||||
return Boolean(
|
||||
element?.isContentEditable ||
|
||||
element?.closest(
|
||||
'input, textarea, select, button, a, [contenteditable="true"], [role="button"]',
|
||||
),
|
||||
);
|
||||
};
|
||||
const onKeyDown = (event: KeyboardEvent) => {
|
||||
if (
|
||||
isEditableTarget(event.target) ||
|
||||
(!event.ctrlKey && !event.metaKey)
|
||||
) {
|
||||
return;
|
||||
}
|
||||
const isUndo = event.key.toLowerCase() === 'z' && !event.shiftKey;
|
||||
const isRedo =
|
||||
(event.key.toLowerCase() === 'z' && event.shiftKey) ||
|
||||
(event.ctrlKey && event.key.toLowerCase() === 'y');
|
||||
if (isUndo && session.history.undo()) {
|
||||
event.preventDefault();
|
||||
} else if (isRedo && session.history.redo()) {
|
||||
event.preventDefault();
|
||||
}
|
||||
};
|
||||
window.addEventListener('keydown', onKeyDown);
|
||||
return () => window.removeEventListener('keydown', onKeyDown);
|
||||
}, [session.history]);
|
||||
|
||||
async function save(afterReturn = false) {
|
||||
if (await session.save.save()) {
|
||||
if (afterReturn) {
|
||||
@@ -155,6 +186,26 @@ export default function UiEditorPage({
|
||||
</button>
|
||||
<strong className="text-sm">{resourceLabel ?? 'UI 设计'}</strong>
|
||||
<div className="game-workbench-editor-actions">
|
||||
<button
|
||||
type="button"
|
||||
className="inline-flex items-center gap-1 rounded-lg border border-(--platform-subpanel-border) px-2.5 py-1.5 text-sm disabled:cursor-not-allowed disabled:opacity-40"
|
||||
aria-label="撤销"
|
||||
disabled={!session.history.canUndo || session.save.isLocked}
|
||||
onClick={() => session.history.undo()}
|
||||
>
|
||||
<Undo2 size={16} aria-hidden="true" />
|
||||
撤销
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
className="inline-flex items-center gap-1 rounded-lg border border-(--platform-subpanel-border) px-2.5 py-1.5 text-sm disabled:cursor-not-allowed disabled:opacity-40"
|
||||
aria-label="重做"
|
||||
disabled={!session.history.canRedo || session.save.isLocked}
|
||||
onClick={() => session.history.redo()}
|
||||
>
|
||||
<Redo2 size={16} aria-hidden="true" />
|
||||
重做
|
||||
</button>
|
||||
{walletEntry ? (
|
||||
<div className="game-workbench-editor-wallet">{walletEntry}</div>
|
||||
) : null}
|
||||
|
||||
Reference in New Issue
Block a user