@petrarca/sonnet-playground 0.1.5 → 0.2.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,8 @@
1
+ import {
2
+ PlayGraph
3
+ } from "./chunk-PGI54O43.js";
4
+ import "./chunk-FTN2A5YL.js";
5
+ export {
6
+ PlayGraph as default
7
+ };
8
+ //# sourceMappingURL=PlayGraph-FLGLSUWV.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
@@ -0,0 +1,321 @@
1
+ import {
2
+ PlaygroundSection
3
+ } from "./chunk-FTN2A5YL.js";
4
+
5
+ // src/pages/PlayGraph.tsx
6
+ import { useCallback, useState } from "react";
7
+ import {
8
+ GraphVisualizer,
9
+ ActionPanel,
10
+ GraphRendererProvider,
11
+ GraphStoresContext,
12
+ createGraphDataStore,
13
+ createGraphFilterStore,
14
+ createGraphExplorationStore,
15
+ createSelectionStore,
16
+ createGraphFocusStore,
17
+ enrichNodes,
18
+ enrichEdges,
19
+ buildColorPalette
20
+ } from "@petrarca/sonnet-graph";
21
+ import {
22
+ Button,
23
+ Alert,
24
+ AlertDescription,
25
+ Tabs,
26
+ TabsContent,
27
+ TabsList,
28
+ TabsTrigger
29
+ } from "@petrarca/sonnet-ui";
30
+ import { Play, RotateCcw } from "lucide-react";
31
+ import { jsx, jsxs } from "react/jsx-runtime";
32
+ var MOCK_NODES = [
33
+ {
34
+ id_: 1,
35
+ label_: "Company",
36
+ properties_: { name: "Acme Corp", founded: 1985, industry: "Technology" }
37
+ },
38
+ {
39
+ id_: 2,
40
+ label_: "Department",
41
+ properties_: { name: "Engineering", headcount: 42 }
42
+ },
43
+ {
44
+ id_: 3,
45
+ label_: "Department",
46
+ properties_: { name: "Marketing", headcount: 18 }
47
+ },
48
+ {
49
+ id_: 4,
50
+ label_: "Department",
51
+ properties_: { name: "Sales", headcount: 25 }
52
+ },
53
+ {
54
+ id_: 5,
55
+ label_: "Person",
56
+ properties_: { name: "Alice Chen", role: "CTO" }
57
+ },
58
+ {
59
+ id_: 6,
60
+ label_: "Person",
61
+ properties_: { name: "Bob Smith", role: "VP Engineering" }
62
+ },
63
+ {
64
+ id_: 7,
65
+ label_: "Person",
66
+ properties_: { name: "Carol Davis", role: "CMO" }
67
+ },
68
+ {
69
+ id_: 8,
70
+ label_: "Person",
71
+ properties_: { name: "Dave Wilson", role: "VP Sales" }
72
+ },
73
+ {
74
+ id_: 9,
75
+ label_: "Person",
76
+ properties_: { name: "Eve Johnson", role: "Senior Engineer" }
77
+ },
78
+ {
79
+ id_: 10,
80
+ label_: "Person",
81
+ properties_: { name: "Frank Brown", role: "Product Manager" }
82
+ },
83
+ {
84
+ id_: 11,
85
+ label_: "Product",
86
+ properties_: { name: "CloudSuite", version: "3.2", status: "GA" }
87
+ },
88
+ {
89
+ id_: 12,
90
+ label_: "Product",
91
+ properties_: { name: "DataPipeline", version: "1.0", status: "Beta" }
92
+ }
93
+ ];
94
+ var MOCK_EDGES = [
95
+ {
96
+ id_: 101,
97
+ label_: "HAS_DEPARTMENT",
98
+ start_id_: 1,
99
+ end_id_: 2,
100
+ properties_: {}
101
+ },
102
+ {
103
+ id_: 102,
104
+ label_: "HAS_DEPARTMENT",
105
+ start_id_: 1,
106
+ end_id_: 3,
107
+ properties_: {}
108
+ },
109
+ {
110
+ id_: 103,
111
+ label_: "HAS_DEPARTMENT",
112
+ start_id_: 1,
113
+ end_id_: 4,
114
+ properties_: {}
115
+ },
116
+ {
117
+ id_: 104,
118
+ label_: "LEADS",
119
+ start_id_: 5,
120
+ end_id_: 2,
121
+ properties_: { since: 2019 }
122
+ },
123
+ {
124
+ id_: 105,
125
+ label_: "WORKS_IN",
126
+ start_id_: 6,
127
+ end_id_: 2,
128
+ properties_: { since: 2020 }
129
+ },
130
+ {
131
+ id_: 106,
132
+ label_: "LEADS",
133
+ start_id_: 7,
134
+ end_id_: 3,
135
+ properties_: { since: 2021 }
136
+ },
137
+ {
138
+ id_: 107,
139
+ label_: "LEADS",
140
+ start_id_: 8,
141
+ end_id_: 4,
142
+ properties_: { since: 2018 }
143
+ },
144
+ {
145
+ id_: 108,
146
+ label_: "WORKS_IN",
147
+ start_id_: 9,
148
+ end_id_: 2,
149
+ properties_: { since: 2022 }
150
+ },
151
+ {
152
+ id_: 109,
153
+ label_: "WORKS_IN",
154
+ start_id_: 10,
155
+ end_id_: 2,
156
+ properties_: { since: 2021 }
157
+ },
158
+ { id_: 110, label_: "REPORTS_TO", start_id_: 6, end_id_: 5, properties_: {} },
159
+ { id_: 111, label_: "REPORTS_TO", start_id_: 9, end_id_: 6, properties_: {} },
160
+ {
161
+ id_: 112,
162
+ label_: "REPORTS_TO",
163
+ start_id_: 10,
164
+ end_id_: 6,
165
+ properties_: {}
166
+ },
167
+ { id_: 113, label_: "OWNS", start_id_: 2, end_id_: 11, properties_: {} },
168
+ { id_: 114, label_: "OWNS", start_id_: 2, end_id_: 12, properties_: {} }
169
+ ];
170
+ function createPlaygroundStores() {
171
+ const graphFilter = createGraphFilterStore();
172
+ const graphData = createGraphDataStore();
173
+ const selection = createSelectionStore();
174
+ const graphFocus = createGraphFocusStore();
175
+ const graphExploration = createGraphExplorationStore({
176
+ graphData,
177
+ selection,
178
+ graphFocus,
179
+ graphFilter,
180
+ // Static data -- no server expansion available in the playground
181
+ expandNode: async () => ({ nodes: [], edges: [] }),
182
+ getNodes: async () => []
183
+ });
184
+ return { graphFilter, graphData, graphExploration, selection };
185
+ }
186
+ var PLAYGROUND_STORES = createPlaygroundStores();
187
+ var INITIAL_DATA = { nodes: MOCK_NODES, edges: MOCK_EDGES };
188
+ function serializeGraphData(data) {
189
+ return JSON.stringify(data, null, 2);
190
+ }
191
+ function validateNode(n, i) {
192
+ if (!n || typeof n !== "object") return `nodes[${i}] must be an object`;
193
+ const node = n;
194
+ if (node.id_ === void 0) return `nodes[${i}] is missing id_`;
195
+ if (typeof node.label_ !== "string") return `nodes[${i}] is missing label_`;
196
+ return null;
197
+ }
198
+ function validateEdge(e, i) {
199
+ if (!e || typeof e !== "object") return `edges[${i}] must be an object`;
200
+ const edge = e;
201
+ if (edge.id_ === void 0) return `edges[${i}] is missing id_`;
202
+ if (typeof edge.label_ !== "string") return `edges[${i}] is missing label_`;
203
+ if (edge.start_id_ === void 0) return `edges[${i}] is missing start_id_`;
204
+ if (edge.end_id_ === void 0) return `edges[${i}] is missing end_id_`;
205
+ return null;
206
+ }
207
+ function validateGraphInput(value) {
208
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
209
+ return "JSON must be an object with nodes and edges arrays";
210
+ }
211
+ const obj = value;
212
+ if (!Array.isArray(obj.nodes)) return '"nodes" must be an array';
213
+ if (!Array.isArray(obj.edges)) return '"edges" must be an array';
214
+ for (const [i, n] of obj.nodes.entries()) {
215
+ const err = validateNode(n, i);
216
+ if (err) return err;
217
+ }
218
+ for (const [i, e] of obj.edges.entries()) {
219
+ const err = validateEdge(e, i);
220
+ if (err) return err;
221
+ }
222
+ return null;
223
+ }
224
+ function loadIntoStore(stores, data) {
225
+ const labelCounts = {};
226
+ for (const n of data.nodes) {
227
+ labelCounts[n.label_] = (labelCounts[n.label_] ?? 0) + 1;
228
+ }
229
+ const palette = buildColorPalette(labelCounts);
230
+ const nodes = enrichNodes(data.nodes, palette);
231
+ const edges = enrichEdges(data.edges, palette);
232
+ stores.graphFilter.getState().resetFilters();
233
+ stores.graphData.getState().setQueryData(nodes, edges, {
234
+ nodes: nodes.length,
235
+ edges: edges.length
236
+ });
237
+ stores.graphFilter.getState().notifyDataChange();
238
+ }
239
+ loadIntoStore(PLAYGROUND_STORES, INITIAL_DATA);
240
+ function PlayGraph() {
241
+ const [jsonText, setJsonText] = useState(
242
+ () => serializeGraphData(INITIAL_DATA)
243
+ );
244
+ const [parseError, setParseError] = useState(null);
245
+ const handleApply = useCallback(() => {
246
+ let parsed;
247
+ try {
248
+ parsed = JSON.parse(jsonText);
249
+ } catch (e) {
250
+ setParseError(e instanceof Error ? e.message : "Invalid JSON");
251
+ return;
252
+ }
253
+ const validationError = validateGraphInput(parsed);
254
+ if (validationError) {
255
+ setParseError(validationError);
256
+ return;
257
+ }
258
+ setParseError(null);
259
+ loadIntoStore(PLAYGROUND_STORES, parsed);
260
+ }, [jsonText]);
261
+ const handleReset = useCallback(() => {
262
+ setJsonText(serializeGraphData(INITIAL_DATA));
263
+ setParseError(null);
264
+ loadIntoStore(PLAYGROUND_STORES, INITIAL_DATA);
265
+ }, []);
266
+ const handleKeyDown = useCallback(
267
+ (e) => {
268
+ if ((e.metaKey || e.ctrlKey) && e.key === "Enter") {
269
+ e.preventDefault();
270
+ handleApply();
271
+ }
272
+ },
273
+ [handleApply]
274
+ );
275
+ return /* @__PURE__ */ jsx(
276
+ PlaygroundSection,
277
+ {
278
+ title: "Graph Visualization",
279
+ description: "Interactive property graph with dual renderer support. Edit the JSON data and apply to re-render.",
280
+ children: /* @__PURE__ */ jsx(GraphStoresContext.Provider, { value: PLAYGROUND_STORES, children: /* @__PURE__ */ jsxs(Tabs, { defaultValue: "graph", className: "space-y-3", children: [
281
+ /* @__PURE__ */ jsxs(TabsList, { children: [
282
+ /* @__PURE__ */ jsx(TabsTrigger, { value: "graph", children: "Graph" }),
283
+ /* @__PURE__ */ jsx(TabsTrigger, { value: "data", children: "Data" })
284
+ ] }),
285
+ /* @__PURE__ */ jsx(TabsContent, { value: "graph", className: "mt-0", children: /* @__PURE__ */ jsx(GraphRendererProvider, { defaultRenderer: "cytoscape", children: /* @__PURE__ */ jsxs("div", { className: "flex border rounded-lg overflow-hidden h-[600px]", children: [
286
+ /* @__PURE__ */ jsx("div", { className: "flex-1 min-w-0", children: /* @__PURE__ */ jsx(GraphVisualizer, {}) }),
287
+ /* @__PURE__ */ jsx("div", { className: "w-[300px] flex-shrink-0 border-l", children: /* @__PURE__ */ jsx(ActionPanel, {}) })
288
+ ] }) }) }),
289
+ /* @__PURE__ */ jsx(TabsContent, { value: "data", className: "mt-0", children: /* @__PURE__ */ jsxs("div", { className: "space-y-3", children: [
290
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
291
+ /* @__PURE__ */ jsxs(Button, { size: "sm", onClick: handleApply, children: [
292
+ /* @__PURE__ */ jsx(Play, { className: "h-4 w-4 mr-1" }),
293
+ "Apply"
294
+ ] }),
295
+ /* @__PURE__ */ jsxs(Button, { size: "sm", variant: "outline", onClick: handleReset, children: [
296
+ /* @__PURE__ */ jsx(RotateCcw, { className: "h-4 w-4 mr-1" }),
297
+ "Reset"
298
+ ] }),
299
+ /* @__PURE__ */ jsx("span", { className: "text-xs text-muted-foreground ml-2", children: "Cmd+Enter to apply" })
300
+ ] }),
301
+ parseError && /* @__PURE__ */ jsx(Alert, { variant: "destructive", children: /* @__PURE__ */ jsx(AlertDescription, { children: parseError }) }),
302
+ /* @__PURE__ */ jsx(
303
+ "textarea",
304
+ {
305
+ value: jsonText,
306
+ onChange: (e) => setJsonText(e.target.value),
307
+ onKeyDown: handleKeyDown,
308
+ spellCheck: false,
309
+ className: "w-full h-[600px] font-mono text-xs p-3 border rounded-lg bg-muted/30 resize-y focus:outline-none focus:ring-2 focus:ring-ring"
310
+ }
311
+ )
312
+ ] }) })
313
+ ] }) })
314
+ }
315
+ );
316
+ }
317
+
318
+ export {
319
+ PlayGraph
320
+ };
321
+ //# sourceMappingURL=chunk-PGI54O43.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/pages/PlayGraph.tsx"],"sourcesContent":["/**\n * Playground page for @petrarca/sonnet-graph.\n * Accessible at /playground/graph\n *\n * Demonstrates graph visualization with static mock data -- no backend required.\n * Uses the GraphStoresContext provider pattern that consumers like explorer\n * and Atlas would use to wire their own stores.\n */\n\nimport React, { useCallback, useState } from \"react\";\nimport {\n GraphVisualizer,\n ActionPanel,\n GraphRendererProvider,\n GraphStoresContext,\n createGraphDataStore,\n createGraphFilterStore,\n createGraphExplorationStore,\n createSelectionStore,\n createGraphFocusStore,\n enrichNodes,\n enrichEdges,\n buildColorPalette,\n type RawGraphNode,\n type RawGraphEdge,\n type WorkspaceStores,\n} from \"@petrarca/sonnet-graph\";\nimport {\n Button,\n Alert,\n AlertDescription,\n Tabs,\n TabsContent,\n TabsList,\n TabsTrigger,\n} from \"@petrarca/sonnet-ui\";\nimport { Play, RotateCcw } from \"lucide-react\";\nimport { PlaygroundSection } from \"../PlaygroundSection\";\n\n// ---------------------------------------------------------------------------\n// Mock data -- a small org hierarchy\n// ---------------------------------------------------------------------------\n\nconst MOCK_NODES: RawGraphNode[] = [\n {\n id_: 1,\n label_: \"Company\",\n properties_: { name: \"Acme Corp\", founded: 1985, industry: \"Technology\" },\n },\n {\n id_: 2,\n label_: \"Department\",\n properties_: { name: \"Engineering\", headcount: 42 },\n },\n {\n id_: 3,\n label_: \"Department\",\n properties_: { name: \"Marketing\", headcount: 18 },\n },\n {\n id_: 4,\n label_: \"Department\",\n properties_: { name: \"Sales\", headcount: 25 },\n },\n {\n id_: 5,\n label_: \"Person\",\n properties_: { name: \"Alice Chen\", role: \"CTO\" },\n },\n {\n id_: 6,\n label_: \"Person\",\n properties_: { name: \"Bob Smith\", role: \"VP Engineering\" },\n },\n {\n id_: 7,\n label_: \"Person\",\n properties_: { name: \"Carol Davis\", role: \"CMO\" },\n },\n {\n id_: 8,\n label_: \"Person\",\n properties_: { name: \"Dave Wilson\", role: \"VP Sales\" },\n },\n {\n id_: 9,\n label_: \"Person\",\n properties_: { name: \"Eve Johnson\", role: \"Senior Engineer\" },\n },\n {\n id_: 10,\n label_: \"Person\",\n properties_: { name: \"Frank Brown\", role: \"Product Manager\" },\n },\n {\n id_: 11,\n label_: \"Product\",\n properties_: { name: \"CloudSuite\", version: \"3.2\", status: \"GA\" },\n },\n {\n id_: 12,\n label_: \"Product\",\n properties_: { name: \"DataPipeline\", version: \"1.0\", status: \"Beta\" },\n },\n];\n\nconst MOCK_EDGES: RawGraphEdge[] = [\n {\n id_: 101,\n label_: \"HAS_DEPARTMENT\",\n start_id_: 1,\n end_id_: 2,\n properties_: {},\n },\n {\n id_: 102,\n label_: \"HAS_DEPARTMENT\",\n start_id_: 1,\n end_id_: 3,\n properties_: {},\n },\n {\n id_: 103,\n label_: \"HAS_DEPARTMENT\",\n start_id_: 1,\n end_id_: 4,\n properties_: {},\n },\n {\n id_: 104,\n label_: \"LEADS\",\n start_id_: 5,\n end_id_: 2,\n properties_: { since: 2019 },\n },\n {\n id_: 105,\n label_: \"WORKS_IN\",\n start_id_: 6,\n end_id_: 2,\n properties_: { since: 2020 },\n },\n {\n id_: 106,\n label_: \"LEADS\",\n start_id_: 7,\n end_id_: 3,\n properties_: { since: 2021 },\n },\n {\n id_: 107,\n label_: \"LEADS\",\n start_id_: 8,\n end_id_: 4,\n properties_: { since: 2018 },\n },\n {\n id_: 108,\n label_: \"WORKS_IN\",\n start_id_: 9,\n end_id_: 2,\n properties_: { since: 2022 },\n },\n {\n id_: 109,\n label_: \"WORKS_IN\",\n start_id_: 10,\n end_id_: 2,\n properties_: { since: 2021 },\n },\n { id_: 110, label_: \"REPORTS_TO\", start_id_: 6, end_id_: 5, properties_: {} },\n { id_: 111, label_: \"REPORTS_TO\", start_id_: 9, end_id_: 6, properties_: {} },\n {\n id_: 112,\n label_: \"REPORTS_TO\",\n start_id_: 10,\n end_id_: 6,\n properties_: {},\n },\n { id_: 113, label_: \"OWNS\", start_id_: 2, end_id_: 11, properties_: {} },\n { id_: 114, label_: \"OWNS\", start_id_: 2, end_id_: 12, properties_: {} },\n];\n\n// ---------------------------------------------------------------------------\n// Store setup\n//\n// Stores are created once at module load, not inside the component.\n// This avoids re-creation on re-render and removes the need for useMemo.\n// ---------------------------------------------------------------------------\n\nfunction createPlaygroundStores(): WorkspaceStores {\n const graphFilter = createGraphFilterStore();\n const graphData = createGraphDataStore();\n const selection = createSelectionStore();\n const graphFocus = createGraphFocusStore();\n const graphExploration = createGraphExplorationStore({\n graphData,\n selection,\n graphFocus,\n graphFilter,\n // Static data -- no server expansion available in the playground\n expandNode: async () => ({ nodes: [], edges: [] }),\n getNodes: async () => [],\n });\n return { graphFilter, graphData, graphExploration, selection };\n}\n\nconst PLAYGROUND_STORES = createPlaygroundStores();\n\n// ---------------------------------------------------------------------------\n// Data helpers\n// ---------------------------------------------------------------------------\n\ninterface GraphInput {\n nodes: RawGraphNode[];\n edges: RawGraphEdge[];\n}\n\nconst INITIAL_DATA: GraphInput = { nodes: MOCK_NODES, edges: MOCK_EDGES };\n\nfunction serializeGraphData(data: GraphInput): string {\n return JSON.stringify(data, null, 2);\n}\n\nfunction validateNode(n: unknown, i: number): string | null {\n if (!n || typeof n !== \"object\") return `nodes[${i}] must be an object`;\n const node = n as Record<string, unknown>;\n if (node.id_ === undefined) return `nodes[${i}] is missing id_`;\n if (typeof node.label_ !== \"string\") return `nodes[${i}] is missing label_`;\n return null;\n}\n\nfunction validateEdge(e: unknown, i: number): string | null {\n if (!e || typeof e !== \"object\") return `edges[${i}] must be an object`;\n const edge = e as Record<string, unknown>;\n if (edge.id_ === undefined) return `edges[${i}] is missing id_`;\n if (typeof edge.label_ !== \"string\") return `edges[${i}] is missing label_`;\n if (edge.start_id_ === undefined) return `edges[${i}] is missing start_id_`;\n if (edge.end_id_ === undefined) return `edges[${i}] is missing end_id_`;\n return null;\n}\n\n/** Validates that parsed JSON is a usable GraphInput. Returns an error string or null. */\nfunction validateGraphInput(value: unknown): string | null {\n if (!value || typeof value !== \"object\" || Array.isArray(value)) {\n return \"JSON must be an object with nodes and edges arrays\";\n }\n const obj = value as Record<string, unknown>;\n if (!Array.isArray(obj.nodes)) return '\"nodes\" must be an array';\n if (!Array.isArray(obj.edges)) return '\"edges\" must be an array';\n for (const [i, n] of (obj.nodes as unknown[]).entries()) {\n const err = validateNode(n, i);\n if (err) return err;\n }\n for (const [i, e] of (obj.edges as unknown[]).entries()) {\n const err = validateEdge(e, i);\n if (err) return err;\n }\n return null;\n}\n\nfunction loadIntoStore(stores: WorkspaceStores, data: GraphInput) {\n const labelCounts: Record<string, number> = {};\n for (const n of data.nodes) {\n labelCounts[n.label_] = (labelCounts[n.label_] ?? 0) + 1;\n }\n const palette = buildColorPalette(labelCounts);\n const nodes = enrichNodes(data.nodes, palette);\n const edges = enrichEdges(data.edges, palette);\n stores.graphFilter.getState().resetFilters();\n stores.graphData.getState().setQueryData(nodes, edges, {\n nodes: nodes.length,\n edges: edges.length,\n });\n // Signal renderers to re-fit layout after data change\n stores.graphFilter.getState().notifyDataChange();\n}\n\n// Load initial data immediately -- no effect needed, no empty render cycle\nloadIntoStore(PLAYGROUND_STORES, INITIAL_DATA);\n\n// ---------------------------------------------------------------------------\n// Component\n// ---------------------------------------------------------------------------\n\nexport default function PlayGraph(): React.ReactElement {\n const [jsonText, setJsonText] = useState(() =>\n serializeGraphData(INITIAL_DATA),\n );\n const [parseError, setParseError] = useState<string | null>(null);\n\n const handleApply = useCallback(() => {\n let parsed: unknown;\n try {\n parsed = JSON.parse(jsonText);\n } catch (e) {\n setParseError(e instanceof Error ? e.message : \"Invalid JSON\");\n return;\n }\n const validationError = validateGraphInput(parsed);\n if (validationError) {\n setParseError(validationError);\n return;\n }\n setParseError(null);\n loadIntoStore(PLAYGROUND_STORES, parsed as GraphInput);\n }, [jsonText]);\n\n const handleReset = useCallback(() => {\n setJsonText(serializeGraphData(INITIAL_DATA));\n setParseError(null);\n loadIntoStore(PLAYGROUND_STORES, INITIAL_DATA);\n }, []);\n\n const handleKeyDown = useCallback(\n (e: React.KeyboardEvent) => {\n if ((e.metaKey || e.ctrlKey) && e.key === \"Enter\") {\n e.preventDefault();\n handleApply();\n }\n },\n [handleApply],\n );\n\n return (\n <PlaygroundSection\n title=\"Graph Visualization\"\n description=\"Interactive property graph with dual renderer support. Edit the JSON data and apply to re-render.\"\n >\n <GraphStoresContext.Provider value={PLAYGROUND_STORES}>\n <Tabs defaultValue=\"graph\" className=\"space-y-3\">\n <TabsList>\n <TabsTrigger value=\"graph\">Graph</TabsTrigger>\n <TabsTrigger value=\"data\">Data</TabsTrigger>\n </TabsList>\n\n <TabsContent value=\"graph\" className=\"mt-0\">\n <GraphRendererProvider defaultRenderer=\"cytoscape\">\n <div className=\"flex border rounded-lg overflow-hidden h-[600px]\">\n <div className=\"flex-1 min-w-0\">\n <GraphVisualizer />\n </div>\n <div className=\"w-[300px] flex-shrink-0 border-l\">\n <ActionPanel />\n </div>\n </div>\n </GraphRendererProvider>\n </TabsContent>\n\n <TabsContent value=\"data\" className=\"mt-0\">\n <div className=\"space-y-3\">\n <div className=\"flex items-center gap-2\">\n <Button size=\"sm\" onClick={handleApply}>\n <Play className=\"h-4 w-4 mr-1\" />\n Apply\n </Button>\n <Button size=\"sm\" variant=\"outline\" onClick={handleReset}>\n <RotateCcw className=\"h-4 w-4 mr-1\" />\n Reset\n </Button>\n <span className=\"text-xs text-muted-foreground ml-2\">\n Cmd+Enter to apply\n </span>\n </div>\n {parseError && (\n <Alert variant=\"destructive\">\n <AlertDescription>{parseError}</AlertDescription>\n </Alert>\n )}\n <textarea\n value={jsonText}\n onChange={(e) => setJsonText(e.target.value)}\n onKeyDown={handleKeyDown}\n spellCheck={false}\n className=\"w-full h-[600px] font-mono text-xs p-3 border rounded-lg bg-muted/30 resize-y focus:outline-none focus:ring-2 focus:ring-ring\"\n />\n </div>\n </TabsContent>\n </Tabs>\n </GraphStoresContext.Provider>\n </PlaygroundSection>\n );\n}\n"],"mappings":"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","names":[]}
package/dist/index.js CHANGED
@@ -83,7 +83,8 @@ import {
83
83
  Check,
84
84
  Edit,
85
85
  Package,
86
- Table2
86
+ Table2,
87
+ Network
87
88
  } from "lucide-react";
