@chengchenccc/tui 0.1.1-rc.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.
- package/dist/autocomplete.d.ts +56 -0
- package/dist/autocomplete.d.ts.map +1 -0
- package/dist/autocomplete.js +647 -0
- package/dist/components/box.d.ts +22 -0
- package/dist/components/box.d.ts.map +1 -0
- package/dist/components/box.js +103 -0
- package/dist/components/card.d.ts +33 -0
- package/dist/components/card.d.ts.map +1 -0
- package/dist/components/card.js +49 -0
- package/dist/components/editor.d.ts +257 -0
- package/dist/components/editor.d.ts.map +1 -0
- package/dist/components/editor.js +1980 -0
- package/dist/components/input.d.ts +37 -0
- package/dist/components/input.d.ts.map +1 -0
- package/dist/components/input.js +389 -0
- package/dist/components/loader.d.ts +33 -0
- package/dist/components/loader.d.ts.map +1 -0
- package/dist/components/loader.js +100 -0
- package/dist/components/markdown.d.ts +108 -0
- package/dist/components/markdown.d.ts.map +1 -0
- package/dist/components/markdown.js +847 -0
- package/dist/components/markdown.test.d.ts +2 -0
- package/dist/components/markdown.test.d.ts.map +1 -0
- package/dist/components/markdown.test.js +81 -0
- package/dist/components/output-block.d.ts +44 -0
- package/dist/components/output-block.d.ts.map +1 -0
- package/dist/components/output-block.js +131 -0
- package/dist/components/select-list.d.ts +50 -0
- package/dist/components/select-list.d.ts.map +1 -0
- package/dist/components/select-list.js +166 -0
- package/dist/components/spacer.d.ts +12 -0
- package/dist/components/spacer.d.ts.map +1 -0
- package/dist/components/spacer.js +22 -0
- package/dist/components/statusline.d.ts +30 -0
- package/dist/components/statusline.d.ts.map +1 -0
- package/dist/components/statusline.js +46 -0
- package/dist/components/text.d.ts +19 -0
- package/dist/components/text.d.ts.map +1 -0
- package/dist/components/text.js +90 -0
- package/dist/components/truncated-text.d.ts +13 -0
- package/dist/components/truncated-text.d.ts.map +1 -0
- package/dist/components/truncated-text.js +50 -0
- package/dist/editor-component.d.ts +39 -0
- package/dist/editor-component.d.ts.map +1 -0
- package/dist/editor-component.js +1 -0
- package/dist/fuzzy.d.ts +16 -0
- package/dist/fuzzy.d.ts.map +1 -0
- package/dist/fuzzy.js +109 -0
- package/dist/index.d.ts +25 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +36 -0
- package/dist/keybindings.d.ts +193 -0
- package/dist/keybindings.d.ts.map +1 -0
- package/dist/keybindings.js +191 -0
- package/dist/keys.d.ts +184 -0
- package/dist/keys.d.ts.map +1 -0
- package/dist/keys.js +1191 -0
- package/dist/kill-ring.d.ts +28 -0
- package/dist/kill-ring.d.ts.map +1 -0
- package/dist/kill-ring.js +43 -0
- package/dist/mermaid.d.ts +23 -0
- package/dist/mermaid.d.ts.map +1 -0
- package/dist/mermaid.js +77 -0
- package/dist/mouse.d.ts +40 -0
- package/dist/mouse.d.ts.map +1 -0
- package/dist/mouse.js +39 -0
- package/dist/mouse.test.d.ts +2 -0
- package/dist/mouse.test.d.ts.map +1 -0
- package/dist/mouse.test.js +36 -0
- package/dist/native-modifiers.d.ts +3 -0
- package/dist/native-modifiers.d.ts.map +1 -0
- package/dist/native-modifiers.js +52 -0
- package/dist/stdin-buffer.d.ts +50 -0
- package/dist/stdin-buffer.d.ts.map +1 -0
- package/dist/stdin-buffer.js +360 -0
- package/dist/terminal-colors.d.ts +10 -0
- package/dist/terminal-colors.d.ts.map +1 -0
- package/dist/terminal-colors.js +58 -0
- package/dist/terminal-image.d.ts +90 -0
- package/dist/terminal-image.d.ts.map +1 -0
- package/dist/terminal-image.js +375 -0
- package/dist/terminal.d.ts +110 -0
- package/dist/terminal.d.ts.map +1 -0
- package/dist/terminal.js +432 -0
- package/dist/tui-scrollback.test.d.ts +2 -0
- package/dist/tui-scrollback.test.d.ts.map +1 -0
- package/dist/tui-scrollback.test.js +51 -0
- package/dist/tui.d.ts +330 -0
- package/dist/tui.d.ts.map +1 -0
- package/dist/tui.js +1568 -0
- package/dist/undo-stack.d.ts +17 -0
- package/dist/undo-stack.d.ts.map +1 -0
- package/dist/undo-stack.js +24 -0
- package/dist/utils.d.ts +85 -0
- package/dist/utils.d.ts.map +1 -0
- package/dist/utils.js +1066 -0
- package/dist/vendor/mermaid-ascii/ascii/ansi.d.ts +42 -0
- package/dist/vendor/mermaid-ascii/ascii/ansi.d.ts.map +1 -0
- package/dist/vendor/mermaid-ascii/ascii/ansi.js +361 -0
- package/dist/vendor/mermaid-ascii/ascii/canvas.d.ts +90 -0
- package/dist/vendor/mermaid-ascii/ascii/canvas.d.ts.map +1 -0
- package/dist/vendor/mermaid-ascii/ascii/canvas.js +414 -0
- package/dist/vendor/mermaid-ascii/ascii/class-diagram.d.ts +8 -0
- package/dist/vendor/mermaid-ascii/ascii/class-diagram.d.ts.map +1 -0
- package/dist/vendor/mermaid-ascii/ascii/class-diagram.js +623 -0
- package/dist/vendor/mermaid-ascii/ascii/converter.d.ts +13 -0
- package/dist/vendor/mermaid-ascii/ascii/converter.d.ts.map +1 -0
- package/dist/vendor/mermaid-ascii/ascii/converter.js +233 -0
- package/dist/vendor/mermaid-ascii/ascii/draw.d.ts +67 -0
- package/dist/vendor/mermaid-ascii/ascii/draw.d.ts.map +1 -0
- package/dist/vendor/mermaid-ascii/ascii/draw.js +1313 -0
- package/dist/vendor/mermaid-ascii/ascii/edge-bundling.d.ts +49 -0
- package/dist/vendor/mermaid-ascii/ascii/edge-bundling.d.ts.map +1 -0
- package/dist/vendor/mermaid-ascii/ascii/edge-bundling.js +289 -0
- package/dist/vendor/mermaid-ascii/ascii/edge-routing.d.ts +44 -0
- package/dist/vendor/mermaid-ascii/ascii/edge-routing.d.ts.map +1 -0
- package/dist/vendor/mermaid-ascii/ascii/edge-routing.js +302 -0
- package/dist/vendor/mermaid-ascii/ascii/er-diagram.d.ts +8 -0
- package/dist/vendor/mermaid-ascii/ascii/er-diagram.d.ts.map +1 -0
- package/dist/vendor/mermaid-ascii/ascii/er-diagram.js +380 -0
- package/dist/vendor/mermaid-ascii/ascii/grid.d.ts +57 -0
- package/dist/vendor/mermaid-ascii/ascii/grid.d.ts.map +1 -0
- package/dist/vendor/mermaid-ascii/ascii/grid.js +516 -0
- package/dist/vendor/mermaid-ascii/ascii/index.d.ts +66 -0
- package/dist/vendor/mermaid-ascii/ascii/index.d.ts.map +1 -0
- package/dist/vendor/mermaid-ascii/ascii/index.js +133 -0
- package/dist/vendor/mermaid-ascii/ascii/multiline-utils.d.ts +28 -0
- package/dist/vendor/mermaid-ascii/ascii/multiline-utils.d.ts.map +1 -0
- package/dist/vendor/mermaid-ascii/ascii/multiline-utils.js +60 -0
- package/dist/vendor/mermaid-ascii/ascii/pathfinder.d.ts +18 -0
- package/dist/vendor/mermaid-ascii/ascii/pathfinder.d.ts.map +1 -0
- package/dist/vendor/mermaid-ascii/ascii/pathfinder.js +224 -0
- package/dist/vendor/mermaid-ascii/ascii/sequence.d.ts +8 -0
- package/dist/vendor/mermaid-ascii/ascii/sequence.d.ts.map +1 -0
- package/dist/vendor/mermaid-ascii/ascii/sequence.js +416 -0
- package/dist/vendor/mermaid-ascii/ascii/shapes/circle.d.ts +12 -0
- package/dist/vendor/mermaid-ascii/ascii/shapes/circle.d.ts.map +1 -0
- package/dist/vendor/mermaid-ascii/ascii/shapes/circle.js +22 -0
- package/dist/vendor/mermaid-ascii/ascii/shapes/corners.d.ts +35 -0
- package/dist/vendor/mermaid-ascii/ascii/shapes/corners.d.ts.map +1 -0
- package/dist/vendor/mermaid-ascii/ascii/shapes/corners.js +91 -0
- package/dist/vendor/mermaid-ascii/ascii/shapes/diamond.d.ts +12 -0
- package/dist/vendor/mermaid-ascii/ascii/shapes/diamond.d.ts.map +1 -0
- package/dist/vendor/mermaid-ascii/ascii/shapes/diamond.js +22 -0
- package/dist/vendor/mermaid-ascii/ascii/shapes/hexagon.d.ts +12 -0
- package/dist/vendor/mermaid-ascii/ascii/shapes/hexagon.d.ts.map +1 -0
- package/dist/vendor/mermaid-ascii/ascii/shapes/hexagon.js +22 -0
- package/dist/vendor/mermaid-ascii/ascii/shapes/index.d.ts +27 -0
- package/dist/vendor/mermaid-ascii/ascii/shapes/index.d.ts.map +1 -0
- package/dist/vendor/mermaid-ascii/ascii/shapes/index.js +66 -0
- package/dist/vendor/mermaid-ascii/ascii/shapes/rectangle.d.ts +32 -0
- package/dist/vendor/mermaid-ascii/ascii/shapes/rectangle.d.ts.map +1 -0
- package/dist/vendor/mermaid-ascii/ascii/shapes/rectangle.js +149 -0
- package/dist/vendor/mermaid-ascii/ascii/shapes/rounded.d.ts +12 -0
- package/dist/vendor/mermaid-ascii/ascii/shapes/rounded.d.ts.map +1 -0
- package/dist/vendor/mermaid-ascii/ascii/shapes/rounded.js +22 -0
- package/dist/vendor/mermaid-ascii/ascii/shapes/special.d.ts +60 -0
- package/dist/vendor/mermaid-ascii/ascii/shapes/special.d.ts.map +1 -0
- package/dist/vendor/mermaid-ascii/ascii/shapes/special.js +253 -0
- package/dist/vendor/mermaid-ascii/ascii/shapes/stadium.d.ts +18 -0
- package/dist/vendor/mermaid-ascii/ascii/shapes/stadium.d.ts.map +1 -0
- package/dist/vendor/mermaid-ascii/ascii/shapes/stadium.js +103 -0
- package/dist/vendor/mermaid-ascii/ascii/shapes/state.d.ts +31 -0
- package/dist/vendor/mermaid-ascii/ascii/shapes/state.d.ts.map +1 -0
- package/dist/vendor/mermaid-ascii/ascii/shapes/state.js +167 -0
- package/dist/vendor/mermaid-ascii/ascii/shapes/types.d.ts +56 -0
- package/dist/vendor/mermaid-ascii/ascii/shapes/types.d.ts.map +1 -0
- package/dist/vendor/mermaid-ascii/ascii/shapes/types.js +4 -0
- package/dist/vendor/mermaid-ascii/ascii/types.d.ts +207 -0
- package/dist/vendor/mermaid-ascii/ascii/types.d.ts.map +1 -0
- package/dist/vendor/mermaid-ascii/ascii/types.js +39 -0
- package/dist/vendor/mermaid-ascii/ascii/validate.d.ts +52 -0
- package/dist/vendor/mermaid-ascii/ascii/validate.d.ts.map +1 -0
- package/dist/vendor/mermaid-ascii/ascii/validate.js +97 -0
- package/dist/vendor/mermaid-ascii/ascii/xychart.d.ts +3 -0
- package/dist/vendor/mermaid-ascii/ascii/xychart.d.ts.map +1 -0
- package/dist/vendor/mermaid-ascii/ascii/xychart.js +719 -0
- package/dist/vendor/mermaid-ascii/class/parser.d.ts +7 -0
- package/dist/vendor/mermaid-ascii/class/parser.d.ts.map +1 -0
- package/dist/vendor/mermaid-ascii/class/parser.js +265 -0
- package/dist/vendor/mermaid-ascii/class/types.d.ts +103 -0
- package/dist/vendor/mermaid-ascii/class/types.d.ts.map +1 -0
- package/dist/vendor/mermaid-ascii/class/types.js +7 -0
- package/dist/vendor/mermaid-ascii/er/parser.d.ts +7 -0
- package/dist/vendor/mermaid-ascii/er/parser.d.ts.map +1 -0
- package/dist/vendor/mermaid-ascii/er/parser.js +162 -0
- package/dist/vendor/mermaid-ascii/er/types.d.ts +77 -0
- package/dist/vendor/mermaid-ascii/er/types.d.ts.map +1 -0
- package/dist/vendor/mermaid-ascii/er/types.js +7 -0
- package/dist/vendor/mermaid-ascii/index.d.ts +2 -0
- package/dist/vendor/mermaid-ascii/index.d.ts.map +1 -0
- package/dist/vendor/mermaid-ascii/index.js +13 -0
- package/dist/vendor/mermaid-ascii/multiline-utils.d.ts +10 -0
- package/dist/vendor/mermaid-ascii/multiline-utils.d.ts.map +1 -0
- package/dist/vendor/mermaid-ascii/multiline-utils.js +29 -0
- package/dist/vendor/mermaid-ascii/parser.d.ts +8 -0
- package/dist/vendor/mermaid-ascii/parser.d.ts.map +1 -0
- package/dist/vendor/mermaid-ascii/parser.js +558 -0
- package/dist/vendor/mermaid-ascii/sequence/parser.d.ts +7 -0
- package/dist/vendor/mermaid-ascii/sequence/parser.d.ts.map +1 -0
- package/dist/vendor/mermaid-ascii/sequence/parser.js +182 -0
- package/dist/vendor/mermaid-ascii/sequence/types.d.ts +131 -0
- package/dist/vendor/mermaid-ascii/sequence/types.d.ts.map +1 -0
- package/dist/vendor/mermaid-ascii/sequence/types.js +7 -0
- package/dist/vendor/mermaid-ascii/text-metrics.d.ts +24 -0
- package/dist/vendor/mermaid-ascii/text-metrics.d.ts.map +1 -0
- package/dist/vendor/mermaid-ascii/text-metrics.js +69 -0
- package/dist/vendor/mermaid-ascii/types.d.ts +115 -0
- package/dist/vendor/mermaid-ascii/types.d.ts.map +1 -0
- package/dist/vendor/mermaid-ascii/types.js +4 -0
- package/dist/vendor/mermaid-ascii/xychart/colors.d.ts +26 -0
- package/dist/vendor/mermaid-ascii/xychart/colors.d.ts.map +1 -0
- package/dist/vendor/mermaid-ascii/xychart/colors.js +145 -0
- package/dist/vendor/mermaid-ascii/xychart/parser.d.ts +7 -0
- package/dist/vendor/mermaid-ascii/xychart/parser.d.ts.map +1 -0
- package/dist/vendor/mermaid-ascii/xychart/parser.js +105 -0
- package/dist/vendor/mermaid-ascii/xychart/types.d.ts +146 -0
- package/dist/vendor/mermaid-ascii/xychart/types.d.ts.map +1 -0
- package/dist/vendor/mermaid-ascii/xychart/types.js +8 -0
- package/dist/virtual-terminal.d.ts +80 -0
- package/dist/virtual-terminal.d.ts.map +1 -0
- package/dist/virtual-terminal.js +284 -0
- package/dist/word-navigation.d.ts +25 -0
- package/dist/word-navigation.d.ts.map +1 -0
- package/dist/word-navigation.js +97 -0
- package/package.json +38 -0
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import type { AsciiGraph, EdgeBundle, GridCoord } from './types.ts';
|
|
2
|
+
/**
|
|
3
|
+
* Analyze graph edges and create bundles for parallel links.
|
|
4
|
+
*
|
|
5
|
+
* Groups edges by:
|
|
6
|
+
* - Fan-in: Multiple edges sharing the same target (A & B --> C)
|
|
7
|
+
* - Fan-out: Multiple edges sharing the same source (A --> B & C)
|
|
8
|
+
*
|
|
9
|
+
* Only creates bundles when:
|
|
10
|
+
* - Graph direction is TD (top-down) - LR routing handles merging naturally
|
|
11
|
+
* - 2+ edges share the endpoint
|
|
12
|
+
* - All edges have the same style (solid/dotted/thick)
|
|
13
|
+
* - None of the edges have labels (labels would overlap at junction)
|
|
14
|
+
* - Edges are not self-loops
|
|
15
|
+
*
|
|
16
|
+
* @returns Array of bundles. Each edge can belong to at most one bundle.
|
|
17
|
+
*/
|
|
18
|
+
export declare function analyzeEdgeBundles(graph: AsciiGraph): EdgeBundle[];
|
|
19
|
+
/**
|
|
20
|
+
* Calculate the optimal junction point for a bundle.
|
|
21
|
+
*
|
|
22
|
+
* For fan-in (A & B --> C):
|
|
23
|
+
* - Junction is placed between the sources and the target
|
|
24
|
+
* - In TD: above the target, horizontally centered between sources
|
|
25
|
+
* - In LR: left of the target, vertically centered between sources
|
|
26
|
+
*
|
|
27
|
+
* For fan-out (A --> B & C):
|
|
28
|
+
* - Junction is placed between the source and the targets
|
|
29
|
+
* - In TD: below the source, horizontally centered between targets
|
|
30
|
+
* - In LR: right of the source, vertically centered between targets
|
|
31
|
+
*/
|
|
32
|
+
export declare function calculateJunctionPoint(graph: AsciiGraph, bundle: EdgeBundle): GridCoord;
|
|
33
|
+
/**
|
|
34
|
+
* Route all edges in a bundle through the junction point.
|
|
35
|
+
*
|
|
36
|
+
* For fan-in bundles:
|
|
37
|
+
* 1. Route each source → junction (stored in edge.pathToJunction)
|
|
38
|
+
* 2. Route junction → target (stored in bundle.sharedPath)
|
|
39
|
+
*
|
|
40
|
+
* For fan-out bundles:
|
|
41
|
+
* 1. Route source → junction (stored in bundle.sharedPath)
|
|
42
|
+
* 2. Route junction → each target (stored in edge.pathToJunction)
|
|
43
|
+
*/
|
|
44
|
+
export declare function routeBundledEdges(graph: AsciiGraph, bundle: EdgeBundle): void;
|
|
45
|
+
/**
|
|
46
|
+
* Process all bundles in a graph: calculate junction points and route edges.
|
|
47
|
+
*/
|
|
48
|
+
export declare function processBundles(graph: AsciiGraph): void;
|
|
49
|
+
//# sourceMappingURL=edge-bundling.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"edge-bundling.d.ts","sourceRoot":"","sources":["../../../../src/vendor/mermaid-ascii/ascii/edge-bundling.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EACV,UAAU,EAAwB,UAAU,EAAE,SAAS,EACxD,MAAM,YAAY,CAAA;AASnB;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,UAAU,GAAG,UAAU,EAAE,CAqFlE;AAuCD;;;;;;;;;;;;GAYG;AACH,wBAAgB,sBAAsB,CACpC,KAAK,EAAE,UAAU,EACjB,MAAM,EAAE,UAAU,GACjB,SAAS,CAkDX;AAMD;;;;;;;;;;GAUG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,UAAU,EAAE,MAAM,EAAE,UAAU,GAAG,IAAI,CAuE7E;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,UAAU,GAAG,IAAI,CAItD"}
|
|
@@ -0,0 +1,289 @@
|
|
|
1
|
+
// ============================================================================
|
|
2
|
+
// ASCII renderer — edge bundling for parallel links
|
|
3
|
+
//
|
|
4
|
+
// Analyzes edges to find parallel links (A & B --> C or A --> B & C) and
|
|
5
|
+
// groups them into bundles. Bundled edges share a visual junction point
|
|
6
|
+
// where they merge/split, creating cleaner diagrams.
|
|
7
|
+
//
|
|
8
|
+
// This module provides:
|
|
9
|
+
// - analyzeEdgeBundles(): Finds and creates bundles from graph edges
|
|
10
|
+
// - calculateJunctionPoint(): Computes optimal merge/split locations
|
|
11
|
+
// - routeBundledEdges(): Routes edges through junction points
|
|
12
|
+
// ============================================================================
|
|
13
|
+
import { Up, Down, Left, Right, Middle } from "./types.js";
|
|
14
|
+
import { getPath, mergePath } from "./pathfinder.js";
|
|
15
|
+
import { getNodeSubgraph } from "./grid.js";
|
|
16
|
+
// ============================================================================
|
|
17
|
+
// Bundle analysis
|
|
18
|
+
// ============================================================================
|
|
19
|
+
/**
|
|
20
|
+
* Analyze graph edges and create bundles for parallel links.
|
|
21
|
+
*
|
|
22
|
+
* Groups edges by:
|
|
23
|
+
* - Fan-in: Multiple edges sharing the same target (A & B --> C)
|
|
24
|
+
* - Fan-out: Multiple edges sharing the same source (A --> B & C)
|
|
25
|
+
*
|
|
26
|
+
* Only creates bundles when:
|
|
27
|
+
* - Graph direction is TD (top-down) - LR routing handles merging naturally
|
|
28
|
+
* - 2+ edges share the endpoint
|
|
29
|
+
* - All edges have the same style (solid/dotted/thick)
|
|
30
|
+
* - None of the edges have labels (labels would overlap at junction)
|
|
31
|
+
* - Edges are not self-loops
|
|
32
|
+
*
|
|
33
|
+
* @returns Array of bundles. Each edge can belong to at most one bundle.
|
|
34
|
+
*/
|
|
35
|
+
export function analyzeEdgeBundles(graph) {
|
|
36
|
+
// Only bundle in TD direction - LR routing handles merging naturally at corners
|
|
37
|
+
if (graph.config.graphDirection !== 'TD') {
|
|
38
|
+
return [];
|
|
39
|
+
}
|
|
40
|
+
const bundles = [];
|
|
41
|
+
const bundledEdges = new Set();
|
|
42
|
+
// Group edges by target (fan-in candidates)
|
|
43
|
+
const edgesByTarget = new Map();
|
|
44
|
+
for (const edge of graph.edges) {
|
|
45
|
+
// Skip self-loops
|
|
46
|
+
if (edge.from === edge.to)
|
|
47
|
+
continue;
|
|
48
|
+
const existing = edgesByTarget.get(edge.to) ?? [];
|
|
49
|
+
existing.push(edge);
|
|
50
|
+
edgesByTarget.set(edge.to, existing);
|
|
51
|
+
}
|
|
52
|
+
// Create fan-in bundles
|
|
53
|
+
for (const [target, edges] of edgesByTarget) {
|
|
54
|
+
if (edges.length < 2)
|
|
55
|
+
continue;
|
|
56
|
+
if (!canBundle(edges, graph))
|
|
57
|
+
continue;
|
|
58
|
+
// Check if all edges are already bundled
|
|
59
|
+
if (edges.some(e => bundledEdges.has(e)))
|
|
60
|
+
continue;
|
|
61
|
+
const bundle = {
|
|
62
|
+
type: 'fan-in',
|
|
63
|
+
edges: [...edges],
|
|
64
|
+
sharedNode: target,
|
|
65
|
+
otherNodes: edges.map(e => e.from),
|
|
66
|
+
junctionPoint: null,
|
|
67
|
+
sharedPath: [],
|
|
68
|
+
junctionDir: Middle,
|
|
69
|
+
sharedNodeDir: Middle,
|
|
70
|
+
};
|
|
71
|
+
// Mark edges as bundled
|
|
72
|
+
for (const edge of edges) {
|
|
73
|
+
edge.bundle = bundle;
|
|
74
|
+
bundledEdges.add(edge);
|
|
75
|
+
}
|
|
76
|
+
bundles.push(bundle);
|
|
77
|
+
}
|
|
78
|
+
// Group edges by source (fan-out candidates)
|
|
79
|
+
const edgesBySource = new Map();
|
|
80
|
+
for (const edge of graph.edges) {
|
|
81
|
+
// Skip self-loops and already bundled edges
|
|
82
|
+
if (edge.from === edge.to)
|
|
83
|
+
continue;
|
|
84
|
+
if (bundledEdges.has(edge))
|
|
85
|
+
continue;
|
|
86
|
+
const existing = edgesBySource.get(edge.from) ?? [];
|
|
87
|
+
existing.push(edge);
|
|
88
|
+
edgesBySource.set(edge.from, existing);
|
|
89
|
+
}
|
|
90
|
+
// Create fan-out bundles
|
|
91
|
+
for (const [source, edges] of edgesBySource) {
|
|
92
|
+
if (edges.length < 2)
|
|
93
|
+
continue;
|
|
94
|
+
if (!canBundle(edges, graph))
|
|
95
|
+
continue;
|
|
96
|
+
const bundle = {
|
|
97
|
+
type: 'fan-out',
|
|
98
|
+
edges: [...edges],
|
|
99
|
+
sharedNode: source,
|
|
100
|
+
otherNodes: edges.map(e => e.to),
|
|
101
|
+
junctionPoint: null,
|
|
102
|
+
sharedPath: [],
|
|
103
|
+
junctionDir: Middle,
|
|
104
|
+
sharedNodeDir: Middle,
|
|
105
|
+
};
|
|
106
|
+
// Mark edges as bundled
|
|
107
|
+
for (const edge of edges) {
|
|
108
|
+
edge.bundle = bundle;
|
|
109
|
+
bundledEdges.add(edge);
|
|
110
|
+
}
|
|
111
|
+
bundles.push(bundle);
|
|
112
|
+
}
|
|
113
|
+
return bundles;
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Check if a group of edges can be bundled together.
|
|
117
|
+
* Returns false if edges have different styles, any have labels,
|
|
118
|
+
* or if the edges span subgraph boundaries (which creates complex routing).
|
|
119
|
+
*/
|
|
120
|
+
function canBundle(edges, graph) {
|
|
121
|
+
if (edges.length < 2)
|
|
122
|
+
return false;
|
|
123
|
+
const firstStyle = edges[0].style;
|
|
124
|
+
const firstFromSg = getNodeSubgraph(graph, edges[0].from);
|
|
125
|
+
const firstToSg = getNodeSubgraph(graph, edges[0].to);
|
|
126
|
+
for (const edge of edges) {
|
|
127
|
+
// Different styles can't be bundled (would look confusing)
|
|
128
|
+
if (edge.style !== firstStyle)
|
|
129
|
+
return false;
|
|
130
|
+
// Edges with labels can't be bundled (labels would overlap at junction)
|
|
131
|
+
if (edge.text.length > 0)
|
|
132
|
+
return false;
|
|
133
|
+
// Don't bundle if edges span different subgraph boundaries
|
|
134
|
+
// (creates complex routing that doesn't look good)
|
|
135
|
+
const fromSg = getNodeSubgraph(graph, edge.from);
|
|
136
|
+
const toSg = getNodeSubgraph(graph, edge.to);
|
|
137
|
+
if (fromSg !== firstFromSg || toSg !== firstToSg)
|
|
138
|
+
return false;
|
|
139
|
+
// Don't bundle if source and target are in different subgraphs
|
|
140
|
+
// (cross-boundary edges have special routing needs)
|
|
141
|
+
if (fromSg !== toSg)
|
|
142
|
+
return false;
|
|
143
|
+
}
|
|
144
|
+
return true;
|
|
145
|
+
}
|
|
146
|
+
// ============================================================================
|
|
147
|
+
// Junction point calculation
|
|
148
|
+
// ============================================================================
|
|
149
|
+
/**
|
|
150
|
+
* Calculate the optimal junction point for a bundle.
|
|
151
|
+
*
|
|
152
|
+
* For fan-in (A & B --> C):
|
|
153
|
+
* - Junction is placed between the sources and the target
|
|
154
|
+
* - In TD: above the target, horizontally centered between sources
|
|
155
|
+
* - In LR: left of the target, vertically centered between sources
|
|
156
|
+
*
|
|
157
|
+
* For fan-out (A --> B & C):
|
|
158
|
+
* - Junction is placed between the source and the targets
|
|
159
|
+
* - In TD: below the source, horizontally centered between targets
|
|
160
|
+
* - In LR: right of the source, vertically centered between targets
|
|
161
|
+
*/
|
|
162
|
+
export function calculateJunctionPoint(graph, bundle) {
|
|
163
|
+
const dir = graph.config.graphDirection;
|
|
164
|
+
const sharedCoord = bundle.sharedNode.gridCoord;
|
|
165
|
+
const otherCoords = bundle.otherNodes.map(n => n.gridCoord);
|
|
166
|
+
if (bundle.type === 'fan-in') {
|
|
167
|
+
// Junction is BEFORE the shared target
|
|
168
|
+
// Calculate center of sources
|
|
169
|
+
const minX = Math.min(...otherCoords.map(c => c.x));
|
|
170
|
+
const maxX = Math.max(...otherCoords.map(c => c.x));
|
|
171
|
+
const minY = Math.min(...otherCoords.map(c => c.y));
|
|
172
|
+
const maxY = Math.max(...otherCoords.map(c => c.y));
|
|
173
|
+
if (dir === 'TD') {
|
|
174
|
+
// Junction above target, centered between sources
|
|
175
|
+
// Place it one row above the target's entry point
|
|
176
|
+
const junctionY = sharedCoord.y - 1;
|
|
177
|
+
// X is centered between sources, but clamped to shared node's X for alignment
|
|
178
|
+
const centerX = Math.floor((minX + maxX) / 2) + 1; // +1 for center of 3x3 block
|
|
179
|
+
const junctionX = sharedCoord.x + 1; // Align with target's center
|
|
180
|
+
return { x: junctionX, y: junctionY };
|
|
181
|
+
}
|
|
182
|
+
else {
|
|
183
|
+
// LR: Junction left of target, centered between sources
|
|
184
|
+
const junctionX = sharedCoord.x - 1;
|
|
185
|
+
const junctionY = sharedCoord.y + 1; // Align with target's center
|
|
186
|
+
return { x: junctionX, y: junctionY };
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
else {
|
|
190
|
+
// fan-out: Junction is AFTER the shared source
|
|
191
|
+
const minX = Math.min(...otherCoords.map(c => c.x));
|
|
192
|
+
const maxX = Math.max(...otherCoords.map(c => c.x));
|
|
193
|
+
const minY = Math.min(...otherCoords.map(c => c.y));
|
|
194
|
+
const maxY = Math.max(...otherCoords.map(c => c.y));
|
|
195
|
+
if (dir === 'TD') {
|
|
196
|
+
// Junction below source, will then split to targets
|
|
197
|
+
const junctionY = sharedCoord.y + 3; // Just below source's 3x3 block
|
|
198
|
+
const junctionX = sharedCoord.x + 1; // Align with source's center
|
|
199
|
+
return { x: junctionX, y: junctionY };
|
|
200
|
+
}
|
|
201
|
+
else {
|
|
202
|
+
// LR: Junction right of source
|
|
203
|
+
const junctionX = sharedCoord.x + 3;
|
|
204
|
+
const junctionY = sharedCoord.y + 1;
|
|
205
|
+
return { x: junctionX, y: junctionY };
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
// ============================================================================
|
|
210
|
+
// Bundled edge routing
|
|
211
|
+
// ============================================================================
|
|
212
|
+
/**
|
|
213
|
+
* Route all edges in a bundle through the junction point.
|
|
214
|
+
*
|
|
215
|
+
* For fan-in bundles:
|
|
216
|
+
* 1. Route each source → junction (stored in edge.pathToJunction)
|
|
217
|
+
* 2. Route junction → target (stored in bundle.sharedPath)
|
|
218
|
+
*
|
|
219
|
+
* For fan-out bundles:
|
|
220
|
+
* 1. Route source → junction (stored in bundle.sharedPath)
|
|
221
|
+
* 2. Route junction → each target (stored in edge.pathToJunction)
|
|
222
|
+
*/
|
|
223
|
+
export function routeBundledEdges(graph, bundle) {
|
|
224
|
+
const dir = graph.config.graphDirection;
|
|
225
|
+
// Calculate and store junction point
|
|
226
|
+
bundle.junctionPoint = calculateJunctionPoint(graph, bundle);
|
|
227
|
+
const junction = bundle.junctionPoint;
|
|
228
|
+
// Determine directions based on graph direction and bundle type
|
|
229
|
+
if (bundle.type === 'fan-in') {
|
|
230
|
+
// Sources converge to junction, then junction to target
|
|
231
|
+
bundle.junctionDir = dir === 'TD' ? Up : Left;
|
|
232
|
+
bundle.sharedNodeDir = dir === 'TD' ? Down : Right;
|
|
233
|
+
// Route junction → target (shared path)
|
|
234
|
+
const targetCoord = bundle.sharedNode.gridCoord;
|
|
235
|
+
const targetEntry = dir === 'TD'
|
|
236
|
+
? { x: targetCoord.x + 1, y: targetCoord.y } // Top center of target
|
|
237
|
+
: { x: targetCoord.x, y: targetCoord.y + 1 }; // Left center of target
|
|
238
|
+
const sharedPath = getPath(graph.grid, junction, targetEntry);
|
|
239
|
+
bundle.sharedPath = sharedPath ? mergePath(sharedPath) : [junction, targetEntry];
|
|
240
|
+
// Route each source → junction
|
|
241
|
+
for (const edge of bundle.edges) {
|
|
242
|
+
const sourceCoord = edge.from.gridCoord;
|
|
243
|
+
const sourceExit = dir === 'TD'
|
|
244
|
+
? { x: sourceCoord.x + 1, y: sourceCoord.y + 2 } // Bottom center of source
|
|
245
|
+
: { x: sourceCoord.x + 2, y: sourceCoord.y + 1 }; // Right center of source
|
|
246
|
+
const pathToJunction = getPath(graph.grid, sourceExit, junction);
|
|
247
|
+
edge.pathToJunction = pathToJunction ? mergePath(pathToJunction) : [sourceExit, junction];
|
|
248
|
+
// Set edge directions for proper drawing
|
|
249
|
+
edge.startDir = dir === 'TD' ? Down : Right;
|
|
250
|
+
edge.endDir = dir === 'TD' ? Up : Left;
|
|
251
|
+
// Build full path for grid size calculation: source → junction → target
|
|
252
|
+
edge.path = [...edge.pathToJunction, ...bundle.sharedPath.slice(1)];
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
else {
|
|
256
|
+
// fan-out: Source to junction, then junction splits to targets
|
|
257
|
+
bundle.junctionDir = dir === 'TD' ? Down : Right;
|
|
258
|
+
bundle.sharedNodeDir = dir === 'TD' ? Up : Left;
|
|
259
|
+
// Route source → junction (shared path)
|
|
260
|
+
const sourceCoord = bundle.sharedNode.gridCoord;
|
|
261
|
+
const sourceExit = dir === 'TD'
|
|
262
|
+
? { x: sourceCoord.x + 1, y: sourceCoord.y + 2 } // Bottom center of source
|
|
263
|
+
: { x: sourceCoord.x + 2, y: sourceCoord.y + 1 }; // Right center of source
|
|
264
|
+
const sharedPath = getPath(graph.grid, sourceExit, junction);
|
|
265
|
+
bundle.sharedPath = sharedPath ? mergePath(sharedPath) : [sourceExit, junction];
|
|
266
|
+
// Route junction → each target
|
|
267
|
+
for (const edge of bundle.edges) {
|
|
268
|
+
const targetCoord = edge.to.gridCoord;
|
|
269
|
+
const targetEntry = dir === 'TD'
|
|
270
|
+
? { x: targetCoord.x + 1, y: targetCoord.y } // Top center of target
|
|
271
|
+
: { x: targetCoord.x, y: targetCoord.y + 1 }; // Left center of target
|
|
272
|
+
const pathToJunction = getPath(graph.grid, junction, targetEntry);
|
|
273
|
+
edge.pathToJunction = pathToJunction ? mergePath(pathToJunction) : [junction, targetEntry];
|
|
274
|
+
// Set edge directions
|
|
275
|
+
edge.startDir = dir === 'TD' ? Down : Right;
|
|
276
|
+
edge.endDir = dir === 'TD' ? Up : Left;
|
|
277
|
+
// Build full path for grid size calculation: source → junction → target
|
|
278
|
+
edge.path = [...bundle.sharedPath, ...edge.pathToJunction.slice(1)];
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
/**
|
|
283
|
+
* Process all bundles in a graph: calculate junction points and route edges.
|
|
284
|
+
*/
|
|
285
|
+
export function processBundles(graph) {
|
|
286
|
+
for (const bundle of graph.bundles) {
|
|
287
|
+
routeBundledEdges(graph, bundle);
|
|
288
|
+
}
|
|
289
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import type { Direction, AsciiEdge, AsciiGraph } from './types.ts';
|
|
2
|
+
export declare function getOpposite(d: Direction): Direction;
|
|
3
|
+
/** Compare directions by value (not reference). */
|
|
4
|
+
export declare function dirEquals(a: Direction, b: Direction): boolean;
|
|
5
|
+
/**
|
|
6
|
+
* Determine 8-way direction from one coordinate to another.
|
|
7
|
+
* Uses the coordinate difference to pick one of 8 cardinal/ordinal directions.
|
|
8
|
+
*/
|
|
9
|
+
export declare function determineDirection(from: {
|
|
10
|
+
x: number;
|
|
11
|
+
y: number;
|
|
12
|
+
}, to: {
|
|
13
|
+
x: number;
|
|
14
|
+
y: number;
|
|
15
|
+
}): Direction;
|
|
16
|
+
/**
|
|
17
|
+
* Determine preferred and alternative start/end directions for an edge.
|
|
18
|
+
* Returns [preferredStart, preferredEnd, alternativeStart, alternativeEnd].
|
|
19
|
+
*
|
|
20
|
+
* The edge routing tries both pairs and picks the shorter path.
|
|
21
|
+
* Direction selection depends on relative node positions and graph direction (LR vs TD).
|
|
22
|
+
*/
|
|
23
|
+
export declare function determineStartAndEndDir(edge: AsciiEdge, graphDirection: string): [Direction, Direction, Direction, Direction];
|
|
24
|
+
/**
|
|
25
|
+
* Determine the path for an edge by trying two candidate routes (preferred + alternative)
|
|
26
|
+
* and picking the shorter one. Sets edge.path, edge.startDir, edge.endDir.
|
|
27
|
+
*
|
|
28
|
+
* When both A* paths fail (common for edges crossing subgraph boundaries), falls back
|
|
29
|
+
* to a direct path using the start/end points. This ensures edges always have a path
|
|
30
|
+
* for arrowhead rendering.
|
|
31
|
+
*
|
|
32
|
+
* Uses the effective direction for edge routing, respecting subgraph direction overrides
|
|
33
|
+
* when both source and target are in the same subgraph.
|
|
34
|
+
*/
|
|
35
|
+
export declare function determinePath(graph: AsciiGraph, edge: AsciiEdge): void;
|
|
36
|
+
/**
|
|
37
|
+
* Find the best line segment in an edge's path to place a label on.
|
|
38
|
+
* Prefers vertical segments for TD/BT graphs and horizontal for LR/RL to avoid
|
|
39
|
+
* label collisions when multiple edges share initial segments.
|
|
40
|
+
* Falls back to the widest segment if none are suitable.
|
|
41
|
+
* Also increases the column width at the label position to fit the text.
|
|
42
|
+
*/
|
|
43
|
+
export declare function determineLabelLine(graph: AsciiGraph, edge: AsciiEdge): void;
|
|
44
|
+
//# sourceMappingURL=edge-routing.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"edge-routing.d.ts","sourceRoot":"","sources":["../../../../src/vendor/mermaid-ascii/ascii/edge-routing.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAa,SAAS,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,YAAY,CAAA;AAa7E,wBAAgB,WAAW,CAAC,CAAC,EAAE,SAAS,GAAG,SAAS,CAUnD;AAED,mDAAmD;AACnD,wBAAgB,SAAS,CAAC,CAAC,EAAE,SAAS,EAAE,CAAC,EAAE,SAAS,GAAG,OAAO,CAE7D;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE;IAAE,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAA;CAAE,EAAE,EAAE,EAAE;IAAE,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,SAAS,CAU1G;AAYD;;;;;;GAMG;AACH,wBAAgB,uBAAuB,CACrC,IAAI,EAAE,SAAS,EACf,cAAc,EAAE,MAAM,GACrB,CAAC,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,CAAC,CAgE9C;AAMD;;;;;;;;;;GAUG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,UAAU,EAAE,IAAI,EAAE,SAAS,GAAG,IAAI,CA+DtE;AAED;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,UAAU,EAAE,IAAI,EAAE,SAAS,GAAG,IAAI,CA0D3E"}
|