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.
- package/CHANGELOG.md +50 -1
- package/NOTICE +2 -2
- package/package.json +13 -5
- package/src/__tests__/RsButton.spec.ts +47 -0
- package/src/__tests__/RsCard.spec.ts +160 -1
- package/src/__tests__/RsConfirmDialog.spec.ts +127 -0
- package/src/__tests__/RsContextMenu.spec.ts +12 -0
- package/src/__tests__/RsDateTimePicker.spec.ts +11 -0
- package/src/__tests__/RsDescriptions.spec.ts +50 -0
- package/src/__tests__/RsDialog.spec.ts +117 -0
- package/src/__tests__/RsDrawer.spec.ts +96 -3
- package/src/__tests__/RsDynamicTags.spec.ts +52 -0
- package/src/__tests__/RsForm.spec.ts +245 -1
- package/src/__tests__/RsInput.spec.ts +15 -1
- package/src/__tests__/RsMenu.spec.ts +406 -14
- package/src/__tests__/RsPagination.spec.ts +67 -2
- package/src/__tests__/RsSelect.spec.ts +42 -1
- package/src/__tests__/RsSwitch.spec.ts +44 -0
- package/src/__tests__/RsTable.a11y.spec.ts +83 -0
- package/src/__tests__/RsTable.dom-baseline.spec.ts +87 -0
- package/src/__tests__/RsTable.perf.spec.ts +23 -4
- package/src/__tests__/RsTable.spec.ts +63 -8
- package/src/__tests__/RsTable.ssr.spec.ts +71 -0
- package/src/__tests__/RsTable.summary.spec.ts +45 -0
- package/src/__tests__/RsTabs.spec.ts +102 -4
- package/src/__tests__/RsTerminal.spec.ts +1 -1
- package/src/__tests__/RsTimePicker.spec.ts +11 -0
- package/src/__tests__/RsUpload.spec.ts +62 -6
- package/src/__tests__/createRsDialog.spec.ts +145 -0
- package/src/__tests__/form-rules.spec.ts +76 -0
- package/src/__tests__/perf-budgets.ts +32 -0
- package/src/__tests__/rs-table-api.spec.ts +206 -0
- package/src/__tests__/rs-table-compat-matrix.spec.ts +108 -0
- package/src/__tests__/rs-table-echarts-adapter.spec.ts +43 -0
- package/src/__tests__/rs-table-grid-nav.spec.ts +63 -0
- package/src/__tests__/rs-table-isolation.spec.ts +158 -0
- package/src/__tests__/split-pane-utils.spec.ts +21 -0
- package/src/__tests__/table-chart-utils.spec.ts +88 -0
- package/src/__tests__/table-summary-utils.spec.ts +62 -0
- package/src/__tests__/table-utils.spec.ts +124 -0
- package/src/__tests__/theme.spec.ts +25 -0
- package/src/__tests__/useRsTableColumnResize.spec.ts +25 -0
- package/src/__tests__/useRsTableCore.perf.spec.ts +170 -0
- package/src/components/RsAlert.vue +212 -0
- package/src/components/RsButton.vue +145 -21
- package/src/components/RsCard.vue +200 -16
- package/src/components/RsConfirmDialog.vue +215 -28
- package/src/components/RsContextMenu.vue +51 -13
- package/src/components/RsDatePicker.vue +267 -34
- package/src/components/RsDateTimePicker.vue +19 -2
- package/src/components/RsDescriptions.vue +186 -0
- package/src/components/RsDescriptionsItem.vue +32 -0
- package/src/components/RsDialog.vue +363 -51
- package/src/components/RsDivider.vue +89 -0
- package/src/components/RsDrawer.vue +558 -33
- package/src/components/RsDropdown.vue +33 -2
- package/src/components/RsDynamicTags.vue +517 -0
- package/src/components/RsForm.vue +97 -8
- package/src/components/RsInput.vue +80 -82
- package/src/components/RsInputNumber.vue +64 -23
- package/src/components/RsLabel.vue +20 -5
- package/src/components/RsLoadingBar.vue +151 -0
- package/src/components/RsMenu.vue +73 -15
- package/src/components/RsMenuItems.vue +147 -9
- package/src/components/RsPagination.vue +93 -14
- package/src/components/RsRadio.vue +81 -0
- package/src/components/RsRadioItem.vue +156 -0
- package/src/components/RsSelect.vue +67 -58
- package/src/components/RsSplitPane.vue +69 -1
- package/src/components/RsSwitch.vue +179 -0
- package/src/components/RsTable.vue +653 -2555
- package/src/components/RsTabs.vue +415 -83
- package/src/components/RsTag.vue +191 -0
- package/src/components/RsTerminal.vue +3 -3
- package/src/components/RsTimePicker.vue +44 -5
- package/src/components/RsTimePickerColumns.vue +136 -77
- package/src/components/RsToaster.vue +58 -18
- package/src/components/RsTree.vue +39 -21
- package/src/components/RsUpload.vue +145 -12
- package/src/components/RsVNodeHost.vue +20 -0
- package/src/components/button-utils.ts +39 -0
- package/src/components/context-menu-utils.ts +6 -0
- package/src/components/date-picker-utils.ts +84 -4
- package/src/components/descriptions-utils.ts +24 -0
- package/src/components/dialog-utils.ts +147 -0
- package/src/components/dialog-window.ts +74 -9
- package/src/components/drawer-utils.ts +73 -0
- package/src/components/form-rules.ts +257 -0
- package/src/components/form-utils.ts +52 -2
- package/src/components/menu-utils.ts +11 -0
- package/src/components/overlay-utils.ts +3 -0
- package/src/components/radio-utils.ts +12 -0
- package/src/components/reka.ts +5 -0
- package/src/components/select-utils.ts +21 -2
- package/src/components/split-pane-utils.ts +65 -12
- package/src/components/table/RsTableBody.vue +217 -0
- package/src/components/table/RsTableBodyRow.vue +90 -1
- package/src/components/table/RsTableColGroup.vue +41 -0
- package/src/components/table/RsTableHeader.vue +158 -0
- package/src/components/table/RsTableSummaryRow.vue +52 -0
- package/src/components/table/rs-table-api.ts +99 -0
- package/src/components/table/rs-table-compat-matrix.ts +71 -0
- package/src/components/table/rs-table-echarts-adapter.ts +81 -0
- package/src/components/table/rs-table-feature-host.ts +178 -0
- package/src/components/table/rs-table-grid-nav.ts +122 -0
- package/src/components/table/rs-table-header-types.ts +47 -0
- package/src/components/table/rs-table-module-registry.ts +72 -0
- package/src/components/table/rs-table-props.ts +274 -0
- package/src/components/table/rs-table-view-context.ts +258 -0
- package/src/components/table/rs-table.css +84 -6
- package/src/components/table/table-chart-utils.ts +165 -0
- package/src/components/table/table-features.ts +284 -0
- package/src/components/table/table-summary-utils.ts +194 -0
- package/src/components/table-utils.ts +452 -2
- package/src/components/tabs-utils.ts +142 -2
- package/src/components/terminal-utils.ts +1 -1
- package/src/components/terminal-wheel.ts +1 -1
- package/src/components/time-picker-utils.ts +76 -3
- package/src/components/upload-utils.ts +122 -0
- package/src/components/virtual-list-utils.ts +15 -2
- package/src/composables/assembleRsTableApi.ts +79 -0
- package/src/composables/bindRsTableViewContext.ts +269 -0
- package/src/composables/createRsDialog.ts +357 -0
- package/src/composables/createRsTableEditEmitBridge.ts +38 -0
- package/src/composables/useRsLoadingBar.ts +36 -0
- package/src/composables/useRsTable.ts +134 -0
- package/src/composables/useRsTableA11y.ts +52 -0
- package/src/composables/useRsTableChartBridge.ts +79 -0
- package/src/composables/useRsTableColumnLayout.ts +320 -0
- package/src/composables/useRsTableColumnResize.ts +244 -0
- package/src/composables/useRsTableColumnVirtual.ts +180 -0
- package/src/composables/useRsTableColumns.ts +200 -0
- package/src/composables/useRsTableContextMenu.ts +257 -0
- package/src/composables/useRsTableCore.ts +256 -0
- package/src/composables/useRsTableEditActions.ts +606 -0
- package/src/composables/useRsTableEditLayer.ts +251 -0
- package/src/composables/useRsTableEngine.ts +357 -0
- package/src/composables/useRsTableGridKeyboard.ts +123 -0
- package/src/composables/useRsTableHeadless.ts +137 -0
- package/src/composables/useRsTableInteraction.ts +433 -0
- package/src/composables/useRsTableScrollHost.ts +75 -0
- package/src/composables/useRsTableScrollLayout.ts +255 -0
- package/src/composables/useRsTableSelectionSource.ts +89 -0
- package/src/composables/useRsTableShell.ts +416 -0
- package/src/composables/useRsTableShellChrome.ts +170 -0
- package/src/composables/useRsTableSummary.ts +113 -0
- package/src/composables/useRsTableViewProvide.ts +263 -0
- package/src/composables/useRsTableVirtual.ts +154 -0
- package/src/composables/useRsTabsNav.ts +4 -0
- package/src/composables/useTableEdit.ts +1 -1
- package/src/icons/lucide.ts +2 -2
- package/src/index.ts +309 -9
- package/src/locale/messages.ts +30 -0
- package/src/styles.css +305 -52
- package/src/theme/brand.example.css +21 -2
- package/src/theme/presets.ts +4 -0
- package/src/theme/types.ts +67 -0
- package/src/components/RsTableColgroup.vue +0 -17
- 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
|
-
|
|
37
|
-
|
|
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:
|
|
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
|
|
14
|
+
/** height 为 0 / 百分比时由父级撑满,组件内用 ResizeObserver 测量可视高度 */
|
|
15
15
|
export function isVirtualListFillHeight(height?: number | string): boolean {
|
|
16
|
-
|
|
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 }
|