slim-select 2.3.0 → 2.3.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/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "slim-select",
3
3
  "description": "Slim advanced select dropdown",
4
- "version": "2.3.0",
4
+ "version": "2.3.2",
5
5
  "author": "Brian Voelker <brian@webiswhatido.com> (http://webiswhatido.com)",
6
6
  "homepage": "https://slimselectjs.com",
7
7
  "license": "MIT",
@@ -55,7 +55,7 @@
55
55
  "downloadjs": "^1.4.7",
56
56
  "jest": "^29.3.1",
57
57
  "jest-environment-jsdom": "^29.3.1",
58
- "prettier": "^2.8.0",
58
+ "prettier": "^2.8.1",
59
59
  "prismjs": "^1.29.0",
60
60
  "rimraf": "^3.0.2",
61
61
  "rollup": "^2.79.1",
@@ -65,10 +65,10 @@
65
65
  "ts-jest": "^29.0.3",
66
66
  "tslib": "^2.4.1",
67
67
  "typescript": "^4.9.3",
68
- "vite": "^3.2.4",
68
+ "vite": "^3.2.5",
69
69
  "vue": "^3.2.45",
70
70
  "vue-router": "^4.1.6",
71
- "vue-tsc": "^1.0.9",
71
+ "vue-tsc": "^1.0.11",
72
72
  "vuex": "^4.0.2"
73
73
  }
74
74
  }
