slim-select 2.2.3 → 2.3.0

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.
@@ -71,7 +71,7 @@
71
71
  this.id = 'ss-' + generateID();
72
72
  this.style = settings.style || '';
73
73
  this.class = settings.class || [];
74
- this.isEnabled = settings.isEnabled !== undefined ? settings.isEnabled : true;
74
+ this.disabled = settings.disabled !== undefined ? settings.disabled : false;
75
75
  this.alwaysOpen = settings.alwaysOpen !== undefined ? settings.alwaysOpen : false;
76
76
  this.showSearch = settings.showSearch !== undefined ? settings.showSearch : true;
77
77
  this.searchPlaceholder = settings.searchPlaceholder || 'Search';
@@ -89,6 +89,8 @@
89
89
  this.minSelected = settings.minSelected || 0;
90
90
  this.maxSelected = settings.maxSelected || 1000;
91
91
  this.timeoutDelay = settings.timeoutDelay || 200;
92
+ this.maxValuesShown = settings.maxValuesShown || 20;
93
+ this.maxValuesMessage = settings.maxValuesMessage || '{number} selected';
92
94
  }
93
95
  }
94
96
 
@@ -305,6 +307,7 @@
305
307
  placeholder: 'ss-placeholder',
306
308
  values: 'ss-values',
307
309
  single: 'ss-single',
310
+ max: 'ss-max',
308
311
  value: 'ss-value',
309
312
  valueText: 'ss-value-text',
310
313
  valueDelete: 'ss-value-delete',
@@ -361,23 +364,7 @@
361
364
  this.main.main.classList.add(this.settings.openPosition === 'up' ? this.classes.openAbove : this.classes.openBelow);
362
365
  this.moveContent();
363
366
  this.renderOptions(this.store.getData());
364
- if (this.settings.contentPosition === 'relative') {
365
- this.moveContentBelow();
366
- }
367
- else if (this.settings.openPosition.toLowerCase() === 'up') {
368
- this.moveContentAbove();
369
- }
370
- else if (this.settings.openPosition.toLowerCase() === 'down') {
371
- this.moveContentBelow();
372
- }
373
- else {
374
- if (this.putContent(this.content.main, this.settings.isOpen) === 'up') {
375
- this.moveContentAbove();
376
- }
377
- else {
378
- this.moveContentBelow();
379
- }
380
- }
367
+ this.moveContent();
381
368
  const selectedOptions = this.store.getSelectedOptions();
382
369
  if (selectedOptions.length) {
383
370
  const selectedId = selectedOptions[selectedOptions.length - 1].id;
@@ -435,7 +422,7 @@
435
422
  }
436
423
  };
