nexus-shell 0.2.6 → 0.2.8
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 +3 -0
- package/dist/components/graph/index.d.ts +1 -0
- package/dist/components/graph/useGraphLayout.d.ts +111 -0
- package/dist/index.d.ts +1 -0
- package/dist/lib/layout.d.ts +86 -0
- package/dist/nexus-shell.es.js +1472 -1328
- package/dist/nexus-shell.umd.js +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -135,6 +135,9 @@ shell's own frame and keep every registration working.
|
|
|
135
135
|
| `GraphMiniMap` | Scaled graph overview with a viewport indicator |
|
|
136
136
|
| `NodePalette` | Drag-to-create and keyboard-to-create node types |
|
|
137
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 |
|
|
138
141
|
| `UserProfile` | Avatar and identity widget |
|
|
139
142
|
|
|
140
143
|
## Theming
|
|
@@ -14,4 +14,5 @@ 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
16
|
export { GraphMiniMap, type GraphMiniMapProps } from './GraphMiniMap';
|
|
17
|
+
export { useGraphLayout, FREEFORM, type LayoutMode, type UseGraphLayoutOptions, type UseGraphLayoutResult, } from './useGraphLayout';
|
|
17
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 { BUILT_IN_LAYOUTS, gridLayout, layeredLayout, type GraphLayout, type GridLayoutOptions, type LayeredLayoutOptions, type LayoutDirection, } from './lib/layout';
|
|
60
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';
|
|
@@ -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>;
|