@carbon/ibm-products 2.92.0 → 2.92.1-rc.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/es/index.js CHANGED
@@ -60,6 +60,7 @@ import { UserAvatar } from "./components/UserAvatar/UserAvatar.js";
60
60
  import { WebTerminalProvider, useWebTerminal } from "./components/WebTerminal/hooks/index.js";
61
61
  import { WebTerminal } from "./components/WebTerminal/WebTerminal.js";
62
62
  import { WebTerminalContentWrapper } from "./components/WebTerminal/WebTerminalContentWrapper.js";
63
+ import { AddSelectData } from "./packages/ibm-products-utilities/src/utils/add-select/add-select-data.js";
63
64
  import { Coachmark as Coachmark$1 } from "./components/Coachmark/next/Coachmark/Coachmark.js";
64
65
  import { CoachmarkTagline } from "./components/Coachmark/next/Coachmark/CoachmarkTagline/CoachmarkTagline.js";
65
66
  import { CoachmarkBeacon as CoachmarkBeacon$1 } from "./components/Coachmark/next/Coachmark/CoachmarkBeacon/CoachmarkBeacon.js";
@@ -148,7 +149,6 @@ import { NavList } from "./components/Nav/NavList.js";
148
149
  import { Nav } from "./components/Nav/Nav.js";
149
150
  import { StatusIndicator } from "./components/StatusIndicator/StatusIndicator.js";
150
151
  import { StatusIndicatorStep } from "./components/StatusIndicator/StatusIndicatorStep.js";
151
- import { AddSelectData } from "./components/index.js";
152
152
  //#region src/index.ts
