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 +0 -10
- package/dist/selectic.common.js +205 -47
- package/dist/selectic.esm.js +205 -47
- package/doc/breakingChanges.md +8 -0
- package/doc/changeIcons.md +8 -2
- package/doc/list.md +2 -1
- package/package.json +2 -1
- package/src/ExtendedList.tsx +5 -5
- package/src/Icon.tsx +2 -2
- package/src/List.tsx +0 -4
- package/src/MainInput.tsx +27 -4
- package/src/Store.tsx +225 -38
- package/src/css/selectic.css +3 -0
- package/src/index.tsx +23 -12
- package/src/tools.ts +13 -0
- package/test/Store/Store_creation.spec.js +86 -12
- package/test/Store/Store_props.spec.js +612 -595
- package/test/Store/changeIcons.spec.js +1 -1
- package/test/Store/commit.spec.js +56 -47
- package/test/Store/selectGroup.spec.js +278 -271
- package/test/Store/selectItem.spec.js +108 -22
- package/test/Store/toggleSelectAll.spec.js +6 -1
- package/test/helper.js +4 -0
- package/test/tools.js +5 -1
- package/types/ExtendedList.d.ts +5 -5
- package/types/List.d.ts +0 -3
- package/types/MainInput.d.ts +2 -1
- package/types/Store.d.ts +15 -2
- package/types/index.d.ts +3 -3
- package/types/tools.d.ts +4 -0
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.
|
package/dist/selectic.common.js
CHANGED
|
@@ -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.
|
|
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
|
-
|
|
541
|
-
|
|
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
|
-
|
|
546
|
-
|
|
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
|
-
|
|
553
|
-
|
|
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
|
-
|
|
557
|
-
|
|
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.
|
|
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
|
-
|
|
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
|
-
|
|
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 =
|
|
949
|
-
const search =
|
|
950
|
-
const 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 =
|
|
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 =
|
|
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 +
|
|
1044
|
+
this.setFilteredOptions(this.buildGroupItems(allOptions), false, totalAllOptions + state.groups.size);
|
|
978
1045
|
const isPartial = vue.unref(this.isPartial);
|
|
979
|
-
if (isPartial &&
|
|
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
|
|
1068
|
-
|
|
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,
|
|
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(() =>
|
|
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(() =>
|
|
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 (
|
|
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
|
|
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
|
|
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 =
|
|
1291
|
-
const hasOnlyOneOption =
|
|
1292
|
-
|
|
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
|
|
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
|
-
|
|
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 (!
|
|
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
|
-
|
|
2805
|
-
|
|
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
|
-
|
|
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
|
|
3109
|
+
|| (extendedList === null || extendedList === void 0 ? void 0 : extendedList.$el.contains(focusedEl))) {
|
|
2952
3110
|
return;
|
|
2953
3111
|
}
|
|
2954
3112
|
this.store.commit('isOpen', false);
|