selectic 3.1.1 → 3.1.3

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/README.md CHANGED
@@ -112,13 +112,3 @@ Run unitary tests:
112
112
  ```console
113
113
  $ npm run test
114
114
  ```
115
-
116
- ## Migration information
117
-
118
- ### From 3.0 to 3.1
119
-
120
- Selectic no more depends on Font-awesome. It embeds its own icons (from Material Design Icons).
121
-
122
- It is still possible to use Font-awesome icons (or from any other libraries).
123
-
124
- Read [the documentation section related to changing icons](./doc/changeIcons.md) for more information on how to handle them.
@@ -32,7 +32,7 @@ function styleInject(css, ref) {
32
32
  }
33
33
  }
34
34
 
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 top: var(--top-position, 0);\n z-index: 2000;\n height: auto;\n max-height: var(--availableSpace);\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 width: var(--list-width, 200px);\n min-width: 200px;\n display: grid;\n grid-template-rows: minmax(0, max-content) 1fr;\n}\n.selectic__extended-list.selectic-position-top {\n box-shadow: 2px -3px 12px 0px #888888;\n}\n.selectic__extended-list__list-container{\n overflow: auto;\n}\n.selectic__extended-list__list-items {\n max-height: calc(var(--selectic-input-height) * 10);\n min-width: max-content;\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__is-group.selectable {\n cursor: pointer;\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.selectic .form-control-feedback.fa.selectic-search-scope {\n width: calc(var(--selectic-input-height) * 0.75);\n height: calc(var(--selectic-input-height) * 0.75);\n line-height: calc(var(--selectic-input-height) * 0.75);\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/* {{{ icons */\n\n@keyframes selectic-animation-spin {\n 0% {\n transform: rotate(0deg);\n }\n 100% {\n transform: rotate(359deg);\n }\n}\n\n.selectic__icon {\n height: 1em;\n fill: currentColor;\n}\n\n.selectic-spin {\n animation: selectic-animation-spin 2s infinite linear;\n}\n\n/* }}} */\n";
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 top: var(--top-position, 0);\n z-index: 2000;\n height: auto;\n max-height: var(--availableSpace);\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 width: var(--list-width, 200px);\n min-width: 200px;\n display: grid;\n grid-template-rows: minmax(0, max-content) 1fr;\n}\n.selectic__extended-list.selectic-position-top {\n box-shadow: 2px -3px 12px 0px #888888;\n}\n.selectic__extended-list__list-container{\n overflow: auto;\n}\n.selectic__extended-list__list-items {\n max-height: calc(var(--selectic-input-height) * 10);\n min-width: max-content;\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.selectic-item__active.selectic-item__disabled:not(.selected) .selectic-item_icon {\n opacity: 0;\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__is-group.selectable {\n cursor: pointer;\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.selectic .form-control-feedback.fa.selectic-search-scope {\n width: calc(var(--selectic-input-height) * 0.75);\n height: calc(var(--selectic-input-height) * 0.75);\n line-height: calc(var(--selectic-input-height) * 0.75);\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/* {{{ icons */\n\n@keyframes selectic-animation-spin {\n 0% {\n transform: rotate(0deg);\n }\n 100% {\n transform: rotate(359deg);\n }\n}\n\n.selectic__icon {\n height: 1em;\n fill: currentColor;\n}\n\n.selectic-spin {\n animation: selectic-animation-spin 2s infinite linear;\n}\n\n/* }}} */\n";
36
36
  styleInject(css_248z);
37
37
 
38
38
  /**
@@ -138,12 +138,25 @@ function compareOptions(oldOptions, newOptions) {
138
138
  });
139
139
  });
140
140
  }
141
+ let displayLog = false;
142
+ function debug(fName, step, ...args) {
143
+ if (!displayLog) {
144
+ return;
145
+ }
146
+ console.log('--%s-- [%s]', fName, step, ...args);
147
+ }
148
+ /** Enable logs for debugging */
149
+ debug.enable = (display) => {
150
+ displayLog = display;
151
+ };
141
152
 
142
153
  /* File Purpose:
143
154
  * It keeps and computes all states at a single place.
144
155
  * Every inner components of Selectic should communicate with this file to
145
156
  * change or to get states.
146
157
  */
158
+ /* For debugging */
159
+ debug.enable(false);
147
160
  /* }}} */
148
161
  /* {{{ Static */
149
162
  function changeTexts$1(texts) {
@@ -178,12 +191,19 @@ let messages = {
178
191
  let defaultFamilyIcon = 'selectic';
179
192
  let icons = {};
180
193
  let closePreviousSelectic;
194
+ /**
195
+ * Time to wait before considering there is no other requests.
196
+ * This time is await only if there is already a requested request.
197
+ */
198
+ const DEBOUNCE_REQUEST = 250;
181
199
  /* }}} */
182
200
  let uid = 0;
183
201
  class SelecticStore {
184
202
  constructor(props = {}) {
185
203
  /* Do not need reactivity */
186
204
  this.requestId = 0;
205
+ this.requestSearchId = 0; /* Used for search request */
206
+ this.isRequesting = false;
187
207
  this._uid = ++uid;
188
208
  /* {{{ Props */
189
209
  const defaultProps = {
@@ -299,6 +319,7 @@ class SelecticStore {
299
319
  this.data.cacheItem.clear();
300
320
  this.setAutomaticClose();
301
321
  this.commit('isOpen', false);
322
+ this.clearDisplay();
302
323
  this.buildAllOptions(true);
303
324
  this.buildSelectedOptions();
304
325
  }, { deep: true });
@@ -389,6 +410,7 @@ class SelecticStore {
389
410
  /* {{{ public methods */
390
411
  commit(name, value) {
391
412
  const oldValue = this.state[name];
413
+ debug('commit', 'start', name, value, 'oldValue:', oldValue);
392
414
  if (oldValue === value) {
393
415
  return;
394
416
  }
@@ -397,8 +419,7 @@ class SelecticStore {
397
419
  case 'searchText':
398
420
  this.state.offsetItem = 0;
399
421
  this.state.activeItemIdx = -1;
400
- this.state.filteredOptions = [];
401
- this.state.totalFilteredOptions = Infinity;
422
+ this.clearDisplay();
402
423
  if (value) {
403
424
  this.buildFilteredOptions();
404
425
  }
@@ -446,6 +467,7 @@ class SelecticStore {
446
467
  }
447
468
  break;
448
469
  }
470
+ debug('commit', '(done)', name);
449
471
  }
450
472
  setAutomaticChange() {
451
473
  this.state.status.automaticChange = true;
@@ -536,25 +558,54 @@ class SelecticStore {
536
558
  if (selected === undefined) {
537
559
  selected = !isAlreadySelected;
538
560
  }
561
+ const selectedOptions = Array.isArray(state.selectedOptions)
562
+ ? state.selectedOptions
563
+ : [];
539
564
  if (id === null) {
540
- state.internalValue = [];
541
- hasChanged = internalValue.length > 0;
565
+ /* Keep disabled items: we cannot removed them because they
566
+ * are disabled */
567
+ const newSelection = selectedOptions.reduce((list, item) => {
568
+ if (item.disabled && item.id) {
569
+ list.push(item.id);
570
+ }
571
+ return list;
572
+ }, []);
573
+ state.internalValue = newSelection;
574
+ hasChanged = internalValue.length > newSelection.length;
542
575
  }
543
576
  else if (selected && !isAlreadySelected) {
577
+ let addItem = true;
544
578
  if (item === null || item === void 0 ? void 0 : item.exclusive) {
545
- /* clear the current selection because the item is exclusive */
546
- internalValue.splice(0, Infinity);
579
+ const hasDisabledSelected = selectedOptions.some((opt) => {
580
+ return opt.disabled;
581
+ });
582
+ if (hasDisabledSelected) {
583
+ /* do not remove disabled item from selection */
584
+ addItem = false;
585
+ }
586
+ else {
587
+ /* clear the current selection because the item is exclusive */
588
+ internalValue.splice(0, Infinity);
589
+ }
547
590
  }
548
591
  else if (internalValue.length === 1) {
549
592
  const selectedId = internalValue[0];
550
593
  const selectedItem = state.allOptions.find((opt) => opt.id === selectedId);
551
594
  if (selectedItem === null || selectedItem === void 0 ? void 0 : selectedItem.exclusive) {
552
- /* clear the current selection because the old item was exclusive */
553
- internalValue.pop();
595
+ if (selectedItem.disabled) {
596
+ /* If selected item is disabled and exclusive do not change the selection */
597
+ addItem = false;
598
+ }
599
+ else {
600
+ /* clear the current selection because the old item was exclusive */
601
+ internalValue.pop();
602
+ }
554
603
  }
555
604
  }
556
- internalValue.push(id);
557
- hasChanged = true;
605
+ if (addItem) {
606
+ internalValue.push(id);
607
+ hasChanged = true;
608
+ }
558
609
  }
559
610
  else if (!selected && isAlreadySelected) {
560
611
  internalValue.splice(internalValue.indexOf(id), 1);
@@ -577,6 +628,11 @@ class SelecticStore {
577
628
  if (id !== oldValue) {
578
629
  return hasChanged;
579
630
  }
631
+ const oldOption = state.selectedOptions;
632
+ if (oldOption === null || oldOption === void 0 ? void 0 : oldOption.disabled) {
633
+ /* old selection is disabled so do not unselect it */
634
+ return hasChanged;
635
+ }
580
636
  id = null;
581
637
  }
582
638
  else if (id === oldValue) {
@@ -631,14 +687,14 @@ class SelecticStore {
631
687
  this.state.status.errorMessage = '';
632
688
  }
633
689
  clearCache(forceReset = false) {
690
+ debug('clearCache', 'start', forceReset);
634
691
  const isPartial = vue.unref(this.isPartial);
635
692
  const total = isPartial ? Infinity : 0;
636
693
  this.data.cacheItem.clear();
637
694
  this.state.allOptions = [];
638
695
  this.state.totalAllOptions = total;
639
696
  this.state.totalDynOptions = total;
640
- this.state.filteredOptions = [];
641
- this.state.totalFilteredOptions = Infinity;
697
+ this.clearDisplay();
642
698
  this.state.status.errorMessage = '';
643
699
  this.state.status.hasChanged = false;
644
700
  if (forceReset) {
@@ -770,6 +826,13 @@ class SelecticStore {
770
826
  this.checkAutoSelect();
771
827
  }
772
828
  }
829
+ /** Reset the display cache in order to rebuild it */
830
+ clearDisplay() {
831
+ debug('clearDisplay', 'start');
832
+ this.state.filteredOptions = [];
833
+ this.state.totalFilteredOptions = Infinity;
834
+ }
835
+ /** rebuild the state filteredOptions to normalize their values */
773
836
  updateFilteredOptions() {
774
837
  if (!this.data.doNotUpdate) {
775
838
  this.state.filteredOptions = this.buildItems(this.state.filteredOptions);
@@ -819,7 +882,7 @@ class SelecticStore {
819
882
  });
820
883
  return listOptions;
821
884
  }
822
- /* This method is for the computed property elementOptions */
885
+ /** This method is for the computed property elementOptions */
823
886
  getElementOptions() {
824
887
  const options = deepClone(this.props.childOptions, ['data']);
825
888
  const childOptions = [];
@@ -850,7 +913,9 @@ class SelecticStore {
850
913
  });
851
914
  return childOptions;
852
915
  }
916
+ /** Generate the list of all options by combining the 3 option lists */
853
917
  buildAllOptions(keepFetched = false, stopFetch = false) {
918
+ debug('buildAllOptions', 'start', 'keepFetched', keepFetched, 'stopFetch', stopFetch);
854
919
  const allOptions = [];
855
920
  let listOptions = [];
856
921
  let elementOptions = [];
@@ -922,8 +987,6 @@ class SelecticStore {
922
987
  }
923
988
  }
924
989
  if (!stopFetch) {
925
- this.state.filteredOptions = [];
926
- this.state.totalFilteredOptions = Infinity;
927
990
  this.buildFilteredOptions().then(() => {
928
991
  /* XXX: To recompute for strict mode and auto-select */
929
992
  this.assertCorrectValue();
@@ -939,18 +1002,21 @@ class SelecticStore {
939
1002
  const options = this.filterOptions(allOptions, search);
940
1003
  this.setFilteredOptions(options);
941
1004
  }
1005
+ debug('buildAllOptions', 'end', 'allOptions:', this.state.allOptions.length, 'totalAllOptions:', this.state.totalAllOptions);
942
1006
  }
943
1007
  async buildFilteredOptions() {
944
- if (!this.state.isOpen) {
1008
+ const state = this.state;
1009
+ if (!state.isOpen) {
945
1010
  /* Do not try to fetch anything while the select is not open */
946
1011
  return;
947
1012
  }
948
- const allOptions = this.state.allOptions;
949
- const search = this.state.searchText;
950
- const totalAllOptions = this.state.totalAllOptions;
1013
+ const allOptions = state.allOptions;
1014
+ const search = state.searchText;
1015
+ const totalAllOptions = state.totalAllOptions;
951
1016
  const allOptionsLength = allOptions.length;
952
- let filteredOptionsLength = this.state.filteredOptions.length;
1017
+ let filteredOptionsLength = state.filteredOptions.length;
953
1018
  const hasAllItems = vue.unref(this.hasAllItems);
1019
+ debug('buildFilteredOptions', 'start', 'hasAllItems:', hasAllItems, 'allOptions', allOptions.length, 'search:', search, 'filteredOptionsLength:', filteredOptionsLength);
954
1020
  if (hasAllItems) {
955
1021
  /* Everything has already been fetched and stored in filteredOptions */
956
1022
  return;
@@ -967,16 +1033,17 @@ class SelecticStore {
967
1033
  return;
968
1034
  }
969
1035
  /* When we only have partial options */
970
- const offsetItem = this.state.offsetItem;
1036
+ const offsetItem = state.offsetItem;
971
1037
  const marginSize = vue.unref(this.marginSize);
972
1038
  const endIndex = offsetItem + marginSize;
1039
+ debug('buildFilteredOptions', 'partial options', 'offsetItem:', offsetItem, 'marginSize:', marginSize, 'filteredOptionsLength', filteredOptionsLength);
973
1040
  if (endIndex <= filteredOptionsLength) {
974
1041
  return;
975
1042
  }
976
1043
  if (!search && endIndex <= allOptionsLength) {
977
- this.setFilteredOptions(this.buildGroupItems(allOptions), false, totalAllOptions + this.state.groups.size);
1044
+ this.setFilteredOptions(this.buildGroupItems(allOptions), false, totalAllOptions + state.groups.size);
978
1045
  const isPartial = vue.unref(this.isPartial);
979
- if (isPartial && this.state.totalDynOptions === Infinity) {
1046
+ if (isPartial && state.totalDynOptions === Infinity) {
980
1047
  this.fetchData();
981
1048
  }
982
1049
  return;
@@ -989,6 +1056,7 @@ class SelecticStore {
989
1056
  return;
990
1057
  }
991
1058
  }
1059
+ debug('buildFilteredOptions', 'end', '(will call fetchData)', this.state.filteredOptions.length);
992
1060
  await this.fetchData();
993
1061
  }
994
1062
  async buildSelectedOptions() {
@@ -1042,6 +1110,39 @@ class SelecticStore {
1042
1110
  state.selectedOptions = items[0];
1043
1111
  }
1044
1112
  }
1113
+ async fetchRequest(fetchCallback, search, offset, limit) {
1114
+ const searchRqId = ++this.requestSearchId;
1115
+ if (!search) {
1116
+ ++this.requestId;
1117
+ }
1118
+ const requestId = this.requestId;
1119
+ debug('fetchRequest', 'start', 'search:', search, 'offset:', offset, 'limit:', limit, 'requestId:', requestId, 'requestSearchId:', searchRqId, 'isRequesting:', this.isRequesting);
1120
+ if (this.isRequesting) {
1121
+ debug('fetchRequest', `await ${DEBOUNCE_REQUEST}ms`);
1122
+ /* debounce the call to avoid sending too much requests */
1123
+ await new Promise((resolve) => {
1124
+ setTimeout(resolve, DEBOUNCE_REQUEST);
1125
+ });
1126
+ /* Check if there are other requested requests, in such case drop this one */
1127
+ if (requestId !== this.requestId || (search && searchRqId !== this.requestSearchId)) {
1128
+ debug('fetchRequest', '××deprecated××', requestId, searchRqId);
1129
+ return false;
1130
+ }
1131
+ }
1132
+ this.isRequesting = true;
1133
+ const response = await fetchCallback(search, offset, limit);
1134
+ /* Check if request is obsolete */
1135
+ if (requestId !== this.requestId || (search && searchRqId !== this.requestSearchId)) {
1136
+ debug('fetchRequest', '×××deprecated×××', requestId, searchRqId);
1137
+ return false;
1138
+ }
1139
+ this.isRequesting = false;
1140
+ const deprecated = searchRqId !== this.requestSearchId;
1141
+ debug('fetchRequest', 'end', response.result.length, response.total, deprecated);
1142
+ return Object.assign(Object.assign({}, response), {
1143
+ /* this is to fulfill the cache */
1144
+ deprecated: deprecated });
1145
+ }
1045
1146
  async fetchData() {
1046
1147
  const state = this.state;
1047
1148
  const labels = this.data.labels;
@@ -1063,9 +1164,14 @@ class SelecticStore {
1063
1164
  const offset = filteredOptionsLength - this.nbGroups(state.filteredOptions) - dynOffset;
1064
1165
  const nbItems = endIndex - offset;
1065
1166
  const limit = Math.ceil(nbItems / pageSize) * pageSize;
1167
+ debug('fetchData', 'start', 'search:', search, 'offset:', offset, 'limit:', limit);
1066
1168
  try {
1067
- const requestId = ++this.requestId;
1068
- const { total: rTotal, result } = await fetchCallback(search, offset, limit);
1169
+ const response = await this.fetchRequest(fetchCallback, search, offset, limit);
1170
+ if (!response) {
1171
+ debug('fetchData', '×× deprecated ××', search, offset, limit);
1172
+ return;
1173
+ }
1174
+ const { total: rTotal, result, deprecated } = response;
1069
1175
  let total = rTotal;
1070
1176
  let errorMessage = '';
1071
1177
  /* Assert result is correctly formatted */
@@ -1083,11 +1189,12 @@ class SelecticStore {
1083
1189
  if (!search) {
1084
1190
  /* update cache */
1085
1191
  state.totalDynOptions = total;
1086
- const old = state.dynOptions.splice(offset, limit, ...result);
1192
+ const old = state.dynOptions.splice(offset, result.length, ...result);
1087
1193
  if (compareOptions(old, result)) {
1088
1194
  /* Added options are the same as previous ones.
1089
1195
  * Stop fetching to avoid infinite loop
1090
1196
  */
1197
+ debug('fetchData', 'no new values');
1091
1198
  if (!vue.unref(this.hasFetchedAllItems)) {
1092
1199
  /* Display error if all items are not fetch
1093
1200
  * We can have the case where old value and result
@@ -1095,14 +1202,21 @@ class SelecticStore {
1095
1202
  * total is 0 */
1096
1203
  errorMessage = labels.wrongQueryResult;
1097
1204
  }
1098
- setTimeout(() => this.buildAllOptions(true, true), 0);
1205
+ setTimeout(() => {
1206
+ debug('fetchData', 'before buildAllOptions (stopped)', 'offsetItem:', this.state.offsetItem, 'allOptions:', this.state.allOptions.length);
1207
+ this.buildAllOptions(true, true);
1208
+ }, 0);
1099
1209
  }
1100
1210
  else {
1101
- setTimeout(() => this.buildAllOptions(true), 0);
1211
+ setTimeout(() => {
1212
+ debug('fetchData', 'before buildAllOptions', 'offsetItem:', this.state.offsetItem, 'allOptions:', this.state.allOptions.length);
1213
+ this.buildAllOptions(true);
1214
+ }, 0);
1102
1215
  }
1103
1216
  }
1104
- /* Check request is not obsolete */
1105
- if (requestId !== this.requestId) {
1217
+ /* Check request (without search) is not obsolete */
1218
+ if (deprecated) {
1219
+ debug('fetchData', '××× deprecated ×××', search, offset, limit);
1106
1220
  return;
1107
1221
  }
1108
1222
  if (!search) {
@@ -1131,14 +1245,17 @@ class SelecticStore {
1131
1245
  }
1132
1246
  catch (e) {
1133
1247
  state.status.errorMessage = e.message;
1248
+ debug('fetchData', 'error', e.message);
1134
1249
  if (!search) {
1135
1250
  state.totalDynOptions = 0;
1136
1251
  this.buildAllOptions(true, true);
1137
1252
  }
1138
1253
  }
1139
1254
  this.state.status.searching = false;
1255
+ debug('fetchData', 'end');
1140
1256
  }
1141
1257
  filterOptions(options, search) {
1258
+ debug('filterOptions', 'start', 'options:', options.length, 'search:', search);
1142
1259
  if (!search) {
1143
1260
  return this.buildGroupItems(options);
1144
1261
  }
@@ -1149,6 +1266,7 @@ class SelecticStore {
1149
1266
  addStaticFilteredOptions(fromDynamic = false) {
1150
1267
  const search = this.state.searchText;
1151
1268
  let continueLoop = fromDynamic;
1269
+ debug('addStaticFilteredOptions', 'start', 'fromDynamic:', fromDynamic, 'optionBehaviorOperation:', this.state.optionBehaviorOperation);
1152
1270
  if (this.state.optionBehaviorOperation !== 'sort') {
1153
1271
  return;
1154
1272
  }
@@ -1174,6 +1292,7 @@ class SelecticStore {
1174
1292
  }
1175
1293
  this.setFilteredOptions(options, true);
1176
1294
  }
1295
+ debug('addStaticFilteredOptions', 'end');
1177
1296
  }
1178
1297
  buildSelectedItems(ids) {
1179
1298
  return this.buildItems(ids.map((id) => {
@@ -1215,6 +1334,7 @@ class SelecticStore {
1215
1334
  }
1216
1335
  buildGroupItems(options, previousItem) {
1217
1336
  let previousGroupId = previousItem && previousItem.group;
1337
+ debug('buildGroupItems', 'start', 'options:', options.length, 'previousGroupId:', previousGroupId);
1218
1338
  const list = this.buildItems(options).reduce((items, item) => {
1219
1339
  if (item.group !== previousGroupId) {
1220
1340
  const groupId = item.group;
@@ -1231,6 +1351,7 @@ class SelecticStore {
1231
1351
  items.push(item);
1232
1352
  return items;
1233
1353
  }, []);
1354
+ debug('buildGroupItems', 'end', list.length);
1234
1355
  return list;
1235
1356
  }
1236
1357
  buildOptionBehavior(optionBehavior, state) {
@@ -1281,15 +1402,23 @@ class SelecticStore {
1281
1402
  if (doNotCheck || !hasFetchedAllItems) {
1282
1403
  return;
1283
1404
  }
1405
+ const selectedOptions = state.selectedOptions;
1284
1406
  const enabledOptions = state.allOptions.filter((opt) => !opt.disabled);
1285
- const nb = enabledOptions.length;
1407
+ const nbEnabled = enabledOptions.length;
1286
1408
  const value = state.internalValue;
1287
1409
  const hasValue = Array.isArray(value) ? value.length > 0 : value !== null;
1288
- const hasValidValue = hasValue && (Array.isArray(value) ? value.every((val) => this.hasValue(val)) :
1410
+ const hasDisabledSelected = Array.isArray(selectedOptions)
1411
+ ? selectedOptions.some((opt) => opt.disabled)
1412
+ : false;
1413
+ const hasOnlyValidValue = hasValue && !hasDisabledSelected && (Array.isArray(value) ? value.every((val) => this.hasValue(val)) :
1289
1414
  this.hasValue(value));
1290
- const isEmpty = nb === 0;
1291
- const hasOnlyOneOption = nb === 1 && hasValidValue && !state.allowClearSelection;
1292
- if (hasOnlyOneOption || isEmpty) {
1415
+ const isEmpty = nbEnabled === 0;
1416
+ const hasOnlyOneOption = nbEnabled === 1 && hasOnlyValidValue && !state.allowClearSelection;
1417
+ const isExclusiveDisabledItem = Array.isArray(selectedOptions) /* which means "multiple" mode */
1418
+ && selectedOptions.length === 1
1419
+ && selectedOptions[0].exclusive
1420
+ && selectedOptions[0].disabled;
1421
+ if (hasOnlyOneOption || isEmpty || isExclusiveDisabledItem) {
1293
1422
  if (state.isOpen) {
1294
1423
  this.setAutomaticClose();
1295
1424
  this.commit('isOpen', false);
@@ -1348,6 +1477,7 @@ class SelecticStore {
1348
1477
  }
1349
1478
  /** assign new value to the filteredOptions and apply change depending on it */
1350
1479
  setFilteredOptions(options, add = false, length = 0) {
1480
+ debug('setFilteredOptions', 'start', 'options:', options.length, 'add', add, 'length', length);
1351
1481
  if (!add) {
1352
1482
  this.state.filteredOptions = options;
1353
1483
  this.state.totalFilteredOptions = length || options.length;
@@ -1708,6 +1838,18 @@ let MainInput = class MainInput extends vtyx.Vue {
1708
1838
  ? Array.isArray(value) && value.length > 0
1709
1839
  : value !== null;
1710
1840
  }
1841
+ get disabledList() {
1842
+ const state = this.store.state;
1843
+ const isMultiple = state.multiple;
1844
+ const value = state.selectedOptions;
1845
+ if (!isMultiple || !value) {
1846
+ return [];
1847
+ }
1848
+ const disabledValues = value.filter((option) => {
1849
+ return option.disabled;
1850
+ });
1851
+ return disabledValues;
1852
+ }
1711
1853
  get displayPlaceholder() {
1712
1854
  const placeholder = this.store.state.placeholder;
1713
1855
  const hasValue = this.hasValue;
@@ -1726,10 +1868,12 @@ let MainInput = class MainInput extends vtyx.Vue {
1726
1868
  const state = this.store.state;
1727
1869
  const isMultiple = state.multiple;
1728
1870
  const value = state.internalValue;
1729
- const hasOnlyOneValue = Array.isArray(value) && value.length === 1;
1871
+ const nbSelection = (Array.isArray(value) && value.length) || 0;
1872
+ const hasOnlyOneValue = nbSelection === 1;
1873
+ const hasOnlyDisabled = nbSelection <= this.disabledList.length;
1730
1874
  /* Should not display the clear action if there is only one selected
1731
1875
  * item in multiple (as this item has already its remove icon) */
1732
- return !isMultiple || !hasOnlyOneValue;
1876
+ return !isMultiple || !hasOnlyOneValue || !hasOnlyDisabled;
1733
1877
  }
1734
1878
  get clearedLabel() {
1735
1879
  const isMultiple = this.store.state.multiple;
@@ -1847,6 +1991,9 @@ let MainInput = class MainInput extends vtyx.Vue {
1847
1991
  /* Check if there is enough space to display items like there are
1848
1992
  * currently shown */
1849
1993
  const el = this.$refs.selectedItems;
1994
+ if (!el) {
1995
+ return;
1996
+ }
1850
1997
  const parentEl = el.parentElement;
1851
1998
  if (!document.contains(parentEl)) {
1852
1999
  /* The element is currently not in DOM */
@@ -1945,7 +2092,7 @@ let MainInput = class MainInput extends vtyx.Vue {
1945
2092
  click: () => this.$emit('item:click', item.id),
1946
2093
  } },
1947
2094
  vtyx.h("span", { class: "selectic-input__selected-items__value" }, item.text),
1948
- !this.isDisabled && (vtyx.h(Icon$1, { icon: "times", class: "selectic-input__selected-items__icon", store: this.store, on: {
2095
+ !this.isDisabled && !item.disabled && (vtyx.h(Icon$1, { icon: "times", class: "selectic-input__selected-items__icon", store: this.store, on: {
1949
2096
  'click.prevent.stop': () => this.selectItem(item.id),
1950
2097
  } }))))),
1951
2098
  this.moreSelectedNb && (vtyx.h("div", { class: "single-value more-items", title: this.moreSelectedTitle }, this.moreSelectedNb)))),
@@ -2699,7 +2846,8 @@ let Selectic = class Selectic extends vtyx.Vue {
2699
2846
  const store = this.store;
2700
2847
  const keepOpenWithOtherSelectic = this.params.keepOpenWithOtherSelectic;
2701
2848
  const extendedList = this.$refs.extendedList;
2702
- if (!extendedList) {
2849
+ const extendedListEl = extendedList === null || extendedList === void 0 ? void 0 : extendedList.$el;
2850
+ if (!extendedListEl) {
2703
2851
  /* this component is not focused anymore */
2704
2852
  if (!keepOpenWithOtherSelectic) {
2705
2853
  this.removeListeners();
@@ -2708,7 +2856,7 @@ let Selectic = class Selectic extends vtyx.Vue {
2708
2856
  return;
2709
2857
  }
2710
2858
  const target = evt.target;
2711
- if (!extendedList.$el.contains(target) && !this.$el.contains(target)) {
2859
+ if (!extendedListEl.contains(target) && !this.$el.contains(target)) {
2712
2860
  store.commit('isOpen', false);
2713
2861
  }
2714
2862
  };
@@ -2801,14 +2949,23 @@ let Selectic = class Selectic extends vtyx.Vue {
2801
2949
  /* }}} */
2802
2950
  /* {{{ private methods */
2803
2951
  computeWidth() {
2804
- const el = this.$refs.mainInput.$el;
2805
- this.width = el.offsetWidth;
2952
+ var _a;
2953
+ const mainInput = (_a = this.$refs) === null || _a === void 0 ? void 0 : _a.mainInput;
2954
+ const mainEl = mainInput === null || mainInput === void 0 ? void 0 : mainInput.$el;
2955
+ if (!mainEl) {
2956
+ /* This method has been called too soon (before render function)
2957
+ * or too late (after unmount) */
2958
+ return;
2959
+ }
2960
+ this.width = mainEl.offsetWidth;
2806
2961
  }
2807
2962
  computeOffset(doNotAddListener = false) {
2808
- const mainInput = this.$refs.mainInput;
2963
+ var _a;
2964
+ const mainInput = (_a = this.$refs) === null || _a === void 0 ? void 0 : _a.mainInput;
2809
2965
  const mainEl = mainInput === null || mainInput === void 0 ? void 0 : mainInput.$el;
2810
2966
  if (!mainEl) {
2811
- /* This method has been called too soon (before render function) */
2967
+ /* This method has been called too soon (before render function)
2968
+ * or too late (after unmount) */
2812
2969
  return;
2813
2970
  }
2814
2971
  const _elementsListeners = this._elementsListeners;
@@ -2942,13 +3099,14 @@ let Selectic = class Selectic extends vtyx.Vue {
2942
3099
  checkFocus() {
2943
3100
  /* Await that focused element becomes active */
2944
3101
  setTimeout(() => {
3102
+ var _a;
2945
3103
  const focusedEl = document.activeElement;
2946
- const extendedList = this.$refs.extendedList;
3104
+ const extendedList = (_a = this.$refs) === null || _a === void 0 ? void 0 : _a.extendedList;
2947
3105
  /* check if there is a focused element (if none the body is
2948
3106
  * selected) and if it is inside current Selectic */
2949
3107
  if (focusedEl === document.body
2950
3108
  || this.$el.contains(focusedEl)
2951
- || (extendedList && extendedList.$el.contains(focusedEl))) {
3109
+ || (extendedList === null || extendedList === void 0 ? void 0 : extendedList.$el.contains(focusedEl))) {
2952
3110
  return;
2953
3111
  }
2954
3112
  this.store.commit('isOpen', false);