Merge remote-tracking branch 'origin/master' into editor-agent-more-tools
Project CI / Repository checks (pull_request) Successful in 1m56s
Project CI / Frontend tests (pull_request) Successful in 1m52s
Project CI / Native shell tests (pull_request) Successful in 2m42s
Project CI / Backend tests (pull_request) Successful in 3m32s

This commit is contained in:
2026-07-27 10:24:33 +08:00
3 changed files with 38 additions and 1 deletions
@@ -66,6 +66,7 @@
- 底边栏中会在上方弹出二级选项的入口不再依赖点击展开。鼠标悬停到入口即可打开二级面板,鼠标离开入口和二级面板后自动收起;当前范围包括 `生成规范``生成音乐`
- 底边栏二级选项面板必须锚定到对应入口按钮本身,不使用屏幕居中或固定底部偏移;移动端窄屏下也应保持跟随入口位置。
- 生成图片和生成视频文本输入框紧贴参考图下方,取消旧网格预留导致的空白高度。
- 在生成类面板或独立修改弹窗的文本输入框内滚动时,滚轮只用于输入内容或面板自身,不得冒泡平移或缩放画布;
- 生成规范类图片固定使用 `16:9·2K · gpt-image-2`。这三个参数在面板底部沿用可编辑参数按钮的胶囊样式展示,但控件保持禁用不可点击,不提供比例、尺寸或模型修改入口。
- 宣发素材的 `游戏首图``详情五图``运营海报` 固定使用 `gpt-image-2`。面板底部只显示禁用态 `gpt-image-2` 模型胶囊和生成按钮,不出现 `nanobanana2` 选项;后端收到 `publication-material` 旧请求时也必须强制归一为 `gpt-image-2`
- 图片快速编辑保留一个提示词输入框,并展示与常规图片生成一致的比例 / 尺寸和模型选择;提示词 placeholder 为 `你希望素材如何修改?`,提交按钮显示 `修改`,不展示额外参考图控件。打开面板时优先继承原图关联生成器记录的模型、比例和尺寸;没有关联生成器时使用图层模型,并按原图真实分辨率推导比例和尺寸;模型缺失或已不受支持时回落到当前默认图片模型。切换模型后只展示该模型支持的参数,不兼容的当前值回落到该模型默认值,按钮泥点按选定模型和尺寸同步刷新。提交时必须同时传递 `model / aspectRatio / imageSize`;后端按模型选择 provider 协议:`nanobanana2` 使用 `generateContent + inline_data``gpt-image-2` 使用 `/v1/images/edits` multipart,不能把 nanobanana 模型 ID 发往 GPT edits 端点。
@@ -191,6 +191,27 @@ describe('useImageCanvasViewportControls', () => {
});
});
it('does not pan the canvas when a generation prompt receives wheel input', () => {
const { result, viewportElement } = renderViewportControls();
const prompt = document.createElement('textarea');
viewportElement.append(prompt);
const initialViewport = result.current.viewport;
const wheelEvent = new WheelEvent('wheel', {
bubbles: true,
cancelable: true,
deltaY: 120,
clientX: 260,
clientY: 190,
});
act(() => {
prompt.dispatchEvent(wheelEvent);
});
expect(result.current.viewport).toEqual(initialViewport);
expect(wheelEvent.defaultPrevented).toBe(false);
});
it('handles native two-axis wheel pan, ctrl wheel zoom and minimap movement', () => {
const rafCallbacks: FrameRequestCallback[] = [];
vi.spyOn(window, 'requestAnimationFrame').mockImplementation(
@@ -34,6 +34,15 @@ export const DEFAULT_IMAGE_CANVAS_VIEWPORT: CanvasViewport = {
scale: 0.5,
};
function isCanvasWheelInteractionTarget(target: EventTarget | null) {
return (
target instanceof Element &&
target.closest(
'input, textarea, select, [contenteditable="true"]',
) !== null
);
}
type UseImageCanvasViewportControlsOptions = {
canvasViewportRef: RefObject<HTMLDivElement | null>;
layers: CanvasLayer[];
@@ -253,12 +262,18 @@ export function useImageCanvasViewportControls({
const handleNativeWheel = useCallback(
(event: WheelEvent) => {
event.preventDefault();
// Let form controls and their scrollable panels keep native wheel input.
if (isCanvasWheelInteractionTarget(event.target)) {
return;
}
const viewportElement = canvasViewportRef.current;
if (!viewportElement) {
return;
}
event.preventDefault();
if (!event.ctrlKey && !event.metaKey) {
const useShiftWheelHorizontalFallback =
event.shiftKey && event.deltaX === 0;