neo.mjs 10.0.0-beta.5 → 10.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 (491) hide show
  1. package/.github/RELEASE_NOTES/v10.0.0-beta.1.md +20 -0
  2. package/.github/RELEASE_NOTES/v10.0.0-beta.2.md +73 -0
  3. package/.github/RELEASE_NOTES/v10.0.0-beta.3.md +39 -0
  4. package/.github/RELEASE_NOTES/v10.0.0-beta.5.md +70 -0
  5. package/.github/RELEASE_NOTES/v10.0.0-beta.6.md +48 -0
  6. package/.github/RELEASE_NOTES/v10.0.0.md +52 -0
  7. package/.github/epic-functional-components.md +498 -0
  8. package/.github/ticket-asymmetric-vdom-updates.md +122 -0
  9. package/README.md +0 -3
  10. package/ServiceWorker.mjs +2 -2
  11. package/apps/colors/store/Colors.mjs +1 -0
  12. package/apps/colors/view/GridContainer.mjs +3 -0
  13. package/apps/colors/view/HeaderToolbar.mjs +2 -0
  14. package/apps/colors/view/Viewport.mjs +3 -0
  15. package/apps/covid/view/FooterContainer.mjs +3 -0
  16. package/apps/covid/view/GalleryContainer.mjs +2 -0
  17. package/apps/covid/view/GalleryContainerController.mjs +1 -0
  18. package/apps/covid/view/HeaderContainer.mjs +2 -0
  19. package/apps/covid/view/HelixContainer.mjs +2 -0
  20. package/apps/covid/view/HelixContainerController.mjs +1 -0
  21. package/apps/covid/view/MainContainer.mjs +3 -0
  22. package/apps/covid/view/TableContainer.mjs +3 -0
  23. package/apps/covid/view/TableContainerController.mjs +1 -0
  24. package/apps/covid/view/WorldMapContainer.mjs +2 -0
  25. package/apps/covid/view/country/Gallery.mjs +3 -0
  26. package/apps/covid/view/country/Helix.mjs +8 -0
  27. package/apps/covid/view/country/HistoricalDataTable.mjs +1 -0
  28. package/apps/covid/view/country/Table.mjs +2 -0
  29. package/apps/covid/view/mapboxGl/Component.mjs +1 -0
  30. package/apps/covid/view/mapboxGl/Container.mjs +2 -0
  31. package/apps/email/EPIC_PLAN.md +58 -0
  32. package/apps/email/neo-config.json +2 -2
  33. package/apps/email/store/Emails.mjs +11 -1
  34. package/apps/email/view/ComposeView.mjs +44 -0
  35. package/apps/email/view/MainView.mjs +89 -0
  36. package/apps/email/view/Viewport.mjs +4 -33
  37. package/apps/email/view/ViewportStateProvider.mjs +3 -3
  38. package/apps/form/store/SideNav.mjs +1 -0
  39. package/apps/form/view/FormContainer.mjs +1 -0
  40. package/apps/form/view/FormPageContainer.mjs +2 -0
  41. package/apps/form/view/SideNavList.mjs +1 -0
  42. package/apps/form/view/Viewport.mjs +3 -0
  43. package/apps/portal/childapps/preview/MainContainer.mjs +1 -0
  44. package/apps/portal/index.html +1 -1
  45. package/apps/portal/store/BlogPosts.mjs +2 -0
  46. package/apps/portal/store/Content.mjs +1 -0
  47. package/apps/portal/store/ContentSections.mjs +1 -0
  48. package/apps/portal/store/Examples.mjs +1 -0
  49. package/apps/portal/view/HeaderToolbar.mjs +1 -0
  50. package/apps/portal/view/Viewport.mjs +5 -0
  51. package/apps/portal/view/ViewportController.mjs +11 -3
  52. package/apps/portal/view/about/Container.mjs +2 -0
  53. package/apps/portal/view/about/MemberContainer.mjs +7 -0
  54. package/apps/portal/view/blog/Container.mjs +2 -0
  55. package/apps/portal/view/blog/List.mjs +2 -0
  56. package/apps/portal/view/examples/List.mjs +29 -19
  57. package/apps/portal/view/examples/TabContainer.mjs +4 -0
  58. package/apps/portal/view/home/ContentBox.mjs +3 -0
  59. package/apps/portal/view/home/FeatureSection.mjs +8 -0
  60. package/apps/portal/view/home/FooterContainer.mjs +4 -1
  61. package/apps/portal/view/home/MainContainer.mjs +2 -0
  62. package/apps/portal/view/home/parts/AfterMath.mjs +2 -0
  63. package/apps/portal/view/home/parts/BaseContainer.mjs +1 -0
  64. package/apps/portal/view/home/parts/Colors.mjs +4 -0
  65. package/apps/portal/view/home/parts/Features.mjs +2 -0
  66. package/apps/portal/view/home/parts/Helix.mjs +5 -0
  67. package/apps/portal/view/home/parts/How.mjs +4 -0
  68. package/apps/portal/view/home/parts/MainNeo.mjs +1 -0
  69. package/apps/portal/view/home/parts/References.mjs +2 -0
  70. package/apps/portal/view/learn/ContentComponent.mjs +11 -5
  71. package/apps/portal/view/learn/ContentTreeList.mjs +2 -0
  72. package/apps/portal/view/learn/CubeLayoutButton.mjs +1 -0
  73. package/apps/portal/view/learn/MainContainer.mjs +4 -0
  74. package/apps/portal/view/learn/PageContainer.mjs +2 -0
  75. package/apps/portal/view/learn/PageSectionsContainer.mjs +3 -0
  76. package/apps/portal/view/learn/PageSectionsList.mjs +1 -0
  77. package/apps/portal/view/services/Component.mjs +1 -0
  78. package/apps/realworld/api/Base.mjs +1 -0
  79. package/apps/realworld/view/HeaderComponent.mjs +4 -0
  80. package/apps/realworld/view/HomeComponent.mjs +7 -0
  81. package/apps/realworld/view/MainContainer.mjs +2 -0
  82. package/apps/realworld/view/MainContainerController.mjs +2 -0
  83. package/apps/realworld/view/article/CommentComponent.mjs +3 -0
  84. package/apps/realworld/view/article/Component.mjs +17 -10
  85. package/apps/realworld/view/article/CreateCommentComponent.mjs +2 -0
  86. package/apps/realworld/view/article/CreateComponent.mjs +5 -0
  87. package/apps/realworld/view/article/PreviewComponent.mjs +9 -0
  88. package/apps/realworld/view/article/TagListComponent.mjs +2 -0
  89. package/apps/realworld/view/user/ProfileComponent.mjs +7 -0
  90. package/apps/realworld/view/user/SettingsComponent.mjs +5 -0
  91. package/apps/realworld/view/user/SignUpComponent.mjs +3 -0
  92. package/apps/realworld2/api/Base.mjs +1 -0
  93. package/apps/realworld2/view/FooterComponent.mjs +1 -0
  94. package/apps/realworld2/view/HeaderToolbar.mjs +3 -0
  95. package/apps/realworld2/view/HomeContainer.mjs +1 -0
  96. package/apps/realworld2/view/MainContainer.mjs +2 -0
  97. package/apps/realworld2/view/MainContainerController.mjs +1 -0
  98. package/apps/realworld2/view/article/Helix.mjs +1 -0
  99. package/apps/realworld2/view/article/PreviewComponent.mjs +9 -0
  100. package/apps/realworld2/view/article/PreviewList.mjs +1 -0
  101. package/apps/realworld2/view/article/TagListComponent.mjs +2 -0
  102. package/apps/route/view/CenterContainer.mjs +1 -0
  103. package/apps/route/view/MainView.mjs +1 -0
  104. package/apps/sharedcovid/childapps/sharedcovidchart/MainContainer.mjs +1 -0
  105. package/apps/sharedcovid/childapps/sharedcovidgallery/MainContainer.mjs +1 -0
  106. package/apps/sharedcovid/childapps/sharedcovidhelix/MainContainer.mjs +1 -0
  107. package/apps/sharedcovid/childapps/sharedcovidmap/MainContainer.mjs +1 -0
  108. package/apps/sharedcovid/view/FooterContainer.mjs +3 -0
  109. package/apps/sharedcovid/view/GalleryContainer.mjs +2 -0
  110. package/apps/sharedcovid/view/GalleryContainerController.mjs +1 -0
  111. package/apps/sharedcovid/view/HeaderContainer.mjs +2 -0
  112. package/apps/sharedcovid/view/HelixContainer.mjs +2 -0
  113. package/apps/sharedcovid/view/HelixContainerController.mjs +1 -0
  114. package/apps/sharedcovid/view/MainContainer.mjs +3 -0
  115. package/apps/sharedcovid/view/TableContainer.mjs +3 -0
  116. package/apps/sharedcovid/view/TableContainerController.mjs +1 -0
  117. package/apps/sharedcovid/view/WorldMapContainer.mjs +2 -0
  118. package/apps/sharedcovid/view/country/Gallery.mjs +3 -0
  119. package/apps/sharedcovid/view/country/Helix.mjs +8 -0
  120. package/apps/sharedcovid/view/country/HistoricalDataTable.mjs +1 -0
  121. package/apps/sharedcovid/view/country/Table.mjs +2 -0
  122. package/apps/sharedcovid/view/mapboxGl/Component.mjs +1 -0
  123. package/apps/sharedcovid/view/mapboxGl/Container.mjs +2 -0
  124. package/apps/shareddialog/childapps/shareddialog2/view/MainContainer.mjs +2 -0
  125. package/apps/shareddialog/view/DemoDialog.mjs +2 -0
  126. package/apps/shareddialog/view/MainContainer.mjs +2 -0
  127. package/apps/shareddialog/view/MainContainerController.mjs +1 -0
  128. package/buildScripts/addReactiveTags.mjs +191 -0
  129. package/buildScripts/checkReactiveTags.mjs +160 -0
  130. package/docs/app/store/Api.mjs +1 -0
  131. package/docs/app/store/Examples.mjs +1 -0
  132. package/docs/app/view/ApiTreeList.mjs +1 -0
  133. package/docs/app/view/ContentTabContainer.mjs +2 -0
  134. package/docs/app/view/ExamplesTreeList.mjs +2 -0
  135. package/docs/app/view/HeaderContainer.mjs +3 -0
  136. package/docs/app/view/MainContainer.mjs +5 -0
  137. package/docs/app/view/classdetails/HeaderComponent.mjs +1 -0
  138. package/docs/app/view/classdetails/MainContainer.mjs +3 -0
  139. package/docs/app/view/classdetails/MembersList.mjs +5 -0
  140. package/docs/app/view/classdetails/SourceViewComponent.mjs +2 -0
  141. package/examples/ConfigurationViewport.mjs +14 -8
  142. package/examples/calendar/weekview/MainContainer.mjs +4 -0
  143. package/examples/component/coronaGallery/CountryGallery.mjs +2 -0
  144. package/examples/component/coronaGallery/CountryStore.mjs +1 -0
  145. package/examples/component/coronaGallery/Viewport.mjs +3 -0
  146. package/examples/component/coronaGallery/ViewportController.mjs +1 -0
  147. package/examples/component/coronaHelix/CountryHelix.mjs +7 -0
  148. package/examples/component/coronaHelix/MainContainer.mjs +1 -0
  149. package/examples/component/gallery/ImageStore.mjs +1 -0
  150. package/examples/component/helix/ImageStore.mjs +1 -0
  151. package/examples/component/helix/Viewport.mjs +3 -0
  152. package/examples/component/helix/ViewportController.mjs +1 -0
  153. package/examples/component/multiWindowCoronaGallery/childapp/Viewport.mjs +1 -0
  154. package/examples/component/multiWindowHelix/childapp/Viewport.mjs +1 -0
  155. package/examples/component/wrapper/googleMaps/MapComponent.mjs +2 -0
  156. package/examples/core/config/MainContainer.mjs +2 -0
  157. package/examples/dialog/DemoDialog.mjs +2 -0
  158. package/examples/dialog/MainContainer.mjs +1 -0
  159. package/examples/form/field/color/MainStore.mjs +1 -0
  160. package/examples/functional/button/base/MainContainer.mjs +207 -0
  161. package/examples/functional/button/base/app.mjs +6 -0
  162. package/examples/functional/button/base/index.html +11 -0
  163. package/examples/functional/button/base/neo-config.json +6 -0
  164. package/examples/functional/defineComponent/Component.mjs +18 -0
  165. package/examples/functional/defineComponent/MainContainer.mjs +41 -0
  166. package/examples/functional/defineComponent/app.mjs +6 -0
  167. package/examples/functional/defineComponent/index.html +11 -0
  168. package/examples/functional/defineComponent/neo-config.json +6 -0
  169. package/examples/functional/hostComponent/Component.mjs +32 -0
  170. package/examples/functional/hostComponent/MainContainer.mjs +48 -0
  171. package/examples/functional/hostComponent/app.mjs +6 -0
  172. package/examples/functional/hostComponent/index.html +11 -0
  173. package/examples/functional/hostComponent/neo-config.json +6 -0
  174. package/examples/grid/animatedRowSorting/Viewport.mjs +1 -1
  175. package/examples/grid/bigData/ControlsContainer.mjs +3 -0
  176. package/examples/grid/bigData/GridContainer.mjs +4 -2
  177. package/examples/grid/bigData/MainContainer.mjs +2 -0
  178. package/examples/grid/bigData/MainModel.mjs +1 -0
  179. package/examples/grid/bigData/MainStore.mjs +3 -0
  180. package/examples/grid/cellEditing/MainContainer.mjs +1 -1
  181. package/examples/grid/container/MainContainer.mjs +1 -1
  182. package/examples/grid/covid/GridContainer.mjs +3 -0
  183. package/examples/grid/covid/MainContainer.mjs +2 -0
  184. package/examples/grid/covid/Store.mjs +1 -0
  185. package/examples/grid/nestedRecordFields/EditUserDialog.mjs +3 -0
  186. package/examples/grid/nestedRecordFields/Viewport.mjs +3 -1
  187. package/examples/list/animate/List.mjs +4 -0
  188. package/examples/list/animate/MainContainer.mjs +2 -0
  189. package/examples/list/circle/MainStore.mjs +1 -0
  190. package/examples/list/color/MainStore.mjs +1 -0
  191. package/examples/preloadingAssets/view/MainContainer.mjs +2 -0
  192. package/examples/stateProvider/advanced/MainContainer.mjs +1 -0
  193. package/examples/stateProvider/dialog/EditUserDialog.mjs +2 -0
  194. package/examples/stateProvider/dialog/MainContainer.mjs +1 -0
  195. package/examples/stateProvider/extendedClass/MainContainer.mjs +2 -0
  196. package/examples/stateProvider/inline/MainContainer.mjs +1 -0
  197. package/examples/stateProvider/inlineNoStateProvider/MainContainer.mjs +1 -0
  198. package/examples/stateProvider/inlineNoStateProvider/MainContainerController.mjs +2 -0
  199. package/examples/stateProvider/multiWindow/EditUserDialog.mjs +3 -0
  200. package/examples/stateProvider/multiWindow/MainContainer.mjs +1 -0
  201. package/examples/stateProvider/multiWindow/Viewport.mjs +1 -0
  202. package/examples/stateProvider/nestedData/MainContainer.mjs +1 -0
  203. package/examples/stateProvider/table/MainContainer.mjs +1 -0
  204. package/examples/table/covid/MainContainer.mjs +2 -0
  205. package/examples/table/covid/Store.mjs +1 -0
  206. package/examples/table/covid/TableContainer.mjs +3 -0
  207. package/examples/table/nestedRecordFields/EditUserDialog.mjs +3 -0
  208. package/examples/table/nestedRecordFields/Viewport.mjs +1 -0
  209. package/examples/todoList/version1/MainComponent.mjs +1 -1
  210. package/examples/toolbar/breadcrumb/view/MainContainer.mjs +2 -0
  211. package/examples/toolbar/paging/store/Users.mjs +1 -0
  212. package/examples/toolbar/paging/view/AddUserDialog.mjs +3 -0
  213. package/examples/toolbar/paging/view/MainContainer.mjs +3 -0
  214. package/examples/treeAccordion/MainContainer.mjs +2 -2
  215. package/examples/worker/task/MainContainer.mjs +1 -0
  216. package/learn/Glossary.md +1 -0
  217. package/learn/UsingTheseTopics.md +1 -0
  218. package/learn/benefits/ConfigSystem.md +2 -0
  219. package/learn/benefits/Effort.md +1 -0
  220. package/learn/benefits/Features.md +1 -0
  221. package/learn/benefits/FormsEngine.md +1 -0
  222. package/learn/benefits/FourEnvironments.md +2 -0
  223. package/learn/benefits/Introduction.md +2 -0
  224. package/learn/benefits/MultiWindow.md +3 -1
  225. package/learn/benefits/OffTheMainThread.md +2 -0
  226. package/learn/benefits/Quick.md +2 -0
  227. package/learn/benefits/RPCLayer.md +2 -0
  228. package/learn/benefits/Speed.md +2 -0
  229. package/learn/blog/v10-deep-dive-functional-components.md +293 -0
  230. package/learn/blog/v10-deep-dive-reactivity.md +522 -0
  231. package/learn/blog/v10-deep-dive-state-provider.md +432 -0
  232. package/learn/blog/v10-deep-dive-vdom-revolution.md +194 -0
  233. package/learn/blog/v10-post1-love-story.md +383 -0
  234. package/learn/comparisons/NeoVsAngular.md +90 -0
  235. package/learn/comparisons/NeoVsExtJs.md +178 -0
  236. package/learn/comparisons/NeoVsNextJs.md +124 -0
  237. package/learn/comparisons/NeoVsReact.md +95 -0
  238. package/learn/comparisons/NeoVsSolid.md +78 -0
  239. package/learn/comparisons/NeoVsVue.md +92 -0
  240. package/learn/comparisons/Overview.md +46 -0
  241. package/learn/gettingstarted/ComponentModels.md +2 -0
  242. package/learn/gettingstarted/Config.md +2 -0
  243. package/learn/gettingstarted/DescribingTheUI.md +2 -0
  244. package/learn/gettingstarted/Events.md +2 -0
  245. package/learn/gettingstarted/Extending.md +2 -0
  246. package/learn/gettingstarted/References.md +2 -0
  247. package/learn/gettingstarted/Setup.md +3 -2
  248. package/learn/gettingstarted/Workspaces.md +2 -0
  249. package/learn/guides/datahandling/Collections.md +1 -0
  250. package/learn/guides/datahandling/Records.md +1 -0
  251. package/learn/guides/datahandling/StateProviders.md +130 -16
  252. package/learn/guides/datahandling/Tables.md +1 -1
  253. package/learn/guides/fundamentals/ConfigSystemDeepDive.md +1 -0
  254. package/learn/guides/fundamentals/DeclarativeComponentTreesVsImperativeVdom.md +2 -0
  255. package/learn/guides/fundamentals/DeclarativeVDOMWithEffects.md +10 -8
  256. package/learn/guides/fundamentals/ExtendingNeoClasses.md +1 -0
  257. package/learn/guides/fundamentals/InstanceLifecycle.md +3 -1
  258. package/learn/guides/fundamentals/MainThreadAddons.md +2 -0
  259. package/learn/guides/specificfeatures/Mixins.md +3 -1
  260. package/learn/guides/specificfeatures/MultiWindow.md +3 -1
  261. package/learn/guides/specificfeatures/PortalApp.md +2 -0
  262. package/learn/guides/uibuildingblocks/ComponentsAndContainers.md +2 -0
  263. package/learn/guides/uibuildingblocks/CustomComponents.md +2 -0
  264. package/learn/guides/uibuildingblocks/Layouts.md +2 -0
  265. package/learn/guides/uibuildingblocks/WorkingWithVDom.md +28 -2
  266. package/learn/guides/userinteraction/Forms.md +2 -0
  267. package/learn/guides/userinteraction/events/CustomEvents.md +2 -1
  268. package/learn/guides/userinteraction/events/DomEvents.md +2 -0
  269. package/learn/javascript/ClassFeatures.md +4 -3
  270. package/learn/javascript/Classes.md +10 -13
  271. package/learn/javascript/Overrides.md +10 -6
  272. package/learn/javascript/Super.md +12 -8
  273. package/learn/tree.json +71 -64
  274. package/learn/tutorials/Earthquakes.md +2 -0
  275. package/learn/tutorials/RSP.md +3 -1
  276. package/learn/tutorials/TodoList.md +103 -7
  277. package/package.json +8 -6
  278. package/resources/scss/src/apps/email/ComposeView.scss +16 -0
  279. package/resources/scss/src/apps/email/MainView.scss +5 -0
  280. package/resources/scss/src/apps/portal/learn/ContentComponent.scss +5 -4
  281. package/src/DefaultConfig.mjs +12 -2
  282. package/src/Main.mjs +1 -0
  283. package/src/Neo.mjs +219 -166
  284. package/src/Xhr.mjs +1 -0
  285. package/src/button/Base.mjs +13 -0
  286. package/src/button/Effect.mjs +16 -2
  287. package/src/button/Split.mjs +2 -0
  288. package/src/calendar/store/Calendars.mjs +1 -0
  289. package/src/calendar/store/Colors.mjs +1 -0
  290. package/src/calendar/store/Events.mjs +1 -0
  291. package/src/calendar/view/DayComponent.mjs +2 -0
  292. package/src/calendar/view/EditEventContainer.mjs +4 -1
  293. package/src/calendar/view/MainContainer.mjs +13 -0
  294. package/src/calendar/view/MainContainerStateProvider.mjs +14 -28
  295. package/src/calendar/view/SettingsContainer.mjs +1 -0
  296. package/src/calendar/view/YearComponent.mjs +16 -0
  297. package/src/calendar/view/calendars/ColorsList.mjs +2 -0
  298. package/src/calendar/view/calendars/Container.mjs +2 -0
  299. package/src/calendar/view/calendars/EditContainer.mjs +1 -0
  300. package/src/calendar/view/month/Component.mjs +11 -0
  301. package/src/calendar/view/settings/GeneralContainer.mjs +1 -0
  302. package/src/calendar/view/settings/MonthContainer.mjs +1 -0
  303. package/src/calendar/view/settings/WeekContainer.mjs +1 -0
  304. package/src/calendar/view/settings/YearContainer.mjs +1 -0
  305. package/src/calendar/view/week/Component.mjs +15 -1
  306. package/src/calendar/view/week/TimeAxisComponent.mjs +4 -0
  307. package/src/code/LivePreview.mjs +51 -23
  308. package/src/collection/Base.mjs +7 -10
  309. package/src/collection/Filter.mjs +6 -0
  310. package/src/collection/Sorter.mjs +3 -0
  311. package/src/component/Abstract.mjs +412 -0
  312. package/src/component/Base.mjs +48 -1077
  313. package/src/component/Canvas.mjs +1 -0
  314. package/src/component/Chip.mjs +4 -0
  315. package/src/component/Circle.mjs +14 -0
  316. package/src/component/Clock.mjs +4 -0
  317. package/src/component/DateSelector.mjs +12 -0
  318. package/src/component/Gallery.mjs +11 -0
  319. package/src/component/Helix.mjs +24 -0
  320. package/src/component/Label.mjs +1 -0
  321. package/src/component/Legend.mjs +3 -0
  322. package/src/component/MagicMoveText.mjs +4 -0
  323. package/src/component/Progress.mjs +3 -0
  324. package/src/component/Splitter.mjs +3 -0
  325. package/src/component/StatusBadge.mjs +6 -0
  326. package/src/component/Timer.mjs +4 -0
  327. package/src/component/Toast.mjs +6 -0
  328. package/src/component/Video.mjs +1 -0
  329. package/src/component/mwc/Button.mjs +7 -0
  330. package/src/component/mwc/TextField.mjs +9 -0
  331. package/src/component/wrapper/AmChart.mjs +2 -0
  332. package/src/component/wrapper/GoogleMaps.mjs +3 -0
  333. package/src/component/wrapper/MapboxGL.mjs +5 -0
  334. package/src/component/wrapper/MonacoEditor.mjs +12 -0
  335. package/src/container/Accordion.mjs +2 -0
  336. package/src/container/Base.mjs +7 -3
  337. package/src/container/Panel.mjs +1 -0
  338. package/src/container/Viewport.mjs +1 -0
  339. package/src/controller/Application.mjs +1 -0
  340. package/src/controller/Base.mjs +1 -0
  341. package/src/controller/Component.mjs +1 -0
  342. package/src/core/Base.mjs +86 -33
  343. package/src/core/Compare.mjs +4 -7
  344. package/src/core/Config.mjs +65 -52
  345. package/src/core/Effect.mjs +86 -24
  346. package/src/core/EffectManager.mjs +117 -8
  347. package/src/core/IdGenerator.mjs +13 -44
  348. package/src/core/Observable.mjs +69 -65
  349. package/src/data/Model.mjs +2 -0
  350. package/src/data/Store.mjs +7 -0
  351. package/src/data/connection/WebSocket.mjs +2 -0
  352. package/src/date/DayViewComponent.mjs +2 -0
  353. package/src/date/SelectorContainer.mjs +14 -0
  354. package/src/dialog/Base.mjs +8 -0
  355. package/src/draggable/DragZone.mjs +5 -0
  356. package/src/draggable/tree/DragZone.mjs +1 -0
  357. package/src/filter/BooleanContainer.mjs +2 -0
  358. package/src/filter/NumberContainer.mjs +3 -0
  359. package/src/filter/ToggleOperatorsButton.mjs +2 -0
  360. package/src/form/Fieldset.mjs +6 -0
  361. package/src/form/field/Base.mjs +7 -0
  362. package/src/form/field/CheckBox.mjs +18 -0
  363. package/src/form/field/Chip.mjs +1 -0
  364. package/src/form/field/ComboBox.mjs +8 -0
  365. package/src/form/field/Country.mjs +1 -0
  366. package/src/form/field/Currency.mjs +2 -0
  367. package/src/form/field/Date.mjs +4 -0
  368. package/src/form/field/Display.mjs +1 -0
  369. package/src/form/field/Email.mjs +1 -0
  370. package/src/form/field/FileUpload.mjs +7 -0
  371. package/src/form/field/Hidden.mjs +1 -0
  372. package/src/form/field/Number.mjs +7 -0
  373. package/src/form/field/Password.mjs +1 -0
  374. package/src/form/field/Phone.mjs +3 -0
  375. package/src/form/field/Picker.mjs +2 -0
  376. package/src/form/field/Radio.mjs +1 -0
  377. package/src/form/field/Range.mjs +3 -0
  378. package/src/form/field/Search.mjs +2 -0
  379. package/src/form/field/Text.mjs +43 -5
  380. package/src/form/field/TextArea.mjs +7 -0
  381. package/src/form/field/Time.mjs +6 -0
  382. package/src/form/field/Url.mjs +3 -0
  383. package/src/form/field/ZipCode.mjs +2 -0
  384. package/src/form/field/trigger/Base.mjs +3 -0
  385. package/src/form/field/trigger/Clear.mjs +2 -0
  386. package/src/form/field/trigger/CopyToClipboard.mjs +2 -0
  387. package/src/form/field/trigger/Date.mjs +1 -0
  388. package/src/form/field/trigger/Picker.mjs +1 -0
  389. package/src/form/field/trigger/Search.mjs +1 -0
  390. package/src/form/field/trigger/SpinDown.mjs +2 -0
  391. package/src/form/field/trigger/SpinUp.mjs +1 -0
  392. package/src/form/field/trigger/Time.mjs +2 -0
  393. package/src/functional/_export.mjs +6 -0
  394. package/src/functional/button/Base.mjs +384 -0
  395. package/src/functional/component/Base.mjs +405 -0
  396. package/src/functional/defineComponent.mjs +102 -0
  397. package/src/functional/useConfig.mjs +52 -0
  398. package/src/functional/useEvent.mjs +43 -0
  399. package/src/grid/Body.mjs +20 -1
  400. package/src/grid/Container.mjs +50 -60
  401. package/src/grid/ScrollManager.mjs +2 -0
  402. package/src/grid/VerticalScrollbar.mjs +2 -0
  403. package/src/grid/column/Base.mjs +2 -0
  404. package/src/grid/header/Button.mjs +7 -0
  405. package/src/grid/header/Toolbar.mjs +6 -0
  406. package/src/grid/plugin/AnimateRows.mjs +2 -0
  407. package/src/layout/Base.mjs +3 -0
  408. package/src/layout/Card.mjs +1 -0
  409. package/src/layout/Cube.mjs +18 -4
  410. package/src/layout/Fit.mjs +1 -0
  411. package/src/layout/Flexbox.mjs +7 -0
  412. package/src/layout/Form.mjs +2 -0
  413. package/src/layout/Grid.mjs +1 -0
  414. package/src/layout/HBox.mjs +1 -0
  415. package/src/layout/VBox.mjs +1 -0
  416. package/src/list/Base.mjs +13 -0
  417. package/src/list/Chip.mjs +1 -0
  418. package/src/list/Circle.mjs +2 -0
  419. package/src/list/Color.mjs +1 -0
  420. package/src/list/plugin/Animate.mjs +2 -0
  421. package/src/main/DeltaUpdates.mjs +1 -0
  422. package/src/main/DomEvents.mjs +2 -0
  423. package/src/main/addon/CloneNode.mjs +1 -0
  424. package/src/main/addon/Cookie.mjs +1 -0
  425. package/src/main/addon/GoogleMaps.mjs +1 -0
  426. package/src/main/addon/LocalStorage.mjs +1 -0
  427. package/src/main/addon/MapboxGL.mjs +1 -0
  428. package/src/main/addon/Markdown.mjs +1 -0
  429. package/src/main/addon/Navigator.mjs +1 -0
  430. package/src/main/addon/Popover.mjs +1 -0
  431. package/src/main/addon/Stylesheet.mjs +1 -0
  432. package/src/main/addon/WindowPosition.mjs +1 -0
  433. package/src/manager/Component.mjs +0 -71
  434. package/src/manager/VDomUpdate.mjs +320 -0
  435. package/src/menu/List.mjs +6 -0
  436. package/src/menu/Model.mjs +1 -0
  437. package/src/menu/Panel.mjs +3 -0
  438. package/src/menu/Store.mjs +1 -0
  439. package/src/mixin/DomEvents.mjs +130 -0
  440. package/src/mixin/VdomLifecycle.mjs +670 -0
  441. package/src/plugin/Base.mjs +1 -0
  442. package/src/plugin/Resizable.mjs +2 -0
  443. package/src/selection/Model.mjs +15 -18
  444. package/src/selection/grid/BaseModel.mjs +1 -0
  445. package/src/sitemap/Component.mjs +1 -0
  446. package/src/state/Provider.mjs +129 -87
  447. package/src/state/createHierarchicalDataProxy.mjs +39 -25
  448. package/src/tab/Container.mjs +6 -0
  449. package/src/tab/Strip.mjs +1 -0
  450. package/src/tab/header/Button.mjs +2 -0
  451. package/src/tab/header/EffectButton.mjs +2 -0
  452. package/src/tab/header/Toolbar.mjs +1 -0
  453. package/src/table/Body.mjs +3 -0
  454. package/src/table/Container.mjs +10 -0
  455. package/src/table/header/Button.mjs +8 -0
  456. package/src/table/header/Toolbar.mjs +5 -0
  457. package/src/table/plugin/CellEditing.mjs +1 -0
  458. package/src/toolbar/Base.mjs +4 -0
  459. package/src/toolbar/Breadcrumb.mjs +3 -0
  460. package/src/toolbar/Paging.mjs +5 -0
  461. package/src/tooltip/Base.mjs +2 -0
  462. package/src/tree/List.mjs +3 -0
  463. package/src/util/HashHistory.mjs +1 -0
  464. package/src/util/KeyNavigation.mjs +2 -0
  465. package/src/util/Matrix.mjs +1 -0
  466. package/src/util/VDom.mjs +18 -5
  467. package/src/util/VNode.mjs +7 -1
  468. package/src/util/vdom/TreeBuilder.mjs +105 -0
  469. package/src/vdom/Helper.mjs +35 -23
  470. package/src/vdom/VNode.mjs +4 -6
  471. package/src/worker/App.mjs +1 -0
  472. package/src/worker/Base.mjs +2 -0
  473. package/src/worker/Manager.mjs +2 -0
  474. package/src/worker/ServiceBase.mjs +6 -1
  475. package/src/worker/mixin/RemoteMethodAccess.mjs +1 -6
  476. package/test/siesta/siesta.js +17 -2
  477. package/test/siesta/tests/VdomCalendar.mjs +19 -15
  478. package/test/siesta/tests/VdomHelper.mjs +7 -7
  479. package/test/siesta/tests/classic/Button.mjs +113 -0
  480. package/test/siesta/tests/core/Effect.mjs +10 -14
  481. package/test/siesta/tests/core/EffectBatching.mjs +72 -79
  482. package/test/siesta/tests/functional/Button.mjs +113 -0
  483. package/test/siesta/tests/state/ProviderNestedDataConfigs.mjs +314 -0
  484. package/test/siesta/tests/state/createHierarchicalDataProxy.mjs +42 -55
  485. package/test/siesta/tests/vdom/Advanced.mjs +14 -8
  486. package/test/siesta/tests/vdom/VdomAsymmetricUpdates.mjs +366 -0
  487. package/test/siesta/tests/vdom/VdomRealWorldUpdates.mjs +249 -0
  488. package/test/siesta/tests/vdom/layout/Cube.mjs +11 -7
  489. package/test/siesta/tests/vdom/table/Container.mjs +9 -5
  490. package/learn/javascript/NewNode.md +0 -31
  491. package/src/core/EffectBatchManager.mjs +0 -68
