selectic 3.0.17 → 3.0.19

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.
@@ -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 z-index: 2000;\n height: auto;\n background-color: var(--selectic-bg, #ffffff);\n box-shadow: 2px 5px 12px 0px #888888;\n border-radius: 0 0 4px 4px;\n padding: 0;\n min-width: 200px;\n}\n.selectic__extended-list__list-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.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/* }}} */\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\n.selectic-item__disabled {\n color: var(--selectic-color-disabled);\n background-color: var(--selectic-bg-disabled);\n}\n\n.selectic-item__is-in-group {\n padding-left: 2em;\n}\n\n.selectic-item__is-group {\n font-weight: bold;\n cursor: default;\n}\n\n.selectic-item.selected {\n color: var(--selectic-selected-item-color);\n}\n.selectic-search-scope {\n color: #e0e0e0;\n left: auto;\n right: 10px;\n}\n.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/* }}} */\n";
36
36
  styleInject(css_248z);
37
37
 
38
38
  /**
@@ -101,11 +101,12 @@ function assignObject(obj, ...sourceObjects) {
101
101
  const result = obj;
102
102
  for (const source of sourceObjects) {
103
103
  for (const key of Object.keys(source)) {
104
- const value = source[key];
104
+ const typedKey = key;
105
+ const value = source[typedKey];
105
106
  if (value === undefined) {
106
107
  continue;
107
108
  }
108
- result[key] = value;
109
+ result[typedKey] = value;
109
110
  }
110
111
  }
111
112
  return result;
@@ -182,6 +183,7 @@ class SelecticStore {
182
183
  isOpen: false,
183
184
  searchText: '',
184
185
  selectionIsExcluded: false,
186
+ forceSelectAll: 'auto',
185
187
  allOptions: [],
186
188
  dynOptions: [],
187
189
  filteredOptions: [],
@@ -1405,7 +1407,7 @@ let MainInput = class MainInput extends vtyx.Vue {
1405
1407
  }
1406
1408
  /* }}} */
1407
1409
  render() {
1408
- return (vtyx.h("div", { class: "has-feedback", on: {
1410
+ return (vtyx.h("div", { class: "selectic-container has-feedback", on: {
1409
1411
  'click.prevent.stop': () => this.toggleFocus(),
1410
1412
  } },
1411
1413
  vtyx.h("div", { id: this.selecticId, class: ['selectic-input form-control',
@@ -1477,14 +1479,31 @@ let FilterPanel = class FilterPanel extends vtyx.Vue {
1477
1479
  get selectionIsExcluded() {
1478
1480
  return this.store.state.selectionIsExcluded;
1479
1481
  }
1482
+ /* {{{ select all */
1483
+ get hasNotAllItems() {
1484
+ return !vue.unref(this.store.hasAllItems);
1485
+ }
1486
+ get disabledPartialData() {
1487
+ const state = this.store.state;
1488
+ const autoDisplay = state.forceSelectAll === 'auto';
1489
+ return this.hasNotAllItems && !this.enableRevert && autoDisplay;
1490
+ }
1480
1491
  get disableSelectAll() {
1481
1492
  const store = this.store;
1482
1493
  const state = store.state;
1483
1494
  const isMultiple = state.multiple;
1484
- const hasItems = state.filteredOptions.length === 0;
1485
- const canNotSelect = !!state.searchText && !vue.unref(store.hasAllItems);
1486
- return !isMultiple || hasItems || canNotSelect;
1495
+ const hasNoItems = state.filteredOptions.length === 0;
1496
+ const canNotSelect = this.hasNotAllItems && !!state.searchText;
1497
+ const partialDataDsbld = this.disabledPartialData;
1498
+ return !isMultiple || hasNoItems || canNotSelect || partialDataDsbld;
1499
+ }
1500
+ get titleSelectAll() {
1501
+ if (this.disableSelectAll && this.disabledPartialData) {
1502
+ return this.store.data.labels.cannotSelectAllRevertItems;
1503
+ }
1504
+ return '';
1487
1505
  }
1506
+ /* }}} */
1488
1507
  get disableRevert() {
1489
1508
  const store = this.store;
1490
1509
  return !store.state.multiple || !vue.unref(store.hasFetchedAllItems);
@@ -1572,7 +1591,7 @@ let FilterPanel = class FilterPanel extends vtyx.Vue {
1572
1591
  vtyx.h("label", { class: ['control-label', {
1573
1592
  'selectic__label-disabled': this.disableSelectAll,
1574
1593
  }] },
1575
- vtyx.h("input", { type: "checkbox", checked: state.status.areAllSelected, disabled: this.disableSelectAll, on: {
1594
+ vtyx.h("input", { type: "checkbox", checked: state.status.areAllSelected, disabled: this.disableSelectAll, title: this.titleSelectAll, on: {
1576
1595
  change: this.onSelectAll,
1577
1596
  } }),
1578
1597
  labels.selectAll))),
@@ -1832,6 +1851,10 @@ var __decorate$1 = (this && this.__decorate) || function (decorators, target, ke
1832
1851
  else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
1833
1852
  return c > 3 && r && Object.defineProperty(target, key, r), r;
1834
1853
  };
1854
+ /* list estimation height
1855
+ * 30px × 10 + 20px (for panel header)
1856
+ */
1857
+ const DEFAULT_LIST_HEIGHT = 320;
1835
1858
  let ExtendedList = class ExtendedList extends vtyx.Vue {
1836
1859
  constructor() {
1837
1860
  /* {{{ props */
@@ -1839,11 +1862,18 @@ let ExtendedList = class ExtendedList extends vtyx.Vue {
1839
1862
  /* }}} */
1840
1863
  /* {{{ data */
1841
1864
  this.topGroup = ' ';
1842
- this.listHeight = 120;
1865
+ this.listHeight = 0;
1843
1866
  this.listWidth = 200;
1867
+ this.availableSpace = 0;
1844
1868
  }
1845
1869
  /* }}} */
1846
1870
  /* {{{ computed */
1871
+ /** check if the height of the box has been completely estimated. */
1872
+ get isFullyEstimated() {
1873
+ const listHeight = this.listHeight;
1874
+ const availableSpace = this.availableSpace;
1875
+ return listHeight !== 0 && listHeight < availableSpace;
1876
+ }
1847
1877
  get searchingLabel() {
1848
1878
  return this.store.data.labels.searching;
1849
1879
  }
@@ -1904,17 +1934,30 @@ let ExtendedList = class ExtendedList extends vtyx.Vue {
1904
1934
  }
1905
1935
  get bestPosition() {
1906
1936
  const windowHeight = window.innerHeight;
1907
- const listHeight = this.listHeight;
1937
+ const isFullyEstimated = this.isFullyEstimated;
1938
+ /* XXX: The max() is because if listHeight is greater than default,
1939
+ * it means that the value is more accurate than the default. */
1940
+ const listHeight = isFullyEstimated ? this.listHeight
1941
+ : Math.max(DEFAULT_LIST_HEIGHT, this.listHeight);
1908
1942
  const inputTop = this.elementTop;
1909
1943
  const inputBottom = this.elementBottom;
1910
- if (inputBottom + listHeight <= windowHeight) {
1944
+ const availableTop = inputTop;
1945
+ const availableBottom = windowHeight - inputBottom;
1946
+ if (listHeight < availableBottom) {
1911
1947
  return 'bottom';
1912
1948
  }
1913
- if (listHeight < inputTop) {
1949
+ if (listHeight < availableTop) {
1914
1950
  return 'top';
1915
1951
  }
1916
1952
  /* There are not enough space neither at bottom nor at top */
1917
- return (windowHeight - inputBottom) < inputTop ? 'top' : 'bottom';
1953
+ return availableBottom < availableTop ? 'top' : 'bottom';
1954
+ }
1955
+ get position() {
1956
+ const listPosition = this.store.state.listPosition;
1957
+ if (listPosition === 'auto') {
1958
+ return this.bestPosition;
1959
+ }
1960
+ return listPosition;
1918
1961
  }
1919
1962
  get horizontalStyle() {
1920
1963
  const windowWidth = window.innerWidth;
@@ -1934,26 +1977,32 @@ let ExtendedList = class ExtendedList extends vtyx.Vue {
1934
1977
  return `left: ${inputLeft}px; min-width: unset;`;
1935
1978
  }
1936
1979
  get positionStyle() {
1937
- let listPosition = this.store.state.listPosition;
1980
+ const listPosition = this.position;
1938
1981
  const horizontalStyle = this.horizontalStyle;
1939
- if (listPosition === 'auto') {
1940
- listPosition = this.bestPosition;
1941
- }
1982
+ const width = this.width;
1942
1983
  if (listPosition === 'top') {
1943
1984
  const transform = horizontalStyle.includes('transform')
1944
1985
  ? 'transform: translateX(-100%) translateY(-100%);'
1945
1986
  : 'transform: translateY(-100%);';
1987
+ const elementTop = this.elementTop;
1988
+ const availableSpace = this.elementTop;
1989
+ this.availableSpace = availableSpace;
1946
1990
  return `
1947
- top: ${this.elementTop}px;
1991
+ --top-position: ${elementTop}px;
1948
1992
  ${horizontalStyle}
1949
- width: ${this.width}px;
1950
- ${transform}
1993
+ --list-width: ${width}px;
1994
+ ${transform};
1995
+ --availableSpace: ${availableSpace}px;
1951
1996
  `;
1952
1997
  }
1998
+ const elementBottom = this.elementBottom;
1999
+ const availableSpace = window.innerHeight - elementBottom;
2000
+ this.availableSpace = availableSpace;
1953
2001
  return `
1954
- top: ${this.elementBottom}px;
2002
+ --top-position: ${elementBottom}px;
1955
2003
  ${horizontalStyle}
1956
- width: ${this.width}px;
2004
+ --list-width: ${width}px;
2005
+ --availableSpace: ${availableSpace}px;
1957
2006
  `;
1958
2007
  }
1959
2008
  /* }}} */
@@ -1996,7 +2045,10 @@ let ExtendedList = class ExtendedList extends vtyx.Vue {
1996
2045
  const state = store.state;
1997
2046
  const isGroup = state.groups.size > 0 &&
1998
2047
  state.totalFilteredOptions > store.data.itemsPerPage;
1999
- return (vtyx.h("div", { style: this.positionStyle, class: "selectic selectic__extended-list" },
2048
+ return (vtyx.h("div", { style: this.positionStyle, class: [
2049
+ 'selectic selectic__extended-list',
2050
+ `selectic-position-${this.position}`,
2051
+ ] },
2000
2052
  !state.hideFilter && (vtyx.h(Filter, { store: this.store })),
2001
2053
  isGroup && (vtyx.h("span", { class: "selectic-item selectic-item--header selectic-item__is-group" }, this.topGroup)),
2002
2054
  vtyx.h(List$1, { store: store, on: {
@@ -2463,6 +2515,7 @@ let Selectic = class Selectic extends vtyx.Vue {
2463
2515
  pageSize: this.params.pageSize || 100,
2464
2516
  hideFilter: (_b = this.params.hideFilter) !== null && _b !== void 0 ? _b : 'auto',
2465
2517
  allowRevert: this.params.allowRevert,
2518
+ forceSelectAll: this.params.forceSelectAll || 'auto',
2466
2519
  allowClearSelection: this.params.allowClearSelection || false,
2467
2520
  autoSelect: this.params.autoSelect === undefined
2468
2521
  ? !this.multiple && !this.params.fetchCallback
@@ -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 z-index: 2000;\n height: auto;\n background-color: var(--selectic-bg, #ffffff);\n box-shadow: 2px 5px 12px 0px #888888;\n border-radius: 0 0 4px 4px;\n padding: 0;\n min-width: 200px;\n}\n.selectic__extended-list__list-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.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/* }}} */\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\n.selectic-item__disabled {\n color: var(--selectic-color-disabled);\n background-color: var(--selectic-bg-disabled);\n}\n\n.selectic-item__is-in-group {\n padding-left: 2em;\n}\n\n.selectic-item__is-group {\n font-weight: bold;\n cursor: default;\n}\n\n.selectic-item.selected {\n color: var(--selectic-selected-item-color);\n}\n.selectic-search-scope {\n color: #e0e0e0;\n left: auto;\n right: 10px;\n}\n.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/* }}} */\n";
32
32
  styleInject(css_248z);
33
33
 
34
34
  /**
@@ -97,11 +97,12 @@ function assignObject(obj, ...sourceObjects) {
97
97
  const result = obj;
98
98
  for (const source of sourceObjects) {
99
99
  for (const key of Object.keys(source)) {
100
- const value = source[key];
100
+ const typedKey = key;
101
+ const value = source[typedKey];
101
102
  if (value === undefined) {
102
103
  continue;
103
104
  }
104
- result[key] = value;
105
+ result[typedKey] = value;
105
106
  }
106
107
  }
107
108
  return result;
@@ -178,6 +179,7 @@ class SelecticStore {
178
179
  isOpen: false,
179
180
  searchText: '',
180
181
  selectionIsExcluded: false,
182
+ forceSelectAll: 'auto',
181
183
  allOptions: [],
182
184
  dynOptions: [],
183
185
  filteredOptions: [],
@@ -1401,7 +1403,7 @@ let MainInput = class MainInput extends Vue {
1401
1403
  }
1402
1404
  /* }}} */
1403
1405
  render() {
1404
- return (h("div", { class: "has-feedback", on: {
1406
+ return (h("div", { class: "selectic-container has-feedback", on: {
1405
1407
  'click.prevent.stop': () => this.toggleFocus(),
1406
1408
  } },
1407
1409
  h("div", { id: this.selecticId, class: ['selectic-input form-control',
@@ -1473,14 +1475,31 @@ let FilterPanel = class FilterPanel extends Vue {
1473
1475
  get selectionIsExcluded() {
1474
1476
  return this.store.state.selectionIsExcluded;
1475
1477
  }
1478
+ /* {{{ select all */
1479
+ get hasNotAllItems() {
1480
+ return !unref(this.store.hasAllItems);
1481
+ }
1482
+ get disabledPartialData() {
1483
+ const state = this.store.state;
1484
+ const autoDisplay = state.forceSelectAll === 'auto';
1485
+ return this.hasNotAllItems && !this.enableRevert && autoDisplay;
1486
+ }
1476
1487
  get disableSelectAll() {
1477
1488
  const store = this.store;
1478
1489
  const state = store.state;
1479
1490
  const isMultiple = state.multiple;
1480
- const hasItems = state.filteredOptions.length === 0;
1481
- const canNotSelect = !!state.searchText && !unref(store.hasAllItems);
1482
- return !isMultiple || hasItems || canNotSelect;
1491
+ const hasNoItems = state.filteredOptions.length === 0;
1492
+ const canNotSelect = this.hasNotAllItems && !!state.searchText;
1493
+ const partialDataDsbld = this.disabledPartialData;
1494
+ return !isMultiple || hasNoItems || canNotSelect || partialDataDsbld;
1495
+ }
1496
+ get titleSelectAll() {
1497
+ if (this.disableSelectAll && this.disabledPartialData) {
1498
+ return this.store.data.labels.cannotSelectAllRevertItems;
1499
+ }
1500
+ return '';
1483
1501
  }
1502
+ /* }}} */
1484
1503
  get disableRevert() {
1485
1504
  const store = this.store;
1486
1505
  return !store.state.multiple || !unref(store.hasFetchedAllItems);
@@ -1568,7 +1587,7 @@ let FilterPanel = class FilterPanel extends Vue {
1568
1587
  h("label", { class: ['control-label', {
1569
1588
  'selectic__label-disabled': this.disableSelectAll,
1570
1589
  }] },
1571
- h("input", { type: "checkbox", checked: state.status.areAllSelected, disabled: this.disableSelectAll, on: {
1590
+ h("input", { type: "checkbox", checked: state.status.areAllSelected, disabled: this.disableSelectAll, title: this.titleSelectAll, on: {
1572
1591
  change: this.onSelectAll,
1573
1592
  } }),
1574
1593
  labels.selectAll))),
@@ -1828,6 +1847,10 @@ var __decorate$1 = (this && this.__decorate) || function (decorators, target, ke
1828
1847
  else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
1829
1848
  return c > 3 && r && Object.defineProperty(target, key, r), r;
1830
1849
  };
1850
+ /* list estimation height
1851
+ * 30px × 10 + 20px (for panel header)
1852
+ */
1853
+ const DEFAULT_LIST_HEIGHT = 320;
1831
1854
  let ExtendedList = class ExtendedList extends Vue {
1832
1855
  constructor() {
1833
1856
  /* {{{ props */
@@ -1835,11 +1858,18 @@ let ExtendedList = class ExtendedList extends Vue {
1835
1858
  /* }}} */
1836
1859
  /* {{{ data */
1837
1860
  this.topGroup = ' ';
1838
- this.listHeight = 120;
1861
+ this.listHeight = 0;
1839
1862
  this.listWidth = 200;
1863
+ this.availableSpace = 0;
1840
1864
  }
1841
1865
  /* }}} */
1842
1866
  /* {{{ computed */
1867
+ /** check if the height of the box has been completely estimated. */
1868
+ get isFullyEstimated() {
1869
+ const listHeight = this.listHeight;
1870
+ const availableSpace = this.availableSpace;
1871
+ return listHeight !== 0 && listHeight < availableSpace;
1872
+ }
1843
1873
  get searchingLabel() {
1844
1874
  return this.store.data.labels.searching;
1845
1875
  }
@@ -1900,17 +1930,30 @@ let ExtendedList = class ExtendedList extends Vue {
1900
1930
  }
1901
1931
  get bestPosition() {
1902
1932
  const windowHeight = window.innerHeight;
1903
- const listHeight = this.listHeight;
1933
+ const isFullyEstimated = this.isFullyEstimated;
1934
+ /* XXX: The max() is because if listHeight is greater than default,
1935
+ * it means that the value is more accurate than the default. */
1936
+ const listHeight = isFullyEstimated ? this.listHeight
1937
+ : Math.max(DEFAULT_LIST_HEIGHT, this.listHeight);
1904
1938
  const inputTop = this.elementTop;
1905
1939
  const inputBottom = this.elementBottom;
1906
- if (inputBottom + listHeight <= windowHeight) {
1940
+ const availableTop = inputTop;
1941
+ const availableBottom = windowHeight - inputBottom;
1942
+ if (listHeight < availableBottom) {
1907
1943
  return 'bottom';
1908
1944
  }
1909
- if (listHeight < inputTop) {
1945
+ if (listHeight < availableTop) {
1910
1946
  return 'top';
1911
1947
  }
1912
1948
  /* There are not enough space neither at bottom nor at top */
1913
- return (windowHeight - inputBottom) < inputTop ? 'top' : 'bottom';
1949
+ return availableBottom < availableTop ? 'top' : 'bottom';
1950
+ }
1951
+ get position() {
1952
+ const listPosition = this.store.state.listPosition;
1953
+ if (listPosition === 'auto') {
1954
+ return this.bestPosition;
1955
+ }
1956
+ return listPosition;
1914
1957
  }
1915
1958
  get horizontalStyle() {
1916
1959
  const windowWidth = window.innerWidth;
@@ -1930,26 +1973,32 @@ let ExtendedList = class ExtendedList extends Vue {
1930
1973
  return `left: ${inputLeft}px; min-width: unset;`;
1931
1974
  }
1932
1975
  get positionStyle() {
1933
- let listPosition = this.store.state.listPosition;
1976
+ const listPosition = this.position;
1934
1977
  const horizontalStyle = this.horizontalStyle;
1935
- if (listPosition === 'auto') {
1936
- listPosition = this.bestPosition;
1937
- }
1978
+ const width = this.width;
1938
1979
  if (listPosition === 'top') {
1939
1980
  const transform = horizontalStyle.includes('transform')
1940
1981
  ? 'transform: translateX(-100%) translateY(-100%);'
1941
1982
  : 'transform: translateY(-100%);';
1983
+ const elementTop = this.elementTop;
1984
+ const availableSpace = this.elementTop;
1985
+ this.availableSpace = availableSpace;
1942
1986
  return `
1943
- top: ${this.elementTop}px;
1987
+ --top-position: ${elementTop}px;
1944
1988
  ${horizontalStyle}
1945
- width: ${this.width}px;
1946
- ${transform}
1989
+ --list-width: ${width}px;
1990
+ ${transform};
1991
+ --availableSpace: ${availableSpace}px;
1947
1992
  `;
1948
1993
  }
1994
+ const elementBottom = this.elementBottom;
1995
+ const availableSpace = window.innerHeight - elementBottom;
1996
+ this.availableSpace = availableSpace;
1949
1997
  return `
1950
- top: ${this.elementBottom}px;
1998
+ --top-position: ${elementBottom}px;
1951
1999
  ${horizontalStyle}
1952
- width: ${this.width}px;
2000
+ --list-width: ${width}px;
2001
+ --availableSpace: ${availableSpace}px;
1953
2002
  `;
1954
2003
  }
1955
2004
  /* }}} */
@@ -1992,7 +2041,10 @@ let ExtendedList = class ExtendedList extends Vue {
1992
2041
  const state = store.state;
1993
2042
  const isGroup = state.groups.size > 0 &&
1994
2043
  state.totalFilteredOptions > store.data.itemsPerPage;
1995
- return (h("div", { style: this.positionStyle, class: "selectic selectic__extended-list" },
2044
+ return (h("div", { style: this.positionStyle, class: [
2045
+ 'selectic selectic__extended-list',
2046
+ `selectic-position-${this.position}`,
2047
+ ] },
1996
2048
  !state.hideFilter && (h(Filter, { store: this.store })),
1997
2049
  isGroup && (h("span", { class: "selectic-item selectic-item--header selectic-item__is-group" }, this.topGroup)),
1998
2050
  h(List$1, { store: store, on: {
@@ -2459,6 +2511,7 @@ let Selectic = class Selectic extends Vue {
2459
2511
  pageSize: this.params.pageSize || 100,
2460
2512
  hideFilter: (_b = this.params.hideFilter) !== null && _b !== void 0 ? _b : 'auto',
2461
2513
  allowRevert: this.params.allowRevert,
2514
+ forceSelectAll: this.params.forceSelectAll || 'auto',
2462
2515
  allowClearSelection: this.params.allowClearSelection || false,
2463
2516
  autoSelect: this.params.autoSelect === undefined
2464
2517
  ? !this.multiple && !this.params.fetchCallback
package/doc/params.md CHANGED
@@ -278,6 +278,32 @@ Read [the extended properties documentation](extendedProperties.md) for more inf
278
278
  />
279
279
  ```
280
280
 
281
+ ## forceSelectAll
282
+
283
+ Type: `'auto' | 'visible'`
284
+
285
+ Default value: `'auto'`
286
+
287
+ In _multiple_ mode, there is a "select all" action.
288
+ If the selection inversion is not available and all data are not fetched (in
289
+ _dynamic_ mode) it will not be possible to select all items. So this action
290
+ will be disabled.
291
+
292
+ This option allows you to change the behavior.
293
+
294
+ * `'auto'`: The action is disabled when not possible.
295
+ * `'visible'`: The action is displayed even when all data are not fetched.
296
+
297
+ ```html
298
+ <selectic
299
+ params={{
300
+ forceSelectAll: 'auto',
301
+ }}
302
+ options={optionList}
303
+ />
304
+ ```
305
+
306
+
281
307
  ## listPosition
282
308
 
283
309
  Type: `'auto' | 'bottom' | 'top'`
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "selectic",
3
- "version": "3.0.17",
3
+ "version": "3.0.19",
4
4
  "description": "Smart Select for VueJS 3.x",
5
5
  "main": "dist/selectic.common.js",
6
6
  "module": "dist/selectic.esm.js",
@@ -41,10 +41,10 @@
41
41
  "vtyx": "4.0.5"
42
42
  },
43
43
  "devDependencies": {
44
- "@babel/types": "^7.19.4",
44
+ "@babel/types": "^7.21.2",
45
45
  "rollup": "^2.79.1",
46
- "rollup-plugin-postcss": "^3.1.8",
47
- "tape": "^4.16.1",
48
- "typescript": "~4.5"
46
+ "rollup-plugin-postcss": "^4.0.2",
47
+ "tape": "^4.16.2",
48
+ "typescript": "~4.8"
49
49
  }
50
50
  }
@@ -20,6 +20,11 @@ export interface Props {
20
20
  elementRight: number;
21
21
  }
22
22
 
23
+ /* list estimation height
24
+ * 30px × 10 + 20px (for panel header)
25
+ */
26
+ const DEFAULT_LIST_HEIGHT = 320;
27
+
23
28
  @Component
24
29
  export default class ExtendedList extends Vue<Props> {
25
30
  /* {{{ props */
@@ -46,12 +51,21 @@ export default class ExtendedList extends Vue<Props> {
46
51
  /* {{{ data */
47
52
 
48
53
  private topGroup = ' ';
49
- private listHeight = 120;
54
+ private listHeight = 0;
50
55
  private listWidth = 200;
56
+ private availableSpace = 0;
51
57
 
52
58
  /* }}} */
53
59
  /* {{{ computed */
54
60
 
61
+ /** check if the height of the box has been completely estimated. */
62
+ get isFullyEstimated(): boolean {
63
+ const listHeight = this.listHeight;
64
+ const availableSpace = this.availableSpace;
65
+
66
+ return listHeight !== 0 && listHeight < availableSpace;
67
+ }
68
+
55
69
  get searchingLabel() {
56
70
  return this.store.data.labels.searching;
57
71
  }
@@ -124,20 +138,36 @@ export default class ExtendedList extends Vue<Props> {
124
138
 
125
139
  get bestPosition(): 'top' | 'bottom' {
126
140
  const windowHeight = window.innerHeight;
127
- const listHeight = this.listHeight;
141
+ const isFullyEstimated = this.isFullyEstimated;
142
+ /* XXX: The max() is because if listHeight is greater than default,
143
+ * it means that the value is more accurate than the default. */
144
+ const listHeight = isFullyEstimated ? this.listHeight
145
+ : Math.max(DEFAULT_LIST_HEIGHT, this.listHeight);
128
146
  const inputTop = this.elementTop;
129
147
  const inputBottom = this.elementBottom;
148
+ const availableTop = inputTop;
149
+ const availableBottom = windowHeight - inputBottom;
130
150
 
131
- if (inputBottom + listHeight <= windowHeight) {
151
+ if (listHeight < availableBottom) {
132
152
  return 'bottom';
133
153
  }
134
154
 
135
- if (listHeight < inputTop) {
155
+ if (listHeight < availableTop) {
136
156
  return 'top';
137
157
  }
138
158
 
139
159
  /* There are not enough space neither at bottom nor at top */
140
- return (windowHeight - inputBottom) < inputTop ? 'top' : 'bottom';
160
+ return availableBottom < availableTop ? 'top' : 'bottom';
161
+ }
162
+
163
+ get position(): 'top' | 'bottom' {
164
+ const listPosition = this.store.state.listPosition;
165
+
166
+ if (listPosition === 'auto') {
167
+ return this.bestPosition;
168
+ }
169
+
170
+ return listPosition;
141
171
  }
142
172
 
143
173
  get horizontalStyle(): string {
@@ -162,30 +192,35 @@ export default class ExtendedList extends Vue<Props> {
162
192
  }
163
193
 
164
194
  get positionStyle() {
165
- let listPosition = this.store.state.listPosition;
195
+ const listPosition = this.position;
166
196
  const horizontalStyle = this.horizontalStyle;
167
-
168
- if (listPosition === 'auto') {
169
- listPosition = this.bestPosition;
170
- }
197
+ const width = this.width;
171
198
 
172
199
  if (listPosition === 'top') {
173
200
  const transform = horizontalStyle.includes('transform')
174
201
  ? 'transform: translateX(-100%) translateY(-100%);'
175
202
  : 'transform: translateY(-100%);';
203
+ const elementTop = this.elementTop;
204
+ const availableSpace = this.elementTop;
205
+ this.availableSpace = availableSpace;
176
206
 
177
207
  return `
178
- top: ${this.elementTop}px;
208
+ --top-position: ${elementTop}px;
179
209
  ${horizontalStyle}
180
- width: ${this.width}px;
181
- ${transform}
210
+ --list-width: ${width}px;
211
+ ${transform};
212
+ --availableSpace: ${availableSpace}px;
182
213
  `;
183
214
  }
215
+ const elementBottom = this.elementBottom;
216
+ const availableSpace = window.innerHeight - elementBottom;
217
+ this.availableSpace = availableSpace;
184
218
 
185
219
  return `
186
- top: ${this.elementBottom}px;
220
+ --top-position: ${elementBottom}px;
187
221
  ${horizontalStyle}
188
- width: ${this.width}px;
222
+ --list-width: ${width}px;
223
+ --availableSpace: ${availableSpace}px;
189
224
  `;
190
225
  }
191
226
 
@@ -248,7 +283,10 @@ export default class ExtendedList extends Vue<Props> {
248
283
  return (
249
284
  <div
250
285
  style={this.positionStyle}
251
- class="selectic selectic__extended-list"
286
+ class={[
287
+ 'selectic selectic__extended-list',
288
+ `selectic-position-${this.position}`,
289
+ ]}
252
290
  >
253
291
  {!state.hideFilter && (
254
292
  <Filter
package/src/Filter.tsx CHANGED
@@ -30,31 +30,53 @@ export default class FilterPanel extends Vue<Props> {
30
30
  /* }}} */
31
31
  /* {{{ computed */
32
32
 
33
- get searchPlaceholder() {
33
+ get searchPlaceholder(): string {
34
34
  return this.store.data.labels.searchPlaceholder;
35
35
  }
36
36
 
37
- get selectionIsExcluded() {
37
+ get selectionIsExcluded(): boolean {
38
38
  return this.store.state.selectionIsExcluded;
39
39
  }
40
40
 
41
- get disableSelectAll() {
41
+ /* {{{ select all */
42
+
43
+ get hasNotAllItems(): boolean {
44
+ return !unref(this.store.hasAllItems);
45
+ }
46
+ get disabledPartialData(): boolean {
47
+ const state = this.store.state;
48
+ const autoDisplay = state.forceSelectAll === 'auto';
49
+ return this.hasNotAllItems && !this.enableRevert && autoDisplay;
50
+ }
51
+
52
+ get disableSelectAll(): boolean {
42
53
  const store = this.store;
43
54
  const state = store.state;
44
55
  const isMultiple = state.multiple;
45
- const hasItems = state.filteredOptions.length === 0;
46
- const canNotSelect = !!state.searchText && !unref(store.hasAllItems);
56
+ const hasNoItems = state.filteredOptions.length === 0;
57
+ const canNotSelect = this.hasNotAllItems && !!state.searchText;
58
+ const partialDataDsbld = this.disabledPartialData;
47
59
 
48
- return !isMultiple || hasItems || canNotSelect;
60
+ return !isMultiple || hasNoItems || canNotSelect || partialDataDsbld;
49
61
  }
50
62
 
51
- get disableRevert() {
63
+ get titleSelectAll(): string {
64
+ if (this.disableSelectAll && this.disabledPartialData) {
65
+ return this.store.data.labels.cannotSelectAllRevertItems;
66
+ }
67
+
68
+ return '';
69
+ }
70
+
71
+ /* }}} */
72
+
73
+ get disableRevert(): boolean {
52
74
  const store = this.store;
53
75
 
54
76
  return !store.state.multiple || !unref(store.hasFetchedAllItems);
55
77
  }
56
78
 
57
- get enableRevert() {
79
+ get enableRevert(): boolean {
58
80
  const state = this.store.state;
59
81
 
60
82
  return state.multiple && state.allowRevert !== false;
@@ -178,6 +200,7 @@ export default class FilterPanel extends Vue<Props> {
178
200
  type="checkbox"
179
201
  checked={state.status.areAllSelected}
180
202
  disabled={this.disableSelectAll}
203
+ title={this.titleSelectAll}
181
204
  on={{
182
205
  change: this.onSelectAll,
183
206
  }}
package/src/MainInput.tsx CHANGED
@@ -281,7 +281,7 @@ export default class MainInput extends Vue<Props> {
281
281
  public render() {
282
282
  return (
283
283
  <div
284
- class="has-feedback"
284
+ class="selectic-container has-feedback"
285
285
  on={{
286
286
  'click.prevent.stop': () => this.toggleFocus(),
287
287
  }}
package/src/Store.tsx CHANGED
@@ -83,6 +83,12 @@ export type HideFilter =
83
83
  /* The panel filter is always open */
84
84
  | 'open';
85
85
 
86
+ export type SelectAllOption =
87
+ /* Display the "select all" only when data are all fetched or allowRevert */
88
+ 'auto'
89
+ /* Always display the "select all" in mulitple mode. */
90
+ | 'visible';
91
+
86
92
  export interface SelecticStoreStateParams {
87
93
  /* Equivalent of <select>'s "multiple" attribute */
88
94
  multiple?: boolean;
@@ -101,6 +107,9 @@ export interface SelecticStoreStateParams {
101
107
  */
102
108
  allowRevert?: boolean;
103
109
 
110
+ /* Force the availability of the "select all" even if all data is not fetched yet. */
111
+ forceSelectAll?: SelectAllOption;
112
+
104
113
  /* Allow user to clear current selection */
105
114
  allowClearSelection?: boolean;
106
115
 
@@ -295,6 +304,9 @@ export interface SelecticStoreState {
295
304
  /* Indicate where the list should be deployed */
296
305
  listPosition: ListPosition;
297
306
 
307
+ /* If true, the "select All" is still available even if all data are not fetched yet. */
308
+ forceSelectAll: SelectAllOption;
309
+
298
310
  /* Inner status which should be modified only by store */
299
311
  status: {
300
312
  /* If true, a search is currently done */
@@ -442,6 +454,7 @@ export default class SelecticStore {
442
454
  isOpen: false,
443
455
  searchText: '',
444
456
  selectionIsExcluded: false,
457
+ forceSelectAll: 'auto',
445
458
  allOptions: [],
446
459
  dynOptions: [],
447
460
  filteredOptions: [],
@@ -184,13 +184,21 @@
184
184
 
185
185
  .selectic__extended-list {
186
186
  position: fixed;
187
+ top: var(--top-position, 0);
187
188
  z-index: 2000;
188
189
  height: auto;
190
+ max-height: var(--availableSpace);
189
191
  background-color: var(--selectic-bg, #ffffff);
190
192
  box-shadow: 2px 5px 12px 0px #888888;
191
193
  border-radius: 0 0 4px 4px;
192
194
  padding: 0;
195
+ width: var(--list-width, 200px);
193
196
  min-width: 200px;
197
+ display: grid;
198
+ grid-template-rows: minmax(0, max-content) 1fr;
199
+ }
200
+ .selectic__extended-list.selectic-position-top {
201
+ box-shadow: 2px -3px 12px 0px #888888;
194
202
  }
195
203
  .selectic__extended-list__list-container{
196
204
  overflow: auto;
package/src/index.tsx CHANGED
@@ -40,6 +40,7 @@ import Store, {
40
40
  SelectionOverflow,
41
41
  ListPosition,
42
42
  HideFilter,
43
+ SelectAllOption,
43
44
  } from './Store';
44
45
  import MainInput from './MainInput';
45
46
  import ExtendedList from './ExtendedList';
@@ -98,6 +99,9 @@ export interface ParamProps {
98
99
  */
99
100
  allowRevert?: boolean;
100
101
 
102
+ /* If true, the "select All" is still available even if all data are not fetched yet. */
103
+ forceSelectAll?: SelectAllOption;
104
+
101
105
  /* Allow user to clear the current selection */
102
106
  allowClearSelection?: boolean;
103
107
 
@@ -794,6 +798,7 @@ export default class Selectic extends Vue<Props> {
794
798
  pageSize: this.params.pageSize || 100,
795
799
  hideFilter: this.params.hideFilter ?? 'auto',
796
800
  allowRevert: this.params.allowRevert, /* it can be undefined */
801
+ forceSelectAll: this.params.forceSelectAll || 'auto',
797
802
  allowClearSelection: this.params.allowClearSelection || false,
798
803
  autoSelect: this.params.autoSelect === undefined
799
804
  ? !this.multiple && !this.params.fetchCallback
package/src/tools.ts CHANGED
@@ -76,11 +76,12 @@ export function assignObject<T>(obj: Partial<T>, ...sourceObjects: Array<Partial
76
76
  const result = obj;
77
77
  for (const source of sourceObjects) {
78
78
  for (const key of Object.keys(source)) {
79
- const value = source[key as keyof T];
79
+ const typedKey = key as keyof T;
80
+ const value = source[typedKey];
80
81
  if (value === undefined) {
81
82
  continue;
82
83
  }
83
- result[key as keyof T] = value;
84
+ result[typedKey] = value!;
84
85
  }
85
86
  }
86
87
  return result as T;
package/test/helper.js CHANGED
@@ -10,6 +10,7 @@ function getInitialState(replacedAttributes) {
10
10
  hideFilter: false,
11
11
  keepFilterOpen: false,
12
12
  allowRevert: undefined,
13
+ forceSelectAll: 'auto',
13
14
  allowClearSelection: false,
14
15
  autoSelect: true,
15
16
  autoDisabled: true,
@@ -18,12 +18,16 @@ export default class ExtendedList extends Vue<Props> {
18
18
  private topGroup;
19
19
  private listHeight;
20
20
  private listWidth;
21
+ private availableSpace;
22
+ /** check if the height of the box has been completely estimated. */
23
+ get isFullyEstimated(): boolean;
21
24
  get searchingLabel(): string;
22
25
  get searching(): boolean;
23
26
  get errorMessage(): string;
24
27
  get infoMessage(): string;
25
28
  get onKeyDown(): (evt: KeyboardEvent) => void;
26
29
  get bestPosition(): 'top' | 'bottom';
30
+ get position(): 'top' | 'bottom';
27
31
  get horizontalStyle(): string;
28
32
  get positionStyle(): string;
29
33
  onFilteredOptionsChange(): void;
package/types/Filter.d.ts CHANGED
@@ -11,7 +11,10 @@ export default class FilterPanel extends Vue<Props> {
11
11
  private closed;
12
12
  get searchPlaceholder(): string;
13
13
  get selectionIsExcluded(): boolean;
14
+ get hasNotAllItems(): boolean;
15
+ get disabledPartialData(): boolean;
14
16
  get disableSelectAll(): boolean;
17
+ get titleSelectAll(): string;
15
18
  get disableRevert(): boolean;
16
19
  get enableRevert(): boolean;
17
20
  get onKeyPressed(): (evt: KeyboardEvent) => void;
package/types/Store.d.ts CHANGED
@@ -39,11 +39,13 @@ export declare type FormatCallback = (_option: OptionItem) => OptionItem;
39
39
  export declare type SelectionOverflow = 'collapsed' | 'multiline';
40
40
  export declare type ListPosition = 'bottom' | 'top' | 'auto';
41
41
  export declare type HideFilter = boolean | 'auto' | 'open';
42
+ export declare type SelectAllOption = 'auto' | 'visible';
42
43
  export interface SelecticStoreStateParams {
43
44
  multiple?: boolean;
44
45
  placeholder?: string;
45
46
  hideFilter?: HideFilter;
46
47
  allowRevert?: boolean;
48
+ forceSelectAll?: SelectAllOption;
47
49
  allowClearSelection?: boolean;
48
50
  pageSize?: number;
49
51
  autoSelect?: boolean;
@@ -110,6 +112,7 @@ export interface SelecticStoreState {
110
112
  optionBehaviorOperation: OptionBehaviorOperation;
111
113
  optionBehaviorOrder: OptionBehaviorOrder[];
112
114
  listPosition: ListPosition;
115
+ forceSelectAll: SelectAllOption;
113
116
  status: {
114
117
  searching: boolean;
115
118
  errorMessage: string;
package/types/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { Vue, h } from 'vtyx';
2
2
  import './css/selectic.css';
3
- import { OptionProp, OptionId, StrictOptionId, GroupValue, SelectedValue, FetchCallback, GetCallback, PartialMessages, OptionValue, OptionItem, FormatCallback, SelectionOverflow, ListPosition, HideFilter } from './Store';
3
+ import { OptionProp, OptionId, StrictOptionId, GroupValue, SelectedValue, FetchCallback, GetCallback, PartialMessages, OptionValue, OptionItem, FormatCallback, SelectionOverflow, ListPosition, HideFilter, SelectAllOption } from './Store';
4
4
  import MainInput from './MainInput';
5
5
  import ExtendedList from './ExtendedList';
6
6
  export { GroupValue, OptionValue, OptionItem, OptionProp, OptionId, StrictOptionId, SelectedValue, PartialMessages, GetCallback, FetchCallback, FormatCallback, SelectionOverflow, ListPosition, HideFilter, };
@@ -19,6 +19,7 @@ export interface ParamProps {
19
19
  pageSize?: number;
20
20
  hideFilter?: HideFilter;
21
21
  allowRevert?: boolean;
22
+ forceSelectAll?: SelectAllOption;
22
23
  allowClearSelection?: boolean;
23
24
  autoSelect?: boolean;
24
25
  autoDisabled?: boolean;