@number10/phaserjsx 0.2.0 → 0.4.0

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 (138) hide show
  1. package/dist/{TransformOriginView-BDM6GE2F.cjs → TransformOriginView-Bx81YEUU.cjs} +1378 -1518
  2. package/dist/TransformOriginView-Bx81YEUU.cjs.map +1 -0
  3. package/dist/{TransformOriginView-CiFiQcku.js → TransformOriginView-DCvId72M.js} +1500 -1640
  4. package/dist/TransformOriginView-DCvId72M.js.map +1 -0
  5. package/dist/camera/camera-fx-registry.d.ts +47 -0
  6. package/dist/camera/camera-fx-registry.d.ts.map +1 -0
  7. package/dist/camera/index.d.ts +6 -0
  8. package/dist/camera/index.d.ts.map +1 -0
  9. package/dist/camera/use-camera-fx.d.ts +59 -0
  10. package/dist/camera/use-camera-fx.d.ts.map +1 -0
  11. package/dist/components/appliers/applyBackground.d.ts +4 -0
  12. package/dist/components/appliers/applyBackground.d.ts.map +1 -1
  13. package/dist/components/appliers/applyParticles.d.ts +7 -0
  14. package/dist/components/appliers/applyParticles.d.ts.map +1 -0
  15. package/dist/components/appliers/applyParticlesLayout.d.ts +11 -0
  16. package/dist/components/appliers/applyParticlesLayout.d.ts.map +1 -0
  17. package/dist/components/creators/createParticlesLayout.d.ts +14 -0
  18. package/dist/components/creators/createParticlesLayout.d.ts.map +1 -0
  19. package/dist/components/custom/Accordion.d.ts +3 -2
  20. package/dist/components/custom/Accordion.d.ts.map +1 -1
  21. package/dist/components/custom/AlertDialog.d.ts +2 -1
  22. package/dist/components/custom/AlertDialog.d.ts.map +1 -1
  23. package/dist/components/custom/Button.d.ts +2 -1
  24. package/dist/components/custom/Button.d.ts.map +1 -1
  25. package/dist/components/custom/CharText/CharText.d.ts +2 -1
  26. package/dist/components/custom/CharText/CharText.d.ts.map +1 -1
  27. package/dist/components/custom/CharTextInput.d.ts +2 -1
  28. package/dist/components/custom/CharTextInput.d.ts.map +1 -1
  29. package/dist/components/custom/Dialog.d.ts +2 -1
  30. package/dist/components/custom/Dialog.d.ts.map +1 -1
  31. package/dist/components/custom/Divider.d.ts +2 -1
  32. package/dist/components/custom/Divider.d.ts.map +1 -1
  33. package/dist/components/custom/Dropdown.d.ts +2 -1
  34. package/dist/components/custom/Dropdown.d.ts.map +1 -1
  35. package/dist/components/custom/Graphics.d.ts +45 -0
  36. package/dist/components/custom/Graphics.d.ts.map +1 -0
  37. package/dist/components/custom/Icon.d.ts +3 -2
  38. package/dist/components/custom/Icon.d.ts.map +1 -1
  39. package/dist/components/custom/Image.d.ts +2 -1
  40. package/dist/components/custom/Image.d.ts.map +1 -1
  41. package/dist/components/custom/Joystick.d.ts +42 -0
  42. package/dist/components/custom/Joystick.d.ts.map +1 -0
  43. package/dist/components/custom/Modal.d.ts +2 -1
  44. package/dist/components/custom/Modal.d.ts.map +1 -1
  45. package/dist/components/custom/NineSlice.d.ts +2 -1
  46. package/dist/components/custom/NineSlice.d.ts.map +1 -1
  47. package/dist/components/custom/NineSliceButton.d.ts +2 -1
  48. package/dist/components/custom/NineSliceButton.d.ts.map +1 -1
  49. package/dist/components/custom/Particles.d.ts +17 -0
  50. package/dist/components/custom/Particles.d.ts.map +1 -0
  51. package/dist/components/custom/Portal.d.ts +2 -1
  52. package/dist/components/custom/Portal.d.ts.map +1 -1
  53. package/dist/components/custom/RadioButton.d.ts +2 -1
  54. package/dist/components/custom/RadioButton.d.ts.map +1 -1
  55. package/dist/components/custom/RadioGroup.d.ts +2 -5
  56. package/dist/components/custom/RadioGroup.d.ts.map +1 -1
  57. package/dist/components/custom/RefOriginView.d.ts +2 -1
  58. package/dist/components/custom/RefOriginView.d.ts.map +1 -1
  59. package/dist/components/custom/ScrollSlider.d.ts +7 -2
  60. package/dist/components/custom/ScrollSlider.d.ts.map +1 -1
  61. package/dist/components/custom/ScrollView.d.ts +29 -4
  62. package/dist/components/custom/ScrollView.d.ts.map +1 -1
  63. package/dist/components/custom/Sidebar.d.ts +2 -1
  64. package/dist/components/custom/Sidebar.d.ts.map +1 -1
  65. package/dist/components/custom/Slider.d.ts +4 -3
  66. package/dist/components/custom/Slider.d.ts.map +1 -1
  67. package/dist/components/custom/Sprite.d.ts +74 -0
  68. package/dist/components/custom/Sprite.d.ts.map +1 -0
  69. package/dist/components/custom/Tabs.d.ts +50 -0
  70. package/dist/components/custom/Tabs.d.ts.map +1 -0
  71. package/dist/components/custom/Text.d.ts +2 -1
  72. package/dist/components/custom/Text.d.ts.map +1 -1
  73. package/dist/components/custom/TileSprite.d.ts +60 -0
  74. package/dist/components/custom/TileSprite.d.ts.map +1 -0
  75. package/dist/components/custom/Toggle.d.ts +2 -1
  76. package/dist/components/custom/Toggle.d.ts.map +1 -1
  77. package/dist/components/custom/TransformOriginView.d.ts +3 -2
  78. package/dist/components/custom/TransformOriginView.d.ts.map +1 -1
  79. package/dist/components/custom/View.d.ts +2 -1
  80. package/dist/components/custom/View.d.ts.map +1 -1
  81. package/dist/components/custom/WrapText.d.ts +2 -1
  82. package/dist/components/custom/WrapText.d.ts.map +1 -1
  83. package/dist/components/custom/index.cjs +6 -1
  84. package/dist/components/custom/index.cjs.map +1 -1
  85. package/dist/components/custom/index.d.ts +3 -0
  86. package/dist/components/custom/index.d.ts.map +1 -1
  87. package/dist/components/custom/index.js +16 -11
  88. package/dist/components/index.d.ts +10 -8
  89. package/dist/components/index.d.ts.map +1 -1
  90. package/dist/components/internal/SceneWrapper.d.ts +1 -1
  91. package/dist/components/internal/SceneWrapper.d.ts.map +1 -1
  92. package/dist/components/primitives/particles.d.ts +37 -0
  93. package/dist/components/primitives/particles.d.ts.map +1 -0
  94. package/dist/core-types.d.ts +5 -0
  95. package/dist/core-types.d.ts.map +1 -1
  96. package/dist/gestures/gesture-manager.d.ts.map +1 -1
  97. package/dist/hooks.d.ts +124 -3
  98. package/dist/hooks.d.ts.map +1 -1
  99. package/dist/index.cjs +2153 -20
  100. package/dist/index.cjs.map +1 -1
  101. package/dist/index.d.ts +4 -1
  102. package/dist/index.d.ts.map +1 -1
  103. package/dist/index.js +2265 -131
  104. package/dist/index.js.map +1 -1
  105. package/dist/jsx-runtime.cjs.map +1 -1
  106. package/dist/jsx-runtime.d.ts +2 -3
  107. package/dist/jsx-runtime.d.ts.map +1 -1
  108. package/dist/jsx-runtime.js.map +1 -1
  109. package/dist/jsx-types.d.ts +8 -0
  110. package/dist/jsx-types.d.ts.map +1 -1
  111. package/dist/layout/layout-engine.d.ts.map +1 -1
  112. package/dist/layout/utils/size-resolver.d.ts.map +1 -1
  113. package/dist/particles/emit-zone.d.ts +67 -0
  114. package/dist/particles/emit-zone.d.ts.map +1 -0
  115. package/dist/particles/index.d.ts +8 -0
  116. package/dist/particles/index.d.ts.map +1 -0
  117. package/dist/particles/particle-types.d.ts +20 -0
  118. package/dist/particles/particle-types.d.ts.map +1 -0
  119. package/dist/particles/preset-registry.d.ts +46 -0
  120. package/dist/particles/preset-registry.d.ts.map +1 -0
  121. package/dist/particles/use-particles.d.ts +15 -0
  122. package/dist/particles/use-particles.d.ts.map +1 -0
  123. package/dist/particles/utils.d.ts +10 -0
  124. package/dist/particles/utils.d.ts.map +1 -0
  125. package/dist/plugin.d.ts +157 -0
  126. package/dist/plugin.d.ts.map +1 -0
  127. package/dist/theme-base.d.ts +10 -1
  128. package/dist/theme-base.d.ts.map +1 -1
  129. package/dist/theme-custom.d.ts +7 -0
  130. package/dist/theme-custom.d.ts.map +1 -1
  131. package/dist/theme-defaults.d.ts.map +1 -1
  132. package/dist/types.d.ts +18 -1
  133. package/dist/types.d.ts.map +1 -1
  134. package/dist/vdom.d.ts +42 -4
  135. package/dist/vdom.d.ts.map +1 -1
  136. package/package.json +4 -5
  137. package/dist/TransformOriginView-BDM6GE2F.cjs.map +0 -1
  138. package/dist/TransformOriginView-CiFiQcku.js.map +0 -1
@@ -75,623 +75,6 @@ const host = {
75
75
  layout() {
76
76
  }
77
77
  };
