@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,91 @@
1
+ /**
2
+ * Grid Layout Strategy
3
+ *
4
+ * Simple grid-based layout that arranges nodes in rows and columns.
5
+ * Useful for getting a quick overview of all nodes.
6
+ */
7
+ // ============================================================================
8
+ // Constants
9
+ // ============================================================================
10
+ const NODE_WIDTH = 220;
11
+ const NODE_HEIGHT = 120;
12
+ // ============================================================================
13
+ // Strategy Implementation
14
+ // ============================================================================
15
+ export class GridLayoutStrategy {
16
+ constructor() {
17
+ this.id = 'grid';
18
+ this.name = 'Grid';
19
+ this.description = 'Arranges nodes in a simple grid pattern. Good for viewing all nodes at once.';
20
+ this.defaultOptions = {
21
+ nodeSpacingX: 50,
22
+ nodeSpacingY: 50,
23
+ margin: 50,
24
+ };
25
+ }
26
+ apply(dialogue, options) {
27
+ const startTime = performance.now();
28
+ const opts = { ...this.defaultOptions, ...options };
29
+ const margin = opts.margin || 50;
30
+ const spacingX = opts.nodeSpacingX || 50;
31
+ const spacingY = opts.nodeSpacingY || 50;
32
+ const nodeIds = Object.keys(dialogue.nodes);
33
+ if (nodeIds.length === 0) {
34
+ return this.emptyResult(dialogue, startTime);
35
+ }
36
+ // Calculate grid dimensions
37
+ const cols = Math.ceil(Math.sqrt(nodeIds.length));
38
+ const cellWidth = NODE_WIDTH + spacingX;
39
+ const cellHeight = NODE_HEIGHT + spacingY;
40
+ // Sort nodes: start node first, then by ID
41
+ const sortedIds = [...nodeIds].sort((a, b) => {
42
+ if (a === dialogue.startNodeId)
43
+ return -1;
44
+ if (b === dialogue.startNodeId)
45
+ return 1;
46
+ return a.localeCompare(b);
47
+ });
48
+ // Position nodes in grid
49
+ const updatedNodes = {};
50
+ let maxX = 0;
51
+ let maxY = 0;
52
+ sortedIds.forEach((id, index) => {
53
+ const col = index % cols;
54
+ const row = Math.floor(index / cols);
55
+ const x = margin + col * cellWidth;
56
+ const y = margin + row * cellHeight;
57
+ updatedNodes[id] = { ...dialogue.nodes[id], x, y };
58
+ maxX = Math.max(maxX, x + NODE_WIDTH);
59
+ maxY = Math.max(maxY, y + NODE_HEIGHT);
60
+ });
61
+ const computeTimeMs = performance.now() - startTime;
62
+ return {
63
+ dialogue: { ...dialogue, nodes: updatedNodes },
64
+ metadata: {
65
+ computeTimeMs,
66
+ nodeCount: nodeIds.length,
67
+ bounds: {
68
+ minX: margin,
69
+ minY: margin,
70
+ maxX,
71
+ maxY,
72
+ width: maxX - margin,
73
+ height: maxY - margin,
74
+ },
75
+ },
76
+ };
77
+ }
78
+ emptyResult(dialogue, startTime) {
79
+ return {
80
+ dialogue,
81
+ metadata: {
82
+ computeTimeMs: performance.now() - startTime,
83
+ nodeCount: 0,
84
+ bounds: { minX: 0, minY: 0, maxX: 0, maxY: 0, width: 0, height: 0 },
85
+ },
86
+ };
87
+ }
88
+ supports() {
89
+ return true; // Works with any graph
90
+ }
91
+ }
@@ -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,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,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,7 @@
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
+ export {};
@@ -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,17 @@
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 {
10
+ // Main functions
11
+ applyLayout, listLayouts,
12
+ // Backward compatibility
13
+ applyDagreLayout, applyHierarchicalLayout, resolveNodeCollisions,
14
+ // Registry
15
+ layoutRegistry,
16
+ // Strategies (for extension)
17
+ DagreLayoutStrategy, ForceLayoutStrategy, GridLayoutStrategy, } from './layout/index';
@@ -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,94 @@
1
+ import { NODE_TYPE } from '../types/constants';
2
+ export function createNode(type, id, x, y) {
3
+ if (type === NODE_TYPE.NPC) {
4
+ return {
5
+ id,
6
+ type,
7
+ content: 'New dialogue...',
8
+ speaker: 'Character',
9
+ x,
10
+ y
11
+ };
12
+ }
13
+ else if (type === NODE_TYPE.PLAYER) {
14
+ return {
15
+ id,
16
+ type,
17
+ content: '',
18
+ choices: [{ id: `c_${Date.now()}`, text: 'Choice 1', nextNodeId: '' }],
19
+ x,
20
+ y
21
+ };
22
+ }
23
+ else if (type === NODE_TYPE.CONDITIONAL) {
24
+ return {
25
+ id,
26
+ type,
27
+ content: '',
28
+ conditionalBlocks: [{
29
+ id: `block_${Date.now()}`,
30
+ type: 'if',
31
+ condition: [],
32
+ content: 'New dialogue...',
33
+ speaker: undefined
34
+ }],
35
+ x,
36
+ y
37
+ };
38
+ }
39
+ // Fallback
40
+ return {
41
+ id,
42
+ type,
43
+ content: '',
44
+ x,
45
+ y
46
+ };
47
+ }
48
+ export function addChoiceToNode(node) {
49
+ if (node.type !== NODE_TYPE.PLAYER)
50
+ return node;
51
+ const newChoice = {
52
+ id: `c_${Date.now()}`,
53
+ text: 'New choice...',
54
+ nextNodeId: ''
55
+ };
56
+ return {
57
+ ...node,
58
+ choices: [...(node.choices || []), newChoice]
59
+ };
60
+ }
61
+ export function removeChoiceFromNode(node, choiceIdx) {
62
+ if (node.type !== NODE_TYPE.PLAYER || !node.choices)
63
+ return node;
64
+ return {
65
+ ...node,
66
+ choices: node.choices.filter((_, i) => i !== choiceIdx)
67
+ };
68
+ }
69
+ export function updateChoiceInNode(node, choiceIdx, updates) {
70
+ if (node.type !== NODE_TYPE.PLAYER || !node.choices)
71
+ return node;
72
+ const newChoices = [...node.choices];
73
+ newChoices[choiceIdx] = { ...newChoices[choiceIdx], ...updates };
74
+ return { ...node, choices: newChoices };
75
+ }
76
+ export function deleteNodeFromTree(tree, nodeId) {
77
+ if (nodeId === tree.startNodeId) {
78
+ throw new Error("Cannot delete the start node");
79
+ }
80
+ const { [nodeId]: _, ...rest } = tree.nodes;
81
+ // Remove references to deleted node
82
+ Object.keys(rest).forEach(id => {
83
+ if (rest[id].nextNodeId === nodeId) {
84
+ rest[id] = { ...rest[id], nextNodeId: undefined };
85
+ }
86
+ if (rest[id].choices) {
87
+ rest[id] = {
88
+ ...rest[id],
89
+ choices: rest[id].choices.map(c => c.nextNodeId === nodeId ? { ...c, nextNodeId: '' } : c)
90
+ };
91
+ }
92
+ });
93
+ return { ...tree, nodes: rest };
94
+ }
@@ -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,217 @@
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 { NODE_TYPE } from '../types/constants';
11
+ import { Position } from 'reactflow';
12
+ // Color scheme for choice edges (same as current implementation)
13
+ export const CHOICE_COLORS = ['#e94560', '#8b5cf6', '#06b6d4', '#22c55e', '#f59e0b'];
14
+ /**
15
+ * Get handle positions based on layout direction
16
+ * For horizontal (LR): source on right, target on left
17
+ * For vertical (TB): source on bottom, target on top
18
+ */
19
+ export function getHandlePositions(direction) {
20
+ if (direction === 'LR') {
21
+ return { sourcePosition: Position.Right, targetPosition: Position.Left };
22
+ }
23
+ return { sourcePosition: Position.Bottom, targetPosition: Position.Top };
24
+ }
25
+ /**
26
+ * Convert DialogueTree to React Flow format
27
+ */
28
+ export function convertDialogueTreeToReactFlow(dialogue, layoutDirection = 'TB') {
29
+ const nodes = [];
30
+ const edges = [];
31
+ const { sourcePosition, targetPosition } = getHandlePositions(layoutDirection);
32
+ // Convert nodes - create new node objects to avoid sharing references
33
+ Object.values(dialogue.nodes).forEach(node => {
34
+ // Deep copy node to avoid sharing references, especially for arrays
35
+ const nodeCopy = {
36
+ ...node,
37
+ choices: node.choices ? node.choices.map(choice => ({ ...choice })) : undefined,
38
+ setFlags: node.setFlags ? [...node.setFlags] : undefined,
39
+ conditionalBlocks: node.conditionalBlocks ? node.conditionalBlocks.map(block => ({
40
+ ...block,
41
+ condition: block.condition ? [...block.condition] : undefined,
42
+ })) : undefined,
43
+ };
44
+ nodes.push({
45
+ id: node.id,
46
+ type: node.type,
47
+ position: { x: node.x, y: node.y },
48
+ data: {
49
+ node: nodeCopy,
50
+ layoutDirection,
51
+ },
52
+ sourcePosition,
53
+ targetPosition,
54
+ selected: false,
55
+ });
56
+ });
57
+ // Convert edges - using smoothstep type for cleaner angular look
58
+ Object.values(dialogue.nodes).forEach(node => {
59
+ if (node.type === NODE_TYPE.NPC && node.nextNodeId) {
60
+ // NPC -> next node (single connection)
61
+ edges.push({
62
+ id: `${node.id}-next`,
63
+ source: node.id,
64
+ target: node.nextNodeId,
65
+ sourceHandle: 'next',
66
+ type: 'default', // Uses NPCEdgeV2 component (smoothstep style)
67
+ });
68
+ }
69
+ if (node.type === NODE_TYPE.PLAYER && node.choices) {
70
+ // Player -> multiple choices (one edge per choice)
71
+ node.choices.forEach((choice, idx) => {
72
+ if (choice.nextNodeId) {
73
+ const color = CHOICE_COLORS[idx % CHOICE_COLORS.length];
74
+ edges.push({
75
+ id: `${node.id}-choice-${idx}`,
76
+ source: node.id,
77
+ target: choice.nextNodeId,
78
+ sourceHandle: `choice-${idx}`, // Connect to specific choice handle
79
+ type: 'choice', // Use custom ChoiceEdge (smoothstep style)
80
+ data: {
81
+ choiceIndex: idx,
82
+ choiceId: choice.id,
83
+ },
84
+ style: {
85
+ stroke: color,
86
+ strokeWidth: 2,
87
+ opacity: 0.7,
88
+ },
89
+ });
90
+ }
91
+ });
92
+ }
93
+ if (node.type === NODE_TYPE.CONDITIONAL && node.conditionalBlocks) {
94
+ // Conditional -> multiple blocks (one edge per block)
95
+ node.conditionalBlocks.forEach((block, idx) => {
96
+ // Each block can have its own nextNodeId (though typically only one path is taken)
97
+ // For now, we'll treat it like choices - each block can connect to a node
98
+ if (block.nextNodeId) {
99
+ const color = CHOICE_COLORS[idx % CHOICE_COLORS.length];
100
+ edges.push({
101
+ id: `${node.id}-block-${idx}`,
102
+ source: node.id,
103
+ target: block.nextNodeId,
104
+ sourceHandle: `block-${idx}`, // Connect to specific block handle
105
+ type: 'choice', // Use same edge type as choices (smoothstep style)
106
+ data: {
107
+ choiceIndex: idx,
108
+ blockId: block.id,
109
+ },
110
+ style: {
111
+ stroke: color,
112
+ strokeWidth: 2,
113
+ opacity: 0.7,
114
+ },
115
+ });
116
+ }
117
+ });
118
+ }
119
+ });
120
+ return { nodes, edges };
121
+ }
122
+ /**
123
+ * Convert React Flow format back to DialogueTree
124
+ *
125
+ * This updates node positions and edge connections in the DialogueTree.
126
+ */
127
+ export function updateDialogueTreeFromReactFlow(dialogue, nodes, edges) {
128
+ // Create a deep copy of all nodes to avoid mutations
129
+ const updatedNodes = {};
130
+ // First, create copies of all nodes with cleared connections
131
+ Object.values(dialogue.nodes).forEach(node => {
132
+ if (node.type === NODE_TYPE.NPC) {
133
+ updatedNodes[node.id] = {
134
+ ...node,
135
+ nextNodeId: undefined,
136
+ };
137
+ }
138
+ else if (node.type === NODE_TYPE.PLAYER) {
139
+ updatedNodes[node.id] = {
140
+ ...node,
141
+ choices: node.choices ? node.choices.map(choice => ({
142
+ ...choice,
143
+ nextNodeId: '',
144
+ })) : [],
145
+ };
146
+ }
147
+ else if (node.type === NODE_TYPE.CONDITIONAL) {
148
+ updatedNodes[node.id] = {
149
+ ...node,
150
+ conditionalBlocks: node.conditionalBlocks ? node.conditionalBlocks.map(block => ({
151
+ ...block,
152
+ nextNodeId: undefined,
153
+ })) : [],
154
+ };
155
+ }
156
+ else {
157
+ updatedNodes[node.id] = { ...node };
158
+ }
159
+ });
160
+ // Update node positions
161
+ nodes.forEach(rfNode => {
162
+ if (updatedNodes[rfNode.id]) {
163
+ updatedNodes[rfNode.id] = {
164
+ ...updatedNodes[rfNode.id],
165
+ x: rfNode.position.x,
166
+ y: rfNode.position.y,
167
+ };
168
+ }
169
+ });
170
+ // Apply edge connections
171
+ edges.forEach(edge => {
172
+ const sourceNode = updatedNodes[edge.source];
173
+ if (!sourceNode)
174
+ return;
175
+ if (edge.sourceHandle === 'next' && sourceNode.type === NODE_TYPE.NPC) {
176
+ // NPC next connection - create new node object
177
+ updatedNodes[edge.source] = {
178
+ ...sourceNode,
179
+ nextNodeId: edge.target,
180
+ };
181
+ }
182
+ else if (edge.sourceHandle?.startsWith('choice-') && sourceNode.type === NODE_TYPE.PLAYER) {
183
+ // Player choice connection - create new node and choice objects
184
+ const choiceIdx = parseInt(edge.sourceHandle.replace('choice-', ''));
185
+ if (sourceNode.choices && sourceNode.choices[choiceIdx]) {
186
+ const updatedChoices = [...sourceNode.choices];
187
+ updatedChoices[choiceIdx] = {
188
+ ...updatedChoices[choiceIdx],
189
+ nextNodeId: edge.target,
190
+ };
191
+ updatedNodes[edge.source] = {
192
+ ...sourceNode,
193
+ choices: updatedChoices,
194
+ };
195
+ }
196
+ }
197
+ else if (edge.sourceHandle?.startsWith('block-') && sourceNode.type === NODE_TYPE.CONDITIONAL) {
198
+ // Conditional block connection
199
+ const blockIdx = parseInt(edge.sourceHandle.replace('block-', ''));
200
+ if (sourceNode.conditionalBlocks && sourceNode.conditionalBlocks[blockIdx]) {
201
+ const updatedBlocks = [...sourceNode.conditionalBlocks];
202
+ updatedBlocks[blockIdx] = {
203
+ ...updatedBlocks[blockIdx],
204
+ nextNodeId: edge.target,
205
+ };
206
+ updatedNodes[edge.source] = {
207
+ ...sourceNode,
208
+ conditionalBlocks: updatedBlocks,
209
+ };
210
+ }
211
+ }
212
+ });
213
+ return {
214
+ ...dialogue,
215
+ nodes: updatedNodes,
216
+ };
217
+ }
@@ -0,0 +1,29 @@
1
+ import { DialogueTree } from '../types';
2
+ import { FlagSchema } from '../types/flags';
3
+ /**
4
+ * Load an example dialogue from a Yarn file
5
+ * This is the unified way to load examples - all examples are Yarn files
6
+ */
7
+ export declare function loadExampleDialogue(exampleId: string): Promise<DialogueTree | null>;
8
+ /**
9
+ * Get flag schema for an example
10
+ */
11
+ export declare function getFlagSchemaForExample(exampleId: string): FlagSchema | null;
12
+ /**
13
+ * Get all examples with their metadata
14
+ */
15
+ export declare function getAllExamples(): {
16
+ flagSchema: FlagSchema | null;
17
+ id: string;
18
+ title: string;
19
+ description: string;
20
+ filename: string;
21
+ flagSchemaId: string;
22
+ nodeCount?: number;
23
+ features: string[];
24
+ }[];
25
+ /**
26
+ * Synchronous version for use with pre-loaded examples
27
+ * This is used when examples are bundled/inlined
28
+ */
29
+ export declare function loadExampleDialogueSync(exampleId: string, yarnContent: string): DialogueTree | null;