@stackline/react-multiselect-dropdown 19.0.2 → 19.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 +331 -23
- package/dist/index.cjs +1767 -428
- package/dist/index.d.cts +348 -6
- package/dist/index.d.ts +348 -6
- package/dist/index.js +1753 -410
- package/package.json +42 -3
package/dist/index.cjs
CHANGED
|
@@ -21,14 +21,207 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
21
21
|
var index_exports = {};
|
|
22
22
|
__export(index_exports, {
|
|
23
23
|
MultiSelectDropdown: () => MultiSelectDropdown,
|
|
24
|
-
ReactMultiSelectDropdown: () => ReactMultiSelectDropdown
|
|
24
|
+
ReactMultiSelectDropdown: () => ReactMultiSelectDropdown,
|
|
25
|
+
createMultiSelectDropdown: () => createMultiSelectDropdown,
|
|
26
|
+
useMultiSelectDropdown: () => useMultiSelectDropdown,
|
|
27
|
+
useMultiSelectState: () => useMultiSelectState
|
|
25
28
|
});
|
|
26
29
|
module.exports = __toCommonJS(index_exports);
|
|
27
30
|
|
|
28
31
|
// src/MultiSelectDropdown.tsx
|
|
29
|
-
var
|
|
32
|
+
var import_react2 = require("react");
|
|
30
33
|
var import_react_dom = require("react-dom");
|
|
31
34
|
|
|
35
|
+
// src/itemUtils.ts
|
|
36
|
+
function isPrimitiveItem(item) {
|
|
37
|
+
return typeof item === "string" || typeof item === "number" || typeof item === "boolean";
|
|
38
|
+
}
|
|
39
|
+
function getLabel(item, settings) {
|
|
40
|
+
if (isPrimitiveItem(item)) {
|
|
41
|
+
return String(item);
|
|
42
|
+
}
|
|
43
|
+
const keys = [settings.labelKey, "itemName", "name", "label", "title", "value"].filter(Boolean);
|
|
44
|
+
for (const key of keys) {
|
|
45
|
+
if (key && item[key] != null) {
|
|
46
|
+
return String(item[key]);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
return JSON.stringify(item);
|
|
50
|
+
}
|
|
51
|
+
function getPrimaryValue(item, settings) {
|
|
52
|
+
if (isPrimitiveItem(item)) {
|
|
53
|
+
return String(item);
|
|
54
|
+
}
|
|
55
|
+
const keys = [settings.primaryKey, "id", "value", "key"].filter(Boolean);
|
|
56
|
+
for (const key of keys) {
|
|
57
|
+
if (key && item[key] != null) {
|
|
58
|
+
return String(item[key]);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
return getLabel(item, settings);
|
|
62
|
+
}
|
|
63
|
+
function sanitizeId(value) {
|
|
64
|
+
return value.replace(/[^a-zA-Z0-9_-]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 56) || "option";
|
|
65
|
+
}
|
|
66
|
+
function normalizeSkinName(value) {
|
|
67
|
+
return sanitizeId(value.toLowerCase()) || "classic";
|
|
68
|
+
}
|
|
69
|
+
function itemMatchesQuery(item, query, settings) {
|
|
70
|
+
if (!query.trim()) {
|
|
71
|
+
return true;
|
|
72
|
+
}
|
|
73
|
+
const needle = query.trim().toLowerCase();
|
|
74
|
+
const haystack = /* @__PURE__ */ new Set([getLabel(item, settings).toLowerCase()]);
|
|
75
|
+
if (!isPrimitiveItem(item)) {
|
|
76
|
+
const objectItem = item;
|
|
77
|
+
const searchKeys = settings.searchBy.length ? settings.searchBy : [settings.labelKey];
|
|
78
|
+
for (const key of searchKeys) {
|
|
79
|
+
if (key && objectItem[key] != null) {
|
|
80
|
+
haystack.add(String(objectItem[key]).toLowerCase());
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
for (const value of haystack) {
|
|
85
|
+
if (value.includes(needle)) {
|
|
86
|
+
return true;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
return false;
|
|
90
|
+
}
|
|
91
|
+
function isDisabledItem(item) {
|
|
92
|
+
return !isPrimitiveItem(item) && Boolean(item.disabled);
|
|
93
|
+
}
|
|
94
|
+
function getGroupName(item, settings) {
|
|
95
|
+
if (!settings.groupBy) {
|
|
96
|
+
return "";
|
|
97
|
+
}
|
|
98
|
+
if (typeof settings.groupBy === "function") {
|
|
99
|
+
return settings.groupBy(item);
|
|
100
|
+
}
|
|
101
|
+
if (!isPrimitiveItem(item)) {
|
|
102
|
+
const objectItem = item;
|
|
103
|
+
if (settings.groupBy in objectItem) {
|
|
104
|
+
return String(objectItem[settings.groupBy] ?? "");
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
return "";
|
|
108
|
+
}
|
|
109
|
+
function mergeUniqueItems(base, extra, settings) {
|
|
110
|
+
const itemsById = /* @__PURE__ */ new Map();
|
|
111
|
+
for (const item of [...base, ...extra]) {
|
|
112
|
+
itemsById.set(getPrimaryValue(item, settings), item);
|
|
113
|
+
}
|
|
114
|
+
return Array.from(itemsById.values());
|
|
115
|
+
}
|
|
116
|
+
function createItemFromQuery(query, settings, sample) {
|
|
117
|
+
if (sample && !isPrimitiveItem(sample)) {
|
|
118
|
+
return {
|
|
119
|
+
[settings.primaryKey]: query.toLowerCase().replace(/\s+/g, "-"),
|
|
120
|
+
[settings.labelKey]: query
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
return query;
|
|
124
|
+
}
|
|
125
|
+
function buildGroups(items, settings) {
|
|
126
|
+
if (!settings.groupBy) {
|
|
127
|
+
return [];
|
|
128
|
+
}
|
|
129
|
+
const itemsByGroup = /* @__PURE__ */ new Map();
|
|
130
|
+
for (const item of items) {
|
|
131
|
+
const groupName = getGroupName(item, settings) || "Ungrouped";
|
|
132
|
+
const currentItems = itemsByGroup.get(groupName) || [];
|
|
133
|
+
currentItems.push(item);
|
|
134
|
+
itemsByGroup.set(groupName, currentItems);
|
|
135
|
+
}
|
|
136
|
+
return Array.from(itemsByGroup.entries()).map(([name, groupedItems]) => ({
|
|
137
|
+
name,
|
|
138
|
+
items: groupedItems
|
|
139
|
+
}));
|
|
140
|
+
}
|
|
141
|
+
function getVisibleBadgeLimit(selectedCount, rawLimit) {
|
|
142
|
+
if (!Number.isFinite(rawLimit)) {
|
|
143
|
+
return selectedCount;
|
|
144
|
+
}
|
|
145
|
+
return Math.min(selectedCount, Math.max(0, Math.floor(rawLimit)));
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// src/settings.ts
|
|
149
|
+
var DEFAULT_KEYBOARD_SETTINGS = {
|
|
150
|
+
space: true,
|
|
151
|
+
spaceOptionAction: "toggle",
|
|
152
|
+
tab: true,
|
|
153
|
+
arrows: true,
|
|
154
|
+
escape: true,
|
|
155
|
+
backspaceRemovesLastWhenSearchEmpty: false,
|
|
156
|
+
deleteRemovesFocusedBadge: true,
|
|
157
|
+
backspace: false
|
|
158
|
+
};
|
|
159
|
+
var DEFAULT_SETTINGS = {
|
|
160
|
+
singleSelection: false,
|
|
161
|
+
text: "Select",
|
|
162
|
+
enableCheckAll: true,
|
|
163
|
+
selectAllText: "Select All",
|
|
164
|
+
unSelectAllText: "Unselect All",
|
|
165
|
+
filterSelectAllText: "Select filtered",
|
|
166
|
+
filterUnSelectAllText: "Unselect filtered",
|
|
167
|
+
enableFilterSelectAll: true,
|
|
168
|
+
enableSearchFilter: false,
|
|
169
|
+
searchBy: [],
|
|
170
|
+
maxHeight: 300,
|
|
171
|
+
badgeShowLimit: Number.MAX_SAFE_INTEGER,
|
|
172
|
+
classes: "",
|
|
173
|
+
limitSelection: 0,
|
|
174
|
+
disabled: false,
|
|
175
|
+
searchPlaceholderText: "Search",
|
|
176
|
+
groupBy: "",
|
|
177
|
+
showCheckbox: true,
|
|
178
|
+
noDataLabel: "No Data Available",
|
|
179
|
+
searchAutofocus: true,
|
|
180
|
+
lazyLoading: false,
|
|
181
|
+
labelKey: "itemName",
|
|
182
|
+
primaryKey: "id",
|
|
183
|
+
position: "bottom",
|
|
184
|
+
autoPosition: true,
|
|
185
|
+
loading: false,
|
|
186
|
+
selectGroup: false,
|
|
187
|
+
addNewItemOnFilter: false,
|
|
188
|
+
addNewButtonText: "Add",
|
|
189
|
+
escapeToClose: true,
|
|
190
|
+
clearAll: true,
|
|
191
|
+
closeDropDownOnSelection: false,
|
|
192
|
+
tagToBody: false,
|
|
193
|
+
appendToBody: false,
|
|
194
|
+
theme: "",
|
|
195
|
+
skin: "classic",
|
|
196
|
+
ariaLabel: "Multiselect dropdown",
|
|
197
|
+
listboxAriaLabel: "Dropdown options",
|
|
198
|
+
searchAriaLabel: "Search options",
|
|
199
|
+
clearSearchAriaLabel: "Clear search",
|
|
200
|
+
clearAllAriaLabel: "Clear selected options",
|
|
201
|
+
removeItemAriaLabel: "Remove selected option",
|
|
202
|
+
openDropdownAriaLabel: "Open dropdown",
|
|
203
|
+
closeDropdownAriaLabel: "Close dropdown",
|
|
204
|
+
loadingText: "Loading options",
|
|
205
|
+
keyboard: DEFAULT_KEYBOARD_SETTINGS
|
|
206
|
+
};
|
|
207
|
+
function resolveDropdownSettings(incomingSettings) {
|
|
208
|
+
const escapeToClose = incomingSettings?.escapeToClose ?? DEFAULT_SETTINGS.escapeToClose;
|
|
209
|
+
const incomingKeyboard = incomingSettings?.keyboard;
|
|
210
|
+
const keyboard = {
|
|
211
|
+
...DEFAULT_KEYBOARD_SETTINGS,
|
|
212
|
+
...incomingKeyboard,
|
|
213
|
+
backspaceRemovesLastWhenSearchEmpty: incomingKeyboard?.backspaceRemovesLastWhenSearchEmpty ?? incomingKeyboard?.backspace ?? DEFAULT_KEYBOARD_SETTINGS.backspaceRemovesLastWhenSearchEmpty,
|
|
214
|
+
deleteRemovesFocusedBadge: incomingKeyboard?.deleteRemovesFocusedBadge ?? DEFAULT_KEYBOARD_SETTINGS.deleteRemovesFocusedBadge,
|
|
215
|
+
escape: escapeToClose && (incomingKeyboard?.escape ?? DEFAULT_KEYBOARD_SETTINGS.escape)
|
|
216
|
+
};
|
|
217
|
+
return {
|
|
218
|
+
...DEFAULT_SETTINGS,
|
|
219
|
+
...incomingSettings,
|
|
220
|
+
escapeToClose,
|
|
221
|
+
keyboard
|
|
222
|
+
};
|
|
223
|
+
}
|
|
224
|
+
|
|
32
225
|
// src/styles.ts
|
|
33
226
|
var STYLE_ID = "stackline-react-multiselect-dropdown-styles";
|
|
34
227
|
var styles = `
|
|
@@ -206,33 +399,25 @@ var styles = `
|
|
|
206
399
|
display: inline-flex;
|
|
207
400
|
align-items: center;
|
|
208
401
|
justify-content: center;
|
|
209
|
-
|
|
210
|
-
min-
|
|
402
|
+
flex: 0 0 auto;
|
|
403
|
+
min-width: 24px;
|
|
404
|
+
min-height: 20px;
|
|
211
405
|
color: var(--rmsd-muted);
|
|
212
406
|
font-size: 0.8rem;
|
|
213
407
|
font-weight: 600;
|
|
408
|
+
line-height: 1;
|
|
409
|
+
white-space: nowrap;
|
|
410
|
+
text-align: center;
|
|
214
411
|
}
|
|
215
412
|
|
|
216
|
-
.rmsd-root.rmsd-has-overflow
|
|
413
|
+
.rmsd-root.rmsd-has-overflow .rmsd-trigger {
|
|
217
414
|
padding-right: 104px;
|
|
218
415
|
}
|
|
219
416
|
|
|
220
|
-
.rmsd-root.rmsd-has-overflow:not(.
|
|
417
|
+
.rmsd-root.rmsd-has-overflow:not(.rmsd-has-clear) .rmsd-trigger {
|
|
221
418
|
padding-right: 74px;
|
|
222
419
|
}
|
|
223
420
|
|
|
224
|
-
.rmsd-root.rmsd-has-overflow:not(.skin-classic) .rmsd-overflow {
|
|
225
|
-
position: absolute;
|
|
226
|
-
top: 50%;
|
|
227
|
-
right: 76px;
|
|
228
|
-
transform: translateY(-50%);
|
|
229
|
-
z-index: 1;
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
.rmsd-root.rmsd-has-overflow:not(.skin-classic):not(.rmsd-has-clear) .rmsd-overflow {
|
|
233
|
-
right: 42px;
|
|
234
|
-
}
|
|
235
|
-
|
|
236
421
|
.rmsd-actions {
|
|
237
422
|
position: absolute;
|
|
238
423
|
top: 50%;
|
|
@@ -797,9 +982,12 @@ var styles = `
|
|
|
797
982
|
|
|
798
983
|
.theme-classic .rmsd-overflow,
|
|
799
984
|
.skin-classic .rmsd-overflow {
|
|
985
|
+
min-width: 24px;
|
|
986
|
+
min-height: 20px;
|
|
800
987
|
color: #333333;
|
|
801
988
|
font-size: 14px;
|
|
802
989
|
font-weight: 400;
|
|
990
|
+
line-height: 1;
|
|
803
991
|
}
|
|
804
992
|
|
|
805
993
|
.theme-classic .rmsd-actions,
|
|
@@ -1085,56 +1273,30 @@ function ensureDropdownStyles() {
|
|
|
1085
1273
|
document.head.appendChild(tag);
|
|
1086
1274
|
}
|
|
1087
1275
|
|
|
1276
|
+
// src/useControllableSelection.ts
|
|
1277
|
+
var import_react = require("react");
|
|
1278
|
+
function useControllableSelection(controlledValue, defaultValue, onChange) {
|
|
1279
|
+
const [internalValue, setInternalValue] = (0, import_react.useState)(defaultValue ?? []);
|
|
1280
|
+
const isControlled = controlledValue !== void 0;
|
|
1281
|
+
const value = isControlled ? controlledValue : internalValue;
|
|
1282
|
+
const setValue = (nextValue) => {
|
|
1283
|
+
if (!isControlled) {
|
|
1284
|
+
setInternalValue(nextValue);
|
|
1285
|
+
}
|
|
1286
|
+
onChange?.(nextValue);
|
|
1287
|
+
};
|
|
1288
|
+
return [value, setValue];
|
|
1289
|
+
}
|
|
1290
|
+
|
|
1088
1291
|
// src/MultiSelectDropdown.tsx
|
|
1089
1292
|
var import_jsx_runtime = require("react/jsx-runtime");
|
|
1090
|
-
var
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
filterUnSelectAllText: "Unselect filtered",
|
|
1098
|
-
enableFilterSelectAll: true,
|
|
1099
|
-
enableSearchFilter: false,
|
|
1100
|
-
searchBy: [],
|
|
1101
|
-
maxHeight: 300,
|
|
1102
|
-
badgeShowLimit: Number.MAX_SAFE_INTEGER,
|
|
1103
|
-
classes: "",
|
|
1104
|
-
limitSelection: 0,
|
|
1105
|
-
disabled: false,
|
|
1106
|
-
searchPlaceholderText: "Search",
|
|
1107
|
-
groupBy: "",
|
|
1108
|
-
showCheckbox: true,
|
|
1109
|
-
noDataLabel: "No Data Available",
|
|
1110
|
-
searchAutofocus: true,
|
|
1111
|
-
lazyLoading: false,
|
|
1112
|
-
labelKey: "itemName",
|
|
1113
|
-
primaryKey: "id",
|
|
1114
|
-
position: "bottom",
|
|
1115
|
-
autoPosition: true,
|
|
1116
|
-
loading: false,
|
|
1117
|
-
selectGroup: false,
|
|
1118
|
-
addNewItemOnFilter: false,
|
|
1119
|
-
addNewButtonText: "Add",
|
|
1120
|
-
escapeToClose: true,
|
|
1121
|
-
clearAll: true,
|
|
1122
|
-
closeDropDownOnSelection: false,
|
|
1123
|
-
tagToBody: false,
|
|
1124
|
-
appendToBody: false,
|
|
1125
|
-
theme: "",
|
|
1126
|
-
skin: "classic",
|
|
1127
|
-
ariaLabel: "Multiselect dropdown",
|
|
1128
|
-
listboxAriaLabel: "Dropdown options",
|
|
1129
|
-
searchAriaLabel: "Search options",
|
|
1130
|
-
clearSearchAriaLabel: "Clear search",
|
|
1131
|
-
clearAllAriaLabel: "Clear selected options",
|
|
1132
|
-
removeItemAriaLabel: "Remove selected option",
|
|
1133
|
-
openDropdownAriaLabel: "Open dropdown",
|
|
1134
|
-
closeDropdownAriaLabel: "Close dropdown",
|
|
1135
|
-
loadingText: "Loading options"
|
|
1136
|
-
};
|
|
1137
|
-
var useClientLayoutEffect = typeof window === "undefined" ? import_react.useEffect : import_react.useLayoutEffect;
|
|
1293
|
+
var useClientLayoutEffect = typeof window === "undefined" ? import_react2.useEffect : import_react2.useLayoutEffect;
|
|
1294
|
+
function isSpaceKey(key) {
|
|
1295
|
+
return key === " " || key === "Spacebar";
|
|
1296
|
+
}
|
|
1297
|
+
function renderSlot(Slot, props, fallback) {
|
|
1298
|
+
return Slot ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_jsx_runtime.Fragment, { children: Slot(props) }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_jsx_runtime.Fragment, { children: fallback });
|
|
1299
|
+
}
|
|
1138
1300
|
function StacklineIcon({ name, className = "rmsd-icon" }) {
|
|
1139
1301
|
if (name === "remove") {
|
|
1140
1302
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("svg", { className, viewBox: "0 0 47.971 47.971", focusable: "false", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M28.228,23.986L47.092,5.122c1.172-1.171,1.172-3.071,0-4.242c-1.172-1.172-3.07-1.172-4.242,0L23.986,19.744L5.121,0.88c-1.172-1.172-3.07-1.172-4.242,0c-1.172,1.171-1.172,3.071,0,4.242l18.865,18.864L0.879,42.85c-1.172,1.171-1.172,3.071,0,4.242C1.465,47.677,2.233,47.97,3,47.97s1.535-0.293,2.121-0.879l18.865-18.864L42.85,47.091c0.586,0.586,1.354,0.879,2.121,0.879s1.535-0.293,2.121-0.879c1.172-1.171,1.172-3.071,0-4.242L28.228,23.986z" }) });
|
|
@@ -1147,131 +1309,6 @@ function StacklineIcon({ name, className = "rmsd-icon" }) {
|
|
|
1147
1309
|
}
|
|
1148
1310
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("svg", { className, viewBox: "0 0 612 612", focusable: "false", "aria-hidden": "true", children: name === "angle-up" ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M604.501,440.509L325.398,134.956c-5.331-5.357-12.423-7.627-19.386-7.27c-6.989-0.357-14.056,1.913-19.387,7.27L7.499,440.509c-9.999,10.024-9.999,26.298,0,36.323s26.223,10.024,36.222,0l262.293-287.164L568.28,476.832c9.999,10.024,26.222,10.024,36.221,0C614.5,466.809,614.5,450.534,604.501,440.509z" }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M604.501,134.782c-9.999-10.05-26.222-10.05-36.221,0L306.014,422.558L43.721,134.782c-9.999-10.05-26.223-10.05-36.222,0s-9.999,26.35,0,36.399l279.103,306.241c5.331,5.357,12.422,7.652,19.386,7.296c6.988,0.356,14.055-1.939,19.386-7.296l279.128-306.268C614.5,161.106,614.5,144.832,604.501,134.782z" }) });
|
|
1149
1311
|
}
|
|
1150
|
-
function isPrimitiveItem(item) {
|
|
1151
|
-
return typeof item === "string" || typeof item === "number" || typeof item === "boolean";
|
|
1152
|
-
}
|
|
1153
|
-
function getLabel(item, settings) {
|
|
1154
|
-
if (isPrimitiveItem(item)) {
|
|
1155
|
-
return String(item);
|
|
1156
|
-
}
|
|
1157
|
-
const keys = [settings.labelKey, "itemName", "name", "label", "title", "value"].filter(Boolean);
|
|
1158
|
-
for (const key of keys) {
|
|
1159
|
-
if (key && item[key] != null) {
|
|
1160
|
-
return String(item[key]);
|
|
1161
|
-
}
|
|
1162
|
-
}
|
|
1163
|
-
return JSON.stringify(item);
|
|
1164
|
-
}
|
|
1165
|
-
function getPrimaryValue(item, settings) {
|
|
1166
|
-
if (isPrimitiveItem(item)) {
|
|
1167
|
-
return String(item);
|
|
1168
|
-
}
|
|
1169
|
-
const keys = [settings.primaryKey, "id", "value", "key"].filter(Boolean);
|
|
1170
|
-
for (const key of keys) {
|
|
1171
|
-
if (key && item[key] != null) {
|
|
1172
|
-
return String(item[key]);
|
|
1173
|
-
}
|
|
1174
|
-
}
|
|
1175
|
-
return getLabel(item, settings);
|
|
1176
|
-
}
|
|
1177
|
-
function itemMatchesQuery(item, query, settings) {
|
|
1178
|
-
if (!query.trim()) {
|
|
1179
|
-
return true;
|
|
1180
|
-
}
|
|
1181
|
-
const needle = query.trim().toLowerCase();
|
|
1182
|
-
const haystack = /* @__PURE__ */ new Set();
|
|
1183
|
-
haystack.add(getLabel(item, settings).toLowerCase());
|
|
1184
|
-
if (!isPrimitiveItem(item)) {
|
|
1185
|
-
const searchKeys = settings.searchBy.length ? settings.searchBy : [settings.labelKey];
|
|
1186
|
-
for (const key of searchKeys) {
|
|
1187
|
-
if (key && item[key] != null) {
|
|
1188
|
-
haystack.add(String(item[key]).toLowerCase());
|
|
1189
|
-
}
|
|
1190
|
-
}
|
|
1191
|
-
}
|
|
1192
|
-
for (const value of haystack) {
|
|
1193
|
-
if (value.includes(needle)) {
|
|
1194
|
-
return true;
|
|
1195
|
-
}
|
|
1196
|
-
}
|
|
1197
|
-
return false;
|
|
1198
|
-
}
|
|
1199
|
-
function getGroupName(item, settings) {
|
|
1200
|
-
if (!settings.groupBy) {
|
|
1201
|
-
return "";
|
|
1202
|
-
}
|
|
1203
|
-
if (typeof settings.groupBy === "function") {
|
|
1204
|
-
return settings.groupBy(item);
|
|
1205
|
-
}
|
|
1206
|
-
if (!isPrimitiveItem(item)) {
|
|
1207
|
-
const groupKey = settings.groupBy;
|
|
1208
|
-
const objectItem = item;
|
|
1209
|
-
if (groupKey in objectItem) {
|
|
1210
|
-
return String(objectItem[groupKey] ?? "");
|
|
1211
|
-
}
|
|
1212
|
-
}
|
|
1213
|
-
return "";
|
|
1214
|
-
}
|
|
1215
|
-
function mergeUniqueItems(base, extra, settings) {
|
|
1216
|
-
const bucket = /* @__PURE__ */ new Map();
|
|
1217
|
-
for (const item of [...base, ...extra]) {
|
|
1218
|
-
bucket.set(getPrimaryValue(item, settings), item);
|
|
1219
|
-
}
|
|
1220
|
-
return Array.from(bucket.values());
|
|
1221
|
-
}
|
|
1222
|
-
function createItemFromQuery(query, settings, sample) {
|
|
1223
|
-
if (sample && !isPrimitiveItem(sample)) {
|
|
1224
|
-
return {
|
|
1225
|
-
[settings.primaryKey]: query.toLowerCase().replace(/\s+/g, "-"),
|
|
1226
|
-
[settings.labelKey]: query
|
|
1227
|
-
};
|
|
1228
|
-
}
|
|
1229
|
-
return query;
|
|
1230
|
-
}
|
|
1231
|
-
function isDisabledItem(item) {
|
|
1232
|
-
return !isPrimitiveItem(item) && Boolean(item.disabled);
|
|
1233
|
-
}
|
|
1234
|
-
function buildGroups(items, settings) {
|
|
1235
|
-
if (!settings.groupBy) {
|
|
1236
|
-
return [];
|
|
1237
|
-
}
|
|
1238
|
-
const map = /* @__PURE__ */ new Map();
|
|
1239
|
-
for (const item of items) {
|
|
1240
|
-
const groupName = getGroupName(item, settings) || "Ungrouped";
|
|
1241
|
-
const current = map.get(groupName) || [];
|
|
1242
|
-
current.push(item);
|
|
1243
|
-
map.set(groupName, current);
|
|
1244
|
-
}
|
|
1245
|
-
return Array.from(map.entries()).map(([name, groupedItems]) => ({
|
|
1246
|
-
name,
|
|
1247
|
-
items: groupedItems
|
|
1248
|
-
}));
|
|
1249
|
-
}
|
|
1250
|
-
function useControllableSelection(controlledValue, defaultValue, onChange) {
|
|
1251
|
-
const [internalValue, setInternalValue] = (0, import_react.useState)(defaultValue ?? []);
|
|
1252
|
-
const isControlled = controlledValue !== void 0;
|
|
1253
|
-
const value = isControlled ? controlledValue : internalValue;
|
|
1254
|
-
const setValue = (nextValue) => {
|
|
1255
|
-
if (!isControlled) {
|
|
1256
|
-
setInternalValue(nextValue);
|
|
1257
|
-
}
|
|
1258
|
-
onChange?.(nextValue);
|
|
1259
|
-
};
|
|
1260
|
-
return [value, setValue];
|
|
1261
|
-
}
|
|
1262
|
-
function sanitizeId(value) {
|
|
1263
|
-
return value.replace(/[^a-zA-Z0-9_-]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 56) || "option";
|
|
1264
|
-
}
|
|
1265
|
-
function normalizeSkinName(value) {
|
|
1266
|
-
return sanitizeId(value.toLowerCase()) || "classic";
|
|
1267
|
-
}
|
|
1268
|
-
function getVisibleBadgeLimit(selectedCount, rawLimit) {
|
|
1269
|
-
if (!Number.isFinite(rawLimit)) {
|
|
1270
|
-
return selectedCount;
|
|
1271
|
-
}
|
|
1272
|
-
const limit = Math.max(0, Math.floor(rawLimit));
|
|
1273
|
-
return Math.min(selectedCount, limit);
|
|
1274
|
-
}
|
|
1275
1312
|
function InnerMultiSelectDropdown({
|
|
1276
1313
|
data,
|
|
1277
1314
|
settings: incomingSettings,
|
|
@@ -1296,41 +1333,43 @@ function InnerMultiSelectDropdown({
|
|
|
1296
1333
|
renderItem,
|
|
1297
1334
|
renderBadge,
|
|
1298
1335
|
renderSearch,
|
|
1299
|
-
renderEmptyState
|
|
1336
|
+
renderEmptyState,
|
|
1337
|
+
slots
|
|
1300
1338
|
}, ref) {
|
|
1301
1339
|
ensureDropdownStyles();
|
|
1302
|
-
const settings =
|
|
1340
|
+
const settings = (0, import_react2.useMemo)(() => resolveDropdownSettings(incomingSettings), [incomingSettings]);
|
|
1303
1341
|
const [selectedItems, setSelectedItems] = useControllableSelection(
|
|
1304
1342
|
controlledSelectedItems,
|
|
1305
1343
|
defaultSelectedItems,
|
|
1306
1344
|
onChange
|
|
1307
1345
|
);
|
|
1308
|
-
const [isOpen, setIsOpen] = (0,
|
|
1309
|
-
const [filter, setFilter] = (0,
|
|
1310
|
-
const [addedItems, setAddedItems] = (0,
|
|
1311
|
-
const [activeDescendantId, setActiveDescendantId] = (0,
|
|
1312
|
-
const [bodyMenuStyle, setBodyMenuStyle] = (0,
|
|
1313
|
-
const [bodyListMaxHeight, setBodyListMaxHeight] = (0,
|
|
1314
|
-
const [effectivePosition, setEffectivePosition] = (0,
|
|
1346
|
+
const [isOpen, setIsOpen] = (0, import_react2.useState)(false);
|
|
1347
|
+
const [filter, setFilter] = (0, import_react2.useState)("");
|
|
1348
|
+
const [addedItems, setAddedItems] = (0, import_react2.useState)([]);
|
|
1349
|
+
const [activeDescendantId, setActiveDescendantId] = (0, import_react2.useState)(null);
|
|
1350
|
+
const [bodyMenuStyle, setBodyMenuStyle] = (0, import_react2.useState)();
|
|
1351
|
+
const [bodyListMaxHeight, setBodyListMaxHeight] = (0, import_react2.useState)();
|
|
1352
|
+
const [effectivePosition, setEffectivePosition] = (0, import_react2.useState)(
|
|
1315
1353
|
settings.position === "top" ? "top" : "bottom"
|
|
1316
1354
|
);
|
|
1317
|
-
const rootRef = (0,
|
|
1318
|
-
const triggerRef = (0,
|
|
1319
|
-
const menuRef = (0,
|
|
1320
|
-
const searchRef = (0,
|
|
1321
|
-
const listRef = (0,
|
|
1322
|
-
const lastScrollHeightRef = (0,
|
|
1323
|
-
const pendingFocusRef = (0,
|
|
1324
|
-
const
|
|
1325
|
-
const
|
|
1326
|
-
|
|
1327
|
-
[
|
|
1355
|
+
const rootRef = (0, import_react2.useRef)(null);
|
|
1356
|
+
const triggerRef = (0, import_react2.useRef)(null);
|
|
1357
|
+
const menuRef = (0, import_react2.useRef)(null);
|
|
1358
|
+
const searchRef = (0, import_react2.useRef)(null);
|
|
1359
|
+
const listRef = (0, import_react2.useRef)(null);
|
|
1360
|
+
const lastScrollHeightRef = (0, import_react2.useRef)(0);
|
|
1361
|
+
const pendingFocusRef = (0, import_react2.useRef)(null);
|
|
1362
|
+
const addRequestIdRef = (0, import_react2.useRef)(0);
|
|
1363
|
+
const instanceIdRef = (0, import_react2.useRef)(`rmsd-${Math.random().toString(36).slice(2)}`);
|
|
1364
|
+
const allItems = (0, import_react2.useMemo)(
|
|
1365
|
+
() => mergeUniqueItems(data, [...selectedItems, ...addedItems], settings),
|
|
1366
|
+
[addedItems, data, selectedItems, settings]
|
|
1328
1367
|
);
|
|
1329
|
-
const filteredItems = (0,
|
|
1368
|
+
const filteredItems = (0, import_react2.useMemo)(
|
|
1330
1369
|
() => allItems.filter((item) => itemMatchesQuery(item, filter, settings)),
|
|
1331
1370
|
[allItems, filter, settings]
|
|
1332
1371
|
);
|
|
1333
|
-
const groupedItems = (0,
|
|
1372
|
+
const groupedItems = (0, import_react2.useMemo)(() => buildGroups(filteredItems, settings), [filteredItems, settings]);
|
|
1334
1373
|
const listboxId = `${instanceIdRef.current}-listbox`;
|
|
1335
1374
|
const getOptionId = (item, index, prefix) => `${instanceIdRef.current}-${prefix}-${index}-${sanitizeId(getPrimaryValue(item, settings))}`;
|
|
1336
1375
|
const isSelected = (item) => selectedItems.some(
|
|
@@ -1355,6 +1394,68 @@ function InnerMultiSelectDropdown({
|
|
|
1355
1394
|
};
|
|
1356
1395
|
const focusFirstOption = () => focusOptionByIndex(0);
|
|
1357
1396
|
const focusLastOption = () => focusOptionByIndex(getOptionElements().length - 1);
|
|
1397
|
+
const focusOptionById = (optionId) => {
|
|
1398
|
+
const option = document.getElementById(optionId);
|
|
1399
|
+
if (!option || !listRef.current?.contains(option) || option.getAttribute("aria-disabled") === "true") {
|
|
1400
|
+
return false;
|
|
1401
|
+
}
|
|
1402
|
+
option.focus();
|
|
1403
|
+
setActiveDescendantId(option.id || null);
|
|
1404
|
+
option.scrollIntoView({ block: "nearest" });
|
|
1405
|
+
return true;
|
|
1406
|
+
};
|
|
1407
|
+
const focusOptionAfterPointerSelection = (optionId, fallbackIndex) => {
|
|
1408
|
+
window.setTimeout(() => {
|
|
1409
|
+
const focusAfterRender = () => {
|
|
1410
|
+
if (focusOptionById(optionId)) {
|
|
1411
|
+
return;
|
|
1412
|
+
}
|
|
1413
|
+
focusOptionByIndex(fallbackIndex);
|
|
1414
|
+
};
|
|
1415
|
+
if (typeof window.requestAnimationFrame === "function") {
|
|
1416
|
+
window.requestAnimationFrame(focusAfterRender);
|
|
1417
|
+
return;
|
|
1418
|
+
}
|
|
1419
|
+
focusAfterRender();
|
|
1420
|
+
}, 0);
|
|
1421
|
+
};
|
|
1422
|
+
const focusOptionAfterKeyboardSelection = (optionId, fallbackIndex, moveToNextOption) => {
|
|
1423
|
+
window.setTimeout(() => {
|
|
1424
|
+
const focusAfterRender = () => {
|
|
1425
|
+
if (moveToNextOption) {
|
|
1426
|
+
const options = getOptionElements();
|
|
1427
|
+
const currentIndex = options.findIndex((option) => option.id === optionId);
|
|
1428
|
+
const nextOption = currentIndex >= 0 ? options[currentIndex + 1] : void 0;
|
|
1429
|
+
if (nextOption) {
|
|
1430
|
+
nextOption.focus();
|
|
1431
|
+
setActiveDescendantId(nextOption.id || null);
|
|
1432
|
+
nextOption.scrollIntoView({ block: "nearest" });
|
|
1433
|
+
return;
|
|
1434
|
+
}
|
|
1435
|
+
}
|
|
1436
|
+
if (!focusOptionById(optionId)) {
|
|
1437
|
+
focusOptionByIndex(fallbackIndex);
|
|
1438
|
+
}
|
|
1439
|
+
};
|
|
1440
|
+
if (typeof window.requestAnimationFrame === "function") {
|
|
1441
|
+
window.requestAnimationFrame(focusAfterRender);
|
|
1442
|
+
return;
|
|
1443
|
+
}
|
|
1444
|
+
focusAfterRender();
|
|
1445
|
+
}, 0);
|
|
1446
|
+
};
|
|
1447
|
+
const focusAfterSelectionChange = (target = "search") => {
|
|
1448
|
+
if (target === "none") {
|
|
1449
|
+
return;
|
|
1450
|
+
}
|
|
1451
|
+
window.setTimeout(() => {
|
|
1452
|
+
if (target === "search" && isOpen && settings.enableSearchFilter) {
|
|
1453
|
+
searchRef.current?.focus();
|
|
1454
|
+
return;
|
|
1455
|
+
}
|
|
1456
|
+
triggerRef.current?.focus();
|
|
1457
|
+
}, 0);
|
|
1458
|
+
};
|
|
1358
1459
|
const updateSelection = (nextItems) => {
|
|
1359
1460
|
setSelectedItems(nextItems);
|
|
1360
1461
|
};
|
|
@@ -1388,6 +1489,7 @@ function InnerMultiSelectDropdown({
|
|
|
1388
1489
|
const previousItems = selectedItems;
|
|
1389
1490
|
updateSelection([]);
|
|
1390
1491
|
onDeSelectAll?.(previousItems);
|
|
1492
|
+
focusAfterSelectionChange();
|
|
1391
1493
|
};
|
|
1392
1494
|
const toggleDropdown = () => {
|
|
1393
1495
|
if (isOpen) {
|
|
@@ -1396,25 +1498,34 @@ function InnerMultiSelectDropdown({
|
|
|
1396
1498
|
openDropdown("search");
|
|
1397
1499
|
}
|
|
1398
1500
|
};
|
|
1399
|
-
const removeItem = (item) => {
|
|
1501
|
+
const removeItem = (item, focusTarget = "search") => {
|
|
1400
1502
|
const nextItems = selectedItems.filter(
|
|
1401
1503
|
(selectedItem) => getPrimaryValue(selectedItem, settings) !== getPrimaryValue(item, settings)
|
|
1402
1504
|
);
|
|
1403
1505
|
updateSelection(nextItems);
|
|
1404
1506
|
onDeSelect?.(item);
|
|
1507
|
+
focusAfterSelectionChange(focusTarget);
|
|
1405
1508
|
};
|
|
1406
|
-
const
|
|
1509
|
+
const removeLastSelectedItem = () => {
|
|
1510
|
+
const lastItem = selectedItems[selectedItems.length - 1];
|
|
1511
|
+
if (!lastItem) {
|
|
1512
|
+
return;
|
|
1513
|
+
}
|
|
1514
|
+
removeItem(lastItem);
|
|
1515
|
+
};
|
|
1516
|
+
const selectItem = (item, focusTarget = "search") => {
|
|
1407
1517
|
if (settings.disabled || isDisabledItem(item)) {
|
|
1408
1518
|
return;
|
|
1409
1519
|
}
|
|
1410
1520
|
if (isSelected(item)) {
|
|
1411
|
-
removeItem(item);
|
|
1521
|
+
removeItem(item, focusTarget);
|
|
1412
1522
|
return;
|
|
1413
1523
|
}
|
|
1414
1524
|
if (settings.singleSelection) {
|
|
1415
1525
|
updateSelection([item]);
|
|
1416
1526
|
onSelect?.(item);
|
|
1417
1527
|
closeDropdown(true);
|
|
1528
|
+
focusAfterSelectionChange("trigger");
|
|
1418
1529
|
return;
|
|
1419
1530
|
}
|
|
1420
1531
|
if (settings.limitSelection && selectedItems.length >= settings.limitSelection) {
|
|
@@ -1425,7 +1536,10 @@ function InnerMultiSelectDropdown({
|
|
|
1425
1536
|
onSelect?.(item);
|
|
1426
1537
|
if (settings.closeDropDownOnSelection) {
|
|
1427
1538
|
closeDropdown(true);
|
|
1539
|
+
focusAfterSelectionChange("trigger");
|
|
1540
|
+
return;
|
|
1428
1541
|
}
|
|
1542
|
+
focusAfterSelectionChange(focusTarget);
|
|
1429
1543
|
};
|
|
1430
1544
|
const selectAllItems = (items, filteredSelection = false) => {
|
|
1431
1545
|
if (settings.singleSelection) {
|
|
@@ -1441,6 +1555,7 @@ function InnerMultiSelectDropdown({
|
|
|
1441
1555
|
} else {
|
|
1442
1556
|
onSelectAll?.(nextItems);
|
|
1443
1557
|
}
|
|
1558
|
+
focusAfterSelectionChange();
|
|
1444
1559
|
};
|
|
1445
1560
|
const deSelectAllItems = (items, filteredSelection = false) => {
|
|
1446
1561
|
const ids = new Set(items.map((item) => getPrimaryValue(item, settings)));
|
|
@@ -1451,13 +1566,19 @@ function InnerMultiSelectDropdown({
|
|
|
1451
1566
|
} else {
|
|
1452
1567
|
onDeSelectAll?.(items);
|
|
1453
1568
|
}
|
|
1569
|
+
focusAfterSelectionChange();
|
|
1454
1570
|
};
|
|
1455
1571
|
const handleAddFilterNewItem = async () => {
|
|
1456
1572
|
const query = filter.trim();
|
|
1457
1573
|
if (!query) {
|
|
1458
1574
|
return;
|
|
1459
1575
|
}
|
|
1576
|
+
const requestId = addRequestIdRef.current + 1;
|
|
1577
|
+
addRequestIdRef.current = requestId;
|
|
1460
1578
|
const result = await onAddFilterNewItem?.(query);
|
|
1579
|
+
if (requestId !== addRequestIdRef.current) {
|
|
1580
|
+
return;
|
|
1581
|
+
}
|
|
1461
1582
|
const nextItem = result === void 0 ? createItemFromQuery(query, settings, data[0]) : result;
|
|
1462
1583
|
setAddedItems((currentItems) => mergeUniqueItems(currentItems, [nextItem], settings));
|
|
1463
1584
|
if (settings.singleSelection) {
|
|
@@ -1466,6 +1587,7 @@ function InnerMultiSelectDropdown({
|
|
|
1466
1587
|
updateSelection(mergeUniqueItems(selectedItems, [nextItem], settings));
|
|
1467
1588
|
}
|
|
1468
1589
|
setFilter("");
|
|
1590
|
+
focusAfterSelectionChange();
|
|
1469
1591
|
};
|
|
1470
1592
|
const toggleGroup = (groupName, items) => {
|
|
1471
1593
|
const groupItems = items.filter((item) => !isDisabledItem(item));
|
|
@@ -1473,10 +1595,12 @@ function InnerMultiSelectDropdown({
|
|
|
1473
1595
|
if (allSelected) {
|
|
1474
1596
|
deSelectAllItems(groupItems, false);
|
|
1475
1597
|
onGroupDeSelect?.(groupName, groupItems);
|
|
1598
|
+
focusAfterSelectionChange();
|
|
1476
1599
|
return;
|
|
1477
1600
|
}
|
|
1478
1601
|
selectAllItems(groupItems, false);
|
|
1479
1602
|
onGroupSelect?.(groupName, groupItems);
|
|
1603
|
+
focusAfterSelectionChange();
|
|
1480
1604
|
};
|
|
1481
1605
|
const handleListScroll = () => {
|
|
1482
1606
|
if (!listRef.current || !onScrollToEnd) {
|
|
@@ -1505,7 +1629,7 @@ function InnerMultiSelectDropdown({
|
|
|
1505
1629
|
}
|
|
1506
1630
|
return "bottom";
|
|
1507
1631
|
};
|
|
1508
|
-
(0,
|
|
1632
|
+
(0, import_react2.useEffect)(() => {
|
|
1509
1633
|
if (!isOpen) {
|
|
1510
1634
|
return;
|
|
1511
1635
|
}
|
|
@@ -1516,7 +1640,7 @@ function InnerMultiSelectDropdown({
|
|
|
1516
1640
|
}
|
|
1517
1641
|
};
|
|
1518
1642
|
const handleKeyDown = (event) => {
|
|
1519
|
-
if (event.key === "Escape" && settings.
|
|
1643
|
+
if (event.key === "Escape" && settings.keyboard.escape) {
|
|
1520
1644
|
closeDropdown(true);
|
|
1521
1645
|
}
|
|
1522
1646
|
};
|
|
@@ -1528,7 +1652,7 @@ function InnerMultiSelectDropdown({
|
|
|
1528
1652
|
document.removeEventListener("touchstart", handlePointerDown);
|
|
1529
1653
|
document.removeEventListener("keydown", handleKeyDown);
|
|
1530
1654
|
};
|
|
1531
|
-
}, [isOpen, settings.
|
|
1655
|
+
}, [isOpen, settings.keyboard.escape]);
|
|
1532
1656
|
const updateBodyMenuPosition = () => {
|
|
1533
1657
|
if (!shouldAppendToBody || !triggerRef.current || typeof window === "undefined") {
|
|
1534
1658
|
return;
|
|
@@ -1588,7 +1712,7 @@ function InnerMultiSelectDropdown({
|
|
|
1588
1712
|
selectedItems.length,
|
|
1589
1713
|
filter
|
|
1590
1714
|
]);
|
|
1591
|
-
(0,
|
|
1715
|
+
(0, import_react2.useEffect)(() => {
|
|
1592
1716
|
if (!isOpen || !shouldAppendToBody || typeof window === "undefined") {
|
|
1593
1717
|
return;
|
|
1594
1718
|
}
|
|
@@ -1614,7 +1738,7 @@ function InnerMultiSelectDropdown({
|
|
|
1614
1738
|
filteredItems.length,
|
|
1615
1739
|
selectedItems.length
|
|
1616
1740
|
]);
|
|
1617
|
-
(0,
|
|
1741
|
+
(0, import_react2.useEffect)(() => {
|
|
1618
1742
|
if (!isOpen) {
|
|
1619
1743
|
return;
|
|
1620
1744
|
}
|
|
@@ -1634,10 +1758,10 @@ function InnerMultiSelectDropdown({
|
|
|
1634
1758
|
}
|
|
1635
1759
|
}, 0);
|
|
1636
1760
|
}, [isOpen, filteredItems.length, settings.enableSearchFilter, settings.searchAutofocus]);
|
|
1637
|
-
(0,
|
|
1761
|
+
(0, import_react2.useEffect)(() => {
|
|
1638
1762
|
lastScrollHeightRef.current = 0;
|
|
1639
1763
|
}, [filteredItems.length]);
|
|
1640
|
-
(0,
|
|
1764
|
+
(0, import_react2.useImperativeHandle)(
|
|
1641
1765
|
ref,
|
|
1642
1766
|
() => ({
|
|
1643
1767
|
openDropdown: () => openDropdown("search"),
|
|
@@ -1687,20 +1811,38 @@ function InnerMultiSelectDropdown({
|
|
|
1687
1811
|
return `${settings.ariaLabel}: ${selectedItems.map((item) => getLabel(item, settings)).join(", ")}`;
|
|
1688
1812
|
};
|
|
1689
1813
|
const stopInlineKey = (event) => {
|
|
1690
|
-
if (event.key
|
|
1814
|
+
if (isSpaceKey(event.key) && !settings.keyboard.space) {
|
|
1815
|
+
event.preventDefault();
|
|
1691
1816
|
event.stopPropagation();
|
|
1817
|
+
return;
|
|
1818
|
+
}
|
|
1819
|
+
if (event.key === "Enter" || isSpaceKey(event.key)) {
|
|
1820
|
+
event.stopPropagation();
|
|
1821
|
+
}
|
|
1822
|
+
};
|
|
1823
|
+
const handleBadgeRemoveKeyDown = (event, item) => {
|
|
1824
|
+
if (settings.keyboard.deleteRemovesFocusedBadge && (event.key === "Backspace" || event.key === "Delete")) {
|
|
1825
|
+
event.preventDefault();
|
|
1826
|
+
event.stopPropagation();
|
|
1827
|
+
removeItem(item);
|
|
1828
|
+
return;
|
|
1692
1829
|
}
|
|
1830
|
+
stopInlineKey(event);
|
|
1693
1831
|
};
|
|
1694
1832
|
const handleTriggerKeyDown = (event) => {
|
|
1695
1833
|
if (settings.disabled) {
|
|
1696
1834
|
return;
|
|
1697
1835
|
}
|
|
1698
|
-
if (event.key
|
|
1836
|
+
if (isSpaceKey(event.key) && !settings.keyboard.space) {
|
|
1837
|
+
event.preventDefault();
|
|
1838
|
+
return;
|
|
1839
|
+
}
|
|
1840
|
+
if (event.key === "Enter" || isSpaceKey(event.key)) {
|
|
1699
1841
|
event.preventDefault();
|
|
1700
1842
|
toggleDropdown();
|
|
1701
1843
|
return;
|
|
1702
1844
|
}
|
|
1703
|
-
if (event.key === "ArrowDown") {
|
|
1845
|
+
if (settings.keyboard.arrows && event.key === "ArrowDown") {
|
|
1704
1846
|
event.preventDefault();
|
|
1705
1847
|
if (!isOpen) {
|
|
1706
1848
|
openDropdown("first");
|
|
@@ -1709,7 +1851,7 @@ function InnerMultiSelectDropdown({
|
|
|
1709
1851
|
}
|
|
1710
1852
|
return;
|
|
1711
1853
|
}
|
|
1712
|
-
if (event.key === "ArrowUp") {
|
|
1854
|
+
if (settings.keyboard.arrows && event.key === "ArrowUp") {
|
|
1713
1855
|
event.preventDefault();
|
|
1714
1856
|
if (!isOpen) {
|
|
1715
1857
|
openDropdown("last");
|
|
@@ -1718,48 +1860,84 @@ function InnerMultiSelectDropdown({
|
|
|
1718
1860
|
}
|
|
1719
1861
|
return;
|
|
1720
1862
|
}
|
|
1721
|
-
if (event.key === "Escape" && isOpen) {
|
|
1863
|
+
if (settings.keyboard.escape && event.key === "Escape" && isOpen) {
|
|
1722
1864
|
event.preventDefault();
|
|
1723
1865
|
closeDropdown(true);
|
|
1724
1866
|
}
|
|
1725
1867
|
};
|
|
1726
1868
|
const handleArrowButtonKeyDown = (event) => {
|
|
1727
|
-
if (event.key
|
|
1869
|
+
if (isSpaceKey(event.key) && !settings.keyboard.space) {
|
|
1870
|
+
event.preventDefault();
|
|
1871
|
+
event.stopPropagation();
|
|
1872
|
+
return;
|
|
1873
|
+
}
|
|
1874
|
+
if (event.key === "Enter" || isSpaceKey(event.key)) {
|
|
1728
1875
|
event.preventDefault();
|
|
1729
1876
|
event.stopPropagation();
|
|
1730
1877
|
toggleDropdown();
|
|
1731
1878
|
return;
|
|
1732
1879
|
}
|
|
1733
|
-
if (event.key === "ArrowDown") {
|
|
1880
|
+
if (settings.keyboard.arrows && event.key === "ArrowDown") {
|
|
1734
1881
|
event.preventDefault();
|
|
1735
1882
|
event.stopPropagation();
|
|
1736
|
-
|
|
1883
|
+
if (isOpen) {
|
|
1884
|
+
focusFirstOption();
|
|
1885
|
+
} else {
|
|
1886
|
+
openDropdown("first");
|
|
1887
|
+
}
|
|
1737
1888
|
return;
|
|
1738
1889
|
}
|
|
1739
|
-
if (event.key === "ArrowUp") {
|
|
1890
|
+
if (settings.keyboard.arrows && event.key === "ArrowUp") {
|
|
1740
1891
|
event.preventDefault();
|
|
1741
1892
|
event.stopPropagation();
|
|
1742
|
-
|
|
1893
|
+
if (isOpen) {
|
|
1894
|
+
focusLastOption();
|
|
1895
|
+
} else {
|
|
1896
|
+
openDropdown("last");
|
|
1897
|
+
}
|
|
1743
1898
|
}
|
|
1744
1899
|
};
|
|
1745
1900
|
const handleSearchKeyDown = (event) => {
|
|
1746
|
-
if (event.key
|
|
1901
|
+
if (isSpaceKey(event.key) && !settings.keyboard.space) {
|
|
1902
|
+
event.preventDefault();
|
|
1903
|
+
return;
|
|
1904
|
+
}
|
|
1905
|
+
if (settings.keyboard.backspaceRemovesLastWhenSearchEmpty && event.key === "Backspace" && !filter && selectedItems.length > 0 && !settings.singleSelection) {
|
|
1906
|
+
event.preventDefault();
|
|
1907
|
+
removeLastSelectedItem();
|
|
1908
|
+
return;
|
|
1909
|
+
}
|
|
1910
|
+
if (settings.keyboard.arrows && event.key === "ArrowDown") {
|
|
1747
1911
|
event.preventDefault();
|
|
1748
1912
|
focusFirstOption();
|
|
1749
1913
|
return;
|
|
1750
1914
|
}
|
|
1751
|
-
if (event.key === "Escape"
|
|
1915
|
+
if (settings.keyboard.escape && event.key === "Escape") {
|
|
1752
1916
|
event.preventDefault();
|
|
1753
1917
|
closeDropdown(true);
|
|
1754
1918
|
}
|
|
1755
1919
|
};
|
|
1756
1920
|
const handleOptionKeyDown = (event, item, optionIndex) => {
|
|
1757
|
-
if (event.key
|
|
1921
|
+
if (isSpaceKey(event.key) && !settings.keyboard.space) {
|
|
1922
|
+
event.preventDefault();
|
|
1923
|
+
return;
|
|
1924
|
+
}
|
|
1925
|
+
if ((event.key === "Enter" || isSpaceKey(event.key)) && event.repeat) {
|
|
1926
|
+
event.preventDefault();
|
|
1927
|
+
return;
|
|
1928
|
+
}
|
|
1929
|
+
if (event.key === "Enter" || isSpaceKey(event.key)) {
|
|
1758
1930
|
event.preventDefault();
|
|
1759
|
-
|
|
1931
|
+
const willClose = !isSelected(item) && (settings.singleSelection || settings.closeDropDownOnSelection);
|
|
1932
|
+
const currentOptionId = event.currentTarget.id;
|
|
1933
|
+
const moveToNextOption = isSpaceKey(event.key) && settings.keyboard.spaceOptionAction === "toggle-and-next";
|
|
1934
|
+
selectItem(item, willClose ? "trigger" : "none");
|
|
1935
|
+
if (!willClose) {
|
|
1936
|
+
focusOptionAfterKeyboardSelection(currentOptionId, optionIndex, moveToNextOption);
|
|
1937
|
+
}
|
|
1760
1938
|
return;
|
|
1761
1939
|
}
|
|
1762
|
-
if (event.key === "ArrowDown") {
|
|
1940
|
+
if (settings.keyboard.arrows && event.key === "ArrowDown") {
|
|
1763
1941
|
event.preventDefault();
|
|
1764
1942
|
const nextIndex = optionIndex + 1;
|
|
1765
1943
|
const options = getOptionElements();
|
|
@@ -1770,7 +1948,7 @@ function InnerMultiSelectDropdown({
|
|
|
1770
1948
|
}
|
|
1771
1949
|
return;
|
|
1772
1950
|
}
|
|
1773
|
-
if (event.key === "ArrowUp") {
|
|
1951
|
+
if (settings.keyboard.arrows && event.key === "ArrowUp") {
|
|
1774
1952
|
event.preventDefault();
|
|
1775
1953
|
if (optionIndex > 0) {
|
|
1776
1954
|
focusOptionByIndex(optionIndex - 1);
|
|
@@ -1781,21 +1959,54 @@ function InnerMultiSelectDropdown({
|
|
|
1781
1959
|
}
|
|
1782
1960
|
return;
|
|
1783
1961
|
}
|
|
1784
|
-
if (event.key === "Home") {
|
|
1962
|
+
if (settings.keyboard.arrows && event.key === "Home") {
|
|
1785
1963
|
event.preventDefault();
|
|
1786
1964
|
focusFirstOption();
|
|
1787
1965
|
return;
|
|
1788
1966
|
}
|
|
1789
|
-
if (event.key === "End") {
|
|
1967
|
+
if (settings.keyboard.arrows && event.key === "End") {
|
|
1790
1968
|
event.preventDefault();
|
|
1791
1969
|
focusLastOption();
|
|
1792
1970
|
return;
|
|
1793
1971
|
}
|
|
1794
|
-
if (event.key === "Escape"
|
|
1972
|
+
if (settings.keyboard.escape && event.key === "Escape") {
|
|
1795
1973
|
event.preventDefault();
|
|
1796
1974
|
closeDropdown(true);
|
|
1797
1975
|
}
|
|
1798
1976
|
};
|
|
1977
|
+
const slotState = {
|
|
1978
|
+
settings,
|
|
1979
|
+
isOpen,
|
|
1980
|
+
filter,
|
|
1981
|
+
selectedItems,
|
|
1982
|
+
visibleBadges,
|
|
1983
|
+
hiddenBadgeCount,
|
|
1984
|
+
filteredItems,
|
|
1985
|
+
selectableItems,
|
|
1986
|
+
allFilteredSelected,
|
|
1987
|
+
hasFilteredResults,
|
|
1988
|
+
loading: Boolean(loading ?? settings.loading),
|
|
1989
|
+
listboxId,
|
|
1990
|
+
activeDescendantId: activeDescendantId || void 0,
|
|
1991
|
+
label: selectedItems.length ? selectedItems.map((item) => getLabel(item, settings)).join(", ") : settings.text
|
|
1992
|
+
};
|
|
1993
|
+
const slotActions = {
|
|
1994
|
+
openDropdown: () => openDropdown("search"),
|
|
1995
|
+
closeDropdown: () => closeDropdown(),
|
|
1996
|
+
toggleDropdown,
|
|
1997
|
+
clearSelection,
|
|
1998
|
+
selectItem: (item) => selectItem(item),
|
|
1999
|
+
removeItem: (item) => removeItem(item),
|
|
2000
|
+
selectAll: (items = selectableItems) => selectAllItems(items),
|
|
2001
|
+
deSelectAll: (items = selectedItems) => deSelectAllItems(items),
|
|
2002
|
+
toggleGroup,
|
|
2003
|
+
addFilterNewItem: handleAddFilterNewItem,
|
|
2004
|
+
setFilter
|
|
2005
|
+
};
|
|
2006
|
+
const slotBase = {
|
|
2007
|
+
state: slotState,
|
|
2008
|
+
actions: slotActions
|
|
2009
|
+
};
|
|
1799
2010
|
const renderItemNode = (item) => {
|
|
1800
2011
|
const context = {
|
|
1801
2012
|
item,
|
|
@@ -1811,49 +2022,122 @@ function InnerMultiSelectDropdown({
|
|
|
1811
2022
|
!isPrimitiveItem(item) && item.caption ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "rmsd-option-hint", children: String(item.caption) }) : null
|
|
1812
2023
|
] });
|
|
1813
2024
|
};
|
|
1814
|
-
const
|
|
2025
|
+
const renderBadgeLabel = (item) => {
|
|
2026
|
+
const label = getLabel(item, settings);
|
|
1815
2027
|
const context = {
|
|
1816
2028
|
item,
|
|
1817
|
-
label
|
|
2029
|
+
label,
|
|
1818
2030
|
selected: true,
|
|
1819
2031
|
disabled: settings.disabled || isDisabledItem(item),
|
|
1820
2032
|
query: filter,
|
|
1821
2033
|
toggle: () => selectItem(item),
|
|
1822
2034
|
remove: () => removeItem(item)
|
|
1823
2035
|
};
|
|
1824
|
-
|
|
2036
|
+
const badgeContent = renderBadge ? renderBadge(item, context) : context.label;
|
|
2037
|
+
const badgeLabelProps = { className: "rmsd-badge-label" };
|
|
2038
|
+
return renderSlot(
|
|
2039
|
+
slots?.BadgeLabel,
|
|
2040
|
+
{ ...slotBase, props: badgeLabelProps, item, label, children: badgeContent },
|
|
2041
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { ...badgeLabelProps, children: badgeContent })
|
|
2042
|
+
);
|
|
2043
|
+
};
|
|
2044
|
+
const renderCheckbox = (checked, context) => {
|
|
2045
|
+
if (!settings.showCheckbox) {
|
|
2046
|
+
return null;
|
|
2047
|
+
}
|
|
2048
|
+
const checkboxProps = {
|
|
2049
|
+
className: "rmsd-checkbox",
|
|
2050
|
+
"data-checked": checked,
|
|
2051
|
+
"aria-hidden": true
|
|
2052
|
+
};
|
|
2053
|
+
return renderSlot(
|
|
2054
|
+
slots?.Checkbox,
|
|
2055
|
+
{ ...slotBase, props: checkboxProps, checked, context },
|
|
2056
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { ...checkboxProps })
|
|
2057
|
+
);
|
|
2058
|
+
};
|
|
2059
|
+
const renderBadgeRemoveButton = (item) => {
|
|
2060
|
+
const label = getLabel(item, settings);
|
|
2061
|
+
const removeProps = {
|
|
2062
|
+
type: "button",
|
|
2063
|
+
className: "rmsd-badge-remove",
|
|
2064
|
+
"aria-label": getRemoveItemAriaLabel(item),
|
|
2065
|
+
onKeyDown: (event) => handleBadgeRemoveKeyDown(event, item),
|
|
2066
|
+
onClick: (event) => {
|
|
2067
|
+
event.stopPropagation();
|
|
2068
|
+
removeItem(item);
|
|
2069
|
+
}
|
|
2070
|
+
};
|
|
2071
|
+
const icon = /* @__PURE__ */ (0, import_jsx_runtime.jsx)(StacklineIcon, { name: "remove" });
|
|
2072
|
+
return renderSlot(
|
|
2073
|
+
slots?.BadgeRemove,
|
|
2074
|
+
{ ...slotBase, props: removeProps, item, label, icon },
|
|
2075
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { ...removeProps, children: icon })
|
|
2076
|
+
);
|
|
2077
|
+
};
|
|
2078
|
+
const renderBadgeNode = (item) => {
|
|
2079
|
+
const label = getLabel(item, settings);
|
|
2080
|
+
const badgeProps = { className: "rmsd-badge" };
|
|
2081
|
+
const removeButton = !settings.disabled ? renderBadgeRemoveButton(item) : null;
|
|
2082
|
+
const children = /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
|
|
2083
|
+
renderBadgeLabel(item),
|
|
2084
|
+
removeButton
|
|
2085
|
+
] });
|
|
2086
|
+
return renderSlot(
|
|
2087
|
+
slots?.Badge,
|
|
2088
|
+
{ ...slotBase, props: badgeProps, item, label, children, removeButton },
|
|
2089
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { ...badgeProps, children })
|
|
2090
|
+
);
|
|
1825
2091
|
};
|
|
1826
|
-
let
|
|
2092
|
+
let enabledOptionCursor = -1;
|
|
1827
2093
|
const renderOption = (item, prefix, localIndex) => {
|
|
1828
2094
|
const selected = isSelected(item);
|
|
1829
2095
|
const disabled = settings.disabled || isDisabledItem(item) || limitReached && !selected;
|
|
1830
|
-
|
|
1831
|
-
const optionIndex = optionCursor;
|
|
2096
|
+
const optionIndex = disabled ? -1 : enabledOptionCursor += 1;
|
|
1832
2097
|
const optionId = getOptionId(item, localIndex, prefix);
|
|
1833
|
-
|
|
1834
|
-
|
|
1835
|
-
|
|
1836
|
-
|
|
1837
|
-
|
|
1838
|
-
|
|
1839
|
-
|
|
1840
|
-
|
|
1841
|
-
|
|
1842
|
-
|
|
1843
|
-
|
|
1844
|
-
|
|
1845
|
-
|
|
1846
|
-
|
|
1847
|
-
|
|
1848
|
-
|
|
1849
|
-
|
|
1850
|
-
|
|
1851
|
-
|
|
1852
|
-
|
|
1853
|
-
|
|
2098
|
+
const optionKey = `${prefix}-${getPrimaryValue(item, settings)}-${localIndex}`;
|
|
2099
|
+
const optionSlot = {
|
|
2100
|
+
item,
|
|
2101
|
+
id: optionId,
|
|
2102
|
+
key: optionKey,
|
|
2103
|
+
label: getLabel(item, settings),
|
|
2104
|
+
selected,
|
|
2105
|
+
disabled,
|
|
2106
|
+
index: optionIndex,
|
|
2107
|
+
groupName: prefix.startsWith("group-") ? prefix : void 0
|
|
2108
|
+
};
|
|
2109
|
+
const optionProps = {
|
|
2110
|
+
id: optionId,
|
|
2111
|
+
className: `rmsd-option${selected ? " rmsd-selected" : ""}${disabled ? " rmsd-disabled" : ""}`,
|
|
2112
|
+
role: "option",
|
|
2113
|
+
"aria-selected": selected,
|
|
2114
|
+
"aria-checked": selected,
|
|
2115
|
+
"aria-disabled": disabled,
|
|
2116
|
+
tabIndex: disabled || !settings.keyboard.tab ? -1 : 0,
|
|
2117
|
+
"data-rmsd-option": "true",
|
|
2118
|
+
onFocus: () => setActiveDescendantId(optionId),
|
|
2119
|
+
onClick: () => {
|
|
2120
|
+
if (disabled) {
|
|
2121
|
+
return;
|
|
2122
|
+
}
|
|
2123
|
+
const willClose = !isSelected(item) && (settings.singleSelection || settings.closeDropDownOnSelection);
|
|
2124
|
+
selectItem(item, willClose ? "trigger" : "none");
|
|
2125
|
+
if (!willClose) {
|
|
2126
|
+
focusOptionAfterPointerSelection(optionId, optionIndex);
|
|
2127
|
+
}
|
|
1854
2128
|
},
|
|
1855
|
-
|
|
1856
|
-
|
|
2129
|
+
onKeyDown: (event) => handleOptionKeyDown(event, item, optionIndex)
|
|
2130
|
+
};
|
|
2131
|
+
const checkbox = renderCheckbox(selected, "option");
|
|
2132
|
+
const children = /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
|
|
2133
|
+
checkbox,
|
|
2134
|
+
renderItemNode(item)
|
|
2135
|
+
] });
|
|
2136
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react2.Fragment, { children: renderSlot(
|
|
2137
|
+
slots?.Option,
|
|
2138
|
+
{ ...slotBase, props: optionProps, option: optionSlot, checkbox, children },
|
|
2139
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { ...optionProps, children })
|
|
2140
|
+
) }, optionKey);
|
|
1857
2141
|
};
|
|
1858
2142
|
const handleTriggerClick = (event) => {
|
|
1859
2143
|
if (event.target.closest("button")) {
|
|
@@ -1861,174 +2145,1229 @@ function InnerMultiSelectDropdown({
|
|
|
1861
2145
|
}
|
|
1862
2146
|
toggleDropdown();
|
|
1863
2147
|
};
|
|
1864
|
-
const
|
|
1865
|
-
|
|
1866
|
-
{
|
|
2148
|
+
const renderSelectAllButton = () => {
|
|
2149
|
+
const label = allFilteredSelected ? filter.trim() ? settings.filterUnSelectAllText : settings.unSelectAllText : filter.trim() ? settings.filterSelectAllText : settings.selectAllText;
|
|
2150
|
+
const selectAllProps = {
|
|
2151
|
+
type: "button",
|
|
2152
|
+
className: "rmsd-inline-button rmsd-select-all-button",
|
|
2153
|
+
onClick: () => allFilteredSelected ? deSelectAllItems(selectableItems, Boolean(filter.trim())) : selectAllItems(selectableItems, Boolean(filter.trim())),
|
|
2154
|
+
onKeyDown: stopInlineKey,
|
|
2155
|
+
disabled: settings.disabled || selectableItems.length === 0
|
|
2156
|
+
};
|
|
2157
|
+
const checkbox = renderCheckbox(allFilteredSelected, "selectAll");
|
|
2158
|
+
return renderSlot(
|
|
2159
|
+
slots?.SelectAll,
|
|
2160
|
+
{ ...slotBase, props: selectAllProps, checked: allFilteredSelected, label, checkbox },
|
|
2161
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("button", { ...selectAllProps, children: [
|
|
2162
|
+
checkbox,
|
|
2163
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: label })
|
|
2164
|
+
] })
|
|
2165
|
+
);
|
|
2166
|
+
};
|
|
2167
|
+
const renderAddNewItemButton = () => {
|
|
2168
|
+
const query = filter.trim();
|
|
2169
|
+
if (!query) {
|
|
2170
|
+
return null;
|
|
2171
|
+
}
|
|
2172
|
+
const label = `${settings.addNewButtonText} "${query}"`;
|
|
2173
|
+
const addItemProps = {
|
|
2174
|
+
type: "button",
|
|
2175
|
+
className: "rmsd-inline-button rmsd-add-button",
|
|
2176
|
+
onKeyDown: stopInlineKey,
|
|
2177
|
+
onClick: handleAddFilterNewItem
|
|
2178
|
+
};
|
|
2179
|
+
return renderSlot(
|
|
2180
|
+
slots?.AddNewItem,
|
|
2181
|
+
{ ...slotBase, props: addItemProps, query, label },
|
|
2182
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { ...addItemProps, children: label })
|
|
2183
|
+
);
|
|
2184
|
+
};
|
|
2185
|
+
const renderSearchNode = () => {
|
|
2186
|
+
if (!settings.enableSearchFilter) {
|
|
2187
|
+
return null;
|
|
2188
|
+
}
|
|
2189
|
+
const searchShellProps = { className: "rmsd-search-shell" };
|
|
2190
|
+
const searchInputProps = {
|
|
2191
|
+
ref: searchRef,
|
|
2192
|
+
className: "rmsd-search-input",
|
|
2193
|
+
value: filter,
|
|
2194
|
+
onChange: (event) => setFilter(event.target.value),
|
|
2195
|
+
onKeyDown: handleSearchKeyDown,
|
|
2196
|
+
placeholder: settings.searchPlaceholderText,
|
|
2197
|
+
"aria-label": settings.searchAriaLabel
|
|
2198
|
+
};
|
|
2199
|
+
const searchClearProps = {
|
|
2200
|
+
type: "button",
|
|
2201
|
+
className: "rmsd-search-clear",
|
|
2202
|
+
"aria-label": settings.clearSearchAriaLabel,
|
|
2203
|
+
onKeyDown: stopInlineKey,
|
|
2204
|
+
onClick: () => setFilter("")
|
|
2205
|
+
};
|
|
2206
|
+
const icon = /* @__PURE__ */ (0, import_jsx_runtime.jsx)(StacklineIcon, { name: "search", className: "rmsd-search-icon" });
|
|
2207
|
+
const clearIcon = /* @__PURE__ */ (0, import_jsx_runtime.jsx)(StacklineIcon, { name: "clear" });
|
|
2208
|
+
const fallback = renderSearch ? renderSearch({ query: filter, setQuery: setFilter, closeDropdown: () => closeDropdown() }) : /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { ...searchShellProps, children: [
|
|
2209
|
+
icon,
|
|
2210
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("input", { ...searchInputProps }),
|
|
2211
|
+
filter ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { ...searchClearProps, children: clearIcon }) : null
|
|
2212
|
+
] });
|
|
2213
|
+
return renderSlot(
|
|
2214
|
+
slots?.Search,
|
|
2215
|
+
{
|
|
2216
|
+
...slotBase,
|
|
2217
|
+
props: searchShellProps,
|
|
2218
|
+
inputProps: searchInputProps,
|
|
2219
|
+
clearButtonProps: searchClearProps,
|
|
2220
|
+
query: filter,
|
|
2221
|
+
icon,
|
|
2222
|
+
clearIcon
|
|
2223
|
+
},
|
|
2224
|
+
fallback
|
|
2225
|
+
);
|
|
2226
|
+
};
|
|
2227
|
+
const renderGroupAction = (group) => {
|
|
2228
|
+
if (!settings.selectGroup || settings.singleSelection) {
|
|
2229
|
+
return null;
|
|
2230
|
+
}
|
|
2231
|
+
const label = group.selected ? "Unselect" : "Select";
|
|
2232
|
+
const groupActionProps = {
|
|
2233
|
+
type: "button",
|
|
2234
|
+
className: "rmsd-group-action",
|
|
2235
|
+
onKeyDown: stopInlineKey,
|
|
2236
|
+
onClick: () => toggleGroup(group.name, group.items)
|
|
2237
|
+
};
|
|
2238
|
+
return renderSlot(
|
|
2239
|
+
slots?.GroupAction,
|
|
2240
|
+
{ ...slotBase, props: groupActionProps, group, label },
|
|
2241
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { ...groupActionProps, children: label })
|
|
2242
|
+
);
|
|
2243
|
+
};
|
|
2244
|
+
const renderGroupNode = (group, groupIndex) => {
|
|
2245
|
+
const enabledItems = group.items.filter((item) => !isDisabledItem(item));
|
|
2246
|
+
const groupSlot = {
|
|
2247
|
+
name: group.name,
|
|
2248
|
+
items: group.items,
|
|
2249
|
+
enabledItems,
|
|
2250
|
+
selected: enabledItems.length > 0 && enabledItems.every((item) => isSelected(item)),
|
|
2251
|
+
disabled: enabledItems.length === 0,
|
|
2252
|
+
index: groupIndex
|
|
2253
|
+
};
|
|
2254
|
+
const action = renderGroupAction(groupSlot);
|
|
2255
|
+
const groupHeaderProps = { className: "rmsd-group-header" };
|
|
2256
|
+
const header = renderSlot(
|
|
2257
|
+
slots?.GroupHeader,
|
|
2258
|
+
{ ...slotBase, props: groupHeaderProps, group: groupSlot, action },
|
|
2259
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { ...groupHeaderProps, children: [
|
|
2260
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { children: [
|
|
2261
|
+
group.name,
|
|
2262
|
+
" \xB7 ",
|
|
2263
|
+
group.items.length
|
|
2264
|
+
] }),
|
|
2265
|
+
action
|
|
2266
|
+
] })
|
|
2267
|
+
);
|
|
2268
|
+
const groupProps = {
|
|
2269
|
+
className: "rmsd-group",
|
|
2270
|
+
role: "group",
|
|
2271
|
+
"aria-label": group.name
|
|
2272
|
+
};
|
|
2273
|
+
const children = group.items.map((item, index) => renderOption(item, `group-${groupIndex}`, index));
|
|
2274
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react2.Fragment, { children: renderSlot(
|
|
2275
|
+
slots?.Group,
|
|
2276
|
+
{ ...slotBase, props: groupProps, group: groupSlot, header, children },
|
|
2277
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { ...groupProps, children: [
|
|
2278
|
+
header,
|
|
2279
|
+
children
|
|
2280
|
+
] })
|
|
2281
|
+
) }, group.name);
|
|
2282
|
+
};
|
|
2283
|
+
const renderOptionListChildren = () => {
|
|
2284
|
+
if (loading ?? settings.loading) {
|
|
2285
|
+
const loadingProps = { className: "rmsd-state", role: "status" };
|
|
2286
|
+
return renderSlot(
|
|
2287
|
+
slots?.LoadingState,
|
|
2288
|
+
{ ...slotBase, props: loadingProps, text: settings.loadingText },
|
|
2289
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { ...loadingProps, children: settings.loadingText })
|
|
2290
|
+
);
|
|
2291
|
+
}
|
|
2292
|
+
if (groupedItems.length > 0) {
|
|
2293
|
+
return groupedItems.map((group, groupIndex) => renderGroupNode(group, groupIndex));
|
|
2294
|
+
}
|
|
2295
|
+
if (hasFilteredResults) {
|
|
2296
|
+
return filteredItems.map((item, index) => renderOption(item, "item", index));
|
|
2297
|
+
}
|
|
2298
|
+
const emptyProps = { className: "rmsd-state" };
|
|
2299
|
+
return renderSlot(
|
|
2300
|
+
slots?.EmptyState,
|
|
2301
|
+
{ ...slotBase, props: emptyProps, query: filter, text: settings.noDataLabel },
|
|
2302
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { ...emptyProps, children: renderEmptyState ? renderEmptyState(filter) : settings.noDataLabel })
|
|
2303
|
+
);
|
|
2304
|
+
};
|
|
2305
|
+
const renderOptionList = () => {
|
|
2306
|
+
const listProps = {
|
|
2307
|
+
className: "rmsd-list",
|
|
2308
|
+
ref: listRef,
|
|
2309
|
+
style: {
|
|
2310
|
+
maxHeight: shouldAppendToBody ? bodyListMaxHeight ?? settings.maxHeight : settings.maxHeight
|
|
2311
|
+
},
|
|
2312
|
+
onScroll: settings.lazyLoading ? handleListScroll : void 0,
|
|
2313
|
+
id: listboxId,
|
|
2314
|
+
role: "listbox",
|
|
2315
|
+
"aria-label": settings.listboxAriaLabel,
|
|
2316
|
+
"aria-multiselectable": !settings.singleSelection
|
|
2317
|
+
};
|
|
2318
|
+
const children = renderOptionListChildren();
|
|
2319
|
+
return renderSlot(
|
|
2320
|
+
slots?.OptionList,
|
|
2321
|
+
{ ...slotBase, props: listProps, children },
|
|
2322
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { ...listProps, children })
|
|
2323
|
+
);
|
|
2324
|
+
};
|
|
2325
|
+
const renderBulkActions = () => {
|
|
2326
|
+
if (!hasBulkActions) {
|
|
2327
|
+
return null;
|
|
2328
|
+
}
|
|
2329
|
+
const bulkActionsProps = { className: "rmsd-bulk-actions" };
|
|
2330
|
+
const children = /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
|
|
2331
|
+
settings.enableCheckAll && !settings.singleSelection ? renderSelectAllButton() : null,
|
|
2332
|
+
settings.addNewItemOnFilter && filter.trim() ? renderAddNewItemButton() : null
|
|
2333
|
+
] });
|
|
2334
|
+
return renderSlot(
|
|
2335
|
+
slots?.BulkActions,
|
|
2336
|
+
{ ...slotBase, props: bulkActionsProps, children },
|
|
2337
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { ...bulkActionsProps, children })
|
|
2338
|
+
);
|
|
2339
|
+
};
|
|
2340
|
+
const renderToolbar = () => {
|
|
2341
|
+
const toolbarProps = { className: "rmsd-toolbar" };
|
|
2342
|
+
const children = /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
|
|
2343
|
+
renderBulkActions(),
|
|
2344
|
+
renderSearchNode()
|
|
2345
|
+
] });
|
|
2346
|
+
return renderSlot(
|
|
2347
|
+
slots?.Toolbar,
|
|
2348
|
+
{ ...slotBase, props: toolbarProps, children },
|
|
2349
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { ...toolbarProps, children })
|
|
2350
|
+
);
|
|
2351
|
+
};
|
|
2352
|
+
const renderMenuFooter = () => {
|
|
2353
|
+
if (!slots?.MenuFooter) {
|
|
2354
|
+
return null;
|
|
2355
|
+
}
|
|
2356
|
+
return renderSlot(slots.MenuFooter, { ...slotBase, props: { className: "rmsd-menu-footer" } }, null);
|
|
2357
|
+
};
|
|
2358
|
+
const renderMenu = () => {
|
|
2359
|
+
if (!isOpen) {
|
|
2360
|
+
return null;
|
|
2361
|
+
}
|
|
2362
|
+
const menuProps = {
|
|
1867
2363
|
ref: menuRef,
|
|
1868
2364
|
className: `rmsd-menu rmsd-${effectivePosition} skin-${skinName} theme-${skinName}${skinFallbackClass ? ` ${skinFallbackClass}` : ""}${shouldAppendToBody ? " rmsd-body-overlay" : ""}`,
|
|
1869
2365
|
style: shouldAppendToBody ? bodyMenuStyle : void 0,
|
|
1870
2366
|
onMouseDown: (event) => event.stopPropagation(),
|
|
1871
|
-
onTouchStart: (event) => event.stopPropagation()
|
|
1872
|
-
|
|
1873
|
-
|
|
1874
|
-
|
|
1875
|
-
|
|
1876
|
-
|
|
1877
|
-
|
|
1878
|
-
|
|
1879
|
-
|
|
1880
|
-
onClick: () => allFilteredSelected ? deSelectAllItems(selectableItems, Boolean(filter.trim())) : selectAllItems(selectableItems, Boolean(filter.trim())),
|
|
1881
|
-
disabled: settings.disabled || selectableItems.length === 0,
|
|
1882
|
-
children: [
|
|
1883
|
-
settings.showCheckbox ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "rmsd-checkbox", "data-checked": allFilteredSelected, "aria-hidden": "true" }) : null,
|
|
1884
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: allFilteredSelected ? filter.trim() ? settings.filterUnSelectAllText : settings.unSelectAllText : filter.trim() ? settings.filterSelectAllText : settings.selectAllText })
|
|
1885
|
-
]
|
|
1886
|
-
}
|
|
1887
|
-
) : null,
|
|
1888
|
-
settings.addNewItemOnFilter && filter.trim() ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("button", { type: "button", className: "rmsd-inline-button rmsd-add-button", onClick: handleAddFilterNewItem, children: [
|
|
1889
|
-
settings.addNewButtonText,
|
|
1890
|
-
' "',
|
|
1891
|
-
filter.trim(),
|
|
1892
|
-
'"'
|
|
1893
|
-
] }) : null
|
|
1894
|
-
] }) : null,
|
|
1895
|
-
settings.enableSearchFilter ? renderSearch ? renderSearch({ query: filter, setQuery: setFilter, closeDropdown: () => closeDropdown() }) : /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "rmsd-search-shell", children: [
|
|
1896
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(StacklineIcon, { name: "search", className: "rmsd-search-icon" }),
|
|
1897
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1898
|
-
"input",
|
|
1899
|
-
{
|
|
1900
|
-
ref: searchRef,
|
|
1901
|
-
className: "rmsd-search-input",
|
|
1902
|
-
value: filter,
|
|
1903
|
-
onChange: (event) => setFilter(event.target.value),
|
|
1904
|
-
onKeyDown: handleSearchKeyDown,
|
|
1905
|
-
placeholder: settings.searchPlaceholderText,
|
|
1906
|
-
"aria-label": settings.searchAriaLabel
|
|
1907
|
-
}
|
|
1908
|
-
),
|
|
1909
|
-
filter ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1910
|
-
"button",
|
|
1911
|
-
{
|
|
1912
|
-
type: "button",
|
|
1913
|
-
className: "rmsd-search-clear",
|
|
1914
|
-
"aria-label": settings.clearSearchAriaLabel,
|
|
1915
|
-
onKeyDown: stopInlineKey,
|
|
1916
|
-
onClick: () => setFilter(""),
|
|
1917
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(StacklineIcon, { name: "clear" })
|
|
1918
|
-
}
|
|
1919
|
-
) : null
|
|
1920
|
-
] }) : null
|
|
1921
|
-
] }),
|
|
1922
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1923
|
-
"div",
|
|
1924
|
-
{
|
|
1925
|
-
className: "rmsd-list",
|
|
1926
|
-
ref: listRef,
|
|
1927
|
-
style: { maxHeight: shouldAppendToBody ? bodyListMaxHeight ?? settings.maxHeight : settings.maxHeight },
|
|
1928
|
-
onScroll: settings.lazyLoading ? handleListScroll : void 0,
|
|
1929
|
-
id: listboxId,
|
|
1930
|
-
role: "listbox",
|
|
1931
|
-
"aria-label": settings.listboxAriaLabel,
|
|
1932
|
-
"aria-multiselectable": !settings.singleSelection,
|
|
1933
|
-
children: loading ?? settings.loading ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "rmsd-state", role: "status", children: settings.loadingText }) : groupedItems.length > 0 ? groupedItems.map((group, groupIndex) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "rmsd-group", role: "group", "aria-label": group.name, children: [
|
|
1934
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "rmsd-group-header", children: [
|
|
1935
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { children: [
|
|
1936
|
-
group.name,
|
|
1937
|
-
" \xB7 ",
|
|
1938
|
-
group.items.length
|
|
1939
|
-
] }),
|
|
1940
|
-
settings.selectGroup && !settings.singleSelection ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { type: "button", className: "rmsd-group-action", onClick: () => toggleGroup(group.name, group.items), children: group.items.filter((item) => !isDisabledItem(item)).every((item) => isSelected(item)) ? "Unselect" : "Select" }) : null
|
|
1941
|
-
] }),
|
|
1942
|
-
group.items.map((item, index) => renderOption(item, `group-${groupIndex}`, index))
|
|
1943
|
-
] }, group.name)) : hasFilteredResults ? filteredItems.map((item, index) => renderOption(item, "item", index)) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "rmsd-state", children: renderEmptyState ? renderEmptyState(filter) : settings.noDataLabel })
|
|
1944
|
-
}
|
|
1945
|
-
)
|
|
1946
|
-
]
|
|
1947
|
-
}
|
|
1948
|
-
) : null;
|
|
1949
|
-
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: rootClassName, style, ref: rootRef, "data-open": isOpen, children: [
|
|
1950
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
1951
|
-
"div",
|
|
2367
|
+
onTouchStart: (event) => event.stopPropagation()
|
|
2368
|
+
};
|
|
2369
|
+
const children = /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
|
|
2370
|
+
renderToolbar(),
|
|
2371
|
+
renderOptionList(),
|
|
2372
|
+
renderMenuFooter()
|
|
2373
|
+
] });
|
|
2374
|
+
return renderSlot(
|
|
2375
|
+
slots?.Menu,
|
|
1952
2376
|
{
|
|
1953
|
-
|
|
1954
|
-
|
|
1955
|
-
|
|
1956
|
-
|
|
1957
|
-
|
|
1958
|
-
|
|
1959
|
-
|
|
1960
|
-
|
|
1961
|
-
|
|
1962
|
-
|
|
1963
|
-
|
|
1964
|
-
|
|
1965
|
-
|
|
1966
|
-
|
|
1967
|
-
|
|
1968
|
-
|
|
1969
|
-
|
|
1970
|
-
|
|
1971
|
-
|
|
1972
|
-
|
|
1973
|
-
|
|
1974
|
-
|
|
1975
|
-
|
|
1976
|
-
|
|
1977
|
-
|
|
1978
|
-
|
|
1979
|
-
|
|
1980
|
-
|
|
1981
|
-
|
|
1982
|
-
|
|
1983
|
-
|
|
1984
|
-
|
|
1985
|
-
|
|
1986
|
-
|
|
1987
|
-
|
|
1988
|
-
|
|
1989
|
-
|
|
1990
|
-
|
|
1991
|
-
|
|
1992
|
-
|
|
1993
|
-
|
|
1994
|
-
|
|
1995
|
-
|
|
1996
|
-
|
|
1997
|
-
|
|
1998
|
-
|
|
1999
|
-
|
|
2000
|
-
|
|
2001
|
-
|
|
2002
|
-
|
|
2003
|
-
|
|
2004
|
-
|
|
2005
|
-
|
|
2006
|
-
{
|
|
2007
|
-
type: "button",
|
|
2008
|
-
className: "rmsd-arrow-button",
|
|
2009
|
-
disabled: settings.disabled,
|
|
2010
|
-
"aria-label": isOpen ? settings.closeDropdownAriaLabel : settings.openDropdownAriaLabel,
|
|
2011
|
-
"aria-expanded": isOpen,
|
|
2012
|
-
"aria-controls": listboxId,
|
|
2013
|
-
onKeyDown: handleArrowButtonKeyDown,
|
|
2014
|
-
onClick: (event) => {
|
|
2015
|
-
event.stopPropagation();
|
|
2016
|
-
toggleDropdown();
|
|
2017
|
-
},
|
|
2018
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "rmsd-arrow", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(StacklineIcon, { name: isOpen ? "angle-up" : "angle-down" }) })
|
|
2019
|
-
}
|
|
2020
|
-
)
|
|
2021
|
-
] })
|
|
2022
|
-
]
|
|
2377
|
+
...slotBase,
|
|
2378
|
+
props: menuProps,
|
|
2379
|
+
children,
|
|
2380
|
+
position: effectivePosition,
|
|
2381
|
+
appendToBody: shouldAppendToBody
|
|
2382
|
+
},
|
|
2383
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { ...menuProps, children })
|
|
2384
|
+
);
|
|
2385
|
+
};
|
|
2386
|
+
const renderValue = () => {
|
|
2387
|
+
const valueProps = { className: "rmsd-value" };
|
|
2388
|
+
let children;
|
|
2389
|
+
if (selectedItems.length === 0) {
|
|
2390
|
+
const placeholderProps = { className: "rmsd-placeholder" };
|
|
2391
|
+
children = renderSlot(
|
|
2392
|
+
slots?.Placeholder,
|
|
2393
|
+
{ ...slotBase, props: placeholderProps, text: settings.text },
|
|
2394
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { ...placeholderProps, children: settings.text })
|
|
2395
|
+
);
|
|
2396
|
+
} else if (settings.singleSelection) {
|
|
2397
|
+
const item = selectedItems[0];
|
|
2398
|
+
const singleValueProps = { className: "rmsd-single-value" };
|
|
2399
|
+
children = renderSlot(
|
|
2400
|
+
slots?.SingleValue,
|
|
2401
|
+
{ ...slotBase, props: singleValueProps, item, label: getLabel(item, settings) },
|
|
2402
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { ...singleValueProps, children: getLabel(item, settings) })
|
|
2403
|
+
);
|
|
2404
|
+
} else {
|
|
2405
|
+
const badgeListProps = { className: "rmsd-badge-list" };
|
|
2406
|
+
const badgeListChildren = visibleBadges.map((item) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react2.Fragment, { children: renderBadgeNode(item) }, getPrimaryValue(item, settings)));
|
|
2407
|
+
children = renderSlot(
|
|
2408
|
+
slots?.BadgeList,
|
|
2409
|
+
{ ...slotBase, props: badgeListProps, items: visibleBadges, children: badgeListChildren },
|
|
2410
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { ...badgeListProps, children: badgeListChildren })
|
|
2411
|
+
);
|
|
2412
|
+
}
|
|
2413
|
+
return renderSlot(
|
|
2414
|
+
slots?.Value,
|
|
2415
|
+
{ ...slotBase, props: valueProps, children },
|
|
2416
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { ...valueProps, children })
|
|
2417
|
+
);
|
|
2418
|
+
};
|
|
2419
|
+
const renderActions = () => {
|
|
2420
|
+
const actionsProps = { className: "rmsd-actions" };
|
|
2421
|
+
const overflowProps = { className: "rmsd-overflow" };
|
|
2422
|
+
const clearAllProps = {
|
|
2423
|
+
type: "button",
|
|
2424
|
+
className: "rmsd-clear",
|
|
2425
|
+
"aria-label": settings.clearAllAriaLabel,
|
|
2426
|
+
onKeyDown: stopInlineKey,
|
|
2427
|
+
onClick: (event) => {
|
|
2428
|
+
event.stopPropagation();
|
|
2429
|
+
clearSelection();
|
|
2023
2430
|
}
|
|
2024
|
-
|
|
2431
|
+
};
|
|
2432
|
+
const arrowProps = {
|
|
2433
|
+
type: "button",
|
|
2434
|
+
className: "rmsd-arrow-button",
|
|
2435
|
+
disabled: settings.disabled,
|
|
2436
|
+
"aria-label": isOpen ? settings.closeDropdownAriaLabel : settings.openDropdownAriaLabel,
|
|
2437
|
+
"aria-expanded": isOpen,
|
|
2438
|
+
"aria-controls": listboxId,
|
|
2439
|
+
onKeyDown: handleArrowButtonKeyDown,
|
|
2440
|
+
onClick: (event) => {
|
|
2441
|
+
event.stopPropagation();
|
|
2442
|
+
toggleDropdown();
|
|
2443
|
+
}
|
|
2444
|
+
};
|
|
2445
|
+
const clearIcon = /* @__PURE__ */ (0, import_jsx_runtime.jsx)(StacklineIcon, { name: "remove" });
|
|
2446
|
+
const arrowIcon = /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "rmsd-arrow", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(StacklineIcon, { name: isOpen ? "angle-up" : "angle-down" }) });
|
|
2447
|
+
const children = /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
|
|
2448
|
+
hiddenBadgeCount > 0 ? renderSlot(
|
|
2449
|
+
slots?.OverflowCounter,
|
|
2450
|
+
{ ...slotBase, props: overflowProps, count: hiddenBadgeCount },
|
|
2451
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { ...overflowProps, children: [
|
|
2452
|
+
"+",
|
|
2453
|
+
hiddenBadgeCount
|
|
2454
|
+
] })
|
|
2455
|
+
) : null,
|
|
2456
|
+
settings.clearAll && selectedItems.length > 0 && !settings.disabled ? renderSlot(
|
|
2457
|
+
slots?.ClearAll,
|
|
2458
|
+
{ ...slotBase, props: clearAllProps, icon: clearIcon },
|
|
2459
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { ...clearAllProps, children: clearIcon })
|
|
2460
|
+
) : null,
|
|
2461
|
+
renderSlot(
|
|
2462
|
+
slots?.Arrow,
|
|
2463
|
+
{ ...slotBase, props: arrowProps, icon: arrowIcon, direction: isOpen ? "up" : "down" },
|
|
2464
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { ...arrowProps, children: arrowIcon })
|
|
2465
|
+
)
|
|
2466
|
+
] });
|
|
2467
|
+
return renderSlot(
|
|
2468
|
+
slots?.Actions,
|
|
2469
|
+
{ ...slotBase, props: actionsProps, children },
|
|
2470
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { ...actionsProps, children })
|
|
2471
|
+
);
|
|
2472
|
+
};
|
|
2473
|
+
const renderTrigger = () => {
|
|
2474
|
+
const triggerProps = {
|
|
2475
|
+
ref: triggerRef,
|
|
2476
|
+
className: `rmsd-trigger${settings.disabled ? " rmsd-disabled" : ""}`,
|
|
2477
|
+
onClick: handleTriggerClick,
|
|
2478
|
+
onKeyDown: handleTriggerKeyDown,
|
|
2479
|
+
tabIndex: settings.disabled ? -1 : 0,
|
|
2480
|
+
role: "combobox",
|
|
2481
|
+
"aria-expanded": isOpen,
|
|
2482
|
+
"aria-haspopup": "listbox",
|
|
2483
|
+
"aria-controls": listboxId,
|
|
2484
|
+
"aria-disabled": settings.disabled,
|
|
2485
|
+
"aria-activedescendant": activeDescendantId || void 0,
|
|
2486
|
+
"aria-label": getTriggerAriaLabel()
|
|
2487
|
+
};
|
|
2488
|
+
const children = /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
|
|
2489
|
+
renderValue(),
|
|
2490
|
+
renderActions()
|
|
2491
|
+
] });
|
|
2492
|
+
return renderSlot(
|
|
2493
|
+
slots?.Trigger,
|
|
2494
|
+
{ ...slotBase, props: triggerProps, children },
|
|
2495
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { ...triggerProps, children })
|
|
2496
|
+
);
|
|
2497
|
+
};
|
|
2498
|
+
const menu = renderMenu();
|
|
2499
|
+
const rootChildren = /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
|
|
2500
|
+
renderTrigger(),
|
|
2025
2501
|
shouldAppendToBody && menu && typeof document !== "undefined" ? (0, import_react_dom.createPortal)(menu, document.body) : menu
|
|
2026
2502
|
] });
|
|
2503
|
+
const rootProps = {
|
|
2504
|
+
className: rootClassName,
|
|
2505
|
+
style,
|
|
2506
|
+
ref: rootRef,
|
|
2507
|
+
"data-open": isOpen
|
|
2508
|
+
};
|
|
2509
|
+
return renderSlot(
|
|
2510
|
+
slots?.Root,
|
|
2511
|
+
{ ...slotBase, props: rootProps, children: rootChildren },
|
|
2512
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { ...rootProps, children: rootChildren })
|
|
2513
|
+
);
|
|
2027
2514
|
}
|
|
2028
|
-
var ReactMultiSelectDropdown = (0,
|
|
2515
|
+
var ReactMultiSelectDropdown = (0, import_react2.forwardRef)(InnerMultiSelectDropdown);
|
|
2029
2516
|
var MultiSelectDropdown = ReactMultiSelectDropdown;
|
|
2517
|
+
|
|
2518
|
+
// src/useMultiSelectDropdown.ts
|
|
2519
|
+
var import_react4 = require("react");
|
|
2520
|
+
|
|
2521
|
+
// src/reactUtils.ts
|
|
2522
|
+
function assignRef(ref, value) {
|
|
2523
|
+
if (typeof ref === "function") {
|
|
2524
|
+
ref(value);
|
|
2525
|
+
return;
|
|
2526
|
+
}
|
|
2527
|
+
if (ref && "current" in ref) {
|
|
2528
|
+
ref.current = value;
|
|
2529
|
+
}
|
|
2530
|
+
}
|
|
2531
|
+
function eventWasPrevented(event) {
|
|
2532
|
+
return Boolean(event.defaultPrevented);
|
|
2533
|
+
}
|
|
2534
|
+
function callAll(ownHandler, userHandler) {
|
|
2535
|
+
return (event) => {
|
|
2536
|
+
userHandler?.(event);
|
|
2537
|
+
if (!eventWasPrevented(event)) {
|
|
2538
|
+
ownHandler?.(event);
|
|
2539
|
+
}
|
|
2540
|
+
};
|
|
2541
|
+
}
|
|
2542
|
+
|
|
2543
|
+
// src/useMultiSelectState.ts
|
|
2544
|
+
var import_react3 = require("react");
|
|
2545
|
+
function useMultiSelectState({
|
|
2546
|
+
data,
|
|
2547
|
+
settings: incomingSettings,
|
|
2548
|
+
selectedItems: controlledSelectedItems,
|
|
2549
|
+
defaultSelectedItems,
|
|
2550
|
+
onChange,
|
|
2551
|
+
onSelect,
|
|
2552
|
+
onDeSelect,
|
|
2553
|
+
onSelectAll,
|
|
2554
|
+
onDeSelectAll,
|
|
2555
|
+
onFilterSelectAll,
|
|
2556
|
+
onFilterDeSelectAll,
|
|
2557
|
+
onAddFilterNewItem,
|
|
2558
|
+
onGroupSelect,
|
|
2559
|
+
onGroupDeSelect,
|
|
2560
|
+
onSelectionShouldClose
|
|
2561
|
+
}) {
|
|
2562
|
+
const [filter, setFilter] = (0, import_react3.useState)("");
|
|
2563
|
+
const [addedItems, setAddedItems] = (0, import_react3.useState)([]);
|
|
2564
|
+
const addRequestIdRef = (0, import_react3.useRef)(0);
|
|
2565
|
+
const settings = (0, import_react3.useMemo)(() => resolveDropdownSettings(incomingSettings), [incomingSettings]);
|
|
2566
|
+
const [selectedItems, setSelectedItems] = useControllableSelection(
|
|
2567
|
+
controlledSelectedItems,
|
|
2568
|
+
defaultSelectedItems,
|
|
2569
|
+
onChange
|
|
2570
|
+
);
|
|
2571
|
+
const allItems = (0, import_react3.useMemo)(
|
|
2572
|
+
() => mergeUniqueItems(data, [...selectedItems, ...addedItems], settings),
|
|
2573
|
+
[addedItems, data, selectedItems, settings]
|
|
2574
|
+
);
|
|
2575
|
+
const filteredItems = (0, import_react3.useMemo)(
|
|
2576
|
+
() => allItems.filter((item) => itemMatchesQuery(item, filter, settings)),
|
|
2577
|
+
[allItems, filter, settings]
|
|
2578
|
+
);
|
|
2579
|
+
const isSelected = (item) => selectedItems.some(
|
|
2580
|
+
(selectedItem) => getPrimaryValue(selectedItem, settings) === getPrimaryValue(item, settings)
|
|
2581
|
+
);
|
|
2582
|
+
const isDisabled = (item) => settings.disabled || isDisabledItem(item);
|
|
2583
|
+
const selectableItems = filteredItems.filter((item) => !isDisabled(item));
|
|
2584
|
+
const allFilteredSelected = selectableItems.length > 0 && selectableItems.every((item) => isSelected(item));
|
|
2585
|
+
const visibleBadgeLimit = getVisibleBadgeLimit(selectedItems.length, settings.badgeShowLimit);
|
|
2586
|
+
const visibleBadges = settings.singleSelection ? selectedItems : selectedItems.slice(0, visibleBadgeLimit);
|
|
2587
|
+
const hiddenBadgeCount = settings.singleSelection ? 0 : Math.max(selectedItems.length - visibleBadges.length, 0);
|
|
2588
|
+
const updateSelection = (nextItems) => {
|
|
2589
|
+
setSelectedItems(nextItems);
|
|
2590
|
+
};
|
|
2591
|
+
const removeItem = (item) => {
|
|
2592
|
+
if (settings.disabled) {
|
|
2593
|
+
return;
|
|
2594
|
+
}
|
|
2595
|
+
const nextItems = selectedItems.filter(
|
|
2596
|
+
(selectedItem) => getPrimaryValue(selectedItem, settings) !== getPrimaryValue(item, settings)
|
|
2597
|
+
);
|
|
2598
|
+
updateSelection(nextItems);
|
|
2599
|
+
onDeSelect?.(item);
|
|
2600
|
+
};
|
|
2601
|
+
const removeLastSelectedItem = () => {
|
|
2602
|
+
const lastItem = selectedItems[selectedItems.length - 1];
|
|
2603
|
+
if (!lastItem || settings.disabled) {
|
|
2604
|
+
return;
|
|
2605
|
+
}
|
|
2606
|
+
removeItem(lastItem);
|
|
2607
|
+
};
|
|
2608
|
+
const selectItem = (item) => {
|
|
2609
|
+
if (settings.disabled || isDisabledItem(item)) {
|
|
2610
|
+
return;
|
|
2611
|
+
}
|
|
2612
|
+
if (isSelected(item)) {
|
|
2613
|
+
removeItem(item);
|
|
2614
|
+
return;
|
|
2615
|
+
}
|
|
2616
|
+
if (settings.singleSelection) {
|
|
2617
|
+
updateSelection([item]);
|
|
2618
|
+
onSelect?.(item);
|
|
2619
|
+
onSelectionShouldClose?.();
|
|
2620
|
+
return;
|
|
2621
|
+
}
|
|
2622
|
+
if (settings.limitSelection && selectedItems.length >= settings.limitSelection) {
|
|
2623
|
+
return;
|
|
2624
|
+
}
|
|
2625
|
+
const nextItems = [...selectedItems, item];
|
|
2626
|
+
updateSelection(nextItems);
|
|
2627
|
+
onSelect?.(item);
|
|
2628
|
+
if (settings.closeDropDownOnSelection) {
|
|
2629
|
+
onSelectionShouldClose?.();
|
|
2630
|
+
}
|
|
2631
|
+
};
|
|
2632
|
+
const selectAll = (items = selectableItems, filteredSelection = false) => {
|
|
2633
|
+
if (settings.disabled || settings.singleSelection) {
|
|
2634
|
+
return;
|
|
2635
|
+
}
|
|
2636
|
+
const selectedIds = new Set(selectedItems.map((item) => getPrimaryValue(item, settings)));
|
|
2637
|
+
const remainingCapacity = settings.limitSelection ? Math.max(settings.limitSelection - selectedItems.length, 0) : Number.MAX_SAFE_INTEGER;
|
|
2638
|
+
const nextItemsToAdd = items.filter((item) => !selectedIds.has(getPrimaryValue(item, settings))).filter((item) => !isDisabledItem(item)).slice(0, remainingCapacity);
|
|
2639
|
+
const nextItems = [...selectedItems, ...nextItemsToAdd];
|
|
2640
|
+
updateSelection(nextItems);
|
|
2641
|
+
if (filteredSelection) {
|
|
2642
|
+
onFilterSelectAll?.(nextItemsToAdd);
|
|
2643
|
+
} else {
|
|
2644
|
+
onSelectAll?.(nextItems);
|
|
2645
|
+
}
|
|
2646
|
+
};
|
|
2647
|
+
const deSelectAll = (items = selectedItems, filteredSelection = false) => {
|
|
2648
|
+
if (settings.disabled) {
|
|
2649
|
+
return;
|
|
2650
|
+
}
|
|
2651
|
+
const itemIds = new Set(items.map((item) => getPrimaryValue(item, settings)));
|
|
2652
|
+
const nextItems = selectedItems.filter((item) => !itemIds.has(getPrimaryValue(item, settings)));
|
|
2653
|
+
updateSelection(nextItems);
|
|
2654
|
+
if (filteredSelection) {
|
|
2655
|
+
onFilterDeSelectAll?.(items);
|
|
2656
|
+
} else {
|
|
2657
|
+
onDeSelectAll?.(items);
|
|
2658
|
+
}
|
|
2659
|
+
};
|
|
2660
|
+
const clearSelection = () => deSelectAll(selectedItems);
|
|
2661
|
+
const toggleGroup = (groupName, items) => {
|
|
2662
|
+
if (settings.disabled) {
|
|
2663
|
+
return;
|
|
2664
|
+
}
|
|
2665
|
+
const enabledItems = items.filter((item) => !isDisabledItem(item));
|
|
2666
|
+
const allSelected = enabledItems.length > 0 && enabledItems.every((item) => isSelected(item));
|
|
2667
|
+
if (allSelected) {
|
|
2668
|
+
deSelectAll(enabledItems);
|
|
2669
|
+
onGroupDeSelect?.(groupName, enabledItems);
|
|
2670
|
+
return;
|
|
2671
|
+
}
|
|
2672
|
+
selectAll(enabledItems);
|
|
2673
|
+
onGroupSelect?.(groupName, enabledItems);
|
|
2674
|
+
};
|
|
2675
|
+
const addFilterNewItem = async () => {
|
|
2676
|
+
if (settings.disabled) {
|
|
2677
|
+
return;
|
|
2678
|
+
}
|
|
2679
|
+
const query = filter.trim();
|
|
2680
|
+
if (!query) {
|
|
2681
|
+
return;
|
|
2682
|
+
}
|
|
2683
|
+
const requestId = addRequestIdRef.current + 1;
|
|
2684
|
+
addRequestIdRef.current = requestId;
|
|
2685
|
+
const result = await onAddFilterNewItem?.(query);
|
|
2686
|
+
if (requestId !== addRequestIdRef.current) {
|
|
2687
|
+
return;
|
|
2688
|
+
}
|
|
2689
|
+
const nextItem = result === void 0 ? createItemFromQuery(query, settings, data[0]) : result;
|
|
2690
|
+
setAddedItems((currentItems) => mergeUniqueItems(currentItems, [nextItem], settings));
|
|
2691
|
+
if (settings.singleSelection) {
|
|
2692
|
+
updateSelection([nextItem]);
|
|
2693
|
+
} else {
|
|
2694
|
+
updateSelection(mergeUniqueItems(selectedItems, [nextItem], settings));
|
|
2695
|
+
}
|
|
2696
|
+
setFilter("");
|
|
2697
|
+
};
|
|
2698
|
+
return {
|
|
2699
|
+
settings,
|
|
2700
|
+
filter,
|
|
2701
|
+
setFilter,
|
|
2702
|
+
selectedItems,
|
|
2703
|
+
allItems,
|
|
2704
|
+
filteredItems,
|
|
2705
|
+
selectableItems,
|
|
2706
|
+
visibleBadges,
|
|
2707
|
+
hiddenBadgeCount,
|
|
2708
|
+
allFilteredSelected,
|
|
2709
|
+
isSelected,
|
|
2710
|
+
isDisabled,
|
|
2711
|
+
getItemLabel: (item) => getLabel(item, settings),
|
|
2712
|
+
getItemKey: (item) => getPrimaryValue(item, settings),
|
|
2713
|
+
selectItem,
|
|
2714
|
+
removeItem,
|
|
2715
|
+
removeLastSelectedItem,
|
|
2716
|
+
selectAll,
|
|
2717
|
+
deSelectAll,
|
|
2718
|
+
clearSelection,
|
|
2719
|
+
toggleGroup,
|
|
2720
|
+
addFilterNewItem
|
|
2721
|
+
};
|
|
2722
|
+
}
|
|
2723
|
+
|
|
2724
|
+
// src/useMultiSelectDropdown.ts
|
|
2725
|
+
function isSpaceKey2(key) {
|
|
2726
|
+
return key === " " || key === "Spacebar";
|
|
2727
|
+
}
|
|
2728
|
+
function useMultiSelectDropdown({
|
|
2729
|
+
id,
|
|
2730
|
+
data,
|
|
2731
|
+
settings: incomingSettings,
|
|
2732
|
+
selectedItems: controlledSelectedItems,
|
|
2733
|
+
defaultSelectedItems,
|
|
2734
|
+
onChange,
|
|
2735
|
+
onSelect,
|
|
2736
|
+
onDeSelect,
|
|
2737
|
+
onSelectAll,
|
|
2738
|
+
onDeSelectAll,
|
|
2739
|
+
onOpen,
|
|
2740
|
+
onClose,
|
|
2741
|
+
onScrollToEnd,
|
|
2742
|
+
onFilterSelectAll,
|
|
2743
|
+
onFilterDeSelectAll,
|
|
2744
|
+
onAddFilterNewItem,
|
|
2745
|
+
onGroupSelect,
|
|
2746
|
+
onGroupDeSelect
|
|
2747
|
+
}) {
|
|
2748
|
+
const reactId = (0, import_react4.useId)();
|
|
2749
|
+
const instanceId = sanitizeId(id || `stackline-multiselect-${reactId}`);
|
|
2750
|
+
const rootRef = (0, import_react4.useRef)(null);
|
|
2751
|
+
const triggerRef = (0, import_react4.useRef)(null);
|
|
2752
|
+
const searchRef = (0, import_react4.useRef)(null);
|
|
2753
|
+
const listboxRef = (0, import_react4.useRef)(null);
|
|
2754
|
+
const optionRefs = (0, import_react4.useRef)(/* @__PURE__ */ new Map());
|
|
2755
|
+
const lastScrollHeightRef = (0, import_react4.useRef)(0);
|
|
2756
|
+
const closeDropdownRef = (0, import_react4.useRef)(() => void 0);
|
|
2757
|
+
const pendingFocusRef = (0, import_react4.useRef)("search");
|
|
2758
|
+
const [isOpen, setIsOpen] = (0, import_react4.useState)(false);
|
|
2759
|
+
const [activeOptionIndex, setActiveOptionIndex] = (0, import_react4.useState)(-1);
|
|
2760
|
+
const listboxId = `${instanceId}-listbox`;
|
|
2761
|
+
const state = useMultiSelectState({
|
|
2762
|
+
data,
|
|
2763
|
+
settings: incomingSettings,
|
|
2764
|
+
selectedItems: controlledSelectedItems,
|
|
2765
|
+
defaultSelectedItems,
|
|
2766
|
+
onChange,
|
|
2767
|
+
onSelect,
|
|
2768
|
+
onDeSelect,
|
|
2769
|
+
onSelectAll,
|
|
2770
|
+
onDeSelectAll,
|
|
2771
|
+
onFilterSelectAll,
|
|
2772
|
+
onFilterDeSelectAll,
|
|
2773
|
+
onAddFilterNewItem,
|
|
2774
|
+
onGroupSelect,
|
|
2775
|
+
onGroupDeSelect,
|
|
2776
|
+
onSelectionShouldClose: () => closeDropdownRef.current()
|
|
2777
|
+
});
|
|
2778
|
+
const {
|
|
2779
|
+
settings,
|
|
2780
|
+
filter,
|
|
2781
|
+
setFilter,
|
|
2782
|
+
selectedItems,
|
|
2783
|
+
filteredItems,
|
|
2784
|
+
selectableItems,
|
|
2785
|
+
visibleBadges,
|
|
2786
|
+
hiddenBadgeCount,
|
|
2787
|
+
allFilteredSelected,
|
|
2788
|
+
isSelected,
|
|
2789
|
+
isDisabled
|
|
2790
|
+
} = state;
|
|
2791
|
+
const limitReached = Boolean(settings.limitSelection) && selectedItems.length >= settings.limitSelection;
|
|
2792
|
+
const options = (0, import_react4.useMemo)(() => {
|
|
2793
|
+
let optionIndex = -1;
|
|
2794
|
+
return filteredItems.map((item) => {
|
|
2795
|
+
optionIndex += 1;
|
|
2796
|
+
const groupName = getGroupName(item, settings) || void 0;
|
|
2797
|
+
const selected = selectedItems.some(
|
|
2798
|
+
(selectedItem) => getPrimaryValue(selectedItem, settings) === getPrimaryValue(item, settings)
|
|
2799
|
+
);
|
|
2800
|
+
const disabled = settings.disabled || isDisabledItem(item) || limitReached && !selected;
|
|
2801
|
+
const key = getPrimaryValue(item, settings);
|
|
2802
|
+
return {
|
|
2803
|
+
item,
|
|
2804
|
+
key,
|
|
2805
|
+
id: `${instanceId}-option-${optionIndex}-${sanitizeId(key)}`,
|
|
2806
|
+
label: getLabel(item, settings),
|
|
2807
|
+
selected,
|
|
2808
|
+
disabled,
|
|
2809
|
+
index: optionIndex,
|
|
2810
|
+
groupName
|
|
2811
|
+
};
|
|
2812
|
+
});
|
|
2813
|
+
}, [filteredItems, instanceId, limitReached, selectedItems, settings]);
|
|
2814
|
+
const selectableOptions = options.filter((option) => !option.disabled);
|
|
2815
|
+
const selectedOptions = options.filter((option) => option.selected);
|
|
2816
|
+
const groups = (0, import_react4.useMemo)(() => {
|
|
2817
|
+
if (!settings.groupBy) {
|
|
2818
|
+
return [];
|
|
2819
|
+
}
|
|
2820
|
+
const bucket = /* @__PURE__ */ new Map();
|
|
2821
|
+
for (const option of options) {
|
|
2822
|
+
const groupName = option.groupName || "Ungrouped";
|
|
2823
|
+
const current = bucket.get(groupName) || [];
|
|
2824
|
+
current.push(option);
|
|
2825
|
+
bucket.set(groupName, current);
|
|
2826
|
+
}
|
|
2827
|
+
return Array.from(bucket.entries()).map(([name, groupOptions]) => {
|
|
2828
|
+
const enabledOptions = groupOptions.filter((option) => !option.disabled);
|
|
2829
|
+
return {
|
|
2830
|
+
name,
|
|
2831
|
+
items: groupOptions,
|
|
2832
|
+
selected: enabledOptions.length > 0 && enabledOptions.every((option) => option.selected),
|
|
2833
|
+
disabled: enabledOptions.length === 0
|
|
2834
|
+
};
|
|
2835
|
+
});
|
|
2836
|
+
}, [options, settings.groupBy]);
|
|
2837
|
+
const activeOption = options.find((option) => option.index === activeOptionIndex && !option.disabled);
|
|
2838
|
+
const activeDescendantId = activeOption?.id;
|
|
2839
|
+
const hasFilteredResults = options.length > 0;
|
|
2840
|
+
const label = selectedItems.length ? selectedItems.map((item) => getLabel(item, settings)).join(", ") : settings.text;
|
|
2841
|
+
const focusOption = (index) => {
|
|
2842
|
+
if (!options.length) {
|
|
2843
|
+
setActiveOptionIndex(-1);
|
|
2844
|
+
return;
|
|
2845
|
+
}
|
|
2846
|
+
const enabledOptions = options.filter((option2) => !option2.disabled);
|
|
2847
|
+
if (!enabledOptions.length) {
|
|
2848
|
+
setActiveOptionIndex(-1);
|
|
2849
|
+
return;
|
|
2850
|
+
}
|
|
2851
|
+
const boundedIndex = Math.max(0, Math.min(index, enabledOptions.length - 1));
|
|
2852
|
+
const option = enabledOptions[boundedIndex];
|
|
2853
|
+
setActiveOptionIndex(option.index);
|
|
2854
|
+
window.setTimeout(() => {
|
|
2855
|
+
optionRefs.current.get(option.id)?.focus();
|
|
2856
|
+
optionRefs.current.get(option.id)?.scrollIntoView({ block: "nearest" });
|
|
2857
|
+
}, 0);
|
|
2858
|
+
};
|
|
2859
|
+
const focusOptionById = (optionId, fallbackIndex, moveToNextOption = false) => {
|
|
2860
|
+
setActiveOptionIndex(fallbackIndex);
|
|
2861
|
+
window.setTimeout(() => {
|
|
2862
|
+
const focusAfterRender = () => {
|
|
2863
|
+
if (moveToNextOption) {
|
|
2864
|
+
const optionNodes = Array.from(
|
|
2865
|
+
listboxRef.current?.querySelectorAll(
|
|
2866
|
+
'[data-headless-option="true"]:not([aria-disabled="true"])'
|
|
2867
|
+
) ?? []
|
|
2868
|
+
);
|
|
2869
|
+
const currentIndex = optionNodes.findIndex((optionNode2) => optionNode2.id === optionId);
|
|
2870
|
+
const nextOptionNode = currentIndex >= 0 ? optionNodes[currentIndex + 1] : void 0;
|
|
2871
|
+
if (nextOptionNode) {
|
|
2872
|
+
const nextOption = options.find((option) => option.id === nextOptionNode.id);
|
|
2873
|
+
nextOptionNode.focus();
|
|
2874
|
+
nextOptionNode.scrollIntoView({ block: "nearest" });
|
|
2875
|
+
setActiveOptionIndex(nextOption?.index ?? fallbackIndex + 1);
|
|
2876
|
+
return;
|
|
2877
|
+
}
|
|
2878
|
+
}
|
|
2879
|
+
const optionNode = optionRefs.current.get(optionId);
|
|
2880
|
+
if (optionNode) {
|
|
2881
|
+
optionNode.focus();
|
|
2882
|
+
optionNode.scrollIntoView({ block: "nearest" });
|
|
2883
|
+
return;
|
|
2884
|
+
}
|
|
2885
|
+
focusOption(fallbackIndex);
|
|
2886
|
+
};
|
|
2887
|
+
if (typeof window.requestAnimationFrame === "function") {
|
|
2888
|
+
window.requestAnimationFrame(focusAfterRender);
|
|
2889
|
+
return;
|
|
2890
|
+
}
|
|
2891
|
+
focusAfterRender();
|
|
2892
|
+
}, 0);
|
|
2893
|
+
};
|
|
2894
|
+
const openDropdown = (focusTarget = "search") => {
|
|
2895
|
+
if (settings.disabled) {
|
|
2896
|
+
return;
|
|
2897
|
+
}
|
|
2898
|
+
pendingFocusRef.current = focusTarget;
|
|
2899
|
+
setIsOpen((current) => {
|
|
2900
|
+
if (!current) {
|
|
2901
|
+
onOpen?.();
|
|
2902
|
+
}
|
|
2903
|
+
return true;
|
|
2904
|
+
});
|
|
2905
|
+
};
|
|
2906
|
+
const closeDropdown = () => {
|
|
2907
|
+
setIsOpen((current) => {
|
|
2908
|
+
if (current) {
|
|
2909
|
+
onClose?.();
|
|
2910
|
+
}
|
|
2911
|
+
return false;
|
|
2912
|
+
});
|
|
2913
|
+
setActiveOptionIndex(-1);
|
|
2914
|
+
};
|
|
2915
|
+
closeDropdownRef.current = closeDropdown;
|
|
2916
|
+
const toggleDropdown = () => {
|
|
2917
|
+
if (isOpen) {
|
|
2918
|
+
closeDropdown();
|
|
2919
|
+
return;
|
|
2920
|
+
}
|
|
2921
|
+
openDropdown();
|
|
2922
|
+
};
|
|
2923
|
+
const focusAfterSelectionChange = (target = "search") => {
|
|
2924
|
+
if (target === "none") {
|
|
2925
|
+
return;
|
|
2926
|
+
}
|
|
2927
|
+
window.setTimeout(() => {
|
|
2928
|
+
if (target === "search" && isOpen && settings.enableSearchFilter) {
|
|
2929
|
+
searchRef.current?.focus();
|
|
2930
|
+
return;
|
|
2931
|
+
}
|
|
2932
|
+
triggerRef.current?.focus();
|
|
2933
|
+
}, 0);
|
|
2934
|
+
};
|
|
2935
|
+
const selectItem = (item, focusTarget = "search") => {
|
|
2936
|
+
const wasSelected = state.isSelected(item);
|
|
2937
|
+
const willClose = !wasSelected && (settings.singleSelection || settings.closeDropDownOnSelection);
|
|
2938
|
+
state.selectItem(item);
|
|
2939
|
+
focusAfterSelectionChange(willClose ? "trigger" : focusTarget);
|
|
2940
|
+
};
|
|
2941
|
+
const removeItem = (item, focusTarget = "search") => {
|
|
2942
|
+
state.removeItem(item);
|
|
2943
|
+
focusAfterSelectionChange(focusTarget);
|
|
2944
|
+
};
|
|
2945
|
+
const removeLastSelectedItem = () => {
|
|
2946
|
+
state.removeLastSelectedItem();
|
|
2947
|
+
focusAfterSelectionChange();
|
|
2948
|
+
};
|
|
2949
|
+
const selectAll = (items = selectableItems, filteredSelection = false) => {
|
|
2950
|
+
state.selectAll(items, filteredSelection);
|
|
2951
|
+
focusAfterSelectionChange();
|
|
2952
|
+
};
|
|
2953
|
+
const deSelectAll = (items = selectedItems, filteredSelection = false) => {
|
|
2954
|
+
state.deSelectAll(items, filteredSelection);
|
|
2955
|
+
focusAfterSelectionChange();
|
|
2956
|
+
};
|
|
2957
|
+
const clearSelection = () => {
|
|
2958
|
+
state.clearSelection();
|
|
2959
|
+
focusAfterSelectionChange();
|
|
2960
|
+
};
|
|
2961
|
+
const toggleGroup = (groupName, items) => {
|
|
2962
|
+
state.toggleGroup(groupName, items);
|
|
2963
|
+
focusAfterSelectionChange();
|
|
2964
|
+
};
|
|
2965
|
+
const addFilterNewItem = async () => {
|
|
2966
|
+
await state.addFilterNewItem();
|
|
2967
|
+
focusAfterSelectionChange();
|
|
2968
|
+
};
|
|
2969
|
+
const handleListScroll = () => {
|
|
2970
|
+
if (!listboxRef.current || !onScrollToEnd) {
|
|
2971
|
+
return;
|
|
2972
|
+
}
|
|
2973
|
+
const { scrollHeight, scrollTop, clientHeight } = listboxRef.current;
|
|
2974
|
+
if (scrollHeight === lastScrollHeightRef.current && scrollTop + clientHeight < scrollHeight - 12) {
|
|
2975
|
+
return;
|
|
2976
|
+
}
|
|
2977
|
+
if (scrollTop + clientHeight >= scrollHeight - 12) {
|
|
2978
|
+
lastScrollHeightRef.current = scrollHeight;
|
|
2979
|
+
onScrollToEnd({ scrollTop, scrollHeight, clientHeight });
|
|
2980
|
+
}
|
|
2981
|
+
};
|
|
2982
|
+
const handleTriggerKeyDown = (event) => {
|
|
2983
|
+
if (settings.disabled) {
|
|
2984
|
+
return;
|
|
2985
|
+
}
|
|
2986
|
+
if (isSpaceKey2(event.key) && !settings.keyboard.space) {
|
|
2987
|
+
event.preventDefault();
|
|
2988
|
+
return;
|
|
2989
|
+
}
|
|
2990
|
+
if (event.key === "Enter" || isSpaceKey2(event.key)) {
|
|
2991
|
+
event.preventDefault();
|
|
2992
|
+
toggleDropdown();
|
|
2993
|
+
return;
|
|
2994
|
+
}
|
|
2995
|
+
if (settings.keyboard.arrows && event.key === "ArrowDown") {
|
|
2996
|
+
event.preventDefault();
|
|
2997
|
+
if (isOpen) {
|
|
2998
|
+
focusOption(0);
|
|
2999
|
+
} else {
|
|
3000
|
+
openDropdown("first");
|
|
3001
|
+
}
|
|
3002
|
+
return;
|
|
3003
|
+
}
|
|
3004
|
+
if (settings.keyboard.arrows && event.key === "ArrowUp") {
|
|
3005
|
+
event.preventDefault();
|
|
3006
|
+
if (isOpen) {
|
|
3007
|
+
focusOption(selectableOptions.length - 1);
|
|
3008
|
+
} else {
|
|
3009
|
+
openDropdown("last");
|
|
3010
|
+
}
|
|
3011
|
+
return;
|
|
3012
|
+
}
|
|
3013
|
+
if (settings.keyboard.escape && event.key === "Escape" && isOpen) {
|
|
3014
|
+
event.preventDefault();
|
|
3015
|
+
closeDropdown();
|
|
3016
|
+
}
|
|
3017
|
+
};
|
|
3018
|
+
const handleSearchKeyDown = (event) => {
|
|
3019
|
+
if (isSpaceKey2(event.key) && !settings.keyboard.space) {
|
|
3020
|
+
event.preventDefault();
|
|
3021
|
+
return;
|
|
3022
|
+
}
|
|
3023
|
+
if (settings.keyboard.backspaceRemovesLastWhenSearchEmpty && event.key === "Backspace" && !filter && selectedItems.length > 0 && !settings.singleSelection) {
|
|
3024
|
+
event.preventDefault();
|
|
3025
|
+
removeLastSelectedItem();
|
|
3026
|
+
return;
|
|
3027
|
+
}
|
|
3028
|
+
if (settings.keyboard.arrows && event.key === "ArrowDown") {
|
|
3029
|
+
event.preventDefault();
|
|
3030
|
+
focusOption(0);
|
|
3031
|
+
return;
|
|
3032
|
+
}
|
|
3033
|
+
if (settings.keyboard.escape && event.key === "Escape") {
|
|
3034
|
+
event.preventDefault();
|
|
3035
|
+
closeDropdown();
|
|
3036
|
+
triggerRef.current?.focus();
|
|
3037
|
+
}
|
|
3038
|
+
};
|
|
3039
|
+
const handleOptionKeyDown = (event, option) => {
|
|
3040
|
+
if (isSpaceKey2(event.key) && !settings.keyboard.space) {
|
|
3041
|
+
event.preventDefault();
|
|
3042
|
+
return;
|
|
3043
|
+
}
|
|
3044
|
+
if ((event.key === "Enter" || isSpaceKey2(event.key)) && event.repeat) {
|
|
3045
|
+
event.preventDefault();
|
|
3046
|
+
return;
|
|
3047
|
+
}
|
|
3048
|
+
if (event.key === "Enter" || isSpaceKey2(event.key)) {
|
|
3049
|
+
event.preventDefault();
|
|
3050
|
+
const enabledOptions2 = options.filter((currentOption) => !currentOption.disabled);
|
|
3051
|
+
const currentEnabledIndex2 = enabledOptions2.findIndex((currentOption) => currentOption.id === option.id);
|
|
3052
|
+
const willClose = !state.isSelected(option.item) && (settings.singleSelection || settings.closeDropDownOnSelection);
|
|
3053
|
+
const moveToNextOption = isSpaceKey2(event.key) && settings.keyboard.spaceOptionAction === "toggle-and-next";
|
|
3054
|
+
selectItem(option.item, willClose ? "trigger" : "none");
|
|
3055
|
+
if (!willClose) {
|
|
3056
|
+
focusOptionById(option.id, Math.max(0, currentEnabledIndex2), moveToNextOption);
|
|
3057
|
+
}
|
|
3058
|
+
return;
|
|
3059
|
+
}
|
|
3060
|
+
const enabledOptions = options.filter((currentOption) => !currentOption.disabled);
|
|
3061
|
+
const currentEnabledIndex = enabledOptions.findIndex((currentOption) => currentOption.id === option.id);
|
|
3062
|
+
if (settings.keyboard.arrows && event.key === "ArrowDown") {
|
|
3063
|
+
event.preventDefault();
|
|
3064
|
+
if (currentEnabledIndex < enabledOptions.length - 1) {
|
|
3065
|
+
focusOption(currentEnabledIndex + 1);
|
|
3066
|
+
} else if (settings.lazyLoading) {
|
|
3067
|
+
handleListScroll();
|
|
3068
|
+
}
|
|
3069
|
+
return;
|
|
3070
|
+
}
|
|
3071
|
+
if (settings.keyboard.arrows && event.key === "ArrowUp") {
|
|
3072
|
+
event.preventDefault();
|
|
3073
|
+
if (currentEnabledIndex > 0) {
|
|
3074
|
+
focusOption(currentEnabledIndex - 1);
|
|
3075
|
+
} else if (settings.enableSearchFilter) {
|
|
3076
|
+
searchRef.current?.focus();
|
|
3077
|
+
} else {
|
|
3078
|
+
triggerRef.current?.focus();
|
|
3079
|
+
}
|
|
3080
|
+
return;
|
|
3081
|
+
}
|
|
3082
|
+
if (settings.keyboard.arrows && event.key === "Home") {
|
|
3083
|
+
event.preventDefault();
|
|
3084
|
+
focusOption(0);
|
|
3085
|
+
return;
|
|
3086
|
+
}
|
|
3087
|
+
if (settings.keyboard.arrows && event.key === "End") {
|
|
3088
|
+
event.preventDefault();
|
|
3089
|
+
focusOption(enabledOptions.length - 1);
|
|
3090
|
+
return;
|
|
3091
|
+
}
|
|
3092
|
+
if (settings.keyboard.escape && event.key === "Escape") {
|
|
3093
|
+
event.preventDefault();
|
|
3094
|
+
closeDropdown();
|
|
3095
|
+
triggerRef.current?.focus();
|
|
3096
|
+
}
|
|
3097
|
+
};
|
|
3098
|
+
const handleInlineButtonKeyDown = (event) => {
|
|
3099
|
+
if (isSpaceKey2(event.key) && !settings.keyboard.space) {
|
|
3100
|
+
event.preventDefault();
|
|
3101
|
+
event.stopPropagation();
|
|
3102
|
+
return;
|
|
3103
|
+
}
|
|
3104
|
+
if (event.key === "Enter" || isSpaceKey2(event.key)) {
|
|
3105
|
+
event.stopPropagation();
|
|
3106
|
+
}
|
|
3107
|
+
};
|
|
3108
|
+
const handleRemoveButtonKeyDown = (event, item) => {
|
|
3109
|
+
if (settings.keyboard.deleteRemovesFocusedBadge && (event.key === "Backspace" || event.key === "Delete")) {
|
|
3110
|
+
event.preventDefault();
|
|
3111
|
+
event.stopPropagation();
|
|
3112
|
+
removeItem(item);
|
|
3113
|
+
return;
|
|
3114
|
+
}
|
|
3115
|
+
handleInlineButtonKeyDown(event);
|
|
3116
|
+
};
|
|
3117
|
+
const getOptionFromItem = (optionOrItem) => {
|
|
3118
|
+
if (optionOrItem && typeof optionOrItem === "object" && "item" in optionOrItem && "id" in optionOrItem && "index" in optionOrItem) {
|
|
3119
|
+
return optionOrItem;
|
|
3120
|
+
}
|
|
3121
|
+
const item = optionOrItem;
|
|
3122
|
+
const key = getPrimaryValue(item, settings);
|
|
3123
|
+
const existingOption = options.find((option) => option.key === key);
|
|
3124
|
+
if (existingOption) {
|
|
3125
|
+
return existingOption;
|
|
3126
|
+
}
|
|
3127
|
+
const selected = isSelected(item);
|
|
3128
|
+
return {
|
|
3129
|
+
item,
|
|
3130
|
+
key,
|
|
3131
|
+
id: `${instanceId}-option-manual-${sanitizeId(key)}`,
|
|
3132
|
+
label: getLabel(item, settings),
|
|
3133
|
+
selected,
|
|
3134
|
+
disabled: settings.disabled || isDisabledItem(item) || limitReached && !selected,
|
|
3135
|
+
index: -1,
|
|
3136
|
+
groupName: getGroupName(item, settings) || void 0
|
|
3137
|
+
};
|
|
3138
|
+
};
|
|
3139
|
+
(0, import_react4.useEffect)(() => {
|
|
3140
|
+
if (!isOpen) {
|
|
3141
|
+
return;
|
|
3142
|
+
}
|
|
3143
|
+
const handlePointerDown = (event) => {
|
|
3144
|
+
const target = event.target;
|
|
3145
|
+
if (!rootRef.current?.contains(target) && !listboxRef.current?.contains(target)) {
|
|
3146
|
+
closeDropdown();
|
|
3147
|
+
}
|
|
3148
|
+
};
|
|
3149
|
+
const handleKeyDown = (event) => {
|
|
3150
|
+
if (event.key === "Escape" && settings.keyboard.escape) {
|
|
3151
|
+
closeDropdown();
|
|
3152
|
+
}
|
|
3153
|
+
};
|
|
3154
|
+
document.addEventListener("mousedown", handlePointerDown);
|
|
3155
|
+
document.addEventListener("touchstart", handlePointerDown);
|
|
3156
|
+
document.addEventListener("keydown", handleKeyDown);
|
|
3157
|
+
return () => {
|
|
3158
|
+
document.removeEventListener("mousedown", handlePointerDown);
|
|
3159
|
+
document.removeEventListener("touchstart", handlePointerDown);
|
|
3160
|
+
document.removeEventListener("keydown", handleKeyDown);
|
|
3161
|
+
};
|
|
3162
|
+
}, [isOpen, settings.keyboard.escape]);
|
|
3163
|
+
(0, import_react4.useEffect)(() => {
|
|
3164
|
+
lastScrollHeightRef.current = 0;
|
|
3165
|
+
}, [options.length]);
|
|
3166
|
+
(0, import_react4.useEffect)(() => {
|
|
3167
|
+
if (!isOpen) {
|
|
3168
|
+
return;
|
|
3169
|
+
}
|
|
3170
|
+
const pendingFocus = pendingFocusRef.current;
|
|
3171
|
+
pendingFocusRef.current = "search";
|
|
3172
|
+
window.setTimeout(() => {
|
|
3173
|
+
if (pendingFocus === "first") {
|
|
3174
|
+
focusOption(0);
|
|
3175
|
+
return;
|
|
3176
|
+
}
|
|
3177
|
+
if (pendingFocus === "last") {
|
|
3178
|
+
focusOption(selectableOptions.length - 1);
|
|
3179
|
+
return;
|
|
3180
|
+
}
|
|
3181
|
+
if (settings.enableSearchFilter && settings.searchAutofocus) {
|
|
3182
|
+
searchRef.current?.focus();
|
|
3183
|
+
}
|
|
3184
|
+
}, 0);
|
|
3185
|
+
}, [
|
|
3186
|
+
isOpen,
|
|
3187
|
+
options.length,
|
|
3188
|
+
selectableOptions.length,
|
|
3189
|
+
settings.enableSearchFilter,
|
|
3190
|
+
settings.searchAutofocus
|
|
3191
|
+
]);
|
|
3192
|
+
return {
|
|
3193
|
+
settings,
|
|
3194
|
+
isOpen,
|
|
3195
|
+
filter,
|
|
3196
|
+
setFilter,
|
|
3197
|
+
selectedItems,
|
|
3198
|
+
selectedOptions,
|
|
3199
|
+
options,
|
|
3200
|
+
groups,
|
|
3201
|
+
visibleOptions: options,
|
|
3202
|
+
visibleBadges,
|
|
3203
|
+
hiddenBadgeCount,
|
|
3204
|
+
allFilteredSelected,
|
|
3205
|
+
hasFilteredResults,
|
|
3206
|
+
activeDescendantId,
|
|
3207
|
+
listboxId,
|
|
3208
|
+
label,
|
|
3209
|
+
openDropdown,
|
|
3210
|
+
closeDropdown,
|
|
3211
|
+
toggleDropdown,
|
|
3212
|
+
clearSelection,
|
|
3213
|
+
selectItem,
|
|
3214
|
+
removeItem,
|
|
3215
|
+
selectAll,
|
|
3216
|
+
deSelectAll,
|
|
3217
|
+
toggleGroup,
|
|
3218
|
+
addFilterNewItem,
|
|
3219
|
+
isSelected,
|
|
3220
|
+
isDisabled,
|
|
3221
|
+
getItemLabel: (item) => getLabel(item, settings),
|
|
3222
|
+
getItemKey: (item) => getPrimaryValue(item, settings),
|
|
3223
|
+
getRootProps: (props = {}) => ({
|
|
3224
|
+
...props,
|
|
3225
|
+
ref: (node) => {
|
|
3226
|
+
rootRef.current = node;
|
|
3227
|
+
assignRef(props.ref, node);
|
|
3228
|
+
}
|
|
3229
|
+
}),
|
|
3230
|
+
getTriggerProps: (props = {}) => ({
|
|
3231
|
+
type: "button",
|
|
3232
|
+
...props,
|
|
3233
|
+
ref: (node) => {
|
|
3234
|
+
triggerRef.current = node;
|
|
3235
|
+
assignRef(props.ref, node);
|
|
3236
|
+
},
|
|
3237
|
+
disabled: settings.disabled || props.disabled,
|
|
3238
|
+
role: "combobox",
|
|
3239
|
+
"aria-expanded": isOpen,
|
|
3240
|
+
"aria-haspopup": "listbox",
|
|
3241
|
+
"aria-controls": listboxId,
|
|
3242
|
+
"aria-disabled": settings.disabled || void 0,
|
|
3243
|
+
"aria-activedescendant": activeDescendantId,
|
|
3244
|
+
"aria-label": selectedItems.length ? `${settings.ariaLabel}: ${selectedItems.map((item) => getLabel(item, settings)).join(", ")}` : settings.ariaLabel,
|
|
3245
|
+
onClick: callAll(() => toggleDropdown(), props.onClick),
|
|
3246
|
+
onKeyDown: callAll((event) => {
|
|
3247
|
+
handleTriggerKeyDown(event);
|
|
3248
|
+
}, props.onKeyDown)
|
|
3249
|
+
}),
|
|
3250
|
+
getListboxProps: (props = {}) => ({
|
|
3251
|
+
...props,
|
|
3252
|
+
ref: (node) => {
|
|
3253
|
+
listboxRef.current = node;
|
|
3254
|
+
assignRef(props.ref, node);
|
|
3255
|
+
},
|
|
3256
|
+
id: props.id || listboxId,
|
|
3257
|
+
role: "listbox",
|
|
3258
|
+
"aria-label": props["aria-label"] || settings.listboxAriaLabel,
|
|
3259
|
+
"aria-multiselectable": !settings.singleSelection,
|
|
3260
|
+
onScroll: callAll(() => {
|
|
3261
|
+
if (settings.lazyLoading) {
|
|
3262
|
+
handleListScroll();
|
|
3263
|
+
}
|
|
3264
|
+
}, props.onScroll)
|
|
3265
|
+
}),
|
|
3266
|
+
getOptionProps: (optionOrItem, props = {}) => {
|
|
3267
|
+
const option = getOptionFromItem(optionOrItem);
|
|
3268
|
+
return {
|
|
3269
|
+
...props,
|
|
3270
|
+
ref: (node) => {
|
|
3271
|
+
if (node) {
|
|
3272
|
+
optionRefs.current.set(option.id, node);
|
|
3273
|
+
} else {
|
|
3274
|
+
optionRefs.current.delete(option.id);
|
|
3275
|
+
}
|
|
3276
|
+
assignRef(props.ref, node);
|
|
3277
|
+
},
|
|
3278
|
+
id: props.id || option.id,
|
|
3279
|
+
role: "option",
|
|
3280
|
+
tabIndex: option.disabled || !settings.keyboard.tab ? -1 : props.tabIndex ?? 0,
|
|
3281
|
+
"aria-selected": option.selected,
|
|
3282
|
+
"aria-checked": option.selected,
|
|
3283
|
+
"aria-disabled": option.disabled || void 0,
|
|
3284
|
+
"data-headless-option": "true",
|
|
3285
|
+
onClick: callAll((event) => {
|
|
3286
|
+
if (option.disabled) {
|
|
3287
|
+
return;
|
|
3288
|
+
}
|
|
3289
|
+
const willClose = !state.isSelected(option.item) && (settings.singleSelection || settings.closeDropDownOnSelection);
|
|
3290
|
+
selectItem(option.item, willClose ? "trigger" : "none");
|
|
3291
|
+
if (!willClose) {
|
|
3292
|
+
setActiveOptionIndex(option.index);
|
|
3293
|
+
focusOptionById(option.id, option.index);
|
|
3294
|
+
}
|
|
3295
|
+
}, props.onClick),
|
|
3296
|
+
onFocus: callAll(() => setActiveOptionIndex(option.index), props.onFocus),
|
|
3297
|
+
onKeyDown: callAll((event) => {
|
|
3298
|
+
handleOptionKeyDown(event, option);
|
|
3299
|
+
}, props.onKeyDown)
|
|
3300
|
+
};
|
|
3301
|
+
},
|
|
3302
|
+
getSearchInputProps: (props = {}) => ({
|
|
3303
|
+
type: "search",
|
|
3304
|
+
...props,
|
|
3305
|
+
ref: (node) => {
|
|
3306
|
+
searchRef.current = node;
|
|
3307
|
+
assignRef(props.ref, node);
|
|
3308
|
+
},
|
|
3309
|
+
value: props.value ?? filter,
|
|
3310
|
+
placeholder: props.placeholder ?? settings.searchPlaceholderText,
|
|
3311
|
+
"aria-label": props["aria-label"] ?? settings.searchAriaLabel,
|
|
3312
|
+
onChange: callAll((event) => {
|
|
3313
|
+
setFilter(event.currentTarget.value);
|
|
3314
|
+
}, props.onChange),
|
|
3315
|
+
onKeyDown: callAll((event) => {
|
|
3316
|
+
handleSearchKeyDown(event);
|
|
3317
|
+
}, props.onKeyDown)
|
|
3318
|
+
}),
|
|
3319
|
+
getClearAllButtonProps: (props = {}) => ({
|
|
3320
|
+
type: "button",
|
|
3321
|
+
...props,
|
|
3322
|
+
disabled: settings.disabled || selectedItems.length === 0 || props.disabled,
|
|
3323
|
+
"aria-label": props["aria-label"] ?? settings.clearAllAriaLabel,
|
|
3324
|
+
onKeyDown: callAll((event) => {
|
|
3325
|
+
handleInlineButtonKeyDown(event);
|
|
3326
|
+
}, props.onKeyDown),
|
|
3327
|
+
onClick: callAll(() => clearSelection(), props.onClick)
|
|
3328
|
+
}),
|
|
3329
|
+
getRemoveButtonProps: (item, props = {}) => ({
|
|
3330
|
+
type: "button",
|
|
3331
|
+
...props,
|
|
3332
|
+
disabled: settings.disabled || props.disabled,
|
|
3333
|
+
"aria-label": props["aria-label"] ?? (typeof settings.removeItemAriaLabel === "function" ? settings.removeItemAriaLabel(item) : `${settings.removeItemAriaLabel}: ${getLabel(item, settings)}`),
|
|
3334
|
+
onKeyDown: callAll((event) => {
|
|
3335
|
+
handleRemoveButtonKeyDown(event, item);
|
|
3336
|
+
}, props.onKeyDown),
|
|
3337
|
+
onClick: callAll(() => removeItem(item), props.onClick)
|
|
3338
|
+
})
|
|
3339
|
+
};
|
|
3340
|
+
}
|
|
3341
|
+
|
|
3342
|
+
// src/createMultiSelectDropdown.ts
|
|
3343
|
+
function createMultiSelectDropdown() {
|
|
3344
|
+
const TypedDropdown = MultiSelectDropdown;
|
|
3345
|
+
function useDropdown(props) {
|
|
3346
|
+
return useMultiSelectDropdown(props);
|
|
3347
|
+
}
|
|
3348
|
+
function useSelectionState(props) {
|
|
3349
|
+
return useMultiSelectState(props);
|
|
3350
|
+
}
|
|
3351
|
+
function defineSettings(settings) {
|
|
3352
|
+
return settings;
|
|
3353
|
+
}
|
|
3354
|
+
function defineSlots(slots) {
|
|
3355
|
+
return slots;
|
|
3356
|
+
}
|
|
3357
|
+
return {
|
|
3358
|
+
Dropdown: TypedDropdown,
|
|
3359
|
+
MultiSelectDropdown: TypedDropdown,
|
|
3360
|
+
useDropdown,
|
|
3361
|
+
useSelectionState,
|
|
3362
|
+
defineSettings,
|
|
3363
|
+
defineSlots
|
|
3364
|
+
};
|
|
3365
|
+
}
|
|
2030
3366
|
// Annotate the CommonJS export names for ESM import in node:
|
|
2031
3367
|
0 && (module.exports = {
|
|
2032
3368
|
MultiSelectDropdown,
|
|
2033
|
-
ReactMultiSelectDropdown
|
|
3369
|
+
ReactMultiSelectDropdown,
|
|
3370
|
+
createMultiSelectDropdown,
|
|
3371
|
+
useMultiSelectDropdown,
|
|
3372
|
+
useMultiSelectState
|
|
2034
3373
|
});
|