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
@@ -0,0 +1,667 @@
|
|
1
|
+
import Base from '../core/Base.mjs';
|
2
|
+
import ComponentManager from '../manager/Component.mjs';
|
3
|
+
import NeoArray from '../util/Array.mjs';
|
4
|
+
import TreeBuilder from '../util/vdom/TreeBuilder.mjs';
|
5
|
+
import VDomUtil from '../util/VDom.mjs';
|
6
|
+
import VDomUpdate from '../manager/VDomUpdate.mjs';
|
7
|
+
import VNodeUtil from '../util/VNode.mjs';
|
8
|
+
import {isDescriptor} from '../core/ConfigSymbols.mjs';
|
9
|
+
|
10
|
+
const {currentWorker} = Neo;
|
11
|
+
|
12
|
+
/**
|
13
|
+
* @class Neo.mixin.VdomLifecycle
|
14
|
+
* @extends Neo.core.Base
|
15
|
+
*/
|
16
|
+
class VdomLifecycle extends Base {
|
17
|
+
static config = {
|
18
|
+
/**
|
19
|
+
* @member {String} className='Neo.mixin.VdomLifecycle'
|
20
|
+
* @protected
|
21
|
+
*/
|
22
|
+
className: 'Neo.mixin.VdomLifecycle',
|
23
|
+
/**
|
24
|
+
* True automatically mounts a component after being rendered.
|
25
|
+
* Use this for the top level component of your app.
|
26
|
+
* @member {Boolean} autoMount=false
|
27
|
+
* @tutorial 02_ClassSystem
|
28
|
+
*/
|
29
|
+
autoMount: false,
|
30
|
+
/**
|
31
|
+
* True automatically renders a component after being created inside the init call.
|
32
|
+
* Use this for the top level component of your app.
|
33
|
+
* @member {Boolean} autoRender=false
|
34
|
+
* @see {@link Neo.component.Base#init init}
|
35
|
+
* @tutorial 02_ClassSystem
|
36
|
+
*/
|
37
|
+
autoRender: false,
|
38
|
+
/**
|
39
|
+
* Internal flag for vdom changes after a component got unmounted
|
40
|
+
* (delta updates can no longer get applied & a new render call is required before re-mounting)
|
41
|
+
* @member {Boolean} hasUnmountedVdomChanges_=false
|
42
|
+
* @protected
|
43
|
+
* @reactive
|
44
|
+
*/
|
45
|
+
hasUnmountedVdomChanges_: false,
|
46
|
+
/**
|
47
|
+
* Internal flag which will get set to true while an update request (worker messages) is in progress
|
48
|
+
* @member {Boolean} isVdomUpdating_=false
|
49
|
+
* @protected
|
50
|
+
* @reactive
|
51
|
+
*/
|
52
|
+
isVdomUpdating_: false,
|
53
|
+
/**
|
54
|
+
* True in case the component is mounted to the DOM
|
55
|
+
* @member {Boolean} mounted_=false
|
56
|
+
* @protected
|
57
|
+
* @reactive
|
58
|
+
*/
|
59
|
+
mounted_: false,
|
60
|
+
/**
|
61
|
+
* Internal flag which will get set to true in case an update call arrives while another update is running
|
62
|
+
* @member {Boolean} needsVdomUpdate_=false
|
63
|
+
* @protected
|
64
|
+
* @reactive
|
65
|
+
*/
|
66
|
+
needsVdomUpdate_: false,
|
67
|
+
/**
|
68
|
+
* True in case the component is rendering the vnode
|
69
|
+
* @member {Boolean} rendering_=false
|
70
|
+
* @protected
|
71
|
+
* @reactive
|
72
|
+
*/
|
73
|
+
rendering_: false,
|
74
|
+
/**
|
75
|
+
* Set this to true for bulk updates. Ensure to set it back to false afterwards.
|
76
|
+
* Internally the value will get saved as a number to ensure that child methods won't stop the silent mode too early.
|
77
|
+
* @member {Boolean} silentVdomUpdate_=false
|
78
|
+
* @reactive
|
79
|
+
*/
|
80
|
+
silentVdomUpdate_: false,
|
81
|
+
/**
|
82
|
+
* Defines the depth of the vdom tree for the next update cycle.
|
83
|
+
* - The value 1 will only send the current vdom structure as it is
|
84
|
+
* - The value of 2 will include the vdom of direct children
|
85
|
+
* - The value of 3 will include the vdom of grandchildren
|
86
|
+
* - The value of -1 will include the full tree of any depth
|
87
|
+
* @member {Number} updateDepth_=1
|
88
|
+
* @reactive
|
89
|
+
*/
|
90
|
+
updateDepth_: 1,
|
91
|
+
/**
|
92
|
+
* The component vnode tree. Available after the component got rendered.
|
93
|
+
* @member {Object} vnode_=={[isDescriptor]: true, value: null, isEqual: (a, b) => a === b,}
|
94
|
+
* @protected
|
95
|
+
* @reactive
|
96
|
+
*/
|
97
|
+
vnode_: {
|
98
|
+
[isDescriptor]: true,
|
99
|
+
clone : 'none',
|
100
|
+
cloneOnGet : 'none',
|
101
|
+
isEqual : (a, b) => a === b, // vnode trees can be huge, and will get compared by the vdom worker.
|
102
|
+
value : null,
|
103
|
+
}
|
104
|
+
}
|
105
|
+
|
106
|
+
/**
|
107
|
+
* Triggered after the hasUnmountedVdomChanges config got changed
|
108
|
+
* @param {Boolean} value
|
109
|
+
* @param {Boolean} oldValue
|
110
|
+
* @protected
|
111
|
+
*/
|
112
|
+
afterSetHasUnmountedVdomChanges(value, oldValue) {
|
113
|
+
if (value || (!value && oldValue)) {
|
114
|
+
let parentIds = ComponentManager.getParentIds(this),
|
115
|
+
i = 0,
|
116
|
+
len = parentIds.length,
|
117
|
+
parent;
|
118
|
+
|
119
|
+
for (; i < len; i++) {
|
120
|
+
parent = Neo.getComponent(parentIds[i]);
|
121
|
+
|
122
|
+
if (parent) {
|
123
|
+
parent._hasUnmountedVdomChanges = value // silent update
|
124
|
+
}
|
125
|
+
}
|
126
|
+
}
|
127
|
+
}
|
128
|
+
|
129
|
+
/**
|
130
|
+
* Triggered after the vdom pseudo-config got changed
|
131
|
+
* @param {Object} value
|
132
|
+
* @param {Object|null} oldValue
|
133
|
+
* @protected
|
134
|
+
*/
|
135
|
+
afterSetVdom(value, oldValue) {
|
136
|
+
this.updateVdom()
|
137
|
+
}
|
138
|
+
|
139
|
+
/**
|
140
|
+
* Triggered after the vnode config got changed
|
141
|
+
* @param {Object} value
|
142
|
+
* @param {Object|null} oldValue
|
143
|
+
* @protected
|
144
|
+
*/
|
145
|
+
afterSetVnode(value, oldValue) {
|
146
|
+
oldValue !== undefined && this.syncVnodeTree()
|
147
|
+
}
|
148
|
+
|
149
|
+
/**
|
150
|
+
* Creates a lightweight, serializable placeholder for this component, intended for injection
|
151
|
+
* into the VDOM of other components.
|
152
|
+
*
|
153
|
+
* This is the **only recommended way** to nest a component within another component's VDOM tree.
|
154
|
+
* Directly embedding one component's full `vdom` object into another's is an anti-pattern
|
155
|
+
* that violates the principle of scoped VDOM, leading to unpredictable rendering behavior
|
156
|
+
* and making updates inefficient.
|
157
|
+
*
|
158
|
+
* At its core, the returned object contains a `componentId` that uniquely identifies the
|
159
|
+
* component instance. In cases where a component's structure is wrapped by another element
|
160
|
+
* (e.g., a Button in a Table Header being wrapped by a `<td>`), the reference will also
|
161
|
+
* include the wrapper's `id`. This happens when a component uses `getVdomRoot()` to
|
162
|
+
* designate a deeper node as its logical root, causing the component's `id` and its
|
163
|
+
* VDOM root's `id` to differ. The framework uses this dual-ID reference to correctly
|
164
|
+
* assemble the final VDOM tree.
|
165
|
+
*
|
166
|
+
* @returns {{componentId: String, id: String|undefined}} The VDOM reference object.
|
167
|
+
*/
|
168
|
+
createVdomReference() {
|
169
|
+
let me = this,
|
170
|
+
reference = {componentId: me.id},
|
171
|
+
vdomId = me.vdom.id;
|
172
|
+
|
173
|
+
if (vdomId && me.id !== vdomId) {
|
174
|
+
reference.id = vdomId
|
175
|
+
}
|
176
|
+
|
177
|
+
return reference
|
178
|
+
}
|
179
|
+
|
180
|
+
/**
|
181
|
+
* Internal method to send update requests to the vdom worker
|
182
|
+
* @param {function} [resolve] used by promiseUpdate()
|
183
|
+
* @param {function} [reject] used by promiseUpdate()
|
184
|
+
* @private
|
185
|
+
*/
|
186
|
+
async executeVdomUpdate(resolve, reject) {
|
187
|
+
let me = this;
|
188
|
+
|
189
|
+
resolve && VDomUpdate.addPromiseCallback(me.id, resolve);
|
190
|
+
|
191
|
+
me.isVdomUpdating = true;
|
192
|
+
// Centralize in-flight state
|
193
|
+
VDomUpdate.registerInFlightUpdate(me.id, me.updateDepth);
|
194
|
+
|
195
|
+
try {
|
196
|
+
const
|
197
|
+
{vdom, vnode} = me,
|
198
|
+
mergedChildIds = VDomUpdate.getMergedChildIds(me.id),
|
199
|
+
opts = {
|
200
|
+
vdom : TreeBuilder.getVdomTree(vdom, me.updateDepth, mergedChildIds),
|
201
|
+
vnode: TreeBuilder.getVnodeTree(vnode, me.updateDepth, mergedChildIds)
|
202
|
+
};
|
203
|
+
|
204
|
+
if (currentWorker?.isSharedWorker) {
|
205
|
+
opts.appName = me.appName;
|
206
|
+
opts.windowId = me.windowId;
|
207
|
+
}
|
208
|
+
|
209
|
+
// We cannot set the config directly => it could already be false,
|
210
|
+
// and we still want to pass it further into subtrees
|
211
|
+
me._needsVdomUpdate = false;
|
212
|
+
me.afterSetNeedsVdomUpdate?.(false, true);
|
213
|
+
|
214
|
+
// Reset the updateDepth to the default value for the next update cycle
|
215
|
+
me._updateDepth = me.constructor.config.updateDepth;
|
216
|
+
|
217
|
+
const data = await Promise.resolve(Neo.vdom.Helper.update(opts));
|
218
|
+
|
219
|
+
// Component could be destroyed while the update is running
|
220
|
+
if (me.id) {
|
221
|
+
// It is crucial to delegate the vnode tree before resolving the cycle
|
222
|
+
me.vnode = data.vnode;
|
223
|
+
|
224
|
+
// When not using a VdomWorker, we need to apply the deltas inside the App worker
|
225
|
+
if (!Neo.config.useVdomWorker && data.deltas?.length > 0) {
|
226
|
+
await Neo.applyDeltas(me.appName, data.deltas)
|
227
|
+
}
|
228
|
+
|
229
|
+
me.isVdomUpdating = false;
|
230
|
+
me.resolveVdomUpdate(data)
|
231
|
+
}
|
232
|
+
} catch (err) {
|
233
|
+
me.isVdomUpdating = false;
|
234
|
+
// Ensure state is cleaned up on error
|
235
|
+
VDomUpdate.unregisterInFlightUpdate(me.id);
|
236
|
+
reject?.(err)
|
237
|
+
}
|
238
|
+
}
|
239
|
+
|
240
|
+
/**
|
241
|
+
* Honors different item roots for mount / render OPs
|
242
|
+
* @returns {String}
|
243
|
+
*/
|
244
|
+
getMountedParentId() {
|
245
|
+
let parentId = this.parentId,
|
246
|
+
parent = Neo.getComponent(parentId),
|
247
|
+
itemsRoot = parent?.getVdomItemsRoot?.();
|
248
|
+
|
249
|
+
return itemsRoot ? itemsRoot.id : parentId
|
250
|
+
}
|
251
|
+
|
252
|
+
/**
|
253
|
+
* Calculate the real parentIndex inside the DOM
|
254
|
+
* @returns {Number|undefined}
|
255
|
+
*/
|
256
|
+
getMountedParentIndex() {
|
257
|
+
let parent = this.parent,
|
258
|
+
items = parent?.items || [],
|
259
|
+
i = 0,
|
260
|
+
index = 0,
|
261
|
+
len = items.length,
|
262
|
+
item;
|
263
|
+
|
264
|
+
for (; i < len; i++) {
|
265
|
+
item = items[i];
|
266
|
+
|
267
|
+
if (item === this) {
|
268
|
+
return index
|
269
|
+
}
|
270
|
+
|
271
|
+
if (!item.hidden && item.hideMode === 'removeDom') {
|
272
|
+
index++
|
273
|
+
}
|
274
|
+
}
|
275
|
+
}
|
276
|
+
|
277
|
+
/**
|
278
|
+
* Search a vdom child node by id for a given vdom tree
|
279
|
+
* @param {String} id
|
280
|
+
* @param {Object} vdom=this.vdom
|
281
|
+
* @returns {Object}
|
282
|
+
*/
|
283
|
+
getVdomChild(id, vdom=this.vdom) {
|
284
|
+
return VDomUtil.find(vdom, id)?.vdom
|
285
|
+
}
|
286
|
+
|
287
|
+
/**
|
288
|
+
* Specify a different vdom root if needed to apply the top level style attributes on a different level.
|
289
|
+
* Make sure to use getVnodeRoot() as well, to keep the vdom & vnode trees in sync.
|
290
|
+
* @returns {Object} The new vdom root
|
291
|
+
*/
|
292
|
+
getVdomRoot() {
|
293
|
+
return this.vdom
|
294
|
+
}
|
295
|
+
|
296
|
+
/**
|
297
|
+
* Specify a different vnode root if needed to apply the top level style attributes on a different level.
|
298
|
+
* Make sure to use getVdomRoot() as well, to keep the vdom & vnode trees in sync.
|
299
|
+
* @returns {Object} The new vnode root
|
300
|
+
*/
|
301
|
+
getVnodeRoot() {
|
302
|
+
return this.vnode
|
303
|
+
}
|
304
|
+
|
305
|
+
/**
|
306
|
+
* Checks if a given updateDepth & distance would result in an update collision
|
307
|
+
* @param {Number} updateDepth
|
308
|
+
* @param {Number} distance
|
309
|
+
* @returns {Boolean}
|
310
|
+
*/
|
311
|
+
hasUpdateCollision(updateDepth, distance) {
|
312
|
+
return updateDepth === -1 ? true : distance < updateDepth
|
313
|
+
}
|
314
|
+
|
315
|
+
/**
|
316
|
+
* Checks for vdom updates inside the parent chain and if found.
|
317
|
+
* Registers the component for a vdom update once done.
|
318
|
+
* @param {String} parentId=this.parentId
|
319
|
+
* @param {Function} [resolve] Gets passed by updateVdom()
|
320
|
+
* @param {Number} distance=1 Distance inside the component tree
|
321
|
+
* @returns {Boolean}
|
322
|
+
*/
|
323
|
+
isParentUpdating(parentId=this.parentId, resolve, distance=1) {
|
324
|
+
if (parentId !== 'document.body') {
|
325
|
+
let me = this,
|
326
|
+
parent = Neo.getComponent(parentId);
|
327
|
+
|
328
|
+
if (parent) {
|
329
|
+
if (parent.isVdomUpdating) {
|
330
|
+
// Get the in-flight update depth from the central manager
|
331
|
+
const parentUpdateDepth = VDomUpdate.getInFlightUpdateDepth(parent.id);
|
332
|
+
|
333
|
+
if (me.hasUpdateCollision(parentUpdateDepth, distance)) {
|
334
|
+
if (Neo.config.logVdomUpdateCollisions) {
|
335
|
+
console.warn('vdom parent update conflict with:', parent, 'for:', me)
|
336
|
+
}
|
337
|
+
|
338
|
+
VDomUpdate.registerPostUpdate(parent.id, me.id, resolve);
|
339
|
+
return true
|
340
|
+
}
|
341
|
+
|
342
|
+
// If an update is running and does not have a collision, we do not need to check further parents
|
343
|
+
return false
|
344
|
+
}
|
345
|
+
|
346
|
+
return me.isParentUpdating(parent.parentId, resolve, distance+1)
|
347
|
+
}
|
348
|
+
}
|
349
|
+
|
350
|
+
return false
|
351
|
+
}
|
352
|
+
|
353
|
+
/**
|
354
|
+
* Checks the needsVdomUpdate config inside the parent tree
|
355
|
+
* @param {String} parentId=this.parentId
|
356
|
+
* @param {Function} [resolve] gets passed by updateVdom()
|
357
|
+
* @param {Number} distance=1 Distance inside the component tree
|
358
|
+
* @returns {Boolean}
|
359
|
+
*/
|
360
|
+
mergeIntoParentUpdate(parentId=this.parentId, distance=1) {
|
361
|
+
if (parentId !== 'document.body') {
|
362
|
+
let me = this,
|
363
|
+
parent = Neo.getComponent(parentId);
|
364
|
+
|
365
|
+
if (parent) {
|
366
|
+
// We are checking for parent.updateDepth, since we care about the depth of the next update cycle
|
367
|
+
if (parent.needsVdomUpdate && me.hasUpdateCollision(parent.updateDepth, distance)) {
|
368
|
+
VDomUpdate.registerMerged(parent.id, me.id, me.updateDepth, distance);
|
369
|
+
return true
|
370
|
+
}
|
371
|
+
|
372
|
+
return me.mergeIntoParentUpdate(parent.parentId, distance+1)
|
373
|
+
}
|
374
|
+
}
|
375
|
+
|
376
|
+
return false
|
377
|
+
}
|
378
|
+
|
379
|
+
/**
|
380
|
+
* Gets called from the render() promise success handler
|
381
|
+
* @param {Object} vnode
|
382
|
+
* @param {Boolean} autoMount Mount the DOM after the vnode got created
|
383
|
+
* @protected
|
384
|
+
*/
|
385
|
+
onRender(vnode, autoMount) {
|
386
|
+
let me = this,
|
387
|
+
{app} = me;
|
388
|
+
|
389
|
+
me.rendering = false;
|
390
|
+
|
391
|
+
// if app is a check to see if the Component got destroyed while rendering => before onRender got triggered
|
392
|
+
if (app) {
|
393
|
+
if (!app.rendered) {
|
394
|
+
app.rendering = false;
|
395
|
+
app.rendered = true;
|
396
|
+
app.fire('render')
|
397
|
+
}
|
398
|
+
|
399
|
+
me.vnode = vnode;
|
400
|
+
|
401
|
+
let childIds = ComponentManager.getChildIds(vnode),
|
402
|
+
i = 0,
|
403
|
+
len = childIds.length,
|
404
|
+
child;
|
405
|
+
|
406
|
+
for (; i < len; i++) {
|
407
|
+
child = Neo.getComponent(childIds[i]);
|
408
|
+
|
409
|
+
if (child) {
|
410
|
+
child.rendered = true
|
411
|
+
}
|
412
|
+
}
|
413
|
+
|
414
|
+
me._rendered = true; // silent update
|
415
|
+
me.fire('rendered', me.id);
|
416
|
+
|
417
|
+
if (autoMount) {
|
418
|
+
me.mounted = true;
|
419
|
+
|
420
|
+
if (!app.mounted) {
|
421
|
+
app.mounted = true;
|
422
|
+
app.fire('mounted')
|
423
|
+
}
|
424
|
+
}
|
425
|
+
}
|
426
|
+
}
|
427
|
+
|
428
|
+
/**
|
429
|
+
* Promise based vdom update
|
430
|
+
* @returns {Promise<any>}
|
431
|
+
*/
|
432
|
+
promiseUpdate() {
|
433
|
+
return new Promise((resolve, reject) => {
|
434
|
+
this.updateVdom(resolve, reject)
|
435
|
+
})
|
436
|
+
}
|
437
|
+
|
438
|
+
/**
|
439
|
+
* Creates the vnode tree for this component and mounts the component in case
|
440
|
+
* - you pass true for the mount param
|
441
|
+
* - or the autoMount config is set to true
|
442
|
+
* @param {Boolean} [mount] Mount the DOM after the vnode got created
|
443
|
+
*/
|
444
|
+
async render(mount) {
|
445
|
+
let me = this,
|
446
|
+
autoMount = mount || me.autoMount,
|
447
|
+
{app} = me,
|
448
|
+
{allowVdomUpdatesInTests, unitTestMode, useVdomWorker} = Neo.config;
|
449
|
+
|
450
|
+
if (unitTestMode && !allowVdomUpdatesInTests) return;
|
451
|
+
|
452
|
+
// Verify that the critical rendering path => CSS files for the new tree is in place
|
453
|
+
if (!unitTestMode && autoMount && currentWorker.countLoadingThemeFiles !== 0) {
|
454
|
+
currentWorker.on('themeFilesLoaded', function() {
|
455
|
+
!me.mounted && me.render(mount)
|
456
|
+
}, me, {once: true});
|
457
|
+
|
458
|
+
return
|
459
|
+
}
|
460
|
+
|
461
|
+
me.rendering = true;
|
462
|
+
|
463
|
+
if (!app.rendered) {
|
464
|
+
app.rendering = true
|
465
|
+
}
|
466
|
+
|
467
|
+
if (me.vdom) {
|
468
|
+
me.isVdomUpdating = true;
|
469
|
+
|
470
|
+
delete me.vdom.removeDom;
|
471
|
+
|
472
|
+
me._needsVdomUpdate = false;
|
473
|
+
me.afterSetNeedsVdomUpdate?.(false, true);
|
474
|
+
|
475
|
+
const data = await Promise.resolve(Neo.vdom.Helper.create({
|
476
|
+
appName : me.appName,
|
477
|
+
autoMount,
|
478
|
+
parentId : autoMount ? me.getMountedParentId() : undefined,
|
479
|
+
parentIndex: autoMount ? me.getMountedParentIndex() : undefined,
|
480
|
+
vdom : TreeBuilder.getVdomTree(me.vdom, -1),
|
481
|
+
windowId : me.windowId
|
482
|
+
}));
|
483
|
+
|
484
|
+
me.onRender(data.vnode, useVdomWorker ? autoMount : false);
|
485
|
+
me.isVdomUpdating = false;
|
486
|
+
|
487
|
+
autoMount && !useVdomWorker && me.mount();
|
488
|
+
|
489
|
+
me.resolveVdomUpdate()
|
490
|
+
}
|
491
|
+
}
|
492
|
+
|
493
|
+
/**
|
494
|
+
* Internal helper fn to resolve the Promise for updateVdom()
|
495
|
+
* @param {Object} [data] The return value of vdom.Helper.update()
|
496
|
+
* @protected
|
497
|
+
*/
|
498
|
+
resolveVdomUpdate(data) {
|
499
|
+
let me = this;
|
500
|
+
|
501
|
+
// Execute callbacks for merged updates
|
502
|
+
VDomUpdate.executeCallbacks(me.id, data);
|
503
|
+
|
504
|
+
// The update is no longer in-flight
|
505
|
+
VDomUpdate.unregisterInFlightUpdate(me.id);
|
506
|
+
|
507
|
+
// Trigger updates for components that were in-flight
|
508
|
+
VDomUpdate.triggerPostUpdates(me.id);
|
509
|
+
|
510
|
+
if (me.needsVdomUpdate) {
|
511
|
+
// any new promise callbacks will get picked up by the next update cycle
|
512
|
+
me.update()
|
513
|
+
}
|
514
|
+
}
|
515
|
+
|
516
|
+
/**
|
517
|
+
* Placeholder method for util.VDom.syncVdomIds to allow overriding (disabling) it
|
518
|
+
* @param {Neo.vdom.VNode} [vnode=this.vnode]
|
519
|
+
* @param {Object} [vdom=this.vdom]
|
520
|
+
* @param {Boolean} force=false
|
521
|
+
*/
|
522
|
+
syncVdomIds(vnode=this.vnode, vdom=this.vdom, force=false) {
|
523
|
+
VDomUtil.syncVdomIds(vnode, vdom, force)
|
524
|
+
}
|
525
|
+
|
526
|
+
/**
|
527
|
+
* In case a component receives a new vnode, we want to do:
|
528
|
+
* - sync the vdom ids
|
529
|
+
* - setting rendered to true for child components
|
530
|
+
* - updating the parent component to ensure that the vnode tree stays persistent
|
531
|
+
* @param {Neo.vdom.VNode} [vnode=this.vnode]
|
532
|
+
*/
|
533
|
+
syncVnodeTree(vnode=this.vnode) {
|
534
|
+
let me = this,
|
535
|
+
childComponents = ComponentManager.getChildren(me),
|
536
|
+
debug = false,
|
537
|
+
map = {},
|
538
|
+
childVnode, start;
|
539
|
+
|
540
|
+
if (debug) {
|
541
|
+
start = performance.now()
|
542
|
+
}
|
543
|
+
|
544
|
+
me.syncVdomIds();
|
545
|
+
|
546
|
+
if (vnode && me.id !== vnode.id) {
|
547
|
+
ComponentManager.registerWrapperNode(vnode.id, me)
|
548
|
+
}
|
549
|
+
|
550
|
+
// we need one separate iteration first to ensure all wrapper nodes get registered
|
551
|
+
childComponents.forEach(component => {
|
552
|
+
childVnode = VNodeUtil.find(me.vnode, component.vdom.id)?.vnode;
|
553
|
+
|
554
|
+
if (childVnode) {
|
555
|
+
map[component.id] = childVnode;
|
556
|
+
|
557
|
+
if (component.id !== childVnode.id) {
|
558
|
+
ComponentManager.registerWrapperNode(childVnode.id, component)
|
559
|
+
}
|
560
|
+
}
|
561
|
+
});
|
562
|
+
|
563
|
+
// delegate the latest node updates to all possible child components found inside the vnode tree
|
564
|
+
childComponents.forEach(component => {
|
565
|
+
childVnode = map[component.id];
|
566
|
+
|
567
|
+
if (childVnode) {
|
568
|
+
// silent update
|
569
|
+
component._vnode = ComponentManager.addVnodeComponentReferences(childVnode, component.id);
|
570
|
+
|
571
|
+
if (!component.rendered) {
|
572
|
+
component._rendered = true;
|
573
|
+
component.fire('rendered', component.id)
|
574
|
+
}
|
575
|
+
|
576
|
+
component.mounted = true
|
577
|
+
} else {
|
578
|
+
console.warn('syncVnodeTree: Could not replace the child vnode for', component.id)
|
579
|
+
}
|
580
|
+
});
|
581
|
+
|
582
|
+
// silent update
|
583
|
+
me._vnode = vnode ? ComponentManager.addVnodeComponentReferences(vnode, me.id) : null;
|
584
|
+
|
585
|
+
debug && console.log('syncVnodeTree', me.id, performance.now() - start)
|
586
|
+
}
|
587
|
+
|
588
|
+
/**
|
589
|
+
*
|
590
|
+
*/
|
591
|
+
update() {
|
592
|
+
this.afterSetVdom(this.vdom, null)
|
593
|
+
}
|
594
|
+
|
595
|
+
/**
|
596
|
+
* Gets called after the vdom config gets changed in case the component is already mounted (delta updates).
|
597
|
+
* @param {function} [resolve] used by promiseUpdate()
|
598
|
+
* @param {function} [reject] used by promiseUpdate()
|
599
|
+
* @protected
|
600
|
+
*/
|
601
|
+
updateVdom(resolve, reject) {
|
602
|
+
if (!this.isConstructed) {
|
603
|
+
resolve?.();
|
604
|
+
return
|
605
|
+
}
|
606
|
+
|
607
|
+
if (Neo.config.unitTestMode && !Neo.config.allowVdomUpdatesInTests) {
|
608
|
+
reject?.();
|
609
|
+
return
|
610
|
+
}
|
611
|
+
|
612
|
+
let me = this,
|
613
|
+
{mounted, parentId, vnode} = me;
|
614
|
+
|
615
|
+
if (me.isVdomUpdating || me.silentVdomUpdate) {
|
616
|
+
resolve && VDomUpdate.addPromiseCallback(me.id, resolve);
|
617
|
+
me.needsVdomUpdate = true
|
618
|
+
} else {
|
619
|
+
// If there's a promise, register it against this component's ID immediately.
|
620
|
+
// The manager will ensure it's called when the appropriate update cycle completes.
|
621
|
+
resolve && VDomUpdate.addPromiseCallback(me.id, resolve);
|
622
|
+
|
623
|
+
// If an update is triggered on an unmounted component, we must wait for it to be mounted.
|
624
|
+
if (!mounted) {
|
625
|
+
// Use a flag to prevent setting up multiple `then` listeners for subsequent updates
|
626
|
+
// that might arrive before the component is mounted.
|
627
|
+
if (!me.isAwaitingMount) {
|
628
|
+
me.isAwaitingMount = true;
|
629
|
+
me.mountedPromise.then(() => {
|
630
|
+
me.isAwaitingMount = false;
|
631
|
+
// After mounting, re-trigger the update cycle. The cached callbacks will be picked up.
|
632
|
+
me.vnode && me.update();
|
633
|
+
});
|
634
|
+
}
|
635
|
+
} else {
|
636
|
+
if (
|
637
|
+
!me.mergeIntoParentUpdate(parentId)
|
638
|
+
&& !me.isParentUpdating(parentId, resolve)
|
639
|
+
&& mounted
|
640
|
+
&& vnode
|
641
|
+
) {
|
642
|
+
// Check for merged child updates and adjust the update depth accordingly
|
643
|
+
let adjustedDepth = VDomUpdate.getAdjustedUpdateDepth(me.id);
|
644
|
+
|
645
|
+
if (adjustedDepth !== null) {
|
646
|
+
me.updateDepth = adjustedDepth;
|
647
|
+
}
|
648
|
+
|
649
|
+
// Verify that the critical rendering path => CSS files for the new tree is in place
|
650
|
+
if (!Neo.config.unitTestMode && currentWorker.countLoadingThemeFiles !== 0) {
|
651
|
+
currentWorker.on('themeFilesLoaded', function() {
|
652
|
+
me.updateVdom(resolve, reject)
|
653
|
+
}, me, {once: true})
|
654
|
+
} else {
|
655
|
+
me.executeVdomUpdate(null, reject)
|
656
|
+
}
|
657
|
+
}
|
658
|
+
}
|
659
|
+
}
|
660
|
+
|
661
|
+
me.hasUnmountedVdomChanges = !mounted && me.hasBeenMounted
|
662
|
+
}
|
663
|
+
}
|
664
|
+
|
665
|
+
Neo.setupClass(VdomLifecycle);
|
666
|
+
|
667
|
+
export default VdomLifecycle;
|
package/src/plugin/Base.mjs
CHANGED
package/src/plugin/Resizable.mjs
CHANGED
@@ -49,6 +49,7 @@ class Resizable extends Plugin {
|
|
49
49
|
/**
|
50
50
|
* The name of the App this instance belongs to
|
51
51
|
* @member {String|null} appName_=null
|
52
|
+
* @reactive
|
52
53
|
*/
|
53
54
|
appName_: null,
|
54
55
|
/**
|
@@ -74,6 +75,7 @@ class Resizable extends Plugin {
|
|
74
75
|
/**
|
75
76
|
* Directions into which you want to drag => resize
|
76
77
|
* @member {String[]} directions_=['b','bl','br','l','r','t','tl','tr']
|
78
|
+
* @reactive
|
77
79
|
*/
|
78
80
|
directions_: ['b', 'bl', 'br', 'l', 'r', 't', 'tl', 'tr'],
|
79
81
|
/**
|