88
89
  var builtinEntries = [
89
90
  {
@@ -173,6 +174,17 @@ var builtinEntries = [
173
174
  component: lazy(() => import("./PlayDataComponents-GZSRTW4F.js")),
174
175
  group: "Data",
175
176
  order: 0
177
+ },
178
+ {
179
+ id: "sonnet.graph",
180
+ title: "Graph Visualization",
181
+ description: "Interactive property graph visualization with dual renderer support (Cytoscape, Reagraph). Org hierarchy demo with filtering, selection, and exploration.",
182
+ icon: Network,
183
+ color: "cyan",
184
+ path: "graph",
185
+ component: lazy(() => import("./PlayGraph-FLGLSUWV.js")),
186
+ group: "Graph",
187
+ order: 0
176
188
  }
177
189
  ];
178
190
 
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/PlaygroundRegistry.ts","../src/builtinEntries.ts","../src/createPlaygroundModule.tsx","../src/PlaygroundOverview.tsx","../src/index.ts"],"sourcesContent":["/**\n * PlaygroundRegistry -- mutable collection of playground entries.\n *\n * The library ships a default instance pre-populated with the built-in\n * sonnet component demos. Consumers register additional entries for\n * domain-specific playgrounds before passing the registry to\n * createPlaygroundModule().\n */\nimport type { PlaygroundEntry } from \"./types\";\n\nexport class PlaygroundRegistry {\n private entries: Map<string, PlaygroundEntry> = new Map();\n\n /** Register a playground entry. Overwrites any existing entry with the same id. */\n register(entry: PlaygroundEntry): void {\n this.entries.set(entry.id, entry);\n }\n\n /** Register multiple entries at once. */\n registerAll(entries: PlaygroundEntry[]): void {\n for (const entry of entries) {\n this.entries.set(entry.id, entry);\n }\n }\n\n /** Remove an entry by id. Returns true if it existed. */\n unregister(id: string): boolean {\n return this.entries.delete(id);\n }\n\n /** Get a single entry by id. */\n get(id: string): PlaygroundEntry | undefined {\n return this.entries.get(id);\n }\n\n /** Fallback group label for entries with no group defined. */\n static readonly DEFAULT_GROUP = \"General\";\n\n /**\n * All registered entries, sorted by group registration order then\n * by `order` within each group.\n */\n getAll(): PlaygroundEntry[] {\n const groupOrder = this.getGroupOrder();\n return [...this.entries.values()].sort((a, b) => {\n const groupA = a.group ?? PlaygroundRegistry.DEFAULT_GROUP;\n const groupB = b.group ?? PlaygroundRegistry.DEFAULT_GROUP;\n if (groupA !== groupB) {\n return (\n (groupOrder.get(groupA) ?? 999) - (groupOrder.get(groupB) ?? 999)\n );\n }\n return (a.order ?? 0) - (b.order ?? 0);\n });\n }\n\n /**\n * Entries grouped by their group label.\n * Returns an array of [groupLabel, entries[]] tuples, preserving\n * first-seen registration order for groups and `order` within each group.\n */\n getGrouped(): Array<[string, PlaygroundEntry[]]> {\n const grouped = new Map<string, PlaygroundEntry[]>();\n for (const entry of this.getAll()) {\n const group = entry.group ?? PlaygroundRegistry.DEFAULT_GROUP;\n const list = grouped.get(group) ?? [];\n list.push(entry);\n grouped.set(group, list);\n }\n return [...grouped.entries()];\n }\n\n /** Map of group name → first-seen index (registration order). */\n private getGroupOrder(): Map<string, number> {\n const order = new Map<string, number>();\n let idx = 0;\n for (const entry of this.entries.values()) {\n const group = entry.group ?? PlaygroundRegistry.DEFAULT_GROUP;\n if (!order.has(group)) {\n order.set(group, idx++);\n }\n }\n return order;\n }\n\n /** Number of registered entries. */\n get size(): number {\n return this.entries.size;\n }\n}\n","/**\n * Built-in playground entries for the sonnet component library.\n *\n * These entries demonstrate @petrarca/sonnet-* components with static\n * mock data -- no application backend required. Each page is lazy-loaded.\n */\nimport { lazy } from \"react\";\nimport {\n Type,\n Palette,\n Grid,\n Braces,\n Check,\n Edit,\n Package,\n Table2,\n} from \"lucide-react\";\nimport type { PlaygroundEntry } from \"./types\";\n\nexport const builtinEntries: PlaygroundEntry[] = [\n {\n id: \"sonnet.typography\",\n title: \"Typography\",\n description:\n \"Living style-guide for the typography system. Font families, type scale, weights, heading hierarchy, color tiers, and component patterns.\",\n icon: Type,\n color: \"teal\",\n path: \"typography\",\n component: lazy(() => import(\"./pages/PlayTypography\")),\n group: \"Design System\",\n order: 0,\n },\n {\n id: \"sonnet.color-palette\",\n title: \"Color Palette\",\n description:\n \"Living reference for the color system. Semantic tokens, extended palette, badge colors, icon accents, and usage guidance.\",\n icon: Palette,\n color: \"violet\",\n path: \"color-palette\",\n component: lazy(() => import(\"./pages/PlayColorPalette\")),\n group: \"Design System\",\n order: 1,\n },\n {\n id: \"sonnet.core-components\",\n title: \"Core UI Components\",\n description:\n \"Test all core UI components (notifications, buttons, dialogs, forms, etc.) in isolation before production use.\",\n icon: Grid,\n color: \"indigo\",\n path: \"core-components\",\n component: lazy(() => import(\"./pages/PlayCoreComponents\")),\n group: \"Components\",\n order: 0,\n },\n {\n id: \"sonnet.json-editor\",\n title: \"JSON Editor\",\n description:\n \"Constrained JSON editor with selectively editable regions using JSON Pointer (RFC 6901). Readonly sections are visible but locked.\",\n icon: Braces,\n color: \"amber\",\n path: \"json-editor\",\n component: lazy(() => import(\"./pages/PlayJsonEditor\")),\n group: \"Components\",\n order: 1,\n },\n {\n id: \"sonnet.form-components\",\n title: \"Form Components\",\n description:\n \"Test custom Form wrapper components with labels, descriptions, and error states. Includes Input, Textarea, Number, Checkbox, Select, MultiSelect, and Tags.\",\n icon: Check,\n color: \"blue\",\n path: \"form-components\",\n component: lazy(() => import(\"./pages/PlayFormComponents\")),\n group: \"Forms\",\n order: 0,\n },\n {\n id: \"sonnet.forms\",\n title: \"Forms Renderer\",\n description:\n \"Test and experiment with the JsonSchemaFormRenderer component. Try different schemas and see real-time validation.\",\n icon: Edit,\n color: \"purple\",\n path: \"forms\",\n component: lazy(() => import(\"./pages/PlayForms\")),\n group: \"Forms\",\n order: 1,\n },\n {\n id: \"sonnet.form-widgets\",\n title: \"Form Widgets\",\n description:\n \"Pluggable field components consumed by the Forms Renderer. Each widget maps to a JSON Schema type or format and can be swapped independently.\",\n icon: Package,\n color: \"indigo\",\n path: \"form-widgets\",\n component: lazy(() => import(\"./pages/PlayFormWidgets\")),\n group: \"Forms\",\n order: 2,\n },\n {\n id: \"sonnet.data-components\",\n title: \"Data Components\",\n description:\n \"Interactive sandbox for SearchInput (simple and faceted mode) and EntityTable. Includes a live table wired to the faceted search.\",\n icon: Table2,\n color: \"teal\",\n path: \"data-components\",\n component: lazy(() => import(\"./pages/PlayDataComponents\")),\n group: \"Data\",\n order: 0,\n },\n];\n","/**\n * Factory that turns a PlaygroundRegistry into a ServiceModule.\n *\n * Generates routes (lazy + Suspense), sidebar navigation, and the\n * overview index page -- all derived from the registry entries.\n * The consumer just passes a registry and optional overrides.\n */\nimport React, { Suspense } from \"react\";\nimport { FlaskConical } from \"lucide-react\";\nimport type { ServiceModule, NavGroup } from \"@petrarca/sonnet-shell\";\nimport type { PlaygroundRegistry } from \"./PlaygroundRegistry\";\nimport type { PlaygroundModuleOptions } from \"./types\";\nimport { PlaygroundOverview } from \"./PlaygroundOverview\";\n\n/**\n * Build sidebar navigation groups from registry entries.\n *\n * Groups entries by their `group` field. Each group becomes a NavGroup\n * with a heading. Ungrouped entries go into a \"General\" group.\n */\nfunction buildNavigation(\n registry: PlaygroundRegistry,\n basePath: string,\n): NavGroup[] {\n const groups = registry.getGrouped();\n const navGroups: NavGroup[] = [];\n\n // Overview link is always first\n const overviewGroup: NavGroup = {\n id: \"playground-overview\",\n links: [{ label: \"Overview\", path: basePath }],\n };\n navGroups.push(overviewGroup);\n\n for (const [groupLabel, entries] of groups) {\n navGroups.push({\n id: `playground-${groupLabel.toLowerCase().replace(/\\s+/g, \"-\")}`,\n heading: groupLabel,\n links: entries.map((e) => ({\n label: e.title,\n path: `${basePath}/${e.path}`,\n })),\n });\n }\n\n return navGroups;\n}\n\n/** Wrap a component in Suspense for lazy loading. */\nfunction suspended(Component: React.ComponentType): React.ReactElement {\n return (\n <Suspense>\n <Component />\n </Suspense>\n );\n}\n\n/**\n * Create a ServiceModule for the playground.\n *\n * Returns a complete module definition ready to pass to\n * createModuleRegistry(). Routes, navigation, and the overview page\n * are all generated from the registry.\n */\nexport function createPlaygroundModule(\n registry: PlaygroundRegistry,\n options: PlaygroundModuleOptions = {},\n): ServiceModule {\n const {\n icon = FlaskConical,\n label = \"Playground\",\n basePath = \"/playground\",\n overviewTitle = \"Developer Playground\",\n overviewSubtitle = \"Experiment with components, test features, and explore capabilities.\",\n grouped = true,\n } = options;\n\n // Strip leading slash for route paths (React Router relative convention)\n const routeBase = basePath.replace(/^\\//, \"\");\n\n const routes = [\n {\n path: routeBase,\n element: suspended(() => (\n <PlaygroundOverview\n registry={registry}\n basePath={basePath}\n title={overviewTitle}\n subtitle={overviewSubtitle}\n grouped={grouped}\n />\n )),\n },\n ...registry.getAll().map((entry) => ({\n path: `${routeBase}/${entry.path}`,\n element: suspended(entry.component),\n })),\n ];\n\n return {\n id: \"playground\",\n label,\n icon,\n basePath,\n pinBottom: true,\n navigation: buildNavigation(registry, basePath),\n routes,\n };\n}\n","/**\n * PlaygroundOverview -- tile grid rendered from a PlaygroundRegistry.\n *\n * Displays cards with colored icons. Clicking a card navigates to the\n * playground page. A toggle in the header lets the user switch between\n * grouped (by category) and flat (all tiles) views.\n */\nimport React, { useState } from \"react\";\nimport { useNavigate } from \"react-router-dom\";\nimport { LayoutGrid, List } from \"lucide-react\";\nimport { Card, Button, SimpleTooltip } from \"@petrarca/sonnet-ui\";\nimport type { PlaygroundRegistry } from \"./PlaygroundRegistry\";\nimport type { PlaygroundColor, PlaygroundEntry } from \"./types\";\n\n// Maps colour name to icon container classes (bg-*-100 text-*-600 pairing).\nconst COLOR_CLASSES: Record<PlaygroundColor, string> = {\n blue: \"bg-blue-100 text-blue-600\",\n violet: \"bg-violet-100 text-violet-600\",\n indigo: \"bg-indigo-100 text-indigo-600\",\n purple: \"bg-purple-100 text-purple-600\",\n teal: \"bg-teal-100 text-teal-600\",\n amber: \"bg-amber-100 text-amber-600\",\n emerald: \"bg-emerald-100 text-emerald-600\",\n rose: \"bg-rose-100 text-rose-600\",\n orange: \"bg-orange-100 text-orange-600\",\n cyan: \"bg-cyan-100 text-cyan-600\",\n};\n\nconst TILE_GRID = \"grid grid-cols-1 sm:grid-cols-2 2xl:grid-cols-3 gap-6\";\n\ninterface PlaygroundOverviewProps {\n registry: PlaygroundRegistry;\n basePath: string;\n title: string;\n subtitle: string;\n /** Initial grouping state. Defaults to true. User can toggle at runtime. */\n grouped?: boolean;\n}\n\ninterface TileProps {\n item: PlaygroundEntry;\n onNavigate: (path: string) => void;\n}\n\n/** A single playground tile card. */\nfunction PlaygroundTile({ item, onNavigate }: TileProps): React.ReactElement {\n return (\n <Card\n className=\"cursor-pointer shadow-sm border rounded-md p-6 transition-transform duration-200 motion-safe:hover:-translate-y-1\"\n onClick={() => onNavigate(item.path)}\n >\n <div className=\"flex items-center mb-6\">\n <div\n className={`flex items-center justify-center w-[50px] h-[50px] rounded-md ${COLOR_CLASSES[item.color] ?? COLOR_CLASSES.blue}`}\n >\n <item.icon size={28} />\n </div>\n </div>\n <h3 className=\"heading-section mb-1\">{item.title}</h3>\n <p className=\"text-sm text-muted-foreground\">{item.description}</p>\n </Card>\n );\n}\n\n/** Developer playground overview -- card grid linking to all registered pages. */\nexport function PlaygroundOverview({\n registry,\n basePath,\n title,\n subtitle,\n grouped: initialGrouped = true,\n}: PlaygroundOverviewProps): React.ReactElement {\n const navigate = useNavigate();\n const [grouped, setGrouped] = useState(initialGrouped);\n\n const handleNavigate = (path: string) => navigate(`${basePath}/${path}`);\n\n return (\n <div className=\"w-full py-12 px-4\">\n <div className=\"flex items-start justify-between mb-6\">\n <div>\n <h1 className=\"mb-1\">{title}</h1>\n <p className=\"text-lg text-muted-foreground\">{subtitle}</p>\n </div>\n <SimpleTooltip label={grouped ? \"Show flat list\" : \"Group by category\"}>\n <Button\n variant=\"ghost\"\n size=\"icon\"\n onClick={() => setGrouped((v) => !v)}\n >\n {grouped ? (\n <LayoutGrid className=\"h-4 w-4\" />\n ) : (\n <List className=\"h-4 w-4\" />\n )}\n </Button>\n </SimpleTooltip>\n </div>\n\n {grouped ? (\n registry.getGrouped().map(([groupLabel, entries]) => (\n <div key={groupLabel} className=\"mb-8\">\n <h2 className=\"text-sm font-medium text-muted-foreground uppercase tracking-wider mb-4\">\n {groupLabel}\n </h2>\n <div className={TILE_GRID}>\n {entries.map((item) => (\n <PlaygroundTile\n key={item.id}\n item={item}\n onNavigate={handleNavigate}\n />\n ))}\n </div>\n </div>\n ))\n ) : (\n <div className={TILE_GRID}>\n {registry.getAll().map((item) => (\n <PlaygroundTile\n key={item.id}\n item={item}\n onNavigate={handleNavigate}\n />\n ))}\n </div>\n )}\n </div>\n );\n}\n","/**\n * @petrarca/sonnet-playground\n *\n * Playground framework and built-in component demos for the Petrarca\n * Sonnet component library.\n *\n * Usage:\n *\n * import {\n * createPlaygroundRegistry,\n * createPlaygroundModule,\n * } from \"@petrarca/sonnet-playground\";\n *\n * const playground = createPlaygroundRegistry();\n * // Optionally register additional entries:\n * playground.register({ id: \"app.custom\", ... });\n *\n * const playgroundModule = createPlaygroundModule(playground);\n */\n\nimport { PlaygroundRegistry } from \"./PlaygroundRegistry\";\nimport { builtinEntries } from \"./builtinEntries\";\n\n// Framework\nexport { PlaygroundRegistry } from \"./PlaygroundRegistry\";\nexport { createPlaygroundModule } from \"./createPlaygroundModule\";\nexport { PlaygroundOverview } from \"./PlaygroundOverview\";\nexport { PlaygroundSection } from \"./PlaygroundSection\";\n\n// Types\nexport type {\n PlaygroundEntry,\n PlaygroundColor,\n PlaygroundModuleOptions,\n} from \"./types\";\n\n// Built-in entries (for selective use or extending)\nexport { builtinEntries } from \"./builtinEntries\";\n\n/**\n * Convenience factory: creates a new PlaygroundRegistry pre-populated\n * with all built-in sonnet component demos.\n */\nexport function createPlaygroundRegistry(): PlaygroundRegistry {\n const registry = new PlaygroundRegistry();\n registry.registerAll(builtinEntries);\n return registry;\n}\n"],"mappings":"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","names":["jsx"]}
1
+ {"version":3,"sources":["../src/PlaygroundRegistry.ts","../src/builtinEntries.ts","../src/createPlaygroundModule.tsx","../src/PlaygroundOverview.tsx","../src/index.ts"],"sourcesContent":["/**\n * PlaygroundRegistry -- mutable collection of playground entries.\n *\n * The library ships a default instance pre-populated with the built-in\n * sonnet component demos. Consumers register additional entries for\n * domain-specific playgrounds before passing the registry to\n * createPlaygroundModule().\n */\nimport type { PlaygroundEntry } from \"./types\";\n\nexport class PlaygroundRegistry {\n private entries: Map<string, PlaygroundEntry> = new Map();\n\n /** Register a playground entry. Overwrites any existing entry with the same id. */\n register(entry: PlaygroundEntry): void {\n this.entries.set(entry.id, entry);\n }\n\n /** Register multiple entries at once. */\n registerAll(entries: PlaygroundEntry[]): void {\n for (const entry of entries) {\n this.entries.set(entry.id, entry);\n }\n }\n\n /** Remove an entry by id. Returns true if it existed. */\n unregister(id: string): boolean {\n return this.entries.delete(id);\n }\n\n /** Get a single entry by id. */\n get(id: string): PlaygroundEntry | undefined {\n return this.entries.get(id);\n }\n\n /** Fallback group label for entries with no group defined. */\n static readonly DEFAULT_GROUP = \"General\";\n\n /**\n * All registered entries, sorted by group registration order then\n * by `order` within each group.\n */\n getAll(): PlaygroundEntry[] {\n const groupOrder = this.getGroupOrder();\n return [...this.entries.values()].sort((a, b) => {\n const groupA = a.group ?? PlaygroundRegistry.DEFAULT_GROUP;\n const groupB = b.group ?? PlaygroundRegistry.DEFAULT_GROUP;\n if (groupA !== groupB) {\n return (\n (groupOrder.get(groupA) ?? 999) - (groupOrder.get(groupB) ?? 999)\n );\n }\n return (a.order ?? 0) - (b.order ?? 0);\n });\n }\n\n /**\n * Entries grouped by their group label.\n * Returns an array of [groupLabel, entries[]] tuples, preserving\n * first-seen registration order for groups and `order` within each group.\n */\n getGrouped(): Array<[string, PlaygroundEntry[]]> {\n const grouped = new Map<string, PlaygroundEntry[]>();\n for (const entry of this.getAll()) {\n const group = entry.group ?? PlaygroundRegistry.DEFAULT_GROUP;\n const list = grouped.get(group) ?? [];\n list.push(entry);\n grouped.set(group, list);\n }\n return [...grouped.entries()];\n }\n\n /** Map of group name → first-seen index (registration order). */\n private getGroupOrder(): Map<string, number> {\n const order = new Map<string, number>();\n let idx = 0;\n for (const entry of this.entries.values()) {\n const group = entry.group ?? PlaygroundRegistry.DEFAULT_GROUP;\n if (!order.has(group)) {\n order.set(group, idx++);\n }\n }\n return order;\n }\n\n /** Number of registered entries. */\n get size(): number {\n return this.entries.size;\n }\n}\n","/**\n * Built-in playground entries for the sonnet component library.\n *\n * These entries demonstrate @petrarca/sonnet-* components with static\n * mock data -- no application backend required. Each page is lazy-loaded.\n */\nimport { lazy } from \"react\";\nimport {\n Type,\n Palette,\n Grid,\n Braces,\n Check,\n Edit,\n Package,\n Table2,\n Network,\n} from \"lucide-react\";\nimport type { PlaygroundEntry } from \"./types\";\n\nexport const builtinEntries: PlaygroundEntry[] = [\n {\n id: \"sonnet.typography\",\n title: \"Typography\",\n description:\n \"Living style-guide for the typography system. Font families, type scale, weights, heading hierarchy, color tiers, and component patterns.\",\n icon: Type,\n color: \"teal\",\n path: \"typography\",\n component: lazy(() => import(\"./pages/PlayTypography\")),\n group: \"Design System\",\n order: 0,\n },\n {\n id: \"sonnet.color-palette\",\n title: \"Color Palette\",\n description:\n \"Living reference for the color system. Semantic tokens, extended palette, badge colors, icon accents, and usage guidance.\",\n icon: Palette,\n color: \"violet\",\n path: \"color-palette\",\n component: lazy(() => import(\"./pages/PlayColorPalette\")),\n group: \"Design System\",\n order: 1,\n },\n {\n id: \"sonnet.core-components\",\n title: \"Core UI Components\",\n description:\n \"Test all core UI components (notifications, buttons, dialogs, forms, etc.) in isolation before production use.\",\n icon: Grid,\n color: \"indigo\",\n path: \"core-components\",\n component: lazy(() => import(\"./pages/PlayCoreComponents\")),\n group: \"Components\",\n order: 0,\n },\n {\n id: \"sonnet.json-editor\",\n title: \"JSON Editor\",\n description:\n \"Constrained JSON editor with selectively editable regions using JSON Pointer (RFC 6901). Readonly sections are visible but locked.\",\n icon: Braces,\n color: \"amber\",\n path: \"json-editor\",\n component: lazy(() => import(\"./pages/PlayJsonEditor\")),\n group: \"Components\",\n order: 1,\n },\n {\n id: \"sonnet.form-components\",\n title: \"Form Components\",\n description:\n \"Test custom Form wrapper components with labels, descriptions, and error states. Includes Input, Textarea, Number, Checkbox, Select, MultiSelect, and Tags.\",\n icon: Check,\n color: \"blue\",\n path: \"form-components\",\n component: lazy(() => import(\"./pages/PlayFormComponents\")),\n group: \"Forms\",\n order: 0,\n },\n {\n id: \"sonnet.forms\",\n title: \"Forms Renderer\",\n description:\n \"Test and experiment with the JsonSchemaFormRenderer component. Try different schemas and see real-time validation.\",\n icon: Edit,\n color: \"purple\",\n path: \"forms\",\n component: lazy(() => import(\"./pages/PlayForms\")),\n group: \"Forms\",\n order: 1,\n },\n {\n id: \"sonnet.form-widgets\",\n title: \"Form Widgets\",\n description:\n \"Pluggable field components consumed by the Forms Renderer. Each widget maps to a JSON Schema type or format and can be swapped independently.\",\n icon: Package,\n color: \"indigo\",\n path: \"form-widgets\",\n component: lazy(() => import(\"./pages/PlayFormWidgets\")),\n group: \"Forms\",\n order: 2,\n },\n {\n id: \"sonnet.data-components\",\n title: \"Data Components\",\n description:\n \"Interactive sandbox for SearchInput (simple and faceted mode) and EntityTable. Includes a live table wired to the faceted search.\",\n icon: Table2,\n color: \"teal\",\n path: \"data-components\",\n component: lazy(() => import(\"./pages/PlayDataComponents\")),\n group: \"Data\",\n order: 0,\n },\n {\n id: \"sonnet.graph\",\n title: \"Graph Visualization\",\n description:\n \"Interactive property graph visualization with dual renderer support (Cytoscape, Reagraph). Org hierarchy demo with filtering, selection, and exploration.\",\n icon: Network,\n color: \"cyan\",\n path: \"graph\",\n component: lazy(() => import(\"./pages/PlayGraph\")),\n group: \"Graph\",\n order: 0,\n },\n];\n","/**\n * Factory that turns a PlaygroundRegistry into a ServiceModule.\n *\n * Generates routes (lazy + Suspense), sidebar navigation, and the\n * overview index page -- all derived from the registry entries.\n * The consumer just passes a registry and optional overrides.\n */\nimport React, { Suspense } from \"react\";\nimport { FlaskConical } from \"lucide-react\";\nimport type { ServiceModule, NavGroup } from \"@petrarca/sonnet-shell\";\nimport type { PlaygroundRegistry } from \"./PlaygroundRegistry\";\nimport type { PlaygroundModuleOptions } from \"./types\";\nimport { PlaygroundOverview } from \"./PlaygroundOverview\";\n\n/**\n * Build sidebar navigation groups from registry entries.\n *\n * Groups entries by their `group` field. Each group becomes a NavGroup\n * with a heading. Ungrouped entries go into a \"General\" group.\n */\nfunction buildNavigation(\n registry: PlaygroundRegistry,\n basePath: string,\n): NavGroup[] {\n const groups = registry.getGrouped();\n const navGroups: NavGroup[] = [];\n\n // Overview link is always first\n const overviewGroup: NavGroup = {\n id: \"playground-overview\",\n links: [{ label: \"Overview\", path: basePath }],\n };\n navGroups.push(overviewGroup);\n\n for (const [groupLabel, entries] of groups) {\n navGroups.push({\n id: `playground-${groupLabel.toLowerCase().replace(/\\s+/g, \"-\")}`,\n heading: groupLabel,\n links: entries.map((e) => ({\n label: e.title,\n path: `${basePath}/${e.path}`,\n })),\n });\n }\n\n return navGroups;\n}\n\n/** Wrap a component in Suspense for lazy loading. */\nfunction suspended(Component: React.ComponentType): React.ReactElement {\n return (\n <Suspense>\n <Component />\n </Suspense>\n );\n}\n\n/**\n * Create a ServiceModule for the playground.\n *\n * Returns a complete module definition ready to pass to\n * createModuleRegistry(). Routes, navigation, and the overview page\n * are all generated from the registry.\n */\nexport function createPlaygroundModule(\n registry: PlaygroundRegistry,\n options: PlaygroundModuleOptions = {},\n): ServiceModule {\n const {\n icon = FlaskConical,\n label = \"Playground\",\n basePath = \"/playground\",\n overviewTitle = \"Developer Playground\",\n overviewSubtitle = \"Experiment with components, test features, and explore capabilities.\",\n grouped = true,\n } = options;\n\n // Strip leading slash for route paths (React Router relative convention)\n const routeBase = basePath.replace(/^\\//, \"\");\n\n const routes = [\n {\n path: routeBase,\n element: suspended(() => (\n <PlaygroundOverview\n registry={registry}\n basePath={basePath}\n title={overviewTitle}\n subtitle={overviewSubtitle}\n grouped={grouped}\n />\n )),\n },\n ...registry.getAll().map((entry) => ({\n path: `${routeBase}/${entry.path}`,\n element: suspended(entry.component),\n })),\n ];\n\n return {\n id: \"playground\",\n label,\n icon,\n basePath,\n pinBottom: true,\n navigation: buildNavigation(registry, basePath),\n routes,\n };\n}\n","/**\n * PlaygroundOverview -- tile grid rendered from a PlaygroundRegistry.\n *\n * Displays cards with colored icons. Clicking a card navigates to the\n * playground page. A toggle in the header lets the user switch between\n * grouped (by category) and flat (all tiles) views.\n */\nimport React, { useState } from \"react\";\nimport { useNavigate } from \"react-router-dom\";\nimport { LayoutGrid, List } from \"lucide-react\";\nimport { Card, Button, SimpleTooltip } from \"@petrarca/sonnet-ui\";\nimport type { PlaygroundRegistry } from \"./PlaygroundRegistry\";\nimport type { PlaygroundColor, PlaygroundEntry } from \"./types\";\n\n// Maps colour name to icon container classes (bg-*-100 text-*-600 pairing).\nconst COLOR_CLASSES: Record<PlaygroundColor, string> = {\n blue: \"bg-blue-100 text-blue-600\",\n violet: \"bg-violet-100 text-violet-600\",\n indigo: \"bg-indigo-100 text-indigo-600\",\n purple: \"bg-purple-100 text-purple-600\",\n teal: \"bg-teal-100 text-teal-600\",\n amber: \"bg-amber-100 text-amber-600\",\n emerald: \"bg-emerald-100 text-emerald-600\",\n rose: \"bg-rose-100 text-rose-600\",\n orange: \"bg-orange-100 text-orange-600\",\n cyan: \"bg-cyan-100 text-cyan-600\",\n};\n\nconst TILE_GRID = \"grid grid-cols-1 sm:grid-cols-2 2xl:grid-cols-3 gap-6\";\n\ninterface PlaygroundOverviewProps {\n registry: PlaygroundRegistry;\n basePath: string;\n title: string;\n subtitle: string;\n /** Initial grouping state. Defaults to true. User can toggle at runtime. */\n grouped?: boolean;\n}\n\ninterface TileProps {\n item: PlaygroundEntry;\n onNavigate: (path: string) => void;\n}\n\n/** A single playground tile card. */\nfunction PlaygroundTile({ item, onNavigate }: TileProps): React.ReactElement {\n return (\n <Card\n className=\"cursor-pointer shadow-sm border rounded-md p-6 transition-transform duration-200 motion-safe:hover:-translate-y-1\"\n onClick={() => onNavigate(item.path)}\n >\n <div className=\"flex items-center mb-6\">\n <div\n className={`flex items-center justify-center w-[50px] h-[50px] rounded-md ${COLOR_CLASSES[item.color] ?? COLOR_CLASSES.blue}`}\n >\n <item.icon size={28} />\n </div>\n </div>\n <h3 className=\"heading-section mb-1\">{item.title}</h3>\n <p className=\"text-sm text-muted-foreground\">{item.description}</p>\n </Card>\n );\n}\n\n/** Developer playground overview -- card grid linking to all registered pages. */\nexport function PlaygroundOverview({\n registry,\n basePath,\n title,\n subtitle,\n grouped: initialGrouped = true,\n}: PlaygroundOverviewProps): React.ReactElement {\n const navigate = useNavigate();\n const [grouped, setGrouped] = useState(initialGrouped);\n\n const handleNavigate = (path: string) => navigate(`${basePath}/${path}`);\n\n return (\n <div className=\"w-full py-12 px-4\">\n <div className=\"flex items-start justify-between mb-6\">\n <div>\n <h1 className=\"mb-1\">{title}</h1>\n <p className=\"text-lg text-muted-foreground\">{subtitle}</p>\n </div>\n <SimpleTooltip label={grouped ? \"Show flat list\" : \"Group by category\"}>\n <Button\n variant=\"ghost\"\n size=\"icon\"\n onClick={() => setGrouped((v) => !v)}\n >\n {grouped ? (\n <LayoutGrid className=\"h-4 w-4\" />\n ) : (\n <List className=\"h-4 w-4\" />\n )}\n </Button>\n </SimpleTooltip>\n </div>\n\n {grouped ? (\n registry.getGrouped().map(([groupLabel, entries]) => (\n <div key={groupLabel} className=\"mb-8\">\n <h2 className=\"text-sm font-medium text-muted-foreground uppercase tracking-wider mb-4\">\n {groupLabel}\n </h2>\n <div className={TILE_GRID}>\n {entries.map((item) => (\n <PlaygroundTile\n key={item.id}\n item={item}\n onNavigate={handleNavigate}\n />\n ))}\n </div>\n </div>\n ))\n ) : (\n <div className={TILE_GRID}>\n {registry.getAll().map((item) => (\n <PlaygroundTile\n key={item.id}\n item={item}\n onNavigate={handleNavigate}\n />\n ))}\n </div>\n )}\n </div>\n );\n}\n","/**\n * @petrarca/sonnet-playground\n *\n * Playground framework and built-in component demos for the Petrarca\n * Sonnet component library.\n *\n * Usage:\n *\n * import {\n * createPlaygroundRegistry,\n * createPlaygroundModule,\n * } from \"@petrarca/sonnet-playground\";\n *\n * const playground = createPlaygroundRegistry();\n * // Optionally register additional entries:\n * playground.register({ id: \"app.custom\", ... });\n *\n * const playgroundModule = createPlaygroundModule(playground);\n */\n\nimport { PlaygroundRegistry } from \"./PlaygroundRegistry\";\nimport { builtinEntries } from \"./builtinEntries\";\n\n// Framework\nexport { PlaygroundRegistry } from \"./PlaygroundRegistry\";\nexport { createPlaygroundModule } from \"./createPlaygroundModule\";\nexport { PlaygroundOverview } from \"./PlaygroundOverview\";\nexport { PlaygroundSection } from \"./PlaygroundSection\";\n\n// Types\nexport type {\n PlaygroundEntry,\n PlaygroundColor,\n PlaygroundModuleOptions,\n} from \"./types\";\n\n// Built-in entries (for selective use or extending)\nexport { builtinEntries } from \"./builtinEntries\";\n\n/**\n * Convenience factory: creates a new PlaygroundRegistry pre-populated\n * with all built-in sonnet component demos.\n */\nexport function createPlaygroundRegistry(): PlaygroundRegistry {\n const registry = new PlaygroundRegistry();\n registry.registerAll(builtinEntries);\n return registry;\n}\n"],"mappings":"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","names":["jsx"]}
@@ -66,4 +66,15 @@ declare function PlayFormWidgets(): react_jsx_runtime.JSX.Element;
66
66
  /** Playground sandbox for SearchInput, EntitySelect, and EntityTable. */
