From 8a543a317da06474be965bd68196e292c16da885 Mon Sep 17 00:00:00 2001 From: Kamil Fogel Date: Mon, 8 Dec 2025 11:09:54 +0100 Subject: [PATCH 1/6] AF-365 Add grab cursor on background and investigate further cursor changes --- .../components/diagram/ng-diagram.component.scss | 5 +++++ .../lib/components/diagram/ng-diagram.component.ts | 4 ++++ .../components/node/ng-diagram-node.component.scss | 1 + .../input-events/panning/panning.directive.ts | 13 +++++++++++++ 4 files changed, 23 insertions(+) diff --git a/packages/ng-diagram/projects/ng-diagram/src/lib/components/diagram/ng-diagram.component.scss b/packages/ng-diagram/projects/ng-diagram/src/lib/components/diagram/ng-diagram.component.scss index 468b70832..2d93c4a76 100644 --- a/packages/ng-diagram/projects/ng-diagram/src/lib/components/diagram/ng-diagram.component.scss +++ b/packages/ng-diagram/projects/ng-diagram/src/lib/components/diagram/ng-diagram.component.scss @@ -8,6 +8,7 @@ touch-action: none; transform: translateZ(0px); -webkit-font-smoothing: antialiased; + cursor: grab; outline: none; @@ -15,4 +16,8 @@ width: 100%; height: 100%; } + + &.grabbing { + cursor: grabbing; + } } diff --git a/packages/ng-diagram/projects/ng-diagram/src/lib/components/diagram/ng-diagram.component.ts b/packages/ng-diagram/projects/ng-diagram/src/lib/components/diagram/ng-diagram.component.ts index 8f16cd9b4..b0a1eb8f3 100644 --- a/packages/ng-diagram/projects/ng-diagram/src/lib/components/diagram/ng-diagram.component.ts +++ b/packages/ng-diagram/projects/ng-diagram/src/lib/components/diagram/ng-diagram.component.ts @@ -317,6 +317,10 @@ export class NgDiagramComponent implements OnInit, OnDestroy { return this.elementRef.nativeElement.getBoundingClientRect(); } + getDiagramElement(): HTMLElement { + return this.elementRef.nativeElement; + } + private getFlowOffset = () => { const clientRect = this.elementRef.nativeElement.getBoundingClientRect(); return clientRect ? { x: clientRect.left, y: clientRect.top } : { x: 0, y: 0 }; diff --git a/packages/ng-diagram/projects/ng-diagram/src/lib/components/node/ng-diagram-node.component.scss b/packages/ng-diagram/projects/ng-diagram/src/lib/components/node/ng-diagram-node.component.scss index 20c988dd4..f7b6a927b 100644 --- a/packages/ng-diagram/projects/ng-diagram/src/lib/components/node/ng-diagram-node.component.scss +++ b/packages/ng-diagram/projects/ng-diagram/src/lib/components/node/ng-diagram-node.component.scss @@ -5,6 +5,7 @@ transform-origin: 0 0; pointer-events: none; user-select: none; + cursor: pointer; } .node-content { diff --git a/packages/ng-diagram/projects/ng-diagram/src/lib/directives/input-events/panning/panning.directive.ts b/packages/ng-diagram/projects/ng-diagram/src/lib/directives/input-events/panning/panning.directive.ts index 145f30da4..f1936d908 100644 --- a/packages/ng-diagram/projects/ng-diagram/src/lib/directives/input-events/panning/panning.directive.ts +++ b/packages/ng-diagram/projects/ng-diagram/src/lib/directives/input-events/panning/panning.directive.ts @@ -1,4 +1,5 @@ import { Directive, inject, type OnDestroy } from '@angular/core'; +import { NgDiagramComponent } from '../../../components/diagram/ng-diagram.component'; import { InputEventsRouterService } from '../../../services/input-events/input-events-router.service'; import type { PointerInputEvent } from '../../../types/event'; import { shouldDiscardEvent } from '../utils/should-discard-event'; @@ -11,6 +12,7 @@ import { shouldDiscardEvent } from '../utils/should-discard-event'; }, }) export class PanningDirective implements OnDestroy { + private readonly diagramComponent = inject(NgDiagramComponent); private readonly inputEventsRouter = inject(InputEventsRouterService); ngOnDestroy(): void { @@ -22,6 +24,7 @@ export class PanningDirective implements OnDestroy { if (!this.inputEventsRouter.eventGuards.withPrimaryButton(event) || !this.shouldHandle(event)) { return; } + this.toggleGrabbingCursor(true); event.preventDefault(); event.stopPropagation(); @@ -47,6 +50,7 @@ export class PanningDirective implements OnDestroy { if (!this.inputEventsRouter.eventGuards.withPrimaryButton(event)) { return; } + this.toggleGrabbingCursor(false); event.preventDefault(); event.stopPropagation(); @@ -109,4 +113,13 @@ export class PanningDirective implements OnDestroy { event.zoomingHandled ); } + + private toggleGrabbingCursor(isGrabbing: boolean): void { + const diagramElement = this.diagramComponent.getDiagramElement(); + if (isGrabbing) { + diagramElement.classList.add('grabbing'); + } else { + diagramElement.classList.remove('grabbing'); + } + } } From 61e3a4c04a81cbcb07b15763a3e0a3fc8262b74a Mon Sep 17 00:00:00 2001 From: Kamil Fogel Date: Mon, 8 Dec 2025 12:00:45 +0100 Subject: [PATCH 2/6] AF-365 Add grab cursor on background and investigate further cursor changes --- packages/ng-diagram/api-report/ng-diagram.api.md | 14 ++++++++------ .../lib/components/diagram/ng-diagram.component.ts | 3 +++ 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/packages/ng-diagram/api-report/ng-diagram.api.md b/packages/ng-diagram/api-report/ng-diagram.api.md index 75fde8427..e217650e1 100644 --- a/packages/ng-diagram/api-report/ng-diagram.api.md +++ b/packages/ng-diagram/api-report/ng-diagram.api.md @@ -155,7 +155,7 @@ export interface DiagramInitEvent { // @public (undocumented) export class DiagramSelectionDirective extends ObjectSelectionDirective { // (undocumented) - readonly targetData: InputSignal | Node_2 | undefined>; + readonly targetData: InputSignal | undefined>; // (undocumented) targetType: BasePointerInputEvent['targetType']; // (undocumented) @@ -266,7 +266,7 @@ export type EdgeRoutingName = LooseAutocomplete; // @public (undocumented) export class EdgeSelectionDirective extends ObjectSelectionDirective { // (undocumented) - readonly targetData: InputSignal | Node_2 | undefined>; + readonly targetData: InputSignal | undefined>; // (undocumented) targetType: BasePointerInputEvent['targetType']; // (undocumented) @@ -663,6 +663,8 @@ export class NgDiagramComponent implements OnInit, OnDestroy { edgeTemplateMap: InputSignal; // (undocumented) getBoundingClientRect(): DOMRect; + // @internal (undocumented) + getDiagramElement(): HTMLElement; // (undocumented) getEdgeTemplate(edgeType: Edge['type']): Type> | null; getNodeTemplate(nodeType: Node_2['type']): Type>> | Type> | null; @@ -926,7 +928,7 @@ export class NgDiagramPortComponent extends NodeContextGuardBase implements OnIn // (undocumented) protected readonly lastSide: WritableSignal; // (undocumented) - protected readonly lastType: WritableSignal<"source" | "target" | "both" | undefined>; + protected readonly lastType: WritableSignal<"target" | "source" | "both" | undefined>; // @internal (undocumented) ngAfterContentInit(): void; // @internal (undocumented) @@ -939,7 +941,7 @@ export class NgDiagramPortComponent extends NodeContextGuardBase implements OnIn // (undocumented) get portClass(): string; side: InputSignal; - type: InputSignal<"source" | "target" | "both">; + type: InputSignal<"target" | "source" | "both">; // (undocumented) static ɵcmp: i0.ɵɵComponentDeclaration; // (undocumented) @@ -1055,7 +1057,7 @@ export interface NodeRotationConfig { // @public (undocumented) export class NodeSelectionDirective extends ObjectSelectionDirective { // (undocumented) - readonly targetData: InputSignal | Node_2 | undefined>; + readonly targetData: InputSignal | undefined>; // (undocumented) targetType: BasePointerInputEvent['targetType']; // (undocumented) @@ -1340,7 +1342,7 @@ export interface ZIndexConfig { // @public (undocumented) export class ZIndexDirective { // (undocumented) - data: InputSignal | Node_2>; + data: InputSignal>; // (undocumented) zIndex: Signal; // (undocumented) diff --git a/packages/ng-diagram/projects/ng-diagram/src/lib/components/diagram/ng-diagram.component.ts b/packages/ng-diagram/projects/ng-diagram/src/lib/components/diagram/ng-diagram.component.ts index b0a1eb8f3..dda811ed8 100644 --- a/packages/ng-diagram/projects/ng-diagram/src/lib/components/diagram/ng-diagram.component.ts +++ b/packages/ng-diagram/projects/ng-diagram/src/lib/components/diagram/ng-diagram.component.ts @@ -317,6 +317,9 @@ export class NgDiagramComponent implements OnInit, OnDestroy { return this.elementRef.nativeElement.getBoundingClientRect(); } + /** + * @internal + */ getDiagramElement(): HTMLElement { return this.elementRef.nativeElement; } From 796047c1151d0f3edb19987e82cb5e646db05d5f Mon Sep 17 00:00:00 2001 From: Kamil Fogel Date: Mon, 8 Dec 2025 13:44:06 +0100 Subject: [PATCH 3/6] AF-365 Add grab cursor on background and investigate further cursor changes - Pr fix --- .../directives/input-events/panning/panning.directive.ts | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/packages/ng-diagram/projects/ng-diagram/src/lib/directives/input-events/panning/panning.directive.ts b/packages/ng-diagram/projects/ng-diagram/src/lib/directives/input-events/panning/panning.directive.ts index f1936d908..b4b48a4f7 100644 --- a/packages/ng-diagram/projects/ng-diagram/src/lib/directives/input-events/panning/panning.directive.ts +++ b/packages/ng-diagram/projects/ng-diagram/src/lib/directives/input-events/panning/panning.directive.ts @@ -1,5 +1,4 @@ -import { Directive, inject, type OnDestroy } from '@angular/core'; -import { NgDiagramComponent } from '../../../components/diagram/ng-diagram.component'; +import { Directive, ElementRef, inject, type OnDestroy } from '@angular/core'; import { InputEventsRouterService } from '../../../services/input-events/input-events-router.service'; import type { PointerInputEvent } from '../../../types/event'; import { shouldDiscardEvent } from '../utils/should-discard-event'; @@ -12,8 +11,8 @@ import { shouldDiscardEvent } from '../utils/should-discard-event'; }, }) export class PanningDirective implements OnDestroy { - private readonly diagramComponent = inject(NgDiagramComponent); private readonly inputEventsRouter = inject(InputEventsRouterService); + private readonly elementRef = inject(ElementRef); ngOnDestroy(): void { document.removeEventListener('pointermove', this.onMouseMove); @@ -115,7 +114,7 @@ export class PanningDirective implements OnDestroy { } private toggleGrabbingCursor(isGrabbing: boolean): void { - const diagramElement = this.diagramComponent.getDiagramElement(); + const diagramElement = this.elementRef.nativeElement; if (isGrabbing) { diagramElement.classList.add('grabbing'); } else { From eadba8ff4027fe02175cda195742411229329a67 Mon Sep 17 00:00:00 2001 From: Kamil Fogel Date: Mon, 8 Dec 2025 13:55:19 +0100 Subject: [PATCH 4/6] AF-365 Add grab cursor on background and investigate further cursor changes - Pr fix --- packages/ng-diagram/api-report/ng-diagram.api.md | 6 ++---- .../src/lib/components/diagram/ng-diagram.component.ts | 7 ------- 2 files changed, 2 insertions(+), 11 deletions(-) diff --git a/packages/ng-diagram/api-report/ng-diagram.api.md b/packages/ng-diagram/api-report/ng-diagram.api.md index e217650e1..1079d6e83 100644 --- a/packages/ng-diagram/api-report/ng-diagram.api.md +++ b/packages/ng-diagram/api-report/ng-diagram.api.md @@ -663,8 +663,6 @@ export class NgDiagramComponent implements OnInit, OnDestroy { edgeTemplateMap: InputSignal; // (undocumented) getBoundingClientRect(): DOMRect; - // @internal (undocumented) - getDiagramElement(): HTMLElement; // (undocumented) getEdgeTemplate(edgeType: Edge['type']): Type> | null; getNodeTemplate(nodeType: Node_2['type']): Type>> | Type> | null; @@ -928,7 +926,7 @@ export class NgDiagramPortComponent extends NodeContextGuardBase implements OnIn // (undocumented) protected readonly lastSide: WritableSignal; // (undocumented) - protected readonly lastType: WritableSignal<"target" | "source" | "both" | undefined>; + protected readonly lastType: WritableSignal<"source" | "target" | "both" | undefined>; // @internal (undocumented) ngAfterContentInit(): void; // @internal (undocumented) @@ -941,7 +939,7 @@ export class NgDiagramPortComponent extends NodeContextGuardBase implements OnIn // (undocumented) get portClass(): string; side: InputSignal; - type: InputSignal<"target" | "source" | "both">; + type: InputSignal<"source" | "target" | "both">; // (undocumented) static ɵcmp: i0.ɵɵComponentDeclaration; // (undocumented) diff --git a/packages/ng-diagram/projects/ng-diagram/src/lib/components/diagram/ng-diagram.component.ts b/packages/ng-diagram/projects/ng-diagram/src/lib/components/diagram/ng-diagram.component.ts index dda811ed8..8f16cd9b4 100644 --- a/packages/ng-diagram/projects/ng-diagram/src/lib/components/diagram/ng-diagram.component.ts +++ b/packages/ng-diagram/projects/ng-diagram/src/lib/components/diagram/ng-diagram.component.ts @@ -317,13 +317,6 @@ export class NgDiagramComponent implements OnInit, OnDestroy { return this.elementRef.nativeElement.getBoundingClientRect(); } - /** - * @internal - */ - getDiagramElement(): HTMLElement { - return this.elementRef.nativeElement; - } - private getFlowOffset = () => { const clientRect = this.elementRef.nativeElement.getBoundingClientRect(); return clientRect ? { x: clientRect.left, y: clientRect.top } : { x: 0, y: 0 }; From a11891a77ef8ccfe1af398869c1a35964a892c56 Mon Sep 17 00:00:00 2001 From: Kamil Fogel Date: Mon, 8 Dec 2025 14:01:59 +0100 Subject: [PATCH 5/6] AF-365 Add grab cursor on background and investigate further cursor changes - Pr fix --- packages/ng-diagram/api-report/ng-diagram.api.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/ng-diagram/api-report/ng-diagram.api.md b/packages/ng-diagram/api-report/ng-diagram.api.md index 1079d6e83..75fde8427 100644 --- a/packages/ng-diagram/api-report/ng-diagram.api.md +++ b/packages/ng-diagram/api-report/ng-diagram.api.md @@ -155,7 +155,7 @@ export interface DiagramInitEvent { // @public (undocumented) export class DiagramSelectionDirective extends ObjectSelectionDirective { // (undocumented) - readonly targetData: InputSignal | undefined>; + readonly targetData: InputSignal | Node_2 | undefined>; // (undocumented) targetType: BasePointerInputEvent['targetType']; // (undocumented) @@ -266,7 +266,7 @@ export type EdgeRoutingName = LooseAutocomplete; // @public (undocumented) export class EdgeSelectionDirective extends ObjectSelectionDirective { // (undocumented) - readonly targetData: InputSignal | undefined>; + readonly targetData: InputSignal | Node_2 | undefined>; // (undocumented) targetType: BasePointerInputEvent['targetType']; // (undocumented) @@ -1055,7 +1055,7 @@ export interface NodeRotationConfig { // @public (undocumented) export class NodeSelectionDirective extends ObjectSelectionDirective { // (undocumented) - readonly targetData: InputSignal | undefined>; + readonly targetData: InputSignal | Node_2 | undefined>; // (undocumented) targetType: BasePointerInputEvent['targetType']; // (undocumented) @@ -1340,7 +1340,7 @@ export interface ZIndexConfig { // @public (undocumented) export class ZIndexDirective { // (undocumented) - data: InputSignal>; + data: InputSignal | Node_2>; // (undocumented) zIndex: Signal; // (undocumented) From 28ec25e84764afbc7568bf76a6d86a8afa02829d Mon Sep 17 00:00:00 2001 From: Kamil Fogel Date: Tue, 9 Dec 2025 12:17:13 +0100 Subject: [PATCH 6/6] AF-365 Add grab cursor on background and investigate further cursor changes - Pr fix --- .../directives/input-events/panning/panning.directive.ts | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/packages/ng-diagram/projects/ng-diagram/src/lib/directives/input-events/panning/panning.directive.ts b/packages/ng-diagram/projects/ng-diagram/src/lib/directives/input-events/panning/panning.directive.ts index b4b48a4f7..26637a5ec 100644 --- a/packages/ng-diagram/projects/ng-diagram/src/lib/directives/input-events/panning/panning.directive.ts +++ b/packages/ng-diagram/projects/ng-diagram/src/lib/directives/input-events/panning/panning.directive.ts @@ -115,10 +115,6 @@ export class PanningDirective implements OnDestroy { private toggleGrabbingCursor(isGrabbing: boolean): void { const diagramElement = this.elementRef.nativeElement; - if (isGrabbing) { - diagramElement.classList.add('grabbing'); - } else { - diagramElement.classList.remove('grabbing'); - } + diagramElement.classList.toggle('grabbing', isGrabbing); } }