@rezi-ui/core 0.1.0-alpha.60 → 0.1.0-alpha.63

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 (345) hide show
  1. package/dist/app/createApp/breadcrumbs.d.ts +38 -0
  2. package/dist/app/createApp/breadcrumbs.d.ts.map +1 -0
  3. package/dist/app/createApp/breadcrumbs.js +65 -0
  4. package/dist/app/createApp/breadcrumbs.js.map +1 -0
  5. package/dist/app/createApp/config.d.ts +25 -0
  6. package/dist/app/createApp/config.d.ts.map +1 -0
  7. package/dist/app/createApp/config.js +130 -0
  8. package/dist/app/createApp/config.js.map +1 -0
  9. package/dist/app/createApp/eventLoop.d.ts +95 -0
  10. package/dist/app/createApp/eventLoop.d.ts.map +1 -0
  11. package/dist/app/createApp/eventLoop.js +384 -0
  12. package/dist/app/createApp/eventLoop.js.map +1 -0
  13. package/dist/app/createApp/guards.d.ts +21 -0
  14. package/dist/app/createApp/guards.d.ts.map +1 -0
  15. package/dist/app/createApp/guards.js +54 -0
  16. package/dist/app/createApp/guards.js.map +1 -0
  17. package/dist/app/createApp/keybindings.d.ts +28 -0
  18. package/dist/app/createApp/keybindings.d.ts.map +1 -0
  19. package/dist/app/createApp/keybindings.js +113 -0
  20. package/dist/app/createApp/keybindings.js.map +1 -0
  21. package/dist/app/createApp/renderLoop.d.ts +64 -0
  22. package/dist/app/createApp/renderLoop.d.ts.map +1 -0
  23. package/dist/app/createApp/renderLoop.js +305 -0
  24. package/dist/app/createApp/renderLoop.js.map +1 -0
  25. package/dist/app/createApp.d.ts +3 -39
  26. package/dist/app/createApp.d.ts.map +1 -1
  27. package/dist/app/createApp.js +403 -1205
  28. package/dist/app/createApp.js.map +1 -1
  29. package/dist/app/widgetRenderer/constraintState.d.ts +98 -0
  30. package/dist/app/widgetRenderer/constraintState.d.ts.map +1 -0
  31. package/dist/app/widgetRenderer/constraintState.js +563 -0
  32. package/dist/app/widgetRenderer/constraintState.js.map +1 -0
  33. package/dist/app/widgetRenderer/fileNodeCache.d.ts +2 -0
  34. package/dist/app/widgetRenderer/fileNodeCache.d.ts.map +1 -1
  35. package/dist/app/widgetRenderer/fileNodeCache.js +31 -0
  36. package/dist/app/widgetRenderer/fileNodeCache.js.map +1 -1
  37. package/dist/app/widgetRenderer/filePickerRouting.d.ts +12 -1
  38. package/dist/app/widgetRenderer/filePickerRouting.d.ts.map +1 -1
  39. package/dist/app/widgetRenderer/filePickerRouting.js +63 -14
  40. package/dist/app/widgetRenderer/filePickerRouting.js.map +1 -1
  41. package/dist/app/widgetRenderer/focusState.d.ts +46 -0
  42. package/dist/app/widgetRenderer/focusState.d.ts.map +1 -0
  43. package/dist/app/widgetRenderer/focusState.js +122 -0
  44. package/dist/app/widgetRenderer/focusState.js.map +1 -0
  45. package/dist/app/widgetRenderer/keyboardRouting.d.ts.map +1 -1
  46. package/dist/app/widgetRenderer/keyboardRouting.js.map +1 -1
  47. package/dist/app/widgetRenderer/mouseRouting.d.ts +5 -0
  48. package/dist/app/widgetRenderer/mouseRouting.d.ts.map +1 -1
  49. package/dist/app/widgetRenderer/mouseRouting.js +78 -8
  50. package/dist/app/widgetRenderer/mouseRouting.js.map +1 -1
  51. package/dist/app/widgetRenderer/overlayShortcuts.d.ts.map +1 -1
  52. package/dist/app/widgetRenderer/overlayShortcuts.js +14 -4
  53. package/dist/app/widgetRenderer/overlayShortcuts.js.map +1 -1
  54. package/dist/app/widgetRenderer/overlayState.d.ts +198 -0
  55. package/dist/app/widgetRenderer/overlayState.d.ts.map +1 -0
  56. package/dist/app/widgetRenderer/overlayState.js +590 -0
  57. package/dist/app/widgetRenderer/overlayState.js.map +1 -0
  58. package/dist/app/widgetRenderer/routeEngineEvent.d.ts +189 -0
  59. package/dist/app/widgetRenderer/routeEngineEvent.d.ts.map +1 -0
  60. package/dist/app/widgetRenderer/routeEngineEvent.js +527 -0
  61. package/dist/app/widgetRenderer/routeEngineEvent.js.map +1 -0
  62. package/dist/app/widgetRenderer.d.ts +2 -1
  63. package/dist/app/widgetRenderer.d.ts.map +1 -1
  64. package/dist/app/widgetRenderer.js +334 -1707
  65. package/dist/app/widgetRenderer.js.map +1 -1
  66. package/dist/forms/internal/arrayState.d.ts +35 -0
  67. package/dist/forms/internal/arrayState.d.ts.map +1 -0
  68. package/dist/forms/internal/arrayState.js +238 -0
  69. package/dist/forms/internal/arrayState.js.map +1 -0
  70. package/dist/forms/internal/bindings.d.ts +46 -0
  71. package/dist/forms/internal/bindings.d.ts.map +1 -0
  72. package/dist/forms/internal/bindings.js +161 -0
  73. package/dist/forms/internal/bindings.js.map +1 -0
  74. package/dist/forms/internal/dev.d.ts +4 -0
  75. package/dist/forms/internal/dev.d.ts.map +1 -0
  76. package/dist/forms/internal/dev.js +21 -0
  77. package/dist/forms/internal/dev.js.map +1 -0
  78. package/dist/forms/internal/state.d.ts +52 -0
  79. package/dist/forms/internal/state.d.ts.map +1 -0
  80. package/dist/forms/internal/state.js +240 -0
  81. package/dist/forms/internal/state.js.map +1 -0
  82. package/dist/forms/internal/submit.d.ts +43 -0
  83. package/dist/forms/internal/submit.d.ts.map +1 -0
  84. package/dist/forms/internal/submit.js +165 -0
  85. package/dist/forms/internal/submit.js.map +1 -0
  86. package/dist/forms/internal/wizard.d.ts +53 -0
  87. package/dist/forms/internal/wizard.d.ts.map +1 -0
  88. package/dist/forms/internal/wizard.js +311 -0
  89. package/dist/forms/internal/wizard.js.map +1 -0
  90. package/dist/forms/useForm.d.ts.map +1 -1
  91. package/dist/forms/useForm.js +90 -1117
  92. package/dist/forms/useForm.js.map +1 -1
  93. package/dist/index.d.ts +1 -1
  94. package/dist/index.d.ts.map +1 -1
  95. package/dist/index.js +1 -1
  96. package/dist/index.js.map +1 -1
  97. package/dist/keybindings/manager.d.ts.map +1 -1
  98. package/dist/keybindings/manager.js.map +1 -1
  99. package/dist/keybindings/parser.d.ts.map +1 -1
  100. package/dist/keybindings/parser.js +10 -5
  101. package/dist/keybindings/parser.js.map +1 -1
  102. package/dist/layout/dropdownGeometry.d.ts +8 -0
  103. package/dist/layout/dropdownGeometry.d.ts.map +1 -1
  104. package/dist/layout/dropdownGeometry.js +40 -0
  105. package/dist/layout/dropdownGeometry.js.map +1 -1
  106. package/dist/layout/engine/layoutEngine.js +1 -1
  107. package/dist/layout/engine/layoutEngine.js.map +1 -1
  108. package/dist/layout/kinds/overlays.d.ts.map +1 -1
  109. package/dist/layout/kinds/stack.d.ts +1 -3
  110. package/dist/layout/kinds/stack.d.ts.map +1 -1
  111. package/dist/layout/kinds/stack.js +11 -1523
  112. package/dist/layout/kinds/stack.js.map +1 -1
  113. package/dist/layout/kinds/stackParts/axis.d.ts +32 -0
  114. package/dist/layout/kinds/stackParts/axis.d.ts.map +1 -0
  115. package/dist/layout/kinds/stackParts/axis.js +61 -0
  116. package/dist/layout/kinds/stackParts/axis.js.map +1 -0
  117. package/dist/layout/kinds/stackParts/constraintPlan.d.ts +18 -0
  118. package/dist/layout/kinds/stackParts/constraintPlan.d.ts.map +1 -0
  119. package/dist/layout/kinds/stackParts/constraintPlan.js +434 -0
  120. package/dist/layout/kinds/stackParts/constraintPlan.js.map +1 -0
  121. package/dist/layout/kinds/stackParts/layout.d.ts +6 -0
  122. package/dist/layout/kinds/stackParts/layout.d.ts.map +1 -0
  123. package/dist/layout/kinds/stackParts/layout.js +376 -0
  124. package/dist/layout/kinds/stackParts/layout.js.map +1 -0
  125. package/dist/layout/kinds/stackParts/measure.d.ts +6 -0
  126. package/dist/layout/kinds/stackParts/measure.d.ts.map +1 -0
  127. package/dist/layout/kinds/stackParts/measure.js +212 -0
  128. package/dist/layout/kinds/stackParts/measure.js.map +1 -0
  129. package/dist/layout/kinds/stackParts/shared.d.ts +31 -0
  130. package/dist/layout/kinds/stackParts/shared.d.ts.map +1 -0
  131. package/dist/layout/kinds/stackParts/shared.js +94 -0
  132. package/dist/layout/kinds/stackParts/shared.js.map +1 -0
  133. package/dist/layout/kinds/stackParts/wrap.d.ts +26 -0
  134. package/dist/layout/kinds/stackParts/wrap.d.ts.map +1 -0
  135. package/dist/layout/kinds/stackParts/wrap.js +374 -0
  136. package/dist/layout/kinds/stackParts/wrap.js.map +1 -0
  137. package/dist/layout/validate/interactive.d.ts +106 -0
  138. package/dist/layout/validate/interactive.d.ts.map +1 -0
  139. package/dist/layout/validate/interactive.js +430 -0
  140. package/dist/layout/validate/interactive.js.map +1 -0
  141. package/dist/layout/validate/layoutConstraints.d.ts +51 -0
  142. package/dist/layout/validate/layoutConstraints.d.ts.map +1 -0
  143. package/dist/layout/validate/layoutConstraints.js +100 -0
  144. package/dist/layout/validate/layoutConstraints.js.map +1 -0
  145. package/dist/layout/validate/primitives.d.ts +31 -0
  146. package/dist/layout/validate/primitives.d.ts.map +1 -0
  147. package/dist/layout/validate/primitives.js +299 -0
  148. package/dist/layout/validate/primitives.js.map +1 -0
  149. package/dist/layout/validate/shared.d.ts +23 -0
  150. package/dist/layout/validate/shared.d.ts.map +1 -0
  151. package/dist/layout/validate/shared.js +32 -0
  152. package/dist/layout/validate/shared.js.map +1 -0
  153. package/dist/layout/validate/spacing.d.ts +21 -0
  154. package/dist/layout/validate/spacing.d.ts.map +1 -0
  155. package/dist/layout/validate/spacing.js +33 -0
  156. package/dist/layout/validate/spacing.js.map +1 -0
  157. package/dist/layout/validateProps.d.ts +5 -159
  158. package/dist/layout/validateProps.d.ts.map +1 -1
  159. package/dist/layout/validateProps.js +1 -832
  160. package/dist/layout/validateProps.js.map +1 -1
  161. package/dist/pipeline.js +1 -1
  162. package/dist/pipeline.js.map +1 -1
  163. package/dist/renderer/renderToDrawlist/renderTree.d.ts +1 -1
  164. package/dist/renderer/renderToDrawlist/renderTree.d.ts.map +1 -1
  165. package/dist/renderer/renderToDrawlist/renderTree.js +3 -3
  166. package/dist/renderer/renderToDrawlist/renderTree.js.map +1 -1
  167. package/dist/renderer/renderToDrawlist/types.d.ts +2 -0
  168. package/dist/renderer/renderToDrawlist/types.d.ts.map +1 -1
  169. package/dist/renderer/renderToDrawlist/widgets/containers.d.ts.map +1 -1
  170. package/dist/renderer/renderToDrawlist/widgets/containers.js +1 -1
  171. package/dist/renderer/renderToDrawlist/widgets/containers.js.map +1 -1
  172. package/dist/renderer/renderToDrawlist/widgets/files.d.ts +2 -1
  173. package/dist/renderer/renderToDrawlist/widgets/files.d.ts.map +1 -1
  174. package/dist/renderer/renderToDrawlist/widgets/files.js +30 -3
  175. package/dist/renderer/renderToDrawlist/widgets/files.js.map +1 -1
  176. package/dist/renderer/renderToDrawlist/widgets/overlays.d.ts +1 -1
  177. package/dist/renderer/renderToDrawlist/widgets/overlays.d.ts.map +1 -1
  178. package/dist/renderer/renderToDrawlist/widgets/overlays.js +26 -6
  179. package/dist/renderer/renderToDrawlist/widgets/overlays.js.map +1 -1
  180. package/dist/renderer/renderToDrawlist/widgets/renderFormWidgets.d.ts.map +1 -1
  181. package/dist/renderer/renderToDrawlist/widgets/renderFormWidgets.js +52 -18
  182. package/dist/renderer/renderToDrawlist/widgets/renderFormWidgets.js.map +1 -1
  183. package/dist/renderer/renderToDrawlist.d.ts +0 -8
  184. package/dist/renderer/renderToDrawlist.d.ts.map +1 -1
  185. package/dist/renderer/renderToDrawlist.js +1 -9
  186. package/dist/renderer/renderToDrawlist.js.map +1 -1
  187. package/dist/runtime/commit/composite.d.ts +11 -0
  188. package/dist/runtime/commit/composite.d.ts.map +1 -0
  189. package/dist/runtime/commit/composite.js +238 -0
  190. package/dist/runtime/commit/composite.js.map +1 -0
  191. package/dist/runtime/commit/container.d.ts +7 -0
  192. package/dist/runtime/commit/container.d.ts.map +1 -0
  193. package/dist/runtime/commit/container.js +350 -0
  194. package/dist/runtime/commit/container.js.map +1 -0
  195. package/dist/runtime/commit/equality.d.ts +20 -0
  196. package/dist/runtime/commit/equality.d.ts.map +1 -0
  197. package/dist/runtime/commit/equality.js +436 -0
  198. package/dist/runtime/commit/equality.js.map +1 -0
  199. package/dist/runtime/commit/errorBoundary.d.ts +7 -0
  200. package/dist/runtime/commit/errorBoundary.d.ts.map +1 -0
  201. package/dist/runtime/commit/errorBoundary.js +53 -0
  202. package/dist/runtime/commit/errorBoundary.js.map +1 -0
  203. package/dist/runtime/commit/shared.d.ts +138 -0
  204. package/dist/runtime/commit/shared.d.ts.map +1 -0
  205. package/dist/runtime/commit/shared.js +11 -0
  206. package/dist/runtime/commit/shared.js.map +1 -0
  207. package/dist/runtime/commit/transitions.d.ts +9 -0
  208. package/dist/runtime/commit/transitions.d.ts.map +1 -0
  209. package/dist/runtime/commit/transitions.js +93 -0
  210. package/dist/runtime/commit/transitions.js.map +1 -0
  211. package/dist/runtime/commit/validation.d.ts +16 -0
  212. package/dist/runtime/commit/validation.d.ts.map +1 -0
  213. package/dist/runtime/commit/validation.js +157 -0
  214. package/dist/runtime/commit/validation.js.map +1 -0
  215. package/dist/runtime/commit.d.ts +7 -117
  216. package/dist/runtime/commit.d.ts.map +1 -1
  217. package/dist/runtime/commit.js +13 -1394
  218. package/dist/runtime/commit.js.map +1 -1
  219. package/dist/runtime/localState.d.ts +4 -0
  220. package/dist/runtime/localState.d.ts.map +1 -1
  221. package/dist/runtime/localState.js.map +1 -1
  222. package/dist/runtime/widgetMeta/collector.d.ts +77 -0
  223. package/dist/runtime/widgetMeta/collector.d.ts.map +1 -0
  224. package/dist/runtime/widgetMeta/collector.js +293 -0
  225. package/dist/runtime/widgetMeta/collector.js.map +1 -0
  226. package/dist/runtime/widgetMeta/focusContainers.d.ts +44 -0
  227. package/dist/runtime/widgetMeta/focusContainers.d.ts.map +1 -0
  228. package/dist/runtime/widgetMeta/focusContainers.js +190 -0
  229. package/dist/runtime/widgetMeta/focusContainers.js.map +1 -0
  230. package/dist/runtime/widgetMeta/focusInfo.d.ts +19 -0
  231. package/dist/runtime/widgetMeta/focusInfo.d.ts.map +1 -0
  232. package/dist/runtime/widgetMeta/focusInfo.js +172 -0
  233. package/dist/runtime/widgetMeta/focusInfo.js.map +1 -0
  234. package/dist/runtime/widgetMeta/helpers.d.ts +47 -0
  235. package/dist/runtime/widgetMeta/helpers.d.ts.map +1 -0
  236. package/dist/runtime/widgetMeta/helpers.js +182 -0
  237. package/dist/runtime/widgetMeta/helpers.js.map +1 -0
  238. package/dist/runtime/widgetMeta.d.ts +12 -175
  239. package/dist/runtime/widgetMeta.d.ts.map +1 -1
  240. package/dist/runtime/widgetMeta.js +6 -847
  241. package/dist/runtime/widgetMeta.js.map +1 -1
  242. package/dist/ui/capabilities.d.ts.map +1 -1
  243. package/dist/ui/designTokens.d.ts.map +1 -1
  244. package/dist/widgets/accordion.d.ts.map +1 -1
  245. package/dist/widgets/accordion.js +8 -13
  246. package/dist/widgets/accordion.js.map +1 -1
  247. package/dist/widgets/factories/advanced.d.ts +20 -0
  248. package/dist/widgets/factories/advanced.d.ts.map +1 -0
  249. package/dist/widgets/factories/advanced.js +75 -0
  250. package/dist/widgets/factories/advanced.js.map +1 -0
  251. package/dist/widgets/factories/basic.d.ts +14 -0
  252. package/dist/widgets/factories/basic.d.ts.map +1 -0
  253. package/dist/widgets/factories/basic.js +44 -0
  254. package/dist/widgets/factories/basic.js.map +1 -0
  255. package/dist/widgets/factories/feedback.d.ts +20 -0
  256. package/dist/widgets/factories/feedback.d.ts.map +1 -0
  257. package/dist/widgets/factories/feedback.js +102 -0
  258. package/dist/widgets/factories/feedback.js.map +1 -0
  259. package/dist/widgets/factories/helpers.d.ts +41 -0
  260. package/dist/widgets/factories/helpers.d.ts.map +1 -0
  261. package/dist/widgets/factories/helpers.js +72 -0
  262. package/dist/widgets/factories/helpers.js.map +1 -0
  263. package/dist/widgets/factories/interactive.d.ts +15 -0
  264. package/dist/widgets/factories/interactive.d.ts.map +1 -0
  265. package/dist/widgets/factories/interactive.js +46 -0
  266. package/dist/widgets/factories/interactive.js.map +1 -0
  267. package/dist/widgets/factories/layoutShell.d.ts +22 -0
  268. package/dist/widgets/factories/layoutShell.d.ts.map +1 -0
  269. package/dist/widgets/factories/layoutShell.js +190 -0
  270. package/dist/widgets/factories/layoutShell.js.map +1 -0
  271. package/dist/widgets/factories/media.d.ts +14 -0
  272. package/dist/widgets/factories/media.d.ts.map +1 -0
  273. package/dist/widgets/factories/media.js +25 -0
  274. package/dist/widgets/factories/media.js.map +1 -0
  275. package/dist/widgets/factories/navigation.d.ts +10 -0
  276. package/dist/widgets/factories/navigation.d.ts.map +1 -0
  277. package/dist/widgets/factories/navigation.js +24 -0
  278. package/dist/widgets/factories/navigation.js.map +1 -0
  279. package/dist/widgets/field.d.ts +6 -1
  280. package/dist/widgets/field.d.ts.map +1 -1
  281. package/dist/widgets/field.js +8 -2
  282. package/dist/widgets/field.js.map +1 -1
  283. package/dist/widgets/filePicker.d.ts +5 -0
  284. package/dist/widgets/filePicker.d.ts.map +1 -0
  285. package/dist/widgets/filePicker.js +136 -0
  286. package/dist/widgets/filePicker.js.map +1 -0
  287. package/dist/widgets/protocol.d.ts +0 -6
  288. package/dist/widgets/protocol.d.ts.map +1 -1
  289. package/dist/widgets/protocol.js +0 -6
  290. package/dist/widgets/protocol.js.map +1 -1
  291. package/dist/widgets/select.js +1 -1
  292. package/dist/widgets/select.js.map +1 -1
  293. package/dist/widgets/splitPane.d.ts.map +1 -1
  294. package/dist/widgets/splitPane.js.map +1 -1
  295. package/dist/widgets/table.d.ts.map +1 -1
  296. package/dist/widgets/table.js +43 -1
  297. package/dist/widgets/table.js.map +1 -1
  298. package/dist/widgets/tree.d.ts.map +1 -1
  299. package/dist/widgets/types/advanced.d.ts +611 -0
  300. package/dist/widgets/types/advanced.d.ts.map +1 -0
  301. package/dist/widgets/types/advanced.js +2 -0
  302. package/dist/widgets/types/advanced.js.map +1 -0
  303. package/dist/widgets/types/base.d.ts +933 -0
  304. package/dist/widgets/types/base.d.ts.map +1 -0
  305. package/dist/widgets/types/base.js +2 -0
  306. package/dist/widgets/types/base.js.map +1 -0
  307. package/dist/widgets/types/forms.d.ts +136 -0
  308. package/dist/widgets/types/forms.d.ts.map +1 -0
  309. package/dist/widgets/types/forms.js +2 -0
  310. package/dist/widgets/types/forms.js.map +1 -0
  311. package/dist/widgets/types/navigation.d.ts +83 -0
  312. package/dist/widgets/types/navigation.d.ts.map +1 -0
  313. package/dist/widgets/types/navigation.js +2 -0
  314. package/dist/widgets/types/navigation.js.map +1 -0
  315. package/dist/widgets/types/overlaysShell.d.ts +223 -0
  316. package/dist/widgets/types/overlaysShell.d.ts.map +1 -0
  317. package/dist/widgets/types/overlaysShell.js +2 -0
  318. package/dist/widgets/types/overlaysShell.js.map +1 -0
  319. package/dist/widgets/types/table.d.ts +104 -0
  320. package/dist/widgets/types/table.d.ts.map +1 -0
  321. package/dist/widgets/types/table.js +2 -0
  322. package/dist/widgets/types/table.js.map +1 -0
  323. package/dist/widgets/types/tree.d.ts +64 -0
  324. package/dist/widgets/types/tree.d.ts.map +1 -0
  325. package/dist/widgets/types/tree.js +2 -0
  326. package/dist/widgets/types/tree.js.map +1 -0
  327. package/dist/widgets/types.d.ts +14 -2123
  328. package/dist/widgets/types.d.ts.map +1 -1
  329. package/dist/widgets/ui.d.ts +37 -843
  330. package/dist/widgets/ui.d.ts.map +1 -1
  331. package/dist/widgets/ui.js +37 -1262
  332. package/dist/widgets/ui.js.map +1 -1
  333. package/package.json +2 -2
  334. package/dist/constraints/aggregation.d.ts +0 -17
  335. package/dist/constraints/aggregation.d.ts.map +0 -1
  336. package/dist/constraints/aggregation.js +0 -59
  337. package/dist/constraints/aggregation.js.map +0 -1
  338. package/dist/renderer/renderToDrawlist/overflowCulling.d.ts +0 -3
  339. package/dist/renderer/renderToDrawlist/overflowCulling.d.ts.map +0 -1
  340. package/dist/renderer/renderToDrawlist/overflowCulling.js +0 -81
  341. package/dist/renderer/renderToDrawlist/overflowCulling.js.map +0 -1
  342. package/dist/widgets/tests/protocol.test.d.ts +0 -2
  343. package/dist/widgets/tests/protocol.test.d.ts.map +0 -1
  344. package/dist/widgets/tests/protocol.test.js +0 -120
  345. package/dist/widgets/tests/protocol.test.js.map +0 -1
