selectic 3.0.17 → 3.0.18

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.
@@ -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;
1487
1499
  }
1500
+ get titleSelectAll() {
1501
+ if (this.disableSelectAll && this.disabledPartialData) {
1502
+ return this.store.data.labels.cannotSelectAllRevertItems;
1503
+ }
1504
+ return '';
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))),
@@ -2463,6 +2482,7 @@ let Selectic = class Selectic extends vtyx.Vue {
2463
2482
  pageSize: this.params.pageSize || 100,
2464
2483
  hideFilter: (_b = this.params.hideFilter) !== null && _b !== void 0 ? _b : 'auto',
2465
2484
  allowRevert: this.params.allowRevert,
2485
+ forceSelectAll: this.params.forceSelectAll || 'auto',
2466
2486
  allowClearSelection: this.params.allowClearSelection || false,
2467
2487
  autoSelect: this.params.autoSelect === undefined
2468
2488
  ? !this.multiple && !this.params.fetchCallback
@@ -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;
1483
1495
  }
1496
+ get titleSelectAll() {
1497
+ if (this.disableSelectAll && this.disabledPartialData) {
1498
+ return this.store.data.labels.cannotSelectAllRevertItems;
1499
+ }
1500
+ return '';
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))),
@@ -2459,6 +2478,7 @@ let Selectic = class Selectic extends Vue {
2459
2478
  pageSize: this.params.pageSize || 100,
2460
2479
  hideFilter: (_b = this.params.hideFilter) !== null && _b !== void 0 ? _b : 'auto',
2461
2480
  allowRevert: this.params.allowRevert,
2481
+ forceSelectAll: this.params.forceSelectAll || 'auto',
2462
2482
  allowClearSelection: this.params.allowClearSelection || false,
2463
2483
  autoSelect: this.params.autoSelect === undefined
2464
2484
  ? !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.18",
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.20.7",
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
  }
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: [],
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,
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;