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.
- package/dist/selectic.common.js +68 -30
- package/dist/selectic.esm.js +68 -30
- package/package.json +1 -1
- package/src/ExtendedList.tsx +2 -2
- package/src/Filter.tsx +1 -1
- package/src/List.tsx +1 -1
- package/src/MainInput.tsx +1 -1
- package/src/Store.tsx +13 -48
- package/src/index.tsx +9 -7
- package/src/tools.ts +79 -0
- package/types/ExtendedList.d.ts +1 -1
- package/types/Filter.d.ts +1 -1
- package/types/index.d.ts +1 -1
- package/types/tools.d.ts +21 -0
package/dist/selectic.common.js
CHANGED
|
@@ -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
|
-
|
|
39
|
-
*
|
|
40
|
-
*
|
|
41
|
-
*
|
|
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
|
-
/*
|
|
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 =
|
|
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
|
-
|
|
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
|
-
|
|
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 =
|
|
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
|
-
|
|
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'),
|
package/dist/selectic.esm.js
CHANGED
|
@@ -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
|
-
|
|
35
|
-
*
|
|
36
|
-
*
|
|
37
|
-
*
|
|
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
|
-
/*
|
|
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 =
|
|
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
|
-
|
|
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
|
-
|
|
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 =
|
|
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
|
-
|
|
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
package/src/ExtendedList.tsx
CHANGED
|
@@ -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
|
|
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
package/src/List.tsx
CHANGED
package/src/MainInput.tsx
CHANGED
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
|
-
|
|
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 =
|
|
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
|
|
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
|
+
}
|
package/types/ExtendedList.d.ts
CHANGED
package/types/Filter.d.ts
CHANGED
package/types/index.d.ts
CHANGED
package/types/tools.d.ts
ADDED
|
@@ -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;
|