canvasengine 2.0.0-beta.4 → 2.0.0-beta.41

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 (142) hide show
  1. package/dist/DebugRenderer-BxfW34YG.js +172 -0
  2. package/dist/DebugRenderer-BxfW34YG.js.map +1 -0
  3. package/dist/components/Button.d.ts +183 -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/DOMElement.d.ts +44 -0
  8. package/dist/components/DOMElement.d.ts.map +1 -0
  9. package/dist/components/Graphic.d.ts +65 -0
  10. package/dist/components/Graphic.d.ts.map +1 -0
  11. package/dist/components/Joystick.d.ts +36 -0
  12. package/dist/components/Joystick.d.ts.map +1 -0
  13. package/dist/components/NineSliceSprite.d.ts +17 -0
  14. package/dist/components/NineSliceSprite.d.ts.map +1 -0
  15. package/dist/components/ParticleEmitter.d.ts +5 -0
  16. package/dist/components/ParticleEmitter.d.ts.map +1 -0
  17. package/dist/components/Scene.d.ts +2 -0
  18. package/dist/components/Scene.d.ts.map +1 -0
  19. package/dist/components/Text.d.ts +26 -0
  20. package/dist/components/Text.d.ts.map +1 -0
  21. package/dist/components/TilingSprite.d.ts +18 -0
  22. package/dist/components/TilingSprite.d.ts.map +1 -0
  23. package/dist/components/Video.d.ts +15 -0
  24. package/dist/components/Video.d.ts.map +1 -0
  25. package/dist/components/index.d.ts +18 -0
  26. package/dist/components/index.d.ts.map +1 -0
  27. package/dist/components/types/DisplayObject.d.ts +110 -0
  28. package/dist/components/types/DisplayObject.d.ts.map +1 -0
  29. package/dist/components/types/MouseEvent.d.ts +4 -0
  30. package/dist/components/types/MouseEvent.d.ts.map +1 -0
  31. package/dist/components/types/Spritesheet.d.ts +248 -0
  32. package/dist/components/types/Spritesheet.d.ts.map +1 -0
  33. package/dist/components/types/index.d.ts +5 -0
  34. package/dist/components/types/index.d.ts.map +1 -0
  35. package/dist/directives/Controls.d.ts +113 -0
  36. package/dist/directives/Controls.d.ts.map +1 -0
  37. package/dist/directives/ControlsBase.d.ts +198 -0
  38. package/dist/directives/ControlsBase.d.ts.map +1 -0
  39. package/dist/directives/Drag.d.ts +70 -0
  40. package/dist/directives/Drag.d.ts.map +1 -0
  41. package/dist/directives/Flash.d.ts +117 -0
  42. package/dist/directives/Flash.d.ts.map +1 -0
  43. package/dist/directives/GamepadControls.d.ts +225 -0
  44. package/dist/directives/GamepadControls.d.ts.map +1 -0
  45. package/dist/directives/JoystickControls.d.ts +172 -0
  46. package/dist/directives/JoystickControls.d.ts.map +1 -0
  47. package/dist/directives/KeyboardControls.d.ts +219 -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/Shake.d.ts +98 -0
  52. package/dist/directives/Shake.d.ts.map +1 -0
  53. package/dist/directives/Sound.d.ts +26 -0
  54. package/dist/directives/Sound.d.ts.map +1 -0
  55. package/dist/directives/Transition.d.ts +11 -0
  56. package/dist/directives/Transition.d.ts.map +1 -0
  57. package/dist/directives/ViewportCull.d.ts +12 -0
  58. package/dist/directives/ViewportCull.d.ts.map +1 -0
  59. package/dist/directives/ViewportFollow.d.ts +19 -0
  60. package/dist/directives/ViewportFollow.d.ts.map +1 -0
  61. package/dist/directives/index.d.ts +13 -0
  62. package/dist/directives/index.d.ts.map +1 -0
  63. package/dist/engine/animation.d.ts +73 -0
  64. package/dist/engine/animation.d.ts.map +1 -0
  65. package/dist/engine/bootstrap.d.ts +16 -0
  66. package/dist/engine/bootstrap.d.ts.map +1 -0
  67. package/dist/engine/directive.d.ts +14 -0
  68. package/dist/engine/directive.d.ts.map +1 -0
  69. package/dist/engine/reactive.d.ts +105 -0
  70. package/dist/engine/reactive.d.ts.map +1 -0
  71. package/dist/engine/signal.d.ts +72 -0
  72. package/dist/engine/signal.d.ts.map +1 -0
  73. package/dist/engine/trigger.d.ts +54 -0
  74. package/dist/engine/trigger.d.ts.map +1 -0
  75. package/dist/engine/utils.d.ts +90 -0
  76. package/dist/engine/utils.d.ts.map +1 -0
  77. package/dist/hooks/addContext.d.ts +2 -0
  78. package/dist/hooks/addContext.d.ts.map +1 -0
  79. package/dist/hooks/useProps.d.ts +42 -0
  80. package/dist/hooks/useProps.d.ts.map +1 -0
  81. package/dist/hooks/useRef.d.ts +5 -0
  82. package/dist/hooks/useRef.d.ts.map +1 -0
  83. package/dist/index-BnuKipxl.js +12568 -0
  84. package/dist/index-BnuKipxl.js.map +1 -0
  85. package/dist/index.d.ts +15 -1083
  86. package/dist/index.d.ts.map +1 -0
  87. package/dist/index.global.js +29 -0
  88. package/dist/index.global.js.map +1 -0
  89. package/dist/index.js +81 -3041
  90. package/dist/index.js.map +1 -1
  91. package/dist/utils/Ease.d.ts +17 -0
  92. package/dist/utils/Ease.d.ts.map +1 -0
  93. package/dist/utils/GlobalAssetLoader.d.ts +141 -0
  94. package/dist/utils/GlobalAssetLoader.d.ts.map +1 -0
  95. package/dist/utils/RadialGradient.d.ts +58 -0
  96. package/dist/utils/RadialGradient.d.ts.map +1 -0
  97. package/dist/utils/functions.d.ts +2 -0
  98. package/dist/utils/functions.d.ts.map +1 -0
  99. package/package.json +13 -7
  100. package/src/components/Button.ts +396 -0
  101. package/src/components/Canvas.ts +61 -45
  102. package/src/components/Container.ts +21 -2
  103. package/src/components/DOMContainer.ts +123 -0
  104. package/src/components/DOMElement.ts +421 -0
  105. package/src/components/DisplayObject.ts +350 -197
  106. package/src/components/Graphic.ts +200 -34
  107. package/src/components/Joystick.ts +363 -0
  108. package/src/components/Mesh.ts +222 -0
  109. package/src/components/NineSliceSprite.ts +4 -1
  110. package/src/components/ParticleEmitter.ts +12 -8
  111. package/src/components/Sprite.ts +306 -30
  112. package/src/components/Text.ts +125 -18
  113. package/src/components/Video.ts +110 -0
  114. package/src/components/Viewport.ts +59 -43
  115. package/src/components/index.ts +8 -2
  116. package/src/components/types/DisplayObject.ts +34 -0
  117. package/src/components/types/Spritesheet.ts +0 -118
  118. package/src/directives/Controls.ts +254 -0
  119. package/src/directives/ControlsBase.ts +266 -0
  120. package/src/directives/Drag.ts +357 -52
  121. package/src/directives/Flash.ts +419 -0
  122. package/src/directives/GamepadControls.ts +537 -0
  123. package/src/directives/JoystickControls.ts +396 -0
  124. package/src/directives/KeyboardControls.ts +66 -424
  125. package/src/directives/Shake.ts +295 -0
  126. package/src/directives/Sound.ts +94 -31
  127. package/src/directives/ViewportFollow.ts +35 -7
  128. package/src/directives/index.ts +12 -6
  129. package/src/engine/animation.ts +175 -21
  130. package/src/engine/bootstrap.ts +23 -3
  131. package/src/engine/directive.ts +2 -2
  132. package/src/engine/reactive.ts +780 -177
  133. package/src/engine/signal.ts +35 -4
  134. package/src/engine/trigger.ts +34 -7
  135. package/src/engine/utils.ts +19 -3
  136. package/src/hooks/useProps.ts +1 -1
  137. package/src/index.ts +4 -2
  138. package/src/utils/GlobalAssetLoader.ts +257 -0
  139. package/src/utils/functions.ts +7 -0
  140. package/testing/index.ts +12 -0
  141. package/tsconfig.json +17 -0
  142. package/vite.config.ts +39 -0
