diff --git a/packages/grid/src/grid.component.html b/packages/grid/src/grid.component.html
index 6f268ea5..05ec37f9 100644
--- a/packages/grid/src/grid.component.html
+++ b/packages/grid/src/grid.component.html
@@ -10,6 +10,9 @@
(koDblclick)="stageDblclick($event)"
(koMouseleave)="stageMouseleave($event)"
(koWheel)="stageWheel($event)"
+ (koTouchstart)="stageTouchstart($event)"
+ (koTouchmove)="stageTouchmove($event)"
+ (koTouchend)="stageTouchend($event)"
>
@if (domToolTips().length > 0) {
Date.now();
+ }
+
+ private ignoreMouseEventsFor(durationMs: number): void {
+ this.ignoreMouseEventsUntil = Date.now() + durationMs;
+ }
+
+ private ignoreMouseEventsAfterTouchScroll(): void {
+ this.ignoreMouseEventsFor(this.touchScrollMouseSuppressionMs);
+ }
+
private dragSelectState: {
isDragging: boolean;
startCell: AIRecordFieldIdPath | null;
@@ -588,6 +616,9 @@ export class AITableGrid extends AITableGridBase implements OnInit, OnDestroy {
}
stageMousedown(e: KoEventObject) {
+ if (this.shouldIgnoreMouseEvents()) {
+ return;
+ }
const mouseEvent = e.event.evt;
const _targetName = e.event.target.name();
@@ -709,12 +740,68 @@ export class AITableGrid extends AITableGridBase implements OnInit, OnDestroy {
}
stageWheel(e: KoEventObject) {
+ if (this.shouldIgnoreMouseEvents()) {
+ return;
+ }
e.event.evt.preventDefault();
this.aiTableGridEventService.closeCellEditor();
this.scrollAction({ deltaX: e.event.evt.deltaX, deltaY: e.event.evt.deltaY, shiftKey: e.event.evt.shiftKey });
}
+ stageTouchstart(e: KoEventObject) {
+ const touch = e.event.evt.touches?.[0];
+ if (!touch) {
+ return;
+ }
+ this.touchPanState = {
+ isTouching: true,
+ lastClientX: touch.clientX,
+ lastClientY: touch.clientY,
+ hasMoved: false
+ };
+ }
+
+ stageTouchmove(e: KoEventObject) {
+ const touch = e.event.evt.touches?.[0];
+ if (!touch || !this.touchPanState.isTouching) {
+ return;
+ }
+
+ const deltaX = this.touchPanState.lastClientX - touch.clientX;
+ const deltaY = this.touchPanState.lastClientY - touch.clientY;
+
+ this.touchPanState.lastClientX = touch.clientX;
+ this.touchPanState.lastClientY = touch.clientY;
+
+ if (Math.abs(deltaX) < 0.5 && Math.abs(deltaY) < 0.5) {
+ return;
+ }
+
+ e.event.evt.preventDefault();
+ this.aiTableGridEventService.closeCellEditor();
+
+ if (!this.touchPanState.hasMoved && (Math.abs(deltaX) > 2 || Math.abs(deltaY) > 2)) {
+ this.touchPanState.hasMoved = true;
+ }
+ if (this.touchPanState.hasMoved) {
+ this.ignoreMouseEventsAfterTouchScroll();
+ }
+
+ this.scrollAction({ deltaX, deltaY, shiftKey: false });
+ }
+
+ stageTouchend(e: KoEventObject) {
+ if (this.touchPanState.hasMoved) {
+ this.ignoreMouseEventsAfterTouchScroll();
+ }
+ this.touchPanState.isTouching = false;
+ this.touchPanState.hasMoved = false;
+ }
+
stageContextmenu(e: KoEventObject) {
+ if (this.shouldIgnoreMouseEvents()) {
+ return;
+ }
const mouseEvent = e.event.evt;
mouseEvent.preventDefault();
@@ -751,6 +838,9 @@ export class AITableGrid extends AITableGridBase implements OnInit, OnDestroy {
}
stageClick(e: KoEventObject) {
+ if (this.shouldIgnoreMouseEvents()) {
+ return;
+ }
const targetNameDetail = getDetailByTargetName(e.event.target.name());
this.aiClick.emit({
...e,
@@ -868,6 +958,9 @@ export class AITableGrid extends AITableGridBase implements OnInit, OnDestroy {
}
stageDblclick(e: KoEventObject) {
+ if (this.shouldIgnoreMouseEvents()) {
+ return;
+ }
const _targetName = e.event.target.name();
const targetNameDetail = getDetailByTargetName(_targetName);
this.aiDbClick.emit({
diff --git a/packages/grid/src/renderer/renderer.component.html b/packages/grid/src/renderer/renderer.component.html
index 295320cb..901c8fe1 100644
--- a/packages/grid/src/renderer/renderer.component.html
+++ b/packages/grid/src/renderer/renderer.component.html
@@ -8,6 +8,9 @@
(koDblclick)="stageDblclick($event)"
(koMouseleave)="stageMouseleave($event)"
(koWheel)="stageWheel($event)"
+ (koTouchstart)="stageTouchstart($event)"
+ (koTouchmove)="stageTouchmove($event)"
+ (koTouchend)="stageTouchend($event)"
>
diff --git a/packages/grid/src/renderer/renderer.component.ts b/packages/grid/src/renderer/renderer.component.ts
index d7e1215f..86f15eac 100644
--- a/packages/grid/src/renderer/renderer.component.ts
+++ b/packages/grid/src/renderer/renderer.component.ts
@@ -91,6 +91,12 @@ export class AITableRenderer {
koMouseleave = output>();
+ koTouchstart = output>();
+
+ koTouchmove = output>();
+
+ koTouchend = output>();
+
onScrollPosition = output<{ scrollX: number; scrollY: number }>();
isHoverStatContainer = signal(false);
@@ -468,6 +474,18 @@ export class AITableRenderer {
this.koMouseleave.emit(e as KoEventObject);
}
+ stageTouchstart(e: KoEventObject) {
+ this.koTouchstart.emit(e as KoEventObject);
+ }
+
+ stageTouchmove(e: KoEventObject) {
+ this.koTouchmove.emit(e as KoEventObject);
+ }
+
+ stageTouchend(e: KoEventObject) {
+ this.koTouchend.emit(e as KoEventObject);
+ }
+
stageWheel(e: KoEventObject) {
this.koWheel.emit(e);
}
diff --git a/packages/grid/src/styles/styles.scss b/packages/grid/src/styles/styles.scss
index 6a8acb0b..33fb13eb 100644
--- a/packages/grid/src/styles/styles.scss
+++ b/packages/grid/src/styles/styles.scss
@@ -163,6 +163,11 @@
width: 100%;
height: 100%;
position: relative;
+ touch-action: none;
+
+ .konvajs-content {
+ touch-action: none;
+ }
}
.ai-table-left-background-wrapper {