@@ -15,1379 +15,16 @@
15
15
  *
16
16
  * @see docs/guide/runtime-and-layout.md
17
17
  */
18
- import { resolveEasing } from "../animation/easing.js";
19
- import { normalizeDurationMs } from "../animation/interpolate.js";
20
- import { describeThrown } from "../debug/describeThrown.js";
21
- import { defaultTheme } from "../theme/defaultTheme.js";
22
- import { mergeThemeOverride } from "../theme/interop.js";
23
- import { getCompositeMeta, scopedId, } from "../widgets/composition.js";
24
- import { getWidgetProtocol, kindRequiresId } from "../widgets/protocol.js";
25
- import { createHookContext, } from "./instances.js";
18
+ import { getCompositeMeta } from "../widgets/composition.js";
19
+ import { executeCompositeRender } from "./commit/composite.js";
20
+ import { commitContainer } from "./commit/container.js";
21
+ import { __commitDiag, leafVNodeEqual } from "./commit/equality.js";
22
+ import { captureErrorBoundaryState, commitErrorBoundaryFallback } from "./commit/errorBoundary.js";
23
+ import { DEV_MODE, EMPTY_CHILDREN, LAYOUT_DEPTH_PATH_TRACK_START, LAYOUT_DEPTH_WARN_THRESHOLD, MAX_LAYOUT_NESTING_DEPTH, } from "./commit/shared.js";
24
+ import { collectSubtreeInstanceIds, deleteLocalStateForSubtree, tryScheduleExitAnimation, } from "./commit/transitions.js";
25
+ import { ensureFocusContainerId, ensureInteractiveId, formatWidgetPath, isContainerVNode, isVNode, warnDev, widgetPathEntry, } from "./commit/validation.js";
26
26
  import { reconcileChildren } from "./reconcile.js";
