neo.mjs 10.0.0-beta.4 → 10.0.0-beta.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/RELEASE_NOTES/v10.0.0-beta.4.md +2 -2
- 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/button/effect/MainContainer.mjs +207 -0
- package/examples/button/effect/app.mjs +6 -0
- package/examples/button/effect/index.html +11 -0
- package/examples/button/effect/neo-config.json +6 -0
- 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 +131 -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 +168 -0
- 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 -63
- 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 +377 -178
- package/src/Xhr.mjs +1 -0
- package/src/button/Base.mjs +13 -0
- package/src/button/Effect.mjs +449 -0
- 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 +14 -12
- package/src/collection/Filter.mjs +6 -0
- package/src/collection/Sorter.mjs +3 -0
- package/src/component/Base.mjs +156 -802
- 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 +34 -26
- 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 +193 -22
- package/src/core/Compare.mjs +4 -7
- package/src/core/Config.mjs +137 -33
- package/src/core/Effect.mjs +193 -0
- package/src/core/EffectBatchManager.mjs +67 -0
- package/src/core/EffectManager.mjs +60 -0
- 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 +57 -63
- 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/column/Component.mjs +1 -1
- 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 +376 -457
- package/src/state/createHierarchicalDataProxy.mjs +138 -0
- 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 +77 -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 +44 -33
- package/src/vdom/VNode.mjs +5 -7
- package/src/worker/App.mjs +1 -5
- 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 +36 -1
- package/test/siesta/tests/CollectionBase.mjs +10 -10
- package/test/siesta/tests/VdomCalendar.mjs +13 -9
- package/test/siesta/tests/VdomHelper.mjs +22 -59
- package/test/siesta/tests/config/AfterSetConfig.mjs +100 -0
- package/test/siesta/tests/{ReactiveConfigs.mjs → config/Basic.mjs} +58 -21
- package/test/siesta/tests/config/CircularDependencies.mjs +166 -0
- package/test/siesta/tests/config/CustomFunctions.mjs +69 -0
- package/test/siesta/tests/config/Hierarchy.mjs +94 -0
- package/test/siesta/tests/config/MemoryLeak.mjs +92 -0
- package/test/siesta/tests/config/MultiLevelHierarchy.mjs +85 -0
- package/test/siesta/tests/core/Effect.mjs +127 -0
- package/test/siesta/tests/core/EffectBatching.mjs +310 -0
- package/test/siesta/tests/neo/MixinStaticConfig.mjs +138 -0
- package/test/siesta/tests/state/Provider.mjs +537 -0
- package/test/siesta/tests/state/ProviderNestedDataConfigs.mjs +255 -0
- package/test/siesta/tests/state/createHierarchicalDataProxy.mjs +204 -0
- 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
@@ -0,0 +1,122 @@
|
|
1
|
+
# Epic: Optimized VDOM Update Strategies
|
2
|
+
|
3
|
+
This epic outlines a series of surgical enhancements to the framework's VDOM update lifecycle. The goal is to improve the robustness and maintainability of the update mechanism by centralizing complex state for all collision scenarios, without altering the existing high-performance, real-time messaging architecture.
|
4
|
+
|
5
|
+
## Core Problem: Distributed State
|
6
|
+
The current VDOM update logic is extremely fast, but the state management for aggregated updates is complex and distributed across component instances. This is true for two scenarios:
|
7
|
+
1. **Pre-Flight Merges:** Multiple updates are queued in the same event loop tick and merged before a worker message is sent.
|
8
|
+
2. **In-Flight Collisions:** A child requests an update while its parent's update is already in-flight to the worker.
|
9
|
+
|
10
|
+
In both cases, callbacks and post-update triggers are stored in scattered instance-level caches (`resolveUpdateCache`, `childUpdateCache`), making the lifecycle hard to debug and maintain.
|
11
|
+
|
12
|
+
## Solution: Centralized Orchestration Manager
|
13
|
+
|
14
|
+
We will introduce a new manager to act as a central orchestrator for all collision-related state. This approach preserves the existing high-performance update engine while drastically simplifying the `VdomLifecycle` mixin.
|
15
|
+
|
16
|
+
### 1. New Class: `Neo.manager.VDomUpdate` (Orchestrator)
|
17
|
+
- This new singleton manager will **not** schedule or delay updates.
|
18
|
+
- It will contain two maps to manage all collision scenarios:
|
19
|
+
- `mergedCallbackMap`: Stores callbacks and relevant update depth information for **pre-flight merges**.
|
20
|
+
- `postUpdateQueueMap`: Stores child components that need updating after an **in-flight collision**.
|
21
|
+
- It will expose methods to be called by the `VdomLifecycle` mixin:
|
22
|
+
- `registerMerged(ownerId, childId, callbacks, childUpdateDepth, distance)`: Stores the child's callbacks, its `updateDepth`, and its `distance` from the owner.
|
23
|
+
- `registerPostUpdate(ownerId, childId, resolve)`
|
24
|
+
- `executeCallbacks(ownerId)`: This method will also be responsible for calculating the maximum required `updateDepth` for the `ownerId` (parent) based on the `childUpdateDepth` and `distance` of all merged children. It will then set the `ownerId` component's `updateDepth` to this calculated maximum *before* the parent's `update()` method is called (if `needsVdomUpdate` is true).
|
25
|
+
- `triggerPostUpdates(ownerId)`
|
26
|
+
|
27
|
+
### 2. `VdomLifecycle.mjs` Refactoring
|
28
|
+
- The core, high-performance update logic (`updateVdom`, collision detection) will remain.
|
29
|
+
- **Pre-Flight Merge:** When an update is merged (e.g., in `mergeIntoParentUpdate()`), it will now call `Neo.manager.VDomUpdate.registerMerged(parent.id, me.id, me.resolveUpdateCache, me.updateDepth, distance)` instead of manipulating local caches.
|
30
|
+
- **In-Flight Collision:** When an update collides with an in-flight parent (in `isParentUpdating()`), it will call `Neo.manager.VDomUpdate.registerPostUpdate(...)`. The child component will still set its own `needsVdomUpdate = true` and hold its own callback in its `resolveUpdateCache` for the update it will eventually run.
|
31
|
+
- **On Update Completion:** When a root update cycle finishes, its `then()` block will call both `manager.executeCallbacks(this.id)` and `manager.triggerPostUpdates(this.id)`.
|
32
|
+
- This change allows for the complete removal of the complex `childUpdateCache` property and simplifies the logic around `resolveUpdateCache`.
|
33
|
+
|
34
|
+
### 3. Asymmetric VDOM Serialization (`ComponentManager.mjs`)
|
35
|
+
- This part of the plan remains crucial and unchanged.
|
36
|
+
- `getVdomTree()` and `getVnodeTree()` will be refactored to honor the `updateDepth` of each individual component.
|
37
|
+
- If a child component is excluded from an update, a lightweight placeholder object `{componentId: 'neo-ignore'}` will be inserted into the tree to preserve its structural integrity.
|
38
|
+
|
39
|
+
### 4. VDOM Worker Enhancement (`vdom/Helper.mjs`)
|
40
|
+
- The VDOM worker's `createDeltas()` method will be enhanced to recognize the `neo-ignore` placeholder. When it encounters this node, it will skip the diffing process, leaving the corresponding DOM element untouched.
|
41
|
+
|
42
|
+
### 5. Testing Strategy
|
43
|
+
Given the architectural significance of these changes, a comprehensive testing strategy is required. Since the test environment runs in a single thread (main), the strategy will be:
|
44
|
+
|
45
|
+
1. **Unit Test Environment Setup:**
|
46
|
+
- The test suite will import all necessary classes directly into the main thread: `vdom.Helper`, `manager.VDomUpdate`, and all relevant components and containers.
|
47
|
+
- Components will be instantiated in a non-rendering mode (`preventDOM: true` or a similar mechanism) to avoid any interaction with the actual DOM.
|
48
|
+
|
49
|
+
2. **Validation Points:**
|
50
|
+
- **Aggregation Logic:** Create complex scenarios with nested components triggering updates simultaneously to verify that the new `VDomUpdate` manager correctly handles both pre-flight and in-flight collisions.
|
51
|
+
- **Delta Correctness:** After a test update cycle, inspect the generated `deltas` array to ensure it is correct and that the `neo-ignore` placeholder is working as expected.
|
52
|
+
- **VNode Redistribution:** Verify that after an update, the new `vnode` is correctly passed down and synchronized to all relevant child components.
|
53
|
+
- **Callback Execution:** Ensure that all `resolve` callbacks from merged and queued updates are executed correctly and exactly once.
|
54
|
+
|
55
|
+
3. **Benchmarking:**
|
56
|
+
- A dedicated feature branch will be used for this epic.
|
57
|
+
- Create a suite of performance tests that simulate high-frequency updates on complex component trees.
|
58
|
+
- Run these benchmarks on both the `main` branch (old implementation) and the feature branch (new implementation) to rigorously compare performance and ensure there are no regressions.
|
59
|
+
|
60
|
+
This final, refined approach provides the best of all worlds: it fixes the code complexity and maintainability issues by centralizing all collision-related state, while fully preserving the framework's proven, real-time performance characteristics.
|
61
|
+
|
62
|
+
## Implementation Progress
|
63
|
+
|
64
|
+
**Status:** Foundational work complete. Documentation and a regression test suite are in place, and key framework APIs have been enhanced.
|
65
|
+
|
66
|
+
### 1. Documentation & Test Suite
|
67
|
+
|
68
|
+
Two crucial files have been created to guide and validate this epic:
|
69
|
+
|
70
|
+
- **Epic Ticket (`.github/ticket-asymmetric-vdom-updates.md`):** This central document outlines the problem, defines the solution, and tracks our progress.
|
71
|
+
- **`VdomAsymmetricUpdates.mjs`:** A low-level unit test that directly validates the core logic of the new `VDomUpdate` manager and `TreeBuilder`. It simulates asymmetric updates with mock components to ensure the delta generation is correct.
|
72
|
+
- **`VdomRealWorldUpdates.mjs`:** A high-level integration test using real components to create a regression suite. It verifies that the framework's *existing* ability to merge updates from multiple component levels into a single, efficient cycle remains intact.
|
73
|
+
|
74
|
+
Key achievements of these tests:
|
75
|
+
- **Validates Current Logic:** It successfully tests the *existing* logic where updates from multiple component levels (e.g., a parent and a grandchild) within the same event loop tick are correctly merged into a single, efficient VDOM update cycle.
|
76
|
+
- **Pure VDOM Testing:** The test runs without a real DOM. It creates component instances, generates their initial `vnode` structure, and then programmatically triggers updates.
|
77
|
+
- **Asserts on Deltas:** Instead of inspecting the DOM, the test awaits the `promiseUpdate()` method (which was enhanced to resolve with the update data) and directly inspects the raw `deltas` array. This provides a precise and reliable way to verify that the update-merging logic is working as expected.
|
78
|
+
|
79
|
+
This test now serves as a critical regression suite, ensuring that the planned refactoring of the update mechanism will not alter this core, high-performance behavior.
|
80
|
+
|
81
|
+
### 2. Framework API Enhancements
|
82
|
+
|
83
|
+
The process of building the test suite revealed opportunities to improve the core framework. The following enhancements have been implemented:
|
84
|
+
|
85
|
+
- **`Component.mountedPromise`:** A new, robust `mountedPromise` getter has been added to `component.Base`. This provides a clean, reusable, promise-based API for awaiting a component's mounted state. The implementation is resilient to the framework's full lifecycle, correctly handling unmounting and remounting, making it a valuable tool for both testing and application-level code.
|
86
|
+
- **`VdomLifecycle.promiseUpdate()` Enhancement:** The `promiseUpdate()` method was refactored to resolve with the full data object from `vdom.Helper.update()`, giving developers and tests access to the generated `deltas` and the new `vnode`.
|
87
|
+
- **Environment Robustness:** Several fixes were made to the `VdomLifecycle` mixin to ensure it works reliably in both multi-threaded (worker) and single-threaded (test) environments, particularly around `vdom.Helper` calls and `Neo.currentWorker` access.
|
88
|
+
|
89
|
+
- **`VdomLifecycle.promiseUpdate()` Enhancement:** The `promiseUpdate()` method was refactored to resolve with the full data object from `vdom.Helper.update()`, giving developers and tests access to the generated `deltas` and the new `vnode`.
|
90
|
+
- **Environment Robustness:** Several fixes were made to the `VdomLifecycle` mixin to ensure it works reliably in both multi-threaded (worker) and single-threaded (test) environments, particularly around `vdom.Helper` calls and `Neo.currentWorker` access.
|
91
|
+
|
92
|
+
## Comparison with `dev` Branch (based on PR #7077)
|
93
|
+
|
94
|
+
This feature branch represents a major architectural enhancement to the VDOM update lifecycle. Here is a summary of the key changes compared to the `dev` branch:
|
95
|
+
|
96
|
+
- **New Update Orchestration Core:**
|
97
|
+
- `manager.VDomUpdate`: A new singleton manager has been introduced to centralize the state for both pre-flight update merges and in-flight update collisions.
|
98
|
+
- `util.vdom.TreeBuilder`: A new utility class for recursively building VDOM and VNode trees. It is the engine behind creating the *asymmetric* trees needed for optimized updates, correctly expanding component references based on a calculated `updateDepth`.
|
99
|
+
|
100
|
+
- **Core Framework Refactoring:**
|
101
|
+
- `mixin/VdomLifecycle.mjs`: This critical mixin has been significantly refactored. The complex, distributed state management (`childUpdateCache`) has been removed, and it now delegates all collision and merge logic to the new `VDomUpdate` manager.
|
102
|
+
The `executeVdomUpdate()` method has been modernized to use `async/await`, making the control flow more robust and readable, and ensuring deltas are correctly applied in non-worker environments.
|
103
|
+
- `vdom/Helper.mjs`: The diffing engine has been enhanced to support the new asymmetric update strategy.
|
104
|
+
- `component/Base.mjs`: The base component has been improved with a robust `mountedPromise` for easier async handling and other lifecycle enhancements to support the new update model.
|
105
|
+
- `manager/Component.mjs`: Has undergone significant refactoring to align with the new VDOM strategies.
|
106
|
+
- `functional/component/Base.mjs`: The base for functional components has been updated to align with the lifecycle changes in `component.Base`.
|
107
|
+
|
108
|
+
- **New Testing Infrastructure:**
|
109
|
+
- `test/siesta/tests/vdom/VdomAsymmetricUpdates.mjs`: A new low-level test suite that directly validates the logic of `VDomUpdate` and `TreeBuilder` using mock components.
|
110
|
+
- `test/siesta/tests/vdom/VdomRealWorldUpdates.mjs`: A new high-level integration test suite using real, nested components to serve as a regression test.
|
111
|
+
- `src/DefaultConfig.mjs`: The new `allowVdomUpdatesInTests: true` flag has been added to facilitate running VDOM-related tests in a unit test environment.
|
112
|
+
- `test/siesta/siesta.js`: The test runner has been updated to include these new test suites.
|
113
|
+
|
114
|
+
### Remaining Work to Complete the Epic (as of this PR)
|
115
|
+
|
116
|
+
While the core architectural shift is complete, the following tasks remain to finalize the epic:
|
117
|
+
|
118
|
+
- **Finalize Cleanup:**
|
119
|
+
- The `childUpdateCache` property inside `src/component/Base.mjs` is now obsolete. It can be safely removed, as `VDomUpdate` has taken over its responsibilities.
|
120
|
+
- The `updateVdom()` method in `VdomLifecycle.mjs` still uses a `timeout` to handle updates on unmounted components. This can be refactored to use the new `mountedPromise`, creating a cleaner and more robust implementation.
|
121
|
+
- **Complete Asymmetric Logic:** The `TreeBuilder` and `vdom.Helper` still need the final logic to handle the `neo-ignore` placeholder. This will enable truly asymmetric updates where non-participating component sub-trees are completely skipped during the diffing process.
|
122
|
+
- **Performance Benchmarking:** Conduct rigorous performance tests to compare this branch against `dev` and ensure no regressions.
|
package/README.md
CHANGED
@@ -84,9 +84,6 @@ That’s Neo.mjs in action — solving problems others can’t touch.
|
|
84
84
|
* **Persistent Component Instances**: Components maintain their state and logic even when their DOM is removed or moved.
|
85
85
|
No more wasteful re-creations – just surgical, efficient updates.
|
86
86
|
|
87
|
-
* **Reactive State Management**: Built-in reactivity ensures dynamic, efficient updates between components and state providers,
|
88
|
-
all handled off the main thread.
|
89
|
-
|
90
87
|
* **Reactive State Management**: Leveraging `Neo.state.Provider`, Neo.mjs offers natively integrated, hierarchical state management.
|
91
88
|
Components declare their data needs via a concise `bind` config. These `bind` functions act as powerful inline formulas, allowing
|
92
89
|
Components to automatically react to changes and combine data from multiple state providers within the component hierarchy.
|
package/ServiceWorker.mjs
CHANGED
@@ -13,10 +13,12 @@ class GridContainer extends BaseGridContainer {
|
|
13
13
|
className: 'Colors.view.GridContainer',
|
14
14
|
/**
|
15
15
|
* @member {Number|null} amountColumns_=null
|
16
|
+
* @reactive
|
16
17
|
*/
|
17
18
|
amountColumns_: null,
|
18
19
|
/**
|
19
20
|
* @member {Number|null} amountRows_=null
|
21
|
+
* @reactive
|
20
22
|
*/
|
21
23
|
amountRows_: null,
|
22
24
|
/**
|
@@ -29,6 +31,7 @@ class GridContainer extends BaseGridContainer {
|
|
29
31
|
},
|
30
32
|
/**
|
31
33
|
* @member {String[]} cls=['colors-grid-container']
|
34
|
+
* @reactive
|
32
35
|
*/
|
33
36
|
cls: ['colors-grid-container']
|
34
37
|
}
|
@@ -16,10 +16,12 @@ class HeaderToolbar extends Toolbar {
|
|
16
16
|
className: 'Colors.view.HeaderToolbar',
|
17
17
|
/**
|
18
18
|
* @member {String[]} cls=['colors-header-toolbar']
|
19
|
+
* @reactive
|
19
20
|
*/
|
20
21
|
cls: ['colors-header-toolbar'],
|
21
22
|
/**
|
22
23
|
* @member {Object} layout={ntype:'hbox',align:'stretch',wrap:'wrap'}
|
24
|
+
* @reactive
|
23
25
|
*/
|
24
26
|
layout: {ntype: 'hbox', align: 'center', pack: 'start', wrap: 'wrap'},
|
25
27
|
/**
|
@@ -19,10 +19,12 @@ class Viewport extends BaseViewport {
|
|
19
19
|
className: 'Colors.view.Viewport',
|
20
20
|
/**
|
21
21
|
* @member {String[]} cls=['colors-viewport']
|
22
|
+
* @reactive
|
22
23
|
*/
|
23
24
|
cls: ['colors-viewport'],
|
24
25
|
/**
|
25
26
|
* @member {Neo.controller.Component} controller=ViewportController
|
27
|
+
* @reactive
|
26
28
|
*/
|
27
29
|
controller: ViewportController,
|
28
30
|
/**
|
@@ -49,6 +51,7 @@ class Viewport extends BaseViewport {
|
|
49
51
|
}],
|
50
52
|
/**
|
51
53
|
* @member {Neo.state.Provider} stateProvider=ViewportStateProvider
|
54
|
+
* @reactive
|
52
55
|
*/
|
53
56
|
stateProvider: ViewportStateProvider
|
54
57
|
}
|
@@ -13,14 +13,17 @@ class FooterContainer extends Container {
|
|
13
13
|
className: 'Covid.view.FooterContainer',
|
14
14
|
/**
|
15
15
|
* @member {Number} height=20
|
16
|
+
* @reactive
|
16
17
|
*/
|
17
18
|
height: 25,
|
18
19
|
/**
|
19
20
|
* @member {Object} layout={ntype: 'hbox'}
|
21
|
+
* @reactive
|
20
22
|
*/
|
21
23
|
layout: {ntype: 'hbox'},
|
22
24
|
/**
|
23
25
|
* @member {String} reference='footer'
|
26
|
+
* @reactive
|
24
27
|
*/
|
25
28
|
reference: 'footer',
|
26
29
|
/**
|
@@ -22,6 +22,7 @@ class GalleryContainer extends Container {
|
|
22
22
|
baseCls: ['neo-gallery-maincontainer', 'neo-viewport'],
|
23
23
|
/**
|
24
24
|
* @member {Neo.controller.Component|null} controller=GalleryContainerController
|
25
|
+
* @reactive
|
25
26
|
*/
|
26
27
|
controller: GalleryContainerController,
|
27
28
|
/**
|
@@ -34,6 +35,7 @@ class GalleryContainer extends Container {
|
|
34
35
|
galleryConfig: null,
|
35
36
|
/**
|
36
37
|
* @member {Object|null} layout={ntype: 'hbox', align: 'stretch'}
|
38
|
+
* @reactive
|
37
39
|
*/
|
38
40
|
layout: {ntype: 'hbox', align: 'stretch'},
|
39
41
|
/**
|
@@ -19,10 +19,12 @@ class HeaderContainer extends Container {
|
|
19
19
|
baseCls: ['covid-header-container'],
|
20
20
|
/**
|
21
21
|
* @member {Number} height=70
|
22
|
+
* @reactive
|
22
23
|
*/
|
23
24
|
height: 120,
|
24
25
|
/**
|
25
26
|
* @member {Object} layout={ntype: 'hbox', align: 'stretch'}
|
27
|
+
* @reactive
|
26
28
|
*/
|
27
29
|
layout: {ntype: 'hbox', align: 'stretch'},
|
28
30
|
/**
|
@@ -22,6 +22,7 @@ class HelixContainer extends Container {
|
|
22
22
|
baseCls: ['neo-helix-maincontainer', 'neo-viewport'],
|
23
23
|
/**
|
24
24
|
* @member {Neo.controller.Component|null} controller=HelixContainerController
|
25
|
+
* @reactive
|
25
26
|
*/
|
26
27
|
controller: HelixContainerController,
|
27
28
|
/**
|
@@ -34,6 +35,7 @@ class HelixContainer extends Container {
|
|
34
35
|
helixConfig: null,
|
35
36
|
/**
|
36
37
|
* @member {Object|null} layout={ntype: 'hbox', align: 'stretch'}
|
38
|
+
* @reactive
|
37
39
|
*/
|
38
40
|
layout: {ntype: 'hbox', align: 'stretch'},
|
39
41
|
/**
|
@@ -22,6 +22,7 @@ class MainContainer extends Viewport {
|
|
22
22
|
baseCls: ['covid-viewport', 'neo-viewport'],
|
23
23
|
/**
|
24
24
|
* @member {Neo.controller.Component} controller=MainContainerController
|
25
|
+
* @reactive
|
25
26
|
*/
|
26
27
|
controller: MainContainerController,
|
27
28
|
/**
|
@@ -83,10 +84,12 @@ class MainContainer extends Viewport {
|
|
83
84
|
}, FooterContainer],
|
84
85
|
/**
|
85
86
|
* @member {Object} layout={ntype: 'vbox', align: 'stretch'}
|
87
|
+
* @reactive
|
86
88
|
*/
|
87
89
|
layout: {ntype: 'vbox', align: 'stretch'},
|
88
90
|
/**
|
89
91
|
* @member {Neo.state.Provider} stateProvider=MainContainerStateProvider
|
92
|
+
* @reactive
|
90
93
|
*/
|
91
94
|
stateProvider: MainContainerStateProvider
|
92
95
|
}
|
@@ -27,10 +27,12 @@ class TableContainer extends Container {
|
|
27
27
|
},
|
28
28
|
/**
|
29
29
|
* @member {Neo.controller.Component|null} controller=TableContainerController
|
30
|
+
* @reactive
|
30
31
|
*/
|
31
32
|
controller: TableContainerController,
|
32
33
|
/**
|
33
34
|
* @member {Object} countryRecord_=null
|
35
|
+
* @reactive
|
34
36
|
*/
|
35
37
|
countryRecord_: null,
|
36
38
|
/**
|
@@ -48,6 +50,7 @@ class TableContainer extends Container {
|
|
48
50
|
tableConfig: null,
|
49
51
|
/**
|
50
52
|
* @member {Object|null} layout={ntype: 'hbox', align: 'stretch'}
|
53
|
+
* @reactive
|
51
54
|
*/
|
52
55
|
layout: {ntype: 'hbox', align: 'stretch'},
|
53
56
|
/**
|
@@ -17,10 +17,12 @@ class WorldMapContainer extends Container {
|
|
17
17
|
className: 'Covid.view.WorldMapContainer',
|
18
18
|
/**
|
19
19
|
* @member {Neo.controller.Component} controller=WorldMapContainerController
|
20
|
+
* @reactive
|
20
21
|
*/
|
21
22
|
controller: WorldMapContainerController,
|
22
23
|
/**
|
23
24
|
* @member {Object} layout={ntype: 'vbox', align: 'stretch'}
|
25
|
+
* @reactive
|
24
26
|
*/
|
25
27
|
layout: {ntype: 'vbox', align: 'stretch'},
|
26
28
|
/**
|
@@ -25,6 +25,7 @@ class CountryGallery extends Gallery {
|
|
25
25
|
},
|
26
26
|
/**
|
27
27
|
* @member {String|null} country_=null
|
28
|
+
* @reactive
|
28
29
|
*/
|
29
30
|
country_: null,
|
30
31
|
/**
|
@@ -34,6 +35,7 @@ class CountryGallery extends Gallery {
|
|
34
35
|
itemHeight: 280,
|
35
36
|
/**
|
36
37
|
* @member {Object} itemTpl_
|
38
|
+
* @reactive
|
37
39
|
*/
|
38
40
|
itemTpl:
|
39
41
|
{cls: ['neo-gallery-item', 'image-wrap', 'view', 'neo-transition-1000'], tabIndex: '-1', cn: [
|
@@ -86,6 +88,7 @@ class CountryGallery extends Gallery {
|
|
86
88
|
selectOnMount: false,
|
87
89
|
/**
|
88
90
|
* @member {Neo.data.Store} store=CountryStore
|
91
|
+
* @reactive
|
89
92
|
*/
|
90
93
|
store: CountryStore
|
91
94
|
}
|
@@ -25,15 +25,18 @@ class CountryHelix extends Helix {
|
|
25
25
|
},
|
26
26
|
/**
|
27
27
|
* @member {String|null} country_=null
|
28
|
+
* @reactive
|
28
29
|
*/
|
29
30
|
country_: null,
|
30
31
|
/**
|
31
32
|
* The vertical delta between each helix item (increasing this value will create a spiral)
|
32
33
|
* @member {Number} deltaY=1.2
|
34
|
+
* @reactive
|
33
35
|
*/
|
34
36
|
deltaY: 1.2,
|
35
37
|
/**
|
36
38
|
* @member {Object} itemTpl_
|
39
|
+
* @reactive
|
37
40
|
*/
|
38
41
|
itemTpl:
|
39
42
|
{cls: ['surface', 'neo-helix-item'], style: {}, tabIndex: '-1', cn: [
|
@@ -77,11 +80,13 @@ class CountryHelix extends Helix {
|
|
77
80
|
/**
|
78
81
|
* The radius of the Helix in px
|
79
82
|
* @member {Number} radius=2500
|
83
|
+
* @reactive
|
80
84
|
*/
|
81
85
|
radius: 2500,
|
82
86
|
/**
|
83
87
|
* The rotationAngle of the Helix in degrees
|
84
88
|
* @member {Number} rotationAngle=720
|
89
|
+
* @reactive
|
85
90
|
*/
|
86
91
|
rotationAngle: 720,
|
87
92
|
/**
|
@@ -91,16 +96,19 @@ class CountryHelix extends Helix {
|
|
91
96
|
showCloneInfo: false,
|
92
97
|
/**
|
93
98
|
* @member {Neo.data.Store} store=CountryStore
|
99
|
+
* @reactive
|
94
100
|
*/
|
95
101
|
store: CountryStore,
|
96
102
|
/**
|
97
103
|
* The translateX value gets included into each helix item
|
98
104
|
* @member {Number} translateY=500
|
105
|
+
* @reactive
|
99
106
|
*/
|
100
107
|
translateY: 500,
|
101
108
|
/**
|
102
109
|
* The translateX value gets included into each helix item
|
103
110
|
* @member {Number} translateZ_=-2300
|
111
|
+
* @reactive
|
104
112
|
*/
|
105
113
|
translateZ: -2300
|
106
114
|
}
|
@@ -104,10 +104,12 @@ class Table extends Container {
|
|
104
104
|
}],
|
105
105
|
/**
|
106
106
|
* @member {String|null} country_=null
|
107
|
+
* @reactive
|
107
108
|
*/
|
108
109
|
country_: null,
|
109
110
|
/**
|
110
111
|
* @member {Neo.data.Store} store=CountryStore
|
112
|
+
* @reactive
|
111
113
|
*/
|
112
114
|
store: CountryStore
|
113
115
|
}
|
@@ -22,6 +22,7 @@ class Container extends BaseContainer {
|
|
22
22
|
ntype: 'covid-mapboxgl-container',
|
23
23
|
/**
|
24
24
|
* @member {Neo.controller.Component} controller=ContainerController
|
25
|
+
* @reactive
|
25
26
|
*/
|
26
27
|
controller: ContainerController,
|
27
28
|
/**
|
@@ -88,6 +89,7 @@ class Container extends BaseContainer {
|
|
88
89
|
}],
|
89
90
|
/**
|
90
91
|
* @member {Object} layout={ntype: 'fit'}
|
92
|
+
* @reactive
|
91
93
|
*/
|
92
94
|
layout: {ntype: 'fit'},
|
93
95
|
|
@@ -0,0 +1,58 @@
|
|
1
|
+
# EPIC: Refactor and Enhance the Email App
|
2
|
+
|
3
|
+
This document outlines the plan for refactoring the `apps/email` application into a showcase for the Neo.mjs functional component architecture and multi-window capabilities.
|
4
|
+
|
5
|
+
## Architectural Milestones & Key Learnings
|
6
|
+
|
7
|
+
This epic has driven significant architectural improvements to the functional component system. For a full understanding of the current state, review this ticket:
|
8
|
+
|
9
|
+
- **[#ticket-functional-recursive-config-diffing.md](/.github/ticket-functional-recursive-config-diffing.md):** A plan for a future enhancement to make the diffing logic recursive, allowing for deep, declarative control over nested component configurations.
|
10
|
+
|
11
|
+
---
|
12
|
+
|
13
|
+
## Phase 1: Foundation and Basic Layout (Completed)
|
14
|
+
|
15
|
+
**Goal:** Implement the main 3-pane layout as a functional `MainView` component and set it as the content of the existing classic `Viewport`.
|
16
|
+
|
17
|
+
**Learnings & Decisions:**
|
18
|
+
- **Interoperability:** Kept the classic `Viewport` and embedded the new functional `MainView` component, showcasing seamless integration.
|
19
|
+
- **Naming:** Renamed `Main.mjs` to `MainView.mjs` for clarity.
|
20
|
+
|
21
|
+
---
|
22
|
+
|
23
|
+
## Phase 2: Email List View (Completed)
|
24
|
+
|
25
|
+
**Goal:** Implement the email list pane using a `Neo.grid.Container`.
|
26
|
+
|
27
|
+
**Learnings & Decisions:**
|
28
|
+
- **Complex Component Integration:** Discovered that complex classic components require specific configs (e.g., `wrapperStyle`) to manage their own layout when nested inside functional components.
|
29
|
+
- **Stateful Child Problem:** Uncovered the core issue of stateful children (stores, columns) being re-created on every parent render. This led directly to the architectural work on VDOM diffing.
|
30
|
+
|
31
|
+
---
|
32
|
+
|
33
|
+
## Phase 3: Email Detail View (Completed)
|
34
|
+
|
35
|
+
**Goal:** Display the content of a selected email from the grid.
|
36
|
+
- Implemented a `selection.RowModel` on the grid and used a `useConfig` state variable (`selectedEmail`) to drive a conditional render of the detail pane.
|
37
|
+
|
38
|
+
---
|
39
|
+
|
40
|
+
## Phase 4: Compose Email Functionality (Next)
|
41
|
+
|
42
|
+
**Goal:** Implement the ability to compose a new email, initially within the main window.
|
43
|
+
|
44
|
+
**Proposed Plan:**
|
45
|
+
1. **Compose Button:** Add a `Neo.button.Base` to the "Folders" pane.
|
46
|
+
2. **State Management:** Use `useConfig` in `MainView` to manage an `isComposing` boolean state.
|
47
|
+
3. **Compose View:** Create a new functional component, `view/ComposeView.mjs`, containing the form for the new email.
|
48
|
+
4. **Conditional Rendering:** Use the `isComposing` flag to conditionally render the `ComposeView` as an overlay on top of the main view.
|
49
|
+
5. **Event Handling:** The "Compose" button will set `isComposing` to `true`. The `ComposeView` will have a "Close" button that sets it back to `false`.
|
50
|
+
6. **Overlay Implementation:** We will build a custom functional overlay for this, as it's a good exercise and provides maximum flexibility.
|
51
|
+
|
52
|
+
---
|
53
|
+
|
54
|
+
## Phase 5: Multi-Window Detach
|
55
|
+
|
56
|
+
**Goal:** Implement the "detach" functionality to move the compose view into a separate browser window.
|
57
|
+
**Sub-Tasks:** *(To be defined)*
|
58
|
+
|
@@ -15,7 +15,17 @@ class Emails extends Store {
|
|
15
15
|
/**
|
16
16
|
* @member {Neo.data.Model} model=Email
|
17
17
|
*/
|
18
|
-
model: EmailModel
|
18
|
+
model: EmailModel,
|
19
|
+
/**
|
20
|
+
* @member {Object[]} data
|
21
|
+
*/
|
22
|
+
data: [
|
23
|
+
{id: 1, sender: 'John Doe', title: 'Hello World!', content: 'This is the first email.', dateSent: '2025-07-15T10:00:00Z'},
|
24
|
+
{id: 2, sender: 'Jane Smith', title: 'Re: Project Update', content: 'Here is the project update you requested.', dateSent: '2025-07-15T11:30:00Z'},
|
25
|
+
{id: 3, sender: 'Peter Jones', title: 'Lunch tomorrow?', content: 'Are we still on for lunch tomorrow at 12:30?', dateSent: '2025-07-15T12:15:00Z'},
|
26
|
+
{id: 4, sender: 'Mary Williams', title: 'Your order has shipped', content: 'Your order #12345 has shipped and will arrive in 3-5 business days.', dateSent: '2025-07-14T15:45:00Z'},
|
27
|
+
{id: 5, sender: 'David Brown', title: 'Quick question', content: 'I have a quick question about the new feature.', dateSent: '2025-07-14T09:20:00Z'}
|
28
|
+
]
|
19
29
|
}
|
20
30
|
}
|
21
31
|
|
@@ -0,0 +1,44 @@
|
|
1
|
+
import Button from '../../../src/button/Base.mjs';
|
2
|
+
import TextField from '../../../src/form/field/Text.mjs';
|
3
|
+
import TextAreaField from '../../../src/form/field/TextArea.mjs';
|
4
|
+
import {defineComponent} from '../../../src/functional/_export.mjs';
|
5
|
+
|
6
|
+
export default defineComponent({
|
7
|
+
config: {
|
8
|
+
className: 'Email.view.ComposeView',
|
9
|
+
cls : ['email-compose-view']
|
10
|
+
},
|
11
|
+
createVdom({onClose}) {
|
12
|
+
const fieldStyle = {
|
13
|
+
marginBottom: '10px'
|
14
|
+
};
|
15
|
+
|
16
|
+
return {
|
17
|
+
cn: [{
|
18
|
+
module : TextField,
|
19
|
+
id : 'compose-to',
|
20
|
+
labelText : 'To:',
|
21
|
+
labelWidth: 80,
|
22
|
+
style : fieldStyle
|
23
|
+
}, {
|
24
|
+
module : TextField,
|
25
|
+
id : 'compose-subject',
|
26
|
+
labelText : 'Subject:',
|
27
|
+
labelWidth: 80,
|
28
|
+
style : fieldStyle
|
29
|
+
}, {
|
30
|
+
module : TextAreaField,
|
31
|
+
id : 'compose-body',
|
32
|
+
labelText: 'Body:',
|
33
|
+
height : 200,
|
34
|
+
style : fieldStyle
|
35
|
+
}, {
|
36
|
+
module : Button,
|
37
|
+
handler: onClose,
|
38
|
+
id : 'compose-close-button',
|
39
|
+
style : {alignSelf: 'flex-end'},
|
40
|
+
text : 'Close'
|
41
|
+
}]
|
42
|
+
}
|
43
|
+
}
|
44
|
+
});
|