neo.mjs 7.7.0 → 7.9.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.
Files changed (58) hide show
  1. package/apps/ServiceWorker.mjs +2 -2
  2. package/apps/portal/index.html +1 -1
  3. package/apps/portal/neo-config.json +1 -0
  4. package/apps/portal/view/ViewportController.mjs +20 -4
  5. package/apps/portal/view/home/FooterContainer.mjs +1 -1
  6. package/apps/portal/view/learn/{ContentView.mjs → ContentComponent.mjs} +98 -38
  7. package/apps/portal/view/learn/CubeLayoutButton.mjs +77 -0
  8. package/apps/portal/view/learn/MainContainerController.mjs +2 -1
  9. package/apps/portal/view/learn/PageContainer.mjs +4 -4
  10. package/apps/shareddialog/view/DemoDialog.mjs +2 -10
  11. package/apps/shareddialog/view/MainContainerController.mjs +107 -105
  12. package/buildScripts/webpack/json/myApps.template.json +1 -1
  13. package/examples/ServiceWorker.mjs +2 -2
  14. package/examples/table/nestedRecordFields/EditUserDialog.mjs +127 -0
  15. package/examples/table/nestedRecordFields/MainContainer.mjs +113 -0
  16. package/examples/table/nestedRecordFields/MainContainerModel.mjs +61 -0
  17. package/examples/table/nestedRecordFields/MainModel.mjs +41 -0
  18. package/examples/table/nestedRecordFields/MainStore.mjs +54 -0
  19. package/examples/table/nestedRecordFields/app.mjs +6 -0
  20. package/examples/table/nestedRecordFields/index.html +11 -0
  21. package/examples/table/nestedRecordFields/neo-config.json +6 -0
  22. package/package.json +4 -4
  23. package/resources/data/deck/learnneo/pages/Welcome.md +1 -1
  24. package/resources/data/deck/learnneo/pages/benefits/FormsEngine.md +1 -1
  25. package/resources/data/deck/learnneo/pages/guides/PortalApp.md +35 -0
  26. package/resources/data/deck/learnneo/tree.json +1 -0
  27. package/resources/scss/src/apps/portal/learn/PageContainer.scss +5 -0
  28. package/src/DefaultConfig.mjs +2 -2
  29. package/src/collection/Base.mjs +4 -3
  30. package/src/container/Base.mjs +12 -7
  31. package/src/data/Model.mjs +0 -7
  32. package/src/data/RecordFactory.mjs +82 -61
  33. package/src/data/Store.mjs +7 -0
  34. package/src/draggable/DragProxyComponent.mjs +10 -20
  35. package/src/form/field/CheckBox.mjs +12 -7
  36. package/src/form/field/ComboBox.mjs +8 -7
  37. package/src/grid/View.mjs +2 -2
  38. package/src/list/Base.mjs +1 -1
  39. package/src/main/addon/Navigator.mjs +34 -32
  40. package/src/main/addon/WindowPosition.mjs +9 -11
  41. package/src/model/Component.mjs +10 -1
  42. package/src/plugin/Resizable.mjs +12 -6
  43. package/src/tab/Container.mjs +5 -1
  44. package/src/table/View.mjs +31 -15
  45. package/src/table/header/Button.mjs +33 -18
  46. package/test/siesta/siesta.js +1 -0
  47. package/test/siesta/tests/ManagerInstance.mjs +35 -0
  48. package/apps/krausest/README.md +0 -3
  49. package/apps/krausest/TableCollection.mjs +0 -46
  50. package/apps/krausest/app.mjs +0 -8
  51. package/apps/krausest/css/currentStyle.css +0 -2
  52. package/apps/krausest/css/main.css +0 -26
  53. package/apps/krausest/index.html +0 -12
  54. package/apps/krausest/neo-config.json +0 -10
  55. package/apps/krausest/view/MainComponent.mjs +0 -122
  56. package/apps/krausest/view/MainComponentController.mjs +0 -33
  57. package/apps/krausest/view/TableComponent.mjs +0 -152
  58. /package/resources/scss/src/apps/portal/learn/{ContentView.scss → ContentComponent.scss} +0 -0