27
- /** Shared frozen empty array for leaf RuntimeInstance children. Avoids per-node allocation. */
28
- const EMPTY_CHILDREN = Object.freeze([]);
29
- /** Global commit diagnostics buffer. */
30
- export const __commitDiag = {
31
- enabled: false,
32
- entries: [],
33
- reset() {
34
- this.entries.length = 0;
35
- },
36
- push(e) {
37
- this.entries.push(e);
38
- },
39
- };
40
- /** Fast equality for packed color values. */
41
- function colorEqual(a, b) {
42
- return a === b;
43
- }
44
- /**
45
- * Fast shallow equality for text style objects.
46
- * Returns true if both styles produce identical render output.
47
- */
48
- function textStyleEqual(a, b) {
49
- if (a === b)
50
- return true;
51
- if (!a || !b)
52
- return false;
53
- return (a.bold === b.bold &&
54
- a.dim === b.dim &&
55
- a.italic === b.italic &&
56
- a.underline === b.underline &&
57
- a.inverse === b.inverse &&
58
- a.strikethrough === b.strikethrough &&
59
- a.overline === b.overline &&
60
- a.blink === b.blink &&
61
- colorEqual(a.fg, b.fg) &&
62
- colorEqual(a.bg, b.bg));
63
- }
64
- /**
65
- * Check if two leaf VNodes are semantically equal (same render output).
66
- * Used to skip allocating new RuntimeInstance objects for unchanged leaves.
67
- * Only covers common leaf kinds; returns false for unknown kinds (safe fallback).
68
- */
69
- function leafVNodeEqual(a, b) {
70
- switch (a.kind) {
71
- case "text": {
72
- if (b.kind !== "text")
73
- return false;
74
- if (a.text !== b.text)
75
- return false;
76
- if (a.props === b.props)
77
- return true;
78
- const ap = a.props;
79
- const bp = b.props;
80
- // Even when render output is identical, `id` changes must re-commit so downstream
81
- // id-based lookups (layout rect indexing, anchors, etc) don't observe stale ids.
82
- if (ap.id !== bp.id)
83
- return false;
84
- if (ap.textOverflow !== bp.textOverflow)
85
- return false;
86
- if (ap.variant !== bp.variant)
87
- return false;
88
- if (ap.maxWidth !== bp.maxWidth)
89
- return false;
90
- return textStyleEqual(ap.style, bp.style);
91
- }
92
- case "spacer": {
93
- if (b.kind !== "spacer")
94
- return false;
95
- const ap = a.props;
96
- const bp = b.props;
97
- return ap.size === bp.size && ap.flex === bp.flex;
98
- }
99
- case "divider": {
100
- if (b.kind !== "divider")
101
- return false;
102
- const ap = a.props;
103
- const bp = b.props;
104
- return (ap.direction === bp.direction &&
105
- ap.char === bp.char &&
106
- ap.label === bp.label &&
107
- ap.color === bp.color);
108
- }
109
- case "richText": {
110
- if (b.kind !== "richText")
111
- return false;
112
- const ap = a.props;
113
- const bp = b.props;
114
- const as = ap.spans;
115
- const bs = bp.spans;
116
- if (as === bs)
117
- return true;
118
- if (!as || !bs || as.length !== bs.length)
119
- return false;
120
- for (let i = 0; i < as.length; i++) {
121
- const sa = as[i];
122
- const sb = bs[i];
123
- if (!sa || !sb)
124
- return false;
125
- if (sa.text !== sb.text)
126
- return false;
127
- if (!textStyleEqual(sa.style, sb.style))
128
- return false;
129
- }
130
- return true;
131
- }
132
- default:
133
- return false;
134
- }
135
- }
136
- function boxShadowEqual(a, b) {
137
- if (a === b)
138
- return true;
139
- if (a === undefined || b === undefined)
140
- return false;
141
- if (typeof a === "boolean" || typeof b === "boolean")
142
- return a === b;
143
- if (typeof a !== "object" || typeof b !== "object" || a === null || b === null)
144
- return false;
145
- const ao = a;
146
- const bo = b;
147
- return ao.offsetX === bo.offsetX && ao.offsetY === bo.offsetY && ao.density === bo.density;
148
- }
149
- function transitionPropertiesEqual(a, b) {
150
- if (a === b)
151
- return true;
152
- if (a === undefined || b === undefined)
153
- return false;
154
- if (a === "all" || b === "all")
155
- return a === b;
156
- if (!Array.isArray(a) || !Array.isArray(b))
157
- return false;
158
- if (a.length !== b.length)
159
- return false;
160
- for (let i = 0; i < a.length; i++) {
161
- if (a[i] !== b[i])
162
- return false;
163
- }
164
- return true;
165
- }
166
- function transitionSpecEqual(a, b) {
167
- if (a === b)
168
- return true;
169
- if (a === undefined || b === undefined)
170
- return false;
171
- if (typeof a !== "object" || typeof b !== "object" || a === null || b === null)
172
- return false;
173
- const ao = a;
174
- const bo = b;
175
- return (ao.duration === bo.duration &&
176
- ao.easing === bo.easing &&
177
- transitionPropertiesEqual(ao.properties, bo.properties));
178
- }
179
- function layoutConstraintsEqual(a, b) {
180
- if (a === b)
181
- return true;
182
- const ao = (a ?? {});
183
- const bo = (b ?? {});
184
- return (ao.width === bo.width &&
185
- ao.height === bo.height &&
186
- ao.minWidth === bo.minWidth &&
187
- ao.maxWidth === bo.maxWidth &&
188
- ao.minHeight === bo.minHeight &&
189
- ao.maxHeight === bo.maxHeight &&
190
- ao.flex === bo.flex &&
191
- ao.aspectRatio === bo.aspectRatio);
192
- }
193
- function shallowRecordEqual(a, b) {
194
- const aKeys = Object.keys(a);
195
- const bKeys = Object.keys(b);
196
- if (aKeys.length !== bKeys.length)
197
- return false;
198
- for (const key of aKeys) {
199
- if (!(key in b))
200
- return false;
201
- if (!Object.is(a[key], b[key]))
202
- return false;
203
- }
204
- return true;
205
- }
206
- function compositePropsEqual(prev, next) {
207
- if (Object.is(prev, next))
208
- return true;
209
- if (typeof prev !== "object" || prev === null)
210
- return false;
211
- if (typeof next !== "object" || next === null)
212
- return false;
213
- return shallowRecordEqual(prev, next);
214
- }
215
- function evaluateAppStateSelections(selections, appState) {
216
- for (const selection of selections) {
217
- try {
218
- const nextValue = selection.selector(appState);
219
- if (!Object.is(nextValue, selection.value)) {
220
- return { changed: true, threw: null };
221
- }
222
- }
223
- catch (e) {
224
- return { changed: true, threw: e };
225
- }
226
- }
227
- return { changed: false, threw: null };
228
- }
229
- function spacingPropsEqual(a, b) {
230
- if (a === b)
231
- return true;
232
- const ao = (a ?? {});
233
- const bo = (b ?? {});
234
- return (ao.p === bo.p &&
235
- ao.px === bo.px &&
236
- ao.py === bo.py &&
237
- ao.pt === bo.pt &&
238
- ao.pb === bo.pb &&
239
- ao.pl === bo.pl &&
240
- ao.pr === bo.pr &&
241
- ao.m === bo.m &&
242
- ao.mx === bo.mx &&
243
- ao.my === bo.my &&
244
- ao.mt === bo.mt &&
245
- ao.mr === bo.mr &&
246
- ao.mb === bo.mb &&
247
- ao.ml === bo.ml);
248
- }
249
- function boxPropsEqual(a, b) {
250
- if (a === b)
251
- return true;
252
- const ao = (a ?? {});
253
- const bo = (b ?? {});
254
- return (ao.title === bo.title &&
255
- ao.titleAlign === bo.titleAlign &&
256
- ao.pad === bo.pad &&
257
- ao.border === bo.border &&
258
- ao.borderTop === bo.borderTop &&
259
- ao.borderRight === bo.borderRight &&
260
- ao.borderBottom === bo.borderBottom &&
261
- ao.borderLeft === bo.borderLeft &&
262
- boxShadowEqual(ao.shadow, bo.shadow) &&
263
- textStyleEqual(ao.style, bo.style) &&
264
- textStyleEqual(ao.inheritStyle, bo.inheritStyle) &&
265
- ao.opacity === bo.opacity &&
266
- transitionSpecEqual(ao.transition, bo.transition) &&
267
- transitionSpecEqual(ao.exitTransition, bo.exitTransition) &&
268
- spacingPropsEqual(ao, bo) &&
269
- layoutConstraintsEqual(ao, bo));
270
- }
271
- function stackPropsEqual(a, b) {
272
- if (a === b)
273
- return true;
274
- const ao = (a ?? {});
275
- const bo = (b ?? {});
276
- return (ao.pad === bo.pad &&
277
- ao.gap === bo.gap &&
278
- ao.align === bo.align &&
279
- ao.justify === bo.justify &&
280
- ao.items === bo.items &&
281
- textStyleEqual(ao.style, bo.style) &&
282
- textStyleEqual(ao.inheritStyle, bo.inheritStyle) &&
283
- transitionSpecEqual(ao.transition, bo.transition) &&
284
- transitionSpecEqual(ao.exitTransition, bo.exitTransition) &&
285
- spacingPropsEqual(ao, bo) &&
286
- layoutConstraintsEqual(ao, bo));
287
- }
288
- function focusZonePropsEqual(a, b) {
289
- if (a === b)
290
- return true;
291
- const ao = (a ?? {});
292
- const bo = (b ?? {});
293
- return (ao.id === bo.id &&
294
- ao.tabIndex === bo.tabIndex &&
295
- ao.navigation === bo.navigation &&
296
- ao.columns === bo.columns &&
297
- ao.wrapAround === bo.wrapAround &&
298
- ao.onEnter === bo.onEnter &&
299
- ao.onExit === bo.onExit);
300
- }
301
- function focusTrapPropsEqual(a, b) {
302
- if (a === b)
303
- return true;
304
- const ao = (a ?? {});
305
- const bo = (b ?? {});
306
- return (ao.id === bo.id &&
307
- ao.active === bo.active &&
308
- ao.returnFocusTo === bo.returnFocusTo &&
309
- ao.initialFocus === bo.initialFocus);
310
- }
311
- function deepEqualUnknown(a, b) {
312
- if (a === b)
313
- return true;
314
- if (typeof a !== typeof b)
315
- return false;
316
- if (typeof a !== "object" || a === null || b === null)
317
- return false;
318
- if (Array.isArray(a) || Array.isArray(b)) {
319
- if (!Array.isArray(a) || !Array.isArray(b))
320
- return false;
321
- if (a.length !== b.length)
322
- return false;
323
- for (let i = 0; i < a.length; i++) {
324
- if (!deepEqualUnknown(a[i], b[i]))
325
- return false;
326
- }
327
- return true;
328
- }
329
- const aRecord = a;
330
- const bRecord = b;
331
- const aKeys = Object.keys(aRecord);
332
- const bKeys = Object.keys(bRecord);
333
- if (aKeys.length !== bKeys.length)
334
- return false;
335
- for (const key of aKeys) {
336
- if (!Object.prototype.hasOwnProperty.call(bRecord, key))
337
- return false;
338
- if (!deepEqualUnknown(aRecord[key], bRecord[key]))
339
- return false;
340
- }
341
- return true;
342
- }
343
- function themedPropsEqual(a, b) {
344
- if (a === b)
345
- return true;
346
- const ao = (a ?? {});
347
- const bo = (b ?? {});
348
- return deepEqualUnknown(ao.theme, bo.theme);
349
- }
350
- function fragmentPropsEqual(a, b) {
351
- if (a === b)
352
- return true;
353
- const ao = (a ?? {});
354
- const bo = (b ?? {});
355
- return ao.key === bo.key;
356
- }
357
- function canFastReuseContainerSelf(prev, next) {
358
- if (prev.kind !== next.kind)
359
- return false;
360
- switch (prev.kind) {
361
- case "fragment":
362
- return fragmentPropsEqual(prev.props, next.props);
363
- case "box":
364
- return boxPropsEqual(prev.props, next.props);
365
- case "row":
366
- case "column":
367
- return stackPropsEqual(prev.props, next.props);
368
- case "focusZone":
369
- return focusZonePropsEqual(prev.props, next.props);
370
- case "focusTrap":
371
- return focusTrapPropsEqual(prev.props, next.props);
372
- case "themed":
373
- return themedPropsEqual(prev.props, next.props);
374
- default:
375
- return false;
376
- }
377
- }
378
- /**
379
- * Diagnostic: identify which specific prop fails for container reuse.
380
- * Only called when __commitDiag.enabled is true.
381
- */
382
- function diagWhichPropFails(prev, next) {
383
- if (prev.kind !== next.kind)
384
- return "kind";
385
- const ap = (prev.props ?? {});
386
- const bp = (next.props ?? {});
387
- if (prev.kind === "fragment" && ap.key !== bp.key) {
388
- return "key";
389
- }
390
- if (prev.kind === "row" || prev.kind === "column") {
391
- for (const k of ["pad", "gap", "align", "justify", "items"]) {
392
- if (ap[k] !== bp[k])
393
- return k;
394
- }
395
- if (!textStyleEqual(ap.style, bp.style))
396
- return "style";
397
- if (!textStyleEqual(ap.inheritStyle, bp.inheritStyle))
398
- return "inheritStyle";
399
- // layout constraints
400
- for (const k of [
401
- "width",
402
- "height",
403
- "minWidth",
404
- "maxWidth",
405
- "minHeight",
406
- "maxHeight",
407
- "flex",
408
- "aspectRatio",
409
- ]) {
410
- if (ap[k] !== bp[k])
411
- return k;
412
- }
413
- // spacing
414
- for (const k of [
415
- "p",
416
- "px",
417
- "py",
418
- "pt",
419
- "pb",
420
- "pl",
421
- "pr",
422
- "m",
423
- "mx",
424
- "my",
425
- "mt",
426
- "mr",
427
- "mb",
428
- "ml",
429
- ]) {
430
- if (ap[k] !== bp[k])
431
- return k;
432
- }
433
- }
434
- if (prev.kind === "box") {
435
- for (const k of [
436
- "title",
437
- "titleAlign",
438
- "pad",
439
- "border",
440
- "borderTop",
441
- "borderRight",
442
- "borderBottom",
443
- "borderLeft",
444
- "opacity",
445
- ]) {
446
- if (ap[k] !== bp[k])
447
- return k;
448
- }
449
- if (!textStyleEqual(ap.style, bp.style))
450
- return "style";
451
- for (const k of [
452
- "width",
453
- "height",
454
- "minWidth",
455
- "maxWidth",
456
- "minHeight",
457
- "maxHeight",
458
- "flex",
459
- "aspectRatio",
460
- ]) {
461
- if (ap[k] !== bp[k])
462
- return k;
463
- }
464
- }
465
- return "unknown";
466
- }
467
- function runtimeChildrenChanged(prevChildren, nextChildren) {
468
- if (prevChildren.length !== nextChildren.length)
469
- return true;
470
- for (let i = 0; i < prevChildren.length; i++) {
471
- if (prevChildren[i] !== nextChildren[i])
472
- return true;
473
- }
474
- return false;
475
- }
476
- function hasDirtyChild(children) {
477
- for (const child of children) {
478
- if (child.dirty)
479
- return true;
480
- }
481
- return false;
482
- }
483
- const NODE_ENV = globalThis.process?.env?.NODE_ENV ??
484
- "development";
485
- const DEV_MODE = NODE_ENV !== "production";
486
- const LAYOUT_DEPTH_WARN_THRESHOLD = 200;
487
- const MAX_LAYOUT_NESTING_DEPTH = 500;
488
- const MAX_LAYOUT_DEPTH_PATH_SEGMENTS = 32;
489
- const MAX_INTERACTIVE_ID_LENGTH = 256;
490
- const DEFAULT_EXIT_TRANSITION_DURATION_MS = 180;
491
- const LAYOUT_DEPTH_PATH_TRACK_START = Math.max(1, LAYOUT_DEPTH_WARN_THRESHOLD - MAX_LAYOUT_DEPTH_PATH_SEGMENTS + 2);
492
- function warnDev(message) {
493
- const c = globalThis.console;
494
- c?.warn?.(message);
495
- }
496
- function widgetPathEntry(vnode) {
497
- const props = vnode.props;
498
- const id = typeof props?.id === "string" && props.id.length > 0 ? `#${props.id}` : "";
499
- const key = typeof props?.key === "string" || typeof props?.key === "number"
500
- ? `[key=${String(props.key)}]`
501
- : "";
502
- return `${vnode.kind}${id}${key}`;
503
- }
504
- function formatWidgetPath(depth, tailPath) {
505
- if (tailPath.length === 0)
506
- return "(root)";
507
- const path = tailPath.join(" -> ");
508
- return depth > tailPath.length ? `... -> ${path}` : path;
509
- }
510
- function isInteractiveVNode(v) {
511
- const proto = getWidgetProtocol(v.kind);
512
- return proto.requiresId || proto.focusable || proto.pressable;
513
- }
514
- function ensureInteractiveId(seen, instanceId, vnode) {
515
- if (!isInteractiveVNode(vnode))
516
- return null;
517
- // Runtime validation (even though most interactive widgets are typed with required ids).
518
- const id = vnode.props.id;
519
- if (typeof id !== "string" || id.length === 0) {
520
- if (!kindRequiresId(vnode.kind))
521
- return null;
522
- return {
523
- code: "ZRUI_INVALID_PROPS",
524
- detail: `interactive node missing required id (kind=${vnode.kind}, instanceId=${String(instanceId)})`,
525
- };
526
- }
527
- if (id.trim().length === 0) {
528
- return {
529
- code: "ZRUI_INVALID_PROPS",
530
- detail: `interactive node id must contain non-whitespace characters (kind=${vnode.kind}, instanceId=${String(instanceId)})`,
531
- };
532
- }
533
- const existing = seen.get(id);
534
- if (existing !== undefined) {
535
- return {
536
- code: "ZRUI_DUPLICATE_ID",
537
- detail: `Duplicate interactive widget id "${id}". First: <${existing}>, second: <${vnode.kind}>. Hint: Use ctx.id() inside defineWidget to generate unique IDs for list items.`,
538
- };
539
- }
540
- if (DEV_MODE && id.length > MAX_INTERACTIVE_ID_LENGTH) {
541
- warnDev(`[rezi][commit] interactive widget id exceeds ${String(MAX_INTERACTIVE_ID_LENGTH)} chars (kind=${vnode.kind}, id length=${String(id.length)}). Consider using shorter IDs.`);
542
- }
543
- seen.set(id, vnode.kind);
544
- return null;
545
- }
546
- function isFocusContainerVNode(vnode) {
547
- return vnode.kind === "focusZone" || vnode.kind === "focusTrap" || vnode.kind === "modal";
548
- }
549
- function ensureFocusContainerId(seen, instanceId, vnode) {
550
- if (!isFocusContainerVNode(vnode))
551
- return null;
552
- const id = vnode.props.id;
553
- if (typeof id !== "string" || id.length === 0) {
554
- return {
555
- code: "ZRUI_INVALID_PROPS",
556
- detail: `focus container missing required id (kind=${vnode.kind}, instanceId=${String(instanceId)})`,
557
- };
558
- }
559
- if (id.trim().length === 0) {
560
- return {
561
- code: "ZRUI_INVALID_PROPS",
562
- detail: `focus container id must contain non-whitespace characters (kind=${vnode.kind}, instanceId=${String(instanceId)})`,
563
- };
564
- }
565
- const existing = seen.get(id);
566
- if (existing !== undefined) {
567
- return {
568
- code: "ZRUI_DUPLICATE_ID",
569
- detail: `Duplicate focus container id "${id}". First: <${existing}>, second: <${vnode.kind}>. Hint: focusZone, focusTrap, and modal ids must be unique across the tree.`,
570
- };
571
- }
572
- seen.set(id, vnode.kind);
573
- return null;
574
- }
575
- function isVNode(v) {
576
- return typeof v === "object" && v !== null && "kind" in v;
577
- }
578
- function commitChildrenForVNode(vnode) {
579
- if (vnode.kind === "fragment" ||
580
- vnode.kind === "box" ||
581
- vnode.kind === "row" ||
582
- vnode.kind === "column" ||
583
- vnode.kind === "themed" ||
584
- vnode.kind === "grid" ||
585
- vnode.kind === "focusZone" ||
586
- vnode.kind === "focusTrap" ||
587
- vnode.kind === "layers" ||
588
- vnode.kind === "tabs" ||
589
- vnode.kind === "accordion" ||
590
- vnode.kind === "breadcrumb" ||
591
- vnode.kind === "pagination" ||
592
- // Advanced container widgets (GitHub issue #136)
593
- vnode.kind === "splitPane" ||
594
- vnode.kind === "panelGroup") {
595
- return vnode.children;
596
- }
597
- if (vnode.kind === "field" || vnode.kind === "resizablePanel") {
598
- const child = vnode.children[0];
599
- return child ? [child] : [];
600
- }
601
- if (vnode.kind === "layer") {
602
- const content = vnode.props.content;
603
- return isVNode(content) ? [content] : [];
604
- }
605
- if (vnode.kind === "modal") {
606
- const props = vnode.props;
607
- const content = isVNode(props.content) ? props.content : null;
608
- const actionsRaw = Array.isArray(props.actions) ? props.actions : [];
609
- const actions = [];
610
- for (const a of actionsRaw) {
611
- if (isVNode(a))
612
- actions.push(a);
613
- }
614
- const children = [];
615
- if (content)
616
- children.push(content);
617
- children.push(...actions);
618
- return children;
619
- }
620
- return [];
621
- }
622
- function collectSubtreeInstanceIds(node, out) {
623
- out.push(node.instanceId);
624
- for (const c of node.children)
625
- collectSubtreeInstanceIds(c, out);
626
- }
627
- function deleteLocalStateForSubtree(store, node) {
628
- if (!store)
629
- return;
630
- const stack = [node];
631
- while (stack.length > 0) {
632
- const cur = stack.pop();
633
- if (!cur)
634
- continue;
635
- store.delete(cur.instanceId);
636
- for (const c of cur.children)
637
- stack.push(c);
638
- }
639
- }
640
- function commitNowMs() {
641
- const perf = globalThis.performance;
642
- const perfNow = perf?.now;
643
- if (typeof perfNow === "function")
644
- return perfNow.call(perf);
645
- return Date.now();
646
- }
647
- function readVNodeKey(vnode) {
648
- const props = vnode.props;
649
- const key = props?.key;
650
- return typeof key === "string" ? key : undefined;
651
- }
652
- function readExitTransition(vnode) {
653
- if (vnode.kind !== "box" &&
654
- vnode.kind !== "row" &&
655
- vnode.kind !== "column" &&
656
- vnode.kind !== "grid") {
657
- return null;
658
- }
659
- const props = vnode.props;
660
- return props?.exitTransition ?? null;
661
- }
662
- function resolveExitAnimationState(instanceId, transition) {
663
- const durationMs = normalizeDurationMs(transition.duration, DEFAULT_EXIT_TRANSITION_DURATION_MS);
664
- if (durationMs <= 0)
665
- return null;
666
- return Object.freeze({
667
- instanceId,
668
- startMs: commitNowMs(),
669
- durationMs,
670
- easing: resolveEasing(transition.easing),
671
- properties: transition.properties ?? "all",
672
- });
673
- }
674
- function createDeferredLocalStateCleanup(localState, node) {
675
- let cleaned = false;
676
- return () => {
677
- if (cleaned)
678
- return;
679
- cleaned = true;
680
- deleteLocalStateForSubtree(localState, node);
681
- };
682
- }
683
- function tryScheduleExitAnimation(ctx, node, parentInstanceId) {
684
- const exitTransition = readExitTransition(node.vnode);
685
- if (!exitTransition)
686
- return false;
687
- const exit = resolveExitAnimationState(node.instanceId, exitTransition);
688
- if (!exit)
689
- return false;
690
- const subtreeInstanceIds = [];
691
- collectSubtreeInstanceIds(node, subtreeInstanceIds);
692
- ctx.pendingExitAnimations.push(Object.freeze({
693
- instanceId: node.instanceId,
694
- parentInstanceId,
695
- runtimeRoot: node,
696
- vnodeKind: node.vnode.kind,
697
- key: readVNodeKey(node.vnode),
698
- exit,
699
- subtreeInstanceIds: Object.freeze(subtreeInstanceIds),
700
- runDeferredLocalStateCleanup: createDeferredLocalStateCleanup(ctx.localState, node),
701
- }));
702
- return true;
703
- }
704
- function markCompositeSubtreeStale(registry, node) {
705
- const stack = [node];
706
- while (stack.length > 0) {
707
- const cur = stack.pop();
708
- if (!cur)
709
- continue;
710
- registry.incrementGeneration(cur.instanceId);
711
- for (const c of cur.children)
712
- stack.push(c);
713
- }
714
- }
715
- function currentCompositeTheme(ctx) {
716
- if (ctx.compositeThemeStack.length === 0)
717
- return null;
718
- return ctx.compositeThemeStack[ctx.compositeThemeStack.length - 1] ?? null;
719
- }
720
- function resolveCompositeChildTheme(parentTheme, vnode) {
721
- if (vnode.kind === "themed") {
722
- const props = vnode.props;
723
- return mergeThemeOverride(parentTheme, props.theme);
724
- }
725
- if (vnode.kind === "row" ||
726
- vnode.kind === "column" ||
727
- vnode.kind === "grid" ||
728
- vnode.kind === "box") {
729
- const props = vnode.props;
730
- return mergeThemeOverride(parentTheme, props.theme);
731
- }
732
- return parentTheme;
733
- }
734
- function readCompositeColorTokens(ctx) {
735
- const composite = ctx.composite;
736
- if (!composite)
737
- return defaultTheme.definition.colors;
738
- const theme = currentCompositeTheme(ctx);
739
- if (theme !== null) {
740
- if (!composite.getColorTokens)
741
- return theme.definition.colors;
742
- return composite.getColorTokens(theme) ?? theme.definition.colors;
743
- }
744
- return composite.colorTokens ?? defaultTheme.definition.colors;
745
- }
746
- const MAX_COMPOSITE_RENDER_DEPTH = 100;
747
- const DEFAULT_VIEWPORT_SNAPSHOT = Object.freeze({
748
- width: 0,
749
- height: 0,
750
- breakpoint: "sm",
751
- });
752
- function captureErrorBoundaryState(detail) {
753
- return Object.freeze({
754
- code: "ZRUI_USER_CODE_THROW",
755
- detail,
756
- message: detail,
757
- });
758
- }
759
- function commitErrorBoundaryFallback(prev, instanceId, boundaryPath, fallbackPath, props, state, ctx) {
760
- const fallback = props.fallback;
761
- if (typeof fallback !== "function") {
762
- return {
763
- ok: false,
764
- fatal: {
765
- code: "ZRUI_INVALID_PROPS",
766
- detail: "errorBoundary fallback must be a function",
767
- },
768
- };
769
- }
770
- let fallbackVNode;
771
- try {
772
- fallbackVNode = fallback(Object.freeze({
773
- code: state.code,
774
- message: state.message,
775
- detail: state.detail,
776
- ...(state.stack ? { stack: state.stack } : {}),
777
- retry: () => {
778
- ctx.errorBoundary?.requestRetry(boundaryPath);
779
- },
780
- }));
781
- }
782
- catch (e) {
783
- return {
784
- ok: false,
785
- fatal: {
786
- code: "ZRUI_USER_CODE_THROW",
787
- detail: describeThrown(e),
788
- },
789
- };
790
- }
791
- if (!isVNode(fallbackVNode)) {
792
- return {
793
- ok: false,
794
- fatal: {
795
- code: "ZRUI_INVALID_PROPS",
796
- detail: "errorBoundary fallback must return a VNode",
797
- },
798
- };
799
- }
800
- return commitNode(prev, instanceId, fallbackVNode, ctx, fallbackPath);
801
- }
802
- function appendNodePath(nodePath, segment) {
803
- return [...nodePath, segment];
804
- }
805
- function formatNodePath(nodePath) {
806
- return nodePath.join("/");
807
- }
808
- function isContainerVNode(vnode) {
809
- return (vnode.kind === "fragment" ||
810
- vnode.kind === "box" ||
811
- vnode.kind === "row" ||
812
- vnode.kind === "column" ||
813
- vnode.kind === "themed" ||
814
- vnode.kind === "grid" ||
815
- vnode.kind === "focusZone" ||
816
- vnode.kind === "focusTrap" ||
817
- vnode.kind === "layers" ||
818
- vnode.kind === "field" ||
819
- vnode.kind === "tabs" ||
820
- vnode.kind === "accordion" ||
821
- vnode.kind === "breadcrumb" ||
822
- vnode.kind === "pagination" ||
823
- // Advanced container widgets (GitHub issue #136)
824
- vnode.kind === "splitPane" ||
825
- vnode.kind === "panelGroup" ||
826
- vnode.kind === "resizablePanel" ||
827
- vnode.kind === "modal" ||
828
- vnode.kind === "layer");
829
- }
830
- function rewriteCommittedVNode(next, committedChildren) {
831
- if (next.kind === "modal") {
832
- const props = next.props;
833
- const contentPresent = isVNode(props.content);
834
- const nextContent = contentPresent ? (committedChildren[0] ?? props.content) : props.content;
835
- const actionsStart = contentPresent ? 1 : 0;
836
- const actions = committedChildren.slice(actionsStart);
837
- return {
838
- ...next,
839
- props: {
840
- ...next.props,
841
- ...(isVNode(nextContent) ? { content: nextContent } : {}),
842
- actions: actions.length > 0 ? actions : undefined,
843
- },
844
- };
845
- }
846
- if (next.kind === "layer") {
847
- const props = next.props;
848
- const nextContent = committedChildren[0] ?? props.content;
849
- return {
850
- ...next,
851
- props: {
852
- ...next.props,
853
- ...(isVNode(nextContent) ? { content: nextContent } : {}),
854
- },
855
- };
856
- }
857
- if (next.kind === "fragment" ||
858
- next.kind === "box" ||
859
- next.kind === "row" ||
860
- next.kind === "column" ||
861
- next.kind === "themed" ||
862
- next.kind === "grid" ||
863
- next.kind === "focusZone" ||
864
- next.kind === "focusTrap" ||
865
- next.kind === "layers" ||
866
- next.kind === "field" ||
867
- next.kind === "tabs" ||
868
- next.kind === "accordion" ||
869
- next.kind === "breadcrumb" ||
870
- next.kind === "pagination" ||
871
- // Advanced container widgets (GitHub issue #136)
872
- next.kind === "splitPane" ||
873
- next.kind === "panelGroup" ||
874
- next.kind === "resizablePanel") {
875
- return {
876
- ...next,
877
- children: committedChildren,
878
- };
879
- }
880
- return next;
881
- }
882
- function commitContainer(instanceId, vnode, prev, ctx, nodePath, depth) {
883
- void depth;
884
- const parentProps = vnode.props;
885
- const parentId = typeof parentProps?.id === "string" && parentProps.id.length > 0 ? parentProps.id : undefined;
886
- const prevChildren = prev ? prev.children : [];
887
- const compositeWrapperChildren = ctx.containerChildOverrides.get(instanceId) ?? null;
888
- const res = reconcileChildren(instanceId, prevChildren, compositeWrapperChildren ? compositeWrapperChildren : commitChildrenForVNode(vnode), ctx.allocator, {
889
- kind: vnode.kind,
890
- ...(parentId === undefined ? {} : { id: parentId }),
891
- });
892
- if (!res.ok)
893
- return { ok: false, fatal: res.fatal };
894
- const byPrevIndex = prevChildren;
895
- let byPrevInstanceId = null;
896
- if (res.value.unmountedInstanceIds.length > 0) {
897
- byPrevInstanceId = new Map();
898
- for (const c of prevChildren)
899
- byPrevInstanceId.set(c.instanceId, c);
900
- }
901
- const parentCompositeTheme = currentCompositeTheme(ctx);
902
- let pushedCompositeTheme = false;
903
- if (parentCompositeTheme !== null) {
904
- const nextCompositeTheme = resolveCompositeChildTheme(parentCompositeTheme, vnode);
905
- if (nextCompositeTheme !== parentCompositeTheme) {
906
- ctx.compositeThemeStack.push(nextCompositeTheme);
907
- pushedCompositeTheme = true;
908
- }
909
- }
910
- try {
911
- // Container fast path: when reconciliation reuses all children with no
912
- // additions/removals, commit each child and check if all return the exact
913
- // same RuntimeInstance reference. If so, reuse the parent's RuntimeInstance,
914
- // avoiding new arrays, VNode spreads, and RuntimeInstance allocation.
915
- const canTryFastReuse = prev !== null &&
916
- res.value.newInstanceIds.length === 0 &&
917
- res.value.unmountedInstanceIds.length === 0 &&
918
- res.value.nextChildren.length === prevChildren.length;
919
- let childOrderStable = true;
920
- if (canTryFastReuse) {
921
- for (let i = 0; i < res.value.nextChildren.length; i++) {
922
- const child = res.value.nextChildren[i];
923
- if (!child || child.prevIndex !== i) {
924
- childOrderStable = false;
925
- break;
926
- }
927
- }
928
- }
929
- // Avoid allocating nextChildren/committedChildVNodes for the common case where
930
- // everything is reused (e.g., list updates where only a couple rows change).
931
- let nextChildren = null;
932
- let committedChildVNodes = null;
933
- if (canTryFastReuse) {
934
- let allChildrenSame = true;
935
- for (let i = 0; i < res.value.nextChildren.length; i++) {
936
- const child = res.value.nextChildren[i];
937
- if (!child)
938
- continue;
939
- const prevChild = child.prevIndex !== null ? byPrevIndex[child.prevIndex] : null;
940
- const committed = commitNode(prevChild ?? null, child.instanceId, child.vnode, ctx, formatNodePath(appendNodePath(nodePath, child.slotId)));
941
- if (!committed.ok)
942
- return committed;
943
- if (allChildrenSame && committed.value.root !== prevChild) {
944
- allChildrenSame = false;
945
- // First mismatch: allocate arrays and backfill prior entries with the prevChild refs
946
- // we already proved were identical in earlier iterations.
947
- const len = res.value.nextChildren.length;
948
- const nextChildrenArr = new Array(len);
949
- const committedChildVNodesArr = new Array(len);
950
- nextChildren = nextChildrenArr;
951
- committedChildVNodes = committedChildVNodesArr;
952
- for (let j = 0; j < i; j++) {
953
- const plan = res.value.nextChildren[j];
954
- if (!plan)
955
- continue;
956
- const pc = plan.prevIndex !== null ? byPrevIndex[plan.prevIndex] : null;
957
- if (!pc)
958
- continue;
959
- nextChildrenArr[j] = pc;
960
- committedChildVNodesArr[j] = pc.vnode;
961
- }
962
- }
963
- if (!allChildrenSame) {
964
- // Arrays are allocated after the first mismatch.
965
- if (!nextChildren || !committedChildVNodes) {
966
- return {
967
- ok: false,
968
- fatal: {
969
- code: "ZRUI_INVALID_PROPS",
970
- detail: "commitNode: internal fast-reuse invariant",
971
- },
972
- };
973
- }
974
- nextChildren[i] = committed.value.root;
975
- committedChildVNodes[i] = committed.value.root.vnode;
976
- }
977
- }
978
- if (allChildrenSame &&
979
- prev !== null &&
980
- childOrderStable &&
981
- canFastReuseContainerSelf(prev.vnode, vnode)) {
982
- // Even when child RuntimeInstance references are stable, child VNodes may have
983
- // been updated via in-place child commits. Keep the parent VNode's committed
984
- // child wiring in sync so layout traverses the same tree shape as runtime.
985
- const fastReuseCommittedChildren = prev.children.map((child) => child.vnode);
986
- prev.vnode = rewriteCommittedVNode(vnode, fastReuseCommittedChildren);
987
- // All children are identical references → reuse parent entirely.
988
- // Propagate dirty from children: a child may have been mutated in-place
989
- // with dirty=true even though it returned the same reference.
990
- if (__commitDiag.enabled) {
991
- const wasDirty = prev.selfDirty;
992
- __commitDiag.push({
993
- id: instanceId,
994
- kind: vnode.kind,
995
- reason: "fast-reuse",
996
- detail: wasDirty ? "was-dirty" : undefined,
997
- });
998
- }
999
- prev.selfDirty = false;
1000
- prev.dirty = hasDirtyChild(prev.children);
1001
- return { ok: true, value: { root: prev } };
1002
- }
1003
- // Fast-path in-place mutation: children changed but props are identical.
1004
- // Mutate the existing RuntimeInstance to preserve reference identity and
1005
- // prevent parent containers from cascading new-instance creation.
1006
- if (!allChildrenSame &&
1007
- prev !== null &&
1008
- nextChildren !== null &&
1009
- committedChildVNodes !== null &&
1010
- canFastReuseContainerSelf(prev.vnode, vnode)) {
1011
- if (__commitDiag.enabled) {
1012
- let childDiffs = 0;
1013
- for (let ci = 0; ci < prevChildren.length; ci++) {
1014
- if (prevChildren[ci] !== nextChildren[ci])
1015
- childDiffs++;
1016
- }
1017
- __commitDiag.push({
1018
- id: instanceId,
1019
- kind: vnode.kind,
1020
- reason: "fast-reuse",
1021
- detail: "children-changed",
1022
- childDiffs,
1023
- prevChildren: prevChildren.length,
1024
- nextChildren: nextChildren.length,
1025
- });
1026
- }
1027
- prev.children = nextChildren;
1028
- prev.vnode = rewriteCommittedVNode(vnode, committedChildVNodes);
1029
- prev.selfDirty = true;
1030
- prev.dirty = true;
1031
- return { ok: true, value: { root: prev } };
1032
- }
1033
- // Diagnostic: fast-reuse check failed at container level
1034
- if (__commitDiag.enabled && prev !== null && canTryFastReuse) {
1035
- if (!allChildrenSame) {
1036
- // children are different — but WHY? count how many differ
1037
- let childDiffs = 0;
1038
- for (let ci = 0; ci < prevChildren.length; ci++) {
1039
- if (nextChildren &&
1040
- prevChildren[ci] !== nextChildren[ci])
1041
- childDiffs++;
1042
- }
1043
- // also check if props would have passed
1044
- const propsOk = canFastReuseContainerSelf(prev.vnode, vnode);
1045
- __commitDiag.push({
1046
- id: instanceId,
1047
- kind: vnode.kind,
1048
- reason: "new-instance",
1049
- detail: propsOk ? "children-changed" : "props+children",
1050
- failingProp: propsOk ? undefined : diagWhichPropFails(prev.vnode, vnode),
1051
- childDiffs,
1052
- prevChildren: prevChildren.length,
1053
- nextChildren: nextChildren
1054
- ? nextChildren.length
1055
- : res.value.nextChildren.length,
1056
- });
1057
- }
1058
- else if (!childOrderStable) {
1059
- __commitDiag.push({
1060
- id: instanceId,
1061
- kind: vnode.kind,
1062
- reason: "new-instance",
1063
- detail: "children-changed",
1064
- });
1065
- }
1066
- else {
1067
- // allChildrenSame && childOrderStable but canFastReuseContainerSelf failed
1068
- __commitDiag.push({
1069
- id: instanceId,
1070
- kind: vnode.kind,
1071
- reason: "new-instance",
1072
- detail: "props-changed",
1073
- failingProp: diagWhichPropFails(prev.vnode, vnode),
1074
- });
1075
- }
1076
- }
1077
- }
1078
- else {
1079
- // General path: commit children and build next arrays.
1080
- const nextChildrenArr = [];
1081
- const committedChildVNodesArr = [];
1082
- for (const child of res.value.nextChildren) {
1083
- const prevChild = child.prevIndex !== null ? byPrevIndex[child.prevIndex] : null;
1084
- const committed = commitNode(prevChild ?? null, child.instanceId, child.vnode, ctx, formatNodePath(appendNodePath(nodePath, child.slotId)));
1085
- if (!committed.ok)
1086
- return committed;
1087
- nextChildrenArr.push(committed.value.root);
1088
- committedChildVNodesArr.push(committed.value.root.vnode);
1089
- }
1090
- nextChildren = nextChildrenArr;
1091
- committedChildVNodes = committedChildVNodesArr;
1092
- }
1093
- for (const unmountedId of res.value.unmountedInstanceIds) {
1094
- const prevNode = byPrevInstanceId?.get(unmountedId);
1095
- if (!prevNode)
1096
- continue;
1097
- if (tryScheduleExitAnimation(ctx, prevNode, instanceId)) {
1098
- continue;
1099
- }
1100
- if (ctx.composite) {
1101
- markCompositeSubtreeStale(ctx.composite.registry, prevNode);
1102
- }
1103
- deleteLocalStateForSubtree(ctx.localState, prevNode);
1104
- collectSubtreeInstanceIds(prevNode, ctx.lists.unmounted);
1105
- }
1106
- if (!nextChildren || !committedChildVNodes) {
1107
- // All committed children matched existing instances, but we still need to
1108
- // materialize the next order (e.g., keyed reorders) when parent reuse is disallowed.
1109
- const reorderedChildren = [];
1110
- const reorderedVNodes = [];
1111
- for (const child of res.value.nextChildren) {
1112
- const reused = child.prevIndex !== null ? byPrevIndex[child.prevIndex] : null;
1113
- if (!reused)
1114
- continue;
1115
- reorderedChildren.push(reused);
1116
- reorderedVNodes.push(reused.vnode);
1117
- }
1118
- nextChildren = reorderedChildren;
1119
- committedChildVNodes = reorderedVNodes;
1120
- }
1121
- if (!committedChildVNodes) {
1122
- return {
1123
- ok: false,
1124
- fatal: {
1125
- code: "ZRUI_INVALID_PROPS",
1126
- detail: "commit invariant violated: missing committed child VNodes",
1127
- },
1128
- };
1129
- }
1130
- const propsChanged = prev === null || !canFastReuseContainerSelf(prev.vnode, vnode);
1131
- const childrenChanged = prev === null || runtimeChildrenChanged(prevChildren, nextChildren);
1132
- const selfDirty = propsChanged || childrenChanged;
1133
- // Diagnostic: general-path new-instance (only if not already logged by fast-reuse diagnostic)
1134
- if (__commitDiag.enabled && !canTryFastReuse && prev !== null) {
1135
- let cDiffs = 0;
1136
- const minLen = Math.min(prevChildren.length, nextChildren.length);
1137
- for (let ci = 0; ci < minLen; ci++) {
1138
- if (prevChildren[ci] !== nextChildren[ci])
1139
- cDiffs++;
1140
- }
1141
- cDiffs += Math.abs(prevChildren.length - nextChildren.length);
1142
- __commitDiag.push({
1143
- id: instanceId,
1144
- kind: vnode.kind,
1145
- reason: "new-instance",
1146
- detail: propsChanged && childrenChanged
1147
- ? "props+children"
1148
- : propsChanged
1149
- ? "props-changed"
1150
- : childrenChanged
1151
- ? "children-changed"
1152
- : "general-path",
1153
- failingProp: propsChanged ? diagWhichPropFails(prev.vnode, vnode) : undefined,
1154
- childDiffs: cDiffs,
1155
- prevChildren: prevChildren.length,
1156
- nextChildren: nextChildren.length,
1157
- });
1158
- }
1159
- else if (__commitDiag.enabled && prev === null) {
1160
- __commitDiag.push({
1161
- id: instanceId,
1162
- kind: vnode.kind,
1163
- reason: "new-instance",
1164
- detail: "no-prev",
1165
- });
1166
- }
1167
- // In-place mutation: when props are unchanged and only children references
1168
- // changed, mutate the existing RuntimeInstance to preserve reference identity.
1169
- // This prevents parent containers from cascading new-instance creation.
1170
- if (prev !== null && !propsChanged && childrenChanged) {
1171
- prev.children = nextChildren;
1172
- prev.vnode = rewriteCommittedVNode(vnode, committedChildVNodes);
1173
- prev.selfDirty = true;
1174
- prev.dirty = true;
1175
- return { ok: true, value: { root: prev } };
1176
- }
1177
- return {
1178
- ok: true,
1179
- value: {
1180
- root: {
1181
- instanceId,
1182
- vnode: rewriteCommittedVNode(vnode, committedChildVNodes),
1183
- children: nextChildren,
1184
- dirty: selfDirty || childrenChanged || hasDirtyChild(nextChildren),
1185
- selfDirty,
1186
- renderPacketKey: prev?.renderPacketKey ?? 0,
1187
- renderPacket: prev?.renderPacket ?? null,
1188
- },
1189
- },
1190
- };
1191
- }
1192
- finally {
1193
- if (pushedCompositeTheme) {
1194
- ctx.compositeThemeStack.pop();
1195
- }
1196
- }
1197
- }
1198
- function executeCompositeRender(instanceId, vnode, compositeMeta, ctx, nodePath, depth) {
1199
- const prev = ctx.prevNodeStack.length > 0 ? (ctx.prevNodeStack[ctx.prevNodeStack.length - 1] ?? null) : null;
1200
- const compositeRuntime = ctx.composite;
1201
- let compositeChild = null;
1202
- let popCompositeStack = false;
1203
- try {
1204
- const activeCompositeMeta = compositeMeta;
1205
- const registry = compositeRuntime.registry;
1206
- const existing = registry.get(instanceId);
1207
- if (existing && existing.widgetKey !== compositeMeta.widgetKey) {
1208
- // Same instanceId but different widget type: invalidate stale closures and remount hooks.
1209
- registry.incrementGeneration(instanceId);
1210
- registry.delete(instanceId);
1211
- }
1212
- if (!registry.get(instanceId)) {
1213
- try {
1214
- registry.create(instanceId, compositeMeta.widgetKey);
1215
- }
1216
- catch (e) {
1217
- return {
1218
- ok: false,
1219
- fatal: {
1220
- code: "ZRUI_USER_CODE_THROW",
1221
- detail: describeThrown(e),
1222
- },
1223
- };
1224
- }
1225
- }
1226
- const state = registry.get(instanceId);
1227
- if (!state) {
1228
- return {
1229
- ok: false,
1230
- fatal: {
1231
- code: "ZRUI_INVALID_PROPS",
1232
- detail: `composite state missing for instanceId=${String(instanceId)}`,
1233
- },
1234
- };
1235
- }
1236
- const invalidateInstance = () => {
1237
- registry.invalidate(instanceId);
1238
- ctx.composite?.onInvalidate(instanceId);
1239
- };
1240
- const prevMeta = prev ? getCompositeMeta(prev.vnode) : null;
1241
- const prevChild = prev?.children[0] ?? null;
1242
- const previousSelections = registry.getAppStateSelections(instanceId);
1243
- const skipRenderEligible = !state.needsRender &&
1244
- previousSelections.length > 0 &&
1245
- prevMeta !== null &&
1246
- prevChild !== null &&
1247
- prevMeta.widgetKey === activeCompositeMeta.widgetKey &&
1248
- compositePropsEqual(prevMeta.props, activeCompositeMeta.props);
1249
- let canSkipCompositeRender = false;
1250
- if (skipRenderEligible) {
1251
- const evalRes = evaluateAppStateSelections(previousSelections, compositeRuntime.appState);
1252
- if (evalRes.threw !== null) {
1253
- return {
1254
- ok: false,
1255
- fatal: {
1256
- code: "ZRUI_USER_CODE_THROW",
1257
- detail: describeThrown(evalRes.threw),
1258
- },
1259
- };
1260
- }
1261
- canSkipCompositeRender = !evalRes.changed;
1262
- }
1263
- if (canSkipCompositeRender && prevChild !== null) {
1264
- compositeChild = prevChild.vnode;
1265
- }
1266
- else {
1267
- let colorTokens;
1268
- try {
1269
- colorTokens = readCompositeColorTokens(ctx);
1270
- }
1271
- catch (e) {
1272
- return {
1273
- ok: false,
1274
- fatal: {
1275
- code: "ZRUI_USER_CODE_THROW",
1276
- detail: describeThrown(e),
1277
- },
1278
- };
1279
- }
1280
- const compositeDepth = ctx.compositeRenderStack.length + 1;
1281
- if (compositeDepth > MAX_COMPOSITE_RENDER_DEPTH) {
1282
- const chain = ctx.compositeRenderStack
1283
- .map((entry) => entry.widgetKey)
1284
- .concat(activeCompositeMeta.widgetKey)
1285
- .join(" -> ");
1286
- return {
1287
- ok: false,
1288
- fatal: {
1289
- code: "ZRUI_INVALID_PROPS",
1290
- detail: `ZRUI_MAX_DEPTH: composite render depth ${String(compositeDepth)} exceeds max ${String(MAX_COMPOSITE_RENDER_DEPTH)}. Chain: ${chain}`,
1291
- },
1292
- };
1293
- }
1294
- registry.beginRender(instanceId);
1295
- const hookCtx = createHookContext(state, invalidateInstance);
1296
- const nextSelections = [];
1297
- const widgetCtx = Object.freeze({
1298
- id: (suffix) => scopedId(activeCompositeMeta.widgetKey, instanceId, suffix),
1299
- useState: hookCtx.useState,
1300
- useReducer: hookCtx.useReducer,
1301
- useRef: hookCtx.useRef,
1302
- useEffect: hookCtx.useEffect,
1303
- useMemo: hookCtx.useMemo,
1304
- useCallback: hookCtx.useCallback,
1305
- useAppState: (selector) => {
1306
- const selected = selector(compositeRuntime.appState);
1307
- nextSelections.push({
1308
- selector: selector,
1309
- value: selected,
1310
- });
1311
- return selected;
1312
- },
1313
- useTheme: () => colorTokens,
1314
- useViewport: () => {
1315
- compositeRuntime.onUseViewport?.();
1316
- return compositeRuntime.viewport ?? DEFAULT_VIEWPORT_SNAPSHOT;
1317
- },
1318
- invalidate: invalidateInstance,
1319
- });
1320
- ctx.compositeRenderStack.push({
1321
- widgetKey: activeCompositeMeta.widgetKey,
1322
- instanceId,
1323
- });
1324
- popCompositeStack = true;
1325
- try {
1326
- compositeChild = activeCompositeMeta.render(widgetCtx);
1327
- }
1328
- catch (e) {
1329
- return {
1330
- ok: false,
1331
- fatal: {
1332
- code: "ZRUI_USER_CODE_THROW",
1333
- detail: describeThrown(e),
1334
- },
1335
- };
1336
- }
1337
- try {
1338
- const pending = registry.endRender(instanceId);
1339
- const pendingCleanups = registry.getPendingCleanups(instanceId);
1340
- for (const cleanup of pendingCleanups)
1341
- ctx.pendingCleanups.push(cleanup);
1342
- for (const eff of pending)
1343
- ctx.pendingEffects.push(eff);
1344
- registry.setAppStateSelections(instanceId, nextSelections);
1345
- }
1346
- catch (e) {
1347
- return {
1348
- ok: false,
1349
- fatal: {
1350
- code: "ZRUI_USER_CODE_THROW",
1351
- detail: describeThrown(e),
1352
- },
1353
- };
1354
- }
1355
- }
1356
- if (isContainerVNode(vnode)) {
1357
- const childOverride = compositeChild ? [compositeChild] : null;
1358
- if (childOverride) {
1359
- ctx.containerChildOverrides.set(instanceId, childOverride);
1360
- }
1361
- try {
1362
- return commitContainer(instanceId, vnode, prev, ctx, nodePath, depth);
1363
- }
1364
- finally {
1365
- if (childOverride) {
1366
- ctx.containerChildOverrides.delete(instanceId);
1367
- }
1368
- }
1369
- }
1370
- return {
1371
- ok: true,
1372
- value: {
1373
- root: {
1374
- instanceId,
1375
- vnode,
1376
- children: EMPTY_CHILDREN,
1377
- dirty: true,
1378
- selfDirty: true,
1379
- renderPacketKey: 0,
1380
- renderPacket: null,
1381
- },
1382
- },
1383
- };
1384
- }
1385
- finally {
1386
- if (popCompositeStack) {
1387
- ctx.compositeRenderStack.pop();
1388
- }
1389
- }
1390
- }
27
+ export { __commitDiag } from "./commit/equality.js";
1391
28
  function commitNode(prev, instanceId, vnode, ctx, nodePath) {
1392
29
  ctx.layoutDepthRef.value += 1;
1393
30
  const layoutDepth = ctx.layoutDepthRef.value;
@@ -1411,7 +48,6 @@ function commitNode(prev, instanceId, vnode, ctx, nodePath) {
1411
48
  },
1412
49
  };
