@weasel-js/diagram 1.13.0 → 1.14.0

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.
Files changed (35) hide show
  1. package/README.md +122 -17
  2. package/dist/{chunk-Y72FK3Y7.js → chunk-5VNPLOIX.js} +94 -6
  3. package/dist/chunk-5VNPLOIX.js.map +1 -0
  4. package/dist/{chunk-ESFIS7BB.js → chunk-62SMY45E.js} +918 -574
  5. package/dist/chunk-62SMY45E.js.map +1 -0
  6. package/dist/{chunk-FAQXYGMX.js → chunk-TBG6DFB2.js} +3 -3
  7. package/dist/{chunk-FAQXYGMX.js.map → chunk-TBG6DFB2.js.map} +1 -1
  8. package/dist/{chunk-L4H444QI.js → chunk-VB6HUKNG.js} +659 -185
  9. package/dist/chunk-VB6HUKNG.js.map +1 -0
  10. package/dist/{chunk-QU4QZUC6.js → chunk-ZWXM5F4I.js} +141 -39
  11. package/dist/chunk-ZWXM5F4I.js.map +1 -0
  12. package/dist/{dataTypes-DW-MljuN.d.ts → dataTypes-BIkhAOc4.d.ts} +13 -2
  13. package/dist/effect-audio.d.ts +2 -1
  14. package/dist/effect-audio.js +6 -5
  15. package/dist/effect-audio.js.map +1 -1
  16. package/dist/effect.d.ts +46 -16
  17. package/dist/effect.js +257 -102
  18. package/dist/effect.js.map +1 -1
  19. package/dist/icons.table.js +262 -0
  20. package/dist/icons.table.js.map +1 -1
  21. package/dist/icons.table.json +262 -0
  22. package/dist/index.d.ts +491 -167
  23. package/dist/index.js +586 -36
  24. package/dist/index.js.map +1 -1
  25. package/dist/labelTrait-BBjRgxbz.d.ts +44 -0
  26. package/dist/layout.d.ts +4 -3
  27. package/dist/{layout.entry-CQoPNfzA.d.ts → layout.entry-Ca6pVvqo.d.ts} +23 -2
  28. package/dist/layout.js +2 -2
  29. package/dist/{stageTypes-DvnR8cKQ.d.ts → stageTypes-UiO25hcn.d.ts} +7 -0
  30. package/dist/{types-vbW21fHm.d.ts → types-B0n2CNTW.d.ts} +108 -81
  31. package/package.json +11 -9
  32. package/dist/chunk-ESFIS7BB.js.map +0 -1
  33. package/dist/chunk-L4H444QI.js.map +0 -1
  34. package/dist/chunk-QU4QZUC6.js.map +0 -1
  35. package/dist/chunk-Y72FK3Y7.js.map +0 -1
package/README.md CHANGED
@@ -73,7 +73,8 @@ return <SceneCanvas ref={canvasRef} scene={scene} ambient={[contribution]} />;
73
73
 
74
74
  Dragging one port onto another authors an edge. Which pairs may be joined is
75
75
  `canConnect`, which defaults to "a port may not join itself, and two ports that
76
- both declare a `type` must declare the same one".
76
+ both declare a `type` must declare the same one". It answers a `DropVerdict`
77
+ (see "Refusing a drop with a reason").
77
78
 
78
79
  A port may name other places it can sit, in `sites`. An edge meeting it takes
79
80
  whichever place faces the edge's next point — its first waypoint, or the other
@@ -378,7 +379,33 @@ pointer moves onto an overlay. Edges answer only with `pickEdges`. For DOM
378
379
  the view does not hold, `rectOf(id)` on the ref gives a target's client rect
379
380
  and `subscribeFrame` says when to read it again.
380
381
 
