canvasengine 2.0.0-beta.3 → 2.0.0-beta.30

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 (130) hide show
  1. package/dist/DebugRenderer-DcvJLrrD.js +172 -0
  2. package/dist/DebugRenderer-DcvJLrrD.js.map +1 -0
  3. package/dist/components/Button.d.ts +136 -0
  4. package/dist/components/Button.d.ts.map +1 -0
  5. package/dist/components/Canvas.d.ts +18 -0
  6. package/dist/components/Canvas.d.ts.map +1 -0
  7. package/dist/components/Container.d.ts +80 -0
  8. package/dist/components/Container.d.ts.map +1 -0
  9. package/dist/components/DOMContainer.d.ts +77 -0
  10. package/dist/components/DOMContainer.d.ts.map +1 -0
  11. package/dist/components/DOMElement.d.ts +44 -0
  12. package/dist/components/DOMElement.d.ts.map +1 -0
  13. package/dist/components/DisplayObject.d.ts +82 -0
  14. package/dist/components/DisplayObject.d.ts.map +1 -0
  15. package/dist/components/Graphic.d.ts +65 -0
  16. package/dist/components/Graphic.d.ts.map +1 -0
  17. package/dist/components/Mesh.d.ts +202 -0
  18. package/dist/components/Mesh.d.ts.map +1 -0
  19. package/dist/components/NineSliceSprite.d.ts +17 -0
  20. package/dist/components/NineSliceSprite.d.ts.map +1 -0
  21. package/dist/components/ParticleEmitter.d.ts +5 -0
  22. package/dist/components/ParticleEmitter.d.ts.map +1 -0
  23. package/dist/components/Scene.d.ts +2 -0
  24. package/dist/components/Scene.d.ts.map +1 -0
  25. package/dist/components/Sprite.d.ts +174 -0
  26. package/dist/components/Sprite.d.ts.map +1 -0
  27. package/dist/components/Text.d.ts +21 -0
  28. package/dist/components/Text.d.ts.map +1 -0
  29. package/dist/components/TilingSprite.d.ts +18 -0
  30. package/dist/components/TilingSprite.d.ts.map +1 -0
  31. package/dist/components/Video.d.ts +15 -0
  32. package/dist/components/Video.d.ts.map +1 -0
  33. package/dist/components/Viewport.d.ts +106 -0
  34. package/dist/components/Viewport.d.ts.map +1 -0
  35. package/dist/components/index.d.ts +17 -0
  36. package/dist/components/index.d.ts.map +1 -0
  37. package/dist/components/types/DisplayObject.d.ts +106 -0
  38. package/dist/components/types/DisplayObject.d.ts.map +1 -0
  39. package/dist/components/types/MouseEvent.d.ts +4 -0
  40. package/dist/components/types/MouseEvent.d.ts.map +1 -0
  41. package/dist/components/types/Spritesheet.d.ts +366 -0
  42. package/dist/components/types/Spritesheet.d.ts.map +1 -0
  43. package/dist/components/types/index.d.ts +5 -0
  44. package/dist/components/types/index.d.ts.map +1 -0
  45. package/dist/directives/Drag.d.ts +70 -0
  46. package/dist/directives/Drag.d.ts.map +1 -0
  47. package/dist/directives/KeyboardControls.d.ts +530 -0
  48. package/dist/directives/KeyboardControls.d.ts.map +1 -0
  49. package/dist/directives/Scheduler.d.ts +36 -0
  50. package/dist/directives/Scheduler.d.ts.map +1 -0
  51. package/dist/directives/Sound.d.ts +26 -0
  52. package/dist/directives/Sound.d.ts.map +1 -0
  53. package/dist/directives/Transition.d.ts +11 -0
  54. package/dist/directives/Transition.d.ts.map +1 -0
  55. package/dist/directives/ViewportCull.d.ts +12 -0
  56. package/dist/directives/ViewportCull.d.ts.map +1 -0
  57. package/dist/directives/ViewportFollow.d.ts +19 -0
  58. package/dist/directives/ViewportFollow.d.ts.map +1 -0
  59. package/dist/directives/index.d.ts +2 -0
  60. package/dist/directives/index.d.ts.map +1 -0
  61. package/dist/engine/animation.d.ts +59 -0
  62. package/dist/engine/animation.d.ts.map +1 -0
  63. package/dist/engine/bootstrap.d.ts +16 -0
  64. package/dist/engine/bootstrap.d.ts.map +1 -0
  65. package/dist/engine/directive.d.ts +14 -0
  66. package/dist/engine/directive.d.ts.map +1 -0
  67. package/dist/engine/reactive.d.ts +95 -0
  68. package/dist/engine/reactive.d.ts.map +1 -0
  69. package/dist/engine/signal.d.ts +72 -0
  70. package/dist/engine/signal.d.ts.map +1 -0
  71. package/dist/engine/trigger.d.ts +51 -0
  72. package/dist/engine/trigger.d.ts.map +1 -0
  73. package/dist/engine/utils.d.ts +90 -0
  74. package/dist/engine/utils.d.ts.map +1 -0
  75. package/dist/hooks/addContext.d.ts +2 -0
  76. package/dist/hooks/addContext.d.ts.map +1 -0
  77. package/dist/hooks/useProps.d.ts +42 -0
  78. package/dist/hooks/useProps.d.ts.map +1 -0
  79. package/dist/hooks/useRef.d.ts +5 -0
  80. package/dist/hooks/useRef.d.ts.map +1 -0
  81. package/dist/index-C-iY-lCt.js +11080 -0
  82. package/dist/index-C-iY-lCt.js.map +1 -0
  83. package/dist/index.d.ts +15 -919
  84. package/dist/index.d.ts.map +1 -0
  85. package/dist/index.global.js +29 -0
  86. package/dist/index.global.js.map +1 -0
  87. package/dist/index.js +63 -2950
  88. package/dist/index.js.map +1 -1
  89. package/dist/utils/Ease.d.ts +17 -0
  90. package/dist/utils/Ease.d.ts.map +1 -0
  91. package/dist/utils/RadialGradient.d.ts +58 -0
  92. package/dist/utils/RadialGradient.d.ts.map +1 -0
  93. package/dist/utils/functions.d.ts +2 -0
  94. package/dist/utils/functions.d.ts.map +1 -0
  95. package/index.d.ts +4 -0
  96. package/package.json +12 -7
  97. package/src/components/Button.ts +269 -0
  98. package/src/components/Canvas.ts +53 -45
  99. package/src/components/Container.ts +2 -2
  100. package/src/components/DOMContainer.ts +123 -0
  101. package/src/components/DOMElement.ts +421 -0
  102. package/src/components/DisplayObject.ts +283 -190
  103. package/src/components/Graphic.ts +200 -34
  104. package/src/components/Mesh.ts +222 -0
  105. package/src/components/NineSliceSprite.ts +4 -1
  106. package/src/components/ParticleEmitter.ts +12 -8
  107. package/src/components/Sprite.ts +92 -22
  108. package/src/components/Text.ts +34 -14
  109. package/src/components/Video.ts +110 -0
  110. package/src/components/Viewport.ts +59 -43
  111. package/src/components/index.ts +7 -2
  112. package/src/components/types/DisplayObject.ts +30 -0
  113. package/src/directives/Drag.ts +357 -52
  114. package/src/directives/KeyboardControls.ts +3 -1
  115. package/src/directives/Sound.ts +94 -31
  116. package/src/directives/ViewportFollow.ts +35 -7
  117. package/src/engine/animation.ts +41 -5
  118. package/src/engine/bootstrap.ts +23 -3
  119. package/src/engine/directive.ts +2 -2
  120. package/src/engine/reactive.ts +472 -172
  121. package/src/engine/signal.ts +18 -2
  122. package/src/engine/trigger.ts +65 -9
  123. package/src/engine/utils.ts +97 -9
  124. package/src/hooks/useProps.ts +1 -1
  125. package/src/index.ts +4 -1
  126. package/src/utils/RadialGradient.ts +29 -0
  127. package/src/utils/functions.ts +7 -0
  128. package/testing/index.ts +12 -0
  129. package/tsconfig.json +17 -0
  130. package/vite.config.ts +39 -0
