@number10/jsx-core 5.0.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 (340) hide show
  1. package/LICENSE +667 -0
  2. package/README.md +38 -0
  3. package/dist/animation/animated-signal.cjs +19 -0
  4. package/dist/animation/animated-signal.cjs.map +1 -0
  5. package/dist/animation/animated-signal.d.ts +35 -0
  6. package/dist/animation/animated-signal.d.ts.map +1 -0
  7. package/dist/animation/animated-signal.js +19 -0
  8. package/dist/animation/animated-signal.js.map +1 -0
  9. package/dist/animation/create-spring.cjs +80 -0
  10. package/dist/animation/create-spring.cjs.map +1 -0
  11. package/dist/animation/create-spring.d.ts +56 -0
  12. package/dist/animation/create-spring.d.ts.map +1 -0
  13. package/dist/animation/create-spring.js +80 -0
  14. package/dist/animation/create-spring.js.map +1 -0
  15. package/dist/animation/easing.cjs +76 -0
  16. package/dist/animation/easing.cjs.map +1 -0
  17. package/dist/animation/easing.d.ts +45 -0
  18. package/dist/animation/easing.d.ts.map +1 -0
  19. package/dist/animation/easing.js +76 -0
  20. package/dist/animation/easing.js.map +1 -0
  21. package/dist/animation/effect-definitions.cjs +441 -0
  22. package/dist/animation/effect-definitions.cjs.map +1 -0
  23. package/dist/animation/effect-definitions.d.ts +60 -0
  24. package/dist/animation/effect-definitions.d.ts.map +1 -0
  25. package/dist/animation/effect-definitions.js +441 -0
  26. package/dist/animation/effect-definitions.js.map +1 -0
  27. package/dist/animation/effect-engine.cjs +189 -0
  28. package/dist/animation/effect-engine.cjs.map +1 -0
  29. package/dist/animation/effect-engine.d.ts +70 -0
  30. package/dist/animation/effect-engine.d.ts.map +1 -0
  31. package/dist/animation/effect-engine.js +189 -0
  32. package/dist/animation/effect-engine.js.map +1 -0
  33. package/dist/animation/index.d.ts +24 -0
  34. package/dist/animation/index.d.ts.map +1 -0
  35. package/dist/animation/spring-physics.cjs +94 -0
  36. package/dist/animation/spring-physics.cjs.map +1 -0
  37. package/dist/animation/spring-physics.d.ts +145 -0
  38. package/dist/animation/spring-physics.d.ts.map +1 -0
  39. package/dist/animation/spring-physics.js +94 -0
  40. package/dist/animation/spring-physics.js.map +1 -0
  41. package/dist/animation/tween.cjs +67 -0
  42. package/dist/animation/tween.cjs.map +1 -0
  43. package/dist/animation/tween.d.ts +60 -0
  44. package/dist/animation/tween.d.ts.map +1 -0
  45. package/dist/animation/tween.js +67 -0
  46. package/dist/animation/tween.js.map +1 -0
  47. package/dist/animation/types.d.ts +31 -0
  48. package/dist/animation/types.d.ts.map +1 -0
  49. package/dist/animation/useSpring.cjs +152 -0
  50. package/dist/animation/useSpring.cjs.map +1 -0
  51. package/dist/animation/useSpring.d.ts +55 -0
  52. package/dist/animation/useSpring.d.ts.map +1 -0
  53. package/dist/animation/useSpring.js +149 -0
  54. package/dist/animation/useSpring.js.map +1 -0
  55. package/dist/animation/useTween.cjs +208 -0
  56. package/dist/animation/useTween.cjs.map +1 -0
  57. package/dist/animation/useTween.d.ts +116 -0
  58. package/dist/animation/useTween.d.ts.map +1 -0
  59. package/dist/animation/useTween.js +208 -0
  60. package/dist/animation/useTween.js.map +1 -0
  61. package/dist/border-geometry.cjs +447 -0
  62. package/dist/border-geometry.cjs.map +1 -0
  63. package/dist/border-geometry.d.ts +114 -0
  64. package/dist/border-geometry.d.ts.map +1 -0
  65. package/dist/border-geometry.js +447 -0
  66. package/dist/border-geometry.js.map +1 -0
  67. package/dist/colors/color-presets.cjs +236 -0
  68. package/dist/colors/color-presets.cjs.map +1 -0
  69. package/dist/colors/color-presets.d.ts +89 -0
  70. package/dist/colors/color-presets.d.ts.map +1 -0
  71. package/dist/colors/color-presets.js +236 -0
  72. package/dist/colors/color-presets.js.map +1 -0
  73. package/dist/colors/color-theme-helpers.cjs +32 -0
  74. package/dist/colors/color-theme-helpers.cjs.map +1 -0
  75. package/dist/colors/color-theme-helpers.d.ts +65 -0
  76. package/dist/colors/color-theme-helpers.d.ts.map +1 -0
  77. package/dist/colors/color-theme-helpers.js +32 -0
  78. package/dist/colors/color-theme-helpers.js.map +1 -0
  79. package/dist/colors/color-types.cjs +38 -0
  80. package/dist/colors/color-types.cjs.map +1 -0
  81. package/dist/colors/color-types.d.ts +112 -0
  82. package/dist/colors/color-types.d.ts.map +1 -0
  83. package/dist/colors/color-types.js +38 -0
  84. package/dist/colors/color-types.js.map +1 -0
  85. package/dist/colors/color-utils.cjs +197 -0
  86. package/dist/colors/color-utils.cjs.map +1 -0
  87. package/dist/colors/color-utils.d.ts +216 -0
  88. package/dist/colors/color-utils.d.ts.map +1 -0
  89. package/dist/colors/color-utils.js +197 -0
  90. package/dist/colors/color-utils.js.map +1 -0
  91. package/dist/colors/contrast-contracts.cjs +265 -0
  92. package/dist/colors/contrast-contracts.cjs.map +1 -0
  93. package/dist/colors/contrast-contracts.d.ts +289 -0
  94. package/dist/colors/contrast-contracts.d.ts.map +1 -0
  95. package/dist/colors/contrast-contracts.js +265 -0
  96. package/dist/colors/contrast-contracts.js.map +1 -0
  97. package/dist/colors/index.cjs +55 -0
  98. package/dist/colors/index.cjs.map +1 -0
  99. package/dist/colors/index.d.ts +16 -0
  100. package/dist/colors/index.d.ts.map +1 -0
  101. package/dist/colors/index.js +55 -0
  102. package/dist/colors/index.js.map +1 -0
  103. package/dist/core-props.cjs +66 -0
  104. package/dist/core-props.cjs.map +1 -0
  105. package/dist/core-props.d.ts +395 -0
  106. package/dist/core-props.d.ts.map +1 -0
  107. package/dist/core-props.js +66 -0
  108. package/dist/core-props.js.map +1 -0
  109. package/dist/design-tokens/design-token-presets.cjs +91 -0
  110. package/dist/design-tokens/design-token-presets.cjs.map +1 -0
  111. package/dist/design-tokens/design-token-presets.d.ts +34 -0
  112. package/dist/design-tokens/design-token-presets.d.ts.map +1 -0
  113. package/dist/design-tokens/design-token-presets.js +91 -0
  114. package/dist/design-tokens/design-token-presets.js.map +1 -0
  115. package/dist/design-tokens/design-token-types.d.ts +97 -0
  116. package/dist/design-tokens/design-token-types.d.ts.map +1 -0
  117. package/dist/design-tokens/index.cjs +10 -0
  118. package/dist/design-tokens/index.cjs.map +1 -0
  119. package/dist/design-tokens/index.d.ts +9 -0
  120. package/dist/design-tokens/index.d.ts.map +1 -0
  121. package/dist/design-tokens/index.js +10 -0
  122. package/dist/design-tokens/index.js.map +1 -0
  123. package/dist/dev-config.cjs +296 -0
  124. package/dist/dev-config.cjs.map +1 -0
  125. package/dist/dev-config.d.ts +238 -0
  126. package/dist/dev-config.d.ts.map +1 -0
  127. package/dist/dev-config.js +296 -0
  128. package/dist/dev-config.js.map +1 -0
  129. package/dist/effects.cjs +69 -0
  130. package/dist/effects.cjs.map +1 -0
  131. package/dist/effects.d.ts +152 -0
  132. package/dist/effects.d.ts.map +1 -0
  133. package/dist/effects.js +69 -0
  134. package/dist/effects.js.map +1 -0
  135. package/dist/global-registry.cjs +25 -0
  136. package/dist/global-registry.cjs.map +1 -0
  137. package/dist/global-registry.d.ts +19 -0
  138. package/dist/global-registry.d.ts.map +1 -0
  139. package/dist/global-registry.js +25 -0
  140. package/dist/global-registry.js.map +1 -0
  141. package/dist/hooks.cjs +378 -0
  142. package/dist/hooks.cjs.map +1 -0
  143. package/dist/hooks.d.ts +322 -0
  144. package/dist/hooks.d.ts.map +1 -0
  145. package/dist/hooks.js +378 -0
  146. package/dist/hooks.js.map +1 -0
  147. package/dist/host-adapter.d.ts +414 -0
  148. package/dist/host-adapter.d.ts.map +1 -0
  149. package/dist/index.cjs +229 -0
  150. package/dist/index.cjs.map +1 -0
  151. package/dist/index.d.ts +32 -0
  152. package/dist/index.d.ts.map +1 -0
  153. package/dist/index.js +226 -0
  154. package/dist/index.js.map +1 -0
  155. package/dist/jsx-dev-runtime.cjs +10 -0
  156. package/dist/jsx-dev-runtime.cjs.map +1 -0
  157. package/dist/jsx-dev-runtime.d.ts +5 -0
  158. package/dist/jsx-dev-runtime.d.ts.map +1 -0
  159. package/dist/jsx-dev-runtime.js +11 -0
  160. package/dist/jsx-dev-runtime.js.map +1 -0
  161. package/dist/jsx-runtime.cjs +44 -0
  162. package/dist/jsx-runtime.cjs.map +1 -0
  163. package/dist/jsx-runtime.d.ts +24 -0
  164. package/dist/jsx-runtime.d.ts.map +1 -0
  165. package/dist/jsx-runtime.js +44 -0
  166. package/dist/jsx-runtime.js.map +1 -0
  167. package/dist/jsx-types.d.ts +25 -0
  168. package/dist/jsx-types.d.ts.map +1 -0
  169. package/dist/layout/appliers/container-applier.cjs +20 -0
  170. package/dist/layout/appliers/container-applier.cjs.map +1 -0
  171. package/dist/layout/appliers/container-applier.d.ts +9 -0
  172. package/dist/layout/appliers/container-applier.d.ts.map +1 -0
  173. package/dist/layout/appliers/container-applier.js +20 -0
  174. package/dist/layout/appliers/container-applier.js.map +1 -0
  175. package/dist/layout/appliers/position-applier.cjs +31 -0
  176. package/dist/layout/appliers/position-applier.cjs.map +1 -0
  177. package/dist/layout/appliers/position-applier.d.ts +8 -0
  178. package/dist/layout/appliers/position-applier.d.ts.map +1 -0
  179. package/dist/layout/appliers/position-applier.js +31 -0
  180. package/dist/layout/appliers/position-applier.js.map +1 -0
  181. package/dist/layout/layout-engine-test-utils.d.ts +26 -0
  182. package/dist/layout/layout-engine-test-utils.d.ts.map +1 -0
  183. package/dist/layout/layout-engine.cjs +628 -0
  184. package/dist/layout/layout-engine.cjs.map +1 -0
  185. package/dist/layout/layout-engine.d.ts +140 -0
  186. package/dist/layout/layout-engine.d.ts.map +1 -0
  187. package/dist/layout/layout-engine.js +628 -0
  188. package/dist/layout/layout-engine.js.map +1 -0
  189. package/dist/layout/strategies/base-strategy.cjs +31 -0
  190. package/dist/layout/strategies/base-strategy.cjs.map +1 -0
  191. package/dist/layout/strategies/base-strategy.d.ts +59 -0
  192. package/dist/layout/strategies/base-strategy.d.ts.map +1 -0
  193. package/dist/layout/strategies/base-strategy.js +31 -0
  194. package/dist/layout/strategies/base-strategy.js.map +1 -0
  195. package/dist/layout/strategies/column-layout.cjs +145 -0
  196. package/dist/layout/strategies/column-layout.cjs.map +1 -0
  197. package/dist/layout/strategies/column-layout.d.ts +38 -0
  198. package/dist/layout/strategies/column-layout.d.ts.map +1 -0
  199. package/dist/layout/strategies/column-layout.js +145 -0
  200. package/dist/layout/strategies/column-layout.js.map +1 -0
  201. package/dist/layout/strategies/row-layout.cjs +145 -0
  202. package/dist/layout/strategies/row-layout.cjs.map +1 -0
  203. package/dist/layout/strategies/row-layout.d.ts +38 -0
  204. package/dist/layout/strategies/row-layout.d.ts.map +1 -0
  205. package/dist/layout/strategies/row-layout.js +145 -0
  206. package/dist/layout/strategies/row-layout.js.map +1 -0
  207. package/dist/layout/strategies/stack-layout.cjs +94 -0
  208. package/dist/layout/strategies/stack-layout.cjs.map +1 -0
  209. package/dist/layout/strategies/stack-layout.d.ts +30 -0
  210. package/dist/layout/strategies/stack-layout.d.ts.map +1 -0
  211. package/dist/layout/strategies/stack-layout.js +94 -0
  212. package/dist/layout/strategies/stack-layout.js.map +1 -0
  213. package/dist/layout/types.d.ts +134 -0
  214. package/dist/layout/types.d.ts.map +1 -0
  215. package/dist/layout/utils/child-utils.cjs +129 -0
  216. package/dist/layout/utils/child-utils.cjs.map +1 -0
  217. package/dist/layout/utils/child-utils.d.ts +54 -0
  218. package/dist/layout/utils/child-utils.d.ts.map +1 -0
  219. package/dist/layout/utils/child-utils.js +129 -0
  220. package/dist/layout/utils/child-utils.js.map +1 -0
  221. package/dist/layout/utils/dimension-calculator.cjs +109 -0
  222. package/dist/layout/utils/dimension-calculator.cjs.map +1 -0
  223. package/dist/layout/utils/dimension-calculator.d.ts +59 -0
  224. package/dist/layout/utils/dimension-calculator.d.ts.map +1 -0
  225. package/dist/layout/utils/dimension-calculator.js +109 -0
  226. package/dist/layout/utils/dimension-calculator.js.map +1 -0
  227. package/dist/layout/utils/flex-distributor.cjs +173 -0
  228. package/dist/layout/utils/flex-distributor.cjs.map +1 -0
  229. package/dist/layout/utils/flex-distributor.d.ts +18 -0
  230. package/dist/layout/utils/flex-distributor.d.ts.map +1 -0
  231. package/dist/layout/utils/flex-distributor.js +173 -0
  232. package/dist/layout/utils/flex-distributor.js.map +1 -0
  233. package/dist/layout/utils/size-resolver.cjs +280 -0
  234. package/dist/layout/utils/size-resolver.cjs.map +1 -0
  235. package/dist/layout/utils/size-resolver.d.ts +84 -0
  236. package/dist/layout/utils/size-resolver.d.ts.map +1 -0
  237. package/dist/layout/utils/size-resolver.js +280 -0
  238. package/dist/layout/utils/size-resolver.js.map +1 -0
  239. package/dist/layout/utils/spacing-calculator.cjs +50 -0
  240. package/dist/layout/utils/spacing-calculator.cjs.map +1 -0
  241. package/dist/layout/utils/spacing-calculator.d.ts +27 -0
  242. package/dist/layout/utils/spacing-calculator.d.ts.map +1 -0
  243. package/dist/layout/utils/spacing-calculator.js +50 -0
  244. package/dist/layout/utils/spacing-calculator.js.map +1 -0
  245. package/dist/memo.cjs +18 -0
  246. package/dist/memo.cjs.map +1 -0
  247. package/dist/memo.d.ts +29 -0
  248. package/dist/memo.d.ts.map +1 -0
  249. package/dist/memo.js +18 -0
  250. package/dist/memo.js.map +1 -0
  251. package/dist/nineslice-contract.cjs +60 -0
  252. package/dist/nineslice-contract.cjs.map +1 -0
  253. package/dist/nineslice-contract.d.ts +107 -0
  254. package/dist/nineslice-contract.d.ts.map +1 -0
  255. package/dist/nineslice-contract.js +60 -0
  256. package/dist/nineslice-contract.js.map +1 -0
  257. package/dist/placeholder.cjs +12 -0
  258. package/dist/placeholder.cjs.map +1 -0
  259. package/dist/placeholder.d.ts +44 -0
  260. package/dist/placeholder.d.ts.map +1 -0
  261. package/dist/placeholder.js +12 -0
  262. package/dist/placeholder.js.map +1 -0
  263. package/dist/portal.cjs +89 -0
  264. package/dist/portal.cjs.map +1 -0
  265. package/dist/portal.d.ts +62 -0
  266. package/dist/portal.d.ts.map +1 -0
  267. package/dist/portal.js +89 -0
  268. package/dist/portal.js.map +1 -0
  269. package/dist/primitive-contracts.cjs +12 -0
  270. package/dist/primitive-contracts.cjs.map +1 -0
  271. package/dist/primitive-contracts.d.ts +186 -0
  272. package/dist/primitive-contracts.d.ts.map +1 -0
  273. package/dist/primitive-contracts.js +12 -0
  274. package/dist/primitive-contracts.js.map +1 -0
  275. package/dist/theme.cjs +332 -0
  276. package/dist/theme.cjs.map +1 -0
  277. package/dist/theme.d.ts +204 -0
  278. package/dist/theme.d.ts.map +1 -0
  279. package/dist/theme.js +332 -0
  280. package/dist/theme.js.map +1 -0
  281. package/dist/types.d.ts +86 -0
  282. package/dist/types.d.ts.map +1 -0
  283. package/dist/vdom/create-runtime.cjs +79 -0
  284. package/dist/vdom/create-runtime.cjs.map +1 -0
  285. package/dist/vdom/create-runtime.d.ts +7 -0
  286. package/dist/vdom/create-runtime.d.ts.map +1 -0
  287. package/dist/vdom/create-runtime.js +79 -0
  288. package/dist/vdom/create-runtime.js.map +1 -0
  289. package/dist/vdom/index.cjs +8 -0
  290. package/dist/vdom/index.cjs.map +1 -0
  291. package/dist/vdom/index.d.ts +4 -0
  292. package/dist/vdom/index.d.ts.map +1 -0
  293. package/dist/vdom/index.js +8 -0
  294. package/dist/vdom/index.js.map +1 -0
  295. package/dist/vdom/mount.cjs +161 -0
  296. package/dist/vdom/mount.cjs.map +1 -0
  297. package/dist/vdom/mount.d.ts +6 -0
  298. package/dist/vdom/mount.d.ts.map +1 -0
  299. package/dist/vdom/mount.js +161 -0
  300. package/dist/vdom/mount.js.map +1 -0
  301. package/dist/vdom/patch.cjs +163 -0
  302. package/dist/vdom/patch.cjs.map +1 -0
  303. package/dist/vdom/patch.d.ts +3 -0
  304. package/dist/vdom/patch.d.ts.map +1 -0
  305. package/dist/vdom/patch.js +163 -0
  306. package/dist/vdom/patch.js.map +1 -0
  307. package/dist/vdom/registry.cjs +85 -0
  308. package/dist/vdom/registry.cjs.map +1 -0
  309. package/dist/vdom/registry.d.ts +28 -0
  310. package/dist/vdom/registry.d.ts.map +1 -0
  311. package/dist/vdom/registry.js +85 -0
  312. package/dist/vdom/registry.js.map +1 -0
  313. package/dist/vdom/runtime-helpers.cjs +23 -0
  314. package/dist/vdom/runtime-helpers.cjs.map +1 -0
  315. package/dist/vdom/runtime-helpers.d.ts +8 -0
  316. package/dist/vdom/runtime-helpers.d.ts.map +1 -0
  317. package/dist/vdom/runtime-helpers.js +23 -0
  318. package/dist/vdom/runtime-helpers.js.map +1 -0
  319. package/dist/vdom/surface.cjs +107 -0
  320. package/dist/vdom/surface.cjs.map +1 -0
  321. package/dist/vdom/surface.d.ts +9 -0
  322. package/dist/vdom/surface.d.ts.map +1 -0
  323. package/dist/vdom/surface.js +107 -0
  324. package/dist/vdom/surface.js.map +1 -0
  325. package/dist/vdom/types.d.ts +104 -0
  326. package/dist/vdom/types.d.ts.map +1 -0
  327. package/dist/vdom/utils.cjs +146 -0
  328. package/dist/vdom/utils.cjs.map +1 -0
  329. package/dist/vdom/utils.d.ts +24 -0
  330. package/dist/vdom/utils.d.ts.map +1 -0
  331. package/dist/vdom/utils.js +146 -0
  332. package/dist/vdom/utils.js.map +1 -0
  333. package/dist/vdom.d.ts +4 -0
  334. package/dist/vdom.d.ts.map +1 -0
  335. package/dist/vector-draw-context.d.ts +63 -0
  336. package/dist/vector-draw-context.d.ts.map +1 -0
  337. package/package.json +161 -0
  338. package/vdom/index.cjs +1 -0
  339. package/vdom/index.d.ts +1 -0
  340. package/vdom/index.js +1 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"layout-engine.js","sources":["../../src/layout/layout-engine.ts"],"sourcesContent":["/**\n * Layout engine — main orchestrator for layout calculations.\n *\n * Renderer-neutral. Uses strategy pattern for layout directions.\n * Renderer-specific operations (clipping, background drawing, hit areas)\n * are injected via callbacks.\n *\n * @migration(audit:phase-5f+) Phase 5F+ — moved from @number10/jsx-phaser to @number10/jsx-core.\n * Phaser-specific parts (stencil clip, background) extracted to callbacks.\n */\nimport type { LayoutProps } from '../core-props'\nimport { normalizeGap } from '../core-props'\nimport { DebugLogger } from '../dev-config'\nimport { getGlobalValue, getOrCreateGlobalValue, setGlobalValue } from '../global-registry'\nimport { applyContainerDimensions } from './appliers/container-applier'\nimport { applyChildPositions } from './appliers/position-applier'\nimport type { LayoutStrategy } from './strategies/base-strategy'\nimport { ColumnLayoutStrategy } from './strategies/column-layout'\nimport { RowLayoutStrategy } from './strategies/row-layout'\nimport { StackLayoutStrategy } from './strategies/stack-layout'\nimport type { LayoutChild, LayoutContainer, LayoutContext, LayoutLine, Position } from './types'\nimport { getChildSize, getMargin, isLayoutChild, processNestedContainer } from './utils/child-utils'\nimport { calculateContainerSize, normalizePadding } from './utils/dimension-calculator'\nimport { distributeFlexSpace, hasFlexChildren } from './utils/flex-distributor'\nimport { clampSize, parseSize, resolveSize } from './utils/size-resolver'\nimport { calculateAlignItems, calculateJustifyContent } from './utils/spacing-calculator'\n\n// ---------------------------------------------------------------------------\n// Renderer-specific callbacks (injected by the renderer package)\n// ---------------------------------------------------------------------------\n\n/**\n * Callback to apply overflow clipping on a container.\n * Each renderer implements its own clipping mechanism (e.g., stencil buffer, scissor rect).\n */\nexport type ApplyOverflowClip = (\n container: LayoutContainer,\n containerProps: LayoutProps & {\n cornerRadius?: number | { tl?: number; tr?: number; bl?: number; br?: number }\n },\n width: number,\n height: number\n) => void\n\n/**\n * Callback invoked after layout dimensions are applied.\n * Used for renderer-specific post-layout operations (background drawing, hit areas).\n */\nexport type AfterLayoutCallback = (\n container: LayoutContainer,\n width: number,\n height: number\n) => void\n\nconst GLOBAL_NS = '@number10/jsx-core:layout'\nconst _overflowClipRegistryKey = Symbol.for(`${GLOBAL_NS}:overflowClipRegistry`)\nconst _onAfterLayoutKey = Symbol.for(`${GLOBAL_NS}:onAfterLayout`)\n\nfunction getOverflowClipRegistry(): ApplyOverflowClip[] {\n return getOrCreateGlobalValue(_overflowClipRegistryKey, () => [])\n}\n\nfunction getOnAfterLayout(): AfterLayoutCallback {\n return getGlobalValue<AfterLayoutCallback>(_onAfterLayoutKey) ?? noopAfterLayout\n}\n\nfunction setOnAfterLayout(fn: AfterLayoutCallback): void {\n setGlobalValue(_onAfterLayoutKey, fn)\n}\n\n/** No-op defaults — renderer must inject real implementations. */\nconst noopAfterLayout: AfterLayoutCallback = () => {}\n\n/**\n * Register a renderer-specific overflow clip implementation.\n * Multiple renderers can each register their own clip; the layout engine\n * tries each one until a handler accepts the container.\n * Prefer this over setApplyOverflowClip for multi-renderer setups.\n */\nexport function registerApplyOverflowClip(fn: ApplyOverflowClip): void {\n getOverflowClipRegistry().push(fn)\n}\n\n/**\n * Replace all registered overflow clip handlers with a single one.\n * For single-renderer setups. Equivalent to clearing the registry and registering one.\n * @deprecated Prefer registerApplyOverflowClip for multi-renderer safety.\n */\nexport function setApplyOverflowClip(fn: ApplyOverflowClip): void {\n const registry = getOverflowClipRegistry()\n registry.length = 0\n registry.push(fn)\n}\n\n/** Inject the renderer-specific after-layout callback (background, hit area). */\nexport function setAfterLayout(fn: AfterLayoutCallback): void {\n setOnAfterLayout(fn)\n}\n\n/**\n * Callback function for deferred layout updates\n * Executed after all layouts are complete in next frame\n */\ntype DeferredUpdateCallback = () => void\n\n/**\n * Central processor for deferred layout updates\n * Collects all updates that require final world coordinates or completed parent layouts\n * Executes them in batch via single requestAnimationFrame for optimal performance\n *\n * Use cases:\n * - Overflow mask positioning (needs world coordinates)\n * - Scroll position updates (needs final content size)\n * - Animation initialization (needs final positions)\n * - Custom effects requiring complete layout\n * - Gesture hit area updates (needs final layout size)\n */\nexport class DeferredLayoutQueue {\n private static callbacks: DeferredUpdateCallback[] = []\n private static scheduled = false\n\n /**\n * Schedule a callback to execute after current layout pass completes\n * All callbacks are batched and executed in single requestAnimationFrame\n * @param callback - Function to execute in next frame\n */\n static defer(callback: DeferredUpdateCallback): void {\n this.callbacks.push(callback)\n\n // Schedule flush if not already scheduled (only 1 requestAnimationFrame per frame)\n if (!this.scheduled) {\n this.scheduled = true\n requestAnimationFrame(() => this.flush())\n }\n }\n\n /**\n * Execute all pending callbacks in batch\n * Called once per frame via requestAnimationFrame\n */\n private static flush(): void {\n this.scheduled = false\n\n // Copy and clear callbacks before execution to prevent infinite loops\n const callbacks = [...this.callbacks]\n this.callbacks = []\n\n // Execute all callbacks with error isolation\n for (const callback of callbacks) {\n try {\n callback()\n } catch (error) {\n DebugLogger.error('DeferredLayoutQueue', 'Error in deferred callback:', error)\n }\n }\n }\n}\n\n/**\n * Entry for batched layout calculation\n */\ninterface LayoutBatchEntry {\n container: LayoutContainer\n containerProps: LayoutProps\n parentSize: { width: number; height: number } | undefined\n parentPadding: { horizontal: number; vertical: number } | undefined\n}\n\n/**\n * Batches layout calculations to reduce redundant recalculations\n * Prevents multiple calculations of same container within single synchronous call stack\n * Does NOT defer to next frame - executes immediately after current stack completes\n *\n * Benefits:\n * - Prevents multiple calculations of same container in one update\n * - Bottom-up execution order prevents redundant parent recalculations\n * - No visual flickering (executes in same frame)\n *\n * Usage:\n * - VDOM patches: LayoutBatchQueue.schedule() instead of direct calculateLayout()\n * - Appliers: LayoutBatchQueue.schedule() instead of direct calculateLayout()\n * - Tests: Set LayoutBatchQueue.synchronous = true for immediate execution\n */\nexport class LayoutBatchQueue {\n private static pending = new Map<LayoutContainer, LayoutBatchEntry>()\n private static scheduled = false\n\n /**\n * Enable synchronous mode for testing\n * When true, layouts execute immediately instead of batching\n */\n static synchronous = false\n\n /**\n * Schedule a layout calculation to execute after current call stack\n * Uses microtask (Promise) instead of requestAnimationFrame to avoid flickering\n * If container is already scheduled, updates entry with latest props\n * @param container - Container to calculate layout for\n * @param containerProps - Layout props\n * @param parentSize - Optional parent size for percentage resolution\n * @param parentPadding - Optional parent padding for fill resolution\n */\n static schedule(\n container: LayoutContainer,\n containerProps: LayoutProps,\n parentSize?: { width: number; height: number },\n parentPadding?: { horizontal: number; vertical: number }\n ): void {\n // Synchronous mode for tests - execute immediately\n if (this.synchronous) {\n calculateLayoutImmediate(container, containerProps, parentSize, parentPadding)\n return\n }\n\n // Update or add entry (latest props win if scheduled multiple times)\n this.pending.set(container, { container, containerProps, parentSize, parentPadding })\n\n // Schedule flush if not already scheduled\n // Use microtask (Promise.resolve) instead of requestAnimationFrame\n // This executes in SAME FRAME after current call stack, preventing flickering\n if (!this.scheduled) {\n this.scheduled = true\n Promise.resolve().then(() => this.flush())\n }\n }\n\n /**\n * Execute all pending layout calculations immediately\n * Processes in bottom-up order (deepest children first)\n * This prevents redundant parent recalculations\n */\n static flush(): void {\n this.scheduled = false\n\n if (this.pending.size === 0) return\n\n DebugLogger.time('performance', 'LayoutBatchQueue.flush')\n\n // Copy and clear pending entries\n const entries = Array.from(this.pending.values())\n this.pending.clear()\n\n // Sort bottom-up (deepest containers first)\n // This ensures children are laid out before parents\n entries.sort((a, b) => {\n const depthA = getContainerDepth(a.container)\n const depthB = getContainerDepth(b.container)\n return depthB - depthA // Higher depth = deeper = execute first\n })\n\n // Execute layout calculations in optimal order\n for (const entry of entries) {\n try {\n // Only calculate if container still exists, is visible, and not destroyed\n const node = entry.container as LayoutContainer & { destroyed?: boolean }\n if (node.destroyed === true) continue\n if (entry.container.visible === false) continue\n calculateLayoutImmediate(\n entry.container,\n entry.containerProps,\n entry.parentSize,\n entry.parentPadding\n )\n } catch (error) {\n DebugLogger.error('LayoutBatchQueue', 'Error calculating layout:', error)\n }\n }\n\n DebugLogger.timeEnd('performance', 'LayoutBatchQueue.flush')\n }\n}\n\n/**\n * Get depth of container in scene hierarchy by walking parent references.\n * Root containers have depth 0, children have depth 1, etc.\n * Requires LayoutNode.parent to be set by the VDOM / mount process.\n * @param container - Container to get depth for\n * @returns Depth level (0 = root)\n */\nfunction getContainerDepth(container: LayoutContainer): number {\n let depth = 0\n let current: LayoutContainer | undefined = getLayoutParent(container)\n\n while (current) {\n depth++\n current = getLayoutParent(current)\n }\n\n return depth\n}\n\nfunction getLayoutParent(container: LayoutContainer): LayoutContainer | undefined {\n if (container.__layoutParent) {\n return container.__layoutParent as LayoutContainer\n }\n\n if (container.parent) {\n return container.parent\n }\n\n // Phaser uses parentContainer instead of the renderer-neutral parent field.\n const parentContainer = (container as Record<string, unknown>).parentContainer\n if (parentContainer && typeof parentContainer === 'object') {\n return parentContainer as LayoutContainer\n }\n\n return undefined\n}\n\n/**\n * Applies overflow clipping via the renderer-injected callback.\n * Each renderer provides its own clipping implementation.\n */\nfunction applyOverflowMask(\n container: LayoutContainer,\n containerProps: LayoutProps & {\n cornerRadius?: number | { tl?: number; tr?: number; bl?: number; br?: number }\n },\n width: number,\n height: number\n): void {\n for (const clip of getOverflowClipRegistry()) {\n clip(container, containerProps, width, height)\n }\n}\n\n/**\n * Strategy map - reusable strategy instances\n */\nconst strategies: Record<string, LayoutStrategy> = {\n column: new ColumnLayoutStrategy(),\n row: new RowLayoutStrategy(),\n stack: new StackLayoutStrategy(),\n}\n\n/**\n * Invalidates parent layout if container size changed after recalculation\n * Propagates layout changes up the hierarchy to ensure parent containers adapt\n * @param container - Container that was just laid out\n * @param oldSize - Size before layout calculation\n * @param newWidth - New width after layout\n * @param newHeight - New height after layout\n */\ntype LayoutSize = { width: number; height: number }\ntype LayoutCycleState = {\n last: LayoutSize\n prev?: LayoutSize\n count: number\n lastTime: number\n}\n\nconst LAYOUT_CYCLE_EPSILON = 0.5\nconst LAYOUT_CYCLE_TIME_MS = 20\nconst LAYOUT_CYCLE_MAX = 5\nconst LAYOUT_MAX_SIZE = 200000\nconst layoutCycleGuard = new WeakMap<LayoutContainer, LayoutCycleState>()\nconst deferredParentInvalidations = new WeakSet<LayoutContainer>()\n\nfunction isCloseSize(a: LayoutSize, b: LayoutSize, epsilon: number): boolean {\n return Math.abs(a.width - b.width) < epsilon && Math.abs(a.height - b.height) < epsilon\n}\n\nfunction invalidateParentLayoutIfNeeded(\n container: LayoutContainer,\n oldSize: { width: number; height: number } | undefined,\n newWidth: number,\n newHeight: number\n): void {\n // Skip if no old size (first layout) or size unchanged\n if (\n !oldSize ||\n (Math.abs(oldSize.width - newWidth) < LAYOUT_CYCLE_EPSILON &&\n Math.abs(oldSize.height - newHeight) < LAYOUT_CYCLE_EPSILON)\n ) {\n return\n }\n\n if (\n !Number.isFinite(newWidth) ||\n !Number.isFinite(newHeight) ||\n newWidth > LAYOUT_MAX_SIZE ||\n newHeight > LAYOUT_MAX_SIZE\n ) {\n DebugLogger.warn('layout', 'Runaway layout size detected, skipping parent invalidation', {\n oldSize,\n newSize: { width: newWidth, height: newHeight },\n containerProps: container.__layoutProps,\n childCount: (container.list as unknown[])?.length ?? 0,\n })\n return\n }\n\n const newSize = { width: newWidth, height: newHeight }\n const now = Date.now()\n\n // Size changed - need to recalculate parent layout\n const parent = getLayoutParent(container) as\n | (LayoutContainer & {\n __layoutProps?: LayoutProps\n __getLayoutSize?: () => { width: number; height: number }\n })\n | undefined\n\n if (!parent || !parent.__layoutProps) {\n return // No layout parent to invalidate\n }\n\n const guard = layoutCycleGuard.get(container)\n if (guard) {\n const repeatsPrev = guard.prev ? isCloseSize(guard.prev, newSize, LAYOUT_CYCLE_EPSILON) : false\n if (repeatsPrev && now - guard.lastTime < LAYOUT_CYCLE_TIME_MS) {\n guard.count += 1\n } else {\n guard.count = 0\n }\n guard.prev = guard.last\n guard.last = newSize\n guard.lastTime = now\n layoutCycleGuard.set(container, guard)\n\n if (guard.count >= LAYOUT_CYCLE_MAX) {\n DebugLogger.log('layout', 'Layout cycle detected, deferring parent invalidation', {\n container,\n oldSize,\n newSize,\n })\n guard.count = 0\n guard.lastTime = 0\n layoutCycleGuard.set(container, guard)\n deferParentLayoutInvalidation(container)\n return\n }\n } else {\n layoutCycleGuard.set(container, {\n last: newSize,\n count: 0,\n lastTime: now,\n })\n }\n\n DebugLogger.log(\n 'layout',\n 'Container size changed, invalidating parent:',\n `${oldSize.width}x${oldSize.height} -> ${newWidth}x${newHeight}`\n )\n invalidateParentLayout(container)\n}\n\nfunction deferParentLayoutInvalidation(container: LayoutContainer): void {\n if (deferredParentInvalidations.has(container)) {\n return\n }\n\n deferredParentInvalidations.add(container)\n DeferredLayoutQueue.defer(() => {\n deferredParentInvalidations.delete(container)\n invalidateParentLayout(container)\n })\n}\n\nfunction invalidateParentLayout(container: LayoutContainer): void {\n const parent = getLayoutParent(container) as\n | (LayoutContainer & {\n __layoutProps?: LayoutProps\n __getLayoutSize?: () => { width: number; height: number }\n })\n | undefined\n\n if (!parent || !parent.__layoutProps) {\n return\n }\n\n const grandParent = getLayoutParent(parent) as\n | (LayoutContainer & {\n __layoutProps?: LayoutProps\n __getLayoutSize?: () => { width: number; height: number }\n })\n | undefined\n\n let grandParentSize: { width: number; height: number } | undefined\n if (grandParent && grandParent.__getLayoutSize) {\n const totalSize = grandParent.__getLayoutSize()\n const padding = (grandParent.__layoutProps?.padding ?? 0) as\n | number\n | { left?: number; right?: number; top?: number; bottom?: number }\n const normPadding =\n typeof padding === 'number'\n ? { left: padding, right: padding, top: padding, bottom: padding }\n : {\n left: padding.left ?? 0,\n right: padding.right ?? 0,\n top: padding.top ?? 0,\n bottom: padding.bottom ?? 0,\n }\n grandParentSize = {\n width: totalSize.width - normPadding.left - normPadding.right,\n height: totalSize.height - normPadding.top - normPadding.bottom,\n }\n }\n\n calculateLayout(parent, parent.__layoutProps, grandParentSize)\n}\n\n/**\n * Calculate layout for a container and its children immediately (internal)\n * DO NOT CALL DIRECTLY - Use calculateLayout() which batches for performance\n * @param container - Phaser container with children\n * @param containerProps - Layout props of the container\n * @param parentSize - Optional parent dimensions for percentage resolution\n * @param parentPadding - Optional parent padding for 'fill' resolution\n */\nfunction calculateLayoutImmediate(\n container: LayoutContainer,\n containerProps: LayoutProps,\n parentSize?: { width: number; height: number },\n parentPadding?: { horizontal: number; vertical: number }\n): void {\n const children = (container.list ?? []) as LayoutContainer[]\n\n // Store old size before layout calculation for parent invalidation\n const containerWithLayout = container as typeof container & {\n __getLayoutSize?: () => { width: number; height: number }\n }\n const oldContainerSize = containerWithLayout.__getLayoutSize?.()\n\n // Debug: Track excessive layout calls\n // console.log('[LAYOUT] calculateLayout called for container with', children?.length ?? 0, 'children')\n\n if (!children || !Array.isArray(children)) {\n return\n }\n\n // Performance timing\n DebugLogger.time('performance', 'calculateLayout')\n\n // 1. Extract layout parameters\n const direction = containerProps.direction ?? 'column'\n const padding = normalizePadding(containerProps.padding)\n const gap = normalizeGap(containerProps.gap)\n const justifyContent = containerProps.justifyContent ?? 'start'\n\n DebugLogger.log('layout', `Direction: ${direction}, Padding:`, padding)\n\n // 2a. Pre-calculate container size if possible (needed for percentage children and nested containers)\n // This allows percentage-based child sizes to resolve correctly and nested containers\n // to receive the correct content-area as their parent size\n let currentContainerSize: { width: number; height: number } | undefined\n\n // Try to calculate width early if we have explicit width or can resolve from parent\n const parsedWidth = parseSize(containerProps.width)\n const canCalculateWidth =\n parsedWidth.type === 'fixed' ||\n (parentSize?.width !== undefined &&\n (parsedWidth.type === 'percent' ||\n parsedWidth.type === 'fill' ||\n parsedWidth.type === 'calc'))\n\n const width = canCalculateWidth\n ? resolveSize(parsedWidth, parentSize?.width, container.width, parentPadding?.horizontal)\n : undefined\n\n // Try to calculate height early if we have explicit height or can resolve from parent\n const parsedHeight = parseSize(containerProps.height)\n const canCalculateHeight =\n parsedHeight.type === 'fixed' ||\n (parentSize?.height !== undefined &&\n (parsedHeight.type === 'percent' ||\n parsedHeight.type === 'fill' ||\n parsedHeight.type === 'calc'))\n\n const height = canCalculateHeight\n ? resolveSize(parsedHeight, parentSize?.height, container.height, parentPadding?.vertical)\n : undefined\n\n // Set currentContainerSize if we could calculate at least one dimension\n if (width !== undefined || height !== undefined) {\n // Apply constraints\n const clampedWidth =\n width !== undefined\n ? clampSize(\n width,\n containerProps.minWidth,\n containerProps.maxWidth,\n parentSize?.width,\n container.width,\n parentPadding?.horizontal\n )\n : (container.width ?? 0)\n const clampedHeight =\n height !== undefined\n ? clampSize(\n height,\n containerProps.minHeight,\n containerProps.maxHeight,\n parentSize?.height,\n container.height,\n parentPadding?.vertical\n )\n : (container.height ?? 0)\n\n currentContainerSize = {\n width: clampedWidth,\n height: clampedHeight,\n }\n }\n\n // Calculate available content size (container minus padding) for child size resolution\n // This allows 'fill' and percentage sizes to resolve correctly relative to content area\n const availableContentSize = currentContainerSize\n ? {\n width: currentContainerSize.width - padding.left - padding.right,\n height: currentContainerSize.height - padding.top - padding.bottom,\n }\n : undefined\n\n DebugLogger.log('layout', 'Pre-calculated container size:', currentContainerSize)\n DebugLogger.log('layout', 'Available content size (for fill):', availableContentSize)\n\n // 2. Prepare layout children (filter backgrounds, headless objects, process nested containers)\n const layoutChildren: LayoutChild[] = []\n\n for (const child of children) {\n // Skip non-layout children (backgrounds, headless objects, missing __getLayoutSize)\n if (!isLayoutChild(child)) {\n DebugLogger.log('layout', 'Skipping non-layout child:', {\n isBackground: child.__isBackground,\n headless: child.__layoutProps?.headless,\n hasLayoutSize: typeof child.__getLayoutSize === 'function',\n })\n continue\n } // Skip processing nested containers with flex (they need parent size first)\n const hasFlex = (child.__layoutProps?.flex ?? 0) > 0\n if (!hasFlex) {\n // Process nested containers - pass content-area (size minus padding) as parent size\n // This ensures nested children see the correct available space\n const parentSizeForNested = currentContainerSize\n ? {\n width: currentContainerSize.width - padding.left - padding.right,\n height: currentContainerSize.height - padding.top - padding.bottom,\n }\n : parentSize\n ? {\n width: parentSize.width - (parentPadding?.horizontal ?? 0),\n height: parentSize.height - (parentPadding?.vertical ?? 0),\n }\n : undefined\n\n processNestedContainer(\n child,\n calculateLayout,\n parentSizeForNested,\n undefined // No padding offset needed since we pass content-area\n )\n }\n\n // Get child size - pass content-area (container size minus padding) for % and fill\n // This way percentages and fill are relative to available content space\n const contentAreaForChild = currentContainerSize\n ? {\n width: currentContainerSize.width - padding.left - padding.right,\n height: currentContainerSize.height - padding.top - padding.bottom,\n }\n : parentSize\n ? {\n width: parentSize.width - (parentPadding?.horizontal ?? 0),\n height: parentSize.height - (parentPadding?.vertical ?? 0),\n }\n : undefined\n\n const size = getChildSize(child, contentAreaForChild, undefined)\n const margin = getMargin(child)\n\n layoutChildren.push({ child, size, margin })\n }\n\n // 3. Select strategy based on direction\n const strategy = strategies[direction]\n if (!strategy) {\n DebugLogger.error('Layout', `Unknown direction: ${direction}`)\n return\n }\n\n // 4. Build layout context (will be used after we know container dimensions)\n const contextPartial = {\n containerProps,\n padding,\n gap,\n children: layoutChildren,\n }\n\n // 5. Calculate metrics using strategy\n const metrics = strategy.calculateMetrics(layoutChildren, contextPartial as LayoutContext)\n\n // 5a. Check if wrapping is enabled\n const flexWrap = containerProps.flexWrap ?? 'nowrap'\n const shouldWrap = flexWrap !== 'nowrap' && direction !== 'stack'\n\n // 6. Calculate container dimensions (with parent size and padding for resolution)\n const { width: containerWidth, height: containerHeight } = calculateContainerSize(\n containerProps,\n metrics,\n padding,\n direction,\n gap,\n layoutChildren.length,\n parentSize,\n parentPadding\n )\n\n // 6a. Distribute flex space if there are flex children (skip if wrapping - will be done per line)\n let finalLayoutChildren = layoutChildren\n if (hasFlexChildren(layoutChildren) && !shouldWrap) {\n const contentSize =\n direction === 'row'\n ? containerWidth - padding.left - padding.right\n : containerHeight - padding.top - padding.bottom\n\n // Subtract gap space (gap appears between children, so n-1 gaps for n children)\n const gapValue = direction === 'row' ? gap.horizontal : gap.vertical\n const totalGapSpace = layoutChildren.length > 1 ? gapValue * (layoutChildren.length - 1) : 0\n const availableMainSpace = contentSize - totalGapSpace\n\n finalLayoutChildren = distributeFlexSpace(layoutChildren, availableMainSpace, direction)\n\n // Process nested flex containers now that they have their size\n for (const layoutChild of finalLayoutChildren) {\n const props = layoutChild.child.__layoutProps\n const isFlexItem =\n (props?.flex !== undefined && props.flex > 0) ||\n props?.flexShrink !== undefined ||\n props?.flexBasis !== undefined\n if (isFlexItem) {\n // Temporarily set explicit size based on flex calculation\n const originalProps = { ...layoutChild.child.__layoutProps }\n if (direction === 'row') {\n layoutChild.child.__layoutProps = {\n ...layoutChild.child.__layoutProps,\n width: layoutChild.size.width,\n }\n } else {\n layoutChild.child.__layoutProps = {\n ...layoutChild.child.__layoutProps,\n height: layoutChild.size.height,\n }\n }\n\n processNestedContainer(\n layoutChild.child,\n calculateLayout,\n {\n width: containerWidth,\n height: containerHeight,\n },\n {\n horizontal: padding.left + padding.right,\n vertical: padding.top + padding.bottom,\n }\n )\n\n // Restore original props\n layoutChild.child.__layoutProps = originalProps\n }\n }\n\n // Recalculate metrics with updated sizes\n const updatedMetrics = strategy.calculateMetrics(\n finalLayoutChildren,\n contextPartial as LayoutContext\n )\n metrics.totalMainSize = updatedMetrics.totalMainSize\n if (direction === 'column') {\n metrics.maxWidth = updatedMetrics.maxWidth\n } else if (direction === 'row') {\n metrics.maxHeight = updatedMetrics.maxHeight\n }\n }\n\n // 7. Calculate content area\n const contentArea = {\n width: containerWidth - padding.left - padding.right,\n height: containerHeight - padding.top - padding.bottom,\n }\n\n // 8. Complete layout context\n const context: LayoutContext = {\n ...contextPartial,\n children: finalLayoutChildren,\n contentArea,\n parentSize: {\n width: containerWidth,\n height: containerHeight,\n },\n }\n\n // 9. Calculate spacing for justifyContent\n const availableMainSpace = direction === 'row' ? contentArea.width : contentArea.height\n // Calculate total gap space (gaps between children, not before first or after last)\n const gapValue = direction === 'row' ? gap.horizontal : gap.vertical\n const totalGapSpace =\n finalLayoutChildren.length > 1 ? gapValue * (finalLayoutChildren.length - 1) : 0\n const remainingSpace = availableMainSpace - metrics.totalMainSize - totalGapSpace\n\n let mainStart = 0\n let spaceBetween = 0\n\n // For stack direction, justifyContent is not applicable\n if (direction !== 'stack') {\n const justifyResult = calculateJustifyContent(\n justifyContent,\n remainingSpace,\n finalLayoutChildren.length\n )\n mainStart = justifyResult.mainStart\n spaceBetween = justifyResult.spaceBetween\n }\n\n // 9a. Apply stretch if alignItems is 'stretch'\n const alignItems = containerProps.alignItems ?? 'start'\n if (alignItems === 'stretch' && direction !== 'stack') {\n for (const layoutChild of finalLayoutChildren) {\n const margin = getMargin(layoutChild.child)\n const child = layoutChild.child\n\n if (direction === 'row') {\n // Stretch height to full cross-axis (minus margins)\n const stretchHeight = contentArea.height - (margin.top ?? 0) - (margin.bottom ?? 0)\n layoutChild.size.height = Math.max(0, stretchHeight)\n\n // If child is a container with layout props, update its height prop and recalculate nested layout\n if (child.__layoutProps) {\n const originalHeight = child.__layoutProps.height\n child.__layoutProps = { ...child.__layoutProps, height: stretchHeight }\n\n // Recalculate nested container layout with new height\n processNestedContainer(child, calculateLayout, {\n width: containerWidth,\n height: containerHeight,\n })\n\n // Restore original height prop (in case it was percentage or undefined)\n child.__layoutProps = { ...child.__layoutProps, height: originalHeight }\n }\n } else if (direction === 'column') {\n // Stretch width to full cross-axis (minus margins)\n const stretchWidth = contentArea.width - (margin.left ?? 0) - (margin.right ?? 0)\n layoutChild.size.width = Math.max(0, stretchWidth)\n\n // If child is a container with layout props, update its width prop and recalculate nested layout\n if (child.__layoutProps) {\n const originalWidth = child.__layoutProps.width\n child.__layoutProps = { ...child.__layoutProps, width: stretchWidth }\n\n // Recalculate nested container layout with new width\n processNestedContainer(child, calculateLayout, {\n width: containerWidth,\n height: containerHeight,\n })\n\n // Restore original width prop (in case it was percentage or undefined)\n child.__layoutProps = { ...child.__layoutProps, width: originalWidth }\n }\n }\n }\n }\n\n // 10. Handle wrapping if enabled\n const positions: Position[] = []\n let adjustedContainerWidth = containerWidth\n let adjustedContainerHeight = containerHeight\n\n if (shouldWrap && 'wrapChildren' in strategy) {\n // Wrap children into multiple lines\n const availableMainSize = direction === 'row' ? contentArea.width : contentArea.height\n const mainGapValue = direction === 'row' ? gap.horizontal : gap.vertical\n const lines = (strategy as RowLayoutStrategy | ColumnLayoutStrategy).wrapChildren(\n finalLayoutChildren,\n availableMainSize,\n mainGapValue\n )\n\n if (flexWrap === 'wrap-reverse') {\n lines.reverse()\n }\n\n // Calculate total cross size needed for all lines\n const totalCrossSize = lines.reduce(\n (sum: number, line: LayoutLine) => sum + line.crossAxisSize,\n 0\n )\n const crossGapValue = direction === 'row' ? gap.vertical : gap.horizontal\n const totalLineGaps = (lines.length - 1) * crossGapValue\n\n // Adjust container dimensions if auto-sizing and wrapping occurred\n if (\n direction === 'row' &&\n (containerProps.height === undefined || containerProps.height === 'auto')\n ) {\n // For row direction with auto-height, calculate height based on wrapped lines\n adjustedContainerHeight = totalCrossSize + totalLineGaps + padding.top + padding.bottom\n } else if (\n direction === 'column' &&\n (containerProps.width === undefined || containerProps.width === 'auto')\n ) {\n // For column direction with auto-width, calculate width based on wrapped lines\n adjustedContainerWidth = totalCrossSize + totalLineGaps + padding.left + padding.right\n }\n\n const availableCrossSize = direction === 'row' ? contentArea.height : contentArea.width\n const freeCrossSpace = availableCrossSize - totalCrossSize - totalLineGaps\n\n // Apply alignContent to distribute lines\n const alignContent = containerProps.alignContent ?? 'stretch'\n let crossOffset = 0\n let lineCrossSpacing = 0\n\n if (alignContent === 'center') {\n crossOffset = freeCrossSpace / 2\n } else if (alignContent === 'end') {\n crossOffset = freeCrossSpace\n } else if (alignContent === 'space-between' && lines.length > 1) {\n lineCrossSpacing = freeCrossSpace / (lines.length - 1)\n } else if (alignContent === 'space-around') {\n lineCrossSpacing = freeCrossSpace / lines.length\n crossOffset = lineCrossSpacing / 2\n }\n\n // Position children line by line\n for (const line of lines) {\n // Apply flex distribution per line if line has flex children\n let lineChildren = line.children\n if (hasFlexChildren(line.children)) {\n const lineGapSpace = (line.children.length - 1) * mainGapValue\n const lineAvailableSpace = availableMainSize - lineGapSpace\n lineChildren = distributeFlexSpace(line.children, lineAvailableSpace, direction)\n\n // Update line main size after flex distribution\n line.mainAxisSize = lineChildren.reduce((sum: number, child: LayoutChild) => {\n const size = direction === 'row' ? child.size.width : child.size.height\n const margin = getMargin(child.child)\n const marginSize =\n direction === 'row'\n ? (margin.left ?? 0) + (margin.right ?? 0)\n : (margin.top ?? 0) + (margin.bottom ?? 0)\n return sum + size + marginSize\n }, 0)\n }\n\n // Calculate line-specific justifyContent\n const lineMainSize = line.mainAxisSize\n const lineAvailableMain = availableMainSize\n const lineRemainingSpace = lineAvailableMain - lineMainSize\n const lineGapSpace = (line.children.length - 1) * mainGapValue\n const lineFreeSpace = lineRemainingSpace - lineGapSpace\n\n const lineJustifyResult = calculateJustifyContent(\n justifyContent,\n lineFreeSpace,\n line.children.length\n )\n\n let lineMainOffset = lineJustifyResult.mainStart\n const lineSpaceBetween = lineJustifyResult.spaceBetween\n\n // Position each child in the line\n for (let i = 0; i < lineChildren.length; i++) {\n const child = lineChildren[i]\n if (!child) continue\n\n const margin = getMargin(child.child)\n\n let x: number\n let y: number\n\n if (direction === 'row') {\n // Main axis: horizontal\n lineMainOffset += margin.left ?? 0\n x = padding.left + lineMainOffset\n\n // Cross axis: vertical\n const childCrossOffset = calculateAlignItems(\n alignItems,\n line.crossAxisSize,\n child.size.height,\n margin.top ?? 0,\n margin.bottom ?? 0\n )\n y = padding.top + crossOffset + childCrossOffset\n\n lineMainOffset += child.size.width + (margin.right ?? 0)\n if (i < lineChildren.length - 1) {\n lineMainOffset += mainGapValue + lineSpaceBetween\n }\n } else {\n // Main axis: vertical\n lineMainOffset += margin.top ?? 0\n y = padding.top + lineMainOffset\n\n // Cross axis: horizontal\n const childCrossOffset = calculateAlignItems(\n alignItems,\n line.crossAxisSize,\n child.size.width,\n margin.left ?? 0,\n margin.right ?? 0\n )\n x = padding.left + crossOffset + childCrossOffset\n\n lineMainOffset += child.size.height + (margin.bottom ?? 0)\n if (i < lineChildren.length - 1) {\n lineMainOffset += mainGapValue + lineSpaceBetween\n }\n }\n\n // Find child index in original array for correct position assignment\n const childIndex = finalLayoutChildren.indexOf(child)\n if (childIndex !== -1) {\n positions[childIndex] = { x, y }\n }\n }\n\n // Move to next line\n crossOffset += line.crossAxisSize + crossGapValue + lineCrossSpacing\n }\n } else {\n // No wrapping - use original single-line positioning\n let currentMain = mainStart\n\n for (let i = 0; i < finalLayoutChildren.length; i++) {\n const child = finalLayoutChildren[i]\n if (!child) continue\n\n const result = strategy.positionChild(child, i, context, currentMain)\n\n positions.push(result.position)\n currentMain = result.nextMain\n\n // Add gap and space-between spacing (not for stack)\n if (direction !== 'stack' && i < finalLayoutChildren.length - 1) {\n currentMain += gapValue + spaceBetween\n }\n }\n }\n\n // 11. Apply positions to children\n applyChildPositions(finalLayoutChildren, positions)\n\n // 12. Apply container dimensions (use adjusted dimensions if wrapping changed them)\n applyContainerDimensions(container, adjustedContainerWidth, adjustedContainerHeight)\n\n // 13. Invoke after-layout callback (renderer-specific: background, hit area)\n getOnAfterLayout()(container, adjustedContainerWidth, adjustedContainerHeight)\n\n // 14. Apply overflow mask if needed\n applyOverflowMask(container, containerProps, adjustedContainerWidth, adjustedContainerHeight)\n\n // End performance timing\n DebugLogger.timeEnd('performance', 'calculateLayout')\n\n // 15. Propagate layout changes to parent if size changed\n // This ensures parent containers resize when child content changes\n invalidateParentLayoutIfNeeded(\n container,\n oldContainerSize,\n adjustedContainerWidth,\n adjustedContainerHeight\n )\n}\n\n/**\n * Calculate layout for a container and its children\n * Batches layout calculations for optimal performance\n * Multiple calls within same frame are deduplicated and executed bottom-up\n * @param container - Phaser container with children\n * @param containerProps - Layout props of the container\n * @param parentSize - Optional parent dimensions for percentage resolution\n * @param parentPadding - Optional parent padding for 'fill' resolution\n */\n/**\n * Main entry point for layout calculation.\n *\n * @param container - Container node to layout (satisfies LayoutContainer via duck-typing)\n * @param containerProps - Layout properties\n * @param parentSize - Parent dimensions for percentage/fill resolution (optional)\n * @param parentPadding - Parent padding for fill resolution (optional)\n *\n * @migration(audit:scene-portal-mount) Phase 2 — LayoutContainer replaces Phaser.GameObjects.Container\n */\nexport function calculateLayout(\n container: LayoutContainer,\n containerProps: LayoutProps,\n parentSize?: { width: number; height: number },\n parentPadding?: { horizontal: number; vertical: number }\n): void {\n LayoutBatchQueue.schedule(container, containerProps, parentSize, parentPadding)\n}\n"],"names":["gapValue","totalGapSpace","availableMainSpace","lineGapSpace"],"mappings":"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"}
