@energy8platform/game-engine 0.14.5 → 0.14.7

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.esm.js CHANGED
@@ -23,6 +23,11 @@ function extend(components) {
23
23
  const RESERVED = new Set(['children', 'key', 'ref']);
24
24
  /** Props handled by the reconciler as flex item config, not forwarded to components */
25
25
  const FLEX_ITEM_PROPS$1 = new Set(['flexGrow', 'flexShrink', 'layoutWidth', 'layoutHeight', 'alignSelf', 'flexExclude', 'top', 'right', 'bottom', 'left']);
26
+ /** Base Container props applied directly to the instance (not via config) */
27
+ const CONTAINER_PROPS = new Set([
28
+ 'x', 'y', 'alpha', 'visible', 'rotation', 'angle', 'zIndex',
29
+ 'label', 'cursor', 'eventMode',
30
+ ]);
26
31
  // ─── UI Component helpers ────────────────────────────────
27
32
  /**
28
33
  * Extract a config object from React props.
@@ -32,7 +37,7 @@ const FLEX_ITEM_PROPS$1 = new Set(['flexGrow', 'flexShrink', 'layoutWidth', 'lay
32
37
  function extractConfig(props) {
33
38
  const config = {};
34
39
  for (const key in props) {
35
- if (RESERVED.has(key) || FLEX_ITEM_PROPS$1.has(key) || isEventProp(key))
40
+ if (RESERVED.has(key) || FLEX_ITEM_PROPS$1.has(key) || CONTAINER_PROPS.has(key) || isEventProp(key))
36
41
  continue;
37
42
  if (key.includes('-')) {
38
43
  const parts = key.split('-');
@@ -57,7 +62,7 @@ function diffConfig(newProps, oldProps) {
57
62
  const changed = {};
58
63
  // New or changed props
59
64
  for (const key in newProps) {
60
- if (RESERVED.has(key) || FLEX_ITEM_PROPS$1.has(key) || isEventProp(key))
65
+ if (RESERVED.has(key) || FLEX_ITEM_PROPS$1.has(key) || CONTAINER_PROPS.has(key) || isEventProp(key))
61
66
  continue;
62
67
  if (newProps[key] !== oldProps[key]) {
63
68
  if (key.includes('-')) {
@@ -153,6 +158,50 @@ function setNestedValue(target, path, value) {
153
158
  }
154
159
  obj[path[path.length - 1]] = value;
155
160
  }
161
+ /**
162
+ * Apply base Container props (x, y, alpha, visible, etc.) directly to the instance.
163
+ * Called for ALL elements — both UI components and standard PixiJS elements.
164
+ * Also handles scale, pivot, position, anchor via dash-notation.
165
+ */
166
+ function applyContainerProps(instance, newProps, oldProps = {}) {
167
+ for (const key of CONTAINER_PROPS) {
168
+ if (key in newProps && newProps[key] !== oldProps[key]) {
169
+ try {
170
+ instance[key] = newProps[key];
171
+ }
172
+ catch { /* read-only */ }
173
+ }
174
+ else if (key in oldProps && !(key in newProps)) {
175
+ // Prop removed — reset to undefined (PixiJS defaults)
176
+ try {
177
+ instance[key] = undefined;
178
+ }
179
+ catch { /* read-only */ }
180
+ }
181
+ }
182
+ // Handle scale as uniform number or {x,y} object
183
+ if ('scale' in newProps && newProps.scale !== oldProps.scale) {
184
+ const s = newProps.scale;
185
+ if (typeof s === 'number') {
186
+ instance.scale?.set?.(s, s);
187
+ }
188
+ else if (s && typeof s === 'object') {
189
+ instance.scale?.set?.(s.x ?? 1, s.y ?? 1);
190
+ }
191
+ }
192
+ // Handle dash-notation container props: scale-x, scale-y, pivot-x, pivot-y, position-x, position-y, anchor-x, anchor-y
193
+ for (const key in newProps) {
194
+ if (!key.includes('-'))
195
+ continue;
196
+ const parts = key.split('-');
197
+ const root = parts[0];
198
+ if (root === 'scale' || root === 'pivot' || root === 'position' || root === 'anchor') {
199
+ if (newProps[key] !== oldProps[key]) {
200
+ setNestedValue(instance, parts, newProps[key]);
201
+ }
202
+ }
203
+ }
204
+ }
156
205
  function applyProps(instance, newProps, oldProps = {}) {
157
206
  // Remove old props not in newProps
158
207
  for (const key in oldProps) {
@@ -818,6 +867,17 @@ function isSuspendable(obj) {
818
867
  }
819
868
  /** Layout containers that need flush after commit phase */
820
869
  const pendingLayoutFlush = new Set();
870
+ /** Suspend a layout container and all its suspendable ancestors, add them to pending flush */
871
+ function suspendWithAncestors(instance) {
872
+ let current = instance;
873
+ while (current) {
874
+ if (isSuspendable(current)) {
875
+ current.suspendLayout();
876
+ pendingLayoutFlush.add(current);
877
+ }
878
+ current = current.parent;
879
+ }
880
+ }
821
881
  /** Extract FlexItemConfig from props if any flex item props are present */
822
882
  function extractFlexItemConfig(props) {
823
883
  let config;
@@ -860,6 +920,7 @@ const hostConfig = {
860
920
  // Config-based UI component: pass props as constructor config
861
921
  const config = extractConfig(props);
862
922
  instance = new Ctor(config);
923
+ applyContainerProps(instance, props);
863
924
  applyEventProps(instance, props);
864
925
  }
865
926
  else {
@@ -965,11 +1026,18 @@ const hostConfig = {
965
1026
  }
966
1027
  },
967
1028
  commitUpdate(instance, _updatePayload, _type, oldProps, newProps) {
1029
+ // Suspend this instance and ancestors before applying changes —
1030
+ // prevents intermediate relayouts with partially-updated tree
1031
+ const dimensionsChanged = newProps.width !== oldProps.width || newProps.height !== oldProps.height;
1032
+ if (isSuspendable(instance) || dimensionsChanged) {
1033
+ suspendWithAncestors(instance);
1034
+ }
968
1035
  if (typeof instance.updateConfig === 'function') {
969
1036
  const changed = diffConfig(newProps, oldProps);
970
1037
  if (Object.keys(changed).length > 0) {
971
1038
  instance.updateConfig(changed);
972
1039
  }
1040
+ applyContainerProps(instance, newProps, oldProps);
973
1041
  applyEventProps(instance, newProps, oldProps);
974
1042
  }
975
1043
  else {
@@ -992,11 +1060,9 @@ const hostConfig = {
992
1060
  }
993
1061
  }
994
1062
  }
995
- // Trigger parent relayout if flex config or dimensions changed
996
- if (newFlexConfig || oldFlexConfig || newProps.width !== oldProps.width || newProps.height !== oldProps.height) {
997
- if (instance.parent instanceof FlexContainer) {
998
- instance.parent.updateLayout();
999
- }
1063
+ // Mark ancestors dirty if flex config or dimensions changed
1064
+ if (newFlexConfig || oldFlexConfig || dimensionsChanged) {
1065
+ suspendWithAncestors(instance);
1000
1066
  }
1001
1067
  if (hasEventProps(newProps) && instance.eventMode === 'auto') {
1002
1068
  instance.eventMode = 'static';
@@ -1028,8 +1094,25 @@ const hostConfig = {
1028
1094
  return null;
1029
1095
  },
1030
1096
  resetAfterCommit() {
1031
- // Flush deferred layout for all FlexContainers modified during this commit
1032
- for (const fc of pendingLayoutFlush) {
1097
+ if (pendingLayoutFlush.size === 0)
1098
+ return;
1099
+ // Sort by depth (deepest first) so children compute sizes before parents lay out
1100
+ const sorted = [...pendingLayoutFlush].sort((a, b) => {
1101
+ let da = 0;
1102
+ let n = a;
1103
+ while (n.parent) {
1104
+ da++;
1105
+ n = n.parent;
1106
+ }
1107
+ let db = 0;
1108
+ n = b;
1109
+ while (n.parent) {
1110
+ db++;
1111
+ n = n.parent;
1112
+ }
1113
+ return db - da; // deepest first
1114
+ });
1115
+ for (const fc of sorted) {
1033
1116
  fc.resumeLayout();
1034
1117
  }
1035
1118
  pendingLayoutFlush.clear();
@@ -2186,10 +2269,11 @@ class Modal extends Container {
2186
2269
  // Overlay
2187
2270
  this._overlay = new Graphics();
2188
2271
  this._overlay.eventMode = 'static';
2272
+ this._overlay.on('pointertap', () => {
2273
+ if (this._config.closeOnOverlay)
2274
+ this.hide();
2275
+ });
2189
2276
  this.addChild(this._overlay);
2190
- if (this._config.closeOnOverlay) {
2191
- this._overlay.on('pointertap', () => this.hide());
2192
- }
2193
2277
  // Content container
2194
2278
  this._contentContainer = new Container();
2195
2279
  this.addChild(this._contentContainer);