neo.mjs 10.0.0-beta.5 → 10.0.0-beta.6

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 (468) hide show
  1. package/.github/RELEASE_NOTES/v10.0.0-beta.5.md +70 -0
  2. package/.github/RELEASE_NOTES/v10.0.0-beta.6.md +48 -0
  3. package/.github/epic-functional-components.md +498 -0
  4. package/.github/ticket-asymmetric-vdom-updates.md +122 -0
  5. package/README.md +0 -3
  6. package/ServiceWorker.mjs +2 -2
  7. package/apps/colors/store/Colors.mjs +1 -0
  8. package/apps/colors/view/GridContainer.mjs +3 -0
  9. package/apps/colors/view/HeaderToolbar.mjs +2 -0
  10. package/apps/colors/view/Viewport.mjs +3 -0
  11. package/apps/covid/view/FooterContainer.mjs +3 -0
  12. package/apps/covid/view/GalleryContainer.mjs +2 -0
  13. package/apps/covid/view/GalleryContainerController.mjs +1 -0
  14. package/apps/covid/view/HeaderContainer.mjs +2 -0
  15. package/apps/covid/view/HelixContainer.mjs +2 -0
  16. package/apps/covid/view/HelixContainerController.mjs +1 -0
  17. package/apps/covid/view/MainContainer.mjs +3 -0
  18. package/apps/covid/view/TableContainer.mjs +3 -0
  19. package/apps/covid/view/TableContainerController.mjs +1 -0
  20. package/apps/covid/view/WorldMapContainer.mjs +2 -0
  21. package/apps/covid/view/country/Gallery.mjs +3 -0
  22. package/apps/covid/view/country/Helix.mjs +8 -0
  23. package/apps/covid/view/country/HistoricalDataTable.mjs +1 -0
  24. package/apps/covid/view/country/Table.mjs +2 -0
  25. package/apps/covid/view/mapboxGl/Component.mjs +1 -0
  26. package/apps/covid/view/mapboxGl/Container.mjs +2 -0
  27. package/apps/email/EPIC_PLAN.md +58 -0
  28. package/apps/email/neo-config.json +2 -2
  29. package/apps/email/store/Emails.mjs +11 -1
  30. package/apps/email/view/ComposeView.mjs +44 -0
  31. package/apps/email/view/MainView.mjs +89 -0
  32. package/apps/email/view/Viewport.mjs +4 -33
  33. package/apps/email/view/ViewportStateProvider.mjs +3 -3
  34. package/apps/form/store/SideNav.mjs +1 -0
  35. package/apps/form/view/FormContainer.mjs +1 -0
  36. package/apps/form/view/FormPageContainer.mjs +2 -0
  37. package/apps/form/view/SideNavList.mjs +1 -0
  38. package/apps/form/view/Viewport.mjs +3 -0
  39. package/apps/portal/childapps/preview/MainContainer.mjs +1 -0
  40. package/apps/portal/index.html +1 -1
  41. package/apps/portal/store/BlogPosts.mjs +2 -0
  42. package/apps/portal/store/Content.mjs +1 -0
  43. package/apps/portal/store/ContentSections.mjs +1 -0
  44. package/apps/portal/store/Examples.mjs +1 -0
  45. package/apps/portal/view/HeaderToolbar.mjs +1 -0
  46. package/apps/portal/view/Viewport.mjs +5 -0
  47. package/apps/portal/view/ViewportController.mjs +8 -2
  48. package/apps/portal/view/about/Container.mjs +2 -0
  49. package/apps/portal/view/about/MemberContainer.mjs +7 -0
  50. package/apps/portal/view/blog/Container.mjs +2 -0
  51. package/apps/portal/view/blog/List.mjs +2 -0
  52. package/apps/portal/view/examples/List.mjs +1 -0
  53. package/apps/portal/view/examples/TabContainer.mjs +4 -0
  54. package/apps/portal/view/home/ContentBox.mjs +3 -0
  55. package/apps/portal/view/home/FeatureSection.mjs +8 -0
  56. package/apps/portal/view/home/FooterContainer.mjs +4 -1
  57. package/apps/portal/view/home/MainContainer.mjs +2 -0
  58. package/apps/portal/view/home/parts/AfterMath.mjs +2 -0
  59. package/apps/portal/view/home/parts/BaseContainer.mjs +1 -0
  60. package/apps/portal/view/home/parts/Colors.mjs +4 -0
  61. package/apps/portal/view/home/parts/Features.mjs +2 -0
  62. package/apps/portal/view/home/parts/Helix.mjs +5 -0
  63. package/apps/portal/view/home/parts/How.mjs +4 -0
  64. package/apps/portal/view/home/parts/MainNeo.mjs +1 -0
  65. package/apps/portal/view/home/parts/References.mjs +2 -0
  66. package/apps/portal/view/learn/ContentComponent.mjs +11 -5
  67. package/apps/portal/view/learn/ContentTreeList.mjs +2 -0
  68. package/apps/portal/view/learn/CubeLayoutButton.mjs +1 -0
  69. package/apps/portal/view/learn/MainContainer.mjs +4 -0
  70. package/apps/portal/view/learn/PageContainer.mjs +2 -0
  71. package/apps/portal/view/learn/PageSectionsContainer.mjs +3 -0
  72. package/apps/portal/view/learn/PageSectionsList.mjs +1 -0
  73. package/apps/portal/view/services/Component.mjs +1 -0
  74. package/apps/realworld/api/Base.mjs +1 -0
  75. package/apps/realworld/view/HeaderComponent.mjs +4 -0
  76. package/apps/realworld/view/HomeComponent.mjs +7 -0
  77. package/apps/realworld/view/MainContainer.mjs +2 -0
  78. package/apps/realworld/view/MainContainerController.mjs +2 -0
  79. package/apps/realworld/view/article/CommentComponent.mjs +3 -0
  80. package/apps/realworld/view/article/Component.mjs +17 -10
  81. package/apps/realworld/view/article/CreateCommentComponent.mjs +2 -0
  82. package/apps/realworld/view/article/CreateComponent.mjs +5 -0
  83. package/apps/realworld/view/article/PreviewComponent.mjs +9 -0
  84. package/apps/realworld/view/article/TagListComponent.mjs +2 -0
  85. package/apps/realworld/view/user/ProfileComponent.mjs +7 -0
  86. package/apps/realworld/view/user/SettingsComponent.mjs +5 -0
  87. package/apps/realworld/view/user/SignUpComponent.mjs +3 -0
  88. package/apps/realworld2/api/Base.mjs +1 -0
  89. package/apps/realworld2/view/FooterComponent.mjs +1 -0
  90. package/apps/realworld2/view/HeaderToolbar.mjs +3 -0
  91. package/apps/realworld2/view/HomeContainer.mjs +1 -0
  92. package/apps/realworld2/view/MainContainer.mjs +2 -0
  93. package/apps/realworld2/view/MainContainerController.mjs +1 -0
  94. package/apps/realworld2/view/article/Helix.mjs +1 -0
  95. package/apps/realworld2/view/article/PreviewComponent.mjs +9 -0
  96. package/apps/realworld2/view/article/PreviewList.mjs +1 -0
  97. package/apps/realworld2/view/article/TagListComponent.mjs +2 -0
  98. package/apps/route/view/CenterContainer.mjs +1 -0
  99. package/apps/route/view/MainView.mjs +1 -0
  100. package/apps/sharedcovid/childapps/sharedcovidchart/MainContainer.mjs +1 -0
  101. package/apps/sharedcovid/childapps/sharedcovidgallery/MainContainer.mjs +1 -0
  102. package/apps/sharedcovid/childapps/sharedcovidhelix/MainContainer.mjs +1 -0
  103. package/apps/sharedcovid/childapps/sharedcovidmap/MainContainer.mjs +1 -0
  104. package/apps/sharedcovid/view/FooterContainer.mjs +3 -0
  105. package/apps/sharedcovid/view/GalleryContainer.mjs +2 -0
  106. package/apps/sharedcovid/view/GalleryContainerController.mjs +1 -0
  107. package/apps/sharedcovid/view/HeaderContainer.mjs +2 -0
  108. package/apps/sharedcovid/view/HelixContainer.mjs +2 -0
  109. package/apps/sharedcovid/view/HelixContainerController.mjs +1 -0
  110. package/apps/sharedcovid/view/MainContainer.mjs +3 -0
  111. package/apps/sharedcovid/view/TableContainer.mjs +3 -0
  112. package/apps/sharedcovid/view/TableContainerController.mjs +1 -0
  113. package/apps/sharedcovid/view/WorldMapContainer.mjs +2 -0
  114. package/apps/sharedcovid/view/country/Gallery.mjs +3 -0
  115. package/apps/sharedcovid/view/country/Helix.mjs +8 -0
  116. package/apps/sharedcovid/view/country/HistoricalDataTable.mjs +1 -0
  117. package/apps/sharedcovid/view/country/Table.mjs +2 -0
  118. package/apps/sharedcovid/view/mapboxGl/Component.mjs +1 -0
  119. package/apps/sharedcovid/view/mapboxGl/Container.mjs +2 -0
  120. package/apps/shareddialog/childapps/shareddialog2/view/MainContainer.mjs +2 -0
  121. package/apps/shareddialog/view/DemoDialog.mjs +2 -0
  122. package/apps/shareddialog/view/MainContainer.mjs +2 -0
  123. package/apps/shareddialog/view/MainContainerController.mjs +1 -0
  124. package/buildScripts/addReactiveTags.mjs +191 -0
  125. package/buildScripts/checkReactiveTags.mjs +160 -0
  126. package/docs/app/store/Api.mjs +1 -0
  127. package/docs/app/store/Examples.mjs +1 -0
  128. package/docs/app/view/ApiTreeList.mjs +1 -0
  129. package/docs/app/view/ContentTabContainer.mjs +2 -0
  130. package/docs/app/view/ExamplesTreeList.mjs +2 -0
  131. package/docs/app/view/HeaderContainer.mjs +3 -0
  132. package/docs/app/view/MainContainer.mjs +5 -0
  133. package/docs/app/view/classdetails/HeaderComponent.mjs +1 -0
  134. package/docs/app/view/classdetails/MainContainer.mjs +3 -0
  135. package/docs/app/view/classdetails/MembersList.mjs +5 -0
  136. package/docs/app/view/classdetails/SourceViewComponent.mjs +2 -0
  137. package/examples/ConfigurationViewport.mjs +14 -8
  138. package/examples/calendar/weekview/MainContainer.mjs +4 -0
  139. package/examples/component/coronaGallery/CountryGallery.mjs +2 -0
  140. package/examples/component/coronaGallery/CountryStore.mjs +1 -0
  141. package/examples/component/coronaGallery/Viewport.mjs +3 -0
  142. package/examples/component/coronaGallery/ViewportController.mjs +1 -0
  143. package/examples/component/coronaHelix/CountryHelix.mjs +7 -0
  144. package/examples/component/coronaHelix/MainContainer.mjs +1 -0
  145. package/examples/component/gallery/ImageStore.mjs +1 -0
  146. package/examples/component/helix/ImageStore.mjs +1 -0
  147. package/examples/component/helix/Viewport.mjs +3 -0
  148. package/examples/component/helix/ViewportController.mjs +1 -0
  149. package/examples/component/multiWindowCoronaGallery/childapp/Viewport.mjs +1 -0
  150. package/examples/component/multiWindowHelix/childapp/Viewport.mjs +1 -0
  151. package/examples/component/wrapper/googleMaps/MapComponent.mjs +2 -0
  152. package/examples/core/config/MainContainer.mjs +2 -0
  153. package/examples/dialog/DemoDialog.mjs +2 -0
  154. package/examples/dialog/MainContainer.mjs +1 -0
  155. package/examples/form/field/color/MainStore.mjs +1 -0
  156. package/examples/functional/defineComponent/Component.mjs +18 -0
  157. package/examples/functional/defineComponent/MainContainer.mjs +41 -0
  158. package/examples/functional/defineComponent/app.mjs +6 -0
  159. package/examples/functional/defineComponent/index.html +11 -0
  160. package/examples/functional/defineComponent/neo-config.json +6 -0
  161. package/examples/functional/hostComponent/Component.mjs +32 -0
  162. package/examples/functional/hostComponent/MainContainer.mjs +48 -0
  163. package/examples/functional/hostComponent/app.mjs +6 -0
  164. package/examples/functional/hostComponent/index.html +11 -0
  165. package/examples/functional/hostComponent/neo-config.json +6 -0
  166. package/examples/grid/animatedRowSorting/Viewport.mjs +1 -1
  167. package/examples/grid/bigData/ControlsContainer.mjs +3 -0
  168. package/examples/grid/bigData/GridContainer.mjs +4 -2
  169. package/examples/grid/bigData/MainContainer.mjs +2 -0
  170. package/examples/grid/bigData/MainModel.mjs +1 -0
  171. package/examples/grid/bigData/MainStore.mjs +3 -0
  172. package/examples/grid/cellEditing/MainContainer.mjs +1 -1
  173. package/examples/grid/container/MainContainer.mjs +1 -1
  174. package/examples/grid/covid/GridContainer.mjs +3 -0
  175. package/examples/grid/covid/MainContainer.mjs +2 -0
  176. package/examples/grid/covid/Store.mjs +1 -0
  177. package/examples/grid/nestedRecordFields/EditUserDialog.mjs +3 -0
  178. package/examples/grid/nestedRecordFields/Viewport.mjs +3 -1
  179. package/examples/list/animate/List.mjs +4 -0
  180. package/examples/list/animate/MainContainer.mjs +2 -0
  181. package/examples/list/circle/MainStore.mjs +1 -0
  182. package/examples/list/color/MainStore.mjs +1 -0
  183. package/examples/preloadingAssets/view/MainContainer.mjs +2 -0
  184. package/examples/stateProvider/advanced/MainContainer.mjs +1 -0
  185. package/examples/stateProvider/dialog/EditUserDialog.mjs +2 -0
  186. package/examples/stateProvider/dialog/MainContainer.mjs +1 -0
  187. package/examples/stateProvider/extendedClass/MainContainer.mjs +2 -0
  188. package/examples/stateProvider/inline/MainContainer.mjs +1 -0
  189. package/examples/stateProvider/inlineNoStateProvider/MainContainer.mjs +1 -0
  190. package/examples/stateProvider/inlineNoStateProvider/MainContainerController.mjs +2 -0
  191. package/examples/stateProvider/multiWindow/EditUserDialog.mjs +3 -0
  192. package/examples/stateProvider/multiWindow/MainContainer.mjs +1 -0
  193. package/examples/stateProvider/multiWindow/Viewport.mjs +1 -0
  194. package/examples/stateProvider/nestedData/MainContainer.mjs +1 -0
  195. package/examples/stateProvider/table/MainContainer.mjs +1 -0
  196. package/examples/table/covid/MainContainer.mjs +2 -0
  197. package/examples/table/covid/Store.mjs +1 -0
  198. package/examples/table/covid/TableContainer.mjs +3 -0
  199. package/examples/table/nestedRecordFields/EditUserDialog.mjs +3 -0
  200. package/examples/table/nestedRecordFields/Viewport.mjs +1 -0
  201. package/examples/todoList/version1/MainComponent.mjs +1 -1
  202. package/examples/toolbar/breadcrumb/view/MainContainer.mjs +2 -0
  203. package/examples/toolbar/paging/store/Users.mjs +1 -0
  204. package/examples/toolbar/paging/view/AddUserDialog.mjs +3 -0
  205. package/examples/toolbar/paging/view/MainContainer.mjs +3 -0
  206. package/examples/treeAccordion/MainContainer.mjs +2 -2
  207. package/examples/worker/task/MainContainer.mjs +1 -0
  208. package/learn/Glossary.md +1 -0
  209. package/learn/UsingTheseTopics.md +1 -0
  210. package/learn/benefits/ConfigSystem.md +2 -0
  211. package/learn/benefits/Effort.md +1 -0
  212. package/learn/benefits/Features.md +1 -0
  213. package/learn/benefits/FormsEngine.md +1 -0
  214. package/learn/benefits/FourEnvironments.md +2 -0
  215. package/learn/benefits/Introduction.md +2 -0
  216. package/learn/benefits/MultiWindow.md +3 -1
  217. package/learn/benefits/OffTheMainThread.md +2 -0
  218. package/learn/benefits/Quick.md +2 -0
  219. package/learn/benefits/RPCLayer.md +2 -0
  220. package/learn/benefits/Speed.md +2 -0
  221. package/learn/comparisons/NeoVsAngular.md +90 -0
  222. package/learn/comparisons/NeoVsExtJs.md +178 -0
  223. package/learn/comparisons/NeoVsNextJs.md +124 -0
  224. package/learn/comparisons/NeoVsReact.md +95 -0
  225. package/learn/comparisons/NeoVsSolid.md +78 -0
  226. package/learn/comparisons/NeoVsVue.md +92 -0
  227. package/learn/comparisons/Overview.md +46 -0
  228. package/learn/gettingstarted/ComponentModels.md +2 -0
  229. package/learn/gettingstarted/Config.md +2 -0
  230. package/learn/gettingstarted/DescribingTheUI.md +2 -0
  231. package/learn/gettingstarted/Events.md +2 -0
  232. package/learn/gettingstarted/Extending.md +2 -0
  233. package/learn/gettingstarted/References.md +2 -0
  234. package/learn/gettingstarted/Setup.md +3 -2
  235. package/learn/gettingstarted/Workspaces.md +2 -0
  236. package/learn/guides/datahandling/Collections.md +1 -0
  237. package/learn/guides/datahandling/Records.md +1 -0
  238. package/learn/guides/datahandling/StateProviders.md +130 -16
  239. package/learn/guides/datahandling/Tables.md +1 -1
  240. package/learn/guides/fundamentals/ConfigSystemDeepDive.md +1 -0
  241. package/learn/guides/fundamentals/DeclarativeComponentTreesVsImperativeVdom.md +2 -0
  242. package/learn/guides/fundamentals/DeclarativeVDOMWithEffects.md +10 -8
  243. package/learn/guides/fundamentals/ExtendingNeoClasses.md +1 -0
  244. package/learn/guides/fundamentals/InstanceLifecycle.md +3 -1
  245. package/learn/guides/fundamentals/MainThreadAddons.md +2 -0
  246. package/learn/guides/specificfeatures/Mixins.md +3 -1
  247. package/learn/guides/specificfeatures/MultiWindow.md +3 -1
  248. package/learn/guides/specificfeatures/PortalApp.md +2 -0
  249. package/learn/guides/uibuildingblocks/ComponentsAndContainers.md +2 -0
  250. package/learn/guides/uibuildingblocks/CustomComponents.md +2 -0
  251. package/learn/guides/uibuildingblocks/Layouts.md +2 -0
  252. package/learn/guides/uibuildingblocks/WorkingWithVDom.md +2 -0
  253. package/learn/guides/userinteraction/Forms.md +2 -0
  254. package/learn/guides/userinteraction/events/CustomEvents.md +2 -1
  255. package/learn/guides/userinteraction/events/DomEvents.md +2 -0
  256. package/learn/javascript/ClassFeatures.md +4 -3
  257. package/learn/javascript/Classes.md +10 -13
  258. package/learn/javascript/Overrides.md +10 -6
  259. package/learn/javascript/Super.md +12 -8
  260. package/learn/tree.json +71 -64
  261. package/learn/tutorials/Earthquakes.md +2 -0
  262. package/learn/tutorials/RSP.md +3 -1
  263. package/learn/tutorials/TodoList.md +103 -7
  264. package/package.json +6 -4
  265. package/resources/scss/src/apps/email/ComposeView.scss +16 -0
  266. package/resources/scss/src/apps/email/MainView.scss +5 -0
  267. package/resources/scss/src/apps/portal/learn/ContentComponent.scss +5 -4
  268. package/src/DefaultConfig.mjs +12 -2
  269. package/src/Main.mjs +1 -0
  270. package/src/Neo.mjs +217 -166
  271. package/src/Xhr.mjs +1 -0
  272. package/src/button/Base.mjs +13 -0
  273. package/src/button/Effect.mjs +16 -2
  274. package/src/button/Split.mjs +2 -0
  275. package/src/calendar/store/Calendars.mjs +1 -0
  276. package/src/calendar/store/Colors.mjs +1 -0
  277. package/src/calendar/store/Events.mjs +1 -0
  278. package/src/calendar/view/DayComponent.mjs +2 -0
  279. package/src/calendar/view/EditEventContainer.mjs +4 -1
  280. package/src/calendar/view/MainContainer.mjs +13 -0
  281. package/src/calendar/view/MainContainerStateProvider.mjs +14 -28
  282. package/src/calendar/view/SettingsContainer.mjs +1 -0
  283. package/src/calendar/view/YearComponent.mjs +16 -0
  284. package/src/calendar/view/calendars/ColorsList.mjs +2 -0
  285. package/src/calendar/view/calendars/Container.mjs +2 -0
  286. package/src/calendar/view/calendars/EditContainer.mjs +1 -0
  287. package/src/calendar/view/month/Component.mjs +11 -0
  288. package/src/calendar/view/settings/GeneralContainer.mjs +1 -0
  289. package/src/calendar/view/settings/MonthContainer.mjs +1 -0
  290. package/src/calendar/view/settings/WeekContainer.mjs +1 -0
  291. package/src/calendar/view/settings/YearContainer.mjs +1 -0
  292. package/src/calendar/view/week/Component.mjs +15 -1
  293. package/src/calendar/view/week/TimeAxisComponent.mjs +4 -0
  294. package/src/code/LivePreview.mjs +51 -23
  295. package/src/collection/Base.mjs +7 -10
  296. package/src/collection/Filter.mjs +6 -0
  297. package/src/collection/Sorter.mjs +3 -0
  298. package/src/component/Base.mjs +104 -771
  299. package/src/component/Canvas.mjs +1 -0
  300. package/src/component/Chip.mjs +4 -0
  301. package/src/component/Circle.mjs +14 -0
  302. package/src/component/Clock.mjs +4 -0
  303. package/src/component/DateSelector.mjs +12 -0
  304. package/src/component/Gallery.mjs +11 -0
  305. package/src/component/Helix.mjs +24 -0
  306. package/src/component/Label.mjs +1 -0
  307. package/src/component/Legend.mjs +3 -0
  308. package/src/component/MagicMoveText.mjs +4 -0
  309. package/src/component/Progress.mjs +3 -0
  310. package/src/component/Splitter.mjs +3 -0
  311. package/src/component/StatusBadge.mjs +6 -0
  312. package/src/component/Timer.mjs +4 -0
  313. package/src/component/Toast.mjs +6 -0
  314. package/src/component/Video.mjs +1 -0
  315. package/src/component/mwc/Button.mjs +7 -0
  316. package/src/component/mwc/TextField.mjs +9 -0
  317. package/src/component/wrapper/AmChart.mjs +2 -0
  318. package/src/component/wrapper/GoogleMaps.mjs +3 -0
  319. package/src/component/wrapper/MapboxGL.mjs +5 -0
  320. package/src/component/wrapper/MonacoEditor.mjs +12 -0
  321. package/src/container/Accordion.mjs +2 -0
  322. package/src/container/Base.mjs +7 -3
  323. package/src/container/Panel.mjs +1 -0
  324. package/src/container/Viewport.mjs +1 -0
  325. package/src/controller/Application.mjs +1 -0
  326. package/src/controller/Base.mjs +1 -0
  327. package/src/controller/Component.mjs +1 -0
  328. package/src/core/Base.mjs +55 -3
  329. package/src/core/Compare.mjs +4 -7
  330. package/src/core/Config.mjs +65 -52
  331. package/src/core/Effect.mjs +79 -13
  332. package/src/core/EffectBatchManager.mjs +18 -19
  333. package/src/core/EffectManager.mjs +25 -3
  334. package/src/core/IdGenerator.mjs +13 -44
  335. package/src/data/Model.mjs +2 -0
  336. package/src/data/Store.mjs +7 -0
  337. package/src/data/connection/WebSocket.mjs +2 -0
  338. package/src/date/DayViewComponent.mjs +2 -0
  339. package/src/date/SelectorContainer.mjs +14 -0
  340. package/src/dialog/Base.mjs +8 -0
  341. package/src/draggable/DragZone.mjs +5 -0
  342. package/src/draggable/tree/DragZone.mjs +1 -0
  343. package/src/filter/BooleanContainer.mjs +2 -0
  344. package/src/filter/NumberContainer.mjs +3 -0
  345. package/src/filter/ToggleOperatorsButton.mjs +2 -0
  346. package/src/form/Fieldset.mjs +6 -0
  347. package/src/form/field/Base.mjs +7 -0
  348. package/src/form/field/CheckBox.mjs +18 -0
  349. package/src/form/field/Chip.mjs +1 -0
  350. package/src/form/field/ComboBox.mjs +8 -0
  351. package/src/form/field/Country.mjs +1 -0
  352. package/src/form/field/Currency.mjs +2 -0
  353. package/src/form/field/Date.mjs +4 -0
  354. package/src/form/field/Display.mjs +1 -0
  355. package/src/form/field/Email.mjs +1 -0
  356. package/src/form/field/FileUpload.mjs +7 -0
  357. package/src/form/field/Hidden.mjs +1 -0
  358. package/src/form/field/Number.mjs +7 -0
  359. package/src/form/field/Password.mjs +1 -0
  360. package/src/form/field/Phone.mjs +3 -0
  361. package/src/form/field/Picker.mjs +2 -0
  362. package/src/form/field/Radio.mjs +1 -0
  363. package/src/form/field/Range.mjs +3 -0
  364. package/src/form/field/Search.mjs +2 -0
  365. package/src/form/field/Text.mjs +32 -0
  366. package/src/form/field/TextArea.mjs +7 -0
  367. package/src/form/field/Time.mjs +6 -0
  368. package/src/form/field/Url.mjs +3 -0
  369. package/src/form/field/ZipCode.mjs +2 -0
  370. package/src/form/field/trigger/Base.mjs +3 -0
  371. package/src/form/field/trigger/Clear.mjs +2 -0
  372. package/src/form/field/trigger/CopyToClipboard.mjs +2 -0
  373. package/src/form/field/trigger/Date.mjs +1 -0
  374. package/src/form/field/trigger/Picker.mjs +1 -0
  375. package/src/form/field/trigger/Search.mjs +1 -0
  376. package/src/form/field/trigger/SpinDown.mjs +2 -0
  377. package/src/form/field/trigger/SpinUp.mjs +1 -0
  378. package/src/form/field/trigger/Time.mjs +2 -0
  379. package/src/functional/_export.mjs +6 -0
  380. package/src/functional/component/Base.mjs +499 -0
  381. package/src/functional/defineComponent.mjs +102 -0
  382. package/src/functional/useConfig.mjs +52 -0
  383. package/src/functional/useEvent.mjs +43 -0
  384. package/src/grid/Body.mjs +20 -1
  385. package/src/grid/Container.mjs +50 -60
  386. package/src/grid/ScrollManager.mjs +2 -0
  387. package/src/grid/VerticalScrollbar.mjs +2 -0
  388. package/src/grid/column/Base.mjs +2 -0
  389. package/src/grid/header/Button.mjs +7 -0
  390. package/src/grid/header/Toolbar.mjs +6 -0
  391. package/src/grid/plugin/AnimateRows.mjs +2 -0
  392. package/src/layout/Base.mjs +3 -0
  393. package/src/layout/Card.mjs +1 -0
  394. package/src/layout/Cube.mjs +11 -1
  395. package/src/layout/Fit.mjs +1 -0
  396. package/src/layout/Flexbox.mjs +7 -0
  397. package/src/layout/Form.mjs +2 -0
  398. package/src/layout/Grid.mjs +1 -0
  399. package/src/layout/HBox.mjs +1 -0
  400. package/src/layout/VBox.mjs +1 -0
  401. package/src/list/Base.mjs +13 -0
  402. package/src/list/Chip.mjs +1 -0
  403. package/src/list/Circle.mjs +2 -0
  404. package/src/list/Color.mjs +1 -0
  405. package/src/list/plugin/Animate.mjs +2 -0
  406. package/src/main/DeltaUpdates.mjs +1 -0
  407. package/src/main/DomEvents.mjs +2 -0
  408. package/src/main/addon/CloneNode.mjs +1 -0
  409. package/src/main/addon/Cookie.mjs +1 -0
  410. package/src/main/addon/GoogleMaps.mjs +1 -0
  411. package/src/main/addon/LocalStorage.mjs +1 -0
  412. package/src/main/addon/MapboxGL.mjs +1 -0
  413. package/src/main/addon/Markdown.mjs +1 -0
  414. package/src/main/addon/Navigator.mjs +1 -0
  415. package/src/main/addon/Popover.mjs +1 -0
  416. package/src/main/addon/Stylesheet.mjs +1 -0
  417. package/src/main/addon/WindowPosition.mjs +1 -0
  418. package/src/manager/Component.mjs +0 -71
  419. package/src/manager/VDomUpdate.mjs +235 -0
  420. package/src/menu/List.mjs +6 -0
  421. package/src/menu/Model.mjs +1 -0
  422. package/src/menu/Panel.mjs +3 -0
  423. package/src/menu/Store.mjs +1 -0
  424. package/src/mixin/DomEvents.mjs +130 -0
  425. package/src/mixin/VdomLifecycle.mjs +667 -0
  426. package/src/plugin/Base.mjs +1 -0
  427. package/src/plugin/Resizable.mjs +2 -0
  428. package/src/selection/Model.mjs +15 -18
  429. package/src/selection/grid/BaseModel.mjs +1 -0
  430. package/src/sitemap/Component.mjs +1 -0
  431. package/src/state/Provider.mjs +98 -70
  432. package/src/state/createHierarchicalDataProxy.mjs +39 -25
  433. package/src/tab/Container.mjs +6 -0
  434. package/src/tab/Strip.mjs +1 -0
  435. package/src/tab/header/Button.mjs +2 -0
  436. package/src/tab/header/EffectButton.mjs +2 -0
  437. package/src/tab/header/Toolbar.mjs +1 -0
  438. package/src/table/Body.mjs +3 -0
  439. package/src/table/Container.mjs +10 -0
  440. package/src/table/header/Button.mjs +8 -0
  441. package/src/table/header/Toolbar.mjs +5 -0
  442. package/src/table/plugin/CellEditing.mjs +1 -0
  443. package/src/toolbar/Base.mjs +4 -0
  444. package/src/toolbar/Breadcrumb.mjs +3 -0
  445. package/src/toolbar/Paging.mjs +5 -0
  446. package/src/tooltip/Base.mjs +2 -0
  447. package/src/tree/List.mjs +3 -0
  448. package/src/util/HashHistory.mjs +1 -0
  449. package/src/util/KeyNavigation.mjs +2 -0
  450. package/src/util/Matrix.mjs +1 -0
  451. package/src/util/VDom.mjs +7 -1
  452. package/src/util/VNode.mjs +7 -1
  453. package/src/util/vdom/TreeBuilder.mjs +129 -0
  454. package/src/vdom/Helper.mjs +35 -23
  455. package/src/vdom/VNode.mjs +4 -6
  456. package/src/worker/App.mjs +1 -0
  457. package/src/worker/Base.mjs +2 -0
  458. package/src/worker/Manager.mjs +2 -0
  459. package/src/worker/ServiceBase.mjs +6 -1
  460. package/test/siesta/siesta.js +5 -2
  461. package/test/siesta/tests/VdomCalendar.mjs +13 -9
  462. package/test/siesta/tests/core/Effect.mjs +10 -14
  463. package/test/siesta/tests/core/EffectBatching.mjs +25 -37
  464. package/test/siesta/tests/state/ProviderNestedDataConfigs.mjs +255 -0
  465. package/test/siesta/tests/state/createHierarchicalDataProxy.mjs +42 -55
  466. package/test/siesta/tests/vdom/VdomAsymmetricUpdates.mjs +366 -0
  467. package/test/siesta/tests/vdom/VdomRealWorldUpdates.mjs +249 -0
  468. package/learn/javascript/NewNode.md +0 -31