381
- ### Reordering a group's members
382
+ ### Refusing a drop with a reason
383
+
384
+ Every "may this land here?" check answers a `DropVerdict`, the one shape core
385
+ uses too: `true` lands, `false` is a silent no, and `{ refuse: string }` is a
386
+ no the user is told about.
387
+
388
+ | Check | Asked about |
389
+ |---|---|
390
+ | `canConnect(from, to, moving?)` | a new edge's end, or a selected edge's end being moved (`moving` names it) |
391
+ | `canReparent(ids, container)` | nodes dragged into a container or lane they are not already in, once the diagram's own rules allow it |
392
+ | `canDropItem(item, target)` | an item carried in from a palette (see "Dropping items from a palette") |
393
+
394
+ Over a `false` the drag behaves as if the target were not there: a port is
395
+ never snapped to, and a container is passed over for the one around it. Over a
396
+ refusal the canvas outlines the target in the `refused` overlay role and shows
397
+ the reason beside the pointer; a release there reports nothing, and a moved
398
+ node goes back where it was.
399
+
400
+ ```tsx
401
+ <DiagramView
402
+ specs={specs}
403
+ canConnect={(from, to) => (to.nodeId === 'source' ? { refuse: 'The source takes no inputs' } : true)}
404
+ canReparent={(_ids, into) => (into === 'shelf' ? { refuse: 'The shelf is locked' } : true)}
405
+ />
406
+ ```
407
+
408
+ ### Reordering a group's or a container's members
382
409
 
383
410
  A group with `reorder: 'x' | 'y'` lets `onReorder` drag any of its members
384
411
  along that axis; a member that is a group carries everything inside it. The
@@ -389,9 +416,51 @@ order given across every rank, so writing the order back is all it takes.
389
416
 
390
417
  ```tsx
391
418
  const data = { nodes, edges, groups: [...rows, { id: 'layers', members: order, reorder: 'y' }] };
392
- <DiagramView specs={diagramScene(data)} onReorder={({ order }) => setOrder(order)} />
419
+ <DiagramView specs={diagramScene(data)} onReorder={({ parent, order }) => setOrder(order)} />
393
420
  ```
394
421
 
422
+ A `DataContainer` takes `reorder` the same way, with the same drag, the same
423
+ Alt and arrow key, and the same report: `parent` is the container's id and
424
+ `order` its members in their new order. Nothing moves until the data does, so
425
+ place the members by their order and write it to `members`. A body drag on a
426
+ member of a reorderable container reorders it until the pointer leaves the
427
+ container's box; from there it is a move, reported to `onMove` with the
428
+ `parent` it lands in, as any shape dragged out of a container is.
429
+
430
+ ### Dropping items from a palette
431
+
432
+ A list the host renders outside the canvas becomes a palette with
433
+ `dragItemProps(item)`, spread on each entry: a press carries `item`, any value
434
+ of the host's own, over the page. While it is over the diagram, the shape or
435
+ container it would land on is outlined, and in a container marked `reorder` a
436
+ bar marks its place. Release reports an `ItemDrop` to `onDropItem` and adds
437
+ nothing.
438
+
439
+ | Field | What it holds |
440
+ |---|---|
441
+ | `item` | the value `dragItemProps` was given |
442
+ | `target` | the shape or the container it was dropped on, or `null` for the bare canvas |
443
+ | `container` | the container or lane that would hold it: the target when that is one, else the one around the pointer; `null` at the top level |
444
+ | `index` | its place among `container`'s members, along the container's `reorder` axis, else in reading order (top to bottom, then left to right); `null` with no container |
445
+ | `at` | the pointer, in world units |
446
+
447
+ ```tsx
448
+ <li {...dragItemProps({ kind: 'blur' })}>Blur</li>
449
+ <DiagramView
450
+ specs={specs}
451
+ onDropItem={({ item, container, index }) => insert(item, container, index)}
452
+ canDropItem={(item, { container }) => (container === 'shelf' ? { refuse: 'The shelf is locked' } : true)}
453
+ />
454
+ ```
455
+
456
+ Give each entry `touch-action: none` so a touch drag is a carry, not a scroll.
457
+ `startItemDrag(event, item)` starts one from a pointer event of your own, and
458
+ `createItemDropAction` (or `itemDropContribution`, to pass as `ambient`) is the
459
+ canvas half for a `SceneCanvas` of your own; the carry travels as
460
+ `DIAGRAM_ITEM_CARRY`. There its `report` gets the canvas's deps as well as the
461
+ drop, and `requires` names the ones it reads, so it can add the item itself
462
+ through `insert`. A `ToolPalette` carries from its buttons with `carryTool`.
463
+
395
464
  ### Stencils
