@magicborn/dialogue-forge 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +233 -0
- package/bin/dialogue-forge.js +78 -0
- package/demo/app/layout.tsx +36 -0
- package/demo/app/page.tsx +440 -0
- package/demo/components/ThemeSwitcher.tsx +611 -0
- package/demo/next.config.mjs +7 -0
- package/demo/package.json +29 -0
- package/demo/postcss.config.mjs +7 -0
- package/demo/public/logo.svg +1 -0
- package/demo/styles/globals.css +19 -0
- package/demo/tailwind.config.ts +90 -0
- package/demo/tsconfig.json +42 -0
- package/dist/components/ChoiceEdgeV2.d.ts +3 -0
- package/dist/components/ChoiceEdgeV2.js +103 -0
- package/dist/components/CodeBlock.d.ts +8 -0
- package/dist/components/CodeBlock.js +24 -0
- package/dist/components/ConditionAutocomplete.d.ts +14 -0
- package/dist/components/ConditionAutocomplete.js +284 -0
- package/dist/components/ConditionalNodeV2.d.ts +16 -0
- package/dist/components/ConditionalNodeV2.js +147 -0
- package/dist/components/DialogueEditorV2.d.ts +22 -0
- package/dist/components/DialogueEditorV2.js +1170 -0
- package/dist/components/EdgeIcon.d.ts +8 -0
- package/dist/components/EdgeIcon.js +13 -0
- package/dist/components/ExampleLoader.d.ts +11 -0
- package/dist/components/ExampleLoader.js +52 -0
- package/dist/components/ExampleLoaderButton.d.ts +15 -0
- package/dist/components/ExampleLoaderButton.js +102 -0
- package/dist/components/FlagManager.d.ts +11 -0
- package/dist/components/FlagManager.js +282 -0
- package/dist/components/FlagSelector.d.ts +11 -0
- package/dist/components/FlagSelector.js +235 -0
- package/dist/components/GuidePanel.d.ts +7 -0
- package/dist/components/GuidePanel.js +1176 -0
- package/dist/components/Minimap.d.ts +16 -0
- package/dist/components/Minimap.js +93 -0
- package/dist/components/NPCEdgeV2.d.ts +3 -0
- package/dist/components/NPCEdgeV2.js +104 -0
- package/dist/components/NPCNodeV2.d.ts +26 -0
- package/dist/components/NPCNodeV2.js +86 -0
- package/dist/components/NodeEditor.d.ts +18 -0
- package/dist/components/NodeEditor.js +1025 -0
- package/dist/components/PlayView.d.ts +12 -0
- package/dist/components/PlayView.js +307 -0
- package/dist/components/PlayerNodeV2.d.ts +16 -0
- package/dist/components/PlayerNodeV2.js +139 -0
- package/dist/components/ReactFlowPOC.d.ts +61 -0
- package/dist/components/ReactFlowPOC.js +312 -0
- package/dist/components/ScenePlayer.d.ts +18 -0
- package/dist/components/ScenePlayer.js +196 -0
- package/dist/components/YarnView.d.ts +9 -0
- package/dist/components/YarnView.js +45 -0
- package/dist/components/ZoomControls.d.ts +11 -0
- package/dist/components/ZoomControls.js +34 -0
- package/dist/esm/components/ChoiceEdgeV2.d.ts +3 -0
- package/dist/esm/components/ChoiceEdgeV2.js +67 -0
- package/dist/esm/components/CodeBlock.d.ts +8 -0
- package/dist/esm/components/CodeBlock.js +18 -0
- package/dist/esm/components/ConditionAutocomplete.d.ts +14 -0
- package/dist/esm/components/ConditionAutocomplete.js +248 -0
- package/dist/esm/components/ConditionalNodeV2.d.ts +16 -0
- package/dist/esm/components/ConditionalNodeV2.js +111 -0
- package/dist/esm/components/DialogueEditorV2.d.ts +22 -0
- package/dist/esm/components/DialogueEditorV2.js +1134 -0
- package/dist/esm/components/EdgeIcon.d.ts +8 -0
- package/dist/esm/components/EdgeIcon.js +7 -0
- package/dist/esm/components/ExampleLoader.d.ts +11 -0
- package/dist/esm/components/ExampleLoader.js +46 -0
- package/dist/esm/components/ExampleLoaderButton.d.ts +15 -0
- package/dist/esm/components/ExampleLoaderButton.js +66 -0
- package/dist/esm/components/FlagManager.d.ts +11 -0
- package/dist/esm/components/FlagManager.js +246 -0
- package/dist/esm/components/FlagSelector.d.ts +11 -0
- package/dist/esm/components/FlagSelector.js +199 -0
- package/dist/esm/components/GuidePanel.d.ts +7 -0
- package/dist/esm/components/GuidePanel.js +1140 -0
- package/dist/esm/components/Minimap.d.ts +16 -0
- package/dist/esm/components/Minimap.js +57 -0
- package/dist/esm/components/NPCEdgeV2.d.ts +3 -0
- package/dist/esm/components/NPCEdgeV2.js +68 -0
- package/dist/esm/components/NPCNodeV2.d.ts +26 -0
- package/dist/esm/components/NPCNodeV2.js +80 -0
- package/dist/esm/components/NodeEditor.d.ts +18 -0
- package/dist/esm/components/NodeEditor.js +989 -0
- package/dist/esm/components/PlayView.d.ts +12 -0
- package/dist/esm/components/PlayView.js +271 -0
- package/dist/esm/components/PlayerNodeV2.d.ts +16 -0
- package/dist/esm/components/PlayerNodeV2.js +103 -0
- package/dist/esm/components/ReactFlowPOC.d.ts +61 -0
- package/dist/esm/components/ReactFlowPOC.js +275 -0
- package/dist/esm/components/ScenePlayer.d.ts +18 -0
- package/dist/esm/components/ScenePlayer.js +160 -0
- package/dist/esm/components/YarnView.d.ts +9 -0
- package/dist/esm/components/YarnView.js +39 -0
- package/dist/esm/components/ZoomControls.d.ts +11 -0
- package/dist/esm/components/ZoomControls.js +28 -0
- package/dist/esm/examples/example-loader.d.ts +29 -0
- package/dist/esm/examples/example-loader.js +103 -0
- package/dist/esm/examples/examples-registry.d.ts +38 -0
- package/dist/esm/examples/examples-registry.js +153 -0
- package/dist/esm/examples/index.d.ts +26 -0
- package/dist/esm/examples/index.js +50 -0
- package/dist/esm/examples/legacy-examples.d.ts +9 -0
- package/dist/esm/examples/legacy-examples.js +814 -0
- package/dist/esm/examples/yarn-examples.d.ts +35 -0
- package/dist/esm/examples/yarn-examples.js +181 -0
- package/dist/esm/index.d.ts +21 -0
- package/dist/esm/index.js +26 -0
- package/dist/esm/lib/flag-manager.d.ts +21 -0
- package/dist/esm/lib/flag-manager.js +93 -0
- package/dist/esm/lib/yarn-converter/__tests__/round-trip.test.d.ts +1 -0
- package/dist/esm/lib/yarn-converter/__tests__/round-trip.test.js +169 -0
- package/dist/esm/lib/yarn-converter.d.ts +17 -0
- package/dist/esm/lib/yarn-converter.js +521 -0
- package/dist/esm/lib/yarn-runner/__tests__/condition-evaluator.test.d.ts +1 -0
- package/dist/esm/lib/yarn-runner/__tests__/condition-evaluator.test.js +171 -0
- package/dist/esm/lib/yarn-runner/__tests__/node-processor.test.d.ts +1 -0
- package/dist/esm/lib/yarn-runner/__tests__/node-processor.test.js +237 -0
- package/dist/esm/lib/yarn-runner/__tests__/variable-manager.test.d.ts +1 -0
- package/dist/esm/lib/yarn-runner/__tests__/variable-manager.test.js +106 -0
- package/dist/esm/lib/yarn-runner/condition-evaluator.d.ts +12 -0
- package/dist/esm/lib/yarn-runner/condition-evaluator.js +56 -0
- package/dist/esm/lib/yarn-runner/index.d.ts +12 -0
- package/dist/esm/lib/yarn-runner/index.js +11 -0
- package/dist/esm/lib/yarn-runner/node-processor.d.ts +18 -0
- package/dist/esm/lib/yarn-runner/node-processor.js +129 -0
- package/dist/esm/lib/yarn-runner/variable-manager.d.ts +51 -0
- package/dist/esm/lib/yarn-runner/variable-manager.js +120 -0
- package/dist/esm/lib/yarn-runner/variable-operations.d.ts +16 -0
- package/dist/esm/lib/yarn-runner/variable-operations.js +88 -0
- package/dist/esm/types/conditionals.d.ts +29 -0
- package/dist/esm/types/conditionals.js +1 -0
- package/dist/esm/types/constants.d.ts +59 -0
- package/dist/esm/types/constants.js +55 -0
- package/dist/esm/types/flags.d.ts +49 -0
- package/dist/esm/types/flags.js +49 -0
- package/dist/esm/types/game-state.d.ts +62 -0
- package/dist/esm/types/game-state.js +6 -0
- package/dist/esm/types/index.d.ts +77 -0
- package/dist/esm/types/index.js +1 -0
- package/dist/esm/utils/constants.d.ts +5 -0
- package/dist/esm/utils/constants.js +5 -0
- package/dist/esm/utils/feature-flags.d.ts +11 -0
- package/dist/esm/utils/feature-flags.js +11 -0
- package/dist/esm/utils/game-state-flattener.d.ts +41 -0
- package/dist/esm/utils/game-state-flattener.js +135 -0
- package/dist/esm/utils/layout/collision.d.ts +27 -0
- package/dist/esm/utils/layout/collision.js +74 -0
- package/dist/esm/utils/layout/index.d.ts +82 -0
- package/dist/esm/utils/layout/index.js +98 -0
- package/dist/esm/utils/layout/registry.d.ts +91 -0
- package/dist/esm/utils/layout/registry.js +148 -0
- package/dist/esm/utils/layout/strategies/dagre.d.ts +19 -0
- package/dist/esm/utils/layout/strategies/dagre.js +182 -0
- package/dist/esm/utils/layout/strategies/force.d.ts +21 -0
- package/dist/esm/utils/layout/strategies/force.js +178 -0
- package/dist/esm/utils/layout/strategies/grid.d.ts +17 -0
- package/dist/esm/utils/layout/strategies/grid.js +91 -0
- package/dist/esm/utils/layout/strategies/index.d.ts +8 -0
- package/dist/esm/utils/layout/strategies/index.js +8 -0
- package/dist/esm/utils/layout/types.d.ts +100 -0
- package/dist/esm/utils/layout/types.js +7 -0
- package/dist/esm/utils/layout.d.ts +9 -0
- package/dist/esm/utils/layout.js +17 -0
- package/dist/esm/utils/node-helpers.d.ts +7 -0
- package/dist/esm/utils/node-helpers.js +94 -0
- package/dist/esm/utils/reactflow-converter.d.ts +42 -0
- package/dist/esm/utils/reactflow-converter.js +217 -0
- package/dist/examples/example-loader.d.ts +29 -0
- package/dist/examples/example-loader.js +109 -0
- package/dist/examples/examples-registry.d.ts +38 -0
- package/dist/examples/examples-registry.js +160 -0
- package/dist/examples/index.d.ts +26 -0
- package/dist/examples/index.js +63 -0
- package/dist/examples/legacy-examples.d.ts +9 -0
- package/dist/examples/legacy-examples.js +817 -0
- package/dist/examples/yarn-examples.d.ts +35 -0
- package/dist/examples/yarn-examples.js +189 -0
- package/dist/index.d.ts +21 -0
- package/dist/index.js +66 -0
- package/dist/lib/flag-manager.d.ts +21 -0
- package/dist/lib/flag-manager.js +99 -0
- package/dist/lib/yarn-converter/__tests__/round-trip.test.d.ts +1 -0
- package/dist/lib/yarn-converter/__tests__/round-trip.test.js +171 -0
- package/dist/lib/yarn-converter.d.ts +17 -0
- package/dist/lib/yarn-converter.js +525 -0
- package/dist/lib/yarn-runner/__tests__/condition-evaluator.test.d.ts +1 -0
- package/dist/lib/yarn-runner/__tests__/condition-evaluator.test.js +173 -0
- package/dist/lib/yarn-runner/__tests__/node-processor.test.d.ts +1 -0
- package/dist/lib/yarn-runner/__tests__/node-processor.test.js +239 -0
- package/dist/lib/yarn-runner/__tests__/variable-manager.test.d.ts +1 -0
- package/dist/lib/yarn-runner/__tests__/variable-manager.test.js +108 -0
- package/dist/lib/yarn-runner/condition-evaluator.d.ts +12 -0
- package/dist/lib/yarn-runner/condition-evaluator.js +60 -0
- package/dist/lib/yarn-runner/index.d.ts +12 -0
- package/dist/lib/yarn-runner/index.js +21 -0
- package/dist/lib/yarn-runner/node-processor.d.ts +18 -0
- package/dist/lib/yarn-runner/node-processor.js +133 -0
- package/dist/lib/yarn-runner/variable-manager.d.ts +51 -0
- package/dist/lib/yarn-runner/variable-manager.js +124 -0
- package/dist/lib/yarn-runner/variable-operations.d.ts +16 -0
- package/dist/lib/yarn-runner/variable-operations.js +92 -0
- package/dist/types/conditionals.d.ts +29 -0
- package/dist/types/conditionals.js +2 -0
- package/dist/types/constants.d.ts +59 -0
- package/dist/types/constants.js +58 -0
- package/dist/types/flags.d.ts +49 -0
- package/dist/types/flags.js +52 -0
- package/dist/types/game-state.d.ts +62 -0
- package/dist/types/game-state.js +7 -0
- package/dist/types/index.d.ts +77 -0
- package/dist/types/index.js +2 -0
- package/dist/utils/constants.d.ts +5 -0
- package/dist/utils/constants.js +8 -0
- package/dist/utils/feature-flags.d.ts +11 -0
- package/dist/utils/feature-flags.js +14 -0
- package/dist/utils/game-state-flattener.d.ts +41 -0
- package/dist/utils/game-state-flattener.js +140 -0
- package/dist/utils/layout/collision.d.ts +27 -0
- package/dist/utils/layout/collision.js +77 -0
- package/dist/utils/layout/index.d.ts +82 -0
- package/dist/utils/layout/index.js +109 -0
- package/dist/utils/layout/registry.d.ts +91 -0
- package/dist/utils/layout/registry.js +151 -0
- package/dist/utils/layout/strategies/dagre.d.ts +19 -0
- package/dist/utils/layout/strategies/dagre.js +189 -0
- package/dist/utils/layout/strategies/force.d.ts +21 -0
- package/dist/utils/layout/strategies/force.js +182 -0
- package/dist/utils/layout/strategies/grid.d.ts +17 -0
- package/dist/utils/layout/strategies/grid.js +95 -0
- package/dist/utils/layout/strategies/index.d.ts +8 -0
- package/dist/utils/layout/strategies/index.js +14 -0
- package/dist/utils/layout/types.d.ts +100 -0
- package/dist/utils/layout/types.js +8 -0
- package/dist/utils/layout.d.ts +9 -0
- package/dist/utils/layout.js +25 -0
- package/dist/utils/node-helpers.d.ts +7 -0
- package/dist/utils/node-helpers.js +101 -0
- package/dist/utils/reactflow-converter.d.ts +42 -0
- package/dist/utils/reactflow-converter.js +223 -0
- package/package.json +70 -0
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Grid Layout Strategy
|
|
4
|
+
*
|
|
5
|
+
* Simple grid-based layout that arranges nodes in rows and columns.
|
|
6
|
+
* Useful for getting a quick overview of all nodes.
|
|
7
|
+
*/
|
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
+
exports.GridLayoutStrategy = void 0;
|
|
10
|
+
// ============================================================================
|
|
11
|
+
// Constants
|
|
12
|
+
// ============================================================================
|
|
13
|
+
const NODE_WIDTH = 220;
|
|
14
|
+
const NODE_HEIGHT = 120;
|
|
15
|
+
// ============================================================================
|
|
16
|
+
// Strategy Implementation
|
|
17
|
+
// ============================================================================
|
|
18
|
+
class GridLayoutStrategy {
|
|
19
|
+
constructor() {
|
|
20
|
+
this.id = 'grid';
|
|
21
|
+
this.name = 'Grid';
|
|
22
|
+
this.description = 'Arranges nodes in a simple grid pattern. Good for viewing all nodes at once.';
|
|
23
|
+
this.defaultOptions = {
|
|
24
|
+
nodeSpacingX: 50,
|
|
25
|
+
nodeSpacingY: 50,
|
|
26
|
+
margin: 50,
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
apply(dialogue, options) {
|
|
30
|
+
const startTime = performance.now();
|
|
31
|
+
const opts = { ...this.defaultOptions, ...options };
|
|
32
|
+
const margin = opts.margin || 50;
|
|
33
|
+
const spacingX = opts.nodeSpacingX || 50;
|
|
34
|
+
const spacingY = opts.nodeSpacingY || 50;
|
|
35
|
+
const nodeIds = Object.keys(dialogue.nodes);
|
|
36
|
+
if (nodeIds.length === 0) {
|
|
37
|
+
return this.emptyResult(dialogue, startTime);
|
|
38
|
+
}
|
|
39
|
+
// Calculate grid dimensions
|
|
40
|
+
const cols = Math.ceil(Math.sqrt(nodeIds.length));
|
|
41
|
+
const cellWidth = NODE_WIDTH + spacingX;
|
|
42
|
+
const cellHeight = NODE_HEIGHT + spacingY;
|
|
43
|
+
// Sort nodes: start node first, then by ID
|
|
44
|
+
const sortedIds = [...nodeIds].sort((a, b) => {
|
|
45
|
+
if (a === dialogue.startNodeId)
|
|
46
|
+
return -1;
|
|
47
|
+
if (b === dialogue.startNodeId)
|
|
48
|
+
return 1;
|
|
49
|
+
return a.localeCompare(b);
|
|
50
|
+
});
|
|
51
|
+
// Position nodes in grid
|
|
52
|
+
const updatedNodes = {};
|
|
53
|
+
let maxX = 0;
|
|
54
|
+
let maxY = 0;
|
|
55
|
+
sortedIds.forEach((id, index) => {
|
|
56
|
+
const col = index % cols;
|
|
57
|
+
const row = Math.floor(index / cols);
|
|
58
|
+
const x = margin + col * cellWidth;
|
|
59
|
+
const y = margin + row * cellHeight;
|
|
60
|
+
updatedNodes[id] = { ...dialogue.nodes[id], x, y };
|
|
61
|
+
maxX = Math.max(maxX, x + NODE_WIDTH);
|
|
62
|
+
maxY = Math.max(maxY, y + NODE_HEIGHT);
|
|
63
|
+
});
|
|
64
|
+
const computeTimeMs = performance.now() - startTime;
|
|
65
|
+
return {
|
|
66
|
+
dialogue: { ...dialogue, nodes: updatedNodes },
|
|
67
|
+
metadata: {
|
|
68
|
+
computeTimeMs,
|
|
69
|
+
nodeCount: nodeIds.length,
|
|
70
|
+
bounds: {
|
|
71
|
+
minX: margin,
|
|
72
|
+
minY: margin,
|
|
73
|
+
maxX,
|
|
74
|
+
maxY,
|
|
75
|
+
width: maxX - margin,
|
|
76
|
+
height: maxY - margin,
|
|
77
|
+
},
|
|
78
|
+
},
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
emptyResult(dialogue, startTime) {
|
|
82
|
+
return {
|
|
83
|
+
dialogue,
|
|
84
|
+
metadata: {
|
|
85
|
+
computeTimeMs: performance.now() - startTime,
|
|
86
|
+
nodeCount: 0,
|
|
87
|
+
bounds: { minX: 0, minY: 0, maxX: 0, maxY: 0, width: 0, height: 0 },
|
|
88
|
+
},
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
supports() {
|
|
92
|
+
return true; // Works with any graph
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
exports.GridLayoutStrategy = GridLayoutStrategy;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Layout Strategies Index
|
|
4
|
+
*
|
|
5
|
+
* Export all built-in layout strategies.
|
|
6
|
+
*/
|
|
7
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
|
+
exports.GridLayoutStrategy = exports.ForceLayoutStrategy = exports.DagreLayoutStrategy = void 0;
|
|
9
|
+
var dagre_1 = require("./dagre");
|
|
10
|
+
Object.defineProperty(exports, "DagreLayoutStrategy", { enumerable: true, get: function () { return dagre_1.DagreLayoutStrategy; } });
|
|
11
|
+
var force_1 = require("./force");
|
|
12
|
+
Object.defineProperty(exports, "ForceLayoutStrategy", { enumerable: true, get: function () { return force_1.ForceLayoutStrategy; } });
|
|
13
|
+
var grid_1 = require("./grid");
|
|
14
|
+
Object.defineProperty(exports, "GridLayoutStrategy", { enumerable: true, get: function () { return grid_1.GridLayoutStrategy; } });
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Layout Strategy Types
|
|
3
|
+
*
|
|
4
|
+
* Defines the interface and types for layout algorithms.
|
|
5
|
+
* Implements the Strategy pattern to allow swappable layout algorithms.
|
|
6
|
+
*/
|
|
7
|
+
import { DialogueTree } from '../../types';
|
|
8
|
+
/**
|
|
9
|
+
* Layout direction for hierarchical layouts
|
|
10
|
+
* - TB: Top to Bottom (vertical flow)
|
|
11
|
+
* - LR: Left to Right (horizontal flow)
|
|
12
|
+
*/
|
|
13
|
+
export type LayoutDirection = 'TB' | 'LR';
|
|
14
|
+
/**
|
|
15
|
+
* Configuration options for layout algorithms
|
|
16
|
+
*/
|
|
17
|
+
export interface LayoutOptions {
|
|
18
|
+
/** Direction of flow for hierarchical layouts */
|
|
19
|
+
direction?: LayoutDirection;
|
|
20
|
+
/** Horizontal spacing between nodes */
|
|
21
|
+
nodeSpacingX?: number;
|
|
22
|
+
/** Vertical spacing between nodes */
|
|
23
|
+
nodeSpacingY?: number;
|
|
24
|
+
/** Margin around the entire layout */
|
|
25
|
+
margin?: number;
|
|
26
|
+
/** Whether to animate the transition */
|
|
27
|
+
animate?: boolean;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Result of a layout operation
|
|
31
|
+
*/
|
|
32
|
+
export interface LayoutResult {
|
|
33
|
+
/** The dialogue tree with updated node positions */
|
|
34
|
+
dialogue: DialogueTree;
|
|
35
|
+
/** Metadata about the layout operation */
|
|
36
|
+
metadata: {
|
|
37
|
+
/** Time taken to compute layout in milliseconds */
|
|
38
|
+
computeTimeMs: number;
|
|
39
|
+
/** Number of nodes processed */
|
|
40
|
+
nodeCount: number;
|
|
41
|
+
/** Bounding box of the layout */
|
|
42
|
+
bounds: {
|
|
43
|
+
minX: number;
|
|
44
|
+
minY: number;
|
|
45
|
+
maxX: number;
|
|
46
|
+
maxY: number;
|
|
47
|
+
width: number;
|
|
48
|
+
height: number;
|
|
49
|
+
};
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Layout Strategy Interface
|
|
54
|
+
*
|
|
55
|
+
* All layout algorithms must implement this interface.
|
|
56
|
+
* This enables the Strategy pattern - algorithms can be swapped at runtime.
|
|
57
|
+
*
|
|
58
|
+
* @example
|
|
59
|
+
* ```typescript
|
|
60
|
+
* class MyCustomLayout implements LayoutStrategy {
|
|
61
|
+
* readonly id = 'my-custom';
|
|
62
|
+
* readonly name = 'My Custom Layout';
|
|
63
|
+
* readonly description = 'A custom layout algorithm';
|
|
64
|
+
*
|
|
65
|
+
* apply(dialogue: DialogueTree, options?: LayoutOptions): LayoutResult {
|
|
66
|
+
* // Your layout logic here
|
|
67
|
+
* }
|
|
68
|
+
* }
|
|
69
|
+
* ```
|
|
70
|
+
*/
|
|
71
|
+
export interface LayoutStrategy {
|
|
72
|
+
/** Unique identifier for the strategy */
|
|
73
|
+
readonly id: string;
|
|
74
|
+
/** Human-readable name */
|
|
75
|
+
readonly name: string;
|
|
76
|
+
/** Description of what this layout does */
|
|
77
|
+
readonly description: string;
|
|
78
|
+
/** Default options for this strategy */
|
|
79
|
+
readonly defaultOptions?: Partial<LayoutOptions>;
|
|
80
|
+
/**
|
|
81
|
+
* Apply the layout algorithm to a dialogue tree
|
|
82
|
+
* @param dialogue - The dialogue tree to layout
|
|
83
|
+
* @param options - Optional configuration
|
|
84
|
+
* @returns The layout result with updated positions
|
|
85
|
+
*/
|
|
86
|
+
apply(dialogue: DialogueTree, options?: LayoutOptions): LayoutResult;
|
|
87
|
+
/**
|
|
88
|
+
* Check if this strategy supports the given dialogue
|
|
89
|
+
* Some strategies may not work well with certain graph structures
|
|
90
|
+
*/
|
|
91
|
+
supports?(dialogue: DialogueTree): boolean;
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Registry entry for a layout strategy
|
|
95
|
+
*/
|
|
96
|
+
export interface LayoutStrategyEntry {
|
|
97
|
+
strategy: LayoutStrategy;
|
|
98
|
+
/** Whether this is the default strategy */
|
|
99
|
+
isDefault?: boolean;
|
|
100
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Layout Utilities - Re-export from modular layout system
|
|
3
|
+
*
|
|
4
|
+
* This file provides backward compatibility.
|
|
5
|
+
* For new code, import directly from './layout/index.ts'
|
|
6
|
+
*
|
|
7
|
+
* @see LAYOUT_STRATEGIES.md for documentation
|
|
8
|
+
*/
|
|
9
|
+
export { applyLayout, listLayouts, applyDagreLayout, applyHierarchicalLayout, resolveNodeCollisions, type LayoutStrategy, type LayoutOptions, type LayoutResult, type LayoutDirection, layoutRegistry, DagreLayoutStrategy, ForceLayoutStrategy, GridLayoutStrategy, } from './layout/index';
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Layout Utilities - Re-export from modular layout system
|
|
4
|
+
*
|
|
5
|
+
* This file provides backward compatibility.
|
|
6
|
+
* For new code, import directly from './layout/index.ts'
|
|
7
|
+
*
|
|
8
|
+
* @see LAYOUT_STRATEGIES.md for documentation
|
|
9
|
+
*/
|
|
10
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
11
|
+
exports.GridLayoutStrategy = exports.ForceLayoutStrategy = exports.DagreLayoutStrategy = exports.layoutRegistry = exports.resolveNodeCollisions = exports.applyHierarchicalLayout = exports.applyDagreLayout = exports.listLayouts = exports.applyLayout = void 0;
|
|
12
|
+
var index_1 = require("./layout/index");
|
|
13
|
+
// Main functions
|
|
14
|
+
Object.defineProperty(exports, "applyLayout", { enumerable: true, get: function () { return index_1.applyLayout; } });
|
|
15
|
+
Object.defineProperty(exports, "listLayouts", { enumerable: true, get: function () { return index_1.listLayouts; } });
|
|
16
|
+
// Backward compatibility
|
|
17
|
+
Object.defineProperty(exports, "applyDagreLayout", { enumerable: true, get: function () { return index_1.applyDagreLayout; } });
|
|
18
|
+
Object.defineProperty(exports, "applyHierarchicalLayout", { enumerable: true, get: function () { return index_1.applyHierarchicalLayout; } });
|
|
19
|
+
Object.defineProperty(exports, "resolveNodeCollisions", { enumerable: true, get: function () { return index_1.resolveNodeCollisions; } });
|
|
20
|
+
// Registry
|
|
21
|
+
Object.defineProperty(exports, "layoutRegistry", { enumerable: true, get: function () { return index_1.layoutRegistry; } });
|
|
22
|
+
// Strategies (for extension)
|
|
23
|
+
Object.defineProperty(exports, "DagreLayoutStrategy", { enumerable: true, get: function () { return index_1.DagreLayoutStrategy; } });
|
|
24
|
+
Object.defineProperty(exports, "ForceLayoutStrategy", { enumerable: true, get: function () { return index_1.ForceLayoutStrategy; } });
|
|
25
|
+
Object.defineProperty(exports, "GridLayoutStrategy", { enumerable: true, get: function () { return index_1.GridLayoutStrategy; } });
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { DialogueNode, DialogueTree, Choice } from '../types';
|
|
2
|
+
import { NodeType } from '../types/constants';
|
|
3
|
+
export declare function createNode(type: NodeType, id: string, x: number, y: number): DialogueNode;
|
|
4
|
+
export declare function addChoiceToNode(node: DialogueNode): DialogueNode;
|
|
5
|
+
export declare function removeChoiceFromNode(node: DialogueNode, choiceIdx: number): DialogueNode;
|
|
6
|
+
export declare function updateChoiceInNode(node: DialogueNode, choiceIdx: number, updates: Partial<Choice>): DialogueNode;
|
|
7
|
+
export declare function deleteNodeFromTree(tree: DialogueTree, nodeId: string): DialogueTree;
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createNode = createNode;
|
|
4
|
+
exports.addChoiceToNode = addChoiceToNode;
|
|
5
|
+
exports.removeChoiceFromNode = removeChoiceFromNode;
|
|
6
|
+
exports.updateChoiceInNode = updateChoiceInNode;
|
|
7
|
+
exports.deleteNodeFromTree = deleteNodeFromTree;
|
|
8
|
+
const constants_1 = require("../types/constants");
|
|
9
|
+
function createNode(type, id, x, y) {
|
|
10
|
+
if (type === constants_1.NODE_TYPE.NPC) {
|
|
11
|
+
return {
|
|
12
|
+
id,
|
|
13
|
+
type,
|
|
14
|
+
content: 'New dialogue...',
|
|
15
|
+
speaker: 'Character',
|
|
16
|
+
x,
|
|
17
|
+
y
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
else if (type === constants_1.NODE_TYPE.PLAYER) {
|
|
21
|
+
return {
|
|
22
|
+
id,
|
|
23
|
+
type,
|
|
24
|
+
content: '',
|
|
25
|
+
choices: [{ id: `c_${Date.now()}`, text: 'Choice 1', nextNodeId: '' }],
|
|
26
|
+
x,
|
|
27
|
+
y
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
else if (type === constants_1.NODE_TYPE.CONDITIONAL) {
|
|
31
|
+
return {
|
|
32
|
+
id,
|
|
33
|
+
type,
|
|
34
|
+
content: '',
|
|
35
|
+
conditionalBlocks: [{
|
|
36
|
+
id: `block_${Date.now()}`,
|
|
37
|
+
type: 'if',
|
|
38
|
+
condition: [],
|
|
39
|
+
content: 'New dialogue...',
|
|
40
|
+
speaker: undefined
|
|
41
|
+
}],
|
|
42
|
+
x,
|
|
43
|
+
y
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
// Fallback
|
|
47
|
+
return {
|
|
48
|
+
id,
|
|
49
|
+
type,
|
|
50
|
+
content: '',
|
|
51
|
+
x,
|
|
52
|
+
y
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
function addChoiceToNode(node) {
|
|
56
|
+
if (node.type !== constants_1.NODE_TYPE.PLAYER)
|
|
57
|
+
return node;
|
|
58
|
+
const newChoice = {
|
|
59
|
+
id: `c_${Date.now()}`,
|
|
60
|
+
text: 'New choice...',
|
|
61
|
+
nextNodeId: ''
|
|
62
|
+
};
|
|
63
|
+
return {
|
|
64
|
+
...node,
|
|
65
|
+
choices: [...(node.choices || []), newChoice]
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
function removeChoiceFromNode(node, choiceIdx) {
|
|
69
|
+
if (node.type !== constants_1.NODE_TYPE.PLAYER || !node.choices)
|
|
70
|
+
return node;
|
|
71
|
+
return {
|
|
72
|
+
...node,
|
|
73
|
+
choices: node.choices.filter((_, i) => i !== choiceIdx)
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
function updateChoiceInNode(node, choiceIdx, updates) {
|
|
77
|
+
if (node.type !== constants_1.NODE_TYPE.PLAYER || !node.choices)
|
|
78
|
+
return node;
|
|
79
|
+
const newChoices = [...node.choices];
|
|
80
|
+
newChoices[choiceIdx] = { ...newChoices[choiceIdx], ...updates };
|
|
81
|
+
return { ...node, choices: newChoices };
|
|
82
|
+
}
|
|
83
|
+
function deleteNodeFromTree(tree, nodeId) {
|
|
84
|
+
if (nodeId === tree.startNodeId) {
|
|
85
|
+
throw new Error("Cannot delete the start node");
|
|
86
|
+
}
|
|
87
|
+
const { [nodeId]: _, ...rest } = tree.nodes;
|
|
88
|
+
// Remove references to deleted node
|
|
89
|
+
Object.keys(rest).forEach(id => {
|
|
90
|
+
if (rest[id].nextNodeId === nodeId) {
|
|
91
|
+
rest[id] = { ...rest[id], nextNodeId: undefined };
|
|
92
|
+
}
|
|
93
|
+
if (rest[id].choices) {
|
|
94
|
+
rest[id] = {
|
|
95
|
+
...rest[id],
|
|
96
|
+
choices: rest[id].choices.map(c => c.nextNodeId === nodeId ? { ...c, nextNodeId: '' } : c)
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
});
|
|
100
|
+
return { ...tree, nodes: rest };
|
|
101
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* React Flow Converter Utilities
|
|
3
|
+
*
|
|
4
|
+
* Converts between DialogueTree format and React Flow format.
|
|
5
|
+
*
|
|
6
|
+
* React Flow Format:
|
|
7
|
+
* - nodes: Array of { id, type, position: {x, y}, data }
|
|
8
|
+
* - edges: Array of { id, source, target, sourceHandle?, targetHandle?, type, data? }
|
|
9
|
+
*/
|
|
10
|
+
import { DialogueTree, DialogueNode } from '../types';
|
|
11
|
+
import { Node, Edge, Position } from 'reactflow';
|
|
12
|
+
import { LayoutDirection } from './layout';
|
|
13
|
+
export declare const CHOICE_COLORS: string[];
|
|
14
|
+
export interface ReactFlowNodeData {
|
|
15
|
+
node: DialogueNode;
|
|
16
|
+
flagSchema?: any;
|
|
17
|
+
layoutDirection?: LayoutDirection;
|
|
18
|
+
}
|
|
19
|
+
export type ReactFlowNode = Node<ReactFlowNodeData>;
|
|
20
|
+
export type ReactFlowEdge = Edge;
|
|
21
|
+
/**
|
|
22
|
+
* Get handle positions based on layout direction
|
|
23
|
+
* For horizontal (LR): source on right, target on left
|
|
24
|
+
* For vertical (TB): source on bottom, target on top
|
|
25
|
+
*/
|
|
26
|
+
export declare function getHandlePositions(direction: LayoutDirection): {
|
|
27
|
+
sourcePosition: Position;
|
|
28
|
+
targetPosition: Position;
|
|
29
|
+
};
|
|
30
|
+
/**
|
|
31
|
+
* Convert DialogueTree to React Flow format
|
|
32
|
+
*/
|
|
33
|
+
export declare function convertDialogueTreeToReactFlow(dialogue: DialogueTree, layoutDirection?: LayoutDirection): {
|
|
34
|
+
nodes: ReactFlowNode[];
|
|
35
|
+
edges: ReactFlowEdge[];
|
|
36
|
+
};
|
|
37
|
+
/**
|
|
38
|
+
* Convert React Flow format back to DialogueTree
|
|
39
|
+
*
|
|
40
|
+
* This updates node positions and edge connections in the DialogueTree.
|
|
41
|
+
*/
|
|
42
|
+
export declare function updateDialogueTreeFromReactFlow(dialogue: DialogueTree, nodes: Node[], edges: Edge[]): DialogueTree;
|
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* React Flow Converter Utilities
|
|
4
|
+
*
|
|
5
|
+
* Converts between DialogueTree format and React Flow format.
|
|
6
|
+
*
|
|
7
|
+
* React Flow Format:
|
|
8
|
+
* - nodes: Array of { id, type, position: {x, y}, data }
|
|
9
|
+
* - edges: Array of { id, source, target, sourceHandle?, targetHandle?, type, data? }
|
|
10
|
+
*/
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.CHOICE_COLORS = void 0;
|
|
13
|
+
exports.getHandlePositions = getHandlePositions;
|
|
14
|
+
exports.convertDialogueTreeToReactFlow = convertDialogueTreeToReactFlow;
|
|
15
|
+
exports.updateDialogueTreeFromReactFlow = updateDialogueTreeFromReactFlow;
|
|
16
|
+
const constants_1 = require("../types/constants");
|
|
17
|
+
const reactflow_1 = require("reactflow");
|
|
18
|
+
// Color scheme for choice edges (same as current implementation)
|
|
19
|
+
exports.CHOICE_COLORS = ['#e94560', '#8b5cf6', '#06b6d4', '#22c55e', '#f59e0b'];
|
|
20
|
+
/**
|
|
21
|
+
* Get handle positions based on layout direction
|
|
22
|
+
* For horizontal (LR): source on right, target on left
|
|
23
|
+
* For vertical (TB): source on bottom, target on top
|
|
24
|
+
*/
|
|
25
|
+
function getHandlePositions(direction) {
|
|
26
|
+
if (direction === 'LR') {
|
|
27
|
+
return { sourcePosition: reactflow_1.Position.Right, targetPosition: reactflow_1.Position.Left };
|
|
28
|
+
}
|
|
29
|
+
return { sourcePosition: reactflow_1.Position.Bottom, targetPosition: reactflow_1.Position.Top };
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Convert DialogueTree to React Flow format
|
|
33
|
+
*/
|
|
34
|
+
function convertDialogueTreeToReactFlow(dialogue, layoutDirection = 'TB') {
|
|
35
|
+
const nodes = [];
|
|
36
|
+
const edges = [];
|
|
37
|
+
const { sourcePosition, targetPosition } = getHandlePositions(layoutDirection);
|
|
38
|
+
// Convert nodes - create new node objects to avoid sharing references
|
|
39
|
+
Object.values(dialogue.nodes).forEach(node => {
|
|
40
|
+
// Deep copy node to avoid sharing references, especially for arrays
|
|
41
|
+
const nodeCopy = {
|
|
42
|
+
...node,
|
|
43
|
+
choices: node.choices ? node.choices.map(choice => ({ ...choice })) : undefined,
|
|
44
|
+
setFlags: node.setFlags ? [...node.setFlags] : undefined,
|
|
45
|
+
conditionalBlocks: node.conditionalBlocks ? node.conditionalBlocks.map(block => ({
|
|
46
|
+
...block,
|
|
47
|
+
condition: block.condition ? [...block.condition] : undefined,
|
|
48
|
+
})) : undefined,
|
|
49
|
+
};
|
|
50
|
+
nodes.push({
|
|
51
|
+
id: node.id,
|
|
52
|
+
type: node.type,
|
|
53
|
+
position: { x: node.x, y: node.y },
|
|
54
|
+
data: {
|
|
55
|
+
node: nodeCopy,
|
|
56
|
+
layoutDirection,
|
|
57
|
+
},
|
|
58
|
+
sourcePosition,
|
|
59
|
+
targetPosition,
|
|
60
|
+
selected: false,
|
|
61
|
+
});
|
|
62
|
+
});
|
|
63
|
+
// Convert edges - using smoothstep type for cleaner angular look
|
|
64
|
+
Object.values(dialogue.nodes).forEach(node => {
|
|
65
|
+
if (node.type === constants_1.NODE_TYPE.NPC && node.nextNodeId) {
|
|
66
|
+
// NPC -> next node (single connection)
|
|
67
|
+
edges.push({
|
|
68
|
+
id: `${node.id}-next`,
|
|
69
|
+
source: node.id,
|
|
70
|
+
target: node.nextNodeId,
|
|
71
|
+
sourceHandle: 'next',
|
|
72
|
+
type: 'default', // Uses NPCEdgeV2 component (smoothstep style)
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
if (node.type === constants_1.NODE_TYPE.PLAYER && node.choices) {
|
|
76
|
+
// Player -> multiple choices (one edge per choice)
|
|
77
|
+
node.choices.forEach((choice, idx) => {
|
|
78
|
+
if (choice.nextNodeId) {
|
|
79
|
+
const color = exports.CHOICE_COLORS[idx % exports.CHOICE_COLORS.length];
|
|
80
|
+
edges.push({
|
|
81
|
+
id: `${node.id}-choice-${idx}`,
|
|
82
|
+
source: node.id,
|
|
83
|
+
target: choice.nextNodeId,
|
|
84
|
+
sourceHandle: `choice-${idx}`, // Connect to specific choice handle
|
|
85
|
+
type: 'choice', // Use custom ChoiceEdge (smoothstep style)
|
|
86
|
+
data: {
|
|
87
|
+
choiceIndex: idx,
|
|
88
|
+
choiceId: choice.id,
|
|
89
|
+
},
|
|
90
|
+
style: {
|
|
91
|
+
stroke: color,
|
|
92
|
+
strokeWidth: 2,
|
|
93
|
+
opacity: 0.7,
|
|
94
|
+
},
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
if (node.type === constants_1.NODE_TYPE.CONDITIONAL && node.conditionalBlocks) {
|
|
100
|
+
// Conditional -> multiple blocks (one edge per block)
|
|
101
|
+
node.conditionalBlocks.forEach((block, idx) => {
|
|
102
|
+
// Each block can have its own nextNodeId (though typically only one path is taken)
|
|
103
|
+
// For now, we'll treat it like choices - each block can connect to a node
|
|
104
|
+
if (block.nextNodeId) {
|
|
105
|
+
const color = exports.CHOICE_COLORS[idx % exports.CHOICE_COLORS.length];
|
|
106
|
+
edges.push({
|
|
107
|
+
id: `${node.id}-block-${idx}`,
|
|
108
|
+
source: node.id,
|
|
109
|
+
target: block.nextNodeId,
|
|
110
|
+
sourceHandle: `block-${idx}`, // Connect to specific block handle
|
|
111
|
+
type: 'choice', // Use same edge type as choices (smoothstep style)
|
|
112
|
+
data: {
|
|
113
|
+
choiceIndex: idx,
|
|
114
|
+
blockId: block.id,
|
|
115
|
+
},
|
|
116
|
+
style: {
|
|
117
|
+
stroke: color,
|
|
118
|
+
strokeWidth: 2,
|
|
119
|
+
opacity: 0.7,
|
|
120
|
+
},
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
});
|
|
126
|
+
return { nodes, edges };
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Convert React Flow format back to DialogueTree
|
|
130
|
+
*
|
|
131
|
+
* This updates node positions and edge connections in the DialogueTree.
|
|
132
|
+
*/
|
|
133
|
+
function updateDialogueTreeFromReactFlow(dialogue, nodes, edges) {
|
|
134
|
+
// Create a deep copy of all nodes to avoid mutations
|
|
135
|
+
const updatedNodes = {};
|
|
136
|
+
// First, create copies of all nodes with cleared connections
|
|
137
|
+
Object.values(dialogue.nodes).forEach(node => {
|
|
138
|
+
if (node.type === constants_1.NODE_TYPE.NPC) {
|
|
139
|
+
updatedNodes[node.id] = {
|
|
140
|
+
...node,
|
|
141
|
+
nextNodeId: undefined,
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
else if (node.type === constants_1.NODE_TYPE.PLAYER) {
|
|
145
|
+
updatedNodes[node.id] = {
|
|
146
|
+
...node,
|
|
147
|
+
choices: node.choices ? node.choices.map(choice => ({
|
|
148
|
+
...choice,
|
|
149
|
+
nextNodeId: '',
|
|
150
|
+
})) : [],
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
else if (node.type === constants_1.NODE_TYPE.CONDITIONAL) {
|
|
154
|
+
updatedNodes[node.id] = {
|
|
155
|
+
...node,
|
|
156
|
+
conditionalBlocks: node.conditionalBlocks ? node.conditionalBlocks.map(block => ({
|
|
157
|
+
...block,
|
|
158
|
+
nextNodeId: undefined,
|
|
159
|
+
})) : [],
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
else {
|
|
163
|
+
updatedNodes[node.id] = { ...node };
|
|
164
|
+
}
|
|
165
|
+
});
|
|
166
|
+
// Update node positions
|
|
167
|
+
nodes.forEach(rfNode => {
|
|
168
|
+
if (updatedNodes[rfNode.id]) {
|
|
169
|
+
updatedNodes[rfNode.id] = {
|
|
170
|
+
...updatedNodes[rfNode.id],
|
|
171
|
+
x: rfNode.position.x,
|
|
172
|
+
y: rfNode.position.y,
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
});
|
|
176
|
+
// Apply edge connections
|
|
177
|
+
edges.forEach(edge => {
|
|
178
|
+
const sourceNode = updatedNodes[edge.source];
|
|
179
|
+
if (!sourceNode)
|
|
180
|
+
return;
|
|
181
|
+
if (edge.sourceHandle === 'next' && sourceNode.type === constants_1.NODE_TYPE.NPC) {
|
|
182
|
+
// NPC next connection - create new node object
|
|
183
|
+
updatedNodes[edge.source] = {
|
|
184
|
+
...sourceNode,
|
|
185
|
+
nextNodeId: edge.target,
|
|
186
|
+
};
|
|
187
|
+
}
|
|
188
|
+
else if (edge.sourceHandle?.startsWith('choice-') && sourceNode.type === constants_1.NODE_TYPE.PLAYER) {
|
|
189
|
+
// Player choice connection - create new node and choice objects
|
|
190
|
+
const choiceIdx = parseInt(edge.sourceHandle.replace('choice-', ''));
|
|
191
|
+
if (sourceNode.choices && sourceNode.choices[choiceIdx]) {
|
|
192
|
+
const updatedChoices = [...sourceNode.choices];
|
|
193
|
+
updatedChoices[choiceIdx] = {
|
|
194
|
+
...updatedChoices[choiceIdx],
|
|
195
|
+
nextNodeId: edge.target,
|
|
196
|
+
};
|
|
197
|
+
updatedNodes[edge.source] = {
|
|
198
|
+
...sourceNode,
|
|
199
|
+
choices: updatedChoices,
|
|
200
|
+
};
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
else if (edge.sourceHandle?.startsWith('block-') && sourceNode.type === constants_1.NODE_TYPE.CONDITIONAL) {
|
|
204
|
+
// Conditional block connection
|
|
205
|
+
const blockIdx = parseInt(edge.sourceHandle.replace('block-', ''));
|
|
206
|
+
if (sourceNode.conditionalBlocks && sourceNode.conditionalBlocks[blockIdx]) {
|
|
207
|
+
const updatedBlocks = [...sourceNode.conditionalBlocks];
|
|
208
|
+
updatedBlocks[blockIdx] = {
|
|
209
|
+
...updatedBlocks[blockIdx],
|
|
210
|
+
nextNodeId: edge.target,
|
|
211
|
+
};
|
|
212
|
+
updatedNodes[edge.source] = {
|
|
213
|
+
...sourceNode,
|
|
214
|
+
conditionalBlocks: updatedBlocks,
|
|
215
|
+
};
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
});
|
|
219
|
+
return {
|
|
220
|
+
...dialogue,
|
|
221
|
+
nodes: updatedNodes,
|
|
222
|
+
};
|
|
223
|
+
}
|