neo.mjs 6.0.2 → 6.0.3

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.
@@ -20,9 +20,9 @@ class ServiceWorker extends ServiceBase {
20
20
  */
21
21
  singleton: true,
22
22
  /**
23
- * @member {String} version='6.0.2'
23
+ * @member {String} version='6.0.3'
24
24
  */
25
- version: '6.0.2'
25
+ version: '6.0.3'
26
26
  }
27
27
 
28
28
  /**
@@ -20,9 +20,9 @@ class ServiceWorker extends ServiceBase {
20
20
  */
21
21
  singleton: true,
22
22
  /**
23
- * @member {String} version='6.0.2'
23
+ * @member {String} version='6.0.3'
24
24
  */
25
- version: '6.0.2'
25
+ version: '6.0.3'
26
26
  }
27
27
 
28
28
  /**
@@ -1,9 +1,13 @@
1
1
  import ConfigurationViewport from '../ConfigurationViewport.mjs';
2
2
 
3
- import Store from '../../src/data/Store.mjs';
4
- import NumberField from '../../src/form/field/Number.mjs';
5
- import AccordionTree from '../../src/tree/Accordion.mjs';
6
- import CheckBox from "../../src/form/field/CheckBox.mjs";
3
+ import AccordionTree from '../../src/tree/Accordion.mjs';
4
+ import CheckBox from "../../src/form/field/CheckBox.mjs";
5
+ import NumberField from '../../src/form/field/Number.mjs';
6
+ import Panel from '../../src/container/Panel.mjs';
7
+ import Store from '../../src/data/Store.mjs';
8
+ // Do not remove the ViewController nor ViewModel
9
+ import ViewController from '../../src/controller/Component.mjs';
10
+ import ViewModel from '../../src/model/Component.mjs';
7
11
 
8
12
  /**
9
13
  * @class Neo.examples.treeSelectionModel.MainContainer
@@ -48,9 +52,9 @@ class MainContainer extends ConfigurationViewport {
48
52
  labelText: 'height',
49
53
  listeners: {change: me.onConfigChange.bind(me, 'height')},
50
54
  maxValue : 1200,
51
- minValue : 400,
52
- stepSize : 5,
53
- value : treeList.height,
55
+ minValue : 250,
56
+ stepSize : 50,
57
+ value : 650,
54
58
  style : {marginTop: '10px'}
55
59
  }, {
56
60
  module : NumberField,
@@ -59,9 +63,9 @@ class MainContainer extends ConfigurationViewport {
59
63
  listeners: {change: me.onConfigChange.bind(me, 'width')},
60
64
  maxValue : 1200,
61
65
  minValue : 200,
62
- stepSize : 5,
66
+ stepSize : 3,
63
67
  style : {marginTop: '10px'},
64
- value : treeList.width
68
+ value : 400
65
69
  }];
66
70
  }
67
71
 
@@ -69,69 +73,91 @@ class MainContainer extends ConfigurationViewport {
69
73
  * @returns {*}
70
74
  */
