@rohal12/spindle 0.14.0 → 0.16.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 (44) hide show
  1. package/dist/pkg/format.js +1 -1
  2. package/package.json +1 -1
  3. package/src/components/macros/Back.tsx +5 -6
  4. package/src/components/macros/Button.tsx +6 -11
  5. package/src/components/macros/Checkbox.tsx +5 -7
  6. package/src/components/macros/Computed.tsx +5 -5
  7. package/src/components/macros/Cycle.tsx +5 -9
  8. package/src/components/macros/Do.tsx +6 -8
  9. package/src/components/macros/For.tsx +10 -9
  10. package/src/components/macros/Forward.tsx +5 -6
  11. package/src/components/macros/Goto.tsx +5 -5
  12. package/src/components/macros/If.tsx +5 -5
  13. package/src/components/macros/Include.tsx +5 -7
  14. package/src/components/macros/Listbox.tsx +6 -9
  15. package/src/components/macros/MacroLink.tsx +8 -12
  16. package/src/components/macros/Meter.tsx +5 -7
  17. package/src/components/macros/Numberbox.tsx +5 -7
  18. package/src/components/macros/PassageDisplay.tsx +5 -6
  19. package/src/components/macros/Print.tsx +5 -7
  20. package/src/components/macros/QuickLoad.tsx +5 -6
  21. package/src/components/macros/QuickSave.tsx +5 -6
  22. package/src/components/macros/Radiobutton.tsx +5 -7
  23. package/src/components/macros/Repeat.tsx +6 -10
  24. package/src/components/macros/Restart.tsx +5 -6
  25. package/src/components/macros/Saves.tsx +5 -6
  26. package/src/components/macros/Set.tsx +6 -7
  27. package/src/components/macros/SettingsButton.tsx +5 -6
  28. package/src/components/macros/Stop.tsx +5 -1
  29. package/src/components/macros/StoryTitle.tsx +5 -6
  30. package/src/components/macros/Switch.tsx +7 -6
  31. package/src/components/macros/Textarea.tsx +5 -7
  32. package/src/components/macros/Textbox.tsx +5 -7
  33. package/src/components/macros/Timed.tsx +12 -14
  34. package/src/components/macros/Type.tsx +5 -9
  35. package/src/components/macros/Unset.tsx +5 -5
  36. package/src/components/macros/VarDisplay.tsx +1 -2
  37. package/src/components/macros/Widget.tsx +5 -7
  38. package/src/components/macros/WidgetInvocation.tsx +1 -1
  39. package/src/execute-mutation.ts +1 -1
  40. package/src/hooks/use-merged-locals.ts +3 -20
  41. package/src/index.tsx +1 -0
  42. package/src/macros/register-builtins.ts +35 -0
  43. package/src/markup/render.tsx +36 -404
  44. package/src/registry.ts +13 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rohal12/spindle",
3
- "version": "0.14.0",
3
+ "version": "0.16.0",
4
4
  "type": "module",
5
5
  "description": "A Preact-based story format for Twine 2.",
6
6
  "license": "Unlicense",
@@ -1,12 +1,9 @@
1
1
  import { useStoryStore } from '../../store';
2
2
  import { useAction } from '../../hooks/use-action';
3
+ import { registerMacro } from '../../registry';
4
+ import type { MacroProps } from '../../registry';
3
5
 
