yarn-spinner-runner-ts 0.1.4-b → 0.1.4-c
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/react/DialogueExample.js +4 -4
- package/dist/react/DialogueExample.js.map +1 -1
- package/dist/react/DialogueView.d.ts +2 -1
- package/dist/react/DialogueView.js +29 -17
- package/dist/react/DialogueView.js.map +1 -1
- package/dist/react/useYarnRunner.js +60 -16
- package/dist/react/useYarnRunner.js.map +1 -1
- package/dist/tests/dialogue_view.test.d.ts +1 -0
- package/dist/tests/dialogue_view.test.js +18 -0
- package/dist/tests/dialogue_view.test.js.map +1 -0
- package/package.json +1 -1
- package/src/react/DialogueExample.tsx +9 -7
- package/src/react/DialogueView.tsx +25 -11
- package/src/react/useYarnRunner.tsx +101 -46
- package/src/tests/dialogue_view.test.tsx +26 -0
|
@@ -7,8 +7,8 @@ import { parseScenes } from "../scene/parser.js";
|
|
|
7
7
|
const DEFAULT_YARN = `title: Start
|
|
8
8
|
scene: scene1
|
|
9
9
|
---
|
|
10
|
-
Narrator: {
|
|
11
|
-
Narrator:
|
|
10
|
+
Narrator: Welcome to [b]yarn-spinner-ts[/b], {$playerName}!
|
|
11
|
+
Narrator: Current street cred: {$reputation}
|
|
12
12
|
npc: This is a dialogue system powered by Yarn Spinner.
|
|
13
13
|
Narrator: Click anywhere to continue, or choose an option below.
|
|
14
14
|
-> Start the adventure &css{backgroundColor: #4a9eff; color: white;}
|
|
@@ -43,7 +43,7 @@ actors:
|
|
|
43
43
|
export function DialogueExample() {
|
|
44
44
|
const [yarnText] = useState(DEFAULT_YARN);
|
|
45
45
|
const [error, setError] = useState(null);
|
|
46
|
-
const enableTypingAnimation =
|
|
46
|
+
const enableTypingAnimation = false;
|
|
47
47
|
const scenes = useMemo(() => {
|
|
48
48
|
try {
|
|
49
49
|
return parseScenes(DEFAULT_SCENES);
|
|
@@ -81,7 +81,7 @@ export function DialogueExample() {
|
|
|
81
81
|
padding: "16px",
|
|
82
82
|
borderRadius: "8px",
|
|
83
83
|
marginBottom: "20px",
|
|
84
|
-
}, children: [_jsx("strong", { children: "Error:" }), " ", error] })), _jsx(DialogueView, { program: program || { nodes: {}, enums: {} }, startNode: "Start", scenes: scenes, enableTypingAnimation: enableTypingAnimation, showTypingCursor: true, typingSpeed: 20, cursorCharacter: "$", autoAdvanceAfterTyping: true, autoAdvanceDelay: 2000, actorTransitionDuration: 1000, pauseBeforeAdvance: enableTypingAnimation ? 1000 : 0, onStoryEnd: (info) => {
|
|
84
|
+
}, children: [_jsx("strong", { children: "Error:" }), " ", error] })), _jsx(DialogueView, { program: program || { nodes: {}, enums: {} }, startNode: "Start", scenes: scenes, variables: { playerName: "V", reputation: 3 }, enableTypingAnimation: enableTypingAnimation, showTypingCursor: true, typingSpeed: 20, cursorCharacter: "$", autoAdvanceAfterTyping: true, autoAdvanceDelay: 2000, actorTransitionDuration: 1000, pauseBeforeAdvance: enableTypingAnimation ? 1000 : 0, onStoryEnd: (info) => {
|
|
85
85
|
console.log('Story ended with variables:', info.variables);
|
|
86
86
|
}, functions: customFunctions })] }) }));
|
|
87
87
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DialogueExample.js","sourceRoot":"","sources":["../../src/react/DialogueExample.tsx"],"names":[],"mappings":";AAAA,OAAc,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,OAAO,CAAC;AACjD,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAC/C,OAAO,EAAE,OAAO,EAAE,MAAM,wBAAwB,CAAC;AACjD,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAGjD,MAAM,YAAY,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;IA0BjB,CAAC;AAEL,MAAM,cAAc,GAAG;;;;;;;;CAQtB,CAAC;AAEF,MAAM,UAAU,eAAe;IAC7B,MAAM,CAAC,QAAQ,CAAC,GAAG,QAAQ,CAAC,YAAY,CAAC,CAAC;IAC1C,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,GAAG,QAAQ,CAAgB,IAAI,CAAC,CAAC;IACxD,MAAM,qBAAqB,GAAG,
|
|
1
|
+
{"version":3,"file":"DialogueExample.js","sourceRoot":"","sources":["../../src/react/DialogueExample.tsx"],"names":[],"mappings":"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"}
|
|
@@ -7,6 +7,7 @@ export interface DialogueViewProps {
|
|
|
7
7
|
scenes?: SceneCollection;
|
|
8
8
|
actorTransitionDuration?: number;
|
|
9
9
|
functions?: Record<string, (...args: unknown[]) => unknown>;
|
|
10
|
+
variables?: Record<string, unknown>;
|
|
10
11
|
onStoryEnd?: (info: {
|
|
11
12
|
variables: Readonly<Record<string, unknown>>;
|
|
12
13
|
storyEnd: true;
|
|
@@ -19,5 +20,5 @@ export interface DialogueViewProps {
|
|
|
19
20
|
autoAdvanceDelay?: number;
|
|
20
21
|
pauseBeforeAdvance?: number;
|
|
21
22
|
}
|
|
22
|
-
export declare function DialogueView({ program, startNode, className, scenes, actorTransitionDuration, functions, onStoryEnd, enableTypingAnimation, typingSpeed, // Characters per second (50 cps = ~20ms per character)
|
|
23
|
+
export declare function DialogueView({ program, startNode, className, scenes, actorTransitionDuration, functions, variables, onStoryEnd, enableTypingAnimation, typingSpeed, // Characters per second (50 cps = ~20ms per character)
|
|
23
24
|
showTypingCursor, cursorCharacter, autoAdvanceAfterTyping, autoAdvanceDelay, pauseBeforeAdvance, }: DialogueViewProps): import("react/jsx-runtime").JSX.Element | null;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import
|
|
2
|
+
import { useRef, useEffect, useState } from "react";
|
|
3
3
|
import { DialogueScene } from "./DialogueScene.js";
|
|
4
4
|
import { TypingText } from "./TypingText.js";
|
|
5
5
|
import { useYarnRunner } from "./useYarnRunner.js";
|
|
@@ -65,13 +65,12 @@ function parseCss(cssStr) {
|
|
|
65
65
|
});
|
|
66
66
|
return styles;
|
|
67
67
|
}
|
|
68
|
-
export function DialogueView({ program, startNode = "Start", className, scenes, actorTransitionDuration = 350, functions, onStoryEnd, enableTypingAnimation = false, typingSpeed = 50, // Characters per second (50 cps = ~20ms per character)
|
|
68
|
+
export function DialogueView({ program, startNode = "Start", className, scenes, actorTransitionDuration = 350, functions, variables, onStoryEnd, enableTypingAnimation = false, typingSpeed = 50, // Characters per second (50 cps = ~20ms per character)
|
|
69
69
|
showTypingCursor = true, cursorCharacter = "|", autoAdvanceAfterTyping = false, autoAdvanceDelay = 500, pauseBeforeAdvance = 0, }) {
|
|
70
|
-
const { result, advance } = useYarnRunner(program, {
|
|
70
|
+
const { result, advance, runner } = useYarnRunner(program, {
|
|
71
71
|
startAt: startNode,
|
|
72
72
|
functions,
|
|
73
|
-
variables
|
|
74
|
-
onStoryEnd,
|
|
73
|
+
variables,
|
|
75
74
|
});
|
|
76
75
|
const sceneName = result?.type === "text" || result?.type === "options" ? result.scene : undefined;
|
|
77
76
|
const speaker = result?.type === "text" ? result.speaker : undefined;
|
|
@@ -80,6 +79,31 @@ showTypingCursor = true, cursorCharacter = "|", autoAdvanceAfterTyping = false,
|
|
|
80
79
|
const [currentTextKey, setCurrentTextKey] = useState(0);
|
|
81
80
|
const [skipTyping, setSkipTyping] = useState(false);
|
|
82
81
|
const advanceTimeoutRef = useRef(null);
|
|
82
|
+
const storyEndTriggeredRef = useRef(false);
|
|
83
|
+
useEffect(() => {
|
|
84
|
+
storyEndTriggeredRef.current = false;
|
|
85
|
+
}, [program, startNode]);
|
|
86
|
+
useEffect(() => {
|
|
87
|
+
if (!result || result.type !== "command") {
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
const timer = setTimeout(() => advance(), 50);
|
|
91
|
+
return () => clearTimeout(timer);
|
|
92
|
+
}, [result, advance]);
|
|
93
|
+
useEffect(() => {
|
|
94
|
+
if (!onStoryEnd || !result || storyEndTriggeredRef.current) {
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
if (!result.isDialogueEnd) {
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
if (result.type === "options") {
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
storyEndTriggeredRef.current = true;
|
|
104
|
+
const variablesSnapshot = Object.freeze({ ...(runner?.getVariables?.() ?? {}) });
|
|
105
|
+
onStoryEnd({ storyEnd: true, variables: variablesSnapshot });
|
|
106
|
+
}, [result, onStoryEnd, runner]);
|
|
83
107
|
// Reset typing completion when text changes
|
|
84
108
|
useEffect(() => {
|
|
85
109
|
if (result?.type === "text") {
|
|
@@ -114,13 +138,6 @@ showTypingCursor = true, cursorCharacter = "|", autoAdvanceAfterTyping = false,
|
|
|
114
138
|
const nodeStyles = parseCss(result.nodeCss);
|
|
115
139
|
const displayText = result.text || "\u00A0";
|
|
116
140
|
const shouldShowContinue = !result.isDialogueEnd && !enableTypingAnimation;
|
|
117
|
-
// Handle story end and call onStoryEnd if provided
|
|
118
|
-
if (result.isDialogueEnd && onStoryEnd && 'variables' in result) {
|
|
119
|
-
onStoryEnd({
|
|
120
|
-
variables: result.variables,
|
|
121
|
-
storyEnd: true
|
|
122
|
-
});
|
|
123
|
-
}
|
|
124
141
|
const handleClick = () => {
|
|
125
142
|
if (result.isDialogueEnd)
|
|
126
143
|
return;
|
|
@@ -159,11 +176,6 @@ showTypingCursor = true, cursorCharacter = "|", autoAdvanceAfterTyping = false,
|
|
|
159
176
|
}
|
|
160
177
|
// Command result - auto-advance
|
|
161
178
|
if (result.type === "command") {
|
|
162
|
-
// Auto-advance commands after a brief moment
|
|
163
|
-
React.useEffect(() => {
|
|
164
|
-
const timer = setTimeout(() => advance(), 50);
|
|
165
|
-
return () => clearTimeout(timer);
|
|
166
|
-
}, [result.command, advance]);
|
|
167
179
|
return (_jsx("div", { className: `yd-command ${className || ""}`, children: _jsxs("p", { children: ["Executing: ", result.command] }) }));
|
|
168
180
|
}
|
|
169
181
|
return null;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DialogueView.js","sourceRoot":"","sources":["../../src/react/DialogueView.tsx"],"names":[],"mappings":";AAAA,
|
|
1
|
+
{"version":3,"file":"DialogueView.js","sourceRoot":"","sources":["../../src/react/DialogueView.tsx"],"names":[],"mappings":"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"}
|
|
@@ -1,27 +1,71 @@
|
|
|
1
|
-
import { useState, useCallback, useRef } from "react";
|
|
1
|
+
import { useState, useCallback, useRef, useEffect } from "react";
|
|
2
2
|
import { YarnRunner } from "../runtime/runner.js";
|
|
3
|
+
function haveFunctionsChanged(prev, next) {
|
|
4
|
+
const prevFns = prev ?? {};
|
|
5
|
+
const nextFns = next ?? {};
|
|
6
|
+
const prevKeys = Object.keys(prevFns);
|
|
7
|
+
const nextKeys = Object.keys(nextFns);
|
|
8
|
+
if (prevKeys.length !== nextKeys.length) {
|
|
9
|
+
return true;
|
|
10
|
+
}
|
|
11
|
+
for (const key of prevKeys) {
|
|
12
|
+
if (!Object.prototype.hasOwnProperty.call(nextFns, key) || prevFns[key] !== nextFns[key]) {
|
|
13
|
+
return true;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
return false;
|
|
17
|
+
}
|
|
18
|
+
function haveVariablesChanged(prev, next) {
|
|
19
|
+
const prevVars = prev ?? {};
|
|
20
|
+
const nextVars = next ?? {};
|
|
21
|
+
return JSON.stringify(prevVars) !== JSON.stringify(nextVars);
|
|
22
|
+
}
|
|
3
23
|
export function useYarnRunner(program, options) {
|
|
4
24
|
const runnerRef = useRef(null);
|
|
5
|
-
const [result, setResult] = useState(null);
|
|
6
25
|
const optionsRef = useRef(options);
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
runnerRef.current =
|
|
11
|
-
setResult(runnerRef.current.currentResult);
|
|
26
|
+
const programRef = useRef(program);
|
|
27
|
+
const [result, setResult] = useState(() => {
|
|
28
|
+
const runner = new YarnRunner(program, options);
|
|
29
|
+
runnerRef.current = runner;
|
|
12
30
|
optionsRef.current = options;
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
31
|
+
programRef.current = program;
|
|
32
|
+
return runner.currentResult;
|
|
33
|
+
});
|
|
34
|
+
useEffect(() => {
|
|
35
|
+
const prevProgram = programRef.current;
|
|
36
|
+
const prevOptions = optionsRef.current;
|
|
37
|
+
const programChanged = prevProgram !== program;
|
|
38
|
+
const functionsChanged = haveFunctionsChanged(prevOptions?.functions, options.functions);
|
|
39
|
+
const startNodeChanged = prevOptions?.startAt !== options.startAt;
|
|
40
|
+
const variablesChanged = haveVariablesChanged(prevOptions?.variables, options.variables);
|
|
41
|
+
const handlersChanged = prevOptions?.handleCommand !== options.handleCommand ||
|
|
42
|
+
prevOptions?.commandHandler !== options.commandHandler ||
|
|
43
|
+
prevOptions?.onStoryEnd !== options.onStoryEnd;
|
|
44
|
+
if (!runnerRef.current ||
|
|
45
|
+
programChanged ||
|
|
46
|
+
functionsChanged ||
|
|
47
|
+
startNodeChanged ||
|
|
48
|
+
variablesChanged ||
|
|
49
|
+
handlersChanged) {
|
|
50
|
+
const runner = new YarnRunner(program, options);
|
|
51
|
+
runnerRef.current = runner;
|
|
52
|
+
setResult(runner.currentResult);
|
|
53
|
+
}
|
|
54
|
+
programRef.current = program;
|
|
18
55
|
optionsRef.current = options;
|
|
19
|
-
}
|
|
20
|
-
const runner = runnerRef.current;
|
|
56
|
+
}, [program, options]);
|
|
21
57
|
const advance = useCallback((optionIndex) => {
|
|
58
|
+
const runner = runnerRef.current;
|
|
59
|
+
if (!runner) {
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
22
62
|
runner.advance(optionIndex);
|
|
23
63
|
setResult(runner.currentResult);
|
|
24
|
-
}, [
|
|
25
|
-
return {
|
|
64
|
+
}, []);
|
|
65
|
+
return {
|
|
66
|
+
result,
|
|
67
|
+
advance,
|
|
68
|
+
runner: runnerRef.current,
|
|
69
|
+
};
|
|
26
70
|
}
|
|
27
71
|
//# sourceMappingURL=useYarnRunner.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useYarnRunner.js","sourceRoot":"","sources":["../../src/react/useYarnRunner.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"useYarnRunner.js","sourceRoot":"","sources":["../../src/react/useYarnRunner.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { test } from "node:test";
|
|
3
|
+
import { ok } from "node:assert";
|
|
4
|
+
import { renderToStaticMarkup } from "react-dom/server";
|
|
5
|
+
import { parseYarn } from "../parse/parser.js";
|
|
6
|
+
import { compile } from "../compile/compiler.js";
|
|
7
|
+
import { DialogueView } from "../react/DialogueView.js";
|
|
8
|
+
test("DialogueView renders initial variables provided via props", () => {
|
|
9
|
+
const yarn = `
|
|
10
|
+
title: Start
|
|
11
|
+
---
|
|
12
|
+
Narrator: Hello {$playerName}!
|
|
13
|
+
===`;
|
|
14
|
+
const program = compile(parseYarn(yarn));
|
|
15
|
+
const html = renderToStaticMarkup(_jsx(DialogueView, { program: program, startNode: "Start", variables: { playerName: "V" } }));
|
|
16
|
+
ok(html.includes("Hello V"), "Expected rendered dialogue to include the interpolated variable value from props");
|
|
17
|
+
});
|
|
18
|
+
//# sourceMappingURL=dialogue_view.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dialogue_view.test.js","sourceRoot":"","sources":["../../src/tests/dialogue_view.test.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,EAAE,EAAE,MAAM,aAAa,CAAC;AAEjC,OAAO,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAC;AACxD,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAC/C,OAAO,EAAE,OAAO,EAAE,MAAM,wBAAwB,CAAC;AACjD,OAAO,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAExD,IAAI,CAAC,2DAA2D,EAAE,GAAG,EAAE;IACrE,MAAM,IAAI,GAAG;;;;IAIX,CAAC;IAEH,MAAM,OAAO,GAAG,OAAO,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC;IAEzC,MAAM,IAAI,GAAG,oBAAoB,CAC/B,KAAC,YAAY,IAAC,OAAO,EAAE,OAAO,EAAE,SAAS,EAAC,OAAO,EAAC,SAAS,EAAE,EAAE,UAAU,EAAE,GAAG,EAAE,GAAI,CACrF,CAAC;IAEF,EAAE,CACA,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,EACxB,kFAAkF,CACnF,CAAC;AACJ,CAAC,CAAC,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "yarn-spinner-runner-ts",
|
|
3
|
-
"version": "0.1.4-
|
|
3
|
+
"version": "0.1.4-c",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "TypeScript parser, compiler, and runtime for Yarn Spinner 3.x with React adapter [NPM package](https://www.npmjs.com/package/yarn-spinner-runner-ts)",
|
|
6
6
|
"license": "MIT",
|
|
@@ -8,7 +8,8 @@ import type { SceneCollection } from "../scene/types.js";
|
|
|
8
8
|
const DEFAULT_YARN = `title: Start
|
|
9
9
|
scene: scene1
|
|
10
10
|
---
|
|
11
|
-
Narrator: Welcome to [b]yarn-spinner-ts[/b]!
|
|
11
|
+
Narrator: Welcome to [b]yarn-spinner-ts[/b], {$playerName}!
|
|
12
|
+
Narrator: Current street cred: {$reputation}
|
|
12
13
|
npc: This is a dialogue system powered by Yarn Spinner.
|
|
13
14
|
Narrator: Click anywhere to continue, or choose an option below.
|
|
14
15
|
-> Start the adventure &css{backgroundColor: #4a9eff; color: white;}
|
|
@@ -100,12 +101,13 @@ export function DialogueExample() {
|
|
|
100
101
|
</div>
|
|
101
102
|
)}
|
|
102
103
|
|
|
103
|
-
<DialogueView
|
|
104
|
-
program={program || { nodes: {}, enums: {} }}
|
|
105
|
-
startNode="Start"
|
|
106
|
-
scenes={scenes}
|
|
107
|
-
|
|
108
|
-
|
|
104
|
+
<DialogueView
|
|
105
|
+
program={program || { nodes: {}, enums: {} }}
|
|
106
|
+
startNode="Start"
|
|
107
|
+
scenes={scenes}
|
|
108
|
+
variables={{ playerName: "V", reputation: 3 }}
|
|
109
|
+
enableTypingAnimation={enableTypingAnimation}
|
|
110
|
+
showTypingCursor={true}
|
|
109
111
|
typingSpeed={20}
|
|
110
112
|
cursorCharacter="$"
|
|
111
113
|
autoAdvanceAfterTyping={true}
|
|
@@ -17,6 +17,7 @@ export interface DialogueViewProps {
|
|
|
17
17
|
actorTransitionDuration?: number;
|
|
18
18
|
// Custom functions and callbacks
|
|
19
19
|
functions?: Record<string, (...args: unknown[]) => unknown>;
|
|
20
|
+
variables?: Record<string, unknown>;
|
|
20
21
|
onStoryEnd?: (info: { variables: Readonly<Record<string, unknown>>; storyEnd: true }) => void;
|
|
21
22
|
// Typing animation options
|
|
22
23
|
enableTypingAnimation?: boolean;
|
|
@@ -94,6 +95,7 @@ export function DialogueView({
|
|
|
94
95
|
scenes,
|
|
95
96
|
actorTransitionDuration = 350,
|
|
96
97
|
functions,
|
|
98
|
+
variables,
|
|
97
99
|
onStoryEnd,
|
|
98
100
|
enableTypingAnimation = false,
|
|
99
101
|
typingSpeed = 50, // Characters per second (50 cps = ~20ms per character)
|
|
@@ -103,11 +105,10 @@ export function DialogueView({
|
|
|
103
105
|
autoAdvanceDelay = 500,
|
|
104
106
|
pauseBeforeAdvance = 0,
|
|
105
107
|
}: DialogueViewProps) {
|
|
106
|
-
const { result, advance } = useYarnRunner(program, {
|
|
108
|
+
const { result, advance, runner } = useYarnRunner(program, {
|
|
107
109
|
startAt: startNode,
|
|
108
110
|
functions,
|
|
109
|
-
variables
|
|
110
|
-
onStoryEnd,
|
|
111
|
+
variables,
|
|
111
112
|
});
|
|
112
113
|
const sceneName = result?.type === "text" || result?.type === "options" ? result.scene : undefined;
|
|
113
114
|
const speaker = result?.type === "text" ? result.speaker : undefined;
|
|
@@ -117,6 +118,11 @@ export function DialogueView({
|
|
|
117
118
|
const [currentTextKey, setCurrentTextKey] = useState(0);
|
|
118
119
|
const [skipTyping, setSkipTyping] = useState(false);
|
|
119
120
|
const advanceTimeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null);
|
|
121
|
+
const storyEndTriggeredRef = useRef(false);
|
|
122
|
+
|
|
123
|
+
useEffect(() => {
|
|
124
|
+
storyEndTriggeredRef.current = false;
|
|
125
|
+
}, [program, startNode]);
|
|
120
126
|
|
|
121
127
|
useEffect(() => {
|
|
122
128
|
if (!result || result.type !== "command") {
|
|
@@ -126,6 +132,22 @@ export function DialogueView({
|
|
|
126
132
|
return () => clearTimeout(timer);
|
|
127
133
|
}, [result, advance]);
|
|
128
134
|
|
|
135
|
+
useEffect(() => {
|
|
136
|
+
if (!onStoryEnd || !result || storyEndTriggeredRef.current) {
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
139
|
+
if (!result.isDialogueEnd) {
|
|
140
|
+
return;
|
|
141
|
+
}
|
|
142
|
+
if (result.type === "options") {
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
storyEndTriggeredRef.current = true;
|
|
147
|
+
const variablesSnapshot = Object.freeze({ ...(runner?.getVariables?.() ?? {}) });
|
|
148
|
+
onStoryEnd({ storyEnd: true, variables: variablesSnapshot });
|
|
149
|
+
}, [result, onStoryEnd, runner]);
|
|
150
|
+
|
|
129
151
|
// Reset typing completion when text changes
|
|
130
152
|
useEffect(() => {
|
|
131
153
|
if (result?.type === "text") {
|
|
@@ -170,14 +192,6 @@ export function DialogueView({
|
|
|
170
192
|
const displayText = result.text || "\u00A0";
|
|
171
193
|
const shouldShowContinue = !result.isDialogueEnd && !enableTypingAnimation;
|
|
172
194
|
|
|
173
|
-
// Handle story end and call onStoryEnd if provided
|
|
174
|
-
if (result.isDialogueEnd && onStoryEnd && 'variables' in result) {
|
|
175
|
-
onStoryEnd({
|
|
176
|
-
variables: result.variables as Readonly<Record<string, unknown>>,
|
|
177
|
-
storyEnd: true
|
|
178
|
-
});
|
|
179
|
-
}
|
|
180
|
-
|
|
181
195
|
const handleClick = () => {
|
|
182
196
|
if (result.isDialogueEnd) return;
|
|
183
197
|
|
|
@@ -1,47 +1,102 @@
|
|
|
1
|
-
import { useState, useCallback, useRef } from "react";
|
|
2
|
-
import { YarnRunner, type RunnerOptions } from "../runtime/runner.js";
|
|
3
|
-
import type { IRProgram } from "../compile/ir.js";
|
|
4
|
-
import type { RuntimeResult } from "../runtime/results.js";
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
): {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
const
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
);
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
1
|
+
import { useState, useCallback, useRef, useEffect } from "react";
|
|
2
|
+
import { YarnRunner, type RunnerOptions } from "../runtime/runner.js";
|
|
3
|
+
import type { IRProgram } from "../compile/ir.js";
|
|
4
|
+
import type { RuntimeResult } from "../runtime/results.js";
|
|
5
|
+
|
|
6
|
+
function haveFunctionsChanged(
|
|
7
|
+
prev: RunnerOptions["functions"],
|
|
8
|
+
next: RunnerOptions["functions"]
|
|
9
|
+
): boolean {
|
|
10
|
+
const prevFns = prev ?? {};
|
|
11
|
+
const nextFns = next ?? {};
|
|
12
|
+
|
|
13
|
+
const prevKeys = Object.keys(prevFns);
|
|
14
|
+
const nextKeys = Object.keys(nextFns);
|
|
15
|
+
|
|
16
|
+
if (prevKeys.length !== nextKeys.length) {
|
|
17
|
+
return true;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
for (const key of prevKeys) {
|
|
21
|
+
if (!Object.prototype.hasOwnProperty.call(nextFns, key) || prevFns[key] !== nextFns[key]) {
|
|
22
|
+
return true;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
return false;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function haveVariablesChanged(
|
|
30
|
+
prev: RunnerOptions["variables"],
|
|
31
|
+
next: RunnerOptions["variables"]
|
|
32
|
+
): boolean {
|
|
33
|
+
const prevVars = prev ?? {};
|
|
34
|
+
const nextVars = next ?? {};
|
|
35
|
+
return JSON.stringify(prevVars) !== JSON.stringify(nextVars);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export function useYarnRunner(
|
|
39
|
+
program: IRProgram,
|
|
40
|
+
options: RunnerOptions
|
|
41
|
+
): {
|
|
42
|
+
result: RuntimeResult | null;
|
|
43
|
+
advance: (optionIndex?: number) => void;
|
|
44
|
+
runner: YarnRunner;
|
|
45
|
+
} {
|
|
46
|
+
const runnerRef = useRef<YarnRunner | null>(null);
|
|
47
|
+
const optionsRef = useRef(options);
|
|
48
|
+
const programRef = useRef(program);
|
|
49
|
+
const [result, setResult] = useState<RuntimeResult | null>(() => {
|
|
50
|
+
const runner = new YarnRunner(program, options);
|
|
51
|
+
runnerRef.current = runner;
|
|
52
|
+
optionsRef.current = options;
|
|
53
|
+
programRef.current = program;
|
|
54
|
+
return runner.currentResult;
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
useEffect(() => {
|
|
58
|
+
const prevProgram = programRef.current;
|
|
59
|
+
const prevOptions = optionsRef.current;
|
|
60
|
+
|
|
61
|
+
const programChanged = prevProgram !== program;
|
|
62
|
+
const functionsChanged = haveFunctionsChanged(prevOptions?.functions, options.functions);
|
|
63
|
+
const startNodeChanged = prevOptions?.startAt !== options.startAt;
|
|
64
|
+
const variablesChanged = haveVariablesChanged(prevOptions?.variables, options.variables);
|
|
65
|
+
const handlersChanged =
|
|
66
|
+
prevOptions?.handleCommand !== options.handleCommand ||
|
|
67
|
+
prevOptions?.commandHandler !== options.commandHandler ||
|
|
68
|
+
prevOptions?.onStoryEnd !== options.onStoryEnd;
|
|
69
|
+
|
|
70
|
+
if (
|
|
71
|
+
!runnerRef.current ||
|
|
72
|
+
programChanged ||
|
|
73
|
+
functionsChanged ||
|
|
74
|
+
startNodeChanged ||
|
|
75
|
+
variablesChanged ||
|
|
76
|
+
handlersChanged
|
|
77
|
+
) {
|
|
78
|
+
const runner = new YarnRunner(program, options);
|
|
79
|
+
runnerRef.current = runner;
|
|
80
|
+
setResult(runner.currentResult);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
programRef.current = program;
|
|
84
|
+
optionsRef.current = options;
|
|
85
|
+
}, [program, options]);
|
|
86
|
+
|
|
87
|
+
const advance = useCallback((optionIndex?: number) => {
|
|
88
|
+
const runner = runnerRef.current;
|
|
89
|
+
if (!runner) {
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
runner.advance(optionIndex);
|
|
93
|
+
setResult(runner.currentResult);
|
|
94
|
+
}, []);
|
|
95
|
+
|
|
96
|
+
return {
|
|
97
|
+
result,
|
|
98
|
+
advance,
|
|
99
|
+
runner: runnerRef.current as YarnRunner,
|
|
100
|
+
};
|
|
101
|
+
}
|
|
47
102
|
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { test } from "node:test";
|
|
2
|
+
import { ok } from "node:assert";
|
|
3
|
+
import React from "react";
|
|
4
|
+
import { renderToStaticMarkup } from "react-dom/server";
|
|
5
|
+
import { parseYarn } from "../parse/parser.js";
|
|
6
|
+
import { compile } from "../compile/compiler.js";
|
|
7
|
+
import { DialogueView } from "../react/DialogueView.js";
|
|
8
|
+
|
|
9
|
+
test("DialogueView renders initial variables provided via props", () => {
|
|
10
|
+
const yarn = `
|
|
11
|
+
title: Start
|
|
12
|
+
---
|
|
13
|
+
Narrator: Hello {$playerName}!
|
|
14
|
+
===`;
|
|
15
|
+
|
|
16
|
+
const program = compile(parseYarn(yarn));
|
|
17
|
+
|
|
18
|
+
const html = renderToStaticMarkup(
|
|
19
|
+
<DialogueView program={program} startNode="Start" variables={{ playerName: "V" }} />
|
|
20
|
+
);
|
|
21
|
+
|
|
22
|
+
ok(
|
|
23
|
+
html.includes("Hello V"),
|
|
24
|
+
"Expected rendered dialogue to include the interpolated variable value from props"
|
|
25
|
+
);
|
|
26
|
+
});
|