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
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* RsTable ARIA Grid 键盘漫游(与编辑键盘解耦)。
|
|
3
|
+
*
|
|
4
|
+
* - 始终可在壳层焦点下移动 focusCell(只读表也可用)
|
|
5
|
+
* - 编辑中 / 表单控件内不抢键
|
|
6
|
+
* - 箭头 / Home / End / Ctrl+Home|End / PageUp|PageDown
|
|
7
|
+
* - 移动后将焦点格 scrollIntoView(nearest)
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { nextTick, type Ref } from 'vue'
|
|
11
|
+
import type { useTableEdit } from './useTableEdit'
|
|
12
|
+
import {
|
|
13
|
+
navigateGridCell,
|
|
14
|
+
resolveGridNavDirection,
|
|
15
|
+
type RsTableGridCellRef,
|
|
16
|
+
} from '../components/table/rs-table-grid-nav'
|
|
17
|
+
import type { RsTableColumn, RsTableRowData, RsTableRowEntry } from '../components/table-utils'
|
|
18
|
+
|
|
19
|
+
type TableEditApi = ReturnType<typeof useTableEdit>
|
|
20
|
+
|
|
21
|
+
export interface UseRsTableGridKeyboardOptions<T extends RsTableRowData> {
|
|
22
|
+
tableEdit: TableEditApi
|
|
23
|
+
/** 默认 true;可关以兼容旧行为 */
|
|
24
|
+
enabled?: () => boolean
|
|
25
|
+
dataRows: () => Array<Extract<RsTableRowEntry<T>, { type: 'row' }>>
|
|
26
|
+
rowKeyFor: (entry: Extract<RsTableRowEntry<T>, { type: 'row' }>) => string
|
|
27
|
+
/** 可见数据列(与虚拟列切片一致) */
|
|
28
|
+
colKeys: () => string[]
|
|
29
|
+
displayColumns?: () => RsTableColumn<T>[]
|
|
30
|
+
applyRowClickHighlight: (rowKey: string) => void
|
|
31
|
+
/** PageUp/Down 跨越行数,默认 10 */
|
|
32
|
+
pageSize?: () => number
|
|
33
|
+
/** 滚动容器:用于焦点格滚入视口 */
|
|
34
|
+
scrollContainerRef?: Ref<HTMLElement | null | undefined>
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function escapeAttr(value: string): string {
|
|
38
|
+
if (typeof CSS !== 'undefined' && typeof CSS.escape === 'function') {
|
|
39
|
+
return CSS.escape(value)
|
|
40
|
+
}
|
|
41
|
+
return value.replace(/\\/g, '\\\\').replace(/"/g, '\\"')
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function scrollFocusCellIntoView(
|
|
45
|
+
container: HTMLElement | null | undefined,
|
|
46
|
+
cell: RsTableGridCellRef,
|
|
47
|
+
): void {
|
|
48
|
+
if (!container) return
|
|
49
|
+
const selector = `tr[data-row-key="${escapeAttr(cell.rowKey)}"] td[data-col-key="${escapeAttr(cell.colKey)}"]`
|
|
50
|
+
const el = container.querySelector(selector) as HTMLElement | null
|
|
51
|
+
// jsdom 无 scrollIntoView;浏览器 / happy-dom 才滚
|
|
52
|
+
if (el && typeof el.scrollIntoView === 'function') {
|
|
53
|
+
el.scrollIntoView({ block: 'nearest', inline: 'nearest' })
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* 网格键盘漫游 API。
|
|
59
|
+
*/
|
|
60
|
+
export function useRsTableGridKeyboard<T extends RsTableRowData>(
|
|
61
|
+
options: UseRsTableGridKeyboardOptions<T>,
|
|
62
|
+
) {
|
|
63
|
+
function buildRows(): Array<{ rowKey: string; rowIndex: number }> {
|
|
64
|
+
return options.dataRows().map((entry) => ({
|
|
65
|
+
rowKey: options.rowKeyFor(entry),
|
|
66
|
+
rowIndex: entry.rowIndex,
|
|
67
|
+
}))
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function resolveColKeys(): string[] {
|
|
71
|
+
const keys = options.colKeys()
|
|
72
|
+
if (keys.length) return keys
|
|
73
|
+
return (options.displayColumns?.() ?? []).map((c) => c.key)
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* 处理网格导航键。已处理返回 true(调用方应停止后续编辑键逻辑中的箭头分支)。
|
|
78
|
+
*/
|
|
79
|
+
function onGridKeydown(event: KeyboardEvent): boolean {
|
|
80
|
+
if (options.enabled && !options.enabled()) return false
|
|
81
|
+
if (options.tableEdit.editingCell.value) return false
|
|
82
|
+
|
|
83
|
+
const target = event.target as HTMLElement | null
|
|
84
|
+
if (target?.closest('input, textarea, select, [contenteditable="true"]')) {
|
|
85
|
+
return false
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
const direction = resolveGridNavDirection(event)
|
|
89
|
+
if (!direction) return false
|
|
90
|
+
|
|
91
|
+
const rows = buildRows()
|
|
92
|
+
const colKeys = resolveColKeys()
|
|
93
|
+
if (!rows.length || !colKeys.length) return false
|
|
94
|
+
|
|
95
|
+
const focus = options.tableEdit.focusCell.value
|
|
96
|
+
const current: RsTableGridCellRef | null = focus
|
|
97
|
+
? {
|
|
98
|
+
rowKey: focus.rowKey,
|
|
99
|
+
colKey: focus.colKey,
|
|
100
|
+
rowIndex: focus.rowIndex,
|
|
101
|
+
}
|
|
102
|
+
: null
|
|
103
|
+
|
|
104
|
+
const next = navigateGridCell(
|
|
105
|
+
rows,
|
|
106
|
+
colKeys,
|
|
107
|
+
current,
|
|
108
|
+
direction,
|
|
109
|
+
options.pageSize?.() ?? 10,
|
|
110
|
+
)
|
|
111
|
+
if (!next) return false
|
|
112
|
+
|
|
113
|
+
event.preventDefault()
|
|
114
|
+
options.tableEdit.setFocusCell(next)
|
|
115
|
+
options.applyRowClickHighlight(next.rowKey)
|
|
116
|
+
void nextTick(() => {
|
|
117
|
+
scrollFocusCellIntoView(options.scrollContainerRef?.value, next)
|
|
118
|
+
})
|
|
119
|
+
return true
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
return { onGridKeydown }
|
|
123
|
+
}
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* RsTable 无头驱动入口(无模板也能跑 Engine / Features / Api)。
|
|
3
|
+
*
|
|
4
|
+
* 适用:服务端预计算、自定义渲染器、图表只消费 snapshot。
|
|
5
|
+
* 不含列宽 DOM / 右键 / 编辑交互(那些依赖视图壳)。
|
|
6
|
+
*
|
|
7
|
+
* 多表:每次调用产生独立 Core + FeatureHost;互不共享状态。
|
|
8
|
+
* 唯一全局点是 RsTableModuleRegistry(显式 register 才会影响所有实例)。
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import type { Ref } from 'vue'
|
|
12
|
+
import type { RsTableColumn, RsTableRowData, RsTableRowKey } from '../components/table-utils'
|
|
13
|
+
import type { RsTableFeature } from '../components/table/table-features'
|
|
14
|
+
import { useRsTableCore, type UseRsTableCoreOptions } from './useRsTableCore'
|
|
15
|
+
|
|
16
|
+
export interface UseRsTableHeadlessOptions<T extends RsTableRowData> {
|
|
17
|
+
columns: Ref<RsTableColumn<T>[]> | (() => RsTableColumn<T>[])
|
|
18
|
+
data: Ref<T[]> | (() => T[])
|
|
19
|
+
rowKey?: RsTableRowKey<T> | (() => RsTableRowKey<T> | undefined)
|
|
20
|
+
selectable?: boolean
|
|
21
|
+
features?: RsTableFeature<T>[] | (() => RsTableFeature<T>[] | undefined)
|
|
22
|
+
/** 最小 emit 桩;受控同步时可传入 */
|
|
23
|
+
emit?: UseRsTableCoreOptions<T>['emit']
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function readRefOrGetter<T>(source: Ref<T> | (() => T)): () => T {
|
|
27
|
+
return typeof source === 'function' ? (source as () => T) : () => (source as Ref<T>).value
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* 无头表格:复用 useRsTableCore(已含 Feature 绑定),再装配 Api。
|
|
32
|
+
*/
|
|
33
|
+
export function useRsTableHeadless<T extends RsTableRowData>(
|
|
34
|
+
options: UseRsTableHeadlessOptions<T>,
|
|
35
|
+
) {
|
|
36
|
+
const getColumns = readRefOrGetter(options.columns)
|
|
37
|
+
const getData = readRefOrGetter(options.data)
|
|
38
|
+
const getRowKey = () =>
|
|
39
|
+
typeof options.rowKey === 'function' ? options.rowKey() : options.rowKey
|
|
40
|
+
const getFeatures = () =>
|
|
41
|
+
typeof options.features === 'function' ? options.features() : options.features
|
|
42
|
+
|
|
43
|
+
const noopEmit = ((() => undefined) as unknown) as UseRsTableCoreOptions<T>['emit']
|
|
44
|
+
|
|
45
|
+
const core = useRsTableCore<T>({
|
|
46
|
+
columns: getColumns,
|
|
47
|
+
data: getData,
|
|
48
|
+
rowKey: getRowKey,
|
|
49
|
+
compact: () => false,
|
|
50
|
+
size: () => 'md',
|
|
51
|
+
columnOrder: () => undefined,
|
|
52
|
+
defaultColumnOrder: [],
|
|
53
|
+
columnFilters: () => undefined,
|
|
54
|
+
defaultColumnFilters: {},
|
|
55
|
+
initialColumnWidths: () => undefined,
|
|
56
|
+
resizable: () => false,
|
|
57
|
+
columnLayout: () => 'auto',
|
|
58
|
+
sort: () => undefined,
|
|
59
|
+
defaultSort: null,
|
|
60
|
+
sorts: () => undefined,
|
|
61
|
+
defaultSorts: [],
|
|
62
|
+
multiSort: () => false,
|
|
63
|
+
remoteSort: () => false,
|
|
64
|
+
filterText: () => undefined,
|
|
65
|
+
filterKeys: () => undefined,
|
|
66
|
+
groupBy: () => undefined,
|
|
67
|
+
groupLabel: () => undefined,
|
|
68
|
+
treeConfig: () => undefined,
|
|
69
|
+
expandable: () => false,
|
|
70
|
+
rowExpandable: () => undefined,
|
|
71
|
+
selectedRowKeys: () => undefined,
|
|
72
|
+
defaultSelectedRowKeys: [],
|
|
73
|
+
expandedRowKeys: () => undefined,
|
|
74
|
+
defaultExpandedRowKeys: [],
|
|
75
|
+
rowSelectable: () => undefined,
|
|
76
|
+
height: () => 320,
|
|
77
|
+
layoutActive: () => true,
|
|
78
|
+
viewKey: () => undefined,
|
|
79
|
+
virtual: () => false,
|
|
80
|
+
virtualAutoThreshold: () => 50,
|
|
81
|
+
fill: () => false,
|
|
82
|
+
infinite: () => false,
|
|
83
|
+
virtualOnInfinite: () => true,
|
|
84
|
+
overscan: () => 4,
|
|
85
|
+
expandRowHeight: () => undefined,
|
|
86
|
+
rowHeight: () => undefined,
|
|
87
|
+
selectable: () => Boolean(options.selectable),
|
|
88
|
+
editable: () => false,
|
|
89
|
+
contextMenu: () => false,
|
|
90
|
+
summaryFeatureEnabled: () => false,
|
|
91
|
+
features: getFeatures,
|
|
92
|
+
emit: options.emit ?? noopEmit,
|
|
93
|
+
})
|
|
94
|
+
|
|
95
|
+
const api = core.tableSurface.createApi(
|
|
96
|
+
{
|
|
97
|
+
getRowByKey: (rowKey) => {
|
|
98
|
+
const entry = core.dataRows.value.find(
|
|
99
|
+
(item) => core.rowKeyByIndex.value.get(item.rowIndex) === rowKey,
|
|
100
|
+
)
|
|
101
|
+
return entry?.row
|
|
102
|
+
},
|
|
103
|
+
getRowByIndex: (index) =>
|
|
104
|
+
core.dataRows.value.find((item) => item.rowIndex === index)?.row,
|
|
105
|
+
getColumnValues: () => [],
|
|
106
|
+
getCellValue: () => undefined,
|
|
107
|
+
getViewRows: () => core.viewRows.value,
|
|
108
|
+
getSelectedRows: () => core.selectedRows.value,
|
|
109
|
+
getSelectedRowKeys: () => [...core.selectedRowKeys.value],
|
|
110
|
+
getAnalyticsSnapshot: () => core.analyticsSource.getSnapshot(),
|
|
111
|
+
subscribeAnalytics: (listener) => core.analyticsSource.subscribe(listener),
|
|
112
|
+
getHighlightedRowKey: () => undefined,
|
|
113
|
+
setHighlightedRowKey: () => undefined,
|
|
114
|
+
cancelCellEdit: () => undefined,
|
|
115
|
+
cancelAllEdits: () => undefined,
|
|
116
|
+
getDirtyCellKeys: () => [],
|
|
117
|
+
getCellError: () => undefined,
|
|
118
|
+
setCellError: () => undefined,
|
|
119
|
+
stageCell: () => undefined,
|
|
120
|
+
rejectRowEdit: () => undefined,
|
|
121
|
+
undoEdit: () => undefined,
|
|
122
|
+
redoEdit: () => undefined,
|
|
123
|
+
commitRowEdits: () => undefined,
|
|
124
|
+
rollbackRowEdits: () => undefined,
|
|
125
|
+
getToolbarItems: () => core.tableSurface.getToolbarItems(),
|
|
126
|
+
getOverlayContributions: () => core.tableSurface.getOverlayContributions(),
|
|
127
|
+
},
|
|
128
|
+
{ provide: false },
|
|
129
|
+
)
|
|
130
|
+
|
|
131
|
+
return {
|
|
132
|
+
api,
|
|
133
|
+
core,
|
|
134
|
+
getToolbarItems: () => core.tableSurface.getToolbarItems(),
|
|
135
|
+
getOverlayContributions: () => core.tableSurface.getOverlayContributions(),
|
|
136
|
+
}
|
|
137
|
+
}
|
|
@@ -0,0 +1,433 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* RsTable 行/列交互:排序点击、列拖拽排序、行选/展开、行拖拽封装。
|
|
3
|
+
*
|
|
4
|
+
* 性能约定:
|
|
5
|
+
* - 不引入对 data 的 deep watch
|
|
6
|
+
* - rowKeyFor 走 Engine 的 rowKeyByIndex 缓存,避免热路径重复 resolve
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { ref, type ComputedRef, type Ref } from 'vue'
|
|
10
|
+
import {
|
|
11
|
+
createTableRowDragHandlers,
|
|
12
|
+
createTableRowDragState,
|
|
13
|
+
type RsTableRowDragTrigger,
|
|
14
|
+
type RsTableRowDropMode,
|
|
15
|
+
} from '../components/table-drag'
|
|
16
|
+
import {
|
|
17
|
+
getSortOrderForKey,
|
|
18
|
+
getSortPriorityForKey,
|
|
19
|
+
getTableTreeChildren,
|
|
20
|
+
hasTableTreeChildren,
|
|
21
|
+
isTableRowDisabled,
|
|
22
|
+
reorderColumnKeys,
|
|
23
|
+
resolveRowKey,
|
|
24
|
+
resolveTableTreeCheckState,
|
|
25
|
+
selectRowKeys,
|
|
26
|
+
selectRowKeysByClick,
|
|
27
|
+
toggleExpandedRowKeys,
|
|
28
|
+
toggleMultiSortState,
|
|
29
|
+
toggleSelectAll,
|
|
30
|
+
toggleSortState,
|
|
31
|
+
toggleTableTreeCheck,
|
|
32
|
+
type RsTableColumn,
|
|
33
|
+
type RsTableRowData,
|
|
34
|
+
type RsTableRowEntry,
|
|
35
|
+
type RsTableRowKey,
|
|
36
|
+
type RsTableSelectionType,
|
|
37
|
+
type RsTableSortOrder,
|
|
38
|
+
type RsTableSortState,
|
|
39
|
+
type RsTableTreeConfig,
|
|
40
|
+
type RsTableTreeNodeIndex,
|
|
41
|
+
type RsTableRowDropPosition,
|
|
42
|
+
} from '../components/table-utils'
|
|
43
|
+
|
|
44
|
+
function read<T>(source: ComputedRef<T> | (() => T) | Ref<T>): T {
|
|
45
|
+
if (typeof source === 'function') return (source as () => T)()
|
|
46
|
+
return (source as Ref<T> | ComputedRef<T>).value
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export interface UseRsTableInteractionOptions<T extends RsTableRowData> {
|
|
50
|
+
multiSort: () => boolean
|
|
51
|
+
maxSort: () => number | undefined
|
|
52
|
+
columnDraggable: () => boolean
|
|
53
|
+
selectable: () => boolean
|
|
54
|
+
selectionType: () => RsTableSelectionType
|
|
55
|
+
rowSelectable?: (row: T, index: number) => boolean
|
|
56
|
+
rowDraggable: () => boolean
|
|
57
|
+
rowDragTrigger: () => RsTableRowDragTrigger
|
|
58
|
+
rowDropMode: () => RsTableRowDropMode
|
|
59
|
+
rowDraggableWhen?: (row: T, index: number) => boolean
|
|
60
|
+
rowDropTargetWhen?: (row: T, index: number) => boolean
|
|
61
|
+
canRowDrop?: (dragKeys: string[], dropKey: string) => boolean
|
|
62
|
+
rowKey: () => RsTableRowKey<T> | undefined
|
|
63
|
+
rowKeyByIndex: () => Map<number, string>
|
|
64
|
+
selectedRowKeys: {
|
|
65
|
+
get: () => string[]
|
|
66
|
+
set: (keys: string[]) => void
|
|
67
|
+
}
|
|
68
|
+
selectedKeySet: () => Set<string>
|
|
69
|
+
selectableRowKeys: () => string[]
|
|
70
|
+
selectAllState: () => 'checked' | 'indeterminate' | 'unchecked'
|
|
71
|
+
expandedRowKeys: {
|
|
72
|
+
get: () => string[]
|
|
73
|
+
set: (keys: string[]) => void
|
|
74
|
+
}
|
|
75
|
+
expandedKeySet: () => Set<string>
|
|
76
|
+
treeMode: () => boolean
|
|
77
|
+
treeCheckStrictly: () => boolean
|
|
78
|
+
treeLazy: () => boolean
|
|
79
|
+
treeChildrenField: () => string
|
|
80
|
+
treeIsLeafField: () => string
|
|
81
|
+
treeLoadingKeys: {
|
|
82
|
+
get: () => string[]
|
|
83
|
+
set: (keys: string[]) => void
|
|
84
|
+
}
|
|
85
|
+
treeLoadingKeySet: () => Set<string>
|
|
86
|
+
tableTreeNodeIndex: () => Map<string, RsTableTreeNodeIndex> | null
|
|
87
|
+
treeConfig: () => RsTableTreeConfig<T> | undefined
|
|
88
|
+
expandable: () => boolean
|
|
89
|
+
rowExpandable?: (row: T, index: number) => boolean
|
|
90
|
+
sortState: {
|
|
91
|
+
get: () => RsTableSortState | null
|
|
92
|
+
set: (value: RsTableSortState | null) => void
|
|
93
|
+
}
|
|
94
|
+
sortsState: {
|
|
95
|
+
get: () => RsTableSortState[]
|
|
96
|
+
set: (value: RsTableSortState[]) => void
|
|
97
|
+
}
|
|
98
|
+
columnOrderState: {
|
|
99
|
+
get: () => string[]
|
|
100
|
+
set: (value: string[]) => void
|
|
101
|
+
}
|
|
102
|
+
/** 行选时若正在编辑则不改选中 */
|
|
103
|
+
isEditingAny: () => boolean
|
|
104
|
+
applyRowClickHighlight: (rowKey: string) => void
|
|
105
|
+
onRowClickEmit: (row: T, index: number) => void
|
|
106
|
+
onRowDblclickEmit: (row: T, index: number) => void
|
|
107
|
+
onRowDragStartEmit: (dragKeys: string[], event: DragEvent) => void
|
|
108
|
+
onRowDropEmit: (dragKeys: string[], dropKey: string, position: RsTableRowDropPosition) => void
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* 表格交互 API(排序 / 列拖 / 行选展开 / 行拖)。
|
|
113
|
+
*/
|
|
114
|
+
export function useRsTableInteraction<T extends RsTableRowData>(
|
|
115
|
+
options: UseRsTableInteractionOptions<T>,
|
|
116
|
+
) {
|
|
117
|
+
const dragColumnKey = ref<string | null>(null)
|
|
118
|
+
const dropColumnKey = ref<string | null>(null)
|
|
119
|
+
const selectionAnchorKey = ref<string | null>(null)
|
|
120
|
+
const rowDragState = createTableRowDragState()
|
|
121
|
+
const { dragRowKeys, dropRowTargetKey, dropRowPosition } = rowDragState
|
|
122
|
+
|
|
123
|
+
function rowKeyFor(entry: Extract<RsTableRowEntry<T>, { type: 'row' }>): string {
|
|
124
|
+
return (
|
|
125
|
+
options.rowKeyByIndex().get(entry.rowIndex) ??
|
|
126
|
+
entry.treeKey ??
|
|
127
|
+
resolveRowKey(entry.row, entry.rowIndex, options.rowKey())
|
|
128
|
+
)
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
function sortOrderFor(key: string): RsTableSortOrder {
|
|
132
|
+
if (options.multiSort()) return getSortOrderForKey(options.sortsState.get(), key)
|
|
133
|
+
const sort = options.sortState.get()
|
|
134
|
+
return sort?.key === key ? sort.order : null
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
function sortPriorityFor(key: string): number {
|
|
138
|
+
if (!options.multiSort()) return 0
|
|
139
|
+
return getSortPriorityForKey(options.sortsState.get(), key)
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
function sortIconName(key: string): string {
|
|
143
|
+
const order = sortOrderFor(key)
|
|
144
|
+
if (order === 'asc') return 'arrow-up'
|
|
145
|
+
if (order === 'desc') return 'arrow-down'
|
|
146
|
+
return 'arrow-up-down'
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
function onHeaderClick(column: RsTableColumn<T>): void {
|
|
150
|
+
if (!column.sortable) return
|
|
151
|
+
if (options.multiSort()) {
|
|
152
|
+
options.sortsState.set(
|
|
153
|
+
toggleMultiSortState(options.sortsState.get(), column.key, options.maxSort()),
|
|
154
|
+
)
|
|
155
|
+
return
|
|
156
|
+
}
|
|
157
|
+
options.sortState.set(toggleSortState(options.sortState.get(), column.key))
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
function onColumnDragStart(key: string, event: DragEvent): void {
|
|
161
|
+
if (!options.columnDraggable()) return
|
|
162
|
+
dragColumnKey.value = key
|
|
163
|
+
dropColumnKey.value = null
|
|
164
|
+
if (!event.dataTransfer) return
|
|
165
|
+
event.dataTransfer.setData('text/plain', key)
|
|
166
|
+
event.dataTransfer.effectAllowed = 'move'
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
function onColumnDragOver(key: string, event: DragEvent): void {
|
|
170
|
+
if (!options.columnDraggable() || !dragColumnKey.value) return
|
|
171
|
+
if (dragColumnKey.value === key) {
|
|
172
|
+
if (dropColumnKey.value !== null) dropColumnKey.value = null
|
|
173
|
+
return
|
|
174
|
+
}
|
|
175
|
+
event.preventDefault()
|
|
176
|
+
if (dropColumnKey.value !== key) dropColumnKey.value = key
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
function onColumnDrop(key: string, event: DragEvent): void {
|
|
180
|
+
if (!options.columnDraggable() || !dragColumnKey.value) return
|
|
181
|
+
event.preventDefault()
|
|
182
|
+
if (dragColumnKey.value === key) return
|
|
183
|
+
options.columnOrderState.set(
|
|
184
|
+
reorderColumnKeys(options.columnOrderState.get(), dragColumnKey.value, key),
|
|
185
|
+
)
|
|
186
|
+
dragColumnKey.value = null
|
|
187
|
+
dropColumnKey.value = null
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
function onColumnDragEnd(): void {
|
|
191
|
+
dragColumnKey.value = null
|
|
192
|
+
dropColumnKey.value = null
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
const isRowSelection = () =>
|
|
196
|
+
options.selectable() && options.selectionType() === 'row'
|
|
197
|
+
|
|
198
|
+
function canSelectRow(entry: Extract<RsTableRowEntry<T>, { type: 'row' }>): boolean {
|
|
199
|
+
if (isTableRowDisabled(entry.row)) return false
|
|
200
|
+
return options.rowSelectable ? options.rowSelectable(entry.row, entry.rowIndex) : true
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
function isRowSelected(entry: Extract<RsTableRowEntry<T>, { type: 'row' }>): boolean {
|
|
204
|
+
const key = rowKeyFor(entry)
|
|
205
|
+
const index = options.tableTreeNodeIndex()
|
|
206
|
+
if (index && !options.treeCheckStrictly()) {
|
|
207
|
+
return resolveTableTreeCheckState(key, options.selectedKeySet(), index, false) === 'checked'
|
|
208
|
+
}
|
|
209
|
+
return options.selectedKeySet().has(key)
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
function isRowIndeterminate(entry: Extract<RsTableRowEntry<T>, { type: 'row' }>): boolean {
|
|
213
|
+
const index = options.tableTreeNodeIndex()
|
|
214
|
+
if (!index || options.treeCheckStrictly()) return false
|
|
215
|
+
return (
|
|
216
|
+
resolveTableTreeCheckState(rowKeyFor(entry), options.selectedKeySet(), index, false) ===
|
|
217
|
+
'indeterminate'
|
|
218
|
+
)
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
function onToggleRow(entry: Extract<RsTableRowEntry<T>, { type: 'row' }>): void {
|
|
222
|
+
if (!canSelectRow(entry)) return
|
|
223
|
+
const key = rowKeyFor(entry)
|
|
224
|
+
const index = options.tableTreeNodeIndex()
|
|
225
|
+
if (index && !options.treeCheckStrictly() && options.selectionType() !== 'radio') {
|
|
226
|
+
options.selectedRowKeys.set(
|
|
227
|
+
toggleTableTreeCheck(key, options.selectedKeySet(), index, false),
|
|
228
|
+
)
|
|
229
|
+
return
|
|
230
|
+
}
|
|
231
|
+
options.selectedRowKeys.set(
|
|
232
|
+
selectRowKeys(options.selectedRowKeys.get(), key, options.selectionType()),
|
|
233
|
+
)
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
function onToggleSelectAll(): void {
|
|
237
|
+
const select = options.selectAllState() !== 'checked'
|
|
238
|
+
options.selectedRowKeys.set(
|
|
239
|
+
toggleSelectAll(options.selectedRowKeys.get(), options.selectableRowKeys(), select),
|
|
240
|
+
)
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
function canExpandRow(entry: Extract<RsTableRowEntry<T>, { type: 'row' }>): boolean {
|
|
244
|
+
if (options.treeMode()) {
|
|
245
|
+
if (entry.hasChildren != null) return entry.hasChildren
|
|
246
|
+
return hasTableTreeChildren(entry.row, {
|
|
247
|
+
childrenField: options.treeChildrenField(),
|
|
248
|
+
isLeafField: options.treeIsLeafField(),
|
|
249
|
+
lazy: options.treeLazy(),
|
|
250
|
+
})
|
|
251
|
+
}
|
|
252
|
+
if (!options.expandable()) return false
|
|
253
|
+
if (options.rowExpandable) return options.rowExpandable(entry.row, entry.rowIndex)
|
|
254
|
+
return true
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
function isRowExpanded(entry: Extract<RsTableRowEntry<T>, { type: 'row' }>): boolean {
|
|
258
|
+
return options.expandedKeySet().has(rowKeyFor(entry))
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
function treeDepthOf(entry: Extract<RsTableRowEntry<T>, { type: 'row' }>): number {
|
|
262
|
+
return entry.depth ?? 0
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
async function onToggleExpand(
|
|
266
|
+
entry: Extract<RsTableRowEntry<T>, { type: 'row' }>,
|
|
267
|
+
): Promise<void> {
|
|
268
|
+
if (!canExpandRow(entry)) return
|
|
269
|
+
const key = rowKeyFor(entry)
|
|
270
|
+
const expanding = !options.expandedKeySet().has(key)
|
|
271
|
+
const tree = options.treeConfig()
|
|
272
|
+
|
|
273
|
+
if (
|
|
274
|
+
options.treeMode() &&
|
|
275
|
+
expanding &&
|
|
276
|
+
options.treeLazy() &&
|
|
277
|
+
tree?.loadData &&
|
|
278
|
+
getTableTreeChildren(entry.row, options.treeChildrenField()).length === 0
|
|
279
|
+
) {
|
|
280
|
+
if (options.treeLoadingKeySet().has(key)) return
|
|
281
|
+
options.treeLoadingKeys.set([...options.treeLoadingKeys.get(), key])
|
|
282
|
+
try {
|
|
283
|
+
const loaded = await tree.loadData(entry.row, key)
|
|
284
|
+
if (Array.isArray(loaded)) {
|
|
285
|
+
;(entry.row as Record<string, unknown>)[options.treeChildrenField()] = loaded
|
|
286
|
+
}
|
|
287
|
+
} finally {
|
|
288
|
+
options.treeLoadingKeys.set(options.treeLoadingKeys.get().filter((item) => item !== key))
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
options.expandedRowKeys.set(toggleExpandedRowKeys(options.expandedRowKeys.get(), key))
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
function onRowClick(entry: RsTableRowEntry<T>, event?: MouseEvent): void {
|
|
296
|
+
if (entry.type !== 'row') return
|
|
297
|
+
const rowKey = rowKeyFor(entry)
|
|
298
|
+
if (isRowSelection() && canSelectRow(entry) && !options.isEditingAny()) {
|
|
299
|
+
const toggle = Boolean(event && (event.ctrlKey || event.metaKey))
|
|
300
|
+
const range = Boolean(event?.shiftKey)
|
|
301
|
+
options.selectedRowKeys.set(
|
|
302
|
+
selectRowKeysByClick(options.selectedRowKeys.get(), rowKey, {
|
|
303
|
+
toggle,
|
|
304
|
+
range,
|
|
305
|
+
orderedKeys: options.selectableRowKeys(),
|
|
306
|
+
anchorKey: selectionAnchorKey.value,
|
|
307
|
+
}),
|
|
308
|
+
)
|
|
309
|
+
if (!range) selectionAnchorKey.value = rowKey
|
|
310
|
+
if (typeof window !== 'undefined') {
|
|
311
|
+
window.getSelection()?.removeAllRanges()
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
options.applyRowClickHighlight(rowKey)
|
|
315
|
+
options.onRowClickEmit(entry.row, entry.rowIndex)
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
function onRowSelectMouseDown(event: MouseEvent): void {
|
|
319
|
+
if (!isRowSelection()) return
|
|
320
|
+
if (event.shiftKey || event.ctrlKey || event.metaKey) {
|
|
321
|
+
event.preventDefault()
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
function onRowDblclick(entry: RsTableRowEntry<T>, _event?: MouseEvent): void {
|
|
326
|
+
if (entry.type !== 'row') return
|
|
327
|
+
options.onRowDblclickEmit(entry.row, entry.rowIndex)
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
const rowDrag = createTableRowDragHandlers<T>({
|
|
331
|
+
state: rowDragState,
|
|
332
|
+
getRowDraggable: () => options.rowDraggable(),
|
|
333
|
+
getRowDragTrigger: () => options.rowDragTrigger(),
|
|
334
|
+
getRowDropMode: () => options.rowDropMode(),
|
|
335
|
+
rowDraggableWhen: options.rowDraggableWhen,
|
|
336
|
+
rowDropTargetWhen: options.rowDropTargetWhen,
|
|
337
|
+
canRowDrop: options.canRowDrop,
|
|
338
|
+
rowKeyFor: (row, index) => resolveRowKey(row, index, options.rowKey()),
|
|
339
|
+
isRowDisabled: isTableRowDisabled,
|
|
340
|
+
getSelectedKeys: () => options.selectedRowKeys.get(),
|
|
341
|
+
onDragStart: (dragKeys, event) => options.onRowDragStartEmit(dragKeys, event),
|
|
342
|
+
onDrop: (dragKeys, dropKey, position) =>
|
|
343
|
+
options.onRowDropEmit(dragKeys, dropKey, position),
|
|
344
|
+
})
|
|
345
|
+
|
|
346
|
+
function onRowDragStart(
|
|
347
|
+
entry: Extract<RsTableRowEntry<T>, { type: 'row' }>,
|
|
348
|
+
event: DragEvent,
|
|
349
|
+
): void {
|
|
350
|
+
rowDrag.onRowDragStart(entry.row, entry.rowIndex, event)
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
function onRowDragOver(
|
|
354
|
+
entry: Extract<RsTableRowEntry<T>, { type: 'row' }>,
|
|
355
|
+
event: DragEvent,
|
|
356
|
+
): void {
|
|
357
|
+
rowDrag.onRowDragOver(entry.row, entry.rowIndex, event)
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
function onRowDragLeave(event: DragEvent): void {
|
|
361
|
+
rowDrag.onRowDragLeave(event)
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
function onRowDrop(
|
|
365
|
+
entry: Extract<RsTableRowEntry<T>, { type: 'row' }>,
|
|
366
|
+
event: DragEvent,
|
|
367
|
+
): void {
|
|
368
|
+
rowDrag.onRowDrop(entry.row, entry.rowIndex, event)
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
function onRowDragEnd(): void {
|
|
372
|
+
rowDrag.onRowDragEnd()
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
function isRowDropTarget(entry: Extract<RsTableRowEntry<T>, { type: 'row' }>): boolean {
|
|
376
|
+
return rowDrag.isRowDropTarget(rowKeyFor(entry))
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
function isRowDragging(entry: Extract<RsTableRowEntry<T>, { type: 'row' }>): boolean {
|
|
380
|
+
return rowDrag.isRowDragging(rowKeyFor(entry))
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
function canDragRow(entry: Extract<RsTableRowEntry<T>, { type: 'row' }>): boolean {
|
|
384
|
+
return rowDrag.canDragRow(entry.row, entry.rowIndex)
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
function isRowDragByRow(entry: Extract<RsTableRowEntry<T>, { type: 'row' }>): boolean {
|
|
388
|
+
return options.rowDraggable() && options.rowDragTrigger() === 'row' && canDragRow(entry)
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
return {
|
|
392
|
+
dragColumnKey,
|
|
393
|
+
dropColumnKey,
|
|
394
|
+
selectionAnchorKey,
|
|
395
|
+
dragRowKeys,
|
|
396
|
+
dropRowTargetKey,
|
|
397
|
+
dropRowPosition,
|
|
398
|
+
rowKeyFor,
|
|
399
|
+
sortOrderFor,
|
|
400
|
+
sortPriorityFor,
|
|
401
|
+
sortIconName,
|
|
402
|
+
onHeaderClick,
|
|
403
|
+
onColumnDragStart,
|
|
404
|
+
onColumnDragOver,
|
|
405
|
+
onColumnDrop,
|
|
406
|
+
onColumnDragEnd,
|
|
407
|
+
canSelectRow,
|
|
408
|
+
isRowSelected,
|
|
409
|
+
isRowIndeterminate,
|
|
410
|
+
onToggleRow,
|
|
411
|
+
onToggleSelectAll,
|
|
412
|
+
canExpandRow,
|
|
413
|
+
isRowExpanded,
|
|
414
|
+
treeDepthOf,
|
|
415
|
+
onToggleExpand,
|
|
416
|
+
onRowClick,
|
|
417
|
+
onRowSelectMouseDown,
|
|
418
|
+
onRowDblclick,
|
|
419
|
+
onRowDragStart,
|
|
420
|
+
onRowDragOver,
|
|
421
|
+
onRowDragLeave,
|
|
422
|
+
onRowDrop,
|
|
423
|
+
onRowDragEnd,
|
|
424
|
+
isRowDropTarget,
|
|
425
|
+
isRowDragging,
|
|
426
|
+
canDragRow,
|
|
427
|
+
isRowDragByRow,
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
export type RsTableInteractionApi<T extends RsTableRowData> = ReturnType<
|
|
432
|
+
typeof useRsTableInteraction<T>
|
|
433
|
+
>
|