78
- function shallowEqual$1(a, b) {
79
- if (!a || !b) return a === b;
80
- if (a.length !== b.length) return false;
81
- return a.every((val, i) => val === b[i]);
82
- }
83
- function applyGraphicsProps(node, _prev, next) {
84
- const prevDeps = node.__drawDependencies;
85
- const nextDeps = next.dependencies;
86
- const depsChanged2 = !shallowEqual$1(prevDeps, nextDeps);
87
- if (depsChanged2 && next.onDraw) {
88
- if (next.autoClear !== false) {
89
- node.clear();
90
- }
91
- next.onDraw(node, next);
92
- node.__drawDependencies = nextDeps;
93
- }
94
- }
95
- function applyGraphicsLayout(node, prev, next) {
96
- node.__layoutProps = next;
97
- if (prev.width !== next.width || prev.height !== next.height || prev.headless !== next.headless) {
98
- node.__getLayoutSize = () => {
99
- if (next.headless ?? true) {
100
- return { width: 0.01, height: 0.01 };
101
- }
102
- return {
103
- width: typeof next.width === "number" ? next.width : 0,
104
- height: typeof next.height === "number" ? next.height : 0
105
- };
106
- };
107
- }
108
- }
109
- function normalizeVisible$1(visible) {
110
- if (visible === void 0) return true;
111
- if (typeof visible === "boolean") return visible;
112
- if (visible === "visible") return true;
113
- if (visible === "invisible" || visible === "none") return false;
114
- return true;
115
- }
116
- function applyPhaserProps(node, prev, next) {
117
- if (prev.alpha !== next.alpha && typeof next.alpha === "number") {
118
- node.setAlpha?.(next.alpha);
119
- }
120
- if (prev.depth !== next.depth && typeof next.depth === "number") {
121
- node.setDepth?.(next.depth);
122
- }
123
- if (prev.visible !== next.visible) {
124
- const visibleValue = normalizeVisible$1(next.visible);
125
- node.visible = visibleValue;
126
- }
127
- }
128
- function applyTransformProps(node, prev, next) {
129
- if (prev.x !== next.x && typeof next.x === "number") {
130
- node.x = next.x;
131
- }
132
- if (prev.y !== next.y && typeof next.y === "number") {
133
- node.y = next.y;
134
- }
135
- if (prev.rotation !== next.rotation && typeof next.rotation === "number") {
136
- node.rotation = next.rotation;
137
- }
138
- const nextScale = next.scale;
139
- const nextScaleX = next.scaleX;
140
- const nextScaleY = next.scaleY;
141
- const prevScale = prev.scale;
142
- const prevScaleX = prev.scaleX;
143
- const prevScaleY = prev.scaleY;
144
- if (nextScale !== void 0 && nextScale !== prevScale) {
145
- node.setScale?.(nextScale, nextScale);
146
- } else if (nextScaleX !== prevScaleX || nextScaleY !== prevScaleY) {
147
- const currentScaleX = node.scaleX ?? 1;
148
- const currentScaleY = node.scaleY ?? 1;
149
- const sx = nextScaleX ?? currentScaleX;
150
- const sy = nextScaleY ?? currentScaleY;
151
- node.setScale?.(sx, sy);
152
- }
153
- }
154
- function createGraphicsLayout(graphics, props) {
155
- if (props.headless === false) {
156
- if (typeof props.width !== "number" || typeof props.height !== "number") {
157
- throw new Error(
158
- "Graphics component requires explicit width and height props when headless=false"
159
- );
160
- }
161
- }
162
- graphics.__layoutProps = props;
163
- graphics.__getLayoutSize = () => {
164
- if (graphics.__layoutProps?.headless ?? true) {
165
- return { width: 0.01, height: 0.01 };
166
- }
167
- return {
168
- width: props.width ?? 0,
169
- height: props.height ?? 0
170
- };
171
- };
172
- graphics.__drawDependencies = props.dependencies;
173
- }
174
- function normalizeVisible(visible) {
175
- if (visible === void 0) return true;
176
- if (typeof visible === "boolean") return visible;
177
- if (visible === "visible") return true;
178
- if (visible === "invisible" || visible === "none") return false;
179
- return true;
180
- }
181
- function createPhaser(node, props) {
182
- if (props.visible !== void 0) {
183
- node.visible = normalizeVisible(props.visible);
184
- }
185
- if (props.depth !== void 0) {
186
- node.setDepth(props.depth);
187
- }
188
- if (props.alpha !== void 0) {
189
- node.setAlpha(props.alpha);
190
- }
191
- }
192
- function createTransform(node, props) {
193
- if (props.scaleX !== void 0 || props.scaleY !== void 0) {
194
- node.setScale(
195
- props.scaleX ?? 1,
196
- props.scaleY ?? 1
197
- );
198
- }
199
- if (props.rotation !== void 0) {
200
- node.setRotation(props.rotation);
201
- }
202
- }
203
- const graphicsCreator = (scene, props) => {
204
- const graphics = scene.add.graphics();
205
- graphics.setPosition(props.x ?? 0, props.y ?? 0);
206
- createTransform(graphics, props);
207
- createPhaser(graphics, props);
208
- createGraphicsLayout(graphics, props);
209
- if (props.onDraw) {
210
- props.onDraw(graphics, props);
211
- }
212
- return graphics;
213
- };
214
- const graphicsPatcher = (node, prev, next) => {
215
- applyTransformProps(node, prev, next);
216
- applyPhaserProps(node, prev, next);
217
- applyGraphicsProps(node, prev, next);
218
- applyGraphicsLayout(node, prev, next);
219
- };
220
- function calculateFitScale$1(image, targetWidth, targetHeight, fit = "fill") {
221
- const textureWidth = image.width;
222
- const textureHeight = image.height;
223
- if (textureWidth === 0 || textureHeight === 0) {
224
- return { scaleX: 1, scaleY: 1 };
225
- }
226
- if (fit === "fill") {
227
- return {
228
- scaleX: targetWidth / textureWidth,
229
- scaleY: targetHeight / textureHeight
230
- };
231
- }
232
- const targetAspect = targetWidth / targetHeight;
233
- const textureAspect = textureWidth / textureHeight;
234
- if (fit === "contain") {
235
- const scale = targetAspect > textureAspect ? targetHeight / textureHeight : targetWidth / textureWidth;
236
- return { scaleX: scale, scaleY: scale };
237
- }
238
- if (fit === "cover") {
239
- const scale = targetAspect < textureAspect ? targetHeight / textureHeight : targetWidth / textureWidth;
240
- return { scaleX: scale, scaleY: scale };
241
- }
242
- return { scaleX: 1, scaleY: 1 };
243
- }
244
- function applyImageProps(image, prev, next) {
245
- const textureChanged = prev.texture !== next.texture || prev.frame !== next.frame;
246
- if (textureChanged && next.texture) {
247
- image.setTexture(next.texture, next.frame);
248
- }
249
- if (prev.tint !== next.tint) {
250
- if (typeof next.tint === "number") {
251
- image.setTint(next.tint);
252
- } else {
253
- image.clearTint();
254
- }
255
- }
256
- if (prev.originX !== next.originX || prev.originY !== next.originY) {
257
- const originX = next.originX ?? image.originX;
258
- const originY = next.originY ?? image.originY;
259
- image.setOrigin(originX, originY);
260
- }
261
- const displayWidthChanged = prev.displayWidth !== next.displayWidth;
262
- const displayHeightChanged = prev.displayHeight !== next.displayHeight;
263
- const fitChanged = prev.fit !== next.fit;
264
- if (displayWidthChanged || displayHeightChanged || fitChanged || textureChanged) {
265
- if (typeof next.displayWidth === "number" && typeof next.displayHeight === "number") {
266
- const { scaleX, scaleY } = calculateFitScale$1(
267
- image,
268
- next.displayWidth,
269
- next.displayHeight,
270
- next.fit
271
- );
272
- image.setScale(scaleX, scaleY);
273
- } else if (typeof next.displayWidth === "number") {
274
- const scale = next.displayWidth / image.width;
275
- image.setScale(scale);
276
- } else if (typeof next.displayHeight === "number") {
277
- const scale = next.displayHeight / image.height;
278
- image.setScale(scale, scale);
279
- }
280
- }
281
- }
282
- function applyImageLayout(image, prev, next) {
283
- image.__layoutProps = next;
284
- if (prev.headless !== next.headless) {
285
- image.__getLayoutSize = () => {
286
- if (image.__layoutProps?.headless) {
287
- return { width: 0.01, height: 0.01 };
288
- }
289
- return {
290
- width: image.displayWidth,
291
- height: image.displayHeight
292
- };
293
- };
294
- }
295
- }
296
- function createImageLayout(image, props) {
297
- image.__layoutProps = props;
298
- image.__getLayoutSize = () => {
299
- if (image.__layoutProps?.headless) {
300
- return { width: 0.01, height: 0.01 };
301
- }
302
- return {
303
- width: image.displayWidth,
304
- height: image.displayHeight
305
- };
306
- };
307
- }
308
- const imageCreator = (scene, props) => {
309
- const image = scene.add.image(props.x ?? 0, props.y ?? 0, props.texture, props.frame);
310
- if (props.headless) {
311
- image.setOrigin(0.5, 0.5);
312
- } else {
313
- image.setOrigin(0, 0);
314
- }
315
- if (props.originX !== void 0 || props.originY !== void 0) {
316
- image.setOrigin(props.originX ?? image.originX, props.originY ?? image.originY);
317
- }
318
- const normalizedProps = { ...props };
319
- if (props.headless) {
320
- delete normalizedProps.padding;
321
- delete normalizedProps.margin;
322
- delete normalizedProps.gap;
323
- } else {
324
- if (normalizedProps.rotation !== void 0) {
325
- delete normalizedProps.rotation;
326
- }
327
- }
328
- createTransform(image, normalizedProps);
329
- createPhaser(image, normalizedProps);
330
- if (props.tint !== void 0) {
331
- image.setTint(props.tint);
332
- }
333
- if (props.displayWidth !== void 0 || props.displayHeight !== void 0) {
334
- if (props.displayWidth !== void 0 && props.displayHeight !== void 0) {
335
- const fit = props.fit ?? "fill";
336
- const textureWidth = image.width;
337
- const textureHeight = image.height;
338
- if (textureWidth > 0 && textureHeight > 0) {
339
- if (fit === "fill") {
340
- image.setDisplaySize(props.displayWidth, props.displayHeight);
341
- } else if (fit === "contain") {
342
- const targetAspect = props.displayWidth / props.displayHeight;
343
- const textureAspect = textureWidth / textureHeight;
344
- const scale = targetAspect > textureAspect ? props.displayHeight / textureHeight : props.displayWidth / textureWidth;
345
- image.setScale(scale);
346
- } else if (fit === "cover") {
347
- const targetAspect = props.displayWidth / props.displayHeight;
348
- const textureAspect = textureWidth / textureHeight;
349
- const scale = targetAspect < textureAspect ? props.displayHeight / textureHeight : props.displayWidth / textureWidth;
350
- image.setScale(scale);
351
- }
352
- }
353
- } else if (props.displayWidth !== void 0) {
354
- const scale = props.displayWidth / image.width;
355
- image.setScale(scale);
356
- } else if (props.displayHeight !== void 0) {
357
- const scale = props.displayHeight / image.height;
358
- image.setScale(scale);
359
- }
360
- }
361
- createImageLayout(image, normalizedProps);
362
- if (props.onReady) {
363
- props.onReady(image);
364
- }
365
- return image;
366
- };
367
- const imagePatcher = (node, prev, next) => {
368
- if (prev.headless !== next.headless) {
369
- if (next.headless) {
370
- node.setOrigin(0.5, 0.5);
371
- } else {
372
- node.setOrigin(0, 0);
373
- }
374
- }
375
- const normalizedPrev = { ...prev };
376
- const normalizedNext = { ...next };
377
- if (next.headless) {
378
- delete normalizedNext.padding;
379
- delete normalizedNext.margin;
380
- delete normalizedNext.gap;
381
- } else {
382
- if (normalizedNext.rotation !== void 0) {
383
- delete normalizedNext.rotation;
384
- }
385
- }
386
- if (prev.headless) {
387
- delete normalizedPrev.padding;
388
- delete normalizedPrev.margin;
389
- delete normalizedPrev.gap;
390
- } else {
391
- if (normalizedPrev.rotation !== void 0) {
392
- delete normalizedPrev.rotation;
393
- }
394
- }
395
- applyTransformProps(node, normalizedPrev, normalizedNext);
396
- applyPhaserProps(node, normalizedPrev, normalizedNext);
397
- applyImageProps(node, normalizedPrev, normalizedNext);
398
- applyImageLayout(node, normalizedPrev, normalizedNext);
399
- };
400
- function applyNineSliceProps(nineSlice, prev, next) {
401
- const textureChanged = prev.texture !== next.texture || prev.frame !== next.frame;
402
- if (textureChanged && next.texture) {
403
- nineSlice.setTexture(next.texture, next.frame);
404
- }
405
- const sliceChanged = prev.leftWidth !== next.leftWidth || prev.rightWidth !== next.rightWidth || prev.topHeight !== next.topHeight || prev.bottomHeight !== next.bottomHeight;
406
- if (sliceChanged) {
407
- const width = typeof next.width === "number" ? next.width : nineSlice.width;
408
- const height = typeof next.height === "number" ? next.height : nineSlice.height;
409
- nineSlice.setSlices(
410
- width,
411
- height,
412
- next.leftWidth ?? prev.leftWidth ?? 0,
413
- next.rightWidth ?? prev.rightWidth ?? 0,
414
- next.topHeight ?? prev.topHeight,
415
- next.bottomHeight ?? prev.bottomHeight
416
- );
417
- }
418
- const prevWidth = typeof prev.width === "number" ? prev.width : nineSlice.width;
419
- const nextWidth = typeof next.width === "number" ? next.width : nineSlice.width;
420
- const prevHeight = typeof prev.height === "number" ? prev.height : nineSlice.height;
421
- const nextHeight = typeof next.height === "number" ? next.height : nineSlice.height;
422
- if (prevWidth !== nextWidth || prevHeight !== nextHeight) {
423
- nineSlice.setSize(nextWidth, nextHeight);
424
- }
425
- if (prev.tint !== next.tint) {
426
- if (next.tint !== void 0) {
427
- nineSlice.setTint(next.tint);
428
- } else {
429
- nineSlice.clearTint();
430
- }
431
- }
432
- }
433
- function applyNineSliceLayout(nineSlice, prev, next) {
434
- nineSlice.__layoutProps = next;
435
- if (prev.width !== next.width || prev.height !== next.height) {
436
- nineSlice.__getLayoutSize = () => {
437
- return {
438
- width: nineSlice.width,
439
- height: nineSlice.height
440
- };
441
- };
442
- }
443
- }
444
- function createNineSliceLayout(nineSlice, props) {
445
- nineSlice.__layoutProps = props;
446
- nineSlice.__getLayoutSize = () => {
447
- return {
448
- width: nineSlice.width,
449
- height: nineSlice.height
450
- };
451
- };
452
- }
453
- const nineSliceCreator = (scene, props) => {
454
- const initialWidth = typeof props.width === "number" ? props.width : 64;
455
- const initialHeight = typeof props.height === "number" ? props.height : 64;
456
- const nineSlice = scene.add.nineslice(
457
- props.x ?? 0,
458
- props.y ?? 0,
459
- props.texture,
460
- props.frame,
461
- initialWidth,
462
- initialHeight,
463
- props.leftWidth,
464
- props.rightWidth,
465
- props.topHeight,
466
- props.bottomHeight
467
- );
468
- nineSlice.setOrigin(0, 0);
469
- if (props.tint !== void 0) {
470
- nineSlice.setTint(props.tint);
471
- }
472
- createTransform(nineSlice, props);
473
- createPhaser(nineSlice, props);
474
- createNineSliceLayout(nineSlice, props);
475
- return nineSlice;
476
- };
477
- const nineSlicePatcher = (node, prev, next) => {
478
- applyTransformProps(node, prev, next);
479
- applyPhaserProps(node, prev, next);
480
- applyNineSliceProps(node, prev, next);
481
- applyNineSliceLayout(node, prev, next);
482
- };
483
- function getOriginalTextureDimensions(sprite) {
484
- const frame = sprite.frame;
485
- return {
486
- width: frame.width,
487
- height: frame.height
488
- };
489
- }
490
- function calculateFitScale(sprite, targetWidth, targetHeight, fit = "fill") {
491
- const { width: textureWidth, height: textureHeight } = getOriginalTextureDimensions(sprite);
492
- if (textureWidth === 0 || textureHeight === 0) {
493
- return { scaleX: 1, scaleY: 1 };
494
- }
495
- if (fit === "fill") {
496
- return {
497
- scaleX: targetWidth / textureWidth,
498
- scaleY: targetHeight / textureHeight
499
- };
500
- }
501
- const targetAspect = targetWidth / targetHeight;
502
- const textureAspect = textureWidth / textureHeight;
503
- if (fit === "contain") {
504
- const scale = targetAspect > textureAspect ? targetHeight / textureHeight : targetWidth / textureWidth;
505
- return { scaleX: scale, scaleY: scale };
506
- }
507
- if (fit === "cover") {
508
- const scale = targetAspect < textureAspect ? targetHeight / textureHeight : targetWidth / textureWidth;
509
- return { scaleX: scale, scaleY: scale };
510
- }
511
- return { scaleX: 1, scaleY: 1 };
512
- }
513
- function applySpriteProps(sprite, prev, next) {
514
- const textureChanged = prev.texture !== next.texture || prev.frame !== next.frame;
515
- if (textureChanged && next.texture) {
516
- sprite.setTexture(next.texture, next.frame);
517
- }
518
- if (prev.tint !== next.tint) {
519
- if (typeof next.tint === "number") {
520
- sprite.setTint(next.tint);
521
- } else {
522
- sprite.clearTint();
523
- }
524
- }
525
- if (prev.originX !== next.originX || prev.originY !== next.originY) {
526
- const originX = next.originX ?? sprite.originX;
527
- const originY = next.originY ?? sprite.originY;
528
- sprite.setOrigin(originX, originY);
529
- }
530
- const displayWidthChanged = prev.displayWidth !== next.displayWidth;
531
- const displayHeightChanged = prev.displayHeight !== next.displayHeight;
532
- const fitChanged = prev.fit !== next.fit;
533
- if (displayWidthChanged || displayHeightChanged || fitChanged || textureChanged) {
534
- if (typeof next.displayWidth === "number" && typeof next.displayHeight === "number") {
535
- const fit = next.fit ?? "fill";
536
- if (fit === "fill") {
537
- sprite.setDisplaySize(next.displayWidth, next.displayHeight);
538
- } else {
539
- const { scaleX, scaleY } = calculateFitScale(
540
- sprite,
541
- next.displayWidth,
542
- next.displayHeight,
543
- fit
544
- );
545
- sprite.setScale(scaleX, scaleY);
546
- }
547
- } else if (typeof next.displayWidth === "number") {
548
- const { width: origWidth } = getOriginalTextureDimensions(sprite);
549
- const scale = next.displayWidth / origWidth;
550
- sprite.setScale(scale);
551
- } else if (typeof next.displayHeight === "number") {
552
- const { height: origHeight } = getOriginalTextureDimensions(sprite);
553
- const scale = next.displayHeight / origHeight;
554
- sprite.setScale(scale, scale);
555
- } else {
556
- sprite.setScale(1);
557
- }
558
- }
559
- const animationChanged = prev.animationKey !== next.animationKey || prev.loop !== next.loop || prev.repeatDelay !== next.repeatDelay;
560
- if (animationChanged) {
561
- if (sprite.anims.isPlaying) {
562
- sprite.anims.stop();
563
- }
564
- if (next.animationKey) {
565
- sprite.anims.play({
566
- key: next.animationKey,
567
- repeat: next.loop ? -1 : 0,
568
- repeatDelay: next.repeatDelay ?? 0
569
- });
570
- }
571
- }
572
- const callbacksChanged = prev.onAnimationStart !== next.onAnimationStart || prev.onAnimationComplete !== next.onAnimationComplete || prev.onAnimationRepeat !== next.onAnimationRepeat || prev.onAnimationUpdate !== next.onAnimationUpdate;
573
- if (callbacksChanged) {
574
- sprite.off("animationstart");
575
- sprite.off("animationcomplete");
576
- sprite.off("animationrepeat");
577
- sprite.off("animationupdate");
578
- if (next.onAnimationStart) {
579
- sprite.on("animationstart", (anim) => {
580
- next.onAnimationStart?.(anim.key);
581
- });
582
- }
583
- if (next.onAnimationComplete) {
584
- sprite.on("animationcomplete", (anim) => {
585
- next.onAnimationComplete?.(anim.key);
586
- });
587
- }
588
- if (next.onAnimationRepeat) {
589
- sprite.on("animationrepeat", (anim) => {
590
- next.onAnimationRepeat?.(anim.key);
591
- });
592
- }
593
- if (next.onAnimationUpdate) {
594
- sprite.on(
595
- "animationupdate",
596
- (anim, frame) => {
597
- next.onAnimationUpdate?.(anim.key, frame);
598
- }
599
- );
600
- }
601
- }
602
- }
603
- function applySpriteLayout(sprite, _prev, next) {
604
- sprite.__layoutProps = next;
605
- }
606
- function createSpriteLayout(sprite, props) {
607
- sprite.__layoutProps = props;
608
- sprite.__getLayoutSize = () => {
609
- return { width: 0.01, height: 0.01 };
610
- };
611
- }
612
- const spriteCreator = (scene, props) => {
613
- const sprite = scene.add.sprite(props.x ?? 0, props.y ?? 0, props.texture, props.frame);
614
- sprite.setOrigin(0.5, 0.5);
615
- if (props.originX !== void 0 || props.originY !== void 0) {
616
- sprite.setOrigin(props.originX ?? sprite.originX, props.originY ?? sprite.originY);
617
- }
618
- createTransform(sprite, props);
619
- createPhaser(sprite, props);
620
- if (props.tint !== void 0) {
621
- sprite.setTint(props.tint);
622
- }
623
- if (props.displayWidth !== void 0 || props.displayHeight !== void 0) {
624
- if (props.displayWidth !== void 0 && props.displayHeight !== void 0) {
625
- const fit = props.fit ?? "fill";
626
- const textureWidth = sprite.width;
627
- const textureHeight = sprite.height;
628
- if (textureWidth > 0 && textureHeight > 0) {
629
- if (fit === "fill") {
630
- sprite.setDisplaySize(props.displayWidth, props.displayHeight);
631
- } else if (fit === "contain") {
632
- const targetAspect = props.displayWidth / props.displayHeight;
633
- const textureAspect = textureWidth / textureHeight;
634
- const scale = targetAspect > textureAspect ? props.displayHeight / textureHeight : props.displayWidth / textureWidth;
635
- sprite.setScale(scale);
636
- } else if (fit === "cover") {
637
- const targetAspect = props.displayWidth / props.displayHeight;
638
- const textureAspect = textureWidth / textureHeight;
639
- const scale = targetAspect < textureAspect ? props.displayHeight / textureHeight : props.displayWidth / textureWidth;
640
- sprite.setScale(scale);
641
- }
642
- }
643
- } else if (props.displayWidth !== void 0) {
644
- const scale = props.displayWidth / sprite.width;
645
- sprite.setScale(scale);
646
- } else if (props.displayHeight !== void 0) {
647
- const scale = props.displayHeight / sprite.height;
648
- sprite.setScale(scale);
649
- }
650
- }
651
- if (props.animationKey) {
652
- if (sprite.scene && sprite.scene.anims.exists(props.animationKey)) {
653
- sprite.anims.play({
654
- key: props.animationKey,
655
- repeat: props.loop ? -1 : 0,
656
- repeatDelay: props.repeatDelay ?? 0
657
- });
658
- }
659
- }
660
- if (props.onAnimationStart) {
661
- sprite.on("animationstart", (anim) => {
662
- props.onAnimationStart?.(anim.key);
663
- });
664
- }
665
- if (props.onAnimationComplete) {
666
- sprite.on("animationcomplete", (anim) => {
667
- props.onAnimationComplete?.(anim.key);
668
- });
669
- }
670
- if (props.onAnimationRepeat) {
671
- sprite.on("animationrepeat", (anim) => {
672
- props.onAnimationRepeat?.(anim.key);
673
- });
674
- }
675
- if (props.onAnimationUpdate) {
676
- sprite.on(
677
- "animationupdate",
678
- (anim, frame) => {
679
- props.onAnimationUpdate?.(anim.key, frame);
680
- }
681
- );
682
- }
683
- createSpriteLayout(sprite, props);
684
- if (props.onReady) {
685
- props.onReady(sprite);
686
- }
687
- return sprite;
688
- };
689
- const spritePatcher = (node, prev, next) => {
690
- applyTransformProps(node, prev, next);
691
- applyPhaserProps(node, prev, next);
692
- applySpriteProps(node, prev, next);
693
- applySpriteLayout(node, prev, next);
694
- };
695
78
  var commonjsGlobal = typeof globalThis !== "undefined" ? globalThis : typeof window !== "undefined" ? window : typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : {};
696
79
  function getDefaultExportFromCjs(x) {
697
80
  return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, "default") ? x["default"] : x;
@@ -6644,10 +6027,6 @@ function resolveCalcOperand(operand, parentSize, viewportSize) {
6644
6027
  }
6645
6028
  if (operand.type === "percent") {
6646
6029
  if (parentSize === void 0) {
6647
- DebugLogger.warn(
6648
- "Size",
6649
- "Cannot resolve percentage in calc() without parent size. Using 0."
6650
- );
6651
6030
  return 0;
6652
6031
  }
6653
6032
  return parentSize * operand.value / 100;
@@ -6770,213 +6149,6 @@ function clampSize(size, minSize, maxSize, parentSize, fallbackSize, parentPaddi
6770
6149
  }
6771
6150
  return clamped;
6772
6151
  }
6773
- function applyTextProps(node, prev, next) {
6774
- if (node.active === false || node.scene && !node.scene.sys.game) {
6775
- return;
6776
- }
6777
- let needsUpdate = false;
6778
- if (prev.text !== next.text && typeof next.text === "string") {
6779
- node.setText(next.text);
6780
- needsUpdate = true;
6781
- }
6782
- if (next.style !== void 0 && !equal(next.style, prev.style || {})) {
6783
- try {
6784
- node.setStyle(next.style);
6785
- needsUpdate = true;
6786
- } catch (error) {
6787
- console.warn("Failed to apply text style (scene may be transitioning):", error);
6788
- }
6789
- }
6790
- if (next.maxWidth !== prev.maxWidth && next.maxWidth !== void 0) {
6791
- const viewport = viewportRegistry.getViewport();
6792
- const parsedMaxWidth = parseSize(next.maxWidth);
6793
- const resolvedMaxWidth = resolveSize(parsedMaxWidth, viewport?.width, void 0, void 0);
6794
- node.setWordWrapWidth(resolvedMaxWidth, true);
6795
- needsUpdate = true;
6796
- }
6797
- if (prev.style !== next.style && next.style !== void 0) {
6798
- try {
6799
- node.setStyle(next.style);
6800
- needsUpdate = true;
6801
- } catch (error) {
6802
- console.warn("Failed to apply text style (scene may be transitioning):", error);
6803
- }
6804
- }
6805
- if (needsUpdate && node.updateText) {
6806
- node.updateText();
6807
- }
6808
- }
6809
- function applyTextLayout(text, _prev, next) {
6810
- text.__layoutProps = next;
6811
- text.__getLayoutSize = () => {
6812
- if (text.__layoutProps?.headless) {
6813
- return { width: 0.01, height: 0.01 };
6814
- }
6815
- return {
6816
- width: text.width,
6817
- height: text.height
6818
- };
6819
- };
6820
- }
6821
- function createTextLayout(text, props) {
6822
- text.__layoutProps = props;
6823
- text.__getLayoutSize = () => {
6824
- if (text.__layoutProps?.headless) {
6825
- return { width: 0.01, height: 0.01 };
6826
- }
6827
- return {
6828
- width: text.width,
6829
- height: text.height
6830
- };
6831
- };
6832
- }
6833
- const textCreator = (scene, props) => {
6834
- const text = scene.add.text(props.x ?? 0, props.y ?? 0, props.text ?? "", props.style);
6835
- if (props.headless) {
6836
- text.setOrigin(0.5, 0.5);
6837
- } else {
6838
- text.setOrigin(0, 0);
6839
- }
6840
- const normalizedProps = { ...props };
6841
- if (props.headless) {
6842
- delete normalizedProps.padding;
6843
- delete normalizedProps.margin;
6844
- delete normalizedProps.gap;
6845
- } else {
6846
- if (normalizedProps.rotation !== void 0) {
6847
- delete normalizedProps.rotation;
6848
- }
6849
- }
6850
- createTransform(text, normalizedProps);
6851
- createPhaser(text, normalizedProps);
6852
- createTextLayout(text, normalizedProps);
6853
- return text;
6854
- };
6855
- const textPatcher = (node, prev, next) => {
6856
- if (prev.headless !== next.headless) {
6857
- if (next.headless) {
6858
- node.setOrigin(0.5, 0.5);
6859
- } else {
6860
- node.setOrigin(0, 0);
6861
- }
6862
- }
6863
- const normalizedPrev = { ...prev };
6864
- const normalizedNext = { ...next };
6865
- if (next.headless) {
6866
- delete normalizedNext.padding;
6867
- delete normalizedNext.margin;
6868
- delete normalizedNext.gap;
6869
- } else {
6870
- if (normalizedNext.rotation !== void 0) {
6871
- delete normalizedNext.rotation;
6872
- }
6873
- }
6874
- if (prev.headless) {
6875
- delete normalizedPrev.padding;
6876
- delete normalizedPrev.margin;
6877
- delete normalizedPrev.gap;
6878
- } else {
6879
- if (normalizedPrev.rotation !== void 0) {
6880
- delete normalizedPrev.rotation;
6881
- }
6882
- }
6883
- applyTransformProps(node, normalizedPrev, normalizedNext);
6884
- applyPhaserProps(node, normalizedPrev, normalizedNext);
6885
- applyTextProps(node, normalizedPrev, normalizedNext);
6886
- applyTextLayout(node, normalizedPrev, normalizedNext);
6887
- };
6888
- const tileSpriteCreator = (_scene, _props) => {
6889
- throw new Error(
6890
- "TileSprite component not implemented yet. This is a placeholder for architecture planning."
6891
- );
6892
- };
6893
- const tileSpritePatcher = (_node, _prev, _next) => {
6894
- throw new Error(
6895
- "TileSprite component not implemented yet. This is a placeholder for architecture planning."
6896
- );
6897
- };
6898
- function applyBackgroundProps(container, prev, next) {
6899
- const prevBgColor = prev.backgroundColor;
6900
- const nextBgColor = next.backgroundColor;
6901
- const prevBgAlpha = prev.backgroundAlpha ?? 1;
6902
- const nextBgAlpha = next.backgroundAlpha ?? 1;
6903
- const prevWidth = typeof prev.width === "number" ? prev.width : 100;
6904
- const nextWidth = typeof next.width === "number" ? next.width : 100;
6905
- const prevHeight = typeof prev.height === "number" ? prev.height : 100;
6906
- const nextHeight = typeof next.height === "number" ? next.height : 100;
6907
- const prevCornerRadius = prev.cornerRadius ?? 0;
6908
- const nextCornerRadius = next.cornerRadius ?? 0;
6909
- const prevBorderColor = prev.borderColor;
6910
- const nextBorderColor = next.borderColor;
6911
- const prevBorderWidth = prev.borderWidth ?? 0;
6912
- const nextBorderWidth = next.borderWidth ?? 0;
6913
- const prevBorderAlpha = prev.borderAlpha ?? 1;
6914
- const nextBorderAlpha = next.borderAlpha ?? 1;
6915
- const prevHasBorder = prevBorderWidth > 0 && prevBorderColor !== void 0;
6916
- const nextHasBorder = nextBorderWidth > 0 && nextBorderColor !== void 0;
6917
- const prevHasGraphics = prevBgColor !== void 0 || prevHasBorder;
6918
- const nextHasGraphics = nextBgColor !== void 0 || nextHasBorder;
6919
- if (prevHasGraphics && !nextHasGraphics) {
6920
- if (container.__background) {
6921
- container.__background.destroy();
6922
- delete container.__background;
6923
- }
6924
- } else if (!prevHasGraphics && nextHasGraphics) {
6925
- if (container.scene) {
6926
- const background = container.scene.add.graphics();
6927
- if (nextBgColor !== void 0) {
6928
- background.fillStyle(nextBgColor, nextBgAlpha);
6929
- }
6930
- if (nextHasBorder) {
6931
- background.lineStyle(nextBorderWidth, nextBorderColor, nextBorderAlpha);
6932
- }
6933
- if (nextCornerRadius !== 0) {
6934
- if (nextBgColor !== void 0) {
6935
- background.fillRoundedRect(0, 0, nextWidth, nextHeight, nextCornerRadius);
6936
- }
6937
- if (nextHasBorder) {
6938
- background.strokeRoundedRect(0, 0, nextWidth, nextHeight, nextCornerRadius);
6939
- }
6940
- } else {
6941
- if (nextBgColor !== void 0) {
6942
- background.fillRect(0, 0, nextWidth, nextHeight);
6943
- }
6944
- if (nextHasBorder) {
6945
- background.strokeRect(0, 0, nextWidth, nextHeight);
6946
- }
6947
- }
6948
- container.addAt(background, 0);
6949
- container.__background = background;
6950
- background.__isBackground = true;
6951
- }
6952
- } else if (container.__background && nextHasGraphics) {
6953
- const needsRedraw = prevBgColor !== nextBgColor || prevBgAlpha !== nextBgAlpha || prevWidth !== nextWidth || prevHeight !== nextHeight || prevCornerRadius !== nextCornerRadius || prevBorderWidth !== nextBorderWidth || prevBorderColor !== nextBorderColor || prevBorderAlpha !== nextBorderAlpha;
6954
- if (needsRedraw) {
6955
- container.__background.clear();
6956
- if (nextBgColor !== void 0) {
6957
- container.__background.fillStyle(nextBgColor, nextBgAlpha);
6958
- }
6959
- if (nextHasBorder) {
6960
- container.__background.lineStyle(nextBorderWidth, nextBorderColor, nextBorderAlpha);
6961
- }
6962
- if (nextCornerRadius !== 0) {
6963
- if (nextBgColor !== void 0) {
6964
- container.__background.fillRoundedRect(0, 0, nextWidth, nextHeight, nextCornerRadius);
6965
- }
6966
- if (nextHasBorder) {
6967
- container.__background.strokeRoundedRect(0, 0, nextWidth, nextHeight, nextCornerRadius);
6968
- }
6969
- } else {
6970
- if (nextBgColor !== void 0) {
6971
- container.__background.fillRect(0, 0, nextWidth, nextHeight);
6972
- }
6973
- if (nextHasBorder) {
6974
- container.__background.strokeRect(0, 0, nextWidth, nextHeight);
6975
- }
6976
- }
6977
- }
6978
- }
6979
- }
6980
6152
  const DEFAULT_GESTURE_CONFIG = {
6981
6153
  longPressDuration: 500,
6982
6154
  doubleTapDelay: 300,
@@ -7055,6 +6227,9 @@ class GestureManager {
7055
6227
  this.activePointerDown = null;
7056
6228
  }
7057
6229
  this.hoveredContainers.delete(container);
6230
+ for (const hitContainers of this.activeContainersForMove.values()) {
6231
+ hitContainers.delete(container);
6232
+ }
7058
6233
  }
