@robot-admin/naive-ui-components 0.16.0 → 0.17.1

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 (225) hide show
  1. package/CHANGELOG.md +39 -0
  2. package/README.md +12 -9
  3. package/README_EN.md +12 -9
  4. package/dist/C_ActionBar.css +56 -48
  5. package/dist/C_ActionBar2.cjs +1 -1
  6. package/dist/C_ActionBar2.js +1 -1
  7. package/dist/C_AntV2.cjs +1 -1
  8. package/dist/C_AntV2.js +3 -3
  9. package/dist/C_Barcode.css +6 -6
  10. package/dist/C_Barcode2.cjs +1 -1
  11. package/dist/C_Barcode2.js +1 -1
  12. package/dist/C_Chat.css +269 -185
  13. package/dist/C_Chat2.cjs +1 -1
  14. package/dist/C_Chat2.js +1 -1
  15. package/dist/C_Code.css +26 -26
  16. package/dist/C_Code2.cjs +1 -1
  17. package/dist/C_Code2.js +1 -1
  18. package/dist/C_Draggable2.cjs +1 -1
  19. package/dist/C_Draggable2.js +1 -1
  20. package/dist/C_FilePreview.css +96 -57
  21. package/dist/C_FilePreview2.cjs +1 -1
  22. package/dist/C_FilePreview2.js +1 -1
  23. package/dist/C_Form.base.css +295 -277
  24. package/dist/C_Form.css +295 -277
  25. package/dist/C_Form.d.cts +2 -1
  26. package/dist/C_Form.d.ts +2 -1
  27. package/dist/C_FormModal.css +10 -10
  28. package/dist/C_FormModal2.cjs +1 -1
  29. package/dist/C_FormModal2.js +1 -1
  30. package/dist/C_FormSearch.css +67 -68
  31. package/dist/C_FormSearch.d.cts +2 -1
  32. package/dist/C_FormSearch.d.ts +2 -1
  33. package/dist/C_FormSearch2.cjs +1 -1
  34. package/dist/C_FormSearch2.js +1 -1
  35. package/dist/C_FullCalendar2.cjs +1 -1
  36. package/dist/C_FullCalendar2.js +1 -1
  37. package/dist/C_GlobalSearch.css +140 -118
  38. package/dist/C_GlobalSearch2.cjs +1 -1
  39. package/dist/C_GlobalSearch2.js +1 -1
  40. package/dist/C_ImageCropper.css +12 -10
  41. package/dist/C_ImageCropper2.cjs +1 -1
  42. package/dist/C_ImageCropper2.js +1 -1
  43. package/dist/C_Login.css +79 -79
  44. package/dist/C_Login2.cjs +1 -1
  45. package/dist/C_Login2.js +1 -1
  46. package/dist/C_Map.css +10 -10
  47. package/dist/C_Map2.cjs +1 -1
  48. package/dist/C_Map2.js +1 -1
  49. package/dist/C_OrgChart.css +28 -4
  50. package/dist/C_OrgChart2.cjs +1 -1
  51. package/dist/C_OrgChart2.js +1 -1
  52. package/dist/C_QRCode2.cjs +1 -1
  53. package/dist/C_QRCode2.js +1 -1
  54. package/dist/C_Signature.css +15 -15
  55. package/dist/C_Signature2.cjs +1 -1
  56. package/dist/C_Signature2.js +1 -1
  57. package/dist/C_SplitPane.cjs +1 -1
  58. package/dist/C_SplitPane.css +251 -109
  59. package/dist/C_SplitPane.js +1 -1
  60. package/dist/C_SplitPane2.cjs +1 -1
  61. package/dist/C_SplitPane2.js +1 -1
  62. package/dist/C_Table.base.css +491 -563
  63. package/dist/C_Table.cjs +1 -1
  64. package/dist/C_Table.css +491 -563
  65. package/dist/C_Table.d.cts +3 -2
  66. package/dist/C_Table.d.ts +4 -2
  67. package/dist/C_Table.js +1 -1
  68. package/dist/C_TagsView2.cjs +1 -1
  69. package/dist/C_TagsView2.js +1 -1
  70. package/dist/C_Transfer.css +93 -84
  71. package/dist/C_Transfer2.cjs +1 -1
  72. package/dist/C_Transfer2.js +1 -1
  73. package/dist/C_Tree.css +72 -125
  74. package/dist/C_Tree.d.cts +3 -2
  75. package/dist/C_Tree.d.ts +15 -2
  76. package/dist/C_Tree2.cjs +1 -1
  77. package/dist/C_Tree2.js +1 -1
  78. package/dist/C_Upload.css +5 -5
  79. package/dist/C_Upload2.cjs +1 -1
  80. package/dist/C_Upload2.js +1 -1
  81. package/dist/C_VideoPlayer2.cjs +4 -3
  82. package/dist/C_VideoPlayer2.js +4 -3
  83. package/dist/C_VtableGantt.css +29 -28
  84. package/dist/C_VtableGantt2.cjs +1 -1
  85. package/dist/C_VtableGantt2.js +1 -1
  86. package/dist/C_WaterFall.css +29 -29
  87. package/dist/C_WaterFall2.cjs +1 -1
  88. package/dist/C_WaterFall2.js +1 -1
  89. package/dist/C_WorkFlow2.cjs +1 -1
  90. package/dist/C_WorkFlow2.js +1 -1
  91. package/dist/Card.cjs +1 -1
  92. package/dist/Card.js +1 -1
  93. package/dist/Custom.cjs +1 -1
  94. package/dist/Custom.js +1 -1
  95. package/dist/Dynamic.cjs +1 -1
  96. package/dist/Dynamic.js +1 -1
  97. package/dist/Steps.cjs +1 -1
  98. package/dist/Steps.js +1 -1
  99. package/dist/Tabs.cjs +1 -1
  100. package/dist/Tabs.js +1 -1
  101. package/dist/constants.d.cts +2 -2
  102. package/dist/constants.d.ts +2 -2
  103. package/dist/constants2.d.cts +2 -2
  104. package/dist/constants2.d.ts +2 -2
  105. package/dist/constants3.d.cts +2 -2
  106. package/dist/constants3.d.ts +2 -2
  107. package/dist/constants4.d.cts +4 -4
  108. package/dist/constants4.d.ts +4 -4
  109. package/dist/constants5.d.cts +3 -7
  110. package/dist/constants5.d.ts +3 -7
  111. package/dist/data.d.cts +10 -10
  112. package/dist/data.d.ts +10 -10
  113. package/dist/density.cjs +1 -0
  114. package/dist/density.d.cts +15 -0
  115. package/dist/density.d.ts +15 -0
  116. package/dist/density.js +1 -0
  117. package/dist/helpers.cjs +1 -1
  118. package/dist/helpers.js +1 -1
  119. package/dist/index.cjs +1 -1
  120. package/dist/index.d.cts +3 -3
  121. package/dist/index.d.ts +5 -3
  122. package/dist/index.js +1 -1
  123. package/dist/index.vue.d.cts +5 -5
  124. package/dist/index.vue.d.ts +5 -5
  125. package/dist/index10.vue.d.cts +5 -5
  126. package/dist/index10.vue.d.ts +3 -3
  127. package/dist/index11.vue.d.cts +3 -3
  128. package/dist/index11.vue.d.ts +5 -5
  129. package/dist/index12.vue.d.cts +5 -5
  130. package/dist/index13.vue.d.ts +5 -5
  131. package/dist/index14.vue.d.cts +5 -5
  132. package/dist/index14.vue.d.ts +9 -9
  133. package/dist/index15.vue.d.cts +9 -9
  134. package/dist/index15.vue.d.ts +3 -3
  135. package/dist/index16.vue.d.cts +3 -3
  136. package/dist/index17.vue.d.ts +1 -1
  137. package/dist/index18.vue.d.cts +1 -1
  138. package/dist/index18.vue.d.ts +7 -7
  139. package/dist/index19.vue.d.cts +7 -7
  140. package/dist/index19.vue.d.ts +5 -5
  141. package/dist/index2.vue.d.cts +2 -2
  142. package/dist/index2.vue.d.ts +2 -2
  143. package/dist/index20.vue.d.cts +6 -2
  144. package/dist/index20.vue.d.ts +6 -2
  145. package/dist/index21.vue.d.cts +2 -2
  146. package/dist/index21.vue.d.ts +2 -2
  147. package/dist/index22.vue.d.cts +2 -2
  148. package/dist/index22.vue.d.ts +2 -2
  149. package/dist/index23.vue.d.cts +2 -2
  150. package/dist/index23.vue.d.ts +2 -2
  151. package/dist/index25.vue.d.cts +5 -5
  152. package/dist/index25.vue.d.ts +5 -5
  153. package/dist/index27.vue.d.cts +2 -2
  154. package/dist/index27.vue.d.ts +2 -2
  155. package/dist/index28.vue.d.cts +7 -3
  156. package/dist/index28.vue.d.ts +7 -3
  157. package/dist/index3.vue.d.cts +3 -3
  158. package/dist/index3.vue.d.ts +3 -3
  159. package/dist/index4.vue.d.cts +5 -5
  160. package/dist/index5.vue.d.ts +2 -2
  161. package/dist/index6.vue.d.cts +2 -2
  162. package/dist/index6.vue.d.ts +7 -4
  163. package/dist/index7.vue.d.cts +7 -4
  164. package/dist/index7.vue.d.ts +2 -2
  165. package/dist/index8.vue.d.cts +2 -2
  166. package/dist/index8.vue.d.ts +4 -6
  167. package/dist/index9.vue.d.cts +4 -6
  168. package/dist/index9.vue.d.ts +5 -5
  169. package/dist/mapUtils.d.cts +4 -4
  170. package/dist/mapUtils.d.ts +4 -4
  171. package/dist/presets.d.cts +4 -1
  172. package/dist/presets.d.ts +4 -1
  173. package/dist/style.css +1763 -1566
  174. package/dist/useCalendarEvents.d.cts +10 -9
  175. package/dist/useCalendarEvents.d.ts +10 -9
  176. package/dist/useCollapsePanel.d.cts +3 -3
  177. package/dist/useCollapsePanel.d.ts +3 -3
  178. package/dist/useCropperCore.d.cts +9 -9
  179. package/dist/useCropperCore.d.ts +9 -9
  180. package/dist/useDraggableLayout.d.cts +15 -13
  181. package/dist/useDraggableLayout.d.ts +15 -13
  182. package/dist/useDynamicFormState.d.cts +5 -2
  183. package/dist/useDynamicFormState.d.ts +5 -2
  184. package/dist/useEdgeInteraction.d.cts +3 -3
  185. package/dist/useEdgeInteraction.d.ts +3 -3
  186. package/dist/useFullscreen.d.cts +4 -0
  187. package/dist/useFullscreen.d.ts +4 -0
  188. package/dist/useGlobalSearch.d.cts +9 -4
  189. package/dist/useGlobalSearch.d.ts +9 -4
  190. package/dist/useInfiniteScroll.d.cts +4 -1
  191. package/dist/useInfiniteScroll.d.ts +4 -1
  192. package/dist/useQRCode.d.cts +3 -3
  193. package/dist/useQRCode.d.ts +3 -3
  194. package/dist/useSearchState.d.cts +8 -6
  195. package/dist/useSearchState.d.ts +8 -6
  196. package/dist/useSignatureHistory.d.cts +7 -7
  197. package/dist/useSignatureHistory.d.ts +7 -7
  198. package/dist/useSplitResize.d.cts +50 -61
  199. package/dist/useSplitResize.d.ts +50 -61
  200. package/dist/useTableQuery.cjs +3 -3
  201. package/dist/useTableQuery.d.cts +237 -13
  202. package/dist/useTableQuery.d.ts +237 -13
  203. package/dist/useTableQuery.js +3 -3
  204. package/dist/useTimeSelection.d.cts +2 -2
  205. package/dist/useTimeSelection.d.ts +2 -2
  206. package/dist/useWorkflowValidation.d.cts +3 -3
  207. package/dist/useWorkflowValidation.d.ts +3 -3
  208. package/dist/verification.d.cts +5 -5
  209. package/dist/verification.d.ts +5 -5
  210. package/docs/component-review-20261019.md +55 -0
  211. package/docs/guides/form-density.en.md +42 -0
  212. package/docs/guides/form-density.md +59 -0
  213. package/docs/guides/runtime-performance.md +38 -0
  214. package/docs/guides/split-pane.en.md +103 -0
  215. package/docs/guides/split-pane.md +126 -0
  216. package/docs/guides/table-density.md +87 -0
  217. package/docs/guides/transfer.md +11 -0
  218. package/docs/guides/tree.md +157 -0
  219. package/docs/guides/usage.en.md +2 -0
  220. package/docs/guides/usage.md +2 -0
  221. package/docs/runtime-review-20261019.md +41 -0
  222. package/docs/wl-ui-produce-coverage.md +62 -0
  223. package/package.json +4 -2
  224. package/dist/useTreeOperations.d.cts +0 -185
  225. package/dist/useTreeOperations.d.ts +0 -185
