neo.mjs 10.0.0-beta.4 → 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 (485) hide show
  1. package/.github/RELEASE_NOTES/v10.0.0-beta.4.md +2 -2
  2. package/.github/RELEASE_NOTES/v10.0.0-beta.5.md +70 -0
  3. package/.github/RELEASE_NOTES/v10.0.0-beta.6.md +48 -0
  4. package/.github/epic-functional-components.md +498 -0
  5. package/.github/ticket-asymmetric-vdom-updates.md +122 -0
  6. package/README.md +0 -3
  7. package/ServiceWorker.mjs +2 -2
  8. package/apps/colors/store/Colors.mjs +1 -0
  9. package/apps/colors/view/GridContainer.mjs +3 -0
  10. package/apps/colors/view/HeaderToolbar.mjs +2 -0
  11. package/apps/colors/view/Viewport.mjs +3 -0
  12. package/apps/covid/view/FooterContainer.mjs +3 -0
  13. package/apps/covid/view/GalleryContainer.mjs +2 -0
  14. package/apps/covid/view/GalleryContainerController.mjs +1 -0
  15. package/apps/covid/view/HeaderContainer.mjs +2 -0
  16. package/apps/covid/view/HelixContainer.mjs +2 -0
  17. package/apps/covid/view/HelixContainerController.mjs +1 -0
  18. package/apps/covid/view/MainContainer.mjs +3 -0
  19. package/apps/covid/view/TableContainer.mjs +3 -0
  20. package/apps/covid/view/TableContainerController.mjs +1 -0
  21. package/apps/covid/view/WorldMapContainer.mjs +2 -0
  22. package/apps/covid/view/country/Gallery.mjs +3 -0
  23. package/apps/covid/view/country/Helix.mjs +8 -0
  24. package/apps/covid/view/country/HistoricalDataTable.mjs +1 -0
  25. package/apps/covid/view/country/Table.mjs +2 -0
  26. package/apps/covid/view/mapboxGl/Component.mjs +1 -0
  27. package/apps/covid/view/mapboxGl/Container.mjs +2 -0
  28. package/apps/email/EPIC_PLAN.md +58 -0
  29. package/apps/email/neo-config.json +2 -2
  30. package/apps/email/store/Emails.mjs +11 -1
  31. package/apps/email/view/ComposeView.mjs +44 -0
  32. package/apps/email/view/MainView.mjs +89 -0
  33. package/apps/email/view/Viewport.mjs +4 -33
  34. package/apps/email/view/ViewportStateProvider.mjs +3 -3
  35. package/apps/form/store/SideNav.mjs +1 -0
  36. package/apps/form/view/FormContainer.mjs +1 -0
  37. package/apps/form/view/FormPageContainer.mjs +2 -0
  38. package/apps/form/view/SideNavList.mjs +1 -0
  39. package/apps/form/view/Viewport.mjs +3 -0
  40. package/apps/portal/childapps/preview/MainContainer.mjs +1 -0
  41. package/apps/portal/index.html +1 -1
  42. package/apps/portal/store/BlogPosts.mjs +2 -0
  43. package/apps/portal/store/Content.mjs +1 -0
  44. package/apps/portal/store/ContentSections.mjs +1 -0
  45. package/apps/portal/store/Examples.mjs +1 -0
  46. package/apps/portal/view/HeaderToolbar.mjs +1 -0
  47. package/apps/portal/view/Viewport.mjs +5 -0
  48. package/apps/portal/view/ViewportController.mjs +8 -2
  49. package/apps/portal/view/about/Container.mjs +2 -0
  50. package/apps/portal/view/about/MemberContainer.mjs +7 -0
  51. package/apps/portal/view/blog/Container.mjs +2 -0
  52. package/apps/portal/view/blog/List.mjs +2 -0
  53. package/apps/portal/view/examples/List.mjs +1 -0
  54. package/apps/portal/view/examples/TabContainer.mjs +4 -0
  55. package/apps/portal/view/home/ContentBox.mjs +3 -0
  56. package/apps/portal/view/home/FeatureSection.mjs +8 -0
  57. package/apps/portal/view/home/FooterContainer.mjs +4 -1
  58. package/apps/portal/view/home/MainContainer.mjs +2 -0
  59. package/apps/portal/view/home/parts/AfterMath.mjs +2 -0
  60. package/apps/portal/view/home/parts/BaseContainer.mjs +1 -0
  61. package/apps/portal/view/home/parts/Colors.mjs +4 -0
  62. package/apps/portal/view/home/parts/Features.mjs +2 -0
  63. package/apps/portal/view/home/parts/Helix.mjs +5 -0
  64. package/apps/portal/view/home/parts/How.mjs +4 -0
  65. package/apps/portal/view/home/parts/MainNeo.mjs +1 -0
  66. package/apps/portal/view/home/parts/References.mjs +2 -0
  67. package/apps/portal/view/learn/ContentComponent.mjs +11 -5
  68. package/apps/portal/view/learn/ContentTreeList.mjs +2 -0
  69. package/apps/portal/view/learn/CubeLayoutButton.mjs +1 -0
  70. package/apps/portal/view/learn/MainContainer.mjs +4 -0
  71. package/apps/portal/view/learn/PageContainer.mjs +2 -0
  72. package/apps/portal/view/learn/PageSectionsContainer.mjs +3 -0
  73. package/apps/portal/view/learn/PageSectionsList.mjs +1 -0
  74. package/apps/portal/view/services/Component.mjs +1 -0
  75. package/apps/realworld/api/Base.mjs +1 -0
  76. package/apps/realworld/view/HeaderComponent.mjs +4 -0
  77. package/apps/realworld/view/HomeComponent.mjs +7 -0
  78. package/apps/realworld/view/MainContainer.mjs +2 -0
  79. package/apps/realworld/view/MainContainerController.mjs +2 -0
  80. package/apps/realworld/view/article/CommentComponent.mjs +3 -0
  81. package/apps/realworld/view/article/Component.mjs +17 -10
  82. package/apps/realworld/view/article/CreateCommentComponent.mjs +2 -0
  83. package/apps/realworld/view/article/CreateComponent.mjs +5 -0
  84. package/apps/realworld/view/article/PreviewComponent.mjs +9 -0
  85. package/apps/realworld/view/article/TagListComponent.mjs +2 -0
  86. package/apps/realworld/view/user/ProfileComponent.mjs +7 -0
  87. package/apps/realworld/view/user/SettingsComponent.mjs +5 -0
  88. package/apps/realworld/view/user/SignUpComponent.mjs +3 -0
  89. package/apps/realworld2/api/Base.mjs +1 -0
  90. package/apps/realworld2/view/FooterComponent.mjs +1 -0
  91. package/apps/realworld2/view/HeaderToolbar.mjs +3 -0
  92. package/apps/realworld2/view/HomeContainer.mjs +1 -0
  93. package/apps/realworld2/view/MainContainer.mjs +2 -0
  94. package/apps/realworld2/view/MainContainerController.mjs +1 -0
  95. package/apps/realworld2/view/article/Helix.mjs +1 -0
  96. package/apps/realworld2/view/article/PreviewComponent.mjs +9 -0
  97. package/apps/realworld2/view/article/PreviewList.mjs +1 -0
  98. package/apps/realworld2/view/article/TagListComponent.mjs +2 -0
  99. package/apps/route/view/CenterContainer.mjs +1 -0
  100. package/apps/route/view/MainView.mjs +1 -0
  101. package/apps/sharedcovid/childapps/sharedcovidchart/MainContainer.mjs +1 -0
  102. package/apps/sharedcovid/childapps/sharedcovidgallery/MainContainer.mjs +1 -0
  103. package/apps/sharedcovid/childapps/sharedcovidhelix/MainContainer.mjs +1 -0
  104. package/apps/sharedcovid/childapps/sharedcovidmap/MainContainer.mjs +1 -0
  105. package/apps/sharedcovid/view/FooterContainer.mjs +3 -0
  106. package/apps/sharedcovid/view/GalleryContainer.mjs +2 -0
  107. package/apps/sharedcovid/view/GalleryContainerController.mjs +1 -0
  108. package/apps/sharedcovid/view/HeaderContainer.mjs +2 -0
  109. package/apps/sharedcovid/view/HelixContainer.mjs +2 -0
  110. package/apps/sharedcovid/view/HelixContainerController.mjs +1 -0
  111. package/apps/sharedcovid/view/MainContainer.mjs +3 -0
  112. package/apps/sharedcovid/view/TableContainer.mjs +3 -0
  113. package/apps/sharedcovid/view/TableContainerController.mjs +1 -0
  114. package/apps/sharedcovid/view/WorldMapContainer.mjs +2 -0
  115. package/apps/sharedcovid/view/country/Gallery.mjs +3 -0
  116. package/apps/sharedcovid/view/country/Helix.mjs +8 -0
  117. package/apps/sharedcovid/view/country/HistoricalDataTable.mjs +1 -0
  118. package/apps/sharedcovid/view/country/Table.mjs +2 -0
  119. package/apps/sharedcovid/view/mapboxGl/Component.mjs +1 -0
  120. package/apps/sharedcovid/view/mapboxGl/Container.mjs +2 -0
  121. package/apps/shareddialog/childapps/shareddialog2/view/MainContainer.mjs +2 -0
  122. package/apps/shareddialog/view/DemoDialog.mjs +2 -0
  123. package/apps/shareddialog/view/MainContainer.mjs +2 -0
  124. package/apps/shareddialog/view/MainContainerController.mjs +1 -0
  125. package/buildScripts/addReactiveTags.mjs +191 -0
  126. package/buildScripts/checkReactiveTags.mjs +160 -0
  127. package/docs/app/store/Api.mjs +1 -0
  128. package/docs/app/store/Examples.mjs +1 -0
  129. package/docs/app/view/ApiTreeList.mjs +1 -0
  130. package/docs/app/view/ContentTabContainer.mjs +2 -0
  131. package/docs/app/view/ExamplesTreeList.mjs +2 -0
  132. package/docs/app/view/HeaderContainer.mjs +3 -0
  133. package/docs/app/view/MainContainer.mjs +5 -0
  134. package/docs/app/view/classdetails/HeaderComponent.mjs +1 -0
  135. package/docs/app/view/classdetails/MainContainer.mjs +3 -0
  136. package/docs/app/view/classdetails/MembersList.mjs +5 -0
  137. package/docs/app/view/classdetails/SourceViewComponent.mjs +2 -0
  138. package/examples/ConfigurationViewport.mjs +14 -8
  139. package/examples/button/effect/MainContainer.mjs +207 -0
  140. package/examples/button/effect/app.mjs +6 -0
  141. package/examples/button/effect/index.html +11 -0
  142. package/examples/button/effect/neo-config.json +6 -0
  143. package/examples/calendar/weekview/MainContainer.mjs +4 -0
  144. package/examples/component/coronaGallery/CountryGallery.mjs +2 -0
  145. package/examples/component/coronaGallery/CountryStore.mjs +1 -0
  146. package/examples/component/coronaGallery/Viewport.mjs +3 -0
  147. package/examples/component/coronaGallery/ViewportController.mjs +1 -0
  148. package/examples/component/coronaHelix/CountryHelix.mjs +7 -0
  149. package/examples/component/coronaHelix/MainContainer.mjs +1 -0
  150. package/examples/component/gallery/ImageStore.mjs +1 -0
  151. package/examples/component/helix/ImageStore.mjs +1 -0
  152. package/examples/component/helix/Viewport.mjs +3 -0
  153. package/examples/component/helix/ViewportController.mjs +1 -0
  154. package/examples/component/multiWindowCoronaGallery/childapp/Viewport.mjs +1 -0
  155. package/examples/component/multiWindowHelix/childapp/Viewport.mjs +1 -0
  156. package/examples/component/wrapper/googleMaps/MapComponent.mjs +2 -0
  157. package/examples/core/config/MainContainer.mjs +2 -0
  158. package/examples/dialog/DemoDialog.mjs +2 -0
  159. package/examples/dialog/MainContainer.mjs +1 -0
  160. package/examples/form/field/color/MainStore.mjs +1 -0
  161. package/examples/functional/defineComponent/Component.mjs +18 -0
  162. package/examples/functional/defineComponent/MainContainer.mjs +41 -0
  163. package/examples/functional/defineComponent/app.mjs +6 -0
  164. package/examples/functional/defineComponent/index.html +11 -0
  165. package/examples/functional/defineComponent/neo-config.json +6 -0
  166. package/examples/functional/hostComponent/Component.mjs +32 -0
  167. package/examples/functional/hostComponent/MainContainer.mjs +48 -0
  168. package/examples/functional/hostComponent/app.mjs +6 -0
  169. package/examples/functional/hostComponent/index.html +11 -0
  170. package/examples/functional/hostComponent/neo-config.json +6 -0
  171. package/examples/grid/animatedRowSorting/Viewport.mjs +1 -1
  172. package/examples/grid/bigData/ControlsContainer.mjs +3 -0
  173. package/examples/grid/bigData/GridContainer.mjs +4 -2
  174. package/examples/grid/bigData/MainContainer.mjs +2 -0
  175. package/examples/grid/bigData/MainModel.mjs +1 -0
  176. package/examples/grid/bigData/MainStore.mjs +3 -0
  177. package/examples/grid/cellEditing/MainContainer.mjs +1 -1
  178. package/examples/grid/container/MainContainer.mjs +1 -1
  179. package/examples/grid/covid/GridContainer.mjs +3 -0
  180. package/examples/grid/covid/MainContainer.mjs +2 -0
  181. package/examples/grid/covid/Store.mjs +1 -0
  182. package/examples/grid/nestedRecordFields/EditUserDialog.mjs +3 -0
  183. package/examples/grid/nestedRecordFields/Viewport.mjs +3 -1
  184. package/examples/list/animate/List.mjs +4 -0
  185. package/examples/list/animate/MainContainer.mjs +2 -0
  186. package/examples/list/circle/MainStore.mjs +1 -0
  187. package/examples/list/color/MainStore.mjs +1 -0
  188. package/examples/preloadingAssets/view/MainContainer.mjs +2 -0
  189. package/examples/stateProvider/advanced/MainContainer.mjs +1 -0
  190. package/examples/stateProvider/dialog/EditUserDialog.mjs +2 -0
  191. package/examples/stateProvider/dialog/MainContainer.mjs +1 -0
  192. package/examples/stateProvider/extendedClass/MainContainer.mjs +2 -0
  193. package/examples/stateProvider/inline/MainContainer.mjs +1 -0
  194. package/examples/stateProvider/inlineNoStateProvider/MainContainer.mjs +1 -0
  195. package/examples/stateProvider/inlineNoStateProvider/MainContainerController.mjs +2 -0
  196. package/examples/stateProvider/multiWindow/EditUserDialog.mjs +3 -0
  197. package/examples/stateProvider/multiWindow/MainContainer.mjs +1 -0
  198. package/examples/stateProvider/multiWindow/Viewport.mjs +1 -0
  199. package/examples/stateProvider/nestedData/MainContainer.mjs +1 -0
  200. package/examples/stateProvider/table/MainContainer.mjs +1 -0
  201. package/examples/table/covid/MainContainer.mjs +2 -0
  202. package/examples/table/covid/Store.mjs +1 -0
  203. package/examples/table/covid/TableContainer.mjs +3 -0
  204. package/examples/table/nestedRecordFields/EditUserDialog.mjs +3 -0
  205. package/examples/table/nestedRecordFields/Viewport.mjs +1 -0
  206. package/examples/todoList/version1/MainComponent.mjs +1 -1
  207. package/examples/toolbar/breadcrumb/view/MainContainer.mjs +2 -0
  208. package/examples/toolbar/paging/store/Users.mjs +1 -0
  209. package/examples/toolbar/paging/view/AddUserDialog.mjs +3 -0
  210. package/examples/toolbar/paging/view/MainContainer.mjs +3 -0
  211. package/examples/treeAccordion/MainContainer.mjs +2 -2
  212. package/examples/worker/task/MainContainer.mjs +1 -0
  213. package/learn/Glossary.md +1 -0
  214. package/learn/UsingTheseTopics.md +1 -0
  215. package/learn/benefits/ConfigSystem.md +2 -0
  216. package/learn/benefits/Effort.md +1 -0
  217. package/learn/benefits/Features.md +1 -0
  218. package/learn/benefits/FormsEngine.md +1 -0
  219. package/learn/benefits/FourEnvironments.md +2 -0
  220. package/learn/benefits/Introduction.md +2 -0
  221. package/learn/benefits/MultiWindow.md +3 -1
  222. package/learn/benefits/OffTheMainThread.md +2 -0
  223. package/learn/benefits/Quick.md +2 -0
  224. package/learn/benefits/RPCLayer.md +2 -0
  225. package/learn/benefits/Speed.md +2 -0
  226. package/learn/comparisons/NeoVsAngular.md +90 -0
  227. package/learn/comparisons/NeoVsExtJs.md +178 -0
  228. package/learn/comparisons/NeoVsNextJs.md +124 -0
  229. package/learn/comparisons/NeoVsReact.md +95 -0
  230. package/learn/comparisons/NeoVsSolid.md +78 -0
  231. package/learn/comparisons/NeoVsVue.md +92 -0
  232. package/learn/comparisons/Overview.md +46 -0
  233. package/learn/gettingstarted/ComponentModels.md +2 -0
  234. package/learn/gettingstarted/Config.md +2 -0
  235. package/learn/gettingstarted/DescribingTheUI.md +2 -0
  236. package/learn/gettingstarted/Events.md +2 -0
  237. package/learn/gettingstarted/Extending.md +2 -0
  238. package/learn/gettingstarted/References.md +2 -0
  239. package/learn/gettingstarted/Setup.md +3 -2
  240. package/learn/gettingstarted/Workspaces.md +2 -0
  241. package/learn/guides/datahandling/Collections.md +1 -0
  242. package/learn/guides/datahandling/Records.md +1 -0
  243. package/learn/guides/datahandling/StateProviders.md +131 -16
  244. package/learn/guides/datahandling/Tables.md +1 -1
  245. package/learn/guides/fundamentals/ConfigSystemDeepDive.md +1 -0
  246. package/learn/guides/fundamentals/DeclarativeComponentTreesVsImperativeVdom.md +2 -0
  247. package/learn/guides/fundamentals/DeclarativeVDOMWithEffects.md +168 -0
  248. package/learn/guides/fundamentals/ExtendingNeoClasses.md +1 -0
  249. package/learn/guides/fundamentals/InstanceLifecycle.md +3 -1
  250. package/learn/guides/fundamentals/MainThreadAddons.md +2 -0
  251. package/learn/guides/specificfeatures/Mixins.md +3 -1
  252. package/learn/guides/specificfeatures/MultiWindow.md +3 -1
  253. package/learn/guides/specificfeatures/PortalApp.md +2 -0
  254. package/learn/guides/uibuildingblocks/ComponentsAndContainers.md +2 -0
  255. package/learn/guides/uibuildingblocks/CustomComponents.md +2 -0
  256. package/learn/guides/uibuildingblocks/Layouts.md +2 -0
  257. package/learn/guides/uibuildingblocks/WorkingWithVDom.md +2 -0
  258. package/learn/guides/userinteraction/Forms.md +2 -0
  259. package/learn/guides/userinteraction/events/CustomEvents.md +2 -1
  260. package/learn/guides/userinteraction/events/DomEvents.md +2 -0
  261. package/learn/javascript/ClassFeatures.md +4 -3
  262. package/learn/javascript/Classes.md +10 -13
  263. package/learn/javascript/Overrides.md +10 -6
  264. package/learn/javascript/Super.md +12 -8
  265. package/learn/tree.json +71 -63
  266. package/learn/tutorials/Earthquakes.md +2 -0
  267. package/learn/tutorials/RSP.md +3 -1
  268. package/learn/tutorials/TodoList.md +103 -7
  269. package/package.json +6 -4
  270. package/resources/scss/src/apps/email/ComposeView.scss +16 -0
  271. package/resources/scss/src/apps/email/MainView.scss +5 -0
  272. package/resources/scss/src/apps/portal/learn/ContentComponent.scss +5 -4
  273. package/src/DefaultConfig.mjs +12 -2
  274. package/src/Main.mjs +1 -0
  275. package/src/Neo.mjs +377 -178
  276. package/src/Xhr.mjs +1 -0
  277. package/src/button/Base.mjs +13 -0
  278. package/src/button/Effect.mjs +449 -0
  279. package/src/button/Split.mjs +2 -0
  280. package/src/calendar/store/Calendars.mjs +1 -0
  281. package/src/calendar/store/Colors.mjs +1 -0
  282. package/src/calendar/store/Events.mjs +1 -0
  283. package/src/calendar/view/DayComponent.mjs +2 -0
  284. package/src/calendar/view/EditEventContainer.mjs +4 -1
  285. package/src/calendar/view/MainContainer.mjs +13 -0
  286. package/src/calendar/view/MainContainerStateProvider.mjs +14 -28
  287. package/src/calendar/view/SettingsContainer.mjs +1 -0
  288. package/src/calendar/view/YearComponent.mjs +16 -0
  289. package/src/calendar/view/calendars/ColorsList.mjs +2 -0
  290. package/src/calendar/view/calendars/Container.mjs +2 -0
  291. package/src/calendar/view/calendars/EditContainer.mjs +1 -0
  292. package/src/calendar/view/month/Component.mjs +11 -0
  293. package/src/calendar/view/settings/GeneralContainer.mjs +1 -0
  294. package/src/calendar/view/settings/MonthContainer.mjs +1 -0
  295. package/src/calendar/view/settings/WeekContainer.mjs +1 -0
  296. package/src/calendar/view/settings/YearContainer.mjs +1 -0
  297. package/src/calendar/view/week/Component.mjs +15 -1
  298. package/src/calendar/view/week/TimeAxisComponent.mjs +4 -0
  299. package/src/code/LivePreview.mjs +51 -23
  300. package/src/collection/Base.mjs +14 -12
  301. package/src/collection/Filter.mjs +6 -0
  302. package/src/collection/Sorter.mjs +3 -0
  303. package/src/component/Base.mjs +156 -802
  304. package/src/component/Canvas.mjs +1 -0
  305. package/src/component/Chip.mjs +4 -0
  306. package/src/component/Circle.mjs +14 -0
  307. package/src/component/Clock.mjs +4 -0
  308. package/src/component/DateSelector.mjs +12 -0
  309. package/src/component/Gallery.mjs +11 -0
  310. package/src/component/Helix.mjs +24 -0
  311. package/src/component/Label.mjs +1 -0
  312. package/src/component/Legend.mjs +3 -0
  313. package/src/component/MagicMoveText.mjs +4 -0
  314. package/src/component/Progress.mjs +3 -0
  315. package/src/component/Splitter.mjs +3 -0
  316. package/src/component/StatusBadge.mjs +6 -0
  317. package/src/component/Timer.mjs +4 -0
  318. package/src/component/Toast.mjs +6 -0
  319. package/src/component/Video.mjs +1 -0
  320. package/src/component/mwc/Button.mjs +7 -0
  321. package/src/component/mwc/TextField.mjs +9 -0
  322. package/src/component/wrapper/AmChart.mjs +2 -0
  323. package/src/component/wrapper/GoogleMaps.mjs +3 -0
  324. package/src/component/wrapper/MapboxGL.mjs +5 -0
  325. package/src/component/wrapper/MonacoEditor.mjs +12 -0
  326. package/src/container/Accordion.mjs +2 -0
  327. package/src/container/Base.mjs +34 -26
  328. package/src/container/Panel.mjs +1 -0
  329. package/src/container/Viewport.mjs +1 -0
  330. package/src/controller/Application.mjs +1 -0
  331. package/src/controller/Base.mjs +1 -0
  332. package/src/controller/Component.mjs +1 -0
  333. package/src/core/Base.mjs +193 -22
  334. package/src/core/Compare.mjs +4 -7
  335. package/src/core/Config.mjs +137 -33
  336. package/src/core/Effect.mjs +193 -0
  337. package/src/core/EffectBatchManager.mjs +67 -0
  338. package/src/core/EffectManager.mjs +60 -0
  339. package/src/core/IdGenerator.mjs +13 -44
  340. package/src/data/Model.mjs +2 -0
  341. package/src/data/Store.mjs +7 -0
  342. package/src/data/connection/WebSocket.mjs +2 -0
  343. package/src/date/DayViewComponent.mjs +2 -0
  344. package/src/date/SelectorContainer.mjs +14 -0
  345. package/src/dialog/Base.mjs +8 -0
  346. package/src/draggable/DragZone.mjs +5 -0
  347. package/src/draggable/tree/DragZone.mjs +1 -0
  348. package/src/filter/BooleanContainer.mjs +2 -0
  349. package/src/filter/NumberContainer.mjs +3 -0
  350. package/src/filter/ToggleOperatorsButton.mjs +2 -0
  351. package/src/form/Fieldset.mjs +6 -0
  352. package/src/form/field/Base.mjs +7 -0
  353. package/src/form/field/CheckBox.mjs +18 -0
  354. package/src/form/field/Chip.mjs +1 -0
  355. package/src/form/field/ComboBox.mjs +8 -0
  356. package/src/form/field/Country.mjs +1 -0
  357. package/src/form/field/Currency.mjs +2 -0
  358. package/src/form/field/Date.mjs +4 -0
  359. package/src/form/field/Display.mjs +1 -0
  360. package/src/form/field/Email.mjs +1 -0
  361. package/src/form/field/FileUpload.mjs +7 -0
  362. package/src/form/field/Hidden.mjs +1 -0
  363. package/src/form/field/Number.mjs +7 -0
  364. package/src/form/field/Password.mjs +1 -0
  365. package/src/form/field/Phone.mjs +3 -0
  366. package/src/form/field/Picker.mjs +2 -0
  367. package/src/form/field/Radio.mjs +1 -0
  368. package/src/form/field/Range.mjs +3 -0
  369. package/src/form/field/Search.mjs +2 -0
  370. package/src/form/field/Text.mjs +32 -0
  371. package/src/form/field/TextArea.mjs +7 -0
  372. package/src/form/field/Time.mjs +6 -0
  373. package/src/form/field/Url.mjs +3 -0
  374. package/src/form/field/ZipCode.mjs +2 -0
  375. package/src/form/field/trigger/Base.mjs +3 -0
  376. package/src/form/field/trigger/Clear.mjs +2 -0
  377. package/src/form/field/trigger/CopyToClipboard.mjs +2 -0
  378. package/src/form/field/trigger/Date.mjs +1 -0
  379. package/src/form/field/trigger/Picker.mjs +1 -0
  380. package/src/form/field/trigger/Search.mjs +1 -0
  381. package/src/form/field/trigger/SpinDown.mjs +2 -0
  382. package/src/form/field/trigger/SpinUp.mjs +1 -0
  383. package/src/form/field/trigger/Time.mjs +2 -0
  384. package/src/functional/_export.mjs +6 -0
  385. package/src/functional/component/Base.mjs +499 -0
  386. package/src/functional/defineComponent.mjs +102 -0
  387. package/src/functional/useConfig.mjs +52 -0
  388. package/src/functional/useEvent.mjs +43 -0
  389. package/src/grid/Body.mjs +20 -1
  390. package/src/grid/Container.mjs +57 -63
  391. package/src/grid/ScrollManager.mjs +2 -0
  392. package/src/grid/VerticalScrollbar.mjs +2 -0
  393. package/src/grid/column/Base.mjs +2 -0
  394. package/src/grid/column/Component.mjs +1 -1
  395. package/src/grid/header/Button.mjs +7 -0
  396. package/src/grid/header/Toolbar.mjs +6 -0
  397. package/src/grid/plugin/AnimateRows.mjs +2 -0
  398. package/src/layout/Base.mjs +3 -0
  399. package/src/layout/Card.mjs +1 -0
  400. package/src/layout/Cube.mjs +11 -1
  401. package/src/layout/Fit.mjs +1 -0
  402. package/src/layout/Flexbox.mjs +7 -0
  403. package/src/layout/Form.mjs +2 -0
  404. package/src/layout/Grid.mjs +1 -0
  405. package/src/layout/HBox.mjs +1 -0
  406. package/src/layout/VBox.mjs +1 -0
  407. package/src/list/Base.mjs +13 -0
  408. package/src/list/Chip.mjs +1 -0
  409. package/src/list/Circle.mjs +2 -0
  410. package/src/list/Color.mjs +1 -0
  411. package/src/list/plugin/Animate.mjs +2 -0
  412. package/src/main/DeltaUpdates.mjs +1 -0
  413. package/src/main/DomEvents.mjs +2 -0
  414. package/src/main/addon/CloneNode.mjs +1 -0
  415. package/src/main/addon/Cookie.mjs +1 -0
  416. package/src/main/addon/GoogleMaps.mjs +1 -0
  417. package/src/main/addon/LocalStorage.mjs +1 -0
  418. package/src/main/addon/MapboxGL.mjs +1 -0
  419. package/src/main/addon/Markdown.mjs +1 -0
  420. package/src/main/addon/Navigator.mjs +1 -0
  421. package/src/main/addon/Popover.mjs +1 -0
  422. package/src/main/addon/Stylesheet.mjs +1 -0
  423. package/src/main/addon/WindowPosition.mjs +1 -0
  424. package/src/manager/Component.mjs +0 -71
  425. package/src/manager/VDomUpdate.mjs +235 -0
  426. package/src/menu/List.mjs +6 -0
  427. package/src/menu/Model.mjs +1 -0
  428. package/src/menu/Panel.mjs +3 -0
  429. package/src/menu/Store.mjs +1 -0
  430. package/src/mixin/DomEvents.mjs +130 -0
  431. package/src/mixin/VdomLifecycle.mjs +667 -0
  432. package/src/plugin/Base.mjs +1 -0
  433. package/src/plugin/Resizable.mjs +2 -0
  434. package/src/selection/Model.mjs +15 -18
  435. package/src/selection/grid/BaseModel.mjs +1 -0
  436. package/src/sitemap/Component.mjs +1 -0
  437. package/src/state/Provider.mjs +376 -457
  438. package/src/state/createHierarchicalDataProxy.mjs +138 -0
  439. package/src/tab/Container.mjs +6 -0
  440. package/src/tab/Strip.mjs +1 -0
  441. package/src/tab/header/Button.mjs +2 -0
  442. package/src/tab/header/EffectButton.mjs +77 -0
  443. package/src/tab/header/Toolbar.mjs +1 -0
  444. package/src/table/Body.mjs +3 -0
  445. package/src/table/Container.mjs +10 -0
  446. package/src/table/header/Button.mjs +8 -0
  447. package/src/table/header/Toolbar.mjs +5 -0
  448. package/src/table/plugin/CellEditing.mjs +1 -0
  449. package/src/toolbar/Base.mjs +4 -0
  450. package/src/toolbar/Breadcrumb.mjs +3 -0
  451. package/src/toolbar/Paging.mjs +5 -0
  452. package/src/tooltip/Base.mjs +2 -0
  453. package/src/tree/List.mjs +3 -0
  454. package/src/util/HashHistory.mjs +1 -0
  455. package/src/util/KeyNavigation.mjs +2 -0
  456. package/src/util/Matrix.mjs +1 -0
  457. package/src/util/VDom.mjs +7 -1
  458. package/src/util/VNode.mjs +7 -1
  459. package/src/util/vdom/TreeBuilder.mjs +129 -0
  460. package/src/vdom/Helper.mjs +44 -33
  461. package/src/vdom/VNode.mjs +5 -7
  462. package/src/worker/App.mjs +1 -5
  463. package/src/worker/Base.mjs +2 -0
  464. package/src/worker/Manager.mjs +2 -0
  465. package/src/worker/ServiceBase.mjs +6 -1
  466. package/test/siesta/siesta.js +36 -1
  467. package/test/siesta/tests/CollectionBase.mjs +10 -10
  468. package/test/siesta/tests/VdomCalendar.mjs +13 -9
  469. package/test/siesta/tests/VdomHelper.mjs +22 -59
  470. package/test/siesta/tests/config/AfterSetConfig.mjs +100 -0
  471. package/test/siesta/tests/{ReactiveConfigs.mjs → config/Basic.mjs} +58 -21
  472. package/test/siesta/tests/config/CircularDependencies.mjs +166 -0
  473. package/test/siesta/tests/config/CustomFunctions.mjs +69 -0
  474. package/test/siesta/tests/config/Hierarchy.mjs +94 -0
  475. package/test/siesta/tests/config/MemoryLeak.mjs +92 -0
  476. package/test/siesta/tests/config/MultiLevelHierarchy.mjs +85 -0
  477. package/test/siesta/tests/core/Effect.mjs +127 -0
  478. package/test/siesta/tests/core/EffectBatching.mjs +310 -0
  479. package/test/siesta/tests/neo/MixinStaticConfig.mjs +138 -0
  480. package/test/siesta/tests/state/Provider.mjs +537 -0
  481. package/test/siesta/tests/state/ProviderNestedDataConfigs.mjs +255 -0
  482. package/test/siesta/tests/state/createHierarchicalDataProxy.mjs +204 -0
  483. package/test/siesta/tests/vdom/VdomAsymmetricUpdates.mjs +366 -0
  484. package/test/siesta/tests/vdom/VdomRealWorldUpdates.mjs +249 -0
  485. package/learn/javascript/NewNode.md +0 -31
