narraleaf-react 0.17.1 → 0.19.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.
@@ -3,8 +3,9 @@ import { GameState } from "../../player/gameState";
3
3
  import { Storable, Namespace } from "../elements/persistent/storable";
4
4
  import { LiveGame } from "../game/liveGame";
5
5
  import { Preference } from "../game/preference";
6
+ import type { StorableChange, StorableRestore } from "../elements/persistent/storable";
6
7
  import type { SavedGame } from "../gameTypes";
7
8
  import type { StackSnapshot, StackFrameSnapshot } from "../action/stackModel";
8
9
  import { KeyMap } from "../game/keyMap";
9
10
  export { LiveGame, GameState, Game, Storable, Namespace, Preference, KeyMap, };
10
- export type { SavedGame, StackSnapshot, StackFrameSnapshot, };
11
+ export type { SavedGame, StackSnapshot, StackFrameSnapshot, StorableChange, StorableRestore, };
@@ -3,6 +3,7 @@ import { Chained, Proxied } from "../../action/chain";
3
3
  import { GameState } from "../../common/game";
4
4
  import { LogicAction } from "../../game";
5
5
  import type { LiveGameEventToken } from "../../types";
6
+ import { Image } from "../displayable/image";
6
7
  import { Layer } from "../layer";
7
8
  import { DynamicPersistent, Persistent } from "../persistent";
8
9
  import { Scene } from "../scene";
@@ -23,6 +24,15 @@ export declare class DevTools {
23
24
  static wrapAction(action: LogicAction.Actions[] | Proxied<LogicAction.GameElement, Chained<LogicAction.Actions>>): ControlAction;
24
25
  static getNamespaceName(persistent: Persistent<any>): string;
25
26
  static getCurrentScene(gameState: GameState): Scene | null;
27
+ /**
28
+ * The src of each of a layered image's layers, bottom to top, for the given tags (the image's
29
+ * current ones when omitted). `null` entries are layers that draw nothing; a non-layered image
30
+ * yields an empty array.
31
+ *
32
+ * A layered image has no single src to read — it is a stack — so an editor host that renders
33
+ * its own thumbnail of an on-stage element has to composite these itself, in order.
34
+ */
35
+ static getLayerSrcs(image: Image, tags?: string[]): (string | null)[];
26
36
  /**
27
37
  * Register a displayable into a scene's render tree without emitting a `displayable:init`
28
38
  * action. The element renders immediately at its constructor-config transform state
@@ -49,10 +49,21 @@ export type TagSrcResolver<T extends TagGroupDefinition> = (...tags: SelectEleme
49
49
  * A set of mutually exclusive variants for one layer, keyed by tag.
50
50
  *
51
51
  * `null` means the layer draws nothing for that tag.
52
+ *
53
+ * The tag set is the group's identity: every layer offering the *same* set of tags is driven by
54
+ * one group, which is how a single `char(["angry"])` moves the brows, the eyes and the mouth at
55
+ * once. To follow a group, repeat its whole tag set on the layer and use `null` for the tags
56
+ * where that layer draws nothing. Offering only part of a set instead declares a *different*
57
+ * group, and the shared tags then collide.
52
58
  */
53
59
  export type LayerVariants = Record<string, string | null>;
54
60
  /**
55
61
  * Derives a layer's src from the currently active tags. Declares no tags of its own.
62
+ *
63
+ * A resolver is opaque, so the srcs it can return are invisible to the preloader and are fetched
64
+ * on first use. Prefer {@link LayerVariants} — including for a layer that follows another layer's
65
+ * group, which no longer needs a resolver — and keep resolvers for sources that genuinely cannot
66
+ * be enumerated.
56
67
  */
57
68
  export type LayerResolver = (tags: ReadonlySet<string>) => string | null;
58
69
  /**
@@ -74,7 +85,8 @@ export type LayeredDefinition<L extends LayerGroupDefinition = LayerGroupDefinit
74
85
  */
75
86
  layers: L;
76
87
  /**
77
- * One tag per variant layer, in any order.
88
+ * One tag per group, in any order. Layers that offer the same tag set share a group and so
89
+ * share that one default.
78
90
  */
79
91
  defaults: readonly LayerTagsOf<L>[];
80
92
  };
@@ -88,10 +100,14 @@ export declare class Image<Tags extends TagGroupDefinition | null = TagGroupDefi
88
100
  * src: {
89
101
  * layers: [
90
102
  * "body.png",
91
- * {happy: "happy.png", sad: "sad.png"},
92
103
  * {shirt: "shirt.png", coat: "coat.png"},
104
+ * // Both layers offer {happy, sad}, so one group drives them together.
105
+ * {happy: "brows_happy.png", sad: "brows_sad.png"},
106
+ * {happy: "mouth_happy.png", sad: "mouth_sad.png"},
107
+ * // Follows the same group, and draws nothing while happy.
108
+ * {happy: null, sad: "tears.png"},
93
109
  * ],
94
- * defaults: ["happy", "shirt"],
110
+ * defaults: ["shirt", "happy"],
95
111
  * }
96
112
  * });
