@veltra/desktop 1.0.7 → 1.0.9

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 (247) hide show
  1. package/dist/components/action/action-group.vue.d.ts +1 -1
  2. package/dist/components/action/action.vue.d.ts +3 -3
  3. package/dist/components/action/style.js +3 -0
  4. package/dist/components/auto-complete/auto-complete.vue.d.ts +2 -2
  5. package/dist/components/auto-complete/style.js +5 -0
  6. package/dist/components/batch-edit/style.js +9 -0
  7. package/dist/components/breadcrumb/style2.css +0 -6
  8. package/dist/components/button/style.js +1 -0
  9. package/dist/components/cascade/cascade.js +15 -13
  10. package/dist/components/cascade/cascade.js.map +1 -1
  11. package/dist/components/cascade/cascade.vue.d.ts +3 -3
  12. package/dist/components/cascade/node.js.map +1 -1
  13. package/dist/components/cascade/style.js +7 -0
  14. package/dist/components/cascade/use-check.js +3 -2
  15. package/dist/components/cascade/use-check.js.map +1 -1
  16. package/dist/components/cascade/use-select.js +3 -3
  17. package/dist/components/cascade/use-select.js.map +1 -1
  18. package/dist/components/checkbox/style.js +1 -0
  19. package/dist/components/checkbox/style2.css +0 -8
  20. package/dist/components/checkbox-group/checkbox-group.vue.d.ts +2 -2
  21. package/dist/components/checkbox-group/style.js +1 -0
  22. package/dist/components/context-menu/style.js +1 -0
  23. package/dist/components/date-panel/date-panel.vue.d.ts +1 -1
  24. package/dist/components/date-picker/date-picker.js +9 -9
  25. package/dist/components/date-picker/date-picker.js.map +1 -1
  26. package/dist/components/date-picker/date-picker.vue.d.ts +2 -2
  27. package/dist/components/date-picker/style.js +3 -0
  28. package/dist/components/date-range-picker/date-range-picker.js +9 -9
  29. package/dist/components/date-range-picker/date-range-picker.js.map +1 -1
  30. package/dist/components/date-range-picker/date-range-picker.vue.d.ts +2 -2
  31. package/dist/components/date-range-picker/style.js +3 -0
  32. package/dist/components/dialog/style.js +2 -0
  33. package/dist/components/drawer/style.js +1 -0
  34. package/dist/components/drawer/style2.css +4 -16
  35. package/dist/components/empty/style.js +1 -0
  36. package/dist/components/expression-editor/style.js +6 -0
  37. package/dist/components/file-picker/file-picker.vue.d.ts +1 -1
  38. package/dist/components/file-picker/helper.js +19 -7
  39. package/dist/components/file-picker/helper.js.map +1 -1
  40. package/dist/components/file-viewer/file-viewer.js +294 -0
  41. package/dist/components/file-viewer/file-viewer.js.map +1 -0
  42. package/dist/components/file-viewer/file-viewer.vue.d.ts +42 -0
  43. package/dist/components/file-viewer/helper.js +185 -0
  44. package/dist/components/file-viewer/helper.js.map +1 -0
  45. package/dist/components/file-viewer/index.d.ts +1 -0
  46. package/dist/components/file-viewer/previewers/docx-previewer.js +76 -0
  47. package/dist/components/file-viewer/previewers/docx-previewer.js.map +1 -0
  48. package/dist/components/file-viewer/previewers/image-previewer.js +64 -0
  49. package/dist/components/file-viewer/previewers/image-previewer.js.map +1 -0
  50. package/dist/components/file-viewer/previewers/pdf-previewer.js +90 -0
  51. package/dist/components/file-viewer/previewers/pdf-previewer.js.map +1 -0
  52. package/dist/components/file-viewer/previewers/sheet-previewer.js +175 -0
  53. package/dist/components/file-viewer/previewers/sheet-previewer.js.map +1 -0
  54. package/dist/components/file-viewer/previewers/text-previewer.js +74 -0
  55. package/dist/components/file-viewer/previewers/text-previewer.js.map +1 -0
  56. package/dist/components/file-viewer/previewers/video-previewer.js +62 -0
  57. package/dist/components/file-viewer/previewers/video-previewer.js.map +1 -0
  58. package/dist/components/file-viewer/style.d.ts +1 -0
  59. package/dist/components/file-viewer/style.js +4 -0
  60. package/dist/components/file-viewer/style2.css +445 -0
  61. package/dist/components/float-button/style.js +1 -0
  62. package/dist/components/form/style.js +2 -0
  63. package/dist/components/form-item/style.js +1 -0
  64. package/dist/components/form-item/style2.css +2 -3
  65. package/dist/components/grid-input/grid-input.vue.d.ts +1 -1
  66. package/dist/components/index.d.ts +12 -9
  67. package/dist/components/input/input.vue.d.ts +2 -2
  68. package/dist/components/input/style.js +1 -0
  69. package/dist/components/layout/style.js +1 -0
  70. package/dist/components/list/style.js +1 -0
  71. package/dist/components/loading/style2.css +16 -20
  72. package/dist/components/menu/style.js +2 -0
  73. package/dist/components/menu/style2.css +0 -78
  74. package/dist/components/multi-select/multi-select-option.js +14 -10
  75. package/dist/components/multi-select/multi-select-option.js.map +1 -1
  76. package/dist/components/multi-select/multi-select.js +16 -19
  77. package/dist/components/multi-select/multi-select.js.map +1 -1
  78. package/dist/components/multi-select/multi-select.vue.d.ts +3 -3
  79. package/dist/components/multi-select/style.js +7 -0
  80. package/dist/components/multi-tree-select/multi-tree-select.vue.d.ts +4 -4
  81. package/dist/components/multi-tree-select/style.js +7 -0
  82. package/dist/components/notification/notification.vue.d.ts +1 -1
  83. package/dist/components/number-input/number-input.vue.d.ts +2 -2
  84. package/dist/components/number-input/style.js +1 -0
  85. package/dist/components/number-range-input/number-range-input.vue.d.ts +2 -2
  86. package/dist/components/number-range-input/style.js +1 -0
  87. package/dist/components/paginator/style.js +3 -0
  88. package/dist/components/palette/di.js.map +1 -1
  89. package/dist/components/palette/palette-alpha.js +7 -10
  90. package/dist/components/palette/palette-alpha.js.map +1 -1
  91. package/dist/components/palette/palette-hue.js +5 -7
  92. package/dist/components/palette/palette-hue.js.map +1 -1
  93. package/dist/components/palette/palette-sv.js +8 -10
  94. package/dist/components/palette/palette-sv.js.map +1 -1
  95. package/dist/components/palette/palette.js +22 -24
  96. package/dist/components/palette/palette.js.map +1 -1
  97. package/dist/components/palette/style.js +3 -0
  98. package/dist/components/password-input/password-input.vue.d.ts +1 -1
  99. package/dist/components/password-input/style.js +2 -0
  100. package/dist/components/pop-confirm/pop-confirm.vue.d.ts +1 -1
  101. package/dist/components/pop-confirm/style.js +3 -0
  102. package/dist/components/progress-nodes/progress-nodes.vue.d.ts +2 -2
  103. package/dist/components/progress-nodes/style2.css +79 -33
  104. package/dist/components/radio/style2.css +0 -8
  105. package/dist/components/radio-group/radio-group.vue.d.ts +2 -2
  106. package/dist/components/radio-group/style.js +1 -0
  107. package/dist/components/rich-text-editor/rich-text-editor.vue.d.ts +2 -2
  108. package/dist/components/select/select.js +14 -12
  109. package/dist/components/select/select.js.map +1 -1
  110. package/dist/components/select/select.vue.d.ts +2 -2
  111. package/dist/components/select/style.js +5 -0
  112. package/dist/components/select/style2.css +0 -20
  113. package/dist/components/slider/slider-thumb.js +10 -13
  114. package/dist/components/slider/slider-thumb.js.map +1 -1
  115. package/dist/components/slider/slider.js +12 -15
  116. package/dist/components/slider/slider.js.map +1 -1
  117. package/dist/components/steps/style.js +2 -0
  118. package/dist/components/steps/style2.css +28 -35
  119. package/dist/components/switch/style2.css +0 -3
  120. package/dist/components/table/di.js.map +1 -1
  121. package/dist/components/table/node/row.d.ts +10 -1
  122. package/dist/components/table/node/row.js +9 -0
  123. package/dist/components/table/node/row.js.map +1 -1
  124. package/dist/components/table/style.js +7 -0
  125. package/dist/components/table/style2.css +0 -41
  126. package/dist/components/table/table-body.js +25 -26
  127. package/dist/components/table/table-body.js.map +1 -1
  128. package/dist/components/table/table-cell.js +16 -9
  129. package/dist/components/table/table-cell.js.map +1 -1
  130. package/dist/components/table/table-row.js +78 -19
  131. package/dist/components/table/table-row.js.map +1 -1
  132. package/dist/components/table/table.js +76 -34
  133. package/dist/components/table/table.js.map +1 -1
  134. package/dist/components/table/use-fixed-columns.js +27 -8
  135. package/dist/components/table/use-fixed-columns.js.map +1 -1
  136. package/dist/components/table/use-rows.js +2 -2
  137. package/dist/components/table/use-rows.js.map +1 -1
  138. package/dist/components/table/use-table.js +25 -3
  139. package/dist/components/table/use-table.js.map +1 -1
  140. package/dist/components/table-editor/style.js +2 -0
  141. package/dist/components/tabs/index.d.ts +3 -1
  142. package/dist/components/tabs/style.js +2 -0
  143. package/dist/components/tabs/style2.css +169 -107
  144. package/dist/components/tabs/tabs-horizontal.js +133 -0
  145. package/dist/components/tabs/tabs-horizontal.js.map +1 -0
  146. package/dist/components/tabs/tabs-horizontal.vue.d.ts +29 -0
  147. package/dist/components/tabs/tabs-vertical.js +89 -0
  148. package/dist/components/tabs/tabs-vertical.js.map +1 -0
  149. package/dist/components/tabs/tabs-vertical.vue.d.ts +28 -0
  150. package/dist/components/tabs/tabs.js +75 -105
  151. package/dist/components/tabs/tabs.js.map +1 -1
  152. package/dist/components/tabs/tabs.vue.d.ts +9 -23
  153. package/dist/components/tabs/use-tabs-bar.js +105 -0
  154. package/dist/components/tabs/use-tabs-bar.js.map +1 -0
  155. package/dist/components/tag/style2.css +0 -6
  156. package/dist/components/textarea/style.js +1 -0
  157. package/dist/components/textarea/textarea.vue.d.ts +2 -2
  158. package/dist/components/theme/style.js +5 -0
  159. package/dist/components/tip/tip.vue.d.ts +2 -2
  160. package/dist/components/tree/style.js +4 -0
  161. package/dist/components/tree/style2.css +45 -23
  162. package/dist/components/tree/tree-node.js +50 -35
  163. package/dist/components/tree/tree-node.js.map +1 -1
  164. package/dist/components/tree/tree.js +27 -20
  165. package/dist/components/tree/tree.js.map +1 -1
  166. package/dist/components/tree/tree.vue.d.ts +1 -1
  167. package/dist/components/tree/use-check.js +52 -14
  168. package/dist/components/tree/use-check.js.map +1 -1
  169. package/dist/components/tree/use-tree-nodes.js +51 -24
  170. package/dist/components/tree/use-tree-nodes.js.map +1 -1
  171. package/dist/components/tree-select/style.js +4 -0
  172. package/dist/components/tree-select/tree-select.vue.d.ts +3 -3
  173. package/dist/components/watermark/watermark.vue.d.ts +1 -1
  174. package/dist/index.d.ts +57 -53
  175. package/dist/index.js +51 -48
  176. package/dist/types/file-viewer.d.ts +71 -0
  177. package/dist/types/index.d.ts +4 -3
  178. package/dist/types/tabs.d.ts +106 -14
  179. package/dist/types/tree.d.ts +6 -1
  180. package/package.json +32 -31
  181. package/src/components/breadcrumb/style.scss +0 -6
  182. package/src/components/cascade/cascade.vue +18 -18
  183. package/src/components/cascade/node.ts +4 -1
  184. package/src/components/cascade/use-check.ts +5 -4
  185. package/src/components/cascade/use-select.ts +4 -5
  186. package/src/components/checkbox/style.scss +0 -4
  187. package/src/components/date-picker/date-picker.vue +10 -9
  188. package/src/components/date-range-picker/date-range-picker.vue +12 -12
  189. package/src/components/drawer/style.scss +18 -11
  190. package/src/components/file-picker/helper.ts +21 -10
  191. package/src/components/file-viewer/file-viewer.vue +311 -0
  192. package/src/components/file-viewer/helper.ts +193 -0
  193. package/src/components/file-viewer/index.ts +1 -0
  194. package/src/components/file-viewer/previewers/docx-previewer.vue +78 -0
  195. package/src/components/file-viewer/previewers/image-previewer.vue +64 -0
  196. package/src/components/file-viewer/previewers/pdf-previewer.vue +90 -0
  197. package/src/components/file-viewer/previewers/sheet-previewer.vue +210 -0
  198. package/src/components/file-viewer/previewers/text-previewer.vue +76 -0
  199. package/src/components/file-viewer/previewers/video-previewer.vue +72 -0
  200. package/src/components/file-viewer/style.scss +504 -0
  201. package/src/components/file-viewer/style.ts +4 -0
  202. package/src/components/form-item/style.scss +2 -3
  203. package/src/components/index.ts +2 -0
  204. package/src/components/loading/style.scss +125 -126
  205. package/src/components/menu/style.scss +0 -31
  206. package/src/components/multi-select/multi-select-option.vue +16 -3
  207. package/src/components/multi-select/multi-select.vue +17 -9
  208. package/src/components/palette/di.ts +5 -3
  209. package/src/components/palette/palette-alpha.vue +7 -10
  210. package/src/components/palette/palette-hue.vue +5 -7
  211. package/src/components/palette/palette-sv.vue +12 -14
  212. package/src/components/palette/palette.vue +19 -21
  213. package/src/components/progress-nodes/style.scss +28 -22
  214. package/src/components/radio/style.scss +0 -4
  215. package/src/components/select/select.vue +21 -19
  216. package/src/components/select/style.scss +0 -12
  217. package/src/components/slider/slider-thumb.vue +11 -14
  218. package/src/components/slider/slider.vue +15 -15
  219. package/src/components/steps/style.scss +10 -10
  220. package/src/components/switch/style.scss +0 -4
  221. package/src/components/table/di.ts +20 -3
  222. package/src/components/table/node/row.ts +10 -1
  223. package/src/components/table/style.scss +0 -26
  224. package/src/components/table/table-body.vue +28 -33
  225. package/src/components/table/table-cell.vue +17 -9
  226. package/src/components/table/table-row.tsx +83 -17
  227. package/src/components/table/table.vue +73 -45
  228. package/src/components/table/use-fixed-columns.ts +46 -12
  229. package/src/components/table/use-rows.ts +14 -3
  230. package/src/components/table/use-table.ts +27 -3
  231. package/src/components/tabs/index.ts +2 -0
  232. package/src/components/tabs/style.scss +217 -134
  233. package/src/components/tabs/tabs-horizontal.vue +125 -0
  234. package/src/components/tabs/tabs-vertical.vue +75 -0
  235. package/src/components/tabs/tabs.vue +56 -127
  236. package/src/components/tabs/use-tabs-bar.ts +119 -0
  237. package/src/components/tag/style.scss +0 -6
  238. package/src/components/tree/style.scss +74 -29
  239. package/src/components/tree/tree-node.vue +10 -4
  240. package/src/components/tree/tree.vue +39 -12
  241. package/src/components/tree/use-check.ts +79 -23
  242. package/src/components/tree/use-tree-nodes.ts +85 -34
  243. package/src/types/file-viewer.ts +69 -0
  244. package/src/types/index.ts +1 -0
  245. package/src/types/tabs.ts +113 -19
  246. package/src/types/tree.ts +6 -1
  247. package/dist/types/index.js +0 -0
