neo.mjs 8.9.0 → 8.10.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 (35) hide show
  1. package/apps/ServiceWorker.mjs +2 -2
  2. package/apps/portal/index.html +1 -1
  3. package/apps/portal/view/home/FooterContainer.mjs +1 -1
  4. package/examples/ServiceWorker.mjs +2 -2
  5. package/examples/grid/container/MainContainer.mjs +19 -15
  6. package/examples/table/cellEditing/MainContainer.mjs +30 -15
  7. package/examples/table/container/MainContainer.mjs +34 -19
  8. package/examples/tableFiltering/MainContainer.mjs +1 -1
  9. package/examples/tableStore/MainContainer.mjs +14 -13
  10. package/examples/tableStore/MainModel.mjs +3 -3
  11. package/package.json +1 -1
  12. package/src/DefaultConfig.mjs +2 -2
  13. package/src/Main.mjs +1 -0
  14. package/src/component/Base.mjs +37 -1
  15. package/src/dialog/Base.mjs +14 -2
  16. package/src/grid/Container.mjs +11 -11
  17. package/src/grid/View.mjs +9 -1
  18. package/src/selection/Model.mjs +5 -13
  19. package/src/selection/grid/BaseModel.mjs +4 -38
  20. package/src/selection/grid/CellColumnModel.mjs +29 -36
  21. package/src/selection/grid/CellColumnRowModel.mjs +27 -34
  22. package/src/selection/grid/CellModel.mjs +50 -44
  23. package/src/selection/grid/CellRowModel.mjs +18 -35
  24. package/src/selection/grid/ColumnModel.mjs +28 -62
  25. package/src/selection/grid/RowModel.mjs +2 -2
  26. package/src/selection/table/BaseModel.mjs +0 -42
  27. package/src/selection/table/CellColumnModel.mjs +9 -18
  28. package/src/selection/table/CellColumnRowModel.mjs +9 -18
  29. package/src/selection/table/CellModel.mjs +3 -3
  30. package/src/selection/table/CellRowModel.mjs +4 -19
  31. package/src/selection/table/ColumnModel.mjs +9 -9
  32. package/src/selection/table/RowModel.mjs +2 -2
  33. package/src/table/Container.mjs +11 -31
  34. package/src/table/View.mjs +46 -7
  35. package/src/table/plugin/CellEditing.mjs +2 -2
@@ -20,9 +20,9 @@ class ServiceWorker extends ServiceBase {
20
20
  */
21
21
  singleton: true,
22
22
  /**
23
- * @member {String} version='8.9.0'
23
+ * @member {String} version='8.10.0'
24
24
  */
25
- version: '8.9.0'
25
+ version: '8.10.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-01-25",
19
+ "datePublished": "2025-01-26",
20
20
  "publisher": {
21
21
  "@type": "Organization",
22
22
  "name": "Neo.mjs"
@@ -107,7 +107,7 @@ class FooterContainer extends Container {
107
107
  }, {
108
108
  module: Component,
109
109
  cls : ['neo-version'],
110
- html : 'v8.9.0'
110
+ html : 'v8.10.0'
111
111
  }]
112
112
  }],
113
113
  /**
@@ -20,9 +20,9 @@ class ServiceWorker extends ServiceBase {
20
20
  */
21
21
  singleton: true,
22
22
  /**
23
- * @member {String} version='8.9.0'
23
+ * @member {String} version='8.10.0'
24
24
  */
25
- version: '8.9.0'
25
+ version: '8.10.0'
26
26
  }
27
27
 