396
465
 
397
466
  A `DiagramStencil` is a palette entry: an id, a label, an outline and a default
@@ -439,7 +508,7 @@ drawn inside a container or a lane becomes its member (`diagramDropParentAt`).
439
508
  `containerBuild` returns the ops on their own, and `addLane` and
440
509
  `releaseMembers` are the edits as functions.
441
510
 
442
- What a region admits is the `canDropInto` dep's call, and `diagramCanDropInto(scene)`
511
+ What a region admits is the `canDropInto` dep's call, and `diagramCanDropInto(scene, canReparent?)`
443
512
  is the one for a diagram: containers and lanes take shapes and containers, a
444
513
  pool takes only lanes, and a stencil body, an edge, or a label takes nothing.
445
514
  `diagramContainers` returns the lane layer to register and the contribution to
@@ -517,7 +586,7 @@ dragged undoes in one step; `scene.history.seal()` ends the run. `parseDiagramTh
517
586
 
518
587
  ### Laying it out
519
588
 
520
- `layered`, `tree`, `force` and `chain` are plain functions of the graph. Each
589
+ `layered`, `tree`, `force`, `chain`, and `radial` are plain functions of the graph. Each
521
590
  hands back the new top-left for every node that **moves** — a node already
522
591
  standing where the layout wants it is absent, so re-running a layout on an
523
592
  unchanged diagram writes nothing at all.
@@ -601,6 +670,14 @@ naming ports that face each other, runs on a track of its own in the gap
601
670
  between them, so a fan of them never crosses; the gap grows to keep tracks 12
602
671
  apart. Groups are ignored.
603
672
 
673
+ `radial` is the mind-map layout. The first root `tree` would find sits in the middle, and its
674
+ children are dealt to its right and its left, in graph order, each to whichever side holds fewer
675
+ nodes so far. Each side grows away from the root as a horizontal `tree`, one band per depth
676
+ `rankGap` apart, its subtrees packed as blocks `nodeGap` apart and centered on the root. Because
677
+ sides are dealt in graph order and each side keeps the order its branches stand in, a second run
678
+ moves nothing. Further trees lay out the same way, stacked below the first. `direction` and groups
679
+ are ignored.
680
+
604
681
  ### From data
605
682
 
606
683
  `diagramScene` turns plain `{ nodes, edges }` into a laid-out scene, and
@@ -611,6 +688,11 @@ const specs = useMemo(() => diagramScene(data, { nodeStyle }), [data]);
611
688
  return <DiagramView specs={specs} width={360} height={600} selected={id} onSelect={setId} />;
612
689
  ```
613
690
 
691
+ `onSelect(id, ids)` reports the latest pick and every id picked. With
692
+ `selectionMode="multiple"`, Shift-click adds a node, group or edge to the pick
693
+ or takes it out; `selected` takes one id or an array, and handing back the
694
+ reported `id` leaves the rest picked.
695
+
614
696
  Every box is a `buildBody` body, so a data node takes the same knobs a body
615
697
  does — `outline`, `rows`, `padding`, `gap`, `verticalAlign`, `ports` — plus `pinned`, a
616
698
  starting `at`, and a minimum `width`/`height`; `lines` is shorthand for one
