canvasengine 2.0.0-beta.37 → 2.0.0-beta.39

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 (45) hide show
  1. package/dist/{DebugRenderer-CTWPthRt.js → DebugRenderer-Rrw9FlTd.js} +2 -2
  2. package/dist/{DebugRenderer-CTWPthRt.js.map → DebugRenderer-Rrw9FlTd.js.map} +1 -1
  3. package/dist/components/Button.d.ts +50 -3
  4. package/dist/components/Button.d.ts.map +1 -1
  5. package/dist/components/Canvas.d.ts.map +1 -1
  6. package/dist/components/Joystick.d.ts +36 -0
  7. package/dist/components/Joystick.d.ts.map +1 -0
  8. package/dist/components/Sprite.d.ts +2 -0
  9. package/dist/components/Sprite.d.ts.map +1 -1
  10. package/dist/components/index.d.ts +1 -0
  11. package/dist/components/index.d.ts.map +1 -1
  12. package/dist/components/types/Spritesheet.d.ts +0 -118
  13. package/dist/components/types/Spritesheet.d.ts.map +1 -1
  14. package/dist/directives/Controls.d.ts +16 -7
  15. package/dist/directives/Controls.d.ts.map +1 -1
  16. package/dist/directives/GamepadControls.d.ts +3 -1
  17. package/dist/directives/GamepadControls.d.ts.map +1 -1
  18. package/dist/directives/JoystickControls.d.ts +172 -0
  19. package/dist/directives/JoystickControls.d.ts.map +1 -0
  20. package/dist/directives/index.d.ts +1 -0
  21. package/dist/directives/index.d.ts.map +1 -1
  22. package/dist/engine/reactive.d.ts.map +1 -1
  23. package/dist/engine/signal.d.ts.map +1 -1
  24. package/dist/{index-BqwprEPH.js → index-BQ99FClW.js} +6057 -5433
  25. package/dist/index-BQ99FClW.js.map +1 -0
  26. package/dist/index.global.js +7 -7
  27. package/dist/index.global.js.map +1 -1
  28. package/dist/index.js +59 -57
  29. package/dist/utils/GlobalAssetLoader.d.ts +141 -0
  30. package/dist/utils/GlobalAssetLoader.d.ts.map +1 -0
  31. package/package.json +1 -1
  32. package/src/components/Button.ts +168 -41
  33. package/src/components/Canvas.ts +3 -0
  34. package/src/components/Joystick.ts +361 -0
  35. package/src/components/Sprite.ts +82 -16
  36. package/src/components/index.ts +2 -1
  37. package/src/components/types/Spritesheet.ts +0 -118
  38. package/src/directives/Controls.ts +42 -8
  39. package/src/directives/GamepadControls.ts +40 -18
  40. package/src/directives/JoystickControls.ts +396 -0
  41. package/src/directives/index.ts +1 -0
  42. package/src/engine/reactive.ts +362 -242
  43. package/src/engine/signal.ts +8 -2
  44. package/src/utils/GlobalAssetLoader.ts +257 -0
  45. package/dist/index-BqwprEPH.js.map +0 -1
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
- import { h as a } from "./index-BqwprEPH.js";
2
- import { A as r, X as o, Y as n, q as l, v as c, r as p, C as S, d as u, U as m, W as g, ai as d, f as b, D as C, ah as h, af as T, w as j, j as w, G as D, t as f, c as v, I as E, K as O, M as k, Q as y, O as P, P as V, ag as x, R as A, z as B, S as G, g as H, e as M, B as N, y as R, J as q, L as F, T as I, x as K, b as U, H as z, N as J, V as L, ae as Q, ad as W, ab as X, k as Y, a2 as Z, a0 as _, a3 as $, l as aa, a7 as sa, ac as ea, m as ta, n as ia, Z as ra, o as oa, i as na, _ as la, p as ca, a8 as pa, a1 as Sa, a5 as ua, a4 as ma, aa as ga, $ as da, s as ba, a6 as Ca, a9 as ha, a as Ta, u as ja } from "./index-BqwprEPH.js";
1
+ import { h as a } from "./index-BQ99FClW.js";
2
+ import { A as r, Y as o, Z as n, q as l, v as c, r as p, C as S, d as u, W as m, X as g, ak as d, f as b, D as C, aj as h, ah as j, w as T, j as k, G as w, t as D, c as f, I as v, _ as y, J as E, K as O, M as P, U as V, O as x, P as A, ai as B, R as G, z as H, S as M, g as J, e as N, B as R, y as q, L as F, N as I, T as K, x as U, b as z, H as L, Q, V as W, ag as X, af as Y, ad as Z, k as _, a4 as $, a2 as aa, a5 as sa, l as ea, a9 as ta, ae as ia, m as ra, n as oa, $ as na, o as la, i as ca, a0 as pa, p as Sa, aa as ua, a3 as ma, a7 as ga, a6 as da, ac as ba, a1 as Ca, s as ha, a8 as ja, ab as Ta, a as ka, u as wa } from "./index-BQ99FClW.js";
3
3
  const e = a.Howler;
