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
@@ -16,6 +16,7 @@ class ServiceBase extends Base {
16
16
  className: 'Neo.worker.ServiceBase',
17
17
  /**
18
18
  * @member {String} cacheName_='neo-runtime'
19
+ * @reactive
19
20
  */
20
21
  cacheName_: 'neo-runtime',
21
22
  /**
@@ -26,6 +27,7 @@ class ServiceBase extends Base {
26
27
  * Remote method access for other workers
27
28
  * @member {Object} remote={app: [//...]}
28
29
  * @protected
30
+ * @reactive
29
31
  */
30
32
  remote: {
31
33
  app: [
@@ -175,6 +177,8 @@ class ServiceBase extends Base {
175
177
  * @param {ExtendableMessageEvent} event
176
178
  */
177
179
  async onActivate(event) {
180
+ await globalThis.clients.claim();
181
+
178
182
  console.log('onActivate', event);
179
183
 
180
184
  let me = this,
@@ -229,7 +233,8 @@ class ServiceBase extends Base {
229
233
  * @param {ExtendableMessageEvent} event
230
234
  */
231
235
  onInstall(event) {
232
- console.log('onInstall', event)
236
+ console.log('onInstall', event);
237
+ globalThis.skipWaiting();
233
238
  }
234
239
 
235
240
  /**
@@ -48,7 +48,8 @@ project.plan(
48
48
  group: 'state',
49
49
  items: [
50
50
  'tests/state/createHierarchicalDataProxy.mjs',
51
- 'tests/state/Provider.mjs'
51
+ 'tests/state/Provider.mjs',
52
+ 'tests/state/ProviderNestedDataConfigs.mjs'
52
53
  ]
53
54
  },
54
55
  'tests/CollectionBase.mjs',
@@ -69,7 +70,9 @@ project.plan(
69
70
  'tests/vdom/table/Container.mjs'
70
71
  ]
71
72
  },
72
- 'tests/vdom/Advanced.mjs']
73
+ 'tests/vdom/Advanced.mjs',
74
+ 'tests/vdom/VdomAsymmetricUpdates.mjs',
75
+ 'tests/vdom/VdomRealWorldUpdates.mjs']
73
76
  }
74
77
  );
75
78
 
@@ -7,6 +7,10 @@ import VDomUtil from '../../../src/util/VDom.mjs';
7
7
 
8
8
  let deltas, output, vdom, vnode;
9
9
 
10
+ // tests are designed for this rendering mode
11
+ Neo.config.useDomApiRenderer = false;
12
+ VdomHelper.onNeoConfigChange({useDomApiRenderer: false})
13
+
10
14
  StartTest(t => {
11
15
  t.it('Week view: Infinite Scrolling', t => {
12
16
  vdom =
@@ -23,7 +27,7 @@ StartTest(t => {
23
27
  {id: 'col-15'}
24
28
  ]};
25
29
 
26
- vnode = VdomHelper.create(vdom);
30
+ let vnode = VdomHelper.create({vdom}).vnode;
27
31
 
28
32
  vdom =
29
33
  {id: 'neo-vnode-1', cn: [
@@ -105,7 +109,7 @@ StartTest(t => {
105
109
  ]}
106
110
  ]};
107
111
 
108
- vnode = VdomHelper.create(vdom);
112
+ let vnode = VdomHelper.create({vdom}).vnode;
109
113
 
110
114
  vdom =
111
115
  {id: 'neo-calendar-week', cn: [
@@ -165,7 +169,7 @@ StartTest(t => {
165
169
  ]}
166
170
  ]};
167
171
 
168
- vnode = VdomHelper.create(vdom);
172
+ let vnode = VdomHelper.create({vdom}).vnode;
169
173
 
170
174
  vdom =
171
175
  {id: 'neo-calendar-week', cn: [
@@ -216,7 +220,7 @@ StartTest(t => {
216
220
  ]}
217
221
  ]};
218
222
 
219
- vnode = VdomHelper.create(vdom);
223
+ let vnode = VdomHelper.create({vdom}).vnode;
220
224
 
221
225
  vdom =
222
226
  {id: 'neo-calendar-week', cn: [
@@ -268,7 +272,7 @@ StartTest(t => {
268
272
  {id: 'neo-column-3'}
269
273
  ]};
270
274
 
271
- vnode = VdomHelper.create(vdom);
275
+ let vnode = VdomHelper.create({vdom}).vnode;
272
276
 
273
277
  vdom =
274
278
  {id: 'neo-calendar-week', cn: [
@@ -333,7 +337,7 @@ StartTest(t => {
333
337
  vdom =
334
338
  {id: 'neo-1'};
335
339
 
336
- vnode = VdomHelper.create(vdom);
340
+ vnode = VdomHelper.create({vdom}).vnode;
337
341
 
338
342
  vdom =
339
343
  {id: 'neo-1', removeDom: true};
@@ -358,7 +362,7 @@ StartTest(t => {
358
362
  ]}
359
363
  ]};
360
364
 
361
- vnode = VdomHelper.create(vdom);
365
+ vnode = VdomHelper.create({vdom}).vnode;
362
366
 
363
367
  vdom =
364
368
  {id: 'neo-calendar-week', cn: [
@@ -403,7 +407,7 @@ StartTest(t => {
403
407
  ]}
404
408
  ]};
405
409
 
406
- vnode = VdomHelper.create(vdom);
410
+ vnode = VdomHelper.create({vdom}).vnode;
407
411
 
408
412
  vdom =
409
413
  {tag: 'ul', id: 'neo-calendar-calendars-list-1', cn: [
@@ -1696,7 +1700,7 @@ StartTest(t => {
1696
1700
  }], tag: 'div'
1697
1701
  }
1698
1702
 
1699
- vnode = VdomHelper.create(vdom);
1703
+ let vnode = VdomHelper.create({vdom}).vnode;
1700
1704
 
1701
1705
  vdom =
1702
1706
  {cls: ['neo-c-m-scrollcontainer', 'neo-scroll-shadows', 'neo-is-scrolling'], id: 'neo-vnode-150', cn: [
@@ -6,8 +6,8 @@ import Config from '../../../../src/core/Config.mjs';
6
6
 
7
7
  StartTest(t => {
8
8
  t.it('EffectManager should manage active effects', t => {
9
- const effect1 = new Effect({fn: () => {}});
10
- const effect2 = new Effect({fn: () => {}});
9
+ const effect1 = new Effect(() => {});
10
+ const effect2 = new Effect(() => {});
11
11
 
12
12
  t.is(EffectManager.getActiveEffect(), null, 'No active effect initially');
13
13
 
@@ -38,13 +38,11 @@ StartTest(t => {
38
38
  t.is(configB, configB, 'configB is strictly equal to itself');
39
39
  t.isNot(configA, configB, 'configA is not strictly equal to configB');
40
40
 
41
- const effect = new Effect({
42
- fn: () => {
43
- runCount++;
44
- // Access configs to register them as dependencies
45
- sum = configA.get() + configB.get();
46
- t.pass(`Effect ran. Sum: ${sum}`);
47
- }
41
+ const effect = new Effect(() => {
42
+ runCount++;
43
+ // Access configs to register them as dependencies
44
+ sum = configA.get() + configB.get();
45
+ t.pass(`Effect ran. Sum: ${sum}`);
48
46
  });
49
47
 
50
48
  t.is(runCount, 1, 'Effect function ran once on creation');
@@ -82,11 +80,9 @@ StartTest(t => {
82
80
  const configY = new Config('Y');
83
81
 
84
82
  // Initial effect: depends on configX
85
- const effect = new Effect({
86
- fn: () => {
87
- runCount++;
88
- t.is(configX.get(), 'X', 'Effect ran (1st): configX value');
89
- }
83
+ const effect = new Effect(() => {
84
+ runCount++;
85
+ t.is(configX.get(), 'X', 'Effect ran (1st): configX value');
90
86
  });
91
87
 
92
88
  t.is(runCount, 1, 'Effect ran once initially');
@@ -19,13 +19,11 @@ StartTest(t => {
19
19
  let effectRunCount = 0;
20
20
  let sum = 0;
21
21
 
22
- const effect = new Effect({
23
- fn: () => {
24
- effectRunCount++;
25
- // Access all props to make them dependencies
26
- sum = instance.configA + instance.configB + instance.configC;
27
- t.pass(`Effect ran. Sum: ${sum}`);
28
- }
22
+ const effect = new Effect(() => {
23
+ effectRunCount++;
24
+ // Access all props to make them dependencies
25
+ sum = instance.configA + instance.configB + instance.configC;
26
+ t.pass(`Effect ran. Sum: ${sum}`);
29
27
  });
30
28
 
31
29
  t.is(effectRunCount, 1, 'Effect ran once on initial creation');
@@ -108,12 +106,10 @@ StartTest(t => {
108
106
  let effectValue = '';
109
107
 
110
108
  // Effect depends only on configB
111
- const effect = new Effect({
112
- fn: () => {
113
- effectRunCount++;
114
- effectValue = instance.configB;
115
- t.pass(`Effect ran. configB: ${effectValue}`);
116
- }
109
+ const effect = new Effect(() => {
110
+ effectRunCount++;
111
+ effectValue = instance.configB;
112
+ t.pass(`Effect ran. configB: ${effectValue}`);
117
113
  });
118
114
 
119
115
  t.is(effectRunCount, 1, 'Effect ran once on initial creation');
@@ -158,12 +154,10 @@ StartTest(t => {
158
154
  let effectValue = '';
159
155
 
160
156
  // Effect depends only on configC
161
- const effect = new Effect({
162
- fn: () => {
163
- effectRunCount++;
164
- effectValue = instance.configC;
165
- t.pass(`Effect ran. configC: ${effectValue}`);
166
- }
157
+ const effect = new Effect(() => {
158
+ effectRunCount++;
159
+ effectValue = instance.configC;
160
+ t.pass(`Effect ran. configC: ${effectValue}`);
167
161
  });
168
162
 
169
163
  t.is(effectRunCount, 1, 'Effect ran once on initial creation');
@@ -216,21 +210,17 @@ StartTest(t => {
216
210
  let effectCValue = '';
217
211
 
218
212
  // Effect for configB (changed by afterSet)
219
- const effectB = new Effect({
220
- fn: () => {
221
- effectBRunCount++;
222
- effectBValue = instance.configB;
223
- t.pass(`EffectB ran. configB: ${effectBValue}`);
224
- }
213
+ const effectB = new Effect(() => {
214
+ effectBRunCount++;
215
+ effectBValue = instance.configB;
216
+ t.pass(`EffectB ran. configB: ${effectBValue}`);
225
217
  });
226
218
 
227
219
  // Effect for configC (changed by beforeSet)
228
- const effectC = new Effect({
229
- fn: () => {
230
- effectCRunCount++;
231
- effectCValue = instance.configC;
232
- t.pass(`EffectC ran. configC: ${effectCValue}`);
233
- }
220
+ const effectC = new Effect(() => {
221
+ effectCRunCount++;
222
+ effectCValue = instance.configC;
223
+ t.pass(`EffectC ran. configC: ${effectCValue}`);
234
224
  });
235
225
 
236
226
  t.is(effectBRunCount, 1, 'EffectB ran once on initial creation');
@@ -292,12 +282,10 @@ StartTest(t => {
292
282
  let effectValue = '';
293
283
 
294
284
  // Single Effect depends on both configB and configC
295
- const effect = new Effect({
296
- fn: () => {
297
- effectRunCount++;
298
- effectValue = `${instance.configB} | ${instance.configC}`;
299
- t.pass(`Effect ran. Combined: ${effectValue}`);
300
- }
285
+ const effect = new Effect(() => {
286
+ effectRunCount++;
287
+ effectValue = `${instance.configB} | ${instance.configC}`;
288
+ t.pass(`Effect ran. Combined: ${effectValue}`);
301
289
  });
302
290
 
303
291
  t.is(effectRunCount, 1, 'Effect ran once on initial creation');
@@ -0,0 +1,255 @@
1
+ import Neo from '../../../../src/Neo.mjs';
2
+ import * as core from '../../../../src/core/_export.mjs';
3
+ import InstanceManager from '../../../../src/manager/Instance.mjs';
4
+ import Component from '../../../../src/component/Base.mjs';
5
+ import StateProvider from '../../../../src/state/Provider.mjs';
6
+
7
+ // IMPORTANT: This test file uses real components and expects them to render.
8
+ // We need to enable unitTestMode for isolation, but also allow VDOM updates.
9
+ Neo.config.unitTestMode = true;
10
+ Neo.config.allowVdomUpdatesInTests = true;
11
+
12
+ class MockComponent extends Component {
13
+ static config = {
14
+ className: 'Mock.Component',
15
+ appName: 'test-app',
16
+ user_: null,
17
+ userName_: null
18
+ }
19
+ }
20
+ Neo.setupClass(MockComponent);
21
+
22
+ // Helper function to convert a proxy to a plain object for deep comparison
23
+ function proxyToObject(proxy) {
24
+ if (proxy === null || typeof proxy !== 'object') {
25
+ return proxy;
26
+ }
27
+ // A simple way to deep-clone and remove proxy
28
+ return JSON.parse(JSON.stringify(proxy));
29
+ }
30
+
31
+ StartTest(t => {
32
+ t.it('State Provider should trigger parent effects when a leaf node changes (bubbling)', t => {
33
+ let effectRunCount = 0;
34
+
35
+ const component = Neo.create(MockComponent, {
36
+ stateProvider: {
37
+ data: {
38
+ user: {
39
+ name: 'John',
40
+ age: 30
41
+ }
42
+ }
43
+ }
44
+ });
45
+
46
+ const provider = component.getStateProvider();
47
+
48
+ // This binding depends on the 'user' object itself.
49
+ provider.createBinding(component.id, 'user', data => {
50
+ effectRunCount++;
51
+ return data.user;
52
+ });
53
+
54
+ t.is(effectRunCount, 1, 'Effect should run once initially');
55
+ t.isDeeply(proxyToObject(component.user), { name: 'John', age: 30 }, 'Initial user object is correct');
56
+
57
+ // Change a leaf property. This should trigger the effect for the parent 'user' object.
58
+ provider.setData('user.age', 31);
59
+
60
+ t.is(effectRunCount, 2, 'Effect should re-run after changing a leaf property (user.age)');
61
+ t.isDeeply(proxyToObject(component.user), { name: 'John', age: 31 }, 'User object is updated correctly in the component');
62
+
63
+ // Change another leaf property
64
+ provider.setData('user.name', 'Jane');
65
+
66
+ t.is(effectRunCount, 3, 'Effect should re-run after changing another leaf property (user.name)');
67
+ t.isDeeply(proxyToObject(component.user), { name: 'Jane', age: 31 }, 'User object is updated again');
68
+
69
+ component.destroy();
70
+ });
71
+
72
+ t.it('Formulas should react to leaf node changes via bubbling', t => {
73
+ let effectRunCount = 0;
74
+
75
+ const component = Neo.create(MockComponent, {
76
+ stateProvider: {
77
+ data: {
78
+ user: {
79
+ firstName: 'John',
80
+ lastName: 'Doe'
81
+ }
82
+ },
83
+ formulas: {
84
+ // This formula depends on the 'user' object.
85
+ fullName: data => {
86
+ effectRunCount++;
87
+ return `${data.user.firstName} ${data.user.lastName}`;
88
+ }
89
+ }
90
+ }
91
+ });
92
+
93
+ const provider = component.getStateProvider();
94
+
95
+ // The formula runs once on initialization.
96
+ t.is(effectRunCount, 1, 'Formula should run once initially');
97
+ t.is(provider.getData('fullName'), 'John Doe', 'Initial formula calculation is correct');
98
+
99
+ // Change a leaf property. This should trigger the formula that depends on the parent 'user' object.
100
+ provider.setData('user.firstName', 'Jane');
101
+
102
+ t.is(effectRunCount, 2, 'Formula should re-run after changing a leaf property');
103
+ t.is(provider.getData('fullName'), 'Jane Doe', 'Formula is correctly re-calculated');
104
+
105
+ component.destroy();
106
+ });
107
+
108
+ t.it('State Provider should handle deeply nested data changes', t => {
109
+ let effectRunCountL1 = 0,
110
+ effectRunCountL2 = 0,
111
+ effectRunCountL3 = 0;
112
+
113
+ const component = Neo.create(MockComponent, {
114
+ stateProvider: {
115
+ data: {
116
+ level1: {
117
+ level2: {
118
+ level3: {
119
+ value: 10
120
+ }
121
+ }
122
+ }
123
+ }
124
+ }
125
+ });
126
+
127
+ const provider = component.getStateProvider();
128
+
129
+ // Bindings to each level of the nested structure
130
+ provider.createBinding(component.id, 'level1', data => {
131
+ effectRunCountL1++;
132
+ return data.level1;
133
+ });
134
+ provider.createBinding(component.id, 'level2', data => {
135
+ effectRunCountL2++;
136
+ return data.level1.level2;
137
+ });
138
+ provider.createBinding(component.id, 'level3', data => {
139
+ effectRunCountL3++;
140
+ return data.level1.level2.level3;
141
+ });
142
+
143
+ t.is(effectRunCountL1, 1, 'L1 Effect ran once initially');
144
+ t.is(effectRunCountL2, 1, 'L2 Effect ran once initially');
145
+ t.is(effectRunCountL3, 1, 'L3 Effect ran once initially');
146
+
147
+ // Change the deepest leaf node
148
+ provider.setData('level1.level2.level3.value', 20);
149
+
150
+ t.is(effectRunCountL1, 2, 'L1 Effect re-ran due to bubbling');
151
+ t.is(effectRunCountL2, 2, 'L2 Effect re-ran due to bubbling');
152
+ t.is(effectRunCountL3, 2, 'L3 Effect re-ran due to bubbling');
153
+
154
+ const finalState = proxyToObject(component.level1);
155
+ t.is(finalState.level2.level3.value, 20, 'Deeply nested value is updated correctly');
156
+
157
+ component.destroy();
158
+ });
159
+
160
+ t.it('Formulas should react to deeply nested data changes', t => {
161
+ let formulaRunCount = 0;
162
+
163
+ const component = Neo.create(MockComponent, {
164
+ stateProvider: {
165
+ data: {
166
+ config: {
167
+ settings: {
168
+ a: 1,
169
+ b: 2
170
+ }
171
+ },
172
+ multiplier: 10
173
+ },
174
+ formulas: {
175
+ // This formula depends on multiple deeply nested properties
176
+ calculated: data => {
177
+ formulaRunCount++;
178
+ return (data.config.settings.a + data.config.settings.b) * data.multiplier;
179
+ }
180
+ }
181
+ }
182
+ });
183
+
184
+ const provider = component.getStateProvider();
185
+
186
+ t.is(formulaRunCount, 1, 'Formula ran once initially');
187
+ t.is(provider.getData('calculated'), 30, 'Initial formula calculation is correct');
188
+
189
+ // Change a deeply nested property
190
+ provider.setData('config.settings.a', 5);
191
+
192
+ t.is(formulaRunCount, 2, 'Formula re-ran after deep leaf change');
193
+ t.is(provider.getData('calculated'), 70, 'Formula re-calculated correctly');
194
+
195
+ // Change another property at a different level
196
+ provider.setData('multiplier', 2);
197
+
198
+ t.is(formulaRunCount, 3, 'Formula re-ran after sibling property change');
199
+ t.is(provider.getData('calculated'), 14, 'Formula re-calculated correctly again');
200
+
201
+ component.destroy();
202
+ });
203
+
204
+ t.it('Hierarchical providers should bubble reactivity from parent to child', t => {
205
+ let childFormulaRunCount = 0;
206
+
207
+ const parentComponent = Neo.create(MockComponent, {
208
+ stateProvider: {
209
+ data: {
210
+ user: {
211
+ name: 'Parent',
212
+ role: 'admin'
213
+ }
214
+ }
215
+ }
216
+ });
217
+
218
+ const childComponent = Neo.create(MockComponent, {
219
+ parentComponent, // Establishes the hierarchy
220
+ stateProvider: {
221
+ data: {
222
+ prefix: 'User:'
223
+ },
224
+ formulas: {
225
+ // This formula depends on the parent's 'user' object and the child's 'prefix'
226
+ display: data => {
227
+ childFormulaRunCount++;
228
+ return `${data.prefix} ${data.user.name} (${data.user.role})`;
229
+ }
230
+ }
231
+ }
232
+ });
233
+
234
+ const parentProvider = parentComponent.getStateProvider();
235
+ const childProvider = childComponent.getStateProvider();
236
+
237
+ t.is(childFormulaRunCount, 1, 'Child formula ran once initially');
238
+ t.is(childProvider.getData('display'), 'User: Parent (admin)', 'Initial hierarchical formula calculation is correct');
239
+
240
+ // Modify a leaf node in the PARENT provider
241
+ parentProvider.setData('user.role', 'editor');
242
+
243
+ t.is(childFormulaRunCount, 2, 'Child formula re-ran after parent data change');
244
+ t.is(childProvider.getData('display'), 'User: Parent (editor)', 'Hierarchical formula re-calculated correctly');
245
+
246
+ // Modify a leaf node in the CHILD provider to ensure it also works
247
+ childProvider.setData('prefix', 'Account:');
248
+
249
+ t.is(childFormulaRunCount, 3, 'Child formula re-ran after child data change');
250
+ t.is(childProvider.getData('display'), 'Account: Parent (editor)', 'Formula updates correctly from own data');
251
+
252
+ parentComponent.destroy();
253
+ childComponent.destroy();
254
+ });
255
+ });