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
@@ -30,16 +30,89 @@ export function rangeInclusive(max: number): number[] {
30
30
  return Array.from({ length: max + 1 }, (_, index) => index)
31
31
  }
32
32
 
33
+ /** 时分秒列选项(value + 预格式化 label,避免模板内反复 padStart) */
34
+ export interface RsTimeUnitOption {
35
+ value: number
36
+ label: string
37
+ }
38
+
39
+ /** 时间列单位 */
40
+ export type RsTimeUnit = 'hour' | 'minute' | 'second'
41
+
42
+ export function formatTimeUnitLabel(value: number): string {
43
+ return String(value).padStart(2, '0')
44
+ }
45
+
46
+ function buildTimeUnitOptions(max: number, step = 1): RsTimeUnitOption[] {
47
+ const options: RsTimeUnitOption[] = []
48
+ for (let value = 0; value <= max; value += step) {
49
+ options.push({ value, label: formatTimeUnitLabel(value) })
50
+ }
51
+ return options
52
+ }
53
+
54
+ /** 小时列固定选项 00–23 */
55
+ export const TIME_HOUR_OPTIONS: readonly RsTimeUnitOption[] = buildTimeUnitOptions(23)
56
+
57
+ /** 秒列固定选项 00–59 */
58
+ export const TIME_SECOND_OPTIONS: readonly RsTimeUnitOption[] = buildTimeUnitOptions(59)
59
+
60
+ const minuteOptionsCache = new Map<number, readonly RsTimeUnitOption[]>()
61
+
62
+ /** 按步进缓存分钟列选项,默认 step=1 为 00–59 */
63
+ export function getTimeMinuteOptions(step = 1): readonly RsTimeUnitOption[] {
64
+ const normalized = Math.max(1, Math.floor(step) || 1)
65
+ const cached = minuteOptionsCache.get(normalized)
66
+ if (cached) return cached
67
+ const options = buildTimeUnitOptions(59, normalized)
68
+ minuteOptionsCache.set(normalized, options)
69
+ return options
70
+ }
71
+
72
+ /**
73
+ * 将时间列滚到指定 value,只改容器 scrollTop。
74
+ * 避免 scrollIntoView 带动外层页面 / Popover 滚动。
75
+ */
76
+ export function scrollTimeColumnToValue(
77
+ container: HTMLElement | null | undefined,
78
+ value: number,
79
+ ): void {
80
+ if (!container) return
81
+ const item = container.querySelector<HTMLElement>(`:scope > [data-value="${value}"]`)
82
+ if (!item) return
83
+ const top = item.offsetTop - (container.clientHeight - item.offsetHeight) / 2
84
+ container.scrollTop = Math.max(0, top)
85
+ }
86
+
33
87
  export function parseTimeValue(value?: string, withSeconds = false): RsParsedTime | null {
34
88
  if (!value?.trim()) return null
35
89
  const trimmed = value.trim()
36
- const pattern = withSeconds ? TIME_WITH_SECONDS_PATTERN : TIME_PATTERN
37
- const match = pattern.exec(trimmed)
90
+ if (withSeconds) {
91
+ const withSec = TIME_WITH_SECONDS_PATTERN.exec(trimmed)
92
+ if (withSec) {
93
+ return {
94
+ hour: Number.parseInt(withSec[1], 10),
95
+ minute: Number.parseInt(withSec[2], 10),
96
+ second: Number.parseInt(withSec[3], 10),
97
+ }
98
+ }
99
+ // 兼容仅到分的旧值,秒补 0
100
+ const minuteOnly = TIME_PATTERN.exec(trimmed)
101
+ if (minuteOnly) {
102
+ return {
103
+ hour: Number.parseInt(minuteOnly[1], 10),
104
+ minute: Number.parseInt(minuteOnly[2], 10),
105
+ second: 0,
106
+ }
107
+ }
108
+ return null
109
+ }
110
+ const match = TIME_PATTERN.exec(trimmed)
38
111
  if (!match) return null
39
112
  return {
40
113
  hour: Number.parseInt(match[1], 10),
41
114
  minute: Number.parseInt(match[2], 10),
42
- second: withSeconds ? Number.parseInt(match[3], 10) : 0,
115
+ second: 0,
43
116
  }
44
117
  }
