selectic 3.0.19 → 3.0.21

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/.tool-versions ADDED
@@ -0,0 +1,5 @@
1
+ # ASDF configuration file for mmsx repository.
2
+ #
3
+ # https://asdf-vm.com/manage/configuration.html
4
+
5
+ nodejs 12.18.4 system
package/README.md CHANGED
@@ -12,51 +12,66 @@ reverse selection, and many other possibilities.
12
12
 
13
13
  It integrates well with VueJS and is reactive to option changes.
14
14
 
15
+ Typescript types are provided.
16
+
15
17
  There are very few dependencies and code stays very small (~90kB).
16
18
 
19
+ ![example of a Selectic component](./doc/images/selectic_example.png)
20
+
17
21
  ## Example
18
22
 
19
23
  ```html
20
24
  <Selectic
21
- :options="['first choice', 'second choice', 'third choice']"
22
- v-model="selection"
25
+ :options="['first choice', 'second choice', 'third choice']"
26
+ v-model="selection"
23
27
  />
24
28
 
25
29
  <Selectic
26
- value="item2"
27
- :options="[{
28
- id: 'item1',
29
- text: 'The first item',
30
- icon: 'fa fa-thumbs-o-up',
31
- }, {
32
- id: 'item2',
33
- text: 'Another item',
34
- title: 'second choice',
35
- }, {
36
- id: 'item3',
37
- text: 'Disabled item',
38
- disabled: true,
39
- }]"
40
- multiple
41
-
42
- @input="onChange"
30
+ multiple
31
+ value="item2"
32
+ :options="[{
33
+ id: 'item1',
34
+ text: 'The first item',
35
+ icon: 'fa fa-thumbs-o-up',
36
+ }, {
37
+ id: 'item2',
38
+ text: 'Another item',
39
+ title: 'second choice',
40
+ }, {
41
+ id: 'item3',
42
+ text: 'Disabled item',
43
+ disabled: true,
44
+ }]"
45
+
46
+ @input="onChange"
43
47
  />
44
48
 
45
- <Selectic>
46
- <optgroup label="Animals">
47
- <option>Cat</option>
48
- <option value="dog">Dog</option>
49
- <option :value="42">42 goldfishes</option>
50
- </optgroup>
51
- </Selectic>
49
+ <Selectic
50
+ :options="[{
51
+ id: 'animals',
52
+ text: 'Animals',
53
+ options: [{
54
+ id: 'cat',
55
+ text: 'Cat',
56
+ }, {
57
+ id: 'dog',
58
+ text: 'A dog',
59
+ }, {
60
+ id: 42,
61
+ text: '42 goldfishes',
62
+ }],
63
+ }]"
64
+ />
52
65
  ```
53
66
 
67
+ [Full documentation](./doc/main.md)
68
+
54
69
  ## Features
55
70
 
56
71
  * List of items (either string array or object array).
57
72
  * Can load dynamically list from a server and the list can be paginate (with a
58
73
  cache system to avoid reloading previous requests).
59
- * Slots: options may be added from Vue template (by writing explicit `<option>` or `<optgroup>`) in a reactive way _(currently disabled in 3.0.0)_.
74
+ * ~~Slots: options may be added from Vue template (by writing explicit `<option>` or `<optgroup>`) in a reactive way~~ _(currently disabled in 3.0.0+)_.
60
75
  * Multi-sources: Possibility to combine options from different sources (static, dynamic or slots) or to use the other as fallback (if the list is empty).
61
76
  * Supports basic Select properties like `multiple`, `disabled`, `title`
62
77
  * Supports group element (equivalent of optGroup), even for dynamic list.
@@ -111,6 +111,33 @@ function assignObject(obj, ...sourceObjects) {
111
111
  }
112
112
  return result;
113
113
  }
