neo.mjs 10.0.2 → 10.1.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.
@@ -0,0 +1,17 @@
1
+ **Neo.mjs v10.1.0 Release Notes**
2
+
3
+ This release includes important fixes and minor improvements, primarily focusing on VDOM optimization, collection performance, and selection model improvements.
4
+
5
+ **Key Updates:**
6
+
7
+ * **VDOM Optimization & `neo-ignore` Refinement (Addresses #7114):**
8
+ The internal handling of the `neo-ignore` flag has been significantly improved. Previously, `neo-ignore` could interfere with the VDOM's structural integrity, potentially leading to rendering anomalies, **especially in complex layouts like grids, where elements might overlap**. Now, a dedicated `neoIgnore: true` flag is added to VDOM nodes, preserving the original `componentId` and `id`. This ensures the VDOM engine can correctly identify and skip sub-trees during diffing, leading to more robust and efficient asymmetric VDOM updates and resolving visual rendering issues **such as those observed in grid components**.
9
+
10
+ * **Collection Performance Enhancements (Addresses #7115):**
11
+ Several methods within `src/collection/Base.mjs` (e.g., `clear`, `findBy`, `pop`, `remove`) have been optimized by replacing `this.getCount()` method calls with direct access to `this.count`. This change streamlines collection operations, leading to improved performance.
12
+
13
+ * **Enhanced Selection Model (Addresses #7116):**
14
+ The `src/selection/Model.mjs` has been updated to provide more comprehensive data during selection changes. A new `getController()` method has been added, and the `selectionChange` event now includes the `records` array, offering richer context for selection handling and better integration with view controllers.
15
+
16
+ * **Minor Fixes & Improvements (Addresses #7117):**
17
+ This release also includes minor cleanups and documentation improvements, such as an updated JSDoc comment in `src/grid/Body.mjs` and the removal of a debug `console.log` statement in `src/main/DeltaUpdates.mjs`.
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.2'
23
+ * @member {String} version='10.1.0'
24
24
  */
25
- version: '10.0.2'
25
+ version: '10.1.0'
26
26
  }
27
27
 
28
28
  /**
@@ -16,7 +16,7 @@
16
16
  "@type": "Organization",
17
17
  "name": "Neo.mjs"
18
18
  },
19
- "datePublished": "2025-07-26",
19
+ "datePublished": "2025-07-27",
20
20
  "publisher": {
21
21
  "@type": "Organization",
22
22
  "name": "Neo.mjs"
@@ -108,7 +108,7 @@ class FooterContainer extends Container {
108
108
  }, {
109
109
  module: Component,
110
110
  cls : ['neo-version'],
111
- text : 'v10.0.2'
111
+ text : 'v10.1.0'
112
112
  }]
113
113
  }],
114
114
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name" : "neo.mjs",
3
- "version" : "10.0.2",
3
+ "version" : "10.1.0",
4
4
  "description" : "Neo.mjs: The multi-threaded UI framework for building ultra-fast, desktop-like web applications with uncompromised responsiveness, inherent security, and a transpilation-free dev mode.",
5
5
  "type" : "module",
6
6
  "repository" : {
@@ -299,12 +299,12 @@ const DefaultConfig = {
299
299
  useVdomWorker: true,
300
300
  /**
301
301
  * buildScripts/injectPackageVersion.mjs will update this value
302
- * @default '10.0.2'
302
+ * @default '10.1.0'
303
303
  * @memberOf! module:Neo
304
304
  * @name config.version
305
305
  * @type String
306
306
  */
307
- version: '10.0.2'
307
+ version: '10.1.0'
308
308
  };
309
309
 
310
310
  Object.assign(DefaultConfig, {
@@ -412,7 +412,7 @@ class Collection extends Base {
412
412
  * Removes all items and clears the map
413
413
  */
414
414
  clear() {
415
- this.splice(0, this.getCount())
415
+ this.splice(0, this.count)
416
416
  }
417
417
 
418
418
  /**
@@ -429,7 +429,7 @@ class Collection extends Base {
429
429
  clearSilent() {
430
430
  let me = this;
431
431
 
432
- me._items.splice(0, me.getCount());
432
+ me._items.splice(0, me.count);
433
433
  me.map.clear()
434
434
  }
435
435
 
@@ -817,10 +817,10 @@ class Collection extends Base {
817
817
  * @param {Object} fn.item The current collection item
818
818
  * @param {Object} scope=this The scope in which the passed function gets executed
819
819
  * @param {Number} start=0 The start index
820
- * @param {Number} end=this.getCount() The end index (up to, last value excluded)
820
+ * @param {Number} end=this.count The end index (up to, last value excluded)
821
821
  * @returns {Array} Returns an empty Array in case no items are found
822
822
  */
823
- findBy(fn, scope=this, start=0, end=this.getCount()) {
823
+ findBy(fn, scope=this, start=0, end=this.count) {
824
824
  let me = this,
825
825
  items = [],
826
826
  i = start;
@@ -1041,7 +1041,7 @@ class Collection extends Base {
1041
1041
  * @returns {Object}
1042
1042
  */
1043
1043
  last() {
1044
- return this._items[this.getCount() -1]
1044
+ return this._items[this.count -1]
1045
1045
  }
1046
1046
 
1047
1047
  /**
@@ -1102,7 +1102,7 @@ class Collection extends Base {
1102
1102
  * @returns {Object} The removed element from the collection; undefined if the collection is empty.
1103
1103
  */
1104
1104
  pop() {
1105
- let mutation = this.splice(this.getCount() -1, 1);
1105
+ let mutation = this.splice(this.count -1, 1);
1106
1106
  return mutation.removedItems[0]
1107
1107
  }
1108
1108
 
@@ -1122,7 +1122,7 @@ class Collection extends Base {
1122
1122
  */
1123
1123
  remove(key) {
1124
1124
  this.splice(0, Array.isArray(key) ? key : [key]);
1125
- return this.getCount()
1125
+ return this.count
1126
1126
  }
1127
1127
 
1128
1128
  /**
@@ -1132,7 +1132,7 @@ class Collection extends Base {
1132
1132
  */
1133
1133
  removeAt(index) {
1134
1134
  this.splice(index, 1);
1135
- return this.getCount()
1135
+ return this.count
1136
1136
  }
1137
1137
 
1138
1138
  /**
@@ -1310,7 +1310,7 @@ class Collection extends Base {
1310
1310
  */
1311
1311
  unshift(item) {
1312
1312
  this.splice(0, 0, item);
1313
- return this.getCount()
1313
+ return this.count
1314
1314
  }
1315
1315
  }
1316
1316
 
package/src/grid/Body.mjs CHANGED
@@ -954,7 +954,7 @@ class GridBody extends Component {
954
954
  /**
955
955
  * @param {Object} data
956
956
  * @param {Object[]} data.fields Each field object contains the keys: name, oldValue, value
957
- * @param {Neo.data.Model} data.model The model instance of the changed record
957
+ * @param {Neo.data.Model} data.model The model instance of the changed record
958
958
  * @param {Object} data.record
959
959
  */
960
960
  onStoreRecordChange({fields, record}) {
@@ -370,10 +370,6 @@ class DeltaUpdates extends Base {
370
370
  let me = this,
371
371
  node = DomAccess.getElementOrBody(delta.id);
372
372
 
373
- if (!node) {
374
- console.log('node not found', delta.id);
375
- }
376
-
377
373
  if (node) {
378
374
  Object.entries(delta).forEach(([prop, value]) => {
379
375
  switch (prop) {
@@ -157,6 +157,14 @@ class Model extends Base {
157
157
  super.destroy(...args)
158
158
  }
159
159
 
160
+ /**
161
+ * Important for mapping listeners to view controllers
162
+ * @returns {Neo.controller.Component|null}
163
+ */
164
+ getController() {
165
+ return this.view.getController()
166
+ }
167
+
160
168
  /**
161
169
  * @returns {Array} this.items
162
170
  */
@@ -226,8 +234,9 @@ class Model extends Base {
226
234
  items = [items]
227
235
  }
228
236
 
229
- let me = this,
230
- {view} = me;
237
+ let me = this,
238
+ {view} = me,
239
+ records = [...items]; // Potential records
231
240
 
232
241
  // We hold vdom ids for now, so all incoming selections must be converted.
233
242
  items = items.map(item => item.isRecord ? view.getItemId(item) : Neo.isObject(item) ? item.id : item);
@@ -256,6 +265,7 @@ class Model extends Base {
256
265
  view.onSelect?.(items);
257
266
 
258
267
  me.fire('selectionChange', {
268
+ records,
259
269
  selection: itemCollection
260
270
  })
261
271
  }
@@ -51,7 +51,7 @@ class TreeBuilder extends Base {
51
51
  if (currentItem.componentId) {
52
52
  // Prune the branch only if we are at the boundary AND the child is not part of a merged update
53
53
  if (depth === 1 && !mergedChildIds?.has(currentItem.componentId)) {
54
- output[childKey].push({componentId: 'neo-ignore', id: item.id || item.componentId});
54
+ output[childKey].push({...currentItem, neoIgnore: true});
55
55
  return // Stop processing this branch
56
56
  }
57
57
  // Expand the branch if it's part of a merged update, or if the depth requires it
@@ -255,7 +255,8 @@ class Helper extends Base {
255
255
  // Case 2: Both nodes are placeholders for the same component
256
256
  (childNode.componentId && childNode.componentId === oldChildNode.componentId)
257
257
  )) {
258
- if (childNode.componentId === 'neo-ignore') {
258
+ if (childNode.neoIgnore) {
259
+ delete childNode.neoIgnore;
259
260
  continue
260
261
  }
261
262