@@ -75,8 +75,17 @@ export default class SlimSelect {
75
75
  this.settings = new Settings(config.settings)
76
76
 
77
77
  // Set events
78
+ const debounceEvents = ['afterChange', 'beforeOpen', 'afterOpen', 'beforeClose', 'afterClose']
78
79
  for (const key in config.events) {
79
- if (config.events.hasOwnProperty(key)) {
80
+ // Check if key exists in events
81
+ if (!config.events.hasOwnProperty(key)) {
82
+ continue
83
+ }
84
+
85
+ // Check if key is in debounceEvents
86
+ if (debounceEvents.indexOf(key) !== -1) {
87
+ ;(this.events as { [key: string]: any })[key] = debounce((config.events as { [key: string]: any })[key], 100)
88
+ } else {
80
89
  ;(this.events as { [key: string]: any })[key] = (config.events as { [key: string]: any })[key]
81
90
  }
82
91
  }
@@ -97,6 +106,13 @@ export default class SlimSelect {
97
106
  // Run set selected from the values given
98
107
  this.setSelected(values)
99
108
  }
109
+ this.select.onClassChange = (classes: string[]) => {
110
+ // Update settings with new class
111
+ this.settings.class = classes
112
+
113
+ // Run render updateClassStyles
114
+ this.render.updateClassStyles()
115
+ }
100
116
  this.select.onDisabledChange = (disabled: boolean) => {
101
117
  if (disabled) {
102
118
  this.disable()
@@ -222,7 +238,7 @@ export default class SlimSelect {
222
238
  return this.store.getSelected()
223
239
  }
224
240
 
225
- public setSelected(value: string | string[]): void {
241
+ public setSelected(value: string | string[], runAfterChange = true): void {
226
242
  // Get original selected values
227
243
  const selected = this.store.getSelected()
228
244
 
@@ -245,7 +261,7 @@ export default class SlimSelect {
245
261
  }
246
262
 
247
263
  // Trigger afterChange event, if it doesnt equal the original selected values
248
- if (this.events.afterChange && !isEqual(selected, this.store.getSelected())) {
264
+ if (runAfterChange && this.events.afterChange && !isEqual(selected, this.store.getSelected())) {
249
265
  this.events.afterChange(this.store.getSelectedOptions())
250
266
  }
251
267
  }
@@ -327,8 +343,10 @@ export default class SlimSelect {
327
343
  // Tell render to close
328
344
  this.render.close()
329
345
 
330
- // Clear search
331
- this.search('') // Clear search
346
+ // Clear search only if not empty
347
+ if (this.render.content.search.input.value !== '') {
348
+ this.search('') // Clear search
349
+ }
332
350
 
333
351
  // If we arent tabbing focus back on the main element
334
352
  this.render.mainFocus(false)
@@ -6,7 +6,7 @@ export interface Callbacks {
6
6
  open: () => void
7
7
  close: () => void
8
8
  addable?: (value: string) => Promise<OptionOptional | string> | OptionOptional | string
9
- setSelected: (value: string[]) => void
9
+ setSelected: (value: string[], runAfterChange: boolean) => void
10
10
  addOption: (option: Option) => void
11
11
  search: (search: string) => void
12
12
  beforeChange?: (newVal: Option[], oldVal: Option[]) => boolean | void
@@ -125,6 +125,9 @@ export default class Render {
125
125
  this.main = this.mainDiv()
126
126
  this.content = this.contentDiv()
127
127
 
128
+ // Add classes and styles to main/content
129
+ this.updateClassStyles()
130
+
128
131
  // Add content to the content location settings
129
132
  this.settings.contentLocation.appendChild(this.content.main)
130
133
  }
@@ -156,12 +159,6 @@ export default class Render {
156
159
  // move the content in to the right location
157
160
  this.moveContent()
158
161
 
159
- // Render the options
160
- this.renderOptions(this.store.getData())
161
-
162
- // Move the content in to the right location
163
- this.moveContent()
164
-
165
162
  // Move to last selected option
166
163
  const selectedOptions = this.store.getSelectedOptions()
167
164
  if (selectedOptions.length) {
@@ -181,30 +178,49 @@ export default class Render {
181
178
  this.main.arrow.path.setAttribute('d', this.classes.arrowClose)
182
179
  }
183
180
 
184
- public mainDiv(): Main {
185
- // Create main container
186
- const main = document.createElement('div')
187
-
188
- // Set tabable to allow tabbing to the element
189
- main.tabIndex = 0
181
+ public updateClassStyles(): void {
182
+ // Clear all classes and styles
183
+ this.main.main.className = ''
184
+ this.main.main.removeAttribute('style')
185
+ this.content.main.className = ''
186
+ this.content.main.removeAttribute('style')
190
187
 
191
- // Add style and classes
192
- main.style.cssText = this.settings.style !== '' ? this.settings.style : ''
188
+ // Make sure main/content has its base class
189
+ this.main.main.classList.add(this.classes.main)
190
+ this.content.main.classList.add(this.classes.content)
193
191
 
194
- // Clear out classlist
195
- main.className = ''
192
+ // Add styles
193
+ if (this.settings.style !== '') {
194
+ this.content.main.style.cssText = this.settings.style
195
+ }
196
196
 
197
- // Loop through config class and add
198
- main.classList.add(this.settings.id)
199
- main.classList.add(this.classes.main)
200
- if (this.settings.class) {
197
+ // Add classes
198
+ if (this.settings.class.length) {
201
199
  for (const c of this.settings.class) {
202
200
  if (c.trim() !== '') {
203
- main.classList.add(c.trim())
201
+ this.main.main.classList.add(c.trim())
202
+ this.content.main.classList.add(c.trim())
204
203
  }
205
204
  }
206
205
  }
207
206
 
207
+ // Misc classes
208
+ // Add content position class
209
+ if (this.settings.contentPosition === 'relative') {
210
+ this.content.main.classList.add('ss-' + this.settings.contentPosition)
211
+ }
212
+ }
213
+
214
+ public mainDiv(): Main {
215
+ // Create main container
216
+ const main = document.createElement('div')
217
+
218
+ // Add id to data-id
219
+ main.dataset.id = this.settings.id
220
+
221
+ // Set tabable to allow tabbing to the element
222
+ main.tabIndex = 0
223
+
208
224
  // If main gets focus, open the content
209
225
  main.onfocus = () => {
210
226
  if (this.settings.triggerFocus) {
@@ -280,7 +296,7 @@ export default class Render {
280
296
  }
281
297
 
282
298
  if (shouldDelete) {
283
- this.callbacks.setSelected([''])
299
+ this.callbacks.setSelected([''], false)
284
300
 
285
301
  // Check if we need to close the dropdown
286
302
  if (this.settings.closeOnSelect) {
@@ -546,7 +562,7 @@ export default class Render {
546
562
  selectedValues.push(o.value)
547
563
  }
548
564
  }
549
- this.callbacks.setSelected(selectedValues)
565
+ this.callbacks.setSelected(selectedValues, false)
550
566
 
551
567
  // Check if we need to close the dropdown
552
568
  if (this.settings.closeOnSelect) {
@@ -576,28 +592,10 @@ export default class Render {
576
592
 
577
593
  public contentDiv(): Content {
578
594
  const main = document.createElement('div')
579
- main.classList.add(this.classes.content)
580
595
 
581
596
  // Add id to data-id
582
597
  main.dataset.id = this.settings.id
583
598
 
584
- // Add styles
585
- if (this.settings.style !== '') {
586
- main.style.cssText = this.settings.style
587
- }
588
-
589
- // Add classes
590
- if (this.settings.contentPosition === 'relative') {
591
- main.classList.add('ss-' + this.settings.contentPosition)
592
- }
593
- if (this.settings.class.length) {
594
- for (const c of this.settings.class) {
595
- if (c.trim() !== '') {
596
- main.classList.add(c.trim())
597
- }
598
- }
599
- }
600
-
601
599
  // Add search
602
600
  const search = this.searchDiv()
603
601
  main.appendChild(search.main)
@@ -753,9 +751,9 @@ export default class Render {
753
751
  if (this.settings.isMultiple) {
754
752
  let values = this.store.getSelected()
755
753
  values.push(newOption.value)
756
- this.callbacks.setSelected(values)
754
+ this.callbacks.setSelected(values, true)
757
755
  } else {
758
- this.callbacks.setSelected([newOption.value])
756
+ this.callbacks.setSelected([newOption.value], true)
759
757
  }
760
758
 
761
759
  // Clear search
@@ -1024,13 +1022,13 @@ export default class Render {
1024
1022
  return true
1025
1023
  })
1026
1024
 
1027
- this.callbacks.setSelected(newSelected)
1025
+ this.callbacks.setSelected(newSelected, true)
1028
1026
  return
1029
1027
  } else {
1030
1028
  // Put together new list with all options in this optgroup
1031
1029
  const newSelected = currentSelected.concat(d.options.map((o) => o.value))
1032
1030
 
1033
- this.callbacks.setSelected(newSelected)
1031
+ this.callbacks.setSelected(newSelected, true)
1034
1032
  }
1035
1033
  })
1036
1034
 
@@ -1148,6 +1146,11 @@ export default class Render {
1148
1146
  optionEl.setAttribute('title', optionEl.textContent)
1149
1147
  }
1150
1148
 
1149
+ // If option is disabled
1150
+ if (!option.display) {
1151
+ optionEl.classList.add(this.classes.hide)
1152
+ }
1153
+
1151
1154
  // If allowed to deselect, null onclick and add disabled
1152
1155
  if (option.disabled) {
1153
1156
  optionEl.classList.add(this.classes.disabled)
@@ -1238,7 +1241,10 @@ export default class Render {
1238
1241
  }
1239
1242
 
1240
1243
  // Get values from after and set as selected
1241
- this.callbacks.setSelected(after.map((o: Option) => o.value))
1244
+ this.callbacks.setSelected(
1245
+ after.map((o: Option) => o.value),
1246
+ false,
1247
+ )
1242
1248
 
1243
1249
  // If closeOnSelect is true
1244
1250
  if (this.settings.closeOnSelect) {
@@ -6,6 +6,7 @@ export default class Select {
6
6
 
7
7
  // Mutation observer fields
8
8
  public onValueChange?: (value: string[]) => void
9
+ public onClassChange?: (classes: string[]) => void
9
10
  public onDisabledChange?: (disabled: boolean) => void
10
11
  public onOptionsChange?: (data: DataArrayPartial) => void
11
12
 
@@ -88,6 +89,7 @@ export default class Select {
88
89
  return
89
90
  }
90
91
 
92
+ let classChanged = false
91
93
  let disabledChanged = false
92
94
  let optgroupOptionChanged = false
93
95
 
@@ -99,6 +101,11 @@ export default class Select {
99
101
  if (m.attributeName === 'disabled') {
100
102
  disabledChanged = true
101
103
  }
104
+
105
+ // Check if class has changed
106
+ if (m.attributeName === 'class') {
107
+ classChanged = true
108
+ }
102
109
  }
103
110
 
104
111
  // Check if its an optgroup or option
@@ -107,6 +114,11 @@ export default class Select {
107
114
  }
108
115
  }
109
116
 
117
+ // If class has changed then call the class change function
118
+ if (classChanged && this.onClassChange) {
119
+ this.onClassChange(this.select.className.split(' '))
120
+ }
121
+
110
122
  // If disabled has changed then call the disabled change function
111
123
  if (disabledChanged && this.onDisabledChange) {
112
124
  this.changeListen(false)
@@ -241,9 +253,9 @@ export default class Select {
241
253
  // Stop listening to changes
242
254
  this.changeListen(false)
243
255
 
244
- // Update id
256
+ // Update id, only if the id isnt already set
245
257
  if (id) {
246
- this.select.id = id
258
+ this.select.dataset.id = id
247
259
  }
248
260
 
249
261
  // Update style
@@ -310,7 +322,7 @@ export default class Select {
310
322
  public createOption(info: Option): HTMLOptionElement {
311
323
  const optionEl = document.createElement('option')
312
324
  optionEl.id = info.id
313
- optionEl.value = info.value // !== '' ? info.value : info.text
325
+ optionEl.value = info.value
314
326
  optionEl.innerHTML = info.text
315
327
  if (info.html !== '') {
316
328
  optionEl.setAttribute('data-html', info.html)
@@ -356,7 +368,10 @@ export default class Select {
356
368
  this.observer = null
357
369
  }
358
370
 
359
- // show the original select
371
+ // Remove dataset id from original select
372
+ delete this.select.dataset.id
373
+
374
+ // Show the original select
360
375
  this.showUI()
361
376
  }
362
377
  }
@@ -55,7 +55,7 @@ export default class Settings {
55
55
  this.contentLocation = settings.contentLocation || document.body
56
56
  this.contentPosition = settings.contentPosition || 'absolute'
57
57
  this.openPosition = settings.openPosition || 'auto' // options: auto, up, down
58
- this.placeholderText = settings.placeholderText || 'Select Value'
58
+ this.placeholderText = settings.placeholderText !== undefined ? settings.placeholderText : 'Select Value'
59
59
  this.allowDeselect = settings.allowDeselect !== undefined ? settings.allowDeselect : false
60
60
  this.hideSelected = settings.hideSelected !== undefined ? settings.hideSelected : false
61
61
  this.showOptionTooltips = settings.showOptionTooltips !== undefined ? settings.showOptionTooltips : false
@@ -33,7 +33,7 @@ export default class SlimSelect {
33
33
  getData(): DataArray;
34
34
  setData(data: DataArrayPartial): void;
35
35
  getSelected(): string[];
36
- setSelected(value: string | string[]): void;
36
+ setSelected(value: string | string[], runAfterChange?: boolean): void;
37
37
  addOption(option: OptionOptional): void;
38
38
  open(): void;
39
39
  close(): void;
@@ -4,7 +4,7 @@ export interface Callbacks {
4
4
  open: () => void;
5
5
  close: () => void;
6
6
  addable?: (value: string) => Promise<OptionOptional | string> | OptionOptional | string;
7
- setSelected: (value: string[]) => void;
7
+ setSelected: (value: string[], runAfterChange: boolean) => void;
8
8
  addOption: (option: Option) => void;
9
9
  search: (search: string) => void;
10
10
  beforeChange?: (newVal: Option[], oldVal: Option[]) => boolean | void;
@@ -90,6 +90,7 @@ export default class Render {
90
90
  disable(): void;
91
91
  open(): void;
92
92
  close(): void;
93
+ updateClassStyles(): void;
93
94
  mainDiv(): Main;
94
95
  mainFocus(trigger: boolean): void;
95
96
  placeholder(): HTMLDivElement;
@@ -2,6 +2,7 @@ import { DataArray, DataArrayPartial, Optgroup, OptgroupOptional, Option } from
2
2
  export default class Select {
3
3
  select: HTMLSelectElement;
4
4
  onValueChange?: (value: string[]) => void;
5
+ onClassChange?: (classes: string[]) => void;
5
6
  onDisabledChange?: (disabled: boolean) => void;
6
7
  onOptionsChange?: (data: DataArrayPartial) => void;
7
8
  listen: boolean;
@@ -78,7 +78,7 @@ class Settings {
78
78
  this.contentLocation = settings.contentLocation || document.body;
79
79
  this.contentPosition = settings.contentPosition || 'absolute';
80
80
  this.openPosition = settings.openPosition || 'auto';
81
- this.placeholderText = settings.placeholderText || 'Select Value';
81
+ this.placeholderText = settings.placeholderText !== undefined ? settings.placeholderText : 'Select Value';
82
82
  this.allowDeselect = settings.allowDeselect !== undefined ? settings.allowDeselect : false;
83
83
  this.hideSelected = settings.hideSelected !== undefined ? settings.hideSelected : false;
84
84
  this.showOptionTooltips = settings.showOptionTooltips !== undefined ? settings.showOptionTooltips : false;
@@ -345,6 +345,7 @@ class Render {
345
345
  this.callbacks = callbacks;
346
346
  this.main = this.mainDiv();
347
347
  this.content = this.contentDiv();
348
+ this.updateClassStyles();
348
349
  this.settings.contentLocation.appendChild(this.content.main);
349
350
  }
350
351
  enable() {
@@ -359,8 +360,6 @@ class Render {
359
360
  this.main.arrow.path.setAttribute('d', this.classes.arrowOpen);
360
361
  this.main.main.classList.add(this.settings.openPosition === 'up' ? this.classes.openAbove : this.classes.openBelow);
361
362
  this.moveContent();
362
- this.renderOptions(this.store.getData());
363
- this.moveContent();
364
363
  const selectedOptions = this.store.getSelectedOptions();
365
364
  if (selectedOptions.length) {
366
365
  const selectedId = selectedOptions[selectedOptions.length - 1].id;
@@ -377,20 +376,32 @@ class Render {
377
376
  this.content.main.classList.remove(this.classes.openBelow);
378
377
  this.main.arrow.path.setAttribute('d', this.classes.arrowClose);
379
378
  }
380
- mainDiv() {
381
- const main = document.createElement('div');
382
- main.tabIndex = 0;
383
- main.style.cssText = this.settings.style !== '' ? this.settings.style : '';
384
- main.className = '';
385
- main.classList.add(this.settings.id);
386
- main.classList.add(this.classes.main);
387
- if (this.settings.class) {
379
+ updateClassStyles() {
380
+ this.main.main.className = '';
381
+ this.main.main.removeAttribute('style');
382
+ this.content.main.className = '';
383
+ this.content.main.removeAttribute('style');
384
+ this.main.main.classList.add(this.classes.main);
385
+ this.content.main.classList.add(this.classes.content);
386
+ if (this.settings.style !== '') {
387
+ this.content.main.style.cssText = this.settings.style;
388
+ }
389
+ if (this.settings.class.length) {
388
390
  for (const c of this.settings.class) {
389
391
  if (c.trim() !== '') {
390
- main.classList.add(c.trim());
392
+ this.main.main.classList.add(c.trim());
393
+ this.content.main.classList.add(c.trim());
391
394
  }
392
395
  }
393
396
  }
397
+ if (this.settings.contentPosition === 'relative') {
398
+ this.content.main.classList.add('ss-' + this.settings.contentPosition);
399
+ }
400
+ }
401
+ mainDiv() {
402
+ const main = document.createElement('div');
403
+ main.dataset.id = this.settings.id;
404
+ main.tabIndex = 0;
394
405
  main.onfocus = () => {
395
406
  if (this.settings.triggerFocus) {
396
407
  this.callbacks.open();
@@ -443,7 +454,7 @@ class Render {
443
454
  shouldDelete = this.callbacks.beforeChange(after, before) === true;
444
455
  }
445
456
  if (shouldDelete) {
446
- this.callbacks.setSelected(['']);
457
+ this.callbacks.setSelected([''], false);
447
458
  if (this.settings.closeOnSelect) {
448
459
  this.callbacks.close();
449
460
  }
@@ -642,7 +653,7 @@ class Render {
642
653
  selectedValues.push(o.value);
643
654
  }
644
655
  }
645
- this.callbacks.setSelected(selectedValues);
656
+ this.callbacks.setSelected(selectedValues, false);
646
657
  if (this.settings.closeOnSelect) {
647
658
  this.callbacks.close();
648
659
  }
@@ -663,21 +674,7 @@ class Render {
663
674
  }
664
675
  contentDiv() {
665
676
  const main = document.createElement('div');
666
- main.classList.add(this.classes.content);
667
677
  main.dataset.id = this.settings.id;
668
- if (this.settings.style !== '') {
669
- main.style.cssText = this.settings.style;
670
- }
671
- if (this.settings.contentPosition === 'relative') {
672
- main.classList.add('ss-' + this.settings.contentPosition);
673
- }
674
- if (this.settings.class.length) {
675
- for (const c of this.settings.class) {
676
- if (c.trim() !== '') {
677
- main.classList.add(c.trim());
678
- }
679
- }
680
- }
681
678
  const search = this.searchDiv();
682
679
  main.appendChild(search.main);
683
680
  const list = this.listDiv();
@@ -789,10 +786,10 @@ class Render {
789
786
  if (this.settings.isMultiple) {
790
787
  let values = this.store.getSelected();
791
788
  values.push(newOption.value);
792
- this.callbacks.setSelected(values);
789
+ this.callbacks.setSelected(values, true);
793
790
  }
794
791
  else {
795
- this.callbacks.setSelected([newOption.value]);
792
+ this.callbacks.setSelected([newOption.value], true);
796
793
  }
797
794
  this.callbacks.search('');
798
795
  if (this.settings.closeOnSelect) {
@@ -974,12 +971,12 @@ class Render {
974
971
  }
975
972
  return true;
976
973
  });
977
- this.callbacks.setSelected(newSelected);
974
+ this.callbacks.setSelected(newSelected, true);
978
975
  return;
979
976
  }
980
977
  else {
981
978
  const newSelected = currentSelected.concat(d.options.map((o) => o.value));
982
- this.callbacks.setSelected(newSelected);
979
+ this.callbacks.setSelected(newSelected, true);
983
980
  }
984
981
  });
985
982
  optgroupActions.appendChild(selectAll);
@@ -1063,6 +1060,9 @@ class Render {
1063
1060
  if (this.settings.showOptionTooltips && optionEl.textContent) {
1064
1061
  optionEl.setAttribute('title', optionEl.textContent);
1065
1062
  }
1063
+ if (!option.display) {
1064
+ optionEl.classList.add(this.classes.hide);
1065
+ }
1066
1066
  if (option.disabled) {
1067
1067
  optionEl.classList.add(this.classes.disabled);
1068
1068
  }
@@ -1122,7 +1122,7 @@ class Render {
1122
1122
  if (!this.store.getOptionByID(elementID)) {
1123
1123
  this.callbacks.addOption(option);
1124
1124
  }
1125
- this.callbacks.setSelected(after.map((o) => o.value));
1125
+ this.callbacks.setSelected(after.map((o) => o.value), false);
1126
1126
  if (this.settings.closeOnSelect) {
1127
1127
  this.callbacks.close();
1128
1128
  }
@@ -1258,6 +1258,7 @@ class Select {
1258
1258
  if (!this.listen) {
1259
1259
  return;
1260
1260
  }
1261
+ let classChanged = false;
1261
1262
  let disabledChanged = false;
1262
1263
  let optgroupOptionChanged = false;
1263
1264
  for (const m of mutations) {
@@ -1265,11 +1266,17 @@ class Select {
1265
1266
  if (m.attributeName === 'disabled') {
1266
1267
  disabledChanged = true;
1267
1268
  }
1269
+ if (m.attributeName === 'class') {
1270
+ classChanged = true;
1271
+ }
1268
1272
  }
1269
1273
  if (m.target.nodeName === 'OPTGROUP' || m.target.nodeName === 'OPTION') {
1270
1274
  optgroupOptionChanged = true;
1271
1275
  }
1272
1276
  }
1277
+ if (classChanged && this.onClassChange) {
1278
+ this.onClassChange(this.select.className.split(' '));
1279
+ }
1273
1280
  if (disabledChanged && this.onDisabledChange) {
1274
1281
  this.changeListen(false);
1275
1282
  this.onDisabledChange(this.select.disabled);
@@ -1374,7 +1381,7 @@ class Select {
1374
1381
  updateSelect(id, style, classes) {
1375
1382
  this.changeListen(false);
1376
1383
  if (id) {
1377
- this.select.id = id;
1384
+ this.select.dataset.id = id;
1378
1385
  }
1379
1386
  if (style) {
1380
1387
  this.select.style.cssText = style;
@@ -1462,6 +1469,7 @@ class Select {
1462
1469
  this.observer.disconnect();
1463
1470
  this.observer = null;
1464
1471
  }
1472
+ delete this.select.dataset.id;
1465
1473
  this.showUI();
1466
1474
  }
1467
1475
  }
@@ -1519,8 +1527,15 @@ class SlimSelect {
1519
1527
  this.destroy();
1520
1528
  }
1521
1529
  this.settings = new Settings(config.settings);
1530
+ const debounceEvents = ['afterChange', 'beforeOpen', 'afterOpen', 'beforeClose', 'afterClose'];
1522
1531
  for (const key in config.events) {
1523
- if (config.events.hasOwnProperty(key)) {
1532
+ if (!config.events.hasOwnProperty(key)) {
1533
+ continue;
1534
+ }
1535
+ if (debounceEvents.indexOf(key) !== -1) {
1536
+ this.events[key] = debounce(config.events[key], 100);
1537
+ }
1538
+ else {
1524
1539
  this.events[key] = config.events[key];
1525
1540
  }
1526
1541
  }
@@ -1534,6 +1549,10 @@ class SlimSelect {
1534
1549
  this.select.onValueChange = (values) => {
1535
1550
  this.setSelected(values);
1536
1551
  };
1552
+ this.select.onClassChange = (classes) => {
1553
+ this.settings.class = classes;
1554
+ this.render.updateClassStyles();
1555
+ };
1537
1556
  this.select.onDisabledChange = (disabled) => {
1538
1557
  if (disabled) {
1539
1558
  this.disable();
@@ -1612,7 +1631,7 @@ class SlimSelect {
1612
1631
  getSelected() {
1613
1632
  return this.store.getSelected();
1614
1633
  }
1615
- setSelected(value) {
1634
+ setSelected(value, runAfterChange = true) {
1616
1635
  const selected = this.store.getSelected();
1617
1636
  this.store.setSelectedBy('value', Array.isArray(value) ? value : [value]);
1618
1637
  const data = this.store.getData();
@@ -1624,7 +1643,7 @@ class SlimSelect {
1624
1643
  else {
1625
1644
  this.render.renderOptions(data);
1626
1645
  }
1627
- if (this.events.afterChange && !isEqual(selected, this.store.getSelected())) {
1646
+ if (runAfterChange && this.events.afterChange && !isEqual(selected, this.store.getSelected())) {
1628
1647
  this.events.afterChange(this.store.getSelectedOptions());
1629
1648
  }
1630
1649
  }
@@ -1671,7 +1690,9 @@ class SlimSelect {
1671
1690
  this.events.beforeClose();
1672
1691
  }
1673
1692
  this.render.close();
1674
- this.search('');
1693
+ if (this.render.content.search.input.value !== '') {
1694
+ this.search('');
1695
+ }
1675
1696
  this.render.mainFocus(false);
1676
1697
  setTimeout(() => {
1677
1698
  if (this.events.afterClose) {