@linhey/rhine-design 0.4.0 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (69) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/README.md +24 -7
  3. package/components/AdvancedForms.tsx +184 -0
  4. package/components/AppShell.tsx +71 -0
  5. package/components/Background.tsx +29 -0
  6. package/components/COMMON_COMPONENTS.md +2 -2
  7. package/components/Charts.tsx +94 -0
  8. package/components/Data.tsx +98 -18
  9. package/components/Forms.tsx +14 -8
  10. package/components/MOTION.md +9 -1
  11. package/components/Media.tsx +82 -0
  12. package/components/OrbitBackdrop.tsx +33 -0
  13. package/components/Overlays.tsx +4 -3
  14. package/components/README.md +12 -1
  15. package/components/StatusTimeline.tsx +50 -12
  16. package/components/background.css +43 -0
  17. package/components/charts.css +27 -0
  18. package/components/common.css +5 -5
  19. package/components/data.css +6 -0
  20. package/components/drawer-placement.css +4 -0
  21. package/components/extensions.css +70 -0
  22. package/components/index.ts +14 -2
  23. package/components/media-parity.css +3 -0
  24. package/components/orbit.css +42 -0
  25. package/components/orbitRenderer.ts +230 -0
  26. package/components/patterns.css +1 -1
  27. package/components/styles.css +5 -1
  28. package/components/theme-arknights.css +10 -5
  29. package/components/theme-neo-brutalism.css +10 -4
  30. package/components/timeline.css +2 -2
  31. package/components/tokens.css +43 -0
  32. package/docs/ANTD_MUI_AUDIT.md +38 -0
  33. package/docs/APPLICATION_COMPONENTS.md +175 -0
  34. package/docs/DESIGN_SYSTEM_AUDIT.md +2 -0
  35. package/docs/ISSUE_4_VALIDATION.md +21 -0
  36. package/docs/ISSUE_VALIDATION.md +52 -0
  37. package/docs/ORBIT_BACKDROP.md +81 -0
  38. package/docs/REFERENCE_RESEARCH.md +2 -0
  39. package/docs/THEMING.md +41 -0
  40. package/docs/assets/application-shell.png +0 -0
  41. package/docs/assets/issue4-shell.png +0 -0
  42. package/docs/assets/media-viewer-mobile.png +0 -0
  43. package/docs/assets/monitoring-desktop.png +0 -0
  44. package/docs/assets/orbit-backdrop.png +0 -0
  45. package/docs/audits/DATA_ANTD_MUI.md +75 -0
  46. package/docs/audits/FORMS_ANTD_MUI.md +88 -0
  47. package/docs/audits/MONITORING_ANTD_MUI.md +44 -0
  48. package/docs/audits/SHELL_MEDIA_ANTD_MUI.md +91 -0
  49. package/package.json +1 -1
  50. package/preview/BackgroundGallery.tsx +46 -0
  51. package/preview/ExtensionsGallery.tsx +95 -0
  52. package/preview/GalleryShell.tsx +4 -3
  53. package/preview/MonitoringGallery.tsx +27 -0
  54. package/preview/OrbitGallery.tsx +47 -0
  55. package/preview/backgrounds.css +10 -0
  56. package/preview/extensions.css +6 -0
  57. package/preview/main.tsx +12 -1
  58. package/skills/rhine-design/SKILL.md +24 -3
  59. package/skills/rhine-design/references/API_MAP.md +6 -0
  60. package/skills/rhine-design/references/TASK_MAP.md +3 -1
  61. package/skills/rhine-design/references/integration.md +4 -2
  62. package/tests/Background.test.tsx +22 -0
  63. package/tests/DataParity.test.tsx +148 -0
  64. package/tests/Extensions.test.tsx +145 -0
  65. package/tests/FormParity.test.tsx +185 -0
  66. package/tests/Monitoring.test.tsx +38 -0
  67. package/tests/MonitoringParity.test.tsx +125 -0
  68. package/tests/OrbitBackdrop.test.tsx +183 -0
  69. package/tests/ShellMediaParity.test.tsx +180 -0