4
4
  export {
5
5
  r as ArraySubject,
@@ -16,62 +16,64 @@ export {
16
16
  b as Drag,
17
17
  C as Drop,
18
18
  h as EVENTS,
19
- T as Easing,
20
- j as Ellipse,
21
- w as Flash,
22
- D as GamepadControls,
23
- f as Graphics,
24
- v as Howl,
19
+ j as Easing,
20
+ T as Ellipse,
21
+ k as Flash,
22
+ w as GamepadControls,
23
+ D as Graphics,
24
+ f as Howl,
25
25
  e as Howler,
26
- E as Input,
26
+ v as Input,
27
+ y as Joystick,
28
+ E as JoystickControls,
27
29
  O as KeyboardControls,
28
- k as Mesh,
29
- y as NineSliceSprite,
30
- P as ObjectSubject,
31
- V as ParticlesEmitter,
32
- x as RadialGradient,
33
- A as Rect,
34
- B as Scene,
35
- G as Scheduler,
36
- H as Shake,
37
- M as Sound,
38
- N as Sprite,
39
- R as Svg,
40
- q as Text,
41
- F as TilingSprite,
42
- I as Transition,
43
- K as Triangle,
44
- U as Utils,
45
- z as Video,
46
- J as Viewport,
47
- L as ViewportFollow,
48
- Q as animatedSequence,
49
- W as animatedSignal,
50
- X as bootstrapCanvas,
51
- Y as computed,
52
- Z as cond,
53
- _ as createComponent,
54
- $ as currentSubscriptionsTracker,
55
- aa as effect,
56
- sa as h,
57
- ea as isAnimatedSignal,
58
- ta as isArraySubject,
59
- ia as isComputed,
60
- ra as isElement,
61
- oa as isObjectSubject,
62
- na as isObservable,
63
- la as isPrimitive,
64
- ca as isSignal,
65
- pa as isTrigger,
66
- Sa as loop,
67
- ua as mount,
68
- ma as mountTracker,
69
- ga as on,
70
- da as registerComponent,
71
- ba as signal,
72
- Ca as tick,
73
- ha as trigger,
74
- Ta as useDefineProps,
75
- ja as useProps
30
+ P as Mesh,
31
+ V as NineSliceSprite,
32
+ x as ObjectSubject,
33
+ A as ParticlesEmitter,
34
+ B as RadialGradient,
35
+ G as Rect,
36
+ H as Scene,
37
+ M as Scheduler,
38
+ J as Shake,
39
+ N as Sound,
40
+ R as Sprite,
41
+ q as Svg,
42
+ F as Text,
43
+ I as TilingSprite,
44
+ K as Transition,
45
+ U as Triangle,
46
+ z as Utils,
47
+ L as Video,
48
+ Q as Viewport,
49
+ W as ViewportFollow,
50
+ X as animatedSequence,
51
+ Y as animatedSignal,
52
+ Z as bootstrapCanvas,
53
+ _ as computed,
54
+ $ as cond,
55
+ aa as createComponent,
56
+ sa as currentSubscriptionsTracker,
57
+ ea as effect,
58
+ ta as h,
59
+ ia as isAnimatedSignal,
60
+ ra as isArraySubject,
61
+ oa as isComputed,
62
+ na as isElement,
63
+ la as isObjectSubject,
64
+ ca as isObservable,
65
+ pa as isPrimitive,
66
+ Sa as isSignal,
67
+ ua as isTrigger,
68
+ ma as loop,
69
+ ga as mount,
70
+ da as mountTracker,
71
+ ba as on,
72
+ Ca as registerComponent,
73
+ ha as signal,
74
+ ja as tick,
75
+ Ta as trigger,
76
+ ka as useDefineProps,
77
+ wa as useProps
76
78
  };
77
79
  //# sourceMappingURL=index.js.map
@@ -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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "canvasengine",
3
- "version": "2.0.0-beta.37",
3
+ "version": "2.0.0-beta.39",
4
4
  "type": "module",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -1,10 +1,13 @@
1
- import { effect, signal, computed } from "@signe/reactive";
1
+ import { effect, signal, computed, isSignal } from "@signe/reactive";
2
2
  import { FederatedPointerEvent } from "pixi.js";
3
3
  import { h } from "../engine/signal";
4
4
  import { useDefineProps } from "../hooks/useProps";
5
5
  import { Container } from "./Container";
6
- import { Rect } from "./Graphic";
6
+ import { Rect, Circle, Ellipse } from "./Graphic";
7
7
  import { Text } from "./Text";
8
+ import { ControlsDirective } from "../directives/Controls";
9
+ import { JoystickControls } from "../directives/JoystickControls";
10
+ import { Element } from "../engine/reactive";
8
11
 
9
12
  /**
10
13
  * Button states for visual feedback
@@ -82,6 +85,16 @@ export interface ButtonProps {
82
85
  visible?: boolean;
83
86
  /** Button cursor */
84
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[];
85
98
  }