@@ -1,22 +1,41 @@
1
- import { ref } from "vue";
1
+ import { ref, watch } from "vue";
2
2
  import { debounce } from "@cat-kit/core";
3
3
  //#region src/components/table/use-fixed-columns.ts
4
4
  /**
5
5
  * 固定列
6
6
  * @returns
7
7
  */
8
- function useFixedColumns() {
8
+ function useFixedColumns(options = {}) {
9
+ const { isScrolling } = options;
9
10
  const leftFixed = ref(false);
10
11
  const rightFixed = ref(false);
12
+ let pendingLeft = null;
13
+ let pendingRight = null;
14
+ const applyImmediate = (nextLeft, nextRight) => {
15
+ if (nextLeft !== leftFixed.value) leftFixed.value = nextLeft;
16
+ if (nextRight !== rightFixed.value) rightFixed.value = nextRight;
17
+ pendingLeft = null;
18
+ pendingRight = null;
19
+ };
20
+ const handleScroll = debounce((e) => {
21
+ const nextLeft = e.x > 0;
22
+ const nextRight = !(e.cw + e.x + 1 >= e.sw);
23
+ if (isScrolling?.value) {
24
+ pendingLeft = nextLeft;
25
+ pendingRight = nextRight;
26
+ return;
27
+ }
28
+ applyImmediate(nextLeft, nextRight);
29
+ }, 50);
30
+ if (isScrolling) watch(isScrolling, (v) => {
31
+ if (v) return;
32
+ if (pendingLeft === null && pendingRight === null) return;
33
+ applyImmediate(pendingLeft ?? leftFixed.value, pendingRight ?? rightFixed.value);
34
+ });
11
35
  return {
12
36
  leftFixed,
13
37
  rightFixed,
14
- handleScroll: debounce((e) => {
15
- if (e.x > 0) leftFixed.value = true;
16
- else leftFixed.value = false;
17
- if (e.cw + e.x + 1 >= e.sw) rightFixed.value = false;
18
- else rightFixed.value = true;
19
- }, 50)
38
+ handleScroll
20
39
  };
21
40
  }
22
41
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"use-fixed-columns.js","names":[],"sources":["../../../src/components/table/use-fixed-columns.ts"],"sourcesContent":["import { debounce } from '@cat-kit/core'\nimport { type ShallowRef, ref } from 'vue'\n\nimport type { ScrollPosition } from '../../types'\n\ninterface UseColumnFixedReturned {\n leftFixed: ShallowRef<boolean>\n rightFixed: ShallowRef<boolean>\n handleScroll: (e: Required<ScrollPosition>) => void\n}\n\n/**\n * 固定列\n * @returns\n */\nexport function useFixedColumns(): UseColumnFixedReturned {\n const leftFixed = ref(false)\n const rightFixed = ref(false)\n\n const handleScroll = debounce((e: Required<ScrollPosition>) => {\n if (e.x > 0) {\n leftFixed.value = true\n } else {\n leftFixed.value = false\n }\n\n // 精度修正\n if (e.cw + e.x + 1 >= e.sw) {\n rightFixed.value = false\n } else {\n rightFixed.value = true\n }\n }, 50)\n\n return { leftFixed, rightFixed, handleScroll }\n}\n"],"mappings":";;;;;;;AAeA,SAAgB,kBAA0C;CACxD,MAAM,YAAY,IAAI,MAAM;CAC5B,MAAM,aAAa,IAAI,MAAM;AAiB7B,QAAO;EAAE;EAAW;EAAY,cAfX,UAAU,MAAgC;AAC7D,OAAI,EAAE,IAAI,EACR,WAAU,QAAQ;OAElB,WAAU,QAAQ;AAIpB,OAAI,EAAE,KAAK,EAAE,IAAI,KAAK,EAAE,GACtB,YAAW,QAAQ;OAEnB,YAAW,QAAQ;KAEpB,GAAG;EAEwC"}
1
+ {"version":3,"file":"use-fixed-columns.js","names":[],"sources":["../../../src/components/table/use-fixed-columns.ts"],"sourcesContent":["import { debounce } from '@cat-kit/core'\nimport { type ShallowRef, type Ref, ref, watch } from 'vue'\n\nimport type { ScrollPosition } from '../../types'\n\ninterface UseColumnFixedReturned {\n leftFixed: ShallowRef<boolean>\n rightFixed: ShallowRef<boolean>\n handleScroll: (e: Required<ScrollPosition>) => void\n}\n\ninterface Options {\n /**\n * D1:滚动中 (`true`) 暂缓 `leftFixed` / `rightFixed` 的切换,滚动结束后\n * 一次性补算。\n *\n * 背景:固定列的阴影是通过在 cell 上切换 `is-last-fixed` / `is-first-fixed`\n * 等 class 实现的,这些 class 会穿透到 `useTable.getCellClass` 的缓存键,\n * 任何一次切换都会让全表的单元格类名失效重算。滚动本身并不需要实时更新阴影,\n * 因此把切换推迟到 `isScrolling` 归零时做一次即可。\n *\n * 未传入时退化到旧行为(实时切换)。\n */\n isScrolling?: Ref<boolean>\n}\n\n/**\n * 固定列\n * @returns\n */\nexport function useFixedColumns(options: Options = {}): UseColumnFixedReturned {\n const { isScrolling } = options\n\n const leftFixed = ref(false)\n const rightFixed = ref(false)\n\n let pendingLeft: boolean | null = null\n let pendingRight: boolean | null = null\n\n const applyImmediate = (nextLeft: boolean, nextRight: boolean): void => {\n if (nextLeft !== leftFixed.value) leftFixed.value = nextLeft\n if (nextRight !== rightFixed.value) rightFixed.value = nextRight\n pendingLeft = null\n pendingRight = null\n }\n\n const handleScroll = debounce((e: Required<ScrollPosition>) => {\n const nextLeft = e.x > 0\n // 精度修正:浏览器滚动条最后 1px 的误差\n const nextRight = !(e.cw + e.x + 1 >= e.sw)\n\n if (isScrolling?.value) {\n pendingLeft = nextLeft\n pendingRight = nextRight\n return\n }\n\n applyImmediate(nextLeft, nextRight)\n }, 50)\n\n if (isScrolling) {\n watch(isScrolling, (v) => {\n if (v) return\n if (pendingLeft === null && pendingRight === null) return\n applyImmediate(pendingLeft ?? leftFixed.value, pendingRight ?? rightFixed.value)\n })\n }\n\n return { leftFixed, rightFixed, handleScroll }\n}\n"],"mappings":";;;;;;;AA8BA,SAAgB,gBAAgB,UAAmB,EAAE,EAA0B;CAC7E,MAAM,EAAE,gBAAgB;CAExB,MAAM,YAAY,IAAI,MAAM;CAC5B,MAAM,aAAa,IAAI,MAAM;CAE7B,IAAI,cAA8B;CAClC,IAAI,eAA+B;CAEnC,MAAM,kBAAkB,UAAmB,cAA6B;AACtE,MAAI,aAAa,UAAU,MAAO,WAAU,QAAQ;AACpD,MAAI,cAAc,WAAW,MAAO,YAAW,QAAQ;AACvD,gBAAc;AACd,iBAAe;;CAGjB,MAAM,eAAe,UAAU,MAAgC;EAC7D,MAAM,WAAW,EAAE,IAAI;EAEvB,MAAM,YAAY,EAAE,EAAE,KAAK,EAAE,IAAI,KAAK,EAAE;AAExC,MAAI,aAAa,OAAO;AACtB,iBAAc;AACd,kBAAe;AACf;;AAGF,iBAAe,UAAU,UAAU;IAClC,GAAG;AAEN,KAAI,YACF,OAAM,cAAc,MAAM;AACxB,MAAI,EAAG;AACP,MAAI,gBAAgB,QAAQ,iBAAiB,KAAM;AACnD,iBAAe,eAAe,UAAU,OAAO,gBAAgB,WAAW,MAAM;GAChF;AAGJ,QAAO;EAAE;EAAW;EAAY;EAAc"}
@@ -4,7 +4,7 @@ import { Forest, o } from "@cat-kit/core";
4
4
  import { useModel as useModel$1 } from "@veltra/compositions";
