@momoyu-ink/kit 0.9.0 → 0.10.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.mjs CHANGED
@@ -19,9 +19,14 @@ var __reExport = (target, mod, secondTarget) => (__copyProps(target, mod, "defau
19
19
  // src/lib.ts
20
20
  var lib_exports = {};
21
21
  __export(lib_exports, {
22
+ Button: () => Button,
23
+ Checkbox: () => Checkbox,
22
24
  DEBUG_EMPTY_PAGE: () => DEBUG_EMPTY_PAGE,
23
25
  OverlayParamsContext: () => OverlayParamsContext,
24
26
  PageParamsContext: () => PageParamsContext,
27
+ ScrollView: () => ScrollView,
28
+ Select: () => Select,
29
+ Slider: () => Slider,
25
30
  StageContextProvider: () => StageContextProvider,
26
31
  a: () => animated,
27
32
  addEventListener: () => addEventListener,
@@ -47,6 +52,7 @@ __export(lib_exports, {
47
52
  initGlobalVariableDefaults: () => initGlobalVariableDefaults,
48
53
  initUiData: () => initUiData,
49
54
  loadVariablesDocument: () => loadVariablesDocument,
55
+ mergeEvent: () => mergeEvent,
50
56
  moyu: () => moyu_exports,
51
57
  nextLine: () => nextLine,
52
58
  registerAppStateAdapter: () => registerAppStateAdapter,
@@ -73,6 +79,7 @@ __export(lib_exports, {
73
79
  useNavigationParams: () => useNavigationParams,
74
80
  useNavigationState: () => useNavigationState,
75
81
  useScenario: () => useScenario,
82
+ useScrollView: () => useScrollView,
76
83
  useSkipBlocker: () => useSkipBlocker,
77
84
  useSkipCallback: () => useSkipCallback,
78
85
  useSoundEffect: () => useSoundEffect,
@@ -782,6 +789,8 @@ import { Globals, colors, createStringInterpolator } from "@react-spring/shared"
782
789
  // src/spring/primitives.ts
783
790
  var primitives = [
784
791
  "container",
792
+ "vbox",
793
+ "hbox",
785
794
  "sprite",
786
795
  "text",
787
796
  "clip",
@@ -940,6 +949,19 @@ function getStageSize() {
940
949
  });
941
950
  return stageSize;
942
951
  }
952
+ function mergeEvent(handlers, defaultHandler) {
953
+ return (event) => {
954
+ if (handlers) {
955
+ const handlerList = Array.isArray(handlers) ? handlers : [handlers];
956
+ for (const handler of handlerList) {
957
+ handler(event);
958
+ }
959
+ }
960
+ if (!event.defaultPrevented) {
961
+ defaultHandler?.(event);
962
+ }
963
+ };
964
+ }
943
965
 
944
966
  // src/gameState.ts
945
967
  import { createContext, createElement, useContext } from "react";
@@ -1017,7 +1039,11 @@ function createGameStateContext(defaults) {
1017
1039
  // src/components/navigation.tsx
1018
1040
  import { createContext as createContext2, useContext as useContext2 } from "react";
1019
1041
  import { proxy as proxy2, useSnapshot as useSnapshot2 } from "valtio";
1042
+
1043
+ // src/jsx-runtime.ts
1020
1044
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
1045
+
1046
+ // src/components/navigation.tsx
1021
1047
  var PageParamsContext = createContext2(void 0);
1022
1048
  var OverlayParamsContext = createContext2(void 0);
1023
1049
  var DEBUG_EMPTY_PAGE = "debug-empty";
@@ -1173,6 +1199,374 @@ function useNavigationParams() {
1173
1199
  return overlayParams ?? pageParams ?? {};
1174
1200
  }
1175
1201
 
1202
+ // src/components/scroll-view.tsx
1203
+ function ScrollView({ width, height, controller, children, clipProps, contentProps }) {
1204
+ return /* @__PURE__ */ jsx(
1205
+ "clip",
1206
+ {
1207
+ ...clipProps,
1208
+ width,
1209
+ height,
1210
+ onWheel: controller.handleWheel,
1211
+ onTouchStart: controller.handleTouchStart,
1212
+ onTouchMove: controller.handleTouchMove,
1213
+ onTouchEnd: controller.handleTouchEnd,
1214
+ onTouchCancel: controller.handleTouchEnd,
1215
+ children: /* @__PURE__ */ jsx(
1216
+ animated.vbox,
1217
+ {
1218
+ ...contentProps,
1219
+ y: controller.scrollOffset.to((value) => -value),
1220
+ onLayout: controller.handleContentLayout,
1221
+ children
1222
+ }
1223
+ )
1224
+ }
1225
+ );
1226
+ }
1227
+
1228
+ // src/components/button.tsx
1229
+ import { useEffect, useState } from "react";
1230
+
1231
+ // src/components/control.ts
1232
+ function resolveControlStateValue(value, state) {
1233
+ if (!Array.isArray(value)) {
1234
+ return value;
1235
+ }
1236
+ const index = state === "idle" ? 0 : state === "hover" ? 1 : state === "press" ? 2 : 3;
1237
+ return value[index] ?? value[0];
1238
+ }
1239
+
1240
+ // src/components/button.tsx
1241
+ function Button({
1242
+ sprite,
1243
+ disabled = false,
1244
+ lockOn,
1245
+ onPress,
1246
+ text,
1247
+ textStyle,
1248
+ textOffsetX,
1249
+ textOffsetY,
1250
+ textAlign = "center",
1251
+ anchor,
1252
+ pivot = anchor,
1253
+ interactive,
1254
+ onMouseEnter,
1255
+ onMouseLeave,
1256
+ onMouseDown,
1257
+ onMouseUp,
1258
+ onTouchStart,
1259
+ onTouchEnd,
1260
+ onTouchCancel,
1261
+ ...containerProps
1262
+ }) {
1263
+ const [hovered, setHovered] = useState(false);
1264
+ const [pressed, setPressed] = useState(false);
1265
+ useEffect(() => {
1266
+ if (disabled) {
1267
+ setHovered(false);
1268
+ setPressed(false);
1269
+ }
1270
+ }, [disabled]);
1271
+ const state = disabled ? "disabled" : lockOn ?? (pressed ? "press" : hovered ? "hover" : "idle");
1272
+ const { src, ...spriteProps } = sprite;
1273
+ const resolvedTextStyle = textStyle ? resolveControlStateValue(textStyle, state) : void 0;
1274
+ const textAnchor = textAlign === "left" ? [0, 0.5] : textAlign === "right" ? [1, 0.5] : [0.5, 0.5];
1275
+ return /* @__PURE__ */ jsx(
1276
+ "container",
1277
+ {
1278
+ ...containerProps,
1279
+ anchor,
1280
+ pivot,
1281
+ interactive: disabled ? false : interactive,
1282
+ onMouseEnter: mergeEvent(onMouseEnter, (event) => {
1283
+ if (event.targetId === event.currentTargetId) {
1284
+ event.stopPropagation();
1285
+ return;
1286
+ }
1287
+ setHovered(true);
1288
+ }),
1289
+ onMouseLeave: mergeEvent(onMouseLeave, () => {
1290
+ setHovered(false);
1291
+ setPressed(false);
1292
+ }),
1293
+ onMouseDown: mergeEvent(onMouseDown, () => setPressed(true)),
1294
+ onMouseUp: mergeEvent(onMouseUp, (event) => {
1295
+ if (pressed) {
1296
+ onPress?.(event);
1297
+ }
1298
+ setPressed(false);
1299
+ setHovered(true);
1300
+ }),
1301
+ onTouchStart: mergeEvent(onTouchStart, () => setPressed(true)),
1302
+ onTouchEnd: mergeEvent(onTouchEnd, (event) => {
1303
+ if (pressed) {
1304
+ onPress?.(event);
1305
+ }
1306
+ setPressed(false);
1307
+ setHovered(true);
1308
+ }),
1309
+ onTouchCancel: mergeEvent(onTouchCancel, () => {
1310
+ setHovered(false);
1311
+ setPressed(false);
1312
+ }),
1313
+ onClick: (event) => event.stopPropagation(),
1314
+ children: /* @__PURE__ */ jsx("sprite", { ...spriteProps, src: resolveControlStateValue(src, state), cursor: "pointer", children: text !== void 0 ? /* @__PURE__ */ jsx(
1315
+ "text",
1316
+ {
1317
+ ...resolvedTextStyle,
1318
+ text,
1319
+ x: textOffsetX,
1320
+ y: textOffsetY,
1321
+ interactive: false,
1322
+ anchor: textAnchor,
1323
+ pivot: textAnchor
1324
+ }
1325
+ ) : void 0 })
1326
+ }
1327
+ );
1328
+ }
1329
+
1330
+ // src/components/checkbox.tsx
1331
+ import { useState as useState2 } from "react";
1332
+ function Checkbox({
1333
+ checked,
1334
+ defaultChecked = false,
1335
+ onCheckedChange,
1336
+ uncheckedSprite,
1337
+ checkedSprite,
1338
+ onPress,
1339
+ ...buttonProps
1340
+ }) {
1341
+ const [internalChecked, setInternalChecked] = useState2(defaultChecked);
1342
+ const currentChecked = checked ?? internalChecked;
1343
+ return /* @__PURE__ */ jsx(
1344
+ Button,
1345
+ {
1346
+ ...buttonProps,
1347
+ sprite: currentChecked ? checkedSprite : uncheckedSprite,
1348
+ onPress: (event) => {
1349
+ onPress?.(event);
1350
+ if (event.defaultPrevented) {
1351
+ return;
1352
+ }
1353
+ const nextChecked = !currentChecked;
1354
+ if (checked === void 0) {
1355
+ setInternalChecked(nextChecked);
1356
+ }
1357
+ onCheckedChange?.(nextChecked);
1358
+ }
1359
+ }
1360
+ );
1361
+ }
1362
+
1363
+ // src/components/select.tsx
1364
+ import { useState as useState3 } from "react";
1365
+ function Select({
1366
+ value,
1367
+ defaultValue,
1368
+ onValueChange,
1369
+ onPress,
1370
+ disabled = false,
1371
+ options,
1372
+ trigger,
1373
+ list,
1374
+ option,
1375
+ textStyle,
1376
+ textOffsetX,
1377
+ textOffsetY,
1378
+ textAlign,
1379
+ anchor,
1380
+ pivot = anchor,
1381
+ ...containerProps
1382
+ }) {
1383
+ const [internalValue, setInternalValue] = useState3(defaultValue);
1384
+ const [open, setOpen] = useState3(false);
1385
+ const currentValue = value ?? internalValue;
1386
+ const currentOption = options.find((item) => item.value === currentValue);
1387
+ const { paddingX = 0, paddingY = 0, gap = 0, offsetX = 0, offsetY = 0, ...listSprite } = list;
1388
+ const listHeight = paddingY * 2 + options.length * option.targetHeight + Math.max(0, options.length - 1) * gap;
1389
+ return /* @__PURE__ */ jsxs(
1390
+ "container",
1391
+ {
1392
+ ...containerProps,
1393
+ anchor,
1394
+ pivot,
1395
+ interactive: disabled ? false : containerProps.interactive,
1396
+ children: [
1397
+ /* @__PURE__ */ jsx(
1398
+ Button,
1399
+ {
1400
+ sprite: trigger,
1401
+ disabled,
1402
+ lockOn: open ? "press" : void 0,
1403
+ text: currentOption?.text ?? "",
1404
+ textStyle,
1405
+ textOffsetX,
1406
+ textOffsetY,
1407
+ textAlign,
1408
+ onPress: (event) => {
1409
+ onPress?.(event);
1410
+ if (!event.defaultPrevented) {
1411
+ setOpen((active) => !active);
1412
+ }
1413
+ }
1414
+ }
1415
+ ),
1416
+ open && !disabled ? /* @__PURE__ */ jsx("sprite", { ...listSprite, targetHeight: listHeight, x: offsetX, y: (trigger.targetHeight ?? 0) + offsetY, children: /* @__PURE__ */ jsx("vbox", { x: paddingX, y: paddingY, gap, children: options.map((item) => /* @__PURE__ */ jsx(
1417
+ Button,
1418
+ {
1419
+ sprite: option,
1420
+ lockOn: item.value === currentValue ? "press" : void 0,
1421
+ text: item.text,
1422
+ textStyle,
1423
+ textOffsetX,
1424
+ textOffsetY,
1425
+ textAlign,
1426
+ onPress: (event) => {
1427
+ if (event.defaultPrevented) {
1428
+ return;
1429
+ }
1430
+ if (value === void 0) {
1431
+ setInternalValue(item.value);
1432
+ }
1433
+ onValueChange?.(item.value, item);
1434
+ setOpen(false);
1435
+ }
1436
+ },
1437
+ item.value
1438
+ )) }) }) : void 0
1439
+ ]
1440
+ }
1441
+ );
1442
+ }
1443
+
1444
+ // src/components/slider.tsx
1445
+ import { useCallback, useEffect as useEffect2, useRef, useState as useState4 } from "react";
1446
+ function clampValue(value) {
1447
+ return Math.max(0, Math.min(1, value));
1448
+ }
1449
+ function Slider({
1450
+ value,
1451
+ defaultValue = 0,
1452
+ onValueChange,
1453
+ onPress,
1454
+ disabled = false,
1455
+ track,
1456
+ thumb,
1457
+ anchor,
1458
+ pivot = anchor,
1459
+ interactive,
1460
+ onMouseEnter,
1461
+ onMouseLeave,
1462
+ onMouseDown,
1463
+ onMouseUp,
1464
+ onMouseMove,
1465
+ onTouchStart,
1466
+ onTouchMove,
1467
+ onTouchEnd,
1468
+ onTouchCancel,
1469
+ ...containerProps
1470
+ }) {
1471
+ const [internalValue, setInternalValue] = useState4(() => clampValue(defaultValue));
1472
+ const [hovered, setHovered] = useState4(false);
1473
+ const [dragging, setDragging] = useState4(false);
1474
+ const draggingRef = useRef(false);
1475
+ const currentValue = clampValue(value ?? internalValue);
1476
+ const distance = Math.max(0, track.targetWidth - thumb.targetWidth);
1477
+ const state = disabled ? "disabled" : dragging ? "press" : hovered ? "hover" : "idle";
1478
+ const { src: trackSrc, ...trackProps } = track;
1479
+ const { src: thumbSrc, ...thumbProps } = thumb;
1480
+ const updateValue = (event) => {
1481
+ event.stopPropagation();
1482
+ if (distance === 0) {
1483
+ return;
1484
+ }
1485
+ const nextValue = clampValue((event.offsetX - thumb.targetWidth / 2) / distance);
1486
+ if (value === void 0) {
1487
+ setInternalValue(nextValue);
1488
+ }
1489
+ onValueChange?.(nextValue);
1490
+ };
1491
+ const endDragging = useCallback(() => {
1492
+ draggingRef.current = false;
1493
+ setDragging(false);
1494
+ }, []);
1495
+ useEffect2(() => {
1496
+ const handleEnd = () => {
1497
+ if (draggingRef.current) {
1498
+ endDragging();
1499
+ }
1500
+ };
1501
+ const removeMouseUp = addEventListener("mouseup", handleEnd);
1502
+ const removeTouchEnd = addEventListener("touchend", handleEnd);
1503
+ const removeTouchCancel = addEventListener("touchcancel", handleEnd);
1504
+ return () => {
1505
+ removeMouseUp();
1506
+ removeTouchEnd();
1507
+ removeTouchCancel();
1508
+ };
1509
+ }, [endDragging]);
1510
+ useEffect2(() => {
1511
+ if (disabled) {
1512
+ endDragging();
1513
+ setHovered(false);
1514
+ }
1515
+ }, [disabled, endDragging]);
1516
+ const startDragging = (event) => {
1517
+ onPress?.(event);
1518
+ if (event.defaultPrevented) {
1519
+ return;
1520
+ }
1521
+ draggingRef.current = true;
1522
+ setDragging(true);
1523
+ updateValue(event);
1524
+ };
1525
+ return /* @__PURE__ */ jsx(
1526
+ "container",
1527
+ {
1528
+ ...containerProps,
1529
+ anchor,
1530
+ pivot,
1531
+ interactive: disabled ? false : interactive,
1532
+ onMouseEnter: mergeEvent(onMouseEnter, () => setHovered(true)),
1533
+ onMouseLeave: mergeEvent(onMouseLeave, () => {
1534
+ setHovered(false);
1535
+ if (!draggingRef.current) {
1536
+ setDragging(false);
1537
+ }
1538
+ }),
1539
+ onMouseDown: mergeEvent(onMouseDown, startDragging),
1540
+ onMouseUp: mergeEvent(onMouseUp, endDragging),
1541
+ onMouseMove: mergeEvent(onMouseMove, (event) => {
1542
+ if (draggingRef.current) {
1543
+ updateValue(event);
1544
+ }
1545
+ }),
1546
+ onTouchStart: mergeEvent(onTouchStart, startDragging),
1547
+ onTouchMove: mergeEvent(onTouchMove, (event) => {
1548
+ if (draggingRef.current) {
1549
+ updateValue(event);
1550
+ }
1551
+ }),
1552
+ onTouchEnd: mergeEvent(onTouchEnd, endDragging),
1553
+ onTouchCancel: mergeEvent(onTouchCancel, endDragging),
1554
+ onClick: (event) => event.stopPropagation(),
1555
+ children: /* @__PURE__ */ jsx("sprite", { ...trackProps, src: resolveControlStateValue(trackSrc, state), cursor: "pointer", children: /* @__PURE__ */ jsx(
1556
+ "sprite",
1557
+ {
1558
+ ...thumbProps,
1559
+ src: resolveControlStateValue(thumbSrc, state),
1560
+ anchor: [0, 0.5],
1561
+ pivot: [0, 0.5],
1562
+ x: currentValue * distance,
1563
+ interactive: false
1564
+ }
1565
+ ) })
1566
+ }
1567
+ );
1568
+ }
1569
+
1176
1570
  // src/debug/session.ts
1177
1571
  import { useSnapshot as useSnapshot3, proxy as proxy3 } from "valtio";
1178
1572
  var debugState = proxy3({
@@ -2120,14 +2514,144 @@ function useFadeOut(outTime, pause = false, onFinished) {
2120
2514
  );
2121
2515
  const skip = () => {
2122
2516
  api.stop();
2123
- api.set({ opacity: 1 });
2517
+ api.set({ opacity: 0 });
2124
2518
  onFinished?.();
2125
2519
  };
2126
2520
  return [style, api, skip];
2127
2521
  }
2128
2522
 
2523
+ // src/hooks/useScrollView.ts
2524
+ import { useSpringValue } from "@react-spring/core";
2525
+ import { useCallback as useCallback2, useEffect as useEffect3, useMemo, useRef as useRef2, useState as useState5 } from "react";
2526
+ function clamp(value, min, max) {
2527
+ return Math.max(min, Math.min(max, value));
2528
+ }
2529
+ function normalizeWheelDelta(event, viewportHeight) {
2530
+ switch (event.deltaMode) {
2531
+ case "line":
2532
+ return event.deltaY * 36;
2533
+ case "page":
2534
+ return event.deltaY * viewportHeight * 0.85;
2535
+ case "pixel":
2536
+ default:
2537
+ return event.deltaY;
2538
+ }
2539
+ }
2540
+ function useScrollView({
2541
+ viewportHeight,
2542
+ initialPosition = "start",
2543
+ wheelStep = 72
2544
+ }) {
2545
+ const [contentHeight, setContentHeight] = useState5(0);
2546
+ const [hasContentLayout, setHasContentLayout] = useState5(false);
2547
+ const scrollTargetRef = useRef2(0);
2548
+ const didSetInitialPositionRef = useRef2(false);
2549
+ const touchDraggingRef = useRef2(false);
2550
+ const touchStartYRef = useRef2(0);
2551
+ const touchStartOffsetRef = useRef2(0);
2552
+ const scrollOffset = useSpringValue(0, {
2553
+ config: {
2554
+ tension: 320,
2555
+ friction: 32
2556
+ }
2557
+ });
2558
+ const maxScroll = useMemo(() => Math.max(0, contentHeight - viewportHeight), [contentHeight, viewportHeight]);
2559
+ const scrollTo = useCallback2(
2560
+ (nextOffset, immediate = false) => {
2561
+ const offset = clamp(nextOffset, 0, maxScroll);
2562
+ if (offset === scrollTargetRef.current && !immediate) {
2563
+ return;
2564
+ }
2565
+ scrollTargetRef.current = offset;
2566
+ scrollOffset.start(offset, { immediate });
2567
+ },
2568
+ [maxScroll, scrollOffset]
2569
+ );
2570
+ const scrollToRatio = useCallback2(
2571
+ (ratio, immediate = false) => {
2572
+ scrollTo(clamp(ratio, 0, 1) * maxScroll, immediate);
2573
+ },
2574
+ [maxScroll, scrollTo]
2575
+ );
2576
+ const handleContentLayout = useCallback2(
2577
+ (event) => {
2578
+ if (!didSetInitialPositionRef.current) {
2579
+ const initialOffset = initialPosition === "end" ? Math.max(0, event.height - viewportHeight) : 0;
2580
+ didSetInitialPositionRef.current = true;
2581
+ scrollTargetRef.current = initialOffset;
2582
+ scrollOffset.start(initialOffset, { immediate: true });
2583
+ }
2584
+ setContentHeight(event.height);
2585
+ setHasContentLayout(true);
2586
+ },
2587
+ [initialPosition, scrollOffset, viewportHeight]
2588
+ );
2589
+ useEffect3(() => {
2590
+ if (!hasContentLayout) {
2591
+ return;
2592
+ }
2593
+ scrollTo(scrollTargetRef.current, true);
2594
+ }, [hasContentLayout, maxScroll, scrollTo]);
2595
+ const handleWheel = useCallback2(
2596
+ (event) => {
2597
+ if (maxScroll <= 0) {
2598
+ return;
2599
+ }
2600
+ const delta = normalizeWheelDelta(event, viewportHeight);
2601
+ if (delta === 0) {
2602
+ return;
2603
+ }
2604
+ event.stopPropagation();
2605
+ const step = -Math.sign(delta) * Math.max(wheelStep, Math.min(Math.abs(delta), viewportHeight * 0.45));
2606
+ scrollTo(scrollTargetRef.current + step);
2607
+ },
2608
+ [maxScroll, scrollTo, viewportHeight, wheelStep]
2609
+ );
2610
+ const handleTouchStart = useCallback2(
2611
+ (event) => {
2612
+ if (maxScroll <= 0) {
2613
+ return;
2614
+ }
2615
+ event.stopPropagation();
2616
+ touchDraggingRef.current = true;
2617
+ touchStartYRef.current = event.clientY;
2618
+ touchStartOffsetRef.current = scrollTargetRef.current;
2619
+ },
2620
+ [maxScroll]
2621
+ );
2622
+ const handleTouchMove = useCallback2(
2623
+ (event) => {
2624
+ if (!touchDraggingRef.current) {
2625
+ return;
2626
+ }
2627
+ event.stopPropagation();
2628
+ scrollTo(touchStartOffsetRef.current + touchStartYRef.current - event.clientY, true);
2629
+ },
2630
+ [scrollTo]
2631
+ );
2632
+ const handleTouchEnd = useCallback2((event) => {
2633
+ if (!touchDraggingRef.current) {
2634
+ return;
2635
+ }
2636
+ event.stopPropagation();
2637
+ touchDraggingRef.current = false;
2638
+ }, []);
2639
+ return {
2640
+ scrollOffset,
2641
+ contentHeight,
2642
+ maxScroll,
2643
+ handleContentLayout,
2644
+ handleWheel,
2645
+ handleTouchStart,
2646
+ handleTouchMove,
2647
+ handleTouchEnd,
2648
+ scrollTo,
2649
+ scrollToRatio
2650
+ };
2651
+ }
2652
+
2129
2653
  // src/hooks/useScenario.ts
2130
- import { useEffect } from "react";
2654
+ import { useEffect as useEffect4 } from "react";
2131
2655
  var currentScenarioSession = null;
2132
2656
  var scenarioSessionId = 0;
2133
2657
  var scenarioLifecycleQueue = Promise.resolve();
@@ -2269,7 +2793,7 @@ function setWaiting(time, skippable) {
2269
2793
  executePluginCommand("scenario", { subCommand: "setWaiting", time, skippable });
2270
2794
  }
2271
2795
  function useScenario(stories, startName, entryName, goNextOnLoad = false) {
2272
- useEffect(() => {
2796
+ useEffect4(() => {
2273
2797
  const session = acquireScenarioSession({
2274
2798
  stories: normalizeStories(stories),
2275
2799
  startName,
@@ -2283,9 +2807,9 @@ function useScenario(stories, startName, entryName, goNextOnLoad = false) {
2283
2807
  }
2284
2808
 
2285
2809
  // src/hooks/useSoundEffect.ts
2286
- import { useCallback, useEffect as useEffect2 } from "react";
2810
+ import { useCallback as useCallback3, useEffect as useEffect5 } from "react";
2287
2811
  function useSoundEffect(src) {
2288
- useEffect2(() => {
2812
+ useEffect5(() => {
2289
2813
  return () => {
2290
2814
  try {
2291
2815
  if (src) {
@@ -2300,7 +2824,7 @@ function useSoundEffect(src) {
2300
2824
  }
2301
2825
  };
2302
2826
  }, [src]);
2303
- return useCallback(() => {
2827
+ return useCallback3(() => {
2304
2828
  try {
2305
2829
  if (src) {
2306
2830
  executePluginCommand("audio", {
@@ -2316,7 +2840,7 @@ function useSoundEffect(src) {
2316
2840
  }
2317
2841
 
2318
2842
  // src/hooks/useStage.ts
2319
- import { createContext as createContext3, useContext as useContext3, useEffect as useEffect3, createElement as createElement2, useCallback as useCallback2 } from "react";
2843
+ import { createContext as createContext3, useContext as useContext3, useEffect as useEffect6, createElement as createElement2, useCallback as useCallback4 } from "react";
2320
2844
  import { proxy as proxy5, useSnapshot as useSnapshot5 } from "valtio";
2321
2845
  var SKIP_INTERVAL_MS = 80;
2322
2846
  var DEFAULT_FAST_FORWARD_STEP_LIMIT = 1e4;
@@ -2993,38 +3517,38 @@ function useStageContext() {
2993
3517
  return ctx;
2994
3518
  }
2995
3519
  function StageContextProvider({ stage, children }) {
2996
- useEffect3(() => {
3520
+ useEffect6(() => {
2997
3521
  return stage.bindEvents();
2998
3522
  }, [stage]);
2999
3523
  return createElement2(StageContext.Provider, { value: stage }, children);
3000
3524
  }
3001
3525
  function useSkipCallback(callback) {
3002
3526
  const stage = useStageContext();
3003
- useEffect3(() => {
3527
+ useEffect6(() => {
3004
3528
  return stage.addSkipCallback(callback);
3005
3529
  }, [stage, callback]);
3006
3530
  }
3007
3531
  function useInterruptCallback(callback) {
3008
3532
  const stage = useStageContext();
3009
- useEffect3(() => {
3533
+ useEffect6(() => {
3010
3534
  return stage.addInterruptCallback(callback);
3011
3535
  }, [stage, callback]);
3012
3536
  }
3013
3537
  function useSkipBlocker(callback) {
3014
3538
  const stage = useStageContext();
3015
- useEffect3(() => {
3539
+ useEffect6(() => {
3016
3540
  return stage.addSkipBlocker(callback);
3017
3541
  }, [stage, callback]);
3018
3542
  }
3019
3543
  function useAutoBlocker(callback) {
3020
3544
  const stage = useStageContext();
3021
- useEffect3(() => {
3545
+ useEffect6(() => {
3022
3546
  return stage.addAutoBlocker(callback);
3023
3547
  }, [stage, callback]);
3024
3548
  }
3025
3549
  function useAutoTicket() {
3026
3550
  const stage = useStageContext();
3027
- return useCallback2(
3551
+ return useCallback4(
3028
3552
  (options) => {
3029
3553
  return stage.issueAutoTicket(options);
3030
3554
  },
@@ -3033,7 +3557,7 @@ function useAutoTicket() {
3033
3557
  }
3034
3558
  function useBeforeHandleCommandCallback(callback) {
3035
3559
  const stage = useStageContext();
3036
- useEffect3(() => {
3560
+ useEffect6(() => {
3037
3561
  return stage.addBeforeHandleCommandCallback(callback);
3038
3562
  }, [stage, callback]);
3039
3563
  }
@@ -3041,9 +3565,14 @@ function useBeforeHandleCommandCallback(callback) {
3041
3565
  // src/lib.ts
3042
3566
  export * from "@react-spring/core";
3043
3567
  export {
3568
+ Button,
3569
+ Checkbox,
3044
3570
  DEBUG_EMPTY_PAGE,
3045
3571
  OverlayParamsContext,
3046
3572
  PageParamsContext,
3573
+ ScrollView,
3574
+ Select,
3575
+ Slider,
3047
3576
  StageContextProvider,
3048
3577
  animated as a,
3049
3578
  addEventListener,
@@ -3069,6 +3598,7 @@ export {
3069
3598
  initGlobalVariableDefaults,
3070
3599
  initUiData,
3071
3600
  loadVariablesDocument,
3601
+ mergeEvent,
3072
3602
  moyu_exports as moyu,
3073
3603
  nextLine,
3074
3604
  registerAppStateAdapter,
@@ -3095,6 +3625,7 @@ export {
3095
3625
  useNavigationParams,
3096
3626
  useNavigationState,
3097
3627
  useScenario,
3628
+ useScrollView,
3098
3629
  useSkipBlocker,
3099
3630
  useSkipCallback,
3100
3631
  useSoundEffect,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@momoyu-ink/kit",
3
- "version": "0.9.0",
3
+ "version": "0.10.0",
4
4
  "description": "Software Development Kit of Moyu Visual Novel Engine",
5
5
  "main": "dist/lib.cjs",
6
6
  "module": "dist/lib.mjs",