feat(editor): drag result grid columns into the SQL editor
This commit is contained in:
1 parent
9e4fe8ce56
commit
ab4e747bf9
17 files changed
+911
-25
No files matched your search
@@ -2,7 +2,7 @@
|
||||
|
||||
import { effectScope, nextTick, ref } from "vue";
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { dataGridColumnOffsets, dataGridHorizontalColumnWindow, useDataGridColumnLayout, useDataGridColumnLayoutState } from "@/composables/useDataGridColumnLayout";
|
||||
import { dataGridColumnOffsets, dataGridHorizontalColumnWindow, useDataGridColumnLayout, useDataGridColumnLayoutState, type ColumnHeaderReferenceDragController } from "@/composables/useDataGridColumnLayout";
|
||||
import { columnHeaderDragAutoScrollDelta, columnHeaderDropTargetIndex } from "@/lib/dataGrid/dataGridColumnHeaderInteraction";
|
||||
import { loadDataGridColumnLayout, saveDataGridColumnLayout } from "@/lib/dataGrid/dataGridColumnLayoutStorage";
|
||||
|
||||
@@ -548,6 +548,280 @@ describe("useDataGridColumnLayout", () => {
|
||||
scope.stop();
|
||||
});
|
||||
|
||||
it("switches to reference mode over the editor and drops without reordering", () => {
|
||||
vi.stubGlobal(
|
||||
"requestAnimationFrame",
|
||||
vi.fn((callback: FrameRequestCallback) => {
|
||||
callback(0);
|
||||
return 0;
|
||||
}),
|
||||
);
|
||||
vi.stubGlobal("cancelAnimationFrame", vi.fn());
|
||||
|
||||
const header = document.createElement("div");
|
||||
for (let index = 0; index < 2; index++) {
|
||||
const column = document.createElement("div");
|
||||
column.dataset.visibleColIndex = String(index);
|
||||
column.getBoundingClientRect = () => ({ left: index * 100, width: 100, right: (index + 1) * 100, top: 0, bottom: 20, height: 20, x: index * 100, y: 0, toJSON: () => ({}) });
|
||||
header.append(column);
|
||||
}
|
||||
const controller: ColumnHeaderReferenceDragController = {
|
||||
isOverEditorTarget: (clientX) => clientX > 300,
|
||||
onEnter: vi.fn(() => "id"),
|
||||
onMove: vi.fn(),
|
||||
onDrop: vi.fn(() => true),
|
||||
onCancel: vi.fn(),
|
||||
};
|
||||
const persist = vi.fn();
|
||||
const scope = effectScope();
|
||||
const layout = scope.run(() =>
|
||||
useDataGridColumnLayout({
|
||||
columnNames: ref(["id", "name"]),
|
||||
visibleColumnIndexes: ref([0, 1]),
|
||||
renderedColumnWidths: ref([100, 100]),
|
||||
scrollLeft: ref(0),
|
||||
viewportWidth: ref(400),
|
||||
rowNumberWidth: 40,
|
||||
headerRef: ref(header),
|
||||
onPersistColumnOrder: persist,
|
||||
columnReferenceDrag: controller,
|
||||
}),
|
||||
)!;
|
||||
|
||||
layout.startColumnHeaderDrag(0, new PointerEvent("pointerdown", { button: 0, clientX: 50, clientY: 10 }));
|
||||
// 网格内:仍是重排序预览
|
||||
window.dispatchEvent(new PointerEvent("pointermove", { clientX: 120, clientY: 10 }));
|
||||
expect(controller.onEnter).not.toHaveBeenCalled();
|
||||
expect(document.body.querySelector("[data-column-header-drag-preview]")).not.toBeNull();
|
||||
|
||||
// 进入编辑器区域:切换为引用模式,重排序预览移除
|
||||
window.dispatchEvent(new PointerEvent("pointermove", { clientX: 320, clientY: 10 }));
|
||||
expect(controller.onEnter).toHaveBeenCalledWith(0);
|
||||
expect(controller.onMove).toHaveBeenCalledWith(0, 320, 10);
|
||||
expect(document.body.querySelector("[data-column-header-drag-preview]")).toBeNull();
|
||||
expect(layout.columnHeaderPreviewOffsets.value).toEqual([0, 0]);
|
||||
|
||||
// 在编辑器内释放:插入但不重排列
|
||||
window.dispatchEvent(new PointerEvent("pointerup", { clientX: 320, clientY: 10 }));
|
||||
expect(controller.onDrop).toHaveBeenCalledWith(0, 320, 10);
|
||||
expect(controller.onCancel).toHaveBeenCalled();
|
||||
expect(persist).not.toHaveBeenCalled();
|
||||
scope.stop();
|
||||
});
|
||||
|
||||
it("cancels the reference drag and restores reorder preview when leaving the editor", () => {
|
||||
vi.stubGlobal(
|
||||
"requestAnimationFrame",
|
||||
vi.fn((callback: FrameRequestCallback) => {
|
||||
callback(0);
|
||||
return 0;
|
||||
}),
|
||||
);
|
||||
vi.stubGlobal("cancelAnimationFrame", vi.fn());
|
||||
|
||||
const header = document.createElement("div");
|
||||
for (let index = 0; index < 2; index++) {
|
||||
const column = document.createElement("div");
|
||||
column.dataset.visibleColIndex = String(index);
|
||||
column.getBoundingClientRect = () => ({ left: index * 100, width: 100, right: (index + 1) * 100, top: 0, bottom: 20, height: 20, x: index * 100, y: 0, toJSON: () => ({}) });
|
||||
header.append(column);
|
||||
}
|
||||
const controller: ColumnHeaderReferenceDragController = {
|
||||
isOverEditorTarget: (clientX) => clientX > 300,
|
||||
onEnter: vi.fn(() => "id"),
|
||||
onMove: vi.fn(),
|
||||
onDrop: vi.fn(() => true),
|
||||
onCancel: vi.fn(),
|
||||
};
|
||||
const persist = vi.fn();
|
||||
const scope = effectScope();
|
||||
const layout = scope.run(() =>
|
||||
useDataGridColumnLayout({
|
||||
columnNames: ref(["id", "name"]),
|
||||
visibleColumnIndexes: ref([0, 1]),
|
||||
renderedColumnWidths: ref([100, 100]),
|
||||
scrollLeft: ref(0),
|
||||
viewportWidth: ref(400),
|
||||
rowNumberWidth: 40,
|
||||
headerRef: ref(header),
|
||||
onPersistColumnOrder: persist,
|
||||
columnReferenceDrag: controller,
|
||||
}),
|
||||
)!;
|
||||
|
||||
layout.startColumnHeaderDrag(0, new PointerEvent("pointerdown", { button: 0, clientX: 50, clientY: 10 }));
|
||||
window.dispatchEvent(new PointerEvent("pointermove", { clientX: 320, clientY: 10 }));
|
||||
expect(controller.onEnter).toHaveBeenCalledTimes(1);
|
||||
|
||||
// 拖回网格:还原重排序预览,引用反馈被取消
|
||||
window.dispatchEvent(new PointerEvent("pointermove", { clientX: 120, clientY: 10 }));
|
||||
expect(controller.onCancel).toHaveBeenCalledTimes(1);
|
||||
expect(document.body.querySelector("[data-column-header-drag-preview]")).not.toBeNull();
|
||||
|
||||
// 拖出后释放(不在编辑器内):整体取消,不重排也不插入
|
||||
window.dispatchEvent(new PointerEvent("pointermove", { clientX: 320, clientY: 10 }));
|
||||
window.dispatchEvent(new PointerEvent("pointerup", { clientX: 120, clientY: 10 }));
|
||||
expect(controller.onDrop).not.toHaveBeenCalled();
|
||||
expect(persist).not.toHaveBeenCalled();
|
||||
scope.stop();
|
||||
});
|
||||
|
||||
it("keeps reorder mode when the controller refuses the reference drag", () => {
|
||||
vi.stubGlobal(
|
||||
"requestAnimationFrame",
|
||||
vi.fn((callback: FrameRequestCallback) => {
|
||||
callback(0);
|
||||
return 0;
|
||||
}),
|
||||
);
|
||||
vi.stubGlobal("cancelAnimationFrame", vi.fn());
|
||||
|
||||
const header = document.createElement("div");
|
||||
for (let index = 0; index < 2; index++) {
|
||||
const column = document.createElement("div");
|
||||
column.dataset.visibleColIndex = String(index);
|
||||
column.getBoundingClientRect = () => ({ left: index * 100, width: 100, right: (index + 1) * 100, top: 0, bottom: 20, height: 20, x: index * 100, y: 0, toJSON: () => ({}) });
|
||||
header.append(column);
|
||||
}
|
||||
const controller: ColumnHeaderReferenceDragController = {
|
||||
isOverEditorTarget: () => true,
|
||||
onEnter: vi.fn(() => null),
|
||||
onMove: vi.fn(),
|
||||
onDrop: vi.fn(() => true),
|
||||
onCancel: vi.fn(),
|
||||
};
|
||||
const persist = vi.fn();
|
||||
const scope = effectScope();
|
||||
const layout = scope.run(() =>
|
||||
useDataGridColumnLayout({
|
||||
columnNames: ref(["id", "name"]),
|
||||
visibleColumnIndexes: ref([0, 1]),
|
||||
renderedColumnWidths: ref([100, 100]),
|
||||
scrollLeft: ref(0),
|
||||
viewportWidth: ref(400),
|
||||
rowNumberWidth: 40,
|
||||
headerRef: ref(header),
|
||||
onPersistColumnOrder: persist,
|
||||
columnReferenceDrag: controller,
|
||||
}),
|
||||
)!;
|
||||
|
||||
layout.startColumnHeaderDrag(0, new PointerEvent("pointerdown", { button: 0, clientX: 50, clientY: 10 }));
|
||||
window.dispatchEvent(new PointerEvent("pointermove", { clientX: 320, clientY: 10 }));
|
||||
expect(controller.onEnter).toHaveBeenCalled();
|
||||
expect(controller.onMove).not.toHaveBeenCalled();
|
||||
expect(document.body.querySelector("[data-column-header-drag-preview]")).not.toBeNull();
|
||||
|
||||
window.dispatchEvent(new PointerEvent("pointerup", { clientX: 320, clientY: 10 }));
|
||||
expect(controller.onDrop).not.toHaveBeenCalled();
|
||||
expect(persist).toHaveBeenCalled();
|
||||
scope.stop();
|
||||
});
|
||||
|
||||
it("cancels a plain reorder drag released outside both the grid and the editor", () => {
|
||||
vi.stubGlobal(
|
||||
"requestAnimationFrame",
|
||||
vi.fn((callback: FrameRequestCallback) => {
|
||||
callback(0);
|
||||
return 0;
|
||||
}),
|
||||
);
|
||||
vi.stubGlobal("cancelAnimationFrame", vi.fn());
|
||||
|
||||
const header = document.createElement("div");
|
||||
header.getBoundingClientRect = () => ({ left: 0, width: 200, right: 200, top: 0, bottom: 20, height: 20, x: 0, y: 0, toJSON: () => ({}) });
|
||||
for (let index = 0; index < 2; index++) {
|
||||
const column = document.createElement("div");
|
||||
column.dataset.visibleColIndex = String(index);
|
||||
column.getBoundingClientRect = () => ({ left: index * 100, width: 100, right: (index + 1) * 100, top: 0, bottom: 20, height: 20, x: index * 100, y: 0, toJSON: () => ({}) });
|
||||
header.append(column);
|
||||
}
|
||||
const controller: ColumnHeaderReferenceDragController = {
|
||||
isOverEditorTarget: () => false,
|
||||
onEnter: vi.fn(() => null),
|
||||
onMove: vi.fn(),
|
||||
onDrop: vi.fn(() => true),
|
||||
onCancel: vi.fn(),
|
||||
};
|
||||
const persist = vi.fn();
|
||||
const scope = effectScope();
|
||||
const layout = scope.run(() =>
|
||||
useDataGridColumnLayout({
|
||||
columnNames: ref(["id", "name"]),
|
||||
visibleColumnIndexes: ref([0, 1]),
|
||||
renderedColumnWidths: ref([100, 100]),
|
||||
scrollLeft: ref(0),
|
||||
viewportWidth: ref(400),
|
||||
rowNumberWidth: 40,
|
||||
headerRef: ref(header),
|
||||
onPersistColumnOrder: persist,
|
||||
columnReferenceDrag: controller,
|
||||
}),
|
||||
)!;
|
||||
|
||||
layout.startColumnHeaderDrag(0, new PointerEvent("pointerdown", { button: 0, clientX: 50, clientY: 10 }));
|
||||
window.dispatchEvent(new PointerEvent("pointermove", { clientX: 120, clientY: 10 }));
|
||||
// 释放点 (320, 500) 不在表头/滚动区,也不在编辑器内:整体取消
|
||||
window.dispatchEvent(new PointerEvent("pointerup", { clientX: 320, clientY: 500 }));
|
||||
expect(persist).not.toHaveBeenCalled();
|
||||
|
||||
// 对照:网格内释放仍提交重排序
|
||||
layout.startColumnHeaderDrag(0, new PointerEvent("pointerdown", { button: 0, clientX: 50, clientY: 10 }));
|
||||
window.dispatchEvent(new PointerEvent("pointermove", { clientX: 180, clientY: 10 }));
|
||||
window.dispatchEvent(new PointerEvent("pointerup", { clientX: 180, clientY: 10 }));
|
||||
expect(persist).toHaveBeenCalledWith([1, 0]);
|
||||
scope.stop();
|
||||
});
|
||||
|
||||
it("blocks native selection and drag while dragging columns", () => {
|
||||
vi.stubGlobal(
|
||||
"requestAnimationFrame",
|
||||
vi.fn((callback: FrameRequestCallback) => {
|
||||
callback(0);
|
||||
return 0;
|
||||
}),
|
||||
);
|
||||
vi.stubGlobal("cancelAnimationFrame", vi.fn());
|
||||
|
||||
const header = document.createElement("div");
|
||||
const column = document.createElement("div");
|
||||
column.dataset.visibleColIndex = "0";
|
||||
column.getBoundingClientRect = () => ({ left: 0, width: 100, right: 100, top: 0, bottom: 20, height: 20, x: 0, y: 0, toJSON: () => ({}) });
|
||||
header.append(column);
|
||||
|
||||
const scope = effectScope();
|
||||
const layout = scope.run(() =>
|
||||
useDataGridColumnLayout({
|
||||
columnNames: ref(["id", "name"]),
|
||||
visibleColumnIndexes: ref([0, 1]),
|
||||
renderedColumnWidths: ref([100, 100]),
|
||||
scrollLeft: ref(0),
|
||||
viewportWidth: ref(400),
|
||||
rowNumberWidth: 40,
|
||||
headerRef: ref(header),
|
||||
}),
|
||||
)!;
|
||||
|
||||
layout.startColumnHeaderDrag(0, new PointerEvent("pointerdown", { button: 0, clientX: 50, clientY: 10 }));
|
||||
|
||||
// 拖拽期间原生选择与拖拽启动被拦截
|
||||
const selectStart = new Event("selectstart", { cancelable: true });
|
||||
document.dispatchEvent(selectStart);
|
||||
expect(selectStart.defaultPrevented).toBe(true);
|
||||
const dragStart = new Event("dragstart", { cancelable: true });
|
||||
document.dispatchEvent(dragStart);
|
||||
expect(dragStart.defaultPrevented).toBe(true);
|
||||
|
||||
window.dispatchEvent(new PointerEvent("pointerup", { clientX: 150, clientY: 10 }));
|
||||
expect(document.body.style.userSelect).toBe("");
|
||||
|
||||
// 手势结束后恢复原生效行为
|
||||
const laterSelect = new Event("selectstart", { cancelable: true });
|
||||
document.dispatchEvent(laterSelect);
|
||||
expect(laterSelect.defaultPrevented).toBe(false);
|
||||
scope.stop();
|
||||
});
|
||||
|
||||
it("uses the edge after frozen columns as the left auto-scroll trigger", () => {
|
||||
const frames = new Map<number, FrameRequestCallback>();
|
||||
let nextFrame = 1;
|
||||
|
||||
@@ -50,8 +50,27 @@ type ColumnHeaderDragState = {
|
||||
columnRects: { visibleIndex: number; left: number; width: number }[];
|
||||
previewElement: HTMLElement | null;
|
||||
dragging: boolean;
|
||||
/** 指针进入 SQL 编辑器后切换为“插入列引用”模式,重排序预览挂起。 */
|
||||
referenceMode: boolean;
|
||||
/** 本次手势中 onEnter 已拒绝过该列(不可作为引用),不再重复试探。 */
|
||||
referenceUnavailable: boolean;
|
||||
};
|
||||
|
||||
/**
|
||||
* 目标导向拖拽控制器:网格内保持列重排序手势;指针进入 SQL 编辑器区域时
|
||||
* 由 DataGrid 提供的实现接管反馈与最终插入。
|
||||
*/
|
||||
export interface ColumnHeaderReferenceDragController {
|
||||
isOverEditorTarget(clientX: number, clientY: number): boolean;
|
||||
/** 进入编辑器目标时回调;返回 chip 文案,null 表示该列不可作为引用拖入。 */
|
||||
onEnter(sourceVisibleIndex: number): string | null;
|
||||
onMove(sourceVisibleIndex: number, clientX: number, clientY: number): void;
|
||||
/** 在编辑器目标内释放时回调;返回 true 表示已处理插入。 */
|
||||
onDrop(sourceVisibleIndex: number, clientX: number, clientY: number): boolean;
|
||||
/** 引用模式结束(无论是否发生插入)时清理反馈。 */
|
||||
onCancel(): void;
|
||||
}
|
||||
|
||||
export function dataGridColumnOffsets(widths: readonly number[]): number[] {
|
||||
const offsets = Array.from({ length: widths.length + 1 }, () => 0);
|
||||
for (let index = 0; index < widths.length; index++) offsets[index + 1] = offsets[index] + (widths[index] ?? 0);
|
||||
@@ -427,6 +446,7 @@ export function useDataGridColumnLayout(options: {
|
||||
onRefreshMetrics?: () => void;
|
||||
onPersistColumnOrder?: (indexes: number[]) => void;
|
||||
frozenColumnCount?: MaybeRefOrGetter<number>;
|
||||
columnReferenceDrag?: ColumnHeaderReferenceDragController;
|
||||
}) {
|
||||
const renderedColumnOffsets = computed(() => dataGridColumnOffsets(toValue(options.renderedColumnWidths)));
|
||||
const frozenColumnCount = computed(() => toValue(options.frozenColumnCount ?? 0));
|
||||
@@ -706,6 +726,8 @@ export function useDataGridColumnLayout(options: {
|
||||
window.removeEventListener("pointerup", onColumnHeaderPointerUp, true);
|
||||
window.removeEventListener("pointercancel", onColumnHeaderPointerCancel, true);
|
||||
window.removeEventListener("blur", onColumnHeaderPointerCancel, true);
|
||||
document.removeEventListener("selectstart", blockColumnHeaderNativeInteraction, true);
|
||||
document.removeEventListener("dragstart", blockColumnHeaderNativeInteraction, true);
|
||||
cancelColumnHeaderDragPreview();
|
||||
removeColumnHeaderDragPreview(state);
|
||||
document.body.style.userSelect = "";
|
||||
@@ -723,6 +745,36 @@ export function useDataGridColumnLayout(options: {
|
||||
options.onRefreshMetrics?.();
|
||||
}
|
||||
|
||||
function enterColumnReferenceMode(state: ColumnHeaderDragState, clientX: number, clientY: number): boolean {
|
||||
const controller = options.columnReferenceDrag;
|
||||
if (!controller) return false;
|
||||
const label = controller.onEnter(state.sourceVisibleIndex);
|
||||
if (label == null) return false;
|
||||
state.referenceMode = true;
|
||||
cancelColumnHeaderDragPreview();
|
||||
removeColumnHeaderDragPreview(state);
|
||||
controller.onMove(state.sourceVisibleIndex, clientX, clientY);
|
||||
return true;
|
||||
}
|
||||
|
||||
function exitColumnReferenceMode(state: ColumnHeaderDragState) {
|
||||
const controller = options.columnReferenceDrag;
|
||||
state.referenceMode = false;
|
||||
state.referenceUnavailable = false;
|
||||
if (state.dragging) createColumnHeaderDragPreview(state);
|
||||
controller?.onCancel();
|
||||
}
|
||||
|
||||
/** 指针是否仍在本网格区域内(滚动区或表头行),用于“拖出网格释放=取消”。 */
|
||||
function pointerInsideGridArea(clientX: number, clientY: number): boolean {
|
||||
const rects: DOMRect[] = [];
|
||||
const scroller = options.getScrollElement?.();
|
||||
if (scroller) rects.push(scroller.getBoundingClientRect());
|
||||
const header = toValue(options.headerRef);
|
||||
if (header) rects.push(header.getBoundingClientRect());
|
||||
return rects.some((rect) => clientX >= rect.left && clientX <= rect.right && clientY >= rect.top && clientY <= rect.bottom);
|
||||
}
|
||||
|
||||
function onColumnHeaderPointerMove(event: PointerEvent) {
|
||||
const state = columnHeaderDragState.value;
|
||||
if (!state) return;
|
||||
@@ -734,20 +786,59 @@ export function useDataGridColumnLayout(options: {
|
||||
createColumnHeaderDragPreview(state);
|
||||
}
|
||||
if (!state.dragging) return;
|
||||
const controller = options.columnReferenceDrag;
|
||||
if (controller && !state.referenceUnavailable) {
|
||||
const overEditor = controller.isOverEditorTarget(event.clientX, event.clientY);
|
||||
if (overEditor && !state.referenceMode) {
|
||||
// 进入编辑器:尝试切换为列引用模式;不可引用(onEnter 返回 null)时保持重排序并不再试探。
|
||||
if (enterColumnReferenceMode(state, event.clientX, event.clientY)) return;
|
||||
state.referenceUnavailable = true;
|
||||
} else if (!overEditor && state.referenceMode) {
|
||||
exitColumnReferenceMode(state);
|
||||
}
|
||||
}
|
||||
if (state.referenceMode) {
|
||||
event.preventDefault();
|
||||
controller?.onMove(state.sourceVisibleIndex, event.clientX, event.clientY);
|
||||
return;
|
||||
}
|
||||
event.preventDefault();
|
||||
scheduleColumnHeaderDragPreview(event.clientX);
|
||||
}
|
||||
|
||||
function onColumnHeaderPointerUp(event: PointerEvent) {
|
||||
const state = columnHeaderDragState.value;
|
||||
if (state?.referenceMode) {
|
||||
const controller = options.columnReferenceDrag!;
|
||||
if (controller.isOverEditorTarget(event.clientX, event.clientY)) {
|
||||
// 在编辑器内释放:插入列引用(onDrop 失败也只按取消收尾)。
|
||||
controller.onDrop(state.sourceVisibleIndex, event.clientX, event.clientY);
|
||||
}
|
||||
controller.onCancel();
|
||||
stopColumnHeaderDrag(false);
|
||||
return;
|
||||
}
|
||||
columnHeaderPendingClientX = event.clientX;
|
||||
flushColumnHeaderDragPreview();
|
||||
// 目标导向手势启用时,把列拖出网格与编辑器之外释放=取消,不重排列。
|
||||
if (state?.dragging && options.columnReferenceDrag && !options.columnReferenceDrag.isOverEditorTarget(event.clientX, event.clientY) && !pointerInsideGridArea(event.clientX, event.clientY)) {
|
||||
stopColumnHeaderDrag(false);
|
||||
return;
|
||||
}
|
||||
stopColumnHeaderDrag(true);
|
||||
}
|
||||
|
||||
function onColumnHeaderPointerCancel() {
|
||||
const state = columnHeaderDragState.value;
|
||||
if (state?.referenceMode) options.columnReferenceDrag?.onCancel();
|
||||
stopColumnHeaderDrag(false);
|
||||
}
|
||||
|
||||
/** 拖拽期间拦截原生文本选择与 HTML5 拖拽启动,防止其抢占指针事件流。 */
|
||||
function blockColumnHeaderNativeInteraction(event: Event) {
|
||||
event.preventDefault();
|
||||
}
|
||||
|
||||
function startColumnHeaderDrag(visibleColIdx: number, event: PointerEvent) {
|
||||
if (event.button !== 0 || options.getIsResizing?.() || columnHeaderInteractiveTarget(event.target)) return;
|
||||
const scroller = options.getScrollElement?.();
|
||||
@@ -755,6 +846,11 @@ export function useDataGridColumnLayout(options: {
|
||||
const columnRects = columnHeaderLayoutRects();
|
||||
const sourceRect = columnRects.find((rect) => rect.visibleIndex === visibleColIdx);
|
||||
const dragCenterClientOffsetX = sourceRect ? sourceRect.left + sourceRect.width / 2 - event.clientX : 0;
|
||||
// 阻止原生文本选择/HTML5 拖拽抢占事件流:一旦发生会派发 pointercancel 并停发 pointermove,
|
||||
// 手势将被冻结(表现为拖不动)。参照侧边栏表引用路径在起点即禁用。
|
||||
event.preventDefault();
|
||||
document.addEventListener("selectstart", blockColumnHeaderNativeInteraction, true);
|
||||
document.addEventListener("dragstart", blockColumnHeaderNativeInteraction, true);
|
||||
columnHeaderDragState.value = {
|
||||
sourceVisibleIndex: visibleColIdx,
|
||||
targetVisibleIndex: visibleColIdx,
|
||||
@@ -769,6 +865,8 @@ export function useDataGridColumnLayout(options: {
|
||||
columnRects,
|
||||
previewElement: null,
|
||||
dragging: false,
|
||||
referenceMode: false,
|
||||
referenceUnavailable: false,
|
||||
};
|
||||
columnHeaderPendingClientX = event.clientX;
|
||||
window.addEventListener("pointermove", onColumnHeaderPointerMove, true);
|
||||
@@ -788,12 +886,12 @@ export function useDataGridColumnLayout(options: {
|
||||
|
||||
function columnHeaderDragClass(visibleColIdx: number) {
|
||||
const state = columnHeaderDragState.value;
|
||||
return { "opacity-0 pointer-events-none": state?.dragging && state.sourceVisibleIndex === visibleColIdx };
|
||||
return { "opacity-0 pointer-events-none": state?.dragging && !state.referenceMode && state.sourceVisibleIndex === visibleColIdx };
|
||||
}
|
||||
|
||||
function columnHeaderPreviewOffset(visibleColIdx: number): number {
|
||||
const state = columnHeaderDragState.value;
|
||||
if (!state) return 0;
|
||||
if (!state || state.referenceMode) return 0;
|
||||
const scrollCompensation = state.sourceVisibleIndex < frozenColumnCount.value ? 0 : state.currentScrollLeft - state.startScrollLeft;
|
||||
return columnHeaderPreviewOffsetForColumn({
|
||||
columnDragActive: state.dragging,
|
||||
@@ -820,7 +918,7 @@ export function useDataGridColumnLayout(options: {
|
||||
const columnHeaderPreviewOffsets = computed(() => toValue(options.renderedColumnWidths).map((_, visibleColIdx) => columnHeaderPreviewOffset(visibleColIdx)));
|
||||
const columnHeaderPreviewSourceVisibleIndex = computed(() => {
|
||||
const state = columnHeaderDragState.value;
|
||||
return state?.dragging ? state.sourceVisibleIndex : null;
|
||||
return state?.dragging && !state.referenceMode ? state.sourceVisibleIndex : null;
|
||||
});
|
||||
|
||||
function disposeColumnHeaderInteractions() {
|
||||
|
||||
Reference in new issue
Block a user