selectic 3.1.2 → 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/dist/selectic.common.js +95 -25
- package/dist/selectic.esm.js +95 -25
- package/doc/list.md +2 -1
- package/package.json +2 -1
- package/src/MainInput.tsx +27 -4
- package/src/Store.tsx +64 -13
- package/src/css/selectic.css +3 -0
- package/src/index.tsx +21 -10
- package/test/Store/Store_creation.spec.js +74 -0
- package/test/Store/selectItem.spec.js +108 -22
- package/types/MainInput.d.ts +2 -1
- package/types/index.d.ts +1 -1
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
|
/**
|
|
@@ -558,25 +558,54 @@ class SelecticStore {
|
|
|
558
558
|
if (selected === undefined) {
|
|
559
559
|
selected = !isAlreadySelected;
|
|
560
560
|
}
|
|
561
|
+
const selectedOptions = Array.isArray(state.selectedOptions)
|
|
562
|
+
? state.selectedOptions
|
|
563
|
+
: [];
|
|
561
564
|
if (id === null) {
|
|
562
|
-
|
|
563
|
-
|
|
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;
|
|
564
575
|
}
|
|
565
576
|
else if (selected && !isAlreadySelected) {
|
|
577
|
+
let addItem = true;
|
|
566
578
|
if (item === null || item === void 0 ? void 0 : item.exclusive) {
|
|
567
|
-
|
|
568
|
-
|
|
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
|
+
}
|
|
569
590
|
}
|
|
570
591
|
else if (internalValue.length === 1) {
|
|
571
592
|
const selectedId = internalValue[0];
|
|
572
593
|
const selectedItem = state.allOptions.find((opt) => opt.id === selectedId);
|
|
573
594
|
if (selectedItem === null || selectedItem === void 0 ? void 0 : selectedItem.exclusive) {
|
|
574
|
-
|
|
575
|
-
|
|
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
|
+
}
|
|
576
603
|
}
|
|
577
604
|
}
|
|
578
|
-
|
|
579
|
-
|
|
605
|
+
if (addItem) {
|
|
606
|
+
internalValue.push(id);
|
|
607
|
+
hasChanged = true;
|
|
608
|
+
}
|
|
580
609
|
}
|
|
581
610
|
else if (!selected && isAlreadySelected) {
|
|
582
611
|
internalValue.splice(internalValue.indexOf(id), 1);
|
|
@@ -599,6 +628,11 @@ class SelecticStore {
|
|
|
599
628
|
if (id !== oldValue) {
|
|
600
629
|
return hasChanged;
|
|
601
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
|
+
}
|
|
602
636
|
id = null;
|
|
603
637
|
}
|
|
604
638
|
else if (id === oldValue) {
|
|
@@ -1368,15 +1402,23 @@ class SelecticStore {
|
|
|
1368
1402
|
if (doNotCheck || !hasFetchedAllItems) {
|
|
1369
1403
|
return;
|
|
1370
1404
|
}
|
|
1405
|
+
const selectedOptions = state.selectedOptions;
|
|
1371
1406
|
const enabledOptions = state.allOptions.filter((opt) => !opt.disabled);
|
|
1372
|
-
const
|
|
1407
|
+
const nbEnabled = enabledOptions.length;
|
|
1373
1408
|
const value = state.internalValue;
|
|
1374
1409
|
const hasValue = Array.isArray(value) ? value.length > 0 : value !== null;
|
|
1375
|
-
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)) :
|
|
1376
1414
|
this.hasValue(value));
|
|
1377
|
-
const isEmpty =
|
|
1378
|
-
const hasOnlyOneOption =
|
|
1379
|
-
|
|
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) {
|
|
1380
1422
|
if (state.isOpen) {
|
|
1381
1423
|
this.setAutomaticClose();
|
|
1382
1424
|
this.commit('isOpen', false);
|
|
@@ -1796,6 +1838,18 @@ let MainInput = class MainInput extends vtyx.Vue {
|
|
|
1796
1838
|
? Array.isArray(value) && value.length > 0
|
|
1797
1839
|
: value !== null;
|
|
1798
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
|
+
}
|
|
1799
1853
|
get displayPlaceholder() {
|
|
1800
1854
|
const placeholder = this.store.state.placeholder;
|
|
1801
1855
|
const hasValue = this.hasValue;
|
|
@@ -1814,10 +1868,12 @@ let MainInput = class MainInput extends vtyx.Vue {
|
|
|
1814
1868
|
const state = this.store.state;
|
|
1815
1869
|
const isMultiple = state.multiple;
|
|
1816
1870
|
const value = state.internalValue;
|
|
1817
|
-
const
|
|
1871
|
+
const nbSelection = (Array.isArray(value) && value.length) || 0;
|
|
1872
|
+
const hasOnlyOneValue = nbSelection === 1;
|
|
1873
|
+
const hasOnlyDisabled = nbSelection <= this.disabledList.length;
|
|
1818
1874
|
/* Should not display the clear action if there is only one selected
|
|
1819
1875
|
* item in multiple (as this item has already its remove icon) */
|
|
1820
|
-
return !isMultiple || !hasOnlyOneValue;
|
|
1876
|
+
return !isMultiple || !hasOnlyOneValue || !hasOnlyDisabled;
|
|
1821
1877
|
}
|
|
1822
1878
|
get clearedLabel() {
|
|
1823
1879
|
const isMultiple = this.store.state.multiple;
|
|
@@ -1935,6 +1991,9 @@ let MainInput = class MainInput extends vtyx.Vue {
|
|
|
1935
1991
|
/* Check if there is enough space to display items like there are
|
|
1936
1992
|
* currently shown */
|
|
1937
1993
|
const el = this.$refs.selectedItems;
|
|
1994
|
+
if (!el) {
|
|
1995
|
+
return;
|
|
1996
|
+
}
|
|
1938
1997
|
const parentEl = el.parentElement;
|
|
1939
1998
|
if (!document.contains(parentEl)) {
|
|
1940
1999
|
/* The element is currently not in DOM */
|
|
@@ -2033,7 +2092,7 @@ let MainInput = class MainInput extends vtyx.Vue {
|
|
|
2033
2092
|
click: () => this.$emit('item:click', item.id),
|
|
2034
2093
|
} },
|
|
2035
2094
|
vtyx.h("span", { class: "selectic-input__selected-items__value" }, item.text),
|
|
2036
|
-
!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: {
|
|
2037
2096
|
'click.prevent.stop': () => this.selectItem(item.id),
|
|
2038
2097
|
} }))))),
|
|
2039
2098
|
this.moreSelectedNb && (vtyx.h("div", { class: "single-value more-items", title: this.moreSelectedTitle }, this.moreSelectedNb)))),
|
|
@@ -2787,7 +2846,8 @@ let Selectic = class Selectic extends vtyx.Vue {
|
|
|
2787
2846
|
const store = this.store;
|
|
2788
2847
|
const keepOpenWithOtherSelectic = this.params.keepOpenWithOtherSelectic;
|
|
2789
2848
|
const extendedList = this.$refs.extendedList;
|
|
2790
|
-
|
|
2849
|
+
const extendedListEl = extendedList === null || extendedList === void 0 ? void 0 : extendedList.$el;
|
|
2850
|
+
if (!extendedListEl) {
|
|
2791
2851
|
/* this component is not focused anymore */
|
|
2792
2852
|
if (!keepOpenWithOtherSelectic) {
|
|
2793
2853
|
this.removeListeners();
|
|
@@ -2796,7 +2856,7 @@ let Selectic = class Selectic extends vtyx.Vue {
|
|
|
2796
2856
|
return;
|
|
2797
2857
|
}
|
|
2798
2858
|
const target = evt.target;
|
|
2799
|
-
if (!
|
|
2859
|
+
if (!extendedListEl.contains(target) && !this.$el.contains(target)) {
|
|
2800
2860
|
store.commit('isOpen', false);
|
|
2801
2861
|
}
|
|
2802
2862
|
};
|
|
@@ -2889,14 +2949,23 @@ let Selectic = class Selectic extends vtyx.Vue {
|
|
|
2889
2949
|
/* }}} */
|
|
2890
2950
|
/* {{{ private methods */
|
|
2891
2951
|
computeWidth() {
|
|
2892
|
-
|
|
2893
|
-
|
|
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;
|
|
2894
2961
|
}
|
|
2895
2962
|
computeOffset(doNotAddListener = false) {
|
|
2896
|
-
|
|
2963
|
+
var _a;
|
|
2964
|
+
const mainInput = (_a = this.$refs) === null || _a === void 0 ? void 0 : _a.mainInput;
|
|
2897
2965
|
const mainEl = mainInput === null || mainInput === void 0 ? void 0 : mainInput.$el;
|
|
2898
2966
|
if (!mainEl) {
|
|
2899
|
-
/* 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) */
|
|
2900
2969
|
return;
|
|
2901
2970
|
}
|
|
2902
2971
|
const _elementsListeners = this._elementsListeners;
|
|
@@ -3030,13 +3099,14 @@ let Selectic = class Selectic extends vtyx.Vue {
|
|
|
3030
3099
|
checkFocus() {
|
|
3031
3100
|
/* Await that focused element becomes active */
|
|
3032
3101
|
setTimeout(() => {
|
|
3102
|
+
var _a;
|
|
3033
3103
|
const focusedEl = document.activeElement;
|
|
3034
|
-
const extendedList = this.$refs.extendedList;
|
|
3104
|
+
const extendedList = (_a = this.$refs) === null || _a === void 0 ? void 0 : _a.extendedList;
|
|
3035
3105
|
/* check if there is a focused element (if none the body is
|
|
3036
3106
|
* selected) and if it is inside current Selectic */
|
|
3037
3107
|
if (focusedEl === document.body
|
|
3038
3108
|
|| this.$el.contains(focusedEl)
|
|
3039
|
-
|| (extendedList
|
|
3109
|
+
|| (extendedList === null || extendedList === void 0 ? void 0 : extendedList.$el.contains(focusedEl))) {
|
|
3040
3110
|
return;
|
|
3041
3111
|
}
|
|
3042
3112
|
this.store.commit('isOpen', false);
|
package/dist/selectic.esm.js
CHANGED
|
@@ -28,7 +28,7 @@ function styleInject(css, ref) {
|
|
|
28
28
|
}
|
|
29
29
|
}
|
|
30
30
|
|
|
31
|
-
var css_248z = "/* {{{ Variables */\n\n:root {\n --selectic-font-size: 14px;\n --selectic-cursor-disabled: not-allowed;\n\n /* The main element */\n --selectic-color: #555555;\n --selectic-bg: #ffffff;\n\n /* The main element (when disabled) */\n --selectic-color-disabled: #787878;\n --selectic-bg-disabled: #eeeeee;\n\n /* The list */\n --selectic-panel-bg: #f0f0f0;\n --selectic-separator-bordercolor: #cccccc;\n /* --selectic-item-color: var(--selectic-color); /* Can be set in any CSS configuration */\n\n /* The current selected item */\n --selectic-selected-item-color: #428bca;\n\n /* When mouse is over items or by selecting with key arrows */\n --selectic-active-item-color: #ffffff;\n --selectic-active-item-bg: #66afe9;\n\n /* Selected values in main element */\n --selectic-value-bg: #f0f0f0;\n /* --selectic-more-items-bg: var(--selectic-info-bg); /* can be set in any CSS configuration */\n /* --selectic-more-items-color: var(--selectic-info-color); /* can be set in any CSS configuration */\n --selectic-more-items-bg-disabled: #cccccc;\n\n /* Information message */\n --selectic-info-bg: #5bc0de;\n --selectic-info-color: #ffffff;\n\n /* Error message */\n --selectic-error-bg: #b72c29;\n --selectic-error-color: #ffffff;\n\n /* XXX: Currently it is important to keep this size for a correct scroll\n * height estimation */\n --selectic-input-height: 30px;\n}\n\n/* }}} */\n/* {{{ Bootstrap equivalent style */\n\n.selectic .form-control {\n display: block;\n width: 100%;\n height: calc(var(--selectic-input-height) - 2px);\n font-size: var(--selectic-font-size);\n line-height: 1.42857143;\n color: var(--selectic-color);\n background-color: var(--selectic-bg);\n background-image: none;\n border: 1px solid var(--selectic-separator-bordercolor); /* should use a better variable */\n border-radius: 4px;\n box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);\n transition: border-color ease-in-out 0.15s, box-shadow ease-in-out 0.15s;\n}\n.selectic .has-feedback {\n position: relative;\n}\n.selectic .has-feedback .form-control {\n padding-right: calc(var(--selectic-input-height) + 4px);\n}\n\n.selectic .form-control-feedback.fa,\n.selectic .form-control-feedback {\n position: absolute;\n top: 0;\n right: 0;\n z-index: 2;\n display: block;\n width: calc(var(--selectic-input-height) + 4px);\n height: calc(var(--selectic-input-height) + 4px);\n line-height: var(--selectic-input-height);\n text-align: center;\n pointer-events: none;\n}\n\n.selectic .alert-info {\n background-color: var(--selectic-info-bg);\n color: var(--selectic-info-color);\n}\n\n.selectic .alert-danger {\n background-color: var(--selectic-error-bg);\n color: var(--selectic-error-color);\n}\n\n/* }}} */\n\n.selectic * {\n -webkit-box-sizing: border-box;\n -moz-box-sizing: border-box;\n box-sizing: border-box;\n}\n\n.selectic.form-control {\n display: inline-block;\n padding: 0;\n cursor: pointer;\n border: unset;\n}\n\n.has-feedback .selectic__icon-container.form-control-feedback {\n right: 0;\n}\n\n/* The input which contains the selected value\n * XXX: This input should stay hidden behind other elements, but is \"visible\"\n * (in term of DOM point of view) in order to get and to trigger the `focus`\n * DOM event. */\n.selectic__input-value {\n position: fixed;\n opacity: 0;\n z-index: -1000;\n top: -100px;\n}\n\n/* XXX: .form-control has been added to this selector to improve priority and\n * override some rules of the original .form-control */\n.selectic-input.form-control {\n display: inline-flex;\n justify-content: space-between;\n overflow: hidden;\n width: 100%;\n min-height: var(--selectic-input-height);\n padding-top: 0;\n padding-bottom: 0;\n padding-left: 5px;\n line-height: calc(var(--selectic-input-height) - 4px);\n color: var(--selectic-color);\n}\n\n.selectic-input__reverse-icon {\n align-self: center;\n margin-right: 3px;\n cursor: default;\n}\n.selectic-input__clear-icon {\n align-self: center;\n margin-left: 3px;\n cursor: pointer;\n}\n.selectic-input__clear-icon:hover {\n color: var(--selectic-selected-item-color);\n}\n\n.selectic-input.focused {\n border-bottom-left-radius: 0px;\n border-bottom-right-radius: 0px;\n}\n\n.selectic-input.disabled {\n cursor: var(--selectic-cursor-disabled);\n background-color: var(--selectic-bg-disabled);\n}\n.selectic-input.disabled .more-items {\n\tbackground-color: var(--selectic-more-items-bg-disabled);\n}\n\n.selectic-input__selected-items {\n display: inline-flex;\n flex-wrap: nowrap;\n align-items: center;\n white-space: nowrap;\n}\n\n.selectic-input__selected-items__placeholder {\n font-style: italic;\n opacity: 0.7;\n white-space: nowrap;\n}\n\n.selectic-icon {\n color: var(--selectic-color);\n text-align: center;\n vertical-align: middle;\n}\n\n.selectic__extended-list {\n position: fixed;\n 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";
|
|
31
|
+
var css_248z = "/* {{{ Variables */\n\n:root {\n --selectic-font-size: 14px;\n --selectic-cursor-disabled: not-allowed;\n\n /* The main element */\n --selectic-color: #555555;\n --selectic-bg: #ffffff;\n\n /* The main element (when disabled) */\n --selectic-color-disabled: #787878;\n --selectic-bg-disabled: #eeeeee;\n\n /* The list */\n --selectic-panel-bg: #f0f0f0;\n --selectic-separator-bordercolor: #cccccc;\n /* --selectic-item-color: var(--selectic-color); /* Can be set in any CSS configuration */\n\n /* The current selected item */\n --selectic-selected-item-color: #428bca;\n\n /* When mouse is over items or by selecting with key arrows */\n --selectic-active-item-color: #ffffff;\n --selectic-active-item-bg: #66afe9;\n\n /* Selected values in main element */\n --selectic-value-bg: #f0f0f0;\n /* --selectic-more-items-bg: var(--selectic-info-bg); /* can be set in any CSS configuration */\n /* --selectic-more-items-color: var(--selectic-info-color); /* can be set in any CSS configuration */\n --selectic-more-items-bg-disabled: #cccccc;\n\n /* Information message */\n --selectic-info-bg: #5bc0de;\n --selectic-info-color: #ffffff;\n\n /* Error message */\n --selectic-error-bg: #b72c29;\n --selectic-error-color: #ffffff;\n\n /* XXX: Currently it is important to keep this size for a correct scroll\n * height estimation */\n --selectic-input-height: 30px;\n}\n\n/* }}} */\n/* {{{ Bootstrap equivalent style */\n\n.selectic .form-control {\n display: block;\n width: 100%;\n height: calc(var(--selectic-input-height) - 2px);\n font-size: var(--selectic-font-size);\n line-height: 1.42857143;\n color: var(--selectic-color);\n background-color: var(--selectic-bg);\n background-image: none;\n border: 1px solid var(--selectic-separator-bordercolor); /* should use a better variable */\n border-radius: 4px;\n box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);\n transition: border-color ease-in-out 0.15s, box-shadow ease-in-out 0.15s;\n}\n.selectic .has-feedback {\n position: relative;\n}\n.selectic .has-feedback .form-control {\n padding-right: calc(var(--selectic-input-height) + 4px);\n}\n\n.selectic .form-control-feedback.fa,\n.selectic .form-control-feedback {\n position: absolute;\n top: 0;\n right: 0;\n z-index: 2;\n display: block;\n width: calc(var(--selectic-input-height) + 4px);\n height: calc(var(--selectic-input-height) + 4px);\n line-height: var(--selectic-input-height);\n text-align: center;\n pointer-events: none;\n}\n\n.selectic .alert-info {\n background-color: var(--selectic-info-bg);\n color: var(--selectic-info-color);\n}\n\n.selectic .alert-danger {\n background-color: var(--selectic-error-bg);\n color: var(--selectic-error-color);\n}\n\n/* }}} */\n\n.selectic * {\n -webkit-box-sizing: border-box;\n -moz-box-sizing: border-box;\n box-sizing: border-box;\n}\n\n.selectic.form-control {\n display: inline-block;\n padding: 0;\n cursor: pointer;\n border: unset;\n}\n\n.has-feedback .selectic__icon-container.form-control-feedback {\n right: 0;\n}\n\n/* The input which contains the selected value\n * XXX: This input should stay hidden behind other elements, but is \"visible\"\n * (in term of DOM point of view) in order to get and to trigger the `focus`\n * DOM event. */\n.selectic__input-value {\n position: fixed;\n opacity: 0;\n z-index: -1000;\n top: -100px;\n}\n\n/* XXX: .form-control has been added to this selector to improve priority and\n * override some rules of the original .form-control */\n.selectic-input.form-control {\n display: inline-flex;\n justify-content: space-between;\n overflow: hidden;\n width: 100%;\n min-height: var(--selectic-input-height);\n padding-top: 0;\n padding-bottom: 0;\n padding-left: 5px;\n line-height: calc(var(--selectic-input-height) - 4px);\n color: var(--selectic-color);\n}\n\n.selectic-input__reverse-icon {\n align-self: center;\n margin-right: 3px;\n cursor: default;\n}\n.selectic-input__clear-icon {\n align-self: center;\n margin-left: 3px;\n cursor: pointer;\n}\n.selectic-input__clear-icon:hover {\n color: var(--selectic-selected-item-color);\n}\n\n.selectic-input.focused {\n border-bottom-left-radius: 0px;\n border-bottom-right-radius: 0px;\n}\n\n.selectic-input.disabled {\n cursor: var(--selectic-cursor-disabled);\n background-color: var(--selectic-bg-disabled);\n}\n.selectic-input.disabled .more-items {\n\tbackground-color: var(--selectic-more-items-bg-disabled);\n}\n\n.selectic-input__selected-items {\n display: inline-flex;\n flex-wrap: nowrap;\n align-items: center;\n white-space: nowrap;\n}\n\n.selectic-input__selected-items__placeholder {\n font-style: italic;\n opacity: 0.7;\n white-space: nowrap;\n}\n\n.selectic-icon {\n color: var(--selectic-color);\n text-align: center;\n vertical-align: middle;\n}\n\n.selectic__extended-list {\n position: fixed;\n 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";
|
|
32
32
|
styleInject(css_248z);
|
|
33
33
|
|
|
34
34
|
/**
|
|
@@ -554,25 +554,54 @@ class SelecticStore {
|
|
|
554
554
|
if (selected === undefined) {
|
|
555
555
|
selected = !isAlreadySelected;
|
|
556
556
|
}
|
|
557
|
+
const selectedOptions = Array.isArray(state.selectedOptions)
|
|
558
|
+
? state.selectedOptions
|
|
559
|
+
: [];
|
|
557
560
|
if (id === null) {
|
|
558
|
-
|
|
559
|
-
|
|
561
|
+
/* Keep disabled items: we cannot removed them because they
|
|
562
|
+
* are disabled */
|
|
563
|
+
const newSelection = selectedOptions.reduce((list, item) => {
|
|
564
|
+
if (item.disabled && item.id) {
|
|
565
|
+
list.push(item.id);
|
|
566
|
+
}
|
|
567
|
+
return list;
|
|
568
|
+
}, []);
|
|
569
|
+
state.internalValue = newSelection;
|
|
570
|
+
hasChanged = internalValue.length > newSelection.length;
|
|
560
571
|
}
|
|
561
572
|
else if (selected && !isAlreadySelected) {
|
|
573
|
+
let addItem = true;
|
|
562
574
|
if (item === null || item === void 0 ? void 0 : item.exclusive) {
|
|
563
|
-
|
|
564
|
-
|
|
575
|
+
const hasDisabledSelected = selectedOptions.some((opt) => {
|
|
576
|
+
return opt.disabled;
|
|
577
|
+
});
|
|
578
|
+
if (hasDisabledSelected) {
|
|
579
|
+
/* do not remove disabled item from selection */
|
|
580
|
+
addItem = false;
|
|
581
|
+
}
|
|
582
|
+
else {
|
|
583
|
+
/* clear the current selection because the item is exclusive */
|
|
584
|
+
internalValue.splice(0, Infinity);
|
|
585
|
+
}
|
|
565
586
|
}
|
|
566
587
|
else if (internalValue.length === 1) {
|
|
567
588
|
const selectedId = internalValue[0];
|
|
568
589
|
const selectedItem = state.allOptions.find((opt) => opt.id === selectedId);
|
|
569
590
|
if (selectedItem === null || selectedItem === void 0 ? void 0 : selectedItem.exclusive) {
|
|
570
|
-
|
|
571
|
-
|
|
591
|
+
if (selectedItem.disabled) {
|
|
592
|
+
/* If selected item is disabled and exclusive do not change the selection */
|
|
593
|
+
addItem = false;
|
|
594
|
+
}
|
|
595
|
+
else {
|
|
596
|
+
/* clear the current selection because the old item was exclusive */
|
|
597
|
+
internalValue.pop();
|
|
598
|
+
}
|
|
572
599
|
}
|
|
573
600
|
}
|
|
574
|
-
|
|
575
|
-
|
|
601
|
+
if (addItem) {
|
|
602
|
+
internalValue.push(id);
|
|
603
|
+
hasChanged = true;
|
|
604
|
+
}
|
|
576
605
|
}
|
|
577
606
|
else if (!selected && isAlreadySelected) {
|
|
578
607
|
internalValue.splice(internalValue.indexOf(id), 1);
|
|
@@ -595,6 +624,11 @@ class SelecticStore {
|
|
|
595
624
|
if (id !== oldValue) {
|
|
596
625
|
return hasChanged;
|
|
597
626
|
}
|
|
627
|
+
const oldOption = state.selectedOptions;
|
|
628
|
+
if (oldOption === null || oldOption === void 0 ? void 0 : oldOption.disabled) {
|
|
629
|
+
/* old selection is disabled so do not unselect it */
|
|
630
|
+
return hasChanged;
|
|
631
|
+
}
|
|
598
632
|
id = null;
|
|
599
633
|
}
|
|
600
634
|
else if (id === oldValue) {
|
|
@@ -1364,15 +1398,23 @@ class SelecticStore {
|
|
|
1364
1398
|
if (doNotCheck || !hasFetchedAllItems) {
|
|
1365
1399
|
return;
|
|
1366
1400
|
}
|
|
1401
|
+
const selectedOptions = state.selectedOptions;
|
|
1367
1402
|
const enabledOptions = state.allOptions.filter((opt) => !opt.disabled);
|
|
1368
|
-
const
|
|
1403
|
+
const nbEnabled = enabledOptions.length;
|
|
1369
1404
|
const value = state.internalValue;
|
|
1370
1405
|
const hasValue = Array.isArray(value) ? value.length > 0 : value !== null;
|
|
1371
|
-
const
|
|
1406
|
+
const hasDisabledSelected = Array.isArray(selectedOptions)
|
|
1407
|
+
? selectedOptions.some((opt) => opt.disabled)
|
|
1408
|
+
: false;
|
|
1409
|
+
const hasOnlyValidValue = hasValue && !hasDisabledSelected && (Array.isArray(value) ? value.every((val) => this.hasValue(val)) :
|
|
1372
1410
|
this.hasValue(value));
|
|
1373
|
-
const isEmpty =
|
|
1374
|
-
const hasOnlyOneOption =
|
|
1375
|
-
|
|
1411
|
+
const isEmpty = nbEnabled === 0;
|
|
1412
|
+
const hasOnlyOneOption = nbEnabled === 1 && hasOnlyValidValue && !state.allowClearSelection;
|
|
1413
|
+
const isExclusiveDisabledItem = Array.isArray(selectedOptions) /* which means "multiple" mode */
|
|
1414
|
+
&& selectedOptions.length === 1
|
|
1415
|
+
&& selectedOptions[0].exclusive
|
|
1416
|
+
&& selectedOptions[0].disabled;
|
|
1417
|
+
if (hasOnlyOneOption || isEmpty || isExclusiveDisabledItem) {
|
|
1376
1418
|
if (state.isOpen) {
|
|
1377
1419
|
this.setAutomaticClose();
|
|
1378
1420
|
this.commit('isOpen', false);
|
|
@@ -1792,6 +1834,18 @@ let MainInput = class MainInput extends Vue {
|
|
|
1792
1834
|
? Array.isArray(value) && value.length > 0
|
|
1793
1835
|
: value !== null;
|
|
1794
1836
|
}
|
|
1837
|
+
get disabledList() {
|
|
1838
|
+
const state = this.store.state;
|
|
1839
|
+
const isMultiple = state.multiple;
|
|
1840
|
+
const value = state.selectedOptions;
|
|
1841
|
+
if (!isMultiple || !value) {
|
|
1842
|
+
return [];
|
|
1843
|
+
}
|
|
1844
|
+
const disabledValues = value.filter((option) => {
|
|
1845
|
+
return option.disabled;
|
|
1846
|
+
});
|
|
1847
|
+
return disabledValues;
|
|
1848
|
+
}
|
|
1795
1849
|
get displayPlaceholder() {
|
|
1796
1850
|
const placeholder = this.store.state.placeholder;
|
|
1797
1851
|
const hasValue = this.hasValue;
|
|
@@ -1810,10 +1864,12 @@ let MainInput = class MainInput extends Vue {
|
|
|
1810
1864
|
const state = this.store.state;
|
|
1811
1865
|
const isMultiple = state.multiple;
|
|
1812
1866
|
const value = state.internalValue;
|
|
1813
|
-
const
|
|
1867
|
+
const nbSelection = (Array.isArray(value) && value.length) || 0;
|
|
1868
|
+
const hasOnlyOneValue = nbSelection === 1;
|
|
1869
|
+
const hasOnlyDisabled = nbSelection <= this.disabledList.length;
|
|
1814
1870
|
/* Should not display the clear action if there is only one selected
|
|
1815
1871
|
* item in multiple (as this item has already its remove icon) */
|
|
1816
|
-
return !isMultiple || !hasOnlyOneValue;
|
|
1872
|
+
return !isMultiple || !hasOnlyOneValue || !hasOnlyDisabled;
|
|
1817
1873
|
}
|
|
1818
1874
|
get clearedLabel() {
|
|
1819
1875
|
const isMultiple = this.store.state.multiple;
|
|
@@ -1931,6 +1987,9 @@ let MainInput = class MainInput extends Vue {
|
|
|
1931
1987
|
/* Check if there is enough space to display items like there are
|
|
1932
1988
|
* currently shown */
|
|
1933
1989
|
const el = this.$refs.selectedItems;
|
|
1990
|
+
if (!el) {
|
|
1991
|
+
return;
|
|
1992
|
+
}
|
|
1934
1993
|
const parentEl = el.parentElement;
|
|
1935
1994
|
if (!document.contains(parentEl)) {
|
|
1936
1995
|
/* The element is currently not in DOM */
|
|
@@ -2029,7 +2088,7 @@ let MainInput = class MainInput extends Vue {
|
|
|
2029
2088
|
click: () => this.$emit('item:click', item.id),
|
|
2030
2089
|
} },
|
|
2031
2090
|
h("span", { class: "selectic-input__selected-items__value" }, item.text),
|
|
2032
|
-
!this.isDisabled && (h(Icon$1, { icon: "times", class: "selectic-input__selected-items__icon", store: this.store, on: {
|
|
2091
|
+
!this.isDisabled && !item.disabled && (h(Icon$1, { icon: "times", class: "selectic-input__selected-items__icon", store: this.store, on: {
|
|
2033
2092
|
'click.prevent.stop': () => this.selectItem(item.id),
|
|
2034
2093
|
} }))))),
|
|
2035
2094
|
this.moreSelectedNb && (h("div", { class: "single-value more-items", title: this.moreSelectedTitle }, this.moreSelectedNb)))),
|
|
@@ -2783,7 +2842,8 @@ let Selectic = class Selectic extends Vue {
|
|
|
2783
2842
|
const store = this.store;
|
|
2784
2843
|
const keepOpenWithOtherSelectic = this.params.keepOpenWithOtherSelectic;
|
|
2785
2844
|
const extendedList = this.$refs.extendedList;
|
|
2786
|
-
|
|
2845
|
+
const extendedListEl = extendedList === null || extendedList === void 0 ? void 0 : extendedList.$el;
|
|
2846
|
+
if (!extendedListEl) {
|
|
2787
2847
|
/* this component is not focused anymore */
|
|
2788
2848
|
if (!keepOpenWithOtherSelectic) {
|
|
2789
2849
|
this.removeListeners();
|
|
@@ -2792,7 +2852,7 @@ let Selectic = class Selectic extends Vue {
|
|
|
2792
2852
|
return;
|
|
2793
2853
|
}
|
|
2794
2854
|
const target = evt.target;
|
|
2795
|
-
if (!
|
|
2855
|
+
if (!extendedListEl.contains(target) && !this.$el.contains(target)) {
|
|
2796
2856
|
store.commit('isOpen', false);
|
|
2797
2857
|
}
|
|
2798
2858
|
};
|
|
@@ -2885,14 +2945,23 @@ let Selectic = class Selectic extends Vue {
|
|
|
2885
2945
|
/* }}} */
|
|
2886
2946
|
/* {{{ private methods */
|
|
2887
2947
|
computeWidth() {
|
|
2888
|
-
|
|
2889
|
-
|
|
2948
|
+
var _a;
|
|
2949
|
+
const mainInput = (_a = this.$refs) === null || _a === void 0 ? void 0 : _a.mainInput;
|
|
2950
|
+
const mainEl = mainInput === null || mainInput === void 0 ? void 0 : mainInput.$el;
|
|
2951
|
+
if (!mainEl) {
|
|
2952
|
+
/* This method has been called too soon (before render function)
|
|
2953
|
+
* or too late (after unmount) */
|
|
2954
|
+
return;
|
|
2955
|
+
}
|
|
2956
|
+
this.width = mainEl.offsetWidth;
|
|
2890
2957
|
}
|
|
2891
2958
|
computeOffset(doNotAddListener = false) {
|
|
2892
|
-
|
|
2959
|
+
var _a;
|
|
2960
|
+
const mainInput = (_a = this.$refs) === null || _a === void 0 ? void 0 : _a.mainInput;
|
|
2893
2961
|
const mainEl = mainInput === null || mainInput === void 0 ? void 0 : mainInput.$el;
|
|
2894
2962
|
if (!mainEl) {
|
|
2895
|
-
/* This method has been called too soon (before render function)
|
|
2963
|
+
/* This method has been called too soon (before render function)
|
|
2964
|
+
* or too late (after unmount) */
|
|
2896
2965
|
return;
|
|
2897
2966
|
}
|
|
2898
2967
|
const _elementsListeners = this._elementsListeners;
|
|
@@ -3026,13 +3095,14 @@ let Selectic = class Selectic extends Vue {
|
|
|
3026
3095
|
checkFocus() {
|
|
3027
3096
|
/* Await that focused element becomes active */
|
|
3028
3097
|
setTimeout(() => {
|
|
3098
|
+
var _a;
|
|
3029
3099
|
const focusedEl = document.activeElement;
|
|
3030
|
-
const extendedList = this.$refs.extendedList;
|
|
3100
|
+
const extendedList = (_a = this.$refs) === null || _a === void 0 ? void 0 : _a.extendedList;
|
|
3031
3101
|
/* check if there is a focused element (if none the body is
|
|
3032
3102
|
* selected) and if it is inside current Selectic */
|
|
3033
3103
|
if (focusedEl === document.body
|
|
3034
3104
|
|| this.$el.contains(focusedEl)
|
|
3035
|
-
|| (extendedList
|
|
3105
|
+
|| (extendedList === null || extendedList === void 0 ? void 0 : extendedList.$el.contains(focusedEl))) {
|
|
3036
3106
|
return;
|
|
3037
3107
|
}
|
|
3038
3108
|
this.store.commit('isOpen', false);
|
package/doc/list.md
CHANGED
|
@@ -28,12 +28,13 @@ It is possible to define the `option` more precisely.
|
|
|
28
28
|
* **text** {`string`} _(mandatory)_: The text which is displayed to select the option or when it is selected.
|
|
29
29
|
* **title** {`string`}: Text displayed in `title` when cursor is over the option (default: `''`).
|
|
30
30
|
* **disabled** {`boolean`}: if `true`, this option cannot be selected (default: `false`).
|
|
31
|
+
In "multiple" mode, if the option is already selected, it cannot be removed from selection (it can always be removed by changing `value` of the component).
|
|
31
32
|
* **className** {`string`}: `class` that are applied on the option (default: `''`).
|
|
32
33
|
* **style** {`string`}: css style which are applied on the option (default: `''`).
|
|
33
34
|
* **icon** {`string`}: class names which are applied on a `<span>` before text in the option to display an icon (default: `''`).
|
|
34
35
|
* **options** {`options[]`}: an other list of options. The current option is considered as a group (equivalent of `optgroup`) (default: `undefined`).
|
|
35
36
|
* **group** {`string | number`}: If set, the option is part of the given group. This property is needed only in dynamic mode if the option is part of an optgroup (default: `null`).
|
|
36
|
-
* **exclusive** {`boolean`}: If set to `true`, in multiple mode, this option will be the only one selected. It means that it clears the previous selected options, and if another option is selected, this option is no more selected.
|
|
37
|
+
* **exclusive** {`boolean`}: If set to `true`, in "multiple" mode, this option will be the only one selected. It means that it clears the previous selected options, and if another option is selected, this option is no more selected.
|
|
37
38
|
* **data** {`any`}: You can store any information here, it will be provided when getting selected options. _It is not used by selectic so it can be anything you want_ (default: `undefined`).
|
|
38
39
|
|
|
39
40
|
```javascript
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "selectic",
|
|
3
|
-
"version": "3.1.
|
|
3
|
+
"version": "3.1.3",
|
|
4
4
|
"description": "Smart Select for VueJS 3.x",
|
|
5
5
|
"main": "dist/selectic.common.js",
|
|
6
6
|
"module": "dist/selectic.esm.js",
|
|
@@ -17,6 +17,7 @@
|
|
|
17
17
|
"homepage": "https://github.com/intersec/selectic#readme",
|
|
18
18
|
"keywords": [
|
|
19
19
|
"select",
|
|
20
|
+
"selectic",
|
|
20
21
|
"multiselect",
|
|
21
22
|
"multi-select",
|
|
22
23
|
"multi-select",
|
package/src/MainInput.tsx
CHANGED
|
@@ -17,7 +17,7 @@ export interface Props {
|
|
|
17
17
|
@Component
|
|
18
18
|
export default class MainInput extends Vue<Props> {
|
|
19
19
|
public $refs: {
|
|
20
|
-
selectedItems
|
|
20
|
+
selectedItems?: HTMLDivElement;
|
|
21
21
|
};
|
|
22
22
|
|
|
23
23
|
/* {{{ props */
|
|
@@ -53,6 +53,22 @@ export default class MainInput extends Vue<Props> {
|
|
|
53
53
|
: value !== null;
|
|
54
54
|
}
|
|
55
55
|
|
|
56
|
+
get disabledList(): OptionItem[] {
|
|
57
|
+
const state = this.store.state;
|
|
58
|
+
const isMultiple = state.multiple;
|
|
59
|
+
const value = state.selectedOptions;
|
|
60
|
+
|
|
61
|
+
if (!isMultiple || !value) {
|
|
62
|
+
return [];
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const disabledValues = (value as OptionItem[]).filter((option) => {
|
|
66
|
+
return option.disabled;
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
return disabledValues;
|
|
70
|
+
}
|
|
71
|
+
|
|
56
72
|
get displayPlaceholder(): boolean {
|
|
57
73
|
const placeholder = this.store.state.placeholder;
|
|
58
74
|
const hasValue = this.hasValue;
|
|
@@ -76,11 +92,13 @@ export default class MainInput extends Vue<Props> {
|
|
|
76
92
|
const state = this.store.state;
|
|
77
93
|
const isMultiple = state.multiple;
|
|
78
94
|
const value = state.internalValue;
|
|
79
|
-
const
|
|
95
|
+
const nbSelection = (Array.isArray(value) && value.length) || 0;
|
|
96
|
+
const hasOnlyOneValue = nbSelection === 1;
|
|
97
|
+
const hasOnlyDisabled = nbSelection <= this.disabledList.length;
|
|
80
98
|
|
|
81
99
|
/* Should not display the clear action if there is only one selected
|
|
82
100
|
* item in multiple (as this item has already its remove icon) */
|
|
83
|
-
return !isMultiple || !hasOnlyOneValue;
|
|
101
|
+
return !isMultiple || !hasOnlyOneValue || !hasOnlyDisabled;
|
|
84
102
|
}
|
|
85
103
|
|
|
86
104
|
get clearedLabel(): string {
|
|
@@ -239,6 +257,11 @@ export default class MainInput extends Vue<Props> {
|
|
|
239
257
|
/* Check if there is enough space to display items like there are
|
|
240
258
|
* currently shown */
|
|
241
259
|
const el = this.$refs.selectedItems;
|
|
260
|
+
|
|
261
|
+
if (!el) {
|
|
262
|
+
return;
|
|
263
|
+
}
|
|
264
|
+
|
|
242
265
|
const parentEl = el.parentElement as HTMLDivElement;
|
|
243
266
|
|
|
244
267
|
if (!document.contains(parentEl)) {
|
|
@@ -401,7 +424,7 @@ export default class MainInput extends Vue<Props> {
|
|
|
401
424
|
>
|
|
402
425
|
{ item.text }
|
|
403
426
|
</span>
|
|
404
|
-
{!this.isDisabled && (
|
|
427
|
+
{!this.isDisabled && !item.disabled && (
|
|
405
428
|
<Icon
|
|
406
429
|
icon="times"
|
|
407
430
|
class="selectic-input__selected-items__icon"
|
package/src/Store.tsx
CHANGED
|
@@ -939,24 +939,58 @@ export default class SelecticStore {
|
|
|
939
939
|
selected = !isAlreadySelected;
|
|
940
940
|
}
|
|
941
941
|
|
|
942
|
+
const selectedOptions = Array.isArray(state.selectedOptions)
|
|
943
|
+
? state.selectedOptions
|
|
944
|
+
: [];
|
|
945
|
+
|
|
942
946
|
if (id === null) {
|
|
943
|
-
|
|
944
|
-
|
|
947
|
+
/* Keep disabled items: we cannot removed them because they
|
|
948
|
+
* are disabled */
|
|
949
|
+
const newSelection = selectedOptions.reduce((list, item) => {
|
|
950
|
+
if (item.disabled && item.id) {
|
|
951
|
+
list.push(item.id);
|
|
952
|
+
}
|
|
953
|
+
|
|
954
|
+
return list;
|
|
955
|
+
}, [] as StrictOptionId[]);
|
|
956
|
+
|
|
957
|
+
state.internalValue = newSelection;
|
|
958
|
+
hasChanged = internalValue.length > newSelection.length;
|
|
945
959
|
} else
|
|
946
960
|
if (selected && !isAlreadySelected) {
|
|
961
|
+
let addItem = true;
|
|
962
|
+
|
|
947
963
|
if (item?.exclusive) {
|
|
948
|
-
|
|
949
|
-
|
|
964
|
+
const hasDisabledSelected = selectedOptions.some((opt) => {
|
|
965
|
+
return opt.disabled;
|
|
966
|
+
});
|
|
967
|
+
|
|
968
|
+
if (hasDisabledSelected) {
|
|
969
|
+
/* do not remove disabled item from selection */
|
|
970
|
+
addItem = false;
|
|
971
|
+
} else {
|
|
972
|
+
/* clear the current selection because the item is exclusive */
|
|
973
|
+
internalValue.splice(0, Infinity);
|
|
974
|
+
}
|
|
950
975
|
} else if (internalValue.length === 1) {
|
|
951
976
|
const selectedId = internalValue[0];
|
|
952
977
|
const selectedItem = state.allOptions.find((opt) => opt.id === selectedId);
|
|
978
|
+
|
|
953
979
|
if (selectedItem?.exclusive) {
|
|
954
|
-
|
|
955
|
-
|
|
980
|
+
if (selectedItem.disabled) {
|
|
981
|
+
/* If selected item is disabled and exclusive do not change the selection */
|
|
982
|
+
addItem = false;
|
|
983
|
+
} else {
|
|
984
|
+
/* clear the current selection because the old item was exclusive */
|
|
985
|
+
internalValue.pop();
|
|
986
|
+
}
|
|
956
987
|
}
|
|
957
988
|
}
|
|
958
|
-
|
|
959
|
-
|
|
989
|
+
|
|
990
|
+
if (addItem) {
|
|
991
|
+
internalValue.push(id);
|
|
992
|
+
hasChanged = true;
|
|
993
|
+
}
|
|
960
994
|
} else
|
|
961
995
|
if (!selected && isAlreadySelected) {
|
|
962
996
|
internalValue.splice(internalValue.indexOf(id), 1);
|
|
@@ -982,6 +1016,14 @@ export default class SelecticStore {
|
|
|
982
1016
|
if (id !== oldValue) {
|
|
983
1017
|
return hasChanged;
|
|
984
1018
|
}
|
|
1019
|
+
|
|
1020
|
+
const oldOption = state.selectedOptions as OptionItem | null;
|
|
1021
|
+
|
|
1022
|
+
if (oldOption?.disabled) {
|
|
1023
|
+
/* old selection is disabled so do not unselect it */
|
|
1024
|
+
return hasChanged;
|
|
1025
|
+
}
|
|
1026
|
+
|
|
985
1027
|
id = null;
|
|
986
1028
|
} else
|
|
987
1029
|
if (id === oldValue) {
|
|
@@ -1925,18 +1967,27 @@ export default class SelecticStore {
|
|
|
1925
1967
|
return;
|
|
1926
1968
|
}
|
|
1927
1969
|
|
|
1970
|
+
const selectedOptions = state.selectedOptions;
|
|
1928
1971
|
const enabledOptions = state.allOptions.filter((opt) => !opt.disabled);
|
|
1929
|
-
const
|
|
1972
|
+
const nbEnabled = enabledOptions.length;
|
|
1930
1973
|
const value = state.internalValue;
|
|
1931
1974
|
const hasValue = Array.isArray(value) ? value.length > 0 : value !== null;
|
|
1932
|
-
const
|
|
1975
|
+
const hasDisabledSelected = Array.isArray(selectedOptions)
|
|
1976
|
+
? selectedOptions.some((opt) => opt.disabled)
|
|
1977
|
+
: false;
|
|
1978
|
+
const hasOnlyValidValue = hasValue && !hasDisabledSelected && (
|
|
1933
1979
|
Array.isArray(value) ? value.every((val) => this.hasValue(val)) :
|
|
1934
1980
|
this.hasValue(value)
|
|
1935
1981
|
);
|
|
1936
|
-
const isEmpty = nb === 0;
|
|
1937
|
-
const hasOnlyOneOption = nb === 1 && hasValidValue && !state.allowClearSelection;
|
|
1938
1982
|
|
|
1939
|
-
|
|
1983
|
+
const isEmpty = nbEnabled === 0;
|
|
1984
|
+
const hasOnlyOneOption = nbEnabled === 1 && hasOnlyValidValue && !state.allowClearSelection;
|
|
1985
|
+
const isExclusiveDisabledItem = Array.isArray(selectedOptions) /* which means "multiple" mode */
|
|
1986
|
+
&& selectedOptions.length === 1
|
|
1987
|
+
&& selectedOptions[0].exclusive
|
|
1988
|
+
&& selectedOptions[0].disabled;
|
|
1989
|
+
|
|
1990
|
+
if (hasOnlyOneOption || isEmpty || isExclusiveDisabledItem) {
|
|
1940
1991
|
if (state.isOpen) {
|
|
1941
1992
|
this.setAutomaticClose();
|
|
1942
1993
|
this.commit('isOpen', false);
|
package/src/css/selectic.css
CHANGED
|
@@ -244,6 +244,9 @@
|
|
|
244
244
|
.selectic-item__active:not(.selected) .selectic-item_icon {
|
|
245
245
|
opacity: 0.2;
|
|
246
246
|
}
|
|
247
|
+
.selectic-item__active.selectic-item__disabled:not(.selected) .selectic-item_icon {
|
|
248
|
+
opacity: 0;
|
|
249
|
+
}
|
|
247
250
|
|
|
248
251
|
.selectic-item__disabled {
|
|
249
252
|
color: var(--selectic-color-disabled);
|
package/src/index.tsx
CHANGED
|
@@ -243,7 +243,7 @@ export function changeIcons(icons: PartialIcons, iconFamily?: IconFamily) {
|
|
|
243
243
|
export default class Selectic extends Vue<Props> {
|
|
244
244
|
public $refs: {
|
|
245
245
|
mainInput: MainInput;
|
|
246
|
-
extendedList
|
|
246
|
+
extendedList?: ExtendedList;
|
|
247
247
|
};
|
|
248
248
|
|
|
249
249
|
/* {{{ props */
|
|
@@ -349,19 +349,21 @@ export default class Selectic extends Vue<Props> {
|
|
|
349
349
|
const store = this.store;
|
|
350
350
|
const keepOpenWithOtherSelectic = this.params.keepOpenWithOtherSelectic;
|
|
351
351
|
const extendedList = this.$refs.extendedList;
|
|
352
|
+
const extendedListEl: HTMLElement | undefined = extendedList?.$el;
|
|
352
353
|
|
|
353
|
-
if (!
|
|
354
|
+
if (!extendedListEl) {
|
|
354
355
|
/* this component is not focused anymore */
|
|
355
356
|
if (!keepOpenWithOtherSelectic) {
|
|
356
357
|
this.removeListeners();
|
|
357
358
|
this.store.commit('isOpen', false);
|
|
358
359
|
}
|
|
360
|
+
|
|
359
361
|
return;
|
|
360
362
|
}
|
|
361
363
|
|
|
362
364
|
const target = evt.target as Node;
|
|
363
365
|
|
|
364
|
-
if (!
|
|
366
|
+
if (!extendedListEl.contains(target) && !this.$el.contains(target)) {
|
|
365
367
|
store.commit('isOpen', false);
|
|
366
368
|
}
|
|
367
369
|
};
|
|
@@ -477,18 +479,27 @@ export default class Selectic extends Vue<Props> {
|
|
|
477
479
|
/* {{{ private methods */
|
|
478
480
|
|
|
479
481
|
private computeWidth() {
|
|
480
|
-
const
|
|
482
|
+
const mainInput = this.$refs?.mainInput;
|
|
483
|
+
|
|
484
|
+
const mainEl: HTMLElement | undefined = mainInput?.$el;
|
|
481
485
|
|
|
482
|
-
|
|
486
|
+
if (!mainEl) {
|
|
487
|
+
/* This method has been called too soon (before render function)
|
|
488
|
+
* or too late (after unmount) */
|
|
489
|
+
return;
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
this.width = mainEl.offsetWidth;
|
|
483
493
|
}
|
|
484
494
|
|
|
485
495
|
private computeOffset(doNotAddListener = false) {
|
|
486
|
-
const mainInput = this.$refs
|
|
496
|
+
const mainInput = this.$refs?.mainInput;
|
|
487
497
|
|
|
488
|
-
const mainEl = mainInput?.$el
|
|
498
|
+
const mainEl: HTMLElement | undefined = mainInput?.$el;
|
|
489
499
|
|
|
490
500
|
if (!mainEl) {
|
|
491
|
-
/* This method has been called too soon (before render function)
|
|
501
|
+
/* This method has been called too soon (before render function)
|
|
502
|
+
* or too late (after unmount) */
|
|
492
503
|
return;
|
|
493
504
|
}
|
|
494
505
|
|
|
@@ -669,13 +680,13 @@ export default class Selectic extends Vue<Props> {
|
|
|
669
680
|
/* Await that focused element becomes active */
|
|
670
681
|
setTimeout(() => {
|
|
671
682
|
const focusedEl = document.activeElement;
|
|
672
|
-
const extendedList = this.$refs
|
|
683
|
+
const extendedList = this.$refs?.extendedList;
|
|
673
684
|
|
|
674
685
|
/* check if there is a focused element (if none the body is
|
|
675
686
|
* selected) and if it is inside current Selectic */
|
|
676
687
|
if (focusedEl === document.body
|
|
677
688
|
|| this.$el.contains(focusedEl)
|
|
678
|
-
||
|
|
689
|
+
|| extendedList?.$el.contains(focusedEl))
|
|
679
690
|
{
|
|
680
691
|
return;
|
|
681
692
|
}
|
|
@@ -699,6 +699,80 @@ tape.test('Store creation', (subT) => {
|
|
|
699
699
|
t.end();
|
|
700
700
|
});
|
|
701
701
|
|
|
702
|
+
sTest.test('should disable multiple select with the only enabled value selected', async (t) => {
|
|
703
|
+
const options = getOptions(3);
|
|
704
|
+
options[0].disabled = true;
|
|
705
|
+
options[1].disabled = true;
|
|
706
|
+
|
|
707
|
+
const store = new Store({
|
|
708
|
+
options: options,
|
|
709
|
+
disabled: false,
|
|
710
|
+
value: [2],
|
|
711
|
+
params: {
|
|
712
|
+
multiple: true,
|
|
713
|
+
autoDisabled: true,
|
|
714
|
+
allowClearSelection: false,
|
|
715
|
+
},
|
|
716
|
+
});
|
|
717
|
+
|
|
718
|
+
await sleep(0);
|
|
719
|
+
|
|
720
|
+
t.is(store.state.disabled, true);
|
|
721
|
+
t.deepEqual(store.state.internalValue, [2]);
|
|
722
|
+
|
|
723
|
+
t.end();
|
|
724
|
+
});
|
|
725
|
+
|
|
726
|
+
sTest.test('should not disable multiple select when it is possible to remove selected value', async (t) => {
|
|
727
|
+
const options = getOptions(3);
|
|
728
|
+
options[0].disabled = true;
|
|
729
|
+
options[1].disabled = true;
|
|
730
|
+
|
|
731
|
+
const store = new Store({
|
|
732
|
+
options: options,
|
|
733
|
+
disabled: false,
|
|
734
|
+
value: [1, 2],
|
|
735
|
+
params: {
|
|
736
|
+
multiple: true,
|
|
737
|
+
autoDisabled: true,
|
|
738
|
+
allowClearSelection: false,
|
|
739
|
+
},
|
|
740
|
+
});
|
|
741
|
+
|
|
742
|
+
await sleep(0);
|
|
743
|
+
|
|
744
|
+
/* It is possible to remove the item "2" because there is another value */
|
|
745
|
+
t.is(store.state.disabled, false);
|
|
746
|
+
t.deepEqual(store.state.internalValue, [1, 2]);
|
|
747
|
+
|
|
748
|
+
t.end();
|
|
749
|
+
});
|
|
750
|
+
|
|
751
|
+
sTest.test('should disable multiple select when exclusive disabled item is selected', async (t) => {
|
|
752
|
+
const options = getOptions(3);
|
|
753
|
+
options[1].disabled = true;
|
|
754
|
+
options[1].exclusive = true;
|
|
755
|
+
|
|
756
|
+
const store = new Store({
|
|
757
|
+
options: options,
|
|
758
|
+
disabled: false,
|
|
759
|
+
value: [1],
|
|
760
|
+
params: {
|
|
761
|
+
multiple: true,
|
|
762
|
+
autoDisabled: true,
|
|
763
|
+
allowClearSelection: false,
|
|
764
|
+
},
|
|
765
|
+
});
|
|
766
|
+
|
|
767
|
+
await sleep(0);
|
|
768
|
+
|
|
769
|
+
/* It is not possible to change the value */
|
|
770
|
+
t.is(store.state.disabled, true);
|
|
771
|
+
t.deepEqual(store.state.internalValue, [1]);
|
|
772
|
+
|
|
773
|
+
t.end();
|
|
774
|
+
});
|
|
775
|
+
|
|
702
776
|
sTest.test('should not disable select without autoDisabled', async (t) => {
|
|
703
777
|
const store = new Store({
|
|
704
778
|
options: getOptions(1),
|
|
@@ -31,7 +31,7 @@ tape.test('selectItem()', (st) => {
|
|
|
31
31
|
const result1 = store.selectItem(2, true);
|
|
32
32
|
t.is(store.state.internalValue, 2);
|
|
33
33
|
t.is(store.state.status.hasChanged, true);
|
|
34
|
-
t.is(result1, true, 'should return if a change occurs');
|
|
34
|
+
t.is(result1, true, 'should return true if a change occurs');
|
|
35
35
|
|
|
36
36
|
/* reset status to check that it is modified */
|
|
37
37
|
store.state.status.hasChanged = false;
|
|
@@ -39,7 +39,17 @@ tape.test('selectItem()', (st) => {
|
|
|
39
39
|
const result2 = store.selectItem(5, true);
|
|
40
40
|
t.is(store.state.internalValue, 5);
|
|
41
41
|
t.is(store.state.status.hasChanged, true);
|
|
42
|
-
t.is(result2, true, 'should return if a change occurs');
|
|
42
|
+
t.is(result2, true, 'should return true if a change occurs');
|
|
43
|
+
|
|
44
|
+
/* Should replace a disabled selected item */
|
|
45
|
+
store.commit('internalValue', 4);
|
|
46
|
+
store.state.status.hasChanged = false;
|
|
47
|
+
|
|
48
|
+
const result3 = store.selectItem(3);
|
|
49
|
+
t.is(store.state.internalValue, 3);
|
|
50
|
+
t.is(store.state.status.hasChanged, true);
|
|
51
|
+
t.is(result3, true, 'should return true if a change occurs');
|
|
52
|
+
|
|
43
53
|
t.end();
|
|
44
54
|
});
|
|
45
55
|
|
|
@@ -50,12 +60,24 @@ tape.test('selectItem()', (st) => {
|
|
|
50
60
|
/* reset status to check that it is modified */
|
|
51
61
|
store.state.status.hasChanged = false;
|
|
52
62
|
|
|
53
|
-
const
|
|
63
|
+
const result1 = store.selectItem(2, false);
|
|
54
64
|
t.is(store.state.internalValue, null);
|
|
55
65
|
t.is(store.state.status.hasChanged, true);
|
|
56
66
|
|
|
57
67
|
t.is(store.state.selectionIsExcluded, false);
|
|
58
|
-
t.is(
|
|
68
|
+
t.is(result1, true, 'should return true if a change occurs');
|
|
69
|
+
|
|
70
|
+
/* Should not deselect a disabled selected item */
|
|
71
|
+
store.commit('internalValue', 4);
|
|
72
|
+
store.state.status.hasChanged = false;
|
|
73
|
+
|
|
74
|
+
const result2 = store.selectItem(4, false);
|
|
75
|
+
t.is(store.state.internalValue, 4);
|
|
76
|
+
t.is(store.state.status.hasChanged, false);
|
|
77
|
+
|
|
78
|
+
t.is(store.state.selectionIsExcluded, false);
|
|
79
|
+
t.is(result2, false, 'should return false if no change occurs');
|
|
80
|
+
|
|
59
81
|
t.end();
|
|
60
82
|
});
|
|
61
83
|
|
|
@@ -173,31 +195,40 @@ tape.test('selectItem()', (st) => {
|
|
|
173
195
|
sTest.test('should clear selection', (t) => {
|
|
174
196
|
const store = getStore();
|
|
175
197
|
store.commit('isOpen', true);
|
|
176
|
-
store.
|
|
198
|
+
store.commit('internalValue', 1);
|
|
177
199
|
|
|
178
200
|
const result1 = store.selectItem(null);
|
|
179
201
|
t.is(store.state.isOpen, false);
|
|
180
202
|
t.is(store.state.internalValue, null);
|
|
181
203
|
t.is(store.state.status.hasChanged, true);
|
|
182
|
-
t.is(result1, true, 'should return if a change occurs');
|
|
204
|
+
t.is(result1, true, 'should return true if a change occurs');
|
|
183
205
|
|
|
206
|
+
store.commit('internalValue', 2);
|
|
184
207
|
store.state.status.hasChanged = false;
|
|
185
|
-
store.state.internalValue = 2;
|
|
186
208
|
|
|
187
209
|
/* applied also when selectic is closed */
|
|
188
210
|
const result2 = store.selectItem(null);
|
|
189
211
|
t.is(store.state.internalValue, null);
|
|
190
212
|
t.is(store.state.status.hasChanged, true);
|
|
191
|
-
t.is(result2, true, 'should return if a change occurs');
|
|
213
|
+
t.is(result2, true, 'should return true if a change occurs');
|
|
192
214
|
|
|
215
|
+
store.commit('internalValue', 3);
|
|
193
216
|
store.state.status.hasChanged = false;
|
|
194
|
-
store.state.internalValue = 3;
|
|
195
217
|
|
|
196
218
|
/* ignore the selected argument */
|
|
197
219
|
const result3 = store.selectItem(null, false);
|
|
198
220
|
t.is(store.state.internalValue, null);
|
|
199
221
|
t.is(store.state.status.hasChanged, true);
|
|
200
|
-
t.is(result3, true, 'should return if a change occurs');
|
|
222
|
+
t.is(result3, true, 'should return true if a change occurs');
|
|
223
|
+
|
|
224
|
+
/* Should removed a disabled selected item */
|
|
225
|
+
store.commit('internalValue', 4);
|
|
226
|
+
store.state.status.hasChanged = false;
|
|
227
|
+
|
|
228
|
+
const result4 = store.selectItem(null, false);
|
|
229
|
+
t.is(store.state.internalValue, null);
|
|
230
|
+
t.is(store.state.status.hasChanged, true);
|
|
231
|
+
t.is(result4, true, 'should return true if a change occurs');
|
|
201
232
|
|
|
202
233
|
t.end();
|
|
203
234
|
});
|
|
@@ -225,10 +256,12 @@ tape.test('selectItem()', (st) => {
|
|
|
225
256
|
|
|
226
257
|
st.test('when "multiple" is true', (sTest) => {
|
|
227
258
|
function getStore() {
|
|
228
|
-
const options = getOptions(
|
|
259
|
+
const options = getOptions(9);
|
|
229
260
|
options[4].disabled = true;
|
|
230
261
|
options[6].exclusive = true;
|
|
231
262
|
options[7].exclusive = true;
|
|
263
|
+
options[8].disabled = true;
|
|
264
|
+
options[8].exclusive = true;
|
|
232
265
|
|
|
233
266
|
const store = new Store({
|
|
234
267
|
options: options,
|
|
@@ -410,24 +443,24 @@ tape.test('selectItem()', (st) => {
|
|
|
410
443
|
|
|
411
444
|
sTest.test('should clear selection', (t) => {
|
|
412
445
|
const store = getStore();
|
|
413
|
-
store.
|
|
446
|
+
store.commit('internalValue', [1, 3]);
|
|
414
447
|
|
|
415
448
|
const result1 = store.selectItem(null);
|
|
416
449
|
t.deepEqual(store.state.internalValue, []);
|
|
417
450
|
t.is(store.state.status.hasChanged, true);
|
|
418
|
-
t.is(result1, true, 'should return if a change occurs');
|
|
451
|
+
t.is(result1, true, 'should return true if a change occurs');
|
|
419
452
|
|
|
453
|
+
store.commit('internalValue', [2, 3]);
|
|
420
454
|
store.state.status.hasChanged = false;
|
|
421
|
-
store.state.internalValue = [2, 4];
|
|
422
455
|
|
|
423
456
|
/* ignore the selected argument */
|
|
424
457
|
const result2 = store.selectItem(null, false);
|
|
425
458
|
t.deepEqual(store.state.internalValue, []);
|
|
426
459
|
t.is(store.state.status.hasChanged, true);
|
|
427
|
-
t.is(result2, true, 'should return if a change occurs');
|
|
460
|
+
t.is(result2, true, 'should return true if a change occurs');
|
|
428
461
|
|
|
462
|
+
store.commit('internalValue', [3, 5]);
|
|
429
463
|
store.state.status.hasChanged = false;
|
|
430
|
-
store.state.internalValue = [3, 4];
|
|
431
464
|
|
|
432
465
|
/* applied also when selectic is open */
|
|
433
466
|
store.commit('isOpen', true);
|
|
@@ -435,7 +468,33 @@ tape.test('selectItem()', (st) => {
|
|
|
435
468
|
t.is(store.state.isOpen, true);
|
|
436
469
|
t.deepEqual(store.state.internalValue, []);
|
|
437
470
|
t.is(store.state.status.hasChanged, true);
|
|
438
|
-
t.is(result3, true, 'should return if a change occurs');
|
|
471
|
+
t.is(result3, true, 'should return true if a change occurs');
|
|
472
|
+
t.end();
|
|
473
|
+
});
|
|
474
|
+
|
|
475
|
+
sTest.test('should clear selection with disabled item', (t) => {
|
|
476
|
+
const store = getStore();
|
|
477
|
+
store.commit('internalValue', [1, 4]);
|
|
478
|
+
|
|
479
|
+
const result1 = store.selectItem(null);
|
|
480
|
+
t.deepEqual(store.state.internalValue, [4], 'should keep disabled item in selection');
|
|
481
|
+
t.is(store.state.status.hasChanged, true);
|
|
482
|
+
t.is(result1, true, 'should return true if a change occurs');
|
|
483
|
+
|
|
484
|
+
store.state.status.hasChanged = false;
|
|
485
|
+
|
|
486
|
+
/* With only disabled item in selection */
|
|
487
|
+
const result2 = store.selectItem(null);
|
|
488
|
+
t.deepEqual(store.state.internalValue, [4]);
|
|
489
|
+
t.is(store.state.status.hasChanged, false);
|
|
490
|
+
t.is(result2, false, 'should return false if no change occurs');
|
|
491
|
+
|
|
492
|
+
store.state.status.hasChanged = false;
|
|
493
|
+
|
|
494
|
+
/* Assert disabled items can be removed by changing the selection */
|
|
495
|
+
store.commit('internalValue', [3, 2]);
|
|
496
|
+
t.deepEqual(store.state.internalValue, [3, 2], 'should remove disabled item');
|
|
497
|
+
|
|
439
498
|
t.end();
|
|
440
499
|
});
|
|
441
500
|
|
|
@@ -466,30 +525,57 @@ tape.test('selectItem()', (st) => {
|
|
|
466
525
|
|
|
467
526
|
sTest.test('should keep only exclusive item', (t) => {
|
|
468
527
|
const store = getStore();
|
|
469
|
-
store.
|
|
528
|
+
store.commit('internalValue', [1, 3, 5]);
|
|
470
529
|
|
|
471
530
|
const result1 = store.selectItem(6, true);
|
|
472
531
|
t.deepEqual(store.state.internalValue, [6]);
|
|
473
532
|
t.is(store.state.status.hasChanged, true);
|
|
474
|
-
t.is(result1, true, 'should return if a change occurs');
|
|
533
|
+
t.is(result1, true, 'should return true if a change occurs');
|
|
475
534
|
|
|
476
535
|
const result2 = store.selectItem(7, true);
|
|
477
536
|
t.deepEqual(store.state.internalValue, [7]);
|
|
478
537
|
t.is(store.state.status.hasChanged, true);
|
|
479
|
-
t.is(result2, true, 'should return if a change occurs');
|
|
538
|
+
t.is(result2, true, 'should return true if a change occurs');
|
|
480
539
|
|
|
481
540
|
const result3 = store.selectItem(1, true);
|
|
482
541
|
t.deepEqual(store.state.internalValue, [1]);
|
|
483
542
|
t.is(store.state.status.hasChanged, true);
|
|
484
|
-
t.is(result3, true, 'should return if a change occurs');
|
|
543
|
+
t.is(result3, true, 'should return true if a change occurs');
|
|
485
544
|
|
|
486
545
|
const result4 = store.selectItem(5, true);
|
|
487
546
|
t.deepEqual(store.state.internalValue, [1, 5]);
|
|
488
547
|
t.is(store.state.status.hasChanged, true);
|
|
489
|
-
t.is(result4, true, 'should return if a change occurs');
|
|
548
|
+
t.is(result4, true, 'should return true if a change occurs');
|
|
490
549
|
|
|
491
550
|
t.is(store.state.selectionIsExcluded, false);
|
|
492
551
|
t.end();
|
|
493
552
|
});
|
|
553
|
+
|
|
554
|
+
sTest.test('should manage exclusive item with disabled item', (t) => {
|
|
555
|
+
const store = getStore();
|
|
556
|
+
store.commit('internalValue', [1, 4, 5]);
|
|
557
|
+
|
|
558
|
+
const result1 = store.selectItem(6, true);
|
|
559
|
+
t.deepEqual(store.state.internalValue, [1, 4, 5]);
|
|
560
|
+
t.is(store.state.status.hasChanged, false);
|
|
561
|
+
t.is(result1, false, 'should return false if no change occurs');
|
|
562
|
+
|
|
563
|
+
/* With exclusive and disabled item selected */
|
|
564
|
+
store.commit('internalValue', [8]);
|
|
565
|
+
|
|
566
|
+
const result2 = store.selectItem(6, true);
|
|
567
|
+
t.deepEqual(store.state.internalValue, [8]);
|
|
568
|
+
t.is(store.state.status.hasChanged, false);
|
|
569
|
+
t.is(result2, false, 'should return false if no change occurs');
|
|
570
|
+
|
|
571
|
+
const result3 = store.selectItem(1, true);
|
|
572
|
+
t.deepEqual(store.state.internalValue, [8]);
|
|
573
|
+
t.is(store.state.status.hasChanged, false);
|
|
574
|
+
t.is(result3, false, 'should return false if no change occurs');
|
|
575
|
+
|
|
576
|
+
t.is(store.state.selectionIsExcluded, false);
|
|
577
|
+
|
|
578
|
+
t.end();
|
|
579
|
+
});
|
|
494
580
|
});
|
|
495
581
|
});
|
package/types/MainInput.d.ts
CHANGED
|
@@ -6,7 +6,7 @@ export interface Props {
|
|
|
6
6
|
}
|
|
7
7
|
export default class MainInput extends Vue<Props> {
|
|
8
8
|
$refs: {
|
|
9
|
-
selectedItems
|
|
9
|
+
selectedItems?: HTMLDivElement;
|
|
10
10
|
};
|
|
11
11
|
private store;
|
|
12
12
|
private id;
|
|
@@ -14,6 +14,7 @@ export default class MainInput extends Vue<Props> {
|
|
|
14
14
|
private domObserver;
|
|
15
15
|
get isDisabled(): boolean;
|
|
16
16
|
get hasValue(): boolean;
|
|
17
|
+
get disabledList(): OptionItem[];
|
|
17
18
|
get displayPlaceholder(): boolean;
|
|
18
19
|
get canBeCleared(): boolean;
|
|
19
20
|
get showClearAll(): boolean;
|
package/types/index.d.ts
CHANGED
|
@@ -133,7 +133,7 @@ export declare function changeIcons(icons: PartialIcons, iconFamily?: IconFamily
|
|
|
133
133
|
export default class Selectic extends Vue<Props> {
|
|
134
134
|
$refs: {
|
|
135
135
|
mainInput: MainInput;
|
|
136
|
-
extendedList
|
|
136
|
+
extendedList?: ExtendedList;
|
|
137
137
|
};
|
|
138
138
|
value?: SelectedValue;
|
|
139
139
|
selectionIsExcluded: boolean;
|