114
+ /** Compare 2 list of options.
115
+ * @returns true if there are no difference
116
+ */
117
+ function compareOptions(oldOptions, newOptions) {
118
+ if (oldOptions.length !== newOptions.length) {
119
+ return false;
120
+ }
121
+ return oldOptions.every((oldOption, idx) => {
122
+ const newOption = newOptions[idx];
123
+ const keys = Object.keys(oldOption);
124
+ if (keys.length !== Object.keys(newOption).length) {
125
+ return false;
126
+ }
127
+ return keys.every((optionKey) => {
128
+ const key = optionKey;
129
+ const oldValue = oldOption[key];
130
+ const newValue = newOption[key];
131
+ if (key === 'options') {
132
+ return compareOptions(oldValue, newValue);
133
+ }
134
+ if (key === 'data') {
135
+ return JSON.stringify(oldValue) === JSON.stringify(newValue);
136
+ }
137
+ return oldValue === newValue;
138
+ });
139
+ });
140
+ }
114
141
 
115
142
  /* File Purpose:
116
143
  * It keeps and computes all states at a single place.
@@ -140,6 +167,7 @@ let messages = {
140
167
  moreSelectedItem: '+1 other',
141
168
  moreSelectedItems: '+%d others',
142
169
  unknownPropertyValue: 'property "%s" has incorrect values.',
170
+ wrongQueryResult: 'Query did not return all results.',
143
171
  };
144
172
  let closePreviousSelectic;
145
173
  /* }}} */
@@ -767,7 +795,7 @@ class SelecticStore {
767
795
  });
768
796
  return childOptions;
769
797
  }
770
- buildAllOptions(keepFetched = false) {
798
+ buildAllOptions(keepFetched = false, stopFetch = false) {
771
799
  const allOptions = [];
772
800
  let listOptions = [];
773
801
  let elementOptions = [];
@@ -838,12 +866,26 @@ class SelecticStore {
838
866
  this.state.totalAllOptions = allOptions.length;
839
867
  }
840
868
  }
841
- this.state.filteredOptions = [];
842
- this.state.totalFilteredOptions = Infinity;
843
- this.buildFilteredOptions().then(() => {
844
- /* XXX: To recompute for strict mode and auto-select */
845
- this.assertCorrectValue();
846
- });
869
+ if (!stopFetch) {
870
+ this.state.filteredOptions = [];
871
+ this.state.totalFilteredOptions = Infinity;
872
+ this.buildFilteredOptions().then(() => {
873
+ /* XXX: To recompute for strict mode and auto-select */
874
+ this.assertCorrectValue();
875
+ });
876
+ }
877
+ else {
878
+ /* Do not fetch again just build filteredOptions */
879
+ const search = this.state.searchText;
880
+ if (!search) {
881
+ this.state.filteredOptions = this.buildGroupItems(allOptions);
882
+ this.state.totalFilteredOptions = this.state.filteredOptions.length;
883
+ return;
884
+ }
885
+ const options = this.filterOptions(allOptions, search);
886
+ this.state.filteredOptions = options;
887
+ this.state.totalFilteredOptions = this.state.filteredOptions.length;
888
+ }
847
889
  }