@@ -628,12 +710,24 @@ give the style an item is drawn in, for a writer that needs it without drawing;
628
710
  no width, `NODE_STROKE_WIDTH`, `LANE_STROKE_WIDTH`, and `EDGE_STROKE_WIDTH` are what is drawn. `layer` puts every
629
711
  spec on a layer other than `'main'`.
630
712
 
631
- `outline` is `'rect'`, `'diamond'`, `'stadium'`, `'parallelogram'`,
632
- `'trapezoid'` (a demultiplexer: tall at the right, short at the left),
633
- `'hexagon'` (pointed at the left and right, its rows kept between the points), or a
634
- `Path` drawn in a unit square — `(0, 0)` the box's top-left, `(1, 1)` its
635
- bottom-right — which is stretched over the box, so it follows its node as
636
- marks do.
713
+ `outline` is a name from the outline table, or a `Path` drawn in a unit square
714
+ — `(0, 0)` the box's top-left, `(1, 1)` its bottom-right — which is stretched
715
+ over the box, so it follows its node as marks do. The built-in names are the
716
+ flowchart shapes `'rect'`, `'diamond'`, `'stadium'`, `'ellipse'`, `'parallelogram'`,
717
+ `'trapezoid'` (a demultiplexer: tall at the right, short at the left), and
718
+ `'hexagon'` (pointed at the left and right, its rows kept between the points);
719
+ `'roundRect'`, `'triangle'`, `'octagon'`, `'cloud'`, `'doubleEllipse'`, and
720
+ `'actor'` (a stick figure, its label in the strip beneath it); and `'cylinder'`,
721
+ `'document'`, `'note'`, `'folder'`, and `'cube'`. Each keeps its rows inside the
722
+ visible shape, clear of a cylinder's cap or a note's fold. Some draw a detail,
723
+ stroked over the fill: a cylinder's rim, a note's fold, a cube's front edges.
724
+
725
+ `registerOutline(name, def)` adds a name, or shadows a built-in until its
726
+ disposer runs. An `OutlineDef` builds `path` in a node's bounds, and optionally
727
+ `detail`, `content` (the box rows lay out in), and `boxForContent` (its inverse,
728
+ for sizing a node to its rows). `outlineFromD(d, { detail, content })` builds one
729
+ from SVG path data in a unit square. A saved name that is not registered paints
730
+ as `'rect'` and warns once.
637
731
 
638
732
  `marks` draws more over a box than its rows. A mark with `d` is SVG path data
639
733
  in a unit square, stretched over the node's box; it takes `fill`, `stroke`,
@@ -720,7 +814,8 @@ A pool always has a box: 600 across and 120 along per lane when it gives none
720
814
  (`'y'`, rows, by default) at their `size`, and lanes giving none share what
721
815
  the pool's box leaves. An edge with an end inside a boxed region ranks against
722
816
  the outermost one holding it, and keeps none of layout's route. `pinned`
723
- leaves a box where it is. Under `theme`, a region naming a `style` role takes
817
+ leaves a box where it is. A container's `reorder` lets `onReorder` drag its
818
+ members along that axis (see "Reordering a group's or a container's members"). Under `theme`, a region naming a `style` role takes
724
819
  that role's colors; otherwise a container takes the theme's `container`, a
725
820
  pool its `lane.header`, and lanes the `lane.bodies` in turn; titles are set in
726
821
  the diagram's face, the theme's when `font` is unset. `router="avoid"`
