canvasengine 2.0.0-beta.16 → 2.0.0-beta.18

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.
@@ -1,22 +1,24 @@
1
- import { Node } from "yoga-layout";
2
1
  import { Element, isElement, Props } from "../engine/reactive";
3
2
  import { setObservablePoint } from "../engine/utils";
4
3
  import type {
5
4
  AlignContent,
6
5
  EdgeSize,
7
6
  FlexDirection,
8
- Size,
7
+ ObjectFit,
8
+ ObjectPosition,
9
+ TransformOrigin,
9
10
  } from "./types/DisplayObject";
10
- import { effect, Signal, signal } from "@signe/reactive";
11
+ import { signal } from "@signe/reactive";
11
12
  import { DropShadowFilter } from "pixi-filters";
12
13
  import { BlurFilter, ObservablePoint } from "pixi.js";
14
+ import { isPercent } from "../utils/functions";
13
15
 
14
16
  export interface ComponentInstance extends PixiMixins.ContainerOptions {
15
17
  id?: string;
16
18
  children?: ComponentInstance[];
17
19
  onInit?(props: Props): void;
18
20
  onUpdate?(props: Props): void;
19
- onDestroy?(parent: Element): void;
21
+ onDestroy?(parent: Element, afterDestroy: () => void): void;
20
22
  onMount?(context: Element, index?: number): void;
21
23
  setWidth(width: number): void;
22
24
  setHeight(height: number): void;
@@ -93,6 +95,8 @@ export const EVENTS = [
93
95
  "wheelcapture",
94
96
  ];
95
97
 
98
+ type OnHook = (() => void) | (() => Promise<void> | void);
99
+
96
100
  export function DisplayObject(extendClass) {
97
101
  return class DisplayObject extends extendClass {
98
102
  #canvasContext: {
@@ -101,20 +105,14 @@ export function DisplayObject(extendClass) {
101
105
  isFlex: boolean = false;
102
106
  fullProps: Props = {};
103
107
  isMounted: boolean = false;
104
- _anchorPoints = new ObservablePoint(
105
- { _onUpdate: () => {} },
106
- 0,
107
- 0
108
- );
108
+ _anchorPoints = new ObservablePoint({ _onUpdate: () => {} }, 0, 0);
109
109
  isCustomAnchor: boolean = false;
110
110
  displayWidth = signal(0);
111
111
  displayHeight = signal(0);
112
112
  overrideProps: string[] = [];
113
- node: Node;
114
-
115
- get yoga() {
116
- return this.#canvasContext?.Yoga;
117
- }
113
+ layout = null;
114
+ onBeforeDestroy: OnHook | null = null;
115
+ onAfterMount: OnHook | null = null;
118
116
 
119
117
  get deltaRatio() {
120
118
  return this.#canvasContext?.scheduler?.tick.value.deltaRatio;
@@ -128,80 +126,45 @@ export function DisplayObject(extendClass) {
128
126
  this.on(event, props[event]);
129
127
  }
130
128
  }
129
+ if (props.onBeforeDestroy || props['on-before-destroy']) {
130
+ this.onBeforeDestroy = props.onBeforeDestroy || props['on-before-destroy'];
131
+ }
132
+ if (props.onAfterMount || props['on-after-mount']) {
133
+ this.onAfterMount = props.onAfterMount || props['on-after-mount'];
134
+ }
135
+ if (
136
+ props.justifyContent ||
137
+ props.alignItems ||
138
+ props.flexDirection ||
139
+ props.flexWrap ||
140
+ props.alignContent ||
141
+ props.display == "flex" ||
142
+ isPercent(props.width) ||
143
+ isPercent(props.height) ||
144
+ props.isRoot
145
+ ) {
146
+ this.layout = {};
147
+ this.isFlex = true;
148
+ }
131
149
  }
132
150
 
133
- onMount({ parent, props }: Element<DisplayObject>, index?: number) {
151
+ async onMount({ parent, props }: Element<DisplayObject>, index?: number) {
134
152
  this.#canvasContext = props.context;
135
- this.node = this.yoga.Node.create();
136
153
  if (parent) {
137
154
  const instance = parent.componentInstance as DisplayObject;
155
+ if (instance.isFlex && !this.layout) {
156
+ this.layout = {};
157
+ }
138
158
  if (index === undefined) {
139
159
  instance.addChild(this);
140
160
  } else {
141
161
  instance.addChildAt(this, index);
142
162
  }
143
- if (instance.layer) this.parentLayer = instance.layer;
144
163
  this.isMounted = true;
145
- this.effectSize(props.width, props.height);
146
164
  this.onUpdate(props);
147
- this.parent.node.insertChild(
148
- this.node,
149
- this.parent.node.getChildCount()
150
- );
151
- if (parent.props.flexDirection) {
152
- this.parent.node.calculateLayout();
153
- for (let child of this.parent.children) {
154
- const { left, top } = child.getComputedLayout();
155
- child.x = left;
156
- child.y = top;
157
- }
158
- }
159
-
160
- }
161
- }
162
-
163
- effectSize(width: Size, height: Size) {
164
- const handleSize = (
165
- size: Size,
166
- setter: (value: number) => void,
167
- parentSize: Signal<number>
168
- ) => {
169
- if (typeof size === "string" && size.endsWith("%")) {
170
- effect(() => {
171
- setter(parentSize() * (parseInt(size) / 100));
172
- if (this.isFlex) {
173
- this.applyFlexLayout();
174
- }
175
- });
176
- } else {
177
- setter(+size);
165
+ if (this.onAfterMount) {
166
+ await this.onAfterMount();
178
167
  }
179
- };
180
-
181
- if (width != undefined)
182
- handleSize(width, this.setWidth.bind(this), this.parent.displayWidth);
183
- if (height != undefined)
184
- handleSize(
185
- height,
186
- this.setHeight.bind(this),
187
- this.parent.displayHeight
188
- );
189
- }
190
-
191
- applyFlexLayout() {
192
- this.calculateLayout();
193
- for (let child of this.children) {
194
- const { left, top } = child.node.getComputedLayout();
195
- child.x = left;
196
- child.y = top;
197
- }
198
- }
199
-
200
- #flexRender(props) {
201
- if (!this.parent) return;
202
- if (props.flexDirection || props.justifyContent) {
203
- this.isFlex = true;
204
- this.applyFlexLayout();
205
168
  }
206
169
  }
207
170
 
@@ -212,6 +175,7 @@ export function DisplayObject(extendClass) {
212
175
  };
213
176
 
214
177
  if (!this.#canvasContext || !this.parent) return;
178
+
215
179
  if (props.x !== undefined) this.setX(props.x);
216
180
  if (props.y !== undefined) this.setY(props.y);
217
181
  if (props.scale !== undefined)
@@ -219,6 +183,28 @@ export function DisplayObject(extendClass) {
219
183
  if (props.anchor !== undefined && !this.isCustomAnchor) {
220
184
  setObservablePoint(this.anchor, props.anchor);
221
185
  }
186
+ if (props.width !== undefined) this.setWidth(props.width);
187
+ if (props.height !== undefined) this.setHeight(props.height);
188
+ if (props.minWidth !== undefined) this.setMinWidth(props.minWidth);
189
+ if (props.minHeight !== undefined) this.setMinHeight(props.minHeight);
190
+ if (props.maxWidth !== undefined) this.setMaxWidth(props.maxWidth);
191
+ if (props.maxHeight !== undefined) this.setMaxHeight(props.maxHeight);
192
+ if (props.aspectRatio !== undefined)
193
+ this.setAspectRatio(props.aspectRatio);
194
+ if (props.flexGrow !== undefined) this.setFlexGrow(props.flexGrow);
195
+ if (props.flexShrink !== undefined) this.setFlexShrink(props.flexShrink);
196
+ if (props.flexBasis !== undefined) this.setFlexBasis(props.flexBasis);
197
+ if (props.rowGap !== undefined) this.setRowGap(props.rowGap);
198
+ if (props.columnGap !== undefined) this.setColumnGap(props.columnGap);
199
+ if (props.top !== undefined) this.setTop(props.top);
200
+ if (props.left !== undefined) this.setLeft(props.left);
201
+ if (props.right !== undefined) this.setRight(props.right);
202
+ if (props.bottom !== undefined) this.setBottom(props.bottom);
203
+ if (props.objectFit !== undefined) this.setObjectFit(props.objectFit);
204
+ if (props.objectPosition !== undefined)
205
+ this.setObjectPosition(props.objectPosition);
206
+ if (props.transformOrigin !== undefined)
207
+ this.setTransformOrigin(props.transformOrigin);
222
208
  if (props.skew !== undefined) setObservablePoint(this.skew, props.skew);
223
209
  if (props.tint) this.tint = props.tint;
224
210
  if (props.rotation !== undefined) this.rotation = props.rotation;
@@ -279,73 +265,34 @@ export function DisplayObject(extendClass) {
279
265
  }
280
266
 
281
267
  this.filters = currentFilters;
282
-
283
- this.#flexRender(props);
284
268
  }
285
269
 
286
- onDestroy() {
270
+ async onDestroy(parent: Element, afterDestroy?: () => void) {
271
+ if (this.onBeforeDestroy) {
272
+ await this.onBeforeDestroy();
273
+ }
287
274
  super.destroy();
288
- this.node?.freeRecursive();
289
- }
290
-
291
- getComputedLayout() {
292
- return this.node.getComputedLayout();
293
- }
294
-
295
- applyComputedLayout() {
296
- const layout = this.getComputedLayout();
297
- this.x = layout.left;
298
- this.y = layout.top;
299
- }
300
-
301
- calculateLayout() {
302
- this.node.calculateLayout();
275
+ if (this.onAfterDestroy) this.onAfterDestroy()
303
276
  }
304
277
 
305
278
  setFlexDirection(direction: FlexDirection) {
306
- const mapping = {
307
- row: this.yoga.FLEX_DIRECTION_ROW,
308
- column: this.yoga.FLEX_DIRECTION_COLUMN,
309
- "row-reverse": this.yoga.FLEX_DIRECTION_ROW_REVERSE,
310
- "column-reverse": this.yoga.FLEX_DIRECTION_COLUMN_REVERSE,
311
- };
312
- this.node.setFlexDirection(mapping[direction]);
279
+ this.layout = { flexDirection: direction };
313
280
  }
314
281
 
315
282
  setFlexWrap(wrap: "wrap" | "nowrap" | "wrap-reverse") {
316
- const mapping = {
317
- wrap: this.yoga.WRAP_WRAP,
318
- nowrap: this.yoga.WRAP_NO_WRAP,
319
- "wrap-reverse": this.yoga.WRAP_WRAP_REVERSE,
320
- };
321
- this.node.setFlexWrap(mapping[wrap]);
322
- }
323
-
324
- #setAlign(methodName: string, align: AlignContent) {
325
- const mapping = {
326
- auto: this.yoga.ALIGN_AUTO,
327
- "flex-start": this.yoga.ALIGN_FLEX_START,
328
- "flex-end": this.yoga.ALIGN_FLEX_END,
329
- center: this.yoga.ALIGN_CENTER,
330
- stretch: this.yoga.ALIGN_STRETCH,
331
- baseline: this.yoga.ALIGN_BASELINE,
332
- "space-between": this.yoga.ALIGN_SPACE_BETWEEN,
333
- "space-around": this.yoga.ALIGN_SPACE_AROUND,
334
- };
335
- const method = (this.node as any)[methodName].bind(this.node);
336
- method(mapping[align]);
283
+ this.layout = { flexWrap: wrap };
337
284
  }
338
285
 
339
286
  setAlignContent(align: AlignContent) {
340
- this.#setAlign("setAlignContent", align);
287
+ this.layout = { alignContent: align };
341
288
  }
342
289
 
343
290
  setAlignSelf(align: AlignContent) {
344
- this.#setAlign("setAlignSelf", align);
291
+ this.layout = { alignSelf: align };
345
292
  }
346
293
 
347
294
  setAlignItems(align: AlignContent) {
348
- this.#setAlign("setAlignItems", align);
295
+ this.layout = { alignItems: align };
349
296
  }
350
297
 
351
298
  setJustifyContent(
@@ -356,95 +303,133 @@ export function DisplayObject(extendClass) {
356
303
  | "space-between"
357
304
  | "space-around"
358
305
  ) {
359
- const mapping = {
360
- "flex-start": this.yoga.JUSTIFY_FLEX_START,
361
- "flex-end": this.yoga.JUSTIFY_FLEX_END,
362
- center: this.yoga.JUSTIFY_CENTER,
363
- "space-between": this.yoga.JUSTIFY_SPACE_BETWEEN,
364
- "space-around": this.yoga.JUSTIFY_SPACE_AROUND,
365
- };
366
- this.node.setJustifyContent(mapping[justifyContent]);
367
- }
368
-
369
- #setEdgeSize(methodName: string, size: EdgeSize) {
370
- const method = (this.node as any)[methodName].bind(this.node);
371
- if (size instanceof Array) {
372
- if (size.length === 2) {
373
- method(this.yoga.EDGE_VERTICAL, size[0]);
374
- method(this.yoga.EDGE_HORIZONTAL, size[1]);
375
- } else if (size.length === 4) {
376
- method(this.yoga.EDGE_TOP, size[0]);
377
- method(this.yoga.EDGE_RIGHT, size[1]);
378
- method(this.yoga.EDGE_BOTTOM, size[2]);
379
- method(this.yoga.EDGE_LEFT, size[3]);
380
- }
381
- } else {
382
- method(this.yoga.EDGE_ALL, size);
383
- }
306
+ this.layout = { justifyContent };
384
307
  }
385
308
 
386
309
  setPosition(position: EdgeSize) {
387
- this.#setEdgeSize("setPosition", position);
310
+ if (position instanceof Array) {
311
+ if (position.length === 2) {
312
+ this.layout = {
313
+ positionY: position[0],
314
+ positionX: position[1],
315
+ };
316
+ } else if (position.length === 4) {
317
+ this.layout = {
318
+ positionTop: position[0],
319
+ positionRight: position[1],
320
+ positionBottom: position[2],
321
+ positionLeft: position[3],
322
+ };
323
+ }
324
+ } else {
325
+ this.layout = { position };
326
+ }
388
327
  }
389
328
 
390
329
  setX(x: number) {
391
330
  x = x + this.getWidth() * this._anchorPoints.x;
392
331
  if (!this.parent.isFlex) {
393
332
  this.x = x;
333
+ } else {
334
+ this.x = x;
335
+ this.layout = { x };
394
336
  }
395
- this.node.setPosition(this.yoga.EDGE_LEFT, x);
396
337
  }
397
338
 
398
339
  setY(y: number) {
399
340
  y = y + this.getHeight() * this._anchorPoints.y;
400
341
  if (!this.parent.isFlex) {
401
342
  this.y = y;
343
+ } else {
344
+ this.y = y;
345
+ this.layout = { y };
402
346
  }
403
- this.node.setPosition(this.yoga.EDGE_TOP, y);
404
347
  }
405
348
 
406
349
  setPadding(padding: EdgeSize) {
407
- this.#setEdgeSize("setPadding", padding);
350
+ if (padding instanceof Array) {
351
+ if (padding.length === 2) {
352
+ this.layout = {
353
+ paddingVertical: padding[0],
354
+ paddingHorizontal: padding[1],
355
+ };
356
+ } else if (padding.length === 4) {
357
+ this.layout = {
358
+ paddingTop: padding[0],
359
+ paddingRight: padding[1],
360
+ paddingBottom: padding[2],
361
+ paddingLeft: padding[3],
362
+ };
363
+ }
364
+ } else {
365
+ this.layout = { padding };
366
+ }
408
367
  }
409
368
 
410
369
  setMargin(margin: EdgeSize) {
411
- this.#setEdgeSize("setMargin", margin);
370
+ if (margin instanceof Array) {
371
+ if (margin.length === 2) {
372
+ this.layout = {
373
+ marginVertical: margin[0],
374
+ marginHorizontal: margin[1],
375
+ };
376
+ } else if (margin.length === 4) {
377
+ this.layout = {
378
+ marginTop: margin[0],
379
+ marginRight: margin[1],
380
+ marginBottom: margin[2],
381
+ marginLeft: margin[3],
382
+ };
383
+ }
384
+ } else {
385
+ this.layout = { margin };
386
+ }
412
387
  }
413
388
 
414
389
  setGap(gap: EdgeSize) {
415
- this.node.setGap(this.yoga.GAP_ALL, +gap);
390
+ this.layout = { gap };
416
391
  }
417
392
 
418
393
  setBorder(border: EdgeSize) {
419
- this.#setEdgeSize("setBorder", border);
394
+ if (border instanceof Array) {
395
+ if (border.length === 2) {
396
+ this.layout = {
397
+ borderVertical: border[0],
398
+ borderHorizontal: border[1],
399
+ };
400
+ } else if (border.length === 4) {
401
+ this.layout = {
402
+ borderTop: border[0],
403
+ borderRight: border[1],
404
+ borderBottom: border[2],
405
+ borderLeft: border[3],
406
+ };
407
+ }
408
+ } else {
409
+ this.layout = { border };
410
+ }
420
411
  }
421
412
 
422
413
  setPositionType(positionType: "relative" | "absolute") {
423
- const mapping = {
424
- relative: this.yoga.POSITION_TYPE_RELATIVE,
425
- absolute: this.yoga.POSITION_TYPE_ABSOLUTE,
426
- };
427
- this.node.setPositionType(mapping[positionType]);
428
- }
429
-
430
- calculateBounds() {
431
- super.calculateBounds();
432
- if (!this._geometry) return;
433
- const bounds = this._geometry.bounds;
434
- const width = Math.abs(bounds.minX - bounds.maxX);
435
- const height = Math.abs(bounds.minY - bounds.maxY);
436
- // this.node.setWidth(width);
437
- // this.node.setHeight(height);
414
+ this.layout = { position: positionType };
438
415
  }
439
416
 
440
417
  setWidth(width: number) {
441
418
  this.displayWidth.set(width);
442
- this.node?.setWidth(width);
419
+ if (!this.parent?.isFlex) {
420
+ this.width = width;
421
+ } else {
422
+ this.layout = { width };
423
+ }
443
424
  }
444
425
 
445
426
  setHeight(height: number) {
446
427
  this.displayHeight.set(height);
447
- this.node?.setHeight(height);
428
+ if (!this.parent?.isFlex) {
429
+ this.height = height;
430
+ } else {
431
+ this.layout = { height };
432
+ }
448
433
  }
449
434
 
450
435
  getWidth() {
@@ -454,5 +439,79 @@ export function DisplayObject(extendClass) {
454
439
  getHeight() {
455
440
  return this.displayHeight();
456
441
  }
442
+
443
+ // Min/Max constraints
444
+ setMinWidth(minWidth: number | string) {
445
+ this.layout = { minWidth };
446
+ }
447
+
448
+ setMinHeight(minHeight: number | string) {
449
+ this.layout = { minHeight };
450
+ }
451
+
452
+ setMaxWidth(maxWidth: number | string) {
453
+ this.layout = { maxWidth };
454
+ }
455
+
456
+ setMaxHeight(maxHeight: number | string) {
457
+ this.layout = { maxHeight };
458
+ }
459
+
460
+ // Aspect ratio
461
+ setAspectRatio(aspectRatio: number) {
462
+ this.layout = { aspectRatio };
463
+ }
464
+
465
+ // Flex properties
466
+ setFlexGrow(flexGrow: number) {
467
+ this.layout = { flexGrow };
468
+ }
469
+
470
+ setFlexShrink(flexShrink: number) {
471
+ this.layout = { flexShrink };
472
+ }
473
+
474
+ setFlexBasis(flexBasis: number | string) {
475
+ this.layout = { flexBasis };
476
+ }
477
+
478
+ // Gap properties
479
+ setRowGap(rowGap: number) {
480
+ this.layout = { rowGap };
481
+ }
482
+
483
+ setColumnGap(columnGap: number) {
484
+ this.layout = { columnGap };
485
+ }
486
+
487
+ // Position insets
488
+ setTop(top: number | string) {
489
+ this.layout = { top };
490
+ }
491
+
492
+ setLeft(left: number | string) {
493
+ this.layout = { left };
494
+ }
495
+
496
+ setRight(right: number | string) {
497
+ this.layout = { right };
498
+ }
499
+
500
+ setBottom(bottom: number | string) {
501
+ this.layout = { bottom };
502
+ }
503
+
504
+ // Object properties
505
+ setObjectFit(objectFit: ObjectFit) {
506
+ this.layout = { objectFit };
507
+ }
508
+
509
+ setObjectPosition(objectPosition: ObjectPosition) {
510
+ this.layout = { objectPosition };
511
+ }
512
+
513
+ setTransformOrigin(transformOrigin: TransformOrigin) {
514
+ this.layout = { transformOrigin };
515
+ }
457
516
  };
458
517
  }
@@ -1,7 +1,7 @@
1
1
  import { Effect, effect, Signal } from "@signe/reactive";
2
2
  import { Graphics as PixiGraphics } from "pixi.js";
3
- import { createComponent, registerComponent } from "../engine/reactive";
4
- import { DisplayObject } from "./DisplayObject";
3
+ import { createComponent, Element, registerComponent } from "../engine/reactive";
4
+ import { ComponentInstance, DisplayObject } from "./DisplayObject";
5
5
  import { DisplayObjectProps } from "./types/DisplayObject";
6
6
  import { useProps } from "../hooks/useProps";
7
7
  import { SignalOrPrimitive } from "./types";
@@ -44,14 +44,25 @@ class CanvasGraphics extends DisplayObject(PixiGraphics) {
44
44
  }
45
45
  }
46
46
 
47
- onDestroy() {
48
- this.clearEffect.subscription.unsubscribe();
49
- super.onDestroy();
47
+ /**
48
+ * Called when the component is about to be destroyed.
49
+ * This method should be overridden by subclasses to perform any cleanup.
50
+ * It ensures that the clearEffect subscription is unsubscribed before calling the original afterDestroy callback.
51
+ * @param parent The parent element.
52
+ * @param afterDestroy A callback function to be executed after the component's own destruction logic.
53
+ * @example
54
+ * // This method is typically called by the engine internally.
55
+ * // await component.onDestroy(parentElement, () => console.log('Component destroyed'));
56
+ */
57
+ async onDestroy(parent: Element<ComponentInstance>, afterDestroy: () => void): Promise<void> {
58
+ const _afterDestroyCallback = async () => {
59
+ this.clearEffect.subscription.unsubscribe();
60
+ afterDestroy();
61
+ }
62
+ await super.onDestroy(parent, _afterDestroyCallback);
50
63
  }
51
64
  }
52
65
 
53
- interface CanvasGraphics extends PixiGraphics {}
54
-
55
66
  registerComponent("Graphics", CanvasGraphics);
56
67
 
57
68
  export function Graphics(props: GraphicsProps) {
@@ -2,6 +2,7 @@ import { Assets, NineSliceSprite as PixiNineSliceSprite, Texture } from "pixi.js
2
2
  import { createComponent, registerComponent } from "../engine/reactive";
3
3
  import { DisplayObject } from "./DisplayObject";
4
4
  import { DisplayObjectProps } from "./types/DisplayObject";
5
+ import { Layout } from "@pixi/layout";
5
6
 
6
7
  interface NineSliceSpriteProps extends DisplayObjectProps {
7
8
  image?: string;
@@ -37,7 +38,9 @@ class CanvasNineSliceSprite extends DisplayObject(PixiNineSliceSprite) {
37
38
  }
38
39
  }
39
40
 
40
- interface CanvasNineSliceSprite extends PixiNineSliceSprite {}
41
+ interface CanvasNineSliceSprite extends PixiNineSliceSprite {
42
+ layout: Layout | null;
43
+ }
41
44
 
42
45
  registerComponent("NineSliceSprite", CanvasNineSliceSprite);
43
46
 
@@ -1,14 +1,15 @@
1
1
  import * as particles from "@barvynkoa/particle-emitter";
2
- import { createComponent, registerComponent } from "../engine/reactive";
2
+ import { createComponent, Element, registerComponent } from "../engine/reactive";
3
3
  import { CanvasContainer } from "./Container";
4
4
  import { Signal } from "@signe/reactive";
5
+ import { ComponentInstance } from "./DisplayObject";
5
6
 
6
7
  class CanvasParticlesEmitter extends CanvasContainer {
7
8
  private emitter: particles.Emitter | null;
8
9
  private elapsed: number = Date.now();
9
10
 
10
- onMount(params) {
11
- super.onMount(params);
11
+ async onMount(params) {
12
+ await super.onMount(params);
12
13
  const { props } = params;
13
14
  const tick: Signal = props.context.tick;
14
15
  this.emitter = new particles.Emitter(this as any, props.config);
@@ -24,11 +25,14 @@ class CanvasParticlesEmitter extends CanvasContainer {
24
25
 
25
26
  onUpdate(props) {}
26
27
 
27
- onDestroy(): void {
28
- super.onDestroy();
29
- this.emitter?.destroy();
30
- this.emitter = null;
31
- this.subscriptionTick.unsubscribe();
28
+ async onDestroy(parent: Element<ComponentInstance>, afterDestroy: () => void) {
29
+ const _afterDestroy = async () => {
30
+ this.emitter?.destroy();
31
+ this.emitter = null;
32
+ this.subscriptionTick.unsubscribe();
33
+ afterDestroy();
34
+ }
35
+ await super.onDestroy(parent, _afterDestroy);
32
36
  }
33
37
  }
34
38
 
@@ -25,6 +25,7 @@ import {
25
25
  import { ComponentFunction } from "../engine/signal";
26
26
  import { DisplayObjectProps } from "./types/DisplayObject";
27
27
  import { AnimatedSignal, isAnimatedSignal } from "../engine/animation";
28
+ import { Layout } from '@pixi/layout';
28
29
 
29
30
  const log = console.log;
30
31
 
@@ -219,7 +220,7 @@ export class CanvasSprite extends DisplayObject(PixiSprite) {
219
220
  this.sheetCurrentAnimation = StandardAnimation.Stand;
220
221
  }
221
222
 
222
- this.play(this.sheetCurrentAnimation, [this.sheetParams]);
223
+ if (this.spritesheet) this.play(this.sheetCurrentAnimation, [this.sheetParams]);
223
224
  });
224
225
 
225
226
  super.onMount(params);
@@ -272,8 +273,8 @@ export class CanvasSprite extends DisplayObject(PixiSprite) {
272
273
  }
273
274
  }
274
275
 
275
- onDestroy(): void {
276
- super.onDestroy();
276
+ async onDestroy(parent: Element, afterDestroy: () => void): Promise<void> {
277
+ await super.onDestroy(parent);
277
278
  this.subscriptionSheet.forEach((sub) => sub.unsubscribe());
278
279
  this.subscriptionTick.unsubscribe();
279
280
  if (this.currentAnimationContainer && this.parent instanceof Container) {
@@ -463,7 +464,9 @@ export class CanvasSprite extends DisplayObject(PixiSprite) {
463
464
  }
464
465
  }
465
466
 
466
- export interface CanvasSprite extends PixiSprite {}
467
+ export interface CanvasSprite extends PixiSprite {
468
+ layout: Layout | null;
469
+ }
467
470
 
468
471
  registerComponent("Sprite", CanvasSprite);
469
472