@@ -22,6 +22,7 @@ class Toolbar extends BaseToolbar {
22
22
  baseCls: ['neo-tab-header-toolbar', 'neo-toolbar'],
23
23
  /**
24
24
  * @member {Boolean} useActiveTabIndicator_=true
25
+ * @reactive
25
26
  */
26
27
  useActiveTabIndicator_: true
27
28
  }
@@ -36,6 +36,7 @@ class TableBody extends Component {
36
36
  containerId: null,
37
37
  /**
38
38
  * @member {Boolean} highlightModifiedCells_=false
39
+ * @reactive
39
40
  */
40
41
  highlightModifiedCells_: false,
41
42
  /**
@@ -49,6 +50,7 @@ class TableBody extends Component {
49
50
  recordVnodeMap: {},
50
51
  /**
51
52
  * @member {Neo.selection.Model} selectionModel_=null
53
+ * @reactive
52
54
  */
53
55
  selectionModel_: null,
54
56
  /**
@@ -57,6 +59,7 @@ class TableBody extends Component {
57
59
  selectedRecordField: 'annotations.selected',
58
60
  /**
59
61
  * @member {Neo.data.Store|null} store_=null
62
+ * @reactive
60
63
  */
61
64
  store_: null,
62
65
  /**
@@ -34,11 +34,13 @@ class Container extends BaseContainer {
34
34
  /**
35
35
  * @member {String|null} bodyId_=null
36
36
  * @protected
37
+ * @reactive
37
38
  */
38
39
  bodyId_: null,
39
40
  /**
40
41
  * true uses table.plugin.CellEditing
41
42
  * @member {Boolean} cellEditing_=false
43
+ * @reactive
42
44
  */
43
45
  cellEditing_: false,
44
46
  /**
@@ -48,6 +50,7 @@ class Container extends BaseContainer {
48
50
  columnDefaults: null,
49
51
  /**
50
52
  * @member {Object[]} columns_=[]
53
+ * @reactive
51
54
  */
52
55
  columns_: [],
53
56
  /**
@@ -57,10 +60,12 @@ class Container extends BaseContainer {
57
60
  headerToolbarConfig: null,
58
61
  /**
59
62
  * @member {String|null} headerToolbarId_=null
63
+ * @reactive
60
64
  */
61
65
  headerToolbarId_: null,
62
66
  /**
63
67
  * @member {String} layout='base'
68
+ * @reactive
64
69
  */
65
70
  layout: 'base',
66
71
  /**
@@ -70,24 +75,29 @@ class Container extends BaseContainer {
70
75
  scrollbarsCssApplied: false,
71
76
  /**
72
77
  * @member {Boolean} showHeaderFilters_=false
78
+ * @reactive
73
79
  */
74
80
  showHeaderFilters_: false,
75
81
  /**
76
82
  * @member {Boolean} sortable_=true
83
+ * @reactive
77
84
  */
78
85
  sortable_: true,
79
86
  /**
80
87
  * @member {Neo.data.Store} store_=null
88
+ * @reactive
81
89
  */
82
90
  store_: null,
83
91
  /**
84
92
  * todo: only works for chrome & safari -> add a check
85
93
  * @member {Boolean} useCustomScrollbars_=true
94
+ * @reactive
86
95
  */
87
96
  useCustomScrollbars_: true,
88
97
  /**
89
98
  * @member {Array|null} items=null
90
99
  * @protected
100
+ * @reactive
91
101
  */
92
102
  items: null,
93
103
  /**
@@ -34,6 +34,7 @@ class Button extends BaseButton {
34
34
  /**
35
35
  * Alignment of the matching table cells. Valid values are left, center, right
36
36
  * @member {String} cellAlign_='left'
37
+ * @reactive
37
38
  */
38
39
  cellAlign_: 'left',
39
40
  /**
@@ -47,6 +48,7 @@ class Button extends BaseButton {
47
48
  defaultSortDirection: 'ASC',
48
49
  /**
49
50
  * @member {Boolean} draggable_=true
51
+ * @reactive
50
52
  */
51
53
  draggable_: true,
52
54
  /**
@@ -64,20 +66,24 @@ class Button extends BaseButton {
64
66
  filterField: null,
65
67
  /**
66
68
  * @member {String} iconCls='fa fa-arrow-circle-up'
69
+ * @reactive
67
70
  */
68
71
  iconCls: 'fa fa-arrow-circle-up',
69
72
  /**
70
73
  * @member {String} iconPosition='right'
74
+ * @reactive
71
75
  */
72
76
  iconPosition: 'right',
73
77
  /**
74
78
  * 'ASC', 'DESC' or null
75
79
  * @member {String|null} isSorted_=null
76
80
  * @protected
81
+ * @reactive
77
82
  */
78
83
  isSorted_: null,
79
84
  /**
80
85
  * @member {Function|String|null} renderer_='cellRenderer'
86
+ * @reactive
81
87
  */
82
88
  renderer_: 'cellRenderer',
83
89
  /**
@@ -88,10 +94,12 @@ class Button extends BaseButton {
88
94
  rendererScope: null,
89
95
  /**
90
96
  * @member {Boolean} showHeaderFilter_=false
97
+ * @reactive
91
98
  */
92
99
  showHeaderFilter_: false,
93
100
  /**
94
101
  * @member {Boolean} sortable_=true
102
+ * @reactive
95
103
  */
96
104
  sortable_: true,
97
105
  /**
@@ -22,26 +22,31 @@ class Toolbar extends BaseToolbar {
22
22
  baseCls: ['neo-table-header-toolbar'],
23
23
  /**
24
24
  * @member {Boolean} draggable_=true
25
+ * @reactive
25
26
  */
26
27
  draggable_: true,
27
28
  /**
28
29
  * @member {String} layout='base'
30
+ * @reactive
29
31
  */
30
32
  layout: 'base',
31
33
  /**
32
34
  * @member {Object} itemDefaults={ntype : 'table-header-button'}
35
+ * @reactive
33
36
  */
34
37
  itemDefaults: {
35
38
  ntype: 'table-header-button'
36
39
  },
37
40
  /**
38
41
  * @member {Boolean} showHeaderFilters_=false
42
+ * @reactive
39
43
  */
40
44
  showHeaderFilters_: false,
41
45
  /**
42
46
  * Convenience shortcut to pass sortable to all toolbar items.
43
47
  * If set to true, header clicks will sort the matching column (ASC, DESC, null)
44
48
  * @member {Boolean} sortable=true
49
+ * @reactive
45
50
  */
46
51
  sortable: true,
47
52
  /**
@@ -24,6 +24,7 @@ class CellEditing extends Plugin {
24
24
  cellCls: 'neo-table-cell',
25
25
  /**
26
26
  * @member {Boolean} disabled_=false
27
+ * @reactive
27
28
  */
28
29
  disabled_: false,
29
30
  /**
@@ -33,16 +33,19 @@ class Toolbar extends Container {
33
33
  baseCls: ['neo-toolbar'],
34
34
  /**
35
35
  * @member {String|null} dock_=null
36
+ * @reactive
36
37
  */
37
38
  dock_: null,
38
39
  /**
39
40
  * @member {Object} itemDefaults={ntype:'button'}
41
+ * @reactive
40
42
  */
41
43
  itemDefaults: {
42
44
  ntype: 'button'
43
45
  },
44
46
  /**
45
47
  * @member {Object} layout={ntype:'flexbox',align:'center',direction: 'row', pack:'start'}
48
+ * @reactive
46
49
  */
47
50
  layout: {
48
51
  ntype : 'flexbox',
@@ -52,6 +55,7 @@ class Toolbar extends Container {
52
55
  },
53
56
  /**
54
57
  * @member {Boolean} sortable_=false
58
+ * @reactive
55
59
  */
56
60
  sortable_: false,
57
61
  /**
@@ -21,6 +21,7 @@ class Breadcrumb extends Toolbar {
21
21
  ntype: 'breadcrumb-toolbar',
22
22
  /**
23
23
  * @member {Number|String|null} activeKey_=null
24
+ * @reactive
24
25
  */
25
26
  activeKey_: null,
26
27
  /**
@@ -29,6 +30,7 @@ class Breadcrumb extends Toolbar {
29
30
  baseCls: ['neo-breadcrumb-toolbar', 'neo-toolbar'],
30
31
  /**
31
32
  * @member {Object} itemDefaults={ntype:'button', ui: 'tertiary'}
33
+ * @reactive
32
34
  */
33
35
  itemDefaults: {
34
36
  ntype: 'button',
@@ -36,6 +38,7 @@ class Breadcrumb extends Toolbar {
36
38
  },
37
39
  /**
38
40
  * @member {Neo.data.Store|Object} store_=null
41
+ * @reactive
39
42
  */
40
43
  store_: null
41
44
  }
@@ -24,22 +24,27 @@ class Paging extends Toolbar {
24
24
  baseCls: ['neo-paging-toolbar', 'neo-toolbar'],
25
25
  /**
26
26
  * @member {Number} currentPage_=1
27
+ * @reactive
27
28
  */
28
29
  currentPage_: 1,
29
30
  /**
30
31
  * @member {Number} pageSize_=30
32
+ * @reactive
31
33
  */
32
34
  pageSize_: 30,
33
35
  /**
34
36
  * @member {Function} pagesText_=me=>`Page: ${me.page} / ${me.getMaxPages()}`
37
+ * @reactive
35
38
  */
36
39
  pagesText_: me => `Page ${me.currentPage} / ${me.getMaxPages()}`,
37
40
  /**
38
41
  * @member {Neo.data.Store|null} store_=null
42
+ * @reactive
39
43
  */
40
44
  store_: null,
41
45
  /**
42
46
  * @member {Function} totalText_=count=>`Total: ${count} records`
47
+ * @reactive
43
48
  */
44
49
  totalText_: count => `Total: ${count} rows`,
45
50
  /**
@@ -27,6 +27,7 @@ class Tooltip extends Container {
27
27
  /**
28
28
  * A reference to the target component which is supposed to show this tooltip on mouseenter
29
29
  * @member {String|null} componentId_=null
30
+ * @reactive
30
31
  */
31
32
  componentId_: null,
32
33
  /**
@@ -75,6 +76,7 @@ class Tooltip extends Container {
75
76
  /**
76
77
  * True prevents the tooltip from hiding while the mouse cursor is above it
77
78
  * @member {Boolean|null} stayOnHover_=true
79
+ * @reactive
78
80
  */
79
81
  stayOnHover_: true
80
82
  }
package/src/tree/List.mjs CHANGED
@@ -27,6 +27,7 @@ class Tree extends Base {
27
27
  baseCls: ['neo-tree-list'],
28
28
  /**
29
29
  * @member {Boolean} disableSelection=false
30
+ * @reactive
30
31
  */
31
32
  disableSelection: false,
32
33
  /**
@@ -43,6 +44,7 @@ class Tree extends Base {
43
44
  showCollapseExpandAllIcons: true,
44
45
  /**
45
46
  * @member {Boolean} sortable_=false
47
+ * @reactive
46
48
  */
47
49
  sortable_: false,
48
50
  /**
@@ -55,6 +57,7 @@ class Tree extends Base {
55
57
  sortZoneConfig: null,
56
58
  /**
57
59
  * @member {String[]} wrapperCls=[]
60
+ * @reactive
58
61
  */
59
62
  wrapperCls: [],
60
63
  /**
@@ -4,6 +4,7 @@ import Observable from '../core/Observable.mjs';
4
4
  /**
5
5
  * @class Neo.util.HashHistory
6
6
  * @extends Neo.core.Base
7
+ * @mixes Neo.core.Observable
7
8
  * @singleton
8
9
  */
9
10
  class HashHistory extends Base {
@@ -20,6 +20,7 @@ class KeyNavigation extends Base {
20
20
  /**
21
21
  * Internally stores the component id inside _component
22
22
  * @member {Neo.component.Base|null} component_=null
23
+ * @reactive
23
24
  */
24
25
  component_: null,
25
26
  /**
@@ -29,6 +30,7 @@ class KeyNavigation extends Base {
29
30
  keyDownEventBubble: false,
30
31
  /**
31
32
  * @member {Array|null} keys_=null
33
+ * @reactive
32
34
  */
33
35
  keys_: null
34
36
  }
@@ -15,6 +15,7 @@ class Matrix extends Base {
15
15
  /**
16
16
  * @member {Array|null} items_=null
17
17
  * @protected
18
+ * @reactive
18
19
  */
19
20
  items_: null
20
21
  }
package/src/util/VDom.mjs CHANGED
@@ -261,7 +261,13 @@ class VDom extends Base {
261
261
  */
262
262
  static getVdom(vdom) {
263
263
  if (vdom.componentId) {
264
- vdom = ComponentManager.get(vdom.componentId).vdom
264
+ const component = ComponentManager.get(vdom.componentId);
265
+
266
+ if (!component) {
267
+ throw new Error(`util.VDom.getVdom: Component not found for id: ${vdom.componentId}`)
268
+ }
269
+
270
+ vdom = component.vdom
265
271
  }
266
272
 
267
273
  return vdom
@@ -385,16 +391,23 @@ class VDom extends Base {
385
391
  vdom.id = vnode.id
386
392
  }
387
393
  } else {
388
- // we only want to change vdom ids in case there is not already an own id
389
- // (think of adding & removing nodes in parallel)
390
- if (!vdom.id && vnode.id) {
394
+ // We only want to add an ID if the vdom node does not already have one.
395
+ // This preserves developer-provided IDs while allowing the framework
396
+ // to assign IDs to nodes that need them for reconciliation.
397
+ // Also think of adding and removing nodes in parallel.
398
+ if (vnode.id && (!vdom.id || vdom.id.startsWith('neo-vnode-'))) {
391
399
  vdom.id = vnode.id
392
400
  }
393
401
  }
394
402
 
395
403
  if (childNodes) {
396
404
  cn = childNodes.map(item => VDom.getVdom(item));
397
- cn = cn.filter(item => item.removeDom !== true);
405
+ // The vnode.childNodes array is already filtered by the worker.
406
+ // We must filter the component's vdom.cn array identically to ensure
407
+ // both arrays are structurally aligned for the sync loop.
408
+ // The boolean check `item &&` is critical to remove falsy values
409
+ // from conditional rendering and prevent runtime errors.
410
+ cn = cn.filter(item => item && item.removeDom !== true);
398
411
  i = 0;
399
412
  len = cn?.length || 0;
400
413
 
@@ -168,7 +168,13 @@ class VNode extends Base {
168
168
  */
169
169
  static getVnode(vnode) {
170
170
  if (vnode.componentId) {
171
- vnode = ComponentManager.get(vnode.componentId).vnode
171
+ const component = ComponentManager.get(vnode.componentId);
172
+
173
+ if (!component) {
174
+ throw new Error(`util.VNode.getVnode: Component not found for id: ${vnode.componentId}`)
175
+ }
176
+
177
+ vnode = component.vnode
172
178
  }
173
179
 
174
180
  return vnode
@@ -0,0 +1,105 @@
1
+ import Base from '../../core/Base.mjs';
2
+ import ComponentManager from '../../manager/Component.mjs';
3
+
4
+ /**
5
+ * A singleton utility class responsible for recursively building VDOM and VNode trees.
6
+ * It can expand component references within a tree structure into their full VDOM/VNode representations,
7
+ * supporting selective (asymmetric) tree expansion for optimized updates.
8
+ * @class Neo.util.vdom.TreeBuilder
9
+ * @extends Neo.core.Base
10
+ * @singleton
11
+ */
12
+ class TreeBuilder extends Base {
13
+ static config = {
14
+ /**
15
+ * @member {String} className='Neo.util.vdom.TreeBuilder'
16
+ * @protected
17
+ */
18
+ className: 'Neo.util.vdom.TreeBuilder',
19
+ /**
20
+ * @member {Boolean} singleton=true
21
+ * @protected
22
+ */
23
+ singleton: true
24
+ }
25
+
26
+ /**
27
+ * Private helper to recursively build a tree, abstracting the child node key.
28
+ * @param {Object} node The vdom or vnode to process.
29
+ * @param {Number} depth The current recursion depth.
30
+ * @param {Set<String>|null} mergedChildIds A set of component IDs to selectively expand.
31
+ * @param {String} childKey The property name for child nodes ('cn' or 'childNodes').
32
+ * @returns {Object}
33
+ * @private
34
+ */
35
+ #buildTree(node, depth, mergedChildIds, childKey) {
36
+ // We can not use Neo.isObject() here, since inside unit-test scenarios, we will import vdom.Helper into main threads.
37
+ // Inside this scenario, Neo.isObject() returns false for VNode instances
38
+ if (typeof node !== 'object' || node === null) {
39
+ return node
40
+ }
41
+
42
+ let output = {...node}; // Shallow copy
43
+
44
+ if (node[childKey]) {
45
+ output[childKey] = [];
46
+
47
+ node[childKey].forEach(item => {
48
+ let currentItem = item,
49
+ childDepth;
50
+
51
+ if (currentItem.componentId) {
52
+ // Prune the branch only if we are at the boundary AND the child is not part of a merged update
53
+ if (depth === 1 && !mergedChildIds?.has(currentItem.componentId)) {
54
+ output[childKey].push({componentId: 'neo-ignore', id: item.id || item.componentId});
55
+ return // Stop processing this branch
56
+ }
57
+ // Expand the branch if it's part of a merged update, or if the depth requires it
58
+ else if (depth > 1 || depth === -1 || mergedChildIds?.has(currentItem.componentId)) {
59
+ const component = ComponentManager.get(currentItem.componentId);
60
+ // Use the correct tree type based on the childKey
61
+ const componentTree = childKey === 'cn' ? component?.vdom : component?.vnode;
62
+ if (componentTree) {
63
+ currentItem = componentTree
64
+ }
65
+ }
66
+ }
67
+
68
+ if (item.componentId) {
69
+ childDepth = (depth === -1) ? -1 : Math.max(0, depth - 1)
70
+ } else {
71
+ childDepth = depth
72
+ }
73
+
74
+ output[childKey].push(this.#buildTree(currentItem, childDepth, mergedChildIds, childKey))
75
+ })
76
+ }
77
+
78
+ return output
79
+ }
80
+
81
+
82
+ /**
83
+ * Copies a given vdom tree and replaces child component references with their vdom.
84
+ * @param {Object} vdom
85
+ * @param {Number} [depth=-1]
86
+ * @param {Set<String>|null} [mergedChildIds=null]
87
+ * @returns {Object}
88
+ */
89
+ getVdomTree(vdom, depth=-1, mergedChildIds=null) {
90
+ return this.#buildTree(vdom, depth, mergedChildIds, 'cn')
91
+ }
92
+
93
+ /**
94
+ * Copies a given vnode tree and replaces child component references with their vnode.
95
+ * @param {Object} vnode
96
+ * @param {Number} [depth=-1]
97
+ * @param {Set<String>|null} [mergedChildIds=null]
98
+ * @returns {Object}
99
+ */
100
+ getVnodeTree(vnode, depth=-1, mergedChildIds=null) {
101
+ return this.#buildTree(vnode, depth, mergedChildIds, 'childNodes')
102
+ }
103
+ }
104
+
105
+ export default Neo.setupClass(TreeBuilder);
@@ -23,6 +23,7 @@ class Helper extends Base {
23
23
  * Remote method access for other workers
24
24
  * @member {Object} remote={app:['create','update']}
25
25
  * @protected
26
+ * @reactive
26
27
  */
27
28
  remote: {
28
29
  app: [
@@ -47,19 +48,21 @@ class Helper extends Base {
47
48
  * @protected
48
49
  */
49
50
  compareAttributes({deltas, oldVnode, vnode, vnodeMap}) {
50
- // Do not compare attributes for component references
51
- if (oldVnode.componentId && (oldVnode.id === vnode.id || oldVnode.componentId === vnode.id)) {
52
- return deltas
51
+ // If either vnode is a component placeholder (indicated by the presence of componentId),
52
+ // we must not compare element attributes.
53
+ if (vnode.componentId || oldVnode.componentId) {
54
+ return deltas;
53
55
  }
54
56
 
55
- let attributes, delta, value, keys, styles, add, remove;
57
+ let delta = {},
58
+ attributes, value, keys, styles, add, remove;
56
59
 
57
- if (vnode.vtype === 'text' && vnode.innerHTML !== oldVnode.innerHTML) {
60
+ if (vnode.vtype === 'text' && vnode.textContent !== oldVnode.textContent) {
58
61
  deltas.default.push({
59
62
  action : 'updateVtext',
60
63
  id : vnode.id,
61
64
  parentId: vnodeMap.get(vnode.id).parentNode.id,
62
- value : vnode.innerHTML
65
+ value : vnode.textContent
63
66
  })
64
67
  } else {
65
68
  keys = Object.keys(vnode);
@@ -77,7 +80,6 @@ class Helper extends Base {
77
80
  });
78
81
 
79
82
  keys.forEach(prop => {
80
- delta = {};
81
83
  value = vnode[prop];
82
84
 
83
85
  switch (prop) {
@@ -143,12 +145,12 @@ class Helper extends Base {
143
145
  }
144
146
  break
145
147
  }
148
+ });
146
149
 
147
- if (Object.keys(delta).length > 0) {
148
- delta.id = vnode.id;
149
- deltas.default.push(delta)
150
- }
151
- })
150
+ if (Object.keys(delta).length > 0) {
151
+ delta.id = vnode.id;
152
+ deltas.default.push(delta)
153
+ }
152
154
  }
153
155
 
154
156
  return deltas
@@ -200,12 +202,11 @@ class Helper extends Base {
200
202
  */
201
203
  createDeltas(config) {
202
204
  let {deltas={default: [], remove: []}, oldVnode, vnode} = config,
203
- oldVnodeId = oldVnode?.id || oldVnode?.componentId,
204
- vnodeId = vnode?.id;
205
+ vnodeId = vnode?.id;
205
206
 
206
207
  // Edge case: setting `removeDom: true` on a top-level vdom node
207
- if (!vnode && oldVnodeId) {
208
- deltas.remove.push({action: 'removeNode', id: oldVnodeId});
208
+ if (!vnode && (oldVnode?.id || oldVnode?.componentId)) {
209
+ deltas.remove.push({action: 'removeNode', id: oldVnode.id || oldVnode.componentId});
209
210
  return deltas
210
211
  }
211
212
 
@@ -213,8 +214,10 @@ class Helper extends Base {
213
214
  return deltas
214
215
  }
215
216
 
216
- if (vnodeId !== oldVnodeId && vnode.componentId !== oldVnode.componentId) {
217
- throw new Error(`createDeltas() must get called for the same node. ${vnodeId}, ${oldVnodeId}`);
217
+ // The top-level nodes passed to createDeltas must be the same logical node. The VdomLifecycle
218
+ // mixin ensures symmetric trees, so IDs and types (component vs element) must match.
219
+ if (vnode.id !== oldVnode.id || vnode.componentId !== oldVnode.componentId) {
220
+ throw new Error(`createDeltas() must be called for the same node. new: {id: ${vnode.id}, cId: ${vnode.componentId}}, old: {id: ${oldVnode.id}, cId: ${oldVnode.componentId}}`);
218
221
  }
219
222
 
220
223
  let me = this,
@@ -243,11 +246,19 @@ class Helper extends Base {
243
246
  break
244
247
  }
245
248
 
246
- // Same node, continue recursively
249
+ // A "match" requires nodes to be of the same type (placeholder or element) and have
250
+ // the same identifier. The VdomLifecycle mixin ensures that both the old (vnode)
251
+ // and new (vdom) trees are expanded to the same symmetric depth before diffing.
247
252
  if (childNode && oldChildNode && (
248
- childNode.id === oldChildNode.id ||
249
- (childNode.componentId && childNode.componentId === oldChildNode.componentId))
250
- ) {
253
+ // Case 1: Both nodes are elements with the same ID
254
+ (!childNode.componentId && !oldChildNode.componentId && childNode.id === oldChildNode.id) ||
255
+ // Case 2: Both nodes are placeholders for the same component
256
+ (childNode.componentId && childNode.componentId === oldChildNode.componentId)
257
+ )) {
258
+ if (childNode.componentId === 'neo-ignore') {
259
+ continue
260
+ }
261
+
251
262
  me.createDeltas({deltas, oldVnode: oldChildNode, oldVnodeMap, vnode: childNode, vnodeMap});
252
263
  continue
253
264
  }
@@ -334,7 +345,7 @@ class Helper extends Base {
334
345
 
335
346
  newValue = [];
336
347
 
337
- value.forEach(item => {
348
+ value.filter(Boolean).forEach(item => {
338
349
  if (item.removeDom !== true) {
339
350
  delete item.removeDom; // could be false
340
351
  potentialNode = me.createVnode(item);
@@ -371,6 +382,7 @@ class Helper extends Base {
371
382
  case 'componentId':
372
383
  case 'id':
373
384
  case 'static':
385
+ case 'vtype':
374
386
  node[key] = value;
375
387
  break
376
388
  case 'style':
@@ -71,8 +71,9 @@ class VNode {
71
71
  });
72
72
 
73
73
  if (isVText) {
74
- // XSS Security: a pure text node is not supposed to contain HTML
75
- me.textContent = StringUtil.escapeHtml(hasInnerHtml ? config.innerHTML : textContent)
74
+ // A vtext node represents a pure text node. It should not be created from an innerHTML property.
75
+ // For XSS Security, we escape the content when using the string-based renderer.
76
+ me.textContent = Neo.config.useDomApiRenderer ? textContent : StringUtil.escapeHtml(textContent);
76
77
  } else {
77
78
  Object.assign(me, {
78
79
  attributes: config.attributes || {},
@@ -135,7 +136,4 @@ function normalizeClassName(classNameInput) {
135
136
  return [...new Set(normalizedClasses)]
136
137
  }
137
138
 
138
- const ns = Neo.ns('Neo.vdom', true);
139
- ns.VNode = VNode;
140
-
141
- export default VNode;
139
+ export default Neo.gatekeep(VNode, 'Neo.vdom.VNode');
@@ -21,6 +21,7 @@ class App extends Base {
21
21
  className: 'Neo.worker.App',
22
22
  /**
23
23
  * @member {Number} countLoadingThemeFiles_=0
24
+ * @reactive
24
25
  */
25
26
  countLoadingThemeFiles_: 0,
26
27
  /**