slim-select 2.8.2 → 2.9.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.
Files changed (69) hide show
  1. package/.prettierignore +1 -0
  2. package/.prettierrc +4 -3
  3. package/README.md +5 -2
  4. package/dist/classes.d.ts +43 -0
  5. package/dist/helpers.d.ts +1 -1
  6. package/dist/index.d.ts +5 -2
  7. package/dist/render.d.ts +4 -44
  8. package/dist/select.d.ts +4 -2
  9. package/dist/settings.d.ts +2 -1
  10. package/dist/slimselect.cjs.js +248 -120
  11. package/dist/slimselect.css +1 -1
  12. package/dist/slimselect.css.map +1 -1
  13. package/dist/slimselect.es.js +248 -120
  14. package/dist/slimselect.global.js +248 -120
  15. package/dist/slimselect.js +248 -120
  16. package/dist/slimselect.min.js +1 -1
  17. package/dist/slimselect.umd.js +248 -120
  18. package/dist/slimselect.umd.min.js +1 -1
  19. package/dist/store.d.ts +4 -2
  20. package/index.html +1 -4
  21. package/jest.config.js +6 -0
  22. package/package.json +31 -40
  23. package/src/slim-select/classes.test.ts +72 -0
  24. package/src/slim-select/classes.ts +109 -0
  25. package/src/slim-select/helpers.test.ts +160 -0
  26. package/src/slim-select/helpers.ts +3 -12
  27. package/src/slim-select/index.test.ts +109 -16
  28. package/src/slim-select/index.ts +41 -12
  29. package/src/slim-select/render.test.ts +1169 -18
  30. package/src/slim-select/render.ts +78 -97
  31. package/src/slim-select/rollup.config.mjs +28 -28
  32. package/src/slim-select/select.test.ts +306 -156
  33. package/src/slim-select/select.ts +70 -21
  34. package/src/slim-select/settings.test.ts +272 -0
  35. package/src/slim-select/settings.ts +5 -1
  36. package/src/slim-select/slimselect.scss +7 -3
  37. package/src/slim-select/store.test.ts +986 -235
  38. package/src/slim-select/store.ts +70 -28
  39. package/src/{vue/slimselect.vue → slim-select/vue.vue} +19 -17
  40. package/tsconfig.json +2 -3
  41. package/{vite.config.ts → vite.config.mts} +11 -4
  42. package/src/react/.eslintignore +0 -2
  43. package/src/react/.eslintrc.cjs +0 -24
  44. package/src/react/index.html +0 -14
  45. package/src/react/jestconfig.json +0 -11
  46. package/src/react/package.json +0 -32
  47. package/src/react/src/frameworkpage.tsx +0 -133
  48. package/src/react/src/index.ts +0 -3
  49. package/src/react/src/slimselect.tsx +0 -148
  50. package/src/react/tests/slimselect.test.tsx +0 -52
  51. package/src/react/tsconfig.json +0 -37
  52. package/src/react/tsconfig.node.json +0 -10
  53. package/src/react/vite.config.ts +0 -55
  54. package/src/vue/README.md +0 -48
  55. package/src/vue/dist/slim-select/helpers.d.ts +0 -5
  56. package/src/vue/dist/slim-select/index.d.ts +0 -46
  57. package/src/vue/dist/slim-select/render.d.ts +0 -120
  58. package/src/vue/dist/slim-select/select.d.ts +0 -28
  59. package/src/vue/dist/slim-select/settings.d.ts +0 -34
  60. package/src/vue/dist/slim-select/store.d.ts +0 -80
  61. package/src/vue/dist/slimselectvue.es.js +0 -1978
  62. package/src/vue/dist/slimselectvue.global.js +0 -1981
  63. package/src/vue/dist/slimselectvue.ssr.js +0 -1980
  64. package/src/vue/dist/vue/hello.d.ts +0 -2
  65. package/src/vue/dist/vue/slimselect.vue.d.ts +0 -326
  66. package/src/vue/hello.ts +0 -5
  67. package/src/vue/package.json +0 -28
  68. package/src/vue/rollup.config.mjs +0 -44
  69. package/src/vue/tsconfig.json +0 -14
@@ -1,5 +1,53 @@
1
1
  'use strict';
2
2
 
