neo.mjs 10.0.0-beta.2 → 10.0.0-beta.4

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.
Files changed (52) hide show
  1. package/.github/RELEASE_NOTES/v10.0.0-beta.4.md +41 -0
  2. package/ServiceWorker.mjs +2 -2
  3. package/apps/form/view/FormPageContainer.mjs +2 -3
  4. package/apps/portal/index.html +1 -1
  5. package/apps/portal/view/ViewportController.mjs +1 -1
  6. package/apps/portal/view/home/FooterContainer.mjs +1 -1
  7. package/apps/portal/view/learn/ContentComponent.mjs +18 -11
  8. package/apps/portal/view/learn/MainContainerController.mjs +6 -6
  9. package/learn/README.md +9 -14
  10. package/learn/guides/datahandling/Collections.md +436 -0
  11. package/learn/guides/datahandling/Grids.md +621 -0
  12. package/learn/guides/datahandling/Records.md +287 -0
  13. package/learn/guides/{StateProviders.md → datahandling/StateProviders.md} +145 -1
  14. package/learn/guides/fundamentals/ExtendingNeoClasses.md +359 -0
  15. package/learn/guides/uibuildingblocks/CustomComponents.md +287 -0
  16. package/learn/guides/uibuildingblocks/Layouts.md +248 -0
  17. package/learn/guides/userinteraction/Forms.md +449 -0
  18. package/learn/guides/userinteraction/form_fields/ComboBox.md +241 -0
  19. package/learn/tree.json +63 -52
  20. package/package.json +2 -2
  21. package/resources/scss/src/apps/portal/learn/ContentComponent.scss +9 -0
  22. package/src/DefaultConfig.mjs +2 -2
  23. package/src/Neo.mjs +37 -29
  24. package/src/collection/Base.mjs +29 -2
  25. package/src/component/Base.mjs +6 -16
  26. package/src/controller/Base.mjs +87 -63
  27. package/src/core/Base.mjs +72 -17
  28. package/src/core/Compare.mjs +3 -13
  29. package/src/core/Config.mjs +139 -0
  30. package/src/core/ConfigSymbols.mjs +3 -0
  31. package/src/core/Util.mjs +3 -18
  32. package/src/data/RecordFactory.mjs +22 -3
  33. package/src/form/field/ComboBox.mjs +6 -1
  34. package/src/util/Function.mjs +52 -5
  35. package/src/vdom/Helper.mjs +7 -5
  36. package/test/siesta/tests/ReactiveConfigs.mjs +112 -0
  37. package/learn/guides/CustomComponents.md +0 -45
  38. package/learn/guides/Forms.md +0 -1
  39. package/learn/guides/Layouts.md +0 -1
  40. /package/learn/guides/{Tables.md → datahandling/Tables.md} +0 -0
  41. /package/learn/guides/{ApplicationBootstrap.md → fundamentals/ApplicationBootstrap.md} +0 -0
  42. /package/learn/guides/{ConfigSystemDeepDive.md → fundamentals/ConfigSystemDeepDive.md} +0 -0
  43. /package/learn/guides/{DeclarativeComponentTreesVsImperativeVdom.md → fundamentals/DeclarativeComponentTreesVsImperativeVdom.md} +0 -0
  44. /package/learn/guides/{InstanceLifecycle.md → fundamentals/InstanceLifecycle.md} +0 -0
  45. /package/learn/guides/{MainThreadAddons.md → fundamentals/MainThreadAddons.md} +0 -0
  46. /package/learn/guides/{Mixins.md → specificfeatures/Mixins.md} +0 -0
  47. /package/learn/guides/{MultiWindow.md → specificfeatures/MultiWindow.md} +0 -0
  48. /package/learn/guides/{PortalApp.md → specificfeatures/PortalApp.md} +0 -0
  49. /package/learn/guides/{ComponentsAndContainers.md → uibuildingblocks/ComponentsAndContainers.md} +0 -0
  50. /package/learn/guides/{WorkingWithVDom.md → uibuildingblocks/WorkingWithVDom.md} +0 -0
  51. /package/learn/guides/{events → userinteraction/events}/CustomEvents.md +0 -0
  52. /package/learn/guides/{events → userinteraction/events}/DomEvents.md +0 -0
