selectic 3.0.6 → 3.0.10

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.
@@ -35,13 +35,45 @@ function styleInject(css, ref) {
35
35
  var css_248z = "/* {{{ Variables */\n\n:root {\n --selectic-font-size: 14px;\n --selectic-cursor-disabled: not-allowed;\n\n /* The main element */\n --selectic-color: #555555;\n --selectic-bg: #ffffff;\n\n /* The main element (when disabled) */\n --selectic-color-disabled: #787878;\n --selectic-bg-disabled: #eeeeee;\n\n /* The list */\n --selectic-panel-bg: #f0f0f0;\n --selectic-separator-bordercolor: #cccccc;\n /* --selectic-item-color: var(--selectic-color); /* Can be set in any CSS configuration */\n\n /* The current selected item */\n --selectic-selected-item-color: #428bca;\n\n /* When mouse is over items or by selecting with key arrows */\n --selectic-active-item-color: #ffffff;\n --selectic-active-item-bg: #66afe9;\n\n /* Selected values in main element */\n --selectic-value-bg: #f0f0f0;\n /* --selectic-more-items-bg: var(--selectic-info-bg); /* can be set in any CSS configuration */\n /* --selectic-more-items-color: var(--selectic-info-color); /* can be set in any CSS configuration */\n --selectic-more-items-bg-disabled: #cccccc;\n\n /* Information message */\n --selectic-info-bg: #5bc0de;\n --selectic-info-color: #ffffff;\n\n /* Error message */\n --selectic-error-bg: #b72c29;\n --selectic-error-color: #ffffff;\n\n /* XXX: Currently it is important to keep this size for a correct scroll\n * height estimation */\n --selectic-input-height: 30px;\n}\n\n/* }}} */\n/* {{{ Bootstrap equivalent style */\n\n.selectic .form-control {\n display: block;\n width: 100%;\n height: calc(var(--selectic-input-height) - 2px);\n font-size: var(--selectic-font-size);\n line-height: 1.42857143;\n color: var(--selectic-color);\n background-color: var(--selectic-bg);\n background-image: none;\n border: 1px solid var(--selectic-separator-bordercolor); /* should use a better variable */\n border-radius: 4px;\n box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);\n transition: border-color ease-in-out 0.15s, box-shadow ease-in-out 0.15s;\n}\n.selectic .has-feedback {\n position: relative;\n}\n.selectic .has-feedback .form-control {\n padding-right: calc(var(--selectic-input-height) + 4px);\n}\n\n.selectic .form-control-feedback.fa,\n.selectic .form-control-feedback {\n position: absolute;\n top: 0;\n right: 0;\n z-index: 2;\n display: block;\n width: calc(var(--selectic-input-height) + 4px);\n height: calc(var(--selectic-input-height) + 4px);\n line-height: var(--selectic-input-height);\n text-align: center;\n pointer-events: none;\n}\n\n.selectic .alert-info {\n background-color: var(--selectic-info-bg);\n color: var(--selectic-info-color);\n}\n\n.selectic .alert-danger {\n background-color: var(--selectic-error-bg);\n color: var(--selectic-error-color);\n}\n\n/* }}} */\n\n.selectic * {\n -webkit-box-sizing: border-box;\n -moz-box-sizing: border-box;\n box-sizing: border-box;\n}\n\n.selectic.form-control {\n display: inline-block;\n padding: 0;\n cursor: pointer;\n border: unset;\n}\n\n.has-feedback .selectic__icon-container.form-control-feedback {\n right: 0;\n}\n\n/* The input which contains the selected value\n * XXX: This input should stay hidden behind other elements, but is \"visible\"\n * (in term of DOM point of view) in order to get and to trigger the `focus`\n * DOM event. */\n.selectic__input-value {\n position: fixed;\n opacity: 0;\n z-index: -1000;\n top: -100px;\n}\n\n/* XXX: .form-control has been added to this selector to improve priority and\n * override some rules of the original .form-control */\n.selectic-input.form-control {\n display: inline-flex;\n justify-content: space-between;\n overflow: hidden;\n width: 100%;\n min-height: var(--selectic-input-height);\n padding-top: 0;\n padding-bottom: 0;\n padding-left: 5px;\n line-height: calc(var(--selectic-input-height) - 4px);\n color: var(--selectic-color);\n}\n\n.selectic-input__reverse-icon {\n align-self: center;\n margin-right: 3px;\n cursor: default;\n}\n.selectic-input__clear-icon {\n align-self: center;\n margin-left: 3px;\n cursor: pointer;\n}\n.selectic-input__clear-icon:hover {\n color: var(--selectic-selected-item-color);\n}\n\n.selectic-input.focused {\n border-bottom-left-radius: 0px;\n border-bottom-right-radius: 0px;\n}\n\n.selectic-input.disabled {\n cursor: var(--selectic-cursor-disabled);\n background-color: var(--selectic-bg-disabled);\n}\n.selectic-input.disabled .more-items {\n\tbackground-color: var(--selectic-more-items-bg-disabled);\n}\n\n.selectic-input__selected-items {\n display: inline-flex;\n flex-wrap: nowrap;\n align-items: center;\n white-space: nowrap;\n}\n\n.selectic-input__selected-items__placeholder {\n font-style: italic;\n opacity: 0.7;\n white-space: nowrap;\n}\n\n.selectic-icon {\n color: var(--selectic-color);\n text-align: center;\n vertical-align: middle;\n}\n\n.selectic__extended-list {\n position: fixed;\n z-index: 2000;\n height: auto;\n background-color: var(--selectic-bg, #ffffff);\n box-shadow: 2px 5px 12px 0px #888888;\n border-radius: 0 0 4px 4px;\n padding: 0;\n min-width: 200px;\n}\n.selectic__extended-list__list-items {\n max-height: calc(var(--selectic-input-height) * 10);\n overflow: auto;\n padding-left: 0;\n}\n\n.selectic-item {\n display: block;\n position: relative;\n box-sizing: border-box;\n padding: 2px 8px;\n color: var(--selectic-item-color, var(--selectic-color));\n min-height: calc(var(--selectic-input-height) - 3px);\n list-style-type: none;\n white-space: nowrap;\n cursor: pointer;\n}\n\n.selectic-item_text {\n white-space: nowrap;\n text-overflow: ellipsis;\n overflow: hidden;\n}\n\n.selectic-item:not(.selected) .selectic-item_icon {\n opacity: 0;\n}\n\n.selectic-item_text {\n white-space: nowrap;\n text-overflow: ellipsis;\n overflow: hidden;\n}\n\n.selectic-item__active {\n background-color: var(--selectic-active-item-bg);\n color: var(--selectic-active-item-color);\n}\n.selectic-item__active:not(.selected) .selectic-item_icon {\n opacity: 0.2;\n}\n\n.selectic-item__disabled {\n color: var(--selectic-color-disabled);\n background-color: var(--selectic-bg-disabled);\n}\n\n.selectic-item__is-in-group {\n padding-left: 2em;\n}\n\n.selectic-item__is-group {\n font-weight: bold;\n cursor: default;\n}\n\n.selectic-item.selected {\n color: var(--selectic-selected-item-color);\n}\n.selectic-search-scope {\n color: #e0e0e0;\n left: auto;\n right: 10px;\n}\n\n.selectic__message {\n text-align: center;\n padding: 3px;\n}\n\n.selectic .filter-panel {\n padding: 3px;\n margin-left: 0px;\n margin-right: 0px;\n background-color: var(--selectic-panel-bg);\n border-bottom: 1px solid var(--selectic-separator-bordercolor);\n}\n\n.selectic .panelclosed {\n max-height: 0px;\n transition: max-height 0.3s ease-out;\n overflow: hidden;\n}\n\n.panelopened {\n max-height: 200px;\n transition: max-height 0.3s ease-in;\n overflow: hidden;\n}\n\n.selectic .filter-panel__input {\n padding-left: 0px;\n padding-right: 0px;\n padding-bottom: 10px;\n margin-bottom: 0px;\n}\n.selectic .filter-input {\n height: calc(var(--selectic-input-height) * 0.75);\n}\n\n.selectic .checkbox-filter {\n padding: 5px;\n text-align: center;\n}\n\n.selectic .curtain-handler {\n text-align: center;\n}\n\n.selectic .toggle-selectic {\n margin: 5px;\n padding-left: 0px;\n padding-right: 0px;\n}\n\n.selectic .toggle-boolean-select-all-toggle {\n display: inline;\n margin-right: 15px;\n}\n\n.selectic .toggle-boolean-excluding-toggle {\n display: inline;\n margin-right: 15px;\n}\n\n.selectic .single-value {\n display: grid;\n grid-template: \"value icon\" 1fr / max-content max-content;\n\n padding: 2px;\n padding-left: 5px;\n margin-left: 0;\n margin-right: 5px;\n /* margin top/bottom are mainly to create a gutter in multilines */\n margin-top: 2px;\n margin-bottom: 2px;\n\n border-radius: 3px;\n background-color: var(--selectic-value-bg);\n max-height: calc(var(--selectic-input-height) - 10px);\n max-width: 100%;\n min-width: 30px;\n\n overflow: hidden;\n white-space: nowrap;\n line-height: initial;\n vertical-align: middle;\n}\n\n.selectic .more-items {\n display: inline-block;\n\n padding-left: 5px;\n padding-right: 5px;\n border-radius: 10px;\n\n background-color: var(--selectic-more-items-bg, var(--selectic-info-bg));\n color: var(--selectic-more-items-color, var(--selectic-info-color));\n cursor: help;\n}\n.selectic-input__selected-items__value {\n grid-area: value;\n align-self: center;\n justify-self: normal;\n text-overflow: ellipsis;\n overflow: hidden;\n white-space: nowrap;\n}\n\n.selectic-input__selected-items__icon {\n grid-area: icon;\n align-self: center;\n justify-self: center;\n margin-left: 5px;\n}\n.selectic-input__selected-items__icon:hover {\n color: var(--selectic-selected-item-color);\n}\n\n.selectic__label-disabled {\n opacity: 0.5;\n transition: opacity 400ms;\n}\n\n/* XXX: override padding of bootstrap input-sm.\n * This padding introduce a line shift. */\n.selectic.input-sm {\n padding: 0;\n}\n\n/* {{{ overflow multiline */\n\n.selectic--overflow-multiline,\n.selectic--overflow-multiline.form-control,\n.selectic--overflow-multiline .form-control {\n height: unset;\n}\n\n.selectic--overflow-multiline .selectic-input {\n overflow: unset;\n}\n\n.selectic--overflow-multiline .selectic-input__selected-items {\n flex-wrap: wrap;\n}\n\n/* }}} */\n";
36
36
  styleInject(css_248z);
37
37
 
38
- /* File Purpose:
39
- * It keeps and computes all states at a single place.
40
- * Every inner components of Selectic should communicate with this file to
41
- * change or to get states.
38
+ /**
39
+ * Clone the object and its inner properties.
40
+ * @param obj The object to be clone.
41
+ * @param refs internal reference to object to avoid cyclic references
42
+ * @returns a copy of obj
42
43
  */
43
- /* }}} */
44
- /* {{{ Helper */
44
+ function deepClone(obj, refs = new WeakMap()) {
45
+ /* For circular references */
46
+ if (refs.has(obj)) {
47
+ return refs.get(obj);
48
+ }
49
+ if (typeof obj === 'object') {
50
+ if (obj === null) {
51
+ return obj;
52
+ }
53
+ if (Array.isArray(obj)) {
54
+ const ref = [];
55
+ refs.set(obj, ref);
56
+ obj.forEach((val, idx) => {
57
+ ref[idx] = deepClone(val, refs);
58
+ });
59
+ return ref;
60
+ }
61
+ if (obj instanceof RegExp) {
62
+ const ref = new RegExp(obj.source, obj.flags);
63
+ refs.set(obj, ref);
64
+ return ref;
65
+ }
66
+ /* This should be an object */
67
+ const ref = {};
68
+ refs.set(obj, ref);
69
+ for (const [key, val] of Object.entries(obj)) {
70
+ ref[key] = deepClone(val, refs);
71
+ }
72
+ return ref;
73
+ }
74
+ /* This should be a primitive */
75
+ return obj;
76
+ }
45
77
  /**
46
78
  * Escape search string to consider regexp special characters as they
47
79
  * are and not like special characters.
@@ -72,6 +104,12 @@ function assignObject(obj, ...sourceObjects) {
72
104
  }
73
105
  return result;
74
106
  }
107
+
108
+ /* File Purpose:
109
+ * It keeps and computes all states at a single place.
110
+ * Every inner components of Selectic should communicate with this file to
111
+ * change or to get states.
112
+ */
75
113
  /* }}} */
76
114
  /* {{{ Static */
77
115
  function changeTexts$1(texts) {
@@ -211,17 +249,17 @@ class SelecticStore {
211
249
  this.commit('isOpen', false);
212
250
  this.buildAllOptions(true);
213
251
  this.buildSelectedOptions();
214
- });
252
+ }, { deep: true });
215
253
  vue.watch(() => [this.listOptions, this.elementOptions], () => {
216
254
  /* TODO: transform allOptions as a computed properties and this
217
255
  * watcher become useless */
218
256
  this.buildAllOptions(true);
219
- });
257
+ }, { deep: true });
220
258
  vue.watch(() => this.props.value, () => {
221
259
  var _a;
222
260
  const value = (_a = this.props.value) !== null && _a !== void 0 ? _a : null;
223
261
  this.commit('internalValue', value);
224
- });
262
+ }, { deep: true });
225
263
  vue.watch(() => this.props.selectionIsExcluded, () => {
226
264
  this.commit('selectionIsExcluded', this.props.selectionIsExcluded);
227
265
  });