@@ -977,7 +1072,7 @@ and a `color(type)` for the ports. `EFFECT_LOOKS` holds `nodeGraph`, `rack`, `la
977
1072
  | Look | Draws | Options |
978
1073
  | --- | --- | --- |
979
1074
  | `nodeGraph` (default) | Every port a named row on its stage, a wire from port to port, flowing left to right. | `router` (default `'bezier'`), `nodeGap`, `rankGap`, `colors`, `showParams`, `showValues`, `showPreviews`, `previewSize`, `branch` |
980
- | `rack` | The main signal on one straight line, and everything else hung beside the stage on the line it is nearest to, whichever way the wire runs. | `chain`, `side`, `nodeGap`, `rankGap`, `colors`, `showParams`, `showValues`, `showPreviews`, `previewSize`, `branch`, `collapseSkips` |
1075
+ | `rack` | The main signal on one straight line, and everything else hung beside the stage on the line it is nearest to, whichever way the wire runs. | `chain`, `direction`, `side`, `nodeGap`, `rankGap`, `colors`, `showParams`, `showValues`, `showPreviews`, `previewSize`, `branch`, `collapseSkips` |
981
1076
  | `lanes` | A horizontal lane per value type, and each stage standing across the lanes of the types it reads and writes, as tall as they are, its ports in their own lanes. | `lanes`, `laneHeight`, `rankGap`, `router`, `colors`, `showParams`, `showValues`, `showPreviews`, `previewSize`, `branch`, `measure` |
982
1077
  | `compact` | Each stage one line, its title alone, no ports drawn, and one line between two stages however many wires join them. For a pipeline too big to read as a node graph. | `router`, `nodeGap`, `rankGap`, `colors`, `branch` |
983
1078
 
@@ -986,8 +1081,16 @@ true) shows the `params` of ordinary stages, sources and sinks; `showValues`
986
1081
  (default false) keeps a row per output on those stages for a run's values, and
987
1082
  `showPreviews` (default false) a slot per output for its previews. `rack` runs
988
1083
  along `chain`, a list of stage ids that defaults to the longest path over data
989
- wires (`mainChain(pipeline)` returns it); `side` is `'below'` (default) or
990
- `'above'`.
1084
+ wires (`mainChain(pipeline)` returns it). Its `direction` is `'right'`
1085
+ (default), the line running left to right, or `'down'`, a column the main
1086
+ signal enters at each stage's top and leaves at its bottom, which a reorder
1087
+ drags along vertically. `side` is `'below'` (default) or `'above'`; in a
1088
+ column, `'below'` hangs the side stages on the column's right and `'above'`
1089
+ on its left, and a collapsed skip's arc runs down the other edge. A wire from
1090
+ a stage's main output into the side input of a stage further down the line,
1091
+ past at least one stage, leaves from a tap on the side stages' edge (a port
1092
+ named `~tap:<output>`), so it runs beside the stages between rather than
1093
+ through them; the editor and a run read it as the output it taps.
991
1094
 
992
1095
  `lanes` puts the lanes top down in the order their types first appear on the
993
1096
  pipeline's ports, after any it is given in `lanes`. A stage stands
@@ -1200,7 +1303,9 @@ reports, so the editor gathers them and reports one edit once the drag is done
1200
1303
  reporting, a microtask later.
1201
1304
 
1202
1305
  `selectedGroup` and `onSelectGroup` are the group pick, beside `selected` and
1203
- `onSelect`, under every look. The ref's `group(ids)` and `ungroup(id)` report
1306
+ `onSelect`, under every look. Shift-click adds a stage or group to the pick or
1307
+ takes it out, and `onSelect`'s second argument lists every stage and group
1308
+ picked, ready for `group(ids)`. The ref's `group(ids)` and `ungroup(id)` report
1204
1309
  `'Group'` and `'Ungroup'`, and `renameGroup(id)` opens the title field. The
1205
1310
  edits are plain functions too:
1206
1311
 
@@ -1317,7 +1422,7 @@ resize; `rayHit` moves it onto the shape. Don't store outline-relative anchors.
1317
1422
  connect is routing, and lives in the binding's `target`. Which ports a live
1318
1423
  connect may land on cannot be routing — the dispatcher never re-reads the
1319
1424
  affordance under a moving pointer — so `canConnect` filters the candidate set
1320
- instead. Neither is an action body inspecting a hit and bailing.
1425
+ instead, and a refusal stays a candidate so it can be drawn refused. Neither is an action body inspecting a hit and bailing.
1321
1426
 
1322
1427
  **A live run does not re-anchor; the one-shot layouts do.** The anchor
1323
1428
  translation keeps a single 300-tick jump from moving the diagram off where the
@@ -1,4 +1,4 @@
1
- import { labelCenter, samePoints } from './chunk-L4H444QI.js';
1
+ import { labelCenter, DEFAULT_NODE_GAP, DEFAULT_RANK_GAP, forestOf, subtreeBlocks, graphOrder, translated, pinnedSet, samePoints } from './chunk-VB6HUKNG.js';
2
2
  import { polylineFromPoints } from '@weasel-js/core/math';
3
3
 
4
4
  // src/hops/types.ts
@@ -1342,7 +1342,7 @@ function candidatesOf(label, route, tries, spacing) {
1342
1342
  const length = route.length;
1343
1343
  if (length === 0) return out;
1344
1344
  const start = typeof at === "object" ? arcNearest(route.points, at.near) : (typeof at === "number" ? at : NAMED[at] ?? 0.5) * length;
1345
- const sides = offset === 0 ? [0] : [offset, -offset];
1345
+ const sides2 = offset === 0 ? [0] : [offset, -offset];
1346
1346
  const push = (s, side) => {
1347
1347
  const spot = { at: s / length, offset: side };
1348
1348
  out.push({ placement: { at: spot.at, offset: side }, spot });
@@ -1353,7 +1353,7 @@ function candidatesOf(label, route, tries, spacing) {
1353
1353
  for (const dir of [1, -1]) {
1354
1354
  const s = start + dir * k * step;
1355
1355
  if (s < 0 || s > length) continue;
1356
- for (const side of sides) push(s, side);
1356
+ for (const side of sides2) push(s, side);
1357
1357
  }
1358
1358
  }
1359
1359
  return out;
@@ -1426,6 +1426,94 @@ function placeLabels(input, opts = {}) {
1426
1426
  return out;
1427
1427
  }
1428
1428
 
1429
- export { AVOID_DEFAULTS, DEFAULT_HOP_SIZE, HOPS_DOC_KEY, createAvoidRouter, edgeHops, placeLabels, simplifyStops };
1430
- //# sourceMappingURL=chunk-Y72FK3Y7.js.map
1431
- //# sourceMappingURL=chunk-Y72FK3Y7.js.map
1429
+ // src/radial.ts
1430
+ var radial = (graph, opts = {}) => {
1431
+ const nodeGap = opts.nodeGap ?? DEFAULT_NODE_GAP;
1432
+ const rankGap = opts.rankGap ?? DEFAULT_RANK_GAP;
1433
+ const { roots, children } = forestOf(graph, "y");
1434
+ const blocks2 = subtreeBlocks(children, "y", nodeGap);
1435
+ const order2 = graphOrder(graph);
1436
+ const placed = /* @__PURE__ */ new Map();
1437
+ let top = 0;
1438
+ for (const root of roots) {
1439
+ const tree = mindMap(root, children, order2, blocks2, nodeGap, rankGap);
1440
+ for (const [id, p] of tree.at) placed.set(id, { x: p.x, y: p.y - tree.top + top });
1441
+ top += tree.bottom - tree.top + nodeGap;
1442
+ }
1443
+ return translated(graph, placed, pinnedSet(graph, opts), opts.tolerance);
1444
+ };
1445
+ function mindMap(root, children, order2, blocks2, nodeGap, rankGap) {
1446
+ const at = /* @__PURE__ */ new Map([[root.id, { x: -root.bounds.width / 2, y: -root.bounds.height / 2 }]]);
1447
+ let top = -root.bounds.height / 2;
1448
+ let bottom = root.bounds.height / 2;
1449
+ const [right, left] = sides(root, children, order2);
1450
+ for (const [sign2, branches] of [[1, right], [-1, left]]) {
1451
+ if (branches.length === 0) continue;
1452
+ const span = branches.reduce((sum, b) => sum + blocks2.span(b), 0) + (branches.length - 1) * nodeGap;
1453
+ const ys = /* @__PURE__ */ new Map();
1454
+ let cursor = -span / 2;
1455
+ for (const branch of branches) {
1456
+ blocks2.lay(branch, cursor, ys);
1457
+ cursor += blocks2.span(branch) + nodeGap;
1458
+ }
1459
+ top = Math.min(top, -span / 2);
1460
+ bottom = Math.max(bottom, span / 2);
1461
+ for (const [id, x] of sideColumns(branches, children, root.bounds.width / 2 + rankGap, rankGap, sign2)) {
1462
+ at.set(id, { x, y: ys.get(id) });
1463
+ }
1464
+ }
1465
+ return { at, top, bottom };
1466
+ }
1467
+ function sides(root, children, order2) {
1468
+ const weight = (node) => 1 + (children.get(node.id) ?? []).reduce((sum, k) => sum + weight(k), 0);
1469
+ const kids = children.get(root.id) ?? [];
1470
+ const half = root.bounds.width / 2;
1471
+ const mid = root.bounds.x + half;
1472
+ const standing = (k) => {
1473
+ const c = k.bounds.x + k.bounds.width / 2 - mid;
1474
+ return c > half ? 1 : c < -half ? -1 : 0;
1475
+ };
1476
+ const stands = new Map(kids.map((k) => [k, standing(k)]));
1477
+ const arranged = [...stands.values()].includes(1) && [...stands.values()].includes(-1);
1478
+ const right = /* @__PURE__ */ new Set();
1479
+ let r = 0;
1480
+ let l = 0;
1481
+ const dealt = arranged ? kids.filter((k) => stands.get(k) !== 0) : [];
1482
+ for (const k of dealt) {
1483
+ if (stands.get(k) === 1) {
1484
+ right.add(k);
1485
+ r += weight(k);
1486
+ } else l += weight(k);
1487
+ }
1488
+ for (const child of kids.filter((k) => !dealt.includes(k)).sort((a, b) => order2(a.id) - order2(b.id))) {
1489
+ const w = weight(child);
1490
+ if (r <= l) {
1491
+ right.add(child);
1492
+ r += w;
1493
+ } else l += w;
1494
+ }
1495
+ return [kids.filter((k) => right.has(k)), kids.filter((k) => !right.has(k))];
1496
+ }
1497
+ function sideColumns(branches, children, from, rankGap, sign2) {
1498
+ const rows = [];
1499
+ const visit = (node, depth) => {
1500
+ (rows[depth] ??= []).push(node);
1501
+ for (const kid of children.get(node.id) ?? []) visit(kid, depth + 1);
1502
+ };
1503
+ for (const branch of branches) visit(branch, 0);
1504
+ const xs = /* @__PURE__ */ new Map();
1505
+ let start = from;
1506
+ for (const row of rows) {
1507
+ const band = Math.max(...row.map((n) => n.bounds.width));
1508
+ for (const node of row) {
1509
+ const near = start + (band - node.bounds.width) / 2;
1510
+ xs.set(node.id, sign2 === 1 ? near : -near - node.bounds.width);
1511
+ }
1512
+ start += band + rankGap;
1513
+ }
1514
+ return xs;
1515
+ }
1516
+
1517
+ export { AVOID_DEFAULTS, DEFAULT_HOP_SIZE, HOPS_DOC_KEY, createAvoidRouter, edgeHops, placeLabels, radial, simplifyStops };
1518
+ //# sourceMappingURL=chunk-5VNPLOIX.js.map
1519
+ //# sourceMappingURL=chunk-5VNPLOIX.js.map