@@ -1,5 +1,7 @@
1
- import { computed, effect, isSignal, Signal, WritableSignal } from "@signe/reactive";
1
+ import { Howl } from 'howler';
2
+ import { computed, effect, isSignal, Signal } from "@signe/reactive";
2
3
  import {
4
+ Application,
3
5
  Assets,
4
6
  Container,
5
7
  Sprite as PixiSprite,
@@ -10,6 +12,7 @@ import { Subscription } from "rxjs";
10
12
  import {
11
13
  Element,
12
14
  createComponent,
15
+ isElement,
13
16
  registerComponent,
14
17
  } from "../engine/reactive";
15
18
  import { arrayEquals, isFunction } from "../engine/utils";
@@ -24,6 +27,7 @@ import {
24
27
  import { ComponentFunction } from "../engine/signal";
25
28
  import { DisplayObjectProps } from "./types/DisplayObject";
26
29
  import { AnimatedSignal, isAnimatedSignal } from "../engine/animation";
30
+ import { Layout } from '@pixi/layout';
27
31
 
28
32
  const log = console.log;
29
33
 
@@ -73,14 +77,25 @@ export class CanvasSprite extends DisplayObject(PixiSprite) {
73
77
  private subscriptionSheet: Subscription[] = [];
74
78
  private sheetParams: any = {};
75
79
  private sheetCurrentAnimation: string = StandardAnimation.Stand;
80
+ private app: Application | null = null;
76
81
  onFinish: () => void;
77
82
 
83
+ get renderer() {
84
+ return this.app?.renderer;
85
+ }
86
+
78
87
  private currentAnimationContainer: Container | null = null;
79
88
 
80
89
  private async createTextures(
81
90
  options: Required<TextureOptionsMerging>
82
91
  ): Promise<Texture[][]> {
83
92
  const { width, height, framesHeight, framesWidth, image, offset } = options;
93
+
94
+ if (!image || typeof image !== 'string' || image.trim() === '') {
95
+ console.warn('Invalid image path provided to createTextures:', image);
96
+ return [];
97
+ }
98
+
84
99
  const texture = await Assets.load(image);
85
100
  const spriteWidth = options.spriteWidth;
86
101
  const spriteHeight = options.spriteHeight;
@@ -167,10 +182,12 @@ export class CanvasSprite extends DisplayObject(PixiSprite) {
167
182
  const { props, propObservables } = params;
168
183
  const tick: Signal = props.context.tick;
169
184
  const sheet = props.sheet ?? {};
185
+ this.app = props.context.app();
170
186
  if (sheet?.onFinish) {
171
187
  this.onFinish = sheet.onFinish;
172
188
  }
173
189
  this.subscriptionTick = tick.observable.subscribe((value) => {
190
+ if (this.destroyed) return
174
191
  this.update(value);
175
192
  });
176
193
  if (props.sheet?.definition) {
@@ -218,15 +235,38 @@ export class CanvasSprite extends DisplayObject(PixiSprite) {
218
235
  this.sheetCurrentAnimation = StandardAnimation.Stand;
219
236
  }
220
237
 
221
- this.play(this.sheetCurrentAnimation, [this.sheetParams]);
238
+ if (this.spritesheet) this.play(this.sheetCurrentAnimation, [this.sheetParams]);
222
239
  });
223
-
224
240
  super.onMount(params);
225
241
  }
226
242
 
227
243
  async onUpdate(props) {
244
+ if (this.destroyed) return
228
245
  super.onUpdate(props);
229
246
 
247
+ const setTexture = async (image: string) => {
248
+ if (!image || typeof image !== 'string' || image.trim() === '') {
249
+ console.warn('Invalid image path provided to setTexture:', image);
250
+ return null;
251
+ }
252
+
253
+ const onProgress = this.fullProps.loader?.onProgress;
254
+ const texture = await Assets.load(image, (progress) => {
255
+ if (onProgress) onProgress(progress);
256
+ if (progress == 1) {
257
+ const onComplete = this.fullProps.loader?.onComplete;
258
+ if (onComplete) {
259
+ // hack to memoize the texture
260
+ setTimeout(() => {
261
+ onComplete(texture);
262
+ });
263
+ }
264
+ }
265
+ });
266
+
267
+ return texture
268
+ }
269
+
230
270
  const sheet = props.sheet;
231
271
  if (sheet?.params) this.sheetParams = sheet?.params;
232
272
 
@@ -235,32 +275,50 @@ export class CanvasSprite extends DisplayObject(PixiSprite) {
235
275
  this.play(this.sheetCurrentAnimation, [this.sheetParams]);
236
276
  }
237
277
 
238
- if (props.hitbox) this.hitbox = props.hitbox;
278
+ if (props.hitbox) this.hitbox = props.hitbox.value ?? props.hitbox;
239
279
 
240
280
  if (props.scaleMode) this.baseTexture.scaleMode = props.scaleMode;
241
281
  else if (props.image && this.fullProps.rectangle === undefined) {
242
- this.texture = await Assets.load(this.fullProps.image);
282
+ const texture = await setTexture(this.fullProps.image);
283
+ if (texture) {
284
+ this.texture = texture;
285
+ }
243
286
  } else if (props.texture) {
244
- this.texture = props.texture;
287
+ if (isElement(props.texture)) {
288
+ const textureInstance = props.texture.componentInstance;
289
+ textureInstance.subjectInit
290
+ .subscribe((value) => {
291
+ console.log('a', value?.width)
292
+ })
293
+ this.texture = this.renderer?.generateTexture(props.texture.componentInstance);
294
+ } else {
295
+ this.texture = props.texture;
296
+ }
245
297
  }
246
-
247
298
  if (props.rectangle !== undefined) {
248
299
  const { x, y, width, height } = props.rectangle?.value ?? props.rectangle;
249
- const texture = await Assets.load(this.fullProps.image);
250
- this.texture = new Texture({
251
- source: texture.source,
252
- frame: new Rectangle(x, y, width, height),
253
- });
300
+ const texture = await setTexture(this.fullProps.image);
301
+ if (texture) {
302
+ this.texture = new Texture({
303
+ source: texture.source,
304
+ frame: new Rectangle(x, y, width, height),
305
+ });
306
+ }
254
307
  }
255
308
  }
256
309
 
257
- onDestroy(): void {
258
- super.onDestroy();
259
- this.subscriptionSheet.forEach((sub) => sub.unsubscribe());
260
- this.subscriptionTick.unsubscribe();
261
- if (this.currentAnimationContainer && this.parent instanceof Container) {
262
- this.parent.removeChild(this.currentAnimationContainer);
263
- }
310
+ async onDestroy(parent: Element, afterDestroy: () => void): Promise<void> {
311
+ const _afterDestroy = async () => {
312
+ this.subscriptionSheet.forEach((sub) => sub.unsubscribe());
313
+ this.subscriptionTick.unsubscribe();
314
+ if (this.currentAnimationContainer && this.parent instanceof Container) {
315
+ this.parent.removeChild(this.currentAnimationContainer);
316
+ }
317
+ if (afterDestroy) {
318
+ afterDestroy();
319
+ }
320
+ };
321
+ await super.onDestroy(parent, _afterDestroy);
264
322
  }
265
323
 
266
324
  has(name: string): boolean {
@@ -295,7 +353,7 @@ export class CanvasSprite extends DisplayObject(PixiSprite) {
295
353
  );
296
354
  }
297
355
 
298
- const cloneParams = structuredClone(params);
356
+ const cloneParams = (params);
299
357
 
300
358
  this.removeChildren();
301
359
  animation.sprites = [];
@@ -321,7 +379,12 @@ export class CanvasSprite extends DisplayObject(PixiSprite) {
321
379
  const sound = this.currentAnimation.data.sound;
322
380
 
323
381
  if (sound) {
324
- //RpgSound.get(sound).play()
382
+ new Howl({
383
+ src: sound,
384
+ autoplay: true,
385
+ loop: false,
386
+ volume: 1,
387
+ })
325
388
  }
326
389
 
327
390
  // Updates immediately to avoid flickering
@@ -396,6 +459,7 @@ export class CanvasSprite extends DisplayObject(PixiSprite) {
396
459
  const widthOfSprite =
397
460
  typeof realSize == "number" ? realSize : realSize?.width;
398
461
 
462
+
399
463
  const applyAnchorBySize = () => {
400
464
  if (heightOfSprite && this.hitbox) {
401
465
  const { spriteWidth, spriteHeight } = data;
@@ -440,7 +504,9 @@ export class CanvasSprite extends DisplayObject(PixiSprite) {
440
504
  }
441
505
  }
442
506
 
443
- export interface CanvasSprite extends PixiSprite {}
507
+ export interface CanvasSprite extends PixiSprite {
508
+ layout: Layout | null;
509
+ }
444
510
 
445
511
  registerComponent("Sprite", CanvasSprite);
446
512
 
@@ -483,6 +549,10 @@ export interface SpritePropsWithSheet
483
549
  params?: any;
484
550
  onFinish?: () => void;
485
551
  };
552
+ loader?: {
553
+ onProgress?: (progress: number) => void;
554
+ onComplete?: (texture: Texture) => void;
555
+ };
486
556
  }
487
557
 
488
558
  export type SpritePropTypes = SpritePropsWithImage | SpritePropsWithSheet;
@@ -1,15 +1,15 @@
1
1
  import { Text as PixiText, TextStyle } from "pixi.js";
2
- import { createComponent, registerComponent } from "../engine/reactive";
3
- import { DisplayObject } from "./DisplayObject";
2
+ import { createComponent, registerComponent, Element, Props } from "../engine/reactive";
3
+ import { DisplayObject, ComponentInstance } from "./DisplayObject";
4
4
  import { DisplayObjectProps } from "./types/DisplayObject";
5
5
  import { Signal } from "@signe/reactive";
6
- import { on } from "../engine/trigger";
6
+ import { on, isTrigger } from "../engine/trigger";
7
7
 
8
8
  enum TextEffect {
9
9
  Typewriter = "typewriter",
10
10
  }
11
11
 
12
- interface TextProps extends DisplayObjectProps {
12
+ export interface TextProps extends DisplayObjectProps {
13
13
  text?: string;
14
14
  style?: Partial<TextStyle>;
15
15
  color?: string;
@@ -21,6 +21,7 @@ interface TextProps extends DisplayObjectProps {
21
21
  onComplete?: () => void;
22
22
  skip?: () => void;
23
23
  };
24
+ context?: any; // Ensure context is available, ideally typed from a base prop or injected
24
25
  }
25
26
 
26
27
  class CanvasText extends DisplayObject(PixiText) {
@@ -32,9 +33,15 @@ class CanvasText extends DisplayObject(PixiText) {
32
33
  private typewriterOptions: any = {};
33
34
  private skipSignal?: () => void;
34
35
 
35
- onMount(args) {
36
- super.onMount(args);
37
- const { props } = args;
36
+ /**
37
+ * Called when the component is mounted to the scene graph.
38
+ * Initializes the typewriter effect if configured.
39
+ * @param {Element<CanvasText>} element - The element being mounted with parent and props.
40
+ * @param {number} [index] - The index of the component among its siblings.
41
+ */
42
+ async onMount(element: Element<CanvasText>, index?: number): Promise<void> {
43
+ const { props } = element;
44
+ await super.onMount(element, index);
38
45
  const tick: Signal = props.context.tick;
39
46
 
40
47
  if (props.text && props.typewriter) {
@@ -44,7 +51,7 @@ class CanvasText extends DisplayObject(PixiText) {
44
51
  // Set typewriter options
45
52
  if (props.typewriter) {
46
53
  this.typewriterOptions = props.typewriter;
47
- if (this.typewriterOptions.skip) {
54
+ if (this.typewriterOptions.skip && isTrigger(this.typewriterOptions.skip)) {
48
55
  on(this.typewriterOptions.skip, () => {
49
56
  this.skipTypewriter();
50
57
  });
@@ -65,8 +72,8 @@ class CanvasText extends DisplayObject(PixiText) {
65
72
  this.typewriterOptions = props.typewriter;
66
73
  }
67
74
  }
68
- if (props.text) {
69
- this.text = props.text;
75
+ if (props.text !== undefined) {
76
+ this.text = ''+props.text;
70
77
  }
71
78
  if (props.text !== undefined && props.text !== this.fullText && this.fullProps.typewriter) {
72
79
  this.text = "";
@@ -130,13 +137,26 @@ class CanvasText extends DisplayObject(PixiText) {
130
137
  this.currentIndex = this.fullText.length;
131
138
  }
132
139
 
133
- onDestroy(): void {
134
- super.onDestroy();
135
- this.subscriptionTick.unsubscribe();
140
+ /**
141
+ * Called when the component is about to be destroyed.
142
+ * Unsubscribes from the tick observable.
143
+ * @param {Element<any>} parent - The parent element.
144
+ * @param {() => void} [afterDestroy] - An optional callback function to be executed after the component's own destruction logic.
145
+ */
146
+ async onDestroy(parent: Element<any>, afterDestroy?: () => void): Promise<void> {
147
+ const _afterDestroy = async () => {
148
+ if (this.subscriptionTick) {
149
+ this.subscriptionTick.unsubscribe();
150
+ }
151
+ if (afterDestroy) {
152
+ afterDestroy();
153
+ }
154
+ }
155
+ await super.onDestroy(parent, _afterDestroy);
136
156
  }
137
157
  }
138
158
 
139
- interface CanvasText extends PixiText {}
159
+ // interface CanvasText extends PixiText {} // Removed as it's redundant and causes type conflicts
140
160
 
141
161
  registerComponent("Text", CanvasText);
142
162
 
@@ -0,0 +1,110 @@
1
+ import { Texture } from "pixi.js";
2
+ import { h, mount } from "../engine/signal";
3
+ import { useDefineProps } from "../hooks/useProps";
4
+ import { Sprite } from "./Sprite";
5
+ import { effect, Signal, signal } from "@signe/reactive";
6
+
7
+ interface VideoProps {
8
+ src: string;
9
+ paused?: boolean;
10
+ loop?: boolean;
11
+ muted?: boolean;
12
+ loader?: {
13
+ onComplete?: (texture: Texture) => void;
14
+ onProgress?: (progress: number) => void;
15
+ };
16
+ }
17
+
18
+ export function Video(props: VideoProps) {
19
+ const eventsMap = {
20
+ audioprocess: null,
21
+ canplay: null,
22
+ canplaythrough: null,
23
+ complete: null,
24
+ durationchange: null,
25
+ emptied: null,
26
+ ended: null,
27
+ loadeddata: null,
28
+ loadedmetadata: null,
29
+ pause: null,
30
+ play: null,
31
+ playing: null,
32
+ progress: null,
33
+ ratechange: null,
34
+ seeked: null,
35
+ seeking: null,
36
+ stalled: null,
37
+ suspend: null,
38
+ timeupdate: null,
39
+ volumechange: null,
40
+ waiting: null
41
+ }
42
+
43
+ const video: Signal<HTMLVideoElement | null> = signal(null)
44
+ const defineProps = useDefineProps(props)
45
+ const { play, loop, muted } = defineProps({
46
+ play: {
47
+ type: Boolean,
48
+ default: true
49
+ },
50
+ loop: {
51
+ type: Boolean,
52
+ default: false
53
+ },
54
+ muted: {
55
+ type: Boolean,
56
+ default: false
57
+ }
58
+ })
59
+
60
+ effect(() => {
61
+ const _video = video()
62
+ const state = play()
63
+ if (_video && state !== undefined) {
64
+ if (state) {
65
+ _video.play()
66
+ } else {
67
+ _video.pause()
68
+ }
69
+ }
70
+ if (_video && loop()) {
71
+ _video.loop = loop()
72
+ }
73
+ if (_video && muted()) {
74
+ _video.muted = muted()
75
+ }
76
+ })
77
+
78
+ mount(() => {
79
+ return () => {
80
+ for (let event in eventsMap) {
81
+ if (eventsMap[event]) {
82
+ video().removeEventListener(event, eventsMap[event])
83
+ }
84
+ }
85
+ }
86
+ })
87
+
88
+ return h(Sprite, {
89
+ ...props,
90
+ image: props.src,
91
+ loader: {
92
+ onComplete: (texture) => {
93
+ const source = texture.source.resource
94
+ video.set(source)
95
+ if (props?.loader?.onComplete) {
96
+ props.loader.onComplete(texture)
97
+ }
98
+ for (let event in eventsMap) {
99
+ if (props[event]) {
100
+ const cb = (ev) => {
101
+ props[event](ev)
102
+ }
103
+ eventsMap[event] = cb
104
+ source.addEventListener(event, cb)
105
+ }
106
+ }
107
+ }
108
+ }
109
+ })
110
+ }
@@ -1,8 +1,8 @@
1
1
  import { Viewport as PixiViewport } from 'pixi-viewport';
2
2
  import { Subscription } from 'rxjs';
3
- import { createComponent, registerComponent } from '../engine/reactive';
4
- import { DisplayObject } from './DisplayObject';
5
- import { effect } from '@signe/reactive';
3
+ import { createComponent, registerComponent, Element, Props } from '../engine/reactive';
4
+ import { DisplayObject, ComponentInstance } from './DisplayObject';
5
+ import { effect, Signal } from '@signe/reactive';
6
6
 
7
7
  const EVENTS = [
8
8
  'bounce-x-end',
@@ -28,6 +28,21 @@ const EVENTS = [
28
28
  'zoomed-end'
29
29
  ]
30
30
 
31
+ export interface ViewportProps extends Props {
32
+ screenWidth?: number;
33
+ screenHeight?: number;
34
+ worldWidth?: number;
35
+ worldHeight?: number;
36
+ clamp?: boolean | {
37
+ left?: number;
38
+ right?: number;
39
+ top?: number;
40
+ bottom?: number;
41
+ };
42
+ context?: any;
43
+ [key: string]: any;
44
+ }
45
+
31
46
  export class CanvasViewport extends DisplayObject(PixiViewport) {
32
47
  private tickSubscription: Subscription
33
48
  overrideProps = ['wheel']
@@ -48,16 +63,20 @@ export class CanvasViewport extends DisplayObject(PixiViewport) {
48
63
  onInit(props) {
49
64
  super.onInit(props)
50
65
  for (let event of EVENTS) {
51
- const camelCaseEvent = event.replace(/-([a-z])/g, (g) => g[1].toUpperCase());
52
- if (props[camelCaseEvent]) {
53
- this.on(event, props[camelCaseEvent])
54
- }
66
+ if (props[event]) this.on(event, props[event])
55
67
  }
56
68
  }
57
69
 
58
- onMount(element) {
59
- super.onMount(element)
60
- const { tick, renderer, canvasSize } = element.props.context
70
+ /**
71
+ * Called when the component is mounted to the scene graph.
72
+ * Initializes viewport settings and subscriptions.
73
+ * @param {Element<CanvasViewport>} element - The element being mounted. Its `props` property (of type ViewportProps) contains component properties and context.
74
+ * @param {number} [index] - The index of the component among its siblings.
75
+ */
76
+ async onMount(element: Element<CanvasViewport>, index?: number): Promise<void> {
77
+ await super.onMount(element, index);
78
+ const { props } = element;
79
+ const { tick, app, canvasSize } = props.context;
61
80
  let isDragging = false
62
81
 
63
82
  effect(() => {
@@ -65,18 +84,26 @@ export class CanvasViewport extends DisplayObject(PixiViewport) {
65
84
  this.screenHeight = canvasSize().height
66
85
  })
67
86
 
68
- renderer.events.domElement.addEventListener(
69
- 'wheel',
70
- this.input.wheelFunction
71
- );
72
- this.options.events = renderer.events
87
+ effect(() => {
88
+ const _app = app()
89
+ if (!_app) return
90
+
91
+ const renderer = _app.renderer
92
+
93
+ renderer.events.domElement.addEventListener(
94
+ 'wheel',
95
+ this.input.wheelFunction
96
+ );
97
+
98
+ this.options.events = renderer.events
99
+ })
73
100
 
74
101
  this.tickSubscription = tick.observable.subscribe(({ value }) => {
75
102
  this.update(value.timestamp)
76
103
  })
77
104
 
78
105
  element.props.context.viewport = this
79
- this.updateViewportSettings(element.props)
106
+ this.updateViewportSettings(props)
80
107
  }
81
108
 
82
109
  onUpdate(props) {
@@ -97,15 +124,11 @@ export class CanvasViewport extends DisplayObject(PixiViewport) {
97
124
  if (props.worldHeight !== undefined) {
98
125
  this.worldHeight = props.worldHeight
99
126
  }
100
- // if (props.drag) {
101
- // if (props.drag === true) {
102
-
103
- // } else {
104
- // this.drag(props.drag)
105
- // }
106
- // }
127
+ if (props.drag) {
128
+ this.drag(props.drag)
129
+ }
107
130
  if (props.clamp) {
108
- this.clamp(props.clamp)
131
+ this.clamp(props.clamp.value ?? props.clamp)
109
132
  }
110
133
  if (props.wheel) {
111
134
  if (props.wheel === true) {
@@ -130,30 +153,23 @@ export class CanvasViewport extends DisplayObject(PixiViewport) {
130
153
  }
131
154
  }
132
155
 
133
- onDestroy(): void {
134
- super.onDestroy()
135
- this.tickSubscription.unsubscribe()
156
+ /**
157
+ * Called when the component is about to be destroyed.
158
+ * Unsubscribes from the tick observable.
159
+ * @param {Element<any>} parent - The parent element.
160
+ * @param {() => void} [afterDestroy] - An optional callback function to be executed after the component's own destruction logic.
161
+ */
162
+ async onDestroy(parent: Element<any>, afterDestroy?: () => void): Promise<void> {
163
+ const _afterDestroy = async () => {
164
+ this.tickSubscription.unsubscribe()
165
+ afterDestroy()
166
+ }
167
+ await super.onDestroy(parent, _afterDestroy);
136
168
  }
137
169
  }
138
170
 
139
- export interface CanvasViewport extends PixiViewport { }
140
-
141
171
  registerComponent('Viewport', CanvasViewport)
142
172
 
143
- export interface ViewportProps {
144
- screenWidth?: number;
145
- screenHeight?: number;
146
- worldWidth?: number;
147
- worldHeight?: number;
148
- clamp?: boolean | {
149
- left?: number;
150
- right?: number;
151
- top?: number;
152
- bottom?: number;
153
- };
154
- [key: string]: any;
155
- }
156
-
157
173
  export function Viewport(props: ViewportProps) {
158
174
  return createComponent('Viewport', props);
159
175
  }
@@ -1,11 +1,16 @@
1
1
  export { Canvas } from './Canvas'
2
2
  export { Container } from './Container'
3
- export { Graphics, Rect, Circle, Ellipse, Triangle, Svg as svg } from './Graphic'
3
+ export { Graphics, Rect, Circle, Ellipse, Triangle, Svg } from './Graphic'
4
+ export { Mesh } from './Mesh'
4
5
  export { Scene } from './Scene'
5
6
  export { ParticlesEmitter } from './ParticleEmitter'
6
7
  export { Sprite } from './Sprite'
8
+ export { Video } from './Video'
7
9
  export { Text } from './Text'
8
10
  export { TilingSprite } from './TilingSprite'
9
11
  export { Viewport } from './Viewport'
10
12
  export { NineSliceSprite } from './NineSliceSprite'
11
- export { type ComponentInstance } from './DisplayObject'
13
+ export { type ComponentInstance } from './DisplayObject'
14
+ export { DOMContainer } from './DOMContainer'
15
+ export { DOMElement } from './DOMElement'
16
+ export { Button, ButtonState, type ButtonProps, type ButtonStyle } from './Button'
@@ -1,18 +1,43 @@
1
1
  import * as PIXI from "pixi.js";
2
2
  import { SignalOrPrimitive } from ".";
3
+ import { DragProps } from "../../directives/Drag";
4
+ import { ViewportFollowProps } from "../../directives/ViewportFollow";
3
5
 
4
6
  export type FlexDirection = 'row' | 'column' | 'row-reverse' | 'column-reverse';
5
7
  export type JustifyContent = 'flex-start' | 'flex-end' | 'center' | 'space-between' | 'space-around';
6
8
  export type AlignContent = 'flex-start' | 'flex-end' | 'center' | 'space-between' | 'space-around';
7
9
  export type Size = number | `${number}%`
8
10
  export type EdgeSize = SignalOrPrimitive<Size | [Size, Size] | [Size, Size, Size, Size]>
11
+ export type ObjectFit = 'contain' | 'cover' | 'fill' | 'none' | 'scale-down';
12
+ export type ObjectPosition = string;
13
+ export type TransformOrigin = string;
14
+ export type PositionType = 'relative' | 'absolute' | 'static';
9
15
 
10
16
  export interface DisplayObjectProps {
17
+ attach?: any;
11
18
  ref?: string;
12
19
  x?: SignalOrPrimitive<number>;
13
20
  y?: SignalOrPrimitive<number>;
14
21
  width?: SignalOrPrimitive<Size>;
15
22
  height?: SignalOrPrimitive<Size>;
23
+ minWidth?: SignalOrPrimitive<Size>;
24
+ minHeight?: SignalOrPrimitive<Size>;
25
+ maxWidth?: SignalOrPrimitive<Size>;
26
+ maxHeight?: SignalOrPrimitive<Size>;
27
+ aspectRatio?: SignalOrPrimitive<number>;
28
+ flexGrow?: SignalOrPrimitive<number>;
29
+ flexShrink?: SignalOrPrimitive<number>;
30
+ flexBasis?: SignalOrPrimitive<Size>;
31
+ rowGap?: SignalOrPrimitive<number>;
32
+ columnGap?: SignalOrPrimitive<number>;
33
+ positionType?: PositionType;
34
+ top?: SignalOrPrimitive<Size>;
35
+ right?: SignalOrPrimitive<Size>;
36
+ bottom?: SignalOrPrimitive<Size>;
37
+ left?: SignalOrPrimitive<Size>;
38
+ objectFit?: ObjectFit;
39
+ objectPosition?: ObjectPosition;
40
+ transformOrigin?: TransformOrigin;
16
41
  children?: any[];
17
42
  flexDirection?: FlexDirection;
18
43
  justifyContent?: JustifyContent;
@@ -36,6 +61,11 @@ export interface DisplayObjectProps {
36
61
  blendMode?: SignalOrPrimitive<PIXI.BLEND_MODES>;
37
62
  blur?: SignalOrPrimitive<number>;
38
63
 
64
+ // Directives
65
+ drag?: DragProps;
66
+ viewportFollow?: ViewportFollowProps;
67
+
68
+ // Events
39
69
  click?: PIXI.FederatedEventHandler;
40
70
  mousedown?: PIXI.FederatedEventHandler;
41
71
  mouseenter?: PIXI.FederatedEventHandler;