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.
- package/.github/RELEASE_NOTES/v10.0.0-beta.5.md +70 -0
- package/.github/RELEASE_NOTES/v10.0.0-beta.6.md +48 -0
- package/.github/epic-functional-components.md +498 -0
- package/.github/ticket-asymmetric-vdom-updates.md +122 -0
- package/README.md +0 -3
- package/ServiceWorker.mjs +2 -2
- package/apps/colors/store/Colors.mjs +1 -0
- package/apps/colors/view/GridContainer.mjs +3 -0
- package/apps/colors/view/HeaderToolbar.mjs +2 -0
- package/apps/colors/view/Viewport.mjs +3 -0
- package/apps/covid/view/FooterContainer.mjs +3 -0
- package/apps/covid/view/GalleryContainer.mjs +2 -0
- package/apps/covid/view/GalleryContainerController.mjs +1 -0
- package/apps/covid/view/HeaderContainer.mjs +2 -0
- package/apps/covid/view/HelixContainer.mjs +2 -0
- package/apps/covid/view/HelixContainerController.mjs +1 -0
- package/apps/covid/view/MainContainer.mjs +3 -0
- package/apps/covid/view/TableContainer.mjs +3 -0
- package/apps/covid/view/TableContainerController.mjs +1 -0
- package/apps/covid/view/WorldMapContainer.mjs +2 -0
- package/apps/covid/view/country/Gallery.mjs +3 -0
- package/apps/covid/view/country/Helix.mjs +8 -0
- package/apps/covid/view/country/HistoricalDataTable.mjs +1 -0
- package/apps/covid/view/country/Table.mjs +2 -0
- package/apps/covid/view/mapboxGl/Component.mjs +1 -0
- package/apps/covid/view/mapboxGl/Container.mjs +2 -0
- package/apps/email/EPIC_PLAN.md +58 -0
- package/apps/email/neo-config.json +2 -2
- package/apps/email/store/Emails.mjs +11 -1
- package/apps/email/view/ComposeView.mjs +44 -0
- package/apps/email/view/MainView.mjs +89 -0
- package/apps/email/view/Viewport.mjs +4 -33
- package/apps/email/view/ViewportStateProvider.mjs +3 -3
- package/apps/form/store/SideNav.mjs +1 -0
- package/apps/form/view/FormContainer.mjs +1 -0
- package/apps/form/view/FormPageContainer.mjs +2 -0
- package/apps/form/view/SideNavList.mjs +1 -0
- package/apps/form/view/Viewport.mjs +3 -0
- package/apps/portal/childapps/preview/MainContainer.mjs +1 -0
- package/apps/portal/index.html +1 -1
- package/apps/portal/store/BlogPosts.mjs +2 -0
- package/apps/portal/store/Content.mjs +1 -0
- package/apps/portal/store/ContentSections.mjs +1 -0
- package/apps/portal/store/Examples.mjs +1 -0
- package/apps/portal/view/HeaderToolbar.mjs +1 -0
- package/apps/portal/view/Viewport.mjs +5 -0
- package/apps/portal/view/ViewportController.mjs +8 -2
- package/apps/portal/view/about/Container.mjs +2 -0
- package/apps/portal/view/about/MemberContainer.mjs +7 -0
- package/apps/portal/view/blog/Container.mjs +2 -0
- package/apps/portal/view/blog/List.mjs +2 -0
- package/apps/portal/view/examples/List.mjs +1 -0
- package/apps/portal/view/examples/TabContainer.mjs +4 -0
- package/apps/portal/view/home/ContentBox.mjs +3 -0
- package/apps/portal/view/home/FeatureSection.mjs +8 -0
- package/apps/portal/view/home/FooterContainer.mjs +4 -1
- package/apps/portal/view/home/MainContainer.mjs +2 -0
- package/apps/portal/view/home/parts/AfterMath.mjs +2 -0
- package/apps/portal/view/home/parts/BaseContainer.mjs +1 -0
- package/apps/portal/view/home/parts/Colors.mjs +4 -0
- package/apps/portal/view/home/parts/Features.mjs +2 -0
- package/apps/portal/view/home/parts/Helix.mjs +5 -0
- package/apps/portal/view/home/parts/How.mjs +4 -0
- package/apps/portal/view/home/parts/MainNeo.mjs +1 -0
- package/apps/portal/view/home/parts/References.mjs +2 -0
- package/apps/portal/view/learn/ContentComponent.mjs +11 -5
- package/apps/portal/view/learn/ContentTreeList.mjs +2 -0
- package/apps/portal/view/learn/CubeLayoutButton.mjs +1 -0
- package/apps/portal/view/learn/MainContainer.mjs +4 -0
- package/apps/portal/view/learn/PageContainer.mjs +2 -0
- package/apps/portal/view/learn/PageSectionsContainer.mjs +3 -0
- package/apps/portal/view/learn/PageSectionsList.mjs +1 -0
- package/apps/portal/view/services/Component.mjs +1 -0
- package/apps/realworld/api/Base.mjs +1 -0
- package/apps/realworld/view/HeaderComponent.mjs +4 -0
- package/apps/realworld/view/HomeComponent.mjs +7 -0
- package/apps/realworld/view/MainContainer.mjs +2 -0
- package/apps/realworld/view/MainContainerController.mjs +2 -0
- package/apps/realworld/view/article/CommentComponent.mjs +3 -0
- package/apps/realworld/view/article/Component.mjs +17 -10
- package/apps/realworld/view/article/CreateCommentComponent.mjs +2 -0
- package/apps/realworld/view/article/CreateComponent.mjs +5 -0
- package/apps/realworld/view/article/PreviewComponent.mjs +9 -0
- package/apps/realworld/view/article/TagListComponent.mjs +2 -0
- package/apps/realworld/view/user/ProfileComponent.mjs +7 -0
- package/apps/realworld/view/user/SettingsComponent.mjs +5 -0
- package/apps/realworld/view/user/SignUpComponent.mjs +3 -0
- package/apps/realworld2/api/Base.mjs +1 -0
- package/apps/realworld2/view/FooterComponent.mjs +1 -0
- package/apps/realworld2/view/HeaderToolbar.mjs +3 -0
- package/apps/realworld2/view/HomeContainer.mjs +1 -0
- package/apps/realworld2/view/MainContainer.mjs +2 -0
- package/apps/realworld2/view/MainContainerController.mjs +1 -0
- package/apps/realworld2/view/article/Helix.mjs +1 -0
- package/apps/realworld2/view/article/PreviewComponent.mjs +9 -0
- package/apps/realworld2/view/article/PreviewList.mjs +1 -0
- package/apps/realworld2/view/article/TagListComponent.mjs +2 -0
- package/apps/route/view/CenterContainer.mjs +1 -0
- package/apps/route/view/MainView.mjs +1 -0
- package/apps/sharedcovid/childapps/sharedcovidchart/MainContainer.mjs +1 -0
- package/apps/sharedcovid/childapps/sharedcovidgallery/MainContainer.mjs +1 -0
- package/apps/sharedcovid/childapps/sharedcovidhelix/MainContainer.mjs +1 -0
- package/apps/sharedcovid/childapps/sharedcovidmap/MainContainer.mjs +1 -0
- package/apps/sharedcovid/view/FooterContainer.mjs +3 -0
- package/apps/sharedcovid/view/GalleryContainer.mjs +2 -0
- package/apps/sharedcovid/view/GalleryContainerController.mjs +1 -0
- package/apps/sharedcovid/view/HeaderContainer.mjs +2 -0
- package/apps/sharedcovid/view/HelixContainer.mjs +2 -0
- package/apps/sharedcovid/view/HelixContainerController.mjs +1 -0
- package/apps/sharedcovid/view/MainContainer.mjs +3 -0
- package/apps/sharedcovid/view/TableContainer.mjs +3 -0
- package/apps/sharedcovid/view/TableContainerController.mjs +1 -0
- package/apps/sharedcovid/view/WorldMapContainer.mjs +2 -0
- package/apps/sharedcovid/view/country/Gallery.mjs +3 -0
- package/apps/sharedcovid/view/country/Helix.mjs +8 -0
- package/apps/sharedcovid/view/country/HistoricalDataTable.mjs +1 -0
- package/apps/sharedcovid/view/country/Table.mjs +2 -0
- package/apps/sharedcovid/view/mapboxGl/Component.mjs +1 -0
- package/apps/sharedcovid/view/mapboxGl/Container.mjs +2 -0
- package/apps/shareddialog/childapps/shareddialog2/view/MainContainer.mjs +2 -0
- package/apps/shareddialog/view/DemoDialog.mjs +2 -0
- package/apps/shareddialog/view/MainContainer.mjs +2 -0
- package/apps/shareddialog/view/MainContainerController.mjs +1 -0
- package/buildScripts/addReactiveTags.mjs +191 -0
- package/buildScripts/checkReactiveTags.mjs +160 -0
- package/docs/app/store/Api.mjs +1 -0
- package/docs/app/store/Examples.mjs +1 -0
- package/docs/app/view/ApiTreeList.mjs +1 -0
- package/docs/app/view/ContentTabContainer.mjs +2 -0
- package/docs/app/view/ExamplesTreeList.mjs +2 -0
- package/docs/app/view/HeaderContainer.mjs +3 -0
- package/docs/app/view/MainContainer.mjs +5 -0
- package/docs/app/view/classdetails/HeaderComponent.mjs +1 -0
- package/docs/app/view/classdetails/MainContainer.mjs +3 -0
- package/docs/app/view/classdetails/MembersList.mjs +5 -0
- package/docs/app/view/classdetails/SourceViewComponent.mjs +2 -0
- package/examples/ConfigurationViewport.mjs +14 -8
- package/examples/calendar/weekview/MainContainer.mjs +4 -0
- package/examples/component/coronaGallery/CountryGallery.mjs +2 -0
- package/examples/component/coronaGallery/CountryStore.mjs +1 -0
- package/examples/component/coronaGallery/Viewport.mjs +3 -0
- package/examples/component/coronaGallery/ViewportController.mjs +1 -0
- package/examples/component/coronaHelix/CountryHelix.mjs +7 -0
- package/examples/component/coronaHelix/MainContainer.mjs +1 -0
- package/examples/component/gallery/ImageStore.mjs +1 -0
- package/examples/component/helix/ImageStore.mjs +1 -0
- package/examples/component/helix/Viewport.mjs +3 -0
- package/examples/component/helix/ViewportController.mjs +1 -0
- package/examples/component/multiWindowCoronaGallery/childapp/Viewport.mjs +1 -0
- package/examples/component/multiWindowHelix/childapp/Viewport.mjs +1 -0
- package/examples/component/wrapper/googleMaps/MapComponent.mjs +2 -0
- package/examples/core/config/MainContainer.mjs +2 -0
- package/examples/dialog/DemoDialog.mjs +2 -0
- package/examples/dialog/MainContainer.mjs +1 -0
- package/examples/form/field/color/MainStore.mjs +1 -0
- package/examples/functional/defineComponent/Component.mjs +18 -0
- package/examples/functional/defineComponent/MainContainer.mjs +41 -0
- package/examples/functional/defineComponent/app.mjs +6 -0
- package/examples/functional/defineComponent/index.html +11 -0
- package/examples/functional/defineComponent/neo-config.json +6 -0
- package/examples/functional/hostComponent/Component.mjs +32 -0
- package/examples/functional/hostComponent/MainContainer.mjs +48 -0
- package/examples/functional/hostComponent/app.mjs +6 -0
- package/examples/functional/hostComponent/index.html +11 -0
- package/examples/functional/hostComponent/neo-config.json +6 -0
- package/examples/grid/animatedRowSorting/Viewport.mjs +1 -1
- package/examples/grid/bigData/ControlsContainer.mjs +3 -0
- package/examples/grid/bigData/GridContainer.mjs +4 -2
- package/examples/grid/bigData/MainContainer.mjs +2 -0
- package/examples/grid/bigData/MainModel.mjs +1 -0
- package/examples/grid/bigData/MainStore.mjs +3 -0
- package/examples/grid/cellEditing/MainContainer.mjs +1 -1
- package/examples/grid/container/MainContainer.mjs +1 -1
- package/examples/grid/covid/GridContainer.mjs +3 -0
- package/examples/grid/covid/MainContainer.mjs +2 -0
- package/examples/grid/covid/Store.mjs +1 -0
- package/examples/grid/nestedRecordFields/EditUserDialog.mjs +3 -0
- package/examples/grid/nestedRecordFields/Viewport.mjs +3 -1
- package/examples/list/animate/List.mjs +4 -0
- package/examples/list/animate/MainContainer.mjs +2 -0
- package/examples/list/circle/MainStore.mjs +1 -0
- package/examples/list/color/MainStore.mjs +1 -0
- package/examples/preloadingAssets/view/MainContainer.mjs +2 -0
- package/examples/stateProvider/advanced/MainContainer.mjs +1 -0
- package/examples/stateProvider/dialog/EditUserDialog.mjs +2 -0
- package/examples/stateProvider/dialog/MainContainer.mjs +1 -0
- package/examples/stateProvider/extendedClass/MainContainer.mjs +2 -0
- package/examples/stateProvider/inline/MainContainer.mjs +1 -0
- package/examples/stateProvider/inlineNoStateProvider/MainContainer.mjs +1 -0
- package/examples/stateProvider/inlineNoStateProvider/MainContainerController.mjs +2 -0
- package/examples/stateProvider/multiWindow/EditUserDialog.mjs +3 -0
- package/examples/stateProvider/multiWindow/MainContainer.mjs +1 -0
- package/examples/stateProvider/multiWindow/Viewport.mjs +1 -0
- package/examples/stateProvider/nestedData/MainContainer.mjs +1 -0
- package/examples/stateProvider/table/MainContainer.mjs +1 -0
- package/examples/table/covid/MainContainer.mjs +2 -0
- package/examples/table/covid/Store.mjs +1 -0
- package/examples/table/covid/TableContainer.mjs +3 -0
- package/examples/table/nestedRecordFields/EditUserDialog.mjs +3 -0
- package/examples/table/nestedRecordFields/Viewport.mjs +1 -0
- package/examples/todoList/version1/MainComponent.mjs +1 -1
- package/examples/toolbar/breadcrumb/view/MainContainer.mjs +2 -0
- package/examples/toolbar/paging/store/Users.mjs +1 -0
- package/examples/toolbar/paging/view/AddUserDialog.mjs +3 -0
- package/examples/toolbar/paging/view/MainContainer.mjs +3 -0
- package/examples/treeAccordion/MainContainer.mjs +2 -2
- package/examples/worker/task/MainContainer.mjs +1 -0
- package/learn/Glossary.md +1 -0
- package/learn/UsingTheseTopics.md +1 -0
- package/learn/benefits/ConfigSystem.md +2 -0
- package/learn/benefits/Effort.md +1 -0
- package/learn/benefits/Features.md +1 -0
- package/learn/benefits/FormsEngine.md +1 -0
- package/learn/benefits/FourEnvironments.md +2 -0
- package/learn/benefits/Introduction.md +2 -0
- package/learn/benefits/MultiWindow.md +3 -1
- package/learn/benefits/OffTheMainThread.md +2 -0
- package/learn/benefits/Quick.md +2 -0
- package/learn/benefits/RPCLayer.md +2 -0
- package/learn/benefits/Speed.md +2 -0
- package/learn/comparisons/NeoVsAngular.md +90 -0
- package/learn/comparisons/NeoVsExtJs.md +178 -0
- package/learn/comparisons/NeoVsNextJs.md +124 -0
- package/learn/comparisons/NeoVsReact.md +95 -0
- package/learn/comparisons/NeoVsSolid.md +78 -0
- package/learn/comparisons/NeoVsVue.md +92 -0
- package/learn/comparisons/Overview.md +46 -0
- package/learn/gettingstarted/ComponentModels.md +2 -0
- package/learn/gettingstarted/Config.md +2 -0
- package/learn/gettingstarted/DescribingTheUI.md +2 -0
- package/learn/gettingstarted/Events.md +2 -0
- package/learn/gettingstarted/Extending.md +2 -0
- package/learn/gettingstarted/References.md +2 -0
- package/learn/gettingstarted/Setup.md +3 -2
- package/learn/gettingstarted/Workspaces.md +2 -0
- package/learn/guides/datahandling/Collections.md +1 -0
- package/learn/guides/datahandling/Records.md +1 -0
- package/learn/guides/datahandling/StateProviders.md +130 -16
- package/learn/guides/datahandling/Tables.md +1 -1
- package/learn/guides/fundamentals/ConfigSystemDeepDive.md +1 -0
- package/learn/guides/fundamentals/DeclarativeComponentTreesVsImperativeVdom.md +2 -0
- package/learn/guides/fundamentals/DeclarativeVDOMWithEffects.md +10 -8
- package/learn/guides/fundamentals/ExtendingNeoClasses.md +1 -0
- package/learn/guides/fundamentals/InstanceLifecycle.md +3 -1
- package/learn/guides/fundamentals/MainThreadAddons.md +2 -0
- package/learn/guides/specificfeatures/Mixins.md +3 -1
- package/learn/guides/specificfeatures/MultiWindow.md +3 -1
- package/learn/guides/specificfeatures/PortalApp.md +2 -0
- package/learn/guides/uibuildingblocks/ComponentsAndContainers.md +2 -0
- package/learn/guides/uibuildingblocks/CustomComponents.md +2 -0
- package/learn/guides/uibuildingblocks/Layouts.md +2 -0
- package/learn/guides/uibuildingblocks/WorkingWithVDom.md +2 -0
- package/learn/guides/userinteraction/Forms.md +2 -0
- package/learn/guides/userinteraction/events/CustomEvents.md +2 -1
- package/learn/guides/userinteraction/events/DomEvents.md +2 -0
- package/learn/javascript/ClassFeatures.md +4 -3
- package/learn/javascript/Classes.md +10 -13
- package/learn/javascript/Overrides.md +10 -6
- package/learn/javascript/Super.md +12 -8
- package/learn/tree.json +71 -64
- package/learn/tutorials/Earthquakes.md +2 -0
- package/learn/tutorials/RSP.md +3 -1
- package/learn/tutorials/TodoList.md +103 -7
- package/package.json +6 -4
- package/resources/scss/src/apps/email/ComposeView.scss +16 -0
- package/resources/scss/src/apps/email/MainView.scss +5 -0
- package/resources/scss/src/apps/portal/learn/ContentComponent.scss +5 -4
- package/src/DefaultConfig.mjs +12 -2
- package/src/Main.mjs +1 -0
- package/src/Neo.mjs +217 -166
- package/src/Xhr.mjs +1 -0
- package/src/button/Base.mjs +13 -0
- package/src/button/Effect.mjs +16 -2
- package/src/button/Split.mjs +2 -0
- package/src/calendar/store/Calendars.mjs +1 -0
- package/src/calendar/store/Colors.mjs +1 -0
- package/src/calendar/store/Events.mjs +1 -0
- package/src/calendar/view/DayComponent.mjs +2 -0
- package/src/calendar/view/EditEventContainer.mjs +4 -1
- package/src/calendar/view/MainContainer.mjs +13 -0
- package/src/calendar/view/MainContainerStateProvider.mjs +14 -28
- package/src/calendar/view/SettingsContainer.mjs +1 -0
- package/src/calendar/view/YearComponent.mjs +16 -0
- package/src/calendar/view/calendars/ColorsList.mjs +2 -0
- package/src/calendar/view/calendars/Container.mjs +2 -0
- package/src/calendar/view/calendars/EditContainer.mjs +1 -0
- package/src/calendar/view/month/Component.mjs +11 -0
- package/src/calendar/view/settings/GeneralContainer.mjs +1 -0
- package/src/calendar/view/settings/MonthContainer.mjs +1 -0
- package/src/calendar/view/settings/WeekContainer.mjs +1 -0
- package/src/calendar/view/settings/YearContainer.mjs +1 -0
- package/src/calendar/view/week/Component.mjs +15 -1
- package/src/calendar/view/week/TimeAxisComponent.mjs +4 -0
- package/src/code/LivePreview.mjs +51 -23
- package/src/collection/Base.mjs +7 -10
- package/src/collection/Filter.mjs +6 -0
- package/src/collection/Sorter.mjs +3 -0
- package/src/component/Base.mjs +104 -771
- package/src/component/Canvas.mjs +1 -0
- package/src/component/Chip.mjs +4 -0
- package/src/component/Circle.mjs +14 -0
- package/src/component/Clock.mjs +4 -0
- package/src/component/DateSelector.mjs +12 -0
- package/src/component/Gallery.mjs +11 -0
- package/src/component/Helix.mjs +24 -0
- package/src/component/Label.mjs +1 -0
- package/src/component/Legend.mjs +3 -0
- package/src/component/MagicMoveText.mjs +4 -0
- package/src/component/Progress.mjs +3 -0
- package/src/component/Splitter.mjs +3 -0
- package/src/component/StatusBadge.mjs +6 -0
- package/src/component/Timer.mjs +4 -0
- package/src/component/Toast.mjs +6 -0
- package/src/component/Video.mjs +1 -0
- package/src/component/mwc/Button.mjs +7 -0
- package/src/component/mwc/TextField.mjs +9 -0
- package/src/component/wrapper/AmChart.mjs +2 -0
- package/src/component/wrapper/GoogleMaps.mjs +3 -0
- package/src/component/wrapper/MapboxGL.mjs +5 -0
- package/src/component/wrapper/MonacoEditor.mjs +12 -0
- package/src/container/Accordion.mjs +2 -0
- package/src/container/Base.mjs +7 -3
- package/src/container/Panel.mjs +1 -0
- package/src/container/Viewport.mjs +1 -0
- package/src/controller/Application.mjs +1 -0
- package/src/controller/Base.mjs +1 -0
- package/src/controller/Component.mjs +1 -0
- package/src/core/Base.mjs +55 -3
- package/src/core/Compare.mjs +4 -7
- package/src/core/Config.mjs +65 -52
- package/src/core/Effect.mjs +79 -13
- package/src/core/EffectBatchManager.mjs +18 -19
- package/src/core/EffectManager.mjs +25 -3
- package/src/core/IdGenerator.mjs +13 -44
- package/src/data/Model.mjs +2 -0
- package/src/data/Store.mjs +7 -0
- package/src/data/connection/WebSocket.mjs +2 -0
- package/src/date/DayViewComponent.mjs +2 -0
- package/src/date/SelectorContainer.mjs +14 -0
- package/src/dialog/Base.mjs +8 -0
- package/src/draggable/DragZone.mjs +5 -0
- package/src/draggable/tree/DragZone.mjs +1 -0
- package/src/filter/BooleanContainer.mjs +2 -0
- package/src/filter/NumberContainer.mjs +3 -0
- package/src/filter/ToggleOperatorsButton.mjs +2 -0
- package/src/form/Fieldset.mjs +6 -0
- package/src/form/field/Base.mjs +7 -0
- package/src/form/field/CheckBox.mjs +18 -0
- package/src/form/field/Chip.mjs +1 -0
- package/src/form/field/ComboBox.mjs +8 -0
- package/src/form/field/Country.mjs +1 -0
- package/src/form/field/Currency.mjs +2 -0
- package/src/form/field/Date.mjs +4 -0
- package/src/form/field/Display.mjs +1 -0
- package/src/form/field/Email.mjs +1 -0
- package/src/form/field/FileUpload.mjs +7 -0
- package/src/form/field/Hidden.mjs +1 -0
- package/src/form/field/Number.mjs +7 -0
- package/src/form/field/Password.mjs +1 -0
- package/src/form/field/Phone.mjs +3 -0
- package/src/form/field/Picker.mjs +2 -0
- package/src/form/field/Radio.mjs +1 -0
- package/src/form/field/Range.mjs +3 -0
- package/src/form/field/Search.mjs +2 -0
- package/src/form/field/Text.mjs +32 -0
- package/src/form/field/TextArea.mjs +7 -0
- package/src/form/field/Time.mjs +6 -0
- package/src/form/field/Url.mjs +3 -0
- package/src/form/field/ZipCode.mjs +2 -0
- package/src/form/field/trigger/Base.mjs +3 -0
- package/src/form/field/trigger/Clear.mjs +2 -0
- package/src/form/field/trigger/CopyToClipboard.mjs +2 -0
- package/src/form/field/trigger/Date.mjs +1 -0
- package/src/form/field/trigger/Picker.mjs +1 -0
- package/src/form/field/trigger/Search.mjs +1 -0
- package/src/form/field/trigger/SpinDown.mjs +2 -0
- package/src/form/field/trigger/SpinUp.mjs +1 -0
- package/src/form/field/trigger/Time.mjs +2 -0
- package/src/functional/_export.mjs +6 -0
- package/src/functional/component/Base.mjs +499 -0
- package/src/functional/defineComponent.mjs +102 -0
- package/src/functional/useConfig.mjs +52 -0
- package/src/functional/useEvent.mjs +43 -0
- package/src/grid/Body.mjs +20 -1
- package/src/grid/Container.mjs +50 -60
- package/src/grid/ScrollManager.mjs +2 -0
- package/src/grid/VerticalScrollbar.mjs +2 -0
- package/src/grid/column/Base.mjs +2 -0
- package/src/grid/header/Button.mjs +7 -0
- package/src/grid/header/Toolbar.mjs +6 -0
- package/src/grid/plugin/AnimateRows.mjs +2 -0
- package/src/layout/Base.mjs +3 -0
- package/src/layout/Card.mjs +1 -0
- package/src/layout/Cube.mjs +11 -1
- package/src/layout/Fit.mjs +1 -0
- package/src/layout/Flexbox.mjs +7 -0
- package/src/layout/Form.mjs +2 -0
- package/src/layout/Grid.mjs +1 -0
- package/src/layout/HBox.mjs +1 -0
- package/src/layout/VBox.mjs +1 -0
- package/src/list/Base.mjs +13 -0
- package/src/list/Chip.mjs +1 -0
- package/src/list/Circle.mjs +2 -0
- package/src/list/Color.mjs +1 -0
- package/src/list/plugin/Animate.mjs +2 -0
- package/src/main/DeltaUpdates.mjs +1 -0
- package/src/main/DomEvents.mjs +2 -0
- package/src/main/addon/CloneNode.mjs +1 -0
- package/src/main/addon/Cookie.mjs +1 -0
- package/src/main/addon/GoogleMaps.mjs +1 -0
- package/src/main/addon/LocalStorage.mjs +1 -0
- package/src/main/addon/MapboxGL.mjs +1 -0
- package/src/main/addon/Markdown.mjs +1 -0
- package/src/main/addon/Navigator.mjs +1 -0
- package/src/main/addon/Popover.mjs +1 -0
- package/src/main/addon/Stylesheet.mjs +1 -0
- package/src/main/addon/WindowPosition.mjs +1 -0
- package/src/manager/Component.mjs +0 -71
- package/src/manager/VDomUpdate.mjs +235 -0
- package/src/menu/List.mjs +6 -0
- package/src/menu/Model.mjs +1 -0
- package/src/menu/Panel.mjs +3 -0
- package/src/menu/Store.mjs +1 -0
- package/src/mixin/DomEvents.mjs +130 -0
- package/src/mixin/VdomLifecycle.mjs +667 -0
- package/src/plugin/Base.mjs +1 -0
- package/src/plugin/Resizable.mjs +2 -0
- package/src/selection/Model.mjs +15 -18
- package/src/selection/grid/BaseModel.mjs +1 -0
- package/src/sitemap/Component.mjs +1 -0
- package/src/state/Provider.mjs +98 -70
- package/src/state/createHierarchicalDataProxy.mjs +39 -25
- package/src/tab/Container.mjs +6 -0
- package/src/tab/Strip.mjs +1 -0
- package/src/tab/header/Button.mjs +2 -0
- package/src/tab/header/EffectButton.mjs +2 -0
- package/src/tab/header/Toolbar.mjs +1 -0
- package/src/table/Body.mjs +3 -0
- package/src/table/Container.mjs +10 -0
- package/src/table/header/Button.mjs +8 -0
- package/src/table/header/Toolbar.mjs +5 -0
- package/src/table/plugin/CellEditing.mjs +1 -0
- package/src/toolbar/Base.mjs +4 -0
- package/src/toolbar/Breadcrumb.mjs +3 -0
- package/src/toolbar/Paging.mjs +5 -0
- package/src/tooltip/Base.mjs +2 -0
- package/src/tree/List.mjs +3 -0
- package/src/util/HashHistory.mjs +1 -0
- package/src/util/KeyNavigation.mjs +2 -0
- package/src/util/Matrix.mjs +1 -0
- package/src/util/VDom.mjs +7 -1
- package/src/util/VNode.mjs +7 -1
- package/src/util/vdom/TreeBuilder.mjs +129 -0
- package/src/vdom/Helper.mjs +35 -23
- package/src/vdom/VNode.mjs +4 -6
- package/src/worker/App.mjs +1 -0
- package/src/worker/Base.mjs +2 -0
- package/src/worker/Manager.mjs +2 -0
- package/src/worker/ServiceBase.mjs +6 -1
- package/test/siesta/siesta.js +5 -2
- package/test/siesta/tests/VdomCalendar.mjs +13 -9
- package/test/siesta/tests/core/Effect.mjs +10 -14
- package/test/siesta/tests/core/EffectBatching.mjs +25 -37
- package/test/siesta/tests/state/ProviderNestedDataConfigs.mjs +255 -0
- package/test/siesta/tests/state/createHierarchicalDataProxy.mjs +42 -55
- package/test/siesta/tests/vdom/VdomAsymmetricUpdates.mjs +366 -0
- package/test/siesta/tests/vdom/VdomRealWorldUpdates.mjs +249 -0
- 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
|
/**
|
package/test/siesta/siesta.js
CHANGED
@@ -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(
|
10
|
-
const effect2 = new Effect(
|
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
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
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
|
-
|
87
|
-
|
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
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
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
|
-
|
113
|
-
|
114
|
-
|
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
|
-
|
163
|
-
|
164
|
-
|
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
|
-
|
221
|
-
|
222
|
-
|
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
|
-
|
230
|
-
|
231
|
-
|
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
|
-
|
297
|
-
|
298
|
-
|
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
|
+
});
|