4
- interface BackProps {
5
- className?: string;
6
- id?: string;
7
- }
8
-
9
- export function Back({ className, id }: BackProps) {
6
+ export function Back({ className, id }: MacroProps) {
10
7
  const goBack = useStoryStore((s) => s.goBack);
11
8
  const canGoBack = useStoryStore((s) => s.historyIndex > 0);
12
9
  const cls = className ? `menubar-button ${className}` : 'menubar-button';
@@ -31,3 +28,5 @@ export function Back({ className, id }: BackProps) {
31
28
  </button>
32
29
  );
33
30
  }
31
+
32
+ registerMacro('back', Back);
@@ -2,20 +2,13 @@ import { useContext } from 'preact/hooks';
2
2
  import { renderInlineNodes, LocalsUpdateContext } from '../../markup/render';
3
3
  import { collectText } from '../../utils/extract-text';
4
4
  import { useAction } from '../../hooks/use-action';
5
- import { stripLocalsPrefix } from '../../hooks/use-merged-locals';
6
5
  import { useInterpolate } from '../../hooks/use-interpolate';
7
6
  import { executeMutation } from '../../execute-mutation';
8
7
  import { currentSourceLocation } from '../../utils/source-location';
9
- import type { ASTNode } from '../../markup/ast';
8
+ import { registerMacro } from '../../registry';
9
+ import type { MacroProps } from '../../registry';
10
10
 
11
- interface ButtonProps {
12
- rawArgs: string;
13
- children: ASTNode[];
14
- className?: string;
15
- id?: string;
16
- }
17
-
18
- export function Button({ rawArgs, children, className, id }: ButtonProps) {
11
+ export function Button({ rawArgs, children = [], className, id }: MacroProps) {
19
12
  const resolve = useInterpolate();
20
13
  className = resolve(className);
21
14
  id = resolve(id);
@@ -23,7 +16,7 @@ export function Button({ rawArgs, children, className, id }: ButtonProps) {
23
16
 
24
17
  const handleClick = () => {
25
18
  try {
26
- executeMutation(rawArgs, stripLocalsPrefix(getValues()), update);
19
+ executeMutation(rawArgs, getValues(), update);
27
20
  } catch (err) {
28
21
  console.error(
29
22
  `spindle: Error in {button ${rawArgs}}${currentSourceLocation()}:`,
@@ -52,3 +45,5 @@ export function Button({ rawArgs, children, className, id }: ButtonProps) {
52
45
  </button>
53
46
  );
54
47
  }
48
+
49
+ registerMacro('button', Button);
@@ -1,11 +1,7 @@
1
1
  import { useStoryStore } from '../../store';
2
2
  import { useAction } from '../../hooks/use-action';
3
-
4
- interface CheckboxProps {
5
- rawArgs: string;
6
- className?: string;
7
- id?: string;
8
- }
3
+ import { registerMacro } from '../../registry';
4
+ import type { MacroProps } from '../../registry';
9
5
 
10
6
  function parseArgs(rawArgs: string): { varName: string; label: string } {
11
7
  const match = rawArgs.match(/^\s*(["']?\$\w+["']?)\s+["']?(.+?)["']?\s*$/);
@@ -17,7 +13,7 @@ function parseArgs(rawArgs: string): { varName: string; label: string } {
17
13
  return { varName, label };
18
14
  }
19
15
 
20
- export function Checkbox({ rawArgs, className, id }: CheckboxProps) {
16
+ export function Checkbox({ rawArgs, className, id }: MacroProps) {
21
17
  const { varName, label } = parseArgs(rawArgs);
22
18
  const name = varName.startsWith('$') ? varName.slice(1) : varName;
23
19
 
@@ -50,3 +46,5 @@ export function Checkbox({ rawArgs, className, id }: CheckboxProps) {
50
46
  </label>
51
47
  );
52
48
  }
49
+
50
+ registerMacro('checkbox', Checkbox);
@@ -3,10 +3,8 @@ import { useStoryStore } from '../../store';
3
3
  import { evaluate } from '../../expression';
4
4
  import { useMergedLocals } from '../../hooks/use-merged-locals';
5
5
  import { currentSourceLocation } from '../../utils/source-location';
6
-
7
- interface ComputedProps {
8
- rawArgs: string;
9
- }
6
+ import { registerMacro } from '../../registry';
7
+ import type { MacroProps } from '../../registry';
10
8
 
11
9
  function parseComputedArgs(rawArgs: string): { target: string; expr: string } {
12
10
  const trimmed = rawArgs.trim();
@@ -87,7 +85,7 @@ function computeAndApply(
87
85
  }
88
86
  }
89
87
 
90
- export function Computed({ rawArgs }: ComputedProps) {
88
+ export function Computed({ rawArgs }: MacroProps) {
91
89
  const [mergedVars, mergedTemps, mergedLocals] = useMergedLocals();
92
90
 
93
91
  let target: string;
@@ -138,3 +136,5 @@ export function Computed({ rawArgs }: ComputedProps) {
138
136
 
139
137
  return null;
140
138
  }
139
+
140
+ registerMacro('computed', Computed);
@@ -1,16 +1,10 @@
1
1
  import { useStoryStore } from '../../store';
2
2
  import { extractOptions } from './option-utils';
3
3
  import { useAction } from '../../hooks/use-action';
4
- import type { ASTNode } from '../../markup/ast';
4
+ import { registerMacro } from '../../registry';
5
+ import type { MacroProps } from '../../registry';
5
6
 
6
- interface CycleProps {
7
- rawArgs: string;
8
- children: ASTNode[];
9
- className?: string;
10
- id?: string;
11
- }
12
-
13
- export function Cycle({ rawArgs, children, className, id }: CycleProps) {
7
+ export function Cycle({ rawArgs, children = [], className, id }: MacroProps) {
14
8
  const varName = rawArgs.trim().replace(/["']/g, '');
15
9
  const name = varName.startsWith('$') ? varName.slice(1) : varName;
16
10
 
@@ -55,3 +49,5 @@ export function Cycle({ rawArgs, children, className, id }: CycleProps) {
55
49
  </button>
56
50
  );
57
51
  }
52
+
53
+ registerMacro('cycle', Cycle);
@@ -1,22 +1,18 @@
1
1
  import { useLayoutEffect, useContext } from 'preact/hooks';
2
- import type { ASTNode } from '../../markup/ast';
3
2
  import { LocalsUpdateContext } from '../../markup/render';
4
- import { stripLocalsPrefix } from '../../hooks/use-merged-locals';
5
3
  import { executeMutation } from '../../execute-mutation';
6
4
  import { currentSourceLocation } from '../../utils/source-location';
7
5
  import { collectText } from '../../utils/extract-text';
6
+ import { registerMacro } from '../../registry';
7
+ import type { MacroProps } from '../../registry';
8
8
 
9
- interface DoProps {
10
- children: ASTNode[];
11
- }
12
-
13
- export function Do({ children }: DoProps) {
9
+ export function Do({ children = [] }: MacroProps) {
14
10
  const code = collectText(children);
15
11
  const { update, getValues } = useContext(LocalsUpdateContext);
16
12
 
17
13
  useLayoutEffect(() => {
18
14
  try {
19
- executeMutation(code, stripLocalsPrefix(getValues()), update);
15
+ executeMutation(code, getValues(), update);
20
16
  } catch (err) {
21
17
  console.error(`spindle: Error in {do}${currentSourceLocation()}:`, err);
22
18
  }
@@ -24,3 +20,5 @@ export function Do({ children }: DoProps) {
24
20
 
25
21
  return null;
26
22
  }
23
+
24
+ registerMacro('do', Do);
@@ -14,15 +14,10 @@ import {
14
14
  import { useMergedLocals } from '../../hooks/use-merged-locals';
15
15
  import { useInterpolate } from '../../hooks/use-interpolate';
16
16
  import { currentSourceLocation } from '../../utils/source-location';
17
+ import { registerMacro } from '../../registry';
18
+ import type { MacroProps } from '../../registry';
17
19
  import type { ASTNode } from '../../markup/ast';
18
20
 
19
- interface ForProps {
20
- rawArgs: string;
21
- children: ASTNode[];
22
- className?: string;
23
- id?: string;
24
- }
25
-
26
21
  /**
27
22
  * Parse for-loop args: "@item, @i of $list" or "@item of $list"
28
23
  */
@@ -52,7 +47,11 @@ function parseForArgs(rawArgs: string): {
52
47
  );
53
48
  }
54
49
 
55
- return { itemVar, indexVar, listExpr };
50
+ return {
51
+ itemVar: itemVar.slice(1),
52
+ indexVar: indexVar ? indexVar.slice(1) : null,
53
+ listExpr,
54
+ };
56
55
  }
57
56
 
58
57
  function ForIteration({
@@ -90,7 +89,7 @@ function ForIteration({
90
89
  );
91
90
  }
92
91
 
93
- export function For({ rawArgs, children, className, id }: ForProps) {
92
+ export function For({ rawArgs, children = [], className, id }: MacroProps) {
94
93
  const resolve = useInterpolate();
95
94
  className = resolve(className);
96
95
  id = resolve(id);
@@ -163,3 +162,5 @@ export function For({ rawArgs, children, className, id }: ForProps) {
163
162
  );
164
163
  return <>{content}</>;
165
164
  }
165
+
166
+ registerMacro('for', For);
@@ -1,12 +1,9 @@
1
1
  import { useStoryStore } from '../../store';
2
2
  import { useAction } from '../../hooks/use-action';
3
+ import { registerMacro } from '../../registry';
4
+ import type { MacroProps } from '../../registry';
3
5
 
4
- interface ForwardProps {
5
- className?: string;
6
- id?: string;
7
- }
8
-
9
- export function Forward({ className, id }: ForwardProps) {
6
+ export function Forward({ className, id }: MacroProps) {
10
7
  const goForward = useStoryStore((s) => s.goForward);
11
8
  const canGoForward = useStoryStore(
12
9
  (s) => s.historyIndex < s.history.length - 1,
@@ -33,3 +30,5 @@ export function Forward({ className, id }: ForwardProps) {
33
30
  </button>
34
31
  );
35
32
  }
33
+
34
+ registerMacro('forward', Forward);
@@ -2,12 +2,10 @@ import { useLayoutEffect } from 'preact/hooks';
2
2
  import { useStoryStore } from '../../store';
3
3
  import { evaluate } from '../../expression';
4
4
  import { useMergedLocals } from '../../hooks/use-merged-locals';
5
+ import { registerMacro } from '../../registry';
6
+ import type { MacroProps } from '../../registry';
5
7
 
6
- interface GotoProps {
7
- rawArgs: string;
8
- }
9
-
10
- export function Goto({ rawArgs }: GotoProps) {
8
+ export function Goto({ rawArgs }: MacroProps) {
11
9
  const [variables, temporary, locals] = useMergedLocals();
12
10
 
13
11
  useLayoutEffect(() => {
@@ -23,3 +21,5 @@ export function Goto({ rawArgs }: GotoProps) {
23
21
 
24
22
  return null;
25
23
  }
24
+
25
+ registerMacro('goto', Goto);
@@ -3,13 +3,11 @@ import { renderNodes } from '../../markup/render';
3
3
  import { useMergedLocals } from '../../hooks/use-merged-locals';
4
4
  import { useInterpolate } from '../../hooks/use-interpolate';
5
5
  import { currentSourceLocation } from '../../utils/source-location';
6
+ import { registerMacro } from '../../registry';
7
+ import type { MacroProps } from '../../registry';
6
8
  import type { Branch } from '../../markup/ast';
7
9
 
8
- interface IfProps {
9
- branches: Branch[];
10
- }
11
-
12
- export function If({ branches }: IfProps) {
10
+ export function If({ branches = [] }: MacroProps) {
13
11
  const resolve = useInterpolate();
14
12
  const [mergedVars, mergedTemps, mergedLocals] = useMergedLocals();
15
13
 
@@ -59,3 +57,5 @@ export function If({ branches }: IfProps) {
59
57
 
60
58
  return null;
61
59
  }
60
+
61
+ registerMacro('if', If);
@@ -6,14 +6,10 @@ import { renderNodes } from '../../markup/render';
6
6
  import { useMergedLocals } from '../../hooks/use-merged-locals';
7
7
  import { useInterpolate } from '../../hooks/use-interpolate';
8
8
  import { currentSourceLocation } from '../../utils/source-location';
9
+ import { registerMacro } from '../../registry';
10
+ import type { MacroProps } from '../../registry';
9
11
 
10
- interface IncludeProps {
11
- rawArgs: string;
12
- className?: string;
13
- id?: string;
14
- }
15
-
16
- export function Include({ rawArgs, className, id }: IncludeProps) {
12
+ export function Include({ rawArgs, className, id }: MacroProps) {
17
13
  const resolve = useInterpolate();
18
14
  className = resolve(className);
19
15
  id = resolve(id);
@@ -55,3 +51,5 @@ export function Include({ rawArgs, className, id }: IncludeProps) {
55
51
  );
56
52
  return <>{content}</>;
57
53
  }
54
+
55
+ registerMacro('include', Include);
@@ -1,16 +1,10 @@
1
1
  import { useStoryStore } from '../../store';
2
2
  import { extractOptions } from './option-utils';
3
3
  import { useAction } from '../../hooks/use-action';
4
- import type { ASTNode } from '../../markup/ast';
4
+ import { registerMacro, registerSubMacro } from '../../registry';
5
+ import type { MacroProps } from '../../registry';
5
6
 
6
- interface ListboxProps {
7
- rawArgs: string;
8
- children: ASTNode[];
9
- className?: string;
10
- id?: string;
11
- }
12
-
13
- export function Listbox({ rawArgs, children, className, id }: ListboxProps) {
7
+ export function Listbox({ rawArgs, children = [], className, id }: MacroProps) {
14
8
  const varName = rawArgs.trim().replace(/["']/g, '');
15
9
  const name = varName.startsWith('$') ? varName.slice(1) : varName;
16
10
 
@@ -52,3 +46,6 @@ export function Listbox({ rawArgs, children, className, id }: ListboxProps) {
52
46
  </select>
53
47
  );
54
48
  }
49
+
50
+ registerMacro('listbox', Listbox);
51
+ registerSubMacro('option');
@@ -2,17 +2,11 @@ import { useContext } from 'preact/hooks';
2
2
  import { useStoryStore } from '../../store';
3
3
  import type { ASTNode } from '../../markup/ast';
4
4
  import { LocalsUpdateContext } from '../../markup/render';
5
- import { stripLocalsPrefix } from '../../hooks/use-merged-locals';
6
5
  import { useInterpolate } from '../../hooks/use-interpolate';
7
6
  import { executeMutation } from '../../execute-mutation';
8
7
  import { currentSourceLocation } from '../../utils/source-location';
9
-
10
- interface MacroLinkProps {
11
- rawArgs: string;
12
- children: ASTNode[];
13
- className?: string;
14
- id?: string;
15
- }
8
+ import { registerMacro } from '../../registry';
9
+ import type { MacroProps } from '../../registry';
16
10
 
17
11
  function parseArgs(rawArgs: string): {
18
12
  display: string;
@@ -73,10 +67,10 @@ function executeChildren(
73
67
 
74
68
  export function MacroLink({
75
69
  rawArgs,
76
- children,
70
+ children = [],
77
71
  className,
78
72
  id,
79
- }: MacroLinkProps) {
73
+ }: MacroProps) {
80
74
  const resolve = useInterpolate();
81
75
  className = resolve(className);
82
76
  id = resolve(id);
@@ -85,7 +79,7 @@ export function MacroLink({
85
79
 
86
80
  const handleClick = (e: Event) => {
87
81
  e.preventDefault();
88
- executeChildren(children, stripLocalsPrefix(getValues()), update);
82
+ executeChildren(children, getValues(), update);
89
83
  if (passage) {
90
84
  useStoryStore.getState().navigate(passage);
91
85
  }
@@ -98,7 +92,7 @@ export function MacroLink({
98
92
  label: display,
99
93
  target: passage ?? undefined,
100
94
  perform: () => {
101
- executeChildren(children, stripLocalsPrefix(getValues()), update);
95
+ executeChildren(children, getValues(), update);
102
96
  if (passage) {
103
97
  useStoryStore.getState().navigate(passage);
104
98
  }
@@ -118,3 +112,5 @@ export function MacroLink({
118
112
  </a>
119
113
  );
120
114
  }
115
+
116
+ registerMacro('link', MacroLink);
@@ -1,12 +1,8 @@
1
1
  import { evaluate } from '../../expression';
2
2
  import { useMergedLocals } from '../../hooks/use-merged-locals';
3
3
  import { useInterpolate } from '../../hooks/use-interpolate';
4
-
5
- interface MeterProps {
6
- rawArgs: string;
7
- className?: string;
8
- id?: string;
9
- }
4
+ import { registerMacro } from '../../registry';
5
+ import type { MacroProps } from '../../registry';
10
6
 
11
7
  /**
12
8
  * Parse rawArgs into currentExpr, maxExpr, and optional labelMode.
@@ -83,7 +79,7 @@ function formatLabel(
83
79
  return `${current} / ${max}`;
84
80
  }
85
81
 
86
- export function Meter({ rawArgs, className, id }: MeterProps) {
82
+ export function Meter({ rawArgs, className, id }: MacroProps) {
87
83
  const resolve = useInterpolate();
88
84
  className = resolve(className);
89
85
  id = resolve(id);
@@ -126,3 +122,5 @@ export function Meter({ rawArgs, className, id }: MeterProps) {
126
122
  );
127
123
  }
128
124
  }
125
+
126
+ registerMacro('meter', Meter);
@@ -1,11 +1,7 @@
1
1
  import { useStoryStore } from '../../store';
2
2
  import { useAction } from '../../hooks/use-action';
3
-
4
- interface NumberboxProps {
5
- rawArgs: string;
6
- className?: string;
7
- id?: string;
8
- }
3
+ import { registerMacro } from '../../registry';
4
+ import type { MacroProps } from '../../registry';
9
5
 
10
6
  function parseArgs(rawArgs: string): { varName: string; placeholder: string } {
11
7
  const match = rawArgs.match(/^\s*(["']?\$\w+["']?)\s*(?:["'](.*)["'])?\s*$/);
@@ -17,7 +13,7 @@ function parseArgs(rawArgs: string): { varName: string; placeholder: string } {
17
13
  return { varName, placeholder };
18
14
  }
19
15
 
20
- export function Numberbox({ rawArgs, className, id }: NumberboxProps) {
16
+ export function Numberbox({ rawArgs, className, id }: MacroProps) {
21
17
  const { varName, placeholder } = parseArgs(rawArgs);
22
18
  const name = varName.startsWith('$') ? varName.slice(1) : varName;
23
19
 
@@ -50,3 +46,5 @@ export function Numberbox({ rawArgs, className, id }: NumberboxProps) {
50
46
  />
51
47
  );
52
48
  }
49
+
50
+ registerMacro('numberbox', Numberbox);
@@ -1,13 +1,10 @@
1
1
  import { useStoryStore } from '../../store';
2
2
  import { Passage } from '../Passage';
3
3
  import { useInterpolate } from '../../hooks/use-interpolate';
4
+ import { registerMacro } from '../../registry';
5
+ import type { MacroProps } from '../../registry';
4
6
 
5
- interface PassageDisplayProps {
6
- className?: string;
7
- id?: string;
8
- }
9
-
10
- export function PassageDisplay({ className, id }: PassageDisplayProps) {
7
+ export function PassageDisplay({ className, id }: MacroProps) {
11
8
  const resolve = useInterpolate();
12
9
  className = resolve(className);
13
10
  id = resolve(id);
@@ -35,3 +32,5 @@ export function PassageDisplay({ className, id }: PassageDisplayProps) {
35
32
  </div>
36
33
  );
37
34
  }
35
+
36
+ registerMacro('passage', PassageDisplay);
@@ -2,14 +2,10 @@ import { evaluate } from '../../expression';
2
2
  import { useMergedLocals } from '../../hooks/use-merged-locals';
3
3
  import { useInterpolate } from '../../hooks/use-interpolate';
4
4
  import { currentSourceLocation } from '../../utils/source-location';
5
+ import { registerMacro } from '../../registry';
6
+ import type { MacroProps } from '../../registry';
5
7
 
6
- interface PrintProps {
7
- rawArgs: string;
8
- className?: string;
9
- id?: string;
10
- }
11
-
12
- export function Print({ rawArgs, className, id }: PrintProps) {
8
+ export function Print({ rawArgs, className, id }: MacroProps) {
13
9
  const resolve = useInterpolate();
14
10
  className = resolve(className);
15
11
  id = resolve(id);
@@ -39,3 +35,5 @@ export function Print({ rawArgs, className, id }: PrintProps) {
39
35
  );
40
36
  }
41
37
  }
38
+
39
+ registerMacro('print', Print);
@@ -1,12 +1,9 @@
1
1
  import { useStoryStore } from '../../store';
2
2
  import { useAction } from '../../hooks/use-action';
3
+ import { registerMacro } from '../../registry';
4
+ import type { MacroProps } from '../../registry';
3
5
 
4
- interface QuickLoadProps {
5
- className?: string;
6
- id?: string;
7
- }
8
-
9
- export function QuickLoad({ className, id }: QuickLoadProps) {
6
+ export function QuickLoad({ className, id }: MacroProps) {
10
7
  const load = useStoryStore((s) => s.load);
11
8
  const hasSave = useStoryStore((s) => s.hasSave);
12
9
  // Subscribe to saveVersion so we re-render when a save is created
@@ -41,3 +38,5 @@ export function QuickLoad({ className, id }: QuickLoadProps) {
41
38
  </button>
42
39
  );
43
40
  }
41
+
42
+ registerMacro('quickload', QuickLoad);
@@ -1,12 +1,9 @@
1
1
  import { useStoryStore } from '../../store';
2
2
  import { useAction } from '../../hooks/use-action';
3
+ import { registerMacro } from '../../registry';
4
+ import type { MacroProps } from '../../registry';
3
5
 
4
- interface QuickSaveProps {
5
- className?: string;
6
- id?: string;
7
- }
8
-
9
- export function QuickSave({ className, id }: QuickSaveProps) {
6
+ export function QuickSave({ className, id }: MacroProps) {
10
7
  const save = useStoryStore((s) => s.save);
11
8
  const cls = className ? `menubar-button ${className}` : 'menubar-button';
12
9
 
@@ -29,3 +26,5 @@ export function QuickSave({ className, id }: QuickSaveProps) {
29
26
  </button>
30
27
  );
31
28
  }
29
+
30
+ registerMacro('quicksave', QuickSave);
@@ -1,11 +1,7 @@
1
1
  import { useStoryStore } from '../../store';
2
2
  import { useAction } from '../../hooks/use-action';
3
-
4
- interface RadiobuttonProps {
5
- rawArgs: string;
6
- className?: string;
7
- id?: string;
8
- }
3
+ import { registerMacro } from '../../registry';
4
+ import type { MacroProps } from '../../registry';
9
5
 
10
6
  function parseArgs(rawArgs: string): {
11
7
  varName: string;
@@ -32,7 +28,7 @@ function parseArgs(rawArgs: string): {
32
28
  };
33
29
  }
34
30
 
35
- export function Radiobutton({ rawArgs, className, id }: RadiobuttonProps) {
31
+ export function Radiobutton({ rawArgs, className, id }: MacroProps) {
36
32
  const { varName, value: radioValue, label } = parseArgs(rawArgs);
37
33
  const name = varName.startsWith('$') ? varName.slice(1) : varName;
38
34
 
@@ -68,3 +64,5 @@ export function Radiobutton({ rawArgs, className, id }: RadiobuttonProps) {
68
64
  </label>
69
65
  );
70
66
  }
67
+
68
+ registerMacro('radiobutton', Radiobutton);
@@ -4,25 +4,19 @@ import { renderNodes } from '../../markup/render';
4
4
  import { parseDelay } from '../../utils/parse-delay';
5
5
  import { hasInterpolation, interpolate } from '../../interpolation';
6
6
  import { useStoryStore } from '../../store';
7
- import type { ASTNode } from '../../markup/ast';
7
+ import { registerMacro } from '../../registry';
8
+ import type { MacroProps } from '../../registry';
8
9
 
9
10
  export const RepeatContext = createContext<{ stop: () => void }>({
10
11
  stop: () => {},
11
12
  });
12
13
 
13
- interface RepeatProps {
14
- rawArgs: string;
15
- children: ASTNode[];
16
- className?: string;
17
- id?: string;
18
- }
19
-
20
14
  export function Repeat({
21
15
  rawArgs,
22
- children,
16
+ children = [],
23
17
  className: rawClassName,
24
18
  id: rawId,
25
- }: RepeatProps) {
19
+ }: MacroProps) {
26
20
  const [className, id] = useMemo(() => {
27
21
  const resolveOnce = (s: string | undefined) => {
28
22
  if (!s || !hasInterpolation(s)) return s;
@@ -67,3 +61,5 @@ export function Repeat({
67
61
  );
68
62
  return content;
69
63
  }
64
+
65
+ registerMacro('repeat', Repeat);
@@ -1,12 +1,9 @@
1
1
  import { useStoryStore } from '../../store';
2
2
  import { useAction } from '../../hooks/use-action';
3
+ import { registerMacro } from '../../registry';
4
+ import type { MacroProps } from '../../registry';
3
5
 
4
- interface RestartProps {
5
- className?: string;
6
- id?: string;
7
- }
8
-
9
- export function Restart({ className, id }: RestartProps) {
6
+ export function Restart({ className, id }: MacroProps) {
10
7
  const restart = useStoryStore((s) => s.restart);
11
8
  const cls = className ? `menubar-button ${className}` : 'menubar-button';
12
9
 
@@ -34,3 +31,5 @@ export function Restart({ className, id }: RestartProps) {
34
31
  </button>
35
32
  );
36
33
  }
34
+
35
+ registerMacro('restart', Restart);
@@ -1,12 +1,9 @@
1
1
  import { useState } from 'preact/hooks';
2
2
  import { SaveLoadDialog } from '../SaveLoadDialog';
3
+ import { registerMacro } from '../../registry';
4
+ import type { MacroProps } from '../../registry';
3
5
 
4
- interface SavesProps {
5
- className?: string;
6
- id?: string;
7
- }
8
-
9
- export function Saves({ className, id }: SavesProps) {
6
+ export function Saves({ className, id }: MacroProps) {
10
7
  const [open, setOpen] = useState(false);
11
8
  const cls = className ? `menubar-button ${className}` : 'menubar-button';
12
9
 
@@ -23,3 +20,5 @@ export function Saves({ className, id }: SavesProps) {
23
20
  </>
24
21
  );
25
22
  }
23
+
24
+ registerMacro('saves', Saves);