@@ -0,0 +1,41 @@
1
+ ## Neo.mjs v10.0.0-beta.4 Release Notes
2
+
3
+ This beta release introduces a powerful, opt-in **Reactive Config System**, a foundational architectural enhancement that enables fine-grained, cross-instance state management and significantly improves the developer experience for building complex, interactive applications.
4
+
5
+ ### Core Framework & Features
6
+
7
+ The centerpiece of this release is the new reactive config system, internally named "Config Atoms". This system is fully opt-in and backward compatible, ensuring that existing applications continue to work without any changes.
8
+
9
+ * **New Reactive Config System ("Config Atoms")**:
10
+ * **Opt-in Reactivity**: By adding a trailing underscore (`_`) to a config property in its `static config` block (e.g., `myValue_`), the property becomes "reactive." It is automatically wrapped in a `Neo.core.Config` instance, which acts as an observable container for its value.
11
+ * **Cross-Instance State Sharing**: The new system exposes a `subscribe()` method on each reactive config, allowing components to listen for changes to a config on any other component instance. This enables a clean, decoupled, and highly efficient way to implement cross-component state synchronization.
12
+ ```javascript
13
+ // In ComponentA
14
+ const componentB = Neo.get('b');
15
+
16
+ // Subscribe to changes in componentB's 'items' config
17
+ this.cleanup = componentB.getConfig('items').subscribe((newValue, oldValue) => {
18
+ this.someOtherProperty = newValue; // Reactively update
19
+ });
20
+
21
+ // In ComponentA's destroy() method:
22
+ this.cleanup?.(); // Simple, clean, and prevents memory leaks.
23
+ ```
24
+ * **Fine-Grained Control (Future Foundation)**: While not fully implemented in this beta, the groundwork is laid for using config descriptors to define custom `mergeStrategy` and `isEqual` functions, which will provide even more control over config behavior in a future release.
25
+ * **Transactional Consistency**: The new system fully integrates with Neo.mjs's existing transactional update mechanism (`set()`), ensuring that `afterSet` hooks always have a consistent view of all pending config changes within a single operation.
26
+
27
+ ### Developer Experience
28
+
29
+ * **Simplified State Management**: The `subscribe()` API drastically simplifies the logic required for components to react to state changes in other parts of the application, reducing boilerplate and the need for complex event chains.
30
+ * **Improved Debugging**: The observable nature of reactive configs makes it easier to trace how and when state changes occur throughout your application.
31
+
32
+ ---
33
+
34
+ This release marks a significant step forward in the evolution of the Neo.mjs architecture. The new reactive config system provides a robust foundation for building the next generation of highly interactive and state-driven web applications.
35
+
36
+ ### Call To Action
37
+
38
+ We are incredibly excited for you to start experimenting with this powerful new feature!
39
+
40
+ * **Try Reactive Configs**: Start by making a config reactive by adding a `_` to its name in the `static config` block and explore the new possibilities with `getConfig().subscribe()`.
41
+ * **Share Your Feedback**: This is a foundational change, and your feedback is more critical than ever. Please share your experiences, report any issues, or suggest improvements via [GitHub Issues](https://github.com/neomjs/neo/issues) or our [Slack Channel](https://join.slack.com/t/neomjs/shared_invite/zt-6c50ueeu-3E1~M4T9xkNnb~M_prEEOA).
package/ServiceWorker.mjs CHANGED
@@ -20,9 +20,9 @@ class ServiceWorker extends ServiceBase {
20
20
  */
21
21
  singleton: true,
22
22
  /**
23
- * @member {String} version='10.0.0-beta.2'
23
+ * @member {String} version='10.0.0-beta.4'
24
24
  */
25
- version: '10.0.0-beta.2'
25
+ version: '10.0.0-beta.4'
26
26
  }
27
27
 
28
28
  /**
@@ -26,10 +26,9 @@ class FormPageContainer extends FormContainer {
26
26
  */
27
27
  style: {overflow: 'auto'},
28
28
  /**
29
- * @member {Object} _vdom
29
+ * @member {String} tag='div'
30
30
  */
31
- vdom:
32
- {cn: []} // using a div instead of a form tag
31
+ tag: 'div' // using a div instead of a form tag
33
32
  }
34
33
  }
35
34
 
@@ -16,7 +16,7 @@
16
16
  "@type": "Organization",
17
17
  "name": "Neo.mjs"
18
18
  },