@@ -237,14 +275,14 @@ class SelecticStore {
237
275
  areAllSelected = this.state.filteredOptions.every((item) => !!(+item.selected ^ selectionIsExcluded));
238
276
  }
239
277
  this.state.status.areAllSelected = areAllSelected;
240
- });
278
+ }, { deep: true });
241
279
  vue.watch(() => this.state.internalValue, () => {
242
280
  this.buildSelectedOptions();
243
- });
281
+ }, { deep: true });
244
282
  vue.watch(() => this.state.allOptions, () => {
245
283
  this.checkAutoSelect();
246
284
  this.checkAutoDisabled();
247
- });
285
+ }, { deep: true });
248
286
  vue.watch(() => this.state.totalAllOptions, () => {
249
287
  this.checkHideFilter();
250
288
  });
@@ -253,10 +291,10 @@ class SelecticStore {
253
291
  this.setAutomaticClose();
254
292
  this.commit('isOpen', false);
255
293
  };
256
- const value = this.props.value;
294
+ const value = deepClone(this.props.value);
257
295
  /* set initial value for non reactive attribute */
258
296
  this.cacheRequest = new Map();
259
- const stateParam = Object.assign({}, this.props.params);
297
+ const stateParam = deepClone(this.props.params);
260
298
  if (stateParam.optionBehavior) {
261
299
  this.buildOptionBehavior(stateParam.optionBehavior, stateParam);
262
300
  delete stateParam.optionBehavior;
@@ -274,8 +312,8 @@ class SelecticStore {
274
312
  * and ensure convertValue run with correct state */
275
313
  assignObject(this.state, {
276
314
  internalValue: this.convertTypeValue(value),
277
- selectionIsExcluded: !!props.selectionIsExcluded,
278
- disabled: !!props.disabled, /* XXX: !! is needed to copy value and not proxy reference */
315
+ selectionIsExcluded: !!this.props.selectionIsExcluded,
316
+ disabled: !!this.props.disabled, /* XXX: !! is needed to copy value and not proxy reference */
279
317
  });
280
318
  this.checkHideFilter();
281
319
  if (this.props.texts) {
@@ -646,7 +684,7 @@ class SelecticStore {
646
684
  }
647
685
  /* This method is for the computed property listOptions */
648
686
  getListOptions() {
649
- const options = this.props.options;
687
+ const options = deepClone(this.props.options);
650
688
  const listOptions = [];
651
689
  if (!Array.isArray(options)) {
652
690
  return listOptions;
@@ -683,7 +721,7 @@ class SelecticStore {
683
721
  }
684
722
  /* This method is for the computed property elementOptions */
685
723
  getElementOptions() {
686
- const options = this.props.childOptions;
724
+ const options = deepClone(this.props.childOptions);
687
725
  const childOptions = [];
688
726
  if (!Array.isArray(options) || options.length === 0) {
689
727
  return childOptions;
@@ -1393,7 +1431,7 @@ __decorate$4([
1393
1431
  vtyx.Prop({ default: '' })
1394
1432
  ], MainInput.prototype, "id", void 0);
1395
1433
  __decorate$4([
1396
- vtyx.Watch('store.state.internalValue')
1434
+ vtyx.Watch('store.state.internalValue', { deep: true })
1397
1435
  ], MainInput.prototype, "onInternalChange", null);
1398
1436
  MainInput = __decorate$4([
1399
1437
  vtyx.Component
@@ -1497,7 +1535,7 @@ let FilterPanel = class FilterPanel extends vtyx.Vue {
1497
1535
  document.addEventListener('keypress', this.onKeyPressed);
1498
1536
  this.getFocus();
1499
1537
  }
1500
- destroyed() {
1538
+ unmounted() {
1501
1539
  document.removeEventListener('keypress', this.onKeyPressed);
1502
1540
  }
1503
1541
  /* }}} */
@@ -1757,7 +1795,7 @@ __decorate$2([
1757
1795
  vtyx.Watch('store.state.offsetItem')
1758
1796
  ], List.prototype, "onOffsetChange", null);
1759
1797
  __decorate$2([
1760
- vtyx.Watch('filteredOptions')
1798
+ vtyx.Watch('filteredOptions', { deep: true })
1761
1799
  ], List.prototype, "onFilteredOptionsChange", null);
1762
1800
  __decorate$2([
1763
1801
  vtyx.Watch('groupId')
@@ -1928,7 +1966,7 @@ let ExtendedList = class ExtendedList extends vtyx.Vue {
1928
1966
  document.body.addEventListener('keydown', this.onKeyDown);
1929
1967
  this.computeListSize();
1930
1968
  }
1931
- destroyed() {
1969
+ unmounted() {
1932
1970
  document.body.removeEventListener('keydown', this.onKeyDown);
1933
1971
  /* force the element to be removed from DOM */
1934
1972
  if (this.$el.parentNode) {
@@ -1973,7 +2011,7 @@ __decorate$1([
1973
2011
  vtyx.Prop({ default: 300 })
1974
2012
  ], ExtendedList.prototype, "width", void 0);
1975
2013
  __decorate$1([
1976
- vtyx.Watch('store.state.filteredOptions')
2014
+ vtyx.Watch('store.state.filteredOptions', { deep: true })
1977
2015
  ], ExtendedList.prototype, "onFilteredOptionsChange", null);
1978
2016
  __decorate$1([
1979
2017
  vtyx.Watch('store.state.hideFilter')
@@ -2221,7 +2259,7 @@ let Selectic = class Selectic extends vtyx.Vue {
2221
2259
  this.store.props.selectionIsExcluded = this.selectionIsExcluded;
2222
2260
  }
2223
2261
  onOptionsChange() {
2224
- this.store.props.options = Array.from(this.options);
2262
+ this.store.props.options = deepClone(this.options);
2225
2263
  }
2226
2264
  onTextsChange() {
2227
2265
  const texts = this.texts;
@@ -2462,7 +2500,7 @@ let Selectic = class Selectic extends vtyx.Vue {
2462
2500
  // }
2463
2501
  // this.store.childOptions = options;
2464
2502
  }
2465
- beforeDestroy() {
2503
+ beforeUnmount() {
2466
2504
  this.removeListeners();
2467
2505
  }
2468
2506
  /* }}} */
@@ -2538,22 +2576,22 @@ __decorate([
2538
2576
  vtyx.Prop()
2539
2577
  ], Selectic.prototype, "_getMethods", void 0);
2540
2578
  __decorate([
2541
- vtyx.Watch('value')
2579
+ vtyx.Watch('value', { deep: true })
2542
2580
  ], Selectic.prototype, "onValueChange", null);
2543
2581
  __decorate([
2544
2582
  vtyx.Watch('selectionIsExcluded')
2545
2583
  ], Selectic.prototype, "onExcludedChange", null);
2546
2584
  __decorate([
2547
- vtyx.Watch('options')
2585
+ vtyx.Watch('options', { deep: true })
2548
2586
  ], Selectic.prototype, "onOptionsChange", null);
2549
2587
  __decorate([
2550
- vtyx.Watch('texts')
2588
+ vtyx.Watch('texts', { deep: true })
2551
2589
  ], Selectic.prototype, "onTextsChange", null);
2552
2590
  __decorate([
2553
2591
  vtyx.Watch('disabled')
2554
2592
  ], Selectic.prototype, "onDisabledChange", null);
2555
2593
  __decorate([
2556
- vtyx.Watch('groups')
2594
+ vtyx.Watch('groups', { deep: true })
2557
2595
  ], Selectic.prototype, "onGroupsChanged", null);
2558
2596
  __decorate([
2559
2597
  vtyx.Watch('placeholder')
@@ -2565,7 +2603,7 @@ __decorate([
2565
2603
  vtyx.Watch('isFocused')
2566
2604
  ], Selectic.prototype, "onFocusChanged", null);
2567
2605
  __decorate([
2568
- vtyx.Watch('store.state.internalValue')
2606
+ vtyx.Watch('store.state.internalValue', { deep: true })
2569
2607
  ], Selectic.prototype, "onInternalValueChange", null);
2570
2608
  __decorate([
2571
2609
  vtyx.Emit('input'),
@@ -31,13 +31,45 @@ function styleInject(css, ref) {
31
31
  var css_248z = "/* {{{ Variables */\n\n:root {\n --selectic-font-size: 14px;\n --selectic-cursor-disabled: not-allowed;\n\n /* The main element */\n --selectic-color: #555555;\n --selectic-bg: #ffffff;\n\n /* The main element (when disabled) */\n --selectic-color-disabled: #787878;\n --selectic-bg-disabled: #eeeeee;\n\n /* The list */\n --selectic-panel-bg: #f0f0f0;\n --selectic-separator-bordercolor: #cccccc;\n /* --selectic-item-color: var(--selectic-color); /* Can be set in any CSS configuration */\n\n /* The current selected item */\n --selectic-selected-item-color: #428bca;\n\n /* When mouse is over items or by selecting with key arrows */\n --selectic-active-item-color: #ffffff;\n --selectic-active-item-bg: #66afe9;\n\n /* Selected values in main element */\n --selectic-value-bg: #f0f0f0;\n /* --selectic-more-items-bg: var(--selectic-info-bg); /* can be set in any CSS configuration */\n /* --selectic-more-items-color: var(--selectic-info-color); /* can be set in any CSS configuration */\n --selectic-more-items-bg-disabled: #cccccc;\n\n /* Information message */\n --selectic-info-bg: #5bc0de;\n --selectic-info-color: #ffffff;\n\n /* Error message */\n --selectic-error-bg: #b72c29;\n --selectic-error-color: #ffffff;\n\n /* XXX: Currently it is important to keep this size for a correct scroll\n * height estimation */\n --selectic-input-height: 30px;\n}\n\n/* }}} */\n/* {{{ Bootstrap equivalent style */\n\n.selectic .form-control {\n display: block;\n width: 100%;\n height: calc(var(--selectic-input-height) - 2px);\n font-size: var(--selectic-font-size);\n line-height: 1.42857143;\n color: var(--selectic-color);\n background-color: var(--selectic-bg);\n background-image: none;\n border: 1px solid var(--selectic-separator-bordercolor); /* should use a better variable */\n border-radius: 4px;\n box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);\n transition: border-color ease-in-out 0.15s, box-shadow ease-in-out 0.15s;\n}\n.selectic .has-feedback {\n position: relative;\n}\n.selectic .has-feedback .form-control {\n padding-right: calc(var(--selectic-input-height) + 4px);\n}\n\n.selectic .form-control-feedback.fa,\n.selectic .form-control-feedback {\n position: absolute;\n top: 0;\n right: 0;\n z-index: 2;\n display: block;\n width: calc(var(--selectic-input-height) + 4px);\n height: calc(var(--selectic-input-height) + 4px);\n line-height: var(--selectic-input-height);\n text-align: center;\n pointer-events: none;\n}\n\n.selectic .alert-info {\n background-color: var(--selectic-info-bg);\n color: var(--selectic-info-color);\n}\n\n.selectic .alert-danger {\n background-color: var(--selectic-error-bg);\n color: var(--selectic-error-color);\n}\n\n/* }}} */\n\n.selectic * {\n -webkit-box-sizing: border-box;\n -moz-box-sizing: border-box;\n box-sizing: border-box;\n}\n\n.selectic.form-control {\n display: inline-block;\n padding: 0;\n cursor: pointer;\n border: unset;\n}\n\n.has-feedback .selectic__icon-container.form-control-feedback {\n right: 0;\n}\n\n/* The input which contains the selected value\n * XXX: This input should stay hidden behind other elements, but is \"visible\"\n * (in term of DOM point of view) in order to get and to trigger the `focus`\n * DOM event. */\n.selectic__input-value {\n position: fixed;\n opacity: 0;\n z-index: -1000;\n top: -100px;\n}\n\n/* XXX: .form-control has been added to this selector to improve priority and\n * override some rules of the original .form-control */\n.selectic-input.form-control {\n display: inline-flex;\n justify-content: space-between;\n overflow: hidden;\n width: 100%;\n min-height: var(--selectic-input-height);\n padding-top: 0;\n padding-bottom: 0;\n padding-left: 5px;\n line-height: calc(var(--selectic-input-height) - 4px);\n color: var(--selectic-color);\n}\n\n.selectic-input__reverse-icon {\n align-self: center;\n margin-right: 3px;\n cursor: default;\n}\n.selectic-input__clear-icon {\n align-self: center;\n margin-left: 3px;\n cursor: pointer;\n}\n.selectic-input__clear-icon:hover {\n color: var(--selectic-selected-item-color);\n}\n\n.selectic-input.focused {\n border-bottom-left-radius: 0px;\n border-bottom-right-radius: 0px;\n}\n\n.selectic-input.disabled {\n cursor: var(--selectic-cursor-disabled);\n background-color: var(--selectic-bg-disabled);\n}\n.selectic-input.disabled .more-items {\n\tbackground-color: var(--selectic-more-items-bg-disabled);\n}\n\n.selectic-input__selected-items {\n display: inline-flex;\n flex-wrap: nowrap;\n align-items: center;\n white-space: nowrap;\n}\n\n.selectic-input__selected-items__placeholder {\n font-style: italic;\n opacity: 0.7;\n white-space: nowrap;\n}\n\n.selectic-icon {\n color: var(--selectic-color);\n text-align: center;\n vertical-align: middle;\n}\n\n.selectic__extended-list {\n position: fixed;\n z-index: 2000;\n height: auto;\n background-color: var(--selectic-bg, #ffffff);\n box-shadow: 2px 5px 12px 0px #888888;\n border-radius: 0 0 4px 4px;\n padding: 0;\n min-width: 200px;\n}\n.selectic__extended-list__list-items {\n max-height: calc(var(--selectic-input-height) * 10);\n overflow: auto;\n padding-left: 0;\n}\n\n.selectic-item {\n display: block;\n position: relative;\n box-sizing: border-box;\n padding: 2px 8px;\n color: var(--selectic-item-color, var(--selectic-color));\n min-height: calc(var(--selectic-input-height) - 3px);\n list-style-type: none;\n white-space: nowrap;\n cursor: pointer;\n}\n\n.selectic-item_text {\n white-space: nowrap;\n text-overflow: ellipsis;\n overflow: hidden;\n}\n\n.selectic-item:not(.selected) .selectic-item_icon {\n opacity: 0;\n}\n\n.selectic-item_text {\n white-space: nowrap;\n text-overflow: ellipsis;\n overflow: hidden;\n}\n\n.selectic-item__active {\n background-color: var(--selectic-active-item-bg);\n color: var(--selectic-active-item-color);\n}\n.selectic-item__active:not(.selected) .selectic-item_icon {\n opacity: 0.2;\n}\n\n.selectic-item__disabled {\n color: var(--selectic-color-disabled);\n background-color: var(--selectic-bg-disabled);\n}\n\n.selectic-item__is-in-group {\n padding-left: 2em;\n}\n\n.selectic-item__is-group {\n font-weight: bold;\n cursor: default;\n}\n\n.selectic-item.selected {\n color: var(--selectic-selected-item-color);\n}\n.selectic-search-scope {\n color: #e0e0e0;\n left: auto;\n right: 10px;\n}\n\n.selectic__message {\n text-align: center;\n padding: 3px;\n}\n\n.selectic .filter-panel {\n padding: 3px;\n margin-left: 0px;\n margin-right: 0px;\n background-color: var(--selectic-panel-bg);\n border-bottom: 1px solid var(--selectic-separator-bordercolor);\n}\n\n.selectic .panelclosed {\n max-height: 0px;\n transition: max-height 0.3s ease-out;\n overflow: hidden;\n}\n\n.panelopened {\n max-height: 200px;\n transition: max-height 0.3s ease-in;\n overflow: hidden;\n}\n\n.selectic .filter-panel__input {\n padding-left: 0px;\n padding-right: 0px;\n padding-bottom: 10px;\n margin-bottom: 0px;\n}\n.selectic .filter-input {\n height: calc(var(--selectic-input-height) * 0.75);\n}\n\n.selectic .checkbox-filter {\n padding: 5px;\n text-align: center;\n}\n\n.selectic .curtain-handler {\n text-align: center;\n}\n\n.selectic .toggle-selectic {\n margin: 5px;\n padding-left: 0px;\n padding-right: 0px;\n}\n\n.selectic .toggle-boolean-select-all-toggle {\n display: inline;\n margin-right: 15px;\n}\n\n.selectic .toggle-boolean-excluding-toggle {\n display: inline;\n margin-right: 15px;\n}\n\n.selectic .single-value {\n display: grid;\n grid-template: \"value icon\" 1fr / max-content max-content;\n\n padding: 2px;\n padding-left: 5px;\n margin-left: 0;\n margin-right: 5px;\n /* margin top/bottom are mainly to create a gutter in multilines */\n margin-top: 2px;\n margin-bottom: 2px;\n\n border-radius: 3px;\n background-color: var(--selectic-value-bg);\n max-height: calc(var(--selectic-input-height) - 10px);\n max-width: 100%;\n min-width: 30px;\n\n overflow: hidden;\n white-space: nowrap;\n line-height: initial;\n vertical-align: middle;\n}\n\n.selectic .more-items {\n display: inline-block;\n\n padding-left: 5px;\n padding-right: 5px;\n border-radius: 10px;\n\n background-color: var(--selectic-more-items-bg, var(--selectic-info-bg));\n color: var(--selectic-more-items-color, var(--selectic-info-color));\n cursor: help;\n}\n.selectic-input__selected-items__value {\n grid-area: value;\n align-self: center;\n justify-self: normal;\n text-overflow: ellipsis;\n overflow: hidden;\n white-space: nowrap;\n}\n\n.selectic-input__selected-items__icon {\n grid-area: icon;\n align-self: center;\n justify-self: center;\n margin-left: 5px;\n}\n.selectic-input__selected-items__icon:hover {\n color: var(--selectic-selected-item-color);\n}\n\n.selectic__label-disabled {\n opacity: 0.5;\n transition: opacity 400ms;\n}\n\n/* XXX: override padding of bootstrap input-sm.\n * This padding introduce a line shift. */\n.selectic.input-sm {\n padding: 0;\n}\n\n/* {{{ overflow multiline */\n\n.selectic--overflow-multiline,\n.selectic--overflow-multiline.form-control,\n.selectic--overflow-multiline .form-control {\n height: unset;\n}\n\n.selectic--overflow-multiline .selectic-input {\n overflow: unset;\n}\n\n.selectic--overflow-multiline .selectic-input__selected-items {\n flex-wrap: wrap;\n}\n\n/* }}} */\n";
32
32
  styleInject(css_248z);
33
33
 
34
- /* File Purpose:
35
- * It keeps and computes all states at a single place.
36
- * Every inner components of Selectic should communicate with this file to
37
- * change or to get states.
34
+ /**
35
+ * Clone the object and its inner properties.
36
+ * @param obj The object to be clone.
37
+ * @param refs internal reference to object to avoid cyclic references
38
+ * @returns a copy of obj
38
39
  */
39
- /* }}} */
40
- /* {{{ Helper */
40
+ function deepClone(obj, refs = new WeakMap()) {
41
+ /* For circular references */
42
+ if (refs.has(obj)) {
43
+ return refs.get(obj);
44
+ }
45
+ if (typeof obj === 'object') {
46
+ if (obj === null) {
47
+ return obj;
48
+ }
49
+ if (Array.isArray(obj)) {
50
+ const ref = [];
51
+ refs.set(obj, ref);
52
+ obj.forEach((val, idx) => {
53
+ ref[idx] = deepClone(val, refs);
54
+ });
55
+ return ref;
56
+ }
57
+ if (obj instanceof RegExp) {
58
+ const ref = new RegExp(obj.source, obj.flags);
59
+ refs.set(obj, ref);
60
+ return ref;
61
+ }
62
+ /* This should be an object */
63
+ const ref = {};
64
+ refs.set(obj, ref);
65
+ for (const [key, val] of Object.entries(obj)) {
66
+ ref[key] = deepClone(val, refs);
67
+ }
68
+ return ref;
69
+ }
70
+ /* This should be a primitive */
71
+ return obj;
72
+ }
41
73
  /**
42
74
  * Escape search string to consider regexp special characters as they
43
75
  * are and not like special characters.
@@ -68,6 +100,12 @@ function assignObject(obj, ...sourceObjects) {
68
100
  }
69
101
  return result;
70
102
  }
103
+
104
+ /* File Purpose:
105
+ * It keeps and computes all states at a single place.
106
+ * Every inner components of Selectic should communicate with this file to
107
+ * change or to get states.
108
+ */
71
109
  /* }}} */
72
110
  /* {{{ Static */
73
111
  function changeTexts$1(texts) {
@@ -207,17 +245,17 @@ class SelecticStore {
207
245
  this.commit('isOpen', false);
208
246
  this.buildAllOptions(true);
209
247
  this.buildSelectedOptions();
210
- });
248
+ }, { deep: true });
211
249
  watch(() => [this.listOptions, this.elementOptions], () => {
212
250
  /* TODO: transform allOptions as a computed properties and this
213
251
  * watcher become useless */
214
252
  this.buildAllOptions(true);
215
- });
253
+ }, { deep: true });
216
254
  watch(() => this.props.value, () => {
217
255
  var _a;
218
256
  const value = (_a = this.props.value) !== null && _a !== void 0 ? _a : null;
219
257
  this.commit('internalValue', value);
220
- });
258
+ }, { deep: true });
221
259
  watch(() => this.props.selectionIsExcluded, () => {
222
260
  this.commit('selectionIsExcluded', this.props.selectionIsExcluded);
223
261
  });
@@ -233,14 +271,14 @@ class SelecticStore {
233
271
  areAllSelected = this.state.filteredOptions.every((item) => !!(+item.selected ^ selectionIsExcluded));
234
272
  }
235
273
  this.state.status.areAllSelected = areAllSelected;
236
- });
274
+ }, { deep: true });
237
275
  watch(() => this.state.internalValue, () => {
238
276
  this.buildSelectedOptions();
239
- });
277
+ }, { deep: true });
240
278
  watch(() => this.state.allOptions, () => {
241
279
  this.checkAutoSelect();
242
280
  this.checkAutoDisabled();
243
- });
281
+ }, { deep: true });
244
282
  watch(() => this.state.totalAllOptions, () => {
245
283
  this.checkHideFilter();
246
284
  });
@@ -249,10 +287,10 @@ class SelecticStore {
249
287
  this.setAutomaticClose();
250
288
  this.commit('isOpen', false);
251
289
  };
252
- const value = this.props.value;
290
+ const value = deepClone(this.props.value);
253
291
  /* set initial value for non reactive attribute */
254
292
  this.cacheRequest = new Map();
255
- const stateParam = Object.assign({}, this.props.params);
293
+ const stateParam = deepClone(this.props.params);
256
294
  if (stateParam.optionBehavior) {
257
295
  this.buildOptionBehavior(stateParam.optionBehavior, stateParam);
258
296
  delete stateParam.optionBehavior;
@@ -270,8 +308,8 @@ class SelecticStore {
270
308
  * and ensure convertValue run with correct state */
271
309
  assignObject(this.state, {
272
310
  internalValue: this.convertTypeValue(value),
273
- selectionIsExcluded: !!props.selectionIsExcluded,
274
- disabled: !!props.disabled, /* XXX: !! is needed to copy value and not proxy reference */
311
+ selectionIsExcluded: !!this.props.selectionIsExcluded,
312
+ disabled: !!this.props.disabled, /* XXX: !! is needed to copy value and not proxy reference */
275
313
  });
276
314
  this.checkHideFilter();
277
315
  if (this.props.texts) {
@@ -642,7 +680,7 @@ class SelecticStore {
642
680
  }
643
681
  /* This method is for the computed property listOptions */
644
682
  getListOptions() {
645
- const options = this.props.options;
683
+ const options = deepClone(this.props.options);
646
684
  const listOptions = [];
647
685
  if (!Array.isArray(options)) {
648
686
  return listOptions;
@@ -679,7 +717,7 @@ class SelecticStore {
679
717
  }
680
718
  /* This method is for the computed property elementOptions */
681
719
  getElementOptions() {
682
- const options = this.props.childOptions;
720
+ const options = deepClone(this.props.childOptions);
683
721
  const childOptions = [];
684
722
  if (!Array.isArray(options) || options.length === 0) {
685
723
  return childOptions;
@@ -1389,7 +1427,7 @@ __decorate$4([
1389
1427
  Prop({ default: '' })
1390
1428
  ], MainInput.prototype, "id", void 0);
1391
1429
  __decorate$4([
1392
- Watch('store.state.internalValue')
1430
+ Watch('store.state.internalValue', { deep: true })
1393
1431
  ], MainInput.prototype, "onInternalChange", null);
1394
1432
  MainInput = __decorate$4([
1395
1433
  Component
@@ -1493,7 +1531,7 @@ let FilterPanel = class FilterPanel extends Vue {
1493
1531
  document.addEventListener('keypress', this.onKeyPressed);
1494
1532
  this.getFocus();
1495
1533
  }
1496
- destroyed() {
1534
+ unmounted() {
1497
1535
  document.removeEventListener('keypress', this.onKeyPressed);
1498
1536
  }
1499
1537
  /* }}} */
@@ -1753,7 +1791,7 @@ __decorate$2([
1753
1791
  Watch('store.state.offsetItem')
1754
1792
  ], List.prototype, "onOffsetChange", null);
1755
1793
  __decorate$2([
1756
- Watch('filteredOptions')
1794
+ Watch('filteredOptions', { deep: true })
1757
1795
  ], List.prototype, "onFilteredOptionsChange", null);
1758
1796
  __decorate$2([
1759
1797
  Watch('groupId')
@@ -1924,7 +1962,7 @@ let ExtendedList = class ExtendedList extends Vue {
1924
1962
  document.body.addEventListener('keydown', this.onKeyDown);
1925
1963
  this.computeListSize();
1926
1964
  }
1927
- destroyed() {
1965
+ unmounted() {
1928
1966
  document.body.removeEventListener('keydown', this.onKeyDown);
1929
1967
  /* force the element to be removed from DOM */
1930
1968
  if (this.$el.parentNode) {
@@ -1969,7 +2007,7 @@ __decorate$1([
1969
2007
  Prop({ default: 300 })
1970
2008
  ], ExtendedList.prototype, "width", void 0);
1971
2009
  __decorate$1([
1972
- Watch('store.state.filteredOptions')
2010
+ Watch('store.state.filteredOptions', { deep: true })
1973
2011
  ], ExtendedList.prototype, "onFilteredOptionsChange", null);
1974
2012
  __decorate$1([
1975
2013
  Watch('store.state.hideFilter')
@@ -2217,7 +2255,7 @@ let Selectic = class Selectic extends Vue {
2217
2255
  this.store.props.selectionIsExcluded = this.selectionIsExcluded;
2218
2256
  }
2219
2257
  onOptionsChange() {
2220
- this.store.props.options = Array.from(this.options);
2258
+ this.store.props.options = deepClone(this.options);
2221
2259
  }
2222
2260
  onTextsChange() {
2223
2261
  const texts = this.texts;
@@ -2458,7 +2496,7 @@ let Selectic = class Selectic extends Vue {
2458
2496
  // }
2459
2497
  // this.store.childOptions = options;
2460
2498
  }
2461
- beforeDestroy() {
2499
+ beforeUnmount() {
2462
2500
  this.removeListeners();
2463
2501
  }
2464
2502
  /* }}} */
@@ -2534,22 +2572,22 @@ __decorate([
2534
2572
  Prop()
2535
2573
  ], Selectic.prototype, "_getMethods", void 0);
2536
2574
  __decorate([
2537
- Watch('value')
2575
+ Watch('value', { deep: true })
2538
2576
  ], Selectic.prototype, "onValueChange", null);
2539
2577
  __decorate([
2540
2578
  Watch('selectionIsExcluded')
2541
2579
  ], Selectic.prototype, "onExcludedChange", null);
2542
2580
  __decorate([
2543
- Watch('options')
2581
+ Watch('options', { deep: true })
2544
2582
  ], Selectic.prototype, "onOptionsChange", null);
2545
2583
  __decorate([
2546
- Watch('texts')
2584
+ Watch('texts', { deep: true })
2547
2585
  ], Selectic.prototype, "onTextsChange", null);
2548
2586
  __decorate([
2549
2587
  Watch('disabled')
2550
2588
  ], Selectic.prototype, "onDisabledChange", null);
2551
2589
  __decorate([
2552
- Watch('groups')
2590
+ Watch('groups', { deep: true })
2553
2591
  ], Selectic.prototype, "onGroupsChanged", null);
2554
2592
  __decorate([
2555
2593
  Watch('placeholder')
@@ -2561,7 +2599,7 @@ __decorate([
2561
2599
  Watch('isFocused')
2562
2600
  ], Selectic.prototype, "onFocusChanged", null);
2563
2601
  __decorate([
2564
- Watch('store.state.internalValue')
2602
+ Watch('store.state.internalValue', { deep: true })
2565
2603
  ], Selectic.prototype, "onInternalValueChange", null);
2566
2604
  __decorate([
2567
2605
  Emit('input'),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "selectic",
3
- "version": "3.0.6",
3
+ "version": "3.0.10",
4
4
  "description": "Smart Select for VueJS 3.x",
5
5
  "main": "dist/selectic.common.js",
6
6
  "module": "dist/selectic.esm.js",
@@ -192,7 +192,7 @@ export default class ExtendedList extends Vue<Props> {
192
192
  /* }}} */
193
193
  /* {{{ watch */
194
194
 
195
- @Watch('store.state.filteredOptions')
195
+ @Watch('store.state.filteredOptions', { deep: true })
196
196
  public onFilteredOptionsChange() {
197
197
  this.$nextTick(this.computeListSize);
198
198
  }
@@ -228,7 +228,7 @@ export default class ExtendedList extends Vue<Props> {
228
228
  this.computeListSize();
229
229
  }
230
230
 
231
- public destroyed() {
231
+ public unmounted() {
232
232
  document.body.removeEventListener('keydown', this.onKeyDown);
233
233
 
234
234
  /* force the element to be removed from DOM */
package/src/Filter.tsx CHANGED
@@ -133,7 +133,7 @@ export default class FilterPanel extends Vue<Props> {
133
133
  this.getFocus();
134
134
  }
135
135
 
136
- public destroyed() {
136
+ public unmounted() {
137
137
  document.removeEventListener('keypress', this.onKeyPressed);
138
138
  }
139
139
 
package/src/List.tsx CHANGED
@@ -220,7 +220,7 @@ export default class List extends Vue<Props> {
220
220
  this.checkOffset();
221
221
  }
222
222
 
223
- @Watch('filteredOptions')
223
+ @Watch('filteredOptions', { deep: true })
224
224
  public onFilteredOptionsChange() {
225
225
  this.checkOffset();
226
226
  }
package/src/MainInput.tsx CHANGED
@@ -264,7 +264,7 @@ export default class MainInput extends Vue<Props> {
264
264
  /* }}} */
265
265
  /* {{{ watch */
266
266
 
267
- @Watch('store.state.internalValue')
267
+ @Watch('store.state.internalValue', { deep: true })
268
268
  public onInternalChange() {
269
269
  this.nbHiddenItems = 0;
270
270
  }
package/src/Store.tsx CHANGED
@@ -5,6 +5,7 @@
5
5
  */
6
6
 
7
7
  import { reactive, watch, unref, computed, ComputedRef } from 'vue';
8
+ import { convertToRegExp, assignObject, deepClone } from './tools';
8
9
 
9
10
  /* {{{ Types definitions */
10
11
 
@@ -336,42 +337,6 @@ interface Messages {
336
337
 
337
338
  export type PartialMessages = { [K in keyof Messages]?: Messages[K] };
338
339
 
339
- /* }}} */
340
- /* {{{ Helper */
341
-
342
- /**
343
- * Escape search string to consider regexp special characters as they
344
- * are and not like special characters.
345
- * Consider * characters as a wildcards characters (meanings 0 or
346
- * more characters) and convert them to .* (the wildcard characters
347
- * in Regexp)
348
- *
349
- * @param {String} name the original string to convert
350
- * @param {String} [flag] mode to apply for regExp
351
- * @return {String} the string ready to use for RegExp format
352
- */
353
- function convertToRegExp(name: string, flag = 'i'): RegExp {
354
- const pattern = name.replace(/[\\^$.+?(){}[\]|]/g, '\\$&')
355
- .replace(/\*/g, '.*');
356
-
357
- return new RegExp(pattern, flag);
358
- }
359
-
360
- /** Does the same as Object.assign but does not replace if value is undefined */
361
- function assignObject<T>(obj: Partial<T>, ...sourceObjects: Array<Partial<T>>): T {
362
- const result = obj;
363
- for (const source of sourceObjects) {
364
- for (const key of Object.keys(source)) {
365
- const value = source[key as keyof T];
366
- if (value === undefined) {
367
- continue;
368
- }
369
- result[key as keyof T] = value;
370
- }
371
- }
372
- return result as T;
373
- }
374
-
375
340
  /* }}} */
376
341
  /* {{{ Static */
377
342
 
@@ -567,18 +532,18 @@ export default class SelecticStore {
567
532
  this.commit('isOpen', false);
568
533
  this.buildAllOptions(true);
569
534
  this.buildSelectedOptions();
570
- });
535
+ }, { deep: true });
571
536
 
572
537
  watch(() => [this.listOptions, this.elementOptions], () => {
573
538
  /* TODO: transform allOptions as a computed properties and this
574
539
  * watcher become useless */
575
540
  this.buildAllOptions(true);
576
- });
541
+ }, { deep: true });
577
542
 
578
543
  watch(() => this.props.value, () => {
579
544
  const value = this.props.value ?? null;
580
545
  this.commit('internalValue', value);
581
- });
546
+ }, { deep: true });
582
547
 
583
548
  watch(() => this.props.selectionIsExcluded, () => {
584
549
  this.commit('selectionIsExcluded', this.props.selectionIsExcluded);
@@ -600,16 +565,16 @@ export default class SelecticStore {
600
565
  }
601
566
 
602
567
  this.state.status.areAllSelected = areAllSelected;
603
- });
568
+ }, { deep: true });
604
569
 
605
570
  watch(() => this.state.internalValue, () => {
606
571
  this.buildSelectedOptions();
607
- });
572
+ }, { deep: true });
608
573
 
609
574
  watch(() => this.state.allOptions, () => {
610
575
  this.checkAutoSelect();
611
576
  this.checkAutoDisabled();
612
- });
577
+ }, { deep: true });
613
578
 
614
579
  watch(() => this.state.totalAllOptions, () => {
615
580
  this.checkHideFilter();
@@ -622,13 +587,13 @@ export default class SelecticStore {
622
587
  this.commit('isOpen', false);
623
588
  }
624
589
 
625
- const value = this.props.value;
590
+ const value = deepClone(this.props.value);
626
591
 
627
592
  /* set initial value for non reactive attribute */
628
593
  this.cacheRequest = new Map();
629
594
 
630
595
  const stateParam: SelecticStoreStateParams | SelecticStoreState =
631
- Object.assign({}, this.props.params);
596
+ deepClone(this.props.params);
632
597
 
633
598
  if (stateParam.optionBehavior) {
634
599
  this.buildOptionBehavior(
@@ -651,8 +616,8 @@ export default class SelecticStore {
651
616
  * and ensure convertValue run with correct state */
652
617
  assignObject(this.state, {
653
618
  internalValue: this.convertTypeValue(value),
654
- selectionIsExcluded: !!props.selectionIsExcluded,
655
- disabled: !!props.disabled, /* XXX: !! is needed to copy value and not proxy reference */
619
+ selectionIsExcluded: !!this.props.selectionIsExcluded,
620
+ disabled: !!this.props.disabled, /* XXX: !! is needed to copy value and not proxy reference */
656
621
  });
657
622
 
658
623
  this.checkHideFilter();
@@ -1095,7 +1060,7 @@ export default class SelecticStore {
1095
1060
 
1096
1061
  /* This method is for the computed property listOptions */
1097
1062
  private getListOptions(): OptionValue[] {
1098
- const options = this.props.options;
1063
+ const options = deepClone(this.props.options);
1099
1064
  const listOptions: OptionValue[] = [];
1100
1065
 
1101
1066
  if (!Array.isArray(options)) {
@@ -1141,7 +1106,7 @@ export default class SelecticStore {
1141
1106
 
1142
1107
  /* This method is for the computed property elementOptions */
1143
1108
  private getElementOptions(): OptionValue[] {
1144
- const options = this.props.childOptions;
1109
+ const options = deepClone(this.props.childOptions);
1145
1110
  const childOptions: OptionValue[] = [];
1146
1111
 
1147
1112
  if (!Array.isArray(options) || options.length === 0) {
package/src/index.tsx CHANGED
@@ -21,6 +21,8 @@
21
21
  import {Vue, Component, Emit, Prop, Watch, h} from 'vtyx';
22
22
  import './css/selectic.css';
23
23
 
24
+ import { deepClone } from './tools';
25
+
24
26
  import Store, {
25
27
  changeTexts as storeChangeTexts,
26
28
  OptionProp,
@@ -537,7 +539,7 @@ export default class Selectic extends Vue<Props> {
537
539
  /* }}} */
538
540
  /* {{{ watch */
539
541
 
540
- @Watch('value')
542
+ @Watch('value', { deep: true })
541
543
  public onValueChange() {
542
544
  const currentValue = this.store.state.internalValue;
543
545
  const newValue = this.value ?? null;
@@ -556,12 +558,12 @@ export default class Selectic extends Vue<Props> {
556
558
  this.store.props.selectionIsExcluded = this.selectionIsExcluded;
557
559
  }
558
560
 
559
- @Watch('options')
561
+ @Watch('options', { deep: true })
560
562
  public onOptionsChange() {
561
- this.store.props.options = Array.from(this.options);
563
+ this.store.props.options = deepClone(this.options);
562
564
  }
563
565
 
564
- @Watch('texts')
566
+ @Watch('texts', { deep: true })
565
567
  public onTextsChange() {
566
568
  const texts = this.texts;
567
569
 
@@ -575,7 +577,7 @@ export default class Selectic extends Vue<Props> {
575
577
  this.store.props.disabled = this.disabled;
576
578
  }
577
579
 
578
- @Watch('groups')
580
+ @Watch('groups', { deep: true })
579
581
  public onGroupsChanged() {
580
582
  this.store.changeGroups(this.groups);
581
583
  }
@@ -595,7 +597,7 @@ export default class Selectic extends Vue<Props> {
595
597
  this.focusToggled();
596
598
  }
597
599
 
598
- @Watch('store.state.internalValue')
600
+ @Watch('store.state.internalValue', { deep: true })
599
601
  public onInternalValueChange() {
600
602
  const oldValue = this._oldValue;
601
603
  const value = this.getValue();
@@ -851,7 +853,7 @@ export default class Selectic extends Vue<Props> {
851
853
  // this.store.childOptions = options;
852
854
  }
853
855
 
854
- public beforeDestroy() {
856
+ public beforeUnmount() {
855
857
  this.removeListeners();
856
858
  }
857
859
 
package/src/tools.ts ADDED
@@ -0,0 +1,79 @@
1
+
2
+ /**
3
+ * Clone the object and its inner properties.
4
+ * @param obj The object to be clone.
5
+ * @param refs internal reference to object to avoid cyclic references
6
+ * @returns a copy of obj
7
+ */
8
+ export function deepClone<T = any>(obj: T, refs: WeakMap<any, any> = new WeakMap()): T {
9
+ /* For circular references */
10
+ if (refs.has(obj)) {
11
+ return refs.get(obj);
12
+ }
13
+
14
+ if (typeof obj === 'object') {
15
+ if (obj === null) {
16
+ return obj;
17
+ }
18
+
19
+ if (Array.isArray(obj)) {
20
+ const ref: any[] = [];
21
+ refs.set(obj, ref);
22
+ obj.forEach((val, idx) => {
23
+ ref[idx] = deepClone(val, refs);
24
+ });
25
+ return ref as unknown as T;
26
+ }
27
+
28
+ if (obj instanceof RegExp) {
29
+ const ref = new RegExp(obj.source, obj.flags);
30
+ refs.set(obj, ref);
31
+ return ref as unknown as T;
32
+ }
33
+
34
+ /* This should be an object */
35
+ const ref: any = {};
36
+ refs.set(obj, ref);
37
+ for (const [key, val] of Object.entries(obj)) {
38
+ ref[key] = deepClone(val, refs);
39
+ }
40
+ return ref as unknown as T;
41
+ }
42
+
43
+ /* This should be a primitive */
44
+ return obj;
45
+ }
46
+
47
+
48
+ /**
49
+ * Escape search string to consider regexp special characters as they
50
+ * are and not like special characters.
51
+ * Consider * characters as a wildcards characters (meanings 0 or
52
+ * more characters) and convert them to .* (the wildcard characters
53
+ * in Regexp)
54
+ *
55
+ * @param {String} name the original string to convert
56
+ * @param {String} [flag] mode to apply for regExp
57
+ * @return {String} the string ready to use for RegExp format
58
+ */
59
+ export function convertToRegExp(name: string, flag = 'i'): RegExp {
60
+ const pattern = name.replace(/[\\^$.+?(){}[\]|]/g, '\\$&')
61
+ .replace(/\*/g, '.*');
62
+
63
+ return new RegExp(pattern, flag);
64
+ }
65
+
66
+ /** Does the same as Object.assign but does not replace if value is undefined */
67
+ export function assignObject<T>(obj: Partial<T>, ...sourceObjects: Array<Partial<T>>): T {
68
+ const result = obj;
69
+ for (const source of sourceObjects) {
70
+ for (const key of Object.keys(source)) {
71
+ const value = source[key as keyof T];
72
+ if (value === undefined) {
73
+ continue;
74
+ }
75
+ result[key as keyof T] = value;
76
+ }
77
+ }
78
+ return result as T;
79
+ }
@@ -31,6 +31,6 @@ export default class ExtendedList extends Vue<Props> {
31
31
  private getGroup;
32
32
  private computeListSize;
33
33
  mounted(): void;
34
- destroyed(): void;
34
+ unmounted(): void;
35
35
  render(): h.JSX.Element;
36
36
  }
package/types/Filter.d.ts CHANGED
@@ -23,6 +23,6 @@ export default class FilterPanel extends Vue<Props> {
23
23
  private getFocus;
24
24
  onClosed(): void;
25
25
  mounted(): void;
26
- destroyed(): void;
26
+ unmounted(): void;
27
27
  render(): h.JSX.Element;
28
28
  }
package/types/index.d.ts CHANGED
@@ -136,6 +136,6 @@ export default class Selectic extends Vue<Props> {
136
136
  created(): void;
137
137
  mounted(): void;
138
138
  beforeUpdate(): void;
139
- beforeDestroy(): void;
139
+ beforeUnmount(): void;
140
140
  render(): h.JSX.Element | undefined;
141
141
  }
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Clone the object and its inner properties.
3
+ * @param obj The object to be clone.
4
+ * @param refs internal reference to object to avoid cyclic references
5
+ * @returns a copy of obj
6
+ */
7
+ export declare function deepClone<T = any>(obj: T, refs?: WeakMap<any, any>): T;
8
+ /**
9
+ * Escape search string to consider regexp special characters as they
10
+ * are and not like special characters.
11
+ * Consider * characters as a wildcards characters (meanings 0 or
12
+ * more characters) and convert them to .* (the wildcard characters
13
+ * in Regexp)
14
+ *
15
+ * @param {String} name the original string to convert
16
+ * @param {String} [flag] mode to apply for regExp
17
+ * @return {String} the string ready to use for RegExp format
18
+ */
19
+ export declare function convertToRegExp(name: string, flag?: string): RegExp;
20
+ /** Does the same as Object.assign but does not replace if value is undefined */
21
+ export declare function assignObject<T>(obj: Partial<T>, ...sourceObjects: Array<Partial<T>>): T;