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,274 @@
1
+ /**
2
+ * RsTable 公开 props / emits / 默认值(从 SFC 抽出,削薄编排层)。
3
+ */
4
+
5
+ import type { RsContextMenuItem } from '../context-menu-utils'
6
+ import type {
7
+ RsTableColumn,
8
+ RsTableGroupBy,
9
+ RsTableRowData,
10
+ RsTableRowDropPosition,
11
+ RsTableRowKey,
12
+ RsTableSelectionType,
13
+ RsTableSize,
14
+ RsTableSortState,
15
+ RsTableTreeConfig,
16
+ } from '../table-utils'
17
+ import type { RsTableRowDragTrigger, RsTableRowDropMode } from '../table-drag'
18
+ import type { RsTableCellEditFocusMode } from './table-edit-utils'
19
+ import type { RsTableFeature } from './table-features'
20
+ import type { RsTableSummaryData, RsTableSummaryMode } from './table-summary-utils'
21
+
22
+ /** RsTable 组件 props */
23
+ export interface RsTableProps<T extends RsTableRowData = RsTableRowData> {
24
+ columns: RsTableColumn<T>[]
25
+ data: T[]
26
+ rowKey?: RsTableRowKey<T>
27
+ loading?: boolean
28
+ bordered?: boolean
29
+ columnBordered?: boolean
30
+ /** 外容器圆角;嵌套在已有圆角/直角父级时可设为 false */
31
+ rounded?: boolean
32
+ /** 填充父级高度:表格自身成为受限滚动容器 */
33
+ fill?: boolean
34
+ compact?: boolean
35
+ size?: RsTableSize
36
+ scrollX?: number | string
37
+ selectable?: boolean
38
+ selectionType?: RsTableSelectionType
39
+ selectedRowKeys?: string[]
40
+ defaultSelectedRowKeys?: string[]
41
+ rowSelectable?: (row: T, index: number) => boolean
42
+ expandable?: boolean
43
+ expandedRowKeys?: string[]
44
+ defaultExpandedRowKeys?: string[]
45
+ rowExpandable?: (row: T, index: number) => boolean
46
+ expandRowHeight?: number
47
+ /**
48
+ * 树形表格:按 children 展平可见行,在指定列缩进展开。
49
+ * 与 `expandable`(明细行)/ `groupBy` 互斥。
50
+ */
51
+ treeConfig?: RsTableTreeConfig<T>
52
+ striped?: boolean
53
+ showIndex?: boolean
54
+ /** 行号列宽度(px,showIndex 且未显示 edit gutter 时生效) */
55
+ indexWidth?: number
56
+ showHeader?: boolean
57
+ remoteSort?: boolean
58
+ filterText?: string
59
+ filterKeys?: string[]
60
+ columnFilters?: Record<string, string>
61
+ defaultColumnFilters?: Record<string, string>
62
+ groupBy?: RsTableGroupBy<T>
63
+ groupLabel?: (key: string) => string
64
+ sort?: RsTableSortState | null
65
+ defaultSort?: RsTableSortState | null
66
+ multiSort?: boolean
67
+ maxSort?: number
68
+ sorts?: RsTableSortState[]
69
+ defaultSorts?: RsTableSortState[]
70
+ columnDraggable?: boolean
71
+ columnOrder?: string[]
72
+ defaultColumnOrder?: string[]
73
+ rowDraggable?: boolean
74
+ rowDragTrigger?: RsTableRowDragTrigger
75
+ rowDropMode?: RsTableRowDropMode
76
+ rowDraggableWhen?: (row: T, index: number) => boolean
77
+ rowDropTargetWhen?: (row: T, index: number) => boolean
78
+ canRowDrop?: (dragKeys: string[], dropKey: string) => boolean
79
+ virtual?: boolean
80
+ /** fill 模式下数据行数达到该阈值时自动启用虚拟滚动;0 表示禁用自动启用 */
81
+ virtualAutoThreshold?: number
82
+ /**
83
+ * 列虚拟化:仅渲染横向可视区附近的数据列。
84
+ * true 强制开;false 强制关;默认 `'auto'` 由 virtualColumnsAutoThreshold 判定。
85
+ */
86
+ virtualColumns?: boolean | 'auto'
87
+ /** 数据列数达到该阈值时自动列虚拟化;0 表示禁用自动。默认 40 */
88
+ virtualColumnsAutoThreshold?: number
89
+ virtualColumnOverscan?: number
90
+ height?: number | string
91
+ rowHeight?: number
92
+ overscan?: number
93
+ infinite?: boolean
94
+ hasMore?: boolean
95
+ loadingMore?: boolean
96
+ infiniteDistance?: number
97
+ virtualOnInfinite?: boolean
98
+ resizable?: boolean
99
+ columnLayout?: 'auto' | 'fixed'
100
+ initialColumnWidths?: Record<string, number>
101
+ minColumnWidth?: number
102
+ maxColumnWidth?: number
103
+ selectOnContextmenu?: boolean
104
+ contextMenuItems?: (row: T | null, selectedRows: T[]) => RsContextMenuItem[]
105
+ contextMenu?: boolean
106
+ cellTooltip?: boolean
107
+ cellTooltipDelay?: number
108
+ headerTooltip?: boolean
109
+ editable?: boolean
110
+ editTrigger?: 'click' | 'dblclick'
111
+ editGutter?: boolean
112
+ editGutterWidth?: number
113
+ highlightRow?: boolean
114
+ highlightedRowKey?: string
115
+ defaultHighlightedRowKey?: string
116
+ highlightRowOnClick?: boolean
117
+ rowCommit?: boolean
118
+ rowPending?: (row: T, index: number) => boolean
119
+ showRowStatus?: boolean
120
+ allowNull?: boolean
121
+ nullLabel?: string
122
+ editFocusMode?: RsTableCellEditFocusMode
123
+ editKeyboard?: boolean
124
+ editUndo?: boolean
125
+ editUndoLimit?: number
126
+ editPaste?: boolean
127
+ editBatch?: boolean
128
+ summaryMode?: RsTableSummaryMode
129
+ summaryData?: RsTableSummaryData | null
130
+ showSummary?: boolean
131
+ features?: RsTableFeature<T>[]
132
+ viewKey?: string | number
133
+ layoutActive?: boolean
134
+ /** 无障碍名称;未传时回退 i18n `table.a11yLabel` */
135
+ ariaLabel?: string
136
+ }
137
+
138
+ /** RsTable 组件 emits(defineEmits 类型) */
139
+ export type RsTableEmits<T extends RsTableRowData = RsTableRowData> = {
140
+ rowClick: [row: T, index: number]
141
+ rowDblclick: [row: T, index: number]
142
+ cellView: [row: T, column: RsTableColumn<T>, index: number]
143
+ rowContextmenu: [row: T, index: number, event: MouseEvent]
144
+ contextMenuSelect: [key: string, row: T | null, selectedRows: T[]]
145
+ 'update:sort': [value: RsTableSortState | null]
146
+ 'update:sorts': [value: RsTableSortState[]]
147
+ sortsChange: [value: RsTableSortState[]]
148
+ 'update:columnOrder': [value: string[]]
149
+ columnOrderChange: [value: string[]]
150
+ 'update:columnFilters': [value: Record<string, string>]
151
+ columnFiltersChange: [value: Record<string, string>]
152
+ rowDrop: [dragKeys: string[], dropKey: string, position: RsTableRowDropPosition]
153
+ rowDragStart: [dragKeys: string[], event: DragEvent]
154
+ 'update:selectedRowKeys': [keys: string[]]
155
+ 'update:expandedRowKeys': [keys: string[]]
156
+ selectionChange: [keys: string[]]
157
+ expandChange: [keys: string[]]
158
+ loadMore: []
159
+ columnResize: [key: string, width: number]
160
+ 'update:highlightedRowKey': [key: string | undefined]
161
+ highlightChange: [key: string | undefined]
162
+ cellEditStart: [row: T, column: RsTableColumn<T>, index: number]
163
+ cellEditDialog: [row: T, column: RsTableColumn<T>, index: number, draft: string]
164
+ cellEditCommit: [
165
+ row: T,
166
+ column: RsTableColumn<T>,
167
+ index: number,
168
+ value: unknown,
169
+ previous: unknown,
170
+ ]
171
+ cellEditCancel: [row: T, column: RsTableColumn<T>, index: number]
172
+ cellEditInvalid: [
173
+ row: T,
174
+ column: RsTableColumn<T>,
175
+ index: number,
176
+ message: string,
177
+ value: unknown,
178
+ ]
179
+ cellEditBatchCommit: [
180
+ column: RsTableColumn<T>,
181
+ changes: Array<{ row: T; index: number; value: unknown; previous: unknown }>,
182
+ ]
183
+ cellEditUndo: [
184
+ entry: {
185
+ items: Array<{
186
+ rowKey: string
187
+ colKey: string
188
+ rowIndex: number
189
+ previous: unknown
190
+ next: unknown
191
+ }>
192
+ },
193
+ ]
194
+ cellEditRedo: [
195
+ entry: {
196
+ items: Array<{
197
+ rowKey: string
198
+ colKey: string
199
+ rowIndex: number
200
+ previous: unknown
201
+ next: unknown
202
+ }>
203
+ },
204
+ ]
205
+ cellEditReject: [row: T, index: number, reason?: string]
206
+ rowEditCommit: [
207
+ row: T,
208
+ index: number,
209
+ changes: Array<{ colKey: string; value: unknown; previous: unknown }>,
210
+ ]
211
+ rowEditRollback: [row: T, index: number]
212
+ }
213
+
214
+ /** withDefaults 第二参(工厂默认用函数) */
215
+ export const RS_TABLE_PROP_DEFAULTS = {
216
+ loading: false,
217
+ bordered: true,
218
+ columnBordered: false,
219
+ rounded: false,
220
+ fill: false,
221
+ compact: false,
222
+ size: 'md' as const,
223
+ selectable: false,
224
+ selectionType: 'checkbox' as const,
225
+ expandable: false,
226
+ defaultExpandedRowKeys: () => [] as string[],
227
+ striped: false,
228
+ showIndex: false,
229
+ indexWidth: 48,
230
+ showHeader: true,
231
+ remoteSort: false,
232
+ defaultSelectedRowKeys: () => [] as string[],
233
+ defaultSorts: () => [] as RsTableSortState[],
234
+ defaultColumnOrder: () => [] as string[],
235
+ multiSort: false,
236
+ maxSort: 3,
237
+ columnDraggable: false,
238
+ rowDraggable: false,
239
+ rowDragTrigger: 'handle' as const,
240
+ rowDropMode: 'reorder' as const,
241
+ overscan: 4,
242
+ virtualColumnOverscan: 2,
243
+ infiniteDistance: 80,
244
+ virtualOnInfinite: true,
245
+ virtualAutoThreshold: 50,
246
+ virtualColumns: 'auto' as const,
247
+ virtualColumnsAutoThreshold: 40,
248
+ resizable: false,
249
+ columnLayout: 'auto' as const,
250
+ minColumnWidth: 48,
251
+ maxColumnWidth: 640,
252
+ cellTooltip: true,
253
+ cellTooltipDelay: 300,
254
+ headerTooltip: true,
255
+ editable: false,
256
+ editTrigger: 'dblclick' as const,
257
+ editGutter: true,
258
+ editGutterWidth: 32,
259
+ highlightRow: false,
260
+ highlightRowOnClick: true,
261
+ rowCommit: false,
262
+ showRowStatus: true,
263
+ allowNull: true,
264
+ nullLabel: '(NULL)',
265
+ editFocusMode: 'end' as const,
266
+ editKeyboard: true,
267
+ editUndo: true,
268
+ editUndoLimit: 50,
269
+ editPaste: true,
270
+ editBatch: true,
271
+ contextMenu: true,
272
+ summaryMode: 'client' as const,
273
+ showSummary: false,
274
+ }
@@ -0,0 +1,258 @@
1
+ /**
2
+ * RsTable 视图上下文(provide/inject)。
3
+ *
4
+ * 多表隔离(关键):
5
+ * - 每个 RsTable 实例在自身 setup 内 provide,子树 inject 最近祖先
6
+ * - 同页多表互不影响:A 的 Header/Body 不会读到 B 的 view
7
+ * - 禁止把 view 存到模块级单例;instanceId 仅用于诊断
8
+ *
9
+ * 对比:RsTableModuleRegistry 是进程级全局(同 AG Grid ModuleRegistry),
10
+ * 会作用于所有实例;实例专属能力请用 props.features。
11
+ */
12
+
13
+ import { inject, provide, type InjectionKey } from 'vue'
14
+ import type { CSSProperties } from 'vue'
15
+ import type {
16
+ RsTableColumn,
17
+ RsTableRowData,
18
+ RsTableRowDropPosition,
19
+ RsTableRowEntry,
20
+ RsTableRowKey,
21
+ RsTableSelectionType,
22
+ } from '../table-utils'
23
+ import type {
24
+ RsTableCellEditFocusMode,
25
+ RsTableCellEditTrigger,
26
+ RsTableCellNavigateDirection,
27
+ } from './table-edit-utils'
28
+
29
+ /** 每实例递增,仅诊断用,不参与业务逻辑 */
30
+ let viewInstanceSeq = 0
31
+
32
+ export const RS_TABLE_VIEW_KEY: InjectionKey<RsTableViewContext> = Symbol('rsTableView')
33
+
34
+ /** 视图层内联样式(Vue CSSProperties 或普通字符串字典) */
35
+ export type RsTableViewStyle = CSSProperties | Record<string, string> | undefined
36
+
37
+ export type RsTableHeaderLabels = {
38
+ selectAll: string
39
+ index: string
40
+ rowStatus: string
41
+ dragColumn: string
42
+ filterColumn: string
43
+ filterPlaceholder: string
44
+ filterClear: string
45
+ filterApply: string
46
+ }
47
+
48
+ export type RsTableBodyLabels = {
49
+ loading: string
50
+ empty: string
51
+ loadingMore: string
52
+ dragRow: string
53
+ expandRow: string
54
+ collapseRow: string
55
+ selectRow: string
56
+ rowCommit: string
57
+ rowRollback: string
58
+ gutterCommit: string
59
+ }
60
+
61
+ type RowEntry<T extends RsTableRowData> = Extract<RsTableRowEntry<T>, { type: 'row' }>
62
+
63
+ /**
64
+ * 视图只读状态 + 事件处理。
65
+ * 状态字段经 getter 暴露,子组件 render 访问时收集依赖;多表各自刷新、互不串扰。
66
+ */
67
+ export interface RsTableViewContext<T extends RsTableRowData = RsTableRowData> {
68
+ readonly instanceId: string
69
+
70
+ readonly useFixedColumnLayout: boolean
71
+ readonly showRowDragHandle: boolean
72
+ readonly detailExpandable: boolean
73
+ readonly showSelectColumn: boolean
74
+ readonly showEditGutterColumn: boolean
75
+ readonly showIndexColumn: boolean
76
+ readonly showRowStatusColumn: boolean
77
+ readonly columnPadLeft: number
78
+ readonly columnPadRight: number
79
+ readonly visibleDataColumns: RsTableColumn<T>[]
80
+ readonly prefixWidths: { drag: number; expand: number; select: number; status: number }
81
+ readonly resolvedGutterWidth: number
82
+ readonly resolvedIndexWidth: number
83
+ resolvedDataColumnWidth: (key: string, fallback?: number | string) => number
84
+
85
+ readonly isRadioSelection: boolean
86
+ readonly selectAllState: 'checked' | 'indeterminate' | 'unchecked'
87
+ readonly columnDraggable: boolean
88
+ readonly resizable: boolean
89
+ readonly multiSort: boolean
90
+ readonly columnFiltersState: Record<string, string>
91
+ readonly dragColumnKey: string | null
92
+ readonly dropColumnKey: string | null
93
+ readonly dragLeadHeaderStyle: RsTableViewStyle
94
+ readonly expandLeadHeaderStyle: RsTableViewStyle
95
+ readonly selectLeadHeaderStyle: RsTableViewStyle
96
+ readonly gutterLeadHeaderStyle: RsTableViewStyle
97
+ readonly indexLeadHeaderStyle: RsTableViewStyle
98
+ readonly columnHeaderStyleMap: Map<string, Record<string, string> | undefined>
99
+ readonly headerLabels: RsTableHeaderLabels
100
+ columnFilterValue: (key: string) => string
101
+ isColumnFilterActive: (filters: Record<string, string>, key: string) => boolean
102
+ sortOrderFor: (key: string) => string | null | undefined
103
+ sortPriorityFor: (key: string) => number
104
+ sortIconName: (key: string) => string
105
+ onToggleSelectAll: () => void
106
+ onColumnDragOver: (key: string, event: DragEvent) => void
107
+ onColumnDrop: (key: string, event: DragEvent) => void
108
+ onColumnDragStart: (key: string, event: DragEvent) => void
109
+ onColumnDragEnd: () => void
110
+ updateColumnFilter: (key: string, value: string) => void
111
+ onHeaderClick: (column: RsTableColumn<T>) => void
112
+ onResizeStart: (key: string, event: MouseEvent) => void
113
+ onHeaderPointerOver: (event: PointerEvent) => void
114
+ onHeaderPointerOut: (event: PointerEvent) => void
115
+
116
+ readonly loading: boolean
117
+ readonly hasData: boolean
118
+ readonly loadingMore: boolean
119
+ readonly infinite: boolean
120
+ readonly bodyColspan: number
121
+ readonly emptyContentStyle: RsTableViewStyle
122
+ readonly virtualScrollEnabled: boolean
123
+ readonly virtualSlice: { paddingTop: number; paddingBottom: number }
124
+ readonly visibleEntries: RsTableRowEntry<T>[]
125
+ readonly rowKey: RsTableRowKey<T> | undefined
126
+ readonly treeMode: boolean
127
+ readonly treeIndentPx: number
128
+ readonly treeExpandColumnKey: string | null
129
+ readonly treeLoadingKeySet: Set<string>
130
+ readonly striped: boolean
131
+ readonly selectionType: RsTableSelectionType
132
+ readonly editable: boolean
133
+ readonly editTrigger: RsTableCellEditTrigger
134
+ readonly rowCommit: boolean
135
+ readonly allowNull: boolean
136
+ readonly editFocusMode: RsTableCellEditFocusMode
137
+ readonly nullLabel: string
138
+ readonly dragLeadStyle: Record<string, string>
139
+ readonly expandLeadStyle: Record<string, string>
140
+ readonly selectLeadStyle: Record<string, string>
141
+ readonly indexLeadStyle: Record<string, string>
142
+ readonly gutterLeadStyle: Record<string, string>
143
+ readonly columnTdClassMap: Map<string, string[]>
144
+ readonly columnStyleMap: Map<string, Record<string, string> | undefined>
145
+ readonly dragRowKeys: string[]
146
+ readonly dropRowTargetKey: string | null
147
+ readonly dropRowPosition: RsTableRowDropPosition | null
148
+ readonly activeEditCellKey: string
149
+ readonly activeFocusCellKey: string
150
+ readonly activeErrorMapSize: number
151
+ readonly activeValidatingMapSize: number
152
+ readonly stagedMapSize: number
153
+ readonly editingDraft: string
154
+ readonly editingCell: { rowKey: string; colKey: string } | null
155
+ readonly focusCell: { rowKey: string; colKey: string } | null
156
+ readonly bodyLabels: RsTableBodyLabels
157
+ rowKeyFor: (entry: RowEntry<T>) => string
158
+ isRowSelected: (entry: RowEntry<T>) => boolean
159
+ isRowIndeterminate: (entry: RowEntry<T>) => boolean
160
+ isRowExpanded: (entry: RowEntry<T>) => boolean
161
+ isHighlighted: (rowKey: string) => boolean
162
+ rowEditPending: (entry: RowEntry<T>) => boolean
163
+ isExternalRowPending: (entry: RowEntry<T>) => boolean
164
+ treeDepthOf: (entry: RowEntry<T>) => number
165
+ canExpandRow: (entry: RowEntry<T>) => boolean
166
+ canSelectRow: (entry: RowEntry<T>) => boolean
167
+ isRowDragByRow: (entry: RowEntry<T>) => boolean
168
+ isRowDragging: (entry: RowEntry<T>) => boolean
169
+ isRowDropTarget: (entry: RowEntry<T>) => boolean
170
+ isRowDirty: (rowKey: string) => boolean
171
+ hasColumnSlot: (key: string) => boolean
172
+ hasEditSlot: (key: string) => boolean
173
+ cellTooltipEnabled: (column: RsTableColumn<T>, rowIndex: number) => boolean
174
+ cellTooltipMode: (column: RsTableColumn<T>, rowIndex: number) => string | undefined
175
+ cellTooltipText: (column: RsTableColumn<T>, row: T, rowIndex: number) => string | undefined
176
+ cellTooltipFallbackTitle: (column: RsTableColumn<T>, row: T, rowIndex: number) => string | undefined
177
+ getCellDraft: (rowKey: string, colKey: string) => string | undefined
178
+ isCellDirty: (rowKey: string, colKey: string) => boolean
179
+ getCellError: (rowKey: string, colKey: string) => string | undefined
180
+ isCellValidating: (rowKey: string, colKey: string) => boolean
181
+ onBodyPointerOver: (event: PointerEvent) => void
182
+ onBodyPointerOut: (event: PointerEvent) => void
183
+ onRowClick: (entry: RowEntry<T>, event: MouseEvent) => void
184
+ onRowSelectMouseDown: (event: MouseEvent) => void
185
+ onCellClick: (entry: RowEntry<T>, colKey: string, event: MouseEvent) => void
186
+ onCellDblclick: (entry: RowEntry<T>, colKey: string, event: MouseEvent) => void
187
+ onCellContextmenu: (entry: RowEntry<T>, colKey: string, event: MouseEvent) => void
188
+ onRowDblclick: (entry: RowEntry<T>, event: MouseEvent) => void
189
+ onRowContextmenu: (entry: RowEntry<T>, event: MouseEvent) => void
190
+ onRowDragOver: (entry: RowEntry<T>, event: DragEvent) => void
191
+ onRowDragLeave: (event: DragEvent) => void
192
+ onRowDrop: (entry: RowEntry<T>, event: DragEvent) => void
193
+ onRowDragStart: (entry: RowEntry<T>, event: DragEvent) => void
194
+ onRowDragEnd: () => void
195
+ onToggleExpand: (entry: RowEntry<T>) => void
196
+ onToggleSelect: (entry: RowEntry<T>) => void
197
+ onCellStartEdit: (entry: RowEntry<T>, colKey: string) => void
198
+ onCellCommit: (entry: RowEntry<T>, colKey: string, value: string) => void
199
+ onCellCancel: (entry: RowEntry<T>, colKey: string) => void
200
+ onCellUpdateDraft: (entry: RowEntry<T>, colKey: string, value: string) => void
201
+ onCellNavigate: (
202
+ entry: RowEntry<T>,
203
+ colKey: string,
204
+ direction: RsTableCellNavigateDirection,
205
+ ) => void
206
+ onRowCommit: (entry: RowEntry<T>) => void
207
+ onRowRollback: (entry: RowEntry<T>) => void
208
+ onGutterCommit: (entry: RowEntry<T>) => void
209
+ }
210
+
211
+ /**
212
+ * 显式区分 state getters 与 handlers,避免把零参 handler 误当成状态 getter。
213
+ */
214
+ export function createRsTableViewContext<T extends RsTableRowData>(parts: {
215
+ state: { [K in keyof RsTableViewContext<T>]?: () => RsTableViewContext<T>[K] }
216
+ handlers: { [K in keyof RsTableViewContext<T>]?: RsTableViewContext<T>[K] }
217
+ }): RsTableViewContext<T> {
218
+ const instanceId = `rs-table-view-${++viewInstanceSeq}`
219
+ const ctx: Record<string, unknown> = { instanceId }
220
+ for (const [key, getter] of Object.entries(parts.state)) {
221
+ if (!getter) continue
222
+ Object.defineProperty(ctx, key, {
223
+ enumerable: true,
224
+ configurable: true,
225
+ get: getter as () => unknown,
226
+ })
227
+ }
228
+ for (const [key, fn] of Object.entries(parts.handlers)) {
229
+ if (fn !== undefined) ctx[key] = fn
230
+ }
231
+ return ctx as unknown as RsTableViewContext<T>
232
+ }
233
+
234
+ /** 在 RsTable 内 provide(每个实例调用一次) */
235
+ export function provideRsTableView<T extends RsTableRowData>(ctx: RsTableViewContext<T>): void {
236
+ // 与 useRsTableView 对称:泛型 T 与默认 object 行类型在函数/数组位不重叠,经 unknown 擦除
237
+ provide(RS_TABLE_VIEW_KEY, ctx as unknown as RsTableViewContext)
238
+ }
239
+
240
+ /**
241
+ * 子视图 inject;必须在某个 RsTable 子树内。
242
+ * 多表场景下自动绑定到最近的表格实例。
243
+ */
244
+ export function useRsTableView<T extends RsTableRowData = RsTableRowData>(): RsTableViewContext<T> {
245
+ const ctx = inject(RS_TABLE_VIEW_KEY, null)
246
+ if (!ctx) {
247
+ throw new Error(
248
+ '[RsTable] useRsTableView() 必须在 RsTable 子树内调用(每表独立 provide,多表互不串扰)',
249
+ )
250
+ }
251
+ // InjectionKey 无泛型实参;经 unknown 收窄到调用方 T(实例隔离由 provide 树保证)
252
+ return ctx as unknown as RsTableViewContext<T>
253
+ }
254
+
255
+ /** 测试用:重置 instance 序号 */
256
+ export function resetRsTableViewInstanceSeqForTest(): void {
257
+ viewInstanceSeq = 0
258
+ }
@@ -130,6 +130,18 @@
130
130
  font-size: var(--rs-table-cell-size, var(--rs-font-size-xs));
