@3plate/graph-core 0.1.6 → 0.1.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +163 -28
- package/dist/index.d.cts +27 -2
- package/dist/index.d.ts +27 -2
- package/dist/index.js +162 -28
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -34,6 +34,7 @@ __export(index_exports, {
|
|
|
34
34
|
FileSystemSource: () => FileSystemSource,
|
|
35
35
|
Ingest: () => Ingest,
|
|
36
36
|
Playground: () => Playground,
|
|
37
|
+
Updater: () => Updater,
|
|
37
38
|
WebSocketSource: () => WebSocketSource,
|
|
38
39
|
default: () => index_default,
|
|
39
40
|
graph: () => graph
|
|
@@ -1380,15 +1381,16 @@ var Layout = class _Layout {
|
|
|
1380
1381
|
|
|
1381
1382
|
// src/canvas/marker.tsx
|
|
1382
1383
|
var import_jsx_runtime = require("jsx-dom/jsx-runtime");
|
|
1383
|
-
function arrow(size, reverse = false) {
|
|
1384
|
+
function arrow(size, reverse = false, prefix = "") {
|
|
1384
1385
|
const h = size / 1.5;
|
|
1385
1386
|
const w = size;
|
|
1386
1387
|
const ry = h / 2;
|
|
1387
1388
|
const suffix = reverse ? "-reverse" : "";
|
|
1389
|
+
const id = prefix ? `${prefix}-g3p-marker-arrow${suffix}` : `g3p-marker-arrow${suffix}`;
|
|
1388
1390
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1389
1391
|
"marker",
|
|
1390
1392
|
{
|
|
1391
|
-
id
|
|
1393
|
+
id,
|
|
1392
1394
|
className: "g3p-marker g3p-marker-arrow",
|
|
1393
1395
|
markerWidth: size,
|
|
1394
1396
|
markerHeight: size,
|
|
@@ -1400,14 +1402,15 @@ function arrow(size, reverse = false) {
|
|
|
1400
1402
|
}
|
|
1401
1403
|
);
|
|
1402
1404
|
}
|
|
1403
|
-
function circle(size, reverse = false) {
|
|
1405
|
+
function circle(size, reverse = false, prefix = "") {
|
|
1404
1406
|
const r = size / 3;
|
|
1405
1407
|
const cy = size / 2;
|
|
1406
1408
|
const suffix = reverse ? "-reverse" : "";
|
|
1409
|
+
const id = prefix ? `${prefix}-g3p-marker-circle${suffix}` : `g3p-marker-circle${suffix}`;
|
|
1407
1410
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1408
1411
|
"marker",
|
|
1409
1412
|
{
|
|
1410
|
-
id
|
|
1413
|
+
id,
|
|
1411
1414
|
className: "g3p-marker g3p-marker-circle",
|
|
1412
1415
|
markerWidth: size,
|
|
1413
1416
|
markerHeight: size,
|
|
@@ -1419,15 +1422,16 @@ function circle(size, reverse = false) {
|
|
|
1419
1422
|
}
|
|
1420
1423
|
);
|
|
1421
1424
|
}
|
|
1422
|
-
function diamond(size, reverse = false) {
|
|
1425
|
+
function diamond(size, reverse = false, prefix = "") {
|
|
1423
1426
|
const w = size * 0.7;
|
|
1424
1427
|
const h = size / 2;
|
|
1425
1428
|
const cy = size / 2;
|
|
1426
1429
|
const suffix = reverse ? "-reverse" : "";
|
|
1430
|
+
const id = prefix ? `${prefix}-g3p-marker-diamond${suffix}` : `g3p-marker-diamond${suffix}`;
|
|
1427
1431
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1428
1432
|
"marker",
|
|
1429
1433
|
{
|
|
1430
|
-
id
|
|
1434
|
+
id,
|
|
1431
1435
|
className: "g3p-marker g3p-marker-diamond",
|
|
1432
1436
|
markerWidth: size,
|
|
1433
1437
|
markerHeight: size,
|
|
@@ -1439,14 +1443,15 @@ function diamond(size, reverse = false) {
|
|
|
1439
1443
|
}
|
|
1440
1444
|
);
|
|
1441
1445
|
}
|
|
1442
|
-
function bar(size, reverse = false) {
|
|
1446
|
+
function bar(size, reverse = false, prefix = "") {
|
|
1443
1447
|
const h = size * 0.6;
|
|
1444
1448
|
const cy = size / 2;
|
|
1445
1449
|
const suffix = reverse ? "-reverse" : "";
|
|
1450
|
+
const id = prefix ? `${prefix}-g3p-marker-bar${suffix}` : `g3p-marker-bar${suffix}`;
|
|
1446
1451
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1447
1452
|
"marker",
|
|
1448
1453
|
{
|
|
1449
|
-
id
|
|
1454
|
+
id,
|
|
1450
1455
|
className: "g3p-marker g3p-marker-bar",
|
|
1451
1456
|
markerWidth: size,
|
|
1452
1457
|
markerHeight: size,
|
|
@@ -1458,7 +1463,7 @@ function bar(size, reverse = false) {
|
|
|
1458
1463
|
}
|
|
1459
1464
|
);
|
|
1460
1465
|
}
|
|
1461
|
-
function none(size, reverse = false) {
|
|
1466
|
+
function none(size, reverse = false, prefix = "") {
|
|
1462
1467
|
return void 0;
|
|
1463
1468
|
}
|
|
1464
1469
|
function normalize(data) {
|
|
@@ -2240,6 +2245,9 @@ var Seg2 = class {
|
|
|
2240
2245
|
if (this.source.isDummy) source = void 0;
|
|
2241
2246
|
if (this.target.isDummy) target = void 0;
|
|
2242
2247
|
const typeClass = this.type ? `g3p-edge-type-${this.type}` : "";
|
|
2248
|
+
const prefix = this.canvas.markerPrefix;
|
|
2249
|
+
const markerStartId = source ? prefix ? `${prefix}-g3p-marker-${source}-reverse` : `g3p-marker-${source}-reverse` : void 0;
|
|
2250
|
+
const markerEndId = target ? prefix ? `${prefix}-g3p-marker-${target}` : `g3p-marker-${target}` : void 0;
|
|
2243
2251
|
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
2244
2252
|
"g",
|
|
2245
2253
|
{
|
|
@@ -2254,8 +2262,8 @@ var Seg2 = class {
|
|
|
2254
2262
|
d: this.svg,
|
|
2255
2263
|
fill: "none",
|
|
2256
2264
|
className: "g3p-seg-line",
|
|
2257
|
-
markerStart:
|
|
2258
|
-
markerEnd:
|
|
2265
|
+
markerStart: markerStartId ? `url(#${markerStartId})` : void 0,
|
|
2266
|
+
markerEnd: markerEndId ? `url(#${markerEndId})` : void 0
|
|
2259
2267
|
}
|
|
2260
2268
|
),
|
|
2261
2269
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
@@ -2840,6 +2848,10 @@ var Canvas = class {
|
|
|
2840
2848
|
curNodes;
|
|
2841
2849
|
curSegs;
|
|
2842
2850
|
updating;
|
|
2851
|
+
// Unique marker ID prefix for this canvas instance
|
|
2852
|
+
markerPrefix;
|
|
2853
|
+
// Dynamic style element for this instance (for cleanup)
|
|
2854
|
+
dynamicStyleEl;
|
|
2843
2855
|
// Pan-zoom state
|
|
2844
2856
|
panScale = null;
|
|
2845
2857
|
zoomControls;
|
|
@@ -2853,6 +2865,13 @@ var Canvas = class {
|
|
|
2853
2865
|
constructor(api, options) {
|
|
2854
2866
|
Object.assign(this, options);
|
|
2855
2867
|
this.api = api;
|
|
2868
|
+
this.reset();
|
|
2869
|
+
this.markerPrefix = api.root.replace(/[^a-zA-Z0-9-_]/g, "-");
|
|
2870
|
+
this.createMeasurementContainer();
|
|
2871
|
+
this.createCanvasContainer();
|
|
2872
|
+
if (this.panZoom) this.setupPanZoom();
|
|
2873
|
+
}
|
|
2874
|
+
reset() {
|
|
2856
2875
|
this.allNodes = /* @__PURE__ */ new Map();
|
|
2857
2876
|
this.curNodes = /* @__PURE__ */ new Map();
|
|
2858
2877
|
this.curSegs = /* @__PURE__ */ new Map();
|
|
@@ -2861,9 +2880,7 @@ var Canvas = class {
|
|
|
2861
2880
|
this.transform = { x: 0, y: 0, scale: 1 };
|
|
2862
2881
|
this.editMode = new EditMode();
|
|
2863
2882
|
this.editMode.editable = this.editable;
|
|
2864
|
-
this.
|
|
2865
|
-
this.createCanvasContainer();
|
|
2866
|
-
if (this.panZoom) this.setupPanZoom();
|
|
2883
|
+
if (this.group) this.group.innerHTML = "";
|
|
2867
2884
|
}
|
|
2868
2885
|
createMeasurementContainer() {
|
|
2869
2886
|
this.measurement = document.createElement("div");
|
|
@@ -3048,12 +3065,13 @@ var Canvas = class {
|
|
|
3048
3065
|
}
|
|
3049
3066
|
generateDynamicStyles() {
|
|
3050
3067
|
let css = "";
|
|
3051
|
-
|
|
3068
|
+
const scope = `[data-g3p-instance="${this.markerPrefix}"]`;
|
|
3069
|
+
css += themeToCSS(this.theme, scope);
|
|
3052
3070
|
for (const [type, vars] of Object.entries(this.nodeTypes)) {
|
|
3053
|
-
css += themeToCSS(vars,
|
|
3071
|
+
css += themeToCSS(vars, `${scope} .g3p-node-type-${type}`, "node");
|
|
3054
3072
|
}
|
|
3055
3073
|
for (const [type, vars] of Object.entries(this.edgeTypes)) {
|
|
3056
|
-
css += themeToCSS(vars,
|
|
3074
|
+
css += themeToCSS(vars, `${scope} .g3p-edge-type-${type}`);
|
|
3057
3075
|
}
|
|
3058
3076
|
return css;
|
|
3059
3077
|
}
|
|
@@ -3066,15 +3084,18 @@ var Canvas = class {
|
|
|
3066
3084
|
}
|
|
3067
3085
|
const dynamicStyles = this.generateDynamicStyles();
|
|
3068
3086
|
if (dynamicStyles) {
|
|
3069
|
-
|
|
3070
|
-
dynamicStyleEl
|
|
3071
|
-
|
|
3087
|
+
this.dynamicStyleEl?.remove();
|
|
3088
|
+
this.dynamicStyleEl = document.createElement("style");
|
|
3089
|
+
this.dynamicStyleEl.id = `g3p-styles-${this.markerPrefix}`;
|
|
3090
|
+
this.dynamicStyleEl.textContent = dynamicStyles;
|
|
3091
|
+
document.head.appendChild(this.dynamicStyleEl);
|
|
3072
3092
|
}
|
|
3073
3093
|
const colorModeClass = this.colorMode !== "system" ? `g3p-${this.colorMode}` : "";
|
|
3074
3094
|
this.container = /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
3075
3095
|
"div",
|
|
3076
3096
|
{
|
|
3077
3097
|
className: `g3p-canvas-container ${colorModeClass}`.trim(),
|
|
3098
|
+
"data-g3p-instance": this.markerPrefix,
|
|
3078
3099
|
ref: (el) => this.container = el,
|
|
3079
3100
|
onContextMenu: this.onContextMenu.bind(this),
|
|
3080
3101
|
children: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
|
|
@@ -3090,8 +3111,8 @@ var Canvas = class {
|
|
|
3090
3111
|
onDblClick: this.onDoubleClick.bind(this),
|
|
3091
3112
|
children: [
|
|
3092
3113
|
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("defs", { children: [
|
|
3093
|
-
Object.values(markerDefs).map((marker) => marker(this.markerSize, false)),
|
|
3094
|
-
Object.values(markerDefs).map((marker) => marker(this.markerSize, true))
|
|
3114
|
+
Object.values(markerDefs).map((marker) => marker(this.markerSize, false, this.markerPrefix)),
|
|
3115
|
+
Object.values(markerDefs).map((marker) => marker(this.markerSize, true, this.markerPrefix))
|
|
3095
3116
|
] }),
|
|
3096
3117
|
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
3097
3118
|
"g",
|
|
@@ -3448,6 +3469,40 @@ var Canvas = class {
|
|
|
3448
3469
|
}
|
|
3449
3470
|
return { type: "canvas" };
|
|
3450
3471
|
}
|
|
3472
|
+
/** Update theme and type styles dynamically */
|
|
3473
|
+
updateStyles(options) {
|
|
3474
|
+
if (options.theme !== void 0) this.theme = options.theme;
|
|
3475
|
+
if (options.nodeTypes !== void 0) this.nodeTypes = options.nodeTypes;
|
|
3476
|
+
if (options.edgeTypes !== void 0) this.edgeTypes = options.edgeTypes;
|
|
3477
|
+
const dynamicStyles = this.generateDynamicStyles();
|
|
3478
|
+
if (dynamicStyles) {
|
|
3479
|
+
if (!this.dynamicStyleEl) {
|
|
3480
|
+
this.dynamicStyleEl = document.createElement("style");
|
|
3481
|
+
this.dynamicStyleEl.id = `g3p-styles-${this.markerPrefix}`;
|
|
3482
|
+
document.head.appendChild(this.dynamicStyleEl);
|
|
3483
|
+
}
|
|
3484
|
+
this.dynamicStyleEl.textContent = dynamicStyles;
|
|
3485
|
+
} else if (this.dynamicStyleEl) {
|
|
3486
|
+
this.dynamicStyleEl.remove();
|
|
3487
|
+
this.dynamicStyleEl = void 0;
|
|
3488
|
+
}
|
|
3489
|
+
}
|
|
3490
|
+
/** Update color mode without recreating the canvas */
|
|
3491
|
+
setColorMode(colorMode) {
|
|
3492
|
+
if (!this.container) return;
|
|
3493
|
+
this.colorMode = colorMode;
|
|
3494
|
+
this.container.classList.remove("g3p-light", "g3p-dark");
|
|
3495
|
+
if (colorMode !== "system") {
|
|
3496
|
+
this.container.classList.add(`g3p-${colorMode}`);
|
|
3497
|
+
}
|
|
3498
|
+
}
|
|
3499
|
+
/** Cleanup resources when the canvas is destroyed */
|
|
3500
|
+
destroy() {
|
|
3501
|
+
this.dynamicStyleEl?.remove();
|
|
3502
|
+
this.dynamicStyleEl = void 0;
|
|
3503
|
+
this.measurement?.remove();
|
|
3504
|
+
this.measurement = void 0;
|
|
3505
|
+
}
|
|
3451
3506
|
};
|
|
3452
3507
|
var themeVarMap = {
|
|
3453
3508
|
// Canvas
|
|
@@ -3664,6 +3719,7 @@ var API = class {
|
|
|
3664
3719
|
this.nodeFields = /* @__PURE__ */ new Map();
|
|
3665
3720
|
this.nextNodeId = 1;
|
|
3666
3721
|
this.nextEdgeId = 1;
|
|
3722
|
+
this.canvas?.reset?.();
|
|
3667
3723
|
}
|
|
3668
3724
|
/** Initialize the API */
|
|
3669
3725
|
async init() {
|
|
@@ -3671,6 +3727,9 @@ var API = class {
|
|
|
3671
3727
|
if (!root) throw new Error("root element not found");
|
|
3672
3728
|
root.appendChild(this.canvas.container);
|
|
3673
3729
|
await this.applyHistory();
|
|
3730
|
+
if (this.events.onInit) {
|
|
3731
|
+
this.events.onInit();
|
|
3732
|
+
}
|
|
3674
3733
|
}
|
|
3675
3734
|
async applyHistory() {
|
|
3676
3735
|
for (const update of this.history)
|
|
@@ -4126,6 +4185,18 @@ var API = class {
|
|
|
4126
4185
|
else
|
|
4127
4186
|
await this.deleteEdge(edge.data);
|
|
4128
4187
|
}
|
|
4188
|
+
/** Update theme and type styles dynamically */
|
|
4189
|
+
updateStyles(options) {
|
|
4190
|
+
this.canvas?.updateStyles(options);
|
|
4191
|
+
}
|
|
4192
|
+
/** Update color mode without recreating the canvas */
|
|
4193
|
+
setColorMode(colorMode) {
|
|
4194
|
+
this.canvas?.setColorMode(colorMode);
|
|
4195
|
+
}
|
|
4196
|
+
/** Cleanup resources when the graph is destroyed */
|
|
4197
|
+
destroy() {
|
|
4198
|
+
this.canvas?.destroy();
|
|
4199
|
+
}
|
|
4129
4200
|
};
|
|
4130
4201
|
|
|
4131
4202
|
// src/api/ingest.ts
|
|
@@ -4415,6 +4486,7 @@ var Playground = class {
|
|
|
4415
4486
|
options;
|
|
4416
4487
|
rootElement;
|
|
4417
4488
|
currentExample;
|
|
4489
|
+
examples;
|
|
4418
4490
|
currentGraph = null;
|
|
4419
4491
|
ingest = null;
|
|
4420
4492
|
isEditable = false;
|
|
@@ -4432,7 +4504,8 @@ var Playground = class {
|
|
|
4432
4504
|
graphContainerId;
|
|
4433
4505
|
constructor(options) {
|
|
4434
4506
|
this.options = options;
|
|
4435
|
-
this.
|
|
4507
|
+
this.examples = { ...options.examples };
|
|
4508
|
+
this.exampleList = Object.keys(this.examples);
|
|
4436
4509
|
this.currentExample = options.defaultExample || this.exampleList[0];
|
|
4437
4510
|
this.graphContainerId = `playground-graph-${Math.random().toString(36).substr(2, 9)}`;
|
|
4438
4511
|
if (typeof options.root === "string") {
|
|
@@ -4463,7 +4536,7 @@ var Playground = class {
|
|
|
4463
4536
|
}
|
|
4464
4537
|
createDOM() {
|
|
4465
4538
|
const exampleList = this.exampleList.map((key, i) => {
|
|
4466
|
-
const example = this.
|
|
4539
|
+
const example = this.examples[key];
|
|
4467
4540
|
const isActive = i === 0 || key === this.currentExample;
|
|
4468
4541
|
return `
|
|
4469
4542
|
<button class="example-btn ${isActive ? "active" : ""}" data-example="${key}">
|
|
@@ -4549,7 +4622,14 @@ var Playground = class {
|
|
|
4549
4622
|
});
|
|
4550
4623
|
});
|
|
4551
4624
|
this.rootElement.querySelectorAll(".options select, .options input").forEach((el) => {
|
|
4552
|
-
el.addEventListener("change", () =>
|
|
4625
|
+
el.addEventListener("change", () => {
|
|
4626
|
+
if (el.id === "colorMode" && this.currentGraph) {
|
|
4627
|
+
const mode = el.value;
|
|
4628
|
+
this.currentGraph.setColorMode(mode);
|
|
4629
|
+
} else {
|
|
4630
|
+
this.renderGraph();
|
|
4631
|
+
}
|
|
4632
|
+
});
|
|
4553
4633
|
});
|
|
4554
4634
|
this.rootElement.querySelector("#nav-first")?.addEventListener("click", () => {
|
|
4555
4635
|
this.currentGraph?.nav("first");
|
|
@@ -4636,8 +4716,10 @@ var Playground = class {
|
|
|
4636
4716
|
async renderGraph() {
|
|
4637
4717
|
const container = this.rootElement.querySelector(`#${this.graphContainerId}`);
|
|
4638
4718
|
if (!container) return;
|
|
4719
|
+
this.currentGraph?.destroy();
|
|
4720
|
+
this.currentGraph = null;
|
|
4639
4721
|
container.innerHTML = "";
|
|
4640
|
-
const example = this.
|
|
4722
|
+
const example = this.examples[this.currentExample];
|
|
4641
4723
|
const options = this.getOptions(example.options);
|
|
4642
4724
|
try {
|
|
4643
4725
|
this.currentGraph = await graph({
|
|
@@ -4668,7 +4750,7 @@ var Playground = class {
|
|
|
4668
4750
|
}
|
|
4669
4751
|
}
|
|
4670
4752
|
connectExampleSource() {
|
|
4671
|
-
const example = this.
|
|
4753
|
+
const example = this.examples[this.currentExample];
|
|
4672
4754
|
if (!example.source) {
|
|
4673
4755
|
this.disconnectAllSources();
|
|
4674
4756
|
return;
|
|
@@ -5011,7 +5093,7 @@ var Playground = class {
|
|
|
5011
5093
|
`;
|
|
5012
5094
|
}
|
|
5013
5095
|
} else if (this.activeSourceType === "file") {
|
|
5014
|
-
const example = this.
|
|
5096
|
+
const example = this.examples[this.currentExample];
|
|
5015
5097
|
const filePath = example.source?.type === "file" ? example.source.path : "";
|
|
5016
5098
|
if (this.fileStatus === "connecting") {
|
|
5017
5099
|
statusDiv.innerHTML = `
|
|
@@ -5109,6 +5191,58 @@ var Playground = class {
|
|
|
5109
5191
|
this.fsSource?.close();
|
|
5110
5192
|
this.updateSourceModal();
|
|
5111
5193
|
}
|
|
5194
|
+
/**
|
|
5195
|
+
* Add or update an example
|
|
5196
|
+
*/
|
|
5197
|
+
addExample(key, example) {
|
|
5198
|
+
this.examples[key] = example;
|
|
5199
|
+
this.updateExampleList();
|
|
5200
|
+
if (this.currentExample === key) {
|
|
5201
|
+
this.renderGraph();
|
|
5202
|
+
this.connectExampleSource();
|
|
5203
|
+
}
|
|
5204
|
+
}
|
|
5205
|
+
/**
|
|
5206
|
+
* Remove an example
|
|
5207
|
+
*/
|
|
5208
|
+
removeExample(key) {
|
|
5209
|
+
delete this.examples[key];
|
|
5210
|
+
if (this.currentExample === key) {
|
|
5211
|
+
this.exampleList = Object.keys(this.examples);
|
|
5212
|
+
this.currentExample = this.exampleList[0] || "";
|
|
5213
|
+
if (this.currentExample) {
|
|
5214
|
+
this.renderGraph();
|
|
5215
|
+
this.connectExampleSource();
|
|
5216
|
+
}
|
|
5217
|
+
}
|
|
5218
|
+
this.updateExampleList();
|
|
5219
|
+
}
|
|
5220
|
+
/**
|
|
5221
|
+
* Update the example list in the DOM
|
|
5222
|
+
*/
|
|
5223
|
+
updateExampleList() {
|
|
5224
|
+
this.exampleList = Object.keys(this.examples);
|
|
5225
|
+
const exampleListEl = this.rootElement.querySelector(".example-list");
|
|
5226
|
+
if (!exampleListEl) return;
|
|
5227
|
+
exampleListEl.innerHTML = this.exampleList.map((key, i) => {
|
|
5228
|
+
const example = this.examples[key];
|
|
5229
|
+
const isActive = key === this.currentExample;
|
|
5230
|
+
return `
|
|
5231
|
+
<button class="example-btn ${isActive ? "active" : ""}" data-example="${key}">
|
|
5232
|
+
${example.name}
|
|
5233
|
+
</button>
|
|
5234
|
+
`;
|
|
5235
|
+
}).join("");
|
|
5236
|
+
exampleListEl.querySelectorAll(".example-btn").forEach((btn) => {
|
|
5237
|
+
btn.addEventListener("click", () => {
|
|
5238
|
+
this.rootElement.querySelectorAll(".example-btn").forEach((b) => b.classList.remove("active"));
|
|
5239
|
+
btn.classList.add("active");
|
|
5240
|
+
this.currentExample = btn.getAttribute("data-example") || this.exampleList[0];
|
|
5241
|
+
this.renderGraph();
|
|
5242
|
+
this.connectExampleSource();
|
|
5243
|
+
});
|
|
5244
|
+
});
|
|
5245
|
+
}
|
|
5112
5246
|
};
|
|
5113
5247
|
|
|
5114
5248
|
// src/index.ts
|
|
@@ -5124,6 +5258,7 @@ var index_default = graph;
|
|
|
5124
5258
|
FileSystemSource,
|
|
5125
5259
|
Ingest,
|
|
5126
5260
|
Playground,
|
|
5261
|
+
Updater,
|
|
5127
5262
|
WebSocketSource,
|
|
5128
5263
|
graph
|
|
5129
5264
|
});
|
package/dist/index.d.cts
CHANGED
|
@@ -75,6 +75,8 @@ type GraphOptions = {
|
|
|
75
75
|
* Events that can be handled by the user.
|
|
76
76
|
*/
|
|
77
77
|
type EventsOptions<N, E> = {
|
|
78
|
+
/** Called when the API has finished initializing */
|
|
79
|
+
onInit?: () => void;
|
|
78
80
|
/** Called when a node is clicked */
|
|
79
81
|
nodeClick?: (node: N) => void;
|
|
80
82
|
/** Called when an edge is clicked */
|
|
@@ -368,7 +370,7 @@ declare class API<N, E> {
|
|
|
368
370
|
private nextNodeId;
|
|
369
371
|
private nextEdgeId;
|
|
370
372
|
private events;
|
|
371
|
-
|
|
373
|
+
root: string;
|
|
372
374
|
constructor(args: APIArguments<N, E>);
|
|
373
375
|
reset(): void;
|
|
374
376
|
/** Initialize the API */
|
|
@@ -436,6 +438,16 @@ declare class API<N, E> {
|
|
|
436
438
|
handleAddEdge(data: EditEdgeProps): Promise<void>;
|
|
437
439
|
handleDeleteNode(id: NodeId): Promise<void>;
|
|
438
440
|
handleDeleteEdge(id: EdgeId): Promise<void>;
|
|
441
|
+
/** Update theme and type styles dynamically */
|
|
442
|
+
updateStyles(options: {
|
|
443
|
+
theme?: ThemeVars;
|
|
444
|
+
nodeTypes?: Record<string, ThemeVars>;
|
|
445
|
+
edgeTypes?: Record<string, ThemeVars>;
|
|
446
|
+
}): void;
|
|
447
|
+
/** Update color mode without recreating the canvas */
|
|
448
|
+
setColorMode(colorMode: 'light' | 'dark' | 'system'): void;
|
|
449
|
+
/** Cleanup resources when the graph is destroyed */
|
|
450
|
+
destroy(): void;
|
|
439
451
|
}
|
|
440
452
|
|
|
441
453
|
type SnapshotMessage<N, E> = {
|
|
@@ -575,6 +587,7 @@ declare class Playground {
|
|
|
575
587
|
private options;
|
|
576
588
|
private rootElement;
|
|
577
589
|
private currentExample;
|
|
590
|
+
private examples;
|
|
578
591
|
private currentGraph;
|
|
579
592
|
private ingest;
|
|
580
593
|
private isEditable;
|
|
@@ -619,8 +632,20 @@ declare class Playground {
|
|
|
619
632
|
private handleChangeConnection;
|
|
620
633
|
private handleOpenFolder;
|
|
621
634
|
private handleCloseFolder;
|
|
635
|
+
/**
|
|
636
|
+
* Add or update an example
|
|
637
|
+
*/
|
|
638
|
+
addExample(key: string, example: Example): void;
|
|
639
|
+
/**
|
|
640
|
+
* Remove an example
|
|
641
|
+
*/
|
|
642
|
+
removeExample(key: string): void;
|
|
643
|
+
/**
|
|
644
|
+
* Update the example list in the DOM
|
|
645
|
+
*/
|
|
646
|
+
private updateExampleList;
|
|
622
647
|
}
|
|
623
648
|
|
|
624
649
|
declare function graph<N, E>(args?: APIArguments<N, E>): Promise<API<N, E>>;
|
|
625
650
|
|
|
626
|
-
export { type Example, type ExampleEdge, type ExampleNode, type ExampleOptions, FileSource, FileSystemSource, type HistoryMessage, Ingest, type IngestMessage, Playground, type PlaygroundOptions, type SnapshotMessage, type UpdateMessage, WebSocketSource, graph as default, graph };
|
|
651
|
+
export { API, type APIArguments, type APIOptions, type EventsOptions, type Example, type ExampleEdge, type ExampleNode, type ExampleOptions, FileSource, FileSystemSource, type HistoryMessage, Ingest, type IngestMessage, Playground, type PlaygroundOptions, type SnapshotMessage, type Update, type UpdateMessage, Updater, WebSocketSource, graph as default, graph };
|
package/dist/index.d.ts
CHANGED
|
@@ -75,6 +75,8 @@ type GraphOptions = {
|
|
|
75
75
|
* Events that can be handled by the user.
|
|
76
76
|
*/
|
|
77
77
|
type EventsOptions<N, E> = {
|
|
78
|
+
/** Called when the API has finished initializing */
|
|
79
|
+
onInit?: () => void;
|
|
78
80
|
/** Called when a node is clicked */
|
|
79
81
|
nodeClick?: (node: N) => void;
|
|
80
82
|
/** Called when an edge is clicked */
|
|
@@ -368,7 +370,7 @@ declare class API<N, E> {
|
|
|
368
370
|
private nextNodeId;
|
|
369
371
|
private nextEdgeId;
|
|
370
372
|
private events;
|
|
371
|
-
|
|
373
|
+
root: string;
|
|
372
374
|
constructor(args: APIArguments<N, E>);
|
|
373
375
|
reset(): void;
|
|
374
376
|
/** Initialize the API */
|
|
@@ -436,6 +438,16 @@ declare class API<N, E> {
|
|
|
436
438
|
handleAddEdge(data: EditEdgeProps): Promise<void>;
|
|
437
439
|
handleDeleteNode(id: NodeId): Promise<void>;
|
|
438
440
|
handleDeleteEdge(id: EdgeId): Promise<void>;
|
|
441
|
+
/** Update theme and type styles dynamically */
|
|
442
|
+
updateStyles(options: {
|
|
443
|
+
theme?: ThemeVars;
|
|
444
|
+
nodeTypes?: Record<string, ThemeVars>;
|
|
445
|
+
edgeTypes?: Record<string, ThemeVars>;
|
|
446
|
+
}): void;
|
|
447
|
+
/** Update color mode without recreating the canvas */
|
|
448
|
+
setColorMode(colorMode: 'light' | 'dark' | 'system'): void;
|
|
449
|
+
/** Cleanup resources when the graph is destroyed */
|
|
450
|
+
destroy(): void;
|
|
439
451
|
}
|
|
440
452
|
|
|
441
453
|
type SnapshotMessage<N, E> = {
|
|
@@ -575,6 +587,7 @@ declare class Playground {
|
|
|
575
587
|
private options;
|
|
576
588
|
private rootElement;
|
|
577
589
|
private currentExample;
|
|
590
|
+
private examples;
|
|
578
591
|
private currentGraph;
|
|
579
592
|
private ingest;
|
|
580
593
|
private isEditable;
|
|
@@ -619,8 +632,20 @@ declare class Playground {
|
|
|
619
632
|
private handleChangeConnection;
|
|
620
633
|
private handleOpenFolder;
|
|
621
634
|
private handleCloseFolder;
|
|
635
|
+
/**
|
|
636
|
+
* Add or update an example
|
|
637
|
+
*/
|
|
638
|
+
addExample(key: string, example: Example): void;
|
|
639
|
+
/**
|
|
640
|
+
* Remove an example
|
|
641
|
+
*/
|
|
642
|
+
removeExample(key: string): void;
|
|
643
|
+
/**
|
|
644
|
+
* Update the example list in the DOM
|
|
645
|
+
*/
|
|
646
|
+
private updateExampleList;
|
|
622
647
|
}
|
|
623
648
|
|
|
624
649
|
declare function graph<N, E>(args?: APIArguments<N, E>): Promise<API<N, E>>;
|
|
625
650
|
|
|
626
|
-
export { type Example, type ExampleEdge, type ExampleNode, type ExampleOptions, FileSource, FileSystemSource, type HistoryMessage, Ingest, type IngestMessage, Playground, type PlaygroundOptions, type SnapshotMessage, type UpdateMessage, WebSocketSource, graph as default, graph };
|
|
651
|
+
export { API, type APIArguments, type APIOptions, type EventsOptions, type Example, type ExampleEdge, type ExampleNode, type ExampleOptions, FileSource, FileSystemSource, type HistoryMessage, Ingest, type IngestMessage, Playground, type PlaygroundOptions, type SnapshotMessage, type Update, type UpdateMessage, Updater, WebSocketSource, graph as default, graph };
|
package/dist/index.js
CHANGED
|
@@ -1338,15 +1338,16 @@ var Layout = class _Layout {
|
|
|
1338
1338
|
|
|
1339
1339
|
// src/canvas/marker.tsx
|
|
1340
1340
|
import { jsx } from "jsx-dom/jsx-runtime";
|
|
1341
|
-
function arrow(size, reverse = false) {
|
|
1341
|
+
function arrow(size, reverse = false, prefix = "") {
|
|
1342
1342
|
const h = size / 1.5;
|
|
1343
1343
|
const w = size;
|
|
1344
1344
|
const ry = h / 2;
|
|
1345
1345
|
const suffix = reverse ? "-reverse" : "";
|
|
1346
|
+
const id = prefix ? `${prefix}-g3p-marker-arrow${suffix}` : `g3p-marker-arrow${suffix}`;
|
|
1346
1347
|
return /* @__PURE__ */ jsx(
|
|
1347
1348
|
"marker",
|
|
1348
1349
|
{
|
|
1349
|
-
id
|
|
1350
|
+
id,
|
|
1350
1351
|
className: "g3p-marker g3p-marker-arrow",
|
|
1351
1352
|
markerWidth: size,
|
|
1352
1353
|
markerHeight: size,
|
|
@@ -1358,14 +1359,15 @@ function arrow(size, reverse = false) {
|
|
|
1358
1359
|
}
|
|
1359
1360
|
);
|
|
1360
1361
|
}
|
|
1361
|
-
function circle(size, reverse = false) {
|
|
1362
|
+
function circle(size, reverse = false, prefix = "") {
|
|
1362
1363
|
const r = size / 3;
|
|
1363
1364
|
const cy = size / 2;
|
|
1364
1365
|
const suffix = reverse ? "-reverse" : "";
|
|
1366
|
+
const id = prefix ? `${prefix}-g3p-marker-circle${suffix}` : `g3p-marker-circle${suffix}`;
|
|
1365
1367
|
return /* @__PURE__ */ jsx(
|
|
1366
1368
|
"marker",
|
|
1367
1369
|
{
|
|
1368
|
-
id
|
|
1370
|
+
id,
|
|
1369
1371
|
className: "g3p-marker g3p-marker-circle",
|
|
1370
1372
|
markerWidth: size,
|
|
1371
1373
|
markerHeight: size,
|
|
@@ -1377,15 +1379,16 @@ function circle(size, reverse = false) {
|
|
|
1377
1379
|
}
|
|
1378
1380
|
);
|
|
1379
1381
|
}
|
|
1380
|
-
function diamond(size, reverse = false) {
|
|
1382
|
+
function diamond(size, reverse = false, prefix = "") {
|
|
1381
1383
|
const w = size * 0.7;
|
|
1382
1384
|
const h = size / 2;
|
|
1383
1385
|
const cy = size / 2;
|
|
1384
1386
|
const suffix = reverse ? "-reverse" : "";
|
|
1387
|
+
const id = prefix ? `${prefix}-g3p-marker-diamond${suffix}` : `g3p-marker-diamond${suffix}`;
|
|
1385
1388
|
return /* @__PURE__ */ jsx(
|
|
1386
1389
|
"marker",
|
|
1387
1390
|
{
|
|
1388
|
-
id
|
|
1391
|
+
id,
|
|
1389
1392
|
className: "g3p-marker g3p-marker-diamond",
|
|
1390
1393
|
markerWidth: size,
|
|
1391
1394
|
markerHeight: size,
|
|
@@ -1397,14 +1400,15 @@ function diamond(size, reverse = false) {
|
|
|
1397
1400
|
}
|
|
1398
1401
|
);
|
|
1399
1402
|
}
|
|
1400
|
-
function bar(size, reverse = false) {
|
|
1403
|
+
function bar(size, reverse = false, prefix = "") {
|
|
1401
1404
|
const h = size * 0.6;
|
|
1402
1405
|
const cy = size / 2;
|
|
1403
1406
|
const suffix = reverse ? "-reverse" : "";
|
|
1407
|
+
const id = prefix ? `${prefix}-g3p-marker-bar${suffix}` : `g3p-marker-bar${suffix}`;
|
|
1404
1408
|
return /* @__PURE__ */ jsx(
|
|
1405
1409
|
"marker",
|
|
1406
1410
|
{
|
|
1407
|
-
id
|
|
1411
|
+
id,
|
|
1408
1412
|
className: "g3p-marker g3p-marker-bar",
|
|
1409
1413
|
markerWidth: size,
|
|
1410
1414
|
markerHeight: size,
|
|
@@ -1416,7 +1420,7 @@ function bar(size, reverse = false) {
|
|
|
1416
1420
|
}
|
|
1417
1421
|
);
|
|
1418
1422
|
}
|
|
1419
|
-
function none(size, reverse = false) {
|
|
1423
|
+
function none(size, reverse = false, prefix = "") {
|
|
1420
1424
|
return void 0;
|
|
1421
1425
|
}
|
|
1422
1426
|
function normalize(data) {
|
|
@@ -2198,6 +2202,9 @@ var Seg2 = class {
|
|
|
2198
2202
|
if (this.source.isDummy) source = void 0;
|
|
2199
2203
|
if (this.target.isDummy) target = void 0;
|
|
2200
2204
|
const typeClass = this.type ? `g3p-edge-type-${this.type}` : "";
|
|
2205
|
+
const prefix = this.canvas.markerPrefix;
|
|
2206
|
+
const markerStartId = source ? prefix ? `${prefix}-g3p-marker-${source}-reverse` : `g3p-marker-${source}-reverse` : void 0;
|
|
2207
|
+
const markerEndId = target ? prefix ? `${prefix}-g3p-marker-${target}` : `g3p-marker-${target}` : void 0;
|
|
2201
2208
|
return /* @__PURE__ */ jsxs2(
|
|
2202
2209
|
"g",
|
|
2203
2210
|
{
|
|
@@ -2212,8 +2219,8 @@ var Seg2 = class {
|
|
|
2212
2219
|
d: this.svg,
|
|
2213
2220
|
fill: "none",
|
|
2214
2221
|
className: "g3p-seg-line",
|
|
2215
|
-
markerStart:
|
|
2216
|
-
markerEnd:
|
|
2222
|
+
markerStart: markerStartId ? `url(#${markerStartId})` : void 0,
|
|
2223
|
+
markerEnd: markerEndId ? `url(#${markerEndId})` : void 0
|
|
2217
2224
|
}
|
|
2218
2225
|
),
|
|
2219
2226
|
/* @__PURE__ */ jsx3(
|
|
@@ -2798,6 +2805,10 @@ var Canvas = class {
|
|
|
2798
2805
|
curNodes;
|
|
2799
2806
|
curSegs;
|
|
2800
2807
|
updating;
|
|
2808
|
+
// Unique marker ID prefix for this canvas instance
|
|
2809
|
+
markerPrefix;
|
|
2810
|
+
// Dynamic style element for this instance (for cleanup)
|
|
2811
|
+
dynamicStyleEl;
|
|
2801
2812
|
// Pan-zoom state
|
|
2802
2813
|
panScale = null;
|
|
2803
2814
|
zoomControls;
|
|
@@ -2811,6 +2822,13 @@ var Canvas = class {
|
|
|
2811
2822
|
constructor(api, options) {
|
|
2812
2823
|
Object.assign(this, options);
|
|
2813
2824
|
this.api = api;
|
|
2825
|
+
this.reset();
|
|
2826
|
+
this.markerPrefix = api.root.replace(/[^a-zA-Z0-9-_]/g, "-");
|
|
2827
|
+
this.createMeasurementContainer();
|
|
2828
|
+
this.createCanvasContainer();
|
|
2829
|
+
if (this.panZoom) this.setupPanZoom();
|
|
2830
|
+
}
|
|
2831
|
+
reset() {
|
|
2814
2832
|
this.allNodes = /* @__PURE__ */ new Map();
|
|
2815
2833
|
this.curNodes = /* @__PURE__ */ new Map();
|
|
2816
2834
|
this.curSegs = /* @__PURE__ */ new Map();
|
|
@@ -2819,9 +2837,7 @@ var Canvas = class {
|
|
|
2819
2837
|
this.transform = { x: 0, y: 0, scale: 1 };
|
|
2820
2838
|
this.editMode = new EditMode();
|
|
2821
2839
|
this.editMode.editable = this.editable;
|
|
2822
|
-
this.
|
|
2823
|
-
this.createCanvasContainer();
|
|
2824
|
-
if (this.panZoom) this.setupPanZoom();
|
|
2840
|
+
if (this.group) this.group.innerHTML = "";
|
|
2825
2841
|
}
|
|
2826
2842
|
createMeasurementContainer() {
|
|
2827
2843
|
this.measurement = document.createElement("div");
|
|
@@ -3006,12 +3022,13 @@ var Canvas = class {
|
|
|
3006
3022
|
}
|
|
3007
3023
|
generateDynamicStyles() {
|
|
3008
3024
|
let css = "";
|
|
3009
|
-
|
|
3025
|
+
const scope = `[data-g3p-instance="${this.markerPrefix}"]`;
|
|
3026
|
+
css += themeToCSS(this.theme, scope);
|
|
3010
3027
|
for (const [type, vars] of Object.entries(this.nodeTypes)) {
|
|
3011
|
-
css += themeToCSS(vars,
|
|
3028
|
+
css += themeToCSS(vars, `${scope} .g3p-node-type-${type}`, "node");
|
|
3012
3029
|
}
|
|
3013
3030
|
for (const [type, vars] of Object.entries(this.edgeTypes)) {
|
|
3014
|
-
css += themeToCSS(vars,
|
|
3031
|
+
css += themeToCSS(vars, `${scope} .g3p-edge-type-${type}`);
|
|
3015
3032
|
}
|
|
3016
3033
|
return css;
|
|
3017
3034
|
}
|
|
@@ -3024,15 +3041,18 @@ var Canvas = class {
|
|
|
3024
3041
|
}
|
|
3025
3042
|
const dynamicStyles = this.generateDynamicStyles();
|
|
3026
3043
|
if (dynamicStyles) {
|
|
3027
|
-
|
|
3028
|
-
dynamicStyleEl
|
|
3029
|
-
|
|
3044
|
+
this.dynamicStyleEl?.remove();
|
|
3045
|
+
this.dynamicStyleEl = document.createElement("style");
|
|
3046
|
+
this.dynamicStyleEl.id = `g3p-styles-${this.markerPrefix}`;
|
|
3047
|
+
this.dynamicStyleEl.textContent = dynamicStyles;
|
|
3048
|
+
document.head.appendChild(this.dynamicStyleEl);
|
|
3030
3049
|
}
|
|
3031
3050
|
const colorModeClass = this.colorMode !== "system" ? `g3p-${this.colorMode}` : "";
|
|
3032
3051
|
this.container = /* @__PURE__ */ jsx6(
|
|
3033
3052
|
"div",
|
|
3034
3053
|
{
|
|
3035
3054
|
className: `g3p-canvas-container ${colorModeClass}`.trim(),
|
|
3055
|
+
"data-g3p-instance": this.markerPrefix,
|
|
3036
3056
|
ref: (el) => this.container = el,
|
|
3037
3057
|
onContextMenu: this.onContextMenu.bind(this),
|
|
3038
3058
|
children: /* @__PURE__ */ jsxs5(
|
|
@@ -3048,8 +3068,8 @@ var Canvas = class {
|
|
|
3048
3068
|
onDblClick: this.onDoubleClick.bind(this),
|
|
3049
3069
|
children: [
|
|
3050
3070
|
/* @__PURE__ */ jsxs5("defs", { children: [
|
|
3051
|
-
Object.values(markerDefs).map((marker) => marker(this.markerSize, false)),
|
|
3052
|
-
Object.values(markerDefs).map((marker) => marker(this.markerSize, true))
|
|
3071
|
+
Object.values(markerDefs).map((marker) => marker(this.markerSize, false, this.markerPrefix)),
|
|
3072
|
+
Object.values(markerDefs).map((marker) => marker(this.markerSize, true, this.markerPrefix))
|
|
3053
3073
|
] }),
|
|
3054
3074
|
/* @__PURE__ */ jsx6(
|
|
3055
3075
|
"g",
|
|
@@ -3406,6 +3426,40 @@ var Canvas = class {
|
|
|
3406
3426
|
}
|
|
3407
3427
|
return { type: "canvas" };
|
|
3408
3428
|
}
|
|
3429
|
+
/** Update theme and type styles dynamically */
|
|
3430
|
+
updateStyles(options) {
|
|
3431
|
+
if (options.theme !== void 0) this.theme = options.theme;
|
|
3432
|
+
if (options.nodeTypes !== void 0) this.nodeTypes = options.nodeTypes;
|
|
3433
|
+
if (options.edgeTypes !== void 0) this.edgeTypes = options.edgeTypes;
|
|
3434
|
+
const dynamicStyles = this.generateDynamicStyles();
|
|
3435
|
+
if (dynamicStyles) {
|
|
3436
|
+
if (!this.dynamicStyleEl) {
|
|
3437
|
+
this.dynamicStyleEl = document.createElement("style");
|
|
3438
|
+
this.dynamicStyleEl.id = `g3p-styles-${this.markerPrefix}`;
|
|
3439
|
+
document.head.appendChild(this.dynamicStyleEl);
|
|
3440
|
+
}
|
|
3441
|
+
this.dynamicStyleEl.textContent = dynamicStyles;
|
|
3442
|
+
} else if (this.dynamicStyleEl) {
|
|
3443
|
+
this.dynamicStyleEl.remove();
|
|
3444
|
+
this.dynamicStyleEl = void 0;
|
|
3445
|
+
}
|
|
3446
|
+
}
|
|
3447
|
+
/** Update color mode without recreating the canvas */
|
|
3448
|
+
setColorMode(colorMode) {
|
|
3449
|
+
if (!this.container) return;
|
|
3450
|
+
this.colorMode = colorMode;
|
|
3451
|
+
this.container.classList.remove("g3p-light", "g3p-dark");
|
|
3452
|
+
if (colorMode !== "system") {
|
|
3453
|
+
this.container.classList.add(`g3p-${colorMode}`);
|
|
3454
|
+
}
|
|
3455
|
+
}
|
|
3456
|
+
/** Cleanup resources when the canvas is destroyed */
|
|
3457
|
+
destroy() {
|
|
3458
|
+
this.dynamicStyleEl?.remove();
|
|
3459
|
+
this.dynamicStyleEl = void 0;
|
|
3460
|
+
this.measurement?.remove();
|
|
3461
|
+
this.measurement = void 0;
|
|
3462
|
+
}
|
|
3409
3463
|
};
|
|
3410
3464
|
var themeVarMap = {
|
|
3411
3465
|
// Canvas
|
|
@@ -3622,6 +3676,7 @@ var API = class {
|
|
|
3622
3676
|
this.nodeFields = /* @__PURE__ */ new Map();
|
|
3623
3677
|
this.nextNodeId = 1;
|
|
3624
3678
|
this.nextEdgeId = 1;
|
|
3679
|
+
this.canvas?.reset?.();
|
|
3625
3680
|
}
|
|
3626
3681
|
/** Initialize the API */
|
|
3627
3682
|
async init() {
|
|
@@ -3629,6 +3684,9 @@ var API = class {
|
|
|
3629
3684
|
if (!root) throw new Error("root element not found");
|
|
3630
3685
|
root.appendChild(this.canvas.container);
|
|
3631
3686
|
await this.applyHistory();
|
|
3687
|
+
if (this.events.onInit) {
|
|
3688
|
+
this.events.onInit();
|
|
3689
|
+
}
|
|
3632
3690
|
}
|
|
3633
3691
|
async applyHistory() {
|
|
3634
3692
|
for (const update of this.history)
|
|
@@ -4084,6 +4142,18 @@ var API = class {
|
|
|
4084
4142
|
else
|
|
4085
4143
|
await this.deleteEdge(edge.data);
|
|
4086
4144
|
}
|
|
4145
|
+
/** Update theme and type styles dynamically */
|
|
4146
|
+
updateStyles(options) {
|
|
4147
|
+
this.canvas?.updateStyles(options);
|
|
4148
|
+
}
|
|
4149
|
+
/** Update color mode without recreating the canvas */
|
|
4150
|
+
setColorMode(colorMode) {
|
|
4151
|
+
this.canvas?.setColorMode(colorMode);
|
|
4152
|
+
}
|
|
4153
|
+
/** Cleanup resources when the graph is destroyed */
|
|
4154
|
+
destroy() {
|
|
4155
|
+
this.canvas?.destroy();
|
|
4156
|
+
}
|
|
4087
4157
|
};
|
|
4088
4158
|
|
|
4089
4159
|
// src/api/ingest.ts
|
|
@@ -4373,6 +4443,7 @@ var Playground = class {
|
|
|
4373
4443
|
options;
|
|
4374
4444
|
rootElement;
|
|
4375
4445
|
currentExample;
|
|
4446
|
+
examples;
|
|
4376
4447
|
currentGraph = null;
|
|
4377
4448
|
ingest = null;
|
|
4378
4449
|
isEditable = false;
|
|
@@ -4390,7 +4461,8 @@ var Playground = class {
|
|
|
4390
4461
|
graphContainerId;
|
|
4391
4462
|
constructor(options) {
|
|
4392
4463
|
this.options = options;
|
|
4393
|
-
this.
|
|
4464
|
+
this.examples = { ...options.examples };
|
|
4465
|
+
this.exampleList = Object.keys(this.examples);
|
|
4394
4466
|
this.currentExample = options.defaultExample || this.exampleList[0];
|
|
4395
4467
|
this.graphContainerId = `playground-graph-${Math.random().toString(36).substr(2, 9)}`;
|
|
4396
4468
|
if (typeof options.root === "string") {
|
|
@@ -4421,7 +4493,7 @@ var Playground = class {
|
|
|
4421
4493
|
}
|
|
4422
4494
|
createDOM() {
|
|
4423
4495
|
const exampleList = this.exampleList.map((key, i) => {
|
|
4424
|
-
const example = this.
|
|
4496
|
+
const example = this.examples[key];
|
|
4425
4497
|
const isActive = i === 0 || key === this.currentExample;
|
|
4426
4498
|
return `
|
|
4427
4499
|
<button class="example-btn ${isActive ? "active" : ""}" data-example="${key}">
|
|
@@ -4507,7 +4579,14 @@ var Playground = class {
|
|
|
4507
4579
|
});
|
|
4508
4580
|
});
|
|
4509
4581
|
this.rootElement.querySelectorAll(".options select, .options input").forEach((el) => {
|
|
4510
|
-
el.addEventListener("change", () =>
|
|
4582
|
+
el.addEventListener("change", () => {
|
|
4583
|
+
if (el.id === "colorMode" && this.currentGraph) {
|
|
4584
|
+
const mode = el.value;
|
|
4585
|
+
this.currentGraph.setColorMode(mode);
|
|
4586
|
+
} else {
|
|
4587
|
+
this.renderGraph();
|
|
4588
|
+
}
|
|
4589
|
+
});
|
|
4511
4590
|
});
|
|
4512
4591
|
this.rootElement.querySelector("#nav-first")?.addEventListener("click", () => {
|
|
4513
4592
|
this.currentGraph?.nav("first");
|
|
@@ -4594,8 +4673,10 @@ var Playground = class {
|
|
|
4594
4673
|
async renderGraph() {
|
|
4595
4674
|
const container = this.rootElement.querySelector(`#${this.graphContainerId}`);
|
|
4596
4675
|
if (!container) return;
|
|
4676
|
+
this.currentGraph?.destroy();
|
|
4677
|
+
this.currentGraph = null;
|
|
4597
4678
|
container.innerHTML = "";
|
|
4598
|
-
const example = this.
|
|
4679
|
+
const example = this.examples[this.currentExample];
|
|
4599
4680
|
const options = this.getOptions(example.options);
|
|
4600
4681
|
try {
|
|
4601
4682
|
this.currentGraph = await graph({
|
|
@@ -4626,7 +4707,7 @@ var Playground = class {
|
|
|
4626
4707
|
}
|
|
4627
4708
|
}
|
|
4628
4709
|
connectExampleSource() {
|
|
4629
|
-
const example = this.
|
|
4710
|
+
const example = this.examples[this.currentExample];
|
|
4630
4711
|
if (!example.source) {
|
|
4631
4712
|
this.disconnectAllSources();
|
|
4632
4713
|
return;
|
|
@@ -4969,7 +5050,7 @@ var Playground = class {
|
|
|
4969
5050
|
`;
|
|
4970
5051
|
}
|
|
4971
5052
|
} else if (this.activeSourceType === "file") {
|
|
4972
|
-
const example = this.
|
|
5053
|
+
const example = this.examples[this.currentExample];
|
|
4973
5054
|
const filePath = example.source?.type === "file" ? example.source.path : "";
|
|
4974
5055
|
if (this.fileStatus === "connecting") {
|
|
4975
5056
|
statusDiv.innerHTML = `
|
|
@@ -5067,6 +5148,58 @@ var Playground = class {
|
|
|
5067
5148
|
this.fsSource?.close();
|
|
5068
5149
|
this.updateSourceModal();
|
|
5069
5150
|
}
|
|
5151
|
+
/**
|
|
5152
|
+
* Add or update an example
|
|
5153
|
+
*/
|
|
5154
|
+
addExample(key, example) {
|
|
5155
|
+
this.examples[key] = example;
|
|
5156
|
+
this.updateExampleList();
|
|
5157
|
+
if (this.currentExample === key) {
|
|
5158
|
+
this.renderGraph();
|
|
5159
|
+
this.connectExampleSource();
|
|
5160
|
+
}
|
|
5161
|
+
}
|
|
5162
|
+
/**
|
|
5163
|
+
* Remove an example
|
|
5164
|
+
*/
|
|
5165
|
+
removeExample(key) {
|
|
5166
|
+
delete this.examples[key];
|
|
5167
|
+
if (this.currentExample === key) {
|
|
5168
|
+
this.exampleList = Object.keys(this.examples);
|
|
5169
|
+
this.currentExample = this.exampleList[0] || "";
|
|
5170
|
+
if (this.currentExample) {
|
|
5171
|
+
this.renderGraph();
|
|
5172
|
+
this.connectExampleSource();
|
|
5173
|
+
}
|
|
5174
|
+
}
|
|
5175
|
+
this.updateExampleList();
|
|
5176
|
+
}
|
|
5177
|
+
/**
|
|
5178
|
+
* Update the example list in the DOM
|
|
5179
|
+
*/
|
|
5180
|
+
updateExampleList() {
|
|
5181
|
+
this.exampleList = Object.keys(this.examples);
|
|
5182
|
+
const exampleListEl = this.rootElement.querySelector(".example-list");
|
|
5183
|
+
if (!exampleListEl) return;
|
|
5184
|
+
exampleListEl.innerHTML = this.exampleList.map((key, i) => {
|
|
5185
|
+
const example = this.examples[key];
|
|
5186
|
+
const isActive = key === this.currentExample;
|
|
5187
|
+
return `
|
|
5188
|
+
<button class="example-btn ${isActive ? "active" : ""}" data-example="${key}">
|
|
5189
|
+
${example.name}
|
|
5190
|
+
</button>
|
|
5191
|
+
`;
|
|
5192
|
+
}).join("");
|
|
5193
|
+
exampleListEl.querySelectorAll(".example-btn").forEach((btn) => {
|
|
5194
|
+
btn.addEventListener("click", () => {
|
|
5195
|
+
this.rootElement.querySelectorAll(".example-btn").forEach((b) => b.classList.remove("active"));
|
|
5196
|
+
btn.classList.add("active");
|
|
5197
|
+
this.currentExample = btn.getAttribute("data-example") || this.exampleList[0];
|
|
5198
|
+
this.renderGraph();
|
|
5199
|
+
this.connectExampleSource();
|
|
5200
|
+
});
|
|
5201
|
+
});
|
|
5202
|
+
}
|
|
5070
5203
|
};
|
|
5071
5204
|
|
|
5072
5205
|
// src/index.ts
|
|
@@ -5081,6 +5214,7 @@ export {
|
|
|
5081
5214
|
FileSystemSource,
|
|
5082
5215
|
Ingest,
|
|
5083
5216
|
Playground,
|
|
5217
|
+
Updater,
|
|
5084
5218
|
WebSocketSource,
|
|
5085
5219
|
index_default as default,
|
|
5086
5220
|
graph
|