Merge remote-tracking branch 'origin/master' into editor-agent-more-tools
This commit is contained in:
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user