neo.mjs 10.0.0-beta.5 → 10.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/RELEASE_NOTES/v10.0.0-beta.1.md +20 -0
- package/.github/RELEASE_NOTES/v10.0.0-beta.2.md +73 -0
- package/.github/RELEASE_NOTES/v10.0.0-beta.3.md +39 -0
- 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/RELEASE_NOTES/v10.0.0.md +52 -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 +11 -3
- 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 +29 -19
- 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/button/base/MainContainer.mjs +207 -0
- package/examples/functional/button/base/app.mjs +6 -0
- package/examples/functional/button/base/index.html +11 -0
- package/examples/functional/button/base/neo-config.json +6 -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/blog/v10-deep-dive-functional-components.md +293 -0
- package/learn/blog/v10-deep-dive-reactivity.md +522 -0
- package/learn/blog/v10-deep-dive-state-provider.md +432 -0
- package/learn/blog/v10-deep-dive-vdom-revolution.md +194 -0
- package/learn/blog/v10-post1-love-story.md +383 -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 +28 -2
- 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 +8 -6
- 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 +219 -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/Abstract.mjs +412 -0
- package/src/component/Base.mjs +48 -1077
- 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 +86 -33
- package/src/core/Compare.mjs +4 -7
- package/src/core/Config.mjs +65 -52
- package/src/core/Effect.mjs +86 -24
- package/src/core/EffectManager.mjs +117 -8
- package/src/core/IdGenerator.mjs +13 -44
- package/src/core/Observable.mjs +69 -65
- 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 +43 -5
- 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/button/Base.mjs +384 -0
- package/src/functional/component/Base.mjs +405 -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 +18 -4
- 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 +320 -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 +670 -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 +129 -87
- 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 +18 -5
- package/src/util/VNode.mjs +7 -1
- package/src/util/vdom/TreeBuilder.mjs +105 -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/src/worker/mixin/RemoteMethodAccess.mjs +1 -6
- package/test/siesta/siesta.js +17 -2
- package/test/siesta/tests/VdomCalendar.mjs +19 -15
- package/test/siesta/tests/VdomHelper.mjs +7 -7
- package/test/siesta/tests/classic/Button.mjs +113 -0
- package/test/siesta/tests/core/Effect.mjs +10 -14
- package/test/siesta/tests/core/EffectBatching.mjs +72 -79
- package/test/siesta/tests/functional/Button.mjs +113 -0
- package/test/siesta/tests/state/ProviderNestedDataConfigs.mjs +314 -0
- package/test/siesta/tests/state/createHierarchicalDataProxy.mjs +42 -55
- package/test/siesta/tests/vdom/Advanced.mjs +14 -8
- package/test/siesta/tests/vdom/VdomAsymmetricUpdates.mjs +366 -0
- package/test/siesta/tests/vdom/VdomRealWorldUpdates.mjs +249 -0
- package/test/siesta/tests/vdom/layout/Cube.mjs +11 -7
- package/test/siesta/tests/vdom/table/Container.mjs +9 -5
- package/learn/javascript/NewNode.md +0 -31
- package/src/core/EffectBatchManager.mjs +0 -68
package/src/core/Config.mjs
CHANGED
@@ -14,13 +14,26 @@ import {isDescriptor} from './ConfigSymbols.mjs';
|
|
14
14
|
*/
|
15
15
|
class Config {
|
16
16
|
/**
|
17
|
-
*
|
17
|
+
* Stores all subscriptions for this Config instance.
|
18
|
+
* The data structure is a Map where:
|
19
|
+
* - The key is the ID of the subscription owner (e.g., a component's `id`).
|
20
|
+
* - The value is another Map (the subscriberMap).
|
21
|
+
*
|
22
|
+
* The nested subscriberMap is structured as:
|
23
|
+
* - The key is the callback function (`fn`).
|
24
|
+
* - The value is a Set of scopes (`scopeSet`).
|
25
|
+
*
|
26
|
+
* This nested structure `Map<string, Map<function, Set<scope>>>` is intentionally chosen
|
27
|
+
* to robustly handle the edge case where the same function is subscribed multiple times
|
28
|
+
* with different scopes, all under the same owner ID. It ensures that each
|
29
|
+
* `fn`-`scope` combination is unique and that cleanup is precise.
|
30
|
+
* @member {Object} #subscribers={}
|
18
31
|
* @private
|
19
32
|
*/
|
20
33
|
#subscribers = {}
|
21
34
|
/**
|
22
35
|
* The internal value of the config property.
|
23
|
-
* @member #value
|
36
|
+
* @member {*} #value
|
24
37
|
* @private
|
25
38
|
*/
|
26
39
|
#value
|
@@ -67,7 +80,7 @@ class Config {
|
|
67
80
|
get() {
|
68
81
|
// Registers this Config instance as a dependency with the currently active Effect,
|
69
82
|
// enabling automatic re-execution when this Config's value changes.
|
70
|
-
EffectManager.
|
83
|
+
EffectManager.addDependency(this);
|
71
84
|
return this.#value
|
72
85
|
}
|
73
86
|
|
@@ -75,52 +88,56 @@ class Config {
|
|
75
88
|
* Initializes the `Config` instance using a descriptor object.
|
76
89
|
* Extracts `clone`, `mergeStrategy` and `isEqual` from the descriptor.
|
77
90
|
* The internal `#value` is NOT set by this method.
|
78
|
-
* @param {Object}
|
79
|
-
* @param {any} descriptor.value - The default value for the config (not set by this method).
|
91
|
+
* @param {Object} descriptor - The descriptor object for the config.
|
80
92
|
* @param {string} [descriptor.clone='deep'] - The clone strategy for set.
|
81
93
|
* @param {string} [descriptor.cloneOnGet] - The clone strategy for get. Defaults to 'shallow' if clone is 'deep' or 'shallow', and 'none' if clone is 'none'.
|
82
|
-
* @param {string} [descriptor.merge='deep'] - The merge strategy.
|
83
94
|
* @param {Function} [descriptor.isEqual=Neo.isEqual] - The equality comparison function.
|
95
|
+
* @param {string} [descriptor.merge='deep'] - The merge strategy.
|
96
|
+
* @param {any} descriptor.value - The default value for the config (not set by this method).
|
84
97
|
*/
|
85
98
|
initDescriptor({clone, cloneOnGet, isEqual, merge}) {
|
86
99
|
let me = this;
|
87
100
|
|
88
101
|
if (clone && clone !== me.clone) {
|
89
102
|
Object.defineProperty(me, 'clone', {
|
90
|
-
|
103
|
+
configurable: true, enumerable: true, value: clone, writable: true
|
91
104
|
})
|
92
105
|
}
|
93
106
|
|
94
107
|
if (cloneOnGet && cloneOnGet !== me.cloneOnGet) {
|
95
108
|
Object.defineProperty(me, 'cloneOnGet', {
|
96
|
-
|
109
|
+
configurable: true, enumerable: true, value: cloneOnGet, writable: true
|
97
110
|
})
|
98
111
|
}
|
99
112
|
|
100
113
|
if (isEqual && isEqual !== me.isEqual) {
|
101
114
|
Object.defineProperty(me, 'isEqual', {
|
102
|
-
|
115
|
+
configurable: true, enumerable: true, value: isEqual, writable: true
|
103
116
|
})
|
104
117
|
}
|
105
118
|
|
106
119
|
if (merge && merge !== me.mergeStrategy) {
|
107
120
|
Object.defineProperty(me, 'mergeStrategy', {
|
108
|
-
|
121
|
+
configurable: true, enumerable: true, value: merge, writable: true
|
109
122
|
})
|
110
123
|
}
|
111
124
|
}
|
112
125
|
|
113
126
|
/**
|
114
127
|
* Notifies all subscribed callbacks about a change in the config's value.
|
128
|
+
* It iterates through the nested subscriber structure to ensure each callback
|
129
|
+
* is executed with its intended scope.
|
115
130
|
* @param {any} newValue - The new value of the config.
|
116
131
|
* @param {any} oldValue - The old value of the config.
|
117
132
|
*/
|
118
133
|
notify(newValue, oldValue) {
|
119
134
|
for (const id in this.#subscribers) {
|
120
135
|
if (this.#subscribers.hasOwnProperty(id)) {
|
121
|
-
const
|
122
|
-
for (const
|
123
|
-
|
136
|
+
const subscriberMap = this.#subscribers[id];
|
137
|
+
for (const [fn, scopeSet] of subscriberMap) {
|
138
|
+
for (const scope of scopeSet) {
|
139
|
+
fn.call(scope || null, newValue, oldValue)
|
140
|
+
}
|
124
141
|
}
|
125
142
|
}
|
126
143
|
}
|
@@ -164,12 +181,13 @@ class Config {
|
|
164
181
|
/**
|
165
182
|
* Subscribes a callback function to changes in this config's value.
|
166
183
|
* The callback will be invoked with `(newValue, oldValue)` whenever the config changes.
|
167
|
-
* @param {Object}
|
168
|
-
* @param {String}
|
169
|
-
* @param {Function} options.fn
|
184
|
+
* @param {Object} options - An object containing the subscription details.
|
185
|
+
* @param {String} options.id - The ID of the subscription owner (e.g., a Neo.core.Base instance's id).
|
186
|
+
* @param {Function} options.fn - The callback function.
|
187
|
+
* @param {Object} [options.scope] - The scope to execute the callback in.
|
170
188
|
* @returns {Function} A cleanup function to unsubscribe the callback.
|
171
189
|
*/
|
172
|
-
subscribe({id, fn}) {
|
190
|
+
subscribe({id, fn, scope}) {
|
173
191
|
if (typeof id !== 'string' || id.length === 0 || typeof fn !== 'function') {
|
174
192
|
throw new Error([
|
175
193
|
'Config.subscribe: options must be an object with a non-empty string `id` ',
|
@@ -179,18 +197,36 @@ class Config {
|
|
179
197
|
|
180
198
|
const me = this;
|
181
199
|
|
200
|
+
// Get or create the top-level Map for the subscription owner.
|
182
201
|
if (!me.#subscribers[id]) {
|
183
|
-
me.#subscribers[id] = new
|
202
|
+
me.#subscribers[id] = new Map()
|
184
203
|
}
|
185
204
|
|
186
|
-
me.#subscribers[id]
|
205
|
+
const subscriberMap = me.#subscribers[id];
|
206
|
+
|
207
|
+
// Get or create the Set of scopes for the specific callback function.
|
208
|
+
if (!subscriberMap.has(fn)) {
|
209
|
+
subscriberMap.set(fn, new Set())
|
210
|
+
}
|
187
211
|
|
212
|
+
const scopeSet = subscriberMap.get(fn);
|
213
|
+
scopeSet.add(scope);
|
214
|
+
|
215
|
+
// The returned cleanup function is precise. It removes only the specific
|
216
|
+
// scope for the function, and cleans up the parent data structures
|
217
|
+
// (the Set and the Maps) only if they become empty.
|
188
218
|
return () => {
|
189
|
-
const
|
190
|
-
if (
|
191
|
-
|
192
|
-
if (
|
193
|
-
delete
|
219
|
+
const currentSubscriberMap = me.#subscribers[id];
|
220
|
+
if (currentSubscriberMap) {
|
221
|
+
const currentScopeSet = currentSubscriberMap.get(fn);
|
222
|
+
if (currentScopeSet) {
|
223
|
+
currentScopeSet.delete(scope);
|
224
|
+
if (currentScopeSet.size === 0) {
|
225
|
+
currentSubscriberMap.delete(fn);
|
226
|
+
if (currentSubscriberMap.size === 0) {
|
227
|
+
delete me.#subscribers[id]
|
228
|
+
}
|
229
|
+
}
|
194
230
|
}
|
195
231
|
}
|
196
232
|
}
|
@@ -198,33 +234,10 @@ class Config {
|
|
198
234
|
}
|
199
235
|
|
200
236
|
Object.defineProperties(Config.prototype, {
|
201
|
-
clone: {
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
enumerable: false
|
206
|
-
},
|
207
|
-
cloneOnGet: {
|
208
|
-
value: null,
|
209
|
-
writable: false,
|
210
|
-
configurable: true,
|
211
|
-
enumerable: false
|
212
|
-
},
|
213
|
-
isEqual: {
|
214
|
-
value: Neo.isEqual,
|
215
|
-
writable: false,
|
216
|
-
configurable: true,
|
217
|
-
enumerable: false
|
218
|
-
},
|
219
|
-
mergeStrategy: {
|
220
|
-
value: 'replace',
|
221
|
-
writable: false,
|
222
|
-
configurable: true,
|
223
|
-
enumerable: false
|
224
|
-
}
|
237
|
+
clone : {configurable: true, enumerable: false, value: 'deep', writable: false},
|
238
|
+
cloneOnGet : {configurable: true, enumerable: false, value: null, writable: false},
|
239
|
+
isEqual : {configurable: true, enumerable: false, value: Neo.isEqual, writable: false},
|
240
|
+
mergeStrategy: {configurable: true, enumerable: false, value: 'replace', writable: false}
|
225
241
|
});
|
226
242
|
|
227
|
-
|
228
|
-
ns.Config = Config;
|
229
|
-
|
230
|
-
export default Config;
|
243
|
+
export default Neo.gatekeep(Config, 'Neo.core.Config');
|
package/src/core/Effect.mjs
CHANGED
@@ -1,6 +1,6 @@
|
|
1
|
-
import
|
2
|
-
import
|
3
|
-
import IdGenerator
|
1
|
+
import Config from './Config.mjs';
|
2
|
+
import EffectManager from './EffectManager.mjs';
|
3
|
+
import IdGenerator from './IdGenerator.mjs';
|
4
4
|
|
5
5
|
/**
|
6
6
|
* Creates a reactive effect that automatically tracks its dependencies and re-runs when any of them change.
|
@@ -9,6 +9,11 @@ import IdGenerator from './IdGenerator.mjs';
|
|
9
9
|
* @class Neo.core.Effect
|
10
10
|
*/
|
11
11
|
class Effect {
|
12
|
+
/**
|
13
|
+
* The optional component id this effect belongs to.
|
14
|
+
* @member {String|null} componentId=null
|
15
|
+
*/
|
16
|
+
componentId = null
|
12
17
|
/**
|
13
18
|
* A Map containing Config instances as keys and their cleanup functions as values.
|
14
19
|
* @member {Map} dependencies=new Map()
|
@@ -31,10 +36,10 @@ class Effect {
|
|
31
36
|
*/
|
32
37
|
isDestroyed = false
|
33
38
|
/**
|
34
|
-
* @member {
|
39
|
+
* @member {Neo.core.Config}
|
35
40
|
* @protected
|
36
41
|
*/
|
37
|
-
isRunning =
|
42
|
+
isRunning = null
|
38
43
|
|
39
44
|
/**
|
40
45
|
* @member fn
|
@@ -51,11 +56,44 @@ class Effect {
|
|
51
56
|
}
|
52
57
|
|
53
58
|
/**
|
54
|
-
* @param {Object} config
|
55
|
-
* @param {Function}
|
59
|
+
* @param {Function|Object} fn - The function to execute, or a config object for the effect.
|
60
|
+
* @param {Function} [fn.fn] - The function to execute for the effect (if the first argument is an object).
|
61
|
+
* @param {String} [fn.componentId] - The component id this effect belongs to.
|
62
|
+
* @param {Boolean} [fn.lazy=false] - If true, the effect will not run immediately upon creation.
|
63
|
+
* @param {Object|Object[]} [fn.subscriber] - A single subscriber or an array of subscribers for the isRunning config.
|
64
|
+
* @param {Object} [options={}] - Optional. Used if the first argument is a function, this object contains the options.
|
65
|
+
* @example
|
66
|
+
* // Signature 1: Function and Options
|
67
|
+
* const myEffect = new Effect(() => console.log('Run'), {lazy: true});
|
68
|
+
* @example
|
69
|
+
* // Signature 2: Single Config Object
|
70
|
+
* const myEffect = new Effect({fn: () => console.log('Run'), lazy: true});
|
56
71
|
*/
|
57
|
-
constructor({
|
58
|
-
|
72
|
+
constructor(fn, options={}) {
|
73
|
+
const me = this;
|
74
|
+
|
75
|
+
const {
|
76
|
+
fn: effectFn,
|
77
|
+
componentId,
|
78
|
+
lazy = false,
|
79
|
+
subscriber
|
80
|
+
} = (typeof fn === 'function') ? { ...options, fn } : (fn || {});
|
81
|
+
|
82
|
+
if (componentId) {
|
83
|
+
me.componentId = componentId
|
84
|
+
}
|
85
|
+
|
86
|
+
me.isRunning = new Config(false);
|
87
|
+
|
88
|
+
if (subscriber) {
|
89
|
+
[].concat(subscriber).forEach(sub => me.isRunning.subscribe(sub))
|
90
|
+
}
|
91
|
+
|
92
|
+
if (lazy) {
|
93
|
+
me._fn = effectFn
|
94
|
+
} else {
|
95
|
+
me.fn = effectFn
|
96
|
+
}
|
59
97
|
}
|
60
98
|
|
61
99
|
/**
|
@@ -70,34 +108,53 @@ class Effect {
|
|
70
108
|
}
|
71
109
|
|
72
110
|
/**
|
73
|
-
* Executes the effect function,
|
74
|
-
*
|
75
|
-
* The dynamic re-tracking ensures the effect always reflects its current dependencies,
|
76
|
-
* even if the logic within `fn` changes conditionally.
|
111
|
+
* Executes the effect function, re-evaluating its dependencies.
|
112
|
+
* If the EffectManager is paused (e.g., inside a batch), it queues itself to be run later.
|
77
113
|
* @protected
|
78
114
|
*/
|
79
115
|
run() {
|
80
116
|
const me = this;
|
81
117
|
|
82
|
-
if (me.isDestroyed
|
118
|
+
if (me.isDestroyed) {
|
119
|
+
return
|
120
|
+
}
|
121
|
+
|
122
|
+
// Check if already running without creating a dependency on `isRunning`.
|
123
|
+
EffectManager.pauseTracking();
|
124
|
+
const isRunning = me.isRunning.get();
|
125
|
+
EffectManager.resumeTracking();
|
126
|
+
|
127
|
+
if (isRunning) {
|
128
|
+
return
|
129
|
+
}
|
83
130
|
|
84
|
-
|
85
|
-
|
131
|
+
// If the manager is globally paused for batching, queue this effect and stop.
|
132
|
+
if (EffectManager.isPaused()) {
|
133
|
+
EffectManager.queue(me);
|
86
134
|
return
|
87
135
|
}
|
88
136
|
|
89
|
-
|
137
|
+
// Set `isRunning` to true without creating a dependency.
|
138
|
+
EffectManager.pauseTracking();
|
139
|
+
me.isRunning.set(true);
|
140
|
+
EffectManager.resumeTracking();
|
90
141
|
|
142
|
+
// Clear old dependencies and set this as the active effect.
|
91
143
|
me.dependencies.forEach(cleanup => cleanup());
|
92
144
|
me.dependencies.clear();
|
93
|
-
|
94
145
|
EffectManager.push(me);
|
95
146
|
|
96
147
|
try {
|
148
|
+
// Execute the function, which will collect new dependencies.
|
97
149
|
me.fn()
|
98
150
|
} finally {
|
151
|
+
// Clean up after the run.
|
99
152
|
EffectManager.pop();
|
100
|
-
|
153
|
+
|
154
|
+
// Set `isRunning` to false without creating a dependency.
|
155
|
+
EffectManager.pauseTracking();
|
156
|
+
me.isRunning.set(false);
|
157
|
+
EffectManager.resumeTracking()
|
101
158
|
}
|
102
159
|
}
|
103
160
|
|
@@ -109,7 +166,6 @@ class Effect {
|
|
109
166
|
addDependency(config) {
|
110
167
|
const me = this;
|
111
168
|
|
112
|
-
// Only add if not already a dependency. Map uses strict equality (===) for object keys.
|
113
169
|
if (!me.dependencies.has(config)) {
|
114
170
|
const cleanup = config.subscribe({
|
115
171
|
id: me.id,
|
@@ -121,7 +177,13 @@ class Effect {
|
|
121
177
|
}
|
122
178
|
}
|
123
179
|
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
180
|
+
export default Neo.gatekeep(Effect, 'Neo.core.Effect', () => {
|
181
|
+
/**
|
182
|
+
* Factory shortcut to create a new Neo.core.Effect instance.
|
183
|
+
* @function Neo.effect
|
184
|
+
* @param {Function|Object} fn - The function to execute, or a config object for the effect.
|
185
|
+
* @param {Object} [options] - Optional. Used if the first argument is a function.
|
186
|
+
* @returns {Neo.core.Effect}
|
187
|
+
*/
|
188
|
+
Neo.effect = (fn, options) => new Effect(fn, options)
|
189
|
+
});
|
@@ -1,11 +1,48 @@
|
|
1
1
|
/**
|
2
|
-
* A singleton manager to track the currently running effect.
|
3
|
-
*
|
2
|
+
* A singleton manager to track the currently running effect and control global effect execution.
|
3
|
+
* It provides a centralized mechanism for pausing, resuming, and batching effect runs.
|
4
4
|
* @class Neo.core.EffectManager
|
5
5
|
* @singleton
|
6
6
|
*/
|
7
7
|
const EffectManager = {
|
8
|
+
/**
|
9
|
+
* A stack to keep track of the currently active effect and its predecessors.
|
10
|
+
* @member {Neo.core.Effect[]} effectStack=[]
|
11
|
+
* @protected
|
12
|
+
*/
|
8
13
|
effectStack: [],
|
14
|
+
/**
|
15
|
+
* A flag to temporarily disable dependency tracking for the active effect.
|
16
|
+
* This is used internally to prevent effects from depending on their own state, like `isRunning`.
|
17
|
+
* @member {Boolean} isTrackingPaused=false
|
18
|
+
* @protected
|
19
|
+
*/
|
20
|
+
isTrackingPaused: false,
|
21
|
+
/**
|
22
|
+
* A counter to manage nested calls to pause() and resume(). Effect execution is
|
23
|
+
* paused or batched while this counter is greater than 0.
|
24
|
+
* @member {Number} pauseCounter=0
|
25
|
+
* @protected
|
26
|
+
*/
|
27
|
+
pauseCounter: 0,
|
28
|
+
/**
|
29
|
+
* A Set to store unique effects that are triggered while the manager is paused.
|
30
|
+
* These effects will be run when resume() is called and the pauseCounter returns to 0.
|
31
|
+
* @member {Set<Neo.core.Effect>} queuedEffects=new Set()
|
32
|
+
* @protected
|
33
|
+
*/
|
34
|
+
queuedEffects: new Set(),
|
35
|
+
|
36
|
+
/**
|
37
|
+
* Adds a `Neo.core.Config` instance as a dependency for the currently active effect,
|
38
|
+
* unless dependency tracking is explicitly paused.
|
39
|
+
* @param {Neo.core.Config} config The config instance to add as a dependency.
|
40
|
+
*/
|
41
|
+
addDependency(config) {
|
42
|
+
if (!this.isTrackingPaused) {
|
43
|
+
this.getActiveEffect()?.addDependency(config)
|
44
|
+
}
|
45
|
+
},
|
9
46
|
|
10
47
|
/**
|
11
48
|
* Returns the effect currently at the top of the stack (i.e., the one currently running).
|
@@ -16,7 +53,31 @@ const EffectManager = {
|
|
16
53
|
},
|
17
54
|
|
18
55
|
/**
|
19
|
-
*
|
56
|
+
* Checks if effect execution is currently paused or batched.
|
57
|
+
* @returns {Boolean} True if the pauseCounter is greater than 0.
|
58
|
+
*/
|
59
|
+
isPaused() {
|
60
|
+
return this.pauseCounter > 0
|
61
|
+
},
|
62
|
+
|
63
|
+
/**
|
64
|
+
* Pauses effect execution and begins batching.
|
65
|
+
* Each call to pause() increments a counter, allowing for nested control.
|
66
|
+
*/
|
67
|
+
pause() {
|
68
|
+
this.pauseCounter++
|
69
|
+
},
|
70
|
+
|
71
|
+
/**
|
72
|
+
* Disables dependency tracking for the currently active effect.
|
73
|
+
* @protected
|
74
|
+
*/
|
75
|
+
pauseTracking() {
|
76
|
+
this.isTrackingPaused = true
|
77
|
+
},
|
78
|
+
|
79
|
+
/**
|
80
|
+
* Pops the current effect from the stack.
|
20
81
|
* @returns {Neo.core.Effect|null}
|
21
82
|
*/
|
22
83
|
pop() {
|
@@ -24,15 +85,63 @@ const EffectManager = {
|
|
24
85
|
},
|
25
86
|
|
26
87
|
/**
|
27
|
-
* Pushes an effect onto the stack
|
88
|
+
* Pushes an effect onto the stack.
|
28
89
|
* @param {Neo.core.Effect} effect The effect to push.
|
29
90
|
*/
|
30
91
|
push(effect) {
|
31
92
|
this.effectStack.push(effect)
|
93
|
+
},
|
94
|
+
|
95
|
+
/**
|
96
|
+
* Queues a unique effect to be run later.
|
97
|
+
* @param {Neo.core.Effect} effect The effect to queue.
|
98
|
+
* @protected
|
99
|
+
*/
|
100
|
+
queue(effect) {
|
101
|
+
this.queuedEffects.add(effect)
|
102
|
+
},
|
103
|
+
|
104
|
+
/**
|
105
|
+
* Resumes effect execution. If the pause counter returns to zero and effects
|
106
|
+
* have been queued, they will all be executed synchronously.
|
107
|
+
*/
|
108
|
+
resume() {
|
109
|
+
let me = this;
|
110
|
+
|
111
|
+
if (me.pauseCounter > 0) {
|
112
|
+
me.pauseCounter--;
|
113
|
+
|
114
|
+
if (me.pauseCounter === 0 && me.queuedEffects.size > 0) {
|
115
|
+
const effectsToRun = [...me.queuedEffects];
|
116
|
+
me.queuedEffects.clear();
|
117
|
+
effectsToRun.forEach(effect => effect.run())
|
118
|
+
}
|
119
|
+
}
|
120
|
+
},
|
121
|
+
|
122
|
+
/**
|
123
|
+
* Re-enables dependency tracking for the currently active effect.
|
124
|
+
* @protected
|
125
|
+
*/
|
126
|
+
resumeTracking() {
|
127
|
+
this.isTrackingPaused = false
|
32
128
|
}
|
33
129
|
};
|
34
130
|
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
131
|
+
export default Neo.gatekeep(EffectManager, 'Neo.core.EffectManager', () => {
|
132
|
+
/**
|
133
|
+
* Wraps a function in a batch operation, ensuring that all effects triggered
|
134
|
+
* within it are run only once after the function completes.
|
135
|
+
* @function Neo.batch
|
136
|
+
* @param {Function} fn The function to execute.
|
137
|
+
*/
|
138
|
+
Neo.batch = function(fn) {
|
139
|
+
EffectManager.pause();
|
140
|
+
try {
|
141
|
+
fn()
|
142
|
+
} finally {
|
143
|
+
// The public resume() method handles running queued effects.
|
144
|
+
EffectManager.resume()
|
145
|
+
}
|
146
|
+
}
|
147
|
+
});
|
package/src/core/IdGenerator.mjs
CHANGED
@@ -1,44 +1,17 @@
|
|
1
1
|
/**
|
2
|
-
*
|
3
|
-
*
|
4
|
-
* @class Neo.core.IdGenerator
|
5
|
-
* @singleton
|
2
|
+
* Provides a singleton utility for generating unique IDs.
|
3
|
+
* @namespace Neo.core.IdGenerator
|
6
4
|
*/
|
7
|
-
|
8
|
-
static config = {
|
9
|
-
/**
|
10
|
-
* @member {String} className='Neo.core.IdGenerator'
|
11
|
-
* @protected
|
12
|
-
*/
|
13
|
-
className: 'Neo.core.IdGenerator',
|
14
|
-
/**
|
15
|
-
* @member {String} ntype='id-generator'
|
16
|
-
* @protected
|
17
|
-
*/
|
18
|
-
ntype: 'id-generator',
|
19
|
-
/**
|
20
|
-
* The default prefix for neo instance ids
|
21
|
-
* @member {String} base='neo-'
|
22
|
-
*/
|
23
|
-
base: 'neo-',
|
24
|
-
/**
|
25
|
-
* @member {Boolean} singleton='true
|
26
|
-
* @protected
|
27
|
-
*/
|
28
|
-
singleton: true
|
29
|
-
}
|
30
|
-
|
5
|
+
const IdGenerator = {
|
31
6
|
/**
|
32
|
-
*
|
7
|
+
* The default prefix for neo instance ids
|
8
|
+
* @member {String} base='neo-'
|
33
9
|
*/
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
// alias
|
40
|
-
Neo.getId = me.getId.bind(me);
|
41
|
-
}
|
10
|
+
base: 'neo-',
|
11
|
+
/**
|
12
|
+
* @member {Object} idCounter={}
|
13
|
+
*/
|
14
|
+
idCounter: {},
|
42
15
|
|
43
16
|
/**
|
44
17
|
* @param name
|
@@ -55,12 +28,8 @@ class IdGenerator {
|
|
55
28
|
|
56
29
|
return me.base + (name === 'neo' ? '' : name + '-') + count;
|
57
30
|
}
|
58
|
-
|
59
|
-
init() {}
|
60
|
-
|
61
|
-
onAfterConstructed() {}
|
62
|
-
|
63
|
-
onConstructed() {}
|
64
31
|
}
|
65
32
|
|
66
|
-
export default Neo.
|
33
|
+
export default Neo.gatekeep(IdGenerator, 'Neo.core.IdGenerator', () => {
|
34
|
+
Neo.getId = IdGenerator.getId.bind(IdGenerator);
|
35
|
+
});
|