@@ -1,13 +1,14 @@
1
1
  import Base from '../core/Base.mjs';
2
2
  import ClassSystemUtil from '../util/ClassSystem.mjs';
3
3
  import ComponentManager from '../manager/Component.mjs';
4
- import DomEventManager from '../manager/DomEvent.mjs';
4
+ import DomEvents from '../mixin/DomEvents.mjs';
5
5
  import KeyNavigation from '../util/KeyNavigation.mjs';
6
6
  import Logger from '../util/Logger.mjs';
7
7
  import NeoArray from '../util/Array.mjs';
8
8
  import Observable from '../core/Observable.mjs';
9
9
  import Rectangle from '../util/Rectangle.mjs';
10
10
  import Style from '../util/Style.mjs';
11
+ import VdomLifecycle from '../mixin/VdomLifecycle.mjs';
11
12
  import VDomUtil from '../util/VDom.mjs';
12
13
  import VNodeUtil from '../util/VNode.mjs';
13
14
  import {isDescriptor} from '../core/ConfigSymbols.mjs';
@@ -24,6 +25,9 @@ const
24
25
  * Base class for all Components which have a DOM representation
25
26
  * @class Neo.component.Base
26
27
  * @extends Neo.core.Base
28
+ * @mixes Neo.component.mixin.DomEvents
29
+ * @mixes Neo.core.Observable
30
+ * @mixes Neo.component.mixin.VdomLifecycle
27
31
  */