153
153
  /**
154
154
  * Copyright IBM Corp. 2024, 2025
@@ -0,0 +1,384 @@
1
+ /**
2
+ * Copyright IBM Corp. 2020, 2026
3
+ *
4
+ * This source code is licensed under the Apache-2.0 license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ */
7
+
8
+ //#region ../ibm-products-utilities/src/utils/add-select/add-select-data.ts
9
+ /**
10
+ * AddSelectData - A lightweight, framework-agnostic utility for managing hierarchical data
11
+ *
12
+ * This utility provides standard APIs for common operations such as setting, selecting,
13
+ * traversing, searching, and sorting hierarchical data structures. It encapsulates data
14
+ * logic separate from UI, allowing both React and Web Components to reuse the same
15
+ * data management functions.
16
+ */
17
+ var AddSelectData = class {
18
+ constructor() {
19
+ this.items = [];
20
+ this.itemMap = /* @__PURE__ */ new Map();
21
+ this.parentMap = /* @__PURE__ */ new Map();
22
+ this.selectedIds = /* @__PURE__ */ new Set();
23
+ this.depthCache = /* @__PURE__ */ new Map();
24
+ this.selectedItemsCache = null;
25
+ }
26
+ /**
27
+ * Initialize or replace the hierarchical data
28
+ * @param items - Array of hierarchical items
29
+ */
30
+ setItems(items) {
31
+ this.items = items;
32
+ this._invalidateCaches();
33
+ this._buildMaps(items);
34
+ }
35
+ /**
36
+ * Get the full list of items
37
+ * @returns Array of all items
38
+ */
39
+ getItems() {
40
+ return this.items;
41
+ }
42
+ /**
43
+ * Retrieve a single item by its id
44
+ * @param id - The item id
45
+ * @returns The item or undefined if not found
46
+ */
47
+ getItem(id) {
48
+ return this.itemMap.get(id);
49
+ }
50
+ /**
51
+ * Update a given item with new properties
52
+ * @param id - The item id
53
+ * @param newProperties - Properties to update
54
+ * @returns true if item was found and updated, false otherwise
55
+ */
56
+ setItem(id, newProperties) {
57
+ const item = this.itemMap.get(id);
58
+ if (!item) return false;
59
+ Object.assign(item, newProperties);
60
+ if ("selected" in newProperties || "status" in newProperties) this._invalidateSelectionCache();
61
+ return true;
62
+ }
63
+ /**
64
+ * Returns an array of items marked as selected (memoized)
65
+ * @returns Array of selected items
66
+ */
67
+ getSelectedItems() {
68
+ if (this.selectedItemsCache !== null) return this.selectedItemsCache;
69
+ const selected = [];
70
+ this.selectedIds.forEach((id) => {
71
+ const item = this.itemMap.get(id);
72
+ if (item) selected.push(item);
73
+ });
74
+ this.selectedItemsCache = selected;
75
+ return selected;
76
+ }
77
+ /**
78
+ * Mark one or more items (by id) as selected
79
+ * @param ids - Single id or array of ids to select
80
+ * @param exclusive - If true, deselect all other items (default: false)
81
+ */
82
+ setSelectedItems(ids, exclusive = false) {
83
+ const idArray = Array.isArray(ids) ? ids : [ids];
84
+ if (exclusive) {
85
+ this.selectedIds.forEach((id) => {
86
+ const item = this.itemMap.get(id);
87
+ if (item) {
88
+ item.selected = false;
89
+ item.status = "unchecked";
90
+ }
91
+ });
92
+ this.selectedIds.clear();
93
+ }
94
+ idArray.forEach((id) => {
95
+ const item = this.itemMap.get(id);
96
+ if (item) {
97
+ item.selected = true;
98
+ item.status = "checked";
99
+ this.selectedIds.add(id);
100
+ }
101
+ });
102
+ this._invalidateSelectionCache();
103
+ }
104
+ /**
105
+ * Get direct children of a node
106
+ * @param id - The parent item id
107
+ * @returns Array of child items or empty array if no children
108
+ */
109
+ getItemChildren(id) {
110
+ const item = this.itemMap.get(id);
111
+ if (!item) return [];
112
+ return item.children?.entries ?? [];
113
+ }
114
+ /**
115
+ * Get the parent of a node
116
+ * @param id - The child item id
117
+ * @returns The parent item or undefined if no parent (root level)
118
+ */
119
+ getItemParent(id) {
120
+ const parentId = this.parentMap.get(id);
121
+ return parentId ? this.itemMap.get(parentId) : void 0;
122
+ }
123
+ /**
124
+ * Get all ancestors (parents up to the root) of a node
125
+ * @param id - The item id
126
+ * @returns Array of ancestor items from immediate parent to root
127
+ */
128
+ getItemParents(id) {
129
+ const parents = [];
130
+ let currentId = id;
131
+ while (currentId) {
132
+ const parentId = this.parentMap.get(currentId);
133
+ if (!parentId) break;
134
+ const parent = this.itemMap.get(parentId);
135
+ if (parent) parents.push(parent);
136
+ currentId = parentId;
137
+ }
138
+ return parents;
139
+ }
140
+ /**
141
+ * Retrieve the selected state status of an item
142
+ * @param id - The item id
143
+ * @returns The status or undefined if item not found
144
+ */
145
+ getItemStatus(id) {
146
+ return this.itemMap.get(id)?.status;
147
+ }
148
+ /**
149
+ * Set or update the status of an item
150
+ * @param id - The item id
151
+ * @param status - The new status
152
+ * @returns true if item was found and updated, false otherwise
153
+ */
154
+ setItemStatus(id, status) {
155
+ const item = this.itemMap.get(id);
156
+ if (!item) return false;
157
+ const wasSelected = item.selected;
158
+ item.status = status;
159
+ item.selected = status === "checked";
160
+ if (item.selected) this.selectedIds.add(id);
161
+ else this.selectedIds.delete(id);
162
+ if (wasSelected !== item.selected) this._invalidateSelectionCache();
163
+ return true;
164
+ }
165
+ /**
166
+ * Check whether an item is selected (O(1) lookup)
167
+ * @param id - The item id
168
+ * @returns true if selected, false otherwise
169
+ */
170
+ isSelected(id) {
171
+ return this.selectedIds.has(id);
172
+ }
173
+ /**
174
+ * Search items based on a query and return matching items
175
+ * @param query - The search query string
176
+ * @param options - Search options
177
+ * @returns Array of matching items
178
+ */
179
+ search(query, options = {}) {
180
+ if (!query) return [];
181
+ const { caseSensitive = false, searchFields = ["title", "value"], maxResults } = options;
182
+ const searchTerm = caseSensitive ? query : query.toLowerCase();
183
+ const results = [];
184
+ const shouldContinue = () => {
185
+ return !maxResults || results.length < maxResults;
186
+ };
187
+ this._traverseItems(this.items, (item) => {
188
+ if (!shouldContinue()) return;
189
+ for (const field of searchFields) {
190
+ const fieldValue = item[field];
191
+ if (fieldValue) {
192
+ if ((caseSensitive ? String(fieldValue) : String(fieldValue).toLowerCase()).includes(searchTerm)) {
193
+ results.push(item);
194
+ break;
195
+ }
196
+ }
197
+ }
198
+ });
199
+ return results;
200
+ }
201
+ /**
202
+ * Sort items based on a comparator function
203
+ * @param compareFn - Comparison function for sorting
204
+ * @param recursive - If true, sort children recursively (default: false)
205
+ */
206
+ sort(compareFn, recursive = false) {
207
+ if (recursive) this._sortRecursive(this.items, compareFn);
208
+ this.items.sort(compareFn);
209
+ this._invalidateCaches();
210
+ this._buildMaps(this.items);
211
+ }
212
+ /**
213
+ * Clear all selections (optimized with Set)
214
+ */
215
+ clearSelections() {
216
+ this.selectedIds.forEach((id) => {
217
+ const item = this.itemMap.get(id);
218
+ if (item) {
219
+ item.selected = false;
220
+ item.status = "unchecked";
221
+ }
222
+ });
223
+ this.selectedIds.clear();
224
+ this._invalidateSelectionCache();
225
+ }
226
+ /**
227
+ * Get the depth/level of an item in the hierarchy (cached)
228
+ * @param id - The item id
229
+ * @returns The depth (0 for root level items) or -1 if not found
230
+ */
231
+ getItemDepth(id) {
232
+ const cachedDepth = this.depthCache.get(id);
233
+ if (cachedDepth !== void 0) return cachedDepth;
234
+ if (!this.itemMap.has(id)) return -1;
235
+ let depth = 0;
236
+ let currentId = id;
237
+ while (currentId) {
238
+ const parentId = this.parentMap.get(currentId);
239
+ if (!parentId) break;
240
+ depth++;
241
+ currentId = parentId;
242
+ }
243
+ this.depthCache.set(id, depth);
244
+ return depth;
245
+ }
246
+ /**
247
+ * Check if an item has children
248
+ * @param id - The item id
249
+ * @returns true if item has children, false otherwise
250
+ */
251
+ hasChildren(id) {
252
+ return !!this.itemMap.get(id)?.children?.entries?.length;
253
+ }
254
+ /**
255
+ * Get all descendant items of a node
256
+ * @param id - The parent item id
257
+ * @returns Array of all descendant items
258
+ */
259
+ getItemDescendants(id) {
260
+ const item = this.itemMap.get(id);
261
+ if (!item?.children?.entries) return [];
262
+ const descendants = [];
263
+ this._traverseItems(item.children.entries, (child) => {
264
+ descendants.push(child);
265
+ });
266
+ return descendants;
267
+ }
268
+ /**
269
+ * Check if an item has any selected descendants (optimized)
270
+ * @param id - The item id
271
+ * @param selectedIds - Set of selected item IDs (defaults to internal selectedIds)
272
+ * @returns true if any descendant is selected, false otherwise
273
+ */
274
+ hasSelectedDescendants(id, selectedIds = this.selectedIds) {
275
+ const children = this.getItemChildren(id);
276
+ if (!children.length) return false;
277
+ for (const child of children) if (selectedIds.has(child.id) || this.hasSelectedDescendants(child.id, selectedIds)) return true;
278
+ return false;
279
+ }
280
+ /**
281
+ * Check if all descendants of an item are selected (optimized)
282
+ * @param id - The item id
283
+ * @param selectedIds - Set of selected item IDs (defaults to internal selectedIds)
284
+ * @returns true if all descendants are selected, false otherwise
285
+ */
286
+ allDescendantsSelected(id, selectedIds = this.selectedIds) {
287
+ const item = this.itemMap.get(id);
288
+ if (!item) return false;
289
+ const children = this.getItemChildren(id);
290
+ if (!children.length) return selectedIds.has(item.id);
291
+ for (const child of children) if (!selectedIds.has(child.id) || !this.allDescendantsSelected(child.id, selectedIds)) return false;
292
+ return true;
293
+ }
294
+ /**
295
+ * Get all descendant IDs from an item (including the item itself)
296
+ * @param id - The item id
297
+ * @returns Array of all descendant IDs including the item itself
298
+ */
299
+ getAllDescendantIds(id) {
300
+ if (!this.itemMap.get(id)) return [];
301
+ const ids = [id];
302
+ const children = this.getItemChildren(id);
303
+ for (const child of children) ids.push(...this.getAllDescendantIds(child.id));
304
+ return ids;
305
+ }
306
+ /**
307
+ * Get only top-level selected items (items without selected ancestors)
308
+ * @param selectedIds - Set of selected item IDs (defaults to internal selectedIds)
309
+ * @returns Array of top-level selected items
310
+ */
311
+ getTopLevelSelectedItems(selectedIds = this.selectedIds) {
312
+ const topLevelItems = [];
313
+ const processedIds = /* @__PURE__ */ new Set();
314
+ const hasSelectedAncestor = (itemId) => {
315
+ return this.getItemParents(itemId).some((parent) => selectedIds.has(parent.id));
316
+ };
317
+ selectedIds.forEach((id) => {
318
+ if (!processedIds.has(id) && !hasSelectedAncestor(id)) {
319
+ const item = this.itemMap.get(id);
320
+ if (item) {
321
+ topLevelItems.push(item);
322
+ this.getAllDescendantIds(id).forEach((descId) => processedIds.add(descId));
323
+ }
324
+ }
325
+ });
326
+ return topLevelItems;
327
+ }
328
+ /**
329
+ * Invalidate all caches
330
+ * @private
331
+ */
332
+ _invalidateCaches() {
333
+ this.selectedItemsCache = null;
334
+ this.depthCache.clear();
335
+ }
336
+ /**
337
+ * Invalidate selection cache only
338
+ * @private
339
+ */
340
+ _invalidateSelectionCache() {
341
+ this.selectedItemsCache = null;
342
+ }
343
+ /**
344
+ * Build internal maps for efficient lookups (optimized with depth caching)
345
+ * @private
346
+ */
347
+ _buildMaps(items, parentId, depth = 0) {
348
+ if (!parentId) {
349
+ this.itemMap.clear();
350
+ this.parentMap.clear();
351
+ this.selectedIds.clear();
352
+ this.depthCache.clear();
353
+ }
354
+ items.forEach((item) => {
355
+ this.itemMap.set(item.id, item);
356
+ this.depthCache.set(item.id, depth);
357
+ if (parentId) this.parentMap.set(item.id, parentId);
358
+ if (item.selected) this.selectedIds.add(item.id);
359
+ if (item.children?.entries) this._buildMaps(item.children.entries, item.id, depth + 1);
360
+ });
361
+ }
362
+ /**
363
+ * Traverse all items and apply a callback function
364
+ * @private
365
+ */
366
+ _traverseItems(items, callback) {
367
+ for (const item of items) {
368
+ callback(item);
369
+ if (item.children?.entries) this._traverseItems(item.children.entries, callback);
370
+ }
371
+ }
372
+ /**
373
+ * Sort items recursively
374
+ * @private
375
+ */
376
+ _sortRecursive(items, compareFn) {
377
+ for (const item of items) if (item.children?.entries) {
378
+ item.children.entries.sort(compareFn);
379
+ this._sortRecursive(item.children.entries, compareFn);
380
+ }
381
+ }
382
+ };
383
+ //#endregion
384
+ export { AddSelectData };
package/lib/index.js CHANGED
@@ -7,7 +7,6 @@
7
7
 