28
28
  /**
@@ -25,8 +25,8 @@ class MainContainer extends ConfigurationViewport {
25
25
  }
26
26
 
27
27
  createConfigurationComponents() {
28
- let me = this,
29
- {view} = me.exampleComponent;
28
+ let me = this,
29
+ {selectionModel} = me.exampleComponent.view;
30
30
 
31
31
  const selectionModelRadioDefaults = {
32
32
  module : Radio,
@@ -46,35 +46,35 @@ class MainContainer extends ConfigurationViewport {
46
46
  value : me.exampleComponent.height
47
47
  }, {
48
48
  ...selectionModelRadioDefaults,
49
- checked : view.selectionModel.ntype === 'selection-grid-cellmodel',
49
+ checked : selectionModel.ntype === 'selection-grid-cellmodel',
50
50
  labelText : 'selectionModel',
51
- listeners : {change: me.onRadioChange.bind(me, 'selectionModel', CellModel)},
51
+ listeners : {change: me.onRadioViewChange.bind(me, 'selectionModel', CellModel)},
52
52
  style : {marginTop: '10px'},
53
53
  valueLabelText: 'Cell'
54
54
  }, {
55
55
  ...selectionModelRadioDefaults,
56
- checked : view.selectionModel.ntype === 'selection-grid-columnmodel',
57
- listeners : {change: me.onRadioChange.bind(me, 'selectionModel', ColumnModel)},
56
+ checked : selectionModel.ntype === 'selection-grid-columnmodel',
57
+ listeners : {change: me.onRadioViewChange.bind(me, 'selectionModel', ColumnModel)},
58
58
  valueLabelText: 'Column'
59
59
  }, {
60
60
  ...selectionModelRadioDefaults,
61
- checked : view.selectionModel.ntype === 'selection-grid-rowmodel',
62
- listeners : {change: me.onRadioChange.bind(me, 'selectionModel', RowModel)},
61
+ checked : selectionModel.ntype === 'selection-grid-rowmodel',
62
+ listeners : {change: me.onRadioViewChange.bind(me, 'selectionModel', RowModel)},
63
63
  valueLabelText: 'Row'
64
64
  }, {
65
65
  ...selectionModelRadioDefaults,
66
- checked : view.selectionModel.ntype === 'selection-grid-cellcolumnmodel',
67
- listeners : {change: me.onRadioChange.bind(me, 'selectionModel', CellColumnModel)},
66
+ checked : selectionModel.ntype === 'selection-grid-cellcolumnmodel',
67
+ listeners : {change: me.onRadioViewChange.bind(me, 'selectionModel', CellColumnModel)},
68
68
  valueLabelText: 'Cell & Column'
69
69
  }, {
70
70
  ...selectionModelRadioDefaults,
71
- checked : view.selectionModel.ntype === 'selection-grid-cellrowmodel',
72
- listeners : {change: me.onRadioChange.bind(me, 'selectionModel', CellRowModel)},
71
+ checked : selectionModel.ntype === 'selection-grid-cellrowmodel',
72
+ listeners : {change: me.onRadioViewChange.bind(me, 'selectionModel', CellRowModel)},
73
73
  valueLabelText: 'Cell & Row'
74
74
  }, {
75
75
  ...selectionModelRadioDefaults,
76
- checked : view.selectionModel.ntype === 'selection-grid-cellcolumnrowmodel',
77
- listeners : {change: me.onRadioChange.bind(me, 'selectionModel', CellColumnRowModel)},
76
+ checked : selectionModel.ntype === 'selection-grid-cellcolumnrowmodel',
77
+ listeners : {change: me.onRadioViewChange.bind(me, 'selectionModel', CellColumnRowModel)},
78
78
  valueLabelText: 'Cell & Column & Row'
79
79
  }]
80
80
  }
@@ -97,6 +97,10 @@ class MainContainer extends ConfigurationViewport {
97
97
 
98
98
  viewConfig: {
99
99
  selectionModel: CellModel
100
+ },
101
+
102
+ wrapperStyle: {
103
+ height: '250px'
100
104
  }
101
105
  }
102
106
  }
@@ -106,7 +110,7 @@ class MainContainer extends ConfigurationViewport {
106
110
  * @param {String} value
107
111
  * @param {Object} opts
108
112
  */