@@ -0,0 +1,55 @@
1
+ # 表格布局、性能与组件复查
2
+
3
+ 日期:2026-10-19。基线为 `v0.17.0`,本轮修改通过 Changeset 登记为后续补丁,不将源码合入描述为已发布新 npm 版本。
4
+
5
+ ## 展开列间距的原因与默认行为
6
+
7
+ 原样式给非末列统一加 `min-width: 80px !important`;普通列映射又为辅助列填入业务默认宽度,展开/选择增强器随后丢弃显式元数据。宽屏自动布局还会把空余空间分给所有定宽列,不能只改一个 CSS 数字。
8
+
9
+ 本轮将辅助列默认宽度收敛为选择 40、展开 40、序号 50。未声明宽度的普通非固定业务列保持自然弹性,并保留首选最小宽度;辅助列与弹性业务列共存时默认采用原生 fixed 布局。显式宽度、上限、固定位置、全局列宽和原生 table-layout 不被改写。所有业务列均显式定宽时保留原生余量分配语义。
10
+
11
+ 相同 1440px 独立浏览器场景中,0.17.0 的三个辅助列各约 142.56px;修改后为 40/40/50px。该场景含一列未指定宽度、最小宽度 220px 的名称列,同时测试普通与固定列布局。详细配置见[表格指南](./guides/table-density.md)。
12
+
13
+ ## 性能改进的可验证范围
14
+
15
+ | 位置 | 原问题 | 修改与验证 |
16
+ | -------------- | --------------------------------------------- | ----------------------------------------------------------------------------------- |
17
+ | 程序化跨页选择 | 每选择一个键都扫描本地数据 | 首次使用时建索引,重复查询复用;1 万行选择末尾 100 行,rowKey 调用 995,150 → 10,100 |
18
+ | 批量展开 | 每个新键线性找行,差集反复 includes | 惰性行键索引与 Set 差集;1 万键展开线性访问,不重复扫描 |
19
+ | 树行辅助遍历 | 深度递归可栈溢出 | 迭代 DFS,保留对象身份、顺序和循环/共享节点去重 |
20
+ | 表单修改检测 | 只判断是否修改仍比较所有字段 | 首个差异短路;嵌套 Map/Set 修改仍可触发外层计算 |
21
+ | 图和甘特实例 | 第三方大型对象被 Vue 深代理,同帧配置多次重建 | 原始实例浅引用,甘特主题/配置合并监听与重复初始化取消 |
22
+
23
+ 以上是算法调用量和生命周期验证,不表示整表 FPS 按同比例提升。2 万深、15 万宽的辅助遍历测试不代表 Naive 原生能渲染同等规模的 DOM;实际大表仍应使用分页、虚拟滚动、稳定且唯一的 rowKey。
24
+
25
+ ## 其他已修复问题
26
+
27
+ | 组件 | 修改 |
28
+ | ------------------------ | --------------------------------------------------------------------------------- |
29
+ | Login | 异步校验任务锁;等待后重新核对禁用、加载、表单快照、视图与卸载状态 |
30
+ | ImageCropper / Signature | 新读取、清空、替换与卸载使旧图片结果失效;裁剪导出在 scope 结束时结算并释放计时器 |
31
+ | WorkFlow | 清理旧定位延迟;卸载、替换画布、删除节点或重置后不打开旧配置 |
32
+ | TagsView | 批量关闭保留所有 affix 固定标签 |
33
+ | Chat | 历史前插保留阅读位置;同条数切换会话定位;末条消息更新仅在接近底部时跟随 |
34
+ | VideoPlayer | 常规 WebVTT 时间行正确解析;复用字幕请求,防切换乱序、关闭后重开和卸载后写入 |
35
+ | Barcode | 按真实 vendor 契约传入 options,非法内容触发 error 并支持恢复 |
36
+ | Draggable | 跨列表及克隆事件返回真实业务对象,避免把 DOM 或邻项当业务数据 |
37
+
38
+ ## 审查范围与后续空间
39
+
40
+ 后续进展:本节列出的列表窗口化、字幕索引、瀑布流图片批处理及 Code/QRCode 异步边界已在后续专项处理中完善,见[大列表与异步任务](./guides/runtime-performance.md)。下文保留本次表格复查时的记录,不能将两个阶段的测试数量混用。
41
+
42
+ 本轮逐项源码审读 51 个公开组件:表单/表格/树与分割、导航/标签/主题、消息/工作流、图表、媒体/编辑器、选择/拖拽、加载与其他工具组件。Map、OrgChart、FilePreview、Upload 在另一个活动工作区单独改进,本轮不覆盖或混入其未提交修改。公共 `_shared` 目录不计作业务组件。
43
+
44
+ 审读重点是高频计算、重复初始化、事件/observer/计时器释放、异步任务身份、公开事件和 vendor 真实接入。只有已修改路径及明确场景有新增针对性回归,不能将源码审读等同于所有组件、浏览器、第三方引擎都做了压测。
45
+
46
+ 仍有专项空间:WaterFall 图片布局批处理与窗口化、Chat/Transfer/GlobalSearch 等海量列表的窗口化、长字幕的时间索引、媒体运行时配置切换与大文档编辑性能。现有普通 DOM 列表并非无限数据容器;应按实际数据量和耗时/内存证据推进,不为了统一形式给所有组件加入自建虚拟滚动和更多开关。
47
+
48
+ 次要异步状态仍可进一步完善:Code 快速切换语言时 loading 尚无独立请求代次;QRCode 的旧 Logo 图像请求虽不会提交过期结果,底层网络加载本身没有主动取消。这些没有作为本轮已修复项。
49
+
50
+ ## 本轮实际校验
51
+
52
+ - 完整 `bun run verify` 通过:282 项单元、173 项真实组件挂载,以及 TypeScript、Vue/组件/消费者声明、lint、构建、ESM/CJS 与 Node16/NodeNext 打包消费者契约检查。
53
+ - 包与四个轻量入口的体积预算通过,未放宽预算;消费者契约复用本机安装的依赖版本,没有宣称重新从公开 registry 安装了尚未发布的补丁。
54
+ - 隔离浏览器以 1440/720/420px、明暗主题和三种密度组合运行 18 组场景、36 个表格实例,核对实际辅助列宽、表头/表体对齐、业务最小宽度、展开/收起、真实选择和页面错误。对比基线使用已发布 0.17.0 的实际产物。
55
+ - 本轮没有运行真实业务后端、没有给所有第三方引擎做性能压测,也没有以 Chromium 结果替代其他浏览器/平台验收。
@@ -0,0 +1,42 @@
1
+ # Form and search density
2
+
3
+ `C_Form`, `C_FormSearch`, and `C_Table` share `config.density`. Reuse a reactive value to align fields, action buttons, and spacing throughout a page.
4
+
5
+ ```vue
6
+ <C_FormSearch v-model="query" :form-item-list="filters" :config="{ density }" />
7
+ <C_Table :columns="columns" :data="rows" :config="{ density }" />
8
+ <C_Form v-model="model" :options="fields" :config="{ density }" />
9
+ ```
10
+
11
+ ```ts
12
+ import { ref } from 'vue'
13
+ import type { ComponentDensity } from '@robot-admin/naive-ui-components/C_Form'
14
+
15
+ const density = ref<ComponentDensity>('compact')
16
+ ```
17
+
18
+ | Density | Field and button size | Layout gap | Card padding | Form feedback minimum |
19
+ | ------------- | --------------------- | ---------- | ------------ | --------------------- |
20
+ | `default` | `medium` | 16px | 24px | 24px |
21
+ | `compact` | `small` | 8px | 12px | 12px |
22
+ | `comfortable` | `large` | 20px | 28px | 28px |
23
+
24
+ Validation feedback can grow beyond its minimum height. Changing density preserves form values, search drafts, expanded filters, and card collapse state. Each instance owns its density.
25
+
26
+ Omitting `density` retains existing spacing and the default `medium` size. Explicit `C_Form` `config.size`, `C_FormSearch` `size`, field `attrs.size`, and individual layout gaps take precedence over the preset.
27
+
28
+ Existing native `size` passthrough on `C_Form` retains its final-override priority and synchronizes fields and buttons. Prefer `config` for new integrations.
29
+
30
+ ```ts
31
+ const config = { density: 'compact', grid: { xGap: 12 } } as const
32
+ const fields = [
33
+ { type: 'input', prop: 'name' },
34
+ { type: 'select', prop: 'owner', attrs: { size: 'large' }, children: [] },
35
+ ]
36
+ ```
37
+
38
+ All eight form layouts support density: default, inline, grid, card, tabs, steps, dynamic, and custom. Naive UI step indicators support only `small` and `medium`, so comfortable step indicators use `medium` while fields and action buttons use `large`. Custom renderers and business slots own their styling; controls with a different size contract, such as `Rate`, retain that contract.
39
+
40
+ Density presets are plain data and preserve lazy loading of layouts and fields.
41
+
42
+ `C_FormModal` applies `config.density` to both its form and footer buttons and inherits application form density. Without density it preserves its historical `small` field default. Table editor modals inherit table density as well.
@@ -0,0 +1,59 @@
1
+ # 表单与搜索密度
2
+
3
+ `C_Form`、`C_FormSearch` 和 `C_Table` 使用同一项 `config.density`。同一个页面共享一个值即可同步字段、操作按钮和布局留白,不需要逐项传尺寸。
4
+
5
+ ```vue
6
+ <C_FormSearch v-model="query" :form-item-list="filters" :config="{ density }" />
7
+ <C_Table :columns="columns" :data="rows" :config="{ density }" />
8
+ <C_Form v-model="model" :options="fields" :config="{ density }" />
9
+ ```
10
+
11
+ ```ts
12
+ import { ref } from 'vue'
13
+ import type { ComponentDensity } from '@robot-admin/naive-ui-components/C_Form'
14
+
15
+ const density = ref<ComponentDensity>('compact')
16
+ ```
17
+
18
+ | 密度 | 字段与操作按钮 | 布局间距 | 卡片留白 | 表单反馈预留高度 |
19
+ | ------------- | -------------- | -------- | -------- | ---------------- |
20
+ | `default` | `medium` | 16px | 24px | 24px |
21
+ | `compact` | `small` | 8px | 12px | 12px |
22
+ | `comfortable` | `large` | 20px | 28px | 28px |
23
+
24
+ 反馈预留高度是最小值,校验错误可自然撑开。密度支持响应式切换,切换不会清空表单值、搜索草稿、折叠条件或分组展开状态;不同实例可以使用不同密度。
25
+
26
+ ## 保留明确覆盖
27
+
28
+ 已有项目未配置 `density` 时保留原来的间距和默认 `medium` 尺寸。显式配置的控件尺寸、字段尺寸和布局间距继续优先,不需要迁移旧用法。
29
+
30
+ 已有 `C_Form` 原生 `size` 透传继续按原有末尾覆盖顺序生效,并同步字段与操作按钮;新接入推荐统一使用 `config`。
31
+
32
+ ```ts
33
+ // 布局紧凑,只有指定字段保持较大尺寸。
34
+ const formConfig = { density: 'compact', grid: { xGap: 12 } } as const
35
+ const fields = [
36
+ { type: 'input', prop: 'name' },
37
+ { type: 'select', prop: 'owner', attrs: { size: 'large' }, children: [] },
38
+ ]
39
+
40
+ // Form: config.size 优先于 density 推导的尺寸。
41
+ const largeFields = { density: 'compact', size: 'large' } as const
42
+ ```
43
+
44
+ `C_FormSearch` 的原 `size` 属性也保留优先级:
45
+
46
+ ```vue
47
+ <C_FormSearch
48
+ v-model="query"
49
+ :form-item-list="filters"
50
+ :config="{ density: 'compact' }"
51
+ size="large"
52
+ />
53
+ ```
54
+
55
+ `C_Form` 的默认、内联、网格、卡片、标签页、步骤、动态和自定义布局均支持密度。步骤指示器只支持 Naive UI 原生的 `small`/`medium`;`comfortable` 下指示器使用 `medium`,字段和操作按钮使用 `large`。自定义渲染器和业务插槽由使用侧控制自身样式;密度不会强改业务内容或 `Rate` 等使用不同尺寸协议的组件。
56
+
57
+ 卡片、网格等布局仍按需加载。密度预设仅为纯数据,不引入额外 UI 依赖。
58
+
59
+ `C_FormModal` 的 `config.density` 同步控制表单与页脚按钮,也继承应用级表单密度;未配置密度时保留弹窗原有 `small` 字段默认值。表格编辑弹窗也会继承表格密度。
@@ -0,0 +1,38 @@
1
+ # 大列表与异步任务
2
+
3
+ 组件保持按需导入和现有事件契约。以下优化默认生效;普通接入无需配置虚拟列表引擎、分页游标或滚动状态。
4
+
5
+ ## 自动减少列表 DOM
6
+
7
+ | 组件 | 生效条件 | 保留的语义 |
8
+ | ---------------- | ---------------------------------- | ------------------------------------------------------------ |
9
+ | `C_Transfer` | 左右面板分别按筛选后项数,100 项起 | 完整数据筛选、全选、禁用项、移动顺序、v-model |
10
+ | `C_Chat` | 消息 200 条起;联系人 100 条起 | 图片、文件、系统消息、重发、联系人事件;实际测量变高行 |
11
+ | `C_GlobalSearch` | 搜索结果列表 | 完整匹配结果、上下键跨视口定位、Enter 选择、输入法与历史记录 |
12
+
13
+ ```vue
14
+ <C_Transfer v-model="selectedKeys" :data="people" filterable />
15
+ <C_Chat :messages="messages" :contacts="contacts" @send="sendMessage" />
16
+ <C_GlobalSearch :options="searchOptions" />
17
+ ```
18
+
19
+ 窗口化复用 `vueuc` 的公开 `VVirtualList`,兼容本包声明的 Naive UI 2.35;不依赖 Naive 内部导入,也不提高 Naive peer 下限。只减少渲染的 DOM,数据仍完整保存在内存中,搜索仍检查完整索引。
20
+
21
+ 穿梭框的三档行高和自定义方式见[穿梭框指南](./transfer.md)。聊天会实测文本、图片和文件行高度,无需调用方预先计算高度。业务 ID 应唯一、稳定;聊天容器应有确定高度,例如外层 `height: 600px`。
22
+
23
+ 若打印、DOM 集成或自定义穿梭框行高需要完整节点,可给 `C_Transfer` 或 `C_Chat` 设置 `:virtual-scroll="false"`。不要把此开关作为加载更多数据的接口;聊天加载历史仍通过 `load-more` 事件及 `loading-history` 状态接入。
24
+
25
+ ## 聊天滚动与输入
26
+
27
+ 打开或切换会话定位最新消息。阅读历史时,新增消息不抢滚动位置;前插历史保留阅读锚点。正在底部时,流式文本、迟到图片与面板高度变化继续跟随。跨越自动窗口化门槛也保持当前阅读状态。
28
+
29
+ 公开 `scrollToBottom()` 可用于主动跳到最新消息。输入法 Enter 确认候选不会提前发送;普通 Enter 保持发送行为。
30
+
31
+ ## 图片、字幕和异步状态
32
+
33
+ - 瀑布流将同帧图片测量合并为一次布局,参数变化和公开 `relayout()` 仍立即计算。替换图片来源后忽略旧测量,卸载时取消待执行帧。导出的 `useWaterFallLayout` 原有四参数用法保持同步行为。
34
+ - 字幕载入时编译时间索引;播放与前后跳转查询使用二分查找,保留重叠字幕按原文件顺序首匹配的语义。
35
+ - 代码语言加载只由当前请求更新 loading 和高亮。语言注册后主动更新高亮器引用,同一种语言异步加载完成也会重新着色。复制事件返回点击当时的文本。
36
+ - 二维码渲染及每次导出分别保存配置快照。新渲染取消旧 Logo 加载,导出相互独立;卸载取消所有任务并释放 Image 事件。组件销毁期间尚未完成的导出会以 `AbortError` 拒绝,调用方按普通异步错误处理即可。
37
+
38
+ 这些改进不代表列表、瀑布流和编辑器可以无限增加数据。大规模业务仍应按实际场景分段加载、回收历史,并测量内存、交互延迟与目标浏览器表现。
@@ -0,0 +1,103 @@
1
+ # Split panes and multiple-table workspaces
2
+
3
+ `C_SplitPane` divides a container horizontally (left/right) or vertically (top/bottom). Nest the same component to build tree/list, master/detail and three-table layouts. Slots render directly, so resizing does not recreate child components or replace their refs.
4
+
5
+ ## Minimal configuration
6
+
7
+ ```vue
8
+ <script setup lang="ts">
9
+ import { ref } from 'vue'
10
+ import { C_SplitPane } from '@robot-admin/naive-ui-components/C_SplitPane'
11
+ import '@robot-admin/naive-ui-components/C_SplitPane/style.css'
12
+ const size = ref(30)
13
+ </script>
14
+
15
+ <template>
16
+ <div class="workspace">
17
+ <C_SplitPane
18
+ v-model:size="size"
19
+ :min-first-size="240"
20
+ :min-second-size="320"
21
+ aria-label="Departments"
22
+ >
23
+ <template #first><DepartmentTree /></template>
24
+ <template #second><OrderList /></template>
25
+ </C_SplitPane>
26
+ </div>
27
+ </template>
28
+
29
+ <style scoped>
30
+ .workspace {
31
+ height: 100%;
32
+ min-height: 0;
33
+ min-width: 0;
34
+ }
35
+ </style>
36
+ ```
37
+
38
+ Omit `size` for internal state; `defaultSize` is 50. Use `v-model:size` when the application owns layout preferences or persistence. The component does not access localStorage. Scope persisted state by account, tenant and page in the application.
39
+
40
+ `size`, `defaultSize`, `minSize`, `maxSize` and `step` use percentage points. `minFirstSize`, `minSecondSize` and `gutterSize` use pixels. Percentages divide the space **remaining after the gutter**. A collapsed pane has an actual zero basis, avoiding negative width or height calculations.
41
+
42
+ ## Nested tables
43
+
44
+ ```vue
45
+ <C_SplitPane v-model:size="masterSize" :min-first-size="280" :min-second-size="420">
46
+ <template #first="{ collapsed }"><OrderTable v-if="!collapsed" /></template>
47
+ <template #second>
48
+ <C_SplitPane v-model:size="detailSize" direction="vertical" :min-first-size="180" :min-second-size="180">
49
+ <template #first><MaterialDetails /></template>
50
+ <template #second><DeliveryDetails /></template>
51
+ </C_SplitPane>
52
+ </template>
53
+ </C_SplitPane>
54
+ ```
55
+
56
+ Each pane needs a complete, measurable height chain from the page through Tabs, cards and table wrappers. Set `min-height:0; min-width:0` on intermediate flex containers. `C_Table flex-height` fills that workspace and keeps table rows scrolling internally. A bare table `height:100%` cannot repair a missing parent height.
57
+
58
+ Pane content scrolls automatically. For a table workspace, stretch the slot root to `height:100%` and let the table own row scrolling. For a long workbench with fixed-height tables, let the relevant pane or page own vertical document scrolling. Avoid adding competing page scrollbars to every intermediate wrapper.
59
+
60
+ Both slots expose `{ size, collapsed }`. By default, collapse preserves mounted content and marks it `inert` / `aria-hidden`. Use `v-if="!collapsed"` to suspend expensive tables; keep selections, edits and column preferences outside that subtree when state must survive unmounting. Otherwise keep the table mounted and let its ResizeObserver handle visibility changes. Third-party tables requiring an explicit layout call should receive it through their own API after a Tab/dialog becomes visible.
61
+
62
+ Do not wire SplitPane resize events to table data queries or make the layout component depend on table instances.
63
+
64
+ ## Configuration and boundaries
65
+
66
+ | Prop | Unit / default | Meaning |
67
+ | ---------------------------------- | --------------- | ----------------------------------------------------------- |
68
+ | `size` | % / unset | Controlled first-pane share, accepted through `update:size` |
69
+ | `defaultSize` | % / 50 | Internal initial value and current reset target |
70
+ | `minSize / maxSize` | % / 0 / 100 | Allowed first-pane share; reversed bounds are normalized |
71
+ | `minFirstSize / minSecondSize` | px / 0 | Physical minimum width or height while expanded |
72
+ | `direction` | `horizontal` | `horizontal` for left/right; `vertical` for top/bottom |
73
+ | `gutterSize` | px / 6 | Divider space, minimum 4 |
74
+ | `step` | % / 2 | Arrow-key adjustment; Shift multiplies it by 10 |
75
+ | `collapsible / showCollapseButton` | true / true | Collapse availability and button visibility |
76
+ | `disabled` | false | Disables user interaction; exposed methods remain available |
77
+ | `ariaLabel` | accessible name | Name the primary pane / splitter |
78
+
79
+ Pixel constraints update with the container size and orientation. Percentage limits, pixel minima and keyboard steps are reactive. Explicit collapse bypasses expanded minima. If the container cannot satisfy both pixel minima, the available space is shared proportionally, within the percentage bounds. No negative dimensions or forced container overflow result. The application should choose a stacked or Tab layout when multiple tables no longer fit usefully.
80
+
81
+ Existing uncontrolled usage remains supported. Moving the gutter outside the percentage calculation preserves 50/50 layouts and corrects asymmetric layouts by a few pixels for a normal 6px divider.
82
+
83
+ ## Interaction
84
+
85
+ A fine divider line carries a centered capsule grip (80px long, 16px thick by default). Nearby collapse buttons appear on hover or keyboard focus and stay visible while collapsed. Borders, a restrained shadow and local accent feedback use the existing `--c-primary`, `--c-bg-card`, `--c-border` and `--c-text-3` theme tokens in both orientations.
86
+
87
+ The capsule itself accepts dragging without increasing the layout space reserved by `gutterSize`. Touch input gets a 24px grip thickness and permanently visible 28px buttons. Collapsed controls dock inside the container to avoid clipping. Inline SVG arrows require no remote icon request, and reduced-motion preferences disable transitions.
88
+
89
+ The [W3C APG Window Splitter pattern](https://www.w3.org/WAI/ARIA/apg/patterns/windowsplitter/) informs keyboard behavior and separator semantics. Use Left/Right for left/right layouts and Up/Down for top/bottom layouts. Home/End move to the current boundaries. Enter collapses the first pane or restores an already collapsed pane. Double-click toggles the first pane.
90
+
91
+ Pointer Events support mouse, pen and touch. Pointer cancellation, window blur, document hiding, disablement, direction changes and unmounting all dispose listeners and restore the previous body cursor / text selection styles. Nested splitters do not overwrite `document.onmousemove`.
92
+
93
+ The separator exposes orientation, its decimal value, responsive limits and a unique controlled pane ID. Collapse buttons expose their target and expanded state, show keyboard focus and remain visible for touch input.
94
+
95
+ `resize(first, second)` reports actual displayed proportions; `update:size` requests a controlled-state change. `drag-start/drag-end` report gesture boundaries. `collapse/expand` report actual state transitions. Exposed methods: `setSize`, `resetSize`, `collapse`, `expand`, `toggle`, `getPanelInfo`.
96
+
97
+ ## Production-reference comparison
98
+
99
+ The `wl-ui-produce` comparison was read-only: no component migration or backend write was performed. Three Vue files use `jh-drag-row`; no current `src` call uses `jh-drag-col`. Left/right tree examples come from its local layout standard 14. The installed common-core source/declarations are partly stripped, so they cannot prove every threshold documented in that standard.
100
+
101
+ Both implementations are movable pane separators. The production master/detail wrapper supplies `top-height=390/470` pixel initial values; the local standard shows `left-width=240`. This library deliberately retains percentage initial values and adds physical minima, rather than introducing multiple pixel aliases. Convert an exact pixel initial value at the application boundary when needed.
102
+
103
+ `c_steelListPanel` owns its ResizeObserver and table layout call. `c_steelWorkstation` also coordinates forms, streams, Tabs and business data. SplitPane supplies geometry; it does not replace those domain responsibilities or establish equivalence with Element Plus / BaseTable / AG Grid. See the [coverage assessment](../wl-ui-produce-coverage.md) for the wider limitations.
@@ -0,0 +1,126 @@
1
+ # 分割面板与复杂多表布局
2
+
3
+ `C_SplitPane` 是布局组件:`horizontal` 左右分栏,`vertical` 上下分栏,按相同方式嵌套即可组合左树右表、主从表、三表及工作台。两个 slot 都直接渲染,组件引用、表格选择和未保存编辑不会因拖动重建。
4
+
5
+ ## 最少配置
6
+
7
+ ```vue
8
+ <script setup lang="ts">
9
+ import { ref } from 'vue'
10
+ import { C_SplitPane } from '@robot-admin/naive-ui-components/C_SplitPane'
11
+ import '@robot-admin/naive-ui-components/C_SplitPane/style.css'
12
+
13
+ const size = ref(30)
14
+ </script>
15
+
16
+ <template>
17
+ <div class="workbench">
18
+ <C_SplitPane
19
+ v-model:size="size"
20
+ :min-first-size="240"
21
+ :min-second-size="320"
22
+ >
23
+ <template #first><DepartmentTree /></template>
24
+ <template #second><OrderList /></template>
25
+ </C_SplitPane>
26
+ </div>
27
+ </template>
28
+
29
+ <style scoped>
30
+ .workbench {
31
+ height: 100%;
32
+ min-height: 0;
33
+ min-width: 0;
34
+ }
35
+ </style>
36
+ ```
37
+
38
+ 省略 `size` 即使用内部状态,`defaultSize` 默认 50%。`v-model:size` 由应用持有当前百分比,适合与页面路由、用户偏好或业务布局状态组合。组件不直接访问 localStorage,避免多账号、多租户、页面之间污染。
39
+
40
+ `size/defaultSize/minSize/maxSize/step` 始终使用百分比;`minFirstSize/minSecondSize/gutterSize` 使用 px。百分比按**扣除手柄后的可用空间**计算,两个面板总比例为 100,手柄不再从两侧各扣半宽,折叠面板为合法的零宽/零高。
41
+
42
+ ## 三表与树表组合
43
+
44
+ ```vue
45
+ <C_SplitPane v-model:size="treeSize" :min-first-size="220" :min-second-size="520">
46
+ <template #first><DepartmentTree /></template>
47
+ <template #second>
48
+ <C_SplitPane
49
+ v-model:size="masterSize"
50
+ direction="vertical"
51
+ :min-first-size="220"
52
+ :min-second-size="180"
53
+ >
54
+ <template #first="{ collapsed }">
55
+ <OrderTable v-if="!collapsed" />
56
+ </template>
57
+ <template #second>
58
+ <C_SplitPane :default-size="50" :min-first-size="220" :min-second-size="220">
59
+ <template #first><OrderDetails /></template>
60
+ <template #second><DeliveryDetails /></template>
61
+ </C_SplitPane>
62
+ </template>
63
+ </C_SplitPane>
64
+ </template>
65
+ </C_SplitPane>
66
+ ```
67
+
68
+ 每个 `C_SplitPane` 负责自己的约束、键盘焦点和滚动容器。页根、Tabs 内容、slot 内的卡片与表格父容器都需要可计算的高度;使用 flex 布局时,中间层设置 `min-height: 0; min-width: 0`。仅设置表格 `height:100%` 无法补齐上级容器缺失的高度。
69
+
70
+ 两种滚动方式按内容选用:
71
+
72
+ - 表格工作区:slot 根节点撑满面板,`C_Table flex-height` 在该高度内滚动;工具栏、搜索区与分页占用工作区自身的空间。不要给每一层卡片重复添加页面滚动。
73
+ - 文档或纵向长工作台:保持面板内容的默认 `overflow:auto`,固定高度表格在内部滚动,面板负责其余纵向内容。
74
+
75
+ `#first/#second` 都提供 `{ size, collapsed }`。默认折叠只隐藏布局并设置 `inert/aria-hidden`,保留组件状态;大型表格可选择 `v-if="!collapsed"` 释放观察器与渲染工作,但卸载也会丢失未外置的选择、列状态与编辑状态。需要保留状态时保持挂载,通过表格自身的 ResizeObserver 感知展开;第三方表格要求显式 `doLayout` 时,在对应 Tab/dialog 激活后调用其公开布局方法。
76
+
77
+ 不要在 SplitPane 内注入表格实例,也不要把 `@resize` 绑定成每个表格查询/数据刷新的触发器。拖动只改变容器尺寸,不应请求业务数据。
78
+
79
+ ## 约束与边界
80
+
81
+ | 配置 | 单位 / 默认 | 含义 |
82
+ | ---------------------------------- | ------------ | -------------------------------------------------------- |
83
+ | `size` / `v-model:size` | % / 未设置 | 受控首面板比例;父组件接受 `update:size` 后生效 |
84
+ | `defaultSize` | % / 50 | 非受控初值;`resetSize()` 也使用当前默认值 |
85
+ | `minSize / maxSize` | % / 0 / 100 | 首面板可拖动比例范围;反向配置会自动排序 |
86
+ | `minFirstSize / minSecondSize` | px / 0 | 展开时各面板的实际宽度或高度下限 |
87
+ | `direction` | `horizontal` | 左右;`vertical` 为上下 |
88
+ | `gutterSize` | px / 6 | 手柄占用空间,最小 4 |
89
+ | `step` | % / 2 | 方向键每次调整量 |
90
+ | `collapsible / showCollapseButton` | true / true | 是否允许折叠、是否显示折叠按钮 |
91
+ | `disabled` | false | 禁止用户拖动、键盘调整及折叠按钮;公开方法仍可供应用控制 |
92
+
93
+ 像素约束随容器 ResizeObserver 和方向变化重新计算;`minSize/maxSize/minFirstSize/minSecondSize/step` 动态修改后立即使用新值。显式折叠可越过展开时的最小尺寸。容器比两个像素下限之和更小时,按两者比例分配可用空间,再遵守百分比范围,避免负尺寸和溢出;这时应用应视实际业务切换单表/Tab 布局,而不是宣称小屏仍可完整容纳任意多表。
94
+
95
+ 已有非受控用法保持兼容。百分比在旧实现中包含整条手柄,现在按剩余空间分配,可消除边缘负尺寸;默认 6px 手柄下,50/50 布局不变,非对称布局只有几个像素的修正。
96
+
97
+ ## 交互与无障碍
98
+
99
+ 手柄采用细轨道与居中胶囊握柄,默认长 80px、厚 16px,保留三点拖动提示。悬停和键盘聚焦时,在握柄两侧显示折叠入口,并以局部描边和轻阴影提示当前状态;折叠后入口持续显示。横向、纵向使用相同视觉规则,主题颜色复用 `--c-primary / --c-bg-card / --c-border / --c-text-3`。
100
+
101
+ 胶囊是独立的实际拖动区域,其视觉厚度不会改变 `gutterSize` 占用的布局空间。触屏下握柄厚度增至 24px、折叠按钮增至 28px,并保持按钮常驻;折叠到边缘时控件向容器内部停靠,避免被裁切。箭头使用本地 SVG,不请求远程图标。
102
+
103
+ 键盘交互与 separator 语义参照 [W3C APG Window Splitter](https://www.w3.org/WAI/ARIA/apg/patterns/windowsplitter/)。可用 `aria-label="订单主表"` 设置面板对应的可访问名称。
104
+
105
+ - 拖动支持鼠标、触控笔和触屏 Pointer Events,不接管宿主的 `document.onmousemove`。
106
+ - 拖动结束、pointercancel、窗口失焦、页面隐藏、动态禁用、方向切换和卸载都会移除监听、恢复此前的光标与文本选择样式。
107
+ - 左右布局使用 Left/Right,上下布局使用 Up/Down;Shift 将 `step` 放大 10 倍,Home/End 到当前可用边界。
108
+ - Enter 折叠首面板,已折叠时还原;双击手柄折叠/展开首面板。按钮有明确的展开状态、目标面板、可见焦点和触屏常驻入口。
109
+ - `role="separator"` 提供 orientation、当前百分比、真实上下限和唯一的受控面板 ID。折叠内容不能通过 Tab 获取焦点。
110
+
111
+ `resize(first, second)` 表示实际显示比例变化,`update:size(size)` 用于受控状态更新;`drag-start/drag-end` 可记录拖动会话。`collapse/expand` 表示实际折叠状态变化。暴露 `setSize/resetSize/collapse/expand/toggle/getPanelInfo`,应用无需查找或操作内部 DOM。
112
+
113
+ ## 与 wl-ui-produce 的对应关系
114
+
115
+ 本轮只读对比 `wl-ui-produce` 的真实 `jh-drag-row` 调用(3 个 Vue 文件;当前 src 未发现 col 标签)、`@jhlc/common-core` 安装源码/声明以及本地布局规范 14,未修改该项目,也未更换其 BaseTable/AG Grid 或 Element Plus 技术栈。
116
+
117
+ | 生产项目证据 | C_SplitPane 对应能力 / 边界 |
118
+ | ---------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------ |
119
+ | 规范 14 的 `jh-drag-col` 左树右表示例、`leftWidth=240`(当前 src 无真实 col 调用) | 同类左右布局。这里保留百分比初值与双向绑定,新增各面板 px 最小值;**不提供** `leftWidth/rightWidth` 固定像素初值别名 |
120
+ | `c_steelMasterDetail` 使用 `jh-drag-row`,`top-height=390/470` | 同类上下主从布局,`direction="vertical"`;默认比例应按页面高度设计,精确 px 初值可由应用测量后换算,不把 px 值直接传给百分比 `defaultSize` |
121
+ | 本地规范 14:原生 slot、多层嵌套和完整高度链 | 直接渲染 slot;组件自身包含 min-height/min-width:0,页面和 Tabs 的外部高度链仍由应用保证 |
122
+ | `c_steelListPanel` 自己观察 panel 并调用 `table.doLayout` | 同样保持布局与表格职责分离;原生 C_Table 的 flexHeight 负责表内尺寸适配 |
123
+ | `c_steelWorkstation` 还有多 Tab 表单、流别/物料表和页面级纵向滚动 | 这是工作台业务组合;分割面板能提供尺寸布局,不能替代查询/编辑/主从关系/Tab 状态与流程管理 |
124
+ | 规范 FAQ 提及 common-core 可配置像素阈值 | 安装包部分源码/声明被裁剪,未据此推断其完整实际 API;本库的像素约束以自身实现和测试为准 |
125
+
126
+ 因此两者的分割手柄属于同一类机制;C_SplitPane 能作为复杂多表布局基础,但不能保证“任意业务场景零配置覆盖”。交叉冻结列、树表权限、主从联动、编辑提交、业务事务和超长工作台仍由各自组件与应用组合完成。
@@ -0,0 +1,87 @@
1
+ # 表格密度与模式切换
2
+
3
+ `C_Form`、`C_FormSearch` 和 `C_Table` 共用 `ComponentDensity`。普通页面只需共享一个状态:
4
+
5
+ ```vue
6
+ <script setup lang="ts">
7
+ import { ref } from 'vue'
8
+ import type { ComponentDensity } from '@robot-admin/naive-ui-components/C_Table'
9
+ const density = ref<ComponentDensity>('compact')
10
+ </script>
11
+
12
+ <template>
13
+ <C_FormSearch
14
+ v-model="query"
15
+ :form-item-list="searchFields"
16
+ :config="{ density }"
17
+ />
18
+ <C_Table
19
+ :data="rows"
20
+ :columns="columns"
21
+ :config="{ density, edit: 'cell', selection: true }"
22
+ />
23
+ </template>
24
+ ```
25
+
26
+ | density | 原生控件尺寸 | 用途 |
27
+ | ------------- | ------------ | ------------------------------ |
28
+ | `compact` | `small` | 高频操作、多表工作台、紧凑查询 |
29
+ | `default` | `medium` | 常规管理页面 |
30
+ | `comfortable` | `large` | 信息较少、强调可读性的录入页面 |
31
+
32
+ 密度同步表格行尺寸、编辑器、分页、工具栏按钮、批量按钮、内置编辑弹窗和组件内部留白。
33
+ `display.size`、`pagination.size`、`toolbar.actionBar`、列 `editProps.size` 仍可分别覆盖;原生表格 attrs 保持既有覆盖顺序。
34
+ 不传 `density` 保留旧表格尺寸和紧凑工具按钮。密度仅影响当前实例,不修改全局主题和相邻表格。
35
+
36
+ ## 编辑模式使用一个配置项
37
+
38
+ ```ts
39
+ const config = { density: 'compact', edit: 'row', pagination: false } as const
40
+ ```
41
+
42
+ | edit | 行为 |
43
+ | ------------------------- | -------------- |
44
+ | `false` / `'none'` / 不传 | 只读 |
45
+ | `true` / `'modal'` | 弹窗编辑 |
46
+ | `'row'` | 整行编辑 |
47
+ | `'cell'` | 单元格编辑 |
48
+ | `'both'` | 行与单元格编辑 |
49
+
50
+ 需要保存回调、标题或宽度时升级为对象,不增加额外开关:
51
+
52
+ ```ts
53
+ const config = {
54
+ density: 'compact',
55
+ edit: { mode: 'row', onSave: saveRow, onError: reportError },
56
+ selection: true,
57
+ pagination: { remote: true, total: 100, pageSize: 20 },
58
+ }
59
+ ```
60
+
61
+ 运行时修改密度保留草稿;修改编辑模式或关闭编辑会清理旧草稿。正在校验或保存的旧会话不能恢复草稿,旧结果也不会继续发出本地数据补丁。已经交给业务 `onSave` 的请求由业务自行取消或完成,组件不能撤销服务器写入。模式切换本身不会触发业务取消回调或自动保存。
62
+
63
+ 绑定 `crud` 且提供 `crud.save` 时,CRUD 的函数式 `actions.edit` 视为保存能力标记:点击铅笔按配置打开内置编辑器,确认后才通过 `crud.save` 保存一次。自定义打开方式显式放在 `config.actions.edit`;没有独立 `save` 的外部绑定仍保留原有函数行为。
64
+
65
+ 分页、树表、虚拟滚动、选择、导出继续使用各自的分组配置。它们是可组合能力,不设隐含开启多种行为的“万能模式”。
66
+
67
+ 多表分屏请参阅[分割面板](./split-pane.md);表单优先级与布局示例请参阅[表单密度](./form-density.md)。
68
+
69
+ ## 展开、序号和弹性业务列
70
+
71
+ 默认辅助列宽度:选择列 `40px`、展开列 `40px`、序号列 `50px`。普通未固定的业务列不再被统一填上 `width: 180`;未指定宽度时,它按首选最小宽度吸收容器余量。有辅助列和自然弹性业务列时,默认使用原生 `fixed` 表格布局,避免空余空间把展开与序号撑大:
72
+
73
+ ```ts
74
+ const columns: TableColumn<Order>[] = [
75
+ { type: 'selection' },
76
+ { type: 'expand' },
77
+ { type: 'index' },
78
+ { key: 'name', title: '订单名称', minWidth: 220 }, // 自然弹性列
79
+ { key: 'amount', title: '金额', width: 140 },
80
+ ]
81
+ ```
82
+
83
+ 不需要给每张表写辅助列 CSS。显式列 `width / minWidth / maxWidth / fixed / className / cellProps` 保持转发;`config.display.columnWidth`(包括全局配置中的显式 `180`)仍表示统一列宽。固定业务列继续使用可计算的数值默认宽度;原生 `table-layout` 属性可覆盖自动选择的布局。
84
+
85
+ 若所有业务列都显式指定宽度,且总宽小于容器,保留原生表格的剩余空间分配规则;这时声明的 `width` 不保证等于最后测量的像素。通常让名称或描述列保持弹性,比给所有列设宽更合适。虚拟横向滚动仍需按 Naive UI 的契约提供具体列宽。
86
+
87
+ 独立的列 `renderExpand` 直接转交原生表格;配置 `config.expand.onLoadData / renderContent` 后由组件的加载、失败重试和内容渲染器接管展开区。不要同时配置两套展开内容并依赖原生渲染器优先。自动横向滚动宽度按最终可见列计算,包含辅助列、动态选择列和操作列,不再额外追加固定留白。
@@ -0,0 +1,11 @@
1
+ # 穿梭框与大列表
2
+
3
+ ```vue
4
+ <C_Transfer v-model="selectedKeys" :data="people" filterable />
5
+ ```
6
+
7
+ 左右面板分别按搜索后的项数决定渲染方式:少于 100 项使用普通列表,100 项起复用 Naive UI 同样使用的官方 `vueuc/VVirtualList`,只挂载当前视口及相邻行。全选、禁用判断和移动顺序仍以完整列表为准;滚动到视口之外的选中项不会丢失。右侧保持 `modelValue` 的顺序,新增项按左侧数据顺序追加。
8
+
9
+ `size="small | medium | large"` 对应 28 / 34 / 40px 固定行高。继续通过既有 `--tf-height` 覆盖列表高度,例如 `style="--tf-height: 240px"`;无需为大列表额外设置高度或分页。
10
+
11
+ 若项目自行改变行高、需要打印全部项,或依赖完整列表 DOM,可显式设置 `:virtual-scroll="false"` 保留普通渲染。默认开启自动判断,常规接入无需配置。搜索仍检查全部数据;虚拟列表减少 DOM 与组件挂载量,不把筛选或数据存储变成无限容量服务。