97
113
  * ```
@@ -1,4 +1,31 @@
1
- import { NameSpaceContent } from "../../elements/persistent/type";
1
+ import { NameSpaceContent, StorableType } from "../../elements/persistent/type";
2
+ import { EventDispatcher, EventToken } from "../../../../util/data";
3
+ /**
4
+ * One stored value changing. Reported by {@link Storable.onChange} after the new value is
5
+ * already readable through `getNamespace(namespace).get(key)`.
6
+ */
7
+ export type StorableChange<T extends StorableType = any> = {
8
+ /**
9
+ * The key the namespace is registered under in the {@link Storable} — the same string
10
+ * {@link Storable.getNamespace} takes, and the one a save file carries. For a namespace
11
+ * declared with `new Persistent("player", ...)` this is `"persistent:player"`.
12
+ */
13
+ namespace: string;
14
+ key: string;
15
+ /** The value that was there. `undefined` if the key had never been written. */
16
+ previous: T | undefined;
17
+ /** The value that is there now. `undefined` if the key was dropped (see {@link Namespace.reset}). */
18
+ next: T | undefined;
19
+ };
20
+ /**
21
+ * A bulk value application — a save being loaded, or a namespace being rewound to a
22
+ * snapshot. Reported by {@link Storable.onRestore} *instead of* per-key changes; see the
23
+ * note on {@link Namespace.deserialize}.
24
+ */
25
+ export type StorableRestore = {
26
+ /** The namespace keys whose contents were replaced. */
27
+ namespaces: string[];
28
+ };
2
29
  export declare class Namespace<T extends NameSpaceContent<keyof T>> {
3
30
  static isSerializable(value: any): boolean;
4
31
  name: string;
@@ -11,10 +38,25 @@ export declare class Namespace<T extends NameSpaceContent<keyof T>> {
11
38
  keys(): (keyof T)[];
12
39
  values(): T[keyof T][];
13
40
  entries(): [keyof T, T[keyof T]][];
41
+ /**
42
+ * Restore the author's defaults.
43
+ *
44
+ * Reports one change per key that actually moved. A key written after construction is
45
+ * not in the defaults, so it is dropped and reported as changing to `undefined`.
46
+ */
14
47
  reset(): this;
15
48
  }
16
49
  export declare class Storable {
50
+ static EventTypes: {
51
+ readonly "event:storable.change": "event:storable.change";
52
+ readonly "event:storable.restore": "event:storable.restore";
53
+ };
17
54
  static createNamespace<T extends NameSpaceContent<keyof T>>(name: string, initContent: T, key?: string): Namespace<T>;
55
+ /**
56
+ * Changes to any value in any registered namespace. Prefer {@link Storable.onChange},
57
+ * which filters by namespace and key.
58
+ */
59
+ readonly events: EventDispatcher<StorableEvents>;
18
60
  addNamespace<T extends NameSpaceContent<keyof T>>(namespace: Namespace<T>): this | undefined;
19
61
  getNamespace<T extends NameSpaceContent<keyof T> = any>(key: string): Namespace<T>;
20
62
  setNamespace<T extends NameSpaceContent<keyof T> = any>(key: string, namespace: Namespace<T>): this;
@@ -26,4 +68,45 @@ export declare class Storable {
26
68
  keys(): string[];
27
69
  values(): Namespace<any>[];
28
70
  entries(): [string, Namespace<any>][];
71
+ /**
72
+ * Listen for a stored value changing.
73
+ *
74
+ * The listener runs after the new value is readable, and only when the value actually
75
+ * moved — writing a value equal to the one already there reports nothing, so a line that
76
+ * re-asserts a flag every time it runs does not wake anything up. Equality is structural,
77
+ * so rebuilding an object with the same contents is also a no-op.
78
+ *
79
+ * Loading a save does not report changes; see {@link Storable.onRestore}.
80
+ *
81
+ * Subscriptions outlive the namespaces they watch: `newGame()` and loading a save both
82
+ * rebuild every namespace from scratch, and a listener registered here survives that.
83
+ *
84
+ * @example
85
+ * ```ts
86
+ * // every change, anywhere
87
+ * liveGame.getStorable().onChange(({namespace, key, previous, next}) => {...});
88
+ *
89
+ * // one namespace
90
+ * liveGame.getStorable().onChange("persistent:player", ({key, next}) => {...});
91
+ *
92
+ * // one key
93
+ * liveGame.getStorable().onChange("persistent:player", "gold", ({next}) => {
94
+ * if (next === 100) {...}
95
+ * });
96
+ * ```
97
+ * @returns a token whose `cancel()` removes the listener
98
+ */
99
+ onChange(listener: (change: StorableChange) => void): EventToken;
100
+ onChange(namespace: string, listener: (change: StorableChange) => void): EventToken;
101
+ onChange(namespace: string, key: string, listener: (change: StorableChange) => void): EventToken;
102
+ /**
103
+ * Listen for the store being replaced wholesale — loading a save, or rewinding a
104
+ * namespace to a snapshot. Fires once per bulk application, naming the namespaces
105
+ * involved, instead of the changes it implies.
106
+ *
107
+ * Re-read whatever you derive from the store when this fires.
108
+ *
109
+ * @returns a token whose `cancel()` removes the listener
110
+ */
111
+ onRestore(listener: (restore: StorableRestore) => void): EventToken;
29
112
  }