@stackline/react-multiselect-dropdown 19.0.1 → 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 +365 -21
- package/dist/index.cjs +1770 -429
- package/dist/index.d.cts +348 -6
- package/dist/index.d.ts +348 -6
- package/dist/index.js +1756 -411
- 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 = `
|
|
@@ -108,6 +301,7 @@ var styles = `
|
|
|
108
301
|
display: flex;
|
|
109
302
|
flex: 1 1 auto;
|
|
110
303
|
min-width: 0;
|
|
304
|
+
min-height: 1.45em;
|
|
111
305
|
align-items: center;
|
|
112
306
|
align-content: center;
|
|
113
307
|
gap: 8px;
|
|
@@ -121,6 +315,7 @@ var styles = `
|
|
|
121
315
|
align-self: center;
|
|
122
316
|
justify-content: flex-start;
|
|
123
317
|
min-width: 0;
|
|
318
|
+
min-height: 1.45em;
|
|
124
319
|
max-width: 100%;
|
|
125
320
|
color: var(--rmsd-muted);
|
|
126
321
|
font-size: 0.95rem;
|
|
@@ -204,33 +399,25 @@ var styles = `
|
|
|
204
399
|
display: inline-flex;
|
|
205
400
|
align-items: center;
|
|
206
401
|
justify-content: center;
|
|
207
|
-
|
|
208
|
-
min-
|
|
402
|
+
flex: 0 0 auto;
|
|
403
|
+
min-width: 24px;
|
|
404
|
+
min-height: 20px;
|
|
209
405
|
color: var(--rmsd-muted);
|
|
210
406
|
font-size: 0.8rem;
|
|
211
407
|
font-weight: 600;
|
|
408
|
+
line-height: 1;
|
|
409
|
+
white-space: nowrap;
|
|
410
|
+
text-align: center;
|
|
212
411
|
}
|
|
213
412
|
|
|
214
|
-
.rmsd-root.rmsd-has-overflow
|
|
413
|
+
.rmsd-root.rmsd-has-overflow .rmsd-trigger {
|
|
215
414
|
padding-right: 104px;
|
|
216
415
|
}
|
|
217
416
|
|
|
218
|
-
.rmsd-root.rmsd-has-overflow:not(.
|
|
417
|
+
.rmsd-root.rmsd-has-overflow:not(.rmsd-has-clear) .rmsd-trigger {
|
|
219
418
|
padding-right: 74px;
|
|
220
419
|
}
|
|
221
420
|
|
|
222
|
-
.rmsd-root.rmsd-has-overflow:not(.skin-classic) .rmsd-overflow {
|
|
223
|
-
position: absolute;
|
|
224
|
-
top: 50%;
|
|
225
|
-
right: 76px;
|
|
226
|
-
transform: translateY(-50%);
|
|
227
|
-
z-index: 1;
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
.rmsd-root.rmsd-has-overflow:not(.skin-classic):not(.rmsd-has-clear) .rmsd-overflow {
|
|
231
|
-
right: 42px;
|
|
232
|
-
}
|
|
233
|
-
|
|
234
421
|
.rmsd-actions {
|
|
235
422
|
position: absolute;
|
|
236
423
|
top: 50%;
|
|
@@ -795,9 +982,12 @@ var styles = `
|
|
|
795
982
|
|
|
796
983
|
.theme-classic .rmsd-overflow,
|
|
797
984
|
.skin-classic .rmsd-overflow {
|
|
985
|
+
min-width: 24px;
|
|
986
|
+
min-height: 20px;
|
|
798
987
|
color: #333333;
|
|
799
988
|
font-size: 14px;
|
|
800
989
|
font-weight: 400;
|
|
990
|
+
line-height: 1;
|
|
801
991
|
}
|
|
802
992
|
|
|
803
993
|
.theme-classic .rmsd-actions,
|
|
@@ -1065,7 +1255,7 @@ var styles = `
|
|
|
1065
1255
|
|
|
1066
1256
|
@media (max-width: 720px) {
|
|
1067
1257
|
.rmsd-trigger {
|
|
1068
|
-
align-items:
|
|
1258
|
+
align-items: center;
|
|
1069
1259
|
padding-right: 54px;
|
|
1070
1260
|
}
|
|
1071
1261
|
}
|
|
@@ -1083,56 +1273,30 @@ function ensureDropdownStyles() {
|
|
|
1083
1273
|
document.head.appendChild(tag);
|
|
1084
1274
|
}
|
|
1085
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
|
+
|
|
1086
1291
|
// src/MultiSelectDropdown.tsx
|
|
1087
1292
|
var import_jsx_runtime = require("react/jsx-runtime");
|
|
1088
|
-
var
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
filterUnSelectAllText: "Unselect filtered",
|
|
1096
|
-
enableFilterSelectAll: true,
|
|
1097
|
-
enableSearchFilter: false,
|
|
1098
|
-
searchBy: [],
|
|
1099
|
-
maxHeight: 300,
|
|
1100
|
-
badgeShowLimit: Number.MAX_SAFE_INTEGER,
|
|
1101
|
-
classes: "",
|
|
1102
|
-
limitSelection: 0,
|
|
1103
|
-
disabled: false,
|
|
1104
|
-
searchPlaceholderText: "Search",
|
|
1105
|
-
groupBy: "",
|
|
1106
|
-
showCheckbox: true,
|
|
1107
|
-
noDataLabel: "No Data Available",
|
|
1108
|
-
searchAutofocus: true,
|
|
1109
|
-
lazyLoading: false,
|
|
1110
|
-
labelKey: "itemName",
|
|
1111
|
-
primaryKey: "id",
|
|
1112
|
-
position: "bottom",
|
|
1113
|
-
autoPosition: true,
|
|
1114
|
-
loading: false,
|
|
1115
|
-
selectGroup: false,
|
|
1116
|
-
addNewItemOnFilter: false,
|
|
1117
|
-
addNewButtonText: "Add",
|
|
1118
|
-
escapeToClose: true,
|
|
1119
|
-
clearAll: true,
|
|
1120
|
-
closeDropDownOnSelection: false,
|
|
1121
|
-
tagToBody: false,
|
|
1122
|
-
appendToBody: false,
|
|
1123
|
-
theme: "",
|
|
1124
|
-
skin: "classic",
|
|
1125
|
-
ariaLabel: "Multiselect dropdown",
|
|
1126
|
-
listboxAriaLabel: "Dropdown options",
|
|
1127
|
-
searchAriaLabel: "Search options",
|
|
1128
|
-
clearSearchAriaLabel: "Clear search",
|
|
1129
|
-
clearAllAriaLabel: "Clear selected options",
|
|
1130
|
-
removeItemAriaLabel: "Remove selected option",
|
|
1131
|
-
openDropdownAriaLabel: "Open dropdown",
|
|
1132
|
-
closeDropdownAriaLabel: "Close dropdown",
|
|
1133
|
-
loadingText: "Loading options"
|
|
1134
|
-
};
|
|
1135
|
-
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
|
+
}
|
|
1136
1300
|
function StacklineIcon({ name, className = "rmsd-icon" }) {
|
|
1137
1301
|
if (name === "remove") {
|
|
1138
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" }) });
|
|
@@ -1145,131 +1309,6 @@ function StacklineIcon({ name, className = "rmsd-icon" }) {
|
|
|
1145
1309
|
}
|
|
1146
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" }) });
|
|
1147
1311
|
}
|
|
1148
|
-
function isPrimitiveItem(item) {
|
|
1149
|
-
return typeof item === "string" || typeof item === "number" || typeof item === "boolean";
|
|
1150
|
-
}
|
|
1151
|
-
function getLabel(item, settings) {
|
|
1152
|
-
if (isPrimitiveItem(item)) {
|
|
1153
|
-
return String(item);
|
|
1154
|
-
}
|
|
1155
|
-
const keys = [settings.labelKey, "itemName", "name", "label", "title", "value"].filter(Boolean);
|
|
1156
|
-
for (const key of keys) {
|
|
1157
|
-
if (key && item[key] != null) {
|
|
1158
|
-
return String(item[key]);
|
|
1159
|
-
}
|
|
1160
|
-
}
|
|
1161
|
-
return JSON.stringify(item);
|
|
1162
|
-
}
|
|
1163
|
-
function getPrimaryValue(item, settings) {
|
|
1164
|
-
if (isPrimitiveItem(item)) {
|
|
1165
|
-
return String(item);
|
|
1166
|
-
}
|
|
1167
|
-
const keys = [settings.primaryKey, "id", "value", "key"].filter(Boolean);
|
|
1168
|
-
for (const key of keys) {
|
|
1169
|
-
if (key && item[key] != null) {
|
|
1170
|
-
return String(item[key]);
|
|
1171
|
-
}
|
|
1172
|
-
}
|
|
1173
|
-
return getLabel(item, settings);
|
|
1174
|
-
}
|
|
1175
|
-
function itemMatchesQuery(item, query, settings) {
|
|
1176
|
-
if (!query.trim()) {
|
|
1177
|
-
return true;
|
|
1178
|
-
}
|
|
1179
|
-
const needle = query.trim().toLowerCase();
|
|
1180
|
-
const haystack = /* @__PURE__ */ new Set();
|
|
1181
|
-
haystack.add(getLabel(item, settings).toLowerCase());
|
|
1182
|
-
if (!isPrimitiveItem(item)) {
|
|
1183
|
-
const searchKeys = settings.searchBy.length ? settings.searchBy : [settings.labelKey];
|
|
1184
|
-
for (const key of searchKeys) {
|
|
1185
|
-
if (key && item[key] != null) {
|
|
1186
|
-
haystack.add(String(item[key]).toLowerCase());
|
|
1187
|
-
}
|
|
1188
|
-
}
|
|
1189
|
-
}
|
|
1190
|
-
for (const value of haystack) {
|
|
1191
|
-
if (value.includes(needle)) {
|
|
1192
|
-
return true;
|
|
1193
|
-
}
|
|
1194
|
-
}
|
|
1195
|
-
return false;
|
|
1196
|
-
}
|
|
1197
|
-
function getGroupName(item, settings) {
|
|
1198
|
-
if (!settings.groupBy) {
|
|
1199
|
-
return "";
|
|
1200
|
-
}
|
|
1201
|
-
if (typeof settings.groupBy === "function") {
|
|
1202
|
-
return settings.groupBy(item);
|
|
1203
|
-
}
|
|
1204
|
-
if (!isPrimitiveItem(item)) {
|
|
1205
|
-
const groupKey = settings.groupBy;
|
|
1206
|
-
const objectItem = item;
|
|
1207
|
-
if (groupKey in objectItem) {
|
|
1208
|
-
return String(objectItem[groupKey] ?? "");
|
|
1209
|
-
}
|
|
1210
|
-
}
|
|
1211
|
-
return "";
|
|
1212
|
-
}
|
|
1213
|
-
function mergeUniqueItems(base, extra, settings) {
|
|
1214
|
-
const bucket = /* @__PURE__ */ new Map();
|
|
1215
|
-
for (const item of [...base, ...extra]) {
|
|
1216
|
-
bucket.set(getPrimaryValue(item, settings), item);
|
|
1217
|
-
}
|
|
1218
|
-
return Array.from(bucket.values());
|
|
1219
|
-
}
|
|
1220
|
-
function createItemFromQuery(query, settings, sample) {
|
|
1221
|
-
if (sample && !isPrimitiveItem(sample)) {
|
|
1222
|
-
return {
|
|
1223
|
-
[settings.primaryKey]: query.toLowerCase().replace(/\s+/g, "-"),
|
|
1224
|
-
[settings.labelKey]: query
|
|
1225
|
-
};
|
|
1226
|
-
}
|
|
1227
|
-
return query;
|
|
1228
|
-
}
|
|
1229
|
-
function isDisabledItem(item) {
|
|
1230
|
-
return !isPrimitiveItem(item) && Boolean(item.disabled);
|
|
1231
|
-
}
|
|
1232
|
-
function buildGroups(items, settings) {
|
|
1233
|
-
if (!settings.groupBy) {
|
|
1234
|
-
return [];
|
|
1235
|
-
}
|
|
1236
|
-
const map = /* @__PURE__ */ new Map();
|
|
1237
|
-
for (const item of items) {
|
|
1238
|
-
const groupName = getGroupName(item, settings) || "Ungrouped";
|
|
1239
|
-
const current = map.get(groupName) || [];
|
|
1240
|
-
current.push(item);
|
|
1241
|
-
map.set(groupName, current);
|
|
1242
|
-
}
|
|
1243
|
-
return Array.from(map.entries()).map(([name, groupedItems]) => ({
|
|
1244
|
-
name,
|
|
1245
|
-
items: groupedItems
|
|
1246
|
-
}));
|
|
1247
|
-
}
|
|
1248
|
-
function useControllableSelection(controlledValue, defaultValue, onChange) {
|
|
1249
|
-
const [internalValue, setInternalValue] = (0, import_react.useState)(defaultValue ?? []);
|
|
1250
|
-
const isControlled = controlledValue !== void 0;
|
|
1251
|
-
const value = isControlled ? controlledValue : internalValue;
|
|
1252
|
-
const setValue = (nextValue) => {
|
|
1253
|
-
if (!isControlled) {
|
|
1254
|
-
setInternalValue(nextValue);
|
|
1255
|
-
}
|
|
1256
|
-
onChange?.(nextValue);
|
|
1257
|
-
};
|
|
1258
|
-
return [value, setValue];
|
|
1259
|
-
}
|
|
1260
|
-
function sanitizeId(value) {
|
|
1261
|
-
return value.replace(/[^a-zA-Z0-9_-]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 56) || "option";
|
|
1262
|
-
}
|
|
1263
|
-
function normalizeSkinName(value) {
|
|
1264
|
-
return sanitizeId(value.toLowerCase()) || "classic";
|
|
1265
|
-
}
|
|
1266
|
-
function getVisibleBadgeLimit(selectedCount, rawLimit) {
|
|
1267
|
-
if (!Number.isFinite(rawLimit)) {
|
|
1268
|
-
return selectedCount;
|
|
1269
|
-
}
|
|
1270
|
-
const limit = Math.max(0, Math.floor(rawLimit));
|
|
1271
|
-
return Math.min(selectedCount, limit);
|
|
1272
|
-
}
|
|
1273
1312
|
function InnerMultiSelectDropdown({
|
|
1274
1313
|
data,
|
|
1275
1314
|
settings: incomingSettings,
|
|
@@ -1294,41 +1333,43 @@ function InnerMultiSelectDropdown({
|
|
|
1294
1333
|
renderItem,
|
|
1295
1334
|
renderBadge,
|
|
1296
1335
|
renderSearch,
|
|
1297
|
-
renderEmptyState
|
|
1336
|
+
renderEmptyState,
|
|
1337
|
+
slots
|
|
1298
1338
|
}, ref) {
|
|
1299
1339
|
ensureDropdownStyles();
|
|
1300
|
-
const settings =
|
|
1340
|
+
const settings = (0, import_react2.useMemo)(() => resolveDropdownSettings(incomingSettings), [incomingSettings]);
|
|
1301
1341
|
const [selectedItems, setSelectedItems] = useControllableSelection(
|
|
1302
1342
|
controlledSelectedItems,
|
|
1303
1343
|
defaultSelectedItems,
|
|
1304
1344
|
onChange
|
|
1305
1345
|
);
|
|
1306
|
-
const [isOpen, setIsOpen] = (0,
|
|
1307
|
-
const [filter, setFilter] = (0,
|
|
1308
|
-
const [addedItems, setAddedItems] = (0,
|
|
1309
|
-
const [activeDescendantId, setActiveDescendantId] = (0,
|
|
1310
|
-
const [bodyMenuStyle, setBodyMenuStyle] = (0,
|
|
1311
|
-
const [bodyListMaxHeight, setBodyListMaxHeight] = (0,
|
|
1312
|
-
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)(
|
|
1313
1353
|
settings.position === "top" ? "top" : "bottom"
|
|
1314
1354
|
);
|
|
1315
|
-
const rootRef = (0,
|
|
1316
|
-
const triggerRef = (0,
|
|
1317
|
-
const menuRef = (0,
|
|
1318
|
-
const searchRef = (0,
|
|
1319
|
-
const listRef = (0,
|
|
1320
|
-
const lastScrollHeightRef = (0,
|
|
1321
|
-
const pendingFocusRef = (0,
|
|
1322
|
-
const
|
|
1323
|
-
const
|
|
1324
|
-
|
|
1325
|
-
[
|
|
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]
|
|
1326
1367
|
);
|
|
1327
|
-
const filteredItems = (0,
|
|
1368
|
+
const filteredItems = (0, import_react2.useMemo)(
|
|
1328
1369
|
() => allItems.filter((item) => itemMatchesQuery(item, filter, settings)),
|
|
1329
1370
|
[allItems, filter, settings]
|
|
1330
1371
|
);
|
|
1331
|
-
const groupedItems = (0,
|
|
1372
|
+
const groupedItems = (0, import_react2.useMemo)(() => buildGroups(filteredItems, settings), [filteredItems, settings]);
|
|
1332
1373
|
const listboxId = `${instanceIdRef.current}-listbox`;
|
|
1333
1374
|
const getOptionId = (item, index, prefix) => `${instanceIdRef.current}-${prefix}-${index}-${sanitizeId(getPrimaryValue(item, settings))}`;
|
|
1334
1375
|
const isSelected = (item) => selectedItems.some(
|
|
@@ -1353,6 +1394,68 @@ function InnerMultiSelectDropdown({
|
|
|
1353
1394
|
};
|
|
1354
1395
|
const focusFirstOption = () => focusOptionByIndex(0);
|
|
1355
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
|
+
};
|
|
1356
1459
|
const updateSelection = (nextItems) => {
|
|
1357
1460
|
setSelectedItems(nextItems);
|
|
1358
1461
|
};
|
|
@@ -1386,6 +1489,7 @@ function InnerMultiSelectDropdown({
|
|
|
1386
1489
|
const previousItems = selectedItems;
|
|
1387
1490
|
updateSelection([]);
|
|
1388
1491
|
onDeSelectAll?.(previousItems);
|
|
1492
|
+
focusAfterSelectionChange();
|
|
1389
1493
|
};
|
|
1390
1494
|
const toggleDropdown = () => {
|
|
1391
1495
|
if (isOpen) {
|
|
@@ -1394,25 +1498,34 @@ function InnerMultiSelectDropdown({
|
|
|
1394
1498
|
openDropdown("search");
|
|
1395
1499
|
}
|
|
1396
1500
|
};
|
|
1397
|
-
const removeItem = (item) => {
|
|
1501
|
+
const removeItem = (item, focusTarget = "search") => {
|
|
1398
1502
|
const nextItems = selectedItems.filter(
|
|
1399
1503
|
(selectedItem) => getPrimaryValue(selectedItem, settings) !== getPrimaryValue(item, settings)
|
|
1400
1504
|
);
|
|
1401
1505
|
updateSelection(nextItems);
|
|
1402
1506
|
onDeSelect?.(item);
|
|
1507
|
+
focusAfterSelectionChange(focusTarget);
|
|
1403
1508
|
};
|
|
1404
|
-
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") => {
|
|
1405
1517
|
if (settings.disabled || isDisabledItem(item)) {
|
|
1406
1518
|
return;
|
|
1407
1519
|
}
|
|
1408
1520
|
if (isSelected(item)) {
|
|
1409
|
-
removeItem(item);
|
|
1521
|
+
removeItem(item, focusTarget);
|
|
1410
1522
|
return;
|
|
1411
1523
|
}
|
|
1412
1524
|
if (settings.singleSelection) {
|
|
1413
1525
|
updateSelection([item]);
|
|
1414
1526
|
onSelect?.(item);
|
|
1415
1527
|
closeDropdown(true);
|
|
1528
|
+
focusAfterSelectionChange("trigger");
|
|
1416
1529
|
return;
|
|
1417
1530
|
}
|
|
1418
1531
|
if (settings.limitSelection && selectedItems.length >= settings.limitSelection) {
|
|
@@ -1423,7 +1536,10 @@ function InnerMultiSelectDropdown({
|
|
|
1423
1536
|
onSelect?.(item);
|
|
1424
1537
|
if (settings.closeDropDownOnSelection) {
|
|
1425
1538
|
closeDropdown(true);
|
|
1539
|
+
focusAfterSelectionChange("trigger");
|
|
1540
|
+
return;
|
|
1426
1541
|
}
|
|
1542
|
+
focusAfterSelectionChange(focusTarget);
|
|
1427
1543
|
};
|
|
1428
1544
|
const selectAllItems = (items, filteredSelection = false) => {
|
|
1429
1545
|
if (settings.singleSelection) {
|
|
@@ -1439,6 +1555,7 @@ function InnerMultiSelectDropdown({
|
|
|
1439
1555
|
} else {
|
|
1440
1556
|
onSelectAll?.(nextItems);
|
|
1441
1557
|
}
|
|
1558
|
+
focusAfterSelectionChange();
|
|
1442
1559
|
};
|
|
1443
1560
|
const deSelectAllItems = (items, filteredSelection = false) => {
|
|
1444
1561
|
const ids = new Set(items.map((item) => getPrimaryValue(item, settings)));
|
|
@@ -1449,13 +1566,19 @@ function InnerMultiSelectDropdown({
|
|
|
1449
1566
|
} else {
|
|
1450
1567
|
onDeSelectAll?.(items);
|
|
1451
1568
|
}
|
|
1569
|
+
focusAfterSelectionChange();
|
|
1452
1570
|
};
|
|
1453
1571
|
const handleAddFilterNewItem = async () => {
|
|
1454
1572
|
const query = filter.trim();
|
|
1455
1573
|
if (!query) {
|
|
1456
1574
|
return;
|
|
1457
1575
|
}
|
|
1576
|
+
const requestId = addRequestIdRef.current + 1;
|
|
1577
|
+
addRequestIdRef.current = requestId;
|
|
1458
1578
|
const result = await onAddFilterNewItem?.(query);
|
|
1579
|
+
if (requestId !== addRequestIdRef.current) {
|
|
1580
|
+
return;
|
|
1581
|
+
}
|
|
1459
1582
|
const nextItem = result === void 0 ? createItemFromQuery(query, settings, data[0]) : result;
|
|
1460
1583
|
setAddedItems((currentItems) => mergeUniqueItems(currentItems, [nextItem], settings));
|
|
1461
1584
|
if (settings.singleSelection) {
|
|
@@ -1464,6 +1587,7 @@ function InnerMultiSelectDropdown({
|
|
|
1464
1587
|
updateSelection(mergeUniqueItems(selectedItems, [nextItem], settings));
|
|
1465
1588
|
}
|
|
1466
1589
|
setFilter("");
|
|
1590
|
+
focusAfterSelectionChange();
|
|
1467
1591
|
};
|
|
1468
1592
|
const toggleGroup = (groupName, items) => {
|
|
1469
1593
|
const groupItems = items.filter((item) => !isDisabledItem(item));
|
|
@@ -1471,10 +1595,12 @@ function InnerMultiSelectDropdown({
|
|
|
1471
1595
|
if (allSelected) {
|
|
1472
1596
|
deSelectAllItems(groupItems, false);
|
|
1473
1597
|
onGroupDeSelect?.(groupName, groupItems);
|
|
1598
|
+
focusAfterSelectionChange();
|
|
1474
1599
|
return;
|
|
1475
1600
|
}
|
|
1476
1601
|
selectAllItems(groupItems, false);
|
|
1477
1602
|
onGroupSelect?.(groupName, groupItems);
|
|
1603
|
+
focusAfterSelectionChange();
|
|
1478
1604
|
};
|
|
1479
1605
|
const handleListScroll = () => {
|
|
1480
1606
|
if (!listRef.current || !onScrollToEnd) {
|
|
@@ -1503,7 +1629,7 @@ function InnerMultiSelectDropdown({
|
|
|
1503
1629
|
}
|
|
1504
1630
|
return "bottom";
|
|
1505
1631
|
};
|
|
1506
|
-
(0,
|
|
1632
|
+
(0, import_react2.useEffect)(() => {
|
|
1507
1633
|
if (!isOpen) {
|
|
1508
1634
|
return;
|
|
1509
1635
|
}
|
|
@@ -1514,7 +1640,7 @@ function InnerMultiSelectDropdown({
|
|
|
1514
1640
|
}
|
|
1515
1641
|
};
|
|
1516
1642
|
const handleKeyDown = (event) => {
|
|
1517
|
-
if (event.key === "Escape" && settings.
|
|
1643
|
+
if (event.key === "Escape" && settings.keyboard.escape) {
|
|
1518
1644
|
closeDropdown(true);
|
|
1519
1645
|
}
|
|
1520
1646
|
};
|
|
@@ -1526,7 +1652,7 @@ function InnerMultiSelectDropdown({
|
|
|
1526
1652
|
document.removeEventListener("touchstart", handlePointerDown);
|
|
1527
1653
|
document.removeEventListener("keydown", handleKeyDown);
|
|
1528
1654
|
};
|
|
1529
|
-
}, [isOpen, settings.
|
|
1655
|
+
}, [isOpen, settings.keyboard.escape]);
|
|
1530
1656
|
const updateBodyMenuPosition = () => {
|
|
1531
1657
|
if (!shouldAppendToBody || !triggerRef.current || typeof window === "undefined") {
|
|
1532
1658
|
return;
|
|
@@ -1586,7 +1712,7 @@ function InnerMultiSelectDropdown({
|
|
|
1586
1712
|
selectedItems.length,
|
|
1587
1713
|
filter
|
|
1588
1714
|
]);
|
|
1589
|
-
(0,
|
|
1715
|
+
(0, import_react2.useEffect)(() => {
|
|
1590
1716
|
if (!isOpen || !shouldAppendToBody || typeof window === "undefined") {
|
|
1591
1717
|
return;
|
|
1592
1718
|
}
|
|
@@ -1612,7 +1738,7 @@ function InnerMultiSelectDropdown({
|
|
|
1612
1738
|
filteredItems.length,
|
|
1613
1739
|
selectedItems.length
|
|
1614
1740
|
]);
|
|
1615
|
-
(0,
|
|
1741
|
+
(0, import_react2.useEffect)(() => {
|
|
1616
1742
|
if (!isOpen) {
|
|
1617
1743
|
return;
|
|
1618
1744
|
}
|
|
@@ -1632,10 +1758,10 @@ function InnerMultiSelectDropdown({
|
|
|
1632
1758
|
}
|
|
1633
1759
|
}, 0);
|
|
1634
1760
|
}, [isOpen, filteredItems.length, settings.enableSearchFilter, settings.searchAutofocus]);
|
|
1635
|
-
(0,
|
|
1761
|
+
(0, import_react2.useEffect)(() => {
|
|
1636
1762
|
lastScrollHeightRef.current = 0;
|
|
1637
1763
|
}, [filteredItems.length]);
|
|
1638
|
-
(0,
|
|
1764
|
+
(0, import_react2.useImperativeHandle)(
|
|
1639
1765
|
ref,
|
|
1640
1766
|
() => ({
|
|
1641
1767
|
openDropdown: () => openDropdown("search"),
|
|
@@ -1685,20 +1811,38 @@ function InnerMultiSelectDropdown({
|
|
|
1685
1811
|
return `${settings.ariaLabel}: ${selectedItems.map((item) => getLabel(item, settings)).join(", ")}`;
|
|
1686
1812
|
};
|
|
1687
1813
|
const stopInlineKey = (event) => {
|
|
1688
|
-
if (event.key
|
|
1814
|
+
if (isSpaceKey(event.key) && !settings.keyboard.space) {
|
|
1815
|
+
event.preventDefault();
|
|
1689
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;
|
|
1690
1829
|
}
|
|
1830
|
+
stopInlineKey(event);
|
|
1691
1831
|
};
|
|
1692
1832
|
const handleTriggerKeyDown = (event) => {
|
|
1693
1833
|
if (settings.disabled) {
|
|
1694
1834
|
return;
|
|
1695
1835
|
}
|
|
1696
|
-
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)) {
|
|
1697
1841
|
event.preventDefault();
|
|
1698
1842
|
toggleDropdown();
|
|
1699
1843
|
return;
|
|
1700
1844
|
}
|
|
1701
|
-
if (event.key === "ArrowDown") {
|
|
1845
|
+
if (settings.keyboard.arrows && event.key === "ArrowDown") {
|
|
1702
1846
|
event.preventDefault();
|
|
1703
1847
|
if (!isOpen) {
|
|
1704
1848
|
openDropdown("first");
|
|
@@ -1707,7 +1851,7 @@ function InnerMultiSelectDropdown({
|
|
|
1707
1851
|
}
|
|
1708
1852
|
return;
|
|
1709
1853
|
}
|
|
1710
|
-
if (event.key === "ArrowUp") {
|
|
1854
|
+
if (settings.keyboard.arrows && event.key === "ArrowUp") {
|
|
1711
1855
|
event.preventDefault();
|
|
1712
1856
|
if (!isOpen) {
|
|
1713
1857
|
openDropdown("last");
|
|
@@ -1716,48 +1860,84 @@ function InnerMultiSelectDropdown({
|
|
|
1716
1860
|
}
|
|
1717
1861
|
return;
|
|
1718
1862
|
}
|
|
1719
|
-
if (event.key === "Escape" && isOpen) {
|
|
1863
|
+
if (settings.keyboard.escape && event.key === "Escape" && isOpen) {
|
|
1720
1864
|
event.preventDefault();
|
|
1721
1865
|
closeDropdown(true);
|
|
1722
1866
|
}
|
|
1723
1867
|
};
|
|
1724
1868
|
const handleArrowButtonKeyDown = (event) => {
|
|
1725
|
-
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)) {
|
|
1726
1875
|
event.preventDefault();
|
|
1727
1876
|
event.stopPropagation();
|
|
1728
1877
|
toggleDropdown();
|
|
1729
1878
|
return;
|
|
1730
1879
|
}
|
|
1731
|
-
if (event.key === "ArrowDown") {
|
|
1880
|
+
if (settings.keyboard.arrows && event.key === "ArrowDown") {
|
|
1732
1881
|
event.preventDefault();
|
|
1733
1882
|
event.stopPropagation();
|
|
1734
|
-
|
|
1883
|
+
if (isOpen) {
|
|
1884
|
+
focusFirstOption();
|
|
1885
|
+
} else {
|
|
1886
|
+
openDropdown("first");
|
|
1887
|
+
}
|
|
1735
1888
|
return;
|
|
1736
1889
|
}
|
|
1737
|
-
if (event.key === "ArrowUp") {
|
|
1890
|
+
if (settings.keyboard.arrows && event.key === "ArrowUp") {
|
|
1738
1891
|
event.preventDefault();
|
|
1739
1892
|
event.stopPropagation();
|
|
1740
|
-
|
|
1893
|
+
if (isOpen) {
|
|
1894
|
+
focusLastOption();
|
|
1895
|
+
} else {
|
|
1896
|
+
openDropdown("last");
|
|
1897
|
+
}
|
|
1741
1898
|
}
|
|
1742
1899
|
};
|
|
1743
1900
|
const handleSearchKeyDown = (event) => {
|
|
1744
|
-
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") {
|
|
1745
1911
|
event.preventDefault();
|
|
1746
1912
|
focusFirstOption();
|
|
1747
1913
|
return;
|
|
1748
1914
|
}
|
|
1749
|
-
if (event.key === "Escape"
|
|
1915
|
+
if (settings.keyboard.escape && event.key === "Escape") {
|
|
1750
1916
|
event.preventDefault();
|
|
1751
1917
|
closeDropdown(true);
|
|
1752
1918
|
}
|
|
1753
1919
|
};
|
|
1754
1920
|
const handleOptionKeyDown = (event, item, optionIndex) => {
|
|
1755
|
-
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)) {
|
|
1756
1930
|
event.preventDefault();
|
|
1757
|
-
|
|
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
|
+
}
|
|
1758
1938
|
return;
|
|
1759
1939
|
}
|
|
1760
|
-
if (event.key === "ArrowDown") {
|
|
1940
|
+
if (settings.keyboard.arrows && event.key === "ArrowDown") {
|
|
1761
1941
|
event.preventDefault();
|
|
1762
1942
|
const nextIndex = optionIndex + 1;
|
|
1763
1943
|
const options = getOptionElements();
|
|
@@ -1768,7 +1948,7 @@ function InnerMultiSelectDropdown({
|
|
|
1768
1948
|
}
|
|
1769
1949
|
return;
|
|
1770
1950
|
}
|
|
1771
|
-
if (event.key === "ArrowUp") {
|
|
1951
|
+
if (settings.keyboard.arrows && event.key === "ArrowUp") {
|
|
1772
1952
|
event.preventDefault();
|
|
1773
1953
|
if (optionIndex > 0) {
|
|
1774
1954
|
focusOptionByIndex(optionIndex - 1);
|
|
@@ -1779,21 +1959,54 @@ function InnerMultiSelectDropdown({
|
|
|
1779
1959
|
}
|
|
1780
1960
|
return;
|
|
1781
1961
|
}
|
|
1782
|
-
if (event.key === "Home") {
|
|
1962
|
+
if (settings.keyboard.arrows && event.key === "Home") {
|
|
1783
1963
|
event.preventDefault();
|
|
1784
1964
|
focusFirstOption();
|
|
1785
1965
|
return;
|
|
1786
1966
|
}
|
|
1787
|
-
if (event.key === "End") {
|
|
1967
|
+
if (settings.keyboard.arrows && event.key === "End") {
|
|
1788
1968
|
event.preventDefault();
|
|
1789
1969
|
focusLastOption();
|
|
1790
1970
|
return;
|
|
1791
1971
|
}
|
|
1792
|
-
if (event.key === "Escape"
|
|
1972
|
+
if (settings.keyboard.escape && event.key === "Escape") {
|
|
1793
1973
|
event.preventDefault();
|
|
1794
1974
|
closeDropdown(true);
|
|
1795
1975
|
}
|
|
1796
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
|
+
};
|
|
1797
2010
|
const renderItemNode = (item) => {
|
|
1798
2011
|
const context = {
|
|
1799
2012
|
item,
|
|
@@ -1809,49 +2022,122 @@ function InnerMultiSelectDropdown({
|
|
|
1809
2022
|
!isPrimitiveItem(item) && item.caption ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "rmsd-option-hint", children: String(item.caption) }) : null
|
|
1810
2023
|
] });
|
|
1811
2024
|
};
|
|
1812
|
-
const
|
|
2025
|
+
const renderBadgeLabel = (item) => {
|
|
2026
|
+
const label = getLabel(item, settings);
|
|
1813
2027
|
const context = {
|
|
1814
2028
|
item,
|
|
1815
|
-
label
|
|
2029
|
+
label,
|
|
1816
2030
|
selected: true,
|
|
1817
2031
|
disabled: settings.disabled || isDisabledItem(item),
|
|
1818
2032
|
query: filter,
|
|
1819
2033
|
toggle: () => selectItem(item),
|
|
1820
2034
|
remove: () => removeItem(item)
|
|
1821
2035
|
};
|
|
1822
|
-
|
|
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
|
+
);
|
|
1823
2091
|
};
|
|
1824
|
-
let
|
|
2092
|
+
let enabledOptionCursor = -1;
|
|
1825
2093
|
const renderOption = (item, prefix, localIndex) => {
|
|
1826
2094
|
const selected = isSelected(item);
|
|
1827
2095
|
const disabled = settings.disabled || isDisabledItem(item) || limitReached && !selected;
|
|
1828
|
-
|
|
1829
|
-
const optionIndex = optionCursor;
|
|
2096
|
+
const optionIndex = disabled ? -1 : enabledOptionCursor += 1;
|
|
1830
2097
|
const optionId = getOptionId(item, localIndex, prefix);
|
|
1831
|
-
|
|
1832
|
-
|
|
1833
|
-
|
|
1834
|
-
|
|
1835
|
-
|
|
1836
|
-
|
|
1837
|
-
|
|
1838
|
-
|
|
1839
|
-
|
|
1840
|
-
|
|
1841
|
-
|
|
1842
|
-
|
|
1843
|
-
|
|
1844
|
-
|
|
1845
|
-
|
|
1846
|
-
|
|
1847
|
-
|
|
1848
|
-
|
|
1849
|
-
|
|
1850
|
-
|
|
1851
|
-
|
|
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
|
+
}
|
|
1852
2128
|
},
|
|
1853
|
-
|
|
1854
|
-
|
|
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);
|
|
1855
2141
|
};
|
|
1856
2142
|
const handleTriggerClick = (event) => {
|
|
1857
2143
|
if (event.target.closest("button")) {
|
|
@@ -1859,174 +2145,1229 @@ function InnerMultiSelectDropdown({
|
|
|
1859
2145
|
}
|
|
1860
2146
|
toggleDropdown();
|
|
1861
2147
|
};
|
|
1862
|
-
const
|
|
1863
|
-
|
|
1864
|
-
{
|
|
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 = {
|
|
1865
2363
|
ref: menuRef,
|
|
1866
2364
|
className: `rmsd-menu rmsd-${effectivePosition} skin-${skinName} theme-${skinName}${skinFallbackClass ? ` ${skinFallbackClass}` : ""}${shouldAppendToBody ? " rmsd-body-overlay" : ""}`,
|
|
1867
2365
|
style: shouldAppendToBody ? bodyMenuStyle : void 0,
|
|
1868
2366
|
onMouseDown: (event) => event.stopPropagation(),
|
|
1869
|
-
onTouchStart: (event) => event.stopPropagation()
|
|
1870
|
-
|
|
1871
|
-
|
|
1872
|
-
|
|
1873
|
-
|
|
1874
|
-
|
|
1875
|
-
|
|
1876
|
-
|
|
1877
|
-
|
|
1878
|
-
onClick: () => allFilteredSelected ? deSelectAllItems(selectableItems, Boolean(filter.trim())) : selectAllItems(selectableItems, Boolean(filter.trim())),
|
|
1879
|
-
disabled: settings.disabled || selectableItems.length === 0,
|
|
1880
|
-
children: [
|
|
1881
|
-
settings.showCheckbox ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "rmsd-checkbox", "data-checked": allFilteredSelected, "aria-hidden": "true" }) : null,
|
|
1882
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: allFilteredSelected ? filter.trim() ? settings.filterUnSelectAllText : settings.unSelectAllText : filter.trim() ? settings.filterSelectAllText : settings.selectAllText })
|
|
1883
|
-
]
|
|
1884
|
-
}
|
|
1885
|
-
) : null,
|
|
1886
|
-
settings.addNewItemOnFilter && filter.trim() ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("button", { type: "button", className: "rmsd-inline-button rmsd-add-button", onClick: handleAddFilterNewItem, children: [
|
|
1887
|
-
settings.addNewButtonText,
|
|
1888
|
-
' "',
|
|
1889
|
-
filter.trim(),
|
|
1890
|
-
'"'
|
|
1891
|
-
] }) : null
|
|
1892
|
-
] }) : null,
|
|
1893
|
-
settings.enableSearchFilter ? renderSearch ? renderSearch({ query: filter, setQuery: setFilter, closeDropdown: () => closeDropdown() }) : /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "rmsd-search-shell", children: [
|
|
1894
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(StacklineIcon, { name: "search", className: "rmsd-search-icon" }),
|
|
1895
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1896
|
-
"input",
|
|
1897
|
-
{
|
|
1898
|
-
ref: searchRef,
|
|
1899
|
-
className: "rmsd-search-input",
|
|
1900
|
-
value: filter,
|
|
1901
|
-
onChange: (event) => setFilter(event.target.value),
|
|
1902
|
-
onKeyDown: handleSearchKeyDown,
|
|
1903
|
-
placeholder: settings.searchPlaceholderText,
|
|
1904
|
-
"aria-label": settings.searchAriaLabel
|
|
1905
|
-
}
|
|
1906
|
-
),
|
|
1907
|
-
filter ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1908
|
-
"button",
|
|
1909
|
-
{
|
|
1910
|
-
type: "button",
|
|
1911
|
-
className: "rmsd-search-clear",
|
|
1912
|
-
"aria-label": settings.clearSearchAriaLabel,
|
|
1913
|
-
onKeyDown: stopInlineKey,
|
|
1914
|
-
onClick: () => setFilter(""),
|
|
1915
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(StacklineIcon, { name: "clear" })
|
|
1916
|
-
}
|
|
1917
|
-
) : null
|
|
1918
|
-
] }) : null
|
|
1919
|
-
] }),
|
|
1920
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1921
|
-
"div",
|
|
1922
|
-
{
|
|
1923
|
-
className: "rmsd-list",
|
|
1924
|
-
ref: listRef,
|
|
1925
|
-
style: { maxHeight: shouldAppendToBody ? bodyListMaxHeight ?? settings.maxHeight : settings.maxHeight },
|
|
1926
|
-
onScroll: settings.lazyLoading ? handleListScroll : void 0,
|
|
1927
|
-
id: listboxId,
|
|
1928
|
-
role: "listbox",
|
|
1929
|
-
"aria-label": settings.listboxAriaLabel,
|
|
1930
|
-
"aria-multiselectable": !settings.singleSelection,
|
|
1931
|
-
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: [
|
|
1932
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "rmsd-group-header", children: [
|
|
1933
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { children: [
|
|
1934
|
-
group.name,
|
|
1935
|
-
" \xB7 ",
|
|
1936
|
-
group.items.length
|
|
1937
|
-
] }),
|
|
1938
|
-
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
|
|
1939
|
-
] }),
|
|
1940
|
-
group.items.map((item, index) => renderOption(item, `group-${groupIndex}`, index))
|
|
1941
|
-
] }, 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 })
|
|
1942
|
-
}
|
|
1943
|
-
)
|
|
1944
|
-
]
|
|
1945
|
-
}
|
|
1946
|
-
) : null;
|
|
1947
|
-
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: rootClassName, style, ref: rootRef, "data-open": isOpen, children: [
|
|
1948
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
1949
|
-
"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,
|
|
1950
2376
|
{
|
|
1951
|
-
|
|
1952
|
-
|
|
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
|
-
type: "button",
|
|
2006
|
-
className: "rmsd-arrow-button",
|
|
2007
|
-
disabled: settings.disabled,
|
|
2008
|
-
"aria-label": isOpen ? settings.closeDropdownAriaLabel : settings.openDropdownAriaLabel,
|
|
2009
|
-
"aria-expanded": isOpen,
|
|
2010
|
-
"aria-controls": listboxId,
|
|
2011
|
-
onKeyDown: handleArrowButtonKeyDown,
|
|
2012
|
-
onClick: (event) => {
|
|
2013
|
-
event.stopPropagation();
|
|
2014
|
-
toggleDropdown();
|
|
2015
|
-
},
|
|
2016
|
-
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" }) })
|
|
2017
|
-
}
|
|
2018
|
-
)
|
|
2019
|
-
] })
|
|
2020
|
-
]
|
|
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();
|
|
2021
2430
|
}
|
|
2022
|
-
|
|
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(),
|
|
2023
2501
|
shouldAppendToBody && menu && typeof document !== "undefined" ? (0, import_react_dom.createPortal)(menu, document.body) : menu
|
|
2024
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
|
+
);
|
|
2025
2514
|
}
|
|
2026
|
-
var ReactMultiSelectDropdown = (0,
|
|
2515
|
+
var ReactMultiSelectDropdown = (0, import_react2.forwardRef)(InnerMultiSelectDropdown);
|
|
2027
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
|
+
}
|
|
2028
3366
|
// Annotate the CommonJS export names for ESM import in node:
|
|
2029
3367
|
0 && (module.exports = {
|
|
2030
3368
|
MultiSelectDropdown,
|
|
2031
|
-
ReactMultiSelectDropdown
|
|
3369
|
+
ReactMultiSelectDropdown,
|
|
3370
|
+
createMultiSelectDropdown,
|
|
3371
|
+
useMultiSelectDropdown,
|
|
3372
|
+
useMultiSelectState
|
|
2032
3373
|
});
|