收口统一弹窗关闭按钮
新增 PlatformModalCloseButton pixel 变体承接像素风关闭入口 将 UnifiedModal 头部关闭按钮迁移到 PlatformModalCloseButton 补充平台态和像素态关闭按钮测试 更新 PlatformUiKit 文档和 Hermes 决策记录
This commit is contained in:
@@ -49,6 +49,7 @@
|
||||
- 2026-06-09 追加:公开编号搜索结果弹窗关闭按钮使用 `PlatformModalCloseButton variant="platformIcon"`,平台壳不再手写 `platform-icon-button` + 关闭文本。
|
||||
- 2026-06-10 追加:RPG 大编辑器主壳层和紧凑对话壳层的右上角关闭入口使用 `PlatformModalCloseButton variant="platformIcon"`,暗色编辑器保留 `platform-icon-button` 视觉 token,但业务 JSX 不再手写关闭按钮 aria、默认 X 图标和禁用态拼接。
|
||||
- 2026-06-10 追加:`PlatformModalCloseButton variant="editorDark"` 承接 RPG 暗色弹窗中非像素风的圆形 X 关闭入口,根节点固定带 `platform-modal-close-button--editor-dark` 稳定类名;自定义选择弹窗头部关闭按钮已迁移,并补齐 `aria-label`,业务 JSX 不再手写暗色关闭按钮边框、底色、hover 和默认 X 图标。验证命令:`npm run test -- src/components/common/PlatformModalCloseButton.test.tsx src/components/SelectionCustomizationModals.test.tsx`。
|
||||
- 2026-06-10 追加:`PlatformModalCloseButton variant="pixel"` 承接 `UnifiedModal variant="pixel"` 头部圆形关闭入口;`UnifiedModal` 只选择 `platformIcon / pixel` 变体并保留 closeDisabled、Backdrop、Escape 和 portal 语义,不再手写 X 图标、aria 和关闭按钮 class。验证命令:`npm run test -- src/components/common/UnifiedModal.test.tsx src/components/common/PlatformModalCloseButton.test.tsx src/components/common/UnifiedConfirmDialog.test.tsx`。
|
||||
- 2026-06-09 追加:RPG 大编辑器暗色面板内的保存和角色槽动作继续走本地 `ActionButton`,不再混用白底平台 `platform-button` class;平台白底动作收口和编辑器暗色动作收口保持两套视觉边界。
|
||||
- 2026-06-10 追加:`PlatformActionButton surface="editorDark"` 承接 RPG 暗色弹窗 / 运行面板里的普通取消、确认、刷新和编组动作,支持 `size="xxs"` 与 `tone="success" | "warning"`;角色自定义 footer、自定义世界生成 footer、地图切换确认、营地编组普通动作和角色聊天刷新动作已迁移。暗色可选项卡仍使用 `PlatformDarkOptionCard`,像素风发送 / 强品牌动作继续保留专用布局。验证命令:`npm run test -- src/components/common/platformActionButtonModel.test.ts src/components/common/PlatformActionButton.test.tsx src/components/SelectionCustomizationModals.test.tsx src/components/CompanionCampModal.test.tsx src/components/MapModal.test.tsx src/components/CharacterChatModal.test.tsx`。
|
||||
- 2026-06-10 追加:RPG 大编辑器里的当前角色、可选角色、预设背景和场景连接关系等暗色信息面板通过本地 `EditorInfoPanel` 复用 `PlatformSubpanel surface="dark"`;有右侧动作的面板也只向适配器传 actions,不再在业务 JSX 中重复手写暗色面板边框、底色、圆角、标题行和内容间距。验证命令:`npm run test -- src/components/CustomWorldEntityEditorModal.test.tsx -t "场景编辑器会在场景内展示槽位化多幕配置并保存"`。
|
||||
@@ -344,6 +345,7 @@
|
||||
- 2026-06-09 验证补充:平台标签编辑器收口补跑 `npm run test -- src/components/common/PlatformTagEditor.test.tsx src/components/puzzle-result/PuzzleResultView.test.tsx src/components/wooden-fish-result/WoodenFishResultView.test.tsx src/components/match3d-result/Match3DResultView.test.tsx`。
|
||||
- 2026-06-09 验证补充:反馈页上传方块和上传预览收口补跑 `npm run test -- src/components/common/PlatformUploadPreviewCard.test.tsx src/components/common/PlatformUploadTile.test.tsx src/components/platform-entry/PlatformFeedbackView.test.tsx`。
|
||||
- 2026-06-10 验证补充:反馈页查看记录次级动作收口补跑 `npm run test -- src/components/platform-entry/PlatformFeedbackView.test.tsx src/components/common/PlatformActionButton.test.tsx`。
|
||||
- 2026-06-10 验证补充:UnifiedModal 头部关闭按钮收口到 `PlatformModalCloseButton platformIcon / pixel` 后,补跑 `npm run test -- src/components/common/UnifiedModal.test.tsx src/components/common/PlatformModalCloseButton.test.tsx src/components/common/UnifiedConfirmDialog.test.tsx`。
|
||||
- 2026-06-10 验证补充:上传预览卡右上移除按钮收口到 `PlatformIconButton darkMini` 后,补跑 `npm run test -- src/components/common/PlatformIconButton.test.tsx src/components/common/PlatformUploadPreviewCard.test.tsx`。
|
||||
- 2026-06-10 验证补充:RPG 大编辑器参考图和封面上传入口收口到 `PlatformUploadTile surface="editorDark"`、参考图预览条收口到 `PlatformUploadPreviewCard surface="editorDark"` 后,补跑 `npm run test -- src/components/common/PlatformUploadTile.test.tsx src/components/common/PlatformUploadPreviewCard.test.tsx src/components/CustomWorldEntityEditorModal.test.tsx -t "场景图片保存后会同步更新编辑页和场景列表"`。
|
||||
- 2026-06-10 验证补充:角色素材工作室参考图入口收口到 `PlatformUploadTile surface="editorDark"` 后,补跑 `npm run test -- src/components/rpg-creation-asset-studio/RpgCreationRoleAssetStudioModal.test.tsx`。
|
||||
|
||||
@@ -121,7 +121,7 @@
|
||||
- `PlatformToggleRow`:接收 `label`、`checked`、`onChange`、`disabled`、`mode="checkbox" | "status"`、`icon`、`onLabel`、`offLabel`、`onClick`、`surface="soft" | "plain"`、`className` 和 `labelClassName`;`checkbox` 模式用于结果页运行配置和角色可见性,`status` 模式用于 runtime 设置面板的只读开关状态,可选 `onClick` 时自身渲染为 button。视觉小说结果页运行配置 / 玩家可见开关、视觉小说 runtime 设置面板和拼消消创作工作台 AI 生成底图开关已先迁移,业务页不再重复手写 `flex min-h-12 ... bg-white/74 px-3`、checkbox class 或“开启 / 关闭”状态 pill。
|
||||
- `PlatformInfoBlock`:接收可选 `label`、`children`、`multiline`、`className`、`labelClassName` 和 `valueClassName`;统一承载平台弹窗 / 详情页中的短标签、无标签只读正文、白底圆角边框、内容换行、单行加粗排版和横向只读信息行的标签 / 值局部排版。错误弹窗与生成完成弹窗的来源、错误、状态块、分享弹窗正文,以及汪汪声浪预览卡场景 / 形象 / 难度 / 声浪信息行已先迁移,后续同类只读信息展示只传 label、内容和必要局部排版 class,纯正文块可省略 label,不在业务 JSX 中重复写 `rounded-[1rem] border ... bg-white/72 px-3 py-2`、`rounded-[1.25rem] border ... bg-white/72 p-4` 或 `rounded-[0.85rem] bg-white/74 px-* py-*`。
|
||||
- `PlatformInfoBlock` 补充:当前 Interface 支持 `variant="compactRow"` 承接预览卡里的密集横向 label / value 行,标签、值、圆角、白底和响应式内边距由公共组件控制;汪汪声浪预览卡四个信息行已去掉本地 `PREVIEW_INFO_*` class 常量。
|
||||
- `PlatformModalCloseButton`:接收 `label`、`variant="profile" | "profileCompact" | "floating" | "floatingPlain" | "platformIcon" | "editorDark"`、`icon` 和原生 button props;`profile` 复用个人中心 `platform-modal-close` 圆形按钮,`profileCompact` 复用个人中心小弹窗 `platform-profile-icon-button` 关闭按钮,`floating` 复用平台浮层右上角白底关闭按钮,`floatingPlain` 复用个人中心邀请 / 社区浮层的透明右上角关闭按钮,`platformIcon` 复用平台弹窗头部 `platform-icon-button` 关闭入口,`editorDark` 承接 RPG 暗色弹窗中非像素风的圆形 X 关闭入口并固定带 `platform-modal-close-button--editor-dark` 稳定类名。认证入口、邀请码弹窗等平台弹窗头部关闭按钮使用 `variant="platformIcon"`,自定义选择弹窗使用 `variant="editorDark"`,业务页可以追加局部 class,但不重新声明基础尺寸、圆角、默认图标和 `aria-label`。
|
||||
- `PlatformModalCloseButton`:接收 `label`、`variant="profile" | "profileCompact" | "floating" | "floatingPlain" | "platformIcon" | "pixel" | "editorDark"`、`icon` 和原生 button props;`profile` 复用个人中心 `platform-modal-close` 圆形按钮,`profileCompact` 复用个人中心小弹窗 `platform-profile-icon-button` 关闭按钮,`floating` 复用平台浮层右上角白底关闭按钮,`floatingPlain` 复用个人中心邀请 / 社区浮层的透明右上角关闭按钮,`platformIcon` 复用平台弹窗头部 `platform-icon-button` 关闭入口,`pixel` 复用 `UnifiedModal variant="pixel"` 的像素风圆形关闭入口,`editorDark` 承接 RPG 暗色弹窗中非像素风的圆形 X 关闭入口并固定带 `platform-modal-close-button--editor-dark` 稳定类名。认证入口、邀请码弹窗等平台弹窗头部关闭按钮使用 `variant="platformIcon"`,像素风 `UnifiedModal` 使用 `variant="pixel"`,自定义选择弹窗使用 `variant="editorDark"`,业务页可以追加局部 class,但不重新声明基础尺寸、圆角、默认图标和 `aria-label`。
|
||||
- `squareImageCropModel`:导出 `SquareImageCropRect`、`buildCenteredSquareImageCropRect(imageSize)` 和 `clampSquareImageCropRect(imageSize, crop)`;可复用裁剪数学留在 model,`SquareImageCropModal` 只承接弹窗 UI、拖拽交互和提交动作。
|
||||
|
||||
## 迁移顺序
|
||||
@@ -142,7 +142,7 @@
|
||||
14. 带复杂内容的专用 Module 可以保留自己的布局,但复制反馈仍应复用 `useCopyFeedback`;如果有可点击复制按钮,优先复用 `CopyFeedbackButton`;如果只展示复制结果提示,优先复用 `CopyFeedbackMessage`。
|
||||
15. 白底平台弹窗、详情页、结果页、目录页、个人页、认证入口、统一创作工作台和通用创作输入区的基础错误 / 成功 / 信息 / 警告 / 中性状态提示逐步迁移到 `PlatformStatusMessage`;RPG 结果页、拼图结果页、抓大鹅结果页、跳一跳结果页、敲木鱼结果页、拼消消结果页、宝贝识物结果页、方洞结果页、汪汪声浪结果页、视觉小说结果页、拼消消创作工作台、宝贝识物创作工作台、视觉小说创作工作台、汪汪声浪创作工作台、creative-agent 工作台、creation-agent operation banner、自定义世界实体目录和拼消消 runtime 白底错误条已使用 `surface="platform"` 承接发布检查、错误提示、进度提示、素材生成提示、资源未就绪提示和主线目标提示;个人中心、认证入口、统一创作工作台和创作输入区需要 profile token 外观时使用 `surface="profile"`;RPG 暗色编辑 / 运行面板里的普通错误 / 成功 / 信息 / 警告 / 中性提示使用 `surface="editorDark"`,背包故事档案 QA 提示、NPC 交易 / 赠礼 / 招募叙事提示和角色聊天错误提示已先迁移。运行态里的短错误 / 成功 / 命中反馈 chip 使用 `PlatformRuntimeStatusToast`,位置和玩法强品牌 HUD 仍留在 runtime 壳层;深色半透明游戏内提示和强品牌样式可以暂保留专用布局,避免状态条组件过早承接游戏视觉。
|
||||
16. 正方形图片裁剪的初始居中、边界 clamp 和裁剪矩形类型统一从 `squareImageCropModel` 导入,避免头像裁剪、拼图参考图裁剪等业务页面依赖弹窗组件文件里的 helper。
|
||||
17. 个人中心的账户充值、泥点账单、每日任务、兑换码、扫码、存档、玩过作品、邀请 / 社区、昵称修改、头像裁剪,以及平台筛选、创作图片预览、认证入口、邀请码弹窗、公开编号搜索结果弹窗、方洞结果页图片素材弹窗、视觉小说结果页资产 / 音频 / 编辑器弹窗、视觉小说 runtime 普通面板、creative-agent 模板确认弹窗和自定义选择弹窗等圆形关闭按钮迁移到 `PlatformModalCloseButton`;后续新增弹窗关闭按钮先判断是否属于 `profile`、`profileCompact`、`floating`、`floatingPlain`、`platformIcon` 或 `editorDark` 六类,确有品牌化或运行态 HUD 语义时才保留专用按钮。
|
||||
17. 个人中心的账户充值、泥点账单、每日任务、兑换码、扫码、存档、玩过作品、邀请 / 社区、昵称修改、头像裁剪,以及平台筛选、创作图片预览、认证入口、邀请码弹窗、公开编号搜索结果弹窗、方洞结果页图片素材弹窗、视觉小说结果页资产 / 音频 / 编辑器弹窗、视觉小说 runtime 普通面板、creative-agent 模板确认弹窗、像素风 UnifiedModal 和自定义选择弹窗等圆形关闭按钮迁移到 `PlatformModalCloseButton`;后续新增弹窗关闭按钮先判断是否属于 `profile`、`profileCompact`、`floating`、`floatingPlain`、`platformIcon`、`pixel` 或 `editorDark` 七类,确有品牌化或运行态 HUD 语义时才保留专用按钮。
|
||||
17.1. 平台弹窗 header 和普通工具栏里的 `platform-icon-button` 迁移到 `PlatformIconButton`;历史图片选择弹窗、RPG 发布检查弹窗、creative-agent 侧边栏关闭 / 外观 / 设置入口、通用输入 Composer 上传 / 发送 / 移除参考图、creation-agent composer 上传文档 / 上传参考图、creation-agent 参考图移除、敲木鱼结果页新增主题标签入口、敲木鱼创作工作台功德词条删除入口、拼图结果页标签生成 / 标签新增 / 关卡详情关闭 / 发布弹窗关闭 / 删除关卡入口、视觉小说结果页素材选择 / 音频生成 / 保存草稿 / 运行配置入口、RPG 首页搜索结果清空入口、方洞结果页形状 / 洞口选项删除入口,以及抓大鹅结果页标签生成 / 标签新增 / 物品素材删除 / 参考图上传入口已先迁移。结果页内的普通平台弹窗关闭入口使用 `PlatformModalCloseButton variant="platformIcon"`;图标上传控件使用 `PlatformIconButton asChild="label"` 保留 label + file input 语义,不改成普通按钮;`PlatformIconButton` 的 label 模式会自动写入隐藏文本,保证内嵌 file input 仍能继承可访问名称。通用创作图片面板中覆盖在图片上的更换主图、移除主图、历史入口短标签按钮和提示词参考图上传入口,抓大鹅封面编辑中覆盖在封面图上的移除入口,以及敲木鱼创作工作台功德词条删除入口使用 `PlatformIconButton variant="surfaceFloating"`,不再手写白底圆形 / 短标签浮动按钮 chrome。运行态 HUD、带复制状态或需要专用交互禁用语义的图标按钮,先保留专用布局,等对应场景验证时再迁移。
|
||||
17.2. 非交互图标徽章迁移到 `PlatformIconBadge`;视觉小说 runtime 面板标题、存档列表项,creative-agent 模板卡 / 模板确认 / 顶部 hero / 目标就绪 / 过程条目图标圆槽,创作类型弹层锁定卡小圆锁图标,大鱼吃小鱼发布失败弹窗图标槽,通用创作图片面板空主图上传占位图标槽,拼图结果页智能修订条图标槽,以及 GameCanvas 宝箱遭遇图标槽已先迁移。后续同类图标槽只表达 icon、尺寸、形状和 neutral / soft / softBright / hero / heroMuted / darkAmber / success / danger 调性,不再重复中性、白底柔和、hero 叠层、暗色琥珀、成功或危险底色、文字色、居中和 shrink class。
|
||||
17.3. RPG 大编辑器主壳层和紧凑对话壳层的右上角关闭入口迁移到 `PlatformModalCloseButton variant="platformIcon"`;暗色编辑器仍保留原 `platform-icon-button` 视觉 token,但业务 JSX 不再手写 `button`、`aria-label` 和默认关闭图标。
|
||||
@@ -363,6 +363,7 @@
|
||||
- `npm run test -- src/components/common/PlatformTextField.test.tsx src/components/common/PlatformTagEditor.test.tsx`
|
||||
- `npm run test -- src/components/common/PlatformPillSwitch.test.tsx src/components/common/CreativeImageInputPanel.test.tsx src/components/match3d-result/Match3DResultView.test.tsx`
|
||||
- `npm run test -- src/components/common/PlatformModalCloseButton.test.tsx`
|
||||
- `npm run test -- src/components/common/UnifiedModal.test.tsx src/components/common/PlatformModalCloseButton.test.tsx src/components/common/UnifiedConfirmDialog.test.tsx`
|
||||
- `npm run test -- src/components/common/PlatformModalCloseButton.test.tsx src/components/SelectionCustomizationModals.test.tsx`
|
||||
- `npm run test -- src/components/common/squareImageCropModel.test.ts`
|
||||
- `npm run test -- src/components/platform-entry/PlatformEntryFlowShellImpl.test.ts`
|
||||
|
||||
@@ -71,9 +71,20 @@ test('supports platform icon close button', () => {
|
||||
const button = screen.getByRole('button', { name: '关闭素材图片' });
|
||||
|
||||
expect(button.className).toContain('platform-icon-button');
|
||||
expect(button.className).toContain('disabled:opacity-45');
|
||||
expect(button.querySelector('svg')).toBeTruthy();
|
||||
});
|
||||
|
||||
test('supports pixel close button', () => {
|
||||
render(<PlatformModalCloseButton label="关闭像素弹窗" variant="pixel" />);
|
||||
|
||||
const button = screen.getByRole('button', { name: '关闭像素弹窗' });
|
||||
|
||||
expect(button.className).toContain('bg-black/20');
|
||||
expect(button.className).toContain('text-zinc-400');
|
||||
expect(button.className).toContain('disabled:opacity-45');
|
||||
});
|
||||
|
||||
test('supports editor dark close button', () => {
|
||||
render(
|
||||
<PlatformModalCloseButton label="关闭角色自定义" variant="editorDark" />,
|
||||
|
||||
@@ -7,6 +7,7 @@ type PlatformModalCloseButtonVariant =
|
||||
| 'floating'
|
||||
| 'floatingPlain'
|
||||
| 'platformIcon'
|
||||
| 'pixel'
|
||||
| 'editorDark';
|
||||
|
||||
type PlatformModalCloseButtonProps = Omit<
|
||||
@@ -30,7 +31,9 @@ const PLATFORM_MODAL_CLOSE_BUTTON_CLASS_BY_VARIANT: Record<
|
||||
'absolute right-3 top-3 z-10 flex h-8 w-8 items-center justify-center rounded-full bg-white/80 text-[#ff4056] shadow-sm',
|
||||
floatingPlain:
|
||||
'absolute right-3 top-2 z-10 flex h-8 w-8 items-center justify-center rounded-full text-[#ff4056]',
|
||||
platformIcon: 'platform-icon-button',
|
||||
platformIcon: 'platform-icon-button disabled:cursor-not-allowed disabled:opacity-45',
|
||||
pixel:
|
||||
'rounded-full border border-white/10 bg-black/20 p-2 text-zinc-400 transition-colors hover:text-white disabled:cursor-not-allowed disabled:opacity-45',
|
||||
editorDark:
|
||||
'platform-modal-close-button--editor-dark rounded-full border border-white/10 bg-white/5 p-2 text-zinc-300 transition hover:bg-white/10 hover:text-white',
|
||||
};
|
||||
|
||||
@@ -14,6 +14,9 @@ test('renders an accessible platform modal', () => {
|
||||
|
||||
expect(screen.getByRole('dialog', { name: '统一弹窗' })).toBeTruthy();
|
||||
expect(screen.getByText('窗口内容')).toBeTruthy();
|
||||
expect(screen.getByRole('button', { name: '关闭' }).className).toContain(
|
||||
'platform-icon-button',
|
||||
);
|
||||
});
|
||||
|
||||
test('closes through backdrop and escape', () => {
|
||||
@@ -56,3 +59,25 @@ test('respects closeDisabled for every default close path', () => {
|
||||
|
||||
expect(onClose).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
test('uses shared pixel close button chrome', () => {
|
||||
render(
|
||||
<UnifiedModal
|
||||
open
|
||||
title="像素弹窗"
|
||||
onClose={() => {}}
|
||||
variant="pixel"
|
||||
portal={false}
|
||||
>
|
||||
<div>窗口内容</div>
|
||||
</UnifiedModal>,
|
||||
);
|
||||
|
||||
const closeButton = screen.getByRole('button', { name: '关闭' });
|
||||
|
||||
expect(screen.getByRole('dialog', { name: '像素弹窗' }).className).toContain(
|
||||
'pixel-modal-shell',
|
||||
);
|
||||
expect(closeButton.className).toContain('bg-black/20');
|
||||
expect(closeButton.className).toContain('text-zinc-400');
|
||||
});
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import { X } from 'lucide-react';
|
||||
import {
|
||||
type CSSProperties,
|
||||
type ReactNode,
|
||||
@@ -8,6 +7,7 @@ import {
|
||||
import { createPortal } from 'react-dom';
|
||||
|
||||
import { getNineSliceStyle, UI_CHROME } from '../../uiAssets';
|
||||
import { PlatformModalCloseButton } from './PlatformModalCloseButton';
|
||||
|
||||
type UnifiedModalVariant = 'platform' | 'pixel';
|
||||
type UnifiedModalSize = 'sm' | 'md' | 'lg' | 'xl' | 'fullscreen';
|
||||
@@ -145,10 +145,6 @@ function UnifiedModalContent({
|
||||
? 'flex flex-wrap items-center justify-end gap-3 border-t border-white/10 px-4 py-3 sm:px-5 sm:py-4'
|
||||
: 'flex flex-wrap items-center justify-end gap-3 border-t border-[var(--platform-subpanel-border)] px-4 py-4 sm:px-5';
|
||||
|
||||
const closeButtonClasses = isPixel
|
||||
? 'rounded-full border border-white/10 bg-black/20 p-2 text-zinc-400 transition-colors hover:text-white disabled:cursor-not-allowed disabled:opacity-45'
|
||||
: 'platform-icon-button disabled:cursor-not-allowed disabled:opacity-45';
|
||||
|
||||
return (
|
||||
<div
|
||||
className={joinClassNames(overlayClasses, zIndexClassName, overlayClassName)}
|
||||
@@ -183,15 +179,12 @@ function UnifiedModalContent({
|
||||
) : null}
|
||||
</div>
|
||||
{showCloseButton ? (
|
||||
<button
|
||||
type="button"
|
||||
aria-label={closeLabel}
|
||||
<PlatformModalCloseButton
|
||||
label={closeLabel}
|
||||
onClick={onClose}
|
||||
disabled={closeDisabled}
|
||||
className={closeButtonClasses}
|
||||
>
|
||||
<X className="h-4 w-4" />
|
||||
</button>
|
||||
variant={isPixel ? 'pixel' : 'platformIcon'}
|
||||
/>
|
||||
) : null}
|
||||
</div>
|
||||
<div className={joinClassNames(bodyClasses, bodyClassName)}>
|
||||
|
||||
Reference in New Issue
Block a user