neo.mjs 6.0.1 → 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.1'
23
+ * @member {String} version='6.0.3'
24
24
  */
25
- version: '6.0.1'
25
+ version: '6.0.3'
26
26
  }
27
27
 
28
28
  /**
@@ -390,31 +390,18 @@ class MainContainerController extends ComponentController {
390
390
  logo.vdom.src = logoPath + (theme === 'neo-theme-dark' ? 'covid_logo_dark.jpg' : 'covid_logo_light.jpg');
391
391
  logo.update();
392
392
 
393
+ cls = [...component.cls];
393
394
 
394
- if (Neo.config.useCssVars) {
395
- cls = [...component.cls];
396
-
397
- component.cls.forEach(item => {
398
- if (item.includes('neo-theme')) {
399
- NeoArray.remove(cls, item);
400
- }
401
- });
395
+ component.cls.forEach(item => {
396
+ if (item.includes('neo-theme')) {
397
+ NeoArray.remove(cls, item);
398
+ }
399
+ });
402
400
 
403
- NeoArray.add(cls, theme);
404
- component.cls = cls;
401
+ NeoArray.add(cls, theme);
402
+ component.cls = cls;
405
403
 
406
- button.set({
407
- iconCls,
408
- text: buttonText
409
- });
410
- } else {
411
- Neo.main.addon.Stylesheet.swapStyleSheet({
412
- href: href,
413
- id : 'neo-theme'
414
- }).then(data => {
415
- button.text = buttonText;
416
- });
417
- }
404
+ button.set({iconCls, text: buttonText});
418
405
 
419
406
  if (mapView) {
420
407
  mapView.mapboxStyle = mapViewStyle;
@@ -580,42 +580,23 @@ class MainContainerController extends ComponentController {
580
580
  logo.vdom.src = logoPath + (theme === 'neo-theme-dark' ? 'covid_logo_dark.jpg' : 'covid_logo_light.jpg');
581
581
  logo.update();
582
582
 
583
+ [component.appName, ...me.connectedApps].forEach(appName => {
584
+ component = me.getMainView(appName);
583
585
 
584
- if (Neo.config.useCssVars) {
585
- [component.appName, ...me.connectedApps].forEach(appName => {
586
- component = me.getMainView(appName);
586
+ cls = [...component.cls];
587
587
 
588
- cls = [...component.cls];
589
-
590
- component.cls.forEach(item => {
591
- if (item.includes('neo-theme')) {
592
- NeoArray.remove(cls, item);
593
- }
594
- });
595
-
596
- NeoArray.add(cls, theme);
597
- component.cls = cls;
598
- });
599
-
600
- button.set({
601
- iconCls,
602
- text: buttonText
603
- });
604
- } else {
605
- [component.appName, ...me.connectedApps].forEach(appName => {
606
- Neo.main.addon.Stylesheet.swapStyleSheet({
607
- appName,
608
- href,
609
- id: 'neo-theme'
610
- });
588
+ component.cls.forEach(item => {
589
+ if (item.includes('neo-theme')) {
590
+ NeoArray.remove(cls, item)
591
+ }
611
592
  });
612
- }
613
593
 
614
- button.set({
615
- iconCls,
616
- text: buttonText
594
+ NeoArray.add(cls, theme);
595
+ component.cls = cls;
617
596
  });
618
597
 
598
+ button.set({iconCls, text: buttonText});
599
+
619
600
  if (mapView) {
620
601
  mapView.mapboxStyle = mapViewStyle;
621
602
  } else {
@@ -192,20 +192,18 @@ class MainContainerController extends Component {
192
192
  theme = 'neo-theme-dark';
193
193
  }
194
194
 
195
- if (Neo.config.useCssVars) {
196
- cls = [...view.cls];
195
+ cls = [...view.cls];
197
196
 
198
- view.cls.forEach((item, index) => {
199
- if (item.includes('neo-theme')) {
200
- NeoArray.remove(cls, item);
201
- }
202
- });
197
+ view.cls.forEach(item => {
198
+ if (item.includes('neo-theme')) {
199
+ NeoArray.remove(cls, item)
200
+ }
201
+ });
203
202
 
204
- NeoArray.add(cls, theme);
205
- view.cls = cls;
203
+ NeoArray.add(cls, theme);
204
+ view.cls = cls;
206
205
 
207
- button.text = buttonText;
208
- }
206
+ button.text = buttonText
209
207
  }
210
208
 
211
209
  /**
@@ -20,9 +20,9 @@ class ServiceWorker extends ServiceBase {
20
20
  */
