@stackline/vue-multiselect-dropdown 3.0.3 → 3.1.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.
- package/README.md +641 -51
- 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.js
CHANGED
|
@@ -80,6 +80,7 @@ var styles = `
|
|
|
80
80
|
display: flex;
|
|
81
81
|
flex: 1 1 auto;
|
|
82
82
|
min-width: 0;
|
|
83
|
+
min-height: 1.45em;
|
|
83
84
|
align-items: center;
|
|
84
85
|
align-content: center;
|
|
85
86
|
gap: 8px;
|
|
@@ -93,6 +94,7 @@ var styles = `
|
|
|
93
94
|
align-self: center;
|
|
94
95
|
justify-content: flex-start;
|
|
95
96
|
min-width: 0;
|
|
97
|
+
min-height: 1.45em;
|
|
96
98
|
max-width: 100%;
|
|
97
99
|
color: var(--vmsd-muted);
|
|
98
100
|
font-size: 0.95rem;
|
|
@@ -176,33 +178,25 @@ var styles = `
|
|
|
176
178
|
display: inline-flex;
|
|
177
179
|
align-items: center;
|
|
178
180
|
justify-content: center;
|
|
179
|
-
|
|
180
|
-
min-
|
|
181
|
+
flex: 0 0 auto;
|
|
182
|
+
min-width: 24px;
|
|
183
|
+
min-height: 20px;
|
|
181
184
|
color: var(--vmsd-muted);
|
|
182
185
|
font-size: 0.8rem;
|
|
183
186
|
font-weight: 600;
|
|
187
|
+
line-height: 1;
|
|
188
|
+
white-space: nowrap;
|
|
189
|
+
text-align: center;
|
|
184
190
|
}
|
|
185
191
|
|
|
186
|
-
.vmsd-root.vmsd-has-overflow
|
|
192
|
+
.vmsd-root.vmsd-has-overflow .vmsd-trigger {
|
|
187
193
|
padding-right: 104px;
|
|
188
194
|
}
|
|
189
195
|
|
|
190
|
-
.vmsd-root.vmsd-has-overflow:not(.
|
|
196
|
+
.vmsd-root.vmsd-has-overflow:not(.vmsd-has-clear) .vmsd-trigger {
|
|
191
197
|
padding-right: 74px;
|
|
192
198
|
}
|
|
193
199
|
|
|
194
|
-
.vmsd-root.vmsd-has-overflow:not(.skin-classic) .vmsd-overflow {
|
|
195
|
-
position: absolute;
|
|
196
|
-
top: 50%;
|
|
197
|
-
right: 76px;
|
|
198
|
-
transform: translateY(-50%);
|
|
199
|
-
z-index: 1;
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
.vmsd-root.vmsd-has-overflow:not(.skin-classic):not(.vmsd-has-clear) .vmsd-overflow {
|
|
203
|
-
right: 42px;
|
|
204
|
-
}
|
|
205
|
-
|
|
206
200
|
.vmsd-actions {
|
|
207
201
|
position: absolute;
|
|
208
202
|
top: 50%;
|
|
@@ -479,9 +473,6 @@ var styles = `
|
|
|
479
473
|
.vmsd-checkbox {
|
|
480
474
|
position: relative;
|
|
481
475
|
box-sizing: content-box;
|
|
482
|
-
display: inline-grid;
|
|
483
|
-
place-items: center;
|
|
484
|
-
align-self: center;
|
|
485
476
|
flex: 0 0 auto;
|
|
486
477
|
width: 18px;
|
|
487
478
|
height: 18px;
|
|
@@ -489,8 +480,6 @@ var styles = `
|
|
|
489
480
|
border: 2px solid var(--vmsd-border-strong);
|
|
490
481
|
border-radius: 6px;
|
|
491
482
|
background-color: var(--vmsd-bg);
|
|
492
|
-
line-height: 0;
|
|
493
|
-
vertical-align: middle;
|
|
494
483
|
}
|
|
495
484
|
|
|
496
485
|
.vmsd-checkbox[data-checked="true"] {
|
|
@@ -510,7 +499,7 @@ var styles = `
|
|
|
510
499
|
border-color: #fff;
|
|
511
500
|
border-style: solid;
|
|
512
501
|
border-width: 0 0 2px 2px;
|
|
513
|
-
transform: translate(-50%, -
|
|
502
|
+
transform: translate(-50%, -58%) rotate(-45deg);
|
|
514
503
|
transform-origin: 50%;
|
|
515
504
|
}
|
|
516
505
|
|
|
@@ -772,9 +761,12 @@ var styles = `
|
|
|
772
761
|
|
|
773
762
|
.theme-classic .vmsd-overflow,
|
|
774
763
|
.skin-classic .vmsd-overflow {
|
|
764
|
+
min-width: 24px;
|
|
765
|
+
min-height: 20px;
|
|
775
766
|
color: #333333;
|
|
776
767
|
font-size: 14px;
|
|
777
768
|
font-weight: 400;
|
|
769
|
+
line-height: 1;
|
|
778
770
|
}
|
|
779
771
|
|
|
780
772
|
.theme-classic .vmsd-actions,
|
|
@@ -1009,7 +1001,7 @@ var styles = `
|
|
|
1009
1001
|
height: 3px;
|
|
1010
1002
|
margin-top: 0;
|
|
1011
1003
|
border-width: 0 0 3px 3px;
|
|
1012
|
-
transform: translate(-50%, -
|
|
1004
|
+
transform: translate(-50%, -58%) rotate(-45deg);
|
|
1013
1005
|
}
|
|
1014
1006
|
|
|
1015
1007
|
.theme-classic .vmsd-option-label,
|
|
@@ -1042,12 +1034,10 @@ var styles = `
|
|
|
1042
1034
|
|
|
1043
1035
|
@media (max-width: 720px) {
|
|
1044
1036
|
.vmsd-trigger {
|
|
1045
|
-
align-items:
|
|
1037
|
+
align-items: center;
|
|
1046
1038
|
padding-right: 54px;
|
|
1047
1039
|
}
|
|
1048
1040
|
}
|
|
1049
|
-
|
|
1050
|
-
/* stackline-vue3-live-20260527 */
|
|
1051
1041
|
`;
|
|
1052
1042
|
function ensureDropdownStyles() {
|
|
1053
1043
|
if (typeof document === "undefined") {
|
|
@@ -1108,7 +1098,16 @@ var DEFAULT_SETTINGS = {
|
|
|
1108
1098
|
removeItemAriaLabel: "Remove selected option",
|
|
1109
1099
|
openDropdownAriaLabel: "Open dropdown",
|
|
1110
1100
|
closeDropdownAriaLabel: "Close dropdown",
|
|
1111
|
-
loadingText: "Loading options"
|
|
1101
|
+
loadingText: "Loading options",
|
|
1102
|
+
keyboard: {
|
|
1103
|
+
space: true,
|
|
1104
|
+
spaceOptionAction: "toggle",
|
|
1105
|
+
tab: true,
|
|
1106
|
+
arrows: true,
|
|
1107
|
+
escape: true,
|
|
1108
|
+
backspaceRemovesLastWhenSearchEmpty: false,
|
|
1109
|
+
deleteRemovesFocusedBadge: true
|
|
1110
|
+
}
|
|
1112
1111
|
};
|
|
1113
1112
|
function iconPath(name) {
|
|
1114
1113
|
if (name === "remove") {
|
|
@@ -1247,9 +1246,15 @@ function buildGroups(items, settings) {
|
|
|
1247
1246
|
}
|
|
1248
1247
|
function mergeUniqueItems(base, extra, settings) {
|
|
1249
1248
|
const bucket = /* @__PURE__ */ new Map();
|
|
1250
|
-
for (const item of base
|
|
1249
|
+
for (const item of base) {
|
|
1251
1250
|
bucket.set(getPrimaryValue(item, settings), item);
|
|
1252
1251
|
}
|
|
1252
|
+
for (const item of extra) {
|
|
1253
|
+
const key = getPrimaryValue(item, settings);
|
|
1254
|
+
if (!bucket.has(key)) {
|
|
1255
|
+
bucket.set(key, item);
|
|
1256
|
+
}
|
|
1257
|
+
}
|
|
1253
1258
|
return Array.from(bucket.values());
|
|
1254
1259
|
}
|
|
1255
1260
|
function callRenderFunction(renderFunction, h2, item, context) {
|
|
@@ -1258,6 +1263,10 @@ function callRenderFunction(renderFunction, h2, item, context) {
|
|
|
1258
1263
|
}
|
|
1259
1264
|
return renderFunction(item, context, h2);
|
|
1260
1265
|
}
|
|
1266
|
+
function callSlot(vm, name, props) {
|
|
1267
|
+
const slot = vm.$slots && vm.$slots[name];
|
|
1268
|
+
return typeof slot === "function" ? slot(props) : null;
|
|
1269
|
+
}
|
|
1261
1270
|
function escapeSelectorValue(value) {
|
|
1262
1271
|
if (typeof CSS !== "undefined" && typeof CSS.escape === "function") {
|
|
1263
1272
|
return CSS.escape(value);
|
|
@@ -1267,6 +1276,9 @@ function escapeSelectorValue(value) {
|
|
|
1267
1276
|
function isActivationKey(event) {
|
|
1268
1277
|
return event.key === "Enter" || event.key === " " || event.key === "Spacebar";
|
|
1269
1278
|
}
|
|
1279
|
+
function isSpaceKey(event) {
|
|
1280
|
+
return event.key === " " || event.key === "Spacebar";
|
|
1281
|
+
}
|
|
1270
1282
|
function isTextInputTarget(target) {
|
|
1271
1283
|
const element = target;
|
|
1272
1284
|
if (!element) {
|
|
@@ -1350,10 +1362,21 @@ var VueMultiselectDropdown = {
|
|
|
1350
1362
|
},
|
|
1351
1363
|
computed: {
|
|
1352
1364
|
resolvedSettings() {
|
|
1365
|
+
const userSettings = this.settings || {};
|
|
1353
1366
|
const merged = {
|
|
1354
1367
|
...DEFAULT_SETTINGS,
|
|
1355
|
-
...
|
|
1368
|
+
...userSettings,
|
|
1369
|
+
keyboard: {
|
|
1370
|
+
...DEFAULT_SETTINGS.keyboard,
|
|
1371
|
+
...userSettings.keyboard || {}
|
|
1372
|
+
}
|
|
1356
1373
|
};
|
|
1374
|
+
if (typeof userSettings.escapeToClose === "boolean" && userSettings.keyboard?.escape == null) {
|
|
1375
|
+
merged.keyboard.escape = userSettings.escapeToClose;
|
|
1376
|
+
}
|
|
1377
|
+
if (typeof merged.keyboard.backspace === "boolean") {
|
|
1378
|
+
merged.keyboard.backspaceRemovesLastWhenSearchEmpty = merged.keyboard.backspace;
|
|
1379
|
+
}
|
|
1357
1380
|
const skin = merged.skin || merged.theme || "classic";
|
|
1358
1381
|
return {
|
|
1359
1382
|
...merged,
|
|
@@ -1447,6 +1470,9 @@ var VueMultiselectDropdown = {
|
|
|
1447
1470
|
getKey(item) {
|
|
1448
1471
|
return getPrimaryValue(item, this.resolvedSettings);
|
|
1449
1472
|
},
|
|
1473
|
+
getOptionId(key) {
|
|
1474
|
+
return `${this.instanceId}-option-${key}`;
|
|
1475
|
+
},
|
|
1450
1476
|
isSelected(item) {
|
|
1451
1477
|
const key = this.getKey(item);
|
|
1452
1478
|
return this.selected.some((selectedItem) => this.getKey(selectedItem) === key);
|
|
@@ -1579,6 +1605,13 @@ var VueMultiselectDropdown = {
|
|
|
1579
1605
|
this.emitSelection(next);
|
|
1580
1606
|
this.$emit("de-select", item);
|
|
1581
1607
|
},
|
|
1608
|
+
removeLastSelected() {
|
|
1609
|
+
const last = this.selected[this.selected.length - 1];
|
|
1610
|
+
if (!last) {
|
|
1611
|
+
return;
|
|
1612
|
+
}
|
|
1613
|
+
this.removeItem(last);
|
|
1614
|
+
},
|
|
1582
1615
|
addFilterItem(event) {
|
|
1583
1616
|
event.preventDefault();
|
|
1584
1617
|
event.stopPropagation();
|
|
@@ -1595,35 +1628,51 @@ var VueMultiselectDropdown = {
|
|
|
1595
1628
|
this.query = "";
|
|
1596
1629
|
},
|
|
1597
1630
|
onTriggerKeydown(event) {
|
|
1598
|
-
|
|
1631
|
+
const keyboard = this.resolvedSettings.keyboard;
|
|
1632
|
+
if (event.key === "Enter" || isSpaceKey(event) && keyboard.space !== false) {
|
|
1599
1633
|
event.preventDefault();
|
|
1600
1634
|
this.toggleDropdown();
|
|
1601
1635
|
return;
|
|
1602
1636
|
}
|
|
1603
|
-
if (event.key === "ArrowDown") {
|
|
1637
|
+
if (keyboard.arrows !== false && event.key === "ArrowDown") {
|
|
1604
1638
|
event.preventDefault();
|
|
1605
1639
|
this.openDropdown();
|
|
1606
1640
|
this.focusFirstOption();
|
|
1607
1641
|
return;
|
|
1608
1642
|
}
|
|
1609
|
-
if (event.key === "ArrowUp") {
|
|
1643
|
+
if (keyboard.arrows !== false && event.key === "ArrowUp") {
|
|
1610
1644
|
event.preventDefault();
|
|
1611
1645
|
this.openDropdown();
|
|
1612
1646
|
this.focusLastOption();
|
|
1613
1647
|
return;
|
|
1614
1648
|
}
|
|
1615
|
-
if (event.key === "Escape") {
|
|
1649
|
+
if (keyboard.escape !== false && event.key === "Escape") {
|
|
1616
1650
|
this.closeDropdown();
|
|
1617
1651
|
}
|
|
1618
1652
|
},
|
|
1619
1653
|
onListKeydown(event) {
|
|
1620
|
-
|
|
1654
|
+
const keyboard = this.resolvedSettings.keyboard;
|
|
1655
|
+
if (keyboard.escape !== false && event.key === "Escape") {
|
|
1621
1656
|
event.preventDefault();
|
|
1622
1657
|
event.stopPropagation();
|
|
1623
1658
|
this.closeDropdown();
|
|
1624
1659
|
return;
|
|
1625
1660
|
}
|
|
1626
|
-
if (
|
|
1661
|
+
if (event.key === "Tab") {
|
|
1662
|
+
return;
|
|
1663
|
+
}
|
|
1664
|
+
if (isTextInputTarget(event.target)) {
|
|
1665
|
+
if (event.key === "Backspace" && !this.query && keyboard.backspaceRemovesLastWhenSearchEmpty === true) {
|
|
1666
|
+
event.preventDefault();
|
|
1667
|
+
event.stopPropagation();
|
|
1668
|
+
this.removeLastSelected();
|
|
1669
|
+
return;
|
|
1670
|
+
}
|
|
1671
|
+
if (!["ArrowDown", "ArrowUp", "Home", "End"].includes(event.key)) {
|
|
1672
|
+
return;
|
|
1673
|
+
}
|
|
1674
|
+
}
|
|
1675
|
+
if (keyboard.arrows === false && ["ArrowDown", "ArrowUp", "Home", "End"].includes(event.key)) {
|
|
1627
1676
|
return;
|
|
1628
1677
|
}
|
|
1629
1678
|
const selectable = this.visibleSelectableItems();
|
|
@@ -1658,10 +1707,22 @@ var VueMultiselectDropdown = {
|
|
|
1658
1707
|
return;
|
|
1659
1708
|
}
|
|
1660
1709
|
if (isActivationKey(event)) {
|
|
1710
|
+
if (isSpaceKey(event) && keyboard.space === false) {
|
|
1711
|
+
return;
|
|
1712
|
+
}
|
|
1661
1713
|
event.preventDefault();
|
|
1662
1714
|
event.stopPropagation();
|
|
1663
1715
|
const activeItem = selectable.find((item) => this.getKey(item) === this.focusedKey) || selectable[0];
|
|
1664
1716
|
this.toggleItem(activeItem);
|
|
1717
|
+
if (keyboard.spaceOptionAction === "toggle-and-next") {
|
|
1718
|
+
const activeIndex = selectable.findIndex((item) => this.getKey(item) === this.getKey(activeItem));
|
|
1719
|
+
const nextItem = selectable[Math.min(activeIndex + 1, selectable.length - 1)];
|
|
1720
|
+
if (nextItem) {
|
|
1721
|
+
this.focusOption(nextItem);
|
|
1722
|
+
}
|
|
1723
|
+
} else {
|
|
1724
|
+
this.focusOption(activeItem);
|
|
1725
|
+
}
|
|
1665
1726
|
return;
|
|
1666
1727
|
}
|
|
1667
1728
|
},
|
|
@@ -1698,19 +1759,26 @@ var VueMultiselectDropdown = {
|
|
|
1698
1759
|
if (isActivationKey(event)) {
|
|
1699
1760
|
event.stopPropagation();
|
|
1700
1761
|
}
|
|
1701
|
-
if (event.key === "ArrowDown") {
|
|
1762
|
+
if (this.resolvedSettings.keyboard.arrows !== false && event.key === "ArrowDown") {
|
|
1702
1763
|
event.preventDefault();
|
|
1703
1764
|
event.stopPropagation();
|
|
1704
1765
|
this.openDropdown();
|
|
1705
1766
|
this.focusFirstOption();
|
|
1706
1767
|
}
|
|
1707
|
-
if (event.key === "ArrowUp") {
|
|
1768
|
+
if (this.resolvedSettings.keyboard.arrows !== false && event.key === "ArrowUp") {
|
|
1708
1769
|
event.preventDefault();
|
|
1709
1770
|
event.stopPropagation();
|
|
1710
1771
|
this.openDropdown();
|
|
1711
1772
|
this.focusLastOption();
|
|
1712
1773
|
}
|
|
1713
1774
|
},
|
|
1775
|
+
onRemoveButtonKeydown(item, event) {
|
|
1776
|
+
if (this.resolvedSettings.keyboard.deleteRemovesFocusedBadge !== false && (event.key === "Backspace" || event.key === "Delete")) {
|
|
1777
|
+
this.removeItem(item, event);
|
|
1778
|
+
return;
|
|
1779
|
+
}
|
|
1780
|
+
this.onInlineKeydown(event);
|
|
1781
|
+
},
|
|
1714
1782
|
onTriggerClick(event) {
|
|
1715
1783
|
const target = event.target;
|
|
1716
1784
|
if (target && target.closest("button")) {
|
|
@@ -1731,7 +1799,7 @@ var VueMultiselectDropdown = {
|
|
|
1731
1799
|
this.closeDropdown();
|
|
1732
1800
|
},
|
|
1733
1801
|
onDocumentKeydown(event) {
|
|
1734
|
-
if (this.isOpen && this.resolvedSettings.
|
|
1802
|
+
if (this.isOpen && this.resolvedSettings.keyboard.escape !== false && event.key === "Escape") {
|
|
1735
1803
|
this.closeDropdown();
|
|
1736
1804
|
}
|
|
1737
1805
|
},
|
|
@@ -1849,11 +1917,14 @@ var VueMultiselectDropdown = {
|
|
|
1849
1917
|
label,
|
|
1850
1918
|
selected: true,
|
|
1851
1919
|
disabled: false,
|
|
1920
|
+
key: this.getKey(item),
|
|
1921
|
+
ariaSelected: "true",
|
|
1922
|
+
ariaChecked: "true",
|
|
1852
1923
|
query: this.query,
|
|
1853
1924
|
toggle: () => this.toggleItem(item),
|
|
1854
1925
|
remove: () => this.removeItem(item)
|
|
1855
1926
|
};
|
|
1856
|
-
const rendered = callRenderFunction(this.renderBadge, h, item, context);
|
|
1927
|
+
const rendered = callSlot(this, "badge", context) || callRenderFunction(this.renderBadge, h, item, context);
|
|
1857
1928
|
const removeLabel = typeof settings.removeItemAriaLabel === "function" ? settings.removeItemAriaLabel(item) : `${settings.removeItemAriaLabel}: ${label}`;
|
|
1858
1929
|
return h("span", { class: "vmsd-badge", key: this.getKey(item) }, [
|
|
1859
1930
|
h("span", { class: "vmsd-badge-label" }, [rendered || label]),
|
|
@@ -1864,17 +1935,18 @@ var VueMultiselectDropdown = {
|
|
|
1864
1935
|
attrs: { type: "button", "aria-label": removeLabel },
|
|
1865
1936
|
on: {
|
|
1866
1937
|
click: (event) => this.removeItem(item, event),
|
|
1867
|
-
keydown: this.
|
|
1938
|
+
keydown: (event) => this.onRemoveButtonKeydown(item, event)
|
|
1868
1939
|
}
|
|
1869
1940
|
},
|
|
1870
1941
|
[renderIcon(h, "remove")]
|
|
1871
1942
|
)
|
|
1872
1943
|
]);
|
|
1873
1944
|
});
|
|
1874
|
-
const valueContent = hasSelection ? [h("span", { class: "vmsd-badge-list" }, badges)] : [
|
|
1875
|
-
|
|
1876
|
-
|
|
1877
|
-
|
|
1945
|
+
const valueContent = hasSelection ? [h("span", { class: "vmsd-badge-list" }, badges)] : [
|
|
1946
|
+
h("span", { class: "vmsd-placeholder" }, [
|
|
1947
|
+
callSlot(this, "placeholder", { label: settings.text, state: { isOpen: this.isOpen, query: this.query } }) || settings.text
|
|
1948
|
+
])
|
|
1949
|
+
];
|
|
1878
1950
|
const trigger = h(
|
|
1879
1951
|
"div",
|
|
1880
1952
|
{
|
|
@@ -1887,7 +1959,8 @@ var VueMultiselectDropdown = {
|
|
|
1887
1959
|
"aria-expanded": this.isOpen ? "true" : "false",
|
|
1888
1960
|
"aria-haspopup": "listbox",
|
|
1889
1961
|
"aria-disabled": settings.disabled ? "true" : "false",
|
|
1890
|
-
"aria-controls": `${this.instanceId}-listbox
|
|
1962
|
+
"aria-controls": `${this.instanceId}-listbox`,
|
|
1963
|
+
"aria-activedescendant": this.focusedKey ? this.getOptionId(this.focusedKey) : void 0
|
|
1891
1964
|
},
|
|
1892
1965
|
on: {
|
|
1893
1966
|
click: this.onTriggerClick,
|
|
@@ -1895,8 +1968,15 @@ var VueMultiselectDropdown = {
|
|
|
1895
1968
|
}
|
|
1896
1969
|
},
|
|
1897
1970
|
[
|
|
1898
|
-
|
|
1971
|
+
callSlot(this, "trigger", {
|
|
1972
|
+
selected: this.selected,
|
|
1973
|
+
label: hasSelection ? this.selected.map((item) => this.getLabel(item)).join(", ") : settings.text,
|
|
1974
|
+
isOpen: this.isOpen,
|
|
1975
|
+
clearSelection: this.clearSelection,
|
|
1976
|
+
toggleDropdown: this.toggleDropdown
|
|
1977
|
+
}) || h("div", { class: "vmsd-value" }, valueContent),
|
|
1899
1978
|
h("div", { class: "vmsd-actions" }, [
|
|
1979
|
+
hiddenCount > 0 ? h("span", { class: "vmsd-overflow", attrs: { "aria-label": `${hiddenCount} more selected options` } }, [`+${hiddenCount}`]) : null,
|
|
1900
1980
|
hasClear ? h(
|
|
1901
1981
|
"button",
|
|
1902
1982
|
{
|
|
@@ -1995,28 +2075,37 @@ var VueMultiselectDropdown = {
|
|
|
1995
2075
|
label,
|
|
1996
2076
|
selected,
|
|
1997
2077
|
disabled,
|
|
2078
|
+
index: this.filteredItems.findIndex((candidate) => this.getKey(candidate) === key),
|
|
2079
|
+
group: getGroupName(item, settings),
|
|
2080
|
+
key,
|
|
2081
|
+
optionId: this.getOptionId(key),
|
|
2082
|
+
ariaSelected: selected ? "true" : "false",
|
|
2083
|
+
ariaChecked: selected ? "true" : "false",
|
|
1998
2084
|
query: this.query,
|
|
1999
2085
|
toggle: () => this.toggleItem(item),
|
|
2000
2086
|
remove: () => this.removeItem(item)
|
|
2001
2087
|
};
|
|
2002
|
-
const rendered = callRenderFunction(this.renderItem, h, item, context);
|
|
2088
|
+
const rendered = callSlot(this, "option", context) || callRenderFunction(this.renderItem, h, item, context);
|
|
2003
2089
|
return h(
|
|
2004
2090
|
"div",
|
|
2005
2091
|
{
|
|
2006
2092
|
key,
|
|
2007
2093
|
class: ["vmsd-option", selected ? "vmsd-selected" : "", disabled ? "vmsd-disabled" : ""],
|
|
2008
2094
|
attrs: {
|
|
2095
|
+
id: this.getOptionId(key),
|
|
2009
2096
|
role: "option",
|
|
2010
2097
|
tabindex: disabled ? "-1" : "0",
|
|
2011
2098
|
"data-vmsd-option": "true",
|
|
2012
2099
|
"data-vmsd-key": key,
|
|
2013
2100
|
"aria-disabled": disabled ? "true" : "false",
|
|
2014
|
-
"aria-selected": selected ? "true" : "false"
|
|
2101
|
+
"aria-selected": selected ? "true" : "false",
|
|
2102
|
+
"aria-checked": selected ? "true" : "false"
|
|
2015
2103
|
},
|
|
2016
2104
|
on: {
|
|
2017
2105
|
click: (event) => {
|
|
2018
2106
|
if (!disabled) {
|
|
2019
2107
|
this.toggleItem(item, event);
|
|
2108
|
+
this.focusOption(item);
|
|
2020
2109
|
}
|
|
2021
2110
|
},
|
|
2022
2111
|
focus: () => this.focusedKey = key,
|
|
@@ -2033,9 +2122,13 @@ var VueMultiselectDropdown = {
|
|
|
2033
2122
|
]
|
|
2034
2123
|
);
|
|
2035
2124
|
};
|
|
2036
|
-
const listChildren = settings.loading ? [h("div", { class: "vmsd-state", attrs: { role: "status" } }, [settings.loadingText])] : settings.groupBy ? this.groupedItems.map(
|
|
2125
|
+
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(
|
|
2037
2126
|
(group) => h("div", { class: "vmsd-group", key: group.name, attrs: { role: "group", "aria-label": group.name } }, [
|
|
2038
|
-
|
|
2127
|
+
callSlot(this, "group-header", {
|
|
2128
|
+
group,
|
|
2129
|
+
selected: group.items.filter((item) => !isDisabledItem(item)).every((item) => this.isSelected(item)),
|
|
2130
|
+
selectGroup: (event) => this.selectGroup(group.name, group.items, event)
|
|
2131
|
+
}) || h("div", { class: "vmsd-group-header" }, [
|
|
2039
2132
|
h("span", [`${group.name} \xB7 ${group.items.length}`]),
|
|
2040
2133
|
settings.selectGroup ? h(
|
|
2041
2134
|
"button",
|
|
@@ -2050,8 +2143,8 @@ var VueMultiselectDropdown = {
|
|
|
2050
2143
|
group.items.map(renderOption)
|
|
2051
2144
|
])
|
|
2052
2145
|
) : this.filteredItems.map(renderOption);
|
|
2053
|
-
if (!this.filteredItems.length && !settings.loading) {
|
|
2054
|
-
const emptyContent = this.renderEmptyState ? this.renderEmptyState(this.query, h) : settings.noDataLabel;
|
|
2146
|
+
if (this.isOpen && !this.filteredItems.length && !settings.loading) {
|
|
2147
|
+
const emptyContent = callSlot(this, "empty", { query: this.query, label: settings.noDataLabel }) || (this.renderEmptyState ? this.renderEmptyState(this.query, h) : settings.noDataLabel);
|
|
2055
2148
|
listChildren.push(h("div", { class: "vmsd-state" }, [emptyContent]));
|
|
2056
2149
|
}
|
|
2057
2150
|
const menu = h(
|
|
@@ -2081,7 +2174,8 @@ var VueMultiselectDropdown = {
|
|
|
2081
2174
|
on: { scroll: this.onListScroll }
|
|
2082
2175
|
},
|
|
2083
2176
|
listChildren
|
|
2084
|
-
)
|
|
2177
|
+
),
|
|
2178
|
+
this.isOpen ? callSlot(this, "menu-footer", { selected: this.selected, filteredItems: this.filteredItems, close: this.closeDropdown }) : null
|
|
2085
2179
|
]
|
|
2086
2180
|
);
|
|
2087
2181
|
return h(
|
|
@@ -2109,6 +2203,498 @@ var VueMultiselectDropdown = {
|
|
|
2109
2203
|
};
|
|
2110
2204
|
var StacklineVueMultiselect = VueMultiselectDropdown;
|
|
2111
2205
|
|
|
2206
|
+
// src/composables.ts
|
|
2207
|
+
import { computed, ref, unref } from "vue";
|
|
2208
|
+
var DEFAULT_KEYS = {
|
|
2209
|
+
labelKey: "itemName",
|
|
2210
|
+
primaryKey: "id"
|
|
2211
|
+
};
|
|
2212
|
+
function read(value, fallback) {
|
|
2213
|
+
return value == null ? fallback : unref(value);
|
|
2214
|
+
}
|
|
2215
|
+
function isPrimitiveItem2(item) {
|
|
2216
|
+
return typeof item === "string" || typeof item === "number" || typeof item === "boolean";
|
|
2217
|
+
}
|
|
2218
|
+
function resolveSettings(settings) {
|
|
2219
|
+
const value = read(settings, {});
|
|
2220
|
+
return {
|
|
2221
|
+
...value,
|
|
2222
|
+
text: value.text || "Select",
|
|
2223
|
+
singleSelection: Boolean(value.singleSelection),
|
|
2224
|
+
labelKey: value.labelKey || DEFAULT_KEYS.labelKey,
|
|
2225
|
+
primaryKey: value.primaryKey || DEFAULT_KEYS.primaryKey,
|
|
2226
|
+
searchBy: Array.isArray(value.searchBy) ? value.searchBy : [],
|
|
2227
|
+
groupBy: value.groupBy || ""
|
|
2228
|
+
};
|
|
2229
|
+
}
|
|
2230
|
+
function getLabel2(item, settings) {
|
|
2231
|
+
if (isPrimitiveItem2(item)) {
|
|
2232
|
+
return String(item);
|
|
2233
|
+
}
|
|
2234
|
+
const labelKey = settings.labelKey || DEFAULT_KEYS.labelKey;
|
|
2235
|
+
const keys = [labelKey, "itemName", "name", "label", "title", "value"];
|
|
2236
|
+
for (const key of keys) {
|
|
2237
|
+
if (item[key] != null) {
|
|
2238
|
+
return String(item[key]);
|
|
2239
|
+
}
|
|
2240
|
+
}
|
|
2241
|
+
return JSON.stringify(item);
|
|
2242
|
+
}
|
|
2243
|
+
function getKey(item, settings) {
|
|
2244
|
+
if (isPrimitiveItem2(item)) {
|
|
2245
|
+
return String(item);
|
|
2246
|
+
}
|
|
2247
|
+
const primaryKey = settings.primaryKey || DEFAULT_KEYS.primaryKey;
|
|
2248
|
+
const keys = [primaryKey, "id", "value", "key"];
|
|
2249
|
+
for (const key of keys) {
|
|
2250
|
+
if (item[key] != null) {
|
|
2251
|
+
return String(item[key]);
|
|
2252
|
+
}
|
|
2253
|
+
}
|
|
2254
|
+
return getLabel2(item, settings);
|
|
2255
|
+
}
|
|
2256
|
+
function getGroup(item, settings) {
|
|
2257
|
+
if (!settings.groupBy) {
|
|
2258
|
+
return void 0;
|
|
2259
|
+
}
|
|
2260
|
+
if (typeof settings.groupBy === "function") {
|
|
2261
|
+
return settings.groupBy(item);
|
|
2262
|
+
}
|
|
2263
|
+
return !isPrimitiveItem2(item) && item[settings.groupBy] != null ? String(item[settings.groupBy]) : void 0;
|
|
2264
|
+
}
|
|
2265
|
+
function isDisabled(item) {
|
|
2266
|
+
return !isPrimitiveItem2(item) && Boolean(item.disabled);
|
|
2267
|
+
}
|
|
2268
|
+
function matchesQuery(item, query, settings) {
|
|
2269
|
+
const needle = query.trim().toLowerCase();
|
|
2270
|
+
if (!needle) {
|
|
2271
|
+
return true;
|
|
2272
|
+
}
|
|
2273
|
+
const values = /* @__PURE__ */ new Set([getLabel2(item, settings).toLowerCase()]);
|
|
2274
|
+
if (!isPrimitiveItem2(item)) {
|
|
2275
|
+
const keys = settings.searchBy && settings.searchBy.length ? settings.searchBy : [settings.labelKey || DEFAULT_KEYS.labelKey];
|
|
2276
|
+
for (const key of keys) {
|
|
2277
|
+
if (key && item[key] != null) {
|
|
2278
|
+
values.add(String(item[key]).toLowerCase());
|
|
2279
|
+
}
|
|
2280
|
+
}
|
|
2281
|
+
}
|
|
2282
|
+
return Array.from(values).some((value) => value.includes(needle));
|
|
2283
|
+
}
|
|
2284
|
+
function mergeSelected(selected, incoming, settings) {
|
|
2285
|
+
const byKey = /* @__PURE__ */ new Map();
|
|
2286
|
+
for (const item of selected) {
|
|
2287
|
+
byKey.set(getKey(item, settings), item);
|
|
2288
|
+
}
|
|
2289
|
+
for (const item of incoming) {
|
|
2290
|
+
const key = getKey(item, settings);
|
|
2291
|
+
if (!byKey.has(key)) {
|
|
2292
|
+
byKey.set(key, item);
|
|
2293
|
+
}
|
|
2294
|
+
}
|
|
2295
|
+
return Array.from(byKey.values());
|
|
2296
|
+
}
|
|
2297
|
+
function readBadgeLimit(selected, settings) {
|
|
2298
|
+
if (settings.singleSelection) {
|
|
2299
|
+
return selected.length;
|
|
2300
|
+
}
|
|
2301
|
+
const value = Number(settings.badgeShowLimit);
|
|
2302
|
+
if (!Number.isFinite(value) || value <= 0) {
|
|
2303
|
+
return selected.length;
|
|
2304
|
+
}
|
|
2305
|
+
return Math.floor(value);
|
|
2306
|
+
}
|
|
2307
|
+
function normalizeExtraProps(props = {}) {
|
|
2308
|
+
const normalized = { ...props };
|
|
2309
|
+
if (normalized.className && !normalized.class) {
|
|
2310
|
+
normalized.class = normalized.className;
|
|
2311
|
+
}
|
|
2312
|
+
delete normalized.className;
|
|
2313
|
+
return normalized;
|
|
2314
|
+
}
|
|
2315
|
+
function mergePropBags(base, extra = {}) {
|
|
2316
|
+
const incoming = normalizeExtraProps(extra);
|
|
2317
|
+
const merged = { ...incoming, ...base };
|
|
2318
|
+
if (base.class || incoming.class) {
|
|
2319
|
+
merged.class = [incoming.class, base.class].filter(Boolean).join(" ");
|
|
2320
|
+
}
|
|
2321
|
+
if (base.style || incoming.style) {
|
|
2322
|
+
merged.style = {
|
|
2323
|
+
...typeof incoming.style === "object" ? incoming.style : {},
|
|
2324
|
+
...typeof base.style === "object" ? base.style : {}
|
|
2325
|
+
};
|
|
2326
|
+
}
|
|
2327
|
+
for (const key of Object.keys(base)) {
|
|
2328
|
+
if (/^on[A-Z]/.test(key) && typeof base[key] === "function" && typeof incoming[key] === "function") {
|
|
2329
|
+
merged[key] = (...args) => {
|
|
2330
|
+
incoming[key](...args);
|
|
2331
|
+
base[key](...args);
|
|
2332
|
+
};
|
|
2333
|
+
}
|
|
2334
|
+
}
|
|
2335
|
+
return merged;
|
|
2336
|
+
}
|
|
2337
|
+
function defineSettings(settings) {
|
|
2338
|
+
return settings;
|
|
2339
|
+
}
|
|
2340
|
+
function defineSlots(slots) {
|
|
2341
|
+
return slots;
|
|
2342
|
+
}
|
|
2343
|
+
function useMultiSelectState(options = {}) {
|
|
2344
|
+
const internalSelected = ref(options.defaultSelectedItems ? options.defaultSelectedItems.slice() : []);
|
|
2345
|
+
const filter = ref("");
|
|
2346
|
+
const settings = computed(() => resolveSettings(options.settings));
|
|
2347
|
+
const data = computed(() => read(options.data, []));
|
|
2348
|
+
const selectedItems = computed(() => read(options.selectedItems, internalSelected.value));
|
|
2349
|
+
const filteredItems = computed(() => data.value.filter((item) => matchesQuery(item, filter.value, settings.value)));
|
|
2350
|
+
const isSelected = (item) => {
|
|
2351
|
+
const key = getKey(item, settings.value);
|
|
2352
|
+
return selectedItems.value.some((selected) => getKey(selected, settings.value) === key);
|
|
2353
|
+
};
|
|
2354
|
+
const commit = (next) => {
|
|
2355
|
+
if (!options.selectedItems) {
|
|
2356
|
+
internalSelected.value = next;
|
|
2357
|
+
}
|
|
2358
|
+
options.onChange?.(next);
|
|
2359
|
+
};
|
|
2360
|
+
const getItemKey = (item) => getKey(item, settings.value);
|
|
2361
|
+
const getItemLabel = (item) => getLabel2(item, settings.value);
|
|
2362
|
+
const selectableItems = computed(() => filteredItems.value.filter((item) => !isDisabled(item)));
|
|
2363
|
+
const visibleBadges = computed(() => {
|
|
2364
|
+
const limit = readBadgeLimit(selectedItems.value, settings.value);
|
|
2365
|
+
return selectedItems.value.slice(0, limit);
|
|
2366
|
+
});
|
|
2367
|
+
const hiddenBadgeCount = computed(() => Math.max(selectedItems.value.length - visibleBadges.value.length, 0));
|
|
2368
|
+
const allFilteredSelected = computed(() => selectableItems.value.length > 0 && selectableItems.value.every((item) => isSelected(item)));
|
|
2369
|
+
const removeItem = (item) => {
|
|
2370
|
+
const key = getItemKey(item);
|
|
2371
|
+
const next = selectedItems.value.filter((selected) => getItemKey(selected) !== key);
|
|
2372
|
+
commit(next);
|
|
2373
|
+
options.onDeSelect?.(item);
|
|
2374
|
+
};
|
|
2375
|
+
const addItem = (item) => {
|
|
2376
|
+
if (isDisabled(item)) {
|
|
2377
|
+
return;
|
|
2378
|
+
}
|
|
2379
|
+
if (settings.value.singleSelection) {
|
|
2380
|
+
commit([item]);
|
|
2381
|
+
options.onSelect?.(item);
|
|
2382
|
+
return;
|
|
2383
|
+
}
|
|
2384
|
+
if (!isSelected(item)) {
|
|
2385
|
+
commit(selectedItems.value.concat(item));
|
|
2386
|
+
options.onSelect?.(item);
|
|
2387
|
+
}
|
|
2388
|
+
};
|
|
2389
|
+
const toggleItem = (item) => {
|
|
2390
|
+
if (isDisabled(item)) {
|
|
2391
|
+
return;
|
|
2392
|
+
}
|
|
2393
|
+
if (isSelected(item)) {
|
|
2394
|
+
removeItem(item);
|
|
2395
|
+
return;
|
|
2396
|
+
}
|
|
2397
|
+
addItem(item);
|
|
2398
|
+
};
|
|
2399
|
+
const clearSelection = () => {
|
|
2400
|
+
const previous = selectedItems.value.slice();
|
|
2401
|
+
commit([]);
|
|
2402
|
+
options.onDeSelectAll?.(previous);
|
|
2403
|
+
};
|
|
2404
|
+
const deSelectAll = (items) => {
|
|
2405
|
+
if (!items || !items.length) {
|
|
2406
|
+
clearSelection();
|
|
2407
|
+
return;
|
|
2408
|
+
}
|
|
2409
|
+
const keys = new Set(items.map(getItemKey));
|
|
2410
|
+
commit(selectedItems.value.filter((item) => !keys.has(getItemKey(item))));
|
|
2411
|
+
options.onDeSelectAll?.(items);
|
|
2412
|
+
};
|
|
2413
|
+
const selectAll = (items) => {
|
|
2414
|
+
const enabled = (items || selectableItems.value).filter((item) => !isDisabled(item));
|
|
2415
|
+
const before = selectedItems.value.length;
|
|
2416
|
+
commit(settings.value.singleSelection ? enabled.slice(0, 1) : mergeSelected(selectedItems.value, enabled, settings.value));
|
|
2417
|
+
options.onSelectAll?.(enabled);
|
|
2418
|
+
if (!enabled.length && before !== selectedItems.value.length) {
|
|
2419
|
+
options.onChange?.(selectedItems.value);
|
|
2420
|
+
}
|
|
2421
|
+
};
|
|
2422
|
+
const toggleGroup = (groupName, items) => {
|
|
2423
|
+
const enabled = items.filter((item) => !isDisabled(item));
|
|
2424
|
+
if (!enabled.length) {
|
|
2425
|
+
return;
|
|
2426
|
+
}
|
|
2427
|
+
const everySelected = enabled.every((item) => isSelected(item));
|
|
2428
|
+
if (everySelected) {
|
|
2429
|
+
deSelectAll(enabled);
|
|
2430
|
+
options.onGroupDeSelect?.(groupName, enabled);
|
|
2431
|
+
return;
|
|
2432
|
+
}
|
|
2433
|
+
selectAll(enabled);
|
|
2434
|
+
options.onGroupSelect?.(groupName, enabled);
|
|
2435
|
+
};
|
|
2436
|
+
const removeLastSelectedItem = () => {
|
|
2437
|
+
const last = selectedItems.value[selectedItems.value.length - 1];
|
|
2438
|
+
if (last) {
|
|
2439
|
+
removeItem(last);
|
|
2440
|
+
}
|
|
2441
|
+
};
|
|
2442
|
+
return {
|
|
2443
|
+
data,
|
|
2444
|
+
settings,
|
|
2445
|
+
filter,
|
|
2446
|
+
filteredItems,
|
|
2447
|
+
selectableItems,
|
|
2448
|
+
selectedItems,
|
|
2449
|
+
visibleBadges,
|
|
2450
|
+
hiddenBadgeCount,
|
|
2451
|
+
allFilteredSelected,
|
|
2452
|
+
isSelected,
|
|
2453
|
+
getItemKey,
|
|
2454
|
+
getItemLabel,
|
|
2455
|
+
setFilter: (value) => {
|
|
2456
|
+
filter.value = value;
|
|
2457
|
+
},
|
|
2458
|
+
selectItem: addItem,
|
|
2459
|
+
removeItem,
|
|
2460
|
+
removeLastSelectedItem,
|
|
2461
|
+
toggleItem,
|
|
2462
|
+
clearSelection,
|
|
2463
|
+
selectAll,
|
|
2464
|
+
deSelectAll,
|
|
2465
|
+
toggleGroup
|
|
2466
|
+
};
|
|
2467
|
+
}
|
|
2468
|
+
function useMultiSelectDropdown(options = {}) {
|
|
2469
|
+
const state = useMultiSelectState(options);
|
|
2470
|
+
const isOpen = ref(false);
|
|
2471
|
+
const query = ref("");
|
|
2472
|
+
const activeKey = ref("");
|
|
2473
|
+
const instanceId = `stackline-vmsd-headless-${Math.random().toString(36).slice(2)}`;
|
|
2474
|
+
const listboxId = `${instanceId}-listbox`;
|
|
2475
|
+
const visibleOptions = computed(() => {
|
|
2476
|
+
let index = 0;
|
|
2477
|
+
return state.filteredItems.value.map((item) => {
|
|
2478
|
+
const key = getKey(item, state.settings.value);
|
|
2479
|
+
return {
|
|
2480
|
+
item,
|
|
2481
|
+
key,
|
|
2482
|
+
label: getLabel2(item, state.settings.value),
|
|
2483
|
+
selected: state.isSelected(item),
|
|
2484
|
+
disabled: isDisabled(item),
|
|
2485
|
+
group: getGroup(item, state.settings.value),
|
|
2486
|
+
index: index++
|
|
2487
|
+
};
|
|
2488
|
+
});
|
|
2489
|
+
});
|
|
2490
|
+
const activeDescendantId = computed(() => activeKey.value ? `${instanceId}-option-${activeKey.value}` : void 0);
|
|
2491
|
+
const groups = computed(() => {
|
|
2492
|
+
const byName = /* @__PURE__ */ new Map();
|
|
2493
|
+
for (const option of visibleOptions.value) {
|
|
2494
|
+
const name = option.group || "Ungrouped";
|
|
2495
|
+
const existing = byName.get(name) || [];
|
|
2496
|
+
existing.push(option);
|
|
2497
|
+
byName.set(name, existing);
|
|
2498
|
+
}
|
|
2499
|
+
return Array.from(byName.entries()).map(([name, items]) => {
|
|
2500
|
+
const enabledItems = items.filter((option) => !option.disabled);
|
|
2501
|
+
return {
|
|
2502
|
+
name,
|
|
2503
|
+
items,
|
|
2504
|
+
enabledItems,
|
|
2505
|
+
selected: enabledItems.length > 0 && enabledItems.every((option) => option.selected),
|
|
2506
|
+
disabled: enabledItems.length === 0
|
|
2507
|
+
};
|
|
2508
|
+
});
|
|
2509
|
+
});
|
|
2510
|
+
const label = computed(() => {
|
|
2511
|
+
if (!state.selectedItems.value.length) {
|
|
2512
|
+
return state.settings.value.text || "Select";
|
|
2513
|
+
}
|
|
2514
|
+
return state.selectedItems.value.map((item) => getLabel2(item, state.settings.value)).join(", ");
|
|
2515
|
+
});
|
|
2516
|
+
const open = () => {
|
|
2517
|
+
isOpen.value = true;
|
|
2518
|
+
if (!activeKey.value && visibleOptions.value[0]) {
|
|
2519
|
+
activeKey.value = visibleOptions.value[0].key;
|
|
2520
|
+
}
|
|
2521
|
+
};
|
|
2522
|
+
const close = () => {
|
|
2523
|
+
isOpen.value = false;
|
|
2524
|
+
};
|
|
2525
|
+
const toggleOpen = () => isOpen.value ? close() : open();
|
|
2526
|
+
const focusNext = (direction) => {
|
|
2527
|
+
const optionsList = visibleOptions.value.filter((option) => !option.disabled);
|
|
2528
|
+
const currentIndex = Math.max(0, optionsList.findIndex((option) => option.key === activeKey.value));
|
|
2529
|
+
const next = optionsList[Math.min(Math.max(currentIndex + direction, 0), optionsList.length - 1)];
|
|
2530
|
+
if (next) {
|
|
2531
|
+
activeKey.value = next.key;
|
|
2532
|
+
}
|
|
2533
|
+
};
|
|
2534
|
+
const getRootProps = (props = {}) => mergePropBags({
|
|
2535
|
+
"data-stackline-multiselect": "true",
|
|
2536
|
+
"data-open": isOpen.value ? "true" : "false"
|
|
2537
|
+
}, props);
|
|
2538
|
+
const getTriggerProps = (props = {}) => mergePropBags({
|
|
2539
|
+
type: "button",
|
|
2540
|
+
role: "combobox",
|
|
2541
|
+
"aria-expanded": isOpen.value ? "true" : "false",
|
|
2542
|
+
"aria-haspopup": "listbox",
|
|
2543
|
+
"aria-controls": listboxId,
|
|
2544
|
+
"aria-activedescendant": activeDescendantId.value,
|
|
2545
|
+
onClick: toggleOpen,
|
|
2546
|
+
onKeydown: (event) => {
|
|
2547
|
+
if (event.key === "Enter" || event.key === " " || event.key === "Spacebar") {
|
|
2548
|
+
event.preventDefault();
|
|
2549
|
+
toggleOpen();
|
|
2550
|
+
}
|
|
2551
|
+
if (event.key === "ArrowDown") {
|
|
2552
|
+
event.preventDefault();
|
|
2553
|
+
open();
|
|
2554
|
+
focusNext(1);
|
|
2555
|
+
}
|
|
2556
|
+
if (event.key === "ArrowUp") {
|
|
2557
|
+
event.preventDefault();
|
|
2558
|
+
open();
|
|
2559
|
+
focusNext(-1);
|
|
2560
|
+
}
|
|
2561
|
+
if (event.key === "Escape") {
|
|
2562
|
+
close();
|
|
2563
|
+
}
|
|
2564
|
+
}
|
|
2565
|
+
}, props);
|
|
2566
|
+
const getSearchInputProps = (props = {}) => mergePropBags({
|
|
2567
|
+
value: query.value,
|
|
2568
|
+
"aria-label": "Search options",
|
|
2569
|
+
onInput: (event) => {
|
|
2570
|
+
query.value = String(event.target.value || "");
|
|
2571
|
+
state.setFilter(query.value);
|
|
2572
|
+
},
|
|
2573
|
+
onKeydown: (event) => {
|
|
2574
|
+
if (event.key === "ArrowDown") {
|
|
2575
|
+
event.preventDefault();
|
|
2576
|
+
focusNext(1);
|
|
2577
|
+
}
|
|
2578
|
+
if (event.key === "ArrowUp") {
|
|
2579
|
+
event.preventDefault();
|
|
2580
|
+
focusNext(-1);
|
|
2581
|
+
}
|
|
2582
|
+
if (event.key === "Escape") {
|
|
2583
|
+
close();
|
|
2584
|
+
}
|
|
2585
|
+
}
|
|
2586
|
+
}, props);
|
|
2587
|
+
const getListboxProps = (props = {}) => mergePropBags({
|
|
2588
|
+
id: listboxId,
|
|
2589
|
+
role: "listbox",
|
|
2590
|
+
"aria-multiselectable": state.settings.value.singleSelection ? "false" : "true"
|
|
2591
|
+
}, props);
|
|
2592
|
+
const getOptionProps = (option, props = {}) => mergePropBags({
|
|
2593
|
+
id: `${instanceId}-option-${option.key}`,
|
|
2594
|
+
role: "option",
|
|
2595
|
+
tabindex: option.disabled ? -1 : 0,
|
|
2596
|
+
"aria-selected": option.selected ? "true" : "false",
|
|
2597
|
+
"aria-checked": option.selected ? "true" : "false",
|
|
2598
|
+
"aria-disabled": option.disabled ? "true" : "false",
|
|
2599
|
+
onMouseenter: () => {
|
|
2600
|
+
activeKey.value = option.key;
|
|
2601
|
+
},
|
|
2602
|
+
onClick: () => {
|
|
2603
|
+
if (!option.disabled) {
|
|
2604
|
+
state.toggleItem(option.item);
|
|
2605
|
+
activeKey.value = option.key;
|
|
2606
|
+
}
|
|
2607
|
+
},
|
|
2608
|
+
onKeydown: (event) => {
|
|
2609
|
+
if (event.key === "ArrowDown") {
|
|
2610
|
+
event.preventDefault();
|
|
2611
|
+
focusNext(1);
|
|
2612
|
+
}
|
|
2613
|
+
if (event.key === "ArrowUp") {
|
|
2614
|
+
event.preventDefault();
|
|
2615
|
+
focusNext(-1);
|
|
2616
|
+
}
|
|
2617
|
+
if (event.key === "Enter" || event.key === " " || event.key === "Spacebar") {
|
|
2618
|
+
event.preventDefault();
|
|
2619
|
+
state.toggleItem(option.item);
|
|
2620
|
+
activeKey.value = option.key;
|
|
2621
|
+
}
|
|
2622
|
+
if (event.key === "Escape") {
|
|
2623
|
+
close();
|
|
2624
|
+
}
|
|
2625
|
+
}
|
|
2626
|
+
}, props);
|
|
2627
|
+
const getClearAllButtonProps = (props = {}) => mergePropBags({
|
|
2628
|
+
type: "button",
|
|
2629
|
+
"aria-label": "Clear selected options",
|
|
2630
|
+
onClick: state.clearSelection
|
|
2631
|
+
}, props);
|
|
2632
|
+
const getRemoveButtonProps = (item, props = {}) => mergePropBags({
|
|
2633
|
+
type: "button",
|
|
2634
|
+
"aria-label": `Remove ${getLabel2(item, state.settings.value)}`,
|
|
2635
|
+
onClick: () => {
|
|
2636
|
+
state.removeItem(item);
|
|
2637
|
+
},
|
|
2638
|
+
onKeydown: (event) => {
|
|
2639
|
+
if (event.key === "Backspace" || event.key === "Delete") {
|
|
2640
|
+
event.preventDefault();
|
|
2641
|
+
state.removeItem(item);
|
|
2642
|
+
}
|
|
2643
|
+
}
|
|
2644
|
+
}, props);
|
|
2645
|
+
return {
|
|
2646
|
+
isOpen,
|
|
2647
|
+
query,
|
|
2648
|
+
filter: state.filter,
|
|
2649
|
+
activeKey,
|
|
2650
|
+
activeDescendantId,
|
|
2651
|
+
listboxId,
|
|
2652
|
+
settings: state.settings,
|
|
2653
|
+
filteredItems: state.filteredItems,
|
|
2654
|
+
selectableItems: state.selectableItems,
|
|
2655
|
+
selectedItems: state.selectedItems,
|
|
2656
|
+
visibleBadges: state.visibleBadges,
|
|
2657
|
+
hiddenBadgeCount: state.hiddenBadgeCount,
|
|
2658
|
+
visibleOptions,
|
|
2659
|
+
groups,
|
|
2660
|
+
allFilteredSelected: state.allFilteredSelected,
|
|
2661
|
+
label,
|
|
2662
|
+
open,
|
|
2663
|
+
close,
|
|
2664
|
+
toggleOpen,
|
|
2665
|
+
clearSelection: state.clearSelection,
|
|
2666
|
+
selectAll: state.selectAll,
|
|
2667
|
+
deSelectAll: state.deSelectAll,
|
|
2668
|
+
toggleGroup: state.toggleGroup,
|
|
2669
|
+
toggleItem: state.toggleItem,
|
|
2670
|
+
selectItem: state.selectItem,
|
|
2671
|
+
removeItem: state.removeItem,
|
|
2672
|
+
removeLastSelectedItem: state.removeLastSelectedItem,
|
|
2673
|
+
isSelected: state.isSelected,
|
|
2674
|
+
setFilter: (value) => {
|
|
2675
|
+
query.value = value;
|
|
2676
|
+
state.setFilter(value);
|
|
2677
|
+
},
|
|
2678
|
+
getItemKey: state.getItemKey,
|
|
2679
|
+
getItemLabel: state.getItemLabel,
|
|
2680
|
+
getRootProps,
|
|
2681
|
+
getTriggerProps,
|
|
2682
|
+
getSearchInputProps,
|
|
2683
|
+
getListboxProps,
|
|
2684
|
+
getOptionProps,
|
|
2685
|
+
getClearAllButtonProps,
|
|
2686
|
+
getRemoveButtonProps
|
|
2687
|
+
};
|
|
2688
|
+
}
|
|
2689
|
+
function createVueMultiselectDropdown() {
|
|
2690
|
+
return {
|
|
2691
|
+
defineSettings: (settings) => defineSettings(settings),
|
|
2692
|
+
defineSlots,
|
|
2693
|
+
useMultiSelectState: (options = {}) => useMultiSelectState(options),
|
|
2694
|
+
useMultiSelectDropdown: (options = {}) => useMultiSelectDropdown(options)
|
|
2695
|
+
};
|
|
2696
|
+
}
|
|
2697
|
+
|
|
2112
2698
|
// src/plugin.ts
|
|
2113
2699
|
var VueMultiselect = {
|
|
2114
2700
|
install(app) {
|
|
@@ -2123,5 +2709,10 @@ export {
|
|
|
2123
2709
|
StacklineVueMultiselect,
|
|
2124
2710
|
VueMultiselect,
|
|
2125
2711
|
VueMultiselectDropdown,
|
|
2126
|
-
|
|
2712
|
+
createVueMultiselectDropdown,
|
|
2713
|
+
plugin_default as default,
|
|
2714
|
+
defineSettings,
|
|
2715
|
+
defineSlots,
|
|
2716
|
+
useMultiSelectDropdown,
|
|
2717
|
+
useMultiSelectState
|
|
2127
2718
|
};
|