1413
50
  }
1414
- // Temporary debug: trace commit matching (remove after investigation)
1415
51
  const commitDebug = globalThis;
1416
52
  if (commitDebug.__commitDebug) {
1417
53
  const debugLog = commitDebug.__commitDebugLog;
@@ -1419,9 +55,6 @@ function commitNode(prev, instanceId, vnode, ctx, nodePath) {
1419
55
  debugLog.push(`commitNode(${String(instanceId)}, ${vnode.kind}, prev=${prev ? `${prev.vnode.kind}:${String(prev.instanceId)}` : "null"})`);
1420
56
  }
1421
57
  }
1422
- // Leaf nodes — fast path: reuse previous RuntimeInstance when content is unchanged.
1423
- // Do this before any bookkeeping so unchanged leaf-heavy subtrees (lists, tables)
1424
- // don't pay per-node validation overhead.
1425
58
  if (prev && prev.vnode.kind === vnode.kind && leafVNodeEqual(prev.vnode, vnode)) {
1426
59
  if (__commitDiag.enabled) {
1427
60
  const wasDirty = prev.selfDirty;
@@ -1438,7 +71,6 @@ function commitNode(prev, instanceId, vnode, ctx, nodePath) {
1438
71
  prev.selfDirty = false;
1439
72
  return { ok: true, value: { root: prev } };
1440
73
  }
1441
- // Diagnostic: leaf not reused
1442
74
  if (__commitDiag.enabled && prev && !isContainerVNode(vnode)) {
1443
75
  if (prev.vnode.kind !== vnode.kind) {
1444
76
  __commitDiag.push({
@@ -1475,7 +107,7 @@ function commitNode(prev, instanceId, vnode, ctx, nodePath) {
1475
107
  const retryRequested = ctx.errorBoundary?.retryRequestedPaths.delete(nodePath) === true;
1476
108
  const existingState = ctx.errorBoundary?.errorsByPath.get(nodePath);
1477
109
  if (existingState && !retryRequested) {
1478
- return commitErrorBoundaryFallback(prev, instanceId, nodePath, fallbackPath, props, existingState, ctx);
110
+ return commitErrorBoundaryFallback(prev, instanceId, nodePath, fallbackPath, props, existingState, ctx, commitNode);
1479
111
  }
1480
112
  const committedProtected = commitNode(prev, instanceId, protectedChild, ctx, protectedPath);
1481
113
  if (committedProtected.ok) {
@@ -1487,7 +119,7 @@ function commitNode(prev, instanceId, vnode, ctx, nodePath) {
1487
119
  }
1488
120
  const trappedState = captureErrorBoundaryState(committedProtected.fatal.detail);
1489
121
  ctx.errorBoundary?.errorsByPath.set(nodePath, trappedState);
1490
- return commitErrorBoundaryFallback(prev, instanceId, nodePath, fallbackPath, props, trappedState, ctx);
122
+ return commitErrorBoundaryFallback(prev, instanceId, nodePath, fallbackPath, props, trappedState, ctx, commitNode);
1491
123
  }
1492
124
  const idFatal = ensureInteractiveId(ctx.seenInteractiveIds, instanceId, vnode);
1493
125
  if (idFatal)
@@ -1507,15 +139,12 @@ function commitNode(prev, instanceId, vnode, ctx, nodePath) {
1507
139
  if (ctx.composite) {
1508
140
  const compositeMeta = getCompositeMeta(vnode);
1509
141
  if (compositeMeta) {
1510
- return executeCompositeRender(instanceId, vnode, compositeMeta, ctx, [nodePath], layoutDepth);
142
+ return executeCompositeRender(instanceId, vnode, compositeMeta, ctx, [nodePath], layoutDepth, (nextInstanceId, nextVnode, nextPrev, nextCtx, nextNodePath, nextDepth) => commitContainer(nextInstanceId, nextVnode, nextPrev, nextCtx, nextNodePath, nextDepth, commitNode));
1511
143
  }
1512
144
  }
1513
145
  if (isContainerVNode(vnode)) {
1514
- return commitContainer(instanceId, vnode, prev, ctx, [nodePath], layoutDepth);
146
+ return commitContainer(instanceId, vnode, prev, ctx, [nodePath], layoutDepth, commitNode);
1515
147
  }
1516
- // Leaf node: when prev exists and kind matches, mutate in-place to preserve
1517
- // reference identity. This prevents parent containers from cascading new-instance
1518
- // creation when only leaf content changed.
1519
148
  if (prev !== null && prev.vnode.kind === vnode.kind) {
1520
149
  prev.vnode = vnode;
1521
150
  prev.selfDirty = true;
@@ -1544,14 +173,6 @@ function commitNode(prev, instanceId, vnode, ctx, nodePath) {
1544
173
  ctx.layoutDepthRef.value -= 1;
1545
174
  }
1546
175
  }
1547
- /**
1548
- * Deterministically commit a VNode tree into a runtime instance tree, applying
1549
- * locked reconciliation rules (docs/10) and enforcing interactive id uniqueness.
1550
- *
1551
- * Notes:
1552
- * - Uses an implicit root parent instanceId=0 for reconciliation of the returned root VNode.
1553
- * - Does not perform layout, focus, routing, or drawlist building.
1554
- */
1555
176
  export function commitVNodeTree(prevRoot, nextRootVNode, opts) {
1556
177
  const collectLifecycleInstanceIds = opts.collectLifecycleInstanceIds !== false;
1557
178
  const interactiveIdIndex = opts.interactiveIdIndex ?? new Map();
@@ -1590,8 +211,6 @@ export function commitVNodeTree(prevRoot, nextRootVNode, opts) {
1590
211
  };
1591
212
  }
1592
213
  if (prevRoot && rootPlan.prevIndex === null) {
1593
- // Root was replaced; unmount the entire previous tree before committing the new one so
1594
- // the returned lists include the unmount lifecycle deterministically.
1595
214
  if (!tryScheduleExitAnimation(ctx, prevRoot, 0)) {
1596
215
  deleteLocalStateForSubtree(opts.localState, prevRoot);
1597
216
  collectSubtreeInstanceIds(prevRoot, ctx.lists.unmounted);