7059
6234
  /**
7060
6235
  * Check if a container is registered
@@ -7233,8 +6408,8 @@ class GestureManager {
7233
6408
  this.activePointerDown = {
7234
6409
  pointerId: pointer.id,
7235
6410
  container: state.container,
7236
- startX: pointer.x,
7237
- startY: pointer.y
6411
+ startX: pointer.worldX,
6412
+ startY: pointer.worldY
7238
6413
  };
7239
6414
  state.longPressTriggered = false;
7240
6415
  state.pointerDownTime = Date.now();
@@ -7256,12 +6431,31 @@ class GestureManager {
7256
6431
  }
7257
6432
  }, state.config.longPressDuration);
7258
6433
  }
7259
- state.pointerDownPosition = { x: pointer.x, y: pointer.y };
6434
+ state.pointerDownPosition = { x: pointer.worldX, y: pointer.worldY };
7260
6435
  }
7261
6436
  }
7262
6437
  }
7263
6438
  if (hitContainers.size > 0) {
7264
6439
  this.activeContainersForMove.set(pointer.id, hitContainers);
6440
+ this.bubbleEvent(
6441
+ pointer,
6442
+ "onTouchMove",
6443
+ (targetState, targetLocalPos) => {
6444
+ const isInside = this.isPointerInContainer(pointer, targetState);
6445
+ const data = this.createEventData(
6446
+ pointer,
6447
+ targetLocalPos.x,
6448
+ targetLocalPos.y,
6449
+ targetState.hitArea.width,
6450
+ targetState.hitArea.height,
6451
+ { dx: 0, dy: 0, isInside, state: "start" }
6452
+ );
6453
+ targetState.callbacks.onTouchMove?.(data);
6454
+ targetState.isFirstMove = false;
6455
+ return data.isPropagationStopped();
6456
+ },
6457
+ hitContainers
6458
+ );
7265
6459
  }
7266
6460
  }
7267
6461
  /**
@@ -7283,8 +6477,8 @@ class GestureManager {
7283
6477
  const touchDuration = state.pointerDownTime ? Date.now() - state.pointerDownTime : 0;
7284
6478
  const isTouchTooLong = touchDuration > state.config.maxTouchDuration;
7285
6479
  const last = this.lastPointerPositions.get(pointer.id);
7286
- const dx = last ? pointer.x - last.x : 0;
7287
- const dy = last ? pointer.y - last.y : 0;
6480
+ const dx = last ? pointer.worldX - last.x : 0;
6481
+ const dy = last ? pointer.worldY - last.y : 0;
7288
6482
  const hitContainers = this.activeContainersForMove.get(pointer.id);
7289
6483
  this.bubbleEvent(
7290
6484
  pointer,
@@ -7420,8 +6614,8 @@ class GestureManager {
7420
6614
  state.longPressTimer = void 0;
7421
6615
  }
7422
6616
  const last = this.lastPointerPositions.get(pointer.id);
7423
- const dx = last ? pointer.x - last.x : 0;
7424
- const dy = last ? pointer.y - last.y : 0;
6617
+ const dx = last ? pointer.worldX - last.x : 0;
6618
+ const dy = last ? pointer.worldY - last.y : 0;
7425
6619
  const hitContainers = this.activeContainersForMove.get(pointer.id);
7426
6620
  this.bubbleEvent(
7427
6621
  pointer,
@@ -7459,9 +6653,9 @@ class GestureManager {
7459
6653
  */