131
131
  font-weight: var(--rs-table-cell-weight, 400);
132
132
  }
133
+ /* showHeader=false:保留 th 供 AT / 静态表头规则,视觉隐藏 */
134
+ .rs-table__head--sr-only {
135
+ position: absolute;
136
+ width: 1px;
137
+ height: 1px;
138
+ padding: 0;
139
+ margin: -1px;
140
+ overflow: hidden;
141
+ clip: rect(0, 0, 0, 0);
142
+ white-space: nowrap;
143
+ border: 0;
144
+ }
133
145
  .rs-table__th,
134
146
  .rs-table__td {
135
147
  padding: var(--rs-space-sm) var(--rs-space-md);
@@ -295,6 +307,35 @@
295
307
  .rs-table__expand-btn--expanded {
296
308
  transform: rotate(90deg);
297
309
  }
310
+ .rs-table__tree-cell {
311
+ display: flex;
312
+ align-items: center;
313
+ gap: 0.125rem;
314
+ min-width: 0;
315
+ width: 100%;
316
+ }
317
+ .rs-table__tree-toggle {
318
+ flex: 0 0 auto;
319
+ }
320
+ .rs-table__tree-toggle--loading {
321
+ opacity: 0.5;
322
+ cursor: wait;
323
+ }
324
+ .rs-table__tree-leaf {
325
+ display: inline-flex;
326
+ flex: 0 0 auto;
327
+ width: 1.25rem;
328
+ height: 1.25rem;
329
+ }
330
+ .rs-table__tree-content {
331
+ display: inline-flex;
332
+ align-items: center;
333
+ min-width: 0;
334
+ flex: 1 1 auto;
335
+ }
336
+ .rs-table__td--tree {
337
+ overflow: hidden;
338
+ }
298
339
  .rs-table__expand-row {
299
340
  background: var(--rs-table-expand-bg);
300
341
  }
@@ -312,6 +353,26 @@
312
353
  color: var(--rs-table-muted-fg);
313
354
  font-weight: var(--rs-table-header-weight);
314
355
  }