67
67
  declare function PlayDataComponents(): React.ReactElement;
68
68
 
69
- export { PlayColorPalette, PlayCoreComponents, PlayDataComponents, PlayFormComponents, PlayFormWidgets, PlayForms, PlayJsonEditor, PlayTypography };
69
+ /**
70
+ * Playground page for @petrarca/sonnet-graph.
71
+ * Accessible at /playground/graph
72
+ *
73
+ * Demonstrates graph visualization with static mock data -- no backend required.
74
+ * Uses the GraphStoresContext provider pattern that consumers like explorer
75
+ * and Atlas would use to wire their own stores.
76
+ */
77
+
78
+ declare function PlayGraph(): React.ReactElement;
79
+
80
+ export { PlayColorPalette, PlayCoreComponents, PlayDataComponents, PlayFormComponents, PlayFormWidgets, PlayForms, PlayGraph, PlayJsonEditor, PlayTypography };
@@ -4,6 +4,9 @@ import {
4
4
  import {
5
5
  PlayDataComponents
6
6
  } from "../chunk-TZGJH7YS.js";
7
+ import {
8
+ PlayGraph
9
+ } from "../chunk-PGI54O43.js";
7
10
  import {
8
11
  PlayTypography
9
12
  } from "../chunk-CYNK2P2Q.js";
@@ -30,6 +33,7 @@ export {
30
33
  PlayFormComponents,
31
34
  PlayFormWidgets,
32
35
  PlayForms,
36
+ PlayGraph,
33
37
  PlayJsonEditor,
34
38
  PlayTypography
35
39
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@petrarca/sonnet-playground",
3
- "version": "0.1.5",
3
+ "version": "0.2.0",
4
4
  "description": "Playground framework and built-in component demos for the Petrarca Sonnet component library",
5
5
  "license": "Apache-2.0",
6
6
  "publishConfig": {
@@ -26,10 +26,11 @@
26
26
  "lucide-react": "^0.553.0",
27
27
  "sonner": "^2.0.7",
28
28
  "zod": "^4.3.6",
29
- "@petrarca/sonnet-core": "0.1.5",
30
- "@petrarca/sonnet-ui": "0.1.5",
31
- "@petrarca/sonnet-forms": "0.1.5",
32
- "@petrarca/sonnet-shell": "0.1.5"
29
+ "@petrarca/sonnet-core": "0.2.0",
30
+ "@petrarca/sonnet-ui": "0.2.0",
31
+ "@petrarca/sonnet-forms": "0.2.0",
32
+ "@petrarca/sonnet-shell": "0.2.0",
33
+ "@petrarca/sonnet-graph": "0.2.0"
33
34
  },
34
35
  "peerDependencies": {
35
36
  "react": ">=19",