3
+ class CssClasses {
4
+ constructor(classes) {
5
+ if (!classes) {
6
+ classes = {};
7
+ }
8
+ this.main = classes.main || 'ss-main';
9
+ this.placeholder = classes.placeholder || 'ss-placeholder';
10
+ this.values = classes.values || 'ss-values';
11
+ this.single = classes.single || 'ss-single';
12
+ this.max = classes.max || 'ss-max';
13
+ this.value = classes.value || 'ss-value';
14
+ this.valueText = classes.valueText || 'ss-value-text';
15
+ this.valueDelete = classes.valueDelete || 'ss-value-delete';
16
+ this.valueOut = classes.valueOut || 'ss-value-out';
17
+ this.deselect = classes.deselect || 'ss-deselect';
18
+ this.deselectPath = classes.deselectPath || 'M10,10 L90,90 M10,90 L90,10';
19
+ this.arrow = classes.arrow || 'ss-arrow';
20
+ this.arrowClose = classes.arrowClose || 'M10,30 L50,70 L90,30';
21
+ this.arrowOpen = classes.arrowOpen || 'M10,70 L50,30 L90,70';
22
+ this.content = classes.content || 'ss-content';
23
+ this.openAbove = classes.openAbove || 'ss-open-above';
24
+ this.openBelow = classes.openBelow || 'ss-open-below';
25
+ this.search = classes.search || 'ss-search';
26
+ this.searchHighlighter = classes.searchHighlighter || 'ss-search-highlight';
27
+ this.searching = classes.searching || 'ss-searching';
28
+ this.addable = classes.addable || 'ss-addable';
29
+ this.addablePath = classes.addablePath || 'M50,10 L50,90 M10,50 L90,50';
30
+ this.list = classes.list || 'ss-list';
31
+ this.optgroup = classes.optgroup || 'ss-optgroup';
32
+ this.optgroupLabel = classes.optgroupLabel || 'ss-optgroup-label';
33
+ this.optgroupLabelText = classes.optgroupLabelText || 'ss-optgroup-label-text';
34
+ this.optgroupActions = classes.optgroupActions || 'ss-optgroup-actions';
35
+ this.optgroupSelectAll = classes.optgroupSelectAll || 'ss-selectall';
36
+ this.optgroupSelectAllBox = classes.optgroupSelectAllBox || 'M60,10 L10,10 L10,90 L90,90 L90,50';
37
+ this.optgroupSelectAllCheck = classes.optgroupSelectAllCheck || 'M30,45 L50,70 L90,10';
38
+ this.optgroupClosable = classes.optgroupClosable || 'ss-closable';
39
+ this.option = classes.option || 'ss-option';
40
+ this.optionDelete = classes.optionDelete || 'M10,10 L90,90 M10,90 L90,10';
41
+ this.highlighted = classes.highlighted || 'ss-highlighted';
42
+ this.open = classes.open || 'ss-open';
43
+ this.close = classes.close || 'ss-close';
44
+ this.selected = classes.selected || 'ss-selected';
45
+ this.error = classes.error || 'ss-error';
46
+ this.disabled = classes.disabled || 'ss-disabled';
47
+ this.hide = classes.hide || 'ss-hide';
48
+ }
49
+ }
50
+
3
51
  function generateID() {
4
52
  return Math.random().toString(36).substring(2, 10);
5
53
  }
@@ -87,6 +135,7 @@ class Store {
87
135
  constructor(type, data) {
88
136
  this.selectType = 'single';
89
137
  this.data = [];
138
+ this.selectedOrder = [];
90
139
  this.selectType = type;
91
140
  this.setData(data);
92
141
  }
@@ -101,12 +150,18 @@ class Store {
101
150
  }
102
151
  if ('options' in dataObj && dataObj.options) {
103
152
  for (let option of dataObj.options) {
104
- return this.validateOption(option);
153
+ const validationError = this.validateOption(option);
154
+ if (validationError) {
155
+ return validationError;
156
+ }
105
157
  }
106
158
  }
107
159
  }
108
160
  else if (dataObj instanceof Option || 'text' in dataObj) {
109
- return this.validateOption(dataObj);
161
+ const validationError = this.validateOption(dataObj);
162
+ if (validationError) {
163
+ return validationError;
164
+ }
110
165
  }