21
21
  singleton: true,
22
22
  /**
23
- * @member {String} version='6.0.1'
23
+ * @member {String} version='6.0.3'
24
24
  */
25
- version: '6.0.1'
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.1",
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) {
@@ -153,7 +153,6 @@ const DefaultConfig = {
153
153
  renderCountDeltas: false,
154
154
  /**
155
155
  * Add themes you want to use here. The first theme will get applied.
156
- * If config.useCssVars === true, other theme variables will get included as well
157
156
  * @default ['neo-theme-light', 'neo-theme-dark']
158
157
  * @memberOf! module:Neo
159
158
  * @name config.themes
@@ -168,14 +167,6 @@ const DefaultConfig = {
168
167
  * @type Boolean
169
168
  */
170
169
  unitTestMode: false,
171
- /**
172
- * Flag if CSS variable based stylesheets are in use (important for switching themes)
173
- * @default true
174
- * @memberOf! module:Neo
175
- * @name config.useCssVars
176
- * @type Boolean
177
- */
178
- useCssVars: true,
179
170
  /**
180
171
  * Experimental flag if an offscreen canvas worker should get created.
181
172
  * @default false
@@ -245,12 +236,12 @@ const DefaultConfig = {
245
236
  useVdomWorker: true,
246
237
  /**
247
238
  * buildScripts/injectPackageVersion.mjs will update this value
248
- * @default '6.0.1'
239
+ * @default '6.0.3'
249
240
  * @memberOf! module:Neo
250
241
  * @name config.version
251
242
  * @type String
252
243
  */
253
- version: '6.0.1'
244
+ version: '6.0.3'
254
245
  };
255
246
 
256
247
  Object.assign(DefaultConfig, {
package/src/Main.mjs CHANGED
@@ -50,6 +50,7 @@ class Main extends core.Base {
50
50
  'editRoute',
51
51
  'getByPath',
52
52
  'getWindowData',
53
+ 'importAddon',
53
54
  'redirectTo',
54
55
  'setNeoConfig',
55
56
  'setRoute',
@@ -192,9 +193,25 @@ class Main extends core.Base {
192
193
  };
193
194
  }
194
195
 
195
- // todo: https://developer.mozilla.org/en-US/docs/Web/Events/resize
196
- globalResizeListener(event) {
197
- console.log('globalResizeListener', event);
196
+ /**
197
+ * Import main thread addons at run-time from within the app worker
198
+ * @param {Object} data
199
+ * @param {String} data.name
200
+ * @returns {Boolean}
201
+ */
202
+ async importAddon(data) {
203
+ let name = data.name,
204
+ module;
205
+
206
+ if (name.startsWith('WS/')) {
207
+ module = await import(`../../../src/main/addon/${name.substring(3)}.mjs`)
208
+ } else {
209
+ module = await import(`./main/addon/${name}.mjs`)
210
+ }
211
+
212
+ this.addon[module.default.constructor.name] = module.default;
213
+
214
+ return true
198
215
  }
199
216
 
200
217
  /**
@@ -209,9 +226,6 @@ class Main extends core.Base {
209
226
 
210
227
  DomAccess.onDomContentLoaded();
211
228
 
212
- // not in use right now
213
- // window.addEventListener('resize', me.globalResizeListener.bind(me));
214
-
215
229
  // we need different publicPath values for the main thread inside the webpack based dist envs,
216
230
  // depending on the hierarchy level of the app entry point
217
231
  if (config.environment !== 'development') {
@@ -229,7 +243,7 @@ class Main extends core.Base {
229
243
 
230
244
  mainThreadAddons.forEach(addon => {
231
245
  if (addon.startsWith('WS/')) {
232
- imports.push(import(`../../../src/main/addon/${addon.substr(3)}.mjs`));
246
+ imports.push(import(`../../../src/main/addon/${addon.substring(3)}.mjs`));
233
247
  } else {
234
248
  imports.push(import(`./main/addon/${addon}.mjs`));
235
249
  }
@@ -245,7 +259,7 @@ class Main extends core.Base {
245
259
 
246
260
  WorkerManager.onWorkerConstructed({
247
261
  origin: 'main'
248
- });
262
+ })
249
263
  }
250
264
 
251
265
  /**
@@ -258,7 +272,7 @@ class Main extends core.Base {
258
272
  action : 'reply',
259
273
  replyId: data.id,
260
274
  success: true
261
- });
275
+ })
262
276
  }
263
277
 
264
278
  /**
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,
@@ -118,8 +118,8 @@ class DomEvents extends Base {
118
118
 
119
119
  let me = this;
120
120
 
121
- document.addEventListener('selectionchange', me.onSelectionChange .bind(me));
122
121
  document.addEventListener('DOMContentLoaded', me.onDomContentLoaded.bind(me));
122
+ document.addEventListener('selectionchange', me.onSelectionChange .bind(me));
123
123
  window .addEventListener('hashchange', me.onHashChange .bind(me));
124
124
 
125
125
  if (Neo.config.useSharedWorkers) {
@@ -332,6 +332,11 @@ class DomEvents extends Base {
332
332
  return path
333
333
  }
334
334
 
335
+ /**
336
+ * @param {Object[]} path
337
+ * @param {HTMLElement} target
338
+ * @returns {Object[]}
339
+ */
335
340
  getSelectionPath(path, target) {
336
341
  if (target.parentNode && target.id.split('__').length > 1) {
337
342
  path = this.getSelectionPath(path, target.parentNode);
@@ -343,7 +348,7 @@ class DomEvents extends Base {
343
348
  }
344
349
 
345
350
  /**
346
- * @param {Object} node
351
+ * @param {HTMLElement} node
347
352
  * @returns {Object}
348
353
  */
349
354
  getTargetData(node) {
@@ -72,7 +72,7 @@ class Stylesheet extends Base {
72
72
  addGlobalCss() {
73
73
  let config = Neo.config,
74
74
  themes = config.themes,
75
- folders = config.useCssVars ? ['src', ...themes] : [themes[0]],
75
+ folders = ['src', ...themes],
76
76
  env = config.environment,
77
77
  path = env.startsWith('dist/') ? '' : config.appPath.includes('docs') ? `../dist/${env}/` : `../../dist/${env}/`,
78
78
  rootPath = config.basePath.substr(6);
@@ -87,7 +87,7 @@ class Stylesheet extends Base {
87
87
  this.createStyleSheet(
88
88
  null,
89
89
  null,
90
- `${rootPath}${path}css${config.useCssVars ? '' : '-no-vars'}/${folder}/Global.css`
90
+ `${rootPath}${path}css/${folder}/Global.css`
91
91
  );
92
92
  });
93
93
  }
@@ -112,19 +112,14 @@ class Stylesheet extends Base {
112
112
  className = className.split('.').join('/');
113
113
 
114
114
  data.folders.forEach(folder => {
115
- if (
116
- folder === 'src' && config.useCssVars || folder.includes('theme-') && (
117
- config.useCssVars && config.themes.includes(`neo-${folder}`) ||
118
- !config.useCssVars && config.themes[0] === `neo-${folder}`
119
- )
120
- ) {
115
+ if (folder === 'src' || folder.includes('theme-') && config.themes.includes(`neo-${folder}`)) {
121
116
  this.createStyleSheet(
122
117
  null,
123
118
  null,
124
- `${rootPath}${path}css${config.useCssVars ? '' : '-no-vars'}/${folder}/${className}.css`
125
- );
119
+ `${rootPath}${path}css/${folder}/${className}.css`
120
+ )
126
121
  }
127
- });
122
+ })
128
123
  }
129
124
 
130
125
  /**
@@ -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() {
@@ -313,7 +313,7 @@ class App extends Base {
313
313
  super.onRegisterNeoConfig(msg);
314
314
 
315
315
  let config = Neo.config,
316
- url = `resources/theme-map${config.useCssVars ? '' : '-no-vars'}.json`;
316
+ url = 'resources/theme-map.json';
317
317
 
318
318
  if (config.environment === 'development') {
319
319
  url = `../../${url}`
@@ -1,17 +0,0 @@
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 Docs NoCssVars</title>
7
- </head>
8
- <body>
9
- <script type="module">
10
- fetch('./neo-config-no-css-vars.json').then(response => response.json()).then(data => {
11
- self.Neo = {config: {}};
12
- Object.assign(Neo.config, data);
13
- import(data.mainPath);
14
- });
15
- </script>
16
- </body>
17
- </html>
@@ -1,8 +0,0 @@
1
- {
2
- "appPath" : "docs/app.mjs",
3
- "basePath" : "../",
4
- "environment" : "development",
5
- "mainPath" : "../src/Main.mjs",
6
- "mainThreadAddons": ["DragDrop", "HighlightJS", "Stylesheet"],
7
- "useCssVars" : false
8
- }