71
75
  createExampleComponent() {
72
- const store = Neo.create(Store, {
73
- keyProperty: 'id',
74
- model : {
75
- fields: [
76
- {name: 'collapsed', type: 'Boolean'},
77
- {name: 'content', type: 'String'},
78
- {name: 'iconCls', type: 'String'},
79
- {name: 'id', type: 'Integer'},
80
- {name: 'isLeaf', type: 'Boolean'},
81
- {name: 'name', type: 'String'},
82
- {name: 'parentId', type: 'Integer'}
83
- ]
84
- }
85
- });
76
+ const me = this,
77
+ store = Neo.create(Store, {
78
+ keyProperty: 'id',
79
+ model : {
80
+ fields: [
81
+ {name: 'collapsed', type: 'Boolean'},
82
+ {name: 'content', type: 'String'},
83
+ {name: 'iconCls', type: 'String'},
84
+ {name: 'id', type: 'Integer'},
85
+ {name: 'isLeaf', type: 'Boolean'},
86
+ {name: 'name', type: 'String'},
87
+ {name: 'parentId', type: 'Integer'}
88
+ ]
89
+ },
90
+
91
+ autoLoad: true,
92
+ url : '../../examples/treeSelectionModel/tree.json'
93
+ });
86
94
 
87
95
  return Neo.ntype({
88
- ntype : 'container',
96
+ ntype: 'container',
97
+
98
+ model: {
99
+ data: {
100
+ selection: [{name: 'Please select something'}]
101
+ }
102
+ },
103
+
89
104
  layout: {ntype: 'hbox', align: 'stretch'},
90
105
  items : [{
91
- // module: TextField,
92
- // label: 'Test',
93
- // plugin: {
94
- // Plugin: {
95
- // bold: true
96
- // }
97
- // }
98
- // },{
99
106
  module: AccordionTree,
100
- store : store,
101
- height: 800,
102
- width : 400,
103
-
104
- // ensure afterSetMounted runs only once
105
- storeLoaded: false,
106
- afterSetMounted() {
107
- if (!this.storeLoaded) {
108
- this.storeLoaded = true;
109
- } else {
110
- return;
111
- }
112
107
 
113
- let me = this;
108
+ bind: {selection: {twoWay: true, value: data => data.selection}},
114
109
 
115
- Neo.Xhr.promiseJson({
116
- url: '../../examples/treeSelectionModel/tree.json'
117
- }).then(data => {
118
- const items = data.json,
119
- colorArray = ['red', 'yellow', 'green'],
120
- iconArray = ['home', 'industry', 'user'];
110
+ store: store,
121
111
 
122
- // create random iconCls colors
123
- items.forEach((item) => {
124
- if (!item.iconCls) {
125
- const rand = Math.floor(Math.random() * 3);
126
-
127
- item.iconCls = 'fa fa-' + iconArray[rand] + ' color-' + colorArray[rand];
128
- }
129
- });
112
+ /**
113
+ * We are using data-binding.
114
+ * Here is an example for listener and controller
115
+ */
116
+ // controller: {
117
+ // module: ViewController,
118
+ //
119
+ // onAccordionItemClick(record) {
120
+ // let viewport = Neo.get('neo-configuration-viewport-1'),
121
+ // outputEl = viewport.getReference('output');
122
+ //
123
+ // outputEl.html = record.name;
124
+ // }
125
+ // },
126
+ //
127
+ // listeners: {
128
+ // leafItemClick: 'onAccordionItemClick'
129
+ // }
130
130
 
131
- me.store.data = data.json;
132
- me.createItems(null, me.getListItemsRoot(), 0);
133
- });
131
+ listeners: {
132
+ selectPreFirstItem: () => Neo.log('listener selectPreFirstItem fired'),
133
+ selectPostLastItem: () => Neo.log('listener selectPostLastItem fired')
134
134
  }
135
+ }, {
136
+ module: Panel,
137
+ height: 150,
138
+ width : '100%',
139
+
140
+ itemDefaults: {
141
+ style: {
142
+ padding: '10px'
143
+ }
144
+ },
145
+
146
+ headers: [{
147
+ dock : 'top',
148
+ style: {borderRightColor: 'transparent'},
149
+
150
+ items: [{
151
+ ntype: 'label',
152
+ text : 'Accordion Selection'
153
+ }]
154
+ }],
155
+
156
+ items: [{
157
+ ntype : 'component',
158
+ reference: 'output',
159
+ bind : {html: data => data.selection[0].name}
160
+ }]
135
161
  }]
136
162
  });
137
163
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "neo.mjs",
3
- "version": "6.0.2",
3
+ "version": "6.0.3",
4
4
  "description": "The webworkers driven UI framework",
5
5
  "type": "module",
6
6
  "repository": {
@@ -109,6 +109,9 @@
109
109
  .neo-file-upload-error-message {
110
110
  display : initial;
111
111
  }
112
+ input[type="file"],label {
113
+ display : none;
114
+ }
112
115
  }
113
116
  }
114
117
 
@@ -230,7 +233,7 @@
230
233
  }
231
234
  }
232
235
 
