@pyreon/flow 0.10.0 → 0.11.1

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.
@@ -1,17 +1,17 @@
1
- import { describe, expect, it } from 'vitest'
1
+ import { describe, expect, it } from "vitest"
2
2
  import {
3
3
  getBezierPath,
4
4
  getSmartHandlePositions,
5
5
  getSmoothStepPath,
6
6
  getWaypointPath,
7
- } from '../edges'
8
- import { createFlow } from '../flow'
9
- import { Position } from '../types'
7
+ } from "../edges"
8
+ import { createFlow } from "../flow"
9
+ import { Position } from "../types"
10
10
 
11
11
  // ─── Edge paths — additional coverage ────────────────────────────────────────
12
12
 
13
- describe('edge paths — additional branches', () => {
14
- it('getBezierPath with Top/Left source positions', () => {
13
+ describe("edge paths — additional branches", () => {
14
+ it("getBezierPath with Top/Left source positions", () => {
15
15
  const top = getBezierPath({
16
16
  sourceX: 100,
17
17
  sourceY: 100,
@@ -33,13 +33,8 @@ describe('edge paths — additional branches', () => {
33
33
  expect(left.path).toMatch(/^M/)
34
34
  })
35
35
 
36
- it('getBezierPath with all target positions', () => {
37
- for (const pos of [
38
- Position.Top,
39
- Position.Right,
40
- Position.Bottom,
41
- Position.Left,
42
- ]) {
36
+ it("getBezierPath with all target positions", () => {
37
+ for (const pos of [Position.Top, Position.Right, Position.Bottom, Position.Left]) {
43
38
  const result = getBezierPath({
44
39
  sourceX: 0,
45
40
  sourceY: 0,
@@ -52,7 +47,7 @@ describe('edge paths — additional branches', () => {
52
47
  }
53
48
  })
54
49
 
55
- it('getSmoothStepPath with horizontal→horizontal positions', () => {
50
+ it("getSmoothStepPath with horizontal→horizontal positions", () => {
56
51
  const result = getSmoothStepPath({
57
52
  sourceX: 0,
58
53
  sourceY: 0,
@@ -64,7 +59,7 @@ describe('edge paths — additional branches', () => {
64
59
  expect(result.path).toMatch(/^M/)
65
60
  })
66
61
 
67
- it('getSmoothStepPath with vertical→vertical positions', () => {
62
+ it("getSmoothStepPath with vertical→vertical positions", () => {
68
63
  const result = getSmoothStepPath({
69
64
  sourceX: 0,
70
65
  sourceY: 0,
@@ -76,7 +71,7 @@ describe('edge paths — additional branches', () => {
76
71
  expect(result.path).toMatch(/^M/)
77
72
  })
78
73
 
79
- it('getSmoothStepPath with vertical→horizontal', () => {
74
+ it("getSmoothStepPath with vertical→horizontal", () => {
80
75
  const result = getSmoothStepPath({
81
76
  sourceX: 0,
82
77
  sourceY: 0,
@@ -88,7 +83,7 @@ describe('edge paths — additional branches', () => {
88
83
  expect(result.path).toMatch(/^M/)
89
84
  })
90
85
 
91
- it('getSmoothStepPath with Left source', () => {
86
+ it("getSmoothStepPath with Left source", () => {
92
87
  const result = getSmoothStepPath({
93
88
  sourceX: 200,
94
89
  sourceY: 0,
@@ -100,7 +95,7 @@ describe('edge paths — additional branches', () => {
100
95
  expect(result.path).toMatch(/^M/)
101
96
  })
102
97
 
103
- it('getSmoothStepPath with Bottom target', () => {
98
+ it("getSmoothStepPath with Bottom target", () => {
104
99
  const result = getSmoothStepPath({
105
100
  sourceX: 0,
106
101
  sourceY: 0,
@@ -112,47 +107,45 @@ describe('edge paths — additional branches', () => {
112
107
  expect(result.path).toMatch(/^M/)
113
108
  })
114
109
 
115
- it('getSmartHandlePositions with nodes at various positions', () => {
110
+ it("getSmartHandlePositions with nodes at various positions", () => {
116
111
  // Target to the left
117
112
  const leftward = getSmartHandlePositions(
118
- { id: '1', position: { x: 200, y: 0 }, data: {} },
119
- { id: '2', position: { x: 0, y: 0 }, data: {} },
113
+ { id: "1", position: { x: 200, y: 0 }, data: {} },
114
+ { id: "2", position: { x: 0, y: 0 }, data: {} },
120
115
  )
121
116
  expect(leftward.sourcePosition).toBe(Position.Left)
122
117
  expect(leftward.targetPosition).toBe(Position.Right)
123
118
 
124
119
  // Target below
125
120
  const downward = getSmartHandlePositions(
126
- { id: '1', position: { x: 0, y: 0 }, data: {} },
127
- { id: '2', position: { x: 0, y: 300 }, data: {} },
121
+ { id: "1", position: { x: 0, y: 0 }, data: {} },
122
+ { id: "2", position: { x: 0, y: 300 }, data: {} },
128
123
  )
129
124
  expect(downward.sourcePosition).toBe(Position.Bottom)
130
125
  expect(downward.targetPosition).toBe(Position.Top)
131
126
 
132
127
  // Target above
133
128
  const upward = getSmartHandlePositions(
134
- { id: '1', position: { x: 0, y: 300 }, data: {} },
135
- { id: '2', position: { x: 0, y: 0 }, data: {} },
129
+ { id: "1", position: { x: 0, y: 300 }, data: {} },
130
+ { id: "2", position: { x: 0, y: 0 }, data: {} },
136
131
  )
137
132
  expect(upward.sourcePosition).toBe(Position.Top)
138
133
  expect(upward.targetPosition).toBe(Position.Bottom)
139
134
  })
140
135
 
141
- it('getSmartHandlePositions with configured handles', () => {
136
+ it("getSmartHandlePositions with configured handles", () => {
142
137
  const result = getSmartHandlePositions(
143
138
  {
144
- id: '1',
139
+ id: "1",
145
140
  position: { x: 0, y: 0 },
146
141
  data: {},
147
- sourceHandles: [
148
- { type: 'source', position: Position.Bottom, id: 'out' },
149
- ],
142
+ sourceHandles: [{ type: "source", position: Position.Bottom, id: "out" }],
150
143
  },
151
144
  {
152
- id: '2',
145
+ id: "2",
153
146
  position: { x: 200, y: 200 },
154
147
  data: {},
155
- targetHandles: [{ type: 'target', position: Position.Top, id: 'in' }],
148
+ targetHandles: [{ type: "target", position: Position.Top, id: "in" }],
156
149
  },
157
150
  )
158
151
  // Should use configured handle positions
@@ -160,7 +153,7 @@ describe('edge paths — additional branches', () => {
160
153
  expect(result.targetPosition).toBe(Position.Top)
161
154
  })
162
155
 
163
- it('getWaypointPath with single waypoint', () => {
156
+ it("getWaypointPath with single waypoint", () => {
164
157
  const result = getWaypointPath({
165
158
  sourceX: 0,
166
159
  sourceY: 0,
@@ -168,7 +161,7 @@ describe('edge paths — additional branches', () => {
168
161
  targetY: 0,
169
162
  waypoints: [{ x: 100, y: 50 }],
170
163
  })
171
- expect(result.path).toBe('M0,0 L100,50 L200,0')
164
+ expect(result.path).toBe("M0,0 L100,50 L200,0")
172
165
  expect(result.labelX).toBe(100)
173
166
  expect(result.labelY).toBe(50)
174
167
  })
@@ -176,20 +169,20 @@ describe('edge paths — additional branches', () => {
176
169
 
177
170
  // ─── Flow — advanced operations ──────────────────────────────────────────────
178
171
 
179
- describe('createFlow — advanced', () => {
180
- describe('resolveCollisions', () => {
181
- it('pushes overlapping nodes apart', () => {
172
+ describe("createFlow — advanced", () => {
173
+ describe("resolveCollisions", () => {
174
+ it("pushes overlapping nodes apart", () => {
182
175
  const flow = createFlow({
183
176
  nodes: [
184
177
  {
185
- id: '1',
178
+ id: "1",
186
179
  position: { x: 0, y: 0 },
187
180
  width: 100,
188
181
  height: 50,
189
182
  data: {},
190
183
  },
191
184
  {
192
- id: '2',
185
+ id: "2",
193
186
  position: { x: 50, y: 0 },
194
187
  width: 100,
195
188
  height: 50,
@@ -198,25 +191,25 @@ describe('createFlow — advanced', () => {
198
191
  ],
199
192
  })
200
193
 
201
- flow.resolveCollisions('1')
194
+ flow.resolveCollisions("1")
202
195
  // Node 2 should have moved (either X or Y)
203
- const node2 = flow.getNode('2')!
196
+ const node2 = flow.getNode("2")!
204
197
  const moved = node2.position.x !== 50 || node2.position.y !== 0
205
198
  expect(moved).toBe(true)
206
199
  })
207
200
 
208
- it('does nothing when no overlaps', () => {
201
+ it("does nothing when no overlaps", () => {
209
202
  const flow = createFlow({
210
203
  nodes: [
211
204
  {
212
- id: '1',
205
+ id: "1",
213
206
  position: { x: 0, y: 0 },
214
207
  width: 100,
215
208
  height: 50,
216
209
  data: {},
217
210
  },
218
211
  {
219
- id: '2',
212
+ id: "2",
220
213
  position: { x: 500, y: 500 },
221
214
  width: 100,
222
215
  height: 50,
@@ -225,22 +218,22 @@ describe('createFlow — advanced', () => {
225
218
  ],
226
219
  })
227
220
 
228
- flow.resolveCollisions('1')
229
- expect(flow.getNode('2')!.position).toEqual({ x: 500, y: 500 })
221
+ flow.resolveCollisions("1")
222
+ expect(flow.getNode("2")!.position).toEqual({ x: 500, y: 500 })
230
223
  })
231
224
 
232
- it('resolves vertical overlaps', () => {
225
+ it("resolves vertical overlaps", () => {
233
226
  const flow = createFlow({
234
227
  nodes: [
235
228
  {
236
- id: '1',
229
+ id: "1",
237
230
  position: { x: 0, y: 0 },
238
231
  width: 200,
239
232
  height: 50,
240
233
  data: {},
241
234
  },
242
235
  {
243
- id: '2',
236
+ id: "2",
244
237
  position: { x: 0, y: 30 },
245
238
  width: 200,
246
239
  height: 50,
@@ -249,123 +242,121 @@ describe('createFlow — advanced', () => {
249
242
  ],
250
243
  })
251
244
 
252
- flow.resolveCollisions('1')
253
- const node2 = flow.getNode('2')!
245
+ flow.resolveCollisions("1")
246
+ const node2 = flow.getNode("2")!
254
247
  // Should push vertically since horizontal overlap is larger
255
248
  expect(node2.position.y).not.toBe(30)
256
249
  })
257
250
  })
258
251
 
259
- describe('getChildNodes / getAbsolutePosition', () => {
260
- it('returns child nodes of a group', () => {
252
+ describe("getChildNodes / getAbsolutePosition", () => {
253
+ it("returns child nodes of a group", () => {
261
254
  const flow = createFlow({
262
255
  nodes: [
263
256
  {
264
- id: 'group',
257
+ id: "group",
265
258
  position: { x: 0, y: 0 },
266
259
  group: true,
267
260
  data: {},
268
261
  },
269
262
  {
270
- id: 'child1',
263
+ id: "child1",
271
264
  position: { x: 10, y: 10 },
272
- parentId: 'group',
265
+ parentId: "group",
273
266
  data: {},
274
267
  },
275
268
  {
276
- id: 'child2',
269
+ id: "child2",
277
270
  position: { x: 20, y: 20 },
278
- parentId: 'group',
271
+ parentId: "group",
279
272
  data: {},
280
273
  },
281
- { id: 'other', position: { x: 100, y: 100 }, data: {} },
274
+ { id: "other", position: { x: 100, y: 100 }, data: {} },
282
275
  ],
283
276
  })
284
277
 
285
- const children = flow.getChildNodes('group')
278
+ const children = flow.getChildNodes("group")
286
279
  expect(children).toHaveLength(2)
287
- expect(children.map((n) => n.id)).toEqual(
288
- expect.arrayContaining(['child1', 'child2']),
289
- )
280
+ expect(children.map((n) => n.id)).toEqual(expect.arrayContaining(["child1", "child2"]))
290
281
  })
291
282
 
292
- it('getAbsolutePosition accounts for parent offset', () => {
283
+ it("getAbsolutePosition accounts for parent offset", () => {
293
284
  const flow = createFlow({
294
285
  nodes: [
295
286
  {
296
- id: 'parent',
287
+ id: "parent",
297
288
  position: { x: 100, y: 200 },
298
289
  data: {},
299
290
  },
300
291
  {
301
- id: 'child',
292
+ id: "child",
302
293
  position: { x: 10, y: 20 },
303
- parentId: 'parent',
294
+ parentId: "parent",
304
295
  data: {},
305
296
  },
306
297
  ],
307
298
  })
308
299
 
309
- const abs = flow.getAbsolutePosition('child')
300
+ const abs = flow.getAbsolutePosition("child")
310
301
  expect(abs).toEqual({ x: 110, y: 220 })
311
302
  })
312
303
 
313
- it('getAbsolutePosition for root node returns position', () => {
304
+ it("getAbsolutePosition for root node returns position", () => {
314
305
  const flow = createFlow({
315
- nodes: [{ id: '1', position: { x: 50, y: 75 }, data: {} }],
306
+ nodes: [{ id: "1", position: { x: 50, y: 75 }, data: {} }],
316
307
  })
317
308
 
318
- expect(flow.getAbsolutePosition('1')).toEqual({ x: 50, y: 75 })
309
+ expect(flow.getAbsolutePosition("1")).toEqual({ x: 50, y: 75 })
319
310
  })
320
311
 
321
- it('getAbsolutePosition for missing node returns 0,0', () => {
312
+ it("getAbsolutePosition for missing node returns 0,0", () => {
322
313
  const flow = createFlow()
323
- expect(flow.getAbsolutePosition('missing')).toEqual({ x: 0, y: 0 })
314
+ expect(flow.getAbsolutePosition("missing")).toEqual({ x: 0, y: 0 })
324
315
  })
325
316
  })
326
317
 
327
- describe('moveSelectedNodes', () => {
328
- it('moves all selected nodes by delta', () => {
318
+ describe("moveSelectedNodes", () => {
319
+ it("moves all selected nodes by delta", () => {
329
320
  const flow = createFlow({
330
321
  nodes: [
331
- { id: '1', position: { x: 0, y: 0 }, data: {} },
332
- { id: '2', position: { x: 100, y: 0 }, data: {} },
333
- { id: '3', position: { x: 200, y: 0 }, data: {} },
322
+ { id: "1", position: { x: 0, y: 0 }, data: {} },
323
+ { id: "2", position: { x: 100, y: 0 }, data: {} },
324
+ { id: "3", position: { x: 200, y: 0 }, data: {} },
334
325
  ],
335
326
  })
336
327
 
337
- flow.selectNode('1')
338
- flow.selectNode('2', true)
328
+ flow.selectNode("1")
329
+ flow.selectNode("2", true)
339
330
  flow.moveSelectedNodes(50, 25)
340
331
 
341
- expect(flow.getNode('1')!.position).toEqual({ x: 50, y: 25 })
342
- expect(flow.getNode('2')!.position).toEqual({ x: 150, y: 25 })
343
- expect(flow.getNode('3')!.position).toEqual({ x: 200, y: 0 }) // not selected
332
+ expect(flow.getNode("1")!.position).toEqual({ x: 50, y: 25 })
333
+ expect(flow.getNode("2")!.position).toEqual({ x: 150, y: 25 })
334
+ expect(flow.getNode("3")!.position).toEqual({ x: 200, y: 0 }) // not selected
344
335
  })
345
336
 
346
- it('does nothing with no selection', () => {
337
+ it("does nothing with no selection", () => {
347
338
  const flow = createFlow({
348
- nodes: [{ id: '1', position: { x: 0, y: 0 }, data: {} }],
339
+ nodes: [{ id: "1", position: { x: 0, y: 0 }, data: {} }],
349
340
  })
350
341
 
351
342
  flow.moveSelectedNodes(100, 100)
352
- expect(flow.getNode('1')!.position).toEqual({ x: 0, y: 0 })
343
+ expect(flow.getNode("1")!.position).toEqual({ x: 0, y: 0 })
353
344
  })
354
345
  })
355
346
 
356
- describe('getSnapLines', () => {
357
- it('snaps to aligned nodes', () => {
347
+ describe("getSnapLines", () => {
348
+ it("snaps to aligned nodes", () => {
358
349
  const flow = createFlow({
359
350
  nodes: [
360
351
  {
361
- id: '1',
352
+ id: "1",
362
353
  position: { x: 100, y: 100 },
363
354
  width: 100,
364
355
  height: 50,
365
356
  data: {},
366
357
  },
367
358
  {
368
- id: '2',
359
+ id: "2",
369
360
  position: { x: 300, y: 200 },
370
361
  width: 100,
371
362
  height: 50,
@@ -375,23 +366,23 @@ describe('createFlow — advanced', () => {
375
366
  })
376
367
 
377
368
  // Move node 2 close to node 1's center X
378
- const snap = flow.getSnapLines('2', { x: 98, y: 200 })
369
+ const snap = flow.getSnapLines("2", { x: 98, y: 200 })
379
370
  expect(snap.x).not.toBeNull()
380
371
  expect(snap.snappedPosition.x).not.toBe(98)
381
372
  })
382
373
 
383
- it('returns null lines when no alignment', () => {
374
+ it("returns null lines when no alignment", () => {
384
375
  const flow = createFlow({
385
376
  nodes: [
386
377
  {
387
- id: '1',
378
+ id: "1",
388
379
  position: { x: 0, y: 0 },
389
380
  width: 100,
390
381
  height: 50,
391
382
  data: {},
392
383
  },
393
384
  {
394
- id: '2',
385
+ id: "2",
395
386
  position: { x: 500, y: 500 },
396
387
  width: 100,
397
388
  height: 50,
@@ -400,23 +391,23 @@ describe('createFlow — advanced', () => {
400
391
  ],
401
392
  })
402
393
 
403
- const snap = flow.getSnapLines('2', { x: 500, y: 500 })
394
+ const snap = flow.getSnapLines("2", { x: 500, y: 500 })
404
395
  expect(snap.x).toBeNull()
405
396
  expect(snap.y).toBeNull()
406
397
  })
407
398
 
408
- it('snaps to left edge alignment', () => {
399
+ it("snaps to left edge alignment", () => {
409
400
  const flow = createFlow({
410
401
  nodes: [
411
402
  {
412
- id: '1',
403
+ id: "1",
413
404
  position: { x: 100, y: 0 },
414
405
  width: 100,
415
406
  height: 50,
416
407
  data: {},
417
408
  },
418
409
  {
419
- id: '2',
410
+ id: "2",
420
411
  position: { x: 100, y: 100 },
421
412
  width: 100,
422
413
  height: 50,
@@ -426,22 +417,22 @@ describe('createFlow — advanced', () => {
426
417
  })
427
418
 
428
419
  // Node 2 is already aligned on left edge
429
- const snap = flow.getSnapLines('2', { x: 102, y: 100 })
420
+ const snap = flow.getSnapLines("2", { x: 102, y: 100 })
430
421
  expect(snap.snappedPosition.x).toBe(100) // snapped to left edge
431
422
  })
432
423
 
433
- it('snaps to right edge alignment', () => {
424
+ it("snaps to right edge alignment", () => {
434
425
  const flow = createFlow({
435
426
  nodes: [
436
427
  {
437
- id: '1',
428
+ id: "1",
438
429
  position: { x: 100, y: 0 },
439
430
  width: 100,
440
431
  height: 50,
441
432
  data: {},
442
433
  },
443
434
  {
444
- id: '2',
435
+ id: "2",
445
436
  position: { x: 100, y: 100 },
446
437
  width: 100,
447
438
  height: 50,
@@ -451,24 +442,24 @@ describe('createFlow — advanced', () => {
451
442
  })
452
443
 
453
444
  // Move node 2 so right edges almost align
454
- const snap = flow.getSnapLines('2', { x: 98, y: 100 })
445
+ const snap = flow.getSnapLines("2", { x: 98, y: 100 })
455
446
  // Right edge of node1: 200, right edge of moved node2: 98+100=198
456
447
  // Diff = 2, within threshold 5
457
448
  expect(snap.snappedPosition.x).toBe(100) // snapped
458
449
  })
459
450
 
460
- it('snaps to center Y alignment', () => {
451
+ it("snaps to center Y alignment", () => {
461
452
  const flow = createFlow({
462
453
  nodes: [
463
454
  {
464
- id: '1',
455
+ id: "1",
465
456
  position: { x: 0, y: 100 },
466
457
  width: 100,
467
458
  height: 50,
468
459
  data: {},
469
460
  },
470
461
  {
471
- id: '2',
462
+ id: "2",
472
463
  position: { x: 200, y: 0 },
473
464
  width: 100,
474
465
  height: 50,
@@ -479,22 +470,22 @@ describe('createFlow — advanced', () => {
479
470
 
480
471
  // center Y of node1 = 100+25 = 125
481
472
  // Move node2 so its center Y is close: y + 25 ≈ 125 → y ≈ 100
482
- const snap = flow.getSnapLines('2', { x: 200, y: 102 })
473
+ const snap = flow.getSnapLines("2", { x: 200, y: 102 })
483
474
  expect(snap.snappedPosition.y).toBe(100) // snapped to center Y
484
475
  })
485
476
 
486
- it('snaps to bottom edge alignment', () => {
477
+ it("snaps to bottom edge alignment", () => {
487
478
  const flow = createFlow({
488
479
  nodes: [
489
480
  {
490
- id: '1',
481
+ id: "1",
491
482
  position: { x: 0, y: 0 },
492
483
  width: 100,
493
484
  height: 50,
494
485
  data: {},
495
486
  },
496
487
  {
497
- id: '2',
488
+ id: "2",
498
489
  position: { x: 200, y: 0 },
499
490
  width: 100,
500
491
  height: 50,
@@ -505,75 +496,75 @@ describe('createFlow — advanced', () => {
505
496
 
506
497
  // bottom of node1 = 50, bottom of node2 = y + 50
507
498
  // For snap: abs(y+50 - 50) < 5 → abs(y) < 5
508
- const snap = flow.getSnapLines('2', { x: 200, y: 3 })
499
+ const snap = flow.getSnapLines("2", { x: 200, y: 3 })
509
500
  expect(snap.snappedPosition.y).toBe(0) // snapped to bottom edge
510
501
  })
511
502
 
512
- it('returns original position for missing node', () => {
503
+ it("returns original position for missing node", () => {
513
504
  const flow = createFlow()
514
- const snap = flow.getSnapLines('missing', { x: 100, y: 200 })
505
+ const snap = flow.getSnapLines("missing", { x: 100, y: 200 })
515
506
  expect(snap.snappedPosition).toEqual({ x: 100, y: 200 })
516
507
  })
517
508
  })
518
509
 
519
- describe('reconnectEdge', () => {
520
- it('changes edge source', () => {
510
+ describe("reconnectEdge", () => {
511
+ it("changes edge source", () => {
521
512
  const flow = createFlow({
522
513
  nodes: [
523
- { id: '1', position: { x: 0, y: 0 }, data: {} },
524
- { id: '2', position: { x: 100, y: 0 }, data: {} },
525
- { id: '3', position: { x: 200, y: 0 }, data: {} },
514
+ { id: "1", position: { x: 0, y: 0 }, data: {} },
515
+ { id: "2", position: { x: 100, y: 0 }, data: {} },
516
+ { id: "3", position: { x: 200, y: 0 }, data: {} },
526
517
  ],
527
- edges: [{ id: 'e1', source: '1', target: '2' }],
518
+ edges: [{ id: "e1", source: "1", target: "2" }],
528
519
  })
529
520
 
530
- flow.reconnectEdge('e1', { source: '3' })
531
- expect(flow.getEdge('e1')!.source).toBe('3')
532
- expect(flow.getEdge('e1')!.target).toBe('2') // unchanged
521
+ flow.reconnectEdge("e1", { source: "3" })
522
+ expect(flow.getEdge("e1")!.source).toBe("3")
523
+ expect(flow.getEdge("e1")!.target).toBe("2") // unchanged
533
524
  })
534
525
 
535
- it('changes edge target', () => {
526
+ it("changes edge target", () => {
536
527
  const flow = createFlow({
537
528
  nodes: [
538
- { id: '1', position: { x: 0, y: 0 }, data: {} },
539
- { id: '2', position: { x: 100, y: 0 }, data: {} },
540
- { id: '3', position: { x: 200, y: 0 }, data: {} },
529
+ { id: "1", position: { x: 0, y: 0 }, data: {} },
530
+ { id: "2", position: { x: 100, y: 0 }, data: {} },
531
+ { id: "3", position: { x: 200, y: 0 }, data: {} },
541
532
  ],
542
- edges: [{ id: 'e1', source: '1', target: '2' }],
533
+ edges: [{ id: "e1", source: "1", target: "2" }],
543
534
  })
544
535
 
545
- flow.reconnectEdge('e1', { target: '3' })
546
- expect(flow.getEdge('e1')!.target).toBe('3')
536
+ flow.reconnectEdge("e1", { target: "3" })
537
+ expect(flow.getEdge("e1")!.target).toBe("3")
547
538
  })
548
539
  })
549
540
 
550
- describe('edge with custom id and handle', () => {
551
- it('generates id from source/target handles', () => {
541
+ describe("edge with custom id and handle", () => {
542
+ it("generates id from source/target handles", () => {
552
543
  const flow = createFlow({
553
544
  nodes: [
554
- { id: '1', position: { x: 0, y: 0 }, data: {} },
555
- { id: '2', position: { x: 100, y: 0 }, data: {} },
545
+ { id: "1", position: { x: 0, y: 0 }, data: {} },
546
+ { id: "2", position: { x: 100, y: 0 }, data: {} },
556
547
  ],
557
548
  edges: [
558
549
  {
559
- source: '1',
560
- target: '2',
561
- sourceHandle: 'out',
562
- targetHandle: 'in',
550
+ source: "1",
551
+ target: "2",
552
+ sourceHandle: "out",
553
+ targetHandle: "in",
563
554
  },
564
555
  ],
565
556
  })
566
557
 
567
- expect(flow.edges()[0]!.id).toBe('e-1-out-2-in')
558
+ expect(flow.edges()[0]!.id).toBe("e-1-out-2-in")
568
559
  })
569
560
  })
570
561
 
571
- describe('fitView with initial config', () => {
572
- it('fits view on creation when config.fitView is true', () => {
562
+ describe("fitView with initial config", () => {
563
+ it("fits view on creation when config.fitView is true", () => {
573
564
  const flow = createFlow({
574
565
  nodes: [
575
- { id: '1', position: { x: 0, y: 0 }, data: {} },
576
- { id: '2', position: { x: 500, y: 500 }, data: {} },
566
+ { id: "1", position: { x: 0, y: 0 }, data: {} },
567
+ { id: "2", position: { x: 500, y: 500 }, data: {} },
577
568
  ],
578
569
  fitView: true,
579
570
  })
@@ -584,19 +575,19 @@ describe('createFlow — advanced', () => {
584
575
  })
585
576
  })
586
577
 
587
- describe('proximity connect with connection rules', () => {
588
- it('respects connection rules', () => {
578
+ describe("proximity connect with connection rules", () => {
579
+ it("respects connection rules", () => {
589
580
  const flow = createFlow({
590
581
  nodes: [
591
582
  {
592
- id: '1',
593
- type: 'output',
583
+ id: "1",
584
+ type: "output",
594
585
  position: { x: 0, y: 0 },
595
586
  data: {},
596
587
  },
597
588
  {
598
- id: '2',
599
- type: 'input',
589
+ id: "2",
590
+ type: "input",
600
591
  position: { x: 100, y: 0 },
601
592
  data: {},
602
593
  },
@@ -606,37 +597,37 @@ describe('createFlow — advanced', () => {
606
597
  },
607
598
  })
608
599
 
609
- expect(flow.getProximityConnection('1', 200)).toBeNull()
600
+ expect(flow.getProximityConnection("1", 200)).toBeNull()
610
601
  })
611
602
  })
612
603
 
613
- describe('undo/redo edge cases', () => {
614
- it('undo with empty history does nothing', () => {
604
+ describe("undo/redo edge cases", () => {
605
+ it("undo with empty history does nothing", () => {
615
606
  const flow = createFlow({
616
- nodes: [{ id: '1', position: { x: 0, y: 0 }, data: {} }],
607
+ nodes: [{ id: "1", position: { x: 0, y: 0 }, data: {} }],
617
608
  })
618
609
 
619
610
  flow.undo()
620
611
  expect(flow.nodes()).toHaveLength(1)
621
612
  })
622
613
 
623
- it('redo with empty redo stack does nothing', () => {
614
+ it("redo with empty redo stack does nothing", () => {
624
615
  const flow = createFlow({
625
- nodes: [{ id: '1', position: { x: 0, y: 0 }, data: {} }],
616
+ nodes: [{ id: "1", position: { x: 0, y: 0 }, data: {} }],
626
617
  })
627
618
 
628
619
  flow.redo()
629
620
  expect(flow.nodes()).toHaveLength(1)
630
621
  })
631
622
 
632
- it('multiple undo/redo cycles', () => {
623
+ it("multiple undo/redo cycles", () => {
633
624
  const flow = createFlow()
634
625
 
635
626
  flow.pushHistory()
636
- flow.addNode({ id: '1', position: { x: 0, y: 0 }, data: {} })
627
+ flow.addNode({ id: "1", position: { x: 0, y: 0 }, data: {} })
637
628
 
638
629
  flow.pushHistory()
639
- flow.addNode({ id: '2', position: { x: 100, y: 0 }, data: {} })
630
+ flow.addNode({ id: "2", position: { x: 100, y: 0 }, data: {} })
640
631
 
641
632
  expect(flow.nodes()).toHaveLength(2)
642
633
 
@@ -654,22 +645,22 @@ describe('createFlow — advanced', () => {
654
645
  })
655
646
  })
656
647
 
657
- describe('copy/paste with edges', () => {
658
- it('copies connected edges between selected nodes', () => {
648
+ describe("copy/paste with edges", () => {
649
+ it("copies connected edges between selected nodes", () => {
659
650
  const flow = createFlow({
660
651
  nodes: [
661
- { id: '1', position: { x: 0, y: 0 }, data: {} },
662
- { id: '2', position: { x: 100, y: 0 }, data: {} },
663
- { id: '3', position: { x: 200, y: 0 }, data: {} },
652
+ { id: "1", position: { x: 0, y: 0 }, data: {} },
653
+ { id: "2", position: { x: 100, y: 0 }, data: {} },
654
+ { id: "3", position: { x: 200, y: 0 }, data: {} },
664
655
  ],
665
656
  edges: [
666
- { source: '1', target: '2' },
667
- { source: '2', target: '3' },
657
+ { source: "1", target: "2" },
658
+ { source: "2", target: "3" },
668
659
  ],
669
660
  })
670
661
 
671
- flow.selectNode('1')
672
- flow.selectNode('2', true)
662
+ flow.selectNode("1")
663
+ flow.selectNode("2", true)
673
664
  flow.copySelected()
674
665
  flow.paste()
675
666
 
@@ -679,9 +670,9 @@ describe('createFlow — advanced', () => {
679
670
  expect(flow.edges()).toHaveLength(3)
680
671
  })
681
672
 
682
- it('copy with no selection does nothing', () => {
673
+ it("copy with no selection does nothing", () => {
683
674
  const flow = createFlow({
684
- nodes: [{ id: '1', position: { x: 0, y: 0 }, data: {} }],
675
+ nodes: [{ id: "1", position: { x: 0, y: 0 }, data: {} }],
685
676
  })
686
677
 
687
678
  flow.copySelected()
@@ -690,10 +681,10 @@ describe('createFlow — advanced', () => {
690
681
  })
691
682
  })
692
683
 
693
- describe('listener callbacks', () => {
694
- it('onNodeDragStart/End can be registered', () => {
684
+ describe("listener callbacks", () => {
685
+ it("onNodeDragStart/End can be registered", () => {
695
686
  const flow = createFlow({
696
- nodes: [{ id: '1', position: { x: 0, y: 0 }, data: {} }],
687
+ nodes: [{ id: "1", position: { x: 0, y: 0 }, data: {} }],
697
688
  })
698
689
 
699
690
  const starts: string[] = []
@@ -703,32 +694,32 @@ describe('createFlow — advanced', () => {
703
694
  flow.onNodeDragEnd((n) => ends.push(n.id))
704
695
 
705
696
  // Emit manually via _emit
706
- flow._emit.nodeDragStart(flow.getNode('1')!)
707
- flow._emit.nodeDragEnd(flow.getNode('1')!)
697
+ flow._emit.nodeDragStart(flow.getNode("1")!)
698
+ flow._emit.nodeDragEnd(flow.getNode("1")!)
708
699
 
709
- expect(starts).toEqual(['1'])
710
- expect(ends).toEqual(['1'])
700
+ expect(starts).toEqual(["1"])
701
+ expect(ends).toEqual(["1"])
711
702
  })
712
703
 
713
- it('onNodeDoubleClick', () => {
704
+ it("onNodeDoubleClick", () => {
714
705
  const flow = createFlow({
715
- nodes: [{ id: '1', position: { x: 0, y: 0 }, data: {} }],
706
+ nodes: [{ id: "1", position: { x: 0, y: 0 }, data: {} }],
716
707
  })
717
708
 
718
709
  const clicked: string[] = []
719
710
  flow.onNodeDoubleClick((n) => clicked.push(n.id))
720
711
 
721
- flow._emit.nodeDoubleClick(flow.getNode('1')!)
722
- expect(clicked).toEqual(['1'])
712
+ flow._emit.nodeDoubleClick(flow.getNode("1")!)
713
+ expect(clicked).toEqual(["1"])
723
714
  })
724
715
 
725
- it('onNodeClick / onEdgeClick', () => {
716
+ it("onNodeClick / onEdgeClick", () => {
726
717
  const flow = createFlow({
727
718
  nodes: [
728
- { id: '1', position: { x: 0, y: 0 }, data: {} },
729
- { id: '2', position: { x: 100, y: 0 }, data: {} },
719
+ { id: "1", position: { x: 0, y: 0 }, data: {} },
720
+ { id: "2", position: { x: 100, y: 0 }, data: {} },
730
721
  ],
731
- edges: [{ id: 'e1', source: '1', target: '2' }],
722
+ edges: [{ id: "e1", source: "1", target: "2" }],
732
723
  })
733
724
 
734
725
  const nodeClicks: string[] = []
@@ -737,29 +728,29 @@ describe('createFlow — advanced', () => {
737
728
  flow.onNodeClick((n) => nodeClicks.push(n.id))
738
729
  flow.onEdgeClick((e) => edgeClicks.push(e.id!))
739
730
 
740
- flow._emit.nodeClick(flow.getNode('1')!)
741
- flow._emit.edgeClick(flow.getEdge('e1')!)
731
+ flow._emit.nodeClick(flow.getNode("1")!)
732
+ flow._emit.edgeClick(flow.getEdge("e1")!)
742
733
 
743
- expect(nodeClicks).toEqual(['1'])
744
- expect(edgeClicks).toEqual(['e1'])
734
+ expect(nodeClicks).toEqual(["1"])
735
+ expect(edgeClicks).toEqual(["e1"])
745
736
  })
746
737
  })
747
738
 
748
- describe('containerSize', () => {
749
- it('containerSize signal exists with defaults', () => {
739
+ describe("containerSize", () => {
740
+ it("containerSize signal exists with defaults", () => {
750
741
  const flow = createFlow()
751
742
  expect(flow.containerSize()).toEqual({ width: 800, height: 600 })
752
743
  })
753
744
 
754
- it('containerSize can be updated', () => {
745
+ it("containerSize can be updated", () => {
755
746
  const flow = createFlow()
756
747
  flow.containerSize.set({ width: 1200, height: 900 })
757
748
  expect(flow.containerSize()).toEqual({ width: 1200, height: 900 })
758
749
  })
759
750
  })
760
751
 
761
- describe('clampToExtent', () => {
762
- it('returns position unchanged when no extent', () => {
752
+ describe("clampToExtent", () => {
753
+ it("returns position unchanged when no extent", () => {
763
754
  const flow = createFlow()
764
755
  expect(flow.clampToExtent({ x: -999, y: -999 })).toEqual({
765
756
  x: -999,
@@ -767,7 +758,7 @@ describe('createFlow — advanced', () => {
767
758
  })
768
759
  })
769
760
 
770
- it('clamps to extent boundaries', () => {
761
+ it("clamps to extent boundaries", () => {
771
762
  const flow = createFlow({
772
763
  nodeExtent: [
773
764
  [0, 0],
@@ -785,18 +776,18 @@ describe('createFlow — advanced', () => {
785
776
  })
786
777
  })
787
778
 
788
- describe('edge default type', () => {
789
- it('uses defaultEdgeType from config', () => {
779
+ describe("edge default type", () => {
780
+ it("uses defaultEdgeType from config", () => {
790
781
  const flow = createFlow({
791
782
  nodes: [
792
- { id: '1', position: { x: 0, y: 0 }, data: {} },
793
- { id: '2', position: { x: 100, y: 0 }, data: {} },
783
+ { id: "1", position: { x: 0, y: 0 }, data: {} },
784
+ { id: "2", position: { x: 100, y: 0 }, data: {} },
794
785
  ],
795
- edges: [{ source: '1', target: '2' }],
796
- defaultEdgeType: 'straight',
786
+ edges: [{ source: "1", target: "2" }],
787
+ defaultEdgeType: "straight",
797
788
  })
798
789
 
799
- expect(flow.edges()[0]!.type).toBe('straight')
790
+ expect(flow.edges()[0]!.type).toBe("straight")
800
791
  })
801
792
  })
802
793
  })