@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.
Files changed (241) hide show
  1. package/README.md +233 -0
  2. package/bin/dialogue-forge.js +78 -0
  3. package/demo/app/layout.tsx +36 -0
  4. package/demo/app/page.tsx +440 -0
  5. package/demo/components/ThemeSwitcher.tsx +611 -0
  6. package/demo/next.config.mjs +7 -0
  7. package/demo/package.json +29 -0
  8. package/demo/postcss.config.mjs +7 -0
  9. package/demo/public/logo.svg +1 -0
  10. package/demo/styles/globals.css +19 -0
  11. package/demo/tailwind.config.ts +90 -0
  12. package/demo/tsconfig.json +42 -0
  13. package/dist/components/ChoiceEdgeV2.d.ts +3 -0
  14. package/dist/components/ChoiceEdgeV2.js +103 -0
  15. package/dist/components/CodeBlock.d.ts +8 -0
  16. package/dist/components/CodeBlock.js +24 -0
  17. package/dist/components/ConditionAutocomplete.d.ts +14 -0
  18. package/dist/components/ConditionAutocomplete.js +284 -0
  19. package/dist/components/ConditionalNodeV2.d.ts +16 -0
  20. package/dist/components/ConditionalNodeV2.js +147 -0
  21. package/dist/components/DialogueEditorV2.d.ts +22 -0
  22. package/dist/components/DialogueEditorV2.js +1170 -0
  23. package/dist/components/EdgeIcon.d.ts +8 -0
  24. package/dist/components/EdgeIcon.js +13 -0
  25. package/dist/components/ExampleLoader.d.ts +11 -0
  26. package/dist/components/ExampleLoader.js +52 -0
  27. package/dist/components/ExampleLoaderButton.d.ts +15 -0
  28. package/dist/components/ExampleLoaderButton.js +102 -0
  29. package/dist/components/FlagManager.d.ts +11 -0
  30. package/dist/components/FlagManager.js +282 -0
  31. package/dist/components/FlagSelector.d.ts +11 -0
  32. package/dist/components/FlagSelector.js +235 -0
  33. package/dist/components/GuidePanel.d.ts +7 -0
  34. package/dist/components/GuidePanel.js +1176 -0
  35. package/dist/components/Minimap.d.ts +16 -0
  36. package/dist/components/Minimap.js +93 -0
  37. package/dist/components/NPCEdgeV2.d.ts +3 -0
  38. package/dist/components/NPCEdgeV2.js +104 -0
  39. package/dist/components/NPCNodeV2.d.ts +26 -0
  40. package/dist/components/NPCNodeV2.js +86 -0
  41. package/dist/components/NodeEditor.d.ts +18 -0
  42. package/dist/components/NodeEditor.js +1025 -0
  43. package/dist/components/PlayView.d.ts +12 -0
  44. package/dist/components/PlayView.js +307 -0
  45. package/dist/components/PlayerNodeV2.d.ts +16 -0
  46. package/dist/components/PlayerNodeV2.js +139 -0
  47. package/dist/components/ReactFlowPOC.d.ts +61 -0
  48. package/dist/components/ReactFlowPOC.js +312 -0
  49. package/dist/components/ScenePlayer.d.ts +18 -0
  50. package/dist/components/ScenePlayer.js +196 -0
  51. package/dist/components/YarnView.d.ts +9 -0
  52. package/dist/components/YarnView.js +45 -0
  53. package/dist/components/ZoomControls.d.ts +11 -0
  54. package/dist/components/ZoomControls.js +34 -0
  55. package/dist/esm/components/ChoiceEdgeV2.d.ts +3 -0
  56. package/dist/esm/components/ChoiceEdgeV2.js +67 -0
  57. package/dist/esm/components/CodeBlock.d.ts +8 -0
  58. package/dist/esm/components/CodeBlock.js +18 -0
  59. package/dist/esm/components/ConditionAutocomplete.d.ts +14 -0
  60. package/dist/esm/components/ConditionAutocomplete.js +248 -0
  61. package/dist/esm/components/ConditionalNodeV2.d.ts +16 -0
  62. package/dist/esm/components/ConditionalNodeV2.js +111 -0
  63. package/dist/esm/components/DialogueEditorV2.d.ts +22 -0
  64. package/dist/esm/components/DialogueEditorV2.js +1134 -0
  65. package/dist/esm/components/EdgeIcon.d.ts +8 -0
  66. package/dist/esm/components/EdgeIcon.js +7 -0
  67. package/dist/esm/components/ExampleLoader.d.ts +11 -0
  68. package/dist/esm/components/ExampleLoader.js +46 -0
  69. package/dist/esm/components/ExampleLoaderButton.d.ts +15 -0
  70. package/dist/esm/components/ExampleLoaderButton.js +66 -0
  71. package/dist/esm/components/FlagManager.d.ts +11 -0
  72. package/dist/esm/components/FlagManager.js +246 -0
  73. package/dist/esm/components/FlagSelector.d.ts +11 -0
  74. package/dist/esm/components/FlagSelector.js +199 -0
  75. package/dist/esm/components/GuidePanel.d.ts +7 -0
  76. package/dist/esm/components/GuidePanel.js +1140 -0
  77. package/dist/esm/components/Minimap.d.ts +16 -0
  78. package/dist/esm/components/Minimap.js +57 -0
  79. package/dist/esm/components/NPCEdgeV2.d.ts +3 -0
  80. package/dist/esm/components/NPCEdgeV2.js +68 -0
  81. package/dist/esm/components/NPCNodeV2.d.ts +26 -0
  82. package/dist/esm/components/NPCNodeV2.js +80 -0
  83. package/dist/esm/components/NodeEditor.d.ts +18 -0
  84. package/dist/esm/components/NodeEditor.js +989 -0
  85. package/dist/esm/components/PlayView.d.ts +12 -0
  86. package/dist/esm/components/PlayView.js +271 -0
  87. package/dist/esm/components/PlayerNodeV2.d.ts +16 -0
  88. package/dist/esm/components/PlayerNodeV2.js +103 -0
  89. package/dist/esm/components/ReactFlowPOC.d.ts +61 -0
  90. package/dist/esm/components/ReactFlowPOC.js +275 -0
  91. package/dist/esm/components/ScenePlayer.d.ts +18 -0
  92. package/dist/esm/components/ScenePlayer.js +160 -0
  93. package/dist/esm/components/YarnView.d.ts +9 -0
  94. package/dist/esm/components/YarnView.js +39 -0
  95. package/dist/esm/components/ZoomControls.d.ts +11 -0
  96. package/dist/esm/components/ZoomControls.js +28 -0
  97. package/dist/esm/examples/example-loader.d.ts +29 -0
  98. package/dist/esm/examples/example-loader.js +103 -0
  99. package/dist/esm/examples/examples-registry.d.ts +38 -0
  100. package/dist/esm/examples/examples-registry.js +153 -0
  101. package/dist/esm/examples/index.d.ts +26 -0
  102. package/dist/esm/examples/index.js +50 -0
  103. package/dist/esm/examples/legacy-examples.d.ts +9 -0
  104. package/dist/esm/examples/legacy-examples.js +814 -0
  105. package/dist/esm/examples/yarn-examples.d.ts +35 -0
  106. package/dist/esm/examples/yarn-examples.js +181 -0
  107. package/dist/esm/index.d.ts +21 -0
  108. package/dist/esm/index.js +26 -0
  109. package/dist/esm/lib/flag-manager.d.ts +21 -0
  110. package/dist/esm/lib/flag-manager.js +93 -0
  111. package/dist/esm/lib/yarn-converter/__tests__/round-trip.test.d.ts +1 -0
  112. package/dist/esm/lib/yarn-converter/__tests__/round-trip.test.js +169 -0
  113. package/dist/esm/lib/yarn-converter.d.ts +17 -0
  114. package/dist/esm/lib/yarn-converter.js +521 -0
  115. package/dist/esm/lib/yarn-runner/__tests__/condition-evaluator.test.d.ts +1 -0
  116. package/dist/esm/lib/yarn-runner/__tests__/condition-evaluator.test.js +171 -0
  117. package/dist/esm/lib/yarn-runner/__tests__/node-processor.test.d.ts +1 -0
  118. package/dist/esm/lib/yarn-runner/__tests__/node-processor.test.js +237 -0
  119. package/dist/esm/lib/yarn-runner/__tests__/variable-manager.test.d.ts +1 -0
  120. package/dist/esm/lib/yarn-runner/__tests__/variable-manager.test.js +106 -0
  121. package/dist/esm/lib/yarn-runner/condition-evaluator.d.ts +12 -0
  122. package/dist/esm/lib/yarn-runner/condition-evaluator.js +56 -0
  123. package/dist/esm/lib/yarn-runner/index.d.ts +12 -0
  124. package/dist/esm/lib/yarn-runner/index.js +11 -0
  125. package/dist/esm/lib/yarn-runner/node-processor.d.ts +18 -0
  126. package/dist/esm/lib/yarn-runner/node-processor.js +129 -0
  127. package/dist/esm/lib/yarn-runner/variable-manager.d.ts +51 -0
  128. package/dist/esm/lib/yarn-runner/variable-manager.js +120 -0
  129. package/dist/esm/lib/yarn-runner/variable-operations.d.ts +16 -0
  130. package/dist/esm/lib/yarn-runner/variable-operations.js +88 -0
  131. package/dist/esm/types/conditionals.d.ts +29 -0
  132. package/dist/esm/types/conditionals.js +1 -0
  133. package/dist/esm/types/constants.d.ts +59 -0
  134. package/dist/esm/types/constants.js +55 -0
  135. package/dist/esm/types/flags.d.ts +49 -0
  136. package/dist/esm/types/flags.js +49 -0
  137. package/dist/esm/types/game-state.d.ts +62 -0
  138. package/dist/esm/types/game-state.js +6 -0
  139. package/dist/esm/types/index.d.ts +77 -0
  140. package/dist/esm/types/index.js +1 -0
  141. package/dist/esm/utils/constants.d.ts +5 -0
  142. package/dist/esm/utils/constants.js +5 -0
  143. package/dist/esm/utils/feature-flags.d.ts +11 -0
  144. package/dist/esm/utils/feature-flags.js +11 -0
  145. package/dist/esm/utils/game-state-flattener.d.ts +41 -0
  146. package/dist/esm/utils/game-state-flattener.js +135 -0
  147. package/dist/esm/utils/layout/collision.d.ts +27 -0
  148. package/dist/esm/utils/layout/collision.js +74 -0
  149. package/dist/esm/utils/layout/index.d.ts +82 -0
  150. package/dist/esm/utils/layout/index.js +98 -0
  151. package/dist/esm/utils/layout/registry.d.ts +91 -0
  152. package/dist/esm/utils/layout/registry.js +148 -0
  153. package/dist/esm/utils/layout/strategies/dagre.d.ts +19 -0
  154. package/dist/esm/utils/layout/strategies/dagre.js +182 -0
  155. package/dist/esm/utils/layout/strategies/force.d.ts +21 -0
  156. package/dist/esm/utils/layout/strategies/force.js +178 -0
  157. package/dist/esm/utils/layout/strategies/grid.d.ts +17 -0
  158. package/dist/esm/utils/layout/strategies/grid.js +91 -0
  159. package/dist/esm/utils/layout/strategies/index.d.ts +8 -0
  160. package/dist/esm/utils/layout/strategies/index.js +8 -0
  161. package/dist/esm/utils/layout/types.d.ts +100 -0
  162. package/dist/esm/utils/layout/types.js +7 -0
  163. package/dist/esm/utils/layout.d.ts +9 -0
  164. package/dist/esm/utils/layout.js +17 -0
  165. package/dist/esm/utils/node-helpers.d.ts +7 -0
  166. package/dist/esm/utils/node-helpers.js +94 -0
  167. package/dist/esm/utils/reactflow-converter.d.ts +42 -0
  168. package/dist/esm/utils/reactflow-converter.js +217 -0
  169. package/dist/examples/example-loader.d.ts +29 -0
  170. package/dist/examples/example-loader.js +109 -0
  171. package/dist/examples/examples-registry.d.ts +38 -0
  172. package/dist/examples/examples-registry.js +160 -0
  173. package/dist/examples/index.d.ts +26 -0
  174. package/dist/examples/index.js +63 -0
  175. package/dist/examples/legacy-examples.d.ts +9 -0
  176. package/dist/examples/legacy-examples.js +817 -0
  177. package/dist/examples/yarn-examples.d.ts +35 -0
  178. package/dist/examples/yarn-examples.js +189 -0
  179. package/dist/index.d.ts +21 -0
  180. package/dist/index.js +66 -0
  181. package/dist/lib/flag-manager.d.ts +21 -0
  182. package/dist/lib/flag-manager.js +99 -0
  183. package/dist/lib/yarn-converter/__tests__/round-trip.test.d.ts +1 -0
  184. package/dist/lib/yarn-converter/__tests__/round-trip.test.js +171 -0
  185. package/dist/lib/yarn-converter.d.ts +17 -0
  186. package/dist/lib/yarn-converter.js +525 -0
  187. package/dist/lib/yarn-runner/__tests__/condition-evaluator.test.d.ts +1 -0
  188. package/dist/lib/yarn-runner/__tests__/condition-evaluator.test.js +173 -0
  189. package/dist/lib/yarn-runner/__tests__/node-processor.test.d.ts +1 -0
  190. package/dist/lib/yarn-runner/__tests__/node-processor.test.js +239 -0
  191. package/dist/lib/yarn-runner/__tests__/variable-manager.test.d.ts +1 -0
  192. package/dist/lib/yarn-runner/__tests__/variable-manager.test.js +108 -0
  193. package/dist/lib/yarn-runner/condition-evaluator.d.ts +12 -0
  194. package/dist/lib/yarn-runner/condition-evaluator.js +60 -0
  195. package/dist/lib/yarn-runner/index.d.ts +12 -0
  196. package/dist/lib/yarn-runner/index.js +21 -0
  197. package/dist/lib/yarn-runner/node-processor.d.ts +18 -0
  198. package/dist/lib/yarn-runner/node-processor.js +133 -0
  199. package/dist/lib/yarn-runner/variable-manager.d.ts +51 -0
  200. package/dist/lib/yarn-runner/variable-manager.js +124 -0
  201. package/dist/lib/yarn-runner/variable-operations.d.ts +16 -0
  202. package/dist/lib/yarn-runner/variable-operations.js +92 -0
  203. package/dist/types/conditionals.d.ts +29 -0
  204. package/dist/types/conditionals.js +2 -0
  205. package/dist/types/constants.d.ts +59 -0
  206. package/dist/types/constants.js +58 -0
  207. package/dist/types/flags.d.ts +49 -0
  208. package/dist/types/flags.js +52 -0
  209. package/dist/types/game-state.d.ts +62 -0
  210. package/dist/types/game-state.js +7 -0
  211. package/dist/types/index.d.ts +77 -0
  212. package/dist/types/index.js +2 -0
  213. package/dist/utils/constants.d.ts +5 -0
  214. package/dist/utils/constants.js +8 -0
  215. package/dist/utils/feature-flags.d.ts +11 -0
  216. package/dist/utils/feature-flags.js +14 -0
  217. package/dist/utils/game-state-flattener.d.ts +41 -0
  218. package/dist/utils/game-state-flattener.js +140 -0
  219. package/dist/utils/layout/collision.d.ts +27 -0
  220. package/dist/utils/layout/collision.js +77 -0
  221. package/dist/utils/layout/index.d.ts +82 -0
  222. package/dist/utils/layout/index.js +109 -0
  223. package/dist/utils/layout/registry.d.ts +91 -0
  224. package/dist/utils/layout/registry.js +151 -0
  225. package/dist/utils/layout/strategies/dagre.d.ts +19 -0
  226. package/dist/utils/layout/strategies/dagre.js +189 -0
  227. package/dist/utils/layout/strategies/force.d.ts +21 -0
  228. package/dist/utils/layout/strategies/force.js +182 -0
  229. package/dist/utils/layout/strategies/grid.d.ts +17 -0
  230. package/dist/utils/layout/strategies/grid.js +95 -0
  231. package/dist/utils/layout/strategies/index.d.ts +8 -0
  232. package/dist/utils/layout/strategies/index.js +14 -0
  233. package/dist/utils/layout/types.d.ts +100 -0
  234. package/dist/utils/layout/types.js +8 -0
  235. package/dist/utils/layout.d.ts +9 -0
  236. package/dist/utils/layout.js +25 -0
  237. package/dist/utils/node-helpers.d.ts +7 -0
  238. package/dist/utils/node-helpers.js +101 -0
  239. package/dist/utils/reactflow-converter.d.ts +42 -0
  240. package/dist/utils/reactflow-converter.js +223 -0
  241. 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,8 @@
1
+ /**
2
+ * Layout Strategies Index
3
+ *
4
+ * Export all built-in layout strategies.
5
+ */
6
+ export { DagreLayoutStrategy } from './dagre';
7
+ export { ForceLayoutStrategy } from './force';
8
+ export { GridLayoutStrategy } from './grid';
@@ -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,8 @@
1
+ "use strict";
2
+ /**
3
+ * Layout Strategy Types
4
+ *
5
+ * Defines the interface and types for layout algorithms.
6
+ * Implements the Strategy pattern to allow swappable layout algorithms.
7
+ */
8
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -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
+ }