neo.mjs 6.12.0 → 6.12.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.
@@ -20,9 +20,9 @@ class ServiceWorker extends ServiceBase {
20
20
  */
21
21
  singleton: true,
22
22
  /**
23
- * @member {String} version='6.12.0'
23
+ * @member {String} version='6.12.1'
24
24
  */
25
- version: '6.12.0'
25
+ version: '6.12.1'
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.12.0'
23
+ * @member {String} version='6.12.1'
24
24
  */
25
- version: '6.12.0'
25
+ version: '6.12.1'
26
26
  }
27
27
 
28
28
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "neo.mjs",
3
- "version": "6.12.0",
3
+ "version": "6.12.1",
4
4
  "description": "The webworkers driven UI framework",
5
5
  "type": "module",
6
6
  "repository": {
@@ -62,7 +62,7 @@
62
62
  "url": "^0.11.3",
63
63
  "webpack": "^5.90.1",
64
64
  "webpack-cli": "^5.1.4",
65
- "webpack-dev-server": "4.15.1",
65
+ "webpack-dev-server": "5.0.1",
66
66
  "webpack-hook-plugin": "^1.0.7",
67
67
  "webpack-node-externals": "^3.0.0"
68
68
  },
@@ -236,12 +236,12 @@ const DefaultConfig = {
236
236
  useVdomWorker: true,
237
237
  /**
238
238
  * buildScripts/injectPackageVersion.mjs will update this value
239
- * @default '6.12.0'
239
+ * @default '6.12.1'
240
240
  * @memberOf! module:Neo
241
241
  * @name config.version
242
242
  * @type String
243
243
  */
244
- version: '6.12.0'
244
+ version: '6.12.1'
245
245
  };
246
246
 