111
166
  else {
112
167
  return new Error('Data object must be a valid optgroup or option');
@@ -143,7 +198,7 @@ class Store {
143
198
  setData(data) {
144
199
  this.data = this.partialToFullData(data);
145
200
  if (this.selectType === 'single') {
146
- this.setSelectedBy('value', this.getSelected());
201
+ this.setSelectedBy('id', this.getSelected());
147
202
  }
148
203
  }
149
204
  getData() {
@@ -152,12 +207,19 @@ class Store {
152
207
  getDataOptions() {
153
208
  return this.filter(null, false);
154
209
  }
155
- addOption(option) {
156
- this.setData(this.getData().concat(new Option(option)));
210
+ addOption(option, addToStart = false) {
211
+ if (addToStart) {
212
+ let data = [new Option(option)];
213
+ this.setData(data.concat(this.getData()));
214
+ }
215
+ else {
216
+ this.setData(this.getData().concat(new Option(option)));
217
+ }
157
218
  }
158
219
  setSelectedBy(selectedType, selectedValues) {
159
220
  let firstOption = null;
160
221
  let hasSelected = false;
222
+ const selectedObjects = [];
161
223
  for (let dataObj of this.data) {
162
224
  if (dataObj instanceof Optgroup) {
163
225
  for (let option of dataObj.options) {
@@ -165,8 +227,11 @@ class Store {
165
227
  firstOption = option;
166
228
  }
167
229
  option.selected = hasSelected ? false : selectedValues.includes(option[selectedType]);
168
- if (option.selected && this.selectType === 'single') {
169
- hasSelected = true;
230
+ if (option.selected) {
231
+ selectedObjects.push(option);
232
+ if (this.selectType === 'single') {
233
+ hasSelected = true;
234
+ }
170
235
  }
171
236
  }
172
237
  }
@@ -175,36 +240,35 @@ class Store {
175
240
  firstOption = dataObj;
176
241
  }
177
242
  dataObj.selected = hasSelected ? false : selectedValues.includes(dataObj[selectedType]);
178
- if (dataObj.selected && this.selectType === 'single') {
179
- hasSelected = true;
243
+ if (dataObj.selected) {
244
+ selectedObjects.push(dataObj);
245
+ if (this.selectType === 'single') {
246
+ hasSelected = true;
247
+ }
180
248
  }
181
249
  }
182
250
  }
183
251
  if (this.selectType === 'single' && firstOption && !hasSelected) {
184
252
  firstOption.selected = true;
253
+ selectedObjects.push(firstOption);
185
254
  }
255
+ const selectedIds = selectedValues.map((value) => {
256
+ var _a;
257
+ return ((_a = selectedObjects.find((option) => option[selectedType] === value)) === null || _a === void 0 ? void 0 : _a.id) || '';
258
+ });
259
+ this.selectedOrder = selectedIds;
186
260
  }
187
261
  getSelected() {
188
- let selectedOptions = this.getSelectedOptions();
189
- let selectedValues = [];
190
- selectedOptions.forEach((option) => {
191
- selectedValues.push(option.value);
192
- });
193
- return selectedValues;
262
+ return this.getSelectedOptions().map((option) => option.id);
263
+ }
264
+ getSelectedValues() {
265
+ return this.getSelectedOptions().map((option) => option.value);
194
266
  }
195
267
  getSelectedOptions() {
196
268
  return this.filter((opt) => {
197
269
  return opt.selected;
198
270
  }, false);
199
271
  }
200
- getSelectedIDs() {
201
- let selectedOptions = this.getSelectedOptions();
202
- let selectedIDs = [];
203
- selectedOptions.forEach((op) => {
204
- selectedIDs.push(op.id);
205
- });
206
- return selectedIDs;
207
- }
208
272
  getOptgroupByID(id) {
209
273
  for (let dataObj of this.data) {
210
274
  if (dataObj instanceof Optgroup && dataObj.id === id) {
@@ -275,54 +339,35 @@ class Store {
275
339
  });
276
340
  return dataSearch;
277
341
  }
342
+ selectedOrderOptions(options) {
343
+ const newOrder = [];
344
+ this.selectedOrder.forEach((id) => {
345
+ const option = options.find((opt) => opt.id === id);
346
+ if (option) {
347
+ newOrder.push(option);
348
+ }
349
+ });
350
+ options.forEach((option) => {
351
+ let isIn = false;
352
+ newOrder.forEach((selectedOption) => {
353
+ if (option.id === selectedOption.id) {
354
+ isIn = true;
355
+ return;
356
+ }
357
+ });
358
+ if (!isIn) {
359
+ newOrder.push(option);
360
+ }
361
+ });
362
+ return newOrder;
363
+ }
278
364
  }
279
365
 
280
366
  class Render {
281
- constructor(settings, store, callbacks) {
282
- this.classes = {
283
- main: 'ss-main',
284
- placeholder: 'ss-placeholder',
285
- values: 'ss-values',
286
- single: 'ss-single',
287
- max: 'ss-max',
288
- value: 'ss-value',
289
- valueText: 'ss-value-text',
290
- valueDelete: 'ss-value-delete',
291
- valueOut: 'ss-value-out',
292
- deselect: 'ss-deselect',
293
- deselectPath: 'M10,10 L90,90 M10,90 L90,10',
294
- arrow: 'ss-arrow',
295
- arrowClose: 'M10,30 L50,70 L90,30',
296
- arrowOpen: 'M10,70 L50,30 L90,70',
297
- content: 'ss-content',
298
- openAbove: 'ss-open-above',
299
- openBelow: 'ss-open-below',
300
- search: 'ss-search',
301
- searchHighlighter: 'ss-search-highlight',
302
- searching: 'ss-searching',
303
- addable: 'ss-addable',
304
- addablePath: 'M50,10 L50,90 M10,50 L90,50',
305
- list: 'ss-list',
306
- optgroup: 'ss-optgroup',
307
- optgroupLabel: 'ss-optgroup-label',
308
- optgroupLabelText: 'ss-optgroup-label-text',
309
- optgroupActions: 'ss-optgroup-actions',
310
- optgroupSelectAll: 'ss-selectall',
311
- optgroupSelectAllBox: 'M60,10 L10,10 L10,90 L90,90 L90,50',
312
- optgroupSelectAllCheck: 'M30,45 L50,70 L90,10',
313
- optgroupClosable: 'ss-closable',
314
- option: 'ss-option',
315
- optionDelete: 'M10,10 L90,90 M10,90 L90,10',
316
- highlighted: 'ss-highlighted',
317
- open: 'ss-open',
318
- close: 'ss-close',
319
- selected: 'ss-selected',
320
- error: 'ss-error',
321
- disabled: 'ss-disabled',
322
- hide: 'ss-hide',
323
- };
367
+ constructor(settings, classes, store, callbacks) {
324
368
  this.store = store;
325
369
  this.settings = settings;
370
+ this.classes = classes;
326
371
  this.callbacks = callbacks;
327
372
  this.main = this.mainDiv();
328
373
  this.content = this.contentDiv();
@@ -418,7 +463,7 @@ class Render {
418
463
  this.callbacks.close();
419
464
  return false;
420
465
  }
421
- return false;
466
+ return true;
422
467
  };
423
468
  main.onclick = (e) => {
424
469
  if (this.settings.disabled) {
@@ -456,8 +501,8 @@ class Render {
456
501
  }
457
502
  else {
458
503
  const firstOption = this.store.getFirstOption();
459
- const value = firstOption ? firstOption.value : '';
460
- this.callbacks.setSelected(value, false);
504
+ const id = firstOption ? firstOption.id : '';
505
+ this.callbacks.setSelected(id, false);
461
506
  }
462
507
  if (this.settings.closeOnSelect) {
463
508
  this.callbacks.close();
@@ -490,12 +535,12 @@ class Render {
490
535
  deselect: {
491
536
  main: deselect,
492
537
  svg: deselectSvg,
493
- path: deselectPath,
538
+ path: deselectPath
494
539
  },
495
540
  arrow: {
496
541
  main: arrow,
497
- path: arrowPath,
498
- },
542
+ path: arrowPath
543
+ }
499
544
  };
500
545
  }
501
546
  mainFocus(eventType) {
@@ -581,6 +626,9 @@ class Render {
581
626
  maxValuesMessage.remove();
582
627
  }
583
628
  }
629
+ if (this.settings.keepOrder) {
630
+ selectedOptions = this.store.selectedOrderOptions(selectedOptions);
631
+ }
584
632
  let removeNodes = [];
585
633
  for (let i = 0; i < currentNodes.length; i++) {
586
634
  const node = currentNodes[i];
@@ -634,7 +682,7 @@ class Render {
634
682
  value.dataset.id = option.id;
635
683
  const text = document.createElement('div');
636
684
  text.classList.add(this.classes.valueText);
637
- text.innerText = option.text;
685
+ text.textContent = option.text;
638
686
  value.appendChild(text);
639
687
  if (!option.mandatory) {
640
688
  const deleteDiv = document.createElement('div');
@@ -657,18 +705,18 @@ class Render {
657
705
  shouldDelete = this.callbacks.beforeChange(after, before) === true;
658
706
  }
659
707
  if (shouldDelete) {
660
- let selectedValues = [];
708
+ let selectedIds = [];
661
709
  for (const o of after) {
662
710
  if (o instanceof Optgroup) {
663
711
  for (const c of o.options) {
664
- selectedValues.push(c.value);
712
+ selectedIds.push(c.id);
665
713
  }
666
714
  }
667
715
  if (o instanceof Option) {
668
- selectedValues.push(o.value);
716
+ selectedIds.push(o.id);
669
717
  }
670
718
  }
671
- this.callbacks.setSelected(selectedValues, false);
719
+ this.callbacks.setSelected(selectedIds, false);
672
720
  if (this.settings.closeOnSelect) {
673
721
  this.callbacks.close();
674
722
  }
@@ -698,7 +746,7 @@ class Render {
698
746
  return {
699
747
  main: main,
700
748
  search: search,
701
- list: list,
749
+ list: list
702
750
  };
703
751
  }
704
752
  moveContent() {
@@ -728,7 +776,7 @@ class Render {
728
776
  main.classList.add(this.classes.search);
729
777
  const searchReturn = {
730
778
  main,
731
- input,
779
+ input
732
780
  };
733
781
  if (!this.settings.showSearch) {
734
782
  main.classList.add(this.classes.hide);
@@ -756,9 +804,15 @@ class Render {
756
804
  case 'Escape':
757
805
  this.callbacks.close();
758
806
  return false;
759
- case 'Enter':
760
807
  case ' ':
761
- if (this.callbacks.addable && e.ctrlKey) {
808
+ const highlighted = this.content.list.querySelector('.' + this.classes.highlighted);
809
+ if (highlighted) {
810
+ highlighted.click();
811
+ return false;
812
+ }
813
+ return true;
814
+ case 'Enter':
815
+ if (this.callbacks.addable) {
762
816
  addable.click();
763
817
  return false;
764
818
  }
@@ -797,12 +851,12 @@ class Render {
797
851
  let newOption = new Option(oo);
798
852
  this.callbacks.addOption(newOption);
799
853
  if (this.settings.isMultiple) {
800
- let values = this.store.getSelected();
801
- values.push(newOption.value);
802
- this.callbacks.setSelected(values, true);
854
+ let ids = this.store.getSelected();
855
+ ids.push(newOption.id);
856
+ this.callbacks.setSelected(ids, true);
803
857
  }
804
858
  else {
805
- this.callbacks.setSelected([newOption.value], true);
859
+ this.callbacks.setSelected([newOption.id], true);
806
860
  }
807
861
  this.callbacks.search('');
808
862
  if (this.settings.closeOnSelect) {
@@ -820,9 +874,12 @@ class Render {
820
874
  if (typeof value === 'string') {
821
875
  runFinish({
822
876
  text: value,
823
- value: value,
877
+ value: value
824
878
  });
825
879
  }
880
+ else if (addableValue instanceof Error) {
881
+ this.renderError(addableValue.message);
882
+ }
826
883
  else {
827
884
  runFinish(value);
828
885
  }
@@ -831,9 +888,12 @@ class Render {
831
888
  else if (typeof addableValue === 'string') {
832
889
  runFinish({
833
890
  text: addableValue,
834
- value: addableValue,
891
+ value: addableValue
835
892
  });
836
893
  }
894
+ else if (addableValue instanceof Error) {
895
+ this.renderError(addableValue.message);
896
+ }
837
897
  else {
838
898
  runFinish(addableValue);
839
899
  }
@@ -843,7 +903,7 @@ class Render {
843
903
  searchReturn.addable = {
844
904
  main: addable,
845
905
  svg: plus,
846
- path: plusPath,
906
+ path: plusPath
847
907
  };
848
908
  }
849
909
  return searchReturn;
@@ -940,10 +1000,26 @@ class Render {
940
1000
  if (data.length === 0) {
941
1001
  const noResults = document.createElement('div');
942
1002
  noResults.classList.add(this.classes.search);
943
- noResults.innerHTML = this.settings.searchText;
1003
+ if (this.callbacks.addable) {
1004
+ noResults.innerHTML = this.settings.addableText.replace('{value}', this.content.search.input.value);
1005
+ }
1006
+ else {
1007
+ noResults.innerHTML = this.settings.searchText;
1008
+ }
944
1009
  this.content.list.appendChild(noResults);
945
1010
  return;
946
1011
  }
1012
+ if (this.settings.allowDeselect && !this.settings.isMultiple) {
1013
+ const placeholderOption = this.store.filter((o) => o.placeholder, false);
1014
+ if (!placeholderOption.length) {
1015
+ this.store.addOption(new Option({
1016
+ text: '',
1017
+ value: '',
1018
+ selected: false,
1019
+ placeholder: true
1020
+ }), true);
1021
+ }
1022
+ }
947
1023
  for (const d of data) {
948
1024
  if (d instanceof Optgroup) {
949
1025
  const optgroupEl = document.createElement('div');
@@ -990,7 +1066,7 @@ class Render {
990
1066
  if (allSelected) {
991
1067
  const newSelected = currentSelected.filter((s) => {
992
1068
  for (const o of d.options) {
993
- if (s === o.value) {
1069
+ if (s === o.id) {
994
1070
  return false;
995
1071
  }
996
1072
  }
@@ -1000,7 +1076,7 @@ class Render {
1000
1076
  return;
1001
1077
  }
1002
1078
  else {
1003
- const newSelected = currentSelected.concat(d.options.map((o) => o.value));
1079
+ const newSelected = currentSelected.concat(d.options.map((o) => o.id));
1004
1080
  for (const o of d.options) {
1005
1081
  if (!this.store.getOptionByID(o.id)) {
1006
1082
  this.callbacks.addOption(o);
@@ -1157,7 +1233,7 @@ class Render {
1157
1233
  if (!this.store.getOptionByID(elementID)) {
1158
1234
  this.callbacks.addOption(option);
1159
1235
  }
1160
- this.callbacks.setSelected(after.map((o) => o.value), false);
1236
+ this.callbacks.setSelected(after.map((o) => o.id), false);
1161
1237
  if (this.settings.closeOnSelect) {
1162
1238
  this.callbacks.close();
1163
1239
  }
@@ -1174,7 +1250,7 @@ class Render {
1174
1250
  }
1175
1251
  highlightText(str, search, className) {
1176
1252
  let completedString = str;
1177
- const regex = new RegExp('(' + search.trim() + ')(?![^<]*>[^<>]*</)', 'i');
1253
+ const regex = new RegExp('(?![^<]*>)(' + search.trim() + ')(?![^<]*>[^<>]*</)', 'i');
1178
1254
  if (!str.match(regex)) {
1179
1255
  return str;
1180
1256
  }
@@ -1263,7 +1339,7 @@ class Select {
1263
1339
  this.select = select;
1264
1340
  this.valueChange = this.valueChange.bind(this);
1265
1341
  this.select.addEventListener('change', this.valueChange, {
1266
- passive: true,
1342
+ passive: true
1267
1343
  });
1268
1344
  this.observer = new MutationObserver(this.observeCall.bind(this));
1269
1345
  this.changeListen(true);
@@ -1291,7 +1367,7 @@ class Select {
1291
1367
  this.observer.observe(this.select, {
1292
1368
  subtree: true,
1293
1369
  childList: true,
1294
- attributes: true,
1370
+ attributes: true
1295
1371
  });
1296
1372
  }
1297
1373
  }
@@ -1303,7 +1379,7 @@ class Select {
1303
1379
  }
1304
1380
  valueChange(ev) {
1305
1381
  if (this.listen && this.onValueChange) {
1306
- this.onValueChange(this.getSelectedValues());
1382
+ this.onValueChange(this.getSelectedOptions());
1307
1383
  }
1308
1384
  return true;
1309
1385
  }
@@ -1322,6 +1398,15 @@ class Select {
1322
1398
  if (m.attributeName === 'class') {
1323
1399
  classChanged = true;
1324
1400
  }
1401
+ if (m.type === 'childList') {
1402
+ for (const n of m.addedNodes) {
1403
+ if (n.nodeName === 'OPTION' && n.value === this.select.value) {
1404
+ this.select.dispatchEvent(new Event('change'));
1405
+ break;
1406
+ }
1407
+ }
1408
+ optgroupOptionChanged = true;
1409
+ }
1325
1410
  }
1326
1411
  if (m.target.nodeName === 'OPTGROUP' || m.target.nodeName === 'OPTION') {
1327
1412
  optgroupOptionChanged = true;
@@ -1361,7 +1446,7 @@ class Select {
1361
1446
  selectAll: optgroup.dataset ? optgroup.dataset.selectall === 'true' : false,
1362
1447
  selectAllText: optgroup.dataset ? optgroup.dataset.selectalltext : 'Select all',
1363
1448
  closable: optgroup.dataset ? optgroup.dataset.closable : 'off',
1364
- options: [],
1449
+ options: []
1365
1450
  };
1366
1451
  const options = optgroup.childNodes;
1367
1452
  for (const o of options) {
@@ -1378,26 +1463,26 @@ class Select {
1378
1463
  text: option.text,
1379
1464
  html: option.dataset && option.dataset.html ? option.dataset.html : '',
1380
1465
  selected: option.selected,
1381
- display: option.style.display === 'none' ? false : true,
1466
+ display: option.style.display !== 'none',
1382
1467
  disabled: option.disabled,
1383
1468
  mandatory: option.dataset ? option.dataset.mandatory === 'true' : false,
1384
1469
  placeholder: option.dataset.placeholder === 'true',
1385
1470
  class: option.className,
1386
1471
  style: option.style.cssText,
1387
- data: option.dataset,
1472
+ data: option.dataset
1388
1473
  };
1389
1474
  }
1390
- getSelectedValues() {
1391
- let values = [];
1392
- const options = this.select.childNodes;
1393
- for (const o of options) {
1475
+ getSelectedOptions() {
1476
+ let options = [];
1477
+ const opts = this.select.childNodes;
1478
+ for (const o of opts) {
1394
1479
  if (o.nodeName === 'OPTGROUP') {
1395
1480
  const optgroupOptions = o.childNodes;
1396
1481
  for (const oo of optgroupOptions) {
1397
1482
  if (oo.nodeName === 'OPTION') {
1398
1483
  const option = oo;
1399
1484
  if (option.selected) {
1400
- values.push(option.value);
1485
+ options.push(this.getDataFromOption(option));
1401
1486
  }
1402
1487
  }
1403
1488
  }
@@ -1405,13 +1490,16 @@ class Select {
1405
1490
  if (o.nodeName === 'OPTION') {
1406
1491
  const option = o;
1407
1492
  if (option.selected) {
1408
- values.push(option.value);
1493
+ options.push(this.getDataFromOption(option));
1409
1494
  }
1410
1495
  }
1411
1496
  }
1412
- return values;
1497
+ return options;
1413
1498
  }
1414
- setSelected(value) {
1499
+ getSelectedValues() {
1500
+ return this.getSelectedOptions().map((option) => option.value);
1501
+ }
1502
+ setSelected(ids) {
1415
1503
  this.changeListen(false);
1416
1504
  const options = this.select.childNodes;
1417
1505
  for (const o of options) {
@@ -1421,13 +1509,34 @@ class Select {
1421
1509
  for (const oo of optgroupOptions) {
1422
1510
  if (oo.nodeName === 'OPTION') {
1423
1511
  const option = oo;
1424
- option.selected = value.includes(option.value);
1512
+ option.selected = ids.includes(option.id);
1425
1513
  }
1426
1514
  }
1427
1515
  }
1428
1516
  if (o.nodeName === 'OPTION') {
1429
1517
  const option = o;
1430
- option.selected = value.includes(option.value);
1518
+ option.selected = ids.includes(option.id);
1519
+ }
1520
+ }
1521
+ this.changeListen(true);
1522
+ }
1523
+ setSelectedByValue(values) {
1524
+ this.changeListen(false);
1525
+ const options = this.select.childNodes;
1526
+ for (const o of options) {
1527
+ if (o.nodeName === 'OPTGROUP') {
1528
+ const optgroup = o;
1529
+ const optgroupOptions = optgroup.childNodes;
1530
+ for (const oo of optgroupOptions) {
1531
+ if (oo.nodeName === 'OPTION') {
1532
+ const option = oo;
1533
+ option.selected = values.includes(option.value);
1534
+ }
1535
+ }
1536
+ }
1537
+ if (o.nodeName === 'OPTION') {
1538
+ const option = o;
1539
+ option.selected = values.includes(option.value);
1431
1540
  }
1432
1541
  }
1433
1542
  this.changeListen(true);
@@ -1461,7 +1570,7 @@ class Select {
1461
1570
  this.select.appendChild(this.createOption(d));
1462
1571
  }
1463
1572
  }
1464
- this.select.dispatchEvent(new Event('change'));
1573
+ this.select.dispatchEvent(new Event('change', { bubbles: true }));
1465
1574
  this.changeListen(true);
1466
1575
  }
1467
1576
  createOptgroup(optgroup) {
@@ -1495,7 +1604,7 @@ class Select {
1495
1604
  if (info.disabled) {
1496
1605
  optionEl.disabled = true;
1497
1606
  }
1498
- if (info.display === false) {
1607
+ if (!info.display) {
1499
1608
  optionEl.style.display = 'none';
1500
1609
  }
1501
1610
  if (info.placeholder) {
@@ -1546,6 +1655,7 @@ class Settings {
1546
1655
  this.disabled = settings.disabled !== undefined ? settings.disabled : false;
1547
1656
  this.alwaysOpen = settings.alwaysOpen !== undefined ? settings.alwaysOpen : false;
1548
1657
  this.showSearch = settings.showSearch !== undefined ? settings.showSearch : true;
1658
+ this.focusSearch = settings.focusSearch !== undefined ? settings.focusSearch : true;
1549
1659
  this.ariaLabel = settings.ariaLabel || 'Combobox';
1550
1660
  this.searchPlaceholder = settings.searchPlaceholder || 'Search';
1551
1661
  this.searchText = settings.searchText || 'No Results';
@@ -1565,6 +1675,7 @@ class Settings {
1565
1675
  this.timeoutDelay = settings.timeoutDelay || 200;
1566
1676
  this.maxValuesShown = settings.maxValuesShown || 20;
1567
1677
  this.maxValuesMessage = settings.maxValuesMessage || '{number} selected';
1678
+ this.addableText = settings.addableText || 'Press "Enter" to add {value}';
1568
1679
  }
1569
1680
  }
1570
1681
 
@@ -1582,7 +1693,7 @@ class SlimSelect {
1582
1693
  beforeOpen: undefined,
1583
1694
  afterOpen: undefined,
1584
1695
  beforeClose: undefined,
1585
- afterClose: undefined,
1696
+ afterClose: undefined
1586
1697
  };
1587
1698
  this.windowResize = debounce(() => {
1588
1699
  if (!this.settings.isOpen && !this.settings.isFullOpen) {
@@ -1626,6 +1737,7 @@ class SlimSelect {
1626
1737
  this.destroy();
1627
1738
  }
1628
1739
  this.settings = new Settings(config.settings);
1740
+ this.cssClasses = new CssClasses(config.cssClasses);
1629
1741
  const debounceEvents = ['afterChange', 'beforeOpen', 'afterOpen', 'beforeClose', 'afterClose'];
1630
1742
  for (const key in config.events) {
1631
1743
  if (!config.events.hasOwnProperty(key)) {
@@ -1645,8 +1757,8 @@ class SlimSelect {
1645
1757
  this.select = new Select(this.selectEl);
1646
1758
  this.select.updateSelect(this.settings.id, this.settings.style, this.settings.class);
1647
1759
  this.select.hideUI();
1648
- this.select.onValueChange = (values) => {
1649
- this.setSelected(values);
1760
+ this.select.onValueChange = (options) => {
1761
+ this.setSelected(options.map((option) => option.id));
1650
1762
  };
1651
1763
  this.select.onClassChange = (classes) => {
1652
1764
  this.settings.class = classes;
@@ -1675,9 +1787,9 @@ class SlimSelect {
1675
1787
  addOption: this.addOption.bind(this),
1676
1788
  search: this.search.bind(this),
1677
1789
  beforeChange: this.events.beforeChange,
1678
- afterChange: this.events.afterChange,
1790
+ afterChange: this.events.afterChange
1679
1791
  };
1680
- this.render = new Render(this.settings, this.store, renderCallbacks);
1792
+ this.render = new Render(this.settings, this.cssClasses, this.store, renderCallbacks);
1681
1793
  this.render.renderValues();
1682
1794
  this.render.renderOptions(this.store.getData());
1683
1795
  const selectAriaLabel = this.selectEl.getAttribute('aria-label');
@@ -1736,11 +1848,27 @@ class SlimSelect {
1736
1848
  }
1737
1849
  }
1738
1850
  getSelected() {
1739
- return this.store.getSelected();
1851
+ let options = this.store.getSelectedOptions();
1852
+ if (this.settings.keepOrder) {
1853
+ options = this.store.selectedOrderOptions(options);
1854
+ }
1855
+ return options.map((option) => option.value);
1740
1856
  }
1741
- setSelected(value, runAfterChange = true) {
1857
+ setSelected(values, runAfterChange = true) {
1742
1858
  const selected = this.store.getSelected();
1743
- this.store.setSelectedBy('value', Array.isArray(value) ? value : [value]);
1859
+ const options = this.store.getDataOptions();
1860
+ values = Array.isArray(values) ? values : [values];
1861
+ const ids = [];
1862
+ for (const value of values) {
1863
+ if (options.find((option) => option.id == value)) {
1864
+ ids.push(value);
1865
+ continue;
1866
+ }
1867
+ for (const option of options.filter((option) => option.value == value)) {
1868
+ ids.push(option.id);
1869
+ }
1870
+ }
1871
+ this.store.setSelectedBy('id', ids);
1744
1872
  const data = this.store.getData();
1745
1873
  this.select.updateOptions(data);
1746
1874
  this.render.renderValues();
@@ -1775,7 +1903,7 @@ class SlimSelect {
1775
1903
  this.events.beforeOpen();
1776
1904
  }
1777
1905
  this.render.open();
1778
- if (this.settings.showSearch) {
1906
+ if (this.settings.showSearch && this.settings.focusSearch) {
1779
1907
  this.render.searchFocus();
1780
1908
  }
1781
1909
  this.settings.isOpen = true;