19
- "datePublished": "2025-06-30",
19
+ "datePublished": "2025-07-04",
20
20
  "publisher": {
21
21
  "@type": "Organization",
22
22
  "name": "Neo.mjs"
@@ -50,7 +50,7 @@ class ViewportController extends Controller {
50
50
  '/examples/{itemId}': 'onExamplesRoute',
51
51
  '/home' : 'onHomeRoute',
52
52
  '/learn' : 'onLearnRoute',
53
- '/learn/{itemId}' : 'onLearnRoute',
53
+ '/learn/{*itemId}' : 'onLearnRoute',
54
54
  '/services' : 'onServicesRoute'
55
55
  },
56
56
  /**
@@ -107,7 +107,7 @@ class FooterContainer extends Container {
107
107
  }, {
108
108
  module: Component,
109
109
  cls : ['neo-version'],
110
- text : 'v10.0.0-beta.2'
110
+ text : 'v10.0.0-beta.4'
111
111
  }]
112
112
  }],
113
113
  /**
@@ -3,11 +3,12 @@ import LivePreview from '../../../../src/code/LivePreview.mjs';
3
3
  import {marked} from '../../../../node_modules/marked/lib/marked.esm.js';
4
4
 
5
5
  const
6
- labCloseRegex = /<!--\s*\/lab\s*-->/g,
7
- labOpenRegex = /<!--\s*lab\s*-->/g,
8
- regexLivePreview = /```(javascript|html|css|json)\s+live-preview\s*\n([\s\S]*?)\n\s*```/g,
9
- regexNeoComponent = /```json\s+neo-component\s*\n([\s\S]*?)\n\s*```/g,
10
- regexReadonly = /```(javascript|html|css|json)\s+readonly\s*\n([\s\S]*?)\n\s*```/g;
6
+ regexInlineCode = /`([^`]+)`/g,
7
+ regexLabClose = /<!--\s*\/lab\s*-->/g,
8
+ regexLabOpen = /<!--\s*lab\s*-->/g,
9
+ regexLivePreview = /```(javascript|html|css|json)\s+live-preview\s*\n([\s\S]*?)\n\s*```/g,
10
+ regexNeoComponent = /```json\s+neo-component\s*\n([\s\S]*?)\n\s*```/g,
11
+ regexReadonly = /```(javascript|html|css|json)\s+readonly\s*\n([\s\S]*?)\n\s*```/g;
11
12
 
12
13
  /**
13
14
  * @class Portal.view.learn.ContentComponent
@@ -233,10 +234,10 @@ class ContentComponent extends Component {
233
234
  */
234
235
  insertLabDivs(inputString) {
235
236
  // Replace <!-- lab --> with <div class="lab">
236
- inputString = inputString.replace(labOpenRegex, '<div class="lab">');
237
+ inputString = inputString.replace(regexLabOpen, '<div class="lab">');
237
238
 
238
239
  // Replace <!-- /lab --> with </div>
239
- inputString = inputString.replace(labCloseRegex, '</div>');
240
+ inputString = inputString.replace(regexLabClose, '</div>');
240
241
 
241
242
  return inputString
242
243
  }
@@ -307,7 +308,7 @@ class ContentComponent extends Component {
307
308
  replacementPromises.push(
308
309
  Neo.main.addon.HighlightJS.highlightAuto({html: code, windowId})
309
310
  .then(highlightedHtml => ({
310
- after: `<pre data-javascript id="pre-readonly-${Neo.core.IdGenerator.getId()}">${highlightedHtml}</pre>`,
311
+ after: `<pre data-javascript id="pre-readonly-${Neo.core.IdGenerator.getId()}">${highlightedHtml.trim()}</pre>`,
311
312
  token: token
312
313
  }))
313
314
  );
@@ -336,7 +337,7 @@ class ContentComponent extends Component {
336
337
  contentArray = content.split('\n'),
337
338
  i = 1,
338
339
  storeData = [],
339
- tag;
340
+ headline, sideNavTitle, tag;
340
341
 
341
342
  contentArray.forEach((line, index) => {
342
343
  tag = null;
@@ -352,9 +353,15 @@ class ContentComponent extends Component {
352
353
  }
353
354
 
354
355
  if (tag) {
355
- storeData.push({id: i, name: line, sourceId: me.id, tag});
356
+ // Convert backticks to <code> tags for the article headline tags
357
+ headline = line.replace(regexInlineCode, '<code>$1</code>');
356
358
 
357
- contentArray[index] = `<${tag} class="neo-${tag}" data-record-id="${i}">${line}</${tag}>`;
359
+ // Markdown titles can contain inline code, which we don't want to display inside PageSectionsList.
360
+ sideNavTitle = line.replaceAll('`', '');
361
+
362
+ storeData.push({id: i, name: sideNavTitle, sourceId: me.id, tag});
363
+
364
+ contentArray[index] = `<${tag} class="neo-${tag}" data-record-id="${i}">${headline}</${tag}>`;
358
365
 
359
366
  i++
360
367
  }
@@ -17,8 +17,8 @@ class MainContainerController extends Controller {
17
17
  * @member {Object} routes
18
18
  */
19
19
  routes: {
20
- '/learn' : 'onRouteDefault',
21
- '/learn/{itemId}': 'onRouteLearnItem'
20
+ '/learn' : 'onRouteDefault',
21
+ '/learn/{*itemId}': 'onRouteLearnItem'
22
22
  }
23
23
  }
24
24
 
@@ -118,7 +118,7 @@ class MainContainerController extends Controller {
118
118
  */
119
119
  onRouteDefault(data) {
120
120
  if (!this.getStateProvider().data.currentPageRecord) {
121
- this.onRouteLearnItem({itemId: 'benefits.Introduction'})
121
+ this.onRouteLearnItem({itemId: 'benefits/Introduction'})
122
122
  }
123
123
  }
124
124
 
@@ -126,15 +126,15 @@ class MainContainerController extends Controller {
126
126
  * @param {Object} data
127
127
  * @param {String} data.itemId
128
128
  */
129
- onRouteLearnItem(data) {
129
+ onRouteLearnItem({itemId}) {
130
130
  let stateProvider = this.getStateProvider(),
131
131
  store = stateProvider.getStore('contentTree');
132
132
 
133
133
  if (store.getCount() > 0) {
134
- stateProvider.data.currentPageRecord = store.get(data.itemId)
134
+ stateProvider.data.currentPageRecord = store.get(itemId)
135
135
  } else {
136
136
  store.on({
137
- load : () => {stateProvider.data.currentPageRecord = store.get(data.itemId)},
137
+ load : () => {stateProvider.data.currentPageRecord = store.get(itemId)},
138
138
  delay: 10,
139
139
  once : true
140
140
  })
package/learn/README.md CHANGED
@@ -16,7 +16,7 @@ Neo.mjs is the **first and only JavaScript framework** that achieves:
16
16
  ## 🌐 Best Learning Experience
17
17
 
18
18
  **For the optimal learning experience, visit:**
19
- **https://neomjs.com/dist/production/apps/portal/index.html#/learn**
19
+ **[neomjs.com#/learn](https://neomjs.com/dist/production/apps/portal/index.html#/learn)**
20
20
 
21
21
  The web portal provides:
22
22
  - ✨ **Enhanced Markdown rendering** with syntax highlighting
@@ -25,25 +25,20 @@ The web portal provides:
25
25
  - 📱 **Responsive layout** optimized for learning
26
26
  - 🔗 **Interactive navigation** between topics
27
27
 
28
- ## 📚 What's Inside
29
-
30
- - **[Benefits](./benefits/)** - Why choose Neo.mjs and its revolutionary OMT advantages
31
- - **[Getting Started](./gettingstarted/)** - Step-by-step introduction to Off-Main-Thread development
32
- - **[Guides](./guides/)** - In-depth technical documentation on advanced concepts
33
- - **[Tutorials](./tutorials/)** - Hands-on projects and practical examples
34
- - **[JavaScript Classes](./javascript/)** - JavaScript fundamentals for Neo.mjs development
35
-
36
28
  ## 🎯 Learning Path
37
29
 
38
- 1. Start with [Benefits](./benefits/) to understand Neo.mjs's revolutionary OMT approach
39
- 2. Follow [Getting Started](./gettingstarted/) for Off-Main-Thread development basics
40
- 3. Explore [Guides](./guides/) for comprehensive technical knowledge
41
- 4. Practice with [Tutorials](./tutorials/) for hands-on experience
30
+ For a structured and effective learning experience, we recommend the following progression:
31
+
32
+ 1. Start with [Benefits](./benefits/) to understand Neo.mjs's revolutionary OMT approach
33
+ 2. Follow [Getting Started](./gettingstarted/) for Off-Main-Thread development basics
34
+ 3. Explore [Guides](./guides/) for comprehensive technical knowledge
35
+ 4. Practice with [Tutorials](./tutorials/) for hands-on experience
36
+ 5. Review [JavaScript Classes](./javascript/) for JavaScript fundamentals relevant to Neo.mjs development
42
37
 
43
38
  ## 📖 Reading Options
44
39
 
45
40
  - **🌐 Web Portal** (Recommended): Enhanced experience with live previews
46
- → [neomjs.com/learn](https://neomjs.com/dist/production/apps/portal/index.html#/learn)
41
+ → [neomjs.com#/learn](https://neomjs.com/dist/production/apps/portal/index.html#/learn)
47
42
  - **📁 GitHub**: Raw markdown files for quick reference or offline reading
48
43
  - **💻 Local**: Clone the repo and browse files directly
49
44