@danielgindi/selectbox 1.0.122 → 1.0.124

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.
package/lib/DropList.js CHANGED
@@ -21,9 +21,9 @@ import {
21
21
  VALUE_DOWN,
22
22
  VALUE_END,
23
23
  VALUE_ENTER, VALUE_ESCAPE,
24
- VALUE_HOME,
24
+ VALUE_HOME, VALUE_LEFT,
25
25
  VALUE_PAGE_DOWN,
26
- VALUE_PAGE_UP,
26
+ VALUE_PAGE_UP, VALUE_RIGHT,
27
27
  VALUE_SPACE,
28
28
  VALUE_UP,
29
29
  } from 'keycode-js';
@@ -90,6 +90,7 @@ const hasOwnProperty = Object.prototype.hasOwnProperty;
90
90
  * @property {boolean} [_child=false]
91
91
  * @property {boolean} [_nocheck=false]
92
92
  * @property {boolean} [_nointeraction=false]
93
+ * @property {DropList.ItemBase[]} [_subitems]
93
94
  * */
94
95
 
95
96
  /**
@@ -136,6 +137,9 @@ Emits the following events:
136
137
  'hide:after': emitted after the hide css transition has ended, or immediately after 'hide'.
137
138
  'check' {value, item, checked: boolean, isGroup: boolean, isCheckingGroup: boolean}: item was selected (in multi mode).
138
139
  'groupcheck' {value, item, affectedItems}: item was selected (in multi mode).
140
+ 'show_subitems {value, item, el, droplist: DropList}': subitems dropdown will show.
141
+ 'hide_subitems {value, item, el}': subitems dropdown did hide.
142
+ 'subitems:select' {value, item, event?, el}: item was selected (in single mode).
139
143
  */
140
144
 
141
145
  // noinspection JSUnusedGlobalSymbols
