niuma-ui 1.0.0 → 1.0.2

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 (159) hide show
  1. package/CHANGELOG.md +50 -1
  2. package/NOTICE +2 -2
  3. package/package.json +13 -5
  4. package/src/__tests__/RsButton.spec.ts +47 -0
  5. package/src/__tests__/RsCard.spec.ts +160 -1
  6. package/src/__tests__/RsConfirmDialog.spec.ts +127 -0
  7. package/src/__tests__/RsContextMenu.spec.ts +12 -0
  8. package/src/__tests__/RsDateTimePicker.spec.ts +11 -0
  9. package/src/__tests__/RsDescriptions.spec.ts +50 -0
  10. package/src/__tests__/RsDialog.spec.ts +117 -0
  11. package/src/__tests__/RsDrawer.spec.ts +96 -3
  12. package/src/__tests__/RsDynamicTags.spec.ts +52 -0
  13. package/src/__tests__/RsForm.spec.ts +245 -1
  14. package/src/__tests__/RsInput.spec.ts +15 -1
  15. package/src/__tests__/RsMenu.spec.ts +406 -14
  16. package/src/__tests__/RsPagination.spec.ts +67 -2
  17. package/src/__tests__/RsSelect.spec.ts +42 -1
  18. package/src/__tests__/RsSwitch.spec.ts +44 -0
  19. package/src/__tests__/RsTable.a11y.spec.ts +83 -0
  20. package/src/__tests__/RsTable.dom-baseline.spec.ts +87 -0
  21. package/src/__tests__/RsTable.perf.spec.ts +23 -4
  22. package/src/__tests__/RsTable.spec.ts +63 -8
  23. package/src/__tests__/RsTable.ssr.spec.ts +71 -0
  24. package/src/__tests__/RsTable.summary.spec.ts +45 -0
  25. package/src/__tests__/RsTabs.spec.ts +102 -4
  26. package/src/__tests__/RsTerminal.spec.ts +1 -1
  27. package/src/__tests__/RsTimePicker.spec.ts +11 -0
  28. package/src/__tests__/RsUpload.spec.ts +62 -6
  29. package/src/__tests__/createRsDialog.spec.ts +145 -0
  30. package/src/__tests__/form-rules.spec.ts +76 -0
  31. package/src/__tests__/perf-budgets.ts +32 -0
  32. package/src/__tests__/rs-table-api.spec.ts +206 -0
  33. package/src/__tests__/rs-table-compat-matrix.spec.ts +108 -0
  34. package/src/__tests__/rs-table-echarts-adapter.spec.ts +43 -0
  35. package/src/__tests__/rs-table-grid-nav.spec.ts +63 -0
  36. package/src/__tests__/rs-table-isolation.spec.ts +158 -0
  37. package/src/__tests__/split-pane-utils.spec.ts +21 -0
  38. package/src/__tests__/table-chart-utils.spec.ts +88 -0
  39. package/src/__tests__/table-summary-utils.spec.ts +62 -0
  40. package/src/__tests__/table-utils.spec.ts +124 -0
  41. package/src/__tests__/theme.spec.ts +25 -0
  42. package/src/__tests__/useRsTableColumnResize.spec.ts +25 -0
  43. package/src/__tests__/useRsTableCore.perf.spec.ts +170 -0
  44. package/src/components/RsAlert.vue +212 -0
  45. package/src/components/RsButton.vue +145 -21
  46. package/src/components/RsCard.vue +200 -16
  47. package/src/components/RsConfirmDialog.vue +215 -28
  48. package/src/components/RsContextMenu.vue +51 -13
  49. package/src/components/RsDatePicker.vue +267 -34
  50. package/src/components/RsDateTimePicker.vue +19 -2
  51. package/src/components/RsDescriptions.vue +186 -0
  52. package/src/components/RsDescriptionsItem.vue +32 -0
  53. package/src/components/RsDialog.vue +363 -51
  54. package/src/components/RsDivider.vue +89 -0
  55. package/src/components/RsDrawer.vue +558 -33
  56. package/src/components/RsDropdown.vue +33 -2
  57. package/src/components/RsDynamicTags.vue +517 -0
  58. package/src/components/RsForm.vue +97 -8
  59. package/src/components/RsInput.vue +80 -82
  60. package/src/components/RsInputNumber.vue +64 -23
  61. package/src/components/RsLabel.vue +20 -5
  62. package/src/components/RsLoadingBar.vue +151 -0
  63. package/src/components/RsMenu.vue +73 -15
  64. package/src/components/RsMenuItems.vue +147 -9
  65. package/src/components/RsPagination.vue +93 -14
  66. package/src/components/RsRadio.vue +81 -0
  67. package/src/components/RsRadioItem.vue +156 -0
  68. package/src/components/RsSelect.vue +67 -58
  69. package/src/components/RsSplitPane.vue +69 -1
  70. package/src/components/RsSwitch.vue +179 -0
  71. package/src/components/RsTable.vue +653 -2555
  72. package/src/components/RsTabs.vue +415 -83
  73. package/src/components/RsTag.vue +191 -0
  74. package/src/components/RsTerminal.vue +3 -3
  75. package/src/components/RsTimePicker.vue +44 -5
  76. package/src/components/RsTimePickerColumns.vue +136 -77
  77. package/src/components/RsToaster.vue +58 -18
  78. package/src/components/RsTree.vue +39 -21
  79. package/src/components/RsUpload.vue +145 -12
  80. package/src/components/RsVNodeHost.vue +20 -0
  81. package/src/components/button-utils.ts +39 -0
  82. package/src/components/context-menu-utils.ts +6 -0
  83. package/src/components/date-picker-utils.ts +84 -4
  84. package/src/components/descriptions-utils.ts +24 -0
  85. package/src/components/dialog-utils.ts +147 -0
  86. package/src/components/dialog-window.ts +74 -9
  87. package/src/components/drawer-utils.ts +73 -0
  88. package/src/components/form-rules.ts +257 -0
  89. package/src/components/form-utils.ts +52 -2
  90. package/src/components/menu-utils.ts +11 -0
  91. package/src/components/overlay-utils.ts +3 -0
  92. package/src/components/radio-utils.ts +12 -0
  93. package/src/components/reka.ts +5 -0
  94. package/src/components/select-utils.ts +21 -2
  95. package/src/components/split-pane-utils.ts +65 -12
  96. package/src/components/table/RsTableBody.vue +217 -0
  97. package/src/components/table/RsTableBodyRow.vue +90 -1
  98. package/src/components/table/RsTableColGroup.vue +41 -0
  99. package/src/components/table/RsTableHeader.vue +158 -0
  100. package/src/components/table/RsTableSummaryRow.vue +52 -0
  101. package/src/components/table/rs-table-api.ts +99 -0
  102. package/src/components/table/rs-table-compat-matrix.ts +71 -0
  103. package/src/components/table/rs-table-echarts-adapter.ts +81 -0
  104. package/src/components/table/rs-table-feature-host.ts +178 -0
  105. package/src/components/table/rs-table-grid-nav.ts +122 -0
  106. package/src/components/table/rs-table-header-types.ts +47 -0
  107. package/src/components/table/rs-table-module-registry.ts +72 -0
  108. package/src/components/table/rs-table-props.ts +274 -0
  109. package/src/components/table/rs-table-view-context.ts +258 -0
  110. package/src/components/table/rs-table.css +84 -6
  111. package/src/components/table/table-chart-utils.ts +165 -0
  112. package/src/components/table/table-features.ts +284 -0
  113. package/src/components/table/table-summary-utils.ts +194 -0
  114. package/src/components/table-utils.ts +452 -2
  115. package/src/components/tabs-utils.ts +142 -2
  116. package/src/components/terminal-utils.ts +1 -1
  117. package/src/components/terminal-wheel.ts +1 -1
  118. package/src/components/time-picker-utils.ts +76 -3
  119. package/src/components/upload-utils.ts +122 -0
  120. package/src/components/virtual-list-utils.ts +15 -2
  121. package/src/composables/assembleRsTableApi.ts +79 -0
  122. package/src/composables/bindRsTableViewContext.ts +269 -0
  123. package/src/composables/createRsDialog.ts +357 -0
  124. package/src/composables/createRsTableEditEmitBridge.ts +38 -0
  125. package/src/composables/useRsLoadingBar.ts +36 -0
  126. package/src/composables/useRsTable.ts +134 -0
  127. package/src/composables/useRsTableA11y.ts +52 -0
  128. package/src/composables/useRsTableChartBridge.ts +79 -0
  129. package/src/composables/useRsTableColumnLayout.ts +320 -0
  130. package/src/composables/useRsTableColumnResize.ts +244 -0
  131. package/src/composables/useRsTableColumnVirtual.ts +180 -0
  132. package/src/composables/useRsTableColumns.ts +200 -0
  133. package/src/composables/useRsTableContextMenu.ts +257 -0
  134. package/src/composables/useRsTableCore.ts +256 -0
  135. package/src/composables/useRsTableEditActions.ts +606 -0
  136. package/src/composables/useRsTableEditLayer.ts +251 -0
  137. package/src/composables/useRsTableEngine.ts +357 -0
  138. package/src/composables/useRsTableGridKeyboard.ts +123 -0
  139. package/src/composables/useRsTableHeadless.ts +137 -0
  140. package/src/composables/useRsTableInteraction.ts +433 -0
  141. package/src/composables/useRsTableScrollHost.ts +75 -0
  142. package/src/composables/useRsTableScrollLayout.ts +255 -0
  143. package/src/composables/useRsTableSelectionSource.ts +89 -0
  144. package/src/composables/useRsTableShell.ts +416 -0
  145. package/src/composables/useRsTableShellChrome.ts +170 -0
  146. package/src/composables/useRsTableSummary.ts +113 -0
  147. package/src/composables/useRsTableViewProvide.ts +263 -0
  148. package/src/composables/useRsTableVirtual.ts +154 -0
  149. package/src/composables/useRsTabsNav.ts +4 -0
  150. package/src/composables/useTableEdit.ts +1 -1
  151. package/src/icons/lucide.ts +2 -2
  152. package/src/index.ts +309 -9
  153. package/src/locale/messages.ts +30 -0
  154. package/src/styles.css +305 -52
  155. package/src/theme/brand.example.css +21 -2
  156. package/src/theme/presets.ts +4 -0
  157. package/src/theme/types.ts +67 -0
  158. package/src/components/RsTableColgroup.vue +0 -17
  159. package/src/components/RsTableHeaderRow.vue +0 -30
