selectic 3.3.0 → 3.3.1

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.
@@ -1456,13 +1456,26 @@ class SelecticStore {
1456
1456
  : false;
1457
1457
  const hasOnlyValidValue = hasValue && !hasDisabledSelected && (Array.isArray(value) ? value.every((val) => this.hasValue(val)) :
1458
1458
  this.hasValue(value));
1459
+ /* Whether at least one option, that is not disabled, is not selected. */
1460
+ const hasAvailableNonSelectedOptions = state.allOptions.some((opt) => {
1461
+ const isOptionSelected = (Array.isArray(selectedOptions)
1462
+ ? selectedOptions.some((selectedOpt) => selectedOpt.id === opt.id)
1463
+ : selectedOptions && selectedOptions.id === opt.id);
1464
+ return !isOptionSelected && !opt.disabled;
1465
+ });
1459
1466
  const isEmpty = nbEnabled === 0;
1460
- const hasOnlyOneOption = nbEnabled === 1 && hasOnlyValidValue && !state.allowClearSelection;
1467
+ const hasOnlyOneOption = (nbEnabled === 1 && hasOnlyValidValue && !state.allowClearSelection);
1468
+ /* In most cases if `hasOnlyOneOption` is true, we disable selection.
1469
+ * However, if we are not in multi-select mode and if the only option available is not the selected one then
1470
+ * we do not disable selection (to let the user switch from its current disabled selection,
1471
+ * and a valid one).
1472
+ */
1473
+ const cannotSelectAnyOption = hasOnlyOneOption && (Array.isArray(selectedOptions) || !hasAvailableNonSelectedOptions);
1461
1474
  const isExclusiveDisabledItem = Array.isArray(selectedOptions) /* which means "multiple" mode */
1462
1475
  && selectedOptions.length === 1
1463
1476
  && selectedOptions[0].exclusive
1464
1477
  && selectedOptions[0].disabled;
1465
- if (hasOnlyOneOption || isEmpty || isExclusiveDisabledItem) {
1478
+ if (cannotSelectAnyOption || isEmpty || isExclusiveDisabledItem) {
1466
1479
  if (state.isOpen) {
1467
1480
  this.setAutomaticClose();
1468
1481
  this.commit('isOpen', false);
@@ -1452,13 +1452,26 @@ class SelecticStore {
1452
1452
  : false;
1453
1453
  const hasOnlyValidValue = hasValue && !hasDisabledSelected && (Array.isArray(value) ? value.every((val) => this.hasValue(val)) :
1454
1454
  this.hasValue(value));
1455
+ /* Whether at least one option, that is not disabled, is not selected. */
1456
+ const hasAvailableNonSelectedOptions = state.allOptions.some((opt) => {
1457
+ const isOptionSelected = (Array.isArray(selectedOptions)
1458
+ ? selectedOptions.some((selectedOpt) => selectedOpt.id === opt.id)
1459
+ : selectedOptions && selectedOptions.id === opt.id);
1460
+ return !isOptionSelected && !opt.disabled;
1461
+ });
1455
1462
  const isEmpty = nbEnabled === 0;
1456
- const hasOnlyOneOption = nbEnabled === 1 && hasOnlyValidValue && !state.allowClearSelection;
1463
+ const hasOnlyOneOption = (nbEnabled === 1 && hasOnlyValidValue && !state.allowClearSelection);
1464
+ /* In most cases if `hasOnlyOneOption` is true, we disable selection.
1465
+ * However, if we are not in multi-select mode and if the only option available is not the selected one then
1466
+ * we do not disable selection (to let the user switch from its current disabled selection,
1467
+ * and a valid one).
1468
+ */
1469
+ const cannotSelectAnyOption = hasOnlyOneOption && (Array.isArray(selectedOptions) || !hasAvailableNonSelectedOptions);
1457
1470
  const isExclusiveDisabledItem = Array.isArray(selectedOptions) /* which means "multiple" mode */
1458
1471
  && selectedOptions.length === 1
1459
1472
  && selectedOptions[0].exclusive
1460
1473
  && selectedOptions[0].disabled;
1461
- if (hasOnlyOneOption || isEmpty || isExclusiveDisabledItem) {
1474
+ if (cannotSelectAnyOption || isEmpty || isExclusiveDisabledItem) {
1462
1475
  if (state.isOpen) {
1463
1476
  this.setAutomaticClose();
1464
1477
  this.commit('isOpen', false);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "selectic",
3
- "version": "3.3.0",
3
+ "version": "3.3.1",
4
4
  "description": "Smart Select for VueJS 3.x",
5
5
  "main": "dist/selectic.common.js",
6
6
  "module": "dist/selectic.esm.js",
@@ -39,11 +39,11 @@
39
39
  "test": "npm run build && tape test/**/*.spec.js"
40
40
  },
41
41
  "dependencies": {
42
- "vtyx": "4.4.2"
42
+ "vtyx": "4.4.3"
43
43
  },
44
44
  "devDependencies": {
45
- "@babel/types": "^7.28.2",
46
- "rollup": "^2.79.2",
45
+ "@babel/types": "^7.29.0",
46
+ "rollup": "^2.80.0",
47
47
  "rollup-plugin-postcss": "^4.0.2",
48
48
  "tape": "^4.17.0",
49
49
  "typescript": "~5.9"
package/src/Store.tsx CHANGED
@@ -1988,14 +1988,37 @@ export default class SelecticStore {
1988
1988
  this.hasValue(value)
1989
1989
  );
1990
1990
 
1991
+ /* Whether at least one option, that is not disabled, is not selected. */
1992
+ const hasAvailableNonSelectedOptions = state.allOptions.some((opt) => {
1993
+ const isOptionSelected = (
1994
+ Array.isArray(selectedOptions)
1995
+ ? selectedOptions.some((selectedOpt) => selectedOpt.id === opt.id)
1996
+ : selectedOptions && selectedOptions.id === opt.id
1997
+ );
1998
+
1999
+ return !isOptionSelected && !opt.disabled;
2000
+ });
2001
+
1991
2002
  const isEmpty = nbEnabled === 0;
1992
- const hasOnlyOneOption = nbEnabled === 1 && hasOnlyValidValue && !state.allowClearSelection;
2003
+ const hasOnlyOneOption = (
2004
+ nbEnabled === 1 && hasOnlyValidValue && !state.allowClearSelection
2005
+ );
2006
+
2007
+ /* In most cases if `hasOnlyOneOption` is true, we disable selection.
2008
+ * However, if we are not in multi-select mode and if the only option available is not the selected one then
2009
+ * we do not disable selection (to let the user switch from its current disabled selection,
2010
+ * and a valid one).
2011
+ */
2012
+ const cannotSelectAnyOption = hasOnlyOneOption && (
2013
+ Array.isArray(selectedOptions) || !hasAvailableNonSelectedOptions
2014
+ );
2015
+
1993
2016
  const isExclusiveDisabledItem = Array.isArray(selectedOptions) /* which means "multiple" mode */
1994
2017
  && selectedOptions.length === 1
1995
2018
  && selectedOptions[0].exclusive
1996
2019
  && selectedOptions[0].disabled;
1997
2020
 
1998
- if (hasOnlyOneOption || isEmpty || isExclusiveDisabledItem) {
2021
+ if (cannotSelectAnyOption || isEmpty || isExclusiveDisabledItem) {
1999
2022
  if (state.isOpen) {
2000
2023
  this.setAutomaticClose();
2001
2024
  this.commit('isOpen', false);
@@ -229,6 +229,62 @@ tape.test('change props', (subT) => {
229
229
  t.end();
230
230
  });
231
231
 
232
+ sTest.test('should not disable the select, if selected item is disabled but there is another option',
233
+ async (t) => {
234
+ const options = getOptions(2, 'alpha');
235
+ options[1].disabled = true;
236
+
237
+ const store = new Store({
238
+ value: 1,
239
+ options: options,
240
+ disabled: false,
241
+ params: {
242
+ autoDisabled: true,
243
+ },
244
+ });
245
+
246
+ store.commit('isOpen', true);
247
+ await _.nextVueTick(store);
248
+
249
+ t.is(store.state.selectedOptions.text, 'alpha1');
250
+ t.is(store.state.internalValue, 1);
251
+ t.is(store.state.disabled, false);
252
+
253
+ /* Once we choose the only valid option, disable the selection */
254
+ store.props.value = 0;
255
+ await _.nextVueTick(store);
256
+
257
+ t.is(store.state.selectedOptions.text, 'alpha0');
258
+ t.is(store.state.internalValue, 0);
259
+ t.is(store.state.disabled, true);
260
+
261
+ t.end();
262
+ });
263
+
264
+ sTest.test('multi select should not be disabled, even if only disabled options are left',
265
+ async (t) => {
266
+ const options = getOptions(3, 'alpha');
267
+ options[1].disabled = true;
268
+ options[2].disabled = true;
269
+
270
+ const store = new Store({
271
+ value: [0, 1],
272
+ options: options,
273
+ disabled: false,
274
+ params: {
275
+ autoDisabled: true,
276
+ multiple: true,
277
+ },
278
+ });
279
+
280
+ store.commit('isOpen', true);
281
+ await _.nextVueTick(store);
282
+
283
+ t.deepEqual(store.state.internalValue, [0, 1]);
284
+ t.is(store.state.disabled, false);
285
+ t.end();
286
+ });
287
+
232
288
  sTest.test('should not disable the select with an invalid value', async (t) => {
233
289
  const store = new Store({
234
290
  value: 2,