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 {