@momoyu-ink/kit 0.10.0 → 0.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/lib.cjs CHANGED
@@ -34,14 +34,18 @@ __export(lib_exports, {
34
34
  Button: () => Button,
35
35
  Checkbox: () => Checkbox,
36
36
  DEBUG_EMPTY_PAGE: () => DEBUG_EMPTY_PAGE,
37
+ Input: () => Input,
37
38
  OverlayParamsContext: () => OverlayParamsContext,
38
39
  PageParamsContext: () => PageParamsContext,
40
+ Radio: () => Radio,
41
+ RadioGroup: () => RadioGroup,
39
42
  ScrollView: () => ScrollView,
40
43
  Select: () => Select,
41
44
  Slider: () => Slider,
42
45
  StageContextProvider: () => StageContextProvider,
43
46
  a: () => animated,
44
47
  addEventListener: () => addEventListener,
48
+ addFluidObserver: () => addFluidObserver,
45
49
  animated: () => animated,
46
50
  autoState: () => autoState,
47
51
  createBubbleEvent: () => createBubbleEvent,
@@ -68,6 +72,7 @@ __export(lib_exports, {
68
72
  moyu: () => moyu_exports,
69
73
  nextLine: () => nextLine,
70
74
  registerAppStateAdapter: () => registerAppStateAdapter,
75
+ removeFluidObserver: () => removeFluidObserver,
71
76
  replaceUiData: () => replaceUiData,
72
77
  setDefaultAutoTailMs: () => setDefaultAutoTailMs,
73
78
  setWaiting: () => setWaiting,
@@ -110,10 +115,12 @@ var import_constants = require("react-reconciler/constants.js");
110
115
  var moyu_exports = {};
111
116
  __export(moyu_exports, {
112
117
  addChild: () => addChild,
118
+ blurEditable: () => blurEditable,
113
119
  createInstance: () => createInstance,
114
120
  destroyInstance: () => destroyInstance,
115
121
  executeNodeCommand: () => executeNodeCommand,
116
122
  executePluginCommand: () => executePluginCommand,
123
+ focusEditable: () => focusEditable,
117
124
  insertChild: () => insertChild,
118
125
  insertChildBefore: () => insertChildBefore,
119
126
  removeChild: () => removeChild,
@@ -151,6 +158,12 @@ function removeChild(nodeId, childNodeId) {
151
158
  function updateProps(nodeId, props) {
152
159
  moyu.pushCommand("update_props", [nodeId, props]);
153
160
  }
161
+ function focusEditable(nodeId) {
162
+ moyu.pushCommand("focus_editable", [nodeId]);
163
+ }
164
+ function blurEditable(nodeId) {
165
+ moyu.pushCommand("blur_editable", [nodeId]);
166
+ }
154
167
  function executeNodeCommand(nodeId, payload) {
155
168
  return moyu.executeNodeCommand(nodeId, payload);
156
169
  }
@@ -794,7 +807,9 @@ globalThis.__moyu_eval_sandbox = (code) => {
794
807
  var spring_exports = {};
795
808
  __export(spring_exports, {
796
809
  a: () => animated,
797
- animated: () => animated
810
+ addFluidObserver: () => addFluidObserver,
811
+ animated: () => animated,
812
+ removeFluidObserver: () => removeFluidObserver
798
813
  });
799
814
  var import_animated = require("@react-spring/animated");
800
815
  var import_shared = require("@react-spring/shared");
@@ -827,6 +842,8 @@ var host = (0, import_animated.createHost)(primitives, {
827
842
  }
828
843
  });
829
844
  var animated = host.animated;
845
+ var addFluidObserver = import_shared.addFluidObserver;
846
+ var removeFluidObserver = import_shared.removeFluidObserver;
830
847
 
831
848
  // src/lib.ts
832
849
  __reExport(lib_exports, spring_exports, module.exports);
@@ -851,7 +868,8 @@ function createBubbleEvent(body, targetId) {
851
868
 
852
869
  // src/events/globals.ts
853
870
  var globalEventListeners = {};
854
- var globalRequestAnimationFrameListeners = [];
871
+ var globalRequestAnimationFrameListeners = /* @__PURE__ */ new Map();
872
+ var nextAnimationFrameHandle = 0;
855
873
  var BUBBLE_EVENT_NAMES = ["mouseevent", "touchevent", "keyboardevent", "wheelevent"];
856
874
  globalThis.__moyu_receive_event = (raw_event) => {
857
875
  const { name, body } = raw_event;
@@ -878,7 +896,8 @@ globalThis.__moyu_receive_event = (raw_event) => {
878
896
  return;
879
897
  }
880
898
  case "animationframecallbackevent": {
881
- const listeners = globalRequestAnimationFrameListeners.splice(0);
899
+ const listeners = [...globalRequestAnimationFrameListeners.values()];
900
+ globalRequestAnimationFrameListeners.clear();
882
901
  const { timestamp } = body;
883
902
  for (const listener of listeners) {
884
903
  listener?.(timestamp);
@@ -936,10 +955,13 @@ function handleBubbleEvent(name, body) {
936
955
  }
937
956
  if (globalThis.__moyu_native) {
938
957
  globalThis.requestAnimationFrame = (callback) => {
939
- return globalRequestAnimationFrameListeners.push(callback) - 1;
958
+ const handle = nextAnimationFrameHandle;
959
+ nextAnimationFrameHandle += 1;
960
+ globalRequestAnimationFrameListeners.set(handle, callback);
961
+ return handle;
940
962
  };
941
963
  globalThis.cancelAnimationFrame = (handle) => {
942
- globalRequestAnimationFrameListeners.splice(handle, 1);
964
+ globalRequestAnimationFrameListeners.delete(handle);
943
965
  };
944
966
  }
945
967
 
@@ -1260,6 +1282,7 @@ function Button({
1260
1282
  textOffsetX,
1261
1283
  textOffsetY,
1262
1284
  textAlign = "center",
1285
+ children,
1263
1286
  anchor,
1264
1287
  pivot = anchor,
1265
1288
  interactive,
@@ -1274,6 +1297,20 @@ function Button({
1274
1297
  }) {
1275
1298
  const [hovered, setHovered] = (0, import_react4.useState)(false);
1276
1299
  const [pressed, setPressed] = (0, import_react4.useState)(false);
1300
+ (0, import_react4.useEffect)(() => {
1301
+ if (!pressed) {
1302
+ return;
1303
+ }
1304
+ const release = () => setPressed(false);
1305
+ const removeMouseUp = addEventListener("mouseup", release);
1306
+ const removeTouchEnd = addEventListener("touchend", release);
1307
+ const removeTouchCancel = addEventListener("touchcancel", release);
1308
+ return () => {
1309
+ removeMouseUp();
1310
+ removeTouchEnd();
1311
+ removeTouchCancel();
1312
+ };
1313
+ }, [pressed]);
1277
1314
  (0, import_react4.useEffect)(() => {
1278
1315
  if (disabled) {
1279
1316
  setHovered(false);
@@ -1323,18 +1360,21 @@ function Button({
1323
1360
  setPressed(false);
1324
1361
  }),
1325
1362
  onClick: (event) => event.stopPropagation(),
1326
- children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("sprite", { ...spriteProps, src: resolveControlStateValue(src, state), cursor: "pointer", children: text !== void 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1327
- "text",
1328
- {
1329
- ...resolvedTextStyle,
1330
- text,
1331
- x: textOffsetX,
1332
- y: textOffsetY,
1333
- interactive: false,
1334
- anchor: textAnchor,
1335
- pivot: textAnchor
1336
- }
1337
- ) : void 0 })
1363
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("sprite", { ...spriteProps, src: resolveControlStateValue(src, state), cursor: "pointer", children: [
1364
+ text !== void 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1365
+ "text",
1366
+ {
1367
+ ...resolvedTextStyle,
1368
+ text,
1369
+ x: textOffsetX,
1370
+ y: textOffsetY,
1371
+ interactive: false,
1372
+ anchor: textAnchor,
1373
+ pivot: textAnchor
1374
+ }
1375
+ ) : void 0,
1376
+ children
1377
+ ] })
1338
1378
  }
1339
1379
  );
1340
1380
  }
@@ -1372,8 +1412,343 @@ function Checkbox({
1372
1412
  );
1373
1413
  }
1374
1414
 
1375
- // src/components/select.tsx
1415
+ // src/components/input.tsx
1376
1416
  var import_react6 = require("react");
1417
+ var Input = (0, import_react6.forwardRef)(function Input2({
1418
+ value,
1419
+ defaultValue = "",
1420
+ placeholder = "",
1421
+ disabled = false,
1422
+ readOnly = false,
1423
+ autoFocus = false,
1424
+ width,
1425
+ height,
1426
+ paddingX = 0,
1427
+ textStyle,
1428
+ placeholderStyle,
1429
+ caret,
1430
+ background,
1431
+ onInput,
1432
+ onChange,
1433
+ onFocus,
1434
+ onBlur,
1435
+ onCompositionStart,
1436
+ onCompositionUpdate,
1437
+ onCompositionEnd,
1438
+ interactive,
1439
+ cursor = "text",
1440
+ onMouseEnter,
1441
+ onMouseLeave,
1442
+ onMouseDown,
1443
+ onMouseUp,
1444
+ onTouchStart,
1445
+ onTouchEnd,
1446
+ onTouchCancel,
1447
+ ...nodeProps
1448
+ }, ref) {
1449
+ const editableRef = (0, import_react6.useRef)(null);
1450
+ const initialValueRef = (0, import_react6.useRef)(value ?? defaultValue);
1451
+ const initialValue = initialValueRef.current;
1452
+ const stateRef = (0, import_react6.useRef)({
1453
+ value: initialValue,
1454
+ isComposing: false,
1455
+ compositionText: ""
1456
+ });
1457
+ const [state, setState] = (0, import_react6.useState)(stateRef.current);
1458
+ const [focused, setFocused] = (0, import_react6.useState)(false);
1459
+ const [hovered, setHovered] = (0, import_react6.useState)(false);
1460
+ const [pressed, setPressed] = (0, import_react6.useState)(false);
1461
+ const [caretPosition, setCaretPosition] = (0, import_react6.useState)();
1462
+ const [caretVisible, setCaretVisible] = (0, import_react6.useState)(true);
1463
+ const shouldAutoFocusRef = (0, import_react6.useRef)(autoFocus && !disabled);
1464
+ const viewportWidth = Math.max(0, Math.round(width));
1465
+ const viewportHeight = Math.max(0, Math.round(height));
1466
+ const contentWidth = Math.max(0, viewportWidth - paddingX * 2);
1467
+ const { width: caretWidth, height: configuredCaretHeight, blinkInterval, ...caretSpriteProps } = caret;
1468
+ const caretHeight = configuredCaretHeight ?? textStyle.fontSize ?? viewportHeight;
1469
+ const backgroundStyle = background && "idle" in background ? disabled ? background.disabled ?? background.idle : readOnly ? background.readOnly ?? background.idle : pressed ? background.press ?? background.idle : focused ? background.focused ?? background.idle : hovered ? background.hover ?? background.idle : background.idle : background;
1470
+ const displayValue = state.value + state.compositionText;
1471
+ const updateState = (0, import_react6.useCallback)((nextState) => {
1472
+ const previousState = stateRef.current;
1473
+ if (previousState.value === nextState.value && previousState.isComposing === nextState.isComposing && previousState.compositionText === nextState.compositionText) {
1474
+ return;
1475
+ }
1476
+ const displayValueChanged = previousState.value + previousState.compositionText !== nextState.value + nextState.compositionText;
1477
+ stateRef.current = nextState;
1478
+ setState(nextState);
1479
+ if (displayValueChanged) {
1480
+ setCaretPosition(void 0);
1481
+ }
1482
+ setCaretVisible(true);
1483
+ }, []);
1484
+ const handleInput = (0, import_react6.useCallback)(
1485
+ (event) => {
1486
+ updateState(event.state);
1487
+ onInput?.(event.state);
1488
+ },
1489
+ [onInput, updateState]
1490
+ );
1491
+ const handleChange = (0, import_react6.useCallback)(
1492
+ (event) => {
1493
+ updateState(event.state);
1494
+ onChange?.(event.state, event.source);
1495
+ },
1496
+ [onChange, updateState]
1497
+ );
1498
+ const handleFocus = (0, import_react6.useCallback)(
1499
+ (event) => {
1500
+ updateState(event.state);
1501
+ setFocused(true);
1502
+ onFocus?.(event.state);
1503
+ },
1504
+ [onFocus, updateState]
1505
+ );
1506
+ const handleBlur = (0, import_react6.useCallback)(
1507
+ (event) => {
1508
+ updateState(event.state);
1509
+ setFocused(false);
1510
+ onBlur?.(event.state);
1511
+ },
1512
+ [onBlur, updateState]
1513
+ );
1514
+ const handleCompositionStart = (0, import_react6.useCallback)(
1515
+ (event) => {
1516
+ updateState(event.state);
1517
+ onCompositionStart?.(event.state);
1518
+ },
1519
+ [onCompositionStart, updateState]
1520
+ );
1521
+ const handleCompositionUpdate = (0, import_react6.useCallback)(
1522
+ (event) => {
1523
+ updateState(event.state);
1524
+ onCompositionUpdate?.(event.state);
1525
+ },
1526
+ [onCompositionUpdate, updateState]
1527
+ );
1528
+ const handleCompositionEnd = (0, import_react6.useCallback)(
1529
+ (event) => {
1530
+ updateState(event.state);
1531
+ onCompositionEnd?.(event.state);
1532
+ },
1533
+ [onCompositionEnd, updateState]
1534
+ );
1535
+ const handleTextLayout = (0, import_react6.useCallback)((event) => {
1536
+ if (event.text === stateRef.current.value + stateRef.current.compositionText) {
1537
+ setCaretPosition(event.endCursorPosition);
1538
+ }
1539
+ }, []);
1540
+ (0, import_react6.useImperativeHandle)(
1541
+ ref,
1542
+ () => ({
1543
+ focus: () => {
1544
+ if (editableRef.current) {
1545
+ focusEditable(editableRef.current.nodeId);
1546
+ }
1547
+ },
1548
+ blur: () => {
1549
+ if (editableRef.current) {
1550
+ blurEditable(editableRef.current.nodeId);
1551
+ }
1552
+ },
1553
+ getState: () => stateRef.current
1554
+ }),
1555
+ []
1556
+ );
1557
+ (0, import_react6.useEffect)(() => {
1558
+ if (value === void 0 || value === stateRef.current.value) {
1559
+ return;
1560
+ }
1561
+ editableRef.current?.executeCommand({ subCommand: "setValue", value });
1562
+ const nextState = editableRef.current?.executeCommand({ subCommand: "getState" });
1563
+ if (nextState) {
1564
+ updateState(nextState);
1565
+ }
1566
+ }, [updateState, value]);
1567
+ (0, import_react6.useEffect)(() => {
1568
+ if (shouldAutoFocusRef.current && editableRef.current) {
1569
+ focusEditable(editableRef.current.nodeId);
1570
+ }
1571
+ }, []);
1572
+ (0, import_react6.useEffect)(() => {
1573
+ if (!pressed) {
1574
+ return;
1575
+ }
1576
+ const release = () => setPressed(false);
1577
+ const removeMouseUp = addEventListener("mouseup", release);
1578
+ const removeTouchEnd = addEventListener("touchend", release);
1579
+ const removeTouchCancel = addEventListener("touchcancel", release);
1580
+ return () => {
1581
+ removeMouseUp();
1582
+ removeTouchEnd();
1583
+ removeTouchCancel();
1584
+ };
1585
+ }, [pressed]);
1586
+ (0, import_react6.useEffect)(() => {
1587
+ if (disabled) {
1588
+ setHovered(false);
1589
+ setPressed(false);
1590
+ }
1591
+ }, [disabled]);
1592
+ (0, import_react6.useEffect)(() => {
1593
+ if (!focused) {
1594
+ setCaretVisible(false);
1595
+ return;
1596
+ }
1597
+ const expectedDisplayValue = displayValue;
1598
+ setCaretVisible(true);
1599
+ const timer = setInterval(() => {
1600
+ if (stateRef.current.value + stateRef.current.compositionText === expectedDisplayValue) {
1601
+ setCaretVisible((visible) => !visible);
1602
+ }
1603
+ }, blinkInterval ?? 500);
1604
+ return () => clearInterval(timer);
1605
+ }, [blinkInterval, displayValue, focused]);
1606
+ (0, import_react6.useEffect)(() => {
1607
+ if (!focused || !caretPosition) {
1608
+ return;
1609
+ }
1610
+ editableRef.current?.executeCommand({
1611
+ subCommand: "setCaretRect",
1612
+ x: paddingX + caretPosition[0],
1613
+ y: (viewportHeight - caretHeight) / 2,
1614
+ width: caretWidth,
1615
+ height: caretHeight
1616
+ });
1617
+ }, [caretHeight, caretPosition, caretWidth, focused, paddingX, viewportHeight]);
1618
+ const caretX = caretPosition?.[0] ?? 0;
1619
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
1620
+ "editable",
1621
+ {
1622
+ ...nodeProps,
1623
+ ref: editableRef,
1624
+ value: initialValue,
1625
+ disabled,
1626
+ readOnly,
1627
+ interactive: disabled ? false : interactive,
1628
+ cursor,
1629
+ onMouseEnter: mergeEvent(onMouseEnter, () => setHovered(true)),
1630
+ onMouseLeave: mergeEvent(onMouseLeave, () => {
1631
+ setHovered(false);
1632
+ setPressed(false);
1633
+ }),
1634
+ onMouseDown: mergeEvent(onMouseDown, () => setPressed(true)),
1635
+ onMouseUp: mergeEvent(onMouseUp, () => {
1636
+ setPressed(false);
1637
+ setHovered(true);
1638
+ }),
1639
+ onTouchStart: mergeEvent(onTouchStart, () => setPressed(true)),
1640
+ onTouchEnd: mergeEvent(onTouchEnd, () => {
1641
+ setPressed(false);
1642
+ setHovered(true);
1643
+ }),
1644
+ onTouchCancel: mergeEvent(onTouchCancel, () => {
1645
+ setHovered(false);
1646
+ setPressed(false);
1647
+ }),
1648
+ onInput: handleInput,
1649
+ onChange: handleChange,
1650
+ onFocus: handleFocus,
1651
+ onBlur: handleBlur,
1652
+ onCompositionStart: handleCompositionStart,
1653
+ onCompositionUpdate: handleCompositionUpdate,
1654
+ onCompositionEnd: handleCompositionEnd,
1655
+ children: [
1656
+ backgroundStyle ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("sprite", { ...backgroundStyle, targetWidth: viewportWidth, targetHeight: viewportHeight, interactive: false }) : null,
1657
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("clip", { x: paddingX, width: contentWidth, height: viewportHeight, interactive: false, children: [
1658
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1659
+ "text",
1660
+ {
1661
+ ...textStyle,
1662
+ text: displayValue,
1663
+ parseMarkup: false,
1664
+ printMode: "instant",
1665
+ anchor: [0, 0.5],
1666
+ pivot: [0, 0.5],
1667
+ interactive: false,
1668
+ onTextLayout: handleTextLayout
1669
+ }
1670
+ ),
1671
+ state.value.length === 0 && state.compositionText.length === 0 && placeholder ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1672
+ "text",
1673
+ {
1674
+ ...textStyle,
1675
+ ...placeholderStyle,
1676
+ text: placeholder,
1677
+ parseMarkup: false,
1678
+ printMode: "instant",
1679
+ anchor: [0, 0.5],
1680
+ pivot: [0, 0.5],
1681
+ interactive: false
1682
+ }
1683
+ ) : null,
1684
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1685
+ "sprite",
1686
+ {
1687
+ ...caretSpriteProps,
1688
+ x: caretX,
1689
+ y: (viewportHeight - caretHeight) / 2,
1690
+ mode: "nineslice",
1691
+ bounds: [0, 0, 0, 0],
1692
+ targetWidth: caretWidth,
1693
+ targetHeight: caretHeight,
1694
+ visible: focused && caretVisible && caretPosition !== void 0,
1695
+ interactive: false
1696
+ }
1697
+ )
1698
+ ] })
1699
+ ]
1700
+ }
1701
+ );
1702
+ });
1703
+
1704
+ // src/components/radio.tsx
1705
+ var import_react7 = require("react");
1706
+ var RadioGroupContext = (0, import_react7.createContext)(null);
1707
+ function RadioGroup({ value, defaultValue, onValueChange, children, ...containerProps }) {
1708
+ const [internalValue, setInternalValue] = (0, import_react7.useState)(defaultValue);
1709
+ const currentValue = value ?? internalValue;
1710
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1711
+ RadioGroupContext.Provider,
1712
+ {
1713
+ value: {
1714
+ value: currentValue,
1715
+ select: (nextValue) => {
1716
+ if (nextValue === currentValue) {
1717
+ return;
1718
+ }
1719
+ if (value === void 0) {
1720
+ setInternalValue(nextValue);
1721
+ }
1722
+ onValueChange?.(nextValue);
1723
+ }
1724
+ },
1725
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("container", { ...containerProps, children })
1726
+ }
1727
+ );
1728
+ }
1729
+ function Radio({ value, uncheckedSprite, checkedSprite, onPress, ...buttonProps }) {
1730
+ const group = (0, import_react7.useContext)(RadioGroupContext);
1731
+ if (!group) {
1732
+ throw new Error("Radio must be rendered inside a RadioGroup.");
1733
+ }
1734
+ const checked = group.value === value;
1735
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1736
+ Button,
1737
+ {
1738
+ ...buttonProps,
1739
+ sprite: checked ? checkedSprite : uncheckedSprite,
1740
+ onPress: (event) => {
1741
+ onPress?.(event);
1742
+ if (!event.defaultPrevented) {
1743
+ group.select(value);
1744
+ }
1745
+ }
1746
+ }
1747
+ );
1748
+ }
1749
+
1750
+ // src/components/select.tsx
1751
+ var import_react8 = require("react");
1377
1752
  function Select({
1378
1753
  value,
1379
1754
  defaultValue,
@@ -1392,8 +1767,8 @@ function Select({
1392
1767
  pivot = anchor,
1393
1768
  ...containerProps
1394
1769
  }) {
1395
- const [internalValue, setInternalValue] = (0, import_react6.useState)(defaultValue);
1396
- const [open, setOpen] = (0, import_react6.useState)(false);
1770
+ const [internalValue, setInternalValue] = (0, import_react8.useState)(defaultValue);
1771
+ const [open, setOpen] = (0, import_react8.useState)(false);
1397
1772
  const currentValue = value ?? internalValue;
1398
1773
  const currentOption = options.find((item) => item.value === currentValue);
1399
1774
  const { paddingX = 0, paddingY = 0, gap = 0, offsetX = 0, offsetY = 0, ...listSprite } = list;
@@ -1425,43 +1800,57 @@ function Select({
1425
1800
  }
1426
1801
  }
1427
1802
  ),
1428
- open && !disabled ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("sprite", { ...listSprite, targetHeight: listHeight, x: offsetX, y: (trigger.targetHeight ?? 0) + offsetY, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("vbox", { x: paddingX, y: paddingY, gap, children: options.map((item) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1429
- Button,
1803
+ open && !disabled ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1804
+ "sprite",
1430
1805
  {
1431
- sprite: option,
1432
- lockOn: item.value === currentValue ? "press" : void 0,
1433
- text: item.text,
1434
- textStyle,
1435
- textOffsetX,
1436
- textOffsetY,
1437
- textAlign,
1438
- onPress: (event) => {
1439
- if (event.defaultPrevented) {
1440
- return;
1441
- }
1442
- if (value === void 0) {
1443
- setInternalValue(item.value);
1444
- }
1445
- onValueChange?.(item.value, item);
1446
- setOpen(false);
1447
- }
1448
- },
1449
- item.value
1450
- )) }) }) : void 0
1806
+ ...listSprite,
1807
+ excludeFromLayout: true,
1808
+ targetHeight: listHeight,
1809
+ x: offsetX,
1810
+ y: (trigger.targetHeight ?? 0) + offsetY,
1811
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("vbox", { x: paddingX, y: paddingY, gap, children: options.map((item) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1812
+ Button,
1813
+ {
1814
+ sprite: option,
1815
+ lockOn: item.value === currentValue ? "press" : void 0,
1816
+ text: item.text,
1817
+ textStyle,
1818
+ textOffsetX,
1819
+ textOffsetY,
1820
+ textAlign,
1821
+ onPress: (event) => {
1822
+ if (event.defaultPrevented) {
1823
+ return;
1824
+ }
1825
+ if (value === void 0) {
1826
+ setInternalValue(item.value);
1827
+ }
1828
+ onValueChange?.(item.value, item);
1829
+ setOpen(false);
1830
+ }
1831
+ },
1832
+ item.value
1833
+ )) })
1834
+ }
1835
+ ) : void 0
1451
1836
  ]
1452
1837
  }
1453
1838
  );
1454
1839
  }