@@ -168,6 +172,7 @@ class DropList {
168
172
  useExactTargetWidth: o.useExactTargetWidth,
169
173
  constrainToWindow: o.constrainToWindow,
170
174
  autoFlipDirection: o.autoFlipDirection,
175
+ estimatedItemHeight: o.estimatedItemHeight,
171
176
  estimateWidth: o.estimateWidth,
172
177
  virtualMinItems: o.virtualMinItems,
173
178
  labelProp: o.labelProp,
@@ -343,6 +348,11 @@ class DropList {
343
348
  remove(p.el);
344
349
  }
345
350
 
351
+ if (p.currentSubDropList) {
352
+ p.currentSubDropList?.droplist?.destroy();
353
+ p.currentSubDropList = null;
354
+ }
355
+
346
356
  if (!p.ownsEl) {
347
357
  for (let name of Array.from(p.el.classList)) {
348
358
  if (name.startsWith(p.baseClassName)) {
@@ -371,6 +381,22 @@ class DropList {
371
381
  return this._p.el;
372
382
  }
373
383
 
384
+ /**
385
+ * Returns true if other is an inclusive descendant of node, and false otherwise.
386
+ * @param {Node} other
387
+ * @param {boolean} [considerSubmenus=true]
388
+ * @returns {boolean}
389
+ */
390
+ elContains(other, considerSubmenus = true) {
391
+ if (this.el.contains(other))
392
+ return true;
393
+
394
+ if (considerSubmenus && this._p.currentSubDropList?.droplist?.elContains(other))
395
+ return true;
396
+
397
+ return false;
398
+ }
399
+
374
400
  /**
375
401
  * @param {string|string[]} classes
376
402
  * @returns {DropList}
@@ -508,6 +534,10 @@ class DropList {
508
534
  if (!item)
509
535
  return;
510
536
 
537
+ if (p.currentSubDropList) {
538
+ this._hideSublist();
539
+ }
540
+
511
541
  this._trigger('itemblur', { value: item.value, item: item[ItemSymbol] ?? item });
512
542
  }
513
543
 
@@ -617,6 +647,7 @@ class DropList {
617
647
  value: oitem[valueProp],
618
648
  _nocheck: !!oitem._nocheck,
619
649
  _nointeraction: !!oitem._nointeraction,
650
+ _subitems: oitem._subitems,
620
651
  };
621
652
 
622
653
  if (isMulti) {
@@ -692,6 +723,9 @@ class DropList {
692
723
  if (hasOwnProperty.call(newItem, '_nointeraction'))
693
724
  item._nointeraction = !!newItem._nointeraction;
694
725
 
726
+ if (hasOwnProperty.call(newItem, '_subitems'))
727
+ item._subitems = !!newItem._subitems;
728
+
695
729
  if (p.multi) {
696
730
  if (hasOwnProperty.call(newItem, '_checked'))
697
731
  item._checked = !!newItem._checked;
@@ -1292,6 +1326,10 @@ class DropList {
1292
1326
 
1293
1327
  if (this[DestroyedSymbol]) return;
1294
1328
  this._trigger('hide:after');
1329
+
1330
+ if (p.currentSubDropList) {
1331
+ this._hideSublist();
1332
+ }
1295
1333
  }
1296
1334
 
1297
1335
  if (p.lastPositionTarget) {
@@ -1347,18 +1385,99 @@ class DropList {
1347
1385
  itemElement.classList.add(`${p.baseClassName}__item_focus`);
1348
1386
  p.focusItemEl = itemElement;
1349
1387
 
1388
+ const item = itemElement[ItemSymbol];
1389
+
1350
1390
  this._trigger('itemfocus', {
1351
- value: itemElement.value,
1352
- item: itemElement[ItemSymbol],
1391
+ value: item.value,
1392
+ item: item[ItemSymbol] ?? item,
1353
1393
  event: null,
1354
1394
  el: itemElement,
1355
1395
  });
1396
+
1397
+ this._showSublist(item, itemElement);
1356
1398
  }
1357
1399
  }
1358
1400
 
1359
1401
  return this;
1360
1402
  }
1361
1403
 
1404
+ _showSublist(item, itemElement) {
1405
+ if (!item._subitems?.length) return;
1406
+
1407
+ const p = this._p;
1408
+
1409
+ const droplist = new DropList({
1410
+ baseClassName: p.baseClassName,
1411
+ additionalClasses: p.additionalClasses,
1412
+ direction: p.direction,
1413
+ autoItemBlur: p.autoItemBlur,
1414
+ autoItemBlurDelay: p.autoItemBlurDelay,
1415
+ capturesFocus: p.capturesFocus,
1416
+ multi: p.multi,
1417
+ keyDownHandler: p.keyDownHandler,
1418
+ autoCheckGroupChildren: p.autoCheckGroupChildren,
1419
+ useExactTargetWidth: p.useExactTargetWidth,
1420
+ constrainToWindow: p.constrainToWindow,
1421
+ autoFlipDirection: p.autoFlipDirection,
1422
+ estimatedItemHeight: p.estimatedItemHeight,
1423
+ estimateWidth: p.estimateWidth,
1424
+ virtualMinItems: p.virtualMinItems,
1425
+ labelProp: p.labelProp,
1426
+ valueProp: p.valueProp,
1427
+ renderItem: p.renderItem,
1428
+ unrenderItem: p.unrenderItem,
1429
+ });
1430
+
1431
+ droplist
1432
+ .on('select', event => {
1433
+ this._trigger('subitems:select', event);
1434
+ })
1435
+ .on('subitems:select', event => {
1436
+ this._trigger('subitems:select', event);
1437
+ });
1438
+
1439
+ droplist.setItems(item._subitems);
1440
+
1441
+ this._trigger('show_subitems', {
1442
+ value: item.value,
1443
+ item: item[ItemSymbol] ?? item,
1444
+ el: itemElement,
1445
+ droplist: droplist,
1446
+ });
1447
+
1448
+ droplist.show( {
1449
+ target: itemElement,
1450
+ position: { x: 'start', y: 'top' },
1451
+ anchor: { x: 'end', y: 'top' },
1452
+ offset: { x: 0, y: 0 },
1453
+ updateWidth: true,
1454
+ });
1455
+
1456
+ p.currentSubDropList = {
1457
+ item: item,
1458
+ itemElement: itemElement,
1459
+ droplist: droplist,
1460
+ };
1461
+ }
1462
+
1463
+ _hideSublist() {
1464
+ const p = this._p;
1465
+
1466
+ if (!p.currentSubDropList)
1467
+ return;
1468
+
1469
+ const data = p.currentSubDropList;
1470
+ data.droplist.hide();
1471
+ data.droplist.destroy();
1472
+ p.currentSubDropList = null;
1473
+
1474
+ this._trigger('hide_subitems', {
1475
+ value: data.item.value,
1476
+ item: data.item,
1477
+ el: data.itemElement,
1478
+ });
1479
+ }
1480
+
1362
1481
  setFocusedItem(item) {
1363
1482
  const p = this._p;
1364
1483
 
@@ -1600,7 +1719,7 @@ class DropList {
1600
1719
  }
1601
1720
 
1602
1721
  _handleMouseOver(event, itemEl) {
1603
- this._focus(event, itemEl);
1722
+ this._focus(event, itemEl, true);
1604
1723
  }
1605
1724
 
1606
1725
  _hookTouchEvents() {
@@ -1666,7 +1785,7 @@ class DropList {
1666
1785
  let itemEl = p.focusItemEl || // focused item
1667
1786
  p.el.firstChild; // or the first item
1668
1787
 
1669
- this._focus(event, itemEl);
1788
+ this._focus(event, itemEl, false);
1670
1789
  })
1671
1790
  .add(p.el, 'blur', () => {
1672
1791
  setTimeout(() => {
@@ -1725,6 +1844,21 @@ class DropList {
1725
1844
  }
1726
1845
  break;
1727
1846
 
1847
+ case VALUE_LEFT:
1848
+ case VALUE_RIGHT:
1849
+ if (event.key === VALUE_RIGHT && getComputedStyle(event.target).direction !== 'rtl' ||
1850
+ event.key === VALUE_LEFT && getComputedStyle(event.target).direction === 'rtl') {
1851
+ let item = p.items[p.focusItemIndex];
1852
+ if (p.focusItemIndex > -1 && item._subitems)
1853
+ this._showSublist(item, p.focusItemEl);
1854
+ } else {
1855
+ if (p.currentSubDropList) {
1856
+ p.currentSubDropList.hide();
1857
+ preventDefault = false;
1858
+ }
1859
+ }
1860
+ break;
1861
+
1728
1862
  case VALUE_ENTER:
1729
1863
  this.triggerItemSelection(null, event);
1730
1864
  event.preventDefault();
@@ -1801,7 +1935,7 @@ class DropList {
1801
1935
 
1802
1936
  if (matchIndex > -1) {
1803
1937
  let next = p.virtualListHelper.getItemElementAt(matchIndex);
1804
- this._focus(evt, next || null, matchIndex);
1938
+ this._focus(evt, next || null, matchIndex, true);
1805
1939
 
1806
1940
  if (!this.isVisible()) {
1807
1941
  this.triggerItemSelection(next ? null : p.items[matchIndex], evt);
@@ -1820,7 +1954,7 @@ class DropList {
1820
1954
  }
1821
1955
  }
1822
1956
 
1823
- _focus(event, itemEl, itemIndex) {
1957
+ _focus(event, itemEl, itemIndex, openSubitems) {
1824
1958
  const p = this._p;
1825
1959
 
1826
1960
  if (!itemIndex && itemEl) {
@@ -1851,7 +1985,15 @@ class DropList {
1851
1985
  p.focusItemIndex = itemIndex;
1852
1986
 
1853
1987
  const item = p.items[itemIndex];
1854
- this._trigger('itemfocus', { value: item.value, item: item[ItemSymbol] ?? item, event: event, el: focusItemEl });
1988
+ this._trigger('itemfocus', {
1989
+ value: item.value,
1990
+ item: item[ItemSymbol] ?? item,
1991
+ event: event,
1992
+ el: focusItemEl,
1993
+ });
1994
+
1995
+ if (openSubitems)
1996
+ this._showSublist(item, focusItemEl);
1855
1997
  }
1856
1998
 
1857
1999
  _delayBlurItemOnBlur() {
@@ -1995,7 +2137,7 @@ class DropList {
1995
2137
  }
1996
2138
 
1997
2139
  next = p.virtualListHelper.getItemElementAt(nextIndex);
1998
- this._focus(event, next || null, nextIndex);
2140
+ this._focus(event, next || null, nextIndex, false);
1999
2141
 
2000
2142
  if (!this.isVisible()) {
2001
2143
  this.triggerItemSelection(item, event);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@danielgindi/selectbox",
3
- "version": "1.0.122",
3
+ "version": "1.0.124",
4
4
  "description": "A collection of dom utilities. So you can work natively with the dom without dom frameworks.",
5
5
  "main": "dist/lib.cjs.min.js",
6
6
  "module": "lib/index.js",
@@ -31,22 +31,22 @@
31
31
  "homepage": "https://github.com/danielgindi/selectbox#readme",
32
32
  "license": "MIT",
33
33
  "devDependencies": {
34
- "@babel/core": "^7.23.9",
35
- "@babel/preset-env": "^7.23.9",
36
- "@babel/runtime": "^7.23.9",
34
+ "@babel/core": "^7.24.3",
35
+ "@babel/preset-env": "^7.24.3",
36
+ "@babel/runtime": "^7.24.1",
37
37
  "@rollup/plugin-babel": "^6.0.4",
38
38
  "@rollup/plugin-commonjs": "^25.0.7",
39
39
  "@rollup/plugin-node-resolve": "^15.2.3",
40
40
  "@rollup/plugin-terser": "^0.4.4",
41
- "core-js": "^3.35.1",
42
- "eslint": "^8.56.0",
41
+ "core-js": "^3.36.1",
42
+ "eslint": "^8.57.0",
43
43
  "eslint-formatter-codeframe": "^7.32.1",
44
- "eslint-plugin-vue": "^9.21.1",
44
+ "eslint-plugin-vue": "^9.24.0",
45
45
  "fs-extra": "^11.2.0",
46
- "husky": "^9.0.10",
46
+ "husky": "^9.0.11",
47
47
  "pinst": "^3.0.0",
48
- "rollup": "^4.10.0",
49
- "sass": "^1.70.0"
48
+ "rollup": "^4.13.2",
49
+ "sass": "^1.72.0"
50
50
  },
51
51
  "dependencies": {
52
52
  "@danielgindi/dom-utils": "^1.0.8",
package/vue/DropList.vue CHANGED
@@ -10,7 +10,13 @@ import { version } from 'vue';
10
10
 
11
11
  const isVue3 = version > '3.';
12
12
 
13
- const AllListEvents = ['itemfocus', 'itemblur', 'select', 'show:before', 'show', 'hide:before', 'hide', 'hide:after', 'check', 'groupcheck'];
13
+ const AllListEvents = [
14
+ 'itemfocus', 'itemblur', 'select',
15
+ 'show:before', 'show',
16
+ 'hide:before', 'hide', 'hide:after',
17
+ 'check', 'groupcheck',
18
+ 'show_subitems', 'hide_subitems', 'subitems:select',
19
+ ];
14
20
 
15
21
  export default {
16
22
  inheritAttrs: false,