nexus-shell 0.2.5 → 0.2.7
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/README.md +4 -0
- package/dist/components/graph/GraphCanvas.d.ts +15 -0
- package/dist/components/graph/GraphMiniMap.d.ts +83 -0
- package/dist/components/graph/NodePalette.d.ts +44 -3
- package/dist/components/graph/index.d.ts +3 -1
- package/dist/components/graph/useGraphLayout.d.ts +111 -0
- package/dist/index.d.ts +2 -1
- package/dist/lib/graph.d.ts +21 -0
- package/dist/lib/layout.d.ts +86 -0
- package/dist/nexus-shell.es.js +1747 -1392
- package/dist/nexus-shell.umd.js +1 -1
- package/dist/style.css +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -132,8 +132,12 @@ shell's own frame and keep every registration working.
|
|
|
132
132
|
| `GraphCanvas` | Infinite pannable, zoomable field for node-and-edge editing |
|
|
133
133
|
| `GraphNode` | Positioned, focusable node with edge ports |
|
|
134
134
|
| `GraphEdge` | Directed edge with bezier / smoothstep / straight routing |
|
|
135
|
+
| `GraphMiniMap` | Scaled graph overview with a viewport indicator |
|
|
135
136
|
| `NodePalette` | Drag-to-create and keyboard-to-create node types |
|
|
136
137
|
| `useGraphKeyboard` | Spatial keyboard navigation and editing for a graph |
|
|
138
|
+
| `useGraphLayout` | Auto layout engines, with a freeform escape for hand placement |
|
|
139
|
+
| `layeredLayout` | Layered tree layout in four directions; handles cycles |
|
|
140
|
+
| `gridLayout` | Uniform grid, ignoring edges |
|
|
137
141
|
| `UserProfile` | Avatar and identity widget |
|
|
138
142
|
|
|
139
143
|
## Theming
|
|
@@ -12,6 +12,11 @@ export interface GraphCanvasHandle {
|
|
|
12
12
|
zoomBy: (factor: number) => void;
|
|
13
13
|
/** Convert a client (page) point into graph space. */
|
|
14
14
|
clientToGraph: (client: IPoint) => IPoint;
|
|
15
|
+
/** The element's pixel size. A minimap needs this to draw its indicator. */
|
|
16
|
+
getSize: () => {
|
|
17
|
+
width: number;
|
|
18
|
+
height: number;
|
|
19
|
+
};
|
|
15
20
|
/** Move keyboard focus to the canvas. */
|
|
16
21
|
focus: () => void;
|
|
17
22
|
}
|
|
@@ -36,6 +41,16 @@ export interface GraphCanvasProps {
|
|
|
36
41
|
defaultViewport?: IViewport;
|
|
37
42
|
/** Called whenever pan or zoom changes, controlled or not. */
|
|
38
43
|
onViewportChange?: (viewport: IViewport) => void;
|
|
44
|
+
/**
|
|
45
|
+
* Called on mount and whenever the element resizes, with its pixel size.
|
|
46
|
+
*
|
|
47
|
+
* Pass this to a {@link GraphMiniMap} as `canvasSize` — the indicator cannot
|
|
48
|
+
* be drawn without knowing how much of the graph is on screen.
|
|
49
|
+
*/
|
|
50
|
+
onSizeChange?: (size: {
|
|
51
|
+
width: number;
|
|
52
|
+
height: number;
|
|
53
|
+
}) => void;
|
|
39
54
|
/**
|
|
40
55
|
* Called with a graph-space point when empty canvas is clicked. Use it to
|
|
41
56
|
* clear selection, or to place a node at the click.
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { IGraphNode, IViewport } from '../../lib/graph';
|
|
2
|
+
|
|
3
|
+
export interface GraphMiniMapProps {
|
|
4
|
+
/** The nodes to plot. Only position and size are read. */
|
|
5
|
+
nodes: IGraphNode[];
|
|
6
|
+
/** The canvas's current pan and zoom. */
|
|
7
|
+
viewport: IViewport;
|
|
8
|
+
/**
|
|
9
|
+
* Pixel size of the canvas the minimap mirrors. Get it from `GraphCanvas`'s
|
|
10
|
+
* `onSizeChange`; without it the viewport indicator can't be drawn.
|
|
11
|
+
*/
|
|
12
|
+
canvasSize: {
|
|
13
|
+
width: number;
|
|
14
|
+
height: number;
|
|
15
|
+
};
|
|
16
|
+
/**
|
|
17
|
+
* Called with a viewport that recentres the canvas. Omit it and the minimap
|
|
18
|
+
* becomes a read-only overview.
|
|
19
|
+
*/
|
|
20
|
+
onViewportChange?: (viewport: IViewport) => void;
|
|
21
|
+
/** Minimap width in pixels. Defaults to `180`. */
|
|
22
|
+
width?: number;
|
|
23
|
+
/** Minimap height in pixels. Defaults to `120`. */
|
|
24
|
+
height?: number;
|
|
25
|
+
/**
|
|
26
|
+
* Fill colour for a node, as a CSS colour or Tailwind class. Receives the
|
|
27
|
+
* node, so you can colour by `kind`. Defaults to the muted foreground.
|
|
28
|
+
*/
|
|
29
|
+
nodeColor?: (node: IGraphNode) => string;
|
|
30
|
+
/**
|
|
31
|
+
* Highlight these node ids — a selection, or search results. Drawn in the
|
|
32
|
+
* primary colour above the rest.
|
|
33
|
+
*/
|
|
34
|
+
highlightIds?: string[];
|
|
35
|
+
/** Padding around the plotted content, in minimap pixels. Defaults to `8`. */
|
|
36
|
+
padding?: number;
|
|
37
|
+
/** How far an arrow key pans, in graph units. Defaults to `80`. */
|
|
38
|
+
panDistance?: number;
|
|
39
|
+
/** Accessible label. Defaults to `"Graph minimap"`. */
|
|
40
|
+
'aria-label'?: string;
|
|
41
|
+
/** Extra classes merged onto the root element. */
|
|
42
|
+
className?: string;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* A scaled overview of the whole graph, with an indicator showing what the
|
|
46
|
+
* canvas is currently looking at.
|
|
47
|
+
*
|
|
48
|
+
* Click anywhere to jump there, drag to pan continuously, or focus it and use
|
|
49
|
+
* the arrow keys. The zoom level is never changed — a minimap answers "where am
|
|
50
|
+
* I", and changing scale on a click makes that answer harder to trust.
|
|
51
|
+
*
|
|
52
|
+
* The plotted extent is the union of the graph's bounds and the current
|
|
53
|
+
* viewport, so the indicator stays visible even when you have panned far away
|
|
54
|
+
* from every node. Without that, panning into empty space makes the minimap
|
|
55
|
+
* appear broken.
|
|
56
|
+
*
|
|
57
|
+
* Fully controlled: it reads `viewport` and reports where you want to go, but
|
|
58
|
+
* never moves the canvas itself.
|
|
59
|
+
*
|
|
60
|
+
* @example
|
|
61
|
+
* ```tsx
|
|
62
|
+
* const [viewport, setViewport] = useState(IDENTITY_VIEWPORT);
|
|
63
|
+
* const [size, setSize] = useState({ width: 0, height: 0 });
|
|
64
|
+
*
|
|
65
|
+
* <GraphCanvas
|
|
66
|
+
* viewport={viewport}
|
|
67
|
+
* onViewportChange={setViewport}
|
|
68
|
+
* onSizeChange={setSize}
|
|
69
|
+
* overlay={
|
|
70
|
+
* <GraphMiniMap
|
|
71
|
+
* nodes={nodes}
|
|
72
|
+
* viewport={viewport}
|
|
73
|
+
* canvasSize={size}
|
|
74
|
+
* onViewportChange={setViewport}
|
|
75
|
+
* className="absolute bottom-3 right-3"
|
|
76
|
+
* />
|
|
77
|
+
* }
|
|
78
|
+
* >
|
|
79
|
+
* …
|
|
80
|
+
* </GraphCanvas>
|
|
81
|
+
* ```
|
|
82
|
+
*/
|
|
83
|
+
export declare const GraphMiniMap: ({ nodes, viewport, canvasSize, onViewportChange, width, height, nodeColor, highlightIds, padding, panDistance, "aria-label": ariaLabel, className, }: GraphMiniMapProps) => import("react/jsx-runtime").JSX.Element;
|
|
@@ -2,6 +2,17 @@ import { default as React, ReactNode } from 'react';
|
|
|
2
2
|
|
|
3
3
|
/** The MIME type palette entries put their kind on during a drag. */
|
|
4
4
|
export declare const GRAPH_NODE_MIME = "application/x-nexus-graph-node";
|
|
5
|
+
/**
|
|
6
|
+
* How the palette lays its items out.
|
|
7
|
+
*
|
|
8
|
+
* - `horizontal` — a row, wrapping if it must.
|
|
9
|
+
* - `vertical` — a column.
|
|
10
|
+
* - `auto` — whichever fits the space the palette is given. See
|
|
11
|
+
* {@link NodePalette} for the rule.
|
|
12
|
+
*/
|
|
13
|
+
export type PaletteOrientation = 'horizontal' | 'vertical' | 'auto';
|
|
14
|
+
/** The orientation actually rendered, once `auto` has been resolved. */
|
|
15
|
+
export type ResolvedOrientation = Exclude<PaletteOrientation, 'auto'>;
|
|
5
16
|
/** An entry in a {@link NodePalette}. */
|
|
6
17
|
export interface INodePaletteItem {
|
|
7
18
|
/**
|
|
@@ -26,8 +37,21 @@ export interface NodePaletteProps {
|
|
|
26
37
|
onSelect?: (item: INodePaletteItem) => void;
|
|
27
38
|
/** Called when a drag starts, if you want to show a drop hint. */
|
|
28
39
|
onDragStart?: (item: INodePaletteItem) => void;
|
|
29
|
-
/**
|
|
30
|
-
|
|
40
|
+
/**
|
|
41
|
+
* Layout axis. Defaults to `"auto"`, which measures the available space and
|
|
42
|
+
* picks whichever axis fits.
|
|
43
|
+
*/
|
|
44
|
+
orientation?: PaletteOrientation;
|
|
45
|
+
/**
|
|
46
|
+
* Called when `auto` settles on an axis, and whenever it changes. Useful for
|
|
47
|
+
* adjusting surrounding layout to match.
|
|
48
|
+
*/
|
|
49
|
+
onOrientationChange?: (orientation: ResolvedOrientation) => void;
|
|
50
|
+
/**
|
|
51
|
+
* Hide labels and show icons only. Useful for a narrow rail; items keep their
|
|
52
|
+
* accessible name, so nothing is lost to a screen reader.
|
|
53
|
+
*/
|
|
54
|
+
iconOnly?: boolean;
|
|
31
55
|
/** Extra classes merged onto the root element. */
|
|
32
56
|
className?: string;
|
|
33
57
|
/** Accessible label for the group. Defaults to `"Node palette"`. */
|
|
@@ -44,6 +68,23 @@ export interface NodePaletteProps {
|
|
|
44
68
|
* Every item is a real button, so the palette is fully usable without a
|
|
45
69
|
* pointer — `onSelect` fires on click or Enter.
|
|
46
70
|
*
|
|
71
|
+
* ## Orientation
|
|
72
|
+
*
|
|
73
|
+
* `auto` (the default) measures the space the palette's container gives it and
|
|
74
|
+
* picks the axis that fits:
|
|
75
|
+
*
|
|
76
|
+
* 1. a row, if the items fit the available width;
|
|
77
|
+
* 2. otherwise a column, if they fit the available height;
|
|
78
|
+
* 3. otherwise a row that wraps.
|
|
79
|
+
*
|
|
80
|
+
* A container that shrink-wraps its content — an absolutely positioned overlay,
|
|
81
|
+
* say — offers no information about available space, so the palette measures
|
|
82
|
+
* the nearest ancestor that has a size of its own. That is what stops a
|
|
83
|
+
* vertical palette from narrowing its own container and then being unable to
|
|
84
|
+
* discover it has room to go horizontal again.
|
|
85
|
+
*
|
|
86
|
+
* Pass `horizontal` or `vertical` when you already know.
|
|
87
|
+
*
|
|
47
88
|
* @example
|
|
48
89
|
* ```tsx
|
|
49
90
|
* <GraphCanvas
|
|
@@ -60,7 +101,7 @@ export interface NodePaletteProps {
|
|
|
60
101
|
* />
|
|
61
102
|
* ```
|
|
62
103
|
*/
|
|
63
|
-
export declare const NodePalette: ({ items, onSelect, onDragStart,
|
|
104
|
+
export declare const NodePalette: ({ items, onSelect, onDragStart, orientation, onOrientationChange, iconOnly, className, "aria-label": ariaLabel, }: NodePaletteProps) => import("react/jsx-runtime").JSX.Element;
|
|
64
105
|
/**
|
|
65
106
|
* Read the node kind from a drop on the canvas, or `null` if the drag did not
|
|
66
107
|
* come from a {@link NodePalette}.
|
|
@@ -13,4 +13,6 @@ export { GraphCanvas, type GraphCanvasProps, type GraphCanvasHandle } from './Gr
|
|
|
13
13
|
export { GraphNode, type GraphNodeProps } from './GraphNode';
|
|
14
14
|
export { GraphEdge, GraphEdgeLayer, edgePath, type GraphEdgeProps, type GraphEdgeLayerProps, type EdgeRouting, } from './GraphEdge';
|
|
15
15
|
export { useGraphKeyboard, DEFAULT_GRAPH_KEYS, type UseGraphKeyboardOptions, type UseGraphKeyboardResult, type GraphKeyboardActions, } from './useGraphKeyboard';
|
|
16
|
-
export {
|
|
16
|
+
export { GraphMiniMap, type GraphMiniMapProps } from './GraphMiniMap';
|
|
17
|
+
export { useGraphLayout, FREEFORM, type LayoutMode, type UseGraphLayoutOptions, type UseGraphLayoutResult, } from './useGraphLayout';
|
|
18
|
+
export { NodePalette, readPaletteDrag, GRAPH_NODE_MIME, type NodePaletteProps, type INodePaletteItem, type PaletteOrientation, type ResolvedOrientation, } from './NodePalette';
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import { GraphLayout } from '../../lib/layout';
|
|
2
|
+
import { IGraphEdge, IGraphNode, IPoint } from '../../lib/graph';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* The mode in which positions are hand-held rather than computed.
|
|
6
|
+
*
|
|
7
|
+
* Reserved: a layout may not be registered under this name.
|
|
8
|
+
*/
|
|
9
|
+
export declare const FREEFORM: "freeform";
|
|
10
|
+
/** The active layout's name, or {@link FREEFORM}. */
|
|
11
|
+
export type LayoutMode = typeof FREEFORM | (string & {});
|
|
12
|
+
export interface UseGraphLayoutOptions {
|
|
13
|
+
/** Your nodes. Positions here are the hand-placed ones. */
|
|
14
|
+
nodes: IGraphNode[];
|
|
15
|
+
/** Your edges. Layouts that ignore structure ignore these. */
|
|
16
|
+
edges: IGraphEdge[];
|
|
17
|
+
/**
|
|
18
|
+
* Named layouts to offer. Defaults to the bundled `vertical`, `horizontal`
|
|
19
|
+
* and `grid`. Spread it to add your own.
|
|
20
|
+
*/
|
|
21
|
+
layouts?: Record<string, GraphLayout>;
|
|
22
|
+
/** Take control of the mode. */
|
|
23
|
+
mode?: LayoutMode;
|
|
24
|
+
/** Starting mode when uncontrolled. Defaults to {@link FREEFORM}. */
|
|
25
|
+
defaultMode?: LayoutMode;
|
|
26
|
+
/** Called whenever the mode changes, including the escape on drag. */
|
|
27
|
+
onModeChange?: (mode: LayoutMode) => void;
|
|
28
|
+
/**
|
|
29
|
+
* Called when a node is moved by hand, so you can persist the position.
|
|
30
|
+
*
|
|
31
|
+
* Without it, a drag under an auto layout still escapes to freeform but the
|
|
32
|
+
* node snaps back to where it was — the engine no longer places it, and
|
|
33
|
+
* nothing recorded where the pointer left it.
|
|
34
|
+
*/
|
|
35
|
+
onNodeMove?: (id: string, position: IPoint) => void;
|
|
36
|
+
/**
|
|
37
|
+
* Dragging a node while an auto layout is active switches to freeform,
|
|
38
|
+
* keeping the arrangement as it stood. Defaults to `true`.
|
|
39
|
+
*
|
|
40
|
+
* Turn it off for a graph whose positions are entirely derived — a
|
|
41
|
+
* visualisation rather than an editor — where a stray drag should be ignored.
|
|
42
|
+
*/
|
|
43
|
+
escapeOnDrag?: boolean;
|
|
44
|
+
}
|
|
45
|
+
export interface UseGraphLayoutResult {
|
|
46
|
+
/**
|
|
47
|
+
* Nodes to render: positioned by the active layout, or exactly your nodes in
|
|
48
|
+
* freeform. Pass these to `GraphNode`, not your originals.
|
|
49
|
+
*/
|
|
50
|
+
nodes: IGraphNode[];
|
|
51
|
+
/** The active mode. */
|
|
52
|
+
mode: LayoutMode;
|
|
53
|
+
setMode: (mode: LayoutMode) => void;
|
|
54
|
+
/** Names of the available layouts, for building a picker. */
|
|
55
|
+
available: string[];
|
|
56
|
+
/** Whether a layout is currently placing nodes. */
|
|
57
|
+
isAuto: boolean;
|
|
58
|
+
/**
|
|
59
|
+
* Wire to `GraphNode`'s `onMove`. Records the position and, under an auto
|
|
60
|
+
* layout, escapes to freeform so the drag actually takes effect.
|
|
61
|
+
*/
|
|
62
|
+
onMove: (id: string, position: IPoint) => void;
|
|
63
|
+
/**
|
|
64
|
+
* Positions from the active layout, applied to your nodes and returned for
|
|
65
|
+
* you to persist. Use it to "bake in" an arrangement before switching to
|
|
66
|
+
* freeform, so hand editing starts from the laid-out positions rather than
|
|
67
|
+
* from wherever the nodes previously sat.
|
|
68
|
+
*/
|
|
69
|
+
bake: () => IGraphNode[];
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Apply a layout engine to a graph, with an escape hatch to hand placement.
|
|
73
|
+
*
|
|
74
|
+
* Two kinds of mode:
|
|
75
|
+
*
|
|
76
|
+
* - **An auto layout** — positions come from the engine. Your nodes' own
|
|
77
|
+
* positions are ignored while it is active, but never overwritten, so
|
|
78
|
+
* switching back to freeform restores the arrangement you had.
|
|
79
|
+
* - **`freeform`** — positions are yours, exactly as stored.
|
|
80
|
+
*
|
|
81
|
+
* Dragging a node under an auto layout escapes to freeform rather than fighting
|
|
82
|
+
* the engine. That is the behaviour that makes auto layout usable: you can
|
|
83
|
+
* always grab a node, and the graph stops rearranging itself the moment you do.
|
|
84
|
+
*
|
|
85
|
+
* The hook derives positions and reports intent; it owns no node data and
|
|
86
|
+
* mutates nothing.
|
|
87
|
+
*
|
|
88
|
+
* @example
|
|
89
|
+
* ```tsx
|
|
90
|
+
* const layout = useGraphLayout({
|
|
91
|
+
* nodes,
|
|
92
|
+
* edges,
|
|
93
|
+
* defaultMode: 'vertical',
|
|
94
|
+
* onNodeMove: (id, position) => setNodes(move(nodes, id, position)),
|
|
95
|
+
* });
|
|
96
|
+
*
|
|
97
|
+
* <GraphCanvas>
|
|
98
|
+
* {layout.nodes.map((node) => (
|
|
99
|
+
* <GraphNode key={node.id} node={node} onMove={layout.onMove}>
|
|
100
|
+
* {label(node)}
|
|
101
|
+
* </GraphNode>
|
|
102
|
+
* ))}
|
|
103
|
+
* </GraphCanvas>
|
|
104
|
+
*
|
|
105
|
+
* // A picker is a few lines of your own UI:
|
|
106
|
+
* {[FREEFORM, ...layout.available].map((mode) => (
|
|
107
|
+
* <button key={mode} onClick={() => layout.setMode(mode)}>{mode}</button>
|
|
108
|
+
* ))}
|
|
109
|
+
* ```
|
|
110
|
+
*/
|
|
111
|
+
export declare const useGraphLayout: ({ nodes, edges, layouts, mode: controlledMode, defaultMode, onModeChange, onNodeMove, escapeOnDrag, }: UseGraphLayoutOptions) => UseGraphLayoutResult;
|
package/dist/index.d.ts
CHANGED
|
@@ -57,6 +57,7 @@ export { ThemeSwitcher, type ThemeSwitcherProps, type IThemeOption, DEFAULT_THEM
|
|
|
57
57
|
export { TreeWidget, type TreeWidgetProps, type ITreeNode, type ITreeAction, type ITreeContext } from './components/widgets/TreeWidget';
|
|
58
58
|
export { UserProfile, type UserProfileProps, type IUserProfile, type IUserProfileAction } from './components/widgets/UserProfile';
|
|
59
59
|
export * from './components/graph';
|
|
60
|
-
export {
|
|
60
|
+
export { BUILT_IN_LAYOUTS, gridLayout, layeredLayout, type GraphLayout, type GridLayoutOptions, type LayeredLayoutOptions, type LayoutDirection, } from './lib/layout';
|
|
61
|
+
export { DEFAULT_NODE_SIZE, IDENTITY_VIEWPORT, clampScale, edgesOf, findNeighbour, fitViewport, graphBounds, isConnected, nextId, nodeRect, placeRelativeTo, portPoint, rectCenter, removeNode, resolvePorts, toGraphSpace, toScreenSpace, unionRect, viewportRect, centerOn, zoomAt, type Direction, type GraphPort, type IGraphEdge, type IGraphNode, type IPoint, type IRect, type IViewport, } from './lib/graph';
|
|
61
62
|
export { cn } from './lib/cn';
|
|
62
63
|
export { BUNDLED_THEMES, BUNDLED_THEME_CLASSES, themeClass, type IBundledTheme, type BundledThemeId, } from './lib/themes';
|
package/dist/lib/graph.d.ts
CHANGED
|
@@ -102,6 +102,27 @@ export declare const resolvePorts: (from: IRect, to: IRect) => {
|
|
|
102
102
|
* Used to fit the viewport to the graph.
|
|
103
103
|
*/
|
|
104
104
|
export declare const graphBounds: (nodes: IGraphNode[]) => IRect | null;
|
|
105
|
+
/**
|
|
106
|
+
* The region of graph space currently visible in an element of the given size.
|
|
107
|
+
*
|
|
108
|
+
* This is what a minimap draws as its viewport indicator, and what a culling
|
|
109
|
+
* pass would test against.
|
|
110
|
+
*/
|
|
111
|
+
export declare const viewportRect: (viewport: IViewport, size: {
|
|
112
|
+
width: number;
|
|
113
|
+
height: number;
|
|
114
|
+
}) => IRect;
|
|
115
|
+
/**
|
|
116
|
+
* A viewport that puts a graph-space point at the centre of the element,
|
|
117
|
+
* keeping the current zoom. Used for jumping somewhere from a minimap or a
|
|
118
|
+
* search result.
|
|
119
|
+
*/
|
|
120
|
+
export declare const centerOn: (point: IPoint, size: {
|
|
121
|
+
width: number;
|
|
122
|
+
height: number;
|
|
123
|
+
}, scale: number) => IViewport;
|
|
124
|
+
/** The smallest rectangle containing both inputs. */
|
|
125
|
+
export declare const unionRect: (a: IRect, b: IRect) => IRect;
|
|
105
126
|
/** A viewport that fits `nodes` inside a element of the given size. */
|
|
106
127
|
export declare const fitViewport: (nodes: IGraphNode[], size: {
|
|
107
128
|
width: number;
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { IGraphEdge, IGraphNode, IPoint } from './graph';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Graph layout engines.
|
|
5
|
+
*
|
|
6
|
+
* A layout is a pure function from a graph to repositioned nodes. It never
|
|
7
|
+
* mutates, never renders, and knows nothing about React — which makes each one
|
|
8
|
+
* testable in isolation and lets an application supply its own.
|
|
9
|
+
*
|
|
10
|
+
* ```ts
|
|
11
|
+
* const positioned = layeredLayout({ direction: 'right' })(nodes, edges);
|
|
12
|
+
* ```
|
|
13
|
+
*
|
|
14
|
+
* See {@link useGraphLayout} for applying one to a live graph, including the
|
|
15
|
+
* freeform mode that lets a hand-placed node escape the engine.
|
|
16
|
+
*/
|
|
17
|
+
/** Repositions a graph. Must be pure: same input, same output, no mutation. */
|
|
18
|
+
export type GraphLayout = (nodes: IGraphNode[], edges: IGraphEdge[]) => IGraphNode[];
|
|
19
|
+
/** Which way a layered layout flows. */
|
|
20
|
+
export type LayoutDirection = 'down' | 'up' | 'right' | 'left';
|
|
21
|
+
export interface LayeredLayoutOptions {
|
|
22
|
+
/** Flow direction. Defaults to `"down"`. */
|
|
23
|
+
direction?: LayoutDirection;
|
|
24
|
+
/** Gap between siblings within a layer, in graph units. Defaults to `48`. */
|
|
25
|
+
nodeSpacing?: number;
|
|
26
|
+
/** Gap between layers, in graph units. Defaults to `96`. */
|
|
27
|
+
layerSpacing?: number;
|
|
28
|
+
/** Top-left of the laid-out block. Defaults to the origin. */
|
|
29
|
+
origin?: IPoint;
|
|
30
|
+
/**
|
|
31
|
+
* How siblings line up across a layer. `center` reads best for trees;
|
|
32
|
+
* `start` keeps a ragged left edge, which suits deep hierarchies.
|
|
33
|
+
* Defaults to `"center"`.
|
|
34
|
+
*/
|
|
35
|
+
align?: 'center' | 'start';
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* A layered (Sugiyama-style) tree layout.
|
|
39
|
+
*
|
|
40
|
+
* Nodes are grouped into layers by graph depth, then spread along the
|
|
41
|
+
* cross-axis within each layer. Real node sizes are used, so mixed-size nodes
|
|
42
|
+
* don't overlap — a fixed step would.
|
|
43
|
+
*
|
|
44
|
+
* Handles cycles and disconnected components without dropping nodes.
|
|
45
|
+
*
|
|
46
|
+
* @example
|
|
47
|
+
* ```ts
|
|
48
|
+
* const layout = layeredLayout({ direction: 'right', layerSpacing: 140 });
|
|
49
|
+
* setNodes(layout(nodes, edges));
|
|
50
|
+
* ```
|
|
51
|
+
*/
|
|
52
|
+
export declare const layeredLayout: ({ direction, nodeSpacing, layerSpacing, origin, align, }?: LayeredLayoutOptions) => GraphLayout;
|
|
53
|
+
export interface GridLayoutOptions {
|
|
54
|
+
/**
|
|
55
|
+
* Number of columns. Defaults to a square-ish grid, which keeps a large
|
|
56
|
+
* unstructured set roughly as wide as it is tall.
|
|
57
|
+
*/
|
|
58
|
+
columns?: number;
|
|
59
|
+
/** Horizontal gap between cells. Defaults to `48`. */
|
|
60
|
+
spacingX?: number;
|
|
61
|
+
/** Vertical gap between cells. Defaults to `48`. */
|
|
62
|
+
spacingY?: number;
|
|
63
|
+
/** Top-left of the grid. Defaults to the origin. */
|
|
64
|
+
origin?: IPoint;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* A uniform grid, ignoring edges entirely.
|
|
68
|
+
*
|
|
69
|
+
* Useful for a set with no meaningful hierarchy, or as a reset before hand
|
|
70
|
+
* arranging. Column widths and row heights come from the largest node in each,
|
|
71
|
+
* so mixed sizes stay aligned.
|
|
72
|
+
*
|
|
73
|
+
* @example
|
|
74
|
+
* ```ts
|
|
75
|
+
* setNodes(gridLayout({ columns: 4 })(nodes, edges));
|
|
76
|
+
* ```
|
|
77
|
+
*/
|
|
78
|
+
export declare const gridLayout: ({ columns, spacingX, spacingY, origin, }?: GridLayoutOptions) => GraphLayout;
|
|
79
|
+
/**
|
|
80
|
+
* The layouts bundled with the library, ready to pass to
|
|
81
|
+
* {@link useGraphLayout}.
|
|
82
|
+
*
|
|
83
|
+
* Spread it and add your own, or ignore it and supply a different set —
|
|
84
|
+
* `useGraphLayout` takes any `Record<string, GraphLayout>`.
|
|
85
|
+
*/
|
|
86
|
+
export declare const BUILT_IN_LAYOUTS: Record<string, GraphLayout>;
|