8
8
  "use client";
9
9
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
10
- require("./_virtual/_rolldown/runtime.js");
11
10
  const require_settings = require("./settings.js");
12
11
  const require_usePrefix = require("./global/js/hooks/usePrefix.js");
13
12
  const require_index = require("./components/FeatureFlags/index.js");
@@ -62,6 +61,7 @@ const require_UserAvatar = require("./components/UserAvatar/UserAvatar.js");
62
61
  const require_index$1 = require("./components/WebTerminal/hooks/index.js");
63
62
  const require_WebTerminal = require("./components/WebTerminal/WebTerminal.js");
64
63
  const require_WebTerminalContentWrapper = require("./components/WebTerminal/WebTerminalContentWrapper.js");
64
+ const require_add_select_data = require("./packages/ibm-products-utilities/src/utils/add-select/add-select-data.js");
65
65
  const require_Coachmark = require("./components/Coachmark/next/Coachmark/Coachmark.js");
66
66
  const require_CoachmarkTagline = require("./components/Coachmark/next/Coachmark/CoachmarkTagline/CoachmarkTagline.js");
67
67
  const require_CoachmarkBeacon = require("./components/Coachmark/next/Coachmark/CoachmarkBeacon/CoachmarkBeacon.js");
@@ -150,7 +150,6 @@ const require_NavList = require("./components/Nav/NavList.js");
150
150
  const require_Nav = require("./components/Nav/Nav.js");
