@kubex/zinc 1.1.26 → 1.1.28

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.
@@ -120,6 +120,9 @@ export default class ZnFlowCanvas extends ZincElement {
120
120
  @state() private _linkPos: { x: number; y: number } | null = null;
121
121
  /** The valid node under the cursor while linking — the preview snaps to its input. */
122
122
  @state() private _linkTarget: string | null = null;
123
+ /** Last pointer position (client coords) while linking, for edge auto-pan. */
124
+ private _linkClient: { x: number; y: number } | null = null;
125
+ private _linkScrollRaf: number | null = null;
123
126
 
124
127
  private _dragMoved = false;
125
128
  /** Centre the flow when it first arrives; any earlier user interaction opts out. */
@@ -307,13 +310,20 @@ export default class ZnFlowCanvas extends ZincElement {
307
310
  private _startLink(nodeId: string, port: string) {
308
311
  this._linking = {nodeId, port};
309
312
  this._linkPos = null;
313
+ this._linkClient = null;
310
314
  window.addEventListener('pointermove', this._onLinkPointerMove);
311
315
  window.addEventListener('keydown', this._onLinkKeyDown);
312
316
  window.addEventListener('blur', this._cancelLink);
317
+ this._linkScrollRaf = requestAnimationFrame(this._linkEdgeScroll);
313
318
  }
314
319
 
315
320
  private _onLinkPointerMove = (e: PointerEvent) => {
316
- const p = this.screenToCanvas(e.clientX, e.clientY);
321
+ this._linkClient = {x: e.clientX, y: e.clientY};
322
+ this._updateLinkFromClient(e.clientX, e.clientY);
323
+ };
324
+
325
+ private _updateLinkFromClient(clientX: number, clientY: number) {
326
+ const p = this.screenToCanvas(clientX, clientY);
317
327
  this._linkPos = p;
318
328
  const linking = this._linking;
319
329
  if (!linking) return;
@@ -327,6 +337,37 @@ export default class ZnFlowCanvas extends ZincElement {
327
337
  && nodeInputs(n, this._typeFor(n)).length > 0
328
338
  );
329
339
  this._linkTarget = target?.id ?? null;
340
+ }
341
+
342
+ /**
343
+ * While a branch rides the cursor, holding the pointer near (or past) a
344
+ * canvas edge auto-pans in that direction, so the target can be off-screen.
345
+ * Runs per frame until the link attaches or cancels.
346
+ */
347
+ private _linkEdgeScroll = () => {
348
+ this._linkScrollRaf = null;
349
+ if (!this._linking) return;
350
+ if (this._linkClient) {
351
+ const rect = this.getBoundingClientRect();
352
+ const ZONE = 48;
353
+ const MAX = 14;
354
+ const speed = (depth: number) => Math.min(MAX, Math.ceil(((ZONE - depth) / ZONE) * MAX));
355
+ const {x, y} = this._linkClient;
356
+ let dx = 0;
357
+ let dy = 0;
358
+ if (x < rect.left + ZONE) dx = speed(x - rect.left);
359
+ else if (x > rect.right - ZONE) dx = -speed(rect.right - x);
360
+ if (y < rect.top + ZONE) dy = speed(y - rect.top);
361
+ else if (y > rect.bottom - ZONE) dy = -speed(rect.bottom - y);
362
+ if (dx || dy) {
363
+ this.panX += dx;
364
+ this.panY += dy;
365
+ // The canvas moved under the stationary cursor — keep the preview and
366
+ // the snap target tracking it.
367
+ this._updateLinkFromClient(x, y);
368
+ }
369
+ }
370
+ this._linkScrollRaf = requestAnimationFrame(this._linkEdgeScroll);
330
371
  };
331
372
 
332
373
  private _onLinkKeyDown = (e: KeyboardEvent) => {
@@ -338,6 +379,11 @@ export default class ZnFlowCanvas extends ZincElement {
338
379
  this._linking = null;
339
380
  this._linkPos = null;
340
381
  this._linkTarget = null;
382
+ this._linkClient = null;
383
+ if (this._linkScrollRaf !== null) {
384
+ cancelAnimationFrame(this._linkScrollRaf);
385
+ this._linkScrollRaf = null;
386
+ }
341
387
  window.removeEventListener('pointermove', this._onLinkPointerMove);
342
388
  window.removeEventListener('keydown', this._onLinkKeyDown);
343
389
  window.removeEventListener('blur', this._cancelLink);