@@ -0,0 +1,31 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
+ class BaseLayoutStrategy {
4
+ /**
5
+ * Helper: Normalize margin values
6
+ * @param child - Layout child
7
+ * @returns Normalized margin values
8
+ */
9
+ getMarginValues(child) {
10
+ return {
11
+ top: child.margin.top ?? 0,
12
+ right: child.margin.right ?? 0,
13
+ bottom: child.margin.bottom ?? 0,
14
+ left: child.margin.left ?? 0
15
+ };
16
+ }
17
+ /**
18
+ * Helper: Calculate total child size including margins
19
+ * @param child - Layout child
20
+ * @returns Total width and height including margins
21
+ */
22
+ getTotalChildSize(child) {
23
+ const margin = this.getMarginValues(child);
24
+ return {
25
+ width: margin.left + child.size.width + margin.right,
26
+ height: margin.top + child.size.height + margin.bottom
27
+ };
28
+ }
29
+ }
30
+ exports.BaseLayoutStrategy = BaseLayoutStrategy;
31
+ //# sourceMappingURL=base-strategy.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"base-strategy.cjs","sources":["../../../src/layout/strategies/base-strategy.ts"],"sourcesContent":["/**\n * Base strategy interface for layout algorithms\n * Defines the contract for all layout strategies\n */\nimport type { LayoutChild, LayoutContext, Position } from '../types'\nimport type { ContentMetrics } from '../utils/dimension-calculator'\n\n/**\n * Layout strategy interface\n * Each direction (row, column, stack) implements this interface\n */\nexport interface LayoutStrategy {\n /**\n * Calculate content dimensions for this layout strategy\n * @param children - Array of layout children\n * @param context - Layout context\n * @returns Content metrics (maxWidth, maxHeight, totalMainSize)\n */\n calculateMetrics(children: LayoutChild[], context: LayoutContext): ContentMetrics\n\n /**\n * Calculate position for a child at given index\n * @param child - Layout child\n * @param index - Child index\n * @param context - Layout context\n * @param currentMain - Current position on main axis\n * @returns Position (x, y) and updated currentMain value\n */\n positionChild(\n child: LayoutChild,\n index: number,\n context: LayoutContext,\n currentMain: number\n ): { position: Position; nextMain: number }\n}\n\n/**\n * Abstract base class for layout strategies\n * Provides common functionality for all strategies\n */\nexport abstract class BaseLayoutStrategy implements LayoutStrategy {\n abstract calculateMetrics(children: LayoutChild[], context: LayoutContext): ContentMetrics\n\n abstract positionChild(\n child: LayoutChild,\n index: number,\n context: LayoutContext,\n currentMain: number\n ): { position: Position; nextMain: number }\n\n /**\n * Helper: Normalize margin values\n * @param child - Layout child\n * @returns Normalized margin values\n */\n protected getMarginValues(child: LayoutChild) {\n return {\n top: child.margin.top ?? 0,\n right: child.margin.right ?? 0,\n bottom: child.margin.bottom ?? 0,\n left: child.margin.left ?? 0,\n }\n }\n\n /**\n * Helper: Calculate total child size including margins\n * @param child - Layout child\n * @returns Total width and height including margins\n */\n protected getTotalChildSize(child: LayoutChild) {\n const margin = this.getMarginValues(child)\n return {\n width: margin.left + child.size.width + margin.right,\n height: margin.top + child.size.height + margin.bottom,\n }\n }\n}\n"],"names":[],"mappings":";;AAwCO,MAAe,mBAA6C;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAevD,gBAAgB,OAAoB;AAC5C,WAAO;AAAA,MACL,KAAK,MAAM,OAAO,OAAO;AAAA,MACzB,OAAO,MAAM,OAAO,SAAS;AAAA,MAC7B,QAAQ,MAAM,OAAO,UAAU;AAAA,MAC/B,MAAM,MAAM,OAAO,QAAQ;AAAA,IAAA;AAAA,EAE/B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOU,kBAAkB,OAAoB;AAC9C,UAAM,SAAS,KAAK,gBAAgB,KAAK;AACzC,WAAO;AAAA,MACL,OAAO,OAAO,OAAO,MAAM,KAAK,QAAQ,OAAO;AAAA,MAC/C,QAAQ,OAAO,MAAM,MAAM,KAAK,SAAS,OAAO;AAAA,IAAA;AAAA,EAEpD;AACF;;"}
@@ -0,0 +1,59 @@
1
+ import { LayoutChild, LayoutContext, Position } from '../types';
2
+ import { ContentMetrics } from '../utils/dimension-calculator';
3
+ /**
4
+ * Layout strategy interface
5
+ * Each direction (row, column, stack) implements this interface
6
+ */
7
+ export interface LayoutStrategy {
8
+ /**
9
+ * Calculate content dimensions for this layout strategy
10
+ * @param children - Array of layout children
11
+ * @param context - Layout context
12
+ * @returns Content metrics (maxWidth, maxHeight, totalMainSize)
13
+ */
14
+ calculateMetrics(children: LayoutChild[], context: LayoutContext): ContentMetrics;
15
+ /**
16
+ * Calculate position for a child at given index
17
+ * @param child - Layout child
18
+ * @param index - Child index
19
+ * @param context - Layout context
20
+ * @param currentMain - Current position on main axis
21
+ * @returns Position (x, y) and updated currentMain value
22
+ */
23
+ positionChild(child: LayoutChild, index: number, context: LayoutContext, currentMain: number): {
24
+ position: Position;
25
+ nextMain: number;
26
+ };
27
+ }
28
+ /**
29
+ * Abstract base class for layout strategies
30
+ * Provides common functionality for all strategies
31
+ */
32
+ export declare abstract class BaseLayoutStrategy implements LayoutStrategy {
33
+ abstract calculateMetrics(children: LayoutChild[], context: LayoutContext): ContentMetrics;
34
+ abstract positionChild(child: LayoutChild, index: number, context: LayoutContext, currentMain: number): {
35
+ position: Position;
36
+ nextMain: number;
37
+ };
38
+ /**
39
+ * Helper: Normalize margin values
40
+ * @param child - Layout child
41
+ * @returns Normalized margin values
42
+ */
43
+ protected getMarginValues(child: LayoutChild): {
44
+ top: number;
45
+ right: number;
46
+ bottom: number;
47
+ left: number;
48
+ };
49
+ /**
50
+ * Helper: Calculate total child size including margins
51
+ * @param child - Layout child
52
+ * @returns Total width and height including margins
53
+ */
54
+ protected getTotalChildSize(child: LayoutChild): {
55
+ width: number;
56
+ height: number;
57
+ };
58
+ }
59
+ //# sourceMappingURL=base-strategy.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"base-strategy.d.ts","sourceRoot":"","sources":["../../../src/layout/strategies/base-strategy.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,KAAK,EAAE,WAAW,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAA;AACpE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,+BAA+B,CAAA;AAEnE;;;GAGG;AACH,MAAM,WAAW,cAAc;IAC7B;;;;;OAKG;IACH,gBAAgB,CAAC,QAAQ,EAAE,WAAW,EAAE,EAAE,OAAO,EAAE,aAAa,GAAG,cAAc,CAAA;IAEjF;;;;;;;OAOG;IACH,aAAa,CACX,KAAK,EAAE,WAAW,EAClB,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,aAAa,EACtB,WAAW,EAAE,MAAM,GAClB;QAAE,QAAQ,EAAE,QAAQ,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAA;CAC5C;AAED;;;GAGG;AACH,8BAAsB,kBAAmB,YAAW,cAAc;IAChE,QAAQ,CAAC,gBAAgB,CAAC,QAAQ,EAAE,WAAW,EAAE,EAAE,OAAO,EAAE,aAAa,GAAG,cAAc;IAE1F,QAAQ,CAAC,aAAa,CACpB,KAAK,EAAE,WAAW,EAClB,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,aAAa,EACtB,WAAW,EAAE,MAAM,GAClB;QAAE,QAAQ,EAAE,QAAQ,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE;IAE3C;;;;OAIG;IACH,SAAS,CAAC,eAAe,CAAC,KAAK,EAAE,WAAW;;;;;;IAS5C;;;;OAIG;IACH,SAAS,CAAC,iBAAiB,CAAC,KAAK,EAAE,WAAW;;;;CAO/C"}
@@ -0,0 +1,31 @@
1
+ class BaseLayoutStrategy {
2
+ /**
3
+ * Helper: Normalize margin values
4
+ * @param child - Layout child
5
+ * @returns Normalized margin values
6
+ */
7
+ getMarginValues(child) {
8
+ return {
9
+ top: child.margin.top ?? 0,
10
+ right: child.margin.right ?? 0,
11
+ bottom: child.margin.bottom ?? 0,
12
+ left: child.margin.left ?? 0
13
+ };
14
+ }
15
+ /**
16
+ * Helper: Calculate total child size including margins
17
+ * @param child - Layout child
18
+ * @returns Total width and height including margins
19
+ */
20
+ getTotalChildSize(child) {
21
+ const margin = this.getMarginValues(child);
22
+ return {
23
+ width: margin.left + child.size.width + margin.right,
24
+ height: margin.top + child.size.height + margin.bottom
25
+ };
26
+ }
27
+ }
28
+ export {
29
+ BaseLayoutStrategy
30
+ };
31
+ //# sourceMappingURL=base-strategy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"base-strategy.js","sources":["../../../src/layout/strategies/base-strategy.ts"],"sourcesContent":["/**\n * Base strategy interface for layout algorithms\n * Defines the contract for all layout strategies\n */\nimport type { LayoutChild, LayoutContext, Position } from '../types'\nimport type { ContentMetrics } from '../utils/dimension-calculator'\n\n/**\n * Layout strategy interface\n * Each direction (row, column, stack) implements this interface\n */\nexport interface LayoutStrategy {\n /**\n * Calculate content dimensions for this layout strategy\n * @param children - Array of layout children\n * @param context - Layout context\n * @returns Content metrics (maxWidth, maxHeight, totalMainSize)\n */\n calculateMetrics(children: LayoutChild[], context: LayoutContext): ContentMetrics\n\n /**\n * Calculate position for a child at given index\n * @param child - Layout child\n * @param index - Child index\n * @param context - Layout context\n * @param currentMain - Current position on main axis\n * @returns Position (x, y) and updated currentMain value\n */\n positionChild(\n child: LayoutChild,\n index: number,\n context: LayoutContext,\n currentMain: number\n ): { position: Position; nextMain: number }\n}\n\n/**\n * Abstract base class for layout strategies\n * Provides common functionality for all strategies\n */\nexport abstract class BaseLayoutStrategy implements LayoutStrategy {\n abstract calculateMetrics(children: LayoutChild[], context: LayoutContext): ContentMetrics\n\n abstract positionChild(\n child: LayoutChild,\n index: number,\n context: LayoutContext,\n currentMain: number\n ): { position: Position; nextMain: number }\n\n /**\n * Helper: Normalize margin values\n * @param child - Layout child\n * @returns Normalized margin values\n */\n protected getMarginValues(child: LayoutChild) {\n return {\n top: child.margin.top ?? 0,\n right: child.margin.right ?? 0,\n bottom: child.margin.bottom ?? 0,\n left: child.margin.left ?? 0,\n }\n }\n\n /**\n * Helper: Calculate total child size including margins\n * @param child - Layout child\n * @returns Total width and height including margins\n */\n protected getTotalChildSize(child: LayoutChild) {\n const margin = this.getMarginValues(child)\n return {\n width: margin.left + child.size.width + margin.right,\n height: margin.top + child.size.height + margin.bottom,\n }\n }\n}\n"],"names":[],"mappings":"AAwCO,MAAe,mBAA6C;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAevD,gBAAgB,OAAoB;AAC5C,WAAO;AAAA,MACL,KAAK,MAAM,OAAO,OAAO;AAAA,MACzB,OAAO,MAAM,OAAO,SAAS;AAAA,MAC7B,QAAQ,MAAM,OAAO,UAAU;AAAA,MAC/B,MAAM,MAAM,OAAO,QAAQ;AAAA,IAAA;AAAA,EAE/B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOU,kBAAkB,OAAoB;AAC9C,UAAM,SAAS,KAAK,gBAAgB,KAAK;AACzC,WAAO;AAAA,MACL,OAAO,OAAO,OAAO,MAAM,KAAK,QAAQ,OAAO;AAAA,MAC/C,QAAQ,OAAO,MAAM,MAAM,KAAK,SAAS,OAAO;AAAA,IAAA;AAAA,EAEpD;AACF;"}
@@ -0,0 +1,145 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
+ const sizeResolver = require("../utils/size-resolver.cjs");
4
+ const spacingCalculator = require("../utils/spacing-calculator.cjs");
5
+ const baseStrategy = require("./base-strategy.cjs");
6
+ class ColumnLayoutStrategy extends baseStrategy.BaseLayoutStrategy {
7
+ /**
8
+ * Calculate content dimensions for column layout
9
+ * For flex children, uses a minimum default size to avoid chicken-egg sizing issues
10
+ * @param children - Array of layout children
11
+ * @param context - Layout context
12
+ * @returns Content metrics
13
+ */
14
+ calculateMetrics(children, _context) {
15
+ const FLEX_CHILD_MIN_SIZE = 100;
16
+ let maxWidth = 0;
17
+ let totalMainSize = 0;
18
+ for (const child of children) {
19
+ const total = this.getTotalChildSize(child);
20
+ maxWidth = Math.max(maxWidth, total.width);
21
+ const props = child.child.__layoutProps;
22
+ const isFlexItem = props?.flex !== void 0 && props.flex > 0 || props?.flexShrink !== void 0 || props?.flexBasis !== void 0;
23
+ const childHeight = isFlexItem && child.size.height <= 10 ? FLEX_CHILD_MIN_SIZE : total.height;
24
+ totalMainSize += childHeight;
25
+ }
26
+ return {
27
+ maxWidth,
28
+ maxHeight: 0,
29
+ // Not used for column
30
+ totalMainSize
31
+ };
32
+ }
33
+ /**
34
+ * Position a child in column layout
35
+ * @param child - Layout child
36
+ * @param _index - Child index (unused for column layout)
37
+ * @param context - Layout context
38
+ * @param currentMain - Current Y position
39
+ * @returns Position and next main axis value
40
+ */
41
+ positionChild(child, _index, context, currentMain) {
42
+ const margin = this.getMarginValues(child);
43
+ const isHeadless = child.child.__layoutProps?.headless;
44
+ let x;
45
+ let y;
46
+ let nextMain;
47
+ if (isHeadless) {
48
+ const parentWidth = context.parentSize?.width ?? context.contentArea.width;
49
+ const parentHeight = context.parentSize?.height ?? context.contentArea.height;
50
+ const justify = context.containerProps.justifyContent ?? "start";
51
+ let mainAxisOffset = 0;
52
+ if (justify === "center") {
53
+ mainAxisOffset = (parentHeight - child.size.height) / 2;
54
+ } else if (justify === "end") {
55
+ mainAxisOffset = parentHeight - child.size.height;
56
+ }
57
+ y = mainAxisOffset;
58
+ const crossAxisOffset = spacingCalculator.calculateAlignItems(
59
+ context.containerProps.alignItems,
60
+ parentWidth,
61
+ child.size.width,
62
+ 0,
63
+ 0
64
+ );
65
+ x = crossAxisOffset;
66
+ nextMain = currentMain;
67
+ } else {
68
+ currentMain += margin.top;
69
+ y = context.padding.top + currentMain;
70
+ const alignOffset = spacingCalculator.calculateAlignItems(
71
+ context.containerProps.alignItems,
72
+ context.contentArea.width,
73
+ child.size.width,
74
+ margin.left,
75
+ margin.right
76
+ );
77
+ x = context.padding.left + alignOffset;
78
+ nextMain = currentMain + child.size.height + margin.bottom;
79
+ }
80
+ return {
81
+ position: { x, y },
82
+ nextMain
83
+ };
84
+ }
85
+ /**
86
+ * Wrap children into lines based on available height
87
+ * Used when flexWrap is 'wrap' or 'wrap-reverse'
88
+ * @param children - Layout children to wrap
89
+ * @param availableHeight - Available height for each line
90
+ * @param gap - Gap between children
91
+ * @returns Array of layout lines
92
+ */
93
+ wrapChildren(children, availableHeight, gap) {
94
+ const lines = [];
95
+ let currentLine = [];
96
+ let currentLineHeight = 0;
97
+ let currentLineWidth = 0;
98
+ for (const child of children) {
99
+ if (child.child.__layoutProps?.headless) {
100
+ continue;
101
+ }
102
+ const margin = this.getMarginValues(child);
103
+ const props = child.child.__layoutProps;
104
+ let effectiveHeight = child.size.height;
105
+ if (effectiveHeight <= 0 && props) {
106
+ if (props.flexBasis !== void 0 && typeof props.flexBasis === "number") {
107
+ effectiveHeight = props.flexBasis;
108
+ } else if (props.minHeight !== void 0) {
109
+ const parsed = sizeResolver.parseSize(props.minHeight);
110
+ effectiveHeight = sizeResolver.resolveSize(parsed, availableHeight, 100, void 0);
111
+ } else if (props.flex && props.flex > 0) {
112
+ effectiveHeight = 100;
113
+ }
114
+ }
115
+ const childHeight = effectiveHeight + margin.top + margin.bottom;
116
+ const childWidth = child.size.width + margin.left + margin.right;
117
+ const gapSpace = currentLine.length > 0 ? gap : 0;
118
+ const requiredSpace = currentLineHeight + childHeight + gapSpace;
119
+ if (requiredSpace > availableHeight && currentLine.length > 0) {
120
+ lines.push({
121
+ children: currentLine,
122
+ mainAxisSize: currentLineHeight,
123
+ crossAxisSize: currentLineWidth
124
+ });
125
+ currentLine = [child];
126
+ currentLineHeight = childHeight;
127
+ currentLineWidth = childWidth;
128
+ } else {
129
+ currentLine.push(child);
130
+ currentLineHeight = requiredSpace;
131
+ currentLineWidth = Math.max(currentLineWidth, childWidth);
132
+ }
133
+ }
134
+ if (currentLine.length > 0) {
135
+ lines.push({
136
+ children: currentLine,
137
+ mainAxisSize: currentLineHeight,
138
+ crossAxisSize: currentLineWidth
139
+ });
140
+ }
141
+ return lines;
142
+ }
143
+ }
144
+ exports.ColumnLayoutStrategy = ColumnLayoutStrategy;
145
+ //# sourceMappingURL=column-layout.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"column-layout.cjs","sources":["../../../src/layout/strategies/column-layout.ts"],"sourcesContent":["/**\n * Column layout strategy (vertical stacking)\n * Like SwiftUI's VStack\n */\nimport type { LayoutChild, LayoutContext, LayoutLine, Position } from '../types'\nimport type { ContentMetrics } from '../utils/dimension-calculator'\nimport { parseSize, resolveSize } from '../utils/size-resolver'\nimport { calculateAlignItems } from '../utils/spacing-calculator'\nimport { BaseLayoutStrategy } from './base-strategy'\n\n/**\n * Column layout strategy - stacks children vertically\n */\nexport class ColumnLayoutStrategy extends BaseLayoutStrategy {\n /**\n * Calculate content dimensions for column layout\n * For flex children, uses a minimum default size to avoid chicken-egg sizing issues\n * @param children - Array of layout children\n * @param context - Layout context\n * @returns Content metrics\n */\n calculateMetrics(children: LayoutChild[], _context: LayoutContext): ContentMetrics {\n const FLEX_CHILD_MIN_SIZE = 100 // Minimum size for flex children in content calculation\n let maxWidth = 0\n let totalMainSize = 0\n\n for (const child of children) {\n const total = this.getTotalChildSize(child)\n maxWidth = Math.max(maxWidth, total.width)\n\n // Check if this child participates in flexbox (flex, flexShrink, or flexBasis)\n const props = child.child.__layoutProps\n const isFlexItem =\n (props?.flex !== undefined && props.flex > 0) ||\n props?.flexShrink !== undefined ||\n props?.flexBasis !== undefined\n // If flex child already has a resolved size (> 10), use it; otherwise use minimum\n const childHeight = isFlexItem && child.size.height <= 10 ? FLEX_CHILD_MIN_SIZE : total.height\n\n totalMainSize += childHeight\n }\n\n return {\n maxWidth,\n maxHeight: 0, // Not used for column\n totalMainSize,\n }\n }\n\n /**\n * Position a child in column layout\n * @param child - Layout child\n * @param _index - Child index (unused for column layout)\n * @param context - Layout context\n * @param currentMain - Current Y position\n * @returns Position and next main axis value\n */\n positionChild(\n child: LayoutChild,\n _index: number,\n context: LayoutContext,\n currentMain: number\n ): { position: Position; nextMain: number } {\n const margin = this.getMarginValues(child)\n const isHeadless = child.child.__layoutProps?.headless\n\n let x: number\n let y: number\n let nextMain: number\n\n if (isHeadless) {\n // Headless: calculate position directly using alignItems/justifyContent on full parent size\n const parentWidth = context.parentSize?.width ?? context.contentArea.width\n const parentHeight = context.parentSize?.height ?? context.contentArea.height\n\n // justifyContent on main axis (vertical) - manual calculation\n const justify = context.containerProps.justifyContent ?? 'start'\n let mainAxisOffset = 0\n if (justify === 'center') {\n mainAxisOffset = (parentHeight - child.size.height) / 2\n } else if (justify === 'end') {\n mainAxisOffset = parentHeight - child.size.height\n }\n // start and space-* variants use 0 for single item\n y = mainAxisOffset\n\n // alignItems on cross axis (horizontal)\n const crossAxisOffset = calculateAlignItems(\n context.containerProps.alignItems,\n parentWidth,\n child.size.width,\n 0,\n 0\n )\n x = crossAxisOffset\n\n // Don't advance currentMain for headless (they don't participate in flow)\n nextMain = currentMain\n } else {\n // Normal: use container padding and contentArea\n currentMain += margin.top\n y = context.padding.top + currentMain\n\n const alignOffset = calculateAlignItems(\n context.containerProps.alignItems,\n context.contentArea.width,\n child.size.width,\n margin.left,\n margin.right\n )\n x = context.padding.left + alignOffset\n\n nextMain = currentMain + child.size.height + margin.bottom\n }\n\n return {\n position: { x, y },\n nextMain,\n }\n }\n\n /**\n * Wrap children into lines based on available height\n * Used when flexWrap is 'wrap' or 'wrap-reverse'\n * @param children - Layout children to wrap\n * @param availableHeight - Available height for each line\n * @param gap - Gap between children\n * @returns Array of layout lines\n */\n wrapChildren(children: LayoutChild[], availableHeight: number, gap: number): LayoutLine[] {\n const lines: LayoutLine[] = []\n let currentLine: LayoutChild[] = []\n let currentLineHeight = 0\n let currentLineWidth = 0\n\n for (const child of children) {\n // Skip headless children in wrapping calculation\n if (child.child.__layoutProps?.headless) {\n continue\n }\n\n const margin = this.getMarginValues(child)\n const props = child.child.__layoutProps\n\n // For flex items with no size, use flexBasis or minHeight as hint for wrapping\n let effectiveHeight = child.size.height\n if (effectiveHeight <= 0 && props) {\n if (props.flexBasis !== undefined && typeof props.flexBasis === 'number') {\n effectiveHeight = props.flexBasis\n } else if (props.minHeight !== undefined) {\n // Resolve minHeight SizeValue to number\n const parsed = parseSize(props.minHeight)\n effectiveHeight = resolveSize(parsed, availableHeight, 100, undefined)\n } else if (props.flex && props.flex > 0) {\n // Use a reasonable default for flex items with no size hint\n effectiveHeight = 100\n }\n }\n\n const childHeight = effectiveHeight + margin.top + margin.bottom\n const childWidth = child.size.width + margin.left + margin.right\n\n const gapSpace = currentLine.length > 0 ? gap : 0\n const requiredSpace = currentLineHeight + childHeight + gapSpace\n\n // Check if we need to wrap to a new line (column)\n if (requiredSpace > availableHeight && currentLine.length > 0) {\n // Save current line\n lines.push({\n children: currentLine,\n mainAxisSize: currentLineHeight,\n crossAxisSize: currentLineWidth,\n })\n\n // Start new line\n currentLine = [child]\n currentLineHeight = childHeight\n currentLineWidth = childWidth\n } else {\n // Add to current line\n currentLine.push(child)\n currentLineHeight = requiredSpace\n currentLineWidth = Math.max(currentLineWidth, childWidth)\n }\n }\n\n // Add remaining line\n if (currentLine.length > 0) {\n lines.push({\n children: currentLine,\n mainAxisSize: currentLineHeight,\n crossAxisSize: currentLineWidth,\n })\n }\n\n return lines\n }\n}\n"],"names":["BaseLayoutStrategy","calculateAlignItems","parseSize","resolveSize"],"mappings":"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"}
@@ -0,0 +1,38 @@
1
+ import { LayoutChild, LayoutContext, LayoutLine, Position } from '../types';
2
+ import { ContentMetrics } from '../utils/dimension-calculator';
3
+ import { BaseLayoutStrategy } from './base-strategy';
4
+ /**
5
+ * Column layout strategy - stacks children vertically
6
+ */
7
+ export declare class ColumnLayoutStrategy extends BaseLayoutStrategy {
8
+ /**
9
+ * Calculate content dimensions for column layout
10
+ * For flex children, uses a minimum default size to avoid chicken-egg sizing issues
11
+ * @param children - Array of layout children
12
+ * @param context - Layout context
13
+ * @returns Content metrics
14
+ */
15
+ calculateMetrics(children: LayoutChild[], _context: LayoutContext): ContentMetrics;
16
+ /**
17
+ * Position a child in column layout
18
+ * @param child - Layout child
19
+ * @param _index - Child index (unused for column layout)
20
+ * @param context - Layout context
21
+ * @param currentMain - Current Y position
22
+ * @returns Position and next main axis value
23
+ */
24
+ positionChild(child: LayoutChild, _index: number, context: LayoutContext, currentMain: number): {
25
+ position: Position;
26
+ nextMain: number;
27
+ };
28
+ /**
29
+ * Wrap children into lines based on available height
30
+ * Used when flexWrap is 'wrap' or 'wrap-reverse'
31
+ * @param children - Layout children to wrap
32
+ * @param availableHeight - Available height for each line
33
+ * @param gap - Gap between children
34
+ * @returns Array of layout lines
35
+ */
36
+ wrapChildren(children: LayoutChild[], availableHeight: number, gap: number): LayoutLine[];
37
+ }
38
+ //# sourceMappingURL=column-layout.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"column-layout.d.ts","sourceRoot":"","sources":["../../../src/layout/strategies/column-layout.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,KAAK,EAAE,WAAW,EAAE,aAAa,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAA;AAChF,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,+BAA+B,CAAA;AAGnE,OAAO,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAA;AAEpD;;GAEG;AACH,qBAAa,oBAAqB,SAAQ,kBAAkB;IAC1D;;;;;;OAMG;IACH,gBAAgB,CAAC,QAAQ,EAAE,WAAW,EAAE,EAAE,QAAQ,EAAE,aAAa,GAAG,cAAc;IA4BlF;;;;;;;OAOG;IACH,aAAa,CACX,KAAK,EAAE,WAAW,EAClB,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,aAAa,EACtB,WAAW,EAAE,MAAM,GAClB;QAAE,QAAQ,EAAE,QAAQ,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE;IA2D3C;;;;;;;OAOG;IACH,YAAY,CAAC,QAAQ,EAAE,WAAW,EAAE,EAAE,eAAe,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,UAAU,EAAE;CAoE1F"}
@@ -0,0 +1,145 @@
1
+ import { parseSize, resolveSize } from "../utils/size-resolver.js";
2
+ import { calculateAlignItems } from "../utils/spacing-calculator.js";
3
+ import { BaseLayoutStrategy } from "./base-strategy.js";
4
+ class ColumnLayoutStrategy extends BaseLayoutStrategy {
5
+ /**
6
+ * Calculate content dimensions for column layout
7
+ * For flex children, uses a minimum default size to avoid chicken-egg sizing issues
8
+ * @param children - Array of layout children
9
+ * @param context - Layout context
10
+ * @returns Content metrics
11
+ */
12
+ calculateMetrics(children, _context) {
13
+ const FLEX_CHILD_MIN_SIZE = 100;
14
+ let maxWidth = 0;
15
+ let totalMainSize = 0;
16
+ for (const child of children) {
17
+ const total = this.getTotalChildSize(child);
18
+ maxWidth = Math.max(maxWidth, total.width);
19
+ const props = child.child.__layoutProps;
20
+ const isFlexItem = props?.flex !== void 0 && props.flex > 0 || props?.flexShrink !== void 0 || props?.flexBasis !== void 0;
21
+ const childHeight = isFlexItem && child.size.height <= 10 ? FLEX_CHILD_MIN_SIZE : total.height;
22
+ totalMainSize += childHeight;
23
+ }
24
+ return {
25
+ maxWidth,
26
+ maxHeight: 0,
27
+ // Not used for column
28
+ totalMainSize
29
+ };
30
+ }
31
+ /**
32
+ * Position a child in column layout
33
+ * @param child - Layout child
34
+ * @param _index - Child index (unused for column layout)
35
+ * @param context - Layout context
36
+ * @param currentMain - Current Y position
37
+ * @returns Position and next main axis value
38
+ */
39
+ positionChild(child, _index, context, currentMain) {
40
+ const margin = this.getMarginValues(child);
41
+ const isHeadless = child.child.__layoutProps?.headless;
42
+ let x;
43
+ let y;
44
+ let nextMain;
45
+ if (isHeadless) {
46
+ const parentWidth = context.parentSize?.width ?? context.contentArea.width;
47
+ const parentHeight = context.parentSize?.height ?? context.contentArea.height;
48
+ const justify = context.containerProps.justifyContent ?? "start";
49
+ let mainAxisOffset = 0;
50
+ if (justify === "center") {
51
+ mainAxisOffset = (parentHeight - child.size.height) / 2;
52
+ } else if (justify === "end") {
53
+ mainAxisOffset = parentHeight - child.size.height;
54
+ }
55
+ y = mainAxisOffset;
56
+ const crossAxisOffset = calculateAlignItems(
57
+ context.containerProps.alignItems,
58
+ parentWidth,
59
+ child.size.width,
60
+ 0,
61
+ 0
62
+ );
63
+ x = crossAxisOffset;
64
+ nextMain = currentMain;
65
+ } else {
66
+ currentMain += margin.top;
67
+ y = context.padding.top + currentMain;
68
+ const alignOffset = calculateAlignItems(
69
+ context.containerProps.alignItems,
70
+ context.contentArea.width,
71
+ child.size.width,
72
+ margin.left,
73
+ margin.right
74
+ );
75
+ x = context.padding.left + alignOffset;
76
+ nextMain = currentMain + child.size.height + margin.bottom;
77
+ }
78
+ return {
79
+ position: { x, y },
80
+ nextMain
81
+ };
82
+ }
83
+ /**
84
+ * Wrap children into lines based on available height
85
+ * Used when flexWrap is 'wrap' or 'wrap-reverse'
86
+ * @param children - Layout children to wrap
87
+ * @param availableHeight - Available height for each line
88
+ * @param gap - Gap between children
89
+ * @returns Array of layout lines
90
+ */
91
+ wrapChildren(children, availableHeight, gap) {
92
+ const lines = [];
93
+ let currentLine = [];
94
+ let currentLineHeight = 0;
95
+ let currentLineWidth = 0;
96
+ for (const child of children) {
97
+ if (child.child.__layoutProps?.headless) {
98
+ continue;
99
+ }
100
+ const margin = this.getMarginValues(child);
101
+ const props = child.child.__layoutProps;
102
+ let effectiveHeight = child.size.height;
103
+ if (effectiveHeight <= 0 && props) {
104
+ if (props.flexBasis !== void 0 && typeof props.flexBasis === "number") {
105
+ effectiveHeight = props.flexBasis;
106
+ } else if (props.minHeight !== void 0) {
107
+ const parsed = parseSize(props.minHeight);
108
+ effectiveHeight = resolveSize(parsed, availableHeight, 100, void 0);
109
+ } else if (props.flex && props.flex > 0) {
110
+ effectiveHeight = 100;
111
+ }
112
+ }
113
+ const childHeight = effectiveHeight + margin.top + margin.bottom;
114
+ const childWidth = child.size.width + margin.left + margin.right;
115
+ const gapSpace = currentLine.length > 0 ? gap : 0;
116
+ const requiredSpace = currentLineHeight + childHeight + gapSpace;
117
+ if (requiredSpace > availableHeight && currentLine.length > 0) {
118
+ lines.push({
119
+ children: currentLine,
120
+ mainAxisSize: currentLineHeight,
121
+ crossAxisSize: currentLineWidth
122
+ });
123
+ currentLine = [child];
124
+ currentLineHeight = childHeight;
125
+ currentLineWidth = childWidth;
126
+ } else {
127
+ currentLine.push(child);
128
+ currentLineHeight = requiredSpace;
129
+ currentLineWidth = Math.max(currentLineWidth, childWidth);
130
+ }
131
+ }
132
+ if (currentLine.length > 0) {
133
+ lines.push({
134
+ children: currentLine,
135
+ mainAxisSize: currentLineHeight,
136
+ crossAxisSize: currentLineWidth
137
+ });
138
+ }
139
+ return lines;
140
+ }
141
+ }
142
+ export {
143
+ ColumnLayoutStrategy
144
+ };
145
+ //# sourceMappingURL=column-layout.js.map