canvasengine 2.0.0-beta.5 → 2.0.0-beta.50

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.
Files changed (172) hide show
  1. package/dist/components/Button.d.ts +185 -0
  2. package/dist/components/Button.d.ts.map +1 -0
  3. package/dist/components/Canvas.d.ts +17 -0
  4. package/dist/components/Canvas.d.ts.map +1 -0
  5. package/dist/components/Container.d.ts +86 -0
  6. package/dist/components/Container.d.ts.map +1 -0
  7. package/dist/components/DOMContainer.d.ts +98 -0
  8. package/dist/components/DOMContainer.d.ts.map +1 -0
  9. package/dist/components/DOMElement.d.ts +54 -0
  10. package/dist/components/DOMElement.d.ts.map +1 -0
  11. package/dist/components/DOMSprite.d.ts +127 -0
  12. package/dist/components/DOMSprite.d.ts.map +1 -0
  13. package/dist/components/DisplayObject.d.ts +94 -0
  14. package/dist/components/DisplayObject.d.ts.map +1 -0
  15. package/dist/components/FocusContainer.d.ts +129 -0
  16. package/dist/components/FocusContainer.d.ts.map +1 -0
  17. package/dist/components/Graphic.d.ts +64 -0
  18. package/dist/components/Graphic.d.ts.map +1 -0
  19. package/dist/components/Joystick.d.ts +36 -0
  20. package/dist/components/Joystick.d.ts.map +1 -0
  21. package/dist/components/Mesh.d.ts +208 -0
  22. package/dist/components/Mesh.d.ts.map +1 -0
  23. package/dist/components/NineSliceSprite.d.ts +16 -0
  24. package/dist/components/NineSliceSprite.d.ts.map +1 -0
  25. package/dist/components/ParticleEmitter.d.ts +4 -0
  26. package/dist/components/ParticleEmitter.d.ts.map +1 -0
  27. package/dist/components/Scene.d.ts +2 -0
  28. package/dist/components/Scene.d.ts.map +1 -0
  29. package/dist/components/Sprite.d.ts +242 -0
  30. package/dist/components/Sprite.d.ts.map +1 -0
  31. package/dist/components/Text.d.ts +25 -0
  32. package/dist/components/Text.d.ts.map +1 -0
  33. package/dist/components/TilingSprite.d.ts +17 -0
  34. package/dist/components/TilingSprite.d.ts.map +1 -0
  35. package/dist/components/Video.d.ts +14 -0
  36. package/dist/components/Video.d.ts.map +1 -0
  37. package/dist/components/Viewport.d.ts +121 -0
  38. package/dist/components/Viewport.d.ts.map +1 -0
  39. package/dist/components/index.d.ts +20 -0
  40. package/dist/components/index.d.ts.map +1 -0
  41. package/dist/components/types/DisplayObject.d.ts +106 -0
  42. package/dist/components/types/DisplayObject.d.ts.map +1 -0
  43. package/dist/components/types/MouseEvent.d.ts +4 -0
  44. package/dist/components/types/MouseEvent.d.ts.map +1 -0
  45. package/dist/components/types/Spritesheet.d.ts +248 -0
  46. package/dist/components/types/Spritesheet.d.ts.map +1 -0
  47. package/dist/components/types/index.d.ts +4 -0
  48. package/dist/components/types/index.d.ts.map +1 -0
  49. package/dist/directives/Controls.d.ts +112 -0
  50. package/dist/directives/Controls.d.ts.map +1 -0
  51. package/dist/directives/ControlsBase.d.ts +199 -0
  52. package/dist/directives/ControlsBase.d.ts.map +1 -0
  53. package/dist/directives/Drag.d.ts +69 -0
  54. package/dist/directives/Drag.d.ts.map +1 -0
  55. package/dist/directives/Flash.d.ts +116 -0
  56. package/dist/directives/Flash.d.ts.map +1 -0
  57. package/dist/directives/FocusNavigation.d.ts +52 -0
  58. package/dist/directives/FocusNavigation.d.ts.map +1 -0
  59. package/dist/directives/GamepadControls.d.ts +224 -0
  60. package/dist/directives/GamepadControls.d.ts.map +1 -0
  61. package/dist/directives/JoystickControls.d.ts +171 -0
  62. package/dist/directives/JoystickControls.d.ts.map +1 -0
  63. package/dist/directives/KeyboardControls.d.ts +219 -0
  64. package/dist/directives/KeyboardControls.d.ts.map +1 -0
  65. package/dist/directives/Scheduler.d.ts +35 -0
  66. package/dist/directives/Scheduler.d.ts.map +1 -0
  67. package/dist/directives/Shake.d.ts +98 -0
  68. package/dist/directives/Shake.d.ts.map +1 -0
  69. package/dist/directives/Sound.d.ts +25 -0
  70. package/dist/directives/Sound.d.ts.map +1 -0
  71. package/dist/directives/Transition.d.ts +10 -0
  72. package/dist/directives/Transition.d.ts.map +1 -0
  73. package/dist/directives/ViewportCull.d.ts +11 -0
  74. package/dist/directives/ViewportCull.d.ts.map +1 -0
  75. package/dist/directives/ViewportFollow.d.ts +18 -0
  76. package/dist/directives/ViewportFollow.d.ts.map +1 -0
  77. package/dist/directives/index.d.ts +13 -0
  78. package/dist/directives/index.d.ts.map +1 -0
  79. package/dist/engine/FocusManager.d.ts +174 -0
  80. package/dist/engine/FocusManager.d.ts.map +1 -0
  81. package/dist/engine/animation.d.ts +72 -0
  82. package/dist/engine/animation.d.ts.map +1 -0
  83. package/dist/engine/bootstrap.d.ts +48 -0
  84. package/dist/engine/bootstrap.d.ts.map +1 -0
  85. package/dist/engine/directive.d.ts +13 -0
  86. package/dist/engine/directive.d.ts.map +1 -0
  87. package/dist/engine/reactive.d.ts +134 -0
  88. package/dist/engine/reactive.d.ts.map +1 -0
  89. package/dist/engine/signal.d.ts +71 -0
  90. package/dist/engine/signal.d.ts.map +1 -0
  91. package/dist/engine/trigger.d.ts +54 -0
  92. package/dist/engine/trigger.d.ts.map +1 -0
  93. package/dist/engine/utils.d.ts +89 -0
  94. package/dist/engine/utils.d.ts.map +1 -0
  95. package/dist/hooks/addContext.d.ts +2 -0
  96. package/dist/hooks/addContext.d.ts.map +1 -0
  97. package/dist/hooks/useFocus.d.ts +60 -0
  98. package/dist/hooks/useFocus.d.ts.map +1 -0
  99. package/dist/hooks/useProps.d.ts +42 -0
  100. package/dist/hooks/useProps.d.ts.map +1 -0
  101. package/dist/hooks/useRef.d.ts +4 -0
  102. package/dist/hooks/useRef.d.ts.map +1 -0
  103. package/dist/index-DaGekQUW.js +2218 -0
  104. package/dist/index-DaGekQUW.js.map +1 -0
  105. package/dist/index.d.ts +19 -1099
  106. package/dist/index.d.ts.map +1 -0
  107. package/dist/index.global.js +5 -0
  108. package/dist/index.global.js.map +1 -0
  109. package/dist/index.js +11749 -2901
  110. package/dist/index.js.map +1 -1
  111. package/dist/utils/Ease.d.ts +17 -0
  112. package/dist/utils/Ease.d.ts.map +1 -0
  113. package/dist/utils/GlobalAssetLoader.d.ts +141 -0
  114. package/dist/utils/GlobalAssetLoader.d.ts.map +1 -0
  115. package/dist/utils/RadialGradient.d.ts +57 -0
  116. package/dist/utils/RadialGradient.d.ts.map +1 -0
  117. package/dist/utils/functions.d.ts +2 -0
  118. package/dist/utils/functions.d.ts.map +1 -0
  119. package/dist/utils/tabindex.d.ts +16 -0
  120. package/dist/utils/tabindex.d.ts.map +1 -0
  121. package/package.json +13 -7
  122. package/src/components/Button.ts +399 -0
  123. package/src/components/Canvas.ts +62 -46
  124. package/src/components/Container.ts +21 -2
  125. package/src/components/DOMContainer.ts +379 -0
  126. package/src/components/DOMElement.ts +556 -0
  127. package/src/components/DOMSprite.ts +1040 -0
  128. package/src/components/DisplayObject.ts +392 -201
  129. package/src/components/FocusContainer.ts +368 -0
  130. package/src/components/Graphic.ts +227 -66
  131. package/src/components/Joystick.ts +363 -0
  132. package/src/components/Mesh.ts +222 -0
  133. package/src/components/NineSliceSprite.ts +4 -1
  134. package/src/components/ParticleEmitter.ts +12 -8
  135. package/src/components/Sprite.ts +297 -31
  136. package/src/components/Text.ts +125 -18
  137. package/src/components/Video.ts +2 -2
  138. package/src/components/Viewport.ts +118 -63
  139. package/src/components/index.ts +9 -2
  140. package/src/components/types/DisplayObject.ts +41 -4
  141. package/src/components/types/Spritesheet.ts +0 -118
  142. package/src/directives/Controls.ts +254 -0
  143. package/src/directives/ControlsBase.ts +267 -0
  144. package/src/directives/Drag.ts +357 -52
  145. package/src/directives/Flash.ts +419 -0
  146. package/src/directives/FocusNavigation.ts +113 -0
  147. package/src/directives/GamepadControls.ts +537 -0
  148. package/src/directives/JoystickControls.ts +396 -0
  149. package/src/directives/KeyboardControls.ts +85 -430
  150. package/src/directives/Scheduler.ts +12 -4
  151. package/src/directives/Shake.ts +298 -0
  152. package/src/directives/Sound.ts +94 -31
  153. package/src/directives/ViewportFollow.ts +40 -9
  154. package/src/directives/index.ts +12 -6
  155. package/src/engine/FocusManager.ts +510 -0
  156. package/src/engine/animation.ts +175 -21
  157. package/src/engine/bootstrap.ts +93 -3
  158. package/src/engine/directive.ts +4 -4
  159. package/src/engine/reactive.ts +901 -161
  160. package/src/engine/signal.ts +113 -25
  161. package/src/engine/trigger.ts +34 -7
  162. package/src/engine/utils.ts +19 -3
  163. package/src/hooks/useFocus.ts +91 -0
  164. package/src/hooks/useProps.ts +1 -1
  165. package/src/index.ts +8 -2
  166. package/src/types/pixi-cull.d.ts +7 -0
  167. package/src/utils/GlobalAssetLoader.ts +257 -0
  168. package/src/utils/functions.ts +7 -0
  169. package/src/utils/tabindex.ts +70 -0
  170. package/testing/index.ts +35 -4
  171. package/tsconfig.json +18 -0
  172. package/vite.config.ts +39 -0