151
151
  const require_StatusIndicator = require("./components/StatusIndicator/StatusIndicator.js");
152
152
  const require_StatusIndicatorStep = require("./components/StatusIndicator/StatusIndicatorStep.js");
153
- let _carbon_ibm_products_utilities = require("@carbon/ibm-products-utilities");
154
153
  //#region src/index.ts
155
154
  /**
156
155
  * Copyright IBM Corp. 2024, 2025
@@ -162,12 +161,7 @@ let _carbon_ibm_products_utilities = require("@carbon/ibm-products-utilities");
162
161
  exports.APIKeyModal = require_APIKeyModal.APIKeyModal;
163
162
  exports.AboutModal = require_AboutModal.AboutModal;
164
163
  exports.ActionBar = require_ActionBar.ActionBar;
165
- Object.defineProperty(exports, "AddSelectData", {
166
- enumerable: true,
167
- get: function() {
168
- return _carbon_ibm_products_utilities.AddSelectData;
169
- }
170
- });
164
+ exports.AddSelectData = require_add_select_data.AddSelectData;
171
165
  exports.BEACON_KIND = require_enums.BEACON_KIND;
172
166
  exports.COACHMARK_ALIGNMENT = require_enums.COACHMARK_ALIGNMENT;
173
167
  exports.COACHMARK_OVERLAY_KIND = require_enums.COACHMARK_OVERLAY_KIND;
@@ -0,0 +1,384 @@
1
+ /**
2
+ * Copyright IBM Corp. 2020, 2026
3
+ *
4
+ * This source code is licensed under the Apache-2.0 license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ */
7
+
8
+ //#region ../ibm-products-utilities/src/utils/add-select/add-select-data.ts
9
+ /**
10
+ * AddSelectData - A lightweight, framework-agnostic utility for managing hierarchical data
11
+ *
12
+ * This utility provides standard APIs for common operations such as setting, selecting,
13
+ * traversing, searching, and sorting hierarchical data structures. It encapsulates data
14
+ * logic separate from UI, allowing both React and Web Components to reuse the same
15
+ * data management functions.
16
+ */
17
+ var AddSelectData = class {
18
+ constructor() {
19
+ this.items = [];
20
+ this.itemMap = /* @__PURE__ */ new Map();
21
+ this.parentMap = /* @__PURE__ */ new Map();
22
+ this.selectedIds = /* @__PURE__ */ new Set();
23
+ this.depthCache = /* @__PURE__ */ new Map();
24
+ this.selectedItemsCache = null;
25
+ }
26
+ /**
27
+ * Initialize or replace the hierarchical data
28
+ * @param items - Array of hierarchical items
29
+ */
30
+ setItems(items) {
31
+ this.items = items;
32
+ this._invalidateCaches();
33
+ this._buildMaps(items);
34
+ }
35
+ /**
36
+ * Get the full list of items
37
+ * @returns Array of all items
38
+ */
39
+ getItems() {
40
+ return this.items;
41
+ }
42
+ /**
43
+ * Retrieve a single item by its id
44
+ * @param id - The item id
45
+ * @returns The item or undefined if not found
46
+ */
47
+ getItem(id) {
48
+ return this.itemMap.get(id);
49
+ }
50
+ /**
51
+ * Update a given item with new properties
52
+ * @param id - The item id
53
+ * @param newProperties - Properties to update
54
+ * @returns true if item was found and updated, false otherwise
55
+ */
56
+ setItem(id, newProperties) {
57
+ const item = this.itemMap.get(id);
58
+ if (!item) return false;
59
+ Object.assign(item, newProperties);
60
+ if ("selected" in newProperties || "status" in newProperties) this._invalidateSelectionCache();
61
+ return true;
62
+ }
63
+ /**
64
+ * Returns an array of items marked as selected (memoized)
65
+ * @returns Array of selected items
66
+ */
67
+ getSelectedItems() {
68
+ if (this.selectedItemsCache !== null) return this.selectedItemsCache;
69
+ const selected = [];
70
+ this.selectedIds.forEach((id) => {
71
+ const item = this.itemMap.get(id);
72
+ if (item) selected.push(item);
73
+ });
74
+ this.selectedItemsCache = selected;
75
+ return selected;
76
+ }
77
+ /**
78
+ * Mark one or more items (by id) as selected
79
+ * @param ids - Single id or array of ids to select
80
+ * @param exclusive - If true, deselect all other items (default: false)
81
+ */
82
+ setSelectedItems(ids, exclusive = false) {
83
+ const idArray = Array.isArray(ids) ? ids : [ids];
84
+ if (exclusive) {
85
+ this.selectedIds.forEach((id) => {
86
+ const item = this.itemMap.get(id);
87
+ if (item) {
88
+ item.selected = false;
89
+ item.status = "unchecked";
90
+ }
91
+ });
92
+ this.selectedIds.clear();
93
+ }
94
+ idArray.forEach((id) => {
95
+ const item = this.itemMap.get(id);
96
+ if (item) {
97
+ item.selected = true;
98
+ item.status = "checked";
99
+ this.selectedIds.add(id);
100
+ }
101
+ });
102
+ this._invalidateSelectionCache();
103
+ }
104
+ /**
105
+ * Get direct children of a node
106
+ * @param id - The parent item id
107
+ * @returns Array of child items or empty array if no children
108
+ */
109
+ getItemChildren(id) {
110
+ const item = this.itemMap.get(id);
111
+ if (!item) return [];
112
+ return item.children?.entries ?? [];
113
+ }
114
+ /**
115
+ * Get the parent of a node
116
+ * @param id - The child item id
117
+ * @returns The parent item or undefined if no parent (root level)
118
+ */
119
+ getItemParent(id) {
120
+ const parentId = this.parentMap.get(id);
121
+ return parentId ? this.itemMap.get(parentId) : void 0;
122
+ }
123
+ /**
124
+ * Get all ancestors (parents up to the root) of a node
125
+ * @param id - The item id
126
+ * @returns Array of ancestor items from immediate parent to root
127
+ */
128
+ getItemParents(id) {
129
+ const parents = [];
130
+ let currentId = id;
131
+ while (currentId) {
132
+ const parentId = this.parentMap.get(currentId);
133
+ if (!parentId) break;
134
+ const parent = this.itemMap.get(parentId);
135
+ if (parent) parents.push(parent);
136
+ currentId = parentId;
137
+ }
138
+ return parents;
139
+ }
140
+ /**
141
+ * Retrieve the selected state status of an item
142
+ * @param id - The item id
143
+ * @returns The status or undefined if item not found
144
+ */
145
+ getItemStatus(id) {
146
+ return this.itemMap.get(id)?.status;
147
+ }
148
+ /**
149
+ * Set or update the status of an item
150
+ * @param id - The item id
151
+ * @param status - The new status
152
+ * @returns true if item was found and updated, false otherwise
153
+ */
154
+ setItemStatus(id, status) {
155
+ const item = this.itemMap.get(id);
156
+ if (!item) return false;
157
+ const wasSelected = item.selected;
158
+ item.status = status;
159
+ item.selected = status === "checked";
160
+ if (item.selected) this.selectedIds.add(id);
161
+ else this.selectedIds.delete(id);
162
+ if (wasSelected !== item.selected) this._invalidateSelectionCache();
163
+ return true;
164
+ }
165
+ /**
166
+ * Check whether an item is selected (O(1) lookup)
167
+ * @param id - The item id
168
+ * @returns true if selected, false otherwise
169
+ */
170
+ isSelected(id) {
171
+ return this.selectedIds.has(id);
172
+ }
173
+ /**
174
+ * Search items based on a query and return matching items
175
+ * @param query - The search query string
176
+ * @param options - Search options
177
+ * @returns Array of matching items
178
+ */
179
+ search(query, options = {}) {
180
+ if (!query) return [];
181
+ const { caseSensitive = false, searchFields = ["title", "value"], maxResults } = options;
182
+ const searchTerm = caseSensitive ? query : query.toLowerCase();
183
+ const results = [];
184
+ const shouldContinue = () => {
185
+ return !maxResults || results.length < maxResults;
186
+ };
187
+ this._traverseItems(this.items, (item) => {
188
+ if (!shouldContinue()) return;
189
+ for (const field of searchFields) {
190
+ const fieldValue = item[field];
191
+ if (fieldValue) {
192
+ if ((caseSensitive ? String(fieldValue) : String(fieldValue).toLowerCase()).includes(searchTerm)) {
193
+ results.push(item);
194
+ break;
195
+ }
196
+ }
197
+ }
198
+ });
199
+ return results;
200
+ }
201
+ /**
202
+ * Sort items based on a comparator function
203
+ * @param compareFn - Comparison function for sorting
204
+ * @param recursive - If true, sort children recursively (default: false)
205
+ */
206
+ sort(compareFn, recursive = false) {
207
+ if (recursive) this._sortRecursive(this.items, compareFn);
208
+ this.items.sort(compareFn);
209
+ this._invalidateCaches();
210
+ this._buildMaps(this.items);
211
+ }
212
+ /**
213
+ * Clear all selections (optimized with Set)
214
+ */
215
+ clearSelections() {
216
+ this.selectedIds.forEach((id) => {
217
+ const item = this.itemMap.get(id);
218
+ if (item) {
219
+ item.selected = false;
220
+ item.status = "unchecked";
221
+ }
222
+ });
223
+ this.selectedIds.clear();
224
+ this._invalidateSelectionCache();
225
+ }
226
+ /**
227
+ * Get the depth/level of an item in the hierarchy (cached)
228
+ * @param id - The item id
229
+ * @returns The depth (0 for root level items) or -1 if not found
230
+ */
231
+ getItemDepth(id) {
232
+ const cachedDepth = this.depthCache.get(id);
233
+ if (cachedDepth !== void 0) return cachedDepth;
234
+ if (!this.itemMap.has(id)) return -1;
235
+ let depth = 0;
236
+ let currentId = id;
237
+ while (currentId) {
238
+ const parentId = this.parentMap.get(currentId);
239
+ if (!parentId) break;
240
+ depth++;
241
+ currentId = parentId;
242
+ }
243
+ this.depthCache.set(id, depth);
244
+ return depth;
245
+ }
246
+ /**
247
+ * Check if an item has children
248
+ * @param id - The item id
249
+ * @returns true if item has children, false otherwise
250
+ */
251
+ hasChildren(id) {
252
+ return !!this.itemMap.get(id)?.children?.entries?.length;
253
+ }
254
+ /**
255
+ * Get all descendant items of a node
256
+ * @param id - The parent item id
257
+ * @returns Array of all descendant items
258
+ */
259
+ getItemDescendants(id) {
260
+ const item = this.itemMap.get(id);
261
+ if (!item?.children?.entries) return [];
262
+ const descendants = [];
263
+ this._traverseItems(item.children.entries, (child) => {
264
+ descendants.push(child);
265
+ });
266
+ return descendants;
267
+ }
268
+ /**
269
+ * Check if an item has any selected descendants (optimized)
270
+ * @param id - The item id
271
+ * @param selectedIds - Set of selected item IDs (defaults to internal selectedIds)
272
+ * @returns true if any descendant is selected, false otherwise
273
+ */
274
+ hasSelectedDescendants(id, selectedIds = this.selectedIds) {
275
+ const children = this.getItemChildren(id);
276
+ if (!children.length) return false;
277
+ for (const child of children) if (selectedIds.has(child.id) || this.hasSelectedDescendants(child.id, selectedIds)) return true;
278
+ return false;
279
+ }
280
+ /**
281
+ * Check if all descendants of an item are selected (optimized)
282
+ * @param id - The item id
283
+ * @param selectedIds - Set of selected item IDs (defaults to internal selectedIds)
284
+ * @returns true if all descendants are selected, false otherwise
285
+ */
286
+ allDescendantsSelected(id, selectedIds = this.selectedIds) {
287
+ const item = this.itemMap.get(id);
288
+ if (!item) return false;
289
+ const children = this.getItemChildren(id);
290
+ if (!children.length) return selectedIds.has(item.id);
291
+ for (const child of children) if (!selectedIds.has(child.id) || !this.allDescendantsSelected(child.id, selectedIds)) return false;
292
+ return true;
293
+ }
294
+ /**
295
+ * Get all descendant IDs from an item (including the item itself)
296
+ * @param id - The item id
297
+ * @returns Array of all descendant IDs including the item itself
298
+ */
299
+ getAllDescendantIds(id) {
300
+ if (!this.itemMap.get(id)) return [];
301
+ const ids = [id];
302
+ const children = this.getItemChildren(id);
303
+ for (const child of children) ids.push(...this.getAllDescendantIds(child.id));
304
+ return ids;
305
+ }
306
+ /**
307
+ * Get only top-level selected items (items without selected ancestors)
308
+ * @param selectedIds - Set of selected item IDs (defaults to internal selectedIds)
309
+ * @returns Array of top-level selected items
310
+ */
311
+ getTopLevelSelectedItems(selectedIds = this.selectedIds) {
312
+ const topLevelItems = [];
313
+ const processedIds = /* @__PURE__ */ new Set();
314
+ const hasSelectedAncestor = (itemId) => {
315
+ return this.getItemParents(itemId).some((parent) => selectedIds.has(parent.id));
316
+ };
317
+ selectedIds.forEach((id) => {
318
+ if (!processedIds.has(id) && !hasSelectedAncestor(id)) {
319
+ const item = this.itemMap.get(id);
320
+ if (item) {
321
+ topLevelItems.push(item);
322
+ this.getAllDescendantIds(id).forEach((descId) => processedIds.add(descId));
323
+ }
324
+ }
325
+ });
326
+ return topLevelItems;
327
+ }
328
+ /**
329
+ * Invalidate all caches
330
+ * @private
331
+ */
332
+ _invalidateCaches() {
333
+ this.selectedItemsCache = null;
334
+ this.depthCache.clear();
335
+ }
336
+ /**
337
+ * Invalidate selection cache only
338
+ * @private
339
+ */
340
+ _invalidateSelectionCache() {
341
+ this.selectedItemsCache = null;
342
+ }
343
+ /**
344
+ * Build internal maps for efficient lookups (optimized with depth caching)
345
+ * @private
346
+ */
347
+ _buildMaps(items, parentId, depth = 0) {
348
+ if (!parentId) {
349
+ this.itemMap.clear();
350
+ this.parentMap.clear();
351
+ this.selectedIds.clear();
352
+ this.depthCache.clear();
353
+ }
354
+ items.forEach((item) => {
355
+ this.itemMap.set(item.id, item);
356
+ this.depthCache.set(item.id, depth);
357
+ if (parentId) this.parentMap.set(item.id, parentId);
358
+ if (item.selected) this.selectedIds.add(item.id);
359
+ if (item.children?.entries) this._buildMaps(item.children.entries, item.id, depth + 1);
360
+ });
361
+ }
362
+ /**
363
+ * Traverse all items and apply a callback function
364
+ * @private
365
+ */
366
+ _traverseItems(items, callback) {
367
+ for (const item of items) {
368
+ callback(item);
369
+ if (item.children?.entries) this._traverseItems(item.children.entries, callback);
370
+ }
371
+ }
372
+ /**
373
+ * Sort items recursively
374
+ * @private
375
+ */
376
+ _sortRecursive(items, compareFn) {
377
+ for (const item of items) if (item.children?.entries) {
378
+ item.children.entries.sort(compareFn);
379
+ this._sortRecursive(item.children.entries, compareFn);
380
+ }
381
+ }
382
+ };
383
+ //#endregion
384
+ exports.AddSelectData = AddSelectData;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@carbon/ibm-products",
3
3
  "description": "Carbon for IBM Products",
