@energy8platform/game-engine 0.14.10 → 0.15.1

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.
package/dist/react.cjs.js CHANGED
@@ -24,7 +24,7 @@ function extend(components) {
24
24
 
25
25
  const RESERVED = new Set(['children', 'key', 'ref']);
26
26
  /** Props handled by the reconciler as flex item config, not forwarded to components */
27
- const FLEX_ITEM_PROPS$1 = new Set(['flexGrow', 'flexShrink', 'layoutWidth', 'layoutHeight', 'alignSelf', 'flexExclude', 'top', 'right', 'bottom', 'left']);
27
+ const FLEX_ITEM_PROPS$1 = new Set(['flexGrow', 'flexShrink', 'layoutWidth', 'layoutHeight', 'alignSelf', 'flexExclude', 'top', 'right', 'bottom', 'left', 'centerX', 'centerY']);
28
28
  /** Base Container props applied directly to the instance (not via config) */
29
29
  const CONTAINER_PROPS = new Set([
30
30
  'x', 'y', 'alpha', 'visible', 'rotation', 'angle', 'zIndex',
@@ -151,6 +151,34 @@ function hasEventProps(props) {
151
151
  }
152
152
  return false;
153
153
  }
154
+ /**
155
+ * Graphics does not have an intrinsic size — its bounds come from the `draw` callback.
156
+ * PixiJS's `Container.width` setter applies a scale transform to match the requested
157
+ * value, which silently makes the rendered size diverge from `getLocalBounds()` and
158
+ * breaks downstream flex layout. For Graphics we treat `width`/`height` as layout
159
+ * hints instead, storing them on `_flexConfig.layoutWidth`/`layoutHeight` so parent
160
+ * FlexContainers measure correctly without touching the child's scale.
161
+ */
162
+ function isGraphicsLike(instance) {
163
+ return typeof instance?.clear === 'function'
164
+ && typeof instance?.fill === 'function'
165
+ && typeof instance?.rect === 'function';
166
+ }
167
+ /** Redirect a width/height write on a Graphics into its flex layout hint. Returns true if handled. */
168
+ function applyGraphicsDimension(instance, key, value) {
169
+ if ((key !== 'width' && key !== 'height') || !isGraphicsLike(instance))
170
+ return false;
171
+ const target = key === 'width' ? 'layoutWidth' : 'layoutHeight';
172
+ if (value === undefined) {
173
+ if (instance._flexConfig)
174
+ delete instance._flexConfig[target];
175
+ return true;
176
+ }
177
+ if (!instance._flexConfig)
178
+ instance._flexConfig = {};
179
+ instance._flexConfig[target] = value;
180
+ return true;
181
+ }
154
182
  function setNestedValue(target, path, value) {
155
183
  let obj = target;
156
184
  for (let i = 0; i < path.length - 1; i++) {
@@ -215,6 +243,7 @@ function applyProps(instance, newProps, oldProps = {}) {
215
243
  }
216
244
  else if (key === 'draw') ;
217
245
  else if (key.includes('-')) ;
246
+ else if (applyGraphicsDimension(instance, key, undefined)) ;
218
247
  else {
219
248
  try {
220
249
  instance[key] = undefined;
@@ -241,6 +270,7 @@ function applyProps(instance, newProps, oldProps = {}) {
241
270
  const parts = key.split('-');
242
271
  setNestedValue(instance, parts, value);
243
272
  }
273
+ else if (applyGraphicsDimension(instance, key, value)) ;
244
274
  else {
245
275
  try {
246
276
  instance[key] = value;
@@ -789,22 +819,36 @@ class FlexContainer extends pixi_js.Container {
789
819
  this._computedWidth = this._explicitWidth > 0 ? this._explicitWidth : (pl + totalCrossNatural + pr);
790
820
  this._computedHeight = this._explicitHeight > 0 ? this._explicitHeight : (pt + naturalMainSize + pb);
791
821
  }
792
- // Position flexExclude children (absolute positioning)
822
+ // Position flexExclude children (absolute positioning).
823
+ // All position props describe the visual (bounds) rectangle. We derive the
824
+ // visual rectangle directly from `getLocalBounds()` rather than the
825
+ // layout-config `w`/`h` returned by measureChild — those may differ from
826
+ // actual bounds when the user pins `layoutWidth`/`layoutHeight` to a value
827
+ // that doesn't match the child's real visual extent (e.g. a Button whose
828
+ // text overflows its configured `width`). Mixing layout size with real
829
+ // bounds-origin would shift the visual center off the requested point.
830
+ // `centerX/centerY` take precedence over `left/right` / `top/bottom` on each axis.
793
831
  for (const child of this._layoutChildren) {
794
832
  if (!child._flexConfig?.flexExclude)
795
833
  continue;
796
834
  const cfg = child._flexConfig;
797
- const { w, h } = measureChild(child, pctRefW, pctRefH);
835
+ const bounds = child.getLocalBounds();
798
836
  const cw = this._computedWidth;
799
837
  const ch = this._computedHeight;
800
- if (cfg.left !== undefined)
801
- child.x = cfg.left;
838
+ const centerX = resolveDimension(cfg.centerX, pctRefW);
839
+ if (centerX !== undefined)
840
+ child.x = centerX - bounds.x - bounds.width / 2;
841
+ else if (cfg.left !== undefined)
842
+ child.x = cfg.left - bounds.x;
802
843
  else if (cfg.right !== undefined)
803
- child.x = cw - w - cfg.right;
804
- if (cfg.top !== undefined)
805
- child.y = cfg.top;
844
+ child.x = cw - cfg.right - bounds.x - bounds.width;
845
+ const centerY = resolveDimension(cfg.centerY, pctRefH);
846
+ if (centerY !== undefined)
847
+ child.y = centerY - bounds.y - bounds.height / 2;
848
+ else if (cfg.top !== undefined)
849
+ child.y = cfg.top - bounds.y;
806
850
  else if (cfg.bottom !== undefined)
807
- child.y = ch - h - cfg.bottom;
851
+ child.y = ch - cfg.bottom - bounds.y - bounds.height;
808
852
  }
809
853
  }
810
854
  /** Computed content size (after layout) */
@@ -863,7 +907,7 @@ class FlexContainer extends pixi_js.Container {
863
907
  }
864
908
 
865
909
  /** Flex item prop names that should be forwarded to _flexConfig on the child */
866
- const FLEX_ITEM_PROPS = ['flexGrow', 'flexShrink', 'layoutWidth', 'layoutHeight', 'alignSelf', 'flexExclude', 'top', 'right', 'bottom', 'left'];
910
+ const FLEX_ITEM_PROPS = ['flexGrow', 'flexShrink', 'layoutWidth', 'layoutHeight', 'alignSelf', 'flexExclude', 'top', 'right', 'bottom', 'left', 'centerX', 'centerY'];
867
911
  function isSuspendable(obj) {
868
912
  return typeof obj?.suspendLayout === 'function' && typeof obj?.resumeLayout === 'function';
869
913
  }
@@ -1862,6 +1906,97 @@ class Label extends pixi_js.Container {
1862
1906
  }
1863
1907
  }
1864
1908
 
1909
+ /**
1910
+ * Two-row text cell with a muted caption above and a prominent value below —
1911
+ * the archetypal casino UI pattern (BALANCE/€500, BET/€1, WIN/€0.00).
1912
+ *
1913
+ * Extends FlexContainer, so it participates in parent flex layouts directly
1914
+ * (you can pass `flexGrow`, `alignSelf`, etc. when it's a child of another
1915
+ * FlexContainer) and auto-sizes to its contents when no explicit size is set.
1916
+ *
1917
+ * @example
1918
+ * ```tsx
1919
+ * <labelValue
1920
+ * label="BALANCE"
1921
+ * value={`€${balance.toFixed(2)}`}
1922
+ * labelStyle={{ fontSize: 12, fill: 0x888888 }}
1923
+ * valueStyle={{ fontSize: 22, fill: 0xffffff, fontWeight: 'bold' }}
1924
+ * gap={6}
1925
+ * align="center"
1926
+ * />
1927
+ * ```
1928
+ */
1929
+ class LabelValue extends FlexContainer {
1930
+ _labelEl;
1931
+ _valueEl;
1932
+ _valueMaxWidth;
1933
+ constructor(config = {}) {
1934
+ super({
1935
+ direction: 'column',
1936
+ alignItems: toAlignItems(config.align ?? 'center'),
1937
+ gap: config.gap ?? 4,
1938
+ padding: config.padding,
1939
+ });
1940
+ this._valueMaxWidth = config.maxWidth ?? Infinity;
1941
+ this._labelEl = new Label({
1942
+ text: config.label ?? '',
1943
+ style: config.labelStyle,
1944
+ });
1945
+ this._valueEl = new Label({
1946
+ text: config.value ?? '',
1947
+ style: config.valueStyle,
1948
+ maxWidth: config.maxWidth,
1949
+ autoFit: config.maxWidth !== undefined,
1950
+ });
1951
+ this.addFlexChild(this._labelEl);
1952
+ this.addFlexChild(this._valueEl);
1953
+ }
1954
+ /** Get the caption Label (for advanced styling / animation) */
1955
+ get labelElement() {
1956
+ return this._labelEl;
1957
+ }
1958
+ /** Get the value Label */
1959
+ get valueElement() {
1960
+ return this._valueEl;
1961
+ }
1962
+ /** Update caption text */
1963
+ setLabel(text) {
1964
+ this._labelEl.text = text;
1965
+ this.updateLayout();
1966
+ }
1967
+ /** Update value text */
1968
+ setValue(text) {
1969
+ this._valueEl.text = text;
1970
+ this.updateLayout();
1971
+ }
1972
+ /** React reconciler update hook */
1973
+ updateConfig(changed) {
1974
+ if ('label' in changed)
1975
+ this._labelEl.text = changed.label ?? '';
1976
+ if ('value' in changed)
1977
+ this._valueEl.text = changed.value ?? '';
1978
+ if ('labelStyle' in changed && typeof changed.labelStyle === 'object') {
1979
+ Object.assign(this._labelEl.style, changed.labelStyle);
1980
+ }
1981
+ if ('valueStyle' in changed && typeof changed.valueStyle === 'object') {
1982
+ Object.assign(this._valueEl.style, changed.valueStyle);
1983
+ }
1984
+ if ('maxWidth' in changed) {
1985
+ this._valueMaxWidth = changed.maxWidth ?? Infinity;
1986
+ this._valueEl.maxWidth = this._valueMaxWidth;
1987
+ }
1988
+ if ('gap' in changed)
1989
+ this.setGap(changed.gap);
1990
+ if ('align' in changed)
1991
+ this.setAlignItems(toAlignItems(changed.align));
1992
+ // Forward remaining FlexContainer props (e.g. padding, width, height)
1993
+ super.updateConfig(changed);
1994
+ }
1995
+ }
1996
+ function toAlignItems(align) {
1997
+ return align;
1998
+ }
1999
+
1865
2000
  /**
1866
2001
  * Background panel with optional flexbox content layout.
1867
2002
  *
@@ -3459,7 +3594,7 @@ function extendPixiElements() {
3459
3594
  */
3460
3595
  function extendUIElements() {
3461
3596
  extend({
3462
- Button, Label, Panel, FlexContainer, ProgressBar,
3597
+ Button, Label, LabelValue, Panel, FlexContainer, ProgressBar,
3463
3598
  ScrollContainer, Modal, Toast, BalanceDisplay, WinDisplay, Layout,
3464
3599
  Slider, Toggle,
3465
3600
  });