slim-select 2.3.3 → 2.4.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.
@@ -60,8 +60,7 @@ var SlimSelect = (function () {
60
60
  this.class = [];
61
61
  this.isMultiple = false;
62
62
  this.isOpen = false;
63
- this.isWindowFocused = true;
64
- this.triggerFocus = true;
63
+ this.isFullOpen = false;
65
64
  this.intervalMove = null;
66
65
  if (!settings) {
67
66
  settings = {};
@@ -348,6 +347,7 @@ var SlimSelect = (function () {
348
347
  this.main = this.mainDiv();
349
348
  this.content = this.contentDiv();
350
349
  this.updateClassStyles();
350
+ this.updateAriaAttributes();
351
351
  this.settings.contentLocation.appendChild(this.content.main);
352
352
  }
353
353
  enable() {
@@ -361,6 +361,7 @@ var SlimSelect = (function () {
361
361
  open() {
362
362
  this.main.arrow.path.setAttribute('d', this.classes.arrowOpen);
363
363
  this.main.main.classList.add(this.settings.openPosition === 'up' ? this.classes.openAbove : this.classes.openBelow);
364
+ this.main.main.setAttribute('aria-expanded', 'true');
364
365
  this.moveContent();
365
366
  const selectedOptions = this.store.getSelectedOptions();
366
367
  if (selectedOptions.length) {
@@ -374,6 +375,7 @@ var SlimSelect = (function () {
374
375
  close() {
375
376
  this.main.main.classList.remove(this.classes.openAbove);
376
377
  this.main.main.classList.remove(this.classes.openBelow);
378
+ this.main.main.setAttribute('aria-expanded', 'false');
377
379
  this.content.main.classList.remove(this.classes.openAbove);
378
380
  this.content.main.classList.remove(this.classes.openBelow);
379
381
  this.main.arrow.path.setAttribute('d', this.classes.arrowClose);
@@ -400,15 +402,18 @@ var SlimSelect = (function () {
400
402
  this.content.main.classList.add('ss-' + this.settings.contentPosition);
401
403
  }
402
404
  }
405
+ updateAriaAttributes() {
406
+ this.main.main.role = 'combobox';
407
+ this.main.main.setAttribute('aria-haspopup', 'listbox');
408
+ this.main.main.setAttribute('aria-controls', this.content.main.id);
409
+ this.main.main.setAttribute('aria-expanded', 'false');
410
+ this.content.main.setAttribute('role', 'listbox');
411
+ }
403
412
  mainDiv() {
404
413
  const main = document.createElement('div');
405
414
  main.dataset.id = this.settings.id;
415
+ main.id = this.settings.id;
406
416
  main.tabIndex = 0;
407
- main.onfocus = () => {
408
- if (this.settings.triggerFocus && this.settings.isWindowFocused) {
409
- this.callbacks.open();
410
- }
411
- };
412
417
  main.onkeydown = (e) => {
413
418
  switch (e.key) {
414
419
  case 'ArrowUp':
@@ -420,6 +425,8 @@ var SlimSelect = (function () {
420
425
  this.callbacks.close();
421
426
  return true;
422
427
  case 'Enter':
428
+ case ' ':
429
+ this.callbacks.open();
423
430
  const highlighted = this.content.list.querySelector('.' + this.classes.highlighted);
424
431
  if (highlighted) {
425
432
  highlighted.click();
@@ -496,12 +503,10 @@ var SlimSelect = (function () {
496
503
  },
497
504
  };
498
505
  }
499
- mainFocus(trigger) {
500
- if (!trigger) {
501
- this.settings.triggerFocus = false;
506
+ mainFocus(eventType) {
507
+ if (eventType !== 'click') {
508
+ this.main.main.focus({ preventScroll: true });
502
509
  }
503
- this.main.main.focus({ preventScroll: true });
504
- this.settings.triggerFocus = true;
505
510
  }
506
511
  placeholder() {
507
512
  const placeholderOption = this.store.filter((o) => o.placeholder, false);
@@ -677,6 +682,7 @@ var SlimSelect = (function () {
677
682
  contentDiv() {
678
683
  const main = document.createElement('div');
679
684
  main.dataset.id = this.settings.id;
685
+ main.id = this.settings.id;
680
686
  const search = this.searchDiv();
681
687
  main.appendChild(search.main);
682
688
  const list = this.listDiv();
@@ -734,7 +740,6 @@ var SlimSelect = (function () {
734
740
  switch (e.key) {
735
741
  case 'ArrowUp':
736
742
  case 'ArrowDown':
737
- this.callbacks.open();
738
743
  e.key === 'ArrowDown' ? this.highlight('down') : this.highlight('up');
739
744
  return false;
740
745
  case 'Tab':
@@ -744,6 +749,7 @@ var SlimSelect = (function () {
744
749
  this.callbacks.close();
745
750
  return false;
746
751
  case 'Enter':
752
+ case ' ':
747
753
  if (this.callbacks.addable && e.ctrlKey) {
748
754
  addable.click();
749
755
  }
@@ -756,12 +762,6 @@ var SlimSelect = (function () {
756
762
  return false;
757
763
  }
758
764
  };
759
- input.onfocus = () => {
760
- if (this.settings.isOpen) {
761
- return;
762
- }
763
- this.callbacks.open();
764
- };
765
765
  main.appendChild(input);
766
766
  if (this.callbacks.addable) {
767
767
  addable.classList.add(this.classes.addable);
@@ -834,12 +834,8 @@ var SlimSelect = (function () {
834
834
  }
835
835
  return searchReturn;
836
836
  }
837
- searchFocus(trigger) {
838
- if (!trigger) {
839
- this.settings.triggerFocus = false;
840
- }
837
+ searchFocus() {
841
838
  this.content.search.input.focus();
842
- this.settings.triggerFocus = true;
843
839
  }
844
840
  getOptions(notPlaceholder = false, notDisabled = false, notHidden = false) {
845
841
  let query = '.' + this.classes.option;
@@ -895,7 +891,6 @@ var SlimSelect = (function () {
895
891
  listDiv() {
896
892
  const options = document.createElement('div');
897
893
  options.classList.add(this.classes.list);
898
- options.setAttribute('role', 'listbox');
899
894
  return options;
900
895
  }
901
896
  renderError(error) {
@@ -1040,6 +1035,7 @@ var SlimSelect = (function () {
1040
1035
  }
1041
1036
  const optionEl = document.createElement('div');
1042
1037
  optionEl.dataset.id = option.id;
1038
+ optionEl.id = option.id;
1043
1039
  optionEl.classList.add(this.classes.option);
1044
1040
  optionEl.setAttribute('role', 'option');
1045
1041
  if (option.class) {
@@ -1073,9 +1069,12 @@ var SlimSelect = (function () {
1073
1069
  }
1074
1070
  if (option.selected) {
1075
1071
  optionEl.classList.add(this.classes.selected);
1072
+ optionEl.setAttribute('aria-selected', 'true');
1073
+ this.main.main.setAttribute('aria-activedescendant', optionEl.id);
1076
1074
  }
1077
1075
  else {
1078
1076
  optionEl.classList.remove(this.classes.selected);
1077
+ optionEl.setAttribute('aria-selected', 'false');
1079
1078
  }
1080
1079
  optionEl.addEventListener('click', (e) => {
1081
1080
  e.preventDefault();
@@ -1493,13 +1492,13 @@ var SlimSelect = (function () {
1493
1492
  afterClose: undefined,
1494
1493
  };
1495
1494
  this.windowResize = debounce(() => {
1496
- if (!this.settings.isOpen) {
1495
+ if (!this.settings.isOpen && !this.settings.isFullOpen) {
1497
1496
  return;
1498
1497
  }
1499
1498
  this.render.moveContent();
1500
1499
  });
1501
1500
  this.windowScroll = debounce(() => {
1502
- if (!this.settings.isOpen) {
1501
+ if (!this.settings.isOpen && !this.settings.isFullOpen) {
1503
1502
  return;
1504
1503
  }
1505
1504
  this.render.moveContent();
@@ -1509,19 +1508,13 @@ var SlimSelect = (function () {
1509
1508
  return;
1510
1509
  }
1511
1510
  if (e.target && !hasClassInTree(e.target, this.settings.id)) {
1512
- this.close();
1511
+ this.close(e.type);
1513
1512
  }
1514
1513
  };
1515
1514
  this.windowVisibilityChange = () => {
1516
1515
  if (document.hidden) {
1517
- this.settings.isWindowFocused = false;
1518
1516
  this.close();
1519
1517
  }
1520
- else {
1521
- setTimeout(() => {
1522
- this.settings.isWindowFocused = true;
1523
- }, 20);
1524
- }
1525
1518
  };
1526
1519
  this.selectEl = (typeof config.select === 'string' ? document.querySelector(config.select) : config.select);
1527
1520
  if (!this.selectEl) {
@@ -1594,6 +1587,14 @@ var SlimSelect = (function () {
1594
1587
  this.render = new Render(this.settings, this.store, callbacks);
1595
1588
  this.render.renderValues();
1596
1589
  this.render.renderOptions(this.store.getData());
1590
+ const selectAriaLabel = this.selectEl.getAttribute('aria-label');
1591
+ const selectAriaLabelledBy = this.selectEl.getAttribute('aria-labelledby');
1592
+ if (selectAriaLabel) {
1593
+ this.render.main.main.setAttribute('aria-label', selectAriaLabel);
1594
+ }
1595
+ else if (selectAriaLabelledBy) {
1596
+ this.render.main.main.setAttribute('aria-labelledby', selectAriaLabelledBy);
1597
+ }
1597
1598
  if (this.selectEl.parentNode) {
1598
1599
  this.selectEl.parentNode.insertBefore(this.render.main.main, this.selectEl.nextSibling);
1599
1600
  }
@@ -1683,13 +1684,16 @@ var SlimSelect = (function () {
1683
1684
  }
1684
1685
  this.render.open();
1685
1686
  if (this.settings.showSearch) {
1686
- this.render.searchFocus(false);
1687
+ this.render.searchFocus();
1687
1688
  }
1689
+ this.settings.isOpen = true;
1688
1690
  setTimeout(() => {
1689
1691
  if (this.events.afterOpen) {
1690
1692
  this.events.afterOpen();
1691
1693
  }
1692
- this.settings.isOpen = true;
1694
+ if (this.settings.isOpen) {
1695
+ this.settings.isFullOpen = true;
1696
+ }
1693
1697
  }, this.settings.timeoutDelay);
1694
1698
  if (this.settings.contentPosition === 'absolute') {
1695
1699
  if (this.settings.intervalMove) {
@@ -1698,7 +1702,7 @@ var SlimSelect = (function () {
1698
1702
  this.settings.intervalMove = setInterval(this.render.moveContent.bind(this.render), 500);
1699
1703
  }
1700
1704
  }
1701
- close() {
1705
+ close(eventType = null) {
1702
1706
  if (!this.settings.isOpen || this.settings.alwaysOpen) {
1703
1707
  return;
1704
1708
  }
@@ -1709,12 +1713,13 @@ var SlimSelect = (function () {
1709
1713
  if (this.render.content.search.input.value !== '') {
1710
1714
  this.search('');
1711
1715
  }
1712
- this.render.mainFocus(false);
1716
+ this.render.mainFocus(eventType);
1717
+ this.settings.isOpen = false;
1718
+ this.settings.isFullOpen = false;
1713
1719
  setTimeout(() => {
1714
1720
  if (this.events.afterClose) {
1715
1721
  this.events.afterClose();
1716
1722
  }
1717
- this.settings.isOpen = false;
1718
1723
  }, this.settings.timeoutDelay);
1719
1724
  if (this.settings.intervalMove) {
1720
1725
  clearInterval(this.settings.intervalMove);
@@ -63,8 +63,7 @@
63
63
  this.class = [];
64
64
  this.isMultiple = false;
65
65
  this.isOpen = false;
66
- this.isWindowFocused = true;
67
- this.triggerFocus = true;
66
+ this.isFullOpen = false;
68
67
  this.intervalMove = null;
69
68
  if (!settings) {
70
69
  settings = {};
@@ -351,6 +350,7 @@
351
350
  this.main = this.mainDiv();
352
351
  this.content = this.contentDiv();
353
352
  this.updateClassStyles();
353
+ this.updateAriaAttributes();
354
354
  this.settings.contentLocation.appendChild(this.content.main);
355
355
  }
356
356
  enable() {
@@ -364,6 +364,7 @@
364
364
  open() {
365
365
  this.main.arrow.path.setAttribute('d', this.classes.arrowOpen);
366
366
  this.main.main.classList.add(this.settings.openPosition === 'up' ? this.classes.openAbove : this.classes.openBelow);
367
+ this.main.main.setAttribute('aria-expanded', 'true');
367
368
  this.moveContent();
368
369
  const selectedOptions = this.store.getSelectedOptions();
369
370
  if (selectedOptions.length) {
@@ -377,6 +378,7 @@
377
378
  close() {
378
379
  this.main.main.classList.remove(this.classes.openAbove);
379
380
  this.main.main.classList.remove(this.classes.openBelow);
381
+ this.main.main.setAttribute('aria-expanded', 'false');
380
382
  this.content.main.classList.remove(this.classes.openAbove);
381
383
  this.content.main.classList.remove(this.classes.openBelow);
382
384
  this.main.arrow.path.setAttribute('d', this.classes.arrowClose);
@@ -403,15 +405,18 @@
403
405
  this.content.main.classList.add('ss-' + this.settings.contentPosition);
404
406
  }
405
407
  }
408
+ updateAriaAttributes() {
409
+ this.main.main.role = 'combobox';
410
+ this.main.main.setAttribute('aria-haspopup', 'listbox');
411
+ this.main.main.setAttribute('aria-controls', this.content.main.id);
412
+ this.main.main.setAttribute('aria-expanded', 'false');
413
+ this.content.main.setAttribute('role', 'listbox');
414
+ }
406
415
  mainDiv() {
407
416
  const main = document.createElement('div');
408
417
  main.dataset.id = this.settings.id;
418
+ main.id = this.settings.id;
409
419
  main.tabIndex = 0;
410
- main.onfocus = () => {
411
- if (this.settings.triggerFocus && this.settings.isWindowFocused) {
412
- this.callbacks.open();
413
- }
414
- };
415
420
  main.onkeydown = (e) => {
416
421
  switch (e.key) {
417
422
  case 'ArrowUp':
@@ -423,6 +428,8 @@
423
428
  this.callbacks.close();
424
429
  return true;
425
430
  case 'Enter':
431
+ case ' ':
432
+ this.callbacks.open();
426
433
  const highlighted = this.content.list.querySelector('.' + this.classes.highlighted);
427
434
  if (highlighted) {
428
435
  highlighted.click();
@@ -499,12 +506,10 @@
499
506
  },
500
507
  };
501
508
  }
502
- mainFocus(trigger) {
503
- if (!trigger) {
504
- this.settings.triggerFocus = false;
509
+ mainFocus(eventType) {
510
+ if (eventType !== 'click') {
511
+ this.main.main.focus({ preventScroll: true });
505
512
  }
506
- this.main.main.focus({ preventScroll: true });
507
- this.settings.triggerFocus = true;
508
513
  }
509
514
  placeholder() {
510
515
  const placeholderOption = this.store.filter((o) => o.placeholder, false);
@@ -680,6 +685,7 @@
680
685
  contentDiv() {
681
686
  const main = document.createElement('div');
682
687
  main.dataset.id = this.settings.id;
688
+ main.id = this.settings.id;
683
689
  const search = this.searchDiv();
684
690
  main.appendChild(search.main);
685
691
  const list = this.listDiv();
@@ -737,7 +743,6 @@
737
743
  switch (e.key) {
738
744
  case 'ArrowUp':
739
745
  case 'ArrowDown':
740
- this.callbacks.open();
741
746
  e.key === 'ArrowDown' ? this.highlight('down') : this.highlight('up');
742
747
  return false;
743
748
  case 'Tab':
@@ -747,6 +752,7 @@
747
752
  this.callbacks.close();
748
753
  return false;
749
754
  case 'Enter':
755
+ case ' ':
750
756
  if (this.callbacks.addable && e.ctrlKey) {
751
757
  addable.click();
752
758
  }
@@ -759,12 +765,6 @@
759
765
  return false;
760
766
  }
761
767
  };
762
- input.onfocus = () => {
763
- if (this.settings.isOpen) {
764
- return;
765
- }
766
- this.callbacks.open();
767
- };
768
768
  main.appendChild(input);
769
769
  if (this.callbacks.addable) {
770
770
  addable.classList.add(this.classes.addable);
@@ -837,12 +837,8 @@
837
837
  }
838
838
  return searchReturn;
839
839
  }
840
- searchFocus(trigger) {
841
- if (!trigger) {
842
- this.settings.triggerFocus = false;
843
- }
840
+ searchFocus() {
844
841
  this.content.search.input.focus();
845
- this.settings.triggerFocus = true;
846
842
  }
847
843
  getOptions(notPlaceholder = false, notDisabled = false, notHidden = false) {
848
844
  let query = '.' + this.classes.option;
@@ -898,7 +894,6 @@
898
894
  listDiv() {
899
895
  const options = document.createElement('div');
900
896
  options.classList.add(this.classes.list);
901
- options.setAttribute('role', 'listbox');
902
897
  return options;
903
898
  }
904
899
  renderError(error) {
@@ -1043,6 +1038,7 @@
1043
1038
  }
1044
1039
  const optionEl = document.createElement('div');
1045
1040
  optionEl.dataset.id = option.id;
1041
+ optionEl.id = option.id;
1046
1042
  optionEl.classList.add(this.classes.option);
1047
1043
  optionEl.setAttribute('role', 'option');
1048
1044
  if (option.class) {
@@ -1076,9 +1072,12 @@
1076
1072
  }
1077
1073
  if (option.selected) {
1078
1074
  optionEl.classList.add(this.classes.selected);
1075
+ optionEl.setAttribute('aria-selected', 'true');
1076
+ this.main.main.setAttribute('aria-activedescendant', optionEl.id);
1079
1077
  }
1080
1078
  else {
1081
1079
  optionEl.classList.remove(this.classes.selected);
1080
+ optionEl.setAttribute('aria-selected', 'false');
1082
1081
  }
1083
1082
  optionEl.addEventListener('click', (e) => {
1084
1083
  e.preventDefault();
@@ -1496,13 +1495,13 @@
1496
1495
  afterClose: undefined,
1497
1496
  };
1498
1497
  this.windowResize = debounce(() => {
1499
- if (!this.settings.isOpen) {
1498
+ if (!this.settings.isOpen && !this.settings.isFullOpen) {
1500
1499
  return;
1501
1500
  }
1502
1501
  this.render.moveContent();
1503
1502
  });
1504
1503
  this.windowScroll = debounce(() => {
1505
- if (!this.settings.isOpen) {
1504
+ if (!this.settings.isOpen && !this.settings.isFullOpen) {
1506
1505
  return;
1507
1506
  }
1508
1507
  this.render.moveContent();
@@ -1512,19 +1511,13 @@
1512
1511
  return;
1513
1512
  }
1514
1513
  if (e.target && !hasClassInTree(e.target, this.settings.id)) {
1515
- this.close();
1514
+ this.close(e.type);
1516
1515
  }
1517
1516
  };
1518
1517
  this.windowVisibilityChange = () => {
1519
1518
  if (document.hidden) {
1520
- this.settings.isWindowFocused = false;
1521
1519
  this.close();
1522
1520
  }
1523
- else {
1524
- setTimeout(() => {
1525
- this.settings.isWindowFocused = true;
1526
- }, 20);
1527
- }
1528
1521
  };
1529
1522
  this.selectEl = (typeof config.select === 'string' ? document.querySelector(config.select) : config.select);
1530
1523
  if (!this.selectEl) {
@@ -1597,6 +1590,14 @@
1597
1590
  this.render = new Render(this.settings, this.store, callbacks);
1598
1591
  this.render.renderValues();
1599
1592
  this.render.renderOptions(this.store.getData());
1593
+ const selectAriaLabel = this.selectEl.getAttribute('aria-label');
1594
+ const selectAriaLabelledBy = this.selectEl.getAttribute('aria-labelledby');
1595
+ if (selectAriaLabel) {
1596
+ this.render.main.main.setAttribute('aria-label', selectAriaLabel);
1597
+ }
1598
+ else if (selectAriaLabelledBy) {
1599
+ this.render.main.main.setAttribute('aria-labelledby', selectAriaLabelledBy);
1600
+ }
1600
1601
  if (this.selectEl.parentNode) {
1601
1602
  this.selectEl.parentNode.insertBefore(this.render.main.main, this.selectEl.nextSibling);
1602
1603
  }
@@ -1686,13 +1687,16 @@
1686
1687
  }
1687
1688
  this.render.open();
1688
1689
  if (this.settings.showSearch) {
1689
- this.render.searchFocus(false);
1690
+ this.render.searchFocus();
1690
1691
  }
1692
+ this.settings.isOpen = true;
1691
1693
  setTimeout(() => {
1692
1694
  if (this.events.afterOpen) {
1693
1695
  this.events.afterOpen();
1694
1696
  }
1695
- this.settings.isOpen = true;
1697
+ if (this.settings.isOpen) {
1698
+ this.settings.isFullOpen = true;
1699
+ }
1696
1700
  }, this.settings.timeoutDelay);
1697
1701
  if (this.settings.contentPosition === 'absolute') {
1698
1702
  if (this.settings.intervalMove) {
@@ -1701,7 +1705,7 @@
1701
1705
  this.settings.intervalMove = setInterval(this.render.moveContent.bind(this.render), 500);
1702
1706
  }
1703
1707
  }
1704
- close() {
1708
+ close(eventType = null) {
1705
1709
  if (!this.settings.isOpen || this.settings.alwaysOpen) {
1706
1710
  return;
1707
1711
  }
@@ -1712,12 +1716,13 @@
1712
1716
  if (this.render.content.search.input.value !== '') {
1713
1717
  this.search('');
1714
1718
  }
1715
- this.render.mainFocus(false);
1719
+ this.render.mainFocus(eventType);
1720
+ this.settings.isOpen = false;
1721
+ this.settings.isFullOpen = false;
1716
1722
  setTimeout(() => {
1717
1723
  if (this.events.afterClose) {
1718
1724
  this.events.afterClose();
1719
1725
  }
1720
- this.settings.isOpen = false;
1721
1726
  }, this.settings.timeoutDelay);
1722
1727
  if (this.settings.intervalMove) {
1723
1728
  clearInterval(this.settings.intervalMove);