@@ -0,0 +1,17 @@
1
+ export declare const Easing: {
2
+ linear: import('popmotion').Easing;
3
+ easeIn: import('popmotion').Easing;
4
+ easeInOut: import('popmotion').Easing;
5
+ easeOut: import('popmotion').Easing;
6
+ circIn: import('popmotion').Easing;
7
+ circInOut: import('popmotion').Easing;
8
+ circOut: import('popmotion').Easing;
9
+ backIn: import('popmotion').Easing;
10
+ backInOut: import('popmotion').Easing;
11
+ backOut: import('popmotion').Easing;
12
+ anticipate: import('popmotion').Easing;
13
+ bounceIn: import('popmotion').Easing;
14
+ bounceInOut: (p: number) => number;
15
+ bounceOut: (p: number) => number;
16
+ };
17
+ //# sourceMappingURL=Ease.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Ease.d.ts","sourceRoot":"","sources":["../../src/utils/Ease.ts"],"names":[],"mappings":"AAiBA,eAAO,MAAM,MAAM;;;;;;;;;;;;;;;CAelB,CAAA"}
@@ -0,0 +1,141 @@
1
+ /**
2
+ * Global Asset Loader
3
+ *
4
+ * Tracks the loading progress of all assets (images, spritesheets, etc.) across all sprites in a component tree.
5
+ * This allows components to know when all assets are loaded, useful for displaying loaders or progress bars.
6
+ *
7
+ * @example
8
+ * ```typescript
9
+ * const loader = new GlobalAssetLoader();
10
+ *
11
+ * loader.onProgress((progress) => {
12
+ * console.log(`Loading: ${(progress * 100).toFixed(0)}%`);
13
+ * });
14
+ *
15
+ * loader.onComplete(() => {
16
+ * console.log('All assets loaded!');
17
+ * });
18
+ *
19
+ * // Register assets as they start loading
20
+ * const assetId = loader.registerAsset('path/to/image.png');
21
+ *
22
+ * // Update progress
23
+ * loader.updateProgress(assetId, 0.5);
24
+ *
25
+ * // Mark as complete
26
+ * loader.completeAsset(assetId);
27
+ * ```
28
+ */
29
+ export declare class GlobalAssetLoader {
30
+ private assets;
31
+ private onProgressCallbacks;
32
+ private onCompleteCallbacks;
33
+ private assetCounter;
34
+ private isComplete;
35
+ /**
36
+ * Registers a new asset to track
37
+ *
38
+ * @param assetPath - The path or identifier of the asset being loaded
39
+ * @returns A unique ID for this asset that should be used for progress updates
40
+ *
41
+ * @example
42
+ * ```typescript
43
+ * const assetId = loader.registerAsset('path/to/image.png');
44
+ * ```
45
+ */
46
+ registerAsset(assetPath: string): string;
47
+ /**
48
+ * Updates the progress of a specific asset
49
+ *
50
+ * @param assetId - The ID returned by registerAsset
51
+ * @param progress - Progress value between 0 and 1
52
+ *
53
+ * @example
54
+ * ```typescript
55
+ * loader.updateProgress(assetId, 0.5); // 50% loaded
56
+ * ```
57
+ */
58
+ updateProgress(assetId: string, progress: number): void;
59
+ /**
60
+ * Marks an asset as completely loaded
61
+ *
62
+ * @param assetId - The ID returned by registerAsset
63
+ *
64
+ * @example
65
+ * ```typescript
66
+ * loader.completeAsset(assetId);
67
+ * ```
68
+ */
69
+ completeAsset(assetId: string): void;
70
+ /**
71
+ * Removes an asset from tracking (useful for cleanup)
72
+ *
73
+ * @param assetId - The ID returned by registerAsset
74
+ */
75
+ removeAsset(assetId: string): void;
76
+ /**
77
+ * Registers a callback that will be called whenever the global progress changes
78
+ *
79
+ * @param callback - Function that receives the global progress (0-1)
80
+ * @returns A function to unregister the callback
81
+ *
82
+ * @example
83
+ * ```typescript
84
+ * const unsubscribe = loader.onProgress((progress) => {
85
+ * console.log(`Loading: ${(progress * 100).toFixed(0)}%`);
86
+ * });
87
+ *
88
+ * // Later, to unsubscribe:
89
+ * unsubscribe();
90
+ * ```
91
+ */
92
+ onProgress(callback: (progress: number) => void): () => void;
93
+ /**
94
+ * Registers a callback that will be called when all assets are loaded
95
+ *
96
+ * @param callback - Function to call when all assets are complete
97
+ * @returns A function to unregister the callback
98
+ *
99
+ * @example
100
+ * ```typescript
101
+ * const unsubscribe = loader.onComplete(() => {
102
+ * console.log('All assets loaded!');
103
+ * });
104
+ *
105
+ * // Later, to unsubscribe:
106
+ * unsubscribe();
107
+ * ```
108
+ */
109
+ onComplete(callback: () => void): () => void;
110
+ /**
111
+ * Gets the current global progress (0-1)
112
+ *
113
+ * @returns Progress value between 0 and 1
114
+ */
115
+ getGlobalProgress(): number;
116
+ /**
117
+ * Gets the number of assets currently being tracked
118
+ *
119
+ * @returns Number of registered assets
120
+ */
121
+ getAssetCount(): number;
122
+ /**
123
+ * Gets the number of completed assets
124
+ *
125
+ * @returns Number of completed assets
126
+ */
127
+ getCompletedCount(): number;
128
+ /**
129
+ * Checks if all assets are loaded and triggers onComplete callbacks
130
+ */
131
+ private checkCompletion;
132
+ /**
133
+ * Updates global progress and notifies all progress callbacks
134
+ */
135
+ private updateGlobalProgress;
136
+ /**
137
+ * Resets the loader, clearing all assets and callbacks
138
+ */
139
+ reset(): void;
140
+ }
141
+ //# sourceMappingURL=GlobalAssetLoader.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"GlobalAssetLoader.d.ts","sourceRoot":"","sources":["../../src/utils/GlobalAssetLoader.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,MAAM,CAAoE;IAClF,OAAO,CAAC,mBAAmB,CAA8C;IACzE,OAAO,CAAC,mBAAmB,CAA8B;IACzD,OAAO,CAAC,YAAY,CAAa;IACjC,OAAO,CAAC,UAAU,CAAkB;IAEpC;;;;;;;;;;OAUG;IACH,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM;IAQxC;;;;;;;;;;OAUG;IACH,cAAc,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI;IAWvD;;;;;;;;;OASG;IACH,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IAapC;;;;OAIG;IACH,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IAKlC;;;;;;;;;;;;;;;OAeG;IACH,UAAU,CAAC,QAAQ,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,GAAG,MAAM,IAAI;IAe5D;;;;;;;;;;;;;;;OAeG;IACH,UAAU,CAAC,QAAQ,EAAE,MAAM,IAAI,GAAG,MAAM,IAAI;IAa5C;;;;OAIG;IACH,iBAAiB,IAAI,MAAM;IAa3B;;;;OAIG;IACH,aAAa,IAAI,MAAM;IAIvB;;;;OAIG;IACH,iBAAiB,IAAI,MAAM;IAQ3B;;OAEG;IACH,OAAO,CAAC,eAAe;IAiBvB;;OAEG;IACH,OAAO,CAAC,oBAAoB;IAa5B;;OAEG;IACH,KAAK,IAAI,IAAI;CAOd"}
@@ -0,0 +1,57 @@
1
+ import { Texture, Matrix } from 'pixi.js';
2
+ /**
3
+ * Creates a radial gradient texture that can be used in PixiJS.
4
+ * @example
5
+ * const gradient = new RadialGradient(size, size, 0, size, size, 0);
6
+ * gradient.addColorStop(0, "rgba(255, 255, 0, 1)");
7
+ * gradient.addColorStop(0.5, "rgba(255, 255, 0, 0.3)");
8
+ * gradient.addColorStop(0.8, "rgba(255, 255, 0, 0)");
9
+ */
10
+ export declare class RadialGradient {
11
+ private x0;
12
+ private y0;
13
+ private x1;
14
+ private y1;
15
+ private x2;
16
+ private y2;
17
+ private focalPoint;
18
+ private canvas;
19
+ private ctx;
20
+ private gradient;
21
+ private texture;
22
+ transform: Matrix;
23
+ size: number;
24
+ /**
25
+ * Creates a new RadialGradient instance
26
+ * @param x0 - The x-coordinate of the starting circle
27
+ * @param y0 - The y-coordinate of the starting circle
28
+ * @param x1 - The x-coordinate of the ending circle
29
+ * @param y1 - The y-coordinate of the ending circle
30
+ * @param x2 - The x-coordinate for gradient transformation
31
+ * @param y2 - The y-coordinate for gradient transformation
32
+ * @param focalPoint - The focal point of the gradient (0-1), defaults to 0
33
+ */
34
+ constructor(x0: number, y0: number, x1: number, y1: number, x2: number, y2: number, focalPoint?: number);
35
+ /**
36
+ * Adds a color stop to the gradient
37
+ * @param offset - The position of the color stop (0-1)
38
+ * @param color - The color value (any valid CSS color string)
39
+ */
40
+ addColorStop(offset: number, color: string): void;
41
+ /**
42
+ * Renders the gradient and returns the texture with its transformation matrix
43
+ * @param options - Render options
44
+ * @param options.translate - Optional translation coordinates
45
+ * @returns Object containing the texture and transformation matrix
46
+ */
47
+ render({ translate }?: {
48
+ translate?: {
49
+ x: number;
50
+ y: number;
51
+ };
52
+ }): {
53
+ texture: Texture<import('pixi.js').TextureSource<any>>;
54
+ matrix: Matrix;
55
+ };
56
+ }
57
+ //# sourceMappingURL=RadialGradient.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RadialGradient.d.ts","sourceRoot":"","sources":["../../src/utils/RadialGradient.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAA2B,MAAM,EAAE,MAAM,SAAS,CAAC;AAEnE;;;;;;;GAOG;AACH,qBAAa,cAAc;IAoBvB,OAAO,CAAC,EAAE;IACV,OAAO,CAAC,EAAE;IACV,OAAO,CAAC,EAAE;IACV,OAAO,CAAC,EAAE;IACV,OAAO,CAAC,EAAE;IACV,OAAO,CAAC,EAAE;IACV,OAAO,CAAC,UAAU;IAzBpB,OAAO,CAAC,MAAM,CAAoB;IAClC,OAAO,CAAC,GAAG,CAAkC;IAC7C,OAAO,CAAC,QAAQ,CAA+B;IAC/C,OAAO,CAAC,OAAO,CAAwB;IAChC,SAAS,EAAE,MAAM,CAAC;IAElB,IAAI,SAAO;IAElB;;;;;;;;;OASG;gBAEO,EAAE,EAAE,MAAM,EACV,EAAE,EAAE,MAAM,EACV,EAAE,EAAE,MAAM,EACV,EAAE,EAAE,MAAM,EACV,EAAE,EAAE,MAAM,EACV,EAAE,EAAE,MAAM,EACV,UAAU,GAAE,MAAU;IAsBhC;;;;OAIG;IACH,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM;IAM1C;;;;;OAKG;IACH,MAAM,CAAC,EAAE,SAAS,EAAE,GAAE;QAAE,SAAS,CAAC,EAAE;YAAE,CAAC,EAAE,MAAM,CAAC;YAAC,CAAC,EAAE,MAAM,CAAA;SAAE,CAAA;KAAO;;;;CAuCpE"}
@@ -0,0 +1,2 @@
1
+ export declare function isPercent(value?: string | number): boolean;
2
+ //# sourceMappingURL=functions.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"functions.d.ts","sourceRoot":"","sources":["../../src/utils/functions.ts"],"names":[],"mappings":"AAAA,wBAAgB,SAAS,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,WAMhD"}
@@ -0,0 +1,16 @@
1
+ import { WritableSignal } from '@signe/reactive';
2
+ export type TabindexBoundaryMode = "wrap" | "clamp" | "none";
3
+ export type TabindexBounds = {
4
+ count: () => number;
5
+ min?: number;
6
+ } | {
7
+ min: number;
8
+ max: number;
9
+ };
10
+ type TabindexNavigator = {
11
+ next: (delta: number) => void;
12
+ set: (value: number) => void;
13
+ };
14
+ export declare function createTabindexNavigator(tabindex: WritableSignal<number>, bounds: TabindexBounds, mode?: TabindexBoundaryMode): TabindexNavigator;
15
+ export {};
16
+ //# sourceMappingURL=tabindex.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tabindex.d.ts","sourceRoot":"","sources":["../../src/utils/tabindex.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAEjD,MAAM,MAAM,oBAAoB,GAAG,MAAM,GAAG,OAAO,GAAG,MAAM,CAAC;AAE7D,MAAM,MAAM,cAAc,GACtB;IAAE,KAAK,EAAE,MAAM,MAAM,CAAC;IAAC,GAAG,CAAC,EAAE,MAAM,CAAA;CAAE,GACrC;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,CAAC;AAEjC,KAAK,iBAAiB,GAAG;IACvB,IAAI,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAC9B,GAAG,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;CAC9B,CAAC;AAuCF,wBAAgB,uBAAuB,CACrC,QAAQ,EAAE,cAAc,CAAC,MAAM,CAAC,EAChC,MAAM,EAAE,cAAc,EACtB,IAAI,GAAE,oBAA6B,GAClC,iBAAiB,CAenB"}
package/package.json CHANGED
@@ -1,22 +1,28 @@
1
1
  {
2
2
  "name": "canvasengine",
3
- "version": "2.0.0-beta.5",
3
+ "version": "2.0.0-beta.50",
4
4
  "type": "module",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
7
+ "peerDependencies": {
8
+ "pixi.js": "^8.9.2"
9
+ },
7
10
  "dependencies": {
8
11
  "@barvynkoa/particle-emitter": "^0.0.1",
9
- "@signe/reactive": "^1.0.1",
12
+ "@pixi/layout": "^3.2.0",
13
+ "@signe/reactive": "^2.6.0",
10
14
  "howler": "^2.2.4",
15
+ "joypad.js": "^2.3.5",
11
16
  "pixi-filters": "^6.0.5",
12
17
  "pixi-viewport": "^6.0.3",
13
- "pixi.js": "^8.6.4",
14
18
  "popmotion": "^11.0.5",
15
19
  "rxjs": "^7.8.1",
16
- "yoga-layout": "^2.0.1"
20
+ "yoga-layout": "^3.2.1"
17
21
  },
18
22
  "devDependencies": {
19
- "@types/howler": "^2.2.11"
23
+ "@types/howler": "^2.2.11",
24
+ "vite": "^7.3.0",
25
+ "vite-plugin-dts": "^4.5.4"
20
26
  },
21
27
  "author": "Samuel Ronce",
22
28
  "license": "MIT",
@@ -38,7 +44,7 @@
38
44
  "access": "public"
39
45
  },