5
5
  //#region src/components/table/use-rows.ts
6
6
  function useRows(options) {
7
- const { props, emit } = options;
7
+ const { props, emit, isScrolling } = options;
8
8
  /** 所有可见的行 */
9
9
  const rows = shallowRef([]);
10
10
  /** 数据行, 不包括展开和折叠的行 */
@@ -145,7 +145,7 @@ function useRows(options) {
145
145
  }
146
146
  }
147
147
  function handleRowClick(row, e) {
148
- currentRow.value = currentRow.value === row ? void 0 : row;
148
+ if (!isScrolling?.value) currentRow.value = currentRow.value === row ? void 0 : row;
149
149
  emit("row-click", row, e);
150
150
  }
151
151
  function handleCellClick(row, column, e) {
@@ -1 +1 @@
1
- {"version":3,"file":"use-rows.js","names":["useModel"],"sources":["../../../src/components/table/use-rows.ts"],"sourcesContent":["import { Forest, o } from '@cat-kit/core'\nimport { useModel } from '@veltra/compositions'\nimport { shallowRef, watch, type ShallowRef } from 'vue'\n\nimport type { TableColumn, TableEmits, TableProps, TableRow } from '../../types'\nimport { TableRowNode } from './node/row'\n\ninterface Options {\n props: TableProps\n emit: TableEmits\n}\n\ninterface UseRowsReturned {\n /** 所有的行森林(树形数据) */\n rowForest: ShallowRef<Forest<Record<string, unknown>, any> | undefined>\n /** 当前可见的展平行列表 */\n rows: ShallowRef<TableRowNode[]>\n /** 切换树形行节点的展开/折叠 */\n toggleTreeRowExpand: (node: TableRow) => void\n /** 是否全部展开 */\n allExpanded: ShallowRef<boolean>\n /** 切换全部展开/折叠 */\n toggleAllTreeRowExpand: () => void\n /** 行点击处理 */\n handleRowClick: (row: TableRow, e: MouseEvent) => void\n /** 单元格点击处理 */\n handleCellClick: (row: TableRow, column: TableColumn, e: MouseEvent) => void\n /** 根据原始数据对象获取对应的 TableRow */\n getRowByData: (data: Record<string, any>) => TableRow | undefined\n}\n\nexport function useRows(options: Options): UseRowsReturned {\n const { props, emit } = options\n\n // --- 状态定义 ---\n\n /** 所有可见的行 */\n const rows = shallowRef<TableRowNode[]>([])\n /** 数据行, 不包括展开和折叠的行 */\n const dataRows = shallowRef<TableRowNode[]>([])\n /** 行森林(数据结构树) */\n const rowForest = shallowRef<Forest<Record<string, unknown>, any>>()\n /** 树形节点是否全部展开 */\n const allExpanded = shallowRef(props.defaultExpandAll ?? false)\n\n /** 当前高亮的行 */\n const currentRow = useModel({\n props,\n emit,\n propName: 'current',\n shallow: true,\n local: () => !!props.highlightCurrent\n })\n\n // --- 行字典维护 (性能优化) ---\n\n /**\n * 用于优化增删改时的性能。\n * 原理:Vue 的组件在属性发生改变时会重新渲染,通过 WeakMap 缓存 data -> TableRow 的映射,\n * 可以在数据更新时复用已有的 TableRowNode 实例,避免重复创建和 DOM 抖动。\n */\n let rowDicts = new WeakMap<Record<string, any>, TableRowNode>()\n let tempRowDicts: null | WeakMap<Record<string, any>, TableRowNode> = null\n let uidSeed = 0\n\n /** 获取行唯一标识 */\n const getRowUID = props.rowKey\n ? (rowData: Record<string, any>) => rowData && o(rowData).get(props.rowKey!)\n : () => uidSeed++\n\n /** 创建或复用 TableRow 实例 */\n const createRow = (\n data: Record<string, any>,\n index: number,\n depth = 0,\n parent?: TableRowNode\n ) => {\n const existRow = data ? rowDicts.get(data) : undefined\n if (existRow) {\n existRow.index = index\n existRow.depth = depth\n existRow.parent = parent\n return existRow\n }\n return new TableRowNode({ data, index, depth, parent, uid: getRowUID(data) })\n }\n\n // --- 行处理逻辑 ---\n\n /** 处理常规扁平列表 */\n function getDataRows(data: Record<string, any>[]): TableRowNode[] {\n let i = data.length\n const result = Array.from({ length: i }) as TableRowNode[]\n tempRowDicts = new WeakMap()\n\n while (i--) {\n const dataItem = data[i]!\n const row = createRow(dataItem, i)\n result[i] = row\n tempRowDicts.set(dataItem, row)\n }\n\n rowDicts = tempRowDicts\n tempRowDicts = null\n return result\n }\n\n function expandDataRows(): void {\n const result: TableRowNode[] = []\n let i = -1\n while (++i < dataRows.value.length) {\n const row = dataRows.value[i]!\n result.push(row)\n if (row.expanded) {\n result.push(row.copy())\n }\n }\n rows.value = result\n }\n\n /** 处理树形森林结构 */\n function getRowForest(data: Record<string, any>[]): Forest<Record<string, unknown>, any> {\n tempRowDicts = new WeakMap()\n const childrenKey = typeof props.tree === 'string' ? props.tree : 'children'\n const ret = new Forest<Record<string, unknown>, any>({\n data,\n childrenKey,\n createNode(val, index, depth, _forest, parent) {\n const row = createRow(val, index, depth, parent)\n if (props.defaultExpandAll) {\n row.expanded = true\n }\n val && tempRowDicts!.set(val, row)\n return row\n }\n })\n\n rowDicts = tempRowDicts\n tempRowDicts = null\n return ret\n }\n\n /** 展平树形结构为可见行列表 */\n function updateFlattedRows(): void {\n if (!rowForest.value) return\n rows.value = rowForest.value.flattenVisible((n) => n.expanded)\n }\n\n // --- 副作用监听 ---\n\n // 监听当前行切换,维护 isCurrent 状态\n watch(\n () => currentRow.value,\n (row, oldRow) => {\n if (oldRow) oldRow.isCurrent = false\n if (row) row.isCurrent = true\n }\n )\n\n // 同步状态给外部\n watch(rows, (rows) => emit('update:rows', rows))\n watch(rowForest, (forest) => emit('update:forest', forest))\n\n // 核心:监听原始数据变化,重新构建行列表或树\n watch(\n [() => props.data, () => props.tree, () => props.defaultExpandAll],\n ([data, tree]) => {\n if (!data?.length) {\n rows.value = []\n rowDicts = new WeakMap()\n rowForest.value = undefined\n return\n }\n\n if (!tree) {\n rowForest.value = undefined\n dataRows.value = getDataRows(data)\n rows.value = dataRows.value\n } else {\n dataRows.value = []\n rowForest.value = getRowForest(data)\n updateFlattedRows()\n }\n },\n { immediate: true }\n )\n\n // --- 交互方法 ---\n\n function toggleTreeRowExpand(node: TableRow): void {\n node.expanded = !node.expanded\n\n if (props.tree) {\n return updateFlattedRows()\n }\n if (props.expandable) {\n expandDataRows()\n }\n }\n\n function toggleAllTreeRowExpand(): void {\n allExpanded.value = !allExpanded.value\n if (props.tree) {\n rowForest.value?.dfs((node) => {\n node.expanded = allExpanded.value\n })\n updateFlattedRows()\n return\n }\n if (props.expandable) {\n dataRows.value.forEach((row) => {\n row.expanded = allExpanded.value\n })\n expandDataRows()\n return\n }\n }\n\n function handleRowClick(row: TableRow, e: MouseEvent): void {\n currentRow.value = currentRow.value === row ? undefined : row\n emit('row-click', row, e)\n }\n\n function handleCellClick(row: TableRow, column: TableColumn, e: MouseEvent): void {\n emit('cell-click', row, column, e)\n }\n\n function getRowByData(data: Record<string, any>): TableRow | undefined {\n return rowDicts.get(data)\n }\n\n return {\n rowForest,\n rows,\n allExpanded,\n toggleTreeRowExpand,\n toggleAllTreeRowExpand,\n handleRowClick,\n handleCellClick,\n getRowByData\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"use-rows.js","names":["useModel"],"sources":["../../../src/components/table/use-rows.ts"],"sourcesContent":["import { Forest, o } from '@cat-kit/core'\nimport { useModel } from '@veltra/compositions'\nimport { shallowRef, watch, type Ref, type ShallowRef } from 'vue'\n\nimport type { TableColumn, TableEmits, TableProps, TableRow } from '../../types'\nimport { TableRowNode } from './node/row'\n\ninterface Options {\n props: TableProps\n emit: TableEmits\n /**\n * D2:滚动中 (`true`) 跳过 `currentRow` 高亮写入。\n *\n * 行点击处理会通过 `currentRow` watcher 把 `isCurrent` 切换到新行 / 旧行上,\n * 触发对应 `<tr>` 的 class 重绘。在滚动期间 (移动端/触控板惯性滚动常见)\n * 意外点击不应改变高亮,因此直接跳过;滚动结束后的正常点击仍会生效。\n */\n isScrolling?: Ref<boolean>\n}\n\ninterface UseRowsReturned {\n /** 所有的行森林(树形数据) */\n rowForest: ShallowRef<Forest<Record<string, unknown>, any> | undefined>\n /** 当前可见的展平行列表 */\n rows: ShallowRef<TableRowNode[]>\n /** 切换树形行节点的展开/折叠 */\n toggleTreeRowExpand: (node: TableRow) => void\n /** 是否全部展开 */\n allExpanded: ShallowRef<boolean>\n /** 切换全部展开/折叠 */\n toggleAllTreeRowExpand: () => void\n /** 行点击处理 */\n handleRowClick: (row: TableRow, e: MouseEvent) => void\n /** 单元格点击处理 */\n handleCellClick: (row: TableRow, column: TableColumn, e: MouseEvent) => void\n /** 根据原始数据对象获取对应的 TableRow */\n getRowByData: (data: Record<string, any>) => TableRow | undefined\n}\n\nexport function useRows(options: Options): UseRowsReturned {\n const { props, emit, isScrolling } = options\n\n // --- 状态定义 ---\n\n /** 所有可见的行 */\n const rows = shallowRef<TableRowNode[]>([])\n /** 数据行, 不包括展开和折叠的行 */\n const dataRows = shallowRef<TableRowNode[]>([])\n /** 行森林(数据结构树) */\n const rowForest = shallowRef<Forest<Record<string, unknown>, any>>()\n /** 树形节点是否全部展开 */\n const allExpanded = shallowRef(props.defaultExpandAll ?? false)\n\n /** 当前高亮的行 */\n const currentRow = useModel({\n props,\n emit,\n propName: 'current',\n shallow: true,\n local: () => !!props.highlightCurrent\n })\n\n // --- 行字典维护 (性能优化) ---\n\n /**\n * 用于优化增删改时的性能。\n * 原理:Vue 的组件在属性发生改变时会重新渲染,通过 WeakMap 缓存 data -> TableRow 的映射,\n * 可以在数据更新时复用已有的 TableRowNode 实例,避免重复创建和 DOM 抖动。\n */\n let rowDicts = new WeakMap<Record<string, any>, TableRowNode>()\n let tempRowDicts: null | WeakMap<Record<string, any>, TableRowNode> = null\n let uidSeed = 0\n\n /** 获取行唯一标识 */\n const getRowUID = props.rowKey\n ? (rowData: Record<string, any>) => rowData && o(rowData).get(props.rowKey!)\n : () => uidSeed++\n\n /** 创建或复用 TableRow 实例 */\n const createRow = (\n data: Record<string, any>,\n index: number,\n depth = 0,\n parent?: TableRowNode\n ) => {\n const existRow = data ? rowDicts.get(data) : undefined\n if (existRow) {\n existRow.index = index\n existRow.depth = depth\n existRow.parent = parent\n return existRow\n }\n return new TableRowNode({ data, index, depth, parent, uid: getRowUID(data) })\n }\n\n // --- 行处理逻辑 ---\n\n /** 处理常规扁平列表 */\n function getDataRows(data: Record<string, any>[]): TableRowNode[] {\n let i = data.length\n const result = Array.from({ length: i }) as TableRowNode[]\n tempRowDicts = new WeakMap()\n\n while (i--) {\n const dataItem = data[i]!\n const row = createRow(dataItem, i)\n result[i] = row\n tempRowDicts.set(dataItem, row)\n }\n\n rowDicts = tempRowDicts\n tempRowDicts = null\n return result\n }\n\n function expandDataRows(): void {\n const result: TableRowNode[] = []\n let i = -1\n while (++i < dataRows.value.length) {\n const row = dataRows.value[i]!\n result.push(row)\n if (row.expanded) {\n result.push(row.copy())\n }\n }\n rows.value = result\n }\n\n /** 处理树形森林结构 */\n function getRowForest(data: Record<string, any>[]): Forest<Record<string, unknown>, any> {\n tempRowDicts = new WeakMap()\n const childrenKey = typeof props.tree === 'string' ? props.tree : 'children'\n const ret = new Forest<Record<string, unknown>, any>({\n data,\n childrenKey,\n createNode(val, index, depth, _forest, parent) {\n const row = createRow(val, index, depth, parent)\n if (props.defaultExpandAll) {\n row.expanded = true\n }\n val && tempRowDicts!.set(val, row)\n return row\n }\n })\n\n rowDicts = tempRowDicts\n tempRowDicts = null\n return ret\n }\n\n /** 展平树形结构为可见行列表 */\n function updateFlattedRows(): void {\n if (!rowForest.value) return\n rows.value = rowForest.value.flattenVisible((n) => n.expanded)\n }\n\n // --- 副作用监听 ---\n\n // 监听当前行切换,维护 isCurrent 状态\n watch(\n () => currentRow.value,\n (row, oldRow) => {\n if (oldRow) oldRow.isCurrent = false\n if (row) row.isCurrent = true\n }\n )\n\n // 同步状态给外部\n watch(rows, (rows) => emit('update:rows', rows))\n watch(rowForest, (forest) => emit('update:forest', forest))\n\n // 核心:监听原始数据变化,重新构建行列表或树\n watch(\n [() => props.data, () => props.tree, () => props.defaultExpandAll],\n ([data, tree]) => {\n if (!data?.length) {\n rows.value = []\n rowDicts = new WeakMap()\n rowForest.value = undefined\n return\n }\n\n if (!tree) {\n rowForest.value = undefined\n dataRows.value = getDataRows(data)\n rows.value = dataRows.value\n } else {\n dataRows.value = []\n rowForest.value = getRowForest(data)\n updateFlattedRows()\n }\n },\n { immediate: true }\n )\n\n // --- 交互方法 ---\n\n function toggleTreeRowExpand(node: TableRow): void {\n node.expanded = !node.expanded\n\n if (props.tree) {\n return updateFlattedRows()\n }\n if (props.expandable) {\n expandDataRows()\n }\n }\n\n function toggleAllTreeRowExpand(): void {\n allExpanded.value = !allExpanded.value\n if (props.tree) {\n rowForest.value?.dfs((node) => {\n node.expanded = allExpanded.value\n })\n updateFlattedRows()\n return\n }\n if (props.expandable) {\n dataRows.value.forEach((row) => {\n row.expanded = allExpanded.value\n })\n expandDataRows()\n return\n }\n }\n\n function handleRowClick(row: TableRow, e: MouseEvent): void {\n // D2:滚动中的点击(多为惯性滚动误触)不应改变 currentRow 高亮。\n if (!isScrolling?.value) {\n currentRow.value = currentRow.value === row ? undefined : row\n }\n emit('row-click', row, e)\n }\n\n function handleCellClick(row: TableRow, column: TableColumn, e: MouseEvent): void {\n emit('cell-click', row, column, e)\n }\n\n function getRowByData(data: Record<string, any>): TableRow | undefined {\n return rowDicts.get(data)\n }\n\n return {\n rowForest,\n rows,\n allExpanded,\n toggleTreeRowExpand,\n toggleAllTreeRowExpand,\n handleRowClick,\n handleCellClick,\n getRowByData\n }\n}\n"],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import { useSlots } from "vue";
1
+ import { useSlots, watch } from "vue";
2
2
  import { o } from "@cat-kit/core";
3
3
  import { bem } from "@veltra/utils";
4
4
  //#region src/components/table/use-table.ts
@@ -33,11 +33,33 @@ function useTable(options) {
33
33
  if (column.fixed) classList.push(bem.is("fixed-" + column.fixed));
34
34
  return classList.join(" ");
35
35
  };
36
+ /**
37
+ * B1: 单元格类名按 ColumnNode 身份缓存。
38
+ *
39
+ * 对同一列,类名只取决于 (column.fixed, column.isLastFixed, column.isFirstFixed,
40
+ * column.align, leftFixed, rightFixed)。其中前四个绑定在 ColumnNode 实例上,
41
+ * 后两个在 leftFixed/rightFixed 变化时失效缓存即可。用 WeakMap 以 ColumnNode
42
+ * 为键可避免字符串 key 的拼接/哈希开销,且列树重建时节点随 GC 自动释放。
43
+ */
44
+ let cellClassCache = /* @__PURE__ */ new WeakMap();
45
+ let headerCellClassCache = /* @__PURE__ */ new WeakMap();
46
+ watch([leftFixed, rightFixed], () => {
47
+ cellClassCache = /* @__PURE__ */ new WeakMap();
48
+ headerCellClassCache = /* @__PURE__ */ new WeakMap();
49
+ });
36
50
  const getCellClass = (column) => {
37
- return getCommonClassName(column) + ` ${bem.is(column.align)}`;
51
+ const cached = cellClassCache.get(column);
52
+ if (cached !== void 0) return cached;
53
+ const result = getCommonClassName(column) + ` ${bem.is(column.align)}`;
54
+ cellClassCache.set(column, result);
55
+ return result;
38
56
  };
39
57
  const getHeaderCellClass = (column) => {
40
- return getCommonClassName(column) + ` ${bem.is(column.headerAlign)}`;
58
+ const cached = headerCellClassCache.get(column);
59
+ if (cached !== void 0) return cached;
60
+ const result = getCommonClassName(column) + ` ${bem.is(column.headerAlign)}`;
61
+ headerCellClassCache.set(column, result);
62
+ return result;
41
63
  };
42
64
  const getCellCtx = (row, column) => {
43
65
  const rowData = row.data;
@@ -1 +1 @@
1
- {"version":3,"file":"use-table.js","names":[],"sources":["../../../src/components/table/use-table.ts"],"sourcesContent":["import { o } from '@cat-kit/core'\nimport { bem, type BEM } from '@veltra/utils'\nimport { useSlots, type Ref } from 'vue'\n\nimport type {\n TableColumnRenderContext,\n TableColumnSlotsScope,\n TableProps,\n TableRow,\n RenderReturn,\n TableRowSlotsScope\n} from '../../types'\nimport type { ColumnNode } from './node/col'\n\ninterface Options {\n props: TableProps\n cls: BEM<'table'>\n leftFixed: Ref<boolean>\n rightFixed: Ref<boolean>\n}\n\ninterface UseTableReturn {\n getColumnSlotsNode: (ctx: TableColumnSlotsScope | TableColumnRenderContext) => RenderReturn\n getHeaderSlotsNode: (ctx: { column: ColumnNode }) => RenderReturn\n getExpandRowSlotsNode: (ctx: TableRowSlotsScope) => RenderReturn\n getCellClass: (column: ColumnNode) => string\n getHeaderCellClass: (column: ColumnNode) => string\n getCellCtx: (\n row: TableRow,\n column: ColumnNode\n ) => TableColumnSlotsScope | TableColumnRenderContext\n}\n\nexport function useTable(options: Options): UseTableReturn {\n const { props, cls, leftFixed, rightFixed } = options\n\n const slots = useSlots()\n\n const getColumnSlotsNode = (\n ctx: TableColumnSlotsScope | TableColumnRenderContext\n ): RenderReturn => {\n const column = ctx.column.data\n\n const { render, key } = column\n\n if (render) return render(ctx)\n\n const slotsRender = props.slots?.[`column:${key}`] ?? slots[`column:${key}`]\n\n if (slotsRender) return slotsRender(ctx)\n\n return ctx.val\n }\n\n const getHeaderSlotsNode = (ctx: { column: ColumnNode }): RenderReturn => {\n const column = ctx.column.data\n const { nameRender, key } = column\n\n if (nameRender) return nameRender(ctx)\n\n const slotsRender = props.slots?.[`header:${key}`] ?? slots[`header:${key}`]\n\n if (slotsRender) return slotsRender(ctx)\n\n return column.name\n }\n\n const getExpandRowSlotsNode = (ctx: TableRowSlotsScope): RenderReturn => {\n const slotsRender = props.slots?.['row:expand'] ?? slots['row:expand']\n\n if (slotsRender) return slotsRender(ctx)\n return null\n }\n\n const cellCls = cls.e('cell')\n\n const getCommonClassName = (column: ColumnNode): string => {\n const classList: string[] = [cellCls]\n\n leftFixed.value && column.isLastFixed && classList.push(bem.is('last-fixed'))\n\n rightFixed.value && column.isFirstFixed && classList.push(bem.is('first-fixed'))\n\n if (column.fixed) {\n classList.push(bem.is('fixed-' + column.fixed))\n }\n return classList.join(' ')\n }\n\n const getCellClass = (column: ColumnNode): string => {\n return getCommonClassName(column) + ` ${bem.is(column.align)}`\n }\n\n const getHeaderCellClass = (column: ColumnNode): string => {\n return getCommonClassName(column) + ` ${bem.is(column.headerAlign)}`\n }\n\n const getCellCtx = (\n row: TableRow,\n column: ColumnNode\n ): TableColumnSlotsScope | TableColumnRenderContext => {\n const rowData = row.data\n const val = column.key ? o(rowData).get(column.key) : undefined\n\n const ctx = {\n row,\n column,\n rowData,\n val,\n model: {\n modelValue: val,\n 'onUpdate:modelValue': (val: any) => {\n rowData[column.key] = val\n }\n }\n }\n\n return ctx\n }\n\n return {\n /**\n * 获取列插槽VNode\n * @param ctx 列渲染上下文\n */\n getColumnSlotsNode,\n /**\n * 获取表头插槽VNode\n * @param ctx 表头渲染上下文\n */\n getHeaderSlotsNode,\n /**\n * 获取展开行插槽VNode\n * @param ctx 展开行渲染上下文\n */\n getExpandRowSlotsNode,\n /**\n * 获取单元格类名\n * @param column 列\n */\n getCellClass,\n /**\n * 获取表头单元格类名\n * @param column 列\n */\n getHeaderCellClass,\n /**\n * 获取单元格上下文\n * @param row 行\n * @param column 列\n */\n getCellCtx\n }\n}\n"],"mappings":";;;;AAiCA,SAAgB,SAAS,SAAkC;CACzD,MAAM,EAAE,OAAO,KAAK,WAAW,eAAe;CAE9C,MAAM,QAAQ,UAAU;CAExB,MAAM,sBACJ,QACiB;EAGjB,MAAM,EAAE,QAAQ,QAFD,IAAI,OAAO;AAI1B,MAAI,OAAQ,QAAO,OAAO,IAAI;EAE9B,MAAM,cAAc,MAAM,QAAQ,UAAU,UAAU,MAAM,UAAU;AAEtE,MAAI,YAAa,QAAO,YAAY,IAAI;AAExC,SAAO,IAAI;;CAGb,MAAM,sBAAsB,QAA8C;EACxE,MAAM,SAAS,IAAI,OAAO;EAC1B,MAAM,EAAE,YAAY,QAAQ;AAE5B,MAAI,WAAY,QAAO,WAAW,IAAI;EAEtC,MAAM,cAAc,MAAM,QAAQ,UAAU,UAAU,MAAM,UAAU;AAEtE,MAAI,YAAa,QAAO,YAAY,IAAI;AAExC,SAAO,OAAO;;CAGhB,MAAM,yBAAyB,QAA0C;EACvE,MAAM,cAAc,MAAM,QAAQ,iBAAiB,MAAM;AAEzD,MAAI,YAAa,QAAO,YAAY,IAAI;AACxC,SAAO;;CAGT,MAAM,UAAU,IAAI,EAAE,OAAO;CAE7B,MAAM,sBAAsB,WAA+B;EACzD,MAAM,YAAsB,CAAC,QAAQ;AAErC,YAAU,SAAS,OAAO,eAAe,UAAU,KAAK,IAAI,GAAG,aAAa,CAAC;AAE7E,aAAW,SAAS,OAAO,gBAAgB,UAAU,KAAK,IAAI,GAAG,cAAc,CAAC;AAEhF,MAAI,OAAO,MACT,WAAU,KAAK,IAAI,GAAG,WAAW,OAAO,MAAM,CAAC;AAEjD,SAAO,UAAU,KAAK,IAAI;;CAG5B,MAAM,gBAAgB,WAA+B;AACnD,SAAO,mBAAmB,OAAO,GAAG,IAAI,IAAI,GAAG,OAAO,MAAM;;CAG9D,MAAM,sBAAsB,WAA+B;AACzD,SAAO,mBAAmB,OAAO,GAAG,IAAI,IAAI,GAAG,OAAO,YAAY;;CAGpE,MAAM,cACJ,KACA,WACqD;EACrD,MAAM,UAAU,IAAI;EACpB,MAAM,MAAM,OAAO,MAAM,EAAE,QAAQ,CAAC,IAAI,OAAO,IAAI,GAAG,KAAA;AAetD,SAbY;GACV;GACA;GACA;GACA;GACA,OAAO;IACL,YAAY;IACZ,wBAAwB,QAAa;AACnC,aAAQ,OAAO,OAAO;;IAEzB;GACF;;AAKH,QAAO;EAKL;EAKA;EAKA;EAKA;EAKA;EAMA;EACD"}
1
+ {"version":3,"file":"use-table.js","names":[],"sources":["../../../src/components/table/use-table.ts"],"sourcesContent":["import { o } from '@cat-kit/core'\nimport { bem, type BEM } from '@veltra/utils'\nimport { useSlots, watch, type Ref } from 'vue'\n\nimport type {\n TableColumnRenderContext,\n TableColumnSlotsScope,\n TableProps,\n TableRow,\n RenderReturn,\n TableRowSlotsScope\n} from '../../types'\nimport type { ColumnNode } from './node/col'\n\ninterface Options {\n props: TableProps\n cls: BEM<'table'>\n leftFixed: Ref<boolean>\n rightFixed: Ref<boolean>\n}\n\ninterface UseTableReturn {\n getColumnSlotsNode: (ctx: TableColumnSlotsScope | TableColumnRenderContext) => RenderReturn\n getHeaderSlotsNode: (ctx: { column: ColumnNode }) => RenderReturn\n getExpandRowSlotsNode: (ctx: TableRowSlotsScope) => RenderReturn\n getCellClass: (column: ColumnNode) => string\n getHeaderCellClass: (column: ColumnNode) => string\n getCellCtx: (\n row: TableRow,\n column: ColumnNode\n ) => TableColumnSlotsScope | TableColumnRenderContext\n}\n\nexport function useTable(options: Options): UseTableReturn {\n const { props, cls, leftFixed, rightFixed } = options\n\n const slots = useSlots()\n\n const getColumnSlotsNode = (\n ctx: TableColumnSlotsScope | TableColumnRenderContext\n ): RenderReturn => {\n const column = ctx.column.data\n\n const { render, key } = column\n\n if (render) return render(ctx)\n\n const slotsRender = props.slots?.[`column:${key}`] ?? slots[`column:${key}`]\n\n if (slotsRender) return slotsRender(ctx)\n\n return ctx.val\n }\n\n const getHeaderSlotsNode = (ctx: { column: ColumnNode }): RenderReturn => {\n const column = ctx.column.data\n const { nameRender, key } = column\n\n if (nameRender) return nameRender(ctx)\n\n const slotsRender = props.slots?.[`header:${key}`] ?? slots[`header:${key}`]\n\n if (slotsRender) return slotsRender(ctx)\n\n return column.name\n }\n\n const getExpandRowSlotsNode = (ctx: TableRowSlotsScope): RenderReturn => {\n const slotsRender = props.slots?.['row:expand'] ?? slots['row:expand']\n\n if (slotsRender) return slotsRender(ctx)\n return null\n }\n\n const cellCls = cls.e('cell')\n\n const getCommonClassName = (column: ColumnNode): string => {\n const classList: string[] = [cellCls]\n\n leftFixed.value && column.isLastFixed && classList.push(bem.is('last-fixed'))\n\n rightFixed.value && column.isFirstFixed && classList.push(bem.is('first-fixed'))\n\n if (column.fixed) {\n classList.push(bem.is('fixed-' + column.fixed))\n }\n return classList.join(' ')\n }\n\n /**\n * B1: 单元格类名按 ColumnNode 身份缓存。\n *\n * 对同一列,类名只取决于 (column.fixed, column.isLastFixed, column.isFirstFixed,\n * column.align, leftFixed, rightFixed)。其中前四个绑定在 ColumnNode 实例上,\n * 后两个在 leftFixed/rightFixed 变化时失效缓存即可。用 WeakMap 以 ColumnNode\n * 为键可避免字符串 key 的拼接/哈希开销,且列树重建时节点随 GC 自动释放。\n */\n let cellClassCache = new WeakMap<ColumnNode, string>()\n let headerCellClassCache = new WeakMap<ColumnNode, string>()\n\n watch([leftFixed, rightFixed], () => {\n cellClassCache = new WeakMap()\n headerCellClassCache = new WeakMap()\n })\n\n const getCellClass = (column: ColumnNode): string => {\n const cached = cellClassCache.get(column)\n if (cached !== undefined) return cached\n const result = getCommonClassName(column) + ` ${bem.is(column.align)}`\n cellClassCache.set(column, result)\n return result\n }\n\n const getHeaderCellClass = (column: ColumnNode): string => {\n const cached = headerCellClassCache.get(column)\n if (cached !== undefined) return cached\n const result = getCommonClassName(column) + ` ${bem.is(column.headerAlign)}`\n headerCellClassCache.set(column, result)\n return result\n }\n\n const getCellCtx = (\n row: TableRow,\n column: ColumnNode\n ): TableColumnSlotsScope | TableColumnRenderContext => {\n const rowData = row.data\n const val = column.key ? o(rowData).get(column.key) : undefined\n\n const ctx = {\n row,\n column,\n rowData,\n val,\n model: {\n modelValue: val,\n 'onUpdate:modelValue': (val: any) => {\n rowData[column.key] = val\n }\n }\n }\n\n return ctx\n }\n\n return {\n /**\n * 获取列插槽VNode\n * @param ctx 列渲染上下文\n */\n getColumnSlotsNode,\n /**\n * 获取表头插槽VNode\n * @param ctx 表头渲染上下文\n */\n getHeaderSlotsNode,\n /**\n * 获取展开行插槽VNode\n * @param ctx 展开行渲染上下文\n */\n getExpandRowSlotsNode,\n /**\n * 获取单元格类名\n * @param column 列\n */\n getCellClass,\n /**\n * 获取表头单元格类名\n * @param column 列\n */\n getHeaderCellClass,\n /**\n * 获取单元格上下文\n * @param row 行\n * @param column 列\n */\n getCellCtx\n }\n}\n"],"mappings":";;;;AAiCA,SAAgB,SAAS,SAAkC;CACzD,MAAM,EAAE,OAAO,KAAK,WAAW,eAAe;CAE9C,MAAM,QAAQ,UAAU;CAExB,MAAM,sBACJ,QACiB;EAGjB,MAAM,EAAE,QAAQ,QAFD,IAAI,OAAO;AAI1B,MAAI,OAAQ,QAAO,OAAO,IAAI;EAE9B,MAAM,cAAc,MAAM,QAAQ,UAAU,UAAU,MAAM,UAAU;AAEtE,MAAI,YAAa,QAAO,YAAY,IAAI;AAExC,SAAO,IAAI;;CAGb,MAAM,sBAAsB,QAA8C;EACxE,MAAM,SAAS,IAAI,OAAO;EAC1B,MAAM,EAAE,YAAY,QAAQ;AAE5B,MAAI,WAAY,QAAO,WAAW,IAAI;EAEtC,MAAM,cAAc,MAAM,QAAQ,UAAU,UAAU,MAAM,UAAU;AAEtE,MAAI,YAAa,QAAO,YAAY,IAAI;AAExC,SAAO,OAAO;;CAGhB,MAAM,yBAAyB,QAA0C;EACvE,MAAM,cAAc,MAAM,QAAQ,iBAAiB,MAAM;AAEzD,MAAI,YAAa,QAAO,YAAY,IAAI;AACxC,SAAO;;CAGT,MAAM,UAAU,IAAI,EAAE,OAAO;CAE7B,MAAM,sBAAsB,WAA+B;EACzD,MAAM,YAAsB,CAAC,QAAQ;AAErC,YAAU,SAAS,OAAO,eAAe,UAAU,KAAK,IAAI,GAAG,aAAa,CAAC;AAE7E,aAAW,SAAS,OAAO,gBAAgB,UAAU,KAAK,IAAI,GAAG,cAAc,CAAC;AAEhF,MAAI,OAAO,MACT,WAAU,KAAK,IAAI,GAAG,WAAW,OAAO,MAAM,CAAC;AAEjD,SAAO,UAAU,KAAK,IAAI;;;;;;;;;;CAW5B,IAAI,iCAAiB,IAAI,SAA6B;CACtD,IAAI,uCAAuB,IAAI,SAA6B;AAE5D,OAAM,CAAC,WAAW,WAAW,QAAQ;AACnC,mCAAiB,IAAI,SAAS;AAC9B,yCAAuB,IAAI,SAAS;GACpC;CAEF,MAAM,gBAAgB,WAA+B;EACnD,MAAM,SAAS,eAAe,IAAI,OAAO;AACzC,MAAI,WAAW,KAAA,EAAW,QAAO;EACjC,MAAM,SAAS,mBAAmB,OAAO,GAAG,IAAI,IAAI,GAAG,OAAO,MAAM;AACpE,iBAAe,IAAI,QAAQ,OAAO;AAClC,SAAO;;CAGT,MAAM,sBAAsB,WAA+B;EACzD,MAAM,SAAS,qBAAqB,IAAI,OAAO;AAC/C,MAAI,WAAW,KAAA,EAAW,QAAO;EACjC,MAAM,SAAS,mBAAmB,OAAO,GAAG,IAAI,IAAI,GAAG,OAAO,YAAY;AAC1E,uBAAqB,IAAI,QAAQ,OAAO;AACxC,SAAO;;CAGT,MAAM,cACJ,KACA,WACqD;EACrD,MAAM,UAAU,IAAI;EACpB,MAAM,MAAM,OAAO,MAAM,EAAE,QAAQ,CAAC,IAAI,OAAO,IAAI,GAAG,KAAA;AAetD,SAbY;GACV;GACA;GACA;GACA;GACA,OAAO;IACL,YAAY;IACZ,wBAAwB,QAAa;AACnC,aAAQ,OAAO,OAAO;;IAEzB;GACF;;AAKH,QAAO;EAKL;EAKA;EAKA;EAKA;EAKA;EAMA;EACD"}
@@ -1 +1,3 @@
1
+ import "../button/style.js";
2
+ import "../table/style.js";
1
3
  import "./style2.css";
@@ -1 +1,3 @@
1
- import { _default } from "./tabs.vue.js";
1
+ import { _default } from "./tabs.vue.js";
2
+ import { _default as _default$1 } from "./tabs-horizontal.vue.js";
3
+ import { _default as _default$2 } from "./tabs-vertical.vue.js";
@@ -1,2 +1,4 @@
1
+ import "../icon/style.js";
2
+ import "../scroll/style.js";
1
3
  import "./style2.css";
2
4
  import "@veltra/directives/ripple/style.js";
@@ -15,152 +15,214 @@
15
15
  * --u-height-small: 24px;
16
16
  */
17
17
  /** 暗色:data-theme 与系统偏好,与 UITheme.injectBuiltInThemes 选择器策略一致 */
18
+ /** shadcn 风格 TabsList:hover 背景底色容器 + 白底活动态;rounded=true 时水平为胶囊状。 */
19
+ /* ===== 复合标签页:bar + content 布局容器 ===== */
18
20
  .u-tabs {
19
21
  display: flex;
20
- }
21
- .u-tabs__header {
22
- flex-shrink: 0;
22
+ gap: var(--u-gap-small);
23
23
  }
24
24
  .u-tabs__content {
25
- flex-grow: 1;
25
+ flex: 1 1 auto;
26
+ width: 100%;
27
+ min-height: 0;
28
+ border-radius: var(--u-radius-default);
26
29
  }
27
- .u-tabs__header-item {
28
- cursor: pointer;
29
- font-weight: 600;
30
- letter-spacing: 1px;
31
- color: var(--u-text-color-main);
32
- user-select: none;
33
- position: relative;
30
+ .u-tabs--top {
31
+ flex-direction: column;
34
32
  }
35
- .u-tabs__header-item::after {
36
- content: "";
37
- position: absolute;
38
- background-color: var(--u-color-primary);
39
- transition-duration: 0.25s;
40
- transition-property: transform;
41
- transition-timing-function: cubic-bezier(0.35, 0, 0.25, 1);
33
+ .u-tabs--bottom {
34
+ flex-direction: column-reverse;
42
35
  }
43
- .u-tabs__header-item {
44
- display: flex;
45
- justify-content: flex-start;
46
- align-items: center;
47
- flex-wrap: nowrap;
36
+ .u-tabs--left {
37
+ flex-direction: row;
48
38
  }
49
- .u-tabs__header-item.is-disabled {
50
- color: var(--u-text-color-disabled);
51
- cursor: not-allowed;
39
+ .u-tabs--left .u-tabs__content {
40
+ height: 100%;
52
41
  }
53
- .u-tabs__header-item.is-active {
54
- color: var(--u-color-primary);
42
+ .u-tabs--right {
43
+ flex-direction: row-reverse;
55
44
  }
56
- .u-tabs__close {
57
- width: 0;
58
- transition-property: width, margin-left;
59
- transition-duration: 0.25s;
60
- margin-left: 0;
45
+ .u-tabs--right .u-tabs__content {
46
+ height: 100%;
61
47
  }
62
- .u-tabs__close-placeholder {
63
- height: 1em;
64
- width: 1em;
65
- margin-left: var(--u-gap-small);
48
+
49
+ /* ===== 标签栏(独立组件):水平 / 垂直 ===== */
50
+ .u-tabs-bar {
51
+ display: inline-flex;
52
+ align-self: flex-start;
53
+ max-width: 100%;
54
+ min-width: 0;
55
+ padding: 0 4px;
56
+ background-color: var(--u-bg-color-hover);
57
+ border-radius: var(--u-radius-default);
58
+ gap: 2px;
66
59
  }
67
- .u-tabs--top .u-tabs__header, .u-tabs--bottom .u-tabs__header {
68
- display: flex;
69
- justify-content: flex-start;
60
+ .u-tabs-bar--horizontal {
70
61
  align-items: center;
71
- flex-wrap: nowrap;
72
- }
73
- .u-tabs--top .u-tabs__header-item::after, .u-tabs--bottom .u-tabs__header-item::after {
74
- bottom: 0;
75
- left: 0;
76
- height: 2px;
77
- width: 100%;
78
- transform: scaleX(0);
79
- }
80
- .u-tabs--top .u-tabs__header-item.is-active::after, .u-tabs--bottom .u-tabs__header-item.is-active::after {
81
- transform: scaleX(1);
62
+ position: relative;
63
+ flex-shrink: 0;
82
64
  }
83
- .u-tabs--top {
65
+ .u-tabs-bar--vertical {
84
66
  flex-direction: column;
85
67
  }
86
- .u-tabs--top .u-tabs__header {
87
- border-bottom: var(--u-border);
68
+ .u-tabs-bar__viewport {
69
+ flex: 1 1 auto;
70
+ min-width: 0;
71
+ padding: 4px 0;
72
+ overflow-x: auto;
73
+ overflow-y: hidden;
74
+ scrollbar-width: none;
88
75
  }
89
- .u-tabs--bottom {
90
- flex-direction: column-reverse;
76
+ .u-tabs-bar__viewport::-webkit-scrollbar {
77
+ display: none;
78
+ }
79
+ .u-tabs-bar__list {
80
+ display: inline-flex;
81
+ flex-wrap: nowrap;
82
+ flex-shrink: 0;
83
+ width: max-content;
84
+ margin: 0;
85
+ padding: 0;
86
+ gap: 2px;
91
87
  }
92
- .u-tabs--bottom .u-tabs__header {
93
- border-top: var(--u-border);
88
+ .u-tabs-bar__item {
89
+ cursor: pointer;
90
+ font-weight: 500;
91
+ letter-spacing: 0.25px;
92
+ color: var(--u-text-color-main);
93
+ user-select: none;
94
+ position: relative;
95
+ border-radius: calc(var(--u-radius-default) - 2px);
96
+ background-color: transparent;
97
+ box-shadow: none;
98
+ border: none;
99
+ outline: none;
100
+ white-space: nowrap;
101
+ display: inline-flex;
102
+ align-items: center;
103
+ justify-content: center;
104
+ gap: 0;
105
+ transition: color 0.2s ease, background-color 0.2s ease, box-shadow 0.2s ease;
94
106
  }
95
- .u-tabs--bottom .u-tabs__header-item {
96
- border-radius: 0 0 var(--u-radius-large) var(--u-radius-large);
107
+ .u-tabs-bar__item:not(.is-active):not(.is-disabled):hover {
108
+ color: var(--u-text-color-title);
97
109
  }
98
- .u-tabs--left .u-tabs__content, .u-tabs--right .u-tabs__content {
99
- height: 100%;
110
+ .u-tabs-bar__item.is-disabled {
111
+ color: var(--u-text-color-disabled);
112
+ cursor: not-allowed;
100
113
  }
101
- .u-tabs--left .u-tabs__header-item::after, .u-tabs--right .u-tabs__header-item::after {
102
- top: 0;
103
- width: 2px;
104
- height: 100%;
105
- transform: scaleY(0);
114
+ .u-tabs-bar__item.is-active {
115
+ color: var(--u-text-color-title);
116
+ background-color: var(--u-bg-color-top);
117
+ box-shadow: 0 1px 2px rgba(15, 23, 42, 0.08), 0 1px 3px rgba(15, 23, 42, 0.06);
106
118
  }
107
- .u-tabs--left .u-tabs__header-item.is-active::after, .u-tabs--right .u-tabs__header-item.is-active::after {
108
- transform: scaleY(1);
119
+ .u-tabs-bar__item-label {
120
+ display: inline-flex;
121
+ align-items: center;
122
+ min-width: 0;
109
123
  }
110
- .u-tabs--left .u-tabs__header {
111
- border-right: var(--u-border);
124
+ .u-tabs-bar__close {
125
+ flex: 0 0 auto;
126
+ display: inline-flex;
127
+ align-items: center;
128
+ justify-content: center;
129
+ width: 16px;
130
+ height: 16px;
131
+ margin-left: 6px;
132
+ overflow: hidden;
133
+ padding: 0;
134
+ border: none;
135
+ background: transparent;
136
+ color: var(--u-text-color-secondary);
137
+ cursor: pointer;
138
+ border-radius: var(--u-radius-default);
139
+ font-size: 12px;
140
+ line-height: 1;
141
+ transition: width 0.18s ease, margin-left 0.18s ease, opacity 0.18s ease, transform 0.18s ease, color 0.15s ease, background-color 0.15s ease;
112
142
  }
113
- .u-tabs--left .u-tabs__header-item {
114
- border-radius: var(--u-radius-large) 0 0 var(--u-radius-large);
115
- justify-content: flex-end;
143
+ .u-tabs-bar__close:hover {
144
+ color: var(--u-text-color-title);
145
+ background-color: rgba(15, 23, 42, 0.08);
116
146
  }
117
- .u-tabs--left .u-tabs__header-item::after {
118
- right: 0;
147
+ .u-tabs-bar__close:active {
148
+ background-color: rgba(15, 23, 42, 0.14);
119
149
  }
120
- .u-tabs--right {
121
- flex-direction: row-reverse;
150
+ .u-tabs-bar--horizontal .u-tabs-bar__item .u-tabs-bar__close {
151
+ width: 0;
152
+ margin-left: 0;
153
+ opacity: 0;
154
+ transform: scale(0.6);
155
+ pointer-events: none;
156
+ }
157
+ .u-tabs-bar--horizontal .u-tabs-bar__item:hover .u-tabs-bar__close {
158
+ width: 16px;
159
+ margin-left: 6px;
160
+ opacity: 1;
161
+ transform: scale(1);
162
+ pointer-events: auto;
163
+ }
164
+ .u-tabs-bar--vertical .u-tabs-bar__item {
165
+ justify-content: space-between;
166
+ }
167
+ .u-tabs-bar__nav {
168
+ flex: 0 0 auto;
169
+ display: inline-flex;
170
+ align-items: center;
171
+ justify-content: center;
172
+ padding: 0;
173
+ border: none;
174
+ background: transparent;
175
+ color: var(--u-text-color-main);
176
+ cursor: pointer;
177
+ user-select: none;
178
+ border-radius: calc(var(--u-radius-default) - 2px);
179
+ transition: color 0.2s ease, background-color 0.2s ease, box-shadow 0.2s ease, opacity 0.2s ease;
122
180
  }
123
- .u-tabs--right .u-tabs__header {
124
- border-left: var(--u-border);
181
+ .u-tabs-bar__nav:hover:not(:disabled) {
182
+ color: var(--u-text-color-title);
183
+ background-color: var(--u-bg-color-top);
184
+ box-shadow: 0 1px 2px rgba(15, 23, 42, 0.08), 0 1px 3px rgba(15, 23, 42, 0.06);
125
185
  }
126
- .u-tabs--right .u-tabs__header-item {
127
- border-radius: 0 var(--u-radius-large) var(--u-radius-large) 0;
186
+ .u-tabs-bar__nav:disabled {
187
+ cursor: not-allowed;
188
+ opacity: 0.4;
128
189
  }
129
- .u-tabs--right .u-tabs__header-item::after {
130
- left: 0;
190
+ .u-tabs-bar.is-block {
191
+ display: flex;
192
+ width: 100%;
193
+ max-width: 100%;
194
+ align-self: stretch;
131
195
  }
132
- .u-tabs--small .u-tabs__header-item {
133
- height: var(--u-form-component-height-small);
196
+ .u-tabs-bar--small .u-tabs-bar__item {
197
+ height: calc(var(--u-form-component-height-small) - 4px);
134
198
  padding: 0 var(--u-gap-small);
135
199
  }
136
- .u-tabs--small .u-tabs__header-item:hover .u-tabs__close {
137
- width: var(--u-font-size-main-small);
138
- margin-left: var(--u-gap-small);
200
+ .u-tabs-bar--small .u-tabs-bar__nav {
201
+ width: calc(var(--u-form-component-height-small) - 4px);
202
+ height: calc(var(--u-form-component-height-small) - 4px);
139
203
  }
140
- .u-tabs--default .u-tabs__header-item {
141
- height: var(--u-form-component-height-default);
204
+ .u-tabs-bar--default .u-tabs-bar__item {
205
+ height: calc(var(--u-form-component-height-default) - 4px);
142
206
  padding: 0 var(--u-gap-default);
143
207
  }
144
- .u-tabs--default .u-tabs__header-item:hover .u-tabs__close {
145
- width: var(--u-font-size-main-default);
146
- margin-left: var(--u-gap-small);
208
+ .u-tabs-bar--default .u-tabs-bar__nav {
209
+ width: calc(var(--u-form-component-height-default) - 4px);
210
+ height: calc(var(--u-form-component-height-default) - 4px);
147
211
  }
148
- .u-tabs--large .u-tabs__header-item {
149
- height: var(--u-form-component-height-large);
212
+ .u-tabs-bar--large .u-tabs-bar__item {
213
+ height: calc(var(--u-form-component-height-large) - 4px);
150
214
  padding: 0 var(--u-gap-large);
151
215
  }
152
- .u-tabs--large .u-tabs__header-item:hover .u-tabs__close {
153
- width: var(--u-font-size-main-large);
154
- margin-left: var(--u-gap-small);
216
+ .u-tabs-bar--large .u-tabs-bar__nav {
217
+ width: calc(var(--u-form-component-height-large) - 4px);
218
+ height: calc(var(--u-form-component-height-large) - 4px);
155
219
  }
156
- .u-tabs--left .u-tabs__close, .u-tabs--right .u-tabs__close {
157
- width: auto;
220
+ .u-tabs-bar.is-rounded .u-tabs-bar__item {
221
+ border-radius: 9999px;
158
222
  }
159
- .u-tabs__content {
160
- width: 100%;
161
- border-radius: var(--u-radius-default);
223
+ .u-tabs-bar.is-rounded .u-tabs-bar__nav {
224
+ border-radius: 9999px;
162
225
  }
163
- .u-tabs__ripple {
164
- background-color: var(--u-color-primary);
165
- opacity: 0.1;
226
+ .u-tabs-bar--horizontal.is-rounded {
227
+ border-radius: 9999px;
166
228
  }