neo.mjs 10.0.0-beta.5 → 10.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (491) hide show
  1. package/.github/RELEASE_NOTES/v10.0.0-beta.1.md +20 -0
  2. package/.github/RELEASE_NOTES/v10.0.0-beta.2.md +73 -0
  3. package/.github/RELEASE_NOTES/v10.0.0-beta.3.md +39 -0
  4. package/.github/RELEASE_NOTES/v10.0.0-beta.5.md +70 -0
  5. package/.github/RELEASE_NOTES/v10.0.0-beta.6.md +48 -0
  6. package/.github/RELEASE_NOTES/v10.0.0.md +52 -0
  7. package/.github/epic-functional-components.md +498 -0
  8. package/.github/ticket-asymmetric-vdom-updates.md +122 -0
  9. package/README.md +0 -3
  10. package/ServiceWorker.mjs +2 -2
  11. package/apps/colors/store/Colors.mjs +1 -0
  12. package/apps/colors/view/GridContainer.mjs +3 -0
  13. package/apps/colors/view/HeaderToolbar.mjs +2 -0
  14. package/apps/colors/view/Viewport.mjs +3 -0
  15. package/apps/covid/view/FooterContainer.mjs +3 -0
  16. package/apps/covid/view/GalleryContainer.mjs +2 -0
  17. package/apps/covid/view/GalleryContainerController.mjs +1 -0
  18. package/apps/covid/view/HeaderContainer.mjs +2 -0
  19. package/apps/covid/view/HelixContainer.mjs +2 -0
  20. package/apps/covid/view/HelixContainerController.mjs +1 -0
  21. package/apps/covid/view/MainContainer.mjs +3 -0
  22. package/apps/covid/view/TableContainer.mjs +3 -0
  23. package/apps/covid/view/TableContainerController.mjs +1 -0
  24. package/apps/covid/view/WorldMapContainer.mjs +2 -0
  25. package/apps/covid/view/country/Gallery.mjs +3 -0
  26. package/apps/covid/view/country/Helix.mjs +8 -0
  27. package/apps/covid/view/country/HistoricalDataTable.mjs +1 -0
  28. package/apps/covid/view/country/Table.mjs +2 -0
  29. package/apps/covid/view/mapboxGl/Component.mjs +1 -0
  30. package/apps/covid/view/mapboxGl/Container.mjs +2 -0
  31. package/apps/email/EPIC_PLAN.md +58 -0
  32. package/apps/email/neo-config.json +2 -2
  33. package/apps/email/store/Emails.mjs +11 -1
  34. package/apps/email/view/ComposeView.mjs +44 -0
  35. package/apps/email/view/MainView.mjs +89 -0
  36. package/apps/email/view/Viewport.mjs +4 -33
  37. package/apps/email/view/ViewportStateProvider.mjs +3 -3
  38. package/apps/form/store/SideNav.mjs +1 -0
  39. package/apps/form/view/FormContainer.mjs +1 -0
  40. package/apps/form/view/FormPageContainer.mjs +2 -0
  41. package/apps/form/view/SideNavList.mjs +1 -0
  42. package/apps/form/view/Viewport.mjs +3 -0
  43. package/apps/portal/childapps/preview/MainContainer.mjs +1 -0
  44. package/apps/portal/index.html +1 -1
  45. package/apps/portal/store/BlogPosts.mjs +2 -0
  46. package/apps/portal/store/Content.mjs +1 -0
  47. package/apps/portal/store/ContentSections.mjs +1 -0
  48. package/apps/portal/store/Examples.mjs +1 -0
  49. package/apps/portal/view/HeaderToolbar.mjs +1 -0
  50. package/apps/portal/view/Viewport.mjs +5 -0
  51. package/apps/portal/view/ViewportController.mjs +11 -3
  52. package/apps/portal/view/about/Container.mjs +2 -0
  53. package/apps/portal/view/about/MemberContainer.mjs +7 -0
  54. package/apps/portal/view/blog/Container.mjs +2 -0
  55. package/apps/portal/view/blog/List.mjs +2 -0
  56. package/apps/portal/view/examples/List.mjs +29 -19
  57. package/apps/portal/view/examples/TabContainer.mjs +4 -0
  58. package/apps/portal/view/home/ContentBox.mjs +3 -0
  59. package/apps/portal/view/home/FeatureSection.mjs +8 -0
  60. package/apps/portal/view/home/FooterContainer.mjs +4 -1
  61. package/apps/portal/view/home/MainContainer.mjs +2 -0
  62. package/apps/portal/view/home/parts/AfterMath.mjs +2 -0
  63. package/apps/portal/view/home/parts/BaseContainer.mjs +1 -0
  64. package/apps/portal/view/home/parts/Colors.mjs +4 -0
  65. package/apps/portal/view/home/parts/Features.mjs +2 -0
  66. package/apps/portal/view/home/parts/Helix.mjs +5 -0
  67. package/apps/portal/view/home/parts/How.mjs +4 -0
  68. package/apps/portal/view/home/parts/MainNeo.mjs +1 -0
  69. package/apps/portal/view/home/parts/References.mjs +2 -0
  70. package/apps/portal/view/learn/ContentComponent.mjs +11 -5
  71. package/apps/portal/view/learn/ContentTreeList.mjs +2 -0
  72. package/apps/portal/view/learn/CubeLayoutButton.mjs +1 -0
  73. package/apps/portal/view/learn/MainContainer.mjs +4 -0
  74. package/apps/portal/view/learn/PageContainer.mjs +2 -0
  75. package/apps/portal/view/learn/PageSectionsContainer.mjs +3 -0
  76. package/apps/portal/view/learn/PageSectionsList.mjs +1 -0
  77. package/apps/portal/view/services/Component.mjs +1 -0
  78. package/apps/realworld/api/Base.mjs +1 -0
  79. package/apps/realworld/view/HeaderComponent.mjs +4 -0
  80. package/apps/realworld/view/HomeComponent.mjs +7 -0
  81. package/apps/realworld/view/MainContainer.mjs +2 -0
  82. package/apps/realworld/view/MainContainerController.mjs +2 -0
  83. package/apps/realworld/view/article/CommentComponent.mjs +3 -0
  84. package/apps/realworld/view/article/Component.mjs +17 -10
  85. package/apps/realworld/view/article/CreateCommentComponent.mjs +2 -0
  86. package/apps/realworld/view/article/CreateComponent.mjs +5 -0
  87. package/apps/realworld/view/article/PreviewComponent.mjs +9 -0
  88. package/apps/realworld/view/article/TagListComponent.mjs +2 -0
  89. package/apps/realworld/view/user/ProfileComponent.mjs +7 -0
  90. package/apps/realworld/view/user/SettingsComponent.mjs +5 -0
  91. package/apps/realworld/view/user/SignUpComponent.mjs +3 -0
  92. package/apps/realworld2/api/Base.mjs +1 -0
  93. package/apps/realworld2/view/FooterComponent.mjs +1 -0
  94. package/apps/realworld2/view/HeaderToolbar.mjs +3 -0
  95. package/apps/realworld2/view/HomeContainer.mjs +1 -0
  96. package/apps/realworld2/view/MainContainer.mjs +2 -0
  97. package/apps/realworld2/view/MainContainerController.mjs +1 -0
  98. package/apps/realworld2/view/article/Helix.mjs +1 -0
  99. package/apps/realworld2/view/article/PreviewComponent.mjs +9 -0
  100. package/apps/realworld2/view/article/PreviewList.mjs +1 -0
  101. package/apps/realworld2/view/article/TagListComponent.mjs +2 -0
  102. package/apps/route/view/CenterContainer.mjs +1 -0
  103. package/apps/route/view/MainView.mjs +1 -0
  104. package/apps/sharedcovid/childapps/sharedcovidchart/MainContainer.mjs +1 -0
  105. package/apps/sharedcovid/childapps/sharedcovidgallery/MainContainer.mjs +1 -0
  106. package/apps/sharedcovid/childapps/sharedcovidhelix/MainContainer.mjs +1 -0
  107. package/apps/sharedcovid/childapps/sharedcovidmap/MainContainer.mjs +1 -0
  108. package/apps/sharedcovid/view/FooterContainer.mjs +3 -0
  109. package/apps/sharedcovid/view/GalleryContainer.mjs +2 -0
  110. package/apps/sharedcovid/view/GalleryContainerController.mjs +1 -0
  111. package/apps/sharedcovid/view/HeaderContainer.mjs +2 -0
  112. package/apps/sharedcovid/view/HelixContainer.mjs +2 -0
  113. package/apps/sharedcovid/view/HelixContainerController.mjs +1 -0
  114. package/apps/sharedcovid/view/MainContainer.mjs +3 -0
  115. package/apps/sharedcovid/view/TableContainer.mjs +3 -0
  116. package/apps/sharedcovid/view/TableContainerController.mjs +1 -0
  117. package/apps/sharedcovid/view/WorldMapContainer.mjs +2 -0
  118. package/apps/sharedcovid/view/country/Gallery.mjs +3 -0
  119. package/apps/sharedcovid/view/country/Helix.mjs +8 -0
  120. package/apps/sharedcovid/view/country/HistoricalDataTable.mjs +1 -0
  121. package/apps/sharedcovid/view/country/Table.mjs +2 -0
  122. package/apps/sharedcovid/view/mapboxGl/Component.mjs +1 -0
  123. package/apps/sharedcovid/view/mapboxGl/Container.mjs +2 -0
  124. package/apps/shareddialog/childapps/shareddialog2/view/MainContainer.mjs +2 -0
  125. package/apps/shareddialog/view/DemoDialog.mjs +2 -0
  126. package/apps/shareddialog/view/MainContainer.mjs +2 -0
  127. package/apps/shareddialog/view/MainContainerController.mjs +1 -0
  128. package/buildScripts/addReactiveTags.mjs +191 -0
  129. package/buildScripts/checkReactiveTags.mjs +160 -0
  130. package/docs/app/store/Api.mjs +1 -0
  131. package/docs/app/store/Examples.mjs +1 -0
  132. package/docs/app/view/ApiTreeList.mjs +1 -0
  133. package/docs/app/view/ContentTabContainer.mjs +2 -0
  134. package/docs/app/view/ExamplesTreeList.mjs +2 -0
  135. package/docs/app/view/HeaderContainer.mjs +3 -0
  136. package/docs/app/view/MainContainer.mjs +5 -0
  137. package/docs/app/view/classdetails/HeaderComponent.mjs +1 -0
  138. package/docs/app/view/classdetails/MainContainer.mjs +3 -0
  139. package/docs/app/view/classdetails/MembersList.mjs +5 -0
  140. package/docs/app/view/classdetails/SourceViewComponent.mjs +2 -0
  141. package/examples/ConfigurationViewport.mjs +14 -8
  142. package/examples/calendar/weekview/MainContainer.mjs +4 -0
  143. package/examples/component/coronaGallery/CountryGallery.mjs +2 -0
  144. package/examples/component/coronaGallery/CountryStore.mjs +1 -0
  145. package/examples/component/coronaGallery/Viewport.mjs +3 -0
  146. package/examples/component/coronaGallery/ViewportController.mjs +1 -0
  147. package/examples/component/coronaHelix/CountryHelix.mjs +7 -0
  148. package/examples/component/coronaHelix/MainContainer.mjs +1 -0
  149. package/examples/component/gallery/ImageStore.mjs +1 -0
  150. package/examples/component/helix/ImageStore.mjs +1 -0
  151. package/examples/component/helix/Viewport.mjs +3 -0
  152. package/examples/component/helix/ViewportController.mjs +1 -0
  153. package/examples/component/multiWindowCoronaGallery/childapp/Viewport.mjs +1 -0
  154. package/examples/component/multiWindowHelix/childapp/Viewport.mjs +1 -0
  155. package/examples/component/wrapper/googleMaps/MapComponent.mjs +2 -0
  156. package/examples/core/config/MainContainer.mjs +2 -0
  157. package/examples/dialog/DemoDialog.mjs +2 -0
  158. package/examples/dialog/MainContainer.mjs +1 -0
  159. package/examples/form/field/color/MainStore.mjs +1 -0
  160. package/examples/functional/button/base/MainContainer.mjs +207 -0
  161. package/examples/functional/button/base/app.mjs +6 -0
  162. package/examples/functional/button/base/index.html +11 -0
  163. package/examples/functional/button/base/neo-config.json +6 -0
  164. package/examples/functional/defineComponent/Component.mjs +18 -0
  165. package/examples/functional/defineComponent/MainContainer.mjs +41 -0
  166. package/examples/functional/defineComponent/app.mjs +6 -0
  167. package/examples/functional/defineComponent/index.html +11 -0
  168. package/examples/functional/defineComponent/neo-config.json +6 -0
  169. package/examples/functional/hostComponent/Component.mjs +32 -0
  170. package/examples/functional/hostComponent/MainContainer.mjs +48 -0
  171. package/examples/functional/hostComponent/app.mjs +6 -0
  172. package/examples/functional/hostComponent/index.html +11 -0
  173. package/examples/functional/hostComponent/neo-config.json +6 -0
  174. package/examples/grid/animatedRowSorting/Viewport.mjs +1 -1
  175. package/examples/grid/bigData/ControlsContainer.mjs +3 -0
  176. package/examples/grid/bigData/GridContainer.mjs +4 -2
  177. package/examples/grid/bigData/MainContainer.mjs +2 -0
  178. package/examples/grid/bigData/MainModel.mjs +1 -0
  179. package/examples/grid/bigData/MainStore.mjs +3 -0
  180. package/examples/grid/cellEditing/MainContainer.mjs +1 -1
  181. package/examples/grid/container/MainContainer.mjs +1 -1
  182. package/examples/grid/covid/GridContainer.mjs +3 -0
  183. package/examples/grid/covid/MainContainer.mjs +2 -0
  184. package/examples/grid/covid/Store.mjs +1 -0
  185. package/examples/grid/nestedRecordFields/EditUserDialog.mjs +3 -0
  186. package/examples/grid/nestedRecordFields/Viewport.mjs +3 -1
  187. package/examples/list/animate/List.mjs +4 -0
  188. package/examples/list/animate/MainContainer.mjs +2 -0
  189. package/examples/list/circle/MainStore.mjs +1 -0
  190. package/examples/list/color/MainStore.mjs +1 -0
  191. package/examples/preloadingAssets/view/MainContainer.mjs +2 -0
  192. package/examples/stateProvider/advanced/MainContainer.mjs +1 -0
  193. package/examples/stateProvider/dialog/EditUserDialog.mjs +2 -0
  194. package/examples/stateProvider/dialog/MainContainer.mjs +1 -0
  195. package/examples/stateProvider/extendedClass/MainContainer.mjs +2 -0
  196. package/examples/stateProvider/inline/MainContainer.mjs +1 -0
  197. package/examples/stateProvider/inlineNoStateProvider/MainContainer.mjs +1 -0
  198. package/examples/stateProvider/inlineNoStateProvider/MainContainerController.mjs +2 -0
  199. package/examples/stateProvider/multiWindow/EditUserDialog.mjs +3 -0
  200. package/examples/stateProvider/multiWindow/MainContainer.mjs +1 -0
  201. package/examples/stateProvider/multiWindow/Viewport.mjs +1 -0
  202. package/examples/stateProvider/nestedData/MainContainer.mjs +1 -0
  203. package/examples/stateProvider/table/MainContainer.mjs +1 -0
  204. package/examples/table/covid/MainContainer.mjs +2 -0
  205. package/examples/table/covid/Store.mjs +1 -0
  206. package/examples/table/covid/TableContainer.mjs +3 -0
  207. package/examples/table/nestedRecordFields/EditUserDialog.mjs +3 -0
  208. package/examples/table/nestedRecordFields/Viewport.mjs +1 -0
  209. package/examples/todoList/version1/MainComponent.mjs +1 -1
  210. package/examples/toolbar/breadcrumb/view/MainContainer.mjs +2 -0
  211. package/examples/toolbar/paging/store/Users.mjs +1 -0
  212. package/examples/toolbar/paging/view/AddUserDialog.mjs +3 -0
  213. package/examples/toolbar/paging/view/MainContainer.mjs +3 -0
  214. package/examples/treeAccordion/MainContainer.mjs +2 -2
  215. package/examples/worker/task/MainContainer.mjs +1 -0
  216. package/learn/Glossary.md +1 -0
  217. package/learn/UsingTheseTopics.md +1 -0
  218. package/learn/benefits/ConfigSystem.md +2 -0
  219. package/learn/benefits/Effort.md +1 -0
  220. package/learn/benefits/Features.md +1 -0
  221. package/learn/benefits/FormsEngine.md +1 -0
  222. package/learn/benefits/FourEnvironments.md +2 -0
  223. package/learn/benefits/Introduction.md +2 -0
  224. package/learn/benefits/MultiWindow.md +3 -1
  225. package/learn/benefits/OffTheMainThread.md +2 -0
  226. package/learn/benefits/Quick.md +2 -0
  227. package/learn/benefits/RPCLayer.md +2 -0
  228. package/learn/benefits/Speed.md +2 -0
  229. package/learn/blog/v10-deep-dive-functional-components.md +293 -0
  230. package/learn/blog/v10-deep-dive-reactivity.md +522 -0
  231. package/learn/blog/v10-deep-dive-state-provider.md +432 -0
  232. package/learn/blog/v10-deep-dive-vdom-revolution.md +194 -0
  233. package/learn/blog/v10-post1-love-story.md +383 -0
  234. package/learn/comparisons/NeoVsAngular.md +90 -0
  235. package/learn/comparisons/NeoVsExtJs.md +178 -0
  236. package/learn/comparisons/NeoVsNextJs.md +124 -0
  237. package/learn/comparisons/NeoVsReact.md +95 -0
  238. package/learn/comparisons/NeoVsSolid.md +78 -0
  239. package/learn/comparisons/NeoVsVue.md +92 -0
  240. package/learn/comparisons/Overview.md +46 -0
  241. package/learn/gettingstarted/ComponentModels.md +2 -0
  242. package/learn/gettingstarted/Config.md +2 -0
  243. package/learn/gettingstarted/DescribingTheUI.md +2 -0
  244. package/learn/gettingstarted/Events.md +2 -0
  245. package/learn/gettingstarted/Extending.md +2 -0
  246. package/learn/gettingstarted/References.md +2 -0
  247. package/learn/gettingstarted/Setup.md +3 -2
  248. package/learn/gettingstarted/Workspaces.md +2 -0
  249. package/learn/guides/datahandling/Collections.md +1 -0
  250. package/learn/guides/datahandling/Records.md +1 -0
  251. package/learn/guides/datahandling/StateProviders.md +130 -16
  252. package/learn/guides/datahandling/Tables.md +1 -1
  253. package/learn/guides/fundamentals/ConfigSystemDeepDive.md +1 -0
  254. package/learn/guides/fundamentals/DeclarativeComponentTreesVsImperativeVdom.md +2 -0
  255. package/learn/guides/fundamentals/DeclarativeVDOMWithEffects.md +10 -8
  256. package/learn/guides/fundamentals/ExtendingNeoClasses.md +1 -0
  257. package/learn/guides/fundamentals/InstanceLifecycle.md +3 -1
  258. package/learn/guides/fundamentals/MainThreadAddons.md +2 -0
  259. package/learn/guides/specificfeatures/Mixins.md +3 -1
  260. package/learn/guides/specificfeatures/MultiWindow.md +3 -1
  261. package/learn/guides/specificfeatures/PortalApp.md +2 -0
  262. package/learn/guides/uibuildingblocks/ComponentsAndContainers.md +2 -0
  263. package/learn/guides/uibuildingblocks/CustomComponents.md +2 -0
  264. package/learn/guides/uibuildingblocks/Layouts.md +2 -0
  265. package/learn/guides/uibuildingblocks/WorkingWithVDom.md +28 -2
  266. package/learn/guides/userinteraction/Forms.md +2 -0
  267. package/learn/guides/userinteraction/events/CustomEvents.md +2 -1
  268. package/learn/guides/userinteraction/events/DomEvents.md +2 -0
  269. package/learn/javascript/ClassFeatures.md +4 -3
  270. package/learn/javascript/Classes.md +10 -13
  271. package/learn/javascript/Overrides.md +10 -6
  272. package/learn/javascript/Super.md +12 -8
  273. package/learn/tree.json +71 -64
  274. package/learn/tutorials/Earthquakes.md +2 -0
  275. package/learn/tutorials/RSP.md +3 -1
  276. package/learn/tutorials/TodoList.md +103 -7
  277. package/package.json +8 -6
  278. package/resources/scss/src/apps/email/ComposeView.scss +16 -0
  279. package/resources/scss/src/apps/email/MainView.scss +5 -0
  280. package/resources/scss/src/apps/portal/learn/ContentComponent.scss +5 -4
  281. package/src/DefaultConfig.mjs +12 -2
  282. package/src/Main.mjs +1 -0
  283. package/src/Neo.mjs +219 -166
  284. package/src/Xhr.mjs +1 -0
  285. package/src/button/Base.mjs +13 -0
  286. package/src/button/Effect.mjs +16 -2
  287. package/src/button/Split.mjs +2 -0
  288. package/src/calendar/store/Calendars.mjs +1 -0
  289. package/src/calendar/store/Colors.mjs +1 -0
  290. package/src/calendar/store/Events.mjs +1 -0
  291. package/src/calendar/view/DayComponent.mjs +2 -0
  292. package/src/calendar/view/EditEventContainer.mjs +4 -1
  293. package/src/calendar/view/MainContainer.mjs +13 -0
  294. package/src/calendar/view/MainContainerStateProvider.mjs +14 -28
  295. package/src/calendar/view/SettingsContainer.mjs +1 -0
  296. package/src/calendar/view/YearComponent.mjs +16 -0
  297. package/src/calendar/view/calendars/ColorsList.mjs +2 -0
  298. package/src/calendar/view/calendars/Container.mjs +2 -0
  299. package/src/calendar/view/calendars/EditContainer.mjs +1 -0
  300. package/src/calendar/view/month/Component.mjs +11 -0
  301. package/src/calendar/view/settings/GeneralContainer.mjs +1 -0
  302. package/src/calendar/view/settings/MonthContainer.mjs +1 -0
  303. package/src/calendar/view/settings/WeekContainer.mjs +1 -0
  304. package/src/calendar/view/settings/YearContainer.mjs +1 -0
  305. package/src/calendar/view/week/Component.mjs +15 -1
  306. package/src/calendar/view/week/TimeAxisComponent.mjs +4 -0
  307. package/src/code/LivePreview.mjs +51 -23
  308. package/src/collection/Base.mjs +7 -10
  309. package/src/collection/Filter.mjs +6 -0
  310. package/src/collection/Sorter.mjs +3 -0
  311. package/src/component/Abstract.mjs +412 -0
  312. package/src/component/Base.mjs +48 -1077
  313. package/src/component/Canvas.mjs +1 -0
  314. package/src/component/Chip.mjs +4 -0
  315. package/src/component/Circle.mjs +14 -0
  316. package/src/component/Clock.mjs +4 -0
  317. package/src/component/DateSelector.mjs +12 -0
  318. package/src/component/Gallery.mjs +11 -0
  319. package/src/component/Helix.mjs +24 -0
  320. package/src/component/Label.mjs +1 -0
  321. package/src/component/Legend.mjs +3 -0
  322. package/src/component/MagicMoveText.mjs +4 -0
  323. package/src/component/Progress.mjs +3 -0
  324. package/src/component/Splitter.mjs +3 -0
  325. package/src/component/StatusBadge.mjs +6 -0
  326. package/src/component/Timer.mjs +4 -0
  327. package/src/component/Toast.mjs +6 -0
  328. package/src/component/Video.mjs +1 -0
  329. package/src/component/mwc/Button.mjs +7 -0
  330. package/src/component/mwc/TextField.mjs +9 -0
  331. package/src/component/wrapper/AmChart.mjs +2 -0
  332. package/src/component/wrapper/GoogleMaps.mjs +3 -0
  333. package/src/component/wrapper/MapboxGL.mjs +5 -0
  334. package/src/component/wrapper/MonacoEditor.mjs +12 -0
  335. package/src/container/Accordion.mjs +2 -0
  336. package/src/container/Base.mjs +7 -3
  337. package/src/container/Panel.mjs +1 -0
  338. package/src/container/Viewport.mjs +1 -0
  339. package/src/controller/Application.mjs +1 -0
  340. package/src/controller/Base.mjs +1 -0
  341. package/src/controller/Component.mjs +1 -0
  342. package/src/core/Base.mjs +86 -33
  343. package/src/core/Compare.mjs +4 -7
  344. package/src/core/Config.mjs +65 -52
  345. package/src/core/Effect.mjs +86 -24
  346. package/src/core/EffectManager.mjs +117 -8
  347. package/src/core/IdGenerator.mjs +13 -44
  348. package/src/core/Observable.mjs +69 -65
  349. package/src/data/Model.mjs +2 -0
  350. package/src/data/Store.mjs +7 -0
  351. package/src/data/connection/WebSocket.mjs +2 -0
  352. package/src/date/DayViewComponent.mjs +2 -0
  353. package/src/date/SelectorContainer.mjs +14 -0
  354. package/src/dialog/Base.mjs +8 -0
  355. package/src/draggable/DragZone.mjs +5 -0
  356. package/src/draggable/tree/DragZone.mjs +1 -0
  357. package/src/filter/BooleanContainer.mjs +2 -0
  358. package/src/filter/NumberContainer.mjs +3 -0
  359. package/src/filter/ToggleOperatorsButton.mjs +2 -0
  360. package/src/form/Fieldset.mjs +6 -0
  361. package/src/form/field/Base.mjs +7 -0
  362. package/src/form/field/CheckBox.mjs +18 -0
  363. package/src/form/field/Chip.mjs +1 -0
  364. package/src/form/field/ComboBox.mjs +8 -0
  365. package/src/form/field/Country.mjs +1 -0
  366. package/src/form/field/Currency.mjs +2 -0
  367. package/src/form/field/Date.mjs +4 -0
  368. package/src/form/field/Display.mjs +1 -0
  369. package/src/form/field/Email.mjs +1 -0
  370. package/src/form/field/FileUpload.mjs +7 -0
  371. package/src/form/field/Hidden.mjs +1 -0
  372. package/src/form/field/Number.mjs +7 -0
  373. package/src/form/field/Password.mjs +1 -0
  374. package/src/form/field/Phone.mjs +3 -0
  375. package/src/form/field/Picker.mjs +2 -0
  376. package/src/form/field/Radio.mjs +1 -0
  377. package/src/form/field/Range.mjs +3 -0
  378. package/src/form/field/Search.mjs +2 -0
  379. package/src/form/field/Text.mjs +43 -5
  380. package/src/form/field/TextArea.mjs +7 -0
  381. package/src/form/field/Time.mjs +6 -0
  382. package/src/form/field/Url.mjs +3 -0
  383. package/src/form/field/ZipCode.mjs +2 -0
  384. package/src/form/field/trigger/Base.mjs +3 -0
  385. package/src/form/field/trigger/Clear.mjs +2 -0
  386. package/src/form/field/trigger/CopyToClipboard.mjs +2 -0
  387. package/src/form/field/trigger/Date.mjs +1 -0
  388. package/src/form/field/trigger/Picker.mjs +1 -0
  389. package/src/form/field/trigger/Search.mjs +1 -0
  390. package/src/form/field/trigger/SpinDown.mjs +2 -0
  391. package/src/form/field/trigger/SpinUp.mjs +1 -0
  392. package/src/form/field/trigger/Time.mjs +2 -0
  393. package/src/functional/_export.mjs +6 -0
  394. package/src/functional/button/Base.mjs +384 -0
  395. package/src/functional/component/Base.mjs +405 -0
  396. package/src/functional/defineComponent.mjs +102 -0
  397. package/src/functional/useConfig.mjs +52 -0
  398. package/src/functional/useEvent.mjs +43 -0
  399. package/src/grid/Body.mjs +20 -1
  400. package/src/grid/Container.mjs +50 -60
  401. package/src/grid/ScrollManager.mjs +2 -0
  402. package/src/grid/VerticalScrollbar.mjs +2 -0
  403. package/src/grid/column/Base.mjs +2 -0
  404. package/src/grid/header/Button.mjs +7 -0
  405. package/src/grid/header/Toolbar.mjs +6 -0
  406. package/src/grid/plugin/AnimateRows.mjs +2 -0
  407. package/src/layout/Base.mjs +3 -0
  408. package/src/layout/Card.mjs +1 -0
  409. package/src/layout/Cube.mjs +18 -4
  410. package/src/layout/Fit.mjs +1 -0
  411. package/src/layout/Flexbox.mjs +7 -0
  412. package/src/layout/Form.mjs +2 -0
  413. package/src/layout/Grid.mjs +1 -0
  414. package/src/layout/HBox.mjs +1 -0
  415. package/src/layout/VBox.mjs +1 -0
  416. package/src/list/Base.mjs +13 -0
  417. package/src/list/Chip.mjs +1 -0
  418. package/src/list/Circle.mjs +2 -0
  419. package/src/list/Color.mjs +1 -0
  420. package/src/list/plugin/Animate.mjs +2 -0
  421. package/src/main/DeltaUpdates.mjs +1 -0
  422. package/src/main/DomEvents.mjs +2 -0
  423. package/src/main/addon/CloneNode.mjs +1 -0
  424. package/src/main/addon/Cookie.mjs +1 -0
  425. package/src/main/addon/GoogleMaps.mjs +1 -0
  426. package/src/main/addon/LocalStorage.mjs +1 -0
  427. package/src/main/addon/MapboxGL.mjs +1 -0
  428. package/src/main/addon/Markdown.mjs +1 -0
  429. package/src/main/addon/Navigator.mjs +1 -0
  430. package/src/main/addon/Popover.mjs +1 -0
  431. package/src/main/addon/Stylesheet.mjs +1 -0
  432. package/src/main/addon/WindowPosition.mjs +1 -0
  433. package/src/manager/Component.mjs +0 -71
  434. package/src/manager/VDomUpdate.mjs +320 -0
  435. package/src/menu/List.mjs +6 -0
  436. package/src/menu/Model.mjs +1 -0
  437. package/src/menu/Panel.mjs +3 -0
  438. package/src/menu/Store.mjs +1 -0
  439. package/src/mixin/DomEvents.mjs +130 -0
  440. package/src/mixin/VdomLifecycle.mjs +670 -0
  441. package/src/plugin/Base.mjs +1 -0
  442. package/src/plugin/Resizable.mjs +2 -0
  443. package/src/selection/Model.mjs +15 -18
  444. package/src/selection/grid/BaseModel.mjs +1 -0
  445. package/src/sitemap/Component.mjs +1 -0
  446. package/src/state/Provider.mjs +129 -87
  447. package/src/state/createHierarchicalDataProxy.mjs +39 -25
  448. package/src/tab/Container.mjs +6 -0
  449. package/src/tab/Strip.mjs +1 -0
  450. package/src/tab/header/Button.mjs +2 -0
  451. package/src/tab/header/EffectButton.mjs +2 -0
  452. package/src/tab/header/Toolbar.mjs +1 -0
  453. package/src/table/Body.mjs +3 -0
  454. package/src/table/Container.mjs +10 -0
  455. package/src/table/header/Button.mjs +8 -0
  456. package/src/table/header/Toolbar.mjs +5 -0
  457. package/src/table/plugin/CellEditing.mjs +1 -0
  458. package/src/toolbar/Base.mjs +4 -0
  459. package/src/toolbar/Breadcrumb.mjs +3 -0
  460. package/src/toolbar/Paging.mjs +5 -0
  461. package/src/tooltip/Base.mjs +2 -0
  462. package/src/tree/List.mjs +3 -0
  463. package/src/util/HashHistory.mjs +1 -0
  464. package/src/util/KeyNavigation.mjs +2 -0
  465. package/src/util/Matrix.mjs +1 -0
  466. package/src/util/VDom.mjs +18 -5
  467. package/src/util/VNode.mjs +7 -1
  468. package/src/util/vdom/TreeBuilder.mjs +105 -0
  469. package/src/vdom/Helper.mjs +35 -23
  470. package/src/vdom/VNode.mjs +4 -6
  471. package/src/worker/App.mjs +1 -0
  472. package/src/worker/Base.mjs +2 -0
  473. package/src/worker/Manager.mjs +2 -0
  474. package/src/worker/ServiceBase.mjs +6 -1
  475. package/src/worker/mixin/RemoteMethodAccess.mjs +1 -6
  476. package/test/siesta/siesta.js +17 -2
  477. package/test/siesta/tests/VdomCalendar.mjs +19 -15
  478. package/test/siesta/tests/VdomHelper.mjs +7 -7
  479. package/test/siesta/tests/classic/Button.mjs +113 -0
  480. package/test/siesta/tests/core/Effect.mjs +10 -14
  481. package/test/siesta/tests/core/EffectBatching.mjs +72 -79
  482. package/test/siesta/tests/functional/Button.mjs +113 -0
  483. package/test/siesta/tests/state/ProviderNestedDataConfigs.mjs +314 -0
  484. package/test/siesta/tests/state/createHierarchicalDataProxy.mjs +42 -55
  485. package/test/siesta/tests/vdom/Advanced.mjs +14 -8
  486. package/test/siesta/tests/vdom/VdomAsymmetricUpdates.mjs +366 -0
  487. package/test/siesta/tests/vdom/VdomRealWorldUpdates.mjs +249 -0
  488. package/test/siesta/tests/vdom/layout/Cube.mjs +11 -7
  489. package/test/siesta/tests/vdom/table/Container.mjs +9 -5
  490. package/learn/javascript/NewNode.md +0 -31
  491. package/src/core/EffectBatchManager.mjs +0 -68
