Files
Genarrative/apps/ai-game-creator-shell/tests/windowChromeOverlayContract.test.ts
kdletters c38d07044a 修复 AGC 弹窗打开时自绘标题栏窗口按钮失效
- ThemedModal 的焦点陷阱只放行落在 [data-window-chrome-bar] 内的点击,标题栏拖拽与最小化/最大化/关闭恢复可用,工作区内容点击仍被拦住
- WindowChrome 标题栏加 data-window-chrome-bar 标记,作为这条约定的唯一契约点
- styles.css 明确「全屏弹层一律从标题栏下方开始」,.app-update-overlay 从 inset:0 改为标题栏下方,.game-publish-progress-overlay 显式声明 top
- 新增 tests/windowChromeOverlayContract.test.ts 覆盖 7 个全屏弹层;themedModal / WindowChrome 用例补「标题栏点击放行 + 工作区点击仍被拦」回归;gamePublishFeedback 用例按新口径断言
- pitfalls 记录该静默失效的机制与现行口径
2026-09-23 19:05:33 +08:00

54 lines
1.8 KiB
TypeScript

// @vitest-environment jsdom
import { readFileSync } from 'node:fs';
import { describe, expect, it } from 'vitest';
import { repoPath } from './repoPath';
import { parseStyleSheet } from './styleCascade';
const STYLES_PATH = repoPath('apps/ai-game-creator-shell/src/styles.css');
/**
* 全屏弹层清单:每一层都必须从自绘标题栏下方开始。
*
* 标题栏是窗口边框,不是弹层内容 —— 只要有一个全屏遮罩盖住它,弹窗打开时
* 「最小化 / 最大化 / 关闭」就会被挡住。焦点陷阱那一半的问题见
* `themedModal.test.tsx` 与 `WindowChrome.test.tsx`;新增全屏弹层时把类名加进这份清单。
*/
const WINDOW_CHROME_SAFE_OVERLAYS = [
// ThemedModal 与共享弹层的通用遮罩:top 由这条规则统一抬到标题栏下方。
'.fixed.inset-0',
'.app-update-overlay',
'.game-publish-progress-overlay',
'.launcher-dialog-backdrop',
'.settings-overlay',
'.game-approval-backdrop',
'.project-chat-settings-backdrop',
] as const;
function declarationsForSelector(css: string, selector: string) {
const merged = new Map<string, string>();
for (const rule of parseStyleSheet(css)) {
if (!rule.selectors.includes(selector)) {
continue;
}
for (const [property, value] of rule.declarations) {
merged.set(property, value);
}
}
return merged;
}
describe('窗口标题栏与全屏弹层的层叠约定', () => {
const css = readFileSync(STYLES_PATH, 'utf8');
it.each(WINDOW_CHROME_SAFE_OVERLAYS)('%s 从标题栏下方开始', (selector) => {
const declarations = declarationsForSelector(css, selector);
expect(
declarations.get('top'),
`${selector} 必须声明 top: var(--window-chrome-height)`,
).toBe('var(--window-chrome-height)');
});
});