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,3 +1,51 @@
1
+ class CssClasses {
2
+ constructor(classes) {
3
+ if (!classes) {
4
+ classes = {};
5
+ }
6
+ this.main = classes.main || 'ss-main';
7
+ this.placeholder = classes.placeholder || 'ss-placeholder';
8
+ this.values = classes.values || 'ss-values';
9
+ this.single = classes.single || 'ss-single';
10
+ this.max = classes.max || 'ss-max';
11
+ this.value = classes.value || 'ss-value';
12
+ this.valueText = classes.valueText || 'ss-value-text';
13
+ this.valueDelete = classes.valueDelete || 'ss-value-delete';
14
+ this.valueOut = classes.valueOut || 'ss-value-out';
15
+ this.deselect = classes.deselect || 'ss-deselect';
16
+ this.deselectPath = classes.deselectPath || 'M10,10 L90,90 M10,90 L90,10';
17
+ this.arrow = classes.arrow || 'ss-arrow';
18
+ this.arrowClose = classes.arrowClose || 'M10,30 L50,70 L90,30';
19
+ this.arrowOpen = classes.arrowOpen || 'M10,70 L50,30 L90,70';
20
+ this.content = classes.content || 'ss-content';
21
+ this.openAbove = classes.openAbove || 'ss-open-above';
22
+ this.openBelow = classes.openBelow || 'ss-open-below';
23
+ this.search = classes.search || 'ss-search';
24
+ this.searchHighlighter = classes.searchHighlighter || 'ss-search-highlight';
25
+ this.searching = classes.searching || 'ss-searching';
26
+ this.addable = classes.addable || 'ss-addable';
27
+ this.addablePath = classes.addablePath || 'M50,10 L50,90 M10,50 L90,50';
28
+ this.list = classes.list || 'ss-list';
29
+ this.optgroup = classes.optgroup || 'ss-optgroup';
30
+ this.optgroupLabel = classes.optgroupLabel || 'ss-optgroup-label';
31
+ this.optgroupLabelText = classes.optgroupLabelText || 'ss-optgroup-label-text';
32
+ this.optgroupActions = classes.optgroupActions || 'ss-optgroup-actions';
33
+ this.optgroupSelectAll = classes.optgroupSelectAll || 'ss-selectall';
34
+ this.optgroupSelectAllBox = classes.optgroupSelectAllBox || 'M60,10 L10,10 L10,90 L90,90 L90,50';
35
+ this.optgroupSelectAllCheck = classes.optgroupSelectAllCheck || 'M30,45 L50,70 L90,10';
36
+ this.optgroupClosable = classes.optgroupClosable || 'ss-closable';
37
+ this.option = classes.option || 'ss-option';
38
+ this.optionDelete = classes.optionDelete || 'M10,10 L90,90 M10,90 L90,10';
39
+ this.highlighted = classes.highlighted || 'ss-highlighted';
40
+ this.open = classes.open || 'ss-open';
41
+ this.close = classes.close || 'ss-close';
42
+ this.selected = classes.selected || 'ss-selected';
43
+ this.error = classes.error || 'ss-error';
44
+ this.disabled = classes.disabled || 'ss-disabled';
45
+ this.hide = classes.hide || 'ss-hide';
46
+ }
47
+ }
48
+
1
49
  function generateID() {
2
50
  return Math.random().toString(36).substring(2, 10);
3
51
  }
@@ -85,6 +133,7 @@ class Store {
85
133
  constructor(type, data) {
86
134
  this.selectType = 'single';
87
135
  this.data = [];
136
+ this.selectedOrder = [];
88
137
  this.selectType = type;
89
138
  this.setData(data);
90
139
  }
@@ -99,12 +148,18 @@ class Store {
99
148
  }
100
149
  if ('options' in dataObj && dataObj.options) {
101
150
  for (let option of dataObj.options) {
102
- return this.validateOption(option);
151
+ const validationError = this.validateOption(option);
152
+ if (validationError) {
153
+ return validationError;
154
+ }
103
155
  }
104
156
  }
105
157
  }