@@ -1,10 +1,12 @@
1
- import Base from '../core/Base.mjs';
2
- import NeoArray from '../util/Array.mjs';
3
- import Observable from '../core/Observable.mjs';
1
+ import Base from '../core/Base.mjs';
2
+ import NeoArray from '../util/Array.mjs';
3
+ import Observable from '../core/Observable.mjs';
4
+ import {isDescriptor} from '../core/ConfigSymbols.mjs';
4
5
 
5
6
  /**
6
7
  * @class Neo.selection.Model
7
8
  * @extends Neo.core.Base
9
+ * @mixes Neo.core.Observable
8
10
  */
9
11
  class Model extends Base {
10
12
  /**
@@ -32,10 +34,17 @@ class Model extends Base {
32
34
  */
33
35
  cls: null,
34
36
  /**
35
- * @member {Array} items_=null
37
+ * @member {Array} items_
36
38
  * @protected
39
+ * @reactive
37
40
  */
38
- items_: null,
41
+ items_: {
42
+ [isDescriptor]: true,
43
+ clone : 'shallow',
44
+ cloneOnGet : 'none',
45
+ isEqual : () => false,
46
+ value : []
47
+ },
39
48
  /**
40
49
  * @member {String} selectedCls='selected'
41
50
  */
@@ -48,23 +57,11 @@ class Model extends Base {
48
57
  * Internally saves the view id, but the getter will return the matching instance
49
58
  * @member {Object} view_=null
50
59
  * @protected
60
+ * @reactive
51
61
  */
52
62
  view_: null
53
63
  }
54
64
 
55
- /**
56
- * Gets triggered before getting the value of the items config
57
- * @param {Array|null} value
58
- * @returns {Array}
59
- */
60
- beforeGetItems(value) {
61
- if (!value) {
62
- this._items = value = []
63
- }
64
-
65
- return value
66
- }
67
-
68
65
  /**
69
66
  * Gets triggered before getting the value of the view config
70
67
  * @param {String} value
@@ -53,6 +53,7 @@ class BaseModel extends Model {
53
53
  }
54
54
 
55
55
  me.fire('selectionChange', {
56
+ records : me.selectedRows.map(id => view.store.get(id)),
56
57
  selection: me.selectedRows
57
58
  })
58
59
  } else if (!silent) {
@@ -34,6 +34,7 @@ class Component extends Base {
34
34
  * Valid values: removeDom, visibility
35
35
  * Defines if the component items should use css visibility:'hidden' or vdom:removeDom
36
36
  * @member {String} hideMode_='removeDom'
37
+ * @reactive
37
38
  */
38
39
  itemHideMode_: 'removeDom',
39
40
  /*
@@ -2,6 +2,7 @@ import Base from '../core/Base.mjs';
2
2
  import ClassSystemUtil from '../util/ClassSystem.mjs';
3
3
  import Config from '../core/Config.mjs';
4
4
  import Effect from '../core/Effect.mjs';
5
+ import EffectManager from '../core/EffectManager.mjs';
5
6
  import Observable from '../core/Observable.mjs';
6
7
  import {createHierarchicalDataProxy} from './createHierarchicalDataProxy.mjs';
7
8
  import {isDescriptor} from '../core/ConfigSymbols.mjs';
@@ -12,6 +13,7 @@ const twoWayBindingSymbol = Symbol.for('twoWayBinding');
12
13
  * An optional component state provider for adding bindings to configs
13
14
  * @class Neo.state.Provider
14
15
  * @extends Neo.core.Base
16
+ * @mixes Neo.core.Observable
15
17
  */
16
18
  class Provider extends Base {
17
19
  /**
@@ -55,6 +57,7 @@ class Provider extends Base {
55
57
  * theme: 'dark'
56
58
  * }
57
59
  * }
60
+ * @reactive
58
61
  */
59
62
  data_: {
60
63
  [isDescriptor]: true,
@@ -79,10 +82,12 @@ class Provider extends Base {
79
82
  * // Accessing parent data (assuming a parent provider has a 'taxRate' property)
80
83
  * totalWithTax: (data) => data.total * (1 + data.taxRate)
81
84
  * }
85
+ * @reactive
82
86
  */
83
87
  formulas_: null,
84
88
  /**
85
89
  * @member {Neo.state.Provider|null} parent_=null
90
+ * @reactive
86
91
  */
87
92
  parent_: null,
88
93
  /**
@@ -104,6 +109,7 @@ class Provider extends Base {
104
109
  * autoLoad: true
105
110
  * }
106
111
  * }
112
+ * @reactive
107
113
  */
108
114
  stores_: null
109
115
  }
@@ -161,21 +167,16 @@ class Provider extends Base {
161
167
 
162
168
  if (value) {
163
169
  Object.entries(value).forEach(([formulaKey, formulaFn]) => {
164
- // Create a new Effect for each formula. The Effect's fn will re-run whenever its dependencies change.
170
+ // Create a new lazy Effect. It will not run until explicitly told to.
165
171
  const effect = new Effect({
166
172
  fn: () => {
167
173
  const
168
- hierarchicalData = me.getHierarchyData(), // Get the reactive data proxy
169
- result = formulaFn(hierarchicalData); // Execute the formula with the data
170
-
171
- // Assign the result back to the state provider's data.
172
- // This makes the formula's output available as a data property.
173
- if (isNaN(result)) {
174
- me.setData(formulaKey, null)
175
- } else {
176
- me.setData(formulaKey, result)
177
- }
178
- }
174
+ hierarchicalData = me.getHierarchyData(),
175
+ result = formulaFn(hierarchicalData);
176
+
177
+ me.setData(formulaKey, result);
178
+ },
179
+ lazy: true
179
180
  });
180
181
 
181
182
  me.#formulaEffects.set(formulaKey, effect)
@@ -223,24 +224,22 @@ class Provider extends Base {
223
224
  * @param {String} configKey The component config to bind (e.g., 'text').
224
225
  * @param {String|Function} formatter The function that computes the value.
225
226
  */
226
- createBinding(componentId, configKey, key, isTwoWay) {
227
+ createBinding(componentId, configKey, formatter) {
227
228
  const
228
229
  me = this,
229
- effect = new Effect({
230
- fn: () => {
230
+ effect = new Effect(() => {
231
231
  const component = Neo.get(componentId);
232
232
 
233
233
  if (component && !component.isDestroyed) {
234
234
  const
235
235
  hierarchicalData = me.getHierarchyData(),
236
- newValue = Neo.isFunction(key) ? key.call(me, hierarchicalData) : hierarchicalData[key];
236
+ newValue = Neo.isFunction(formatter) ? formatter.call(me, hierarchicalData) : hierarchicalData[formatter];
237
237
 
238
238
  component._skipTwoWayPush = configKey;
239
239
  component[configKey] = newValue;
240
240
  delete component._skipTwoWayPush
241
241
  }
242
- }
243
- });
242
+ });
244
243
 
245
244
  me.#bindingEffects.set(componentId, effect);
246
245
 
@@ -262,7 +261,8 @@ class Provider extends Base {
262
261
  * @param {Neo.component.Base} component The component instance whose bindings are to be created.
263
262
  */
264
263
  createBindings(component) {
265
- let hasTwoWayBinding = false;
264
+ let me = this,
265
+ hasTwoWayBinding = false;
266
266
 
267
267
  Object.entries(component.bind || {}).forEach(([configKey, value]) => {
268
268
  let key = value;
@@ -276,12 +276,12 @@ class Provider extends Base {
276
276
  }
277
277
 
278
278
  // Determine if it's a store binding or a data binding.
279
- if (this.isStoreValue(key)) {
279
+ if (me.isStoreValue(key)) {
280
280
  // For store bindings, resolve the store and assign it to the component config.
281
- this.resolveStore(component, configKey, key.substring(7)) // remove the "stores." prefix
281
+ me.resolveStore(component, configKey, key.substring(7)) // remove the "stores." prefix
282
282
  } else {
283
283
  // For data bindings, create an Effect to keep the component config in sync with the data.
284
- this.createBinding(component.id, configKey, key, value.twoWay)
284
+ me.createBinding(component.id, configKey, key, value.twoWay)
285
285
  }
286
286
  });
287
287
 
@@ -435,52 +435,45 @@ class Provider extends Base {
435
435
  * @returns {String[]}
436
436
  */
437
437
  getTopLevelDataKeys(path) {
438
- const keys = new Set();
439
- const pathPrefix = path ? `${path}.` : '';
438
+ const
439
+ keys = new Set(),
440
+ pathPrefix = path ? `${path}.` : '';
440
441
 
441
442
  for (const fullPath in this.#dataConfigs) {
442
443
  if (fullPath.startsWith(pathPrefix)) {
443
- const relativePath = fullPath.substring(pathPrefix.length);
444
- const topLevelKey = relativePath.split('.')[0];
444
+ const
445
+ relativePath = fullPath.substring(pathPrefix.length),
446
+ topLevelKey = relativePath.split('.')[0];
447
+
445
448
  if (topLevelKey) {
446
- keys.add(topLevelKey);
449
+ keys.add(topLevelKey)
447
450
  }
448
451
  }
449
452
  }
450
- return Array.from(keys);
453
+
454
+ return Array.from(keys)
451
455
  }
452
456
 
453
457
  /**
454
- * Internal method to avoid code redundancy.
455
- * Use setData() or setDataAtSameLevel() instead.
458
+ * This is the core method for setting data, providing a single entry point for all data modifications.
459
+ * It handles multiple scenarios:
460
+ * 1. **Object-based updates:** If `key` is an object, it recursively calls itself for each key-value pair.
461
+ * 2. **Data Records:** If `value` is a `Neo.data.Record`, it is treated as an atomic value and set directly.
462
+ * 3. **Bubbling Reactivity:** For a given key (e.g., 'user.name'), it sets the leaf value and then "bubbles up"
463
+ * the change, creating new parent objects (e.g., 'user') to ensure that effects depending on any part
464
+ * of the path are triggered.
456
465
  *
457
- * This method handles setting data properties, including nested paths and Neo.data.Record instances.
458
- * It determines the owning StateProvider in the hierarchy and delegates to #setConfigValue.
466
+ * All updates are batched by the public `setData` methods to ensure effects run only once.
467
+ * Use `setData()` or `setDataAtSameLevel()` instead of calling this method directly.
459
468
  *
460
- * Passing an originStateProvider param will try to set each key on the closest property match
461
- * inside the parent stateProvider chain => setData()
462
- * Not passing it will set all values on the stateProvider where the method gets called => setDataAtSameLevel()
463
- * @param {Object|String} key
464
- * @param {*} value
465
- * @param {Neo.state.Provider} [originStateProvider]
469
+ * @param {Object|String} key The property to set, or an object of key-value pairs.
470
+ * @param {*} value The new value.
471
+ * @param {Neo.state.Provider} [originStateProvider] The provider to start the search from for hierarchical updates.
466
472
  * @protected
467
473
  */
468
474
  internalSetData(key, value, originStateProvider) {
469
475
  const me = this;
470
476
 
471
- // If the value is a Neo.data.Record, treat it as an atomic value
472
- // and set it directly without further recursive processing of its properties.
473
- if (Neo.isObject(value) && value.isRecord) {
474
- const
475
- ownerDetails = me.getOwnerOfDataProperty(key),
476
- targetProvider = ownerDetails ? ownerDetails.owner : (originStateProvider || me);
477
-
478
- me.#setConfigValue(targetProvider, key, value, null);
479
- return
480
- }
481
-
482
- // If the key is an object, iterate over its entries and recursively call internalSetData.
483
- // This handles setting multiple properties at once (e.g., setData({prop1: val1, prop2: val2})).
484
477
  if (Neo.isObject(key)) {
485
478
  Object.entries(key).forEach(([dataKey, dataValue]) => {
486
479
  me.internalSetData(dataKey, dataValue, originStateProvider)
@@ -488,33 +481,52 @@ class Provider extends Base {
488
481
  return
489
482
  }
490
483
 
491
- // Handle single key/value pairs, including nested paths (e.g., 'user.firstName').
484
+ // Now 'key' is a string path.
485
+ // If 'value' is a plain object, we need to drill down further.
486
+ // If the value is a Neo.data.Record, treat it as an atomic value => it will not enter this block.
487
+ if (Neo.typeOf(value) === 'Object') {
488
+ Object.entries(value).forEach(([nestedKey, nestedValue]) => {
489
+ const fullPath = `${key}.${nestedKey}`;
490
+ me.internalSetData(fullPath, nestedValue, originStateProvider);
491
+ });
492
+ return // We've delegated the setting to deeper paths.
493
+ }
494
+
492
495
  const
493
496
  ownerDetails = me.getOwnerOfDataProperty(key),
494
- targetProvider = ownerDetails ? ownerDetails.owner : (originStateProvider || me),
495
- pathParts = key.split('.');
496
-
497
- let currentPath = '',
498
- currentConfig = null,
499
- currentProvider = targetProvider;
500
-
501
- for (let i = 0; i < pathParts.length; i++) {
502
- const part = pathParts[i];
503
- currentPath = currentPath ? `${currentPath}.${part}` : part;
504
- currentConfig = currentProvider.getDataConfig(currentPath);
505
-
506
- if (i === pathParts.length - 1) { // Last part of the path
507
- // Set the value for the final property in the path.
508
- me.#setConfigValue(currentProvider, currentPath, value, null)
509
- } else { // Intermediate part of the path
510
- // Ensure intermediate paths exist as objects. If not, create them.
511
- // If an intermediate path exists but is not an object, overwrite it with an empty object.
512
- if (!currentConfig) {
513
- currentConfig = new Config({}); // Create an empty object config
514
- currentProvider.#dataConfigs[currentPath] = currentConfig
515
- } else if (!Neo.isObject(currentConfig.get())) {
516
- currentConfig.set({})
497
+ targetProvider = ownerDetails ? ownerDetails.owner : (originStateProvider || me);
498
+
499
+ me.#setConfigValue(targetProvider, key, value, null);
500
+
501
+ // This is the "reactivity bubbling" logic. When a leaf property like 'user.name' changes,
502
+ // we must also trigger effects that depend on the parent object 'user'. We do this by
503
+ // creating a new object reference for each parent in the path. The spread syntax
504
+ // `{ ...oldParentValue, [leafKey]: latestValue }` is key, as it creates a new
505
+ // object, which the reactivity system detects as a change.
506
+ let path = key,
507
+ latestValue = value;
508
+
509
+ while (path.includes('.')) {
510
+ const leafKey = path.split('.').pop();
511
+ path = path.substring(0, path.lastIndexOf('.'));
512
+
513
+ const parentConfig = targetProvider.getDataConfig(path);
514
+
515
+ if (parentConfig) {
516
+ const oldParentValue = parentConfig.get();
517
+ if (Neo.isObject(oldParentValue)) {
518
+ const newParentValue = { ...oldParentValue, [leafKey]: latestValue };
519
+ parentConfig.set(newParentValue);
520
+ latestValue = newParentValue;
521
+ } else {
522
+ break // Stop if parent is not an object
517
523
  }
524
+ } else {
525
+ // If the parent config doesn't exist, we need to create it to support bubbling.
526
+ // This is crucial for creating new nested data structures at runtime.
527
+ const newParentValue = {[leafKey]: latestValue};
528
+ me.#setConfigValue(targetProvider, path, newParentValue);
529
+ latestValue = newParentValue
518
530
  }
519
531
  }
520
532
  }
@@ -528,6 +540,18 @@ class Provider extends Base {
528
540
  return Neo.isString(value) && value.startsWith('stores.')
529
541
  }
530
542
 
543
+ /**
544
+ * Gets called after all constructors & configs are applied.
545
+ * @protected
546
+ */
547
+ onConstructed() {
548
+ super.onConstructed();
549
+
550
+ // After the provider is fully constructed and initial data is set,
551
+ // run the formula effects for the first time to compute their initial values.
552
+ this.#formulaEffects.forEach(effect => effect.run())
553
+ }
554
+
531
555
  /**
532
556
  * @param {String} key
533
557
  * @param {*} value
@@ -552,22 +576,22 @@ class Provider extends Base {
552
576
 
553
577
  // Ensure a Config instance exists for the current fullPath
554
578
  if (me.#dataConfigs[fullPath]) {
555
- me.#dataConfigs[fullPath].set(value);
579
+ me.#dataConfigs[fullPath].set(value)
556
580
  } else {
557
- me.#dataConfigs[fullPath] = new Config(value);
581
+ me.#dataConfigs[fullPath] = new Config(value)
558
582
  }
559
583
 
560
584
  // If the value is a plain object, recursively process its properties
561
585
  if (Neo.typeOf(value) === 'Object') {
562
- me.processDataObject(value, fullPath);
586
+ me.processDataObject(value, fullPath)
563
587
  }
564
588
  });
565
589
  }
566
590
 
567
591
  /**
568
592
  * @param {Neo.component.Base} component
569
- * @param {String} configName
570
- * @param {String} storeName
593
+ * @param {String} configName
594
+ * @param {String} storeName
571
595
  */
572
596
  resolveStore(component, configName, storeName) {
573
597
  let store = this.getStore(storeName);
@@ -582,9 +606,9 @@ class Provider extends Base {
582
606
  * This method creates a new Config instance if one doesn't exist for the given path,
583
607
  * or updates an existing one. It also triggers binding effects and calls onDataPropertyChange.
584
608
  * @param {Neo.state.Provider} provider The StateProvider instance owning the config.
585
- * @param {String} path The full path of the data property (e.g., 'user.firstname').
586
- * @param {*} newValue The new value to set.
587
- * @param {*} oldVal The old value (optional, used for initial setup).
609
+ * @param {String} path The full path of the data property (e.g., 'user.firstname').
610
+ * @param {*} newValue The new value to set.
611
+ * @param {*} [oldVal] The old value (optional, used for initial setup).
588
612
  * @private
589
613
  */
590
614
  #setConfigValue(provider, path, newValue, oldVal) {
@@ -608,21 +632,39 @@ class Provider extends Base {
608
632
  /**
609
633
  * The method will assign all values to the closest stateProvider where it finds an existing key.
610
634
  * In case no match is found inside the parent chain, a new data property will get generated.
635
+ *
636
+ * All updates within a single call are batched to ensure that reactive effects (bindings and formulas)
637
+ * are run only once.
638
+ *
611
639
  * @param {Object|String} key
612
- * @param {*} value
640
+ * @param {*} value
613
641
  */
614
642
  setData(key, value) {
615
- this.internalSetData(key, value, this)
643
+ EffectManager.pause();
644
+ try {
645
+ this.internalSetData(key, value, this)
646
+ } finally {
647
+ EffectManager.resume()
648
+ }
616
649
  }
617
650
 
618
651
  /**
619
652
  * Use this method instead of setData() in case you want to enforce
620
653
  * setting all keys on this instance instead of looking for matches inside parent stateProviders.
654
+ *
655
+ * All updates within a single call are batched to ensure that reactive effects (bindings and formulas)
656
+ * are run only once.
657
+ *
621
658
  * @param {Object|String} key
622
- * @param {*} value
659
+ * @param {*} value
623
660
  */
624
661
  setDataAtSameLevel(key, value) {
625
- this.internalSetData(key, value)
662
+ EffectManager.pause();
663
+ try {
664
+ this.internalSetData(key, value)
665
+ } finally {
666
+ EffectManager.resume()
667
+ }
626
668
  }
627
669
  }
628
670
 
@@ -22,7 +22,7 @@ function createNestedProxy(rootProvider, path) {
22
22
  // Handle internal properties that might be set directly on the proxy's target
23
23
  // or are expected by the environment (like Siesta's __REFADR__).
24
24
  if (typeof property === 'symbol' || property === '__REFADR__' || property === 'inspect' || property === 'then') {
25
- return Reflect.get(currentTarget, property);
25
+ return Reflect.get(currentTarget, property)
26
26
  }
27
27
 
28
28
  // Only allow string or number properties to proceed as data paths.
@@ -30,6 +30,20 @@ function createNestedProxy(rootProvider, path) {
30
30
  return undefined; // For other non-string/non-number properties, return undefined.
31
31
  }
32
32
 
33
+ // Special handling for the 'stores' property at the root level
34
+ if (path === '' && property === 'stores') {
35
+ return new Proxy({}, {
36
+ get(target, storeName) {
37
+ if (typeof storeName === 'symbol' || storeName === '__REFADR__') {
38
+ return Reflect.get(target, storeName)
39
+ }
40
+ // Delegate to the StateProvider's getStore method for hierarchical resolution
41
+ // Accessing store.count later will register the dependency via the Config system
42
+ return rootProvider.getStore(storeName)
43
+ }
44
+ })
45
+ }
46
+
33
47
  const fullPath = path ? `${path}.${property}` : property;
34
48
 
35
49
  // 1. Check if the full path corresponds to an actual data property.
@@ -41,17 +55,15 @@ function createNestedProxy(rootProvider, path) {
41
55
  config = owner.getDataConfig(propertyName);
42
56
 
43
57
  if (config) {
44
- const activeEffect = EffectManager.getActiveEffect();
45
- if (activeEffect) {
46
- activeEffect.addDependency(config);
47
- }
58
+ EffectManager.getActiveEffect()?.addDependency(config);
48
59
 
49
60
  const value = config.get();
50
61
  // If the value is an object, return a new proxy for it to ensure nested accesses are also proxied.
51
- if (Neo.typeOf(value) === 'Object') {
62
+ if (Neo.isObject(value)) {
52
63
  return createNestedProxy(rootProvider, fullPath)
53
64
  }
54
- return value;
65
+
66
+ return value
55
67
  }
56
68
  }
57
69
 
@@ -62,52 +74,54 @@ function createNestedProxy(rootProvider, path) {
62
74
  return createNestedProxy(rootProvider, fullPath)
63
75
  }
64
76
 
65
- // 3. If it's neither a data property nor a path to one, it doesn't exist in the state.
66
- return null
77
+ // 3. If it's neither a data property nor a path to one, it doesn't exist.
78
+ // Returning undefined ensures that chained accesses (e.g., data.nonexistent.property) fail gracefully.
67
79
  },
68
80
 
69
81
  set(currentTarget, property, value) {
70
82
  // Allow internal properties (like Symbols or specific strings) to be set directly on the target.
71
83
  if (typeof property === 'symbol' || property === '__REFADR__') {
72
- return Reflect.set(currentTarget, property, value);
84
+ return Reflect.set(currentTarget, property, value)
73
85
  }
74
86
 
75
- const fullPath = path ? `${path}.${property}` : property;
76
- const ownerDetails = rootProvider.getOwnerOfDataProperty(fullPath);
77
-
87
+ const
88
+ fullPath = path ? `${path}.${property}` : property,
89
+ ownerDetails = rootProvider.getOwnerOfDataProperty(fullPath);
78
90
  let targetProvider;
91
+
79
92
  if (ownerDetails) {
80
- targetProvider = ownerDetails.owner;
93
+ targetProvider = ownerDetails.owner
81
94
  } else {
82
95
  // If no owner is found, set it on the rootProvider (the one that created this proxy)
83
- targetProvider = rootProvider;
96
+ targetProvider = rootProvider
84
97
  }
85
98
 
86
99
  targetProvider.setData(fullPath, value);
87
- return true; // Indicate that the assignment was successful
100
+ return true // Indicate that the assignment was successful
88
101
  },
89
102
 
90
103
  ownKeys(currentTarget) {
91
- return rootProvider.getTopLevelDataKeys(path);
104
+ return rootProvider.getTopLevelDataKeys(path)
92
105
  },
93
106
 
94
107
  getOwnPropertyDescriptor(currentTarget, property) {
95
- const fullPath = path ? `${path}.${property}` : property;
96
- const ownerDetails = rootProvider.getOwnerOfDataProperty(fullPath);
108
+ const
109
+ fullPath = path ? `${path}.${property}` : property,
110
+ ownerDetails = rootProvider.getOwnerOfDataProperty(fullPath);
97
111
 
98
112
  if (ownerDetails) {
99
113
  const config = ownerDetails.owner.getDataConfig(ownerDetails.propertyName);
114
+
100
115
  if (config) {
101
116
  const value = config.get();
102
117
  return {
103
- value: Neo.isObject(value) ? createNestedProxy(rootProvider, fullPath) : value,
104
- writable: true,
105
- enumerable: true,
106
- configurable: true,
107
- };
118
+ value : Neo.isObject(value) ? createNestedProxy(rootProvider, fullPath) : value,
119
+ writable : true,
120
+ enumerable : true,
121
+ configurable: true
122
+ }
108
123
  }
109
124
  }
110
- return undefined; // Property not found
111
125
  }
112
126
  })
113
127
  }
@@ -32,6 +32,7 @@ class Container extends BaseContainer {
32
32
  /**
33
33
  * You can use null to not render any items initially
34
34
  * @member {Number|null} activeIndex_=0
35
+ * @reactive
35
36
  */
36
37
  activeIndex_: 0,
37
38
  /**
@@ -60,11 +61,13 @@ class Container extends BaseContainer {
60
61
  headerToolbar: null,
61
62
  /**
62
63
  * @member {Object|null} layout=null
64
+ * @reactive
63
65
  */
64
66
  layout: null,
65
67
  /**
66
68
  * True to not apply a background effect to the tab header container
67
69
  * @member {Boolean} plain_=true
70
+ * @reactive
68
71
  */
69
72
  plain_: true,
70
73
  /*
@@ -77,6 +80,7 @@ class Container extends BaseContainer {
77
80
  * true enables sorting tabs via drag&drop.
78
81
  * The config gets passed to the header toolbar
79
82
  * @member {Boolean} sortable_=false
83
+ * @reactive
80
84
  */
81
85
  sortable_: false,
82
86
  /**
@@ -96,6 +100,7 @@ class Container extends BaseContainer {
96
100
  * The position of the tab header toolbar.
97
101
  * Valid values are top, right, bottom, left.
98
102
  * @member {String} tabBarPosition_='top'
103
+ * @reactive
99
104
  */
100
105
  tabBarPosition_: 'top',
101
106
  /**
@@ -105,6 +110,7 @@ class Container extends BaseContainer {
105
110
  tabContainerCls: 'neo-tab-container',
106
111
  /**
107
112
  * @member {Boolean} useActiveTabIndicator_=true
113
+ * @reactive
108
114
  */
109
115
  useActiveTabIndicator_: true
110
116
  }
package/src/tab/Strip.mjs CHANGED
@@ -26,6 +26,7 @@ class Strip extends Component {
26
26
  tabContainerId: null,
27
27
  /**
28
28
  * @member {Boolean} useActiveTabIndicator_=true
29
+ * @reactive
29
30
  */
30
31
  useActiveTabIndicator_: true,
31
32
  /**
@@ -23,10 +23,12 @@ class Button extends BaseButton {
23
23
  /**
24
24
  * Specify a role tag attribute for the vdom root.
25
25
  * @member {String|null} role='tab'
26
+ * @reactive
26
27
  */
27
28
  role: 'tab',
28
29
  /**
29
30
  * @member {Boolean} useActiveTabIndicator_=true
31
+ * @reactive
30
32
  */
31
33
  useActiveTabIndicator_: true,
32
34
  /**
@@ -23,10 +23,12 @@ class EffectTabButton extends EffectButton {
23
23
  /**
24
24
  * Specify a role tag attribute for the vdom root.
25
25
  * @member {String|null} role='tab'
26
+ * @reactive
26
27
  */
27
28
  role: 'tab',
28
29
  /**
29
30
  * @member {Boolean} useActiveTabIndicator_=true
31
+ * @reactive
30
32
  */
31
33
  useActiveTabIndicator_: true
32
34
  }