selectic 3.1.1 → 3.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +0 -10
- package/dist/selectic.common.js +205 -47
- package/dist/selectic.esm.js +205 -47
- package/doc/breakingChanges.md +8 -0
- package/doc/changeIcons.md +8 -2
- package/doc/list.md +2 -1
- package/package.json +2 -1
- package/src/ExtendedList.tsx +5 -5
- package/src/Icon.tsx +2 -2
- package/src/List.tsx +0 -4
- package/src/MainInput.tsx +27 -4
- package/src/Store.tsx +225 -38
- package/src/css/selectic.css +3 -0
- package/src/index.tsx +23 -12
- package/src/tools.ts +13 -0
- package/test/Store/Store_creation.spec.js +86 -12
- package/test/Store/Store_props.spec.js +612 -595
- package/test/Store/changeIcons.spec.js +1 -1
- package/test/Store/commit.spec.js +56 -47
- package/test/Store/selectGroup.spec.js +278 -271
- package/test/Store/selectItem.spec.js +108 -22
- package/test/Store/toggleSelectAll.spec.js +6 -1
- package/test/helper.js +4 -0
- package/test/tools.js +5 -1
- package/types/ExtendedList.d.ts +5 -5
- package/types/List.d.ts +0 -3
- package/types/MainInput.d.ts +2 -1
- package/types/Store.d.ts +15 -2
- package/types/index.d.ts +3 -3
- package/types/tools.d.ts +4 -0
package/src/index.tsx
CHANGED
|
@@ -206,11 +206,11 @@ export interface Props {
|
|
|
206
206
|
iconFamily?: IconFamily;
|
|
207
207
|
|
|
208
208
|
/** If enabled, it resets the dynamic cache when selectic opens */
|
|
209
|
-
noCache?:
|
|
209
|
+
noCache?: boolean;
|
|
210
210
|
|
|
211
211
|
/** If true, the component opens (at start or if it is closed).
|
|
212
212
|
* If false, the components closes (if it is opened). */
|
|
213
|
-
open?:
|
|
213
|
+
open?: boolean;
|
|
214
214
|
|
|
215
215
|
/** Props which is not expected to change during the life time of the
|
|
216
216
|
* component.
|
|
@@ -243,7 +243,7 @@ export function changeIcons(icons: PartialIcons, iconFamily?: IconFamily) {
|
|
|
243
243
|
export default class Selectic extends Vue<Props> {
|
|
244
244
|
public $refs: {
|
|
245
245
|
mainInput: MainInput;
|
|
246
|
-
extendedList
|
|
246
|
+
extendedList?: ExtendedList;
|
|
247
247
|
};
|
|
248
248
|
|
|
249
249
|
/* {{{ props */
|
|
@@ -349,19 +349,21 @@ export default class Selectic extends Vue<Props> {
|
|
|
349
349
|
const store = this.store;
|
|
350
350
|
const keepOpenWithOtherSelectic = this.params.keepOpenWithOtherSelectic;
|
|
351
351
|
const extendedList = this.$refs.extendedList;
|
|
352
|
+
const extendedListEl: HTMLElement | undefined = extendedList?.$el;
|
|
352
353
|
|
|
353
|
-
if (!
|
|
354
|
+
if (!extendedListEl) {
|
|
354
355
|
/* this component is not focused anymore */
|
|
355
356
|
if (!keepOpenWithOtherSelectic) {
|
|
356
357
|
this.removeListeners();
|
|
357
358
|
this.store.commit('isOpen', false);
|
|
358
359
|
}
|
|
360
|
+
|
|
359
361
|
return;
|
|
360
362
|
}
|
|
361
363
|
|
|
362
364
|
const target = evt.target as Node;
|
|
363
365
|
|
|
364
|
-
if (!
|
|
366
|
+
if (!extendedListEl.contains(target) && !this.$el.contains(target)) {
|
|
365
367
|
store.commit('isOpen', false);
|
|
366
368
|
}
|
|
367
369
|
};
|
|
@@ -477,18 +479,27 @@ export default class Selectic extends Vue<Props> {
|
|
|
477
479
|
/* {{{ private methods */
|
|
478
480
|
|
|
479
481
|
private computeWidth() {
|
|
480
|
-
const
|
|
482
|
+
const mainInput = this.$refs?.mainInput;
|
|
483
|
+
|
|
484
|
+
const mainEl: HTMLElement | undefined = mainInput?.$el;
|
|
481
485
|
|
|
482
|
-
|
|
486
|
+
if (!mainEl) {
|
|
487
|
+
/* This method has been called too soon (before render function)
|
|
488
|
+
* or too late (after unmount) */
|
|
489
|
+
return;
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
this.width = mainEl.offsetWidth;
|
|
483
493
|
}
|
|
484
494
|
|
|
485
495
|
private computeOffset(doNotAddListener = false) {
|
|
486
|
-
const mainInput = this.$refs
|
|
496
|
+
const mainInput = this.$refs?.mainInput;
|
|
487
497
|
|
|
488
|
-
const mainEl = mainInput?.$el
|
|
498
|
+
const mainEl: HTMLElement | undefined = mainInput?.$el;
|
|
489
499
|
|
|
490
500
|
if (!mainEl) {
|
|
491
|
-
/* This method has been called too soon (before render function)
|
|
501
|
+
/* This method has been called too soon (before render function)
|
|
502
|
+
* or too late (after unmount) */
|
|
492
503
|
return;
|
|
493
504
|
}
|
|
494
505
|
|
|
@@ -669,13 +680,13 @@ export default class Selectic extends Vue<Props> {
|
|
|
669
680
|
/* Await that focused element becomes active */
|
|
670
681
|
setTimeout(() => {
|
|
671
682
|
const focusedEl = document.activeElement;
|
|
672
|
-
const extendedList = this.$refs
|
|
683
|
+
const extendedList = this.$refs?.extendedList;
|
|
673
684
|
|
|
674
685
|
/* check if there is a focused element (if none the body is
|
|
675
686
|
* selected) and if it is inside current Selectic */
|
|
676
687
|
if (focusedEl === document.body
|
|
677
688
|
|| this.$el.contains(focusedEl)
|
|
678
|
-
||
|
|
689
|
+
|| extendedList?.$el.contains(focusedEl))
|
|
679
690
|
{
|
|
680
691
|
return;
|
|
681
692
|
}
|
package/src/tools.ts
CHANGED
|
@@ -117,3 +117,16 @@ export function compareOptions(oldOptions: OptionValue[], newOptions: OptionValu
|
|
|
117
117
|
});
|
|
118
118
|
});
|
|
119
119
|
}
|
|
120
|
+
|
|
121
|
+
let displayLog = false;
|
|
122
|
+
export function debug(fName: string, step: string, ...args: any[]) {
|
|
123
|
+
if (!displayLog) {
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
console.log('--%s-- [%s]', fName, step, ...args);
|
|
128
|
+
}
|
|
129
|
+
/** Enable logs for debugging */
|
|
130
|
+
debug.enable = (display: boolean) => {
|
|
131
|
+
displayLog = display;
|
|
132
|
+
};
|
|
@@ -699,6 +699,80 @@ tape.test('Store creation', (subT) => {
|
|
|
699
699
|
t.end();
|
|
700
700
|
});
|
|
701
701
|
|
|
702
|
+
sTest.test('should disable multiple select with the only enabled value selected', async (t) => {
|
|
703
|
+
const options = getOptions(3);
|
|
704
|
+
options[0].disabled = true;
|
|
705
|
+
options[1].disabled = true;
|
|
706
|
+
|
|
707
|
+
const store = new Store({
|
|
708
|
+
options: options,
|
|
709
|
+
disabled: false,
|
|
710
|
+
value: [2],
|
|
711
|
+
params: {
|
|
712
|
+
multiple: true,
|
|
713
|
+
autoDisabled: true,
|
|
714
|
+
allowClearSelection: false,
|
|
715
|
+
},
|
|
716
|
+
});
|
|
717
|
+
|
|
718
|
+
await sleep(0);
|
|
719
|
+
|
|
720
|
+
t.is(store.state.disabled, true);
|
|
721
|
+
t.deepEqual(store.state.internalValue, [2]);
|
|
722
|
+
|
|
723
|
+
t.end();
|
|
724
|
+
});
|
|
725
|
+
|
|
726
|
+
sTest.test('should not disable multiple select when it is possible to remove selected value', async (t) => {
|
|
727
|
+
const options = getOptions(3);
|
|
728
|
+
options[0].disabled = true;
|
|
729
|
+
options[1].disabled = true;
|
|
730
|
+
|
|
731
|
+
const store = new Store({
|
|
732
|
+
options: options,
|
|
733
|
+
disabled: false,
|
|
734
|
+
value: [1, 2],
|
|
735
|
+
params: {
|
|
736
|
+
multiple: true,
|
|
737
|
+
autoDisabled: true,
|
|
738
|
+
allowClearSelection: false,
|
|
739
|
+
},
|
|
740
|
+
});
|
|
741
|
+
|
|
742
|
+
await sleep(0);
|
|
743
|
+
|
|
744
|
+
/* It is possible to remove the item "2" because there is another value */
|
|
745
|
+
t.is(store.state.disabled, false);
|
|
746
|
+
t.deepEqual(store.state.internalValue, [1, 2]);
|
|
747
|
+
|
|
748
|
+
t.end();
|
|
749
|
+
});
|
|
750
|
+
|
|
751
|
+
sTest.test('should disable multiple select when exclusive disabled item is selected', async (t) => {
|
|
752
|
+
const options = getOptions(3);
|
|
753
|
+
options[1].disabled = true;
|
|
754
|
+
options[1].exclusive = true;
|
|
755
|
+
|
|
756
|
+
const store = new Store({
|
|
757
|
+
options: options,
|
|
758
|
+
disabled: false,
|
|
759
|
+
value: [1],
|
|
760
|
+
params: {
|
|
761
|
+
multiple: true,
|
|
762
|
+
autoDisabled: true,
|
|
763
|
+
allowClearSelection: false,
|
|
764
|
+
},
|
|
765
|
+
});
|
|
766
|
+
|
|
767
|
+
await sleep(0);
|
|
768
|
+
|
|
769
|
+
/* It is not possible to change the value */
|
|
770
|
+
t.is(store.state.disabled, true);
|
|
771
|
+
t.deepEqual(store.state.internalValue, [1]);
|
|
772
|
+
|
|
773
|
+
t.end();
|
|
774
|
+
});
|
|
775
|
+
|
|
702
776
|
sTest.test('should not disable select without autoDisabled', async (t) => {
|
|
703
777
|
const store = new Store({
|
|
704
778
|
options: getOptions(1),
|
|
@@ -788,7 +862,7 @@ tape.test('Store creation', (subT) => {
|
|
|
788
862
|
|
|
789
863
|
/* Load data */
|
|
790
864
|
store.commit('isOpen', true);
|
|
791
|
-
await _.nextVueTick(store, spy.promise);
|
|
865
|
+
await _.nextVueTick(store, spy.promise, sleep(0) /* await request resolution */);
|
|
792
866
|
store.commit('isOpen', false);
|
|
793
867
|
await sleep(0);
|
|
794
868
|
|
|
@@ -1343,7 +1417,7 @@ tape.test('Store creation', (subT) => {
|
|
|
1343
1417
|
await sleep(0);
|
|
1344
1418
|
t.is(store1.state.filteredOptions.length, 0);
|
|
1345
1419
|
command1.fetch();
|
|
1346
|
-
await _.nextVueTick(store1, spy1.promise);
|
|
1420
|
+
await _.nextVueTick(store1, spy1.promise, sleep(0) /* await request resolution */);
|
|
1347
1421
|
|
|
1348
1422
|
t.is(store1.state.filteredOptions.length, 4);
|
|
1349
1423
|
|
|
@@ -1385,7 +1459,7 @@ tape.test('Store creation', (subT) => {
|
|
|
1385
1459
|
store1.commit('isOpen', true);
|
|
1386
1460
|
await sleep(0);
|
|
1387
1461
|
command1.fetch();
|
|
1388
|
-
await _.nextVueTick(store1, spy1.promise);
|
|
1462
|
+
await _.nextVueTick(store1, spy1.promise, sleep(0) /* await request resolution */);
|
|
1389
1463
|
|
|
1390
1464
|
t.is(store1.state.filteredOptions.length, 3, 'should contain the groups');
|
|
1391
1465
|
|
|
@@ -1405,7 +1479,7 @@ tape.test('Store creation', (subT) => {
|
|
|
1405
1479
|
store2.commit('isOpen', true);
|
|
1406
1480
|
await sleep(0);
|
|
1407
1481
|
command2.fetch();
|
|
1408
|
-
await _.nextVueTick(store2, spy2.promise);
|
|
1482
|
+
await _.nextVueTick(store2, spy2.promise, sleep(0) /* await request resolution */);
|
|
1409
1483
|
|
|
1410
1484
|
t.is(store2.state.filteredOptions.length, 4);
|
|
1411
1485
|
|
|
@@ -1425,7 +1499,7 @@ tape.test('Store creation', (subT) => {
|
|
|
1425
1499
|
store3.commit('isOpen', true);
|
|
1426
1500
|
await sleep(0);
|
|
1427
1501
|
command3.fetch();
|
|
1428
|
-
await _.nextVueTick(store3, spy3.promise);
|
|
1502
|
+
await _.nextVueTick(store3, spy3.promise, sleep(0) /* await request resolution */);
|
|
1429
1503
|
|
|
1430
1504
|
t.is(store3.state.filteredOptions.length, 2);
|
|
1431
1505
|
t.end();
|
|
@@ -1449,7 +1523,7 @@ tape.test('Store creation', (subT) => {
|
|
|
1449
1523
|
store1.commit('isOpen', true);
|
|
1450
1524
|
await sleep(0);
|
|
1451
1525
|
command1.fetch();
|
|
1452
|
-
await _.nextVueTick(store1, spy1.promise);
|
|
1526
|
+
await _.nextVueTick(store1, spy1.promise, sleep(0) /* await request resolution */);
|
|
1453
1527
|
|
|
1454
1528
|
t.is(store1.state.filteredOptions.length, 3);
|
|
1455
1529
|
|
|
@@ -1470,7 +1544,7 @@ tape.test('Store creation', (subT) => {
|
|
|
1470
1544
|
store2.commit('isOpen', true);
|
|
1471
1545
|
await sleep(0);
|
|
1472
1546
|
command2.fetch();
|
|
1473
|
-
await _.nextVueTick(store2, spy2.promise);
|
|
1547
|
+
await _.nextVueTick(store2, spy2.promise, sleep(0) /* await request resolution */);
|
|
1474
1548
|
|
|
1475
1549
|
t.is(store2.state.filteredOptions.length, 4);
|
|
1476
1550
|
|
|
@@ -1491,7 +1565,7 @@ tape.test('Store creation', (subT) => {
|
|
|
1491
1565
|
store3.commit('isOpen', true);
|
|
1492
1566
|
await sleep(0);
|
|
1493
1567
|
command3.fetch();
|
|
1494
|
-
await _.nextVueTick(store3, spy3.promise);
|
|
1568
|
+
await _.nextVueTick(store3, spy3.promise, sleep(0) /* await request resolution */);
|
|
1495
1569
|
|
|
1496
1570
|
t.is(store3.state.filteredOptions.length, 2);
|
|
1497
1571
|
t.end();
|
|
@@ -1540,7 +1614,7 @@ tape.test('Store creation', (subT) => {
|
|
|
1540
1614
|
await sleep(0);
|
|
1541
1615
|
t.is(store1.state.filteredOptions.length, 0);
|
|
1542
1616
|
command1.fetch();
|
|
1543
|
-
await _.nextVueTick(store1, spy1.promise);
|
|
1617
|
+
await _.nextVueTick(store1, spy1.promise, sleep(0) /* await request resolution */);
|
|
1544
1618
|
|
|
1545
1619
|
t.is(store1.state.filteredOptions.length, 9);
|
|
1546
1620
|
t.end();
|
|
@@ -1565,7 +1639,7 @@ tape.test('Store creation', (subT) => {
|
|
|
1565
1639
|
t.is(store.state.filteredOptions.length, 5); // previous options should be displayed
|
|
1566
1640
|
t.true(toHaveBeenCalledWith(spy, ['', 0, 100])); // dynamic index should always start at 0
|
|
1567
1641
|
command.fetch();
|
|
1568
|
-
await _.nextVueTick(store, spy.promise);
|
|
1642
|
+
await _.nextVueTick(store, spy.promise, sleep(0) /* await request resolution */);
|
|
1569
1643
|
|
|
1570
1644
|
t.is(store.state.filteredOptions.length, 9); // finally all options should be displayed
|
|
1571
1645
|
t.end();
|
|
@@ -1590,7 +1664,7 @@ tape.test('Store creation', (subT) => {
|
|
|
1590
1664
|
t.true(toHaveBeenCalledWith(spy1, ['', 0, 100]));
|
|
1591
1665
|
|
|
1592
1666
|
command1.fetch();
|
|
1593
|
-
await _.nextVueTick(store1, spy1.promise);
|
|
1667
|
+
await _.nextVueTick(store1, spy1.promise, sleep(0) /* await request resolution */);
|
|
1594
1668
|
|
|
1595
1669
|
t.is(store1.state.allOptions.length, 104);
|
|
1596
1670
|
t.is(store1.state.filteredOptions.length, 104);
|
|
@@ -1675,7 +1749,7 @@ tape.test('Store creation', (subT) => {
|
|
|
1675
1749
|
t.true(toHaveBeenCalled(spy));
|
|
1676
1750
|
|
|
1677
1751
|
command.fetch();
|
|
1678
|
-
await _.nextVueTick(store, spy.promise);
|
|
1752
|
+
await _.nextVueTick(store, spy.promise, sleep(0) /* await request resolution */);
|
|
1679
1753
|
|
|
1680
1754
|
t.is(store.state.isOpen, true);
|
|
1681
1755
|
t.is(store.state.filteredOptions.length, 4);
|