356
+ .rs-table__summary-row .rs-table__summary-cell {
357
+ padding: var(--rs-space-sm) var(--rs-space-md);
358
+ color: var(--rs-table-muted-fg);
359
+ font-weight: var(--rs-table-header-weight);
360
+ background: var(--rs-table-footer-bg);
361
+ border-top: 1px solid var(--rs-table-border, var(--rs-border));
362
+ white-space: nowrap;
363
+ }
364
+ .rs-table__summary-cell--left {
365
+ text-align: left;
366
+ }
367
+ .rs-table__summary-cell--center {
368
+ text-align: center;
369
+ }
370
+ .rs-table__summary-cell--right {
371
+ text-align: right;
372
+ }
373
+ .rs-table__summary-cell--pad {
374
+ padding: 0;
375
+ }
315
376
  .rs-table__checkbox-box--radio {
316
377
  border-radius: 999px;
317
378
  }
@@ -470,16 +531,21 @@
470
531
  }
471
532
  .rs-table__th--selection,
472
533
  .rs-table__td--selection {
473
- width: 40px;
474
- padding-inline: var(--rs-space-sm);
534
+ /* 与序号列一样锁死宽度,避免 table-layout:auto + width:100% 时被分到多余空白 */
535
+ width: var(--rs-table-select-width, 40px);
536
+ min-width: var(--rs-table-select-width, 40px);
537
+ max-width: var(--rs-table-select-width, 40px);
538
+ padding-inline: 0;
539
+ box-sizing: border-box;
475
540
  text-align: center;
476
541
  vertical-align: middle;
477
542
  }