106
158
  else if (dataObj instanceof Option || 'text' in dataObj) {
107
- return this.validateOption(dataObj);
159
+ const validationError = this.validateOption(dataObj);
160
+ if (validationError) {
161
+ return validationError;
162
+ }
108
163
  }
109
164
  else {
110
165
  return new Error('Data object must be a valid optgroup or option');
@@ -141,7 +196,7 @@ class Store {
141
196
  setData(data) {
142
197
  this.data = this.partialToFullData(data);
143
198
  if (this.selectType === 'single') {
144
- this.setSelectedBy('value', this.getSelected());
199
+ this.setSelectedBy('id', this.getSelected());
145
200
  }
146
201
  }
147
202
  getData() {
@@ -150,12 +205,19 @@ class Store {
150
205
  getDataOptions() {
151
206
  return this.filter(null, false);
152
207
  }
153
- addOption(option) {
154
- this.setData(this.getData().concat(new Option(option)));
208
+ addOption(option, addToStart = false) {
209
+ if (addToStart) {
210
+ let data = [new Option(option)];
211
+ this.setData(data.concat(this.getData()));
212
+ }
213
+ else {
214
+ this.setData(this.getData().concat(new Option(option)));
215
+ }
155
216
  }
156
217
  setSelectedBy(selectedType, selectedValues) {
157
218
  let firstOption = null;
158
219
  let hasSelected = false;
220
+ const selectedObjects = [];
159
221
  for (let dataObj of this.data) {
160
222
  if (dataObj instanceof Optgroup) {
161
223
  for (let option of dataObj.options) {
@@ -163,8 +225,11 @@ class Store {
163
225
  firstOption = option;
164
226
  }
165
227
  option.selected = hasSelected ? false : selectedValues.includes(option[selectedType]);
166
- if (option.selected && this.selectType === 'single') {
167
- hasSelected = true;
228
+ if (option.selected) {
229
+ selectedObjects.push(option);
230
+ if (this.selectType === 'single') {
231
+ hasSelected = true;
232
+ }
168
233
  }
169
234
  }
170
235
  }
@@ -173,36 +238,35 @@ class Store {
173
238
  firstOption = dataObj;
174
239
  }
175
240
  dataObj.selected = hasSelected ? false : selectedValues.includes(dataObj[selectedType]);
176
- if (dataObj.selected && this.selectType === 'single') {
177
- hasSelected = true;
241
+ if (dataObj.selected) {
242
+ selectedObjects.push(dataObj);
243
+ if (this.selectType === 'single') {
244
+ hasSelected = true;
245
+ }
178
246
  }
179
247
  }
180
248
  }
181
249
  if (this.selectType === 'single' && firstOption && !hasSelected) {
182
250
  firstOption.selected = true;
251
+ selectedObjects.push(firstOption);
183
252
  }
253
+ const selectedIds = selectedValues.map((value) => {
254
+ var _a;
255
+ return ((_a = selectedObjects.find((option) => option[selectedType] === value)) === null || _a === void 0 ? void 0 : _a.id) || '';
256
+ });
257
+ this.selectedOrder = selectedIds;
184
258
  }
185
259
  getSelected() {
186
- let selectedOptions = this.getSelectedOptions();
187
- let selectedValues = [];
188
- selectedOptions.forEach((option) => {
189
- selectedValues.push(option.value);
190
- });
191
- return selectedValues;
260
+ return this.getSelectedOptions().map((option) => option.id);
261
+ }
262
+ getSelectedValues() {
263
+ return this.getSelectedOptions().map((option) => option.value);
192
264
  }
193
265
  getSelectedOptions() {
194
266
  return this.filter((opt) => {
195
267
  return opt.selected;
196
268
  }, false);
197
269
  }
198
- getSelectedIDs() {
199
- let selectedOptions = this.getSelectedOptions();
200
- let selectedIDs = [];
201
- selectedOptions.forEach((op) => {
202
- selectedIDs.push(op.id);
203
- });
204
- return selectedIDs;
205
- }
206
270
  getOptgroupByID(id) {
207
271
  for (let dataObj of this.data) {
208
272
  if (dataObj instanceof Optgroup && dataObj.id === id) {
@@ -273,54 +337,35 @@ class Store {
273
337
  });
274
338
  return dataSearch;
275
339
  }
340
+ selectedOrderOptions(options) {
341
+ const newOrder = [];
342
+ this.selectedOrder.forEach((id) => {
343
+ const option = options.find((opt) => opt.id === id);
344
+ if (option) {
345
+ newOrder.push(option);
346
+ }
347
+ });
348
+ options.forEach((option) => {
349
+ let isIn = false;
350
+ newOrder.forEach((selectedOption) => {
351
+ if (option.id === selectedOption.id) {
352
+ isIn = true;
353
+ return;
354
+ }
355
+ });
356
+ if (!isIn) {
357
+ newOrder.push(option);
358
+ }
359
+ });
360
+ return newOrder;
361
+ }
276
362
  }
277
363
 
278
364
  class Render {
279
- constructor(settings, store, callbacks) {
280
- this.classes = {
281
- main: 'ss-main',
282
- placeholder: 'ss-placeholder',
283
- values: 'ss-values',
284
- single: 'ss-single',
285
- max: 'ss-max',
286
- value: 'ss-value',
287
- valueText: 'ss-value-text',
288
- valueDelete: 'ss-value-delete',
289
- valueOut: 'ss-value-out',
290
- deselect: 'ss-deselect',
291
- deselectPath: 'M10,10 L90,90 M10,90 L90,10',
292
- arrow: 'ss-arrow',
293
- arrowClose: 'M10,30 L50,70 L90,30',
294
- arrowOpen: 'M10,70 L50,30 L90,70',
295
- content: 'ss-content',
296
- openAbove: 'ss-open-above',
297
- openBelow: 'ss-open-below',
298
- search: 'ss-search',
299
- searchHighlighter: 'ss-search-highlight',
300
- searching: 'ss-searching',
301
- addable: 'ss-addable',
302
- addablePath: 'M50,10 L50,90 M10,50 L90,50',
303
- list: 'ss-list',
304
- optgroup: 'ss-optgroup',
305
- optgroupLabel: 'ss-optgroup-label',
306
- optgroupLabelText: 'ss-optgroup-label-text',
307
- optgroupActions: 'ss-optgroup-actions',
308
- optgroupSelectAll: 'ss-selectall',
309
- optgroupSelectAllBox: 'M60,10 L10,10 L10,90 L90,90 L90,50',
310
- optgroupSelectAllCheck: 'M30,45 L50,70 L90,10',
311
- optgroupClosable: 'ss-closable',
312
- option: 'ss-option',
313
- optionDelete: 'M10,10 L90,90 M10,90 L90,10',
314
- highlighted: 'ss-highlighted',
315
- open: 'ss-open',
316
- close: 'ss-close',
317
- selected: 'ss-selected',
318
- error: 'ss-error',
319
- disabled: 'ss-disabled',
320
- hide: 'ss-hide',
321
- };
365
+ constructor(settings, classes, store, callbacks) {
322
366
  this.store = store;
323
367
  this.settings = settings;
368
+ this.classes = classes;
324
369
  this.callbacks = callbacks;
325
370
  this.main = this.mainDiv();
326
371
  this.content = this.contentDiv();
@@ -416,7 +461,7 @@ class Render {
416
461
  this.callbacks.close();
417
462
  return false;
418
463
  }
419
- return false;
464
+ return true;
420
465
  };
421
466
  main.onclick = (e) => {
422
467
  if (this.settings.disabled) {
@@ -454,8 +499,8 @@ class Render {
454
499
  }
455
500
  else {
456
501
  const firstOption = this.store.getFirstOption();
457
- const value = firstOption ? firstOption.value : '';
458
- this.callbacks.setSelected(value, false);
502
+ const id = firstOption ? firstOption.id : '';
503
+ this.callbacks.setSelected(id, false);
459
504
  }
460
505
  if (this.settings.closeOnSelect) {
461
506
  this.callbacks.close();
@@ -488,12 +533,12 @@ class Render {
488
533
  deselect: {
489
534
  main: deselect,
490
535
  svg: deselectSvg,
491
- path: deselectPath,
536
+ path: deselectPath
492
537
  },
493
538
  arrow: {
494
539
  main: arrow,
495
- path: arrowPath,
496
- },
540
+ path: arrowPath
541
+ }
497
542
  };
498
543
  }
499
544
  mainFocus(eventType) {
@@ -579,6 +624,9 @@ class Render {
579
624
  maxValuesMessage.remove();
580
625
  }
581
626
  }
627
+ if (this.settings.keepOrder) {
628
+ selectedOptions = this.store.selectedOrderOptions(selectedOptions);
629
+ }
582
630
  let removeNodes = [];
583
631
  for (let i = 0; i < currentNodes.length; i++) {
584
632
  const node = currentNodes[i];
@@ -632,7 +680,7 @@ class Render {
632
680
  value.dataset.id = option.id;
633
681
  const text = document.createElement('div');
634
682
  text.classList.add(this.classes.valueText);
635
- text.innerText = option.text;
683
+ text.textContent = option.text;
636
684
  value.appendChild(text);
637
685
  if (!option.mandatory) {
638
686
  const deleteDiv = document.createElement('div');
@@ -655,18 +703,18 @@ class Render {
655
703
  shouldDelete = this.callbacks.beforeChange(after, before) === true;
656
704
  }
657
705
  if (shouldDelete) {
658
- let selectedValues = [];
706
+ let selectedIds = [];
659
707
  for (const o of after) {
660
708
  if (o instanceof Optgroup) {
661
709
  for (const c of o.options) {
662
- selectedValues.push(c.value);
710
+ selectedIds.push(c.id);
663
711
  }
664
712
  }
665
713
  if (o instanceof Option) {
666
- selectedValues.push(o.value);
714
+ selectedIds.push(o.id);
667
715
  }
668
716
  }
669
- this.callbacks.setSelected(selectedValues, false);
717
+ this.callbacks.setSelected(selectedIds, false);
670
718
  if (this.settings.closeOnSelect) {
671
719
  this.callbacks.close();
672
720
  }
@@ -696,7 +744,7 @@ class Render {
696
744
  return {
697
745
  main: main,
698
746
  search: search,
699
- list: list,
747
+ list: list
700
748
  };
701
749
  }
702
750
  moveContent() {
@@ -726,7 +774,7 @@ class Render {
726
774
  main.classList.add(this.classes.search);
727
775
  const searchReturn = {
728
776
  main,
729
- input,
777
+ input
730
778
  };
731
779
  if (!this.settings.showSearch) {
732
780
  main.classList.add(this.classes.hide);
@@ -754,9 +802,15 @@ class Render {
754
802
  case 'Escape':
755
803
  this.callbacks.close();
756
804
  return false;
757
- case 'Enter':
758
805
  case ' ':
759
- if (this.callbacks.addable && e.ctrlKey) {
806
+ const highlighted = this.content.list.querySelector('.' + this.classes.highlighted);
807
+ if (highlighted) {
808
+ highlighted.click();
809
+ return false;
810
+ }
811
+ return true;
812
+ case 'Enter':
813
+ if (this.callbacks.addable) {
760
814
  addable.click();
761
815
  return false;
762
816
  }
@@ -795,12 +849,12 @@ class Render {
795
849
  let newOption = new Option(oo);
796
850
  this.callbacks.addOption(newOption);
797
851
  if (this.settings.isMultiple) {
798
- let values = this.store.getSelected();
799
- values.push(newOption.value);
800
- this.callbacks.setSelected(values, true);
852
+ let ids = this.store.getSelected();
853
+ ids.push(newOption.id);
854
+ this.callbacks.setSelected(ids, true);
801
855
  }
802
856
  else {
803
- this.callbacks.setSelected([newOption.value], true);
857
+ this.callbacks.setSelected([newOption.id], true);
804
858
  }
805
859
  this.callbacks.search('');
806
860
  if (this.settings.closeOnSelect) {
@@ -818,9 +872,12 @@ class Render {
818
872
  if (typeof value === 'string') {
819
873
  runFinish({
820
874
  text: value,
821
- value: value,
875
+ value: value
822
876
  });
823
877
  }
878
+ else if (addableValue instanceof Error) {
879
+ this.renderError(addableValue.message);
880
+ }
824
881
  else {
825
882
  runFinish(value);
826
883
  }
@@ -829,9 +886,12 @@ class Render {
829
886
  else if (typeof addableValue === 'string') {
830
887
  runFinish({
831
888
  text: addableValue,
832
- value: addableValue,
889
+ value: addableValue
833
890
  });
834
891
  }
892
+ else if (addableValue instanceof Error) {
893
+ this.renderError(addableValue.message);
894
+ }
835
895
  else {
836
896
  runFinish(addableValue);
837
897
  }
@@ -841,7 +901,7 @@ class Render {
841
901
  searchReturn.addable = {
842
902
  main: addable,
843
903
  svg: plus,
844
- path: plusPath,
904
+ path: plusPath
845
905
  };
846
906
  }
847
907
  return searchReturn;
@@ -938,10 +998,26 @@ class Render {
938
998
  if (data.length === 0) {
939
999
  const noResults = document.createElement('div');
940
1000
  noResults.classList.add(this.classes.search);
941
- noResults.innerHTML = this.settings.searchText;
1001
+ if (this.callbacks.addable) {
1002
+ noResults.innerHTML = this.settings.addableText.replace('{value}', this.content.search.input.value);
1003
+ }
1004
+ else {
1005
+ noResults.innerHTML = this.settings.searchText;
1006
+ }
942
1007
  this.content.list.appendChild(noResults);
943
1008
  return;
944
1009
  }
1010
+ if (this.settings.allowDeselect && !this.settings.isMultiple) {
1011
+ const placeholderOption = this.store.filter((o) => o.placeholder, false);
1012
+ if (!placeholderOption.length) {
1013
+ this.store.addOption(new Option({
1014
+ text: '',
1015
+ value: '',
1016
+ selected: false,
1017
+ placeholder: true
1018
+ }), true);
1019
+ }
1020
+ }
945
1021
  for (const d of data) {
946
1022
  if (d instanceof Optgroup) {
947
1023
  const optgroupEl = document.createElement('div');
@@ -988,7 +1064,7 @@ class Render {
988
1064
  if (allSelected) {
989
1065
  const newSelected = currentSelected.filter((s) => {
990
1066
  for (const o of d.options) {
991
- if (s === o.value) {
1067
+ if (s === o.id) {
992
1068
  return false;
993
1069
  }
994
1070
  }
@@ -998,7 +1074,7 @@ class Render {
998
1074
  return;
999
1075
  }
1000
1076
  else {
1001
- const newSelected = currentSelected.concat(d.options.map((o) => o.value));
1077
+ const newSelected = currentSelected.concat(d.options.map((o) => o.id));
1002
1078
  for (const o of d.options) {
1003
1079
  if (!this.store.getOptionByID(o.id)) {
1004
1080
  this.callbacks.addOption(o);
@@ -1155,7 +1231,7 @@ class Render {
1155
1231
  if (!this.store.getOptionByID(elementID)) {
1156
1232
  this.callbacks.addOption(option);
1157
1233
  }
1158
- this.callbacks.setSelected(after.map((o) => o.value), false);
1234
+ this.callbacks.setSelected(after.map((o) => o.id), false);
1159
1235
  if (this.settings.closeOnSelect) {
1160
1236
  this.callbacks.close();
1161
1237
  }
@@ -1172,7 +1248,7 @@ class Render {
1172
1248
  }
1173
1249
  highlightText(str, search, className) {
1174
1250
  let completedString = str;
1175
- const regex = new RegExp('(' + search.trim() + ')(?![^<]*>[^<>]*</)', 'i');
1251
+ const regex = new RegExp('(?![^<]*>)(' + search.trim() + ')(?![^<]*>[^<>]*</)', 'i');
1176
1252
  if (!str.match(regex)) {
1177
1253
  return str;
1178
1254
  }
@@ -1261,7 +1337,7 @@ class Select {
1261
1337
  this.select = select;
1262
1338
  this.valueChange = this.valueChange.bind(this);
1263
1339
  this.select.addEventListener('change', this.valueChange, {
1264
- passive: true,
1340
+ passive: true
1265
1341
  });
1266
1342
  this.observer = new MutationObserver(this.observeCall.bind(this));
1267
1343
  this.changeListen(true);
@@ -1289,7 +1365,7 @@ class Select {
1289
1365
  this.observer.observe(this.select, {
1290
1366
  subtree: true,
1291
1367
  childList: true,
1292
- attributes: true,
1368
+ attributes: true
1293
1369
  });
1294
1370
  }
1295
1371
  }
@@ -1301,7 +1377,7 @@ class Select {
1301
1377
  }
1302
1378
  valueChange(ev) {
1303
1379
  if (this.listen && this.onValueChange) {
1304
- this.onValueChange(this.getSelectedValues());
1380
+ this.onValueChange(this.getSelectedOptions());
1305
1381
  }
1306
1382
  return true;
1307
1383
  }
@@ -1320,6 +1396,15 @@ class Select {
1320
1396
  if (m.attributeName === 'class') {
1321
1397
  classChanged = true;
1322
1398
  }
1399
+ if (m.type === 'childList') {
1400
+ for (const n of m.addedNodes) {
1401
+ if (n.nodeName === 'OPTION' && n.value === this.select.value) {
1402
+ this.select.dispatchEvent(new Event('change'));
1403
+ break;
1404
+ }
1405
+ }
1406
+ optgroupOptionChanged = true;
1407
+ }
1323
1408
  }
1324
1409
  if (m.target.nodeName === 'OPTGROUP' || m.target.nodeName === 'OPTION') {
1325
1410
  optgroupOptionChanged = true;
@@ -1359,7 +1444,7 @@ class Select {
1359
1444
  selectAll: optgroup.dataset ? optgroup.dataset.selectall === 'true' : false,
1360
1445
  selectAllText: optgroup.dataset ? optgroup.dataset.selectalltext : 'Select all',
1361
1446
  closable: optgroup.dataset ? optgroup.dataset.closable : 'off',
1362
- options: [],
1447
+ options: []
1363
1448
  };
1364
1449
  const options = optgroup.childNodes;
1365
1450
  for (const o of options) {
@@ -1376,26 +1461,26 @@ class Select {
1376
1461
  text: option.text,
1377
1462
  html: option.dataset && option.dataset.html ? option.dataset.html : '',
1378
1463
  selected: option.selected,
1379
- display: option.style.display === 'none' ? false : true,
1464
+ display: option.style.display !== 'none',
1380
1465
  disabled: option.disabled,
1381
1466
  mandatory: option.dataset ? option.dataset.mandatory === 'true' : false,
1382
1467
  placeholder: option.dataset.placeholder === 'true',
1383
1468
  class: option.className,
1384
1469
  style: option.style.cssText,
1385
- data: option.dataset,
1470
+ data: option.dataset
1386
1471
  };
1387
1472
  }
1388
- getSelectedValues() {
1389
- let values = [];
1390
- const options = this.select.childNodes;
1391
- for (const o of options) {
1473
+ getSelectedOptions() {
1474
+ let options = [];
1475
+ const opts = this.select.childNodes;
1476
+ for (const o of opts) {
1392
1477
  if (o.nodeName === 'OPTGROUP') {
1393
1478
  const optgroupOptions = o.childNodes;
1394
1479
  for (const oo of optgroupOptions) {
1395
1480
  if (oo.nodeName === 'OPTION') {
1396
1481
  const option = oo;
1397
1482
  if (option.selected) {
1398
- values.push(option.value);
1483
+ options.push(this.getDataFromOption(option));
1399
1484
  }
1400
1485
  }
1401
1486
  }
@@ -1403,13 +1488,16 @@ class Select {
1403
1488
  if (o.nodeName === 'OPTION') {
1404
1489
  const option = o;
1405
1490
  if (option.selected) {
1406
- values.push(option.value);
1491
+ options.push(this.getDataFromOption(option));
1407
1492
  }
1408
1493
  }
1409
1494
  }
1410
- return values;
1495
+ return options;
1411
1496
  }
1412
- setSelected(value) {
1497
+ getSelectedValues() {
1498
+ return this.getSelectedOptions().map((option) => option.value);
1499
+ }
1500
+ setSelected(ids) {
1413
1501
  this.changeListen(false);
1414
1502
  const options = this.select.childNodes;
1415
1503
  for (const o of options) {
@@ -1419,13 +1507,34 @@ class Select {
1419
1507
  for (const oo of optgroupOptions) {
1420
1508
  if (oo.nodeName === 'OPTION') {
1421
1509
  const option = oo;
1422
- option.selected = value.includes(option.value);
1510
+ option.selected = ids.includes(option.id);
1423
1511
  }
1424
1512
  }
1425
1513
  }
1426
1514
  if (o.nodeName === 'OPTION') {
1427
1515
  const option = o;
1428
- option.selected = value.includes(option.value);
1516
+ option.selected = ids.includes(option.id);
1517
+ }
1518
+ }
1519
+ this.changeListen(true);
1520
+ }
1521
+ setSelectedByValue(values) {
1522
+ this.changeListen(false);
1523
+ const options = this.select.childNodes;
1524
+ for (const o of options) {
1525
+ if (o.nodeName === 'OPTGROUP') {
1526
+ const optgroup = o;
1527
+ const optgroupOptions = optgroup.childNodes;
1528
+ for (const oo of optgroupOptions) {
1529
+ if (oo.nodeName === 'OPTION') {
1530
+ const option = oo;
1531
+ option.selected = values.includes(option.value);
1532
+ }
1533
+ }
1534
+ }
1535
+ if (o.nodeName === 'OPTION') {
1536
+ const option = o;
1537
+ option.selected = values.includes(option.value);
1429
1538
  }
1430
1539
  }
1431
1540
  this.changeListen(true);
@@ -1459,7 +1568,7 @@ class Select {
1459
1568
  this.select.appendChild(this.createOption(d));
1460
1569
  }
1461
1570
  }
1462
- this.select.dispatchEvent(new Event('change'));
1571
+ this.select.dispatchEvent(new Event('change', { bubbles: true }));
1463
1572
  this.changeListen(true);
1464
1573
  }
1465
1574
  createOptgroup(optgroup) {
@@ -1493,7 +1602,7 @@ class Select {
1493
1602
  if (info.disabled) {
1494
1603
  optionEl.disabled = true;
1495
1604
  }
1496
- if (info.display === false) {
1605
+ if (!info.display) {
1497
1606
  optionEl.style.display = 'none';
1498
1607
  }
1499
1608
  if (info.placeholder) {
@@ -1544,6 +1653,7 @@ class Settings {
1544
1653
  this.disabled = settings.disabled !== undefined ? settings.disabled : false;
1545
1654
  this.alwaysOpen = settings.alwaysOpen !== undefined ? settings.alwaysOpen : false;
1546
1655
  this.showSearch = settings.showSearch !== undefined ? settings.showSearch : true;
1656
+ this.focusSearch = settings.focusSearch !== undefined ? settings.focusSearch : true;
1547
1657
  this.ariaLabel = settings.ariaLabel || 'Combobox';
1548
1658
  this.searchPlaceholder = settings.searchPlaceholder || 'Search';
1549
1659
  this.searchText = settings.searchText || 'No Results';
@@ -1563,6 +1673,7 @@ class Settings {
1563
1673
  this.timeoutDelay = settings.timeoutDelay || 200;
1564
1674
  this.maxValuesShown = settings.maxValuesShown || 20;
1565
1675
  this.maxValuesMessage = settings.maxValuesMessage || '{number} selected';
1676
+ this.addableText = settings.addableText || 'Press "Enter" to add {value}';
1566
1677
  }
1567
1678
  }
1568
1679
 
@@ -1580,7 +1691,7 @@ class SlimSelect {
1580
1691
  beforeOpen: undefined,
1581
1692
  afterOpen: undefined,
1582
1693
  beforeClose: undefined,
1583
- afterClose: undefined,
1694
+ afterClose: undefined
1584
1695
  };
1585
1696
  this.windowResize = debounce(() => {
1586
1697
  if (!this.settings.isOpen && !this.settings.isFullOpen) {
@@ -1624,6 +1735,7 @@ class SlimSelect {
1624
1735
  this.destroy();
1625
1736
  }
1626
1737
  this.settings = new Settings(config.settings);
1738
+ this.cssClasses = new CssClasses(config.cssClasses);
1627
1739
  const debounceEvents = ['afterChange', 'beforeOpen', 'afterOpen', 'beforeClose', 'afterClose'];
1628
1740
  for (const key in config.events) {
1629
1741
  if (!config.events.hasOwnProperty(key)) {
@@ -1643,8 +1755,8 @@ class SlimSelect {
1643
1755
  this.select = new Select(this.selectEl);
1644
1756
  this.select.updateSelect(this.settings.id, this.settings.style, this.settings.class);
1645
1757
  this.select.hideUI();
1646
- this.select.onValueChange = (values) => {
1647
- this.setSelected(values);
1758
+ this.select.onValueChange = (options) => {
1759
+ this.setSelected(options.map((option) => option.id));
1648
1760
  };
1649
1761
  this.select.onClassChange = (classes) => {
1650
1762
  this.settings.class = classes;
@@ -1673,9 +1785,9 @@ class SlimSelect {
1673
1785
  addOption: this.addOption.bind(this),
1674
1786
  search: this.search.bind(this),
1675
1787
  beforeChange: this.events.beforeChange,
1676
- afterChange: this.events.afterChange,
1788
+ afterChange: this.events.afterChange
1677
1789
  };
1678
- this.render = new Render(this.settings, this.store, renderCallbacks);
1790
+ this.render = new Render(this.settings, this.cssClasses, this.store, renderCallbacks);
1679
1791
  this.render.renderValues();
1680
1792
  this.render.renderOptions(this.store.getData());
1681
1793
  const selectAriaLabel = this.selectEl.getAttribute('aria-label');
@@ -1734,11 +1846,27 @@ class SlimSelect {
1734
1846
  }
1735
1847
  }
1736
1848
  getSelected() {
1737
- return this.store.getSelected();
1849
+ let options = this.store.getSelectedOptions();
1850
+ if (this.settings.keepOrder) {
1851
+ options = this.store.selectedOrderOptions(options);
1852
+ }
1853
+ return options.map((option) => option.value);
1738
1854
  }
1739
- setSelected(value, runAfterChange = true) {
1855
+ setSelected(values, runAfterChange = true) {
1740
1856
  const selected = this.store.getSelected();
1741
- this.store.setSelectedBy('value', Array.isArray(value) ? value : [value]);
1857
+ const options = this.store.getDataOptions();
1858
+ values = Array.isArray(values) ? values : [values];
1859
+ const ids = [];
1860
+ for (const value of values) {
1861
+ if (options.find((option) => option.id == value)) {
1862
+ ids.push(value);
1863
+ continue;
1864
+ }
1865
+ for (const option of options.filter((option) => option.value == value)) {
1866
+ ids.push(option.id);
1867
+ }
1868
+ }
1869
+ this.store.setSelectedBy('id', ids);
1742
1870
  const data = this.store.getData();
1743
1871
  this.select.updateOptions(data);
1744
1872
  this.render.renderValues();
@@ -1773,7 +1901,7 @@ class SlimSelect {
1773
1901
  this.events.beforeOpen();
1774
1902
  }
1775
1903
  this.render.open();
1776
- if (this.settings.showSearch) {
1904
+ if (this.settings.showSearch && this.settings.focusSearch) {
1777
1905
  this.render.searchFocus();
1778
1906
  }
1779
1907
  this.settings.isOpen = true;