86
99
 
87
100
  /**
@@ -94,18 +107,52 @@ export interface ButtonProps {
94
107
  * The button is built using a Container with background and text elements,
95
108
  * providing reactive state management and event handling.
96
109
  *
97
- * @param props - Button configuration including text, styling, and event handlers
110
+ * ## Features
111
+ *
112
+ * - **Controls Integration**: Automatically trigger controls via `applyControl` when clicked
113
+ * - **Multiple Shapes**: Support for rect, circle, and ellipse shapes
114
+ * - **Custom Content**: Use children components for custom button content
115
+ * - **Custom Background**: Provide a custom background component
116
+ *
117
+ * @param props - Button configuration including text, styling, controls, shape, and event handlers
98
118
  * @returns A reactive Button component
99
119
  * @example
100
120
  * ```typescript
101
121
  * // Simple button with text and click handler
102
122
  * const simpleButton = Button({
103
123
  * text: "Click Me",
104
- * onClick: () => console.log("Button clicked!"),
124
+ * click: () => console.log("Button clicked!"),
105
125
  * width: 150,
106
126
  * height: 50
107
127
  * });
108
128
  *
129
+ * // Button with controls integration
130
+ * const jumpButton = Button({
131
+ * text: "Jump",
132
+ * controls: controlsInstance,
133
+ * controlName: "jump",
134
+ * width: 120,
135
+ * height: 40
136
+ * });
137
+ *
138
+ * // Circular button
139
+ * const circleButton = Button({
140
+ * text: "Action",
141
+ * shape: "circle",
142
+ * width: 100,
143
+ * height: 100
144
+ * });
145
+ *
146
+ * // Button with custom content (children)
147
+ * const customButton = Button({
148
+ * shape: "circle",
149
+ * width: 80,
150
+ * height: 80,
151
+ * children: [
152
+ * h(Sprite, { image: "icon.png", width: 50, height: 50 })
153
+ * ]
154
+ * });
155
+ *
109
156
  * // Styled button with custom colors
110
157
  * const styledButton = Button({
111
158
  * text: "Styled Button",
@@ -149,7 +196,7 @@ export function Button(props: ButtonProps) {
149
196
 
150
197
  // Define reactive props with defaults
151
198
  const defineProps = useDefineProps(props);
152
- const { text, disabled, width, height, style } = defineProps({
199
+ const { text, disabled, width, height, style, shape, controlName } = defineProps({
153
200
  text: {
154
201
  type: String,
155
202
  default: ""
@@ -169,9 +216,26 @@ export function Button(props: ButtonProps) {
169
216
  style: {
170
217
  type: Object,
171
218
  default: () => ({})
219
+ },
220
+ shape: {
221
+ type: String,
222
+ default: "rect"
223
+ },
224
+ controlName: {
225
+ type: String,
226
+ default: undefined
172
227
  }
173
228
  });
174
229
 
230
+ // Helper function to get controls instance (handles signals like Joystick)
231
+ const getControls = () => {
232
+ if (!props.controls) return null;
233
+ if (isSignal(props.controls)) {
234
+ return props.controls();
235
+ }
236
+ return props.controls;
237
+ };
238
+
175
239
  // Update button state based on disabled and interaction states
176
240
  effect(() => {
177
241
  const isDisabled = disabled();
@@ -202,25 +266,119 @@ export function Button(props: ButtonProps) {
202
266
  isPressed.set(false);
203
267
  props.hoverLeave?.(event);
204
268
  },
205
- pointerdown: (event: FederatedPointerEvent) => {
269
+ pointerdown: async (event: FederatedPointerEvent) => {
206
270
  if (!disabled()) {
207
271
  isPressed.set(true);
208
272
  props.pressDown?.(event);
273
+
274
+ // Apply control if controls and controlName are provided
275
+ const controls = getControls();
276
+ const name = controlName();
277
+ if (controls && name && controls.applyControl) {
278
+ await controls.applyControl(name, true);
279
+ }
209
280
  }
210
281
  },
211
- pointerup: (event: FederatedPointerEvent) => {
282
+ pointerup: async (event: FederatedPointerEvent) => {
212
283
  if (!disabled() && isPressed()) {
213
284
  isPressed.set(false);
214
285
  props.pressUp?.(event);
286
+
287
+ // Apply control release if controls and controlName are provided
288
+ const controls = getControls();
289
+ const name = controlName();
290
+ if (controls && name && controls.applyControl) {
291
+ await controls.applyControl(name, false);
292
+ }
215
293
  }
216
294
  },
217
- pointertap: (event: FederatedPointerEvent) => {
295
+ pointertap: async (event: FederatedPointerEvent) => {
218
296
  if (!disabled()) {
219
297
  props.click?.(event);
298
+
299
+ // Apply control if controls and controlName are provided (press and release)
300
+ const controls = getControls();
301
+ const name = controlName();
302
+ if (controls && name && controls.applyControl) {
303
+ await controls.applyControl(name);
304
+ }
220
305
  }
221
306
  }
222
307
  };
223
308
 
309
+ // Generate background element
310
+ const getBackgroundElement = () => {
311
+ // If custom background is provided, use it
312
+ if (props.background) {
313
+ return props.background;
314
+ }
315
+
316
+ // Otherwise, use shape-based background
317
+ const currentShape = shape();
318
+ const bgColor = computed(() => {
319
+ const currentStyle = style();
320
+ const backgroundColor = currentStyle.backgroundColor || {
321
+ [ButtonState.Normal]: "#007bff",
322
+ [ButtonState.Hover]: "#0056b3",
323
+ [ButtonState.Pressed]: "#004085",
324
+ [ButtonState.Disabled]: "#6c757d"
325
+ };
326
+ const state = currentState();
327
+ return backgroundColor[state] || backgroundColor[ButtonState.Normal];
328
+ });
329
+
330
+ if (currentShape === 'circle') {
331
+ // For circle, use the smaller dimension as radius
332
+ const radius = computed(() => Math.min(width(), height()) / 2);
333
+ return h(Circle, {
334
+ radius: radius,
335
+ x: computed(() => width() / 2),
336
+ y: computed(() => height() / 2),
337
+ color: bgColor
338
+ });
339
+ } else if (currentShape === 'ellipse') {
340
+ return h(Ellipse, {
341
+ width: width,
342
+ height: height,
343
+ color: bgColor
344
+ });
345
+ } else {
346
+ // Default: rect
347
+ return h(Rect, {
348
+ width: width,
349
+ height: height,
350
+ color: bgColor
351
+ });
352
+ }
353
+ };
354
+
355
+ // Generate content element(s)
356
+ const getContentElements = () => {
357
+ // If children are provided, use them (priority over text)
358
+ if (props.children && props.children.length > 0) {
359
+ return props.children;
360
+ }
361
+
362
+ // Otherwise, use text
363
+ return [
364
+ h(Text, {
365
+ text: text,
366
+ x: computed(() => width() / 2),
367
+ y: computed(() => height() / 2),
368
+ anchor: { x: 0.5, y: 0.5 },
369
+ style: computed(() => {
370
+ const currentStyle = style();
371
+ const textStyle = currentStyle.text || {};
372
+ return {
373
+ fontSize: textStyle.fontSize || 16,
374
+ fontFamily: textStyle.fontFamily || "Arial",
375
+ fill: textStyle.color || "#ffffff"
376
+ };
377
+ })()
378
+ })
379
+ ];
380
+ };
381
+
224
382
  // Return Container with h() children
225
383
  return h(Container, {
226
384
  x: props.x,
@@ -232,38 +390,7 @@ export function Button(props: ButtonProps) {
232
390
  cursor: props.cursor || "pointer",
233
391
  ...eventHandlers
234
392
  }, [
235
- // Background element (either sprite or graphics)
236
- h(Rect, {
237
- width: width,
238
- height: height,
239
- color: computed(() => {
240
- const currentStyle = style();
241
- const backgroundColor = currentStyle.backgroundColor || {
242
- [ButtonState.Normal]: "#007bff",
243
- [ButtonState.Hover]: "#0056b3",
244
- [ButtonState.Pressed]: "#004085",
245
- [ButtonState.Disabled]: "#6c757d"
246
- };
247
- const state = currentState();
248
- return backgroundColor[state] || backgroundColor[ButtonState.Normal];
249
- })
250
- }),
251
-
252
- // Text element
253
- h(Text, {
254
- text: text,
255
- x: computed(() => width() / 2),
256
- y: computed(() => height() / 2),
257
- anchor: { x: 0.5, y: 0.5 },
258
- style: computed(() => {
259
- const currentStyle = style();
260
- const textStyle = currentStyle.text || {};
261
- return {
262
- fontSize: textStyle.fontSize || 16,
263
- fontFamily: textStyle.fontFamily || "Arial",
264
- fill: textStyle.color || "#ffffff"
265
- };
266
- })()
267
- })
393
+ getBackgroundElement(),
394
+ ...getContentElements()
268
395
  ]);
269
396
  }
@@ -12,6 +12,7 @@ import { ComponentFunction } from "../engine/signal";
12
12
  import { SignalOrPrimitive } from "./types";
13
13
  import { Size } from "./types/DisplayObject";
14
14
  import { Scheduler, Tick } from "../directives/Scheduler";
15
+ import { GlobalAssetLoader } from "../utils/GlobalAssetLoader";
15
16
 
16
17
  interface CanvasElement extends Element<ComponentInstance> {
17
18
  render: (rootElement: HTMLElement, app?: Application) => void;
@@ -49,11 +50,13 @@ export const Canvas: ComponentFunction<CanvasProps> = async (props = {}) => {
49
50
  });
50
51
 
51
52
  props.isRoot = true;
53
+ const globalLoader = new GlobalAssetLoader();
52
54
  const options: CanvasProps = {
53
55
  ...props,
54
56
  context: {
55
57
  canvasSize,
56
58
  app: signal(null),
59
+ globalLoader,
57
60
  },
58
61
  width: width?.(),
59
62
  height: height?.(),