247
247
  Object.assign(DefaultConfig, {
@@ -32,6 +32,10 @@ class Select extends Picker {
32
32
  * @protected
33
33
  */
34
34
  ntype: 'selectfield',
35
+ /**
36
+ * @member {String|Number|null} activeRecordId=null
37
+ */
38
+ activeRecordId: null,
35
39
  /**
36
40
  * @member {String[]} baseCls=['neo-selectfield','neo-pickerfield','neo-textfield']
37
41
  */
@@ -40,6 +44,12 @@ class Select extends Picker {
40
44
  * @member {String} displayField='name'
41
45
  */
42
46
  displayField: 'name',
47
+ /**
48
+ * The millisecond time to delay between input field mutation and applying the input field's
49
+ * new value to the filter
50
+ * @member {Number} filterDelay=300
51
+ */
52
+ filterDelay : 300,
43
53
  /**
44
54
  * @member {String} filterOperator_='like'
45
55
  */
@@ -50,10 +60,6 @@ class Select extends Picker {
50
60
  * @member {Boolean} forceSelection=false
51
61
  */
52
62
  forceSelection: false,
53
- /**
54
- * @member {String|Number|null} activeRecordId=null
55
- */
56
- activeRecordId: null,
57
63
  /**
58
64
  * Additional used keys for the selection model
59
65
  * @member {Object} keys
@@ -116,13 +122,7 @@ class Select extends Picker {
116
122
  * which you want to submit instead
117
123
  * @member {Number|String} valueField='id'
118
124
  */
119
- valueField: 'id',
120
- /**
121
- * The millisecond time to delay between input field mutation and applying the input field's
122
- * new value to the filter
123
- * @member {Number} filterDelay=300
124
- */
125
- filterDelay : 300
125
+ valueField: 'id'
126
126
  }
127
127
 
128
128
  /**
@@ -143,7 +143,7 @@ class Select extends Picker {
143
143
  * @param {Object} oldValue
144
144
  * @protected
145
145
  */
146
- afterSetRecord(value) {
146
+ afterSetRecord(value, oldValue) {
147
147
  if (this._picker?.isVisible) {
148
148
  let me = this,
149
149
  selectionModel = me.list?.selectionModel;
@@ -252,7 +252,7 @@ class Select extends Picker {
252
252
  }
253
253
  }
254
254
 
255
- return ClassSystemUtil.beforeSetInstance(value, Store);
255
+ return ClassSystemUtil.beforeSetInstance(value, Store)
256
256
  }
257
257
 
258
258
  /**
@@ -305,16 +305,15 @@ class Select extends Picker {
305
305
  module : List,
306
306
  appName : me.appName,
307
307
  displayField : me.displayField,
308
- role : 'listbox',
309
308
  itemRole : 'option',
309
+ navigator : {eventSource : me.getInputElId()},
310
310
  parentId : me.id,
311
- navigator : {
312
- eventSource : me.getInputElId()
313
- },
311
+ role : 'listbox',
314
312
  selectionModel : {stayInList: false},
315
313
  store : me.store,
316
314
  ...me.listConfig
317
315
  });
316
+
318
317
  me.getInputEl()['aria-controls'] = me.list.id;
319
318
 
320
319
  me.list.addDomListeners({
@@ -323,15 +322,76 @@ class Select extends Picker {
323
322
  scope : me
324
323
  }
325
324
  });
325
+
326
326
  me.list.selectionModel.on({
327
- selectionChange : me.onListItemSelectionChange,
328
327
  noChange : me.onListItemSelectionNoChange,
328
+ selectionChange : me.onListItemSelectionChange,
329
329
  scope : me
330
330
  })
331
331
 
332
332
  return me.list;
333
333
  }
334
334
 
335
+ /**
336
+ * All routes which expect to open the picker route through here. This updates the
337
+ * filter and ensures that the picker is visible and reflecting the state of the filter.
338
+ *
339
+ * Input event processing passes the current input field value in as the filter value.
340
+ *
341
+ * Invocation of the expand trigger passes `null` so as to clear filtering.
342
+ * @private
343
+ * @param {String|null} value The value to filter the picker by
344
+ */
345
+ doFilter(value) {
346
+ let me = this,
347
+ filter = me.store.getFilter(me.displayField),
348
+ {
349
+ record,
350
+ picker
351
+ } = me;
352
+
353
+ if (filter) {
354
+ filter.value = value;
355
+ }
356
+
357
+ // Filter resulting in something to show
358
+ if (me.store.getCount()) {
359
+ me.getPicker().hidden = false;
360
+
361
+ // List might not exist until the picker is created
362
+ const
363
+ { list } = me,
364
+ { selectionModel } = list;
365
+
366
+ // On show, set the active item to be the current selected record or the first
367
+ if (record) {
368
+ // We do not want to hear back about our own selection
369
+ selectionModel.suspendEvents = true;
370
+ selectionModel.select(record);
371
+ selectionModel.suspendEvents = false;
372
+ }
373
+ setTimeout(() => {
374
+ list.activeIndex = me.record || 0;
375
+ }, 100)
376
+ }
377
+ // Filtered down to nothing - hide picker if it has been created.
378
+ else if (picker) {
379
+ picker._hidden = true;
380
+ }
381
+ }
382
+
383
+ /**
384
+ * @param {Object} data
385
+ */
386
+ filterOnInput(data) {
387
+ if (data.value) {
388
+ this.doFilter(data.value);
389
+ }
390
+ else if (this.picker) {
391
+ this.picker?.hide();
392
+ }
393
+ }
394
+
335
395
  /**
336
396
  * Overrides form.field.Base
337
397
  * @param {*} value
@@ -383,7 +443,7 @@ class Select extends Picker {
383
443
 
384
444
  /**
385
445
  * Returns the first selected record or null
386
- * returns {Object}
446
+ * @returns {Object}
387
447
  */
388
448
  getRecord() {
389
449
  let list = this.list,
@@ -401,13 +461,17 @@ class Select extends Picker {
401
461
  return me.record?.[me.valueField] || me.value
402
462
  }
403
463
 
464
+ /**
465
+ *
466
+ */
404
467
  onConstructed() {
405
468
  const inputEl = this.getInputEl();
406
469
 
407
- inputEl['aria-expanded'] = false
408
- inputEl['aria-haspopup'] = 'listbox'
409
- inputEl['aria-activedescendant'] = ''
410
- super.onConstructed(...arguments);
470
+ inputEl['aria-activedescendant'] = '';
471
+ inputEl['aria-expanded'] = false;
472
+ inputEl['aria-haspopup'] = 'listbox';
473
+
474
+ super.onConstructed(...arguments)
411
475
  }
412
476
 
413
477
  /**
@@ -439,15 +503,6 @@ class Select extends Picker {
439
503
  super.onFocusLeave(data)
440
504
  }
441
505
 
442
- filterOnInput(data) {
443
- if (data.value) {
444
- this.doFilter(data.value);
445
- }
446
- else if (this.picker) {
447
- this.picker?.hide();
448
- }
449
- }
450
-
451
506
  /**
452
507
  * @param {Object} data
453
508
  * @protected
@@ -469,17 +524,6 @@ class Select extends Picker {
469
524
  }
470
525
  }
471
526
 
472
- onPickerHiddenChange({ value }) {
473
- const inputEl = this.getInputEl();
474
-
475
- super.onPickerHiddenChange(...arguments);
476
- if (value) {
477
- inputEl['aria-activedescendant'] = '';
478
- }
479
- inputEl['aria-expanded'] = !value;
480
- this.update();
481
- }
482
-
483
527
  // TODO:
484
528
  // When we are using a `Collection` as our `valueCollection`, and that `Collection` is the
485
529
  // `items` of the List's `selectionModel`, then this will be `onValueCollectionChange`,
@@ -541,6 +585,34 @@ class Select extends Picker {
541
585
  }
542
586
  }
543
587
 
588
+ /**
589
+ * @param {Object} data
590
+ */
591
+ onPickerHiddenChange({ value }) {
592
+ const inputEl = this.getInputEl();
593
+
594
+ super.onPickerHiddenChange(...arguments);
595
+ if (value) {
596
+ inputEl['aria-activedescendant'] = '';
597
+ }
598
+ inputEl['aria-expanded'] = !value;
599
+ this.update();
600
+ }
601
+
602
+ /**
603
+ *
604
+ */
605
+ onPickerTriggerClick() {
606
+ let me = this;
607
+
608
+ if (me.picker?.isVisible) {
609
+ me.picker.hidden = true;
610
+ }
611
+ else if (!me.readOnly && !me.disabled) {
612
+ me.doFilter(null)
613
+ }
614
+ }
615
+
544
616
  /**
545
617
  * Selecting a record, if required
546
618
  * @param {Object[]} items
@@ -587,65 +659,6 @@ class Select extends Picker {
587
659
  me.list.selectItem(index);
588
660
  }
589
661
 
590
- onPickerTriggerClick() {
591
- let me = this;
592
-
593
- if (me.picker?.isVisible) {
594
- me.picker.hidden = true;
595
- }
596
- else if (!me.readOnly && !me.disabled) {
597
- me.doFilter(null)
598
- }
599
- }
600
-
601
- /**
602
- * All routes which expect to open the picker route through here. This updates the
603
- * filter and ensures that the picker is visible and reflecting the state of the filter.
604
- *
605
- * Input event processing passes the current input field value in as the filter value.
606
- *
607
- * Invocation of the expand trigger passes `null` so as to clear filtering.
608
- * @private
609
- * @param {String}null} value The value to filter the picker by
610
- */
611
- doFilter(value) {
612
- let me = this,
613
- filter = me.store.getFilter(me.displayField),
614
- {
615
- record,
616
- picker
617
- } = me;
618
-
619
- if (filter) {
620
- filter.value = value;
621
- }
622
-
623
- // Filter resulting in something to show
624
- if (me.store.getCount()) {
625
- me.getPicker().hidden = false;
626
-
627
- // List might not exist until the picker is created
628
- const
629
- { list } = me,
630
- { selectionModel } = list;
631
-
632
- // On show, set the active item to be the current selected record or the first
633
- if (record) {
634
- // We do not want to hear back about our own selection
635
- selectionModel.suspendEvents = true;
636
- selectionModel.select(record);
637
- selectionModel.suspendEvents = false;
638
- }
639
- setTimeout(() => {
640
- list.activeIndex = me.record || 0;
641
- }, 100)
642
- }
643
- // Filtered down to nothing - hide picker if it has been created.
644
- else if (picker) {
645
- picker._hidden = true;
646
- }
647
- }
648
-
649
662
  /**
650
663
  * @param {Boolean} [silent=false]
651
664
  * @protected
package/src/list/Base.mjs CHANGED
@@ -21,6 +21,7 @@ class Base extends Component {
21
21
  */
22
22
  ntype: 'list',
23
23
  /**
24
+ * Keeps track of the selected item index and allows bindings and programmatic changes
24
25
  * @member {Number|null} activeIndex_=null
25
26
  */
26
27
  activeIndex_: null,
@@ -63,6 +64,12 @@ class Base extends Component {
63
64
  * @member {Object} dragZoneConfig=null
64
65
  */
65
66
  dragZoneConfig: null,
67
+ /**
68
+ * Keeps track of the focussed item index and allows bindings and programmatic changes.
69
+ * You can either pass the index or the related record
70
+ * @member {Number|Object|null} focusIndex_=null
71
+ */
72
+ focusIndex_: null,
66
73
  /**
67
74
  * In case we are using list item headers and want to bind list item indexes to e.g. a card layout
68
75
  * for e.g. a sidenav, this config comes in handy.
@@ -178,15 +185,16 @@ class Base extends Component {
178
185
  * @param {Number|null} oldValue
179
186
  * @protected
180
187
  */
181
- afterSetActiveIndex(value) {
182
- let me = this;
188
+ afterSetActiveIndex(value, oldValue) {
189
+ let me = this,
190
+ selectionModel = me.selectionModel;
183
191
 
184
192
  if (Neo.isNumber(value)) {
193
+ selectionModel?.selectAt(value);
185
194
  me.headerlessActiveIndex = me.getHeaderlessIndex(value)
186
- Neo.main.addon.Navigator.navigateTo([value, this.navigator])
187
- }
188
- else if (value) {
189
- Neo.main.addon.Navigator.navigateTo([me.getItemId(value[me.getKeyProperty()]), this.navigator])
195
+ } else if (Neo.isNumber(oldValue)) {
196
+ selectionModel.deselectAll();
197
+ me.headerlessActiveIndex = null
190
198
  }
191
199
  }
192
200
 
@@ -243,6 +251,22 @@ class Base extends Component {
243
251
  }
244
252
  }
245
253
 
254
+ /**
255
+ * Triggered after the focusIndex config got changed
256
+ * @param {Number|Object|null} value
257
+ * @param {Number|Object|null} oldValue
258
+ * @protected
259
+ */
260
+ afterSetFocusIndex(value, oldValue) {
261
+ let me = this;
262
+
263
+ if (Neo.isNumber(value)) {
264
+ Neo.main.addon.Navigator.navigateTo([me.getHeaderlessIndex(value), me.navigator])
265
+ } else if (value) {
266
+ Neo.main.addon.Navigator.navigateTo([me.getItemId(value[me.getKeyProperty()]), me.navigator])
267
+ }
268
+ }
269
+
246
270
  /**
247
271
  * Triggered after the headerlessActiveIndex config got changed
248
272
  * @param {Number} value
@@ -253,7 +277,7 @@ class Base extends Component {
253
277
  let me = this;
254
278
 
255
279
  if (Neo.isNumber(value)) {
256
- me.activeIndex = me.store.getCount() ? value: null
280
+ me.activeIndex = me.store.getCount() ? me.getActiveIndex(value) : null
257
281
  } else if (Neo.isNumber(oldValue)) {
258
282
  me.activeIndex = null
259
283
  }
@@ -755,14 +779,16 @@ class Base extends Component {
755
779
  * @param {Number|String} item
756
780
  */
757
781
  selectItem(item) {
758
- if (!this.disableSelection) {
782
+ let me = this;
783
+
784
+ if (!me.disableSelection) {
759
785
  // Selecting index
760
786
  if (Neo.isNumber(item)) {
761
- this.selectionModel?.selectAt(item)
787
+ me.selectionModel?.selectAt(item)
762
788
  }
763
789
  // Selecting record
764
790
  else if (item) {
765
- this.selectionModel?.selectAt(this.store.indexOf(item));
791
+ me.selectionModel?.selectAt(me.store.indexOf(item))
766
792
  }
767
793
  }
768
794
  }
@@ -77,8 +77,10 @@ class ListModel extends Model {
77
77
  { view } = this,
78
78
  { store } = view;
79
79
 
80
- data.record = store.getAt(Math.min(data.activeIndex, store.getCount()));
81
- view.fire('itemNavigate', data);
80
+ data.record = store.getAt(Math.min(data.activeIndex, store.getCount()));
81
+ view._focusIndex = store.indexOf(data.record); // silent update, no need to refocus
82
+
83
+ view.fire('itemNavigate', data)
82
84
  }
83
85
 
84
86
  /**