@petrarca/sonnet-graph 0.3.0 → 0.4.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.
- package/README.md +144 -0
- package/dist/index.d.ts +12 -1
- package/dist/index.js +128 -19
- package/dist/index.js.map +1 -1
- package/package.json +34 -5
package/README.md
ADDED
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
# @petrarca/sonnet-graph
|
|
2
|
+
|
|
3
|
+
Renderer-agnostic property graph visualization, exploration, and enrichment
|
|
4
|
+
for the Petrarca Sonnet component library.
|
|
5
|
+
|
|
6
|
+
## What's included
|
|
7
|
+
|
|
8
|
+
**GraphVisualizer** — Main visualization component. Renders a property graph
|
|
9
|
+
using the active renderer (Cytoscape or Reagraph). Supports node/edge
|
|
10
|
+
selection, focus mode, hide/show, and graph expansion.
|
|
11
|
+
|
|
12
|
+
**ActionPanel** — Side panel showing selected node/edge details and graph
|
|
13
|
+
exploration actions.
|
|
14
|
+
|
|
15
|
+
**GraphA11yList** — Accessible DOM mirror of the graph's selectable elements.
|
|
16
|
+
Cytoscape (canvas) and Reagraph (WebGL) draw nodes/edges outside the DOM, so they
|
|
17
|
+
are invisible to screen readers, keyboard users, and DOM automation; this renders
|
|
18
|
+
a virtualized list of node/edge `<button>`s that drive the same selection store
|
|
19
|
+
the canvas reads. `sr-only` by default (real apps); pass `visible` for an on-screen
|
|
20
|
+
outline panel.
|
|
21
|
+
|
|
22
|
+
**GraphRendererProvider** — Context provider that selects the active renderer
|
|
23
|
+
(`"cytoscape"` or `"reagraph"`).
|
|
24
|
+
|
|
25
|
+
**Store factories** — Create the Zustand stores the graph components need:
|
|
26
|
+
`createGraphDataStore`, `createGraphFilterStore`, `createGraphExplorationStore`,
|
|
27
|
+
`createSelectionStore`, `createGraphFocusStore`.
|
|
28
|
+
|
|
29
|
+
**Graph utilities** — `enrichNodes`, `enrichEdges`, `buildColorPalette` for
|
|
30
|
+
preparing raw graph data before passing it to stores.
|
|
31
|
+
|
|
32
|
+
---
|
|
33
|
+
|
|
34
|
+
## Install
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
pnpm add @petrarca/sonnet-graph
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
### Required peer dependencies
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
pnpm add react@">=19" react-dom@">=19"
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
### Renderer peer dependencies
|
|
47
|
+
|
|
48
|
+
Install only the renderers you use:
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
pnpm add cytoscape # Cytoscape.js renderer
|
|
52
|
+
pnpm add reagraph # Reagraph (3D/WebGL) renderer
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
If you use `@petrarca/sonnet-playground` (which includes the graph demo page),
|
|
56
|
+
both `cytoscape` and `reagraph` are required even if your app only uses one renderer.
|
|
57
|
+
|
|
58
|
+
### Cytoscape layout plugins (optional)
|
|
59
|
+
|
|
60
|
+
Install the layout algorithms you need. All are optional — the graph works
|
|
61
|
+
without them but with fewer layout options:
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
pnpm add cytoscape-fcose # Force-directed, compound graph
|
|
65
|
+
pnpm add cytoscape-cola # Constraint-based
|
|
66
|
+
pnpm add cytoscape-dagre # DAG / hierarchical
|
|
67
|
+
pnpm add cytoscape-elk # Eclipse Layout Kernel
|
|
68
|
+
pnpm add cytoscape-cise # Circular layout
|
|
69
|
+
pnpm add cytoscape-klay # KLay hierarchical
|
|
70
|
+
pnpm add cytoscape-cxtmenu # Context menu extension
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
### Local development with SONNET_UI_LOCAL=1
|
|
74
|
+
|
|
75
|
+
When resolving `@petrarca/sonnet-graph` from the local dist (via Vite aliases),
|
|
76
|
+
the Cytoscape plugins must also be aliased to the consumer's `node_modules` —
|
|
77
|
+
Vite cannot find them relative to the dist file. Add to your `sonnet-aliases.ts`:
|
|
78
|
+
|
|
79
|
+
```ts
|
|
80
|
+
const nm = path.resolve(baseDir, "node_modules");
|
|
81
|
+
// ...
|
|
82
|
+
"cytoscape-fcose": path.resolve(nm, "cytoscape-fcose"),
|
|
83
|
+
"cytoscape-cola": path.resolve(nm, "cytoscape-cola"),
|
|
84
|
+
"cytoscape-dagre": path.resolve(nm, "cytoscape-dagre"),
|
|
85
|
+
"cytoscape-elk": path.resolve(nm, "cytoscape-elk"),
|
|
86
|
+
"cytoscape-cise": path.resolve(nm, "cytoscape-cise"),
|
|
87
|
+
"cytoscape-klay": path.resolve(nm, "cytoscape-klay"),
|
|
88
|
+
"cytoscape-cxtmenu": path.resolve(nm, "cytoscape-cxtmenu"),
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
See `sonnet-ui-starter/sonnet-aliases.ts` for a complete reference implementation.
|
|
92
|
+
|
|
93
|
+
---
|
|
94
|
+
|
|
95
|
+
## Basic usage
|
|
96
|
+
|
|
97
|
+
```tsx
|
|
98
|
+
import {
|
|
99
|
+
GraphVisualizer,
|
|
100
|
+
ActionPanel,
|
|
101
|
+
GraphRendererProvider,
|
|
102
|
+
GraphStoresContext,
|
|
103
|
+
createGraphDataStore,
|
|
104
|
+
createGraphFilterStore,
|
|
105
|
+
createGraphExplorationStore,
|
|
106
|
+
createSelectionStore,
|
|
107
|
+
createGraphFocusStore,
|
|
108
|
+
enrichNodes,
|
|
109
|
+
enrichEdges,
|
|
110
|
+
buildColorPalette,
|
|
111
|
+
type RawGraphNode,
|
|
112
|
+
type RawGraphEdge,
|
|
113
|
+
type WorkspaceStores,
|
|
114
|
+
} from "@petrarca/sonnet-graph";
|
|
115
|
+
|
|
116
|
+
// Create stores once (e.g. in a context provider)
|
|
117
|
+
const stores: WorkspaceStores = {
|
|
118
|
+
graphData: createGraphDataStore(),
|
|
119
|
+
graphFilter: createGraphFilterStore(),
|
|
120
|
+
graphExploration: createGraphExplorationStore(),
|
|
121
|
+
selection: createSelectionStore(),
|
|
122
|
+
graphFocus: createGraphFocusStore(),
|
|
123
|
+
};
|
|
124
|
+
|
|
125
|
+
// Render
|
|
126
|
+
function MyGraph() {
|
|
127
|
+
return (
|
|
128
|
+
<GraphStoresContext.Provider value={stores}>
|
|
129
|
+
<GraphRendererProvider defaultRenderer="cytoscape">
|
|
130
|
+
<div style={{ display: "flex", height: 600 }}>
|
|
131
|
+
<GraphVisualizer />
|
|
132
|
+
<ActionPanel />
|
|
133
|
+
</div>
|
|
134
|
+
</GraphRendererProvider>
|
|
135
|
+
</GraphStoresContext.Provider>
|
|
136
|
+
);
|
|
137
|
+
}
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
---
|
|
141
|
+
|
|
142
|
+
## License
|
|
143
|
+
|
|
144
|
+
See [LICENSE.md](../../LICENSE.md).
|
package/dist/index.d.ts
CHANGED
|
@@ -855,4 +855,15 @@ declare function EdgeInfoCard({ edge }: Props): react_jsx_runtime.JSX.Element;
|
|
|
855
855
|
|
|
856
856
|
declare function Overview(): react_jsx_runtime.JSX.Element | null;
|
|
857
857
|
|
|
858
|
-
|
|
858
|
+
interface GraphA11yListProps {
|
|
859
|
+
/** Render on-screen instead of visually-hidden (still a11y-present). */
|
|
860
|
+
visible?: boolean;
|
|
861
|
+
/** Estimated row height in px (virtualization). Default 28. */
|
|
862
|
+
rowHeight?: number;
|
|
863
|
+
/** Max viewport height in px when visible. Default 320. */
|
|
864
|
+
maxHeight?: number;
|
|
865
|
+
className?: string;
|
|
866
|
+
}
|
|
867
|
+
declare function GraphA11yList({ visible, rowHeight, maxHeight, className, }: GraphA11yListProps): react_jsx_runtime.JSX.Element;
|
|
868
|
+
|
|
869
|
+
export { ActionPanel, type ActionPanelState, type ActionPanelStore, type ColorPalette, EMPTY_NORMALIZED, EdgeInfoCard, type EdgeVisual, GraphA11yList, type GraphA11yListProps, type GraphDataHook, type GraphDataStore, type GraphDisplayConfig, type GraphExplorationDeps, type GraphExplorationStore, type GraphFilterStore, type GraphFocusAction, type GraphFocusStore, type GraphProperties, type GraphProperty, type GraphRenderer, GraphRendererProvider, type GraphStatistics, type WorkspaceStores as GraphStoreBundle, GraphStoresContext, GraphVisualizer, type GraphVisualizerProps, type LabelDisplayMap, type LiveGraphDataResult, NodeInfoCard, type NodeVisual, type NormalizedGraph, Overview, type RawGraphEdge, type RawGraphNode, type SelectionStore, type StoreFactory, type VisualGraphEdge, type VisualGraphNode, type VisualGraphNormalized, type WorkspaceStores, buildColorPalette, buildColorPaletteFromNodes, createActionPanelStore, createGraphDataStore, createGraphExplorationStore, createGraphFilterStore, createGraphFocusStore, createSelectionStore, enrichEdge, enrichEdges, enrichNode, enrichNodes, extractDisplayLabel, isRawGraphNode, isVisualEdge, isVisualNode, normalizeGraph, toCytoscapeEdge, toCytoscapeNode, toReagraphEdge, toReagraphNode, useActionPanelStore, useCytoscapeData, useGraphFocus, useGraphRenderer, useLiveGraphData, useReagraphData, useWorkspaceGraphData, useWorkspaceGraphExploration, useWorkspaceGraphFilter, useWorkspaceSelection };
|
package/dist/index.js
CHANGED
|
@@ -3616,14 +3616,13 @@ function NodeInfoCard({ node }) {
|
|
|
3616
3616
|
return /* @__PURE__ */ jsxs9(
|
|
3617
3617
|
Card3,
|
|
3618
3618
|
{
|
|
3619
|
-
className: "w-full rounded-lg overflow-hidden bg-
|
|
3619
|
+
className: "w-full rounded-lg overflow-hidden bg-muted/30 border shadow-none p-3",
|
|
3620
3620
|
style: {
|
|
3621
|
-
background: "#f3f4f6",
|
|
3622
3621
|
borderLeft: `4px solid ${node.visual.color}`
|
|
3623
3622
|
},
|
|
3624
3623
|
children: [
|
|
3625
|
-
/* @__PURE__ */ jsx10("p", { className: "leading-tight font-
|
|
3626
|
-
/* @__PURE__ */ jsx10("p", { className: "leading-tight mb-1", children: node.visual.displayName }),
|
|
3624
|
+
/* @__PURE__ */ jsx10("p", { className: "text-sm leading-tight font-medium mb-0", children: node.label_ }),
|
|
3625
|
+
/* @__PURE__ */ jsx10("p", { className: "text-sm leading-tight mb-1", children: node.visual.displayName }),
|
|
3627
3626
|
/* @__PURE__ */ jsx10(
|
|
3628
3627
|
"p",
|
|
3629
3628
|
{
|
|
@@ -3636,9 +3635,9 @@ function NodeInfoCard({ node }) {
|
|
|
3636
3635
|
/* @__PURE__ */ jsxs9(Collapsible, { open: showProperties, onOpenChange: setShowProperties, children: [
|
|
3637
3636
|
/* @__PURE__ */ jsx10(CollapsibleTrigger, { asChild: true, children: /* @__PURE__ */ jsx10("button", { className: "text-xs cursor-pointer", children: showProperties ? "Hide" : "Show more" }) }),
|
|
3638
3637
|
/* @__PURE__ */ jsx10(CollapsibleContent, { children: /* @__PURE__ */ jsxs9("ul", { className: "list-none mt-2", children: [
|
|
3639
|
-
/* @__PURE__ */ jsx10("p", { className: "text-
|
|
3638
|
+
/* @__PURE__ */ jsx10("p", { className: "text-xs font-medium text-muted-foreground uppercase tracking-wide mb-1", children: "Properties" }),
|
|
3640
3639
|
Object.entries(node.properties_ || {}).map(([key, value]) => /* @__PURE__ */ jsxs9("li", { className: "mb-2 leading-tight", children: [
|
|
3641
|
-
/* @__PURE__ */ jsx10("p", { className: "text-xs text-
|
|
3640
|
+
/* @__PURE__ */ jsx10("p", { className: "text-xs text-muted-foreground uppercase tracking-wide", children: key }),
|
|
3642
3641
|
/* @__PURE__ */ jsx10(
|
|
3643
3642
|
"p",
|
|
3644
3643
|
{
|
|
@@ -3673,15 +3672,14 @@ function EdgeInfoCard({ edge }) {
|
|
|
3673
3672
|
return /* @__PURE__ */ jsxs10(
|
|
3674
3673
|
Card4,
|
|
3675
3674
|
{
|
|
3676
|
-
className: "w-full rounded-lg overflow-hidden bg-
|
|
3675
|
+
className: "w-full rounded-lg overflow-hidden bg-muted/30 border shadow-none p-3",
|
|
3677
3676
|
style: {
|
|
3678
|
-
background: "#f3f4f6",
|
|
3679
3677
|
borderLeft: `4px solid ${edge.visual.color}`
|
|
3680
3678
|
},
|
|
3681
3679
|
children: [
|
|
3682
|
-
/* @__PURE__ */ jsxs10("p", { className: "leading-tight mb-1", children: [
|
|
3683
|
-
/* @__PURE__ */ jsx11(ArrowDown, { className: "inline-block mr-1 opacity-70 align-middle" }),
|
|
3684
|
-
/* @__PURE__ */ jsx11("strong", { className: "font-
|
|
3680
|
+
/* @__PURE__ */ jsxs10("p", { className: "text-sm leading-tight mb-1", children: [
|
|
3681
|
+
/* @__PURE__ */ jsx11(ArrowDown, { className: "inline-block mr-1 opacity-70 align-middle h-3.5 w-3.5" }),
|
|
3682
|
+
/* @__PURE__ */ jsx11("strong", { className: "font-medium align-middle", children: edge.label_ })
|
|
3685
3683
|
] }),
|
|
3686
3684
|
edge.id_ && /* @__PURE__ */ jsx11(
|
|
3687
3685
|
"p",
|
|
@@ -3695,9 +3693,9 @@ function EdgeInfoCard({ edge }) {
|
|
|
3695
3693
|
edge.properties_ && Object.keys(edge.properties_).length > 0 && /* @__PURE__ */ jsxs10(Collapsible2, { open: showProperties, onOpenChange: setShowProperties, children: [
|
|
3696
3694
|
/* @__PURE__ */ jsx11(CollapsibleTrigger2, { asChild: true, children: /* @__PURE__ */ jsx11("button", { className: "text-xs cursor-pointer", children: showProperties ? "Hide" : "Show more" }) }),
|
|
3697
3695
|
/* @__PURE__ */ jsx11(CollapsibleContent2, { children: /* @__PURE__ */ jsxs10("ul", { className: "list-none mt-2", children: [
|
|
3698
|
-
/* @__PURE__ */ jsx11("p", { className: "text-
|
|
3696
|
+
/* @__PURE__ */ jsx11("p", { className: "text-xs font-medium text-muted-foreground uppercase tracking-wide mb-1", children: "Properties" }),
|
|
3699
3697
|
Object.entries(edge.properties_ || {}).map(([key, value]) => /* @__PURE__ */ jsxs10("li", { className: "mb-2 leading-tight", children: [
|
|
3700
|
-
/* @__PURE__ */ jsx11("p", { className: "text-xs text-
|
|
3698
|
+
/* @__PURE__ */ jsx11("p", { className: "text-xs text-muted-foreground uppercase tracking-wide", children: key }),
|
|
3701
3699
|
/* @__PURE__ */ jsx11(
|
|
3702
3700
|
"p",
|
|
3703
3701
|
{
|
|
@@ -3756,7 +3754,7 @@ function AllToggleBadge({
|
|
|
3756
3754
|
return /* @__PURE__ */ jsxs11(
|
|
3757
3755
|
Badge,
|
|
3758
3756
|
{
|
|
3759
|
-
className: "cursor-pointer text-
|
|
3757
|
+
className: "cursor-pointer text-xs px-2.5 py-0.5",
|
|
3760
3758
|
style: {
|
|
3761
3759
|
textTransform: "none",
|
|
3762
3760
|
backgroundColor: bgColor,
|
|
@@ -3791,7 +3789,7 @@ function NodeLabelBadges({
|
|
|
3791
3789
|
return /* @__PURE__ */ jsxs11(
|
|
3792
3790
|
Badge,
|
|
3793
3791
|
{
|
|
3794
|
-
className: "cursor-pointer text-
|
|
3792
|
+
className: "cursor-pointer text-xs px-2.5 py-0.5",
|
|
3795
3793
|
style: {
|
|
3796
3794
|
textTransform: "none",
|
|
3797
3795
|
backgroundColor: bgColor,
|
|
@@ -3829,7 +3827,7 @@ function EdgeLabelBadges({
|
|
|
3829
3827
|
return /* @__PURE__ */ jsxs11(
|
|
3830
3828
|
Badge,
|
|
3831
3829
|
{
|
|
3832
|
-
className: "cursor-pointer text-
|
|
3830
|
+
className: "cursor-pointer text-xs px-2.5 py-0.5",
|
|
3833
3831
|
style: {
|
|
3834
3832
|
textTransform: "none",
|
|
3835
3833
|
backgroundColor: bgColor,
|
|
@@ -3972,7 +3970,7 @@ function Overview() {
|
|
|
3972
3970
|
if (stats && stats.values != null && stats.values > 0) {
|
|
3973
3971
|
return /* @__PURE__ */ jsxs11(Fragment3, { children: [
|
|
3974
3972
|
/* @__PURE__ */ jsx12("p", { className: "mt-2 text-sm font-semibold", children: "Overview" }),
|
|
3975
|
-
/* @__PURE__ */ jsxs11("p", { className: "text-sm text-
|
|
3973
|
+
/* @__PURE__ */ jsxs11("p", { className: "text-sm text-muted-foreground", children: [
|
|
3976
3974
|
formatNumber(stats.values),
|
|
3977
3975
|
" Values"
|
|
3978
3976
|
] })
|
|
@@ -4015,11 +4013,11 @@ function ActionPanel({ actions }) {
|
|
|
4015
4013
|
return /* @__PURE__ */ jsxs12(
|
|
4016
4014
|
Card5,
|
|
4017
4015
|
{
|
|
4018
|
-
className: "h-full min-w-64 flex flex-col bg-
|
|
4016
|
+
className: "h-full min-w-64 flex flex-col bg-card shadow-none p-4",
|
|
4019
4017
|
style: { maxHeight: "100%", overflow: "hidden" },
|
|
4020
4018
|
children: [
|
|
4021
4019
|
actions && /* @__PURE__ */ jsx13("div", { className: "flex-shrink-0 mb-2", children: actions }),
|
|
4022
|
-
/* @__PURE__ */ jsx13("div", { className: "flex-1 overflow-auto pr-1", children: /* @__PURE__ */ jsxs12("div", { className: "flex flex-col gap-
|
|
4020
|
+
/* @__PURE__ */ jsx13("div", { className: "flex-1 overflow-auto pr-1", children: /* @__PURE__ */ jsxs12("div", { className: "flex flex-col gap-3", children: [
|
|
4023
4021
|
firstNode && /* @__PURE__ */ jsx13(NodeInfoCard_default, { node: firstNode }),
|
|
4024
4022
|
hasEdge && selectedEdge && /* @__PURE__ */ jsx13(EdgeInfoCard_default, { edge: selectedEdge }),
|
|
4025
4023
|
secondNode && /* @__PURE__ */ jsx13(NodeInfoCard_default, { node: secondNode }),
|
|
@@ -4030,10 +4028,121 @@ function ActionPanel({ actions }) {
|
|
|
4030
4028
|
);
|
|
4031
4029
|
}
|
|
4032
4030
|
var ActionPanel_default = ActionPanel;
|
|
4031
|
+
|
|
4032
|
+
// src/components/GraphA11yList/GraphA11yList.tsx
|
|
4033
|
+
import { useMemo as useMemo6, useRef as useRef3 } from "react";
|
|
4034
|
+
import { useVirtualizer } from "@tanstack/react-virtual";
|
|
4035
|
+
import { cn as cn2 } from "@petrarca/sonnet-core";
|
|
4036
|
+
import { jsx as jsx14 } from "react/jsx-runtime";
|
|
4037
|
+
var SR_ONLY = "absolute h-px w-px overflow-hidden whitespace-nowrap border-0 p-0 [clip:rect(0,0,0,0)] [clip-path:inset(50%)] -m-px";
|
|
4038
|
+
function GraphA11yList({
|
|
4039
|
+
visible = false,
|
|
4040
|
+
rowHeight = 28,
|
|
4041
|
+
maxHeight = 320,
|
|
4042
|
+
className
|
|
4043
|
+
}) {
|
|
4044
|
+
const live = useLiveGraphData();
|
|
4045
|
+
const useSelection3 = useWorkspaceSelection();
|
|
4046
|
+
const selectedNodeIds = useSelection3(
|
|
4047
|
+
(s) => s.selectedNodeIds
|
|
4048
|
+
);
|
|
4049
|
+
const selectedEdge = useSelection3((s) => s.selectedEdge);
|
|
4050
|
+
const setSelectedNodeIds = useSelection3(
|
|
4051
|
+
(s) => s.setSelectedNodeIds
|
|
4052
|
+
);
|
|
4053
|
+
const setSelectedEdge = useSelection3(
|
|
4054
|
+
(s) => s.setSelectedEdge
|
|
4055
|
+
);
|
|
4056
|
+
const rows = useMemo6(() => {
|
|
4057
|
+
const nodeRows = live.nodes.map((n) => ({
|
|
4058
|
+
kind: "node",
|
|
4059
|
+
id: String(n.id_),
|
|
4060
|
+
label: n.visual?.displayName || n.label_ || String(n.id_),
|
|
4061
|
+
node: n
|
|
4062
|
+
}));
|
|
4063
|
+
const edgeRows = live.edges.map((e) => ({
|
|
4064
|
+
kind: "edge",
|
|
4065
|
+
id: String(e.id_),
|
|
4066
|
+
label: e.label_ || String(e.id_),
|
|
4067
|
+
edge: e
|
|
4068
|
+
}));
|
|
4069
|
+
return [...nodeRows, ...edgeRows];
|
|
4070
|
+
}, [live.nodes, live.edges]);
|
|
4071
|
+
const parentRef = useRef3(null);
|
|
4072
|
+
const virtualizer = useVirtualizer({
|
|
4073
|
+
count: rows.length,
|
|
4074
|
+
getScrollElement: () => parentRef.current,
|
|
4075
|
+
estimateSize: () => rowHeight,
|
|
4076
|
+
overscan: 8
|
|
4077
|
+
});
|
|
4078
|
+
const selectRow = (row) => {
|
|
4079
|
+
if (row.kind === "node") {
|
|
4080
|
+
setSelectedEdge(null);
|
|
4081
|
+
setSelectedNodeIds([row.id]);
|
|
4082
|
+
} else {
|
|
4083
|
+
setSelectedNodeIds([]);
|
|
4084
|
+
setSelectedEdge(row.edge);
|
|
4085
|
+
}
|
|
4086
|
+
};
|
|
4087
|
+
const isSelected = (row) => row.kind === "node" ? selectedNodeIds.includes(row.id) : selectedEdge?.id_ === row.edge.id_;
|
|
4088
|
+
return /* @__PURE__ */ jsx14(
|
|
4089
|
+
"div",
|
|
4090
|
+
{
|
|
4091
|
+
role: "listbox",
|
|
4092
|
+
"aria-label": "Graph elements",
|
|
4093
|
+
className: cn2(visible ? "rounded-md border" : SR_ONLY, className),
|
|
4094
|
+
children: /* @__PURE__ */ jsx14(
|
|
4095
|
+
"div",
|
|
4096
|
+
{
|
|
4097
|
+
ref: parentRef,
|
|
4098
|
+
style: { maxHeight: visible ? maxHeight : void 0, overflow: "auto" },
|
|
4099
|
+
children: /* @__PURE__ */ jsx14(
|
|
4100
|
+
"div",
|
|
4101
|
+
{
|
|
4102
|
+
style: {
|
|
4103
|
+
height: `${virtualizer.getTotalSize()}px`,
|
|
4104
|
+
width: "100%",
|
|
4105
|
+
position: "relative"
|
|
4106
|
+
},
|
|
4107
|
+
children: virtualizer.getVirtualItems().map((vi) => {
|
|
4108
|
+
const row = rows[vi.index];
|
|
4109
|
+
if (!row) return null;
|
|
4110
|
+
const selected = isSelected(row);
|
|
4111
|
+
return /* @__PURE__ */ jsx14(
|
|
4112
|
+
"button",
|
|
4113
|
+
{
|
|
4114
|
+
type: "button",
|
|
4115
|
+
role: "option",
|
|
4116
|
+
"aria-selected": selected,
|
|
4117
|
+
"aria-label": `${row.kind === "node" ? "Node" : "Edge"} ${row.label}`,
|
|
4118
|
+
"data-testid": `graph-${row.kind}-${row.id}`,
|
|
4119
|
+
...row.kind === "node" ? { "data-graph-node-id": row.id } : { "data-graph-edge-id": row.id },
|
|
4120
|
+
onClick: () => selectRow(row),
|
|
4121
|
+
className: cn2(
|
|
4122
|
+
"absolute left-0 top-0 flex w-full items-center px-2 text-left text-sm",
|
|
4123
|
+
visible && "hover:bg-accent aria-selected:bg-state-selected aria-selected:text-foreground"
|
|
4124
|
+
),
|
|
4125
|
+
style: {
|
|
4126
|
+
height: `${vi.size}px`,
|
|
4127
|
+
transform: `translateY(${vi.start}px)`
|
|
4128
|
+
},
|
|
4129
|
+
children: /* @__PURE__ */ jsx14("span", { className: "truncate", children: row.label })
|
|
4130
|
+
},
|
|
4131
|
+
vi.key
|
|
4132
|
+
);
|
|
4133
|
+
})
|
|
4134
|
+
}
|
|
4135
|
+
)
|
|
4136
|
+
}
|
|
4137
|
+
)
|
|
4138
|
+
}
|
|
4139
|
+
);
|
|
4140
|
+
}
|
|
4033
4141
|
export {
|
|
4034
4142
|
ActionPanel_default as ActionPanel,
|
|
4035
4143
|
EMPTY_NORMALIZED,
|
|
4036
4144
|
EdgeInfoCard_default as EdgeInfoCard,
|
|
4145
|
+
GraphA11yList,
|
|
4037
4146
|
GraphRendererProvider,
|
|
4038
4147
|
GraphStoresContext,
|
|
4039
4148
|
GraphVisualizer_default as GraphVisualizer,
|