neo.mjs 8.0.0-alpha.2 → 8.0.0-beta.1

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 (57) hide show
  1. package/.github/CODING_GUIDELINES.md +5 -5
  2. package/.github/CONCEPT.md +10 -10
  3. package/apps/ServiceWorker.mjs +2 -2
  4. package/apps/covid/view/MainContainer.mjs +14 -14
  5. package/apps/covid/view/TableContainer.mjs +2 -2
  6. package/apps/portal/index.html +1 -1
  7. package/apps/portal/view/ViewportController.mjs +2 -2
  8. package/apps/portal/view/examples/TabContainer.mjs +11 -11
  9. package/apps/portal/view/home/FooterContainer.mjs +1 -1
  10. package/apps/portal/view/home/parts/MainNeo.mjs +6 -2
  11. package/apps/realworld/view/article/CreateComponent.mjs +1 -1
  12. package/apps/realworld2/view/HomeContainer.mjs +7 -7
  13. package/apps/sharedcovid/view/MainContainer.mjs +17 -17
  14. package/apps/sharedcovid/view/TableContainer.mjs +2 -2
  15. package/buildScripts/createApp.mjs +2 -2
  16. package/buildScripts/createClass.mjs +4 -6
  17. package/docs/app/view/ContentTabContainer.mjs +1 -1
  18. package/docs/app/view/MainContainer.mjs +3 -3
  19. package/docs/app/view/MainContainerController.mjs +9 -9
  20. package/examples/ServiceWorker.mjs +2 -2
  21. package/examples/component/mwc/buttons/MainContainer.mjs +2 -2
  22. package/examples/component/mwc/textFields/MainContainer.mjs +2 -2
  23. package/examples/fields/MainContainer.mjs +197 -228
  24. package/examples/preloadingAssets/view/MainContainer.mjs +2 -2
  25. package/examples/tab/container/MainContainer.mjs +7 -9
  26. package/examples/tabs/MainContainer.mjs +3 -3
  27. package/examples/tabs/MainContainer2.mjs +4 -4
  28. package/examples/videoMove/MainContainer.mjs +14 -7
  29. package/examples/viewport/MainContainer.mjs +3 -3
  30. package/package.json +6 -6
  31. package/resources/data/deck/learnneo/pages/benefits/FormsEngine.md +13 -13
  32. package/resources/data/deck/training/pages/2022-12-27T21-55-23-144Z.md +2 -2
  33. package/resources/data/deck/training/pages/2022-12-28T17-11-34-653Z.md +6 -6
  34. package/resources/data/deck/training/pages/2022-12-29T18-36-08-226Z.md +2 -2
  35. package/resources/data/deck/training/pages/2022-12-29T18-36-56-893Z.md +2 -2
  36. package/resources/data/deck/training/pages/2022-12-29T20-37-08-919Z.md +2 -2
  37. package/resources/data/deck/training/pages/2022-12-29T20-37-20-344Z.md +2 -2
  38. package/resources/data/deck/training/pages/2023-01-01T21-11-58-025Z.md +3 -3
  39. package/resources/data/deck/training/pages/2023-01-16T20-24-09-690Z.md +4 -4
  40. package/resources/data/deck/training/pages/2023-02-05T17-44-53-815Z.md +3 -3
  41. package/resources/data/deck/training/pages/2023-02-05T17-45-40-114Z.md +1 -1
  42. package/src/DefaultConfig.mjs +2 -2
  43. package/src/calendar/view/SettingsContainer.mjs +13 -28
  44. package/src/calendar/view/calendars/ColorsList.mjs +5 -0
  45. package/src/code/LivePreview.mjs +10 -10
  46. package/src/component/Base.mjs +46 -44
  47. package/src/container/Base.mjs +1 -1
  48. package/src/form/field/Text.mjs +1 -1
  49. package/src/form/field/Time.mjs +5 -3
  50. package/src/form/field/trigger/Time.mjs +2 -1
  51. package/src/list/Base.mjs +7 -1
  52. package/src/list/Color.mjs +3 -3
  53. package/src/main/DomEvents.mjs +1 -1
  54. package/src/main/DomUtils.mjs +39 -36
  55. package/src/tab/Container.mjs +3 -5
  56. package/src/toolbar/Base.mjs +26 -8
  57. package/src/util/VNode.mjs +6 -8