109
- onRadioChange(config, value, opts) {
113
+ onRadioViewChange(config, value, opts) {
110
114
  if (opts.value === true) { // we only want to listen to check events, not uncheck
111
115
  this.exampleComponent.view[config] = value
112
116
  }
@@ -44,7 +44,8 @@ class MainContainer extends ConfigurationViewport {
44
44
  * @returns {Object[]}
45
45
  */
46
46
  createConfigurationComponents() {
47
- let me = this;
47
+ let me = this,
48
+ {selectionModel} = me.exampleComponent.view;
48
49
 
49
50
  const selectionModelRadioDefaults = {
50
51
  module : Radio,
@@ -64,25 +65,25 @@ class MainContainer extends ConfigurationViewport {
64
65
  value : me.exampleComponent.height
65
66
  }, {
66
67
  ...selectionModelRadioDefaults,
67
- checked : me.exampleComponent.selectionModel.ntype === 'selection-table-cellmodel',
68
+ checked : selectionModel.ntype === 'selection-table-cellmodel',
68
69
  labelText : 'selectionModel',
69
- listeners : {change: me.onRadioChange.bind(me, 'selectionModel', CellModel)},
70
+ listeners : {change: me.onRadioViewChange.bind(me, 'selectionModel', CellModel)},
70
71
  style : {marginTop: '10px'},
71
72
  valueLabelText: 'Cell'
72
73
  }, {
73
74
  ...selectionModelRadioDefaults,
74
- checked : me.exampleComponent.selectionModel.ntype === 'selection-table-cellcolumnmodel',
75
- listeners : {change: me.onRadioChange.bind(me, 'selectionModel', CellColumnModel)},
75
+ checked : selectionModel.ntype === 'selection-table-cellcolumnmodel',
76
+ listeners : {change: me.onRadioViewChange.bind(me, 'selectionModel', CellColumnModel)},
76
77
  valueLabelText: 'Cell & Column'
77
78
  }, {
78
79
  ...selectionModelRadioDefaults,
79
- checked : me.exampleComponent.selectionModel.ntype === 'selection-table-cellrowmodel',
80
- listeners : {change: me.onRadioChange.bind(me, 'selectionModel', CellRowModel)},
80
+ checked : selectionModel.ntype === 'selection-table-cellrowmodel',
81
+ listeners : {change: me.onRadioViewChange.bind(me, 'selectionModel', CellRowModel)},
81
82
  valueLabelText: 'Cell & Row'
82
83
  }, {
83
84
  ...selectionModelRadioDefaults,
84
- checked : me.exampleComponent.selectionModel.ntype === 'selection-table-cellcolumnrowmodel',
85
- listeners : {change: me.onRadioChange.bind(me, 'selectionModel', CellColumnRowModel)},
85
+ checked : selectionModel.ntype === 'selection-table-cellcolumnrowmodel',
86
+ listeners : {change: me.onRadioViewChange.bind(me, 'selectionModel', CellColumnRowModel)},
86
87
  valueLabelText: 'Cell & Column & Row'
87
88
  }, {
88
89
  module : CheckBox,
@@ -106,12 +107,15 @@ class MainContainer extends ConfigurationViewport {
106
107
  */
107
108
  createExampleComponent() {
108
109
  return {
109
- module : TableContainer,
110
- bind : {store : 'stores.mainStore'},
111
- cellEditing : true,
112
- parentId : this.id,
113
- selectionModel: CellModel,
114
- store : MainStore,
110
+ module : TableContainer,
111
+ bind : {store: 'stores.mainStore'},
112
+ cellEditing: true,
113
+ parentId : this.id,
114
+ store : MainStore,
115
+
116
+ viewConfig: {
117
+ selectionModel: CellModel
118
+ },
115
119
 
116
120
  columnDefaults: {
117
121
  editable: true
@@ -169,6 +173,17 @@ class MainContainer extends ConfigurationViewport {
169
173
  onPluginConfigChange(config, opts) {
170
174
  this.exampleComponent.getPlugin('table-cell-editing')[config] = opts.value
171
175
  }
176
+
177
+ /**
178
+ * @param {String} config
179
+ * @param {String} value
180
+ * @param {Object} opts
181
+ */
182
+ onRadioViewChange(config, value, opts) {
183
+ if (opts.value === true) { // we only want to listen to check events, not uncheck
184
+ this.exampleComponent.view[config] = value
185
+ }
186
+ }
172
187
  }
173
188
 
174
189
  export default Neo.setupClass(MainContainer);
@@ -27,7 +27,8 @@ class MainContainer extends ConfigurationViewport {
27
27
  }
28
28
 
29
29
  createConfigurationComponents() {
30
- let me = this;
30
+ let me = this,
31
+ {selectionModel} = me.exampleComponent.view;
31
32
 
32
33
  const selectionModelRadioDefaults = {
33
34
  module : Radio,
@@ -47,35 +48,35 @@ class MainContainer extends ConfigurationViewport {
47
48
  value : me.exampleComponent.height
48
49
  }, {
49
50
  ...selectionModelRadioDefaults,
50
- checked : me.exampleComponent.selectionModel.ntype === 'selection-table-cellmodel',
51
+ checked : selectionModel.ntype === 'selection-table-cellmodel',
51
52
  labelText : 'selectionModel',
52
- listeners : {change: me.onRadioChange.bind(me, 'selectionModel', CellModel)},
53
+ listeners : {change: me.onRadioViewChange.bind(me, 'selectionModel', CellModel)},
53
54
  style : {marginTop: '10px'},
54
55
  valueLabelText: 'Cell'
55
56
  }, {
56
57
  ...selectionModelRadioDefaults,
57
- checked : me.exampleComponent.selectionModel.ntype === 'selection-table-columnmodel',
58
- listeners : {change: me.onRadioChange.bind(me, 'selectionModel', ColumnModel)},
58
+ checked : selectionModel.ntype === 'selection-table-columnmodel',
59
+ listeners : {change: me.onRadioViewChange.bind(me, 'selectionModel', ColumnModel)},
59
60
  valueLabelText: 'Column'
60
61
  }, {
61
62
  ...selectionModelRadioDefaults,
62
- checked : me.exampleComponent.selectionModel.ntype === 'selection-table-rowmodel',
63
- listeners : {change: me.onRadioChange.bind(me, 'selectionModel', RowModel)},
63
+ checked : selectionModel.ntype === 'selection-table-rowmodel',
64
+ listeners : {change: me.onRadioViewChange.bind(me, 'selectionModel', RowModel)},
64
65
  valueLabelText: 'Row'
65
66
  }, {
66
67
  ...selectionModelRadioDefaults,
67
- checked : me.exampleComponent.selectionModel.ntype === 'selection-table-cellcolumnmodel',
68
- listeners : {change: me.onRadioChange.bind(me, 'selectionModel', CellColumnModel)},
68
+ checked : selectionModel.ntype === 'selection-table-cellcolumnmodel',
69
+ listeners : {change: me.onRadioViewChange.bind(me, 'selectionModel', CellColumnModel)},
69
70
  valueLabelText: 'Cell & Column'
70
71
  }, {
71
72
  ...selectionModelRadioDefaults,
72
- checked : me.exampleComponent.selectionModel.ntype === 'selection-table-cellrowmodel',
73
- listeners : {change: me.onRadioChange.bind(me, 'selectionModel', CellRowModel)},
73
+ checked : selectionModel.ntype === 'selection-table-cellrowmodel',
74
+ listeners : {change: me.onRadioViewChange.bind(me, 'selectionModel', CellRowModel)},
74
75
  valueLabelText: 'Cell & Row'
75
76
  }, {
76
77
  ...selectionModelRadioDefaults,
77
- checked : me.exampleComponent.selectionModel.ntype === 'selection-table-cellcolumnrowmodel',
78
- listeners : {change: me.onRadioChange.bind(me, 'selectionModel', CellColumnRowModel)},
78
+ checked : selectionModel.ntype === 'selection-table-cellcolumnrowmodel',
79
+ listeners : {change: me.onRadioViewChange.bind(me, 'selectionModel', CellColumnRowModel)},
79
80
  valueLabelText: 'Cell & Column & Row'
80
81
  }, {
81
82
  module : Checkbox,
@@ -88,8 +89,8 @@ class MainContainer extends ConfigurationViewport {
88
89
  checked : false,
89
90
  labelText: 'Fit width',
90
91
  listeners: {
91
- change({ value }) {
92
- const { style } = me.exampleComponent;
92
+ change({value}) {
93
+ const {style} = me.exampleComponent;
93
94
 
94
95
  if (value) {
95
96
  style.width = '100%';
@@ -100,7 +101,7 @@ class MainContainer extends ConfigurationViewport {
100
101
  }
101
102
 
102
103
  me.exampleComponent.style = style;
103
- me.exampleComponent.update();
104
+ me.exampleComponent.update()
104
105
  }
105
106
  },
106
107
  style: {marginTop: '10px'}
@@ -112,9 +113,12 @@ class MainContainer extends ConfigurationViewport {
112
113
  */
113
114
  createExampleComponent() {
114
115
  return Neo.create(TableContainer, {
115
- id : 'myTableStoreContainer',
116
- selectionModel: CellModel,
117
- store : MainStore,
116
+ id : 'myTableStoreContainer',
117
+ store: MainStore,
118
+
119
+ viewConfig: {
120
+ selectionModel: CellModel
121
+ },
118
122
 
119
123
  columns: [
120
124
  {dataField: 'firstname', text: 'Firstname'},
@@ -180,6 +184,17 @@ class MainContainer extends ConfigurationViewport {
180
184
  editButtonHandler(data) {
181
185
  console.log(data)
182
186
  }
187
+
188
+ /**
189
+ * @param {String} config
190
+ * @param {String} value
191
+ * @param {Object} opts
192
+ */
193
+ onRadioViewChange(config, value, opts) {
194
+ if (opts.value === true) { // we only want to listen to check events, not uncheck
195
+ this.exampleComponent.view[config] = value
196
+ }
197
+ }
183
198
  }
184
199
 
185
200
  export default Neo.setupClass(MainContainer);
@@ -47,9 +47,9 @@ class MainContainer extends Viewport {
47
47
  }, {
48
48
  module : TableContainer,
49
49
  id : 'myTableFilterContainer',
50
- selectionModel : CellModel,
51
50
  showHeaderFilters: true,
52
51
  store : MainStore,
52
+ viewConfig : {selectionModel: CellModel},
53
53
  width : '100%',
54
54
  wrapperStyle : {height: '300px'},
55
55
 
@@ -60,7 +60,8 @@ class MainContainer extends Viewport {
60
60
  for (; j < repeats; j++) {
61
61
  for (i=0; i < countRecords; i++) {
62
62
  record = store.items[i];
63
- Object.entries(record).forEach(([field, value]) => {
63
+
64
+ Object.entries(record[Symbol.for('data')]).forEach(([field, value]) => {
64
65
  if (field !== 'githubId') {
65
66
  if (value.includes(string1)) {
66
67
  newValue = value.replace(string1, string2);
@@ -72,7 +73,7 @@ class MainContainer extends Viewport {
72
73
 
73
74
  record[field] = newValue; // triggers the change
74
75
  }
75
- });
76
+ })
76
77
  }
77
78
  }
78
79
  }
@@ -110,7 +111,7 @@ class MainContainer extends Viewport {
110
111
  listeners: {
111
112
  change: function(data) {
112
113
  if (data.value) {
113
- Neo.getComponent('myTableStoreContainer').selectionModel = {
114
+ Neo.getComponent('myTableStoreContainer').view.selectionModel = {
114
115
  ntype: this.value
115
116
  };
116
117
  }
@@ -127,7 +128,7 @@ class MainContainer extends Viewport {
127
128
  listeners: {
128
129
  change: function(data) {
129
130
  if (data.value) {
130
- Neo.getComponent('myTableStoreContainer').selectionModel = {
131
+ Neo.getComponent('myTableStoreContainer').view.selectionModel = {
131
132
  ntype: this.value
132
133
  };
133
134
  }
@@ -144,7 +145,7 @@ class MainContainer extends Viewport {
144
145
  listeners: {
145
146
  change: function(data) {
146
147
  if (data.value) {
147
- Neo.getComponent('myTableStoreContainer').selectionModel = {
148
+ Neo.getComponent('myTableStoreContainer').view.selectionModel = {
148
149
  ntype: this.value
149
150
  };
150
151
  }
@@ -161,7 +162,7 @@ class MainContainer extends Viewport {
161
162
  listeners: {
162
163
  change: function(data) {
163
164
  if (data.value) {
164
- Neo.getComponent('myTableStoreContainer').selectionModel = {
165
+ Neo.getComponent('myTableStoreContainer').view.selectionModel = {
165
166
  ntype: this.value
166
167
  };
167
168
  }
@@ -178,7 +179,7 @@ class MainContainer extends Viewport {
178
179
  listeners: {
179
180
  change: function(data) {
180
181
  if (data.value) {
181
- Neo.getComponent('myTableStoreContainer').selectionModel = {
182
+ Neo.getComponent('myTableStoreContainer').view.selectionModel = {
182
183
  ntype: this.value
183
184
  };
184
185
  }
@@ -186,12 +187,12 @@ class MainContainer extends Viewport {
186
187
  }
187
188
  }]
188
189
  }, {
189
- module : TableContainer,
190
- id : 'myTableStoreContainer',
191
- selectionModel: CellModel,
192
- store : MainStore,
193
- width : '100%',
194
- wrapperStyle : {height: '300px'},
190
+ module : TableContainer,
191
+ id : 'myTableStoreContainer',
192
+ store : MainStore,
193
+ viewConfig : {selectionModel: CellModel},
194
+ width : '100%',
195
+ wrapperStyle: {height: '300px'},
195
196
 
196
197
  columns: [{
197
198
  dataField: 'firstname',
@@ -10,16 +10,16 @@ class MainModel extends Model {
10
10
 
11
11
  fields: [{
12
12
  name: 'country',
13
- type: 'string'
13
+ type: 'html'
14
14
  }, {
15
15
  name: 'firstname',
16
- type: 'string'
16
+ type: 'html'
17
17
  }, {
18
18
  name: 'githubId',
19
19
  type: 'string'
20
20
  }, {
21
21
  name: 'lastname',
22
- type: 'string'
22
+ type: 'html'
23
23
  }]
24
24
  }
25
25
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "neo.mjs",
3
- "version": "8.9.0",
3
+ "version": "8.10.0",
4
4
  "description": "The webworkers driven UI framework",
5
5
  "type": "module",
6
6
  "repository": {
@@ -262,12 +262,12 @@ const DefaultConfig = {
262
262
  useVdomWorker: true,
263
263
  /**
264
264
  * buildScripts/injectPackageVersion.mjs will update this value
265
- * @default '8.9.0'
265
+ * @default '8.10.0'
266
266
  * @memberOf! module:Neo
267
267
  * @name config.version
268
268
  * @type String
269
269
  */
270
- version: '8.9.0'
270
+ version: '8.10.0'
271
271
  };
272
272
 
273
273
  Object.assign(DefaultConfig, {
package/src/Main.mjs CHANGED
@@ -213,6 +213,7 @@ class Main extends core.Base {
213
213
  }
214
214
 
215
215
  this.registerAddon(module.default);
216
+ await this.timeout(20); // Wait until remotes are registered
216
217
 
217
218
  return true
218
219
  }
@@ -1684,7 +1684,7 @@ class Component extends Base {
1684
1684
  * Convenience shortcut
1685
1685
  * @param {String[]|String} id=this.id
1686
1686
  * @param {String} appName=this.appName
1687
- * @returns {Promise<Neo.util.Rectangle>}
1687
+ * @returns {Promise<Neo.util.Rectangle|Neo.util.Rectangle[]>}
1688
1688
  */
1689
1689
  async getDomRect(id=this.id, appName=this.appName) {
1690
1690
  let result = await Neo.main.DomAccess.getBoundingClientRect({appName, id, windowId: this.windowId});
@@ -2722,6 +2722,42 @@ class Component extends Base {
2722
2722
 
2723
2723
  me.hasUnmountedVdomChanges = !mounted && me.hasBeenMounted
2724
2724
  }
2725
+
2726
+ /**
2727
+ * In case you are sure a DOMRect exists, use getDomRect()
2728
+ * Otherwise you can wait for it using this method.
2729
+ * @example:
2730
+ * await this.render(true);
2731
+ * await this.waitForDomRect();
2732
+ * @param {Object} opts
2733
+ * @param {String} opts.appName=this.appName
2734
+ * @param {Number} opts.attempts=10 Reruns in case the rect height or width equals 0
2735
+ * @param {Number} opts.delay=50 Time in ms before checking again
2736
+ * @param {String[]|String} opts.id=this.id
2737
+ * @returns {Promise<Neo.util.Rectangle|Neo.util.Rectangle[]>}
2738
+ */
2739
+ async waitForDomRect({appName=this.appName, attempts=10, delay=50, id=this.id}) {
2740
+ let me = this,
2741
+ result = await me.getDomRect(id, appName),
2742
+ reRun = false;
2743
+
2744
+ if (Array.isArray(result)) {
2745
+ result.forEach(rect => {
2746
+ if (rect.height < 1 || rect.width < 1) {
2747
+ reRun = true
2748
+ }
2749
+ })
2750
+ } else if (result.height < 1 || result.width < 1) {
2751
+ reRun = true
2752
+ }
2753
+
2754
+ if (reRun && attempts > 0) {
2755
+ await me.timeout(delay);
2756
+ return await me.waitForDomRect({appName, attempts: attempts-1, delay, id})
2757
+ }
2758
+
2759
+ return result
2760
+ }
2725
2761
  }
2726
2762
 
2727
2763
  /**
@@ -411,11 +411,23 @@ class Dialog extends Panel {
411
411
 
412
412
  rect = await me.getDomRect(me.animateTargetId);
413
413
 
414
+ if (style.left || style.top) {
415
+ let tempStyle = {...style};
416
+
417
+ // Ensure that the initial mounting happens outside the visible area
418
+ delete style.left;
419
+ delete style.top;
420
+
421
+ me.style = style;
422
+
423
+ // Silent update & ensure that a given starting position won't get lost
424
+ me._style = style = tempStyle
425
+ }
426
+
414
427
  // rendered outside the visible area
415
428
  await me.render(true);
416
- await me.timeout(150);
417
429
 
418
- let [dialogRect, bodyRect] = await me.getDomRect([me.id, 'document.body']);
430
+ let [dialogRect, bodyRect] = await me.waitForDomRect({id: [me.id, 'document.body']});
419
431
 
420
432
  // Move to cover the animation target
421
433
  await Neo.applyDeltas(appName, {
@@ -236,20 +236,20 @@ class GridContainer extends BaseContainer {
236
236
  async addResizeObserver(mounted) {
237
237
  let me = this,
238
238
  ResizeObserver = Neo.main?.addon?.ResizeObserver,
239
- resizeParams = {id: me.id, windowId: me.windowId};
239
+ {windowId} = me,
240
+ resizeParams = {id: me.id, windowId};
240
241
 
241
- // Check if the remotes api is ready for slow network connections & dist/prod
242
242
  if (!ResizeObserver) {
243
- await me.timeout(100);
244
- await me.addResizeObserver(mounted)
243
+ await Neo.Main.importAddon({name: 'ResizeObserver', windowId});
244
+ ResizeObserver = Neo.main.addon.ResizeObserver
245
+ }
246
+
247
+ if (mounted) {
248
+ ResizeObserver.register(resizeParams);
249
+ await me.passSizeToView()
245
250
  } else {
246
- if (mounted) {
247
- ResizeObserver.register(resizeParams);
248
- await me.passSizeToView()
249
- } else {
250
- me.initialResizeEvent = true;
251
- ResizeObserver.unregister(resizeParams)
252
- }
251
+ me.initialResizeEvent = true;
252
+ ResizeObserver.unregister(resizeParams)
253
253
  }
254
254
  }
255
255
 
package/src/grid/View.mjs CHANGED
@@ -632,7 +632,7 @@ class GridView extends Component {
632
632
  * @returns {String}
633
633
  */
634
634
  getCellId(record, dataField) {
635
- return this.id + '__' + record[this.store.keyProperty] + '__' + dataField
635
+ return this.id + '__' + record[this.store.getKeyProperty()] + '__' + dataField
636
636
  }
637
637
 
638
638
  /**
@@ -659,6 +659,14 @@ class GridView extends Component {
659
659
  return null
660
660
  }
661
661
 
662
+ /**
663
+ * @param {String} cellId
664
+ * @returns {String}
665
+ */
666
+ getDataField(cellId) {
667
+ return cellId.split('__')[2]
668
+ }
669
+
662
670
  /**
663
671
  * Get the matching record by passing a row id, a cell id or an id inside a grid cell.
664
672
  * @param {String} nodeId
@@ -110,9 +110,6 @@ class Model extends Base {
110
110
  NeoArray.remove(itemCollection, item);
111
111
 
112
112
  if (!silent) {
113
- // We need a bigger depth, since grid.Container & table.Container use selection.Model as a top-level config.
114
- // In case the config would get moved to grid.View & table.View, we would not need it.
115
- view.updateDepth = -1;
116
113
  view.update();
117
114
 
118
115
  me.fire('selectionChange', {
@@ -127,10 +124,11 @@ class Model extends Base {
127
124
 
128
125
  /**
129
126
  * @param {Boolean} [silent] true to prevent a vdom update
127
+ * @param {Object[]|String[]} itemCollection=this.items
130
128
  */
131
- deselectAll(silent) {
129
+ deselectAll(silent, itemCollection=this.items) {
132
130
  let me = this,
133
- items = [...me.items],
131
+ items = [...itemCollection],
134
132
  {view} = me;
135
133
 
136
134
  if (items.length) {
@@ -139,9 +137,6 @@ class Model extends Base {
139
137
  });
140
138
 
141
139
  if (!silent && items.length > 0) {
142
- // We need a bigger depth, since grid.Container & table.Container use selection.Model as a top-level config.
143
- // In case the config would get moved to grid.View & table.View, we would not need it.
144
- view.updateDepth = -1;
145
140
  view.update()
146
141
  }
147
142
 
@@ -235,8 +230,8 @@ class Model extends Base {
235
230
  items: [items]).map(item => item.isRecord ? view.getItemId(item) : Neo.isObject(item) ? item.id : item);
236
231
 
237
232
  if (!Neo.isEqual(itemCollection, items)) {
238
- if (me.singleSelect) {
239
- me.deselectAll(true)
233
+ if (me.singleSelect && itemCollection === me.items) {
234
+ me.deselectAll(true, itemCollection)
240
235
  }
241
236
 
242
237
  items.forEach(node => {
@@ -251,9 +246,6 @@ class Model extends Base {
251
246
  NeoArray.add(itemCollection, items);
252
247
 
253
248
  if (!view.silentSelect) {
254
- // We need a bigger depth, since grid.Container & table.Container use selection.Model as a top-level config.
255
- // In case the config would get moved to grid.View & table.View, we would not need it.
256
- view.updateDepth = -1;
257
249
  view.update()
258
250
  }
259
251