slim-select 2.4.0 → 2.4.2

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/README.md CHANGED
@@ -1,10 +1,9 @@
1
1
  # Slim Select 2
2
2
 
3
- ## slimselectjs.com
3
+ ## [slimselectjs.com](https://slimselectjs.com)
4
4
 
5
5
  Advanced select dropdown
6
6
 
7
- [![Build Status](https://travis-ci.org/brianvoe/slim-select.svg?branch=master)](https://travis-ci.org/brianvoe/slim-select)
8
7
  [![NPM Downloads](https://img.shields.io/npm/dt/slim-select.svg)](https://www.npmjs.com/package/slim-select)
9
8
 
10
9
  ## Support
@@ -13,7 +12,9 @@ Advanced select dropdown
13
12
 
14
13
  <a href="https://www.buymeacoffee.com/brianvoe" target="_blank"><img src="https://www.buymeacoffee.com/assets/img/custom_images/orange_img.png" alt="Buy Me A Coffee" style="height: auto !important;width: auto !important;" ></a>
15
14
 
16
- For documentation and examples on all features see: http://slimselectjs.com
15
+ ## [Documentation and Examples](https://slimselectjs.com)
16
+
17
+ See [website](https://slimselectjs.com) for the full list of settings, methods and event callbacks
17
18
 
18
19
  ![](https://raw.githubusercontent.com/brianvoe/slim-select/master/slimselect.gif)
19
20
 
@@ -55,12 +56,123 @@ npm install slim-select
55
56
  <link rel="stylesheet" href="https://unpkg.com/slim-select@latest/dist/slimselect.css" />
56
57
  ```
57
58
 
58
- ## Usage
59
+ ## Simple Usage
59
60
 
60
61
  ```javascript
61
62
  import SlimSelect from 'slim-select'
62
63
 
63
64
  new SlimSelect({
64
- select: '#slim-select',
65
+ select: '#selectElement',
66
+ })
67
+ ```
68
+
69
+ ```html
70
+ <select id="selectElement">
71
+ <option value="value1">Value 1</option>
72
+ </select>
73
+ ```
74
+
75
+ ## Data
76
+
77
+ Data is an array of objects that represent both option and optgroups.
78
+
79
+ See below for list of data types
80
+
81
+ ```javascript
82
+ new SlimSelect({
83
+ select: '#selectElement',
84
+
85
+ // Array of Option objects
86
+ data: [{ text: 'Value 1', value: 'value1' }],
87
+
88
+ // or
89
+
90
+ // Array of Optgroups and/or Options
91
+ data: [{ label: 'Optgroup Label', options: { text: 'Value 1', value: 'value1' } }],
92
+ })
93
+ ```
94
+
95
+ ## Data Types
96
+
97
+ ```javascript
98
+ // <optgroup>
99
+ var optgroup = {
100
+ label: 'label', // Required
101
+ selectAll: false, // Optional - default false
102
+ closable: 'off', // Optional - default 'off' - 'off', 'open', 'close'
103
+ options: [], // Required - value is an array of options
104
+ }
105
+
106
+ // <option>
107
+ var option = {
108
+ text: 'text', // Required
109
+ value: 'value', // Optional - value will be set by text if not set
110
+ html: '<b>Html</b>', // Optional - if set, used for display purposes
111
+ selected: false, // Optional - default is false
112
+ display: true, // Optional - default is true
113
+ disabled: false, // Optional - default is false
114
+ mandatory: false, // Optional - default is false
115
+ placeholder: false, // Optional - default is false
116
+ class: '', // Optional - default is not set
117
+ style: '', // Optional - default is not set
118
+ data: {}, // Optional - If you have data attributes
119
+ }
120
+ ```
121
+
122
+ ## Settings
123
+
124
+ Settings are a list of fields that help customize how SlimSelect operates
125
+
126
+ ```javascript
127
+ new SlimSelect({
128
+ select: '#selectElement',
129
+
130
+ settings: {
131
+ // Below are a list of optional fields
132
+ // their values are the defaults
133
+ disabled: false,
134
+ alwaysOpen: false,
135
+ showSearch: true,
136
+ searchPlaceholder: 'Search',
137
+ searchText: 'No Results',
138
+ searchingText: 'Searching...',
139
+ searchHighlight: false,
140
+ closeOnSelect: true,
141
+ contentLocation: document.body,
142
+ contentPosition: 'absolute',
143
+ openPosition: 'auto', // options: auto, up, down
144
+ placeholderText: 'Select Value',
145
+ allowDeselect: false,
146
+ hideSelected: false,
147
+ showOptionTooltips: false,
148
+ minSelected: 0,
149
+ maxSelected: 1000,
150
+ timeoutDelay: 200,
151
+ maxValuesShown: 20,
152
+ maxValuesMessage: '{number} selected',
153
+ },
154
+ })
155
+ ```
156
+
157
+ ## Events
158
+
159
+ Events are function callbacks for when certain actions happen
160
+
161
+ ```javascript
162
+ new SlimSelect({
163
+ select: '#selectElement',
164
+
165
+ events: {
166
+ search: (searchValue: string, currentData: DataArray) => Promise<DataArrayPartial> | DataArrayPartial
167
+ searchFilter: (option: Option, search: string) => boolean
168
+ addable: (value: string) => Promise<OptionOptional | string> | OptionOptional | string
169
+ beforeChange: (newVal: Option[], oldVal: Option[]) => boolean | void
170
+ afterChange: (newVal: Option[]) => void
171
+ beforeOpen: () => void
172
+ afterOpen: () => void
173
+ beforeClose: () => void
174
+ afterClose: () => void
175
+ error: (err: Error) => void
176
+ },
65
177
  })
66
178
  ```
package/dist/render.d.ts CHANGED
@@ -93,7 +93,7 @@ export default class Render {
93
93
  updateClassStyles(): void;
94
94
  updateAriaAttributes(): void;
95
95
  mainDiv(): Main;
96
- mainFocus(trigger: boolean, eventType: string | null): void;
96
+ mainFocus(eventType: string | null): void;
97
97
  placeholder(): HTMLDivElement;
98
98
  renderValues(): void;
99
99
  private renderSingleValue;
@@ -102,7 +102,7 @@ export default class Render {
102
102
  contentDiv(): Content;
103
103
  moveContent(): void;
104
104
  searchDiv(): Search;
105
- searchFocus(trigger: boolean): void;
105
+ searchFocus(): void;
106
106
  getOptions(notPlaceholder?: boolean, notDisabled?: boolean, notHidden?: boolean): HTMLDivElement[];
107
107
  highlight(dir: 'up' | 'down'): void;
108
108
  listDiv(): HTMLDivElement;
@@ -6,8 +6,7 @@ export default class Settings {
6
6
  class: string[];
7
7
  isMultiple: boolean;
8
8
  isOpen: boolean;
9
- isWindowFocused: boolean;
10
- triggerFocus: boolean;
9
+ isFullOpen: boolean;
11
10
  intervalMove: NodeJS.Timeout | null;
12
11
  disabled: boolean;
13
12
  alwaysOpen: boolean;
@@ -59,8 +59,7 @@ class Settings {
59
59
  this.class = [];
60
60
  this.isMultiple = false;
61
61
  this.isOpen = false;
62
- this.isWindowFocused = true;
63
- this.triggerFocus = true;
62
+ this.isFullOpen = false;
64
63
  this.intervalMove = null;
65
64
  if (!settings) {
66
65
  settings = {};
@@ -503,14 +502,10 @@ class Render {
503
502
  },
504
503
  };
505
504
  }
506
- mainFocus(trigger, eventType) {
507
- if (!trigger) {
508
- this.settings.triggerFocus = false;
509
- }
505
+ mainFocus(eventType) {
510
506
  if (eventType !== 'click') {
511
507
  this.main.main.focus({ preventScroll: true });
512
508
  }
513
- this.settings.triggerFocus = true;
514
509
  }
515
510
  placeholder() {
516
511
  const placeholderOption = this.store.filter((o) => o.placeholder, false);
@@ -744,7 +739,6 @@ class Render {
744
739
  switch (e.key) {
745
740
  case 'ArrowUp':
746
741
  case 'ArrowDown':
747
- this.callbacks.open();
748
742
  e.key === 'ArrowDown' ? this.highlight('down') : this.highlight('up');
749
743
  return false;
750
744
  case 'Tab':
@@ -757,21 +751,17 @@ class Render {
757
751
  case ' ':
758
752
  if (this.callbacks.addable && e.ctrlKey) {
759
753
  addable.click();
754
+ return false;
760
755
  }
761
756
  else {
762
757
  const highlighted = this.content.list.querySelector('.' + this.classes.highlighted);
763
758
  if (highlighted) {
764
759
  highlighted.click();
760
+ return false;
765
761
  }
766
762
  }
767
- return false;
768
- }
769
- };
770
- input.onfocus = () => {
771
- if (this.settings.isOpen) {
772
- return;
763
+ return true;
773
764
  }
774
- this.callbacks.open();
775
765
  };
776
766
  main.appendChild(input);
777
767
  if (this.callbacks.addable) {
@@ -845,12 +835,8 @@ class Render {
845
835
  }
846
836
  return searchReturn;
847
837
  }
848
- searchFocus(trigger) {
849
- if (!trigger) {
850
- this.settings.triggerFocus = false;
851
- }
838
+ searchFocus() {
852
839
  this.content.search.input.focus();
853
- this.settings.triggerFocus = true;
854
840
  }
855
841
  getOptions(notPlaceholder = false, notDisabled = false, notHidden = false) {
856
842
  let query = '.' + this.classes.option;
@@ -1507,13 +1493,13 @@ class SlimSelect {
1507
1493
  afterClose: undefined,
1508
1494
  };
1509
1495
  this.windowResize = debounce(() => {
1510
- if (!this.settings.isOpen) {
1496
+ if (!this.settings.isOpen && !this.settings.isFullOpen) {
1511
1497
  return;
1512
1498
  }
1513
1499
  this.render.moveContent();
1514
1500
  });
1515
1501
  this.windowScroll = debounce(() => {
1516
- if (!this.settings.isOpen) {
1502
+ if (!this.settings.isOpen && !this.settings.isFullOpen) {
1517
1503
  return;
1518
1504
  }
1519
1505
  this.render.moveContent();
@@ -1528,14 +1514,8 @@ class SlimSelect {
1528
1514
  };
1529
1515
  this.windowVisibilityChange = () => {
1530
1516
  if (document.hidden) {
1531
- this.settings.isWindowFocused = false;
1532
1517
  this.close();
1533
1518
  }
1534
- else {
1535
- setTimeout(() => {
1536
- this.settings.isWindowFocused = true;
1537
- }, 20);
1538
- }
1539
1519
  };
1540
1520
  this.selectEl = (typeof config.select === 'string' ? document.querySelector(config.select) : config.select);
1541
1521
  if (!this.selectEl) {
@@ -1705,13 +1685,16 @@ class SlimSelect {
1705
1685
  }
1706
1686
  this.render.open();
1707
1687
  if (this.settings.showSearch) {
1708
- this.render.searchFocus(false);
1688
+ this.render.searchFocus();
1709
1689
  }
1690
+ this.settings.isOpen = true;
1710
1691
  setTimeout(() => {
1711
1692
  if (this.events.afterOpen) {
1712
1693
  this.events.afterOpen();
1713
1694
  }
1714
- this.settings.isOpen = true;
1695
+ if (this.settings.isOpen) {
1696
+ this.settings.isFullOpen = true;
1697
+ }
1715
1698
  }, this.settings.timeoutDelay);
1716
1699
  if (this.settings.contentPosition === 'absolute') {
1717
1700
  if (this.settings.intervalMove) {
@@ -1731,12 +1714,13 @@ class SlimSelect {
1731
1714
  if (this.render.content.search.input.value !== '') {
1732
1715
  this.search('');
1733
1716
  }
1734
- this.render.mainFocus(false, eventType);
1717
+ this.render.mainFocus(eventType);
1718
+ this.settings.isOpen = false;
1719
+ this.settings.isFullOpen = false;
1735
1720
  setTimeout(() => {
1736
1721
  if (this.events.afterClose) {
1737
1722
  this.events.afterClose();
1738
1723
  }
1739
- this.settings.isOpen = false;
1740
1724
  }, this.settings.timeoutDelay);
1741
1725
  if (this.settings.intervalMove) {
1742
1726
  clearInterval(this.settings.intervalMove);
@@ -57,8 +57,7 @@ class Settings {
57
57
  this.class = [];
58
58
  this.isMultiple = false;
59
59
  this.isOpen = false;
60
- this.isWindowFocused = true;
61
- this.triggerFocus = true;
60
+ this.isFullOpen = false;
62
61
  this.intervalMove = null;
63
62
  if (!settings) {
64
63
  settings = {};
@@ -501,14 +500,10 @@ class Render {
501
500
  },
502
501
  };
503
502
  }
504
- mainFocus(trigger, eventType) {
505
- if (!trigger) {
506
- this.settings.triggerFocus = false;
507
- }
503
+ mainFocus(eventType) {
508
504
  if (eventType !== 'click') {
509
505
  this.main.main.focus({ preventScroll: true });
510
506
  }
511
- this.settings.triggerFocus = true;
512
507
  }
513
508
  placeholder() {
514
509
  const placeholderOption = this.store.filter((o) => o.placeholder, false);
@@ -742,7 +737,6 @@ class Render {
742
737
  switch (e.key) {
743
738
  case 'ArrowUp':
744
739
  case 'ArrowDown':
745
- this.callbacks.open();
746
740
  e.key === 'ArrowDown' ? this.highlight('down') : this.highlight('up');
747
741
  return false;
748
742
  case 'Tab':
@@ -755,21 +749,17 @@ class Render {
755
749
  case ' ':
756
750
  if (this.callbacks.addable && e.ctrlKey) {
757
751
  addable.click();
752
+ return false;
758
753
  }
759
754
  else {
760
755
  const highlighted = this.content.list.querySelector('.' + this.classes.highlighted);
761
756
  if (highlighted) {
762
757
  highlighted.click();
758
+ return false;
763
759
  }
764
760
  }
765
- return false;
766
- }
767
- };
768
- input.onfocus = () => {
769
- if (this.settings.isOpen) {
770
- return;
761
+ return true;
771
762
  }
772
- this.callbacks.open();
773
763
  };
774
764
  main.appendChild(input);
775
765
  if (this.callbacks.addable) {
@@ -843,12 +833,8 @@ class Render {
843
833
  }
844
834
  return searchReturn;
845
835
  }
846
- searchFocus(trigger) {
847
- if (!trigger) {
848
- this.settings.triggerFocus = false;
849
- }
836
+ searchFocus() {
850
837
  this.content.search.input.focus();
851
- this.settings.triggerFocus = true;
852
838
  }
853
839
  getOptions(notPlaceholder = false, notDisabled = false, notHidden = false) {
854
840
  let query = '.' + this.classes.option;
@@ -1505,13 +1491,13 @@ class SlimSelect {
1505
1491
  afterClose: undefined,
1506
1492
  };
1507
1493
  this.windowResize = debounce(() => {
1508
- if (!this.settings.isOpen) {
1494
+ if (!this.settings.isOpen && !this.settings.isFullOpen) {
1509
1495
  return;
1510
1496
  }
1511
1497
  this.render.moveContent();
1512
1498
  });
1513
1499
  this.windowScroll = debounce(() => {
1514
- if (!this.settings.isOpen) {
1500
+ if (!this.settings.isOpen && !this.settings.isFullOpen) {
1515
1501
  return;
1516
1502
  }
1517
1503
  this.render.moveContent();
@@ -1526,14 +1512,8 @@ class SlimSelect {
1526
1512
  };
1527
1513
  this.windowVisibilityChange = () => {
1528
1514
  if (document.hidden) {
1529
- this.settings.isWindowFocused = false;
1530
1515
  this.close();
1531
1516
  }
1532
- else {
1533
- setTimeout(() => {
1534
- this.settings.isWindowFocused = true;
1535
- }, 20);
1536
- }
1537
1517
  };
1538
1518
  this.selectEl = (typeof config.select === 'string' ? document.querySelector(config.select) : config.select);
1539
1519
  if (!this.selectEl) {
@@ -1703,13 +1683,16 @@ class SlimSelect {
1703
1683
  }
1704
1684
  this.render.open();
1705
1685
  if (this.settings.showSearch) {
1706
- this.render.searchFocus(false);
1686
+ this.render.searchFocus();
1707
1687
  }
1688
+ this.settings.isOpen = true;
1708
1689
  setTimeout(() => {
1709
1690
  if (this.events.afterOpen) {
1710
1691
  this.events.afterOpen();
1711
1692
  }
1712
- this.settings.isOpen = true;
1693
+ if (this.settings.isOpen) {
1694
+ this.settings.isFullOpen = true;
1695
+ }
1713
1696
  }, this.settings.timeoutDelay);
1714
1697
  if (this.settings.contentPosition === 'absolute') {
1715
1698
  if (this.settings.intervalMove) {
@@ -1729,12 +1712,13 @@ class SlimSelect {
1729
1712
  if (this.render.content.search.input.value !== '') {
1730
1713
  this.search('');
1731
1714
  }
1732
- this.render.mainFocus(false, eventType);
1715
+ this.render.mainFocus(eventType);
1716
+ this.settings.isOpen = false;
1717
+ this.settings.isFullOpen = false;
1733
1718
  setTimeout(() => {
1734
1719
  if (this.events.afterClose) {
1735
1720
  this.events.afterClose();
1736
1721
  }
1737
- this.settings.isOpen = false;
1738
1722
  }, this.settings.timeoutDelay);
1739
1723
  if (this.settings.intervalMove) {
1740
1724
  clearInterval(this.settings.intervalMove);
@@ -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 = {};
@@ -504,14 +503,10 @@ var SlimSelect = (function () {
504
503
  },
505
504
  };
506
505
  }
507
- mainFocus(trigger, eventType) {
508
- if (!trigger) {
509
- this.settings.triggerFocus = false;
510
- }
506
+ mainFocus(eventType) {
511
507
  if (eventType !== 'click') {
512
508
  this.main.main.focus({ preventScroll: true });
513
509
  }
514
- this.settings.triggerFocus = true;
515
510
  }
516
511
  placeholder() {
517
512
  const placeholderOption = this.store.filter((o) => o.placeholder, false);
@@ -745,7 +740,6 @@ var SlimSelect = (function () {
745
740
  switch (e.key) {
746
741
  case 'ArrowUp':
747
742
  case 'ArrowDown':
748
- this.callbacks.open();
749
743
  e.key === 'ArrowDown' ? this.highlight('down') : this.highlight('up');
750
744
  return false;
751
745
  case 'Tab':
@@ -758,21 +752,17 @@ var SlimSelect = (function () {
758
752
  case ' ':
759
753
  if (this.callbacks.addable && e.ctrlKey) {
760
754
  addable.click();
755
+ return false;
761
756
  }
762
757
  else {
763
758
  const highlighted = this.content.list.querySelector('.' + this.classes.highlighted);
764
759
  if (highlighted) {
765
760
  highlighted.click();
761
+ return false;
766
762
  }
767
763
  }
768
- return false;
769
- }
770
- };
771
- input.onfocus = () => {
772
- if (this.settings.isOpen) {
773
- return;
764
+ return true;
774
765
  }
775
- this.callbacks.open();
776
766
  };
777
767
  main.appendChild(input);
778
768
  if (this.callbacks.addable) {
@@ -846,12 +836,8 @@ var SlimSelect = (function () {
846
836
  }
847
837
  return searchReturn;
848
838
  }
849
- searchFocus(trigger) {
850
- if (!trigger) {
851
- this.settings.triggerFocus = false;
852
- }
839
+ searchFocus() {
853
840
  this.content.search.input.focus();
854
- this.settings.triggerFocus = true;
855
841
  }
856
842
  getOptions(notPlaceholder = false, notDisabled = false, notHidden = false) {
857
843
  let query = '.' + this.classes.option;
@@ -1508,13 +1494,13 @@ var SlimSelect = (function () {
1508
1494
  afterClose: undefined,
1509
1495
  };
1510
1496
  this.windowResize = debounce(() => {
1511
- if (!this.settings.isOpen) {
1497
+ if (!this.settings.isOpen && !this.settings.isFullOpen) {
1512
1498
  return;
1513
1499
  }
1514
1500
  this.render.moveContent();
1515
1501
  });
1516
1502
  this.windowScroll = debounce(() => {
1517
- if (!this.settings.isOpen) {
1503
+ if (!this.settings.isOpen && !this.settings.isFullOpen) {
1518
1504
  return;
1519
1505
  }
1520
1506
  this.render.moveContent();
@@ -1529,14 +1515,8 @@ var SlimSelect = (function () {
1529
1515
  };
1530
1516
  this.windowVisibilityChange = () => {
1531
1517
  if (document.hidden) {
1532
- this.settings.isWindowFocused = false;
1533
1518
  this.close();
1534
1519
  }
1535
- else {
1536
- setTimeout(() => {
1537
- this.settings.isWindowFocused = true;
1538
- }, 20);
1539
- }
1540
1520
  };
1541
1521
  this.selectEl = (typeof config.select === 'string' ? document.querySelector(config.select) : config.select);
1542
1522
  if (!this.selectEl) {
@@ -1706,13 +1686,16 @@ var SlimSelect = (function () {
1706
1686
  }
1707
1687
  this.render.open();
1708
1688
  if (this.settings.showSearch) {
1709
- this.render.searchFocus(false);
1689
+ this.render.searchFocus();
1710
1690
  }
1691
+ this.settings.isOpen = true;
1711
1692
  setTimeout(() => {
1712
1693
  if (this.events.afterOpen) {
1713
1694
  this.events.afterOpen();
1714
1695
  }
1715
- this.settings.isOpen = true;
1696
+ if (this.settings.isOpen) {
1697
+ this.settings.isFullOpen = true;
1698
+ }
1716
1699
  }, this.settings.timeoutDelay);
1717
1700
  if (this.settings.contentPosition === 'absolute') {
1718
1701
  if (this.settings.intervalMove) {
@@ -1732,12 +1715,13 @@ var SlimSelect = (function () {
1732
1715
  if (this.render.content.search.input.value !== '') {
1733
1716
  this.search('');
1734
1717
  }
1735
- this.render.mainFocus(false, eventType);
1718
+ this.render.mainFocus(eventType);
1719
+ this.settings.isOpen = false;
1720
+ this.settings.isFullOpen = false;
1736
1721
  setTimeout(() => {
1737
1722
  if (this.events.afterClose) {
1738
1723
  this.events.afterClose();
1739
1724
  }
1740
- this.settings.isOpen = false;
1741
1725
  }, this.settings.timeoutDelay);
1742
1726
  if (this.settings.intervalMove) {
1743
1727
  clearInterval(this.settings.intervalMove);