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
@@ -20,32 +20,39 @@ class Button extends Component {
|
|
20
20
|
ntype: 'mwc-button',
|
21
21
|
/**
|
22
22
|
* @member {Boolean} dense_=false
|
23
|
+
* @reactive
|
23
24
|
*/
|
24
25
|
dense_: false,
|
25
26
|
/**
|
26
27
|
* Shortcut for domListeners={click:handler}
|
27
28
|
* A string based value assumes that the handlerFn lives inside a ComponentController
|
28
29
|
* @member {Function|String|null} handler_=null
|
30
|
+
* @reactive
|
29
31
|
*/
|
30
32
|
handler_: null,
|
31
33
|
/**
|
32
34
|
* @member {String} icon_=''
|
35
|
+
* @reactive
|
33
36
|
*/
|
34
37
|
icon_: '',
|
35
38
|
/**
|
36
39
|
* @member {String} label_=''
|
40
|
+
* @reactive
|
37
41
|
*/
|
38
42
|
label_: '',
|
39
43
|
/**
|
40
44
|
* @member {Boolean} outlined_=false
|
45
|
+
* @reactive
|
41
46
|
*/
|
42
47
|
outlined_: false,
|
43
48
|
/**
|
44
49
|
* @member {Boolean} raised_=false
|
50
|
+
* @reactive
|
45
51
|
*/
|
46
52
|
raised_: false,
|
47
53
|
/**
|
48
54
|
* @member {Boolean} unelevated_=false
|
55
|
+
* @reactive
|
49
56
|
*/
|
50
57
|
unelevated_: false,
|
51
58
|
/**
|
@@ -21,38 +21,47 @@ class TextField extends Component {
|
|
21
21
|
/**
|
22
22
|
* Displays a helper text below the field
|
23
23
|
* @member {String} helper_=''
|
24
|
+
* @reactive
|
24
25
|
*/
|
25
26
|
helper_: '',
|
26
27
|
/**
|
27
28
|
* @member {String} icon_=''
|
29
|
+
* @reactive
|
28
30
|
*/
|
29
31
|
icon_: '',
|
30
32
|
/**
|
31
33
|
* @member {String} iconTrailing_=''
|
34
|
+
* @reactive
|
32
35
|
*/
|
33
36
|
iconTrailing_: '',
|
34
37
|
/**
|
35
38
|
* @member {String} label_=''
|
39
|
+
* @reactive
|
36
40
|
*/
|
37
41
|
label_: '',
|
38
42
|
/**
|
39
43
|
* @member {String} name_=''
|
44
|
+
* @reactive
|
40
45
|
*/
|
41
46
|
name_: '',
|
42
47
|
/**
|
43
48
|
* @member {Boolean} outlined_=false
|
49
|
+
* @reactive
|
44
50
|
*/
|
45
51
|
outlined_: false,
|
46
52
|
/**
|
47
53
|
* @member {String} placeholder_=''
|
54
|
+
* @reactive
|
48
55
|
*/
|
49
56
|
placeholder_: '',
|
50
57
|
/**
|
51
58
|
* @member {Boolean} required_=false
|
59
|
+
* @reactive
|
52
60
|
*/
|
53
61
|
required_: false,
|
54
62
|
/**
|
55
63
|
* @member {String} value_=''
|
64
|
+
* @reactive
|
56
65
|
*/
|
57
66
|
value_: '',
|
58
67
|
/**
|
@@ -21,11 +21,13 @@ class AmChart extends Component {
|
|
21
21
|
/**
|
22
22
|
* See: https://www.amcharts.com/docs/v4/
|
23
23
|
* @member {Object} chartConfig_=null
|
24
|
+
* @reactive
|
24
25
|
*/
|
25
26
|
chartConfig_: null,
|
26
27
|
/**
|
27
28
|
* Stores the chart data
|
28
29
|
* @member {Array|null} chartData_=null
|
30
|
+
* @reactive
|
29
31
|
*/
|
30
32
|
chartData_: null,
|
31
33
|
/**
|
@@ -21,12 +21,14 @@ class GoogleMaps extends Base {
|
|
21
21
|
/**
|
22
22
|
* Specify lat & lng for the current focus position
|
23
23
|
* @member {Object} center_={lat: -34.397, lng: 150.644}
|
24
|
+
* @reactive
|
24
25
|
*/
|
25
26
|
center_: {lat: -34.397, lng: 150.644},
|
26
27
|
/**
|
27
28
|
* Prefer to use markerStoreConfig instead.
|
28
29
|
* @member {Neo.data.Store|Object} markerStore_
|
29
30
|
* @protected
|
31
|
+
* @reactive
|
30
32
|
*/
|
31
33
|
markerStore_: {
|
32
34
|
model: {
|
@@ -52,6 +54,7 @@ class GoogleMaps extends Base {
|
|
52
54
|
},
|
53
55
|
/**
|
54
56
|
* @member {Number} zoom_=8
|
57
|
+
* @reactive
|
55
58
|
*/
|
56
59
|
zoom_: 8
|
57
60
|
}
|
@@ -25,10 +25,12 @@ class MapboxGL extends Component {
|
|
25
25
|
accessToken: null,
|
26
26
|
/**
|
27
27
|
* @member {Array|null} chartData_=null
|
28
|
+
* @reactive
|
28
29
|
*/
|
29
30
|
chartData_: null,
|
30
31
|
/**
|
31
32
|
* @member {Object} center_={lat: 0, lng: 0}
|
33
|
+
* @reactive
|
32
34
|
*/
|
33
35
|
center_: {lat: 0, lng: 0},
|
34
36
|
/**
|
@@ -47,6 +49,7 @@ class MapboxGL extends Component {
|
|
47
49
|
* beforeId is a custom property which will get passed as the second param for:
|
48
50
|
* https://docs.mapbox.com/mapbox-gl-js/api/#map#addlayer
|
49
51
|
* @member {Object[]|null} layers_=null
|
52
|
+
* @reactive
|
50
53
|
*/
|
51
54
|
layers_: null,
|
52
55
|
/**
|
@@ -59,6 +62,7 @@ class MapboxGL extends Component {
|
|
59
62
|
* id is a custom property which will get passed as the first param for:
|
60
63
|
* https://docs.mapbox.com/mapbox-gl-js/api/#map#addsource
|
61
64
|
* @member {Object[]|null} sources_=null
|
65
|
+
* @reactive
|
62
66
|
*/
|
63
67
|
sources_: null,
|
64
68
|
/**
|
@@ -73,6 +77,7 @@ class MapboxGL extends Component {
|
|
73
77
|
/**
|
74
78
|
*
|
75
79
|
* @member {Number} zoom_=3
|
80
|
+
* @reactive
|
76
81
|
*/
|
77
82
|
zoom_: 3
|
78
83
|
}
|
@@ -47,34 +47,41 @@ class MonacoEditor extends Base {
|
|
47
47
|
baseCls: ['neo-monaco-editor'],
|
48
48
|
/**
|
49
49
|
* @member {Boolean} contextmenu_=false
|
50
|
+
* @reactive
|
50
51
|
*/
|
51
52
|
contextmenu_: false,
|
52
53
|
/**
|
53
54
|
* Options are: 'blink', 'expand', 'phase', 'smooth', 'solid'
|
54
55
|
* @member {String} cursorBlinking_='blink'
|
56
|
+
* @reactive
|
55
57
|
*/
|
56
58
|
cursorBlinking_: 'blink',
|
57
59
|
/**
|
58
60
|
* additional property to only use in combination with readOnly === true.
|
59
61
|
* domReadOnly additionally sets the readonly attribute to the underlying textarea.
|
60
62
|
* @member {Boolean} domReadOnly_=false
|
63
|
+
* @reactive
|
61
64
|
*/
|
62
65
|
domReadOnly_: false,
|
63
66
|
/**
|
64
67
|
* Options are: 'vs', 'vs-dark', 'hc-black', 'hc-light'
|
65
68
|
* @member {String} editorTheme_='vs'
|
69
|
+
* @reactive
|
66
70
|
*/
|
67
71
|
editorTheme_: 'vs',
|
68
72
|
/**
|
69
73
|
* @member {Number} fontSize_=14
|
74
|
+
* @reactive
|
70
75
|
*/
|
71
76
|
fontSize_: 14,
|
72
77
|
/**
|
73
78
|
* @member {String} language_='javascript'
|
79
|
+
* @reactive
|
74
80
|
*/
|
75
81
|
language_: 'javascript',
|
76
82
|
/**
|
77
83
|
* @member {Object} minimap_={enabled: false}
|
84
|
+
* @reactive
|
78
85
|
*/
|
79
86
|
minimap_: {enabled: false},
|
80
87
|
/**
|
@@ -85,22 +92,27 @@ class MonacoEditor extends Base {
|
|
85
92
|
* For initial options this config will win over related class configs.
|
86
93
|
* However, run-time changes of related class configs will dynamically change their option values.
|
87
94
|
* @member {Object} options_={}
|
95
|
+
* @reactive
|
88
96
|
*/
|
89
97
|
options_: {},
|
90
98
|
/**
|
91
99
|
* @member {Boolean} readOnly_=false
|
100
|
+
* @reactive
|
92
101
|
*/
|
93
102
|
readOnly_: false,
|
94
103
|
/**
|
95
104
|
* @member {Boolean} scrollBeyondLastLine_=false
|
105
|
+
* @reactive
|
96
106
|
*/
|
97
107
|
scrollBeyondLastLine_: false,
|
98
108
|
/**
|
99
109
|
* @member {Boolean} showLineNumbers_=true
|
110
|
+
* @reactive
|
100
111
|
*/
|
101
112
|
showLineNumbers_: true,
|
102
113
|
/**
|
103
114
|
* @member {String|String[]} value_=''
|
115
|
+
* @reactive
|
104
116
|
*/
|
105
117
|
value_: ''
|
106
118
|
}
|
@@ -29,10 +29,12 @@ class Accordion extends Panel {
|
|
29
29
|
initialOpen_: [],
|
30
30
|
/**
|
31
31
|
* @member {Object} itemDefaults={ntype:'accordionitem'}
|
32
|
+
* @reactive
|
32
33
|
*/
|
33
34
|
itemDefaults: {ntype: 'accordionitem'},
|
34
35
|
/**
|
35
36
|
* @member {Object[]} items=[]
|
37
|
+
* @reactive
|
36
38
|
*/
|
37
39
|
items: [],
|
38
40
|
/**
|
package/src/container/Base.mjs
CHANGED
@@ -35,6 +35,7 @@ class Container extends Component {
|
|
35
35
|
* Default configuration for child items within this container.
|
36
36
|
* This config uses a descriptor to enable deep merging with instance based itemDefaults.
|
37
37
|
* @member {Object} itemDefaults_={[isDescriptor]: true, merge: 'deep', value: null}
|
38
|
+
* @reactive
|
38
39
|
*/
|
39
40
|
itemDefaults_: {
|
40
41
|
[isDescriptor]: true,
|
@@ -91,6 +92,7 @@ class Container extends Component {
|
|
91
92
|
* MyRedButton // you can drop imported modules directly into the items array
|
92
93
|
* ]
|
93
94
|
* });
|
95
|
+
* @reactive
|
94
96
|
*/
|
95
97
|
items_: {
|
96
98
|
[isDescriptor]: true,
|
@@ -104,6 +106,7 @@ class Container extends Component {
|
|
104
106
|
* Meaning: onConstructed() is the latest life-cycle point.
|
105
107
|
* You can use layout: 'base', in case you do not need a layout at all.
|
106
108
|
* @member {Object|String|null} layout_={ntype: 'vbox', align: 'stretch'}
|
109
|
+
* @reactive
|
107
110
|
*/
|
108
111
|
layout_: {
|
109
112
|
ntype: 'vbox',
|
@@ -349,13 +352,14 @@ class Container extends Component {
|
|
349
352
|
|
350
353
|
// Convenience logic, especially for moving components into different browser windows:
|
351
354
|
// A component might rely on references & handler methods inside the previous controller realm
|
352
|
-
|
355
|
+
// todo: We need ?. until functional.component.Base supports controllers
|
356
|
+
if (!item.controller && !me.getController() && parent.getController?.()) {
|
353
357
|
item.controller = {parent: parent.getController()}
|
354
358
|
}
|
355
359
|
}
|
356
360
|
|
357
361
|
item.set(config);
|
358
|
-
item.getStateProvider()?.createBindings(item);
|
362
|
+
item.getStateProvider?.()?.createBindings(item);
|
359
363
|
break
|
360
364
|
}
|
361
365
|
|
@@ -437,7 +441,7 @@ class Container extends Component {
|
|
437
441
|
|
438
442
|
// We need to add items into the vdom
|
439
443
|
me.updateDepth = -1;
|
440
|
-
me.update();
|
444
|
+
me.isConstructed && me.update();
|
441
445
|
|
442
446
|
me.fire('itemsCreated', {id: me.id, items})
|
443
447
|
}
|
package/src/container/Panel.mjs
CHANGED
package/src/controller/Base.mjs
CHANGED
package/src/core/Base.mjs
CHANGED
@@ -58,7 +58,26 @@ class Base {
|
|
58
58
|
*/
|
59
59
|
static overwrittenMethods = {}
|
60
60
|
/**
|
61
|
-
*
|
61
|
+
* Defines the default configuration properties for the class. These configurations are
|
62
|
+
* merged throughout the class hierarchy and can be overridden at the instance level.
|
63
|
+
*
|
64
|
+
* There are two main types of configs:
|
65
|
+
*
|
66
|
+
* 1. **Reactive Configs:** Property names ending with a trailing underscore (e.g., `myConfig_`).
|
67
|
+
* The framework automatically generates a public getter and setter, removing the underscore
|
68
|
+
* from the property name (e.g., `this.myConfig`). This system enables powerful, optional
|
69
|
+
* lifecycle hooks that are called automatically if they are implemented on the class:
|
70
|
+
* - `beforeGetMyConfig(value)`: Executed before the getter returns. Can be used to dynamically modify the returned value.
|
71
|
+
* - `beforeSetMyConfig(newValue, oldValue)`: Executed before a new value is set. Can be used for validation or transformation. Returning `undefined` from this hook will cancel the update.
|
72
|
+
* - `afterSetMyConfig(newValue, oldValue)`: Executed after a new value has been successfully set. Ideal for triggering side effects.
|
73
|
+
*
|
74
|
+
* 2. **Non-Reactive (Prototype-based) Configs:** Property names without a trailing underscore.
|
75
|
+
* These are applied directly to the class's **prototype** during the `Neo.setupClass`
|
76
|
+
* process. This is highly memory-efficient as the value is shared across all instances.
|
77
|
+
* It also allows for powerful, application-wide modifications of default behaviors
|
78
|
+
* by using the `Neo.overwrites` mechanism, which modifies these prototype values at
|
79
|
+
* load time.
|
80
|
+
*
|
62
81
|
* @returns {Object} config
|
63
82
|
*/
|
64
83
|
static config = {
|
@@ -83,6 +102,7 @@ class Base {
|
|
83
102
|
/**
|
84
103
|
* The unique component id
|
85
104
|
* @member {String|null} id_=null
|
105
|
+
* @reactive
|
86
106
|
*/
|
87
107
|
id_: null,
|
88
108
|
/**
|
@@ -104,6 +124,7 @@ class Base {
|
|
104
124
|
* Effects can observe this config to clean themselves up.
|
105
125
|
* @member {Boolean} isDestroying_=false
|
106
126
|
* @protected
|
127
|
+
* @reactive
|
107
128
|
*/
|
108
129
|
isDestroying_: false,
|
109
130
|
/**
|
@@ -112,6 +133,7 @@ class Base {
|
|
112
133
|
* Since not all classes use the Observable mixin, Neo will not fire an event.
|
113
134
|
* method body.
|
114
135
|
* @member {Boolean} isReady_=false
|
136
|
+
* @reactive
|
115
137
|
*/
|
116
138
|
isReady_: false,
|
117
139
|
/**
|
@@ -133,6 +155,7 @@ class Base {
|
|
133
155
|
*
|
134
156
|
* @member {Object|null} remote_=null
|
135
157
|
* @protected
|
158
|
+
* @reactive
|
136
159
|
*/
|
137
160
|
remote_: null
|
138
161
|
}
|
@@ -290,9 +313,38 @@ class Base {
|
|
290
313
|
}
|
291
314
|
|
292
315
|
/**
|
293
|
-
*
|
294
|
-
*
|
316
|
+
* This static method is called by `Neo.setupClass()` during the class creation process.
|
317
|
+
* It allows for modifying a class's default prototype-based configs from outside the
|
318
|
+
* class hierarchy, which is a powerful way to avoid boilerplate code.
|
319
|
+
*
|
320
|
+
* It looks for a matching entry in the global `Neo.overwrites` object based on the
|
321
|
+
* class's `className`. If found, it merges the properties from the overwrite object
|
322
|
+
* into the class's static `config`. This provides a powerful mechanism for theming
|
323
|
+
* or applying application-wide customizations to framework or library classes without
|
324
|
+
* needing to extend them.
|
325
|
+
*
|
326
|
+
* @example
|
327
|
+
* // Imagine you have hundreds of buttons in your app, and you want all of them
|
328
|
+
* // to have `labelPosition: 'top'` instead of the default `'left'`.
|
329
|
+
* // Instead of configuring each instance, you can define an overwrite.
|
330
|
+
*
|
331
|
+
* // inside an Overwrites.mjs file loaded by your app:
|
332
|
+
* Neo.overwrites = {
|
333
|
+
* Neo: {
|
334
|
+
* button: {
|
335
|
+
* Base: {
|
336
|
+
* labelPosition: 'top'
|
337
|
+
* }
|
338
|
+
* }
|
339
|
+
* }
|
340
|
+
* };
|
341
|
+
*
|
342
|
+
* // Now, every `Neo.button.Base` (and any class that extends it) will have this
|
343
|
+
* // new default value on its prototype.
|
344
|
+
*
|
345
|
+
* @param {Object} cfg The static `config` object of the class being processed.
|
295
346
|
* @protected
|
347
|
+
* @static
|
296
348
|
*/
|
297
349
|
static applyOverwrites(cfg) {
|
298
350
|
let overwrites = Neo.ns(cfg.className, false, Neo.overwrites),
|
package/src/core/Compare.mjs
CHANGED
@@ -163,10 +163,7 @@ class Compare {
|
|
163
163
|
}
|
164
164
|
}
|
165
165
|
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
Neo.isEqual = Compare.isEqual;
|
171
|
-
|
172
|
-
export default Compare;
|
166
|
+
export default Neo.gatekeep(Compare, 'Neo.core.Compare', () => {
|
167
|
+
// alias
|
168
|
+
Neo.isEqual = Compare.isEqual
|
169
|
+
});
|
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');
|