@@ -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
@@ -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,129 @@
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
+ * Copies a given vdom tree and replaces child component references with the vdom of their matching components
28
+ * @param {Object} vdom
29
+ * @param {Number} [depth=-1]
30
+ * The component replacement depth.
31
+ * -1 will parse the full tree, 1 top level only, 2 include children, 3 include grandchildren
32
+ * @param {Set<String>|null} [mergedChildIds=null] A set of component IDs to selectively expand.
33
+ * @returns {Object}
34
+ */
35
+ getVdomTree(vdom, depth = -1, mergedChildIds = null) {
36
+ if (!Neo.isObject(vdom)) {
37
+ return vdom
38
+ }
39
+
40
+ let output = {...vdom}; // Shallow copy
41
+
42
+ if (vdom.cn) {
43
+ output.cn = [];
44
+
45
+ vdom.cn.forEach(item => {
46
+ let currentItem = item,
47
+ childDepth;
48
+
49
+ if (currentItem.componentId) {
50
+ // Prune the branch only if we are at the boundary AND the child is not part of a merged update
51
+ if (depth === 1 && !mergedChildIds?.has(currentItem.componentId)) {
52
+ output.cn.push({componentId: 'neo-ignore', id: item.id || item.componentId});
53
+ // Stop processing this branch
54
+ return
55
+ }
56
+ // Expand the branch if it's part of a merged update, or if the depth requires it
57
+ else if (depth > 1 || depth === -1 || mergedChildIds?.has(currentItem.componentId)) {
58
+ const component = ComponentManager.get(currentItem.componentId);
59
+ if (component?.vdom) {
60
+ currentItem = component.vdom
61
+ }
62
+ }
63
+ }
64
+
65
+ if (item.componentId) {
66
+ childDepth = (depth === -1) ? -1 : Math.max(0, depth - 1)
67
+ } else {
68
+ childDepth = depth
69
+ }
70
+
71
+ output.cn.push(this.getVdomTree(currentItem, childDepth, mergedChildIds))
72
+ })
73
+ }
74
+
75
+ return output
76
+ }
77
+
78
+ /**
79
+ * Copies a given vnode tree and replaces child component references with the vnode of their matching components
80
+ * @param {Object} vnode
81
+ * @param {Number} [depth=-1]
82
+ * The component replacement depth.
83
+ * -1 will parse the full tree, 1 top level only, 2 include children, 3 include grandchildren
84
+ * @param {Set<String>|null} [mergedChildIds=null] A set of component IDs to selectively expand.
85
+ * @returns {Object}
86
+ */
87
+ getVnodeTree(vnode, depth = -1, mergedChildIds = null) {
88
+ let output = {...vnode}; // Shallow copy
89
+
90
+ if (vnode.childNodes) {
91
+ output.childNodes = [];
92
+
93
+ vnode.childNodes.forEach(item => {
94
+ let currentItem = item,
95
+ childDepth, component;
96
+
97
+ if (currentItem.componentId) {
98
+ // Prune the branch only if we are at the boundary AND the child is not part of a merged update
99
+ if (depth === 1 && !mergedChildIds?.has(currentItem.componentId)) {
100
+ output.childNodes.push({componentId: 'neo-ignore', id: item.id || item.componentId});
101
+ // Stop processing this branch
102
+ return
103
+ }
104
+ // Expand the branch if it's part of a merged update, or if the depth requires it
105
+ else if (depth > 1 || depth === -1 || mergedChildIds?.has(currentItem.componentId)) {
106
+ component = ComponentManager.get(currentItem.componentId);
107
+
108
+ // Keep references in case there is no vnode (e.g. component not mounted yet)
109
+ if (component?.vnode) {
110
+ currentItem = component.vnode
111
+ }
112
+ }
113
+ }
114
+
115
+ if (item.componentId) {
116
+ childDepth = (depth === -1) ? -1 : Math.max(0, depth - 1)
117
+ } else {
118
+ childDepth = depth
119
+ }
120
+
121
+ output.childNodes.push(this.getVnodeTree(currentItem, childDepth, mergedChildIds))
122
+ })
123
+ }
124
+
125
+ return output
126
+ }
127
+ }
128
+
129
+ 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
  /**
@@ -9,6 +9,8 @@ import RemoteMethodAccess from './mixin/RemoteMethodAccess.mjs';
9
9
  * The abstract base class for e.g. the App, Data & VDom worker
10
10
  * @class Neo.worker.Base
11
11
  * @extends Neo.core.Base
12
+ * @mixes Neo.core.Observable
13
+ * @mixes Neo.worker.mixin.RemoteMethodAccess
12
14
  * @abstract
13
15
  */
14
16
  class Worker extends Base {
@@ -18,6 +18,8 @@ navigator.serviceWorker?.addEventListener('controllerchange', function() {
18
18
  * Also, responsible for sending messages from the main thread to the different workers.
19
19
  * @class Neo.worker.Manager
20
20
  * @extends Neo.core.Base
21
+ * @mixes Neo.core.Observable
22
+ * @mixes Neo.worker.mixin.RemoteMethodAccess
21
23
  * @singleton
22
24
  */
23
25
  class Manager extends Base {