437
424
  main.onclick = (e) => {
438
- if (!this.settings.isEnabled) {
425
+ if (this.settings.disabled) {
439
426
  return;
440
427
  }
441
428
  this.settings.isOpen ? this.callbacks.close() : this.callbacks.open();
@@ -450,7 +437,7 @@
450
437
  }
451
438
  deselect.onclick = (e) => {
452
439
  e.stopPropagation();
453
- if (!this.settings.isEnabled) {
440
+ if (this.settings.disabled) {
454
441
  return;
455
442
  }
456
443
  let shouldDelete = true;
@@ -566,6 +553,19 @@
566
553
  placeholder.remove();
567
554
  }
568
555
  }
556
+ if (selectedOptions.length > this.settings.maxValuesShown) {
557
+ const singleValue = document.createElement('div');
558
+ singleValue.classList.add(this.classes.max);
559
+ singleValue.textContent = this.settings.maxValuesMessage.replace('{number}', selectedOptions.length.toString());
560
+ this.main.values.innerHTML = singleValue.outerHTML;
561
+ return;
562
+ }
563
+ else {
564
+ const maxValuesMessage = this.main.values.querySelector('.' + this.classes.max);
565
+ if (maxValuesMessage) {
566
+ maxValuesMessage.remove();
567
+ }
568
+ }
569
569
  let removeNodes = [];
570
570
  for (let i = 0; i < currentNodes.length; i++) {
571
571
  const node = currentNodes[i];
@@ -620,6 +620,9 @@
620
620
  deleteDiv.onclick = (e) => {
621
621
  e.preventDefault();
622
622
  e.stopPropagation();
623
+ if (this.settings.disabled) {
624
+ return;
625
+ }
623
626
  let shouldDelete = true;
624
627
  const before = this.store.getSelectedOptions();
625
628
  const after = before.filter((o) => {
@@ -691,12 +694,23 @@
691
694
  }
692
695
  moveContent() {
693
696
  if (this.settings.contentPosition === 'relative') {
697
+ this.moveContentBelow();
694
698
  return;
695
699
  }
696
- const containerRect = this.main.main.getBoundingClientRect();
697
- this.content.main.style.top = containerRect.top + containerRect.height + window.scrollY + 'px';
698
- this.content.main.style.left = containerRect.left + window.scrollX + 'px';
699
- this.content.main.style.width = containerRect.width + 'px';
700
+ if (this.settings.openPosition === 'down') {
701
+ this.moveContentBelow();
702
+ return;
703
+ }
704
+ else if (this.settings.openPosition === 'up') {
705
+ this.moveContentAbove();
706
+ return;
707
+ }
708
+ if (this.putContent() === 'up') {
709
+ this.moveContentAbove();
710
+ }
711
+ else {
712
+ this.moveContentBelow();
713
+ }
700
714
  }
701
715
  searchDiv() {
702
716
  const main = document.createElement('div');
@@ -907,8 +921,7 @@
907
921
  this.content.list.innerHTML = '';
908
922
  if (data.length === 0) {
909
923
  const noResults = document.createElement('div');
910
- noResults.classList.add(this.classes.option);
911
- noResults.classList.add(this.classes.disabled);
924
+ noResults.classList.add(this.classes.search);
912
925
  noResults.innerHTML = this.settings.searchText;
913
926
  this.content.list.appendChild(noResults);
914
927
  return;
@@ -984,7 +997,7 @@
984
997
  optgroupClosable.appendChild(optgroupClosableSvg);
985
998
  const optgroupClosableArrow = document.createElementNS('http://www.w3.org/2000/svg', 'path');
986
999
  optgroupClosableSvg.appendChild(optgroupClosableArrow);
987
- if (d.options.some((o) => o.selected)) {
1000
+ if (d.options.some((o) => o.selected) || this.content.search.input.value.trim() !== '') {
988
1001
  optgroupClosable.classList.add(this.classes.open);
989
1002
  optgroupClosableArrow.setAttribute('d', this.classes.arrowOpen);
990
1003
  }
@@ -1043,8 +1056,7 @@
1043
1056
  optionEl.style.cssText = option.style;
1044
1057
  }
1045
1058
  if (this.settings.searchHighlight && this.content.search.input.value.trim() !== '') {
1046
- const textOrHtml = option.html !== '' ? option.html : option.text;
1047
- optionEl.innerHTML = this.highlightText(textOrHtml, this.content.search.input.value, this.classes.searchHighlighter);
1059
+ optionEl.innerHTML = this.highlightText(option.html !== '' ? option.html : option.text, this.content.search.input.value, this.classes.searchHighlighter);
1048
1060
  }
1049
1061
  else if (option.html !== '') {
1050
1062
  optionEl.innerHTML = option.html;
@@ -1055,7 +1067,7 @@
1055
1067
  if (this.settings.showOptionTooltips && optionEl.textContent) {
1056
1068
  optionEl.setAttribute('title', optionEl.textContent);
1057
1069
  }
1058
- if ((option.selected && !this.settings.allowDeselect) || (option.disabled && !this.settings.allowDeselect)) {
1070
+ if (option.disabled) {
1059
1071
  optionEl.classList.add(this.classes.disabled);
1060
1072
  }
1061
1073
  if (option.selected && this.settings.hideSelected) {
@@ -1076,9 +1088,8 @@
1076
1088
  if (option.disabled || (option.selected && !this.settings.allowDeselect)) {
1077
1089
  return;
1078
1090
  }
1079
- if (this.settings.isMultiple &&
1080
- Array.isArray(selectedOptions) &&
1081
- this.settings.maxSelected <= selectedOptions.length) {
1091
+ if ((this.settings.isMultiple && this.settings.maxSelected <= selectedOptions.length && !option.selected) ||
1092
+ (this.settings.isMultiple && this.settings.minSelected >= selectedOptions.length && option.selected)) {
1082
1093
  return;
1083
1094
  }
1084
1095
  let shouldUpdate = false;
@@ -1143,23 +1154,30 @@
1143
1154
  return completedString;
1144
1155
  }
1145
1156
  moveContentAbove() {
1146
- let mainHeight = this.main.main.offsetHeight;
1157
+ const mainHeight = this.main.main.offsetHeight;
1147
1158
  const contentHeight = this.content.main.offsetHeight;
1148
- const height = mainHeight + contentHeight - 1;
1149
- this.content.main.style.margin = '-' + height + 'px 0px 0px 0px';
1150
- this.content.main.style.transformOrigin = 'center bottom';
1151
1159
  this.main.main.classList.remove(this.classes.openBelow);
1152
1160
  this.main.main.classList.add(this.classes.openAbove);
1153
1161
  this.content.main.classList.remove(this.classes.openBelow);
1154
1162
  this.content.main.classList.add(this.classes.openAbove);
1163
+ const containerRect = this.main.main.getBoundingClientRect();
1164
+ this.content.main.style.margin = '-' + (mainHeight + contentHeight - 1) + 'px 0px 0px 0px';
1165
+ this.content.main.style.top = containerRect.top + containerRect.height + window.scrollY + 'px';
1166
+ this.content.main.style.left = containerRect.left + window.scrollX + 'px';
1167
+ this.content.main.style.width = containerRect.width + 'px';
1155
1168
  }
1156
1169
  moveContentBelow() {
1157
- this.content.main.style.margin = '-1px 0px 0px 0px';
1158
- this.content.main.style.transformOrigin = 'center top';
1159
1170
  this.main.main.classList.remove(this.classes.openAbove);
1160
1171
  this.main.main.classList.add(this.classes.openBelow);
1161
1172
  this.content.main.classList.remove(this.classes.openAbove);
1162
1173
  this.content.main.classList.add(this.classes.openBelow);
1174
+ const containerRect = this.main.main.getBoundingClientRect();
1175
+ this.content.main.style.margin = '-1px 0px 0px 0px';
1176
+ if (this.settings.contentPosition !== 'relative') {
1177
+ this.content.main.style.top = containerRect.top + containerRect.height + window.scrollY + 'px';
1178
+ this.content.main.style.left = containerRect.left + window.scrollX + 'px';
1179
+ this.content.main.style.width = containerRect.width + 'px';
1180
+ }
1163
1181
  }
1164
1182
  ensureElementInView(container, element) {
1165
1183
  const cTop = container.scrollTop + container.offsetTop;
@@ -1173,16 +1191,18 @@
1173
1191
  container.scrollTop += eBottom - cBottom;
1174
1192
  }
1175
1193
  }
1176
- putContent(el, isOpen) {
1177
- const height = el.offsetHeight;
1178
- const rect = el.getBoundingClientRect();
1179
- const elemTop = isOpen ? rect.top : rect.top - height;
1180
- const elemBottom = isOpen ? rect.bottom : rect.bottom + height;
1181
- if (elemTop <= 0) {
1182
- return 'down';
1183
- }
1184
- if (elemBottom >= window.innerHeight) {
1185
- return 'up';
1194
+ putContent() {
1195
+ const mainHeight = this.main.main.offsetHeight;
1196
+ const mainRect = this.main.main.getBoundingClientRect();
1197
+ const contentHeight = this.content.main.offsetHeight;
1198
+ const spaceBelow = window.innerHeight - (mainRect.top + mainHeight);
1199
+ if (spaceBelow <= contentHeight) {
1200
+ if (mainRect.top > contentHeight) {
1201
+ return 'up';
1202
+ }
1203
+ else {
1204
+ return 'down';
1205
+ }
1186
1206
  }
1187
1207
  return 'down';
1188
1208
  }
@@ -1193,16 +1213,17 @@
1193
1213
  this.listen = false;
1194
1214
  this.observer = null;
1195
1215
  this.select = select;
1216
+ this.select.addEventListener('change', this.valueChange.bind(this), {
1217
+ passive: true,
1218
+ });
1219
+ this.observer = new MutationObserver(this.observeCall.bind(this));
1220
+ this.changeListen(true);
1196
1221
  }
1197
1222
  enable() {
1198
- this.disconnectObserver();
1199
1223
  this.select.disabled = false;
1200
- this.connectObserver();
1201
1224
  }
1202
1225
  disable() {
1203
- this.disconnectObserver();
1204
1226
  this.select.disabled = true;
1205
- this.connectObserver();
1206
1227
  }
1207
1228
  hideUI() {
1208
1229
  this.select.tabIndex = -1;
@@ -1214,65 +1235,54 @@
1214
1235
  this.select.style.display = '';
1215
1236
  this.select.removeAttribute('aria-hidden');
1216
1237
  }
1217
- changeListen(on) {
1218
- this.listen = on;
1219
- if (this.listen) {
1220
- this.connectObserver();
1238
+ changeListen(listen) {
1239
+ this.listen = listen;
1240
+ if (listen) {
1241
+ if (this.observer) {
1242
+ this.observer.observe(this.select, {
1243
+ subtree: true,
1244
+ childList: true,
1245
+ attributes: true,
1246
+ });
1247
+ }
1221
1248
  }
1222
- else {
1223
- this.disconnectObserver();
1249
+ if (!listen) {
1250
+ if (this.observer) {
1251
+ this.observer.disconnect();
1252
+ }
1224
1253
  }
1225
1254
  }
1226
- addSelectChangeListener(func) {
1227
- this.onSelectChange = func;
1228
- this.addObserver();
1229
- this.connectObserver();
1230
- this.changeListen(true);
1231
- }
1232
- removeSelectChangeListener() {
1233
- this.changeListen(false);
1234
- this.onSelectChange = undefined;
1235
- }
1236
- addValueChangeListener(func) {
1237
- this.onValueChange = func;
1238
- this.select.addEventListener('change', this.valueChange.bind(this), {
1239
- passive: true,
1240
- });
1241
- }
1242
- removeValueChangeListener() {
1243
- this.onValueChange = undefined;
1244
- this.select.removeEventListener('change', this.valueChange.bind(this));
1245
- }
1246
1255
  valueChange(ev) {
1247
1256
  if (this.listen && this.onValueChange) {
1248
1257
  this.onValueChange(this.getSelectedValues());
1249
1258
  }
1250
1259
  return true;
1251
1260
  }
1252
- observeWrapper(mutations) {
1253
- if (this.onSelectChange) {
1254
- this.changeListen(false);
1255
- this.onSelectChange(this.getData());
1256
- this.changeListen(true);
1261
+ observeCall(mutations) {
1262
+ if (!this.listen) {
1263
+ return;
1257
1264
  }
1258
- }
1259
- addObserver() {
1260
- if (this.observer) {
1261
- this.disconnectObserver();
1262
- this.observer = null;
1265
+ let disabledChanged = false;
1266
+ let optgroupOptionChanged = false;
1267
+ for (const m of mutations) {
1268
+ if (m.target === this.select) {
1269
+ if (m.attributeName === 'disabled') {
1270
+ disabledChanged = true;
1271
+ }
1272
+ }
1273
+ if (m.target.nodeName === 'OPTGROUP' || m.target.nodeName === 'OPTION') {
1274
+ optgroupOptionChanged = true;
1275
+ }
1263
1276
  }
1264
- this.observer = new MutationObserver(this.observeWrapper.bind(this));
1265
- }
1266
- connectObserver() {
1267
- if (this.observer) {
1268
- this.observer.observe(this.select, {
1269
- childList: true,
1270
- });
1277
+ if (disabledChanged && this.onDisabledChange) {
1278
+ this.changeListen(false);
1279
+ this.onDisabledChange(this.select.disabled);
1280
+ this.changeListen(true);
1271
1281
  }
1272
- }
1273
- disconnectObserver() {
1274
- if (this.observer) {
1275
- this.observer.disconnect();
1282
+ if (optgroupOptionChanged && this.onOptionsChange) {
1283
+ this.changeListen(false);
1284
+ this.onOptionsChange(this.getData());
1285
+ this.changeListen(true);
1276
1286
  }
1277
1287
  }
1278
1288
  getData() {
@@ -1290,7 +1300,7 @@
1290
1300
  }
1291
1301
  getDataFromOptgroup(optgroup) {
1292
1302
  let data = {
1293
- id: (optgroup.dataset ? optgroup.dataset.id : false) || '',
1303
+ id: optgroup.id,
1294
1304
  label: optgroup.label,
1295
1305
  selectAll: optgroup.dataset ? optgroup.dataset.selectall === 'true' : false,
1296
1306
  closable: optgroup.dataset ? optgroup.dataset.closable : 'off',
@@ -1306,10 +1316,10 @@
1306
1316
  }
1307
1317
  getDataFromOption(option) {
1308
1318
  return {
1309
- id: (option.dataset ? option.dataset.id : false) || '',
1319
+ id: option.id,
1310
1320
  value: option.value,
1311
1321
  text: option.text,
1312
- html: option.innerHTML,
1322
+ html: option.dataset && option.dataset.html ? option.dataset.html : '',
1313
1323
  selected: option.selected,
1314
1324
  display: option.style.display === 'none' ? false : true,
1315
1325
  disabled: option.disabled,
@@ -1345,6 +1355,7 @@
1345
1355
  return values;
1346
1356
  }
1347
1357
  setSelected(value) {
1358
+ this.changeListen(false);
1348
1359
  const options = this.select.childNodes;
1349
1360
  for (const o of options) {
1350
1361
  if (o.nodeName === 'OPTGROUP') {
@@ -1362,6 +1373,7 @@
1362
1373
  option.selected = value.includes(option.value);
1363
1374
  }
1364
1375
  }
1376
+ this.changeListen(true);
1365
1377
  }
1366
1378
  updateSelect(id, style, classes) {
1367
1379
  this.changeListen(false);
@@ -1414,8 +1426,12 @@
1414
1426
  }
1415
1427
  createOption(info) {
1416
1428
  const optionEl = document.createElement('option');
1417
- optionEl.value = info.value !== '' ? info.value : info.text;
1418
- optionEl.innerHTML = info.html || info.text;
1429
+ optionEl.id = info.id;
1430
+ optionEl.value = info.value;
1431
+ optionEl.innerHTML = info.text;
1432
+ if (info.html !== '') {
1433
+ optionEl.setAttribute('data-html', info.html);
1434
+ }
1419
1435
  if (info.selected) {
1420
1436
  optionEl.selected = info.selected;
1421
1437
  }
@@ -1445,15 +1461,18 @@
1445
1461
  }
1446
1462
  destroy() {
1447
1463
  this.changeListen(false);
1448
- this.disconnectObserver();
1449
- this.removeSelectChangeListener();
1450
- this.removeValueChangeListener();
1464
+ this.select.removeEventListener('change', this.valueChange.bind(this));
1465
+ if (this.observer) {
1466
+ this.observer.disconnect();
1467
+ this.observer = null;
1468
+ }
1451
1469
  this.showUI();
1452
1470
  }
1453
1471
  }
1454
1472
 
1455
1473
  class SlimSelect {
1456
1474
  constructor(config) {
1475
+ var _a;
1457
1476
  this.events = {
1458
1477
  search: undefined,
1459
1478
  searchFilter: (opt, search) => {
@@ -1477,23 +1496,7 @@
1477
1496
  if (!this.settings.isOpen) {
1478
1497
  return;
1479
1498
  }
1480
- if (this.settings.openPosition === 'down') {
1481
- this.render.moveContentBelow();
1482
- return;
1483
- }
1484
- else if (this.settings.openPosition === 'up') {
1485
- this.render.moveContentAbove();
1486
- return;
1487
- }
1488
- if (this.settings.contentPosition === 'relative') {
1489
- this.render.moveContentBelow();
1490
- }
1491
- else if (this.render.putContent(this.render.content.main, this.settings.isOpen) === 'up') {
1492
- this.render.moveContentAbove();
1493
- }
1494
- else {
1495
- this.render.moveContentBelow();
1496
- }
1499
+ this.render.moveContent();
1497
1500
  });
1498
1501
  this.documentClick = (e) => {
1499
1502
  if (!this.settings.isOpen) {
@@ -1525,18 +1528,27 @@
1525
1528
  this.events[key] = config.events[key];
1526
1529
  }
1527
1530
  }
1531
+ this.settings.disabled = ((_a = config.settings) === null || _a === void 0 ? void 0 : _a.disabled) ? config.settings.disabled : this.selectEl.disabled;
1528
1532
  this.settings.isMultiple = this.selectEl.multiple;
1529
1533
  this.settings.style = this.selectEl.style.cssText;
1530
1534
  this.settings.class = this.selectEl.className.split(' ');
1531
1535
  this.select = new Select(this.selectEl);
1532
1536
  this.select.updateSelect(this.settings.id, this.settings.style, this.settings.class);
1533
1537
  this.select.hideUI();
1534
- this.select.addSelectChangeListener((data) => {
1535
- this.setData(data);
1536
- });
1537
- this.select.addValueChangeListener((values) => {
1538
+ this.select.onValueChange = (values) => {
1538
1539
  this.setSelected(values);
1539
- });
1540
+ };
1541
+ this.select.onDisabledChange = (disabled) => {
1542
+ if (disabled) {
1543
+ this.disable();
1544
+ }
1545
+ else {
1546
+ this.enable();
1547
+ }
1548
+ };
1549
+ this.select.onOptionsChange = (data) => {
1550
+ this.setData(data);
1551
+ };
1540
1552
  this.store = new Store(this.settings.isMultiple ? 'multiple' : 'single', config.data ? config.data : this.select.getData());
1541
1553
  if (config.data) {
1542
1554
  this.select.updateOptions(this.store.getData());
@@ -1562,7 +1574,7 @@
1562
1574
  if (this.settings.openPosition === 'auto') {
1563
1575
  window.addEventListener('scroll', this.windowScroll, false);
1564
1576
  }
1565
- if (!this.settings.isEnabled) {
1577
+ if (this.settings.disabled) {
1566
1578
  this.disable();
1567
1579
  }
1568
1580
  if (this.settings.alwaysOpen) {
@@ -1571,12 +1583,12 @@
1571
1583
  this.selectEl.slim = this;
1572
1584
  }
1573
1585
  enable() {
1574
- this.settings.isEnabled = true;
1586
+ this.settings.disabled = false;
1575
1587
  this.select.enable();
1576
1588
  this.render.enable();
1577
1589
  }
1578
1590
  disable() {
1579
- this.settings.isEnabled = false;
1591
+ this.settings.disabled = true;
1580
1592
  this.select.disable();
1581
1593
  this.render.disable();
1582
1594
  }
@@ -1610,7 +1622,12 @@
1610
1622
  const data = this.store.getData();
1611
1623
  this.select.updateOptions(data);
1612
1624
  this.render.renderValues();
1613
- this.render.renderOptions(data);
1625
+ if (this.render.content.search.input.value !== '') {
1626
+ this.search(this.render.content.search.input.value);
1627
+ }
1628
+ else {
1629
+ this.render.renderOptions(data);
1630
+ }
1614
1631
  if (this.events.afterChange && !isEqual(selected, this.store.getSelected())) {
1615
1632
  this.events.afterChange(this.store.getSelectedOptions());
1616
1633
  }
@@ -1627,7 +1644,7 @@
1627
1644
  }
1628
1645
  }
1629
1646
  open() {
1630
- if (!this.settings.isEnabled || this.settings.isOpen) {
1647
+ if (this.settings.disabled || this.settings.isOpen) {
1631
1648
  return;
1632
1649
  }
1633
1650
  if (this.events.beforeOpen) {
@@ -1643,10 +1660,12 @@
1643
1660
  }
1644
1661
  this.settings.isOpen = true;
1645
1662
  }, this.settings.timeoutDelay);
1646
- if (this.settings.intervalMove) {
1647
- clearInterval(this.settings.intervalMove);
1663
+ if (this.settings.contentPosition === 'absolute') {
1664
+ if (this.settings.intervalMove) {
1665
+ clearInterval(this.settings.intervalMove);
1666
+ }
1667
+ this.settings.intervalMove = setInterval(this.render.moveContent.bind(this.render), 500);
1648
1668
  }
1649
- this.settings.intervalMove = setInterval(this.render.moveContent.bind(this.render), 500);
1650
1669
  }
1651
1670
  close() {
1652
1671
  if (!this.settings.isOpen || this.settings.alwaysOpen) {