@@ -0,0 +1,38 @@
1
+ # Ant Design / MUI:应用组件逐项核对
2
+
3
+ 2026-10-24,issues #1–#6 的 0.5.0 API。核对覆盖全部 11 个新组件及 DataTable、Pagination、StatusTimeline 的扩展。依据官方在线文档,再用本库测试和真实展台验证行为;未安装这两套 UI 库,也不声称 API 兼容或完整功能等价。
4
+
5
+ ## 组件覆盖与修复
6
+
7
+ | 本库组件 | Ant Design 对应 | MUI 对应 | 本轮落地 |
8
+ | --- | --- | --- | --- |
9
+ | DateField | DatePicker | X DateField | 只读/表单标识、动态日期范围错误、校验通知 |
10
+ | DateRangePicker | RangePicker | X DateRangePicker | 两端校验、无效预设禁用、只读/清空配置、可定制字段标签 |
11
+ | NumberField | InputNumber | Number Field 官方 Base UI 组合示例 | 只读、Escape 撤销、空值步进修正、动态边界反馈、控制按钮配置 |
12
+ | RemoteMultiSelect | Select multiple | Autocomplete multiple | 连续选择、多选语义、空查询 Backspace、删除后焦点、只读、原生表单提交 |
13
+ | TreeSelect | TreeSelect / Tree | X Tree View | 已选项进入焦点、字符定位、批量键盘操作、结构节点、收起后焦点、只读 |
14
+ | DataTable 扩展 | Table | Table / X Data Grid | 单选/隐藏全选、取消排序、禁止展开约束、稳定详情 ID、行标题、多固定列自动偏移 |
15
+ | Pagination 扩展 | Pagination | TablePagination | 首末页、独立禁用/名称、未知总量和越界恢复、边界焦点 |
16
+ | Background | Layout / ConfigProvider tokens | Box / Paper / theme | 保留六场景语义与局部覆盖;补 DOM ref |
17
+ | AppShell | Layout.Sider / Drawer | permanent / temporary Drawer | 独立受控移动抽屉、正确左右方向、栏宽/断点配置、缩放下容器判断 |
18
+ | MediaCard | Card / Image | CardActionArea / CardMedia / CardActions | 独立重试等 actions、原生属性/ref、打开与选择保持分离 |
19
+ | MediaViewer | Image PreviewGroup / Modal | Dialog + 自定义画廊 | 方向键、首尾禁用与焦点、defaultOpen、可直接切换信息栏、嵌套编辑与播放按键隔离 |
20
+ | StatusTimeline 扩展 | Slider + Popover | Slider + 浮层 | 稳定 ID、受控/默认选中与开关、禁用、键盘进入详情 |
21
+ | TrendChart | 独立 Ant Design Charts Line / Column | X LineChart / BarChart | 键盘/指针逐点查看、受控高亮、格式化、原始数据保留、极值坐标修正 |
22
+ | StackedBar | Ant Design Charts Bar percent | X stacked BarChart | 数值格式化、零值不留假色段;保留未知总量保护 |
23
+
24
+ ## 详细 API 与交互证据
25
+
26
+ - [表单逐项对照](audits/FORMS_ANTD_MUI.md):5 个组件、官方 API 链接、数据类型、事件、键盘、状态、表单关联及保留差异。
27
+ - [数据表与分页逐项对照](audits/DATA_ANTD_MUI.md):选择、排序、展开、固定列、分页与焦点。
28
+ - [背景、外壳与媒体逐项对照](audits/SHELL_MEDIA_ANTD_MUI.md):组合、受控状态、响应式、浮层及媒体导航。
29
+ - [监控逐项对照](audits/MONITORING_ANTD_MUI.md):时段与事件轴区分、图表数值/键盘、缺失数据及格式化。
30
+ - [最终验证](ISSUE_VALIDATION.md):以本轮实测结果为准;官方库自身能力不能替代 Rhine 的验证。
31
+
32
+ ## 接入变化与范围
33
+
34
+ 原有必填参数保持兼容。RemoteMultiSelect 默认选择后保持候选打开,便于连续选择;如需原行为设 `closeOnSelect`。原单选 Combobox 仍默认选完关闭。其他新参数均为可选,现有受控调用无需迁移。新导出的 `PaginationProps`、`StatusTimelineProps` 与原有组件 Props 一同从包入口可用。
35
+
36
+ 保留 ISO 日期字符串、宿主服务端查询与分页、树父子独立选择、原生 table、单序列轻图表及 slot 媒体内容。自绘日历/时区适配器、树级联与虚拟化、可编辑网格、多轴图表、图像旋转缩放/播放引擎未纳入;各分项说明了为何不采用以及对应差异。组件 props 不增加 AntD/MUI 同义别名,不新增运行时依赖,不迁移消费应用。
37
+
38
+ 这些变化自 0.5.0 提供,npm 0.4.0 不包含本页 API;精确制品与消费验证见[版本验收](ISSUE_VALIDATION.md)。
@@ -0,0 +1,175 @@
1
+ # 应用组件与状态契约
2
+
3
+ 本页对应 GitHub issues [#1](https://github.com/linhay/rhine-design/issues/1)、[#2](https://github.com/linhay/rhine-design/issues/2)、[#3](https://github.com/linhay/rhine-design/issues/3)、[#4](https://github.com/linhay/rhine-design/issues/4)、[#5](https://github.com/linhay/rhine-design/issues/5)、[#6](https://github.com/linhay/rhine-design/issues/6)。新增 11 个组件,公共组件总数为 59。
4
+
5
+ **版本边界:以下 API 自 0.5.0 提供,npm 0.4.0 不含这些能力。** 本次不改变现有组件必填参数;DataTable/Pagination 的参数均为新增可选项。使用 `npm install --save-exact @linhey/rhine-design@0.5.0` 并提交 lockfile。组件库升级不代表消费应用已经迁移。
6
+
7
+ 公开类型从包主入口导出,真实实现是 API 权威:`Background.tsx`、`AppShell.tsx`、`AdvancedForms.tsx`、`Media.tsx`、`Data.tsx`。兼容范围沿用 React 19 + Vite;native WebView、其他构建器、SSR 和屏幕阅读器组合需消费项目另行验证。无需新增依赖。
8
+
9
+ 2026-10-24 已对全部新增组件及扩展逐项核对 Ant Design / MUI 官方 API 与交互,修复与保留差异见[对标清单](ANTD_MUI_AUDIT.md)。以下契约包含本轮补齐;原有必填参数保持兼容。
10
+
11
+ ## 背景层级
12
+
13
+ | 区域 | token / API | 规则 |
14
+ | --- | --- | --- |
15
+ | 应用画布 | `--rhine-canvas-bg`,`roleTone="canvas"` | 整体底色,允许主题纹理 |
16
+ | 正文区域 | `--rhine-content-bg`,`roleTone="content"`(默认) | 默认纯色;显式 `decoration="theme"` 可启用主题纹理 |
17
+ | 全局 / 上下文 / 辅助侧栏 | `--rhine-sidebar-bg`,`roleTone="sidebar"` | 不透明纯色,边界使用 `--rhine-line` |
18
+ | 卡片 / 表单 | `--rhine-surface-bg`,`roleTone="surface"` | 不透明阅读表面,默认无纹理 |
19
+ | 弹窗 / 浮层 | `--rhine-overlay-bg`,`roleTone="overlay"` | 默认无纹理,遮罩独立使用 `--rhine-backdrop-bg` |
20
+ | 图片 / 视频 | `--rhine-media-bg`,`roleTone="media"` | 中性深色底与配套浅色文字,默认无纹理 |
21
+
22
+ 纸面默认无纹理;战术终端使用 32px 低对比网格;橙趣使用 14px 点阵。主题统一提供 `--rhine-background-texture`、`--rhine-background-scale`、`--rhine-background-mark`,无需消费者复制渐变。`decoration="auto"` 为默认值,仅 canvas 使用主题纹理,正文和 AppShell 默认纯色。`theme` 显式启用主题纹理,`none` 关闭本区域装饰,主题切换不会重新启用它。Background 另提供 surface/overlay/media 场景及局部 appearance 覆盖,完整六场景配置见[主题契约](THEMING.md#场景背景050)。
23
+
24
+ `decoration` 默认 `auto`,仅画布默认跟随主题纹理,AppShell 正文默认纯色。`appearance` 支持局部底色、文字色、纹理与尺寸覆盖,完整变量及优先级见[场景背景配置](THEMING.md#场景背景050)。展台 `#backgrounds` 仅展示当前主题,随右上角选择器同步切换。
25
+
26
+ ```tsx
27
+ import { Background, Surface } from '@linhey/rhine-design';
28
+ import { ThemeProvider } from '@linhey/rhine-design/theme';
29
+
30
+ <ThemeProvider defaultTheme="neo-brutalism">
31
+ {/* 用 Background 替换原本 background: var(--rhine-bg) 的正文 div。 */}
32
+ <Background roleTone="content">
33
+ <Surface>不透明的内容卡片</Surface>
34
+ </Background>
35
+ </ThemeProvider>
36
+ ```
37
+
38
+ 背景直接绘制在元素上,无伪元素、无点击拦截层、无 transform/contain/position 副作用。纹理从该区域左上角开始,`background-attachment: scroll` 固定在滚动容器的框上:滚动其内部内容时图案不重置、不跟随内容漂移;外层移动整个区域时背景随框移动。各独立区域拥有独立原点,不承诺跨两个元素接缝完全对齐。使用 CSS 默认背景裁剪;内容和焦点在背景上方,裁剪、滚动和 Portal 不受 Background 改变。背景无动画,也无需嵌套 ThemeProvider。
39
+
40
+ ## 三种外壳布局
41
+
42
+ `AppShell` 接收 `layout="single" | "double-left" | "left-right"`;`navigation` 必填、`secondary` 在后两种布局可选。面板形状为 `{ label, content, open, onOpenChange }`;`header` 放当前任务操作、`children` 为正文,`decoration` 控制正文背景。
43
+
44
+ | 方案 | 用途 | 顺序 |
45
+ | --- | --- | --- |
46
+ | single | 简单管理或设置工具 | 全局导航 + 正文 |
47
+ | double-left | 目录、列表与编辑任务 | 全局导航 + 上下文目录 + 正文 |
48
+ | left-right | 检查器、对象属性与预览 | 全局导航 + 正文 + 辅助详情 |
49
+
50
+ 全局栏宽 224px,次栏宽 256px,正文伸展,三栏同时展开时至少留约 638px 正文空间。判断依据是外壳容器宽度,适用于嵌入展台或桌面应用:小于 1120px 先将次栏转为 Drawer,小于 760px 再将全局栏转为 Drawer。抽屉初始关闭;桌面 `open` 偏好保留,回到宽窗后恢复。已经打开的 Drawer 在扩宽窗口时保持到用户关闭,避免中断操作;不会自动丢弃正文或选中项。
51
+
52
+ 外壳需要父级提供明确高度(例如 `height: 100dvh`,展台用固定高度)。header 是不滚动的同级区域,body 填满余高;导航、次栏和正文各自 `overflow:auto`。宿主不应再给这些区域内的整页容器设置第二个垂直滚动。表格的局部横向/有限高度滚动是显式例外。没有拖拽宽度、持久化或停靠管理器。
53
+
54
+ ```tsx
55
+ const [navigationOpen, setNavigationOpen] = useState(true);
56
+ const [detailsOpen, setDetailsOpen] = useState(true);
57
+ // currentId、draft 等业务状态放在 AppShell 的上层。
58
+ <div style={{ height: '100dvh' }}>
59
+ <AppShell layout="left-right"
60
+ navigation={{ label: '全局导航', open: navigationOpen,
61
+ onOpenChange: setNavigationOpen, content: <SideNav {...navigationProps} /> }}
62
+ secondary={{ label: '辅助详情', open: detailsOpen,
63
+ onOpenChange: setDetailsOpen, content: <ObjectDetails value={object} /> }}
64
+ header={<Button onClick={save}>保存</Button>}>
65
+ <Editor value={draft} onChange={setDraft} />
66
+ </AppShell>
67
+ </div>
68
+ ```
69
+
70
+ SideNav 继续负责当前项、长名称和 aria-current;Drawer 继续负责 Tab、Escape 和触发器焦点归还。正文不因切换布局或主题重建。面板在抽屉与内联之间转换时可能重新挂载,因此选中、展开、输入和请求状态必须提升到宿主;不要在面板 render 时启动不可取消的副作用。主题切换不改变 React key。切换或隐藏面板时将位于其中的焦点送回对应操作按钮。
71
+
72
+ `ShellPanel.drawerOpen/defaultDrawerOpen/onDrawerOpenChange` 独立控制临时抽屉,桌面 `open` 偏好不受影响;宿主选完导航项后可设置 drawerOpen=false。`width` 和 `breakpoint` 使用 CSS px,默认仍为上述数值;断点按容器布局宽度判断。全局导航与双左次栏从左侧打开,左右布局的辅助栏从右侧打开。AppShell 支持 className/style,Background 支持原生属性及 ref。受控与非受控模式在组件生命周期内保持一致。
73
+
74
+ ## 表单
75
+
76
+ | 组件 | 主要 API | 数据与键盘契约 |
77
+ | --- | --- | --- |
78
+ | DateField | `label/value/onValueChange/min/max/disabled/error` | 原生 `input type=date`;ISO 日期字符串或空字符串,无 UTC/时区转换,原生日历和键盘由浏览器实现 |
79
+ | DateRangePicker | 上述范围 + `value={start,end}`、`presets=[{label,value}]` | 两个原生日期输入,自定义范围、受控预设、清空;结束日期下界取 start/min 较晚者;反向范围显示错误,不静默调换 |
80
+ | NumberField | `value: number\|null`、`onValueChange/min/max/step/precision/disabled/error` | 编辑中保存字符串;失焦/Enter 提交;无效及越界输入保留并报错;上下键/按钮步进与钳制边界;空字符串提交 null |
81
+ | TreeSelect | `nodes/value/onValueChange/expandedKeys/onExpandedChange/multiple`、loading/error/disabled | 节点为 `{id,label,disabled?,children?}`;父子独立选择,默认单选;调用方提供搜索后的树,不做全量过滤 |
82
+ | RemoteMultiSelect | `query/onQueryChange/value/onValueChange/options`、loading/error/disabled | value 是完整 `{value,label,disabled?}[]`,已选标签不依赖本次结果;不重复选中;清空保留禁选标签 |
83
+
84
+ 日期 min/max 约束原生日历和表单有效性;手动编辑、业务校验及最终提交由宿主验证。原生日期面板位于浏览器 UI,不放在受裁剪的自定义浮层。日历外观、屏幕阅读器和移动 WebView 行为由具体浏览器决定,不声称提供自绘日历。预设必须使用宿主计算好的日期;不得以本机时区代替产品时区。没有“今天”隐式计算。
85
+
86
+ DateField 新增 `readOnly/required/id/name/hint/onValidationChange`;外部日期或 min/max 改变会更新格式/范围错误,不自动回写值。DateRangePicker 同样支持 readOnly/required/hint/onValidationChange,另有 `clearable`(默认 true)、`startLabel/endLabel/startName/endName`。预设含非法日期、反向区间或任一端越界时禁用。onValidationChange 回传格式/范围/显式 error,required 仍走提交时的原生表单校验。只读时保留浏览与聚焦,预设、清空、步进和选择不能更改值。
87
+
88
+ NumberField 支持小数步进(默认 1);precision 限制为 0–15 位,未指定时普通提交保留解析后的 JS 数值,步进清除至 12 位的浮点尾差;IEEE-754 数值精度不适用于高精度货币账本。`-`、`1.` 等草稿在编辑时不改写;外部 value 真正变化时覆盖草稿。未改变值的失焦/Enter 不触发 onValueChange;输入法组词时不提交或步进。
89
+
90
+ NumberField 另有 `readOnly/required/id/name/hint/controls`(按钮默认显示);Escape 取消未提交草稿并恢复受控值,第二次 Escape 可交给外层浮层。min/max 变化会直接标明当前越界,不伪造用户输入或自动修改宿主值。空值步进按有效范围处理,不再把空字符串当成已达到零边界。
91
+
92
+ TreeSelect 使用 tree/treeitem/group,Tab 进入一个可见节点,上下/Home/End 移动,右键展开或进入首个子项,左键收起或返回父项,Space/Enter 选择。禁选节点可导航和展开,但不能勾选。多选用 aria-checked,单选用 aria-selected。节点 ID 全树唯一稳定;过滤后的祖先与展开状态由宿主提供,选择状态不随结果集消失。
93
+
94
+ 首次进入优先已选可见节点;字符前缀定位不改变选择,`*` 展开同层分支,Ctrl/⌘+A 仅切换可见可选节点。外部收起时焦点回可见祖先。节点 `selectable=false` 用于结构分组;readOnly 允许浏览展开而禁止选择。`name` 为选中 key 生成同名 hidden inputs,disabled 不提交。
95
+
96
+ RemoteMultiSelect 复用 Combobox 的方向键、Enter、Escape 和 IME 防误提交。加载或失败时禁止选择旧候选,已选项仍显示且可移除;默认选中后保持候选列表打开,`closeOnSelect=true` 恢复选完关闭。`clearQueryOnSelect` 默认 false;新增 readOnly/clearable/placeholder/hint/name。空查询 Backspace 删除最后一个可移除标签,标签删除/清空后回输入框;锁定标签保留。name 以同名 hidden inputs 提交受控 keys。单选 Combobox 的默认关闭行为不变。异步取消、序列检查、服务端查询和时区解释全部归宿主。展台有可取消的本地延迟结果演示,但不是生产数据层。
97
+
98
+ 分组底色 `--rhine-field-group-bg`;树缩进 `--rhine-tree-indent`;其余输入、选择、错误和焦点继续用既有语义 tokens,字号不低于 12px。
99
+
100
+ ## DataTable 与 Pagination
101
+
102
+ 所有新参数可选,原表格保持原生 table 语义。此处提供可展开的层级表格,不实现可编辑 ARIA treegrid;键盘使用 Tab 与原生 checkbox/button,不冒充网格方向键导航。
103
+
104
+ - `selection={keys,onChange,isDisabled?}`:keys 为稳定 rowKey 数组,可包含其他页/查询中的记录。表头只选择/取消当前可见且未禁选的行;保留不可见和禁选键,部分选中为 mixed。加载时禁用选择。
105
+ - `expansion={keys,onChange,getChildren?,renderDetail?,canExpand?}`:子行按宿主顺序展开,层级有文字说明;renderDetail 为独立 region,可与子行共存。keys 由宿主管理,折叠不清空选择;不请求子数据、不更改导出范围。大树的加载与虚拟化由宿主决定,本组件不内置虚拟表格。
106
+ - `rowLabel` 默认 rowKey,建议传业务可读名称,供选择/展开按钮命名。所有层级 rowKey 必须全局唯一稳定。
107
+ - `stickyHeader/maxHeight`:提供明确局部滚动区;列可设 `width/sticky/stickyOffset`。多列固定默认按实测 CSS 布局宽度自动累计 offset,显式 stickyOffset 优先;需为正文至少保留一个可读列,不将多列固定到遮满窄屏。展台固定右侧两个窄列。
108
+ - `density="comfortable" | "compact"`:默认单元格内距为 12/16px 或 6/12px;橙趣 comfortable 为 16/12px,compact 同为 6/12px。业务文字 14px、层级说明 12px,操作仍为 44px。tokens:`--rhine-table-cell-padding`、`--rhine-table-header-bg`、`--rhine-table-hover-bg`、`--rhine-table-selected-bg`;选中底色优先于悬停,固定列使用不透明底色。
109
+ - `Pagination.onPageSizeChange` 和 `pageSizeOptions`:仅回传页大小意图,宿主决定是否回到第一页、是否取消请求。total 已知时推导页数;未知时依赖 hasNext。库不筛选、排序、请求或切割全量 rows。
110
+
111
+ ```tsx
112
+ <DataTable caption="记录" rows={response.rows} columns={columns}
113
+ rowKey={row => row.id} rowLabel={row => row.name}
114
+ selection={{ keys: selected, onChange: setSelected, isDisabled: row => !row.canSelect }}
115
+ expansion={{ keys: expanded, onChange: setExpanded, getChildren: row => row.children ?? [] }}
116
+ stickyHeader maxHeight={480} loading={loading} error={error} />
117
+ <Pagination page={page} pageSize={pageSize} total={response.total}
118
+ hasNext={response.hasNext} onPageChange={requestPage} onPageSizeChange={requestPageSize} />
119
+ ```
120
+
121
+ 迁移必须保留选择、导出、查询和层级状态。错误与刷新保留已有行,空数据不伪装成错误;已有 sort/onSortChange 不变。
122
+
123
+ `selection.mode` 默认 multiple,可选 single 使用原生 radio(读取 keys 第一项);新选择回传单个 key,替换旧单选。`hideSelectAll` 保留单行操作但不显示全选。`DataColumn.rowHeader` 输出 th scope=row;`onSortReset` 提供显式取消排序,宿主清空 sort 后生效。canExpand=false 同时阻止旧展开 key 渲染子行/详情,详情 ID 按行 key 稳定。
124
+
125
+ Pagination 新增 `disabled/label/showFirstButton/showLastButton`;首末页按钮默认不显示,未知总量时末页不可操作。负数与非有限 total 视作未知;总量缩小导致当前页超界时明确标注,上一页返回已知末页,不自动发请求。翻页到边界时焦点移至相邻可用按钮,页码摘要有状态播报。
126
+
127
+ ## 媒体
128
+
129
+ `MediaCard` 接收 title、date、kind(photo/video/RAW/Live)、preview、state(ready/loading/error/empty)、aspectRatio(默认 4/3)、onOpen;可选 selected/onSelectedChange/disabled。preview 内的 img/video 使用 contain 保持原比例;媒体类型及失败均有文字。打开按钮与选择 checkbox 为兄弟元素,选择不会触发打开;卡片没有内置网络、轮播、虚拟列表或滚轮监听。preview 应为非交互缩略图,不在打开按钮里嵌套视频控制器。loading 时预览保持隐藏挂载,宿主可在 img.onError/onLoad 后设置 state;缺预览默认 empty,日期为空显示未知。
130
+
131
+ `MediaViewer` 接收 trigger/title/description/children、受控 open/onOpenChange、onPrevious/onNext、actions、metadata/metadataOpen/onMetadataOpenChange。复用 Radix Dialog 的焦点范围与 Escape,关闭归还实际打开它的卡片/触发器;宿主若卸载或虚拟化掉触发器,应在 onOpenChange 中安排替代焦点。
132
+
133
+ MediaCard 支持原生 article 属性、ref 与独立 actions(重试等操作不能嵌套在打开按钮里)。MediaViewer 支持 defaultOpen、defaultMetadataOpen 及 className/style;不传 metadataOpen 时,信息栏按钮即可管理内部状态。`previousDisabled/nextDisabled` 显式表达边界,左右键默认触发上/下一项,可用 `keyboardNavigation=false` 关闭;输入框、选择器、媒体播放器和嵌套浮层保留自身按键。导航按钮到达边界变禁用时焦点留在查看器内,可继续反向浏览。
134
+
135
+ 查看器采用同一主题根中的中性媒体 tokens:canvas `#101214`、overlay `#202428`、text `#f6f7f8`、muted `#bcc3ca`、border `#68727c`、focus `#9bceff`。不把战术主题当暗色媒体模式,也不嵌套 Provider。顶部操作可换行,触控目标至少 44px;桌面 metadata 位于右侧,760px 以下移到底部。短窗口内容可滚动,关闭按钮始终在顶部可达。
136
+
137
+ 媒体 children、下载链接和资源版本选择通过 slots 提供;库不持有下载路径、播放状态或路由。actions 中使用原生 button/select/a 可自动使用中性叠加样式。宿主可将 scroll-snap 列表放入画布,并保留原有 Masonic 或其他虚拟列表。仅复用模态的背景滚动管理,没有增加 wheel 事件锁或自定义手势拦截。内部 Dialog/Popover 优先响应 Escape,下一次 Escape 再关闭查看器;媒体自身不播放进场动画,减少动态遵循同一主题根。
138
+
139
+ ## 健康详情与运维图表(issue #6)
140
+
141
+ `TimelineSegment.detail` 可选,形状为 `{ start, end, reason?, counts?: [{ id, label, value: number|null, unit? }], methodology? }`。开始/结束时间是宿主格式化的含时区字符串;计数 0 与 null 分别呈现为零和未知,NaN/Infinity 也视为未知。统计口径缺失时明确标注未提供,不猜测原因或成功率。旧版只有 label/status 的调用仍兼容。
142
+
143
+ 完整与 compact 健康条均复用同一结构化详情。键盘聚焦和方向键、鼠标定位、触屏按下均打开同一个非模态 Popover;默认优先向上,空间不足自动转向下方,距离视口 12px,内容超过可用高度时内部滚动。Escape 或关闭按钮收起,点击外部也可退出。Popovers 挂到同一主题根,不受侧栏/卡片裁剪。保留当前时段的 aria-valuetext,并用 aria-details 指向已展开详情;焦点不因鼠标悬停被抢走。减少动态无新增例外。
144
+
145
+ StatusTimeline 通过 `activeId/defaultActiveId/onActiveChange` 按稳定时段 ID 控制选中;未指定或当前 ID 消失时显示最后一个时段。`open/defaultOpen/onOpenChange` 控制详情,`disabled` 禁止操作及显示详情。Enter/Space 将键盘焦点送入详情关闭按钮,退出后返回健康条且不会立即重开。
146
+
147
+ `TrendChart({ label, unit, rangeLabel, description, points, kind, stale?, error?, loading? })` 提供 `kind="bar" | "line"`,每个 point 是 `{id,label,value:number|null}`。宿主负责时间桶、排序、聚合、单位与统计说明;组件只映射坐标。零是有效采样,未知值不补零、不插值,折线路径在缺失点处断开;图内 ×、SVG 可访问说明和可展开的原始数据表共同表示缺失。单位、范围与图例均为 HTML 文字,避免窄屏 SVG 缩放导致文字小于 12px。多条资源指标使用多个命名图表组合,不内置数据请求或图表引擎。
148
+
149
+ `StackedBar` 使用相同的 label/unit/rangeLabel/description/反馈字段,接收 `parts=[{id,label,value:number|null,tone?:1|2|3|4}]`。只在每项计数均已知、非负、有限且总和大于零时按传入计数绘制占比;任意未知值会停止归一化并显示“总量未知”,仍列出全部已知/未知计数。全零和负数各有说明。百分比是图例中对这组计数的数学占比,保留一位小数,不是健康分数或成功率。宿主必须提供互斥分类,不能把重叠统计相加当作总量。
150
+
151
+ 两类图表新增 `valueFormatter(value:number|null)`;非有限值以 null 传入。TrendChart 刻度与逐点文字采用格式化,原始数据表保留原数值;StackedBar 格式化图例但不改变比例算法,零分段不占色带空间。TrendChart 可聚焦图形后用左右/Home/End,或悬停/轻触查看同一时段。`activePointId/defaultActivePointId/onActivePointChange` 支持受控高亮与多图联动;null 清除高亮,丢失 ID 不替代为别的样本。高亮值以 HTML 文字播报,缺失桶仍可查看。
152
+
153
+ 图表 `stale` 显示采集陈旧说明,`error` 显示错误并保留旧数据,loading 同样保留旧数据;空数组与全未知区分。图例逐项提供名称与数值,不只靠颜色。`--rhine-chart-series-1/2/3/4`、`--rhine-chart-grid`、`--rhine-chart-missing` 是语义 tokens;前两色跟随主题主色/信号色,后两色供独立分类使用。图形不闪烁、不扫光、不内置告警阈值。相关 API 自 0.5.0 提供,npm 0.4.0 不包含。
154
+
155
+ ```tsx
156
+ <StatusTimeline label="请求历史" segments={segmentsWithDetail}
157
+ startLabel="10:00 UTC+8" endLabel="11:00 UTC+8" />
158
+ <TrendChart kind="line" label="CPU 使用率" unit="%" rangeLabel={range}
159
+ description="每分钟采样,缺失保持未知" points={serverPoints}
160
+ stale={staleMessage} error={requestError} />
161
+ <StackedBar label="互斥结果分类" unit="次" rangeLabel={range}
162
+ description="按最终结果分类" parts={serverCounts} />
163
+ ```
164
+
165
+ ## 真实展台入口
166
+
167
+ 开发服务 `npm run dev` 后访问:
168
+
169
+ - `/#app-shell`:三种布局、独立背景、Surface、固定顶部操作、Drawer/Dialog、状态与可编辑草稿。
170
+ - `/#advanced-forms`:日期预设/自定义/清空、数字草稿、树单多选、远程延迟/取消/IME,以及加载/失败/空/禁用。
171
+ - `/#advanced-data`:跨页选中键、禁选、层级/详情、密度、已知/未知总数和局部固定列。
172
+ - `/#media`:默认、长标题、加载、错误、缺预览,媒体查看器中的版本/下载与分层 Escape。
173
+ - `/#monitoring`:结构化时段详情与紧凑条、柱形趋势、缺失点折线、已知/未知占比、文本替代及空/陈旧/错误状态。
174
+
175
+ 页首切换三主题及减少动态不重建当前展台;切换章节会卸载演示。自动测试验证受控行为,浏览器与版本验收单独记录于 [验证记录](ISSUE_VALIDATION.md)。精确版本的制品校验和与消费验证按 [发布流程](RELEASING.md)保留。
@@ -1,5 +1,7 @@
1
1
  # 莱茵设计 · 主流系统对照与补齐顺序
2
2
 
3
+ 本页保留早期组件基线与补齐顺序。2026-10-24 对 issues #1–#6 的 11 个新增组件及 3 个扩展另有[Ant Design / MUI 逐项审计](ANTD_MUI_AUDIT.md),包含本轮修复、验证和有意差异;当前候选 API 见[应用组件契约](APPLICATION_COMPONENTS.md)。
4
+
3
5
  初次调研:2026-10-22;2026-10-23追加[GitHub项目与skills调研](./REFERENCE_RESEARCH.md),main新增六个组件、14类场景指南和两组动效。对照[莱茵设计](../README.md)的`components/`与通用表单、数据展示、反馈和导航场景。以下优先级是本项目判断;引用用于说明参考系统的原则,不代表它们要求采用我们的尺寸、配色或组件清单。独立展台使用18309的`/#…`入口。
4
6
 
5
7
  ## 参考与取舍
@@ -0,0 +1,21 @@
1
+ # Issue #4 主线整合验证
2
+
3
+ 2026-10-23。此记录对应 #4 专项源码整合,不表示 npm 已发布。包版本保持 0.4.0,新增 API 等待下次 npm 发布窗口。
4
+
5
+ ## 范围
6
+
7
+ 从候选提交 `2e08ebb` 提取 Background、AppShell(组合展台依赖)、背景语义 tokens、三主题表面样式、两组真实 React 展台及相关契约。没有纳入复杂表单、受控数据表、媒体查看器和监控图表。原候选分支保留,后续整合需保留本次背景能力并处理共享文件差异。
8
+
9
+ ## 本轮验证
10
+
11
+ - Node 24 下 `npm ci` 与 `npm run check` 通过:55 项测试、TypeScript、Vite 生产构建、CSS/SVG 产物检查。
12
+ - Chromium 使用本次生产构建:三主题 × 场景背景/应用外壳两个展台 × 400/520/880/1600px,共 24 组,无页面、主工作区或外壳横向溢出。
13
+ - 三主题 × 两个展台,在 1040px 视口 CSS `zoom:2` 下无页面横向溢出,共 6 组。此证据不等同于浏览器菜单 200% 缩放,后者留待发布验收。
14
+ - 三主题的正文纹理开关、纯色降级、内部滚动后图案不重置及顶部操作位置不变通过;纸面无纹理,战术网格与橙趣点阵可独立绘制。
15
+ - Dialog 实际可输入,Escape 关闭后焦点回到触发按钮;正文草稿保留,全页唯一主题根。
16
+ - 系统减少动态偏好下背景无动画;浏览器运行时错误为零。
17
+ - 实际截图:[橙趣正文与侧栏](assets/issue4-shell.png)。
18
+
19
+ ## 后续
20
+
21
+ 等下次 npm 窗口完成最终版本号、干净提交制品、registry 回读及仓库外固定版本安装验证,再更新并关闭 #4。当前仅交付 main 源码与展台,不能按 npm 0.4.0 消费新增 Background/AppShell。
@@ -0,0 +1,52 @@
1
+ # Issues #1–#6 验证记录
2
+
3
+ 2026-10-24 更新,0.5.0 源码与发布前验证。下方保留历史候选证据及其精确提交;正式版本、制品身份与 registry 回读见 [v0.5.0 发布记录](https://github.com/linhay/rhine-design/releases/tag/v0.5.0)。组件库发布不代表消费应用已迁移。
4
+
5
+ ## 0.5.0 发布复核(2026-10-24)
6
+
7
+ - 完成 PR #7 全部有效审阅:数字重复提交与未指定精度的数据损失、加载媒体挂载、空图表提示、slider ARIA、表格主题/密度/悬停及 CSS-only 根派生变量。AppShell 移除辅助栏焦点已有修复,本轮补充清除面板与外部焦点保护回归。
8
+ - Node 24 `npm run check`:**126 项测试、15 个文件通过**;类型、生产构建及 CSS/SVG 检查通过。本轮发布审阅新增 7 项测试。最终 JS/CSS 为 `index-ZdseTmxg.js` / `index-DenpVIW5.css`。
9
+ - Chrome 155 原生“网页缩放”设为 **200%**,设置控件显示选中200%;相同窗口下 innerWidth 从1040变为520,devicePixelRatio从1变为2,HTML/body CSS zoom仍为1。最终产物三主题×六展台×有效400/520px共 **36组布局**、**15组跨组件交互+12组背景/外壳交互**全部通过,意外横向溢出0、运行时错误0。验后恢复100%。这补齐 issue #4 预留的浏览器实际缩放验收。
10
+ - 浏览器补验媒体隐藏节点发起请求并在 onLoad 后显示原节点、长小数/极小数保留且不重复提交;CSS 修前41个断言失败,修后三主题×两密度、主题根 palette 继承/显式场景覆盖与不透明固定单元格底色全部通过。
11
+ - 证据保存在忽略目录 `output/playwright/release-browser-zoom-*`、`release-css-review*`。原生缩放下 Playwright 截图裁剪异常,验收依据设置文本、DPR/尺寸、DOM几何及实际交互,不以截图外观替代行为证据。系统日历、读屏软件、移动WebView和真实媒体解码仍属宿主验收边界。
12
+
13
+ ## Ant Design / MUI 对标补齐(2026-10-24)
14
+
15
+ - [逐项清单](ANTD_MUI_AUDIT.md)覆盖 11 个新增组件与 DataTable/Pagination/StatusTimeline 的扩展,每组记录官方链接、修复项及保留差异。没有安装或复制上游库。
16
+ - Node 24 `npm run check`:**119 项测试、15 个文件全部通过**,包含本轮新增 45 项回归及合入主线保留的 2 项背景专项测试。TypeScript、生产构建及 CSS/SVG 产物检查通过。旧 Shell 测试宽度 mock 同步为 clientWidth,以覆盖真实的 CSS 布局宽度契约。
17
+ - 已合入主线 `0d19c8e` 的背景子集,保留其专项记录与截图并消除 PR 冲突;组件和展台代码与已验候选一致。合并后重新构建的 JS/CSS 文件名仍为 `index-93MfkO6O.js` / `index-BZ6ALQ8I.css`,浏览器及消费包证据仍对应相同运行实现。
18
+ - 生产构建 18319:三主题 × 六展台 × 390/400/520/880/1600 共 **90 组宽度**,document/main/shell 无意外横向溢出、运行时错误 0;三主题 × 六展台共 **18 组 CSS 200% 缩放**,并验证 520px 重排和减少动态。局部表格横向滚动属于预期。
19
+ - 三主题 400px 的生产实际交互:日期只读和无效预设、数字 Escape 撤销、远程多选连续选两项/空查询 Backspace/标签焦点;数据表单选、取消排序焦点、双固定列相邻、末页禁用后的焦点、未知总量末页禁用;左侧导航抽屉选项后受控关闭;卡片重试与打开分离、媒体到末项后可反向键盘浏览、嵌套弹窗不串方向键、Escape 回到实际卡片;双图键盘联动、零/未知时段、健康详情 Enter 进入/Escape 退出。15 组组合流程全部通过,运行时错误 0。
20
+ - 分项开发浏览器另验证:树字符与批选、FormData/只读;多固定列 3 主题 × 3 宽度及 3 次 CSS zoom;左右抽屉边缘、CSS transform 不改变 Shell 断点。详细证据见各审计文档。
21
+ - 独立复审发现 StackedBar 原始小数作为 flex-grow 时总和小于 1 会留下多余空白,已改为归一化权重并补回归;图例和原始计数不变。
22
+ - 从干净提交 `d3685ab` 导出并打包,在仓库外 React 19/Vite 8 消费项目安装实际 tarball;全部 11 个新组件、扩展 API 和新导出的 Props 类型通过严格 TypeScript 检查(Vite client 类型)与生产构建。浏览器验证图表键盘、非受控媒体信息栏和单一主题根;小数权重 0.1/0.2 在 300px 色带内两段实测 98.66/197.34px,加 2px 间距正好填满 298px 内宽,比例与图例一致。消费壳需使用 Stack 留出 compact 时间轴的 44px 命中范围,不能把独立控件无间距堆叠。临时消费项目仅有 favicon 404,无组件运行时错误。
23
+ 测试包仍为本地 0.4.0 标识,未上传 registry;SHA-256:`d051b84e5544b697e436620c9f0c64f7f4875ed08ed956235c03cfdce86dd798`。包清单 116 个文件,不含工作区私有目录与浏览器产物。
24
+ - 本轮浏览器脚本与截图在忽略目录 `output/playwright/parity-*`。只读屏幕像素不能证明键盘/原生辅助技术;没有宣称操作系统日历、移动 WebView、实际屏幕阅读器或浏览器菜单缩放验收。
25
+
26
+ ## 初次候选验证(2026-10-23)
27
+
28
+ - Node 24 下 `npm run check`:72 个测试通过(原有 53 个 + 新增 19 个);TypeScript、Vite 生产构建与 CSS/SVG 产物检查通过。
29
+ - 新增测试覆盖:日期范围限制/预设/清空、数字中间态/精度/越界/空值/IME、远程查询与跨结果选中、树键盘与禁选/父子独立、表格跨页选择/禁选/展开/独立详情、分页意图、背景单一主题根、布局切换保留草稿、媒体选择分离、分层 Escape 与焦点归还。
30
+ - Chromium 生产构建入口(本地 `vite preview`):三主题 × 五展台(场景背景、多侧栏、复杂表单、数据表、媒体)× 390/400/520/880/1600px 共 75 组。document、主工作区和外壳均无意外横向溢出,页面运行时错误为零。表格允许局部横向滚动。
31
+ - 三主题分别验证:侧栏折叠与布局切换保留正文、背景纹理开关、窄窗 Drawer 与 Dialog、选择保留跨页键且跳过禁选、失败保留旧行、媒体版本选择、媒体查看器各宽度、嵌套弹窗实际可点击、Escape 逐层退出、焦点返回原卡片。
32
+ - 400px 三主题真实键盘:数字中间态/错误/提交/步进,日期自定义与清空,远程候选方向键选择及标签保留,树父子独立勾选,加载禁止选择旧候选、禁用输入,候选浮层不超出视口。
33
+ - 三主题 × 五展台共 15 组:1040px 视口下 CSS `zoom:2` 无横向溢出,主要输入/关闭操作可达;另验 520px 有效宽度的媒体查询重排和系统减少动态。此为缩放与重排证据,不冒充浏览器菜单 200% 或原生 WebView 结果。
34
+ - `git diff --check` 通过。包清单检查确认包含新增源码/CSS/文档,未包含工作区私有目录或浏览器产物。
35
+ - 从干净提交 `7bf45ef` 导出源码并 `npm pack`,在仓库外的 React 19/Vite 8 项目安装该 tarball;9 个新增组件及 DataTable/Pagination、主题子入口、CSS、Logo SVG 的生产构建通过。测试包仍标记 0.4.0,仅为本地制品,未上传 registry。tarball SHA-256:`2658d2b8ef5da85b922380b4ecbf8afa0e9d2f95bbaedec5284373aa840a9499`。
36
+ 消费产物的真实浏览器中媒体查看器可打开/关闭,数字输入、唯一主题根和点阵正常;Logo SVG 返回 200。临时消费壳仅有未配置 favicon 的 404,没有组件运行时错误。
37
+
38
+ 真实浏览器验收等待 Radix 完成挂载、可点击性和异步焦点归还后判断;仅等待 `dialog` 可见并立即检查 `pointer-events` 会读到过渡状态。JSDOM 不验证叠层和裁剪,不能替代这部分浏览器证据。
39
+
40
+ 补充 issue #6:三主题 × 390/400/520/880/1600px 共 15 组监控展台,以及三主题 CSS 200% 缩放通过(累计 90 组宽度、18 组缩放)。验证了健康详情在顶部空间不足时转向下方、完整计数/口径、未知计数、键盘 Home/方向键/Escape/焦点归还;图表缺失断线、空/陈旧/失败/未知总量和原始数据表均通过。
41
+
42
+ 包含 #6 与审阅修正的干净提交 `2e08ebb` 再次打包,在同一仓库外消费项目安装全部 11 个新增组件及结构化时间轴并通过生产构建。浏览器验证详情中未知计数、Escape、折线两段路径和总量未知不计算占比。最终测试 tarball SHA-256:`12f6b5052b9569b9d8e1bd83a4c273e51b7636c99aab5953ae02d12af490da75`,仍未上传 registry。
43
+
44
+ 审阅回归修正:全局禁用树不展开、移除/窄化侧栏后恢复焦点、数值 0 详情仍生成合法表格行、媒体卡片显式聚焦并播报加载/失败状态、Markdown 表格中的类型分隔符正确转义。侧栏窗口从 1600px 缩至 880px 的真实浏览器焦点归还另验通过。
45
+
46
+ ## 交付边界
47
+
48
+ - 日期输入复用浏览器原生日历;操作系统日历 UI、读屏软件、移动 WebView、触屏实机和完整视频解码/播放尚未验收。没有增加自绘日期日历或媒体播放引擎。
49
+ - 表格使用原生 table 加层级展开按钮,未实现可编辑 ARIA treegrid。大数据虚拟化、导出和服务端请求需要宿主保留。
50
+ - 本地截图在被 Git 忽略的 `output/playwright/`:`shell-desktop.png`、`media-400.png`、`forms-400.png`。页面可从 `npm run dev` 的 `#app-shell`、`#advanced-forms`、`#advanced-data`、`#media`、`#backgrounds` 复查。
51
+ - 可审阅截图:[桌面多栏](assets/application-shell.png)、[400px 媒体查看器](assets/media-viewer-mobile.png)。截图只作布局参考,交互证据来自上述真实 React 展台和浏览器检查。
52
+ - issues 的发布验收按 [RELEASING](RELEASING.md) 从干净提交打包、固定版本安装并回读 registry,不能将候选源码等同于 npm 能力;实际结果以对应版本发布记录为准。
@@ -0,0 +1,81 @@
1
+ # OrbitBackdrop · 轨道背景(0.6.0)
2
+
3
+ `OrbitBackdrop` 将授权移交的轨道动画作为通用装饰组件维护:固定深色星空衬底、420 个环节点、185 条曲线、80 个深度桶,以及发射箭头、光晕和透视关系。它适合登录、欢迎等入口区域;不包含产品文案、账号逻辑或网络请求。需求与移交记录见 [Issue #8](https://github.com/linhay/rhine-design/issues/8)。
4
+
5
+ **版本边界:**此组件自 `@linhey/rhine-design@0.6.0` 提供,0.5.0 及以前不包含它。采用前核对安装版本与 `components/index.ts`,固定精确版本并提交 lockfile。组件源于 [OrbitBackdrop.tsx](../components/OrbitBackdrop.tsx),绘制实现在 [orbitRenderer.ts](../components/orbitRenderer.ts);后者是内部实现,不作为公共 API 导入。
6
+
7
+ ## 使用与契约
8
+
9
+ ```tsx
10
+ import { Logo, OrbitBackdrop, Text } from '@linhey/rhine-design';
11
+
12
+ // 此示例要求 0.6.0 或以上,并放在现有主题根内。
13
+ export function WelcomeArtwork() {
14
+ return (
15
+ <OrbitBackdrop className="welcome-artwork" style={{ minHeight: 360 }}>
16
+ <Logo decorative />
17
+ <Text as="h1" variant="title">开始新的工作</Text>
18
+ <Text>从这里进入你的工作空间。</Text>
19
+ </OrbitBackdrop>
20
+ );
21
+ }
22
+ ```
23
+
24
+ | 输入 | 契约 |
25
+ | --- | --- |
26
+ | `HTMLAttributes<HTMLDivElement>` | 接收容器原生属性,如 `className`、`style`、`id`;宿主负责尺寸、位置和相邻内容布局 |
27
+ | `reducedMotion?: boolean` | `true` 加强减少动态偏好;`false` 或省略均不能覆盖系统、祖先或环境的停帧条件 |
28
+ | `children` | 放入 `.rhine-orbit-content` 内容层,可组合 Logo、标题、正文、表单、动作和页脚,也可用 Surface 分组;宿主 class 控制内容布局,避免遮挡主要艺术或暂停控件 |
29
+
30
+ 组件持有绘制配方、内部类名、样式与暂停状态。宿主不复制 Canvas 实现,不另写同用途动画,不通过覆盖内部样式重建其视觉。没有速度、节点数量、业务进度或主题配色参数;需要新能力时先在设计系统中补契约与展台。
31
+
32
+ Canvas 绝对定位在内容层下方。内容层为直接置于星空上的文字提供浅色前景,普通 Text 与非 icon Logo 继承当前前景,muted Text 沿当前前景降低透明度;不修改宿主颜色 tokens,也不新建或嵌套 `ThemeProvider`。Surface、Notice 等有底色的组件继续使用自己的语义前景,表单与按钮保留宿主主题的前景 / 背景组合。默认内置 Rhine `Button`,在独立控件区域提供“暂停 / 继续”的明确操作。Canvas 为 `aria-hidden` 纯装饰,不接收键盘焦点,不提供进度或业务状态。有效信息仍由普通 HTML 内容表达;动画暂停、减少动态或 Canvas 不可用均不影响内容与业务操作。
33
+
34
+ ## 动效生命周期
35
+
36
+ 下列任一条件成立时停止逐帧调度,保留静态画面:
37
+
38
+ - 用户主动暂停;
39
+ - 系统 `prefers-reduced-motion: reduce`,或 `reducedMotion` 为 `true`;
40
+ - 祖先的 `data-rhine-motion="reduced"` 偏好生效(内层跟随系统不覆盖外层减少动态);
41
+ - 当前窗口宽度不超过 760px;
42
+ - `document.hidden`、组件离屏或可用绘制尺寸为零。
43
+
44
+ “暂停 / 继续”使用随当前动作变化的按钮名称,不同时声明 `aria-pressed` 切换语义。“继续”只解除用户主动暂停,不越过其他停帧条件。恢复时沿冻结的动画时间继续,不累计隐藏期间的时间,也不追赶错过的帧。偏好或可见性改变时即时重新判断;窗口调整会以当前冻结时间重绘静态画面。设备像素比上限为 2,卸载清理 rAF、监听器和 observers,离开页面不会继续后台绘制。
45
+
46
+ Canvas 不可用时保留静态艺术 fallback 与 `children`。此降级不表示浏览器或页面业务失败,也不以加载提示掩盖缺失的装饰能力。
47
+
48
+ ## 主题与可读性
49
+
50
+ 轨道采用同一固定深色美术配方;切换 Rhine、Arknights 或 Neo Brutalism 时保留动画构图。艺术文字采用浅色前景,控件、语义容器、独立操作区与外框继续使用完整宿主主题 tokens;不能只改控件的前景而保留白色背景。直接叠加的提示和透明 quiet 操作继承当前内容前景;quiet 的有底色 hover / disabled 状态保持宿主配色,键盘焦点使用当前文字颜色的内描边。可按产品分组需要使用 Surface,不以它作为控件可读性的前提。宿主应提供足够的布局空间,避免正文与主要曲线重叠,也不能遮住暂停入口。
51
+
52
+ 轨道动画不替代 `Progress`、`Skeleton` 或 `Logo`。登录提交、校验失败、数据刷新不重播动画;动画时间不决定业务何时就绪。仅为重播装饰而更换 key 时,将 key 限于 `OrbitBackdrop`,输入状态由重播边界外的宿主持有,不能因重播重置表单或其他业务状态。
53
+
54
+ ## 真实组件展台与验收
55
+
56
+ 本地展台 `http://127.0.0.1:18309/#orbit` 复用公开组件,提供暂停 / 继续、局部重播、手动减少动态,以及系统和全局偏好继承。重播只重新挂载装饰组件,不重执行业务动作、不清空外层内容。此条目与 `/#motion` 的 12 组交互配方、`/#startup` 的启动编排分别维护。
57
+
58
+ 验收应覆盖以下行为;本节是验收要求,不代表浏览器检查已执行:
59
+
60
+ 1. 原动画的环节点、曲线、箭头、光晕与透视仍可辨识;采样不同时间的中间帧,不能只检查单张截图。
61
+ 2. 鼠标与键盘可暂停 / 继续;暂停时画面冻结,恢复不跳过冻结期间的时间。
62
+ 3. 系统、显式 prop、祖先偏好均可中断动画;将 `reducedMotion` 设为 `false` 不能覆盖系统减少动态。
63
+ 4. 检查 400 / 520 / 880 宽度、200% 缩放和三套主题,确认窄窗静态呈现、控件可见、焦点可读且无横向溢出。组合 TextField、主 / 次按钮及 Surface,检查输入文字、placeholder、默认 / hover / disabled 状态和容器内 Text 的前景与背景。
64
+ 5. 页面隐藏、离屏、零尺寸时停帧,恢复及 resize 行为一致;卸载无残留调度或监听。
65
+ 6. Canvas 不可用时仍显示静态艺术和内容;业务表单、请求与路由不依赖动画。
66
+
67
+ 宿主接入后仍需验证自己的页面布局与业务交互;单元测试、展台检查不等于宿主原生平台或完整辅助技术验收。
68
+
69
+ ### 2026-10-24 初始源码候选验证
70
+
71
+ `npm ci`、`npm run check` 通过:65 项测试(轨道新增 10 项)、TypeScript 类型检查、展台生产构建及 CSS / SVG 产物检查。轨道测试覆盖完整节点绘制、DPR 上限、暂停时间冻结、系统 / prop / 祖先偏好、隐藏 / 离屏 / 窄窗 / 零尺寸、resize、Strict Mode 清理、Canvas 失败降级和重播保焦点。逻辑绘制尺寸使用 CSS client size,避免 CSS zoom 后暂停或 resize 改变线宽;真实浏览器验证固定画幅在 zoom 1→2→1 及 resize 后静态像素保持一致。
72
+
73
+ 本地 Chromium 真实展台通过 19 项检查:跨时间像素采样可见轨道运动;Space 键暂停 / 继续;系统、显式及祖先减少动态与恢复;三主题 × 400 / 520 / 880 宽度的静态 / 播放和无横向溢出;200% CSS 缩放与局部重播。另验证真实滚动离屏后像素冻结,返回可见区域后继续。页面错误为 0。页面隐藏与卸载由单元测试覆盖,不宣称已验证真实业务入口或原生平台。
74
+
75
+ 0.6.0 发布审阅发现初始候选的局部前景 tokens 会污染嵌入控件;现已移除这组覆盖。非 icon Logo 使用默认写法并继承所在内容的前景,无需按艺术底色另设 `theme="dark"`。上述初始截图与 19 项浏览器证据不代替修正后的组合控件验证。
76
+
77
+ 合并 0.5.0 应用能力并准备 0.6.0 后,重新执行 `npm ci` 与 `npm run check`:16 个测试文件、136 项测试、TypeScript、展台构建及 CSS / SVG 产物检查全部通过。真实展台已加入 Surface 内的正文、提示、TextField 与主 / 次按钮,供发布时单独验证三主题可读性。
78
+
79
+ 仓库外生产构建验证进一步发现:动画帧可先于媒体 `change` 事件观察到减少动态,此时只停帧会留下过期的播放状态。帧检查现复用同一同步路径,更新按钮与状态并清空上一帧时间;不增加停帧后的轮询。新增该事件顺序与恢复不追赶的回归后,16 个测试文件、137 项测试(`--maxWorkers=2`)、类型检查及构建通过。
80
+
81
+ ![真实组件展台](assets/orbit-backdrop.png)
@@ -1,5 +1,7 @@
1
1
  # GitHub 与主流设计系统调研
2
2
 
3
+ 此页保留 2026-10-23 的初次调研记录。后续 issues #1–#6 已新增应用组件,并于 2026-10-24 完成 [Ant Design / MUI 逐项 API 与交互对照](ANTD_MUI_AUDIT.md);当前能力和明确保留差异以该清单及应用组件契约为准。
4
+
3
5
  查询日期:2026-10-23(本地日期)。星标来自当次 GitHub API,是关注度快照,不是质量或安全认证。许可证状态也需在实际复制代码时重新核对。
4
6
 
5
7
  | 项目 / skill | 星标 | 许可 | 本轮采用的原则 |
package/docs/THEMING.md CHANGED
@@ -102,3 +102,44 @@ export function App() {
102
102
  将 `<div className="rhine-theme" data-rhine-theme="arknights">` 替换为 `<ThemeProvider defaultTheme="arknights">`,删除额外主题 CSS 导入;原根节点的布局类、`id`、动效属性直接传给 Provider。需要动态切换时调用 `useTheme().setTheme()`。
103
103
 
104
104
  旧的 CSS-only 用法继续支持:先导入基础组件样式,再导入 `theme-arknights.css` 或 `theme-neo-brutalism.css`,在根节点设置属性。两种用法选择一种即可,不要为迁移再包一层主题根。
105
+
106
+ ## 场景背景(0.5.0)
107
+
108
+ `Background` 从组件主入口导出,复用当前主题,不生成主题根。使用 `roleTone` 选择场景;默认是 `content`。主题定义颜色和纹理,业务无需判断当前主题名称。展台 `#backgrounds` 只展示当前选中主题的六类场景;使用右上角主题选择器切换三套内置主题,背景随之同步更新。
109
+
110
+ | `roleTone` | 用途 | 默认纹理 | 底色 / 文字变量 |
111
+ | --- | --- | --- | --- |
112
+ | `canvas` | 页面、工作台底层 | 跟随主题:纸面无纹理、战术网格、橙趣点阵 | `--rhine-canvas-bg` / `--rhine-canvas-text` |
113
+ | `content` | 正文、阅读区 | 无 | `--rhine-content-bg` / `--rhine-content-text` |
114
+ | `sidebar` | 导航、侧栏 | 无 | `--rhine-sidebar-bg` / `--rhine-sidebar-text` |
115
+ | `surface` | 卡片、表单分区 | 无 | `--rhine-surface-bg` / `--rhine-surface-text` |
116
+ | `overlay` | 弹窗、浮层表面 | 无 | `--rhine-overlay-bg` / `--rhine-overlay-text` |
117
+ | `media` | 图片、视频画布 | 无 | `--rhine-media-bg` / `--rhine-media-text` |
118
+
119
+ 每类背景还有 `--rhine-{roleTone}-texture` 变量,仅用于 `Background` 的场景纹理。纹理尺寸使用 `--rhine-background-scale`。媒体底色默认引用已有 `--rhine-media-canvas`,保留中性深色及配套浅色文字;`Surface` / `Fieldset` 使用表面底色,Dialog / Drawer / Popover / Menu 使用浮层底色,模态遮罩使用独立的 `--rhine-backdrop-bg`。Tooltip 保留各主题的强调配色。
120
+
121
+ ```tsx
122
+ import { Background, Surface } from '@linhey/rhine-design';
123
+
124
+ <Background roleTone="canvas">
125
+ <Background roleTone="content">
126
+ <Surface>正文默认关闭纹理,卡片保持不透明。</Surface>
127
+ </Background>
128
+ </Background>
129
+
130
+ // 显式开启当前区域的主题纹理;纸面主题仍然没有纹理。
131
+ <Background roleTone="content" decoration="theme">概览区域</Background>
132
+
133
+ // 局部配色:同时选择能清楚阅读的文字色。
134
+ <Background appearance={{ color: '#e5ece3', textColor: '#242b28' }}>
135
+ 阅读区域
136
+ </Background>
137
+ ```
138
+
139
+ `decoration` 默认 `auto`,使用场景默认值;`theme` 显式使用主题纹理;`none` 强制移除纹理,包括 `appearance.texture`。`appearance` 可局部覆盖 `color`、`textColor`、`texture`、`textureSize`,优先于场景/主题默认值;省略项仍跟随主题,嵌套 `Background` 重置为自身场景,不继承外层局部覆盖。原生 `style` 保持最终 CSS 覆盖权。
140
+
141
+ 背景只负责当前元素的绘制,不添加内边距、固定高度、定位、裁剪、伪元素或鼠标拦截层。`overlay` 只是视觉表面,不创建对话框、遮罩或焦点管理;实际交互使用 Dialog / Drawer 等组件。媒体与局部文字配色不重写子组件自身的颜色变量;输入、按钮等仍使用完整主题样式。
142
+
143
+ 若需全主题配置,在**主题根**通过 CSS 变量覆盖对应场景的底色、文字与纹理;局部调整优先用 `appearance`。局部背景不会传递给挂在主题根的 Portal,浮层仍使用主题的浮层变量。
144
+
145
+ 兼容已有源码调用:`roleTone` 的原有三种值与显式 `theme` / `none` 均保留;省略 `decoration` 的正文及 `AppShell` 改为 `auto`,默认纯色。需要旧版正文纹理的调用方显式传入 `decoration="theme"`。侧栏显式传入 `theme` 现在也会开启纹理;默认仍关闭。以上能力自 0.5.0 提供,不属于 npm 0.4.0。
Binary file
Binary file
@@ -0,0 +1,75 @@
1
+ # DataTable / Pagination 对标核对
2
+
3
+ 核对日期:2026-10-24。范围:issues #1–#6 的 DataTable 与 Pagination 扩展。以下是 API 与行为核对,不是 Ant Design 或 MUI 的兼容实现;本页扩展自 0.5.0 提供。
4
+
5
+ ## 官方依据
6
+
7
+ - [Ant Design Table API](https://ant.design/components/table/#api):受控排序、选择、展开与固定列;重点为 `selectedRowKeys`、`preserveSelectedRowKeys`、`type`、`hideSelectAll`、`checkStrictly`、`rowExpandable`、`rowScope`。
8
+ - [Ant Design Pagination API](https://ant.design/components/pagination/#api):受控页码/页大小、禁用、快速跳页与总量。
9
+ - [MUI Table](https://mui.com/material-ui/react-table/):原生表格组合、滚动容器、固定表头、分页控件与焦点恢复。
10
+ - [MUI TablePagination API](https://mui.com/material-ui/api/table-pagination/):未知总量、独立页大小事件、首末页与 `disabled`。
11
+ - [MUI X row selection](https://mui.com/x/react-data-grid/row-selection/):受控选择、禁选、跨服务端页保留 key、仅可见行全选。
12
+ - [MUI X tree data](https://mui.com/x/react-data-grid/tree-data/) 与 [master-detail](https://mui.com/x/react-data-grid/master-detail/):树数据、受控详情展开及独立数据所有权。
13
+ - [MUI X sorting](https://mui.com/x/react-data-grid/sorting/) 与 [column pinning](https://mui.com/x/react-data-grid/column-pinning/):受控排序模型与左右固定列的布局约束。
14
+
15
+ ## API 与行为逐项判定
16
+
17
+ | 核对项 | Rhine API / 当前行为 | 判定与本次处理 |
18
+ | --- | --- | --- |
19
+ | 数据与事件所有权 | `rows`、`sort`、`onSortChange`;组件原样展示传入行 | 保留;只回传排序意图,不以本地排序/筛选替代服务端结果 |
20
+ | 多选与禁选 | `selection.keys/onChange/isDisabled` | 已有;只更改可见且可选 key,全选/取消全选均保留跨页及禁选 key |
21
+ | 单选 | `selection.mode='single'`,默认 `multiple` | 补齐;原生同名 radio,选择新行回传仅该 key,不提供全选;单选 keys 只读取第一项 |
22
+ | 不允许批量选择 | `selection.hideSelectAll` | 补齐;保留每行选择与列标题,隐藏全选入口 |
23
+ | 行点击与键盘 | checkbox/radio/button 原生 Tab、Space/Enter | 保留独立操作入口;行内链接、菜单不会隐式改变选择,不伪装 ARIA grid |
24
+ | 父子选择 | 树父、子独立 key | 保留;不推断未加载子树的选择状态,不自动级联 |
25
+ | 排序取消 | 可选 `onSortReset` 显示“清除排序”;原 `onSortChange(TableSort)` 不变 | 补齐显式取消;先将焦点送回排序列按钮(缺失时回到表格滚动区),再发送重置意图,避免按钮卸载丢焦点;宿主清空 `sort` 后才改变排序状态,保留既有升/降循环 |
26
+ | 排序可发现性 | `aria-sort`、文字表头与方向图标、下一方向 `title` | 已有状态语义,补齐下一动作提示;不靠箭头颜色表达方向 |
27
+ | 受控展开与禁展开 | `expansion.keys/onChange/getChildren/renderDetail/canExpand` | 修复:`canExpand=false` 也阻止陈旧 keys 渲染子行及详情,不能只隐藏按钮 |
28
+ | 详情关联 | 展开按钮 `aria-expanded/aria-controls`,详情命名 region | 修复:ID 基于 row key,不因服务端排序更换;数字 `0` 仍是有效详情 |
29
+ | 行标题语义 | `DataColumn.rowHeader` | 补齐可选 `th scope=row`;保持正文背景与固定列层叠,不被固定表头规则吸到顶部 |
30
+ | 多固定列 | `sticky='left'/'right'`、可选 `stickyOffset` | 修复默认多列重叠;按真实布局宽度累计偏移,ResizeObserver 响应尺寸变化,显式 offset 优先;测量使用 CSS 布局宽度,避免 CSS zoom 加倍偏移 |
31
+ | 固定表头与密度 | `stickyHeader/maxHeight/density` | 保留;表格区域内部滚动,操作仍有 44px 命中区 |
32
+ | 加载/失败/空态 | `loading/error/onRetry/emptyTitle` | 保留旧行并说明刷新/错误,初始空态与读取失败分开;禁用会提交新请求的排序/选择 |
33
+ | 页码与页大小 | 1-based `page`、`pageSize`、独立 `onPageChange/onPageSizeChange` | 保留;页大小变化不隐式请求另一页,由宿主原子更新查询条件 |
34
+ | 未知总量 | `total` 缺省,`hasNext` 控制下一页 | 保留;负值/非有限 total 也按未知处理,不把未知写为零;只有 `total=0` 表示零条 |
35
+ | 首页/末页 | `showFirstButton/showLastButton`,均默认 false | 补齐;未知总量的末页按钮禁用,避免捏造最后页 |
36
+ | 全局禁用与多个分页 | `disabled`、`label`(默认“分页”) | 补齐;禁用可与加载分离;不同表格可以提供不同 navigation 名称 |
37
+ | 总量缩小越界 | 显式标注当前页超出总页数;上一页返回已知末页 | 修复;不静默伪装当前行属于另一页,不在 render/effect 自动请求修正 |
38
+ | 分页焦点 | 当当前 action 因页边界禁用时移至相邻可用 action | 补齐;没有可用 action 时不强行移动,外部已获取焦点时不抢回;页码摘要提供 status |
39
+
40
+ ## 有意保留的差异
41
+
42
+ 本库保持原生表格和受控服务端数据边界。AntD 的内置筛选、本地比较器、父子级联、单元格编辑、汇总/合并表头、拖列与虚拟化,以及 MUI X 的网格单元格导航、include/exclude 大数据选择模型、分组聚合,不在本轮 issue 的组件契约内。需要大量数据时宿主提供分页结果;没有自动拉全量模式。树行用明确层级文字与展开按钮,不宣称实现 `treegrid` 的完整键盘模型。
43
+
44
+ 分页为紧凑的服务端前后页控件,补充可选首末页;没有页码枚举、快速跳页或“每页全部”,也不复制两个框架的页码基准差异。Rhine 使用 1-based;适配 MUI TablePagination 的 0-based 状态时由宿主转换。
45
+
46
+ 固定列总宽仍须小于可用表格视口;窄屏由宿主减少固定列,不能用固定列覆盖所有可滚动内容。`stickyOffset` 仍可用于宿主特殊布局。API 以本库原名为准,不同时增加两套同义属性。
47
+
48
+ ## 验证
49
+
50
+ - `tests/DataParity.test.tsx`:12 项针对新增与修复边界的回归,包含单选、隐藏全选、排序取消及焦点、禁展开陈旧 key、详情 ID、行标题、多固定列测量、已知/未知末页、越界恢复、非法数值、禁用/地标及分页焦点。
51
+ - `npm test -- tests/DataParity.test.tsx tests/CommonComponents.test.tsx tests/Extensions.test.tsx`:40 项通过,保留跨页/禁选选择和旧排序/分页契约。
52
+ - `npm run typecheck`:通过。执行环境 Node 24。
53
+ - JSDOM 的列宽测试使用可变 `offsetWidth` 与 ResizeObserver 回调,证明偏移计算及重测。
54
+ - 独立真实组件浏览器 fixture:3 主题 × 400/520/880 共 9 个布局,两个左固定列间距差均为 0px、无正文横向溢出、右列不覆盖左列、固定表头保持顶部且行标题随正文垂直滚动;3 主题在 CSS zoom 200% / 520px 有效宽度下固定列仍相邻。原生 radio 方向键跳过禁选行,分页到末页后焦点回上一页,最终重载回归无 pageerror。该证据不是原生菜单缩放、屏幕阅读器或产品集成验收;真实展台总体验收另记。
55
+
56
+ ## 最小接入
57
+
58
+ ```tsx
59
+ <DataTable
60
+ caption="记录"
61
+ rows={rows}
62
+ rowKey={row => row.id}
63
+ columns={[
64
+ { key: 'name', header: '名称', render: row => row.name, rowHeader: true, sortable: true, sticky: 'left', width: 160 },
65
+ { key: 'status', header: '状态', render: row => row.status, sticky: 'left', width: 120 },
66
+ ]}
67
+ selection={{ mode: 'single', keys: selectedKeys, onChange: setSelectedKeys }}
68
+ sort={sort}
69
+ onSortChange={setSort}
70
+ onSortReset={() => setSort(undefined)}
71
+ />
72
+ <Pagination page={page} pageSize={pageSize} total={total} onPageChange={setPage} showFirstButton showLastButton label="记录分页" />
73
+ ```
74
+
75
+ 示例中的 setState 表示查询意图;实际宿主负责取消旧请求、请求排序/分页结果、更新状态以及处理失败。