4
- "version": "2.92.0",
4
+ "version": "2.92.1-rc.0",
5
5
  "license": "Apache-2.0",
6
6
  "main": "lib/index.js",
7
7
  "module": "es/index.js",
@@ -66,6 +66,7 @@
66
66
  "@babel/preset-env": "^7.26.9",
67
67
  "@babel/preset-react": "^7.26.3",
68
68
  "@babel/preset-typescript": "^7.26.0",
69
+ "@carbon/ibm-products-utilities": "1.1.0",
69
70
  "@carbon/styles": "^1.106.0",
70
71
  "@figma/code-connect": "^1.4.0",
71
72
  "@ibm/telemetry-js-config-generator": "^2.0.1",
@@ -107,7 +108,6 @@
107
108
  "@carbon-labs/react-resizer": "^0.24.0",
108
109
  "@carbon/feature-flags": "^1.3.0",
109
110
  "@carbon/ibm-products-styles": "^2.88.0",
110
- "@carbon/ibm-products-utilities": "^1.1.0",
111
111
  "@carbon/telemetry": "^0.1.0",
112
112
  "@carbon/utilities": "^0.19.0",
113
113
  "@carbon/utilities-react": "0.22.0",
@@ -131,5 +131,5 @@
131
131
  "react-dom": "^16.8.6 || ^17.0.1 || ^18.2.0 || ^19.0.0",