233
- .neo-file-upload-state-ready {
236
+ .neo-file-upload-state-ready:not(.neo-invalid) {
234
237
  // Only the input field and its label is visible when in ready state
235
238
  // It takes up the whole component, and is the only interactive item
236
239
  :not(input[type="file"],label) {
@@ -236,12 +236,12 @@ const DefaultConfig = {
236
236
  useVdomWorker: true,
237
237
  /**
238
238
  * buildScripts/injectPackageVersion.mjs will update this value
239
- * @default '6.0.2'
239
+ * @default '6.0.3'
240
240
  * @memberOf! module:Neo
241
241
  * @name config.version
242
242
  * @type String
243
243
  */
244
- version: '6.0.2'
244
+ version: '6.0.3'
245
245
  };
246
246
 
247
247
  Object.assign(DefaultConfig, {
package/src/Neo.mjs CHANGED
@@ -59,11 +59,11 @@ Neo = globalThis.Neo = Object.assign({
59
59
 
60
60
  if (Object.hasOwn(ctor, 'classConfigApplied')) {
61
61
  baseCfg = Neo.clone(ctor.config, true);
62
- break;
62
+ break
63
63
  }
64
64
 
65
65
  protos.unshift(proto);
66
- proto = proto.__proto__;
66
+ proto = proto.__proto__
67
67
  }
68
68
 
69
69
  config = baseCfg || {};
@@ -76,7 +76,7 @@ Neo = globalThis.Neo = Object.assign({
76
76
  cfg = ctor.config || {};
77
77
 
78
78
  if (Neo.overwrites) {
79
- ctor.applyOverwrites(cfg);
79
+ ctor.applyOverwrites(cfg)
80
80
  }
81
81
 
82
82
  Object.entries(cfg).forEach(([key, value]) => {
@@ -84,7 +84,7 @@ Neo = globalThis.Neo = Object.assign({
84
84
  delete cfg[key];
85
85
  key = key.slice(0, -1);
86
86
  cfg[key] = value;
87
- autoGenerateGetSet(element, key);
87
+ autoGenerateGetSet(element, key)
88
88
  }
89
89
 
90
90
  // only apply properties which have no setters inside the prototype chain
@@ -94,7 +94,7 @@ Neo = globalThis.Neo = Object.assign({
94
94
  enumerable: true,
95
95
  value,
96
96
  writable : true
97
- });
97
+ })
98
98
  }
99
99
  });
100
100
 
@@ -104,7 +104,7 @@ Neo = globalThis.Neo = Object.assign({
104
104
  // Running the docs app inside a workspace can pull in the same classes from different roots,
105
105
  // so we want to check for different class names as well
106
106
  if (Object.hasOwn(ntypeMap, ntype) && cfg.className !== ntypeMap[ntype]) {
107
- throw new Error(`ntype conflict for '${ntype}' inside the classes:\n${ntypeMap[ntype]}\n${cfg.className}`);
107
+ throw new Error(`ntype conflict for '${ntype}' inside the classes:\n${ntypeMap[ntype]}\n${cfg.className}`)
108
108
  }
109
109
 
110
110
  ntypeMap[ntype] = cfg.className;
@@ -113,11 +113,11 @@ Neo = globalThis.Neo = Object.assign({
113
113
  mixins = Object.hasOwn(config, 'mixins') && config.mixins || [];
114
114
 
115
115
  if (ctor.observable) {
116
- mixins.push('Neo.core.Observable');
116
+ mixins.push('Neo.core.Observable')
117
117
  }
118
118
 
119
119
  if (Object.hasOwn(cfg, 'mixins') && Array.isArray(cfg.mixins) && cfg.mixins.length > 0) {
120
- mixins.push(...cfg.mixins);
120
+ mixins.push(...cfg.mixins)
121
121
  }
122
122
 
123
123
  if (mixins.length > 0) {
@@ -139,17 +139,17 @@ Neo = globalThis.Neo = Object.assign({
139
139
  isClass : true
140
140
  });
141
141
 
142
- !config.singleton && this.applyToGlobalNs(cls);
142
+ !config.singleton && this.applyToGlobalNs(cls)
143
143
  });
144
144
 
145
145
  proto = cls.prototype || cls;
146
146
 
147
147
  if (proto.singleton) {
148
148
  cls = Neo.create(cls);
149
- Neo.applyToGlobalNs(cls);
149
+ Neo.applyToGlobalNs(cls)
150
150
  }
151
151
 
152
- return cls;
152
+ return cls
153
153
  },
154
154
 
155
155
  /**
@@ -177,10 +177,10 @@ Neo = globalThis.Neo = Object.assign({
177
177
  Object.entries(config).forEach(([key, value]) => {
178
178
  fnName = namespace[value];
179
179
  target[key] = bind ? fnName.bind(namespace) : fnName;
180
- });
180
+ })
181
181
  }
182
182
 
183
- return target;
183
+ return target
184
184
  },
185
185
 
186
186
  /**
@@ -199,7 +199,7 @@ Neo = globalThis.Neo = Object.assign({
199
199
  nsArray = className.split('.');
200
200
  key = nsArray.pop();
201
201
  ns = Neo.ns(nsArray, true);
202
- ns[key] = cls;
202
+ ns[key] = cls
203
203
  }
204
204
  },
205
205
 
@@ -214,12 +214,12 @@ Neo = globalThis.Neo = Object.assign({
214
214
  if (target && Neo.typeOf(defaults) === 'Object') {
215
215
  Object.entries(defaults).forEach(([key, value]) => {
216
216
  if (!Object.hasOwn(target, key)) {
217
- target[key] = value;
217
+ target[key] = value
218
218
  }
219
- });
219
+ })
220
220
  }
221
221
 
222
- return target;
222
+ return target
223
223
  },
224
224
 
225
225
  /**
@@ -243,7 +243,7 @@ Neo = globalThis.Neo = Object.assign({
243
243
  out = {};
244
244
 
245
245
  Object.entries(obj).forEach(([key, value]) => {
246
- out[key] = !deep ? value : Neo.clone(value, deep, ignoreNeoInstances);
246
+ out[key] = !deep ? value : Neo.clone(value, deep, ignoreNeoInstances)
247
247
  });
248
248
 
249
249
  return out
@@ -263,7 +263,7 @@ Neo = globalThis.Neo = Object.assign({
263
263
  delete config._id;
264
264
  delete config.id;
265
265
 
266
- return Neo.create(instance.className, config);
266
+ return Neo.create(instance.className, config)
267
267
  },
268
268
 
269
269
  /**
@@ -305,7 +305,7 @@ Neo = globalThis.Neo = Object.assign({
305
305
  cls, instance;
306
306
 
307
307
  if (type === 'NeoClass') {
308
- cls = className;
308
+ cls = className
309
309
  } else {
310
310
  if (type === 'Object') {
311
311
  config = className;
@@ -313,17 +313,17 @@ Neo = globalThis.Neo = Object.assign({
313
313
  if (!config.className && !config.module) {
314
314
  // using console.error instead of throw to show the config object
315
315
  console.error('Class created with object configuration missing className or module property', config);
316
- return null;
316
+ return null
317
317
  }
318
318
 
319
319
  className = config.className || config.module.prototype.className;
320
320
  }
321
321
 
322
322
  if (!exists(className)) {
323
- throw new Error('Class ' + className + ' does not exist');
323
+ throw new Error('Class ' + className + ' does not exist')
324
324
  }
325
325
 
326
- cls = Neo.ns(className);
326
+ cls = Neo.ns(className)
327
327
  }
328
328
 
329
329
  instance = new cls();
@@ -333,7 +333,7 @@ Neo = globalThis.Neo = Object.assign({
333
333
  instance.onAfterConstructed();
334
334
  instance.init();
335
335
 
336
- return instance;
336
+ return instance
337
337
  },
338
338
 
339
339
  /**
@@ -435,7 +435,7 @@ Neo = globalThis.Neo = Object.assign({
435
435
  return createArrayNs(true, current, prev);
436
436
  }
437
437
 
438
- prev[current] = {};
438
+ prev[current] = {}
439
439
  }
440
440
 
441
441
  if (prev) {
@@ -443,9 +443,9 @@ Neo = globalThis.Neo = Object.assign({
443
443
  return createArrayNs(false, current, prev);
444
444
  }
445
445
 
446
- return prev[current];
446
+ return prev[current]
447
447
  }
448
- }, scope || globalThis);
448
+ }, scope || globalThis)
449
449
  },
450
450
 
451
451
  /**
@@ -474,16 +474,17 @@ Neo = globalThis.Neo = Object.assign({
474
474
  if (!config.ntype) {
475
475
  throw new Error('Class defined with object configuration missing ntype property. ' + config.ntype);
476
476
  }
477
- ntype = config.ntype;
477
+
478
+ ntype = config.ntype
478
479
  }
479
480
 
480
481
  let className = Neo.ntypeMap[ntype];
481
482
 
482
483
  if (!className) {
483
- throw new Error('ntype ' + ntype + ' does not exist');
484
+ throw new Error('ntype ' + ntype + ' does not exist')
484
485
  }
485
486
 
486
- return Neo.create(className, config);
487
+ return Neo.create(className, config)
487
488
  },
488
489
 
489
490
  /**
@@ -492,7 +493,7 @@ Neo = globalThis.Neo = Object.assign({
492
493
  */
493
494
  typeOf(item) {
494
495
  if (item === null || item === undefined) {
495
- return null;
496
+ return null
496
497
  }
497
498
 
498
499
  return {
@@ -626,7 +627,7 @@ function autoGenerateGetSet(proto, key) {
626
627
  delete me[configSymbol][key];
627
628
 
628
629
  if (key !== 'items') {
629
- value = Neo.clone(value, true, true);
630
+ value = Neo.clone(value, true, true)
630
631
  }
631
632
 
632
633
  // we do want to store the value before the beforeSet modification as well,
@@ -639,7 +640,7 @@ function autoGenerateGetSet(proto, key) {
639
640
  // If they don't return a value, that means no change
640
641
  if (value === undefined) {
641
642
  me[_key] = oldValue;
642
- return;
643
+ return
643
644
  }
644
645
 
645
646
  me[_key] = value;
@@ -650,7 +651,7 @@ function autoGenerateGetSet(proto, key) {
650
651
  !Neo.isEqual(value, oldValue)
651
652
  ) {
652
653
  me[afterSet]?.(value, oldValue);
653
- me.afterSetConfig?.(key, value, oldValue);
654
+ me.afterSetConfig?.(key, value, oldValue)
654
655
  }
655
656
  }
656
657
  };
@@ -672,9 +673,9 @@ function createArrayNs(create, current, prev) {
672
673
  arrItem, arrRoot;
673
674
 
674
675
  if (create) {
675
- prev[arrDetails[0]] = arrRoot = prev[arrDetails[0]] || [];
676
+ prev[arrDetails[0]] = arrRoot = prev[arrDetails[0]] || []
676
677
  } else {
677
- arrRoot = prev[arrDetails[0]];
678
+ arrRoot = prev[arrDetails[0]]
678
679
  }
679
680
 
680
681
  if (!arrRoot) {
@@ -688,10 +689,10 @@ function createArrayNs(create, current, prev) {
688
689
  arrRoot[arrItem] = arrRoot[arrItem] || {};
689
690
  }
690
691
 
691
- arrRoot = arrRoot[arrItem];
692
+ arrRoot = arrRoot[arrItem]
692
693
  }
693
694
 
694
- return arrRoot;
695
+ return arrRoot
695
696
  }
696
697
 
697
698
  /**
@@ -704,9 +705,9 @@ function exists(className) {
704
705
  try {
705
706
  return !!className.split('.').reduce((prev, current) => {
706
707
  return prev[current];
707
- }, globalThis);
708
+ }, globalThis)
708
709
  } catch(e) {
709
- return false;
710
+ return false
710
711
  }
711
712
  }
712
713
 
@@ -725,8 +726,9 @@ function mixinProperty(proto, mixinProto) {
725
726
  if (proto[key]?._from) {
726
727
  if (mixinProto.className === proto[key]._from) {
727
728
  console.warn('Mixin set multiple times or already defined on a Base Class', proto.className, mixinProto.className, key);
728
- return;
729
+ return
729
730
  }
731
+
730
732
  throw new Error(
731
733
  `${proto.className}: Multiple mixins defining same property (${mixinProto.className}, ${proto[key]._from}) => ${key}`
732
734
  );
@@ -737,7 +739,7 @@ function mixinProperty(proto, mixinProto) {
737
739
  Object.getOwnPropertyDescriptor(proto, key)._from = mixinProto.className;
738
740
 
739
741
  if (typeof proto[key] === 'function') {
740
- proto[key]._name = key;
742
+ proto[key]._name = key
741
743
  }
742
744
  };
743
745
  }
@@ -749,8 +751,8 @@ function mixinProperty(proto, mixinProto) {
749
751
  */
750
752
  function mixReduce(mixinCls) {
751
753
  return (prev, current, idx, arr) => {
752
- return prev[current] = idx !== arr.length -1 ? prev[current] || {} : mixinCls;
753
- };
754
+ return prev[current] = idx !== arr.length -1 ? prev[current] || {} : mixinCls
755
+ }
754
756
  }
755
757
 
756
758
  /**
@@ -761,7 +763,7 @@ function mixReduce(mixinCls) {
761
763
  function parseArrayFromString(str) {
762
764
  return (extractArraysRegex.exec(str) || [null]).slice(1).reduce(
763
765
  (fun, args) => [fun].concat(args.match(charsRegex))
764
- );
766
+ )
765
767
  }
766
768
 
767
769
  Neo.config = Neo.config || {};
@@ -481,6 +481,8 @@ class CheckBox extends Base {
481
481
  * @returns {Boolean}
482
482
  */
483
483
  isValid() {
484
+ this.validate(true); // silent
485
+
484
486
  return this.error ? false : super.isValid()
485
487
  }
486
488
 
@@ -153,6 +153,7 @@ class FileUpload extends Base {
153
153
  UPLOADING : 'scanning',
154
154
 
155
155
  MALWARE_DETECTED : 'scan-failed',
156
+ UN_DOWNLOADABLE : 'not-downloadable',
156
157
  AVAILABLE : 'not-downloadable',
157
158
  DOWNLOADABLE : 'downloadable',
158
159
  DELETED : 'deleted'
@@ -317,6 +318,7 @@ class FileUpload extends Base {
317
318
  // UI strings which can be overridden for other languages
318
319
  chooseFile : 'Choose file',
319
320
  documentText : 'Document',
321
+ invalidFileFormat : 'invalid file format',
320
322
  pleaseUseTheseTypes : 'Please use these file types',
321
323
  fileSizeMoreThan : 'File size exceeds',
322
324
  documentDeleteError : 'Document delete service error',
@@ -346,16 +348,19 @@ class FileUpload extends Base {
346
348
  }
347
349
 
348
350
  afterSetId(value, oldValue) {
349
- const
350
- labelEl = this.vdom.cn[4],
351
- inputElId = `${this.id}-input`;
351
+ const inputElId = `${this.id}-input`;
352
352
 
353
- this.getInputEl().id = labelEl.for = inputElId;
354
- labelEl.html = this.chooseFile;
353
+ this.getInputEl().id = this.vdom.cn[4].for = inputElId;
355
354
 
356
355
  // silent vdom update, the super call will trigger the engine
357
356
  super.afterSetId?.(value, oldValue);
358
357
  }
358
+
359
+ onConstructed() {
360
+ super.onConstructed(...arguments);
361
+
362
+ this.vdom.cn[4].html = this.chooseFile;
363
+ }
359
364
 
360
365
  /**
361
366
  * @returns {Object}
@@ -388,7 +393,8 @@ class FileUpload extends Base {
388
393
  onInputValueChange({ files }) {
389
394
  const
390
395
  me = this,
391
- { types } = me;
396
+ { types } = me,
397
+ body = me.vdom.cn[1];
392
398
 
393
399
  if (files.length) {
394
400
  const
@@ -397,9 +403,13 @@ class FileUpload extends Base {
397
403
  type = pointPos > -1 ? file.name.slice(pointPos + 1) : '';
398
404
 
399
405
  if (me.types && !types[type]) {
406
+ body.cn[0].innerHTML = file.name;
407
+ body.cn[1].innerHTML = `${me.invalidFileFormat} (.${type}) ${me.formatSize(file.size)}`;
400
408
  me.error = `${me.pleaseUseTheseTypes}: .${Object.keys(types).join(' .')}`;
401
409
  }
402
410
  else if (file.size > me.maxSize) {
411
+ body.cn[0].innerHTML = file.name;
412
+ body.cn[1].innerHTML = me.formatSize(file.size);
403
413
  me.error = `${me.fileSizeMoreThan} ${String(me._maxSize).toUpperCase()}`;
404
414
  }
405
415
  // If it passes the type and maxSize check, upload it
@@ -553,6 +563,9 @@ class FileUpload extends Base {
553
563
  me.clear();
554
564
  me.state = 'ready';
555
565
  break;
566
+ case 'ready':
567
+ me.clear();
568
+ break;
556
569
  }
557
570
  }
558
571
 
@@ -23,7 +23,7 @@ class Text extends Base {
23
23
  * @protected
24
24
  * @static
25
25
  */
26
- static labelPositions = ['bottom', 'inline', 'left', 'right', 'top']
26
+ static labelPositions = ['bottom', 'inline', 'left', 'right', 'top']
27
27
 
28
28
  static config = {
29
29
  /**
@@ -220,18 +220,14 @@ class Text extends Base {
220
220
  * @member {Object} _vdom
221
221
  */
222
222
  _vdom:
223
- {
224
- cn: [
225
- {tag: 'label', cls: [], style: {}},
226
- {tag: 'label', cls: []},
227
- {tag: 'input', cls: ['neo-textfield-input'], flag: 'neo-real-input', style: {}},
228
- {
229
- cls: ['neo-textfield-error-wrapper'], removeDom: true, cn: [
230
- {cls: ['neo-textfield-error']}
231
- ]
232
- }
233
- ]
234
- }
223
+ {cn: [
224
+ {tag: 'label', cls: [], style: {}},
225
+ {tag: 'label', cls: []},
226
+ {tag: 'input', cls: ['neo-textfield-input'], flag: 'neo-real-input', style: {}},
227
+ {cls: ['neo-textfield-error-wrapper'], removeDom: true, cn: [
228
+ {cls: ['neo-textfield-error']}
229
+ ]}
230
+ ]}
235
231
  }
236
232
 
237
233
  /**
@@ -250,10 +246,10 @@ class Text extends Base {
250
246
  let me = this;
251
247
 
252
248
  me.addDomListeners([
253
- {input: me.onInputValueChange, scope: me},
249
+ {input : me.onInputValueChange, scope: me},
254
250
  {mouseenter: me.onMouseEnter, scope: me},
255
251
  {mouseleave: me.onMouseLeave, scope: me}
256
- ]);
252
+ ])
257
253
  }
258
254
 
259
255
  /**
@@ -263,13 +259,11 @@ class Text extends Base {
263
259
  * @protected
264
260
  */
265
261
  afterSetAppName(value, oldValue) {
266
- let me = this;
267
-
268
262
  super.afterSetAppName(value, oldValue);
269
263
 
270
- value && me.triggers?.forEach(item => {
264
+ value && this.triggers?.forEach(item => {
271
265
  item.appName = value;
272
- });
266
+ })
273
267
  }
274
268
 
275
269
  /**
@@ -279,7 +273,7 @@ class Text extends Base {
279
273
  * @protected
280
274
  */
281
275
  afterSetAutoCapitalize(value, oldValue) {
282
- this.changeInputElKey('autocapitalize', value === 'off' || value === 'none' ? null : value);
276
+ this.changeInputElKey('autocapitalize', value === 'off' || value === 'none' ? null : value)
283
277
  }
284
278
 
285
279
  /**
@@ -290,7 +284,7 @@ class Text extends Base {
290
284
  * @protected
291
285
  */
292
286
  afterSetAutoComplete(value, oldValue) {
293
- this.changeInputElKey('autocomplete', value ? null : 'no');
287
+ this.changeInputElKey('autocomplete', value ? null : 'no')
294
288
  }
295
289
 
296
290
  /**
@@ -306,9 +300,9 @@ class Text extends Base {
306
300
  if (value) {
307
301
  triggers = me.triggers || [];
308
302
  triggers.unshift(ClearTrigger);
309
- me.triggers = triggers;
303
+ me.triggers = triggers
310
304
  } else {
311
- me.removeTrigger('clear');
305
+ me.removeTrigger('clear')
312
306
  }
313
307
  }
314
308
 
@@ -505,7 +499,7 @@ class Text extends Base {
505
499
 
506
500
  !isEmpty && setTimeout(() => {
507
501
  me.updateCenterBorderElWidth(false)
508
- }, 20);
502
+ }, 20)
509
503
  } else {
510
504
  // changes from e.g. left to top
511
505
  me.updateInputWidth()
@@ -980,7 +974,7 @@ class Text extends Base {
980
974
  })
981
975
  }
982
976
 
983
- super.destroy(...args);
977
+ super.destroy(...args)
984
978
  }
985
979
 
986
980
  /**
@@ -1419,7 +1413,7 @@ class Text extends Base {
1419
1413
  * @param {Boolean} silent=true
1420
1414
  * @returns {Boolean} Returns true in case there are no client-side errors
1421
1415
  */
1422
- validate(silent = true) {
1416
+ validate(silent=true) {
1423
1417
  let me = this,
1424
1418
  maxLength = me.maxLength,
1425
1419
  minLength = me.minLength,
@@ -37,6 +37,18 @@ class AccordionTree extends TreeList {
37
37
  * @member {Boolean} firstParentIsVisible=true
38
38
  */
39
39
  firstParentIsVisible_: true,
40
+ /**
41
+ * Currently selected item, which is bindable
42
+ * @member {Record[|null} selection=null
43
+ *
44
+ * @example
45
+ * module: AccordionTree,
46
+ * bind : {selection: {twoWay: true, value: data => data.selection}}
47
+ *
48
+ * ntype: 'component',
49
+ * bind : {html: data => data.selection[0].name}
50
+ */
51
+ selection_: null,
40
52
  /**
41
53
  * @member {Object} _vdom
42
54
  */
@@ -133,12 +145,9 @@ class AccordionTree extends TreeList {
133
145
 
134
146
  if (parentId !== null) {
135
147
  vdomRoot.cn.push({
136
- tag : 'ul',
137
- cls : ['neo-list'],
138
- cn : [],
139
- style: {
140
- paddingLeft: '15px'
141
- }
148
+ tag: 'ul',
149
+ cls: ['neo-list'],
150
+ cn : []
142
151
  });
143
152
 
144
153
  tmpRoot = vdomRoot.cn[vdomRoot.cn.length - 1];
@@ -188,7 +197,6 @@ class AccordionTree extends TreeList {
188
197
  }]
189
198
  }],
190
199
  style: {
191
- padding : '10px',
192
200
  position: item.isLeaf ? null : 'sticky',
193
201
  top : item.isLeaf ? null : (level * 38) + 'px',
194
202
  zIndex : item.isLeaf ? null : (20 / (level + 1)),
@@ -257,6 +265,7 @@ class AccordionTree extends TreeList {
257
265
 
258
266
  /**
259
267
  * Accordion gaining focus without selection => setSelection
268
+ *
260
269
  * @param {Object} data
261
270
  */
262
271
  onFocus(data) {
@@ -267,8 +276,48 @@ class AccordionTree extends TreeList {
267
276
  if (!selection) selModel.selectRoot();
268
277
  }
269
278
 
270
- // Todo Might be needed
271
- onStoreLoad() {
279
+ /**
280
+ * Called from SelectionModel select()
281
+ *
282
+ * @param {String[]} value
283
+ */
284
+ onSelect(value) {
285
+ const me = this;
286
+ let records = [];
287
+
288
+ value.forEach((selectItemId) => {
289
+ let id = me.getItemRecordId(selectItemId),
290
+ record = me.store.get(id);
291
+
292
+ records.push(record);
293
+ });
294
+
295
+ me.selection = records;
296
+ }
297
+
298
+ /**
299
+ * After the store loaded, create the items for the list
300
+ *
301
+ * @param {Record[]} records
302
+ */
303
+ onStoreLoad(records) {
304
+ let me = this,
305
+ listenerId;
306
+
307
+ if (!me.mounted && me.rendering) {
308
+ listenerId = me.on('mounted', () => {
309
+ me.un('mounted', listenerId);
310
+ me.createItems(null, me.getListItemsRoot(), 0);
311
+ me.timeout(0).then(() => {
312
+ me.update()
313
+ });
314
+ });
315
+ } else {
316
+ me.createItems(null, me.getListItemsRoot(), 0);
317
+ me.timeout(0).then(() => {
318
+ me.update()
319
+ });
320
+ }
272
321
  }
273
322
 
274
323
  onStoreRecordChange() {