@novely/core 0.52.0-next.2 → 0.53.0-next

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/index.d.ts CHANGED
@@ -609,15 +609,6 @@ type StateFunction<S extends State> = {
609
609
  (value: DeepPartial<S> | ((prev: S) => S)): void;
610
610
  (): S;
611
611
  };
612
- /**
613
- * @deprecated `EngineTypes` should be used instead
614
- */
615
- type TypeEssentials<$Lang extends Lang, $State extends State, $Data extends Data, $Characters extends Record<string, Character<$Lang>>> = {
616
- readonly l: $Lang | null;
617
- readonly s: $State | null;
618
- readonly d: $Data | null;
619
- readonly c: $Characters | null;
620
- };
621
612
  type EngineTypes<$Lang extends Lang = Lang, $State extends State = State, $Data extends Data = Data, $Characters extends Record<string, Character<$Lang>> = Record<string, Character<$Lang>>> = {
622
613
  readonly l: $Lang;
623
614
  readonly s: $State;
@@ -648,6 +639,37 @@ type Character<$Lang extends Lang = string> = {
648
639
  emotions: Emotions;
649
640
  };
650
641
 
642
+ type TickHandler = (ticker: Ticker) => void;
643
+ declare class Ticker {
644
+ listeners: Set<TickHandler>;
645
+ running: boolean;
646
+ private _factory;
647
+ constructor(factory: TickerFactory);
648
+ get deltaTime(): number;
649
+ get lastTime(): number;
650
+ add(cb: (ticker: Ticker) => void): () => void;
651
+ remove(cb: (ticker: Ticker) => void): void;
652
+ start: () => void;
653
+ stop: () => void;
654
+ detach: () => void;
655
+ }
656
+ declare class TickerFactory {
657
+ private _children;
658
+ private _raf;
659
+ private _running;
660
+ private _unsubscribe;
661
+ deltaTime: number;
662
+ lastTime: number;
663
+ constructor(paused: Derived<boolean>);
664
+ start(): void;
665
+ stop(): void;
666
+ fork(): Ticker;
667
+ check(positive: boolean): void;
668
+ destroy(): void;
669
+ detach(ticker: Ticker): void;
670
+ private update;
671
+ }
672
+
651
673
  type ValidAction = ['choice', string | undefined, ...[string, unknown[], (() => boolean)?, (() => boolean)?, string?][]] | ['clear', Set<keyof DefaultActionProxy>?, Set<string>?, {
652
674
  music: Set<string>;
653
675
  sounds: Set<string>;
@@ -734,7 +756,7 @@ type CustomHandlerFunctionParameters<L extends string, S extends State> = {
734
756
  */
735
757
  dataAtKey: <T extends Record<string, unknown>>(key: string) => T | null;
736
758
  /**
737
- * Function to set cleanup functions.
759
+ * Function to register cleanup callbacks (executed in reverse order of registration).
738
760
  *
739
761
  * @example
740
762
  * ```ts
@@ -793,6 +815,10 @@ type CustomHandlerFunctionParameters<L extends string, S extends State> = {
793
815
  * }
794
816
  */
795
817
  paused: Derived<boolean>;
818
+ /**
819
+ * Ticker
820
+ */
821
+ ticker: Ticker;
796
822
  };
797
823
  type CustomHandlerFunction<L extends string, S extends State> = (parameters: CustomHandlerFunctionParameters<L, S>) => Thenable<void>;
798
824
  type CustomHandlerCalling = {
@@ -1044,19 +1070,6 @@ declare const novely: <$Language extends string, $Characters extends Record<stri
1044
1070
  * ```
1045
1071
  */
1046
1072
  data: StateFunction<$Data>;
1047
- /**
1048
- * Used in combination with type utilities
1049
- * @deprecated Use `engine.types` instead
1050
- * @example
1051
- * ```ts
1052
- * import type { ConditionParams, StateFunction } from '@novely/core';
1053
- *
1054
- * const conditionCheck = (state: StateFunction<ConditionParams<typeof engine.typeEssintials>>) => {
1055
- * return state.age >= 18;
1056
- * }
1057
- * ```
1058
- */
1059
- typeEssentials: TypeEssentials<$Language, $State, $Data, $Characters>;
1060
1073
  /**
1061
1074
  * Used in combination with type utilities
1062
1075
  * @example
@@ -1200,4 +1213,4 @@ declare const pauseOnBlur: (engine: {
1200
1213
  unsubscribe: () => void;
1201
1214
  };
1202
1215
 
1203
- export { type ActionChoiceChoice, type ActionChoiceChoiceObject, type ActionInputOnInputMeta, type ActionInputSetup, type ActionInputSetupCleanup, type ActionProxy, type AllowedContent, type AudioHandle, type BackgroundImage, type BaseTranslationStrings, type Character, type CharacterAssetSizes, type CharacterHandle, type CharactersData, type ChoiceCheckFunction, type ChoiceCheckFunctionProps, type ChoiceOnSelectFunction, type ChoiceOnSelectFunctionProps, type ChoiceParams, type ConditionCheckFunction, type ConditionParams, type Context, type CoreData, type CustomActionHandle, type CustomHandler, type CustomHandlerFunction, type CustomHandlerFunctionGetFn, type CustomHandlerFunctionParameters, type CustomHandlerGetResult, type CustomHandlerGetResultDataFunction, type CustomHandlerInfo, type Data, type DeepPartial, type DefaultActionProxy, type Derived, EN, type Emotions, type EngineTypes, type FunctionParams, type FunctionableValue, type GetActionParameters, type InputHandler, type Lang, type NovelyAsset, type NovelyInit, type NovelyScreen, type Path, type PathItem, type PluralType, type Pluralization, RU, type Renderer, type RendererInit, type RendererInitPreviewReturn, type Save, type Stack, type StackHolder, type State, type StateFunction, type StorageAdapter, type StorageData, type StorageMeta, type Stored, type Story, type TextContent, type Thenable, type TranslationActions, type TypeEssentials, type TypesFromEngine, type TypewriterSpeed, type ValidAction, asset, extendAction, novely, pauseOnBlur, storageAdapterLocal };
1216
+ export { type ActionChoiceChoice, type ActionChoiceChoiceObject, type ActionInputOnInputMeta, type ActionInputSetup, type ActionInputSetupCleanup, type ActionProxy, type AllowedContent, type AudioHandle, type BackgroundImage, type BaseTranslationStrings, type Character, type CharacterAssetSizes, type CharacterHandle, type CharactersData, type ChoiceCheckFunction, type ChoiceCheckFunctionProps, type ChoiceOnSelectFunction, type ChoiceOnSelectFunctionProps, type ChoiceParams, type ConditionCheckFunction, type ConditionParams, type Context, type CoreData, type CustomActionHandle, type CustomHandler, type CustomHandlerFunction, type CustomHandlerFunctionGetFn, type CustomHandlerFunctionParameters, type CustomHandlerGetResult, type CustomHandlerGetResultDataFunction, type CustomHandlerInfo, type Data, type DeepPartial, type DefaultActionProxy, type Derived, EN, type Emotions, type EngineTypes, type FunctionParams, type FunctionableValue, type GetActionParameters, type InputHandler, type Lang, type NovelyAsset, type NovelyInit, type NovelyScreen, type Path, type PathItem, type PluralType, type Pluralization, RU, type Renderer, type RendererInit, type RendererInitPreviewReturn, type Save, type Stack, type StackHolder, type State, type StateFunction, type StorageAdapter, type StorageData, type StorageMeta, type Stored, type Story, type TextContent, type Thenable, Ticker, type TranslationActions, type TypesFromEngine, type TypewriterSpeed, type ValidAction, asset, extendAction, novely, pauseOnBlur, storageAdapterLocal };
package/dist/index.js CHANGED
@@ -1026,6 +1026,15 @@ var getCustomActionCleanupHolder = (ctx) => {
1026
1026
  CUSTOM_ACTION_CLEANUP_MAP.set(ctx.id, holder);
1027
1027
  return holder;
1028
1028
  };
1029
+ var cleanCleanupSource = ({ list }) => {
1030
+ while (list.length) {
1031
+ try {
1032
+ list.pop()();
1033
+ } catch (e) {
1034
+ console.error(e);
1035
+ }
1036
+ }
1037
+ };
1029
1038
  var handleCustomAction = (ctx, fn, {
1030
1039
  lang,
1031
1040
  state,
@@ -1033,7 +1042,8 @@ var handleCustomAction = (ctx, fn, {
1033
1042
  remove: renderersRemove,
1034
1043
  getStack: getStack2,
1035
1044
  templateReplace,
1036
- paused
1045
+ paused,
1046
+ ticker
1037
1047
  }) => {
1038
1048
  const holder = getCustomActionHolder(ctx, fn);
1039
1049
  const cleanupHolder = getCustomActionCleanupHolder(ctx);
@@ -1045,15 +1055,13 @@ var handleCustomAction = (ctx, fn, {
1045
1055
  };
1046
1056
  const cleanupSource = {
1047
1057
  fn,
1048
- list: /* @__PURE__ */ new Set(),
1049
- dom: cleanupNode
1058
+ list: [ticker.detach],
1059
+ node: cleanupNode
1050
1060
  };
1051
1061
  cleanupHolder.push(cleanupSource);
1052
- const flags = {
1053
- ...ctx.meta
1054
- };
1055
1062
  const getDomNodes = (insert = true) => {
1056
1063
  if (holder.node || !insert) {
1064
+ setMountElement(holder.node);
1057
1065
  return {
1058
1066
  element: holder.node,
1059
1067
  root: ctx.root
@@ -1067,7 +1075,7 @@ var handleCustomAction = (ctx, fn, {
1067
1075
  };
1068
1076
  };
1069
1077
  const clear = (func) => {
1070
- cleanupSource.list.add(once2(func));
1078
+ cleanupSource.list.push(once2(func));
1071
1079
  };
1072
1080
  const data = (updatedData) => {
1073
1081
  if (updatedData) {
@@ -1076,9 +1084,9 @@ var handleCustomAction = (ctx, fn, {
1076
1084
  return holder.localData;
1077
1085
  };
1078
1086
  const remove = () => {
1079
- cleanupSource.list.forEach((fn2) => fn2());
1080
- cleanupSource.list.clear();
1081
- cleanupSource.dom();
1087
+ cleanCleanupSource(cleanupSource);
1088
+ holder.node = null;
1089
+ setMountElement(null);
1082
1090
  renderersRemove();
1083
1091
  };
1084
1092
  const stack = getStack2(ctx);
@@ -1086,7 +1094,7 @@ var handleCustomAction = (ctx, fn, {
1086
1094
  return stack.value;
1087
1095
  };
1088
1096
  return fn({
1089
- flags,
1097
+ flags: ctx.meta,
1090
1098
  lang,
1091
1099
  state,
1092
1100
  data,
@@ -1098,7 +1106,8 @@ var handleCustomAction = (ctx, fn, {
1098
1106
  getDomNodes,
1099
1107
  getSave,
1100
1108
  contextKey: ctx.id,
1101
- paused: flags.preview ? immutable(false) : paused
1109
+ paused: ctx.meta.preview ? immutable(false) : paused,
1110
+ ticker
1102
1111
  });
1103
1112
  };
1104
1113
 
@@ -1376,6 +1385,115 @@ var setDocumentLanguage = (language) => {
1376
1385
  document.documentElement.lang = language;
1377
1386
  };
1378
1387
 
1388
+ // src/ticker.ts
1389
+ var Ticker = class {
1390
+ listeners = /* @__PURE__ */ new Set();
1391
+ running = false;
1392
+ _factory;
1393
+ constructor(factory) {
1394
+ this._factory = factory;
1395
+ }
1396
+ get deltaTime() {
1397
+ return this._factory.deltaTime;
1398
+ }
1399
+ get lastTime() {
1400
+ return this._factory.lastTime;
1401
+ }
1402
+ add(cb) {
1403
+ this.listeners.add(cb);
1404
+ if (this.listeners.size === 1) {
1405
+ this._factory.check(true);
1406
+ }
1407
+ return () => {
1408
+ this.remove(cb);
1409
+ };
1410
+ }
1411
+ remove(cb) {
1412
+ this.listeners.delete(cb);
1413
+ if (this.listeners.size === 0) {
1414
+ this._factory.check(false);
1415
+ }
1416
+ }
1417
+ start = () => {
1418
+ this.running = true;
1419
+ if (this.listeners.size > 0) {
1420
+ this._factory.check(true);
1421
+ }
1422
+ };
1423
+ stop = () => {
1424
+ this.running = false;
1425
+ };
1426
+ detach = () => {
1427
+ this._factory.detach(this);
1428
+ };
1429
+ };
1430
+ var TickerFactory = class {
1431
+ _children = /* @__PURE__ */ new Set();
1432
+ _raf = -1;
1433
+ _running = false;
1434
+ _unsubscribe;
1435
+ deltaTime = 0;
1436
+ lastTime = performance.now();
1437
+ constructor(paused) {
1438
+ this._unsubscribe = paused.subscribe((paused2) => {
1439
+ if (paused2) {
1440
+ this.stop();
1441
+ } else if (Array.from(this._children).some((ticker) => ticker.running && ticker.listeners.size > 0)) {
1442
+ this.start();
1443
+ }
1444
+ });
1445
+ }
1446
+ start() {
1447
+ if (this._running) {
1448
+ return;
1449
+ }
1450
+ cancelAnimationFrame(this._raf);
1451
+ this.lastTime = performance.now();
1452
+ this._running = true;
1453
+ this._raf = requestAnimationFrame(this.update);
1454
+ }
1455
+ stop() {
1456
+ cancelAnimationFrame(this._raf);
1457
+ this._running = false;
1458
+ this._raf = -1;
1459
+ }
1460
+ fork() {
1461
+ const ticker = new Ticker(this);
1462
+ this._children.add(ticker);
1463
+ return ticker;
1464
+ }
1465
+ check(positive) {
1466
+ if (positive) {
1467
+ this.start();
1468
+ } else if (Array.from(this._children).every((ticker) => !ticker.running || ticker.listeners.size === 0)) {
1469
+ this.stop();
1470
+ }
1471
+ }
1472
+ destroy() {
1473
+ this._unsubscribe();
1474
+ this._children.forEach((child) => child.detach());
1475
+ }
1476
+ detach(ticker) {
1477
+ this._children.delete(ticker);
1478
+ this.check(false);
1479
+ }
1480
+ update = (currentTime) => {
1481
+ this.deltaTime = currentTime - this.lastTime;
1482
+ this._children.forEach((ticker) => {
1483
+ if (ticker.running) {
1484
+ ticker.listeners.forEach((tick) => {
1485
+ tick(ticker);
1486
+ });
1487
+ }
1488
+ });
1489
+ if (!this._running) {
1490
+ return;
1491
+ }
1492
+ this.lastTime = currentTime;
1493
+ this._raf = requestAnimationFrame(this.update);
1494
+ };
1495
+ };
1496
+
1379
1497
  // src/novely.ts
1380
1498
  var novely = ({
1381
1499
  characters,
@@ -1641,20 +1759,19 @@ var novely = ({
1641
1759
  }
1642
1760
  }
1643
1761
  futures.reverse();
1644
- const dom = /* @__PURE__ */ new Set();
1762
+ const nodeCleanup = /* @__PURE__ */ new Set();
1645
1763
  for (const future of futures) {
1646
1764
  inner: for (let i = cleanupHolder.length - 1; i >= 0; i--) {
1647
1765
  const item = cleanupHolder[i];
1648
1766
  if (future === item.fn) {
1649
- item.list.forEach((fn) => fn());
1650
- item.list.clear();
1767
+ cleanCleanupSource(item);
1768
+ nodeCleanup.add(item.node);
1651
1769
  cleanupHolder.splice(i, 1);
1652
- dom.add(item.dom);
1653
1770
  break inner;
1654
1771
  }
1655
1772
  }
1656
1773
  }
1657
- dom.forEach((f) => f());
1774
+ nodeCleanup.forEach((f) => f());
1658
1775
  }
1659
1776
  const {
1660
1777
  run,
@@ -1717,6 +1834,7 @@ var novely = ({
1717
1834
  save("auto");
1718
1835
  }
1719
1836
  stack.clear();
1837
+ clearCustomActionsAtContext(ctx);
1720
1838
  ctx.clear(EMPTY_SET, EMPTY_SET, { music: EMPTY_SET, sounds: EMPTY_SET }, noop);
1721
1839
  renderer.ui.showScreen("mainmenu");
1722
1840
  ctx.audio.destroy();
@@ -1818,14 +1936,13 @@ var novely = ({
1818
1936
  };
1819
1937
  const clearCustomActionsAtContext = (ctx) => {
1820
1938
  const cleanupHolder = getCustomActionCleanupHolder(ctx);
1821
- const dom = /* @__PURE__ */ new Set();
1939
+ const nodeCleanup = /* @__PURE__ */ new Set();
1822
1940
  for (const item of cleanupHolder) {
1823
- item.list.forEach((fn) => fn());
1824
- item.list.clear();
1825
- dom.add(item.dom);
1941
+ cleanCleanupSource(item);
1942
+ nodeCleanup.add(item.node);
1826
1943
  }
1827
1944
  cleanupHolder.length = 0;
1828
- dom.forEach((fn) => fn());
1945
+ nodeCleanup.forEach((fn) => fn());
1829
1946
  };
1830
1947
  const getResourseTypeWrapper = (url) => {
1831
1948
  return getResourseType({
@@ -1956,6 +2073,7 @@ var novely = ({
1956
2073
  }
1957
2074
  }
1958
2075
  };
2076
+ const ticker = new TickerFactory(paused);
1959
2077
  const { match, nativeActions } = matchAction(matchActionOptions, {
1960
2078
  wait({ ctx, data: data2, push }, [time]) {
1961
2079
  if (ctx.meta.restoring) return;
@@ -2162,6 +2280,7 @@ var novely = ({
2162
2280
  lang,
2163
2281
  getStack: useStack,
2164
2282
  paused,
2283
+ ticker: ticker.fork(),
2165
2284
  templateReplace
2166
2285
  });
2167
2286
  const next2 = () => {
@@ -2387,19 +2506,6 @@ var novely = ({
2387
2506
  * ```
2388
2507
  */
2389
2508
  data,
2390
- /**
2391
- * Used in combination with type utilities
2392
- * @deprecated Use `engine.types` instead
2393
- * @example
2394
- * ```ts
2395
- * import type { ConditionParams, StateFunction } from '@novely/core';
2396
- *
2397
- * const conditionCheck = (state: StateFunction<ConditionParams<typeof engine.typeEssintials>>) => {
2398
- * return state.age >= 18;
2399
- * }
2400
- * ```
2401
- */
2402
- typeEssentials: {},
2403
2509
  /**
2404
2510
  * Used in combination with type utilities
2405
2511
  * @example
@@ -2443,6 +2549,7 @@ var novely = ({
2443
2549
  if (destroyed) return;
2444
2550
  dataLoaded.cancel();
2445
2551
  UIInstance.unmount();
2552
+ ticker.destroy();
2446
2553
  removeEventListener("beforeunload", throttledShortOnStorageDataChange);
2447
2554
  destroyed = true;
2448
2555
  },