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
@@ -0,0 +1,46 @@
|
|
1
|
+
# Overview
|
2
|
+
|
3
|
+
## Framework Comparisons
|
4
|
+
|
5
|
+
This section provides detailed comparisons between Neo.mjs and other popular JavaScript frameworks. Our goal is to help
|
6
|
+
you understand the key similarities, differences, and unique advantages of Neo.mjs in relation to technologies you might
|
7
|
+
already be familiar with.
|
8
|
+
|
9
|
+
We aim to compare these frameworks from a **technical, objective, and constructive perspective**, focusing on how
|
10
|
+
different architectural choices and design philosophies address common web development challenges. Please note that
|
11
|
+
these comparison documents were generated with the assistance of a large language model (Gemini).
|
12
|
+
|
13
|
+
Each comparison article will focus on:
|
14
|
+
|
15
|
+
* **Bridging Knowledge Gaps:** Mapping concepts you know to Neo.mjs.
|
16
|
+
* **Highlighting Differentiators:** What makes Neo.mjs unique.
|
17
|
+
* **Side-by-Side Analysis:** Feature-by-feature comparisons.
|
18
|
+
* **Trade-offs and Use Cases:** When Neo.mjs might be the optimal choice.
|
19
|
+
|
20
|
+
### Architectural Snapshot
|
21
|
+
|
22
|
+
The table below offers a high-level architectural comparison of the frameworks discussed in this section. It is designed
|
23
|
+
to provide a quick snapshot of their core differences. For a deeper understanding, please refer to the detailed comparison
|
24
|
+
articles.
|
25
|
+
|
26
|
+
| Feature | Neo.mjs | React | Vue.js | Solid.js | Angular |
|
27
|
+
| ----------------------- |----------------------------------------| --------------------------------------- | ------------------------------------ | --------------------------------------- | --------------------------------------- |
|
28
|
+
| **Core Architecture** | Multi-Threaded (Worker-Based) | Single-Threaded (Main-Thread Bound) | Single-Threaded (Main-Thread Bound) | Single-Threaded (Main-Thread Bound) | Single-Threaded (Main-Thread Bound) |
|
29
|
+
| **VDOM Location** | App Worker | Main Thread | Main Thread | No VDOM (Direct DOM Updates) | Main Thread |
|
30
|
+
| **Reactivity Model** | Fine-Grained (Surgical Atomic Updates) | Cascading Re-Renders (Manual Memo) | Fine-Grained (Compiler-Assisted) | Fine-Grained (Non-Destructive) | Zone.js (Automatic Change Detection) |
|
31
|
+
| **Manual Optimizations**| Not Required | Required (`memo`, `useCallback`, `useMemo`) | Not Required | Not Required | Not Required |
|
32
|
+
| **State Mutability** | Directly Mutable | Immutable (Enforced) | Mutable (Proxied) | Mutable (Proxied) | Mutable (Observable-based) |
|
33
|
+
| **Dev Environment** | Zero-Builds (Instant) | Build-Based (Vite, etc.) | Build-Based (Vite) | Build-Based (Vite) | Build-Based (Angular CLI) |
|
34
|
+
| **Multi-Window Support**| Native (Shared Data/Components) | Limited/Requires Custom Logic | Limited/Requires Custom Logic | Limited/Requires Custom Logic | Limited/Requires Custom Logic |
|
35
|
+
|
36
|
+
### Available Comparisons
|
37
|
+
|
38
|
+
* [Neo.mjs vs. React](/learn/comparisons/NeoVsReact.md)
|
39
|
+
* [Neo.mjs vs. Angular](/learn/comparisons/NeoVsAngular.md)
|
40
|
+
* [Neo.mjs vs. Vue.js](/learn/comparisons/NeoVsVue.md)
|
41
|
+
* [Neo.mjs vs. Solid.js](/learn/comparisons/NeoVsSolid.md)
|
42
|
+
* [Neo.mjs vs. Next.js](/learn/comparisons/NeoVsNextJs.md)
|
43
|
+
* [Neo.mjs vs. Ext.js](/learn/comparisons/NeoVsExtJs.md)
|
44
|
+
|
45
|
+
If you have feedback on any of our comparisons or would like to see a new one, please feel free to open an issue on our
|
46
|
+
[GitHub repository](https://github.com/neomjs/neo/issues).
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# Extending Classes
|
2
|
+
|
1
3
|
In theory, a Neo.mjs app could be defined in a single `.mjs` source file. But that would be very hard to
|
2
4
|
maintain, and any reusable configs would have to be duplicated. Instead, each of your views and reusable
|
3
5
|
widgets will be defined as its own class. The result is simpler views which are inherently reusable and easier
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# Setup
|
2
|
+
|
1
3
|
Setting up Neo.mjs is pretty easy — all you have to do is confirm that you have some required
|
2
4
|
software then follow a single npx script.
|
3
5
|
|
@@ -5,9 +7,8 @@ software then follow a single npx script.
|
|
5
7
|
|
6
8
|
Before you get started, Neo.mjs requires that you have a few of things installed:
|
7
9
|
|
8
|
-
- npm (see <a href="https://docs.npmjs.com/downloading-and-installing-node-js-and-npm" target="_blank">https://docs.npmjs.com/downloading-and-installing-node-js-and-npm</a>)
|
10
|
+
- npm & nodejs (see <a href="https://docs.npmjs.com/downloading-and-installing-node-js-and-npm" target="_blank">https://docs.npmjs.com/downloading-and-installing-node-js-and-npm</a>)
|
9
11
|
- npx (see <a href="https://www.npmjs.com/package/npx" target="_blank">https://www.npmjs.com/package/npx</a>)
|
10
|
-
- node (see <a href="https://nodejs.org/en/download" target="_blank">https://nodejs.org/en/download</a>)
|
11
12
|
|
12
13
|
## Installation
|
13
14
|
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# Shared Bindable Data (State Providers)
|
2
|
+
|
1
3
|
While Components can manage their own state using the Class Config System,
|
2
4
|
you want to use VMs as soon as you want to share data properties with multiple child Components.
|
3
5
|
|
@@ -8,6 +10,60 @@ Rules of thumb:
|
|
8
10
|
|
9
11
|
Other libraries or frameworks often call state providers "Stores".
|
10
12
|
|
13
|
+
## How Reactivity Works: The Effects-Based System
|
14
|
+
|
15
|
+
Neo.mjs State Providers implement a powerful effects-based reactivity system,
|
16
|
+
which automatically tracks dependencies and re-evaluates computations when
|
17
|
+
their underlying data changes. This system is built around two core concepts:
|
18
|
+
|
19
|
+
### 1. The `Neo.core.Effect` Class
|
20
|
+
|
21
|
+
At the heart of the reactivity is the `Neo.core.Effect` class. An `Effect`
|
22
|
+
is a mechanism that encapsulates a function (its "effect function") and
|
23
|
+
automatically re-runs this function whenever any of the reactive data
|
24
|
+
properties it accesses change.
|
25
|
+
|
26
|
+
* **Implicit Dependency Tracking:** When your effect function (e.g., a formula
|
27
|
+
or a binding formatter) reads a reactive data property (e.g., `data.user.firstName`),
|
28
|
+
the `Effect` automatically "subscribes" to changes in that property.
|
29
|
+
* **Automatic Re-evaluation:** If `data.user.firstName` changes, the `Effect`
|
30
|
+
detects this and automatically re-executes its effect function, ensuring
|
31
|
+
that any dependent computations or UI updates are performed.
|
32
|
+
|
33
|
+
### 2. The Hierarchical Data Proxy
|
34
|
+
|
35
|
+
When you access data within a State Provider (e.g., in a `bind` configuration
|
36
|
+
or a `formula`), you are interacting with a special `Proxy` object. This proxy
|
37
|
+
is created by `Neo.state.createHierarchicalDataProxy` and provides a unified
|
38
|
+
view of data across the entire State Provider hierarchy (current provider and
|
39
|
+
all its parents).
|
40
|
+
|
41
|
+
* **Seamless Data Access:** You can access any data property, whether it lives
|
42
|
+
in the current State Provider or a parent, using simple dot notation (e.g.,
|
43
|
+
`data.myProperty` or `data.user.address.street`).
|
44
|
+
* **Enabling Dependency Tracking:** This proxy works in conjunction with
|
45
|
+
`Neo.core.Effect` to enable implicit dependency tracking. When an `Effect`
|
46
|
+
reads a property through this proxy, the proxy notifies the `Effect` about
|
47
|
+
the access, allowing the `Effect` to register that property as a dependency.
|
48
|
+
|
49
|
+
### How Bindings and Formulas Utilize Effects
|
50
|
+
|
51
|
+
* **Bindings (`bind` config):** When you define a `bind` configuration for a
|
52
|
+
component (e.g., `bind: {text: data => data.hello}`), Neo.mjs creates an
|
53
|
+
`Effect`. The effect function is your formatter (`data => data.hello`).
|
54
|
+
Whenever `data.hello` changes, the `Effect` re-runs, re-evaluates the
|
55
|
+
formatter, and updates the component's `text` config.
|
56
|
+
|
57
|
+
* **Formulas (`formulas` config):** These are effect-based computed properties. Each formula function is wrapped in an `Effect`. When the
|
58
|
+
formula accesses data (e.g., `data.a + data.b`), the `Effect` tracks `data.a`
|
59
|
+
and `data.b` as dependencies. If either changes, the `Effect` re-runs the
|
60
|
+
formula, and its computed result is automatically updated in the State Provider's
|
61
|
+
data.
|
62
|
+
|
63
|
+
This effects-based system significantly reduces boilerplate, making state
|
64
|
+
management intuitive and efficient by handling dependency tracking and updates
|
65
|
+
automatically.
|
66
|
+
|
11
67
|
## Inline State Providers
|
12
68
|
### Direct Bindings
|
13
69
|
```javascript live-preview
|
@@ -111,9 +167,9 @@ Inside the Container are 3 Labels which bind their `text` config to a combinatio
|
|
111
167
|
|
112
168
|
We are showcasing 3 different ways how you can define your binding (resulting in the same output).
|
113
169
|
|
114
|
-
In case any of the bound data props changes, all bound Configs will
|
170
|
+
In case any of the bound data props changes, the underlying `Effect` for that binding will re-evaluate, and all bound Configs will update.
|
115
171
|
|
116
|
-
Important: The Config setter will only trigger in case there is a real change for the bound output.
|
172
|
+
Important: The Config setter will only trigger in case there is a real change for the bound output, ensuring efficient updates.
|
117
173
|
|
118
174
|
We also added 2 Buttons to change the value of each data prop, so that we can see that the bound Label texts
|
119
175
|
update right away.
|
@@ -252,17 +308,82 @@ which contains the nested props `firstname` and `lastname`.
|
|
252
308
|
We can bind to these nested props like before:</br>
|
253
309
|
`bind: {text: data => data.user.firstname + ' ' + data.user.lastname}`
|
254
310
|
|
255
|
-
Any change of a nested data prop will directly get reflected into the bound components.
|
311
|
+
Any change of a nested data prop will directly trigger the associated `Effect` and get reflected into the bound components.
|
256
312
|
|
257
313
|
We can update a nested data prop with passing its path:</br>
|
258
314
|
`data => data.component.setState({'user.lastname': 'Rahder'})`
|
259
315
|
|
260
316
|
Or we can directly pass the object containing the change(s):</br>
|
261
|
-
`data => data.component.setState({user: {firstname: 'Max'}})
|
317
|
+
`data => data.component.setState({user: {firstname: 'Max'}})`</br>
|
318
|
+
**Hint:** This will not override left out nested data props (lastname in this case).</br>
|
319
|
+
**Hint:** This is the recommended way for bulk state changes.
|
320
|
+
|
321
|
+
***You can also directly change state data***
|
322
|
+
|
323
|
+
`data => data.component.setStateProvider().data.user.firstname = 'Max'`
|
324
|
+
|
325
|
+
Shorthand syntax:</br>
|
326
|
+
`data => data.component.data.user.firstname = 'Max'`
|
327
|
+
|
328
|
+
### Formulas in Action
|
329
|
+
|
330
|
+
```javascript live-preview
|
331
|
+
import Button from '../button/Base.mjs';
|
332
|
+
import Container from '../container/Base.mjs';
|
333
|
+
import Label from '../component/Label.mjs';
|
334
|
+
|
335
|
+
class MainView extends Container {
|
336
|
+
static config = {
|
337
|
+
className: 'Guides.vmFormula.MainView',
|
338
|
+
stateProvider: {
|
339
|
+
data: {
|
340
|
+
price : 10,
|
341
|
+
quantity: 2
|
342
|
+
},
|
343
|
+
formulas: {
|
344
|
+
total : data => data.price * data.quantity,
|
345
|
+
discountedTotal: data => data.total * 0.9 // 10% discount
|
346
|
+
}
|
347
|
+
},
|
348
|
+
itemDefaults: {
|
349
|
+
module: Label,
|
350
|
+
style : {margin: '.5em 1em'}
|
351
|
+
},
|
352
|
+
items: [{
|
353
|
+
bind: {text: data => `Price: ${data.price}`}
|
354
|
+
}, {
|
355
|
+
bind: {text: data => `Quantity: ${data.quantity}`}
|
356
|
+
}, {
|
357
|
+
bind: {text: data => `Total: ${data.total}`}
|
358
|
+
}, {
|
359
|
+
bind: {text: data => `Discounted Total (10% off): ${data.discountedTotal.toFixed(2)}`}
|
360
|
+
}, {
|
361
|
+
module : Button,
|
362
|
+
handler: event => event.component.getStateProvider().data.price++,
|
363
|
+
text : 'Increase Price'
|
364
|
+
}, {
|
365
|
+
module : Button,
|
366
|
+
// Shorthand syntax. Less descriptive, but works fine too.
|
367
|
+
handler: event => event.component.data.quantity++,
|
368
|
+
text : 'Increase Quantity'
|
369
|
+
}],
|
370
|
+
layout: {ntype: 'vbox', align: 'start'}
|
371
|
+
}
|
372
|
+
}
|
373
|
+
MainView = Neo.setupClass(MainView);
|
374
|
+
```
|
375
|
+
This example demonstrates how formulas automatically react to changes in their dependencies.
|
376
|
+
|
377
|
+
* We define `price` and `quantity` in the `data` config.
|
378
|
+
The `total` formula computes `data.price * data.quantity`.
|
379
|
+
The `discountedTotal` formula then computes `data.total * 0.9`.
|
262
380
|
|
263
|
-
|
381
|
+
* When you click the "Increase Price" or "Increase Quantity" buttons, you'll observe that
|
382
|
+
`Total` and `Discounted Total` labels update automatically, showcasing the
|
383
|
+
effect-based reactivity of formulas.
|
264
384
|
|
265
385
|
### Dialog connecting to a Container
|
386
|
+
|
266
387
|
```javascript live-preview
|
267
388
|
import Controller from '../controller/Component.mjs';
|
268
389
|
import Dialog from '../dialog/Base.mjs';
|
@@ -383,9 +504,11 @@ MainView = Neo.setupClass(MainView);
|
|
383
504
|
```
|
384
505
|
|
385
506
|
## Class based State Providers
|
507
|
+
|
386
508
|
When your stateProviders contain many data props or need custom logic, you can easily move them into their own classes.
|
387
509
|
|
388
510
|
### Direct Bindings
|
511
|
+
|
389
512
|
```javascript live-preview
|
390
513
|
import Button from '../button/Base.mjs';
|
391
514
|
import Container from '../container/Base.mjs';
|
@@ -498,15 +621,10 @@ class MainViewStateProvider extends StateProvider {
|
|
498
621
|
static config = {
|
499
622
|
className: 'Guides.vm7.MainViewStateProvider',
|
500
623
|
|
501
|
-
data: {
|
502
|
-
myStoreCount: 0
|
503
|
-
},
|
504
|
-
|
505
624
|
stores: {
|
506
625
|
// Define a store using a class reference
|
507
626
|
mySharedStore: {
|
508
|
-
module : MyDataStore
|
509
|
-
listeners: {countChange: 'onMyStoreCountChange'}
|
627
|
+
module : MyDataStore
|
510
628
|
},
|
511
629
|
// Define another store using an inline configuration
|
512
630
|
anotherStore: {
|
@@ -524,10 +642,6 @@ class MainViewStateProvider extends StateProvider {
|
|
524
642
|
}
|
525
643
|
}
|
526
644
|
}
|
527
|
-
|
528
|
-
onMyStoreCountChange(data) {
|
529
|
-
this.data.myStoreCount = data.value // Reactive
|
530
|
-
}
|
531
645
|
}
|
532
646
|
MainViewStateProvider = Neo.setupClass(MainViewStateProvider);
|
533
647
|
|
@@ -557,7 +671,7 @@ class MainView extends Container {
|
|
557
671
|
module: Label,
|
558
672
|
style : {margin: 'auto'},
|
559
673
|
bind: {
|
560
|
-
text: data => `Count: ${data.
|
674
|
+
text: data => `Count: ${data.stores.mySharedStore.count}`
|
561
675
|
}
|
562
676
|
}, {
|
563
677
|
module: Button,
|
@@ -1 +1 @@
|
|
1
|
-
|
1
|
+
# Tables (Stores)
|
@@ -1,10 +1,12 @@
|
|
1
|
-
|
1
|
+
# Declarative VDOM with Effects
|
2
|
+
|
3
|
+
## A New Approach: Declarative VDOM with Effects
|
2
4
|
|
3
5
|
Neo.mjs v10 introduces a powerful new declarative pattern for defining a component's internal Virtual DOM (VDOM), serving as an alternative to the traditional imperative hook-based system. This approach, which leverages the new `Neo.core.Effect` class, allows developers to define a component's entire VDOM structure in a single, reactive function, similar to the `render()` method in React.
|
4
6
|
|
5
7
|
This guide will walk you through the new pattern, compare it to the classic approach, and explain when to use each.
|
6
8
|
|
7
|
-
|
9
|
+
## The Classic Pattern: Imperative Hooks
|
8
10
|
|
9
11
|
Let's look at the traditional way a component like `Neo.button.Base` defines and updates its VDOM.
|
10
12
|
|
@@ -61,7 +63,7 @@ afterSetPressed(value, oldValue) {
|
|
61
63
|
* **High Cognitive Load:** To understand the component's full rendering logic, a developer must find and read multiple, separate methods.
|
62
64
|
* **Error-Prone:** Forgetting to implement a hook for a new config is a common source of bugs.
|
63
65
|
|
64
|
-
|
66
|
+
## The New Pattern: Declarative VDOM with `Effect`
|
65
67
|
|
66
68
|
The new `EffectButton` PoC demonstrates a more modern, declarative approach.
|
67
69
|
|
@@ -71,11 +73,11 @@ Instead of fragmented hooks, the entire VDOM is generated within a `Neo.core.Eff
|
|
71
73
|
```javascript readonly
|
72
74
|
// button.Effect - The "Template Method"
|
73
75
|
createVdomEffect() {
|
74
|
-
return new Effect(
|
76
|
+
return new Effect(() => {
|
75
77
|
// The effect's only job is to get the config and trigger an update.
|
76
78
|
this._vdom = this.getVdomConfig();
|
77
79
|
this.update();
|
78
|
-
}
|
80
|
+
});
|
79
81
|
}
|
80
82
|
|
81
83
|
// The main VDOM builder
|
@@ -113,7 +115,7 @@ getVdomChildren() {
|
|
113
115
|
}
|
114
116
|
```
|
115
117
|
|
116
|
-
|
118
|
+
## The Power of Inheritance
|
117
119
|
|
118
120
|
A key challenge with a single render function is extensibility. The new pattern solves this by using a "Template Method" design. The main effect calls smaller, overridable builder methods.
|
119
121
|
|
@@ -148,7 +150,7 @@ class EffectTabButton extends EffectButton {
|
|
148
150
|
}
|
149
151
|
```
|
150
152
|
|
151
|
-
|
153
|
+
## When to Use Each Pattern: A Hybrid Approach
|
152
154
|
|
153
155
|
Neo.mjs v10 does not force you to choose one pattern over the other. Instead, it empowers you to use the right tool for the job.
|
154
156
|
|
@@ -161,6 +163,6 @@ Neo.mjs v10 does not force you to choose one pattern over the other. Instead, it
|
|
161
163
|
* You are building a highly complex, performance-critical component (e.g., a virtualized data grid or a canvas-based chart).
|
162
164
|
* You need to perform surgical, hand-tuned VDOM manipulations for maximum performance, bypassing a full recalculation.
|
163
165
|
|
164
|
-
|
166
|
+
## Conclusion
|
165
167
|
|
166
168
|
The new declarative VDOM pattern is a major leap forward for component development in Neo.mjs. It provides a more modern, readable, and robust way to build components, while the classic imperative pattern remains a powerful tool for fine-grained performance optimization. By understanding both, you can build sophisticated, high-performance applications with an exceptional developer experience.
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# Instance Lifecycle
|
2
|
+
|
1
3
|
Understanding the lifecycle of a class instance in Neo.mjs is crucial for building robust and predictable
|
2
4
|
applications. The framework provides a series of well-defined hooks that allow you to tap into different stages of an
|
3
5
|
instance's life, from its creation to its destruction.
|
@@ -292,4 +294,4 @@ With this pattern, the `columnPositions` collection is **not** created during th
|
|
292
294
|
instantiated the very first time some other code calls `this.columnPositions`.
|
293
295
|
|
294
296
|
Use the get-driven approach for non-essential or heavy nested instances to optimize performance and memory usage,
|
295
|
-
especially if they are only used in specific scenarios.
|
297
|
+
especially if they are only used in specific scenarios.
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# Main Thread Addons: Interacting with the Browser
|
2
|
+
|
1
3
|
Neo.mjs is multi-threaded. There are worker threads that handle data access, application logic, and
|
2
4
|
keeping track of DOM updates. Practically all your application logic is run in parallel in these
|
3
5
|
threads. However, anything that needs to actually reference or update the DOM (`window.document`),
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# Working with VDom
|
2
|
+
|
1
3
|
## A Comprehensive Guide to Custom Component Development
|
2
4
|
|
3
5
|
**Target Audience**: Developers building custom Neo.mjs components who need to work directly with the VDom layer for performance optimization, complex animations, or advanced UI patterns.
|
@@ -27,7 +29,7 @@ Neo.mjs VDom nodes are plain JavaScript objects that represent DOM elements.
|
|
27
29
|
cn : [], // Child nodes array (exclusive with html/text)
|
28
30
|
vtype : 'vnode', // VNode type: 'vnode', 'text', 'root'
|
29
31
|
static : false, // Exclude from delta updates (optimization)
|
30
|
-
removeDom: false, //
|
32
|
+
removeDom: false, // The recommended way to conditionally render nodes. true removes the element from the DOM while preserving the VDOM structure.
|
31
33
|
data : {custom: 'value'}, // data-* attributes
|
32
34
|
// Standard HTML attributes
|
33
35
|
disabled: true,
|
@@ -376,7 +378,31 @@ class DataList extends Component {
|
|
376
378
|
}
|
377
379
|
```
|
378
380
|
|
379
|
-
### 3.
|
381
|
+
### 3. Best Practice: Conditional Rendering via `removeDom`
|
382
|
+
|
383
|
+
For conditionally showing or hiding elements, the recommended and most robust pattern in Neo.mjs is to use the `removeDom`
|
384
|
+
property. This approach ensures **structural integrity** of your VDom tree, which is critical for performance and stability.
|
385
|
+
|
386
|
+
By keeping a static VDom structure and toggling the `removeDom` flag, you allow the framework's diffing engine to work
|
387
|
+
most efficiently. It can rely on the stable index of each child node, resulting in minimal and correct deltas. This also
|
388
|
+
ensures that internal framework features which traverse the VDOM tree (like `syncVdomIds`) function predictably.
|
389
|
+
|
390
|
+
#### The Anti-Pattern: Modifying the `cn` Array
|
391
|
+
|
392
|
+
Avoid dynamically adding or removing objects from the `cn` array. While it might seem intuitive to build the array based
|
393
|
+
on conditions, it leads to a structurally unstable VDom, unless items have their explicitly defined id.
|
394
|
+
|
395
|
+
This anti-pattern is problematic because:
|
396
|
+
1. It changes the length and indexes of the cn array between renders.
|
397
|
+
2. It confuses the diffing algorithm, which can lead to a "delta storm"—a cascade of inefficient and incorrect
|
398
|
+
`removeNode`, `insertNode`, and `moveNode` operations instead of a single, simple update.
|
399
|
+
3. It forces the developer to manually add stable ids to all sibling nodes to help the diffing algorithm keep its bearings,
|
400
|
+
which is an extra, error-prone step.
|
401
|
+
4. It breaks the contract of a stable VDOM structure, which can interfere with internal framework optimizations.
|
402
|
+
|
403
|
+
Always prefer the `removeDom` flag for predictable, performant, and robust components.
|
404
|
+
|
405
|
+
### 4. Complex VDom Transformations (e.g., 3D Animations)
|
380
406
|
|
381
407
|
For sophisticated UI patterns like 3D visualizations or complex dynamic layouts, you might imperatively calculate and apply VDom properties or even use `Neo.applyDeltas()` for maximum performance.
|
382
408
|
|
@@ -1,5 +1,6 @@
|
|
1
|
-
|
1
|
+
# Custom Events
|
2
2
|
|
3
|
+
As you read in the <a href="#/learn/Events">Getting Started > Events</a> topic, components, stores, and many other objects fire events.
|
3
4
|
|
4
5
|
```javascript live-preview
|
5
6
|
import Container from '../container/Base.mjs';
|
@@ -1,5 +1,6 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
# Other JavaScript Class Features
|
2
|
+
|
3
|
+
Neo.mjs uses standard modular JavaScript, so you're free to use other class features, like private members.
|
3
4
|
|
4
5
|
```javascript readonly
|
5
6
|
class Human extends Mammal {
|
@@ -27,7 +28,7 @@ class Human extends Mammal {
|
|
27
28
|
}
|
28
29
|
}
|
29
30
|
|
30
|
-
Neo.setupClass(Human);
|
31
|
+
Human = Neo.setupClass(Human);
|
31
32
|
|
32
33
|
const myPerson = Neo.create(Human, {
|
33
34
|
name: 'Herbert'
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# Classes, Properties, and Methods
|
2
|
+
|
1
3
|
Neo.mjs classes are standard JavaScript classes. Every source file
|
2
4
|
you write will be a class definition, extending some Neo.mjs
|
3
5
|
class.
|
@@ -13,8 +15,8 @@ class Mammal extends Base {
|
|
13
15
|
|
14
16
|
const myMammal = Neo.create(Mammal);
|
15
17
|
|
16
|
-
|
17
|
-
export default Mammal;
|
18
|
+
// Where Neo.mjs initializes the class and makes the class available elsewhere.
|
19
|
+
export default Neo.setupClass(Mammal);
|
18
20
|
```
|
19
21
|
|
20
22
|
In the example above, we're extending the Neo.mjs base class. The static
|
@@ -40,16 +42,14 @@ class Mammal extends Base {
|
|
40
42
|
}
|
41
43
|
|
42
44
|
const myMammal = Neo.create(Mammal);
|
43
|
-
console.log(myMammal.name);
|
45
|
+
console.log(myMammal.name); // Logs "Anonymous"
|
44
46
|
myMammal.name = 'Herbert';
|
45
|
-
console.log(myMammal.name);
|
46
|
-
|
47
|
-
Neo.setupClass(Mammal);
|
47
|
+
console.log(myMammal.name); // Logs "Herbert"
|
48
48
|
|
49
|
-
export default Mammal;
|
49
|
+
export default Neo.setupClass(Mammal);
|
50
50
|
```
|
51
51
|
|
52
|
-
In Neo.mjs, instance properties are usually added in the `static config` block
|
52
|
+
In Neo.mjs, instance properties are usually added in the `static config` block.</br>
|
53
53
|
The `static config` block does two things:
|
54
54
|
- It formally describes the properties API for your class.
|
55
55
|
- It lets Neo.mjs manage the initialization and lifecycle of those properties.
|
@@ -65,10 +65,9 @@ the instance, using the second argument to the `create` method.
|
|
65
65
|
const myMammal = Neo.create(Mammal, {
|
66
66
|
name: 'Creature'
|
67
67
|
});
|
68
|
-
console.log(myMammal.name);
|
68
|
+
console.log(myMammal.name); // Logs "Creature"
|
69
69
|
```
|
70
70
|
|
71
|
-
|
72
71
|
Since _you_ define those properties, you can
|
73
72
|
look for them in class methods and use them as needed.
|
74
73
|
Let's add a `speak()` method that uses the `name` property.
|
@@ -93,9 +92,7 @@ const myMammal = Neo.create(Mammal, {
|
|
93
92
|
|
94
93
|
myMammal.speak(); // Logs "Creature is grunting."
|
95
94
|
|
96
|
-
Neo.setupClass(Mammal);
|
97
|
-
|
98
|
-
export default Mammal;
|
95
|
+
export default Neo.setupClass(Mammal);
|
99
96
|
```
|
100
97
|
|
101
98
|
|