@@ -0,0 +1,263 @@
1
+ /**
2
+ * 将 Core/Shell/Edit 装配结果安装为实例级 ViewContext。
3
+ *
4
+ * 从 RsTable.vue 下沉大块 provide 装配,便于壳层只做接线。
5
+ * 多表:每次调用 provide 到当前实例树,互不串扰。
6
+ */
7
+
8
+ import type { ComputedRef, Ref } from 'vue'
9
+ import { isColumnFilterActive } from '../components/table-utils'
10
+ import type {
11
+ RsTableColumn,
12
+ RsTableRowData,
13
+ RsTableRowDropPosition,
14
+ RsTableRowEntry,
15
+ RsTableRowKey,
16
+ RsTableSelectionType,
17
+ } from '../components/table-utils'
18
+ import type { RsTableCellEditFocusMode, RsTableCellEditTrigger } from '../components/table/table-edit-utils'
19
+ import {
20
+ createRsTableViewContext,
21
+ provideRsTableView,
22
+ type RsTableBodyLabels,
23
+ type RsTableHeaderLabels,
24
+ type RsTableViewContext,
25
+ type RsTableViewStyle,
26
+ } from '../components/table/rs-table-view-context'
27
+
28
+ type RowEntry<T extends RsTableRowData> = Extract<RsTableRowEntry<T>, { type: 'row' }>
29
+
30
+ function val<T>(source: Ref<T> | ComputedRef<T> | (() => T)): () => T {
31
+ if (typeof source === 'function') return source as () => T
32
+ return () => (source as Ref<T>).value
33
+ }
34
+
35
+ /** ViewContext 安装所需的状态源(getter / Ref 均可) */
36
+ export interface RsTableViewProvideSources<T extends RsTableRowData> {
37
+ useFixedColumnLayout: Ref<boolean> | ComputedRef<boolean> | (() => boolean)
38
+ showRowDragHandle: Ref<boolean> | ComputedRef<boolean> | (() => boolean)
39
+ detailExpandable: Ref<boolean> | ComputedRef<boolean> | (() => boolean)
40
+ showSelectColumn: Ref<boolean> | ComputedRef<boolean> | (() => boolean)
41
+ showEditGutterColumn: Ref<boolean> | ComputedRef<boolean> | (() => boolean)
42
+ showIndexColumn: Ref<boolean> | ComputedRef<boolean> | (() => boolean)
43
+ showRowStatusColumn: Ref<boolean> | ComputedRef<boolean> | (() => boolean)
44
+ columnPadLeft: Ref<number> | ComputedRef<number> | (() => number)
45
+ columnPadRight: Ref<number> | ComputedRef<number> | (() => number)
46
+ visibleDataColumns: Ref<RsTableColumn<T>[]> | ComputedRef<RsTableColumn<T>[]> | (() => RsTableColumn<T>[])
47
+ prefixWidths: { drag: number; expand: number; select: number; status: number }
48
+ resolvedGutterWidth: Ref<number> | ComputedRef<number> | (() => number)
49
+ resolvedIndexWidth: Ref<number> | ComputedRef<number> | (() => number)
50
+ isRadioSelection: Ref<boolean> | ComputedRef<boolean> | (() => boolean)
51
+ selectAllState: Ref<'checked' | 'indeterminate' | 'unchecked'> | ComputedRef<'checked' | 'indeterminate' | 'unchecked'> | (() => 'checked' | 'indeterminate' | 'unchecked')
52
+ columnDraggable: () => boolean
53
+ resizable: () => boolean
54
+ multiSort: () => boolean
55
+ columnFiltersState: Ref<Record<string, string>> | ComputedRef<Record<string, string>> | (() => Record<string, string>)
56
+ dragColumnKey: Ref<string | null> | (() => string | null)
57
+ dropColumnKey: Ref<string | null> | (() => string | null)
58
+ dragLeadHeaderStyle: Ref<RsTableViewStyle> | ComputedRef<RsTableViewStyle> | (() => RsTableViewStyle)
59
+ expandLeadHeaderStyle: Ref<RsTableViewStyle> | ComputedRef<RsTableViewStyle> | (() => RsTableViewStyle)
60
+ selectLeadHeaderStyle: Ref<RsTableViewStyle> | ComputedRef<RsTableViewStyle> | (() => RsTableViewStyle)
61
+ gutterLeadHeaderStyle: Ref<RsTableViewStyle> | ComputedRef<RsTableViewStyle> | (() => RsTableViewStyle)
62
+ indexLeadHeaderStyle: Ref<RsTableViewStyle> | ComputedRef<RsTableViewStyle> | (() => RsTableViewStyle)
63
+ columnHeaderStyleMap: Ref<Map<string, Record<string, string> | undefined>> | ComputedRef<Map<string, Record<string, string> | undefined>> | (() => Map<string, Record<string, string> | undefined>)
64
+ headerLabels: Ref<RsTableHeaderLabels> | ComputedRef<RsTableHeaderLabels> | (() => RsTableHeaderLabels)
65
+ loading: () => boolean
66
+ hasData: Ref<boolean> | ComputedRef<boolean> | (() => boolean)
67
+ loadingMore: () => boolean
68
+ infinite: () => boolean
69
+ bodyColspan: Ref<number> | ComputedRef<number> | (() => number)
70
+ emptyContentStyle: Ref<RsTableViewStyle> | ComputedRef<RsTableViewStyle> | (() => RsTableViewStyle)
71
+ virtualScrollEnabled: Ref<boolean> | ComputedRef<boolean> | (() => boolean)
72
+ virtualSlice: Ref<{ paddingTop: number; paddingBottom: number }> | ComputedRef<{ paddingTop: number; paddingBottom: number }> | (() => { paddingTop: number; paddingBottom: number })
73
+ visibleEntries: Ref<RsTableRowEntry<T>[]> | ComputedRef<RsTableRowEntry<T>[]> | (() => RsTableRowEntry<T>[])
74
+ rowKey: () => RsTableRowKey<T> | undefined
75
+ treeMode: Ref<boolean> | ComputedRef<boolean> | (() => boolean)
76
+ treeIndentPx: Ref<number> | ComputedRef<number> | (() => number)
77
+ treeExpandColumnKey: Ref<string | null> | ComputedRef<string | null> | (() => string | null)
78
+ treeLoadingKeySet: Ref<Set<string>> | ComputedRef<Set<string>> | (() => Set<string>)
79
+ striped: () => boolean
80
+ selectionType: () => RsTableSelectionType
81
+ editable: () => boolean
82
+ editTrigger: () => RsTableCellEditTrigger
83
+ rowCommit: () => boolean
84
+ allowNull: () => boolean
85
+ editFocusMode: () => RsTableCellEditFocusMode
86
+ nullLabel: () => string
87
+ dragLeadStyle: Ref<Record<string, string>> | ComputedRef<Record<string, string>> | (() => Record<string, string>)
88
+ expandLeadStyle: Ref<Record<string, string>> | ComputedRef<Record<string, string>> | (() => Record<string, string>)
89
+ selectLeadStyle: Ref<Record<string, string>> | ComputedRef<Record<string, string>> | (() => Record<string, string>)
90
+ indexLeadStyle: Ref<Record<string, string>> | ComputedRef<Record<string, string>> | (() => Record<string, string>)
91
+ gutterLeadStyle: Ref<Record<string, string>> | ComputedRef<Record<string, string>> | (() => Record<string, string>)
92
+ columnTdClassMap: Ref<Map<string, string[]>> | ComputedRef<Map<string, string[]>> | (() => Map<string, string[]>)
93
+ columnStyleMap: Ref<Map<string, Record<string, string> | undefined>> | ComputedRef<Map<string, Record<string, string> | undefined>> | (() => Map<string, Record<string, string> | undefined>)
94
+ dragRowKeys: Ref<string[]> | (() => string[])
95
+ dropRowTargetKey: Ref<string | null> | (() => string | null)
96
+ dropRowPosition: Ref<RsTableRowDropPosition | null> | (() => RsTableRowDropPosition | null)
97
+ activeEditCellKey: Ref<string> | ComputedRef<string> | (() => string)
98
+ activeFocusCellKey: Ref<string> | ComputedRef<string> | (() => string)
99
+ activeErrorMapSize: Ref<number> | ComputedRef<number> | (() => number)
100
+ activeValidatingMapSize: Ref<number> | ComputedRef<number> | (() => number)
101
+ stagedMapSize: () => number
102
+ editingDraft: () => string
103
+ editingCell: () => { rowKey: string; colKey: string } | null
104
+ focusCell: () => { rowKey: string; colKey: string } | null
105
+ bodyLabels: Ref<RsTableBodyLabels> | ComputedRef<RsTableBodyLabels> | (() => RsTableBodyLabels)
106
+ }
107
+
108
+ export type RsTableViewProvideHandlers<T extends RsTableRowData> = Pick<
109
+ RsTableViewContext<T>,
110
+ | 'resolvedDataColumnWidth'
111
+ | 'columnFilterValue'
112
+ | 'sortOrderFor'
113
+ | 'sortPriorityFor'
114
+ | 'sortIconName'
115
+ | 'onToggleSelectAll'
116
+ | 'onColumnDragOver'
117
+ | 'onColumnDrop'
118
+ | 'onColumnDragStart'
119
+ | 'onColumnDragEnd'
120
+ | 'updateColumnFilter'
121
+ | 'onHeaderClick'
122
+ | 'onResizeStart'
123
+ | 'onHeaderPointerOver'
124
+ | 'onHeaderPointerOut'
125
+ | 'rowKeyFor'
126
+ | 'isRowSelected'
127
+ | 'isRowIndeterminate'
128
+ | 'isRowExpanded'
129
+ | 'isHighlighted'
130
+ | 'rowEditPending'
131
+ | 'isExternalRowPending'
132
+ | 'treeDepthOf'
133
+ | 'canExpandRow'
134
+ | 'canSelectRow'
135
+ | 'isRowDragByRow'
136
+ | 'isRowDragging'
137
+ | 'isRowDropTarget'
138
+ | 'isRowDirty'
139
+ | 'hasColumnSlot'
140
+ | 'hasEditSlot'
141
+ | 'cellTooltipEnabled'
142
+ | 'cellTooltipMode'
143
+ | 'cellTooltipText'
144
+ | 'cellTooltipFallbackTitle'
145
+ | 'getCellDraft'
146
+ | 'isCellDirty'
147
+ | 'getCellError'
148
+ | 'isCellValidating'
149
+ | 'onBodyPointerOver'
150
+ | 'onBodyPointerOut'
151
+ | 'onRowClick'
152
+ | 'onRowSelectMouseDown'
153
+ | 'onCellClick'
154
+ | 'onCellDblclick'
155
+ | 'onCellContextmenu'
156
+ | 'onRowDblclick'
157
+ | 'onRowContextmenu'
158
+ | 'onRowDragOver'
159
+ | 'onRowDragLeave'
160
+ | 'onRowDrop'
161
+ | 'onRowDragStart'
162
+ | 'onRowDragEnd'
163
+ | 'onToggleExpand'
164
+ | 'onToggleSelect'
165
+ | 'onCellStartEdit'
166
+ | 'onCellCommit'
167
+ | 'onCellCancel'
168
+ | 'onCellUpdateDraft'
169
+ | 'onCellNavigate'
170
+ | 'onRowCommit'
171
+ | 'onRowRollback'
172
+ | 'onGutterCommit'
173
+ >
174
+
175
+ /**
176
+ * 装配并 provide ViewContext;返回 ctx(便于测试读 instanceId)。
177
+ */
178
+ export function useRsTableViewProvide<T extends RsTableRowData>(
179
+ sources: RsTableViewProvideSources<T>,
180
+ handlers: RsTableViewProvideHandlers<T>,
181
+ ): RsTableViewContext<T> {
182
+ const ctx = createRsTableViewContext<T>({
183
+ state: {
184
+ useFixedColumnLayout: val(sources.useFixedColumnLayout),
185
+ showRowDragHandle: val(sources.showRowDragHandle),
186
+ detailExpandable: val(sources.detailExpandable),
187
+ showSelectColumn: val(sources.showSelectColumn),
188
+ showEditGutterColumn: val(sources.showEditGutterColumn),
189
+ showIndexColumn: val(sources.showIndexColumn),
190
+ showRowStatusColumn: val(sources.showRowStatusColumn),
191
+ columnPadLeft: val(sources.columnPadLeft),
192
+ columnPadRight: val(sources.columnPadRight),
193
+ visibleDataColumns: val(sources.visibleDataColumns),
194
+ prefixWidths: () => sources.prefixWidths,
195
+ resolvedGutterWidth: val(sources.resolvedGutterWidth),
196
+ resolvedIndexWidth: val(sources.resolvedIndexWidth),
197
+ isRadioSelection: val(sources.isRadioSelection),
198
+ selectAllState: val(sources.selectAllState),
199
+ columnDraggable: sources.columnDraggable,
200
+ resizable: sources.resizable,
201
+ multiSort: sources.multiSort,
202
+ columnFiltersState: val(sources.columnFiltersState),
203
+ dragColumnKey: val(sources.dragColumnKey),
204
+ dropColumnKey: val(sources.dropColumnKey),
205
+ dragLeadHeaderStyle: val(sources.dragLeadHeaderStyle),
206
+ expandLeadHeaderStyle: val(sources.expandLeadHeaderStyle),
207
+ selectLeadHeaderStyle: val(sources.selectLeadHeaderStyle),
208
+ gutterLeadHeaderStyle: val(sources.gutterLeadHeaderStyle),
209
+ indexLeadHeaderStyle: val(sources.indexLeadHeaderStyle),
210
+ columnHeaderStyleMap: val(sources.columnHeaderStyleMap),
211
+ headerLabels: val(sources.headerLabels),
212
+ loading: sources.loading,
213
+ hasData: val(sources.hasData),
214
+ loadingMore: sources.loadingMore,
215
+ infinite: sources.infinite,
216
+ bodyColspan: val(sources.bodyColspan),
217
+ emptyContentStyle: val(sources.emptyContentStyle),
218
+ virtualScrollEnabled: val(sources.virtualScrollEnabled),
219
+ virtualSlice: val(sources.virtualSlice),
220
+ visibleEntries: val(sources.visibleEntries),
221
+ rowKey: sources.rowKey,
222
+ treeMode: val(sources.treeMode),
223
+ treeIndentPx: val(sources.treeIndentPx),
224
+ treeExpandColumnKey: val(sources.treeExpandColumnKey),
225
+ treeLoadingKeySet: val(sources.treeLoadingKeySet),
226
+ striped: sources.striped,
227
+ selectionType: sources.selectionType,
228
+ editable: sources.editable,
229
+ editTrigger: sources.editTrigger,
230
+ rowCommit: sources.rowCommit,
231
+ allowNull: sources.allowNull,
232
+ editFocusMode: sources.editFocusMode,
233
+ nullLabel: sources.nullLabel,
234
+ dragLeadStyle: val(sources.dragLeadStyle),
235
+ expandLeadStyle: val(sources.expandLeadStyle),
236
+ selectLeadStyle: val(sources.selectLeadStyle),
237
+ indexLeadStyle: val(sources.indexLeadStyle),
238
+ gutterLeadStyle: val(sources.gutterLeadStyle),
239
+ columnTdClassMap: val(sources.columnTdClassMap),
240
+ columnStyleMap: val(sources.columnStyleMap),
241
+ dragRowKeys: val(sources.dragRowKeys),
242
+ dropRowTargetKey: val(sources.dropRowTargetKey),
243
+ dropRowPosition: val(sources.dropRowPosition),
244
+ activeEditCellKey: val(sources.activeEditCellKey),
245
+ activeFocusCellKey: val(sources.activeFocusCellKey),
246
+ activeErrorMapSize: val(sources.activeErrorMapSize),
247
+ activeValidatingMapSize: val(sources.activeValidatingMapSize),
248
+ stagedMapSize: sources.stagedMapSize,
249
+ editingDraft: sources.editingDraft,
250
+ editingCell: sources.editingCell,
251
+ focusCell: sources.focusCell,
252
+ bodyLabels: val(sources.bodyLabels),
253
+ },
254
+ handlers: {
255
+ ...handlers,
256
+ isColumnFilterActive,
257
+ },
258
+ })
259
+ provideRsTableView(ctx)
260
+ return ctx
261
+ }
262
+
263
+ export type { RowEntry }
@@ -0,0 +1,154 @@
1
+ /**
2
+ * RsTable 行虚拟滚动:启用判定、高度前缀和、可视窗口切片。
3
+ *
4
+ * 横向列虚拟见 useRsTableColumnVirtual;滚动/视口见 useRsTableScrollLayout。
5
+ * 本 composable 只消费已算好的 `tableEntries`,不参与 entries 构建,避免循环依赖。
6
+ */
7
+
8
+ import { computed, type ComputedRef, type Ref } from 'vue'
9
+ import {
10
+ buildVirtualHeightModel,
11
+ getTableTreeChildren,
12
+ hasTableTreeChildren,
13
+ resolveTableTreeRowKey,
14
+ sliceVirtualHeightModel,
15
+ type RsTableRowData,
16
+ type RsTableRowEntry,
17
+ type RsTableRowKey,
18
+ } from '../components/table-utils'
19
+
20
+ /**
21
+ * useRsTableVirtual 入参。
22
+ * `tableEntriesForThreshold` 用于 auto 阈值,不可直接依赖完整 tableEntries(会循环)。
23
+ */
24
+ export interface UseRsTableVirtualOptions<T extends RsTableRowData> {
25
+ /** 根数据行数(非树表阈值用) */
26
+ dataLength: ComputedRef<number> | (() => number)
27
+ treeMode: ComputedRef<boolean> | (() => boolean)
28
+ /** 树表当前展开态下的可见条目粗算 */
29
+ tableEntriesForThreshold: ComputedRef<number> | (() => number)
30
+ /** virtual prop:true 强制开 / false 强制关 / undefined 走 auto */
31
+ virtual: ComputedRef<boolean | undefined> | (() => boolean | undefined)
32
+ /** auto 模式下的行数阈值 */
33
+ virtualAutoThreshold: ComputedRef<number> | (() => number)
34
+ /** fill 为 true 时才允许 auto 开启虚拟(需确定视口高度) */
35
+ fill: ComputedRef<boolean> | (() => boolean)
36
+ infinite: ComputedRef<boolean> | (() => boolean)
37
+ /** infinite 时默认开启虚拟;可显式关掉 */
38
+ virtualOnInfinite: ComputedRef<boolean> | (() => boolean)
39
+ overscan: ComputedRef<number> | (() => number)
40
+ expandRowHeight: ComputedRef<number | undefined> | (() => number | undefined)
41
+ scrollTop: Ref<number>
42
+ viewportHeight: ComputedRef<number> | (() => number)
43
+ fixedRowHeight: ComputedRef<number> | (() => number)
44
+ /** 完整 entry 列表(含 group / expand 伪行) */
45
+ tableEntries: ComputedRef<RsTableRowEntry<T>[]> | (() => RsTableRowEntry<T>[])
46
+ }
47
+
48
+ /** 统一读取 ComputedRef / Ref / getter */
49
+ function read<T>(source: ComputedRef<T> | (() => T) | Ref<T>): T {
50
+ if (typeof source === 'function') return (source as () => T)()
51
+ return (source as Ref<T> | ComputedRef<T>).value
52
+ }
53
+
54
+ /**
55
+ * 树表展开态下的可见行粗算,供 virtual 自动阈值使用。
56
+ * 仅统计当前 expandedKeys 下可见节点,不做完整 entry 构建。
57
+ *
58
+ * @param rows 根节点列表
59
+ * @param expandedKeys 已展开行 key 集合
60
+ * @param options 树字段与 rowKey 约定
61
+ * @returns 可见行数量(含未展开的叶子占位行本身)
62
+ */
63
+ export function flattenVisibleCountRough<R extends RsTableRowData>(
64
+ rows: readonly R[],
65
+ expandedKeys: ReadonlySet<string>,
66
+ options: {
67
+ childrenField: string
68
+ isLeafField: string
69
+ lazy: boolean
70
+ rowKey?: RsTableRowKey<R>
71
+ },
72
+ ): number {
73
+ let count = 0
74
+ const walk = (items: readonly R[], parentKey: string | null) => {
75
+ for (let i = 0; i < items.length; i += 1) {
76
+ const row = items[i] as R
77
+ count += 1
78
+ const key = resolveTableTreeRowKey(row, i, parentKey, options.rowKey)
79
+ if (hasTableTreeChildren(row, options) && expandedKeys.has(key)) {
80
+ walk(getTableTreeChildren(row, options.childrenField), key)
81
+ }
82
+ }
83
+ }
84
+ walk(rows, null)
85
+ return count
86
+ }
87
+
88
+ /**
89
+ * 行虚拟滚动状态。
90
+ *
91
+ * @returns
92
+ * - `virtualScrollEnabled`:是否启用行虚拟
93
+ * - `virtualHeightModel`:前缀高度模型(总高 / 定位)
94
+ * - `virtualSlice`:当前窗口 entries + 上下 pad
95
+ * - `visibleEntries`:切片后的 entries(模板渲染用)
96
+ */
97
+ export function useRsTableVirtual<T extends RsTableRowData>(options: UseRsTableVirtualOptions<T>) {
98
+ /**
99
+ * 启用规则:
100
+ * 1. virtual === true → 开
101
+ * 2. infinite 且未关闭 virtualOnInfinite → 开
102
+ * 3. virtual === false → 关
103
+ * 4. 否则 auto:fill 且行数 >= threshold
104
+ */
105
+ const virtualScrollEnabled = computed(() => {
106
+ if (read(options.virtual) === true) return true
107
+ if (read(options.infinite) && read(options.virtualOnInfinite) !== false) return true
108
+ if (read(options.virtual) === false) return false
109
+ const threshold = read(options.virtualAutoThreshold) ?? 0
110
+ const rowCount = read(options.treeMode)
111
+ ? read(options.tableEntriesForThreshold)
112
+ : read(options.dataLength)
113
+ return Boolean(read(options.fill) && threshold > 0 && rowCount >= threshold)
114
+ })
115
+
116
+ /** 全量 entries 的高度前缀和模型 */
117
+ const virtualHeightModel = computed(() =>
118
+ buildVirtualHeightModel(
119
+ read(options.tableEntries),
120
+ read(options.fixedRowHeight),
121
+ undefined,
122
+ (read(options.expandRowHeight) ?? undefined) as 80 | undefined,
123
+ ),
124
+ )
125
+
126
+ /**
127
+ * 可视切片。未启用虚拟时返回全部 entries,pad 为 0。
128
+ */
129
+ const virtualSlice = computed(() => {
130
+ if (!virtualScrollEnabled.value) {
131
+ const entries = read(options.tableEntries)
132
+ return { entries, paddingTop: 0, paddingBottom: 0 }
133
+ }
134
+ return sliceVirtualHeightModel(
135
+ virtualHeightModel.value,
136
+ options.scrollTop.value,
137
+ read(options.viewportHeight),
138
+ read(options.fixedRowHeight),
139
+ read(options.overscan),
140
+ )
141
+ })
142
+
143
+ const visibleEntries = computed(() => virtualSlice.value.entries)
144
+
145
+ return {
146
+ virtualScrollEnabled,
147
+ virtualHeightModel,
148
+ virtualSlice,
149
+ visibleEntries,
150
+ }
151
+ }
152
+
153
+ /** useRsTableVirtual 返回值类型 */
154
+ export type RsTableVirtualApi<T extends RsTableRowData> = ReturnType<typeof useRsTableVirtual<T>>
@@ -18,6 +18,8 @@ interface UseRsTabsNavOptions {
18
18
  navRef: Ref<HTMLElement | null>
19
19
  measureRef: Ref<HTMLElement | null>
20
20
  overflowRef: Ref<HTMLElement | null>
21
+ /** 右侧 #extra 区域,计入下拉溢出预留宽度 */
22
+ extraRef?: Ref<HTMLElement | null>
21
23
  addButtonWidth: number
22
24
  }
