diff --git a/.ua/index.json b/.ua/index.json index 0762224..4d0ed29 100644 --- a/.ua/index.json +++ b/.ua/index.json @@ -1,6 +1,6 @@ { "$schema": "ui-arch-registry-index/0.1", - "generatedAt": "2026-10-26T15:13:43.474Z", + "generatedAt": "2026-10-26T15:15:56.703Z", "repoRoot": ".", "packages": [ { @@ -229,7 +229,8 @@ "relativeTime(props):把时间戳渲染成「3 分钟前」并自动刷新,超阈值改显示绝对日期,title 恒给精确值", "sparkline(props):迷你趋势线,把数值序列压成折线(可填充 + 末点标记),无坐标轴无交互", "heatmap(props):日历热力图,按周列 × 星期行铺格子、四档浓度表示当天数量,悬停看明细", - "progressRing(props):环形进度,SVG 双圆靠 dasharray 画弧 + 中心百分比,value 可传信号自动重绘" + "progressRing(props):环形进度,SVG 双圆靠 dasharray 画弧 + 中心百分比,value 可传信号自动重绘", + "noticeBar(props):单行通知条,语义色 + 左侧符号 + 可选跑马灯与关闭,适合页顶常驻播报" ], "keyTypes": [ "ButtonProps", @@ -4581,6 +4582,51 @@ "换色在父级设 color:进度弧读 currentColor,底环固定描边色(--ua-color-border),不引入第二个色源", "这是个「环形进度条」,不是仪表盘:只表达 0-100 单一进度,多段占比请用饼图类组件" ] + }, + { + "id": "noticeBar", + "title": "通知条 NoticeBar", + "demo": "sec-notice", + "props": [ + { + "n": "text", + "t": "string", + "d": "通知正文;单行不换行,超宽需配合 scroll" + }, + { + "n": "variant", + "t": "'info' | 'success' | 'warning' | 'danger'", + "d": "语义色;缺省 info" + }, + { + "n": "icon", + "t": "string", + "d": "左侧符号;缺省按 variant 取(ℹ / ✓ / ! / ×)" + }, + { + "n": "scroll", + "t": "boolean", + "d": "正文超宽时跑马灯滚动;缺省 false(静态,超出裁切)" + }, + { + "n": "closable", + "t": "boolean", + "d": "是否显示关闭按钮;缺省 true" + }, + { + "n": "onClose", + "t": "() => void", + "d": "关闭回调" + } + ], + "example": "noticeBar({ text: '系统将于今晚 23:00 维护 10 分钟', scroll: true })", + "steps": [ + "和 alert 的分工:alert 可多行带标题、占块;通知条只占一行,适合页顶常驻播报(维护公告、试用期提醒)", + "文案比容器宽就传 scroll: true:正文从右向左匀速走,悬停自动暂停,读得完不用追", + "只想播报不需要关闭就传 closable: false:右侧不再留 × 位,横条更紧凑", + "颜色只是第二线索:左侧符号按 variant 自动配(ℹ / ✓ / ! / ×),色弱或灰度打印也能分辨", + "跑马灯在减少动效偏好下自动停成静态首屏——完整原文始终在 title 里,不必为可访问性另写一份" + ] } ] }, diff --git a/AGENTS.md b/AGENTS.md index 44a949b..3b72cb4 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -21,7 +21,7 @@ - `packages/core/table-core`(@ui-arch/table-core):Headless 表格逻辑内核 - `packages/core/frame`(@ui-arch/frame):signal + hyperscript 微框架 -- `packages/skin/ui`(@ui-arch/ui):86 个 DOM 组件(表单 / 反馈 / 浮层 / 导航 / 表格),样式只消费令牌 +- `packages/skin/ui`(@ui-arch/ui):87 个 DOM 组件(表单 / 反馈 / 浮层 / 导航 / 表格),样式只消费令牌 - `packages/design/tokens`(@ui-arch/tokens):设计令牌 - `packages/tools/cli`(@ui-arch/cli):`ua` 命令行 + MCP 注册表服务(private) - `apps/demo`(@ui-arch/demo):交互演示,产物 apps/demo/dist/demo.html diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md index ec2f79e..8edf46a 100644 --- a/ARCHITECTURE.md +++ b/ARCHITECTURE.md @@ -34,7 +34,7 @@ ui-arch-mvp/ │ │ ├── table-core/ # 表格状态内核 │ │ └── frame/ # 信号 + hyperscript 微框架 │ ├── skin/ # 皮肤层(DOM 组件,可发布) -│ │ └── ui/ # 86 个组件 + ui.css +│ │ └── ui/ # 87 个组件 + ui.css │ ├── design/ # 资产层(可发布) │ │ └── tokens/ # --ua-* 设计令牌 │ └── tools/ # 工程层(private,不发布) diff --git a/README.md b/README.md index 64816f4..e8c5287 100644 --- a/README.md +++ b/README.md @@ -12,13 +12,13 @@ npm run docs # 生成人类文档站 apps/docs/index.html + Agent 全 npm run changelog # 依据 git 提交史重写 CHANGELOG.md(发版前跑;changelog:check 可查漂移) ``` -## 组件(共 86 个) +## 组件(共 87 个) -accordion · affix · alert · anchor · autoComplete · avatar · avatarGroup · backTop · badge · breadcrumb · button · calendar · carousel · card · cascader · checkbox · checkboxGroup · codeBlock · colorPicker · commandPalette · copyButton · countdown · dataTable · datePicker · descriptions · diffView · divider · drawer · empty · floatButton · form · grid · heatmap · highlight · image · inputNumber · inputTag · jsonViewer · kbd · layout · link · list · loading · menu · modal · mentions · multiSelect · notification · pagination · pinInput · popover · popconfirm · progress · progressRing · radioGroup · rate · relativeTime · result · segmented · select · signaturePad · skeleton · slider · space · sparkline · spinner · splitter · statistic · stepper · switchButton · tabs · tag · textField · textarea · timeline · timePicker · toast · tooltip · tour · transfer · tree · treeSelect · typography · upload · virtualList · watermark +accordion · affix · alert · anchor · autoComplete · avatar · avatarGroup · backTop · badge · breadcrumb · button · calendar · carousel · card · cascader · checkbox · checkboxGroup · codeBlock · colorPicker · commandPalette · copyButton · countdown · dataTable · datePicker · descriptions · diffView · divider · drawer · empty · floatButton · form · grid · heatmap · highlight · image · inputNumber · inputTag · jsonViewer · kbd · layout · link · list · loading · menu · modal · mentions · multiSelect · noticeBar · notification · pagination · pinInput · popover · popconfirm · progress · progressRing · radioGroup · rate · relativeTime · result · segmented · select · signaturePad · skeleton · slider · space · sparkline · spinner · splitter · statistic · stepper · switchButton · tabs · tag · textField · textarea · timeline · timePicker · toast · tooltip · tour · transfer · tree · treeSelect · typography · upload · virtualList · watermark -分组:表单(button / copyButton / signaturePad / textField / inputNumber / inputTag / textarea / checkbox / checkboxGroup / colorPicker / switchButton / select / mentions / multiSelect / radioGroup / slider / rate / autoComplete / datePicker / timePicker / pinInput / segmented / upload / form + formItem / transfer / cascader)、反馈(alert / loading / toast / notification / result / spinner / progress / progressRing / skeleton / badge / empty / statistic / countdown)、浮层(tooltip / popover / popconfirm / modal / drawer / menu / commandPalette)、导航(tabs / breadcrumb / pagination / accordion / stepper / tree / treeSelect / anchor)、数据展示(dataTable / jsonViewer / diffView / codeBlock / relativeTime / sparkline / heatmap / descriptions / card / list / kbd / highlight / timeline / tag / avatar / avatarGroup / image / carousel / calendar / typography / virtualList)、其他(floatButton / grid / layout / link / space / divider / splitter / backTop / affix / tour / watermark)。 +分组:表单(button / copyButton / signaturePad / textField / inputNumber / inputTag / textarea / checkbox / checkboxGroup / colorPicker / switchButton / select / mentions / multiSelect / radioGroup / slider / rate / autoComplete / datePicker / timePicker / pinInput / segmented / upload / form + formItem / transfer / cascader)、反馈(alert / loading / toast / notification / noticeBar / result / spinner / progress / progressRing / skeleton / badge / empty / statistic / countdown)、浮层(tooltip / popover / popconfirm / modal / drawer / menu / commandPalette)、导航(tabs / breadcrumb / pagination / accordion / stepper / tree / treeSelect / anchor)、数据展示(dataTable / jsonViewer / diffView / codeBlock / relativeTime / sparkline / heatmap / descriptions / card / list / kbd / highlight / timeline / tag / avatar / avatarGroup / image / carousel / calendar / typography / virtualList)、其他(floatButton / grid / layout / link / space / divider / splitter / backTop / affix / tour / watermark)。 ## 可访问性约定 @@ -34,7 +34,7 @@ accordion · affix · alert · anchor · autoComplete · avatar · avatarGroup |---|---| | `packages/core/frame` | @ui-arch/frame:signal / computed / effect + hyperscript(无虚拟 DOM) | | `packages/core/table-core` | @ui-arch/table-core:headless 表格(filter → sort → paginate 派生管线) | -| `packages/skin/ui` | @ui-arch/ui:86 个 DOM 组件 + ui.css(只消费 `--ua-*` 令牌) | +| `packages/skin/ui` | @ui-arch/ui:87 个 DOM 组件 + ui.css(只消费 `--ua-*` 令牌) | | `packages/design/tokens` | @ui-arch/tokens:设计令牌(暗色只换值不换名) | | `packages/tools/cli` | @ui-arch/cli:`ua` 命令行与 stdio MCP server | | `apps/demo` | 交互演示(esbuild 打包成单文件) | diff --git a/apps/demo/main.ts b/apps/demo/main.ts index c6c34ef..68a0862 100644 --- a/apps/demo/main.ts +++ b/apps/demo/main.ts @@ -57,6 +57,7 @@ import { treeSelect, tree, notification, + noticeBar, result, upload, watermark, @@ -1897,6 +1898,23 @@ content.append( ), ); +// 通知条:页顶播报的「一行版 alert」,scroll 让超宽文案自己走过去 +content.append( + section( + 'sec-notice', + '通知条', + 'noticeBar:单行横条,语义色 + 左侧符号 + 关闭;scroll 开启后正文跑马灯(悬停暂停),减少动效偏好下停成静态首屏。', + h( + 'div', + { class: 'col' }, + noticeBar({ text: '系统将于今晚 23:00 维护约 10 分钟,期间提交会排队重试。', onClose: () => toast.info('已关闭维护公告') }), + noticeBar({ text: '长公告示例:新版表格已支持列宽记忆与筛选快照,若发现列宽异常可在设置里一键重置;滚动模式下悬停会自动暂停。', variant: 'warning', scroll: true }), + noticeBar({ text: '构建成功:12 项门禁全部通过。', variant: 'success', closable: false }), + noticeBar({ text: '连接已断开,正在重试第 3 次…', variant: 'danger', icon: '⚠' }), + ), + ), +); + // 悬浮按钮:fixed 定位,挂 body 不参与页面布局 document.body.append( floatButton({ icon: '+', label: '新建工单', tooltip: '新建工单', position: 'left-bottom', onClick: () => toast.success('已新建工单') }), diff --git a/llms-full.txt b/llms-full.txt index 08d92fe..99204c4 100644 --- a/llms-full.txt +++ b/llms-full.txt @@ -1,6 +1,6 @@ # @ui-arch 组件库 Agent 文档(无图形版) -> 自动生成于 2026-10-26T15:13:43.474Z,数据源:各包 ua.manifest.json,勿手改。人类版文档站:apps/docs/index.html。 +> 自动生成于 2026-10-26T15:15:56.703Z,数据源:各包 ua.manifest.json,勿手改。人类版文档站:apps/docs/index.html。 > 组件 = 普通函数,传 props 返回 DOM;状态用 signal 双向绑定:读 signal() 写 signal(v)。 ## 快速上手 @@ -2454,6 +2454,33 @@ progressRing({ value: pct, size: 96 }) 现场演示:apps/docs/demo.html#sec-ring +### noticeBar — 通知条 NoticeBar + +参数: + +- text:string —— 通知正文;单行不换行,超宽需配合 scroll +- variant:'info' | 'success' | 'warning' | 'danger' —— 语义色;缺省 info +- icon:string —— 左侧符号;缺省按 variant 取(ℹ / ✓ / ! / ×) +- scroll:boolean —— 正文超宽时跑马灯滚动;缺省 false(静态,超出裁切) +- closable:boolean —— 是否显示关闭按钮;缺省 true +- onClose:() => void —— 关闭回调 + +示例: + +``` +noticeBar({ text: '系统将于今晚 23:00 维护 10 分钟', scroll: true }) +``` + +手把手: + +1. 和 alert 的分工:alert 可多行带标题、占块;通知条只占一行,适合页顶常驻播报(维护公告、试用期提醒) +2. 文案比容器宽就传 scroll: true:正文从右向左匀速走,悬停自动暂停,读得完不用追 +3. 只想播报不需要关闭就传 closable: false:右侧不再留 × 位,横条更紧凑 +4. 颜色只是第二线索:左侧符号按 variant 自动配(ℹ / ✓ / ! / ×),色弱或灰度打印也能分辨 +5. 跑马灯在减少动效偏好下自动停成静态首屏——完整原文始终在 title 里,不必为可访问性另写一份 + +现场演示:apps/docs/demo.html#sec-notice + API 速览: - button(props):按钮,variant 三档视觉强度,disabled / loading 支持布尔或信号动态同步(loading 转圈并禁点),onClick 点击回调 @@ -2544,6 +2571,7 @@ API 速览: - sparkline(props):迷你趋势线,把数值序列压成折线(可填充 + 末点标记),无坐标轴无交互 - heatmap(props):日历热力图,按周列 × 星期行铺格子、四档浓度表示当天数量,悬停看明细 - progressRing(props):环形进度,SVG 双圆靠 dasharray 画弧 + 中心百分比,value 可传信号自动重绘 +- noticeBar(props):单行通知条,语义色 + 左侧符号 + 可选跑马灯与关闭,适合页顶常驻播报 一行用法: diff --git a/llms.txt b/llms.txt index 46a95e4..8f74107 100644 --- a/llms.txt +++ b/llms.txt @@ -135,6 +135,7 @@ - sparkline(props):迷你趋势线,把数值序列压成折线(可填充 + 末点标记),无坐标轴无交互 - heatmap(props):日历热力图,按周列 × 星期行铺格子、四档浓度表示当天数量,悬停看明细 - progressRing(props):环形进度,SVG 双圆靠 dasharray 画弧 + 中心百分比,value 可传信号自动重绘 + - noticeBar(props):单行通知条,语义色 + 左侧符号 + 可选跑马灯与关闭,适合页顶常驻播报 - 用法: `const checked = signal(false); checkbox({ label: '同意', checked }); const open = signal(false); modal({ title: '确认', open }, '内容')` - 约定: 皮肤不持有业务状态,一律委托 headless 内核或调用方信号 - 约定: 表单类组件统一约定:*Props.value/checked/active 为 Signal 双向绑定,onChange/onInput 为回调 diff --git a/packages/skin/ui/src/index.ts b/packages/skin/ui/src/index.ts index a41f363..21aaad8 100644 --- a/packages/skin/ui/src/index.ts +++ b/packages/skin/ui/src/index.ts @@ -86,3 +86,4 @@ export { relativeTime } from './relativeTime.js'; export { sparkline } from './sparkline.js'; export { heatmap } from './heatmap.js'; export { progressRing } from './progressRing.js'; +export { noticeBar } from './noticeBar.js'; diff --git a/packages/skin/ui/src/noticeBar.ts b/packages/skin/ui/src/noticeBar.ts new file mode 100644 index 0000000..0bc990e --- /dev/null +++ b/packages/skin/ui/src/noticeBar.ts @@ -0,0 +1,37 @@ +import { h, signal } from '@ui-arch/frame'; +import type { NoticeBarProps } from './types.js'; + +// 语义色配符号:只靠颜色区分在灰度/色弱下会失效,符号是第二条线索 +const ICONS: Record = { info: 'ℹ', success: '✓', warning: '!', danger: '×' }; + +/*** 通知条:单行横条,语义色 + 可选跑马灯与关闭;关闭即整条隐藏并回调 ***/ +export function noticeBar(props: NoticeBarProps): HTMLElement { + const variant = props.variant ?? 'info'; + const open = signal(true); // 关闭状态:隐藏而非摘节点,调用方仍可拿到元素句柄 + return h( + 'div', + { + class: `ua-notice ua-notice-${variant}${props.scroll ? ' is-roll' : ''}`, + role: 'status', + title: props.text, // 滚动/裁切时仍能悬停读到完整原文 + hidden: () => !open(), + }, + h('span', { class: 'ua-notice-icon', 'aria-hidden': 'true' }, props.icon ?? ICONS[variant]), + h('div', { class: 'ua-notice-body' }, h('span', { class: 'ua-notice-text' }, props.text)), + props.closable === false + ? null + : h( + 'button', + { + type: 'button', + class: 'ua-notice-close', + 'aria-label': '关闭通知', + onClick: () => { + open(false); + props.onClose?.(); + }, + }, + '×', + ), + ); +} diff --git a/packages/skin/ui/src/types.ts b/packages/skin/ui/src/types.ts index efd4d59..c64c837 100644 --- a/packages/skin/ui/src/types.ts +++ b/packages/skin/ui/src/types.ts @@ -1111,11 +1111,20 @@ export interface HeatmapProps { formatValue?: (count: number, date: string) => string; // 悬停提示文案;缺省「日期 · 数量」 } -/*** 环形进度入参 ***/ -export interface ProgressRingProps { +/*** 环形进度入参 ***/export interface ProgressRingProps { value: number | Signal; // 当前进度 0-100;超出范围自动夹取,信号变化时自动重绘 size?: number; // 外径(px);缺省 96 thickness?: number; // 环宽(px);缺省 8 showText?: boolean; // 是否显示中心文字;缺省 true(关掉时请自行保证 aria 可读) label?: string; // 中心文字;缺省「N%」 } + +/*** 通知条入参 ***/ +export interface NoticeBarProps { + text: string; // 通知正文;单行不换行,超宽需配合 scroll + variant?: 'info' | 'success' | 'warning' | 'danger'; // 语义色;缺省 info + icon?: string; // 左侧符号;缺省按 variant 取(ℹ / ✓ / ! / ×) + scroll?: boolean; // 正文超宽时跑马灯滚动;缺省 false(静态,超出裁切) + closable?: boolean; // 是否显示关闭按钮;缺省 true + onClose?: () => void; // 关闭回调 +} diff --git a/packages/skin/ui/ua.manifest.json b/packages/skin/ui/ua.manifest.json index 7cfb2b4..5573c48 100644 --- a/packages/skin/ui/ua.manifest.json +++ b/packages/skin/ui/ua.manifest.json @@ -100,7 +100,8 @@ "relativeTime(props):把时间戳渲染成「3 分钟前」并自动刷新,超阈值改显示绝对日期,title 恒给精确值", "sparkline(props):迷你趋势线,把数值序列压成折线(可填充 + 末点标记),无坐标轴无交互", "heatmap(props):日历热力图,按周列 × 星期行铺格子、四档浓度表示当天数量,悬停看明细", - "progressRing(props):环形进度,SVG 双圆靠 dasharray 画弧 + 中心百分比,value 可传信号自动重绘" + "progressRing(props):环形进度,SVG 双圆靠 dasharray 画弧 + 中心百分比,value 可传信号自动重绘", + "noticeBar(props):单行通知条,语义色 + 左侧符号 + 可选跑马灯与关闭,适合页顶常驻播报" ], "keyTypes": [ "ButtonProps", @@ -4452,6 +4453,51 @@ "换色在父级设 color:进度弧读 currentColor,底环固定描边色(--ua-color-border),不引入第二个色源", "这是个「环形进度条」,不是仪表盘:只表达 0-100 单一进度,多段占比请用饼图类组件" ] + }, + { + "id": "noticeBar", + "title": "通知条 NoticeBar", + "demo": "sec-notice", + "props": [ + { + "n": "text", + "t": "string", + "d": "通知正文;单行不换行,超宽需配合 scroll" + }, + { + "n": "variant", + "t": "'info' | 'success' | 'warning' | 'danger'", + "d": "语义色;缺省 info" + }, + { + "n": "icon", + "t": "string", + "d": "左侧符号;缺省按 variant 取(ℹ / ✓ / ! / ×)" + }, + { + "n": "scroll", + "t": "boolean", + "d": "正文超宽时跑马灯滚动;缺省 false(静态,超出裁切)" + }, + { + "n": "closable", + "t": "boolean", + "d": "是否显示关闭按钮;缺省 true" + }, + { + "n": "onClose", + "t": "() => void", + "d": "关闭回调" + } + ], + "example": "noticeBar({ text: '系统将于今晚 23:00 维护 10 分钟', scroll: true })", + "steps": [ + "和 alert 的分工:alert 可多行带标题、占块;通知条只占一行,适合页顶常驻播报(维护公告、试用期提醒)", + "文案比容器宽就传 scroll: true:正文从右向左匀速走,悬停自动暂停,读得完不用追", + "只想播报不需要关闭就传 closable: false:右侧不再留 × 位,横条更紧凑", + "颜色只是第二线索:左侧符号按 variant 自动配(ℹ / ✓ / ! / ×),色弱或灰度打印也能分辨", + "跑马灯在减少动效偏好下自动停成静态首屏——完整原文始终在 title 里,不必为可访问性另写一份" + ] } ] } diff --git a/packages/skin/ui/ui.css b/packages/skin/ui/ui.css index d1bb334..ed17dd1 100644 --- a/packages/skin/ui/ui.css +++ b/packages/skin/ui/ui.css @@ -5901,6 +5901,96 @@ h5.ua-type-title { font-size: var(--ua-font-size-md); } font-variant-numeric: tabular-nums; /* 等宽数字:进度跳到 100% 时文字不会左右晃 */ } +/* ---- 通知条:单行横条(与 alert 的分工:alert 可多行带标题,通知条只占一行,适合页顶常驻播报) ---- */ +.ua-notice { + display: flex; + align-items: center; + gap: var(--ua-space-2); + width: 100%; + padding: var(--ua-space-2) var(--ua-space-3); + border: 1px solid transparent; + border-radius: var(--ua-radius-md); + color: var(--ua-color-text); +} + +.ua-notice-icon { + flex: none; + display: inline-flex; + align-items: center; + justify-content: center; + width: 18px; + height: 18px; + font-weight: var(--ua-weight-semibold); +} + +.ua-notice-body { + flex: 1; + min-width: 0; /* 不写这行,flex 子项不会收缩,跑马灯的 100% 基准会算成整行宽 */ + overflow: hidden; +} + +.ua-notice-text { + display: inline-block; + white-space: nowrap; /* 通知条只占一行:换行就不是「条」了 */ +} + +.ua-notice.is-roll .ua-notice-text { + animation: ua-notice-roll var(--ua-duration-loop-long) linear infinite; +} + +.ua-notice.is-roll:hover .ua-notice-text { + animation-play-state: paused; /* 悬停暂停:想读完的人不用追着跑 */ +} + +.ua-notice-close { + flex: none; + padding: 0 var(--ua-space-05); + border: none; + background: none; + color: var(--ua-color-text-muted); + font-size: var(--ua-font-size-lg); + cursor: pointer; +} + +.ua-notice-close:hover { + color: var(--ua-color-text); +} + +.ua-notice-info { + border-color: var(--ua-color-accent); + background: var(--ua-color-tint-accent); +} + +.ua-notice-success { + border-color: var(--ua-color-success); + background: color-mix(in srgb, var(--ua-color-success) var(--ua-alpha-soft), transparent); +} + +.ua-notice-warning { + border-color: var(--ua-color-warning); + background: color-mix(in srgb, var(--ua-color-warning) var(--ua-alpha-soft), transparent); +} + +.ua-notice-danger { + border-color: var(--ua-color-danger); + background: color-mix(in srgb, var(--ua-color-danger) var(--ua-alpha-soft), transparent); +} + +@keyframes ua-notice-roll { + from { + transform: translateX(100%); /* 从右边缘进入 */ + } + to { + transform: translateX(-100%); /* 从左侧走出 */ + } +} + +@media (prefers-reduced-motion: reduce) { + .ua-notice.is-roll .ua-notice-text { + animation: none; /* 减少动效:跑马灯停成静态首屏,完整原文靠 title */ + } +} + /* ---- 减少动效:旋转 / 缩放一律退化为瞬时 ---- 前两类(无限动画、悬停位移)已有专门兜底,但 rotate / scale 过渡属于第三类空间动效: 折叠箭头旋转、卡片按压缩放都靠它提供手感。减少动效下把过渡属性收窄成「只留颜色类」,