@energy8platform/game-engine 0.15.0 → 0.15.2

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,17 +1,26 @@
1
1
  /**
2
- * Ambient JSX IntrinsicElements declarations for the PixiJS React reconciler.
2
+ * JSX prop types for the PixiJS React reconciler.
3
3
  *
4
- * Consumer apps opt in once (e.g. from an app-level `vite-env.d.ts`):
4
+ * The engine auto-augments `react`'s module-scoped `JSX.IntrinsicElements`
5
+ * with every registered element (`<flexContainer>`, `<button>`, `<label>`,
6
+ * `<labelValue>`, etc). Because the augmentation is scoped to the `react`
7
+ * module (not the legacy global `JSX` namespace), it reliably wins over
8
+ * `@types/react`'s HTML defaults for colliding names like `<button>` / `<label>`.
5
9
  *
6
- * import '@energy8platform/game-engine/react-jsx';
10
+ * **Consumers don't need any shim.** Any import from `@energy8platform/game-engine/react`
11
+ * (e.g. `createPixiRoot`, `extendUIElements`, `ReactScene` — you're already
12
+ * importing these to boot the reconciler) pulls this module in and the JSX
13
+ * types activate automatically.
7
14
  *
8
- * After that, TypeScript recognises `<flexContainer>`, `<button>`, `<label>` etc.
9
- * with fully-typed props no need to hand-maintain a local `pixi-jsx.d.ts`.
15
+ * If a project imports only from `/ui` or `/core` and never touches `/react`,
16
+ * add a one-line side-effect import to trigger the augmentation:
10
17
  *
11
- * The JS entry for this subpath is intentionally empty: this module exists
12
- * solely to carry type declarations that side-effect the global `JSX` namespace.
18
+ * ```ts
19
+ * // app/src/pixi-jsx.d.ts
20
+ * import '@energy8platform/game-engine/react-jsx';
21
+ * ```
13
22
  *
14
- * Dash-notation is supported for nested config objects:
23
+ * Dash-notation for nested config objects is supported:
15
24
  * <button colors-default={0xff0000} colors-hover={0x00ff00} />
16
25
  */
17
26
 
@@ -34,7 +43,7 @@ import type { ToggleConfig } from '../ui/Toggle';
34
43
 
35
44
  // ─── Event props ─────────────────────────────────────────
36
45
 