28
32
  class Component extends Base {
29
33
  /**
@@ -33,12 +37,6 @@ class Component extends Base {
33
37
  * @static
34
38
  */
35
39
  static hideModes = ['removeDom', 'visibility']
36
- /**
37
- * True automatically applies the core.Observable mixin
38
- * @member {Boolean} observable=true
39
- * @static
40
- */
41
- static observable = true
42
40
 
43
41
  static config = {
44
42
  /**
@@ -54,32 +52,23 @@ class Component extends Base {
54
52
  /**
55
53
  * The default alignment specification to position this Component relative to some other
56
54
  * Component, or Element or Rectangle. Only applies in case floating = true.
57
- * @member {Object|String} align_={edgeAlign:'t-b',constrainTo:'document.body'}
55
+ * @member {Object|String} align_={[isDescriptor]: true, merge: 'deep', value: {edgeAlign: 't-b',constrainTo: 'document.body'}}
56
+ * @reactive
58
57
  */
59
58
  align_: {
60
- edgeAlign : 't-b',
61
- constrainTo: 'document.body'
59
+ [isDescriptor]: true,
60
+ merge : 'deep',
61
+ value: {
62
+ edgeAlign : 't-b',
63
+ constrainTo: 'document.body'
64
+ }
62
65
  },
63
66
  /**
64
67
  * The name of the App this component belongs to
65
68
  * @member {String|null} appName_=null
69
+ * @reactive
66
70
  */
67
71
  appName_: null,
68
- /**
69
- * True automatically mounts a component after being rendered.
70
- * Use this for the top level component of your app.
71
- * @member {Boolean} autoMount=false
72
- * @tutorial 02_ClassSystem
73
- */
74
- autoMount: false,
75
- /**
76
- * True automatically renders a component after being created inside the init call.
77
- * Use this for the top level component of your app.
78
- * @member {Boolean} autoRender=false
79
- * @see {@link Neo.component.Base#init init}
80
- * @tutorial 02_ClassSystem
81
- */
82
- autoRender: false,
83
72
  /**
84
73
  * CSS selectors to apply to the root level node of this component
85
74
  * @member {String[]} baseCls=[]
@@ -101,17 +90,20 @@ class Component extends Base {
101
90
  * Custom CSS selectors to apply to the root level node of this component
102
91
  * You can override baseCls to remove default selectors.
103
92
  * @member {String[]} cls_=null
93
+ * @reactive
104
94
  */
105
95
  cls_: null,
106
96
  /**
107
97
  * manager.Focus will change this flag on focusin & out dom events
108
98
  * @member {Boolean} containsFocus_=false
109
99
  * @protected
100
+ * @reactive
110
101
  */
111
102
  containsFocus_: false,
112
103
  /**
113
104
  * Assign a component controller to this component (pass an imported module or the string based class name)
114
105
  * @member {Neo.controller.Component|String} controller_=null
106
+ * @reactive
115
107
  */
116
108
  controller_: null,
117
109
  /**
@@ -119,32 +111,19 @@ class Component extends Base {
119
111
  * Read only.
120
112
  * @member {Object} data_=null
121
113
  * @protected
114
+ * @reactive
122
115
  */
123
116
  data_: null,
124
117
  /**
125
118
  * Disabled components will get the neo-disabled cls applied and won't receive DOM events
126
119
  * @member {Boolean} disabled_=false
120
+ * @reactive
127
121
  */
128
122
  disabled_: false,
129
- /**
130
- * An array of domListener configs
131
- * @member {Object[]|null} domListeners_=null
132
- * @example
133
- * afterSetStayOnHover(value, oldValue) {
134
- * if (value) {
135
- * let me = this;
136
- *
137
- * me.addDomListeners(
138
- * {mouseenter: me.onMouseEnter, scope: me},
139
- * {mouseleave: me.onMouseLeave, scope: me}
140
- * )
141
- * }
142
- *}
143
- */
144
- domListeners_: null,
145
123
  /**
146
124
  * Set this config to true to dynamically import a DropZone module & create an instance
147
125
  * @member {Boolean} droppable_=false
126
+ * @reactive
148
127
  */
149
128
  droppable_: false,
150
129
  /**
@@ -166,39 +145,30 @@ class Component extends Base {
166
145
  * @protected
167
146
  */
168
147
  hasBeenMounted: false,
169
- /**
170
- * Internal flag
171
- * @member {Boolean} hasRenderingListener=false
172
- * @protected
173
- */
174
- hasRenderingListener: false,
175
- /**
176
- * Internal flag for vdom changes after a component got unmounted
177
- * (delta updates can no longer get applied & a new render call is required before re-mounting)
178
- * @member {Boolean} hasUnmountedVdomChanges_=false
179
- * @protected
180
- */
181
- hasUnmountedVdomChanges_: false,
182
148
  /**
183
149
  * Shortcut for style.height, defaults to px
184
150
  * @member {Number|String|null} height_=null
151
+ * @reactive
185
152
  */
186
153
  height_: null,
187
154
  /**
188
155
  * Initial setting to hide or show the component and
189
156
  * you can use either hide()/show() or change this config directly to change the hidden state
190
157
  * @member {Boolean} hidden_=false
158
+ * @reactive
191
159
  */
192
160
  hidden_: false,
193
161
  /**
194
162
  * Used for hide and show and defines if the component
195
163
  * should use css visibility:'hidden' or vdom:removeDom
196
164
  * @member {String} hideMode_='removeDom'
165
+ * @reactive
197
166
  */
198
167
  hideMode_: 'removeDom',
199
168
  /**
200
169
  * The top level innerHTML of the component
201
170
  * @member {String|null} html_=null
171
+ * @reactive
202
172
  */
203
173
  html_: null,
204
174
  /**
@@ -207,78 +177,73 @@ class Component extends Base {
207
177
  * @member {Boolean|String} isLoading=false
208
178
  */
209
179
  isLoading_: false,
210
- /**
211
- * Internal flag which will get set to true while an update request (worker messages) is in progress
212
- * @member {Boolean} isVdomUpdating_=false
213
- * @protected
214
- */
215
- isVdomUpdating_: false,
216
180
  /**
217
181
  * Using the keys config will create an instance of Neo.util.KeyNavigation.
218
182
  * @see {@link Neo.util.KeyNavigation KeyNavigation}
219
183
  * @member {Object} keys_=null
184
+ * @reactive
220
185
  */
221
186
  keys_: null,
222
187
  /**
223
188
  * Gets used inside afterSetIsLoading() to define the CSS for the loading spinner icon
224
189
  * @member {String[]} loadingSpinnerCls_=['fa','fa-spinner','fa-spin']
190
+ * @reactive
225
191
  */
226
192
  loadingSpinnerCls_: ['fa', 'fa-spinner', 'fa-spin'],
227
193
  /**
228
194
  * Shortcut for style.maxHeight, defaults to px
229
195
  * @member {Number|String|null} maxHeight_=null
196
+ * @reactive
230
197
  */
231
198
  maxHeight_: null,
232
199
  /**
233
200
  * Shortcut for style.maxWidth, defaults to px
234
201
  * @member {Number|String|null} maxWidth_=null
202
+ * @reactive
235
203
  */
236
204
  maxWidth_: null,
237
205
  /**
238
206
  * Shortcut for style.minHeight, defaults to px
239
207
  * @member {Number|String|null} minHeight_=null
208
+ * @reactive
240
209
  */
241
210
  minHeight_: null,
242
211
  /**
243
212
  * Shortcut for style.minWidth, defaults to px
244
213
  * @member {Number|String|null} minWidth_=null
214
+ * @reactive
245
215
  */
246
216
  minWidth_: null,
217
+ /**
218
+ * @member {Neo.core.Base[]} mixins=[DomEvents, Observable, VdomLifecycle]
219
+ */
220
+ mixins: [DomEvents, Observable, VdomLifecycle],
247
221
  /**
248
222
  * Override specific stateProvider data properties.
249
223
  * This will merge the content.
250
224
  * @member {Object|null} modelData=null
251
225
  */
252
226
  modelData: null,
253
- /**
254
- * True in case the component is mounted to the DOM
255
- * @member {Boolean} mounted_=false
256
- * @protected
257
- */
258
- mounted_: false,
259
- /**
260
- * Internal flag which will get set to true in case an update call arrives while another update is running
261
- * @member {Boolean} needsVdomUpdate_=false
262
- * @protected
263
- */
264
- needsVdomUpdate_: false,
265
227
  /**
266
228
  * If the parentId does not match a neo component id, you can manually set this value for finding
267
229
  * view controllers or state providers.
268
230
  * Use case: manually dropping components into a vdom structure
269
231
  * @member {Neo.component.Base|null} parentComponent_=null
270
232
  * @protected
233
+ * @reactive
271
234
  */
272
235
  parentComponent_: null,
273
236
  /**
274
237
  * The parent component id or document.body
275
238
  * @member {String} parentId_='document.body'
239
+ * @reactive
276
240
  */
277
241
  parentId_: 'document.body',
278
242
  /**
279
243
  * Array of Plugin Modules and / or config objects
280
244
  * @member {Array|null} plugins_=null
281
245
  * @protected
246
+ * @reactive
282
247
  */
283
248
  plugins_: null,
284
249
  /**
@@ -286,6 +251,7 @@ class Component extends Base {
286
251
  * References will also get mapped into the vdom root (data-ref: value).
287
252
  * @member {String|null} reference_=null
288
253
  * @protected
254
+ * @reactive
289
255
  */
290
256
  reference_: null,
291
257
  /**
@@ -295,16 +261,11 @@ class Component extends Base {
295
261
  * @protected
296
262
  */
297
263
  responsive_: null,
298
- /**
299
- * True in case the component is rendering the vnode
300
- * @member {Boolean} rendering_=false
301
- * @protected
302
- */
303
- rendering_: false,
304
264
  /**
305
265
  * Specify a role tag attribute for the vdom root.
306
266
  * See: https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Roles
307
267
  * @member {String|null} role_=null
268
+ * @reactive
308
269
  */
309
270
  role_: null,
310
271
  /**
@@ -312,28 +273,29 @@ class Component extends Base {
312
273
  * Set this to 'x' or 'y' to add style 'overflow-x' or 'overflow-y' to 'auto'
313
274
  * Other than false this will add cls 'neo-scrollable'.
314
275
  * @member {Boolean|"x"|"y"} scrollable_=false
276
+ * @reactive
315
277
  */
316
278
  scrollable_: false,
317
- /**
318
- * Set this to true for bulk updates. Ensure to set it back to false afterwards.
319
- * Internally the value will get saved as a number to ensure that child methods won't stop the silent mode too early.
320
- * @member {Boolean} silentVdomUpdate_=false
321
- */
322
- silentVdomUpdate_: false,
323
279
  /**
324
280
  * Optionally add a state.Provider to share state data with child components
325
281
  * @member {Object|null} stateProvider_=null
282
+ * @reactive
326
283
  */
327
284
  stateProvider_: null,
328
285
  /**
329
286
  * Style attributes added to this vdom root. see: getVdomRoot()
330
- * @member {Object} style_=null
287
+ * @member {Object} style={[isDescriptor]: true, merge: 'shallow', value: null}
331
288
  */
332
- style_: null,
289
+ style_: {
290
+ [isDescriptor]: true,
291
+ merge : 'shallow',
292
+ value : null
293
+ },
333
294
  /**
334
295
  * You can pass a used theme directly to any component,
335
296
  * to style specific component trees differently from your main view.
336
297
  * @member {String|null} theme_=null
298
+ * @reactive
337
299
  */
338
300
  theme_: null,
339
301
  /**
@@ -341,11 +303,13 @@ class Component extends Base {
341
303
  * this shortcut enables us to change the vdom root tag on instance level.
342
304
  * Use cases: switch a Toolbar to a "nav" tag, switch a SideNav to an "aside" tag.
343
305
  * @member {String|null} tag_=null
306
+ * @reactive
344
307
  */
345
308
  tag_: null,
346
309
  /**
347
310
  * The top level textContent of the component
348
311
  * @member {String|null} text_=null
312
+ * @reactive
349
313
  */
350
314
  text_: null,
351
315
  /**
@@ -358,51 +322,42 @@ class Component extends Base {
358
322
  * If a widget needs its own instance for any reason, inslude the property `ownInstance : true`
359
323
  * in the tooltip config object.
360
324
  * @member {Object|String} tooltip_=null
325
+ * @reactive
361
326
  */
362
327
  tooltip_: null,
363
328
  /**
364
329
  * Add 'primary' and other attributes to make it an outstanding design
365
330
  * @member {String|null} ui_=null
331
+ * @reactive
366
332
  */
367
333
  ui_: null,
368
- /**
369
- * Defines the depth of the vdom tree for the next update cycle.
370
- * - The value 1 will only send the current vdom structure as it is
371
- * - The value of 2 will include the vdom of direct children
372
- * - The value of 3 will include the vdom of grandchildren
373
- * - The value of -1 will include the full tree of any depth
374
- * @member {Number} updateDepth_=1
375
- */
376
- updateDepth_: 1,
377
- /**
378
- * The component vnode tree. Available after the component got rendered.
379
- * @member {Object} vnode_=null
380
- * @protected
381
- */
382
- vnode_: {
383
- [isDescriptor]: true,
384
- value : null,
385
- isEqual : (a, b) => a === b // vnode trees can be huge, and will get compared by the vdom worker.
386
- },
387
334
  /**
388
335
  * Shortcut for style.width, defaults to px
389
336
  * @member {Number|String|null} width_=null
337
+ * @reactive
390
338
  */
391
339
  width_: null,
392
340
  /**
393
341
  * The custom windowIs (timestamp) this component belongs to
394
342
  * @member {Number|null} windowId_=null
343
+ * @reactive
395
344
  */
396
345
  windowId_: null,
397
346
  /**
398
347
  * @member {String[]|null} wrapperCls_=null
348
+ * @reactive
399
349
  */
400
350
  wrapperCls_: null,
401
351
  /**
402
352
  * Top level style attributes. Useful in case getVdomRoot() does not point to the top level DOM node.
403
- * @member {Object|null} wrapperStyle_=null
353
+ * @member {Object|null} wrapperStyle_={[isDescriptor]: true, merge: 'shallow', value: null}
354
+ * @reactive
404
355
  */
405
- wrapperStyle_: null,
356
+ wrapperStyle_: {
357
+ [isDescriptor]: true,
358
+ merge : 'shallow',
359
+ value : null
360
+ },
406
361
  /**
407
362
  * The vdom markup for this component.
408
363
  * @member {Object} _vdom={}
@@ -411,21 +366,11 @@ class Component extends Base {
411
366
  }
412
367
 
413
368
  /**
414
- * If an update() gets called while a parent is updating, we store the id & distance of the
415
- * requesting component inside the childUpdateCache of the parent, to get resolved once the update is done.
416
- * e.g. childUpdateCache = {'neo-grid-view-1': {distance: 1, resolve: fn}}
417
- * @member {Object} childUpdateCache={}
418
- */
419
- childUpdateCache = {}
420
- /**
421
- * Stores the updateDepth while an update is running to enable checks for parent update collisions
422
- * @member {Number|null} currentUpdateDepth=null
423
- */
424
- currentUpdateDepth = null
425
- /**
426
- * @member {Function[]} resolveUpdateCache=[]
369
+ * Internal flag which will get set to true while a component is waiting for its mountedPromise
370
+ * @member {Boolean} isAwaitingMount=false
371
+ * @protected
427
372
  */
428
- resolveUpdateCache = []
373
+ isAwaitingMount = false
429
374
 
430
375
  /**
431
376
  * Convenience shortcut to access the App this component belongs to
@@ -453,6 +398,33 @@ class Component extends Base {
453
398
  this._listeners = value
454
399
  }
455
400
 
401
+ /**
402
+ * A Promise that resolves when the component is mounted to the DOM.
403
+ * This provides a convenient way to wait for the component to be fully
404
+ * available and interactive before executing subsequent logic.
405
+ *
406
+ * It also handles unmounting by resetting the promise, so it can be safely
407
+ * awaited again if the component is remounted.
408
+ * @returns {Promise<Neo.component.Base>}
409
+ */
410
+ get mountedPromise() {
411
+ let me = this;
412
+
413
+ if (!me._mountedPromise) {
414
+ me._mountedPromise = new Promise(resolve => {
415
+ if (me.mounted) {
416
+ // If already mounted, resolve immediately.
417
+ resolve(me)
418
+ } else {
419
+ // Otherwise, store the resolver to be called by afterSetMounted.
420
+ me.mountedPromiseResolve = resolve
421
+ }
422
+ })
423
+ }
424
+
425
+ return this._mountedPromise
426
+ }
427
+
456
428
  /**
457
429
  * Convenience method to access the parent component
458
430
  * @returns {Neo.component.Base|null}
@@ -503,21 +475,7 @@ class Component extends Base {
503
475
  this.cls = cls
504
476
  }
505
477
 
506
- /**
507
- * Convenience shortcut to add additional dom listeners
508
- * @param {Object|Object[]} value
509
- */
510
- addDomListeners(value) {
511
- if (!Array.isArray(value)) {
512
- value = [value]
513
- }
514
-
515
- let domListeners = this.domListeners;
516
-
517
- domListeners.push(...value);
518
478
 
519
- this.domListeners = domListeners
520
- }
521
479
 
522
480
  /**
523
481
  * Either a string like 'color: red; background-color: blue;'
@@ -593,7 +551,12 @@ class Component extends Base {
593
551
  afterSetConfig(key, value, oldValue) {
594
552
  let me = this;
595
553
 
596
- if (currentWorker.isUsingStateProviders && me[twoWayBindingSymbol] && oldValue !== undefined) {
554
+ if (Neo.isUsingStateProviders && me[twoWayBindingSymbol]) {
555
+ // When a component config is updated by its state provider, this flag is set to the config's key.
556
+ // This prevents circular updates in two-way data bindings by skipping the push back to the state provider.
557
+ if (me._skipTwoWayPush === key) {
558
+ return;
559
+ }
597
560
  let binding = me.bind?.[key];
598
561
 
599
562
  if (binding?.twoWay) {
@@ -615,19 +578,7 @@ class Component extends Base {
615
578
  this.cls = cls
616
579
  }
617
580
 
618
- /**
619
- * Registers the domListeners inside the Neo.manager.DomEvent
620
- * @param {Object[]} value
621
- * @param {Object[]} oldValue
622
- * @protected
623
- */
624
- afterSetDomListeners(value, oldValue) {
625
- let me = this;
626
581
 
627
- if (value?.[0] || oldValue?.[0]) {
628
- DomEventManager.updateDomListeners(me, value, oldValue)
629
- }
630
- }
631
582
 
632
583
  /**
633
584
  * Triggered after the droppable config got changed
@@ -651,29 +602,6 @@ class Component extends Base {
651
602
  }
652
603
  }
653
604
 
654
- /**
655
- * Triggered after the hasUnmountedVdomChanges config got changed
656
- * @param {Boolean} value
657
- * @param {Boolean} oldValue
658
- * @protected
659
- */
660
- afterSetHasUnmountedVdomChanges(value, oldValue) {
661
- if (value || (!value && oldValue)) {
662
- let parentIds = ComponentManager.getParentIds(this),
663
- i = 0,
664
- len = parentIds.length,
665
- parent;
666
-
667
- for (; i < len; i++) {
668
- parent = Neo.getComponent(parentIds[i]);
669
-
670
- if (parent) {
671
- parent._hasUnmountedVdomChanges = value // silent update
672
- }
673
- }
674
- }
675
- }
676
-
677
605
  /**
678
606
  * Triggered after the height config got changed
679
607
  * @param {Number|String|null} value
@@ -767,16 +695,6 @@ class Component extends Base {
767
695
  }
768
696
  }
769
697
 
770
- /**
771
- * Triggered after the isVdomUpdating config got changed
772
- * @param {Number|null} value
773
- * @param {Number|null} oldValue
774
- * @protected
775
- */
776
- afterSetIsVdomUpdating(value, oldValue) {
777
- this.currentUpdateDepth = value ? this.updateDepth : null
778
- }
779
-
780
698
  /**
781
699
  * Triggered after the maxHeight config got changed
782
700
  * @param {Number|String|null} value
@@ -832,17 +750,10 @@ class Component extends Base {
832
750
  let me = this,
833
751
  {id, windowId} = me;
834
752
 
835
- if (value) {
753
+ if (value) { // mount
836
754
  me.hasBeenMounted = true;
837
755
 
838
- if (me.domListeners?.length > 0) {
839
- // todo: the main thread reply of mount arrives after pushing the task into the queue which does not ensure the dom is mounted
840
- me.timeout(150).then(() => {
841
- DomEventManager.mountDomListeners(me)
842
- })
843
- }
844
-
845
- me.doResolveUpdateCache();
756
+ me.initDomEvents();
846
757
 
847
758
  if (me.floating) {
848
759
  me.alignTo();
@@ -851,9 +762,15 @@ class Component extends Base {
851
762
  me.focus(id, true)
852
763
  }
853
764
 
854
- me.fire('mounted', me.id)
855
- } else {
856
- me.revertFocus()
765
+ me.mountedPromiseResolve?.(this);
766
+ delete me.mountedPromiseResolve;
767
+
768
+ me.fire('mounted', me.id);
769
+ } else { // unmount
770
+ me.revertFocus();
771
+
772
+ // The promise needs to get reset, in case the component gets remounted.
773
+ delete me._mountedPromise;
857
774
  }
858
775
  }
859
776
  }
@@ -939,6 +856,16 @@ class Component extends Base {
939
856
  }
940
857
  }
941
858
 
859
+ /**
860
+ * Triggered after the stateProvider config got changed
861
+ * @param {Neo.state.Provider} value
862
+ * @param {Object|Neo.state.Provider|null} oldValue
863
+ * @protected
864
+ */
865
+ afterSetStateProvider(value, oldValue) {
866
+ value?.createBindings(this)
867
+ }
868
+
942
869
  /**
943
870
  * Triggered after the style config got changed
944
871
  * @param {Object} value
@@ -1042,26 +969,6 @@ class Component extends Base {
1042
969
  me.cls = cls
1043
970
  }
1044
971
 
1045
- /**
1046
- * Triggered after the vdom pseudo-config got changed
1047
- * @param {Object} value
1048
- * @param {Object|null} oldValue
1049
- * @protected
1050
- */
1051
- afterSetVdom(value, oldValue) {
1052
- this.updateVdom()
1053
- }
1054
-
1055
- /**
1056
- * Triggered after the vnode config got changed
1057
- * @param {Object} value
1058
- * @param {Object|null} oldValue
1059
- * @protected
1060
- */
1061
- afterSetVnode(value, oldValue) {
1062
- oldValue !== undefined && this.syncVnodeTree()
1063
- }
1064
-
1065
972
  /**
1066
973
  * Triggered after the width config got changed
1067
974
  * @param {Number|String|null} value
@@ -1232,8 +1139,7 @@ class Component extends Base {
1232
1139
  }
1233
1140
  }
1234
1141
 
1235
- // merge the incoming alignment specification into the configured default
1236
- return Neo.merge({}, value, me.constructor.config.align)
1142
+ return value
1237
1143
  }
1238
1144
 
1239
1145
  /**
@@ -1458,22 +1364,6 @@ class Component extends Base {
1458
1364
  }
1459
1365
  }
1460
1366
 
1461
- /**
1462
- * Convenience shortcut to create a component reference
1463
- * @returns {Object}
1464
- */
1465
- createVdomReference() {
1466
- let me = this,
1467
- reference = {componentId: me.id},
1468
- vdomId = me.vdom.id;
1469
-
1470
- if (vdomId && me.id !== vdomId) {
1471
- reference.id = vdomId
1472
- }
1473
-
1474
- return reference
1475
- }
1476
-
1477
1367
  /**
1478
1368
  * Unregister this instance from the ComponentManager
1479
1369
  * @param {Boolean} updateParentVdom=false true to remove the component from the parent vdom => real dom
@@ -1481,14 +1371,13 @@ class Component extends Base {
1481
1371
  * todo: unregister events
1482
1372
  */
1483
1373
  destroy(updateParentVdom=false, silent=false) {
1484
- let me = this,
1485
- {parent, parentId} = me,
1486
- parentStateProvider = parent?.getStateProvider(),
1374
+ let me = this,
1375
+ {parent, parentId} = me,
1487
1376
  parentVdom;
1488
1377
 
1489
1378
  me.revertFocus();
1490
1379
 
1491
- me.domListeners = [];
1380
+ me.removeDomEvents();
1492
1381
 
1493
1382
  me.controller = null; // triggers destroy()
1494
1383
 
@@ -1496,8 +1385,6 @@ class Component extends Base {
1496
1385
 
1497
1386
  me.stateProvider = null; // triggers destroy()
1498
1387
 
1499
- me.bind && parentStateProvider?.removeBindings(me.id);
1500
-
1501
1388
  me.plugins?.forEach(plugin => {
1502
1389
  plugin.destroy()
1503
1390
  });
@@ -1522,18 +1409,6 @@ class Component extends Base {
1522
1409
  me.unmount = Neo.emptyFn
1523
1410
  }
1524
1411
 
1525
- /**
1526
- * Triggers all stored resolve() callbacks
1527
- */
1528
- doResolveUpdateCache() {
1529
- let me = this;
1530
-
1531
- if (me.resolveUpdateCache) {
1532
- me.resolveUpdateCache.forEach(item => item());
1533
- me.resolveUpdateCache = []
1534
- }
1535
- }
1536
-
1537
1412
  /**
1538
1413
  * Convenience shortcut for Neo.manager.Component.down
1539
1414
  * @param {Object|String} config
@@ -1544,59 +1419,6 @@ class Component extends Base {
1544
1419
  return ComponentManager.down(this, config, returnFirstMatch)
1545
1420
  }
1546
1421
 
1547
- /**
1548
- * Internal method to send update requests to the vdom worker
1549
- * @param {function} [resolve] used by promiseUpdate()
1550
- * @param {function} [reject] used by promiseUpdate()
1551
- * @private
1552
- */
1553
- #executeVdomUpdate(resolve, reject) {
1554
- let me = this,
1555
- {vdom, vnode} = me,
1556
- opts = {},
1557
- deltas;
1558
-
1559
- if (currentWorker.isSharedWorker) {
1560
- opts.appName = me.appName;
1561
- opts.windowId = me.windowId
1562
- }
1563
-
1564
- me.isVdomUpdating = true;
1565
-
1566
- // we can not set the config directly => it could already be false,
1567
- // and we still want to pass it further into subtrees
1568
- me._needsVdomUpdate = false;
1569
- me.afterSetNeedsVdomUpdate?.(false, true);
1570
-
1571
- opts.vdom = ComponentManager.getVdomTree(vdom, me.updateDepth);
1572
- opts.vnode = ComponentManager.getVnodeTree(vnode, me.updateDepth);
1573
-
1574
- // Reset the updateDepth to the default value for the next update cycle
1575
- me._updateDepth = me.constructor.config.updateDepth;
1576
-
1577
- Neo.vdom.Helper.update(opts).catch(err => {
1578
- me.isVdomUpdating = false;
1579
- reject?.()
1580
- }).then(data => {
1581
- // Checking if the component got destroyed before the update cycle is done
1582
- if (me.id) {
1583
- // It is crucial to delegate the vnode tree before resolving the cycle
1584
- me.vnode = data.vnode;
1585
- me.isVdomUpdating = false;
1586
-
1587
- deltas = data.deltas;
1588
-
1589
- if (!Neo.config.useVdomWorker && deltas.length > 0) {
1590
- Neo.applyDeltas(me.appName, deltas).then(() => {
1591
- me.resolveVdomUpdate(resolve)
1592
- })
1593
- } else {
1594
- me.resolveVdomUpdate(resolve)
1595
- }
1596
- }
1597
- })
1598
- }
1599
-
1600
1422
  /**
1601
1423
  * Calls focus() on the top level DOM node of this component or on a given node via id
1602
1424
  * @param {String} id=this.id
@@ -1642,7 +1464,8 @@ class Component extends Base {
1642
1464
  }
1643
1465
 
1644
1466
  if (parentComponent) {
1645
- return parentComponent.getConfigInstanceByNtype(configName, ntype)
1467
+ // todo: We need ?. until functional.component.Base supports controllers
1468
+ return parentComponent.getConfigInstanceByNtype?.(configName, ntype)
1646
1469
  }
1647
1470
 
1648
1471
  return null
@@ -1690,43 +1513,6 @@ class Component extends Base {
1690
1513
  return Rectangle.clone(result)
1691
1514
  }
1692
1515
 
1693
- /**
1694
- * Honors different item roots for mount / render OPs
1695
- * @returns {String}
1696
- */
1697
- getMountedParentId() {
1698
- let parentId = this.parentId,
1699
- parent = Neo.getComponent(parentId),
1700
- itemsRoot = parent?.getVdomItemsRoot?.();
1701
-
1702
- return itemsRoot ? itemsRoot.id : parentId
1703
- }
1704
-
1705
- /**
1706
- * Calculate the real parentIndex inside the DOM
1707
- * @returns {Number|undefined}
1708
- */
1709
- getMountedParentIndex() {
1710
- let parent = this.parent,
1711
- items = parent?.items || [],
1712
- i = 0,
1713
- index = 0,
1714
- len = items.length,
1715
- item;
1716
-
1717
- for (; i < len; i++) {
1718
- item = items[i];
1719
-
1720
- if (item === this) {
1721
- return index
1722
- }
1723
-
1724
- if (!item.hidden && item.hideMode === 'removeDom') {
1725
- index++
1726
- }
1727
- }
1728
- }
1729
-
1730
1516
  /**
1731
1517
  * Get the parent components as an array
1732
1518
  * @returns {Neo.component.Base[]}
@@ -1793,7 +1579,7 @@ class Component extends Base {
1793
1579
  * @returns {Neo.state.Provider|null}
1794
1580
  */
1795
1581
  getStateProvider(ntype) {
1796
- if (!currentWorker.isUsingStateProviders) {
1582
+ if (!Neo.isUsingStateProviders) {
1797
1583
  return null
1798
1584
  }
1799
1585
 
@@ -1849,44 +1635,6 @@ class Component extends Base {
1849
1635
  return Neo.config.themes?.[0]
1850
1636
  }
1851
1637
 
1852
- /**
1853
- * Search a vdom child node by id for a given vdom tree
1854
- * @param {String} id
1855
- * @param {Object} vdom=this.vdom
1856
- * @returns {Object}
1857
- */
1858
- getVdomChild(id, vdom=this.vdom) {
1859
- return VDomUtil.find(vdom, id)?.vdom
1860
- }
1861
-
1862
- /**
1863
- * Specify a different vdom root if needed to apply the top level style attributes on a different level.
1864
- * Make sure to use getVnodeRoot() as well, to keep the vdom & vnode trees in sync.
1865
- * @returns {Object} The new vdom root
1866
- */
1867
- getVdomRoot() {
1868
- return this.vdom
1869
- }
1870
-
1871
- /**
1872
- * Specify a different vnode root if needed to apply the top level style attributes on a different level.
1873
- * Make sure to use getVdomRoot() as well, to keep the vdom & vnode trees in sync.
1874
- * @returns {Object} The new vnode root
1875
- */
1876
- getVnodeRoot() {
1877
- return this.vnode
1878
- }
1879
-
1880
- /**
1881
- * Checks if a given updateDepth & distance would result in an update collision
1882
- * @param {Number} updateDepth
1883
- * @param {Number} distance
1884
- * @returns {Boolean}
1885
- */
1886
- hasUpdateCollision(updateDepth, distance) {
1887
- return updateDepth === -1 ? true : distance < updateDepth
1888
- }
1889
-
1890
1638
  /**
1891
1639
  * Hide the component.
1892
1640
  * hideMode: 'removeDom' uses vdom removeDom.
@@ -1930,16 +1678,11 @@ class Component extends Base {
1930
1678
  }
1931
1679
 
1932
1680
  /**
1933
- * We are using this method as a ctor hook here to add the initial state.Provider & controller.Component parsing
1934
- * @param {Object} config
1935
- * @param {Boolean} [preventOriginalConfig] True prevents the instance from getting an originalConfig property
1681
+ * @param args
1936
1682
  */
1937
- initConfig(config, preventOriginalConfig) {
1938
- super.initConfig(config, preventOriginalConfig);
1939
-
1940
- let me = this;
1941
-
1942
- me.getStateProvider()?.parseConfig(me)
1683
+ initConfig(...args) {
1684
+ super.initConfig(...args);
1685
+ this.getStateProvider()?.createBindings(this)
1943
1686
  }
1944
1687
 
1945
1688
  /**
@@ -1960,45 +1703,6 @@ class Component extends Base {
1960
1703
  return me.parent.floating
1961
1704
  }
1962
1705
 
1963
- /**
1964
- * Checks for vdom updates inside the parent chain and if found.
1965
- * Registers the component for a vdom update once done.
1966
- * @param {String} parentId=this.parentId
1967
- * @param {Function} [resolve] Gets passed by updateVdom()
1968
- * @param {Number} distance=1 Distance inside the component tree
1969
- * @returns {Boolean}
1970
- */
1971
- isParentUpdating(parentId=this.parentId, resolve, distance=1) {
1972
- if (parentId !== 'document.body') {
1973
- let me = this,
1974
- parent = Neo.getComponent(parentId);
1975
-
1976
- if (parent) {
1977
- if (parent.isVdomUpdating) {
1978
- if (me.hasUpdateCollision(parent.currentUpdateDepth, distance)) {
1979
- if (Neo.config.logVdomUpdateCollisions) {
1980
- console.warn('vdom parent update conflict with:', parent, 'for:', me)
1981
- }
1982
-
1983
- parent.childUpdateCache[me.id] = {distance, resolve};
1984
-
1985
- // Adding the resolve fn to its own cache, since the parent will trigger
1986
- // a new update() directly on this cmp
1987
- resolve && me.resolveUpdateCache.push(resolve);
1988
- return true
1989
- }
1990
-
1991
- // If an update is running and does not have a collision, we do not need to check further parents
1992
- return false
1993
- }
1994
-
1995
- return me.isParentUpdating(parent.parentId, resolve, distance+1)
1996
- }
1997
- }
1998
-
1999
- return false
2000
- }
2001
-
2002
1706
  /**
2003
1707
  * @param {Number|String} value
2004
1708
  * @returns {Promise<number>}
@@ -2025,28 +1729,15 @@ class Component extends Base {
2025
1729
  * @returns {Object} config
2026
1730
  */
2027
1731
  mergeConfig(...args) {
2028
- let me = this,
2029
- config = super.mergeConfig(...args),
2030
-
2031
- // it should be possible to set custom configs for the vdom on instance level,
2032
- // however there will be already added attributes (e.g. id), so a merge seems to be the best strategy.
2033
- vdom = {...me._vdom || {}, ...config.vdom || {}};
2034
-
2035
- // avoid any interference on prototype level
2036
- // does not clone existing Neo instances
2037
- me._vdom = Neo.clone(vdom, true, true);
1732
+ let config = super.mergeConfig(...args),
1733
+ vdom = config.vdom || config._vdom || {};
2038
1734
 
2039
- if (config.style) {
2040
- // If we are passed an object, merge it with the class's own style
2041
- me.style = Neo.typeOf(config.style) === 'Object' ? {...config.style, ...me.constructor.config.style} : config.style
2042
- }
2043
-
2044
- me.wrapperStyle = Neo.clone(config.wrapperStyle, false);
1735
+ // It should be possible to modify root level vdom attributes on instance level.
1736
+ // Note that vdom is not a real config, but implemented via get() & set().
1737
+ this._vdom = Neo.clone({...vdom, ...this._vdom || {}}, true);
2045
1738
 
2046
- delete config.style;
2047
1739
  delete config._vdom;
2048
1740
  delete config.vdom;
2049
- delete config.wrapperStyle;
2050
1741
 
2051
1742
  return config
2052
1743
  }
@@ -2099,40 +1790,16 @@ class Component extends Base {
2099
1790
  }
2100
1791
  }
2101
1792
 
2102
- /**
2103
- * Checks the needsVdomUpdate config inside the parent tree
2104
- * @param {String} parentId=this.parentId
2105
- * @param {Function} [resolve] gets passed by updateVdom()
2106
- * @param {Number} distance=1 Distance inside the component tree
2107
- * @returns {Boolean}
2108
- */
2109
- needsParentUpdate(parentId=this.parentId, resolve, distance=1) {
2110
- if (parentId !== 'document.body') {
2111
- let me = this,
2112
- parent = Neo.getComponent(parentId);
2113
-
2114
- if (parent) {
2115
- // We are checking for parent.updateDepth, since we care about the depth of the next update cycle
2116
- if (parent.needsVdomUpdate && me.hasUpdateCollision(parent.updateDepth, distance)) {
2117
- parent.resolveUpdateCache.push(...me.resolveUpdateCache);
2118
- resolve && parent.resolveUpdateCache.push(resolve);
2119
- me.resolveUpdateCache = [];
2120
- return true
2121
- }
2122
-
2123
- return me.needsParentUpdate(parent.parentId, resolve, distance+1)
2124
- }
2125
- }
2126
-
2127
- return false
2128
- }
2129
-
2130
1793
  /**
2131
1794
  *
2132
1795
  */
2133
1796
  onConstructed() {
2134
- super.onConstructed();
2135
- this.keys?.register(this)
1797
+ super.onConstructed()
1798
+
1799
+ let me = this;
1800
+
1801
+ me.keys?.register(me);
1802
+ me.getStateProvider()?.createBindings(me)
2136
1803
  }
2137
1804
 
2138
1805
  /**
@@ -2174,65 +1841,6 @@ class Component extends Base {
2174
1841
  * @param {Array} opts.oldPath dom element ids upwards
2175
1842
  */
2176
1843
 
2177
- /**
2178
- * Gets called from the render() promise success handler
2179
- * @param {Object} vnode
2180
- * @param {Boolean} autoMount Mount the DOM after the vnode got created
2181
- * @protected
2182
- */
2183
- onRender(vnode, autoMount) {
2184
- let me = this,
2185
- {app} = me;
2186
-
2187
- me.rendering = false;
2188
-
2189
- // if app is a check to see if the Component got destroyed while rendering => before onRender got triggered
2190
- if (app) {
2191
- if (!app.rendered) {
2192
- app.rendering = false;
2193
- app.rendered = true;
2194
- app.fire('render')
2195
- }
2196
-
2197
- me.vnode = vnode;
2198
-
2199
- let childIds = ComponentManager.getChildIds(vnode),
2200
- i = 0,
2201
- len = childIds.length,
2202
- child;
2203
-
2204
- for (; i < len; i++) {
2205
- child = Neo.getComponent(childIds[i]);
2206
-
2207
- if (child) {
2208
- child.rendered = true
2209
- }
2210
- }
2211
-
2212
- me._rendered = true; // silent update
2213
- me.fire('rendered', me.id);
2214
-
2215
- if (autoMount) {
2216
- me.mounted = true;
2217
-
2218
- if (!app.mounted) {
2219
- app.mounted = true;
2220
- app.fire('mounted')
2221
- }
2222
- }
2223
- }
2224
- }
2225
-
2226
- /**
2227
- * Promise based vdom update
2228
- * @returns {Promise<any>}
2229
- */
2230
- promiseUpdate() {
2231
- return new Promise((resolve, reject) => {
2232
- this.updateVdom(resolve, reject)
2233
- })
2234
- }
2235
-
2236
1844
  /**
2237
1845
  * Remove a cls from the vdomRoot
2238
1846
  * @param {String} value
@@ -2244,32 +1852,7 @@ class Component extends Base {
2244
1852
  this.cls = cls
2245
1853
  }
2246
1854
 
2247
- /**
2248
- * @param {Array|Object} value
2249
- */
2250
- removeDomListeners(value) {
2251
- if (!Array.isArray(value)) {
2252
- value = [value];
2253
- }
2254
-
2255
- let me = this,
2256
- {domListeners} = me,
2257
- i, len;
2258
-
2259
- value.forEach(item => {
2260
- i = 0;
2261
- len = domListeners.length;
2262
1855
 
2263
- for (; i < len; i++) {
2264
- if (Neo.isEqual(item, domListeners[i])) {
2265
- domListeners.splice(i, 1);
2266
- break
2267
- }
2268
- }
2269
- });
2270
-
2271
- me.domListeners = domListeners
2272
- }
2273
1856
 
2274
1857
  /**
2275
1858
  * Either a string like 'color' or an array containing style attributes to remove
@@ -2298,108 +1881,6 @@ class Component extends Base {
2298
1881
  return style
2299
1882
  }
2300
1883
 
2301
- /**
2302
- * Creates the vnode tree for this component and mounts the component in case
2303
- * - you pass true for the mount param
2304
- * - or the autoMount config is set to true
2305
- * @param {Boolean} [mount] Mount the DOM after the vnode got created
2306
- */
2307
- async render(mount) {
2308
- let me = this,
2309
- autoMount = mount || me.autoMount,
2310
- {app} = me,
2311
- {useVdomWorker} = Neo.config;
2312
-
2313
- // Verify that the critical rendering path => CSS files for the new tree is in place
2314
- if (autoMount && currentWorker.countLoadingThemeFiles !== 0) {
2315
- currentWorker.on('themeFilesLoaded', function() {
2316
- !me.mounted && me.render(mount)
2317
- }, me, {once: true});
2318
-
2319
- return
2320
- }
2321
-
2322
- me.rendering = true;
2323
-
2324
- if (!app.rendered) {
2325
- app.rendering = true
2326
- }
2327
-
2328
- if (me.vdom) {
2329
- me.isVdomUpdating = true;
2330
-
2331
- delete me.vdom.removeDom;
2332
-
2333
- me._needsVdomUpdate = false;
2334
- me.afterSetNeedsVdomUpdate?.(false, true);
2335
-
2336
- const data = await Neo.vdom.Helper.create({
2337
- appName : me.appName,
2338
- autoMount,
2339
- parentId : autoMount ? me.getMountedParentId() : undefined,
2340
- parentIndex: autoMount ? me.getMountedParentIndex() : undefined,
2341
- vdom : ComponentManager.getVdomTree(me.vdom),
2342
- windowId : me.windowId
2343
- });
2344
-
2345
- me.onRender(data.vnode, useVdomWorker ? autoMount : false);
2346
- me.isVdomUpdating = false;
2347
-
2348
- autoMount && !useVdomWorker && me.mount();
2349
-
2350
- me.resolveVdomUpdate()
2351
- }
2352
- }
2353
-
2354
- /**
2355
- * Internal helper fn to resolve the Promise for updateVdom()
2356
- * @param {Function|undefined} resolve
2357
- * @protected
2358
- */
2359
- resolveVdomUpdate(resolve) {
2360
- let me = this,
2361
- hasChildUpdateCache = !Neo.isEmpty(me.childUpdateCache),
2362
- component;
2363
-
2364
- me.doResolveUpdateCache();
2365
-
2366
- resolve?.();
2367
-
2368
- if (me.needsVdomUpdate) {
2369
- if (hasChildUpdateCache) {
2370
- Object.entries(me.childUpdateCache).forEach(([key, value]) => {
2371
- component = Neo.getComponent(key);
2372
-
2373
- // The component might already got destroyed
2374
- if (component) {
2375
- // Pass callbacks to the resolver cache => getting executed once the following update is done
2376
- value.resolve && NeoArray.add(me.resolveUpdateCache, value.resolve);
2377
-
2378
- // Adjust the updateDepth to include the depth of all merged child updates
2379
- if (me.updateDepth !== -1) {
2380
- if (component.updateDepth === -1) {
2381
- me.updateDepth = -1
2382
- } else {
2383
- // Since updateDepth is 1-based, we need to subtract 1 level
2384
- me.updateDepth = me.updateDepth + value.distance + component.updateDepth - 1
2385
- }
2386
- }
2387
- }
2388
- });
2389
-
2390
- me.childUpdateCache = {}
2391
- }
2392
-
2393
- me.update()
2394
- } else if (hasChildUpdateCache) {
2395
- Object.keys(me.childUpdateCache).forEach(key => {
2396
- Neo.getComponent(key)?.update()
2397
- });
2398
-
2399
- me.childUpdateCache = {}
2400
- }
2401
- }
2402
-
2403
1884
  /**
2404
1885
  *
2405
1886
  */
@@ -2418,33 +1899,33 @@ class Component extends Base {
2418
1899
  * @returns {Promise<*>}
2419
1900
  */
2420
1901
  set(values={}, silent=false) {
2421
- let me = this,
2422
- needsRendering = values.hidden === false && values.hidden !== me.hidden;
2423
-
2424
- me.silentVdomUpdate = true;
2425
-
2426
- super.set(values);
1902
+ const
1903
+ me = this,
1904
+ wasHidden = me.hidden;
2427
1905
 
2428
- me.silentVdomUpdate = false;
1906
+ me.setSilent(values);
2429
1907
 
2430
- if (silent || !me.needsVdomUpdate) {
2431
- return Promise.resolve()
2432
- } else {
2433
- if (needsRendering) {
1908
+ if (!silent && me.needsVdomUpdate) {
1909
+ if (wasHidden && !me.hidden) {
2434
1910
  me.show();
2435
1911
  return Promise.resolve()
2436
1912
  }
2437
1913
 
2438
1914
  return me.promiseUpdate()
2439
1915
  }
1916
+
1917
+ return Promise.resolve()
2440
1918
  }
2441
1919
 
2442
1920
  /**
2443
- * Convenience shortcut calling set() with the silent flag
1921
+ * A silent version of set(), which does not trigger a vdom update at the end.
1922
+ * Useful for batching multiple config changes.
2444
1923
  * @param {Object} values={}
2445
1924
  */
2446
- setSilent(values = {}) {
2447
- return this.set(values, true)
1925
+ setSilent(values={}) {
1926
+ this.silentVdomUpdate = true;
1927
+ super.set(values);
1928
+ this.silentVdomUpdate = false
2448
1929
  }
2449
1930
 
2450
1931
  /**
@@ -2483,78 +1964,6 @@ class Component extends Base {
2483
1964
  me._hidden = false
2484
1965
  }
2485
1966
 
2486
- /**
2487
- * Placeholder method for util.VDom.syncVdomIds to allow overriding (disabling) it
2488
- * @param {Neo.vdom.VNode} [vnode=this.vnode]
2489
- * @param {Object} [vdom=this.vdom]
2490
- * @param {Boolean} force=false
2491
- */
2492
- syncVdomIds(vnode=this.vnode, vdom=this.vdom, force=false) {
2493
- VDomUtil.syncVdomIds(vnode, vdom, force)
2494
- }
2495
-
2496
- /**
2497
- * In case a component receives a new vnode, we want to do:
2498
- * - sync the vdom ids
2499
- * - setting rendered to true for child components
2500
- * - updating the parent component to ensure that the vnode tree stays persistent
2501
- * @param {Neo.vdom.VNode} [vnode=this.vnode]
2502
- */
2503
- syncVnodeTree(vnode=this.vnode) {
2504
- let me = this,
2505
- childComponents = ComponentManager.getChildren(me),
2506
- debug = false,
2507
- map = {},
2508
- childVnode, start;
2509
-
2510
- if (debug) {
2511
- start = performance.now()
2512
- }
2513
-
2514
- me.syncVdomIds();
2515
-
2516
- if (vnode && me.id !== vnode.id) {
2517
- ComponentManager.registerWrapperNode(vnode.id, me)
2518
- }
2519
-
2520
- // we need one separate iteration first to ensure all wrapper nodes get registered
2521
- childComponents.forEach(component => {
2522
- childVnode = VNodeUtil.find(me.vnode, component.vdom.id)?.vnode;
2523
-
2524
- if (childVnode) {
2525
- map[component.id] = childVnode;
2526
-
2527
- if (component.id !== childVnode.id) {
2528
- ComponentManager.registerWrapperNode(childVnode.id, component)
2529
- }
2530
- }
2531
- });
2532
-
2533
- // delegate the latest node updates to all possible child components found inside the vnode tree
2534
- childComponents.forEach(component => {
2535
- childVnode = map[component.id];
2536
-
2537
- if (childVnode) {
2538
- // silent update
2539
- component._vnode = ComponentManager.addVnodeComponentReferences(childVnode, component.id);
2540
-
2541
- if (!component.rendered) {
2542
- component._rendered = true;
2543
- component.fire('rendered', component.id)
2544
- }
2545
-
2546
- component.mounted = true
2547
- } else {
2548
- console.warn('syncVnodeTree: Could not replace the child vnode for', component.id)
2549
- }
2550
- });
2551
-
2552
- // silent update
2553
- me._vnode = vnode ? ComponentManager.addVnodeComponentReferences(vnode, me.id) : null;
2554
-
2555
- debug && console.log('syncVnodeTree', me.id, performance.now() - start)
2556
- }
2557
-
2558
1967
  /**
2559
1968
  * Toggle a cls inside the vdomRoot of the component
2560
1969
  * @param {String} value
@@ -2590,13 +1999,6 @@ class Component extends Base {
2590
1999
  return ComponentManager.up(this.id, config)
2591
2000
  }
2592
2001
 
2593
- /**
2594
- *
2595
- */
2596
- update() {
2597
- this.afterSetVdom(this.vdom, null)
2598
- }
2599
-
2600
2002
  /**
2601
2003
  *
2602
2004
  */
@@ -2615,54 +2017,6 @@ class Component extends Base {
2615
2017
  me.update()
2616
2018
  }
2617
2019
 
2618
- /**
2619
- * Gets called after the vdom config gets changed in case the component is already mounted (delta updates).
2620
- * @param {function} [resolve] used by promiseUpdate()
2621
- * @param {function} [reject] used by promiseUpdate()
2622
- * @protected
2623
- */
2624
- updateVdom(resolve, reject) {
2625
- let me = this,
2626
- {app, mounted, parentId, vnode} = me;
2627
-
2628
- if (me.isVdomUpdating || me.silentVdomUpdate) {
2629
- resolve && me.resolveUpdateCache.push(resolve);
2630
- me.needsVdomUpdate = true
2631
- } else {
2632
- if (!mounted && me.isConstructed && !me.hasRenderingListener && app?.rendering === true) {
2633
- me.hasRenderingListener = true;
2634
-
2635
- app.on('mounted', () => {
2636
- me.timeout(50).then(() => {
2637
- me.vnode && me.updateVdom(resolve, reject)
2638
- })
2639
- }, me, {once: true})
2640
- } else {
2641
- if (resolve && (!mounted || !vnode)) {
2642
- me.resolveUpdateCache.push(resolve)
2643
- }
2644
-
2645
- if (
2646
- !me.needsParentUpdate(parentId, resolve)
2647
- && !me.isParentUpdating(parentId, resolve)
2648
- && mounted
2649
- && vnode
2650
- ) {
2651
- // Verify that the critical rendering path => CSS files for the new tree is in place
2652
- if (currentWorker.countLoadingThemeFiles !== 0) {
2653
- currentWorker.on('themeFilesLoaded', function() {
2654
- me.updateVdom(resolve, reject)
2655
- }, me, {once: true})
2656
- } else {
2657
- me.#executeVdomUpdate(resolve, reject)
2658
- }
2659
- }
2660
- }
2661
- }
2662
-
2663
- me.hasUnmountedVdomChanges = !mounted && me.hasBeenMounted
2664
- }
2665
-
2666
2020
  /**
2667
2021
  * In case you are sure a DOMRect exists, use getDomRect()
2668
2022
  * Otherwise you can wait for it using this method.