@@ -1,22 +1,25 @@
1
- import { Node } from "yoga-layout";
2
- import { Element, isElement, Props } from "../engine/reactive";
1
+ import { Element, isElement, Props, isElementFrozen } 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 { DropShadowFilter } from "pixi-filters";
11
+ import { signal } from "@signe/reactive";
12
12
  import { BlurFilter, ObservablePoint } from "pixi.js";
13
+ import * as FILTERS from "pixi-filters";
14
+ import { isPercent } from "../utils/functions";
15
+ import { BehaviorSubject, filter, Subject } from "rxjs";
13
16
 
14
17
  export interface ComponentInstance extends PixiMixins.ContainerOptions {
15
18
  id?: string;
16
19
  children?: ComponentInstance[];
17
20
  onInit?(props: Props): void;
18
21
  onUpdate?(props: Props): void;
19
- onDestroy?(parent: Element): void;
22
+ onDestroy?(parent: Element, afterDestroy: () => void): void;
20
23
  onMount?(context: Element, index?: number): void;
21
24
  setWidth(width: number): void;
22
25
  setHeight(height: number): void;
@@ -93,6 +96,8 @@ export const EVENTS = [
93
96
  "wheelcapture",
94
97
  ];
95
98
 
99
+ export type OnHook = (() => void) | (() => Promise<void> | void);
100
+
96
101
  export function DisplayObject(extendClass) {
97
102
  return class DisplayObject extends extendClass {
98
103
  #canvasContext: {
@@ -101,117 +106,138 @@ export function DisplayObject(extendClass) {
101
106
  isFlex: boolean = false;
102
107
  fullProps: Props = {};
103
108
  isMounted: boolean = false;
104
- _anchorPoints = new ObservablePoint(
105
- { _onUpdate: () => {} },
106
- 0,
107
- 0
108
- );
109
+ _anchorPoints = new ObservablePoint({ _onUpdate: () => {} }, 0, 0);
109
110
  isCustomAnchor: boolean = false;
110
111
  displayWidth = signal(0);
111
112
  displayHeight = signal(0);
112
113
  overrideProps: string[] = [];
113
- node: Node;
114
-
115
- get yoga() {
116
- return this.#canvasContext?.Yoga;
114
+ layout = null;
115
+ onBeforeDestroy: OnHook | null = null;
116
+ onAfterMount: OnHook | null = null;
117
+ subjectInit = new BehaviorSubject(null);
118
+ disableLayout: boolean = false;
119
+ // Store registered event listeners for cleanup
120
+ #registeredEvents: Map<string, Function> = new Map();
121
+ // Store computed layout box dimensions
122
+ #computedLayoutBox: { width?: number; height?: number } | null = null;
123
+ // Store reference to element for freeze checking
124
+ #element: Element<DisplayObject> | null = null;
125
+
126
+ /**
127
+ * Get the element reference for freeze checking
128
+ * @returns The element reference or null
129
+ */
130
+ protected getElement(): Element<DisplayObject> | null {
131
+ return this.#element;
117
132
  }
118
133
 
119
134
  get deltaRatio() {
120
135
  return this.#canvasContext?.scheduler?.tick.value.deltaRatio;
121
136
  }
122
137
 
123
- onInit(props) {
138
+ get parentIsFlex() {
139
+ if (this.disableLayout) return false;
140
+ return this.parent?.isFlex;
141
+ }
142
+
143
+ onInit(props: Props) {
124
144
  this._id = props.id;
125
145
  for (let event of EVENTS) {
126
146
  if (props[event] && !this.overrideProps.includes(event)) {
127
147
  this.eventMode = "static";
128
- this.on(event, props[event]);
148
+ const originalEventHandler = props[event];
149
+
150
+ // Wrap event handler to check freeze state
151
+ const wrappedHandler = (...args: any[]) => {
152
+ // Check if element is frozen before executing handler
153
+ if (this.#element && isElementFrozen(this.#element)) {
154
+ return;
155
+ }
156
+ return originalEventHandler(...args);
157
+ };
158
+
159
+ // Store the wrapped event handler for cleanup
160
+ if (event === 'click') {
161
+ this.on('pointertap', wrappedHandler);
162
+ this.#registeredEvents.set('pointertap', wrappedHandler);
163
+ } else {
164
+ this.on(event, wrappedHandler);
165
+ this.#registeredEvents.set(event, wrappedHandler);
166
+ }
129
167
  }
130
168
  }
169
+ if (props.onBeforeDestroy || props['on-before-destroy']) {
170
+ this.onBeforeDestroy = props.onBeforeDestroy || props['on-before-destroy'];
171
+ }
172
+ if (props.onAfterMount || props['on-after-mount']) {
173
+ this.onAfterMount = props.onAfterMount || props['on-after-mount'];
174
+ }
175
+ if (
176
+ props.justifyContent ||
177
+ props.alignItems ||
178
+ props.flexDirection ||
179
+ props.flexWrap ||
180
+ props.alignContent ||
181
+ props.display == "flex" ||
182
+ isPercent(props.width) ||
183
+ isPercent(props.height) ||
184
+ props.isRoot
185
+ ) {
186
+ this.layout = {};
187
+ this.isFlex = true;
188
+ }
189
+
190
+ this.subjectInit.next(this);
131
191
  }
132
192
 
133
- onMount({ parent, props }: Element<DisplayObject>, index?: number) {
134
- this.#canvasContext = props.context;
135
- this.node = this.yoga.Node.create();
136
- if (parent) {
137
- const instance = parent.componentInstance as DisplayObject;
193
+ async onMount(element: Element<DisplayObject>, index?: number) {
194
+ if (this.destroyed) return
195
+ this.#element = element;
196
+ this.#canvasContext = element.props.context;
197
+ if (element.parent) {
198
+ const instance = element.parent.componentInstance as DisplayObject;
199
+ if (instance.isFlex && !this.layout && !this.disableLayout) {
200
+ try {
201
+ this.layout = {};
202
+ } catch (error) {
203
+ console.warn('Failed to set layout:', error);
204
+ }
205
+ }
138
206
  if (index === undefined) {
139
207
  instance.addChild(this);
140
208
  } else {
141
209
  instance.addChildAt(this, index);
142
210
  }
143
- if (instance.layer) this.parentLayer = instance.layer;
144
211
  this.isMounted = true;
145
- this.effectSize(props.width, props.height);
146
- 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;
212
+ this.onUpdate(element.props);
213
+
214
+ // Listen to layout events to store computed layout dimensions
215
+ const layoutHandler = (event: any) => {
216
+ if (event.computedLayout) {
217
+ this.#computedLayoutBox = {
218
+ width: event.computedLayout.width,
219
+ height: event.computedLayout.height,
220
+ };
157
221
  }
222
+ };
223
+ this.on('layout', layoutHandler);
224
+ this.#registeredEvents.set('layout', layoutHandler);
225
+
226
+ if (this.onAfterMount) {
227
+ await this.onAfterMount();
158
228
  }
159
-
160
229
  }
161
230
  }
162
231
 
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);
178
- }
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
- }
206
- }
207
-
208
- onUpdate(props) {
232
+ onUpdate(props: Props) {
209
233
  this.fullProps = {
210
234
  ...this.fullProps,
211
235
  ...props,
212
236
  };
213
237
 
238
+ if (this.destroyed) return
214
239
  if (!this.#canvasContext || !this.parent) return;
240
+
215
241
  if (props.x !== undefined) this.setX(props.x);
216
242
  if (props.y !== undefined) this.setY(props.y);
217
243
  if (props.scale !== undefined)
@@ -219,6 +245,28 @@ export function DisplayObject(extendClass) {
219
245
  if (props.anchor !== undefined && !this.isCustomAnchor) {
220
246
  setObservablePoint(this.anchor, props.anchor);
221
247
  }
248
+ if (props.width !== undefined) this.setWidth(props.width);
249
+ if (props.height !== undefined) this.setHeight(props.height);
250
+ if (props.minWidth !== undefined) this.setMinWidth(props.minWidth);
251
+ if (props.minHeight !== undefined) this.setMinHeight(props.minHeight);
252
+ if (props.maxWidth !== undefined) this.setMaxWidth(props.maxWidth);
253
+ if (props.maxHeight !== undefined) this.setMaxHeight(props.maxHeight);
254
+ if (props.aspectRatio !== undefined)
255
+ this.setAspectRatio(props.aspectRatio);
256
+ if (props.flexGrow !== undefined) this.setFlexGrow(props.flexGrow);
257
+ if (props.flexShrink !== undefined) this.setFlexShrink(props.flexShrink);
258
+ if (props.flexBasis !== undefined) this.setFlexBasis(props.flexBasis);
259
+ if (props.rowGap !== undefined) this.setRowGap(props.rowGap);
260
+ if (props.columnGap !== undefined) this.setColumnGap(props.columnGap);
261
+ if (props.top !== undefined) this.setTop(props.top);
262
+ if (props.left !== undefined) this.setLeft(props.left);
263
+ if (props.right !== undefined) this.setRight(props.right);
264
+ if (props.bottom !== undefined) this.setBottom(props.bottom);
265
+ if (props.objectFit !== undefined) this.setObjectFit(props.objectFit);
266
+ if (props.objectPosition !== undefined)
267
+ this.setObjectPosition(props.objectPosition);
268
+ if (props.transformOrigin !== undefined)
269
+ this.setTransformOrigin(props.transformOrigin);
222
270
  if (props.skew !== undefined) setObservablePoint(this.skew, props.skew);
223
271
  if (props.tint) this.tint = props.tint;
224
272
  if (props.rotation !== undefined) this.rotation = props.rotation;
@@ -243,23 +291,24 @@ export function DisplayObject(extendClass) {
243
291
  if (props.filters) this.filters = props.filters;
244
292
  if (props.maskOf) {
245
293
  if (isElement(props.maskOf)) {
246
- props.maskOf.componentInstance.mask = this;
294
+ props.maskOf.componentInstance.mask = this as any;
247
295
  }
248
296
  }
249
297
  if (props.blendMode) this.blendMode = props.blendMode;
250
298
  if (props.filterArea) this.filterArea = props.filterArea;
251
299
  const currentFilters = this.filters || [];
252
300
 
253
- if (props.shadow) {
254
- let dropShadowFilter = currentFilters.find(
255
- (filter) => filter instanceof DropShadowFilter
256
- );
257
- if (!dropShadowFilter) {
258
- dropShadowFilter = new DropShadowFilter();
259
- currentFilters.push(dropShadowFilter);
260
- }
261
- Object.assign(dropShadowFilter, props.shadow);
262
- }
301
+ // TODO: Fix DropShadowFilter import issue
302
+ // if (props.shadow) {
303
+ // let dropShadowFilter = currentFilters.find(
304
+ // (filter) => filter instanceof FILTERS.DropShadowFilter
305
+ // );
306
+ // if (!dropShadowFilter) {
307
+ // dropShadowFilter = new FILTERS.DropShadowFilter();
308
+ // currentFilters.push(dropShadowFilter);
309
+ // }
310
+ // Object.assign(dropShadowFilter, props.shadow);
311
+ // }
263
312
 
264
313
  if (props.blur) {
265
314
  let blurFilter = currentFilters.find(
@@ -279,73 +328,41 @@ export function DisplayObject(extendClass) {
279
328
  }
280
329
 
281
330
  this.filters = currentFilters;
282
-
283
- this.#flexRender(props);
284
- }
285
-
286
- onDestroy() {
287
- super.destroy();
288
- this.node?.freeRecursive();
289
- }
290
-
291
- getComputedLayout() {
292
- return this.node.getComputedLayout();
293
331
  }
294
332
 
295
- applyComputedLayout() {
296
- const layout = this.getComputedLayout();
297
- this.x = layout.left;
298
- this.y = layout.top;
299
- }
333
+ async onDestroy(parent: Element, afterDestroy?: () => void) {
334
+ // Remove all registered event listeners
335
+ for (const [eventName, eventHandler] of this.#registeredEvents) {
336
+ this.off(eventName, eventHandler);
337
+ }
338
+ this.#registeredEvents.clear();
339
+ this.#element = null;
300
340
 
301
- calculateLayout() {
302
- this.node.calculateLayout();
341
+ if (this.onBeforeDestroy) {
342
+ await this.onBeforeDestroy();
343
+ }
344
+ if (afterDestroy) afterDestroy();
345
+ super.destroy();
303
346
  }
304
347
 
305
348
  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]);
349
+ this.layout = { flexDirection: direction };
313
350
  }
314
351
 
315
352
  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]);
353
+ this.layout = { flexWrap: wrap };
337
354
  }
338
355
 
339
356
  setAlignContent(align: AlignContent) {
340
- this.#setAlign("setAlignContent", align);
357
+ this.layout = { alignContent: align };
341
358
  }
342
359
 
343
360
  setAlignSelf(align: AlignContent) {
344
- this.#setAlign("setAlignSelf", align);
361
+ this.layout = { alignSelf: align };
345
362
  }
346
363
 
347
364
  setAlignItems(align: AlignContent) {
348
- this.#setAlign("setAlignItems", align);
365
+ this.layout = { alignItems: align };
349
366
  }
350
367
 
351
368
  setJustifyContent(
@@ -356,103 +373,239 @@ export function DisplayObject(extendClass) {
356
373
  | "space-between"
357
374
  | "space-around"
358
375
  ) {
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
- }
376
+ this.layout = { justifyContent };
384
377
  }
385
378
 
386
379
  setPosition(position: EdgeSize) {
387
- this.#setEdgeSize("setPosition", position);
380
+ if (position instanceof Array) {
381
+ if (position.length === 2) {
382
+ this.layout = {
383
+ positionY: position[0],
384
+ positionX: position[1],
385
+ };
386
+ } else if (position.length === 4) {
387
+ this.layout = {
388
+ positionTop: position[0],
389
+ positionRight: position[1],
390
+ positionBottom: position[2],
391
+ positionLeft: position[3],
392
+ };
393
+ }
394
+ } else {
395
+ this.layout = { position };
396
+ }
388
397
  }
389
398
 
390
399
  setX(x: number) {
391
400
  x = x + this.getWidth() * this._anchorPoints.x;
392
- if (!this.parent.isFlex) {
401
+ if (!this.parentIsFlex) {
402
+ this.x = x;
403
+ } else {
393
404
  this.x = x;
405
+ this.layout = { x };
394
406
  }
395
- this.node.setPosition(this.yoga.EDGE_LEFT, x);
396
407
  }
397
408
 
398
409
  setY(y: number) {
399
410
  y = y + this.getHeight() * this._anchorPoints.y;
400
- if (!this.parent.isFlex) {
411
+ if (!this.parentIsFlex) {
401
412
  this.y = y;
413
+ } else {
414
+ this.y = y;
415
+ this.layout = { y };
402
416
  }
403
- this.node.setPosition(this.yoga.EDGE_TOP, y);
404
417
  }
405
418
 
406
419
  setPadding(padding: EdgeSize) {
407
- this.#setEdgeSize("setPadding", padding);
420
+ if (padding instanceof Array) {
421
+ if (padding.length === 2) {
422
+ this.layout = {
423
+ paddingVertical: padding[0],
424
+ paddingHorizontal: padding[1],
425
+ };
426
+ } else if (padding.length === 4) {
427
+ this.layout = {
428
+ paddingTop: padding[0],
429
+ paddingRight: padding[1],
430
+ paddingBottom: padding[2],
431
+ paddingLeft: padding[3],
432
+ };
433
+ }
434
+ } else {
435
+ this.layout = { padding };
436
+ }
408
437
  }
409
438
 
410
439
  setMargin(margin: EdgeSize) {
411
- this.#setEdgeSize("setMargin", margin);
440
+ if (margin instanceof Array) {
441
+ if (margin.length === 2) {
442
+ this.layout = {
443
+ marginVertical: margin[0],
444
+ marginHorizontal: margin[1],
445
+ };
446
+ } else if (margin.length === 4) {
447
+ this.layout = {
448
+ marginTop: margin[0],
449
+ marginRight: margin[1],
450
+ marginBottom: margin[2],
451
+ marginLeft: margin[3],
452
+ };
453
+ }
454
+ } else {
455
+ this.layout = { margin };
456
+ }
412
457
  }
413
458
 
414
459
  setGap(gap: EdgeSize) {
415
- this.node.setGap(this.yoga.GAP_ALL, +gap);
460
+ this.layout = { gap };
416
461
  }
417
462
 
418
463
  setBorder(border: EdgeSize) {
419
- this.#setEdgeSize("setBorder", border);
464
+ if (border instanceof Array) {
465
+ if (border.length === 2) {
466
+ this.layout = {
467
+ borderVertical: border[0],
468
+ borderHorizontal: border[1],
469
+ };
470
+ } else if (border.length === 4) {
471
+ this.layout = {
472
+ borderTop: border[0],
473
+ borderRight: border[1],
474
+ borderBottom: border[2],
475
+ borderLeft: border[3],
476
+ };
477
+ }
478
+ } else {
479
+ this.layout = { border };
480
+ }
420
481
  }
421
482
 
422
483
  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);
484
+ this.layout = { position: positionType };
438
485
  }
439
486
 
440
487
  setWidth(width: number) {
441
488
  this.displayWidth.set(width);
442
- this.node?.setWidth(width);
489
+ if (!this.parentIsFlex) {
490
+ this.width = width;
491
+ } else {
492
+ this.layout = { width };
493
+ }
443
494
  }
444
495
 
445
496
  setHeight(height: number) {
446
497
  this.displayHeight.set(height);
447
- this.node?.setHeight(height);
498
+ if (!this.parentIsFlex) {
499
+ this.height = height;
500
+ } else {
501
+ this.layout = { height };
502
+ }
503
+ }
504
+
505
+ getWidth(): number {
506
+ // If width is a percentage, use computed layout box
507
+ if (isPercent(this.fullProps.width)) {
508
+ if (this.#computedLayoutBox?.width !== undefined) {
509
+ return this.#computedLayoutBox.width;
510
+ }
511
+ // Fallback to native width if layout not yet computed
512
+ return typeof this.width === 'number' ? this.width : 0;
513
+ }
514
+ // For static values, use native PixiJS width or displayWidth signal
515
+ const staticWidth = typeof this.width === 'number' && this.width > 0
516
+ ? this.width
517
+ : (typeof this.displayWidth() === 'number' ? this.displayWidth() : 0);
518
+ return staticWidth;
519
+ }
520
+
521
+ getHeight(): number {
522
+ // If height is a percentage, use computed layout box
523
+ if (isPercent(this.fullProps.height)) {
524
+ if (this.#computedLayoutBox?.height !== undefined) {
525
+ return this.#computedLayoutBox.height;
526
+ }
527
+ // Fallback to native height if layout not yet computed
528
+ return typeof this.height === 'number' ? this.height : 0;
529
+ }
530
+ // For static values, use native PixiJS height or displayHeight signal
531
+ const staticHeight = typeof this.height === 'number' && this.height > 0
532
+ ? this.height
533
+ : (typeof this.displayHeight() === 'number' ? this.displayHeight() : 0);
534
+ return staticHeight;
535
+ }
536
+
537
+ // Min/Max constraints
538
+ setMinWidth(minWidth: number | string) {
539
+ this.layout = { minWidth };
540
+ }
541
+
542
+ setMinHeight(minHeight: number | string) {
543
+ this.layout = { minHeight };
544
+ }
545
+
546
+ setMaxWidth(maxWidth: number | string) {
547
+ this.layout = { maxWidth };
548
+ }
549
+
550
+ setMaxHeight(maxHeight: number | string) {
551
+ this.layout = { maxHeight };
552
+ }
553
+
554
+ // Aspect ratio
555
+ setAspectRatio(aspectRatio: number) {
556
+ this.layout = { aspectRatio };
557
+ }
558
+
559
+ // Flex properties
560
+ setFlexGrow(flexGrow: number) {
561
+ this.layout = { flexGrow };
562
+ }
563
+
564
+ setFlexShrink(flexShrink: number) {
565
+ this.layout = { flexShrink };
566
+ }
567
+
568
+ setFlexBasis(flexBasis: number | string) {
569
+ this.layout = { flexBasis };
570
+ }
571
+
572
+ // Gap properties
573
+ setRowGap(rowGap: number) {
574
+ this.layout = { rowGap };
575
+ }
576
+
577
+ setColumnGap(columnGap: number) {
578
+ this.layout = { columnGap };
579
+ }
580
+
581
+ // Position insets
582
+ setTop(top: number | string) {
583
+ this.layout = { top };
584
+ }
585
+
586
+ setLeft(left: number | string) {
587
+ this.layout = { left };
588
+ }
589
+
590
+ setRight(right: number | string) {
591
+ this.layout = { right };
592
+ }
593
+
594
+ setBottom(bottom: number | string) {
595
+ this.layout = { bottom };
596
+ }
597
+
598
+ // Object properties
599
+ setObjectFit(objectFit: ObjectFit) {
600
+ this.layout = { objectFit };
448
601
  }
449
602
 
450
- getWidth() {
451
- return this.displayWidth();
603
+ setObjectPosition(objectPosition: ObjectPosition) {
604
+ this.layout = { objectPosition };
452
605
  }
453
606
 
454
- getHeight() {
455
- return this.displayHeight();
607
+ setTransformOrigin(transformOrigin: TransformOrigin) {
608
+ this.layout = { transformOrigin };
456
609
  }
457
610
  };
458
611
  }