react-beauti-graph 0.0.0-stage → 1.3.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.
@@ -0,0 +1,244 @@
1
+ import type { FC } from 'react';
2
+ import cytoscape from 'cytoscape';
3
+ import type { StylesheetJson } from 'cytoscape';
4
+ export * from './default_setting.cjs';
5
+ export declare const REPORT_NODE = "node[class = \"macromolecule\"]";
6
+ /** Group (folder box) names mapped to the names of the reports inside them */
7
+ export type NodeGroups = Record<string, string[]>;
8
+ /** Arrows: [source, target] */
9
+ export type Connections = [string, string][];
10
+ /** Layout grid: one list of report ids per row */
11
+ export type Layout = string[][];
12
+ /** Data of a graph element (a group box, a report or an arrow) */
13
+ export interface ElementData {
14
+ id: string;
15
+ class?: string;
16
+ label?: string;
17
+ rawLabel?: string;
18
+ displayLabel?: string;
19
+ group?: string | null;
20
+ parent?: string | undefined;
21
+ source?: string;
22
+ target?: string;
23
+ graphLabel?: string | undefined;
24
+ }
25
+ /** A Cytoscape element as built by buildGraph */
26
+ export interface GraphElement {
27
+ data: ElementData;
28
+ classes?: string;
29
+ }
30
+ /** Grid placement options of the layout */
31
+ export interface LayoutOptions {
32
+ startX?: number | undefined;
33
+ startY?: number | undefined;
34
+ offsetX?: number | undefined;
35
+ offsetY?: number | undefined;
36
+ base?: number | undefined;
37
+ }
38
+ /** A report listed in a group's details: its id, name and group */
39
+ export interface NodeRef {
40
+ id: string;
41
+ name: string;
42
+ group: string | null;
43
+ }
44
+ /** Details of a report shown in the side panel */
45
+ export interface NodeInfo extends NodeRef {
46
+ parents: NodeRef[];
47
+ children: NodeRef[];
48
+ }
49
+ /**
50
+ * Size of a report box: exactly the label plus a little padding.
51
+ * @param {string|undefined} label - The node label text
52
+ * @param {number} [fontSize] - Font size of the label in px
53
+ * @returns {{width: number, height: number}} Box size in px
54
+ */
55
+ export declare function getNodeSize(label: string | undefined, fontSize?: number): {
56
+ width: number;
57
+ height: number;
58
+ };
59
+ /**
60
+ * Compares names alphabetically, case-insensitive; numeric so "n2" comes before "n10".
61
+ * @param {string} a
62
+ * @param {string} b
63
+ * @returns {number}
64
+ */
65
+ export declare function compareNames(a: string, b: string): number;
66
+ /**
67
+ * Renames duplicate node IDs in layout to make them unique.
68
+ * Appends "(n)" suffix when duplicates are detected.
69
+ * @param {string[][]} layout - 2D array of node IDs arranged in rows/columns
70
+ * @returns {string[][]} Layout with renamed duplicates
71
+ */
72
+ export declare function uniquifyLayout(layout?: Layout): Layout;
73
+ /**
74
+ * Positions nodes in the Cytoscape graph based on layout specification.
75
+ * Handles missing/renamed nodes gracefully with fallbacks.
76
+ * @param {cytoscape.Core} cy - Cytoscape instance
77
+ * @param {string[][]} rows - 2D layout array with node IDs
78
+ * @param {Object} opts - Layout options (startX, startY, offsetX, offsetY, base)
79
+ */
80
+ export declare function applyLayout(cy: cytoscape.Core, rows: Layout, opts?: LayoutOptions): void;
81
+ /**
82
+ * Generates a unique ID by appending a counter suffix if needed.
83
+ * @param {string} base - Base ID string
84
+ * @param {Set<string>} taken - Set of already-used IDs (the new ID is added to it)
85
+ * @returns {string} Unique ID
86
+ */
87
+ export declare function uniqueId(base: string, taken: Set<string>): string;
88
+ /**
89
+ * Builds a layout from the groups, used when no layout is given.
90
+ * Each group starts a new row and fills rows of at most `columns` reports
91
+ * (group order, then report order); reports in no group come last.
92
+ * Copies of a report in several groups ("id(1)", ...) sit in their own group.
93
+ * @param {Object[]} elements - Cytoscape elements from buildGraph
94
+ * @param {number} [columns] - Maximum reports per row
95
+ * @returns {string[][]} Layout rows of node IDs
96
+ */
97
+ export declare function layoutFromFolders(elements: GraphElement[], columns?: number): Layout;
98
+ /**
99
+ * Builds the Cytoscape elements from groups, edges and extra node IDs.
100
+ * Folders become compound nodes (FOLDER_CLASS); every report becomes a
101
+ * REPORT_CLASS node. A report listed in several groups gets one copy per
102
+ * group ("id", "id(1)", ...); edges connect to the first copy.
103
+ * @param {Object<string, string[]>} node_groups - Mapping of group names to child IDs
104
+ * @param {Array<[string, string]>} direct_node_connections - Array of [source, target] edge pairs
105
+ * @param {string[]} extraIds - Other node IDs to create even without edges (e.g. from the layout)
106
+ * @returns {Object[]} Cytoscape elements array
107
+ */
108
+ export declare function buildGraph(node_groups?: NodeGroups, direct_node_connections?: Connections, extraIds?: string[]): GraphElement[];
109
+ /**
110
+ * Elements to draw for the current toggles: node label with or without
111
+ * the group, and groups shown or hidden.
112
+ * @param {Object[]} allElements - Output of buildGraph
113
+ * @param {boolean} showFolders - Keep the group (compartment) nodes
114
+ * @param {boolean} showGroupInLabel - Label reports "id (Group)" instead of "id"
115
+ * @returns {Object[]} Fresh element copies, safe to hand to a new Cytoscape instance
116
+ */
117
+ export declare function getVisibleElements(allElements: GraphElement[], showFolders: boolean, showGroupInLabel: boolean): GraphElement[];
118
+ /**
119
+ * Collects the details shown in the side panel for a report node.
120
+ * Parents point to the node, children are pointed to by it;
121
+ * a two-way edge makes the other node both a parent and a child.
122
+ * With allLevels, the lists hold the whole chains instead: the parents of the parents, ...
123
+ * and the children of the children, ... (the node itself is left out).
124
+ * @param {cytoscape.NodeSingular} node - The double-clicked node
125
+ * @param {boolean} [allLevels] - Every level of parents and children, not just the first
126
+ * @returns {{id: string, name: string, group: string|null, parents: Object[], children: Object[]}}
127
+ */
128
+ export declare function getNodeInfo(node: cytoscape.NodeSingular, allLevels?: boolean): NodeInfo;
129
+ /**
130
+ * Follows the edges from a node to collect its whole chain of parents
131
+ * (nodes pointing to it, their parents, ...) or children. A two-way edge
132
+ * counts in both directions, as in getNodeInfo.
133
+ * @param {cytoscape.NodeSingular} start - The tracked node
134
+ * @param {'parents'|'children'} direction - Which way to follow the edges
135
+ * @returns {cytoscape.Collection} The start node plus every node and edge on the chain
136
+ */
137
+ export declare function getTrackedElements(start: cytoscape.NodeSingular, direction: 'parents' | 'children'): cytoscape.Collection;
138
+ /**
139
+ * The elements to hide for the reports unchecked in "Node to Display": those reports
140
+ * (Cytoscape then hides their edges too) and the groups left with no visible report.
141
+ * @param {cytoscape.Core} cy - Cytoscape instance
142
+ * @param {Set<string>} hiddenIds - IDs of the reports to hide
143
+ * @returns {cytoscape.Collection} Elements to hide
144
+ */
145
+ export declare function getHiddenElements(cy: cytoscape.Core, hiddenIds: Set<string>): cytoscape.Collection;
146
+ /**
147
+ * Formats node details as plain text for the clipboard, matching the side panel:
148
+ * the group and the parent/child lists appear only when not empty.
149
+ * @param {ReturnType<typeof getNodeInfo>} info - Output of getNodeInfo
150
+ * @returns {string} Text to copy
151
+ */
152
+ export declare function formatNodeInfo(info: NodeInfo): string;
153
+ /**
154
+ * Mixes a "#rrggbb" or "rgb(r, g, b)" color with white (used as the tracked node's fill).
155
+ * Other color formats fall back to white.
156
+ * @param {string} color - Hex or rgb() color
157
+ * @param {number} [amount=0.88] - Share of white, 0..1
158
+ * @returns {string} Hex color
159
+ */
160
+ export declare function lightTint(color: string, amount?: number): string;
161
+ /**
162
+ * Highlights the tracked chains (Track node 1 and 2) and dims the rest.
163
+ * Elements on one chain get that track's class (track-parents, track2-children, ...);
164
+ * elements on both chains also get "track-mixed" with the common color in
165
+ * data(trackMixColor) and, for the tracked nodes, its light tint in data(trackMixFill).
166
+ * @param {cytoscape.Core} cy - Cytoscape instance
167
+ * @param {{id: string, direction: 'parents'|'children'}[]} tracks - Track 1 and Track 2 ('' id = off)
168
+ * @param {string} [commonColor] - Hex color of elements on both chains
169
+ */
170
+ export interface Track {
171
+ id: string;
172
+ direction: 'parents' | 'children';
173
+ }
174
+ export declare function applyTracking(cy: cytoscape.Core, tracks: Track[], commonColor?: string): void;
175
+ /**
176
+ * Cytoscape stylesheet; later rules override earlier ones.
177
+ * @param {{selectedColor?: string, parentsColor?: string, childrenColor?: string,
178
+ * track2ParentsColor?: string, track2ChildrenColor?: string}} [colors]
179
+ * Selected node color and Track node 1 / Track node 2 chain colors
180
+ * @returns {Object[]} Stylesheet
181
+ */
182
+ export interface StyleColors {
183
+ selectedColor?: string | undefined;
184
+ parentsColor?: string | undefined;
185
+ childrenColor?: string | undefined;
186
+ track2ParentsColor?: string | undefined;
187
+ track2ChildrenColor?: string | undefined;
188
+ }
189
+ export declare function makeStyles({ selectedColor, parentsColor, childrenColor, track2ParentsColor, track2ChildrenColor, }?: StyleColors): StylesheetJson;
190
+ /**
191
+ * Searchable node picker: typing any part of a name (case-insensitive) filters the list.
192
+ * Arrow keys move through the matches, Enter picks one, Escape closes the list.
193
+ * @param {string} [id] - id for the input (to link a <label>)
194
+ * @param {{id: string, label: string}[]} options - Nodes to choose from
195
+ * @param {string} selectedId - Currently selected node id ('' for none)
196
+ * @param {(id: string) => void} onSelect - Called with the chosen node id
197
+ * @param {string} [noneLabel] - Label of the first entry, which selects no node
198
+ * @param {Set<string>} [hiddenIds] - With onToggleVisible: nodes whose checkbox is off
199
+ * @param {(id: string) => void} [onToggleVisible] - When given, each node gets a checkbox
200
+ * (on = shown); called with the node id when it is clicked
201
+ */
202
+ export interface NodeSearchProps {
203
+ id?: string;
204
+ options: {
205
+ id: string;
206
+ label: string;
207
+ }[];
208
+ selectedId: string;
209
+ onSelect: (id: string) => void;
210
+ noneLabel?: string;
211
+ hiddenIds?: Set<string>;
212
+ onToggleVisible?: (id: string) => void;
213
+ }
214
+ export declare function NodeSearch({ id, options, selectedId, onSelect, noneLabel, hiddenIds, onToggleVisible, }: NodeSearchProps): React.JSX.Element;
215
+ /** Options of create_graph: grid placement, colors ("#rrggbb" or "rgb(r, g, b)") and text sizes (CSS lengths) */
216
+ export interface GraphOptions extends LayoutOptions {
217
+ /** Reports per row when the layout is built from the groups */
218
+ layoutColumns?: number | undefined;
219
+ selectedColor?: string | undefined;
220
+ parentsColor?: string | undefined;
221
+ childrenColor?: string | undefined;
222
+ track2ParentsColor?: string | undefined;
223
+ track2ChildrenColor?: string | undefined;
224
+ commonColor?: string | undefined;
225
+ topControlsFontSize?: string | undefined;
226
+ rightDisplayFontSize?: string | undefined;
227
+ }
228
+ /**
229
+ * Factory function that creates a React Graph component.
230
+ * Initializes Cytoscape instance, manages graph state, and handles node selection.
231
+ * @param {Object<string, string[]>} node_groups - Group (group box) names mapped to their report names
232
+ * @param {Array<[string, string]>} direct_node_connections - Edge definitions ([source, target] pairs)
233
+ * @param {string[][]|Object} [layoutOrOptions] - Layout grid (one row per layer). Optional: leave it out
234
+ * and pass the options in its place, e.g. create_graph(node_groups, direct_node_connections, options),
235
+ * to build the layout from the groups
236
+ * @param {Object} [optionsArg] - Layout rendering options (startX, startY, offsetX, offsetY, base,
237
+ * layoutColumns = reports per row when the layout is built from the groups)
238
+ * plus the colors ("#rrggbb"): selectedColor (Node to Display), parentsColor and
239
+ * childrenColor (Track node 1), track2ParentsColor and track2ChildrenColor (Track node 2;
240
+ * commonColor = elements on both chains, default rgb(239, 108, 0)), topControlsFontSize (text size of the top controls row, e.g. '16px')
241
+ * and rightDisplayFontSize (text size of the right details panel)
242
+ * @returns {React.FC} Graph component
243
+ */
244
+ export declare function create_graph(node_groups?: NodeGroups, direct_node_connections?: Connections, layoutOrOptions?: Layout | GraphOptions | null, optionsArg?: GraphOptions): FC;
@@ -0,0 +1,244 @@
1
+ import type { FC } from 'react';
2
+ import cytoscape from 'cytoscape';
3
+ import type { StylesheetJson } from 'cytoscape';
4
+ export * from './default_setting.js';
5
+ export declare const REPORT_NODE = "node[class = \"macromolecule\"]";
6
+ /** Group (folder box) names mapped to the names of the reports inside them */
7
+ export type NodeGroups = Record<string, string[]>;
8
+ /** Arrows: [source, target] */
9
+ export type Connections = [string, string][];
10
+ /** Layout grid: one list of report ids per row */
11
+ export type Layout = string[][];
12
+ /** Data of a graph element (a group box, a report or an arrow) */
13
+ export interface ElementData {
14
+ id: string;
15
+ class?: string;
16
+ label?: string;
17
+ rawLabel?: string;
18
+ displayLabel?: string;
19
+ group?: string | null;
20
+ parent?: string | undefined;
21
+ source?: string;
22
+ target?: string;
23
+ graphLabel?: string | undefined;
24
+ }
25
+ /** A Cytoscape element as built by buildGraph */
26
+ export interface GraphElement {
27
+ data: ElementData;
28
+ classes?: string;
29
+ }
30
+ /** Grid placement options of the layout */
31
+ export interface LayoutOptions {
32
+ startX?: number | undefined;
33
+ startY?: number | undefined;
34
+ offsetX?: number | undefined;
35
+ offsetY?: number | undefined;
36
+ base?: number | undefined;
37
+ }
38
+ /** A report listed in a group's details: its id, name and group */
39
+ export interface NodeRef {
40
+ id: string;
41
+ name: string;
42
+ group: string | null;
43
+ }
44
+ /** Details of a report shown in the side panel */
45
+ export interface NodeInfo extends NodeRef {
46
+ parents: NodeRef[];
47
+ children: NodeRef[];
48
+ }
49
+ /**
50
+ * Size of a report box: exactly the label plus a little padding.
51
+ * @param {string|undefined} label - The node label text
52
+ * @param {number} [fontSize] - Font size of the label in px
53
+ * @returns {{width: number, height: number}} Box size in px
54
+ */
55
+ export declare function getNodeSize(label: string | undefined, fontSize?: number): {
56
+ width: number;
57
+ height: number;
58
+ };
59
+ /**
60
+ * Compares names alphabetically, case-insensitive; numeric so "n2" comes before "n10".
61
+ * @param {string} a
62
+ * @param {string} b
63
+ * @returns {number}
64
+ */
65
+ export declare function compareNames(a: string, b: string): number;
66
+ /**
67
+ * Renames duplicate node IDs in layout to make them unique.
68
+ * Appends "(n)" suffix when duplicates are detected.
69
+ * @param {string[][]} layout - 2D array of node IDs arranged in rows/columns
70
+ * @returns {string[][]} Layout with renamed duplicates
71
+ */
72
+ export declare function uniquifyLayout(layout?: Layout): Layout;
73
+ /**
74
+ * Positions nodes in the Cytoscape graph based on layout specification.
75
+ * Handles missing/renamed nodes gracefully with fallbacks.
76
+ * @param {cytoscape.Core} cy - Cytoscape instance
77
+ * @param {string[][]} rows - 2D layout array with node IDs
78
+ * @param {Object} opts - Layout options (startX, startY, offsetX, offsetY, base)
79
+ */
80
+ export declare function applyLayout(cy: cytoscape.Core, rows: Layout, opts?: LayoutOptions): void;
81
+ /**
82
+ * Generates a unique ID by appending a counter suffix if needed.
83
+ * @param {string} base - Base ID string
84
+ * @param {Set<string>} taken - Set of already-used IDs (the new ID is added to it)
85
+ * @returns {string} Unique ID
86
+ */
87
+ export declare function uniqueId(base: string, taken: Set<string>): string;
88
+ /**
89
+ * Builds a layout from the groups, used when no layout is given.
90
+ * Each group starts a new row and fills rows of at most `columns` reports
91
+ * (group order, then report order); reports in no group come last.
92
+ * Copies of a report in several groups ("id(1)", ...) sit in their own group.
93
+ * @param {Object[]} elements - Cytoscape elements from buildGraph
94
+ * @param {number} [columns] - Maximum reports per row
95
+ * @returns {string[][]} Layout rows of node IDs
96
+ */
97
+ export declare function layoutFromFolders(elements: GraphElement[], columns?: number): Layout;
98
+ /**
99
+ * Builds the Cytoscape elements from groups, edges and extra node IDs.
100
+ * Folders become compound nodes (FOLDER_CLASS); every report becomes a
101
+ * REPORT_CLASS node. A report listed in several groups gets one copy per
102
+ * group ("id", "id(1)", ...); edges connect to the first copy.
103
+ * @param {Object<string, string[]>} node_groups - Mapping of group names to child IDs
104
+ * @param {Array<[string, string]>} direct_node_connections - Array of [source, target] edge pairs
105
+ * @param {string[]} extraIds - Other node IDs to create even without edges (e.g. from the layout)
106
+ * @returns {Object[]} Cytoscape elements array
107
+ */
108
+ export declare function buildGraph(node_groups?: NodeGroups, direct_node_connections?: Connections, extraIds?: string[]): GraphElement[];
109
+ /**
110
+ * Elements to draw for the current toggles: node label with or without
111
+ * the group, and groups shown or hidden.
112
+ * @param {Object[]} allElements - Output of buildGraph
113
+ * @param {boolean} showFolders - Keep the group (compartment) nodes
114
+ * @param {boolean} showGroupInLabel - Label reports "id (Group)" instead of "id"
115
+ * @returns {Object[]} Fresh element copies, safe to hand to a new Cytoscape instance
116
+ */
117
+ export declare function getVisibleElements(allElements: GraphElement[], showFolders: boolean, showGroupInLabel: boolean): GraphElement[];
118
+ /**
119
+ * Collects the details shown in the side panel for a report node.
120
+ * Parents point to the node, children are pointed to by it;
121
+ * a two-way edge makes the other node both a parent and a child.
122
+ * With allLevels, the lists hold the whole chains instead: the parents of the parents, ...
123
+ * and the children of the children, ... (the node itself is left out).
124
+ * @param {cytoscape.NodeSingular} node - The double-clicked node
125
+ * @param {boolean} [allLevels] - Every level of parents and children, not just the first
126
+ * @returns {{id: string, name: string, group: string|null, parents: Object[], children: Object[]}}
127
+ */
128
+ export declare function getNodeInfo(node: cytoscape.NodeSingular, allLevels?: boolean): NodeInfo;
129
+ /**
130
+ * Follows the edges from a node to collect its whole chain of parents
131
+ * (nodes pointing to it, their parents, ...) or children. A two-way edge
132
+ * counts in both directions, as in getNodeInfo.
133
+ * @param {cytoscape.NodeSingular} start - The tracked node
134
+ * @param {'parents'|'children'} direction - Which way to follow the edges
135
+ * @returns {cytoscape.Collection} The start node plus every node and edge on the chain
136
+ */
137
+ export declare function getTrackedElements(start: cytoscape.NodeSingular, direction: 'parents' | 'children'): cytoscape.Collection;
138
+ /**
139
+ * The elements to hide for the reports unchecked in "Node to Display": those reports
140
+ * (Cytoscape then hides their edges too) and the groups left with no visible report.
141
+ * @param {cytoscape.Core} cy - Cytoscape instance
142
+ * @param {Set<string>} hiddenIds - IDs of the reports to hide
143
+ * @returns {cytoscape.Collection} Elements to hide
144
+ */
145
+ export declare function getHiddenElements(cy: cytoscape.Core, hiddenIds: Set<string>): cytoscape.Collection;
146
+ /**
147
+ * Formats node details as plain text for the clipboard, matching the side panel:
148
+ * the group and the parent/child lists appear only when not empty.
149
+ * @param {ReturnType<typeof getNodeInfo>} info - Output of getNodeInfo
150
+ * @returns {string} Text to copy
151
+ */
152
+ export declare function formatNodeInfo(info: NodeInfo): string;
153
+ /**
154
+ * Mixes a "#rrggbb" or "rgb(r, g, b)" color with white (used as the tracked node's fill).
155
+ * Other color formats fall back to white.
156
+ * @param {string} color - Hex or rgb() color
157
+ * @param {number} [amount=0.88] - Share of white, 0..1
158
+ * @returns {string} Hex color
159
+ */
160
+ export declare function lightTint(color: string, amount?: number): string;
161
+ /**
162
+ * Highlights the tracked chains (Track node 1 and 2) and dims the rest.
163
+ * Elements on one chain get that track's class (track-parents, track2-children, ...);
164
+ * elements on both chains also get "track-mixed" with the common color in
165
+ * data(trackMixColor) and, for the tracked nodes, its light tint in data(trackMixFill).
166
+ * @param {cytoscape.Core} cy - Cytoscape instance
167
+ * @param {{id: string, direction: 'parents'|'children'}[]} tracks - Track 1 and Track 2 ('' id = off)
168
+ * @param {string} [commonColor] - Hex color of elements on both chains
169
+ */
170
+ export interface Track {
171
+ id: string;
172
+ direction: 'parents' | 'children';
173
+ }
174
+ export declare function applyTracking(cy: cytoscape.Core, tracks: Track[], commonColor?: string): void;
175
+ /**
176
+ * Cytoscape stylesheet; later rules override earlier ones.
177
+ * @param {{selectedColor?: string, parentsColor?: string, childrenColor?: string,
178
+ * track2ParentsColor?: string, track2ChildrenColor?: string}} [colors]
179
+ * Selected node color and Track node 1 / Track node 2 chain colors
180
+ * @returns {Object[]} Stylesheet
181
+ */
182
+ export interface StyleColors {
183
+ selectedColor?: string | undefined;
184
+ parentsColor?: string | undefined;
185
+ childrenColor?: string | undefined;
186
+ track2ParentsColor?: string | undefined;
187
+ track2ChildrenColor?: string | undefined;
188
+ }
189
+ export declare function makeStyles({ selectedColor, parentsColor, childrenColor, track2ParentsColor, track2ChildrenColor, }?: StyleColors): StylesheetJson;
190
+ /**
191
+ * Searchable node picker: typing any part of a name (case-insensitive) filters the list.
192
+ * Arrow keys move through the matches, Enter picks one, Escape closes the list.
193
+ * @param {string} [id] - id for the input (to link a <label>)
194
+ * @param {{id: string, label: string}[]} options - Nodes to choose from
195
+ * @param {string} selectedId - Currently selected node id ('' for none)
196
+ * @param {(id: string) => void} onSelect - Called with the chosen node id
197
+ * @param {string} [noneLabel] - Label of the first entry, which selects no node
198
+ * @param {Set<string>} [hiddenIds] - With onToggleVisible: nodes whose checkbox is off
199
+ * @param {(id: string) => void} [onToggleVisible] - When given, each node gets a checkbox
200
+ * (on = shown); called with the node id when it is clicked
201
+ */
202
+ export interface NodeSearchProps {
203
+ id?: string;
204
+ options: {
205
+ id: string;
206
+ label: string;
207
+ }[];
208
+ selectedId: string;
209
+ onSelect: (id: string) => void;
210
+ noneLabel?: string;
211
+ hiddenIds?: Set<string>;
212
+ onToggleVisible?: (id: string) => void;
213
+ }
214
+ export declare function NodeSearch({ id, options, selectedId, onSelect, noneLabel, hiddenIds, onToggleVisible, }: NodeSearchProps): React.JSX.Element;
215
+ /** Options of create_graph: grid placement, colors ("#rrggbb" or "rgb(r, g, b)") and text sizes (CSS lengths) */
216
+ export interface GraphOptions extends LayoutOptions {
217
+ /** Reports per row when the layout is built from the groups */
218
+ layoutColumns?: number | undefined;
219
+ selectedColor?: string | undefined;
220
+ parentsColor?: string | undefined;
221
+ childrenColor?: string | undefined;
222
+ track2ParentsColor?: string | undefined;
223
+ track2ChildrenColor?: string | undefined;
224
+ commonColor?: string | undefined;
225
+ topControlsFontSize?: string | undefined;
226
+ rightDisplayFontSize?: string | undefined;
227
+ }
228
+ /**
229
+ * Factory function that creates a React Graph component.
230
+ * Initializes Cytoscape instance, manages graph state, and handles node selection.
231
+ * @param {Object<string, string[]>} node_groups - Group (group box) names mapped to their report names
232
+ * @param {Array<[string, string]>} direct_node_connections - Edge definitions ([source, target] pairs)
233
+ * @param {string[][]|Object} [layoutOrOptions] - Layout grid (one row per layer). Optional: leave it out
234
+ * and pass the options in its place, e.g. create_graph(node_groups, direct_node_connections, options),
235
+ * to build the layout from the groups
236
+ * @param {Object} [optionsArg] - Layout rendering options (startX, startY, offsetX, offsetY, base,
237
+ * layoutColumns = reports per row when the layout is built from the groups)
238
+ * plus the colors ("#rrggbb"): selectedColor (Node to Display), parentsColor and
239
+ * childrenColor (Track node 1), track2ParentsColor and track2ChildrenColor (Track node 2;
240
+ * commonColor = elements on both chains, default rgb(239, 108, 0)), topControlsFontSize (text size of the top controls row, e.g. '16px')
241
+ * and rightDisplayFontSize (text size of the right details panel)
242
+ * @returns {React.FC} Graph component
243
+ */
244
+ export declare function create_graph(node_groups?: NodeGroups, direct_node_connections?: Connections, layoutOrOptions?: Layout | GraphOptions | null, optionsArg?: GraphOptions): FC;
package/dist/index.cjs ADDED
@@ -0,0 +1,3 @@
1
+ "use client";Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});var e=Object.create,t=Object.defineProperty,n=Object.getOwnPropertyDescriptor,r=Object.getOwnPropertyNames,i=Object.getPrototypeOf,a=Object.prototype.hasOwnProperty,o=(e,i,o,s)=>{if(i&&typeof i==`object`||typeof i==`function`)for(var c=r(i),l=0,u=c.length,d;l<u;l++)d=c[l],!a.call(e,d)&&d!==o&&t(e,d,{get:(e=>i[e]).bind(null,d),enumerable:!(s=n(i,d))||s.enumerable});return e},s=(n,r,s)=>(s=n==null?{}:e(i(n)),o(r||!n||!n.__esModule||!a.call(n,`default`)?t(s,`default`,{value:n,enumerable:!0}):s,n));let c=require("react"),l=require("cytoscape");l=s(l,1);let u=require("react/jsx-runtime");var d=`#e91e63`,f=`#2e7d32`,p=`#7b1fa2`,m=`#efeb00`,h=`#8b4513`,g=`rgb(239, 108, 0)`,_=`22px`,v=`18px`,y=`#0066cc`,b=`#fff`,x=`#f0f8ff`,S=2,C=-8,w=16,T=16,E=14,D=[[`top`,`Font Top Panel`],[`right`,`Font Right Panel`],[`graph`,`Font Graph Panel`]],O=`Helvetica Neue, Helvetica, Arial, sans-serif`,k=1.2,A=.6,j=`macromolecule`,M=`compartment`,N=`node[class = "${j}"]`,P;function F(e,t){if(P===void 0)try{P=document.createElement(`canvas`).getContext(`2d`)}catch{P=null}return P?(P.font=`${t}px ${O}`,P.measureText(e).width):e.length*t*A}function ee(e,t=T){return{width:Math.ceil(F(e??``,t))+8,height:Math.ceil(t*k)+8}}function I(e,t){return e.localeCompare(t,void 0,{numeric:!0,sensitivity:`base`})}function te(e=[]){let t=new Map;return e.map(e=>e.map(e=>{let n=t.get(e)??0;if(t.set(e,n+1),n===0)return e;let r=`${e}(${n})`;return console.warn(`layout: duplicate id "${e}" — renamed to "${r}"`),r}))}function ne(e,t,n={}){let{startX:r=0,startY:i=0,offsetX:a=200,offsetY:o=200,base:s=1}=n,c=new Set;t.forEach((t,n)=>{t.forEach((t,l)=>{let u=t,d=e.getElementById(u);if(d.empty()){let n=/^(.+)\((\d+)\)$/.exec(t)?.[1];n!==void 0&&e.getElementById(n).nonempty()&&(u=n,d=e.getElementById(u),console.warn(`applyLayout: "${t}" not found — using "${u}" instead`))}d.empty()?console.warn(`applyLayout: node "${t}" not found`):c.has(u)?console.warn(`applyLayout: duplicate layout entry for node "${u}" (from "${t}") — keeping the first position`):(c.add(u),d.position({x:r+(l+s)*a,y:i+(n+s)*o}))})})}function L(e,t){let n=e,r=2;for(;t.has(n);)n=`${e}_${r++}`;return t.add(n),n}function R(e,t=10){let n=Math.max(1,Math.floor(t)||1),r=e.filter(e=>e.data.class===j),i=e.filter(e=>e.data.class===M).map(e=>r.filter(t=>t.data.parent===e.data.id));i.push(r.filter(e=>!e.data.parent));let a=[];for(let e of i)for(let t=0;t<e.length;t+=n)a.push(e.slice(t,t+n).map(e=>e.data.id));return a}function z(e={},t=[],n=[]){let r=[],i=new Set,a=new Set([...t.flat(),...n]);for(let t of Object.values(e))for(let e of t)i.add(e);for(let e of a)i.add(e);let o=e=>{let t=e.replace(/\s+/g,``);return t?t.charAt(0).toLowerCase()+t.slice(1):`folder`},s=new Map,c=new Map;for(let[t,n]of Object.entries(e)){let e=L(o(t),i);c.set(t,e),r.push({data:{id:e,class:M,label:t}});for(let e of n){let n=s.get(e)??[],r=e;if(n.length>0){let t=n.length;for(r=`${e}(${t})`;i.has(r);)r=`${e}(${++t})`;i.add(r)}n.push({actualId:r,folderLabel:t}),s.set(e,n)}}let l=[];for(let[e,t]of s)for(let{actualId:n,folderLabel:r}of t)l.push({actualId:n,originalId:e,folderLabel:r});for(let e of a)s.has(e)||l.push({actualId:e,originalId:e,folderLabel:null});for(let{actualId:e,originalId:t,folderLabel:n}of l){let i={id:e,class:j,rawLabel:t,displayLabel:n?`${t} (${n})`:t,group:n};n&&(i.parent=c.get(n)),r.push({data:i})}let u=e=>s.get(e)?.[0]?.actualId??e,d=(e,t)=>`${e}->${t}`,f=new Map;return t.forEach(([e,t],n)=>{let a=u(e),o=u(t);if(f.has(d(a,o)))return;let s=f.get(d(o,a));if(s){s.classes=`bidirectional`;return}let c={data:{id:L(`e${n+1}`,i),source:a,target:o}};f.set(d(a,o),c),r.push(c)}),r}function re(e,t,n){return e.filter(e=>t||e.data.class!==M).map(e=>{if(e.data.class!==j)return{...e,data:{...e.data}};let t=n?e.data.displayLabel:e.data.rawLabel;return{...e,data:{...e.data,graphLabel:t}}})}function B(e,t=!1){let n=e=>({id:e.id(),name:e.data(`rawLabel`)??e.id(),group:e.data(`group`)??null}),r=new Map,i=new Map;if(e.connectedEdges().forEach(t=>{let a=t.hasClass(`bidirectional`);t.target().same(e)&&(r.set(t.source().id(),n(t.source())),a&&i.set(t.source().id(),n(t.source()))),t.source().same(e)&&(i.set(t.target().id(),n(t.target())),a&&r.set(t.target().id(),n(t.target())))}),t){let t=[[r,`parents`],[i,`children`]];for(let[r,i]of t)r.clear(),V(e,i).nodes().forEach(t=>{t.same(e)||r.set(t.id(),n(t))})}let a=(e,t)=>I(e.name,t.name);return{...n(e),parents:[...r.values()].sort(a),children:[...i.values()].sort(a)}}function V(e,t){let n=t===`parents`,r=e.cy().collection(),i=new Set([e.id()]),a=[e];for(let e=a.shift();e!==void 0;e=a.shift()){let t=e;t.connectedEdges().forEach(e=>{let o=e.hasClass(`bidirectional`),s=null;e.target().same(t)&&(n||o)&&(s=e.source()),e.source().same(t)&&(!n||o)&&(s=e.target()),s&&(r=r.union(e),i.has(s.id())||(i.add(s.id()),a.push(s)))})}return r.union(e.cy().nodes().filter(e=>i.has(e.id())))}function H(e){return[[`Parent Nodes`,e.parents],[`Child Nodes`,e.children]].filter(([,e])=>e.length>0)}function ie(e,t){let n=e.nodes(N).filter(e=>t.has(e.id())),r=e.nodes(`:parent`).filter(e=>e.children().every(e=>n.has(e)));return n.union(r)}function U(e){let t=e=>e.group?`${e.name} (${e.group})`:e.name,n=[`Node: ${e.name}`];e.group&&n.push(`Group: ${e.group}`);for(let[r,i]of H(e))n.push(``,`${r} (${i.length}):`,...i.map(t));return n.join(`
2
+ `)}function W(e){let t=/^#([0-9a-f]{6})$/i.exec(e)?.[1];if(t!==void 0)return parseInt(t,16);let n=/^rgb\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*\)$/i.exec(e);if(n===null)return null;let[r=0,i=0,a=0]=n.slice(1).map(e=>Math.min(Number(e),255));return r<<16|i<<8|a}function G(e,t=.88){let n=W(e);return n===null?`#ffffff`:`#${[16,8,0].map(e=>{let r=n>>e&255;return Math.round(r+(255-r)*t).toString(16).padStart(2,`0`)}).join(``)}`}function ae(e,t,n=g){let r=[`track`,`track2`],i=r.flatMap(e=>[`${e}-parents`,`${e}-children`,`${e}-root`]).concat(`faded`,`track-mixed`).join(` `);e.batch(()=>{e.elements().removeClass(i).removeData(`trackMixColor trackMixFill`);let a=t.map(({id:t,direction:n},i)=>{if(!t)return null;let a=e.getElementById(t);if(a.empty())return null;let o=V(a,n),s=r[i]??`track`;return o.addClass(`${s}-${n}`),a.addClass(`${s}-root`),o}),o=a.filter(e=>e!==null);if(o.length===0)return;let[s,c]=a;s&&c&&s.intersection(c).forEach(e=>{e.data({trackMixColor:n,trackMixFill:G(n)}),e.addClass(`track-mixed`)});let l=o.reduce((e,t)=>e.union(t));e.elements().not(l).not(`node:parent`).addClass(`faded`)})}function K({selectedColor:e=d,parentsColor:t=f,childrenColor:n=p,track2ParentsColor:r=m,track2ChildrenColor:i=h}={}){return[{selector:`node`,style:{"background-color":b,label:`data(graphLabel)`,shape:`rectangle`,"font-family":O,"font-size":T,color:y,"border-width":2,"border-color":y,"text-valign":`center`,"text-halign":`center`}},{selector:`node:parent`,style:{"background-color":x,"background-opacity":.5,"border-style":`dashed`,label:`data(label)`,"text-valign":`top`,"font-size":E,"font-weight":`bold`,padding:`18px`}},{selector:`.selected`,style:{"overlay-color":e,"overlay-opacity":.35,"overlay-padding":8}},{selector:`edge`,style:{"line-color":y,width:2,"curve-style":`bezier`,"target-arrow-shape":`vee`,"target-arrow-color":y,"target-arrow-fill":`filled`,"arrow-scale":2}},{selector:`edge:loop`,style:{"loop-direction":`0deg`,"loop-sweep":`-50deg`,"control-point-step-size":70}},{selector:`edge.bidirectional`,style:{"source-arrow-shape":`vee`,"source-arrow-color":y,"source-arrow-fill":`filled`}},{selector:`.faded`,style:{opacity:.15}},...[[`track-parents`,`track-root`,t],[`track-children`,`track-root`,n],[`track2-parents`,`track2-root`,r],[`track2-children`,`track2-root`,i]].flatMap(([e,t,n])=>[{selector:`edge.${e}`,style:{"line-color":n,"target-arrow-color":n,"source-arrow-color":n,width:4}},{selector:`node.${e}`,style:{"border-color":n,"border-width":3}},{selector:`node.${e}.${t}`,style:{"border-width":5,"background-color":G(n)}}]),{selector:`edge.track-mixed`,style:{"line-color":`data(trackMixColor)`,"target-arrow-color":`data(trackMixColor)`,"source-arrow-color":`data(trackMixColor)`,width:5}},{selector:`node.track-mixed`,style:{"border-color":`data(trackMixColor)`,"border-width":4}},{selector:`node.track-mixed.track-root, node.track-mixed.track2-root`,style:{"border-width":6,"background-color":`data(trackMixFill)`}},{selector:`.hidden`,style:{display:`none`}}]}var q=`ALL`;function J({id:e,options:t,selectedId:n,onSelect:r,noneLabel:i=q,hiddenIds:a,onToggleVisible:o}){let[s,l]=(0,c.useState)(``),[d,f]=(0,c.useState)(``),[p,m]=(0,c.useState)(!1),[h,g]=(0,c.useState)(0),_=(0,c.useRef)(null),v=(0,c.useRef)(null),y=t.find(e=>e.id===n)?.label??``,[b,x]=(0,c.useState)(null);b!==y&&(x(y),l(y));let S=d.trim().toLowerCase(),C=S?t.filter(e=>e.label.toLowerCase().includes(S)):t,w={id:``,label:i},T=!S||i.toLowerCase().includes(S)?[w,...C]:C,E=()=>{f(``),g(0),m(!0)},D=()=>{m(!1),f(``),l(y)},O=e=>{r(e.id),l(e.id?e.label:``),f(``),m(!1)};return(0,c.useEffect)(()=>{if(!p)return;let e=e=>{_.current?.contains(e.target)||D()};return document.addEventListener(`mousedown`,e),()=>document.removeEventListener(`mousedown`,e)}),(0,c.useEffect)(()=>{v.current?.children[h]?.scrollIntoView({block:`nearest`})},[h,p]),(0,u.jsxs)(`div`,{className:`node-search`,ref:_,children:[(0,u.jsx)(`input`,{id:e,type:`text`,value:s,placeholder:`-- type to search --`,autoComplete:`off`,onChange:e=>{l(e.target.value),f(e.target.value),g(0),m(!0)},onFocus:e=>{e.target.select(),E()},onClick:()=>{p||E()},onKeyDown:e=>{if(e.key===`ArrowDown`)e.preventDefault(),p||m(!0),g(e=>Math.min(e+1,T.length-1));else if(e.key===`ArrowUp`)e.preventDefault(),g(e=>Math.max(e-1,0));else if(e.key===`Enter`&&p){let t=T[h];t&&(e.preventDefault(),O(t))}else e.key===`Escape`&&D()}}),s&&(0,u.jsx)(`button`,{type:`button`,className:`node-search-clear`,"aria-label":`Clear`,onClick:()=>{r(``),l(``),f(``)},children:`×`}),p&&(0,u.jsx)(`ul`,{className:`node-search-list`,ref:v,role:`listbox`,children:T.length===0?(0,u.jsx)(`li`,{className:`node-search-empty`,role:`option`,"aria-selected":`false`,"aria-disabled":`true`,children:`no match`}):T.map((e,t)=>(0,u.jsxs)(`li`,{role:`option`,"aria-selected":t===h,className:[t===h&&`active`,a?.has(e.id)&&`off`].filter(Boolean).join(` `)||void 0,onMouseDown:t=>{t.preventDefault(),O(e)},onMouseEnter:()=>g(t),children:[o&&e.id&&(0,u.jsx)(`input`,{type:`checkbox`,checked:!a?.has(e.id),"aria-label":`Show ${e.label}`,onMouseDown:e=>{e.preventDefault(),e.stopPropagation()},onClick:e=>e.stopPropagation(),onChange:()=>o(e.id)}),e.label]},e.id||`__none__`))})]})}function Y(e={},t=[],n=null,r={}){let i=Array.isArray(n)?n:null,a=n!==null&&!Array.isArray(n)?n:r,o=i!==null&&i.length>0,{selectedColor:s=d,parentsColor:y=f,childrenColor:b=p,track2ParentsColor:x=m,track2ChildrenColor:O=h,commonColor:k=g,topControlsFontSize:A=_,rightDisplayFontSize:j=v,layoutColumns:M=10}=a,P=K({selectedColor:s,parentsColor:y,childrenColor:b,track2ParentsColor:x,track2ChildrenColor:O}),F={"--rbg-parents-color":y,"--rbg-children-color":b},L={"--rbg-parents-color":x,"--rbg-children-color":O},V=z(e,t,i!==null&&o?i.flat():[]),W=i!==null&&o?te(i):R(V,M);function G(){let e=(0,c.useRef)(null),t=(0,c.useRef)(null),n=(0,c.useId)(),[r,i]=(0,c.useState)([]),[o,s]=(0,c.useState)(``),[d,f]=(0,c.useState)(0),[p,m]=(0,c.useState)(``),[h,g]=(0,c.useState)(`parents`),[_,v]=(0,c.useState)(``),[y,b]=(0,c.useState)(`parents`),[x,O]=(0,c.useState)(!0),[M,te]=(0,c.useState)(!0),[R,z]=(0,c.useState)(null),[G,K]=(0,c.useState)(null),[q,Y]=(0,c.useState)(`top`),[X,oe]=(0,c.useState)({top:0,right:0,graph:0}),[Z,se]=(0,c.useState)(!1),Q=(0,c.useRef)(!1);(0,c.useEffect)(()=>{Q.current=Z},[Z]);let[$,ce]=(0,c.useState)(()=>new Set);(0,c.useEffect)(()=>{let n=e.current;if(!n)return;let r=(0,l.default)({container:n,elements:re(V,x,M),style:P,layout:{name:`preset`,fit:!1}});r.on(`cxttap`,N,e=>{let t=U(B(e.target,Q.current)),{clientX:n,clientY:r}=e.originalEvent;z({x:n,y:r,copyText:t})}),r.on(`dbltap`,N,e=>{K(B(e.target,Q.current))}),r.on(`tap cxttap`,e=>{e.target===r&&z(null)}),r.on(`tap`,`node`,()=>z(null)),r.on(`viewport`,()=>z(null));let o=e=>e.preventDefault();return n.addEventListener(`contextmenu`,o),ne(r,W,a),requestAnimationFrame(()=>r.resize()),i(r.nodes(N).map(e=>({id:e.id(),label:e.data(`displayLabel`)})).sort((e,t)=>I(e.label,t.label))),t.current=r,()=>{n.removeEventListener(`contextmenu`,o),z(null),r.destroy(),t.current=null}},[x,M]),(0,c.useEffect)(()=>{let e=t.current;if(!e)return;let n=X.graph;e.batch(()=>{e.nodes(N).forEach(e=>{let t=T+n,{width:r,height:i}=ee(e.data(`graphLabel`),t);e.style({"font-size":t,width:r,height:i})}),e.nodes(`:parent`).style(`font-size`,E+n)})},[X.graph,x,M]),(0,c.useEffect)(()=>{if(!R)return;let e=e=>{e.target.closest(`.node-context-menu`)||z(null)},t=e=>{e.key===`Escape`&&z(null)};return document.addEventListener(`mousedown`,e),document.addEventListener(`keydown`,t),()=>{document.removeEventListener(`mousedown`,e),document.removeEventListener(`keydown`,t)}},[R]);let le=()=>{if(R===null)return;let{copyText:e}=R;z(null),navigator.clipboard.writeText(e).catch(e=>{console.error(`Failed to copy:`,e)})},ue=e=>{ce(t=>{let n=new Set(t);return n.has(e)?n.delete(e):n.add(e),n})},de=e=>{let n=t.current?.getElementById(e);n&&!n.empty()&&($.has(e)&&ue(e),s(e),K(B(n,Z)))},fe=()=>{s(``),K(null),f(e=>e+1)};(0,c.useEffect)(()=>{let e=t.current;e&&e.batch(()=>{e.elements().removeClass(`hidden`),ie(e,$).addClass(`hidden`)})},[$,x,M]),(0,c.useEffect)(()=>{let e=t.current;d&&e&&(e.stop(),e.resize(),e.animate({fit:{eles:e.elements().not(`.hidden`),padding:30}},{duration:400}))},[d]),(0,c.useEffect)(()=>{let e=t.current;if(!e||(e.nodes().removeClass(`selected`),!o))return;let n=e.getElementById(o);n.nonempty()&&(n.addClass(`selected`),e.animate({center:{eles:n},zoom:1.8},{duration:400}))},[o,x,M]),(0,c.useEffect)(()=>{let e=t.current;e&&ae(e,[{id:p,direction:h},{id:_,direction:y}],k)},[p,h,_,y,x,M]),(0,c.useEffect)(()=>{t.current?.resize()},[G!==null]),(0,c.useEffect)(()=>{let e=()=>t.current?.resize();return window.addEventListener(`resize`,e),()=>window.removeEventListener(`resize`,e)},[]);let pe=[{n:1,id:p,setId:m,direction:h,setDirection:g,style:void 0},{n:2,id:_,setId:v,direction:y,setDirection:b,style:L}],me=[{label:`Smaller text`,symbol:`−`,step:-2,atLimit:X[q]<=C},{label:`Larger text`,symbol:`+`,step:S,atLimit:X[q]>=w}];return(0,u.jsxs)(`div`,{className:`rbg-graph`,style:{...F,"--rbg-top-controls-font-size":`calc(${A} + ${X.top}px)`,"--rbg-right-display-font-size":`calc(${j} + ${X.right}px)`},children:[(0,u.jsxs)(`div`,{className:`controls`,children:[(0,u.jsxs)(`span`,{className:`control-group`,children:[(0,u.jsx)(`label`,{htmlFor:`${n}-search`,children:`Node to Display:`}),(0,u.jsx)(J,{id:`${n}-search`,options:r,selectedId:o,onSelect:e=>e?de(e):fe(),hiddenIds:$,onToggleVisible:ue})]}),(0,u.jsxs)(`label`,{children:[(0,u.jsx)(`input`,{type:`checkbox`,checked:x,onChange:e=>O(e.target.checked)}),`Show Groups`]}),(0,u.jsxs)(`label`,{children:[(0,u.jsx)(`input`,{type:`checkbox`,checked:M,onChange:e=>te(e.target.checked)}),`Add Group to Node Name`]}),pe.map(({n:e,id:t,setId:i,direction:a,setDirection:o,style:s})=>(0,u.jsxs)(`span`,{className:`control-group`,style:s,children:[(0,u.jsxs)(`label`,{htmlFor:`${n}-track${e}`,children:[`Show Dependency `,e,`:`]}),(0,u.jsx)(J,{id:`${n}-track${e}`,options:r,selectedId:t,onSelect:i,noneLabel:`Show Nothing`}),(0,u.jsxs)(`span`,{className:t?`track-switch`:`track-switch disabled`,children:[(0,u.jsx)(`span`,{className:a===`parents`?`parents on`:`parents`,children:`Parents`}),(0,u.jsx)(`button`,{type:`button`,role:`switch`,"aria-checked":a===`children`,"aria-label":`Show Dependency ${e}: track children instead of parents`,className:`switch`,disabled:!t,onClick:()=>o(e=>e===`parents`?`children`:`parents`),children:(0,u.jsx)(`span`,{className:`switch-knob`})}),(0,u.jsx)(`span`,{className:a===`children`?`children on`:`children`,children:`Children`})]})]},e)),(0,u.jsxs)(`span`,{className:`help`,children:[(0,u.jsx)(`button`,{type:`button`,className:`help-icon`,"aria-label":`Help`,"aria-describedby":`${n}-help`,children:`?`}),(0,u.jsxs)(`span`,{id:`${n}-help`,role:`tooltip`,className:`help-tooltip`,children:[(0,u.jsx)(`strong`,{children:`Double click`}),` on a node to see its information, parents and children.`,(0,u.jsx)(`br`,{}),(0,u.jsx)(`strong`,{children:`Right click`}),` on a node to save the same information to the clipboard.`]})]}),(0,u.jsxs)(`span`,{className:`font-size-buttons`,children:[(0,u.jsx)(`select`,{"aria-label":`Area whose text size the + and - buttons change`,value:q,onChange:e=>Y(e.target.value),children:D.map(([e,t])=>(0,u.jsx)(`option`,{value:e,children:t},e))}),me.map(({label:e,symbol:t,step:n,atLimit:r})=>(0,u.jsx)(`button`,{type:`button`,className:`help-icon`,"aria-label":e,disabled:r,onClick:()=>oe(e=>({...e,[q]:e[q]+n})),children:t},e))]})]}),(0,u.jsxs)(`div`,{className:`graph-area`,children:[(0,u.jsx)(`div`,{ref:e,className:`cy-container`}),G&&(0,u.jsxs)(`aside`,{className:`node-info-panel`,children:[(0,u.jsxs)(`div`,{className:`node-info-header`,children:[(0,u.jsxs)(`h2`,{children:[(0,u.jsx)(`strong`,{children:`Node:`}),` `,G.name]}),(0,u.jsx)(`button`,{type:`button`,onClick:()=>K(null),"aria-label":`Close`,children:`×`})]}),G.group&&(0,u.jsxs)(`p`,{children:[(0,u.jsx)(`strong`,{children:`Group:`}),` `,G.group]}),(0,u.jsxs)(`div`,{className:`track-switch level-switch`,children:[(0,u.jsx)(`span`,{className:Z?``:`parents on`,children:`One level`}),(0,u.jsx)(`button`,{type:`button`,role:`switch`,"aria-checked":Z,"aria-label":`Show all levels of parents and children`,className:`switch`,onClick:()=>{let e=!Z;se(e);let n=t.current?.getElementById(G.id);n&&!n.empty()&&K(B(n,e))},children:(0,u.jsx)(`span`,{className:`switch-knob`})}),(0,u.jsx)(`span`,{className:Z?`children on`:``,children:`All levels`})]}),H(G).map(([e,t])=>(0,u.jsxs)(`section`,{children:[(0,u.jsxs)(`h3`,{children:[e,` (`,t.length,`):`]}),(0,u.jsx)(`ul`,{children:t.map(e=>(0,u.jsx)(`li`,{children:(0,u.jsxs)(`button`,{type:`button`,onClick:()=>de(e.id),children:[e.name,e.group&&(0,u.jsxs)(`span`,{children:[` (`,e.group,`)`]})]})},e.id))})]},e))]})]}),R&&(0,u.jsx)(`div`,{className:`node-context-menu`,style:{left:R.x,top:R.y},onContextMenu:e=>e.preventDefault(),children:(0,u.jsx)(`button`,{type:`button`,onClick:le,children:`Save to clipboard`})})]})}return G.displayName=`CytoscapeGraph`,G}exports.NodeSearch=J,exports.create_graph=Y,exports.formatNodeInfo=U,exports.getNodeInfo=B;
3
+ //# sourceMappingURL=index.cjs.map