37
- interface PixiEventProps {
46
+ export interface PixiEventProps {
38
47
  onClick?: (e: any) => void;
39
48
  onPointerDown?: (e: any) => void;
40
49
  onPointerUp?: (e: any) => void;
@@ -58,7 +67,7 @@ interface PixiEventProps {
58
67
 
59
68
  // ─── Base container props (shared by all elements) ───────
60
69
 
61
- interface BaseProps extends PixiEventProps {
70
+ export interface BaseProps extends PixiEventProps {
62
71
  key?: React.Key;
63
72
  ref?: React.Ref<any>;
64
73
  children?: React.ReactNode;
@@ -113,13 +122,13 @@ interface BaseProps extends PixiEventProps {
113
122
 
114
123
  // ─── PixiJS primitive elements ───────────────────────────
115
124
 
116
- interface SpriteProps extends BaseProps {
125
+ export interface SpriteProps extends BaseProps {
117
126
  texture?: string | Texture;
118
127
  anchor?: number | { x: number; y: number };
119
128
  tint?: number;
120
129
  }
121
130
 
122
- interface TextProps extends BaseProps {
131
+ export interface TextProps extends BaseProps {
123
132
  text?: string;
124
133
  style?: Partial<TextStyle>;
125
134
  anchor?: number | { x: number; y: number };
@@ -131,7 +140,7 @@ interface TextProps extends BaseProps {
131
140
  'style-letterSpacing'?: number;
132
141
  }
133
142
 
134
- interface GraphicsProps extends BaseProps {
143
+ export interface GraphicsProps extends BaseProps {
135
144
  /** Draw function: receives the Graphics instance, called on mount and updates */
136
145
  draw?: (g: any) => void;
137
146
  /**
@@ -144,9 +153,29 @@ interface GraphicsProps extends BaseProps {
144
153
  height?: number;
145
154
  }
146
155
 
156
+ export interface AnimatedSpriteProps extends BaseProps {
157
+ textures?: Texture[];
158
+ animationSpeed?: number;
159
+ loop?: boolean;
160
+ playing?: boolean;
161
+ }
162
+
163
+ export interface NineSliceSpriteProps extends BaseProps {
164
+ texture?: string | Texture;
165
+ leftWidth?: number;
166
+ topHeight?: number;
167
+ rightWidth?: number;
168
+ bottomHeight?: number;
169
+ }
170
+
171
+ export interface TilingSpriteProps extends BaseProps {
172
+ texture?: string | Texture;
173
+ tilePosition?: { x: number; y: number };
174
+ }
175
+
147
176
  // ─── Engine UI component props ───────────────────────────
148
177
 
149
- interface ButtonComponentProps extends BaseProps, Omit<ButtonConfig, 'colors' | 'textStyle'> {
178
+ export interface ButtonComponentProps extends BaseProps, Omit<ButtonConfig, 'colors' | 'textStyle'> {
150
179
  // Full object form
151
180
  colors?: Partial<Record<ButtonState, number>>;
152
181
  textStyle?: Record<string, unknown>;
@@ -170,7 +199,7 @@ interface ButtonComponentProps extends BaseProps, Omit<ButtonConfig, 'colors' |
170
199
  onPress?: () => void;
171
200
  }
172
201
 
173
- interface LabelComponentProps extends BaseProps, Omit<LabelConfig, 'style'> {
202
+ export interface LabelComponentProps extends BaseProps, Omit<LabelConfig, 'style'> {
174
203
  style?: Partial<TextStyle>;
175
204
  'style-fontSize'?: number;
176
205
  'style-fill'?: number | string;
@@ -179,7 +208,7 @@ interface LabelComponentProps extends BaseProps, Omit<LabelConfig, 'style'> {
179
208
  'style-letterSpacing'?: number;
180
209
  }
181
210
 
182
- interface LabelValueComponentProps extends Omit<BaseProps, 'width' | 'height' | 'label'>,
211
+ export interface LabelValueComponentProps extends Omit<BaseProps, 'width' | 'height' | 'label'>,
183
212
  Omit<LabelValueConfig, 'labelStyle' | 'valueStyle'> {
184
213
  labelStyle?: Partial<TextStyle>;
185
214
  valueStyle?: Partial<TextStyle>;
@@ -196,11 +225,11 @@ interface LabelValueComponentProps extends Omit<BaseProps, 'width' | 'height' |
196
225
  'valueStyle-fontWeight'?: string;
197
226
  }
198
227
 
199
- interface PanelComponentProps extends BaseProps, Omit<PanelConfig, 'layout'> {
228
+ export interface PanelComponentProps extends BaseProps, Omit<PanelConfig, 'layout'> {
200
229
  layout?: Partial<FlexContainerConfig>;
201
230
  }
202
231
 
203
- interface FlexContainerComponentProps extends Omit<BaseProps, 'width' | 'height'>, FlexContainerConfig {
232
+ export interface FlexContainerComponentProps extends Omit<BaseProps, 'width' | 'height'>, FlexContainerConfig {
204
233
  padding?: number | [number, number, number, number];
205
234
  paddingTop?: number;
206
235
  paddingRight?: number;
@@ -211,7 +240,7 @@ interface FlexContainerComponentProps extends Omit<BaseProps, 'width' | 'height'
211
240
  height?: number | string;
212
241
  }
213
242
 
214
- interface ProgressBarComponentProps extends BaseProps, ProgressBarConfig {
243
+ export interface ProgressBarComponentProps extends BaseProps, ProgressBarConfig {
215
244
  progress?: number;
216
245
  /** Custom track background (string texture name, Texture, or Container) */
217
246
  trackView?: ViewInput;
@@ -219,7 +248,7 @@ interface ProgressBarComponentProps extends BaseProps, ProgressBarConfig {
219
248
  fillView?: ViewInput;
220
249
  }
221
250
 
222
- interface ScrollContainerComponentProps extends BaseProps, Omit<ScrollContainerConfig, 'width' | 'height'> {
251
+ export interface ScrollContainerComponentProps extends BaseProps, Omit<ScrollContainerConfig, 'width' | 'height'> {
223
252
  width: number;
224
253
  height: number;
225
254
  /** Show scrollbar indicator */
@@ -232,32 +261,32 @@ interface ScrollContainerComponentProps extends BaseProps, Omit<ScrollContainerC
232
261
  scrollbarAlpha?: number;
233
262
  }
234
263
 
235
- interface ModalComponentProps extends BaseProps, ModalConfig {
264
+ export interface ModalComponentProps extends BaseProps, ModalConfig {
236
265
  onClose?: () => void;
237
266
  }
238
267
 
239
- interface ToastComponentProps extends BaseProps, ToastConfig {
268
+ export interface ToastComponentProps extends BaseProps, ToastConfig {
240
269
  /** Custom background view */
241
270
  backgroundView?: ViewInput;
242
271
  }
243
272
 
244
- interface BalanceDisplayComponentProps extends BaseProps, BalanceDisplayConfig {
273
+ export interface BalanceDisplayComponentProps extends BaseProps, BalanceDisplayConfig {
245
274
  /** Current balance value */
246
275
  value?: number;
247
276
  }
248
277
 
249
- interface WinDisplayComponentProps extends BaseProps, WinDisplayConfig {}
278
+ export interface WinDisplayComponentProps extends BaseProps, WinDisplayConfig {}
250
279
 
251
- interface LayoutComponentProps extends BaseProps, LayoutConfig {}
280
+ export interface LayoutComponentProps extends BaseProps, LayoutConfig {}
252
281
 
253
- interface SliderComponentProps extends BaseProps, Omit<SliderConfig, 'width' | 'height'> {
282
+ export interface SliderComponentProps extends BaseProps, Omit<SliderConfig, 'width' | 'height'> {
254
283
  width?: number;
255
284
  height?: number;
256
285
  onUpdate?: (value: number) => void;
257
286
  onChange?: (value: number) => void;
258
287
  }
259
288
 
260
- interface ToggleComponentProps extends BaseProps, Omit<ToggleConfig, 'width' | 'height'> {
289
+ export interface ToggleComponentProps extends BaseProps, Omit<ToggleConfig, 'width' | 'height'> {
261
290
  width?: number;
262
291
  height?: number;
263
292
  onView?: ViewInput;
@@ -265,37 +294,53 @@ interface ToggleComponentProps extends BaseProps, Omit<ToggleConfig, 'width' | '
265
294
  onChange?: (value: boolean) => void;
266
295
  }
267
296
 
268
- // ─── JSX IntrinsicElements ───────────────────────────────
297
+ // ─── IntrinsicElements map ───────────────────────────────
298
+
299
+ /**
300
+ * Complete element → prop-type map for all engine-registered JSX elements.
301
+ * Also consumable directly for typing custom wrappers around engine elements.
302
+ */
303
+ export interface EngineIntrinsicElements {
304
+ // PixiJS primitives
305
+ container: BaseProps;
306
+ sprite: SpriteProps;
307
+ text: TextProps;
308
+ graphics: GraphicsProps;
309
+ animatedSprite: AnimatedSpriteProps;
310
+ nineSliceSprite: NineSliceSpriteProps;
311
+ tilingSprite: TilingSpriteProps;
312
+
313
+ // Engine UI components
314
+ button: ButtonComponentProps;
315
+ label: LabelComponentProps;
316
+ labelValue: LabelValueComponentProps;
317
+ panel: PanelComponentProps;
318
+ flexContainer: FlexContainerComponentProps;
319
+ progressBar: ProgressBarComponentProps;
320
+ scrollContainer: ScrollContainerComponentProps;
321
+ modal: ModalComponentProps;
322
+ toast: ToastComponentProps;
323
+ balanceDisplay: BalanceDisplayComponentProps;
324
+ winDisplay: WinDisplayComponentProps;
325
+ layout: LayoutComponentProps;
326
+ slider: SliderComponentProps;
327
+ toggle: ToggleComponentProps;
328
+ }
269
329
 
270
- declare global {
330
+ // ─── Auto-augment React's JSX namespace ──────────────────
331
+ //
332
+ // React 19 scopes `JSX.IntrinsicElements` inside `declare module 'react'`,
333
+ // so we augment the same module. `extends EngineIntrinsicElements {}` adds
334
+ // every engine element to the interface the reconciler sees.
335
+ //
336
+ // Interface merging with `@types/react`'s HTML defaults: property names
337
+ // unique to the engine (`flexContainer`, `labelValue`, `button` since it
338
+ // carries our ButtonComponentProps, etc.) merge cleanly. For HTML-colliding
339
+ // names (`button`, `label`), this module-scoped augmentation takes precedence
340
+ // over the legacy global JSX namespace in React-19 apps.
341
+
342
+ declare module 'react' {
271
343
  namespace JSX {
272
- interface IntrinsicElements {
273
- // PixiJS primitives
274
- container: BaseProps;
275
- sprite: SpriteProps;
276
- text: TextProps;
277
- graphics: GraphicsProps;
278
- animatedSprite: BaseProps & { textures?: Texture[]; animationSpeed?: number; loop?: boolean; playing?: boolean };
279
- nineSliceSprite: BaseProps & { texture?: string | Texture; leftWidth?: number; topHeight?: number; rightWidth?: number; bottomHeight?: number };
280
- tilingSprite: BaseProps & { texture?: string | Texture; tilePosition?: { x: number; y: number } };
281
-
282
- // Engine UI components
283
- button: ButtonComponentProps;
284
- label: LabelComponentProps;
285
- labelValue: LabelValueComponentProps;
286
- panel: PanelComponentProps;
287
- flexContainer: FlexContainerComponentProps;
288
- progressBar: ProgressBarComponentProps;
289
- scrollContainer: ScrollContainerComponentProps;
290
- modal: ModalComponentProps;
291
- toast: ToastComponentProps;
292
- balanceDisplay: BalanceDisplayComponentProps;
293
- winDisplay: WinDisplayComponentProps;
294
- layout: LayoutComponentProps;
295
- slider: SliderComponentProps;
296
- toggle: ToggleComponentProps;
297
- }
344
+ interface IntrinsicElements extends EngineIntrinsicElements {}
298
345
  }
299
346
  }
300
-
301
- export {};
@@ -118,26 +118,31 @@ function measureChild(
118
118
  const cfg = child._flexConfig;
119
119
  const resolvedLW = resolveDimension(cfg?.layoutWidth, parentContentW);
120
120
  const resolvedLH = resolveDimension(cfg?.layoutHeight, parentContentH);
121
- if (resolvedLW !== undefined && resolvedLH !== undefined) {
122
- return { w: resolvedLW, h: resolvedLH, ox: 0, oy: 0 };
123
- }
124
121
 
125
- // For FlexContainers, use their explicit or computed size
122
+ // FlexContainer children are top-left origin by construction, so `ox/oy = 0`
123
+ // is correct and we can skip the `getLocalBounds()` call entirely.
126
124
  if (child instanceof FlexContainer) {
127
125
  const fc = child;
128
126
  const w = fc._explicitWidth > 0 ? fc._explicitWidth : (fc._computedWidth > 0 ? fc._computedWidth : undefined);
129
127
  const h = fc._explicitHeight > 0 ? fc._explicitHeight : (fc._computedHeight > 0 ? fc._computedHeight : undefined);
130
128
  if (w !== undefined && h !== undefined) {
131
- return { w, h, ox: 0, oy: 0 };
129
+ return { w: resolvedLW ?? w, h: resolvedLH ?? h, ox: 0, oy: 0 };
132
130
  }
133
131
  }
134
132
 
135
- // Use localBounds to get the true visual extent and origin offset.
136
- // This handles children with non-zero anchors (e.g. Button, Label with centered text).
133
+ // Use localBounds to get the true visual origin offset.
134
+ // We take `ox/oy` from bounds unconditionally a user-supplied `layoutWidth/Height`
135
+ // overrides the SIZE used by flex (protection against pre-paint bounds of 0), but
136
+ // it must NOT erase the center-anchor compensation: Button/Label views are drawn at
137
+ // `(-w/2..w/2)` and their bounds.x = -w/2 is what lets `layoutLine` place the
138
+ // visible rectangle where the layout intends.
137
139
  const bounds = child.getLocalBounds();
138
- const w = resolvedLW ?? bounds.width;
139
- const h = resolvedLH ?? bounds.height;
140
- return { w, h, ox: bounds.x, oy: bounds.y };
140
+ return {
141
+ w: resolvedLW ?? bounds.width,
142
+ h: resolvedLH ?? bounds.height,
143
+ ox: bounds.x,
144
+ oy: bounds.y,
145
+ };
141
146
  }
142
147
 
143
148
  // ─── Layout items within a single line ───────────────────
@@ -699,25 +704,30 @@ export class FlexContainer extends Container {
699
704
  }
700
705
 
701
706
  // Position flexExclude children (absolute positioning).
702
- // All position props describe the visual (bounds) rectangle, so we subtract
703
- // `ox/oy` to compensate for children with a centered origin (Button, Label).
707
+ // All position props describe the visual (bounds) rectangle. We derive the
708
+ // visual rectangle directly from `getLocalBounds()` rather than the
709
+ // layout-config `w`/`h` returned by measureChild — those may differ from
710
+ // actual bounds when the user pins `layoutWidth`/`layoutHeight` to a value
711
+ // that doesn't match the child's real visual extent (e.g. a Button whose
712
+ // text overflows its configured `width`). Mixing layout size with real
713
+ // bounds-origin would shift the visual center off the requested point.
704
714
  // `centerX/centerY` take precedence over `left/right` / `top/bottom` on each axis.
705
715
  for (const child of this._layoutChildren) {
706
716
  if (!child._flexConfig?.flexExclude) continue;
707
717
  const cfg = child._flexConfig;
708
- const { w, h, ox, oy } = measureChild(child, pctRefW, pctRefH);
718
+ const bounds = child.getLocalBounds();
709
719
  const cw = this._computedWidth;
710
720
  const ch = this._computedHeight;
711
721
 
712
722
  const centerX = resolveDimension(cfg.centerX, pctRefW);
713
- if (centerX !== undefined) child.x = centerX - w / 2 - ox;
714
- else if (cfg.left !== undefined) child.x = cfg.left - ox;
715
- else if (cfg.right !== undefined) child.x = cw - w - cfg.right - ox;
723
+ if (centerX !== undefined) child.x = centerX - bounds.x - bounds.width / 2;
724
+ else if (cfg.left !== undefined) child.x = cfg.left - bounds.x;
725
+ else if (cfg.right !== undefined) child.x = cw - cfg.right - bounds.x - bounds.width;
716
726
 
717
727
  const centerY = resolveDimension(cfg.centerY, pctRefH);
718
- if (centerY !== undefined) child.y = centerY - h / 2 - oy;
719
- else if (cfg.top !== undefined) child.y = cfg.top - oy;
720
- else if (cfg.bottom !== undefined) child.y = ch - h - cfg.bottom - oy;
728
+ if (centerY !== undefined) child.y = centerY - bounds.y - bounds.height / 2;
729
+ else if (cfg.top !== undefined) child.y = cfg.top - bounds.y;
730
+ else if (cfg.bottom !== undefined) child.y = ch - cfg.bottom - bounds.y - bounds.height;
721
731
  }
722
732
  }
723
733