45
118
 
@@ -53,3 +53,125 @@ export function mergeUploadFiles(current: readonly File[], next: readonly File[]
53
53
  export function removeUploadFileAt(files: readonly File[], index: number): File[] {
54
54
  return files.filter((_, currentIndex) => currentIndex !== index)
55
55
  }
56
+
57
+ /** 触发浏览器下载指定 File / Blob */
58
+ export function downloadUploadFile(file: File | Blob, filename?: string): void {
59
+ const name = filename || (file instanceof File ? file.name : 'download')
60
+ const url = URL.createObjectURL(file)
61
+ const link = document.createElement('a')
62
+ link.href = url
63
+ link.download = name
64
+ document.body.appendChild(link)
65
+ link.click()
66
+ document.body.removeChild(link)
67
+ URL.revokeObjectURL(url)
68
+ }
69
+
70
+ /** 将文本等内容还原为可回显的 File(编辑态回填) */
71
+ export function createUploadFileFromContent(
72
+ name: string,
73
+ content: BlobPart,
74
+ type = 'application/octet-stream',
75
+ ): File {
76
+ return new File([content], name, { type })
77
+ }
78
+
79
+ /** 扩展名 → Lucide 图标名(kebab-case) */
80
+ const UPLOAD_EXT_ICON: Record<string, string> = {
81
+ // 证书 / 密钥
82
+ pem: 'file-key',
83
+ crt: 'file-key',
84
+ cer: 'file-key',
85
+ key: 'key-round',
86
+ p12: 'file-lock',
87
+ pfx: 'file-lock',
88
+ // 文本 / 文档
89
+ txt: 'file-text',
90
+ md: 'file-text',
91
+ markdown: 'file-text',
92
+ log: 'file-text',
93
+ pdf: 'file-type',
94
+ doc: 'file-text',
95
+ docx: 'file-text',
96
+ rtf: 'file-text',
97
+ // 表格
98
+ csv: 'file-spreadsheet',
99
+ xls: 'file-spreadsheet',
100
+ xlsx: 'file-spreadsheet',
101
+ // 代码 / 配置
102
+ json: 'file-braces',
103
+ yaml: 'file-code',
104
+ yml: 'file-code',
105
+ xml: 'file-code',
106
+ html: 'file-code',
107
+ htm: 'file-code',
108
+ css: 'file-code',
109
+ scss: 'file-code',
110
+ js: 'file-code',
111
+ mjs: 'file-code',
112
+ cjs: 'file-code',
113
+ ts: 'file-code',
114
+ tsx: 'file-code',
115
+ jsx: 'file-code',
116
+ vue: 'file-code',
117
+ go: 'file-code',
118
+ py: 'file-code',
119
+ java: 'file-code',
120
+ rs: 'file-code',
121
+ sql: 'file-terminal',
122
+ sh: 'file-terminal',
123
+ bat: 'file-terminal',
124
+ ps1: 'file-terminal',
125
+ // 图片
126
+ png: 'file-image',
127
+ jpg: 'file-image',
128
+ jpeg: 'file-image',
129
+ gif: 'file-image',
130
+ webp: 'file-image',
131
+ svg: 'file-image',
132
+ bmp: 'file-image',
133
+ ico: 'file-image',
134
+ // 音视频
135
+ mp3: 'file-music',
136
+ wav: 'file-music',
137
+ flac: 'file-music',
138
+ aac: 'file-music',
139
+ mp4: 'file-video-camera',
140
+ webm: 'file-video-camera',
141
+ mov: 'file-video-camera',
142
+ avi: 'file-video-camera',
143
+ // 压缩包
144
+ zip: 'file-archive',
145
+ rar: 'file-archive',
146
+ '7z': 'file-archive',
147
+ tar: 'file-archive',
148
+ gz: 'file-archive',
149
+ tgz: 'file-archive',
150
+ }
151
+
152
+ /** MIME 前缀 → Lucide 图标名(扩展名未知时回退) */
153
+ const UPLOAD_MIME_ICON: Array<{ prefix: string; icon: string }> = [
154
+ { prefix: 'image/', icon: 'file-image' },
155
+ { prefix: 'audio/', icon: 'file-music' },
156
+ { prefix: 'video/', icon: 'file-video-camera' },
157
+ { prefix: 'text/', icon: 'file-text' },
158
+ { prefix: 'application/pdf', icon: 'file-type' },
159
+ { prefix: 'application/json', icon: 'file-braces' },
160
+ { prefix: 'application/zip', icon: 'file-archive' },
161
+ { prefix: 'application/x-tar', icon: 'file-archive' },
162
+ { prefix: 'application/gzip', icon: 'file-archive' },
163
+ ]
164
+
165
+ /**
166
+ * 按文件名扩展名 / MIME 解析列表图标(Lucide kebab-case)。
167
+ * 未匹配时返回 `file`。
168
+ */
169
+ export function resolveUploadFileIcon(file: Pick<File, 'name' | 'type'> | string): string {
170
+ const name = typeof file === 'string' ? file : file.name
171
+ const mime = typeof file === 'string' ? '' : file.type || ''
172
+ const ext = name.includes('.') ? name.split('.').pop()!.toLowerCase() : ''
173
+ if (ext && UPLOAD_EXT_ICON[ext]) return UPLOAD_EXT_ICON[ext]
174
+ const byMime = UPLOAD_MIME_ICON.find((item) => mime.startsWith(item.prefix))
175
+ if (byMime) return byMime.icon
176
+ return 'file'
177
+ }
@@ -11,7 +11,20 @@ export function resolveVirtualListHeight(height?: number | string, fallback = 24
11
11
  return typeof height === 'number' ? `${height}px` : height
12
12
  }
13
13
 
14
- /** height 为 0 时由父级 flex 撑满,组件内用 ResizeObserver 测量可视高度 */
14
+ /** height 为 0 / 百分比时由父级撑满,组件内用 ResizeObserver 测量可视高度 */
15
15
  export function isVirtualListFillHeight(height?: number | string): boolean {
16
- return height === 0
16
+ if (height === 0) return true
17
+ if (typeof height === 'string' && height.trim().endsWith('%')) return true
18
+ return false
19
+ }
20
+
21
+ /** 解析虚拟列表数值视口高度;百分比 / 填满模式返回 null,交由测量值处理 */
22
+ export function parseVirtualListHeightPx(height?: number | string): number | null {
23
+ if (typeof height === 'number' && height > 0) return height
24
+ if (typeof height === 'string') {
25
+ if (height.includes('%')) return null
26
+ const parsed = Number.parseInt(height, 10)
27
+ if (Number.isFinite(parsed) && parsed > 0) return parsed
28
+ }
29
+ return null
17
30
  }
@@ -0,0 +1,79 @@
1
+ /**
2
+ * 装配 RsTable 公开 Api(从 SFC 下沉,单一出口)。
3
+ */
4
+
5
+ import type { ComputedRef, Ref } from 'vue'
6
+ import type { RsTableApi } from '../components/table/rs-table-api'
7
+ import type { RsTableRowData, RsTableRowEntry } from '../components/table-utils'
8
+ import type { RsTableAnalyticsSnapshot } from './useRsTableSelectionSource'
9
+ import type { useRsTable } from './useRsTable'
10
+
11
+ type RowEntry<T extends RsTableRowData> = Extract<RsTableRowEntry<T>, { type: 'row' }>
12
+
13
+ export interface AssembleRsTableApiOptions<T extends RsTableRowData> {
14
+ tableSurface: ReturnType<typeof useRsTable<T>>
15
+ dataRows: Ref<RowEntry<T>[]> | ComputedRef<RowEntry<T>[]>
16
+ rowKeyByIndex: Ref<Map<number, string>> | ComputedRef<Map<number, string>>
17
+ viewRows: Ref<T[]> | ComputedRef<T[]>
18
+ selectedRows: Ref<T[]> | ComputedRef<T[]>
19
+ selectedRowKeys: Ref<string[]> | ComputedRef<string[]>
20
+ getAnalyticsSnapshot: () => RsTableAnalyticsSnapshot<T>
21
+ subscribeAnalytics: (listener: (snap: RsTableAnalyticsSnapshot<T>) => void) => () => void
22
+ getRowByKey: (
23
+ rowKey: string,
24
+ dataRows: RowEntry<T>[],
25
+ rowKeyByIndex: Map<number, string>,
26
+ ) => T | undefined
27
+ getRowByIndex: (index: number, dataRows: RowEntry<T>[]) => T | undefined
28
+ getColumnValues: (colKey: string, dataRows: RowEntry<T>[]) => unknown[]
29
+ getCellValue: (
30
+ rowKey: string,
31
+ colKey: string,
32
+ dataRows: RowEntry<T>[],
33
+ rowKeyByIndex: Map<number, string>,
34
+ ) => unknown
35
+ toApiEditSlice: (ctx: {
36
+ dataRows: Ref<RowEntry<T>[]> | ComputedRef<RowEntry<T>[]>
37
+ rowKeyByIndex: Ref<Map<number, string>> | ComputedRef<Map<number, string>>
38
+ }) => Pick<
39
+ RsTableApi<T>,
40
+ | 'getHighlightedRowKey'
41
+ | 'setHighlightedRowKey'
42
+ | 'cancelCellEdit'
43
+ | 'cancelAllEdits'
44
+ | 'getDirtyCellKeys'
45
+ | 'getCellError'
46
+ | 'setCellError'
47
+ | 'stageCell'
48
+ | 'rejectRowEdit'
49
+ | 'undoEdit'
50
+ | 'redoEdit'
51
+ | 'commitRowEdits'
52
+ | 'rollbackRowEdits'
53
+ >
54
+ }
55
+
56
+ /**
57
+ * 创建并返回 RsTableApi(含 feature 元数据)。
58
+ */
59
+ export function assembleRsTableApi<T extends RsTableRowData>(
60
+ options: AssembleRsTableApiOptions<T>,
61
+ ): RsTableApi<T> {
62
+ const { tableSurface, dataRows, rowKeyByIndex } = options
63
+ return tableSurface.createApi({
64
+ getRowByKey: (rowKey) =>
65
+ options.getRowByKey(rowKey, dataRows.value, rowKeyByIndex.value),
66
+ getRowByIndex: (index) => options.getRowByIndex(index, dataRows.value),
67
+ getColumnValues: (colKey) => options.getColumnValues(colKey, dataRows.value),
68
+ getCellValue: (rowKey, colKey) =>
69
+ options.getCellValue(rowKey, colKey, dataRows.value, rowKeyByIndex.value),
70
+ getViewRows: () => options.viewRows.value,
71
+ getSelectedRows: () => options.selectedRows.value,
72
+ getSelectedRowKeys: () => [...options.selectedRowKeys.value],
73
+ getAnalyticsSnapshot: options.getAnalyticsSnapshot,
74
+ subscribeAnalytics: options.subscribeAnalytics,
75
+ ...options.toApiEditSlice({ dataRows, rowKeyByIndex }),
76
+ getToolbarItems: () => tableSurface.getToolbarItems(),
77
+ getOverlayContributions: () => tableSurface.getOverlayContributions(),
78
+ })
79
+ }
@@ -0,0 +1,269 @@
1
+ /**
2
+ * 将 Shell / Edit / Chrome 接线捆成 ViewContext provide(削薄 RsTable.vue)。
3
+ */
4
+
5
+ import type { ComputedRef, Ref } from 'vue'
6
+ import type {
7
+ RsTableRowData,
8
+ RsTableRowEntry,
9
+ RsTableRowKey,
10
+ RsTableSelectionType,
11
+ } from '../components/table-utils'
12
+ import type { RsTableCellEditFocusMode, RsTableCellEditTrigger } from '../components/table/table-edit-utils'
13
+ import type { RsTableBodyLabels, RsTableHeaderLabels } from '../components/table/rs-table-view-context'
14
+ import type { useTableEdit } from './useTableEdit'
15
+ import {
16
+ useRsTableViewProvide,
17
+ type RsTableViewProvideHandlers,
18
+ type RsTableViewProvideSources,
19
+ } from './useRsTableViewProvide'
20
+
21
+ type RowEntry<T extends RsTableRowData> = Extract<RsTableRowEntry<T>, { type: 'row' }>
22
+ type TableEditApi = ReturnType<typeof useTableEdit>
23
+
24
+ export interface BindRsTableViewContextDeps<T extends RsTableRowData> {
25
+ props: {
26
+ columnDraggable: () => boolean
27
+ resizable: () => boolean
28
+ multiSort: () => boolean
29
+ loading: () => boolean
30
+ loadingMore: () => boolean
31
+ infinite: () => boolean
32
+ rowKey: () => RsTableRowKey<T> | undefined
33
+ striped: () => boolean
34
+ selectionType: () => RsTableSelectionType
35
+ editable: () => boolean
36
+ editTrigger: () => RsTableCellEditTrigger
37
+ rowCommit: () => boolean
38
+ allowNull: () => boolean
39
+ editFocusMode: () => RsTableCellEditFocusMode
40
+ nullLabel: () => string
41
+ }
42
+ layout: Pick<
43
+ RsTableViewProvideSources<T>,
44
+ | 'useFixedColumnLayout'
45
+ | 'showRowDragHandle'
46
+ | 'detailExpandable'
47
+ | 'showSelectColumn'
48
+ | 'showEditGutterColumn'
49
+ | 'showIndexColumn'
50
+ | 'showRowStatusColumn'
51
+ | 'columnPadLeft'
52
+ | 'columnPadRight'
53
+ | 'visibleDataColumns'
54
+ | 'prefixWidths'
55
+ | 'resolvedGutterWidth'
56
+ | 'resolvedIndexWidth'
57
+ | 'isRadioSelection'
58
+ | 'selectAllState'
59
+ | 'columnFiltersState'
60
+ | 'dragColumnKey'
61
+ | 'dropColumnKey'
62
+ | 'dragLeadHeaderStyle'
63
+ | 'expandLeadHeaderStyle'
64
+ | 'selectLeadHeaderStyle'
65
+ | 'gutterLeadHeaderStyle'
66
+ | 'indexLeadHeaderStyle'
67
+ | 'columnHeaderStyleMap'
68
+ | 'bodyColspan'
69
+ | 'emptyContentStyle'
70
+ | 'virtualScrollEnabled'
71
+ | 'virtualSlice'
72
+ | 'visibleEntries'
73
+ | 'treeMode'
74
+ | 'treeIndentPx'
75
+ | 'treeExpandColumnKey'
76
+ | 'treeLoadingKeySet'
77
+ | 'dragLeadStyle'
78
+ | 'expandLeadStyle'
79
+ | 'selectLeadStyle'
80
+ | 'indexLeadStyle'
81
+ | 'gutterLeadStyle'
82
+ | 'columnTdClassMap'
83
+ | 'columnStyleMap'
84
+ | 'dragRowKeys'
85
+ | 'dropRowTargetKey'
86
+ | 'dropRowPosition'
87
+ >
88
+ chrome: {
89
+ hasData: Ref<boolean> | ComputedRef<boolean>
90
+ headerLabels: Ref<RsTableHeaderLabels> | ComputedRef<RsTableHeaderLabels>
91
+ bodyLabels: Ref<RsTableBodyLabels> | ComputedRef<RsTableBodyLabels>
92
+ hasColumnSlot: (key: string) => boolean
93
+ hasEditSlot: (key: string) => boolean
94
+ }
95
+ edit: {
96
+ tableEdit: TableEditApi
97
+ activeEditCellKey: Ref<string> | ComputedRef<string>
98
+ activeFocusCellKey: Ref<string> | ComputedRef<string>
99
+ activeErrorMapSize: Ref<number> | ComputedRef<number>
100
+ activeValidatingMapSize: Ref<number> | ComputedRef<number>
101
+ cellTooltipEnabled: RsTableViewProvideHandlers<T>['cellTooltipEnabled']
102
+ cellTooltipMode: RsTableViewProvideHandlers<T>['cellTooltipMode']
103
+ cellTooltipText: RsTableViewProvideHandlers<T>['cellTooltipText']
104
+ cellTooltipFallbackTitle: RsTableViewProvideHandlers<T>['cellTooltipFallbackTitle']
105
+ rowEditPending: RsTableViewProvideHandlers<T>['rowEditPending']
106
+ isExternalRowPending: RsTableViewProvideHandlers<T>['isExternalRowPending']
107
+ onCellStartEdit: RsTableViewProvideHandlers<T>['onCellStartEdit']
108
+ onCellCommit: RsTableViewProvideHandlers<T>['onCellCommit']
109
+ onCellCancel: RsTableViewProvideHandlers<T>['onCellCancel']
110
+ onCellUpdateDraft: RsTableViewProvideHandlers<T>['onCellUpdateDraft']
111
+ onCellNavigate: RsTableViewProvideHandlers<T>['onCellNavigate']
112
+ onRowCommit: RsTableViewProvideHandlers<T>['onRowCommit']
113
+ onRowRollback: RsTableViewProvideHandlers<T>['onRowRollback']
114
+ onGutterCommit: RsTableViewProvideHandlers<T>['onGutterCommit']
115
+ onCellClick: RsTableViewProvideHandlers<T>['onCellClick']
116
+ onCellDblclick: RsTableViewProvideHandlers<T>['onCellDblclick']
117
+ }
118
+ interaction: {
119
+ isHighlighted: (key: string) => boolean
120
+ onCellTipOver: (event: PointerEvent) => void
121
+ onCellTipOut: (event: PointerEvent) => void
122
+ } & Pick<
123
+ RsTableViewProvideHandlers<T>,
124
+ | 'resolvedDataColumnWidth'
125
+ | 'columnFilterValue'
126
+ | 'sortOrderFor'
127
+ | 'sortPriorityFor'
128
+ | 'sortIconName'
129
+ | 'onToggleSelectAll'
130
+ | 'onColumnDragOver'
131
+ | 'onColumnDrop'
132
+ | 'onColumnDragStart'
133
+ | 'onColumnDragEnd'
134
+ | 'updateColumnFilter'
135
+ | 'onHeaderClick'
136
+ | 'onResizeStart'
137
+ | 'rowKeyFor'
138
+ | 'isRowSelected'
139
+ | 'isRowIndeterminate'
140
+ | 'isRowExpanded'
141
+ | 'treeDepthOf'
142
+ | 'canExpandRow'
143
+ | 'canSelectRow'
144
+ | 'isRowDragByRow'
145
+ | 'isRowDragging'
146
+ | 'isRowDropTarget'
147
+ | 'onRowClick'
148
+ | 'onRowSelectMouseDown'
149
+ | 'onCellContextmenu'
150
+ | 'onRowDblclick'
151
+ | 'onRowContextmenu'
152
+ | 'onRowDragOver'
153
+ | 'onRowDragLeave'
154
+ | 'onRowDrop'
155
+ | 'onRowDragStart'
156
+ | 'onRowDragEnd'
157
+ | 'onToggleExpand'
158
+ | 'onToggleSelect'
159
+ >
160
+ }
161
+
162
+ /**
163
+ * 装配并 provide ViewContext。
164
+ */
165
+ export function bindRsTableViewContext<T extends RsTableRowData>(
166
+ deps: BindRsTableViewContextDeps<T>,
167
+ ) {
168
+ const { props, layout, chrome, edit, interaction } = deps
169
+ const { tableEdit } = edit
170
+
171
+ return useRsTableViewProvide<T>(
172
+ {
173
+ ...layout,
174
+ columnDraggable: props.columnDraggable,
175
+ resizable: props.resizable,
176
+ multiSort: props.multiSort,
177
+ headerLabels: chrome.headerLabels,
178
+ loading: props.loading,
179
+ hasData: chrome.hasData,
180
+ loadingMore: props.loadingMore,
181
+ infinite: props.infinite,
182
+ rowKey: props.rowKey,
183
+ striped: props.striped,
184
+ selectionType: props.selectionType,
185
+ editable: props.editable,
186
+ editTrigger: props.editTrigger,
187
+ rowCommit: props.rowCommit,
188
+ allowNull: props.allowNull,
189
+ editFocusMode: props.editFocusMode,
190
+ nullLabel: props.nullLabel,
191
+ activeEditCellKey: edit.activeEditCellKey,
192
+ activeFocusCellKey: edit.activeFocusCellKey,
193
+ activeErrorMapSize: edit.activeErrorMapSize,
194
+ activeValidatingMapSize: edit.activeValidatingMapSize,
195
+ stagedMapSize: () => tableEdit.stagedMap.value.size,
196
+ editingDraft: () => tableEdit.editingDraft.value,
197
+ editingCell: () => tableEdit.editingCell.value,
198
+ focusCell: () => tableEdit.focusCell.value,
199
+ bodyLabels: chrome.bodyLabels,
200
+ },
201
+ {
202
+ resolvedDataColumnWidth: interaction.resolvedDataColumnWidth,
203
+ columnFilterValue: interaction.columnFilterValue,
204
+ sortOrderFor: interaction.sortOrderFor,
205
+ sortPriorityFor: interaction.sortPriorityFor,
206
+ sortIconName: interaction.sortIconName,
207
+ onToggleSelectAll: interaction.onToggleSelectAll,
208
+ onColumnDragOver: interaction.onColumnDragOver,
209
+ onColumnDrop: interaction.onColumnDrop,
210
+ onColumnDragStart: interaction.onColumnDragStart,
211
+ onColumnDragEnd: interaction.onColumnDragEnd,
212
+ updateColumnFilter: interaction.updateColumnFilter,
213
+ onHeaderClick: interaction.onHeaderClick,
214
+ onResizeStart: interaction.onResizeStart,
215
+ onHeaderPointerOver: interaction.onCellTipOver,
216
+ onHeaderPointerOut: interaction.onCellTipOut,
217
+ rowKeyFor: interaction.rowKeyFor,
218
+ isRowSelected: interaction.isRowSelected,
219
+ isRowIndeterminate: interaction.isRowIndeterminate,
220
+ isRowExpanded: interaction.isRowExpanded,
221
+ isHighlighted: interaction.isHighlighted,
222
+ rowEditPending: edit.rowEditPending,
223
+ isExternalRowPending: edit.isExternalRowPending,
224
+ treeDepthOf: interaction.treeDepthOf,
225
+ canExpandRow: interaction.canExpandRow,
226
+ canSelectRow: interaction.canSelectRow,
227
+ isRowDragByRow: interaction.isRowDragByRow,
228
+ isRowDragging: interaction.isRowDragging,
229
+ isRowDropTarget: interaction.isRowDropTarget,
230
+ isRowDirty: tableEdit.isRowDirty,
231
+ hasColumnSlot: chrome.hasColumnSlot,
232
+ hasEditSlot: chrome.hasEditSlot,
233
+ cellTooltipEnabled: edit.cellTooltipEnabled,
234
+ cellTooltipMode: edit.cellTooltipMode,
235
+ cellTooltipText: edit.cellTooltipText,
236
+ cellTooltipFallbackTitle: edit.cellTooltipFallbackTitle,
237
+ getCellDraft: tableEdit.getDraft,
238
+ isCellDirty: tableEdit.isDirty,
239
+ getCellError: tableEdit.getCellError,
240
+ isCellValidating: tableEdit.isValidating,
241
+ onBodyPointerOver: interaction.onCellTipOver,
242
+ onBodyPointerOut: interaction.onCellTipOut,
243
+ onRowClick: interaction.onRowClick,
244
+ onRowSelectMouseDown: interaction.onRowSelectMouseDown,
245
+ onCellClick: edit.onCellClick,
246
+ onCellDblclick: edit.onCellDblclick,
247
+ onCellContextmenu: interaction.onCellContextmenu,
248
+ onRowDblclick: interaction.onRowDblclick,
249
+ onRowContextmenu: interaction.onRowContextmenu,
250
+ onRowDragOver: interaction.onRowDragOver,
251
+ onRowDragLeave: interaction.onRowDragLeave,
252
+ onRowDrop: interaction.onRowDrop,
253
+ onRowDragStart: interaction.onRowDragStart,
254
+ onRowDragEnd: interaction.onRowDragEnd,
255
+ onToggleExpand: interaction.onToggleExpand,
256
+ onToggleSelect: interaction.onToggleSelect,
257
+ onCellStartEdit: edit.onCellStartEdit,
258
+ onCellCommit: edit.onCellCommit,
259
+ onCellCancel: edit.onCellCancel,
260
+ onCellUpdateDraft: edit.onCellUpdateDraft,
261
+ onCellNavigate: edit.onCellNavigate,
262
+ onRowCommit: edit.onRowCommit,
263
+ onRowRollback: edit.onRowRollback,
264
+ onGutterCommit: edit.onGutterCommit,
265
+ },
266
+ )
267
+ }
268
+
269
+ export type { RowEntry }