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/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
|
/**
|
|
@@ -134,12 +134,25 @@ function compareOptions(oldOptions, newOptions) {
|
|
|
134
134
|
});
|
|
135
135
|
});
|
|
136
136
|
}
|
|
137
|
+
let displayLog = false;
|
|
138
|
+
function debug(fName, step, ...args) {
|
|
139
|
+
if (!displayLog) {
|
|
140
|
+
return;
|
|
141
|
+
}
|
|
142
|
+
console.log('--%s-- [%s]', fName, step, ...args);
|
|
143
|
+
}
|
|
144
|
+
/** Enable logs for debugging */
|
|
145
|
+
debug.enable = (display) => {
|
|
146
|
+
displayLog = display;
|
|
147
|
+
};
|
|
137
148
|
|
|
138
149
|
/* File Purpose:
|
|
139
150
|
* It keeps and computes all states at a single place.
|
|
140
151
|
* Every inner components of Selectic should communicate with this file to
|
|
141
152
|
* change or to get states.
|
|
142
153
|
*/
|
|
154
|
+
/* For debugging */
|
|
155
|
+
debug.enable(false);
|
|
143
156
|
/* }}} */
|
|
144
157
|
/* {{{ Static */
|
|
145
158
|
function changeTexts$1(texts) {
|
|
@@ -174,12 +187,19 @@ let messages = {
|
|
|
174
187
|
let defaultFamilyIcon = 'selectic';
|
|
175
188
|
let icons = {};
|
|
176
189
|
let closePreviousSelectic;
|
|
190
|
+
/**
|
|
191
|
+
* Time to wait before considering there is no other requests.
|
|
192
|
+
* This time is await only if there is already a requested request.
|
|
193
|
+
*/
|
|
194
|
+
const DEBOUNCE_REQUEST = 250;
|
|
177
195
|
/* }}} */
|
|
178
196
|
let uid = 0;
|
|
179
197
|
class SelecticStore {
|
|
180
198
|
constructor(props = {}) {
|
|
181
199
|
/* Do not need reactivity */
|
|
182
200
|
this.requestId = 0;
|
|
201
|
+
this.requestSearchId = 0; /* Used for search request */
|
|
202
|
+
this.isRequesting = false;
|
|
183
203
|
this._uid = ++uid;
|
|
184
204
|
/* {{{ Props */
|
|
185
205
|
const defaultProps = {
|
|
@@ -295,6 +315,7 @@ class SelecticStore {
|
|
|
295
315
|
this.data.cacheItem.clear();
|
|
296
316
|
this.setAutomaticClose();
|
|
297
317
|
this.commit('isOpen', false);
|
|
318
|
+
this.clearDisplay();
|
|
298
319
|
this.buildAllOptions(true);
|
|
299
320
|
this.buildSelectedOptions();
|
|
300
321
|
}, { deep: true });
|
|
@@ -385,6 +406,7 @@ class SelecticStore {
|
|
|
385
406
|
/* {{{ public methods */
|
|
386
407
|
commit(name, value) {
|
|
387
408
|
const oldValue = this.state[name];
|
|
409
|
+
debug('commit', 'start', name, value, 'oldValue:', oldValue);
|
|
388
410
|
if (oldValue === value) {
|
|
389
411
|
return;
|
|
390
412
|
}
|
|
@@ -393,8 +415,7 @@ class SelecticStore {
|
|
|
393
415
|
case 'searchText':
|
|
394
416
|
this.state.offsetItem = 0;
|
|
395
417
|
this.state.activeItemIdx = -1;
|
|
396
|
-
this.
|
|
397
|
-
this.state.totalFilteredOptions = Infinity;
|
|
418
|
+
this.clearDisplay();
|
|
398
419
|
if (value) {
|
|
399
420
|
this.buildFilteredOptions();
|
|
400
421
|
}
|
|
@@ -442,6 +463,7 @@ class SelecticStore {
|
|
|
442
463
|
}
|
|
443
464
|
break;
|
|
444
465
|
}
|
|
466
|
+
debug('commit', '(done)', name);
|
|
445
467
|
}
|
|
446
468
|
setAutomaticChange() {
|
|
447
469
|
this.state.status.automaticChange = true;
|
|
@@ -532,25 +554,54 @@ class SelecticStore {
|
|
|
532
554
|
if (selected === undefined) {
|
|
533
555
|
selected = !isAlreadySelected;
|
|
534
556
|
}
|
|
557
|
+
const selectedOptions = Array.isArray(state.selectedOptions)
|
|
558
|
+
? state.selectedOptions
|
|
559
|
+
: [];
|
|
535
560
|
if (id === null) {
|
|
536
|
-
|
|
537
|
-
|
|
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;
|
|
538
571
|
}
|
|
539
572
|
else if (selected && !isAlreadySelected) {
|
|
573
|
+
let addItem = true;
|
|
540
574
|
if (item === null || item === void 0 ? void 0 : item.exclusive) {
|
|
541
|
-
|
|
542
|
-
|
|
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
|
+
}
|
|
543
586
|
}
|
|
544
587
|
else if (internalValue.length === 1) {
|
|
545
588
|
const selectedId = internalValue[0];
|
|
546
589
|
const selectedItem = state.allOptions.find((opt) => opt.id === selectedId);
|
|
547
590
|
if (selectedItem === null || selectedItem === void 0 ? void 0 : selectedItem.exclusive) {
|
|
548
|
-
|
|
549
|
-
|
|
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
|
+
}
|
|
550
599
|
}
|
|
551
600
|
}
|
|
552
|
-
|
|
553
|
-
|
|
601
|
+
if (addItem) {
|
|
602
|
+
internalValue.push(id);
|
|
603
|
+
hasChanged = true;
|
|
604
|
+
}
|
|
554
605
|
}
|
|
555
606
|
else if (!selected && isAlreadySelected) {
|
|
556
607
|
internalValue.splice(internalValue.indexOf(id), 1);
|
|
@@ -573,6 +624,11 @@ class SelecticStore {
|
|
|
573
624
|
if (id !== oldValue) {
|
|
574
625
|
return hasChanged;
|
|
575
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
|
+
}
|
|
576
632
|
id = null;
|
|
577
633
|
}
|
|
578
634
|
else if (id === oldValue) {
|
|
@@ -627,14 +683,14 @@ class SelecticStore {
|
|
|
627
683
|
this.state.status.errorMessage = '';
|
|
628
684
|
}
|
|
629
685
|
clearCache(forceReset = false) {
|
|
686
|
+
debug('clearCache', 'start', forceReset);
|
|
630
687
|
const isPartial = unref(this.isPartial);
|
|
631
688
|
const total = isPartial ? Infinity : 0;
|
|
632
689
|
this.data.cacheItem.clear();
|
|
633
690
|
this.state.allOptions = [];
|
|
634
691
|
this.state.totalAllOptions = total;
|
|
635
692
|
this.state.totalDynOptions = total;
|
|
636
|
-
this.
|
|
637
|
-
this.state.totalFilteredOptions = Infinity;
|
|
693
|
+
this.clearDisplay();
|
|
638
694
|
this.state.status.errorMessage = '';
|
|
639
695
|
this.state.status.hasChanged = false;
|
|
640
696
|
if (forceReset) {
|
|
@@ -766,6 +822,13 @@ class SelecticStore {
|
|
|
766
822
|
this.checkAutoSelect();
|
|
767
823
|
}
|
|
768
824
|
}
|
|
825
|
+
/** Reset the display cache in order to rebuild it */
|
|
826
|
+
clearDisplay() {
|
|
827
|
+
debug('clearDisplay', 'start');
|
|
828
|
+
this.state.filteredOptions = [];
|
|
829
|
+
this.state.totalFilteredOptions = Infinity;
|
|
830
|
+
}
|
|
831
|
+
/** rebuild the state filteredOptions to normalize their values */
|
|
769
832
|
updateFilteredOptions() {
|
|
770
833
|
if (!this.data.doNotUpdate) {
|
|
771
834
|
this.state.filteredOptions = this.buildItems(this.state.filteredOptions);
|
|
@@ -815,7 +878,7 @@ class SelecticStore {
|
|
|
815
878
|
});
|
|
816
879
|
return listOptions;
|
|
817
880
|
}
|
|
818
|
-
|
|
881
|
+
/** This method is for the computed property elementOptions */
|
|
819
882
|
getElementOptions() {
|
|
820
883
|
const options = deepClone(this.props.childOptions, ['data']);
|
|
821
884
|
const childOptions = [];
|
|
@@ -846,7 +909,9 @@ class SelecticStore {
|
|
|
846
909
|
});
|
|
847
910
|
return childOptions;
|
|
848
911
|
}
|
|
912
|
+
/** Generate the list of all options by combining the 3 option lists */
|
|
849
913
|
buildAllOptions(keepFetched = false, stopFetch = false) {
|
|
914
|
+
debug('buildAllOptions', 'start', 'keepFetched', keepFetched, 'stopFetch', stopFetch);
|
|
850
915
|
const allOptions = [];
|
|
851
916
|
let listOptions = [];
|
|
852
917
|
let elementOptions = [];
|
|
@@ -918,8 +983,6 @@ class SelecticStore {
|
|
|
918
983
|
}
|
|
919
984
|
}
|
|
920
985
|
if (!stopFetch) {
|
|
921
|
-
this.state.filteredOptions = [];
|
|
922
|
-
this.state.totalFilteredOptions = Infinity;
|
|
923
986
|
this.buildFilteredOptions().then(() => {
|
|
924
987
|
/* XXX: To recompute for strict mode and auto-select */
|
|
925
988
|
this.assertCorrectValue();
|
|
@@ -935,18 +998,21 @@ class SelecticStore {
|
|
|
935
998
|
const options = this.filterOptions(allOptions, search);
|
|
936
999
|
this.setFilteredOptions(options);
|
|
937
1000
|
}
|
|
1001
|
+
debug('buildAllOptions', 'end', 'allOptions:', this.state.allOptions.length, 'totalAllOptions:', this.state.totalAllOptions);
|
|
938
1002
|
}
|
|
939
1003
|
async buildFilteredOptions() {
|
|
940
|
-
|
|
1004
|
+
const state = this.state;
|
|
1005
|
+
if (!state.isOpen) {
|
|
941
1006
|
/* Do not try to fetch anything while the select is not open */
|
|
942
1007
|
return;
|
|
943
1008
|
}
|
|
944
|
-
const allOptions =
|
|
945
|
-
const search =
|
|
946
|
-
const totalAllOptions =
|
|
1009
|
+
const allOptions = state.allOptions;
|
|
1010
|
+
const search = state.searchText;
|
|
1011
|
+
const totalAllOptions = state.totalAllOptions;
|
|
947
1012
|
const allOptionsLength = allOptions.length;
|
|
948
|
-
let filteredOptionsLength =
|
|
1013
|
+
let filteredOptionsLength = state.filteredOptions.length;
|
|
949
1014
|
const hasAllItems = unref(this.hasAllItems);
|
|
1015
|
+
debug('buildFilteredOptions', 'start', 'hasAllItems:', hasAllItems, 'allOptions', allOptions.length, 'search:', search, 'filteredOptionsLength:', filteredOptionsLength);
|
|
950
1016
|
if (hasAllItems) {
|
|
951
1017
|
/* Everything has already been fetched and stored in filteredOptions */
|
|
952
1018
|
return;
|
|
@@ -963,16 +1029,17 @@ class SelecticStore {
|
|
|
963
1029
|
return;
|
|
964
1030
|
}
|
|
965
1031
|
/* When we only have partial options */
|
|
966
|
-
const offsetItem =
|
|
1032
|
+
const offsetItem = state.offsetItem;
|
|
967
1033
|
const marginSize = unref(this.marginSize);
|
|
968
1034
|
const endIndex = offsetItem + marginSize;
|
|
1035
|
+
debug('buildFilteredOptions', 'partial options', 'offsetItem:', offsetItem, 'marginSize:', marginSize, 'filteredOptionsLength', filteredOptionsLength);
|
|
969
1036
|
if (endIndex <= filteredOptionsLength) {
|
|
970
1037
|
return;
|
|
971
1038
|
}
|
|
972
1039
|
if (!search && endIndex <= allOptionsLength) {
|
|
973
|
-
this.setFilteredOptions(this.buildGroupItems(allOptions), false, totalAllOptions +
|
|
1040
|
+
this.setFilteredOptions(this.buildGroupItems(allOptions), false, totalAllOptions + state.groups.size);
|
|
974
1041
|
const isPartial = unref(this.isPartial);
|
|
975
|
-
if (isPartial &&
|
|
1042
|
+
if (isPartial && state.totalDynOptions === Infinity) {
|
|
976
1043
|
this.fetchData();
|
|
977
1044
|
}
|
|
978
1045
|
return;
|
|
@@ -985,6 +1052,7 @@ class SelecticStore {
|
|
|
985
1052
|
return;
|
|
986
1053
|
}
|
|
987
1054
|
}
|
|
1055
|
+
debug('buildFilteredOptions', 'end', '(will call fetchData)', this.state.filteredOptions.length);
|
|
988
1056
|
await this.fetchData();
|
|
989
1057
|
}
|
|
990
1058
|
async buildSelectedOptions() {
|
|
@@ -1038,6 +1106,39 @@ class SelecticStore {
|
|
|
1038
1106
|
state.selectedOptions = items[0];
|
|
1039
1107
|
}
|
|
1040
1108
|
}
|
|
1109
|
+
async fetchRequest(fetchCallback, search, offset, limit) {
|
|
1110
|
+
const searchRqId = ++this.requestSearchId;
|
|
1111
|
+
if (!search) {
|
|
1112
|
+
++this.requestId;
|
|
1113
|
+
}
|
|
1114
|
+
const requestId = this.requestId;
|
|
1115
|
+
debug('fetchRequest', 'start', 'search:', search, 'offset:', offset, 'limit:', limit, 'requestId:', requestId, 'requestSearchId:', searchRqId, 'isRequesting:', this.isRequesting);
|
|
1116
|
+
if (this.isRequesting) {
|
|
1117
|
+
debug('fetchRequest', `await ${DEBOUNCE_REQUEST}ms`);
|
|
1118
|
+
/* debounce the call to avoid sending too much requests */
|
|
1119
|
+
await new Promise((resolve) => {
|
|
1120
|
+
setTimeout(resolve, DEBOUNCE_REQUEST);
|
|
1121
|
+
});
|
|
1122
|
+
/* Check if there are other requested requests, in such case drop this one */
|
|
1123
|
+
if (requestId !== this.requestId || (search && searchRqId !== this.requestSearchId)) {
|
|
1124
|
+
debug('fetchRequest', '××deprecated××', requestId, searchRqId);
|
|
1125
|
+
return false;
|
|
1126
|
+
}
|
|
1127
|
+
}
|
|
1128
|
+
this.isRequesting = true;
|
|
1129
|
+
const response = await fetchCallback(search, offset, limit);
|
|
1130
|
+
/* Check if request is obsolete */
|
|
1131
|
+
if (requestId !== this.requestId || (search && searchRqId !== this.requestSearchId)) {
|
|
1132
|
+
debug('fetchRequest', '×××deprecated×××', requestId, searchRqId);
|
|
1133
|
+
return false;
|
|
1134
|
+
}
|
|
1135
|
+
this.isRequesting = false;
|
|
1136
|
+
const deprecated = searchRqId !== this.requestSearchId;
|
|
1137
|
+
debug('fetchRequest', 'end', response.result.length, response.total, deprecated);
|
|
1138
|
+
return Object.assign(Object.assign({}, response), {
|
|
1139
|
+
/* this is to fulfill the cache */
|
|
1140
|
+
deprecated: deprecated });
|
|
1141
|
+
}
|
|
1041
1142
|
async fetchData() {
|
|
1042
1143
|
const state = this.state;
|
|
1043
1144
|
const labels = this.data.labels;
|
|
@@ -1059,9 +1160,14 @@ class SelecticStore {
|
|
|
1059
1160
|
const offset = filteredOptionsLength - this.nbGroups(state.filteredOptions) - dynOffset;
|
|
1060
1161
|
const nbItems = endIndex - offset;
|
|
1061
1162
|
const limit = Math.ceil(nbItems / pageSize) * pageSize;
|
|
1163
|
+
debug('fetchData', 'start', 'search:', search, 'offset:', offset, 'limit:', limit);
|
|
1062
1164
|
try {
|
|
1063
|
-
const
|
|
1064
|
-
|
|
1165
|
+
const response = await this.fetchRequest(fetchCallback, search, offset, limit);
|
|
1166
|
+
if (!response) {
|
|
1167
|
+
debug('fetchData', '×× deprecated ××', search, offset, limit);
|
|
1168
|
+
return;
|
|
1169
|
+
}
|
|
1170
|
+
const { total: rTotal, result, deprecated } = response;
|
|
1065
1171
|
let total = rTotal;
|
|
1066
1172
|
let errorMessage = '';
|
|
1067
1173
|
/* Assert result is correctly formatted */
|
|
@@ -1079,11 +1185,12 @@ class SelecticStore {
|
|
|
1079
1185
|
if (!search) {
|
|
1080
1186
|
/* update cache */
|
|
1081
1187
|
state.totalDynOptions = total;
|
|
1082
|
-
const old = state.dynOptions.splice(offset,
|
|
1188
|
+
const old = state.dynOptions.splice(offset, result.length, ...result);
|
|
1083
1189
|
if (compareOptions(old, result)) {
|
|
1084
1190
|
/* Added options are the same as previous ones.
|
|
1085
1191
|
* Stop fetching to avoid infinite loop
|
|
1086
1192
|
*/
|
|
1193
|
+
debug('fetchData', 'no new values');
|
|
1087
1194
|
if (!unref(this.hasFetchedAllItems)) {
|
|
1088
1195
|
/* Display error if all items are not fetch
|
|
1089
1196
|
* We can have the case where old value and result
|
|
@@ -1091,14 +1198,21 @@ class SelecticStore {
|
|
|
1091
1198
|
* total is 0 */
|
|
1092
1199
|
errorMessage = labels.wrongQueryResult;
|
|
1093
1200
|
}
|
|
1094
|
-
setTimeout(() =>
|
|
1201
|
+
setTimeout(() => {
|
|
1202
|
+
debug('fetchData', 'before buildAllOptions (stopped)', 'offsetItem:', this.state.offsetItem, 'allOptions:', this.state.allOptions.length);
|
|
1203
|
+
this.buildAllOptions(true, true);
|
|
1204
|
+
}, 0);
|
|
1095
1205
|
}
|
|
1096
1206
|
else {
|
|
1097
|
-
setTimeout(() =>
|
|
1207
|
+
setTimeout(() => {
|
|
1208
|
+
debug('fetchData', 'before buildAllOptions', 'offsetItem:', this.state.offsetItem, 'allOptions:', this.state.allOptions.length);
|
|
1209
|
+
this.buildAllOptions(true);
|
|
1210
|
+
}, 0);
|
|
1098
1211
|
}
|
|
1099
1212
|
}
|
|
1100
|
-
/* Check request is not obsolete */
|
|
1101
|
-
if (
|
|
1213
|
+
/* Check request (without search) is not obsolete */
|
|
1214
|
+
if (deprecated) {
|
|
1215
|
+
debug('fetchData', '××× deprecated ×××', search, offset, limit);
|
|
1102
1216
|
return;
|
|
1103
1217
|
}
|
|
1104
1218
|
if (!search) {
|
|
@@ -1127,14 +1241,17 @@ class SelecticStore {
|
|
|
1127
1241
|
}
|
|
1128
1242
|
catch (e) {
|
|
1129
1243
|
state.status.errorMessage = e.message;
|
|
1244
|
+
debug('fetchData', 'error', e.message);
|
|
1130
1245
|
if (!search) {
|
|
1131
1246
|
state.totalDynOptions = 0;
|
|
1132
1247
|
this.buildAllOptions(true, true);
|
|
1133
1248
|
}
|
|
1134
1249
|
}
|
|
1135
1250
|
this.state.status.searching = false;
|
|
1251
|
+
debug('fetchData', 'end');
|
|
1136
1252
|
}
|
|
1137
1253
|
filterOptions(options, search) {
|
|
1254
|
+
debug('filterOptions', 'start', 'options:', options.length, 'search:', search);
|
|
1138
1255
|
if (!search) {
|
|
1139
1256
|
return this.buildGroupItems(options);
|
|
1140
1257
|
}
|
|
@@ -1145,6 +1262,7 @@ class SelecticStore {
|
|
|
1145
1262
|
addStaticFilteredOptions(fromDynamic = false) {
|
|
1146
1263
|
const search = this.state.searchText;
|
|
1147
1264
|
let continueLoop = fromDynamic;
|
|
1265
|
+
debug('addStaticFilteredOptions', 'start', 'fromDynamic:', fromDynamic, 'optionBehaviorOperation:', this.state.optionBehaviorOperation);
|
|
1148
1266
|
if (this.state.optionBehaviorOperation !== 'sort') {
|
|
1149
1267
|
return;
|
|
1150
1268
|
}
|
|
@@ -1170,6 +1288,7 @@ class SelecticStore {
|
|
|
1170
1288
|
}
|
|
1171
1289
|
this.setFilteredOptions(options, true);
|
|
1172
1290
|
}
|
|
1291
|
+
debug('addStaticFilteredOptions', 'end');
|
|
1173
1292
|
}
|
|
1174
1293
|
buildSelectedItems(ids) {
|
|
1175
1294
|
return this.buildItems(ids.map((id) => {
|
|
@@ -1211,6 +1330,7 @@ class SelecticStore {
|
|
|
1211
1330
|
}
|
|
1212
1331
|
buildGroupItems(options, previousItem) {
|
|
1213
1332
|
let previousGroupId = previousItem && previousItem.group;
|
|
1333
|
+
debug('buildGroupItems', 'start', 'options:', options.length, 'previousGroupId:', previousGroupId);
|
|
1214
1334
|
const list = this.buildItems(options).reduce((items, item) => {
|
|
1215
1335
|
if (item.group !== previousGroupId) {
|
|
1216
1336
|
const groupId = item.group;
|
|
@@ -1227,6 +1347,7 @@ class SelecticStore {
|
|
|
1227
1347
|
items.push(item);
|
|
1228
1348
|
return items;
|
|
1229
1349
|
}, []);
|
|
1350
|
+
debug('buildGroupItems', 'end', list.length);
|
|
1230
1351
|
return list;
|
|
1231
1352
|
}
|
|
1232
1353
|
buildOptionBehavior(optionBehavior, state) {
|
|
@@ -1277,15 +1398,23 @@ class SelecticStore {
|
|
|
1277
1398
|
if (doNotCheck || !hasFetchedAllItems) {
|
|
1278
1399
|
return;
|
|
1279
1400
|
}
|
|
1401
|
+
const selectedOptions = state.selectedOptions;
|
|
1280
1402
|
const enabledOptions = state.allOptions.filter((opt) => !opt.disabled);
|
|
1281
|
-
const
|
|
1403
|
+
const nbEnabled = enabledOptions.length;
|
|
1282
1404
|
const value = state.internalValue;
|
|
1283
1405
|
const hasValue = Array.isArray(value) ? value.length > 0 : value !== null;
|
|
1284
|
-
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)) :
|
|
1285
1410
|
this.hasValue(value));
|
|
1286
|
-
const isEmpty =
|
|
1287
|
-
const hasOnlyOneOption =
|
|
1288
|
-
|
|
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) {
|
|
1289
1418
|
if (state.isOpen) {
|
|
1290
1419
|
this.setAutomaticClose();
|
|
1291
1420
|
this.commit('isOpen', false);
|
|
@@ -1344,6 +1473,7 @@ class SelecticStore {
|
|
|
1344
1473
|
}
|
|
1345
1474
|
/** assign new value to the filteredOptions and apply change depending on it */
|
|
1346
1475
|
setFilteredOptions(options, add = false, length = 0) {
|
|
1476
|
+
debug('setFilteredOptions', 'start', 'options:', options.length, 'add', add, 'length', length);
|
|
1347
1477
|
if (!add) {
|
|
1348
1478
|
this.state.filteredOptions = options;
|
|
1349
1479
|
this.state.totalFilteredOptions = length || options.length;
|
|
@@ -1704,6 +1834,18 @@ let MainInput = class MainInput extends Vue {
|
|
|
1704
1834
|
? Array.isArray(value) && value.length > 0
|
|
1705
1835
|
: value !== null;
|
|
1706
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
|
+
}
|
|
1707
1849
|
get displayPlaceholder() {
|
|
1708
1850
|
const placeholder = this.store.state.placeholder;
|
|
1709
1851
|
const hasValue = this.hasValue;
|
|
@@ -1722,10 +1864,12 @@ let MainInput = class MainInput extends Vue {
|
|
|
1722
1864
|
const state = this.store.state;
|
|
1723
1865
|
const isMultiple = state.multiple;
|
|
1724
1866
|
const value = state.internalValue;
|
|
1725
|
-
const
|
|
1867
|
+
const nbSelection = (Array.isArray(value) && value.length) || 0;
|
|
1868
|
+
const hasOnlyOneValue = nbSelection === 1;
|
|
1869
|
+
const hasOnlyDisabled = nbSelection <= this.disabledList.length;
|
|
1726
1870
|
/* Should not display the clear action if there is only one selected
|
|
1727
1871
|
* item in multiple (as this item has already its remove icon) */
|
|
1728
|
-
return !isMultiple || !hasOnlyOneValue;
|
|
1872
|
+
return !isMultiple || !hasOnlyOneValue || !hasOnlyDisabled;
|
|
1729
1873
|
}
|
|
1730
1874
|
get clearedLabel() {
|
|
1731
1875
|
const isMultiple = this.store.state.multiple;
|
|
@@ -1843,6 +1987,9 @@ let MainInput = class MainInput extends Vue {
|
|
|
1843
1987
|
/* Check if there is enough space to display items like there are
|
|
1844
1988
|
* currently shown */
|
|
1845
1989
|
const el = this.$refs.selectedItems;
|
|
1990
|
+
if (!el) {
|
|
1991
|
+
return;
|
|
1992
|
+
}
|
|
1846
1993
|
const parentEl = el.parentElement;
|
|
1847
1994
|
if (!document.contains(parentEl)) {
|
|
1848
1995
|
/* The element is currently not in DOM */
|
|
@@ -1941,7 +2088,7 @@ let MainInput = class MainInput extends Vue {
|
|
|
1941
2088
|
click: () => this.$emit('item:click', item.id),
|
|
1942
2089
|
} },
|
|
1943
2090
|
h("span", { class: "selectic-input__selected-items__value" }, item.text),
|
|
1944
|
-
!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: {
|
|
1945
2092
|
'click.prevent.stop': () => this.selectItem(item.id),
|
|
1946
2093
|
} }))))),
|
|
1947
2094
|
this.moreSelectedNb && (h("div", { class: "single-value more-items", title: this.moreSelectedTitle }, this.moreSelectedNb)))),
|
|
@@ -2695,7 +2842,8 @@ let Selectic = class Selectic extends Vue {
|
|
|
2695
2842
|
const store = this.store;
|
|
2696
2843
|
const keepOpenWithOtherSelectic = this.params.keepOpenWithOtherSelectic;
|
|
2697
2844
|
const extendedList = this.$refs.extendedList;
|
|
2698
|
-
|
|
2845
|
+
const extendedListEl = extendedList === null || extendedList === void 0 ? void 0 : extendedList.$el;
|
|
2846
|
+
if (!extendedListEl) {
|
|
2699
2847
|
/* this component is not focused anymore */
|
|
2700
2848
|
if (!keepOpenWithOtherSelectic) {
|
|
2701
2849
|
this.removeListeners();
|
|
@@ -2704,7 +2852,7 @@ let Selectic = class Selectic extends Vue {
|
|
|
2704
2852
|
return;
|
|
2705
2853
|
}
|
|
2706
2854
|
const target = evt.target;
|
|
2707
|
-
if (!
|
|
2855
|
+
if (!extendedListEl.contains(target) && !this.$el.contains(target)) {
|
|
2708
2856
|
store.commit('isOpen', false);
|
|
2709
2857
|
}
|
|
2710
2858
|
};
|
|
@@ -2797,14 +2945,23 @@ let Selectic = class Selectic extends Vue {
|
|
|
2797
2945
|
/* }}} */
|
|
2798
2946
|
/* {{{ private methods */
|
|
2799
2947
|
computeWidth() {
|
|
2800
|
-
|
|
2801
|
-
|
|
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;
|
|
2802
2957
|
}
|
|
2803
2958
|
computeOffset(doNotAddListener = false) {
|
|
2804
|
-
|
|
2959
|
+
var _a;
|
|
2960
|
+
const mainInput = (_a = this.$refs) === null || _a === void 0 ? void 0 : _a.mainInput;
|
|
2805
2961
|
const mainEl = mainInput === null || mainInput === void 0 ? void 0 : mainInput.$el;
|
|
2806
2962
|
if (!mainEl) {
|
|
2807
|
-
/* 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) */
|
|
2808
2965
|
return;
|
|
2809
2966
|
}
|
|
2810
2967
|
const _elementsListeners = this._elementsListeners;
|
|
@@ -2938,13 +3095,14 @@ let Selectic = class Selectic extends Vue {
|
|
|
2938
3095
|
checkFocus() {
|
|
2939
3096
|
/* Await that focused element becomes active */
|
|
2940
3097
|
setTimeout(() => {
|
|
3098
|
+
var _a;
|
|
2941
3099
|
const focusedEl = document.activeElement;
|
|
2942
|
-
const extendedList = this.$refs.extendedList;
|
|
3100
|
+
const extendedList = (_a = this.$refs) === null || _a === void 0 ? void 0 : _a.extendedList;
|
|
2943
3101
|
/* check if there is a focused element (if none the body is
|
|
2944
3102
|
* selected) and if it is inside current Selectic */
|
|
2945
3103
|
if (focusedEl === document.body
|
|
2946
3104
|
|| this.$el.contains(focusedEl)
|
|
2947
|
-
|| (extendedList
|
|
3105
|
+
|| (extendedList === null || extendedList === void 0 ? void 0 : extendedList.$el.contains(focusedEl))) {
|
|
2948
3106
|
return;
|
|
2949
3107
|
}
|
|
2950
3108
|
this.store.commit('isOpen', false);
|
package/doc/breakingChanges.md
CHANGED
|
@@ -7,6 +7,14 @@ version which want to upgrade them to latest version.
|
|
|
7
7
|
|
|
8
8
|
**This is not something you have to read to understand and to use Selectic.**
|
|
9
9
|
|
|
10
|
+
## 3.0.x → 3.1.x
|
|
11
|
+
|
|
12
|
+
Selectic no more depends on Font-awesome. It embeds its own icons (from Material Design Icons).
|
|
13
|
+
|
|
14
|
+
It is still possible to use Font-awesome icons (or from any other libraries).
|
|
15
|
+
|
|
16
|
+
Read [the documentation section related to changing icons](./changeIcons.md) for more information on how to handle them.
|
|
17
|
+
|
|
10
18
|
## 1.3.x → 3.x
|
|
11
19
|
|
|
12
20
|
### Vue2 → Vue3
|
package/doc/changeIcons.md
CHANGED
|
@@ -5,10 +5,10 @@
|
|
|
5
5
|
There are some icons in selectic. But sometimes it is useful to change them (because you want to use yours or the same of your favorite theme).
|
|
6
6
|
|
|
7
7
|
There are 3 ways to changes these icons:
|
|
8
|
-
* Call the static `changeIcons()` method. It changes icons for all selectic components.
|
|
8
|
+
* Call the static `changeIcons(icons, iconFamily)` method. It changes icons for all selectic components.
|
|
9
9
|
* Change the `icons` property. It changes icons only for the component.
|
|
10
10
|
* Change the `iconFamily` property. It changes the icons origin only for the component.
|
|
11
|
-
* Call the `changeIcons()` method on the component. It changes icons only for the component.
|
|
11
|
+
* Call the `changeIcons(icons, iconFamily)` method on the component. It changes icons only for the component.
|
|
12
12
|
|
|
13
13
|
_Changes made locally take precedence over changes made globally_.
|
|
14
14
|
|
|
@@ -116,3 +116,9 @@ this.$refs.selectic.changeIcons({
|
|
|
116
116
|
* <span class="fa fa-thumbs-o-up"></span>
|
|
117
117
|
*/
|
|
118
118
|
```
|
|
119
|
+
|
|
120
|
+
It is possible to change only the icon family:
|
|
121
|
+
```javascript
|
|
122
|
+
// change icons for all selectic components to use FA-6 icons
|
|
123
|
+
Selectic.changeIcons(null, 'font-awesome-6');
|
|
124
|
+
```
|