478
543
  .rs-table__th--index,
479
544
  .rs-table__td--index {
480
- width: var(--rs-table-index-width, 56px);
481
- min-width: var(--rs-table-index-width, 56px);
482
- max-width: var(--rs-table-index-width, 56px);
545
+ width: var(--rs-table-index-width, 48px);
546
+ min-width: var(--rs-table-index-width, 48px);
547
+ max-width: var(--rs-table-index-width, 48px);
548
+ padding-inline: 0;
483
549
  box-sizing: border-box;
484
550
  color: var(--rs-table-muted-fg);
485
551
  }
@@ -729,10 +795,19 @@
729
795
  text-align: right;
730
796
  }
731
797
  .rs-table__empty {
732
- padding: var(--rs-space-xl);
798
+ padding: 0;
733
799
  color: var(--rs-table-muted-fg);
734
800
  text-align: center;
735
801
  }
802
+ /* 宽表时 td 远大于视口;内层 sticky + 视口宽度,保证空态落在可见区域中心 */
803
+ .rs-table__empty-content {
804
+ position: sticky;
805
+ left: 0;
806
+ box-sizing: border-box;
807
+ max-width: 100%;
808
+ padding: var(--rs-space-xl);
809
+ text-align: center;
810
+ }
736
811
  .rs-table:has(> .rs-table__table > tbody > tr:only-child > .rs-table__empty) .rs-table__empty {
737
812
  height: 100%;
738
813
  vertical-align: middle;
@@ -740,6 +815,9 @@
740
815
  .rs-table__empty--more {
741
816
  padding: var(--rs-space-md);
742
817
  }
818
+ .rs-table__empty--more .rs-table__empty-content {
819
+ padding: var(--rs-space-md);
820
+ }
743
821
  .rs-table__sort--active {
744
822
  color: var(--rs-table-sort-active-fg);
745
823
  }