7460
6654
  handlePointerMove(pointer) {
7461
6655
  const last = this.lastPointerPositions.get(pointer.id);
7462
- const dx = last ? pointer.x - last.x : 0;
7463
- const dy = last ? pointer.y - last.y : 0;
7464
- this.lastPointerPositions.set(pointer.id, { x: pointer.x, y: pointer.y });
6656
+ const dx = last ? pointer.worldX - last.x : 0;
6657
+ const dy = last ? pointer.worldY - last.y : 0;
6658
+ this.lastPointerPositions.set(pointer.id, { x: pointer.worldX, y: pointer.worldY });
7465
6659
  this.detectHoverChanges(pointer);
7466
6660
  if (!this.activePointerDown || pointer.id !== this.activePointerDown.pointerId) {
7467
6661
  return;
@@ -7535,7 +6729,7 @@ class GestureManager {
7535
6729
  getLocalPosition(pointer, container) {
7536
6730
  const matrix = container.getWorldTransformMatrix();
7537
6731
  const inverseMatrix = matrix.invert();
7538
- const localPos = inverseMatrix.transformPoint(pointer.x, pointer.y);
6732
+ const localPos = inverseMatrix.transformPoint(pointer.worldX, pointer.worldY);
7539
6733
  return { x: localPos.x, y: localPos.y };
7540
6734
  }
7541
6735
  /**
@@ -7605,6 +6799,7 @@ class GestureManager {
7605
6799
  const scaleY = canvas.height / rect.height;
7606
6800
  pointer.x = (event.clientX - rect.left) * scaleX;
7607
6801
  pointer.y = (event.clientY - rect.top) * scaleY;
6802
+ pointer.updateWorldPoint(pointer.camera ?? this.scene.cameras.main);
7608
6803
  const containersUnderPointer = [];
7609
6804
  Array.from(this.containers.values()).forEach((state, originalIndex) => {
7610
6805
  if (!state.callbacks.onWheel) return;
@@ -7705,83 +6900,6 @@ function getGestureManager(scene) {
7705
6900
  }
7706
6901
  return manager;
7707
6902
  }
7708
- function applyGesturesProps(scene, container, prev, next) {
7709
- if (!scene || !scene.sys || !scene.data) {
7710
- console.warn("applyGesturesProps: Invalid scene or scene not initialized");
7711
- return;
7712
- }
7713
- if (!scene.sys.isActive() || scene.sys.game === null) {
7714
- console.warn("applyGesturesProps: Scene is not active or game is null");
7715
- return;
7716
- }
7717
- const hasAnyGesture = !!(next.onTouch || next.onTouchOutside || next.onTouchMove || next.onDoubleTap || next.onLongPress || next.onHoverStart || next.onHoverEnd || next.onWheel);
7718
- const hadAnyGesture = !!(prev.onTouch || prev.onTouchOutside || prev.onTouchMove || prev.onDoubleTap || prev.onLongPress || prev.onHoverStart || prev.onHoverEnd || prev.onWheel);
7719
- const prevEnabled = hadAnyGesture && prev.enableGestures !== false;
7720
- const nextEnabled = hasAnyGesture && next.enableGestures !== false;
7721
- const manager = getGestureManager(scene);
7722
- if (!prevEnabled && nextEnabled && hasAnyGesture) {
7723
- const containerWithLayout = container;
7724
- let width = 100;
7725
- let height = 100;
7726
- if (containerWithLayout.__getLayoutSize) {
7727
- const size = containerWithLayout.__getLayoutSize();
7728
- width = size.width;
7729
- height = size.height;
7730
- } else {
7731
- const bounds = container.getBounds();
7732
- width = bounds.width || 100;
7733
- height = bounds.height || 100;
7734
- }
7735
- const hitArea = new Phaser$1.Geom.Rectangle(0, 0, width, height);
7736
- const callbacks = {};
7737
- if (next.onTouch) callbacks.onTouch = next.onTouch;
7738
- if (next.onTouchOutside) callbacks.onTouchOutside = next.onTouchOutside;
7739
- if (next.onTouchMove) callbacks.onTouchMove = next.onTouchMove;
7740
- if (next.onDoubleTap) callbacks.onDoubleTap = next.onDoubleTap;
7741
- if (next.onLongPress) callbacks.onLongPress = next.onLongPress;
7742
- if (next.onHoverStart) callbacks.onHoverStart = next.onHoverStart;
7743
- if (next.onHoverEnd) callbacks.onHoverEnd = next.onHoverEnd;
7744
- if (next.onWheel) callbacks.onWheel = next.onWheel;
7745
- const config = {};
7746
- if (next.longPressDuration !== void 0) config.longPressDuration = next.longPressDuration;
7747
- if (next.doubleTapDelay !== void 0) config.doubleTapDelay = next.doubleTapDelay;
7748
- manager.registerContainer(container, callbacks, hitArea, config);
7749
- return;
7750
- }
7751
- if (prevEnabled && (!nextEnabled || !hasAnyGesture)) {
7752
- manager.unregisterContainer(container);
7753
- return;
7754
- }
7755
- if (nextEnabled && hasAnyGesture) {
7756
- const callbacksChanged = prev.onTouch !== next.onTouch || prev.onTouchOutside !== next.onTouchOutside || prev.onTouchMove !== next.onTouchMove || prev.onDoubleTap !== next.onDoubleTap || prev.onLongPress !== next.onLongPress || prev.onHoverStart !== next.onHoverStart || prev.onHoverEnd !== next.onHoverEnd || prev.onWheel !== next.onWheel;
7757
- if (callbacksChanged) {
7758
- const callbacks = {};
7759
- if (next.onTouch) callbacks.onTouch = next.onTouch;
7760
- if (next.onTouchOutside) callbacks.onTouchOutside = next.onTouchOutside;
7761
- if (next.onTouchMove) callbacks.onTouchMove = next.onTouchMove;
7762
- if (next.onDoubleTap) callbacks.onDoubleTap = next.onDoubleTap;
7763
- if (next.onLongPress) callbacks.onLongPress = next.onLongPress;
7764
- if (next.onHoverStart) callbacks.onHoverStart = next.onHoverStart;
7765
- if (next.onHoverEnd) callbacks.onHoverEnd = next.onHoverEnd;
7766
- if (next.onWheel) callbacks.onWheel = next.onWheel;
7767
- manager.updateCallbacks(container, callbacks);
7768
- }
7769
- const containerWithLayout = container;
7770
- let width = 100;
7771
- let height = 100;
7772
- if (containerWithLayout.__getLayoutSize) {
7773
- const size = containerWithLayout.__getLayoutSize();
7774
- width = size.width;
7775
- height = size.height;
7776
- } else {
7777
- const bounds = container.getBounds();
7778
- width = bounds.width || 100;
7779
- height = bounds.height || 100;
7780
- }
7781
- const hitArea = new Phaser$1.Geom.Rectangle(0, 0, width, height);
7782
- manager.updateHitArea(container, hitArea);
7783
- }
7784
- }
7785
6903
  function normalizeEdgeInsets(value) {
7786
6904
  if (value === void 0) {
7787
6905
  return {};
@@ -8857,10 +7975,57 @@ const strategies = {
8857
7975
  row: new RowLayoutStrategy(),
8858
7976
  stack: new StackLayoutStrategy()
8859
7977
  };
7978
+ const LAYOUT_CYCLE_EPSILON = 0.5;
7979
+ const LAYOUT_CYCLE_TIME_MS = 100;
7980
+ const LAYOUT_CYCLE_MAX = 5;
7981
+ const LAYOUT_MAX_SIZE = 2e5;
7982
+ const layoutCycleGuard = /* @__PURE__ */ new WeakMap();
7983
+ function isCloseSize(a, b, epsilon) {
7984
+ return Math.abs(a.width - b.width) < epsilon && Math.abs(a.height - b.height) < epsilon;
7985
+ }
8860
7986
  function invalidateParentLayoutIfNeeded(container, oldSize, newWidth, newHeight) {
8861
- if (!oldSize || oldSize.width === newWidth && oldSize.height === newHeight) {
7987
+ if (!oldSize || Math.abs(oldSize.width - newWidth) < LAYOUT_CYCLE_EPSILON && Math.abs(oldSize.height - newHeight) < LAYOUT_CYCLE_EPSILON) {
7988
+ return;
7989
+ }
7990
+ if (!Number.isFinite(newWidth) || !Number.isFinite(newHeight) || newWidth > LAYOUT_MAX_SIZE || newHeight > LAYOUT_MAX_SIZE) {
7991
+ const containerWithProps = container;
7992
+ DebugLogger.warn("layout", "Runaway layout size detected, skipping parent invalidation", {
7993
+ oldSize,
7994
+ newSize: { width: newWidth, height: newHeight },
7995
+ containerProps: containerWithProps.__layoutProps,
7996
+ childCount: containerWithProps.list?.length ?? 0
7997
+ });
8862
7998
  return;
8863
7999
  }
8000
+ const newSize = { width: newWidth, height: newHeight };
8001
+ const now = Date.now();
8002
+ const guard = layoutCycleGuard.get(container);
8003
+ if (guard) {
8004
+ const repeatsPrev = guard.prev ? isCloseSize(guard.prev, newSize, LAYOUT_CYCLE_EPSILON) : false;
8005
+ if (repeatsPrev && now - guard.lastTime < LAYOUT_CYCLE_TIME_MS) {
8006
+ guard.count += 1;
8007
+ } else {
8008
+ guard.count = 0;
8009
+ }
8010
+ guard.prev = guard.last;
8011
+ guard.last = newSize;
8012
+ guard.lastTime = now;
8013
+ layoutCycleGuard.set(container, guard);
8014
+ if (guard.count >= LAYOUT_CYCLE_MAX) {
8015
+ DebugLogger.warn("layout", "Layout cycle detected, skipping parent invalidation", {
8016
+ container,
8017
+ oldSize,
8018
+ newSize
8019
+ });
8020
+ return;
8021
+ }
8022
+ } else {
8023
+ layoutCycleGuard.set(container, {
8024
+ last: newSize,
8025
+ count: 0,
8026
+ lastTime: now
8027
+ });
8028
+ }
8864
8029
  const parent = container.parentContainer;
8865
8030
  if (!parent || !parent.__layoutProps) {
8866
8031
  return;
@@ -9245,87 +8410,6 @@ function calculateLayoutImmediate(container, containerProps, parentSize, parentP
9245
8410
  function calculateLayout(container, containerProps, parentSize, parentPadding) {
9246
8411
  LayoutBatchQueue.schedule(container, containerProps, parentSize, parentPadding);
9247
8412
  }
9248
- function updateGestureHitAreaIfNeeded(node) {
9249
- const containerWithLayout = node;
9250
- if (!containerWithLayout.__getLayoutSize) return;
9251
- try {
9252
- const manager = getGestureManager(containerWithLayout.scene);
9253
- const size = containerWithLayout.__getLayoutSize();
9254
- const hitArea = new Phaser.Geom.Rectangle(0, 0, size.width, size.height);
9255
- manager.updateHitArea(node, hitArea);
9256
- } catch {
9257
- }
9258
- }
9259
- const LAYOUT_RELEVANT_PROPS = [
9260
- "width",
9261
- "height",
9262
- "minWidth",
9263
- "maxWidth",
9264
- "minHeight",
9265
- "maxHeight",
9266
- "flex",
9267
- "margin",
9268
- "padding",
9269
- "gap",
9270
- "direction",
9271
- "justifyContent",
9272
- "alignItems",
9273
- "overflow"
9274
- ];
9275
- const DEEP_COMPARE_PROPS$1 = /* @__PURE__ */ new Set(["margin", "padding"]);
9276
- function hasLayoutPropsChanged$1(prev, next) {
9277
- for (const prop of LAYOUT_RELEVANT_PROPS) {
9278
- const oldVal = prev[prop];
9279
- const newVal = next[prop];
9280
- if (DEEP_COMPARE_PROPS$1.has(prop)) {
9281
- if (!equal(oldVal, newVal)) {
9282
- return true;
9283
- }
9284
- } else {
9285
- if (oldVal !== newVal) {
9286
- return true;
9287
- }
9288
- }
9289
- }
9290
- return false;
9291
- }
9292
- function getParentLayoutContext(node) {
9293
- const parent = node.parentContainer;
9294
- if (parent && parent.__layoutProps && parent.__getLayoutSize) {
9295
- const parentSize = parent.__getLayoutSize();
9296
- const padding = parent.__layoutProps.padding ?? 0;
9297
- const normPadding = typeof padding === "number" ? { left: padding, right: padding, top: padding, bottom: padding } : {
9298
- left: padding.left ?? 0,
9299
- right: padding.right ?? 0,
9300
- top: padding.top ?? 0,
9301
- bottom: padding.bottom ?? 0
9302
- };
9303
- return {
9304
- parentSize: {
9305
- width: parentSize.width - normPadding.left - normPadding.right,
9306
- height: parentSize.height - normPadding.top - normPadding.bottom
9307
- }
9308
- // Parent already provides content-area, no padding offset needed
9309
- };
9310
- }
9311
- if (node.scene) {
9312
- return {
9313
- parentSize: {
9314
- width: node.scene.scale.width,
9315
- height: node.scene.scale.height
9316
- }
9317
- };
9318
- }
9319
- return {};
9320
- }
9321
- function applyLayoutProps(node, prev, next) {
9322
- node.__layoutProps = next;
9323
- if (hasLayoutPropsChanged$1(prev, next)) {
9324
- const { parentSize, parentPadding } = getParentLayoutContext(node);
9325
- calculateLayout(node, next, parentSize, parentPadding);
9326
- updateGestureHitAreaIfNeeded(node);
9327
- }
9328
- }
9329
8413
  class HexColor extends String {
9330
8414
  /**
9331
8415
  * Convert to Phaser number format
@@ -9819,6 +8903,10 @@ function buildDefaultTheme(colors) {
9819
8903
  alpha: 1,
9820
8904
  visible: true
9821
8905
  },
8906
+ particles: {
8907
+ alpha: 1,
8908
+ visible: true
8909
+ },
9822
8910
  // Public API (uppercase)
9823
8911
  View: {
9824
8912
  alpha: 1,
@@ -9850,6 +8938,10 @@ function buildDefaultTheme(colors) {
9850
8938
  alpha: 1,
9851
8939
  visible: true
9852
8940
  },
8941
+ Particles: {
8942
+ alpha: 1,
8943
+ visible: true
8944
+ },
9853
8945
  RadioButton: {
9854
8946
  selectedColor: colors.primary.DEFAULT.toNumber(),
9855
8947
  color: colors.border.medium.toNumber(),
@@ -10034,6 +9126,41 @@ function buildDefaultTheme(colors) {
10034
9126
  fontSize: "18px"
10035
9127
  }
10036
9128
  },
9129
+ Tabs: {
9130
+ tabListStyle: {
9131
+ backgroundColor: colors.surface.dark.toNumber(),
9132
+ padding: { left: 8, right: 8, top: 8, bottom: 0 },
9133
+ cornerRadius: { tl: 6, tr: 6, bl: 0, br: 0 },
9134
+ width: "fill",
9135
+ gap: 10,
9136
+ alignItems: "end",
9137
+ justifyContent: "start"
9138
+ },
9139
+ tabStyle: {
9140
+ backgroundColor: colors.surface.medium.toNumber(),
9141
+ borderColor: colors.border.medium.toNumber(),
9142
+ borderWidth: 1,
9143
+ padding: { left: 8, right: 8, top: 8, bottom: 3 },
9144
+ cornerRadius: { tl: 6, tr: 6, bl: 0, br: 0 }
9145
+ },
9146
+ tabActiveStyle: {
9147
+ padding: { left: 8, right: 8, top: 8, bottom: 8 },
9148
+ backgroundColor: colors.primary.DEFAULT.toNumber(),
9149
+ borderColor: colors.primary.dark.toNumber(),
9150
+ borderWidth: 2
9151
+ },
9152
+ tabDisabledStyle: {
9153
+ alpha: 0.4
9154
+ },
9155
+ panelStyle: {
9156
+ backgroundColor: colors.surface.light.toNumber(),
9157
+ borderColor: colors.border.medium.toNumber(),
9158
+ borderWidth: 1,
9159
+ padding: 10,
9160
+ cornerRadius: { tl: 0, tr: 0, bl: 6, br: 6 },
9161
+ width: "fill"
9162
+ }
9163
+ },
10037
9164
  NineSliceButton: {},
10038
9165
  CharText: {
10039
9166
  charSpacing: 0,
@@ -10488,442 +9615,6 @@ function getThemedProps(componentName, localTheme, explicitProps) {
10488
9615
  nestedTheme: mergedNestedThemes
10489
9616
  };
10490
9617
  }
10491
- const tooltipStates = /* @__PURE__ */ new Map();
10492
- function calculateTooltipPosition(targetBounds, position, offset, tooltipWidth, tooltipHeight) {
10493
- const viewport = {
10494
- width: window.innerWidth,
10495
- height: window.innerHeight
10496
- };
10497
- let x = 0;
10498
- let y = 0;
10499
- switch (position) {
10500
- case "top":
10501
- x = targetBounds.centerX - tooltipWidth / 2;
10502
- y = targetBounds.top - tooltipHeight - offset;
10503
- break;
10504
- case "bottom":
10505
- x = targetBounds.centerX - tooltipWidth / 2;
10506
- y = targetBounds.bottom + offset;
10507
- break;
10508
- case "left":
10509
- x = targetBounds.left - tooltipWidth - offset;
10510
- y = targetBounds.centerY - tooltipHeight / 2;
10511
- break;
10512
- case "right":
10513
- x = targetBounds.right + offset;
10514
- y = targetBounds.centerY - tooltipHeight / 2;
10515
- break;
10516
- }
10517
- x = Math.max(8, Math.min(x, viewport.width - tooltipWidth - 8));
10518
- y = Math.max(8, Math.min(y, viewport.height - tooltipHeight - 8));
10519
- return { x, y };
10520
- }
10521
- function showTooltip(scene, container, config) {
10522
- const state = tooltipStates.get(container);
10523
- if (!state || state.isVisible) return;
10524
- state.isVisible = true;
10525
- state.currentConfig = config;
10526
- const theme = themeRegistry.getGlobalTheme();
10527
- const tooltipTheme = theme.Tooltip || {};
10528
- const position = config.position ?? tooltipTheme.position ?? "top";
10529
- const offset = config.offset ?? tooltipTheme.offset ?? 8;
10530
- const content = config.content;
10531
- const targetBounds = container.getBounds();
10532
- const textStyle = tooltipTheme.textStyle ?? {
10533
- fontSize: "14px",
10534
- fontFamily: "Arial",
10535
- color: "#ffffff",
10536
- padding: { x: 8, y: 4 }
10537
- };
10538
- const { backgroundColor: bgColor, ...styleWithoutBg } = textStyle;
10539
- const text = scene.add.text(0, 0, content, styleWithoutBg);
10540
- text.setOrigin(0.5);
10541
- const padding = textStyle.padding ?? { x: 8, y: 4 };
10542
- const paddingX = typeof padding === "number" ? padding : padding.x ?? 8;
10543
- const paddingY = typeof padding === "number" ? padding : padding.y ?? 4;
10544
- const textWidth = text.width;
10545
- const textHeight = text.height;
10546
- const bgWidth = textWidth + paddingX * 2;
10547
- const bgHeight = textHeight + paddingY * 2;
10548
- const cornerRadius = tooltipTheme.cornerRadius ?? 6;
10549
- const graphics = scene.add.graphics();
10550
- const bg = bgColor ?? "#000000dd";
10551
- let fillColor = 0;
10552
- let fillAlpha = 0.87;
10553
- if (typeof bg === "string") {
10554
- if (bg.startsWith("#")) {
10555
- const hex2 = bg.slice(1);
10556
- if (hex2.length === 8) {
10557
- fillColor = parseInt(hex2.slice(0, 6), 16);
10558
- fillAlpha = parseInt(hex2.slice(6, 8), 16) / 255;
10559
- } else if (hex2.length === 6) {
10560
- fillColor = parseInt(hex2, 16);
10561
- fillAlpha = 1;
10562
- }
10563
- }
10564
- }
10565
- graphics.fillStyle(fillColor, fillAlpha);
10566
- graphics.fillRoundedRect(-bgWidth / 2, -bgHeight / 2, bgWidth, bgHeight, cornerRadius);
10567
- const tooltipContainer = scene.add.container(0, 0, [graphics, text]);
10568
- tooltipContainer.setDepth(1e4);
10569
- const textBounds = tooltipContainer.getBounds();
10570
- const pos = calculateTooltipPosition(
10571
- targetBounds,
10572
- position,
10573
- offset,
10574
- textBounds.width,
10575
- textBounds.height
10576
- );
10577
- const themeAnim = tooltipTheme.animation || {};
10578
- const anim = config.animation || {};
10579
- const fadeInDuration = anim.fadeIn ?? themeAnim.fadeIn ?? 200;
10580
- const moveOffset = {
10581
- dx: anim.move?.dx ?? themeAnim.move?.dx ?? 0,
10582
- dy: anim.move?.dy ?? themeAnim.move?.dy ?? 0
10583
- };
10584
- const pulse = anim.pulse ?? themeAnim.pulse ?? false;
10585
- const pulseScale = anim.pulseScale ?? [0.75, 1.25];
10586
- tooltipContainer.setPosition(
10587
- pos.x + textBounds.width / 2 - moveOffset.dx,
10588
- pos.y + textBounds.height / 2 - moveOffset.dy
10589
- );
10590
- tooltipContainer.setAlpha(0);
10591
- state.tooltip = tooltipContainer;
10592
- const fadeTween = scene.tweens.add({
10593
- targets: tooltipContainer,
10594
- alpha: 1,
10595
- x: pos.x + textBounds.width / 2,
10596
- y: pos.y + textBounds.height / 2,
10597
- duration: fadeInDuration,
10598
- ease: "Cubic.Out"
10599
- });
10600
- state.activeTweens.push(fadeTween);
10601
- if (pulse) {
10602
- const pulseTween = scene.tweens.add({
10603
- targets: tooltipContainer,
10604
- scale: { from: pulseScale[0], to: pulseScale[1] },
10605
- duration: 600,
10606
- yoyo: true,
10607
- repeat: -1,
10608
- ease: "Sine.InOut"
10609
- });
10610
- state.activeTweens.push(pulseTween);
10611
- }
10612
- if (config.autoDismiss && config.autoDismiss > 0) {
10613
- state.autoDismissTimer = setTimeout(() => {
10614
- hideTooltip(container);
10615
- }, config.autoDismiss);
10616
- }
10617
- }
10618
- function hideTooltip(container) {
10619
- const state = tooltipStates.get(container);
10620
- if (!state || !state.isVisible) return;
10621
- state.isVisible = false;
10622
- const config = state.currentConfig;
10623
- state.currentConfig = null;
10624
- if (state.autoDismissTimer) {
10625
- clearTimeout(state.autoDismissTimer);
10626
- state.autoDismissTimer = null;
10627
- }
10628
- if (!state.tooltip) return;
10629
- const tooltip = state.tooltip;
10630
- const scene = tooltip.scene;
10631
- const theme = themeRegistry.getGlobalTheme();
10632
- const tooltipTheme = theme.Tooltip || {};
10633
- const themeAnim = tooltipTheme.animation || {};
10634
- const anim = config?.animation || {};
10635
- const fadeOutDuration = anim.fadeOut ?? themeAnim.fadeOut ?? 200;
10636
- state.activeTweens.forEach((tween) => tween.stop());
10637
- state.activeTweens = [];
10638
- scene.tweens.add({
10639
- targets: tooltip,
10640
- alpha: 0,
10641
- duration: fadeOutDuration,
10642
- ease: "Cubic.In",
10643
- onComplete: () => {
10644
- tooltip.destroy();
10645
- }
10646
- });
10647
- state.tooltip = null;
10648
- }
10649
- function applyTooltip(scene, container, nextCallback, existingOnHoverStart, existingOnHoverEnd) {
10650
- if (!tooltipStates.has(container)) {
10651
- tooltipStates.set(container, {
10652
- isVisible: false,
10653
- tooltip: null,
10654
- activeTweens: [],
10655
- showTimer: null,
10656
- hideTimer: null,
10657
- autoDismissTimer: null,
10658
- currentConfig: null
10659
- });
10660
- container.once("destroy", () => {
10661
- const state2 = tooltipStates.get(container);
10662
- if (state2) {
10663
- if (state2.showTimer) clearTimeout(state2.showTimer);
10664
- if (state2.hideTimer) clearTimeout(state2.hideTimer);
10665
- if (state2.autoDismissTimer) clearTimeout(state2.autoDismissTimer);
10666
- state2.activeTweens.forEach((tween) => tween.stop());
10667
- hideTooltip(container);
10668
- tooltipStates.delete(container);
10669
- }
10670
- });
10671
- }
10672
- const state = tooltipStates.get(container);
10673
- if (!state) {
10674
- throw new Error("applyTooltip: state not initialized");
10675
- }
10676
- const theme = themeRegistry.getGlobalTheme();
10677
- const tooltipTheme = theme.Tooltip || {};
10678
- const onHoverStart = (data) => {
10679
- if (existingOnHoverStart) existingOnHoverStart(data);
10680
- if (!nextCallback) return;
10681
- const result = nextCallback();
10682
- if (!result) return;
10683
- const config = typeof result === "string" ? { content: result } : result;
10684
- if (config.disabled) return;
10685
- if (state.hideTimer) {
10686
- clearTimeout(state.hideTimer);
10687
- state.hideTimer = null;
10688
- }
10689
- if (state.autoDismissTimer) {
10690
- clearTimeout(state.autoDismissTimer);
10691
- state.autoDismissTimer = null;
10692
- }
10693
- const showDelay = config.showDelay ?? tooltipTheme.showDelay ?? 500;
10694
- state.showTimer = setTimeout(() => {
10695
- showTooltip(scene, container, config);
10696
- }, showDelay);
10697
- };
10698
- const onHoverEnd = (data) => {
10699
- if (existingOnHoverEnd) existingOnHoverEnd(data);
10700
- if (state.showTimer) {
10701
- clearTimeout(state.showTimer);
10702
- state.showTimer = null;
10703
- }
10704
- const hideDelay = state.currentConfig?.hideDelay ?? tooltipTheme.hideDelay ?? 0;
10705
- if (hideDelay > 0) {
10706
- state.hideTimer = setTimeout(() => {
10707
- hideTooltip(container);
10708
- }, hideDelay);
10709
- } else {
10710
- hideTooltip(container);
10711
- }
10712
- };
10713
- return { onHoverStart, onHoverEnd };
10714
- }
10715
- function createBackground(scene, container, props) {
10716
- const hasBackground = props.backgroundColor !== void 0;
10717
- const hasBorder = props.borderColor !== void 0;
10718
- if (hasBackground || hasBorder) {
10719
- const width = typeof props.width === "number" ? props.width : 100;
10720
- const height = typeof props.height === "number" ? props.height : 100;
10721
- const bgColor = props.backgroundColor;
10722
- const bgAlpha = props.backgroundAlpha ?? 1;
10723
- const cornerRadius = props.cornerRadius ?? 0;
10724
- const borderColor = props.borderColor;
10725
- const borderWidth = props.borderWidth ?? 0;
10726
- const borderAlpha = props.borderAlpha ?? 1;
10727
- const background = scene.add.graphics();
10728
- if (bgColor !== void 0) {
10729
- background.fillStyle(bgColor, bgAlpha);
10730
- }
10731
- if (borderWidth > 0 && borderColor !== void 0) {
10732
- background.lineStyle(borderWidth, borderColor, borderAlpha);
10733
- }
10734
- if (cornerRadius !== 0) {
10735
- if (bgColor !== void 0) {
10736
- background.fillRoundedRect(0, 0, width, height, cornerRadius);
10737
- }
10738
- if (borderWidth > 0 && borderColor !== void 0) {
10739
- background.strokeRoundedRect(0, 0, width, height, cornerRadius);
10740
- }
10741
- } else {
10742
- if (bgColor !== void 0) {
10743
- background.fillRect(0, 0, width, height);
10744
- }
10745
- if (borderWidth > 0 && borderColor !== void 0) {
10746
- background.strokeRect(0, 0, width, height);
10747
- }
10748
- }
10749
- container.addAt(background, 0);
10750
- container.__background = background;
10751
- background.__isBackground = true;
10752
- }
10753
- }
10754
- function createGestures(scene, container, props) {
10755
- const hasAnyGesture = !!(props.onTouch || props.onTouchOutside || props.onTouchMove || props.onDoubleTap || props.onLongPress || props.onHoverStart || props.onHoverEnd || props.onWheel);
10756
- const shouldEnable = hasAnyGesture && props.enableGestures !== false;
10757
- if (!shouldEnable) {
10758
- return;
10759
- }
10760
- const manager = getGestureManager(scene);
10761
- const containerWithLayout = container;
10762
- let width = 100;
10763
- let height = 100;
10764
- if (containerWithLayout.__getLayoutSize) {
10765
- const size = containerWithLayout.__getLayoutSize();
10766
- width = size.width;
10767
- height = size.height;
10768
- } else {
10769
- const bounds = container.getBounds();
10770
- width = bounds.width || 100;
10771
- height = bounds.height || 100;
10772
- }
10773
- const hitArea = new Phaser$1.Geom.Rectangle(0, 0, width, height);
10774
- const callbacks = {};
10775
- if (props.onTouch) callbacks.onTouch = props.onTouch;
10776
- if (props.onTouchOutside) callbacks.onTouchOutside = props.onTouchOutside;
10777
- if (props.onTouchMove) callbacks.onTouchMove = props.onTouchMove;
10778
- if (props.onDoubleTap) callbacks.onDoubleTap = props.onDoubleTap;
10779
- if (props.onLongPress) callbacks.onLongPress = props.onLongPress;
10780
- if (props.onHoverStart) callbacks.onHoverStart = props.onHoverStart;
10781
- if (props.onHoverEnd) callbacks.onHoverEnd = props.onHoverEnd;
10782
- if (props.onWheel) callbacks.onWheel = props.onWheel;
10783
- const config = {};
10784
- if (props.longPressDuration !== void 0) config.longPressDuration = props.longPressDuration;
10785
- if (props.doubleTapDelay !== void 0) config.doubleTapDelay = props.doubleTapDelay;
10786
- if (props.maxTouchDuration !== void 0) config.maxTouchDuration = props.maxTouchDuration;
10787
- manager.registerContainer(container, callbacks, hitArea, config);
10788
- }
10789
- function createLayout(container, props) {
10790
- container.__layoutProps = props;
10791
- container.__getLayoutSize = () => {
10792
- const children = container.list;
10793
- const direction = props.direction ?? "column";
10794
- const paddingRaw = props.padding ?? {};
10795
- const padding = typeof paddingRaw === "number" ? { left: paddingRaw, top: paddingRaw, right: paddingRaw, bottom: paddingRaw } : paddingRaw;
10796
- const paddingLeft = padding.left ?? 0;
10797
- const paddingTop = padding.top ?? 0;
10798
- const paddingRight = padding.right ?? 0;
10799
- const paddingBottom = padding.bottom ?? 0;
10800
- const gapNormalized = normalizeGap(props.gap);
10801
- let maxWidth = 0;
10802
- let maxHeight = 0;
10803
- let totalMainSize = 0;
10804
- let childCount = 0;
10805
- for (const child of children) {
10806
- if (child.__isBackground) {
10807
- continue;
10808
- }
10809
- childCount++;
10810
- const marginRaw = child.__layoutProps?.margin ?? {};
10811
- const margin = typeof marginRaw === "number" ? { top: marginRaw, right: marginRaw, bottom: marginRaw, left: marginRaw } : marginRaw;
10812
- const marginTop = margin.top ?? 0;
10813
- const marginBottom = margin.bottom ?? 0;
10814
- const marginLeft = margin.left ?? 0;
10815
- const marginRight = margin.right ?? 0;
10816
- const childSize = getChildSize(child);
10817
- if (direction === "row") {
10818
- totalMainSize += marginLeft + childSize.width + marginRight;
10819
- const childTotalHeight = marginTop + childSize.height + marginBottom;
10820
- maxHeight = Math.max(maxHeight, childTotalHeight);
10821
- } else {
10822
- const childTotalWidth = marginLeft + childSize.width + marginRight;
10823
- maxWidth = Math.max(maxWidth, childTotalWidth);
10824
- totalMainSize += marginTop + childSize.height + marginBottom;
10825
- }
10826
- }
10827
- if (childCount > 1) {
10828
- const gapValue = direction === "row" ? gapNormalized.horizontal : gapNormalized.vertical;
10829
- totalMainSize += gapValue * (childCount - 1);
10830
- }
10831
- const defaultWidth = direction === "row" ? totalMainSize + paddingLeft + paddingRight : maxWidth + paddingLeft + paddingRight;
10832
- const defaultHeight = direction === "row" ? maxHeight + paddingTop + paddingBottom : totalMainSize + paddingTop + paddingBottom;
10833
- const parsedWidth = parseSize(props.width);
10834
- const finalWidth = resolveSize(parsedWidth, void 0, defaultWidth);
10835
- const parsedHeight = parseSize(props.height);
10836
- const finalHeight = resolveSize(parsedHeight, void 0, defaultHeight);
10837
- return {
10838
- width: finalWidth,
10839
- height: finalHeight
10840
- };
10841
- };
10842
- }
10843
- function normalizeBackgroundProps(props) {
10844
- const bgProps = props;
10845
- const hasBackground = bgProps.backgroundColor !== void 0;
10846
- const hasBorder = bgProps.borderColor !== void 0;
10847
- if (!hasBackground && !hasBorder) {
10848
- return props;
10849
- }
10850
- const normalized = { ...props };
10851
- if (hasBackground && (bgProps.backgroundAlpha === void 0 || bgProps.backgroundAlpha === 0)) {
10852
- normalized.backgroundAlpha = 1;
10853
- }
10854
- if (hasBorder) {
10855
- if (bgProps.borderWidth === void 0 || bgProps.borderWidth === 0) {
10856
- normalized.borderWidth = 1;
10857
- }
10858
- if (bgProps.borderAlpha === void 0 || bgProps.borderAlpha === 0) {
10859
- normalized.borderAlpha = 1;
10860
- }
10861
- }
10862
- return normalized;
10863
- }
10864
- const viewCreator = (scene, props) => {
10865
- if (props.backgroundColor !== void 0 || props.cornerRadius !== void 0) {
10866
- DebugLogger.log("theme", "View Creator - Props received:", {
10867
- backgroundColor: props.backgroundColor,
10868
- cornerRadius: props.cornerRadius,
10869
- width: props.width,
10870
- height: props.height
10871
- });
10872
- }
10873
- const normalizedProps = normalizeBackgroundProps(props);
10874
- const container = scene.add.container(normalizedProps.x ?? 0, normalizedProps.y ?? 0);
10875
- createTransform(container, normalizedProps);
10876
- createPhaser(container, normalizedProps);
10877
- createBackground(
10878
- scene,
10879
- container,
10880
- normalizedProps
10881
- );
10882
- createLayout(container, normalizedProps);
10883
- if (normalizedProps.onTooltip) {
10884
- const handlers = applyTooltip(
10885
- scene,
10886
- container,
10887
- normalizedProps.onTooltip,
10888
- normalizedProps.onHoverStart,
10889
- normalizedProps.onHoverEnd
10890
- );
10891
- normalizedProps.onHoverStart = handlers.onHoverStart;
10892
- normalizedProps.onHoverEnd = handlers.onHoverEnd;
10893
- }
10894
- createGestures(scene, container, normalizedProps);
10895
- DebugLogger.log(
10896
- "layout",
10897
- "View creator storing __layoutProps with padding:",
10898
- normalizedProps.padding
10899
- );
10900
- return container;
10901
- };
10902
- const viewPatcher = (node, prev, next) => {
10903
- const normalizedPrev = normalizeBackgroundProps(prev);
10904
- const normalizedNext = normalizeBackgroundProps(next);
10905
- applyTransformProps(node, normalizedPrev, normalizedNext);
10906
- applyPhaserProps(node, normalizedPrev, normalizedNext);
10907
- const container = node;
10908
- applyBackgroundProps(container, normalizedPrev, normalizedNext);
10909
- if (container.scene && container.scene.data) {
10910
- if (normalizedNext.onTooltip) {
10911
- const handlers = applyTooltip(
10912
- container.scene,
10913
- container,
10914
- normalizedNext.onTooltip,
10915
- normalizedNext.onHoverStart,
10916
- normalizedNext.onHoverEnd
10917
- );
10918
- normalizedNext.onHoverStart = handlers.onHoverStart;
10919
- normalizedNext.onHoverEnd = handlers.onHoverEnd;
10920
- }
10921
- }
10922
- if (container.scene && container.scene.data) {
10923
- applyGesturesProps(container.scene, container, normalizedPrev, normalizedNext);
10924
- }
10925
- applyLayoutProps(container, normalizedPrev, normalizedNext);
10926
- };
10927
9618
  class RenderContext {
10928
9619
  constructor(scene) {
10929
9620
  this.scene = scene;
@@ -11250,9 +9941,9 @@ class MountRegistry {
11250
9941
  * @param rootNode - Root game object
11251
9942
  * @returns Registry ID for this mount
11252
9943
  */
11253
- register(parent, type, props, rootNode) {
9944
+ register(parent, type, props, rootNode, vnode) {
11254
9945
  const id = this.nextId++;
11255
- this.entries.set(id, { id, parent, type, props, rootNode });
9946
+ this.entries.set(id, { id, parent, type, props, rootNode, vnode });
11256
9947
  DebugLogger.log("vdom", `Registered mount ${id}`);
11257
9948
  return id;
11258
9949
  }
@@ -11267,6 +9958,49 @@ class MountRegistry {
11267
9958
  this.entries.delete(id);
11268
9959
  }
11269
9960
  }
9961
+ /**
9962
+ * Get a specific mount entry by registry ID
9963
+ * @param id - Registry ID
9964
+ * @returns Mount entry or undefined if not found
9965
+ */
9966
+ getEntry(id) {
9967
+ return this.entries.get(id);
9968
+ }
9969
+ /**
9970
+ * Find a mount entry by parent and optional key
9971
+ * If key is provided, matches parent AND key
9972
+ * If key is omitted, returns first mount with matching parent (backward compatibility)
9973
+ * Validates that scene is still active and objects are not destroyed
9974
+ * @param parent - Parent container or scene
9975
+ * @param key - Optional unique key to distinguish multiple mounts on same parent
9976
+ * @returns Mount entry or undefined if not found or invalid
9977
+ */
9978
+ findByParentAndKey(parent, key) {
9979
+ for (const entry of this.entries.values()) {
9980
+ const scene = entry.parent instanceof Phaser$1.Scene ? entry.parent : entry.parent.scene;
9981
+ if (!scene || !scene.sys || !scene.sys.settings.active) {
9982
+ DebugLogger.log("vdom", `Removing mount ${entry.id} - scene inactive`);
9983
+ this.unregister(entry.id);
9984
+ continue;
9985
+ }
9986
+ if (!entry.rootNode.active || entry.rootNode.scene !== scene) {
9987
+ DebugLogger.log("vdom", `Removing mount ${entry.id} - rootNode destroyed or scene changed`);
9988
+ this.unregister(entry.id);
9989
+ continue;
9990
+ }
9991
+ const entryKey = entry.props.key;
9992
+ if (key !== void 0) {
9993
+ if (entry.parent === parent && entryKey === key) {
9994
+ return entry;
9995
+ }
9996
+ } else {
9997
+ if (entry.parent === parent) {
9998
+ return entry;
9999
+ }
10000
+ }
10001
+ }
10002
+ return void 0;
10003
+ }
11270
10004
  /**
11271
10005
  * Get all active mount entries
11272
10006
  * @returns Array of mount entries
@@ -11274,6 +10008,50 @@ class MountRegistry {
11274
10008
  getAllEntries() {
11275
10009
  return Array.from(this.entries.values());
11276
10010
  }
10011
+ /**
10012
+ * Get count of active mounts
10013
+ * @returns Number of registered mounts
10014
+ */
10015
+ getCount() {
10016
+ return this.entries.size;
10017
+ }
10018
+ /**
10019
+ * Get statistics about active mounts
10020
+ * @returns Object with mount statistics
10021
+ */
10022
+ getStats() {
10023
+ const byType = /* @__PURE__ */ new Map();
10024
+ const byParent = /* @__PURE__ */ new Map();
10025
+ const byKey = /* @__PURE__ */ new Map();
10026
+ const mounts = [];
10027
+ for (const entry of this.entries.values()) {
10028
+ const typeName = typeof entry.type === "string" ? entry.type : entry.type.name || "Component";
10029
+ byType.set(typeName, (byType.get(typeName) ?? 0) + 1);
10030
+ byParent.set(entry.parent, (byParent.get(entry.parent) ?? 0) + 1);
10031
+ const key = entry.props.key;
10032
+ if (key) {
10033
+ byKey.set(key, (byKey.get(key) ?? 0) + 1);
10034
+ }
10035
+ const parentType = entry.parent instanceof Phaser$1.Scene ? "Scene" : "Container";
10036
+ const mountInfo = {
10037
+ id: entry.id,
10038
+ type: typeName,
10039
+ parentType,
10040
+ propsKeys: Object.keys(entry.props)
10041
+ };
10042
+ if (key !== void 0) {
10043
+ mountInfo.key = key;
10044
+ }
10045
+ mounts.push(mountInfo);
10046
+ }
10047
+ return {
10048
+ totalMounts: this.entries.size,
10049
+ byType,
10050
+ byParent,
10051
+ byKey,
10052
+ mounts
10053
+ };
10054
+ }
11277
10055
  /**
11278
10056
  * Clear all entries (for testing)
11279
10057
  */
@@ -11283,6 +10061,9 @@ class MountRegistry {
11283
10061
  }
11284
10062
  }
11285
10063
  const mountRegistry = new MountRegistry();
10064
+ function getMountStats() {
10065
+ return mountRegistry.getStats();
10066
+ }
11286
10067
  function remountAll() {
11287
10068
  const entries = mountRegistry.getAllEntries();
11288
10069
  if (entries.length === 0) {
@@ -11344,7 +10125,9 @@ function remountAll() {
11344
10125
  rootNode.__mountRootId = generateMountRootId();
11345
10126
  }
11346
10127
  entry.rootNode = rootNode;
10128
+ entry.vnode = vnode;
11347
10129
  rootNode.__registryId = entry.id;
10130
+ rootNode.__rootVNode = vnode;
11348
10131
  console.log("[REMOUNT] Successfully remounted entry", entry.id);
11349
10132
  } catch (error) {
11350
10133
  console.error("[REMOUNT] Failed to remount entry", entry.id, error);
@@ -11352,6 +10135,14 @@ function remountAll() {
11352
10135
  });
11353
10136
  console.log("[REMOUNT] Remount complete");
11354
10137
  }
10138
+ function normalizeVNodeLike(rendered) {
10139
+ if (!rendered) return null;
10140
+ if (Array.isArray(rendered)) {
10141
+ const flat = rendered.flat(Infinity);
10142
+ return { type: jsxRuntime.Fragment, props: {}, children: flat };
10143
+ }
10144
+ return rendered;
10145
+ }
11355
10146
  function flattenChildren(children) {
11356
10147
  if (!children) return [];
11357
10148
  return children.flat(Infinity);
@@ -11605,10 +10396,11 @@ function mount(parentOrScene, vnode) {
11605
10396
  };
11606
10397
  vnode = setVNodePropSafe(vnode, "__ctx", ctx);
11607
10398
  const propsWithChildren = vnode.children?.length ? { ...vnode.props ?? {}, children: vnode.children } : vnode.props;
11608
- let rendered = withHooks(
10399
+ const renderedRaw = withHooks(
11609
10400
  ctx,
11610
10401
  () => vnode.type(propsWithChildren)
11611
10402
  );
10403
+ let rendered = normalizeVNodeLike(renderedRaw);
11612
10404
  if (!rendered) {
11613
10405
  ctx.vnode = rendered;
11614
10406
  for (const run of ctx.effects) run();
@@ -11767,6 +10559,30 @@ function patchVNode(parent, oldV, newV) {
11767
10559
  warnUnnecessaryRemount(oldV, newV);
11768
10560
  unmount(oldV);
11769
10561
  mount(parent, newV);
10562
+ if (parent && typeof parent === "object" && "list" in parent) {
10563
+ const parentContainer = parent;
10564
+ if (parentContainer.__layoutProps) {
10565
+ let grandparentSize;
10566
+ const grandparent = parentContainer.parentContainer;
10567
+ if (grandparent && grandparent.__layoutProps && grandparent.__getLayoutSize) {
10568
+ const gpSize = grandparent.__getLayoutSize();
10569
+ const gpPadding = grandparent.__layoutProps.padding ?? 0;
10570
+ const normGpPadding = typeof gpPadding === "number" ? { left: gpPadding, right: gpPadding, top: gpPadding, bottom: gpPadding } : {
10571
+ left: gpPadding.left ?? 0,
10572
+ right: gpPadding.right ?? 0,
10573
+ top: gpPadding.top ?? 0,
10574
+ bottom: gpPadding.bottom ?? 0
10575
+ };
10576
+ grandparentSize = {
10577
+ width: gpSize.width - normGpPadding.left - normGpPadding.right,
10578
+ height: gpSize.height - normGpPadding.top - normGpPadding.bottom
10579
+ };
10580
+ }
10581
+ calculateLayout(parentContainer, parentContainer.__layoutProps, grandparentSize);
10582
+ const renderContext = getRenderContext(parent);
10583
+ renderContext.deferLayout(() => updateGestureHitAreaAfterLayout(parentContainer));
10584
+ }
10585
+ }
11770
10586
  return;
11771
10587
  }
11772
10588
  if (oldV.type === jsxRuntime.Fragment && newV.type === jsxRuntime.Fragment) {
@@ -11812,10 +10628,12 @@ function patchVNode(parent, oldV, newV) {
11812
10628
  if (!ctx) {
11813
10629
  if (!newV || !oldV) return;
11814
10630
  const propsWithChildren2 = newV.children?.length ? { ...newV.props ?? {}, children: newV.children } : newV.props;
11815
- const oldRendered = oldV.type(
10631
+ const oldRenderedRaw = oldV.type(
11816
10632
  oldV.children?.length ? { ...oldV.props ?? {}, children: oldV.children } : oldV.props
11817
10633
  );
11818
- const newRendered = newV.type(propsWithChildren2);
10634
+ const newRenderedRaw = newV.type(propsWithChildren2);
10635
+ const oldRendered = normalizeVNodeLike(oldRenderedRaw);
10636
+ const newRendered = normalizeVNodeLike(newRenderedRaw);
11819
10637
  patchVNode(parent, oldRendered, newRendered);
11820
10638
  return;
11821
10639
  }
@@ -11833,10 +10651,11 @@ function patchVNode(parent, oldV, newV) {
11833
10651
  if (!shouldComponentUpdate(ctx, propsWithChildren)) {
11834
10652
  return;
11835
10653
  }
11836
- const renderedNext = withHooks(
10654
+ const renderedNextRaw = withHooks(
11837
10655
  ctx,
11838
10656
  () => newVWithCtx.type(propsWithChildren)
11839
10657
  );
10658
+ const renderedNext = normalizeVNodeLike(renderedNextRaw);
11840
10659
  if (!renderedNext) {
11841
10660
  ctx.vnode = renderedNext;
11842
10661
  for (const run of ctx.effects) run();
@@ -11867,6 +10686,7 @@ function patchVNode(parent, oldV, newV) {
11867
10686
  }
11868
10687
  const nodeType = oldV.type;
11869
10688
  newV = setVNodePropSafe(newV, "__node", oldV.__node);
10689
+ newV = setVNodePropSafe(newV, "__parent", parent);
11870
10690
  if (newV.__theme !== void 0) {
11871
10691
  const themed = setThemeSafe(oldV, newV.__theme);
11872
10692
  if (themed !== oldV) {
@@ -11911,6 +10731,11 @@ function patchVNode(parent, oldV, newV) {
11911
10731
  warnMissingKeys(newV, b);
11912
10732
  }
11913
10733
  const containerLayoutChanged = hasLayoutPropsChanged(oldV, newV);
10734
+ const oldValidChildCount = a.filter((c) => c != null && c !== false).length;
10735
+ const newValidChildCount = b.filter((c) => c != null && c !== false).length;
10736
+ if (oldValidChildCount !== newValidChildCount) {
10737
+ childrenChanged = true;
10738
+ }
11914
10739
  for (let i = 0; i < len; i++) {
11915
10740
  const c1 = a[i], c2 = b[i];
11916
10741
  const isValidC1 = c1 != null && c1 !== false;
@@ -11991,7 +10816,74 @@ function patchVNode(parent, oldV, newV) {
11991
10816
  }
11992
10817
  }
11993
10818
  function mountJSX(parentOrScene, type, props = { width: 0, height: 0 }) {
11994
- const { width, height, disableAutoSize = false, ...componentProps } = props;
10819
+ const key = props.key;
10820
+ const existingMount = mountRegistry.findByParentAndKey(parentOrScene, key);
10821
+ if (existingMount) {
10822
+ if (existingMount.type !== type) {
10823
+ const oldTypeName = typeof existingMount.type === "string" ? existingMount.type : existingMount.type.name || "Component";
10824
+ const newTypeName = typeof type === "string" ? type : type.name || "Component";
10825
+ console.warn(
10826
+ `[PhaserJSX] mountJSX type mismatch: Attempting to patch <${oldTypeName}> with <${newTypeName}>.
10827
+ This usually means you're missing a 'key' prop to distinguish multiple mounts on the same parent.
10828
+ Solution: Add unique keys like { key: 'sidebar', ... } and { key: 'main', ... }`
10829
+ );
10830
+ }
10831
+ const newWidth = props.width ?? existingMount.props.width;
10832
+ const newHeight = props.height ?? existingMount.props.height;
10833
+ const dimensionsChanged = newWidth !== existingMount.props.width || newHeight !== existingMount.props.height;
10834
+ const { disableAutoSize: _d, key: _k, ...componentProps2 } = props;
10835
+ if (dimensionsChanged) {
10836
+ existingMount.props = {
10837
+ ...existingMount.props,
10838
+ ...componentProps2,
10839
+ width: newWidth,
10840
+ height: newHeight
10841
+ };
10842
+ } else {
10843
+ existingMount.props = { ...existingMount.props, ...componentProps2 };
10844
+ }
10845
+ let newVNode;
10846
+ if (existingMount.props.disableAutoSize) {
10847
+ newVNode = {
10848
+ type: existingMount.type,
10849
+ props: {
10850
+ ...componentProps2,
10851
+ width: existingMount.props.width,
10852
+ height: existingMount.props.height
10853
+ },
10854
+ children: []
10855
+ };
10856
+ } else {
10857
+ const componentVNode = {
10858
+ type: existingMount.type,
10859
+ props: {
10860
+ ...componentProps2,
10861
+ width: existingMount.props.width,
10862
+ height: existingMount.props.height
10863
+ },
10864
+ children: []
10865
+ };
10866
+ newVNode = {
10867
+ type: SceneWrapper,
10868
+ props: {
10869
+ width: existingMount.props.width,
10870
+ height: existingMount.props.height,
10871
+ children: componentVNode
10872
+ },
10873
+ children: []
10874
+ };
10875
+ }
10876
+ patchVNode(parentOrScene, existingMount.vnode, newVNode);
10877
+ existingMount.vnode = newVNode;
10878
+ const handle2 = existingMount.rootNode;
10879
+ handle2.unmount = () => unmountJSX(handle2);
10880
+ DebugLogger.log(
10881
+ "vdom",
10882
+ `Patched existing mount ${existingMount.id} on same parent (type: ${typeof type === "string" ? type : type.name})`
10883
+ );
10884
+ return handle2;
10885
+ }
10886
+ const { width, height, disableAutoSize = false, key: _key, ...componentProps } = props;
11995
10887
  const scene = parentOrScene instanceof Phaser$1.Scene ? parentOrScene : parentOrScene.scene;
11996
10888
  if (scene) {
11997
10889
  const renderContext = getRenderContext(parentOrScene);
@@ -12004,7 +10896,11 @@ function mountJSX(parentOrScene, type, props = { width: 0, height: 0 }) {
12004
10896
  } else {
12005
10897
  const componentVNode = {
12006
10898
  type,
12007
- props: componentProps,
10899
+ props: {
10900
+ ...componentProps,
10901
+ width,
10902
+ height
10903
+ },
12008
10904
  children: []
12009
10905
  };
12010
10906
  vnode = {
@@ -12024,18 +10920,48 @@ function mountJSX(parentOrScene, type, props = { width: 0, height: 0 }) {
12024
10920
  if (rootNode instanceof Phaser$1.GameObjects.Container) {
12025
10921
  rootNode.__mountRootId = generateMountRootId();
12026
10922
  }
12027
- const registryId = mountRegistry.register(parentOrScene, type, props, rootNode);
10923
+ rootNode.__rootVNode = vnode;
10924
+ const registryId = mountRegistry.register(parentOrScene, type, props, rootNode, vnode);
12028
10925
  rootNode.__registryId = registryId;
12029
- return rootNode;
10926
+ const handle = rootNode;
10927
+ handle.unmount = () => unmountJSX(handle);
10928
+ return handle;
10929
+ }
10930
+ function unmountJSX(target) {
10931
+ const scene = target instanceof Phaser$1.Scene ? target : target.scene;
10932
+ const targetWithVNode = target;
10933
+ const sceneWithVNode = scene;
10934
+ const rootVNode = targetWithVNode.__rootVNode ?? sceneWithVNode?.__rootVNode;
10935
+ if (rootVNode) {
10936
+ unmount(rootVNode);
10937
+ if (targetWithVNode.__rootVNode === rootVNode) {
10938
+ delete targetWithVNode.__rootVNode;
10939
+ }
10940
+ if (sceneWithVNode?.__rootVNode === rootVNode) {
10941
+ delete sceneWithVNode.__rootVNode;
10942
+ }
10943
+ return;
10944
+ }
10945
+ if (targetWithVNode.__registryId !== void 0) {
10946
+ const entry = mountRegistry.getEntry(targetWithVNode.__registryId);
10947
+ if (entry?.vnode) {
10948
+ unmount(entry.vnode);
10949
+ return;
10950
+ }
10951
+ }
10952
+ DebugLogger.log("vdom", "unmountJSX called but no root VNode found on target");
12030
10953
  }
12031
10954
  const vdom = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
12032
10955
  __proto__: null,
12033
10956
  createElement,
10957
+ getMountStats,
12034
10958
  mount,
12035
10959
  mountJSX,
10960
+ normalizeVNodeLike,
12036
10961
  patchVNode,
12037
10962
  remountAll,
12038
- unmount
10963
+ unmount,
10964
+ unmountJSX
12039
10965
  }, Symbol.toStringTag, { value: "Module" }));
12040
10966
  function getCurrent() {
12041
10967
  return _currentCtx;
@@ -12126,6 +11052,68 @@ function useScene() {
12126
11052
  const renderContext = getContextFromParent(ctx.parent);
12127
11053
  return renderContext.scene;
12128
11054
  }
11055
+ function useViewportSize() {
11056
+ const ctx = getCurrent();
11057
+ if (!ctx) {
11058
+ throw new Error("useViewportSize must be called within a component");
11059
+ }
11060
+ const renderContext = getContextFromParent(ctx.parent);
11061
+ return renderContext.getViewport();
11062
+ }
11063
+ function getLayoutSize(container) {
11064
+ if (!container) return void 0;
11065
+ const withLayout = container;
11066
+ return withLayout.__getLayoutSize?.();
11067
+ }
11068
+ function useLayoutSize(ref) {
11069
+ return getLayoutSize(ref.current);
11070
+ }
11071
+ function getLayoutProps(container) {
11072
+ if (!container) return void 0;
11073
+ const withLayout = container;
11074
+ return withLayout.__layoutProps;
11075
+ }
11076
+ function getBackgroundGraphics(container) {
11077
+ if (!container) return void 0;
11078
+ const withBackground = container;
11079
+ return withBackground.__background;
11080
+ }
11081
+ function useBackgroundGraphics(ref) {
11082
+ return getBackgroundGraphics(ref.current);
11083
+ }
11084
+ function getLayoutRect(container) {
11085
+ if (!container) return void 0;
11086
+ const size = getLayoutSize(container);
11087
+ if (!size) return void 0;
11088
+ return {
11089
+ x: container.x,
11090
+ y: container.y,
11091
+ width: size.width,
11092
+ height: size.height
11093
+ };
11094
+ }
11095
+ function useLayoutRect(ref) {
11096
+ return getLayoutRect(ref.current);
11097
+ }
11098
+ function getWorldLayoutRect(container) {
11099
+ if (!container) return void 0;
11100
+ const size = getLayoutSize(container);
11101
+ if (!size) return void 0;
11102
+ const matrix = container.getWorldTransformMatrix();
11103
+ const worldX = matrix.tx;
11104
+ const worldY = matrix.ty;
11105
+ const worldWidth = size.width * Math.abs(matrix.scaleX);
11106
+ const worldHeight = size.height * Math.abs(matrix.scaleY);
11107
+ return {
11108
+ x: worldX,
11109
+ y: worldY,
11110
+ width: worldWidth,
11111
+ height: worldHeight
11112
+ };
11113
+ }
11114
+ function useWorldLayoutRect(ref) {
11115
+ return getWorldLayoutRect(ref.current);
11116
+ }
12129
11117
  function useEffect(fn, deps) {
12130
11118
  const c = getCurrent();
12131
11119
  const i = c.index++;
@@ -12139,6 +11127,21 @@ function useEffect(fn, deps) {
12139
11127
  }
12140
11128
  });
12141
11129
  }
11130
+ function useLayoutEffect(fn, deps) {
11131
+ const c = getCurrent();
11132
+ const i = c.index++;
11133
+ const slot = c.slots[i] ?? (c.slots[i] = { deps: void 0, cleanup: void 0 });
11134
+ c.effects.push(() => {
11135
+ if (!depsChanged(slot.deps, deps)) return;
11136
+ if (typeof slot.cleanup === "function") slot.cleanup();
11137
+ requestAnimationFrame(() => {
11138
+ slot.cleanup = fn();
11139
+ });
11140
+ if (deps !== void 0) {
11141
+ slot.deps = deps;
11142
+ }
11143
+ });
11144
+ }
12142
11145
  function depsChanged(a, b) {
12143
11146
  if (!a || !b) return true;
12144
11147
  if (a.length !== b.length) return true;
@@ -12191,7 +11194,7 @@ function scheduleUpdate(c) {
12191
11194
  }
12192
11195
  const componentProps = c.componentVNode.props ?? {};
12193
11196
  const propsWithChildren = c.componentVNode.children?.length ? { ...componentProps, children: c.componentVNode.children } : componentProps;
12194
- const nextVNode = withHooks(c, () => c.function(propsWithChildren));
11197
+ const nextVNode = normalizeVNodeLike(withHooks(c, () => c.function(propsWithChildren)));
12195
11198
  patchVNode(c.parent, c.vnode, nextVNode);
12196
11199
  c.vnode = nextVNode;
12197
11200
  for (const run of c.effects) run();
@@ -12975,6 +11978,11 @@ function Button(props) {
12975
11978
  }
12976
11979
  );
12977
11980
  }
11981
+ function Graphics(props) {
11982
+ const localTheme = useTheme();
11983
+ const { props: themed, nestedTheme } = getThemedProps("Graphics", localTheme, props);
11984
+ return /* @__PURE__ */ jsxRuntime.jsx("graphics", { ...themed, theme: nestedTheme });
11985
+ }
12978
11986
  function RadioButton(props) {
12979
11987
  const { props: themed, nestedTheme } = getThemedProps("RadioButton", void 0, {});
12980
11988
  const size = themed.size ?? 16;
@@ -13077,24 +12085,8 @@ function Text(props) {
13077
12085
  const { props: themed, nestedTheme } = getThemedProps("Text", localTheme, props);
13078
12086
  return /* @__PURE__ */ jsxRuntime.jsx("text", { ...themed, theme: nestedTheme });
13079
12087
  }
13080
- const Sprite = "Sprite";
13081
- const Graphics = "Graphics";
13082
- const TileSprite = "TileSprite";
13083
- function registerBuiltins() {
13084
- register("view", { create: viewCreator, patch: viewPatcher });
13085
- register("text", { create: textCreator, patch: textPatcher });
13086
- register("nineslice", { create: nineSliceCreator, patch: nineSlicePatcher });
13087
- register("sprite", { create: spriteCreator, patch: spritePatcher });
13088
- register("image", { create: imageCreator, patch: imagePatcher });
13089
- register("graphics", { create: graphicsCreator, patch: graphicsPatcher });
13090
- register("tilesprite", { create: tileSpriteCreator, patch: tileSpritePatcher });
13091
- register("View", { create: viewCreator, patch: viewPatcher });
13092
- register("Text", { create: textCreator, patch: textPatcher });
13093
- register("NineSlice", { create: nineSliceCreator, patch: nineSlicePatcher });
13094
- register("Sprite", { create: spriteCreator, patch: spritePatcher });
13095
- register("Image", { create: imageCreator, patch: imagePatcher });
13096
- register("Graphics", { create: graphicsCreator, patch: graphicsPatcher });
13097
- register("TileSprite", { create: tileSpriteCreator, patch: tileSpritePatcher });
12088
+ function Particles(props) {
12089
+ return /* @__PURE__ */ jsxRuntime.jsx("particles", { ...props });
13098
12090
  }
13099
12091
  function preprocessSvgForTinting(svg) {
13100
12092
  return svg.replace(/fill="currentColor"/gi, 'fill="#FFFFFF"').replace(/fill='currentColor'/gi, "fill='#FFFFFF'").replace(/fill:\s*currentColor/gi, "fill: #FFFFFF").replace(/fill="#000000"/gi, 'fill="#FFFFFF"').replace(/fill="#000"/gi, 'fill="#FFFFFF"').replace(/fill='#000000'/gi, "fill='#FFFFFF'").replace(/fill='#000'/gi, "fill='#FFFFFF'");
@@ -13998,6 +12990,15 @@ function Portal(props) {
13998
12990
  const depth = props.depth ?? 1e3;
13999
12991
  const scene = useScene();
14000
12992
  const blockEvents = props.blockEvents ?? true;
12993
+ const mountedNodesRef = useRef([]);
12994
+ const previousChildrenRef = useRef([]);
12995
+ const normalizeChildren2 = (children) => {
12996
+ if (!children) return [];
12997
+ const flat = Array.isArray(children) ? children.flat(Infinity) : [children];
12998
+ return flat.filter(
12999
+ (child) => !!child && typeof child === "object" && "type" in child
13000
+ );
13001
+ };
14001
13002
  useEffect(() => {
14002
13003
  const portalContainer = portalRegistry.register(
14003
13004
  portalId,
@@ -14012,15 +13013,19 @@ function Portal(props) {
14012
13013
  portalContainer.add(blockerContainer);
14013
13014
  blockerContainer.setDepth(-1);
14014
13015
  }
14015
- const children = Array.isArray(props.children) ? props.children : [props.children];
13016
+ const children = normalizeChildren2(props.children);
13017
+ const mountedNodes = [];
14016
13018
  for (const child of children) {
14017
13019
  if (child) {
14018
13020
  const mountedNode = mount(portalContainer, child);
14019
13021
  if (mountedNode) {
14020
13022
  portalContainer.add(mountedNode);
13023
+ mountedNodes.push(mountedNode);
14021
13024
  }
14022
13025
  }
14023
13026
  }
13027
+ mountedNodesRef.current = mountedNodes;
13028
+ previousChildrenRef.current = children;
14024
13029
  const gestureManager = getGestureManager(scene);
14025
13030
  if (blockEvents && blockerContainer) {
14026
13031
  const blocker = blockerContainer;
@@ -14067,7 +13072,31 @@ function Portal(props) {
14067
13072
  }
14068
13073
  portalRegistry.unregister(portalId);
14069
13074
  };
14070
- }, [portalId, depth, scene, props.children, blockEvents]);
13075
+ }, [portalId, depth, scene, blockEvents]);
13076
+ useEffect(() => {
13077
+ const portal = portalRegistry.get(portalId);
13078
+ if (!portal) return;
13079
+ const portalContainer = portal.container;
13080
+ const newChildren = normalizeChildren2(props.children);
13081
+ const oldChildren = previousChildrenRef.current;
13082
+ const maxLen = Math.max(oldChildren.length, newChildren.length);
13083
+ for (let i = 0; i < maxLen; i++) {
13084
+ const oldChild = oldChildren[i];
13085
+ const newChild = newChildren[i];
13086
+ if (oldChild && newChild) {
13087
+ patchVNode(portalContainer, oldChild, newChild);
13088
+ } else if (!oldChild && newChild) {
13089
+ const mountedNode = mount(portalContainer, newChild);
13090
+ if (mountedNode) {
13091
+ portalContainer.add(mountedNode);
13092
+ mountedNodesRef.current.push(mountedNode);
13093
+ }
13094
+ } else if (oldChild && !newChild) {
13095
+ unmount(oldChild);
13096
+ }
13097
+ }
13098
+ previousChildrenRef.current = newChildren;
13099
+ }, [props.children, portalId]);
14071
13100
  return null;
14072
13101
  }
14073
13102
  function Modal(props) {
@@ -14154,19 +13183,7 @@ function Modal(props) {
14154
13183
  view.setVisible(false);
14155
13184
  backdrop.setVisible(false);
14156
13185
  }
14157
- }, [
14158
- backdropAnimation,
14159
- closeDurationMs,
14160
- isVisible,
14161
- openDurationMs,
14162
- props.onClosed,
14163
- props.onOpen,
14164
- props.onRequestClose,
14165
- props.show,
14166
- stopBackdropEffects,
14167
- stopViewEffects,
14168
- viewAnimation
14169
- ]);
13186
+ }, [props.show]);
14170
13187
  useEffect(() => {
14171
13188
  if (!closeOnEscape || !props.show) return;
14172
13189
  const handleKeyDown = (e) => {
@@ -15465,18 +14482,29 @@ function Divider(props) {
15465
14482
  }
15466
14483
  function calculateSliderSize(size) {
15467
14484
  const { props: themed } = getThemedProps("ScrollSlider", void 0, {});
15468
- const sizeFactor = size === "large" ? 1.25 : size === "small" ? 0.75 : size === "tiny" ? 0.5 : 1;
14485
+ const sizeFactor = size === "large" ? 1.25 : size === "small" ? 0.75 : size === "tiny" ? 0.5 : size === "micro" ? 0.25 : size === "nano" ? 0.125 : 1;
15469
14486
  const border = (themed.borderWidth ?? 1) * sizeFactor;
15470
14487
  const outer = (themed.size ?? 24) * sizeFactor;
15471
14488
  const dimension = outer - border * 2;
15472
14489
  return { border, outer, dimension };
15473
14490
  }
15474
14491
  function ScrollSlider(props) {
15475
- const { direction, scrollPosition, viewportSize, contentSize, onScroll } = props;
14492
+ const {
14493
+ direction,
14494
+ scrollPosition,
14495
+ viewportSize,
14496
+ contentSize,
14497
+ onScroll,
14498
+ momentum = true,
14499
+ onMomentumEnd
14500
+ } = props;
15476
14501
  const { props: themed } = getThemedProps("ScrollSlider", void 0, {});
15477
14502
  const sliderRef = useRef(null);
15478
14503
  const isDraggingRef = useRef(false);
15479
14504
  const trackContainerRef = useRef(null);
14505
+ const velocityRef = useRef(0);
14506
+ const lastTimeRef = useRef(0);
14507
+ const tweenRef = useRef(null);
15480
14508
  const isVertical = direction === "vertical";
15481
14509
  const { border, outer, dimension } = calculateSliderSize(props.size);
15482
14510
  const containerWithLayout = trackContainerRef.current;
@@ -15492,18 +14520,60 @@ function ScrollSlider(props) {
15492
14520
  data.stopPropagation();
15493
14521
  if (data.state === "start") {
15494
14522
  isDraggingRef.current = true;
14523
+ velocityRef.current = 0;
14524
+ lastTimeRef.current = Date.now();
14525
+ if (tweenRef.current) {
14526
+ tweenRef.current.stop();
14527
+ tweenRef.current = null;
14528
+ }
15495
14529
  return;
15496
14530
  }
15497
14531
  if (data.state === "end") {
15498
14532
  isDraggingRef.current = false;
14533
+ if (momentum && Math.abs(velocityRef.current) > 0.1) {
14534
+ startMomentum(scrollPosition);
14535
+ } else if (onMomentumEnd) {
14536
+ onMomentumEnd();
14537
+ }
15499
14538
  return;
15500
14539
  }
15501
14540
  if (!isDraggingRef.current) return;
15502
14541
  const delta = isVertical ? data.dy ?? 0 : data.dx ?? 0;
14542
+ const now = Date.now();
14543
+ const deltaTime = now - lastTimeRef.current;
14544
+ if (deltaTime > 0) {
14545
+ velocityRef.current = delta / deltaTime * 1e3;
14546
+ lastTimeRef.current = now;
14547
+ }
15503
14548
  const newThumbPos = Math.max(0, Math.min(thumbRange, thumbPosition + delta));
15504
14549
  const newScrollPos = thumbRange > 0 ? newThumbPos / thumbRange * maxScroll : 0;
15505
14550
  onScroll(newScrollPos);
15506
14551
  };
14552
+ const startMomentum = (startPos) => {
14553
+ if (!sliderRef.current?.scene) return;
14554
+ const scene = sliderRef.current.scene;
14555
+ const duration = Math.min(1e3, Math.max(200, Math.abs(velocityRef.current)));
14556
+ const targetScrollPos = Math.max(
14557
+ 0,
14558
+ Math.min(maxScroll, startPos + velocityRef.current * (duration / 1e3))
14559
+ );
14560
+ tweenRef.current = scene.tweens.add({
14561
+ targets: { pos: startPos },
14562
+ pos: targetScrollPos,
14563
+ duration,
14564
+ ease: "Quad.easeOut",
14565
+ onUpdate: (tween) => {
14566
+ const target = tween.targets[0];
14567
+ onScroll(target.pos);
14568
+ },
14569
+ onComplete: () => {
14570
+ tweenRef.current = null;
14571
+ if (onMomentumEnd) {
14572
+ onMomentumEnd();
14573
+ }
14574
+ }
14575
+ });
14576
+ };
15507
14577
  const handleBackgroundTouch = (data) => {
15508
14578
  data.stopPropagation();
15509
14579
  const localPos = isVertical ? data.localY ?? 0 : data.localX ?? 0;
@@ -15569,14 +14639,30 @@ function ScrollView(props) {
15569
14639
  showVerticalSlider = "auto",
15570
14640
  showHorizontalSlider = "auto",
15571
14641
  scroll: initialScroll,
15572
- onScrollInfoChange
14642
+ onScrollInfoChange,
14643
+ snap = false,
14644
+ snapAlignment = "start",
14645
+ snapThreshold = 20,
14646
+ momentum = true,
14647
+ onSnap,
14648
+ ...viewProps
15573
14649
  } = props;
15574
- const [scroll, setScroll] = useState(initialScroll ?? { dx: 0, dy: 0 });
14650
+ const [scroll, setScroll] = useState({
14651
+ dx: initialScroll?.dx ?? 0,
14652
+ dy: initialScroll?.dy ?? 0
14653
+ });
14654
+ const scrollRef = useRef(scroll);
14655
+ const hasMountedRef = useRef(false);
14656
+ const lastAppliedSnapIndexRef = useRef(initialScroll?.snapIndex);
15575
14657
  const contentRef = useRef(null);
15576
14658
  const viewportRef = useRef(null);
15577
14659
  const [contentHeight, setContentHeight] = useState(0);
15578
14660
  const [contentWidth, setContentWidth] = useState(0);
15579
- const { outer: sliderSize } = calculateSliderSize(props.sliderSize);
14661
+ const [velocity, setVelocity] = useState({ vx: 0, vy: 0 });
14662
+ const [lastTime, setLastTime] = useState(0);
14663
+ const tweenRef = useRef(null);
14664
+ const wheelSnapTimeoutRef = useRef(null);
14665
+ const WHEEL_SNAP_DELAY = 200;
15580
14666
  const viewportHeight = viewportRef.current?.height ?? 0;
15581
14667
  const viewportWidth = viewportRef.current?.width ?? 0;
15582
14668
  const effectiveContentHeight = Math.max(contentHeight, viewportHeight);
@@ -15586,13 +14672,100 @@ function ScrollView(props) {
15586
14672
  const needsHorizontalScroll = effectiveContentWidth > viewportWidth + epsilon;
15587
14673
  const showVerticalSliderActual = showVerticalSlider === true || needsVerticalScroll && showVerticalSlider === "auto";
15588
14674
  const showHorizontalSliderActual = showHorizontalSlider === true || needsHorizontalScroll && showHorizontalSlider === "auto";
14675
+ const { outer: sliderSize } = calculateSliderSize(props.sliderSize);
14676
+ props.onSliderSize?.({
14677
+ width: showVerticalSlider ? sliderSize : 0,
14678
+ height: showHorizontalSliderActual ? sliderSize : 0
14679
+ });
15589
14680
  const maxScrollY = Math.max(0, effectiveContentHeight - viewportHeight);
15590
14681
  const maxScrollX = Math.max(0, effectiveContentWidth - viewportWidth);
14682
+ const updateScroll = (value) => {
14683
+ setScroll((prev) => {
14684
+ const next = typeof value === "function" ? value(prev) : value;
14685
+ scrollRef.current = next;
14686
+ return next;
14687
+ });
14688
+ };
14689
+ const stopActiveTween = () => {
14690
+ if (tweenRef.current) {
14691
+ tweenRef.current.stop();
14692
+ tweenRef.current = null;
14693
+ }
14694
+ };
14695
+ const resolvedSnapThreshold = typeof snap === "object" && "positions" in snap ? snap.threshold ?? snapThreshold : snapThreshold;
14696
+ const effectiveSnapThreshold = resolvedSnapThreshold === void 0 || resolvedSnapThreshold < 0 ? Infinity : resolvedSnapThreshold;
15591
14697
  useEffect(() => {
15592
- if (initialScroll) {
15593
- setScroll(initialScroll);
14698
+ if (!initialScroll) return;
14699
+ const allowAnimate = hasMountedRef.current;
14700
+ if (snap && typeof snap === "object" && "positions" in snap) {
14701
+ const { x: xTargets, y: yTargets } = getSnapTargets();
14702
+ const hasTargets = xTargets.length > 0 || yTargets.length > 0;
14703
+ if (initialScroll.snapIndex !== void 0 && hasTargets) {
14704
+ const maxIdx = Math.max(xTargets.length, yTargets.length) - 1;
14705
+ const clampedIdx = Math.max(0, Math.min(initialScroll.snapIndex, maxIdx));
14706
+ const targetX = xTargets[clampedIdx];
14707
+ const targetY = yTargets[clampedIdx];
14708
+ const nextDx = targetX !== void 0 ? alignTargetPosition(targetX, viewportWidth, maxScrollX) : initialScroll.dx ?? scrollRef.current.dx;
14709
+ const nextDy = targetY !== void 0 ? alignTargetPosition(targetY, viewportHeight, maxScrollY) : initialScroll.dy ?? scrollRef.current.dy;
14710
+ const shouldAnimate = allowAnimate && (clampedIdx !== lastAppliedSnapIndexRef.current || Math.abs(scrollRef.current.dx - nextDx) > 0.5 || Math.abs(scrollRef.current.dy - nextDy) > 0.5);
14711
+ lastAppliedSnapIndexRef.current = clampedIdx;
14712
+ if (shouldAnimate && contentRef.current?.scene) {
14713
+ stopActiveTween();
14714
+ const scene = contentRef.current.scene;
14715
+ tweenRef.current = scene.tweens.add({
14716
+ targets: { dx: scrollRef.current.dx, dy: scrollRef.current.dy },
14717
+ dx: nextDx,
14718
+ dy: nextDy,
14719
+ duration: 220,
14720
+ ease: "Quad.easeOut",
14721
+ onUpdate: (tween) => {
14722
+ const target = tween.targets[0];
14723
+ updateScroll({ dx: target.dx, dy: target.dy });
14724
+ },
14725
+ onComplete: () => {
14726
+ tweenRef.current = null;
14727
+ if (onSnap) {
14728
+ onSnap(clampedIdx);
14729
+ }
14730
+ }
14731
+ });
14732
+ } else {
14733
+ updateScroll({ dx: nextDx, dy: nextDy });
14734
+ if (onSnap) {
14735
+ onSnap(clampedIdx);
14736
+ }
14737
+ }
14738
+ hasMountedRef.current = true;
14739
+ return;
14740
+ }
15594
14741
  }
15595
- }, [initialScroll]);
14742
+ if (initialScroll.dx !== void 0 && initialScroll.dy !== void 0) {
14743
+ const nextDx = initialScroll.dx;
14744
+ const nextDy = initialScroll.dy;
14745
+ const shouldAnimate = allowAnimate && (Math.abs(scrollRef.current.dx - nextDx) > 0.5 || Math.abs(scrollRef.current.dy - nextDy) > 0.5);
14746
+ if (shouldAnimate && contentRef.current?.scene) {
14747
+ stopActiveTween();
14748
+ const scene = contentRef.current.scene;
14749
+ tweenRef.current = scene.tweens.add({
14750
+ targets: { dx: scrollRef.current.dx, dy: scrollRef.current.dy },
14751
+ dx: nextDx,
14752
+ dy: nextDy,
14753
+ duration: 220,
14754
+ ease: "Quad.easeOut",
14755
+ onUpdate: (tween) => {
14756
+ const target = tween.targets[0];
14757
+ updateScroll({ dx: target.dx, dy: target.dy });
14758
+ },
14759
+ onComplete: () => {
14760
+ tweenRef.current = null;
14761
+ }
14762
+ });
14763
+ } else {
14764
+ updateScroll({ dx: nextDx, dy: nextDy });
14765
+ }
14766
+ }
14767
+ hasMountedRef.current = true;
14768
+ }, [initialScroll, snap, viewportWidth, viewportHeight, maxScrollX, maxScrollY]);
15596
14769
  useEffect(() => {
15597
14770
  if (onScrollInfoChange && viewportWidth > 0 && viewportHeight > 0) {
15598
14771
  onScrollInfoChange({
@@ -15645,27 +14818,194 @@ function ScrollView(props) {
15645
14818
  const maxScrollX2 = Math.max(0, contentWidth2 - viewportWidth2);
15646
14819
  const newScrollY = Math.max(0, Math.min(maxScrollY2, scroll.dy - deltaY));
15647
14820
  const newScrollX = Math.max(0, Math.min(maxScrollX2, scroll.dx - deltaX));
15648
- setScroll({ dx: newScrollX, dy: newScrollY });
14821
+ updateScroll({ dx: newScrollX, dy: newScrollY });
14822
+ };
14823
+ const startMomentum = () => {
14824
+ if (!contentRef.current?.scene) return;
14825
+ const scene = contentRef.current.scene;
14826
+ const duration = Math.min(1e3, Math.max(200, Math.abs(velocity.vx) + Math.abs(velocity.vy)));
14827
+ const currentScroll = scrollRef.current;
14828
+ const baseTargetDx = Math.max(
14829
+ 0,
14830
+ Math.min(maxScrollX, currentScroll.dx - velocity.vx * (duration / 1e3))
14831
+ );
14832
+ const baseTargetDy = Math.max(
14833
+ 0,
14834
+ Math.min(maxScrollY, currentScroll.dy - velocity.vy * (duration / 1e3))
14835
+ );
14836
+ const snappedTarget = snap ? calculateSnapDestination(baseTargetDx, baseTargetDy) : null;
14837
+ stopActiveTween();
14838
+ tweenRef.current = scene.tweens.add({
14839
+ targets: { dx: currentScroll.dx, dy: currentScroll.dy },
14840
+ dx: snappedTarget?.dx ?? baseTargetDx,
14841
+ dy: snappedTarget?.dy ?? baseTargetDy,
14842
+ duration,
14843
+ ease: "Quad.easeOut",
14844
+ onUpdate: (tween) => {
14845
+ const target = tween.targets[0];
14846
+ updateScroll({ dx: target.dx, dy: target.dy });
14847
+ },
14848
+ onComplete: () => {
14849
+ tweenRef.current = null;
14850
+ if (snappedTarget && snappedTarget.index >= 0 && onSnap) {
14851
+ onSnap(snappedTarget.index);
14852
+ }
14853
+ }
14854
+ });
14855
+ };
14856
+ const getSnapTargets = () => {
14857
+ const viewportHeightCurrent = viewportRef.current?.height ?? viewportHeight;
14858
+ const viewportWidthCurrent = viewportRef.current?.width ?? viewportWidth;
14859
+ if (typeof snap === "object" && "positions" in snap) {
14860
+ const sorted = [...snap.positions].sort((a, b) => a - b);
14861
+ const inferredSizeY = sorted.length > 1 ? Math.max(0, (sorted[1] ?? 0) - (sorted[0] ?? 0)) : viewportHeightCurrent || 0;
14862
+ const inferredSizeX = sorted.length > 1 ? Math.max(0, (sorted[1] ?? 0) - (sorted[0] ?? 0)) : viewportWidthCurrent || 0;
14863
+ const targetsX = sorted.map((position, index) => {
14864
+ const next = sorted[index + 1];
14865
+ const size = next !== void 0 ? Math.max(0, next - position) : inferredSizeX > 0 ? inferredSizeX : viewportWidthCurrent || 0;
14866
+ return { position, size };
14867
+ });
14868
+ const targetsY = sorted.map((position, index) => {
14869
+ const next = sorted[index + 1];
14870
+ const size = next !== void 0 ? Math.max(0, next - position) : inferredSizeY > 0 ? inferredSizeY : viewportHeightCurrent || 0;
14871
+ return { position, size };
14872
+ });
14873
+ return { x: targetsX, y: targetsY };
14874
+ }
14875
+ return { x: [], y: [] };
14876
+ };
14877
+ const findNearestSnap = (current, targets, viewportSize, maxScroll) => {
14878
+ if (targets.length === 0) return { position: current, index: -1 };
14879
+ let nearest = current;
14880
+ let minDistance = Infinity;
14881
+ let nearestIndex = -1;
14882
+ for (let index = 0; index < targets.length; index++) {
14883
+ const { position, size } = targets[index] ?? { position: 0, size: 0 };
14884
+ let adjustedPos = position;
14885
+ if (snapAlignment === "center") {
14886
+ adjustedPos = position + size / 2 - viewportSize / 2;
14887
+ } else if (snapAlignment === "end") {
14888
+ adjustedPos = position + size - viewportSize;
14889
+ }
14890
+ adjustedPos = Math.max(0, Math.min(maxScroll, adjustedPos));
14891
+ const distance = Math.abs(current - adjustedPos);
14892
+ if (distance < minDistance && distance <= effectiveSnapThreshold) {
14893
+ minDistance = distance;
14894
+ nearest = adjustedPos;
14895
+ nearestIndex = index;
14896
+ } else if (distance < minDistance && effectiveSnapThreshold === Infinity) {
14897
+ minDistance = distance;
14898
+ nearest = adjustedPos;
14899
+ nearestIndex = index;
14900
+ }
14901
+ }
14902
+ return { position: nearest, index: nearestIndex };
14903
+ };
14904
+ const calculateSnapDestination = (baseDx, baseDy) => {
14905
+ const { x: xTargets, y: yTargets } = getSnapTargets();
14906
+ const viewportHeightLocal = viewportRef.current?.height ?? 0;
14907
+ const viewportWidthLocal = viewportRef.current?.width ?? 0;
14908
+ const snapX = findNearestSnap(baseDx, xTargets, viewportWidthLocal, maxScrollX);
14909
+ const snapY = findNearestSnap(baseDy, yTargets, viewportHeightLocal, maxScrollY);
14910
+ const snapIndex = snapY.index >= 0 ? snapY.index : snapX.index;
14911
+ return { dx: snapX.position, dy: snapY.position, index: snapIndex };
14912
+ };
14913
+ const alignTargetPosition = (target, viewportSize, maxScroll) => {
14914
+ let adjustedPos = target.position;
14915
+ if (snapAlignment === "center") {
14916
+ adjustedPos = target.position + target.size / 2 - viewportSize / 2;
14917
+ } else if (snapAlignment === "end") {
14918
+ adjustedPos = target.position + target.size - viewportSize;
14919
+ }
14920
+ return Math.max(0, Math.min(maxScroll, adjustedPos));
14921
+ };
14922
+ const applySnap = () => {
14923
+ if (!contentRef.current?.scene || !snap) return;
14924
+ const currentScroll = scrollRef.current;
14925
+ const {
14926
+ dx: targetDx,
14927
+ dy: targetDy,
14928
+ index: snapIndex
14929
+ } = calculateSnapDestination(currentScroll.dx, currentScroll.dy);
14930
+ if (targetDx === currentScroll.dx && targetDy === currentScroll.dy) {
14931
+ if (snapIndex >= 0 && onSnap) {
14932
+ onSnap(snapIndex);
14933
+ }
14934
+ return;
14935
+ }
14936
+ const scene = contentRef.current.scene;
14937
+ stopActiveTween();
14938
+ tweenRef.current = scene.tweens.add({
14939
+ targets: { dx: currentScroll.dx, dy: currentScroll.dy },
14940
+ dx: targetDx,
14941
+ dy: targetDy,
14942
+ duration: 250,
14943
+ ease: "Quad.easeOut",
14944
+ onUpdate: (tween) => {
14945
+ const target = tween.targets[0];
14946
+ updateScroll({ dx: target.dx, dy: target.dy });
14947
+ },
14948
+ onComplete: () => {
14949
+ tweenRef.current = null;
14950
+ if (snapIndex >= 0 && onSnap) {
14951
+ onSnap(snapIndex);
14952
+ }
14953
+ }
14954
+ });
15649
14955
  };
15650
14956
  const handleVerticalScroll = (scrollPos) => {
15651
14957
  const clampedScrollPos = Math.max(0, Math.min(maxScrollY, scrollPos));
15652
- setScroll((prev) => ({ ...prev, dy: clampedScrollPos }));
14958
+ updateScroll((prev) => ({ ...prev, dy: clampedScrollPos }));
15653
14959
  };
15654
14960
  const handleHorizontalScroll = (scrollPos) => {
15655
14961
  const clampedScrollPos = Math.max(0, Math.min(maxScrollX, scrollPos));
15656
- setScroll((prev) => ({ ...prev, dx: clampedScrollPos }));
14962
+ updateScroll((prev) => ({ ...prev, dx: clampedScrollPos }));
14963
+ };
14964
+ const handleSliderMomentumEnd = () => {
14965
+ if (snap) {
14966
+ applySnap();
14967
+ }
15657
14968
  };
15658
14969
  const handleTouchMove = (data) => {
15659
- if (data.state === "end") return;
14970
+ if (data.state === "end") {
14971
+ if (momentum && (Math.abs(velocity.vx) > 0.1 || Math.abs(velocity.vy) > 0.1)) {
14972
+ startMomentum();
14973
+ } else if (snap) {
14974
+ applySnap();
14975
+ }
14976
+ return;
14977
+ }
14978
+ if (data.state === "start") {
14979
+ stopActiveTween();
14980
+ setVelocity({ vx: 0, vy: 0 });
14981
+ setLastTime(Date.now());
14982
+ data.stopPropagation();
14983
+ return;
14984
+ }
15660
14985
  data.stopPropagation();
15661
14986
  const deltaX = data.dx ?? 0;
15662
14987
  const deltaY = data.dy ?? 0;
14988
+ const now = Date.now();
14989
+ const deltaTime = now - lastTime;
14990
+ if (deltaTime > 0) {
14991
+ const newVx = deltaX / deltaTime * 1e3;
14992
+ const newVy = deltaY / deltaTime * 1e3;
14993
+ setVelocity({ vx: newVx, vy: newVy });
14994
+ setLastTime(now);
14995
+ }
15663
14996
  calc(deltaX, deltaY);
15664
14997
  };
15665
14998
  const handleWheel = (data) => {
15666
14999
  data.stopPropagation();
15667
15000
  data.preventDefault();
15001
+ stopActiveTween();
15668
15002
  calc(-data.deltaX, -data.deltaY);
15003
+ if (snap) {
15004
+ if (wheelSnapTimeoutRef.current) {
15005
+ clearTimeout(wheelSnapTimeoutRef.current);
15006
+ }
15007
+ wheelSnapTimeoutRef.current = setTimeout(() => applySnap(), WHEEL_SNAP_DELAY);
15008
+ }
15669
15009
  };
15670
15010
  const redraw = useRedraw();
15671
15011
  const [visible, setVisible] = useState(false);
@@ -15675,9 +15015,14 @@ function ScrollView(props) {
15675
15015
  return () => {
15676
15016
  clearTimeout(timer1);
15677
15017
  clearTimeout(timer2);
15018
+ if (wheelSnapTimeoutRef.current) {
15019
+ clearTimeout(wheelSnapTimeoutRef.current);
15020
+ }
15021
+ stopActiveTween();
15678
15022
  };
15679
15023
  }, [showVerticalSliderActual, showHorizontalSliderActual]);
15680
- return /* @__PURE__ */ jsxRuntime.jsx(View, { visible, children: /* @__PURE__ */ jsxRuntime.jsxs(View, { direction: "row", width: "100%", height: "100%", gap: 0, padding: 0, children: [
15024
+ const resolvedVisible = viewProps.visible === "none" ? "none" : visible ? viewProps.visible ?? true : false;
15025
+ return /* @__PURE__ */ jsxRuntime.jsx(View, { ...viewProps, visible: resolvedVisible, children: /* @__PURE__ */ jsxRuntime.jsxs(View, { direction: "row", width: "100%", height: "100%", gap: 0, padding: 0, children: [
15681
15026
  /* @__PURE__ */ jsxRuntime.jsxs(View, { flex: 1, height: "100%", direction: "column", children: [
15682
15027
  /* @__PURE__ */ jsxRuntime.jsxs(
15683
15028
  View,
@@ -15731,7 +15076,9 @@ function ScrollView(props) {
15731
15076
  scrollPosition: scroll.dx,
15732
15077
  viewportSize: viewportWidth,
15733
15078
  contentSize: contentWidth,
15734
- onScroll: handleHorizontalScroll
15079
+ onScroll: handleHorizontalScroll,
15080
+ momentum,
15081
+ onMomentumEnd: handleSliderMomentumEnd
15735
15082
  }
15736
15083
  ) })
15737
15084
  ] }),
@@ -15744,7 +15091,9 @@ function ScrollView(props) {
15744
15091
  scrollPosition: scroll.dy,
15745
15092
  viewportSize: viewportHeight,
15746
15093
  contentSize: effectiveContentHeight,
15747
- onScroll: handleVerticalScroll
15094
+ onScroll: handleVerticalScroll,
15095
+ momentum,
15096
+ onMomentumEnd: handleSliderMomentumEnd
15748
15097
  }
15749
15098
  ) }),
15750
15099
  showHorizontalSliderActual && // Placeholder corner for potential icon - matches slider dimensions
@@ -16092,6 +15441,395 @@ function useIconPreload(type, loader) {
16092
15441
  }, [type, loader]);
16093
15442
  return svg !== null;
16094
15443
  }
15444
+ function joystickThemeFactory(joystickTheme, radius) {
15445
+ function createNeonBase(radius2, color = 65280) {
15446
+ return /* @__PURE__ */ jsxRuntime.jsx(
15447
+ Graphics,
15448
+ {
15449
+ onDraw: (g) => {
15450
+ g.fillStyle(color, 0.1);
15451
+ g.fillCircle(0, 0, radius2 + 10);
15452
+ g.fillStyle(0, 0.4);
15453
+ g.fillCircle(0, 0, radius2);
15454
+ g.lineStyle(3, color, 1);
15455
+ g.strokeCircle(0, 0, radius2);
15456
+ g.lineStyle(1, color, 0.5);
15457
+ g.strokeCircle(0, 0, radius2 - 5);
15458
+ for (let i = 0; i < 4; i++) {
15459
+ const angle = i * 90 * Math.PI / 180;
15460
+ const x1 = Math.cos(angle) * (radius2 - 15);
15461
+ const y1 = Math.sin(angle) * (radius2 - 15);
15462
+ const x2 = Math.cos(angle) * (radius2 - 5);
15463
+ const y2 = Math.sin(angle) * (radius2 - 5);
15464
+ g.lineStyle(2, color, 0.7);
15465
+ g.lineBetween(x1, y1, x2, y2);
15466
+ }
15467
+ }
15468
+ }
15469
+ );
15470
+ }
15471
+ function createNeonThumb(radius2, color = 65280) {
15472
+ const r = radius2 * 0.4;
15473
+ return /* @__PURE__ */ jsxRuntime.jsx(
15474
+ Graphics,
15475
+ {
15476
+ onDraw: (g) => {
15477
+ g.fillStyle(color, 0.2);
15478
+ g.fillCircle(0, 0, r + 5);
15479
+ g.fillStyle(color, 0.8);
15480
+ g.fillCircle(0, 0, r);
15481
+ g.lineStyle(2, color, 1);
15482
+ g.strokeCircle(0, 0, r);
15483
+ g.lineStyle(2, 0, 0.8);
15484
+ g.moveTo(0, -r * 0.6);
15485
+ g.lineTo(0, r * 0.6);
15486
+ g.moveTo(-r * 0.6, 0);
15487
+ g.lineTo(r * 0.6, 0);
15488
+ g.strokePath();
15489
+ }
15490
+ }
15491
+ );
15492
+ }
15493
+ function createTargetBase(radius2, tint2 = 16711680) {
15494
+ return /* @__PURE__ */ jsxRuntime.jsx(
15495
+ Graphics,
15496
+ {
15497
+ onDraw: (g) => {
15498
+ g.fillStyle(0, 0.3);
15499
+ g.fillCircle(0, 0, radius2);
15500
+ for (let i = 0; i < 3; i++) {
15501
+ const r = radius2 - i * 20;
15502
+ g.lineStyle(2, tint2, 0.6 - i * 0.15);
15503
+ g.strokeCircle(0, 0, r);
15504
+ }
15505
+ g.lineStyle(1, tint2, 0.5);
15506
+ g.moveTo(-radius2, 0);
15507
+ g.lineTo(radius2, 0);
15508
+ g.moveTo(0, -radius2);
15509
+ g.lineTo(0, radius2);
15510
+ g.strokePath();
15511
+ g.fillStyle(tint2, 0.8);
15512
+ g.fillCircle(0, 0, 5);
15513
+ }
15514
+ }
15515
+ );
15516
+ }
15517
+ function createTargetThumb(radius2, tint2 = 16711680) {
15518
+ const r = radius2 * 0.35;
15519
+ return /* @__PURE__ */ jsxRuntime.jsx(
15520
+ Graphics,
15521
+ {
15522
+ onDraw: (g) => {
15523
+ g.fillStyle(tint2, 0.7);
15524
+ g.fillCircle(0, 0, r);
15525
+ g.fillStyle(16777215, 0.9);
15526
+ g.fillCircle(0, 0, r * 0.5);
15527
+ g.fillStyle(tint2, 1);
15528
+ g.fillCircle(0, 0, r * 0.2);
15529
+ g.lineStyle(3, tint2, 1);
15530
+ g.beginPath();
15531
+ g.moveTo(0, -r);
15532
+ g.lineTo(r * 0.3, -r * 0.6);
15533
+ g.lineTo(-r * 0.3, -r * 0.6);
15534
+ g.closePath();
15535
+ g.fillPath();
15536
+ }
15537
+ }
15538
+ );
15539
+ }
15540
+ function createGlassBase(radius2, tint2 = 16777215) {
15541
+ return /* @__PURE__ */ jsxRuntime.jsx(
15542
+ Graphics,
15543
+ {
15544
+ onDraw: (g) => {
15545
+ g.fillStyle(tint2, 0.15);
15546
+ g.fillCircle(0, 0, radius2);
15547
+ g.fillStyle(tint2, 0.3);
15548
+ g.fillCircle(-radius2 * 0.3, -radius2 * 0.3, radius2 * 0.4);
15549
+ g.lineStyle(2, tint2, 0.5);
15550
+ g.strokeCircle(0, 0, radius2);
15551
+ g.lineStyle(1, tint2, 0.3);
15552
+ g.strokeCircle(0, 0, radius2 - 3);
15553
+ }
15554
+ }
15555
+ );
15556
+ }
15557
+ function createGlassThumb(radius2, tint2 = 16777215) {
15558
+ const r = radius2 * 0.4;
15559
+ return /* @__PURE__ */ jsxRuntime.jsx(
15560
+ Graphics,
15561
+ {
15562
+ onDraw: (g) => {
15563
+ g.fillStyle(0, 0.2);
15564
+ g.fillCircle(r * 0.1, r * 0.1, r);
15565
+ g.fillStyle(tint2, 0.4);
15566
+ g.fillCircle(0, 0, r);
15567
+ g.fillStyle(tint2, 0.6);
15568
+ g.fillCircle(-r * 0.3, -r * 0.3, r * 0.4);
15569
+ g.lineStyle(2, tint2, 0.7);
15570
+ g.strokeCircle(0, 0, r);
15571
+ }
15572
+ }
15573
+ );
15574
+ }
15575
+ function createMilitaryBase(radius2, tint2 = 65280) {
15576
+ return /* @__PURE__ */ jsxRuntime.jsx(
15577
+ Graphics,
15578
+ {
15579
+ onDraw: (g) => {
15580
+ g.fillStyle(1710618, 0.8);
15581
+ g.fillCircle(0, 0, radius2);
15582
+ g.lineStyle(1, tint2, 0.3);
15583
+ const step = 20;
15584
+ for (let i = -radius2; i <= radius2; i += step) {
15585
+ g.moveTo(-radius2, i);
15586
+ g.lineTo(radius2, i);
15587
+ g.moveTo(i, -radius2);
15588
+ g.lineTo(i, radius2);
15589
+ }
15590
+ g.strokePath();
15591
+ g.lineStyle(2, tint2, 0.6);
15592
+ g.strokeCircle(0, 0, radius2);
15593
+ g.strokeCircle(0, 0, radius2 * 0.66);
15594
+ g.strokeCircle(0, 0, radius2 * 0.33);
15595
+ const corners = [
15596
+ { x: -radius2 * 0.7, y: -radius2 * 0.7 },
15597
+ { x: radius2 * 0.7, y: -radius2 * 0.7 },
15598
+ { x: -radius2 * 0.7, y: radius2 * 0.7 },
15599
+ { x: radius2 * 0.7, y: radius2 * 0.7 }
15600
+ ];
15601
+ g.lineStyle(3, tint2, 0.8);
15602
+ corners.forEach(({ x, y }) => {
15603
+ g.moveTo(x - 10, y);
15604
+ g.lineTo(x + 10, y);
15605
+ g.moveTo(x, y - 10);
15606
+ g.lineTo(x, y + 10);
15607
+ });
15608
+ g.strokePath();
15609
+ }
15610
+ }
15611
+ );
15612
+ }
15613
+ function createMilitaryThumb(radius2, tint2 = 65280) {
15614
+ const r = radius2 * 0.3;
15615
+ return /* @__PURE__ */ jsxRuntime.jsx(
15616
+ Graphics,
15617
+ {
15618
+ onDraw: (g) => {
15619
+ g.fillStyle(tint2, 0.9);
15620
+ g.fillCircle(0, 0, r);
15621
+ g.fillStyle(0, 1);
15622
+ g.beginPath();
15623
+ g.moveTo(0, -r);
15624
+ g.lineTo(r * 0.5, r * 0.3);
15625
+ g.lineTo(-r * 0.5, r * 0.3);
15626
+ g.closePath();
15627
+ g.fillPath();
15628
+ g.lineStyle(2, 0, 0.8);
15629
+ g.strokeCircle(0, 0, r);
15630
+ }
15631
+ }
15632
+ );
15633
+ }
15634
+ function createDefaultBase(radius2, tint2 = 65280) {
15635
+ const size = { width: radius2 * 2 };
15636
+ return /* @__PURE__ */ jsxRuntime.jsx(
15637
+ Graphics,
15638
+ {
15639
+ onDraw: (g) => {
15640
+ g.fillStyle(0, 0.25);
15641
+ g.lineStyle(1, tint2);
15642
+ g.fillCircle(0, 0, size.width / 2);
15643
+ g.strokeCircle(0, 0, size.width / 2);
15644
+ }
15645
+ }
15646
+ );
15647
+ }
15648
+ function createDefaultThumb(radius2, tint2 = 65280) {
15649
+ const size = { width: radius2 * 2 };
15650
+ return /* @__PURE__ */ jsxRuntime.jsx(
15651
+ Graphics,
15652
+ {
15653
+ onDraw: (g) => {
15654
+ const r = size.width * 0.2;
15655
+ g.lineStyle(2, 0, 1);
15656
+ g.moveTo(0, -r);
15657
+ g.lineTo(0, r);
15658
+ g.moveTo(-r, 0);
15659
+ g.lineTo(r, 0);
15660
+ g.strokePath();
15661
+ g.lineStyle(2, tint2, 0.75);
15662
+ g.strokeCircle(0, 0, r * 1.1);
15663
+ }
15664
+ }
15665
+ );
15666
+ }
15667
+ const theme = joystickTheme != null ? joystickTheme.theme : "default";
15668
+ const tint = (joystickTheme != null ? joystickTheme.tint : 65280) ?? 65280;
15669
+ switch (theme) {
15670
+ case "neon":
15671
+ return {
15672
+ base: createNeonBase(radius, tint),
15673
+ thumb: createNeonThumb(radius, tint),
15674
+ rotateThumb: false
15675
+ };
15676
+ case "target":
15677
+ return {
15678
+ base: createTargetBase(radius, tint),
15679
+ thumb: createTargetThumb(radius, tint),
15680
+ rotateThumb: true
15681
+ };
15682
+ case "glass":
15683
+ return {
15684
+ base: createGlassBase(radius, tint),
15685
+ thumb: createGlassThumb(radius, tint),
15686
+ rotateThumb: false
15687
+ };
15688
+ case "military":
15689
+ return {
15690
+ base: createMilitaryBase(radius, tint),
15691
+ thumb: createMilitaryThumb(radius, tint),
15692
+ rotateThumb: true
15693
+ };
15694
+ case "default":
15695
+ default:
15696
+ return {
15697
+ base: createDefaultBase(radius, tint),
15698
+ thumb: createDefaultThumb(radius, tint),
15699
+ rotateThumb: false
15700
+ };
15701
+ }
15702
+ }
15703
+ function Joystick(props) {
15704
+ const outerRef = useRef(null);
15705
+ const [center, setCenter] = useState({ x: 0, y: 0 });
15706
+ const [size, setSize] = useState({ width: 0, height: 0 });
15707
+ const thumbRef = useRef(null);
15708
+ const forceExceededMinimumRef = useRef(false);
15709
+ const activeTweenRef = useRef(null);
15710
+ const isDraggingRef = useRef(false);
15711
+ const currentThumbPosRef = useRef({ x: 0, y: 0 });
15712
+ useEffect(() => {
15713
+ setTimeout(() => {
15714
+ const size2 = getLayoutSize(outerRef.current);
15715
+ console.log(`Joystick size: ${JSON.stringify(size2)}`);
15716
+ if (size2 != null) {
15717
+ const newCenter = { x: size2.width / 2, y: size2.height / 2 };
15718
+ setCenter(newCenter);
15719
+ setSize({ width: size2.width, height: size2.height });
15720
+ if (!isDraggingRef.current && !activeTweenRef.current) {
15721
+ currentThumbPosRef.current = newCenter;
15722
+ if (thumbRef.current != null) {
15723
+ thumbRef.current.setPosition(newCenter.x, newCenter.y);
15724
+ }
15725
+ }
15726
+ }
15727
+ }, 0);
15728
+ }, [outerRef]);
15729
+ const themeType = props.joystickTheme?.theme;
15730
+ const themeTint = props.joystickTheme?.tint;
15731
+ const sizeKey = `${size.width}x${size.height}`;
15732
+ const elements = useMemo(() => {
15733
+ if (props.base != null && props.thumb)
15734
+ return {
15735
+ base: props.base,
15736
+ thumb: props.thumb,
15737
+ rotateThumb: props.rotateThumb ?? false
15738
+ };
15739
+ if (size.width === 0 || size.height === 0)
15740
+ return {
15741
+ base: null,
15742
+ thumb: null,
15743
+ rotateThumb: false
15744
+ };
15745
+ const radius = Math.min(size.width, size.height) / 2;
15746
+ return joystickThemeFactory(props.joystickTheme, radius);
15747
+ }, [props.base, props.thumb, props.rotateThumb, themeType, themeTint, sizeKey]);
15748
+ const touchMove = (data) => {
15749
+ data.stopPropagation();
15750
+ if (thumbRef.current == null) return;
15751
+ if (data.state === "start") {
15752
+ forceExceededMinimumRef.current = false;
15753
+ isDraggingRef.current = true;
15754
+ }
15755
+ if (data.state === "end") {
15756
+ isDraggingRef.current = false;
15757
+ if (activeTweenRef.current) {
15758
+ activeTweenRef.current.stop();
15759
+ activeTweenRef.current = null;
15760
+ }
15761
+ if (thumbRef.current.scene) {
15762
+ activeTweenRef.current = thumbRef.current.scene.tweens.add({
15763
+ targets: thumbRef.current,
15764
+ x: center.x,
15765
+ y: center.y,
15766
+ angle: 0,
15767
+ duration: 150,
15768
+ ease: "Cubic.easeOut",
15769
+ onComplete: () => {
15770
+ activeTweenRef.current = null;
15771
+ currentThumbPosRef.current = { x: center.x, y: center.y };
15772
+ }
15773
+ });
15774
+ }
15775
+ props.onMove?.(false, 0, 0);
15776
+ return;
15777
+ }
15778
+ let offsetX = data.localX - data.width / 2 + center.x;
15779
+ let offsetY = data.localY - data.height / 2 + center.y;
15780
+ const radius = size.width / 2;
15781
+ const dx = offsetX - center.x;
15782
+ const dy = offsetY - center.y;
15783
+ const dist = Math.sqrt(dx * dx + dy * dy);
15784
+ const angle = Math.atan2(dy, dx) * (180 / Math.PI);
15785
+ const rawForce = Math.min(dist / radius, 1);
15786
+ const minForce = props.minForce ?? 0.2;
15787
+ const force = rawForce < minForce ? 0 : (rawForce - minForce) / (1 - minForce);
15788
+ if (force > 0) {
15789
+ forceExceededMinimumRef.current = true;
15790
+ }
15791
+ if (dist > radius) {
15792
+ const angleRad = Math.atan2(dy, dx);
15793
+ offsetX = center.x + Math.cos(angleRad) * radius;
15794
+ offsetY = center.y + Math.sin(angleRad) * radius;
15795
+ }
15796
+ if (activeTweenRef.current) {
15797
+ activeTweenRef.current.stop();
15798
+ activeTweenRef.current = null;
15799
+ }
15800
+ thumbRef.current.setPosition(offsetX, offsetY);
15801
+ currentThumbPosRef.current = { x: offsetX, y: offsetY };
15802
+ if (props.rotateThumb || elements.rotateThumb) {
15803
+ thumbRef.current.setAngle(angle + 90);
15804
+ }
15805
+ if (force > 0) {
15806
+ props.onMove?.(true, angle, force);
15807
+ } else {
15808
+ props.onMove?.(true, 0, 0);
15809
+ }
15810
+ };
15811
+ const handleTouch = () => {
15812
+ if (!forceExceededMinimumRef.current) {
15813
+ props.onTap?.();
15814
+ }
15815
+ };
15816
+ return /* @__PURE__ */ jsxRuntime.jsx(View, { ref: outerRef, width: props.width, height: props.height, children: /* @__PURE__ */ jsxRuntime.jsxs(
15817
+ RefOriginView,
15818
+ {
15819
+ width: props.width,
15820
+ height: props.height,
15821
+ originX: 0.5,
15822
+ originY: 0.5,
15823
+ onTouchMove: touchMove,
15824
+ onTouch: handleTouch,
15825
+ direction: "stack",
15826
+ children: [
15827
+ /* @__PURE__ */ jsxRuntime.jsx(View, { x: center.x, y: center.y, children: elements.base }),
15828
+ /* @__PURE__ */ jsxRuntime.jsx(View, { ref: thumbRef, x: currentThumbPosRef.current.x, y: currentThumbPosRef.current.y, children: elements.thumb })
15829
+ ]
15830
+ }
15831
+ ) });
15832
+ }
16095
15833
  function NineSlice(props) {
16096
15834
  const localTheme = useTheme();
16097
15835
  const { props: themed, nestedTheme } = getThemedProps("NineSlice", localTheme, props);
@@ -16291,7 +16029,13 @@ function Sidebar(props) {
16291
16029
  ...itemContainer
16292
16030
  } = itemStyle ?? {};
16293
16031
  const { textStyle: badgeTextStyle, ...badgeContainer } = badgeStyle ?? {};
16294
- const normalizeChildren = (child) => child ? Array.isArray(child) ? child : [child] : [];
16032
+ const normalizeChildren2 = (child) => {
16033
+ if (!child) return [];
16034
+ const flat = Array.isArray(child) ? child.flat(Infinity) : [child];
16035
+ return flat.filter(
16036
+ (node) => !!node && typeof node === "object" && "type" in node
16037
+ );
16038
+ };
16295
16039
  const renderTitle = (title) => {
16296
16040
  if (!title) return null;
16297
16041
  return typeof title === "string" ? /* @__PURE__ */ jsxRuntime.jsx(Text, { text: title, style: titleStyle }) : title;
@@ -16318,9 +16062,9 @@ function Sidebar(props) {
16318
16062
  const activeProps = item.active ? activeItemStyle ?? {} : {};
16319
16063
  const disabledProps = item.disabled && disabledAlpha !== void 0 ? { alpha: disabledAlpha } : {};
16320
16064
  const content = item.content ?? (item.label ? /* @__PURE__ */ jsxRuntime.jsx(Text, { text: item.label, style: itemTextStyle }) : null);
16321
- const iconNodes = normalizeChildren(item.icon ?? null);
16322
- const contentNodes2 = normalizeChildren(content);
16323
- const badgeNodes = normalizeChildren(renderBadge(item.badge));
16065
+ const iconNodes = normalizeChildren2(item.icon ?? null);
16066
+ const contentNodes2 = normalizeChildren2(content);
16067
+ const badgeNodes = normalizeChildren2(renderBadge(item.badge));
16324
16068
  const handleTouch = item.disabled ? void 0 : () => item.onSelect?.(item.key ?? key);
16325
16069
  return /* @__PURE__ */ jsxRuntime.jsx(
16326
16070
  View,
@@ -16365,7 +16109,7 @@ function Sidebar(props) {
16365
16109
  const hasSections = !!props.sections?.length;
16366
16110
  const primaryContent = sectionsContent ?? (!hasSections ? props.children : null) ?? null;
16367
16111
  const extraContent = hasSections ? props.children ?? null : null;
16368
- const contentNodes = [...normalizeChildren(primaryContent), ...normalizeChildren(extraContent)];
16112
+ const contentNodes = [...normalizeChildren2(primaryContent), ...normalizeChildren2(extraContent)];
16369
16113
  return /* @__PURE__ */ jsxRuntime.jsxs(
16370
16114
  View,
16371
16115
  {
@@ -16838,6 +16582,114 @@ function Slider(props) {
16838
16582
  function RangeSlider(props) {
16839
16583
  return /* @__PURE__ */ jsxRuntime.jsx(BaseSlider, { ...props, mode: "range" });
16840
16584
  }
16585
+ function Tab(_props) {
16586
+ return null;
16587
+ }
16588
+ function TabPanel(_props) {
16589
+ return null;
16590
+ }
16591
+ const normalizeChildren = (children) => {
16592
+ if (!children) return [];
16593
+ const flat = Array.isArray(children) ? children.flat(Infinity) : [children];
16594
+ return flat.filter(
16595
+ (child) => !!child && typeof child === "object" && "type" in child
16596
+ );
16597
+ };
16598
+ function Tabs(props) {
16599
+ const localTheme = useTheme();
16600
+ const { props: themed, nestedTheme } = getThemedProps("Tabs", localTheme, {});
16601
+ const [internalIndex, setInternalIndex] = useState(props.defaultIndex ?? 0);
16602
+ const rawIndex = props.activeIndex ?? internalIndex;
16603
+ const { tabs, panels } = useMemo(() => {
16604
+ const nodes = normalizeChildren(props.children);
16605
+ const collectedTabs = [];
16606
+ const collectedPanels = [];
16607
+ for (const node of nodes) {
16608
+ if (node.type === Tab) collectedTabs.push(node);
16609
+ if (node.type === TabPanel) collectedPanels.push(node);
16610
+ }
16611
+ return { tabs: collectedTabs, panels: collectedPanels };
16612
+ }, [props.children]);
16613
+ const panelCount = Math.min(tabs.length, panels.length);
16614
+ const safeIndex = panelCount > 0 ? Math.min(Math.max(rawIndex, 0), panelCount - 1) : 0;
16615
+ const handleSelect = (index) => {
16616
+ if (props.activeIndex === void 0) {
16617
+ setInternalIndex(index);
16618
+ }
16619
+ if (index !== safeIndex) {
16620
+ props.onChange?.(index);
16621
+ }
16622
+ };
16623
+ const tabListStyle = themed.tabListStyle ?? {};
16624
+ const tabStyle = themed.tabStyle ?? {};
16625
+ const tabActiveStyle = themed.tabActiveStyle ?? {};
16626
+ const tabDisabledStyle = themed.tabDisabledStyle ?? {};
16627
+ const panelStyle = themed.panelStyle ?? {};
16628
+ const {
16629
+ children: _children,
16630
+ activeIndex: _activeIndex,
16631
+ defaultIndex: _defaultIndex,
16632
+ onChange: _onChange,
16633
+ ...viewProps
16634
+ } = props;
16635
+ const activePanel = panels[safeIndex];
16636
+ const activePanelProps = activePanel?.props ?? {};
16637
+ const panelChildren = activePanel?.children ?? activePanelProps.children;
16638
+ const { children: _panelChildren, ...panelViewProps } = activePanelProps;
16639
+ const scrollableTabs = props.scrollableTabs ?? true;
16640
+ const tabListScrollProps = props.tabListScrollProps ?? {};
16641
+ const tabListContent = /* @__PURE__ */ jsxRuntime.jsx(View, { ...tabListStyle, direction: "row", width: scrollableTabs ? "auto" : "100%", children: tabs.slice(0, panelCount).map((tab, index) => {
16642
+ const tabProps = tab.props ?? {};
16643
+ const { disabled, onTouch, enableGestures, ...tabViewProps } = tabProps;
16644
+ const tabChildren = tab.children ?? tabProps.children;
16645
+ const isActive = index === safeIndex;
16646
+ const combinedTabStyle = {
16647
+ ...tabStyle,
16648
+ ...isActive ? tabActiveStyle : {},
16649
+ ...disabled ? tabDisabledStyle : {},
16650
+ ...tabViewProps
16651
+ };
16652
+ const tabKey = tab.__key ?? tabProps.key ?? index;
16653
+ return /* @__PURE__ */ jsxRuntime.jsx(
16654
+ View,
16655
+ {
16656
+ ...combinedTabStyle,
16657
+ enableGestures: !disabled && (enableGestures ?? true),
16658
+ onTouch: (data) => {
16659
+ if (disabled) return;
16660
+ handleSelect(index);
16661
+ onTouch?.(data);
16662
+ },
16663
+ children: tabChildren
16664
+ },
16665
+ tabKey
16666
+ );
16667
+ }) });
16668
+ const [tabHeight, setTabHeight] = useState(0);
16669
+ const [sliderHeight, setSliderHeight] = useState(0);
16670
+ const ref = useRef(null);
16671
+ useLayoutEffect(() => {
16672
+ const layout = useLayoutRect(ref);
16673
+ if (layout) setTabHeight(layout.height);
16674
+ }, [props, ref]);
16675
+ return /* @__PURE__ */ jsxRuntime.jsxs(View, { ...themed, ...viewProps, direction: "column", theme: nestedTheme, children: [
16676
+ scrollableTabs ? /* @__PURE__ */ jsxRuntime.jsx(
16677
+ ScrollView,
16678
+ {
16679
+ width: "100%",
16680
+ height: tabHeight + sliderHeight,
16681
+ showHorizontalSlider: "auto",
16682
+ showVerticalSlider: false,
16683
+ sliderSize: "nano",
16684
+ theme: nestedTheme,
16685
+ onSliderSize: (size) => setSliderHeight(size.height),
16686
+ ...tabListScrollProps,
16687
+ children: /* @__PURE__ */ jsxRuntime.jsx(View, { ref, children: tabListContent })
16688
+ }
16689
+ ) : tabListContent,
16690
+ activePanel ? /* @__PURE__ */ jsxRuntime.jsx(View, { ...panelStyle, ...panelViewProps, children: panelChildren }) : null
16691
+ ] });
16692
+ }
16841
16693
  function interpolateColor(color1, color2, progress) {
16842
16694
  const rgb1 = numberToRgb(color1);
16843
16695
  const rgb2 = numberToRgb(color2);
@@ -16969,7 +16821,7 @@ function Toggle(props) {
16969
16821
  ]
16970
16822
  }
16971
16823
  );
16972
- const labelElement = props.label && labelPosition !== "none" && /* @__PURE__ */ jsxRuntime.jsx(Text, { text: props.label, style: themed.labelStyle });
16824
+ const labelElement = props.label && labelPosition !== "none" ? /* @__PURE__ */ jsxRuntime.jsx(Text, { text: props.label, style: themed.labelStyle }) : null;
16973
16825
  if (!props.label || labelPosition === "none") {
16974
16826
  return /* @__PURE__ */ jsxRuntime.jsxs(View, { ref: containerRef, direction: "row", alignItems: "center", gap, theme: nestedTheme, children: [
16975
16827
  props.prefix,
@@ -17081,10 +16933,12 @@ exports.Graphics = Graphics;
17081
16933
  exports.HexColor = HexColor;
17082
16934
  exports.Icon = Icon;
17083
16935
  exports.Image = Image$1;
16936
+ exports.Joystick = Joystick;
17084
16937
  exports.KeyboardInputManager = KeyboardInputManager;
17085
16938
  exports.Modal = Modal;
17086
16939
  exports.NineSlice = NineSlice;
17087
16940
  exports.NineSliceButton = NineSliceButton;
16941
+ exports.Particles = Particles;
17088
16942
  exports.Portal = Portal;
17089
16943
  exports.RadioButton = RadioButton;
17090
16944
  exports.RadioGroup = RadioGroup;
@@ -17096,9 +16950,10 @@ exports.ScrollView = ScrollView;
17096
16950
  exports.Sidebar = Sidebar;
17097
16951
  exports.Slider = Slider;
17098
16952
  exports.SpringPhysics = SpringPhysics;
17099
- exports.Sprite = Sprite;
16953
+ exports.Tab = Tab;
16954
+ exports.TabPanel = TabPanel;
16955
+ exports.Tabs = Tabs;
17100
16956
  exports.Text = Text;
17101
- exports.TileSprite = TileSprite;
17102
16957
  exports.Toggle = Toggle;
17103
16958
  exports.TransformOriginView = TransformOriginView;
17104
16959
  exports.View = View;
@@ -17108,6 +16963,7 @@ exports.animatedSignal = animatedSignal;
17108
16963
  exports.applyDarkMode = applyDarkMode;
17109
16964
  exports.applyEffectByName = applyEffectByName;
17110
16965
  exports.applyLightMode = applyLightMode;
16966
+ exports.calculateLayout = calculateLayout;
17111
16967
  exports.calculateSliderSize = calculateSliderSize;
17112
16968
  exports.createBounceEffect = createBounceEffect;
17113
16969
  exports.createBreatheEffect = createBreatheEffect;
@@ -17145,21 +17001,26 @@ exports.defaultTextStyleTokens = defaultTextStyleTokens;
17145
17001
  exports.defaultTheme = defaultTheme;
17146
17002
  exports.disposeCtx = disposeCtx;
17147
17003
  exports.ensureContrast = ensureContrast;
17004
+ exports.equal = equal;
17148
17005
  exports.forestGreenPreset = forestGreenPreset;
17149
17006
  exports.generateColorScale = generateColorScale;
17007
+ exports.getBackgroundGraphics = getBackgroundGraphics;
17008
+ exports.getChildSize = getChildSize;
17150
17009
  exports.getContrastRatio = getContrastRatio;
17151
17010
  exports.getCurrent = getCurrent;
17011
+ exports.getGestureManager = getGestureManager;
17012
+ exports.getLayoutProps = getLayoutProps;
17013
+ exports.getLayoutRect = getLayoutRect;
17014
+ exports.getLayoutSize = getLayoutSize;
17015
+ exports.getMountStats = getMountStats;
17152
17016
  exports.getPreset = getPreset;
17153
17017
  exports.getPresetWithMode = getPresetWithMode;
17154
17018
  exports.getRenderContext = getRenderContext;
17155
17019
  exports.getThemedProps = getThemedProps;
17156
- exports.graphicsCreator = graphicsCreator;
17157
- exports.graphicsPatcher = graphicsPatcher;
17020
+ exports.getWorldLayoutRect = getWorldLayoutRect;
17158
17021
  exports.hex = hex;
17159
17022
  exports.hexToNumber = hexToNumber;
17160
17023
  exports.host = host;
17161
- exports.imageCreator = imageCreator;
17162
- exports.imagePatcher = imagePatcher;
17163
17024
  exports.isAnimatedSignal = isAnimatedSignal;
17164
17025
  exports.lighten = lighten;
17165
17026
  exports.lightenHex = lightenHex;
@@ -17167,43 +17028,42 @@ exports.mergeThemes = mergeThemes;
17167
17028
  exports.midnightPreset = midnightPreset;
17168
17029
  exports.mount = mount;
17169
17030
  exports.mountJSX = mountJSX;
17170
- exports.nineSliceCreator = nineSliceCreator;
17171
- exports.nineSlicePatcher = nineSlicePatcher;
17172
17031
  exports.nodeRegistry = nodeRegistry;
17173
17032
  exports.normalizeCornerRadius = normalizeCornerRadius;
17174
17033
  exports.normalizeEdgeInsets = normalizeEdgeInsets;
17175
17034
  exports.normalizeGap = normalizeGap;
17035
+ exports.normalizeVNodeLike = normalizeVNodeLike;
17176
17036
  exports.numberToHex = numberToHex;
17177
17037
  exports.numberToRgb = numberToRgb;
17178
17038
  exports.oceanBluePreset = oceanBluePreset;
17039
+ exports.parseSize = parseSize;
17179
17040
  exports.patchVNode = patchVNode;
17180
17041
  exports.portalRegistry = portalRegistry;
17181
17042
  exports.presets = presets;
17182
17043
  exports.register = register;
17183
- exports.registerBuiltins = registerBuiltins;
17184
17044
  exports.releaseAllSVGTextures = releaseAllSVGTextures;
17185
17045
  exports.releaseSVGTexture = releaseSVGTexture;
17186
17046
  exports.releaseSVGTextures = releaseSVGTextures;
17187
17047
  exports.remountAll = remountAll;
17188
17048
  exports.resolveEffect = resolveEffect;
17049
+ exports.resolveSize = resolveSize;
17189
17050
  exports.rgbToNumber = rgbToNumber;
17190
17051
  exports.shallowEqual = shallowEqual;
17191
17052
  exports.shouldComponentUpdate = shouldComponentUpdate;
17192
- exports.spriteCreator = spriteCreator;
17193
- exports.spritePatcher = spritePatcher;
17194
17053
  exports.svgToTexture = svgToTexture;
17195
- exports.textCreator = textCreator;
17196
- exports.textPatcher = textPatcher;
17197
17054
  exports.themeRegistry = themeRegistry;
17198
- exports.tileSpriteCreator = tileSpriteCreator;
17199
- exports.tileSpritePatcher = tileSpritePatcher;
17200
17055
  exports.unmount = unmount;
17056
+ exports.unmountJSX = unmountJSX;
17201
17057
  exports.unwrapSignal = unwrapSignal;
17058
+ exports.useBackgroundGraphics = useBackgroundGraphics;
17202
17059
  exports.useCallback = useCallback;
17203
17060
  exports.useEffect = useEffect;
17204
17061
  exports.useForceRedraw = useForceRedraw;
17205
17062
  exports.useGameObjectEffect = useGameObjectEffect;
17206
17063
  exports.useIconPreload = useIconPreload;
17064
+ exports.useLayoutEffect = useLayoutEffect;
17065
+ exports.useLayoutRect = useLayoutRect;
17066
+ exports.useLayoutSize = useLayoutSize;
17207
17067
  exports.useMemo = useMemo;
17208
17068
  exports.useRedraw = useRedraw;
17209
17069
  exports.useRef = useRef;
@@ -17214,9 +17074,9 @@ exports.useSpring = useSpring;
17214
17074
  exports.useSprings = useSprings;
17215
17075
  exports.useState = useState;
17216
17076
  exports.useTheme = useTheme;
17077
+ exports.useViewportSize = useViewportSize;
17078
+ exports.useWorldLayoutRect = useWorldLayoutRect;
17217
17079
  exports.vdom = vdom;
17218
- exports.viewCreator = viewCreator;
17219
- exports.viewPatcher = viewPatcher;
17220
17080
  exports.viewportRegistry = viewportRegistry;
17221
17081
  exports.withHooks = withHooks;
17222
- //# sourceMappingURL=TransformOriginView-BDM6GE2F.cjs.map
17082
+ //# sourceMappingURL=TransformOriginView-Bx81YEUU.cjs.map