1455
1840
 
1456
1841
  // src/components/slider.tsx
1457
- var import_react7 = require("react");
1842
+ var import_react9 = require("react");
1458
1843
  function clampValue(value) {
1844
+ if (Number.isNaN(value)) {
1845
+ return 0;
1846
+ }
1459
1847
  return Math.max(0, Math.min(1, value));
1460
1848
  }
1461
1849
  function Slider({
1462
1850
  value,
1463
1851
  defaultValue = 0,
1464
1852
  onValueChange,
1853
+ onValueCommit,
1465
1854
  onPress,
1466
1855
  disabled = false,
1467
1856
  track,
@@ -1480,101 +1869,145 @@ function Slider({
1480
1869
  onTouchCancel,
1481
1870
  ...containerProps
1482
1871
  }) {
1483
- const [internalValue, setInternalValue] = (0, import_react7.useState)(() => clampValue(defaultValue));
1484
- const [hovered, setHovered] = (0, import_react7.useState)(false);
1485
- const [dragging, setDragging] = (0, import_react7.useState)(false);
1486
- const draggingRef = (0, import_react7.useRef)(false);
1872
+ const [internalValue, setInternalValue] = (0, import_react9.useState)(() => clampValue(defaultValue));
1873
+ const [dragging, setDragging] = (0, import_react9.useState)(false);
1487
1874
  const currentValue = clampValue(value ?? internalValue);
1875
+ const currentValueRef = (0, import_react9.useRef)(currentValue);
1876
+ currentValueRef.current = currentValue;
1877
+ const dragStateRef = (0, import_react9.useRef)(null);
1488
1878
  const distance = Math.max(0, track.targetWidth - thumb.targetWidth);
1489
- const state = disabled ? "disabled" : dragging ? "press" : hovered ? "hover" : "idle";
1490
- const { src: trackSrc, ...trackProps } = track;
1491
- const { src: thumbSrc, ...thumbProps } = thumb;
1492
- const updateValue = (event) => {
1493
- event.stopPropagation();
1494
- if (distance === 0) {
1495
- return;
1496
- }
1497
- const nextValue = clampValue((event.offsetX - thumb.targetWidth / 2) / distance);
1879
+ const setSliderValue = (0, import_react9.useCallback)((nextValue) => {
1880
+ const clampedValue = clampValue(nextValue);
1881
+ currentValueRef.current = clampedValue;
1498
1882
  if (value === void 0) {
1499
- setInternalValue(nextValue);
1883
+ setInternalValue(clampedValue);
1500
1884
  }
1501
- onValueChange?.(nextValue);
1502
- };
1503
- const endDragging = (0, import_react7.useCallback)(() => {
1504
- draggingRef.current = false;
1885
+ onValueChange?.(clampedValue);
1886
+ }, [onValueChange, value]);
1887
+ const endDragging = (0, import_react9.useCallback)((commit) => {
1888
+ if (dragStateRef.current === null) {
1889
+ return;
1890
+ }
1891
+ dragStateRef.current = null;
1505
1892
  setDragging(false);
1506
- }, []);
1507
- (0, import_react7.useEffect)(() => {
1508
- const handleEnd = () => {
1509
- if (draggingRef.current) {
1510
- endDragging();
1893
+ if (commit) {
1894
+ onValueCommit?.(currentValueRef.current);
1895
+ }
1896
+ }, [onValueCommit]);
1897
+ (0, import_react9.useEffect)(() => {
1898
+ const handleMouseUp = () => endDragging(true);
1899
+ const handleTouchEnd = (event) => {
1900
+ if (dragStateRef.current?.touchIdentifier === event.identifier) {
1901
+ endDragging(true);
1902
+ }
1903
+ };
1904
+ const handleTouchCancel2 = (event) => {
1905
+ if (dragStateRef.current?.touchIdentifier === event.identifier) {
1906
+ endDragging(false);
1511
1907
  }
1512
1908
  };
1513
- const removeMouseUp = addEventListener("mouseup", handleEnd);
1514
- const removeTouchEnd = addEventListener("touchend", handleEnd);
1515
- const removeTouchCancel = addEventListener("touchcancel", handleEnd);
1909
+ const removeMouseUp = addEventListener("mouseup", handleMouseUp);
1910
+ const removeTouchEnd = addEventListener("touchend", handleTouchEnd);
1911
+ const removeTouchCancel = addEventListener("touchcancel", handleTouchCancel2);
1516
1912
  return () => {
1517
1913
  removeMouseUp();
1518
1914
  removeTouchEnd();
1519
1915
  removeTouchCancel();
1520
1916
  };
1521
1917
  }, [endDragging]);
1522
- (0, import_react7.useEffect)(() => {
1918
+ (0, import_react9.useEffect)(() => {
1523
1919
  if (disabled) {
1524
- endDragging();
1525
- setHovered(false);
1920
+ endDragging(false);
1526
1921
  }
1527
1922
  }, [disabled, endDragging]);
1528
1923
  const startDragging = (event) => {
1924
+ event.stopPropagation();
1925
+ if (dragStateRef.current !== null) {
1926
+ return;
1927
+ }
1928
+ const thumbPosition = currentValueRef.current * distance;
1929
+ dragStateRef.current = {
1930
+ startPosition: event.offsetX,
1931
+ startValue: currentValueRef.current,
1932
+ touchIdentifier: "identifier" in event ? event.identifier : void 0,
1933
+ startedOnThumb: event.offsetX >= thumbPosition && event.offsetX <= thumbPosition + thumb.targetWidth,
1934
+ moved: false
1935
+ };
1936
+ setDragging(true);
1937
+ };
1938
+ const moveDragging = (event) => {
1939
+ const dragState = dragStateRef.current;
1940
+ if (dragState === null || "identifier" in event && dragState.touchIdentifier !== event.identifier || distance === 0) {
1941
+ return;
1942
+ }
1943
+ event.stopPropagation();
1944
+ const delta = event.offsetX - dragState.startPosition;
1945
+ if (delta !== 0) {
1946
+ dragState.moved = true;
1947
+ }
1948
+ setSliderValue(dragState.startValue + delta / distance);
1949
+ };
1950
+ const handlePress = (event) => {
1951
+ const dragState = dragStateRef.current;
1952
+ if (dragState === null || "identifier" in event && dragState.touchIdentifier !== event.identifier) {
1953
+ return;
1954
+ }
1529
1955
  onPress?.(event);
1530
1956
  if (event.defaultPrevented) {
1957
+ endDragging(false);
1531
1958
  return;
1532
1959
  }
1533
- draggingRef.current = true;
1534
- setDragging(true);
1535
- updateValue(event);
1960
+ if (!dragState.moved && !dragState.startedOnThumb && distance > 0) {
1961
+ setSliderValue((event.offsetX - thumb.targetWidth / 2) / distance);
1962
+ }
1963
+ endDragging(true);
1964
+ };
1965
+ const handleTouchCancel = (event) => {
1966
+ if (dragStateRef.current?.touchIdentifier === event.identifier) {
1967
+ endDragging(false);
1968
+ }
1536
1969
  };
1537
1970
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1538
- "container",
1971
+ Button,
1539
1972
  {
1540
1973
  ...containerProps,
1541
1974
  anchor,
1542
1975
  pivot,
1543
- interactive: disabled ? false : interactive,
1544
- onMouseEnter: mergeEvent(onMouseEnter, () => setHovered(true)),
1545
- onMouseLeave: mergeEvent(onMouseLeave, () => {
1546
- setHovered(false);
1547
- if (!draggingRef.current) {
1548
- setDragging(false);
1549
- }
1550
- }),
1976
+ interactive,
1977
+ disabled,
1978
+ lockOn: dragging ? "press" : void 0,
1979
+ sprite: {
1980
+ ...track,
1981
+ pivot: [0, 0.5],
1982
+ y: (track.targetHeight ?? 0) / 2
1983
+ },
1984
+ onPress: handlePress,
1985
+ onMouseEnter,
1986
+ onMouseLeave,
1551
1987
  onMouseDown: mergeEvent(onMouseDown, startDragging),
1552
- onMouseUp: mergeEvent(onMouseUp, endDragging),
1553
- onMouseMove: mergeEvent(onMouseMove, (event) => {
1554
- if (draggingRef.current) {
1555
- updateValue(event);
1556
- }
1557
- }),
1988
+ onMouseUp,
1989
+ onMouseMove: mergeEvent(onMouseMove, moveDragging),
1558
1990
  onTouchStart: mergeEvent(onTouchStart, startDragging),
1559
- onTouchMove: mergeEvent(onTouchMove, (event) => {
1560
- if (draggingRef.current) {
1561
- updateValue(event);
1562
- }
1563
- }),
1564
- onTouchEnd: mergeEvent(onTouchEnd, endDragging),
1565
- onTouchCancel: mergeEvent(onTouchCancel, endDragging),
1566
- onClick: (event) => event.stopPropagation(),
1567
- children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("sprite", { ...trackProps, src: resolveControlStateValue(trackSrc, state), cursor: "pointer", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1568
- "sprite",
1991
+ onTouchMove: mergeEvent(onTouchMove, moveDragging),
1992
+ onTouchEnd,
1993
+ onTouchCancel: mergeEvent(onTouchCancel, handleTouchCancel),
1994
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1995
+ Button,
1569
1996
  {
1570
- ...thumbProps,
1571
- src: resolveControlStateValue(thumbSrc, state),
1997
+ sprite: {
1998
+ ...thumb,
1999
+ anchor: [0, 0.5],
2000
+ pivot: [0, 0.5],
2001
+ x: 0,
2002
+ interactive: false
2003
+ },
2004
+ lockOn: dragging ? "press" : void 0,
2005
+ x: currentValue * distance,
1572
2006
  anchor: [0, 0.5],
1573
2007
  pivot: [0, 0.5],
1574
- x: currentValue * distance,
1575
2008
  interactive: false
1576
2009
  }
1577
- ) })
2010
+ )
1578
2011
  }
1579
2012
  );
1580
2013
  }
@@ -1944,6 +2377,7 @@ var debugSessionController = {
1944
2377
  throw new Error("Page switching is not supported by the app state adapter");
1945
2378
  }
1946
2379
  await appStateAdapter.switchPage(routeName, params);
2380
+ await syncCurrentExecutionCursor();
1947
2381
  return;
1948
2382
  }
1949
2383
  if (navigator.hasOverlay(routeName)) {
@@ -2534,7 +2968,7 @@ function useFadeOut(outTime, pause = false, onFinished) {
2534
2968
 
2535
2969
  // src/hooks/useScrollView.ts
2536
2970
  var import_core = require("@react-spring/core");
2537
- var import_react8 = require("react");
2971
+ var import_react10 = require("react");
2538
2972
  function clamp(value, min, max) {
2539
2973
  return Math.max(min, Math.min(max, value));
2540
2974
  }
@@ -2554,21 +2988,21 @@ function useScrollView({
2554
2988
  initialPosition = "start",
2555
2989
  wheelStep = 72
2556
2990
  }) {
2557
- const [contentHeight, setContentHeight] = (0, import_react8.useState)(0);
2558
- const [hasContentLayout, setHasContentLayout] = (0, import_react8.useState)(false);
2559
- const scrollTargetRef = (0, import_react8.useRef)(0);
2560
- const didSetInitialPositionRef = (0, import_react8.useRef)(false);
2561
- const touchDraggingRef = (0, import_react8.useRef)(false);
2562
- const touchStartYRef = (0, import_react8.useRef)(0);
2563
- const touchStartOffsetRef = (0, import_react8.useRef)(0);
2991
+ const [contentHeight, setContentHeight] = (0, import_react10.useState)(0);
2992
+ const [hasContentLayout, setHasContentLayout] = (0, import_react10.useState)(false);
2993
+ const scrollTargetRef = (0, import_react10.useRef)(0);
2994
+ const didSetInitialPositionRef = (0, import_react10.useRef)(false);
2995
+ const touchDraggingRef = (0, import_react10.useRef)(false);
2996
+ const touchStartYRef = (0, import_react10.useRef)(0);
2997
+ const touchStartOffsetRef = (0, import_react10.useRef)(0);
2564
2998
  const scrollOffset = (0, import_core.useSpringValue)(0, {
2565
2999
  config: {
2566
3000
  tension: 320,
2567
3001
  friction: 32
2568
3002
  }
2569
3003
  });
2570
- const maxScroll = (0, import_react8.useMemo)(() => Math.max(0, contentHeight - viewportHeight), [contentHeight, viewportHeight]);
2571
- const scrollTo = (0, import_react8.useCallback)(
3004
+ const maxScroll = (0, import_react10.useMemo)(() => Math.max(0, contentHeight - viewportHeight), [contentHeight, viewportHeight]);
3005
+ const scrollTo = (0, import_react10.useCallback)(
2572
3006
  (nextOffset, immediate = false) => {
2573
3007
  const offset = clamp(nextOffset, 0, maxScroll);
2574
3008
  if (offset === scrollTargetRef.current && !immediate) {
@@ -2579,13 +3013,13 @@ function useScrollView({
2579
3013
  },
2580
3014
  [maxScroll, scrollOffset]
2581
3015
  );
2582
- const scrollToRatio = (0, import_react8.useCallback)(
3016
+ const scrollToRatio = (0, import_react10.useCallback)(
2583
3017
  (ratio, immediate = false) => {
2584
3018
  scrollTo(clamp(ratio, 0, 1) * maxScroll, immediate);
2585
3019
  },
2586
3020
  [maxScroll, scrollTo]
2587
3021
  );
2588
- const handleContentLayout = (0, import_react8.useCallback)(
3022
+ const handleContentLayout = (0, import_react10.useCallback)(
2589
3023
  (event) => {
2590
3024
  if (!didSetInitialPositionRef.current) {
2591
3025
  const initialOffset = initialPosition === "end" ? Math.max(0, event.height - viewportHeight) : 0;
@@ -2598,13 +3032,13 @@ function useScrollView({
2598
3032
  },
2599
3033
  [initialPosition, scrollOffset, viewportHeight]
2600
3034
  );
2601
- (0, import_react8.useEffect)(() => {
3035
+ (0, import_react10.useEffect)(() => {
2602
3036
  if (!hasContentLayout) {
2603
3037
  return;
2604
3038
  }
2605
3039
  scrollTo(scrollTargetRef.current, true);
2606
3040
  }, [hasContentLayout, maxScroll, scrollTo]);
2607
- const handleWheel = (0, import_react8.useCallback)(
3041
+ const handleWheel = (0, import_react10.useCallback)(
2608
3042
  (event) => {
2609
3043
  if (maxScroll <= 0) {
2610
3044
  return;
@@ -2619,7 +3053,7 @@ function useScrollView({
2619
3053
  },
2620
3054
  [maxScroll, scrollTo, viewportHeight, wheelStep]
2621
3055
  );
2622
- const handleTouchStart = (0, import_react8.useCallback)(
3056
+ const handleTouchStart = (0, import_react10.useCallback)(
2623
3057
  (event) => {
2624
3058
  if (maxScroll <= 0) {
2625
3059
  return;
@@ -2631,7 +3065,7 @@ function useScrollView({
2631
3065
  },
2632
3066
  [maxScroll]
2633
3067
  );
2634
- const handleTouchMove = (0, import_react8.useCallback)(
3068
+ const handleTouchMove = (0, import_react10.useCallback)(
2635
3069
  (event) => {
2636
3070
  if (!touchDraggingRef.current) {
2637
3071
  return;
@@ -2641,7 +3075,7 @@ function useScrollView({
2641
3075
  },
2642
3076
  [scrollTo]
2643
3077
  );
2644
- const handleTouchEnd = (0, import_react8.useCallback)((event) => {
3078
+ const handleTouchEnd = (0, import_react10.useCallback)((event) => {
2645
3079
  if (!touchDraggingRef.current) {
2646
3080
  return;
2647
3081
  }
@@ -2663,7 +3097,7 @@ function useScrollView({
2663
3097
  }
2664
3098
 
2665
3099
  // src/hooks/useScenario.ts
2666
- var import_react9 = require("react");
3100
+ var import_react11 = require("react");
2667
3101
  var currentScenarioSession = null;
2668
3102
  var scenarioSessionId = 0;
2669
3103
  var scenarioLifecycleQueue = Promise.resolve();
@@ -2805,7 +3239,7 @@ function setWaiting(time, skippable) {
2805
3239
  executePluginCommand("scenario", { subCommand: "setWaiting", time, skippable });
2806
3240
  }
2807
3241
  function useScenario(stories, startName, entryName, goNextOnLoad = false) {
2808
- (0, import_react9.useEffect)(() => {
3242
+ (0, import_react11.useEffect)(() => {
2809
3243
  const session = acquireScenarioSession({
2810
3244
  stories: normalizeStories(stories),
2811
3245
  startName,
@@ -2819,9 +3253,9 @@ function useScenario(stories, startName, entryName, goNextOnLoad = false) {
2819
3253
  }
2820
3254
 
2821
3255
  // src/hooks/useSoundEffect.ts
2822
- var import_react10 = require("react");
3256
+ var import_react12 = require("react");
2823
3257
  function useSoundEffect(src) {
2824
- (0, import_react10.useEffect)(() => {
3258
+ (0, import_react12.useEffect)(() => {
2825
3259
  return () => {
2826
3260
  try {
2827
3261
  if (src) {
@@ -2836,7 +3270,7 @@ function useSoundEffect(src) {
2836
3270
  }
2837
3271
  };
2838
3272
  }, [src]);
2839
- return (0, import_react10.useCallback)(() => {
3273
+ return (0, import_react12.useCallback)(() => {
2840
3274
  try {
2841
3275
  if (src) {
2842
3276
  executePluginCommand("audio", {
@@ -2852,7 +3286,7 @@ function useSoundEffect(src) {
2852
3286
  }
2853
3287
 
2854
3288
  // src/hooks/useStage.ts
2855
- var import_react11 = require("react");
3289
+ var import_react13 = require("react");
2856
3290
  var import_valtio5 = require("valtio");
2857
3291
  var SKIP_INTERVAL_MS = 80;
2858
3292
  var DEFAULT_FAST_FORWARD_STEP_LIMIT = 1e4;
@@ -2938,6 +3372,9 @@ function createStage() {
2938
3372
  return addToRegistry(interruptCallbacks, cb);
2939
3373
  }
2940
3374
  function tryInterrupt() {
3375
+ if (tryFinishActiveWait()) {
3376
+ return true;
3377
+ }
2941
3378
  for (const cb of interruptCallbacks) {
2942
3379
  try {
2943
3380
  if (cb()) return true;
@@ -2985,6 +3422,8 @@ function createStage() {
2985
3422
  let _autoTicketSeq = 0;
2986
3423
  const _pendingAutoTickets = /* @__PURE__ */ new Map();
2987
3424
  let _fastForwardRuntime = null;
3425
+ let _activeWait = null;
3426
+ let _activeWaitSeq = 0;
2988
3427
  let _managedAdvanceInFlight = false;
2989
3428
  let _managedAdvancePending = false;
2990
3429
  function resetManagedAdvanceState() {
@@ -3073,12 +3512,53 @@ function createStage() {
3073
3512
  });
3074
3513
  }
3075
3514
  function requestNextLine() {
3515
+ if (_activeWait !== null) {
3516
+ return;
3517
+ }
3076
3518
  if (isManagedAdvanceActive()) {
3077
3519
  scheduleManagedAdvance();
3078
3520
  return;
3079
3521
  }
3080
3522
  void Promise.resolve(nextLine()).catch(handleManagedAdvanceError);
3081
3523
  }
3524
+ function invalidateActiveWait() {
3525
+ if (_activeWait === null) {
3526
+ return;
3527
+ }
3528
+ _activeWait.settled = true;
3529
+ _activeWait = null;
3530
+ }
3531
+ function settleActiveWait(wait, error) {
3532
+ if (_activeWait !== wait || wait.settled) {
3533
+ return;
3534
+ }
3535
+ wait.settled = true;
3536
+ _activeWait = null;
3537
+ if (error !== void 0) {
3538
+ console.error(`[Stage] Promise hold ${wait.id} rejected:`, error);
3539
+ }
3540
+ requestNextLine();
3541
+ }
3542
+ function tryFinishActiveWait() {
3543
+ const wait = _activeWait;
3544
+ if (wait === null || !wait.skippable || wait.settled) {
3545
+ return false;
3546
+ }
3547
+ const finish = wait.until.finish;
3548
+ if (typeof finish === "function") {
3549
+ try {
3550
+ finish.call(wait.until);
3551
+ } catch (error) {
3552
+ console.error(`[Stage] Failed to finish Promise hold ${wait.id}:`, error);
3553
+ }
3554
+ } else {
3555
+ console.warn(
3556
+ `[Stage] Skipping Promise hold ${wait.id} without finish(); the underlying operation may continue.`
3557
+ );
3558
+ }
3559
+ settleActiveWait(wait);
3560
+ return true;
3561
+ }
3082
3562
  function clearAutoResumeTimer() {
3083
3563
  if (_autoResumeTimer !== null) {
3084
3564
  clearTimeout(_autoResumeTimer);
@@ -3266,7 +3746,11 @@ function createStage() {
3266
3746
  if (isAnyBlockerActive()) return;
3267
3747
  skipState.active = true;
3268
3748
  invokeSkipCallbacks();
3749
+ const activeWait = _activeWait;
3269
3750
  tryInterrupt();
3751
+ if (activeWait !== null && activeWait !== _activeWait) {
3752
+ return;
3753
+ }
3270
3754
  scheduleSkipNextLine();
3271
3755
  }
3272
3756
  function stopSkip() {
@@ -3285,6 +3769,7 @@ function createStage() {
3285
3769
  if (fastForwardState.active) return;
3286
3770
  if (isAnyAutoBlockerActive()) return;
3287
3771
  autoState.active = true;
3772
+ if (_activeWait !== null) return;
3288
3773
  tryInterrupt();
3289
3774
  scheduleAutoNextLine();
3290
3775
  }
@@ -3321,6 +3806,7 @@ function createStage() {
3321
3806
  return fastForwardState.active;
3322
3807
  }
3323
3808
  function resetRuntimeState() {
3809
+ invalidateActiveWait();
3324
3810
  skipState.active = false;
3325
3811
  autoState.active = false;
3326
3812
  fastForwardState.active = false;
@@ -3366,7 +3852,7 @@ function createStage() {
3366
3852
  setWaiting(time, skippable);
3367
3853
  }
3368
3854
  },
3369
- hold() {
3855
+ hold(until, skippable = false) {
3370
3856
  handled = true;
3371
3857
  if (warpActive) {
3372
3858
  return;
@@ -3375,6 +3861,24 @@ function createStage() {
3375
3861
  requestNextLine();
3376
3862
  return;
3377
3863
  }
3864
+ if (until !== void 0) {
3865
+ invalidateActiveWait();
3866
+ const wait = {
3867
+ id: ++_activeWaitSeq,
3868
+ until,
3869
+ skippable,
3870
+ settled: false
3871
+ };
3872
+ _activeWait = wait;
3873
+ void Promise.resolve(until).then(
3874
+ () => settleActiveWait(wait),
3875
+ (error) => settleActiveWait(wait, error)
3876
+ );
3877
+ if (skipState.active) {
3878
+ tryFinishActiveWait();
3879
+ }
3880
+ return;
3881
+ }
3378
3882
  if (skipState.active && !unskippableFlag) {
3379
3883
  if (isAnyBlockerActive()) {
3380
3884
  stopSkip();
@@ -3434,6 +3938,7 @@ function createStage() {
3434
3938
  return parsed.data;
3435
3939
  }
3436
3940
  function dispatchCommand(e) {
3941
+ invalidateActiveWait();
3437
3942
  for (const cb of beforeHandleCommandCallbacks) {
3438
3943
  try {
3439
3944
  cb(e);
@@ -3462,6 +3967,7 @@ function createStage() {
3462
3967
  }
3463
3968
  }
3464
3969
  function dispatchTextLine(e) {
3970
+ invalidateActiveWait();
3465
3971
  const { control, wasHandled } = buildControl();
3466
3972
  for (const handler of textLineHandlers) {
3467
3973
  handler(e, control);
@@ -3495,6 +4001,7 @@ function createStage() {
3495
4001
  })
3496
4002
  ];
3497
4003
  return () => {
4004
+ resetRuntimeState();
3498
4005
  for (const cleanup of cleanups) cleanup();
3499
4006
  };
3500
4007
  }
@@ -3515,52 +4022,54 @@ function createStage() {
3515
4022
  startAuto,
3516
4023
  stopAuto,
3517
4024
  isAutoing,
4025
+ setDefaultAutoTailMs,
3518
4026
  startFastForward,
3519
4027
  stopFastForward,
3520
4028
  isFastForwarding,
4029
+ getSeekingType,
3521
4030
  resetRuntimeState,
3522
4031
  bindEvents
3523
4032
  };
3524
4033
  }
3525
- var StageContext = (0, import_react11.createContext)(null);
4034
+ var StageContext = (0, import_react13.createContext)(null);
3526
4035
  function useStageContext() {
3527
- const ctx = (0, import_react11.useContext)(StageContext);
4036
+ const ctx = (0, import_react13.useContext)(StageContext);
3528
4037
  if (!ctx) throw new Error("useStageContext must be used within StageContextProvider");
3529
4038
  return ctx;
3530
4039
  }
3531
4040
  function StageContextProvider({ stage, children }) {
3532
- (0, import_react11.useEffect)(() => {
4041
+ (0, import_react13.useEffect)(() => {
3533
4042
  return stage.bindEvents();
3534
4043
  }, [stage]);
3535
- return (0, import_react11.createElement)(StageContext.Provider, { value: stage }, children);
4044
+ return (0, import_react13.createElement)(StageContext.Provider, { value: stage }, children);
3536
4045
  }
3537
4046
  function useSkipCallback(callback) {
3538
4047
  const stage = useStageContext();
3539
- (0, import_react11.useEffect)(() => {
4048
+ (0, import_react13.useEffect)(() => {
3540
4049
  return stage.addSkipCallback(callback);
3541
4050
  }, [stage, callback]);
3542
4051
  }
3543
4052
  function useInterruptCallback(callback) {
3544
4053
  const stage = useStageContext();
3545
- (0, import_react11.useEffect)(() => {
4054
+ (0, import_react13.useEffect)(() => {
3546
4055
  return stage.addInterruptCallback(callback);
3547
4056
  }, [stage, callback]);
3548
4057
  }
3549
4058
  function useSkipBlocker(callback) {
3550
4059
  const stage = useStageContext();
3551
- (0, import_react11.useEffect)(() => {
4060
+ (0, import_react13.useEffect)(() => {
3552
4061
  return stage.addSkipBlocker(callback);
3553
4062
  }, [stage, callback]);
3554
4063
  }
3555
4064
  function useAutoBlocker(callback) {
3556
4065
  const stage = useStageContext();
3557
- (0, import_react11.useEffect)(() => {
4066
+ (0, import_react13.useEffect)(() => {
3558
4067
  return stage.addAutoBlocker(callback);
3559
4068
  }, [stage, callback]);
3560
4069
  }
3561
4070
  function useAutoTicket() {
3562
4071
  const stage = useStageContext();
3563
- return (0, import_react11.useCallback)(
4072
+ return (0, import_react13.useCallback)(
3564
4073
  (options) => {
3565
4074
  return stage.issueAutoTicket(options);
3566
4075
  },
@@ -3569,7 +4078,7 @@ function useAutoTicket() {
3569
4078
  }
3570
4079
  function useBeforeHandleCommandCallback(callback) {
3571
4080
  const stage = useStageContext();
3572
- (0, import_react11.useEffect)(() => {
4081
+ (0, import_react13.useEffect)(() => {
3573
4082
  return stage.addBeforeHandleCommandCallback(callback);
3574
4083
  }, [stage, callback]);
3575
4084
  }