phaser-hooks 0.3.0 → 0.4.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/README.md CHANGED
@@ -1,3 +1,11 @@
1
+ <p align="center">
2
+ <img src="data/image.png" alt="logo" style="max-width: 300px">
3
+ </p>
4
+
5
+ [![NPM Version](https://img.shields.io/npm/v/phaser-wind)](https://www.npmjs.com/package/phaser-wind)
6
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
7
+ [![TypeScript](https://img.shields.io/badge/TypeScript-Ready-blue.svg)](https://www.typescriptlang.org/)
8
+
1
9
  # Phaser Hooks (like "use" hooks in React)
2
10
 
3
11
  A comprehensive state management library for Phaser games with React-like hooks pattern.
@@ -22,9 +30,14 @@ this.game.registry.events.on('changedata-volume', (game, value) => {
22
30
  // Using scene.data (local)
23
31
  this.data.set('score', 42); // too boring too
24
32
  const score = this.data.get('score');
25
- this.data.events.on('changedata-score', (scene, value) => {
33
+
34
+ const onChangeFn = (scene, value) => {
26
35
  console.log('Score updated to', value);
27
- });
36
+ };
37
+ this.data.events.on('changedata-score', onChangeFn); // If you pass an anonymous function, you cannot unsubscribe :(
38
+
39
+ // when move to another scene, you must unsubscribe. Boring and easy to forget
40
+ this.data.events.off('changeset-score', onChangeFn);
28
41
  ```
29
42
 
30
43
  With _phaser-hooks_, you get a simple, React-like API:
@@ -34,7 +47,13 @@ With _phaser-hooks_, you get a simple, React-like API:
34
47
  const volume = withGlobalState(scene, 'volume', 0.5); // woow! awesome
35
48
  volume.get(); // 0.5
36
49
  volume.set(0.8); // updates value
37
- volume.onChange(v => console.log('Volume changed →', v)); // Nice callback <3
50
+
51
+ const unsubscribe = volume.on('change', v =>
52
+ console.log('Volume changed →', v)
53
+ ); // Nice callback in event <3 - Return the easy unsubscribe function
54
+
55
+ // when move to another scene, just call :)
56
+ unsubscribe();
38
57
 
39
58
  // Persisted state (localStorage / sessionStorage)
40
59
  const score = withPersistState(scene, 'score', 0, { storage: 'local' }); // Wow! Saving in localStorage
@@ -59,6 +78,33 @@ Since this library is designed to work with Phaser games, which typically use pl
59
78
 
60
79
  This approach allows you to use these state management utilities in your Phaser games without having to modify your linting configuration or suppress warnings.
61
80
 
81
+ ## Hook API Reference
82
+
83
+ All hooks return a `HookState` object with the following methods:
84
+
85
+ | Method | Description | Parameters | Returns |
86
+ | -------------------------- | ---------------------------------------------------- | ----------------------------------------- | ----------------------------------- |
87
+ | `get()` | Gets the current state value | None | `T` - Current state value |
88
+ | `set(value)` | Sets a new state value and triggers change listeners | `value: T` - New value to set | `void` |
89
+ | `on('change', callback)` | Registers a callback for state changes | `event: 'change'`, `callback: () => void` | `() => void` - Unsubscribe function |
90
+ | `once('change', callback)` | Registers a callback that fires only once | `event: 'change'`, `callback: () => void` | `() => void` - Unsubscribe function |
91
+ | `off('change', callback)` | Removes an event listener | `event: 'change'`, `callback: () => void` | `void` |
92
+ | `clearListeners()` | Removes all event listeners for this state | None | `void` |
93
+
94
+ ### Special Hook Methods
95
+
96
+ Some hooks have additional methods beyond the standard `HookState` interface:
97
+
98
+ #### `withUndoableState` Additional Methods:
99
+
100
+ | Method | Description | Parameters | Returns |
101
+ | ---------------- | ----------------------------- | ---------- | -------------------------- |
102
+ | `undo()` | Reverts to the previous state | None | `boolean` - Success status |
103
+ | `redo()` | Advances to the next state | None | `boolean` - Success status |
104
+ | `canUndo()` | Checks if undo is available | None | `boolean` |
105
+ | `canRedo()` | Checks if redo is available | None | `boolean` |
106
+ | `clearHistory()` | Clears the undo/redo history | None | `void` |
107
+
62
108
  ## Available Hooks
63
109
 
64
110
  ### Core Hooks
@@ -68,6 +114,12 @@ This approach allows you to use these state management utilities in your Phaser
68
114
  Scene-specific state management that gets cleaned up when the scene is destroyed.
69
115
 
70
116
  ```typescript
117
+ type PlayerData = {
118
+ hp: number;
119
+ level: number;
120
+ exp: number;
121
+ };
122
+
71
123
  const playerState = withLocalState<PlayerData>(scene, 'player', {
72
124
  hp: 100,
73
125
  level: 1,
@@ -80,24 +132,17 @@ const playerState = withLocalState<PlayerData>(scene, 'player', {
80
132
  Application-wide state that persists across all scenes.
81
133
 
82
134
  ```typescript
135
+ type GameSettings = {
136
+ soundVolume: number;
137
+ musicEnabled: true;
138
+ };
139
+
83
140
  const settingsState = withGlobalState<GameSettings>(scene, 'settings', {
84
141
  soundVolume: 0.8,
85
142
  musicEnabled: true,
86
143
  });
87
144
  ```
88
145
 
89
- #### `withStateDef`
90
-
91
- Low-level state definition with custom behaviors and validation.
92
-
93
- ```typescript
94
- const customState = withStateDef<number>(scene, 'score', {
95
- initialValue: 0,
96
- validator: value => value >= 0,
97
- onChange: (newValue, oldValue) => console.log('Score changed!'),
98
- });
99
- ```
100
-
101
146
  ### Enhanced Hooks
102
147
 
103
148
  #### `withPersistentState`
@@ -105,6 +150,11 @@ const customState = withStateDef<number>(scene, 'score', {
105
150
  State with automatic localStorage persistence.
106
151
 
107
152
  ```typescript
153
+ type UserSettings = {
154
+ volume: number;
155
+ difficulty: 'easy' | 'normal' | 'hard';
156
+ };
157
+
108
158
  const persistentSettings = withPersistentState<UserSettings>(
109
159
  'settings',
110
160
  {
@@ -163,13 +213,40 @@ Pre-built validation functions for common patterns.
163
213
  ```typescript
164
214
  import { validators } from 'phaser-hooks';
165
215
 
166
- const scoreState = withGlobalState<number>('score', 0, {
216
+ // Number range validation (0-1000)
217
+ const scoreState = withGlobalState<number>(scene, 'score', 0, {
167
218
  validator: validators.numberRange(0, 1000),
168
219
  });
169
220
 
170
- const nameState = withGlobalState<string>('name', '', {
221
+ // Non-empty string validation
222
+ const nameState = withGlobalState<string>(scene, 'name', '', {
171
223
  validator: validators.nonEmptyString,
172
224
  });
225
+
226
+ // Array length validation (2-4 items)
227
+ const inventoryState = withLocalState<string[]>(scene, 'inventory', [], {
228
+ validator: validators.arrayLength(2, 4),
229
+ });
230
+
231
+ // One of allowed values validation
232
+ const difficultyState = withGlobalState<'easy' | 'normal' | 'hard'>(
233
+ scene,
234
+ 'difficulty',
235
+ 'normal',
236
+ {
237
+ validator: validators.oneOf(['easy', 'normal', 'hard']),
238
+ }
239
+ );
240
+
241
+ // Custom validator example
242
+ const healthState = withLocalState<number>(scene, 'health', 100, {
243
+ validator: value => {
244
+ const health = value as number;
245
+ if (health < 0) return 'Health cannot be negative';
246
+ if (health > 100) return 'Health cannot exceed 100';
247
+ return true; // Valid
248
+ },
249
+ });
173
250
  ```
174
251
 
175
252
  #### `batchStateUpdates`
@@ -211,7 +288,7 @@ export class GameScene extends Phaser.Scene {
211
288
  );
212
289
 
213
290
  // Listen to changes
214
- playerState.onChange((newPlayer, oldPlayer) => {
291
+ const ubsubscribe = playerState.on('change', (newPlayer, oldPlayer) => {
215
292
  console.log('Player health changed:', newPlayer.hp);
216
293
  });
217
294
 
@@ -313,8 +390,7 @@ function withPlayerEnergy(scene: Phaser.Scene) {
313
390
  return {
314
391
  get: () => player.get().energy,
315
392
  set: (value: number) => player.set({ ...player.get(), energy: value }),
316
- onChange: (fn: (energy: number) => void) =>
317
- player.onChange(newVal => fn(newVal.energy)),
393
+ ...player,
318
394
  };
319
395
  }
320
396
  ```
@@ -328,13 +404,281 @@ console.log('Current energy:', energy.get());
328
404
 
329
405
  energy.set(energy.get() - 10);
330
406
 
331
- energy.onChange(newEnergy => {
332
- if (newEnergy <= 0) {
407
+ energy.on('change', () => {
408
+ if (energy.get() <= 0) {
333
409
  console.warn('You are out of energy!');
334
410
  }
335
411
  });
336
412
  ```
337
413
 
414
+ ## Unsubscribe Events
415
+
416
+ When you subscribe to state changes using `.on('change', callback)`, it's crucial to properly unsubscribe to prevent memory leaks and unexpected behavior. Phaser Hooks provides two ways for unsubscribing from events.
417
+
418
+ ### Method 1: Using the Return Value from `.on('change')`
419
+
420
+ The `.on('change', callback)` method returns an unsubscribe function that you can call to remove the listener:
421
+
422
+ ```typescript
423
+ export class GameScene extends Phaser.Scene {
424
+ create() {
425
+ const playerState = withLocalState<{ hp: number }>(this, 'player', {
426
+ hp: 100,
427
+ });
428
+
429
+ // Subscribe to changes and get unsubscribe function
430
+ const unsubscribe = playerState.on('change', (newPlayer, oldPlayer) => {
431
+ console.log('Player health changed:', newPlayer.hp);
432
+ });
433
+
434
+ this.add
435
+ .text(centerX, centerY, 'Go to another scene')
436
+ .setInteractive()
437
+ .on('pointerdown', () => {
438
+ // Later, unsubscribe when needed
439
+ unsubscribe();
440
+
441
+ // To switch to another scene in Phaser, use:
442
+ this.scene.start('OtherSceneKey');
443
+ });
444
+ }
445
+ }
446
+ ```
447
+
448
+ ### Method 2: Using `.off('change', callback)`
449
+
450
+ You can also unsubscribe by passing the same callback function to `.off('change', callback)`:
451
+
452
+ ```typescript
453
+ export class GameScene extends Phaser.Scene {
454
+ private healthCallback?: (newPlayer: any, oldPlayer: any) => void;
455
+
456
+ create() {
457
+ const playerState = withLocalState<{ hp: number }>(this, 'player', {
458
+ hp: 100,
459
+ });
460
+
461
+ // Define callback function
462
+ this.healthCallback = (newPlayer, oldPlayer) => {
463
+ console.log('Player health changed:', newPlayer.hp);
464
+ };
465
+
466
+ // Subscribe to changes
467
+ playerState.on('change', this.healthCallback);
468
+
469
+ this.add
470
+ .text(centerX, centerY, 'Go to another scene')
471
+ .setInteractive()
472
+ .on('pointerdown', () => {
473
+ // Later, unsubscribe when needed
474
+ playerState.off('change', this.healthCallback);
475
+
476
+ // To switch to another scene in Phaser, use:
477
+ this.scene.start('OtherSceneKey');
478
+ });
479
+ }
480
+ }
481
+ ```
482
+
483
+ > **Note:** When using `.off`, you must pass the exact same function instance that was used with `.on`. This means you cannot use an inline closure or anonymous function—use a named function or store the callback reference to unsubscribe properly.
484
+
485
+ ### Best Practices for Scene Cleanup
486
+
487
+ **⚠️ IMPORTANT DISCLAIMER**: If you don't clean up event listeners when leaving a scene, you may encounter:
488
+
489
+ - Memory leaks
490
+ - Unexpected behavior when returning to the scene
491
+ - Callbacks firing on destroyed or inactive scenes
492
+ - Performance issues over time
493
+
494
+ Always unsubscribe from events when transitioning between scenes:
495
+
496
+ ```typescript
497
+ export class GameScene extends Phaser.Scene {
498
+ private unsubscribeFunctions: (() => void)[] = [];
499
+
500
+ create() {
501
+ const playerState = withLocalState<{ hp: number }>(this, 'player', {
502
+ hp: 100,
503
+ });
504
+ const scoreState = withGlobalState<number>(this, 'score', 0);
505
+
506
+ // Store unsubscribe functions
507
+ this.unsubscribeFunctions.push(
508
+ playerState.on('change', newPlayer => {
509
+ console.log('Player updated:', newPlayer);
510
+ })
511
+ );
512
+
513
+ this.unsubscribeFunctions.push(
514
+ scoreState.on('change', newScore => {
515
+ console.log('Score updated:', newScore);
516
+ })
517
+ );
518
+ }
519
+
520
+ // Clean up when scene is destroyed or when transitioning
521
+ shutdown() {
522
+ // Unsubscribe from all events
523
+ this.unsubscribeFunctions.forEach(unsubscribe => unsubscribe());
524
+ this.unsubscribeFunctions = [];
525
+ }
526
+
527
+ // Or clean up before transitioning to another scene
528
+ goToNextScene() {
529
+ // Clean up before changing scenes
530
+ this.unsubscribeFunctions.forEach(unsubscribe => unsubscribe());
531
+ this.unsubscribeFunctions = [];
532
+
533
+ // Then transition
534
+ this.scene.start('NextScene');
535
+ }
536
+ }
537
+ ```
538
+
539
+ ### Using `clearListeners()` for Easy Cleanup
540
+
541
+ For easier cleanup, you can use the `clearListeners()` method to remove all event listeners at once:
542
+
543
+ ```typescript
544
+ export class GameScene extends Phaser.Scene {
545
+ private playerState: HookState<{ hp: number }>;
546
+ private scoreState: HookState<number>;
547
+
548
+ create() {
549
+ this.playerState = withLocalState<{ hp: number }>(this, 'player', { hp: 100 });
550
+ this.scoreState = withGlobalState<number>(this, 'score', 0);
551
+
552
+ // Add listeners
553
+ this.playerState.on('change', (newPlayer) => {
554
+ console.log('Player updated:', newPlayer);
555
+ });
556
+
557
+ this.scoreState.on('change', (newScore) => {
558
+ console.log('Score updated:', newScore);
559
+ });
560
+ }
561
+
562
+ shutdown() {
563
+ // Clear all listeners at once - much easier!
564
+ this.playerState.clearListeners();
565
+ this.scoreState.clearListeners();
566
+ }
567
+ }
568
+ ```
569
+
570
+ #### Important Notes about `clearListeners()`:
571
+
572
+ - **`withLocalState`**: Automatically cleans up when the scene is destroyed, but you can still use `clearListeners()` for manual cleanup
573
+ - **`withGlobalState`**: **Requires manual cleanup** since global state persists across scenes. Always call `clearListeners()` when the scene is destroyed:
574
+
575
+ ```typescript
576
+ export class GameScene extends Phaser.Scene {
577
+ private globalState: HookState<GameSettings>;
578
+
579
+ create() {
580
+ this.globalState = withGlobalState<GameSettings>(this, 'settings', defaultSettings);
581
+
582
+ this.globalState.on('change', (newSettings) => {
583
+ console.log('Settings updated:', newSettings);
584
+ });
585
+
586
+ // IMPORTANT: Clean up global state listeners when scene is destroyed
587
+ this.events.once('destroy', () => {
588
+ this.globalState.clearListeners();
589
+ });
590
+ }
591
+ }
592
+ ```
593
+
594
+ ### Multiple Subscriptions Example
595
+
596
+ You can have multiple listeners for the same state:
597
+
598
+ ```typescript
599
+ export class GameScene extends Phaser.Scene {
600
+ create() {
601
+ const playerState = withLocalState<{ hp: number; level: number }>(
602
+ this,
603
+ 'player',
604
+ {
605
+ hp: 100,
606
+ level: 1,
607
+ }
608
+ );
609
+
610
+ // Multiple listeners for the same state
611
+ const unsubscribeHealth = playerState.on('change', newPlayer => {
612
+ console.log('Health changed:', newPlayer.hp);
613
+ });
614
+
615
+ const unsubscribeLevel = playerState.on('change', newPlayer => {
616
+ console.log('Level changed:', newPlayer.level);
617
+ });
618
+
619
+ // Unsubscribe specific listeners
620
+ unsubscribeHealth(); // Only removes health listener
621
+ // unsubscribeLevel still active
622
+ }
623
+ }
624
+ ```
625
+
626
+ ### Using `.once()` for One-Time Events
627
+
628
+ The `.once()` method registers a callback that will only fire once, then automatically unsubscribes:
629
+
630
+ ```typescript
631
+ export class GameScene extends Phaser.Scene {
632
+ create() {
633
+ const playerState = withLocalState<{ hp: number; level: number }>(
634
+ this,
635
+ 'player',
636
+ {
637
+ hp: 100,
638
+ level: 1,
639
+ }
640
+ );
641
+
642
+ // One-time listener - fires only once then auto-unsubscribes
643
+ const unsubscribeOnce = playerState.once('change', newPlayer => {
644
+ console.log('First level up detected!', newPlayer.level);
645
+ // This callback will only run once, even if the state changes multiple times
646
+ });
647
+
648
+ // You can still manually unsubscribe if needed before it fires
649
+ // unsubscribeOnce();
650
+
651
+ // Simulate level up
652
+ playerState.set({ hp: 100, level: 2 }); // Fires the once callback
653
+ playerState.set({ hp: 100, level: 3 }); // Won't fire the once callback again
654
+ }
655
+ }
656
+ ```
657
+
658
+ ### Validation Error Handling
659
+
660
+ When using validators, invalid values will throw errors. Handle them appropriately:
661
+
662
+ ```typescript
663
+ export class GameScene extends Phaser.Scene {
664
+ create() {
665
+ const healthState = withLocalState<number>(this, 'health', 100, {
666
+ validator: validators.numberRange(0, 100),
667
+ });
668
+
669
+ try {
670
+ healthState.set(150); // This will throw an error: "Value must be between 0 and 100"
671
+ } catch (error) {
672
+ console.error('Invalid health value:', error.message);
673
+ // Handle the error appropriately
674
+ }
675
+
676
+ // Valid value
677
+ healthState.set(75); // This works fine
678
+ }
679
+ }
680
+ ```
681
+
338
682
  ### Why use this pattern?
339
683
 
340
684
  ✅ Keeps your scene code focused on intent (e.g., energy.get()) rather than structure (player.get().energy)
@@ -368,6 +712,105 @@ const playerState = withLocalState<PlayerData>(scene, 'player', {
368
712
  const currentPlayer: PlayerData = playerState.get();
369
713
  ```
370
714
 
715
+ ## Debug Mode / Dev tool
716
+
717
+ Phaser Hooks includes a built-in debug mode that provides detailed logging for state operations. This is extremely useful for development and troubleshooting state management issues.
718
+
719
+ ### How to Enable Debug Mode
720
+
721
+ To enable debug mode, simply pass `{ debug: true }` in the options parameter when creating any hook:
722
+
723
+ ```typescript
724
+ import { withLocalState } from 'phaser-hooks';
725
+
726
+ export class GameScene extends Phaser.Scene {
727
+ create() {
728
+ // Enable debug mode for this state
729
+ const playerState = withLocalState<{ hp: number; level: number }>(
730
+ this,
731
+ 'player',
732
+ {
733
+ hp: 100,
734
+ level: 1,
735
+ },
736
+ { debug: true } // Enable debug logging
737
+ );
738
+
739
+ // All operations will now be logged to the console
740
+ playerState.set({ hp: 90, level: 2 });
741
+ const currentPlayer = playerState.get();
742
+
743
+ // Listen to changes with debug info
744
+ playerState.on('change', (newPlayer, oldPlayer) => {
745
+ console.log('Player state changed:', newPlayer);
746
+ });
747
+ }
748
+ }
749
+ ```
750
+
751
+ ### What Debug Mode Shows
752
+
753
+ When debug mode is enabled, you'll see detailed logs in your browser's developer console for:
754
+
755
+ - **State Initialization**: When a state is first created
756
+ - **State Updates**: When values are set with old and new values
757
+ - **State Retrieval**: When values are accessed
758
+ - **Event Listeners**: When listeners are added, removed, or cleared
759
+ - **Validation**: When validators are applied and their results
760
+ - **Errors**: Detailed error information with context
761
+
762
+ ### Viewing Debug Logs
763
+
764
+ Debug logs appear in your browser's developer console. To view them:
765
+
766
+ 1. Open your browser's Developer Tools (F12 or right-click → Inspect)
767
+ 2. Go to the **Console** tab
768
+ 3. Run your Phaser game
769
+ 4. Look for logs prefixed with `[phaser-hooks]`
770
+
771
+ ![Debug Console Screenshot](data/debug-mode.png)
772
+ *Screenshot showing debug logs in browser console*
773
+
774
+ ### Debug Log Format
775
+
776
+ Debug logs follow a consistent format with timestamps and structured information:
777
+
778
+ ```
779
+ [phaser-hooks] 2024-01-15 10:30:45 [INIT] player - Initializing state with value: {hp: 100, level: 1}
780
+ [phaser-hooks] 2024-01-15 10:30:46 [SET] player - Updating state: {hp: 90, level: 2} (was: {hp: 100, level: 1})
781
+ [phaser-hooks] 2024-01-15 10:30:47 [GET] player - Retrieved state: {hp: 90, level: 2}
782
+ [phaser-hooks] 2024-01-15 10:30:48 [EVENT] player - Added change listener
783
+ ```
784
+
785
+ ### Best Practices for Debug Mode
786
+
787
+ - **Development Only**: Only enable debug mode during development. Remove `{ debug: true }` in production builds
788
+ - **Selective Debugging**: Enable debug mode only for the specific states you're troubleshooting
789
+ - **Performance**: Debug mode adds overhead, so avoid enabling it for all states in production
790
+ - **Console Filtering**: Use browser console filters to focus on specific log types
791
+
792
+ ### Example: Debugging State Issues
793
+
794
+ ```typescript
795
+ export class DebugScene extends Phaser.Scene {
796
+ create() {
797
+ // Enable debug for problematic state
798
+ const inventoryState = withLocalState<string[]>(
799
+ this,
800
+ 'inventory',
801
+ [],
802
+ { debug: true }
803
+ );
804
+
805
+ // Debug logs will show exactly what's happening
806
+ inventoryState.set(['sword', 'potion']);
807
+ inventoryState.set([...inventoryState.get(), 'shield']);
808
+
809
+ // Check console for detailed operation logs
810
+ }
811
+ }
812
+ ```
813
+
371
814
  ## License
372
815
 
373
816
  MIT
@@ -71,5 +71,9 @@ export type HookState<T> = {
71
71
  * @param callback The callback to remove
72
72
  */
73
73
  off: (event: 'change', callback: () => void) => void;
74
+ /**
75
+ * Removes all event listeners for this state
76
+ */
77
+ clearListeners: () => void;
74
78
  };
75
79
  //# sourceMappingURL=type.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"type.d.ts","sourceRoot":"","sources":["../../src/hooks/type.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,MAAM,MAAM,mBAAmB,CAAC,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC,EAAE,QAAQ,EAAE,CAAC,KAAK,IAAI,CAAC;AAExE;;;;GAIG;AACH,MAAM,MAAM,aAAa,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC,KAAK,CAAC,CAAC;AAElD;;;GAGG;AACH,MAAM,MAAM,YAAY,CAAC,CAAC,IAAI,CAAC,YAAY,EAAE,CAAC,KAAK,CAAC,CAAC;AAErD;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,MAAM,MAAM,SAAS,CAAC,CAAC,IAAI;IACzB;;;OAGG;IACH,GAAG,EAAE,MAAM,CAAC,CAAC;IAEb;;;OAGG;IACH,GAAG,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,IAAI,CAAC;IAExB;;;OAGG;IACH,QAAQ,EAAE,CAAC,QAAQ,EAAE,mBAAmB,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC;IAErD;;;OAGG;IACH,EAAE,EAAE,CAAC,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,IAAI,KAAK,MAAM,IAAI,CAAC;IAE1D;;;OAGG;IACH,IAAI,EAAE,CAAC,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,IAAI,KAAK,MAAM,IAAI,CAAC;IAE5D;;;;OAIG;IACH,GAAG,EAAE,CAAC,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,IAAI,KAAK,IAAI,CAAC;CACtD,CAAC"}
1
+ {"version":3,"file":"type.d.ts","sourceRoot":"","sources":["../../src/hooks/type.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,MAAM,MAAM,mBAAmB,CAAC,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC,EAAE,QAAQ,EAAE,CAAC,KAAK,IAAI,CAAC;AAExE;;;;GAIG;AACH,MAAM,MAAM,aAAa,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC,KAAK,CAAC,CAAC;AAElD;;;GAGG;AACH,MAAM,MAAM,YAAY,CAAC,CAAC,IAAI,CAAC,YAAY,EAAE,CAAC,KAAK,CAAC,CAAC;AAErD;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,MAAM,MAAM,SAAS,CAAC,CAAC,IAAI;IACzB;;;OAGG;IACH,GAAG,EAAE,MAAM,CAAC,CAAC;IAEb;;;OAGG;IACH,GAAG,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,IAAI,CAAC;IAExB;;;OAGG;IACH,QAAQ,EAAE,CAAC,QAAQ,EAAE,mBAAmB,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC;IAErD;;;OAGG;IACH,EAAE,EAAE,CAAC,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,IAAI,KAAK,MAAM,IAAI,CAAC;IAE1D;;;OAGG;IACH,IAAI,EAAE,CAAC,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,IAAI,KAAK,MAAM,IAAI,CAAC;IAE5D;;;;OAIG;IACH,GAAG,EAAE,CAAC,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,IAAI,KAAK,IAAI,CAAC;IAErD;;OAEG;IACH,cAAc,EAAE,MAAM,IAAI,CAAC;CAC5B,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"with-computed-state.d.ts","sourceRoot":"","sources":["../../src/hooks/with-computed-state.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,SAAS,EAAE,KAAK,aAAa,EAAE,MAAM,QAAQ,CAAC;AAG5D;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,eAAO,MAAM,iBAAiB,GAAI,CAAC,EAAE,CAAC,EACpC,OAAO,MAAM,CAAC,KAAK,EACnB,KAAK,MAAM,EACX,aAAa,SAAS,CAAC,CAAC,CAAC,EACzB,UAAU,aAAa,CAAC,CAAC,EAAE,CAAC,CAAC,KAC5B,SAAS,CAAC,CAAC,CAwBb,CAAC"}
1
+ {"version":3,"file":"with-computed-state.d.ts","sourceRoot":"","sources":["../../src/hooks/with-computed-state.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,SAAS,EAAE,KAAK,aAAa,EAAE,MAAM,QAAQ,CAAC;AAG5D;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,eAAO,MAAM,iBAAiB,GAAI,CAAC,EAAE,CAAC,EACpC,OAAO,MAAM,CAAC,KAAK,EACnB,KAAK,MAAM,EACX,aAAa,SAAS,CAAC,CAAC,CAAC,EACzB,UAAU,aAAa,CAAC,CAAC,EAAE,CAAC,CAAC,KAC5B,SAAS,CAAC,CAAC,CAoBb,CAAC"}
@@ -31,14 +31,10 @@ export const withComputedState = (scene, key, sourceState, selector) => {
31
31
  computedState.set(newComputedValue);
32
32
  });
33
33
  return {
34
- get: computedState.get,
34
+ ...computedState,
35
35
  set: () => {
36
36
  throw new Error(`[withComputedState] Cannot directly set computed state "${key}". Update the source state instead.`);
37
37
  },
38
- onChange: computedState.onChange,
39
- on: computedState.on,
40
- once: computedState.once,
41
- off: computedState.off,
42
38
  };
43
39
  };
44
40
  //# sourceMappingURL=with-computed-state.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"with-computed-state.js","sourceRoot":"","sources":["../../src/hooks/with-computed-state.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAEpD;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAC/B,KAAmB,EACnB,GAAW,EACX,WAAyB,EACzB,QAA6B,EACf,EAAE;IAChB,iCAAiC;IACjC,MAAM,YAAY,GAAG,QAAQ,CAAC,WAAW,CAAC,GAAG,EAAE,CAAC,CAAC;IACjD,MAAM,aAAa,GAAG,cAAc,CAAI,KAAK,EAAE,GAAG,EAAE,YAAY,CAAC,CAAC;IAElE,4CAA4C;IAC5C,WAAW,CAAC,EAAE,CAAC,QAAQ,EAAE,GAAG,EAAE;QAC5B,MAAM,cAAc,GAAG,WAAW,CAAC,GAAG,EAAE,CAAC;QACzC,MAAM,gBAAgB,GAAG,QAAQ,CAAC,cAAc,CAAC,CAAC;QAClD,aAAa,CAAC,GAAG,CAAC,gBAAgB,CAAC,CAAC;IACtC,CAAC,CAAC,CAAC;IAEH,OAAO;QACL,GAAG,EAAE,aAAa,CAAC,GAAG;QACtB,GAAG,EAAE,GAAS,EAAE;YACd,MAAM,IAAI,KAAK,CACb,2DAA2D,GAAG,qCAAqC,CACpG,CAAC;QACJ,CAAC;QACD,QAAQ,EAAE,aAAa,CAAC,QAAQ;QAChC,EAAE,EAAE,aAAa,CAAC,EAAE;QACpB,IAAI,EAAE,aAAa,CAAC,IAAI;QACxB,GAAG,EAAE,aAAa,CAAC,GAAG;KACvB,CAAC;AACJ,CAAC,CAAC"}
1
+ {"version":3,"file":"with-computed-state.js","sourceRoot":"","sources":["../../src/hooks/with-computed-state.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAEpD;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAC/B,KAAmB,EACnB,GAAW,EACX,WAAyB,EACzB,QAA6B,EACf,EAAE;IAChB,iCAAiC;IACjC,MAAM,YAAY,GAAG,QAAQ,CAAC,WAAW,CAAC,GAAG,EAAE,CAAC,CAAC;IACjD,MAAM,aAAa,GAAG,cAAc,CAAI,KAAK,EAAE,GAAG,EAAE,YAAY,CAAC,CAAC;IAElE,4CAA4C;IAC5C,WAAW,CAAC,EAAE,CAAC,QAAQ,EAAE,GAAG,EAAE;QAC5B,MAAM,cAAc,GAAG,WAAW,CAAC,GAAG,EAAE,CAAC;QACzC,MAAM,gBAAgB,GAAG,QAAQ,CAAC,cAAc,CAAC,CAAC;QAClD,aAAa,CAAC,GAAG,CAAC,gBAAgB,CAAC,CAAC;IACtC,CAAC,CAAC,CAAC;IAEH,OAAO;QACL,GAAG,aAAa;QAChB,GAAG,EAAE,GAAS,EAAE;YACd,MAAM,IAAI,KAAK,CACb,2DAA2D,GAAG,qCAAqC,CACpG,CAAC;QACJ,CAAC;KACF,CAAC;AACJ,CAAC,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"with-debounced-state.d.ts","sourceRoot":"","sources":["../../src/hooks/with-debounced-state.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,SAAS,EAAE,MAAM,QAAQ,CAAC;AAGxC;;;;;;;;;;;;;;;;;;GAkBG;AACH,eAAO,MAAM,kBAAkB,GAAI,CAAC,EAClC,OAAO,MAAM,CAAC,KAAK,EACnB,KAAK,MAAM,EACX,cAAc,CAAC,EACf,YAAY,MAAM,KACjB,SAAS,CAAC,CAAC,CAuBb,CAAC"}
1
+ {"version":3,"file":"with-debounced-state.d.ts","sourceRoot":"","sources":["../../src/hooks/with-debounced-state.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,SAAS,EAAE,MAAM,QAAQ,CAAC;AAGxC;;;;;;;;;;;;;;;;;;GAkBG;AACH,eAAO,MAAM,kBAAkB,GAAI,CAAC,EAClC,OAAO,MAAM,CAAC,KAAK,EACnB,KAAK,MAAM,EACX,cAAc,CAAC,EACf,YAAY,MAAM,KACjB,SAAS,CAAC,CAAC,CAmBb,CAAC"}
@@ -31,12 +31,8 @@ export const withDebouncedState = (scene, key, initialValue, debounceMs) => {
31
31
  }, debounceMs);
32
32
  };
33
33
  return {
34
- get: actualState.get,
34
+ ...actualState,
35
35
  set: debouncedSet,
36
- onChange: actualState.onChange,
37
- on: actualState.on,
38
- once: actualState.once,
39
- off: actualState.off,
40
36
  };
41
37
  };
42
38
  //# sourceMappingURL=with-debounced-state.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"with-debounced-state.js","sourceRoot":"","sources":["../../src/hooks/with-debounced-state.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAEpD;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAChC,KAAmB,EACnB,GAAW,EACX,YAAe,EACf,UAAkB,EACJ,EAAE;IAChB,MAAM,WAAW,GAAG,cAAc,CAAI,KAAK,EAAE,GAAG,EAAE,YAAY,CAAC,CAAC;IAChE,IAAI,SAAS,GAAyC,IAAI,CAAC;IAE3D,MAAM,YAAY,GAAG,CAAC,KAAQ,EAAQ,EAAE;QACtC,IAAI,SAAS,EAAE,CAAC;YACd,YAAY,CAAC,SAAS,CAAC,CAAC;QAC1B,CAAC;QAED,SAAS,GAAG,UAAU,CAAC,GAAG,EAAE;YAC1B,WAAW,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;YACvB,SAAS,GAAG,IAAI,CAAC;QACnB,CAAC,EAAE,UAAU,CAAC,CAAC;IACjB,CAAC,CAAC;IAEF,OAAO;QACL,GAAG,EAAE,WAAW,CAAC,GAAG;QACpB,GAAG,EAAE,YAAY;QACjB,QAAQ,EAAE,WAAW,CAAC,QAAQ;QAC9B,EAAE,EAAE,WAAW,CAAC,EAAE;QAClB,IAAI,EAAE,WAAW,CAAC,IAAI;QACtB,GAAG,EAAE,WAAW,CAAC,GAAG;KACrB,CAAC;AACJ,CAAC,CAAC"}
1
+ {"version":3,"file":"with-debounced-state.js","sourceRoot":"","sources":["../../src/hooks/with-debounced-state.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAEpD;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAChC,KAAmB,EACnB,GAAW,EACX,YAAe,EACf,UAAkB,EACJ,EAAE;IAChB,MAAM,WAAW,GAAG,cAAc,CAAI,KAAK,EAAE,GAAG,EAAE,YAAY,CAAC,CAAC;IAChE,IAAI,SAAS,GAAyC,IAAI,CAAC;IAE3D,MAAM,YAAY,GAAG,CAAC,KAAQ,EAAQ,EAAE;QACtC,IAAI,SAAS,EAAE,CAAC;YACd,YAAY,CAAC,SAAS,CAAC,CAAC;QAC1B,CAAC;QAED,SAAS,GAAG,UAAU,CAAC,GAAG,EAAE;YAC1B,WAAW,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;YACvB,SAAS,GAAG,IAAI,CAAC;QACnB,CAAC,EAAE,UAAU,CAAC,CAAC;IACjB,CAAC,CAAC;IAEF,OAAO;QACL,GAAG,WAAW;QACd,GAAG,EAAE,YAAY;KAClB,CAAC;AACJ,CAAC,CAAC"}