40
46
  "scripts": {
41
- "build": "tsup",
42
- "dev": "tsup --watch"
47
+ "build": "vite build",
48
+ "dev": "vite build --watch"
43
49
  }
44
50
  }
@@ -0,0 +1,399 @@
1
+ import { effect, signal, computed, isSignal, Signal } from "@signe/reactive";
2
+ import { FederatedPointerEvent } from "pixi.js";
3
+ import { h } from "../engine/signal";
4
+ import { useDefineProps } from "../hooks/useProps";
5
+ import { Container } from "./Container";
6
+ import { Rect, Circle, Ellipse } from "./Graphic";
7
+ import { Text } from "./Text";
8
+ import { ControlsDirective } from "../directives/Controls";
9
+ import { JoystickControls } from "../directives/JoystickControls";
10
+ import { Element } from "../engine/reactive";
11
+
12
+ /**
13
+ * Button states for visual feedback
14
+ */
15
+ export enum ButtonState {
16
+ Normal = "normal",
17
+ Hover = "hover",
18
+ Pressed = "pressed",
19
+ Disabled = "disabled"
20
+ }
21
+
22
+ /**
23
+ * Button style configuration for different visual approaches
24
+ */
25
+ export interface ButtonStyle {
26
+ /** Background color for each state */
27
+ backgroundColor?: {
28
+ [ButtonState.Normal]?: string;
29
+ [ButtonState.Hover]?: string;
30
+ [ButtonState.Pressed]?: string;
31
+ [ButtonState.Disabled]?: string;
32
+ };
33
+ /** Border configuration */
34
+ border?: {
35
+ color?: string;
36
+ width?: number;
37
+ radius?: number;
38
+ };
39
+ /** Text styling */
40
+ text?: {
41
+ color?: string;
42
+ fontSize?: number;
43
+ fontFamily?: string;
44
+ };
45
+ /** Sprite textures for each state (alternative to backgroundColor) */
46
+ textures?: {
47
+ [ButtonState.Normal]?: string;
48
+ [ButtonState.Hover]?: string;
49
+ [ButtonState.Pressed]?: string;
50
+ [ButtonState.Disabled]?: string;
51
+ };
52
+ }
53
+
54
+ /**
55
+ * Properties for the Button component
56
+ */
57
+ export interface ButtonProps {
58
+ /** Button text content */
59
+ text?: string;
60
+ /** Button disabled state */
61
+ disabled?: boolean;
62
+ /** Click event handler */
63
+ click?: (event: FederatedPointerEvent) => void;
64
+ /** Hover enter event handler */
65
+ hoverEnter?: (event: FederatedPointerEvent) => void;
66
+ /** Hover leave event handler */
67
+ hoverLeave?: (event: FederatedPointerEvent) => void;
68
+ /** Press down event handler */
69
+ pressDown?: (event: FederatedPointerEvent) => void;
70
+ /** Press up event handler */
71
+ pressUp?: (event: FederatedPointerEvent) => void;
72
+ /** Visual style configuration */
73
+ style?: ButtonStyle;
74
+ /** Button width */
75
+ width?: number;
76
+ /** Button height */
77
+ height?: number;
78
+ /** Button position X */
79
+ x?: number;
80
+ /** Button position Y */
81
+ y?: number;
82
+ /** Button alpha/opacity */
83
+ alpha?: number;
84
+ /** Button visibility */
85
+ visible?: boolean;
86
+ /** Button cursor */
87
+ cursor?: string;
88
+ /** Controls instance to automatically apply button events to (e.g., ControlsDirective or JoystickControls) */
89
+ controls?: ControlsDirective | JoystickControls | any;
90
+ /** Name of the control to trigger with applyControl when button is clicked */
91
+ controlName?: string;
92
+ /** Shape of the button background: 'rect', 'circle', or 'ellipse' */
93
+ shape?: 'rect' | 'circle' | 'ellipse';
94
+ /** Custom background component or element (replaces default background if provided) */
95
+ background?: Element | any;
96
+ /** Custom children components for button content (takes priority over text if provided) */
97
+ children?: Element[];
98
+ /** Focus index for the button */
99
+ tabindex?: number | Signal<number>;
100
+ }
101
+
102
+ /**
103
+ * Creates a Button component with interactive states and customizable styling.
104
+ *
105
+ * This component provides a fully interactive button with visual feedback
106
+ * for different states (normal, hover, pressed, disabled). It supports both
107
+ * sprite-based and graphics-based rendering approaches.
108
+ *
109
+ * The button is built using a Container with background and text elements,
110
+ * providing reactive state management and event handling.
111
+ *
112
+ * ## Features
113
+ *
114
+ * - **Controls Integration**: Automatically trigger controls via `applyControl` when clicked
115
+ * - **Multiple Shapes**: Support for rect, circle, and ellipse shapes
116
+ * - **Custom Content**: Use children components for custom button content
117
+ * - **Custom Background**: Provide a custom background component
118
+ *
119
+ * @param props - Button configuration including text, styling, controls, shape, and event handlers
120
+ * @returns A reactive Button component
121
+ * @example
122
+ * ```typescript
123
+ * // Simple button with text and click handler
124
+ * const simpleButton = Button({
125
+ * text: "Click Me",
126
+ * click: () => console.log("Button clicked!"),
127
+ * width: 150,
128
+ * height: 50
129
+ * });
130
+ *
131
+ * // Button with controls integration
132
+ * const jumpButton = Button({
133
+ * text: "Jump",
134
+ * controls: controlsInstance,
135
+ * controlName: "jump",
136
+ * width: 120,
137
+ * height: 40
138
+ * });
139
+ *
140
+ * // Circular button
141
+ * const circleButton = Button({
142
+ * text: "Action",
143
+ * shape: "circle",
144
+ * width: 100,
145
+ * height: 100
146
+ * });
147
+ *
148
+ * // Button with custom content (children)
149
+ * const customButton = Button({
150
+ * shape: "circle",
151
+ * width: 80,
152
+ * height: 80,
153
+ * children: [
154
+ * h(Sprite, { image: "icon.png", width: 50, height: 50 })
155
+ * ]
156
+ * });
157
+ *
158
+ * // Styled button with custom colors
159
+ * const styledButton = Button({
160
+ * text: "Styled Button",
161
+ * style: {
162
+ * backgroundColor: {
163
+ * normal: "#28a745",
164
+ * hover: "#218838",
165
+ * pressed: "#1e7e34",
166
+ * disabled: "#6c757d"
167
+ * },
168
+ * border: {
169
+ * radius: 8,
170
+ * width: 2,
171
+ * color: "#ffffff"
172
+ * },
173
+ * text: {
174
+ * fontSize: 18,
175
+ * color: "#ffffff"
176
+ * }
177
+ * }
178
+ * });
179
+ *
180
+ * // Sprite-based button
181
+ * const spriteButton = Button({
182
+ * text: "Play Game",
183
+ * style: {
184
+ * textures: {
185
+ * normal: "/assets/button-normal.png",
186
+ * hover: "/assets/button-hover.png",
187
+ * pressed: "/assets/button-pressed.png"
188
+ * }
189
+ * }
190
+ * });
191
+ * ```
192
+ */
193
+ export function Button(props: ButtonProps) {
194
+ // Internal state signals
195
+ const currentState = signal(ButtonState.Normal);
196
+ const isPressed = signal(false);
197
+ const isHovered = signal(false);
198
+
199
+ // Define reactive props with defaults
200
+ const defineProps = useDefineProps(props);
201
+ const { text, disabled, width, height, style, shape, controlName } = defineProps({
202
+ text: {
203
+ type: String,
204
+ default: ""
205
+ },
206
+ disabled: {
207
+ type: Boolean,
208
+ default: false
209
+ },
210
+ width: {
211
+ type: Number,
212
+ default: 120
213
+ },
214
+ height: {
215
+ type: Number,
216
+ default: 40
217
+ },
218
+ style: {
219
+ type: Object,
220
+ default: () => ({})
221
+ },
222
+ shape: {
223
+ type: String,
224
+ default: "rect"
225
+ },
226
+ controlName: {
227
+ type: String,
228
+ default: undefined
229
+ }
230
+ });
231
+
232
+ // Helper function to get controls instance (handles signals like Joystick)
233
+ const getControls = () => {
234
+ if (!props.controls) return null;
235
+ if (isSignal(props.controls)) {
236
+ return props.controls();
237
+ }
238
+ return props.controls;
239
+ };
240
+
241
+ // Update button state based on disabled and interaction states
242
+ effect(() => {
243
+ const isDisabled = disabled();
244
+ const pressed = isPressed();
245
+ const hovered = isHovered();
246
+
247
+ if (isDisabled) {
248
+ currentState.set(ButtonState.Disabled);
249
+ } else if (pressed) {
250
+ currentState.set(ButtonState.Pressed);
251
+ } else if (hovered) {
252
+ currentState.set(ButtonState.Hover);
253
+ } else {
254
+ currentState.set(ButtonState.Normal);
255
+ }
256
+ });
257
+
258
+ // Event handlers
259
+ const eventHandlers = {
260
+ pointerenter: (event: FederatedPointerEvent) => {
261
+ if (!disabled()) {
262
+ isHovered.set(true);
263
+ props.hoverEnter?.(event);
264
+ }
265
+ },
266
+ pointerleave: (event: FederatedPointerEvent) => {
267
+ isHovered.set(false);
268
+ isPressed.set(false);
269
+ props.hoverLeave?.(event);
270
+ },
271
+ pointerdown: async (event: FederatedPointerEvent) => {
272
+ if (!disabled()) {
273
+ isPressed.set(true);
274
+ props.pressDown?.(event);
275
+
276
+ // Apply control if controls and controlName are provided
277
+ const controls = getControls();
278
+ const name = controlName();
279
+ if (controls && name && controls.applyControl) {
280
+ await controls.applyControl(name, true);
281
+ }
282
+ }
283
+ },
284
+ pointerup: async (event: FederatedPointerEvent) => {
285
+ if (!disabled() && isPressed()) {
286
+ isPressed.set(false);
287
+ props.pressUp?.(event);
288
+
289
+ // Apply control release if controls and controlName are provided
290
+ const controls = getControls();
291
+ const name = controlName();
292
+ if (controls && name && controls.applyControl) {
293
+ await controls.applyControl(name, false);
294
+ }
295
+ }
296
+ },
297
+ pointertap: async (event: FederatedPointerEvent) => {
298
+ if (!disabled()) {
299
+ props.click?.(event);
300
+
301
+ // Apply control if controls and controlName are provided (press and release)
302
+ const controls = getControls();
303
+ const name = controlName();
304
+ if (controls && name && controls.applyControl) {
305
+ await controls.applyControl(name);
306
+ }
307
+ }
308
+ }
309
+ };
310
+
311
+ // Generate background element
312
+ const getBackgroundElement = () => {
313
+ // If custom background is provided, use it
314
+ if (props.background) {
315
+ return props.background;
316
+ }
317
+
318
+ // Otherwise, use shape-based background
319
+ const currentShape = shape();
320
+ const bgColor = computed(() => {
321
+ const currentStyle = style();
322
+ const backgroundColor = currentStyle.backgroundColor || {
323
+ [ButtonState.Normal]: "#007bff",
324
+ [ButtonState.Hover]: "#0056b3",
325
+ [ButtonState.Pressed]: "#004085",
326
+ [ButtonState.Disabled]: "#6c757d"
327
+ };
328
+ const state = currentState();
329
+ return backgroundColor[state] || backgroundColor[ButtonState.Normal];
330
+ });
331
+
332
+ if (currentShape === 'circle') {
333
+ // For circle, use the smaller dimension as radius
334
+ const radius = computed(() => Math.min(width(), height()) / 2);
335
+ return h(Circle, {
336
+ radius: radius,
337
+ x: computed(() => width() / 2),
338
+ y: computed(() => height() / 2),
339
+ color: bgColor
340
+ });
341
+ } else if (currentShape === 'ellipse') {
342
+ return h(Ellipse, {
343
+ width: width,
344
+ height: height,
345
+ color: bgColor
346
+ });
347
+ } else {
348
+ // Default: rect
349
+ return h(Rect, {
350
+ width: width,
351
+ height: height,
352
+ color: bgColor
353
+ });
354
+ }
355
+ };
356
+
357
+ // Generate content element(s)
358
+ const getContentElements = () => {
359
+ // If children are provided, use them (priority over text)
360
+ if (props.children && props.children.length > 0) {
361
+ return props.children;
362
+ }
363
+
364
+ // Otherwise, use text
365
+ return [
366
+ h(Text, {
367
+ text: text,
368
+ x: computed(() => width() / 2),
369
+ y: computed(() => height() / 2),
370
+ anchor: { x: 0.5, y: 0.5 },
371
+ style: computed(() => {
372
+ const currentStyle = style();
373
+ const textStyle = currentStyle.text || {};
374
+ return {
375
+ fontSize: textStyle.fontSize || 16,
376
+ fontFamily: textStyle.fontFamily || "Arial",
377
+ fill: textStyle.color || "#ffffff"
378
+ };
379
+ })()
380
+ })
381
+ ];
382
+ };
383
+
384
+ // Return Container with h() children
385
+ return h(Container, {
386
+ x: props.x,
387
+ y: props.y,
388
+ width: props.width,
389
+ height: props.height,
390
+ alpha: props.alpha,
391
+ visible: props.visible,
392
+ cursor: props.cursor || "pointer",
393
+ tabindex: props.tabindex,
394
+ ...eventHandlers
395
+ }, [
396
+ getBackgroundElement(),
397
+ ...getContentElements()
398
+ ]);
399
+ }