132
132
  "react-is": "^16.13.1 || ^17.0.2 || ^18.3.1 || ^19.0.0"
133
133
  },
134
- "gitHead": "3fdb86b45ca8f5b56aeb198d2660877fff326990"
134
+ "gitHead": "873abb7b28373ab7d8bb5d4c93ae98ee99112723"
135
135
  }
@@ -1,149 +0,0 @@
1
- /**
2
- * Copyright IBM Corp. 2020, 2026
3
- *
4
- * This source code is licensed under the Apache-2.0 license found in the
5
- * LICENSE file in the root directory of this source tree.
6
- */
7
-
8
- import "./FeatureFlags/index.js";
9
- import "./AboutModal/AboutModal.js";
10
- import "./ActionBar/ActionBar.js";
11
- import "./APIKeyModal/APIKeyModal.js";
12
- import "./Cascade/Cascade.js";
13
- import "./Checklist/Checklist.js";
14
- import "./CreateFullPage/CreateFullPage.js";
15
- import "./CreateFullPage/CreateFullPageStep.js";
16
- import "./CreateModal/CreateModal.js";
17
- import "./SidePanel/SidePanel.js";
18
- import "./CreateSidePanel/CreateSidePanel.js";
19
- import "./Tearsheet/TearsheetPresence.js";
20
- import "./CreateTearsheet/CreateTearsheet.js";
21
- import "./CreateTearsheet/CreateTearsheetStep.js";
22
- import "./CreateTearsheet/CreateTearsheetDivider.js";
23
- import "./Tearsheet/TearsheetNarrow.js";
24
- import "./CreateTearsheetNarrow/CreateTearsheetNarrow.js";
25
- import "./EditSidePanel/EditSidePanel.js";
26
- import "./EditInPlace/EditInPlace.js";
27
- import "./EmptyStates/EmptyStateV2.deprecated.js";
28
- import "./EmptyStates/EmptyState.js";
29
- import "./EmptyStates/ErrorEmptyState/ErrorEmptyState.js";
30
- import "./EmptyStates/NoDataEmptyState/NoDataEmptyState.js";
31
- import "./EmptyStates/NoTagsEmptyState/NoTagsEmptyState.js";
32
- import "./EmptyStates/NotFoundEmptyState/NotFoundEmptyState.js";
33
- import "./EmptyStates/NotificationsEmptyState/NotificationsEmptyState.js";
34
- import "./EmptyStates/UnauthorizedEmptyState/UnauthorizedEmptyState.js";
35
- import "./ExportModal/ExportModal.js";
36
- import "./ExpressiveCard/ExpressiveCard.js";
37
- import "./FullPageError/FullPageError.js";
38
- import "./ImportModal/ImportModal.js";
39
- import "./InterstitialScreen/InterstitialScreen.js";
40
- import "./InterstitialScreen/InterstitialScreenView.js";
41
- import "./Tearsheet/Tearsheet.js";
42
- import "./UserProfileImage/UserProfileImage.js";
43
- import "./MultiAddSelect/MultiAddSelect.js";
44
- import "./NotificationsPanel/NotificationsPanel.js";
45
- import "./OptionsTile/OptionsTile.js";
46
- import "./TagSet/TagSet.js";
47
- import "./PageHeader/PageHeader.js";
48
- import "./ProductiveCard/ProductiveCard.js";
49
- import "./RemoveModal/RemoveModal.js";
50
- import "./Saving/Saving.js";
51
- import "./ScrollGradient/ScrollGradient.js";
52
- import "./SingleAddSelect/SingleAddSelect.js";
53
- import "./StatusIcon/StatusIcon.js";
54
- import "./StringFormatter/StringFormatter.js";
55
- import "./TagOverflow/TagOverflow.js";
56
- import "./UserAvatar/UserAvatar.js";
57
- import "./WebTerminal/hooks/index.js";
58
- import "./WebTerminal/WebTerminal.js";
59
- import "./WebTerminal/WebTerminalContentWrapper.js";
60
- import "./Coachmark/next/Coachmark/Coachmark.js";
61
- import "./Coachmark/next/Coachmark/CoachmarkTagline/CoachmarkTagline.js";
62
- import "./Coachmark/next/Coachmark/CoachmarkBeacon/CoachmarkBeacon.js";
63
- import "./TruncatedText/TruncatedText.js";
64
- import "./PageHeader/next/index.js";
65
- import "./Tearsheet/next/StackContext.js";
66
- import "./Tearsheet/next/Tearsheet.js";
67
- import "./AddSelect/next/AddSelect.js";
68
- import "./BigNumber/BigNumber.js";
69
- import "./Coachmark/utils/enums.js";
70
- import "./Coachmark/utils/context.js";
71
- import "./Coachmark/Coachmark.js";
72
- import "./CoachmarkBeacon/CoachmarkBeacon.js";
73
- import "./CoachmarkButton/CoachmarkButton.js";
74
- import "./CoachmarkFixed/CoachmarkFixed.js";
75
- import "./CoachmarkOverlayElement/CoachmarkOverlayElement.js";
76
- import "./CoachmarkOverlayElements/CoachmarkOverlayElements.js";
77
- import "./CoachmarkStack/CoachmarkStack.js";
78
- import "./ConditionBuilder/ConditionBuilder.js";
79
- import "./DataSpreadsheet/DataSpreadsheet.js";
80
- import "./DelimitedList/DelimitedList.js";
81
- import "./Decorator/Decorator.js";
82
- import "./GetStartedCard/GetStartedCard.js";
83
- import "./Guidebanner/Guidebanner.js";
84
- import "./Guidebanner/GuidebannerElement.js";
85
- import "./Guidebanner/GuidebannerElementButton.js";
86
- import "./Guidebanner/GuidebannerElementLink.js";
87
- import "./InlineTip/InlineTip.js";
88
- import "./InlineTip/InlineTipButton.js";
89
- import "./InlineTip/InlineTipLink.js";
90
- import "./NonLinearReading/NonLinearReading.js";
91
- import "./SearchBar/SearchBar.js";
92
- import "./Toolbar/Toolbar.js";
93
- import "./Toolbar/ToolbarButton.js";
94
- import "./Toolbar/ToolbarGroup.js";
95
- import "./TruncatedList/TruncatedList.js";
96
- import "./ComboButton/ComboButton.js";
97
- import "./ComboButton/ComboButtonItem/index.js";
98
- import "./Datagrid/Datagrid/addons/Filtering/hooks/useFilterContext.js";
99
- import "./Datagrid/Datagrid/Datagrid.js";
100
- import "./Datagrid/useSortableColumns.js";
101
- import "./Datagrid/useDatagrid.js";
102
- import "./Datagrid/useInfiniteScroll.js";
103
- import "./Datagrid/useNestedRows.js";
104
- import "./Datagrid/useSelectRows.js";
105
- import "./Datagrid/useExpandedRow.js";
106
- import "./Datagrid/useOnRowClick.js";
107
- import "./Datagrid/useRowIsMouseOver.js";
108
- import "./Datagrid/useColumnRightAlign.js";
109
- import "./Datagrid/useDisableSelectRows.js";
110
- import "./Datagrid/useStickyColumn.js";
111
- import "./Datagrid/useActionsColumn.js";
112
- import "./Datagrid/useCustomizeColumns.js";
113
- import "./Datagrid/useSelectAllToggle.js";
114
- import "./Datagrid/useColumnCenterAlign.js";
115
- import "./Datagrid/useColumnOrder.js";
116
- import "./Datagrid/useInlineEdit.js";
117
- import "./Datagrid/useEditableCell.js";
118
- import "./Datagrid/useFiltering.js";
119
- import "./Datagrid/utils/getAutoSizedColumnWidth.js";
120
- import "./DecoratorLink/DecoratorLink.js";
121
- import "./DecoratorDualButton/DecoratorDualButton.js";
122
- import "./DecoratorSingleButton/DecoratorSingleButton.js";
123
- import "./DescriptionList/DescriptionList.js";
124
- import "./DescriptionList/DescriptionListBody.js";
125
- import "./DescriptionList/DescriptionListCell.js";
126
- import "./DescriptionList/DescriptionListRow.js";
127
- import "./EditFullPage/EditFullPage.js";
128
- import "./EditTearsheet/EditTearsheet.js";
129
- import "./EditTearsheet/EditTearsheetForm.js";
130
- import "./EditTearsheetNarrow/EditTearsheetNarrow.js";
131
- import "./EditUpdateCards/EditUpdateCards.js";
132
- import "./FilterPanel/FilterPanel.js";
133
- import "./FilterPanel/FilterPanelLabel/FilterPanelLabel.js";
134
- import "./FilterPanel/FilterPanelGroup/FilterPanelGroup.js";
135
- import "./FilterPanel/FilterPanelAccordion/FilterPanelAccordion.js";
136
- import "./FilterPanel/FilterPanelAccordionItem/FilterPanelAccordionItem.js";
137
- import "./FilterPanel/FilterPanelCheckbox/FilterPanelCheckbox.js";
138
- import "./FilterPanel/FilterPanelCheckboxWithOverflow/FilterPanelCheckboxWithOverflow.js";
139
- import "./FilterPanel/FilterPanelSearch/FilterPanelSearch.js";
140
- import "./HTTPErrors/HTTPError403/HTTPError403.js";
141
- import "./HTTPErrors/HTTPError404/HTTPError404.js";
142
- import "./HTTPErrors/HTTPErrorOther/HTTPErrorOther.js";
143
- import "./Nav/NavItem.js";
144
- import "./Nav/NavList.js";
145
- import "./Nav/Nav.js";
146
- import "./StatusIndicator/StatusIndicator.js";
147
- import "./StatusIndicator/StatusIndicatorStep.js";
148
- import { AddSelectData } from "@carbon/ibm-products-utilities";
149
- export { AddSelectData };