@stackline/vue-multiselect-dropdown 3.0.2 → 3.1.0
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 +637 -50
- package/dist/index.cjs +651 -55
- package/dist/index.d.cts +153 -1
- package/dist/index.d.ts +153 -1
- package/dist/index.js +645 -54
- package/package.json +17 -4
package/dist/index.cjs
CHANGED
|
@@ -23,7 +23,12 @@ __export(index_exports, {
|
|
|
23
23
|
StacklineVueMultiselect: () => StacklineVueMultiselect,
|
|
24
24
|
VueMultiselect: () => VueMultiselect,
|
|
25
25
|
VueMultiselectDropdown: () => VueMultiselectDropdown,
|
|
26
|
-
|
|
26
|
+
createVueMultiselectDropdown: () => createVueMultiselectDropdown,
|
|
27
|
+
default: () => plugin_default,
|
|
28
|
+
defineSettings: () => defineSettings,
|
|
29
|
+
defineSlots: () => defineSlots,
|
|
30
|
+
useMultiSelectDropdown: () => useMultiSelectDropdown,
|
|
31
|
+
useMultiSelectState: () => useMultiSelectState
|
|
27
32
|
});
|
|
28
33
|
module.exports = __toCommonJS(index_exports);
|
|
29
34
|
|
|
@@ -109,6 +114,7 @@ var styles = `
|
|
|
109
114
|
display: flex;
|
|
110
115
|
flex: 1 1 auto;
|
|
111
116
|
min-width: 0;
|
|
117
|
+
min-height: 1.45em;
|
|
112
118
|
align-items: center;
|
|
113
119
|
align-content: center;
|
|
114
120
|
gap: 8px;
|
|
@@ -122,6 +128,7 @@ var styles = `
|
|
|
122
128
|
align-self: center;
|
|
123
129
|
justify-content: flex-start;
|
|
124
130
|
min-width: 0;
|
|
131
|
+
min-height: 1.45em;
|
|
125
132
|
max-width: 100%;
|
|
126
133
|
color: var(--vmsd-muted);
|
|
127
134
|
font-size: 0.95rem;
|
|
@@ -205,33 +212,25 @@ var styles = `
|
|
|
205
212
|
display: inline-flex;
|
|
206
213
|
align-items: center;
|
|
207
214
|
justify-content: center;
|
|
208
|
-
|
|
209
|
-
min-
|
|
215
|
+
flex: 0 0 auto;
|
|
216
|
+
min-width: 24px;
|
|
217
|
+
min-height: 20px;
|
|
210
218
|
color: var(--vmsd-muted);
|
|
211
219
|
font-size: 0.8rem;
|
|
212
220
|
font-weight: 600;
|
|
221
|
+
line-height: 1;
|
|
222
|
+
white-space: nowrap;
|
|
223
|
+
text-align: center;
|
|
213
224
|
}
|
|
214
225
|
|
|
215
|
-
.vmsd-root.vmsd-has-overflow
|
|
226
|
+
.vmsd-root.vmsd-has-overflow .vmsd-trigger {
|
|
216
227
|
padding-right: 104px;
|
|
217
228
|
}
|
|
218
229
|
|
|
219
|
-
.vmsd-root.vmsd-has-overflow:not(.
|
|
230
|
+
.vmsd-root.vmsd-has-overflow:not(.vmsd-has-clear) .vmsd-trigger {
|
|
220
231
|
padding-right: 74px;
|
|
221
232
|
}
|
|
222
233
|
|
|
223
|
-
.vmsd-root.vmsd-has-overflow:not(.skin-classic) .vmsd-overflow {
|
|
224
|
-
position: absolute;
|
|
225
|
-
top: 50%;
|
|
226
|
-
right: 76px;
|
|
227
|
-
transform: translateY(-50%);
|
|
228
|
-
z-index: 1;
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
.vmsd-root.vmsd-has-overflow:not(.skin-classic):not(.vmsd-has-clear) .vmsd-overflow {
|
|
232
|
-
right: 42px;
|
|
233
|
-
}
|
|
234
|
-
|
|
235
234
|
.vmsd-actions {
|
|
236
235
|
position: absolute;
|
|
237
236
|
top: 50%;
|
|
@@ -508,9 +507,6 @@ var styles = `
|
|
|
508
507
|
.vmsd-checkbox {
|
|
509
508
|
position: relative;
|
|
510
509
|
box-sizing: content-box;
|
|
511
|
-
display: inline-grid;
|
|
512
|
-
place-items: center;
|
|
513
|
-
align-self: center;
|
|
514
510
|
flex: 0 0 auto;
|
|
515
511
|
width: 18px;
|
|
516
512
|
height: 18px;
|
|
@@ -518,8 +514,6 @@ var styles = `
|
|
|
518
514
|
border: 2px solid var(--vmsd-border-strong);
|
|
519
515
|
border-radius: 6px;
|
|
520
516
|
background-color: var(--vmsd-bg);
|
|
521
|
-
line-height: 0;
|
|
522
|
-
vertical-align: middle;
|
|
523
517
|
}
|
|
524
518
|
|
|
525
519
|
.vmsd-checkbox[data-checked="true"] {
|
|
@@ -539,7 +533,7 @@ var styles = `
|
|
|
539
533
|
border-color: #fff;
|
|
540
534
|
border-style: solid;
|
|
541
535
|
border-width: 0 0 2px 2px;
|
|
542
|
-
transform: translate(-50%, -
|
|
536
|
+
transform: translate(-50%, -58%) rotate(-45deg);
|
|
543
537
|
transform-origin: 50%;
|
|
544
538
|
}
|
|
545
539
|
|
|
@@ -801,9 +795,12 @@ var styles = `
|
|
|
801
795
|
|
|
802
796
|
.theme-classic .vmsd-overflow,
|
|
803
797
|
.skin-classic .vmsd-overflow {
|
|
798
|
+
min-width: 24px;
|
|
799
|
+
min-height: 20px;
|
|
804
800
|
color: #333333;
|
|
805
801
|
font-size: 14px;
|
|
806
802
|
font-weight: 400;
|
|
803
|
+
line-height: 1;
|
|
807
804
|
}
|
|
808
805
|
|
|
809
806
|
.theme-classic .vmsd-actions,
|
|
@@ -1038,7 +1035,7 @@ var styles = `
|
|
|
1038
1035
|
height: 3px;
|
|
1039
1036
|
margin-top: 0;
|
|
1040
1037
|
border-width: 0 0 3px 3px;
|
|
1041
|
-
transform: translate(-50%, -
|
|
1038
|
+
transform: translate(-50%, -58%) rotate(-45deg);
|
|
1042
1039
|
}
|
|
1043
1040
|
|
|
1044
1041
|
.theme-classic .vmsd-option-label,
|
|
@@ -1071,12 +1068,10 @@ var styles = `
|
|
|
1071
1068
|
|
|
1072
1069
|
@media (max-width: 720px) {
|
|
1073
1070
|
.vmsd-trigger {
|
|
1074
|
-
align-items:
|
|
1071
|
+
align-items: center;
|
|
1075
1072
|
padding-right: 54px;
|
|
1076
1073
|
}
|
|
1077
1074
|
}
|
|
1078
|
-
|
|
1079
|
-
/* stackline-vue3-live-20260527 */
|
|
1080
1075
|
`;
|
|
1081
1076
|
function ensureDropdownStyles() {
|
|
1082
1077
|
if (typeof document === "undefined") {
|
|
@@ -1137,7 +1132,16 @@ var DEFAULT_SETTINGS = {
|
|
|
1137
1132
|
removeItemAriaLabel: "Remove selected option",
|
|
1138
1133
|
openDropdownAriaLabel: "Open dropdown",
|
|
1139
1134
|
closeDropdownAriaLabel: "Close dropdown",
|
|
1140
|
-
loadingText: "Loading options"
|
|
1135
|
+
loadingText: "Loading options",
|
|
1136
|
+
keyboard: {
|
|
1137
|
+
space: true,
|
|
1138
|
+
spaceOptionAction: "toggle",
|
|
1139
|
+
tab: true,
|
|
1140
|
+
arrows: true,
|
|
1141
|
+
escape: true,
|
|
1142
|
+
backspaceRemovesLastWhenSearchEmpty: false,
|
|
1143
|
+
deleteRemovesFocusedBadge: true
|
|
1144
|
+
}
|
|
1141
1145
|
};
|
|
1142
1146
|
function iconPath(name) {
|
|
1143
1147
|
if (name === "remove") {
|
|
@@ -1276,9 +1280,15 @@ function buildGroups(items, settings) {
|
|
|
1276
1280
|
}
|
|
1277
1281
|
function mergeUniqueItems(base, extra, settings) {
|
|
1278
1282
|
const bucket = /* @__PURE__ */ new Map();
|
|
1279
|
-
for (const item of base
|
|
1283
|
+
for (const item of base) {
|
|
1280
1284
|
bucket.set(getPrimaryValue(item, settings), item);
|
|
1281
1285
|
}
|
|
1286
|
+
for (const item of extra) {
|
|
1287
|
+
const key = getPrimaryValue(item, settings);
|
|
1288
|
+
if (!bucket.has(key)) {
|
|
1289
|
+
bucket.set(key, item);
|
|
1290
|
+
}
|
|
1291
|
+
}
|
|
1282
1292
|
return Array.from(bucket.values());
|
|
1283
1293
|
}
|
|
1284
1294
|
function callRenderFunction(renderFunction, h2, item, context) {
|
|
@@ -1287,6 +1297,10 @@ function callRenderFunction(renderFunction, h2, item, context) {
|
|
|
1287
1297
|
}
|
|
1288
1298
|
return renderFunction(item, context, h2);
|
|
1289
1299
|
}
|
|
1300
|
+
function callSlot(vm, name, props) {
|
|
1301
|
+
const slot = vm.$slots && vm.$slots[name];
|
|
1302
|
+
return typeof slot === "function" ? slot(props) : null;
|
|
1303
|
+
}
|
|
1290
1304
|
function escapeSelectorValue(value) {
|
|
1291
1305
|
if (typeof CSS !== "undefined" && typeof CSS.escape === "function") {
|
|
1292
1306
|
return CSS.escape(value);
|
|
@@ -1296,6 +1310,9 @@ function escapeSelectorValue(value) {
|
|
|
1296
1310
|
function isActivationKey(event) {
|
|
1297
1311
|
return event.key === "Enter" || event.key === " " || event.key === "Spacebar";
|
|
1298
1312
|
}
|
|
1313
|
+
function isSpaceKey(event) {
|
|
1314
|
+
return event.key === " " || event.key === "Spacebar";
|
|
1315
|
+
}
|
|
1299
1316
|
function isTextInputTarget(target) {
|
|
1300
1317
|
const element = target;
|
|
1301
1318
|
if (!element) {
|
|
@@ -1379,10 +1396,21 @@ var VueMultiselectDropdown = {
|
|
|
1379
1396
|
},
|
|
1380
1397
|
computed: {
|
|
1381
1398
|
resolvedSettings() {
|
|
1399
|
+
const userSettings = this.settings || {};
|
|
1382
1400
|
const merged = {
|
|
1383
1401
|
...DEFAULT_SETTINGS,
|
|
1384
|
-
...
|
|
1402
|
+
...userSettings,
|
|
1403
|
+
keyboard: {
|
|
1404
|
+
...DEFAULT_SETTINGS.keyboard,
|
|
1405
|
+
...userSettings.keyboard || {}
|
|
1406
|
+
}
|
|
1385
1407
|
};
|
|
1408
|
+
if (typeof userSettings.escapeToClose === "boolean" && userSettings.keyboard?.escape == null) {
|
|
1409
|
+
merged.keyboard.escape = userSettings.escapeToClose;
|
|
1410
|
+
}
|
|
1411
|
+
if (typeof merged.keyboard.backspace === "boolean") {
|
|
1412
|
+
merged.keyboard.backspaceRemovesLastWhenSearchEmpty = merged.keyboard.backspace;
|
|
1413
|
+
}
|
|
1386
1414
|
const skin = merged.skin || merged.theme || "classic";
|
|
1387
1415
|
return {
|
|
1388
1416
|
...merged,
|
|
@@ -1476,6 +1504,9 @@ var VueMultiselectDropdown = {
|
|
|
1476
1504
|
getKey(item) {
|
|
1477
1505
|
return getPrimaryValue(item, this.resolvedSettings);
|
|
1478
1506
|
},
|
|
1507
|
+
getOptionId(key) {
|
|
1508
|
+
return `${this.instanceId}-option-${key}`;
|
|
1509
|
+
},
|
|
1479
1510
|
isSelected(item) {
|
|
1480
1511
|
const key = this.getKey(item);
|
|
1481
1512
|
return this.selected.some((selectedItem) => this.getKey(selectedItem) === key);
|
|
@@ -1608,6 +1639,13 @@ var VueMultiselectDropdown = {
|
|
|
1608
1639
|
this.emitSelection(next);
|
|
1609
1640
|
this.$emit("de-select", item);
|
|
1610
1641
|
},
|
|
1642
|
+
removeLastSelected() {
|
|
1643
|
+
const last = this.selected[this.selected.length - 1];
|
|
1644
|
+
if (!last) {
|
|
1645
|
+
return;
|
|
1646
|
+
}
|
|
1647
|
+
this.removeItem(last);
|
|
1648
|
+
},
|
|
1611
1649
|
addFilterItem(event) {
|
|
1612
1650
|
event.preventDefault();
|
|
1613
1651
|
event.stopPropagation();
|
|
@@ -1624,35 +1662,51 @@ var VueMultiselectDropdown = {
|
|
|
1624
1662
|
this.query = "";
|
|
1625
1663
|
},
|
|
1626
1664
|
onTriggerKeydown(event) {
|
|
1627
|
-
|
|
1665
|
+
const keyboard = this.resolvedSettings.keyboard;
|
|
1666
|
+
if (event.key === "Enter" || isSpaceKey(event) && keyboard.space !== false) {
|
|
1628
1667
|
event.preventDefault();
|
|
1629
1668
|
this.toggleDropdown();
|
|
1630
1669
|
return;
|
|
1631
1670
|
}
|
|
1632
|
-
if (event.key === "ArrowDown") {
|
|
1671
|
+
if (keyboard.arrows !== false && event.key === "ArrowDown") {
|
|
1633
1672
|
event.preventDefault();
|
|
1634
1673
|
this.openDropdown();
|
|
1635
1674
|
this.focusFirstOption();
|
|
1636
1675
|
return;
|
|
1637
1676
|
}
|
|
1638
|
-
if (event.key === "ArrowUp") {
|
|
1677
|
+
if (keyboard.arrows !== false && event.key === "ArrowUp") {
|
|
1639
1678
|
event.preventDefault();
|
|
1640
1679
|
this.openDropdown();
|
|
1641
1680
|
this.focusLastOption();
|
|
1642
1681
|
return;
|
|
1643
1682
|
}
|
|
1644
|
-
if (event.key === "Escape") {
|
|
1683
|
+
if (keyboard.escape !== false && event.key === "Escape") {
|
|
1645
1684
|
this.closeDropdown();
|
|
1646
1685
|
}
|
|
1647
1686
|
},
|
|
1648
1687
|
onListKeydown(event) {
|
|
1649
|
-
|
|
1688
|
+
const keyboard = this.resolvedSettings.keyboard;
|
|
1689
|
+
if (keyboard.escape !== false && event.key === "Escape") {
|
|
1650
1690
|
event.preventDefault();
|
|
1651
1691
|
event.stopPropagation();
|
|
1652
1692
|
this.closeDropdown();
|
|
1653
1693
|
return;
|
|
1654
1694
|
}
|
|
1655
|
-
if (
|
|
1695
|
+
if (event.key === "Tab") {
|
|
1696
|
+
return;
|
|
1697
|
+
}
|
|
1698
|
+
if (isTextInputTarget(event.target)) {
|
|
1699
|
+
if (event.key === "Backspace" && !this.query && keyboard.backspaceRemovesLastWhenSearchEmpty === true) {
|
|
1700
|
+
event.preventDefault();
|
|
1701
|
+
event.stopPropagation();
|
|
1702
|
+
this.removeLastSelected();
|
|
1703
|
+
return;
|
|
1704
|
+
}
|
|
1705
|
+
if (!["ArrowDown", "ArrowUp", "Home", "End"].includes(event.key)) {
|
|
1706
|
+
return;
|
|
1707
|
+
}
|
|
1708
|
+
}
|
|
1709
|
+
if (keyboard.arrows === false && ["ArrowDown", "ArrowUp", "Home", "End"].includes(event.key)) {
|
|
1656
1710
|
return;
|
|
1657
1711
|
}
|
|
1658
1712
|
const selectable = this.visibleSelectableItems();
|
|
@@ -1687,10 +1741,22 @@ var VueMultiselectDropdown = {
|
|
|
1687
1741
|
return;
|
|
1688
1742
|
}
|
|
1689
1743
|
if (isActivationKey(event)) {
|
|
1744
|
+
if (isSpaceKey(event) && keyboard.space === false) {
|
|
1745
|
+
return;
|
|
1746
|
+
}
|
|
1690
1747
|
event.preventDefault();
|
|
1691
1748
|
event.stopPropagation();
|
|
1692
1749
|
const activeItem = selectable.find((item) => this.getKey(item) === this.focusedKey) || selectable[0];
|
|
1693
1750
|
this.toggleItem(activeItem);
|
|
1751
|
+
if (keyboard.spaceOptionAction === "toggle-and-next") {
|
|
1752
|
+
const activeIndex = selectable.findIndex((item) => this.getKey(item) === this.getKey(activeItem));
|
|
1753
|
+
const nextItem = selectable[Math.min(activeIndex + 1, selectable.length - 1)];
|
|
1754
|
+
if (nextItem) {
|
|
1755
|
+
this.focusOption(nextItem);
|
|
1756
|
+
}
|
|
1757
|
+
} else {
|
|
1758
|
+
this.focusOption(activeItem);
|
|
1759
|
+
}
|
|
1694
1760
|
return;
|
|
1695
1761
|
}
|
|
1696
1762
|
},
|
|
@@ -1727,19 +1793,26 @@ var VueMultiselectDropdown = {
|
|
|
1727
1793
|
if (isActivationKey(event)) {
|
|
1728
1794
|
event.stopPropagation();
|
|
1729
1795
|
}
|
|
1730
|
-
if (event.key === "ArrowDown") {
|
|
1796
|
+
if (this.resolvedSettings.keyboard.arrows !== false && event.key === "ArrowDown") {
|
|
1731
1797
|
event.preventDefault();
|
|
1732
1798
|
event.stopPropagation();
|
|
1733
1799
|
this.openDropdown();
|
|
1734
1800
|
this.focusFirstOption();
|
|
1735
1801
|
}
|
|
1736
|
-
if (event.key === "ArrowUp") {
|
|
1802
|
+
if (this.resolvedSettings.keyboard.arrows !== false && event.key === "ArrowUp") {
|
|
1737
1803
|
event.preventDefault();
|
|
1738
1804
|
event.stopPropagation();
|
|
1739
1805
|
this.openDropdown();
|
|
1740
1806
|
this.focusLastOption();
|
|
1741
1807
|
}
|
|
1742
1808
|
},
|
|
1809
|
+
onRemoveButtonKeydown(item, event) {
|
|
1810
|
+
if (this.resolvedSettings.keyboard.deleteRemovesFocusedBadge !== false && (event.key === "Backspace" || event.key === "Delete")) {
|
|
1811
|
+
this.removeItem(item, event);
|
|
1812
|
+
return;
|
|
1813
|
+
}
|
|
1814
|
+
this.onInlineKeydown(event);
|
|
1815
|
+
},
|
|
1743
1816
|
onTriggerClick(event) {
|
|
1744
1817
|
const target = event.target;
|
|
1745
1818
|
if (target && target.closest("button")) {
|
|
@@ -1760,7 +1833,7 @@ var VueMultiselectDropdown = {
|
|
|
1760
1833
|
this.closeDropdown();
|
|
1761
1834
|
},
|
|
1762
1835
|
onDocumentKeydown(event) {
|
|
1763
|
-
if (this.isOpen && this.resolvedSettings.
|
|
1836
|
+
if (this.isOpen && this.resolvedSettings.keyboard.escape !== false && event.key === "Escape") {
|
|
1764
1837
|
this.closeDropdown();
|
|
1765
1838
|
}
|
|
1766
1839
|
},
|
|
@@ -1878,11 +1951,14 @@ var VueMultiselectDropdown = {
|
|
|
1878
1951
|
label,
|
|
1879
1952
|
selected: true,
|
|
1880
1953
|
disabled: false,
|
|
1954
|
+
key: this.getKey(item),
|
|
1955
|
+
ariaSelected: "true",
|
|
1956
|
+
ariaChecked: "true",
|
|
1881
1957
|
query: this.query,
|
|
1882
1958
|
toggle: () => this.toggleItem(item),
|
|
1883
1959
|
remove: () => this.removeItem(item)
|
|
1884
1960
|
};
|
|
1885
|
-
const rendered = callRenderFunction(this.renderBadge, h, item, context);
|
|
1961
|
+
const rendered = callSlot(this, "badge", context) || callRenderFunction(this.renderBadge, h, item, context);
|
|
1886
1962
|
const removeLabel = typeof settings.removeItemAriaLabel === "function" ? settings.removeItemAriaLabel(item) : `${settings.removeItemAriaLabel}: ${label}`;
|
|
1887
1963
|
return h("span", { class: "vmsd-badge", key: this.getKey(item) }, [
|
|
1888
1964
|
h("span", { class: "vmsd-badge-label" }, [rendered || label]),
|
|
@@ -1893,17 +1969,18 @@ var VueMultiselectDropdown = {
|
|
|
1893
1969
|
attrs: { type: "button", "aria-label": removeLabel },
|
|
1894
1970
|
on: {
|
|
1895
1971
|
click: (event) => this.removeItem(item, event),
|
|
1896
|
-
keydown: this.
|
|
1972
|
+
keydown: (event) => this.onRemoveButtonKeydown(item, event)
|
|
1897
1973
|
}
|
|
1898
1974
|
},
|
|
1899
1975
|
[renderIcon(h, "remove")]
|
|
1900
1976
|
)
|
|
1901
1977
|
]);
|
|
1902
1978
|
});
|
|
1903
|
-
const valueContent = hasSelection ? [h("span", { class: "vmsd-badge-list" }, badges)] : [
|
|
1904
|
-
|
|
1905
|
-
|
|
1906
|
-
|
|
1979
|
+
const valueContent = hasSelection ? [h("span", { class: "vmsd-badge-list" }, badges)] : [
|
|
1980
|
+
h("span", { class: "vmsd-placeholder" }, [
|
|
1981
|
+
callSlot(this, "placeholder", { label: settings.text, state: { isOpen: this.isOpen, query: this.query } }) || settings.text
|
|
1982
|
+
])
|
|
1983
|
+
];
|
|
1907
1984
|
const trigger = h(
|
|
1908
1985
|
"div",
|
|
1909
1986
|
{
|
|
@@ -1916,7 +1993,8 @@ var VueMultiselectDropdown = {
|
|
|
1916
1993
|
"aria-expanded": this.isOpen ? "true" : "false",
|
|
1917
1994
|
"aria-haspopup": "listbox",
|
|
1918
1995
|
"aria-disabled": settings.disabled ? "true" : "false",
|
|
1919
|
-
"aria-controls": `${this.instanceId}-listbox
|
|
1996
|
+
"aria-controls": `${this.instanceId}-listbox`,
|
|
1997
|
+
"aria-activedescendant": this.focusedKey ? this.getOptionId(this.focusedKey) : void 0
|
|
1920
1998
|
},
|
|
1921
1999
|
on: {
|
|
1922
2000
|
click: this.onTriggerClick,
|
|
@@ -1924,8 +2002,15 @@ var VueMultiselectDropdown = {
|
|
|
1924
2002
|
}
|
|
1925
2003
|
},
|
|
1926
2004
|
[
|
|
1927
|
-
|
|
2005
|
+
callSlot(this, "trigger", {
|
|
2006
|
+
selected: this.selected,
|
|
2007
|
+
label: hasSelection ? this.selected.map((item) => this.getLabel(item)).join(", ") : settings.text,
|
|
2008
|
+
isOpen: this.isOpen,
|
|
2009
|
+
clearSelection: this.clearSelection,
|
|
2010
|
+
toggleDropdown: this.toggleDropdown
|
|
2011
|
+
}) || h("div", { class: "vmsd-value" }, valueContent),
|
|
1928
2012
|
h("div", { class: "vmsd-actions" }, [
|
|
2013
|
+
hiddenCount > 0 ? h("span", { class: "vmsd-overflow", attrs: { "aria-label": `${hiddenCount} more selected options` } }, [`+${hiddenCount}`]) : null,
|
|
1929
2014
|
hasClear ? h(
|
|
1930
2015
|
"button",
|
|
1931
2016
|
{
|
|
@@ -2024,28 +2109,37 @@ var VueMultiselectDropdown = {
|
|
|
2024
2109
|
label,
|
|
2025
2110
|
selected,
|
|
2026
2111
|
disabled,
|
|
2112
|
+
index: this.filteredItems.findIndex((candidate) => this.getKey(candidate) === key),
|
|
2113
|
+
group: getGroupName(item, settings),
|
|
2114
|
+
key,
|
|
2115
|
+
optionId: this.getOptionId(key),
|
|
2116
|
+
ariaSelected: selected ? "true" : "false",
|
|
2117
|
+
ariaChecked: selected ? "true" : "false",
|
|
2027
2118
|
query: this.query,
|
|
2028
2119
|
toggle: () => this.toggleItem(item),
|
|
2029
2120
|
remove: () => this.removeItem(item)
|
|
2030
2121
|
};
|
|
2031
|
-
const rendered = callRenderFunction(this.renderItem, h, item, context);
|
|
2122
|
+
const rendered = callSlot(this, "option", context) || callRenderFunction(this.renderItem, h, item, context);
|
|
2032
2123
|
return h(
|
|
2033
2124
|
"div",
|
|
2034
2125
|
{
|
|
2035
2126
|
key,
|
|
2036
2127
|
class: ["vmsd-option", selected ? "vmsd-selected" : "", disabled ? "vmsd-disabled" : ""],
|
|
2037
2128
|
attrs: {
|
|
2129
|
+
id: this.getOptionId(key),
|
|
2038
2130
|
role: "option",
|
|
2039
2131
|
tabindex: disabled ? "-1" : "0",
|
|
2040
2132
|
"data-vmsd-option": "true",
|
|
2041
2133
|
"data-vmsd-key": key,
|
|
2042
2134
|
"aria-disabled": disabled ? "true" : "false",
|
|
2043
|
-
"aria-selected": selected ? "true" : "false"
|
|
2135
|
+
"aria-selected": selected ? "true" : "false",
|
|
2136
|
+
"aria-checked": selected ? "true" : "false"
|
|
2044
2137
|
},
|
|
2045
2138
|
on: {
|
|
2046
2139
|
click: (event) => {
|
|
2047
2140
|
if (!disabled) {
|
|
2048
2141
|
this.toggleItem(item, event);
|
|
2142
|
+
this.focusOption(item);
|
|
2049
2143
|
}
|
|
2050
2144
|
},
|
|
2051
2145
|
focus: () => this.focusedKey = key,
|
|
@@ -2062,9 +2156,13 @@ var VueMultiselectDropdown = {
|
|
|
2062
2156
|
]
|
|
2063
2157
|
);
|
|
2064
2158
|
};
|
|
2065
|
-
const listChildren = settings.loading ? [h("div", { class: "vmsd-state", attrs: { role: "status" } }, [settings.loadingText])] : settings.groupBy ? this.groupedItems.map(
|
|
2159
|
+
const listChildren = !this.isOpen ? [] : settings.loading ? [h("div", { class: "vmsd-state", attrs: { role: "status" } }, [callSlot(this, "loading", { label: settings.loadingText }) || settings.loadingText])] : settings.groupBy ? this.groupedItems.map(
|
|
2066
2160
|
(group) => h("div", { class: "vmsd-group", key: group.name, attrs: { role: "group", "aria-label": group.name } }, [
|
|
2067
|
-
|
|
2161
|
+
callSlot(this, "group-header", {
|
|
2162
|
+
group,
|
|
2163
|
+
selected: group.items.filter((item) => !isDisabledItem(item)).every((item) => this.isSelected(item)),
|
|
2164
|
+
selectGroup: (event) => this.selectGroup(group.name, group.items, event)
|
|
2165
|
+
}) || h("div", { class: "vmsd-group-header" }, [
|
|
2068
2166
|
h("span", [`${group.name} \xB7 ${group.items.length}`]),
|
|
2069
2167
|
settings.selectGroup ? h(
|
|
2070
2168
|
"button",
|
|
@@ -2079,8 +2177,8 @@ var VueMultiselectDropdown = {
|
|
|
2079
2177
|
group.items.map(renderOption)
|
|
2080
2178
|
])
|
|
2081
2179
|
) : this.filteredItems.map(renderOption);
|
|
2082
|
-
if (!this.filteredItems.length && !settings.loading) {
|
|
2083
|
-
const emptyContent = this.renderEmptyState ? this.renderEmptyState(this.query, h) : settings.noDataLabel;
|
|
2180
|
+
if (this.isOpen && !this.filteredItems.length && !settings.loading) {
|
|
2181
|
+
const emptyContent = callSlot(this, "empty", { query: this.query, label: settings.noDataLabel }) || (this.renderEmptyState ? this.renderEmptyState(this.query, h) : settings.noDataLabel);
|
|
2084
2182
|
listChildren.push(h("div", { class: "vmsd-state" }, [emptyContent]));
|
|
2085
2183
|
}
|
|
2086
2184
|
const menu = h(
|
|
@@ -2110,7 +2208,8 @@ var VueMultiselectDropdown = {
|
|
|
2110
2208
|
on: { scroll: this.onListScroll }
|
|
2111
2209
|
},
|
|
2112
2210
|
listChildren
|
|
2113
|
-
)
|
|
2211
|
+
),
|
|
2212
|
+
this.isOpen ? callSlot(this, "menu-footer", { selected: this.selected, filteredItems: this.filteredItems, close: this.closeDropdown }) : null
|
|
2114
2213
|
]
|
|
2115
2214
|
);
|
|
2116
2215
|
return h(
|
|
@@ -2138,6 +2237,498 @@ var VueMultiselectDropdown = {
|
|
|
2138
2237
|
};
|
|
2139
2238
|
var StacklineVueMultiselect = VueMultiselectDropdown;
|
|
2140
2239
|
|
|
2240
|
+
// src/composables.ts
|
|
2241
|
+
var import_vue2 = require("vue");
|
|
2242
|
+
var DEFAULT_KEYS = {
|
|
2243
|
+
labelKey: "itemName",
|
|
2244
|
+
primaryKey: "id"
|
|
2245
|
+
};
|
|
2246
|
+
function read(value, fallback) {
|
|
2247
|
+
return value == null ? fallback : (0, import_vue2.unref)(value);
|
|
2248
|
+
}
|
|
2249
|
+
function isPrimitiveItem2(item) {
|
|
2250
|
+
return typeof item === "string" || typeof item === "number" || typeof item === "boolean";
|
|
2251
|
+
}
|
|
2252
|
+
function resolveSettings(settings) {
|
|
2253
|
+
const value = read(settings, {});
|
|
2254
|
+
return {
|
|
2255
|
+
...value,
|
|
2256
|
+
text: value.text || "Select",
|
|
2257
|
+
singleSelection: Boolean(value.singleSelection),
|
|
2258
|
+
labelKey: value.labelKey || DEFAULT_KEYS.labelKey,
|
|
2259
|
+
primaryKey: value.primaryKey || DEFAULT_KEYS.primaryKey,
|
|
2260
|
+
searchBy: Array.isArray(value.searchBy) ? value.searchBy : [],
|
|
2261
|
+
groupBy: value.groupBy || ""
|
|
2262
|
+
};
|
|
2263
|
+
}
|
|
2264
|
+
function getLabel2(item, settings) {
|
|
2265
|
+
if (isPrimitiveItem2(item)) {
|
|
2266
|
+
return String(item);
|
|
2267
|
+
}
|
|
2268
|
+
const labelKey = settings.labelKey || DEFAULT_KEYS.labelKey;
|
|
2269
|
+
const keys = [labelKey, "itemName", "name", "label", "title", "value"];
|
|
2270
|
+
for (const key of keys) {
|
|
2271
|
+
if (item[key] != null) {
|
|
2272
|
+
return String(item[key]);
|
|
2273
|
+
}
|
|
2274
|
+
}
|
|
2275
|
+
return JSON.stringify(item);
|
|
2276
|
+
}
|
|
2277
|
+
function getKey(item, settings) {
|
|
2278
|
+
if (isPrimitiveItem2(item)) {
|
|
2279
|
+
return String(item);
|
|
2280
|
+
}
|
|
2281
|
+
const primaryKey = settings.primaryKey || DEFAULT_KEYS.primaryKey;
|
|
2282
|
+
const keys = [primaryKey, "id", "value", "key"];
|
|
2283
|
+
for (const key of keys) {
|
|
2284
|
+
if (item[key] != null) {
|
|
2285
|
+
return String(item[key]);
|
|
2286
|
+
}
|
|
2287
|
+
}
|
|
2288
|
+
return getLabel2(item, settings);
|
|
2289
|
+
}
|
|
2290
|
+
function getGroup(item, settings) {
|
|
2291
|
+
if (!settings.groupBy) {
|
|
2292
|
+
return void 0;
|
|
2293
|
+
}
|
|
2294
|
+
if (typeof settings.groupBy === "function") {
|
|
2295
|
+
return settings.groupBy(item);
|
|
2296
|
+
}
|
|
2297
|
+
return !isPrimitiveItem2(item) && item[settings.groupBy] != null ? String(item[settings.groupBy]) : void 0;
|
|
2298
|
+
}
|
|
2299
|
+
function isDisabled(item) {
|
|
2300
|
+
return !isPrimitiveItem2(item) && Boolean(item.disabled);
|
|
2301
|
+
}
|
|
2302
|
+
function matchesQuery(item, query, settings) {
|
|
2303
|
+
const needle = query.trim().toLowerCase();
|
|
2304
|
+
if (!needle) {
|
|
2305
|
+
return true;
|
|
2306
|
+
}
|
|
2307
|
+
const values = /* @__PURE__ */ new Set([getLabel2(item, settings).toLowerCase()]);
|
|
2308
|
+
if (!isPrimitiveItem2(item)) {
|
|
2309
|
+
const keys = settings.searchBy && settings.searchBy.length ? settings.searchBy : [settings.labelKey || DEFAULT_KEYS.labelKey];
|
|
2310
|
+
for (const key of keys) {
|
|
2311
|
+
if (key && item[key] != null) {
|
|
2312
|
+
values.add(String(item[key]).toLowerCase());
|
|
2313
|
+
}
|
|
2314
|
+
}
|
|
2315
|
+
}
|
|
2316
|
+
return Array.from(values).some((value) => value.includes(needle));
|
|
2317
|
+
}
|
|
2318
|
+
function mergeSelected(selected, incoming, settings) {
|
|
2319
|
+
const byKey = /* @__PURE__ */ new Map();
|
|
2320
|
+
for (const item of selected) {
|
|
2321
|
+
byKey.set(getKey(item, settings), item);
|
|
2322
|
+
}
|
|
2323
|
+
for (const item of incoming) {
|
|
2324
|
+
const key = getKey(item, settings);
|
|
2325
|
+
if (!byKey.has(key)) {
|
|
2326
|
+
byKey.set(key, item);
|
|
2327
|
+
}
|
|
2328
|
+
}
|
|
2329
|
+
return Array.from(byKey.values());
|
|
2330
|
+
}
|
|
2331
|
+
function readBadgeLimit(selected, settings) {
|
|
2332
|
+
if (settings.singleSelection) {
|
|
2333
|
+
return selected.length;
|
|
2334
|
+
}
|
|
2335
|
+
const value = Number(settings.badgeShowLimit);
|
|
2336
|
+
if (!Number.isFinite(value) || value <= 0) {
|
|
2337
|
+
return selected.length;
|
|
2338
|
+
}
|
|
2339
|
+
return Math.floor(value);
|
|
2340
|
+
}
|
|
2341
|
+
function normalizeExtraProps(props = {}) {
|
|
2342
|
+
const normalized = { ...props };
|
|
2343
|
+
if (normalized.className && !normalized.class) {
|
|
2344
|
+
normalized.class = normalized.className;
|
|
2345
|
+
}
|
|
2346
|
+
delete normalized.className;
|
|
2347
|
+
return normalized;
|
|
2348
|
+
}
|
|
2349
|
+
function mergePropBags(base, extra = {}) {
|
|
2350
|
+
const incoming = normalizeExtraProps(extra);
|
|
2351
|
+
const merged = { ...incoming, ...base };
|
|
2352
|
+
if (base.class || incoming.class) {
|
|
2353
|
+
merged.class = [incoming.class, base.class].filter(Boolean).join(" ");
|
|
2354
|
+
}
|
|
2355
|
+
if (base.style || incoming.style) {
|
|
2356
|
+
merged.style = {
|
|
2357
|
+
...typeof incoming.style === "object" ? incoming.style : {},
|
|
2358
|
+
...typeof base.style === "object" ? base.style : {}
|
|
2359
|
+
};
|
|
2360
|
+
}
|
|
2361
|
+
for (const key of Object.keys(base)) {
|
|
2362
|
+
if (/^on[A-Z]/.test(key) && typeof base[key] === "function" && typeof incoming[key] === "function") {
|
|
2363
|
+
merged[key] = (...args) => {
|
|
2364
|
+
incoming[key](...args);
|
|
2365
|
+
base[key](...args);
|
|
2366
|
+
};
|
|
2367
|
+
}
|
|
2368
|
+
}
|
|
2369
|
+
return merged;
|
|
2370
|
+
}
|
|
2371
|
+
function defineSettings(settings) {
|
|
2372
|
+
return settings;
|
|
2373
|
+
}
|
|
2374
|
+
function defineSlots(slots) {
|
|
2375
|
+
return slots;
|
|
2376
|
+
}
|
|
2377
|
+
function useMultiSelectState(options = {}) {
|
|
2378
|
+
const internalSelected = (0, import_vue2.ref)(options.defaultSelectedItems ? options.defaultSelectedItems.slice() : []);
|
|
2379
|
+
const filter = (0, import_vue2.ref)("");
|
|
2380
|
+
const settings = (0, import_vue2.computed)(() => resolveSettings(options.settings));
|
|
2381
|
+
const data = (0, import_vue2.computed)(() => read(options.data, []));
|
|
2382
|
+
const selectedItems = (0, import_vue2.computed)(() => read(options.selectedItems, internalSelected.value));
|
|
2383
|
+
const filteredItems = (0, import_vue2.computed)(() => data.value.filter((item) => matchesQuery(item, filter.value, settings.value)));
|
|
2384
|
+
const isSelected = (item) => {
|
|
2385
|
+
const key = getKey(item, settings.value);
|
|
2386
|
+
return selectedItems.value.some((selected) => getKey(selected, settings.value) === key);
|
|
2387
|
+
};
|
|
2388
|
+
const commit = (next) => {
|
|
2389
|
+
if (!options.selectedItems) {
|
|
2390
|
+
internalSelected.value = next;
|
|
2391
|
+
}
|
|
2392
|
+
options.onChange?.(next);
|
|
2393
|
+
};
|
|
2394
|
+
const getItemKey = (item) => getKey(item, settings.value);
|
|
2395
|
+
const getItemLabel = (item) => getLabel2(item, settings.value);
|
|
2396
|
+
const selectableItems = (0, import_vue2.computed)(() => filteredItems.value.filter((item) => !isDisabled(item)));
|
|
2397
|
+
const visibleBadges = (0, import_vue2.computed)(() => {
|
|
2398
|
+
const limit = readBadgeLimit(selectedItems.value, settings.value);
|
|
2399
|
+
return selectedItems.value.slice(0, limit);
|
|
2400
|
+
});
|
|
2401
|
+
const hiddenBadgeCount = (0, import_vue2.computed)(() => Math.max(selectedItems.value.length - visibleBadges.value.length, 0));
|
|
2402
|
+
const allFilteredSelected = (0, import_vue2.computed)(() => selectableItems.value.length > 0 && selectableItems.value.every((item) => isSelected(item)));
|
|
2403
|
+
const removeItem = (item) => {
|
|
2404
|
+
const key = getItemKey(item);
|
|
2405
|
+
const next = selectedItems.value.filter((selected) => getItemKey(selected) !== key);
|
|
2406
|
+
commit(next);
|
|
2407
|
+
options.onDeSelect?.(item);
|
|
2408
|
+
};
|
|
2409
|
+
const addItem = (item) => {
|
|
2410
|
+
if (isDisabled(item)) {
|
|
2411
|
+
return;
|
|
2412
|
+
}
|
|
2413
|
+
if (settings.value.singleSelection) {
|
|
2414
|
+
commit([item]);
|
|
2415
|
+
options.onSelect?.(item);
|
|
2416
|
+
return;
|
|
2417
|
+
}
|
|
2418
|
+
if (!isSelected(item)) {
|
|
2419
|
+
commit(selectedItems.value.concat(item));
|
|
2420
|
+
options.onSelect?.(item);
|
|
2421
|
+
}
|
|
2422
|
+
};
|
|
2423
|
+
const toggleItem = (item) => {
|
|
2424
|
+
if (isDisabled(item)) {
|
|
2425
|
+
return;
|
|
2426
|
+
}
|
|
2427
|
+
if (isSelected(item)) {
|
|
2428
|
+
removeItem(item);
|
|
2429
|
+
return;
|
|
2430
|
+
}
|
|
2431
|
+
addItem(item);
|
|
2432
|
+
};
|
|
2433
|
+
const clearSelection = () => {
|
|
2434
|
+
const previous = selectedItems.value.slice();
|
|
2435
|
+
commit([]);
|
|
2436
|
+
options.onDeSelectAll?.(previous);
|
|
2437
|
+
};
|
|
2438
|
+
const deSelectAll = (items) => {
|
|
2439
|
+
if (!items || !items.length) {
|
|
2440
|
+
clearSelection();
|
|
2441
|
+
return;
|
|
2442
|
+
}
|
|
2443
|
+
const keys = new Set(items.map(getItemKey));
|
|
2444
|
+
commit(selectedItems.value.filter((item) => !keys.has(getItemKey(item))));
|
|
2445
|
+
options.onDeSelectAll?.(items);
|
|
2446
|
+
};
|
|
2447
|
+
const selectAll = (items) => {
|
|
2448
|
+
const enabled = (items || selectableItems.value).filter((item) => !isDisabled(item));
|
|
2449
|
+
const before = selectedItems.value.length;
|
|
2450
|
+
commit(settings.value.singleSelection ? enabled.slice(0, 1) : mergeSelected(selectedItems.value, enabled, settings.value));
|
|
2451
|
+
options.onSelectAll?.(enabled);
|
|
2452
|
+
if (!enabled.length && before !== selectedItems.value.length) {
|
|
2453
|
+
options.onChange?.(selectedItems.value);
|
|
2454
|
+
}
|
|
2455
|
+
};
|
|
2456
|
+
const toggleGroup = (groupName, items) => {
|
|
2457
|
+
const enabled = items.filter((item) => !isDisabled(item));
|
|
2458
|
+
if (!enabled.length) {
|
|
2459
|
+
return;
|
|
2460
|
+
}
|
|
2461
|
+
const everySelected = enabled.every((item) => isSelected(item));
|
|
2462
|
+
if (everySelected) {
|
|
2463
|
+
deSelectAll(enabled);
|
|
2464
|
+
options.onGroupDeSelect?.(groupName, enabled);
|
|
2465
|
+
return;
|
|
2466
|
+
}
|
|
2467
|
+
selectAll(enabled);
|
|
2468
|
+
options.onGroupSelect?.(groupName, enabled);
|
|
2469
|
+
};
|
|
2470
|
+
const removeLastSelectedItem = () => {
|
|
2471
|
+
const last = selectedItems.value[selectedItems.value.length - 1];
|
|
2472
|
+
if (last) {
|
|
2473
|
+
removeItem(last);
|
|
2474
|
+
}
|
|
2475
|
+
};
|
|
2476
|
+
return {
|
|
2477
|
+
data,
|
|
2478
|
+
settings,
|
|
2479
|
+
filter,
|
|
2480
|
+
filteredItems,
|
|
2481
|
+
selectableItems,
|
|
2482
|
+
selectedItems,
|
|
2483
|
+
visibleBadges,
|
|
2484
|
+
hiddenBadgeCount,
|
|
2485
|
+
allFilteredSelected,
|
|
2486
|
+
isSelected,
|
|
2487
|
+
getItemKey,
|
|
2488
|
+
getItemLabel,
|
|
2489
|
+
setFilter: (value) => {
|
|
2490
|
+
filter.value = value;
|
|
2491
|
+
},
|
|
2492
|
+
selectItem: addItem,
|
|
2493
|
+
removeItem,
|
|
2494
|
+
removeLastSelectedItem,
|
|
2495
|
+
toggleItem,
|
|
2496
|
+
clearSelection,
|
|
2497
|
+
selectAll,
|
|
2498
|
+
deSelectAll,
|
|
2499
|
+
toggleGroup
|
|
2500
|
+
};
|
|
2501
|
+
}
|
|
2502
|
+
function useMultiSelectDropdown(options = {}) {
|
|
2503
|
+
const state = useMultiSelectState(options);
|
|
2504
|
+
const isOpen = (0, import_vue2.ref)(false);
|
|
2505
|
+
const query = (0, import_vue2.ref)("");
|
|
2506
|
+
const activeKey = (0, import_vue2.ref)("");
|
|
2507
|
+
const instanceId = `stackline-vmsd-headless-${Math.random().toString(36).slice(2)}`;
|
|
2508
|
+
const listboxId = `${instanceId}-listbox`;
|
|
2509
|
+
const visibleOptions = (0, import_vue2.computed)(() => {
|
|
2510
|
+
let index = 0;
|
|
2511
|
+
return state.filteredItems.value.map((item) => {
|
|
2512
|
+
const key = getKey(item, state.settings.value);
|
|
2513
|
+
return {
|
|
2514
|
+
item,
|
|
2515
|
+
key,
|
|
2516
|
+
label: getLabel2(item, state.settings.value),
|
|
2517
|
+
selected: state.isSelected(item),
|
|
2518
|
+
disabled: isDisabled(item),
|
|
2519
|
+
group: getGroup(item, state.settings.value),
|
|
2520
|
+
index: index++
|
|
2521
|
+
};
|
|
2522
|
+
});
|
|
2523
|
+
});
|
|
2524
|
+
const activeDescendantId = (0, import_vue2.computed)(() => activeKey.value ? `${instanceId}-option-${activeKey.value}` : void 0);
|
|
2525
|
+
const groups = (0, import_vue2.computed)(() => {
|
|
2526
|
+
const byName = /* @__PURE__ */ new Map();
|
|
2527
|
+
for (const option of visibleOptions.value) {
|
|
2528
|
+
const name = option.group || "Ungrouped";
|
|
2529
|
+
const existing = byName.get(name) || [];
|
|
2530
|
+
existing.push(option);
|
|
2531
|
+
byName.set(name, existing);
|
|
2532
|
+
}
|
|
2533
|
+
return Array.from(byName.entries()).map(([name, items]) => {
|
|
2534
|
+
const enabledItems = items.filter((option) => !option.disabled);
|
|
2535
|
+
return {
|
|
2536
|
+
name,
|
|
2537
|
+
items,
|
|
2538
|
+
enabledItems,
|
|
2539
|
+
selected: enabledItems.length > 0 && enabledItems.every((option) => option.selected),
|
|
2540
|
+
disabled: enabledItems.length === 0
|
|
2541
|
+
};
|
|
2542
|
+
});
|
|
2543
|
+
});
|
|
2544
|
+
const label = (0, import_vue2.computed)(() => {
|
|
2545
|
+
if (!state.selectedItems.value.length) {
|
|
2546
|
+
return state.settings.value.text || "Select";
|
|
2547
|
+
}
|
|
2548
|
+
return state.selectedItems.value.map((item) => getLabel2(item, state.settings.value)).join(", ");
|
|
2549
|
+
});
|
|
2550
|
+
const open = () => {
|
|
2551
|
+
isOpen.value = true;
|
|
2552
|
+
if (!activeKey.value && visibleOptions.value[0]) {
|
|
2553
|
+
activeKey.value = visibleOptions.value[0].key;
|
|
2554
|
+
}
|
|
2555
|
+
};
|
|
2556
|
+
const close = () => {
|
|
2557
|
+
isOpen.value = false;
|
|
2558
|
+
};
|
|
2559
|
+
const toggleOpen = () => isOpen.value ? close() : open();
|
|
2560
|
+
const focusNext = (direction) => {
|
|
2561
|
+
const optionsList = visibleOptions.value.filter((option) => !option.disabled);
|
|
2562
|
+
const currentIndex = Math.max(0, optionsList.findIndex((option) => option.key === activeKey.value));
|
|
2563
|
+
const next = optionsList[Math.min(Math.max(currentIndex + direction, 0), optionsList.length - 1)];
|
|
2564
|
+
if (next) {
|
|
2565
|
+
activeKey.value = next.key;
|
|
2566
|
+
}
|
|
2567
|
+
};
|
|
2568
|
+
const getRootProps = (props = {}) => mergePropBags({
|
|
2569
|
+
"data-stackline-multiselect": "true",
|
|
2570
|
+
"data-open": isOpen.value ? "true" : "false"
|
|
2571
|
+
}, props);
|
|
2572
|
+
const getTriggerProps = (props = {}) => mergePropBags({
|
|
2573
|
+
type: "button",
|
|
2574
|
+
role: "combobox",
|
|
2575
|
+
"aria-expanded": isOpen.value ? "true" : "false",
|
|
2576
|
+
"aria-haspopup": "listbox",
|
|
2577
|
+
"aria-controls": listboxId,
|
|
2578
|
+
"aria-activedescendant": activeDescendantId.value,
|
|
2579
|
+
onClick: toggleOpen,
|
|
2580
|
+
onKeydown: (event) => {
|
|
2581
|
+
if (event.key === "Enter" || event.key === " " || event.key === "Spacebar") {
|
|
2582
|
+
event.preventDefault();
|
|
2583
|
+
toggleOpen();
|
|
2584
|
+
}
|
|
2585
|
+
if (event.key === "ArrowDown") {
|
|
2586
|
+
event.preventDefault();
|
|
2587
|
+
open();
|
|
2588
|
+
focusNext(1);
|
|
2589
|
+
}
|
|
2590
|
+
if (event.key === "ArrowUp") {
|
|
2591
|
+
event.preventDefault();
|
|
2592
|
+
open();
|
|
2593
|
+
focusNext(-1);
|
|
2594
|
+
}
|
|
2595
|
+
if (event.key === "Escape") {
|
|
2596
|
+
close();
|
|
2597
|
+
}
|
|
2598
|
+
}
|
|
2599
|
+
}, props);
|
|
2600
|
+
const getSearchInputProps = (props = {}) => mergePropBags({
|
|
2601
|
+
value: query.value,
|
|
2602
|
+
"aria-label": "Search options",
|
|
2603
|
+
onInput: (event) => {
|
|
2604
|
+
query.value = String(event.target.value || "");
|
|
2605
|
+
state.setFilter(query.value);
|
|
2606
|
+
},
|
|
2607
|
+
onKeydown: (event) => {
|
|
2608
|
+
if (event.key === "ArrowDown") {
|
|
2609
|
+
event.preventDefault();
|
|
2610
|
+
focusNext(1);
|
|
2611
|
+
}
|
|
2612
|
+
if (event.key === "ArrowUp") {
|
|
2613
|
+
event.preventDefault();
|
|
2614
|
+
focusNext(-1);
|
|
2615
|
+
}
|
|
2616
|
+
if (event.key === "Escape") {
|
|
2617
|
+
close();
|
|
2618
|
+
}
|
|
2619
|
+
}
|
|
2620
|
+
}, props);
|
|
2621
|
+
const getListboxProps = (props = {}) => mergePropBags({
|
|
2622
|
+
id: listboxId,
|
|
2623
|
+
role: "listbox",
|
|
2624
|
+
"aria-multiselectable": state.settings.value.singleSelection ? "false" : "true"
|
|
2625
|
+
}, props);
|
|
2626
|
+
const getOptionProps = (option, props = {}) => mergePropBags({
|
|
2627
|
+
id: `${instanceId}-option-${option.key}`,
|
|
2628
|
+
role: "option",
|
|
2629
|
+
tabindex: option.disabled ? -1 : 0,
|
|
2630
|
+
"aria-selected": option.selected ? "true" : "false",
|
|
2631
|
+
"aria-checked": option.selected ? "true" : "false",
|
|
2632
|
+
"aria-disabled": option.disabled ? "true" : "false",
|
|
2633
|
+
onMouseenter: () => {
|
|
2634
|
+
activeKey.value = option.key;
|
|
2635
|
+
},
|
|
2636
|
+
onClick: () => {
|
|
2637
|
+
if (!option.disabled) {
|
|
2638
|
+
state.toggleItem(option.item);
|
|
2639
|
+
activeKey.value = option.key;
|
|
2640
|
+
}
|
|
2641
|
+
},
|
|
2642
|
+
onKeydown: (event) => {
|
|
2643
|
+
if (event.key === "ArrowDown") {
|
|
2644
|
+
event.preventDefault();
|
|
2645
|
+
focusNext(1);
|
|
2646
|
+
}
|
|
2647
|
+
if (event.key === "ArrowUp") {
|
|
2648
|
+
event.preventDefault();
|
|
2649
|
+
focusNext(-1);
|
|
2650
|
+
}
|
|
2651
|
+
if (event.key === "Enter" || event.key === " " || event.key === "Spacebar") {
|
|
2652
|
+
event.preventDefault();
|
|
2653
|
+
state.toggleItem(option.item);
|
|
2654
|
+
activeKey.value = option.key;
|
|
2655
|
+
}
|
|
2656
|
+
if (event.key === "Escape") {
|
|
2657
|
+
close();
|
|
2658
|
+
}
|
|
2659
|
+
}
|
|
2660
|
+
}, props);
|
|
2661
|
+
const getClearAllButtonProps = (props = {}) => mergePropBags({
|
|
2662
|
+
type: "button",
|
|
2663
|
+
"aria-label": "Clear selected options",
|
|
2664
|
+
onClick: state.clearSelection
|
|
2665
|
+
}, props);
|
|
2666
|
+
const getRemoveButtonProps = (item, props = {}) => mergePropBags({
|
|
2667
|
+
type: "button",
|
|
2668
|
+
"aria-label": `Remove ${getLabel2(item, state.settings.value)}`,
|
|
2669
|
+
onClick: () => {
|
|
2670
|
+
state.removeItem(item);
|
|
2671
|
+
},
|
|
2672
|
+
onKeydown: (event) => {
|
|
2673
|
+
if (event.key === "Backspace" || event.key === "Delete") {
|
|
2674
|
+
event.preventDefault();
|
|
2675
|
+
state.removeItem(item);
|
|
2676
|
+
}
|
|
2677
|
+
}
|
|
2678
|
+
}, props);
|
|
2679
|
+
return {
|
|
2680
|
+
isOpen,
|
|
2681
|
+
query,
|
|
2682
|
+
filter: state.filter,
|
|
2683
|
+
activeKey,
|
|
2684
|
+
activeDescendantId,
|
|
2685
|
+
listboxId,
|
|
2686
|
+
settings: state.settings,
|
|
2687
|
+
filteredItems: state.filteredItems,
|
|
2688
|
+
selectableItems: state.selectableItems,
|
|
2689
|
+
selectedItems: state.selectedItems,
|
|
2690
|
+
visibleBadges: state.visibleBadges,
|
|
2691
|
+
hiddenBadgeCount: state.hiddenBadgeCount,
|
|
2692
|
+
visibleOptions,
|
|
2693
|
+
groups,
|
|
2694
|
+
allFilteredSelected: state.allFilteredSelected,
|
|
2695
|
+
label,
|
|
2696
|
+
open,
|
|
2697
|
+
close,
|
|
2698
|
+
toggleOpen,
|
|
2699
|
+
clearSelection: state.clearSelection,
|
|
2700
|
+
selectAll: state.selectAll,
|
|
2701
|
+
deSelectAll: state.deSelectAll,
|
|
2702
|
+
toggleGroup: state.toggleGroup,
|
|
2703
|
+
toggleItem: state.toggleItem,
|
|
2704
|
+
selectItem: state.selectItem,
|
|
2705
|
+
removeItem: state.removeItem,
|
|
2706
|
+
removeLastSelectedItem: state.removeLastSelectedItem,
|
|
2707
|
+
isSelected: state.isSelected,
|
|
2708
|
+
setFilter: (value) => {
|
|
2709
|
+
query.value = value;
|
|
2710
|
+
state.setFilter(value);
|
|
2711
|
+
},
|
|
2712
|
+
getItemKey: state.getItemKey,
|
|
2713
|
+
getItemLabel: state.getItemLabel,
|
|
2714
|
+
getRootProps,
|
|
2715
|
+
getTriggerProps,
|
|
2716
|
+
getSearchInputProps,
|
|
2717
|
+
getListboxProps,
|
|
2718
|
+
getOptionProps,
|
|
2719
|
+
getClearAllButtonProps,
|
|
2720
|
+
getRemoveButtonProps
|
|
2721
|
+
};
|
|
2722
|
+
}
|
|
2723
|
+
function createVueMultiselectDropdown() {
|
|
2724
|
+
return {
|
|
2725
|
+
defineSettings: (settings) => defineSettings(settings),
|
|
2726
|
+
defineSlots,
|
|
2727
|
+
useMultiSelectState: (options = {}) => useMultiSelectState(options),
|
|
2728
|
+
useMultiSelectDropdown: (options = {}) => useMultiSelectDropdown(options)
|
|
2729
|
+
};
|
|
2730
|
+
}
|
|
2731
|
+
|
|
2141
2732
|
// src/plugin.ts
|
|
2142
2733
|
var VueMultiselect = {
|
|
2143
2734
|
install(app) {
|
|
@@ -2152,5 +2743,10 @@ var plugin_default = VueMultiselect;
|
|
|
2152
2743
|
0 && (module.exports = {
|
|
2153
2744
|
StacklineVueMultiselect,
|
|
2154
2745
|
VueMultiselect,
|
|
2155
|
-
VueMultiselectDropdown
|
|
2746
|
+
VueMultiselectDropdown,
|
|
2747
|
+
createVueMultiselectDropdown,
|
|
2748
|
+
defineSettings,
|
|
2749
|
+
defineSlots,
|
|
2750
|
+
useMultiSelectDropdown,
|
|
2751
|
+
useMultiSelectState
|
|
2156
2752
|
});
|