@@ -0,0 +1,41 @@
1
+ import Model from '../../../src/data/Model.mjs';
2
+
3
+ /**
4
+ * @class Neo.examples.table.nestedRecordFields.MainModel
5
+ * @extends Neo.data.Model
6
+ */
7
+ class MainModel extends Model {
8
+ static config = {
9
+ className: 'Neo.examples.table.container.MainModel',
10
+
11
+ fields: [{
12
+ name: 'annotations',
13
+ type: 'Object',
14
+
15
+ fields: [{
16
+ name : 'annotations.selected',
17
+ type : 'Boolean',
18
+ defaultValue: false
19
+ }]
20
+ }, {
21
+ name: 'country',
22
+ type: 'String'
23
+ }, {
24
+ name: 'githubId',
25
+ type: 'String'
26
+ }, {
27
+ name: 'user',
28
+ type: 'Object',
29
+
30
+ fields: [{
31
+ name: 'user.firstname',
32
+ type: 'String'
33
+ }, {
34
+ name: 'user.lastname',
35
+ type: 'String'
36
+ }]
37
+ }]
38
+ }
39
+ }
40
+
41
+ export default Neo.setupClass(MainModel);
@@ -0,0 +1,54 @@
1
+ import Model from './MainModel.mjs';
2
+ import Store from '../../../src/data/Store.mjs';
3
+
4
+ /**
5
+ * @class Neo.examples.table.nestedRecordFields.MainStore
6
+ * @extends Neo.data.Store
7
+ */
8
+ class MainStore extends Store {
9
+ static config = {
10
+ className : 'Neo.examples.table.container.MainStore',
11
+ keyProperty: 'githubId',
12
+ model : Model,
13
+
14
+ data: [{
15
+ country : 'DE',
16
+ githubId: 'tobiu',
17
+
18
+ user: {
19
+ firstname: 'Tobias',
20
+ lastname : 'Uhlig'
21
+ }
22
+ }, {
23
+ annotations: {
24
+ selected: true
25
+ },
26
+
27
+ country : 'US',
28
+ githubId: 'rwaters',
29
+
30
+ user: {
31
+ firstname: 'Rich',
32
+ lastname : 'Waters'
33
+ }
34
+ }, {
35
+ country : 'DE',
36
+ githubId: 'mrsunshine',
37
+
38
+ user: {
39
+ firstname: 'Nils',
40
+ lastname : 'Dehl'
41
+ }
42
+ }, {
43
+ country : 'US',
44
+ githubId: 'camtnbikerrwc',
45
+
46
+ user: {
47
+ firstname: 'Gerard',
48
+ lastname : 'Horan'
49
+ }
50
+ }]
51
+ }
52
+ }
53
+
54
+ export default Neo.setupClass(MainStore);
@@ -0,0 +1,6 @@
1
+ import MainContainer from './MainContainer.mjs';
2
+
3
+ export const onStart = () => Neo.app({
4
+ mainView: MainContainer,
5
+ name : 'Neo.examples.table.nestedRecordFields'
6
+ });
@@ -0,0 +1,11 @@
1
+ <!DOCTYPE HTML>
2
+ <html>
3
+ <head>
4
+ <meta name="viewport" content="width=device-width, initial-scale=1">
5
+ <meta charset="UTF-8">
6
+ <title>Neo Table: Nested Record Fields</title>
7
+ </head>
8
+ <body>
9
+ <script src="../../../src/MicroLoader.mjs" type="module"></script>
10
+ </body>
11
+ </html>
@@ -0,0 +1,6 @@
1
+ {
2
+ "appPath" : "examples/table/nestedRecordFields/app.mjs",
3
+ "basePath" : "../../../",
4
+ "environment": "development",
5
+ "mainPath" : "./Main.mjs"
6
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "neo.mjs",
3
- "version": "7.7.0",
3
+ "version": "7.9.0",
4
4
  "description": "The webworkers driven UI framework",
5
5
  "type": "module",
6
6
  "repository": {
@@ -54,16 +54,16 @@
54
54
  "envinfo": "^7.14.0",
55
55
  "fs-extra": "^11.2.0",
56
56
  "highlightjs-line-numbers.js": "^2.8.0",
57
- "inquirer": "^10.2.2",
57
+ "inquirer": "^11.0.2",
58
58
  "marked": "^14.1.2",
59
59
  "monaco-editor": "0.50.0",
60
60
  "neo-jsdoc": "1.0.1",
61
61
  "neo-jsdoc-x": "1.0.5",
62
62
  "postcss": "^8.4.47",
63
- "sass": "^1.79.2",
63
+ "sass": "^1.79.3",
64
64
  "siesta-lite": "5.5.2",
65
65
  "url": "^0.11.4",
66
- "webpack": "^5.94.0",
66
+ "webpack": "^5.95.0",
67
67
  "webpack-cli": "^5.1.4",
68
68
  "webpack-dev-server": "^5.1.0",
69
69
  "webpack-hook-plugin": "^1.0.7",
@@ -3,7 +3,7 @@ Welcome to Neo.mjs! This set of topics contains information to help you use Neo.
3
3
 
4
4
  ## Topics
5
5
 
6
- ### Why Neo?
6
+ ### Benefits
7
7
 
8
8
  Describes technical and business reasons for using Neo.mjs
9
9
 
@@ -1,7 +1,7 @@
1
1
  ## Forms include a State-Provider
2
2
 
3
3
  You do not need to define a state tree on your own.
4
- It if sufficient to just use namespaces inside the `name` attribute of each field.
4
+ It is sufficient to just use namespaces inside the `name` attribute of each field.
5
5
 
6
6
  <pre data-neo>
7
7
  import Button from '../button/Base.mjs';
@@ -0,0 +1,35 @@
1
+ ## Study the Code
2
+
3
+ As you hopefully have noticed by now, this entire multi-window app is created based on Neo.mjs.
4
+
5
+ You can learn a lot by studying the code-base carefully:
6
+ <a target="_blank" href="https://github.com/neomjs/neo/tree/dev/apps/portal">Portal App Code</a>
7
+
8
+ Please give us a heads-up, in case there are specific topics which you would like to see
9
+ getting covered here.
10
+
11
+ ## Easter Eggs
12
+
13
+ Every good app needs to have some meaningful Easter eggs.
14
+
15
+ ### Examples: Resort TabHeaderButtons via Drag&Drop
16
+
17
+ Did you notice that you can resort the Tabs inside <a href="#/examples">Examples</a>?
18
+
19
+ After re-sorting, the routing and the tab.Strip animations will still work. Enjoy!
20
+
21
+ ### Switch the main navigation layout to an animated Cube
22
+
23
+ Fair warning: this animated layout does require some advanced GPU processing power.
24
+ At the moment, it performs best using Firefox.
25
+
26
+ The setting will get stored inside the LocalStorage,
27
+ so you will need to click the following Button a 2nd time to deactivate it again.
28
+ Or you can clear the LocalStorage manually.</br></br>
29
+
30
+ <pre data-neo-component>
31
+ {
32
+ "className": "Portal.view.learn.CubeLayoutButton",
33
+ "style" : {"margin": 0}
34
+ }
35
+ </pre>
@@ -32,6 +32,7 @@
32
32
  {"name": "Events", "parentId": "InDepth", "isLeaf": false, "id": "GuideEvents"},
33
33
  {"name": "Custom Events", "parentId": "GuideEvents", "id": "guides.events.CustomEvents"},
34
34
  {"name": "DOM Events", "parentId": "GuideEvents", "id": "guides.events.DomEvents"},
35
+ {"name": "Portal App", "parentId": "InDepth", "id": "guides.PortalApp"},
35
36
  {"name": "Tables (Stores)", "parentId": "InDepth", "id": "guides.Tables", "hidden": true},
36
37
  {"name": "Multi-Window Applications", "parentId": "InDepth", "id": "guides.MultiWindow", "hidden": true},
37
38
  {"name": "Main Thread Addons", "parentId": "InDepth", "isLeaf": false, "id": "MainThreadAddons", "hidden": true},
@@ -14,6 +14,11 @@
14
14
  padding : 0 1rem;
15
15
  }
16
16
 
17
+
18
+ @media (min-width: 1297px) {
19
+ padding: 0 0 0 3rem;
20
+ }
21
+
17
22
  .neo-button {
18
23
  flex : 1 !important;
19
24
  height : 75px;
@@ -262,12 +262,12 @@ const DefaultConfig = {
262
262
  useVdomWorker: true,
263
263
  /**
264
264
  * buildScripts/injectPackageVersion.mjs will update this value
265
- * @default '7.7.0'
265
+ * @default '7.9.0'
266
266
  * @memberOf! module:Neo
267
267
  * @name config.version
268
268
  * @type String
269
269
  */
270
- version: '7.7.0'
270
+ version: '7.9.0'
271
271
  };
272
272
 
273
273
  Object.assign(DefaultConfig, {
@@ -990,12 +990,13 @@ class Base extends CoreBase {
990
990
  }
991
991
 
992
992
  /**
993
- * Helper method to check if a given value is either an object or a neo data record
993
+ * Helper method to check if a given input is either object-like or a key
994
994
  * @param {*} value
995
- * @returns {Boolean}
995
+ * @returns {Boolean} returns true for object-like values
996
996
  */
997
997
  isItem(value) {
998
- return Neo.isObject(value) || Neo.isRecord(value)
998
+ // We can not use Neo.isObject() || Neo.isRecord(), since collections can store neo instances too.
999
+ return typeof value === 'object'
999
1000
  }
1000
1001
 
1001
1002
  /**
@@ -87,7 +87,10 @@ class Base extends Component {
87
87
  */
88
88
  items_: [],
89
89
  /**
90
- * @member {Object} layout_={ntype: 'vbox', align: 'stretch'}
90
+ * It is crucial to define a layout before the container does get rendered.
91
+ * Meaning: onConstructed() is the latest life-cycle point.
92
+ * You can use layout: 'base', in case you do not need a layout at all.
93
+ * @member {Object|String|null} layout_={ntype: 'vbox', align: 'stretch'}
91
94
  */
92
95
  layout_: {
93
96
  ntype: 'vbox',
@@ -135,7 +138,7 @@ class Base extends Component {
135
138
  }
136
139
 
137
140
  /**
138
- * @param {Neo.layout.Base} value
141
+ * @param {Neo.layout.Base|null} value
139
142
  * @param {Neo.layout.Base|null} oldValue
140
143
  * @protected
141
144
  */
@@ -144,15 +147,15 @@ class Base extends Component {
144
147
 
145
148
  if (me.rendered) {
146
149
  oldValue?.removeRenderAttributes();
147
- value.applyRenderAttributes();
150
+ value?.applyRenderAttributes();
148
151
 
149
152
  me.items.forEach((item, index) => {
150
153
  oldValue?.removeChildAttributes(item, index);
151
- value.applyChildAttributes(item, index)
152
- });
153
-
154
- oldValue?.destroy()
154
+ value?.applyChildAttributes(item, index)
155
+ })
155
156
  }
157
+
158
+ oldValue?.destroy?.()
156
159
  }
157
160
 
158
161
  /**
@@ -419,6 +422,8 @@ class Base extends Component {
419
422
  * @param {Boolean} [silent=false] true to update the vdom silently (useful for destroying multiple child items in a row)
420
423
  */
421
424
  destroy(updateParentVdom=false, silent=false) {
425
+ this.layout?.destroy();
426
+
422
427
  this.items?.forEach(item => {
423
428
  item.destroy?.(false, true)
424
429
  });
@@ -38,13 +38,6 @@ class Model extends Base {
38
38
  trackModifiedFields: false
39
39
  }
40
40
 
41
- /**
42
- * A property set in all data records so that they are easily identifiable.
43
- * @property {Boolean} isRecord=true
44
- * @readonly
45
- */
46
- isRecord = true
47
-
48
41
  /**
49
42
  * Finds a field config by a given field name
50
43
  * @param {String} name
@@ -16,11 +16,6 @@ class RecordFactory extends Base {
16
16
  * @protected
17
17
  */
18
18
  className: 'Neo.data.RecordFactory',
19
- /**
20
- * @member {Boolean} singleton=true
21
- * @protected
22
- */
23
- singleton: true,
24
19
  /**
25
20
  * The internal record prefix for original field values.
26
21
  * Only used in case the model has trackModifiedFields set to true.
@@ -30,7 +25,84 @@ class RecordFactory extends Base {
30
25
  /**
31
26
  * @member {String} recordNamespace='Neo.data.record'
32
27
  */
33
- recordNamespace: 'Neo.data.record'
28
+ recordNamespace: 'Neo.data.record',
29
+ /**
30
+ * @member {Boolean} singleton=true
31
+ * @protected
32
+ */
33
+ singleton: true
34
+ }
35
+
36
+ /**
37
+ * @param {Object} data
38
+ * @param {Object} data.config
39
+ * @param {Object} data.field
40
+ * @param {Neo.data.RecordFactory} data.me
41
+ * @param {Neo.data.Model} data.model
42
+ * @param {String} data.path=''
43
+ */
44
+ createField({config, field, me, model, path=''}) {
45
+ let value = Neo.ns(field.mapping || field.name, false, config),
46
+ fieldName = field.name.split('.').pop(),
47
+ symbol = Symbol.for(fieldName),
48
+ fieldPath, parsedValue, properties;
49
+
50
+ if (field.fields) {
51
+ field.fields.forEach(childField => {
52
+ fieldPath = path.split('.');
53
+ fieldPath = fieldPath.filter(Boolean);
54
+ fieldPath.push(field.name);
55
+
56
+ this.createField({config, field: childField, me, model, path: fieldPath.join('.')})
57
+ })
58
+ } else {
59
+ if (value === undefined && Object.hasOwn(field, 'defaultValue')) {
60
+ value = field.defaultValue
61
+ }
62
+
63
+ parsedValue = instance.parseRecordValue(me, field, value, config);
64
+
65
+ properties = {
66
+ [symbol]: {
67
+ value : Neo.clone(parsedValue, true),
68
+ writable: true
69
+ },
70
+ [fieldName]: {
71
+ configurable: true,
72
+ enumerable : true,
73
+ get() {
74
+ return this[symbol]
75
+ },
76
+ set(value) {
77
+ let oldValue = this[symbol];
78
+
79
+ value = instance.parseRecordValue(me, field, value);
80
+
81
+ if (!Neo.isEqual(value, oldValue)) {
82
+ this[symbol] = value;
83
+
84
+ me._isModified = true;
85
+ me._isModified = instance.isModified(me, model.trackModifiedFields);
86
+
87
+ instance.onRecordChange({
88
+ fields: [{name: field.name, oldValue, value}],
89
+ model,
90
+ record: me
91
+ })
92
+ }
93
+ }
94
+ }
95
+ };
96
+
97
+ // adding the original value of each field
98
+ if (model.trackModifiedFields) {
99
+ properties[instance.ovPrefix + field.name] = {
100
+ value: parsedValue
101
+ }
102
+ }
103
+
104
+ Object.defineProperties(path ? Neo.ns(path, true, me) : me, properties)
105
+ }
34
106
  }
35
107
 
36
108
  /**
@@ -67,8 +139,7 @@ class RecordFactory extends Base {
67
139
  static name = 'Record'
68
140
 
69
141
  constructor(config) {
70
- let me = this,
71
- properties;
142
+ let me = this;
72
143
 
73
144
  Object.defineProperties(me, {
74
145
  _isModified: {
@@ -79,57 +150,7 @@ class RecordFactory extends Base {
79
150
 
80
151
  if (Array.isArray(model.fields)) {
81
152
  model.fields.forEach(field => {
82
- let value = config[field.mapping || field.name],
83
- symbol = Symbol.for(field.name),
84
- parsedValue;
85
-
86
- if (!Object.hasOwn(config, field.name) && Object.hasOwn(field, 'defaultValue')) {
87
- value = field.defaultValue
88
- }
89
-
90
- parsedValue = instance.parseRecordValue(me, field, value, config);
91
-
92
- properties = {
93
- [symbol]: {
94
- value : parsedValue,
95
- writable: true
96
- },
97
- [field.name]: {
98
- configurable: true,
99
- enumerable : true,
100
- get() {
101
- return this[symbol]
102
- },
103
- set(value) {
104
- let me = this,
105
- oldValue = me[symbol];
106
-
107
- value = instance.parseRecordValue(me, field, value);
108
-
109
- if (!Neo.isEqual(value, oldValue)) {
110
- me[symbol] = value;
111
-
112
- me._isModified = true;
113
- me._isModified = instance.isModified(me, model.trackModifiedFields);
114
-
115
- instance.onRecordChange({
116
- fields: [{name: field.name, oldValue, value}],
117
- model,
118
- record: me
119
- })
120
- }
121
- }
122
- }
123
- };
124
-
125
- // adding the original value of each field
126
- if (model.trackModifiedFields) {
127
- properties[instance.ovPrefix + field.name] = {
128
- value: parsedValue
129
- }
130
- }
131
-
132
- Object.defineProperties(me, properties)
153
+ instance.createField({config, field, me, model})
133
154
  })
134
155
  }
135
156
  }
@@ -151,8 +172,8 @@ class RecordFactory extends Base {
151
172
  }
152
173
  };
153
174
 
154
- Object.defineProperty(cls.prototype, 'isRecord', { value : true });
155
- Object.defineProperty(cls, 'isClass', { vale : true });
175
+ Object.defineProperty(cls.prototype, 'isRecord', {value: true});
176
+ Object.defineProperty(cls, 'isClass', {value: true});
156
177
 
157
178
  return ns[key]
158
179
  }
@@ -309,6 +309,13 @@ class Store extends Base {
309
309
  RecordFactory.createRecord(config)
310
310
  }
311
311
 
312
+ /**
313
+ * @returns {String}
314
+ */
315
+ getKeyProperty() {
316
+ return this.keyProperty || this.model.keyProperty
317
+ }
318
+
312
319
  /**
313
320
  * @param {Object} opts={}
314
321
  * @param {Object} opts.data
@@ -25,9 +25,9 @@ class DragProxyComponent extends Base {
25
25
  */
26
26
  autoRender: true,
27
27
  /**
28
- * @member {String[]} cls=['neo-dragproxy']
28
+ * @member {String[]} baseCls=['neo-dragproxy']
29
29
  */
30
- cls: ['neo-dragproxy'],
30
+ baseCls: ['neo-dragproxy'],
31
31
  /**
32
32
  * @member {Boolean} moveInMainThread=true
33
33
  */
@@ -35,28 +35,18 @@ class DragProxyComponent extends Base {
35
35
  }
36
36
 
37
37
  /**
38
- * @param {Object} config
38
+ * Triggered after the mounted config got changed
39
+ * @param {Boolean} value
40
+ * @param {Boolean} oldValue
41
+ * @protected
39
42
  */
40
- construct(config) {
41
- super.construct(config);
43
+ afterSetMounted(value, oldValue) {
44
+ super.afterSetMounted(value, oldValue);
42
45
 
43
- let me = this;
44
-
45
- me.on('mounted', me.onMounted, me)
46
- }
47
-
48
- /**
49
- * @param {String} id
50
- */
51
- onMounted(id) {
52
- if (this.moveInMainThread) {
46
+ if (value && this.moveInMainThread) {
53
47
  let {appName, id, windowId} = this;
54
48
 
55
- Neo.main.addon.DragDrop.setDragProxyElement({
56
- appName,
57
- id,
58
- windowId
59
- })
49
+ Neo.main.addon.DragDrop.setDragProxyElement({appName, id, windowId})
60
50
  }
61
51
  }
62
52
  }
@@ -456,14 +456,19 @@ class CheckBox extends Base {
456
456
  */
457
457
  getGroupValue() {
458
458
  let form = this.getClosestForm(),
459
- fields = ComponentManager.find({path: this.getPath()}),
460
- value = [];
459
+ path = this.getPath(),
460
+ value = [],
461
+ fields;
461
462
 
462
- fields.forEach(field => {
463
- if (field.checked && field.getClosestForm() === form) {
464
- NeoArray.add(value, field.value)
465
- }
466
- });
463
+ if (path) {
464
+ fields = ComponentManager.find({path});
465
+
466
+ fields.forEach(field => {
467
+ if (field.checked && field.getClosestForm() === form) {
468
+ NeoArray.add(value, field.value)
469
+ }
470
+ })
471
+ }
467
472
 
468
473
  return value
469
474
  }
@@ -346,6 +346,7 @@ class ComboBox extends Picker {
346
346
  role : 'listbox',
347
347
  selectionModel: {stayInList: false},
348
348
  store : me.store,
349
+ windowId : me.windowId,
349
350
  ...me.listConfig
350
351
  });
351
352
 
@@ -580,18 +581,18 @@ class ComboBox extends Picker {
580
581
  }
581
582
 
582
583
  /**
583
- * @param {Object} record
584
+ * @param {Object} data
584
585
  * @protected
585
586
  */
586
- onListItemNavigate(record) {
587
- let {activeIndex} = record;
587
+ onListItemNavigate(data) {
588
+ let {activeIndex} = data;
588
589
 
589
590
  if (activeIndex >= 0) {
590
591
  let me = this,
591
592
  {store} = me;
592
593
 
593
- me.activeRecord = store.getAt(activeIndex);
594
- me.activeRecordId = me.activeRecord[store.keyProperty || model.keyProperty];
594
+ me.activeRecord = data.record || store.getAt(activeIndex);
595
+ me.activeRecordId = me.activeRecord[store.getKeyProperty()];
595
596
 
596
597
  // Update typeahead hint (which updates DOM), or update DOM
597
598
  me.typeAhead ? me.updateTypeAheadValue(me.lastManualInput) : me.update()
@@ -737,7 +738,7 @@ class ComboBox extends Picker {
737
738
  if (match && inputHintEl) {
738
739
  inputHintEl.value = value + match[displayField].substr(value.length);
739
740
  me.activeRecord = match;
740
- me.activeRecordId = match[store.keyProperty || store.model.keyProperty]
741
+ me.activeRecordId = match[store.getKeyProperty()]
741
742
  }
742
743
  }
743
744
 
@@ -771,7 +772,7 @@ class ComboBox extends Picker {
771
772
  * The select event fires when a list item gets selected
772
773
  * @event select
773
774
  * @param {Object} record
774
- * @param {value} record[store.keyProperty]
775
+ * @param {value} record[store.getKeyProperty()]
775
776
  * @returns {Object}
776
777
  */
777
778
 
package/src/grid/View.mjs CHANGED
@@ -95,9 +95,9 @@ class View extends Component {
95
95
 
96
96
  for (; j < colCount; j++) {
97
97
  column = columns[j];
98
- rendererValue = record[column.field];
98
+ rendererValue = Neo.ns(column.field, false, record);
99
99
 
100
- if (rendererValue === undefined) {
100
+ if (rendererValue === null || rendererValue === undefined) {
101
101
  rendererValue = ''
102
102
  }
103
103
 
package/src/list/Base.mjs CHANGED
@@ -689,7 +689,7 @@ class Base extends Component {
689
689
  getItemRecordId(vnodeId) {
690
690
  let itemId = vnodeId.split('__')[1],
691
691
  {model} = this.store,
692
- keyField = model?.getField(model.keyProperty),
692
+ keyField = model?.getField(this.getKeyProperty()),
693
693
  keyType = keyField?.type?.toLowerCase();
694
694
 
695
695
  if (keyType === 'int' || keyType === 'integer') {