23
25
 
@@ -80,6 +82,8 @@ export function useRsTabsNav(options: UseRsTabsNavOptions) {
80
82
  width += options.overflowRef.value?.offsetWidth ?? 76
81
83
  }
82
84
  if (options.canAdd.value) width += options.addButtonWidth
85
+ // 顶栏右侧操作区不参与标签折叠预算,需从可用宽度中扣除
86
+ width += options.extraRef?.value?.offsetWidth ?? 0
83
87
  return width
84
88
  }
85
89
 
@@ -33,7 +33,7 @@ export interface RsTableUndoEntry {
33
33
 
34
34
  export function useTableEdit(options: {
35
35
  enabled: () => boolean
36
- undoLimit?: () => number
36
+ undoLimit?: () => number | undefined
37
37
  }): {
38
38
  editingCell: Ref<RsTableEditingCell | null>
39
39
  editingDraft: Ref<string>
@@ -34,12 +34,12 @@ const customIconMap = new Map<string, Component>([
34
34
 
35
35
  /** Vite 构建时收集全部 Lucide 图标,运行时按名称 O(1) 查找 */
36
36
  const iconModules = import.meta.glob<{ default: Component }>(
37
- '../../node_modules/lucide-vue-next/dist/esm/icons/*.js',
37
+ '../../node_modules/@lucide/vue/dist/esm/icons/*.mjs',
38
38
  { eager: true },
39
39
  )
40
40
 
41
41
  const iconMap = new Map<string, Component>(customIconMap)
42
- const iconPathPattern = /[/\\]icons[/\\]([^/\\]+)\.js$/
42
+ const iconPathPattern = /[/\\]icons[/\\]([^/\\]+)\.mjs$/
43
43
 
44
44
  /** Lucide 更名兼容:旧 kebab 名 → 新图标文件名 */
45
45
  const iconAliases = new Map<string, string>([