@@ -147,12 +147,12 @@ class MainView extends FormContainer {
147
147
  }, {
148
148
  module: TabContainer,
149
149
  items : [{
150
- module : FormContainer,
151
- itemDefaults : {module: TextField, labelPosition: 'inline'},
152
- layout : {ntype:'vbox', align:'start'},
153
- reference : 'user-form',
154
- tabButtonConfig: {text: 'User'},
155
- tag : 'div',
150
+ module : FormContainer,
151
+ header : {text: 'User'},
152
+ itemDefaults: {module: TextField, labelPosition: 'inline'},
153
+ layout : {ntype:'vbox', align:'start'},
154
+ reference : 'user-form',
155
+ tag : 'div',
156
156
 
157
157
  items: [{
158
158
  labelText: 'Firstname',
@@ -165,12 +165,12 @@ class MainView extends FormContainer {
165
165
  value : 'Doe'
166
166
  }]
167
167
  }, {
168
- module : FormContainer,
169
- itemDefaults : {module: TextField, labelPosition: 'inline'},
170
- layout : {ntype:'vbox', align:'start'},
171
- reference : 'product-form',
172
- tabButtonConfig: {text: 'Product'},
173
- tag : 'div',
168
+ module : FormContainer,
169
+ header : {text: 'Product'},
170
+ itemDefaults: {module: TextField, labelPosition: 'inline'},
171
+ layout : {ntype:'vbox', align:'start'},
172
+ reference : 'product-form',
173
+ tag : 'div',
174
174
 
175
175
  items: [{
176
176
  labelText: 'Name',
@@ -189,7 +189,7 @@ class MainView extends FormContainer {
189
189
  itemDefaults: {module: Button},
190
190
  layout : {ntype: 'hbox'},
191
191
 
192
- items : [{
192
+ items: [{
193
193
  handler: 'up.getMainFormValues',
194
194
  text : 'Get Main Values'
195
195
  }, {
@@ -23,13 +23,13 @@ class MainContainer extends Viewport {
23
23
  style: { padding: '20px' }
24
24
  },
25
25
  items: [{
26
- tabButtonConfig: {
26
+ header: {
27
27
  iconCls: 'fa fa-home',
28
28
  text: 'Tab 1'
29
29
  },
30
30
  vdom: { innerHTML: 'Welcome to your new Neo App.' }
31
31
  }, {
32
- tabButtonConfig: {
32
+ header: {
33
33
  iconCls: 'fa fa-play-circle',
34
34
  text: 'Tab 2'
35
35
  },
@@ -13,18 +13,18 @@ Give it the `ntype:'yelp-businesses-tabs',`.
13
13
 
14
14
  It needs *two* tabs, with the tab button text set to 'Map' and 'Table'.
15
15
 
16
- Remember that a tab is configured with the `tabButtonConfig`, and you'll use the
16
+ Remember that a tab is configured with the `header`, and you'll use the
17
17
  `html` config as a placeholder to indicate that a map and a table will eventually
18
18
  be used. The generated class already has two tabs.
19
19
 
20
- The first tab shoudl end up looking like this.
20
+ The first tab should end up looking like this.
21
21
 
22
22
  {
23
- ntype: 'component',
24
- html: 'The map goes here',
25
- tabButtonConfig: {
23
+ ntype : 'component',
24
+ html : 'The map goes here',
25
+ header: {
26
26
  text: 'Map'
27
- },
27
+ }
28
28
  }
29
29
 
30
30
 
@@ -33,7 +33,7 @@ to inspect it, and run methods on it.
33
33
  Now add a new tab:
34
34
 
35
35
  tabContainer.add({
36
- tabButtonConfig: {
36
+ header: {
37
37
  iconCls: 'fa fa-home',
38
38
  text: 'Hi there!'
39
39
  },
@@ -103,4 +103,4 @@ and change the value.
103
103
  Clear the console and do another _Ctrl-right-click_, then right-click on the button component logged in
104
104
  the console and choose _Store object as global variable_. It'll use a value like _temp1_.
105
105
 
106
- Rather than drilling-down, assign a new text value by entering `temp1.text = 'hi there'`.
106
+ Rather than drilling-down, assign a new text value by entering `temp1.text = 'hi there'`.
@@ -80,7 +80,7 @@ class MainContainer extends Viewport {
80
80
  },
81
81
 
82
82
  items: [{
83
- tabButtonConfig: {
83
+ header: {
84
84
  iconCls: 'fa fa-home',
85
85
  text: 'Tab 1'
86
86
  },
@@ -88,7 +88,7 @@ class MainContainer extends Viewport {
88
88
  innerHTML: 'Welcome to your new Neo App.'
89
89
  }
90
90
  }, {
91
- tabButtonConfig: {
91
+ header: {
92
92
  iconCls: 'fa fa-play-circle',
93
93
  text: 'Tab 2'
94
94
  },
@@ -26,13 +26,13 @@ class MainContainer extends Viewport {
26
26
  style: { padding: '20px' }
27
27
  },
28
28
  items: [{
29
- tabButtonConfig: {
29
+ header: {
30
30
  iconCls: 'fa fa-home',
31
31
  text: 'Tab 1'
32
32
  },
33
33
  vdom: { innerHTML: 'Welcome to your new Neo App.' }
34
34
  }, {
35
- tabButtonConfig: {
35
+ header: {
36
36
  iconCls: 'fa fa-play-circle',
37
37
  text: 'Tab 2'
38
38
  },
@@ -23,13 +23,13 @@ class MainContainer extends Viewport {
23
23
  style: { padding: '20px' }
24
24
  },
25
25
  items: [{
26
- tabButtonConfig: {
26
+ header: {
27
27
  iconCls: 'fa fa-home',
28
28
  text: 'Tab 1'
29
29
  },
30
30
  vdom: { innerHTML: 'Welcome to your new Neo App.' }
31
31
  }, {
32
- tabButtonConfig: {
32
+ header: {
33
33
  iconCls: 'fa fa-play-circle',
34
34
  text: 'Tab 2'
35
35
  },
@@ -14,12 +14,12 @@ class Simple extends Base {
14
14
  items: [{
15
15
  module: Simple
16
16
 
17
- tabButtonConfig: {iconCls: 'fa fa-home', text: 'Simple'},
17
+ header: {iconCls: 'fa fa-home', text: 'Simple'},
18
18
 
19
19
  }, {
20
20
  module: Simple
21
21
  foo: 2, // This value is used for the instance
22
22
 
23
- tabButtonConfig: {iconCls: 'fa fa-home', text: 'Simple'},
23
+ header: {iconCls: 'fa fa-home', text: 'Simple'},
24
24
  }],
25
- </pre>
25
+ </pre>
@@ -1,23 +1,23 @@
1
1
  A tab container is a card-layout container with a tab bar and styled buttons.
2
2
  Do not specify a `layout` for tab containers.
3
3
 
4
- The buttons are configured via `tabButtonConfig`
4
+ The buttons are configured via `header`
5
5
 
6
6
  activeIndex: 2,
7
7
  tabBarPosition: 'left', // top, right, bottom, left
8
8
  itemDefaults: { module: Button },
9
9
  items: [{
10
- tabButtonConfig: {
10
+ header: {
11
11
  iconCls: 'fa fa-home',
12
12
  text: 'Tab 1'
13
13
  }
14
14
  }, {
15
- tabButtonConfig: {
15
+ header: {
16
16
  iconCls: 'fa fa-play-circle',
17
17
  text: 'Tab 2'
18
18
  }
19
19
  }, {
20
- tabButtonConfig: {
20
+ header: {
21
21
  iconCls: 'fa fa-bell',
22
22
  text: 'Tab 3'
23
23
  }
@@ -19,7 +19,7 @@ in the `afterSetBusiness()` method.
19
19
  items: [{
20
20
  module: Component,
21
21
  reference: 'view',
22
- tabButtonConfig: {
22
+ header: {
23
23
  text: 'View'
24
24
  },
25
25
  style: {
@@ -33,7 +33,7 @@ in the `afterSetBusiness()` method.
33
33
  }
34
34
  }, {
35
35
  reference: 'form',
36
- tabButtonConfig: {
36
+ header: {
37
37
  text: 'Edit'
38
38
  }
39
39
  }]
@@ -192,4 +192,4 @@ Here's one way to code it. How does this compare to your solution?
192
192
 
193
193
  The view tab will become more and more complicated as we add content.
194
194
  It should be refactored into its own view class to isolate that complexity.
195
- We won't bother, but on a project that would be the right thing to do.
195
+ We won't bother, but on a project that would be the right thing to do.
@@ -16,7 +16,7 @@ Configure the form to use vbox, along with some other configs.
16
16
  {
17
17
  module: Form,
18
18
  reference: 'form',
19
- tabButtonConfig: {
19
+ header: {
20
20
  text: 'Edit'
21
21
  },
22
22
  style: {
@@ -262,12 +262,12 @@ const DefaultConfig = {
262
262
  useVdomWorker: true,
263
263
  /**
264
264
  * buildScripts/injectPackageVersion.mjs will update this value
265
- * @default '8.0.0-alpha.2'
265
+ * @default '8.0.0-beta.1'
266
266
  * @memberOf! module:Neo
267
267
  * @name config.version
268
268
  * @type String
269
269
  */
270
- version: '8.0.0-alpha.2'
270
+ version: '8.0.0-beta.1'
271
271
  };
272
272
 
273
273
  Object.assign(DefaultConfig, {
@@ -89,44 +89,29 @@ class SettingsContainer extends Container {
89
89
  items: [{
90
90
  module: () => import('./settings/GeneralContainer.mjs'),
91
91
  flag : 'general',
92
- style : {padding: '20px'},
93
-
94
- tabButtonConfig: {
95
- text: 'General'
96
- }
92
+ header: {text: 'General'},
93
+ style : {padding: '20px'}
97
94
  }, {
98
- ntype: 'component',
99
- flag : 'day',
100
- html : 'Day',
101
- style: {padding: '20px'},
102
-
103
- tabButtonConfig: {
104
- text: 'Day'
105
- }
95
+ ntype : 'component',
96
+ flag : 'day',
97
+ header: {text: 'Day'},
98
+ html : 'Day',
99
+ style : {padding: '20px'}
106
100
  }, {
107
101
  module: () => import('./settings/WeekContainer.mjs'),
108
102
  flag : 'week',
109
- style : {padding: '20px'},
110
-
111
- tabButtonConfig: {
112
- text: 'Week'
113
- }
103
+ header: {text: 'Week'},
104
+ style : {padding: '20px'}
114
105
  }, {
115
106
  module: () => import('./settings/MonthContainer.mjs'),
116
107
  flag : 'month',
117
- style : {padding: '20px'},
118
-
119
- tabButtonConfig: {
120
- text: 'Month'
121
- }
108
+ header: {text: 'Month'},
109
+ style : {padding: '20px'}
122
110
  }, {
123
111
  module: () => import('./settings/YearContainer.mjs'),
124
112
  flag : 'year',
125
- style : {padding: '20px'},
126
-
127
- tabButtonConfig: {
128
- text: 'Year'
129
- }
113
+ header: {text: 'Year'},
114
+ style : {padding: '20px'}
130
115
  }],
131
116
 
132
117
  listeners: {
@@ -21,6 +21,11 @@ class ColorsList extends List {
21
21
  bind: {
22
22
  store: 'stores.colors'
23
23
  },
24
+ /**
25
+ * Set this to true in case a keyboard navigation should immediately select the focussed item
26
+ * @member {Boolean} selectOnFocus=true
27
+ */
28
+ selectOnFocus: true,
24
29
  /**
25
30
  * @member {Boolean} useWrapperNode=false
26
31
  */
@@ -63,16 +63,16 @@ class LivePreview extends Container {
63
63
  removeInactiveCards: false,
64
64
 
65
65
  items: [{
66
- module : MonacoEditor,
67
- hideLabel : true,
68
- listeners : {editorChange: 'up.onEditorChange'},
69
- style : {height: '100%'},
70
- reference : 'editor',
71
- tabButtonConfig: {text: 'Source'}
66
+ module : MonacoEditor,
67
+ header : {text: 'Source'},
68
+ hideLabel: true,
69
+ listeners: {editorChange: 'up.onEditorChange'},
70
+ style : {height: '100%'},
71
+ reference: 'editor'
72
72
  }, {
73
- module : Container,
74
- reference : 'preview',
75
- tabButtonConfig: {text: 'Preview'}
73
+ module : Container,
74
+ header : {text: 'Preview'},
75
+ reference: 'preview'
76
76
  }]
77
77
  }],
78
78
  /**
@@ -410,7 +410,7 @@ class LivePreview extends Container {
410
410
  ui : 'ghost'
411
411
  });
412
412
 
413
- items[0].style = {marginLeft: 'auto'};
413
+ items.unshift('->');
414
414
 
415
415
  // we want to add a normal (non-header) button
416
416
  tabContainer.getTabBar().add(items);
@@ -737,13 +737,13 @@ class Base extends CoreBase {
737
737
  * @protected
738
738
  */
739
739
  afterSetIsLoading(value, oldValue) {
740
- if (!(value === false && oldValue === undefined)) {
740
+ if (value || oldValue !== undefined) {
741
741
  let me = this,
742
742
  {cls, vdom} = me,
743
743
  maskIndex;
744
744
 
745
745
  if (oldValue !== undefined && vdom.cn) {
746
- maskIndex = vdom.cn.findIndex(c => c.cls.includes('neo-load-mask'));
746
+ maskIndex = vdom.cn.findLastIndex(c => c.cls?.includes('neo-load-mask'));
747
747
 
748
748
  // Remove the load mask
749
749
  if (maskIndex !== -1) {
@@ -752,19 +752,11 @@ class Base extends CoreBase {
752
752
  }
753
753
 
754
754
  if (value) {
755
- vdom.cn.push(me.loadMask = {
756
- cls: ['neo-load-mask'],
757
- cn : [{
758
- cls: ['neo-load-mask-body'],
759
- cn : [{
760
- cls: me.loadingSpinnerCls
761
- }, {
762
- cls : ['neo-loading-message'],
763
- html : value,
764
- removeDom: !Neo.isString(value)
765
- }]
766
- }]
767
- })
755
+ if (!vdom.cn) {
756
+ vdom.cn = []
757
+ }
758
+
759
+ vdom.cn.push(me.createLoadingMask(value))
768
760
  }
769
761
 
770
762
  NeoArray.toggle(cls, 'neo-masked', value);
@@ -1403,6 +1395,28 @@ class Base extends CoreBase {
1403
1395
  me.update()
1404
1396
  }
1405
1397
 
1398
+ /**
1399
+ * Override this method in case you need different mask markups.
1400
+ * The removal logic relies on the top level node having the cls 'neo-load-mask'
1401
+ * @param {Boolean|String} loadingMessage
1402
+ * @returns {Object} vdom
1403
+ */
1404
+ createLoadingMask(loadingMessage) {
1405
+ return {
1406
+ cls: ['neo-load-mask'],
1407
+ cn : [{
1408
+ cls: ['neo-load-mask-body'],
1409
+ cn : [{
1410
+ cls: this.loadingSpinnerCls
1411
+ }, {
1412
+ cls : ['neo-loading-message'],
1413
+ html : loadingMessage,
1414
+ removeDom: !Neo.isString(loadingMessage)
1415
+ }]
1416
+ }]
1417
+ }
1418
+ }
1419
+
1406
1420
  /**
1407
1421
  * Creates the tooltip instances
1408
1422
  * @param {Object|String} value
@@ -1869,6 +1883,7 @@ class Base extends CoreBase {
1869
1883
  let removeFn = function () {
1870
1884
  if (me.parentId !== 'document.body') {
1871
1885
  me.vdom.removeDom = true;
1886
+ me.parent.updateDepth = 2;
1872
1887
  me.parent.update()
1873
1888
  } else {
1874
1889
  me.unmount()
@@ -1918,7 +1933,7 @@ class Base extends CoreBase {
1918
1933
  * @param {Number} distance=1 Distance inside the component tree
1919
1934
  * @returns {Boolean}
1920
1935
  */
1921
- isParentVdomUpdating(parentId=this.parentId, resolve, distance=1) {
1936
+ isParentUpdating(parentId=this.parentId, resolve, distance=1) {
1922
1937
  if (parentId !== 'document.body') {
1923
1938
  let me = this,
1924
1939
  parent = Neo.getComponent(parentId);
@@ -1940,9 +1955,9 @@ class Base extends CoreBase {
1940
1955
 
1941
1956
  // If an update is running and does not have a collision, we do not need to check further parents
1942
1957
  return false
1943
- } else {
1944
- return me.isParentVdomUpdating(parent.parentId, resolve, distance+1)
1945
1958
  }
1959
+
1960
+ return me.isParentUpdating(parent.parentId, resolve, distance+1)
1946
1961
  }
1947
1962
  }
1948
1963
 
@@ -2053,22 +2068,24 @@ class Base extends CoreBase {
2053
2068
  * Checks the needsVdomUpdate config inside the parent tree
2054
2069
  * @param {String} parentId=this.parentId
2055
2070
  * @param {Function} [resolve] gets passed by updateVdom()
2071
+ * @param {Number} distance=1 Distance inside the component tree
2056
2072
  * @returns {Boolean}
2057
2073
  */
2058
- needsParentUpdate(parentId=this.parentId, resolve) {
2074
+ needsParentUpdate(parentId=this.parentId, resolve, distance=1) {
2059
2075
  if (parentId !== 'document.body') {
2060
2076
  let me = this,
2061
2077
  parent = Neo.getComponent(parentId);
2062
2078
 
2063
2079
  if (parent) {
2064
- if (parent.needsVdomUpdate) {
2080
+ // We are checking for parent.updateDepth, since we care about the depth of the next update cycle
2081
+ if (parent.needsVdomUpdate && me.hasUpdateCollision(parent.updateDepth, distance)) {
2065
2082
  parent.resolveUpdateCache.push(...me.resolveUpdateCache);
2066
2083
  resolve && parent.resolveUpdateCache.push(resolve);
2067
2084
  me.resolveUpdateCache = [];
2068
2085
  return true
2069
- } else {
2070
- return me.needsParentUpdate(parent.parentId)
2071
2086
  }
2087
+
2088
+ return me.needsParentUpdate(parent.parentId, resolve, distance+1)
2072
2089
  }
2073
2090
  }
2074
2091
 
@@ -2179,7 +2196,7 @@ class Base extends CoreBase {
2179
2196
  * @param {Neo.vdom.VNode} vnode= this.vnode
2180
2197
  * @returns {Promise<any>}
2181
2198
  */
2182
- promiseUpdate(vdom = this.vdom, vnode = this.vnode) {
2199
+ promiseUpdate(vdom=this.vdom, vnode=this.vnode) {
2183
2200
  return new Promise((resolve, reject) => {
2184
2201
  this.updateVdom(vdom, vnode, resolve, reject)
2185
2202
  })
@@ -2380,6 +2397,7 @@ class Base extends CoreBase {
2380
2397
  if (me.silentVdomUpdate) {
2381
2398
  me.needsVdomUpdate = true
2382
2399
  } else if (me.parentId !== 'document.body') {
2400
+ me.parent.updateDepth = 2;
2383
2401
  me.parent.update()
2384
2402
  } else {
2385
2403
  !me.mounted && me.render(true)
@@ -2429,7 +2447,7 @@ class Base extends CoreBase {
2429
2447
 
2430
2448
  // we need one separate iteration first to ensure all wrapper nodes get registered
2431
2449
  childComponents.forEach(component => {
2432
- childVnode = VNodeUtil.findChildVnode(me.vnode, component.vdom.id)?.vnode;
2450
+ childVnode = VNodeUtil.find(me.vnode, component.vdom.id)?.vnode;
2433
2451
 
2434
2452
  if (childVnode) {
2435
2453
  map[component.id] = childVnode;
@@ -2517,7 +2535,7 @@ class Base extends CoreBase {
2517
2535
  updateCls(cls, oldCls, id=this.id) {
2518
2536
  let me = this,
2519
2537
  {vnode} = me,
2520
- vnodeTarget = vnode && VNodeUtil.findChildVnode(me.vnode, {id})?.vnode;
2538
+ vnodeTarget = vnode && VNodeUtil.find(me.vnode, {id})?.vnode;
2521
2539
 
2522
2540
  if (vnode && !Neo.isEqual(cls, oldCls)) {
2523
2541
  if (vnodeTarget) {
@@ -2549,7 +2567,7 @@ class Base extends CoreBase {
2549
2567
 
2550
2568
  if (delta) {
2551
2569
  vdom = VDomUtil.find(me.vdom, id);
2552
- vnode = me.vnode && VNodeUtil.findChildVnode(me.vnode, id);
2570
+ vnode = me.vnode && VNodeUtil.find(me.vnode, id);
2553
2571
 
2554
2572
  if (!me.hasUnmountedVdomChanges) {
2555
2573
  me.hasUnmountedVdomChanges = !me.mounted && me.hasBeenMounted
@@ -2600,24 +2618,8 @@ class Base extends CoreBase {
2600
2618
  {app, mounted, parentId} = me,
2601
2619
  listenerId;
2602
2620
 
2603
- // It is important to keep the vdom tree stable to ensure that containers do not lose the references to their
2604
- // child vdom trees. The if case should not happen, but in case it does, keeping the reference and merging
2605
- // the content over seems to be the best strategy
2606
- if (me._vdom !== vdom) {
2607
- Logger.warn('vdom got replaced for: ' + me.id + '. Copying the content into the reference holder object');
2608
-
2609
- Object.keys(me._vdom).forEach(key => {
2610
- delete me._vdom[key]
2611
- });
2612
-
2613
- vdom = Object.assign(me._vdom, vdom)
2614
- }
2615
-
2616
- if (resolve && me.isVdomUpdating) {
2617
- me.resolveUpdateCache.push(resolve)
2618
- }
2619
-
2620
2621
  if (me.isVdomUpdating || me.silentVdomUpdate) {
2622
+ resolve && me.resolveUpdateCache.push(resolve);
2621
2623
  me.needsVdomUpdate = true
2622
2624
  } else {
2623
2625
  if (!mounted && me.isConstructed && !me.hasRenderingListener && app?.rendering === true) {
@@ -2637,7 +2639,7 @@ class Base extends CoreBase {
2637
2639
 
2638
2640
  if (
2639
2641
  !me.needsParentUpdate(parentId, resolve)
2640
- && !me.isParentVdomUpdating(parentId, resolve)
2642
+ && !me.isParentUpdating(parentId, resolve)
2641
2643
  && mounted
2642
2644
  && vnode
2643
2645
  ) {
@@ -500,7 +500,7 @@ class Base extends Component {
500
500
  /**
501
501
  * Inserts an item or array of items at a specific index
502
502
  * @param {Number} index
503
- * @param {Object|Array} item
503
+ * @param {Array|Object} item
504
504
  * @param {Boolean} [silent=false]
505
505
  * @returns {Neo.component.Base|Neo.component.Base[]}
506
506
  */
@@ -1356,7 +1356,7 @@ class Text extends Base {
1356
1356
  let me = this,
1357
1357
  oldValue = me.value,
1358
1358
  inputValue = data.value,
1359
- vnode = VNodeUtil.findChildVnode(me.vnode, {nodeName: 'input'});
1359
+ vnode = VNodeUtil.find(me.vnode, {nodeName: 'input'});
1360
1360
 
1361
1361
  if (vnode) {
1362
1362
  // Update the current state (modified DOM by the user) to enable the delta-updates logic.
@@ -101,9 +101,11 @@ class Time extends Picker {
101
101
  });
102
102
 
103
103
  me.list = Neo.create({
104
- module : List,
105
- displayField: 'value',
106
- store : me.collection,
104
+ module : List,
105
+ displayField : 'value',
106
+ itemsFocusable: false,
107
+ navigator : {eventSource: me.getInputElId()},
108
+ store : me.collection,
107
109
  ...me.listConfig
108
110
  });
109
111
 
@@ -62,10 +62,11 @@ class Time extends Picker {
62
62
  parentId: me.id,
63
63
  showDisc: false,
64
64
  size : null,
65
+ windowId: me.windowId,
65
66
  ...me.clockConfig
66
67
  });
67
68
 
68
- me.vdom.cn = [me.clock.vdom];
69
+ me.vdom.cn = [me.clock.createVdomReference()];
69
70
  me.update()
70
71
  }
71
72
 
package/src/list/Base.mjs CHANGED
@@ -125,7 +125,12 @@ class Base extends Component {
125
125
  */
126
126
  selectionModel_: null,
127
127
  /**
128
- * Set this to true in case a select event should only update _vdom (e.g. when used inside a form.field.Select
128
+ * Set this to true in case a keyboard navigation should immediately select the focussed item
129
+ * @member {Boolean} selectOnFocus=false
130
+ */
131
+ selectOnFocus: false,
132
+ /**
133
+ * Set this to true in case a select event should only update _vdom (e.g. when used inside a form.field.ComboBox
129
134
  * @member {Boolean} silentSelect=false
130
135
  */
131
136
  silentSelect: false,
@@ -298,6 +303,7 @@ class Base extends Component {
298
303
  if (!me.hasNavigator) {
299
304
  me.navigator = {
300
305
  appName : me.appName,
306
+ autoClick : me.selectOnFocus,
301
307
  id : me.id,
302
308
  keepFocusIndex: me.keepFocusIndex,
303
309
  selector : `.${me.itemCls}:not(.neo-disabled,.neo-list-header)`,
@@ -22,13 +22,13 @@ class Color extends Base {
22
22
  baseCls: ['neo-color-list', 'neo-list'],
23
23
  /**
24
24
  * The data.Model field which contains the color value
25
- * @member {String} colorField='name'
25
+ * @member {String} colorField_='name'
26
26
  */
27
- colorField: 'name',
27
+ colorField_: 'name',
28
28
  /**
29
29
  * Override the formatter to apply a custom background-color styling.
30
30
  * E.g. using CSS vars for different themes
31
- * @member {Function} colorField=(scope,data)=>data[scope.colorField]
31
+ * @member {Function} colorFormatter=(scope,data)=>data[scope.colorField]
32
32
  */
33
33
  colorFormatter: (scope,data) => data[scope.colorField]
34
34
  }