848
890
  async buildFilteredOptions() {
849
891
  if (!this.state.isOpen) {
@@ -975,6 +1017,7 @@ class SelecticStore {
975
1017
  const requestId = ++this.requestId;
976
1018
  const { total: rTotal, result } = await fetchCallback(search, offset, limit);
977
1019
  let total = rTotal;
1020
+ let errorMessage = '';
978
1021
  /* Assert result is correctly formatted */
979
1022
  if (!Array.isArray(result)) {
980
1023
  throw new Error(labels.wrongFormattedData);
@@ -990,8 +1033,23 @@ class SelecticStore {
990
1033
  if (!search) {
991
1034
  /* update cache */
992
1035
  state.totalDynOptions = total;
993
- state.dynOptions.splice(offset, limit, ...result);
994
- setTimeout(() => this.buildAllOptions(true), 0);
1036
+ const old = state.dynOptions.splice(offset, limit, ...result);
1037
+ if (compareOptions(old, result)) {
1038
+ /* Added options are the same as previous ones.
1039
+ * Stop fetching to avoid infinite loop
1040
+ */
1041
+ if (!this.hasFetchedAllItems) {
1042
+ /* Display error if all items are not fetch
1043
+ * We can have the case where old value and result
1044
+ * are the same but total is correct when the
1045
+ * total is 0 */
1046
+ errorMessage = labels.wrongQueryResult;
1047
+ }
1048
+ setTimeout(() => this.buildAllOptions(true, true), 0);
1049
+ }
1050
+ else {
1051
+ setTimeout(() => this.buildAllOptions(true), 0);
1052
+ }
995
1053
  }
996
1054
  /* Check request is not obsolete */
997
1055
  if (requestId !== this.requestId) {
@@ -1014,13 +1072,13 @@ class SelecticStore {
1014
1072
  if (search && state.totalFilteredOptions <= state.filteredOptions.length) {
1015
1073
  this.addStaticFilteredOptions(true);
1016
1074
  }
1017
- state.status.errorMessage = '';
1075
+ state.status.errorMessage = errorMessage;
1018
1076
  }
1019
1077
  catch (e) {
1020
1078
  state.status.errorMessage = e.message;
1021
1079
  if (!search) {
1022
1080
  state.totalDynOptions = 0;
1023
- this.buildAllOptions(true);
1081
+ this.buildAllOptions(true, true);
1024
1082
  }
1025
1083
  }
1026
1084
  this.state.status.searching = false;
@@ -1220,6 +1278,8 @@ let MainInput = class MainInput extends vtyx.Vue {
1220
1278
  /* }}} */
1221
1279
  /* {{{ data */
1222
1280
  this.nbHiddenItems = 0;
1281
+ /* reactivity non needed */
1282
+ this.domObserver = null;
1223
1283
  }
1224
1284
  /* }}} */
1225
1285
  /* {{{ computed */
@@ -1265,8 +1325,18 @@ let MainInput = class MainInput extends vtyx.Vue {
1265
1325
  get singleSelectedItem() {
1266
1326
  const state = this.store.state;
1267
1327
  const isMultiple = state.multiple;
1268
- const selected = this.selectedOptions;
1269
- return !isMultiple && !!selected && selected.text;
1328
+ if (isMultiple) {
1329
+ return;
1330
+ }
1331
+ return this.selectedOptions;
1332
+ }
1333
+ get singleSelectedItemText() {
1334
+ const item = this.singleSelectedItem;
1335
+ return (item === null || item === void 0 ? void 0 : item.text) || '';
1336
+ }
1337
+ get singleSelectedItemTitle() {
1338
+ const item = this.singleSelectedItem;
1339
+ return (item === null || item === void 0 ? void 0 : item.title) || (item === null || item === void 0 ? void 0 : item.text) || '';
1270
1340
  }
1271
1341
  get singleStyle() {
1272
1342
  const selected = this.selectedOptions;
@@ -1364,6 +1434,11 @@ let MainInput = class MainInput extends vtyx.Vue {
1364
1434
  * currently shown */
1365
1435
  const el = this.$refs.selectedItems;
1366
1436
  const parentEl = el.parentElement;
1437
+ if (!document.contains(parentEl)) {
1438
+ /* The element is currently not in DOM */
1439
+ this.createObserver(parentEl);
1440
+ return;
1441
+ }
1367
1442
  const parentPadding = parseInt(getComputedStyle(parentEl).getPropertyValue('padding-right'), 10);
1368
1443
  const clearEl = parentEl.querySelector('.selectic-input__clear-icon');
1369
1444
  const clearWidth = clearEl ? clearEl.offsetWidth : 0;
@@ -1395,6 +1470,33 @@ let MainInput = class MainInput extends vtyx.Vue {
1395
1470
  idx--;
1396
1471
  this.nbHiddenItems = selectedOptions.length - idx;
1397
1472
  }
1473
+ closeObserver() {
1474
+ const observer = this.domObserver;
1475
+ if (observer) {
1476
+ observer.disconnect();
1477
+ }
1478
+ this.domObserver = null;
1479
+ }
1480
+ createObserver(el) {
1481
+ this.closeObserver();
1482
+ const observer = new MutationObserver((mutationsList) => {
1483
+ for (const mutation of mutationsList) {
1484
+ if (mutation.type === 'childList') {
1485
+ for (const elMutated of Array.from(mutation.addedNodes)) {
1486
+ /* Check that element has been added to DOM */
1487
+ if (elMutated.contains(el)) {
1488
+ this.closeObserver();
1489
+ this.computeSize();
1490
+ return;
1491
+ }
1492
+ }
1493
+ }
1494
+ }
1495
+ });
1496
+ const config = { childList: true, subtree: true };
1497
+ observer.observe(document, config);
1498
+ this.domObserver = observer;
1499
+ }
1398
1500
  /* }}} */
1399
1501
  /* {{{ watch */
1400
1502
  onInternalChange() {
@@ -1405,6 +1507,9 @@ let MainInput = class MainInput extends vtyx.Vue {
1405
1507
  updated() {
1406
1508
  this.computeSize();
1407
1509
  }
1510
+ beforeUnmount() {
1511
+ this.closeObserver();
1512
+ }
1408
1513
  /* }}} */
1409
1514
  render() {
1410
1515
  return (vtyx.h("div", { class: "selectic-container has-feedback", on: {
@@ -1415,14 +1520,14 @@ let MainInput = class MainInput extends vtyx.Vue {
1415
1520
  focused: this.store.state.isOpen,
1416
1521
  disabled: this.store.state.disabled,
1417
1522
  }] },
1418
- this.hasValue && !this.store.state.multiple && (vtyx.h("span", { class: "selectic-item_text", style: this.singleStyle, title: this.singleSelectedItem || '' }, this.singleSelectedItem)),
1523
+ this.hasValue && !this.store.state.multiple && (vtyx.h("span", { class: "selectic-item_text", style: this.singleStyle, title: this.singleSelectedItemTitle }, this.singleSelectedItemText)),
1419
1524
  this.displayPlaceholder && (vtyx.h("span", { class: [
1420
1525
  'selectic-input__selected-items__placeholder',
1421
1526
  'selectic-item_text',
1422
1527
  ], title: this.store.state.placeholder }, this.store.state.placeholder)),
1423
1528
  this.store.state.multiple && (vtyx.h("div", { class: "selectic-input__selected-items", ref: "selectedItems" },
1424
1529
  this.isSelectionReversed && (vtyx.h("span", { class: "fa fa-strikethrough selectic-input__reverse-icon", title: this.reverseSelectionLabel })),
1425
- this.showSelectedOptions.map((item) => (vtyx.h("div", { class: "single-value", style: item.style, title: item.text, on: {
1530
+ this.showSelectedOptions.map((item) => (vtyx.h("div", { class: "single-value", style: item.style, title: item.title || item.text, on: {
1426
1531
  click: () => this.$emit('item:click', item.id),
1427
1532
  } },
1428
1533
  vtyx.h("span", { class: "selectic-input__selected-items__value" }, item.text),
@@ -107,6 +107,33 @@ function assignObject(obj, ...sourceObjects) {
107
107
  }
108
108
  return result;
109
109
  }
110
+ /** Compare 2 list of options.
111
+ * @returns true if there are no difference
112
+ */
113
+ function compareOptions(oldOptions, newOptions) {
114
+ if (oldOptions.length !== newOptions.length) {
115
+ return false;
116
+ }
117
+ return oldOptions.every((oldOption, idx) => {
118
+ const newOption = newOptions[idx];
119
+ const keys = Object.keys(oldOption);
120
+ if (keys.length !== Object.keys(newOption).length) {
121
+ return false;
122
+ }
123
+ return keys.every((optionKey) => {
124
+ const key = optionKey;
125
+ const oldValue = oldOption[key];
126
+ const newValue = newOption[key];
127
+ if (key === 'options') {
128
+ return compareOptions(oldValue, newValue);
129
+ }
130
+ if (key === 'data') {
131
+ return JSON.stringify(oldValue) === JSON.stringify(newValue);
132
+ }
133
+ return oldValue === newValue;
134
+ });
135
+ });
136
+ }
110
137
 
111
138
  /* File Purpose:
112
139
  * It keeps and computes all states at a single place.
@@ -136,6 +163,7 @@ let messages = {
136
163
  moreSelectedItem: '+1 other',
137
164
  moreSelectedItems: '+%d others',
138
165
  unknownPropertyValue: 'property "%s" has incorrect values.',
166
+ wrongQueryResult: 'Query did not return all results.',
139
167
  };
140
168
  let closePreviousSelectic;
141
169
  /* }}} */
@@ -763,7 +791,7 @@ class SelecticStore {
763
791
  });
764
792
  return childOptions;
765
793
  }
766
- buildAllOptions(keepFetched = false) {
794
+ buildAllOptions(keepFetched = false, stopFetch = false) {
767
795
  const allOptions = [];
768
796
  let listOptions = [];
769
797
  let elementOptions = [];
@@ -834,12 +862,26 @@ class SelecticStore {
834
862
  this.state.totalAllOptions = allOptions.length;
835
863
  }
836
864
  }
837
- this.state.filteredOptions = [];
838
- this.state.totalFilteredOptions = Infinity;
839
- this.buildFilteredOptions().then(() => {
840
- /* XXX: To recompute for strict mode and auto-select */
841
- this.assertCorrectValue();
842
- });
865
+ if (!stopFetch) {
866
+ this.state.filteredOptions = [];
867
+ this.state.totalFilteredOptions = Infinity;
868
+ this.buildFilteredOptions().then(() => {
869
+ /* XXX: To recompute for strict mode and auto-select */
870
+ this.assertCorrectValue();
871
+ });
872
+ }
873
+ else {
874
+ /* Do not fetch again just build filteredOptions */
875
+ const search = this.state.searchText;
876
+ if (!search) {
877
+ this.state.filteredOptions = this.buildGroupItems(allOptions);
878
+ this.state.totalFilteredOptions = this.state.filteredOptions.length;
879
+ return;
880
+ }
881
+ const options = this.filterOptions(allOptions, search);
882
+ this.state.filteredOptions = options;
883
+ this.state.totalFilteredOptions = this.state.filteredOptions.length;
884
+ }
843
885
  }
844
886
  async buildFilteredOptions() {
845
887
  if (!this.state.isOpen) {
@@ -971,6 +1013,7 @@ class SelecticStore {
971
1013
  const requestId = ++this.requestId;
972
1014
  const { total: rTotal, result } = await fetchCallback(search, offset, limit);
973
1015
  let total = rTotal;
1016
+ let errorMessage = '';
974
1017
  /* Assert result is correctly formatted */
975
1018
  if (!Array.isArray(result)) {
976
1019
  throw new Error(labels.wrongFormattedData);
@@ -986,8 +1029,23 @@ class SelecticStore {
986
1029
  if (!search) {
987
1030
  /* update cache */
988
1031
  state.totalDynOptions = total;
989
- state.dynOptions.splice(offset, limit, ...result);
990
- setTimeout(() => this.buildAllOptions(true), 0);
1032
+ const old = state.dynOptions.splice(offset, limit, ...result);
1033
+ if (compareOptions(old, result)) {
1034
+ /* Added options are the same as previous ones.
1035
+ * Stop fetching to avoid infinite loop
1036
+ */
1037
+ if (!this.hasFetchedAllItems) {
1038
+ /* Display error if all items are not fetch
1039
+ * We can have the case where old value and result
1040
+ * are the same but total is correct when the
1041
+ * total is 0 */
1042
+ errorMessage = labels.wrongQueryResult;
1043
+ }
1044
+ setTimeout(() => this.buildAllOptions(true, true), 0);
1045
+ }
1046
+ else {
1047
+ setTimeout(() => this.buildAllOptions(true), 0);
1048
+ }
991
1049
  }
992
1050
  /* Check request is not obsolete */
993
1051
  if (requestId !== this.requestId) {
@@ -1010,13 +1068,13 @@ class SelecticStore {
1010
1068
  if (search && state.totalFilteredOptions <= state.filteredOptions.length) {
1011
1069
  this.addStaticFilteredOptions(true);
1012
1070
  }
1013
- state.status.errorMessage = '';
1071
+ state.status.errorMessage = errorMessage;
1014
1072
  }
1015
1073
  catch (e) {
1016
1074
  state.status.errorMessage = e.message;
1017
1075
  if (!search) {
1018
1076
  state.totalDynOptions = 0;
1019
- this.buildAllOptions(true);
1077
+ this.buildAllOptions(true, true);
1020
1078
  }
1021
1079
  }
1022
1080
  this.state.status.searching = false;
@@ -1216,6 +1274,8 @@ let MainInput = class MainInput extends Vue {
1216
1274
  /* }}} */
1217
1275
  /* {{{ data */
1218
1276
  this.nbHiddenItems = 0;
1277
+ /* reactivity non needed */
1278
+ this.domObserver = null;
1219
1279
  }
1220
1280
  /* }}} */
1221
1281
  /* {{{ computed */
@@ -1261,8 +1321,18 @@ let MainInput = class MainInput extends Vue {
1261
1321
  get singleSelectedItem() {
1262
1322
  const state = this.store.state;
1263
1323
  const isMultiple = state.multiple;
1264
- const selected = this.selectedOptions;
1265
- return !isMultiple && !!selected && selected.text;
1324
+ if (isMultiple) {
1325
+ return;
1326
+ }
1327
+ return this.selectedOptions;
1328
+ }
1329
+ get singleSelectedItemText() {
1330
+ const item = this.singleSelectedItem;
1331
+ return (item === null || item === void 0 ? void 0 : item.text) || '';
1332
+ }
1333
+ get singleSelectedItemTitle() {
1334
+ const item = this.singleSelectedItem;
1335
+ return (item === null || item === void 0 ? void 0 : item.title) || (item === null || item === void 0 ? void 0 : item.text) || '';
1266
1336
  }
1267
1337
  get singleStyle() {
1268
1338
  const selected = this.selectedOptions;
@@ -1360,6 +1430,11 @@ let MainInput = class MainInput extends Vue {
1360
1430
  * currently shown */
1361
1431
  const el = this.$refs.selectedItems;
1362
1432
  const parentEl = el.parentElement;
1433
+ if (!document.contains(parentEl)) {
1434
+ /* The element is currently not in DOM */
1435
+ this.createObserver(parentEl);
1436
+ return;
1437
+ }
1363
1438
  const parentPadding = parseInt(getComputedStyle(parentEl).getPropertyValue('padding-right'), 10);
1364
1439
  const clearEl = parentEl.querySelector('.selectic-input__clear-icon');
1365
1440
  const clearWidth = clearEl ? clearEl.offsetWidth : 0;
@@ -1391,6 +1466,33 @@ let MainInput = class MainInput extends Vue {
1391
1466
  idx--;
1392
1467
  this.nbHiddenItems = selectedOptions.length - idx;
1393
1468
  }
1469
+ closeObserver() {
1470
+ const observer = this.domObserver;
1471
+ if (observer) {
1472
+ observer.disconnect();
1473
+ }
1474
+ this.domObserver = null;
1475
+ }
1476
+ createObserver(el) {
1477
+ this.closeObserver();
1478
+ const observer = new MutationObserver((mutationsList) => {
1479
+ for (const mutation of mutationsList) {
1480
+ if (mutation.type === 'childList') {
1481
+ for (const elMutated of Array.from(mutation.addedNodes)) {
1482
+ /* Check that element has been added to DOM */
1483
+ if (elMutated.contains(el)) {
1484
+ this.closeObserver();
1485
+ this.computeSize();
1486
+ return;
1487
+ }
1488
+ }
1489
+ }
1490
+ }
1491
+ });
1492
+ const config = { childList: true, subtree: true };
1493
+ observer.observe(document, config);
1494
+ this.domObserver = observer;
1495
+ }
1394
1496
  /* }}} */
1395
1497
  /* {{{ watch */
1396
1498
  onInternalChange() {
@@ -1401,6 +1503,9 @@ let MainInput = class MainInput extends Vue {
1401
1503
  updated() {
1402
1504
  this.computeSize();
1403
1505
  }
1506
+ beforeUnmount() {
1507
+ this.closeObserver();
1508
+ }
1404
1509
  /* }}} */
1405
1510
  render() {
1406
1511
  return (h("div", { class: "selectic-container has-feedback", on: {
@@ -1411,14 +1516,14 @@ let MainInput = class MainInput extends Vue {
1411
1516
  focused: this.store.state.isOpen,
1412
1517
  disabled: this.store.state.disabled,
1413
1518
  }] },
1414
- this.hasValue && !this.store.state.multiple && (h("span", { class: "selectic-item_text", style: this.singleStyle, title: this.singleSelectedItem || '' }, this.singleSelectedItem)),
1519
+ this.hasValue && !this.store.state.multiple && (h("span", { class: "selectic-item_text", style: this.singleStyle, title: this.singleSelectedItemTitle }, this.singleSelectedItemText)),
1415
1520
  this.displayPlaceholder && (h("span", { class: [
1416
1521
  'selectic-input__selected-items__placeholder',
1417
1522
  'selectic-item_text',
1418
1523
  ], title: this.store.state.placeholder }, this.store.state.placeholder)),
1419
1524
  this.store.state.multiple && (h("div", { class: "selectic-input__selected-items", ref: "selectedItems" },
1420
1525
  this.isSelectionReversed && (h("span", { class: "fa fa-strikethrough selectic-input__reverse-icon", title: this.reverseSelectionLabel })),
1421
- this.showSelectedOptions.map((item) => (h("div", { class: "single-value", style: item.style, title: item.text, on: {
1526
+ this.showSelectedOptions.map((item) => (h("div", { class: "single-value", style: item.style, title: item.title || item.text, on: {
1422
1527
  click: () => this.$emit('item:click', item.id),
1423
1528
  } },
1424
1529
  h("span", { class: "selectic-input__selected-items__value" }, item.text),
package/doc/changeText.md CHANGED
@@ -5,13 +5,13 @@
5
5
  There are some texts in selectic. But sometimes it is useful to change them (because you want to translate them or to be more precise for the context usage).
6
6
 
7
7
  There are 3 ways to changes these texts:
8
- * Call the static `changetexts()` method. It changes texts for all selectic components.
8
+ * Call the static `changeTexts()` method. It changes texts for all selectic components.
9
9
  * Change the `texts` property. It changes texts only for the component.
10
- * Call the `changetexts()` method on the component. It changes texts only for the component.
10
+ * Call the `changeTexts()` method on the component. It changes texts only for the component.
11
11
 
12
12
  _Changes done locally are prioritary on changes done globally_.
13
13
 
14
- Changing texts on the component with property or with `changetexts()` are equivalent.
14
+ Changing texts on the component with property or with `changeTexts()` are equivalent.
15
15
 
16
16
  They accept the same argument: an object which contains keys of sentences.
17
17
 
@@ -19,7 +19,7 @@ It is possible to replace only some sentences.
19
19
 
20
20
  ## Keys
21
21
 
22
- * **noFetchMethod**: This is an error message which is displayed if some options are missing and `fetchcallback` is not defined. _Default value is `'Fetch callback is missing: it is not possible to retrieve data.'`_.
22
+ * **noFetchMethod**: This is an error message which is displayed if some options are missing and `fetchCallback` is not defined. _Default value is `'Fetch callback is missing: it is not possible to retrieve data.'`_.
23
23
 
24
24
  * **searchPlaceholder**: This is the message in the input placeholder to search for options. _Default value is `'Search'`_.
25
25
 
@@ -47,6 +47,8 @@ It is possible to replace only some sentences.
47
47
 
48
48
  * **moreSelectedItems**: This is a message displayed in a badge if there are more selected options than the size of the component. _Default value is `'+%d others'`_.
49
49
 
50
+ * **wrongQueryResult**: This is an error message displayed when result from the `fetchCallback` don't return all expected values. _Default value is `'Query did not return all results.'`_.
51
+
50
52
 
51
53
  ## Example
52
54
 
@@ -64,11 +66,11 @@ this.$refs.selectic.changeTexts({
64
66
  ```
65
67
 
66
68
  ```html
67
- <selectic
68
- texts: {{
69
+ <Selectic
70
+ :texts="{
69
71
  searchPlaceholder: 'Search for specific options?',
70
72
  searching: 'Loading information about this option',
71
- noData: 'oups, I forgot to fill this select',
72
- }}
73
+ noData: 'ouch, I forgot to fill this select',
74
+ }"
73
75
  />
74
76
  ```
package/doc/css.md CHANGED
@@ -74,7 +74,7 @@ body {
74
74
  * **--selectic-active-item-bg** _(default: `#66afe9`)_: Background color of items where cursor is over or the active by the arrow keys.
75
75
 
76
76
  * **--selectic-input-height** _(default: `30px`)_: The height of each items.<br>
77
- **⚠ Currently this value is also hard-coded in javascript, so it can break the scoll height estimation if this value is changed.**
77
+ **:warning: Currently this value is also hard-coded in javascript, so it can break the scroll height estimation if this value is changed.**
78
78
 
79
79
  ### Messages
80
80