diff --git a/apps/ai-game-creator-shell/src/features/project-workspace/ConversationModelSelect.test.tsx b/apps/ai-game-creator-shell/src/features/project-workspace/ConversationModelSelect.test.tsx index ab1accc17..f2b502107 100644 --- a/apps/ai-game-creator-shell/src/features/project-workspace/ConversationModelSelect.test.tsx +++ b/apps/ai-game-creator-shell/src/features/project-workspace/ConversationModelSelect.test.tsx @@ -84,7 +84,7 @@ afterEach(() => { }); describe('ConversationModelSelect 锁定模型', () => { - it('不可用模型渲染为不可点、可聚焦的原因项', async () => { + it('不可用模型渲染为不可点、可悬停查看原因且不进入 Tab 序列', async () => { mockConfig('basic-model', true); render(); // 等挂载时的目录同步落地,避免把异步状态更新留到断言之后。 @@ -96,8 +96,12 @@ describe('ConversationModelSelect 锁定模型', () => { const planLocked = screen.getByText('专业模型').closest('[role="option"]'); expect(planLocked?.tagName).toBe('DIV'); expect(planLocked?.getAttribute('aria-disabled')).toBe('true'); - expect(planLocked?.getAttribute('tabindex')).toBe('0'); + // 非焦点项:不进入 Tab 序列,避免键盘在不可选项上停留。 + expect(planLocked?.getAttribute('tabindex')).toBeNull(); expect(planLocked?.getAttribute('data-reason')).toBe('plan_required'); + expect(planLocked?.getAttribute('aria-label')).toBe( + '专业模型:订阅计划不支持', + ); expect(planLocked?.getAttribute('data-tooltip')).toBe('订阅计划不支持'); const disabledLocked = screen diff --git a/apps/ai-game-creator-shell/src/features/project-workspace/ConversationModelSelect.tsx b/apps/ai-game-creator-shell/src/features/project-workspace/ConversationModelSelect.tsx index 951f2274e..040474bf1 100644 --- a/apps/ai-game-creator-shell/src/features/project-workspace/ConversationModelSelect.tsx +++ b/apps/ai-game-creator-shell/src/features/project-workspace/ConversationModelSelect.tsx @@ -475,7 +475,8 @@ export function ConversationModelSelect({ ) : null} ))} - {/* 目录里存在但当前档位不可用的模型:不可点,仅 hover / 键盘 focus 出原因。 */} + {/* 目录里存在但当前档位不可用的模型:不可点;原因通过 aria-label 与 hover 提示暴露, + 且刻意不进入 Tab 序列,避免键盘用户在不可选项上停留。 */} {unavailableModels.map((model) => { const reasonLabel = unavailableModelReasonLabel(model.reason); return ( @@ -485,7 +486,6 @@ export function ConversationModelSelect({ aria-selected={false} aria-disabled="true" aria-label={`${model.displayName}:${reasonLabel}`} - tabIndex={0} className="conversation-model-menu-option conversation-model-menu-option-locked" data-reason={model.reason} data-tooltip={reasonLabel} diff --git a/apps/ai-game-creator-shell/src/styles.css b/apps/ai-game-creator-shell/src/styles.css index 792cc2db1..7c200d21f 100644 --- a/apps/ai-game-creator-shell/src/styles.css +++ b/apps/ai-game-creator-shell/src/styles.css @@ -11349,12 +11349,11 @@ button.design-workspace-tree__entry:hover, position: relative; cursor: not-allowed; } -.conversation-model-menu-option-locked:hover, -.conversation-model-menu-option-locked:focus-visible { +.conversation-model-menu-option-locked:hover { background: var(--platform-button-ghost-fill, #f3f4f6); outline: none; } -/* 锁定项的原因提示:仅 hover / 键盘 focus 出现(AGC 桌面端,无移动端适配)。 */ +/* 锁定项的原因提示:仅 hover 出现;锁定项不进入 Tab 序列,不再有键盘 focus 态。 */ .conversation-model-menu-option-locked[data-tooltip]::after { content: attr(data-tooltip); position: absolute; @@ -11373,8 +11372,7 @@ button.design-workspace-tree__entry:hover, white-space: normal; pointer-events: none; } -.conversation-model-menu-option-locked[data-tooltip]:hover::after, -.conversation-model-menu-option-locked[data-tooltip]:focus-visible::after { +.conversation-model-menu-option-locked[data-tooltip]:hover::after { display: block; } .conversation-model-menu-loading {